diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/CREDITS linux-2.4.20/CREDITS
--- linux-2.4.19/CREDITS	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/CREDITS	2002-10-29 11:18:33.000000000 +0000
@@ -704,6 +704,11 @@
 S: Warrendale, Pennsylvania 15086
 S: USA
 
+N: Martin Devera
+E: devik@cdi.cz
+W: http://luxik.cdi.cz/~devik/qos/
+D: HTB qdisc and random networking hacks
+
 N: Alex deVries
 E: adevries@thepuffingroup.com
 D: Various SGI parts, bits of HAL2 and Newport, PA-RISC Linux.
@@ -1258,7 +1263,7 @@
 S: Germany
 
 N: David Hinds
-E: dhinds@zen.stanford.edu
+E: dahinds@users.sourceforge.net
 W: http://tao.stanford.edu/~dhinds
 D: PCMCIA and CardBus stuff, PCMCIA-HOWTO, PCMCIA client drivers
 S: 2019 W. Middlefield Rd #1
@@ -1329,6 +1334,12 @@
 S: Provo, Utah 84606-5607
 S: USA
 
+N: Marcel Holtmann
+E: marcel@holtmann.org
+W: http://www.holtmann.org
+D: Author of the Linux Bluetooth Subsystem PC Card drivers
+S: Germany
+
 N: Rob W. W. Hooft
 E: hooft@EMBL-Heidelberg.DE
 D: Shared libs for graphics-tools and for the f2c compiler
@@ -2154,7 +2165,7 @@
 S: South Australia
 
 N. Wolfgang Muees
-E: wmues@nexgo.de
+E: wolfgang@iksw-muees.de
 D: Auerswald USB driver
 
 N: Ian A. Murdock
@@ -3311,14 +3322,10 @@
 S: Germany
 
 N: Leonard N. Zubkoff
-E: lnz@dandelion.com
 W: http://www.dandelion.com/Linux/
 D: BusLogic SCSI driver
 D: Mylex DAC960 PCI RAID driver
 D: Miscellaneous kernel fixes
-S: 3078 Sulphur Spring Court
-S: San Jose, California 95148
-S: USA
 
 N: Alessandro Zummo
 E: azummo@ita.flashnet.it
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/BK-usage/bk-kernel-howto.txt linux-2.4.20/Documentation/BK-usage/bk-kernel-howto.txt
--- linux-2.4.19/Documentation/BK-usage/bk-kernel-howto.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/BK-usage/bk-kernel-howto.txt	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,275 @@
+
+		   Doing the BK Thing, Penguin-Style
+
+
+
+
+This set of notes is intended mainly for kernel developers, occasional
+or full-time, but sysadmins and power users may find parts of it useful
+as well.  It assumes at least a basic familiarity with CVS, both at a
+user level (use on the cmd line) and at a higher level (client-server model).
+Due to the author's background, an operation may be described in terms
+of CVS, or in terms of how that operation differs from CVS.
+
+This is -not- intended to be BitKeeper documentation.  Always run
+"bk help <command>" or in X "bk helptool <command>" for reference
+documentation.
+
+
+BitKeeper Concepts
+------------------
+
+In the true nature of the Internet itself, BitKeeper is a distributed
+system.  When applied to revision control, this means doing away with
+client-server, and changing to a parent-child model... essentially
+peer-to-peer.  On the developer's end, this also represents a
+fundamental disruption in the standard workflow of changes, commits,
+and merges.  You will need to take a few minutes to think about
+how to best work under BitKeeper, and re-optimize things a bit.
+In some sense it is a bit radical, because it might described as
+tossing changes out into a maelstrom and having them magically
+land at the right destination... but I'm getting ahead of myself.
+
+Let's start with this progression:
+Each BitKeeper source tree on disk is a repository unto itself.
+Each repository has a parent.
+Each repository contains a set of a changesets ("csets").
+Each cset is one or more changed files, bundled together.
+
+Each tree is a repository, so all changes are checked into the local
+tree.  When a change is checked in, all modified files are grouped
+into a logical unit, the changeset.  Internally, BK links these
+changesets in a tree, representing various converging and diverging
+lines of development.  These changesets are the bread and butter of
+the BK system.
+
+After the concept of changesets, the next thing you need to get used
+to is having multiple copies of source trees lying around.  This -really-
+takes some getting used to, for some people.  Separate source trees
+are the means in BitKeeper by which you delineate parallel lines
+of development, both minor and major.  What would be branches in
+CVS become separate source trees, or "clones" in BitKeeper [heh,
+or Star Wars] terminology.
+
+Clones and changesets are the tools from which most of the power of
+BitKeeper is derived.  As mentioned earlier, each clone has a parent,
+the tree used as the source when the new clone was created.  In a
+CVS-like setup, the parent would be a remote server on the Internet,
+and the child is your local clone of that tree.
+
+Once you have established a common baseline between two source trees --
+a common parent -- then you can merge changesets between those two
+trees with ease.  Merging changes into a tree is called a "pull", and
+is analagous to 'cvs update'.  A pull downloads all the changesets in
+the remote tree you do not have, and merges them.  Sending changes in
+one tree to another tree is called a "push".  Push sends all changes
+in the local tree the remote does not yet have, and merges them.
+
+From these concepts come some initial command examples:
+
+1) bk clone -q http://linux.bkbits.net/linux-2.5 linus-2.5
+Download a 2.5 stock kernel tree, naming it "linus-2.5" in the local dir.
+The "-q" disables listing every single file as it is downloaded.
+
+2) bk clone -ql linus-2.5 alpha-2.5
+Create a separate source tree for the Alpha AXP architecture.
+The "-l" uses hard links instead of copying data, since both trees are
+on the local disk.  You can also replace the above with "bk lclone -q ..."
+
+You only clone a tree -once-.  After cloning the tree lives a long time
+on disk, being updating by pushes and pulls.
+
+3) cd alpha-2.5 ; bk pull http://gkernel.bkbits.net/alpha-2.5
+Download changes in "alpha-2.5" repository which are not present
+in the local repository, and merge them into the source tree.
+
+4) bk -r co -q
+Because every tree is a repository, files must be checked out before
+they will be in their standard places in the source tree.
+
+5)	bk vi fs/inode.c				# example change...
+	bk citool					# checkin, using X tool
+	bk push bk://gkernel@bkbits.net/alpha-2.5	# upload change
+Typical example of a BK sequence that would replace the analagous CVS
+situation,
+	vi fs/inode.c
+	cvs commit
+
+As this is just supposed to be a quick BK intro, for more in-depth
+tutorials, live working demos, and docs, see http://www.bitkeeper.com/
+
+
+
+BK and Kernel Development Workflow
+----------------------------------
+Currently the latest 2.5 tree is available via "bk clone $URL"
+and "bk pull $URL" at http://linux.bkbits.net/linux-2.5
+This should change in a few weeks to a kernel.org URL.
+
+
+A big part of using BitKeeper is organizing the various trees you have
+on your local disk, and organizing the flow of changes among those
+trees, and remote trees.  If one were to graph the relationships between
+a desired BK setup, you are likely to see a few-many-few graph, like
+this:
+
+		    linux-2.5
+		        |
+	       merge-to-linus-2.5
+		 /    |      |
+	        /     |      |
+	vm-hacks  bugfixes  filesys   personal-hacks
+	      \	      |	     |		/
+	       \      |      |         /
+		\     |      |        /
+	         testing-and-validation
+
+Since a "bk push" sends all changes not in the target tree, and
+since a "bk pull" receives all changes not in the source tree, you want
+to make sure you are only pushing specific changes to the desired tree,
+not all changes from "peer parent" trees.  For example, pushing a change
+from the testing-and-validation tree would probably be a bad idea,
+because it will push all changes from vm-hacks, bugfixes, filesys, and
+personal-hacks trees into the target tree.
+
+One would typically work on only one "theme" at a time, either
+vm-hacks or bugfixes or filesys, keeping those changes isolated in
+their own tree during development, and only merge the isolated with
+other changes when going upstream (to Linus or other maintainers) or
+downstream (to your "union" trees, like testing-and-validation above).
+
+It should be noted that some of this separation is not just recommended
+practice, it's actually [for now] -enforced- by BitKeeper.  BitKeeper
+requires that changesets maintain a certain order, which is the reason
+that "bk push" sends all local changesets the remote doesn't have.  This
+separation may look like a lot of wasted disk space at first, but it
+helps when two unrelated changes may "pollute" the same area of code, or
+don't follow the same pace of development, or any other of the standard
+reasons why one creates a development branch.
+
+Small development branches (clones) will appear and disappear:
+
+	-------- A --------- B --------- C --------- D -------
+	          \                                 /
+		   -----short-term devel branch-----
+
+While long-term branches will parallel a tree (or trees), with period
+merge points.  In this first example, we pull from a tree (pulls,
+"\") periodically, such as what occurs when tracking changes in a
+vendor tree, never pushing changes back up the line:
+
+	-------- A --------- B --------- C --------- D -------
+	          \                       \           \
+	           ----long-term devel branch-----------------
+
+And then a more common case in Linux kernel development, a long term
+branch with periodic merges back into the tree (pushes, "/"):
+
+	-------- A --------- B --------- C --------- D -------
+	          \                       \         / \
+	           ----long-term devel branch-----------------
+
+
+
+
+
+Submitting Changes to Linus
+---------------------------
+There's a bit of an art, or style, of submitting changes to Linus.
+Since Linus's tree is now (you might say) fully integrated into the
+distributed BitKeeper system, there are several prerequisites to
+properly submitting a BitKeeper change.  All these prereq's are just
+general cleanliness of BK usage, so as people become experts at BK, feel
+free to optimize this process further (assuming Linus agrees, of
+course).
+
+
+
+0) Make sure your tree was originally cloned from the linux-2.5 tree
+created by Linus.  If your tree does not have this as its ancestor, it
+is impossible to reliably exchange changesets.
+
+
+
+1) Pay attention to your commit text.  The commit message that
+accompanies each changeset you submit will live on forever in history,
+and is used by Linus to accurately summarize the changes in each
+pre-patch.  Remember that there is no context, so
+	"fix for new scheduler changes"
+would be too vague, but
+	"fix mips64 arch for new scheduler switch_to(), TIF_xxx semantics"
+would be much better.
+
+You can and should use the command "bk comment -C<rev>" to update the
+commit text, and improve it after the fact.  This is very useful for
+development: poor, quick descriptions during development, which get
+cleaned up using "bk comment" before issuing the "bk push" to submit the
+changes.
+
+
+
+2) Include an Internet-available URL for Linus to pull from, such as
+
+	Pull from:  http://gkernel.bkbits.net/net-drivers-2.5
+
+
+
+3) Include a summary and "diffstat -p1" of each changeset that will be
+downloaded, when Linus issues a "bk pull".  The author auto-generates
+these summaries using "bk push -nl <parent> 2>&1", to obtain a listing
+of all the pending-to-send changesets, and their commit messages.
+
+It is important to show Linus what he will be downloading when he issues
+a "bk pull", to reduce the time required to sift the changes once they
+are downloaded to Linus's local machine.
+
+IMPORTANT NOTE:  One of the features of BK is that your repository does
+not have to be up to date, in order for Linus to receive your changes.
+It is considered a courtesy to keep your repository fairly recent, to
+lessen any potential merge work Linus may need to do.
+
+
+4) Split up your changes.  Each maintainer<->Linus situation is likely
+to be slightly different here, so take this just as general advice.  The
+author splits up changes according to "themes" when merging with Linus.
+Simultaneous pushes from local development go to special trees which
+exist solely to house changes "queued" for Linus.  Example of the trees:
+
+	net-drivers-2.5 -- on-going net driver maintenance
+	vm-2.5 -- VM-related changes
+	fs-2.5 -- filesystem-related changes
+
+Linus then has much more freedom for pulling changes.  He could (for
+example) issue a "bk pull" on vm-2.5 and fs-2.5 trees, to merge their
+changes, but hold off net-drivers-2.5 because of a change that needs
+more discussion.
+
+Other maintainers may find that a single linus-pull-from tree is
+adequate for passing BK changesets to him.
+
+
+
+Frequently Answered Questions
+-----------------------------
+1) How do I change the e-mail address shown in the changelog?
+A. When you run "bk citool" or "bk commit", set environment
+   variables BK_USER and BK_HOST to the desired username
+   and host/domain name.
+
+
+2) How do I use tags / get a diff between two kernel versions?
+A. Pass the tags Linus uses to 'bk export'.
+
+ChangeSets are in a forward-progressing order, so it's pretty easy
+to get a snapshot starting and ending at any two points in time.
+Linus puts tags on each release and pre-release, so you could use
+these two examples:
+
+    bk export -tpatch -hdu -rv2.5.4,v2.5.5 | less
+        # creates patch-2.5.5 essentially
+    bk export -tpatch -du -rv2.5.5-pre1,v2.5.5 | less
+        # changes from pre1 to final
+
+A tag is just an alias for a specific changeset... and since changesets
+are ordered, a tag is thus a marker for a specific point in time (or
+specific state of the tree).
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/BK-usage/bk-make-sum linux-2.4.20/Documentation/BK-usage/bk-make-sum
--- linux-2.4.19/Documentation/BK-usage/bk-make-sum	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/BK-usage/bk-make-sum	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,37 @@
+#!/bin/sh -e
+# DIR=$HOME/BK/axp-2.5
+# cd $DIR
+
+LINUS_REPO=$1
+DIRBASE=`basename $PWD`
+
+{
+cat <<EOT
+Linus, please do a
+
+	bk pull http://gkernel.bkbits.net/$DIRBASE
+
+This will update the following files:
+
+EOT
+
+bk changes -L -d'$unless(:MERGE:){:CSETREV:\n}' $LINUS_REPO |
+while read rev; do
+  bk export -tpatch -r$rev
+done | diffstat -p1 2>/dev/null
+
+cat <<EOT
+
+through these ChangeSets:
+
+EOT
+
+bk changes -L -d'$unless(:MERGE:){ChangeSet|:CSETREV:\n}' $LINUS_REPO |
+bk -R prs -h -d'$unless(:MERGE:){<:P:@:HOST:> (:D: :I:)\n$each(:C:){   (:C:)\n}\n}' -
+
+} > /tmp/linus.txt
+
+cat <<EOT
+Mail text in /tmp/linus.txt; please check and send using your favourite
+mailer.
+EOT
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/BK-usage/bksend linux-2.4.20/Documentation/BK-usage/bksend
--- linux-2.4.19/Documentation/BK-usage/bksend	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/BK-usage/bksend	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,36 @@
+#!/bin/sh
+# A script to format BK changeset output in a manner that is easy to read.
+# Andreas Dilger <adilger@turbolabs.com>  13/02/2002
+#
+# Add diffstat output after Changelog <adilger@turbolabs.com>   21/02/2002
+
+PROG=bksend
+
+usage() {
+	echo "usage: $PROG -r<rev>"
+	echo -e "\twhere <rev> is of the form '1.23', '1.23..', '1.23..1.27',"
+	echo -e "\tor '+' to indicate the most recent revision"
+
+	exit 1
+}
+
+case $1 in
+-r) REV=$2; shift ;;
+-r*) REV=`echo $1 | sed 's/^-r//'` ;;
+*) echo "$PROG: no revision given, you probably don't want that";;
+esac
+
+[ -z "$REV" ] && usage
+
+echo "You can import this changeset into BK by piping this whole message to:"
+echo "'| bk receive [path to repository]' or apply the patch as usual."
+
+SEP="\n===================================================================\n\n"
+echo -e $SEP
+bk changes -r$REV
+echo
+bk export -tpatch -du -h -r$REV | diffstat
+echo; echo
+bk export -tpatch -du -h -r$REV
+echo -e $SEP
+bk send -wgzip_uu -r$REV -
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/BK-usage/bz64wrap linux-2.4.20/Documentation/BK-usage/bz64wrap
--- linux-2.4.19/Documentation/BK-usage/bz64wrap	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/BK-usage/bz64wrap	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+# bz64wrap - the sending side of a bzip2 | base64 stream
+# Andreas Dilger <adilger@clusterfs.com>   Jan 2002
+
+
+PATH=$PATH:/usr/bin:/usr/local/bin:/usr/freeware/bin
+
+# A program to generate base64 encoding on stdout
+BASE64_ENCODE="uuencode -m /dev/stdout"
+BASE64_BEGIN=
+BASE64_END=
+
+BZIP=NO
+BASE64=NO
+
+# Test if we have the bzip program installed
+bzip2 -c /dev/null > /dev/null 2>&1 && BZIP=YES
+
+# Test if uuencode can handle the -m (MIME) encoding option
+$BASE64_ENCODE < /dev/null > /dev/null 2>&1 && BASE64=YES
+
+if [ $BASE64 = NO ]; then
+	BASE64_ENCODE=mimencode
+	BASE64_BEGIN="begin-base64 644 -"
+	BASE64_END="===="
+
+	$BASE64_ENCODE < /dev/null > /dev/null 2>&1 && BASE64=YES
+fi
+
+if [ $BZIP = NO -o $BASE64 = NO ]; then
+	echo "$0: can't use bz64 encoding: bzip2=$BZIP, $BASE64_ENCODE=$BASE64"
+	exit 1
+fi
+
+# Sadly, mimencode does not appear to have good "begin" and "end" markers
+# like uuencode does, and it is picky about getting the right start/end of
+# the base64 stream, so we handle this internally.
+echo "$BASE64_BEGIN"
+bzip2 -9 | $BASE64_ENCODE
+echo "$BASE64_END"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/BK-usage/cset-to-linus linux-2.4.20/Documentation/BK-usage/cset-to-linus
--- linux-2.4.19/Documentation/BK-usage/cset-to-linus	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/BK-usage/cset-to-linus	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,49 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+my ($lhs, $rev, $tmp, $rhs, $s);
+my @cset_text = ();
+my @pipe_text = ();
+my $have_cset = 0;
+
+while (<>) {
+	next if /^---/;
+
+	if (($lhs, $tmp, $rhs) = (/^(ChangeSet\@)([^,]+)(, .*)$/)) {
+		&cset_rev if ($have_cset);
+
+		$rev = $tmp;
+		$have_cset = 1;
+
+		push(@cset_text, $_);
+	}
+
+	elsif ($have_cset) {
+		push(@cset_text, $_);
+	}
+}
+&cset_rev if ($have_cset);
+exit(0);
+
+
+sub cset_rev {
+	my $empty_cset = 0;
+
+	open PIPE, "bk export -tpatch -hdu -r $rev | diffstat -p1 2>/dev/null |" or die;
+	while ($s = <PIPE>) {
+		$empty_cset = 1 if ($s =~ /0 files changed/);
+		push(@pipe_text, $s);
+	}
+	close(PIPE);
+
+	if (! $empty_cset) {
+		print @cset_text;
+		print @pipe_text;
+		print "\n\n";
+	}
+
+	@pipe_text = ();
+	@cset_text = ();
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/BK-usage/csets-to-patches linux-2.4.20/Documentation/BK-usage/csets-to-patches
--- linux-2.4.19/Documentation/BK-usage/csets-to-patches	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/BK-usage/csets-to-patches	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,44 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+my ($lhs, $rev, $tmp, $rhs, $s);
+my @cset_text = ();
+my @pipe_text = ();
+my $have_cset = 0;
+
+while (<>) {
+	next if /^---/;
+
+	if (($lhs, $tmp, $rhs) = (/^(ChangeSet\@)([^,]+)(, .*)$/)) {
+		&cset_rev if ($have_cset);
+
+		$rev = $tmp;
+		$have_cset = 1;
+
+		push(@cset_text, $_);
+	}
+
+	elsif ($have_cset) {
+		push(@cset_text, $_);
+	}
+}
+&cset_rev if ($have_cset);
+exit(0);
+
+
+sub cset_rev {
+	my $empty_cset = 0;
+
+	system("bk export -tpatch -du -r $rev > /tmp/rev-$rev.patch");
+
+	if (! $empty_cset) {
+		print @cset_text;
+		print @pipe_text;
+		print "\n\n";
+	}
+
+	@pipe_text = ();
+	@cset_text = ();
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/BK-usage/unbz64wrap linux-2.4.20/Documentation/BK-usage/unbz64wrap
--- linux-2.4.19/Documentation/BK-usage/unbz64wrap	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/BK-usage/unbz64wrap	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# unbz64wrap - the receiving side of a bzip2 | base64 stream
+# Andreas Dilger <adilger@clusterfs.com>   Jan 2002
+
+# Sadly, mimencode does not appear to have good "begin" and "end" markers
+# like uuencode does, and it is picky about getting the right start/end of
+# the base64 stream, so we handle this explicitly here.
+
+PATH=$PATH:/usr/bin:/usr/local/bin:/usr/freeware/bin
+
+if mimencode -u < /dev/null > /dev/null 2>&1 ; then
+	SHOW=
+	while read LINE; do
+		case $LINE in
+		begin-base64*) SHOW=YES ;;
+		====) SHOW= ;;
+		*) [ "$SHOW" ] && echo "$LINE" ;;
+		esac
+	done | mimencode -u | bunzip2
+	exit $?
+else
+	cat - | uudecode -o /dev/stdout | bunzip2
+	exit $?
+fi
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/Changes linux-2.4.20/Documentation/Changes
--- linux-2.4.19/Documentation/Changes	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/Changes	2002-10-29 11:18:50.000000000 +0000
@@ -55,7 +55,7 @@
 o  modutils               2.4.2                   # insmod -V
 o  e2fsprogs              1.25                    # tune2fs
 o  jfsutils               1.0.12                  # fsck.jfs -V
-o  reiserfsprogs          3.x.1b                  # reiserfsck 2>&1|grep reiserfsprogs
+o  reiserfsprogs          3.6.3                   # reiserfsck -V 2>&1|grep reiserfsprogs
 o  pcmcia-cs              3.1.21                  # cardmgr -V
 o  PPP                    2.4.0                   # pppd --version
 o  isdn4k-utils           3.1pre1                 # isdnctrl 2>&1|grep version
@@ -225,7 +225,6 @@
 version v0.99.0 or higher. Running old versions may cause problems
 with programs using shared memory.
 
-
 Networking
 ==========
 
@@ -326,7 +325,7 @@
 
 Reiserfsprogs
 -------------
-o  <ftp://ftp.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.x.1b.tar.gz>
+o  <http://www.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.6.3.tar.gz>
 
 LVM toolset
 -----------
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/Configure.help linux-2.4.20/Documentation/Configure.help
--- linux-2.4.19/Documentation/Configure.help	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/Configure.help	2002-10-29 11:18:50.000000000 +0000
@@ -2,10 +2,7 @@
 #	Eric S. Raymond <mailto:esr@thyrsus.com>
 #	Steven Cole <mailto:elenstev@mesatop.com>
 #
-# Version 3.00: current with 2.4.19
-#
-# This version of the Linux kernel configuration help texts
-# corresponds to kernel versions 2.4.x and 2.5.x.
+# Version 3.01: current with 2.4.19+
 #
 # Translations of this file available on the WWW:
 #
@@ -233,6 +230,22 @@
   network and embedded applications.  For more information see the
   Axis Communication site, <http://developer.axis.com/>.
 
+Unsynced TSC support
+CONFIG_X86_TSC_DISABLE
+  This option is used for getting Linux to run on a NUMA multi-node 
+  boxes, laptops and other systems suffering from unsynced TSCs or 
+  TSC drift, which can cause gettimeofday to return non-monotonic values. 
+  Choosing this option will disable the CONFIG_X86_TSC optimization,
+  and allows you to then specify "notsc" as a boot option regardless of 
+  which processor you have compiled for. 
+  
+  NOTE: If your system hangs when init should run, you are probably
+  using a i686 compiled glibc which reads the TSC without checking for 
+  availability. Boot without "notsc" and install a i386 compiled glibc 
+  to solve the problem.
+
+  If unsure, say N.
+
 Multiquad support for NUMA systems
 CONFIG_MULTIQUAD
   This option is used for getting Linux to run on a (IBM/Sequent) NUMA 
@@ -376,6 +389,12 @@
   Select this if you have a 32-bit processor and more than 4
   gigabytes of physical RAM.
 
+HIGHMEM I/O support
+CONFIG_HIGHIO
+  If you want to be able to do I/O to high memory pages, say Y.
+  Otherwise low memory pages are used as bounce buffers causing a
+  degrade in performance.
+
 Normal floppy disk support
 CONFIG_BLK_DEV_FD
   If you want to use the floppy disk drive(s) of your PC under Linux,
@@ -494,7 +513,7 @@
 CONFIG_BLK_DEV_UMEM
   Saying Y here will include support for the MM5415 family of
   battery backed (Non-volatile) RAM cards.
-  http://www.umem.com/
+  <http://www.umem.com/>
 
   The cards appear as block devices that can be partitioned into
   as many as 15 partitions.
@@ -534,6 +553,17 @@
 
   If unsure, say N.
 
+Per partition statistics in /proc/partitions
+CONFIG_BLK_STATS
+  If you say yes here, your kernel will keep statistical information
+  for every partition. The information includes things as numbers of
+  read and write accesses, the number of merged requests etc.
+
+  This is required for the full functionality of sar(8) and interesting
+  if you want to do performance tuning, by tweaking the elevator, e.g.
+
+  If unsure, say N.
+
 ATA/IDE/MFM/RLL support
 CONFIG_IDE
   If you say Y here, your kernel will be able to manage low cost mass
@@ -671,6 +701,12 @@
   Support for outboard IDE disks, tape drives, and CD-ROM drives
   connected through a  PCMCIA card.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  ide-cs.o
+
 Include IDE/ATAPI CD-ROM support
 CONFIG_BLK_DEV_IDECD
   If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is
@@ -817,6 +853,12 @@
   If both this SCSI emulation and native ATAPI support are compiled
   into the kernel, the native support will be used.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  ide-scsi.o
+
 Use the NOOP Elevator (WARNING)
 CONFIG_BLK_DEV_ELEVATOR_NOOP
   If you are using a raid class top-level driver above the ATA/IDE core,
@@ -1004,6 +1046,11 @@
   Please read the comments at the top of
   <file:drivers/scsi/3w-xxxx.c>.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called 3w-xxxx.o.
+
 AEC62XX chipset support
 CONFIG_BLK_DEV_AEC62XX
   This driver adds up to 4 more EIDE devices sharing a single
@@ -1067,10 +1114,10 @@
   This effect can be also invoked by calling "idex=ata66"
   If unsure, say N.
 
-CMD64X chipset support
+CMD64X and CMD680 chipset support
 CONFIG_BLK_DEV_CMD64X
   Say Y here if you have an IDE controller which uses any of these
-  chipsets: CMD643, CMD646, or CMD648.
+  chipsets: CMD643, CMD646, CMD648, CMD649 or CMD680.
 
 CY82C693 chipset support
 CONFIG_BLK_DEV_CY82C693
@@ -1796,6 +1843,12 @@
   <http://www.tldp.org/docs.html#howto>. There you will also learn
   where to get the supporting user space utilities raidtools.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  md.o
+
   If unsure, say N.
 
 Linear (append) mode
@@ -1885,6 +1938,12 @@
   transparent failover to the backup path(s) happens if a IO errors
   arrives on the primary path.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  multipath.o
+
   If unsure, say N.
 
 Support for IDE Raid controllers
@@ -1899,6 +1958,12 @@
   has its own Raid drivers, which you should use if you need better
   performance.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  ataraid.o
+
 Support Promise software RAID (Fasttrak(tm))
 CONFIG_BLK_DEV_ATARAID_PDC
   Say Y or M if you have a Promise Fasttrak (tm) Raid controller
@@ -2493,6 +2558,17 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+skb->pkt_type packet match support
+CONFIG_IP_NF_MATCH_PKTTYPE
+  This patch allows you to match packet in accrodance
+  to its "class", eg. BROADCAST, MULTICAST, ...
+  
+  Typical usage:
+  iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG
+  
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 MAC address match support
 CONFIG_IP_NF_MATCH_MAC
   MAC matching allows you to match packets based on the source
@@ -2543,6 +2619,28 @@
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `N'.
 
+DSCP match support
+CONFIG_IP_NF_MATCH_DSCP
+  This option adds a `DSCP' match, which allows you to match against
+  the IPv4 header DSCP field (DSCP codepoint).
+
+  The DSCP codepoint can have any value between 0x0 and 0x4f.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+ 
+
+ECN match support
+CONFIG_IP_NF_MATCH_ECN
+  This option adds a `ECN' match, which allows you to match against
+  the IPv4 and TCP header ECN fields.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+ 
+
 TOS match support
 CONFIG_IP_NF_MATCH_TOS
   TOS matching allows you to match packets based on the Type Of
@@ -2551,6 +2649,18 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+conntrack match support
+CONFIG_IP_NF_MATCH_CONNTRACK
+  This is a general conntrack match module, a superset of the state match.
+
+  It allows matching on additional conntrack information, which is
+  useful in complex configurations, such as NAT gateways with multiple
+  internet links or tunnels.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+
 Connection state match support
 CONFIG_IP_NF_MATCH_STATE
   Connection state matching allows you to match packets based on their
@@ -2610,7 +2720,7 @@
 
   Please note that you will need a recent version (>= 1.2.6a)
   of the iptables userspace program in order to use this feature.
-  See http://www.iptables.org/ for download instructions.
+  See <http://www.iptables.org/> for download instructions.
 
   If unsure, say 'N'.
 
@@ -2668,6 +2778,36 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+DSCP target support
+CONFIG_IP_NF_TARGET_DSCP
+  This option adds a `DSCP' target, which allows you to create rules in
+  the iptables mangle table. The selected packet has the DSCP field set
+  to the hex value provided on the command line; unlike the TOS target
+  which will only set the legal values within ip.h.
+
+  The DSCP field can be set to any value between 0x0 and 0x4f. It does
+  take into account that bits 6 and 7 are used by ECN.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+ 
+
+ECN target support
+CONFIG_IP_NF_TARGET_ECN
+  This option adds a `ECN' target, which can be used in the iptables mangle
+  table.  
+
+  You can use this target to remove the ECN bits from the IPv4 header of
+  an IP packet.  This is particularly useful, if you need to work around
+  existing ECN blackholes on the internet, but don't want to disable
+  ECN support in general.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+ 
+
 TOS target support
 CONFIG_IP_NF_TARGET_TOS
   This option adds a `TOS' target, which allows you to create rules in
@@ -2714,6 +2854,14 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+Helper match support
+CONFIG_IP_NF_MATCH_HELPER
+  Helper matching allows you to match packets in dynamic connections
+  tracked by a conntrack-helper, ie. ip_conntrack_ftp
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `Y'.
+
 TCPMSS match support
 CONFIG_IP_NF_MATCH_TCPMSS
   This option adds a `tcpmss' match, which allows you to examine the
@@ -2731,7 +2879,7 @@
   which can only be viewed through syslog.
 
   The appropriate userspace logging daemon (ulogd) may be obtained from
-  http://www.gnumonks.org/projects/ulogd
+  <http://www.gnumonks.org/projects/ulogd>
 
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `N'.
@@ -2766,6 +2914,15 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+EUI64 address check (EXPERIMENTAL)
+CONFIG_IP6_NF_MATCH_EUI64
+  This module performs checking on the IPv6 source address
+  Compares the last 64 bits with the EUI64 (delivered
+  from the MAC address) address
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 MAC address match support
 CONFIG_IP6_NF_MATCH_MAC
   mac matching allows you to match packets based on the source
@@ -2774,6 +2931,14 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+length match support
+CONFIG_IP6_NF_MATCH_LENGTH
+  This option allows you to match the length of a packet against a
+  specific value or range of values.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 Netfilter MARK match support
 CONFIG_IP6_NF_MATCH_MARK
   Netfilter mark matching allows you to match packets based on the
@@ -3278,6 +3443,16 @@
   a module, say M here and read <file:Documentation/modules.txt>.
   If unsure, say N.
 
+CONFIG_SYNCLINK_CS
+  Enable support for the SyncLink PC Card serial adapter, running
+  asynchronous and HDLC communications up to 512Kbps. The port is
+  selectable for RS-232, V.35, RS-449, RS-530, and X.21
+
+  This driver may be built as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called synclinkmp.o.  If you want to do that, say M
+  here.
+
 ACP Modem (Mwave) support
 CONFIG_MWAVE
   The ACP modem (Mwave) for Linux is a WinModem. It is composed of a
@@ -3511,6 +3686,16 @@
 
   When in doubt, say N.
 
+ACPI PCI Hotplug driver
+CONFIG_HOTPLUG_PCI_ACPI
+  Say Y here if you have a system that supports PCI Hotplug using
+  ACPI.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called acpiphp.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
 MCA support
 CONFIG_MCA
   MicroChannel Architecture is found in some IBM PS/2 machines and
@@ -5007,6 +5192,12 @@
   Say Y here if you need PCMCIA support for your PC-style parallel
   ports. If unsure, say N.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  parport_cs.o
+
 Support foreign hardware
 CONFIG_PARPORT_OTHER
   Say Y here if you want to be able to load driver modules to support
@@ -5311,6 +5502,12 @@
   be inserted in and removed from the running kernel whenever you
   want). Most people won't need this and can say N.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  ipip.o
+
 GRE tunnels over IP
 CONFIG_NET_IPGRE
   Tunneling means encapsulating data of one protocol type within
@@ -5323,6 +5520,12 @@
   tunneling" above). In addition, GRE allows multicast redistribution
   through the tunnel.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  ip_gre.o
+
 Broadcast GRE over IP
 CONFIG_NET_IPGRE_BROADCAST
   One application of GRE/IP is to construct a broadcast WAN (Wide Area
@@ -5404,14 +5607,6 @@
 
   It is safe to say N here for now.
 
-# 2.5 tree only
-IPv6: routing messages via old netlink
-CONFIG_IPV6_NETLINK
-  You can say Y here to receive routing messages from the IPv6 code
-  through the old netlink interface. However, a better option is to
-  say Y to "Kernel/User network link driver" and to "Routing
-  messages" instead.
-
 Kernel httpd acceleration
 CONFIG_KHTTPD
   The kernel httpd acceleration daemon (kHTTPd) is a (limited) web
@@ -5653,6 +5848,12 @@
   This driver is experimental, which means that it may not work.
   See the file <file:Documentation/networking/ltpc.txt>.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  ltpc.o
+
 COPS LocalTalk PC card support
 CONFIG_COPS
   This allows you to use COPS AppleTalk cards to connect to LocalTalk
@@ -5662,6 +5863,12 @@
   networking support, above.
   Please read the file <file:Documentation/networking/cops.txt>.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  cops.o
+
 Dayna firmware support
 CONFIG_COPS_DAYNA
   Support COPS compatible cards with Dayna style firmware (Dayna
@@ -5810,6 +6017,11 @@
   useful if some other computer on your local network has a direct
   amateur radio connection.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called bpqether.o.
+
 High-speed (DMA) SCC driver for AX.25
 CONFIG_DMASCC
   This is a driver for high-speed SCC boards, i.e. those supporting
@@ -5874,9 +6086,10 @@
   port and includes some of the functions of a Terminal Node
   Controller. If you have one of those, say Y here.
 
-  If you want to compile this as a module ( = code which can be
+  If you want to compile the driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called yam.o.
 
 BAYCOM picpar and par96 driver for AX.25
 CONFIG_BAYCOM_PAR
@@ -6166,34 +6379,6 @@
 
   If unsure, say N.
 
-# 2.5 tree only
-Kernel/User network link driver
-CONFIG_NETLINK
-  This driver allows for two-way communication between the kernel and
-  user processes.  It does so by creating a new socket family,
-  PF_NETLINK.  Over this socket, the kernel can send and receive
-  datagrams carrying information.  It is documented on many systems in
-  netlink(7).
-
-  So far, the kernel uses this feature to publish some network related
-  information if you say Y to "Routing messages", below. You also need
-  to say Y here if you want to use arpd, a daemon that helps keep the
-  internal ARP cache (a mapping between IP addresses and hardware
-  addresses on the local network) small.  The ethertap device, which
-  lets user space programs read and write raw Ethernet frames, also
-  needs the network link driver.
-
-  If unsure, say Y.
-
-# 2.5 tree only
-Routing messages
-CONFIG_RTNETLINK
-  If you say Y here, user space programs can receive some network
-  related routing information over the netlink. 'rtmon', supplied
-  with the iproute2 package (<ftp://ftp.inr.ac.ru/>), can read and
-  interpret this data.  Information sent to the kernel over this link
-  is ignored.
-
 Netlink device emulation
 CONFIG_NETLINK_DEV
   This option will be removed soon. Any programs that want to use
@@ -6202,6 +6387,12 @@
   the real netlink socket.
   This is a backward compatibility option, choose Y for now.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  netlink_dev.o
+
 Asynchronous Transfer Mode (ATM)
 CONFIG_ATM
   ATM is a high-speed networking technology for Local Area Networks
@@ -6540,6 +6731,12 @@
   boards supported by this driver, and for further information
   on the use of this driver.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  cciss.o
+
 SCSI tape drive support for Smart Array 5xxx
 CONFIG_CISS_SCSI_TAPE
   When enabled (Y), this option allows SCSI tape drives and SCSI medium
@@ -7048,6 +7245,11 @@
   intended to replace the previous aic7xxx driver maintained by Doug
   Ledford since Doug is no longer maintaining that driver.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called aic7xxx.o.
+
 Adaptec I2O RAID support
 CONFIG_SCSI_DPT_I2O
   This driver supports all of Adaptec's I2O based RAID controllers as 
@@ -7244,6 +7446,11 @@
   Say Y here to compile in support for the Compaq StorageWorks Fibre
   Channel 64-bit/66Mhz Host Bus Adapter.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called cpqfc.o.
+
 DMX3191D SCSI support
 CONFIG_SCSI_DMX3191D
   This is support for Domex DMX3191D SCSI Host Adapters.
@@ -7401,6 +7608,11 @@
   Unless you have an NCR manufactured machine, the chances are that
   you do not have this SCSI card, so say N.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called NCR_D700.o.
+
 HP LASI SCSI support for 53c700/710
 CONFIG_SCSI_LASI700
   This is a driver for the lasi baseboard in some parisc machines
@@ -7469,6 +7681,11 @@
   Please read <file:drivers/scsi/sym53c8xx_2/Documentation.txt> for more
   information.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called sym53c8xx.o.
+
 PCI DMA addressing mode
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE
   This option only applies to PCI-SCSI chip that are PCI DAC capable 
@@ -7531,6 +7748,11 @@
   Please read <file:drivers/scsi/README.ncr53c8xx> for more
   information.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ncr53c8xx.o.
+
 SYM53C8XX Version 1 SCSI support
 CONFIG_SCSI_SYM53C8XX
   This driver supports all the features of recent 53C8XX chips (used
@@ -7556,6 +7778,11 @@
   Please read <file:drivers/scsi/README.ncr53c8xx> for more
   information.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called sym53c8xx.o.
+
 Synchronous transfer frequency in MHz
 CONFIG_SCSI_NCR53C8XX_SYNC
   The SCSI Parallel Interface-2 Standard defines 5 classes of transfer
@@ -8128,10 +8355,10 @@
   in the kernel source in <file:drivers/scsi/gdth.c> and
   <file:drivers/scsi/gdth.h.>
 
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  If you want to compile it as a module, say M here and read
-  <file:Documentation/modules.txt>.
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called gdth.o.
 
 IOMEGA parallel port (ppa - older drives)
 CONFIG_SCSI_PPA
@@ -8221,6 +8448,11 @@
   important data. This is primarily of use to people trying to debug
   the middle and upper layers of the SCSI subsystem. If unsure, say N.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called scsi_debug.o.
+
 Fibre Channel and FC4 SCSI support
 CONFIG_FC4
   Fibre Channel is a high speed serial protocol mainly used to
@@ -8648,9 +8880,10 @@
   a modem (not a synchronous or ISDN modem) to contact your ISP, you
   need this option.
 
-  This code is also available as a module (code which can be inserted
-  into and removed from the running kernel).  If you want to compile
-  it as a module, say M here and read <file:Documentation/modules.txt>.
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ppp_async.o.
 
   If unsure, say Y.
 
@@ -8660,10 +8893,10 @@
   (HDLC) tty devices, such as the SyncLink adapter. These devices
   are often used for high-speed leased lines like T1/E1.
 
-  This code is also available as a module (code which can be inserted
-  into and removed from the running kernel).  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ppp_synctty.o.
 
 PPP Deflate compression
 CONFIG_PPP_DEFLATE
@@ -8674,10 +8907,10 @@
   Deflate compression method as well for this to be useful.  Even if
   they don't support it, it is safe to say Y here.
 
-  This code is also available as a module (code which can be inserted
-  into and removed from the running kernel).  If you want to compile
-  it as a module, say M here and read
-  <file:Documentation/modules.txt>.
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ppp_deflate.o.
 
 PPP BSD-Compress compression
 CONFIG_PPP_BSDCOMP
@@ -9096,6 +9329,11 @@
   configure your card and that /etc/pcmcia/wireless.opts works :
   <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called hermes.o.
+
 Hermes 802.11b in PLX9052 based PCI adaptor support
 CONFIG_PLX_HERMES
   Enable support for PCMCIA cards supported by the "Hermes" (aka
@@ -9134,6 +9372,11 @@
   configure your card and that /etc/pcmcia/wireless.opts works:
   <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called orinoco_cs.o.
+
 Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards
 CONFIG_AIRO
   This is the standard Linux driver to support Cisco/Aironet ISA and
@@ -9168,6 +9411,11 @@
   for location).  You also want to check out the PCMCIA-HOWTO,
   available from <http://www.tldp.org/docs.html#howto>.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called airo_cs.o.
+
 Aviator/Raytheon 2.4MHz wireless support
 CONFIG_PCMCIA_RAYCS
   Say Y here if you intend to attach an Aviator/Raytheon PCMCIA
@@ -9353,6 +9601,11 @@
   of the Cisco HDLC/PPP driver (syncppp.c).
   The SyncLink WAN driver (in character devices) must also be enabled.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called syncppp.o.
+
 FarSync T-Series X.21 (and V.35/V.24) cards
 CONFIG_FARSYNC
   This driver supports the FarSync T-Series X.21 (and V.35/V.24) cards
@@ -9558,6 +9811,20 @@
   whenever you want).  If you want to compile it as a module, say M
   here and read <file:Documentation/modules.txt>.
 
+CONFIG_NET_SCH_HTB
+  Say Y here if you want to use the Hierarchical Token Buckets (HTB)
+  packet scheduling algorithm for some of your network devices. See
+  URL <http://luxik.cdi.cz/~devik/qos/htb/> for complete manual and
+  in-depth articles.
+
+  HTB is very similar to the CBQ regarding its goals however is has 
+  different properties and different algorithm.
+
+  This code is also available as a module called sch_htb.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want).  If you want to compile it as a module, say M
+  here and read <file:Documentation/modules.txt>.
+
 CSZ packet scheduler
 CONFIG_NET_SCH_CSZ
   Say Y here if you want to use the Clark-Shenker-Zhang (CSZ) packet
@@ -9839,6 +10106,11 @@
 
   At this point, the driver can only be compiled as a module.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called hostess_sv11.o.
+
 COSA/SRP sync serial board support
 CONFIG_COSA
   This is a driver for COSA and SRP synchronous serial boards. These
@@ -10133,7 +10405,7 @@
 
   Read linux/Documentation/networking/slicecom.txt for help on
   configuring and using SliceCOM interfaces. Further info on these cards
-  can be found at http://www.itc.hu or <info@itc.hu>.
+  can be found at <http://www.itc.hu> or <info@itc.hu>.
 
 Support for HDLC and syncPPP protocols on MultiGate boards
 CONFIG_COMX_PROTO_PPP
@@ -10207,6 +10479,11 @@
   Generic HDLC driver currently supports raw HDLC, Cisco HDLC, Frame
   Relay, synchronous Point-to-Point Protocol (PPP) and X.25.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called hdlc.o.
+
   If unsure, say N here.
 
 Raw HDLC support
@@ -10259,6 +10536,11 @@
 
   Note that N2csu and N2dds cards are not supported by this driver.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called n2.o.
+
   If unsure, say N here.
 
 Moxa C101 support
@@ -10267,6 +10549,11 @@
   Technologies Co., Ltd. If you have such a card,
   say Y here and see <http://hq.pm.waw.pl/pub/hdlc/>
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called c101.o.
+
   If unsure, say N here.
 
 Ethernet (10 or 100Mbit)
@@ -10474,12 +10761,14 @@
   in case your mainboard has memory consistency issues.  If unsure,
   say N.
 
-Support for automatic channel equalization
+Support for uncommon RTL-8139 rev. K (automatic channel equalization)
 CONFIG_8139TOO_TUNE_TWISTER
-  This implements a function which might come in handy in case you are
-  using low quality on long cabling. It tries to match the transceiver
-  to the cable characteristics. This is experimental since hardly
-  documented by the manufacturer.  If unsure, say N.
+  This implements a function which might come in handy in case you
+  are using low quality on long cabling. It is required for RealTek
+  RTL-8139 revision K boards, and totally unused otherwise.  It tries
+  to match the transceiver to the cable characteristics. This is
+  experimental since hardly documented by the manufacturer.
+  If unsure, say Y.
 
 Support for older RTL-8129/8130 boards
 CONFIG_8139TOO_8129
@@ -10488,6 +10777,14 @@
   instead of an internal one.  Disabling this option will save some
   memory by making the code size smaller.  If unsure, say Y.
 
+Use older RX-reset method
+CONFIG_8139_OLD_RX_RESET
+  The 8139too driver was recently updated to contain a more rapid
+  reset sequence, in the face of severe receive errors.  This "new"
+  RX-reset method should be adequate for all boards.  But if you
+  experience problems, you can enable this option to restore the
+  old RX-reset behavior.  If unsure, say N.
+
 SiS 900/7016 PCI Fast Ethernet Adapter support
 CONFIG_SIS900
   This is a driver for the Fast Ethernet PCI network cards based on
@@ -10609,6 +10906,16 @@
   Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0.  See also
   <http://www.sun.com/products-n-solutions/hardware/docs/pdf/806-3985-10.pdf>.
 
+  This chip is also used by Apple under the name GMAC in all their recent
+  machines starting with the first iBook. This includes all AGP capable
+  Apple machines except some early G4s and iMacs that still used a
+  Tulip chip. This driver obsoletes the GMAC driver for these machines.
+  
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called sungem.o.
+
 Broadcom Tigon3 support
 CONFIG_TIGON3
   This driver supports Broadcom Tigon3 based gigabit Ethernet cards.
@@ -10639,6 +10946,123 @@
   say M here and read <file:Documentation/modules.txt>.  This is
   recommended.  The module will be called dl2k.o.
 
+EtherExpress Pro/100 support (e100, Alternate Intel driver)
+CONFIG_E100
+  This driver supports Intel(R) PRO/100 family of adapters, which
+  includes:
+
+     Controller  Adapter Name                       Board IDs
+     ----------  ------------                       ---------
+
+     82558       PRO/100+ PCI Adapter               668081-xxx,
+                                                    689661-xxx
+     82558       PRO/100+ Management Adapter        691334-xxx,
+                                                    701738-xxx,
+                                                    721383-xxx
+     82558       PRO/100+ Dual Port Server Adapter  714303-xxx,
+                                                    711269-xxx,
+                                                    A28276-xxx
+     82558       PRO/100+ PCI Server Adapter        710550-xxx
+     82550       PRO/100 S Server Adapter           752438-xxx
+     82559                                          A56831-xxx,
+                                                    A10563-xxx,
+                                                    A12171-xxx,
+                                                    A12321-xxx,
+                                                    A12320-xxx,
+                                                    A12170-xxx
+                                                    748568-xxx
+                                                    748565-xxx
+     82550       PRO/100 S Desktop Adapter          751767-xxx
+     82559                                          748592-xxx,
+                                                    A12167-xxx,
+                                                    A12318-xxx,
+                                                    A12317-xxx,
+                                                    A12165-xxx,
+                                                    748569-xxx
+     82559       PRO/100+ Server Adapter            729757-xxx
+     82559       PRO/100 S Management Adapter       748566-xxx,
+                                                    748564-xxx
+     82550       PRO/100 S Dual Port Server Adapter A56831-xxx
+     82551       PRO/100 M Desktop Adapter          A80897-xxx
+                 PRO/100 S Advanced Management Adapter
+                                                    747842-xxx,
+                                                    745171-xxx
+     CNR         PRO/100 VE Desktop Adapter         A10386-xxx,
+                                                    A10725-xxx,
+                                                    A23801-xxx,
+                                                    A19716-xxx
+                 PRO/100 VM Desktop Adapter         A14323-xxx,
+                                                    A19725-xxx,
+                                                    A23801-xxx,
+                                                    A22220-xxx,
+                                                    A23796-xxx
+
+
+  To verify that your adapter is supported, find the board ID number
+  on the adapter. Look for a label that has a barcode and a number
+  in the format 123456-001 (six digits hyphen three digits). Match
+  this to the list of numbers above.
+
+  For more information on how to identify your adapter, go to the
+  Adapter & Driver ID Guide at:
+
+    http://support.intel.com/support/network/adapter/pro100/21397.htm
+
+  For the latest Intel PRO/100 network driver for Linux, see:
+
+    http://appsr.intel.com/scripts-df/support_intel.asp
+
+  More specific information on configuring the driver is in
+  <file:Documentation/networking/e100.txt>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called e100.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+Intel(R) PRO/1000 Gigabit Ethernet support
+CONFIG_E1000
+  This driver supports Intel(R) PRO/1000 gigabit ethernet family of
+  adapters, which includes:
+
+     Controller  Adapter Name                         Board IDs
+     ----------  ------------                         ---------
+     82542       PRO/1000 Gigabit Server Adapter      700262-xxx,
+                                                      717037-xxx
+     82543       PRO/1000 F Server Adapter            738640-xxx,
+                                                      A38888-xxx
+     82543       PRO/1000 T Server Adapter            A19845-xxx,
+                                                      A33948-xxx
+     82544       PRO/1000 XT Server Adapter           A51580-xxx
+     82544       PRO/1000 XF Server Adapter           A50484-xxx
+     82544       PRO/1000 T Desktop Adapter           A62947-xxx
+     82540       PRO/1000 MT Desktop Adapter          A78408-xxx
+     82545       PRO/1000 MT Server Adapter           A92165-xxx
+     82546       PRO/1000 MT Dual Port Server Adapter A92111-xxx
+     82545       PRO/1000 MF Server Adapter           A91622-xxx
+     82545       PRO/1000 MF Server Adapter(LX)       A91624-xxx
+     82546       PRO/1000 MF Dual Port Server Adapter A91620-xxx 
+
+  For more information on how to identify your adapter, go to the
+  Adapter & Driver ID Guide at:
+
+   <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+  For general information and support, go to the Intel support
+  website at:
+
+   <http://support.intel.com>
+
+  More specific information on configuring the driver is in 
+  <file:Documentation/networking/e1000.txt>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called e1000.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
 AMD LANCE and PCnet (AT1500 and NE2100) support
 CONFIG_LANCE
   If you have a network (Ethernet) card of this type, say Y and read
@@ -10798,10 +11222,10 @@
   <file:Documentation/networking/vortex.txt> and in the comments at
   the beginning of <file:drivers/net/3c59x.c>.
 
-  If you want to compile this as a module ( = code which can be
+  If you want to compile the driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt> as well as
-  <file:Documentation/networking/net-modules.txt>.
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called 3c59x.o.
 
 Other ISA cards
 CONFIG_NET_ISA
@@ -10852,6 +11276,11 @@
   documentation in <file:Documentation/networking/arcnet.txt> for more
   information about using arc0e and arc0s.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called rfc1051.o.
+
 Enable standard ARCNet packet format (RFC 1201)
 CONFIG_ARCNET_1201
   This allows you to use RFC1201 with your ARCnet card via the virtual
@@ -10861,12 +11290,22 @@
   ARCnet documentation in <file:Documentation/networking/arcnet.txt>
   for more information about using arc0.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called rfc1201.o.
+
 Enable raw mode packet interface
 CONFIG_ARCNET_RAW
   ARCnet "raw mode" packet encapsulation, no soft headers.  Unlikely
   to work unless talking to a copy of the same Linux arcnet driver,
   but perhaps marginally faster in that case.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called arc-rawmode.o.
+
 ARCnet COM90xx (normal) chipset driver
 CONFIG_ARCNET_COM90xx
   This is the chipset driver for the standard COM90xx cards. If you
@@ -11115,6 +11554,11 @@
   More specific information and updates are available from
   <http://www.scyld.com/network/natsemi.html>.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called natsemi.o.
+
 NatSemi workaround for high errors
 CONFIG_NATSEMI_CABLE_MAGIC
   Some systems see lots of errors with NatSemi ethernet controllers
@@ -11171,6 +11615,11 @@
   boards with this driver should be possible, but has not been tested
   up to now due to lack of hardware.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ibmlana.o.
+
 EISA, VLB, PCI and on board controllers
 CONFIG_NET_PCI
   This is another class of network cards which attach directly to the
@@ -11340,12 +11789,22 @@
   cards. Specifications and data at
   <http://www.myson.com.hk/mtd/datasheet/>.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called fealnx.o.
+
 LP486E on board Ethernet
 CONFIG_LP486E
   Say Y here to support the 82596-based on-board Ethernet controller
   for the Panther motherboard, which is one of the two shipped in the
   Intel Professional Workstation.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called lp486e.o.
+
 ICL EtherTeam 16i/32 support
 CONFIG_ETH16I
   If you have a network (Ethernet) card of this type, say Y and read
@@ -11431,6 +11890,11 @@
   More specific information and updates are available from
   <http://www.scyld.com/network/epic100.html>.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called epic100.o.
+
 DEC LANCE Ethernet controller support
 CONFIG_DECLANCE
   This driver is for the series of Ethernet controllers produced by
@@ -11448,6 +11912,19 @@
   More specific information and updates are available from
   <http://www.scyld.com/network/sundance.html>.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called sundance.o.
+
+Sundance Alta memory-mapped I/O support
+CONFIG_SUNDANCE_MMIO
+  Enable memory-mapped I/O for interaction with Sundance NIC registers.
+  Do NOT enable this by default, PIO (enabled when MMIO is disabled)
+  is known to solve bugs on certain chips.
+
+  If unsure, say N.
+
 Sun3/Sun3x on-board LANCE support
 CONFIG_SUN3LANCE
   Most Sun3 and Sun3x motherboards (including the 3/50, 3/60 and 3/80)
@@ -11795,6 +12272,11 @@
   This is support for the DIGITAL series of EISA (DEFEA) and PCI
   (DEFPA) controllers which can connect you to a local FDDI network.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called defxx.o.
+
 SysKonnect FDDI PCI support
 CONFIG_SKFP
   Say Y here if you have a SysKonnect FDDI PCI adapter.
@@ -12181,6 +12663,12 @@
   them. It will also allow you to select individual drivers for 
   particular hardware and users of MTD devices. If unsure, say N.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  mtdcore.o
+
 MTD debugging support
 CONFIG_MTD_DEBUG
   This turns on low-level debugging for the entire MTD sub-system.
@@ -12193,6 +12681,12 @@
   a separate MTD device, you require this option to be enabled. If
   unsure, say 'Y'.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  mtdpart.o
+
   Note, however, that you don't need this option for the DiskOnChip
   devices. Partitioning on NFTL 'devices' is a different - that's the
   'normal' form of partitioning used on a block device.
@@ -12213,6 +12707,12 @@
   SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
   example.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  redboot.o
+
 Compaq bootldr partition table parsing
 CONFIG_MTD_BOOTLDR_PARTS
   The Compaq bootldr deals with multiple 'images' in flash devices
@@ -12254,6 +12754,12 @@
   memory chips, and also use ioctl() to obtain information about
   the device, or to erase parts of it.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  mtdchar.o
+
 Caching block device access to MTD devices
 CONFIG_MTD_BLOCK
   Although most flash chips have an erase size too large to be useful
@@ -12274,6 +12780,12 @@
   You do not need this option for use with the DiskOnChip devices. For
   those, enable NFTL support (CONFIG_NFTL) instead.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  mtdblock.o
+
 Readonly block device access to MTD devices
 CONFIG_MTD_BLOCK_RO
   This allows you to mount read-only file systems (such as cramfs)
@@ -12283,6 +12795,12 @@
   You do not need this option for use with the DiskOnChip devices. For
   those, enable NFTL support (CONFIG_NFTL) instead.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  mtdblock_ro.o
+
 FTL (Flash Translation Layer) support
 CONFIG_FTL
   This provides support for the original Flash Translation Layer which
@@ -12297,6 +12815,12 @@
   permitted to copy, modify and distribute the code as you wish. Just
   not use it.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  ftl.o
+
 NFTL (NAND Flash Translation Layer) support
 CONFIG_NFTL
   This provides support for the NAND Flash Translation Layer which is
@@ -12311,6 +12835,12 @@
   permitted to copy, modify and distribute the code as you wish. Just
   not use it.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  nftl.o
+
 Write support for NFTL (EXPERIMENTAL)
 CONFIG_NFTL_RW
   If you're lucky, this will actually work. Don't whinge if it
@@ -12327,6 +12857,12 @@
   option. Visit <http://www.amd.com/products/nvd/overview/cfi.html>
   for more information on CFI.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  cfi_probe.o
+
 CFI Advanced configuration options
 CONFIG_MTD_CFI_ADV_OPTIONS
   If you need to specify a specific endianness for access to flash
@@ -12419,6 +12955,12 @@
   commands, including some which are not CFI-compatible and hence 
   cannot be used with the CONFIG_MTD_CFI_INTELxxx options.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  sharp.o
+
 AMD compatible flash chip support (non-CFI)
 CONFIG_MTD_AMDSTD
   This option enables support for flash chips using AMD-compatible
@@ -12427,16 +12969,34 @@
 
   It also works on AMD compatible chips that do conform to CFI.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  amd_flash.o
+
 Support for RAM chips in bus mapping
 CONFIG_MTD_RAM
   This option enables basic support for RAM chips accessed through 
   a bus mapping driver.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  map_ram.o
+
 Support for ROM chips in bus mapping
 CONFIG_MTD_ROM
   This option enables basic support for ROM chips accessed through 
   a bus mapping driver.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  map_rom.o
+
 JEDEC device support
 CONFIG_MTD_JEDEC
   Enable older older JEDEC flash interface devices for self
@@ -12446,6 +13006,12 @@
   chips. WARNING!!!! This code does not compile and is incomplete as
   are the specific JEDEC devices drivers.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  jedec.o
+
 CFI Flash device mapped on StrongARM SA11x0
 CONFIG_MTD_SA1100
   This enables access to the flash chips on most platforms based on
@@ -12476,6 +13042,12 @@
   configure the physical address and size of the flash chips on
   your particular board as well as the bus width.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  physmap.o
+
 Physical start location of flash chip mapping
 CONFIG_MTD_PHYSMAP_START
   This is the physical memory location at which the flash chips
@@ -12529,6 +13101,12 @@
   Dual-in-line JEDEC chip. This 'mapping' driver supports that
   arrangement, implementing three MTD devices.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  sc520cdp.o
+
 Flash chip mapping on Arcom Control Systems SBC-MediaGX
 CONFIG_MTD_SBC_GXX
   This provides a driver for the on-board flash of Arcom Control
@@ -12626,6 +13204,12 @@
   Computer. More information on the board is available at
   <http://www.octagonsystems.com/Products/5066/5066.html>.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  octagon-5066.o
+
 JEDEC Flash device mapped on Tempustech VMAX SBC301
 CONFIG_MTD_VMAX
   This provides a 'mapping' driver which supports the way in which
@@ -12633,11 +13217,23 @@
   Board Computer. More information on the board is available at
   <http://www.tempustech.com/tt301.htm>.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  vmax301.o
+
 Support for NAND flash devices
 CONFIG_MTD_NAND
   This enables support for accessing all type of NAND flash
   devices.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  nand.o
+
 Support for software ECC algorithm
 CONFIG_MTD_NAND_ECC
   This enables software-based ECC for use with NAND flash chips. It
@@ -12663,6 +13259,12 @@
   This provides an MTD device driver for the M-Systems DiskOnChip
   1000 devices, which are obsolete so you probably want to say 'N'.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  doc1000.o
+
 M-Systems Disk-On-Chip 2000 and Millennium support
 CONFIG_MTD_DOC2000
   This provides an MTD device driver for the M-Systems DiskOnChip
@@ -12678,6 +13280,12 @@
   emulate a block device by using a kind of file system on the flash
   chips.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  doc2000.o
+
 Alternative Disk-On-Chip Millennium support
 CONFIG_MTD_DOC2001
   This provides an alternative MTD device driver for the M-Systems 
@@ -12692,6 +13300,12 @@
   emulate a block device by using a kind of file system on the flash
   chips.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  doc2001.o
+
 Probe for DiskOnChip devices
 CONFIG_MTD_DOCPROBE
   This isn't a real config option, it's derived.
@@ -12751,6 +13365,12 @@
   particularly useful on the 2.2 kernels on PPC architectures as there
   was limited kernel space to deal with.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  pmc551.o
+
 PMC551 256M DRAM Bugfix
 CONFIG_MTD_PMC551_BUGFIX
   Some of Ramix's PMC551 boards with 256M configurations have invalid
@@ -12769,12 +13389,24 @@
   you can still use it for storage or swap by using this driver to
   present it to the system as a Memory Technology Device.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  slram.o
+
 Debugging RAM test driver
 CONFIG_MTD_MTDRAM
   This enables a test MTD device driver which uses vmalloc() to
   provide storage.  You probably want to say 'N' unless you're
   testing stuff.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  mtdram.o
+
 MTDRAM erase block size in KB
 CONFIG_MTDRAM_ERASE_SIZE
   This allows you to configure the size of the erase blocks in the
@@ -12817,6 +13449,12 @@
   the system regardless of media presence.  Device nodes created
   with this driver will return -ENODEV upon access.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  map_absent.o
+
 MTD emulation using block device
 CONFIG_MTD_BLKMTD
   This driver allows a block device to appear as an MTD. It would
@@ -12827,6 +13465,12 @@
     Testing MTD users (eg JFFS2) on large media and media that might
     be removed during a write (using the floppy drive).
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  blkmtd.o
+
 Cirrus CDB89712 evaluation board mappings
 CONFIG_MTD_CDB89712
   This enables access to the flash or ROM chips on the CDB89712 board.
@@ -12844,6 +13488,12 @@
   non-CFI Intel chips (that code is in MTD CVS and should shortly be sent
   for inclusion in Linus' tree)
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  jedec_probe.o
+
 BIOS flash chip on Intel L440GX boards
 CONFIG_MTD_L440GX
   Support for treating the BIOS flash chip on Intel L440GX motherboards
@@ -12851,6 +13501,12 @@
 
   BE VERY CAREFUL.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  l440gx.o
+
 28F160xx flash driver for LART
 CONFIG_MTD_LART
   This enables the flash driver for LART. Please note that you do
@@ -13108,9 +13764,9 @@
   The module will be called wacom.o.  If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-Aiptek 8000U tablet support
+Aiptek 6000U/8000U tablet support
 CONFIG_USB_AIPTEK
-  Say Y here if you want to use the USB version of the Aiptek 8000U
+  Say Y here if you want to use the USB version of the Aiptek 6000U/8000U
   tablet.  Make sure to say Y to "Event interface support"
   (CONFIG_INPUT_EVDEV) as well.
 
@@ -13242,7 +13898,6 @@
   inserted in and removed from the running kernel whenever you want).
   The module will be called audio.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
-			
 
 USB Modem (CDC ACM) support
 CONFIG_USB_ACM
@@ -13418,6 +14073,14 @@
 CONFIG_USB_SERIAL_KEYSPAN_USA19W
   Say Y here to include firmware for the USA-19W converter.
 
+USB Keyspan USA-19QW Firmware
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW
+  Say Y here to include firmware for the USA-19QW converter.
+
+USB Keyspan USA-19QI Firmware
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI
+  Say Y here to include firmware for the USA-19QI converter.
+
 USB Keyspan USA-49W Firmware
 CONFIG_USB_SERIAL_KEYSPAN_USA49W
   Say Y here to include firmware for the USA-49W converter.
@@ -13710,7 +14373,7 @@
 CONFIG_USB_RTL8150
   Say Y here if you have RTL8150 based usb-ethernet adapter.
   Send me (petkan@users.sourceforge.net) any comments you may have.
-  You can also check for updates at http://pegasus2.sourceforge.net/
+  You can also check for updates at <http://pegasus2.sourceforge.net/>
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -13761,6 +14424,7 @@
 CONFIG_USB_CATC
   Say Y if you want to use one of the following 10Mbps USB Ethernet
   device based on the EL1210A chip. Supported devices are:
+    Belkin F5U011
     Belkin F5U111
     CATC NetMate
     CATC NetMate II
@@ -13940,6 +14604,11 @@
   Say Y here to include additional code to support the Sandisk SDDR-09
   SmartMedia reader in the USB Mass Storage driver.
 
+SanDisk SDDR-55 SmartMedia support
+CONFIG_USB_STORAGE_SDDR55
+  Say Y here to include additional code to support the Sandisk SDDR-55
+  SmartMedia reader in the USB Mass Storage driver.
+
 USB Diamond Rio500 support
 CONFIG_USB_RIO500
   Say Y here if you want to connect a USB Rio500 mp3 player to your
@@ -13949,7 +14618,7 @@
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called rio500.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
+  a module, say M here and read <file:Documenatation/modules.txt>.
 
 USB Auerswald ISDN device support
 CONFIG_USB_AUERSWALD
@@ -13959,7 +14628,26 @@
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called auerswald.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
+  a module, say M here and read <file:Documenatation/modules.txt>
+
+CONFIG_USB_TIGL
+  If you own a Texas Instruments graphing calculator and use a 
+  TI-GRAPH LINK USB cable (aka SilverLink), then you might be 
+  interested in this driver.
+
+  If you enable this driver, you will be able to communicate with
+  your calculator through a set of device nodes under /dev.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called tiglusb.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+  If you don't know what the SilverLink cable is or what a Texas
+  Instruments graphing calculator is, then you probably don't need this
+  driver.
+
+  If unsure, say N.
 
 Tieman Voyager USB Braille display support
 CONFIG_USB_BRLVOYAGER
@@ -13972,6 +14660,18 @@
   The module will be called brlvger.o. If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
+USBLCD support
+CONFIG_USB_LCD
+  Say Y here if you want to connect an USBLCD to your computer's
+  USB port. The USBLCD is a small USB interface board for
+  alphanumeric LCD modules. See <http://www.usblcd.de> for more
+  information.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usblcd.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
 D-Link DSB-R100 FM radio support
 CONFIG_USB_DSBR
   Say Y here if you want to connect this type of radio to your
@@ -14257,6 +14957,27 @@
   The module will be called bluetooth.o. If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
+USB MIDI support
+CONFIG_USB_MIDI
+  Say Y here if you want to connect a USB MIDI device to your
+  computer's USB port. This driver is for devices that comply with
+  'Universal Serial Bus Device Class Definition for MIDI Device'.
+
+  The following devices are known to work:
+    * Steinberg USB2MIDI
+    * Roland MPU64
+    * Roland PC-300
+    * Roland SC8850
+    * Roland UM-1
+    * Roland UM-2
+    * Roland UA-100
+    * Yamaha MU1000
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usb-midi.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
 Minix fs support
 CONFIG_MINIX_FS
   Minix is a simple operating system used in many classes about OS's.
@@ -14314,12 +15035,13 @@
 
 Publish some reiserfs-specific info under /proc/fs/reiserfs
 CONFIG_REISERFS_PROC_INFO
-  Create under /proc/fs/reiserfs hierarchy of files, displaying
-  various ReiserFS statistics and internal data on the expense of
-  making your kernel or module slightly larger (+8 KB).  This also
-  increases amount of kernel memory required for each mount.  Almost
-  everyone but ReiserFS developers and people fine-tuning reiserfs or
-  tracing problems should say N.
+  Create under /proc/fs/reiserfs a hierarchy of files, displaying
+  various ReiserFS statistics and internal data at the expense of making
+  your kernel or module slightly larger (+8 KB). This also increases the
+  amount of kernel memory required for each mount by 440 bytes.
+  It isn't useful to average persons, and you probably can't measure the
+  performance cost of it.  If you are fine-tuning reiserfs, say Y,
+  otherwise say N.
 
 Second extended fs support
 CONFIG_EXT2_FS
@@ -14441,6 +15163,35 @@
   Because this option adds considerably to the size of each buffer,
   most people will want to say N here.
 
+BeOS filesystem support (BeFS) (read only)
+CONFIG_BEFS_FS
+  The BeOS File System (BeFS) is the native file system of Be, Inc's
+  BeOS. Notable features include support for arbitrary attributes
+  on files and directories, and database-like indices on selected
+  attributes. (Also note that this driver doesn't make those features
+  available at this time). It is a 64 bit filesystem, so it supports
+  extremely large volumes and files.
+
+  If you use this filesystem, you should also say Y to at least one
+  of the NLS (native language support) options below.
+
+  If you don't know what this is about, say N.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called befs.o.
+
+Debug BeFS
+CONFIG_BEFS_DEBUG
+  If you say Y here, you can use the 'debug' mount option to enable
+  debugging output from the driver. This is unlike previous versions
+  of the driver, where enabling this option would turn on debugging
+  output automatically.
+
+  Example:
+  mount -t befs /dev/hda2 /mnt -o debug
+
 BFS file system support
 CONFIG_BFS_FS
   Boot File System (BFS) is a file system used under SCO UnixWare to
@@ -14884,13 +15635,10 @@
   If you would like to include the NFSv3 server as well as the NFSv2
   server, say Y here.  If unsure, say Y.
 
-Provide NFS over TCP server support DEVELOPER ONLY
+Provide NFS over TCP server support EXPERIMENTAL
 CONFIG_NFSD_TCP
-  If you are a developer and want to work on fixing problems with
-  NFS server over TCP support, say Y here.  If unsure, say N.
-
-  Some problems can be found by looking for FIXME in
-  <file:net/sunrpc/svcsock.c>.
+  Enable NFS service over TCP connections.  This the officially
+  still experimental, but seems to work well.
 
 OS/2 HPFS file system support
 CONFIG_HPFS_FS
@@ -15331,12 +16079,6 @@
   were partitioned using EFI GPT.  Presently only useful on the
   IA-64 platform.
 
-/dev/guid support (EXPERIMENTAL)
-CONFIG_DEVFS_GUID
-  Say Y here if you would like to access disks and partitions by
-  their Globally Unique Identifiers (GUIDs) which will appear as
-  symbolic links in /dev/guid.
-
 Ultrix partition table support
 CONFIG_ULTRIX_PARTITION
   Say Y here if you would like to be able to read the hard disk
@@ -15345,9 +16087,11 @@
 
 IBM disk label and partition support
 CONFIG_IBM_PARTITION
-  Say Y here if you would like to be able to read the hard disk
-  partition table format used by IBM DASD disks operating under CMS.
-  Otherwise, say N.
+  You have to say Y here if you would like to be able to read volume 
+  labels of IBM DASD disks. These can be ECKD DASD disks with 
+  compatible disk layout (cdl) and standard Linux disk layout (ldl), 
+  FBA DASD disks and CMS reserved minidisks.
+  Otherwise, say N and you will not be able to access these disks.
 
 ADFS file system support
 CONFIG_ADFS_FS
@@ -15375,6 +16119,25 @@
   hard drives and ADFS-formatted floppy disks. This is experimental
   codes, so if you're unsure, say N.
 
+JFS filesystem support
+CONFIG_JFS_FS
+  This is a port of IBM's Journalling Filesystem .  More information is
+  available in the file Documentation/filesystems/jfs.txt.
+
+  If you do not intend to use the JFS filesystem, say N.
+
+JFS Debugging
+CONFIG_JFS_DEBUG
+  If you are experiencing any problems with the JFS filesystem, say
+  Y here.  This will result in additional debugging messages to be
+  written to the system log.  Under normal circumstances, this
+  results in very little overhead.
+
+JFS Statistics
+CONFIG_JFS_STATISTICS
+  Enabling this option will cause statistics from the JFS file system
+  to be made available to the user in the /proc/fs/jfs/ directory.
+
 /dev/pts file system for Unix98 PTYs
 CONFIG_DEVPTS_FS
   You should say Y here if you said Y to "Unix98 PTY support" above.
@@ -16487,6 +17250,17 @@
   The module will be called synclink.o.  If you want to do that, say M
   here.
 
+CONFIG_SYNCLINKMP
+  Enable support for the SyncLink Multiport (2 or 4 ports)
+  serial adapter, running asynchronous and HDLC communications up
+  to 2.048Mbps. Each ports is independently selectable for
+  RS-232, V.35, RS-449, RS-530, and X.21
+
+  This driver may be built as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called synclinkmp.o.  If you want to do that, say M
+  here.
+
 Synchronous HDLC line discipline support
 CONFIG_N_HDLC
   Allows synchronous HDLC communications with tty device drivers that
@@ -17929,20 +18703,6 @@
   computer, say `Y' here to support its built-in watchdog timer
   feature.  See the help for CONFIG_WATCHDOG for discussion.
 
-W83877F Watchdog Timer
-CONFIG_W83877F_WDT
-  This is the driver for the hardware watchdog on the W83877F chipset
-  as used in EMACS PC-104 motherboards (and likely others).  This
-  watchdog simply watches your kernel to make sure it doesn't freeze,
-  and if it does, it reboots your computer after a certain amount of
-  time.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module is called mixcomwd.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.  Most
-  people will say N.
-
 ALi M7101 Watchdog Timer
 CONFIG_ALIM7101_WDT
   This is the driver for the hardware watchdog on the ALi M7101 PMU
@@ -18007,11 +18767,11 @@
   module, say M here and read <file:Documentation/modules.txt>.  Most
   people will say N.
 
-SuperH 3/4 Watchdog
+SuperH Watchdog
 CONFIG_SH_WDT
   This driver adds watchdog support for the integrated watchdog in the
-  SuperH 3 and 4 processors. If you have one of these processors, say Y,
-  otherwise say N.
+  SuperH 3, 4 and 5 processors. If you have one of these processors, say
+  Y, otherwise say N.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -18051,6 +18811,12 @@
   Toshiba Linux utilities web site at:
   <http://www.buzzard.org.uk/toshiba/>.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  toshiba.o
+
   Say Y if you intend to run this kernel on a Toshiba portable.
   Say N otherwise.
 
@@ -18067,6 +18833,12 @@
   You can force loading on unsupported models by passing the
   parameter `force=1' to the module. Use at your own risk.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  i8k.o
+
   For more information on this driver and for utilities that make
   use of the module see the I8K Linux Utilities web site at:
   <http://www.debian.org/~dz/i8k/>.
@@ -18102,6 +18874,12 @@
   MSR accesses are directed to a specific CPU on multi-processor
   systems.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  msr.o
+
 /dev/cpu/*/cpuid - CPU information support
 CONFIG_X86_CPUID
   This device gives processes access to the x86 CPUID instruction to
@@ -18109,6 +18887,12 @@
   with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to
   /dev/cpu/31/cpuid.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  cpuid.o
+
 SBC-60XX Watchdog Timer
 CONFIG_60XX_WDT
  This driver can be used with the watchdog timer found on some
@@ -18187,9 +18971,10 @@
 CONFIG_NVRAM
   If you say Y here and create a character special file /dev/nvram
   with major number 10 and minor number 144 using mknod ("man mknod"),
-  you get read and write access to the 50 bytes of non-volatile memory
-  in the real time clock (RTC), which is contained in every PC and
-  most Ataris.
+  you get read and write access to the extra bytes of non-volatile
+  memory in the real time clock (RTC), which is contained in every PC
+  and most Ataris.  The actual number of bytes varies, depending on the
+  nvram in the system, but is usually 114 (128-14 for the RTC).
 
   This memory is conventionally called "CMOS RAM" on PCs and "NVRAM"
   on Ataris. /dev/nvram may be used to view settings there, or to
@@ -19406,6 +20191,12 @@
   Say Y or M if you have a sound system driven by ESS's Maestro 3
   PCI sound chip.
 
+ForteMedia FM801 driver
+CONFIG_SOUND_FORTE
+  Say Y or M if you want driver support for the ForteMedia FM801 PCI
+  audio controller (Abit AU10, Genius Sound Maker, HP Workstation
+  zx2000, and others).
+
 Adlib Cards
 CONFIG_SOUND_ADLIB
   Includes ASB 64 4D. Information on programming AdLib cards is
@@ -19581,16 +20372,6 @@
   hardware debugging with a logic analyzer and need to see all traffic
   on the bus.
 
-AU1000 serial console
-CONFIG_AU1000_SERIAL_CONSOLE
-  If you have an Alchemy AU1000 processor (MIPS based) and you want
-  to use a console on a serial port, say Y.  Otherwise, say N.
-
-AU1000 serial support
-CONFIG_AU1000_UART
-  If you have an Alchemy AU1000 processor (MIPS based) and you want
-  to use serial ports, say Y.  Otherwise, say N.
-
 AU1000 ethernet controller on SGI MIPS system
 CONFIG_MIPS_AU1000_ENET
   If you have an Alchemy Semi AU1000 ethernet controller
@@ -19671,6 +20452,11 @@
   method as well for this to be useful. Even if they don't support it,
   it is safe to say Y here.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called isdn_bsdcomp.o.
+
 Support audio via ISDN
 CONFIG_ISDN_AUDIO
   If you say Y here, the modem-emulator will support a subset of the
@@ -19705,6 +20491,11 @@
 
   Please read the file <file:Documentation/isdn/README.diversion>.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called dss1_divert.o.
+
 ICN 2B and 4B support
 CONFIG_ISDN_DRV_ICN
   This enables support for two kinds of ISDN-cards made by a German
@@ -19729,6 +20520,11 @@
   You need will need the loopctrl utility from the latest isdn4k-utils
   package to set up this driver.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called isdnloop.o.
+
 HiSax SiemensChipSet driver support
 CONFIG_ISDN_DRV_HISAX
   This is a driver supporting the Siemens chipset on various
@@ -19794,7 +20590,6 @@
   Enable this if you like to use ISDN in US on a NI1 basic rate
   interface.
 
-# 2.4 tree only
 Maximum number of cards supported by HiSax
 CONFIG_HISAX_MAX_CARDS
   This is used to allocate a driver-internal structure array with one
@@ -20024,15 +20819,30 @@
   This enables the PCMCIA client driver for the Elsa PCMCIA MicroLink
   card.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called elsa_cs.o.
+
 Sedlbauer PCMCIA cards
 CONFIG_HISAX_SEDLBAUER_CS
   This enables the PCMCIA client driver for the Sedlbauer Speed Star
   and Speed Star II cards.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called sedlbauer_cs.o.
+
 CONFIG_HISAX_AVM_A1_CS
   This enables the PCMCIA client driver for the AVM A1 / Fritz!Card
   PCMCIA cards.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called avma1_cs.o.
+
 ST5481 USB ISDN modem
 CONFIG_HISAX_ST5481
   This enables the driver for ST5481 based USB ISDN adapters,
@@ -20074,6 +20884,11 @@
   Say Y here to use your Eicon active ISDN card with ISDN4Linux
   isdn module.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called eicon.o.
+
 Eicon PCI DIVA Server BRI/PRI/4BRI support
 CONFIG_ISDN_DRV_EICON_PCI
   Say Y here if you have an Eicon Diva Server (BRI/PRI/4BRI) ISDN
@@ -20096,6 +20911,11 @@
   cards and will provide its own IDI interface. You should say N
   here.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called divas.o.
+
 Support AT-Fax Class 1 and 2 commands
 CONFIG_ISDN_TTY_FAX
   If you say Y here, the modem-emulator will support a subset of the
@@ -20124,6 +20944,11 @@
   standardized libcapi20 to access this functionality.  You should say
   Y/M here.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called capi.o.
+
 CAPI2.0 Middleware support
 CONFIG_ISDN_CAPI_MIDDLEWARE
   This option will enhance the capabilities of the /dev/capi20
@@ -20146,12 +20971,22 @@
   supported by a CAPI driver, but still want to use old features like
   ippp interfaces or ttyI emulation, say Y/M here.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called capidrv.o.
+
 AVM B1 ISA support
 CONFIG_ISDN_DRV_AVMB1_B1ISA
   Enable support for the ISA version of the AVM B1 card.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called b1isa.o.
+
 AVM B1 PCI support
-CONFIG_ISDN_DRV_AVMB1_B1PCI
+CONFIG_ISDN_DRV_AVMB1_B1CICI
   Enable support for the PCI version of the AVM B1 card.
 
 AVM B1 PCI V4 support
@@ -20163,25 +20998,50 @@
   Enable support for the AVM T1 T1B card.
   Note: This is a PRI card and handle 30 B-channels.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called t1isa.o.
+
 AVM B1/M1/M2 PCMCIA support
 CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
   Enable support for the PCMCIA version of the AVM B1 card.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called b1pcmcia.o.
+
 AVM B1/M1/M2 PCMCIA cs module
 CONFIG_ISDN_DRV_AVMB1_AVM_CS
   Enable the PCMCIA client driver for the AVM B1/M1/M2
   PCMCIA cards.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called avm_cs.o.
+
 AVM T1/T1-B PCI support
 CONFIG_ISDN_DRV_AVMB1_T1PCI
   Enable support for the AVM T1 T1B card.
   Note: This is a PRI card and handle 30 B-channels.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called t1pci.o.
+
 AVM C4/C2 support
 CONFIG_ISDN_DRV_AVMB1_C4
   Enable support for the AVM C4/C2 PCI cards.
   These cards handle 4/2 BRI ISDN lines (8/4 channels).
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called c4.o.
+
 Verbose reason code reporting (kernel size +=7K)
 CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
   If you say Y here, the AVM B1 driver will give verbose reasons for
@@ -20196,6 +21056,11 @@
   isdn4k-utils package. Please read the file
   <file:Documentation/isdn/README.act2000> for more information.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called act2000.o.
+
 Auvertech TurboPAM support
 CONFIG_ISDN_DRV_TPAM
   This enables support for the Auvertech TurboPAM ISDN-card.
@@ -20217,6 +21082,11 @@
   Please read the file <file:Documentation/isdn/README.hysdn> for more
   information.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called hysdn.o.
+
 HYSDN CAPI 2.0 support
 CONFIG_HYSDN_CAPI
   Say Y here if you like to use Hypercope's CAPI 2.0 interface.
@@ -20283,7 +21153,7 @@
 
 Kernel support for 32-bit ELF binaries
 CONFIG_BINFMT_ELF32
-  This allows you to run 32-bit Linux/ELF binaries on your Ultra.
+  This allows you to run 32-bit Linux/ELF binaries on your machine.
   Everybody wants this; say Y.
 
 Kernel support for 32-bit (ie. SunOS) a.out binaries
@@ -20369,7 +21239,7 @@
 DBRI Lowlevel Driver
 CONFIG_SPARCAUDIO_DBRI
   This driver supports the DBRI audio interface found on the SS10,
-  SS20, Sparcbook 3, and Voyager systems.
+  SS20, LX, Sparcbook 3, and Voyager systems.
 
 Dummy Lowlevel Driver
 CONFIG_SPARCAUDIO_DUMMY
@@ -20436,6 +21306,19 @@
   Say Y here to compile SCO support into the kernel or say M to
   compile it as module (sco.o).
 
+BNEP protocol support
+CONFIG_BLUEZ_BNEP
+  BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
+  emulation layer on top of Bluetooth. BNEP is required for Bluetooth
+  PAN (Personal Area Network).
+
+  To use BNEP, you will need user-space utilities provided in the 
+  BlueZ-PAN package.
+  For more information, see <http://bluez.sourceforge.net>.
+
+  Say Y here to compile BNEP support into the kernel or say M to
+  compile it as module (bnep.o).
+
 HCI UART driver
 CONFIG_BLUEZ_HCIUART
   Bluetooth HCI UART driver.
@@ -20464,18 +21347,9 @@
   Say Y here to compile support for Bluetooth USB devices into the
   kernel or say M to compile it as module (hci_usb.o).
 
-HCI USB firmware download support
-CONFIG_BLUEZ_USB_FW_LOAD
-  Firmware download support for Bluetooth USB devices.
-  This support is required for devices like Broadcom BCM2033.
-
-  HCI USB driver uses external firmware downloader program provided 
-  in BlueFW package.
-  For more information, see <http://bluez.sf.net/>.
-
 HCI USB zero packet support
 CONFIG_BLUEZ_USB_ZERO_PACKET
-  Support for USB zero packets. 
+  Support for USB zero packets.
   This option is provided only as a work around for buggy Bluetooth USB 
   devices. Do _not_ enable it unless you know for sure that your device 
   requires zero packets.
@@ -20494,11 +21368,37 @@
   Bluetooth HCI DTL1 (PC Card) driver.
   This driver provides support for Bluetooth PCMCIA devices with
   Nokia DTL1 interface:
-     Nokia Bluetooth PC Card, Socketcom Bluetooth CF module
+     Nokia Bluetooth Card
+     Socket Bluetooth CF Card
 
   Say Y here to compile support for HCI DTL1 devices into the
   kernel or say M to compile it as module (dtl1_cs.o).
 
+HCI BT3C (PC Card) device driver
+CONFIG_BLUEZ_HCIBT3C
+  Bluetooth HCI BT3C (PC Card) driver.
+  This driver provides support for Bluetooth PCMCIA devices with
+  3Com BT3C interface:
+     3Com Bluetooth Card (3CRWB6096)
+     HP Bluetooth Card
+
+  The HCI BT3C driver uses external firmware loader program provided in
+  the BlueFW package. For more information, see <http://bluez.sf.net>.
+
+  Say Y here to compile support for HCI BT3C devices into the
+  kernel or say M to compile it as module (bt3c_cs.o).
+
+HCI BlueCard (PC Card) device driver
+CONFIG_BLUEZ_HCIBLUECARD
+  Bluetooth HCI BlueCard (PC Card) driver.
+  This driver provides support for Bluetooth PCMCIA devices with
+  Anycom BlueCard interface:
+     Anycom Bluetooth PC Card
+     Anycom Bluetooth CF Card
+
+  Say Y here to compile support for HCI BlueCard devices into the
+  kernel or say M to compile it as module (bluecard_cs.o).
+
 # The following options are for Linux when running on the Hitachi
 # SuperH family of RISC microprocessors.
 
@@ -20527,6 +21427,11 @@
 
   "Area6" will work for most boards. For ADX, select "Area5".
 
+Disable data cache
+CONFIG_DCACHE_DISABLE
+  This option allows you to run the kernel with data cache disabled.
+  Say Y if you experience CPM lock-ups.
+
 #
 # m68k-specific kernel options
 # Documented by Chris Lawrence <mailto:quango@themall.net> et al.
@@ -20931,12 +21836,6 @@
   Hades. This increases the SCSI transfer rates at least ten times
   compared to PIO transfers.
 
-Sun3 NCR5380 OBIO SCSI
-CONFIG_SUN3_SCSI
-  This option will enable support for the OBIO (onboard io) NCR5380
-  SCSI controller found in the Sun 3/50 and 3/60.  Note that this
-  driver does not provide support for VME SCSI boards.
-
 Sun3x ESP SCSI
 CONFIG_SUN3X_ESP
   This option will enable support for the ESP SCSI controller found
@@ -20990,11 +21889,6 @@
   General Linux information on the Sun 3 series (now discontinued)
   is at <http://www.angelfire.com/ca2/tech68k/sun3.html>.
 
-Sun3x ESP SCSI driver
-CONFIG_SUN3X_ESP
-  The ESP was an on-board SCSI controller used on Sun 3/80
-  machines.  Say Y here to compile in support for it.
-
 PCMCIA NE2000 and compatibles support
 CONFIG_APNE
   If you have a PCMCIA NE2000 compatible adapter, say Y.  Otherwise,
@@ -21005,19 +21899,6 @@
   want). The module is called apne.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-Sun3/Sun3x on-board LANCE support
-CONFIG_SUN3LANCE
-  This driver enables support for the on-board LANCE ethernet adapter
-  found on the Sun 3/50, 3/60, and 3/80 workstations.  If you have 
-  one of these workstations, and would like Ethernet, say Y. 
-  Otherwise, say N.
-
-Sun3 on-board Intel 82586 support
-CONFIG_SUN3_82586
-  This driver enables support for the on-board Intel 82586 based Ethernet
-  adapter found on Sun 3/1xx and 3/2xx motherboards.  Note that this driver
-  does not support 82586-based adapters on additional VME boards.
-
 Atari Lance support
 CONFIG_ATARILANCE
   Say Y to include support for several Atari Ethernet adapters based
@@ -21354,6 +22235,8 @@
   Select APUS if configuring for a PowerUP Amiga.  More information is
   available at: <http://linux-apus.sourceforge.net/>.
 
+  Note that Total Impact briQ is handled as a CHRP machine.
+
 Synergy-Gemini
 CONFIG_GEMINI
   Select Gemini if configuring for a Synergy Microsystems' Gemini
@@ -21712,7 +22595,7 @@
 
   CU824:
     VMEBus Board with PCI extension with MPC8240 CPU
-    Manufacturer: MicroSys GmbH, http://www.microsys.de/
+    Manufacturer: MicroSys GmbH, <http://www.microsys.de/>
     Date of Release: early 2001 (?)
     End of life: -
     URL: <http://www.microsys.de/html/cu824.html>
@@ -22398,7 +23281,7 @@
   IPL device on another question, that pops up, when you select
   CONFIG_IPL.
 
-IPL from a /390 tape unit
+IPL from a S/390 tape unit
 CONFIG_IPL_TAPE
   Select this option if you want to IPL the image from a Tape.
 
@@ -22407,18 +23290,22 @@
   Select this option if you are running under VM/ESA and want 
   to IPL the image from the emulated card reader.
 
-Support for DASD hard disks
-CONFIG_DASD
-  Enable this option if you want to access DASDs directly utilizing
-  S/390s channel subsystem commands. This is necessary for running
-  natively on a single image or an LPAR.
+CONFIG_PFAULT
+  Select this option, if you want to use PFAULT pseudo page fault
+  handling under VM. If running native or in LPAR, this option
+  has no effect. If your VM does not support PFAULT, PAGEEX
+  pseudo page fault handling will be used.
+  Note that VM 4.2 supports PFAULT but has a bug in its
+  implementation that causes some problems.
+  Everybody who wants to run Linux under VM != VM4.2 should select
+  this option.
 
-Enable DASD fast write
-CONFIG_DASD_FAST_IO
-  Enable fast I/O for DASDs. That means that the next I/O command
-  is already issued at interrupt time, if an I/O request is pending.
-  This option gives significant speedup of I/O, because we don't
-  schedule the bottom-halves as often as Intel.
+CONFIG_SHARED_KERNEL
+  Select this option, if you want to share the text segment of the
+  Linux kernel between different VM guests. This reduces memory
+  usage with lots of guests but greatly increases kernel size.
+  You should only select this option if you know what you are
+  doing and want to exploit this feature.
 
 Support for IBM-style disk-labels (S/390)
 CONFIG_S390_PARTITION
@@ -22427,18 +23314,40 @@
   attached to another IBM mainframe operation system (OS/390, 
   VM/ESA, VSE/ESA).
 
+Support for DASD hard disks
+CONFIG_DASD
+  Enable this option if you want to access DASDs directly utilizing
+  S/390s channel subsystem commands. This is necessary for running
+  natively on a single image or an LPAR.
+
 Support for ECKD hard disks
 CONFIG_DASD_ECKD
-  ECKD devices are the most commonly used devices. You should enable
-  this option unless you are very sure you have no ECKD device.
+  ECKD (Extended Count Key Data) devices are the most commonly used 
+  devices on S/390s. You should enable this option unless you are 
+  very sure you have no ECKD device.
 
-CKD devices
-CONFIG_DASD_CKD
-  CKD devices are currently unsupported.
+ECKD demand loading
+CONFIG_DASD_AUTO_ECKD
+  This option enables demand loading of the ECKD module. 
 
 Support for FBA hard disks
 CONFIG_DASD_FBA
-  FBA devices are currently unsupported.
+  Select this option if you want to use FBA (Fixed Block) devices.
+  If you are not sure what it is, say "Y".
+
+FBA demand loading
+CONFIG_DASD_AUTO_FBA
+  This option enables demand loading of the FBA module. 
+
+Support for DIAG access to CMS reserved Disks
+CONFIG_DASD_DIAG
+  Select this option if you want to use CMS reserved Disks under VM
+  with the Diagnose250 command.  If you are not running under VM or
+  unsure what it is, say "N".
+
+DIAG demand loading
+CONFIG_DASD_AUTO_DIAG
+  This option enables demand loading of the DIAG module. 
 
 Merge some code into the kernel to make the image IPLable
 CONFIG_IPLABLE
@@ -22476,6 +23385,16 @@
   Include support for using an IBM HWC line-mode terminal as the Linux
   system console.
 
+Control Program Identification
+CONFIG_HWC_CPI
+  Allows for Control Program Identification via the HWC interface,
+  i.e. provides a mean to pass an OS instance name (system name)
+  to the machine.
+
+  This option should only be selected as a module since the
+  system name has to be passed as module parameter. The module
+  will be called hwc_cpi.o.
+
 S/390 tape device support
 CONFIG_S390_TAPE
   Select this option if you want to access channel-attached tape
@@ -22484,8 +23403,9 @@
   least one of the tape interface options and one of the tape
   hardware options in order to access a tape device.
   This option is also available as a module. The module will be
-  called tape390.o and include all selected interfaces and
-  hardware drivers.
+  called tape390.o and include all selected interfaces.
+  The hardware drivers will be seperate modules.
+  If unsure, say "Y".
 
 Support for tape character devices
 CONFIG_S390_TAPE_CHAR
@@ -22506,14 +23426,23 @@
 
 Support for 3490 tape hardware
 CONFIG_S390_TAPE_3490
-  Select this option if you want to access IBM 3480 magnetic
+  Select this option if you want to access IBM 3490 magnetic
   tape subsystems and 100% compatibles.
+  This option is also available as a module. The module will be
+  called tape3490.o. If CONFIG_S390_TAPE is selected as a module,
+  this hardware driver cannot be built-in but is only available
+  as a module.
   It is safe to say "Y" here.
 
 Support for 3480 tape hardware
 CONFIG_S390_TAPE_3480
-  Select this option if you want to access IBM 3490 magnetic
+  Select this option if you want to access IBM 3480 magnetic
   tape subsystems and 100% compatibles.
+  This option is also available as a module. The module will be
+  called tape3480.o. If CONFIG_S390_TAPE is selected as a module,
+  this hardware driver cannot be built-in but is only available
+  as a module.
+  It is safe to say "Y" here.
 
 CTC device support
 CONFIG_CTC
@@ -22524,12 +23453,6 @@
   available.  This option is also available as a module which will be
   called ctc.o.  If you do not know what it is, it's safe to say "Y".
 
-Support for DIAG access to CMS reserved Disks
-CONFIG_DASD_DIAG
-  Select this option if you want to use CMS reserved Disks under VM
-  with the Diagnose250 command.  If you are not running under VM or
-  unsure what it is, say "N".
-
 XPRAM disk support
 CONFIG_BLK_DEV_XPRAM
   Select this option if you want to use your expanded storage on S/390
@@ -22552,6 +23475,20 @@
   vehicle networking under VM or VIF.  This option is also available
   as a module which will be called iucv.o. If unsure, say "Y".
 
+Process warning machine checks
+CONFIG_MACHCHK_WARNING
+  Select this option if you want the machine check handler on IBM S/390 or 
+  zSeries to process warning machine checks (e.g. on power failures). 
+  If unsure, say "Y".
+
+Use chscs for Common I/O
+CONFIG_CHSC
+  Select this option if you want the s390 common I/O layer to use information
+  obtained by channel subsystem calls. This will enable Linux to process link
+  failures and resource accessibility events. Moreover, if you have procfs
+  enabled, you'll be able to toggle chpids logically offline and online. Even
+  if you don't understand what this means, you should say "Y".
+
 Kernel support for 31 bit ELF binaries
 CONFIG_S390_SUPPORT
   Select this option if you want to enable your system kernel to
@@ -22608,6 +23545,12 @@
   supported by this driver, and for further information on the use of
   this driver.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  cpqarray.o
+
 Show crashed user process info
 CONFIG_PROCESS_DEBUG
   Say Y to print all process fault locations to the console.  This is
@@ -23014,6 +23957,11 @@
   It is recommended to be used on a NetWinder, but it is not a
   necessity.
 
+Check for stack overflows
+CONFIG_DEBUG_STACKOVERFLOW
+  This option make do_IRQ() check for enough stack space beeing left.
+  This is safe to enable.
+
 Debug high memory support
 CONFIG_DEBUG_HIGHMEM
   This options enables addition error checking for high memory systems.
@@ -23222,13 +24170,24 @@
 
 SRM environment variables in procfs
 CONFIG_SRM_ENV
-  If you enable this option, a subdirectory called srm_environment
-  will give you access to the most important SRM environment
-  variables. If you've got an Alpha style system supporting
-  SRC, then it is a good idea to say Yes or Module to this driver.
+  If you enable this option, a subdirectory inside /proc called
+  /proc/srm_environment will give you access to the all important
+  SRM environment variables (those which have a name) and also
+  to all others (by their internal number).
+
+  SRM is something like a BIOS for Alpha machines. There are some
+  other such BIOSes, like AlphaBIOS, which this driver cannot
+  support (hey, that's not SRM!).
+
+  Despite the fact that this driver doesn't work on all Alphas (but
+  only on those which have SRM as their firmware), it's save to
+  build it even if your particular machine doesn't know about SRM
+  (or if you intend to compile a generic kernel). It will simply
+  not create those subdirectory in /proc (and give you some warning,
+  of course).
 
   This driver is also available as a module and will be called
-  srm_env.o if you build it as a module.
+  srm_env.o then.
 
 Footbridge internal watchdog
 CONFIG_21285_WATCHDOG
@@ -23449,6 +24408,11 @@
   This driver supports the use of zero copy on tx, checksum 
   validation on rx, and 64 bit addressing.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called ns83820.o.
+
 Toshiba Type-O IR Port device driver
 CONFIG_TOSHIBA_FIR
   Say Y here if you want to build support for the Toshiba Type-O IR
@@ -23505,6 +24469,11 @@
   used by IrTTY.  To activate support for ESI dongles you will have to
   start irattach like this: "irattach -d esi".
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called esi.o.
+
 ACTiSYS IR-220L and IR220L+ dongle
 CONFIG_ACTISYS_DONGLE
   Say Y here if you want to build support for the ACTiSYS IR-220L and
@@ -23515,6 +24484,11 @@
   dongles you will have to start irattach like this:
   "irattach -d actisys" or "irattach -d actisys+".
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called actisys.o.
+
 Tekram IrMate 210B dongle
 CONFIG_TEKRAM_DONGLE
   Say Y here if you want to build support for the Tekram IrMate 210B
@@ -23524,6 +24498,11 @@
   by IrTTY.  To activate support for Tekram dongles you will have to
   start irattach like this: "irattach -d tekram".
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called tekram.o.
+
 Greenwich GIrBIL dongle
 CONFIG_GIRBIL_DONGLE
   Say Y here if you want to build support for the Greenwich GIrBIL
@@ -23533,6 +24512,11 @@
   used by IrTTY.  To activate support for Greenwich dongles you will
   have to insert "irattach -d girbil" in the /etc/irda/drivers script.
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called girbil.o.
+
 Parallax LiteLink dongle
 CONFIG_LITELINK_DONGLE
   Say Y here if you want to build support for the Parallax Litelink
@@ -23542,6 +24526,23 @@
   used by IrTTY.  To activate support for Parallax dongles you will
   have to start irattach like this "irattach -d litelink".
 
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called litelink.o.
+
+Microchip MCP2120 dongle
+CONFIG_MCP2120_DONGLE
+  Say Y here if you want to build support for the Microchip MCP2120
+  dongle.  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The MCP2120 dongle attaches to
+  the normal 9-pin serial port connector, and can currently only be
+  used by IrTTY.  To activate support for MCP2120 dongles you will
+  have to insert "irattach -d mcp2120" in the /etc/irda/drivers script.
+
+  You must build this dongle yourself.  For more information see:
+  <http://www.eyetap.org/~tangf/irda_sir_linux.html>
+
 Old Belkin dongle
 CONFIG_OLD_BELKIN_DONGLE
   Say Y here if you want to build support for the Adaptec Airport 1000
@@ -23549,6 +24550,30 @@
   and read <file:Documentation/modules.txt>.  The module will be
   called old_belkin.o.  Some information is contained in the comments
   at the top of <file:drivers/net/irda/old_belkin.c>.
+ 
+ACTiSYS IR-200L dongle (Experimental)
+CONFIG_ACT200L_DONGLE
+  Say Y here if you want to build support for the ACTiSYS IR-200L
+  dongle. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt. The ACTiSYS IR-200L dongle attaches to
+  the normal 9-pin serial port connector, and can currently only be
+  used by IrTTY. To activate support for ACTiSYS IR-200L dongles
+  you will have to start irattach like this: "irattach -d act200l".
+
+Mobile Action MA600 dongle (Experimental)
+CONFIG_MA600_DONGLE
+  Say Y here if you want to build support for the Mobile Action MA600
+  dongle.  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The MA600 dongle attaches to
+  the normal 9-pin serial port connector, and can currently only be
+  tested on IrCOMM.  To activate support for MA600 dongles you will
+  have to insert "irattach -d ma600" in the /etc/irda/drivers script.
+  Note: irutils 0.9.15 requires no modification. irutils 0.9.9 needs
+  modification. For more information, download the following tar gzip
+  file.
+
+  There is a pre-compiled module on
+  <http://engsvr.ust.hk/~eetwl95/download/ma600-2.4.x.tar.gz>
 
 VME (Motorola and BVM) support
 CONFIG_VME
@@ -24400,15 +25425,19 @@
   As of the time of this writing, most hardware is DIG compliant,
   so the "DIG-compliant" option is usually the right choice.
 
-  HP-simulator   For the HP simulator
-                 (<http://software.hp.com/ia64linux/>).
+  HP-simulator   For the HP simulator (<http://software.hp.com/ia64linux/>).
+  HP-zx1	 For HP zx1 Platforms.
   SN1            For SGI SN1 Platforms.
   SN2            For SGI SN2 Platforms.
-  DIG-compliant  For DIG ("Developer's Interface Guide") compliant
-                 system.
+  DIG-compliant  For DIG ("Developer's Interface Guide") compliant systems.
 
   If you don't know what to do, choose "generic".
 
+CONFIG_IA64_HP_ZX1
+  Build a kernel that runs on HP zx1-based systems.  This adds support
+  for the zx1 IOMMU and makes root bus bridges appear in PCI config space
+  (required for zx1 agpgart support).
+
 CONFIG_IA64_SGI_SN_SIM
   Build a kernel that runs on both the SGI simulator AND on hardware.
   There is a very slight performance penalty on hardware for including this
@@ -24456,16 +25485,6 @@
   can select this option to disable the VHPT for debugging.  If you're
   unsure, answer N.
 
-Enable McKinley A-step specific code
-CONFIG_MCKINLEY_ASTEP_SPECIFIC
-  Select this option to build a kernel for an IA64 McKinley system
-  with any A-stepping CPU.
-
-Enable McKinley A0/A1-step specific code
-CONFIG_MCKINLEY_A0_SPECIFIC
-  Select this option to build a kernel for an IA64 McKinley system
-  with an A0 or A1 stepping CPU.
-
 Turn on compare-and-exchange bug checking (slow!)
 CONFIG_IA64_DEBUG_CMPXCHG
   Selecting this option turns on bug checking for the IA64
@@ -24490,9 +25509,7 @@
 CONFIG_IA64_PRINT_HAZARDS
   Selecting this option prints more information for Illegal Dependency
   Faults, that is, for Read after Write, Write after Write or Write
-  after Read violations.  This option is ignored if you are compiling
-  for an Itanium A step processor (CONFIG_ITANIUM_ASTEP_SPECIFIC).  If
-  you're unsure, select Y.
+  after Read violations.  If you're unsure, select Y.
 
 Performance monitor support
 CONFIG_PERFMON
@@ -24526,15 +25543,6 @@
   the IA32 instruction set.  Say Y here to build in kernel support for
   this.  If in doubt, say Y.
 
-/proc/efi/vars support
-CONFIG_EFI_VARS
-  If you say Y here, you are able to get EFI (Extensible Firmware
-  Interface) variable information in /proc/efi/vars.  You may read,
-  write, create, and destroy EFI variables through this interface.
-
-  To use this option, you have to check that the "/proc file system
-  support" (CONFIG_PROC_FS) is enabled, too.
-
 Physical memory granularity (16 MB)
 CONFIG_IA64_GRANULE_16MB
   IA64 identity-mapped regions use a large page size.  We'll call such
@@ -24642,6 +25650,18 @@
   Include in-kernel hooks for the xmon kernel monitor/debugger
   supported by the PPC port.
 
+Include BDI2000 debugger support
+CONFIG_BDI_SWITCH
+  Include in-kernel support for the Abatron BDI2000 debugger.  To
+  learn more about the Abatron BDI2000, visit the web page at
+  <http://www.abatron.ch/>.
+
+Add additional CFLAGS to the kernel build
+CONFIG_MORE_COMPILE_OPTIONS
+  If you want to add additional CFLAGS to the kernel build, such as
+  -g for KGDB, XMON or the BDI2000, enable this option and then
+  enter what you would like to add in the next question.
+
 Include kgdb kernel debugger
 CONFIG_KWDB
   Include in-kernel hooks for kdb, the source level debugger for the
@@ -24998,7 +26018,7 @@
   ethernet interface does, including firewalling, bridging, and of course
   IP traffic.  You will need the 'vconfig' tool from the VLAN project in
   order to effectively use VLANs.  See the VLAN web page for more
-  information:  http://www.candelatech.com/~greear/vlan.html  If unsure,
+  information:  <http://www.candelatech.com/~greear/vlan.html>  If unsure,
   you can safely say 'N'.
 
 ARC console support
@@ -25020,14 +26040,6 @@
   <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
   board at <http://www.mvista.com/allies/semiconductor/ite.html>.
 
-Use chscs for Common I/O
-CONFIG_CHSC
-  Select this option if you want the s390 common I/O layer to use information
-  obtained by channel subsystem calls. This will enable Linux to process link
-  failures and resource accessibility events. Moreover, if you have procfs
-  enabled, you'll be able to toggle chpids logically offline and online. Even
-  if you don't understand what this means, you should say "Y".
-
 Support ARM926T processor
 CONFIG_CPU_ARM926T
   This is a variant of the ARM920.  It has slightly different
@@ -25047,21 +26059,6 @@
   written) to implement the policy. If you don't understand what this
   is all about, it's safe to say 'N'.
 
-Automatic activation of DIAG module
-CONFIG_DASD_AUTO_DIAG
-  Enable this option if you want your DIAG discipline module loaded
-  on DASD driver startup.
-
-Automatic activation of ECKD module
-CONFIG_DASD_AUTO_ECKD
-  Enable this option if you want your ECKD discipline module loaded
-  on DASD driver startup.
-
-Automatic activation of FBA  module
-CONFIG_DASD_AUTO_FBA
-  Enable this option if you want your FBA discipline module loaded
-  on DASD driver startup.
-
 SiS
 CONFIG_DRM_SIS
   Choose this option if you have a SIS graphics card. AGP support is
@@ -25155,16 +26152,6 @@
 
   When in doubt, say N.
 
-Control-Program Identification
-CONFIG_HWC_CPI
-  This option enables the hardware console interface for system
-  identification This is commonly used for workload management and
-  gives you a nice name for the system on the service element.
-  Please select this option as a module since built-in operation is
-  completely untested.
-  You should only select this option if you know what you are doing,
-  need this feature and intend to run your kernel in LPAR.
-
 Enable autotest (llsc). Option to run cache test instead of booting
 CONFIG_IA64_SGI_AUTOTEST
   Build a kernel used for hardware validation. If you include the
@@ -25240,37 +26227,12 @@
   Say Y here to support tuning the ITE8172's IDE interface.  This makes
   it possible to set DMA channel or PIO opration and the transfer rate.
 
-Process warning machine checks
-CONFIG_MACHCHK_WARNING
-  Select this option if you want the machine check handler on IBM S/390 or
-  zSeries to process warning machine checks (e.g. on power failures).
-  If unsure, say "Y".
-
-Pseudo page fault support
-CONFIG_PFAULT
-  Select this option, if you want to use PFAULT pseudo page fault
-  handling under VM. If running native or in LPAR, this option
-  has no effect. If your VM does not support PFAULT, PAGEEX
-  pseudo page fault handling will be used.
-  Note that VM 4.2 supports PFAULT but has a bug in its
-  implementation that causes some problems.
-  Everybody who wants to run Linux under VM != VM4.2 should select
-  this option.
-
 Enable protocol mode for the L1 console
 CONFIG_SERIAL_SGI_L1_PROTOCOL
   Uses protocol mode instead of raw mode for the level 1 console on the
   SGI SN (Scalable NUMA) platform for IA64.  If you are compiling for
   an SGI SN box then Y is the recommended value, otherwise say N.
 
-VM shared kernel support
-CONFIG_SHARED_KERNEL
-  Select this option, if you want to share the text segment of the
-  Linux kernel between different VM guests. This reduces memory
-  usage with lots of guests but greatly increases kernel size.
-  You should only select this option if you know what you are
-  doing and want to exploit this feature.
-
 New bus configuration (EXPERIMENTAL)  
 CONFIG_TULIP_MWI
   This configures your Tulip card specifically for the card and
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/DocBook/Makefile linux-2.4.20/Documentation/DocBook/Makefile
--- linux-2.4.19/Documentation/DocBook/Makefile	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/DocBook/Makefile	2002-10-29 11:18:40.000000000 +0000
@@ -1,7 +1,8 @@
 BOOKS	:= wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \
 	   kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
 	   kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \
-	   deviceiobook.sgml procfs-guide.sgml tulip-user.sgml
+	   deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \
+	   journal-api.sgml
 
 PS	:=	$(patsubst %.sgml, %.ps, $(BOOKS))
 PDF	:=	$(patsubst %.sgml, %.pdf, $(BOOKS))
@@ -138,6 +139,17 @@
 parportbook.sgml: parportbook.tmpl $(TOPDIR)/drivers/parport/init.c
 	$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/parport/init.c <$< >$@
 
+
+JBDSOURCES :=  $(TOPDIR)/include/linux/jbd.h \
+	       $(TOPDIR)/fs/jbd/journal.c \
+	       $(TOPDIR)/fs/jbd/recovery.c \
+	       $(TOPDIR)/fs/jbd/transaction.c
+
+journal-api.sgml: journal-api.tmpl $(JBDSOURCES)
+	$(TOPDIR)/scripts/docgen   $(JBDSOURCES) \
+		<journal-api.tmpl >journal-api.sgml
+
+
 DVI	:=	$(patsubst %.sgml, %.dvi, $(BOOKS))
 AUX	:=	$(patsubst %.sgml, %.aux, $(BOOKS))
 TEX	:=	$(patsubst %.sgml, %.tex, $(BOOKS))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/DocBook/journal-api.tmpl linux-2.4.20/Documentation/DocBook/journal-api.tmpl
--- linux-2.4.19/Documentation/DocBook/journal-api.tmpl	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/DocBook/journal-api.tmpl	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,297 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<book id="LinuxJBDAPI">
+ <bookinfo>
+  <title>The Linux Journalling API</title>
+  <authorgroup>
+  <author>
+     <firstname>Roger</firstname>
+     <surname>Gammans</surname>
+     <affiliation>
+     <address>
+      <email>rgammans@computer-surgery.co.uk</email>
+     </address>
+    </affiliation>
+     </author> 
+  </authorgroup>
+  
+  <authorgroup>
+   <author>
+    <firstname>Stephen</firstname>
+    <surname>Tweedie</surname>
+    <affiliation>
+     <address>
+      <email>sct@redhat.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2002</year>
+   <holder>Roger Gammans</holder>
+  </copyright>
+
+<legalnotice>
+   <para>
+     This documentation 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.
+   </para>
+      
+   <para>
+     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.
+   </para>
+      
+   <para>
+     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
+   </para>
+      
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+  <chapter id="Overview">
+     <title>Overview</title>
+  <sect1>
+     <title>Details</title>
+<para>
+The journalling layer is  easy to use. You need to 
+first of all create a journal_t data structure. There are
+two calls to do this dependent on how you decide to allocate the physical
+media on which the journal resides. The journal_init_inode() call 
+is for journals stored in filesystem inodes, or the journal_init_dev()
+call can be use for journal stored on a raw device (in a continuous range 
+of blocks). A journal_t is a typedef for a struct pointer, so when
+you are finally finished make sure you call journal_destroy() on it
+to free up any used kernel memory.
+</para>
+
+<para>
+Once you have got your journal_t object you need to 'mount' or load the journal
+file, unless of course you haven't initialised it yet - in which case you
+need to call journal_create().
+</para>
+
+<para>
+Most of the time however your journal file will already have been created, but
+before you load it you must call journal_wipe() to empty the journal file.
+Hang on, you say , what if the filesystem wasn't cleanly umount()'d . Well, it is the 
+job of the client file system to detect this and skip the call to journal_wipe().
+</para>
+
+<para>
+In either case the next call should be to journal_load() which prepares the
+journal file for use. Note that journal_wipe(..,0) calls journal_skip_recovery() 
+for you if it detects any outstanding transactions in the journal and similarly
+journal_load() will call journal_recover() if necessary.
+I would advise reading fs/ext3/super.c for examples on this stage.
+[RGG: Why is the journal_wipe() call necessary - doesn't this needlessly 
+complicate the API. Or isn't a good idea for the journal layer to hide 
+dirty mounts from the client fs]
+</para>
+
+<para>
+Now you can go ahead and start modifying the underlying 
+filesystem. Almost.
+</para>
+
+
+<para>
+
+You still need to actually journal your filesystem changes, this
+is done by wrapping them into transactions. Additionally you
+also need to wrap the modification of each of the the buffers
+with calls to the journal layer, so it knows what the modifications
+you are actually making are. To do this use  journal_start() which
+returns a transaction handle.
+</para>
+
+<para>
+journal_start()
+and its counterpart journal_stop(), which indicates the end of a transaction
+are nestable calls, so you can reenter a transaction if necessary,
+but remember you must call journal_stop() the same number of times as
+journal_start() before the transaction is completed (or more accurately
+leaves the the update phase). Ext3/VFS makes use of this feature to simplify 
+quota support.
+</para>
+
+<para>
+Inside each transaction you need to wrap the modifications to the
+individual buffers (blocks). Before you start to modify a buffer you
+need to call journal_get_{create,write,undo}_access() as appropriate,
+this allows the journalling layer to copy the unmodified data if it
+needs to. After all the buffer may be part of a previously uncommitted
+transaction. 
+At this point you are at last ready to modify a buffer, and once
+you are have done so you need to call journal_dirty_{meta,}data().
+Or if you've asked for access to a buffer you now know is now longer 
+required to be pushed back on the device you can call journal_forget()
+in much the same way as you might have used bforget() in the past.
+
+</para>
+
+
+
+<para>
+A journal_flush() may be called at any time to commit and checkpoint
+all your transactions.
+</para>
+<para>
+
+Then at umount time , in your put_super() (2.4) or write_super() (2.5)
+you can then call journal_destroy() to clean up your in-core journal object.
+</para>
+
+
+<para>
+Unfortunately there a couple of ways the journal layer can cause a deadlock.
+The first thing to note is that each task can only have
+a single outstanding transaction at any one time, remember nothing
+commits until the outermost journal_stop(). This means
+you must complete the transaction at the end of each file/inode/address
+etc. operation you perform, so that the journalling system isn't re-entered
+on another journal. Since transactions can't be nested/batched 
+across differing journals, and another filesystem other than
+yours (say ext3) may be modified in a later syscall.
+</para>
+<para>
+
+The second case to bear in mind is that journal_start() can 
+block if there isn't enough space in the journal for your transaction 
+(based on the passed nblocks param) - when it blocks it merely(!) needs to
+wait for transactions to complete and be committed from other tasks, 
+so essentially we are waiting for journal_stop(). So to avoid 
+deadlocks you must treat journal_start/stop() as if they
+were semaphores and include them in your semaphore ordering rules to prevent 
+deadlocks. Note that journal_extend() has similar blocking behaviour to
+journal_start() so you can deadlock here just as easily as on journal_start().
+</para>
+<para>
+
+Try to reserve the right number of blocks the first time. ;-).
+</para>
+<para>
+Another wriggle to watch out for is your on-disk block allocation strategy.
+why? Because, if you undo a delete, you need to ensure you haven't reused any
+of the freed blocks in a later transaction. One simple way of doing this
+is make sure any blocks you allocate only have checkpointed transactions
+listed against them. Ext3 does this in ext3_test_allocatable(). 
+</para>
+
+<para>
+Lock is also providing through journal_{un,}lock_updates(),
+ext3 uses this when it wants a window with a clean and stable fs for a moment.
+eg. 
+<programlisting>
+
+	journal_lock_updates() //stop new stuff happening..
+	journal_flush()        // checkpoint everything.
+	..do stuff on stable fs
+	journal_unlock_updates() // carry on with filesystem use.
+</programlisting>
+
+The opportunities for abuse and DOS attacks with this should be obvious,
+if you allow unprivileged userspace to trigger codepaths containing these
+calls.
+
+<para>
+</sect1>
+<sect1>
+<title>Summary</title>
+<para>
+Using the journal is a matter of wrapping the different context changes,
+being each mount, each modification (transaction) and each changed buffer
+to tell the journalling layer about them.
+
+Here is a some pseudo code to give you an idea of how it works, as
+an example.
+<programlisting>
+  journal_t* my_jnrl = journal_create();
+  journal_init_{dev,inode}(jnrl,...)
+  if (clean) journal_wipe();
+  journal_load();
+
+   foreach(transaction) { /*transactions must be 
+                            completed before
+                            a syscall returns to 
+                            userspace*/
+
+          handle_t * xct=journal_start(my_jnrl);
+          foreach(bh) {
+                journal_get_{create,write,undo}_access(xact,bh);
+                if ( myfs_modify(bh) ) { /* returns true 
+                                        if makes changes */
+                           journal_dirty_{meta,}data(xact,bh);
+                } else {
+                           journal_forget(bh);
+                }
+          }
+          journal_stop(xct);
+   }
+   journal_destroy(my_jrnl);
+</programlisting>
+
+</chapter>
+
+  <chapter id="adt">
+     <title>Data Types</title>
+     <para>	
+	The journalling layer uses typedefs to 'hide' the concrete definitions
+	of the structures used. As a client of the JBD layer you can
+	just rely on the using the pointer as a magic cookie  of some sort.
+	
+	Obviously the hiding is not enforced as this is 'C'.
+	</para>
+	<sect1><title>Structures</title>
+!Iinclude/linux/jbd.h
+	</sect1>
+</chapter>
+
+  <chapter id="calls">
+     <title>Functions</title>
+     <para>	
+	The functions here are split into two groups those that
+	affect a journal as a whole, and those which are used to
+	manage transactions
+</para>
+	<sect1><title>Journal Level</title>
+!Efs/jbd/journal.c
+!Efs/jbd/recovery.c
+	</sect1>
+	<sect1><title>Transasction Level</title>
+!Efs/jbd/transaction.c	
+	</sect1>
+</chapter>
+<chapter>
+     <title>See also</title>
+	<para>
+	<citation>
+	   <ulink url="ftp://ftp.uk.linux.org/pub/linux/sct/fs/jfs/journal-design.ps.gz">
+	   	Journaling the Linux ext2fs Filesystem,LinuxExpo 98, Stephen Tweedie
+	   </ulink>
+	   </citation>
+	   </para>
+	   <para>
+	   <citation>
+	   <ulink url="http://olstrans.sourceforge.net/release/OLS2000-ext3/OLS2000-ext3.html">
+	   	Ext3 Journalling FileSystem , OLS 2000, Dr. Stephen Tweedie
+	   </ulink>
+	   </citation>
+	   </para>
+</chapter>
+
+</book>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/DocBook/kernel-hacking.tmpl linux-2.4.20/Documentation/DocBook/kernel-hacking.tmpl
--- linux-2.4.19/Documentation/DocBook/kernel-hacking.tmpl	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/DocBook/kernel-hacking.tmpl	2002-10-29 11:18:48.000000000 +0000
@@ -1091,18 +1091,17 @@
    <title>Initializing structure members</title>
 
    <para>
-    The preferred method of initializing structures is to use the
-    gcc Labeled Elements extension, eg:
+    The preferred method of initializing structures is to use
+    designated initialisers, as defined by ISO C99, eg:
    </para>
    <programlisting>
 static struct block_device_operations opt_fops = {
-        open:                   opt_open,
-        release:                opt_release,
-        ioctl:                  opt_ioctl,
-        check_media_change:     opt_media_change,
+        .open               = opt_open,
+        .release            = opt_release,
+        .ioctl              = opt_ioctl,
+        .check_media_change = opt_media_change,
 };
    </programlisting>
-
    <para>
     This makes it easy to grep for, and makes it clear which
     structure fields are set.  You should do this because it looks
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/DocBook/parportbook.tmpl linux-2.4.20/Documentation/DocBook/parportbook.tmpl
--- linux-2.4.19/Documentation/DocBook/parportbook.tmpl	2001-10-25 07:07:40.000000000 +0000
+++ linux-2.4.20/Documentation/DocBook/parportbook.tmpl	2002-10-29 11:18:32.000000000 +0000
@@ -595,7 +595,7 @@
    So, the first thing for the device driver to do is tell
    <literal>parport</literal> that it wants to know what parallel
    ports are on the system.  To do this, it uses the
-   <function>parport_register_device</function> function:
+   <function>parport_register_driver</function> function:
   </para>
 
   <funcsynopsis>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/SubmittingDrivers linux-2.4.20/Documentation/SubmittingDrivers
--- linux-2.4.19/Documentation/SubmittingDrivers	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/SubmittingDrivers	2002-10-29 11:18:49.000000000 +0000
@@ -2,9 +2,8 @@
 ---------------------------------------
 
 This document is intended to explain how to submit device drivers to the
-Linux 2.2 and 2.4 kernel trees. Note that if you are interested in video
-card drivers you should probably talk to XFree86 (http://www.xfree86.org) 
-instead.
+various kernel trees. Note that if you are interested in video card drivers
+you should probably talk to XFree86 (http://www.xfree86.org) instead.
 
 Also read the Documentation/SubmittingPatches document.
 
@@ -35,21 +34,22 @@
 	maintainer then please contact Alan Cox <alan@lxorguk.ukuu.org.uk>
 
 Linux 2.4:
-	This kernel tree is under active development. The same rules apply
-	as 2.2 but you may wish to submit your driver via linux-kernel (see
-	resources) and follow that list to track changes in API's. These
-	should no longer be occuring as we are now in a code freeze.
-	The final contact point for Linux 2.4 submissions is 	
-	<torvalds@transmeta.com>.
+	The same rules apply as 2.2. The final contact point for Linux 2.4 
+	submissions is Marcelo Tosatti <marcelo@conectiva.com.br>.
+
+Linux 2.5:
+	The same rules apply as 2.4 except that you should follow linux-kernel
+	to track changes in API's. The final contact point for Linux 2.5
+	submissions is Linus Torvalds <torvalds@transmeta.com>.
 
 What Criteria Determine Acceptance
 ----------------------------------
 
-Licensing:	The code must be released to us under the GNU General Public License. 
-		We don't insist on any kind of exclusively GPL licensing,
-		and if you wish the driver to be useful to other communities
-		such as BSD you may well wish to release under multiple
-		licenses.
+Licensing:	The code must be released to us under the
+		GNU General Public License. We don't insist on any kind
+		of exclusively GPL licensing, and if you wish the driver
+		to be useful to other communities such as BSD you may well
+		wish to release under multiple licenses.
 
 Interfaces:	If your driver uses existing interfaces and behaves like
 		other drivers in the same class it will be much more likely
@@ -64,12 +64,13 @@
 		maintain them just once seperate them out nicely and note
 		this fact.
 
-Portability:	Pointers are not always 32bits, people do not all have
-		floating point and you shouldn't use inline x86 assembler in 
-		your driver without careful thought. Pure x86 drivers
-		generally are not popular. If you only have x86 hardware it 
-		is hard to test portability but it is easy to make sure the
-		code can easily be made portable.
+Portability:	Pointers are not always 32bits, not all computers are little
+		endian, people do not all have floating point and you
+		shouldn't use inline x86 assembler in your driver without
+		careful thought. Pure x86 drivers generally are not popular.
+		If you only have x86 hardware it is hard to test portability
+		but it is easy to make sure the code can easily be made
+		portable.
 
 Clarity:	It helps if anyone can see how to fix the driver. It helps
 		you because you get patches not bug reports. If you submit a
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/SubmittingPatches linux-2.4.20/Documentation/SubmittingPatches
--- linux-2.4.19/Documentation/SubmittingPatches	2000-12-04 01:48:18.000000000 +0000
+++ linux-2.4.20/Documentation/SubmittingPatches	2002-10-29 11:18:31.000000000 +0000
@@ -161,7 +161,7 @@
 When sending patches to Linus, always follow step #6.
 
 Large changes are not appropriate for mailing lists, and some
-maintainers.  If your patch, uncompressed, exceeds 40Kb in size,
+maintainers.  If your patch, uncompressed, exceeds 40 kB in size,
 it is preferred that you store your patch on an Internet-accessible
 server, and provide instead a URL (link) pointing to your patch.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/cdrom/sonycd535 linux-2.4.20/Documentation/cdrom/sonycd535
--- linux-2.4.19/Documentation/cdrom/sonycd535	1998-05-21 01:54:34.000000000 +0000
+++ linux-2.4.20/Documentation/cdrom/sonycd535	2002-10-29 11:18:38.000000000 +0000
@@ -63,8 +63,8 @@
 Thanks also to Eberhard Moenkeberg (emoenke@gwdg.de) for prodding
 me to place this code into the mainstream Linux source tree
 (as of Linux version 1.1.91), as well as some patches to make
-it a better device citizen.  Further thanks to "S. Joel Katz"
-<stimpson@panix.com> for his MODULE patches (see details below),
+it a better device citizen.  Further thanks to Joel Katz
+<joelkatz@webchat.org> for his MODULE patches (see details below),
 Porfiri Claudio <C.Porfiri@nisms.tei.ericsson.se> for patches
 to make the driver work with the older CDU-510/515 series, and
 Heiko Eissfeldt <heiko@colossus.escape.de> for pointing out that
@@ -79,7 +79,7 @@
 ken@halcyon.com
 
 ------------------------------------------------------------------------------
-(The following is from Joel Katz <Stimpson@Panix.COM>.)
+(The following is from Joel Katz <joelkatz@webchat.org>.)
 
 	To build a version of sony535.o that can be installed as a module,
 use the following command:
@@ -103,7 +103,7 @@
 	I have an external drive, and I usually leave it powered off. I used
 to have to reboot if I needed to use the CDROM drive. Now I don't.
 
-	Even if you have an internal drive, why waste the 268K of memory
+	Even if you have an internal drive, why waste the 96K of memory
 (unswappable) that the driver uses if you use your CD-ROM drive infrequently?
 
 	This driver will not install (whether compiled in or loaded as a
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/filesystems/00-INDEX linux-2.4.20/Documentation/filesystems/00-INDEX
--- linux-2.4.19/Documentation/filesystems/00-INDEX	2001-06-20 18:10:27.000000000 +0000
+++ linux-2.4.20/Documentation/filesystems/00-INDEX	2002-10-29 11:18:40.000000000 +0000
@@ -6,6 +6,8 @@
 	- info and mount options for the Acorn Advanced Disc Filing System.
 affs.txt
 	- info and mount options for the Amiga Fast File System.
+befs.txt
+	- info for the BeOS file system (BFS)
 bfs.txt
 	- info for the SCO UnixWare Boot Filesystem (BFS).
 coda.txt
@@ -22,6 +24,8 @@
 	- info and mount options for the OS/2 HPFS.
 isofs.txt
 	- info and mount options for the ISO 9660 (CDROM) filesystem.
+jfs.txt
+	- info and mount options for the JFS filesystem.
 ncpfs.txt
 	- info on Novell Netware(tm) filesystem using NCP protocol.
 ntfs.txt
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/filesystems/Locking linux-2.4.20/Documentation/filesystems/Locking
--- linux-2.4.19/Documentation/filesystems/Locking	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/filesystems/Locking	2002-10-29 11:18:36.000000000 +0000
@@ -45,6 +45,10 @@
 	int (*revalidate) (struct dentry *);
 	int (*setattr) (struct dentry *, struct iattr *);
 	int (*getattr) (struct dentry *, struct iattr *);
+	int (*setxattr) (struct dentry *, const char *, void *, size_t, int);
+	ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
+	ssize_t (*listxattr) (struct dentry *, char *, size_t);
+	int (*removexattr) (struct dentry *, const char *);
 
 locking rules:
 	all may block
@@ -61,9 +65,13 @@
 follow_link:	no	no		no
 truncate:	yes	yes		no		(see below)
 setattr:	yes	if ATTR_SIZE	no
-permssion:	yes	no		no
+permission:	yes	no		no
 getattr:						(see below)
 revalidate:	no					(see below)
+setxattr:	yes	yes		no
+getxattr:	yes	yes		no
+listxattr:	yes	yes		no
+removexattr:	yes	yes		no
 	Additionally, ->rmdir() has i_zombie on victim and so does ->rename()
 in case when target exists and is a directory.
 	->rename() on directories has (per-superblock) ->s_vfs_rename_sem.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/filesystems/befs.txt linux-2.4.20/Documentation/filesystems/befs.txt
--- linux-2.4.19/Documentation/filesystems/befs.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/filesystems/befs.txt	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,111 @@
+BeOS filesystem for Linux
+
+Document last updated: Dec 6, 2001
+
+WARNING
+=======
+Make sure you understand that this is alpha software.  This means that the
+implementation is neither complete nor well-tested. 
+
+I DISCLAIM ALL RESPONSIBILTY FOR ANY POSSIBLE BAD EFFECTS OF THIS CODE!
+
+LICENSE
+=====
+This software is covered by the GNU General Public License. 
+See the file COPYING for the complete text of the license.
+Or the GNU website: <http://www.gnu.org/licenses/licenses.html>
+
+AUTHOR
+=====
+Current maintainer: Will Dyson <will_dyson@pobox.com>
+Has been working on the code since Aug 13, 2001. See the changelog for details.
+
+Original Author: Makoto Kato <m_kato@ga2.so-net.ne.jp>
+His orriginal code can still be found at: <http://hp.vector.co.jp/authors/VA008030/bfs/>
+Does anyone know of a more current email address for Makoto? He doesn't respond
+to the address given above...
+
+WHAT IS THIS DRIVER?
+==================
+This module implements the native filesystem of BeOS <http://www.be.com/>
+for the linux 2.4.1 and later kernels. Currently it is a read-only implementation.
+
+Which is it, BFS or BEFS?
+================
+Be, Inc said, "BeOS Filesystem is officially called BFS, not BeFS". 
+But Unixware Boot Filesystem is called bfs, too. And they are already in the
+kernel.
+Because of this nameing conflict, on Linux the BeOS filesystem is called befs.
+
+HOW TO INSTALL
+==============
+step 1.  Install the BeFS  patch into the source code tree of linux.
+
+Apply the patchfile to your kernel source tree.
+Assuming that your kernel source is in /foo/bar/linux and the patchfile is called
+patch-befs-xxx, you would do the following:
+
+	cd /foo/bar/linux
+	patch -p1 < /path/to/patch-befs-xxx
+
+if the patching step fails (i.e. there are rejected hunks), you can try to
+figure it out yourself (it shouldn't be hard), or mail the maintainer 
+(Will Dyson <will_dyson@pobox.com>) for help.
+
+step 2.  Configuretion & make kernel
+
+The linux kernel has many compile-time options. Most of them are beyond the
+scope of this document. I suggest the Kernel-HOWTO document as a good general
+reference on this topic. <http://www.linux.com/howto/Kernel-HOWTO.html>
+
+However, to use the BeFS module, you must enable it at configure time.
+
+	cd /foo/bar/linux
+	make menuconfig (or xconfig)
+
+The BeFS module is not a standard part of the linux kernel, so you must first
+enable support for experimental code under the "Code maturity level" menu.
+
+Then, under the "Filesystems" menu will be an option called "BeFS filesystem (experimental)",
+or something like that. Enable that option (it is fine to make it a module).
+
+Save your kernel configuration and then build your kernel.
+
+step 3.  Install
+
+See the kernel howto <http://www.linux.com/howto/Kernel-HOWTO.html> for
+instructions on this critical step.
+
+USING BFS
+=========
+To use the BeOS filesystem, use filesystem type 'befs'.
+
+ex)
+    mount -t befs /dev/fd0 /beos
+
+MOUNT OPTIONS
+=============
+uid=nnn        All files in the partition will be owned by user id nnn.
+gid=nnn	       All files in the partition will be in group nnn.
+iocharset=xxx  Use xxx as the name of the NLS translation table.
+debug          The driver will output debugging information to the syslog.
+
+HOW TO GET LASTEST VERSION
+==========================
+
+The latest version is currently available at:
+<http://befs-driver.sourceforge.net/>
+
+ANY KNOWN BUGS?
+===========
+As of Jan 20, 2002:
+	
+	None
+
+SPECIAL THANKS
+==============
+Dominic Giampalo ... Writing "Practical file system design with Be filesystem"
+Hiroyuki Yamada  ... Testing LinuxPPC.
+
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/filesystems/devfs/ChangeLog linux-2.4.20/Documentation/filesystems/devfs/ChangeLog
--- linux-2.4.19/Documentation/filesystems/devfs/ChangeLog	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/filesystems/devfs/ChangeLog	2002-10-29 11:18:33.000000000 +0000
@@ -1936,3 +1936,17 @@
 
 - Protected <scan_dir_for_removable> and <get_removable_partition>
   from changing directory contents
+===============================================================================
+Changes for patch v199.15
+
+- Switched to ISO C structure field initialisers
+
+- Switch to set_current_state() and move before add_wait_queue()
+
+- Updated README from master HTML file
+
+- Fixed devfs entry leak in <devfs_readdir> when *readdir fails
+===============================================================================
+Changes for patch v199.16
+
+- Fixed module unload race in <devfs_open>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/filesystems/devfs/README linux-2.4.20/Documentation/filesystems/devfs/README
--- linux-2.4.19/Documentation/filesystems/devfs/README	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/filesystems/devfs/README	2002-10-29 11:18:39.000000000 +0000
@@ -3,7 +3,7 @@
 
 Linux Devfs (Device File System) FAQ
 Richard Gooch
-7-APR-2002
+21-JUL-2002
 
 
 Document languages:
@@ -788,6 +788,9 @@
 make sure the kernel does not mount devfs at boot time
 
 
+make sure you have a correct /dev/console entry in your
+root file-system (where your disc-based /dev lives)
+
 create the /dev-state directory
 
 
@@ -1288,9 +1291,10 @@
 
 SCSI Generic Devices
 
-All SCSI CD-ROMs are placed under /dev/sg. A similar naming
-scheme is used as for SCSI discs. A SCSI generic device with the
-parameters:c=1,b=2,t=3,u=4 would appear as:
+The generic (aka. raw) interface for all SCSI devices are placed under
+/dev/sg. A similar naming scheme is used as for SCSI discs. A
+SCSI generic device with the parameters:c=1,b=2,t=3,u=4 would appear
+as:
 
 	/dev/sg/c1b2t3u4
 
@@ -1605,6 +1609,23 @@
 do that.
 
 
+I have extra or incorrect entries in /dev
+
+You may have stale entries in your dev-state area. Check for a
+RESTORE configuration line in your devfsd configuration
+(typically /etc/devfsd.conf). If you have this line, check
+the contents of the specified directory for stale entries. Remove
+any entries which are incorrect, then reboot.
+
+
+I get "Unable to open initial console" messages at boot
+
+This usually happens when you don't have devfs automounted onto
+/dev at boot time, and there is no valid
+/dev/console entry on your root file-system. Create a valid
+/dev/console device node.
+
+
 
 
 
@@ -1756,7 +1777,7 @@
 First, remember that no naming scheme will please everybody. You hate
 the scheme, others love it. Who's to say who's right and who's wrong?
 Ultimately, the person who writes the code gets to choose, and what
-exists now is a combination of the the choices made by the
+exists now is a combination of the choices made by the
 devfs author and the
 kernel maintainer (Linus).
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/filesystems/isofs.txt linux-2.4.20/Documentation/filesystems/isofs.txt
--- linux-2.4.19/Documentation/filesystems/isofs.txt	1999-05-26 17:01:43.000000000 +0000
+++ linux-2.4.20/Documentation/filesystems/isofs.txt	2002-10-29 11:18:33.000000000 +0000
@@ -29,3 +29,10 @@
   unhide        Show hidden files.
   session=x     Select number of session on multisession CD
   sbsector=xxx  Session begins from sector xxx
+
+Recommended documents about ISO 9660 standard are located at:
+http://www.y-adagio.com/public/standards/iso_cdromr/tocont.htm
+ftp://ftp.ecma.ch/ecma-st/Ecma-119.pdf
+Quoting from the PDF "This 2nd Edition of Standard ECMA-119 is technically 
+identical with ISO 9660.", so it is a valid and gratis substitute of the
+official ISO specification.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/filesystems/jfs.txt linux-2.4.20/Documentation/filesystems/jfs.txt
--- linux-2.4.19/Documentation/filesystems/jfs.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/filesystems/jfs.txt	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,43 @@
+IBM's Journaled File System (JFS) for Linux
+
+JFS Homepage:  http://oss.software.ibm.com/jfs/
+
+Team members
+------------
+Steve Best         sbest@us.ibm.com
+Dave Kleikamp      shaggy@austin.ibm.com  
+Barry Arndt        barndt@us.ibm.com
+Christoph Hellwig  hch@infradead.org
+
+The following mount options are supported:
+
+iocharset=name	Character set to use for converting from Unicode to
+		ASCII.  The default is compiled into the kernel as
+		CONFIG_NLS_DEFAULT.  Use iocharset=utf8 for UTF8
+		translations.  This requires CONFIG_NLS_UTF8 to be set
+		in the kernel .config file.
+
+resize=value	Resize the volume to <value> blocks.  JFS only supports
+		growing a volume, not shrinking it.  This option is only
+		valid during a remount, when the volume is mounted
+		read-write.  The resize keyword with no value will grow
+		the volume to the full size of the partition.
+
+JFS TODO list:
+
+Plans for our near term development items
+
+   - enhance support for logfile on dedicated partition
+   - get access control list functionality operational
+   - get extended attributes functionality operational
+
+Longer term work items
+
+   - implement defrag utility, for online defragmenting
+   - add quota support
+   - add support for block sizes (512,1024,2048)
+
+Please send bugs, comments, cards and letters to linuxjfs@us.ibm.com.
+
+The JFS mailing list can be subscribed to by using the link labeled
+"Mail list Subscribe" at our web page http://oss.software.ibm.com/jfs/.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/filesystems/proc.txt linux-2.4.20/Documentation/filesystems/proc.txt
--- linux-2.4.19/Documentation/filesystems/proc.txt	2001-11-07 22:39:36.000000000 +0000
+++ linux-2.4.20/Documentation/filesystems/proc.txt	2002-10-29 11:18:35.000000000 +0000
@@ -708,36 +708,26 @@
 used ones  is  far  behind,  you've  encountered  a peak in your usage of file
 handles and you don't need to increase the maximum.
 
-inode-state, inode-nr and inode-max
------------------------------------
-
-As with  file  handles, the kernel allocates the inode structures dynamically,
-but can't free them yet.
-
-The value  in  inode-max  denotes  the  maximum number of inode handlers. This
-value should  be  3 to 4 times larger than the value in file-max, since stdin,
-stdout, and  network  sockets also need an inode struct to handle them. If you
-regularly run out of inodes, you should increase this value.
+inode-state and inode-nr
+------------------------
 
 The file inode-nr contains the first two items from inode-state, so we'll skip
 to that file...
 
-inode-state contains  three  actual numbers and four dummy values. The numbers
-are nr_inodes, nr_free_inodes, and preshrink (in order of appearance).
+inode-state contains  two  actual numbers and five dummy values. The numbers
+are nr_inodes and nr_free_inodes (in order of appearance).
 
 nr_inodes
 ~~~~~~~~~
 
-Denotes the  number  of  inodes the system has allocated. This can be slightly
-more than inode-max because Linux allocates them one pageful at a time.
+Denotes the  number  of  inodes the system has allocated. This number will
+grow and shrink dynamically.
 
 nr_free_inodes
 --------------
 
-Represents the  number  of free inodes and preshrink is nonzero when nr_inodes
-is greater than inode-max and the system needs to prune the inode list instead
-of allocating more.
-
+Represents the  number of free inodes. Ie. The number of inuse inodes is
+(nr_inodes - nr_free_inodes).
 
 super-nr and super-max
 ----------------------
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/ide.txt linux-2.4.20/Documentation/ide.txt
--- linux-2.4.19/Documentation/ide.txt	2001-09-07 16:28:38.000000000 +0000
+++ linux-2.4.20/Documentation/ide.txt	2002-10-29 11:18:33.000000000 +0000
@@ -306,6 +306,9 @@
  "idex=serialize"	: do not overlap operations on idex and ide(x^1)
  "idex=reset"		: reset interface after probe
  "idex=dma"		: automatically configure/use DMA if possible.
+ "idex=nohighio"	: don't use i/o to high memory addresses on this
+			 	interface. i/o to memory locations higher
+				than ~860MiB will be bounced.
 
  The following are valid ONLY on ide0,
  and the defaults for the base,ctl ports must not be altered.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/initrd.txt linux-2.4.20/Documentation/initrd.txt
--- linux-2.4.19/Documentation/initrd.txt	2000-12-04 01:48:18.000000000 +0000
+++ linux-2.4.20/Documentation/initrd.txt	2002-10-29 11:18:49.000000000 +0000
@@ -115,8 +115,12 @@
  1) make sure loopback block devices are configured into the kernel
  2) create an empty file system of the appropriate size, e.g.
     # dd if=/dev/zero of=initrd bs=300k count=1
-    # mke2fs -F -m0 initrd
+    # mke2fs -F -m0 -b 1024 initrd
     (if space is critical, you may want to use the Minix FS instead of Ext2)
+    (Note that due to a problem elsewhere in the kernel, you _must_ use a
+     1024-byte blocksize when creating your file system.  If any other
+     value is used, the kernel will be unable to mount the initrd at boot
+     time, causing a kernel panic.)
  3) mount the file system, e.g.
     # mount -t ext2 -o loop initrd /mnt
  4) create the console device (not necessary if using devfs, but it can't
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/isapnp.txt linux-2.4.20/Documentation/isapnp.txt
--- linux-2.4.19/Documentation/isapnp.txt	2001-04-18 18:49:11.000000000 +0000
+++ linux-2.4.20/Documentation/isapnp.txt	2002-10-29 11:18:50.000000000 +0000
@@ -29,6 +29,7 @@
 poke <reg> <value>	- poke configuration byte to selected register
 pokew <reg> <value>	- poke configuration word to selected register
 poked <reg> <value>	- poke configuration dword to selected register
+allow_dma0 <value>	- allow dma channel 0 during auto activation: 0=off, 1=on
 
 Explanation:
 	- variable <idx> begins with zero
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/isdn/README.HiSax linux-2.4.20/Documentation/isdn/README.HiSax
--- linux-2.4.19/Documentation/isdn/README.HiSax	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/isdn/README.HiSax	2002-10-29 11:18:33.000000000 +0000
@@ -41,9 +41,10 @@
 ELSA Quickstep 3000PCI
 ELSA PCMCIA
 ITK ix1-micro Rev.2
-Eicon.Diehl Diva 2.0 ISA and PCI (S0 and U interface, no PRO version)
-Eicon.Diehl Diva 2.01 ISA and PCI
-Eicon.Diehl Diva Piccola
+Eicon Diva 2.0 ISA and PCI (S0 and U interface, no PRO version)
+Eicon Diva 2.01 ISA and PCI
+Eicon Diva 2.02 PCI
+Eicon Diva Piccola
 ASUSCOM NETWORK INC. ISDNLink 128K PC adapter (order code I-IN100-ST-D)
 Dynalink IS64PH (OEM version of ASUSCOM NETWORK INC. ISDNLink 128K adapter)
 PCBIT-DP (OEM version of ASUSCOM NETWORK INC. ISDNLink)
@@ -67,13 +68,14 @@
 HFC-PCI based cards
 Winbond W6692 based cards
 HFC-S+, HFC-SP/PCMCIA cards
+formula-n enternow
+Gerdes Power ISDN
 
 Note: PCF, PCF-Pro: up to now, only the ISDN part is supported
       PCC-8: not tested yet
       Eicon.Diehl Diva U interface not tested
 
 If you know other passive cards with the Siemens chipset, please let me know.
-To use the PNP cards you need the isapnptools.
 You can combine any card, if there is no conflict between the resources
 (io, mem, irq).
 
@@ -89,8 +91,15 @@
 modules. It is included in the normal "make [menu]config" target at the
 kernel. Don't forget it, especially to select the right D-channel protocol.
 
-Please note: All PnP cards need to be configured with isapnp and will work
-only with the HiSax driver used as a module.
+Please note: In older versions of the HiSax driver, all PnP cards
+needed to be configured with isapnp and worked only with the HiSax
+driver used as a module.
+
+In the current version, HiSax will automatically use the in-kernel
+ISAPnP support, provided you selected it during kernel configuration
+(CONFIG_ISAPNP), if you don't give the io=, irq= command line parameters.
+
+The affected card types are: 4,7,12,14,19,27-30
 
 a) when built as a module
 -------------------------
@@ -191,6 +200,8 @@
    37	HFC 2BDS0 S+, SP         irq,io 
    38	NETspider U PCI card     none
    39	HFC 2BDS0 SP/PCMCIA      irq,io (set with cardmgr)
+   40   hotplug interface
+   41   Formula-n enter:now PCI  none
 
 At the moment IRQ sharing is only possible with PCI cards. Please make sure
 that your IRQ is free and enabled for ISA use.
@@ -216,6 +227,13 @@
                    (IO 1 (BASE 0x0180))
    modprobe hisax type=4 protocol=2 irq=10 io0=0x580 io1=0x180
 
+   In the current version of HiSax, you can instead simply use
+
+   modprobe hisax type=4 protocol=2
+
+   if you configured your kernel for ISAPnP. Don't run isapnp in
+   this case!
+
 6. Teles 16.3, Euro ISDN, I/O base 280 hex, IRQ 12 and
    Teles 16.0, 1TR6, IRQ 5, Memory d0000 hex
    modprobe hisax type=3,1 protocol=2,1 io=0x280 mem=0,0xd0000
@@ -296,7 +314,9 @@
    36	W6692 based PCI cards   none
    37	HFC 2BDS0 S+,SP/PCMCIA  ONLY WORKS AS A MODULE !
    38	NETspider U PCI card    none
-
+   39	HFC 2BDS0 SP/PCMCIA     ONLY WORKS AS A MODULE !
+   40   hotplug interface	ONLY WORKS AS A MODULE !
+   41   Formula-n enter:now PCI none
 
 Running the driver
 ------------------
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/kernel-parameters.txt linux-2.4.20/Documentation/kernel-parameters.txt
--- linux-2.4.19/Documentation/kernel-parameters.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/kernel-parameters.txt	2002-10-29 11:18:48.000000000 +0000
@@ -23,6 +23,7 @@
 	HW	Appropriate hardware is enabled.
 	IA-32	IA-32 aka i386 architecture is enabled.
 	IA-64	IA-64 architecture is enabled.
+	IP_PNP	IP DCHP, BOOTP, or RARP is enabled.
 	ISAPNP  ISA PnP code is enabled.
 	ISDN	Appropriate ISDN support is enabled.
 	JOY 	Appropriate joystick support is enabled.
@@ -251,7 +252,7 @@
 
 	initrd=		[BOOT] Specify the location of the initial ramdisk. 
 
-	ip=		[PNP]
+	ip=		[IP_PNP]
 
 	isapnp=		[ISAPNP] Specify RDP, reset, pci_scan and verbosity.
 
@@ -273,10 +274,14 @@
  
 	kbd-reset	[VT]
 
-	keep_initrd	[HW, ARM]
+	keepinitrd	[HW, ARM]
 
 	load_ramdisk=	[RAM] List of ramdisks to load from floppy.
 
+	lockd.udpport=	[NFS]
+
+	lockd.tcpport=	[NFS]
+
 	logi_busmouse=	[HW, MOUSE]
 
 	lp=0		[LP]	Specify parallel ports to use, e.g,
@@ -313,7 +318,7 @@
 
 	max_scsi_luns=	[SCSI]
 
-	mca-pentium	[BUGS=ix86]
+	mca-pentium	[BUGS=IA-32]
 
 	mcd=		[HW,CD]
 
@@ -327,6 +332,11 @@
 
 	megaraid=	[HW,SCSI]
  
+	mem=exactmap	[KNL,BOOT,IA-32] enable setting of an exact
+			e820 memory map, as specified by the user.
+			Such mem=exactmap lines can be constructed
+			based on BIOS output or other requirements.
+
 	mem=nn[KMG]	[KNL,BOOT] force use of a specific amount of
 			memory; to be used when the kernel is not able
 			to see the whole system memory or for test.
@@ -359,9 +369,9 @@
 
 	nfsroot=	[NFS] nfs root filesystem for disk-less boxes.
 
-	nmi_watchdog=	[KNL,BUGS=ix86] debugging features for SMP kernels.
+	nmi_watchdog=	[KNL,BUGS=IA-32] debugging features for SMP kernels.
 
-	no387		[BUGS=ix86] Tells the kernel to use the 387 maths
+	no387		[BUGS=IA-32] Tells the kernel to use the 387 maths
 			emulation library even if a 387 maths coprocessor
 			is present.
 
@@ -379,7 +389,9 @@
 
 	nohlt		[BUGS=ARM]
  
-	no-hlt		[BUGS=ix86]
+	no-hlt		[BUGS=IA-32] Tells the kernel that the hlt
+			instruction doesn't work correctly and not to
+			use it.
 
 	noht		[SMP,IA-32] Disables P4 Xeon(tm) HyperThreading.
 
@@ -396,7 +408,7 @@
 
 	nosync		[HW, M68K] Disables sync negotiation for all devices.
 
-	notsc           [BUGS=ix86] Disable Time Stamp Counter
+	notsc           [BUGS=IA-32] Disable Time Stamp Counter
 
 	nowb		[ARM]
  
@@ -504,7 +516,7 @@
 	ramdisk_start=	[RAM] Starting block of RAM disk image (so you can
 			place it after the kernel image on a boot floppy).
 
-	reboot=		[BUGS=ix86]
+	reboot=		[BUGS=IA-32]
 
 	reserve=	[KNL,BUGS] force the kernel to ignore some iomem area.
 
@@ -514,6 +526,10 @@
 
 	root=		[KNL] root filesystem.
 
+	rootflags=	[KNL] set root filesystem mount option string
+
+	rootfstype=	[KNL] set root filesystem type
+
 	rw		[KNL] Mount root device read-write on boot.
 
 	S		[KNL] run init in single mode.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/ldm.txt linux-2.4.20/Documentation/ldm.txt
--- linux-2.4.19/Documentation/ldm.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/ldm.txt	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,102 @@
+
+            LDM - Logical Disk Manager (Dynamic Disks)
+            ------------------------------------------
+
+Overview
+--------
+
+Windows 2000 and XP use a new partitioning scheme.  It is a complete
+replacement for the MSDOS style partitions.  It stores its information in a
+1MiB journalled database at the end of the physical disk.  The size of
+partitions is limited only by disk space.  The maximum number of partitions is
+nearly 2000.
+
+Any partitions created under the LDM are called "Dynamic Disks".  There are no
+longer any primary or extended partitions.  Normal MSDOS style partitions are
+now known as Basic Disks.
+
+If you wish to use Spanned, Striped, Mirrored or RAID 5 Volumes, you must use
+Dynamic Disks.  The journalling allows Windows to make changes to these
+partitions and filesystems without the need to reboot.
+
+Once the LDM driver has divided up the disk, you can use the MD driver to
+assemble any multi-partition volumes, e.g.  Stripes, RAID5.
+
+To prevent legacy applications from repartitioning the disk, the LDM creates a
+dummy MSDOS partition containing one disk-sized partition.
+
+
+Example
+-------
+
+Below we have a 50MiB disk, divided into seven partitions.
+N.B.  The missing 1MiB at the end of the disk is where the LDM database is
+      stored.
+
+  Device | Offset Bytes  Sectors  MiB | Size   Bytes  Sectors  MiB
+  -------+----------------------------+---------------------------
+  hda    |            0        0    0 |     52428800   102400   50
+  hda1   |     51380224   100352   49 |      1048576     2048    1
+  hda2   |        16384       32    0 |      6979584    13632    6
+  hda3   |      6995968    13664    6 |     10485760    20480   10
+  hda4   |     17481728    34144   16 |      4194304     8192    4
+  hda5   |     21676032    42336   20 |      5242880    10240    5
+  hda6   |     26918912    52576   25 |     10485760    20480   10
+  hda7   |     37404672    73056   35 |     13959168    27264   13
+
+The LDM Database may not store the partitions in the order that they appear on
+disk, but the driver will sort them.
+
+When Linux boots, you will see something like:
+
+Partition check:
+  hda: [LDM] hda1 hda2 hda3 hda4 hda5 hda6 hda7
+
+
+Compiling LDM Support
+---------------------
+
+To enable LDM, choose the following two options: 
+
+  "Advanced partition selection" CONFIG_PARTITION_ADVANCED
+  "Windows Logical Disk Manager (Dynamic Disk) support" CONFIG_LDM_PARTITION
+
+If you believe the driver isn't working as it should, you can enable the extra
+debugging code.  This will produce a LOT of output.  The option is:
+
+  "Windows LDM extra logging" CONFIG_LDM_DEBUG
+
+N.B. The partition code cannot be compiled as a module.
+
+As with all the partition code, if the driver doesn't see signs of its type of
+partition, it will pass control to another driver, so there is no harm in
+enabling it.
+
+If you have Dynamic Disks but don't enable the driver, then all you will see
+is a dummy MSDOS partition filling the whole disk.  You won't be able to mount
+any of the volumes on the disk.
+
+
+Booting
+-------
+
+If you enable LDM support, then lilo is capable of booting from any of the
+discovered partitions.  However, grub does not understand the LDM partitioning
+and cannot boot from a Dynamic Disk.
+
+
+More Documentation
+------------------
+
+There is an Overview of the LDM online together with complete Technical
+Documentation.  It can also be downloaded in html.
+
+  http://linux-ntfs.sourceforge.net/ldm/index.html
+  http://linux-ntfs.sourceforge.net/downloads.html
+
+If you have any LDM questions that aren't answered on the website, email me.
+
+Cheers,
+    FlatCap - Richard Russon
+    ldm@flatcap.org
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/networking/00-INDEX linux-2.4.20/Documentation/networking/00-INDEX
--- linux-2.4.19/Documentation/networking/00-INDEX	2001-02-09 00:32:44.000000000 +0000
+++ linux-2.4.20/Documentation/networking/00-INDEX	2002-10-29 11:18:34.000000000 +0000
@@ -44,6 +44,10 @@
 	- the Digi International RightSwitch SE-X Ethernet driver
 dmfe.txt
 	- info on the Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver.
+e100.txt
+	- info on Intel's EtherExpress PRO/100 line of 10/100 boards
+e1000.txt
+	- info on Intel's E1000 line of gigabit ethernet boards
 eql.txt
 	- serial IP load balancing
 ethertap.txt
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/networking/8139too.txt linux-2.4.20/Documentation/networking/8139too.txt
--- linux-2.4.19/Documentation/networking/8139too.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/networking/8139too.txt	2002-10-29 11:18:32.000000000 +0000
@@ -185,9 +185,22 @@
 Change History
 --------------
 
-Version 0.9.23 - January 16, 2002
+Version 0.9.26 - August 9, 2002
 
-* New, compile-time conditional for testing better RX reset
+* Fix MII ioctl phy id corruption.
+* Fix big-endian multicast bug.
+* Support register dumps via ethtool.
+* Fix several uses of 'len' after potential skb free, in dev->hard_start_xmit
+* Replace several "magic numbers" with their proper representation
+  constants in linux/mii.h.
+* Support ethtool media interface via generic kernel MII API
+* Export NIC-specific statistics via ethtool.
+* Proper support for RTL8139 rev K. (can be disabled via
+  compile-time conditional)
+* Add PCI ids for new 8139 boards.
+* Use ethernet crc via generic linux/crc32.h kernel API.
+* Better RX reset.  Old rx-reset method still available via
+  a compile-time conditional.
 * Only account specific RX errors if rx_status is !OK
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/networking/NAPI_HOWTO.txt linux-2.4.20/Documentation/networking/NAPI_HOWTO.txt
--- linux-2.4.19/Documentation/networking/NAPI_HOWTO.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/networking/NAPI_HOWTO.txt	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,749 @@
+HISTORY:
+February 16/2002 -- revision 0.2.1:
+COR typo corrected
+February 10/2002 -- revision 0.2:
+some spell checking ;->
+January 12/2002 -- revision 0.1
+This is still work in progress so may change.
+To keep up to date please watch this space.
+
+Introduction to NAPI
+====================
+
+NAPI is a proven (www.cyberus.ca/~hadi/usenix-paper.tgz) technique
+to improve network performance on Linux. For more details please
+read that paper.
+NAPI provides a "inherent mitigation" which is bound by system capacity
+as can be seen from the following data collected by Robert on Gigabit 
+ethernet (e1000):
+
+ Psize    Ipps       Tput     Rxint     Txint    Done     Ndone
+ ---------------------------------------------------------------
+   60    890000     409362        17     27622        7     6823
+  128    758150     464364        21      9301       10     7738
+  256    445632     774646        42     15507       21    12906
+  512    232666     994445    241292     19147   241192     1062
+ 1024    119061    1000003    872519     19258   872511        0
+ 1440     85193    1000003    946576     19505   946569        0
+ 
+
+Legend:
+"Ipps" stands for input packets per second. 
+"Tput" == packets out of total 1M that made it out.
+"txint" == transmit completion interrupts seen
+"Done" == The number of times that the poll() managed to pull all
+packets out of the rx ring. Note from this that the lower the
+load the more we could clean up the rxring
+"Ndone" == is the converse of "Done". Note again, that the higher
+the load the more times we couldnt clean up the rxring.
+
+Observe that:
+when the NIC receives 890Kpackets/sec only 17 rx interrupts are generated. 
+The system cant handle the processing at 1 interrupt/packet at that load level. 
+At lower rates on the other hand, rx interrupts go up and therefore the
+interrupt/packet ratio goes up (as observable from that table). So there is
+possibility that under low enough input, you get one poll call for each
+input packet caused by a single interrupt each time. And if the system 
+cant handle interrupt per packet ratio of 1, then it will just have to 
+chug along ....
+
+
+0) Prerequisites:
+==================
+A driver MAY continue using the old 2.4 technique for interfacing
+to the network stack and not benefit from the NAPI changes.
+NAPI additions to the kernel do not break backward compatibility.
+NAPI, however, requires the following features to be available:
+
+A) DMA ring or enough RAM to store packets in software devices.
+
+B) Ability to turn off interrupts or maybe events that send packets up 
+the stack.
+
+NAPI processes packet events in what is known as dev->poll() method.
+Typically, only packet receive events are processed in dev->poll(). 
+The rest of the events MAY be processed by the regular interrupt handler 
+to reduce processing latency (justified also because there are not that 
+many of them).
+Note, however, NAPI does not enforce that dev->poll() only processes 
+receive events. 
+Tests with the tulip driver indicated slightly increased latency if
+all of the interrupt handler is moved to dev->poll(). Also MII handling
+gets a little trickier.
+The example used in this document is to move the receive processing only
+to dev->poll(); this is shown with the patch for the tulip driver.
+For an example of code that moves all the interrupt driver to 
+dev->poll() look at the ported e1000 code.
+
+There are caveats that might force you to go with moving everything to 
+dev->poll(). Different NICs work differently depending on their status/event 
+acknowledgement setup. 
+There are two types of event register ACK mechanisms.
+	I)  what is known as Clear-on-read (COR).
+	when you read the status/event register, it clears everything!
+	The natsemi and sunbmac NICs are known to do this.
+	In this case your only choice is to move all to dev->poll()
+
+	II) Clear-on-write (COW)
+	 i) you clear the status by writting a 1 in the bit-location you want.
+		These are the majority of the NICs and work the best with NAPI.
+		Put only receive events in dev->poll(); leave the rest in
+		the old interrupt handler.
+	 ii) whatever you write in the status register clears every thing ;->
+		Cant seem to find any supported by Linux which do this. If
+		someone knows such a chip email us please.
+		Move all to dev->poll()
+
+C) Ability to detect new work correctly.
+NAPI works by shutting down event interrupts when theres work and
+turning them on when theres none. 
+New packets might show up in the small window while interrupts were being 
+re-enabled (refer to appendix 2).  A packet might sneak in during the period 
+we are enabling interrupts. We only get to know about such a packet when the 
+next new packet arrives and generates an interrupt. 
+Essentially, there is a small window of opportunity for a race condition
+which for clarity we'll refer to as the "rotting packet".
+
+This is a very important topic and appendix 2 is dedicated for more 
+discussion.
+
+Locking rules and environmental guarantees
+==========================================
+
+-Guarantee: Only one CPU at any time can call dev->poll(); this is because
+only one CPU can pick the initial interrupt and hence the initial
+netif_rx_schedule(dev);
+- The core layer invokes devices to send packets in a round robin format.
+This implies receive is totaly lockless because of the guarantee only that 
+one CPU is executing it.
+-  contention can only be the result of some other CPU accessing the rx
+ring. This happens only in close() and suspend() (when these methods
+try to clean the rx ring); 
+****guarantee: driver authors need not worry about this; synchronization 
+is taken care for them by the top net layer.
+-local interrupts are enabled (if you dont move all to dev->poll()). For 
+example link/MII and txcomplete continue functioning just same old way. 
+This improves the latency of processing these events. It is also assumed that 
+the receive interrupt is the largest cause of noise. Note this might not 
+always be true. 
+[according to Manfred Spraul, the winbond insists on sending one 
+txmitcomplete interrupt for each packet (although this can be mitigated)].
+For these broken drivers, move all to dev->poll().
+
+For the rest of this text, we'll assume that dev->poll() only
+processes receive events.
+
+new methods introduce by NAPI
+=============================
+
+a) netif_rx_schedule(dev)
+Called by an IRQ handler to schedule a poll for device
+
+b) netif_rx_schedule_prep(dev)
+puts the device in a state which allows for it to be added to the
+CPU polling list if it is up and running. You can look at this as
+the first half of  netif_rx_schedule(dev) above; the second half
+being c) below.
+
+c) __netif_rx_schedule(dev)
+Add device to the poll list for this CPU; assuming that _prep above
+has already been called and returned 1.
+
+d) netif_rx_reschedule(dev, undo)
+Called to reschedule polling for device specifically for some
+deficient hardware. Read Appendix 2 for more details.
+
+e) netif_rx_complete(dev)
+
+Remove interface from the CPU poll list: it must be in the poll list
+on current cpu. This primitive is called by dev->poll(), when
+it completes its work. The device cannot be out of poll list at this
+call, if it is then clearly it is a BUG(). You'll know ;->
+
+All these above nethods are used below. So keep reading for clarity.
+
+Device driver changes to be made when porting NAPI
+==================================================
+
+Below we describe what kind of changes are required for NAPI to work.
+
+1) introduction of dev->poll() method 
+=====================================
+
+This is the method that is invoked by the network core when it requests
+for new packets from the driver. A driver is allowed to send upto
+dev->quota packets by the current CPU before yielding to the network
+subsystem (so other devices can also get opportunity to send to the stack).
+
+dev->poll() prototype looks as follows:
+int my_poll(struct net_device *dev, int *budget)
+
+budget is the remaining number of packets the network subsystem on the
+current CPU can send up the stack before yielding to other system tasks.
+*Each driver is responsible for decrementing budget by the total number of
+packets sent.
+	Total number of packets cannot exceed dev->quota.
+
+dev->poll() method is invoked by the top layer, the driver just sends if it 
+can to the stack the packet quantity requested.
+
+more on dev->poll() below after the interrupt changes are explained.
+
+2) registering dev->poll() method
+===================================
+
+dev->poll should be set in the dev->probe() method. 
+e.g:
+dev->open = my_open;
+.
+.
+/* two new additions */
+/* first register my poll method */
+dev->poll = my_poll;
+/* next register my weight/quanta; can be overriden in /proc */
+dev->weight = 16;
+.
+.
+dev->stop = my_close;
+
+
+
+3) scheduling dev->poll()
+=============================
+This involves modifying the interrupt handler and the code
+path which takes the packet off the NIC and sends them to the 
+stack.
+
+it's important at this point to introduce the classical D Becker 
+interrupt processor:
+
+------------------
+static void
+netdevice_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+
+	struct net_device *dev = (struct net_device *)dev_instance;
+	struct my_private *tp = (struct my_private *)dev->priv;
+
+	int work_count = my_work_count;
+        status = read_interrupt_status_reg();
+        if (status == 0)
+                return;         /* Shared IRQ: not us */
+        if (status == 0xffff)
+                return;         /* Hot unplug */
+        if (status & error)
+		do_some_error_handling()
+        
+	do {
+		acknowledge_ints_ASAP();
+
+		if (status & link_interrupt) {
+			spin_lock(&tp->link_lock);
+			do_some_link_stat_stuff();
+			spin_unlock(&tp->link_lock);
+		}
+		
+		if (status & rx_interrupt) {
+			receive_packets(dev);
+		}
+
+		if (status & rx_nobufs) {
+			make_rx_buffs_avail();
+		}
+			
+		if (status & tx_related) {
+			spin_lock(&tp->lock);
+			tx_ring_free(dev);
+			if (tx_died)
+				restart_tx();
+			spin_unlock(&tp->lock);
+		}
+
+		status = read_interrupt_status_reg();
+
+	} while (!(status & error) || more_work_to_be_done);
+
+}
+
+----------------------------------------------------------------------
+
+We now change this to what is shown below to NAPI-enable it:
+
+----------------------------------------------------------------------
+static void
+netdevice_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *)dev_instance;
+	struct my_private *tp = (struct my_private *)dev->priv;
+
+        status = read_interrupt_status_reg();
+        if (status == 0)
+                return;         /* Shared IRQ: not us */
+        if (status == 0xffff)
+                return;         /* Hot unplug */
+        if (status & error)
+		do_some_error_handling();
+        
+	do {
+/************************ start note *********************************/		
+		acknowledge_ints_ASAP();  // dont ack rx and rxnobuff here
+/************************ end note *********************************/		
+
+		if (status & link_interrupt) {
+			spin_lock(&tp->link_lock);
+			do_some_link_stat_stuff();
+			spin_unlock(&tp->link_lock);
+		}
+/************************ start note *********************************/		
+		if (status & rx_interrupt || (status & rx_nobuffs)) {
+			if (netif_rx_schedule_prep(dev)) {
+
+				/* disable interrupts caused 
+			         *	by arriving packets */
+				disable_rx_and_rxnobuff_ints();
+				/* tell system we have work to be done. */
+				__netif_rx_schedule(dev);
+			} else {
+				printk("driver bug! interrupt while in poll\n");
+				/* FIX by disabling interrupts  */
+				disable_rx_and_rxnobuff_ints();
+			}
+		}
+/************************ end note note *********************************/		
+			
+		if (status & tx_related) {
+			spin_lock(&tp->lock);
+			tx_ring_free(dev);
+
+			if (tx_died)
+				restart_tx();
+			spin_unlock(&tp->lock);
+		}
+
+		status = read_interrupt_status_reg();
+
+/************************ start note *********************************/		
+	} while (!(status & error) || more_work_to_be_done(status));
+/************************ end note note *********************************/		
+
+}
+
+---------------------------------------------------------------------
+
+
+We note several things from above:
+
+I) Any interrupt source which is caused by arriving packets is now
+turned off when it occurs. Depending on the hardware, there could be
+several reasons that arriving packets would cause interrupts; these are the
+interrupt sources we wish to avoid. The two common ones are a) a packet 
+arriving (rxint) b) a packet arriving and finding no DMA buffers available
+(rxnobuff) .
+This means also acknowledge_ints_ASAP() will not clear the status
+register for those two items above; clearing is done in the place where 
+proper work is done within NAPI; at the poll() and refill_rx_ring() 
+discussed further below.
+netif_rx_schedule_prep() returns 1 if device is in running state and
+gets successfully added to the core poll list. If we get a zero value
+we can _almost_ assume are already added to the list (instead of not running. 
+Logic based on the fact that you shouldnt get interrupt if not running)
+We rectify this by disabling rx and rxnobuf interrupts.
+
+II) that receive_packets(dev) and make_rx_buffs_avail() may have dissapeared.
+These functionalities are still around actually......
+
+infact, receive_packets(dev) is very close to my_poll() and 
+make_rx_buffs_avail() is invoked from my_poll()
+
+4) converting receive_packets() to dev->poll()
+===============================================
+
+We need to convert the classical D Becker receive_packets(dev) to my_poll()
+
+First the typical receive_packets() below:
+-------------------------------------------------------------------
+
+/* this is called by interrupt handler */
+static void receive_packets (struct net_device *dev)
+{
+
+	struct my_private *tp = (struct my_private *)dev->priv;
+	rx_ring = tp->rx_ring;
+	cur_rx = tp->cur_rx;
+	int entry = cur_rx % RX_RING_SIZE;
+	int received = 0;
+	int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
+
+	while (rx_ring_not_empty) {
+		u32 rx_status;
+		unsigned int rx_size;
+		unsigned int pkt_size;
+		struct sk_buff *skb;
+                /* read size+status of next frame from DMA ring buffer */
+		/* the number 16 and 4 are just examples */
+                rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
+                rx_size = rx_status >> 16;
+                pkt_size = rx_size - 4;
+
+		/* process errors */
+                if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
+                    (!(rx_status & RxStatusOK))) {
+                        netdrv_rx_err (rx_status, dev, tp, ioaddr);
+                        return;
+                }
+
+                if (--rx_work_limit < 0)
+                        break;
+
+		/* grab a skb */
+                skb = dev_alloc_skb (pkt_size + 2);
+                if (skb) {
+			.
+			.
+			netif_rx (skb);
+			.
+			.
+                } else {  /* OOM */
+			/*seems very driver specific ... some just pass
+			whatever is on the ring already. */
+                }
+
+		/* move to the next skb on the ring */
+		entry = (++tp->cur_rx) % RX_RING_SIZE;
+		received++ ;
+
+        }
+
+	/* store current ring pointer state */
+        tp->cur_rx = cur_rx;
+
+        /* Refill the Rx ring buffers if they are needed */
+	refill_rx_ring();
+	.
+	.
+
+}
+-------------------------------------------------------------------
+We change it to a new one below; note the additional parameter in
+the call.
+
+-------------------------------------------------------------------
+
+/* this is called by the network core */
+static void my_poll (struct net_device *dev, int *budget)
+{
+
+	struct my_private *tp = (struct my_private *)dev->priv;
+	rx_ring = tp->rx_ring;
+	cur_rx = tp->cur_rx;
+	int entry = cur_rx % RX_BUF_LEN;
+	/* maximum packets to send to the stack */
+/************************ note note *********************************/		
+	int rx_work_limit = dev->quota;
+
+/************************ end note note *********************************/		
+    do {  // outer beggining loop starts here
+
+	clear_rx_status_register_bit();
+
+	while (rx_ring_not_empty) {
+		u32 rx_status;
+		unsigned int rx_size;
+		unsigned int pkt_size;
+		struct sk_buff *skb;
+                /* read size+status of next frame from DMA ring buffer */
+		/* the number 16 and 4 are just examples */
+                rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
+                rx_size = rx_status >> 16;
+                pkt_size = rx_size - 4;
+
+		/* process errors */
+                if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
+                    (!(rx_status & RxStatusOK))) {
+                        netdrv_rx_err (rx_status, dev, tp, ioaddr);
+                        return;
+                }
+
+/************************ note note *********************************/		
+                if (--rx_work_limit < 0) { /* we got packets, but no quota */
+			/* store current ring pointer state */
+			tp->cur_rx = cur_rx;
+
+			/* Refill the Rx ring buffers if they are needed */
+			refill_rx_ring(dev);
+                        goto not_done;
+		}
+/**********************  end note **********************************/
+
+		/* grab a skb */
+                skb = dev_alloc_skb (pkt_size + 2);
+                if (skb) {
+			.
+			.
+/************************ note note *********************************/		
+			netif_receive_skb (skb);
+/**********************  end note **********************************/
+			.
+			.
+                } else {  /* OOM */
+			/*seems very driver specific ... common is just pass
+			whatever is on the ring already. */
+                }
+
+		/* move to the next skb on the ring */
+		entry = (++tp->cur_rx) % RX_RING_SIZE;
+		received++ ;
+
+        }
+
+	/* store current ring pointer state */
+        tp->cur_rx = cur_rx;
+
+        /* Refill the Rx ring buffers if they are needed */
+	refill_rx_ring(dev);
+	
+	/* no packets on ring; but new ones can arrive since we last 
+	   checked  */
+	status = read_interrupt_status_reg();
+	if (rx status is not set) {
+                        /* If something arrives in this narrow window,
+			an interrupt will be generated */
+                        goto done;
+	}
+	/* done! at least thats what it looks like ;->
+	if new packets came in after our last check on status bits
+	they'll be caught by the while check and we go back and clear them 
+	since we havent exceeded our quota */
+    } while (rx_status_is_set); 
+
+done:
+
+/************************ note note *********************************/		
+        dev->quota -= received;
+        *budget -= received;
+
+        /* If RX ring is not full we are out of memory. */
+        if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
+                goto oom;
+
+	/* we are happy/done, no more packets on ring; put us back
+	to where we can start processing interrupts again */
+        netif_rx_complete(dev);
+	enable_rx_and_rxnobuf_ints();
+
+       /* The last op happens after poll completion. Which means the following:
+        * 1. it can race with disabling irqs in irq handler (which are done to 
+	* schedule polls)
+        * 2. it can race with dis/enabling irqs in other poll threads
+        * 3. if an irq raised after the begining of the outer  beginning 
+        * loop(marked in the code above), it will be immediately
+        * triggered here.
+        *
+        * Summarizing: the logic may results in some redundant irqs both
+        * due to races in masking and due to too late acking of already
+        * processed irqs. The good news: no events are ever lost.
+        */
+
+        return 0;   /* done */
+
+not_done:
+        if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 ||
+            tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
+                refill_rx_ring(dev);
+
+        if (!received) {
+                printk("received==0\n");
+                received = 1;
+        }
+        dev->quota -= received;
+        *budget -= received;
+        return 1;  /* not_done */
+
+oom:
+        /* Start timer, stop polling, but do not enable rx interrupts. */
+	start_poll_timer(dev);
+        return 0;  /* we'll take it from here so tell core "done"*/
+
+/************************ End note note *********************************/		
+}
+-------------------------------------------------------------------
+
+From above we note that:
+0) rx_work_limit = dev->quota 
+1) refill_rx_ring() is in charge of clearing the bit for rxnobuff when
+it does the work.
+2) We have a done and not_done state.
+3) instead of netif_rx() we call netif_receive_skb() to pass the skb.
+4) we have a new way of handling oom condition
+5) A new outer for (;;) loop has been added. This serves the purpose of
+ensuring that if a new packet has come in, after we are all set and done,
+and we have not exceeded our quota that we continue sending packets up.
+ 
+
+-----------------------------------------------------------
+Poll timer code will need to do the following:
+
+a) 
+
+        if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 ||
+            tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) 
+                refill_rx_ring(dev);
+
+        /* If RX ring is not full we are still out of memory.
+	   Restart the timer again. Else we re-add ourselves 
+           to the master poll list.
+         */
+
+        if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
+                restart_timer();
+
+	else netif_rx_schedule(dev);  /* we are back on the poll list */
+	
+5) dev->close() and dev->suspend() issues
+==========================================
+The driver writter neednt worry about this. The top net layer takes
+care of it.
+
+6) Adding new Stats to /proc 
+=============================
+In order to debug some of the new features, we introduce new stats
+that need to be collected.
+TODO: Fill this later.
+
+APPENDIX 1: discussion on using ethernet HW FC
+==============================================
+Most chips with FC only send a pause packet when they run out of Rx buffers.
+Since packets are pulled off the DMA ring by a softirq in NAPI,
+if the system is slow in grabbing them and we have a high input
+rate (faster than the system's capacity to remove packets), then theoretically
+there will only be one rx interrupt for all packets during a given packetstorm.
+Under low load, we might have a single interrupt per packet.
+FC should be programmed to apply in the case when the system cant pull out
+packets fast enough i.e send a pause only when you run out of rx buffers.
+Note FC in itself is a good solution but we have found it to not be
+much of a commodity feature (both in NICs and switches) and hence falls
+under the same category as using NIC based mitigation. Also experiments
+indicate that its much harder to resolve the resource allocation
+issue (aka lazy receiving that NAPI offers) and hence quantify its usefullness
+proved harder. In any case, FC works even better with NAPI but is not
+necessary.
+
+
+APPENDIX 2: the "rotting packet" race-window avoidance scheme 
+=============================================================
+
+There are two types of associations seen here
+
+1) status/int which honors level triggered IRQ
+
+If a status bit for receive or rxnobuff is set and the corresponding 
+interrupt-enable bit is not on, then no interrupts will be generated. However, 
+as soon as the "interrupt-enable" bit is unmasked, an immediate interrupt is 
+generated.  [assuming the status bit was not turned off].
+Generally the concept of level triggered IRQs in association with a status and
+interrupt-enable CSR register set is used to avoid the race.
+
+If we take the example of the tulip:
+"pending work" is indicated by the status bit(CSR5 in tulip).
+the corresponding interrupt bit (CSR7 in tulip) might be turned off (but
+the CSR5 will continue to be turned on with new packet arrivals even if
+we clear it the first time)
+Very important is the fact that if we turn on the interrupt bit on when
+status is set that an immediate irq is triggered.
+ 
+If we cleared the rx ring and proclaimed there was "no more work
+to be done" and then went on to do a few other things;  then when we enable
+interrupts, there is a possibility that a new packet might sneak in during
+this phase. It helps to look at the pseudo code for the tulip poll
+routine:
+
+--------------------------
+        do {
+                ACK;
+                while (ring_is_not_empty()) {
+                        work-work-work
+                        if quota is exceeded: exit, no touching irq status/mask
+                }
+                /* No packets, but new can arrive while we are doing this*/
+                CSR5 := read
+                if (CSR5 is not set) {
+                        /* If something arrives in this narrow window here,
+                        *  where the comments are ;-> irq will be generated */
+                        unmask irqs;
+                        exit poll;
+                }
+        } while (rx_status_is_set);
+------------------------
+
+CSR5 bit of interest is only the rx status. 
+If you look at the last if statement: 
+you just finished grabbing all the packets from the rx ring .. you check if
+status bit says theres more packets just in ... it says none; you then
+enable rx interrupts again; if a new packet just came in during this check,
+we are counting that CSR5 will be set in that small window of opportunity
+and that by re-enabling interrupts, we would actually triger an interrupt
+to register the new packet for processing.
+
+[The above description nay be very verbose, if you have better wording 
+that will make this more understandable, please suggest it.]
+
+2) non-capable hardware
+
+These do not generally respect level triggered IRQs. Normally,
+irqs may be lost while being masked and the only way to leave poll is to do
+a double check for new input after netif_rx_complete() is invoked
+and re-enable polling (after seeing this new input).
+
+Sample code:
+
+---------
+	.
+	.
+restart_poll:
+	while (ring_is_not_empty()) {
+		work-work-work
+		if quota is exceeded: exit, not touching irq status/mask
+	}
+	.
+	.
+	.
+	enable_rx_interrupts()
+	netif_rx_complete(dev);
+	if (ring_has_new_packet() && netif_rx_reschedule(dev, received)) {
+		disable_rx_and_rxnobufs()
+		goto restart_poll
+	} while (rx_status_is_set);
+---------
+		
+Basically netif_rx_complete() removes us from the poll list, but because a
+new packet which will never be caught due to the possibility of a race
+might come in, we attempt to re-add ourselves to the poll list. 
+
+
+
+--------------------------------------------------------------------
+
+relevant sites:
+==================
+ftp://robur.slu.se/pub/Linux/net-development/NAPI/
+
+
+--------------------------------------------------------------------
+TODO: Write net-skeleton.c driver.
+-------------------------------------------------------------
+
+Authors:
+========
+Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+Jamal Hadi Salim <hadi@cyberus.ca>
+Robert Olsson <Robert.Olsson@data.slu.se>
+
+Acknowledgements:
+================
+People who made this document better:
+
+Lennert Buytenhek <buytenh@gnu.org>
+Andrew Morton  <akpm@zip.com.au>
+Manfred Spraul <manfred@colorfullife.com>
+Donald Becker <becker@scyld.com>
+Jeff Garzik 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/networking/dl2k.txt linux-2.4.20/Documentation/networking/dl2k.txt
--- linux-2.4.19/Documentation/networking/dl2k.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/networking/dl2k.txt	2002-10-29 11:18:33.000000000 +0000
@@ -1,7 +1,7 @@
 
     D-Link DL2000-based Gigabit Ethernet Adapter Installation
     for Linux
-    Jan 29, 2002
+    May 23, 2002
 
 Contents
 ========
@@ -202,7 +202,7 @@
 				  1000mbps_fd and 1000mbps_hd types are only
 				  available for fiber adapter.
 
-vlan=[0|1]			- Specifies the VLAN ID. If vlan=0, the
+vlan=n				- Specifies the VLAN ID. If vlan=0, the
 				  Virtual Local Area Network (VLAN) function is
 				  disable.
 
@@ -211,24 +211,34 @@
 				  function is disabled.
 				  Jumbo frame usually improve the performance
 				  int gigabit.
+				  This feature need jumbo frame compatible 
+				  remote.
 				  
-rx_coalesce=n			- Rx frame count each interrupt.
-rx_timeout=n			- Rx DMA wait time for an interrupt. Proper 
-				  values of rx_coalesce and rx_timeout bring 
-				  a conspicuous performance in the fast machine.
-				  Ex. rx_coalesce=5 and rx_timeout=750 
-
-tx_coalesce=n			- Tx transmit count each TxComp interrupt.
-				  Setting value larger than 1 will improve 
-				  performance, but this is possible to lower 
-				  stability in slow UP machines. By default, 
-				  tx_coalesce=1. (dl2k)
+rx_coalesce=m			- Number of rx frame handled each interrupt.
+rx_timeout=n			- Rx DMA wait time for an interrupt. 
+				  If set rx_coalesce > 0, hardware only assert 
+				  an interrupt for m frames. Hardware won't 
+				  assert rx interrupt until m frames received or
+				  reach timeout of n * 640 nano seconds. 
+				  Set proper rx_coalesce and rx_timeout can 
+				  reduce congestion collapse and overload which
+				  has been a bottlenect for high speed network.
 				  
-tx_flow=[1|0]			- Specifies the Tx flow control. If tx_flow=1, 
-				  the Tx flow control enable.
+				  For example, rx_coalesce=10 rx_timeout=800.
+				  that is, hardware assert only 1 interrupt 
+				  for 10 frames received or timeout of 512 us. 
+
+tx_coalesce=n			- Number of tx frame handled each interrupt.
+				  Set n > 1 can reduce the interrupts 
+				  congestion usually lower performance of
+				  high speed network card. Default is 16.
 				  
-rx_flow=[1|0]			- Specifies the Rx flow control. If rx_flow=1, 
-				  the Rx flow control enable.
+tx_flow=[1|0]			- Specifies the Tx flow control. If tx_flow=0, 
+				  the Tx flow control disable else driver
+				  autodetect.
+rx_flow=[1|0]			- Specifies the Rx flow control. If rx_flow=0, 
+				  the Rx flow control enable else driver
+				  autodetect.
 
 
 Configuration Script Sample
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/networking/e100.txt linux-2.4.20/Documentation/networking/e100.txt
--- linux-2.4.19/Documentation/networking/e100.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/networking/e100.txt	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,253 @@
+Linux* Base Driver for the Intel(R) PRO/100 Family of Adapters
+==============================================================
+
+September 16, 2002
+
+
+Contents
+========
+
+- In This Release
+- Supported Adapters
+- Command Line Parameters
+- CPU Cycle Saver
+- Additional Configurations
+- Support
+
+
+In This Release
+===============
+
+This file describes the Linux* Base Driver for the Intel(R) PRO/100 Family of
+Adapters, version 2.1.x.  This driver includes support for Itanium(TM)-based 
+systems.
+
+
+Supported Adapters
+==================
+
+The following Intel network adapters are compatible with the drivers 
+in this release:
+
+Controller  Adapter Name                            Board IDs
+----------  ------------                            ---------
+
+82558       PRO/100+ PCI Adapter                    668081-xxx, 689661-xxx
+
+82558       PRO/100+ Management Adapter             691334-xxx, 701738-xxx,
+                                                    721383-xxx
+
+82558       PRO/100+ Dual Port Server Adapter       714303-xxx, 711269-xxx, 
+                                                    A28276-xxx
+
+82558       PRO/100+ PCI Server Adapter             710550-xxx
+
+82550       PRO/100 S Server Adapter                752438-xxx (82550)
+82559                                               A56831-xxx, A10563-xxx,
+                                                    A12171-xxx, A12321-xxx, 
+                                                    A12320-xxx, A12170-xxx
+                                                    748568-xxx (82559)
+                                                    748565-xxx (82559)
+
+
+82550       PRO/100 S Desktop Adapter               751767-xxx (82550)
+82559                                               748592-xxx, A12167-xxx, 
+                                                    A12318-xxx, A12317-xxx, 
+                                                    A12165-xxx
+                                                    748569-xxx (82559)
+
+
+
+82559       PRO/100+ Server Adapter                 729757-xxx
+
+82559       PRO/100 S Management Adapter            748566-xxx, 748564-xxx
+
+82550       PRO/100 S Dual Port Server Adapter      A56831-xxx
+
+82551       PRO/100 M Desktop Adapter               A80897-xxx
+
+            PRO/100 S Advanced Management Adapter   747842-xxx, 745171-xxx
+
+CNR         PRO/100 VE Desktop Adapter              A10386-xxx, A10725-xxx, 
+                                                    A23801-xxx, A19716-xxx
+
+
+            PRO/100 VM Desktop Adapter              A14323-xxx, A19725-xxx, 
+                                                    A23801-xxx, A22220-xxx, 
+                                                    A23796-xxx
+   
+
+To verify that your adapter is supported, find the board ID number on the 
+adapter. Look for a label that has a barcode and a number in the format 
+A12345-001. Match this to the list of numbers above.
+
+For more information on how to identify your adapter, go to the Adapter & 
+Driver ID Guide at:
+
+  http://support.intel.com/support/network/adapter/pro100/21397.htm
+
+For the latest Intel PRO/100 network driver for Linux, see:
+
+  http://downloadfinder.intel.com/scripts-df/support_intel.asp
+
+
+Command Line Parameters
+=======================
+
+The following optional parameters are used by entering them on the command 
+line with the modprobe or insmod command using this syntax:
+
+     modprobe e100 [<option>=<VAL1>,<VAL2>,...]
+
+     insmod e100 [<option>=<VAL1>,<VAL2>,...] 
+
+For example, with two Intel PRO/100 PCI adapters, entering:
+	
+     modprobe e100 TxDescriptors=32,128
+
+loads the e100 driver with 32 TX resources for the first adapter and 128 TX 
+resources for the second adapter. This configuration favors the second 
+adapter. The driver supports up to 16 network adapters concurrently.
+
+The default value for each parameter is generally the recommended setting,
+unless otherwise noted.
+
+NOTE: Giving any command line option the value "-1" causes the driver to use 
+      the appropriate default value for that option, as if no value was 
+      specified.
+
+
+BundleMax
+Valid Range: 1-65535
+Default Value: 6
+   This parameter holds the maximum number of small packets (less than 128
+   bytes) in a bundle. Suggested values range from 2 to 10. See "CPU Cycle 
+   Saver."
+
+BundleSmallFr
+Valid Range: 0-1 (0=off, 1=on)
+Default Value: 0
+   The value 1 (on) causes small packets (less than 128 bytes) to be bundled. 
+   See "CPU Cycle Saver."
+
+e100_speed_duplex
+Valid Range: 0-4 (1=10half;2=10full;3=100half;4=100full)
+Default Value: 0
+   The default value of 0 sets the adapter to auto-negotiate. Other values
+   set the adapter to forced speed and duplex. 
+   Example usage: insmod e100.o e100_speed_duplex=4,4 (for two adapters)
+
+flow_control
+Valid Range: 0-1 (0=off, 1=on)
+Default Value: 0
+   This parameter controls the automatic generation(Tx) and response(Rx) to 
+   Ethernet PAUSE frames. flow_control should NOT be set to 1 when the 
+   adapter is connected to an interface that does not support Ethernet PAUSE 
+   frames and when the e100_speed_duplex parameter is NOT set to zero. 
+
+IntDelay
+Valid Range: 0-65535 (0=off)
+Default Value: 1536
+   This parameter holds the number of time units (in adapter terminology)
+   until the adapter generates an interrupt. The recommended value for 
+   IntDelay is 1536 (upon initialization). Suggested values range from 
+   512 to 2048. See "CPU Cycle Saver."
+
+IFS
+Valid Range: 0-1 (0=off, 1=on)
+Default Value: 1
+  Inter Frame Spacing (IFS) aims to reduce the number of Ethernet frame
+  collisions by altering the time between frame transmissions. When IFS is 
+  enabled the driver tries to find an optimal IFS value. It is used only at 
+  half duplex.
+
+RxDescriptors
+Valid Range: 8-1024
+Default Value: 64
+   This parameter defines the number of receive descriptors allocated by 
+   the driver. Increasing this value allows the driver to buffer more 
+   incoming packets before the driver is required to service an interrupt. 
+   The maximum value for Itanium-based systems is 64.
+
+TxDescriptors
+Valid Range: 19-1024
+Default Value: 64
+   This value is the number of transmit descriptors allocated by the driver. 
+   Increasing this value allows the protocol stack to queue more transmits at
+   the driver level. The maximum value for Itanium-based systems is 64.
+
+ucode
+Valid Range: 0-1 (0=off, 1=on)
+Default Value: 0 for 82558-based adapters
+               1 for 82559, 82550, and 82551-based adapters
+   On uploads the micro code to the adapter, which enables CPU Cycle Saver. 
+   See the section "CPU Cycle Saver" below.
+   Example usage: insmod e100.o ucode=1
+
+   Not available on 82557-based adapters.
+
+XsumRX
+Valid Range: 0-1 (0=off, 1=on)
+Default Value: 1
+   On allows Rx checksum offloading for TCP/UDP packets. Requires that the 
+   hardware support this feature.
+
+   Not available on 82557 and 82558-based adapters.
+
+
+CPU Cycle Saver
+================
+
+CPU Cycle Saver reduces CPU utilization by reducing the number of interrupts 
+that the adapter generates.
+
+When CPU Cycle Saver is turned off, the adapter generates one interrupt for 
+every frame that is received. This means that the operating system stops what
+it is doing and switches to the network driver in order to process the 
+receive.
+
+When CPU Cycle Saver is on, the adapter does not generate an interrupt for 
+every frame it receives. Instead, it waits until it receives several frames 
+before generating an interrupt. This reduces the amount of time spent 
+switching to and from the driver. 
+
+CPU Cycle Saver consists of these arguments: IntDelay, BundleMax and 
+BundleSmallFr. When IntDelay is increased, the adapter waits longer for 
+frames to arrive before generating the interrupt. By increasing BundleMax, 
+the network adapter waits for the number of small frames (less than 128 bytes)
+specified to arrive before generating the interrupt. When BundleSmallFr is 
+disabled, the adapter does not bundle small packets. Such small packets are 
+often, but not always, control packets that are better served immediately;
+therefore, BundleSmallFr is disabled by default.
+
+For most users, it is recommended that CPU Cycle Saver be used with the 
+default values specified in the Command Line Parameters section. However, in 
+some cases, performance problems may occur with CPU Cycle Saver. If such 
+problems are observed, we recommend turning off this feature by setting 
+ucode=0.
+
+
+Support
+=======
+
+For general information, go to the Intel support website at:
+
+    http://support.intel.com
+
+If an issue is identified with the released source code on the supported
+kernel with a supported adapter, email the specific information related to 
+the issue to linux.nics@intel.com.
+
+
+License
+=======
+
+This software program is released under the terms of a license agreement 
+between you ('Licensee') and Intel. Do not use or load this software or any 
+associated materials (collectively, the 'Software') until you have carefully 
+read the full terms and conditions of the LICENSE located in this software 
+package. By loading or using the Software, you agree to the terms of this 
+Agreement. If you do not agree with the terms of this Agreement, do not 
+install or use the Software.
+
+* Other names and brands may be claimed as the property of others.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/networking/e1000.txt linux-2.4.20/Documentation/networking/e1000.txt
--- linux-2.4.19/Documentation/networking/e1000.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/networking/e1000.txt	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,302 @@
+Linux* Base Driver for the Intel(R) PRO/1000 Family of Adapters
+===============================================================
+
+October 12, 2002
+
+
+Contents
+========
+
+- In This Release
+- Supported Adapters
+- Command Line Parameters
+- Speed and Duplex Configuration
+- Additional Configurations
+- Known Issues
+- Support
+
+
+In This Release
+===============
+
+This file describes the Linux* Base Driver for the Intel(R) PRO/1000 Family
+of Adapters, version 4.4.x.  This driver includes support for 
+Itanium(TM)-based systems.
+
+This release version includes the following:
+
+   - Support for the ethtool 1.6 interface. A third-party application can use
+     the ethtool interface to get and set driver parameters.
+
+   - Zero copy. This feature provides faster data throughput. Enabled by
+     default in supporting kernels. It is not supported on the Intel(R)
+     PRO/1000 Gigabit Server Adapter.
+
+Features include:
+
+   - Support for the 82545 and 82546-based adapters listed below
+
+   - Wake on LAN* support via ethtool for 82540, 82544, 82545, and 82546-
+     based adapters
+
+   - Adaptive IFS for increased performance at half duplex
+
+
+
+Supported Adapters
+==================
+
+The following Intel network adapters are compatible with the drivers in this
+release:
+
+   Controller  Adapter Name                         Board IDs
+   ----------  ------------                         ---------
+
+   82542       PRO/1000 Gigabit Server Adapter      700262-xxx, 717037-xxx
+
+   82543       PRO/1000 F Server Adapter            738640-xxx, A38888-xxx
+
+   82543       PRO/1000 T Server Adapter            A19845-xxx, A33948-xxx
+
+   82544       PRO/1000 XT Server Adapter           A51580-xxx
+
+   82544       PRO/1000 XF Server Adapter           A50484-xxx
+
+   82544       PRO/1000 T Desktop Adapter           A62947-xxx
+
+   82540       PRO/1000 MT Desktop Adapter          A78408-xxx
+
+   82545       PRO/1000 MT Server Adapter           A92165-xxx
+
+   82546       PRO/1000 MT Dual Port Server Adapter A92111-xxx
+
+   82545       PRO/1000 MF Server Adapter           A91622-xxx
+
+   82545       PRO/1000 MF Server Adapter(LX)       A91624-xxx
+
+   82546       PRO/1000 MF Dual Port Server Adapter A91620-xxx
+
+
+To verify your Intel adapter is supported, find the board ID number on the
+adapter. Look for a label that has a barcode and a number in the format of
+123456-001 (six digits hyphen three digits). Match this to the list of
+numbers above.
+
+For more information on how to identify your adapter, go to the Adapter &
+Driver ID Guide at:
+
+    http://support.intel.com/support/network/adapter/pro100/21397.htm
+
+For the latest Intel network drivers for Linux, go to:
+
+    http://appsr.intel.com/scripts-df/support_intel.asp
+
+
+Command Line Parameters
+=======================
+
+If the driver is built as a module, the following optional parameters are 
+used by entering them on the command line with the modprobe or insmod command. 
+For example, with two PRO/1000 PCI adapters, entering:
+
+    insmod e1000 TxDescriptors=80,128
+
+loads the e1000 driver with 80 TX resources for the first adapter and 128 TX
+resources for the second adapter.
+
+For more information about the AutoNeg, Duplex, and Speed parameters, see the
+"Speed and Duplex Configuration" section in this document.
+
+
+AutoNeg (adapters using copper connections only)
+Valid Range: 0x01-0x0F, 0x20-0x2F
+Default Value: 0x2F
+    This parameter is a bit mask that specifies which speed and duplex
+    settings the board advertises. When this parameter is used, the Speed and
+    Duplex parameters must not be specified.  
+
+Duplex (adapters using copper connections only)
+Valid Range: 0-2 (0=auto-negotiate, 1=half, 2=full)
+Default Value: 0
+    Defines the direction in which data is allowed to flow. Can by either one 
+    or two-directional. If both Duplex and the link partner are set to auto-
+    negotiate, the board auto-detects the correct duplex. If the link partner
+    is forced (either full or half), Duplex defaults to half-duplex.
+
+FlowControl
+Valid Range: 0-3 (0=none, 1=Rx only, 2=Tx only, 3=Rx&Tx)
+Default: Read flow control settings from the EEPROM
+    This parameter controls the automatic generation(Tx) and response(Rx) to 
+    Ethernet PAUSE frames.
+
+RxDescriptors
+Valid Range: 80-256 for 82542 and 82543-based adapters
+             80-4096 for 82540, 82544, 82545, and 82546-based adapters
+Default Value: 80
+    This value is the number of receive descriptors allocated by the driver. 
+    Increasing this value allows the driver to buffer more incoming packets. 
+    Each descriptor is 16 bytes.  A receive buffer is also allocated for each
+    descriptor and can be either 2048, 4096, 8192, or 16384 bytes, depending 
+    on the MTU setting. The maximum MTU size is 16110.
+
+    NOTE: MTU designates the frame size. It only needs to be set for Jumbo 
+          Frames.
+
+RxIntDelay
+Valid Range: 0-65535 (0=off)
+Default Value: 0
+    This value delays the generation of receive interrupts in units of 1.024 
+    microseconds.  Receive interrupt reduction can improve CPU efficiency if 
+    properly tuned for specific network traffic. Increasing this value adds 
+    extra latency to frame reception and can end up decreasing the throughput 
+    of TCP traffic. If the system is reporting dropped receives, this value 
+    may be set too high, causing the driver to run out of available receive 
+    descriptors.
+
+    CAUTION: When setting RxIntDelay to a value other than 0, adapters may 
+             hang (stop transmitting) under certain network conditions. If
+             this occurs a NETDEV WATCHDOG message is logged in the system
+             event log. In addition, the controller is automatically reset,
+             restoring the network connection. To eliminate the potential for
+             the hang ensure that RxIntDelay is set to 0.
+
+RxAbsIntDelay (82540, 82545, and 82546-based adapters only)
+Valid Range: 0-65535 (0=off)
+Default Value: 128
+    This value, in units of 1.024 microseconds, limits the delay in which a 
+    transmit interrupt is generated. Useful only if RxIntDelay is non-zero, 
+    this value ensures that an interrupt is generated after the initial 
+    packet is received within the set amount of time.  Proper tuning,
+    along with RxIntDelay, may improve traffic throughput in specific network
+    conditions.
+
+Speed (adapters using copper connections only)
+Valid Settings: 0, 10, 100, 1000
+Default Value: 0 (auto-negotiate at all supported speeds)
+    Speed forces the line speed to the specified value in megabits per second
+    (Mbps). If this parameter is not specified or is set to 0 and the link 
+    partner is set to auto-negotiate, the board will auto-detect the correct 
+    speed. Duplex must also be set when Speed is set to either 10 or 100.
+
+TxDescriptors
+Valid Range: 80-256 for 82542 and 82543-based adapters
+             80-4096 for 82540, 82544, 82545, and 82546-based adapters
+Default Value: 256
+    This value is the number of transmit descriptors allocated by the driver.
+    Increasing this value allows the driver to queue more transmits. Each 
+    descriptor is 16 bytes.
+
+TxIntDelay
+Valid Range: 0-65535 (0=off)
+Default Value: 64
+    This value delays the generation of transmit interrupts in units of 
+    1.024 microseconds.  Transmit interrupt reduction can improve CPU
+    efficiency if properly tuned for specific network traffic. If the
+    system is reporting dropped transmits, this value may be set too high
+    causing the driver to run out of available transmit descriptors.
+
+TxAbsIntDelay (82540, 82545, and 82546-based adapters only)
+Valid Range: 0-65535 (0=off)
+Default Value: 64
+    This value, in units of 1.024 microseconds, limits the delay in which a 
+    transmit interrupt is generated. Useful only if TxIntDelay is non-zero, 
+    this value ensures that an interrupt is generated after the initial 
+    packet is sent on the wire within the set amount of time.  Proper tuning,
+    along with TxIntDelay, may improve traffic throughput in specific 
+    network conditions.
+
+XsumRX (not available on the PRO/1000 Gigabit Server Adapter)
+Valid Range: 0-1
+Default Value: 1
+    A value of '1' indicates that the driver should enable IP checksum
+    offload for received packets (both UDP and TCP) to the adapter hardware.
+
+
+Speed and Duplex Configuration
+==============================
+
+Three keywords are used to control the speed and duplex configuration. These
+keywords are Speed, Duplex, and AutoNeg.
+
+If the board uses a fiber interface, these keywords are ignored, and the
+fiber interface board only links at 1000 Mbps full-duplex.
+
+For copper-based boards, the keywords interact as follows:
+
+  The default operation is auto-negotiate. The board advertises all supported
+  speed and duplex combinations, and it links at the highest common speed and
+  duplex mode IF the link partner is set to auto-negotiate.
+
+  If Speed = 1000, limited auto-negotiation is enabled and only 1000 Mbps is
+  advertised (The 1000BaseT spec requires auto-negotiation.)
+
+  If Speed = 10 or 100, then both Speed and Duplex must be set. Auto-
+  negotiation is disabled, and the AutoNeg parameter is ignored. Partner MUST
+  also be forced.
+
+The AutoNeg parameter is used when more control is required over the auto-
+negotiation process.  When this parameter is used, Speed and Duplex must not
+be specified.  This parameter is a bitmap that specifies which speed and
+duplex settings are advertised to the link partner.
+
+Bit            7      6      5       4       3      2      1       0
+Speed (Mbps)   N/A    N/A    1000    N/A     100    100    10      10
+Duplex                       Full            Full   Half   Full    Half
+
+Note that setting AutoNeg does not guarantee that the board will link at the
+highest specified speed or duplex mode, but the board will link at the
+highest possible speed/duplex of the link partner IF the link partner is also
+set to auto-negotiate. If the link partner is forced speed/duplex, the
+adapter MUST be forced to the same speed/duplex.
+
+
+Additional Configurations
+=========================
+
+  Jumbo Frames
+  ------------
+
+  The driver supports Jumbo Frames for all adapters except 82542-based
+  adapters.  Jumbo Frames support is enabled by changing the MTU to a value
+  larger than the default of 1500.  Use the ifconfig command to increase the
+  MTU size. For example:
+
+        ifconfig ethx mtu 9000 up
+
+
+Known Issues
+============
+
+  Jumbo Frames System Requirement
+  -------------------------------
+
+  Memory allocation failures have been observed on Linux systems with 64 MB
+  of RAM or less that are running Jumbo Frames. If you are using Jumbo
+  Frames, your system may require more than the advertised minimum
+  requirement of 64 MB of system memory.
+
+
+Support
+=======
+
+For general information and support, go to the Intel support website at:
+
+    http://support.intel.com
+
+If an issue is identified with the released source code on the supported
+kernel with a supported adapter, email the specific information related to
+the issue to linux.nics@intel.com.
+
+
+License
+=======
+
+This software program is released under the terms of a license agreement
+between you ('Licensee') and Intel. Do not use or load this software or any
+associated materials (collectively, the 'Software') until you have carefully
+read the full terms and conditions of the LICENSE located in this software
+package. By loading or using the Software, you agree to the terms of this
+Agreement. If you do not agree with the terms of this Agreement, do not
+install or use the Software.
+
+* Other names and brands may be claimed as the property of others.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/networking/ewrk3.txt linux-2.4.20/Documentation/networking/ewrk3.txt
--- linux-2.4.19/Documentation/networking/ewrk3.txt	1998-05-21 01:54:34.000000000 +0000
+++ linux-2.4.20/Documentation/networking/ewrk3.txt	2002-10-29 11:18:34.000000000 +0000
@@ -24,6 +24,7 @@
     kernel with the ewrk3 configuration turned off and reboot.
     5) insmod ewrk3.o
           [Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y]
+          [Adam Kropelin: Multiple cards now supported by irq=x1,x2 io=y1,y2]
     6) run the net startup bits for your new eth?? interface manually 
     (usually /etc/rc.inet[12] at boot time). 
     7) enjoy!
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/networking/khttpd.txt linux-2.4.20/Documentation/networking/khttpd.txt
--- linux-2.4.19/Documentation/networking/khttpd.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/networking/khttpd.txt	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1 @@
+See net/khttpd/README for documentation on khttpd, the kernel http server.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/networking/pktgen.txt linux-2.4.20/Documentation/networking/pktgen.txt
--- linux-2.4.19/Documentation/networking/pktgen.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/networking/pktgen.txt	2002-10-29 11:18:49.000000000 +0000
@@ -4,6 +4,9 @@
    in the place where insmod may find it.
 2. Cut script "ipg" (see below).
 3. Edit script to set preferred device and destination IP address.
+3a.  Create more scripts for different interfaces.  Up to thirty-two
+     pktgen processes can be configured and run at once by using the
+     32 /proc/net/pg* files.
 4. Run in shell: ". ipg"
 5. After this two commands are defined:
    A. "pg" to start generator and to get results.
@@ -12,12 +15,33 @@
       pgset "multiskb 0"      use single SKB for all transmits
       pgset "pkt_size 9014"   sets packet size to 9014
       pgset "frags 5"         packet will consist of 5 fragments
-      pgset "count 200000"    sets number of packets to send
+      pgset "count 200000"    sets number of packets to send, set to zero
+                              for continious sends untill explicitly
+                              stopped.
       pgset "ipg 5000"        sets artificial gap inserted between packets
                               to 5000 nanoseconds
       pgset "dst 10.0.0.1"    sets IP destination address
                               (BEWARE! This generator is very aggressive!)
+      pgset "dst_min 10.0.0.1"            Same as dst
+      pgset "dst_max 10.0.0.254"          Set the maximum destination IP.
+      pgset "src_min 10.0.0.1"            Set the minimum (or only) source IP.
+      pgset "src_max 10.0.0.254"          Set the maximum source IP.
       pgset "dstmac 00:00:00:00:00:00"    sets MAC destination address
+      pgset "srcmac 00:00:00:00:00:00"    sets MAC source address
+      pgset "src_mac_count 1" Sets the number of MACs we'll range through.  The
+                              'minimum' MAC is what you set with srcmac.
+      pgset "dst_mac_count 1" Sets the number of MACs we'll range through.  The
+                              'minimum' MAC is what you set with dstmac.
+      pgset "flag [name]"     Set a flag to determine behaviour.  Current flags
+                              are: IPSRC_RND #IP Source is random (between min/max),
+                                   IPDST_RND, UDPSRC_RND,
+                                   UDPDST_RND, MACSRC_RND, MACDST_RND 
+      pgset "udp_src_min 9"   set UDP source port min, If < udp_src_max, then
+                              cycle through the port range.
+      pgset "udp_src_max 9"   set UDP source port max.
+      pgset "udp_dst_min 9"   set UDP destination port min, If < udp_dst_max, then
+                              cycle through the port range.
+      pgset "udp_dst_max 9"   set UDP destination port max.
       pgset stop    	      aborts injection
       
   Also, ^C aborts generator.
@@ -26,22 +50,24 @@
 
 #! /bin/sh
 
-modprobe pktgen.o
+modprobe pktgen
+
+PGDEV=/proc/net/pg/pg0
 
 function pgset() {
     local result
 
-    echo $1 > /proc/net/pg
+    echo $1 > $PGDEV
 
-    result=`cat /proc/net/pg | fgrep "Result: OK:"`
+    result=`cat $PGDEV | fgrep "Result: OK:"`
     if [ "$result" = "" ]; then
-         cat /proc/net/pg | fgrep Result:
+         cat $PGDEV | fgrep Result:
     fi
 }
 
 function pg() {
-    echo inject > /proc/net/pg
-    cat /proc/net/pg
+    echo inject > $PGDEV
+    cat $PGDEV
 }
 
 pgset "odev eth0"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/networking/tuntap.txt linux-2.4.20/Documentation/networking/tuntap.txt
--- linux-2.4.19/Documentation/networking/tuntap.txt	2001-04-25 21:59:56.000000000 +0000
+++ linux-2.4.20/Documentation/networking/tuntap.txt	2002-10-29 11:18:39.000000000 +0000
@@ -7,43 +7,71 @@
   FreeBSD TAP driver 
   Copyright (c) 1999-2000 Maksim Yevmenkin <m_evmenkin@yahoo.com>
 
+  Revision of this document 2002 by Florian Thiel <florian.thiel@gmx.net>
+
 1. Description
   TUN/TAP provides packet reception and transmission for user space programs. 
-  It can be viewed as a simple Point-to-Point or Ethernet device, which 
-  instead of receiving packets from a physical media, receives them from 
+  It can be seen as a simple Point-to-Point or Ethernet device, which,
+  instead of receiving packets from physical media, receives them from 
   user space program and instead of sending packets via physical media 
   writes them to the user space program. 
 
-  When a program opens /dev/net/tun, driver creates and registers corresponding
-  net device tunX or tapX. After a program closed above devices, driver will 
-  automatically delete tunXX or tapXX device and all routes corresponding to it.
-
-  This package(http://vtun.sourceforge.net/tun) contains two simple example 
-  programs how to use tun and tap devices. Both programs works like 
-  bridge between two network interfaces.
+  In order to use the driver a program has to open /dev/net/tun and issue a
+  corresponding ioctl() to register a network device with the kernel. A network
+  device will appear as tunXX or tapXX, depending on the options chosen. When
+  the program closes the file descriptor, the network device and all
+  corresponding routes will disappear.
+
+  Depending on the type of device chosen the userspace program has to read/write
+  IP packets (with tun) or ethernet frames (with tap). Which one is being used
+  depends on the flags given with the ioctl().
+
+  The package from http://vtun.sourceforge.net/tun contains two simple examples
+  for how to use tun and tap devices. Both programs work like a bridge between
+  two network interfaces.
   br_select.c - bridge based on select system call.
   br_sigio.c  - bridge based on async io and SIGIO signal.
-  However the best example is VTun http://vtun.sourceforge.net :))  
+  However, the best example is VTun http://vtun.sourceforge.net :))
 
 2. Configuration 
   Create device node:
+     mkdir /dev/net (if it doesn't exist already)
      mknod /dev/net/tun c 10 200
+  
+  Set permissions:
+     e.g. chmod 0700 /dev/net/tun
+     if you want the device only accesible by root. Giving regular users the
+     right to assign network devices is NOT a good idea. Users could assign
+     bogus network interfaces to trick firewalls or administrators.
 
   Driver module autoloading
      Make sure that "Kernel module loader" - module auto-loading support is enabled 
      in your kernel. 
 
-     Add following line to the /etc/modules.conf:
+     Add the following line to the /etc/modules.conf:
 	alias char-major-10-200 tun
-     
-     Run:
+     and run
         depmod -a 
-
-     Driver will be automatically loaded when application access /dev/net/tun.
+  
+  Manual loading 
+     insert the module by hand:
+        modprobe tun
+
+  If you do it the latter way, you have to load the module every time you
+  need it, if you do it the other way it will be automatically loaded when
+  /dev/net/tun is being opened.
 
 3. Program interface 
   3.1 Network device allocation:
 
+  char *dev should be the name of the device with a format string (e.g.
+  "tun%d"), but (as far as I can see) this can be any valid network device name.
+  Note that the character pointer becomes overwritten with the real device name
+  (e.g. "tun0")
+
+  #include <linux/if.h>
+  #include <linux/if_tun.h>
+
   int tun_alloc(char *dev)
   {
       struct ifreq ifr;
@@ -79,65 +107,44 @@
 
 Universal TUN/TAP device driver Frequently Asked Question.
    
-1. What is the TUN ?
-The TUN is Virtual Point-to-Point network device.
-TUN driver was designed as low level kernel support for
-IP tunneling. It provides to userland application
-two interfaces:
-  - /dev/tunX	- character device;
-  - tunX	- virtual Point-to-Point interface.
-
-Userland application can write IP frame to /dev/tunX
-and kernel will receive this frame from tunX interface. 
-In the same time every frame that kernel writes to tunX 
-interface can be read by userland application from /dev/tunX
-device.
-
-2. What is the TAP ?
-The TAP is a Virtual Ethernet network device.
-TAP driver was designed as low level kernel support for
-Ethernet tunneling. It provides to userland application
-two interfaces:
-  - /dev/tapX	- character device;
-  - tapX	- virtual Ethernet interface.
-
-Userland application can write Ethernet frame to /dev/tapX
-and kernel will receive this frame from tapX interface. 
-In the same time every frame that kernel writes to tapX 
-interface can be read by userland application from /dev/tapX
-device.
-
-3. What platforms are supported by TUN/TAP driver ?
+1. What platforms are supported by TUN/TAP driver ?
 Currently driver has been written for 3 Unices:
    Linux kernels 2.2.x, 2.4.x 
    FreeBSD 3.x, 4.x, 5.x
    Solaris 2.6, 7.0, 8.0
 
-4. What is TUN/TAP driver used for?
+2. What is TUN/TAP driver used for?
 As mentioned above, main purpose of TUN/TAP driver is tunneling. 
 It is used by VTun (http://vtun.sourceforge.net).
 
-5. How does Virtual network device actually work ? 
+Another interesting application using TUN/TAP is pipsecd
+(http://perso.enst.fr/~beyssac/pipsec/), an userspace IPSec
+implementation that can use complete kernel routing (unlike FreeS/WAN).
+
+3. How does Virtual network device actually work ? 
 Virtual network device can be viewed as a simple Point-to-Point or
 Ethernet device, which instead of receiving packets from a physical 
 media, receives them from user space program and instead of sending 
 packets via physical media sends them to the user space program. 
 
 Let's say that you configured IPX on the tap0, then whenever 
-kernel sends any IPX packet to tap0, it is passed to the application
-(VTun for example). Application encrypts, compresses and sends it to 
-the other side over TCP or UDP. Application on other side decompress 
-and decrypts them and write packet to the TAP device, kernel handles 
-the packet like it came from real physical device.
+the kernel sends an IPX packet to tap0, it is passed to the application
+(VTun for example). The application encrypts, compresses and sends it to 
+the other side over TCP or UDP. The application on the other side decompresses
+and decrypts the data received and writes the packet to the TAP device, 
+the kernel handles the packet like it came from real physical device.
 
-6. What is the difference between TUN driver and TAP driver?
+4. What is the difference between TUN driver and TAP driver?
 TUN works with IP frames. TAP works with Ethernet frames.
 
-7. What is the difference between BPF and TUN/TAP driver?
-BFP is a advanced packet filter. It can be attached to existing
-network interface. It does not provide virtual network interface.
-TUN/TAP driver does provide virtual network interface and it is possible
+This means that you have to read/write IP packets when you are using tun and
+ethernet frames when using tap.
+
+5. What is the difference between BPF and TUN/TAP driver?
+BFP is an advanced packet filter. It can be attached to existing
+network interface. It does not provide a virtual network interface.
+A TUN/TAP driver does provide a virtual network interface and it is possible
 to attach BPF to this interface.
 
-8. Does TAP driver support kernel Ethernet bridging?
+6. Does TAP driver support kernel Ethernet bridging?
 Yes. Linux and FreeBSD drivers support Ethernet bridging. 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/parisc/00-INDEX linux-2.4.20/Documentation/parisc/00-INDEX
--- linux-2.4.19/Documentation/parisc/00-INDEX	2000-12-05 20:29:38.000000000 +0000
+++ linux-2.4.20/Documentation/parisc/00-INDEX	2002-10-29 11:18:49.000000000 +0000
@@ -1,10 +1,10 @@
 00-INDEX
 	- this file.
 IODC.txt
-	- Documentation IODC
+	- Documentation for IODC
 debugging
 	- some debugging hints for real-mode code
-mm
-	- Documentation on parisc mm status
+unwritten
+	- list of unwritten / incomplete functions
 registers
 	- current/planned usage of registers
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/parisc/registers linux-2.4.20/Documentation/parisc/registers
--- linux-2.4.19/Documentation/parisc/registers	2001-09-14 21:04:06.000000000 +0000
+++ linux-2.4.20/Documentation/parisc/registers	2002-10-29 11:18:31.000000000 +0000
@@ -25,8 +25,8 @@
 CR27 (TR 3)			Thread descriptor pointer
 CR28 (TR 4)			not used
 CR29 (TR 5)			not used
-CR30 (TR 6)			current / 0
-CR31 (TR 7)			Temporary register, used in various places
+CR30 (TR 6)			current
+CR31 (TR 7)			interrupt stack base
 
 	Space Registers (kernel mode)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/powerpc/00-INDEX linux-2.4.20/Documentation/powerpc/00-INDEX
--- linux-2.4.19/Documentation/powerpc/00-INDEX	2000-06-20 14:24:52.000000000 +0000
+++ linux-2.4.20/Documentation/powerpc/00-INDEX	2002-10-29 11:18:34.000000000 +0000
@@ -5,6 +5,9 @@
 
 00-INDEX
 	- this file
+cpu_features.txt
+	- info on how we support a variety of CPUs with minimal compile-time
+	options.
 ppc_htab.txt
 	- info about the Linux/PPC /proc/ppc_htab entry
 smp.txt
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/powerpc/cpu_features.txt linux-2.4.20/Documentation/powerpc/cpu_features.txt
--- linux-2.4.19/Documentation/powerpc/cpu_features.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/powerpc/cpu_features.txt	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,56 @@
+Hollis Blanchard <hollis@austin.ibm.com>
+5 Jun 2002
+
+This document describes the system (including self-modifying code) used in the
+PPC Linux kernel to support a variety of PowerPC CPUs without requiring
+compile-time selection.
+
+Early in the boot process the ppc32 kernel detects the current CPU type and
+chooses a set of features accordingly. Some examples include Altivec support,
+split instruction and data caches, and if the CPU supports the DOZE and NAP
+sleep modes.
+
+Detection of the feature set is simple. A list of processors can be found in
+arch/ppc/kernel/cputable.c. The PVR register is masked and compared with each
+value in the list. If a match is found, the cpu_features of cur_cpu_spec is
+assigned to the feature bitmask for this processor and a __setup_cpu function
+is called.
+
+C code may test 'cur_cpu_spec[smp_processor_id()]->cpu_features' for a
+particular feature bit. This is done in quite a few places, for example
+in ppc_setup_l2cr().
+
+Implementing cpufeatures in assembly is a little more involved. There are
+several paths that are performance-critical and would suffer if an array
+index, structure dereference, and conditional branch were added. To avoid the
+performance penalty but still allow for runtime (rather than compile-time) CPU
+selection, unused code is replaced by 'nop' instructions. This nop'ing is
+based on CPU 0's capabilities, so a multi-processor system with non-identical
+processors will not work (but such a system would likely have other problems
+anyways).
+
+After detecting the processor type, the kernel patches out sections of code
+that shouldn't be used by writing nop's over it. Using cpufeatures requires
+just 2 macros (found in include/asm-ppc/cputable.h), as seen in head.S
+transfer_to_handler:
+
+	#ifdef CONFIG_ALTIVEC
+	BEGIN_FTR_SECTION
+		mfspr	r22,SPRN_VRSAVE		/* if G4, save vrsave register value */
+		stw	r22,THREAD_VRSAVE(r23)
+	END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+	#endif /* CONFIG_ALTIVEC */
+
+If CPU 0 supports Altivec, the code is left untouched. If it doesn't, both
+instructions are replaced with nop's.
+
+The END_FTR_SECTION macro has two simpler variations: END_FTR_SECTION_IFSET
+and END_FTR_SECTION_IFCLR. These simply test if a flag is set (in
+cur_cpu_spec[0]->cpu_features) or is cleared, respectively. These two macros
+should be used in the majority of cases.
+
+The END_FTR_SECTION macros are implemented by storing information about this
+code in the '__ftr_fixup' ELF section. When do_cpu_ftr_fixups
+(arch/ppc/kernel/misc.S) is invoked, it will iterate over the records in
+__ftr_fixup, and if the required feature is not present it will loop writing
+nop's from each BEGIN_FTR_SECTION to END_FTR_SECTION.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/s390/3270.ChangeLog linux-2.4.20/Documentation/s390/3270.ChangeLog
--- linux-2.4.19/Documentation/s390/3270.ChangeLog	2001-04-12 19:03:50.000000000 +0000
+++ linux-2.4.20/Documentation/s390/3270.ChangeLog	2002-10-29 11:18:32.000000000 +0000
@@ -1,5 +1,34 @@
 ChangeLog for the UTS Global 3270-support patch
 
+Sep 2002:	Get bootup colors right on 3270 console
+	* In tubttybld.c, substantially revise ESC processing so that
+	  ESC sequences (especially coloring ones) and the strings
+	  they affect work as right as 3270 can get them.  Also, set
+	  screen height to omit the two rows used for input area, in
+	  tty3270_open() in tubtty.c.
+
+Sep 2002:	Dynamically get 3270 input buffer
+	* Oversize 3270 screen widths may exceed GEOM_MAXINPLEN columns,
+	  so get input-area buffer dynamically when sizing the device in
+	  tubmakemin() in tuball.c (if it's the console) or tty3270_open()
+	  in tubtty.c (if needed).  Change tubp->tty_input to be a
+	  pointer rather than an array, in tubio.h.
+
+Sep 2002:	Fix tubfs kmalloc()s
+	* Do read and write lengths correctly in fs3270_read()
+	  and fs3270_write(), whilst never asking kmalloc()
+	  for more than 0x800 bytes.  Affects tubfs.c and tubio.h.
+
+Sep 2002:	Recognize 3270 control unit type 3174
+	* Recognize control-unit type 0x3174 as well as 0x327?.
+	  The IBM 2047 device emulates a 3174 control unit.
+	  Modularize control-unit recognition in tuball.c by
+	  adding and invoking new tub3270_is_ours().
+
+Apr 2002:	Fix 3270 console reboot loop
+	* (Belated log entry) Fixed reboot loop if 3270 console,
+	  in tubtty.c:ttu3270_bh().
+
 Feb 6, 2001:
 	* This changelog is new
 	* tub3270 now supports 3270 console:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/sound/Maestro3 linux-2.4.20/Documentation/sound/Maestro3
--- linux-2.4.19/Documentation/sound/Maestro3	2001-02-04 18:05:29.000000000 +0000
+++ linux-2.4.20/Documentation/sound/Maestro3	2002-10-29 11:18:35.000000000 +0000
@@ -71,10 +71,18 @@
 tell the driver to print minimal debugging information as it runs.  This
 can be collected with 'dmesg' or through the klogd daemon.
 
-The other is 'external_amp', which tells the driver to attempt to enable
+One is 'external_amp', which tells the driver to attempt to enable
 an external amplifier.  This defaults to '1', you can tell the driver
 not to bother enabling such an amplifier by setting it to '0'.
 
+And the last is 'gpio_pin', which tells the driver which GPIO pin number
+the external amp uses (0-15), The Allegro uses 8 by default, all others 1.
+If everything loads correctly and seems to be working but you get no sound, 
+try tweaking this value. 
+
+Systems known to need a different value
+        Panasonic ToughBook CF-72: gpio_pin=13 
+
 Power Management
 ----------------
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/sound/forte linux-2.4.20/Documentation/sound/forte
--- linux-2.4.19/Documentation/sound/forte	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/sound/forte	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,41 @@
+
+     forte - an OSS/Lite driver for FortMedia FM801 sound chips
+     ===========================================================
+
+This is a driver for cards using the FortMedia FM801 audio
+controller.  The Genius Sound Maker Live card and the onboard audio in
+HP Workstation zx2000 has been tested.
+
+Both IA-32 and IA-64 architectures are supported, but the driver
+should work on any platform.
+
+The FM801 controller supports a variety of AC'97 codecs.  This driver
+lets the OSS core code figure the codec out, and should thus support
+any codec with support in the Linux kernel.
+
+The driver supports /dev/mixer and /dev/dsp for generic OSS audio
+support.  In general it adheres to the OSS spec to the extent it can
+be done with the way the hardware works.  The FM801 controller doesn't
+support scatter-gather, so if the application sets fragment size too
+low, it puts strict requirements on interrupt processing speed.  The
+driver tries to compensate by enforcing bigger buffers than requested
+by the application if the fragment size is low.
+
+The forte driver includes both standard read()/write() and the
+unsupported mmap() interface used by Quake.  mmap() is only supported
+in playback mode.
+
+U8 and S16 audio formats are supported, mono/stereo, as well as most
+all sample rates implemented by the chip.  Default is 48 KHz, 16-bit,
+mono.
+
+MIDI, FM audio, and the gameport controller are not currently
+supported.
+
+
+The latest version of this driver can be found at:
+
+    http://mkp.net/forte/
+
+
+Martin K. Petersen, July 2002
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/sysctl/vm.txt linux-2.4.20/Documentation/sysctl/vm.txt
--- linux-2.4.19/Documentation/sysctl/vm.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/sysctl/vm.txt	2002-10-29 11:18:49.000000000 +0000
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/vm/*	kernel version 2.2.10
+Documentation for /proc/sys/vm/*	kernel version 2.4.19
 	(c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
 
 For general info and legal blurb, please look in README.
@@ -6,7 +6,7 @@
 ==============================================================
 
 This file contains the documentation for the sysctl files in
-/proc/sys/vm and is valid for Linux kernel version 2.2.
+/proc/sys/vm and is valid for Linux kernel version 2.4.
 
 The files in this directory can be used to tune the operation
 of the virtual memory (VM) subsystem of the Linux kernel, and
@@ -34,26 +34,27 @@
 This file controls the operation of the bdflush kernel
 daemon. The source code to this struct can be found in
 linux/fs/buffer.c. It currently contains 9 integer values,
-of which 4 are actually used by the kernel.
+of which 6 are actually used by the kernel.
 
 From linux/fs/buffer.c:
 --------------------------------------------------------------
 union bdflush_param {
 	struct {
-		int nfract;	/* Percentage of buffer cache dirty to 
+		int nfract;	/* Percentage of buffer cache dirty to
 				   activate bdflush */
-		int dummy1;	/* old "ndirty" */
+		int ndirty;	/* Maximum number of dirty blocks to write out per
+				   wake-cycle */
 		int dummy2;	/* old "nrefill" */
 		int dummy3;	/* unused */
 		int interval;	/* jiffies delay between kupdate flushes */
-		int age_buffer;	/* Time for normal buffer to age */
-		int nfract_sync;/* Percentage of buffer cache dirty to 
+		int age_buffer;	/* Time for normal buffer to age before we flush it */
+		int nfract_sync;/* Percentage of buffer cache dirty to
 				   activate bdflush synchronously */
-		int dummy4;	/* unused */
+		int nfract_stop_bdflush; /* Percentage of buffer cache dirty to stop bdflush */
 		int dummy5;	/* unused */
 	} b_un;
 	unsigned int data[N_PARAM];
-} bdf_prm = {{30, 64, 64, 256, 5*HZ, 30*HZ, 60, 0, 0}};
+} bdf_prm = {{30, 500, 0, 0, 5*HZ, 30*HZ, 60, 20, 0}};
 --------------------------------------------------------------
 
 int nfract:
@@ -68,6 +69,13 @@
 more frequent I/O operations.  The default value is 30%,
 the minimum is 0%, and the maximum is 100%.
 
+int ndirty:
+The second parameter (ndirty) gives the maximum number of
+dirty buffers that bdflush can write to the disk in one time.
+A high value will mean delayed, bursty I/O, while a small
+value can lead to memory shortage when bdflush isn't woken
+up often enough.
+
 int interval:
 The fifth parameter, interval, is the minimum rate at
 which kupdate will wake and flush.  The value is expressed in
@@ -88,7 +96,11 @@
 synchronously.  This can be viewed as the hard limit before
 bdflush forces buffers to disk.  The default is 60%, the
 minimum is 0%, and the maximum is 100%.
- 
+
+int nfract_stop_bdflush:
+The eighth parameter, nfract_stop_bdflush, governs the percentage
+of buffer cache that is dirty which will stop bdflush.
+The default is 20%, the miniumum is 0%, and the maxiumum is 100%.
 ==============================================================
 buffermem:
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/usb/auerswald.txt linux-2.4.20/Documentation/usb/auerswald.txt
--- linux-2.4.19/Documentation/usb/auerswald.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/usb/auerswald.txt	2002-10-29 11:18:40.000000000 +0000
@@ -27,4 +27,4 @@
 ============
 - Connection to ISDN4LINUX (the hisax interface)
 
-The maintainer of this driver is wmues@nexgo.de
+The maintainer of this driver is wolfgang@iksw-muees.de
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/usb/ov511.txt linux-2.4.20/Documentation/usb/ov511.txt
--- linux-2.4.19/Documentation/usb/ov511.txt	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.20/Documentation/usb/ov511.txt	2002-10-29 11:18:32.000000000 +0000
@@ -128,16 +128,6 @@
         programs that expect RGB data (e.g. gqcam) to work with this driver. If
         your colors look VERY wrong, you may want to change this.
 
-  NAME: buf_timeout
-  TYPE: integer
-  DEFAULT: 5 (seconds)
-  DESC: Number of seconds before unused frame buffers are deallocated.
-        Previously, memory was allocated upon open() and deallocated upon
-        close(). Deallocation now occurs only if the driver is closed and this
-        timeout is reached. If you are capturing frames less frequently than
-        the default timeout, increase this. This will not make any difference
-        with programs that capture multiple frames during an open/close cycle.
-
   NAME: cams
   TYPE: integer (1-4 for OV511, 1-31 for OV511+)
   DEFAULT: 1
@@ -161,13 +151,6 @@
   DESC: This configures the camera's sensor to transmit a colored test-pattern
         instead of an image. This does not work correctly yet.
 
-  NAME: sensor_gbr (*** TEMPORARILY DISABLED ***)
-  TYPE: integer (Boolean)
-  DEFAULT: 0
-  DESC: This makes the sensor output GBR422 instead of YUV420. This saves the
-        driver the trouble of converting YUV to RGB, but it currently does not
-        work very well (the colors are not quite right)
-
   NAME: dumppix
   TYPE: integer (0-2)
   DEFAULT: 0
@@ -182,9 +165,9 @@
   DEFAULT: 1 (Always on)
   DESC: Controls whether the LED (the little light) on the front of the camera
 	is always off (0), always on (1), or only on when driver is open (2).
-	This is only supported with the OV511+ chipset, and even then only on
-	some cameras (ones that actually have the LED wired to the control pin,
-	and not just hardwired to be on all the time).
+	This is not supported with the OV511, and might only work with certain
+	cameras (ones that actually have the LED wired to the control pin, and
+	not just hard-wired to be on all the time).
 
   NAME: dump_bridge
   TYPE: integer (Boolean)
@@ -259,14 +242,6 @@
 		13  VIDEO_PALETTE_YUV422P   (YUV 4:2:2 Planar)
 		15  VIDEO_PALETTE_YUV420P   (YUV 4:2:0 Planar, same as 10)
 
-  NAME: tuner
-  TYPE: integer
-  DEFAULT: -1 (autodetect)
-  DESC: This sets the exact type of the tuner module in a device. This is set
-	automatically based on the custom ID of the OV511 device. In cases
-	where this fails, you can override this auto-detection. Please see
-	linux/drivers/media/video/tuner.h for a complete list.
-
   NAME: backlight
   TYPE: integer (Boolean)
   DEFAULT: 0 (off)
@@ -293,7 +268,14 @@
 	will compensate for the blocks of corruption that can appear when the
 	camera cannot keep up with the speed of the USB bus (eg. at low frame
 	resolutions). This feature is always enabled when compression is on.
- 
+
+  NAME: mirror
+  TYPE: integer (Boolean)
+  DEFAULT: 0 (off)
+  DESC: Setting this to 1 will reverse ("mirror") the image horizontally. This
+	might be necessary if your camera has a custom lens assembly. This has
+	no effect with video capture devices.
+
 WORKING FEATURES:
  o Color streaming/capture at most widths and heights that are multiples of 8.
  o RGB24, RGB565, YUV420/YUV420P, YUV422/YUYV, and YUV422P color
@@ -304,22 +286,9 @@
  o SAA7111A video capture support at 320x240 and 640x480
  o Compression support
 
-EXPERIMENTAL FEATURES:
- o OV6630 sensor support
- o Banding filter
- o SMP compatibility
-
-TO-DO:
- o V4L2 support (This will be done after the next kernel patch release)
- o Setting of hue not working with OV7620
- o Setting of contrast and hue not working with OV7620AE
- o OV8600 sensor support (Not used in anything yet)
- o OV518/OV518+ support (all that's needed is the decompressor)
- o cams >= 3 not working
-
 HOW TO CONTACT ME:
 
-You can email me at mmcclell@bigfoot.com . Please prefix the subject line
+You can email me at mark@alpha.dyndns.org . Please prefix the subject line
 with "OV511: " so that I am certain to notice your message.
 
 CREDITS:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/usb/silverlink.txt linux-2.4.20/Documentation/usb/silverlink.txt
--- linux-2.4.19/Documentation/usb/silverlink.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/usb/silverlink.txt	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,76 @@
+-------------------------------------------------------------------------
+Readme for Linux device driver for the Texas Instruments SilverLink cable
+-------------------------------------------------------------------------
+
+Author: Romain Livin & Julien Blache
+Homepage: http://lpg.ticalc.org/prj_usb
+
+INTRODUCTION:
+
+This is a driver for the TI-GRAPH LINK USB (aka SilverLink) cable, a cable 
+designed by TI for connecting their TI8x/9x calculators to a computer 
+(PC or Mac usually).
+
+If you need more information, please visit the 'SilverLink drivers' homepage 
+at the above URL.
+
+WHAT YOU NEED:
+
+A TI calculator of course and a program capable to communicate with your 
+calculator.
+TiLP will work for sure (since I am his developer !). yal92 may be able to use
+it by changing tidev for tiglusb (may require some hacking...).
+
+HOW TO USE IT:
+
+You must have first compiled USB support, support for your specific USB host
+controller (UHCI or OHCI).
+
+Next, (as root) from your appropriate modules directory (lib/modules/2.5.XX):
+
+       insmod usb/usbcore.o
+       insmod usb/usb-uhci.o  <OR>  insmod usb/ohci-hcd.o
+       insmod tiglusb.o
+
+If it is not already there (it usually is), create the device:
+
+       mknod /dev/tiglusb0 c 115 16
+
+You will have to set permissions on this device to allow you to read/write
+from it:
+
+       chmod 666 /dev/tiglusb0
+       
+Now you are ready to run a linking program such as TiLP. Be sure to configure 
+it properly (RTFM).
+       
+MODULE PARAMETERS:
+
+  You can set these with:  insmod tiglusb NAME=VALUE
+  There is currently no way to set these on a per-cable basis.
+
+  NAME: timeout
+  TYPE: integer
+  DEFAULT: 15
+  DESC: Timeout value in tenth of seconds. If no data is available once this 
+       time has expired then the driver will return with a timeout error.
+
+QUIRKS:
+
+The following problem seems to be specific to the link cable since it appears 
+on all platforms (Linux, Windows, Mac OS-X). 
+
+In some very particular cases, the driver returns with success but
+without any data. The application should retry a read operation at least once.
+
+HOW TO CONTACT US:
+
+You can email me at roms@lpg.ticalc.org. Please prefix the subject line
+with "TIGLUSB: " so that I am certain to notice your message.
+You can also mail JB at jb@jblache.org: he has written the first release of 
+this driver but he better knows the Mac OS-X driver.
+
+CREDITS:
+
+The code is based on dabusb.c, printer.c and scanner.c !
+The driver has been developed independantly of Texas Instruments.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/video4linux/bttv/CARDLIST linux-2.4.20/Documentation/video4linux/bttv/CARDLIST
--- linux-2.4.19/Documentation/video4linux/bttv/CARDLIST	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/video4linux/bttv/CARDLIST	2002-10-29 11:18:33.000000000 +0000
@@ -3,41 +3,41 @@
   card=1 - MIRO PCTV
   card=2 - Hauppauge (bt848)
   card=3 - STB
-  card=4 - Intel
+  card=4 - Intel Create and Share PCI/ Smart Video Recorder III
   card=5 - Diamond DTV2000
   card=6 - AVerMedia TVPhone
   card=7 - MATRIX-Vision MV-Delta
-  card=8 - FlyVideo II (Bt848) LR26
-  card=9 - IXMicro TurboTV
+  card=8 - Lifeview FlyVideo II (Bt848) LR26
+  card=9 - IMS/IXmicro TurboTV
   card=10 - Hauppauge (bt878)
   card=11 - MIRO PCTV pro
-  card=12 - ADS Technologies Channel Surfer TV
+  card=12 - ADS Technologies Channel Surfer TV (bt848)
   card=13 - AVerMedia TVCapture 98
   card=14 - Aimslab Video Highway Xtreme (VHX)
   card=15 - Zoltrix TV-Max
-  card=16 - Pixelview PlayTV (bt878)
+  card=16 - Prolink Pixelview PlayTV (bt878)
   card=17 - Leadtek WinView 601
   card=18 - AVEC Intercapture
-  card=19 - LifeView FlyKit w/o Tuner
+  card=19 - Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)
   card=20 - CEI Raffles Card
-  card=21 - Lucky Star Image World ConferenceTV
-  card=22 - Phoebe Tv Master + FM (CPH050)
+  card=21 - Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50
+  card=22 - Askey CPH050/ Phoebe Tv Master + FM
   card=23 - Modular Technology MM205 PCTV, bt878
-  card=24 - [many vendors] CPH05X/06X (bt878)
-  card=25 - Terratec/Vobis TV-Boostar
-  card=26 - Newer Hauppauge WinCam (bt878)
-  card=27 - MAXI TV Video PCI2
+  card=24 - Askey CPH05X/06X (bt878) [many vendors]
+  card=25 - Terratec Terra TV+ Version 1.0 (Bt848)/Vobis TV-Boostar
+  card=26 - Hauppauge WinCam newer (bt878)
+  card=27 - Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50
   card=28 - Terratec TerraTV+
   card=29 - Imagenation PXC200
-  card=30 - FlyVideo 98
-  card=31 - iProTV
-  card=32 - Intel Create and Share PCI
+  card=30 - Lifeview FlyVideo 98 LR50
+  card=31 - Formac iProTV
+  card=32 - Intel Create and Share PCI/ Smart Video Recorder III
   card=33 - Terratec TerraTValue
   card=34 - Leadtek WinFast 2000
-  card=35 - Flyvideo 98 (LR50Q) / Chronos Video Shuttle II
-  card=36 - Flyvideo 98FM (LR50Q) / Typhoon TView TV/FM Tuner
-  card=37 - PixelView PlayTV pro
-  card=38 - TView99 CPH06X
+  card=35 - Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II
+  card=36 - Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner
+  card=37 - Prolink PixelView PlayTV pro
+  card=38 - Askey CPH06X TView99
   card=39 - Pinnacle PCTV Studio/Rave
   card=40 - STB2
   card=41 - AVerMedia TVPhone 98
@@ -47,45 +47,47 @@
   card=45 - MATRIX-Vision MV-Delta 2
   card=46 - Zoltrix Genie TV/FM
   card=47 - Terratec TV/Radio+
-  card=48 - Dynalink Magic TView 
-  card=49 - GV-BCTV3
+  card=48 - Askey CPH03x/ Dynalink Magic TView
+  card=49 - IODATA GV-BCTV3/PCI
   card=50 - Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP
   card=51 - Eagle Wireless Capricorn2 (bt878A)
   card=52 - Pinnacle PCTV Studio Pro
   card=53 - Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS
-  card=54 - Lifetec LT 9415 TV (LR90 Rev.F)
-  card=55 - BESTBUY Easy TV (CPH031)
-  card=56 - FlyVideo '98/FM
+  card=54 - Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]
+  card=55 - Askey CPH031/ BESTBUY Easy TV
+  card=56 - Lifeview FlyVideo 98FM LR50
   card=57 - GrandTec 'Grand Video Capture' (Bt848)
-  card=58 - Phoebe TV Master Only (No FM) CPH060
-  card=59 - TV Capturer (CPH03X)
+  card=58 - Askey CPH060/ Phoebe TV Master Only (No FM)
+  card=59 - Askey CPH03x TV Capturer
   card=60 - Modular Technology MM100PCTV
   card=61 - AG Electronics GMV1
-  card=62 - BESTBUY Easy TV (bt878)
+  card=62 - Askey CPH061/ BESTBUY Easy TV (bt878)
   card=63 - ATI TV-Wonder
   card=64 - ATI TV-Wonder VE
-  card=65 - FlyVideo 2000S
+  card=65 - Lifeview FlyVideo 2000S LR90
   card=66 - Terratec TValueRadio
-  card=67 - GV-BCTV4/PCI
+  card=67 - IODATA GV-BCTV4/PCI
   card=68 - 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)
   card=69 - Active Imaging AIMMS
-  card=70 - PV-BT878P+
-  card=71 - Flyvideo 98EZ (capture only)
-  card=72 - Prolink PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)
+  card=70 - Prolink Pixelview PV-BT878P+ (Rev.4C)
+  card=71 - Lifeview FlyVideo 98EZ (capture only) LR51
+  card=72 - Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)
   card=73 - Sensoray 311
   card=74 - RemoteVision MX (RV605)
   card=75 - Powercolor MTV878/ MTV878R/ MTV878F
   card=76 - Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)
   card=77 - GrandTec Multi Capture Card (Bt878)
-  card=78 - AOPEN VA1000
+  card=78 - Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF
+  card=79 - DSP Design TCVIDEO
+  card=80 - Hauppauge WinTV PVR
 
 tuner.o
   type=0 - Temic PAL (4002 FH5)
-  type=1 - Philips PAL_I
-  type=2 - Philips NTSC
-  type=3 - Philips SECAM
+  type=1 - Philips PAL_I (FI1246 and compatibles)
+  type=2 - Philips NTSC (FI1236 and compatibles)
+  type=3 - Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)
   type=4 - NoTuner
-  type=5 - Philips PAL
+  type=5 - Philips PAL_BG (FI1216 and compatibles)
   type=6 - Temic NTSC (4032 FY5)
   type=7 - Temic PAL_I (4062 FY5)
   type=8 - Temic NTSC (4036 FY5)
@@ -103,7 +105,7 @@
   type=20 - Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)
   type=21 - Temic NTSC (4039 FR5)
   type=22 - Temic PAL/SECAM multi (4046 FM5)
-  type=23 - Philips PAL_DK
+  type=23 - Philips PAL_DK (FI1256 and compatibles)
   type=24 - Philips PAL/SECAM multi (FQ1216ME)
   type=25 - LG PAL_I+FM (TAPC-I001D)
   type=26 - LG PAL_I (TAPC-I701D)
@@ -118,3 +120,5 @@
   type=35 - Temic PAL_DK/SECAM_L (4012 FY5)
   type=36 - Temic NTSC (4136 FY5)
   type=37 - LG PAL (newer TAPC series)
+  type=38 - Philips PAL/SECAM multi (FM1216ME MK3)
+  type=39 - LG NTSC (newer TAPC series)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/video4linux/bttv/Cards linux-2.4.20/Documentation/video4linux/bttv/Cards
--- linux-2.4.19/Documentation/video4linux/bttv/Cards	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/video4linux/bttv/Cards	2002-10-29 11:18:34.000000000 +0000
@@ -1,3 +1,8 @@
+
+Gunther Mayer's bttv card gallery (graphical version of this text file :-)
+is available at: http://mayerg.gmxhome.de/bttv/bttv-gallery.html
+
+
 Suppported cards:
 
 
@@ -91,10 +96,9 @@
 - sound decoder: TDA9800, MSP34xx (stereo cards) 
 
 
-CPH-Series (CPH050, ...)
-------------------------
-Developed by TelSignal(?), OEMed by many vendors (Askey, Typhoon, 
-  Anubis, Dynalink)
+Askey CPH-Series
+----------------
+Developed by TelSignal(?), OEMed by many vendors (Typhoon, Anubis, Dynalink)
 
   Card series:
     CPH01x: BT848 capture only
@@ -149,9 +153,13 @@
       LR50 Rev.Q = Flyvideo 98 (w/eeprom and PCI subsystem ID)
            Rev.W = Flyvideo 98 (no eeprom)
       LR51 Rev.E = Flyvideo 98 EZ (capture only)
-      LR90       = Flyvideo 2000 series
+      LR90       = Flyvideo 2000 (Bt878)
+		   Flyvideo 2000S (Bt878) w/Stereo TV (Package incl. LR91 daughterboard)
       LR91       = Stereo daughter card for LR90
       LR97       = Flyvideo DVBS
+      LR99 Rev.E = Low profile card for OEM integration (only internal audio!) bt878
+      LR136	 = Flyvideo 2100/3100 (Low profile, SAA7130/SAA7134)
+      LR137      = Flyvideo DV2000/DV3000 (SAA7130/SAA7134 + IEEE1394)
       LR138 Rev.C= Flyvideo 2000 (SAA7130)
 	        or Flyvideo 3000 (SAA7134) w/Stereo TV
 		   These exist in variations w/FM and w/Remote sometimes denoted
@@ -162,15 +170,14 @@
       Their Bt8x8 cards are listed as discontinued.
       Flyvideo 2000S was probably sold as Flyvideo 3000 in some contries(Europe?).
       The new Flyvideo 2000/3000 are SAA7130/SAA7134 based. 
-      Flyvideo 2100/3100 are half-sized cards (for system integrators etc.)
 
   "Flyvideo II" had been the name for the 848 cards, nowadays (in Germany)
   this name is re-used for LR50 Rev.W.
   The Lifeview website mentioned Flyvideo III at some time, but such a card
-  has never been seen. 
+  has not yet been seen (perhaps it was the german name for LR90 [stereo]).
   These cards are sold by many OEMs too.
 
-  FlyVideo A2 = LR90 Rev.F (w/Remote, w/o FM, stereo TV by tda9821)
+  FlyVideo A2 = LR90 Rev.F (w/Remote, w/o FM, stereo TV by tda9821) {Germany}
 
 
 Typhoon TV card series:
@@ -190,7 +197,12 @@
   50686 "TV Tuner"                       = KNC1 TV Station
   50687 "TV Tuner stereo"                = KNC1 TV Station pro
   50688 "TV Tuner RDS" (black package)   = KNC1 TV Station RDS
+  50689  TV SAT DVB-S CARD CI PCI (SAA7146AH)
   50692 "TV/FM Tuner" (small PCB)
+  50694  TV TUNER CARD RDS (PHILIPS CHIPSET SAA7134HL)
+  50696  TV TUNER STEREO (PHILIPS CHIPSET SAA7134HL, MK3ME Tuner)
+  50804  PC-SAT TV/Audio Karte = Techni-PC-Sat (ZORAN 36120PQC, Tuner:Alps)
+  50866  TVIEW SAT RECEIVER+ADR
   50868 "TV/FM Tuner Pal I" (variant of 50682)
   50999 "TV/FM Tuner Secam" (variant of 50682)
 
@@ -207,16 +219,31 @@
 
 Prolink
 -------
-   Pixelview Play TV Pro:
-     PV-BT878P+rev.9B (Play TV Pro w/FM w/NICAM)
-     PV-BT878P+rev.8X 
-     PV-BT878P+rev.4C (Play TV Pro) 
-     PV-BT878P+rev.4E (Play TV Pak) 
-     PV-BT878P+rev.2F 
-     PV-BT878TV 
-
-   PixelView Play TV 
-     PV-BT848P+
+   TV cards:
+   PixelView Play TV pro - (Model: PV-BT878P+ REV 8E)
+   PixelView Play TV pro - (Model: PV-BT878P+ REV 9D)
+   PixelView Play TV pro - (Model: PV-BT878P+ REV 4C / 8D / 10A )
+   PixelView Play TV - (Model: PV-BT848P+)
+   878TV - (Model: PV-BT878TV)
+
+   Multimedia TV packages (card + software pack):
+   PixelView Play TV Theater - (Model: PV-M4200) =  PixelView Play TV pro + Software
+   PixelView Play TV PAK -     (Model: PV-BT878P+ REV 4E)
+   PixelView Play TV/VCR -     (Model: PV-M3200 REV 4C / 8D / 10A ) 
+   PixelView Studio PAK -      (Model:    M2200 REV 4C / 8D / 10A )
+   PixelView PowerStudio PAK - (Model: PV-M3600 REV 4E)
+   PixelView DigitalVCR PAK -  (Model: PV-M2400 REV 4C / 8D / 10A )
+
+   Further Cards:
+   PV-BT878P+rev.9B (Play TV Pro, opt. w/FM w/NICAM)
+   PV-BT878P+rev.2F
+   PV-BT878P Rev.1D (bt878, capture only)
+   
+   Video Conferencing:
+   PixelView Meeting PAK - (Model: PV-BT878P)
+   PixelView Meeting PAK Lite - (Model: PV-BT878P)
+   PixelView Meeting PAK plus - (Model: PV-BT878P+rev 4C/8D/10A)
+   PixelView Capture - (Model: PV-BT848P)
 
 Dynalink
 --------
@@ -235,7 +262,7 @@
 Tekram
 ------
    VideoCap C205 (Bt848)
-   VideoCap C210 (Zoran ZR36120 +Philips)
+   VideoCap C210 (zr36120 +Philips)
    CaptureTV M200 (ISA)
    CaptureTV M205 (Bt848)
 
@@ -257,8 +284,10 @@
    TV-Station FM (+Radio)
    TV-Station RDS (+RDS)
 
-PV951 cards:
-------------
+   newer Cards have saa7134, but model name stayed the same?
+
+Provideo PV951 
+--------------
   These are sold as:
    Boeder TV-FM Video Capture Card
    Titanmedia Supervision TV-2400
@@ -270,12 +299,14 @@
 Highscreen
 ----------
    TV Karte = LR50 Rev.S
-   TV-Boostar = Terratec Terra TV+ Version 1.0 (Bt848, TDA9821) "ceb105.pcb"
+   TV-Boostar = Terratec Terra TV+ Version 1.0 (Bt848, tda9821) "ceb105.pcb"
 
 Zoltrix
 -------
+   Face to Face Capture (Bt848 capture only) (PCB "VP-2848")
    Face To Face TV MAX (Bt848) (PCB "VP-8482 Rev1.3")
    Genie TV (Bt878) (PCB "VP-8790 Rev 2.1")
+   Genie Wonder Pro
 
 AVerMedia
 ---------
@@ -302,21 +333,24 @@
 
 Aimslab
 -------
+   Video Highway or "Video Highway TR200" (ISA)
    Video Highway Xtreme (aka "VHX") (Bt848, FM w/ TEA5757)
 
-IXMicro
+IXMicro (former: IMS=Integrated Micro Solutions)
 -------
    IXTV BT848
    IXTV BT878
    TurboTV (Bt848)
 
 Lifetec/Medion/Tevion/Aldi
--------
-   LT9415/MD9415 = LR90 Rev. F
+--------------------------
+   LT9306/MD9306 = CPH061
+   LT9415/MD9415 = LR90 Rev.F or Rev.G
           MD9592 = Avermedia TVphone98 (PCI_ID=1461:0003), PCB-Rev=M168II-B (w/TDA9873H)
+          MD9717 = KNC One (Rev D4, saa7134)
 
 Modular Technologies (www.modulartech.com) UK
---------------------
+---------------------------------------------
    MM100 PCTV (Bt848)
    MM205 PCTV (Bt878)
    MM210 PCTV (Bt878) (Galaxy TV)
@@ -326,19 +360,28 @@
    Terra TV+ Version 1.0 (Bt848), "ceb105.PCB" printed on the PCB, TDA9821
    Terra TV+ Version 1.1 (Bt878), "LR74 Rev.E" printed on the PCB, TDA9821
    Terra TValueRadio,             "LR102 Rev.C" printed on the PCB
-   Terra TV/Radio+ Version 1.0,   "80-CP2830100-0" TTTV3 printed on the PCB, i
+   Terra TV/Radio+ Version 1.0,   "80-CP2830100-0" TTTV3 printed on the PCB,
 				     "CPH010-E83" on the back, SAA6588T, TDA9873H
    Terra TValue Version BT878,    "80-CP2830110-0 TTTV4" printed on the PCB, 
 				     "CPH011-D83" on back
    Terra TValue Version 1.0       "ceb105.PCB" (really identical to Terra TV+ Version 1.0)
+   Terra Active Radio Upgrade (tea5757h, saa6588t)
 
    LR74 is a newer PCB revision of ceb105 (both incl. connector for Active Radio Upgrade)
 
+   Cinergy 400 (saa7134), "E877 11(S)", "PM820092D" printed on PCB
 
 Technisat
 ---------
-   Mediafocus I (ZR36120/ZR36125)
-   Mediafocus II (SAA7146)
+   Discos ADR PC-Karte ISA (no TV!)
+   Discos ADR PC-Karte PCI (probably no TV?)
+   Techni-PC-Sat (Sat. analog)
+         Rev 1.2 (zr36120, vpx3220, stv0030, saa5246, BSJE3-494A)
+   Mediafocus I (zr36120/zr36125, drp3510, Sat. analog + ADR Radio)
+   Mediafocus II (saa7146, Sat. analog)
+         SatADR Rev 2.1 (saa7146a, saa7113h, stv0056a, msp3400c, drp3510a, BSKE3-307A)
+   SkyStar 1 DVB  (AV7110)
+   SkyStar 2 DVB  (B2C2) (=Sky2PC)
 
 Siemens
 -------
@@ -359,34 +402,262 @@
    Mirovideo PCTV (Bt848)
    Mirovideo PCTV SE (Bt848)
    Mirovideo PCTV Pro (Bt848 + Daughterboard)
-   Studio PCTV Rave (Bt878 w/o infrared)
-   Studio PCTV
-   Studio PCTV Pro (Bt878 stereo w/ FM)
+   Studio PCTV Rave (Bt878 package w/o infrared)
+   Studio PCTV      (Bt878)
+   Studio PCTV Pro  (Bt878 stereo w/ FM)
 
+   M(J)PEG capture and playback:
    DC1+ (ISA)
-   DC10  (zr36057 + zr36060 + saa7110 + adv7176)
-   DC10+ (zr36067 + zr36060 + saa7110 + adv7176)
-   DC20
-   DC30
-   DC30+ (zr36067 + zr36050 + zr36016 + vpx3220 + adv7176)
+   DC10  (zr36057,     zr36060,      saa7110, adv7176)
+   DC10+ (zr36067,     zr36060,      saa7110, adv7176)
+   DC20  (ql16x24b,zr36050, zr36016, saa7110, saa7187 ...)
+   DC30  (zr36057, zr36050, zr36016, vpx3220, adv7176, ad1843, tea6415, miro FST97A1)
+   DC30+ (zr36067, zr36050, zr36016, vpx3220, adv7176)
+   DC50  (zr36067, zr36050, zr36016, saa7112, adv7176 (2 pcs.?), ad1843, miro FST97A1, Lattice ???)
 
 Lenco
 -----
    MXR-9565 (=Technisat Mediafocus?)
-   MXR-9571 (Bt848)
+   MXR-9571 (Bt848) (=CPH031?)
    MXR-9575
-   MXR-9477 (Bt878)
-   MXTV-9578CP (= Prolink PV-BT878P+4E)
+   MXR-9577 (Bt878) (=Prolink 878TV Rev.3x)
+   MXTV-9578CP (Bt878) (= Prolink PV-BT878P+4E)
 
 Iomega
 ------
-   Buz (Zoran zr36067 + zr36060 + SAA7111 + SAA7185)
+   Buz (zr36067, zr36060, saa7111, saa7185)
 
 LML
 ---
-   LML33 (zr36067 + zr36060 + bt819+ bt856)
+   LML33 (zr36067, zr36060, bt819, bt856)
 
 Grandtec
 --------
    Grand Video Capture (Bt848)
    Multi Capture Card  (Bt878)
+
+Koutech
+-------
+   KW-606 (Bt848)
+   KW-607 (Bt848 capture only)
+   KW-606RSF
+   KW-607A (capture only)
+   KW-608 (Zoran capture only)
+ 
+IODATA (jp)
+------
+   GV-BCTV/PCI
+   GV-BCTV2/PCI
+   GV-BCTV3/PCI
+   GV-BCTV4/PCI
+   GV-VCP/PCI (capture only)
+   GV-VCP2/PCI (capture only)
+
+Canopus (jp)
+-------
+   WinDVR	= Kworld "KW-TVL878RF"
+
+www.sigmacom.co.kr 
+------------------
+   Sigma Cyber TV II 
+
+www.sasem.co.kr
+---------------
+   Litte OnAir TV
+
+hama 
+----
+   TV/Radio-Tuner Card, PCI (Model 44677) = CPH051
+
+Sigma Designs
+-------------
+   Hollywood plus (em8300, em9010, adv7175), (PCB "M340-10") MPEG DVD decoder
+
+Formac
+------
+   iProTV (Card for iMac Mezzanine slot, Bt848+SCSI)
+   ProTV (Bt848)
+   ProTV II = ProTV Stereo (Bt878)
+
+ATI
+---
+   TV-Wonder
+   TV-Wonder VE
+
+Diamond Multimedia
+------------------
+   DTV2000 (Bt848, tda9875)
+
+Aopen
+-----
+   VA1000 Plus (w/ Stereo)
+   VA1000 Lite
+   VA1000 (=LR90)
+
+Intel
+-----
+   Smart Video Recorder (ISA full-length)
+   Smart Video Recorder pro (ISA half-length)
+   Smart Video Recorder III (Bt848)
+
+STB
+---
+   TV PCI (Temic4032FY5, tda9850??)
+   other variants?
+
+Videologic
+----------
+   Captivator Pro/TV (ISA?)
+   Captivator PCI/VC (Bt848 bundled with camera) (capture only)
+
+Technotrend
+------------
+   TT-SAT PCI (PCB "Sat-PCI Rev.:1.3.1"; zr36125, vpx3225d, stc0056a, Tuner:BSKE6-155A
+   TT-DVB-Sat
+   TT-DVB-C PCI
+
+Teles
+-----
+   DVB-s (Rev. 2.2, BSRV2-301A, data only?)
+
+Remote Vision
+-------------
+   MX RV605 (Bt848 capture only)
+
+Boeder
+------
+   PC ChatCam (Model 68252) (Bt848 capture only)
+   Tv/Fm Capture Card  (Model 68404) = PV951
+
+Media-Surfer  (esc-kathrein.de)
+-------------------------------
+   Sat-Surfer (ISA)
+   Sat-Surfer PCI = Techni-PC-Sat
+   Cable-Surfer 1
+   Cable-Surfer 2
+   Cable-Surfer PCI (zr36120)
+   Audio-Surfer (ISA Radio card)
+
+Jetway (www.jetway.com.tw)
+--------------------------
+   JW-TV 878M 
+   JW-TV 878  = KWorld KW-TV878RF
+
+Galaxis
+-------
+   Galaxis DVB Card S CI
+   Galaxis DVB Card C CI
+   Galaxis DVB Card S
+   Galaxis DVB Card C
+
+Hauppauge
+---------
+   many many WinTV models ...
+   WinTV DVBs
+   WinTV NOVA
+   WinTV NOVA-CI
+   WinTV-Nexus-s
+
+Matrix-Vision
+-------------
+   MATRIX-Vision MV-Delta
+   MATRIX-Vision MV-Delta 2
+   MVsigma-SLC (Bt848)
+
+Conceptronic (.net)
+------------
+   TVCON FM,  TV card w/ FM = CPH05x
+
+BestData
+--------
+   HCC100 = VCC100rev1 + camera
+   VCC100 rev1 (bt848)
+   VCC100 rev2 (bt878)
+
+Gallant  (www.gallantcom.com) www.minton.com.tw
+-----------------------------------------------
+   Intervision IV-510 (capture only bt8x8)
+   Intervision IV-550 (bt8x8)
+   Intervision IV-100 (zoran)
+   Intervision IV-1000 (bt8x8)
+   
+Asonic (www.asonic.com.cn) (website down)
+-----------------------------------------
+   SkyEye tv 878
+
+Hoontech
+--------
+   878TV/FM
+
+Teppro (www.itcteppro.com.tw)
+-----------------------------
+   ITC PCITV (Card Ver 1.0) "Teppro TV1/TVFM1 Card"
+   ITC PCITV (Card Ver 2.0)
+   ITC PCITV (Card Ver 3.0) = "PV-BT878P+ (REV.9D)"
+   ITC PCITV (Card Ver 4.0)
+   TEPPRO IV-550 (For BT848 Main Chip)
+   ITC DSTTV (bt878, satellite)
+   ITC VideoMaker (saa7146, StreamMachine sm2110, tvtuner) "PV-SM2210P+ (REV:1C)"
+
+Kworld (www.kworld.com.tw)
+--------------------------
+   KWORLD KW-TV878RF-Pro TV Capture with FM Radio
+   KWORLD KW-TV878R-Pro TV
+   KWORLD KW-TVL878RF  (low profile)
+   KWORLD KW-TV878R TV Capture (No FM Radio)
+   KWORLD KW-TV878RF TV
+
+JTT/ Justy Corp.http://www.justy.co.jp/ (www.jtt.com.jp website down)
+---------------------------------------------------------------------
+   JTT-02 (JTT TV) "TV watchmate pro" (bt848) 
+
+ADS www.adstech.com
+-------------------
+   Channel Surfer TV ( CHX-950 ) 
+   Channel Surfer TV+FM ( CHX-960FM )
+
+AVEC www.prochips.com
+---------------------
+   AVEC Intercapture (bt848, tea6320)
+
+NoBrand
+-------
+   TV Excel = Australian Name for "PV-BT878P+ 8E" or so
+
+Mach www.machspeed.com
+----
+   Mach TV 878
+
+Eline www.eline-net.com/
+-----
+   Eline Vision TVMaster / TVMaster FM (ELV-TVM/ ELV-TVM-FM) = LR26  (bt878)
+   Eline Vision TVMaster-2000 (ELV-TVM-2000, ELV-TVM-2000-FM)= LR138 (saa713x)
+
+Spirit http://www.spiritmodems.com.au/
+------
+   Spirit TV Tuner/Video Capture Card (bt848)
+
+Boser www.boser.com.tw
+-----
+   HS-878 Mini PCI Capture Add-on Card
+   HS-879 Mini PCI 3D Audio and Capture Add-on Card (w/ ES1938 Solo-1)
+
+Satelco
+-------
+   TV-FM =KNC1 saa7134
+
+Sensoray www.sensoray.com
+--------
+   Sensoray 311 (PC/104 bus)
+   Sensoray 611 (PCI)
+
+CEI (Chartered Electronics Industries Pte Ltd [CEI] [FCC ID HBY])
+---
+  TV Tuner  -  HBY-33A-RAFFLES  Brooktree Bt848KPF + Philips
+  TV Tuner MG9910  -  HBY33A-TVO  CEI + Philips SAA7110 + OKI M548262 + ST STV8438CV
+  Primetime TV (ISA)
+   acquired by Singapore Technologies
+   now operating as Chartered Semiconductor Manufacturing
+   Manufacturer of video cards is listed as:
+   Cogent Electronics Industries [CEI]
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/video4linux/bttv/Insmod-options linux-2.4.20/Documentation/video4linux/bttv/Insmod-options
--- linux-2.4.19/Documentation/video4linux/bttv/Insmod-options	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/video4linux/bttv/Insmod-options	2002-10-29 11:18:33.000000000 +0000
@@ -29,7 +29,7 @@
 		irq_debug=0/1	irq handler debug messages.
 				default is 0 (off).
 		gbuffers=2-32	number of capture buffers for mmap'ed capture.
-				default is 2.
+				default is 4.
 		gbufsize=	size of capture buffers. default and
 				maximum value is 0x208000 (~2MB)
 		no_overlay=0	Enable overlay on broken hardware.  There
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/video4linux/bttv/README linux-2.4.20/Documentation/video4linux/bttv/README
--- linux-2.4.19/Documentation/video4linux/bttv/README	2001-08-05 20:15:05.000000000 +0000
+++ linux-2.4.20/Documentation/video4linux/bttv/README	2002-10-29 11:18:32.000000000 +0000
@@ -58,6 +58,9 @@
 		the helper modules.
 MAKEDEV:	a script to create the special files for v4l
 CARDLIST:	List of all supported cards
+Cards:		more detailed descriptions of known TV cards:
+		OEM name variants, used i2c chips, ...
+		also includes non-bttv cards.
 
 Loading just the bttv modules isn't enouth for most cards.  The
 drivers for the i2c tuner/sound chips must also be loaded.  bttv tries
@@ -73,6 +76,12 @@
 video but no sound you've very likely specified the wrong (or no)
 card type.  A list of supported cards is in CARDLIST.
 
+For the WinTV/PVR you need one firmware file from the driver CD:
+hcwamc.rbf.  The file is in the pvr45xxx.exe archive (self-extracting
+zip file, unzip can unpack it).  Put it into the /etc/pvr directory or
+use the firm_altera=<path> insmod option to point the driver to the
+location of the file.
+
 If your card isn't listed in CARDLIST or if you have trouble making
 audio work, you should read the Sound-FAQ.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/video4linux/bttv/README.freeze linux-2.4.20/Documentation/video4linux/bttv/README.freeze
--- linux-2.4.19/Documentation/video4linux/bttv/README.freeze	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/video4linux/bttv/README.freeze	2002-10-29 11:18:35.000000000 +0000
@@ -46,6 +46,11 @@
 the PCI bus. The bt848/878 chips have a few workarounds for known
 incompatibilities, see README.quirks.
 
+Some folks report that increasing the pci latency helps too,
+althrought I'm not sure whenever this really fixes the problems or
+only makes it less likely to happen.  Both bttv and btaudio have a
+insmod option to set the PCI latency of the device.
+
 Some mainboard have problems to deal correctly with multiple devices
 doing DMA at the same time.  bttv + ide seems to cause this sometimes,
 if this is the case you likely see freezes only with video and hard disk
@@ -56,6 +61,9 @@
 other
 -----
 
+If you use some binary-only yunk (like nvidia module) try to reproduce
+the problem without.
+
 IRQ sharing is known to cause problems in some cases.  It works just
 fine in theory and many configurations.  Neverless it might be worth a
 try to shuffle around the PCI cards to give bttv another IRQ or make
@@ -63,3 +71,4 @@
 VGA cards seems to cause trouble sometimes.  I've also seen funny
 effects with bttv sharing the IRQ with the ACPI bridge (and
 apci-enabled kernel).
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/video4linux/bttv/Tuners linux-2.4.20/Documentation/video4linux/bttv/Tuners
--- linux-2.4.19/Documentation/video4linux/bttv/Tuners	2001-10-17 21:19:20.000000000 +0000
+++ linux-2.4.20/Documentation/video4linux/bttv/Tuners	2002-10-29 11:18:30.000000000 +0000
@@ -1,3 +1,16 @@
+1) Tuner Programming
+====================
+There are some flavors of Tuner programming APIs.
+These differ mainly by the bandswitch byte.
+
+    L= LG_API       (VHF_LO=0x01, VHF_HI=0x02, UHF=0x08, radio=0x04)
+    P= PHILIPS_API  (VHF_LO=0xA0, VHF_HI=0x90, UHF=0x30, radio=0x04)
+    T= TEMIC_API    (VHF_LO=0x02, VHF_HI=0x04, UHF=0x01)
+    A= ALPS_API     (VHF_LO=0x14, VHF_HI=0x12, UHF=0x11)
+    M= PHILIPS_MK3  (VHF_LO=0x01, VHF_HI=0x02, UHF=0x04, radio=0x19)
+
+2) Tuner Manufacturers
+======================
 
 SAMSUNG Tuner identification: (e.g. TCPM9091PD27)
   TCP [ABCJLMNQ] 90[89][125] [DP] [ACD] 27 [ABCD]
@@ -10,6 +23,7 @@
    M= BG+I+DK
    N= NTSC 
    Q= BG+I+DK+LL
+ [89]: ?
  [125]:
    2: No FM
    5: With FM
@@ -23,43 +37,49 @@
  [ABCD]:
    3-wire/I2C tuning, 2-band/3-band
 
+ These Tuners are PHILIPS_API compatible.
+
 Philips Tuner identification: (e.g. FM1216MF)
-  F[IRMQ]12[1345]{MF|ME|MP}
-  [IRMQ]:
-   I: Tuner Series
-   R: Tuner + Radio IF
-   M: Tuner + FM
-   Q,MR: specials
+  F[IRMQ]12[1345]6{MF|ME|MP}
+  F[IRMQ]:
+   FI12x6: Tuner Series
+   FR12x6: Tuner + Radio IF
+   FM12x6: Tuner + FM
+   FQ12x6: special
+   FMR12x6: special
    TD15xx: Digital Tuner ATSC
-  [1345]
-   1: PAL BG
-   3: NTSC
-   4: PAL I
-   5: Pal DK
+  12[1345]6:
+   1216: PAL BG
+   1236: NTSC
+   1246: PAL I
+   1256: Pal DK
   {MF|ME|MP}
-   MF: w/ Secam
-   ME: BD DK I LL
-   MP: BG DK I
+   MF: BG LL w/ Secam (Multi France)
+   ME: BG DK I LL   (Multi Europe)
+   MP: BG DK I      (Multi PAL)
    MR: BG DK M (?)
    MG: BG DKI M (?)
+  MK2 series PHILIPS_API, most tuners are compatible to this one !
+  MK3 series introduced in 2002 w/ PHILIPS_MK3_API
 
 Temic Tuner identification: (.e.g 4006FH5)
    4[01][0136][269]F[HYNR]5
-    40x2: Tuner (5V/33V), different I2C programming from Philips !
+    40x2: Tuner (5V/33V), TEMIC_API.
     40x6: Tuner 5V
     41xx: Tuner compact
     40x9: Tuner+FM compact
    [0136]
-    0: PAL BG
-    1: Pal DK, Secam LL
-    3: NTSC
-    6: PAL I
+    xx0x: PAL BG
+    xx1x: Pal DK, Secam LL
+    xx3x: NTSC
+    xx6x: PAL I
    F[HYNR]5
     FH5: Pal BG
     FY5: others
     FN5: multistandard
     FR5: w/ FM radio
    3X xxxx: order number with specific connector
+  Note: Only 40x2 series has TEMIC_API, all newer tuners have PHILIPS_API.
 
 LG Innotek Tuner:
   TPI8NSR11 : NTSC J/M    (TPI8NSR01 w/FM)  (P,210/497)
@@ -76,13 +96,20 @@
   TADC-H002F: NTSC (L,175/410?; 2-B, C-W+11, W+12-69)
   TADC-M201D: PAL D/K+B/G+I (L,143/425)  (sound control at I2C address 0xc8)
   TADC-T003F: NTSC Taiwan  (L,175/410?; 2-B, C-W+11, W+12-69)
-
-  (API,Lo-Hi-takeover/Hi-UHF-takeover)
-   I2C APIs:
-    L= LG programming (VHF_LO=0x01, VHF_HI=0x02, UHF=0x08, radio=0x04)
-    P= Philips progr. (VHF_LO=0xA0, VHF_HI=0x90, UHF=0x30, radio=0x04)
-    T= Temic progr.   (VHF_LO=0x02, VHF_HI=0x04, UHF=0x01)
   Suffix: 
     P= Standard phono female socket
     D= IEC female socket
     F= F-connector
+
+Other Tuners:
+TCL2002MB-1 : PAL BG + DK       =TUNER_LG_PAL_NEW_TAPC
+TCL2002MB-1F: PAL BG + DK w/FM  =PHILIPS_PAL
+TCL2002MI-2 : PAL I		= ??
+
+ALPS Tuners:
+   Most are LG_API compatible
+   TSCH6 has ALPS_API (TSCH5 ?)
+   TSBE1 has extra API 05,02,08 Control_byte=0xCB Source:(1)
+
+Lit.
+(1) conexant100029b-PCI-Decoder-ApplicationNote.pdf
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/video4linux/meye.txt linux-2.4.20/Documentation/video4linux/meye.txt
--- linux-2.4.19/Documentation/video4linux/meye.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/Documentation/video4linux/meye.txt	2002-10-29 11:18:34.000000000 +0000
@@ -86,7 +86,7 @@
 
 	MEYEIOC_SYNC
 		Takes as an argument the buffer number you want to sync.
-		This ioctl blocks untils the buffer is filled and ready
+		This ioctl blocks until the buffer is filled and ready
 		for the application to use. It returns the buffer size.
 
 	MEYEIOC_STILLCAPT
@@ -106,7 +106,7 @@
 		
 	- mjpeg hardware playback doesn't work (depends on overlay...)
 
-	- rewrite the driver to use some commun video4linux API for snapshot
+	- rewrite the driver to use some common video4linux API for snapshot
 	  and mjpeg capture. Unfortunately, video4linux1 does not permit it,
 	  the BUZ API seems to be targeted to TV cards only. The video4linux 2
 	  API may be an option, if it goes into the kernel (maybe 2.5 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/x86_64/BUGS linux-2.4.20/Documentation/x86_64/BUGS
--- linux-2.4.19/Documentation/x86_64/BUGS	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/x86_64/BUGS	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,10 @@
+Some known problems:
+
+-- Compiling the kernel with -j for parallel makes is not completely safe
+due to missing dependencies with offset.h. Usually it is safe when it 
+already exists, but not always.
+
+Current hack is to rerun make depend manually when you change anything
+that would touch offset.h (see arch/x86-64/tools/offset.c on what that is).
+Do not use -j with depend. 
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Documentation/x86_64/mm.txt linux-2.4.20/Documentation/x86_64/mm.txt
--- linux-2.4.19/Documentation/x86_64/mm.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/Documentation/x86_64/mm.txt	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,194 @@
+The paging design used on the x86-64 linux kernel port in 2.4.x provides:
+
+o	per process virtual address space limit of 512 Gigabytes
+o	top of userspace stack located at address 0x0000007fffffffff
+o	PAGE_OFFSET = 0xffff800000000000
+o	start of the kernel mapping =  0x0000010000000000
+o	global RAM per system 508*512GB=254 Terabytes
+o	no need of any common code change
+o       512GB of vmalloc/ioremap space
+
+Description:
+        x86-64 has a 4 level page structure, similar to ia32 PSE but with
+        some extensions. Each level consits of a 4K page with 512 64bit
+        entries. The levels are named in Linux PML4, PGD, PMD, PTE; AMD calls them
+        PML4E, PDPE, PDE, PTE respectively. For direct and kernel mapping
+        only 3 levels are used with the PMD pointing to 2MB pages.
+          
+	Userspace is able to modify and it sees only the 3rd/2nd/1st level
+	pagetables (pgd_offset() implicitly walks the 1st slot of the 4th
+	level pagetable and it returns an entry into the 3rd level pagetable).
+	This is where the per-process 512 Gigabytes limit cames from.
+
+	The common code pgd is the PDPE, the pmd is the PDE, the
+	pte is the PTE. The PML4 remains invisible to the common
+	code.
+
+	Since the per-process limit is 512 Gigabytes (due to kernel common
+	code 3 level pagetable limitation), the higher virtual address mapped
+	into userspace is 0x7fffffffff and it makes sense to use it
+	as the top of the userspace stack to allow the stack to grow as
+	much as possible.
+
+	The kernel mapping and the direct memory mapping are split. Direct memory
+	mapping starts directly after userspace after a 512GB gap, while 
+	kernel mapping is at the end of (negative) virtual address space to exploit 
+	the kernel code model. There is no support for discontig memory, this
+	implies that kernel mapping/vmalloc/ioremap/module mapping are not 
+	represented in their "real" mapping in mem_map, but only with their
+	direct mapped (but normally not used) alias.
+	
+Future:
+
+	During 2.5.x we can break the 512 Gigabytes per-process limit
+	possibly by removing from the common code any knowledge about the
+	architectural dependent physical layout of the virtual to physical
+	mapping.
+
+	Once the 512 Gigabytes limit will be removed the kernel stack will
+	be moved (most probably to virtual address 0x00007fffffffffff).
+	Nothing	will break in userspace due that move, as nothing breaks
+	in IA32 compiling the kernel with CONFIG_2G.
+
+Linus agreed on not breaking common code and to live with the 512 Gigabytes
+per-process limitation for the 2.4.x timeframe and he has given me and Andi
+some very useful hints... (thanks! :)
+
+Thanks also to H. Peter Anvin for his interesting and useful suggestions on
+the x86-64-discuss lists!
+
+Current PML4 Layout:
+	Each CPU has an PML4 page that never changes. 
+	Each slot is 512GB of virtual memory. 
+ 
+        0    user space pgd or 40MB low mapping at bootup.  Changed at context switch.
+        1    unmapped
+        2    __PAGE_OFFSET - start of direct mapping of physical memory
+        ...  direct mapping in further slots as needed.
+        510  vmalloc and ioremap space
+	511  kernel code mapping, fixmaps and modules.  
+
+Other memory management related issues follows:
+
+PAGE_SIZE:
+
+	If somebody is wondering why these days we still have a so small
+	4k pagesize (16 or 32 kbytes would be much better for performance
+	of course), the PAGE_SIZE have to remain 4k for 32bit apps to
+	provide 100% backwards compatible IA32 API (we can't allow silent
+	fs corruption or as best a loss of coherency with the page cache
+	by allocating MAP_SHARED areas in MAP_ANONYMOUS memory with a
+	do_mmap_fake). I think it could be possible to have a dynamic page
+	size between 32bit and 64bit apps but it would need extremely
+	intrusive changes in the common code as first for page cache and
+	we sure don't want to depend on them right now even if the
+	hardware would support that.
+
+PAGETABLE SIZE:
+
+	In turn we can't afford to have pagetables larger than 4k because
+	we could not be able to allocate them due physical memory
+	fragmentation, and failing to allocate the kernel stack is a minor
+	issue compared to failing the allocation of a pagetable. If we
+	fail the allocation of a pagetable the only thing we can do is to
+	sched_yield polling the freelist (deadlock prone) or to segfault
+	the task (not even the sighandler would be sure to run).
+
+KERNEL STACK:
+
+	1st stage:
+
+	The kernel stack will be at first allocated with an order 2 allocation
+	(16k) (the utilization of the stack for a 64bit platform really
+	isn't exactly the double of a 32bit platform because the local
+	variables may not be all 64bit wide, but not much less). This will
+	make things even worse than they are right now on IA32 with
+	respect of failing fork/clone due memory fragmentation.
+
+	2nd stage:
+
+	We'll benchmark if reserving one register as task_struct
+	pointer will improve performance of the kernel (instead of
+	recalculating the task_struct pointer starting from the stack
+	pointer each time). My guess is that recalculating will be faster
+	but it worth a try.
+
+		If reserving one register for the task_struct pointer
+		will be faster we can as well split task_struct and kernel
+		stack. task_struct can be a slab allocation or a
+		PAGE_SIZEd allocation, and the kernel stack can then be
+		allocated in a order 1 allocation. Really this is risky,
+		since 8k on a 64bit platform is going to be less than 7k
+		on a 32bit platform but we could try it out. This would
+		reduce the fragmentation problem of an order of magnitude
+		making it equal to the current IA32.
+
+		We must also consider the x86-64 seems to provide in hardware a
+		per-irq stack that could allow us to remove the irq handler
+		footprint from the regular per-process-stack, so it could allow
+		us to live with a smaller kernel stack compared to the other
+		linux architectures.
+
+	3rd stage:
+
+	Before going into production if we still have the order 2
+	allocation we can add a sysctl that allows the kernel stack to be
+	allocated with vmalloc during memory fragmentation. This have to
+	remain turned off during benchmarks :) but it should be ok in real
+	life.
+
+Order of PAGE_CACHE_SIZE and other allocations:
+
+	On the long run we can increase the PAGE_CACHE_SIZE to be
+	an order 2 allocations and also the slab/buffercache etc.ec..
+	could be all done with order 2 allocations. To make the above
+	to work we should change lots of common code thus it can be done
+	only once the basic port will be in a production state. Having
+	a working PAGE_CACHE_SIZE would be a benefit also for
+	IA32 and other architectures of course.
+
+vmalloc:
+	vmalloc should be outside the first 512GB to keep that space free
+	for the user space. It needs an own pgd to work on in common code. 
+	It currently gets an own pgd in the 510th slot of the per CPU PML4.
+	
+PML4: 
+        Each CPU as an own PML4 (=top level of the 4 level page hierarchy). On 
+        context switch the first slot is rewritten to the pgd of the new process 
+        and CR3 is flushed.
+    
+Modules: 
+	Modules need to be in the same 4GB range as the core kernel. Otherwise
+	a GOT would be needed. Modules are currently at 0xffffffffa0000000
+        to 0xffffffffafffffff. This is inbetween the kernel text and the 
+        vsyscall/fixmap mappings.
+
+Vsyscalls: 
+        Vsyscalls have a reserved space near the end of user space that is 
+        acessible by user space. This address is part of the ABI and cannot be
+        changed. They have ffffffffff600000 to ffffffffffe00000 (but only 
+        some small space at the beginning is allocated and known to user space 
+        currently). See vsyscall.c for more details. 
+
+Fixmaps: 
+        Fixed mappings set up at boot. Used to access IO APIC and some other hardware. 
+        These are at the end of vsyscall space (ffffffffffe00000) downwards, 
+        but are not accessible by user space of course.
+
+Early mapping:
+        On a 120TB memory system bootmem could use upto 3.5GB
+        of memory for its bootmem bitmap. To avoid having to map 3.5GB by hand
+        for bootmem's purposes the full direct mapping is created before bootmem
+        is initialized. The direct mapping needs some memory for its page tables,
+        these are directly taken from the physical memory after the kernel. To
+        access these pages they need to be mapped, this is done by a temporary 
+        mapping with a few spare static 2MB PMD entries.
+
+Unsolved issues: 
+	 2MB pages for user space - may need to add a highmem zone for that again to 
+	 avoid fragmentation.
+  
+Andrea <andrea@suse.de> SuSE
+Andi Kleen <ak@suse.de> SuSE
+
+$Id$
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/MAINTAINERS linux-2.4.20/MAINTAINERS
--- linux-2.4.19/MAINTAINERS	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/MAINTAINERS	2002-10-29 11:18:32.000000000 +0000
@@ -1,3 +1,4 @@
+	
 	List of maintainers and how to submit kernel changes
 
 Please try to follow the guidelines below.  This will make things
@@ -241,6 +242,12 @@
 W:	http://www.ife.ee.ethz.ch/~sailer/ham/ham.html
 S:	Maintained
 
+BEFS FILE SYSTEM
+P:	Will Dyson
+M:	will@cs.earlham.edu
+W:	http://cs.earlham.edu/~will/software/linux/kernel/BeFS.html
+S:	Maintained
+
 BERKSHIRE PRODUCTS PC WATCHDOG DRIVER
 P:	Kenji Hollis
 M:	kenji@bitgate.com
@@ -266,6 +273,12 @@
 W:	http://bluez.sf.net
 S:	Maintained
 
+BLUETOOTH SUBSYSTEM (PC Card Drivers)
+P:	Marcel Holtmann
+M:	marcel@holtmann.org
+W:	http://www.holtmann.org/linux/bluetooth/
+S:	Maintained
+
 BTTV VIDEO4LINUX DRIVER
 P:	Gerd Knorr
 M:	kraxel@bytesex.org
@@ -529,7 +542,7 @@
 EMU10K1 SOUND DRIVER
 P:	Rui Sousa	
 M:	rui.p.m.sousa@clix.pt	
-L:	emu10k1-devel@opensource.creative.com
+L:	emu10k1-devel@lists.sourceforge.net
 W:	http://opensource.creative.com/
 S:	Maintained
 
@@ -626,8 +639,8 @@
 S:	Maintained
 
 HFS FILESYSTEM
-P:      Adrian Sun
-M:      asun@cobaltnet.com
+P:      Oliver Neukum
+M:      oliver@neukum.org
 L:      linux-kernel@vger.kernel.org
 S:      Maintained
 
@@ -704,8 +717,10 @@
 S:	Maintained
 
 IBM ServeRAID RAID DRIVER
-P:      Keith Mitchell
-M:      ipslinux@us.ibm.com
+P:      Jack Hammer
+M:      ipslinux@adaptec.com
+P:      David Jeffery
+M:      ipslinux@adaptec.com
 W:      http://www.developer.ibm.com/welcome/netfinity/serveraid.html
 S:      Supported 
 
@@ -796,7 +811,7 @@
 IOC3 DRIVER
 P:	Ralf Baechle
 M:	ralf@oss.sgi.com
-L:	linux-mips@oss.sgi.com
+L:	linux-mips@linux-mips.org
 S:	Maintained
 
 IP MASQUERADING:
@@ -852,6 +867,13 @@
 W:	http://sources.redhat.com/jffs2/
 S:	Maintained
 
+JFS FILESYSTEM
+P:	Dave Kleikamp
+M:	shaggy@austin.ibm.com
+L:	jfs-discussion@oss.software.ibm.com
+W:	http://oss.software.ibm.com/developerworks/opensource/jfs/
+S:	Supported
+
 JOYSTICK DRIVER
 P:	Vojtech Pavlik
 M:	vojtech@suse.cz
@@ -1001,7 +1023,7 @@
 P:	Ralf Baechle
 M:	ralf@gnu.org
 W:	http://oss.sgi.com/mips/mips-howto.html
-L:	linux-mips@oss.sgi.com
+L:	linux-mips@linux-mips.org
 S:	Maintained
 
 MISCELLANEOUS MCA-SUPPORT
@@ -1056,20 +1078,17 @@
 L:	linux-scsi@vger.kernel.org
 S:	Maintained
 
-NETFILTER
+NETFILTER/IPTABLES
 P:	Rusty Russell
-M:	rusty@rustcorp.com.au
 P:	Marc Boucher
-M:	marc@mbsi.ca
 P:	James Morris
-M:	jamesm@intercode.com.au
 P:	Harald Welte
-M:	laforge@gnumonks.org
 P:	Jozsef Kadlecsik
-M:	kadlec@blackhole.kfki.hu
+M:	coreteam@netfilter.org
 W:	http://www.netfilter.org/
 W:	http://www.iptables.org/
-L:	netfilter@lists.samba.org
+L:	netfilter@lists.netfilter.org
+L:	netfilter-devel@lists.netfilter.org
 S:	Supported
 
 NETROM NETWORK LAYER
@@ -1095,14 +1114,11 @@
 P:	Networking Team
 M:	netdev@oss.sgi.com
 L:	linux-net@vger.kernel.org
-W:	http://www.uk.linux.org/NetNews.html (2.0 only)
 S:	Maintained
 
 NETWORKING [IPv4/IPv6]
 P:	David S. Miller
 M:	davem@redhat.com
-P:	Andi Kleen
-M:	ak@muc.de
 P:	Alexey Kuznetsov
 M:	kuznet@ms2.inr.ac.ru
 P:	Pekka Savola (ipv6)
@@ -1236,7 +1252,7 @@
 
 PCMCIA SUBSYSTEM
 P:	David Hinds
-M:	dhinds@zen.stanford.edu
+M:	dahinds@users.sourceforge.net
 L:	linux-kernel@vger.kernel.org
 W:	http://pcmcia-cs.sourceforge.net
 S:	Maintained
@@ -1257,7 +1273,7 @@
 PHILIPS NINO PALM PC
 P:	Steven Hill
 M:	sjhill@realitydiluted.com
-L:	linux-mips@oss.sgi.com
+L:	linux-mips@linux-mips.org
 W:	http://www.realitydiluted.com/projects/nino
 S:	Maintained
 
@@ -1269,6 +1285,15 @@
 W:	http://www-jcr.lmh.ox.ac.uk/~pnp/
 S:	Maintained
 
+POWERVR2 FRAMEBUFFER DRIVER
+P:	M. R. Brown
+M:	mrbrown@0xd6.org
+P:	Paul Mundt
+M:	lethal@0xd6.org
+L:	linux-fbdev-devel@lists.sourceforge.net
+W:	http://www.linuxdc.org
+S:	Maintained
+
 PPP PROTOCOL DRIVERS AND COMPRESSORS
 P:	Paul Mackerras
 M:	paulus@samba.org
@@ -1353,10 +1378,10 @@
 S:	Maintained
 
 RME96XX MULTICHANNEL SOUND DRIVER
-P:      Guenter Geiger
-M:      geiger@epy.co.at  
-L:      linux-kernel@vger.kernel.org
-S:      Maintained
+P:	Guenter Geiger
+M:	geiger@epy.co.at  
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
 
 RTLINUX  REALTIME  LINUX
 P:	Victor Yodaiken
@@ -1530,6 +1555,13 @@
 W:	http://www.rr.iij4u.or.jp/~kkojima/linux-sh4.html
 S:	Maintained
 
+SUPERH WATCHDOG
+P:	Paul Mundt
+M:	lethal@0xd6.org
+L:	linuxsh-dev@lists.sourceforge.net
+W:	http://www.linuxsh.org
+S:	Maintained
+
 SVGA HANDLING
 P:	Martin Mares
 M:	mj@ucw.cz
@@ -1541,6 +1573,20 @@
 M:	hch@infradead.org
 S:	Maintained
 
+TI GRAPH LINK USB (SilverLink) CABLE DRIVER
+P:      Romain Lievin
+M:      roms@lpg.ticalc.org
+P:      Julien Blache
+M:      jb@technologeek.org
+S:      Maintained
+
+TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER
+P:	Stephane Dalton
+M:	sdalton@videotron.ca
+P:	Stphane Doyon
+M:	s.doyon@videotron.ca
+S:	Maintained
+
 TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER
 P:	Stephane Dalton
 M:	sdalton@videotron.ca
@@ -1635,7 +1681,7 @@
 
 USB AUERSWALD DRIVER
 P:	Wolfgang Muees
-M:	wmues@nexgo.de
+M:	wolfgang@iksw-muees.de
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
@@ -1856,6 +1902,13 @@
 M:	mingo@redhat.com
 S:	Maintained
 
+X86-64 port
+P:	Andi Kleen
+M:	ak@suse.de
+L:	discuss@x86-64.org
+W:	http://www.x86-64.org
+S:	Maintained
+
 YAM DRIVER FOR AX.25
 P:	Jean-Paul Roubelat
 M:	jpr@f6fbb.org
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/Makefile linux-2.4.20/Makefile
--- linux-2.4.19/Makefile	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/Makefile	2002-10-29 11:18:33.000000000 +0000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 19
-EXTRAVERSION =
+SUBLEVEL = 20
+EXTRAVERSION = -rc1
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -170,7 +170,7 @@
 DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus_all.o
 DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/driver.o
 DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a
-DRIVERS-$(CONFIG_PPC) += drivers/macintosh/macintosh.o
+DRIVERS-$(CONFIG_PPC32) += drivers/macintosh/macintosh.o
 DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o
 DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o
 DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a
@@ -180,11 +180,13 @@
 DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a
 DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o
 DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o
+DRIVERS-$(CONFIG_HIL) += drivers/hil/hil.o
 DRIVERS-$(CONFIG_I2O) += drivers/message/i2o/i2o.o
 DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o
 DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o
 DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o
 DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o
+DRIVERS-$(CONFIG_GSC) += drivers/gsc/gscbus.o
 DRIVERS-$(CONFIG_BLUEZ) += drivers/bluetooth/bluetooth.o
 DRIVERS-$(CONFIG_HOTPLUG_PCI) += drivers/hotplug/vmlinux-obj.o
 DRIVERS-$(CONFIG_ISDN_BOOL) += drivers/isdn/vmlinux-obj.o
@@ -258,7 +260,7 @@
 # 'kbuild_2_4_nostdinc :=' or -I/usr/include for kernel code and you are not UML
 # then your code is broken!  KAO.
 
-kbuild_2_4_nostdinc	:= -nostdinc $(shell $(CC) -print-search-dirs | sed -ne 's/install: \(.*\)/-I \1include/gp')
+kbuild_2_4_nostdinc	:= -nostdinc -iwithprefix include
 export kbuild_2_4_nostdinc
 
 export	CPPFLAGS CFLAGS CFLAGS_KERNEL AFLAGS AFLAGS_KERNEL
@@ -369,7 +371,7 @@
 TAGS: dummy
 	{ find include/asm-${ARCH} -name '*.h' -print ; \
 	find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print ; \
-	find $(SUBDIRS) init arch/${ARCH} -name '*.[chS]' ; } | grep -v SCCS | etags -
+	find $(SUBDIRS) init arch/${ARCH} -name '*.[chS]' ; } | grep -v SCCS | grep -v '\.svn' | etags -
 
 # Exuberant ctags works better with -I
 tags: dummy
@@ -487,7 +489,7 @@
 
 dep-files: scripts/mkdep archdep include/linux/version.h
 	scripts/mkdep -- init/*.c > .depend
-	scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
+	scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
 	$(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)"
 ifdef CONFIG_MODVERSIONS
 	$(MAKE) update-modverfile
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/alpha/config.in linux-2.4.20/arch/alpha/config.in
--- linux-2.4.19/arch/alpha/config.in	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/alpha/config.in	2002-10-29 11:18:34.000000000 +0000
@@ -250,9 +250,9 @@
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   bool 'Discontiguous Memory Support' CONFIG_DISCONTIGMEM
+   bool 'Discontiguous Memory Support (EXPERIMENTAL)' CONFIG_DISCONTIGMEM
    if [ "$CONFIG_DISCONTIGMEM" = "y" ]; then
-      bool ' NUMA Support' CONFIG_NUMA
+      bool ' NUMA Support (EXPERIMENTAL)' CONFIG_NUMA
    fi
 fi
 
@@ -360,7 +360,7 @@
 mainmenu_option next_comment
 comment 'Old CD-ROM drivers (not SCSI, not IDE)'
 
-bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
+bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
 if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
   source drivers/cdrom/Config.in
 fi
@@ -423,3 +423,5 @@
 fi
 
 endmenu
+
+source lib/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/alpha/kernel/pci.c linux-2.4.20/arch/alpha/kernel/pci.c
--- linux-2.4.19/arch/alpha/kernel/pci.c	2001-11-03 01:39:20.000000000 +0000
+++ linux-2.4.20/arch/alpha/kernel/pci.c	2002-10-29 11:18:32.000000000 +0000
@@ -128,7 +128,8 @@
 #define GB			(1024*MB)
 
 void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res,
+		       unsigned long size, unsigned long align)
 {
 	struct pci_dev *dev = data;
 	struct pci_controller *hose = dev->sysdata;
@@ -168,7 +169,7 @@
 		 */
 
 		/* Align to multiple of size of minimum base.  */
-		alignto = MAX(0x1000, size);
+		alignto = MAX(0x1000, align);
 		start = ALIGN(start, alignto);
 		if (hose->sparse_mem_base && size <= 7 * 16*MB) {
 			if (((start / (16*MB)) & 0x7) == 0) {
@@ -245,25 +246,6 @@
 		/* Root bus */
 		bus->resource[0] = hose->io_space;
 		bus->resource[1] = hose->mem_space;
-	} else {
-		/* This is a bridge. Do not care how it's initialized,
-		   just link its resources to the bus ones */
-		int i;
-
-		for(i=0; i<3; i++) {
-			bus->resource[i] =
-				&dev->resource[PCI_BRIDGE_RESOURCES+i];
-			bus->resource[i]->name = bus->name;
-		}
-		bus->resource[0]->flags |= pci_bridge_check_io(dev);
-		bus->resource[1]->flags |= IORESOURCE_MEM;
-		/* For now, propogate hose limits to the bus;
-		   we'll adjust them later. */
-		bus->resource[0]->end = hose->io_space->end;
-		bus->resource[1]->end = hose->mem_space->end;
-		/* Turn off downstream PF memory address range by default */
-		bus->resource[2]->start = 1024*1024;
-		bus->resource[2]->end = bus->resource[2]->start - 1;
 	}
 
 	for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
@@ -348,10 +330,14 @@
 	ranges->io_end -= hose->io_space->start;
 	ranges->mem_start -= hose->mem_space->start;
 	ranges->mem_end -= hose->mem_space->start;
+/* FIXME: On older alphas we could use dense memory space
+	  to access prefetchable resources. */
+	ranges->prefetch_start -= hose->mem_space->start;
+	ranges->prefetch_end -= hose->mem_space->start;
 }
 
 int
-pcibios_enable_device(struct pci_dev *dev)
+pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	/* Nothing to do, since we enable all devices at startup.  */
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/alpha/kernel/srm_env.c linux-2.4.20/arch/alpha/kernel/srm_env.c
--- linux-2.4.19/arch/alpha/kernel/srm_env.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/alpha/kernel/srm_env.c	2002-10-29 11:18:33.000000000 +0000
@@ -33,6 +33,15 @@
  * Changelog
  * ~~~~~~~~~
  *
+ * Thu, 22 Aug 2002 15:10:43 +0200
+ * 	- Update Config.help entry. I got a number of emails asking
+ * 	  me to tell their senders if they could make use of this
+ * 	  piece of code... So: "SRM is something like BIOS for your
+ * 	  Alpha"
+ * 	- Update code formatting a bit to better conform CodingStyle
+ * 	  rules.
+ * 	- So this is v0.0.5, with no changes (except formatting)
+ * 	
  * Wed, 22 May 2002 00:11:21 +0200
  * 	- Fix typo on comment (SRC -> SRM)
  * 	- Call this "Version 0.0.4"
@@ -59,13 +68,12 @@
 #define BASE_DIR	"srm_environment"	/* Subdir in /proc/		*/
 #define NAMED_DIR	"named_variables"	/* Subdir for known variables	*/
 #define NUMBERED_DIR	"numbered_variables"	/* Subdir for all variables	*/
-#define VERSION		"0.0.4"			/* Module version		*/
+#define VERSION		"0.0.5"			/* Module version		*/
 #define NAME		"srm_env"		/* Module name			*/
 
 MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
 MODULE_DESCRIPTION("Accessing Alpha SRM environment through procfs interface");
 MODULE_LICENSE("GPL");
-EXPORT_NO_SYMBOLS;
 
 typedef struct _srm_env {
 	char			*name;
@@ -98,9 +106,12 @@
 };
 static srm_env_t	srm_numbered_entries[256];
 
+
+
 static int
 srm_env_read(char *page, char **start, off_t off, int count, int *eof,
-		void *data) {
+		void *data)
+{
 	int		nbytes;
 	unsigned long	ret;
 	srm_env_t	*entry;
@@ -112,11 +123,11 @@
 		return -EFAULT;
 	}
 
-	entry	= (srm_env_t *)data;
+	entry	= (srm_env_t *) data;
 	ret	= callback_getenv(entry->id, page, count);
 
 	if((ret >> 61) == 0)
-		nbytes = (int)ret;
+		nbytes = (int) ret;
 	else
 		nbytes = -EFAULT;
 
@@ -125,9 +136,11 @@
 	return nbytes;
 }
 
+
 static int
 srm_env_write(struct file *file, const char *buffer, unsigned long count,
-		void *data) {
+		void *data)
+{
 #define BUFLEN	512
 	int		nbytes;
 	srm_env_t	*entry;
@@ -157,7 +170,7 @@
 		do 
 			ret2 = callback_save_env();
 		while((ret2 >> 61) == 1);
-		nbytes = (int)ret1;
+		nbytes = (int) ret1;
 	} else
 		nbytes = -EFAULT;
 
@@ -166,8 +179,10 @@
 	return nbytes;
 }
 
+
 static void
-srm_env_cleanup(void) {
+srm_env_cleanup(void)
+{
 	srm_env_t	*entry;
 	unsigned long	var_num;
 
@@ -211,8 +226,10 @@
 	return;
 }
 
+
 static int __init
-srm_env_init(void) {
+srm_env_init(void)
+{
 	srm_env_t	*entry;
 	unsigned long	var_num;
 
@@ -221,7 +238,9 @@
 	 */
 	if(!alpha_using_srm) {
 		printk(KERN_INFO "%s: This Alpha system doesn't "
-				"know about SRM...\n", __FUNCTION__);
+				"know about SRM (or you've booted "
+				"SRM->MILO->Linux, which gets "
+				"misdetected)...\n", __FUNCTION__);
 		return -ENODEV;
 	}
 
@@ -275,7 +294,7 @@
 		if(entry->proc_entry == NULL)
 			goto cleanup;
 
-		entry->proc_entry->data		= (void *)entry;
+		entry->proc_entry->data		= (void *) entry;
 		entry->proc_entry->owner	= THIS_MODULE;
 		entry->proc_entry->read_proc	= srm_env_read;
 		entry->proc_entry->write_proc	= srm_env_write;
@@ -296,7 +315,7 @@
 			goto cleanup;
 
 		entry->id			= var_num;
-		entry->proc_entry->data		= (void *)entry;
+		entry->proc_entry->data		= (void *) entry;
 		entry->proc_entry->owner	= THIS_MODULE;
 		entry->proc_entry->read_proc	= srm_env_read;
 		entry->proc_entry->write_proc	= srm_env_write;
@@ -304,20 +323,26 @@
 
 	printk(KERN_INFO "%s: version %s loaded successfully\n", NAME,
 			VERSION);
+
 	return 0;
 
 cleanup:
 	srm_env_cleanup();
+
 	return -ENOMEM;
 }
 
+
 static void __exit
-srm_env_exit(void) {
+srm_env_exit(void)
+{
 	srm_env_cleanup();
 	printk(KERN_INFO "%s: unloaded successfully\n", NAME);
+
 	return;
 }
 
+
 module_init(srm_env_init);
 module_exit(srm_env_exit);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/alpha/kernel/traps.c linux-2.4.20/arch/alpha/kernel/traps.c
--- linux-2.4.19/arch/alpha/kernel/traps.c	2001-11-20 23:49:31.000000000 +0000
+++ linux-2.4.20/arch/alpha/kernel/traps.c	2002-10-29 11:18:35.000000000 +0000
@@ -167,6 +167,11 @@
 	dik_show_trace(sp);
 }
 
+void dump_stack(void)
+{
+	show_stack(NULL);
+}
+
 void
 die_if_kernel(char * str, struct pt_regs *regs, long err, unsigned long *r9_15)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/alpha/lib/ev6-stxncpy.S linux-2.4.20/arch/alpha/lib/ev6-stxncpy.S
--- linux-2.4.19/arch/alpha/lib/ev6-stxncpy.S	2000-12-11 21:46:26.000000000 +0000
+++ linux-2.4.20/arch/alpha/lib/ev6-stxncpy.S	2002-10-29 11:18:35.000000000 +0000
@@ -205,35 +205,30 @@
 
 	cmpbge	zero, t6, t8	# E :
 	beq	a2, $u_eocfin	# U :
-	nop
+	lda	t6, -1		# E :
 	nop
 
 	bne	t8, $u_final	# U :
-	lda	t6, -1		# E : mask out the bits we have
-	mskql	t6, a1, t6	# U :   already seen (stall)
+	mskql	t6, a1, t6	# U : mask out bits already seen
 	stq_u	t0, 0(a0)	# L : store first output word
+	or      t6, t2, t2	# E : (stall)
 
-	or      t6, t2, t2		# E :
-	cmpbge	zero, t2, t8		# E : find nulls in second partial (stall)
-	addq	a0, 8, a0		# E :
-	subq	a2, 1, a2		# E :
-
+	cmpbge	zero, t2, t8	# E : find nulls in second partial
+	addq	a0, 8, a0	# E :
+	subq	a2, 1, a2	# E :
 	bne	t8, $u_late_head_exit	# U :
+
 	/* Finally, we've got all the stupid leading edge cases taken care
 	   of and we can set up to enter the main loop.  */
 	extql	t2, a1, t1	# U : position hi-bits of lo word
+	beq	a2, $u_eoc	# U :
 	ldq_u	t2, 8(a1)	# L : read next high-order source word
 	addq	a1, 8, a1	# E :
 
-	cmpbge	zero, t2, t8	# E : (stall)
-	beq	a2, $u_eoc	# U :
-	nop
-	nop
-
-	bne	t8, $u_eos	# e1    :
-	nop
-	nop
+	extqh	t2, a1, t0	# U : position lo-bits of hi word (stall)
+	cmpbge	zero, t2, t8	# E :
 	nop
+	bne	t8, $u_eos	# U :
 
 	/* Unaligned copy main loop.  In order to avoid reading too much,
 	   the loop is structured to detect zeros in aligned source words.
@@ -243,6 +238,7 @@
 	   to run as fast as possible.
 
 	   On entry to this basic block:
+	   t0 == the shifted low-order bits from the current source word
 	   t1 == the shifted high-order bits from the previous source word
 	   t2 == the unshifted current source word
 
@@ -250,25 +246,20 @@
 
 	.align 4
 $u_loop:
-	extqh	t2, a1, t0	# U : extract high bits for current word
-	addq	a1, 8, a1	# E :
-	extql	t2, a1, t3	# U : extract low bits for next time
+	or	t0, t1, t0	# E : current dst word now complete
+	subq	a2, 1, a2	# E : decrement word count
+	extql	t2, a1, t1	# U : extract low bits for next time
 	addq	a0, 8, a0	# E :
 
-	or	t0, t1, t0	# E : current dst word now complete
-	ldq_u	t2, 0(a1)	# U : Latency=3 load high word for next time
-	stq_u	t0, -8(a0)	# U : save the current word (stall)
-	mov	t3, t1		# E :
+	stq_u	t0, -8(a0)	# U : save the current word
+	beq	a2, $u_eoc	# U :
+	ldq_u	t2, 8(a1)	# U : Latency=3 load high word for next time
+	addq	a1, 8, a1	# E :
 
-	subq	a2, 1, a2	# E :
-	cmpbge	zero, t2, t8	# E : test new word for eos (2 cycle stall for data)
-	beq	a2, $u_eoc	# U : (stall)
+	extqh	t2, a1, t0	# U : extract low bits (2 cycle stall)
+	cmpbge	zero, t2, t8	# E : test new word for eos
 	nop
-
 	beq	t8, $u_loop	# U :
-	nop
-	nop
-	nop
 
 	/* We've found a zero somewhere in the source word we just read.
 	   If it resides in the lower half, we have one (probably partial)
@@ -276,11 +267,12 @@
 	   have one full and one partial word left to write out.
 
 	   On entry to this basic block:
+	   t0 == the shifted low-order bits from the current source word
 	   t1 == the shifted high-order bits from the previous source word
 	   t2 == the unshifted current source word.  */
 $u_eos:
-	extqh	t2, a1, t0	# U :
-	or	t0, t1, t0	# E : first (partial) source word complete (stall)
+	or	t0, t1, t0	# E : first (partial) source word complete
+	nop
 	cmpbge	zero, t0, t8	# E : is the null in this first bit? (stall)
 	bne	t8, $u_final	# U : (stall)
 
@@ -318,17 +310,26 @@
 1:	stq_u	t0, 0(a0)	# L :
 	ret	(t9)		# L0 : Latency=3
 
-$u_eoc:				# end-of-count
-	extqh	t2, a1, t0	# U :
-	or	t0, t1, t0	# E : (stall)
-	cmpbge	zero, t0, t8	# E : (stall)
+	  /* Got to end-of-count before end of string.  
+	     On entry to this basic block:
+	     t1 == the shifted high-order bits from the previous source word  */
+$u_eoc:
+	and	a1, 7, t6	# E : avoid final load if possible
+	sll	t10, t6, t6	# U : (stall)
+	and	t6, 0xff, t6	# E : (stall)
+	bne	t6, 1f		# U : (stall)
+
+	ldq_u	t2, 8(a1)	# L : load final src word
 	nop
+	extqh	t2, a1, t0	# U : extract low bits for last word (stall)
+	or	t1, t0, t1	# E : (stall)
+
+	cmpbge	zero, t1, t8	# E :
+	mov	t1, t0		# E :
 
 $u_eocfin:			# end-of-count, final word
 	or	t10, t8, t8	# E :
 	br	$u_final	# L0 : Latency=3
-	nop
-	nop
 
 	/* Unaligned copy entry point.  */
 	.align 4
@@ -349,9 +350,7 @@
 	mskql	t6, a0, t6	# U :
 	nop
 	nop
-	nop
-1:
-	subq	a1, t4, a1	# E : sub dest misalignment from src addr
+1:	subq	a1, t4, a1	# E : sub dest misalignment from src addr
 
 	/* If source misalignment is larger than dest misalignment, we need
 	   extra startup checks to avoid SEGV.  */
@@ -396,4 +395,3 @@
 	nop
 
 	.end __stxncpy
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/alpha/lib/stxncpy.S linux-2.4.20/arch/alpha/lib/stxncpy.S
--- linux-2.4.19/arch/alpha/lib/stxncpy.S	2000-12-11 21:46:26.000000000 +0000
+++ linux-2.4.20/arch/alpha/lib/stxncpy.S	2002-10-29 11:18:50.000000000 +0000
@@ -164,26 +164,29 @@
 	or	t0, t6, t6	# e1    : mask original data for zero test
 	cmpbge	zero, t6, t8	# e0    :
 	beq	a2, $u_eocfin	# .. e1 :
-	bne	t8, $u_final	# e1    :
+	lda	t6, -1		# e0    :
+	bne	t8, $u_final	# .. e1 :
 
-	lda	t6, -1			# e1    : mask out the bits we have
-	mskql	t6, a1, t6		# e0    :   already seen
-	stq_u	t0, 0(a0)		# e0    : store first output word
-	or      t6, t2, t2		# .. e1 :
-	cmpbge	zero, t2, t8		# e0    : find nulls in second partial
-	addq	a0, 8, a0		# .. e1 :
-	subq	a2, 1, a2		# e0    :
+	mskql	t6, a1, t6	# e0    : mask out bits already seen
+	nop			# .. e1 :
+	stq_u	t0, 0(a0)	# e0    : store first output word
+	or      t6, t2, t2	# .. e1 :
+	cmpbge	zero, t2, t8	# e0    : find nulls in second partial
+	addq	a0, 8, a0	# .. e1 :
+	subq	a2, 1, a2	# e0    :
 	bne	t8, $u_late_head_exit	# .. e1 :
 
 	/* Finally, we've got all the stupid leading edge cases taken care
 	   of and we can set up to enter the main loop.  */
 
 	extql	t2, a1, t1	# e0    : position hi-bits of lo word
-	ldq_u	t2, 8(a1)	# .. e1 : read next high-order source word
-	addq	a1, 8, a1	# e0    :
-	cmpbge	zero, t2, t8	# e1 (stall)
-	beq	a2, $u_eoc	# e1    :
-	bne	t8, $u_eos	# e1    :
+	beq	a2, $u_eoc	# .. e1 :
+	ldq_u	t2, 8(a1)	# e0    : read next high-order source word
+	addq	a1, 8, a1	# .. e1 :
+	extqh	t2, a1, t0	# e0    : position lo-bits of hi word (stall)
+	cmpbge	zero, t2, t8	# .. e1 :
+	nop			# e0    :
+	bne	t8, $u_eos	# .. e1 :
 
 	/* Unaligned copy main loop.  In order to avoid reading too much,
 	   the loop is structured to detect zeros in aligned source words.
@@ -193,6 +196,7 @@
 	   to run as fast as possible.
 
 	   On entry to this basic block:
+	   t0 == the shifted low-order bits from the current source word
 	   t1 == the shifted high-order bits from the previous source word
 	   t2 == the unshifted current source word
 
@@ -200,18 +204,18 @@
 
 	.align 3
 $u_loop:
-	extqh	t2, a1, t0	# e0    : extract high bits for current word
-	addq	a1, 8, a1	# .. e1 :
-	extql	t2, a1, t3	# e0    : extract low bits for next time
-	addq	a0, 8, a0	# .. e1 :
 	or	t0, t1, t0	# e0    : current dst word now complete
-	ldq_u	t2, 0(a1)	# .. e1 : load high word for next time
-	stq_u	t0, -8(a0)	# e0    : save the current word
-	mov	t3, t1		# .. e1 :
-	subq	a2, 1, a2	# e0    :
-	cmpbge	zero, t2, t8	# .. e1 : test new word for eos
-	beq	a2, $u_eoc	# e1    :
-	beq	t8, $u_loop	# e1    :
+	subq	a2, 1, a2	# .. e1 : decrement word count
+	stq_u	t0, 0(a0)	# e0    : save the current word
+	addq	a0, 8, a0	# .. e1 :
+	extql	t2, a1, t1	# e0    : extract high bits for next time
+	beq	a2, $u_eoc	# .. e1 :
+	ldq_u	t2, 8(a1)	# e0    : load high word for next time
+	addq	a1, 8, a1	# .. e1 :
+	nop			# e0    :
+	cmpbge	zero, t2, t8	# e1    : test new word for eos (stall)
+	extqh	t2, a1, t0	# e0    : extract low bits for current word
+	beq	t8, $u_loop	# .. e1 :
 
 	/* We've found a zero somewhere in the source word we just read.
 	   If it resides in the lower half, we have one (probably partial)
@@ -219,12 +223,12 @@
 	   have one full and one partial word left to write out.
 
 	   On entry to this basic block:
+	   t0 == the shifted low-order bits from the current source word
 	   t1 == the shifted high-order bits from the previous source word
 	   t2 == the unshifted current source word.  */
 $u_eos:
-	extqh	t2, a1, t0	# e0    :
-	or	t0, t1, t0	# e1    : first (partial) source word complete
-
+	or	t0, t1, t0	# e0    : first (partial) source word complete
+	nop			# .. e1 :
 	cmpbge	zero, t0, t8	# e0    : is the null in this first bit?
 	bne	t8, $u_final	# .. e1 (zdb)
 
@@ -260,10 +264,22 @@
 1:	stq_u	t0, 0(a0)	# e0    :
 	ret	(t9)		# .. e1 :
 
-$u_eoc:				# end-of-count
-	extqh	t2, a1, t0
-	or	t0, t1, t0
-	cmpbge	zero, t0, t8
+	/* Got to end-of-count before end of string.  
+	   On entry to this basic block:
+	   t1 == the shifted high-order bits from the previous source word  */
+$u_eoc:
+	and	a1, 7, t6	# e1    :
+	sll	t12, t6, t6	# e0    :
+	and	t6, 0xff, t6	# e0    :
+	bne	t6, 1f		# .. e1 :
+
+	ldq_u	t2, 8(a1)	# e0    : load final src word
+	nop			# .. e1 :
+	extqh	t2, a1, t0	# e0    : extract low bits for last word
+	or	t1, t0, t1	# e1    :
+
+1:	cmpbge	zero, t1, t8
+	mov	t1, t0
 
 $u_eocfin:			# end-of-count, final word
 	or	t10, t8, t8
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/alpha/mm/fault.c linux-2.4.20/arch/alpha/mm/fault.c
--- linux-2.4.19/arch/alpha/mm/fault.c	2001-09-17 23:15:02.000000000 +0000
+++ linux-2.4.20/arch/alpha/mm/fault.c	2002-10-29 11:18:35.000000000 +0000
@@ -88,6 +88,7 @@
 	struct mm_struct *mm = current->mm;
 	unsigned int fixup;
 	int fault;
+	siginfo_t info;
 
 	/* As of EV6, a load into $31/$f31 is a prefetch, and never faults
 	   (or is suppressed by the PALcode).  Support that for older CPUs
@@ -108,6 +109,8 @@
 	if (!mm || in_interrupt())
 		goto no_context;
 
+	info.si_code = SEGV_MAPERR;
+
 #ifdef CONFIG_ALPHA_LARGE_VMALLOC
 	if (address >= TASK_SIZE)
 		goto vmalloc_fault;
@@ -128,6 +131,7 @@
  * we can handle it..
  */
 good_area:
+	info.si_code = SEGV_ACCERR;
 	if (cause < 0) {
 		if (!(vma->vm_flags & VM_EXEC))
 			goto bad_area;
@@ -147,13 +151,12 @@
 	 * the fault.
 	 */
 	fault = handle_mm_fault(mm, vma, address, cause > 0);
-	up_read(&mm->mmap_sem);
-
 	if (fault < 0)
 		goto out_of_memory;
 	if (fault == 0)
 		goto do_sigbus;
 
+	up_read(&mm->mmap_sem);
 	return;
 
 /*
@@ -164,7 +167,12 @@
 	up_read(&mm->mmap_sem);
 
 	if (user_mode(regs)) {
-		force_sig(SIGSEGV, current);
+			
+		info.si_signo = SIGSEGV;
+		info.si_errno = 0;
+		/* info.si_code has been set above */
+		info.si_addr = (void *)address;
+		force_sig_info(SIGSEGV,&info,current);
 		return;
 	}
 
@@ -196,11 +204,10 @@
  */
 out_of_memory:
 	if (current->pid == 1) {
-		current->policy |= SCHED_YIELD;
-		schedule();
-		down_read(&mm->mmap_sem);
+		yield();
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk(KERN_ALERT "VM: killing process %s(%d)\n",
 	       current->comm, current->pid);
 	if (!user_mode(regs))
@@ -208,11 +215,17 @@
 	do_exit(SIGKILL);
 
 do_sigbus:
+	up_read(&mm->mmap_sem);
 	/*
 	 * Send a sigbus, regardless of whether we were in kernel
 	 * or user mode.
 	 */
-	force_sig(SIGBUS, current);
+	info.si_signo = SIGBUS;
+	info.si_errno = 0;
+	/* not sure si_code value here  */
+	info.si_code =  BUS_ADRERR;
+	info.si_addr = (void *)address;
+	force_sig_info(SIGBUS,&info,current);
 	if (!user_mode(regs))
 		goto no_context;
 	return;
@@ -220,7 +233,11 @@
 #ifdef CONFIG_ALPHA_LARGE_VMALLOC
 vmalloc_fault:
 	if (user_mode(regs)) {
-		force_sig(SIGSEGV, current);
+		info.si_signo = SIGSEGV;
+		info.si_errno = 0;
+		/* info.si_code has been set above */
+		info.si_addr = (void *)address;
+		force_sig_info(SIGSEGV,&info,current);
 		return;
 	} else {
 		/* Synchronize this task's top level page-table
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/arm/config.in linux-2.4.20/arch/arm/config.in
--- linux-2.4.19/arch/arm/config.in	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/arm/config.in	2002-10-29 11:18:34.000000000 +0000
@@ -417,7 +417,7 @@
 fi
 
 source drivers/pci/Config.in
-bool 'Support hot-pluggable devices' CONFIG_HOTPLUG
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
 if [ "$CONFIG_HOTPLUG" = "y" ]; then
    source drivers/pcmcia/Config.in
 else
@@ -503,7 +503,7 @@
    mainmenu_option next_comment
    comment 'Network device support'
 
-   bool 'Network device support?' CONFIG_NETDEVICES
+   bool 'Network device support' CONFIG_NETDEVICES
    if [ "$CONFIG_NETDEVICES" = "y" ]; then
       source drivers/net/Config.in
    fi
@@ -530,7 +530,7 @@
 mainmenu_option next_comment
 comment 'SCSI support'
 
-tristate 'SCSI support?' CONFIG_SCSI
+tristate 'SCSI support' CONFIG_SCSI
 
 if [ "$CONFIG_SCSI" != "n" ]; then
    source drivers/scsi/Config.in
@@ -618,7 +618,7 @@
    mainmenu_option next_comment
    comment 'Sound'
 
-   tristate 'Sound support' CONFIG_SOUND
+   tristate 'Sound card support' CONFIG_SOUND
    if [ "$CONFIG_SOUND" != "n" ]; then
       source drivers/sound/Config.in
    fi
@@ -655,3 +655,5 @@
 dep_bool '    Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE
 dep_bool '    Kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X
 endmenu
+
+source lib/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/arm/kernel/bios32.c linux-2.4.20/arch/arm/kernel/bios32.c
--- linux-2.4.19/arch/arm/kernel/bios32.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/arm/kernel/bios32.c	2002-10-29 11:18:38.000000000 +0000
@@ -354,25 +354,7 @@
 	struct pci_dev *dev = bus->self;
 	int i;
 
-	if (dev) {
-		for (i = 0; i < 3; i++) {
-			if(root->resource[i]) {
-				bus->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
-				bus->resource[i]->end  = root->resource[i]->end;
-				bus->resource[i]->name = bus->name;
-			}
-		}
-		bus->resource[0]->flags |= pci_bridge_check_io(dev);
-		bus->resource[1]->flags |= IORESOURCE_MEM;
-
-		if (root->resource[2])
-			bus->resource[2]->flags = root->resource[2]->flags;
-		else {
-			/* no prefetchable memory region - disable it */
-			bus->resource[2]->start = 1024*1024;
-			bus->resource[2]->end   = bus->resource[2]->start - 1;
-		}
-	} else {
+	if (!dev) {
 		/*
 		 * Assign root bus resources.
 		 */
@@ -587,7 +569,8 @@
  * but we want to try to avoid allocating at 0x2900-0x2bff
  * which might be mirrored at 0x0100-0x03ff..
  */
-void pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size, unsigned long align)
 {
 	if (res->flags & IORESOURCE_IO) {
 		unsigned long start = res->start;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/arm/mach-integrator/cpu.c linux-2.4.20/arch/arm/mach-integrator/cpu.c
--- linux-2.4.19/arch/arm/mach-integrator/cpu.c	2001-10-11 16:04:57.000000000 +0000
+++ linux-2.4.20/arch/arm/mach-integrator/cpu.c	2002-10-29 11:18:40.000000000 +0000
@@ -121,7 +121,7 @@
 	cpu_freq_khz = vco_to_freq(vco, 1);
 
 #ifdef CONFIG_CPU_FREQ
-	cpufreq_init(cpu_freq_khz);
+	cpufreq_init(cpu_freq_khz, 1000, 0);
 	cpufreq_setfunctions(integrator_validatespeed, integrator_setspeed);
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/arm/mach-sa1100/generic.c linux-2.4.20/arch/arm/mach-sa1100/generic.c
--- linux-2.4.19/arch/arm/mach-sa1100/generic.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/arm/mach-sa1100/generic.c	2002-10-29 11:18:35.000000000 +0000
@@ -86,7 +86,7 @@
 
 static int __init sa11x0_init_clock(void)
 {
-	cpufreq_init(cclk_frequency_100khz[PPCR & 0xf] * 100);
+	cpufreq_init(cclk_frequency_100khz[PPCR & 0xf] * 100, 0, 0);
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/arm/mm/fault-common.c linux-2.4.20/arch/arm/mm/fault-common.c
--- linux-2.4.19/arch/arm/mm/fault-common.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/arm/mm/fault-common.c	2002-10-29 11:18:32.000000000 +0000
@@ -225,8 +225,7 @@
 	 * If we are out of memory for pid1,
 	 * sleep for a while and retry
 	 */
-	tsk->policy |= SCHED_YIELD;
-	schedule();
+	yield();
 	goto survive;
 
 check_stack:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/config.in linux-2.4.20/arch/cris/config.in
--- linux-2.4.19/arch/cris/config.in	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.20/arch/cris/config.in	2002-10-29 11:18:31.000000000 +0000
@@ -39,6 +39,8 @@
 	bool 'Disable watchdog during Oops printouts' CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
 fi
 
+bool 'Enable ETRAX fast timer API' CONFIG_ETRAX_FAST_TIMER
+
 endmenu
 
 mainmenu_option next_comment
@@ -253,4 +255,6 @@
 if [ "$CONFIG_PROFILE" = "y" ]; then
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
+
+source lib/Config.in
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/drivers/Config.in linux-2.4.20/arch/cris/drivers/Config.in
--- linux-2.4.19/arch/cris/drivers/Config.in	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/cris/drivers/Config.in	2002-10-29 11:18:34.000000000 +0000
@@ -23,8 +23,7 @@
 
 bool 'Serial-port support' CONFIG_ETRAX_SERIAL
 if [ "$CONFIG_ETRAX_SERIAL" = "y" ]; then
-#  bool '  Use fast timers for DMA flush and RS-485 timing' CONFIG_ETRAX_SERIAL_FAST_TIMER n
-  define_bool CONFIG_ETRAX_SERIAL_FAST_TIMER n
+  bool '  Use fast timers for serial DMA flush (experimental)' CONFIG_ETRAX_SERIAL_FAST_TIMER
   if [ "$CONFIG_ETRAX_SERIAL_FAST_TIMER" = "n" ]; then
     bool '  Fast serial port DMA flush' CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
     if [ "$CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST" = "n" ]; then
@@ -156,6 +155,11 @@
 # this is true for most products since PB-I2C seems to be somewhat
 # flawed.. 
 	bool 'I2C uses PB not PB-I2C' CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
+
+	if [ "$CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C" = "y" ]; then
+          int '  I2C SDA bit number' CONFIG_ETRAX_I2C_DATA_PORT 0
+          int '  I2C SCL bit number' CONFIG_ETRAX_I2C_CLK_PORT 1
+	fi
 fi
 
 bool 'I2C EEPROM (non-volatile RAM) support' CONFIG_ETRAX_I2C_EEPROM
@@ -182,6 +186,8 @@
 
 fi
 
+bool 'VIRTEX FPGA support' CONFIG_ETRAX_VIRTEX_FPGA
+
 bool 'USB host' CONFIG_ETRAX_USB_HOST
 if [ "$CONFIG_ETRAX_USB_HOST" = "y" ]; then
 	define_bool CONFIG_USB y
@@ -191,7 +197,13 @@
 	define_bool CONFIG_USB n
 fi
 
-bool 'DS1302 Real Time Clock support' CONFIG_ETRAX_DS1302
+bool 'Real Time Clock support' CONFIG_ETRAX_RTC
+if [ "$CONFIG_ETRAX_RTC" = "y" ]; then
+  choice '  RTC chip' \
+    "DS1302 CONFIG_ETRAX_DS1302 \
+     PCF8563  CONFIG_ETRAX_PCF8563" DS1302
+fi
+
 if [ "$CONFIG_ETRAX_DS1302" = "y" ]; then
   bool '  DS1302 RST on Generic Port' CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
   int '  DS1302 RST bit number' CONFIG_ETRAX_DS1302_RSTBIT 2
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/drivers/Makefile linux-2.4.20/arch/cris/drivers/Makefile
--- linux-2.4.19/arch/cris/drivers/Makefile	2001-07-04 18:50:38.000000000 +0000
+++ linux-2.4.20/arch/cris/drivers/Makefile	2002-10-29 11:18:31.000000000 +0000
@@ -6,7 +6,7 @@
 
 obj-y :=
 
-
+obj-$(CONFIG_ETRAX_VIRTEX_FPGA)         += virtex.o
 obj-$(CONFIG_ETRAX_ETHERNET)            += ethernet.o
 obj-$(CONFIG_ETRAX_SERIAL)              += serial.o
 obj-$(CONFIG_ETRAX_IDE)                 += ide.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/drivers/ds1302.c linux-2.4.20/arch/cris/drivers/ds1302.c
--- linux-2.4.19/arch/cris/drivers/ds1302.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/cris/drivers/ds1302.c	2002-10-29 11:18:49.000000000 +0000
@@ -7,6 +7,9 @@
 *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
 *!
 *! $Log: ds1302.c,v $
+*! Revision 1.13  2002/05/29 15:16:08  johana
+*! Removed unused variables.
+*!
 *! Revision 1.12  2002/04/10 15:35:25  johana
 *! Moved probe function closer to init function and marked it __init.
 *!
@@ -85,7 +88,7 @@
 *!
 *! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
 *!
-*! $Id: ds1302.c,v 1.12 2002/04/10 15:35:25 johana Exp $
+*! $Id: ds1302.c,v 1.13 2002/05/29 15:16:08 johana Exp $
 *!
 *!***************************************************************************/
 
@@ -322,7 +325,6 @@
 		{
 			struct rtc_time rtc_tm;
 			unsigned char mon, day, hrs, min, sec, leap_yr;
-			unsigned char save_control, save_freq_select;
 			unsigned int yrs;
 
 			if (!capable(CAP_SYS_TIME))
@@ -386,7 +388,6 @@
 		case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */
 		{
 			int tcs_val;                        
-			unsigned char save_control, save_freq_select;
 
 			if (!capable(CAP_SYS_TIME))
 				return -EPERM;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/drivers/gpio.c linux-2.4.20/arch/cris/drivers/gpio.c
--- linux-2.4.19/arch/cris/drivers/gpio.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/cris/drivers/gpio.c	2002-10-29 11:18:31.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: gpio.c,v 1.15 2002/05/06 13:19:13 johana Exp $
+/* $Id: gpio.c,v 1.17 2002/06/17 15:53:01 johana Exp $
  *
  * Etrax general port I/O device
  *
@@ -9,6 +9,18 @@
  *             Johan Adolfsson  (read/set directions, write, port G)
  *
  * $Log: gpio.c,v $
+ * Revision 1.17  2002/06/17 15:53:01  johana
+ * Added IO_READ_INBITS, IO_READ_OUTBITS, IO_SETGET_INPUT and IO_SETGET_OUTPUT
+ * that take a pointer as argument and thus can handle 32 bit ports (G)
+ * correctly.
+ * These should be used instead of IO_READBITS, IO_SETINPUT and IO_SETOUTPUT.
+ * (especially if Port G bit 31 is used)
+ *
+ * Revision 1.16  2002/06/17 09:59:51  johana
+ * Returning 32 bit values in the ioctl return value doesn't work if bit
+ * 31 is set (could happen for port G), so mask it of with 0x7FFFFFFF.
+ * A new set of ioctl's will be added.
+ *
  * Revision 1.15  2002/05/06 13:19:13  johana
  * IO_SETINPUT returns mask with bit set = inputs for PA and PB as well.
  *
@@ -330,6 +342,107 @@
  * set alarms to wait for using a subsequent select().
  */
 
+unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
+{
+	/* Set direction 0=unchanged 1=input, 
+	 * return mask with 1=input 
+	 */
+	unsigned long flags;
+	if (USE_PORTS(priv)) {
+		save_flags(flags); cli();
+		*priv->dir = *priv->dir_shadow &= 
+		~((unsigned char)arg & priv->changeable_dir);
+		restore_flags(flags);
+		return ~(*priv->dir_shadow);
+	} else if (priv->minor == GPIO_MINOR_G) {
+		/* We must fiddle with R_GEN_CONFIG to change dir */
+		if (((arg & dir_g_in_bits) != arg) && 
+		    (arg & changeable_dir_g)) {
+			arg &= changeable_dir_g;
+			/* Clear bits in genconfig to set to input */
+			if (arg & (1<<0)) {
+				genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g0dir);
+				dir_g_in_bits |= (1<<0);
+				dir_g_out_bits &= ~(1<<0);
+			}
+			if ((arg & 0x0000FF00) == 0x0000FF00) {
+				genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g8_15dir);
+				dir_g_in_bits |= 0x0000FF00;
+				dir_g_out_bits &= ~0x0000FF00;
+			}
+			if ((arg & 0x00FF0000) == 0x00FF0000) {
+				genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g16_23dir);
+				dir_g_in_bits |= 0x00FF0000;
+				dir_g_out_bits &= ~0x00FF0000;
+			}
+			if (arg & (1<<24)) {
+				genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g24dir);
+				dir_g_in_bits |= (1<<24);
+				dir_g_out_bits &= ~(1<<24);
+			}
+			printk("gpio: SETINPUT on port G set "
+				"genconfig to 0x%08lX "
+				"in_bits: 0x%08lX "
+				"out_bits: 0x%08lX\n", 
+			       (unsigned long)genconfig_shadow, 
+			       dir_g_in_bits, dir_g_out_bits);
+			*R_GEN_CONFIG = genconfig_shadow;
+			/* Must be a >120 ns delay before writing this again */
+				
+		}
+		return dir_g_in_bits;
+	}
+	return 0;
+} /* setget_input */
+
+unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg)
+{
+	unsigned long flags;
+	if (USE_PORTS(priv)) {
+		save_flags(flags); cli();
+		*priv->dir = *priv->dir_shadow |= 
+		  ((unsigned char)arg & priv->changeable_dir);
+		restore_flags(flags);
+		return *priv->dir_shadow;
+	} else if (priv->minor == GPIO_MINOR_G) {
+		/* We must fiddle with R_GEN_CONFIG to change dir */			
+		if (((arg & dir_g_out_bits) != arg) &&
+		    (arg & changeable_dir_g)) {
+			/* Set bits in genconfig to set to output */
+			if (arg & (1<<0)) {
+				genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g0dir);
+				dir_g_out_bits |= (1<<0);
+				dir_g_in_bits &= ~(1<<0);
+			}
+			if ((arg & 0x0000FF00) == 0x0000FF00) {
+				genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g8_15dir);
+				dir_g_out_bits |= 0x0000FF00;
+				dir_g_in_bits &= ~0x0000FF00;
+			}
+			if ((arg & 0x00FF0000) == 0x00FF0000) {
+				genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g16_23dir);
+				dir_g_out_bits |= 0x00FF0000;
+				dir_g_in_bits &= ~0x00FF0000;
+			}
+			if (arg & (1<<24)) {
+				genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g24dir);
+				dir_g_out_bits |= (1<<24);
+				dir_g_in_bits &= ~(1<<24);
+			}
+			printk("gpio: SETOUTPUT on port G set "
+				"genconfig to 0x%08lX "
+				"in_bits: 0x%08lX "
+				"out_bits: 0x%08lX\n", 
+			       (unsigned long)genconfig_shadow, 
+			       dir_g_in_bits, dir_g_out_bits);
+			*R_GEN_CONFIG = genconfig_shadow;
+			/* Must be a >120 ns delay before writing this again */
+		}
+		return dir_g_out_bits & 0x7FFFFFFF;
+	}
+	return 0;
+} /* setget_output */
+
 static int
 gpio_leds_ioctl(unsigned int cmd, unsigned long arg);
 
@@ -338,18 +451,19 @@
 	   unsigned int cmd, unsigned long arg)
 {
 	unsigned long flags;
+	unsigned long val;
 	struct gpio_private *priv = (struct gpio_private *)file->private_data;
 	if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
 		return -EINVAL;
 	}
 
 	switch (_IOC_NR(cmd)) {
-	case IO_READBITS:
+	case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
 		// read the port
 		if (USE_PORTS(priv)) {
 			return *priv->port;
 		} else if (priv->minor == GPIO_MINOR_G) {
-			return *R_PORT_G_DATA;
+			return (*R_PORT_G_DATA) & 0x7FFFFFFF;
 		}
 		break;
 	case IO_SETBITS:
@@ -387,113 +501,28 @@
 		priv->highalarm &= ~arg;
 		priv->lowalarm  &= ~arg;
 		break;
-	case IO_READDIR:
+	case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
 		/* Read direction 0=input 1=output */
 		if (USE_PORTS(priv)) {
 			return *priv->dir_shadow;
 		} else if (priv->minor == GPIO_MINOR_G) {
 			/* Note: Some bits are both in and out,
-			 * Those that are dual is set hare as well.
+			 * Those that are dual is set here as well.
 			 */
-			return dir_g_shadow | dir_g_out_bits;
+			return (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF;
 		}
-	case IO_SETINPUT:
+	case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */
 		/* Set direction 0=unchanged 1=input, 
 		 * return mask with 1=input 
 		 */
-		if (USE_PORTS(priv)) {
-			save_flags(flags); cli();
-			*priv->dir = *priv->dir_shadow &= 
-			~((unsigned char)arg & priv->changeable_dir);
-			restore_flags(flags);
-			return ~(*priv->dir_shadow);
-		} else if (priv->minor == GPIO_MINOR_G) {
-			/* We must fiddle with R_GEN_CONFIG to change dir */
-			if (((arg & dir_g_in_bits) != arg) && 
-			    (arg & changeable_dir_g)) {
-				arg &= changeable_dir_g;
-				/* Clear bits in genconfig to set to input */
-				if (arg & (1<<0)) {
-					genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g0dir);
-					dir_g_in_bits |= (1<<0);
-					dir_g_out_bits &= ~(1<<0);
-				}
-				if ((arg & 0x0000FF00) == 0x0000FF00) {
-					genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g8_15dir);
-					dir_g_in_bits |= 0x0000FF00;
-					dir_g_out_bits &= ~0x0000FF00;
-				}
-				if ((arg & 0x00FF0000) == 0x00FF0000) {
-					genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g16_23dir);
-					dir_g_in_bits |= 0x00FF0000;
-					dir_g_out_bits &= ~0x00FF0000;
-				}
-				if (arg & (1<<24)) {
-					genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g24dir);
-					dir_g_in_bits |= (1<<24);
-					dir_g_out_bits &= ~(1<<24);
-				}
-				printk("gpio: SETINPUT on port G set "
-					"genconfig to 0x%08lX "
-					"in_bits: 0x%08lX "
-					"out_bits: 0x%08lX\n", 
-				       (unsigned long)genconfig_shadow, 
-				       dir_g_in_bits, dir_g_out_bits);
-				*R_GEN_CONFIG = genconfig_shadow;
-				/* Must be a >120 ns delay before writing this again */
-				
-			}
-			return dir_g_in_bits;
-		}
-		return 0;
-
-	case IO_SETOUTPUT:
+		return setget_input(priv, arg) & 0x7FFFFFFF;
+		break;
+	case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */
 		/* Set direction 0=unchanged 1=output, 
 		 * return mask with 1=output 
 		 */
-		if (USE_PORTS(priv)) {
-			save_flags(flags); cli();
-			*priv->dir = *priv->dir_shadow |= 
-			  ((unsigned char)arg & priv->changeable_dir);
-			restore_flags(flags);
-			return *priv->dir_shadow;
-		} else if (priv->minor == GPIO_MINOR_G) {
-			/* We must fiddle with R_GEN_CONFIG to change dir */			
-			if (((arg & dir_g_out_bits) != arg) &&
-			    (arg & changeable_dir_g)) {
-				/* Set bits in genconfig to set to output */
-				if (arg & (1<<0)) {
-					genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g0dir);
-					dir_g_out_bits |= (1<<0);
-					dir_g_in_bits &= ~(1<<0);
-				}
-				if ((arg & 0x0000FF00) == 0x0000FF00) {
-					genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g8_15dir);
-					dir_g_out_bits |= 0x0000FF00;
-					dir_g_in_bits &= ~0x0000FF00;
-				}
-				if ((arg & 0x00FF0000) == 0x00FF0000) {
-					genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g16_23dir);
-					dir_g_out_bits |= 0x00FF0000;
-					dir_g_in_bits &= ~0x00FF0000;
-				}
-				if (arg & (1<<24)) {
-					genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g24dir);
-					dir_g_out_bits |= (1<<24);
-					dir_g_in_bits &= ~(1<<24);
-				}
-				printk("gpio: SETOUTPUT on port G set "
-					"genconfig to 0x%08lX "
-					"in_bits: 0x%08lX "
-					"out_bits: 0x%08lX\n", 
-				       (unsigned long)genconfig_shadow, 
-				       dir_g_in_bits, dir_g_out_bits);
-				*R_GEN_CONFIG = genconfig_shadow;
-				/* Must be a >120 ns delay before writing this again */
-			}
-			return dir_g_out_bits;
-		}
-		return 0;
+		return setget_output(priv, arg) & 0x7FFFFFFF;
+
 	case IO_SHUTDOWN:
 		SOFT_SHUTDOWN();
 		break;
@@ -521,6 +550,47 @@
 			return -EPERM;
 		}
 		break;
+	case IO_READ_INBITS: 
+		/* *arg is result of reading the input pins */
+		if (USE_PORTS(priv)) {
+			val = *priv->port;
+		} else if (priv->minor == GPIO_MINOR_G) {
+			val = *R_PORT_G_DATA;
+		}
+		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+			return -EFAULT;
+		return 0;
+		break;
+	case IO_READ_OUTBITS:
+		 /* *arg is result of reading the output shadow */
+		if (USE_PORTS(priv)) {
+			val = *priv->shadow;
+		} else if (priv->minor == GPIO_MINOR_G) {
+			val = port_g_data_shadow;
+		}
+		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+			return -EFAULT;
+		break;
+	case IO_SETGET_INPUT: 
+		/* bits set in *arg is set to input,
+		 * *arg updated with current input pins.
+		 */
+		if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
+			return -EFAULT;
+		val = setget_input(priv, val);
+		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+			return -EFAULT;
+		break;
+	case IO_SETGET_OUTPUT:
+		/* bits set in *arg is set to output,
+		 * *arg updated with current output pins.
+		 */
+		if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
+			return -EFAULT;
+		val = setget_output(priv, val);
+		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+			return -EFAULT;
+		break;
 	default:
 		if (priv->minor == GPIO_MINOR_LEDS)
 			return gpio_leds_ioctl(cmd, arg);
@@ -690,7 +760,7 @@
 
 #endif
 	gpio_init_port_g();
-	printk("ETRAX 100LX GPIO driver v2.3, (c) 2001, 2002 Axis Communications AB\n");
+	printk("ETRAX 100LX GPIO driver v2.4, (c) 2001, 2002 Axis Communications AB\n");
 
 	return res;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/drivers/i2c.c linux-2.4.20/arch/cris/drivers/i2c.c
--- linux-2.4.19/arch/cris/drivers/i2c.c	2001-05-20 00:43:05.000000000 +0000
+++ linux-2.4.20/arch/cris/drivers/i2c.c	2002-10-29 11:18:32.000000000 +0000
@@ -12,6 +12,10 @@
 *!                                 don't use PB_I2C if DS1302 uses same bits,
 *!                                 use PB.
 *! $Log: i2c.c,v $
+*! Revision 1.8  2002/08/13 06:31:53  starvik
+*! Made SDA and SCL line configurable
+*! Modified i2c_inbyte to work with PCF8563
+*!
 *! Revision 1.7  2001/04/04 13:11:36  markusl
 *! Updated according to review remarks
 *!
@@ -40,10 +44,10 @@
 *!
 *! ---------------------------------------------------------------------------
 *!
-*! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN
+*! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
 *!
 *!***************************************************************************/
-/* $Id: i2c.c,v 1.7 2001/04/04 13:11:36 markusl Exp $ */
+/* $Id: i2c.c,v 1.8 2002/08/13 06:31:53 starvik Exp $ */
 /****************** INCLUDE FILES SECTION ***********************************/
 
 #include <linux/module.h>
@@ -93,8 +97,15 @@
 
 #ifdef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
 /* Use PB and not PB_I2C */
-#define SDABIT 0
-#define SCLBIT 1
+#ifndef CONFIG_ETRAX_I2C_DATA_PORT
+#define CONFIG_ETRAX_I2C_DATA_PORT 0
+#endif
+#ifndef CONFIG_ETRAX_I2C_CLK_PORT
+#define CONFIG_ETRAX_I2C_CLK_PORT 1
+#endif
+
+#define SDABIT CONFIG_ETRAX_I2C_DATA_PORT
+#define SCLBIT CONFIG_ETRAX_I2C_CLK_PORT
 #define i2c_enable() 
 #define i2c_disable() 
 
@@ -114,7 +125,7 @@
 
 /* read a bit from the i2c interface */
 
-#define i2c_getbit() (*R_PORT_PB_READ & (1 << SDABIT))
+#define i2c_getbit() (((*R_PORT_PB_READ & (1 << SDABIT))) >> SDABIT)
 
 #else
 /* enable or disable the i2c interface */
@@ -206,7 +217,7 @@
 i2c_outbyte(unsigned char x)
 {
 	int i;
-	
+
 	i2c_dir_out();
 
 	for (i = 0; i < 8; i++) {
@@ -238,65 +249,44 @@
 {
 	unsigned char aBitByte = 0;
 	int i;
-	int iaa;
 
-	/*
-	 * enable output
-	 */
-	i2c_dir_out();
-	/*
-	 * Release data bus by setting
-	 * data high
-	 */
-	i2c_data(I2C_DATA_HIGH);
-	/*
-	 * enable input
-	 */
+	/* Switch off I2C to get bit */
+	i2c_disable();
 	i2c_dir_in();
-	/*
-	 * Use PORT PB instead of I2C
-	 * for input. (I2C not working)
-	 */
-	i2c_clk(1);
-	i2c_data(1);
-	/*
-	 * get bits
-	 */
-	for (i = 0; i < 8; i++) {
-		i2c_delay(CLOCK_LOW_TIME/2);
-		/*
-		 * low clock period
-		 */
+	i2c_delay(CLOCK_HIGH_TIME/2);
+
+	/* Get bit */
+	aBitByte |= i2c_getbit();
+
+	/* Enable I2C */
+	i2c_enable();
+	i2c_dir_out();
+	i2c_delay(CLOCK_LOW_TIME/2);
+
+	for (i = 1; i < 8; i++) {
+		aBitByte <<= 1;
+		/* Clock pulse */
 		i2c_clk(I2C_CLOCK_HIGH);
-		/*
-		 * switch off I2C
-		 */
-		i2c_data(1);
+		i2c_delay(CLOCK_HIGH_TIME);
+		i2c_clk(I2C_CLOCK_LOW);
+		i2c_delay(CLOCK_LOW_TIME);
+
+		/* Switch off I2C to get bit */
 		i2c_disable();
 		i2c_dir_in();
-		/*
-		 * wait before getting bit
-		 */
-		i2c_delay(CLOCK_HIGH_TIME/2);
-		aBitByte = (aBitByte << 1);
-		iaa = i2c_getbit();
-		aBitByte = aBitByte | iaa ;
-		/*
-		 * wait
-		 */
 		i2c_delay(CLOCK_HIGH_TIME/2);
-		/*
-		 * end clock puls
-		 */
+
+		/* Get bit */
+		aBitByte |= i2c_getbit();
+
+		/* Enable I2C */
 		i2c_enable();
 		i2c_dir_out();
-		i2c_clk(I2C_CLOCK_LOW);
-		/*
-		 * low clock period
-		 */
 		i2c_delay(CLOCK_LOW_TIME/2);
 	}
-	i2c_dir_out();
+	i2c_clk(I2C_CLOCK_HIGH);
+	i2c_delay(CLOCK_HIGH_TIME);
+	i2c_clk(I2C_CLOCK_LOW);
 	return aBitByte;
 }
 
@@ -421,7 +411,7 @@
 *#
 *#--------------------------------------------------------------------------*/
 int
-i2c_writereg(unsigned char theSlave, unsigned char theReg,
+i2c_writereg(unsigned char theSlave, unsigned char theReg, 
 	     unsigned char theValue)
 {
 	int error, cntr = 3;
@@ -434,31 +424,12 @@
 		 */
 		save_flags(flags);
 		cli();
-		/*
-		 * generate start condition
-		 */
-		i2c_start();
-		/*
-		 * dummy preamble
-		 */
-		i2c_outbyte(0x01);
-		i2c_data(I2C_DATA_HIGH);
-		i2c_clk(I2C_CLOCK_HIGH);
-		i2c_delay(CLOCK_HIGH_TIME); /* Dummy Acknowledge */
-		i2c_clk(I2C_CLOCK_LOW);
-		i2c_delay(CLOCK_LOW_TIME);
-		i2c_clk(I2C_CLOCK_HIGH);
-		i2c_delay(CLOCK_LOW_TIME); /* Repeated Start Condition */
-		i2c_data(I2C_DATA_LOW);
-		i2c_delay(CLOCK_HIGH_TIME);
-		i2c_clk(I2C_CLOCK_LOW);
-		i2c_delay(CLOCK_LOW_TIME);
 
 		i2c_start();
 		/*
 		 * send slave address
 		 */
-		i2c_outbyte(theSlave);
+		i2c_outbyte((theSlave & 0xfe));
 		/*
 		 * wait for ack
 		 */
@@ -493,7 +464,7 @@
 		restore_flags(flags);
 		
 	} while(error && cntr--);
-	
+
 	i2c_delay(CLOCK_LOW_TIME);
 	
 	return -error;
@@ -512,7 +483,7 @@
 	unsigned char b = 0;
 	int error, cntr = 3;
 	unsigned long flags;
-		
+
 	do {
 		error = 0;
 		/*
@@ -524,28 +495,11 @@
 		 * generate start condition
 		 */
 		i2c_start();
-		/*
-		 * dummy preamble
-		 */
-		i2c_outbyte(0x01);
-		i2c_data(I2C_DATA_HIGH);
-		i2c_clk(I2C_CLOCK_HIGH);
-		i2c_delay(CLOCK_HIGH_TIME); /* Dummy Acknowledge */
-		i2c_clk(I2C_CLOCK_LOW);
-		i2c_delay(CLOCK_LOW_TIME);
-		i2c_clk(I2C_CLOCK_HIGH);
-		i2c_delay(CLOCK_LOW_TIME); /* Repeated Start Condition */
-		i2c_data(I2C_DATA_LOW);
-		i2c_delay(CLOCK_HIGH_TIME);
-		i2c_clk(I2C_CLOCK_LOW);
-		i2c_delay(CLOCK_LOW_TIME);
-    
-		i2c_start();
     
 		/*
 		 * send slave address
 		 */
-		i2c_outbyte(theSlave);
+		i2c_outbyte((theSlave & 0xfe));
 		/*
 		 * wait for ack
 		 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/drivers/pcf8563.c linux-2.4.20/arch/cris/drivers/pcf8563.c
--- linux-2.4.19/arch/cris/drivers/pcf8563.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/cris/drivers/pcf8563.c	2002-10-29 11:18:47.000000000 +0000
@@ -0,0 +1,258 @@
+/*
+ * PCF8563 RTC
+ *
+ * From Phillips' datasheet:
+ *
+ * The PCF8563 is a CMOS real-time clock/calendar optimized for low power
+ * consumption. A programmable clock output, interupt output and voltage
+ * low detector are also provided. All address and data are transferred
+ * serially via two-line bidirectional I2C-bus. Maximum bus speed is
+ * 400 kbits/s. The built-in word address register is incremented
+ * automatically after each written or read bute.
+ *
+ * Copyright (c) 2002, Axis Communications AB
+ * All rights reserved.
+ *
+ * Author: Tobias Anderberg <tobiasa@axis.com>.
+ *
+ * $Id: pcf8563.c,v 1.1 2002/08/12 13:46:02 starvik Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/svinto.h>
+#include <asm/rtc.h>
+#include "i2c.h"
+
+#define PCF8563_MAJOR 121		/* Local major number. */
+#define DEVICE_NAME "rtc"		/* Name which is registered in /proc/devices. */
+#define PCF8563_NAME "PCF8563"
+#define DRIVER_VERSION "$Rev$"
+
+/* Two simple wrapper macros, saves a few keystrokes. */
+#define rtc_read(x) i2c_readreg(RTC_I2C_READ, x)
+#define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y)
+	
+static const unsigned char days_in_month[] =
+	{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+int pcf8563_open(struct inode *, struct file *);
+int pcf8563_release(struct inode *, struct file *);
+
+static struct file_operations pcf8563_fops = {
+	owner: THIS_MODULE,
+	ioctl: pcf8563_ioctl,
+	open: pcf8563_open,
+	release: pcf8563_release,
+};
+
+void
+get_rtc_time(struct rtc_time *tm)
+{
+	unsigned long flags;
+	
+	tm->tm_sec = rtc_read(RTC_SECONDS);
+	tm->tm_min = rtc_read(RTC_MINUTES);
+	tm->tm_hour = rtc_read(RTC_HOURS);
+	tm->tm_mday = rtc_read(RTC_DAY_OF_MONTH);
+	tm->tm_mon = rtc_read(RTC_MONTH);
+	tm->tm_year = rtc_read(RTC_YEAR);
+
+	if (tm->tm_sec & 0x80)
+		printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME);
+
+        tm->tm_year = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0);
+	tm->tm_sec &= 0x7f;
+	tm->tm_min &= 0x7f;
+	tm->tm_hour &= 0x3f;
+	tm->tm_mday &= 0x3f;
+	tm->tm_mon &= 0x1f;
+
+	BCD_TO_BIN(tm->tm_sec);
+	BCD_TO_BIN(tm->tm_min);
+	BCD_TO_BIN(tm->tm_hour);
+	BCD_TO_BIN(tm->tm_mday);
+	BCD_TO_BIN(tm->tm_mon);
+	tm->tm_mon--; /* Month is 1..12 in RTC but 0..11 in linux */
+}
+
+int __init
+pcf8563_init(void)
+{
+	unsigned char ret;
+        struct rtc_time tm;
+        
+	/*
+	 * First of all we need to reset the chip. This is done by
+	 * clearing control1, control2 and clk freq, clear the 
+	 * Voltage Low bit, and resetting all alarms.
+	 */
+	if (rtc_write(RTC_CONTROL1, 0x00) < 0)
+		goto err;
+
+	if (rtc_write(RTC_CONTROL2, 0x00) < 0)
+		goto err;
+
+	if (rtc_write(RTC_CLOCKOUT_FREQ, 0x00) < 0)
+		goto err;
+
+	/* Clear the VL bit in the seconds register. */
+	ret = rtc_read(RTC_SECONDS);
+	
+	if (rtc_write(RTC_SECONDS, (ret & 0x7f)) < 0)
+		goto err;
+		
+	/* Reset the alarms. */
+	if (rtc_write(RTC_MINUTE_ALARM, 0x00) < 0)
+		goto err;
+	
+	if (rtc_write(RTC_HOUR_ALARM, 0x00) < 0)
+		goto err;
+	
+	if (rtc_write(RTC_DAY_ALARM, 0x00) < 0)
+		goto err;
+	
+	if (rtc_write(RTC_WEEKDAY_ALARM, 0x00) < 0)
+		goto err;
+
+	if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) {
+		printk(KERN_INFO "%s: Unable to get major numer %d for RTC device.\n", 
+		       PCF8563_NAME, PCF8563_MAJOR);
+		return -1;
+	}
+
+	printk(KERN_INFO "%s Real-Time Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
+        
+	/* Check for low voltage, and warn about it.. */
+	if (rtc_read(RTC_SECONDS) & 0x80)
+		printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME);
+	
+	return 0;
+
+err:
+	printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME);
+	return -1;
+}
+
+void __exit
+pcf8563_exit(void)
+{
+	if (unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME) < 0) {
+		printk(KERN_INFO "%s: Unable to unregister device.\n", PCF8563_NAME);
+	}
+}
+
+/*
+ * ioctl calls for this driver. Why return -ENOTTY upon error? Because
+ * POSIX says so!
+ */
+int
+pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	/* Some sanity checks. */
+	if (_IOC_TYPE(cmd) != PCF8563_MAGIC)
+		return -ENOTTY;
+
+	if (_IOC_NR(cmd) > RTC_MAX_IOCTL)
+		return -ENOTTY;
+
+	switch (cmd) {
+		case RTC_RD_TIME:
+			{
+				struct rtc_time tm;
+
+				get_rtc_time(&tm);
+
+				if (copy_to_user((struct rtc_time *) arg, &tm, sizeof(struct rtc_time))) {
+					return -EFAULT;
+				}
+
+				return 0;
+			}
+			break;
+		case RTC_SET_TIME:
+			{
+				int leap;
+				int century;
+				unsigned long flags;
+				struct rtc_time tm;
+
+				if (!capable(CAP_SYS_TIME))
+					return -EPERM;
+
+				if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof(struct rtc_time)))
+					return -EFAULT;
+
+				/* Convert from struct tm to struct rtc_time. */
+				tm.tm_year += 1900;
+				tm.tm_mon += 1;
+				
+				leap = ((tm.tm_mon == 2) && ((tm.tm_year % 4) == 0)) ? 1 : 0;
+
+				/* Perform some sanity checks. */
+				if ((tm.tm_year < 1970) ||
+				    (tm.tm_mon > 12) ||
+				    (tm.tm_mday == 0) ||
+				    (tm.tm_mday > days_in_month[tm.tm_mon] + leap) ||
+				    (tm.tm_hour >= 24) ||
+				    (tm.tm_min >= 60) ||
+				    (tm.tm_sec >= 60))
+					return -EINVAL;
+
+				century = (tm.tm_year >= 2000) ? 0x80 : 0;
+				tm.tm_year = tm.tm_year % 100;
+
+				BIN_TO_BCD(tm.tm_year);
+				BIN_TO_BCD(tm.tm_mday);
+				BIN_TO_BCD(tm.tm_hour);
+				BIN_TO_BCD(tm.tm_min);
+				BIN_TO_BCD(tm.tm_sec);
+				tm.tm_mon |= century;
+				
+				rtc_write(RTC_YEAR, tm.tm_year);
+				rtc_write(RTC_MONTH, tm.tm_mon);
+				rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday);
+				rtc_write(RTC_HOURS, tm.tm_hour);
+				rtc_write(RTC_MINUTES, tm.tm_min);
+				rtc_write(RTC_SECONDS, tm.tm_sec);
+
+				return 0;
+			}
+			break;
+		default:
+				return -ENOTTY;
+	}
+
+	return 0;
+}
+
+int 
+pcf8563_open(struct inode *inode, struct file *filp)
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+int
+pcf8563_release(struct inode *inode, struct file *filp)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+EXPORT_NO_SYMBOLS;
+module_init(pcf8563_init);
+module_exit(pcf8563_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/drivers/serial.c linux-2.4.20/arch/cris/drivers/serial.c
--- linux-2.4.19/arch/cris/drivers/serial.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/cris/drivers/serial.c	2002-10-29 11:18:33.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: serial.c,v 1.32 2002/05/22 13:58:00 johana Exp $
+/* $Id: serial.c,v 1.37 2002/08/13 13:02:37 bjornw Exp $
  *
  * Serial port driver for the ETRAX 100LX chip
  *
@@ -7,6 +7,24 @@
  *      Many, many authors. Based once upon a time on serial.c for 16x50.
  *
  * $Log: serial.c,v $
+ * Revision 1.37  2002/08/13 13:02:37  bjornw
+ * Removed some warnings because of unused code
+ *
+ * Revision 1.36  2002/08/08 12:50:01  starvik
+ * Serial interrupt is shared with synchronous serial port driver
+ *
+ * Revision 1.35  2002/06/03 10:40:49  starvik
+ * Increased RS-485 RTS toggle timer to 2 characters
+ *
+ * Revision 1.34  2002/05/28 18:59:36  johana
+ * Whitespace and comment fixing to be more like etrax100ser.c 1.71.
+ *
+ * Revision 1.33  2002/05/28 17:55:43  johana
+ * RS-485 uses FAST_TIMER if enabled, and starts a short (one char time)
+ * timer from tranismit_chars (interrupt context).
+ * The timer toggles RTS in interrupt context when expired giving minimum
+ * latencies.
+ *
  * Revision 1.32  2002/05/22 13:58:00  johana
  * Renamed rs_write() to raw_write() and made it inline.
  * New rs_write() handles RS-485 if configured and enabled
@@ -303,7 +321,7 @@
  *
  */
 
-static char *serial_version = "$Revision: 1.32 $";
+static char *serial_version = "$Revision: 1.37 $";
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -342,7 +360,16 @@
 #include <linux/serial.h>
 /* while we keep our own stuff (struct e100_serial) in a local .h file */
 #include "serial.h"
+#include <asm/fasttimer.h>
 
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
+#error "Disable SERIAL_FLUSH_DMA_FAST to use SERIAL_FAST_TIMER"
+#endif
+#ifndef CONFIG_ETRAX_FAST_TIMER
+#error "Enable FAST_TIMER to use SERIAL_FAST_TIMER"
+#endif
+#endif
 /*
  * All of the compatibilty code so we can compile serial.c against
  * older kernels is hidden in serial_compat.h
@@ -404,8 +431,10 @@
                     const unsigned char *buf, int count);
 static inline int raw_write(struct tty_struct * tty, int from_user,
                             const unsigned char *buf, int count);
+#ifdef CONFIG_ETRAX_RS485
 static int e100_write_rs485(struct tty_struct * tty, int from_user,
                             const unsigned char *buf, int count);
+#endif
 static int 
 get_lsr_info(struct e100_serial * info, unsigned int *value);
 
@@ -519,6 +548,9 @@
 static struct tty_struct *serial_table[NR_PORTS]; 
 static struct termios *serial_termios[NR_PORTS];
 static struct termios *serial_termios_locked[NR_PORTS];
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+static struct fast_timer fast_timers[NR_PORTS];
+#endif
 
 #ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY
 #define PROCSTAT(x) x
@@ -538,7 +570,7 @@
 
 static struct ser_statistics_type ser_stat[NR_PORTS];
 
-#else 
+#else
 
 #define PROCSTAT(x)
 
@@ -546,6 +578,9 @@
 
 /* RS-485 */
 #if defined(CONFIG_ETRAX_RS485)
+#ifdef CONFIG_ETRAX_FAST_TIMER
+static struct fast_timer fast_timers_rs485[NR_PORTS];
+#endif
 #if defined(CONFIG_ETRAX_RS485_ON_PA)
 static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
 #endif
@@ -578,7 +613,7 @@
 	volatile unsigned char *port;
 	volatile unsigned char *shadow;
 	volatile unsigned char *dir_shadow;
-	
+
 	unsigned char dtr_bit;
 	unsigned char ri_bit;
 	unsigned char dsr_bit;
@@ -872,11 +907,6 @@
 		*e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
 		restore_flags(flags);
 	}
-#if 0
-	REG_SHADOW_SET(e100_modem_pins[info->line].port,
-		       *e100_modem_pins[info->line].shadow,
-		       e100_modem_pins[info->line].ri_bit, !set);
-#endif
 #endif
 }
 static inline void 
@@ -895,11 +925,6 @@
 		*e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
 		restore_flags(flags);
 	}
-#if 0
-	REG_SHADOW_SET(e100_modem_pins[info->line].port,
-		       *e100_modem_pins[info->line].shadow,
-		       e100_modem_pins[info->line].cd_bit, !set);
-#endif
 #endif
 }
 
@@ -1014,7 +1039,7 @@
 }
 
 static int
-e100_write_rs485(struct tty_struct *tty, int from_user, 
+e100_write_rs485(struct tty_struct *tty, int from_user,
                  const unsigned char *buf, int count)
 {
 	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
@@ -1031,7 +1056,22 @@
 	info->rs485.enabled = old_enabled;
 	return count;
 }
+
+#ifdef CONFIG_ETRAX_FAST_TIMER
+/* Timer function to toggle RTS when using FAST_TIMER */
+static void rs485_toggle_rts_timer_function(unsigned long data)
+{
+	struct e100_serial *info = (struct e100_serial *)data;
+
+	fast_timers_rs485[info->line].function = NULL;
+	e100_rts(info, info->rs485.rts_after_sent);
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
+	e100_enable_rx(info);
+	e100_enable_rxdma_irq(info);
+#endif
+}
 #endif
+#endif /* CONFIG_ETRAX_RS485 */
 
 /*
  * ------------------------------------------------------------
@@ -1174,6 +1214,16 @@
 		/* our job here is done, don't schedule any new DMA transfer */
 		info->tr_running = 0;
 
+#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
+		if (info->rs485.enabled) {
+			/* Set a short timer to toggle RTS */
+			start_one_shot_timer(&fast_timers_rs485[info->line],
+			                     rs485_toggle_rts_timer_function,
+			                     (unsigned long)info,
+			                     info->char_time_usec*2,
+			                     "RS-485");
+		}
+#endif /* RS485 */
 		return;
 	}
 
@@ -1189,7 +1239,7 @@
 	*info->ocmdadr = 1;       /* dma command start -> R_DMAx_CMD */
 	
 	/* DMA is now running (hopefully) */
-}
+} /* transmit_chars */
 
 static void 
 start_transmit(struct e100_serial *info)
@@ -1205,7 +1255,7 @@
 	info->tr_running = 1;
 
 	transmit_chars(info);
-}
+} /* start_transmit */
 
 #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
 static int serial_fast_timer_started = 0;
@@ -1461,7 +1511,7 @@
 #endif
 
 	/* reset the input dma channel to be sure it works */
-	
+
 	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
 	while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
 	       IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
@@ -1636,7 +1686,7 @@
 	cli();
 
 	length = tty->flip.count;
-	
+
 	while ((buffer = info->first_recv_buffer) && length < TTY_FLIPBUF_SIZE) {
 		unsigned int count = buffer->length;
 
@@ -1889,7 +1939,7 @@
 			}
 			info->break_detected_cnt = 0;
 			DEBUG_LOG(info->line, "#iERR s d %04X\n",
-				  ((rstat & SER_ERROR_MASK) << 8) | data);
+			          ((rstat & SER_ERROR_MASK) << 8) | data);
 		}
 		PROCSTAT(ser_stat[info->line].early_errors_cnt++);
 	} else { /* It was a valid byte, now let the DMA do the rest */
@@ -1903,8 +1953,8 @@
 			 * previous interrupt we should discard it.
 			 */
 			long elapsed_usec = 
-				(curr_time - info->last_rx_active) * (1000000/HZ) + 
-				curr_time_u - info->last_rx_active_usec;
+			  (curr_time - info->last_rx_active) * (1000000/HZ) + 
+			  curr_time_u - info->last_rx_active_usec;
 			if (elapsed_usec < 2*info->char_time_usec) {
 				DEBUG_LOG(info->line, "FBRK %i\n", info->line);
 				/* Report as BREAK (error) and let
@@ -1942,7 +1992,7 @@
 	for (i = 0; i < NR_PORTS; i++) {
 		info = rs_table + i;
 
-		if (!info->uses_dma) 
+		if (!info->enabled || !info->uses_dma) 
 			continue; 
 
 		/* Which line caused the irq? */
@@ -1992,28 +2042,6 @@
 	}
 }
 
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred.  The path of
- * hangup processing is:
- *
- * 	serial interrupt routine -> (scheduler tqueue) ->
- * 	do_serial_hangup() -> tty->hangup() -> rs_hangup()
- * 
- */
-static void 
-do_serial_hangup(void *private_)
-{
-	struct e100_serial	*info = (struct e100_serial *) private_;
-	struct tty_struct	*tty;
-
-	tty = info->tty;
-	if (!tty)
-		return;
-	
-	tty_hangup(tty);
-}
-
 static int 
 startup(struct e100_serial * info)
 {
@@ -2025,7 +2053,8 @@
 	if (!xmit_page)
 		return -ENOMEM;
 
-	save_flags(flags); cli();
+	save_flags(flags); 
+	cli();
 
 	/* if it was already initialized, skip this */
 
@@ -2322,7 +2351,7 @@
 
 static inline int 
 raw_write(struct tty_struct * tty, int from_user,
-	 const unsigned char *buf, int count)
+	  const unsigned char *buf, int count)
 {
 	int	c, ret = 0;
 	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
@@ -2435,6 +2464,11 @@
 		/* If we are in RS-485 mode, we need to toggle RTS and disable
 		 * the receiver before initiating a DMA transfer
 		 */
+#ifdef CONFIG_ETRAX_FAST_TIMER
+		/* Abort any started timer */
+		fast_timers_rs485[info->line].function = NULL;
+		del_fast_timer(&fast_timers_rs485[info->line]);
+#endif
 		e100_rts(info, info->rs485.rts_on_send);
 #if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
 		e100_disable_rx(info);
@@ -2482,7 +2516,7 @@
 #endif /* CONFIG_ETRAX_RS485 */
 
 	return count;
-}
+} /* rs_write */
 
 
 /* how much space is available in the xmit buffer? */
@@ -2563,16 +2597,16 @@
 	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
-	
+
 	printk("throttle %s: %d....\n", _tty_name(tty, buf),
 	       tty->ldisc.chars_in_buffer(tty));
 #endif
-	
+
 	if (I_IXOFF(tty))
 		info->x_char = STOP_CHAR(tty);
-	
+
 	/* Turn off RTS line (do this atomic) should here be an else ?? */
-	
+
 	save_flags(flags); 
 	cli();
 	e100_rts(info, 0);
@@ -2586,20 +2620,20 @@
 	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
-	
+
 	printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
 	       tty->ldisc.chars_in_buffer(tty));
 #endif
-	
+
 	if (I_IXOFF(tty)) {
 		if (info->x_char)
 			info->x_char = 0;
 		else
 			info->x_char = START_CHAR(tty);
 	}
-	
+
 	/* Assert RTS line (do this atomic) */
-	
+
 	save_flags(flags); 
 	cli();
 	e100_rts(info, 1);
@@ -2722,8 +2756,8 @@
 #ifdef SERIAL_DEBUG_IO 
 struct state_str
 {
-  int state;
-  const char *str;
+	int state;
+	const char *str;
 };
 
 const struct state_str control_state_str[] = {
@@ -3678,6 +3712,15 @@
 			       serial_driver.name, info->line, (unsigned int)info->port);
 		}
 	}
+#ifdef CONFIG_ETRAX_FAST_TIMER
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+	memset(fast_timers, 0, sizeof(fast_timers));
+#endif
+#ifdef CONFIG_ETRAX_RS485
+	memset(fast_timers_rs485, 0, sizeof(fast_timers_rs485));
+#endif
+	fast_timer_init();
+#endif
 
 #ifndef CONFIG_SVINTO_SIM
 	/* Not needed in simulator.  May only complicate stuff. */
@@ -3689,7 +3732,7 @@
 		panic("irq23");
 #endif
 #ifdef SERIAL_HANDLE_EARLY_ERRORS
-	if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_INTERRUPT, "serial ", NULL))
+	if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial ", NULL))
 		panic("irq8");
 #endif
 #ifdef CONFIG_ETRAX_SERIAL_PORT1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/drivers/sync_serial.c linux-2.4.20/arch/cris/drivers/sync_serial.c
--- linux-2.4.19/arch/cris/drivers/sync_serial.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/cris/drivers/sync_serial.c	2002-10-29 11:18:33.000000000 +0000
@@ -227,7 +227,7 @@
 #else
 	ports[0].use_dma = 0;
 	initialize_port(0);
-	if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", &ports[0]))
+	if (request_irq(8, manual_interrupt, SA_SHIRQ | SA_INTERRUPT, "synchronous serial manual irq", &ports[0]))
 		panic("Can't allocate sync serial manual irq");
 	*R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser1_data, set);	 
 #endif
@@ -258,9 +258,9 @@
 #else
 	ports[1].use_dma = 0;	
 	initialize_port(1);
-	if (port[0].use_dma) /* Port 0 uses dma, we must manual allocate IRQ */
+	if (ports[0].use_dma) /* Port 0 uses dma, we must manual allocate IRQ */
 	{
-		if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", &ports[1]))
+		if (request_irq(8, manual_interrupt, SA_SHIRQ |SA_INTERRUPT, "synchronous serial manual irq", &ports[1]))
 			panic("Can't allocate sync serial manual irq");
 	}
 	*R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser3_data, set);	 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/drivers/usb-host.c linux-2.4.20/arch/cris/drivers/usb-host.c
--- linux-2.4.19/arch/cris/drivers/usb-host.c	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.20/arch/cris/drivers/usb-host.c	2002-10-29 11:18:36.000000000 +0000
@@ -193,17 +193,17 @@
 static USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));
 static USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4)));
 
-static urb_t *URB_List[NBR_OF_EP_DESC];
+static struct urb *URB_List[NBR_OF_EP_DESC];
 static kmem_cache_t *usb_desc_cache;
 static struct usb_bus *etrax_usb_bus;
 
 #ifdef USB_DEBUG_DESC
-static void dump_urb (purb_t purb);
+static void dump_urb (struct urb *urb);
 #endif
 static void init_rx_buffers(void);
-static int etrax_rh_unlink_urb (urb_t *urb);
-static void etrax_rh_send_irq(urb_t *urb);
-static void etrax_rh_init_int_timer(urb_t *urb);
+static int etrax_rh_unlink_urb (struct urb *urb);
+static void etrax_rh_send_irq(struct urb *urb);
+static void etrax_rh_init_int_timer(struct urb *urb);
 static void etrax_rh_int_timer_do(unsigned long ptr);
 
 static void etrax_usb_setup_epid(int epid, char devnum, char endpoint,
@@ -214,13 +214,13 @@
 static void etrax_usb_free_epid(int epid);
 static void cleanup_sb(USB_SB_Desc_t *sb);
 
-static void etrax_usb_do_ctrl_hw_add(urb_t *urb, int epid, char maxlen);
-static void etrax_usb_do_bulk_hw_add(urb_t *urb, int epid, char maxlen);
+static void etrax_usb_do_ctrl_hw_add(struct urb *urb, int epid, char maxlen);
+static void etrax_usb_do_bulk_hw_add(struct urb *urb, int epid, char maxlen);
 
-static int etrax_usb_submit_ctrl_urb(urb_t *urb);
+static int etrax_usb_submit_ctrl_urb(struct urb *urb);
 
-static int etrax_usb_submit_urb(urb_t *urb);
-static int etrax_usb_unlink_urb(urb_t *urb);
+static int etrax_usb_submit_urb(struct urb *urb);
+static int etrax_usb_unlink_urb(struct urb *urb);
 static int etrax_usb_get_frame_number(struct usb_device *usb_dev);
 static int etrax_usb_allocate_dev(struct usb_device *usb_dev);
 static int etrax_usb_deallocate_dev(struct usb_device *usb_dev);
@@ -229,7 +229,7 @@
 static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs);
 static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs);
 
-static int etrax_rh_submit_urb (urb_t *urb);
+static int etrax_rh_submit_urb (struct urb *urb);
 
 static int etrax_usb_hc_init(void);
 static void etrax_usb_hc_cleanup(void);
@@ -244,24 +244,24 @@
 };
 
 #ifdef USB_DEBUG_DESC
-static void dump_urb(purb_t purb)
+static void dump_urb(struct urb *urb)
 {
-	printk("\nurb                   :0x%08X\n", purb);
-	printk("next                  :0x%08X\n", purb->next);
-	printk("dev                   :0x%08X\n", purb->dev);
-	printk("pipe                  :0x%08X\n", purb->pipe);
-	printk("status                :%d\n", purb->status);
-	printk("transfer_flags        :0x%08X\n", purb->transfer_flags);
-	printk("transfer_buffer       :0x%08X\n", purb->transfer_buffer);
-	printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
-	printk("actual_length         :%d\n", purb->actual_length);
-	printk("setup_packet          :0x%08X\n", purb->setup_packet);
-	printk("start_frame           :%d\n", purb->start_frame);
-	printk("number_of_packets     :%d\n", purb->number_of_packets);
-	printk("interval              :%d\n", purb->interval);
-	printk("error_count           :%d\n", purb->error_count);
-	printk("context               :0x%08X\n", purb->context);
-	printk("complete              :0x%08X\n\n", purb->complete);
+	printk("\nurb                   :0x%08X\n", urb);
+	printk("next                  :0x%08X\n", urb->next);
+	printk("dev                   :0x%08X\n", urb->dev);
+	printk("pipe                  :0x%08X\n", urb->pipe);
+	printk("status                :%d\n", urb->status);
+	printk("transfer_flags        :0x%08X\n", urb->transfer_flags);
+	printk("transfer_buffer       :0x%08X\n", urb->transfer_buffer);
+	printk("transfer_buffer_length:%d\n", urb->transfer_buffer_length);
+	printk("actual_length         :%d\n", urb->actual_length);
+	printk("setup_packet          :0x%08X\n", urb->setup_packet);
+	printk("start_frame           :%d\n", urb->start_frame);
+	printk("number_of_packets     :%d\n", urb->number_of_packets);
+	printk("interval              :%d\n", urb->interval);
+	printk("error_count           :%d\n", urb->error_count);
+	printk("context               :0x%08X\n", urb->context);
+	printk("complete              :0x%08X\n\n", urb->complete);
 }
 
 static void dump_in_desc(USB_IN_Desc_t *in)
@@ -425,7 +425,7 @@
 }
 
 
-static int etrax_usb_unlink_intr_urb(urb_t *urb)
+static int etrax_usb_unlink_intr_urb(struct urb *urb)
 {
 	USB_EP_Desc_t *tmp_ep;
 	USB_EP_Desc_t *first_ep;
@@ -511,7 +511,7 @@
 	} while (tmp_ep != first_ep);
 }
 
-static int etrax_usb_submit_intr_urb(urb_t *urb)
+static int etrax_usb_submit_intr_urb(struct urb *urb)
 {
 	USB_EP_Desc_t *tmp_ep;
 	USB_EP_Desc_t *first_ep;
@@ -641,7 +641,7 @@
 
 static void handle_intr_transfer_attn(int epid, int status)
 {
-	urb_t *old_urb;
+	struct urb *old_urb;
 
 	DBFENTER;
 
@@ -694,7 +694,7 @@
 	DBFEXIT;
 }
 
-static int etrax_rh_unlink_urb (urb_t *urb)
+static int etrax_rh_unlink_urb (struct urb *urb)
 {
 	etrax_hc_t *hc;
 	
@@ -711,7 +711,7 @@
 	return 0;
 }
 
-static void etrax_rh_send_irq(urb_t *urb)
+static void etrax_rh_send_irq(struct urb *urb)
 {
 	__u16 data = 0;
 	etrax_hc_t *hc = urb->dev->bus->hcpriv;
@@ -744,7 +744,7 @@
 /*	DBFEXIT; */
 }
 
-static void etrax_rh_init_int_timer(urb_t *urb)
+static void etrax_rh_init_int_timer(struct urb *urb)
 {
 	etrax_hc_t *hc;
 	
@@ -763,12 +763,12 @@
 
 static void etrax_rh_int_timer_do(unsigned long ptr)
 {
-	urb_t *urb;
+	struct urb *urb;
 	etrax_hc_t *hc;
 	
 /*	DBFENTER; */
 	
-	urb = (urb_t*)ptr;
+	urb = (struct urb*)ptr;
 	hc = urb->dev->bus->hcpriv;
 	
 	if (hc->rh.send) {
@@ -910,7 +910,7 @@
 	return -1;
 }
 
-static int etrax_usb_submit_bulk_urb(urb_t *urb)
+static int etrax_usb_submit_bulk_urb(struct urb *urb)
 {
 	int epid;
 	char devnum;
@@ -919,7 +919,7 @@
 	char out_traffic;
 	char slow;
 
-	urb_t *tmp_urb;
+	struct urb *tmp_urb;
 	
 	unsigned long flags;
 	
@@ -969,7 +969,7 @@
 	return 0;
 }
 
-static void etrax_usb_do_bulk_hw_add(urb_t *urb, int epid, char maxlen)
+static void etrax_usb_do_bulk_hw_add(struct urb *urb, int epid, char maxlen)
 {
 	USB_SB_Desc_t *sb_desc_1;
 
@@ -1086,7 +1086,7 @@
 
 static void handle_bulk_transfer_attn(int epid, int status)
 {
-	urb_t *old_urb;
+	struct urb *old_urb;
 	etrax_urb_priv_t *hc_priv;
 	unsigned long flags;
 
@@ -1166,7 +1166,7 @@
 
 /* ---------------------------------------------------------------------------- */
 
-static int etrax_usb_submit_ctrl_urb(urb_t *urb)
+static int etrax_usb_submit_ctrl_urb(struct urb *urb)
 {
 	int epid;
 	char devnum;
@@ -1175,7 +1175,7 @@
 	char out_traffic;
 	char slow;
 
-	urb_t *tmp_urb;
+	struct urb *tmp_urb;
 	
 	unsigned long flags;
 	
@@ -1225,7 +1225,7 @@
 	return 0;
 }
 
-static void etrax_usb_do_ctrl_hw_add(urb_t *urb, int epid, char maxlen)
+static void etrax_usb_do_ctrl_hw_add(struct urb *urb, int epid, char maxlen)
 {
 	USB_SB_Desc_t *sb_desc_1;
 	USB_SB_Desc_t *sb_desc_2;
@@ -1364,7 +1364,7 @@
 	DBFEXIT;
 }
 
-static int etrax_usb_submit_urb(urb_t *urb)
+static int etrax_usb_submit_urb(struct urb *urb)
 {
 	etrax_hc_t *hc;
 	int rval = -EINVAL;
@@ -1411,7 +1411,7 @@
 	return rval;
 }
 
-static int etrax_usb_unlink_urb(urb_t *urb)
+static int etrax_usb_unlink_urb(struct urb *urb)
 {
 	etrax_hc_t *hc = urb->dev->bus->hcpriv;
 	int epid;
@@ -1455,8 +1455,8 @@
 	cli();
 	
 	for (epid = 0; epid < 32; epid++) {
-		urb_t *u = URB_List[epid];
-		urb_t *prev = NULL;
+		struct urb *u = URB_List[epid];
+		struct urb *prev = NULL;
 		int pos = 0;
 
 		for (; u; u = u->next) {
@@ -1557,7 +1557,7 @@
 static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs)
 {
 	int epid = 0;
-	urb_t *urb;
+	struct urb *urb;
 	etrax_urb_priv_t *urb_priv;
 		
 	*R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do);
@@ -1655,7 +1655,7 @@
 
 static void handle_control_transfer_attn(int epid, int status)
 {
-	urb_t *old_urb;
+	struct urb *old_urb;
 	etrax_urb_priv_t *hc_priv;	
 
 	DBFENTER;
@@ -1981,12 +1981,12 @@
 	DBFEXIT;
 }
 
-static int etrax_rh_submit_urb(urb_t *urb)
+static int etrax_rh_submit_urb(struct urb *urb)
 {
 	struct usb_device *usb_dev = urb->dev;
 	etrax_hc_t *hc = usb_dev->bus->hcpriv;
 	unsigned int pipe = urb->pipe;
-	devrequest *cmd = (devrequest *) urb->setup_packet;
+	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
 	void *data = urb->transfer_buffer;
 	int leni = urb->transfer_buffer_length;
 	int len = 0;
@@ -2010,10 +2010,10 @@
 		return 0;
 	}
 
-	bmRType_bReq = cmd->requesttype | cmd->request << 8;
-	wValue = le16_to_cpu(cmd->value);
-	wIndex = le16_to_cpu(cmd->index);
-	wLength = le16_to_cpu(cmd->length);
+	bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8;
+	wValue = le16_to_cpu(cmd->wValue);
+	wIndex = le16_to_cpu(cmd->wIndex);
+	wLength = le16_to_cpu(cmd->wLength);
 
 	dbg_rh("bmRType_bReq : 0x%04X (%d)", bmRType_bReq, bmRType_bReq);
 	dbg_rh("wValue       : 0x%04X (%d)", wValue, wValue);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/drivers/virtex.c linux-2.4.20/arch/cris/drivers/virtex.c
--- linux-2.4.19/arch/cris/drivers/virtex.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/cris/drivers/virtex.c	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,405 @@
+/*!***************************************************************************
+*!
+*! FILE NAME  : vertex.c
+*!
+*! DESCRIPTION: Implements an interface towards virtex FPGA (mounted on one of our
+*!              evaluation boards) from userspace using ioctl()'s
+*!
+*!              The FPGA can be programmed by copying the bit-file to /dev/fpga.
+*!
+*!                cp fpga.bit > /dev/fpga
+*!
+*!                Kernel log should look like:
+*!                  69900 bytes written
+*!                  FPGA-configuration completed, no errors
+*!
+*!              Number of bytes written depends on the FPGA
+*!
+*!                From Xilinx data sheet:
+*!                XCV50    559,200 bits
+*!                XCV100   781,216 bits
+*!                XCV800 4,715,616 bits
+*!
+*!              Accepted file type is the design.bit generated by Alliance
+*!              Design Manager.
+*!              This software just sends the bitfile into the device without
+*!              checking device type etc.
+*!
+*!              Sync-header 0xff 0xff 0xff 0xff defines the start for the
+*!              byte stream, everything from that position is written to the FPGA.
+*!
+*!  
+*! Jul 19 2002  Stefan Lundberg    Initial version.
+*! $Log: virtex.c,v $
+*! Revision 1.1  2002/06/25 09:58:58  stefanl
+*! New FPGA driver for Platoon
+*!
+*!
+*! ---------------------------------------------------------------------------
+*!
+*! (C) Copyright 2002 Axis Communications AB, LUND, SWEDEN
+*!
+*!***************************************************************************/
+/* $Id: virtex.c,v 1.1 2002/06/25 09:58:58 stefanl Exp $ */
+/****************** INCLUDE FILES SECTION ***********************************/
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/config.h>
+
+#include <linux/hdreg.h>
+#include <linux/mm.h>
+
+#include <asm/etraxvirtex.h>
+
+#include <asm/system.h>
+#include <asm/svinto.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#include "virtex.h"
+
+/******************* VIRTEX DEFINITION SECTION **************************/
+
+#define VIRTEX_DEBUG(x)
+
+#define VIRTEX_MAJOR 246  /* EXPERIMENTAL */
+
+static const char virtex_name[] = "virtex";
+
+/****************** FUNCTION DEFINITION SECTION *************************/
+
+
+
+//
+// Read register interface for FPGA programming:
+//
+//   FPGA_DONE is connected to S1CD_N G28
+//   FPGA_INIT_N is connected to S1IO_N G27
+//
+
+// Write register interface for FPGA programming:
+//
+//  Bit:       15         14      13    12      9   8   7   0
+//        ____________________________________________________
+//       | fpga_write | program | cclk | reserved | cs | data |
+//       |____________|_________|______|__________|____|______|
+//
+
+
+// csp0 = cs_fpga1 = FPGA programming interface
+// csr0 = cs_fpga2 = register interface towards FPGA construction
+
+static volatile short *port_csp0_word_addr;
+static volatile short *port_csr0_word_addr;
+
+static volatile unsigned char open_count;
+static volatile unsigned char bytes_written;
+static volatile unsigned long bytes_written_cnt;
+static volatile unsigned char sync_found;
+static volatile unsigned char sync_count;
+static volatile unsigned char sync_ff_count;
+
+#define WRITE_FPGA_PROG_REG(data) *port_csp0_word_addr=(data)
+#define SET_PROGRAM_BIT(data) (data)|(1<<14)
+
+#define SET_WRITE_BIT(data) (data)|(1<<15)
+#define CLR_WRITE_BIT(data) (data)&(~(1<<15))
+
+#define SET_CS_BIT(data) (data)|(1<<8)
+#define CLR_CS_BIT(data) (data)&(~(1<<8))
+
+#define SET_CCLK_BIT(data) (data)|(1<<13)
+#define CLR_CCLK_BIT(data) (data)&(~(1<<13))
+
+// Bit in read port G (always inputs)
+#define READ_INIT  (*R_PORT_G_DATA)&(1<<27)
+#define READ_DONE  (*R_PORT_G_DATA)&(1<<28)
+
+
+void start_virtex_program(void)
+{
+  unsigned short reg_data=0;
+
+  printk("Start writing to FPGA\n");
+  reg_data = SET_CS_BIT(reg_data); // FPGA unselected
+
+  reg_data = SET_PROGRAM_BIT(reg_data);
+  WRITE_FPGA_PROG_REG(reg_data);
+
+  while(!READ_INIT); // Wait for init
+  
+  reg_data = SET_WRITE_BIT(reg_data);
+  WRITE_FPGA_PROG_REG(reg_data);
+
+  reg_data = CLR_CS_BIT(reg_data); // FPGA selected, CS is active low
+  WRITE_FPGA_PROG_REG(reg_data);
+  return;
+}
+
+// According to datasheet, bytes should be reversed, it is unknown to me why.
+unsigned char bit_reverse(unsigned char data) 
+{
+  unsigned char in=data;
+  unsigned short out=0;
+  unsigned int i=0;
+
+  for(i=0;i<8;i++) {
+    if(in&0x1) {
+      out|=0x1;
+    }
+    in=in>>1;
+    out=out<<1;
+  }
+
+  return(out>>1);
+  
+}
+
+void virtex_program(char* ptr,size_t count)
+{
+  int c;
+  char *p;
+  unsigned char data;  
+  unsigned short reg_data=0;
+//  short tmp_cnt;
+  
+  c=count;
+  p=ptr;
+
+  if(!sync_found) {
+    c=count;
+    p=ptr;
+    while(c--) {
+      data=(unsigned char)*p++;
+      sync_count++;
+
+      if(sync_count>=256) {
+        printk("Sync not found, aborting\n");
+        return;
+      }
+
+      if(data==0xff) {
+        sync_ff_count++;
+      } else {
+        sync_ff_count=0;
+      }
+      if(sync_ff_count==4) {
+        sync_found=1;
+        VIRTEX_DEBUG(printk("Sync found at offset %d\n",sync_count));
+        p--;p--;p--;p--;
+        c++;c++;c++;c++;
+        break;
+      }
+    }
+  }
+
+  if(sync_found) {
+    if(bytes_written==0) {
+      start_virtex_program();
+    }
+    bytes_written=1;
+  
+    reg_data = SET_PROGRAM_BIT(reg_data);
+    reg_data = SET_WRITE_BIT(reg_data);
+    reg_data = CLR_CS_BIT(reg_data);
+  
+//    tmp_cnt=0;
+    
+    printk("*");
+    while(c--) {
+      data=(unsigned char)*p++;
+      data=bit_reverse(data);
+
+/* debug
+      tmp_cnt++;
+      if(tmp_cnt<=32 || c<=32 ) {
+        printk("0x%x ",data); 
+      }
+      if(tmp_cnt==32 || c==0 ) {
+        printk("\n"); 
+      }
+*/
+      bytes_written_cnt++;
+      reg_data = CLR_CCLK_BIT(reg_data);
+      WRITE_FPGA_PROG_REG(reg_data|(data&0xff));
+      reg_data = SET_CCLK_BIT(reg_data);
+      WRITE_FPGA_PROG_REG(reg_data|(data&0xff));
+      reg_data = CLR_CCLK_BIT(reg_data);
+      WRITE_FPGA_PROG_REG(reg_data|(data&0xff));
+  
+    }
+  }
+   
+  return;
+}
+
+void stop_virtex_program(void)
+{
+  unsigned short reg_data=0;
+
+  reg_data = SET_PROGRAM_BIT(reg_data);
+  reg_data = SET_WRITE_BIT(reg_data);
+  reg_data = CLR_CCLK_BIT(reg_data);
+
+  reg_data = SET_CS_BIT(reg_data); // release CS
+  WRITE_FPGA_PROG_REG(reg_data);
+
+  reg_data = CLR_WRITE_BIT(reg_data); // release write, important to do!
+  WRITE_FPGA_PROG_REG(reg_data);
+  printk("%d bytes written\n",bytes_written_cnt);
+  if(READ_DONE) {
+    printk("FPGA-configuration completed, no errors\n");
+  } else {
+    printk("Error, FPGA-configuration failed\n");
+  }
+  return;
+}
+
+static int
+virtex_open(struct inode *inode, struct file *filp)
+{
+  port_csp0_word_addr = port_csp0_addr;
+  if(open_count>=1) {
+    printk("FPGA Device busy, aborting\n");
+    return(-EBUSY);
+  }
+  open_count++;
+  bytes_written=0;
+  sync_found=0;
+  sync_count=0;
+  sync_ff_count=0;
+  bytes_written_cnt=0;
+  return(0);
+}
+
+static int
+virtex_release(struct inode *inode, struct file *filp)
+{
+  open_count--;
+  if(bytes_written!=0)stop_virtex_program();
+  return 0;
+}
+
+// FPGA programming interface
+
+static ssize_t virtex_write(struct file * file, const char * buf, 
+                                 size_t count, loff_t *ppos)
+{
+  char *ptr;
+  VIRTEX_DEBUG(printk("Write FPGA count %d\n", count));
+  
+  ptr=kmalloc(count, GFP_KERNEL);
+  if(!ptr) {
+    printk("FPGA device, kernel malloc failed (%d) bytes\n",count);
+    return -EFAULT;
+  }
+  if(copy_from_user(ptr, buf, count)) {
+    printk("copy_from_user failed\n");
+    return -EFAULT;
+  }
+  
+  virtex_program(ptr,count);
+  
+  kfree(ptr);
+  return count;
+}
+
+/* Main device API. ioctl's to write or read to/from registers.
+ */
+
+int virtex_writereg(unsigned short theReg, unsigned short theValue)
+{
+  port_csr0_word_addr[theReg]=theValue;
+  return(0);
+}
+
+unsigned short virtex_readreg(unsigned short theReg)
+{
+  return(port_csr0_word_addr[theReg]);
+}
+
+
+static int
+virtex_ioctl(struct inode *inode, struct file *file,
+	  unsigned int cmd, unsigned long arg)
+{
+  if(_IOC_TYPE(cmd) != ETRAXVIRTEX_FPGA_IOCTYPE) {
+    return -EINVAL;
+  }
+  
+  switch (_IOC_NR(cmd)) {
+    case VIRTEX_FPGA_WRITEREG:
+      /* write to an FPGA register */
+      VIRTEX_DEBUG(printk("virtex wr %d %d\n", 
+               VIRTEX_FPGA_ARGREG(arg),
+               VIRTEX_FPGA_ARGVALUE(arg)));
+      
+      return virtex_writereg(VIRTEX_FPGA_ARGREG(arg),
+                             VIRTEX_FPGA_ARGVALUE(arg));
+    case VIRTEX_FPGA_READREG:
+    {
+      unsigned char val;
+      /* read from an FPGA register */
+      VIRTEX_DEBUG(printk("virtex rd %d ", 
+              VIRTEX_FPGA_ARGREG(arg)));
+      val = virtex_readreg(VIRTEX_FPGA_ARGREG(arg));
+      VIRTEX_DEBUG(printk("= %d\n", val));
+      return val;
+    }					    
+    default:
+      return -EINVAL;
+    }
+
+return 0;
+}
+
+static struct file_operations virtex_fops = {
+	owner:    THIS_MODULE,
+	ioctl:    virtex_ioctl,
+	open:     virtex_open,
+        write:    virtex_write,
+	release:  virtex_release,
+};
+
+static int __init
+virtex_init(void)
+{
+  int res;
+  
+  /* register char device */
+  res = register_chrdev(VIRTEX_MAJOR, virtex_name, &virtex_fops);
+  if(res < 0) {
+          printk(KERN_ERR "virtex: couldn't get a major number.\n");
+          return res;
+  }
+  
+  port_csr0_word_addr = (volatile unsigned short *) 
+                        ioremap((unsigned long)(MEM_CSR0_START |
+                                                MEM_NON_CACHEABLE), 16);
+     
+// see ~/platoon/rel2/platoon/os/linux/arch/cris/mm/init.c
+//              port_csp0_addr = (volatile unsigned long *)
+//                 ioremap((unsigned long)(MEM_CSP0_START |
+//                                         MEM_NON_CACHEABLE), 16);
+  
+  open_count=0;
+  
+  printk("VIRTEX(TM) FPGA driver v1.0, (c) 2002 Axis Communications AB\n");
+  
+  return 0;
+}
+
+/* this makes sure that virtex_init is called during boot */
+
+module_init(virtex_init);
+
+/****************** END OF FILE virtex.c ********************************/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/drivers/virtex.h linux-2.4.20/arch/cris/drivers/virtex.h
--- linux-2.4.19/arch/cris/drivers/virtex.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/cris/drivers/virtex.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,7 @@
+/* $Id: virtex.h,v 1.1 2002/06/25 09:58:58 stefanl Exp $ */
+
+int virtex_writereg(unsigned short theReg, unsigned short theValue);
+unsigned short virtex_readreg(unsigned short theReg);
+
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/kernel/Makefile linux-2.4.20/arch/cris/kernel/Makefile
--- linux-2.4.19/arch/cris/kernel/Makefile	2001-11-09 21:58:02.000000000 +0000
+++ linux-2.4.20/arch/cris/kernel/Makefile	2002-10-29 11:18:32.000000000 +0000
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.9 2001/10/22 13:10:21 pkj Exp $
+# $Id: Makefile,v 1.10 2002/05/27 15:41:40 johana Exp $
 #
 # Makefile for the linux kernel.
 #
@@ -25,6 +25,7 @@
 
 obj-$(CONFIG_MODULES)    += ksyms.o
 obj-$(CONFIG_ETRAX_KGDB) += kgdb.o
+obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o
 
 # This dependency isn't caught by mkdep.  See entry.S.
 entry.o: entryoffsets.s
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/kernel/fasttimer.c linux-2.4.20/arch/cris/kernel/fasttimer.c
--- linux-2.4.19/arch/cris/kernel/fasttimer.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/cris/kernel/fasttimer.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,974 @@
+/* $Id: fasttimer.c,v 1.4 2002/05/28 17:47:59 johana Exp $
+ * linux/arch/cris/kernel/fasttimer.c
+ *
+ * Fast timers for ETRAX100/ETRAX100LX
+ * This may be useful in other OS than Linux so use 2 space indentation...
+ *
+ * $Log: fasttimer.c,v $
+ * Revision 1.4  2002/05/28 17:47:59  johana
+ * Added del_fast_timer()
+ *
+ * Revision 1.3  2002/05/28 16:16:07  johana
+ * Handle empty fast_timer_list
+ *
+ * Revision 1.2  2002/05/27 15:38:42  johana
+ * Made it compile without warnings on Linux 2.4.
+ * (includes, wait_queue, PROC_FS and snprintf)
+ *
+ * Revision 1.1  2002/05/27 15:32:25  johana
+ * arch/etrax100/kernel/fasttimer.c v1.8 from the elinux tree.
+ *
+ * Revision 1.8  2001/11/27 13:50:40  pkj
+ * Disable interrupts while stopping the timer and while modifying the
+ * list of active timers in timer1_handler() as it may be interrupted
+ * by other interrupts (e.g., the serial interrupt) which may add fast
+ * timers.
+ *
+ * Revision 1.7  2001/11/22 11:50:32  pkj
+ * * Only store information about the last 16 timers.
+ * * proc_fasttimer_read() now uses an allocated buffer, since it
+ *   requires more space than just a page even for only writing the
+ *   last 16 timers. The buffer is only allocated on request, so
+ *   unless /proc/fasttimer is read, it is never allocated.
+ * * Renamed fast_timer_started to fast_timers_started to match
+ *   fast_timers_added and fast_timers_expired.
+ * * Some clean-up.
+ *
+ * Revision 1.6  2000/12/13 14:02:08  johana
+ * Removed volatile for fast_timer_list
+ *
+ * Revision 1.5  2000/12/13 13:55:35  johana
+ * Added DEBUG_LOG, added som cli() and cleanup
+ *
+ * Revision 1.4  2000/12/05 13:48:50  johana
+ * Added range check when writing proc file, modified timer int handling
+ *
+ * Revision 1.3  2000/11/23 10:10:20  johana
+ * More debug/logging possibilities.
+ * Moved GET_JIFFIES_USEC() to timex.h and time.c
+ *
+ * Revision 1.2  2000/11/01 13:41:04  johana
+ * Clean up and bugfixes.
+ * Created new do_gettimeofday_fast() that gets a timeval struct
+ * with time based on jiffies and *R_TIMER0_DATA, uses a table
+ * for fast conversion of timer value to microseconds.
+ * (Much faster the standard do_gettimeofday() and we don't really
+ * wan't to use the true time - we wan't the "uptime" so timers don't screw up
+ * when we change the time.
+ * TODO: Add efficient support for continuous timers as well.
+ *
+ * Revision 1.1  2000/10/26 15:49:16  johana
+ * Added fasttimer, highresolution timers.
+ *
+ * Copyright (C) 2000,2001 2002 Axis Communications AB, Lund, Sweden
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <asm/rtc.h>
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <asm/svinto.h>
+#include <asm/fasttimer.h>
+#include <linux/proc_fs.h>
+
+
+#define DEBUG_LOG_INCLUDED
+#define FAST_TIMER_LOG
+//#define FAST_TIMER_TEST
+
+#define FAST_TIMER_SANITY_CHECKS
+
+#ifdef FAST_TIMER_SANITY_CHECKS
+#define SANITYCHECK(x) x
+static int sanity_failed = 0;
+#else
+#define SANITYCHECK(x)
+#endif
+
+#define D1(x)
+#define D2(x)
+#define DP(x)
+
+#define __INLINE__ inline
+
+static int fast_timer_running = 0;
+static int fast_timers_added = 0;
+static int fast_timers_started = 0;
+static int fast_timers_expired = 0;
+static int fast_timers_deleted = 0;
+static int fast_timer_is_init = 0;
+static int fast_timer_ints = 0;
+
+static struct fast_timer *fast_timer_list = NULL;
+
+#ifdef DEBUG_LOG_INCLUDED
+#define DEBUG_LOG_MAX 128
+static const char * debug_log_string[DEBUG_LOG_MAX];
+static unsigned long debug_log_value[DEBUG_LOG_MAX];
+static int debug_log_cnt = 0;
+static int debug_log_cnt_wrapped = 0;
+
+#define DEBUG_LOG(string, value) \
+{ \
+  unsigned long log_flags; \
+  save_flags(log_flags); \
+  cli(); \
+  debug_log_string[debug_log_cnt] = (string); \
+  debug_log_value[debug_log_cnt] = (unsigned long)(value); \
+  if (++debug_log_cnt >= DEBUG_LOG_MAX) \
+  { \
+    debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \
+    debug_log_cnt_wrapped = 1; \
+  } \
+  restore_flags(log_flags); \
+}
+#else
+#define DEBUG_LOG(string, value)
+#endif
+
+
+/* The frequencies for index = clkselx number in R_TIMER_CTRL */
+#define NUM_TIMER_FREQ 15
+#define MAX_USABLE_TIMER_FREQ 7
+#define MAX_DELAY_US  853333L
+const unsigned long timer_freq_100[NUM_TIMER_FREQ] =
+{
+  3,   /* 0 3333 - 853333 us */
+  6,   /* 1 1666 - 426666 us */
+  12,  /* 2  833 - 213333 us */
+  24,  /* 3  416 - 106666 us */
+  48,  /* 4  208 -  53333 us */
+  96,  /* 5  104 -  26666 us */
+  192, /* 6   52 -  13333 us */
+  384, /* 7   26 -   6666 us */
+  576,
+  1152,
+  2304,
+  4608,
+  9216,
+  18432,
+  62500,
+  /* 15 = cascade */
+};
+#define NUM_TIMER_STATS 16
+#ifdef FAST_TIMER_LOG
+struct fast_timer timer_added_log[NUM_TIMER_STATS];
+struct fast_timer timer_started_log[NUM_TIMER_STATS];
+struct fast_timer timer_expired_log[NUM_TIMER_STATS];
+#endif
+
+int timer_div_settings[NUM_TIMER_STATS];
+int timer_freq_settings[NUM_TIMER_STATS];
+int timer_delay_settings[NUM_TIMER_STATS];
+
+/* Not true gettimeofday, only checks the jiffies (uptime) + useconds */
+void __INLINE__ do_gettimeofday_fast(struct timeval *tv)
+{
+  unsigned long sec = jiffies;
+  unsigned long usec = GET_JIFFIES_USEC();
+
+  usec += (sec % HZ) * (1000000 / HZ);
+  sec = sec / HZ;
+
+  if (usec > 1000000)
+  {
+    usec -= 1000000;
+    sec++;
+  }
+  tv->tv_sec = sec;
+  tv->tv_usec = usec;
+}
+
+int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1)
+{
+  if (t0->tv_sec < t1->tv_sec)
+  {
+    return -1;
+  }
+  else if (t0->tv_sec > t1->tv_sec)
+  {
+    return 1;
+  }
+  if (t0->tv_usec < t1->tv_usec)
+  {
+    return -1;
+  }
+  else if (t0->tv_usec > t1->tv_usec)
+  {
+    return 1;
+  }
+  return 0;
+}
+
+void __INLINE__ start_timer1(unsigned long delay_us)
+{
+  int freq_index = 0; /* This is the lowest resolution */
+  unsigned long upper_limit = MAX_DELAY_US;
+
+  unsigned long div;
+  /* Start/Restart the timer to the new shorter value */
+  /* t = 1/freq = 1/19200 = 53us
+   * T=div*t,  div = T/t = delay_us*freq/1000000
+   */
+#if 1 /* Adaptive timer settings */
+  while (delay_us < upper_limit && freq_index < MAX_USABLE_TIMER_FREQ)
+  {
+    freq_index++;
+    upper_limit >>= 1; /* Divide by 2 using shift */
+  }
+  if (freq_index > 0)
+  {
+    freq_index--;
+  }
+#else
+  freq_index = 6;
+#endif
+  div = delay_us * timer_freq_100[freq_index]/10000;
+  if (div < 2)
+  {
+    /* Maybe increase timer freq? */
+    div = 2;
+  }
+  if (div > 255)
+  {
+    div = 0; /* This means 256, the max the timer takes */
+    /* If a longer timeout than the timer can handle is used,
+     * then we must restart it when it goes off.
+     */
+  }
+
+  timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = div;
+  timer_freq_settings[fast_timers_started % NUM_TIMER_STATS] = freq_index;
+  timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us;
+
+  D1(printk("start_timer1 : %d us freq: %i div: %i\n",
+            delay_us, freq_index, div));
+  /* Clear timer1 irq */
+  *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr);
+
+  /* Set timer values */
+  *R_TIMER_CTRL = r_timer_ctrl_shadow =
+    (r_timer_ctrl_shadow &
+     ~IO_MASK(R_TIMER_CTRL, timerdiv1) &
+     ~IO_MASK(R_TIMER_CTRL, tm1) &
+     ~IO_MASK(R_TIMER_CTRL, clksel1)) |
+    IO_FIELD(R_TIMER_CTRL, timerdiv1, div) |
+    IO_STATE(R_TIMER_CTRL, tm1, stop_ld) |
+    IO_FIELD(R_TIMER_CTRL, clksel1, freq_index ); /* 6=c19k2Hz */
+
+  /* Ack interrupt */
+  *R_TIMER_CTRL =  r_timer_ctrl_shadow |
+    IO_STATE(R_TIMER_CTRL, i1, clr);
+
+  /* Start timer */
+  *R_TIMER_CTRL = r_timer_ctrl_shadow =
+    (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) |
+    IO_STATE(R_TIMER_CTRL, tm1, run);
+
+  /* Enable timer1 irq */
+  *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set);
+  fast_timers_started++;
+  fast_timer_running = 1;
+}
+
+/* In version 1.4 this function takes 27 - 50 us */
+void start_one_shot_timer(struct fast_timer *t,
+                          fast_timer_function_type *function,
+                          unsigned long data,
+                          unsigned long delay_us,
+                          const char *name)
+{
+  unsigned long flags;
+  struct fast_timer *tmp;
+
+  D1(printk("sft %s %d us\n", name, delay_us));
+
+  save_flags(flags);
+  cli();
+
+  do_gettimeofday_fast(&t->tv_set);
+  tmp = fast_timer_list;
+
+  SANITYCHECK({ /* Check so this is not in the list already... */
+    while (tmp != NULL)
+    {
+      if (tmp == t)
+      {
+        printk("timer name: %s data: 0x%08lX already in list!\n", name, data);
+        sanity_failed++;
+        return;
+      }
+      else
+      {
+        tmp = tmp->next;
+      }
+    }
+    tmp = fast_timer_list;
+  });
+
+  t->delay_us = delay_us;
+  t->function = function;
+  t->data = data;
+  t->name = name;
+
+  t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000;
+  t->tv_expires.tv_sec  = t->tv_set.tv_sec  + delay_us / 1000000;
+  if (t->tv_expires.tv_usec > 1000000)
+  {
+    t->tv_expires.tv_usec -= 1000000;
+    t->tv_expires.tv_sec++;
+  }
+#ifdef FAST_TIMER_LOG
+  timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t;
+#endif
+  fast_timers_added++;
+
+  /* Check if this should timeout before anything else */
+  if (tmp == NULL || timeval_cmp(&t->tv_expires, &tmp->tv_expires) < 0)
+  {
+    /* Put first in list and modify the timer value */
+    t->prev = NULL;
+    t->next = fast_timer_list;
+    if (fast_timer_list)
+    {
+      fast_timer_list->prev = t;
+    }
+    fast_timer_list = t;
+#ifdef FAST_TIMER_LOG
+    timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
+#endif
+    start_timer1(delay_us);
+  } else {
+    /* Put in correct place in list */
+    while (tmp->next &&
+           timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0)
+    {
+      tmp = tmp->next;
+    }
+    /* Insert t after tmp */
+    t->prev = tmp;
+    t->next = tmp->next;
+    if (tmp->next)
+    {
+      tmp->next->prev = t;
+    }
+    tmp->next = t;
+  }
+
+  D2(printk("start_one_shot_timer: %d us done\n", delay_us));
+
+  restore_flags(flags);
+} /* start_one_shot_timer */
+
+static inline int fast_timer_pending (const struct fast_timer * t)
+{
+  return (t->next != NULL) || (t->prev != NULL) || (t == fast_timer_list);
+}
+
+static inline int detach_fast_timer (struct fast_timer *t)
+{
+  struct fast_timer *next, *prev;
+  if (!fast_timer_pending(t))
+    return 0;
+  next = t->next;
+  prev = t->prev;
+  if (next)
+    next->prev = prev;
+  if (prev)
+    prev->next = next;
+  else
+    fast_timer_list = next;
+  fast_timers_deleted++;
+  return 1;
+}
+
+int del_fast_timer(struct fast_timer * t)
+{
+  unsigned long flags;
+  int ret;
+  
+  save_flags(flags);
+  cli();
+  ret = detach_fast_timer(t);
+  t->next = t->prev = NULL;
+  restore_flags(flags);
+  return ret;
+} /* del_fast_timer */
+
+
+/* Interrupt routines or functions called in interrupt context */
+
+/* Timer 1 interrupt handler */
+
+static void
+timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct fast_timer *t;
+  unsigned long flags;
+
+  save_flags(flags);
+  cli();
+
+  /* Clear timer1 irq */
+  *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr);
+
+  /* First stop timer, then ack interrupt */
+  /* Stop timer */
+  *R_TIMER_CTRL = r_timer_ctrl_shadow =
+    (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) |
+    IO_STATE(R_TIMER_CTRL, tm1, stop_ld);
+
+  /* Ack interrupt */
+  *R_TIMER_CTRL =  r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i1, clr);
+
+  fast_timer_running = 0;
+  fast_timer_ints++;
+
+  restore_flags(flags);
+
+  t = fast_timer_list;
+  while (t)
+  {
+    struct timeval tv;
+
+    /* Has it really expired? */
+    do_gettimeofday_fast(&tv);
+    D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec));
+
+    if (timeval_cmp(&t->tv_expires, &tv) <= 0)
+    {
+      /* Yes it has expired */
+#ifdef FAST_TIMER_LOG
+      timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t;
+#endif
+      fast_timers_expired++;
+
+      /* Remove this timer before call, since it may reuse the timer */
+      save_flags(flags);
+      cli();
+      if (t->prev)
+      {
+        t->prev->next = t->next;
+      }
+      else
+      {
+        fast_timer_list = t->next;
+      }
+      if (t->next)
+      {
+        t->next->prev = t->prev;
+      }
+      t->prev = NULL;
+      t->next = NULL;
+      restore_flags(flags);
+
+      if (t->function != NULL)
+      {
+        t->function(t->data);
+      }
+      else
+      {
+        DEBUG_LOG("!timer1 %i function==NULL!\n", fast_timer_ints);
+      }
+    }
+    else
+    {
+      /* Timer is to early, let's set it again using the normal routines */
+      D1(printk(".\n"));
+    }
+
+    save_flags(flags);
+    cli();
+    if ((t = fast_timer_list) != NULL)
+    {
+      /* Start next timer.. */
+      long us;
+      struct timeval tv;
+
+      do_gettimeofday_fast(&tv);
+      us = ((t->tv_expires.tv_sec - tv.tv_sec) * 1000000 +
+            t->tv_expires.tv_usec - tv.tv_usec);
+      if (us > 0)
+      {
+        if (!fast_timer_running)
+        {
+#ifdef FAST_TIMER_LOG
+          timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
+#endif
+          start_timer1(us);
+        }
+        restore_flags(flags);
+        break;
+      }
+      else
+      {
+        /* Timer already expired, let's handle it better late than never.
+         * The normal loop handles it
+         */
+        D1(printk("e! %d\n", us));
+      }
+    }
+    restore_flags(flags);
+  }
+
+  if (!t)
+  {
+    D1(printk("t1 stop!\n"));
+  }
+}
+
+static void wake_up_func(unsigned long data)
+{
+#ifdef DECLARE_WAITQUEUE
+  wait_queue_head_t  *sleep_wait_p = (wait_queue_head_t*)data;
+#else
+  struct wait_queue **sleep_wait_p = (struct wait_queue **)data;
+#endif
+  wake_up(sleep_wait_p);
+}
+
+
+/* Useful API */
+
+void schedule_usleep(unsigned long us)
+{
+  struct fast_timer t;
+#ifdef DECLARE_WAITQUEUE
+  wait_queue_head_t sleep_wait;
+  DECLARE_WAITQUEUE(wait, current);
+#else
+  struct wait_queue *sleep_wait = NULL;
+  struct wait_queue wait = { current, NULL };
+#endif
+
+  D1(printk("schedule_usleep(%d)\n", us));
+  add_wait_queue(&sleep_wait, &wait);
+  set_current_state(TASK_INTERRUPTIBLE);
+  start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us,
+                       "usleep");
+  schedule();
+  set_current_state(TASK_RUNNING);
+  remove_wait_queue(&sleep_wait, &wait);
+  D1(printk("done schedule_usleep(%d)\n", us));
+}
+
+#ifdef CONFIG_PROC_FS
+static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+                       ,int *eof, void *data_unused
+#else
+                        ,int unused
+#endif
+                               );
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+static struct proc_dir_entry *fasttimer_proc_entry;
+#else
+static struct proc_dir_entry fasttimer_proc_entry =
+{
+  0, 9, "fasttimer",
+  S_IFREG | S_IRUGO, 1, 0, 0,
+  0, NULL /* ops -- default to array */,
+  &proc_fasttimer_read /* get_info */,
+};
+#endif
+#endif /* CONFIG_PROC_FS */
+
+#ifdef CONFIG_PROC_FS
+
+/* This value is very much based on testing */
+#define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300)
+
+static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+                       ,int *eof, void *data_unused
+#else
+                        ,int unused
+#endif
+                               )
+{
+  unsigned long flags;
+  int i = 0;
+  int num_to_show;
+  struct timeval tv;
+  struct fast_timer *t, *nextt;
+  static char *bigbuf = NULL;
+  static unsigned long used;
+
+  if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE)))
+  {
+    used = 0;
+    bigbuf[0] = '\0';
+    return 0;
+  }
+
+  if (!offset || !used)
+  {
+    do_gettimeofday_fast(&tv);
+
+    used = 0;
+    used += sprintf(bigbuf + used, "Fast timers added:     %i\n",
+                    fast_timers_added);
+    used += sprintf(bigbuf + used, "Fast timers started:   %i\n",
+                    fast_timers_started);
+    used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n",
+                    fast_timer_ints);
+    used += sprintf(bigbuf + used, "Fast timers expired:   %i\n",
+                    fast_timers_expired);
+    used += sprintf(bigbuf + used, "Fast timers deleted:   %i\n",
+                    fast_timers_deleted);
+    used += sprintf(bigbuf + used, "Fast timer running:    %s\n",
+                    fast_timer_running ? "yes" : "no");
+    used += sprintf(bigbuf + used, "Current time:          %lu.%06lu\n",
+                    (unsigned long)tv.tv_sec,
+                    (unsigned long)tv.tv_usec);
+#ifdef FAST_TIMER_SANITY_CHECKS
+    used += sprintf(bigbuf + used, "Sanity failed:         %i\n",
+                    sanity_failed);
+#endif
+    used += sprintf(bigbuf + used, "\n");
+
+#ifdef DEBUG_LOG_INCLUDED
+    {
+      int end_i = debug_log_cnt;
+      i = 0;
+
+      if (debug_log_cnt_wrapped)
+      {
+        i = debug_log_cnt;
+      }
+
+      while ((i != end_i || (debug_log_cnt_wrapped && !used)) &&
+             used+100 < BIG_BUF_SIZE)
+      {
+        used += sprintf(bigbuf + used, debug_log_string[i],
+                        debug_log_value[i]);
+        i = (i+1) % DEBUG_LOG_MAX;
+      }
+    }
+    used += sprintf(bigbuf + used, "\n");
+#endif
+
+    num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started:
+                   NUM_TIMER_STATS);
+    used += sprintf(bigbuf + used, "Timers started: %i\n", fast_timers_started);
+    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++)
+    {
+      int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS;
+
+#if 1 //ndef FAST_TIMER_LOG
+      used += sprintf(bigbuf + used, "div: %i freq: %i delay: %i"
+                      "\n",
+                      timer_div_settings[cur],
+                      timer_freq_settings[cur],
+                      timer_delay_settings[cur]
+                      );
+#endif
+#ifdef FAST_TIMER_LOG
+      t = &timer_started_log[cur];
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+                      );
+#endif
+    }
+    used += sprintf(bigbuf + used, "\n");
+
+#ifdef FAST_TIMER_LOG
+    num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added:
+                   NUM_TIMER_STATS);
+    used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added);
+    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
+    {
+      t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS];
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+                      );
+    }
+    used += sprintf(bigbuf + used, "\n");
+
+    num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired:
+                   NUM_TIMER_STATS);
+    used += sprintf(bigbuf + used, "Timers expired: %i\n", fast_timers_expired);
+    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
+    {
+      t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS];
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+                      );
+    }
+    used += sprintf(bigbuf + used, "\n");
+#endif
+
+    used += sprintf(bigbuf + used, "Active timers:\n");
+    save_flags(flags);
+    cli();
+    t = fast_timer_list;
+    while (t != NULL && (used+100 < BIG_BUF_SIZE))
+    {
+      nextt = t->next;
+      restore_flags(flags);
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+/*                      " func: 0x%08lX" */
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+/*                      , t->function */
+                      );
+      cli();
+      if (t->next != nextt)
+      {
+        printk("timer removed!\n");
+      }
+      t = nextt;
+    }
+    restore_flags(flags);
+  }
+
+  if (used - offset < len)
+  {
+    len = used - offset;
+  }
+
+  memcpy(buf, bigbuf + offset, len);
+  *start = buf;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+  *eof = 1;
+#endif
+
+  return len;
+}
+#endif /* PROC_FS */
+
+#ifdef FAST_TIMER_TEST
+static volatile unsigned long i = 0;
+static volatile int num_test_timeout = 0;
+static struct fast_timer tr[10];
+static int exp_num[10];
+
+static struct timeval tv_exp[100];
+
+static void test_timeout(unsigned long data)
+{
+  do_gettimeofday_fast(&tv_exp[data]);
+  exp_num[data] = num_test_timeout;
+
+  num_test_timeout++;
+}
+
+static void test_timeout1(unsigned long data)
+{
+  do_gettimeofday_fast(&tv_exp[data]);
+  exp_num[data] = num_test_timeout;
+  if (data < 7)
+  {
+    start_one_shot_timer(&tr[i], test_timeout1, i, 1000, "timeout1");
+    i++;
+  }
+  num_test_timeout++;
+}
+
+DP(
+static char buf0[2000];
+static char buf1[2000];
+static char buf2[2000];
+static char buf3[2000];
+static char buf4[2000];
+);
+
+static char buf5[6000];
+static int j_u[1000];
+
+static void fast_timer_test(void)
+{
+  int prev_num;
+  int j;
+
+  struct timeval tv, tv0, tv1, tv2;
+
+  printk("fast_timer_test() start\n");
+  do_gettimeofday_fast(&tv);
+
+  for (j = 0; j < 1000; j++)
+  {
+    j_u[j] = GET_JIFFIES_USEC();
+  }
+  for (j = 0; j < 100; j++)
+  {
+    do_gettimeofday_fast(&tv_exp[j]);
+  }
+  printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec);
+
+  for (j = 0; j < 1000; j++)
+  {
+    printk("%i %i %i %i %i\n",j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]);
+    j += 4;
+  }
+  for (j = 0; j < 100; j++)
+  {
+    printk("%i.%i %i.%i %i.%i %i.%i %i.%i\n",
+           tv_exp[j].tv_sec,tv_exp[j].tv_usec,
+           tv_exp[j+1].tv_sec,tv_exp[j+1].tv_usec,
+           tv_exp[j+2].tv_sec,tv_exp[j+2].tv_usec,
+           tv_exp[j+3].tv_sec,tv_exp[j+3].tv_usec,
+           tv_exp[j+4].tv_sec,tv_exp[j+4].tv_usec);
+    j += 4;
+  }
+  do_gettimeofday_fast(&tv0);
+  start_one_shot_timer(&tr[i], test_timeout, i, 50000, "test0");
+  DP(proc_fasttimer_read(buf0, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout, i, 70000, "test1");
+  DP(proc_fasttimer_read(buf1, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout, i, 40000, "test2");
+  DP(proc_fasttimer_read(buf2, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout, i, 60000, "test3");
+  DP(proc_fasttimer_read(buf3, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout1, i, 55000, "test4xx");
+  DP(proc_fasttimer_read(buf4, NULL, 0, 0, 0));
+  i++;
+  do_gettimeofday_fast(&tv1);
+
+  proc_fasttimer_read(buf5, NULL, 0, 0, 0);
+
+  prev_num = num_test_timeout;
+  while (num_test_timeout < i)
+  {
+    if (num_test_timeout != prev_num)
+    {
+      prev_num = num_test_timeout;
+    }
+  }
+  do_gettimeofday_fast(&tv2);
+  printk("Timers started    %is %06i\n", tv0.tv_sec, tv0.tv_usec);
+  printk("Timers started at %is %06i\n", tv1.tv_sec, tv1.tv_usec);
+  printk("Timers done       %is %06i\n", tv2.tv_sec, tv2.tv_usec);
+  DP(printk("buf0:\n");
+     printk(buf0);
+     printk("buf1:\n");
+     printk(buf1);
+     printk("buf2:\n");
+     printk(buf2);
+     printk("buf3:\n");
+     printk(buf3);
+     printk("buf4:\n");
+     printk(buf4);
+  );
+  printk("buf5:\n");
+  printk(buf5);
+
+  printk("timers set:\n");
+  for(j = 0; j<i; j++)
+  {
+    struct fast_timer *t = &tr[j];
+    printk("%-10s set: %6is %06ius exp: %6is %06ius "
+           "data: 0x%08X func: 0x%08X\n",
+           t->name,
+           t->tv_set.tv_sec,
+           t->tv_set.tv_usec,
+           t->tv_expires.tv_sec,
+           t->tv_expires.tv_usec,
+           t->data,
+           t->function
+           );
+
+    printk("           del: %6ius     did exp: %6is %06ius as #%i error: %6li\n",
+           t->delay_us,
+           tv_exp[j].tv_sec,
+           tv_exp[j].tv_usec,
+           exp_num[j],
+           (tv_exp[j].tv_sec - t->tv_expires.tv_sec)*1000000 + tv_exp[j].tv_usec - t->tv_expires.tv_usec);
+  }
+  proc_fasttimer_read(buf5, NULL, 0, 0, 0);
+  printk("buf5 after all done:\n");
+  printk(buf5);
+  printk("fast_timer_test() done\n");
+}
+#endif
+
+
+void fast_timer_init(void)
+{
+  /* For some reason, request_irq() hangs when called froom time_init() */
+  if (!fast_timer_is_init)
+  {
+#if 0 && defined(FAST_TIMER_TEST)
+    int i;
+#endif
+
+    printk("fast_timer_init()\n");
+
+#if 0 && defined(FAST_TIMER_TEST)
+    for (i = 0; i <= TIMER0_DIV; i++)
+    {
+      /* We must be careful not to get overflow... */
+      printk("%3i %6u\n", i, timer0_value_us[i]);
+    }
+#endif
+#ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+   if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 )))
+     fasttimer_proc_entry->read_proc = proc_fasttimer_read;
+#else
+    proc_register_dynamic(&proc_root, &fasttimer_proc_entry);
+#endif
+#endif /* PROC_FS */
+    if(request_irq(TIMER1_IRQ_NBR, timer1_handler, SA_SHIRQ,
+                   "fast timer int", NULL))
+    {
+      printk("err: timer1 irq\n");
+    }
+    fast_timer_is_init = 1;
+#ifdef FAST_TIMER_TEST
+    printk("do test\n");
+    fast_timer_test();
+#endif
+  }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/kernel/kgdb.c linux-2.4.20/arch/cris/kernel/kgdb.c
--- linux-2.4.19/arch/cris/kernel/kgdb.c	2001-11-09 21:58:02.000000000 +0000
+++ linux-2.4.20/arch/cris/kernel/kgdb.c	2002-10-29 11:18:50.000000000 +0000
@@ -18,6 +18,9 @@
 *! Jul 21 1999  Bjorn Wesen     eLinux port
 *!
 *! $Log: kgdb.c,v $
+*! Revision 1.7  2002/07/12 09:14:56  bjornw
+*! Corrected typo
+*!
 *! Revision 1.6  2001/10/09 13:10:03  matsfg
 *! Added $ on registers and removed some underscores
 *!
@@ -55,7 +58,7 @@
 *!
 *!---------------------------------------------------------------------------
 *!
-*! $Id: kgdb.c,v 1.6 2001/10/09 13:10:03 matsfg Exp $
+*! $Id: kgdb.c,v 1.7 2002/07/12 09:14:56 bjornw Exp $
 *!
 *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN
 *!
@@ -1064,7 +1067,7 @@
 					int regno = gdb_cris_strtol (&remcomInBuffer[1], &suffix, 16);
 					int status;
 #ifdef PROCESS_SUPPORT
-					if (current_thread_g =! executing_task)
+					if (current_thread_g != executing_task)
 						status = write_stack_register (current_thread_g, regno, suffix+1);
 					else
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/kernel/setup.c linux-2.4.20/arch/cris/kernel/setup.c
--- linux-2.4.19/arch/cris/kernel/setup.c	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.20/arch/cris/kernel/setup.c	2002-10-29 11:18:49.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.24 2001/12/07 17:03:19 bjornw Exp $
+/* $Id: setup.c,v 1.26 2002/06/04 07:57:56 jonashg Exp $
  *
  *  linux/arch/cris/kernel/setup.c
  *
@@ -169,20 +169,18 @@
 
 	*cmdline_p = command_line;
 
-	if (romfs_in_flash) {
-		strncpy(command_line, "root=", COMMAND_LINE_SIZE);
-		strncpy(command_line+5, CONFIG_ETRAX_ROOT_DEVICE,
+	strncpy(command_line, "root=", COMMAND_LINE_SIZE);
+	strncpy(command_line+5, CONFIG_ETRAX_ROOT_DEVICE,
 			COMMAND_LINE_SIZE-5);
 
-		/* Save command line copy for /proc/cmdline */
-
-		memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
-		saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
-	}
+	/* Save command line copy for /proc/cmdline */
+	
+	memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
+	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
 
 	/* give credit for the CRIS port */
 
-	printk("Linux/CRIS port on ETRAX 100LX (c) 2001 Axis Communications AB\n");
+	printk("Linux/CRIS port on ETRAX 100LX (c) 2001, 2002 Axis Communications AB\n");
 
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/kernel/traps.c linux-2.4.20/arch/cris/kernel/traps.c
--- linux-2.4.19/arch/cris/kernel/traps.c	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.20/arch/cris/kernel/traps.c	2002-10-29 11:18:49.000000000 +0000
@@ -230,8 +230,12 @@
 #endif	
 }
 
-/* This is normally the 'Oops' routine */
+void dump_stack(void)
+{
+	show_stack(NULL);
+}
 
+/* This is normally the 'Oops' routine */
 void 
 die_if_kernel(const char * str, struct pt_regs * regs, long err)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/lib/dram_init.S linux-2.4.20/arch/cris/lib/dram_init.S
--- linux-2.4.19/arch/cris/lib/dram_init.S	2001-10-08 18:43:54.000000000 +0000
+++ linux-2.4.20/arch/cris/lib/dram_init.S	2002-10-29 11:18:36.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: dram_init.S,v 1.10 2001/10/04 12:00:21 martinnn Exp $
+/* $Id: dram_init.S,v 1.12 2002/08/09 11:37:37 orjanf Exp $
  * 
  * DRAM/SDRAM initialization - alter with care
  * This file is intended to be included from other assembler files
@@ -11,6 +11,12 @@
  * Authors:  Mikael Starvik (starvik@axis.com)	
  * 
  * $Log: dram_init.S,v $
+ * Revision 1.12  2002/08/09 11:37:37  orjanf
+ * Added double initialization work-around for Samsung SDRAMs.
+ *
+ * Revision 1.11  2002/06/04 11:43:21  starvik
+ * Check if mrs_data is specified in kernelconfig (necessary for MCM)
+ *
  * Revision 1.10  2001/10/04 12:00:21  martinnn
  * Added missing underscores.
  *
@@ -70,7 +76,11 @@
 
 	move.d   CONFIG_ETRAX_DEF_R_DRAM_TIMING, $r0
 	move.d   $r0, [R_DRAM_TIMING]
-#else	
+#else
+	;; Samsung SDRAMs seem to require to be initialized twice to work properly.
+	moveq    2, $r6	
+_sdram_init:
+	
 	; Refer to ETRAX 100LX Designers Reference for a description of SDRAM initialization
 	
 	; Bank configuration
@@ -82,6 +92,12 @@
 	; CAS latency = 3 && bus_width = 32 => 0x60
 	; CAS latency = 2 && bus_width = 16 => 0x20
 	; CAS latency = 3 && bus_width = 16 => 0x30
+
+	; Check if value is already supplied in kernel config
+	move.d   CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r2
+	and.d    0x00ff0000, $r2
+	bne	 _set_timing
+	lsrq     16, $r2
 	
 	move.d   0x40, $r2       ; Assume 32 bits and CAS latency = 2
 	move.d   CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r1
@@ -142,6 +158,9 @@
 	bne      1b
 	nop
 	move.d   $r5, [R_SDRAM_TIMING]
+	subq     1, $r6
+	bne      _sdram_init
+	nop
 	ba       _sdram_commands_end
 	nop
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/lib/hw_settings.S linux-2.4.20/arch/cris/lib/hw_settings.S
--- linux-2.4.19/arch/cris/lib/hw_settings.S	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.20/arch/cris/lib/hw_settings.S	2002-10-29 11:18:40.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * $Id: hw_settings.S,v 1.3 2001/04/21 17:02:46 bjornw Exp $
+ * $Id: hw_settings.S,v 1.4 2002/07/04 16:58:56 pkj Exp $
  * 
  * This table is used by some tools to extract hardware parameters.
  * The table should be included in the kernel and the decompressor.
@@ -16,8 +16,8 @@
 		(CONFIG_ETRAX_DEF_R_PORT_PB_DIR << 8) | \
 		(CONFIG_ETRAX_DEF_R_PORT_PB_DATA))
 	
-	.ascii "HW_PARAM_MAGIC" ; Magic number
-	.dword 0xc0004000	; Kernel start address
+	.ascii "HW_PARAM_MAGIC"					; Magic number
+	.dword CONFIG_ETRAX_DRAM_VIRTUAL_BASE | 0x80004000	; Kernel start address
 
 	; Debug port
 #ifdef CONFIG_ETRAX_DEBUG_PORT0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/cris/mm/fault.c linux-2.4.20/arch/cris/mm/fault.c
--- linux-2.4.19/arch/cris/mm/fault.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/cris/mm/fault.c	2002-10-29 11:18:36.000000000 +0000
@@ -6,6 +6,9 @@
  *  Authors:  Bjorn Wesen 
  * 
  *  $Log: fault.c,v $
+ *  Revision 1.21  2002/05/28 14:24:56  bjornw
+ *  Corrected typo
+ *
  *  Revision 1.20  2001/11/22 13:34:06  bjornw
  *  * Bug workaround (LX TR89): force a rerun of the whole of an interrupted
  *    unaligned write, because the second half of the write will be corrupted
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/Makefile linux-2.4.20/arch/i386/Makefile
--- linux-2.4.19/arch/i386/Makefile	2001-04-12 19:20:31.000000000 +0000
+++ linux-2.4.20/arch/i386/Makefile	2002-10-29 11:18:37.000000000 +0000
@@ -83,7 +83,7 @@
 endif
 
 ifdef CONFIG_MCYRIXIII
-CFLAGS += -march=i586
+CFLAGS += -march=i486 -malign-functions=0 -malign-jumps=0 -malign-loops=0
 endif
 
 HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/boot/compressed/misc.c linux-2.4.20/arch/i386/boot/compressed/misc.c
--- linux-2.4.19/arch/i386/boot/compressed/misc.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/boot/compressed/misc.c	2002-10-29 11:18:48.000000000 +0000
@@ -9,6 +9,8 @@
  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  */
 
+#define STANDALONE
+
 #include <linux/linkage.h>
 #include <linux/vmalloc.h>
 #include <linux/tty.h>
@@ -124,10 +126,6 @@
 static int vidport;
 static int lines, cols;
 
-#ifdef CONFIG_MULTIQUAD
-static void * const xquad_portio = NULL;
-#endif
-
 #include "../../../../lib/inflate.c"
 
 static void *malloc(int size)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/config.in linux-2.4.20/arch/i386/config.in
--- linux-2.4.19/arch/i386/config.in	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/config.in	2002-10-29 11:18:36.000000000 +0000
@@ -5,7 +5,6 @@
 mainmenu_name "Linux Kernel Configuration"
 
 define_bool CONFIG_X86 y
-define_bool CONFIG_ISA y
 define_bool CONFIG_SBUS n
 
 define_bool CONFIG_UID16 y
@@ -54,6 +53,7 @@
    define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
    define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
    define_bool CONFIG_X86_PPRO_FENCE y
+   define_bool CONFIG_X86_F00F_WORKS_OK n
 else
    define_bool CONFIG_X86_WP_WORKS_OK y
    define_bool CONFIG_X86_INVLPG y
@@ -69,99 +69,112 @@
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_PPRO_FENCE y
+   define_bool CONFIG_X86_F00F_WORKS_OK n
 fi
 if [ "$CONFIG_M586" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_PPRO_FENCE y
+   define_bool CONFIG_X86_F00F_WORKS_OK n
 fi
 if [ "$CONFIG_M586TSC" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
-   define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_PPRO_FENCE y
+   define_bool CONFIG_X86_F00F_WORKS_OK n
 fi
 if [ "$CONFIG_M586MMX" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
-   define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_PPRO_FENCE y
+   define_bool CONFIG_X86_F00F_WORKS_OK n
 fi
 if [ "$CONFIG_M686" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
-   define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
    define_bool CONFIG_X86_PPRO_FENCE y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MPENTIUMIII" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
-   define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MPENTIUM4" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 7
-   define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MK6" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_ALIGNMENT_16 y
-   define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
 if [ "$CONFIG_MK7" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 6
-   define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_USE_3DNOW y
    define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MELAN" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 4
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MCYRIXIII" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
-   define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_USE_3DNOW y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
 if [ "$CONFIG_MCRUSOE" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
-   define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_HAS_TSC y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MWINCHIPC6" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
    define_bool CONFIG_X86_OOSTORE y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MWINCHIP2" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_ALIGNMENT_16 y
-   define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
    define_bool CONFIG_X86_OOSTORE y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MWINCHIP3D" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_ALIGNMENT_16 y
-   define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
    define_bool CONFIG_X86_OOSTORE y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 
 bool 'Machine Check Exception' CONFIG_X86_MCE
@@ -177,14 +190,19 @@
 	"off    CONFIG_NOHIGHMEM \
 	 4GB    CONFIG_HIGHMEM4G \
 	 64GB   CONFIG_HIGHMEM64G" off
-if [ "$CONFIG_HIGHMEM4G" = "y" ]; then
+if [ "$CONFIG_HIGHMEM4G" = "y" -o "$CONFIG_HIGHMEM64G" = "y" ]; then
    define_bool CONFIG_HIGHMEM y
+else
+   define_bool CONFIG_HIGHMEM n
 fi
 if [ "$CONFIG_HIGHMEM64G" = "y" ]; then
-   define_bool CONFIG_HIGHMEM y
    define_bool CONFIG_X86_PAE y
 fi
 
+if [ "$CONFIG_HIGHMEM" = "y" ]; then
+   bool 'HIGHMEM I/O support' CONFIG_HIGHIO
+fi
+
 bool 'Math emulation' CONFIG_MATH_EMULATION
 bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
 bool 'Symmetric multi-processing support' CONFIG_SMP
@@ -201,6 +219,11 @@
    bool 'Multiquad NUMA system' CONFIG_MULTIQUAD
 fi
 
+bool 'Unsynced TSC support' CONFIG_X86_TSC_DISABLE
+if [ "$CONFIG_X86_TSC_DISABLE" != "y" -a "$CONFIG_X86_HAS_TSC" = "y" ]; then
+   define_bool CONFIG_X86_TSC y
+fi
+
 if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
    define_bool CONFIG_HAVE_DEC_LOCK y
 fi
@@ -218,6 +241,7 @@
    define_bool CONFIG_X86_VISWS_APIC y
    define_bool CONFIG_X86_LOCAL_APIC y
    define_bool CONFIG_PCI y
+   define_bool CONFIG_ISA n
 else
    if [ "$CONFIG_SMP" = "y" ]; then
       define_bool CONFIG_X86_IO_APIC y
@@ -236,6 +260,7 @@
          define_bool CONFIG_PCI_DIRECT y
       fi
    fi
+   bool 'ISA bus support' CONFIG_ISA
 fi
 
 source drivers/pci/Config.in
@@ -366,14 +391,16 @@
 fi
 endmenu
 
-mainmenu_option next_comment
-comment 'Old CD-ROM drivers (not SCSI, not IDE)'
-
-bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
-if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
-   source drivers/cdrom/Config.in
+if [ "$CONFIG_ISA" = "y" ]; then
+    mainmenu_option next_comment
+    comment 'Old CD-ROM drivers (not SCSI, not IDE)'
+
+    bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
+    if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
+       source drivers/cdrom/Config.in
+    fi
+    endmenu
 fi
-endmenu
 
 #
 # input before char - char/joystick depends on it. As does USB.
@@ -417,6 +444,7 @@
 
 bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
 if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
+   bool '  Check for stack overflows' CONFIG_DEBUG_STACKOVERFLOW
    bool '  Debug high memory support' CONFIG_DEBUG_HIGHMEM
    bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
    bool '  Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
@@ -426,3 +454,5 @@
 fi
 
 endmenu
+
+source lib/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/defconfig linux-2.4.20/arch/i386/defconfig
--- linux-2.4.19/arch/i386/defconfig	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/defconfig	2002-10-29 11:18:33.000000000 +0000
@@ -617,7 +617,8 @@
 CONFIG_DRM_TDFX=y
 # CONFIG_DRM_R128 is not set
 CONFIG_DRM_RADEON=y
-# CONFIG_DRM_I810 is not set
+CONFIG_DRM_I810=y
+CONFIG_DRM_I810_XFREE_41=y
 # CONFIG_DRM_MGA is not set
 # CONFIG_DRM_SIS is not set
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/Makefile linux-2.4.20/arch/i386/kernel/Makefile
--- linux-2.4.19/arch/i386/kernel/Makefile	2001-11-09 22:21:21.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/Makefile	2002-10-29 11:18:34.000000000 +0000
@@ -14,7 +14,7 @@
 
 O_TARGET := kernel.o
 
-export-objs     := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o
+export-objs     := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o time.o
 
 obj-y	:= process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
 		ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/apic.c linux-2.4.20/arch/i386/kernel/apic.c
--- linux-2.4.19/arch/i386/kernel/apic.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/apic.c	2002-10-29 11:18:40.000000000 +0000
@@ -29,6 +29,7 @@
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
 #include <asm/pgalloc.h>
+#include <asm/smpboot.h>
 
 /* Using APIC to generate smp_local_timer_interrupt? */
 int using_apic_timer = 0;
@@ -291,14 +292,13 @@
 	 * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
 	 * document number 292116).  So here it goes...
 	 */
-
-	if (!clustered_apic_mode) {
+	if (clustered_apic_mode != CLUSTERED_APIC_NUMAQ) {
 		/*
-		 * In clustered apic mode, the firmware does this for us 
-		 * Put the APIC into flat delivery mode.
-		 * Must be "all ones" explicitly for 82489DX.
+		 * For NUMA-Q (clustered apic logical), the firmware does this
+		 * for us. Otherwise put the APIC into clustered or flat
+		 * delivery mode. Must be "all ones" explicitly for 82489DX.
 		 */
-		apic_write_around(APIC_DFR, 0xffffffff);
+		apic_write_around(APIC_DFR, APIC_DFR_FLAT);
 
 		/*
 		 * Set up the logical destination ID.
@@ -1050,7 +1050,7 @@
 /*
  * Local APIC timer interrupt. This is the most natural way for doing
  * local interrupts, but local timer interrupts can be emulated by
- * broadcast interrupts too. [in case the hw doesnt support APIC timers]
+ * broadcast interrupts too. [in case the hw doesn't support APIC timers]
  *
  * [ if a single-CPU system runs an SMP kernel then we call the local
  *   interrupt as well. Thus we cannot inline the local irq ... ]
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/apm.c linux-2.4.20/arch/i386/kernel/apm.c
--- linux-2.4.19/arch/i386/kernel/apm.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/apm.c	2002-10-29 11:18:32.000000000 +0000
@@ -847,6 +847,7 @@
 			case 1: apm_idle_done = 1;
 				break;
 			default: /* BIOS refused */
+				break;
 			}
 		}
 		if (original_pm_idle)
@@ -862,14 +863,6 @@
 		apm_do_busy();
 }
 
-#ifdef CONFIG_SMP
-static int apm_magic(void * unused)
-{
-	while (1)
-		schedule();
-}
-#endif
-
 /**
  *	apm_power_off	-	ask the BIOS to power off
  *
@@ -897,10 +890,11 @@
 	 */
 #ifdef CONFIG_SMP
 	/* Some bioses don't like being called from CPU != 0 */
-	while (cpu_number_map(smp_processor_id()) != 0) {
-		kernel_thread(apm_magic, NULL,
-			CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
+	if (cpu_number_map(smp_processor_id()) != 0) {
+		current->cpus_allowed = 1;
 		schedule();
+		if (unlikely(cpu_number_map(smp_processor_id()) != 0))
+			BUG();
 	}
 #endif
 	if (apm_info.realmode_power_off)
@@ -1661,6 +1655,21 @@
 	strcpy(current->comm, "kapmd");
 	sigfillset(&current->blocked);
 
+#ifdef CONFIG_SMP
+	/* 2002/08/01 - WT
+	 * This is to avoid random crashes at boot time during initialization
+	 * on SMP systems in case of "apm=power-off" mode. Seen on ASUS A7M266D.
+	 * Some bioses don't like being called from CPU != 0.
+	 * Method suggested by Ingo Molnar.
+	 */
+	if (cpu_number_map(smp_processor_id()) != 0) {
+		current->cpus_allowed = 1;
+		schedule();
+		if (unlikely(cpu_number_map(smp_processor_id()) != 0))
+			BUG();
+	}
+#endif
+	
 	if (apm_info.connection_version == 0) {
 		apm_info.connection_version = apm_info.bios.version;
 		if (apm_info.connection_version > 0x100) {
@@ -1707,7 +1716,7 @@
 		}
 	}
 
-	if (debug && (smp_num_cpus == 1)) {
+	if (debug) {
 		error = apm_get_power_status(&bx, &cx, &dx);
 		if (error)
 			printk(KERN_INFO "apm: power status not available\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/dmi_scan.c linux-2.4.20/arch/i386/kernel/dmi_scan.c
--- linux-2.4.19/arch/i386/kernel/dmi_scan.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/dmi_scan.c	2002-10-29 11:18:37.000000000 +0000
@@ -31,7 +31,7 @@
 	if(!s)
 		return "";
 	s--;
-	while(s>0)
+	while(s>0 && *bp)
 	{
 		bp+=strlen(bp);
 		bp++;
@@ -50,7 +50,7 @@
 	u8 *buf;
 	struct dmi_header *dm;
 	u8 *data;
-	int i=1;
+	int i=0;
 		
 	buf = bt_ioremap(base, len);
 	if(buf==NULL)
@@ -59,28 +59,23 @@
 	data = buf;
 
 	/*
- 	 *	Stop when we see al the items the table claimed to have
+ 	 *	Stop when we see all the items the table claimed to have
  	 *	OR we run off the end of the table (also happens)
  	 */
  
-	while(i<num && (data - buf) < len)
+	while(i<num && data-buf+sizeof(struct dmi_header)<=len)
 	{
 		dm=(struct dmi_header *)data;
-	
 		/*
-		 *	Avoid misparsing crud if the length of the last
-	 	 *	record is crap 
+		 *  We want to know the total length (formated area and strings)
+		 *  before decoding to make sure we won't run off the table in
+		 *  dmi_decode or dmi_string
 		 */
-		if((data-buf+dm->length) >= len)
-			break;
-		decode(dm);		
 		data+=dm->length;
-		/*
-		 *	Don't go off the end of the data if there is
-	 	 *	stuff looking like string fill past the end
-	 	 */
-		while((data-buf) < len && (*data || data[1]))
+		while(data-buf<len-1 && (data[0] || data[1]))
 			data++;
+		if(data-buf<len-1)
+			decode(dm);
 		data+=2;
 		i++;
 	}
@@ -89,11 +84,20 @@
 }
 
 
+inline static int __init dmi_checksum(u8 *buf)
+{
+	u8 sum=0;
+	int a;
+	
+	for(a=0; a<15; a++)
+		sum+=buf[a];
+	return (sum==0);
+}
+
 static int __init dmi_iterate(void (*decode)(struct dmi_header *))
 {
-	unsigned char buf[20];
-	long fp=0xE0000L;
-	fp -= 16;
+	u8 buf[15];
+	u32 fp=0xF0000;
 
 #ifdef CONFIG_SIMNOW
 	/*
@@ -105,24 +109,30 @@
  	
 	while( fp < 0xFFFFF)
 	{
-		fp+=16;
-		isa_memcpy_fromio(buf, fp, 20);
-		if(memcmp(buf, "_DMI_", 5)==0)
+		isa_memcpy_fromio(buf, fp, 15);
+		if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
 		{
 			u16 num=buf[13]<<8|buf[12];
 			u16 len=buf[7]<<8|buf[6];
 			u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
 
-			dmi_printk((KERN_INFO "DMI %d.%d present.\n",
-				buf[14]>>4, buf[14]&0x0F));
+			/*
+			 * DMI version 0.0 means that the real version is taken from
+			 * the SMBIOS version, which we don't know at this point.
+			 */
+			if(buf[14]!=0)
+				dmi_printk((KERN_INFO "DMI %d.%d present.\n",
+					buf[14]>>4, buf[14]&0x0F));
+			else
+				dmi_printk((KERN_INFO "DMI present.\n"));
 			dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
-				buf[13]<<8|buf[12],
-				buf[7]<<8|buf[6]));
+				num, len));
 			dmi_printk((KERN_INFO "DMI table at 0x%08X.\n",
-				buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]));
+				base));
 			if(dmi_table(base,len, num, decode)==0)
 				return 0;
 		}
+		fp+=16;
 	}
 	return -1;
 }
@@ -190,7 +200,6 @@
  *	KT7 series. On these it seems the newer BIOS has fixed them. The
  *	rule needs to be improved to match specific BIOS revisions with
  *	corruption problems
- */ 
  
 static __init int disable_ide_dma(struct dmi_blacklist *d)
 {
@@ -204,6 +213,7 @@
 #endif	
 	return 0;
 }
+ */ 
 
 /* 
  * Reboot options and system auto-detection code provided by
@@ -475,6 +485,22 @@
 	return 0;
 }
 
+/*
+ * Work around broken HP Pavilion Notebooks which assign USB to
+ * IRQ 9 even though it is actually wired to IRQ 11
+ */
+static __init int fix_broken_hp_bios_irq9(struct dmi_blacklist *d)
+{
+#ifdef CONFIG_PCI
+	extern int broken_hp_bios_irq9;
+	if (broken_hp_bios_irq9 == 0)
+	{
+		broken_hp_bios_irq9 = 1;
+		printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident);
+	}
+#endif
+	return 0;
+}
 
 /*
  *	Simple "print if true" callback
@@ -564,6 +590,17 @@
 			MATCH(DMI_BIOS_VERSION, "Version1.01"),
 			NO_MATCH, NO_MATCH,
 			} },
+	{ apm_is_horked, "Intel D850MD", { /* APM crashes */
+			MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
+			MATCH(DMI_BIOS_VERSION, "MV85010A.86A.0016.P07.0201251536"),
+			NO_MATCH, NO_MATCH,
+			} },
+	{ apm_is_horked, "Dell XPS-Z", { /* APM crashes */
+			MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
+			MATCH(DMI_BIOS_VERSION, "A11"),
+			MATCH(DMI_PRODUCT_NAME, "XPS-Z"),
+			NO_MATCH,
+			} },
 	{ apm_is_horked, "Sharp PC-PJ/AX", { /* APM crashes */
 			MATCH(DMI_SYS_VENDOR, "SHARP"),
 			MATCH(DMI_PRODUCT_NAME, "PC-PJ/AX"),
@@ -635,6 +672,12 @@
 			MATCH(DMI_BIOS_DATE, "05/12/01"), NO_MATCH
 			} },
 	
+	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z505LS (with updated BIOS) */
+			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION, "WXP01Z3"),
+			MATCH(DMI_BIOS_DATE, "10/26/01"), NO_MATCH
+			} },
+	
 	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-F104K */
 			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
 			MATCH(DMI_BIOS_VERSION, "R0204K2"),
@@ -738,7 +781,14 @@
 			NO_MATCH, NO_MATCH
 			} },
 	 
-			
+	{ fix_broken_hp_bios_irq9, "HP Pavilion N5400 Series Laptop", {
+			MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			MATCH(DMI_BIOS_VERSION, "GE.M1.03"),
+			MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"),
+			MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736")
+			} },
+ 
+
 	/*
 	 *	Generic per vendor APM settings
 	 */
@@ -793,59 +843,43 @@
 static void __init dmi_decode(struct dmi_header *dm)
 {
 	u8 *data = (u8 *)dm;
-	char *p;
 	
 	switch(dm->type)
 	{
 		case  0:
-			p=dmi_string(dm,data[4]);
-			if(*p)
-			{
-				dmi_printk(("BIOS Vendor: %s\n", p));
-				dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
-				dmi_printk(("BIOS Version: %s\n", 
-					dmi_string(dm, data[5])));
-				dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
-				dmi_printk(("BIOS Release: %s\n",
-					dmi_string(dm, data[8])));
-				dmi_save_ident(dm, DMI_BIOS_DATE, 8);
-			}
+			dmi_printk(("BIOS Vendor: %s\n",
+				dmi_string(dm, data[4])));
+			dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
+			dmi_printk(("BIOS Version: %s\n", 
+				dmi_string(dm, data[5])));
+			dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
+			dmi_printk(("BIOS Release: %s\n",
+				dmi_string(dm, data[8])));
+			dmi_save_ident(dm, DMI_BIOS_DATE, 8);
 			break;
-			
 		case 1:
-			p=dmi_string(dm,data[4]);
-			if(*p)
-			{
-				dmi_printk(("System Vendor: %s.\n",p));
-				dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
-				dmi_printk(("Product Name: %s.\n",
-					dmi_string(dm, data[5])));
-				dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
-				dmi_printk(("Version %s.\n",
-					dmi_string(dm, data[6])));
-				dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
-				dmi_printk(("Serial Number %s.\n",
-					dmi_string(dm, data[7])));
-			}
+			dmi_printk(("System Vendor: %s\n",
+				dmi_string(dm, data[4])));
+			dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
+			dmi_printk(("Product Name: %s\n",
+				dmi_string(dm, data[5])));
+			dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
+			dmi_printk(("Version: %s\n",
+				dmi_string(dm, data[6])));
+			dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
+			dmi_printk(("Serial Number: %s\n",
+				dmi_string(dm, data[7])));
 			break;
 		case 2:
-			p=dmi_string(dm,data[4]);
-			if(*p)
-			{
-				dmi_printk(("Board Vendor: %s.\n",p));
-				dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
-				dmi_printk(("Board Name: %s.\n",
-					dmi_string(dm, data[5])));
-				dmi_save_ident(dm, DMI_BOARD_NAME, 5);
-				dmi_printk(("Board Version: %s.\n",
-					dmi_string(dm, data[6])));
-				dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
-			}
-			break;
-		case 3:
-			p=dmi_string(dm,data[8]);
-			if(*p && *p!=' ')
-				dmi_printk(("Asset Tag: %s.\n", p));
+			dmi_printk(("Board Vendor: %s\n",
+				dmi_string(dm, data[4])));
+			dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
+			dmi_printk(("Board Name: %s\n",
+				dmi_string(dm, data[5])));
+			dmi_save_ident(dm, DMI_BOARD_NAME, 5);
+			dmi_printk(("Board Version: %s\n",
+				dmi_string(dm, data[6])));
+			dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
 			break;
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/entry.S linux-2.4.20/arch/i386/kernel/entry.S
--- linux-2.4.19/arch/i386/kernel/entry.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/entry.S	2002-10-29 11:18:35.000000000 +0000
@@ -622,23 +622,33 @@
 	.long SYMBOL_NAME(sys_ni_syscall)	/* Reserved for Security */
 	.long SYMBOL_NAME(sys_gettid)
 	.long SYMBOL_NAME(sys_readahead)	/* 225 */
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for setxattr */
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for lsetxattr */
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for fsetxattr */
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for getxattr */
-	.long SYMBOL_NAME(sys_ni_syscall)	/* 230 reserved for lgetxattr */
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for fgetxattr */
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for listxattr */
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for llistxattr */
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for flistxattr */
-	.long SYMBOL_NAME(sys_ni_syscall)	/* 235 reserved for removexattr */
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for lremovexattr */
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for fremovexattr */
+	.long SYMBOL_NAME(sys_setxattr)
+	.long SYMBOL_NAME(sys_lsetxattr)
+	.long SYMBOL_NAME(sys_fsetxattr)
+	.long SYMBOL_NAME(sys_getxattr)
+	.long SYMBOL_NAME(sys_lgetxattr)	/* 230 */
+	.long SYMBOL_NAME(sys_fgetxattr)
+	.long SYMBOL_NAME(sys_listxattr)
+	.long SYMBOL_NAME(sys_llistxattr)
+	.long SYMBOL_NAME(sys_flistxattr)
+	.long SYMBOL_NAME(sys_removexattr)	/* 235 */
+	.long SYMBOL_NAME(sys_lremovexattr)
+	.long SYMBOL_NAME(sys_fremovexattr)
  	.long SYMBOL_NAME(sys_tkill)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sendfile64 */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* 240 reserved for futex */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_setaffinity */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_getaffinity */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_set_thread_area */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_get_thread_area */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 245 sys_io_setup */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_destroy */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_getevents */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_submit */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_cancel */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 250 sys_alloc_hugepages */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_free_hugepages */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_exit_group */
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/io_apic.c linux-2.4.20/arch/i386/kernel/io_apic.c
--- linux-2.4.19/arch/i386/kernel/io_apic.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/io_apic.c	2002-10-29 11:18:36.000000000 +0000
@@ -32,6 +32,7 @@
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/desc.h>
+#include <asm/smpboot.h>
 
 #undef APIC_LOCKUP_DEBUG
 
@@ -39,6 +40,10 @@
 
 static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED;
 
+unsigned int int_dest_addr_mode = APIC_DEST_LOGICAL;
+unsigned char int_delivery_mode = dest_LowestPrio;
+
+
 /*
  * # of IRQ routing registers
  */
@@ -625,10 +630,10 @@
 		 */
 		memset(&entry,0,sizeof(entry));
 
-		entry.delivery_mode = dest_LowestPrio;
-		entry.dest_mode = INT_DELIVERY_MODE;
+		entry.delivery_mode = INT_DELIVERY_MODE;
+		entry.dest_mode = (INT_DEST_ADDR_MODE != 0);
 		entry.mask = 0;				/* enable IRQ */
-		entry.dest.logical.logical_dest = TARGET_CPUS;
+		entry.dest.logical.logical_dest = target_cpus();
 
 		idx = find_irq_entry(apic,pin,mp_INT);
 		if (idx == -1) {
@@ -646,7 +651,6 @@
 		if (irq_trigger(idx)) {
 			entry.trigger = 1;
 			entry.mask = 1;
-			entry.dest.logical.logical_dest = TARGET_CPUS;
 		}
 
 		irq = pin_2_irq(idx, apic, pin);
@@ -654,7 +658,8 @@
 		 * skip adding the timer int on secondary nodes, which causes
 		 * a small but painful rift in the time-space continuum
 		 */
-		if (clustered_apic_mode && (apic != 0) && (irq == 0))
+		if ((clustered_apic_mode == CLUSTERED_APIC_NUMAQ) 
+			&& (apic != 0) && (irq == 0))
 			continue;
 		else
 			add_pin_to_irq(irq, apic, pin);
@@ -707,16 +712,16 @@
 	 * We use logical delivery to get the timer IRQ
 	 * to the first CPU.
 	 */
-	entry.dest_mode = INT_DELIVERY_MODE;
+	entry.dest_mode = (INT_DEST_ADDR_MODE != 0);
 	entry.mask = 0;					/* unmask IRQ now */
-	entry.dest.logical.logical_dest = TARGET_CPUS;
-	entry.delivery_mode = dest_LowestPrio;
+	entry.dest.logical.logical_dest = target_cpus();
+	entry.delivery_mode = INT_DELIVERY_MODE;
 	entry.polarity = 0;
 	entry.trigger = 0;
 	entry.vector = vector;
 
 	/*
-	 * The timer IRQ doesnt have to know that behind the
+	 * The timer IRQ doesn't have to know that behind the
 	 * scene we have a 8259A-master in AEOI mode ...
 	 */
 	irq_desc[0].handler = &ioapic_edge_irq_type;
@@ -1586,7 +1591,7 @@
 	printk(" failed.\n");
 
 	if (nmi_watchdog) {
-		printk(KERN_WARNING "timer doesnt work through the IO-APIC - disabling NMI Watchdog!\n");
+		printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n");
 		nmi_watchdog = 0;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/irq.c linux-2.4.20/arch/i386/kernel/irq.c
--- linux-2.4.19/arch/i386/kernel/irq.c	2001-10-25 20:53:46.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/irq.c	2002-10-29 11:18:32.000000000 +0000
@@ -577,6 +577,20 @@
 	irq_desc_t *desc = irq_desc + irq;
 	struct irqaction * action;
 	unsigned int status;
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+	long esp;
+
+	/* Debugging check for stack overflow: is there less than 1KB free? */
+	__asm__ __volatile__("andl %%esp,%0" : "=r" (esp) : "0" (8191));
+	if (unlikely(esp < (sizeof(struct task_struct) + 1024))) {
+		extern void show_stack(unsigned long *);
+
+		printk("do_IRQ: stack overflow: %ld\n",
+			esp - sizeof(struct task_struct));
+		__asm__ __volatile__("movl %%esp,%0" : "=r" (esp));
+		show_stack((void *)esp);
+	}
+#endif
 
 	kstat.irqs[cpu][irq]++;
 	spin_lock(&desc->lock);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/mpparse.c linux-2.4.20/arch/i386/kernel/mpparse.c
--- linux-2.4.19/arch/i386/kernel/mpparse.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/mpparse.c	2002-10-29 11:18:36.000000000 +0000
@@ -26,6 +26,7 @@
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
 #include <asm/pgalloc.h>
+#include <asm/smpboot.h>
 
 /* Have we found an MP table */
 int smp_found_config;
@@ -65,6 +66,8 @@
 /* Bitmask of physically existing CPUs */
 unsigned long phys_cpu_present_map;
 
+unsigned char esr_disable = 0;
+
 /*
  * Intel MP BIOS table parsing routines:
  */
@@ -115,6 +118,8 @@
 		case 0x0F:
 			if (model == 0x00)
 				return("Pentium 4(tm)");
+			if (model == 0x02)
+				return("Pentium 4(tm) XEON(tm)");
 			if (model == 0x0F)
 				return("Special controller");
 	}
@@ -145,7 +150,7 @@
 		return;
 
 	logical_apicid = m->mpc_apicid;
-	if (clustered_apic_mode) {
+	if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) {
 		quad = translation_table[mpc_record]->trans_quad;
 		logical_apicid = (quad << 4) + 
 			(m->mpc_apicid ? m->mpc_apicid << 1 : 1);
@@ -221,11 +226,12 @@
 	if (m->mpc_apicid > MAX_APICS) {
 		printk("Processor #%d INVALID. (Max ID: %d).\n",
 			m->mpc_apicid, MAX_APICS);
+			--num_processors;
 		return;
 	}
 	ver = m->mpc_apicver;
 
-	if (clustered_apic_mode) {
+	if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) {
 		phys_cpu_present_map |= (logical_apicid&0xf) << (4*quad);
 	} else {
 		phys_cpu_present_map |= 1 << m->mpc_apicid;
@@ -248,7 +254,7 @@
 	memcpy(str, m->mpc_bustype, 6);
 	str[6] = 0;
 	
-	if (clustered_apic_mode) {
+	if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) {
 		quad = translation_table[mpc_record]->trans_quad;
 		mp_bus_id_to_node[m->mpc_busid] = quad;
 		mp_bus_id_to_local[m->mpc_busid] = translation_table[mpc_record]->trans_local;
@@ -433,7 +439,7 @@
 	if (!have_acpi_tables)
 		mp_lapic_addr = mpc->mpc_lapic;
 
-	if (clustered_apic_mode && mpc->mpc_oemptr) {
+	if ((clustered_apic_mode == CLUSTERED_APIC_NUMAQ) && mpc->mpc_oemptr) {
 		/* We need to process the oem mpc tables to tell us which quad things are in ... */
 		mpc_record = 0;
 		smp_read_mpc_oem((struct mp_config_oemtable *) mpc->mpc_oemptr, mpc->mpc_oemsize);
@@ -502,6 +508,11 @@
 		}
 		++mpc_record;
 	}
+
+	if (clustered_apic_mode){
+		esr_disable = 1;
+	}
+
 	if (!num_processors)
 		printk(KERN_ERR "SMP mptable: no processors registered!\n");
 	return num_processors;
@@ -815,7 +826,7 @@
 
 /*
  * The Visual Workstation is Intel MP compliant in the hardware
- * sense, but it doesnt have a BIOS(-configuration table).
+ * sense, but it doesn't have a BIOS(-configuration table).
  * No problem for Linux.
  */
 void __init find_visws_smp(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/pci-dma.c linux-2.4.20/arch/i386/kernel/pci-dma.c
--- linux-2.4.19/arch/i386/kernel/pci-dma.c	2000-02-14 23:34:21.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/pci-dma.c	2002-10-29 11:18:34.000000000 +0000
@@ -19,7 +19,7 @@
 	void *ret;
 	int gfp = GFP_ATOMIC;
 
-	if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
+	if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
 		gfp |= GFP_DMA;
 	ret = (void *)__get_free_pages(gfp, get_order(size));
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/pci-i386.c linux-2.4.20/arch/i386/kernel/pci-i386.c
--- linux-2.4.19/arch/i386/kernel/pci-i386.c	2001-11-04 17:31:58.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/pci-i386.c	2002-10-29 11:18:35.000000000 +0000
@@ -136,7 +136,8 @@
  * which might have be mirrored at 0x0100-0x03ff..
  */
 void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res,
+		       unsigned long size, unsigned long align)
 {
 	if (res->flags & IORESOURCE_IO) {
 		unsigned long start = res->start;
@@ -303,7 +304,7 @@
 	pcibios_assign_resources();
 }
 
-int pcibios_enable_resources(struct pci_dev *dev)
+int pcibios_enable_resources(struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
@@ -312,6 +313,10 @@
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for(idx=0; idx<6; idx++) {
+		/* Only set up the requested stuff */
+		if (!(mask & (1<<idx)))
+			continue;
+			
 		r = &dev->resource[idx];
 		if (!r->start && r->end) {
 			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
@@ -347,7 +352,7 @@
 		lat = pcibios_max_latency;
 	else
 		return;
-	printk("PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
+	printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
 	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/pci-i386.h linux-2.4.20/arch/i386/kernel/pci-i386.h
--- linux-2.4.19/arch/i386/kernel/pci-i386.h	2001-11-11 18:09:32.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/pci-i386.h	2002-10-29 11:18:31.000000000 +0000
@@ -29,7 +29,7 @@
 extern unsigned int pcibios_max_latency;
 
 void pcibios_resource_survey(void);
-int pcibios_enable_resources(struct pci_dev *);
+int pcibios_enable_resources(struct pci_dev *, int);
 
 /* pci-pc.c */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/pci-irq.c linux-2.4.20/arch/i386/kernel/pci-irq.c
--- linux-2.4.19/arch/i386/kernel/pci-irq.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/pci-irq.c	2002-10-29 11:18:51.000000000 +0000
@@ -22,6 +22,8 @@
 #define PIRQ_SIGNATURE	(('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
 #define PIRQ_VERSION 0x0100
 
+int broken_hp_bios_irq9;
+
 static struct irq_routing_table *pirq_table;
 
 /*
@@ -596,6 +598,15 @@
 	DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
 	mask &= pcibios_irq_mask;
 
+	/* Work around broken HP Pavilion Notebooks which assign USB to
+	   IRQ 9 even though it is actually wired to IRQ 11 */
+
+	if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) {
+		dev->irq = 11;
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
+		r->set(pirq_router_dev, dev, pirq, 11);
+	}
+
 	/*
 	 * Find the best IRQ to assign: use the one
 	 * reported by the device if possible.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/pci-pc.c linux-2.4.20/arch/i386/kernel/pci-pc.c
--- linux-2.4.19/arch/i386/kernel/pci-pc.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/pci-pc.c	2002-10-29 11:18:39.000000000 +0000
@@ -15,6 +15,7 @@
 #include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/smp.h>
+#include <asm/smpboot.h>
 
 #include "pci-i386.h"
 
@@ -54,11 +55,11 @@
 #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
 	(0x80000000 | (BUS2LOCAL(bus) << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
 
-static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* CONFIG_MULTIQUAD */
+static int pci_conf1_mq_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* CONFIG_MULTIQUAD */
 {
 	unsigned long flags;
 
-	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+	if (bus > 255 || dev > 31 || fn > 7 || reg > 255)
 		return -EINVAL;
 
 	spin_lock_irqsave(&pci_config_lock, flags);
@@ -82,11 +83,11 @@
 	return 0;
 }
 
-static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* CONFIG_MULTIQUAD */
+static int pci_conf1_mq_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* CONFIG_MULTIQUAD */
 {
 	unsigned long flags;
 
-	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+	if (bus > 255 || dev > 31 || fn > 7 || reg > 255) 
 		return -EINVAL;
 
 	spin_lock_irqsave(&pci_config_lock, flags);
@@ -110,7 +111,69 @@
 	return 0;
 }
 
-#else /* !CONFIG_MULTIQUAD */
+static int pci_conf1_read_mq_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	int result; 
+	u32 data;
+
+	result = pci_conf1_mq_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 1, &data);
+
+	*value = (u8)data;
+
+	return result;
+}
+
+static int pci_conf1_read_mq_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	int result; 
+	u32 data;
+
+	result = pci_conf1_mq_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 2, &data);
+
+	*value = (u16)data;
+
+	return result;
+}
+
+static int pci_conf1_read_mq_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	if (!value) 
+		return -EINVAL;
+
+	return pci_conf1_mq_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 4, value);
+}
+
+static int pci_conf1_write_mq_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	return pci_conf1_mq_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 1, value);
+}
+
+static int pci_conf1_write_mq_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	return pci_conf1_mq_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 2, value);
+}
+
+static int pci_conf1_write_mq_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	return pci_conf1_mq_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 4, value);
+}
+
+static struct pci_ops pci_direct_mq_conf1 = {
+	pci_conf1_read_mq_config_byte,
+	pci_conf1_read_mq_config_word,
+	pci_conf1_read_mq_config_dword,
+	pci_conf1_write_mq_config_byte,
+	pci_conf1_write_mq_config_word,
+	pci_conf1_write_mq_config_dword
+};
+
+#endif /* !CONFIG_MULTIQUAD */
 #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
 	(0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
 
@@ -118,7 +181,7 @@
 {
 	unsigned long flags;
 
-	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+	if (bus > 255 || dev > 31 || fn > 7 || reg > 255)
 		return -EINVAL;
 
 	spin_lock_irqsave(&pci_config_lock, flags);
@@ -146,7 +209,7 @@
 {
 	unsigned long flags;
 
-	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+	if ((bus > 255 || dev > 31 || fn > 7 || reg > 255)) 
 		return -EINVAL;
 
 	spin_lock_irqsave(&pci_config_lock, flags);
@@ -170,8 +233,6 @@
 	return 0;
 }
 
-#endif /* CONFIG_MULTIQUAD */
-
 #undef PCI_CONF1_ADDRESS
 
 static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
@@ -179,9 +240,6 @@
 	int result; 
 	u32 data;
 
-	if (!value) 
-		return -EINVAL;
-
 	result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
 		PCI_FUNC(dev->devfn), where, 1, &data);
 
@@ -195,9 +253,6 @@
 	int result; 
 	u32 data;
 
-	if (!value) 
-		return -EINVAL;
-
 	result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
 		PCI_FUNC(dev->devfn), where, 2, &data);
 
@@ -208,9 +263,6 @@
 
 static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
 {
-	if (!value) 
-		return -EINVAL;
-
 	return pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
 		PCI_FUNC(dev->devfn), where, 4, value);
 }
@@ -253,7 +305,7 @@
 {
 	unsigned long flags;
 
-	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+	if (bus > 255 || dev > 31 || fn > 7 || reg > 255)
 		return -EINVAL;
 
 	if (dev & 0x10) 
@@ -287,7 +339,7 @@
 {
 	unsigned long flags;
 
-	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+	if ((bus > 255 || dev > 31 || fn > 7 || reg > 255)) 
 		return -EINVAL;
 
 	if (dev & 0x10) 
@@ -423,6 +475,12 @@
 			__restore_flags(flags);
 			printk(KERN_INFO "PCI: Using configuration type 1\n");
 			request_region(0xCF8, 8, "PCI conf1");
+
+#ifdef CONFIG_MULTIQUAD			
+			/* Multi-Quad has an extended PCI Conf1 */
+			if(clustered_apic_mode == CLUSTERED_APIC_NUMAQ)
+				return &pci_direct_mq_conf1;
+#endif				
 			return &pci_direct_conf1;
 		}
 		outl (tmp, 0xCF8);
@@ -640,7 +698,7 @@
 	unsigned long flags;
 	unsigned long bx = ((bus << 8) | (dev << 3) | fn);
 
-	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+	if (bus > 255 || dev > 31 || fn > 7 || reg > 255)
 		return -EINVAL;
 
 	spin_lock_irqsave(&pci_config_lock, flags);
@@ -695,7 +753,7 @@
 	unsigned long flags;
 	unsigned long bx = ((bus << 8) | (dev << 3) | fn);
 
-	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+	if ((bus > 255 || dev > 31 || fn > 7 || reg > 255)) 
 		return -EINVAL;
 
 	spin_lock_irqsave(&pci_config_lock, flags);
@@ -750,7 +808,7 @@
 	u32 data;
 
 	if (!value) 
-		return -EINVAL;
+		BUG();
 
 	result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
 		PCI_FUNC(dev->devfn), where, 1, &data);
@@ -766,7 +824,7 @@
 	u32 data;
 
 	if (!value) 
-		return -EINVAL;
+		BUG();
 
 	result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
 		PCI_FUNC(dev->devfn), where, 2, &data);
@@ -779,7 +837,7 @@
 static int pci_bios_read_config_dword(struct pci_dev *dev, int where, u32 *value)
 {
 	if (!value) 
-		return -EINVAL;
+		BUG();
 	
 	return pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
 		PCI_FUNC(dev->devfn), where, 4, value);
@@ -1227,6 +1285,11 @@
 	pci_read_config_byte(d, PCI_REVISION_ID, &revision);
 	
 	if (d->device == PCI_DEVICE_ID_VIA_8367_0) {
+		/* fix pci bus latency issues resulted by NB bios error
+		   it appears on bug free^Wreduced kt266x's bios forces
+		   NB latency to zero */
+		pci_write_config_byte(d, PCI_LATENCY_TIMER, 0);
+
 		where = 0x95; /* the memory write queue timer register is 
 				 different for the KT266x's: 0x95 not 0x55 */
 	} else if (d->device == PCI_DEVICE_ID_VIA_8363_0 &&
@@ -1245,6 +1308,22 @@
 	}
 }
 
+/*
+ * For some reasons Intel decided that certain parts of their
+ * 815, 845 and some other chipsets must look like PCI-to-PCI bridges
+ * while they are obviously not. The 82801 family (AA, AB, BAM/CAM,
+ * BA/CA/DB and E) PCI bridges are actually HUB-to-PCI ones, according
+ * to Intel terminology. These devices do forward all addresses from
+ * system to PCI bus no matter what are their window settings, so they are
+ * "transparent" (or subtractive decoding) from programmers point of view.
+ */
+static void __init pci_fixup_transparent_bridge(struct pci_dev *dev)
+{
+	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
+	    (dev->device & 0xff00) == 0x2400)
+		dev->transparent = 1;
+}
+
 struct pci_fixup pcibios_fixups[] = {
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82451NX,	pci_fixup_i450nx },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82454GX,	pci_fixup_i450gx },
@@ -1259,6 +1338,7 @@
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8361,	        pci_fixup_via_northbridge_bug },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8367_0,	pci_fixup_via_northbridge_bug },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_NCR,	PCI_DEVICE_ID_NCR_53C810,	pci_fixup_ncr53c810 },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_ANY_ID,			pci_fixup_transparent_bridge },
 	{ 0 }
 };
 
@@ -1281,6 +1361,11 @@
 	 * both PCI BIOS and direct access, with a preference for direct.
 	 */
 
+#ifdef CONFIG_PCI_DIRECT
+	struct pci_ops *tmp = NULL;
+#endif
+
+
 #ifdef CONFIG_PCI_BIOS
 	if ((pci_probe & PCI_PROBE_BIOS) 
 		&& ((pci_root_ops = pci_find_bios()))) {
@@ -1293,7 +1378,8 @@
 
 #ifdef CONFIG_PCI_DIRECT
 	if ((pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2)) 
-		&& (pci_root_ops = pci_check_direct())) {
+		&& (tmp = pci_check_direct())) {
+		pci_root_ops = tmp;
 		if (pci_root_ops == &pci_direct_conf1) {
 			pci_config_read = pci_conf1_read;
 			pci_config_write = pci_conf1_write;
@@ -1393,11 +1479,11 @@
 	return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
 }
 
-int pcibios_enable_device(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	int err;
 
-	if ((err = pcibios_enable_resources(dev)) < 0)
+	if ((err = pcibios_enable_resources(dev, mask)) < 0)
 		return err;
 	pcibios_enable_irq(dev);
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/pci-visws.c linux-2.4.20/arch/i386/kernel/pci-visws.c
--- linux-2.4.19/arch/i386/kernel/pci-visws.c	2001-11-04 17:31:58.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/pci-visws.c	2002-10-29 11:18:34.000000000 +0000
@@ -131,9 +131,9 @@
 	return str;
 }
 
-int pcibios_enable_device(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
-	return pcibios_enable_resources(dev);
+	return pcibios_enable_resources(dev, mask);
 }
 
 void __init pcibios_penalize_isa_irq(irq)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/semaphore.c linux-2.4.20/arch/i386/kernel/semaphore.c
--- linux-2.4.19/arch/i386/kernel/semaphore.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/semaphore.c	2002-10-29 11:18:39.000000000 +0000
@@ -262,31 +262,30 @@
  */
 #if defined(CONFIG_SMP)
 asm(
-"
-.align	4
-.globl	__write_lock_failed
-__write_lock_failed:
-	" LOCK "addl	$" RW_LOCK_BIAS_STR ",(%eax)
-1:	rep; nop
-	cmpl	$" RW_LOCK_BIAS_STR ",(%eax)
-	jne	1b
-
-	" LOCK "subl	$" RW_LOCK_BIAS_STR ",(%eax)
-	jnz	__write_lock_failed
-	ret
-
-
-.align	4
-.globl	__read_lock_failed
-__read_lock_failed:
-	lock ; incl	(%eax)
-1:	rep; nop
-	cmpl	$1,(%eax)
-	js	1b
+".text\n"
+".align	4\n"
+".globl	__write_lock_failed\n"
+"__write_lock_failed:\n\t"
+	LOCK "addl	$" RW_LOCK_BIAS_STR ",(%eax)\n"
+"1:	rep; nop\n\t"
+	"cmpl	$" RW_LOCK_BIAS_STR ",(%eax)\n\t"
+	"jne	1b\n\t"
+	LOCK "subl	$" RW_LOCK_BIAS_STR ",(%eax)\n\t"
+	"jnz	__write_lock_failed\n\t"
+	"ret"
+);
 
-	lock ; decl	(%eax)
-	js	__read_lock_failed
-	ret
-"
+asm(
+".text\n"
+".align	4\n"
+".globl	__read_lock_failed\n"
+"__read_lock_failed:\n\t"
+	LOCK "incl	(%eax)\n"
+"1:	rep; nop\n\t"
+	"cmpl	$1,(%eax)\n\t"
+	"js	1b\n\t"
+	LOCK "decl	(%eax)\n\t"
+	"js	__read_lock_failed\n\t"
+	"ret"
 );
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/setup.c linux-2.4.20/arch/i386/kernel/setup.c
--- linux-2.4.19/arch/i386/kernel/setup.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/setup.c	2002-10-29 11:18:40.000000000 +0000
@@ -71,13 +71,6 @@
  *  CacheSize bug workaround updates for AMD, Intel & VIA Cyrix.
  *  Dave Jones <davej@suse.de>, September, October 2001.
  *
- *  Short-term fix for a conflicting cache attribute bug in the kernel
- *  that is exposed by advanced speculative caching on new AMD Athlon
- *  processors.
- *  Richard Brunner <richard.brunner@amd.com> and Mark Langsdorf
- *  <mark.langsdorf@amd.com>, June 2002 
- *  Adapted to work with uniprocessor APIC by Bryan O'Sullivan
- *  <bos@serpentine.com>, June 2002.
  */
 
 /*
@@ -171,18 +164,15 @@
 extern int root_mountflags;
 extern char _text, _etext, _edata, _end;
 
+static int have_cpuid_p(void) __init;
+
 static int disable_x86_serial_nr __initdata = 1;
-static int disable_x86_fxsr __initdata = 0;
 static int disable_x86_ht __initdata = 0;
+static u32 disabled_x86_caps[NCAPINTS] __initdata = { 0 };
+extern int blk_nohighio;
 
 int enable_acpi_smp_table;
 
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
-int disable_adv_spec_cache __initdata = 1;
-#else
-int disable_adv_spec_cache __initdata = 0;
-#endif /* CONFIG_AGP */
-
 /*
  * This is set up by the setup-routine at boot-time
  */
@@ -741,41 +731,6 @@
 } /* setup_memory_region */
 
 
-int __init amd_adv_spec_cache_feature(void)
-{
-	char vendor_id[16];
-	int ident;
-	int family, model;
- 
-	/* Must have CPUID */
-	if(!have_cpuid_p())
-		goto donthave;
-	if(cpuid_eax(0)<1)
-		goto donthave;
-	
-	/* Must be x86 architecture */
-	cpuid(0, &ident,  
-		(int *)&vendor_id[0],
-		(int *)&vendor_id[8],
-		(int *)&vendor_id[4]);
-
-	if (memcmp(vendor_id, "AuthenticAMD", 12)) 
-	       goto donthave;
-
-	ident = cpuid_eax(1);
-	family = (ident >> 8) & 0xf;
-	model  = (ident >> 4) & 0xf;
-	if (((family == 6)  && (model >= 6)) || (family == 15)) {
-		printk(KERN_INFO "Advanced speculative caching feature present\n");
-		return 1;
-	}
-
-donthave:
-	printk(KERN_INFO "Advanced speculative caching feature not present\n");
-	return 0;
-}
-
-
 static void __init parse_cmdline_early (char ** cmdline_p)
 {
 	char c = ' ', *to = command_line, *from = COMMAND_LINE;
@@ -802,6 +757,7 @@
 			if (!memcmp(from+4, "nopentium", 9)) {
 				from += 9+4;
 				clear_bit(X86_FEATURE_PSE, &boot_cpu_data.x86_capability);
+				set_bit(X86_FEATURE_PSE, &disabled_x86_caps);
 			} else if (!memcmp(from+4, "exactmap", 8)) {
 				from += 8+4;
 				e820.nr_map = 0;
@@ -827,8 +783,10 @@
 		}
 
 		/* "noht" disables HyperThreading (2 logical cpus per Xeon) */
-		else if (!memcmp(from, "noht", 4))
+		else if (!memcmp(from, "noht", 4)) { 
 			disable_x86_ht = 1;
+			set_bit(X86_FEATURE_HT, disabled_x86_caps);
+		}
 
 		/* "acpismp=force" forces parsing and use of the ACPI SMP table */
 		else if (!memcmp(from, "acpismp=force", 13))
@@ -841,17 +799,6 @@
 		 */
 		else if (!memcmp(from, "highmem=", 8))
 			highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT;
-		/*
-		 * unsafe-gart-alias overrides the short-term fix for a
-		 * conflicting cache attribute bug in the kernel that is
-		 * exposed by advanced speculative caching in newer AMD
-		 * Athlon processors.  Overriding the fix will allow
-		 * higher performance but the kernel bug can cause system
-		 * lock-ups if the system uses an AGP card.  unsafe-gart-alias
-		 * can be turned on for higher performance in servers.
-		 */
-		else if (!memcmp(from, "unsafe-gart-alias", 17))
-			disable_adv_spec_cache = 0;
 nextchar:
 		c = *(from++);
 		if (!c)
@@ -868,49 +815,6 @@
 	}
 }
 
-void __init setup_arch(char **cmdline_p)
-{
-	unsigned long bootmap_size, low_mem_size;
-	unsigned long start_pfn, max_pfn, max_low_pfn;
-	int i;
-
-#ifdef CONFIG_VISWS
-	visws_get_board_type_and_rev();
-#endif
-
- 	ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
- 	drive_info = DRIVE_INFO;
- 	screen_info = SCREEN_INFO;
-	apm_info.bios = APM_BIOS_INFO;
-	if( SYS_DESC_TABLE.length != 0 ) {
-		MCA_bus = SYS_DESC_TABLE.table[3] &0x2;
-		machine_id = SYS_DESC_TABLE.table[0];
-		machine_submodel_id = SYS_DESC_TABLE.table[1];
-		BIOS_revision = SYS_DESC_TABLE.table[2];
-	}
-	aux_device_present = AUX_DEVICE_INFO;
-
-#ifdef CONFIG_BLK_DEV_RAM
-	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
-	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
-	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#endif
-	setup_memory_region();
-
-	if (!MOUNT_ROOT_RDONLY)
-		root_mountflags &= ~MS_RDONLY;
-	init_mm.start_code = (unsigned long) &_text;
-	init_mm.end_code = (unsigned long) &_etext;
-	init_mm.end_data = (unsigned long) &_edata;
-	init_mm.brk = (unsigned long) &_end;
-
-	code_resource.start = virt_to_bus(&_text);
-	code_resource.end = virt_to_bus(&_etext)-1;
-	data_resource.start = virt_to_bus(&_etext);
-	data_resource.end = virt_to_bus(&_edata)-1;
-
-	parse_cmdline_early(cmdline_p);
-
 #define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
 #define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
 #define PFN_PHYS(x)	((x) << PAGE_SHIFT)
@@ -921,15 +825,13 @@
 #define MAXMEM_PFN	PFN_DOWN(MAXMEM)
 #define MAX_NONPAE_PFN	(1 << 20)
 
-	/*
-	 * partially used pages are not usable - thus
-	 * we are rounding upwards:
-	 */
-	start_pfn = PFN_UP(__pa(&_end));
+/*
+ * Find the highest page frame number we have available
+ */
+static void __init find_max_pfn(void)
+{
+	int i;
 
-	/*
-	 * Find the highest page frame number we have available
-	 */
 	max_pfn = 0;
 	for (i = 0; i < e820.nr_map; i++) {
 		unsigned long start, end;
@@ -943,10 +845,15 @@
 		if (end > max_pfn)
 			max_pfn = end;
 	}
+}
+
+/*
+ * Determine low and high memory ranges:
+ */
+static unsigned long __init find_max_low_pfn(void)
+{
+	unsigned long max_low_pfn;
 
-	/*
-	 * Determine low and high memory ranges:
-	 */
 	max_low_pfn = max_pfn;
 	if (max_low_pfn > MAXMEM_PFN) {
 		if (highmem_pages == -1)
@@ -996,27 +903,19 @@
 #endif
 	}
 
-#ifdef CONFIG_HIGHMEM
-	highstart_pfn = highend_pfn = max_pfn;
-	if (max_pfn > max_low_pfn) {
-		highstart_pfn = max_low_pfn;
-	}
-	printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
-		pages_to_mb(highend_pfn - highstart_pfn));
-#endif
-	printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
-			pages_to_mb(max_low_pfn));
-	/*
-	 * Initialize the boot-time allocator (with low memory only):
-	 */
-	bootmap_size = init_bootmem(start_pfn, max_low_pfn);
+	return max_low_pfn;
+}
+
+/*
+ * Register fully available low RAM pages with the bootmem allocator.
+ */
+static void __init register_bootmem_low_pages(unsigned long max_low_pfn)
+{
+	int i;
 
-	/*
-	 * Register fully available low RAM pages with the bootmem allocator.
-	 */
 	for (i = 0; i < e820.nr_map; i++) {
 		unsigned long curr_pfn, last_pfn, size;
- 		/*
+		/*
 		 * Reserve usable low memory
 		 */
 		if (e820.map[i].type != E820_RAM)
@@ -1045,6 +944,39 @@
 		size = last_pfn - curr_pfn;
 		free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size));
 	}
+}
+
+static unsigned long __init setup_memory(void)
+{
+	unsigned long bootmap_size, start_pfn, max_low_pfn;
+
+	/*
+	 * partially used pages are not usable - thus
+	 * we are rounding upwards:
+	 */
+	start_pfn = PFN_UP(__pa(&_end));
+
+	find_max_pfn();
+
+	max_low_pfn = find_max_low_pfn();
+
+#ifdef CONFIG_HIGHMEM
+	highstart_pfn = highend_pfn = max_pfn;
+	if (max_pfn > max_low_pfn) {
+		highstart_pfn = max_low_pfn;
+	}
+	printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
+		pages_to_mb(highend_pfn - highstart_pfn));
+#endif
+	printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
+			pages_to_mb(max_low_pfn));
+	/*
+	 * Initialize the boot-time allocator (with low memory only):
+	 */
+	bootmap_size = init_bootmem(start_pfn, max_low_pfn);
+
+	register_bootmem_low_pages(max_low_pfn);
+
 	/*
 	 * Reserve the bootmem bitmap itself as well. We do this in two
 	 * steps (first step was init_bootmem()) because this catches
@@ -1093,51 +1025,18 @@
 	}
 #endif
 
-	/*
-	 * If enable_acpi_smp_table and HT feature present, acpitable.c
-	 * will find all logical cpus despite disable_x86_ht: so if both
-	 * "noht" and "acpismp=force" are specified, let "noht" override
-	 * "acpismp=force" cleanly.  Why retain "acpismp=force"? because
-	 * parsing ACPI SMP table might prove useful on some non-HT cpu.
-	 */
-	if (disable_x86_ht) {
-		clear_bit(X86_FEATURE_HT, &boot_cpu_data.x86_capability[0]);
-		enable_acpi_smp_table = 0;
-	}
-	if (test_bit(X86_FEATURE_HT, &boot_cpu_data.x86_capability[0]))
-		enable_acpi_smp_table = 1;
-	
-
-	/*
-	 * NOTE: before this point _nobody_ is allowed to allocate
-	 * any memory using the bootmem allocator.
-	 */
-
-#ifdef CONFIG_SMP
-	smp_alloc_memory(); /* AP processor realmode stacks in low memory*/
-#endif
-	/*
-	 * short-term fix for a conflicting cache attribute bug in the 
-	 * kernel that is exposed by advanced speculative caching on
-	 * newer AMD Athlon processors.
-	 */
-	if (disable_adv_spec_cache && amd_adv_spec_cache_feature())
-		clear_bit(X86_FEATURE_PSE, &boot_cpu_data.x86_capability);
-
-	paging_init();
-#ifdef CONFIG_X86_LOCAL_APIC
-	/*
-	 * get boot-time SMP configuration:
-	 */
-	if (smp_found_config)
-		get_smp_config();
-#endif
-
+	return max_low_pfn;
+}
+ 
+/*
+ * Request address space for all standard RAM and ROM resources
+ * and also for regions reported as reserved by the e820.
+ */
+static void __init register_memory(unsigned long max_low_pfn)
+{
+	unsigned long low_mem_size;
+	int i;
 
-	/*
-	 * Request address space for all standard RAM and ROM resources
-	 * and also for regions reported as reserved by the e820.
-	 */
 	probe_roms();
 	for (i = 0; i < e820.nr_map; i++) {
 		struct resource *res;
@@ -1174,6 +1073,89 @@
 	low_mem_size = ((max_low_pfn << PAGE_SHIFT) + 0xfffff) & ~0xfffff;
 	if (low_mem_size > pci_mem_start)
 		pci_mem_start = low_mem_size;
+}
+
+void __init setup_arch(char **cmdline_p)
+{
+	unsigned long max_low_pfn;
+
+#ifdef CONFIG_VISWS
+	visws_get_board_type_and_rev();
+#endif
+
+#ifndef CONFIG_HIGHIO
+	blk_nohighio = 1;
+#endif
+
+ 	ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
+ 	drive_info = DRIVE_INFO;
+ 	screen_info = SCREEN_INFO;
+	apm_info.bios = APM_BIOS_INFO;
+	if( SYS_DESC_TABLE.length != 0 ) {
+		MCA_bus = SYS_DESC_TABLE.table[3] &0x2;
+		machine_id = SYS_DESC_TABLE.table[0];
+		machine_submodel_id = SYS_DESC_TABLE.table[1];
+		BIOS_revision = SYS_DESC_TABLE.table[2];
+	}
+	aux_device_present = AUX_DEVICE_INFO;
+
+#ifdef CONFIG_BLK_DEV_RAM
+	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
+	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
+	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
+#endif
+	setup_memory_region();
+
+	if (!MOUNT_ROOT_RDONLY)
+		root_mountflags &= ~MS_RDONLY;
+	init_mm.start_code = (unsigned long) &_text;
+	init_mm.end_code = (unsigned long) &_etext;
+	init_mm.end_data = (unsigned long) &_edata;
+	init_mm.brk = (unsigned long) &_end;
+
+	code_resource.start = virt_to_bus(&_text);
+	code_resource.end = virt_to_bus(&_etext)-1;
+	data_resource.start = virt_to_bus(&_etext);
+	data_resource.end = virt_to_bus(&_edata)-1;
+
+	parse_cmdline_early(cmdline_p);
+
+	max_low_pfn = setup_memory();
+
+	/*
+	 * If enable_acpi_smp_table and HT feature present, acpitable.c
+	 * will find all logical cpus despite disable_x86_ht: so if both
+	 * "noht" and "acpismp=force" are specified, let "noht" override
+	 * "acpismp=force" cleanly.  Why retain "acpismp=force"? because
+	 * parsing ACPI SMP table might prove useful on some non-HT cpu.
+	 */
+	if (disable_x86_ht) {
+		clear_bit(X86_FEATURE_HT, &boot_cpu_data.x86_capability[0]);
+		set_bit(X86_FEATURE_HT, disabled_x86_caps);
+		enable_acpi_smp_table = 0;
+	}
+	if (test_bit(X86_FEATURE_HT, &boot_cpu_data.x86_capability[0]))
+		enable_acpi_smp_table = 1;
+	
+
+	/*
+	 * NOTE: before this point _nobody_ is allowed to allocate
+	 * any memory using the bootmem allocator.
+	 */
+
+#ifdef CONFIG_SMP
+	smp_alloc_memory(); /* AP processor realmode stacks in low memory*/
+#endif
+	paging_init();
+#ifdef CONFIG_X86_LOCAL_APIC
+	/*
+	 * get boot-time SMP configuration:
+	 */
+	if (smp_found_config)
+		get_smp_config();
+#endif
+
+	register_memory(max_low_pfn);
 
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)
@@ -1197,14 +1179,27 @@
 #ifndef CONFIG_X86_TSC
 static int tsc_disable __initdata = 0;
 
-static int __init tsc_setup(char *str)
+static int __init notsc_setup(char *str)
 {
 	tsc_disable = 1;
 	return 1;
 }
-
-__setup("notsc", tsc_setup);
+#else
+static int __init notsc_setup(char *str)
+{
+	printk("notsc: Kernel compiled with CONFIG_X86_TSC, cannot disable TSC.\n");
+	return 1;
+}
 #endif
+__setup("notsc", notsc_setup);
+
+static int __init highio_setup(char *str)
+{
+	printk("i386: disabling HIGHMEM block I/O\n");
+	blk_nohighio = 1;
+	return 1;
+}
+__setup("nohighio", highio_setup);
 
 static int __init get_model_name(struct cpuinfo_x86 *c)
 {
@@ -1292,31 +1287,6 @@
 	       l2size, ecx & 0xFF);
 }
 
-
-/*=======================================================================
- * amd_adv_spec_cache_disable
- * Setting a special MSR big that disables a small part of advanced
- * speculative caching as part of a short-term fix for a conflicting cache
- * attribute bug in the kernel that is exposed by advanced speculative
- * caching in newer AMD Athlon processors.
- =======================================================================*/
-static void amd_adv_spec_cache_disable(void)
-{
-	printk(KERN_INFO "Disabling advanced speculative caching\n");
-
-	__asm__ __volatile__ (
-		" movl	 $0x9c5a203a,%%edi   \n" /* msr enable */
-		" movl	 $0xc0011022,%%ecx   \n" /* msr addr	 */
-		" rdmsr			     \n" /* get reg val	 */
-		" orl	 $0x00010000,%%eax   \n" /* set bit 16	 */
-		" wrmsr			     \n" /* put it back	 */
-		" xorl	%%edi, %%edi	     \n" /* clear msr enable */
-		: /* no outputs */
-		: /* no inputs, either */
-		: "%eax","%ecx","%edx","%edi" /* clobbered regs */ );
-}
-
-
 /*
  *	B step AMD K6 before B 9730xxxx have hardware bugs that can cause
  *	misexecution of code under Linux. Owners of such processors should
@@ -1450,21 +1420,10 @@
  			 * to enable SSE on Palomino/Morgan CPU's.
 			 * If the BIOS didn't enable it already, enable it
 			 * here.
-			 *
-			 * Avoiding the use of 4MB/2MB pages along with
-			 * setting a special MSR bit that disables a small
-			 * part of advanced speculative caching as part of a
-			 * short-term fix for a conflicting cache attribute
-			 * bug in the kernel that is exposed by advanced
-			 * speculative caching in newer AMD Atlon processors.
-			 *
-			 * If we cleared the PSE bit earlier as part
-			 * of the workaround for this problem, we need
-			 * to clear it again, as our caller may have
-			 * clobbered it if uniprocessor APIC is enabled.
 			 */
-			if (c->x86_model >= 6) {
-				if (!cpu_has_xmm) {
+			if (c->x86_model == 6 || c->x86_model == 7) {
+				if (!test_bit(X86_FEATURE_XMM,
+					      &c->x86_capability)) {
 					printk(KERN_INFO
 					       "Enabling Disabled K7/SSE Support...\n");
 					rdmsr(MSR_K7_HWCR, l, h);
@@ -1473,18 +1432,6 @@
 					set_bit(X86_FEATURE_XMM,
                                                 &c->x86_capability);
 				}
-				if (disable_adv_spec_cache &&
-				    amd_adv_spec_cache_feature()) {
-					clear_bit(X86_FEATURE_PSE,
-						  &c->x86_capability);
-					amd_adv_spec_cache_disable();
-				}
-			}
-			break;
-		case 15: 
-			if (disable_adv_spec_cache && amd_adv_spec_cache_feature()) {
-				clear_bit(X86_FEATURE_PSE, &c->x86_capability);
-				amd_adv_spec_cache_disable();
 			}
 			break;
 
@@ -1534,7 +1481,7 @@
  * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in
  * order to identify the Cyrix CPU model after we're out of setup.c
  *
- * Actually since bugs.h doesnt even reference this perhaps someone should
+ * Actually since bugs.h doesn't even reference this perhaps someone should
  * fix the documentation ???
  */
 static unsigned char Cx86_dir0_msb __initdata = 0;
@@ -2198,6 +2145,11 @@
 	wrmsr(0x80860004, ~0, uk);
 	c->x86_capability[0] = cpuid_edx(0x00000001);
 	wrmsr(0x80860004, cap_mask, uk);
+
+	/* If we can run i686 user-space code, call us an i686 */
+#define USER686 (X86_FEATURE_TSC|X86_FEATURE_CX8|X86_FEATURE_CMOV)
+	if ( c->x86 == 5 && (c->x86_capability[0] & USER686) == USER686 )
+	     c->x86 = 6;
 }
 
 
@@ -2227,31 +2179,69 @@
 
 extern void trap_init_f00f_bug(void);
 
+#define LVL_1_INST      1
+#define LVL_1_DATA      2
+#define LVL_2           3
+#define LVL_3           4
+
+struct _cache_table
+{
+        unsigned char descriptor;
+        char cache_type;
+        short size;
+};
+
+/* all the cache descriptor types we care about (no TLB or trace cache entries) */
+static struct _cache_table cache_table[] __initdata =
+{
+	{ 0x06, LVL_1_INST, 8 },
+	{ 0x08, LVL_1_INST, 16 },
+	{ 0x0A, LVL_1_DATA, 8 },
+	{ 0x0C, LVL_1_DATA, 16 },
+	{ 0x22, LVL_3,      512 },
+	{ 0x23, LVL_3,      1024 },
+	{ 0x25, LVL_3,      2048 },
+	{ 0x29, LVL_3,      4096 },
+	{ 0x41, LVL_2,      128 },
+	{ 0x42, LVL_2,      256 },
+	{ 0x43, LVL_2,      512 },
+	{ 0x44, LVL_2,      1024 },
+	{ 0x45, LVL_2,      2048 },
+	{ 0x66, LVL_1_DATA, 8 },
+	{ 0x67, LVL_1_DATA, 16 },
+	{ 0x68, LVL_1_DATA, 32 },
+	{ 0x79, LVL_2,      128 },
+	{ 0x7A, LVL_2,      256 },
+	{ 0x7B, LVL_2,      512 },
+	{ 0x7C, LVL_2,      1024 },
+	{ 0x82, LVL_2,      256 },
+	{ 0x84, LVL_2,      1024 },
+	{ 0x85, LVL_2,      2048 },
+	{ 0x00, 0, 0}
+};
+
 static void __init init_intel(struct cpuinfo_x86 *c)
 {
-#ifndef CONFIG_M686
-	static int f00f_workaround_enabled = 0;
-#endif
-	char *p = NULL;
 	unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
+	char *p = NULL;
+#ifndef CONFIG_X86_F00F_WORKS_OK
+	static int f00f_workaround_enabled = 0;
 
-#ifndef CONFIG_M686
 	/*
 	 * All current models of Pentium and Pentium with MMX technology CPUs
 	 * have the F0 0F bug, which lets nonpriviledged users lock up the system.
 	 * Note that the workaround only should be initialized once...
 	 */
 	c->f00f_bug = 0;
-	if ( c->x86 == 5 ) {
+	if (c->x86 == 5) {
 		c->f00f_bug = 1;
-		if ( !f00f_workaround_enabled ) {
+		if (!f00f_workaround_enabled) {
 			trap_init_f00f_bug();
 			printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n");
 			f00f_workaround_enabled = 1;
 		}
 	}
-#endif
-
+#endif /* CONFIG_X86_F00F_WORKS_OK */
 
 	if (c->cpuid_level > 1) {
 		/* supports eax=2  call */
@@ -2273,83 +2263,31 @@
 			/* Byte 0 is level count, not a descriptor */
 			for ( j = 1 ; j < 16 ; j++ ) {
 				unsigned char des = dp[j];
-				unsigned char dl, dh;
-				unsigned int cs;
-
-				dh = des >> 4;
-				dl = des & 0x0F;
+				unsigned char k = 0;
 
-				/* Black magic... */
-
-				switch ( dh )
+				/* look up this descriptor in the table */
+				while (cache_table[k].descriptor != 0)
 				{
-				case 0:
-					switch ( dl ) {
-					case 6:
-						/* L1 I cache */
-						l1i += 8;
-						break;
-					case 8:
-						/* L1 I cache */
-						l1i += 16;
-						break;
-					case 10:
-						/* L1 D cache */
-						l1d += 8;
-						break;
-					case 12:
-						/* L1 D cache */
-						l1d += 16;
-						break;
-					default:;
-						/* TLB, or unknown */
-					}
-					break;
-				case 2:
-					if ( dl ) {
-						/* L3 cache */
-						cs = (dl-1) << 9;
-						l3 += cs;
-					}
-					break;
-				case 4:
-					if ( c->x86 > 6 && dl ) {
-						/* P4 family */
-						/* L3 cache */
-						cs = 128 << (dl-1);
-						l3 += cs;
+					if (cache_table[k].descriptor == des) {
+						switch (cache_table[k].cache_type) {
+						case LVL_1_INST:
+							l1i += cache_table[k].size;
+							break;
+						case LVL_1_DATA:
+							l1d += cache_table[k].size;
+							break;
+						case LVL_2:
+							l2 += cache_table[k].size;
+							break;
+						case LVL_3:
+							l3 += cache_table[k].size;
+							break;
+						}
+
 						break;
 					}
-					/* else same as 8 - fall through */
-				case 8:
-					if ( dl ) {
-						/* L2 cache */
-						cs = 128 << (dl-1);
-						l2 += cs;
-					}
-					break;
-				case 6:
-					if (dl > 5) {
-						/* L1 D cache */
-						cs = 8<<(dl-6);
-						l1d += cs;
-					}
-					break;
-				case 7:
-					if ( dl >= 8 ) 
-					{
-						/* L2 cache */
-						cs = 64<<(dl-8);
-						l2 += cs;
-					} else {
-						/* L0 I cache, count as L1 */
-						cs = dl ? (16 << (dl-1)) : 12;
-						l1i += cs;
-					}
-					break;
-				default:
-					/* TLB, or something else we don't know about */
-					break;
+
+					k++;
 				}
 			}
 		}
@@ -2426,7 +2364,7 @@
 			if (smp_num_siblings != NR_SIBLINGS) {
 				printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
 				smp_num_siblings = 1;
-				goto too_many_siblings;
+				return;
 			}
 			tmp = smp_num_siblings;
 			while ((tmp & 1) == 0) {
@@ -2448,7 +2386,6 @@
 		}
 
 	}
-too_many_siblings:
 #endif
 }
 
@@ -2596,7 +2533,8 @@
 
 static int __init x86_fxsr_setup(char * s)
 {
-	disable_x86_fxsr = 1;
+	set_bit(X86_FEATURE_XMM, disabled_x86_caps); 
+	set_bit(X86_FEATURE_FXSR, disabled_x86_caps);
 	return 1;
 }
 __setup("nofxsr", x86_fxsr_setup);
@@ -2749,12 +2687,6 @@
 			      &c->x86_capability[0]);
 			c->x86 = (tfms >> 8) & 15;
 			c->x86_model = (tfms >> 4) & 15;
-			if ( (c->x86_vendor == X86_VENDOR_AMD) &&
-				(c->x86 == 0xf)) {
-				/* AMD Extended Family and Model Values */
-				c->x86 += (tfms >> 20) & 0xff;
-				c->x86_model += (tfms >> 12) & 0xf0;
-			}
 			c->x86_mask = tfms & 15;
 		} else {
 			/* Have CPUID level 0 only - unheard of */
@@ -2778,12 +2710,6 @@
 		}
 	}
 
-	printk(KERN_DEBUG "CPU: Before vendor init, caps: %08x %08x %08x, vendor = %d\n",
-	       c->x86_capability[0],
-	       c->x86_capability[1],
-	       c->x86_capability[2],
-	       c->x86_vendor);
-
 	/*
 	 * Vendor-specific initialization.  In this section we
 	 * canonicalize the feature flags, meaning if there are
@@ -2842,12 +2768,6 @@
 		break;
 	}
 
-	printk(KERN_DEBUG "CPU: After vendor init, caps: %08x %08x %08x %08x\n",
-	       c->x86_capability[0],
-	       c->x86_capability[1],
-	       c->x86_capability[2],
-	       c->x86_capability[3]);
-
 	/*
 	 * The vendor-specific functions might have changed features.  Now
 	 * we do "generic changes."
@@ -2859,14 +2779,9 @@
 		clear_bit(X86_FEATURE_TSC, &c->x86_capability);
 #endif
 
-	/* HT disabled? */
-	if (disable_x86_ht)
-		clear_bit(X86_FEATURE_HT, &c->x86_capability);
-
-	/* FXSR disabled? */
-	if (disable_x86_fxsr) {
-		clear_bit(X86_FEATURE_FXSR, &c->x86_capability);
-		clear_bit(X86_FEATURE_XMM, &c->x86_capability);
+	/* check for caps that have been disabled earlier */ 
+	for (i = 0; i < NCAPINTS; i++) { 
+	     c->x86_capability[i] &= ~disabled_x86_caps[i];
 	}
 
 	/* Disable the PN if appropriate */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/smp.c linux-2.4.20/arch/i386/kernel/smp.c
--- linux-2.4.19/arch/i386/kernel/smp.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/smp.c	2002-10-29 11:18:33.000000000 +0000
@@ -66,7 +66,7 @@
  *	an L1cache=Writethrough or L1cache=off option.
  *
  *		B stepping CPUs may hang. There are hardware work arounds
- *	for this. We warn about it in case your board doesnt have the work
+ *	for this. We warn about it in case your board doesn't have the work
  *	arounds. Basically thats so I can tell anyone with a B stepping
  *	CPU and SMP problems "tough".
  *
@@ -115,7 +115,7 @@
 
 static inline int __prepare_ICR (unsigned int shortcut, int vector)
 {
-	return APIC_DM_FIXED | shortcut | vector | APIC_DEST_LOGICAL;
+	return APIC_DM_FIXED | shortcut | vector | INT_DEST_ADDR_MODE;
 }
 
 static inline int __prepare_ICR2 (unsigned int mask)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/smpboot.c linux-2.4.20/arch/i386/kernel/smpboot.c
--- linux-2.4.19/arch/i386/kernel/smpboot.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/smpboot.c	2002-10-29 11:18:40.000000000 +0000
@@ -830,7 +830,7 @@
 
 	Dprintk("Setting warm reset code and vector.\n");
 
-	if (clustered_apic_mode) {
+	if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) {
 		/* stash the current NMI vector, so we can put things back */
 		nmi_high = *((volatile unsigned short *) TRAMPOLINE_HIGH);
 		nmi_low = *((volatile unsigned short *) TRAMPOLINE_LOW);
@@ -862,7 +862,7 @@
 	 * Starting actual IPI sequence...
 	 */
 
-	if (clustered_apic_mode)
+	if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ)
 		boot_error = wakeup_secondary_via_NMI(apicid);
 	else 
 		boot_error = wakeup_secondary_via_INIT(apicid, start_eip);
@@ -917,7 +917,7 @@
 	/* mark "stuck" area as not stuck */
 	*((volatile unsigned long *)phys_to_virt(8192)) = 0;
 
-	if(clustered_apic_mode) {
+	if(clustered_apic_mode == CLUSTERED_APIC_NUMAQ) {
 		printk("Restoring NMI vector\n");
 		*((volatile unsigned short *) TRAMPOLINE_HIGH) = nmi_high;
 		*((volatile unsigned short *) TRAMPOLINE_LOW) = nmi_low;
@@ -981,7 +981,7 @@
 {
 	int apicid, cpu, bit;
 
-        if (clustered_apic_mode && (numnodes > 1)) {
+        if ((clustered_apic_mode == CLUSTERED_APIC_NUMAQ) && (numnodes > 1)) {
                 printk("Remapping cross-quad port I/O for %d quads\n",
 			numnodes);
                 printk("xquad_portio vaddr 0x%08lx, len %08lx\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/time.c linux-2.4.20/arch/i386/kernel/time.c
--- linux-2.4.19/arch/i386/kernel/time.c	2002-02-25 19:37:53.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/time.c	2002-10-29 11:18:40.000000000 +0000
@@ -31,6 +31,7 @@
  */
 
 #include <linux/errno.h>
+#include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
@@ -116,6 +117,8 @@
 
 spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED;
 
+EXPORT_SYMBOL(i8253_lock);
+
 extern spinlock_t i8259A_lock;
 
 #ifndef CONFIG_X86_TSC
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/trampoline.S linux-2.4.20/arch/i386/kernel/trampoline.S
--- linux-2.4.19/arch/i386/kernel/trampoline.S	2001-10-05 01:42:54.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/trampoline.S	2002-10-29 11:18:38.000000000 +0000
@@ -36,9 +36,7 @@
 
 ENTRY(trampoline_data)
 r_base = .
-#ifdef CONFIG_MULTIQUAD
-	wbinvd
-#endif /* CONFIG_MULTIQUAD */
+	wbinvd			# Needed for NUMA-Q should be harmless for others
 	mov	%cs, %ax	# Code and data in the same place
 	mov	%ax, %ds
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/kernel/traps.c linux-2.4.20/arch/i386/kernel/traps.c
--- linux-2.4.19/arch/i386/kernel/traps.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/kernel/traps.c	2002-10-29 11:18:34.000000000 +0000
@@ -40,9 +40,9 @@
 
 #include <asm/smp.h>
 #include <asm/pgalloc.h>
+#include <asm/fixmap.h>
 
 #ifdef CONFIG_X86_VISWS_APIC
-#include <asm/fixmap.h>
 #include <asm/cobalt.h>
 #include <asm/lithium.h>
 #endif
@@ -186,6 +186,14 @@
 	show_trace(esp);
 }
 
+/*
+ * The architecture-independent backtrace generator
+ */
+void dump_stack(void)
+{
+	show_stack(0);
+}
+
 void show_registers(struct pt_regs *regs)
 {
 	int i;
@@ -305,8 +313,13 @@
 static void inline do_trap(int trapnr, int signr, char *str, int vm86,
 			   struct pt_regs * regs, long error_code, siginfo_t *info)
 {
-	if (vm86 && regs->eflags & VM_MASK)
-		goto vm86_trap;
+	if (regs->eflags & VM_MASK) {
+		if (vm86)
+			goto vm86_trap;
+		else
+			goto trap_signal;
+	}
+
 	if (!(regs->xcs & 3))
 		goto kernel_trap;
 
@@ -514,10 +527,15 @@
 {
 	unsigned int condition;
 	struct task_struct *tsk = current;
+	unsigned long eip = regs->eip;
 	siginfo_t info;
 
 	__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
 
+	/* If the user set TF, it's simplest to clear it right away. */
+	if ((eip >=PAGE_OFFSET) && (regs->eflags & TF_MASK))
+		goto clear_TF;
+
 	/* Mask out spurious debug traps due to lazy DR7 setting */
 	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
 		if (!tsk->thread.debugreg[7])
@@ -758,35 +776,17 @@
 
 #endif /* CONFIG_MATH_EMULATION */
 
-#ifndef CONFIG_M686
+#ifndef CONFIG_X86_F00F_WORKS_OK
 void __init trap_init_f00f_bug(void)
 {
-	unsigned long page;
-	pgd_t * pgd;
-	pmd_t * pmd;
-	pte_t * pte;
-
-	/*
-	 * Allocate a new page in virtual address space, 
-	 * move the IDT into it and write protect this page.
-	 */
-	page = (unsigned long) vmalloc(PAGE_SIZE);
-	pgd = pgd_offset(&init_mm, page);
-	pmd = pmd_offset(pgd, page);
-	pte = pte_offset(pmd, page);
-	__free_page(pte_page(*pte));
-	*pte = mk_pte_phys(__pa(&idt_table), PAGE_KERNEL_RO);
-	/*
-	 * Not that any PGE-capable kernel should have the f00f bug ...
-	 */
-	__flush_tlb_all();
-
 	/*
 	 * "idt" is magic - it overlaps the idt_descr
 	 * variable so that updating idt will automatically
 	 * update the idt descriptor..
 	 */
-	idt = (struct desc_struct *)page;
+	__set_fixmap(FIX_F00F, __pa(&idt_table), PAGE_KERNEL_RO);
+	idt = (struct desc_struct *)__fix_to_virt(FIX_F00F);
+
 	__asm__ __volatile__("lidt %0": "=m" (idt_descr));
 }
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/lib/checksum.S linux-2.4.20/arch/i386/lib/checksum.S
--- linux-2.4.19/arch/i386/lib/checksum.S	2000-09-05 21:01:35.000000000 +0000
+++ linux-2.4.20/arch/i386/lib/checksum.S	2002-10-29 11:18:35.000000000 +0000
@@ -55,8 +55,21 @@
 	movl 20(%esp),%eax	# Function arg: unsigned int sum
 	movl 16(%esp),%ecx	# Function arg: int len
 	movl 12(%esp),%esi	# Function arg: unsigned char *buff
-	testl $2, %esi		# Check alignment.
+	testl $3, %esi		# Check alignment.
 	jz 2f			# Jump if alignment is ok.
+	testl $1, %esi		# Check alignment.
+	jz 10f			# Jump if alignment is boundary of 2bytes.
+
+	# buf is odd
+	dec %ecx
+	jl 8f
+	movzbl (%esi), %ebx
+	adcl %ebx, %eax
+	roll $8, %eax
+	inc %esi
+	testl $2, %esi
+	jz 2f
+10:
 	subl $2, %ecx		# Alignment uses up two bytes.
 	jae 1f			# Jump if we had at least two bytes.
 	addl $2, %ecx		# ecx was < 2.  Deal with it.
@@ -111,6 +124,10 @@
 6:	addl %ecx,%eax
 	adcl $0, %eax 
 7:	
+	testl $1, 12(%esp)
+	jz 8f
+	roll $8, %eax
+8:
 	popl %ebx
 	popl %esi
 	ret
@@ -126,8 +143,8 @@
 	movl 16(%esp),%ecx	# Function arg: int len
 	movl 12(%esp),%esi	# Function arg:	const unsigned char *buf
 
-	testl $2, %esi         
-	jnz 30f                 
+	testl $3, %esi         
+	jnz 25f                 
 10:
 	movl %ecx, %edx
 	movl %ecx, %ebx
@@ -145,10 +162,25 @@
 	lea 2(%esi), %esi
 	adcl $0, %eax
 	jmp 10b
+25:
+	testl $1, %esi         
+	jz 30f                 
+	# buf is odd
+	dec %ecx
+	jl 90f
+	movzbl (%esi), %ebx
+	addl %ebx, %eax
+	adcl $0, %eax
+	roll $8, %eax
+	inc %esi
+	testl $2, %esi
+	jz 10b
 
 30:	subl $2, %ecx          
 	ja 20b                 
 	je 32f
+	addl $2, %ecx
+	jz 80f
 	movzbl (%esi),%ebx	# csumming 1 byte, 2-aligned
 	addl %ebx, %eax
 	adcl $0, %eax
@@ -209,6 +241,10 @@
 	addl %ebx,%eax
 	adcl $0,%eax
 80: 
+	testl $1, 12(%esp)
+	jz 90f
+	roll $8, %eax
+90: 
 	popl %ebx
 	popl %esi
 	ret
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/mm/Makefile linux-2.4.20/arch/i386/mm/Makefile
--- linux-2.4.19/arch/i386/mm/Makefile	2000-12-29 22:07:20.000000000 +0000
+++ linux-2.4.20/arch/i386/mm/Makefile	2002-10-29 11:18:35.000000000 +0000
@@ -9,6 +9,7 @@
 
 O_TARGET := mm.o
 
-obj-y	 := init.o fault.o ioremap.o extable.o
+obj-y	 := init.o fault.o ioremap.o extable.o pageattr.o
+export-objs := pageattr.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/mm/fault.c linux-2.4.20/arch/i386/mm/fault.c
--- linux-2.4.19/arch/i386/mm/fault.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/mm/fault.c	2002-10-29 11:18:31.000000000 +0000
@@ -86,8 +86,7 @@
 
 out_of_memory:
 	if (current->pid == 1) {
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		goto survive;
 	}
 	goto bad_area;
@@ -334,13 +333,11 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
-		tsk->policy |= SCHED_YIELD;
-		schedule();
-		down_read(&mm->mmap_sem);
+		yield();
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (error_code & 4)
 		do_exit(SIGKILL);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/mm/init.c linux-2.4.20/arch/i386/mm/init.c
--- linux-2.4.19/arch/i386/mm/init.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/i386/mm/init.c	2002-10-29 11:18:34.000000000 +0000
@@ -320,6 +320,27 @@
 	flush_tlb_all();
 }
 
+static void __init zone_sizes_init(void)
+{
+	unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
+	unsigned int max_dma, high, low;
+
+	max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+	low = max_low_pfn;
+	high = highend_pfn;
+
+	if (low < max_dma)
+		zones_size[ZONE_DMA] = low;
+	else {
+		zones_size[ZONE_DMA] = max_dma;
+		zones_size[ZONE_NORMAL] = low - max_dma;
+#ifdef CONFIG_HIGHMEM
+		zones_size[ZONE_HIGHMEM] = high - low;
+#endif
+	}
+	free_area_init(zones_size);
+}
+
 /*
  * paging_init() sets up the page tables - note that the first 8MB are
  * already mapped by head.S.
@@ -347,26 +368,7 @@
 #ifdef CONFIG_HIGHMEM
 	kmap_init();
 #endif
-	{
-		unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
-		unsigned int max_dma, high, low;
-
-		max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
-		low = max_low_pfn;
-		high = highend_pfn;
-
-		if (low < max_dma)
-			zones_size[ZONE_DMA] = low;
-		else {
-			zones_size[ZONE_DMA] = max_dma;
-			zones_size[ZONE_NORMAL] = low - max_dma;
-#ifdef CONFIG_HIGHMEM
-			zones_size[ZONE_HIGHMEM] = high - low;
-#endif
-		}
-		free_area_init(zones_size);
-	}
-	return;
+	zone_sizes_init();
 }
 
 /*
@@ -443,62 +445,81 @@
 		return 1;
 	return 0;
 }
-	
-void __init mem_init(void)
-{
-	extern int ppro_with_ram_bug(void);
-	int codesize, reservedpages, datasize, initsize;
-	int tmp;
-	int bad_ppro;
 
-	if (!mem_map)
-		BUG();
+#ifdef CONFIG_HIGHMEM
+void __init one_highpage_init(struct page *page, int pfn, int bad_ppro)
+{
+	if (!page_is_ram(pfn)) {
+		SetPageReserved(page);
+		return;
+	}
 	
-	bad_ppro = ppro_with_ram_bug();
+	if (bad_ppro && page_kills_ppro(pfn)) {
+		SetPageReserved(page);
+		return;
+	}
+	
+	ClearPageReserved(page);
+	set_bit(PG_highmem, &page->flags);
+	atomic_set(&page->count, 1);
+	__free_page(page);
+	totalhigh_pages++;
+}
+#endif /* CONFIG_HIGHMEM */
 
+static void __init set_max_mapnr_init(void)
+{
 #ifdef CONFIG_HIGHMEM
-	highmem_start_page = mem_map + highstart_pfn;
-	max_mapnr = num_physpages = highend_pfn;
-	num_mappedpages = max_low_pfn;
+        highmem_start_page = mem_map + highstart_pfn;
+        max_mapnr = num_physpages = highend_pfn;
+        num_mappedpages = max_low_pfn;
 #else
-	max_mapnr = num_mappedpages = num_physpages = max_low_pfn;
+        max_mapnr = num_mappedpages = num_physpages = max_low_pfn;
 #endif
-	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
+}
 
-	/* clear the zero-page */
-	memset(empty_zero_page, 0, PAGE_SIZE);
+static int __init free_pages_init(void)
+{
+	extern int ppro_with_ram_bug(void);
+	int bad_ppro, reservedpages, pfn;
+
+	bad_ppro = ppro_with_ram_bug();
 
 	/* this will put all low memory onto the freelists */
 	totalram_pages += free_all_bootmem();
 
 	reservedpages = 0;
-	for (tmp = 0; tmp < max_low_pfn; tmp++)
+	for (pfn = 0; pfn < max_low_pfn; pfn++) {
 		/*
 		 * Only count reserved RAM pages
 		 */
-		if (page_is_ram(tmp) && PageReserved(mem_map+tmp))
+		if (page_is_ram(pfn) && PageReserved(mem_map+pfn))
 			reservedpages++;
-#ifdef CONFIG_HIGHMEM
-	for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) {
-		struct page *page = mem_map + tmp;
-
-		if (!page_is_ram(tmp)) {
-			SetPageReserved(page);
-			continue;
-		}
-		if (bad_ppro && page_kills_ppro(tmp))
-		{
-			SetPageReserved(page);
-			continue;
-		}
-		ClearPageReserved(page);
-		set_bit(PG_highmem, &page->flags);
-		atomic_set(&page->count, 1);
-		__free_page(page);
-		totalhigh_pages++;
 	}
+#ifdef CONFIG_HIGHMEM
+	for (pfn = highend_pfn-1; pfn >= highstart_pfn; pfn--)
+		one_highpage_init((struct page *) (mem_map + pfn), pfn, bad_ppro);
 	totalram_pages += totalhigh_pages;
 #endif
+	return reservedpages;
+}
+
+void __init mem_init(void)
+{
+	int codesize, reservedpages, datasize, initsize;
+
+	if (!mem_map)
+		BUG();
+	
+	set_max_mapnr_init();
+
+	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
+
+	/* clear the zero-page */
+	memset(empty_zero_page, 0, PAGE_SIZE);
+
+	reservedpages = free_pages_init();
+
 	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
 	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
 	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/i386/mm/pageattr.c linux-2.4.20/arch/i386/mm/pageattr.c
--- linux-2.4.19/arch/i386/mm/pageattr.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/i386/mm/pageattr.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,175 @@
+/* 
+ * Copyright 2002 Andi Kleen, SuSE Labs. 
+ * Thanks to Ben LaHaise for precious feedback.
+ */ 
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/highmem.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+
+/* Should move most of this stuff into the appropiate includes */
+#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
+#define LARGE_PAGE_SIZE (1UL << PMD_SHIFT)
+
+static inline pte_t *lookup_address(unsigned long address) 
+{ 
+	pmd_t *pmd;	
+	pgd_t *pgd = pgd_offset(&init_mm, address); 
+
+	if (pgd_none(*pgd))
+		return NULL; 
+	if (pgd_val(*pgd) & _PAGE_PSE)
+		return (pte_t *)pgd; 
+	pmd = pmd_offset(pgd, address); 	       
+	if (pmd_none(*pmd))
+		return NULL; 
+	if (pmd_val(*pmd) & _PAGE_PSE) 
+		return (pte_t *)pmd; 
+    return pte_offset(pmd, address);
+} 
+
+static struct page *split_large_page(unsigned long address, pgprot_t prot)
+{ 
+	int i; 
+	unsigned long addr;
+	struct page *base = alloc_pages(GFP_KERNEL, 0);
+	pte_t *pbase;
+	if (!base) 
+		return NULL;
+	address = __pa(address);
+	addr = address & LARGE_PAGE_MASK; 
+	pbase = (pte_t *)page_address(base);
+	for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) {
+		pbase[i] = mk_pte_phys(addr, 
+				      addr == address ? prot : PAGE_KERNEL);
+	}
+	return base;
+} 
+
+static void flush_kernel_map(void * address) 
+{ 
+	if (!test_bit(X86_FEATURE_SELFSNOOP, boot_cpu_data.x86_capability)) {
+		/* Could use CLFLUSH here if the CPU supports it (Hammer,P4) */
+		if (boot_cpu_data.x86_model >= 4) 
+			asm volatile("wbinvd":::"memory"); 	
+	} 
+
+	/* Do global flush here to work around large page flushing errata 
+	   in some early Athlons */
+	__flush_tlb_all(); 	
+}
+
+static void set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte) 
+{ 
+	set_pte_atomic(kpte, pte); 	/* change init_mm */
+#ifndef CONFIG_X86_PAE
+	{
+		struct list_head *l;
+		spin_lock(&mmlist_lock);
+		list_for_each(l, &init_mm.mmlist) { 
+			struct mm_struct *mm = list_entry(l, struct mm_struct, mmlist);
+			pmd_t *pmd = pmd_offset(pgd_offset(mm, address), address);
+			set_pte_atomic((pte_t *)pmd, pte);
+		} 
+		spin_unlock(&mmlist_lock);
+	}
+#endif
+}
+
+/* no more special protections in this 2/4MB area - revert to a
+   large page again. */
+static inline void revert_page(struct page *kpte_page, unsigned long address)
+{
+	pte_t *linear = (pte_t *) 
+		pmd_offset(pgd_offset(&init_mm, address), address);
+	set_pmd_pte(linear,  address,
+		mk_pte_phys(__pa(address & LARGE_PAGE_MASK),
+			    MAKE_GLOBAL(_KERNPG_TABLE|_PAGE_PSE)));
+}	
+ 
+/*
+ * Change the page attributes of an page in the linear mapping.
+ *
+ * This should be used when a page is mapped with a different caching policy
+ * than write-back somewhere - some CPUs do not like it when mappings with
+ * different caching policies exist. This changes the page attributes of the
+ * in kernel linear mapping too.
+ * 
+ * The caller needs to ensure that there are no conflicting mappings elsewhere.
+ * This function only deals with the kernel linear map.
+ * When page is in highmem it must never be kmap'ed.
+ */
+static int 
+__change_page_attr(struct page *page, pgprot_t prot, struct page **oldpage) 
+{ 
+	pte_t *kpte; 
+	unsigned long address;
+	struct page *kpte_page;
+
+#ifdef CONFIG_HIGHMEM
+	if (page >= highmem_start_page) 
+		BUG(); 
+#endif
+	address = (unsigned long)page_address(page);
+	kpte = lookup_address(address);
+	if (!kpte) 
+		return -EINVAL; 
+	kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK);
+	if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) { 
+		if ((pte_val(*kpte) & _PAGE_PSE) == 0) {
+			pte_t old = *kpte;
+			pte_t standard = mk_pte(page, PAGE_KERNEL); 
+
+			set_pte_atomic(kpte, mk_pte(page, prot)); 
+			if (pte_same(old,standard))
+				atomic_inc(&kpte_page->count);
+		} else {
+			struct page *split = split_large_page(address, prot); 
+			if (!split)
+				return -ENOMEM;
+			atomic_inc(&kpte_page->count); 	
+			set_pmd_pte(kpte,address,mk_pte(split, PAGE_KERNEL));
+		}	
+	} else if ((pte_val(*kpte) & _PAGE_PSE) == 0) { 
+		set_pte_atomic(kpte, mk_pte(page, PAGE_KERNEL));
+		atomic_dec(&kpte_page->count); 
+	}
+
+	if (cpu_has_pse && (atomic_read(&kpte_page->count) == 1)) { 
+		*oldpage = kpte_page;
+		revert_page(kpte_page, address);
+	} 
+	return 0;
+} 
+
+int change_page_attr(struct page *page, int numpages, pgprot_t prot)
+{
+	int err = 0; 
+	struct page *fpage; 
+	int i; 
+
+	down_write(&init_mm.mmap_sem);
+	for (i = 0; i < numpages; i++, page++) { 
+		fpage = NULL;
+		err = __change_page_attr(page, prot, &fpage); 
+		if (err) 
+			break; 
+		if (fpage || i == numpages-1) { 
+			void *address = page_address(page);
+#ifdef CONFIG_SMP 
+			smp_call_function(flush_kernel_map, address, 1, 1);
+#endif	
+			flush_kernel_map(address);
+			if (fpage)
+				__free_page(fpage);
+		} 
+	} 	
+	up_write(&init_mm.mmap_sem); 
+	return err;
+}
+
+EXPORT_SYMBOL(change_page_attr);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/Makefile linux-2.4.20/arch/ia64/Makefile
--- linux-2.4.19/arch/ia64/Makefile	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/Makefile	2002-10-29 11:18:32.000000000 +0000
@@ -22,10 +22,10 @@
 # -ffunction-sections
 CFLAGS_KERNEL := -mconstant-gp
 
-GCC_VERSION=$(shell $(CROSS_COMPILE)$(HOSTCC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.')
+GCC_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.')
 
 ifneq ($(GCC_VERSION),2)
-	CFLAGS += -frename-registers --param max-inline-insns=2000
+	CFLAGS += -frename-registers --param max-inline-insns=5000
 endif
 
 ifeq ($(CONFIG_ITANIUM_BSTEP_SPECIFIC),y)
@@ -33,16 +33,11 @@
 endif
 
 ifdef CONFIG_IA64_GENERIC
-	CORE_FILES      :=      arch/$(ARCH)/hp/hp.a	\
-				arch/$(ARCH)/sn/sn.o	\
-				arch/$(ARCH)/dig/dig.a	\
-				arch/$(ARCH)/sn/io/sgiio.o \
+	CORE_FILES      :=      arch/$(ARCH)/hp/hp.o			\
+				arch/$(ARCH)/dig/dig.a			\
 				$(CORE_FILES)
 	SUBDIRS		:=	arch/$(ARCH)/hp		\
-				arch/$(ARCH)/sn/sn1	\
-				arch/$(ARCH)/sn		\
 				arch/$(ARCH)/dig	\
-				arch/$(ARCH)/sn/io	\
 				$(SUBDIRS)
 
 else # !GENERIC
@@ -50,7 +45,16 @@
 ifdef CONFIG_IA64_HP_SIM
         SUBDIRS         :=      arch/$(ARCH)/hp		\
                                 $(SUBDIRS)
-        CORE_FILES      :=      arch/$(ARCH)/hp/hp.a	\
+        CORE_FILES      :=      arch/$(ARCH)/hp/hp.o	\
+                                $(CORE_FILES)
+endif
+
+ifdef CONFIG_IA64_HP_ZX1
+        SUBDIRS         :=      arch/$(ARCH)/hp				\
+				arch/$(ARCH)/dig			\
+                                $(SUBDIRS)
+        CORE_FILES      :=      arch/$(ARCH)/hp/hp.o			\
+				arch/$(ARCH)/dig/dig.a			\
                                 $(CORE_FILES)
 endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/boot/Makefile linux-2.4.20/arch/ia64/boot/Makefile
--- linux-2.4.19/arch/ia64/boot/Makefile	2001-01-04 20:50:17.000000000 +0000
+++ linux-2.4.20/arch/ia64/boot/Makefile	2002-10-29 11:18:48.000000000 +0000
@@ -27,6 +27,6 @@
 	-o bootloader
 
 clean:
-	rm -f $(TARGETS)
+	rm -f $(targets-y) $(OBJECTS)
 
 dep:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/config.in linux-2.4.20/arch/ia64/config.in
--- linux-2.4.19/arch/ia64/config.in	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/config.in	2002-10-29 11:18:48.000000000 +0000
@@ -26,29 +26,32 @@
 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
 define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 
-if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
-  define_bool CONFIG_ACPI y
-  define_bool CONFIG_ACPI_EFI y
-  define_bool CONFIG_ACPI_INTERPRETER y
-  define_bool CONFIG_ACPI_KERNEL_CONFIG y
-fi
-
 choice 'IA-64 processor type' \
-	"Itanium			CONFIG_ITANIUM \
-	 McKinley			CONFIG_MCKINLEY" Itanium
+	"Itanium		CONFIG_ITANIUM \
+	 Itanium-2		CONFIG_MCKINLEY" Itanium
 
 choice 'IA-64 system type'					\
 	"generic		CONFIG_IA64_GENERIC		\
 	 DIG-compliant		CONFIG_IA64_DIG			\
 	 HP-simulator		CONFIG_IA64_HP_SIM		\
+	 HP-zx1			CONFIG_IA64_HP_ZX1		\
 	 SGI-SN1		CONFIG_IA64_SGI_SN1		\
 	 SGI-SN2		CONFIG_IA64_SGI_SN2" generic
 
-choice 'Kernel page size'						\
+if [ "$CONFIG_ITANIUM" = "y" ]; then
+  choice 'Kernel page size'						\
+	"4KB			CONFIG_IA64_PAGE_SIZE_4KB		\
+	 8KB			CONFIG_IA64_PAGE_SIZE_8KB		\
+	 16KB			CONFIG_IA64_PAGE_SIZE_16KB" 16KB
+else
+  choice 'Kernel page size'						\
 	"4KB			CONFIG_IA64_PAGE_SIZE_4KB		\
 	 8KB			CONFIG_IA64_PAGE_SIZE_8KB		\
 	 16KB			CONFIG_IA64_PAGE_SIZE_16KB		\
 	 64KB			CONFIG_IA64_PAGE_SIZE_64KB" 16KB
+fi
+
+bool 'Virtually mapped mem_map?' CONFIG_VIRTUAL_MEM_MAP n
 
 if [ "$CONFIG_ITANIUM" = "y" ]; then
 	define_bool CONFIG_IA64_BRL_EMU y
@@ -68,22 +71,18 @@
 	fi
 fi
 
-if [ "$CONFIG_IA64_DIG" = "y" ]; then
+if [ "$CONFIG_IA64_GENERIC" = "y" -o "$CONFIG_IA64_DIG" = "y" -o "$CONFIG_IA64_HP_ZX1" = "y" ]; then
 	bool '  Enable IA-64 Machine Check Abort' CONFIG_IA64_MCA
 	define_bool CONFIG_PM y
 fi
 
-if [ "$CONFIG_IA64_SGI_SN1" = "y" ] || [ "$CONFIG_IA64_SGI_SN2" = "y" ]; then
+if [ "$CONFIG_IA64_SGI_SN1" = "y" -o "$CONFIG_IA64_SGI_SN2" = "y" ]; then
 	define_bool CONFIG_IA64_SGI_SN y
-	bool '  Enable extra debugging code' CONFIG_IA64_SGI_SN_DEBUG n
+	bool '  Enable extra debugging code' CONFIG_IA64_SGI_SN_DEBUG
 	bool '  Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN_SIM
 	bool '  Enable autotest (llsc). Option to run cache test instead of booting' \
-			CONFIG_IA64_SGI_AUTOTEST n
-	define_bool CONFIG_DEVFS_FS y
-	if [ "$CONFIG_DEVFS_FS" = "y" ]; then
-	  bool '    Enable DEVFS Debug Code' CONFIG_DEVFS_DEBUG n
-	fi
-	bool '  Enable protocol mode for the L1 console' CONFIG_SERIAL_SGI_L1_PROTOCOL y
+			CONFIG_IA64_SGI_AUTOTEST
+	bool '  Enable protocol mode for the L1 console' CONFIG_SERIAL_SGI_L1_PROTOCOL
 	define_bool CONFIG_DISCONTIGMEM y
 	define_bool CONFIG_IA64_MCA y
 	define_bool CONFIG_NUMA y
@@ -107,21 +106,25 @@
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
 if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
+  define_bool CONFIG_ACPI y
+  define_bool CONFIG_ACPI_EFI y
+  define_bool CONFIG_ACPI_INTERPRETER y
+  define_bool CONFIG_ACPI_KERNEL_CONFIG y
 
-source drivers/acpi/Config.in
-
-bool 'PCI support' CONFIG_PCI
-source drivers/pci/Config.in
+  source drivers/acpi/Config.in
 
-bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
-if [ "$CONFIG_HOTPLUG" = "y" ]; then
-   source drivers/pcmcia/Config.in
-else
-   define_bool CONFIG_PCMCIA n
-fi
+  bool 'PCI support' CONFIG_PCI
+  source drivers/pci/Config.in
 
-source drivers/parport/Config.in
+  bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+  if [ "$CONFIG_HOTPLUG" = "y" ]; then
+     source drivers/hotplug/Config.in
+     source drivers/pcmcia/Config.in
+  else
+     define_bool CONFIG_PCMCIA n
+  fi
 
+  source drivers/parport/Config.in
 fi # !HP_SIM
 
 endmenu
@@ -131,28 +134,38 @@
 fi
 
 if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
+  source drivers/mtd/Config.in
+  source drivers/pnp/Config.in
+  source drivers/block/Config.in
+  source drivers/ieee1394/Config.in
+  source drivers/message/i2o/Config.in
+  source drivers/md/Config.in
+  source drivers/message/fusion/Config.in
 
-source drivers/mtd/Config.in
-source drivers/pnp/Config.in
-source drivers/block/Config.in
-source drivers/ieee1394/Config.in
-source drivers/message/i2o/Config.in
-source drivers/md/Config.in
-
-mainmenu_option next_comment
-comment 'ATA/IDE/MFM/RLL support'
-
-tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
+  mainmenu_option next_comment
+  comment 'ATA/IDE/MFM/RLL support'
 
-if [ "$CONFIG_IDE" != "n" ]; then
-  source drivers/ide/Config.in
-else
-  define_bool CONFIG_BLK_DEV_IDE_MODES n
-  define_bool CONFIG_BLK_DEV_HD n
-fi
-endmenu
+  tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
 
-fi # !HP_SIM
+  if [ "$CONFIG_IDE" != "n" ]; then
+    source drivers/ide/Config.in
+  else
+    define_bool CONFIG_BLK_DEV_IDE_MODES n
+    define_bool CONFIG_BLK_DEV_HD n
+  fi
+  endmenu
+else # HP_SIM
+  mainmenu_option next_comment
+  comment 'Block devices'
+  tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
+  dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
+
+  tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
+  if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then
+    int '  Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096
+  fi
+  endmenu
+fi # HP_SIM
 
 mainmenu_option next_comment
 comment 'SCSI support'
@@ -164,43 +177,37 @@
 fi
 endmenu
 
-if [ "$CONFIG_PCI" = "y" ]; then
-  source drivers/message/fusion/Config.in
-fi
-
 if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
+  if [ "$CONFIG_NET" = "y" ]; then
+    mainmenu_option next_comment
+    comment 'Network device support'
+
+    bool 'Network device support' CONFIG_NETDEVICES
+    if [ "$CONFIG_NETDEVICES" = "y" ]; then
+      source drivers/net/Config.in
+    fi
+    endmenu
+  fi
+
+  source net/ax25/Config.in
 
-if [ "$CONFIG_NET" = "y" ]; then
   mainmenu_option next_comment
-  comment 'Network device support'
+  comment 'ISDN subsystem'
 
-  bool 'Network device support' CONFIG_NETDEVICES
-  if [ "$CONFIG_NETDEVICES" = "y" ]; then
-    source drivers/net/Config.in
+  tristate 'ISDN support' CONFIG_ISDN
+  if [ "$CONFIG_ISDN" != "n" ]; then
+    source drivers/isdn/Config.in
   fi
   endmenu
-fi
-
-source net/ax25/Config.in
-
-mainmenu_option next_comment
-comment 'ISDN subsystem'
-
-tristate 'ISDN support' CONFIG_ISDN
-if [ "$CONFIG_ISDN" != "n" ]; then
-  source drivers/isdn/Config.in
-fi
-endmenu
 
-mainmenu_option next_comment
-comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
-
-bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
-if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
-  source drivers/cdrom/Config.in
-fi
-endmenu
+  mainmenu_option next_comment
+  comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
 
+  bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
+  if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
+    source drivers/cdrom/Config.in
+  fi
+  endmenu
 fi # !HP_SIM
 
 #
@@ -227,22 +234,22 @@
 fi
 
 if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
+  mainmenu_option next_comment
+  comment 'Sound'
 
-mainmenu_option next_comment
-comment 'Sound'
-
-tristate 'Sound card support' CONFIG_SOUND
-if [ "$CONFIG_SOUND" != "n" ]; then
-  source drivers/sound/Config.in
-fi
-endmenu
+  tristate 'Sound card support' CONFIG_SOUND
+  if [ "$CONFIG_SOUND" != "n" ]; then
+    source drivers/sound/Config.in
+  fi
+  endmenu
 
-source drivers/usb/Config.in
+  source drivers/usb/Config.in
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   source net/bluetooth/Config.in
-fi
+  source lib/Config.in
 
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+     source net/bluetooth/Config.in
+  fi
 fi # !HP_SIM
 
 if [ "$CONFIG_IA64_HP_SIM" != "n" -o "$CONFIG_IA64_GENERIC" != "n" ]; then
@@ -271,7 +278,14 @@
    bool '  Disable VHPT' CONFIG_DISABLE_VHPT
    bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
 
-   bool '  Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK
+   bool '  Early printk support' CONFIG_IA64_EARLY_PRINTK
+   if [ "$CONFIG_IA64_EARLY_PRINTK" != "n" ]; then
+      bool '    Early printk on MMIO serial port' CONFIG_IA64_EARLY_PRINTK_UART
+      if [ "$CONFIG_IA64_EARLY_PRINTK_UART" != "n" ]; then
+         hex '      UART MMIO base address' CONFIG_IA64_EARLY_PRINTK_UART_BASE 0
+      fi
+      bool '    Early printk on VGA' CONFIG_IA64_EARLY_PRINTK_VGA
+   fi
    bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
    bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
    bool '  Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/defconfig linux-2.4.20/arch/ia64/defconfig
--- linux-2.4.19/arch/ia64/defconfig	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/defconfig	2002-10-29 11:18:33.000000000 +0000
@@ -24,21 +24,18 @@
 # CONFIG_SBUS is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
 CONFIG_ITANIUM=y
 # CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
+CONFIG_IA64_GENERIC=y
+# CONFIG_IA64_DIG is not set
 # CONFIG_IA64_HP_SIM is not set
+# CONFIG_IA64_HP_ZX1 is not set
 # CONFIG_IA64_SGI_SN1 is not set
 # CONFIG_IA64_SGI_SN2 is not set
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
 CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
+CONFIG_VIRTUAL_MEM_MAP=y
 CONFIG_IA64_BRL_EMU=y
 # CONFIG_ITANIUM_BSTEP_SPECIFIC is not set
 CONFIG_IA64_L1_CACHE_SHIFT=6
@@ -56,15 +53,27 @@
 CONFIG_SYSCTL=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_KERNEL_CONFIG=y
+
+#
+# ACPI Support
+#
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_BUS=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_SYSTEM=y
 # CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
+# CONFIG_ACPI_FAN is not set
+# CONFIG_ACPI_PROCESSOR is not set
 # CONFIG_ACPI_THERMAL is not set
+# CONFIG_ACPI_DEBUG is not set
 CONFIG_PCI=y
 CONFIG_PCI_NAMES=y
 # CONFIG_HOTPLUG is not set
@@ -80,7 +89,7 @@
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK is not set
+# CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 CONFIG_FILTER=y
 CONFIG_UNIX=y
@@ -90,6 +99,7 @@
 # CONFIG_IP_PNP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_IPV6 is not set
@@ -102,6 +112,11 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -119,6 +134,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # Memory Technology Devices (MTD)
 #
 # CONFIG_MTD is not set
@@ -137,13 +157,20 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
 
 #
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
 # I2O device support
 #
 # CONFIG_I2O is not set
@@ -166,6 +193,15 @@
 # CONFIG_BLK_DEV_LVM is not set
 
 #
+# Fusion MPT device support
+#
+CONFIG_FUSION=y
+CONFIG_FUSION_BOOT=y
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 CONFIG_IDE=y
@@ -182,6 +218,7 @@
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -196,6 +233,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 CONFIG_BLK_DEV_IDEFLOPPY=y
 CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -207,12 +245,15 @@
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 # CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -220,6 +261,7 @@
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
@@ -278,8 +320,12 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=y
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
 # CONFIG_SCSI_DPT_I2O is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
@@ -299,9 +345,11 @@
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
@@ -331,6 +379,7 @@
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -340,7 +389,6 @@
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -353,7 +401,10 @@
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
-# CONFIG_TULIP is not set
+CONFIG_TULIP=y
+# CONFIG_TC35815 is not set
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
@@ -369,6 +420,7 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_NEW_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -382,12 +434,15 @@
 # Ethernet (1000 Mbit)
 #
 # CONFIG_ACENIC is not set
+# CONFIG_NET_BROADCOM is not set
 # CONFIG_DL2K is not set
 # CONFIG_MYRI_SBUS is not set
+CONFIG_E1000=y
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
+CONFIG_TIGON3=y
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -445,8 +500,9 @@
 CONFIG_VT_CONSOLE=y
 CONFIG_SERIAL=y
 CONFIG_SERIAL_CONSOLE=y
-# CONFIG_SERIAL_ACPI is not set
+CONFIG_SERIAL_HCDP=y
 # CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_ACPI is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
@@ -464,6 +520,7 @@
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
 
 #
 # Joysticks
@@ -519,16 +576,20 @@
 # CONFIG_FTAPE is not set
 CONFIG_AGP=y
 # CONFIG_AGP_INTEL is not set
-CONFIG_AGP_I460=y
 # CONFIG_AGP_I810 is not set
 # CONFIG_AGP_VIA is not set
 # CONFIG_AGP_AMD is not set
 # CONFIG_AGP_SIS is not set
 # CONFIG_AGP_ALI is not set
 # CONFIG_AGP_SWORKS is not set
+CONFIG_AGP_I460=y
+CONFIG_AGP_HP_ZX1=y
 CONFIG_DRM=y
-# CONFIG_DRM_NEW is not set
 CONFIG_DRM_OLD=y
+
+#
+# DRM 4.0 drivers
+#
 CONFIG_DRM40_TDFX=y
 # CONFIG_DRM40_GAMMA is not set
 # CONFIG_DRM40_R128 is not set
@@ -607,7 +668,7 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
@@ -671,12 +732,11 @@
 # CONFIG_MINIX_SUBPARTITION is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
-CONFIG_EFI_PARTITION=y
-# CONFIG_DEVFS_GUID is not set
 # CONFIG_LDM_PARTITION is not set
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+CONFIG_EFI_PARTITION=y
 # CONFIG_SMB_NLS is not set
 CONFIG_NLS=y
 
@@ -705,6 +765,7 @@
 # CONFIG_NLS_CODEPAGE_949 is not set
 # CONFIG_NLS_CODEPAGE_874 is not set
 # CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 # CONFIG_NLS_ISO8859_1 is not set
 # CONFIG_NLS_ISO8859_2 is not set
@@ -737,6 +798,7 @@
 CONFIG_SOUND=y
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_EMU10K1 is not set
 # CONFIG_MIDI_EMU10K1 is not set
 # CONFIG_SOUND_FUSION is not set
@@ -771,8 +833,9 @@
 # CONFIG_USB_LONG_TIMEOUT is not set
 
 #
-# USB Controllers
+# USB Host Controller Drivers
 #
+CONFIG_USB_EHCI_HCD=m
 CONFIG_USB_UHCI=m
 # CONFIG_USB_UHCI_ALT is not set
 # CONFIG_USB_OHCI is not set
@@ -781,6 +844,7 @@
 # USB Device Class drivers
 #
 # CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
 # CONFIG_USB_BLUETOOTH is not set
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
@@ -798,6 +862,7 @@
 # USB Human Interface Devices (HID)
 #
 CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
 CONFIG_USB_HIDDEV=y
 CONFIG_USB_KBD=m
 CONFIG_USB_MOUSE=m
@@ -819,6 +884,8 @@
 # CONFIG_USB_OV511 is not set
 # CONFIG_USB_PWC is not set
 # CONFIG_USB_SE401 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_VICAM is not set
 # CONFIG_USB_DSBR is not set
 # CONFIG_USB_DABUSB is not set
 
@@ -826,6 +893,7 @@
 # USB Network adaptors
 #
 # CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_CATC is not set
 # CONFIG_USB_CDCETHER is not set
@@ -847,6 +915,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -860,6 +929,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
@@ -869,6 +939,8 @@
 # USB Miscellaneous drivers
 #
 # CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_BRLVGER is not set
 
 #
 # Bluetooth support
@@ -876,6 +948,13 @@
 # CONFIG_BLUEZ is not set
 
 #
+# Simulated drivers
+#
+# CONFIG_SIMETH is not set
+# CONFIG_SIM_SERIAL is not set
+# CONFIG_SCSI_SIM is not set
+
+#
 # Kernel hacking
 #
 # CONFIG_IA64_GRANULE_16MB is not set
@@ -885,6 +964,9 @@
 # CONFIG_DISABLE_VHPT is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_IA64_EARLY_PRINTK=y
+CONFIG_IA64_EARLY_PRINTK_UART=y
+CONFIG_IA64_EARLY_PRINTK_UART_BASE=0
+# CONFIG_IA64_EARLY_PRINTK_VGA is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_IA64_DEBUG_CMPXCHG is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/dig/setup.c linux-2.4.20/arch/ia64/dig/setup.c
--- linux-2.4.19/arch/ia64/dig/setup.c	2001-04-05 19:51:47.000000000 +0000
+++ linux-2.4.20/arch/ia64/dig/setup.c	2002-10-29 11:18:35.000000000 +0000
@@ -33,8 +33,7 @@
  * is sufficient (the IDE driver will autodetect the drive geometry).
  */
 char drive_info[4*16];
-
-unsigned char aux_device_present = 0xaa;	/* XXX remove this when legacy I/O is gone */
+extern int pcat_compat;
 
 void __init
 dig_setup (char **cmdline_p)
@@ -81,13 +80,7 @@
 	screen_info.orig_video_ega_bx = 3;	/* XXX fake */
 }
 
-void
+void __init
 dig_irq_init (void)
 {
-	/*
-	 * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
-	 * enabled.
-	 */
-	outb(0xff, 0xA1);
-	outb(0xff, 0x21);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/Makefile linux-2.4.20/arch/ia64/hp/Makefile
--- linux-2.4.19/arch/ia64/hp/Makefile	2001-01-04 20:50:17.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/Makefile	2002-10-29 11:18:48.000000000 +0000
@@ -1,17 +1,15 @@
-#
-# ia64/platform/hp/Makefile
-#
-# Copyright (C) 1999 Silicon Graphics, Inc.
-# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
-#
+# arch/ia64/hp/Makefile
+# Copyright (c) 2002 Matthew Wilcox for Hewlett Packard
 
-all: hp.a
+ALL_SUB_DIRS := sim zx1 common
 
-O_TARGET := hp.a
+O_TARGET := hp.o
 
-obj-y := hpsim_console.o hpsim_irq.o hpsim_setup.o
-obj-$(CONFIG_IA64_GENERIC) += hpsim_machvec.o
+subdir-$(CONFIG_IA64_GENERIC) += $(ALL_SUB_DIRS)
+subdir-$(CONFIG_IA64_HP_SIM) += sim
+subdir-$(CONFIG_IA64_HP_ZX1) += zx1 common
 
-clean::
+SUB_DIRS := $(subdir-y)
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/common/Makefile linux-2.4.20/arch/ia64/hp/common/Makefile
--- linux-2.4.19/arch/ia64/hp/common/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/common/Makefile	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,14 @@
+#
+# ia64/platform/hp/common/Makefile
+#
+# Copyright (C) 2002 Hewlett Packard
+# Copyright (C) Alex Williamson (alex_williamson@hp.com)
+#
+
+O_TARGET := common.o
+
+export-objs := sba_iommu.o
+
+obj-y := sba_iommu.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/common/sba_iommu.c linux-2.4.20/arch/ia64/hp/common/sba_iommu.c
--- linux-2.4.19/arch/ia64/hp/common/sba_iommu.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/common/sba_iommu.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,1867 @@
+/*
+**  IA64 System Bus Adapter (SBA) I/O MMU manager
+**
+**	(c) Copyright 2002 Alex Williamson
+**	(c) Copyright 2002 Hewlett-Packard Company
+**
+**	Portions (c) 2000 Grant Grundler (from parisc I/O MMU code)
+**	Portions (c) 1999 Dave S. Miller (from sparc64 I/O MMU code)
+**
+**	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 module initializes the IOC (I/O Controller) found on HP
+** McKinley machines and their successors.
+**
+*/
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/acpi.h>
+#include <linux/efi.h>
+
+#include <asm/delay.h>		/* ia64_get_itc() */
+#include <asm/io.h>
+#include <asm/page.h>		/* PAGE_OFFSET */
+
+
+#define PFX "IOC: "
+
+#define ALLOW_IOV_BYPASS
+#define ENABLE_MARK_CLEAN
+/*
+** The number of debug flags is a clue - this code is fragile.
+*/
+#undef DEBUG_SBA_INIT
+#undef DEBUG_SBA_RUN
+#undef DEBUG_SBA_RUN_SG
+#undef DEBUG_SBA_RESOURCE
+#undef ASSERT_PDIR_SANITY
+#undef DEBUG_LARGE_SG_ENTRIES
+#undef DEBUG_BYPASS
+
+#define SBA_INLINE	__inline__
+/* #define SBA_INLINE */
+
+#ifdef DEBUG_SBA_INIT
+#define DBG_INIT(x...)	printk(x)
+#else
+#define DBG_INIT(x...)
+#endif
+
+#ifdef DEBUG_SBA_RUN
+#define DBG_RUN(x...)	printk(x)
+#else
+#define DBG_RUN(x...)
+#endif
+
+#ifdef DEBUG_SBA_RUN_SG
+#define DBG_RUN_SG(x...)	printk(x)
+#else
+#define DBG_RUN_SG(x...)
+#endif
+
+
+#ifdef DEBUG_SBA_RESOURCE
+#define DBG_RES(x...)	printk(x)
+#else
+#define DBG_RES(x...)
+#endif
+
+#ifdef DEBUG_BYPASS
+#define DBG_BYPASS(x...)	printk(x)
+#else
+#define DBG_BYPASS(x...)
+#endif
+
+#ifdef ASSERT_PDIR_SANITY
+#define ASSERT(expr) \
+        if(!(expr)) { \
+                printk( "\n" __FILE__ ":%d: Assertion " #expr " failed!\n",__LINE__); \
+                panic(#expr); \
+        }
+#else
+#define ASSERT(expr)
+#endif
+
+/*
+** The number of pdir entries to "free" before issueing
+** a read to PCOM register to flush out PCOM writes.
+** Interacts with allocation granularity (ie 4 or 8 entries
+** allocated and free'd/purged at a time might make this
+** less interesting).
+*/
+#define DELAYED_RESOURCE_CNT	16
+
+#define DEFAULT_DMA_HINT_REG	0
+
+#define ZX1_IOC_ID	((PCI_DEVICE_ID_HP_ZX1_IOC << 16) | PCI_VENDOR_ID_HP)
+#define REO_IOC_ID	((PCI_DEVICE_ID_HP_REO_IOC << 16) | PCI_VENDOR_ID_HP)
+
+#define ZX1_IOC_OFFSET	0x1000	/* ACPI reports SBA, we want IOC */
+
+#define IOC_FUNC_ID	0x000
+#define IOC_FCLASS	0x008	/* function class, bist, header, rev... */
+#define IOC_IBASE	0x300	/* IO TLB */
+#define IOC_IMASK	0x308
+#define IOC_PCOM	0x310
+#define IOC_TCNFG	0x318
+#define IOC_PDIR_BASE	0x320
+
+/* AGP GART driver looks for this */
+#define ZX1_SBA_IOMMU_COOKIE	0x0000badbadc0ffeeUL
+
+/*
+** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
+** It's safer (avoid memory corruption) to keep DMA page mappings
+** equivalently sized to VM PAGE_SIZE.
+**
+** We really can't avoid generating a new mapping for each
+** page since the Virtual Coherence Index has to be generated
+** and updated for each page.
+**
+** IOVP_SIZE could only be greater than PAGE_SIZE if we are
+** confident the drivers really only touch the next physical
+** page iff that driver instance owns it.
+*/
+#define IOVP_SIZE	PAGE_SIZE
+#define IOVP_SHIFT	PAGE_SHIFT
+#define IOVP_MASK	PAGE_MASK
+
+struct ioc {
+	void		*ioc_hpa;	/* I/O MMU base address */
+	char		*res_map;	/* resource map, bit == pdir entry */
+	u64		*pdir_base;	/* physical base address */
+	unsigned long	ibase;		/* pdir IOV Space base */
+	unsigned long	imask;		/* pdir IOV Space mask */
+
+	unsigned long	*res_hint;	/* next avail IOVP - circular search */
+	spinlock_t	res_lock;
+	unsigned long	hint_mask_pdir;	/* bits used for DMA hints */
+	unsigned int	res_bitshift;	/* from the RIGHT! */
+	unsigned int	res_size;	/* size of resource map in bytes */
+	unsigned int	hint_shift_pdir;
+	unsigned long	dma_mask;
+#if DELAYED_RESOURCE_CNT > 0
+	int saved_cnt;
+	struct sba_dma_pair {
+		dma_addr_t	iova;
+		size_t		size;
+	} saved[DELAYED_RESOURCE_CNT];
+#endif
+
+#ifdef CONFIG_PROC_FS
+#define SBA_SEARCH_SAMPLE	0x100
+	unsigned long avg_search[SBA_SEARCH_SAMPLE];
+	unsigned long avg_idx;	/* current index into avg_search */
+	unsigned long used_pages;
+	unsigned long msingle_calls;
+	unsigned long msingle_pages;
+	unsigned long msg_calls;
+	unsigned long msg_pages;
+	unsigned long usingle_calls;
+	unsigned long usingle_pages;
+	unsigned long usg_calls;
+	unsigned long usg_pages;
+#ifdef ALLOW_IOV_BYPASS
+	unsigned long msingle_bypass;
+	unsigned long usingle_bypass;
+	unsigned long msg_bypass;
+#endif
+#endif
+
+	/* Stuff we don't need in performance path */
+	struct ioc	*next;		/* list of IOC's in system */
+	acpi_handle	handle;		/* for multiple IOC's */
+	const char 	*name;
+	unsigned int	func_id;
+	unsigned int	rev;		/* HW revision of chip */
+	u32		iov_size;
+	unsigned int	pdir_size;	/* in bytes, determined by IOV Space size */
+	struct pci_dev	*sac_only_dev;
+};
+
+static struct ioc *ioc_list;
+static int reserve_sba_gart = 1;
+
+#define sba_sg_iova(sg) (sg->address)
+#define sba_sg_len(sg) (sg->length)
+#define sba_sg_buffer(sg) (sg->orig_address)
+
+#define GET_IOC(dev)	((struct ioc *) PCI_CONTROLLER(dev)->iommu)
+
+/*
+** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up
+** (or rather not merge) DMA's into managable chunks.
+** On parisc, this is more of the software/tuning constraint
+** rather than the HW. I/O MMU allocation alogorithms can be
+** faster with smaller size is (to some degree).
+*/
+#define DMA_CHUNK_SIZE  (BITS_PER_LONG*PAGE_SIZE)
+
+#define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1))
+
+/************************************
+** SBA register read and write support
+**
+** BE WARNED: register writes are posted.
+**  (ie follow writes which must reach HW with a read)
+**
+*/
+#define READ_REG(addr)       __raw_readq(addr)
+#define WRITE_REG(val, addr) __raw_writeq(val, addr)
+
+#ifdef DEBUG_SBA_INIT
+
+/**
+ * sba_dump_tlb - debugging only - print IOMMU operating parameters
+ * @hpa: base address of the IOMMU
+ *
+ * Print the size/location of the IO MMU PDIR.
+ */
+static void
+sba_dump_tlb(char *hpa)
+{
+	DBG_INIT("IO TLB at 0x%p\n", (void *)hpa);
+	DBG_INIT("IOC_IBASE    : %016lx\n", READ_REG(hpa+IOC_IBASE));
+	DBG_INIT("IOC_IMASK    : %016lx\n", READ_REG(hpa+IOC_IMASK));
+	DBG_INIT("IOC_TCNFG    : %016lx\n", READ_REG(hpa+IOC_TCNFG));
+	DBG_INIT("IOC_PDIR_BASE: %016lx\n", READ_REG(hpa+IOC_PDIR_BASE));
+	DBG_INIT("\n");
+}
+#endif
+
+
+#ifdef ASSERT_PDIR_SANITY
+
+/**
+ * sba_dump_pdir_entry - debugging only - print one IOMMU PDIR entry
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @msg: text to print ont the output line.
+ * @pide: pdir index.
+ *
+ * Print one entry of the IO MMU PDIR in human readable form.
+ */
+static void
+sba_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide)
+{
+	/* start printing from lowest pde in rval */
+	u64 *ptr = &(ioc->pdir_base[pide  & ~(BITS_PER_LONG - 1)]);
+	unsigned long *rptr = (unsigned long *) &(ioc->res_map[(pide >>3) & ~(sizeof(unsigned long) - 1)]);
+	uint rcnt;
+
+	/* printk(KERN_DEBUG "SBA: %s rp %p bit %d rval 0x%lx\n", */
+	printk("SBA: %s rp %p bit %d rval 0x%lx\n",
+		 msg, rptr, pide & (BITS_PER_LONG - 1), *rptr);
+
+	rcnt = 0;
+	while (rcnt < BITS_PER_LONG) {
+		printk("%s %2d %p %016Lx\n",
+			(rcnt == (pide & (BITS_PER_LONG - 1)))
+				? "    -->" : "       ",
+			rcnt, ptr, *ptr );
+		rcnt++;
+		ptr++;
+	}
+	printk("%s", msg);
+}
+
+
+/**
+ * sba_check_pdir - debugging only - consistency checker
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @msg: text to print ont the output line.
+ *
+ * Verify the resource map and pdir state is consistent
+ */
+static int
+sba_check_pdir(struct ioc *ioc, char *msg)
+{
+	u64 *rptr_end = (u64 *) &(ioc->res_map[ioc->res_size]);
+	u64 *rptr = (u64 *) ioc->res_map;	/* resource map ptr */
+	u64 *pptr = ioc->pdir_base;	/* pdir ptr */
+	uint pide = 0;
+
+	while (rptr < rptr_end) {
+		u64 rval;
+		int rcnt; /* number of bits we might check */
+
+		rval = *rptr;
+		rcnt = 64;
+
+		while (rcnt) {
+			/* Get last byte and highest bit from that */
+			u32 pde = ((u32)((*pptr >> (63)) & 0x1));
+			if ((rval & 0x1) ^ pde)
+			{
+				/*
+				** BUMMER!  -- res_map != pdir --
+				** Dump rval and matching pdir entries
+				*/
+				sba_dump_pdir_entry(ioc, msg, pide);
+				return(1);
+			}
+			rcnt--;
+			rval >>= 1;	/* try the next bit */
+			pptr++;
+			pide++;
+		}
+		rptr++;	/* look at next word of res_map */
+	}
+	/* It'd be nice if we always got here :^) */
+	return 0;
+}
+
+
+/**
+ * sba_dump_sg - debugging only - print Scatter-Gather list
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg: head of the SG list
+ * @nents: number of entries in SG list
+ *
+ * print the SG list so we can verify it's correct by hand.
+ */
+static void
+sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents)
+{
+	while (nents-- > 0) {
+		printk(" %d : %08lx/%05x %p\n",
+				nents,
+				(unsigned long) sba_sg_iova(startsg),
+				sba_sg_len(startsg),
+				sba_sg_buffer(startsg));
+		startsg++;
+	}
+}
+static void
+sba_check_sg( struct ioc *ioc, struct scatterlist *startsg, int nents)
+{
+	struct scatterlist *the_sg = startsg;
+	int the_nents = nents;
+
+	while (the_nents-- > 0) {
+		if (sba_sg_buffer(the_sg) == 0x0UL)
+			sba_dump_sg(NULL, startsg, nents);
+		the_sg++;
+	}
+}
+
+#endif /* ASSERT_PDIR_SANITY */
+
+
+
+
+/**************************************************************
+*
+*   I/O Pdir Resource Management
+*
+*   Bits set in the resource map are in use.
+*   Each bit can represent a number of pages.
+*   LSbs represent lower addresses (IOVA's).
+*
+***************************************************************/
+#define PAGES_PER_RANGE 1	/* could increase this to 4 or 8 if needed */
+
+/* Convert from IOVP to IOVA and vice versa. */
+#define SBA_IOVA(ioc,iovp,offset,hint_reg) ((ioc->ibase) | (iovp) | (offset) | ((hint_reg)<<(ioc->hint_shift_pdir)))
+#define SBA_IOVP(ioc,iova) (((iova) & ioc->hint_mask_pdir) & ~(ioc->ibase))
+
+/* FIXME : review these macros to verify correctness and usage */
+#define PDIR_INDEX(iovp)   ((iovp)>>IOVP_SHIFT)
+
+#define RESMAP_MASK(n)    ~(~0UL << (n))
+#define RESMAP_IDX_MASK   (sizeof(unsigned long) - 1)
+
+
+/**
+ * sba_search_bitmap - find free space in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @bits_wanted: number of entries we need.
+ *
+ * Find consecutive free bits in resource bitmap.
+ * Each bit represents one entry in the IO Pdir.
+ * Cool perf optimization: search for log2(size) bits at a time.
+ */
+static SBA_INLINE unsigned long
+sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted)
+{
+	unsigned long *res_ptr = ioc->res_hint;
+	unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]);
+	unsigned long pide = ~0UL;
+
+	ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0);
+	ASSERT(res_ptr < res_end);
+	if (bits_wanted > (BITS_PER_LONG/2)) {
+		/* Search word at a time - no mask needed */
+		for(; res_ptr < res_end; ++res_ptr) {
+			if (*res_ptr == 0) {
+				*res_ptr = RESMAP_MASK(bits_wanted);
+				pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
+				pide <<= 3;	/* convert to bit address */
+				break;
+			}
+		}
+		/* point to the next word on next pass */
+		res_ptr++;
+		ioc->res_bitshift = 0;
+	} else {
+		/*
+		** Search the resource bit map on well-aligned values.
+		** "o" is the alignment.
+		** We need the alignment to invalidate I/O TLB using
+		** SBA HW features in the unmap path.
+		*/
+		unsigned long o = 1 << get_order(bits_wanted << PAGE_SHIFT);
+		uint bitshiftcnt = ROUNDUP(ioc->res_bitshift, o);
+		unsigned long mask;
+
+		if (bitshiftcnt >= BITS_PER_LONG) {
+			bitshiftcnt = 0;
+			res_ptr++;
+		}
+		mask = RESMAP_MASK(bits_wanted) << bitshiftcnt;
+
+		DBG_RES("%s() o %ld %p", __FUNCTION__, o, res_ptr);
+		while(res_ptr < res_end)
+		{ 
+			DBG_RES("    %p %lx %lx\n", res_ptr, mask, *res_ptr);
+			ASSERT(0 != mask);
+			if(0 == ((*res_ptr) & mask)) {
+				*res_ptr |= mask;     /* mark resources busy! */
+				pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
+				pide <<= 3;	/* convert to bit address */
+				pide += bitshiftcnt;
+				break;
+			}
+			mask <<= o;
+			bitshiftcnt += o;
+			if (0 == mask) {
+				mask = RESMAP_MASK(bits_wanted);
+				bitshiftcnt=0;
+				res_ptr++;
+			}
+		}
+		/* look in the same word on the next pass */
+		ioc->res_bitshift = bitshiftcnt + bits_wanted;
+	}
+
+	/* wrapped ? */
+	if (res_end <= res_ptr) {
+		ioc->res_hint = (unsigned long *) ioc->res_map;
+		ioc->res_bitshift = 0;
+	} else {
+		ioc->res_hint = res_ptr;
+	}
+	return (pide);
+}
+
+
+/**
+ * sba_alloc_range - find free bits and mark them in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @size: number of bytes to create a mapping for
+ *
+ * Given a size, find consecutive unmarked and then mark those bits in the
+ * resource bit map.
+ */
+static int
+sba_alloc_range(struct ioc *ioc, size_t size)
+{
+	unsigned int pages_needed = size >> IOVP_SHIFT;
+#ifdef CONFIG_PROC_FS
+	unsigned long itc_start = ia64_get_itc();
+#endif
+	unsigned long pide;
+
+	ASSERT(pages_needed);
+	ASSERT((pages_needed * IOVP_SIZE) <= DMA_CHUNK_SIZE);
+	ASSERT(pages_needed <= BITS_PER_LONG);
+	ASSERT(0 == (size & ~IOVP_MASK));
+
+	/*
+	** "seek and ye shall find"...praying never hurts either...
+	*/
+
+	pide = sba_search_bitmap(ioc, pages_needed);
+	if (pide >= (ioc->res_size << 3)) {
+		pide = sba_search_bitmap(ioc, pages_needed);
+		if (pide >= (ioc->res_size << 3))
+			panic(__FILE__ ": I/O MMU @ %lx is out of mapping resources\n", ioc->ioc_hpa);
+	}
+
+#ifdef ASSERT_PDIR_SANITY
+	/* verify the first enable bit is clear */
+	if(0x00 != ((u8 *) ioc->pdir_base)[pide*sizeof(u64) + 7]) {
+		sba_dump_pdir_entry(ioc, "sba_search_bitmap() botched it?", pide);
+	}
+#endif
+
+	DBG_RES("%s(%x) %d -> %lx hint %x/%x\n",
+		__FUNCTION__, size, pages_needed, pide,
+		(uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map),
+		ioc->res_bitshift );
+
+#ifdef CONFIG_PROC_FS
+	{
+		unsigned long itc_end = ia64_get_itc();
+		unsigned long tmp = itc_end - itc_start;
+		/* check for roll over */
+		itc_start = (itc_end < itc_start) ?  -(tmp) : (tmp);
+	}
+	ioc->avg_search[ioc->avg_idx++] = itc_start;
+	ioc->avg_idx &= SBA_SEARCH_SAMPLE - 1;
+
+	ioc->used_pages += pages_needed;
+#endif
+
+	return (pide);
+}
+
+
+/**
+ * sba_free_range - unmark bits in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @iova: IO virtual address which was previously allocated.
+ * @size: number of bytes to create a mapping for
+ *
+ * clear bits in the ioc's resource map
+ */
+static SBA_INLINE void
+sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size)
+{
+	unsigned long iovp = SBA_IOVP(ioc, iova);
+	unsigned int pide = PDIR_INDEX(iovp);
+	unsigned int ridx = pide >> 3;	/* convert bit to byte address */
+	unsigned long *res_ptr = (unsigned long *) &((ioc)->res_map[ridx & ~RESMAP_IDX_MASK]);
+
+	int bits_not_wanted = size >> IOVP_SHIFT;
+
+	/* 3-bits "bit" address plus 2 (or 3) bits for "byte" == bit in word */
+	unsigned long m = RESMAP_MASK(bits_not_wanted) << (pide & (BITS_PER_LONG - 1));
+
+	DBG_RES("%s( ,%x,%x) %x/%lx %x %p %lx\n",
+		__FUNCTION__, (uint) iova, size,
+		bits_not_wanted, m, pide, res_ptr, *res_ptr);
+
+#ifdef CONFIG_PROC_FS
+	ioc->used_pages -= bits_not_wanted;
+#endif
+
+	ASSERT(m != 0);
+	ASSERT(bits_not_wanted);
+	ASSERT((bits_not_wanted * IOVP_SIZE) <= DMA_CHUNK_SIZE);
+	ASSERT(bits_not_wanted <= BITS_PER_LONG);
+	ASSERT((*res_ptr & m) == m); /* verify same bits are set */
+	*res_ptr &= ~m;
+}
+
+
+/**************************************************************
+*
+*   "Dynamic DMA Mapping" support (aka "Coherent I/O")
+*
+***************************************************************/
+
+#define SBA_DMA_HINT(ioc, val) ((val) << (ioc)->hint_shift_pdir)
+
+
+/**
+ * sba_io_pdir_entry - fill in one IO PDIR entry
+ * @pdir_ptr:  pointer to IO PDIR entry
+ * @vba: Virtual CPU address of buffer to map
+ *
+ * SBA Mapping Routine
+ *
+ * Given a virtual address (vba, arg1) sba_io_pdir_entry()
+ * loads the I/O PDIR entry pointed to by pdir_ptr (arg0).
+ * Each IO Pdir entry consists of 8 bytes as shown below
+ * (LSB == bit 0):
+ *
+ *  63                    40                                 11    7        0
+ * +-+---------------------+----------------------------------+----+--------+
+ * |V|        U            |            PPN[39:12]            | U  |   FF   |
+ * +-+---------------------+----------------------------------+----+--------+
+ *
+ *  V  == Valid Bit
+ *  U  == Unused
+ * PPN == Physical Page Number
+ *
+ * The physical address fields are filled with the results of virt_to_phys()
+ * on the vba.
+ */
+
+#if 1
+#define sba_io_pdir_entry(pdir_ptr, vba) *pdir_ptr = ((vba & ~0xE000000000000FFFULL) | 0x8000000000000000ULL)
+#else
+void SBA_INLINE
+sba_io_pdir_entry(u64 *pdir_ptr, unsigned long vba)
+{
+	*pdir_ptr = ((vba & ~0xE000000000000FFFULL) | 0x80000000000000FFULL);
+}
+#endif
+
+#ifdef ENABLE_MARK_CLEAN
+/**
+ * Since DMA is i-cache coherent, any (complete) pages that were written via
+ * DMA can be marked as "clean" so that update_mmu_cache() doesn't have to
+ * flush them when they get mapped into an executable vm-area.
+ */
+static void
+mark_clean (void *addr, size_t size)
+{
+	unsigned long pg_addr, end;
+
+	pg_addr = PAGE_ALIGN((unsigned long) addr);
+	end = (unsigned long) addr + size;
+	while (pg_addr + PAGE_SIZE <= end) {
+		struct page *page = virt_to_page(pg_addr);
+		set_bit(PG_arch_1, &page->flags);
+		pg_addr += PAGE_SIZE;
+	}
+}
+#endif
+
+/**
+ * sba_mark_invalid - invalidate one or more IO PDIR entries
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @iova:  IO Virtual Address mapped earlier
+ * @byte_cnt:  number of bytes this mapping covers.
+ *
+ * Marking the IO PDIR entry(ies) as Invalid and invalidate
+ * corresponding IO TLB entry. The PCOM (Purge Command Register)
+ * is to purge stale entries in the IO TLB when unmapping entries.
+ *
+ * The PCOM register supports purging of multiple pages, with a minium
+ * of 1 page and a maximum of 2GB. Hardware requires the address be
+ * aligned to the size of the range being purged. The size of the range
+ * must be a power of 2. The "Cool perf optimization" in the
+ * allocation routine helps keep that true.
+ */
+static SBA_INLINE void
+sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
+{
+	u32 iovp = (u32) SBA_IOVP(ioc,iova);
+
+	int off = PDIR_INDEX(iovp);
+
+	/* Must be non-zero and rounded up */
+	ASSERT(byte_cnt > 0);
+	ASSERT(0 == (byte_cnt & ~IOVP_MASK));
+
+#ifdef ASSERT_PDIR_SANITY
+	/* Assert first pdir entry is set */
+	if (!(ioc->pdir_base[off] >> 60)) {
+		sba_dump_pdir_entry(ioc,"sba_mark_invalid()", PDIR_INDEX(iovp));
+	}
+#endif
+
+	if (byte_cnt <= IOVP_SIZE)
+	{
+		ASSERT(off < ioc->pdir_size);
+
+		iovp |= IOVP_SHIFT;     /* set "size" field for PCOM */
+
+		/*
+		** clear I/O PDIR entry "valid" bit
+		** Do NOT clear the rest - save it for debugging.
+		** We should only clear bits that have previously
+		** been enabled.
+		*/
+		ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+	} else {
+		u32 t = get_order(byte_cnt) + PAGE_SHIFT;
+
+		iovp |= t;
+		ASSERT(t <= 31);   /* 2GB! Max value of "size" field */
+
+		do {
+			/* verify this pdir entry is enabled */
+			ASSERT(ioc->pdir_base[off]  >> 63);
+			/* clear I/O Pdir entry "valid" bit first */
+			ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+			off++;
+			byte_cnt -= IOVP_SIZE;
+		} while (byte_cnt > 0);
+	}
+
+	WRITE_REG(iovp, ioc->ioc_hpa+IOC_PCOM);
+}
+
+/**
+ * sba_map_single - map one buffer and return IOVA for DMA
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @addr:  driver buffer to map.
+ * @size:  number of bytes to map in driver buffer.
+ * @direction:  R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+dma_addr_t
+sba_map_single(struct pci_dev *dev, void *addr, size_t size, int direction)
+{
+	struct ioc *ioc;
+	unsigned long flags; 
+	dma_addr_t iovp;
+	dma_addr_t offset;
+	u64 *pdir_start;
+	int pide;
+#ifdef ALLOW_IOV_BYPASS
+	unsigned long pci_addr = virt_to_phys(addr);
+#endif
+
+	ioc = GET_IOC(dev);
+	ASSERT(ioc);
+
+#ifdef ALLOW_IOV_BYPASS
+	/*
+ 	** Check if the PCI device can DMA to ptr... if so, just return ptr
+ 	*/
+	if ((pci_addr & ~dev->dma_mask) == 0) {
+		/*
+ 		** Device is bit capable of DMA'ing to the buffer...
+		** just return the PCI address of ptr
+ 		*/
+#ifdef CONFIG_PROC_FS
+		spin_lock_irqsave(&ioc->res_lock, flags);
+		ioc->msingle_bypass++;
+		spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+		DBG_BYPASS("sba_map_single() bypass mask/addr: 0x%lx/0x%lx\n",
+		           dev->dma_mask, pci_addr);
+		return pci_addr;
+	}
+#endif
+
+	ASSERT(size > 0);
+	ASSERT(size <= DMA_CHUNK_SIZE);
+
+	/* save offset bits */
+	offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK;
+
+	/* round up to nearest IOVP_SIZE */
+	size = (size + offset + ~IOVP_MASK) & IOVP_MASK;
+
+	spin_lock_irqsave(&ioc->res_lock, flags);
+#ifdef ASSERT_PDIR_SANITY
+	if (sba_check_pdir(ioc,"Check before sba_map_single()"))
+		panic("Sanity check failed");
+#endif
+
+#ifdef CONFIG_PROC_FS
+	ioc->msingle_calls++;
+	ioc->msingle_pages += size >> IOVP_SHIFT;
+#endif
+	pide = sba_alloc_range(ioc, size);
+	iovp = (dma_addr_t) pide << IOVP_SHIFT;
+
+	DBG_RUN("%s() 0x%p -> 0x%lx\n",
+		__FUNCTION__, addr, (long) iovp | offset);
+
+	pdir_start = &(ioc->pdir_base[pide]);
+
+	while (size > 0) {
+		ASSERT(((u8 *)pdir_start)[7] == 0); /* verify availability */
+		sba_io_pdir_entry(pdir_start, (unsigned long) addr);
+
+		DBG_RUN("     pdir 0x%p %lx\n", pdir_start, *pdir_start);
+
+		addr += IOVP_SIZE;
+		size -= IOVP_SIZE;
+		pdir_start++;
+	}
+	/* form complete address */
+#ifdef ASSERT_PDIR_SANITY
+	sba_check_pdir(ioc,"Check after sba_map_single()");
+#endif
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
+	return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG);
+}
+
+/**
+ * sba_unmap_single - unmap one IOVA and free resources
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @iova:  IOVA of driver buffer previously mapped.
+ * @size:  number of bytes mapped in driver buffer.
+ * @direction:  R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+void sba_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size,
+		int direction)
+{
+	struct ioc *ioc;
+#if DELAYED_RESOURCE_CNT > 0
+	struct sba_dma_pair *d;
+#endif
+	unsigned long flags; 
+	dma_addr_t offset;
+
+	ioc = GET_IOC(dev);
+	ASSERT(ioc);
+
+#ifdef ALLOW_IOV_BYPASS
+	if ((iova & ioc->imask) != ioc->ibase) {
+		/*
+		** Address does not fall w/in IOVA, must be bypassing
+		*/
+#ifdef CONFIG_PROC_FS
+		spin_lock_irqsave(&ioc->res_lock, flags);
+		ioc->usingle_bypass++;
+		spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+		DBG_BYPASS("sba_unmap_single() bypass addr: 0x%lx\n", iova);
+
+#ifdef ENABLE_MARK_CLEAN
+		if (direction == PCI_DMA_FROMDEVICE) {
+			mark_clean(phys_to_virt(iova), size);
+		}
+#endif
+		return;
+	}
+#endif
+	offset = iova & ~IOVP_MASK;
+
+	DBG_RUN("%s() iovp 0x%lx/%x\n",
+		__FUNCTION__, (long) iova, size);
+
+	iova ^= offset;        /* clear offset bits */
+	size += offset;
+	size = ROUNDUP(size, IOVP_SIZE);
+
+	spin_lock_irqsave(&ioc->res_lock, flags);
+#ifdef CONFIG_PROC_FS
+	ioc->usingle_calls++;
+	ioc->usingle_pages += size >> IOVP_SHIFT;
+#endif
+
+#if DELAYED_RESOURCE_CNT > 0
+	d = &(ioc->saved[ioc->saved_cnt]);
+	d->iova = iova;
+	d->size = size;
+	if (++(ioc->saved_cnt) >= DELAYED_RESOURCE_CNT) {
+		int cnt = ioc->saved_cnt;
+		while (cnt--) {
+			sba_mark_invalid(ioc, d->iova, d->size);
+			sba_free_range(ioc, d->iova, d->size);
+			d--;
+		}
+		ioc->saved_cnt = 0;
+		READ_REG(ioc->ioc_hpa+IOC_PCOM);	/* flush purges */
+	}
+#else /* DELAYED_RESOURCE_CNT == 0 */
+	sba_mark_invalid(ioc, iova, size);
+	sba_free_range(ioc, iova, size);
+	READ_REG(ioc->ioc_hpa+IOC_PCOM);	/* flush purges */
+#endif /* DELAYED_RESOURCE_CNT == 0 */
+#ifdef ENABLE_MARK_CLEAN
+	if (direction == PCI_DMA_FROMDEVICE) {
+		u32 iovp = (u32) SBA_IOVP(ioc,iova);
+		int off = PDIR_INDEX(iovp);
+		void *addr;
+
+		if (size <= IOVP_SIZE) {
+			addr = phys_to_virt(ioc->pdir_base[off] &
+					    ~0xE000000000000FFFULL);
+			mark_clean(addr, size);
+		} else {
+			size_t byte_cnt = size;
+
+			do {
+				addr = phys_to_virt(ioc->pdir_base[off] &
+				                    ~0xE000000000000FFFULL);
+				mark_clean(addr, min(byte_cnt, IOVP_SIZE));
+				off++;
+				byte_cnt -= IOVP_SIZE;
+
+			   } while (byte_cnt > 0);
+		}
+	}
+#endif
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
+
+	/* XXX REVISIT for 2.5 Linux - need syncdma for zero-copy support.
+	** For Astro based systems this isn't a big deal WRT performance.
+	** As long as 2.4 kernels copyin/copyout data from/to userspace,
+	** we don't need the syncdma. The issue here is I/O MMU cachelines
+	** are *not* coherent in all cases.  May be hwrev dependent.
+	** Need to investigate more.
+	asm volatile("syncdma");	
+	*/
+}
+
+
+/**
+ * sba_alloc_consistent - allocate/map shared mem for DMA
+ * @hwdev: instance of PCI owned by the driver that's asking.
+ * @size:  number of bytes mapped in driver buffer.
+ * @dma_handle:  IOVA of new buffer.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+void *
+sba_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
+{
+	struct ioc *ioc;
+	void *ret;
+
+	if (!hwdev) {
+		/* only support PCI */
+		*dma_handle = 0;
+		return 0;
+	}
+
+        ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size));
+
+	if (ret) {
+		memset(ret, 0, size);
+		/*
+		 * REVISIT: if sba_map_single starts needing more
+		 * than dma_mask from the device, this needs to be
+		 * updated.
+		 */
+		ioc = GET_IOC(hwdev);
+		*dma_handle = sba_map_single(ioc->sac_only_dev, ret, size, 0);
+	}
+
+	return ret;
+}
+
+
+/**
+ * sba_free_consistent - free/unmap shared mem for DMA
+ * @hwdev: instance of PCI owned by the driver that's asking.
+ * @size:  number of bytes mapped in driver buffer.
+ * @vaddr:  virtual address IOVA of "consistent" buffer.
+ * @dma_handler:  IO virtual address of "consistent" buffer.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+void sba_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr,
+		dma_addr_t dma_handle)
+{
+	sba_unmap_single(hwdev, dma_handle, size, 0);
+	free_pages((unsigned long) vaddr, get_order(size));
+}
+
+
+/*
+** Since 0 is a valid pdir_base index value, can't use that
+** to determine if a value is valid or not. Use a flag to indicate
+** the SG list entry contains a valid pdir index.
+*/
+#define PIDE_FLAG 0x1UL
+
+#ifdef DEBUG_LARGE_SG_ENTRIES
+int dump_run_sg = 0;
+#endif
+
+
+/**
+ * sba_fill_pdir - write allocated SG entries into IO PDIR
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg:  list of IOVA/size pairs
+ * @nents: number of entries in startsg list
+ *
+ * Take preprocessed SG list and write corresponding entries
+ * in the IO PDIR.
+ */
+
+static SBA_INLINE int
+sba_fill_pdir(
+	struct ioc *ioc,
+	struct scatterlist *startsg,
+	int nents)
+{
+	struct scatterlist *dma_sg = startsg;	/* pointer to current DMA */
+	int n_mappings = 0;
+	u64 *pdirp = 0;
+	unsigned long dma_offset = 0;
+
+	dma_sg--;
+	while (nents-- > 0) {
+		int     cnt = sba_sg_len(startsg);
+		sba_sg_len(startsg) = 0;
+
+#ifdef DEBUG_LARGE_SG_ENTRIES
+		if (dump_run_sg)
+			printk(" %2d : %08lx/%05x %p\n",
+				nents,
+				(unsigned long) sba_sg_iova(startsg), cnt,
+				sba_sg_buffer(startsg)
+		);
+#else
+		DBG_RUN_SG(" %d : %08lx/%05x %p\n",
+				nents,
+				(unsigned long) sba_sg_iova(startsg), cnt,
+				sba_sg_buffer(startsg)
+		);
+#endif
+		/*
+		** Look for the start of a new DMA stream
+		*/
+		if ((u64)sba_sg_iova(startsg) & PIDE_FLAG) {
+			u32 pide = (u64)sba_sg_iova(startsg) & ~PIDE_FLAG;
+			dma_offset = (unsigned long) pide & ~IOVP_MASK;
+			sba_sg_iova(startsg) = 0;
+			dma_sg++;
+			sba_sg_iova(dma_sg) = (char *)(pide | ioc->ibase);
+			pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]);
+			n_mappings++;
+		}
+
+		/*
+		** Look for a VCONTIG chunk
+		*/
+		if (cnt) {
+			unsigned long vaddr = (unsigned long) sba_sg_buffer(startsg);
+			ASSERT(pdirp);
+
+			/* Since multiple Vcontig blocks could make up
+			** one DMA stream, *add* cnt to dma_len.
+			*/
+			sba_sg_len(dma_sg) += cnt;
+			cnt += dma_offset;
+			dma_offset=0;	/* only want offset on first chunk */
+			cnt = ROUNDUP(cnt, IOVP_SIZE);
+#ifdef CONFIG_PROC_FS
+			ioc->msg_pages += cnt >> IOVP_SHIFT;
+#endif
+			do {
+				sba_io_pdir_entry(pdirp, vaddr);
+				vaddr += IOVP_SIZE;
+				cnt -= IOVP_SIZE;
+				pdirp++;
+			} while (cnt > 0);
+		}
+		startsg++;
+	}
+#ifdef DEBUG_LARGE_SG_ENTRIES
+	dump_run_sg = 0;
+#endif
+	return(n_mappings);
+}
+
+
+/*
+** Two address ranges are DMA contiguous *iff* "end of prev" and
+** "start of next" are both on a page boundry.
+**
+** (shift left is a quick trick to mask off upper bits)
+*/
+#define DMA_CONTIG(__X, __Y) \
+	(((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL)
+
+
+/**
+ * sba_coalesce_chunks - preprocess the SG list
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg:  list of IOVA/size pairs
+ * @nents: number of entries in startsg list
+ *
+ * First pass is to walk the SG list and determine where the breaks are
+ * in the DMA stream. Allocates PDIR entries but does not fill them.
+ * Returns the number of DMA chunks.
+ *
+ * Doing the fill seperate from the coalescing/allocation keeps the
+ * code simpler. Future enhancement could make one pass through
+ * the sglist do both.
+ */
+static SBA_INLINE int
+sba_coalesce_chunks( struct ioc *ioc,
+	struct scatterlist *startsg,
+	int nents)
+{
+	struct scatterlist *vcontig_sg;    /* VCONTIG chunk head */
+	unsigned long vcontig_len;         /* len of VCONTIG chunk */
+	unsigned long vcontig_end;
+	struct scatterlist *dma_sg;        /* next DMA stream head */
+	unsigned long dma_offset, dma_len; /* start/len of DMA stream */
+	int n_mappings = 0;
+
+	while (nents > 0) {
+		unsigned long vaddr = (unsigned long) (startsg->address); 
+
+		/*
+		** Prepare for first/next DMA stream
+		*/
+		dma_sg = vcontig_sg = startsg;
+		dma_len = vcontig_len = vcontig_end = sba_sg_len(startsg);
+		vcontig_end +=  vaddr;
+		dma_offset = vaddr & ~IOVP_MASK;
+
+		/* PARANOID: clear entries */
+		sba_sg_buffer(startsg) = sba_sg_iova(startsg);
+		sba_sg_iova(startsg) = 0;
+		sba_sg_len(startsg) = 0;
+
+		/*
+		** This loop terminates one iteration "early" since
+		** it's always looking one "ahead".
+		*/
+		while (--nents > 0) {
+			unsigned long vaddr;	/* tmp */
+
+			startsg++;
+
+			/* catch brokenness in SCSI layer */
+			ASSERT(startsg->length <= DMA_CHUNK_SIZE);
+
+			/*
+			** First make sure current dma stream won't
+			** exceed DMA_CHUNK_SIZE if we coalesce the
+			** next entry.
+			*/
+			if (((dma_len + dma_offset + startsg->length + ~IOVP_MASK) & IOVP_MASK) > DMA_CHUNK_SIZE)
+				break;
+
+			/*
+			** Then look for virtually contiguous blocks.
+			**
+			** append the next transaction?
+			*/
+			vaddr = (unsigned long) sba_sg_iova(startsg);
+			if  (vcontig_end == vaddr)
+			{
+				vcontig_len += sba_sg_len(startsg);
+				vcontig_end += sba_sg_len(startsg);
+				dma_len     += sba_sg_len(startsg);
+				sba_sg_buffer(startsg) = (char *)vaddr;
+				sba_sg_iova(startsg) = 0;
+				sba_sg_len(startsg) = 0;
+				continue;
+			}
+
+#ifdef DEBUG_LARGE_SG_ENTRIES
+			dump_run_sg = (vcontig_len > IOVP_SIZE);
+#endif
+
+			/*
+			** Not virtually contigous.
+			** Terminate prev chunk.
+			** Start a new chunk.
+			**
+			** Once we start a new VCONTIG chunk, dma_offset
+			** can't change. And we need the offset from the first
+			** chunk - not the last one. Ergo Successive chunks
+			** must start on page boundaries and dove tail
+			** with it's predecessor.
+			*/
+			sba_sg_len(vcontig_sg) = vcontig_len;
+
+			vcontig_sg = startsg;
+			vcontig_len = sba_sg_len(startsg);
+
+			/*
+			** 3) do the entries end/start on page boundaries?
+			**    Don't update vcontig_end until we've checked.
+			*/
+			if (DMA_CONTIG(vcontig_end, vaddr))
+			{
+				vcontig_end = vcontig_len + vaddr;
+				dma_len += vcontig_len;
+				sba_sg_buffer(startsg) = (char *)vaddr;
+				sba_sg_iova(startsg) = 0;
+				continue;
+			} else {
+				break;
+			}
+		}
+
+		/*
+		** End of DMA Stream
+		** Terminate last VCONTIG block.
+		** Allocate space for DMA stream.
+		*/
+		sba_sg_len(vcontig_sg) = vcontig_len;
+		dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK;
+		ASSERT(dma_len <= DMA_CHUNK_SIZE);
+		sba_sg_iova(dma_sg) = (char *) (PIDE_FLAG 
+			| (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT)
+			| dma_offset);
+		n_mappings++;
+	}
+
+	return n_mappings;
+}
+
+
+/**
+ * sba_map_sg - map Scatter/Gather list
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @sglist:  array of buffer/length pairs
+ * @nents:  number of entries in list
+ * @direction:  R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+int sba_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents,
+		int direction)
+{
+	struct ioc *ioc;
+	int coalesced, filled = 0;
+	unsigned long flags;
+#ifdef ALLOW_IOV_BYPASS
+	struct scatterlist *sg;
+#endif
+
+	DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents);
+	ioc = GET_IOC(dev);
+	ASSERT(ioc);
+
+#ifdef ALLOW_IOV_BYPASS
+	if (dev->dma_mask >= ioc->dma_mask) {
+		for (sg = sglist ; filled < nents ; filled++, sg++){
+			sba_sg_buffer(sg) = sba_sg_iova(sg);
+			sba_sg_iova(sg) = (char *)virt_to_phys(sba_sg_buffer(sg));
+		}
+#ifdef CONFIG_PROC_FS
+		spin_lock_irqsave(&ioc->res_lock, flags);
+		ioc->msg_bypass++;
+		spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+		return filled;
+	}
+#endif
+	/* Fast path single entry scatterlists. */
+	if (nents == 1) {
+		sba_sg_buffer(sglist) = sba_sg_iova(sglist);
+		sba_sg_iova(sglist) = (char *)sba_map_single(dev,
+						sba_sg_buffer(sglist),
+						sba_sg_len(sglist), direction);
+#ifdef CONFIG_PROC_FS
+		/*
+		** Should probably do some stats counting, but trying to
+		** be precise quickly starts wasting CPU time.
+		*/
+#endif
+		return 1;
+	}
+
+	spin_lock_irqsave(&ioc->res_lock, flags);
+
+#ifdef ASSERT_PDIR_SANITY
+	if (sba_check_pdir(ioc,"Check before sba_map_sg()"))
+	{
+		sba_dump_sg(ioc, sglist, nents);
+		panic("Check before sba_map_sg()");
+	}
+#endif
+
+#ifdef CONFIG_PROC_FS
+	ioc->msg_calls++;
+#endif
+
+	/*
+	** First coalesce the chunks and allocate I/O pdir space
+	**
+	** If this is one DMA stream, we can properly map using the
+	** correct virtual address associated with each DMA page.
+	** w/o this association, we wouldn't have coherent DMA!
+	** Access to the virtual address is what forces a two pass algorithm.
+	*/
+	coalesced = sba_coalesce_chunks(ioc, sglist, nents);
+ 
+	/*
+	** Program the I/O Pdir
+	**
+	** map the virtual addresses to the I/O Pdir
+	** o dma_address will contain the pdir index
+	** o dma_len will contain the number of bytes to map 
+	** o address contains the virtual address.
+	*/
+	filled = sba_fill_pdir(ioc, sglist, nents);
+
+#ifdef ASSERT_PDIR_SANITY
+	if (sba_check_pdir(ioc,"Check after sba_map_sg()"))
+	{
+		sba_dump_sg(ioc, sglist, nents);
+		panic("Check after sba_map_sg()\n");
+	}
+#endif
+
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
+
+	ASSERT(coalesced == filled);
+	DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled);
+
+	return filled;
+}
+
+
+/**
+ * sba_unmap_sg - unmap Scatter/Gather list
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @sglist:  array of buffer/length pairs
+ * @nents:  number of entries in list
+ * @direction:  R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+void sba_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents,
+		int direction)
+{
+	struct ioc *ioc;
+#ifdef ASSERT_PDIR_SANITY
+	unsigned long flags;
+#endif
+
+	DBG_RUN_SG("%s() START %d entries,  %p,%x\n",
+		__FUNCTION__, nents, sba_sg_buffer(sglist), sglist->length);
+
+	ioc = GET_IOC(dev);
+	ASSERT(ioc);
+
+#ifdef CONFIG_PROC_FS
+	ioc->usg_calls++;
+#endif
+
+#ifdef ASSERT_PDIR_SANITY
+	spin_lock_irqsave(&ioc->res_lock, flags);
+	sba_check_pdir(ioc,"Check before sba_unmap_sg()");
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+
+	while (sba_sg_len(sglist) && nents--) {
+
+		sba_unmap_single(dev, (dma_addr_t)sba_sg_iova(sglist),
+		                 sba_sg_len(sglist), direction);
+#ifdef CONFIG_PROC_FS
+		/*
+		** This leaves inconsistent data in the stats, but we can't
+		** tell which sg lists were mapped by map_single and which
+		** were coalesced to a single entry.  The stats are fun,
+		** but speed is more important.
+		*/
+		ioc->usg_pages += (((u64)sba_sg_iova(sglist) & ~IOVP_MASK) + sba_sg_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;
+#endif
+		++sglist;
+	}
+
+	DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__,  nents);
+
+#ifdef ASSERT_PDIR_SANITY
+	spin_lock_irqsave(&ioc->res_lock, flags);
+	sba_check_pdir(ioc,"Check after sba_unmap_sg()");
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+
+}
+
+unsigned long
+sba_dma_address (struct scatterlist *sg)
+{
+	return ((unsigned long)sba_sg_iova(sg));
+}
+
+int
+sba_dma_supported (struct pci_dev *dev, u64 mask)
+{
+	return 1;
+}
+
+/**************************************************************
+*
+*   Initialization and claim
+*
+***************************************************************/
+
+static void __init
+ioc_iova_init(struct ioc *ioc)
+{
+	u32 iova_space_mask;
+	int iov_order, tcnfg;
+	int agp_found = 0;
+	struct pci_dev *device;
+
+	/*
+	** Firmware programs the base and size of a "safe IOVA space"
+	** (one that doesn't overlap memory or LMMIO space) in the
+	** IBASE and IMASK registers.
+	*/
+	ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE) & ~0x1UL;
+	ioc->iov_size = ~(READ_REG(ioc->ioc_hpa + IOC_IMASK) & 0xFFFFFFFFUL) + 1;
+
+	if (ioc->ibase == 0) {
+		if (((unsigned long) ioc->ioc_hpa & 0x3000UL) == 0x2000)
+			ioc->ibase = 0xc0000000;
+		else
+			ioc->ibase = 0x80000000;
+		printk("WARNING: IBASE is zero; setting to 0x%lx\n", ioc->ibase);
+	}
+
+	if (ioc->ibase < 0xfed00000UL && ioc->ibase + ioc->iov_size >= 0xfee00000UL) {
+		printk("WARNING: IOV space overlaps local config and interrupt message, truncating\n");
+		ioc->iov_size /= 2;
+	}
+
+	/*
+	** iov_order is always based on a 1GB IOVA space since we want to
+	** turn on the other half for AGP GART.
+	*/
+	iov_order = get_order(ioc->iov_size >> (IOVP_SHIFT - PAGE_SHIFT));
+	ioc->pdir_size = (ioc->iov_size / IOVP_SIZE) * sizeof(u64);
+
+	DBG_INIT("%s() hpa 0x%lx IOV %dMB (%d bits) PDIR size 0x%0x\n",
+		__FUNCTION__, ioc->ioc_hpa, ioc->iov_size >> 20,
+		iov_order + PAGE_SHIFT, ioc->pdir_size);
+
+	/* FIXME : DMA HINTs not used */
+	ioc->hint_shift_pdir = iov_order + PAGE_SHIFT;
+	ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT));
+
+	ioc->pdir_base = (void *) __get_free_pages(GFP_KERNEL,
+						   get_order(ioc->pdir_size));
+	if (!ioc->pdir_base)
+		panic(PFX "Couldn't allocate I/O Page Table\n");
+
+	memset(ioc->pdir_base, 0, ioc->pdir_size);
+
+	DBG_INIT("%s() pdir %p size %x hint_shift_pdir %x hint_mask_pdir %lx\n",
+		__FUNCTION__, ioc->pdir_base, ioc->pdir_size,
+		ioc->hint_shift_pdir, ioc->hint_mask_pdir);
+
+	ASSERT((((unsigned long) ioc->pdir_base) & PAGE_MASK) == (unsigned long) ioc->pdir_base);
+	WRITE_REG(virt_to_phys(ioc->pdir_base), ioc->ioc_hpa + IOC_PDIR_BASE);
+
+	DBG_INIT(" base %p\n", ioc->pdir_base);
+
+	/* build IMASK for IOC and Elroy */
+	iova_space_mask =  0xffffffff;
+	iova_space_mask <<= (iov_order + PAGE_SHIFT);
+	ioc->imask = iova_space_mask;
+
+	DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n",
+		__FUNCTION__, ioc->ibase, ioc->imask);
+
+	/*
+	** FIXME: Hint registers are programmed with default hint
+	** values during boot, so hints should be sane even if we
+	** can't reprogram them the way drivers want.
+	*/
+	WRITE_REG(ioc->imask, ioc->ioc_hpa + IOC_IMASK);
+
+	/*
+	** Setting the upper bits makes checking for bypass addresses
+	** a little faster later on.
+	*/
+	ioc->imask |= 0xFFFFFFFF00000000UL;
+
+	/* Set I/O PDIR Page size to system page size */
+	switch (PAGE_SHIFT) {
+		case 12: tcnfg = 0; break;	/*  4K */
+		case 13: tcnfg = 1; break;	/*  8K */
+		case 14: tcnfg = 2; break;	/* 16K */
+		case 16: tcnfg = 3; break;	/* 64K */
+		default:
+			panic(PFX "Unsupported system page size %d",
+				1 << PAGE_SHIFT);
+			break;
+	}
+	WRITE_REG(tcnfg, ioc->ioc_hpa + IOC_TCNFG);
+
+	/*
+	** Program the IOC's ibase and enable IOVA translation
+	** Bit zero == enable bit.
+	*/
+	WRITE_REG(ioc->ibase | 1, ioc->ioc_hpa + IOC_IBASE);
+
+	/*
+	** Clear I/O TLB of any possible entries.
+	** (Yes. This is a bit paranoid...but so what)
+	*/
+	WRITE_REG(0 | 31, ioc->ioc_hpa + IOC_PCOM);
+
+	/*
+	** If an AGP device is present, only use half of the IOV space
+	** for PCI DMA.  Unfortunately we can't know ahead of time
+	** whether GART support will actually be used, for now we
+	** can just key on an AGP device found in the system.
+	** We program the next pdir index after we stop w/ a key for
+	** the GART code to handshake on.
+	*/
+	pci_for_each_dev(device)
+		agp_found |= pci_find_capability(device, PCI_CAP_ID_AGP);
+
+	if (agp_found && reserve_sba_gart) {
+		DBG_INIT("%s: AGP device found, reserving half of IOVA for GART support\n", __FUNCTION__);
+		ioc->pdir_size /= 2;
+		((u64 *)ioc->pdir_base)[PDIR_INDEX(ioc->iov_size/2)] = ZX1_SBA_IOMMU_COOKIE;
+	}
+}
+
+static void __init
+ioc_resource_init(struct ioc *ioc)
+{
+	spin_lock_init(&ioc->res_lock);
+
+	/* resource map size dictated by pdir_size */
+	ioc->res_size = ioc->pdir_size / sizeof(u64); /* entries */
+	ioc->res_size >>= 3;  /* convert bit count to byte count */
+	DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, ioc->res_size);
+
+	ioc->res_map = (char *) __get_free_pages(GFP_KERNEL,
+						 get_order(ioc->res_size));
+	if (!ioc->res_map)
+		panic(PFX "Couldn't allocate resource map\n");
+
+	memset(ioc->res_map, 0, ioc->res_size);
+	/* next available IOVP - circular search */
+	ioc->res_hint = (unsigned long *) ioc->res_map;
+
+#ifdef ASSERT_PDIR_SANITY
+	/* Mark first bit busy - ie no IOVA 0 */
+	ioc->res_map[0] = 0x1;
+	ioc->pdir_base[0] = 0x8000000000000000ULL | ZX1_SBA_IOMMU_COOKIE;
+#endif
+
+	DBG_INIT("%s() res_map %x %p\n", __FUNCTION__,
+		 ioc->res_size, (void *) ioc->res_map);
+}
+
+static void __init
+ioc_sac_init(struct ioc *ioc)
+{
+	struct pci_dev *sac = NULL;
+	struct pci_controller *controller = NULL;
+
+	/*
+	 * pci_alloc_consistent() must return a DMA address which is
+	 * SAC (single address cycle) addressable, so allocate a
+	 * pseudo-device to enforce that.
+	 */
+	sac = kmalloc(sizeof(*sac), GFP_KERNEL);
+	if (!sac)
+		panic(PFX "Couldn't allocate struct pci_dev");
+	memset(sac, 0, sizeof(*sac));
+
+	controller = kmalloc(sizeof(*controller), GFP_KERNEL);
+	if (!controller)
+		panic(PFX "Couldn't allocate struct pci_controller");
+	memset(controller, 0, sizeof(*controller));
+
+	controller->iommu = ioc;
+	sac->sysdata = controller;
+	sac->dma_mask = 0xFFFFFFFFUL;
+	ioc->sac_only_dev = sac;
+}
+
+static void __init
+ioc_zx1_init(struct ioc *ioc)
+{
+	if (ioc->rev < 0x20)
+		panic(PFX "IOC 2.0 or later required for IOMMU support\n");
+
+	ioc->dma_mask = 0xFFFFFFFFFFUL;
+}
+
+typedef void (initfunc)(struct ioc *);
+
+struct ioc_iommu {
+	u32 func_id;
+	char *name;
+	initfunc *init;
+};
+
+static struct ioc_iommu ioc_iommu_info[] __initdata = {
+	{ ZX1_IOC_ID, "zx1", ioc_zx1_init },
+	{ REO_IOC_ID, "REO" },
+};
+
+static struct ioc * __init
+ioc_init(u64 hpa, void *handle)
+{
+	struct ioc *ioc;
+	struct ioc_iommu *info;
+
+	ioc = kmalloc(sizeof(*ioc), GFP_KERNEL);
+	if (!ioc)
+		return NULL;
+
+	memset(ioc, 0, sizeof(*ioc));
+
+	ioc->next = ioc_list;
+	ioc_list = ioc;
+
+	ioc->handle = handle;
+	ioc->ioc_hpa = ioremap(hpa, 0x1000);
+
+	ioc->func_id = READ_REG(ioc->ioc_hpa + IOC_FUNC_ID);
+	ioc->rev = READ_REG(ioc->ioc_hpa + IOC_FCLASS) & 0xFFUL;
+	ioc->dma_mask = 0xFFFFFFFFFFFFFFFFUL;	/* conservative */
+
+	for (info = ioc_iommu_info; info < ioc_iommu_info + ARRAY_SIZE(ioc_iommu_info); info++) {
+		if (ioc->func_id == info->func_id) {
+			ioc->name = info->name;
+			if (info->init)
+				(info->init)(ioc);
+		}
+	}
+	if (!ioc->name)
+		ioc->name = "Unknown";
+
+	ioc_iova_init(ioc);
+	ioc_resource_init(ioc);
+	ioc_sac_init(ioc);
+
+	printk(KERN_INFO PFX
+		"Found %s IOC %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n",
+		ioc->name, (ioc->rev >> 4) & 0xF, ioc->rev & 0xF,
+		hpa, ioc->iov_size >> 20, ioc->ibase);
+
+	return ioc;
+}
+
+
+
+/**************************************************************************
+**
+**   SBA initialization code (HW and SW)
+**
+**   o identify SBA chip itself
+**   o FIXME: initialize DMA hints for reasonable defaults
+**
+**************************************************************************/
+
+#ifdef CONFIG_PROC_FS
+static int
+sba_proc_info_one(char *buf, struct ioc *ioc)
+{
+	int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */
+	unsigned long i = 0, avg = 0, min, max;
+
+	sprintf(buf, "Hewlett Packard %s IOC rev %d.%d\n",
+		ioc->name, ((ioc->rev >> 4) & 0xF), (ioc->rev & 0xF));
+	sprintf(buf, "%sIO PDIR size    : %d bytes (%d entries)\n",
+		buf,
+		(int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */
+		total_pages);
+
+	sprintf(buf, "%sIO PDIR entries : %ld free  %ld used (%d%%)\n", buf,
+		total_pages - ioc->used_pages, ioc->used_pages,
+		(int) (ioc->used_pages * 100 / total_pages));
+	
+	sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", 
+		buf, ioc->res_size, ioc->res_size << 3);   /* 8 bits per byte */
+
+	min = max = ioc->avg_search[0];
+	for (i = 0; i < SBA_SEARCH_SAMPLE; i++) {
+		avg += ioc->avg_search[i];
+		if (ioc->avg_search[i] > max) max = ioc->avg_search[i];
+		if (ioc->avg_search[i] < min) min = ioc->avg_search[i];
+	}
+	avg /= SBA_SEARCH_SAMPLE;
+	sprintf(buf, "%s  Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
+		buf, min, avg, max);
+
+	sprintf(buf, "%spci_map_single(): %12ld calls  %12ld pages (avg %d/1000)\n",
+		buf, ioc->msingle_calls, ioc->msingle_pages,
+		(int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls));
+#ifdef ALLOW_IOV_BYPASS
+	sprintf(buf, "%spci_map_single(): %12ld bypasses\n",
+	        buf, ioc->msingle_bypass);
+#endif
+
+	sprintf(buf, "%spci_unmap_single: %12ld calls  %12ld pages (avg %d/1000)\n",
+		buf, ioc->usingle_calls, ioc->usingle_pages,
+		(int) ((ioc->usingle_pages * 1000)/ioc->usingle_calls));
+#ifdef ALLOW_IOV_BYPASS
+	sprintf(buf, "%spci_unmap_single: %12ld bypasses\n",
+	        buf, ioc->usingle_bypass);
+#endif
+
+	sprintf(buf, "%spci_map_sg()    : %12ld calls  %12ld pages (avg %d/1000)\n",
+		buf, ioc->msg_calls, ioc->msg_pages,
+		(int) ((ioc->msg_pages * 1000)/ioc->msg_calls));
+#ifdef ALLOW_IOV_BYPASS
+	sprintf(buf, "%spci_map_sg()    : %12ld bypasses\n",
+	        buf, ioc->msg_bypass);
+#endif
+
+	sprintf(buf, "%spci_unmap_sg()  : %12ld calls  %12ld pages (avg %d/1000)\n",
+		buf, ioc->usg_calls, ioc->usg_pages,
+		(int) ((ioc->usg_pages * 1000)/ioc->usg_calls));
+
+	return strlen(buf);
+}
+
+static int
+sba_proc_info(char *buf, char **start, off_t offset, int len)
+{
+	struct ioc *ioc;
+	char *base = buf;
+
+	for (ioc = ioc_list; ioc; ioc = ioc->next) {
+		buf += sba_proc_info_one(buf, ioc);
+	}
+
+	return strlen(base);
+}
+
+static int
+sba_resource_map_one(char *buf, struct ioc *ioc)
+{
+	unsigned int *res_ptr = (unsigned int *)ioc->res_map;
+	int i;
+
+	buf[0] = '\0';
+	for(i = 0; i < (ioc->res_size / sizeof(unsigned int)); ++i, ++res_ptr) {
+		if ((i & 7) == 0)
+		    strcat(buf,"\n   ");
+		sprintf(buf, "%s %08x", buf, *res_ptr);
+	}
+	strcat(buf, "\n");
+
+	return strlen(buf);
+}
+
+static int
+sba_resource_map(char *buf, char **start, off_t offset, int len)
+{
+	struct ioc *ioc;
+	char *base = buf;
+
+	for (ioc = ioc_list; ioc; ioc = ioc->next) {
+		buf += sba_resource_map_one(buf, ioc);
+	}
+
+	return strlen(base);
+}
+#endif
+
+void
+sba_enable_device(struct pci_dev *dev)
+{
+	acpi_handle handle, parent;
+	acpi_status status;
+	struct ioc *ioc;
+
+	handle = PCI_CONTROLLER(dev)->acpi_handle;
+	if (!handle)
+		return;
+
+	/*
+	 * The IOC scope encloses PCI root bridges in the ACPI
+	 * namespace, so work our way out until we find an IOC we
+	 * claimed previously.
+	 */
+	do {
+		for (ioc = ioc_list; ioc; ioc = ioc->next)
+			if (ioc->handle == handle) {
+				PCI_CONTROLLER(dev)->iommu = ioc;
+				return;
+			}
+
+		status = acpi_get_parent(handle, &parent);
+		handle = parent;
+	} while (ACPI_SUCCESS(status));
+
+	printk("No IOC for %s in ACPI\n", dev->slot_name);
+}
+
+static int __init
+acpi_sba_ioc_add(struct acpi_device *device)
+{
+	struct ioc *ioc;
+	acpi_status status;
+	u64 hpa, length;
+
+	/*
+	 * Only SBA appears in ACPI namespace.  It encloses the PCI
+	 * root bridges, and its CSR space includes the IOC function.
+	 */
+	status = acpi_hp_csr_space(device->handle, &hpa, &length);
+	if (ACPI_FAILURE(status))
+		return 1;
+	ioc = ioc_init(hpa + ZX1_IOC_OFFSET, device->handle);
+	if (!ioc)
+		return 1;
+
+	return 0;
+}
+
+static int __init
+acpi_ioc_add(struct acpi_device *device)
+{
+	struct ioc *ioc;
+	acpi_status status;
+	u64 hpa, length;
+
+	status = acpi_hp_csr_space(device->handle, &hpa, &length);
+	if (ACPI_FAILURE(status))
+		return 1;
+	ioc = ioc_init(hpa, device->handle);
+	if (!ioc)
+		return 1;
+
+	return 0;
+}
+
+static struct acpi_driver acpi_sba_ioc_driver = {
+	name:		"IOC IOMMU Driver",
+	ids:		"HWP0001",
+	ops: {
+		add:	acpi_sba_ioc_add,
+     },
+};
+
+static struct acpi_driver acpi_ioc_driver = {
+	name:		"IOC IOMMU Driver",
+	ids:		"HWP0004",
+	ops: {
+		add:	acpi_ioc_add,
+     },
+};
+
+void __init
+ioc_acpi_init(void)
+{
+	acpi_bus_register_driver(&acpi_sba_ioc_driver);
+	acpi_bus_register_driver(&acpi_ioc_driver);
+}
+
+void __init
+sba_init(void)
+{
+	ioc_acpi_init();
+
+#ifdef CONFIG_PROC_FS
+	if (ioc_list) {
+		struct proc_dir_entry * proc_mckinley_root;
+
+		proc_mckinley_root = proc_mkdir("bus/mckinley",0);
+		create_proc_info_entry(ioc_list->name, 0, proc_mckinley_root, sba_proc_info);
+		create_proc_info_entry("bitmap", 0, proc_mckinley_root, sba_resource_map);
+	}
+#endif
+}
+
+static int __init
+nosbagart(char *str)
+{
+	reserve_sba_gart = 0;
+	return 1;
+}
+
+__setup("nosbagart", nosbagart);
+
+EXPORT_SYMBOL(sba_init);
+EXPORT_SYMBOL(sba_map_single);
+EXPORT_SYMBOL(sba_unmap_single);
+EXPORT_SYMBOL(sba_map_sg);
+EXPORT_SYMBOL(sba_unmap_sg);
+EXPORT_SYMBOL(sba_dma_address);
+EXPORT_SYMBOL(sba_dma_supported);
+EXPORT_SYMBOL(sba_alloc_consistent);
+EXPORT_SYMBOL(sba_free_consistent);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/hpsim_console.c linux-2.4.20/arch/ia64/hp/hpsim_console.c
--- linux-2.4.19/arch/ia64/hp/hpsim_console.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/hpsim_console.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,61 +0,0 @@
-/*
- * Platform dependent support for HP simulator.
- *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com>
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/kdev_t.h>
-#include <linux/console.h>
-
-#include <asm/delay.h>
-#include <asm/irq.h>
-#include <asm/pal.h>
-#include <asm/machvec.h>
-#include <asm/pgtable.h>
-#include <asm/sal.h>
-
-#include "hpsim_ssc.h"
-
-static int simcons_init (struct console *, char *);
-static void simcons_write (struct console *, const char *, unsigned);
-static kdev_t simcons_console_device (struct console *);
-
-struct console hpsim_cons = {
-	name:		"simcons",
-	write:		simcons_write,
-	device:		simcons_console_device,
-	setup:		simcons_init,
-	flags:		CON_PRINTBUFFER,
-	index:		-1,
-};
-
-static int
-simcons_init (struct console *cons, char *options)
-{
-	return 0;
-}
-
-static void
-simcons_write (struct console *cons, const char *buf, unsigned count)
-{
-	unsigned long ch;
-
-	while (count-- > 0) {
-		ch = *buf++;
-		ia64_ssc(ch, 0, 0, 0, SSC_PUTCHAR);
-		if (ch == '\n')
-		  ia64_ssc('\r', 0, 0, 0, SSC_PUTCHAR);
-	}
-}
-
-static kdev_t
-simcons_console_device (struct console *c)
-{
-	return MKDEV(TTY_MAJOR, 64 + c->index);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/hpsim_irq.c linux-2.4.20/arch/ia64/hp/hpsim_irq.c
--- linux-2.4.19/arch/ia64/hp/hpsim_irq.c	2001-04-05 19:51:47.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/hpsim_irq.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,46 +0,0 @@
-/*
- * Platform dependent support for HP simulator.
- *
- * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/irq.h>
-
-static unsigned int
-hpsim_irq_startup (unsigned int irq)
-{
-	return 0;
-}
-
-static void
-hpsim_irq_noop (unsigned int irq)
-{
-}
-
-static struct hw_interrupt_type irq_type_hp_sim = {
-	typename:	"hpsim",
-	startup:	hpsim_irq_startup,
-	shutdown:	hpsim_irq_noop,
-	enable:		hpsim_irq_noop,
-	disable:	hpsim_irq_noop,
-	ack:		hpsim_irq_noop,
-	end:		hpsim_irq_noop,
-	set_affinity:	(void (*)(unsigned int, unsigned long)) hpsim_irq_noop,
-};
-
-void __init
-hpsim_irq_init (void)
-{
-	irq_desc_t *idesc;
-	int i;
-
-	for (i = 0; i < NR_IRQS; ++i) {
-		idesc = irq_desc(i);
-		if (idesc->handler == &no_irq_type)
-			idesc->handler = &irq_type_hp_sim;
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/hpsim_machvec.c linux-2.4.20/arch/ia64/hp/hpsim_machvec.c
--- linux-2.4.19/arch/ia64/hp/hpsim_machvec.c	2000-08-12 02:09:06.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/hpsim_machvec.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,2 +0,0 @@
-#define MACHVEC_PLATFORM_NAME	hpsim
-#include <asm/machvec_init.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/hpsim_setup.c linux-2.4.20/arch/ia64/hp/hpsim_setup.c
--- linux-2.4.19/arch/ia64/hp/hpsim_setup.c	2001-07-31 17:30:08.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/hpsim_setup.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,58 +0,0 @@
-/*
- * Platform dependent support for HP simulator.
- *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com>
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/kdev_t.h>
-#include <linux/console.h>
-
-#include <asm/delay.h>
-#include <asm/irq.h>
-#include <asm/pal.h>
-#include <asm/machvec.h>
-#include <asm/pgtable.h>
-#include <asm/sal.h>
-
-#include "hpsim_ssc.h"
-
-extern struct console hpsim_cons;
-
-/*
- * Simulator system call.
- */
-asm (".text\n"
-     ".align 32\n"
-     ".global ia64_ssc\n"
-     ".proc ia64_ssc\n"
-     "ia64_ssc:\n"
-     "mov r15=r36\n"
-     "break 0x80001\n"
-     "br.ret.sptk.many rp\n"
-     ".endp\n");
-
-void
-ia64_ssc_connect_irq (long intr, long irq)
-{
-	ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT);
-}
-
-void
-ia64_ctl_trace (long on)
-{
-	ia64_ssc(on, 0, 0, 0, SSC_CTL_TRACE);
-}
-
-void __init
-hpsim_setup (char **cmdline_p)
-{
-	ROOT_DEV = to_kdev_t(0x0801);		/* default to first SCSI drive */
-
-	register_console (&hpsim_cons);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/hpsim_ssc.h linux-2.4.20/arch/ia64/hp/hpsim_ssc.h
--- linux-2.4.19/arch/ia64/hp/hpsim_ssc.h	2000-02-07 02:42:40.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/hpsim_ssc.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,36 +0,0 @@
-/*
- * Platform dependent support for HP simulator.
- *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com>
- */
-#ifndef _IA64_PLATFORM_HPSIM_SSC_H
-#define _IA64_PLATFORM_HPSIM_SSC_H
-
-/* Simulator system calls: */
-
-#define SSC_CONSOLE_INIT		20
-#define SSC_GETCHAR			21
-#define SSC_PUTCHAR			31
-#define SSC_CONNECT_INTERRUPT		58
-#define SSC_GENERATE_INTERRUPT		59
-#define SSC_SET_PERIODIC_INTERRUPT	60
-#define SSC_GET_RTC			65
-#define SSC_EXIT			66
-#define SSC_LOAD_SYMBOLS		69
-#define SSC_GET_TOD			74
-#define SSC_CTL_TRACE			76
-
-#define SSC_NETDEV_PROBE		100
-#define SSC_NETDEV_SEND			101
-#define SSC_NETDEV_RECV			102
-#define SSC_NETDEV_ATTACH		103
-#define SSC_NETDEV_DETACH		104
-
-/*
- * Simulator system call.
- */
-extern long ia64_ssc (long arg0, long arg1, long arg2, long arg3, int nr);
-
-#endif /* _IA64_PLATFORM_HPSIM_SSC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/sim/Makefile linux-2.4.20/arch/ia64/hp/sim/Makefile
--- linux-2.4.19/arch/ia64/hp/sim/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/sim/Makefile	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,13 @@
+#
+# ia64/platform/hp/sim/Makefile
+#
+# Copyright (C) 1999 Silicon Graphics, Inc.
+# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
+#
+
+O_TARGET := sim.o
+
+obj-y := hpsim_console.o hpsim_irq.o hpsim_setup.o
+obj-$(CONFIG_IA64_GENERIC) += hpsim_machvec.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/sim/hpsim_console.c linux-2.4.20/arch/ia64/hp/sim/hpsim_console.c
--- linux-2.4.19/arch/ia64/hp/sim/hpsim_console.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/sim/hpsim_console.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,62 @@
+/*
+ * Platform dependent support for HP simulator.
+ *
+ * Copyright (C) 1998, 1999 Hewlett-Packard Co
+ * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com>
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+#include <linux/console.h>
+
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/pal.h>
+#include <asm/machvec.h>
+#include <asm/pgtable.h>
+#include <asm/sal.h>
+
+#include "hpsim_ssc.h"
+
+static int simcons_init (struct console *, char *);
+static void simcons_write (struct console *, const char *, unsigned);
+static int simcons_wait_key (struct console *);
+static kdev_t simcons_console_device (struct console *);
+
+struct console hpsim_cons = {
+	name:		"simcons",
+	write:		simcons_write,
+	device:		simcons_console_device,
+	setup:		simcons_init,
+	flags:		CON_PRINTBUFFER,
+	index:		-1,
+};
+
+static int
+simcons_init (struct console *cons, char *options)
+{
+	return 0;
+}
+
+static void
+simcons_write (struct console *cons, const char *buf, unsigned count)
+{
+	unsigned long ch;
+
+	while (count-- > 0) {
+		ch = *buf++;
+		ia64_ssc(ch, 0, 0, 0, SSC_PUTCHAR);
+		if (ch == '\n')
+		  ia64_ssc('\r', 0, 0, 0, SSC_PUTCHAR);
+	}
+}
+
+static kdev_t
+simcons_console_device (struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 64 + c->index);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/sim/hpsim_irq.c linux-2.4.20/arch/ia64/hp/sim/hpsim_irq.c
--- linux-2.4.19/arch/ia64/hp/sim/hpsim_irq.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/sim/hpsim_irq.c	2002-10-29 11:18:47.000000000 +0000
@@ -0,0 +1,46 @@
+/*
+ * Platform dependent support for HP simulator.
+ *
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+
+static unsigned int
+hpsim_irq_startup (unsigned int irq)
+{
+	return 0;
+}
+
+static void
+hpsim_irq_noop (unsigned int irq)
+{
+}
+
+static struct hw_interrupt_type irq_type_hp_sim = {
+	typename:	"hpsim",
+	startup:	hpsim_irq_startup,
+	shutdown:	hpsim_irq_noop,
+	enable:		hpsim_irq_noop,
+	disable:	hpsim_irq_noop,
+	ack:		hpsim_irq_noop,
+	end:		hpsim_irq_noop,
+	set_affinity:	(void (*)(unsigned int, unsigned long)) hpsim_irq_noop,
+};
+
+void __init
+hpsim_irq_init (void)
+{
+	irq_desc_t *idesc;
+	int i;
+
+	for (i = 0; i < NR_IRQS; ++i) {
+		idesc = irq_desc(i);
+		if (idesc->handler == &no_irq_type)
+			idesc->handler = &irq_type_hp_sim;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/sim/hpsim_machvec.c linux-2.4.20/arch/ia64/hp/sim/hpsim_machvec.c
--- linux-2.4.19/arch/ia64/hp/sim/hpsim_machvec.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/sim/hpsim_machvec.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,2 @@
+#define MACHVEC_PLATFORM_NAME	hpsim
+#include <asm/machvec_init.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/sim/hpsim_setup.c linux-2.4.20/arch/ia64/hp/sim/hpsim_setup.c
--- linux-2.4.19/arch/ia64/hp/sim/hpsim_setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/sim/hpsim_setup.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,58 @@
+/*
+ * Platform dependent support for HP simulator.
+ *
+ * Copyright (C) 1998, 1999 Hewlett-Packard Co
+ * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com>
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+#include <linux/console.h>
+
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/pal.h>
+#include <asm/machvec.h>
+#include <asm/pgtable.h>
+#include <asm/sal.h>
+
+#include "hpsim_ssc.h"
+
+extern struct console hpsim_cons;
+
+/*
+ * Simulator system call.
+ */
+asm (".text\n"
+     ".align 32\n"
+     ".global ia64_ssc\n"
+     ".proc ia64_ssc\n"
+     "ia64_ssc:\n"
+     "mov r15=r36\n"
+     "break 0x80001\n"
+     "br.ret.sptk.many rp\n"
+     ".endp\n");
+
+void
+ia64_ssc_connect_irq (long intr, long irq)
+{
+	ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT);
+}
+
+void
+ia64_ctl_trace (long on)
+{
+	ia64_ssc(on, 0, 0, 0, SSC_CTL_TRACE);
+}
+
+void __init
+hpsim_setup (char **cmdline_p)
+{
+	ROOT_DEV = to_kdev_t(0x0801);		/* default to first SCSI drive */
+
+	register_console (&hpsim_cons);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/sim/hpsim_ssc.h linux-2.4.20/arch/ia64/hp/sim/hpsim_ssc.h
--- linux-2.4.19/arch/ia64/hp/sim/hpsim_ssc.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/sim/hpsim_ssc.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,36 @@
+/*
+ * Platform dependent support for HP simulator.
+ *
+ * Copyright (C) 1998, 1999 Hewlett-Packard Co
+ * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com>
+ */
+#ifndef _IA64_PLATFORM_HPSIM_SSC_H
+#define _IA64_PLATFORM_HPSIM_SSC_H
+
+/* Simulator system calls: */
+
+#define SSC_CONSOLE_INIT		20
+#define SSC_GETCHAR			21
+#define SSC_PUTCHAR			31
+#define SSC_CONNECT_INTERRUPT		58
+#define SSC_GENERATE_INTERRUPT		59
+#define SSC_SET_PERIODIC_INTERRUPT	60
+#define SSC_GET_RTC			65
+#define SSC_EXIT			66
+#define SSC_LOAD_SYMBOLS		69
+#define SSC_GET_TOD			74
+#define SSC_CTL_TRACE			76
+
+#define SSC_NETDEV_PROBE		100
+#define SSC_NETDEV_SEND			101
+#define SSC_NETDEV_RECV			102
+#define SSC_NETDEV_ATTACH		103
+#define SSC_NETDEV_DETACH		104
+
+/*
+ * Simulator system call.
+ */
+extern long ia64_ssc (long arg0, long arg1, long arg2, long arg3, int nr);
+
+#endif /* _IA64_PLATFORM_HPSIM_SSC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/zx1/Makefile linux-2.4.20/arch/ia64/hp/zx1/Makefile
--- linux-2.4.19/arch/ia64/hp/zx1/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/zx1/Makefile	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,13 @@
+#
+# ia64/platform/hp/zx1/Makefile
+#
+# Copyright (C) 2002 Hewlett Packard
+# Copyright (C) Alex Williamson (alex_williamson@hp.com)
+#
+
+O_TARGET := zx1.o
+
+obj-y := hpzx1_misc.o
+obj-$(CONFIG_IA64_GENERIC) += hpzx1_machvec.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/zx1/hpzx1_machvec.c linux-2.4.20/arch/ia64/hp/zx1/hpzx1_machvec.c
--- linux-2.4.19/arch/ia64/hp/zx1/hpzx1_machvec.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/zx1/hpzx1_machvec.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,2 @@
+#define MACHVEC_PLATFORM_NAME	hpzx1
+#include <asm/machvec_init.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/hp/zx1/hpzx1_misc.c linux-2.4.20/arch/ia64/hp/zx1/hpzx1_misc.c
--- linux-2.4.19/arch/ia64/hp/zx1/hpzx1_misc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/hp/zx1/hpzx1_misc.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,308 @@
+/*
+ * Misc. support for HP zx1 chipset support
+ *
+ * Copyright (C) 2002 Hewlett-Packard Co
+ * Copyright (C) 2002 Alex Williamson <alex_williamson@hp.com>
+ * Copyright (C) 2002 Bjorn Helgaas <bjorn_helgaas@hp.com>
+ */
+
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <linux/efi.h>
+
+#include <asm/dma.h>
+#include <asm/iosapic.h>
+
+extern acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, acpi_object_list *, unsigned long *);
+
+#define PFX "hpzx1: "
+
+static int hpzx1_devices;
+
+struct fake_pci_dev {
+	unsigned long csr_base;
+	unsigned long csr_size;
+	unsigned long mapped_csrs;	// ioremapped
+	int sizing;			// in middle of BAR sizing operation?
+};
+
+#define PCI_FAKE_DEV(dev)	((struct fake_pci_dev *) \
+					PCI_CONTROLLER(dev)->platform_data)
+
+static struct pci_ops *orig_pci_ops;
+
+#define HP_CFG_RD(sz, bits, name) \
+static int hp_cfg_read##sz (struct pci_dev *dev, int where, u##bits *value) \
+{ \
+	struct fake_pci_dev *fake_dev; \
+	if (!(fake_dev = PCI_FAKE_DEV(dev))) \
+		return orig_pci_ops->name(dev, where, value); \
+	\
+	if (where == PCI_BASE_ADDRESS_0) { \
+		if (fake_dev->sizing) \
+			*value = ~(fake_dev->csr_size - 1); \
+		else \
+			*value = (fake_dev->csr_base & \
+				    PCI_BASE_ADDRESS_MEM_MASK) | \
+				PCI_BASE_ADDRESS_SPACE_MEMORY; \
+		fake_dev->sizing = 0; \
+		return PCIBIOS_SUCCESSFUL; \
+	} \
+	*value = read##sz(fake_dev->mapped_csrs + where); \
+	if (where == PCI_COMMAND) \
+		*value |= PCI_COMMAND_MEMORY; /* SBA omits this */ \
+	return PCIBIOS_SUCCESSFUL; \
+}
+
+#define HP_CFG_WR(sz, bits, name) \
+static int hp_cfg_write##sz (struct pci_dev *dev, int where, u##bits value) \
+{ \
+	struct fake_pci_dev *fake_dev; \
+	\
+	if (!(fake_dev = PCI_FAKE_DEV(dev))) \
+		return orig_pci_ops->name(dev, where, value); \
+	\
+	if (where == PCI_BASE_ADDRESS_0) { \
+		if (value == (u##bits) ~0) \
+			fake_dev->sizing = 1; \
+		return PCIBIOS_SUCCESSFUL; \
+	} else \
+		write##sz(value, fake_dev->mapped_csrs + where); \
+	return PCIBIOS_SUCCESSFUL; \
+}
+
+HP_CFG_RD(b,  8, read_byte)
+HP_CFG_RD(w, 16, read_word)
+HP_CFG_RD(l, 32, read_dword)
+HP_CFG_WR(b,  8, write_byte)
+HP_CFG_WR(w, 16, write_word)
+HP_CFG_WR(l, 32, write_dword)
+
+static struct pci_ops hp_pci_conf = {
+	hp_cfg_readb,
+	hp_cfg_readw,
+	hp_cfg_readl,
+	hp_cfg_writeb,
+	hp_cfg_writew,
+	hp_cfg_writel,
+};
+
+static void
+hpzx1_fake_pci_dev(char *name, unsigned int busnum, unsigned long addr, unsigned int size)
+{
+	struct pci_controller *controller;
+	struct fake_pci_dev *fake;
+	int slot;
+	struct pci_dev *dev;
+	struct pci_bus *b, *bus = NULL;
+	u8 hdr;
+
+	controller = kmalloc(sizeof(*controller), GFP_KERNEL);
+	if (!controller) {
+		printk(KERN_ERR PFX "No memory for %s (0x%p) sysdata\n", name,
+			(void *) addr);
+		return;
+	}
+	memset(controller, 0, sizeof(*controller));
+
+        fake = kmalloc(sizeof(*fake), GFP_KERNEL);
+	if (!fake) {
+		printk(KERN_ERR PFX "No memory for %s (0x%p) sysdata\n", name,
+			(void *) addr);
+		kfree(controller);
+		return;
+	}
+
+	memset(fake, 0, sizeof(*fake));
+	fake->csr_base = addr;
+	fake->csr_size = size;
+	fake->mapped_csrs = (unsigned long) ioremap(addr, size);
+	fake->sizing = 0;
+	controller->platform_data = fake;
+
+	pci_for_each_bus(b)
+		if (busnum == b->number) {
+			bus = b;
+			break;
+		}
+
+	if (!bus) {
+		printk(KERN_ERR PFX "No host bus 0x%02x for %s (0x%p)\n",
+			busnum, name, (void *) addr);
+		kfree(fake);
+		kfree(controller);
+		return;
+	}
+
+	for (slot = 0x1e; slot; slot--)
+		if (!pci_find_slot(busnum, PCI_DEVFN(slot, 0)))
+			break;
+
+	if (slot < 0) {
+		printk(KERN_ERR PFX "No space for %s (0x%p) on bus 0x%02x\n",
+			name, (void *) addr, busnum);
+		kfree(fake);
+		kfree(controller);
+		return;
+	}
+
+        dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		printk(KERN_ERR PFX "No memory for %s (0x%p)\n", name,
+			(void *) addr);
+		kfree(fake);
+		kfree(controller);
+		return;
+	}
+
+	bus->ops = &hp_pci_conf;	// replace pci ops for this bus
+
+	memset(dev, 0, sizeof(*dev));
+	dev->bus = bus;
+	dev->sysdata = controller;
+	dev->devfn = PCI_DEVFN(slot, 0);
+	pci_read_config_word(dev, PCI_VENDOR_ID, &dev->vendor);
+	pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device);
+	pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr);
+	dev->hdr_type = hdr & 0x7f;
+
+	pci_setup_device(dev);
+
+	// pci_insert_device() without running /sbin/hotplug
+	list_add_tail(&dev->bus_list, &bus->devices);
+	list_add_tail(&dev->global_list, &pci_devices);
+
+	printk(KERN_INFO PFX "%s at 0x%lx; pci dev %s\n", name, addr,
+		dev->slot_name);
+
+	hpzx1_devices++;
+}
+
+static acpi_status
+hpzx1_sba_probe(acpi_handle obj, u32 depth, void *context, void **ret)
+{
+	u64 csr_base = 0, csr_length = 0;
+	acpi_status status;
+	char *name = context;
+	char fullname[16];
+
+	status = acpi_hp_csr_space(obj, &csr_base, &csr_length);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	/*
+	 * Only SBA shows up in ACPI namespace, so its CSR space
+	 * includes both SBA and IOC.  Make SBA and IOC show up
+	 * separately in PCI space.
+	 */
+	sprintf(fullname, "%s SBA", name);
+	hpzx1_fake_pci_dev(fullname, 0, csr_base, 0x1000);
+	sprintf(fullname, "%s IOC", name);
+	hpzx1_fake_pci_dev(fullname, 0, csr_base + 0x1000, 0x1000);
+
+	return AE_OK;
+}
+
+static acpi_status
+hpzx1_lba_probe(acpi_handle obj, u32 depth, void *context, void **ret)
+{
+	u64 csr_base = 0, csr_length = 0;
+	acpi_status status;
+	NATIVE_UINT busnum;
+	char *name = context;
+	char fullname[32];
+
+	status = acpi_hp_csr_space(obj, &csr_base, &csr_length);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	status = acpi_evaluate_integer(obj, METHOD_NAME__BBN, NULL, &busnum);
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_WARNING PFX "evaluate _BBN fail=0x%x\n", status);
+		busnum = 0;	// no _BBN; stick it on bus 0
+	}
+
+	sprintf(fullname, "%s _BBN 0x%02x", name, (unsigned int) busnum);
+	hpzx1_fake_pci_dev(fullname, busnum, csr_base, csr_length);
+
+	return AE_OK;
+}
+
+static void
+hpzx1_acpi_dev_init(void)
+{
+	extern struct pci_ops *pci_root_ops;
+
+	orig_pci_ops = pci_root_ops;
+
+	/*
+	 * Make fake PCI devices for the following hardware in the
+	 * ACPI namespace.  This makes it more convenient for drivers
+	 * because they can claim these devices based on PCI
+	 * information, rather than needing to know about ACPI.  The
+	 * 64-bit "HPA" space for this hardware is available as BAR
+	 * 0/1.
+	 *
+	 * HWP0001: Single IOC SBA w/o IOC in namespace
+	 * HWP0002: LBA device
+	 * HWP0003: AGP LBA device
+	 */
+	acpi_get_devices("HWP0001", hpzx1_sba_probe, "HWP0001", NULL);
+#ifdef CONFIG_IA64_HP_PROTO
+	if (hpzx1_devices) {
+#endif
+	acpi_get_devices("HWP0002", hpzx1_lba_probe, "HWP0002 PCI LBA", NULL);
+	acpi_get_devices("HWP0003", hpzx1_lba_probe, "HWP0003 AGP LBA", NULL);
+
+#ifdef CONFIG_IA64_HP_PROTO
+	}
+
+#define ZX1_FUNC_ID_VALUE    (PCI_DEVICE_ID_HP_ZX1_SBA << 16) | PCI_VENDOR_ID_HP
+	/*
+	 * Early protos don't have bridges in the ACPI namespace, so
+	 * if we didn't find anything, add the things we know are
+	 * there.
+	 */
+	if (hpzx1_devices == 0) {
+		u64 hpa, csr_base;
+
+		csr_base = 0xfed00000UL;
+		hpa = (u64) ioremap(csr_base, 0x2000);
+		if (__raw_readl(hpa) == ZX1_FUNC_ID_VALUE) {
+			hpzx1_fake_pci_dev("HWP0001 SBA", 0, csr_base, 0x1000);
+			hpzx1_fake_pci_dev("HWP0001 IOC", 0, csr_base + 0x1000,
+					    0x1000);
+
+			csr_base = 0xfed24000UL;
+			iounmap(hpa);
+			hpa = (u64) ioremap(csr_base, 0x1000);
+			hpzx1_fake_pci_dev("HWP0003 AGP LBA", 0x40, csr_base,
+					    0x1000);
+		}
+		iounmap(hpa);
+	}
+#endif
+}
+
+extern void sba_init(void);
+
+void
+hpzx1_pci_fixup (int phase)
+{
+	iosapic_pci_fixup(phase);
+	switch (phase) {
+	      case 0:
+		/* zx1 has a hardware I/O TLB which lets us DMA from any device to any address */
+		MAX_DMA_ADDRESS = ~0UL;
+		break;
+
+	      case 1:
+		hpzx1_acpi_dev_init();
+		sba_init();
+		break;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/ia32/binfmt_elf32.c linux-2.4.20/arch/ia64/ia32/binfmt_elf32.c
--- linux-2.4.19/arch/ia64/ia32/binfmt_elf32.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/ia32/binfmt_elf32.c	2002-10-29 11:18:50.000000000 +0000
@@ -47,6 +47,8 @@
 #define ELF_PLAT_INIT(_r)		ia64_elf32_init(_r)
 #define setup_arg_pages(bprm)		ia32_setup_arg_pages(bprm)
 #define elf_map				elf32_map
+
+#undef SET_PERSONALITY
 #define SET_PERSONALITY(ex, ibcs2)	elf32_set_personality()
 
 /* Ugly but avoids duplication */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/ia32/ia32_traps.c linux-2.4.20/arch/ia64/ia32/ia32_traps.c
--- linux-2.4.19/arch/ia64/ia32/ia32_traps.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/ia32/ia32_traps.c	2002-10-29 11:18:37.000000000 +0000
@@ -20,7 +20,7 @@
 {
 	switch ((isr >> 16) & 0xff) {
 	      case 0:	/* Instruction intercept fault */
-	      case 3:	/* Locked Data reference fault */
+	      case 4:	/* Locked Data reference fault */
 	      case 1:	/* Gate intercept trap */
 		return -1;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/Makefile linux-2.4.20/arch/ia64/kernel/Makefile
--- linux-2.4.19/arch/ia64/kernel/Makefile	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/Makefile	2002-10-29 11:18:40.000000000 +0000
@@ -17,6 +17,7 @@
 	 machvec.o pal.o process.o perfmon.o ptrace.o sal.o salinfo.o semaphore.o setup.o	 \
 	 signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o
 obj-$(CONFIG_IA64_GENERIC) += iosapic.o
+obj-$(CONFIG_IA64_HP_ZX1) += iosapic.o
 obj-$(CONFIG_IA64_DIG) += iosapic.o
 obj-$(CONFIG_IA64_PALINFO) += palinfo.o
 obj-$(CONFIG_EFI_VARS) += efivars.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/acpi.c linux-2.4.20/arch/ia64/kernel/acpi.c
--- linux-2.4.19/arch/ia64/kernel/acpi.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/acpi.c	2002-10-29 11:18:40.000000000 +0000
@@ -1,21 +1,34 @@
 /*
- * Advanced Configuration and Power Interface
+ *  acpi.c - Architecture-Specific Low-Level ACPI Support
  *
- * Based on 'ACPI Specification 1.0b' February 2, 1999 and
- * 'IA-64 Extensions to ACPI Specification' Revision 0.6
+ *  Copyright (C) 1999 VA Linux Systems
+ *  Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
+ *  Copyright (C) 2000, 2002 Hewlett-Packard Co.
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ *  Copyright (C) 2000 Intel Corp.
+ *  Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@intel.com>
+ *  Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
  *
- * Copyright (C) 1999 VA Linux Systems
- * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 2000 Hewlett-Packard Co.
- * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 2000 Intel Corp.
- * Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@intel.com>
- *      ACPI based kernel configuration manager.
- *      ACPI 2.0 & IA64 ext 0.71
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
 #include <linux/config.h>
-
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -23,657 +36,801 @@
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/irq.h>
-#ifdef CONFIG_SERIAL_ACPI
-#include <linux/acpi_serial.h>
-#endif
-
-#include <asm/acpi-ext.h>
-#include <asm/acpikcfg.h>
-#include <asm/efi.h>
+#include <linux/acpi.h>
+#include <linux/efi.h>
 #include <asm/io.h>
 #include <asm/iosapic.h>
 #include <asm/machvec.h>
 #include <asm/page.h>
+#include <asm/system.h>
 
-#undef ACPI_DEBUG		/* Guess what this does? */
 
-/* global array to record platform interrupt vectors for generic int routing */
-int platform_irq_list[ACPI_MAX_PLATFORM_IRQS];
+#define PREFIX			"ACPI: "
 
-/* These are ugly but will be reclaimed by the kernel */
-int __initdata available_cpus;
-int __initdata total_cpus;
+asm (".weak iosapic_register_intr");
+asm (".weak iosapic_override_isa_irq");
+asm (".weak iosapic_register_platform_intr");
+asm (".weak iosapic_init");
+asm (".weak iosapic_version");
 
 void (*pm_idle) (void);
 void (*pm_power_off) (void);
 
-asm (".weak iosapic_register_irq");
-asm (".weak iosapic_register_legacy_irq");
-asm (".weak iosapic_register_platform_irq");
-asm (".weak iosapic_init");
-asm (".weak iosapic_version");
+unsigned char acpi_kbd_controller_present = 1;
 
 const char *
 acpi_get_sysname (void)
 {
-	/* the following should go away once we have an ACPI parser: */
 #ifdef CONFIG_IA64_GENERIC
-	return "hpsim";
+	unsigned long rsdp_phys;
+	struct acpi20_table_rsdp *rsdp;
+	struct acpi_table_xsdt *xsdt;
+	struct acpi_table_header *hdr;
+
+	rsdp_phys = acpi_find_rsdp();
+	if (!rsdp_phys) {
+		printk("ACPI 2.0 RSDP not found, default to \"dig\"\n");
+		return "dig";
+	}
+
+	rsdp = (struct acpi20_table_rsdp *) __va(rsdp_phys);
+	if (strncmp(rsdp->signature, RSDP_SIG, sizeof(RSDP_SIG) - 1)) {
+		printk("ACPI 2.0 RSDP signature incorrect, default to \"dig\"\n");
+		return "dig";
+	}
+
+	xsdt = (struct acpi_table_xsdt *) __va(rsdp->xsdt_address);
+	hdr = &xsdt->header;
+	if (strncmp(hdr->signature, XSDT_SIG, sizeof(XSDT_SIG) - 1)) {
+		printk("ACPI 2.0 XSDT signature incorrect, default to \"dig\"\n");
+		return "dig";
+	}
+
+	if (!strcmp(hdr->oem_id, "HP")) {
+		return "hpzx1";
+	}
+
+	return "dig";
 #else
 # if defined (CONFIG_IA64_HP_SIM)
 	return "hpsim";
+# elif defined (CONFIG_IA64_HP_ZX1)
+	return "hpzx1";
 # elif defined (CONFIG_IA64_SGI_SN1)
 	return "sn1";
 # elif defined (CONFIG_IA64_SGI_SN2)
 	return "sn2";
 # elif defined (CONFIG_IA64_DIG)
 	return "dig";
+# elif defined (CONFIG_IA64_HP_ZX1)
+	return "hpzx1";
 # else
 #	error Unknown platform.  Fix acpi.c.
 # endif
 #endif
+}
+
+#ifdef CONFIG_ACPI
+
+/**
+ * acpi_get_crs - Return the current resource settings for a device
+ * obj: A handle for this device
+ * buf: A buffer to be populated by this call.
+ *
+ * Pass a valid handle, typically obtained by walking the namespace and a
+ * pointer to an allocated buffer, and this function will fill in the buffer
+ * with a list of acpi_resource structures.
+ */
+acpi_status
+acpi_get_crs (acpi_handle obj, acpi_buffer *buf)
+{
+	acpi_status result;
+	buf->length = 0;
+	buf->pointer = NULL;
+
+	result = acpi_get_current_resources(obj, buf);
+	if (result != AE_BUFFER_OVERFLOW)
+		return result;
+	buf->pointer = kmalloc(buf->length, GFP_KERNEL);
+	if (!buf->pointer)
+		return -ENOMEM;
+
+	return acpi_get_current_resources(obj, buf);
+}
+
+acpi_resource *
+acpi_get_crs_next (acpi_buffer *buf, int *offset)
+{
+	acpi_resource *res;
+
+	if (*offset >= buf->length)
+		return NULL;
+
+	res = buf->pointer + *offset;
+	*offset += res->length;
+	return res;
+}
+
+acpi_resource_data *
+acpi_get_crs_type (acpi_buffer *buf, int *offset, int type)
+{
+	for (;;) {
+		acpi_resource *res = acpi_get_crs_next(buf, offset);
+		if (!res)
+			return NULL;
+		if (res->id == type)
+			return &res->data;
+	}
+}
+
+void
+acpi_dispose_crs (acpi_buffer *buf)
+{
+	kfree(buf->pointer);
+}
+
+static void
+acpi_get_crs_addr (acpi_buffer *buf, int type, u64 *base, u64 *length, u64 *tra)
+{
+	int offset = 0;
+	acpi_resource_address16 *addr16;
+	acpi_resource_address32 *addr32;
+	acpi_resource_address64 *addr64;
+
+	for (;;) {
+		acpi_resource *res = acpi_get_crs_next(buf, &offset);
+		if (!res)
+			return;
+		switch (res->id) {
+			case ACPI_RSTYPE_ADDRESS16:
+				addr16 = (acpi_resource_address16 *) &res->data;
+
+				if (type == addr16->resource_type) {
+					*base = addr16->min_address_range;
+					*length = addr16->address_length;
+					*tra = addr16->address_translation_offset;
+					return;
+				}
+				break;
+			case ACPI_RSTYPE_ADDRESS32:
+				addr32 = (acpi_resource_address32 *) &res->data;
+				if (type == addr32->resource_type) {
+					*base = addr32->min_address_range;
+					*length = addr32->address_length;
+					*tra = addr32->address_translation_offset;
+					return;
+				}
+				break;
+			case ACPI_RSTYPE_ADDRESS64:
+				addr64 = (acpi_resource_address64 *) &res->data;
+				if (type == addr64->resource_type) {
+					*base = addr64->min_address_range;
+					*length = addr64->address_length;
+					*tra = addr64->address_translation_offset;
+					return;
+				}
+				break;
+		}
+	}
+}
+
+acpi_status
+acpi_get_addr_space(acpi_handle obj, u8 type, u64 *base, u64 *length, u64 *tra)
+{
+	acpi_status status;
+	acpi_buffer buf;
+
+	*base = 0;
+	*length = 0;
+	*tra = 0;
+
+	status = acpi_get_crs(obj, &buf);
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
+		return status;
+	}
+
+	acpi_get_crs_addr(&buf, type, base, length, tra);
+
+	acpi_dispose_crs(&buf);
+
+	return AE_OK;
+}
+
+typedef struct {
+	u8	guid_id;
+	u8	guid[16];
+	u8	csr_base[8];
+	u8	csr_length[8];
+} acpi_hp_vendor_long;
+
+#define HP_CCSR_LENGTH 0x21
+#define HP_CCSR_TYPE 0x2
+#define HP_CCSR_GUID EFI_GUID(0x69e9adf9, 0x924f, 0xab5f, \
+			      0xf6, 0x4a, 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad)
+
+acpi_status
+acpi_hp_csr_space(acpi_handle obj, u64 *csr_base, u64 *csr_length)
+{
+	int i, offset = 0;
+	acpi_status status;
+	acpi_buffer buf;
+	acpi_resource_vendor *res;
+	acpi_hp_vendor_long *hp_res;
+	efi_guid_t vendor_guid;
+
+	*csr_base = 0;
+	*csr_length = 0;
 
+	status = acpi_get_crs(obj, &buf);
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
+		return status;
+	}
+
+	res = (acpi_resource_vendor *)acpi_get_crs_type(&buf, &offset, ACPI_RSTYPE_VENDOR);
+	if (!res) {
+		printk(KERN_ERR PREFIX "Failed to find config space for device\n");
+		acpi_dispose_crs(&buf);
+		return AE_NOT_FOUND;
+	}
+
+	hp_res = (acpi_hp_vendor_long *)(res->reserved);
+
+	if (res->length != HP_CCSR_LENGTH || hp_res->guid_id != HP_CCSR_TYPE) {
+		printk(KERN_ERR PREFIX "Unknown Vendor data\n");
+		acpi_dispose_crs(&buf);
+		return AE_TYPE; /* Revisit error? */
+	}
+
+	memcpy(&vendor_guid, hp_res->guid, sizeof(efi_guid_t));
+	if (efi_guidcmp(vendor_guid, HP_CCSR_GUID) != 0) {
+		printk(KERN_ERR PREFIX "Vendor GUID does not match\n");
+		acpi_dispose_crs(&buf);
+		return AE_TYPE; /* Revisit error? */
+	}
+
+	for (i = 0 ; i < 8 ; i++) {
+		*csr_base |= ((u64)(hp_res->csr_base[i]) << (i * 8));
+		*csr_length |= ((u64)(hp_res->csr_length[i]) << (i * 8));
+	}
+
+	acpi_dispose_crs(&buf);
+
+	return AE_OK;
 }
+#endif /* CONFIG_ACPI */
+
+#ifdef CONFIG_ACPI_BOOT
+
+#define ACPI_MAX_PLATFORM_INTERRUPTS	256
+
+/* Array to record platform interrupt vectors for generic interrupt routing. */
+int platform_intr_list[ACPI_MAX_PLATFORM_INTERRUPTS] = { [0 ... ACPI_MAX_PLATFORM_INTERRUPTS - 1] = -1 };
+
+enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_IOSAPIC;
 
 /*
- * Interrupt routing API for device drivers.
- * Provides the interrupt vector for a generic platform event
- * (currently only CPEI implemented)
+ * Interrupt routing API for device drivers.  Provides interrupt vector for
+ * a generic platform event.  Currently only CPEI is implemented.
  */
 int
-acpi_request_vector(u32 int_type)
+acpi_request_vector (u32 int_type)
 {
 	int vector = -1;
 
-	if (int_type < ACPI_MAX_PLATFORM_IRQS) {
+	if (int_type < ACPI_MAX_PLATFORM_INTERRUPTS) {
 		/* correctable platform error interrupt */
-		vector = platform_irq_list[int_type];
+		vector = platform_intr_list[int_type];
 	} else
 		printk("acpi_request_vector(): invalid interrupt type\n");
 
 	return vector;
 }
 
-/*
- * Configure legacy IRQ information.
- */
-static void __init
-acpi_legacy_irq (char *p)
+char *
+__acpi_map_table (unsigned long phys_addr, unsigned long size)
 {
-	acpi_entry_int_override_t *legacy = (acpi_entry_int_override_t *) p;
-	unsigned long polarity = 0, edge_triggered = 0;
+	return __va(phys_addr);
+}
 
-	/*
-	 * If the platform we're running doesn't define
-	 * iosapic_register_legacy_irq(), we ignore this info...
-	 */
-	if (!iosapic_register_legacy_irq)
-		return;
+/* --------------------------------------------------------------------------
+                            Boot-time Table Parsing
+   -------------------------------------------------------------------------- */
 
-	switch (legacy->flags) {
-	      case 0x5:	polarity = 1; edge_triggered = 1; break;
-	      case 0x7: polarity = 0; edge_triggered = 1; break;
-	      case 0xd: polarity = 1; edge_triggered = 0; break;
-	      case 0xf: polarity = 0; edge_triggered = 0; break;
-	      default:
-		printk("    ACPI Legacy IRQ 0x%02x: Unknown flags 0x%x\n", legacy->isa_irq,
-		       legacy->flags);
-		break;
-	}
-	iosapic_register_legacy_irq(legacy->isa_irq, legacy->pin, polarity, edge_triggered);
-}
+static int			total_cpus __initdata;
+static int			available_cpus __initdata;
+struct acpi_table_madt *	acpi_madt __initdata;
+static u8			has_8259;
 
-/*
- * ACPI 2.0 tables parsing functions
- */
 
-static unsigned long
-readl_unaligned(void *p)
+static int __init
+acpi_parse_lapic_addr_ovr (acpi_table_entry_header *header)
 {
-	unsigned long ret;
+	struct acpi_table_lapic_addr_ovr *lapic;
+
+	lapic = (struct acpi_table_lapic_addr_ovr *) header;
+	if (!lapic)
+		return -EINVAL;
 
-	memcpy(&ret, p, sizeof(long));
-	return ret;
+	acpi_table_print_madt_entry(header);
+
+	if (lapic->address) {
+		iounmap((void *) ipi_base_addr);
+		ipi_base_addr = (unsigned long) ioremap(lapic->address, 0);
+	}
+
+	return 0;
 }
 
-/*
- * Identify usable CPU's and remember them for SMP bringup later.
- */
-static void __init
-acpi20_lsapic (char *p)
+
+static int __init
+acpi_parse_lsapic (acpi_table_entry_header *header)
 {
-	int add = 1;
+	struct acpi_table_lsapic *lsapic;
 
-	acpi20_entry_lsapic_t *lsapic = (acpi20_entry_lsapic_t *) p;
-	printk("      CPU %.04x:%.04x: ", lsapic->eid, lsapic->id);
+	lsapic = (struct acpi_table_lsapic *) header;
+	if (!lsapic)
+		return -EINVAL;
 
-	if ((lsapic->flags & LSAPIC_ENABLED) == 0) {
-		printk("disabled.\n");
-		add = 0;
-	}
+	acpi_table_print_madt_entry(header);
 
-#ifdef CONFIG_SMP
-	smp_boot_data.cpu_phys_id[total_cpus] = -1;
-#endif
-	if (add) {
+	printk("CPU %d (0x%04x)", total_cpus, (lsapic->id << 8) | lsapic->eid);
+
+	if (lsapic->flags.enabled) {
 		available_cpus++;
-		printk("available");
+		printk(" enabled");
 #ifdef CONFIG_SMP
 		smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid;
 		if (hard_smp_processor_id() == smp_boot_data.cpu_phys_id[total_cpus])
 			printk(" (BSP)");
 #endif
-		printk(".\n");
 	}
+	else {
+		printk(" disabled");
+#ifdef CONFIG_SMP
+		smp_boot_data.cpu_phys_id[total_cpus] = -1;
+#endif
+	}
+
+	printk("\n");
+
 	total_cpus++;
+	return 0;
 }
 
-/*
- * Extract iosapic info from madt (again) to determine which iosapic
- * this platform interrupt resides in
- */
+
+static int __init
+acpi_parse_lapic_nmi (acpi_table_entry_header *header)
+{
+	struct acpi_table_lapic_nmi *lacpi_nmi;
+
+	lacpi_nmi = (struct acpi_table_lapic_nmi*) header;
+	if (!lacpi_nmi)
+		return -EINVAL;
+
+	acpi_table_print_madt_entry(header);
+
+	/* TBD: Support lapic_nmi entries */
+
+	return 0;
+}
+
+
 static int __init
-acpi20_which_iosapic (int global_vector, acpi_madt_t *madt, u32 *irq_base, char **iosapic_address)
+acpi_find_iosapic (unsigned int gsi, u32 *gsi_base, char **iosapic_address)
 {
-	acpi_entry_iosapic_t *iosapic;
-	char *p, *end;
-	int ver, max_pin;
+	struct acpi_table_iosapic *iosapic;
+	int ver;
+	int max_pin;
+	char *p;
+	char *end;
+
+	if (!gsi_base || !iosapic_address)
+		return -ENODEV;
 
-	p = (char *) (madt + 1);
-	end = p + (madt->header.length - sizeof(acpi_madt_t));
+	p = (char *) (acpi_madt + 1);
+	end = p + (acpi_madt->header.length - sizeof(struct acpi_table_madt));
 
 	while (p < end) {
-		switch (*p) {
-		      case ACPI20_ENTRY_IO_SAPIC:
-			/* collect IOSAPIC info for platform int use later */
-			iosapic = (acpi_entry_iosapic_t *)p;
-			*irq_base = iosapic->irq_base;
+		if (*p == ACPI_MADT_IOSAPIC) {
+			iosapic = (struct acpi_table_iosapic *) p;
+
+			*gsi_base = iosapic->global_irq_base;
 			*iosapic_address = ioremap(iosapic->address, 0);
-			/* is this the iosapic we're looking for? */
+
 			ver = iosapic_version(*iosapic_address);
 			max_pin = (ver >> 16) & 0xff;
-			if ((global_vector - *irq_base) <= max_pin)
-				return 0;		/* found it! */
-			break;
-		      default:
-			break;
+
+			if ((gsi - *gsi_base) <= max_pin)
+				return 0;	/* Found it! */
 		}
 		p += p[1];
 	}
-	return 1;
+	return -ENODEV;
 }
 
-/*
- * Info on platform interrupt sources: NMI, PMI, INIT, etc.
- */
-static void __init
-acpi20_platform (char *p, acpi_madt_t *madt)
+
+static int __init
+acpi_parse_iosapic (acpi_table_entry_header *header)
 {
+	struct acpi_table_iosapic *iosapic;
+
+	iosapic = (struct acpi_table_iosapic *) header;
+	if (!iosapic)
+		return -EINVAL;
+
+	acpi_table_print_madt_entry(header);
+
+	if (iosapic_init) {
+#ifndef CONFIG_ITANIUM
+		/* PCAT_COMPAT flag indicates dual-8259 setup */
+		iosapic_init(iosapic->address, iosapic->global_irq_base,
+			     acpi_madt->flags.pcat_compat);
+#else
+		/* Firmware on old Itanium systems is broken */
+		iosapic_init(iosapic->address, iosapic->global_irq_base, 1);
+#endif
+	}
+	return 0;
+}
+
+
+static int __init
+acpi_parse_plat_int_src (acpi_table_entry_header *header)
+{
+	struct acpi_table_plat_int_src *plintsrc;
 	int vector;
-	u32 irq_base;
+	u32 gsi_base;
 	char *iosapic_address;
-	unsigned long polarity = 0, trigger = 0;
-	acpi20_entry_platform_src_t *plat = (acpi20_entry_platform_src_t *) p;
 
-	printk("PLATFORM: IOSAPIC %x -> Vector %x on CPU %.04u:%.04u\n",
-	       plat->iosapic_vector, plat->global_vector, plat->eid, plat->id);
+	plintsrc = (struct acpi_table_plat_int_src *) header;
+	if (!plintsrc)
+		return -EINVAL;
 
-	/* record platform interrupt vectors for generic int routing code */
+	acpi_table_print_madt_entry(header);
 
-	if (!iosapic_register_platform_irq) {
-		printk("acpi20_platform(): no ACPI platform IRQ support\n");
-		return;
-	}
-
-	/* extract polarity and trigger info from flags */
-	switch (plat->flags) {
-	      case 0x5: polarity = 1; trigger = 1; break;
-	      case 0x7: polarity = 0; trigger = 1; break;
-	      case 0xd: polarity = 1; trigger = 0; break;
-	      case 0xf: polarity = 0; trigger = 0; break;
-	      default:
-		printk("acpi20_platform(): unknown flags 0x%x\n", plat->flags);
-		break;
-	}
-
-	/* which iosapic does this IRQ belong to? */
-	if (acpi20_which_iosapic(plat->global_vector, madt, &irq_base, &iosapic_address)) {
-		printk("acpi20_platform(): I/O SAPIC not found!\n");
-		return;
+	if (!iosapic_register_platform_intr) {
+		printk(KERN_WARNING PREFIX "No ACPI platform interrupt support\n");
+		return -ENODEV;
+	}
+
+	if (acpi_find_iosapic(plintsrc->global_irq, &gsi_base, &iosapic_address)) {
+		printk(KERN_WARNING PREFIX "IOSAPIC not found\n");
+		return -ENODEV;
 	}
 
 	/*
-	 * get vector assignment for this IRQ, set attributes, and program the IOSAPIC
-	 * routing table
+	 * Get vector assignment for this interrupt, set attributes,
+	 * and program the IOSAPIC routing table.
 	 */
-	vector = iosapic_register_platform_irq(plat->int_type,
-					       plat->global_vector,
-					       plat->iosapic_vector,
-					       plat->eid,
-					       plat->id,
-					       polarity,
-					       trigger,
-					       irq_base,
-					       iosapic_address);
-	platform_irq_list[plat->int_type] = vector;
+	vector = iosapic_register_platform_intr(plintsrc->type,
+						plintsrc->global_irq,
+						plintsrc->iosapic_vector,
+						plintsrc->eid,
+						plintsrc->id,
+						(plintsrc->flags.polarity == 1) ? 1 : 0,
+						(plintsrc->flags.trigger == 1) ? 1 : 0,
+						gsi_base,
+						iosapic_address);
+
+	platform_intr_list[plintsrc->type] = vector;
+	return 0;
 }
 
-/*
- * Override the physical address of the local APIC in the MADT stable header.
- */
-static void __init
-acpi20_lapic_addr_override (char *p)
+
+static int __init
+acpi_parse_int_src_ovr (acpi_table_entry_header *header)
 {
-	acpi20_entry_lapic_addr_override_t * lapic = (acpi20_entry_lapic_addr_override_t *) p;
+	struct acpi_table_int_src_ovr *p;
 
-	if (lapic->lapic_address) {
-		iounmap((void *)ipi_base_addr);
-		ipi_base_addr = (unsigned long) ioremap(lapic->lapic_address, 0);
+	p = (struct acpi_table_int_src_ovr *) header;
+	if (!p)
+		return -EINVAL;
 
-		printk("LOCAL ACPI override to 0x%lx(p=0x%lx)\n",
-		       ipi_base_addr, lapic->lapic_address);
-	}
+	acpi_table_print_madt_entry(header);
+
+	/* Ignore if the platform doesn't support overrides */
+	if (!iosapic_override_isa_irq)
+		return 0;
+
+	iosapic_override_isa_irq(p->bus_irq, p->global_irq,
+				 (p->flags.polarity == 1) ? 1 : 0,
+				 (p->flags.trigger == 1) ? 1 : 0);
+
+	return 0;
 }
 
-/*
- * Parse the ACPI Multiple APIC Description Table
- */
-static void __init
-acpi20_parse_madt (acpi_madt_t *madt)
+
+static int __init
+acpi_parse_nmi_src (acpi_table_entry_header *header)
 {
-	acpi_entry_iosapic_t *iosapic = NULL;
-	acpi20_entry_lsapic_t *lsapic = NULL;
-	char *p, *end;
-	int i;
-
-	/* Base address of IPI Message Block */
-	if (madt->lapic_address) {
-		ipi_base_addr = (unsigned long) ioremap(madt->lapic_address, 0);
-		printk("Lapic address set to 0x%lx\n", ipi_base_addr);
-	} else
-		printk("Lapic address set to default 0x%lx\n", ipi_base_addr);
+	struct acpi_table_nmi_src *nmi_src;
 
-	p = (char *) (madt + 1);
-	end = p + (madt->header.length - sizeof(acpi_madt_t));
+	nmi_src = (struct acpi_table_nmi_src*) header;
+	if (!nmi_src)
+		return -EINVAL;
 
-	/* Initialize platform interrupt vector array */
-	for (i = 0; i < ACPI_MAX_PLATFORM_IRQS; i++)
-		platform_irq_list[i] = -1;
+	acpi_table_print_madt_entry(header);
 
-	/*
-	 * Split-up entry parsing to ensure ordering.
-	 */
-	while (p < end) {
-		switch (*p) {
-		      case ACPI20_ENTRY_LOCAL_APIC_ADDR_OVERRIDE:
-			printk("ACPI 2.0 MADT: LOCAL APIC Override\n");
-			acpi20_lapic_addr_override(p);
-			break;
-
-		      case ACPI20_ENTRY_LOCAL_SAPIC:
-			printk("ACPI 2.0 MADT: LOCAL SAPIC\n");
-			lsapic = (acpi20_entry_lsapic_t *) p;
-			acpi20_lsapic(p);
-			break;
-
-		      case ACPI20_ENTRY_IO_SAPIC:
-			iosapic = (acpi_entry_iosapic_t *) p;
-			if (iosapic_init)
-				/*
-				 * The PCAT_COMPAT flag indicates that the system has a
-				 * dual-8259 compatible setup.
-				 */
-				iosapic_init(iosapic->address, iosapic->irq_base,
-#ifdef CONFIG_ITANIUM
-					     1 /* fw on some Itanium systems is broken... */
-#else
-					     (madt->flags & MADT_PCAT_COMPAT)
-#endif
-					);
-			break;
+	/* TBD: Support nimsrc entries */
 
-		      case ACPI20_ENTRY_PLATFORM_INT_SOURCE:
-			printk("ACPI 2.0 MADT: PLATFORM INT SOURCE\n");
-			acpi20_platform(p, madt);
-			break;
-
-		      case ACPI20_ENTRY_LOCAL_APIC:
-			printk("ACPI 2.0 MADT: LOCAL APIC entry\n"); break;
-		      case ACPI20_ENTRY_IO_APIC:
-			printk("ACPI 2.0 MADT: IO APIC entry\n"); break;
-		      case ACPI20_ENTRY_NMI_SOURCE:
-			printk("ACPI 2.0 MADT: NMI SOURCE entry\n"); break;
-		      case ACPI20_ENTRY_LOCAL_APIC_NMI:
-			printk("ACPI 2.0 MADT: LOCAL APIC NMI entry\n"); break;
-		      case ACPI20_ENTRY_INT_SRC_OVERRIDE:
-			break;
-		      default:
-			printk("ACPI 2.0 MADT: unknown entry skip\n"); break;
-			break;
-		}
-		p += p[1];
-	}
+	return 0;
+}
 
-	p = (char *) (madt + 1);
-	end = p + (madt->header.length - sizeof(acpi_madt_t));
 
-	while (p < end) {
-		switch (*p) {
-		      case ACPI20_ENTRY_LOCAL_APIC:
-			if (lsapic) break;
-			printk("ACPI 2.0 MADT: LOCAL APIC entry\n");
-			/* parse local apic if there's no local Sapic */
-			break;
-		      case ACPI20_ENTRY_IO_APIC:
-			if (iosapic) break;
-			printk("ACPI 2.0 MADT: IO APIC entry\n");
-			/* parse ioapic if there's no ioSapic */
-			break;
-		      default:
-			break;
-		}
-		p += p[1];
-	}
+static int __init
+acpi_parse_madt (unsigned long phys_addr, unsigned long size)
+{
+	if (!phys_addr || !size)
+		return -EINVAL;
 
-	p = (char *) (madt + 1);
-	end = p + (madt->header.length - sizeof(acpi_madt_t));
+	acpi_madt = (struct acpi_table_madt *) __va(phys_addr);
 
-	while (p < end) {
-		switch (*p) {
-		      case ACPI20_ENTRY_INT_SRC_OVERRIDE:
-			printk("ACPI 2.0 MADT: INT SOURCE Override\n");
-			acpi_legacy_irq(p);
-			break;
-		      default:
-			break;
-		}
-		p += p[1];
-	}
+	/* remember the value for reference after free_initmem() */
+	has_8259 = acpi_madt->flags.pcat_compat;
+
+	/* Get base address of IPI Message Block */
 
-	/* Make bootup pretty */
-	printk("      %d CPUs available, %d CPUs total\n",
-		available_cpus, total_cpus);
+	if (acpi_madt->lapic_address)
+		ipi_base_addr = (unsigned long) ioremap(acpi_madt->lapic_address, 0);
+
+	printk(KERN_INFO PREFIX "Local APIC address 0x%lx\n", ipi_base_addr);
+	return 0;
 }
 
-int __init
-acpi20_parse (acpi20_rsdp_t *rsdp20)
+
+static int __init
+acpi_parse_fadt (unsigned long phys_addr, unsigned long size)
 {
-# ifdef CONFIG_ACPI
-	acpi_xsdt_t *xsdt;
-	acpi_desc_table_hdr_t *hdrp;
-	acpi_madt_t *madt = NULL;
-	int tables, i;
+	struct acpi_table_header *fadt_header;
+	fadt_descriptor_rev2 *fadt;
+	u32 sci_irq, gsi_base;
+	char *iosapic_address;
 
-	if (strncmp(rsdp20->signature, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN)) {
-		printk("ACPI 2.0 RSDP signature incorrect!\n");
-		return 0;
-	} else {
-		printk("ACPI 2.0 Root System Description Ptr at 0x%lx\n",
-			(unsigned long)rsdp20);
-	}
+	if (!phys_addr || !size)
+		return -EINVAL;
 
-	xsdt = __va(rsdp20->xsdt);
-	hdrp = &xsdt->header;
-	if (strncmp(hdrp->signature,
-		ACPI_XSDT_SIG, ACPI_XSDT_SIG_LEN)) {
-		printk("ACPI 2.0 XSDT signature incorrect. Trying RSDT\n");
-		/* RSDT parsing here */
-		return 0;
-	} else {
-		printk("ACPI 2.0 XSDT at 0x%lx (p=0x%lx)\n",
-		(unsigned long)xsdt, (unsigned long)rsdp20->xsdt);
-	}
+	fadt_header = (struct acpi_table_header *) __va(phys_addr);
 
-	printk("ACPI 2.0: %.6s %.8s %d.%d\n",
-		hdrp->oem_id,
-		hdrp->oem_table_id,
-		hdrp->oem_revision >> 16,
-		hdrp->oem_revision & 0xffff);
+	if (fadt_header->revision != 3)
+		return -ENODEV;		/* Only deal with ACPI 2.0 FADT */
 
-	acpi_cf_init((void *)rsdp20);
+	fadt = (fadt_descriptor_rev2 *) fadt_header;
 
-	tables =(hdrp->length -sizeof(acpi_desc_table_hdr_t))>>3;
+	if (!(fadt->iapc_boot_arch & BAF_8042_KEYBOARD_CONTROLLER))
+		acpi_kbd_controller_present = 0;
 
-	for (i = 0; i < tables; i++) {
-		hdrp = (acpi_desc_table_hdr_t *) __va(readl_unaligned(&xsdt->entry_ptrs[i]));
-		printk("        :table %4.4s found\n", hdrp->signature);
+	sci_irq = fadt->sci_int;
 
-		/* Only interested int the MADT table for now ... */
-		if (strncmp(hdrp->signature,
-			ACPI_MADT_SIG, ACPI_MADT_SIG_LEN) != 0)
-			continue;
+	if (has_8259 && sci_irq < 16)
+		return 0;	/* legacy, no setup required */
+
+	if (!iosapic_register_intr)
+		return -ENODEV;
+
+	if (!acpi_find_iosapic(sci_irq, &gsi_base, &iosapic_address))
+		iosapic_register_intr(sci_irq, 0, 0, gsi_base, iosapic_address);
+
+	return 0;
+}
 
-		/* Save MADT pointer for later */
-		madt = (acpi_madt_t *) hdrp;
-		acpi20_parse_madt(madt);
-	}
 
 #ifdef CONFIG_SERIAL_ACPI
+
+#include <linux/acpi_serial.h>
+
+static int __init
+acpi_parse_spcr (unsigned long phys_addr, unsigned long size)
+{
+	acpi_ser_t *spcr;
+	u32 gsi, gsi_base;
+	char *iosapic_address;
+
+	if (!phys_addr || !size)
+		return -EINVAL;
+
+	if (!iosapic_register_intr)
+		return -ENODEV;
+
 	/*
-	 * Now we're interested in other tables.  We want the iosapics already
-	 * initialized, so we do it in a separate loop.
+	 * ACPI is able to describe serial ports that live at non-standard
+	 * memory addresses and use non-standard interrupts, either via
+	 * direct SAPIC mappings or via PCI interrupts.  We handle interrupt
+	 * routing for SAPIC-based (non-PCI) devices here.  Interrupt routing
+	 * for PCI devices will be handled when processing the PCI Interrupt
+	 * Routing Table (PRT).
 	 */
-	for (i = 0; i < tables; i++) {
-		hdrp = (acpi_desc_table_hdr_t *) __va(readl_unaligned(&xsdt->entry_ptrs[i]));
-		/*
-		 * search for SPCR and DBGP table entries so we can enable
-		 * non-pci interrupts to IO-SAPICs.
-		 */
-		if (!strncmp(hdrp->signature, ACPI_SPCRT_SIG, ACPI_SPCRT_SIG_LEN) ||
-		    !strncmp(hdrp->signature, ACPI_DBGPT_SIG, ACPI_DBGPT_SIG_LEN))
-		{
-			acpi_ser_t *spcr = (void *)hdrp;
-			unsigned long global_int;
-
-			setup_serial_acpi(hdrp);
-
-			/*
-			 * ACPI is able to describe serial ports that live at non-standard
-			 * memory space addresses and use SAPIC interrupts.  If not also
-			 * PCI devices, there would be no interrupt vector information for
-			 * them.  This checks for and fixes that situation.
-			 */
-			if (spcr->length < sizeof(acpi_ser_t))
-				/* table is not long enough for full info, thus no int */
-				break;
 
-			/*
-			 * If the device is not in PCI space, but uses a SAPIC interrupt,
-			 * we need to program the SAPIC so that serial can autoprobe for
-			 * the IA64 interrupt vector later on.  If the device is in PCI
-			 * space, it should already be setup via the PCI vectors
-			 */
-			if (spcr->base_addr.space_id != ACPI_SERIAL_PCICONF_SPACE &&
-			    spcr->int_type == ACPI_SERIAL_INT_SAPIC)
-			{
-				u32 irq_base;
-				char *iosapic_address;
-				int vector;
-
-				/* We have a UART in memory space with a SAPIC interrupt */
-				global_int = (  (spcr->global_int[3] << 24)
-					      | (spcr->global_int[2] << 16)
-					      | (spcr->global_int[1] << 8)
-					      | spcr->global_int[0]);
-
-				if (!iosapic_register_irq)
-					continue;
-
-				/* which iosapic does this IRQ belong to? */
-				if (acpi20_which_iosapic(global_int, madt, &irq_base,
-							 &iosapic_address) == 0)
-				{
-					vector = iosapic_register_irq(global_int,
-					                              1, /* active high polarity */
-					                              1, /* edge triggered */
-					                              irq_base,
-					                              iosapic_address);
-				}
-			}
-		}
-	}
-#endif
-	acpi_cf_terminate();
+	spcr = (acpi_ser_t *) __va(phys_addr);
+	setup_serial_acpi(spcr);
 
-#  ifdef CONFIG_SMP
-	if (available_cpus == 0) {
-		printk("ACPI: Found 0 CPUS; assuming 1\n");
-		available_cpus = 1; /* We've got at least one of these, no? */
+	if (spcr->length < sizeof(acpi_ser_t))
+		/* Table not long enough for full info, thus no interrupt */
+		return -ENODEV;
+
+	if ((spcr->base_addr.space_id != ACPI_SERIAL_PCICONF_SPACE) &&
+	    (spcr->int_type == ACPI_SERIAL_INT_SAPIC)) {
+
+		/* We have a UART in memory space with an SAPIC interrupt */
+
+		gsi = (spcr->global_int[3] << 24) |
+		      (spcr->global_int[2] << 16) |
+		      (spcr->global_int[1] << 8)  |
+		      (spcr->global_int[0]);
+
+		if (!acpi_find_iosapic(gsi, &gsi_base, &iosapic_address))
+			iosapic_register_intr(gsi, 1, 1,
+					      gsi_base, iosapic_address);
 	}
-	smp_boot_data.cpu_count = total_cpus;
-#  endif
-# endif /* CONFIG_ACPI */
-	return 1;
+	return 0;
 }
-/*
- * ACPI 1.0b with 0.71 IA64 extensions functions; should be removed once all
- * platforms start supporting ACPI 2.0
- */
 
-/*
- * Identify usable CPU's and remember them for SMP bringup later.
- */
-static void __init
-acpi_lsapic (char *p)
+#endif /*CONFIG_SERIAL_ACPI*/
+
+
+unsigned long __init
+acpi_find_rsdp (void)
 {
-	int add = 1;
+	unsigned long rsdp_phys = 0;
 
-	acpi_entry_lsapic_t *lsapic = (acpi_entry_lsapic_t *) p;
+	if (efi.acpi20)
+		rsdp_phys = __pa(efi.acpi20);
+	else if (efi.acpi)
+		printk(KERN_WARNING PREFIX "v1.0/r0.71 tables no longer supported\n");
 
-	if ((lsapic->flags & LSAPIC_PRESENT) == 0)
-		return;
+	return rsdp_phys;
+}
 
-	printk("      CPU %d (%.04x:%.04x): ", total_cpus, lsapic->eid, lsapic->id);
 
-	if ((lsapic->flags & LSAPIC_ENABLED) == 0) {
-		printk("Disabled.\n");
-		add = 0;
-	} else if (lsapic->flags & LSAPIC_PERFORMANCE_RESTRICTED) {
-		printk("Performance Restricted; ignoring.\n");
-		add = 0;
-	}
+int __init
+acpi_boot_init (char *cmdline)
+{
+	int result;
 
-#ifdef CONFIG_SMP
-	smp_boot_data.cpu_phys_id[total_cpus] = -1;
-#endif
-	if (add) {
-		printk("Available.\n");
-		available_cpus++;
-#ifdef CONFIG_SMP
-		smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid;
-#endif /* CONFIG_SMP */
+	/* Initialize the ACPI boot-time table parser */
+	result = acpi_table_init(cmdline);
+	if (result)
+		return result;
+
+	/*
+	 * MADT
+	 * ----
+	 * Parse the Multiple APIC Description Table (MADT), if exists.
+	 * Note that this table provides platform SMP configuration
+	 * information -- the successor to MPS tables.
+	 */
+
+	if (acpi_table_parse(ACPI_APIC, acpi_parse_madt) < 1) {
+		printk(KERN_ERR PREFIX "Can't find MADT\n");
+		goto skip_madt;
 	}
-	total_cpus++;
-}
 
-/*
- * Info on platform interrupt sources: NMI. PMI, INIT, etc.
- */
-static void __init
-acpi_platform (char *p)
-{
-	acpi_entry_platform_src_t *plat = (acpi_entry_platform_src_t *) p;
+	/* Local APIC */
 
-	printk("PLATFORM: IOSAPIC %x -> Vector %x on CPU %.04u:%.04u\n",
-	       plat->iosapic_vector, plat->global_vector, plat->eid, plat->id);
-}
+	if (acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR,
+				  acpi_parse_lapic_addr_ovr) < 0)
+		printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n");
 
-/*
- * Parse the ACPI Multiple SAPIC Table
- */
-static void __init
-acpi_parse_msapic (acpi_sapic_t *msapic)
-{
-	acpi_entry_iosapic_t *iosapic;
-	char *p, *end;
+	if (acpi_table_parse_madt(ACPI_MADT_LSAPIC,
+				  acpi_parse_lsapic) < 1)
+		printk(KERN_ERR PREFIX "Error parsing MADT - no LAPIC entries\n");
 
-	/* Base address of IPI Message Block */
-	ipi_base_addr = (unsigned long) ioremap(msapic->interrupt_block, 0);
+	if (acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI,
+				  acpi_parse_lapic_nmi) < 0)
+		printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
 
-	p = (char *) (msapic + 1);
-	end = p + (msapic->header.length - sizeof(acpi_sapic_t));
+	/* I/O APIC */
 
-	while (p < end) {
-		switch (*p) {
-		      case ACPI_ENTRY_LOCAL_SAPIC:
-			acpi_lsapic(p);
-			break;
-
-		      case ACPI_ENTRY_IO_SAPIC:
-			iosapic = (acpi_entry_iosapic_t *) p;
-			if (iosapic_init)
-				/*
-				 * The ACPI I/O SAPIC table doesn't have a PCAT_COMPAT
-				 * flag like the MADT table, but we can safely assume that
-				 * ACPI 1.0b systems have a dual-8259 setup.
-				 */
-				iosapic_init(iosapic->address, iosapic->irq_base, 1);
-			break;
-
-		      case ACPI_ENTRY_INT_SRC_OVERRIDE:
-			acpi_legacy_irq(p);
-			break;
-
-		      case ACPI_ENTRY_PLATFORM_INT_SOURCE:
-			acpi_platform(p);
-			break;
+	if (acpi_table_parse_madt(ACPI_MADT_IOSAPIC,
+				  acpi_parse_iosapic) < 1)
+		printk(KERN_ERR PREFIX "Error parsing MADT - no IOAPIC entries\n");
 
-		      default:
-			break;
-		}
+	/* System-Level Interrupt Routing */
 
-		/* Move to next table entry. */
-		p += p[1];
-	}
+	if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC,
+				  acpi_parse_plat_int_src) < 0)
+		printk(KERN_ERR PREFIX "Error parsing platform interrupt source entry\n");
+
+	if (acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR,
+				  acpi_parse_int_src_ovr) < 0)
+		printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n");
 
-	/* Make bootup pretty */
-	printk("      %d CPUs available, %d CPUs total\n", available_cpus, total_cpus);
+	if (acpi_table_parse_madt(ACPI_MADT_NMI_SRC,
+				  acpi_parse_nmi_src) < 0)
+		printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
+skip_madt:
+
+	/*
+	 * The FADT table contains an SCI_INT line, by which the system
+	 * gets interrupts such as power and sleep buttons.  If it's not
+	 * on a Legacy interrupt, it needs to be setup.
+	 */
+	if (acpi_table_parse(ACPI_FACP, acpi_parse_fadt) < 1)
+		printk(KERN_ERR PREFIX "Can't find FADT\n");
+
+#ifdef CONFIG_SERIAL_ACPI
+	acpi_table_parse(ACPI_SPCR, acpi_parse_spcr);
+#endif
+
+#ifdef CONFIG_SMP
+	if (available_cpus == 0) {
+		printk("ACPI: Found 0 CPUS; assuming 1\n");
+		available_cpus = 1; /* We've got at least one of these, no? */
+	}
+	smp_boot_data.cpu_count = total_cpus;
+#endif
+	/* Make boot-up look pretty */
+	printk("%d CPUs available, %d CPUs total\n", available_cpus, total_cpus);
+	return 0;
 }
 
+
+/* --------------------------------------------------------------------------
+                             PCI Interrupt Routing
+   -------------------------------------------------------------------------- */
+
 int __init
-acpi_parse (acpi_rsdp_t *rsdp)
+acpi_get_prt (struct pci_vector_struct **vectors, int *count)
 {
-# ifdef CONFIG_ACPI
-	acpi_rsdt_t *rsdt;
-	acpi_desc_table_hdr_t *hdrp;
-	long tables, i;
+	struct pci_vector_struct *vector;
+	struct list_head *node;
+	struct acpi_prt_entry *entry;
+	int i = 0;
 
-	if (strncmp(rsdp->signature, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN)) {
-		printk("Uh-oh, ACPI RSDP signature incorrect!\n");
-		return 0;
-	}
+	if (!vectors || !count)
+		return -EINVAL;
 
-	rsdt = __va(rsdp->rsdt);
-	if (strncmp(rsdt->header.signature, ACPI_RSDT_SIG, ACPI_RSDT_SIG_LEN)) {
-		printk("Uh-oh, ACPI RDST signature incorrect!\n");
-		return 0;
+	*vectors = NULL;
+	*count = 0;
+
+	if (acpi_prt.count < 0) {
+		printk(KERN_ERR PREFIX "No PCI interrupt routing entries\n");
+		return -ENODEV;
 	}
 
-	printk("ACPI: %.6s %.8s %d.%d\n", rsdt->header.oem_id, rsdt->header.oem_table_id,
-	       rsdt->header.oem_revision >> 16, rsdt->header.oem_revision & 0xffff);
+	/* Allocate vectors */
 
-	acpi_cf_init(rsdp);
+	*vectors = kmalloc(sizeof(struct pci_vector_struct) * acpi_prt.count, GFP_KERNEL);
+	if (!(*vectors))
+		return -ENOMEM;
 
-	tables = (rsdt->header.length - sizeof(acpi_desc_table_hdr_t)) / 8;
-	for (i = 0; i < tables; i++) {
-		hdrp = (acpi_desc_table_hdr_t *) __va(rsdt->entry_ptrs[i]);
+	/* Convert PRT entries to IOSAPIC PCI vectors */
 
-		/* Only interested int the MSAPIC table for now ... */
-		if (strncmp(hdrp->signature, ACPI_SAPIC_SIG, ACPI_SAPIC_SIG_LEN) != 0)
-			continue;
+	vector = *vectors;
 
-		acpi_parse_msapic((acpi_sapic_t *) hdrp);
+	list_for_each(node, &acpi_prt.entries) {
+		entry = (struct acpi_prt_entry *)node;
+		vector[i].segment = entry->id.segment;
+		vector[i].bus    = entry->id.bus;
+		vector[i].pci_id = ((u32) entry->id.device << 16) | 0xffff;
+		vector[i].pin    = entry->pin;
+		vector[i].irq    = entry->link.index;
+		i++;
 	}
+	*count = acpi_prt.count;
+	return 0;
+}
 
-	acpi_cf_terminate();
+/* Assume IA64 always use I/O SAPIC */
 
-#  ifdef CONFIG_SMP
-	if (available_cpus == 0) {
-		printk("ACPI: Found 0 CPUS; assuming 1\n");
-		available_cpus = 1; /* We've got at least one of these, no? */
-	}
-	smp_boot_data.cpu_count = total_cpus;
-#  endif
-# endif /* CONFIG_ACPI */
-	return 1;
+int __init
+acpi_get_interrupt_model (int *type)
+{
+        if (!type)
+                return -EINVAL;
+
+	*type = ACPI_IRQ_MODEL_IOSAPIC;
+        return 0;
+}
+
+int
+acpi_irq_to_vector (u32 irq)
+{
+	if (has_8259 && irq < 16)
+		return isa_irq_to_vector(irq);
+
+	return gsi_to_vector(irq);
 }
+
+#endif /* CONFIG_ACPI_BOOT */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/efi.c linux-2.4.20/arch/ia64/kernel/efi.c
--- linux-2.4.19/arch/ia64/kernel/efi.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/efi.c	2002-10-29 11:18:32.000000000 +0000
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 1999-2001 Hewlett-Packard Co.
+ * Copyright (C) 1999-2002 Hewlett-Packard Co.
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  *	Stephane Eranian <eranian@hpl.hp.com>
  *
@@ -24,8 +24,8 @@
 #include <linux/types.h>
 #include <linux/time.h>
 #include <linux/proc_fs.h>
+#include <linux/efi.h>
 
-#include <asm/efi.h>
 #include <asm/io.h>
 #include <asm/kregs.h>
 #include <asm/pgtable.h>
@@ -125,9 +125,79 @@
 	tv->tv_usec = tm.nanosecond / 1000;
 }
 
+static int
+is_available_memory (efi_memory_desc_t *md)
+{
+	if (!(md->attribute & EFI_MEMORY_WB))
+		return 0;
+
+	switch (md->type) {
+	      case EFI_LOADER_CODE:
+	      case EFI_LOADER_DATA:
+	      case EFI_BOOT_SERVICES_CODE:
+	      case EFI_BOOT_SERVICES_DATA:
+	      case EFI_CONVENTIONAL_MEMORY:
+		return 1;
+	}
+	return 0;
+}
+
 /*
- * Walks the EFI memory map and calls CALLBACK once for each EFI
- * memory descriptor that has memory that is available for OS use.
+ * Trim descriptor MD so its starts at address START_ADDR.  If the descriptor covers
+ * memory that is normally available to the kernel, issue a warning that some memory
+ * is being ignored.
+ */
+static void
+trim_bottom (efi_memory_desc_t *md, u64 start_addr)
+{
+	u64 num_skipped_pages;
+
+	if (md->phys_addr >= start_addr || !md->num_pages)
+		return;
+
+	num_skipped_pages = (start_addr - md->phys_addr) >> EFI_PAGE_SHIFT;
+	if (num_skipped_pages > md->num_pages)
+		num_skipped_pages = md->num_pages;
+
+	if (is_available_memory(md))
+		printk(KERN_NOTICE "efi.%s: ignoring %luKB of memory at 0x%lx due to granule hole "
+		       "at 0x%lx\n", __FUNCTION__,
+		       (num_skipped_pages << EFI_PAGE_SHIFT) >> 10,
+		       md->phys_addr, start_addr - IA64_GRANULE_SIZE);
+	/*
+	 * NOTE: Don't set md->phys_addr to START_ADDR because that could cause the memory
+	 * descriptor list to become unsorted.  In such a case, md->num_pages will be
+	 * zero, so the Right Thing will happen.
+	 */
+	md->phys_addr += num_skipped_pages << EFI_PAGE_SHIFT;
+	md->num_pages -= num_skipped_pages;
+}
+
+static void
+trim_top (efi_memory_desc_t *md, u64 end_addr)
+{
+	u64 num_dropped_pages, md_end_addr;
+
+	md_end_addr = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
+
+	if (md_end_addr <= end_addr || !md->num_pages)
+		return;
+
+	num_dropped_pages = (md_end_addr - end_addr) >> EFI_PAGE_SHIFT;
+	if (num_dropped_pages > md->num_pages)
+		num_dropped_pages = md->num_pages;
+
+	if (is_available_memory(md))
+		printk(KERN_NOTICE "efi.%s: ignoring %luKB of memory at 0x%lx due to granule hole "
+		       "at 0x%lx\n", __FUNCTION__,
+		       (num_dropped_pages << EFI_PAGE_SHIFT) >> 10,
+		       md->phys_addr, end_addr);
+	md->num_pages -= num_dropped_pages;
+}
+
+/*
+ * Walks the EFI memory map and calls CALLBACK once for each EFI memory descriptor that
+ * has memory that is available for OS use.
  */
 void
 efi_memmap_walk (efi_freemem_callback_t callback, void *arg)
@@ -137,9 +207,9 @@
 		u64 start;
 		u64 end;
 	} prev, curr;
-	void *efi_map_start, *efi_map_end, *p;
-	efi_memory_desc_t *md;
-	u64 efi_desc_size, start, end;
+	void *efi_map_start, *efi_map_end, *p, *q;
+	efi_memory_desc_t *md, *check_md;
+	u64 efi_desc_size, start, end, granule_addr, first_non_wb_addr = 0;
 
 	efi_map_start = __va(ia64_boot_param->efi_memmap);
 	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
@@ -147,27 +217,59 @@
 
 	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
 		md = p;
-		switch (md->type) {
-		      case EFI_LOADER_CODE:
-		      case EFI_LOADER_DATA:
-		      case EFI_BOOT_SERVICES_CODE:
-		      case EFI_BOOT_SERVICES_DATA:
-		      case EFI_CONVENTIONAL_MEMORY:
-			if (!(md->attribute & EFI_MEMORY_WB))
-				continue;
-			if (md->phys_addr + (md->num_pages << 12) > mem_limit) {
+
+		/* skip over non-WB memory descriptors; that's all we're interested in... */
+		if (!(md->attribute & EFI_MEMORY_WB))
+			continue;
+
+		if (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) > first_non_wb_addr) {
+			/*
+			 * Search for the next run of contiguous WB memory.  Start search
+			 * at first granule boundary covered by md.
+			 */
+			granule_addr = ((md->phys_addr + IA64_GRANULE_SIZE - 1)
+					& -IA64_GRANULE_SIZE);
+			first_non_wb_addr = granule_addr;
+			for (q = p; q < efi_map_end; q += efi_desc_size) {
+				check_md = q;
+
+				if (check_md->attribute & EFI_MEMORY_WB)
+					trim_bottom(md, granule_addr);
+
+				if (check_md->phys_addr < granule_addr)
+					continue;
+
+				if (!(check_md->attribute & EFI_MEMORY_WB))
+					break;	/* hit a non-WB region; stop search */
+
+				if (check_md->phys_addr != first_non_wb_addr)
+					break;	/* hit a memory hole; stop search */
+
+				first_non_wb_addr += check_md->num_pages << EFI_PAGE_SHIFT;
+			}
+			/* round it down to the previous granule-boundary: */
+			first_non_wb_addr &= -IA64_GRANULE_SIZE;
+
+			if (!(first_non_wb_addr > granule_addr))
+				continue;	/* couldn't find enough contiguous memory */
+		}
+
+		/* BUG_ON((md->phys_addr >> IA64_GRANULE_SHIFT) < first_non_wb_addr); */
+
+		trim_top(md, first_non_wb_addr);
+
+		if (is_available_memory(md)) {
+			if (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) > mem_limit) {
 				if (md->phys_addr > mem_limit)
 					continue;
-				md->num_pages = (mem_limit - md->phys_addr) >> 12;
+				md->num_pages = (mem_limit - md->phys_addr) >> EFI_PAGE_SHIFT;
 			}
-			if (md->num_pages == 0) {
-				printk("efi_memmap_walk: ignoring empty region at 0x%lx",
-				       md->phys_addr);
+
+			if (md->num_pages == 0)
 				continue;
-			}
 
 			curr.start = PAGE_OFFSET + md->phys_addr;
-			curr.end   = curr.start + (md->num_pages << 12);
+			curr.end   = curr.start + (md->num_pages << EFI_PAGE_SHIFT);
 
 			if (!prev_valid) {
 				prev = curr;
@@ -187,10 +289,6 @@
 					prev = curr;
 				}
 			}
-			break;
-
-		      default:
-			continue;
 		}
 	}
 	if (prev_valid) {
@@ -212,8 +310,8 @@
 	void *efi_map_start, *efi_map_end, *p;
 	efi_memory_desc_t *md;
 	u64 efi_desc_size;
-	int pal_code_count=0;
-	u64 mask, flags;
+	int pal_code_count = 0;
+	u64 mask, psr;
 	u64 vaddr;
 
 	efi_map_start = __va(ia64_boot_param->efi_memmap);
@@ -250,25 +348,26 @@
 		 * dedicated ITR for the PAL code.
 		 */
 		if ((vaddr & mask) == (KERNEL_START & mask)) {
-			printk(__FUNCTION__ ": no need to install ITR for PAL code\n");
+			printk("%s: no need to install ITR for PAL code\n", __FUNCTION__);
 			continue;
 		}
 
-		if (md->num_pages << 12 > IA64_GRANULE_SIZE)
+		if (md->num_pages << EFI_PAGE_SHIFT > IA64_GRANULE_SIZE)
 			panic("Woah!  PAL code size bigger than a granule!");
 
 		mask  = ~((1 << IA64_GRANULE_SHIFT) - 1);
 		printk("CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n",
-		       smp_processor_id(), md->phys_addr, md->phys_addr + (md->num_pages << 12),
+		       smp_processor_id(), md->phys_addr,
+		       md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
 		       vaddr & mask, (vaddr & mask) + IA64_GRANULE_SIZE);
 
 		/*
 		 * Cannot write to CRx with PSR.ic=1
 		 */
-		ia64_clear_ic(flags);
+		psr = ia64_clear_ic();
 		ia64_itr(0x1, IA64_TR_PALCODE, vaddr & mask,
 			 pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)), IA64_GRANULE_SHIFT);
-		local_irq_restore(flags);
+		ia64_set_psr(psr);		/* restore psr */
 		ia64_srlz_i();
 	}
 }
@@ -378,7 +477,8 @@
 			md = p;
 			printk("mem%02u: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n",
 			       i, md->type, md->attribute, md->phys_addr,
-			       md->phys_addr + (md->num_pages<<12) - 1, md->num_pages >> 8);
+			       md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
+			       md->num_pages >> (20 - EFI_PAGE_SHIFT));
 		}
 	}
 #endif
@@ -485,8 +585,50 @@
 	return 0;
 }
 
+u32
+efi_mem_type (unsigned long phys_addr)
+{
+	void *efi_map_start, *efi_map_end, *p;
+	efi_memory_desc_t *md;
+	u64 efi_desc_size;
+
+	efi_map_start = __va(ia64_boot_param->efi_memmap);
+	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
+	efi_desc_size = ia64_boot_param->efi_memdesc_size;
+
+	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
+		md = p;
+
+		if ((md->phys_addr <= phys_addr) && (phys_addr <=
+		    (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1)))
+			 return md->type;
+	}
+	return 0;
+}
+
+u64
+efi_mem_attributes (unsigned long phys_addr)
+{
+	void *efi_map_start, *efi_map_end, *p;
+	efi_memory_desc_t *md;
+	u64 efi_desc_size;
+
+	efi_map_start = __va(ia64_boot_param->efi_memmap);
+	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
+	efi_desc_size = ia64_boot_param->efi_memdesc_size;
+
+	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
+		md = p;
+
+		if ((md->phys_addr <= phys_addr) && (phys_addr <=
+		    (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1)))
+			return md->attribute;
+	}
+	return 0;
+}
+
 static void __exit
-efivars_exit(void)
+efivars_exit (void)
 {
 #ifdef CONFIG_PROC_FS
  	remove_proc_entry(efi_dir->name, NULL);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/efi_stub.S linux-2.4.20/arch/ia64/kernel/efi_stub.S
--- linux-2.4.19/arch/ia64/kernel/efi_stub.S	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/efi_stub.S	2002-10-29 11:18:30.000000000 +0000
@@ -53,23 +53,21 @@
 	mov loc4=ar.rsc			// save RSE configuration
 	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
 	;;
-
 	ld8 gp=[in0]			// load EFI function's global pointer
-	mov out0=in1
-	mov out1=in2
 	movl r16=PSR_BITS_TO_CLEAR
-
 	mov loc3=psr			// save processor status word
 	movl r17=PSR_BITS_TO_SET
 	;;
-	mov out2=in3
 	or loc3=loc3,r17
 	mov b6=r2
 	;;
 	andcm r16=loc3,r16		// get psr with IT, DT, and RT bits cleared
-	mov out3=in4
 	br.call.sptk.many rp=ia64_switch_mode
 .ret0:	mov out4=in5
+	mov out0=in1
+	mov out1=in2
+	mov out2=in3
+	mov out3=in4
 	mov out5=in6
 	mov out6=in7
 	br.call.sptk.many rp=b6		// call the EFI function
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/efivars.c linux-2.4.20/arch/ia64/kernel/efivars.c
--- linux-2.4.19/arch/ia64/kernel/efivars.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/efivars.c	2002-10-29 11:18:40.000000000 +0000
@@ -29,6 +29,9 @@
  *
  * Changelog:
  *
+ *  25 Mar 2002 - Matt Domsch <Matt_Domsch@dell.com>
+ *   move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse()
+ *
  *  12 Feb 2002 - Matt Domsch <Matt_Domsch@dell.com>
  *   use list_for_each_safe when deleting vars.
  *   remove ifdef CONFIG_SMP around include <linux/smp.h>
@@ -62,15 +65,15 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/smp.h>
+#include <linux/efi.h>
 
-#include <asm/efi.h>
 #include <asm/uaccess.h>
 
 MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
 MODULE_DESCRIPTION("/proc interface to EFI Variables");
 MODULE_LICENSE("GPL");
 
-#define EFIVARS_VERSION "0.04 2002-Feb-12"
+#define EFIVARS_VERSION "0.05 2002-Mar-26"
 
 static int
 efivar_read(char *page, char **start, off_t off,
@@ -141,20 +144,6 @@
 	return len;
 }
 
-
-static void
-uuid_unparse(efi_guid_t *guid, char *out)
-{
-	sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
-		guid->data1, guid->data2, guid->data3,
-		guid->data4[0], guid->data4[1], guid->data4[2], guid->data4[3],
-		guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]);
-}
-
-
-
-
-
 /*
  * efivar_create_proc_entry()
  * Requires:
@@ -197,7 +186,7 @@
 	   private variables from another's.         */
 
 	*(short_name + strlen(short_name)) = '-';
-	uuid_unparse(vendor_guid, short_name + strlen(short_name));
+	efi_guid_unparse(vendor_guid, short_name + strlen(short_name));
 
 
 	/* Create the entry in proc */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/entry.S linux-2.4.20/arch/ia64/kernel/entry.S
--- linux-2.4.19/arch/ia64/kernel/entry.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/entry.S	2002-10-29 11:18:35.000000000 +0000
@@ -3,7 +3,7 @@
  *
  * Kernel entry points.
  *
- * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2002 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
@@ -667,23 +667,38 @@
 	/*
 	 * To prevent leaking bits between the kernel and user-space,
 	 * we must clear the stacked registers in the "invalid" partition here.
-	 * Not pretty, but at least it's fast (3.34 registers/cycle).
-	 * Architecturally, this loop could go at 4.67 registers/cycle, but that would
-	 * oversubscribe Itanium.
+	 * Not pretty, but at least it's fast (3.34 registers/cycle on Itanium,
+	 * 5 registers/cycle on McKinley).
 	 */
 #	define pRecurse	p6
 #	define pReturn	p7
+#ifdef CONFIG_ITANIUM
 #	define Nregs	10
+#else
+#	define Nregs	14
+#endif
 	alloc loc0=ar.pfs,2,Nregs-2,2,0
 	shr.u loc1=r18,9		// RNaTslots <= dirtySize / (64*8) + 1
 	sub r17=r17,r18			// r17 = (physStackedSize + 8) - dirtySize
 	;;
+#if 1
+	.align 32		// see comment below about gas bug...
+#endif
 	mov ar.rsc=r19			// load ar.rsc to be used for "loadrs"
 	shladd in0=loc1,3,r17
 	mov in1=0
+#if 0
+	// gas-2.11.90 is unable to generate a stop bit after .align, which is bad,
+	// because alloc must be at the beginning of an insn-group.
+	.align 32
+#else
+	nop 0
+	nop 0
+	nop 0
+#endif
 	;;
-//	.align 32	// gas-2.11.90 is unable to generate a stop bit after .align
 rse_clear_invalid:
+#ifdef CONFIG_ITANIUM
 	// cycle 0
  { .mii
 	alloc loc0=ar.pfs,2,Nregs-2,2,0
@@ -712,9 +727,31 @@
 	mov loc7=0
 (pReturn) br.ret.sptk.many b6
 }
+#else /* !CONFIG_ITANIUM */
+	alloc loc0=ar.pfs,2,Nregs-2,2,0
+	cmp.lt pRecurse,p0=Nregs*8,in0	// if more than Nregs regs left to clear, (re)curse
+	add out0=-Nregs*8,in0
+	add out1=1,in1			// increment recursion count
+	mov loc1=0
+	mov loc2=0
+	;;
+	mov loc3=0
+	mov loc4=0
+	mov loc9=0
+	mov loc5=0
+	mov loc6=0
+(pRecurse) br.call.sptk.many b6=rse_clear_invalid
+	;;
+	mov loc7=0
+	mov loc8=0
+	cmp.ne pReturn,p0=r0,in1	// if recursion count != 0, we need to do a br.ret
+	mov loc10=0
+	mov loc11=0
+(pReturn) br.ret.sptk.many b6
+#endif /* !CONFIG_ITANIUM */
 #	undef pRecurse
 #	undef pReturn
-
+	;;
 	alloc r17=ar.pfs,0,0,0,0	// drop current register frame
 	;;
 	loadrs
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/fw-emu.c linux-2.4.20/arch/ia64/kernel/fw-emu.c
--- linux-2.4.19/arch/ia64/kernel/fw-emu.c	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/fw-emu.c	2002-10-29 11:18:32.000000000 +0000
@@ -13,14 +13,16 @@
 # include <linux/pci.h>
 #endif
 
-#include <asm/efi.h>
+#include <linux/efi.h>
 #include <asm/io.h>
 #include <asm/pal.h>
 #include <asm/sal.h>
 
 #define MB	(1024*1024UL)
+#define GB	(1024*MB)
+#define TB	(1024*GB)
 
-#define NUM_MEM_DESCS	3
+#define NUM_MEM_DESCS	4
 
 static char fw_mem[(  sizeof(struct ia64_boot_param)
 		    + sizeof(efi_system_table_t)
@@ -471,7 +473,7 @@
 	md->phys_addr = 0*MB;
 	md->virt_addr = 0;
 	md->num_pages = (1*MB) >> 12;	/* 1MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB;
+	md->attribute = EFI_MEMORY_WB | EFI_MEMORY_WC | EFI_MEMORY_UC;
 
 	/* fill in a memory descriptor: */
 	md = &efi_memmap[1];
@@ -489,23 +491,16 @@
 	md->phys_addr = 1*MB;
 	md->virt_addr = 1*MB;
 	md->num_pages = (1*MB) >> 12;	/* 1MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB;
-
-#if 0
-	/*
-	 * XXX bootmem is broken for now... (remember to NUM_MEM_DESCS
-	 * if you re-enable this!)
-	 */
+	md->attribute = EFI_MEMORY_WB | EFI_MEMORY_WC | EFI_MEMORY_UC;
 
-	/* descriptor for high memory (>4GB): */
+	/* descriptor for high memory (>4TB): */
 	md = &efi_memmap[3];
 	md->type = EFI_CONVENTIONAL_MEMORY;
 	md->pad = 0;
-	md->phys_addr = 4096*MB;
+	md->phys_addr = 4*TB;
 	md->virt_addr = 0;
-	md->num_pages = (32*MB) >> 12;	/* 32MB (in 4KB pages) */
+	md->num_pages = (64*MB) >> 12;	/* 64MB (in 4KB pages) */
 	md->attribute = EFI_MEMORY_WB;
-#endif
 
 	bp->efi_systab = __pa(&fw_mem);
 	bp->efi_memmap = __pa(efi_memmap);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/gate.S linux-2.4.20/arch/ia64/kernel/gate.S
--- linux-2.4.19/arch/ia64/kernel/gate.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/gate.S	2002-10-29 11:18:35.000000000 +0000
@@ -29,7 +29,7 @@
 #	define UNAT_OFF		IA64_SIGCONTEXT_AR_UNAT_OFFSET
 #	define FPSR_OFF		IA64_SIGCONTEXT_AR_FPSR_OFFSET
 #	define PR_OFF		IA64_SIGCONTEXT_PR_OFFSET
-#	define RP_OFF		IA64_SIGCONTEXT_B0_OFFSET
+#	define RP_OFF		IA64_SIGCONTEXT_IP_OFFSET
 #	define SP_OFF		IA64_SIGCONTEXT_R12_OFFSET
 #	define RBS_BASE_OFF	IA64_SIGCONTEXT_RBS_BASE_OFFSET
 #	define LOADRS_OFF	IA64_SIGCONTEXT_LOADRS_OFFSET
@@ -108,7 +108,7 @@
 	dep r8=0,r8,38,26			// clear EC0, CPL0 and reserved bits
 	adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp
 	;;
-	.spillsp ar.pfs, CFM_OFF
+	.spillsp ar.pfs, CFM_OFF+SIGCONTEXT_OFF
 	st8 [base0]=r8				// save CFM0
 	adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
 	;;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/head.S linux-2.4.20/arch/ia64/kernel/head.S
--- linux-2.4.19/arch/ia64/kernel/head.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/head.S	2002-10-29 11:18:49.000000000 +0000
@@ -562,137 +562,114 @@
 END(__ia64_load_fpu)
 
 GLOBAL_ENTRY(__ia64_init_fpu)
-	alloc r2=ar.pfs,0,0,0,0
-	stf.spill [sp]=f0
-	mov      f32=f0
-	;;
-	ldf.fill f33=[sp]
-	ldf.fill f34=[sp]
-	mov      f35=f0
-	;;
-	ldf.fill f36=[sp]
-	ldf.fill f37=[sp]
-	mov      f38=f0
-	;;
-	ldf.fill f39=[sp]
-	ldf.fill f40=[sp]
-	mov      f41=f0
-	;;
-	ldf.fill f42=[sp]
-	ldf.fill f43=[sp]
-	mov      f44=f0
-	;;
-	ldf.fill f45=[sp]
-	ldf.fill f46=[sp]
-	mov      f47=f0
-	;;
-	ldf.fill f48=[sp]
-	ldf.fill f49=[sp]
-	mov      f50=f0
-	;;
-	ldf.fill f51=[sp]
-	ldf.fill f52=[sp]
-	mov      f53=f0
-	;;
-	ldf.fill f54=[sp]
-	ldf.fill f55=[sp]
-	mov      f56=f0
-	;;
-	ldf.fill f57=[sp]
-	ldf.fill f58=[sp]
-	mov      f59=f0
-	;;
-	ldf.fill f60=[sp]
-	ldf.fill f61=[sp]
-	mov      f62=f0
-	;;
-	ldf.fill f63=[sp]
-	ldf.fill f64=[sp]
-	mov      f65=f0
-	;;
-	ldf.fill f66=[sp]
-	ldf.fill f67=[sp]
-	mov      f68=f0
-	;;
-	ldf.fill f69=[sp]
-	ldf.fill f70=[sp]
-	mov      f71=f0
-	;;
-	ldf.fill f72=[sp]
-	ldf.fill f73=[sp]
-	mov      f74=f0
-	;;
-	ldf.fill f75=[sp]
-	ldf.fill f76=[sp]
-	mov      f77=f0
-	;;
-	ldf.fill f78=[sp]
-	ldf.fill f79=[sp]
-	mov      f80=f0
-	;;
-	ldf.fill f81=[sp]
-	ldf.fill f82=[sp]
-	mov      f83=f0
-	;;
-	ldf.fill f84=[sp]
-	ldf.fill f85=[sp]
-	mov      f86=f0
-	;;
-	ldf.fill f87=[sp]
-	ldf.fill f88=[sp]
-	mov      f89=f0
-	;;
-	ldf.fill f90=[sp]
-	ldf.fill f91=[sp]
-	mov      f92=f0
-	;;
-	ldf.fill f93=[sp]
-	ldf.fill f94=[sp]
-	mov      f95=f0
-	;;
-	ldf.fill f96=[sp]
-	ldf.fill f97=[sp]
-	mov      f98=f0
-	;;
-	ldf.fill f99=[sp]
-	ldf.fill f100=[sp]
-	mov      f101=f0
-	;;
-	ldf.fill f102=[sp]
-	ldf.fill f103=[sp]
-	mov      f104=f0
-	;;
-	ldf.fill f105=[sp]
-	ldf.fill f106=[sp]
-	mov      f107=f0
-	;;
-	ldf.fill f108=[sp]
-	ldf.fill f109=[sp]
-	mov      f110=f0
-	;;
-	ldf.fill f111=[sp]
-	ldf.fill f112=[sp]
-	mov      f113=f0
-	;;
-	ldf.fill f114=[sp]
-	ldf.fill f115=[sp]
-	mov      f116=f0
-	;;
-	ldf.fill f117=[sp]
-	ldf.fill f118=[sp]
-	mov      f119=f0
-	;;
-	ldf.fill f120=[sp]
-	ldf.fill f121=[sp]
-	mov      f122=f0
-	;;
-	ldf.fill f123=[sp]
-	ldf.fill f124=[sp]
-	mov      f125=f0
-	;;
-	ldf.fill f126=[sp]
-	mov      f127=f0
-	br.ret.sptk.many rp
+	stf.spill [sp]=f0		// M3
+	mov	 f32=f0			// F
+	nop.b	 0
+
+	ldfps	 f33,f34=[sp]		// M0
+	ldfps	 f35,f36=[sp]		// M1
+	mov      f37=f0			// F
+	;;
+
+	setf.s	 f38=r0			// M2
+	setf.s	 f39=r0			// M3
+	mov      f40=f0			// F
+
+	ldfps	 f41,f42=[sp]		// M0
+	ldfps	 f43,f44=[sp]		// M1
+	mov      f45=f0			// F
+
+	setf.s	 f46=r0			// M2
+	setf.s	 f47=r0			// M3
+	mov      f48=f0			// F
+
+	ldfps	 f49,f50=[sp]		// M0
+	ldfps	 f51,f52=[sp]		// M1
+	mov      f53=f0			// F
+
+	setf.s	 f54=r0			// M2
+	setf.s	 f55=r0			// M3
+	mov      f56=f0			// F
+
+	ldfps	 f57,f58=[sp]		// M0
+	ldfps	 f59,f60=[sp]		// M1
+	mov      f61=f0			// F
+
+	setf.s	 f62=r0			// M2
+	setf.s	 f63=r0			// M3
+	mov      f64=f0			// F
+
+	ldfps	 f65,f66=[sp]		// M0
+	ldfps	 f67,f68=[sp]		// M1
+	mov      f69=f0			// F
+
+	setf.s	 f70=r0			// M2
+	setf.s	 f71=r0			// M3
+	mov      f72=f0			// F
+
+	ldfps	 f73,f74=[sp]		// M0
+	ldfps	 f75,f76=[sp]		// M1
+	mov      f77=f0			// F
+
+	setf.s	 f78=r0			// M2
+	setf.s	 f79=r0			// M3
+	mov      f80=f0			// F
+
+	ldfps	 f81,f82=[sp]		// M0
+	ldfps	 f83,f84=[sp]		// M1
+	mov      f85=f0			// F
+
+	setf.s	 f86=r0			// M2
+	setf.s	 f87=r0			// M3
+	mov      f88=f0			// F
+
+	/*
+	 * When the instructions are cached, it would be faster to initialize
+	 * the remaining registers with simply mov instructions (F-unit).
+	 * This gets the time down to ~29 cycles.  However, this would use up
+	 * 33 bundles, whereas continuing with the above pattern yields
+	 * 10 bundles and ~30 cycles.
+	 */
+
+	ldfps	 f89,f90=[sp]		// M0
+	ldfps	 f91,f92=[sp]		// M1
+	mov      f93=f0			// F
+
+	setf.s	 f94=r0			// M2
+	setf.s	 f95=r0			// M3
+	mov      f96=f0			// F
+
+	ldfps	 f97,f98=[sp]		// M0
+	ldfps	 f99,f100=[sp]		// M1
+	mov      f101=f0		// F
+
+	setf.s	 f102=r0		// M2
+	setf.s	 f103=r0		// M3
+	mov      f104=f0		// F
+
+	ldfps	 f105,f106=[sp]		// M0
+	ldfps	 f107,f108=[sp]		// M1
+	mov      f109=f0		// F
+
+	setf.s	 f110=r0		// M2
+	setf.s	 f111=r0		// M3
+	mov      f112=f0		// F
+
+	ldfps	 f113,f114=[sp]		// M0
+	ldfps	 f115,f116=[sp]		// M1
+	mov      f117=f0		// F
+
+	setf.s	 f118=r0		// M2
+	setf.s	 f119=r0		// M3
+	mov      f120=f0		// F
+
+	ldfps	 f121,f122=[sp]		// M0
+	ldfps	 f123,f124=[sp]		// M1
+	mov      f125=f0		// F
+
+	setf.s	 f126=r0		// M2
+	setf.s	 f127=r0		// M3
+	br.ret.sptk.many rp		// F
 END(__ia64_init_fpu)
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/ia64_ksyms.c linux-2.4.20/arch/ia64/kernel/ia64_ksyms.c
--- linux-2.4.19/arch/ia64/kernel/ia64_ksyms.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/ia64_ksyms.c	2002-10-29 11:18:40.000000000 +0000
@@ -1,11 +1,11 @@
 /*
  * Architecture-specific kernel symbols
  */
-
 #include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/string.h>
+
 EXPORT_SYMBOL_NOVERS(memset);
 EXPORT_SYMBOL(memchr);
 EXPORT_SYMBOL(memcmp);
@@ -148,3 +148,10 @@
 #include <linux/proc_fs.h>
 extern struct proc_dir_entry *efi_dir;
 EXPORT_SYMBOL(efi_dir);
+
+#include <asm/machvec.h>
+#ifdef CONFIG_IA64_GENERIC
+EXPORT_SYMBOL(ia64_mv);
+#endif
+EXPORT_SYMBOL(machvec_noop);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/iosapic.c linux-2.4.20/arch/ia64/kernel/iosapic.c
--- linux-2.4.19/arch/ia64/kernel/iosapic.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/iosapic.c	2002-10-29 11:18:40.000000000 +0000
@@ -22,30 +22,44 @@
  * 02/01/07     E. Focht        <efocht@ess.nec.de> Redirectable interrupt vectors in
  *                              iosapic_set_affinity(), initializations for
  *                              /proc/irq/#/smp_affinity
+ * 02/04/02	P. Diefenbaugh	Cleaned up ACPI PCI IRQ routing.
+ * 02/04/18	J.I. Lee	bug fix in iosapic_init_pci_irq
+ * 02/04/30	J.I. Lee	bug fix in find_iosapic to fix ACPI PCI IRQ to IOSAPIC mapping error
+ * 02/07/29	T. Kochi	Allocate interrupt vectors dynamically
+ * 02/08/04	T. Kochi	Cleaned up terminology (irq, global system interrupt, vector, etc.)
+ * 02/08/13	B. Helgaas	Support PCI segments
  */
 /*
  * Here is what the interrupt logic between a PCI device and the CPU looks like:
  *
  * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD).  The
- *     device is uniquely identified by its bus--, and slot-number (the function
+ *     device is uniquely identified by its segment--, bus--, and slot-number (the function
  *     number does not matter here because all functions share the same interrupt
  *     lines).
  *
  * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC controller.
  *     Multiple interrupt lines may have to share the same IOSAPIC pin (if they're level
- *     triggered and use the same polarity).  Each interrupt line has a unique IOSAPIC
- *     irq number which can be calculated as the sum of the controller's base irq number
- *     and the IOSAPIC pin number to which the line connects.
+ *     triggered and use the same polarity).  Each interrupt line has a unique Global
+ *     System Interrupt (GSI) number which can be calculated as the sum of the controller's
+ *     base GSI number and the IOSAPIC pin number to which the line connects.
  *
- * (3) The IOSAPIC uses an internal table to map the IOSAPIC pin into the IA-64 interrupt
- *     vector.  This interrupt vector is then sent to the CPU.
+ * (3) The IOSAPIC uses internal routing table entries (RTEs) to map the IOSAPIC pin
+ *     to the IA-64 interrupt vector.  This interrupt vector is then sent to the CPU.
  *
- * In other words, there are two levels of indirections involved:
+ * (4) The kernel recognizes an interrupt as an IRQ.  The IRQ interface
+ *     is an architecture-independent interrupt handling mechanism in
+ *     Linux.  An IRQ is a number, so we need a mapping between IRQ
+ *     numbers and IA-64 vectors.  The platform_irq_to_vector(irq) and
+ *     platform_local_vector_to_irq(vector) APIs can define platform-
+ *     specific mappings.
  *
- *	pci pin -> iosapic irq -> IA-64 vector
+ * To sum up, there are three levels of mappings involved:
  *
- * Note: outside this module, IA-64 vectors are called "irqs".  This is because that's
- * the traditional name Linux uses for interrupt vectors.
+ *	PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ
+ *
+ * Note: The term "IRQ" is loosely used everywhere in the Linux kernel
+ * to describe interrupts.  In this module, "IRQ" refers only to Linux
+ * IRQ numbers ("isa_irq" is an exception to this rule).
  */
 #include <linux/config.h>
 
@@ -56,9 +70,8 @@
 #include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/irq.h>
+#include <linux/acpi.h>
 
-#include <asm/acpi-ext.h>
-#include <asm/acpikcfg.h>
 #include <asm/delay.h>
 #include <asm/hw_irq.h>
 #include <asm/io.h>
@@ -69,80 +82,103 @@
 #include <asm/system.h>
 
 
-#undef DEBUG_IRQ_ROUTING
-#undef	OVERRIDE_DEBUG
+#undef DEBUG_INTERRUPT_ROUTING
+#undef OVERRIDE_DEBUG
+
+#ifdef DEBUG_INTERRUPT_ROUTING
+#define DBG(fmt...)	printk(fmt)
+#else
+#define DBG(fmt...)
+#endif
 
 static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED;
 
-/* PCI pin to IOSAPIC irq routing information.  This info typically comes from ACPI. */
+/* PCI pin to GSI routing information.  This info typically comes from ACPI. */
 
 static struct {
 	int num_routes;
 	struct pci_vector_struct *route;
 } pci_irq;
 
-/* This tables maps IA-64 vectors to the IOSAPIC pin that generates this vector. */
+/* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */
+
+static struct iosapic_intr_info {
+	char		*addr;		/* base address of IOSAPIC */
+	unsigned int	gsi_base;	/* first GSI assigned to this IOSAPIC */
+	char		rte_index;	/* IOSAPIC RTE index (-1 => not an IOSAPIC interrupt) */
+	unsigned char	dmode	: 3;	/* delivery mode (see iosapic.h) */
+	unsigned char 	polarity: 1;	/* interrupt polarity (see iosapic.h) */
+	unsigned char	trigger	: 1;	/* trigger mode (see iosapic.h) */
+} iosapic_intr_info[IA64_NUM_VECTORS];
+
+static struct iosapic {
+	char		*addr;		/* base address of IOSAPIC */
+	unsigned int 	gsi_base;	/* first GSI assigned to this IOSAPIC */
+	unsigned short 	num_rte;	/* number of RTE in this IOSAPIC */
+	unsigned char	pcat_compat;	/* 8259 compatibility flag */
+} iosapic_lists[256] __devinitdata;
+
+static int __devinitdata num_iosapic = 0;
 
-static struct iosapic_irq {
-	char *addr;			/* base address of IOSAPIC */
-	unsigned char base_irq;		/* first irq assigned to this IOSAPIC */
-	char pin;			/* IOSAPIC pin (-1 => not an IOSAPIC irq) */
-	unsigned char dmode	: 3;	/* delivery mode (see iosapic.h) */
-	unsigned char polarity	: 1;	/* interrupt polarity (see iosapic.h) */
-	unsigned char trigger	: 1;	/* trigger mode (see iosapic.h) */
-} iosapic_irq[IA64_NUM_VECTORS];
 
 /*
- * Translate IOSAPIC irq number to the corresponding IA-64 interrupt vector.  If no
- * entry exists, return -1.
+ * Find an IOSAPIC associated with a GSI
  */
-int
-iosapic_irq_to_vector (int irq)
+static inline int __devinit
+find_iosapic (unsigned int gsi)
 {
-	int vector;
+	int i;
 
-	for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
-		if (iosapic_irq[vector].base_irq + iosapic_irq[vector].pin == irq)
-			return vector;
+	for (i = 0; i < num_iosapic; i++)
+		if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
+			return i;
 	return -1;
 }
 
 /*
- * Map PCI pin to the corresponding IA-64 interrupt vector.  If no such mapping exists,
- * return -1.
+ * Translate GSI number to the corresponding IA-64 interrupt vector.  If no
+ * entry exists, return -1.
  */
-static int
-pci_pin_to_vector (int bus, int slot, int pci_pin)
+int
+gsi_to_vector (unsigned int gsi)
 {
-	struct pci_vector_struct *r;
+	int vector;
 
-	for (r = pci_irq.route; r < pci_irq.route + pci_irq.num_routes; ++r)
-		if (r->bus == bus && (r->pci_id >> 16) == slot && r->pin == pci_pin)
-			return iosapic_irq_to_vector(r->irq);
+	for (vector = 0; vector < IA64_NUM_VECTORS; vector++)
+		if (iosapic_intr_info[vector].gsi_base + iosapic_intr_info[vector].rte_index == gsi)
+			return vector;
 	return -1;
 }
 
 static void
-set_rte (unsigned int vector, unsigned long dest)
+set_rte (unsigned int vector, unsigned int dest)
 {
 	unsigned long pol, trigger, dmode;
 	u32 low32, high32;
 	char *addr;
-	int pin;
+	int rte_index;
 	char redir;
 
-	pin = iosapic_irq[vector].pin;
-	if (pin < 0)
+	rte_index = iosapic_intr_info[vector].rte_index;
+	if (rte_index < 0)
 		return;		/* not an IOSAPIC interrupt */
 
-	addr    = iosapic_irq[vector].addr;
-	pol     = iosapic_irq[vector].polarity;
-	trigger = iosapic_irq[vector].trigger;
-	dmode   = iosapic_irq[vector].dmode;
+	addr    = iosapic_intr_info[vector].addr;
+	pol     = iosapic_intr_info[vector].polarity;
+	trigger = iosapic_intr_info[vector].trigger;
+	dmode   = iosapic_intr_info[vector].dmode;
 
 	redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0;
 #ifdef CONFIG_SMP
-	set_irq_affinity_info(vector, (int)(dest & 0xffff), redir);
+	{
+		int irq;
+
+		for (irq = 0; irq < NR_IRQS; ++irq)
+			if (irq_to_vector(irq) == vector) {
+				set_irq_affinity_info(irq, (int)(dest & 0xffff), redir);
+				break;
+			}
+	}
 #endif
 
 	low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
@@ -153,9 +189,9 @@
 	/* dest contains both id and eid */
 	high32 = (dest << IOSAPIC_DEST_SHIFT);
 
-	writel(IOSAPIC_RTE_HIGH(pin), addr + IOSAPIC_REG_SELECT);
+	writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT);
 	writel(high32, addr + IOSAPIC_WINDOW);
-	writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT);
+	writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
 	writel(low32, addr + IOSAPIC_WINDOW);
 }
 
@@ -171,18 +207,18 @@
 	unsigned long flags;
 	char *addr;
 	u32 low32;
-	int pin;
+	int rte_index;
 	ia64_vector vec = irq_to_vector(irq);
 
-	addr = iosapic_irq[vec].addr;
-	pin = iosapic_irq[vec].pin;
+	addr = iosapic_intr_info[vec].addr;
+	rte_index = iosapic_intr_info[vec].rte_index;
 
-	if (pin < 0)
+	if (rte_index < 0)
 		return;			/* not an IOSAPIC interrupt! */
 
 	spin_lock_irqsave(&iosapic_lock, flags);
 	{
-		writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT);
+		writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
 		low32 = readl(addr + IOSAPIC_WINDOW);
 
 		low32 |= (1 << IOSAPIC_MASK_SHIFT);    /* set only the mask bit */
@@ -197,17 +233,17 @@
 	unsigned long flags;
 	char *addr;
 	u32 low32;
-	int pin;
+	int rte_index;
 	ia64_vector vec = irq_to_vector(irq);
 
-	addr = iosapic_irq[vec].addr;
-	pin = iosapic_irq[vec].pin;
-	if (pin < 0)
+	addr = iosapic_intr_info[vec].addr;
+	rte_index = iosapic_intr_info[vec].rte_index;
+	if (rte_index < 0)
 		return;			/* not an IOSAPIC interrupt! */
 
 	spin_lock_irqsave(&iosapic_lock, flags);
 	{
-		writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT);
+		writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
 		low32 = readl(addr + IOSAPIC_WINDOW);
 
 		low32 &= ~(1 << IOSAPIC_MASK_SHIFT);    /* clear only the mask bit */
@@ -223,24 +259,28 @@
 #ifdef CONFIG_SMP
 	unsigned long flags;
 	u32 high32, low32;
-	int dest, pin;
+	int dest, rte_index;
 	char *addr;
-	int redir = (irq & (1<<31)) ? 1 : 0;
+	int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
+	ia64_vector vec;
+
+	irq &= (~IA64_IRQ_REDIRECTED);
+	vec = irq_to_vector(irq);
 
 	mask &= (1UL << smp_num_cpus) - 1;
 
-	if (!mask || irq >= IA64_NUM_VECTORS)
+	if (!mask || vec >= IA64_NUM_VECTORS)
 		return;
 
 	dest = cpu_physical_id(ffz(~mask));
 
-	pin = iosapic_irq[irq].pin;
-	addr = iosapic_irq[irq].addr;
+	rte_index = iosapic_intr_info[vec].rte_index;
+	addr = iosapic_intr_info[vec].addr;
 
-	if (pin < 0)
+	if (rte_index < 0)
 		return;			/* not an IOSAPIC interrupt */
 
-	set_irq_affinity_info(irq,dest,redir);
+	set_irq_affinity_info(irq, dest, redir);
 
 	/* dest contains both id and eid */
 	high32 = dest << IOSAPIC_DEST_SHIFT;
@@ -248,7 +288,7 @@
 	spin_lock_irqsave(&iosapic_lock, flags);
 	{
 		/* get current delivery mode by reading the low32 */
-		writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT);
+		writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
 		low32 = readl(addr + IOSAPIC_WINDOW);
 
 		low32 &= ~(7 << IOSAPIC_DELIVERY_SHIFT);
@@ -259,9 +299,9 @@
 		        /* change delivery mode to fixed */
 			low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
 
-		writel(IOSAPIC_RTE_HIGH(pin), addr + IOSAPIC_REG_SELECT);
+		writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT);
 		writel(high32, addr + IOSAPIC_WINDOW);
-		writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT);
+		writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
 		writel(low32, addr + IOSAPIC_WINDOW);
 	}
 	spin_unlock_irqrestore(&iosapic_lock, flags);
@@ -284,7 +324,7 @@
 {
 	ia64_vector vec = irq_to_vector(irq);
 
-	writel(vec, iosapic_irq[vec].addr + IOSAPIC_EOI);
+	writel(vec, iosapic_intr_info[vec].addr + IOSAPIC_EOI);
 }
 
 #define iosapic_shutdown_level_irq	mask_irq
@@ -355,7 +395,7 @@
 	 * {
 	 *	unsigned int version   : 8;
 	 *	unsigned int reserved1 : 8;
-	 *	unsigned int pins      : 8;
+	 *	unsigned int max_redir : 8;
 	 *	unsigned int reserved2 : 8;
 	 * }
 	 */
@@ -372,69 +412,72 @@
 {
 	int new_vector;
 
-	if (iosapic_irq[vector].pin >= 0 || iosapic_irq[vector].addr
-	    || iosapic_irq[vector].base_irq || iosapic_irq[vector].dmode
-	    || iosapic_irq[vector].polarity || iosapic_irq[vector].trigger)
+	if (iosapic_intr_info[vector].rte_index >= 0 || iosapic_intr_info[vector].addr
+	    || iosapic_intr_info[vector].gsi_base || iosapic_intr_info[vector].dmode
+	    || iosapic_intr_info[vector].polarity || iosapic_intr_info[vector].trigger)
 	{
-		new_vector = ia64_alloc_irq();
-		printk("Reassigning Vector 0x%x to 0x%x\n", vector, new_vector);
-		memcpy (&iosapic_irq[new_vector], &iosapic_irq[vector],
-			sizeof(struct iosapic_irq));
-		memset (&iosapic_irq[vector], 0, sizeof(struct iosapic_irq));
-		iosapic_irq[vector].pin = -1;
+		new_vector = ia64_alloc_vector();
+		printk("Reassigning Vector %d to %d\n", vector, new_vector);
+		memcpy (&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
+			sizeof(struct iosapic_intr_info));
+		memset (&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
+		iosapic_intr_info[vector].rte_index = -1;
 	}
 }
 
 static void
-register_irq (u32 global_vector, int vector, int pin, unsigned char delivery,
-	      unsigned long polarity, unsigned long edge_triggered,
-	      u32 base_irq, char *iosapic_address)
+register_intr (unsigned int gsi, int vector, unsigned char delivery,
+	       unsigned long polarity, unsigned long edge_triggered,
+	       unsigned int gsi_base, char *iosapic_address)
 {
 	irq_desc_t *idesc;
 	struct hw_interrupt_type *irq_type;
+	int rte_index;
 
-	iosapic_irq[vector].pin	= pin;
-	iosapic_irq[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW;
-	iosapic_irq[vector].dmode    = delivery;
+	rte_index = gsi - gsi_base;
+	iosapic_intr_info[vector].rte_index = rte_index;
+	iosapic_intr_info[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW;
+	iosapic_intr_info[vector].dmode    = delivery;
 
 	/*
-	 * In override, it does not provide addr/base_irq.  global_vector is enough to
-	 * locate iosapic addr, base_irq and pin by examining base_irq and max_pin of
-	 * registered iosapics (tbd)
+	 * In override, it may not provide addr/gsi_base.  GSI is enough to
+	 * locate iosapic addr, gsi_base and rte_index by examining
+	 * gsi_base and num_rte of registered iosapics (tbd)
 	 */
 #ifndef	OVERRIDE_DEBUG
 	if (iosapic_address) {
-		iosapic_irq[vector].addr = iosapic_address;
-		iosapic_irq[vector].base_irq = base_irq;
+		iosapic_intr_info[vector].addr = iosapic_address;
+		iosapic_intr_info[vector].gsi_base = gsi_base;
 	}
 #else
 	if (iosapic_address) {
-		if (iosapic_irq[vector].addr && (iosapic_irq[vector].addr != iosapic_address))
-			printk("WARN: register_irq: diff IOSAPIC ADDRESS for gv %x, v %x\n",
-			       global_vector, vector);
-		iosapic_irq[vector].addr = iosapic_address;
-		if (iosapic_irq[vector].base_irq && (iosapic_irq[vector].base_irq != base_irq)) {
-			printk("WARN: register_irq: diff BASE IRQ %x for gv %x, v %x\n",
-			       base_irq, global_vector, vector);
+		if (iosapic_intr_info[vector].addr && (iosapic_intr_info[vector].addr != iosapic_address))
+			printk("WARN: %s: diff IOSAPIC ADDRESS for GSI 0x%x, vector %d\n",
+			       __FUNCTION__, gsi, vector);
+		iosapic_intr_info[vector].addr = iosapic_address;
+		if (iosapic_intr_info[vector].gsi_base && (iosapic_intr_info[vector].gsi_base != gsi_base)) {
+			printk("WARN: %s: diff GSI base 0x%x for GSI 0x%x, vector %d\n",
+			       __FUNCTION__, gsi_base, gsi, vector);
 		}
-		iosapic_irq[vector].base_irq = base_irq;
-	} else if (!iosapic_irq[vector].addr)
-		printk("WARN: register_irq: invalid override for gv %x, v %x\n",
-		       global_vector, vector);
+		iosapic_intr_info[vector].gsi_base = gsi_base;
+	} else if (!iosapic_intr_info[vector].addr)
+		printk("WARN: %s: invalid override for GSI 0x%x, vector %d\n",
+		       __FUNCTION__, gsi, vector);
 #endif
 	if (edge_triggered) {
-		iosapic_irq[vector].trigger = IOSAPIC_EDGE;
+		iosapic_intr_info[vector].trigger = IOSAPIC_EDGE;
 		irq_type = &irq_type_iosapic_edge;
 	} else {
-		iosapic_irq[vector].trigger = IOSAPIC_LEVEL;
+		iosapic_intr_info[vector].trigger = IOSAPIC_LEVEL;
 		irq_type = &irq_type_iosapic_level;
 	}
 
 	idesc = irq_desc(vector);
 	if (idesc->handler != irq_type) {
 		if (idesc->handler != &no_irq_type)
-			printk("register_irq(): changing vector 0x%02x from "
-			       "%s to %s\n", vector, idesc->handler->typename, irq_type->typename);
+			printk("%s: changing vector %d from %s to %s\n",
+			       __FUNCTION__, vector, idesc->handler->typename,
+			       irq_type->typename);
 		idesc->handler = irq_type;
 	}
 }
@@ -445,24 +488,26 @@
  * program the IOSAPIC RTE.
  */
 int
-iosapic_register_irq (u32 global_vector, unsigned long polarity, unsigned long
-                      edge_triggered, u32 base_irq, char *iosapic_address)
+iosapic_register_intr (unsigned int gsi,
+		       unsigned long polarity, unsigned long edge_triggered,
+		       unsigned int gsi_base, char *iosapic_address)
 {
 	int vector;
+	unsigned int dest = (ia64_get_lid() >> 16) & 0xffff;
 
-	vector = iosapic_irq_to_vector(global_vector);
+	vector = gsi_to_vector(gsi);
 	if (vector < 0)
-		vector = ia64_alloc_irq();
+		vector = ia64_alloc_vector();
 
-	register_irq (global_vector, vector, global_vector - base_irq,
-			IOSAPIC_LOWEST_PRIORITY, polarity, edge_triggered,
-			base_irq, iosapic_address);
+	register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
+		      polarity, edge_triggered, gsi_base, iosapic_address);
 
-	printk("IOSAPIC 0x%x(%s,%s) -> Vector 0x%x\n", global_vector,
-	       (polarity ? "high" : "low"), (edge_triggered ? "edge" : "level"), vector);
+	printk("GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
+	       gsi, (polarity ? "high" : "low"),
+	       (edge_triggered ? "edge" : "level"), dest, vector);
 
 	/* program the IOSAPIC routing table */
-	set_rte(vector, (ia64_get_lid() >> 16) & 0xffff);
+	set_rte(vector, dest);
 	return vector;
 }
 
@@ -471,15 +516,17 @@
  * Note that the irq_base and IOSAPIC address must be set in iosapic_init().
  */
 int
-iosapic_register_platform_irq (u32 int_type, u32 global_vector,
-			       u32 iosapic_vector, u16 eid, u16 id, unsigned long polarity,
-			       unsigned long edge_triggered, u32 base_irq, char *iosapic_address)
+iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
+				int iosapic_vector, u16 eid, u16 id,
+				unsigned long polarity, unsigned long edge_triggered,
+				unsigned int gsi_base, char *iosapic_address)
 {
 	unsigned char delivery;
 	int vector;
+	unsigned int dest = ((id << 8) | eid) & 0xffff;
 
 	switch (int_type) {
-	case ACPI20_ENTRY_PIS_PMI:
+	      case ACPI_INTERRUPT_PMI:
 		vector = iosapic_vector;
 		/*
 		 * since PMI vector is alloc'd by FW(ACPI) not by kernel,
@@ -488,223 +535,320 @@
 		iosapic_reassign_vector(vector);
 		delivery = IOSAPIC_PMI;
 		break;
-	case ACPI20_ENTRY_PIS_CPEI:
+	      case ACPI_INTERRUPT_INIT:
+		vector = ia64_alloc_vector();
+		delivery = IOSAPIC_INIT;
+		break;
+	      case ACPI_INTERRUPT_CPEI:
 		vector = IA64_PCE_VECTOR;
 		delivery = IOSAPIC_LOWEST_PRIORITY;
 		break;
-	case ACPI20_ENTRY_PIS_INIT:
-		vector = ia64_alloc_irq();
-		delivery = IOSAPIC_INIT;
-		break;
-	default:
-		printk("iosapic_register_platform_irq(): invalid int type\n");
+	      default:
+		printk("%s: invalid interrupt type (%d)\n", __FUNCTION__,
+			int_type);
 		return -1;
 	}
 
-	register_irq(global_vector, vector, global_vector - base_irq, delivery, polarity,
-		     edge_triggered, base_irq, iosapic_address);
+	register_intr(gsi, vector, delivery, polarity,
+		      edge_triggered, gsi_base, iosapic_address);
 
-	printk("PLATFORM int 0x%x: IOSAPIC 0x%x(%s,%s) -> Vector 0x%x CPU %.02u:%.02u\n",
-	       int_type, global_vector, (polarity ? "high" : "low"),
-	       (edge_triggered ? "edge" : "level"), vector, eid, id);
+	printk("PLATFORM int 0x%x: GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
+	       int_type, gsi, (polarity ? "high" : "low"),
+	       (edge_triggered ? "edge" : "level"), dest, vector);
 
 	/* program the IOSAPIC routing table */
-	set_rte(vector, ((id << 8) | eid) & 0xffff);
+	set_rte(vector, dest);
 	return vector;
 }
 
 
 /*
- * ACPI calls this when it finds an entry for a legacy ISA interrupt.
- * Note that the irq_base and IOSAPIC address must be set in iosapic_init().
+ * ACPI calls this when it finds an entry for a legacy ISA IRQ override.
+ * Note that the gsi_base and IOSAPIC address must be set in iosapic_init().
  */
 void
-iosapic_register_legacy_irq (unsigned long irq,
-			     unsigned long pin, unsigned long polarity,
-			     unsigned long edge_triggered)
-{
-	int vector = isa_irq_to_vector(irq);
-
-	register_irq(irq, vector, (int)pin, IOSAPIC_LOWEST_PRIORITY, polarity, edge_triggered,
-		     0, NULL);		/* ignored for override */
-
-#ifdef DEBUG_IRQ_ROUTING
-	printk("ISA: IRQ %u -> IOSAPIC irq 0x%02x (%s, %s) -> vector %02x\n",
-	       (unsigned) irq, (unsigned) pin,
-	       polarity ? "high" : "low", edge_triggered ? "edge" : "level",
-	       vector);
-#endif
+iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
+			  unsigned long polarity, unsigned long edge_triggered)
+{
+	int index, vector;
+	unsigned int gsi_base;
+	char *addr;
+	unsigned int dest = (ia64_get_lid() >> 16) & 0xffff;
+
+	index = find_iosapic(gsi);
+
+	if (index < 0) {
+		printk("ISA: No corresponding IOSAPIC found : ISA IRQ %u -> GSI 0x%x\n", isa_irq, gsi);
+		return;
+	}
+
+	vector = isa_irq_to_vector(isa_irq);
+	addr = iosapic_lists[index].addr;
+	gsi_base = iosapic_lists[index].gsi_base;
+
+	register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, edge_triggered,
+		      gsi_base, addr);
+
+	DBG("ISA: IRQ %u -> GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
+	    isa_irq, global_vector,
+	    polarity ? "high" : "low", edge_triggered ? "edge" : "level",
+	    dest, vector);
 
 	/* program the IOSAPIC routing table */
-	set_rte(vector, (ia64_get_lid() >> 16) & 0xffff);
+	set_rte(vector, dest);
 }
 
-void __init
-iosapic_init (unsigned long phys_addr, unsigned int base_irq, int pcat_compat)
+/*
+ * Map PCI pin to the corresponding GSI.
+ * If no such mapping exists, return -1.
+ */
+static int
+pci_pin_to_gsi (int segment, int bus, int slot, int pci_pin, unsigned int *gsi)
 {
-	int i, irq, max_pin, vector, pin;
-	unsigned int ver;
+	struct pci_vector_struct *r;
+
+	for (r = pci_irq.route; r < pci_irq.route + pci_irq.num_routes; r++)
+		if (r->segment == segment && r->bus == bus &&
+		    (r->pci_id >> 16) == slot && r->pin == pci_pin) {
+			*gsi = r->irq;
+			return 0;
+		}
+
+	return -1;
+}
+
+/*
+ * Map PCI pin to the corresponding IA-64 interrupt vector.  If no such mapping exists,
+ * try to allocate a new vector.  If it fails, return -1.
+ */
+static int
+pci_pin_to_vector (int segment, int bus, int slot, int pci_pin)
+{
+	int index, vector;
+	int gsi_base, pcat_compat;
+	char *addr;
+	unsigned int gsi;
+
+	if (pci_pin_to_gsi(segment, bus, slot, pci_pin, &gsi) < 0) {
+		printk("PCI: no interrupt route for %02x:%02x:%02x pin %c\n",
+			segment, bus, slot, 'A' + pci_pin);
+		return -1;
+	}
+
+	vector = gsi_to_vector(gsi);
+
+	if (vector < 0) {
+		/* we should allocate a vector for this interrupt line */
+
+		index = find_iosapic(gsi);
+
+		if (index < 0) {
+			printk("PCI: GSI 0x%x has no IOSAPIC mapping\n", gsi);
+			return -1;
+		}
+
+		addr = iosapic_lists[index].addr;
+		gsi_base = iosapic_lists[index].gsi_base;
+		pcat_compat = iosapic_lists[index].pcat_compat;
+
+		if (pcat_compat && (gsi < 16))
+			vector = isa_irq_to_vector(gsi);
+		else {
+			/* new GSI; allocate a vector for it */
+			vector = ia64_alloc_vector();
+		}
+
+		register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
+			      0, 0, gsi_base, addr);
+
+		DBG("PCI: (%02x:%02x:%02x:%02x INT%c) -> GSI 0x%x -> vector %d\n",
+		    segment, bus, slot, 'A' + pci_pin, gsi, vector);
+	}
+
+	return vector;
+}
+
+void __devinit
+iosapic_init (unsigned long phys_addr, unsigned int gsi_base, int pcat_compat)
+{
+	int num_rte, vector;
+	unsigned int isa_irq, ver;
 	char *addr;
 	static int first_time = 1;
 
 	if (first_time) {
 		first_time = 0;
-
 		for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
-			iosapic_irq[vector].pin = -1;	/* mark as unused */
+			iosapic_intr_info[vector].rte_index = -1;	/* mark as unused */
+	}
 
+	if (pcat_compat) {
 		/*
-		 * Fetch the PCI interrupt routing table:
+		 * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
+		 * enabled.
 		 */
-		acpi_cf_get_pci_vectors(&pci_irq.route, &pci_irq.num_routes);
+		printk("%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__);
+		outb(0xff, 0xA1);
+		outb(0xff, 0x21);
 	}
 
 	addr = ioremap(phys_addr, 0);
 	ver = iosapic_version(addr);
-	max_pin = (ver >> 16) & 0xff;
 
-	printk("IOSAPIC: version %x.%x, address 0x%lx, IRQs 0x%02x-0x%02x\n",
-	       (ver & 0xf0) >> 4, (ver & 0x0f), phys_addr, base_irq, base_irq + max_pin);
+	/*
+	 * The MAX_REDIR register holds the highest input pin
+	 * number (starting from 0).
+	 * We add 1 so that we can use it for number of pins (= RTEs)
+	 */
+	num_rte = ((ver >> 16) & 0xff) + 1;
+
+	iosapic_lists[num_iosapic].addr = addr;
+	iosapic_lists[num_iosapic].pcat_compat = pcat_compat;
+	iosapic_lists[num_iosapic].gsi_base = gsi_base;
+	iosapic_lists[num_iosapic].num_rte = num_rte;
+	num_iosapic++;
+
+	printk("IOSAPIC: version %x.%x, address 0x%lx, GSIs 0x%x-0x%x\n",
+	       (ver & 0xf0) >> 4, (ver & 0x0f), phys_addr, gsi_base, gsi_base + num_rte - 1);
+
+	if ((gsi_base == 0) && pcat_compat) {
+		unsigned int dest = (ia64_get_lid() >> 16) & 0xffff;
 
-	if ((base_irq == 0) && pcat_compat)
 		/*
 		 * Map the legacy ISA devices into the IOSAPIC data.  Some of these may
 		 * get reprogrammed later on with data from the ACPI Interrupt Source
 		 * Override table.
 		 */
-		for (irq = 0; irq < 16; ++irq) {
-			vector = isa_irq_to_vector(irq);
-			if ((pin = iosapic_irq[vector].pin) == -1)
-				pin = irq;
+		for (isa_irq = 0; isa_irq < 16; ++isa_irq) {
+			vector = isa_irq_to_vector(isa_irq);
 
-			register_irq(irq, vector, pin,
+			register_intr(isa_irq, vector, IOSAPIC_LOWEST_PRIORITY,
 				     /* IOSAPIC_POL_HIGH, IOSAPIC_EDGE */
-				     IOSAPIC_LOWEST_PRIORITY, 1, 1, base_irq, addr);
+				     1, 1, gsi_base, addr);
 
-#ifdef DEBUG_IRQ_ROUTING
-			printk("ISA: IRQ %u -> IOSAPIC irq 0x%02x (high, edge) -> vector 0x%02x\n",
-			       irq, iosapic_irq[vector].base_irq + iosapic_irq[vector].pin,
-			       vector);
-#endif
+			DBG("ISA: IRQ %u -> GSI 0x%x (high,edge) -> CPU 0x%04x vector %d\n",
+			    isa_irq, isa_irq, dest, vector);
 
 			/* program the IOSAPIC routing table: */
-			set_rte(vector, (ia64_get_lid() >> 16) & 0xffff);
+			set_rte(vector, dest);
 		}
+	}
+}
 
-	for (i = 0; i < pci_irq.num_routes; i++) {
-		irq = pci_irq.route[i].irq;
 
-		if ((irq < (int)base_irq) || (irq > (int)(base_irq + max_pin)))
-			/* the interrupt route is for another controller... */
-			continue;
+/*
+ * Set allocated interrupt vector to dev->irq and
+ * program IOSAPIC to deliver interrupts
+ */
+void
+iosapic_fixup_pci_interrupt (struct pci_dev *dev)
+{
+	int segment;
+	unsigned char pci_pin;
+	int vector;
+	unsigned int dest;
+	struct hw_interrupt_type *irq_type;
+	irq_desc_t *idesc;
 
-		if (pcat_compat && (irq < 16))
-			vector = isa_irq_to_vector(irq);
-		else {
-			vector = iosapic_irq_to_vector(irq);
-			if (vector < 0)
-				/* new iosapic irq: allocate a vector for it */
-				vector = ia64_alloc_irq();
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pci_pin);
+	if (pci_pin) {
+		pci_pin--; /* interrupt pins are numberd starting from 1 */
+
+		segment = PCI_SEGMENT(dev);
+		vector = pci_pin_to_vector(segment, dev->bus->number, PCI_SLOT(dev->devfn), pci_pin);
+
+		if (vector < 0 && dev->bus->parent) {
+			/* go back to the bridge */
+			struct pci_dev *bridge = dev->bus->self;
+
+			if (bridge) {
+				/* allow for multiple bridges on an adapter */
+				do {
+					/* do the bridge swizzle... */
+					pci_pin = (pci_pin + PCI_SLOT(dev->devfn)) % 4;
+					vector = pci_pin_to_vector(segment,
+								   bridge->bus->number,
+								   PCI_SLOT(bridge->devfn),
+								   pci_pin);
+				} while (vector < 0 && (bridge = bridge->bus->self));
+			}
+			if (vector >= 0)
+				printk(KERN_WARNING
+				       "PCI: using PPB (%s INT%c) to get vector %d\n",
+				       dev->slot_name, 'A' + pci_pin,
+				       vector);
+			else
+				printk(KERN_WARNING
+				       "PCI: Couldn't map irq for (%s INT%c)\n",
+				       dev->slot_name, 'A' + pci_pin);
 		}
 
-		register_irq(irq, vector, irq - base_irq,
-			     /* IOSAPIC_POL_LOW, IOSAPIC_LEVEL */
-			     IOSAPIC_LOWEST_PRIORITY, 0, 0, base_irq, addr);
-
-# ifdef DEBUG_IRQ_ROUTING
-		printk("PCI: (B%d,I%d,P%d) -> IOSAPIC irq 0x%02x -> vector 0x%02x\n",
-		       pci_irq.route[i].bus, pci_irq.route[i].pci_id>>16, pci_irq.route[i].pin,
-		       iosapic_irq[vector].base_irq + iosapic_irq[vector].pin, vector);
-# endif
+		if (vector >= 0) {
+			dev->irq = vector;
 
-			/* program the IOSAPIC routing table: */
-			set_rte(vector, (ia64_get_lid() >> 16) & 0xffff);
+			irq_type = &irq_type_iosapic_level;
+			idesc = irq_desc(vector);
+			if (idesc->handler != irq_type) {
+				if (idesc->handler != &no_irq_type)
+					printk("%s: changing vector %d from %s to %s\n",
+					       __FUNCTION__, vector,
+					       idesc->handler->typename,
+					       irq_type->typename);
+				idesc->handler = irq_type;
+			}
+#ifdef CONFIG_SMP
+			/*
+			 * For platforms that do not support interrupt redirect
+			 * via the XTP interface, we can round-robin the PCI
+			 * device interrupts to the processors
+			 */
+			if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) {
+				static int cpu_index = 0;
+
+				dest = cpu_physical_id(cpu_index) & 0xffff;
+
+				cpu_index++;
+				if (cpu_index >= smp_num_cpus)
+					cpu_index = 0;
+			} else {
+				/*
+				 * Direct the interrupt vector to the current cpu,
+				 * platform redirection will distribute them.
+				 */
+				dest = (ia64_get_lid() >> 16) & 0xffff;
+			}
+#else
+			/* direct the interrupt vector to the running cpu id */
+			dest = (ia64_get_lid() >> 16) & 0xffff;
+#endif
+
+			printk("PCI->APIC IRQ transform: (%s INT%c) -> CPU 0x%04x vector %d\n",
+			       dev->slot_name, 'A' + pci_pin, dest, vector);
+			set_rte(vector, dest);
+		}
 	}
 }
 
+
 void
 iosapic_pci_fixup (int phase)
 {
 	struct	pci_dev	*dev;
-	unsigned char pin;
-	int vector;
-	struct hw_interrupt_type *irq_type;
-	irq_desc_t *idesc;
+
+	if (phase == 0) {
+		if (0 != acpi_get_prt(&pci_irq.route, &pci_irq.num_routes)) {
+			printk("%s: acpi_get_prt failed\n", __FUNCTION__);
+		}
+		return;
+	}
 
 	if (phase != 1)
 		return;
 
 	pci_for_each_dev(dev) {
-		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-		if (pin) {
-			pin--;          /* interrupt pins are numbered starting from 1 */
-			vector = pci_pin_to_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
-			if (vector < 0 && dev->bus->parent) {
-				/* go back to the bridge */
-				struct pci_dev *bridge = dev->bus->self;
-
-				if (bridge) {
-					/* allow for multiple bridges on an adapter */
-					do {
-						/* do the bridge swizzle... */
-						pin = (pin + PCI_SLOT(dev->devfn)) % 4;
-						vector = pci_pin_to_vector(bridge->bus->number,
-									   PCI_SLOT(bridge->devfn),
-									   pin);
-					} while (vector < 0 && (bridge = bridge->bus->self));
-				}
-				if (vector >= 0)
-					printk(KERN_WARNING
-					       "PCI: using PPB(B%d,I%d,P%d) to get vector %02x\n",
-					       dev->bus->number, PCI_SLOT(dev->devfn),
-					       pin, vector);
-				else
-					printk(KERN_WARNING
-					       "PCI: Couldn't map irq for (B%d,I%d,P%d)\n",
-					       dev->bus->number, PCI_SLOT(dev->devfn), pin);
-			}
-			if (vector >= 0) {
-				printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> 0x%02x\n",
-				       dev->bus->number, PCI_SLOT(dev->devfn), pin, vector);
-				dev->irq = vector;
-
-				irq_type = &irq_type_iosapic_level;
-				idesc = irq_desc(vector);
-				if (idesc->handler != irq_type){
-					if (idesc->handler != &no_irq_type)
-						printk("iosapic_pci_fixup: changing vector 0x%02x "
-						       "from %s to %s\n", vector,
-						       idesc->handler->typename,
-						       irq_type->typename);
-					idesc->handler = irq_type;
-				}
-#ifdef CONFIG_SMP
-				/*
-				 * For platforms that do not support interrupt redirect
-				 * via the XTP interface, we can round-robin the PCI
-				 * device interrupts to the processors
-				 */
-				if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) {
-					static int cpu_index = 0;
+		/* fixup dev->irq and program IOSAPIC */
+		iosapic_fixup_pci_interrupt(dev);
 
-					set_rte(vector, cpu_physical_id(cpu_index) & 0xffff);
-
-					cpu_index++;
-					if (cpu_index >= smp_num_cpus)
-						cpu_index = 0;
-				} else {
-					/*
-					 * Direct the interrupt vector to the current cpu,
-					 * platform redirection will distribute them.
-					 */
-					set_rte(vector, (ia64_get_lid() >> 16) & 0xffff);
-				}
-#else
-				/* direct the interrupt vector to the running cpu id */
-				set_rte(vector, (ia64_get_lid() >> 16) & 0xffff);
-#endif
-			}
-		}
 		/*
 		 * Nothing to fixup
 		 * Fix out-of-range IRQ numbers
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/irq.c linux-2.4.20/arch/ia64/kernel/irq.c
--- linux-2.4.19/arch/ia64/kernel/irq.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/irq.c	2002-10-29 11:18:36.000000000 +0000
@@ -67,6 +67,27 @@
 irq_desc_t _irq_desc[NR_IRQS] __cacheline_aligned =
 	{ [0 ... NR_IRQS-1] = { IRQ_DISABLED, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}};
 
+#ifdef CONFIG_IA64_GENERIC
+struct irq_desc *
+__ia64_irq_desc (unsigned int irq)
+{
+	return _irq_desc + irq;
+}
+
+ia64_vector
+__ia64_irq_to_vector (unsigned int irq)
+{
+	return (ia64_vector) irq;
+}
+
+unsigned int
+__ia64_local_vector_to_irq (ia64_vector vec)
+{
+	return (unsigned int) vec;
+}
+
+#endif
+
 static void register_irq_proc (unsigned int irq);
 
 /*
@@ -1144,7 +1165,7 @@
 	if (!(new_value & cpu_online_map))
 		return -EINVAL;
 
-	irq_desc(irq)->handler->set_affinity(irq | (redir?(1<<31):0), new_value);
+	irq_desc(irq)->handler->set_affinity(irq | (redir? IA64_IRQ_REDIRECTED :0), new_value);
 
 	return full_count;
 }
@@ -1180,7 +1201,7 @@
 {
 	char name [MAX_NAMELEN];
 
-	if (!root_irq_dir || (irq_desc(irq)->handler == &no_irq_type))
+	if (!root_irq_dir || (irq_desc(irq)->handler == &no_irq_type) || irq_dir[irq])
 		return;
 
 	memset(name, 0, MAX_NAMELEN);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/irq_ia64.c linux-2.4.20/arch/ia64/kernel/irq_ia64.c
--- linux-2.4.19/arch/ia64/kernel/irq_ia64.c	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/irq_ia64.c	2002-10-29 11:18:38.000000000 +0000
@@ -36,6 +36,10 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 
+#ifdef CONFIG_PERFMON
+# include <asm/perfmon.h>
+#endif
+
 #define IRQ_DEBUG	0
 
 /* default base addr of IPI table */
@@ -51,14 +55,14 @@
 };
 
 int
-ia64_alloc_irq (void)
+ia64_alloc_vector (void)
 {
-	static int next_irq = IA64_FIRST_DEVICE_VECTOR;
+	static int next_vector = IA64_FIRST_DEVICE_VECTOR;
 
-	if (next_irq > IA64_LAST_DEVICE_VECTOR)
+	if (next_vector > IA64_LAST_DEVICE_VECTOR)
 		/* XXX could look for sharable vectors instead of panic'ing... */
-		panic("ia64_alloc_irq: out of interrupt vectors!");
-	return next_irq++;
+		panic("%s: out of interrupt vectors!", __FUNCTION__);
+	return next_vector++;
 }
 
 extern unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs);
@@ -173,6 +177,9 @@
 #ifdef CONFIG_SMP
 	register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
 #endif
+#ifdef CONFIG_PERFMON
+	perfmon_init_percpu();
+#endif
 	platform_irq_init();
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/ivt.S linux-2.4.20/arch/ia64/kernel/ivt.S
--- linux-2.4.19/arch/ia64/kernel/ivt.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/ivt.S	2002-10-29 11:18:33.000000000 +0000
@@ -126,7 +126,7 @@
 	;;
 (p7)	dep r17=r17,r19,(PAGE_SHIFT-3),3	// put region number bits in place
 	srlz.d					// ensure "rsm psr.dt" has taken effect
-(p6)	movl r19=__pa(SWAPPER_PGD_ADDR)		// region 5 is rooted at swapper_pg_dir
+(p6)	movl r19=__pa(swapper_pg_dir)		// region 5 is rooted at swapper_pg_dir
 (p6)	shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT
 (p7)	shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3
 	;;
@@ -329,12 +329,15 @@
 (p8)	br.cond.dptk dtlb_fault
 #endif
 	extr.u r23=r21,IA64_PSR_CPL0_BIT,2	// extract psr.cpl
+	and r22=IA64_ISR_CODE_MASK,r20		// get the isr.code field
 	tbit.nz p6,p7=r20,IA64_ISR_SP_BIT	// is speculation bit on?
-	and r19=r19,r16		// clear ed, reserved bits, and PTE control bits
-	shr.u r18=r16,57	// move address bit 61 to bit 4
+	shr.u r18=r16,57			// move address bit 61 to bit 4
+	and r19=r19,r16				// clear ed, reserved bits, and PTE control bits
+	tbit.nz p9,p0=r20,IA64_ISR_NA_BIT	// is non-access bit on?
 	;;
 	andcm r18=0x10,r18	// bit 4=~address-bit(61)
 	cmp.ne p8,p0=r0,r23
+(p9)	cmp.eq.or.andcm p6,p7=IA64_ISR_CODE_LFETCH,r22	// check isr.code field
 (p8)	br.cond.spnt page_fault
 
 	dep r21=-1,r21,IA64_PSR_ED_BIT,1
@@ -412,7 +415,7 @@
 	;;
 (p7)	dep r17=r17,r19,(PAGE_SHIFT-3),3	// put region number bits in place
 	srlz.d
-(p6)	movl r19=__pa(SWAPPER_PGD_ADDR)		// region 5 is rooted at swapper_pg_dir
+(p6)	movl r19=__pa(swapper_pg_dir)		// region 5 is rooted at swapper_pg_dir
 (p6)	shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT
 (p7)	shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3
 	;;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/mca.c linux-2.4.20/arch/ia64/kernel/mca.c
--- linux-2.4.19/arch/ia64/kernel/mca.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/mca.c	2002-10-29 11:18:40.000000000 +0000
@@ -3,6 +3,9 @@
  * Purpose:	Generic MCA handling layer
  *
  * Updated for latest kernel
+ * Copyright (C) 2002 Dell Computer Corporation
+ * Copyright (C) Matt Domsch (Matt_Domsch@dell.com)
+ *
  * Copyright (C) 2002 Intel
  * Copyright (C) Jenna Hall (jenna.s.hall@intel.com)
  *
@@ -15,6 +18,8 @@
  * Copyright (C) 1999 Silicon Graphics, Inc.
  * Copyright (C) Vijay Chander(vijay@engr.sgi.com)
  *
+ * 02/03/25 M. Domsch	GUID cleanups
+ *
  * 02/01/04 J. Hall	Aligned MCA stack to 16 bytes, added platform vs. CPU
  *			error flag, set SAL default return values, changed
  *			error record structure to linked list, added init call
@@ -36,6 +41,7 @@
 #include <linux/irq.h>
 #include <linux/smp_lock.h>
 #include <linux/bootmem.h>
+#include <linux/acpi.h>
 
 #include <asm/machvec.h>
 #include <asm/page.h>
@@ -46,7 +52,6 @@
 
 #include <asm/irq.h>
 #include <asm/hw_irq.h>
-#include <asm/acpi-ext.h>
 
 #undef MCA_PRT_XTRA_DATA
 
@@ -348,17 +353,15 @@
 verify_guid (efi_guid_t *test, efi_guid_t *target)
 {
 	int     rc;
+#ifdef IA64_MCA_DEBUG_INFO
+	char out[40];
+#endif
 
-	if ((rc = memcmp((void *)test, (void *)target, sizeof(efi_guid_t)))) {
-		IA64_MCA_DEBUG("ia64_mca_print: invalid guid = "
-			       "{ %08x, %04x, %04x, { %#02x, %#02x, %#02x, %#02x, "
-			       "%#02x, %#02x, %#02x, %#02x, } } \n ",
-			       test->data1, test->data2, test->data3, test->data4[0],
-			       test->data4[1], test->data4[2], test->data4[3],
-			       test->data4[4], test->data4[5], test->data4[6],
-			       test->data4[7]);
+	if ((rc = efi_guidcmp(*test, *target))) {
+		IA64_MCA_DEBUG(KERN_DEBUG
+			       "verify_guid: invalid GUID = %s\n",
+			       efi_guid_unparse(test, out));
 	}
-
 	return rc;
 }
 
@@ -496,7 +499,7 @@
 	{
 		irq_desc_t *desc;
 		unsigned int irq;
-		int cpev = acpi_request_vector(ACPI20_ENTRY_PIS_CPEI);
+		int cpev = acpi_request_vector(ACPI_INTERRUPT_CPEI);
 
 		if (cpev >= 0) {
 			for (irq = 0; irq < NR_IRQS; ++irq)
@@ -856,11 +859,8 @@
 void
 ia64_log_prt_guid (efi_guid_t *p_guid, prfunc_t prfunc)
 {
-	printk("GUID = { %08x, %04x, %04x, { %#02x, %#02x, %#02x, %#02x, "
-	       "%#02x, %#02x, %#02x, %#02x, } } \n ", p_guid->data1,
-	       p_guid->data2, p_guid->data3, p_guid->data4[0], p_guid->data4[1],
-	       p_guid->data4[2], p_guid->data4[3], p_guid->data4[4],
-	       p_guid->data4[5], p_guid->data4[6], p_guid->data4[7]);
+	char out[40];
+	printk(KERN_DEBUG "GUID = %s\n", efi_guid_unparse(p_guid, out));
 }
 
 static void
@@ -1754,7 +1754,7 @@
 		ia64_log_prt_section_header(slsh, prfunc);
 #endif  // MCA_PRT_XTRA_DATA for test only @FVL
 
-		if (verify_guid((void *)&slsh->guid, (void *)&(SAL_PROC_DEV_ERR_SECT_GUID))) {
+		if (verify_guid(&slsh->guid, &(SAL_PROC_DEV_ERR_SECT_GUID))) {
 			IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n");
 			continue;
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/mca_asm.S linux-2.4.20/arch/ia64/kernel/mca_asm.S
--- linux-2.4.19/arch/ia64/kernel/mca_asm.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/mca_asm.S	2002-10-29 11:18:36.000000000 +0000
@@ -684,9 +684,9 @@
 	movl	r3=SAL_GET_STATE_INFO;;
 	DATA_VA_TO_PA(r7);;		// convert to physical address
 	ld8	r8=[r7],8;;		// get pdesc function pointer
-	DATA_VA_TO_PA(r8)		// convert to physical address
+	dep	r8=0,r8,61,3;;		// convert SAL VA to PA
 	ld8	r1=[r7];;		// set new (ia64_sal) gp
-	DATA_VA_TO_PA(r1)		// convert to physical address
+	dep	r1=0,r1,61,3;;		// convert SAL VA to PA
 	mov	b6=r8
 
 	alloc	r5=ar.pfs,8,0,8,0;;	// allocate stack frame for SAL call
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/minstate.h linux-2.4.20/arch/ia64/kernel/minstate.h
--- linux-2.4.19/arch/ia64/kernel/minstate.h	2001-07-31 17:30:08.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/minstate.h	2002-10-29 11:18:36.000000000 +0000
@@ -92,7 +92,6 @@
  *
  * Assumed state upon entry:
  *	psr.ic: off
- *	psr.dt: off
  *	r31:	contains saved predicates (pr)
  *
  * Upon exit, the state is as follows:
@@ -186,7 +185,6 @@
  *
  * Assumed state upon entry:
  *	psr.ic: on
- *	psr.dt: on
  *	r2:	points to &pt_regs.r16
  *	r3:	points to &pt_regs.r17
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/pal.S linux-2.4.20/arch/ia64/kernel/pal.S
--- linux-2.4.19/arch/ia64/kernel/pal.S	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/pal.S	2002-10-29 11:18:50.000000000 +0000
@@ -114,7 +114,7 @@
 	;;
 	rsm psr.i
 	mov b7 = loc2
-	;; 
+	;;
 	br.call.sptk.many rp=b7		// now make the call
 .ret0:	mov psr.l  = loc3
 	mov ar.pfs = loc1
@@ -161,7 +161,7 @@
 	;;
 	mov loc3 = psr			// save psr
 	adds r8  = 1f-1b,r8		// calculate return address for call
-	;; 
+	;;
 	mov loc4=ar.rsc			// save RSE configuration
 	dep.z loc2=loc2,0,61		// convert pal entry point to physical
 	dep.z r8=r8,0,61		// convert rp to physical
@@ -216,7 +216,7 @@
 	mov out3 = in3		// copy arg3
 	;;
 	mov loc3 = psr		// save psr
-	;; 
+	;;
 	mov loc4=ar.rsc			// save RSE configuration
 	dep.z loc2=loc2,0,61		// convert pal entry point to physical
 	;;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/palinfo.c linux-2.4.20/arch/ia64/kernel/palinfo.c
--- linux-2.4.19/arch/ia64/kernel/palinfo.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/palinfo.c	2002-10-29 11:18:31.000000000 +0000
@@ -21,10 +21,10 @@
 #include <linux/proc_fs.h>
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/efi.h>
 
 #include <asm/pal.h>
 #include <asm/sal.h>
-#include <asm/efi.h>
 #include <asm/page.h>
 #include <asm/processor.h>
 #ifdef CONFIG_SMP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/pci.c linux-2.4.20/arch/ia64/kernel/pci.c
--- linux-2.4.19/arch/ia64/kernel/pci.c	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/pci.c	2002-10-29 11:18:40.000000000 +0000
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/spinlock.h>
+#include <linux/acpi.h>
 
 #include <asm/machvec.h>
 #include <asm/page.h>
@@ -42,104 +43,256 @@
 extern void ia64_mca_check_errors( void );
 #endif
 
+struct pci_fixup pcibios_fixups[1];
+
+struct pci_ops *pci_root_ops;
+
+int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value);
+int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value);
+
+
 /*
- * This interrupt-safe spinlock protects all accesses to PCI
- * configuration space.
+ * Low-level SAL-based PCI configuration access functions. Note that SAL
+ * calls are already serialized (via sal_lock), so we don't need another
+ * synchronization mechanism here.
  */
-static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED;
 
-struct pci_fixup pcibios_fixups[] = {
-	{ 0 }
-};
+#define PCI_SAL_ADDRESS(seg, bus, dev, fn, reg) \
+	((u64)(seg << 24) | (u64)(bus << 16) | \
+	 (u64)(dev << 11) | (u64)(fn << 8) | (u64)(reg))
 
-/* Macro to build a PCI configuration address to be passed as a parameter to SAL. */
+static int
+pci_sal_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
+{
+	int result = 0;
+	u64 data = 0;
+
+	if (!value || (seg > 255) || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+		return -EINVAL;
 
-#define PCI_CONFIG_ADDRESS(dev, where) \
-	(((u64) dev->bus->number << 16) | ((u64) (dev->devfn & 0xff) << 8) | (where & 0xff))
+	result = ia64_sal_pci_config_read(PCI_SAL_ADDRESS(seg, bus, dev, fn, reg), len, &data);
+
+	*value = (u32) data;
+
+	return result;
+}
 
 static int
-pci_conf_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+pci_sal_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
 {
-	s64 status;
-	u64 lval;
+	if ((seg > 255) || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+		return -EINVAL;
 
-	status = ia64_sal_pci_config_read(PCI_CONFIG_ADDRESS(dev, where), 1, &lval);
-	*value = lval;
-	return status;
+	return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(seg, bus, dev, fn, reg), len, value);
 }
 
+
 static int
-pci_conf_read_config_word(struct pci_dev *dev, int where, u16 *value)
+pci_sal_read_config_byte (struct pci_dev *dev, int where, u8 *value)
 {
-	s64 status;
-	u64 lval;
+	int result = 0;
+	u32 data = 0;
+
+	if (!value)
+		return -EINVAL;
 
-	status = ia64_sal_pci_config_read(PCI_CONFIG_ADDRESS(dev, where), 2, &lval);
-	*value = lval;
-	return status;
+	result = pci_sal_read(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn),
+			      PCI_FUNC(dev->devfn), where, 1, &data);
+
+	*value = (u8) data;
+
+	return result;
 }
 
 static int
-pci_conf_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+pci_sal_read_config_word (struct pci_dev *dev, int where, u16 *value)
 {
-	s64 status;
-	u64 lval;
+	int result = 0;
+	u32 data = 0;
+
+	if (!value)
+		return -EINVAL;
+
+	result = pci_sal_read(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn),
+			      PCI_FUNC(dev->devfn), where, 2, &data);
 
-	status = ia64_sal_pci_config_read(PCI_CONFIG_ADDRESS(dev, where), 4, &lval);
-	*value = lval;
-	return status;
+	*value = (u16) data;
+
+	return result;
+}
+
+static int
+pci_sal_read_config_dword (struct pci_dev *dev, int where, u32 *value)
+{
+	if (!value)
+		return -EINVAL;
+
+	return pci_sal_read(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn),
+			    PCI_FUNC(dev->devfn), where, 4, value);
 }
 
 static int
-pci_conf_write_config_byte (struct pci_dev *dev, int where, u8 value)
+pci_sal_write_config_byte (struct pci_dev *dev, int where, u8 value)
 {
-	return ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS(dev, where), 1, value);
+	return pci_sal_write(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn),
+			     PCI_FUNC(dev->devfn), where, 1, value);
 }
 
 static int
-pci_conf_write_config_word (struct pci_dev *dev, int where, u16 value)
+pci_sal_write_config_word (struct pci_dev *dev, int where, u16 value)
 {
-	return ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS(dev, where), 2, value);
+	return pci_sal_write(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn),
+			     PCI_FUNC(dev->devfn), where, 2, value);
 }
 
 static int
-pci_conf_write_config_dword (struct pci_dev *dev, int where, u32 value)
+pci_sal_write_config_dword (struct pci_dev *dev, int where, u32 value)
 {
-	return ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS(dev, where), 4, value);
+	return pci_sal_write(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn),
+			     PCI_FUNC(dev->devfn), where, 4, value);
 }
 
-struct pci_ops pci_conf = {
-      pci_conf_read_config_byte,
-      pci_conf_read_config_word,
-      pci_conf_read_config_dword,
-      pci_conf_write_config_byte,
-      pci_conf_write_config_word,
-      pci_conf_write_config_dword
+struct pci_ops pci_sal_ops = {
+	pci_sal_read_config_byte,
+	pci_sal_read_config_word,
+	pci_sal_read_config_dword,
+	pci_sal_write_config_byte,
+	pci_sal_write_config_word,
+	pci_sal_write_config_dword
 };
 
+
 /*
  * Initialization. Uses the SAL interface
  */
+
+static struct pci_controller *
+alloc_pci_controller(int seg)
+{
+	struct pci_controller *controller;
+
+	controller = kmalloc(sizeof(*controller), GFP_KERNEL);
+	if (!controller)
+		return NULL;
+
+	memset(controller, 0, sizeof(*controller));
+	controller->segment = seg;
+	return controller;
+}
+
+static struct pci_bus *
+scan_root_bus(int bus, struct pci_ops *ops, void *sysdata)
+{
+	struct pci_bus *b;
+
+	/*
+	 * We know this is a new root bus we haven't seen before, so
+	 * scan it, even if we've seen the same bus number in a different
+	 * segment.
+	 */
+	b = kmalloc(sizeof(*b), GFP_KERNEL);
+	if (!b)
+		return NULL;
+
+	memset(b, 0, sizeof(*b));
+	INIT_LIST_HEAD(&b->children);
+	INIT_LIST_HEAD(&b->devices);
+
+	list_add_tail(&b->node, &pci_root_buses);
+
+	b->number = b->secondary = bus;
+	b->resource[0] = &ioport_resource;
+	b->resource[1] = &iomem_resource;
+
+	b->sysdata = sysdata;
+	b->ops = ops;
+	b->subordinate = pci_do_scan_bus(b);
+
+	return b;
+}
+
+struct pci_bus *
+pcibios_scan_root(void *handle, int seg, int bus)
+{
+	struct pci_controller *controller;
+	u64 base, size, offset;
+
+	printk("PCI: Probing PCI hardware on bus (%02x:%02x)\n", seg, bus);
+
+	controller = alloc_pci_controller(seg);
+	if (!controller)
+		return NULL;
+
+	controller->acpi_handle = handle;
+
+	acpi_get_addr_space(handle, ACPI_MEMORY_RANGE, &base, &size, &offset);
+	controller->mem_offset = offset;
+
+	return scan_root_bus(bus, pci_root_ops, controller);
+}
+
+void __init
+pcibios_config_init (void)
+{
+	if (pci_root_ops)
+		return;
+
+	printk("PCI: Using SAL to access configuration space\n");
+
+	pci_root_ops = &pci_sal_ops;
+	pci_config_read = pci_sal_read;
+	pci_config_write = pci_sal_write;
+
+	return;
+}
+
 void __init
 pcibios_init (void)
 {
 #	define PCI_BUSES_TO_SCAN 255
-	int i;
+	int i = 0;
+	struct pci_controller *controller;
 
 #ifdef CONFIG_IA64_MCA
 	ia64_mca_check_errors();    /* For post-failure MCA error logging */
 #endif
 
-	platform_pci_fixup(0);	/* phase 0 initialization (before PCI bus has been scanned) */
+	pcibios_config_init();
+
+	platform_pci_fixup(0);	/* phase 0 fixups (before buses scanned) */
 
 	printk("PCI: Probing PCI hardware\n");
-	for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
-		pci_scan_bus(i, &pci_conf, NULL);
+	controller = alloc_pci_controller(0);
+	if (controller)
+		for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
+			pci_scan_bus(i, pci_root_ops, controller);
+
+	platform_pci_fixup(1);	/* phase 1 fixups (after buses scanned) */
 
-	platform_pci_fixup(1);	/* phase 1 initialization (after PCI bus has been scanned) */
 	return;
 }
 
+static void __init
+pcibios_fixup_resource(struct resource *res, u64 offset)
+{
+	res->start += offset;
+	res->end += offset;
+}
+
+void __init
+pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
+{
+	int i;
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		if (!dev->resource[i].start)
+			continue;
+		if (dev->resource[i].flags & IORESOURCE_MEM)
+			pcibios_fixup_resource(&dev->resource[i],
+				PCI_CONTROLLER(dev)->mem_offset);
+	}
+}
+
 /*
  *  Called after each bus is probed, but before its children
  *  are examined.
@@ -147,7 +300,10 @@
 void __init
 pcibios_fixup_bus (struct pci_bus *b)
 {
-	return;
+	struct list_head *ln;
+
+	for (ln = b->devices.next; ln != &b->devices; ln = ln->next)
+		pcibios_fixup_device_resources(pci_dev_b(ln), b);
 }
 
 void __init
@@ -186,12 +342,45 @@
 int
 pcibios_enable_device (struct pci_dev *dev)
 {
-	/* Not needed, since we enable all devices at startup.  */
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	if (!dev)
+		return -EINVAL;
+
+ 	platform_pci_enable_device(dev);
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for (idx=0; idx<6; idx++) {
+		r = &dev->resource[idx];
+		if (!r->start && r->end) {
+			printk(KERN_ERR
+			       "PCI: Device %s not available because of resource collisions\n",
+			       dev->slot_name);
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (dev->resource[PCI_ROM_RESOURCE].start)
+		cmd |= PCI_COMMAND_MEMORY;
+	if (cmd != old_cmd) {
+		printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+
+	printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", dev->irq, dev->slot_name);
+
 	return 0;
 }
 
 void
-pcibios_align_resource (void *data, struct resource *res, unsigned long size)
+pcibios_align_resource (void *data, struct resource *res,
+		        unsigned long size, unsigned long align)
 {
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/perfmon.c linux-2.4.20/arch/ia64/kernel/perfmon.c
--- linux-2.4.19/arch/ia64/kernel/perfmon.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/perfmon.c	2002-10-29 11:18:38.000000000 +0000
@@ -23,6 +23,7 @@
 #include <linux/vmalloc.h>
 #include <linux/wrapper.h>
 #include <linux/mm.h>
+#include <linux/sysctl.h>
 
 #include <asm/bitops.h>
 #include <asm/errno.h>
@@ -42,7 +43,7 @@
  * you must enable the following flag to activate the support for
  * accessing the registers via the perfmonctl() interface.
  */
-#ifdef CONFIG_ITANIUM
+#if defined(CONFIG_ITANIUM) || defined(CONFIG_MCKINLEY)
 #define PFM_PMU_USES_DBR	1
 #endif
 
@@ -68,26 +69,27 @@
 #define PMC_OVFL_NOTIFY(ctx, i)	((ctx)->ctx_soft_pmds[i].flags &  PFM_REGFL_OVFL_NOTIFY)
 #define PFM_FL_INHERIT_MASK	(PFM_FL_INHERIT_NONE|PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL)
 
+/* i assume unsigned */
 #define PMC_IS_IMPL(i)	  (i<pmu_conf.num_pmcs && pmu_conf.impl_regs[i>>6] & (1UL<< (i) %64))
 #define PMD_IS_IMPL(i)	  (i<pmu_conf.num_pmds &&  pmu_conf.impl_regs[4+(i>>6)] & (1UL<<(i) % 64))
 
-#define PMD_IS_COUNTING(i) (i >=0  && i < 256 && pmu_conf.counter_pmds[i>>6] & (1UL <<(i) % 64))
-#define PMC_IS_COUNTING(i) PMD_IS_COUNTING(i)
+/* XXX: these three assume that register i is implemented */
+#define PMD_IS_COUNTING(i) (pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING)
+#define PMC_IS_COUNTING(i) (pmu_conf.pmc_desc[i].type == PFM_REG_COUNTING)
+#define PMC_IS_MONITOR(c)  (pmu_conf.pmc_desc[i].type == PFM_REG_MONITOR)
 
+/* k assume unsigned */
 #define IBR_IS_IMPL(k)	  (k<pmu_conf.num_ibrs)
 #define DBR_IS_IMPL(k)	  (k<pmu_conf.num_dbrs)
 
-#define PMC_IS_BTB(a)	  (((pfm_monitor_t *)(a))->pmc_es == PMU_BTB_EVENT)
-
-#define LSHIFT(x)		(1UL<<(x))
-#define PMM(x)			LSHIFT(x)
-#define PMC_IS_MONITOR(c)	((pmu_conf.monitor_pmcs[0] & PMM((c))) != 0)
-
 #define CTX_IS_ENABLED(c) 	((c)->ctx_flags.state == PFM_CTX_ENABLED)
 #define CTX_OVFL_NOBLOCK(c)	((c)->ctx_fl_block == 0)
 #define CTX_INHERIT_MODE(c)	((c)->ctx_fl_inherit)
 #define CTX_HAS_SMPL(c)		((c)->ctx_psb != NULL)
-#define CTX_USED_PMD(ctx,n) 	(ctx)->ctx_used_pmds[(n)>>6] |= 1UL<< ((n) % 64)
+/* XXX: does not support more than 64 PMDs */
+#define CTX_USED_PMD(ctx, mask) (ctx)->ctx_used_pmds[0] |= (mask)
+#define CTX_IS_USED_PMD(ctx, c) (((ctx)->ctx_used_pmds[0] & (1UL << (c))) != 0UL)
+
 
 #define CTX_USED_IBR(ctx,n) 	(ctx)->ctx_used_ibrs[(n)>>6] |= 1UL<< ((n) % 64)
 #define CTX_USED_DBR(ctx,n) 	(ctx)->ctx_used_dbrs[(n)>>6] |= 1UL<< ((n) % 64)
@@ -104,17 +106,29 @@
 
 #define PFM_REG_RETFLAG_SET(flags, val)	do { flags &= ~PFM_REG_RETFL_MASK; flags |= (val); } while(0)
 
+#ifdef CONFIG_SMP
+#define cpu_is_online(i) (cpu_online_map & (1UL << i))
+#else
+#define cpu_is_online(i)        (i==0)
+#endif
+
 /*
  * debugging
  */
 #define DBprintk(a) \
 	do { \
-		if (pfm_debug_mode >0) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \
+		if (pfm_sysctl.debug >0) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \
+	} while (0)
+
+#define DBprintk_ovfl(a) \
+	do { \
+		if (pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \
 	} while (0)
 
 
+
 /* 
- * These are some helpful architected PMC and IBR/DBR register layouts
+ * Architected PMC structure
  */
 typedef struct {
 	unsigned long pmc_plm:4;	/* privilege level mask */
@@ -139,41 +153,40 @@
 typedef struct _pfm_smpl_buffer_desc {
 	spinlock_t		psb_lock;	/* protection lock */
 	unsigned long		psb_refcnt;	/* how many users for the buffer */
-	int			psb_flags;	/* bitvector of flags */
+	int			psb_flags;	/* bitvector of flags (not yet used) */
 
 	void			*psb_addr;	/* points to location of first entry */
 	unsigned long		psb_entries;	/* maximum number of entries */
 	unsigned long		psb_size;	/* aligned size of buffer */
 	unsigned long		psb_index;	/* next free entry slot XXX: must use the one in buffer */
 	unsigned long		psb_entry_size;	/* size of each entry including entry header */
+
 	perfmon_smpl_hdr_t	*psb_hdr;	/* points to sampling buffer header */
 
 	struct _pfm_smpl_buffer_desc *psb_next;	/* next psb, used for rvfreeing of psb_hdr */
 
 } pfm_smpl_buffer_desc_t;
 
+/*
+ * psb_flags
+ */
+#define PSB_HAS_VMA	0x1		/* a virtual mapping for the buffer exists */
+
 #define LOCK_PSB(p)	spin_lock(&(p)->psb_lock)
 #define UNLOCK_PSB(p)	spin_unlock(&(p)->psb_lock)
 
-#define PFM_PSB_VMA	0x1			/* a VMA is describing the buffer */
-
 /*
- * This structure is initialized at boot time and contains
- * a description of the PMU main characteristic as indicated
- * by PAL
+ * The possible type of a PMU register
  */
-typedef struct {
-	unsigned long pfm_is_disabled;	/* indicates if perfmon is working properly */
-	unsigned long perf_ovfl_val;	/* overflow value for generic counters   */
-	unsigned long max_counters;	/* upper limit on counter pair (PMC/PMD) */
-	unsigned long num_pmcs ;	/* highest PMC implemented (may have holes) */
-	unsigned long num_pmds;		/* highest PMD implemented (may have holes) */
-	unsigned long impl_regs[16];	/* buffer used to hold implememted PMC/PMD mask */
-	unsigned long num_ibrs;		/* number of instruction debug registers */
-	unsigned long num_dbrs;		/* number of data debug registers */
-	unsigned long monitor_pmcs[4];	/* which pmc are controlling monitors */
-	unsigned long counter_pmds[4];	/* which pmd are used as counters */
-} pmu_config_t;
+typedef enum { 
+	PFM_REG_NOTIMPL, /* not implemented */
+	PFM_REG_NONE, 	 /* end marker */
+	PFM_REG_MONITOR, /* a PMC with a pmc.pm field only */
+	PFM_REG_COUNTING,/* a PMC with a pmc.pm AND pmc.oi, a PMD used as a counter */
+	PFM_REG_CONTROL, /* PMU control register */
+	PFM_REG_CONFIG,  /* refine configuration */
+	PFM_REG_BUFFER	 /* PMD used as buffer */
+} pfm_pmu_reg_type_t;
 
 /*
  * 64-bit software counter structure
@@ -221,9 +234,11 @@
 
 	struct semaphore	ctx_restart_sem;   	/* use for blocking notification mode */
 
-	unsigned long		ctx_used_pmds[4];	/* bitmask of used PMD (speedup ctxsw) */
-	unsigned long		ctx_saved_pmcs[4];	/* bitmask of PMC to save on ctxsw */
-	unsigned long		ctx_reload_pmcs[4];	/* bitmask of PMC to reload on ctxsw (SMP) */
+	unsigned long		ctx_used_pmds[4];	/* bitmask of PMD used                 */
+	unsigned long		ctx_reload_pmds[4];	/* bitmask of PMD to reload on ctxsw   */
+
+	unsigned long		ctx_used_pmcs[4];	/* bitmask PMC used by context         */
+	unsigned long		ctx_reload_pmcs[4];	/* bitmask of PMC to reload on ctxsw   */
 
 	unsigned long		ctx_used_ibrs[4];	/* bitmask of used IBR (speedup ctxsw) */
 	unsigned long		ctx_used_dbrs[4];	/* bitmask of used DBR (speedup ctxsw) */
@@ -235,6 +250,7 @@
 	unsigned long		ctx_cpu;		/* cpu to which perfmon is applied (system wide) */
 
 	atomic_t		ctx_saving_in_progress;	/* flag indicating actual save in progress */
+	atomic_t		ctx_is_busy;		/* context accessed by overflow handler */
 	atomic_t		ctx_last_cpu;		/* CPU id of current or last CPU used */
 } pfm_context_t;
 
@@ -250,16 +266,54 @@
  * mostly used to synchronize between system wide and per-process
  */
 typedef struct {
-	spinlock_t		pfs_lock;		/* lock the structure */
+	spinlock_t		pfs_lock;		   /* lock the structure */
 
-	unsigned long		pfs_task_sessions;	/* number of per task sessions */
-	unsigned long		pfs_sys_sessions;	/* number of per system wide sessions */
-	unsigned long   	pfs_sys_use_dbregs;	  	/* incremented when a system wide session uses debug regs */
-	unsigned long   	pfs_ptrace_use_dbregs;	  /* incremented when a process uses debug regs */
-	struct task_struct	*pfs_sys_session[NR_CPUS];  /* point to task owning a system-wide session */
+	unsigned long		pfs_task_sessions;	   /* number of per task sessions */
+	unsigned long		pfs_sys_sessions;	   /* number of per system wide sessions */
+	unsigned long   	pfs_sys_use_dbregs;	   /* incremented when a system wide session uses debug regs */
+	unsigned long   	pfs_ptrace_use_dbregs;	   /* incremented when a process uses debug regs */
+	struct task_struct	*pfs_sys_session[NR_CPUS]; /* point to task owning a system-wide session */
 } pfm_session_t;
 
 /*
+ * information about a PMC or PMD.
+ * dep_pmd[]: a bitmask of dependent PMD registers 
+ * dep_pmc[]: a bitmask of dependent PMC registers
+ */
+typedef struct {
+	pfm_pmu_reg_type_t	type;
+	int			pm_pos;
+	int			(*read_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
+	int			(*write_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
+	unsigned long		dep_pmd[4];
+	unsigned long		dep_pmc[4];
+} pfm_reg_desc_t;
+/* assume cnum is a valid monitor */
+#define PMC_PM(cnum, val)	(((val) >> (pmu_conf.pmc_desc[cnum].pm_pos)) & 0x1)
+#define PMC_WR_FUNC(cnum)	(pmu_conf.pmc_desc[cnum].write_check)
+#define PMD_WR_FUNC(cnum)	(pmu_conf.pmd_desc[cnum].write_check)
+#define PMD_RD_FUNC(cnum)	(pmu_conf.pmd_desc[cnum].read_check)
+
+/*
+ * This structure is initialized at boot time and contains
+ * a description of the PMU main characteristic as indicated
+ * by PAL along with a list of inter-registers dependencies and configurations.
+ */
+typedef struct {
+	unsigned long pfm_is_disabled;	/* indicates if perfmon is working properly */
+	unsigned long perf_ovfl_val;	/* overflow value for generic counters   */
+	unsigned long max_counters;	/* upper limit on counter pair (PMC/PMD) */
+	unsigned long num_pmcs ;	/* highest PMC implemented (may have holes) */
+	unsigned long num_pmds;		/* highest PMD implemented (may have holes) */
+	unsigned long impl_regs[16];	/* buffer used to hold implememted PMC/PMD mask */
+	unsigned long num_ibrs;		/* number of instruction debug registers */
+	unsigned long num_dbrs;		/* number of data debug registers */
+	pfm_reg_desc_t *pmc_desc;	/* detailed PMC register descriptions */
+	pfm_reg_desc_t *pmd_desc;	/* detailed PMD register descriptions */
+} pmu_config_t;
+
+
+/*
  * structure used to pass argument to/from remote CPU 
  * using IPI to check and possibly save the PMU context on SMP systems.
  *
@@ -301,22 +355,50 @@
 #define PFM_CMD_NARG(cmd)	(pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_narg)
 #define PFM_CMD_ARG_SIZE(cmd)	(pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_argsize)
 
+typedef struct {
+	int	debug;		/* turn on/off debugging via syslog */
+	int	debug_ovfl;	/* turn on/off debug printk in overflow handler */
+	int	fastctxsw;	/* turn on/off fast (unsecure) ctxsw */
+} pfm_sysctl_t;
+
+typedef struct {
+	unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */
+	unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */
+	unsigned long pfm_recorded_samples_count;
+	unsigned long pfm_full_smpl_buffer_count; /* how many times the sampling buffer was full */
+} pfm_stats_t;
 
 /*
  * perfmon internal variables
  */
 static pmu_config_t	pmu_conf; 	/* PMU configuration */
-static int		pfm_debug_mode;	/* 0= nodebug, >0= debug output on */
 static pfm_session_t	pfm_sessions;	/* global sessions information */
 static struct proc_dir_entry *perfmon_dir; /* for debug only */
-static unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */
-static unsigned long pfm_ovfl_intr_count; /* keep track of spurious ovfl interrupts */
-static unsigned long pfm_recorded_samples_count;
+static pfm_stats_t	pfm_stats;
 
+/* sysctl() controls */
+static pfm_sysctl_t pfm_sysctl;
+
+static ctl_table pfm_ctl_table[]={
+	{1, "debug", &pfm_sysctl.debug, sizeof(int), 0666, NULL, &proc_dointvec, NULL,},
+	{2, "debug_ovfl", &pfm_sysctl.debug_ovfl, sizeof(int), 0666, NULL, &proc_dointvec, NULL,},
+	{3, "fastctxsw", &pfm_sysctl.fastctxsw, sizeof(int), 0600, NULL, &proc_dointvec, NULL,},
+	{ 0, },
+};
+static ctl_table pfm_sysctl_dir[] = {
+	{1, "perfmon", NULL, 0, 0755, pfm_ctl_table, },
+ 	{0,},
+};
+static ctl_table pfm_sysctl_root[] = {
+	{1, "kernel", NULL, 0, 0755, pfm_sysctl_dir, },
+ 	{0,},
+};
+static struct ctl_table_header *pfm_sysctl_header;
 
 static unsigned long reset_pmcs[IA64_NUM_PMC_REGS];	/* contains PAL reset values for PMCS */
 
 static void pfm_vm_close(struct vm_area_struct * area);
+
 static struct vm_operations_struct pfm_vm_ops={
 	close: pfm_vm_close
 };
@@ -339,6 +421,14 @@
 #endif
 static void pfm_lazy_save_regs (struct task_struct *ta);
 
+#if   defined(CONFIG_ITANIUM)
+#include "perfmon_itanium.h"
+#elif defined(CONFIG_MCKINLEY)
+#include "perfmon_mckinley.h"
+#else
+#include "perfmon_generic.h"
+#endif
+
 static inline unsigned long
 pfm_read_soft_counter(pfm_context_t *ctx, int i)
 {
@@ -353,7 +443,7 @@
 	 * writing to unimplemented part is ignore, so we do not need to
 	 * mask off top part
 	 */
-	ia64_set_pmd(i, val);
+	ia64_set_pmd(i, val & pmu_conf.perf_ovfl_val);
 }
 
 /*
@@ -424,7 +514,6 @@
 	return pa;
 }
 
-
 static void *
 pfm_rvmalloc(unsigned long size)
 {
@@ -500,7 +589,7 @@
 	 *
 	 * This function cannot remove the buffer from here, because exit_mmap() must first
 	 * complete. Given that there is no other vma related callback in the generic code,
-	 * we have created on own with the linked list of sampling buffer to free which
+	 * we have created our own with the linked list of sampling buffers to free. The list
 	 * is part of the thread structure. In release_thread() we check if the list is
 	 * empty. If not we call into perfmon to free the buffer and psb. That is the only
 	 * way to ensure a safe deallocation of the sampling buffer which works when
@@ -516,16 +605,15 @@
 		psb->psb_next = current->thread.pfm_smpl_buf_list;
 		current->thread.pfm_smpl_buf_list = psb;
 
-		DBprintk(("psb for [%d] smpl @%p size %ld inserted into list\n", 
-			current->pid, psb->psb_hdr, psb->psb_size));
+		DBprintk(("[%d] add smpl @%p size %lu to smpl_buf_list psb_flags=0x%x\n", 
+			current->pid, psb->psb_hdr, psb->psb_size, psb->psb_flags));
 	}
-	DBprintk(("psb vma flag cleared for [%d] smpl @%p size %ld inserted into list\n", 
-			current->pid, psb->psb_hdr, psb->psb_size));
-
+	DBprintk(("[%d] clearing psb_flags=0x%x smpl @%p size %lu\n", 
+			current->pid, psb->psb_flags, psb->psb_hdr, psb->psb_size));
 	/*
-	 * indicate to pfm_context_exit() that the vma has been removed. 
+	 * decrement the number vma for the buffer
 	 */
-	psb->psb_flags &= ~PFM_PSB_VMA;
+	psb->psb_flags &= ~PSB_HAS_VMA;
 
 	UNLOCK_PSB(psb);
 }
@@ -548,7 +636,7 @@
 		printk("perfmon: invalid context mm=%p\n", task->mm);
 		return -1;
 	}
-	psb = ctx->ctx_psb;	
+	psb = ctx->ctx_psb;
 
 	down_write(&task->mm->mmap_sem);
 
@@ -559,14 +647,9 @@
 		printk("perfmon: pid %d unable to unmap sampling buffer @0x%lx size=%ld\n", 
 				task->pid, ctx->ctx_smpl_vaddr, psb->psb_size);
 	}
-	DBprintk(("[%d] do_unmap(0x%lx, %ld)=%d\n", 
-		task->pid, ctx->ctx_smpl_vaddr, psb->psb_size, r));
 
-	/* 
-	 * make sure we suppress all traces of this buffer
-	 * (important for pfm_inherit)
-	 */
-	ctx->ctx_smpl_vaddr = 0;
+	DBprintk(("[%d] do_unmap(0x%lx, %ld)=%d refcnt=%lu psb_flags=0x%x\n", 
+		task->pid, ctx->ctx_smpl_vaddr, psb->psb_size, r, psb->psb_refcnt, psb->psb_flags));
 
 	return 0;
 }
@@ -599,7 +682,7 @@
 	while (size > 0) {
 		page = pfm_kvirt_to_pa(buf);
 
-		if (remap_page_range(addr, page, PAGE_SIZE, PAGE_SHARED)) return -ENOMEM;
+		if (remap_page_range(addr, page, PAGE_SIZE, PAGE_READONLY)) return -ENOMEM;
 		
 		addr  += PAGE_SIZE;
 		buf   += PAGE_SIZE;
@@ -638,17 +721,25 @@
 	void *smpl_buf;
 	pfm_smpl_buffer_desc_t *psb;
 
-	regcount = pfm_smpl_entry_size(which_pmds, 1);
 
 	/* note that regcount might be 0, in this case only the header for each
 	 * entry will be recorded.
 	 */
+	regcount = pfm_smpl_entry_size(which_pmds, 1);
+
+	if ((sizeof(perfmon_smpl_hdr_t)+ entries*sizeof(perfmon_smpl_entry_t)) <= entries) {
+		DBprintk(("requested entries %lu is too big\n", entries));
+		return -EINVAL;
+	}
 
 	/*
 	 * 1 buffer hdr and for each entry a header + regcount PMDs to save
 	 */
 	size = PAGE_ALIGN(  sizeof(perfmon_smpl_hdr_t)
 			  + entries * (sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64)));
+
+	DBprintk(("sampling buffer size=%lu bytes\n", size));
+
 	/*
 	 * check requested size to avoid Denial-of-service attacks
 	 * XXX: may have to refine this test	
@@ -688,9 +779,13 @@
 	}
 	/*
 	 * partially initialize the vma for the sampling buffer
+	 *
+	 * The VM_DONTCOPY flag is very important as it ensures that the mapping
+	 * will never be inherited for any child process (via fork()) which is always 
+	 * what we want.
 	 */
 	vma->vm_mm	     = mm;
-	vma->vm_flags	     = VM_READ| VM_MAYREAD |VM_RESERVED;
+	vma->vm_flags	     = VM_READ| VM_MAYREAD |VM_RESERVED|VM_DONTCOPY;
 	vma->vm_page_prot    = PAGE_READONLY; /* XXX may need to change */
 	vma->vm_ops	     = &pfm_vm_ops; /* necesarry to get the close() callback */
 	vma->vm_pgoff	     = 0;
@@ -708,8 +803,8 @@
 	psb->psb_size    = size; /* aligned size */
 	psb->psb_index   = 0;
 	psb->psb_entries = entries;
-	psb->psb_flags   = PFM_PSB_VMA; /* remember that there is a vma describing the buffer */
 	psb->psb_refcnt  = 1;
+	psb->psb_flags   = PSB_HAS_VMA;
 
 	spin_lock_init(&psb->psb_lock);
 
@@ -719,9 +814,9 @@
 	 */
 	psb->psb_entry_size = sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64);
 
-	DBprintk(("psb @%p entry_size=%ld hdr=%p addr=%p\n", 
+	DBprintk(("psb @%p entry_size=%ld hdr=%p addr=%p refcnt=%lu psb_flags=0x%x\n", 
 		  (void *)psb,psb->psb_entry_size, (void *)psb->psb_hdr, 
-		  (void *)psb->psb_addr));
+		  (void *)psb->psb_addr, psb->psb_refcnt, psb->psb_flags));
 
 	/* initialize some of the fields of user visible buffer header */
 	psb->psb_hdr->hdr_version    = PFM_SMPL_VERSION;
@@ -797,7 +892,6 @@
 	    && (current->uid ^ task->suid) && (current->uid ^ task->uid);
 }
 
-
 static int
 pfx_is_sane(struct task_struct *task, pfarg_context_t *pfx)
 {
@@ -813,6 +907,11 @@
 	}
 	ctx_flags = pfx->ctx_flags;
 
+	if ((ctx_flags & PFM_FL_INHERIT_MASK) == (PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL)) {
+		DBprintk(("invalid inherit mask 0x%x\n",ctx_flags & PFM_FL_INHERIT_MASK));
+		return -EINVAL;
+	}
+
 	if (ctx_flags & PFM_FL_SYSTEM_WIDE) {
 		DBprintk(("cpu_mask=0x%lx\n", pfx->ctx_cpu_mask));
 		/*
@@ -832,8 +931,8 @@
 		/*
 		 * and it must be a valid CPU
 		 */
-		cpu = ffs(pfx->ctx_cpu_mask);
-		if (cpu > smp_num_cpus) {
+		cpu = ffz(~pfx->ctx_cpu_mask);
+		if (cpu_is_online(cpu) == 0) {
 			DBprintk(("CPU%d is not online\n", cpu));
 			return -EINVAL;
 		}
@@ -851,7 +950,16 @@
 		 * must provide a target for the signal in blocking mode even when
 		 * no counter is configured with PFM_FL_REG_OVFL_NOTIFY
 		 */
-		if ((ctx_flags & PFM_FL_NOTIFY_BLOCK) && pfx->ctx_notify_pid == 0) return -EINVAL;
+		if ((ctx_flags & PFM_FL_NOTIFY_BLOCK) && pfx->ctx_notify_pid == 0) {
+			DBprintk(("must have notify_pid when blocking for [%d]\n", task->pid));
+			return -EINVAL;
+		}
+#if 0
+		if ((ctx_flags & PFM_FL_NOTIFY_BLOCK) && pfx->ctx_notify_pid == task->pid) {
+			DBprintk(("cannot notify self when blocking for [%d]\n", task->pid));
+			return -EINVAL;
+		}
+#endif
 	}
 	/* probably more to add here */
 
@@ -859,7 +967,7 @@
 }
 
 static int
-pfm_create_context(struct task_struct *task, pfm_context_t *ctx, void *req, int count, 
+pfm_context_create(struct task_struct *task, pfm_context_t *ctx, void *req, int count, 
 		   struct pt_regs *regs)
 {
 	pfarg_context_t tmp;
@@ -890,7 +998,7 @@
 	if (ctx_flags & PFM_FL_SYSTEM_WIDE) {
 
 		/* at this point, we know there is at least one bit set */
-		cpu = ffs(tmp.ctx_cpu_mask) - 1;
+		cpu = ffz(~tmp.ctx_cpu_mask);
 
 		DBprintk(("requesting CPU%d currently on CPU%d\n",cpu, smp_processor_id()));
 
@@ -984,7 +1092,7 @@
 	}
 
 	if (tmp.ctx_smpl_entries) {
-		DBprintk(("sampling entries=%ld\n",tmp.ctx_smpl_entries));
+		DBprintk(("sampling entries=%lu\n",tmp.ctx_smpl_entries));
 
 		ret = pfm_smpl_buffer_alloc(ctx, tmp.ctx_smpl_regs, 
 						 tmp.ctx_smpl_entries, &uaddr);
@@ -1010,20 +1118,12 @@
 
 	atomic_set(&ctx->ctx_last_cpu,-1); /* SMP only, means no CPU */
 
-	/* 
-	 * Keep track of the pmds we want to sample
-	 * XXX: may be we don't need to save/restore the DEAR/IEAR pmds
-	 * but we do need the BTB for sure. This is because of a hardware
-	 * buffer of 1 only for non-BTB pmds.
-	 *
-	 * We ignore the unimplemented pmds specified by the user
-	 */
-	ctx->ctx_used_pmds[0]  = tmp.ctx_smpl_regs[0] & pmu_conf.impl_regs[4];
-	ctx->ctx_saved_pmcs[0] = 1; /* always save/restore PMC[0] */
+	/* may be redudant with memset() but at least it's easier to remember */
+	atomic_set(&ctx->ctx_saving_in_progress, 0); 
+	atomic_set(&ctx->ctx_is_busy, 0); 
 
 	sema_init(&ctx->ctx_restart_sem, 0); /* init this semaphore to locked */
 
-
 	if (copy_to_user(req, &tmp, sizeof(tmp))) {
 		ret = -EFAULT;
 		goto buffer_error;
@@ -1126,21 +1226,22 @@
 			  	current->pid, 
 				flag == PFM_RELOAD_LONG_RESET ? "long" : "short", i, val));
 	}
+	ia64_srlz_d();
 	/* just in case ! */
 	ctx->ctx_ovfl_regs[0] = 0UL;
 }
 
 static int
-pfm_write_pmcs(struct task_struct *ta, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
+pfm_write_pmcs(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
-	struct thread_struct *th = &ta->thread;
+	struct thread_struct *th = &task->thread;
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
 	unsigned int cnum;
 	int i;
 	int ret = 0, reg_retval = 0;
 
 	/* we don't quite support this right now */
-	if (ta != current) return -EINVAL;
+	if (task != current) return -EINVAL;
 
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
@@ -1169,30 +1270,30 @@
 		 * 	- per-task : user monitor
 		 * any other configuration is rejected.
 		 */
-		if (PMC_IS_MONITOR(cnum)) {
-			pfm_monitor_t *p = (pfm_monitor_t *)&tmp.reg_value;
-
-			DBprintk(("pmc[%u].pm = %d\n", cnum, p->pmc_pm));
+		if (PMC_IS_MONITOR(cnum) || PMC_IS_COUNTING(cnum)) {
+			DBprintk(("pmc[%u].pm=%ld\n", cnum, PMC_PM(cnum, tmp.reg_value))); 
 
-			if (ctx->ctx_fl_system ^ p->pmc_pm) {
-			//if ((ctx->ctx_fl_system == 1 && p->pmc_pm == 0)
-			 //  ||(ctx->ctx_fl_system == 0 && p->pmc_pm == 1)) {
+			if (ctx->ctx_fl_system ^ PMC_PM(cnum, tmp.reg_value)) {
+				DBprintk(("pmc_pm=%ld fl_system=%d\n", PMC_PM(cnum, tmp.reg_value), ctx->ctx_fl_system));
 				ret = -EINVAL;
 				goto abort_mission;
 			}
-			/*
-			 * enforce generation of overflow interrupt. Necessary on all
-			 * CPUs which do not implement 64-bit hardware counters.
-			 */
-			p->pmc_oi = 1;
 		}
 
 		if (PMC_IS_COUNTING(cnum)) {
+			pfm_monitor_t *p = (pfm_monitor_t *)&tmp.reg_value;
+			/*
+		 	 * enforce generation of overflow interrupt. Necessary on all
+		 	 * CPUs.
+		 	 */
+			p->pmc_oi = 1;
+
 			if (tmp.reg_flags & PFM_REGFL_OVFL_NOTIFY) {
 				/*
 				 * must have a target for the signal
 				 */
 				if (ctx->ctx_notify_task == NULL) {
+					DBprintk(("no notify_task && PFM_REGFL_OVFL_NOTIFY\n"));
 					ret = -EINVAL;
 					goto abort_mission;
 				}
@@ -1206,14 +1307,11 @@
 			ctx->ctx_soft_pmds[cnum].reset_pmds[1] = tmp.reg_reset_pmds[1];
 			ctx->ctx_soft_pmds[cnum].reset_pmds[2] = tmp.reg_reset_pmds[2];
 			ctx->ctx_soft_pmds[cnum].reset_pmds[3] = tmp.reg_reset_pmds[3];
-
-			/*
-			 * needed in case the user does not initialize the equivalent
-			 * PMD. Clearing is done in reset_pmu() so there is no possible
-			 * leak here.
-			 */
-			CTX_USED_PMD(ctx, cnum);
 		}
+		/*
+		 * execute write checker, if any
+		 */
+		if (PMC_WR_FUNC(cnum)) ret = PMC_WR_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
 abort_mission:
 		if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL;
 
@@ -1233,14 +1331,21 @@
 		 */
 		if (ret != 0) {
 			DBprintk(("[%d] pmc[%u]=0x%lx error %d\n",
-				  ta->pid, cnum, tmp.reg_value, reg_retval));
+				  task->pid, cnum, tmp.reg_value, reg_retval));
 			break;
 		}
 
 		/* 
 		 * We can proceed with this register!
 		 */
-		
+
+		/*
+		 * Needed in case the user does not initialize the equivalent
+		 * PMD. Clearing is done in reset_pmu() so there is no possible
+		 * leak here.
+		 */
+		CTX_USED_PMD(ctx, pmu_conf.pmc_desc[cnum].dep_pmd[0]);
+
 		/* 
 		 * keep copy the pmc, used for register reload
 		 */
@@ -1248,17 +1353,17 @@
 
 		ia64_set_pmc(cnum, tmp.reg_value);
 
-		DBprintk(("[%d] pmc[%u]=0x%lx flags=0x%x save_pmcs=0%lx reload_pmcs=0x%lx\n", 
-			  ta->pid, cnum, tmp.reg_value, 
+		DBprintk(("[%d] pmc[%u]=0x%lx flags=0x%x used_pmds=0x%lx\n", 
+			  task->pid, cnum, tmp.reg_value, 
 			  ctx->ctx_soft_pmds[cnum].flags, 
-			  ctx->ctx_saved_pmcs[0], ctx->ctx_reload_pmcs[0]));
+			  ctx->ctx_used_pmds[0]));
 
 	}
 	return ret;
 }
 
 static int
-pfm_write_pmds(struct task_struct *ta, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
+pfm_write_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
 	unsigned int cnum;
@@ -1266,7 +1371,7 @@
 	int ret = 0, reg_retval = 0;
 
 	/* we don't quite support this right now */
-	if (ta != current) return -EINVAL;
+	if (task != current) return -EINVAL;
 
 	/* 
 	 * Cannot do anything before PMU is enabled 
@@ -1281,7 +1386,6 @@
 		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
 		cnum = tmp.reg_num;
-
 		if (!PMD_IS_IMPL(cnum)) {
 			ret = -EINVAL;
 			goto abort_mission;
@@ -1295,6 +1399,10 @@
 			ctx->ctx_soft_pmds[cnum].short_reset = tmp.reg_short_reset;
 
 		}
+		/*
+		 * execute write checker, if any
+		 */
+		if (PMD_WR_FUNC(cnum)) ret = PMD_WR_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
 abort_mission:
 		if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL;
 
@@ -1311,21 +1419,24 @@
 		 */
 		if (ret != 0) {
 			DBprintk(("[%d] pmc[%u]=0x%lx error %d\n",
-				  ta->pid, cnum, tmp.reg_value, reg_retval));
+				  task->pid, cnum, tmp.reg_value, reg_retval));
 			break;
 		}
 
 		/* keep track of what we use */
-		CTX_USED_PMD(ctx, cnum);
+		CTX_USED_PMD(ctx, pmu_conf.pmd_desc[(cnum)].dep_pmd[0]);
+		/* mark this register as used as well */
+		CTX_USED_PMD(ctx, RDEP(cnum));
 
 		/* writes to unimplemented part is ignored, so this is safe */
-		ia64_set_pmd(cnum, tmp.reg_value);
+		ia64_set_pmd(cnum, tmp.reg_value & pmu_conf.perf_ovfl_val);
 
 		/* to go away */
 		ia64_srlz_d();
+
 		DBprintk(("[%d] pmd[%u]: soft_pmd=0x%lx  short_reset=0x%lx "
 			  "long_reset=0x%lx hw_pmd=%lx notify=%c used_pmds=0x%lx reset_pmds=0x%lx\n",
-				ta->pid, cnum,
+				task->pid, cnum,
 				ctx->ctx_soft_pmds[cnum].val,
 				ctx->ctx_soft_pmds[cnum].short_reset,
 				ctx->ctx_soft_pmds[cnum].long_reset,
@@ -1338,12 +1449,13 @@
 }
 
 static int
-pfm_read_pmds(struct task_struct *ta, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
+pfm_read_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
-	struct thread_struct *th = &ta->thread;
+	struct thread_struct *th = &task->thread;
 	unsigned long val=0;
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
-	int i;
+	unsigned int cnum;
+	int i, ret = 0;
 
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
@@ -1356,14 +1468,25 @@
 
 	/* XXX: ctx locking may be required here */
 
-	DBprintk(("ctx_last_cpu=%d for [%d]\n", atomic_read(&ctx->ctx_last_cpu), ta->pid));
+	DBprintk(("ctx_last_cpu=%d for [%d]\n", atomic_read(&ctx->ctx_last_cpu), task->pid));
 
 	for (i = 0; i < count; i++, req++) {
-		unsigned long reg_val = ~0UL, ctx_val = ~0UL;
+		unsigned long ctx_val = ~0UL;
 
 		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
-		if (!PMD_IS_IMPL(tmp.reg_num)) goto abort_mission;
+		cnum = tmp.reg_num;
+
+		if (!PMD_IS_IMPL(cnum)) goto abort_mission;
+		/*
+		 * we can only read the register that we use. That includes
+		 * the one we explicitely initialize AND the one we want included
+		 * in the sampling buffer (smpl_regs).
+		 *
+		 * Having this restriction allows optimization in the ctxsw routine
+		 * without compromising security (leaks)
+		 */
+		if (!CTX_IS_USED_PMD(ctx, cnum)) goto abort_mission;
 
 		/*
 		 * If the task is not the current one, then we check if the
@@ -1372,8 +1495,8 @@
 		 */
 		if (atomic_read(&ctx->ctx_last_cpu) == smp_processor_id()){
 			ia64_srlz_d();
-			val = reg_val = ia64_get_pmd(tmp.reg_num);
-			DBprintk(("reading pmd[%u]=0x%lx from hw\n", tmp.reg_num, val));
+			val = ia64_get_pmd(cnum);
+			DBprintk(("reading pmd[%u]=0x%lx from hw\n", cnum, val));
 		} else {
 #ifdef CONFIG_SMP
 			int cpu;
@@ -1389,30 +1512,35 @@
 			 */
 			cpu = atomic_read(&ctx->ctx_last_cpu);
 			if (cpu != -1) {
-				DBprintk(("must fetch on CPU%d for [%d]\n", cpu, ta->pid));
-				pfm_fetch_regs(cpu, ta, ctx);
+				DBprintk(("must fetch on CPU%d for [%d]\n", cpu, task->pid));
+				pfm_fetch_regs(cpu, task, ctx);
 			}
 #endif
 			/* context has been saved */
-			val = reg_val = th->pmd[tmp.reg_num];
+			val = th->pmd[cnum];
 		}
-		if (PMD_IS_COUNTING(tmp.reg_num)) {
+		if (PMD_IS_COUNTING(cnum)) {
 			/*
 			 * XXX: need to check for overflow
 			 */
 
 			val &= pmu_conf.perf_ovfl_val;
-			val += ctx_val = ctx->ctx_soft_pmds[tmp.reg_num].val;
-		} else {
+			val += ctx_val = ctx->ctx_soft_pmds[cnum].val;
+		} 
 
-			val = reg_val = ia64_get_pmd(tmp.reg_num);
-		}
-		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);
 		tmp.reg_value = val;
 
-		DBprintk(("read pmd[%u] soft_pmd=0x%lx reg=0x%lx pmc=0x%lx\n", 
-					tmp.reg_num, ctx_val, reg_val, 
-					ia64_get_pmc(tmp.reg_num)));
+		/*
+		 * execute read checker, if any
+		 */
+		if (PMD_RD_FUNC(cnum)) {
+			ret = PMD_RD_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
+		}
+
+		PFM_REG_RETFLAG_SET(tmp.reg_flags, ret);
+
+		DBprintk(("read pmd[%u] ret=%d value=0x%lx pmc=0x%lx\n", 
+					cnum, ret, val, ia64_get_pmc(cnum)));
 
 		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
 	}
@@ -1420,7 +1548,7 @@
 abort_mission:
 	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
 	/* 
-	 * XXX: if this fails, we stick we the original failure, flag not updated!
+	 * XXX: if this fails, we stick with the original failure, flag not updated!
 	 */
 	copy_to_user(req, &tmp, sizeof(tmp));
 	return -EINVAL;
@@ -1455,15 +1583,11 @@
 	 */
 	if (ctx && ctx->ctx_fl_using_dbreg == 1) return -1;
 
-	/*
-	 * XXX: not pretty
-	 */
 	LOCK_PFS();
 
 	/*
-	 * We only allow the use of debug registers when there is no system
-	 * wide monitoring 
-	 * XXX: we could relax this by 
+	 * We cannot allow setting breakpoints when system wide monitoring
+	 * sessions are using the debug registers.
 	 */
 	if (pfm_sessions.pfs_sys_use_dbregs> 0)
 		ret = -1;
@@ -1516,6 +1640,7 @@
 {
 	return 0;
 }
+
 int
 pfm_release_debug_registers(struct task_struct *task)
 {
@@ -1534,12 +1659,6 @@
 	 */
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
-
-	if (ctx->ctx_fl_frozen==0) {
-		printk("task %d without pmu_frozen set\n", task->pid);
-		return -EINVAL;
-	}
-
 	if (task == current) {
 		DBprintk(("restarting self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen));
 
@@ -1656,25 +1775,35 @@
 				current->pid,
 				ctx->ctx_fl_system, PMU_OWNER(),
 				current));
+
 	/* simply stop monitoring but not the PMU */
 	if (ctx->ctx_fl_system) {
 
-		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
-
 		/* disable dcr pp */
 		ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP);
 
+		/* stop monitoring */
+		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
+
+		ia64_srlz_i();
+
 #ifdef CONFIG_SMP
 		local_cpu_data->pfm_dcr_pp  = 0;
 #else
 		pfm_tasklist_toggle_pp(0);
 #endif
-
 		ia64_psr(regs)->pp = 0;
 
 	} else {
+
+		/* stop monitoring */
 		__asm__ __volatile__ ("rum psr.up;;"::: "memory");
 
+		ia64_srlz_i();
+
+		/*
+		 * clear user level psr.up
+		 */
 		ia64_psr(regs)->up = 0;
 	}
 	return 0;
@@ -1701,7 +1830,7 @@
 		ia64_psr(regs)->up = 0;
 	}
 	/* 
-	 * goes back to default behavior 
+	 * goes back to default behavior: no user level control
 	 * no need to change live psr.sp because useless at the kernel level
 	 */
 	ia64_psr(regs)->sp = 1;
@@ -1713,10 +1842,8 @@
 	return 0;
 }
 
-
-
 static int
-pfm_destroy_context(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, 
+pfm_context_destroy(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, 
 	 struct pt_regs *regs)
 {
 	/* we don't quite support this right now */
@@ -1742,15 +1869,14 @@
 		ia64_psr(regs)->up = 0;
 	}
 
-	/* restore security level */
-	ia64_psr(regs)->sp = 1;
-
 skipped_stop:
 	/*
 	 * remove sampling buffer mapping, if any
 	 */
-	if (ctx->ctx_smpl_vaddr) pfm_remove_smpl_mapping(task);
-
+	if (ctx->ctx_smpl_vaddr) {
+		pfm_remove_smpl_mapping(task);
+		ctx->ctx_smpl_vaddr = 0UL;
+	}
 	/* now free context and related state */
 	pfm_context_exit(task);
 
@@ -1761,7 +1887,7 @@
  * does nothing at the moment
  */
 static int
-pfm_unprotect_context(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, 
+pfm_context_unprotect(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, 
 	 struct pt_regs *regs)
 {
 	return 0;
@@ -1791,9 +1917,9 @@
 {
 	unsigned int mode = *(unsigned int *)arg;
 
-	pfm_debug_mode = mode == 0 ? 0 : 1;
+	pfm_sysctl.debug = mode == 0 ? 0 : 1;
 
-	printk("perfmon debugging %s\n", pfm_debug_mode ? "on" : "off");
+	printk("perfmon debugging %s\n", pfm_sysctl.debug ? "on" : "off");
 
 	return 0;
 }
@@ -1863,8 +1989,8 @@
 	if (ctx->ctx_fl_system) {
 		/* we mark ourselves as owner  of the debug registers */
 		ctx->ctx_fl_using_dbreg = 1;
-	} else {
-       		if (ctx->ctx_fl_using_dbreg == 0) {
+		DBprintk(("system-wide setting fl_using_dbreg for [%d]\n", task->pid));
+	} else if (first_time) {
 			ret= -EBUSY;
 			if ((thread->flags & IA64_THREAD_DBG_VALID) != 0) {
 				DBprintk(("debug registers already in use for [%d]\n", task->pid));
@@ -1873,6 +1999,7 @@
 			/* we mark ourselves as owner  of the debug registers */
 			ctx->ctx_fl_using_dbreg = 1;
 
+			DBprintk(("setting fl_using_dbreg for [%d]\n", task->pid));
 			/* 
 			 * Given debug registers cannot be used for both debugging 
 			 * and performance monitoring at the same time, we reuse
@@ -1880,18 +2007,27 @@
 			 */
 			memset(task->thread.dbr, 0, sizeof(task->thread.dbr));
 			memset(task->thread.ibr, 0, sizeof(task->thread.ibr));
+	}
 
-			/*
-			 * clear hardware registers to make sure we don't leak
-			 * information and pick up stale state
-			 */
-			for (i=0; i < pmu_conf.num_ibrs; i++) {
-				ia64_set_ibr(i, 0UL);
-			}
-			for (i=0; i < pmu_conf.num_dbrs; i++) {
-				ia64_set_dbr(i, 0UL);
-			}
+	if (first_time) {
+		DBprintk(("[%d] clearing ibrs,dbrs\n", task->pid));
+		/*
+	 	 * clear hardware registers to make sure we don't
+	 	 * pick up stale state. 
+		 *
+		 * for a system wide session, we do not use
+		 * thread.dbr, thread.ibr because this process
+		 * never leaves the current CPU and the state
+		 * is shared by all processes running on it
+	 	 */
+		for (i=0; i < pmu_conf.num_ibrs; i++) {
+			ia64_set_ibr(i, 0UL);
+		}
+		ia64_srlz_i();
+		for (i=0; i < pmu_conf.num_dbrs; i++) {
+			ia64_set_dbr(i, 0UL);
 		}
+		ia64_srlz_d();
 	}
 
 	ret = -EFAULT;
@@ -1951,6 +2087,7 @@
 			CTX_USED_IBR(ctx, rnum);
 
 			ia64_set_ibr(rnum, dbreg.val);
+			ia64_srlz_i();
 
 			thread->ibr[rnum] = dbreg.val;
 
@@ -1959,6 +2096,7 @@
 			CTX_USED_DBR(ctx, rnum);
 
 			ia64_set_dbr(rnum, dbreg.val);
+			ia64_srlz_d();
 
 			thread->dbr[rnum] = dbreg.val;
 
@@ -2058,27 +2196,35 @@
 
 	if (ctx->ctx_fl_system) {
 		
-		/* enable dcr pp */
-		ia64_set_dcr(ia64_get_dcr()|IA64_DCR_PP);
-
 #ifdef CONFIG_SMP
 		local_cpu_data->pfm_dcr_pp  = 1;
 #else
 		pfm_tasklist_toggle_pp(1);
 #endif
+		/* set user level psr.pp */
 		ia64_psr(regs)->pp = 1;
 
+		/* start monitoring at kernel level */
 		__asm__ __volatile__ ("ssm psr.pp;;"::: "memory");
 
+		/* enable dcr pp */
+		ia64_set_dcr(ia64_get_dcr()|IA64_DCR_PP);
+
+		ia64_srlz_i();
+
 	} else {
 		if ((task->thread.flags & IA64_THREAD_PM_VALID) == 0) {
 			printk("perfmon: pfm_start task flag not set for [%d]\n", task->pid);
 			return -EINVAL;
 		}
+		/* set user level psr.up */
 		ia64_psr(regs)->up = 1;
+
+		/* start monitoring at kernel level */
 		__asm__ __volatile__ ("sum psr.up;;"::: "memory");
+
+		ia64_srlz_i();
 	}
-	ia64_srlz_d();
 
 	return 0;
 }
@@ -2101,7 +2247,9 @@
 		ia64_psr(regs)->pp = 0;
 		ia64_psr(regs)->up = 0; /* just to make sure! */
 
+		/* make sure monitoring is stopped */
 		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
+		ia64_srlz_i();
 
 #ifdef CONFIG_SMP
 		local_cpu_data->pfm_syst_wide = 1;
@@ -2116,21 +2264,21 @@
 		ia64_psr(regs)->pp = 0; /* just to make sure! */
 		ia64_psr(regs)->up = 0;
 
+		/* make sure monitoring is stopped */
 		__asm__ __volatile__ ("rum psr.up;;"::: "memory");
-		/*
-		 * allow user control (user monitors only)
-		if (task  == ctx->ctx_owner) {
-		 */
-		{
-			DBprintk(("clearing psr.sp for [%d]\n", current->pid));
-			ia64_psr(regs)->sp = 0;
-		}
+		ia64_srlz_i();
+
+		DBprintk(("clearing psr.sp for [%d]\n", current->pid));
+
+		/* allow user level control  */
+		ia64_psr(regs)->sp = 0;
+
+		/* PMU state will be saved/restored on ctxsw */
 		task->thread.flags |= IA64_THREAD_PM_VALID;
 	}
 
 	SET_PMU_OWNER(task);
 
-
 	ctx->ctx_flags.state = PFM_CTX_ENABLED;
 	atomic_set(&ctx->ctx_last_cpu, smp_processor_id());
 
@@ -2141,6 +2289,40 @@
 	return 0;
 }
 
+static int
+pfm_get_pmc_reset(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, 
+	   struct pt_regs *regs)
+{
+	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
+	unsigned int cnum;
+	int i;
+
+	for (i = 0; i < count; i++, req++) {
+
+		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+
+		cnum = tmp.reg_num;
+
+		if (!PMC_IS_IMPL(cnum)) goto abort_mission;
+
+		tmp.reg_value = reset_pmcs[cnum];
+
+		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);
+
+		DBprintk(("pmc_reset_val pmc[%u]=0x%lx\n", cnum, tmp.reg_value)); 
+
+		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+	}
+	return 0;
+abort_mission:
+	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
+	/* 
+	 * XXX: if this fails, we stick with the original failure, flag not updated!
+	 */
+	copy_to_user(req, &tmp, sizeof(tmp));
+	return -EINVAL;
+}
+
 /*
  * functions MUST be listed in the increasing order of their index (see permfon.h)
  */
@@ -2148,19 +2330,19 @@
 /* 0  */{ NULL, 0, 0, 0}, /* not used */
 /* 1  */{ pfm_write_pmcs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
 /* 2  */{ pfm_write_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
-/* 3  */{ pfm_read_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
+/* 3  */{ pfm_read_pmds,PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
 /* 4  */{ pfm_stop, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 5  */{ pfm_start, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 6  */{ pfm_enable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 7  */{ pfm_disable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
-/* 8  */{ pfm_create_context, PFM_CMD_ARG_READ, 1, sizeof(pfarg_context_t)},
-/* 9  */{ pfm_destroy_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
+/* 8  */{ pfm_context_create, PFM_CMD_PID|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, 1, sizeof(pfarg_context_t)},
+/* 9  */{ pfm_context_destroy, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 10 */{ pfm_restart, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_NOCHK, 0, 0},
 /* 11 */{ pfm_protect_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 12 */{ pfm_get_features, PFM_CMD_ARG_WRITE, 0, 0},
 /* 13 */{ pfm_debug, 0, 1, sizeof(unsigned int)},
-/* 14 */{ pfm_unprotect_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
-/* 15 */{ NULL, 0, 0, 0}, /* not used */
+/* 14 */{ pfm_context_unprotect, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
+/* 15 */{ pfm_get_pmc_reset, PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
 /* 16 */{ NULL, 0, 0, 0}, /* not used */
 /* 17 */{ NULL, 0, 0, 0}, /* not used */
 /* 18 */{ NULL, 0, 0, 0}, /* not used */
@@ -2222,9 +2404,9 @@
 {
 	struct pt_regs *regs = (struct pt_regs *)&stack;
 	struct task_struct *task = current;
-	pfm_context_t *ctx = task->thread.pfm_context;
+	pfm_context_t *ctx;
 	size_t sz;
-	int ret = -ESRCH, narg;
+	int ret, narg;
 
 	/* 
 	 * reject any call if perfmon was disabled at initialization time
@@ -2254,6 +2436,8 @@
 
 		if (pid != current->pid) {
 
+			ret = -ESRCH;
+
 			read_lock(&tasklist_lock);
 
 			task = find_task_by_pid(pid);
@@ -2268,10 +2452,11 @@
 				ret = check_task_state(task);
 				if (ret != 0) goto abort_call;
 			}
-			ctx = task->thread.pfm_context;
-		}
+		} 
 	} 
 
+	ctx = task->thread.pfm_context;
+
 	if (PFM_CMD_USE_CTX(cmd)) {
 		ret = -EINVAL;
 	       if (ctx == NULL) {
@@ -2387,9 +2572,9 @@
 	int j;
 
 
-pfm_recorded_samples_count++;
+
 	idx = ia64_fetch_and_add(1, &psb->psb_index);
-	DBprintk(("recording index=%ld entries=%ld\n", idx-1, psb->psb_entries));
+	DBprintk_ovfl(("recording index=%ld entries=%ld\n", idx-1, psb->psb_entries));
 
 	/*
 	* XXX: there is a small chance that we could run out on index before resetting
@@ -2409,7 +2594,7 @@
 	/*
 	 * initialize entry header
 	 */
-	h->pid  = task->pid;
+	h->pid  = current->pid;
 	h->cpu  = smp_processor_id();
 	h->rate = 0; /* XXX: add the sampling rate used here */
 	h->ip   = regs ? regs->cr_iip : 0x0;	/* where did the fault happened */
@@ -2437,24 +2622,27 @@
 		} else {
 			*e = ia64_get_pmd(j); /* slow */
 		}
-		DBprintk(("e=%p pmd%d =0x%lx\n", (void *)e, j, *e));
+		DBprintk_ovfl(("e=%p pmd%d =0x%lx\n", (void *)e, j, *e));
 		e++;
 	}
+	pfm_stats.pfm_recorded_samples_count++;
+
 	/*
 	 * make the new entry visible to user, needs to be atomic
 	 */
 	ia64_fetch_and_add(1, &psb->psb_hdr->hdr_count);
 
-	DBprintk(("index=%ld entries=%ld hdr_count=%ld\n", 
+	DBprintk_ovfl(("index=%ld entries=%ld hdr_count=%ld\n", 
 				idx, psb->psb_entries, psb->psb_hdr->hdr_count));
 	/* 
 	 * sampling buffer full ? 
 	 */
 	if (idx == (psb->psb_entries-1)) {
-		DBprintk(("sampling buffer full\n"));
+		DBprintk_ovfl(("sampling buffer full\n"));
 		/*
 		 * XXX: must reset buffer in blocking mode and lost notified
 		 */
+		pfm_stats.pfm_full_smpl_buffer_count++;
 		return 1;
 	}
 	return 0;
@@ -2467,15 +2655,13 @@
  *	new value of pmc[0]. if 0x0 then unfreeze, else keep frozen
  */
 static unsigned long
-pfm_overflow_handler(struct task_struct *task, u64 pmc0, struct pt_regs *regs)
+pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs)
 {
 	unsigned long mask;
 	struct thread_struct *t;
-	pfm_context_t *ctx;
 	unsigned long old_val;
 	unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL;
 	int i;
-	int my_cpu = smp_processor_id();
 	int ret = 1;
 	struct siginfo si;
 	/*
@@ -2491,18 +2677,7 @@
 	 * valid one, i.e. the one that caused the interrupt.
 	 */
 
-	if (task == NULL) {
-		DBprintk(("owners[%d]=NULL\n", my_cpu));
-		return 0x1;
-	}
 	t   = &task->thread;
-	ctx = task->thread.pfm_context;
-
-	if (!ctx) {
-		printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", 
-			task->pid);
-		return 0;
-	}
 
 	/*
 	 * XXX: debug test
@@ -2524,12 +2699,12 @@
 
 	mask = pmc0 >> PMU_FIRST_COUNTER;
 
-	DBprintk(("pmc0=0x%lx pid=%d iip=0x%lx, %s"
-		  " mode used_pmds=0x%lx save_pmcs=0x%lx reload_pmcs=0x%lx\n", 
+	DBprintk_ovfl(("pmc0=0x%lx pid=%d iip=0x%lx, %s"
+		  " mode used_pmds=0x%lx used_pmcs=0x%lx reload_pmcs=0x%lx\n", 
 			pmc0, task->pid, (regs ? regs->cr_iip : 0), 
 			CTX_OVFL_NOBLOCK(ctx) ? "nonblocking" : "blocking",
 			ctx->ctx_used_pmds[0],
-			ctx->ctx_saved_pmcs[0],
+			ctx->ctx_used_pmcs[0],
 			ctx->ctx_reload_pmcs[0]));
 
 	/*
@@ -2540,7 +2715,7 @@
 		/* skip pmd which did not overflow */
 		if ((mask & 0x1) == 0) continue;
 
-		DBprintk(("PMD[%d] overflowed hw_pmd=0x%lx soft_pmd=0x%lx\n", 
+		DBprintk_ovfl(("pmd[%d] overflowed hw_pmd=0x%lx soft_pmd=0x%lx\n", 
 			  i, ia64_get_pmd(i), ctx->ctx_soft_pmds[i].val));
 
 		/*
@@ -2552,8 +2727,7 @@
 		old_val = ctx->ctx_soft_pmds[i].val;
 		ctx->ctx_soft_pmds[i].val = 1 + pmu_conf.perf_ovfl_val + pfm_read_soft_counter(ctx, i);
 
-
-		DBprintk(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx\n", 
+		DBprintk_ovfl(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx\n", 
 			  i, ctx->ctx_soft_pmds[i].val, old_val, 
 			  ia64_get_pmd(i) & pmu_conf.perf_ovfl_val));
 
@@ -2570,7 +2744,7 @@
 
 			ovfl_pmds |= 1UL << i;
 
-			DBprintk(("soft_pmd[%d] overflowed flags=0x%x, ovfl=0x%lx\n", i, ctx->ctx_soft_pmds[i].flags, ovfl_pmds));
+			DBprintk_ovfl(("soft_pmd[%d] overflowed flags=0x%x, ovfl=0x%lx\n", i, ctx->ctx_soft_pmds[i].flags, ovfl_pmds));
 
 			if (PMC_OVFL_NOTIFY(ctx, i)) {
 				ovfl_notify |= 1UL << i;
@@ -2609,7 +2783,8 @@
 	 * No overflow requiring a user level notification
 	 */
 	if (ovfl_notify == 0UL) {
-		pfm_reset_regs(ctx, &ovfl_pmds, PFM_RELOAD_SHORT_RESET);
+		if (ovfl_pmds) 
+			pfm_reset_regs(ctx, &ovfl_pmds, PFM_RELOAD_SHORT_RESET);
 		return 0x0;
 	}
 
@@ -2684,7 +2859,7 @@
 	 	 * necessarily go to the signal handler (if any) when it goes back to
 	 	 * user mode.
 	 	 */
-		DBprintk(("[%d] sending notification to [%d]\n", 
+		DBprintk_ovfl(("[%d] sending notification to [%d]\n", 
 			  task->pid, ctx->ctx_notify_task->pid));
 
 
@@ -2717,7 +2892,7 @@
 		 * before, changing it to NULL will still maintain this invariant.
 		 * Of course, when it is equal to current it cannot change at this point.
 		 */
-		DBprintk(("block=%d notify [%d] current [%d]\n", 
+		DBprintk_ovfl(("block=%d notify [%d] current [%d]\n", 
 			ctx->ctx_fl_block,
 			ctx->ctx_notify_task ? ctx->ctx_notify_task->pid: -1, 
 			current->pid ));
@@ -2728,7 +2903,7 @@
 	} else {
 lost_notify: /* XXX: more to do here, to convert to non-blocking (reset values) */
 
-		DBprintk(("notification task has disappeared !\n"));
+		DBprintk_ovfl(("notification task has disappeared !\n"));
 		/*
 		 * for a non-blocking context, we make sure we do not fall into the 
 		 * pfm_overflow_notify() trap. Also in the case of a blocking context with lost 
@@ -2750,7 +2925,7 @@
 	 */
 	ctx->ctx_fl_frozen = 1;
 
-	DBprintk(("reload pmc0=0x%x must_block=%ld\n",
+	DBprintk_ovfl(("return pmc0=0x%x must_block=%ld\n",
 				ctx->ctx_fl_frozen ? 0x1 : 0x0, t->pfm_ovfl_block_reset));
 
 	return ctx->ctx_fl_frozen ? 0x1 : 0x0;
@@ -2761,8 +2936,9 @@
 {
 	u64 pmc0;
 	struct task_struct *task;
+	pfm_context_t *ctx;
 
-	pfm_ovfl_intr_count++;
+	pfm_stats.pfm_ovfl_intr_count++;
 
 	/* 
 	 * srlz.d done before arriving here
@@ -2776,24 +2952,54 @@
 	 * assumes : if any PM[0].bit[63-1] is set, then PMC[0].fr = 1
 	 */
 	if ((pmc0 & ~0x1UL)!=0UL && (task=PMU_OWNER())!= NULL) {
-
 		/* 
-		 * assumes, PMC[0].fr = 1 at this point 
-		 *
-		 * XXX: change protype to pass &pmc0
+		 * we assume that pmc0.fr is always set here
 		 */
-		pmc0 = pfm_overflow_handler(task, pmc0, regs);
+		ctx = task->thread.pfm_context;
 
-		/* we never explicitely freeze PMU here */
-		if (pmc0 == 0) {
-			ia64_set_pmc(0, 0);
-			ia64_srlz_d();
+		/* sanity check */
+		if (!ctx) {
+			printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", 
+				task->pid);
+			return;
 		}
+#ifdef CONFIG_SMP
+		/*
+		 * Because an IPI has higher priority than the PMU overflow interrupt, it is 
+		 * possible that the handler be interrupted by a request from another CPU to fetch 
+		 * the PMU state of the currently active context. The task may have just been 
+		 * migrated to another CPU which is trying to restore the context. If there was
+		 * a pending overflow interrupt when the task left this CPU, it is possible for
+		 * the handler to get interrupt by the IPI. In which case, we fetch request
+		 * MUST be postponed until the interrupt handler is done. The ctx_is_busy
+		 * flag indicates such a condition. The other CPU must busy wait until it's cleared.
+		 */
+		atomic_set(&ctx->ctx_is_busy, 1);
+#endif
+
+		/* 
+		 * assume PMC[0].fr = 1 at this point 
+		 */
+		pmc0 = pfm_overflow_handler(task, ctx, pmc0, regs);
+
+		/*
+		 * We always clear the overflow status bits and either unfreeze
+		 * or keep the PMU frozen.
+		 */
+		ia64_set_pmc(0, pmc0);
+		ia64_srlz_d();
+
+#ifdef CONFIG_SMP
+		/*
+		 * announce that we are doing with the context
+		 */
+		atomic_set(&ctx->ctx_is_busy, 0);
+#endif
 	} else {
-		pfm_spurious_ovfl_intr_count++;
+		pfm_stats.pfm_spurious_ovfl_intr_count++;
 
-		DBprintk(("perfmon: Spurious PMU overflow interrupt on CPU%d: pmc0=0x%lx owner=%p\n", 
-			smp_processor_id(), pmc0, (void *)PMU_OWNER()));
+		printk("perfmon: Spurious PMU overflow interrupt on CPU%d: pmc0=0x%lx owner=%p\n", 
+			smp_processor_id(), pmc0, (void *)PMU_OWNER());
 	}
 }
 
@@ -2801,33 +3007,31 @@
 static int
 perfmon_proc_info(char *page)
 {
-#ifdef CONFIG_SMP
-#define cpu_is_online(i) (cpu_online_map & (1UL << i))
-#else
-#define cpu_is_online(i)        1
-#endif
 	char *p = page;
-	u64 pmc0 = ia64_get_pmc(0);
 	int i;
 
-	p += sprintf(p, "perfmon enabled: %s\n", pmu_conf.pfm_is_disabled ? "No": "Yes");
-
-	p += sprintf(p, "monitors_pmcs0]=0x%lx\n", pmu_conf.monitor_pmcs[0]);
-	p += sprintf(p, "counter_pmcds[0]=0x%lx\n", pmu_conf.counter_pmds[0]);
-	p += sprintf(p, "overflow interrupts=%lu\n", pfm_ovfl_intr_count);
-	p += sprintf(p, "spurious overflow interrupts=%lu\n", pfm_spurious_ovfl_intr_count);
-	p += sprintf(p, "recorded samples=%lu\n", pfm_recorded_samples_count);
-
-	p += sprintf(p, "CPU%d.pmc[0]=%lx\nPerfmon debug: %s\n", 
-			smp_processor_id(), pmc0, pfm_debug_mode ? "On" : "Off");
+	p += sprintf(p, "enabled          : %s\n", pmu_conf.pfm_is_disabled ? "No": "Yes");
+	p += sprintf(p, "fastctxsw        : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No");
+	p += sprintf(p, "ovfl_mask        : 0x%lx\n", pmu_conf.perf_ovfl_val);
+	p += sprintf(p, "overflow intrs   : %lu\n", pfm_stats.pfm_ovfl_intr_count);
+	p += sprintf(p, "spurious intrs   : %lu\n", pfm_stats.pfm_spurious_ovfl_intr_count);
+	p += sprintf(p, "recorded samples : %lu\n", pfm_stats.pfm_recorded_samples_count);
+	p += sprintf(p, "smpl buffer full : %lu\n", pfm_stats.pfm_full_smpl_buffer_count);
 
 #ifdef CONFIG_SMP
-	p += sprintf(p, "CPU%d cpu_data.pfm_syst_wide=%d cpu_data.dcr_pp=%d\n", 
-			smp_processor_id(), local_cpu_data->pfm_syst_wide, local_cpu_data->pfm_dcr_pp);
+	p += sprintf(p, "CPU%d syst_wide   : %d\n"
+			"CPU%d dcr_pp      : %d\n", 
+			smp_processor_id(), 
+			local_cpu_data->pfm_syst_wide, 
+			smp_processor_id(), 
+			local_cpu_data->pfm_dcr_pp);
 #endif
 
 	LOCK_PFS();
-	p += sprintf(p, "proc_sessions=%lu\nsys_sessions=%lu\nsys_use_dbregs=%lu\nptrace_use_dbregs=%lu\n", 
+	p += sprintf(p, "proc_sessions    : %lu\n"
+			"sys_sessions     : %lu\n"
+			"sys_use_dbregs   : %lu\n"
+			"ptrace_use_dbregs: %lu\n", 
 			pfm_sessions.pfs_task_sessions, 
 			pfm_sessions.pfs_sys_sessions,
 			pfm_sessions.pfs_sys_use_dbregs,
@@ -2837,12 +3041,28 @@
 
 	for(i=0; i < NR_CPUS; i++) {
 		if (cpu_is_online(i)) {
-			p += sprintf(p, "CPU%d.pmu_owner: %-6d\n",
+			p += sprintf(p, "CPU%d owner : %-6d\n",
 					i, 
 					pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1);
 		}
 	}
 
+	for(i=0; pmd_desc[i].type != PFM_REG_NONE; i++) {
+		p += sprintf(p, "PMD%-2d: %d 0x%lx 0x%lx\n", 
+				i,
+				pmd_desc[i].type, 
+				pmd_desc[i].dep_pmd[0], 
+				pmd_desc[i].dep_pmc[0]); 
+	}
+
+	for(i=0; pmc_desc[i].type != PFM_REG_NONE; i++) {
+		p += sprintf(p, "PMC%-2d: %d 0x%lx 0x%lx\n", 
+				i, 
+				pmc_desc[i].type, 
+				pmc_desc[i].dep_pmd[0], 
+				pmc_desc[i].dep_pmc[0]); 
+	}
+
 	return p - page;
 }
 
@@ -2901,6 +3121,7 @@
 	 * It will be restored from ipsr when going back to user level
 	 */
 	__asm__ __volatile__ ("rum psr.up;;"::: "memory");
+	ia64_srlz_i();
 
 	ctx->ctx_saved_psr = psr;
 
@@ -2956,13 +3177,9 @@
 	for (i=0; mask; i++, mask>>=1) {
 		if (mask & 0x1) t->pmd[i] =ia64_get_pmd(i);
 	}
-	/*
-	 * XXX: simplify to pmc0 only
-	 */
-	mask = ctx->ctx_saved_pmcs[0];
-	for (i=0; mask; i++, mask>>=1) {
-		if (mask & 0x1) t->pmc[i] = ia64_get_pmc(i);
-	}
+
+	/* save pmc0 */
+	t->pmc[0] = ia64_get_pmc(0);
 
 	/* not owned by this CPU */
 	atomic_set(&ctx->ctx_last_cpu, -1);
@@ -3000,6 +3217,12 @@
 		  PMU_OWNER() ? PMU_OWNER()->pid: -1,
 		  atomic_read(&ctx->ctx_saving_in_progress)));
 
+	/* must wait until not busy before retrying whole request */
+	if (atomic_read(&ctx->ctx_is_busy)) {
+		arg->retval = 2;
+		return;
+	}
+
 	/* must wait if saving was interrupted */
 	if (atomic_read(&ctx->ctx_saving_in_progress)) {
 		arg->retval = 1;
@@ -3012,9 +3235,9 @@
 		return;
 	}
 
-	DBprintk(("saving state for [%d] save_pmcs=0x%lx all_pmcs=0x%lx used_pmds=0x%lx\n", 
+	DBprintk(("saving state for [%d] used_pmcs=0x%lx reload_pmcs=0x%lx used_pmds=0x%lx\n", 
 		arg->task->pid,
-		ctx->ctx_saved_pmcs[0],
+		ctx->ctx_used_pmcs[0],
 		ctx->ctx_reload_pmcs[0],
 		ctx->ctx_used_pmds[0]));
 
@@ -3027,17 +3250,15 @@
 
 	/*
 	 * XXX needs further optimization.
-	 * Also must take holes into account
 	 */
 	mask = ctx->ctx_used_pmds[0];
 	for (i=0; mask; i++, mask>>=1) {
-		if (mask & 0x1) t->pmd[i] =ia64_get_pmd(i);
-	}
-	
-	mask = ctx->ctx_saved_pmcs[0];
-	for (i=0; mask; i++, mask>>=1) {
-		if (mask & 0x1) t->pmc[i] = ia64_get_pmc(i);
+		if (mask & 0x1) t->pmd[i] = ia64_get_pmd(i);
 	}
+
+	/* save pmc0 */
+	t->pmc[0] = ia64_get_pmc(0);
+
 	/* not owned by this CPU */
 	atomic_set(&ctx->ctx_last_cpu, -1);
 
@@ -3066,11 +3287,17 @@
 	arg.task   = task;
 	arg.retval = -1;
 
+	if (atomic_read(&ctx->ctx_is_busy)) {
+must_wait_busy:
+		while (atomic_read(&ctx->ctx_is_busy));
+	}
+
 	if (atomic_read(&ctx->ctx_saving_in_progress)) {
 		DBprintk(("no IPI, must wait for [%d] to be saved on [%d]\n", task->pid, cpu));
-
+must_wait_saving:
 		/* busy wait */
 		while (atomic_read(&ctx->ctx_saving_in_progress));
+		DBprintk(("done saving for [%d] on [%d]\n", task->pid, cpu));
 		return;
 	}
 	DBprintk(("calling CPU %d from CPU %d\n", cpu, smp_processor_id()));
@@ -3090,11 +3317,8 @@
 	 * This is the case, where we interrupted the saving which started just at the time we sent the
 	 * IPI.
 	 */
-	if (arg.retval == 1) {
-		DBprintk(("must wait for [%d] to be saved on [%d]\n", task->pid, cpu));
-		while (atomic_read(&ctx->ctx_saving_in_progress));
-		DBprintk(("done saving for [%d] on [%d]\n", task->pid, cpu));
-	}
+	if (arg.retval == 1) goto must_wait_saving;
+	if (arg.retval == 2) goto must_wait_busy;
 }
 #endif /* CONFIG_SMP */
 
@@ -3113,6 +3337,30 @@
 
 	owner = PMU_OWNER();
 	ctx   = task->thread.pfm_context;
+	t     = &task->thread;
+
+	/*
+	 * we restore ALL the debug registers to avoid picking up 
+	 * stale state.
+	 *
+	 * This must be done even when the task is still the owner
+	 * as the registers may have been modified via ptrace()
+	 * (not perfmon) by the previous task. 
+	 *
+	 * XXX: dealing with this in a lazy fashion requires modifications
+	 * to the way the the debug registers are managed. This is will done
+	 * in the next version of perfmon.
+	 */
+	if (ctx->ctx_fl_using_dbreg) {
+		for (i=0; i < pmu_conf.num_ibrs; i++) {
+			ia64_set_ibr(i, t->ibr[i]);
+		}
+		ia64_srlz_i();
+		for (i=0; i < pmu_conf.num_dbrs; i++) {
+			ia64_set_dbr(i, t->dbr[i]);
+		}
+		ia64_srlz_d();
+	}
 
 	/*
 	 * if we were the last user, then nothing to do except restore psr
@@ -3148,55 +3396,37 @@
 		pfm_fetch_regs(cpu, task, ctx);
 	}
 #endif
-	t   = &task->thread;
 
 	/*
-	 * XXX: will be replaced by assembly routine
-	 * We clear all unused PMDs to avoid leaking information
+	 * To avoid leaking information to the user level when psr.sp=0,
+	 * we must reload ALL implemented pmds (even the ones we don't use).
+	 * In the kernel we only allow PFM_READ_PMDS on registers which
+	 * we initialized or requested (sampling) so there is no risk there.
+	 *
+	 * As an optimization, we will only reload the PMD that we use when 
+	 * the context is in protected mode, i.e. psr.sp=1 because then there
+	 * is no leak possible.
 	 */
-	mask = ctx->ctx_used_pmds[0];
+	mask = pfm_sysctl.fastctxsw || ctx->ctx_fl_protected ?  ctx->ctx_used_pmds[0] : ctx->ctx_reload_pmds[0];
 	for (i=0; mask; i++, mask>>=1) {
-		if (mask & 0x1) 
-			ia64_set_pmd(i, t->pmd[i]);
-		else
-			ia64_set_pmd(i, 0UL);
+		if (mask & 0x1) ia64_set_pmd(i, t->pmd[i] & pmu_conf.perf_ovfl_val);
 	}
-	/* XXX: will need to clear all unused pmd, for security */
 
 	/* 
-	 * skip pmc[0] to avoid side-effects, 
-	 * all PMCs are systematically reloaded, unsued get default value
-	 * to avoid picking up stale configuration
+	 * PMC0 is never set in the mask because it is always restored
+	 * separately.  
+	 *
+	 * ALL PMCs are systematically reloaded, unused registers
+	 * get their default (PAL reset) values to avoid picking up 
+	 * stale configuration.
 	 */	
-	mask = ctx->ctx_reload_pmcs[0]>>1;
-	for (i=1; mask; i++, mask>>=1) {
-		if (mask & 0x1) ia64_set_pmc(i, t->pmc[i]);
-	}
-
-	/*
-	 * restore debug registers when used for range restrictions.
-	 * We must restore the unused registers to avoid picking up
-	 * stale information.
-	 */
-	mask = ctx->ctx_used_ibrs[0];
+	mask = ctx->ctx_reload_pmcs[0];
 	for (i=0; mask; i++, mask>>=1) {
-		if (mask & 0x1) 
-			ia64_set_ibr(i, t->ibr[i]);
-		else
-			ia64_set_ibr(i, 0UL);
-	}
-
-	mask = ctx->ctx_used_dbrs[0];
-	for (i=0; mask; i++, mask>>=1) {
-		if (mask & 0x1) 
-			ia64_set_dbr(i, t->dbr[i]);
-		else
-			ia64_set_dbr(i, 0UL);
+		if (mask & 0x1) ia64_set_pmc(i, t->pmc[i]);
 	}
 
 	if (t->pmc[0] & ~0x1) {
-		ia64_srlz_d();
-		pfm_overflow_handler(task, t->pmc[0], NULL);
+		pfm_overflow_handler(task, ctx, t->pmc[0], NULL);
 	}
 
 	/*
@@ -3249,7 +3479,7 @@
 			 * When restoring context, we must restore ALL pmcs, even the ones 
 			 * that the task does not use to avoid leaks and possibly corruption
 			 * of the sesion because of configuration conflicts. So here, we 
-			 * initializaed the table used in the context switch restore routine.
+			 * initialize the entire set used in the context switch restore routine.
 	 		 */
 			t->pmc[i] = reset_pmcs[i];
 			DBprintk((" pmc[%d]=0x%lx\n", i, reset_pmcs[i]));
@@ -3258,39 +3488,61 @@
 	}
 	/*
 	 * clear reset values for PMD. 
-	 * XX: good up to 64 PMDS. Suppose that zero is a valid value.
+	 * XXX: good up to 64 PMDS. Suppose that zero is a valid value.
 	 */
 	mask = pmu_conf.impl_regs[4];
 	for(i=0; mask; mask>>=1, i++) {
 		if (mask & 0x1) ia64_set_pmd(i, 0UL);
+		t->pmd[i] = 0UL;
 	}
 
 	/*
-	 * On context switched restore, we must restore ALL pmc even
+	 * On context switched restore, we must restore ALL pmc and ALL pmd even
 	 * when they are not actively used by the task. In UP, the incoming process 
-	 * may otherwise pick up left over PMC state from the previous process.
+	 * may otherwise pick up left over PMC, PMD state from the previous process.
 	 * As opposed to PMD, stale PMC can cause harm to the incoming
 	 * process because they may change what is being measured. 
 	 * Therefore, we must systematically reinstall the entire
 	 * PMC state. In SMP, the same thing is possible on the 
-	 * same CPU but also on between 2 CPUs.
+	 * same CPU but also on between 2 CPUs. 
+	 *
+	 * The problem with PMD is information leaking especially
+	 * to user level when psr.sp=0
 	 *
 	 * There is unfortunately no easy way to avoid this problem
-	 * on either UP or SMP. This definitively slows down the 
-	 * pfm_load_regs(). 
+	 * on either UP or SMP. This definitively slows down the
+	 * pfm_load_regs() function. 
 	 */
 	
 	 /*
 	  * We must include all the PMC in this mask to make sure we don't
-	  * see any side effect of the stale state, such as opcode matching
+	  * see any side effect of a stale state, such as opcode matching
 	  * or range restrictions, for instance.
+	  *
+	  * We never directly restore PMC0 so we do not include it in the mask.
 	  */
-	ctx->ctx_reload_pmcs[0] = pmu_conf.impl_regs[0];
+	ctx->ctx_reload_pmcs[0] = pmu_conf.impl_regs[0] & ~0x1;
+	/*
+	 * We must include all the PMD in this mask to avoid picking
+	 * up stale value and leak information, especially directly
+	 * at the user level when psr.sp=0
+	 */
+	ctx->ctx_reload_pmds[0] = pmu_conf.impl_regs[4];
+
+	/* 
+	 * Keep track of the pmds we want to sample
+	 * XXX: may be we don't need to save/restore the DEAR/IEAR pmds
+	 * but we do need the BTB for sure. This is because of a hardware
+	 * buffer of 1 only for non-BTB pmds.
+	 *
+	 * We ignore the unimplemented pmds specified by the user
+	 */
+	ctx->ctx_used_pmds[0] = ctx->ctx_smpl_regs[0] & pmu_conf.impl_regs[4];
+	ctx->ctx_used_pmcs[0] = 1; /* always save/restore PMC[0] */
 
 	/*
 	 * useful in case of re-enable after disable
 	 */
-	ctx->ctx_used_pmds[0] = 0UL;
 	ctx->ctx_used_ibrs[0] = 0UL;
 	ctx->ctx_used_dbrs[0] = 0UL;
 
@@ -3312,7 +3564,7 @@
 {
 	pfm_context_t *ctx;
 	u64 pmc0;
-	unsigned long mask, mask2, val;
+	unsigned long mask2, val;
 	int i;
 
 	ctx = task->thread.pfm_context;
@@ -3334,22 +3586,28 @@
 	 */
 	if (ctx->ctx_fl_system) {
 
-		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
 
 		/* disable dcr pp */
 		ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP);
 
+		/* stop monitoring */
+		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
+
+		ia64_srlz_i();
+
 #ifdef CONFIG_SMP
 		local_cpu_data->pfm_syst_wide = 0;
 		local_cpu_data->pfm_dcr_pp    = 0;
 #else
 		pfm_tasklist_toggle_pp(0);
 #endif
-
 	} else  {
 
+		/* stop monitoring */
 		__asm__ __volatile__ ("rum psr.up;;"::: "memory");
 
+		ia64_srlz_i();
+
 		/* no more save/restore on ctxsw */
 		current->thread.flags &= ~IA64_THREAD_PM_VALID;
 	}
@@ -3383,7 +3641,7 @@
 	ia64_srlz_d();
 
 	/*
-	 * We don't need to restore psr, because we are on our way out anyway
+	 * We don't need to restore psr, because we are on our way out
 	 */
 
 	/*
@@ -3399,10 +3657,12 @@
 	if (atomic_read(&ctx->ctx_last_cpu) != smp_processor_id()) 
 		printk("perfmon: [%d] last_cpu=%d\n", task->pid, atomic_read(&ctx->ctx_last_cpu));
 
-	mask  = pmc0 >> PMU_FIRST_COUNTER;
-	mask2 = ctx->ctx_used_pmds[0] >> PMU_FIRST_COUNTER;
-
-	for (i = PMU_FIRST_COUNTER; mask2; i++, mask>>=1, mask2>>=1) {
+	/*
+	 * we save all the used pmds
+	 * we take care of overflows for pmds used as counters
+	 */
+	mask2 = ctx->ctx_used_pmds[0];
+	for (i = 0; mask2; i++, mask2>>=1) {
 
 		/* skip non used pmds */
 		if ((mask2 & 0x1) == 0) continue;
@@ -3410,7 +3670,6 @@
 		val = ia64_get_pmd(i);
 
 		if (PMD_IS_COUNTING(i)) {
-
 			DBprintk(("[%d] pmd[%d] soft_pmd=0x%lx hw_pmd=0x%lx\n", task->pid, i, ctx->ctx_soft_pmds[i].val, val & pmu_conf.perf_ovfl_val));
 
 			/* collect latest results */
@@ -3423,15 +3682,19 @@
 			 */
 			task->thread.pmd[i] = 0;
 
-			/* take care of overflow inline */
-			if (mask & 0x1) {
+			/* 
+			 * take care of overflow inline
+			 */
+			if (pmc0 & (1UL << i)) {
 				ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.perf_ovfl_val;
 				DBprintk(("[%d] pmd[%d] overflowed soft_pmd=0x%lx\n",
 					task->pid, i, ctx->ctx_soft_pmds[i].val));
 			}
 		} else {
 			DBprintk(("[%d] pmd[%d] hw_pmd=0x%lx\n", task->pid, i, val));
-			/* not a counter, just save value as is */
+			/* 
+			 * not a counter, just save value as is
+			 */
 			task->thread.pmd[i] = val;
 		}
 	}
@@ -3449,31 +3712,73 @@
 int
 pfm_inherit(struct task_struct *task, struct pt_regs *regs)
 {
-	pfm_context_t *ctx = current->thread.pfm_context;
+	pfm_context_t *ctx;
 	pfm_context_t *nctx;
-	struct thread_struct *th = &task->thread;
+	struct thread_struct *thread;
 	unsigned long m;
 	int i;
 
 	/*
+	 * the new task was copied from parent and therefore points
+	 * to the parent's context at this point
+	 */
+	ctx    = task->thread.pfm_context;
+	thread = &task->thread;
+
+	/*
 	 * make sure child cannot mess up the monitoring session
 	 */
 	 ia64_psr(regs)->sp = 1;
 	 DBprintk(("enabling psr.sp for [%d]\n", task->pid));
 
-	 /*
-	  * remove any sampling buffer mapping from child user 
-	  * address space. Must be done for all cases of inheritance.
-	  */
-	 if (ctx->ctx_smpl_vaddr) pfm_remove_smpl_mapping(task);
+
+	/*
+	 * if there was a virtual mapping for the sampling buffer
+	 * the mapping is NOT inherited across fork() (see VM_DONTCOPY), 
+	 * so we don't have to explicitely remove it here. 
+	 *
+	 *
+	 * Part of the clearing of fields is also done in
+	 * copy_thread() because the fiels are outside the
+	 * pfm_context structure and can affect tasks not
+	 * using perfmon.
+	 */
+
+	/* clear pending notification */
+	task->thread.pfm_ovfl_block_reset = 0;
+
+	/*
+	 * clear cpu pinning restriction for child
+	 */
+	if (ctx->ctx_fl_system) {
+		task->cpus_allowed = ctx->ctx_saved_cpus_allowed;
+		task->need_resched = 1;
+
+	 	DBprintk(("setting cpus_allowed for [%d] to 0x%lx from 0x%lx\n", 
+			task->pid,
+			ctx->ctx_saved_cpus_allowed, 
+			current->cpus_allowed));
+	}
 
 	/*
 	 * takes care of easiest case first
 	 */
 	if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_NONE) {
+
 		DBprintk(("removing PFM context for [%d]\n", task->pid));
-		task->thread.pfm_context     = NULL;
-		task->thread.pfm_ovfl_block_reset  = 0;
+
+		task->thread.pfm_context = NULL;
+
+		/* 
+		 * we must clear psr.up because the new child does
+		 * not have a context and the PM_VALID flag is cleared
+		 * in copy_thread().
+		 *
+		 * we do not clear psr.pp because it is always
+		 * controlled by the system wide logic and we should
+		 * never be here when system wide is running anyway
+		 */
+	 	ia64_psr(regs)->up = 0;
 
 		/* copy_thread() clears IA64_THREAD_PM_VALID */
 		return 0;
@@ -3487,69 +3792,82 @@
 
 	if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_ONCE) {
 		nctx->ctx_fl_inherit = PFM_FL_INHERIT_NONE;
-		atomic_set(&nctx->ctx_last_cpu, -1);
-
-		/*
-		 * task is not yet visible in the tasklist, so we do 
-		 * not need to lock the newly created context.
-		 * However, we must grab the tasklist_lock to ensure
-		 * that the ctx_owner or ctx_notify_task do not disappear
-		 * while we increment their check counters.
-		 */
-		read_lock(&tasklist_lock);
+		DBprintk(("downgrading to INHERIT_NONE for [%d]\n", task->pid));
+	}
+	/*
+	 * task is not yet visible in the tasklist, so we do 
+	 * not need to lock the newly created context.
+	 * However, we must grab the tasklist_lock to ensure
+	 * that the ctx_owner or ctx_notify_task do not disappear
+	 * while we increment their check counters.
+	 */
+	read_lock(&tasklist_lock);
 
-		if (nctx->ctx_notify_task) 
-			atomic_inc(&nctx->ctx_notify_task->thread.pfm_notifiers_check);
+	if (nctx->ctx_notify_task) 
+		atomic_inc(&nctx->ctx_notify_task->thread.pfm_notifiers_check);
 
-		if (nctx->ctx_owner)
-			atomic_inc(&nctx->ctx_owner->thread.pfm_owners_check);
+	if (nctx->ctx_owner)
+		atomic_inc(&nctx->ctx_owner->thread.pfm_owners_check);
 
-		read_unlock(&tasklist_lock);
+	read_unlock(&tasklist_lock);
 
-		DBprintk(("downgrading to INHERIT_NONE for [%d]\n", task->pid));
 
-		LOCK_PFS();
-		pfm_sessions.pfs_task_sessions++;
-		UNLOCK_PFS();
-	}
+	LOCK_PFS();
+	pfm_sessions.pfs_task_sessions++;
+	UNLOCK_PFS();
 
 	/* initialize counters in new context */
-	m = pmu_conf.counter_pmds[0] >> PMU_FIRST_COUNTER;
+	m = nctx->ctx_used_pmds[0] >> PMU_FIRST_COUNTER;
 	for(i = PMU_FIRST_COUNTER ; m ; m>>=1, i++) {
-		if (m & 0x1) {
+		if ((m & 0x1) && pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING) {
 			nctx->ctx_soft_pmds[i].val = nctx->ctx_soft_pmds[i].ival & ~pmu_conf.perf_ovfl_val;
-			th->pmd[i]	      	   = nctx->ctx_soft_pmds[i].ival & pmu_conf.perf_ovfl_val;
+			thread->pmd[i]	      	   = nctx->ctx_soft_pmds[i].ival & pmu_conf.perf_ovfl_val;
 		}
+		/* what about the other pmds? zero or keep as is */
 
 	}
-	/* clear BTB index register */
-	th->pmd[16] = 0;
+	/*
+	 * clear BTB index register
+	 * XXX: CPU-model specific knowledge!
+	 */
+	thread->pmd[16] = 0;
 
-	/* if sampling then increment number of users of buffer */
-	if (nctx->ctx_psb) {
 
-		/*
-		 * XXX: nopt very pretty!
-		 */
+	nctx->ctx_fl_frozen    = 0;
+	nctx->ctx_ovfl_regs[0] = 0UL;
+	atomic_set(&nctx->ctx_last_cpu, -1);
+
+	/*
+	 * here nctx->ctx_psb == ctx->ctx_psb
+	 *
+	 * increment reference count to sampling
+	 * buffer, if any. Note that this is independent
+	 * from the virtual mapping. The latter is never
+	 * inherited while the former will be if context
+	 * is setup to something different from PFM_FL_INHERIT_NONE
+	 */
+	if (nctx->ctx_psb) {
 		LOCK_PSB(nctx->ctx_psb);
+
 		nctx->ctx_psb->psb_refcnt++;
+
+	 	DBprintk(("updated smpl @ %p refcnt=%lu psb_flags=0x%x\n", 
+			ctx->ctx_psb->psb_hdr,
+			ctx->ctx_psb->psb_refcnt,
+			ctx->ctx_psb->psb_flags));
+
 		UNLOCK_PSB(nctx->ctx_psb);
+
 		/*
 	 	 * remove any pointer to sampling buffer mapping
 	 	 */
 		nctx->ctx_smpl_vaddr = 0;
 	}
 
-	nctx->ctx_fl_frozen = 0;
-	nctx->ctx_ovfl_regs[0] = 0UL;
-
 	sema_init(&nctx->ctx_restart_sem, 0); /* reset this semaphore to locked */
 
-	/* clear pending notification */
-	th->pfm_ovfl_block_reset = 0;
-
 	/* link with new task */
-	th->pfm_context    = nctx;
+	thread->pfm_context = nctx;
 
 	DBprintk(("nctx=%p for process [%d]\n", (void *)nctx, task->pid));
 
@@ -3559,7 +3877,7 @@
 	 */
 	if (current->thread.flags & IA64_THREAD_PM_VALID) {
 		DBprintk(("setting PM_VALID for [%d]\n", task->pid));
-		th->flags |= IA64_THREAD_PM_VALID;
+		thread->flags |= IA64_THREAD_PM_VALID;
 	}
 
 	return 0;
@@ -3588,9 +3906,9 @@
 
 		LOCK_PSB(psb);
 
-		DBprintk(("sampling buffer from [%d] @%p size %ld vma_flag=0x%x\n",
+		DBprintk(("sampling buffer from [%d] @%p size %ld refcnt=%lu psb_flags=0x%x\n",
 			task->pid,
-			psb->psb_hdr, psb->psb_size, psb->psb_flags));
+			psb->psb_hdr, psb->psb_size, psb->psb_refcnt, psb->psb_flags));
 
 		/*
 		 * in the case where we are the last user, we may be able to free
@@ -3613,7 +3931,7 @@
 			 *
 			 * See pfm_vm_close() and pfm_cleanup_smpl_buf() for more details.
 			 */
-			if ((psb->psb_flags & PFM_PSB_VMA) == 0) {
+			if ((psb->psb_flags & PSB_HAS_VMA) == 0) {
 
 				DBprintk(("cleaning sampling buffer from [%d] @%p size %ld\n",
 					task->pid,
@@ -3645,7 +3963,7 @@
 	 * direct pointer to a task structure thereby bypassing the tasklist. 
 	 * We must make sure that, if we have task!= NULL, the target task is still 
 	 * present and is identical to the initial task specified 
-	 * during pfm_create_context(). It may already be detached from the tasklist but 
+	 * during pfm_context_create(). It may already be detached from the tasklist but 
 	 * that's okay. Note that it is okay if we miss the deadline and the task scans 
 	 * the list for nothing, it will affect performance but not correctness. 
 	 * The correctness is ensured by using the ctx_lock which prevents the 
@@ -3683,7 +4001,8 @@
 		pfm_sessions.pfs_sys_session[ctx->ctx_cpu] = NULL;
 		pfm_sessions.pfs_sys_sessions--;
 		DBprintk(("freeing syswide session on CPU%ld\n", ctx->ctx_cpu));
-		/* update perfmon debug register counter */
+
+		/* update perfmon debug register usage counter */
 		if (ctx->ctx_fl_using_dbreg) {
 			if (pfm_sessions.pfs_sys_use_dbregs == 0) {
 				printk("perfmon: invalid release for [%d] sys_use_dbregs=0\n", task->pid);
@@ -3795,6 +4114,8 @@
 		}
 	}
 	read_unlock(&tasklist_lock);
+
+	atomic_set(&task->thread.pfm_owners_check, 0);
 }
 
 
@@ -3852,6 +4173,8 @@
 		}
 	}
 	read_unlock(&tasklist_lock);
+
+	atomic_set(&task->thread.pfm_notifiers_check, 0);
 }
 
 static struct irqaction perfmon_irqaction = {
@@ -3870,6 +4193,12 @@
 		if (i >= pmu_conf.num_pmcs) break;
 		if (PMC_IS_IMPL(i)) reset_pmcs[i] = ia64_get_pmc(i);
 	}
+#ifdef CONFIG_MCKINLEY
+	/*
+	 * set the 'stupid' enable bit to power the PMU!
+	 */
+	reset_pmcs[4] |= 1UL << 23;
+#endif
 }
 
 /*
@@ -3881,11 +4210,6 @@
 	pal_perf_mon_info_u_t pm_info;
 	s64 status;
 
-	register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction);
-
-	ia64_set_pmv(IA64_PERFMON_VECTOR);
-	ia64_srlz_d();
-
 	pmu_conf.pfm_is_disabled = 1;
 
 	printk("perfmon: version %u.%u (sampling format v%u.%u) IRQ %u\n", 
@@ -3937,23 +4261,12 @@
 	 */
 	pfm_pmu_snapshot();
 
-	/* 
-	 * list the pmc registers used to control monitors 
-	 * XXX: unfortunately this information is not provided by PAL
-	 *
-	 * We start with the architected minimum and then refine for each CPU model
-	 */
-	pmu_conf.monitor_pmcs[0] = PMM(4)|PMM(5)|PMM(6)|PMM(7);
-
 	/*
-	 * architected counters
+	 * setup the register configuration descriptions for the CPU
 	 */
-	pmu_conf.counter_pmds[0] |= PMM(4)|PMM(5)|PMM(6)|PMM(7);
+	pmu_conf.pmc_desc = pmc_desc;
+	pmu_conf.pmd_desc = pmd_desc;
 
-#ifdef CONFIG_ITANIUM
-	pmu_conf.monitor_pmcs[0] |= PMM(10)|PMM(11)|PMM(12);
-	/* Itanium does not add more counters */
-#endif
 	/* we are all set */
 	pmu_conf.pfm_is_disabled = 0;
 
@@ -3962,6 +4275,8 @@
 	 */
 	perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL);
 
+	pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0);
+
 	spin_lock_init(&pfm_sessions.pfs_lock);
 
 	return 0;
@@ -3972,11 +4287,13 @@
 void
 perfmon_init_percpu (void)
 {
+	if (smp_processor_id() == 0)
+		register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction);
+
 	ia64_set_pmv(IA64_PERFMON_VECTOR);
 	ia64_srlz_d();
 }
 
-
 #else /* !CONFIG_PERFMON */
 
 asmlinkage int
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/perfmon_generic.h linux-2.4.20/arch/ia64/kernel/perfmon_generic.h
--- linux-2.4.19/arch/ia64/kernel/perfmon_generic.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/perfmon_generic.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,29 @@
+#define RDEP(x)	(1UL<<(x))
+
+#ifdef CONFIG_ITANIUM
+#error "This file should not be used when CONFIG_ITANIUM is defined"
+#endif
+
+static pfm_reg_desc_t pmc_desc[256]={
+/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+};
+
+static pfm_reg_desc_t pmd_desc[256]={
+/* pmd0  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
+/* pmd1  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
+/* pmd2  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
+/* pmd3  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/perfmon_itanium.h linux-2.4.20/arch/ia64/kernel/perfmon_itanium.h
--- linux-2.4.19/arch/ia64/kernel/perfmon_itanium.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/perfmon_itanium.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,99 @@
+/*
+ * This file contains the Itanium PMU register description tables
+ * and pmc checker used by perfmon.c.
+ *
+ * Copyright (C) 2002  Hewlett Packard Co
+ *               Stephane Eranian <eranian@hpl.hp.com>
+ */
+
+#define RDEP(x)	(1UL<<(x))
+
+#ifndef CONFIG_ITANIUM
+#error "This file is only valid when CONFIG_ITANIUM is defined"
+#endif
+
+static int pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
+static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs);
+
+static pfm_reg_desc_t pmc_desc[256]={
+/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc8  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc9  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc10 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc11 */ { PFM_REG_MONITOR, 6, NULL, pfm_ita_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc12 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc13 */ { PFM_REG_CONFIG, 0, NULL, pfm_ita_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+};
+
+static pfm_reg_desc_t pmd_desc[256]={
+/* pmd0  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd1  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd2  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd3  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+/* pmd8  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd9  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd10 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd11 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd12 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd13 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd14 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd15 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd16 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd17 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+};
+
+static int
+pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
+{
+	pfm_context_t *ctx = task->thread.pfm_context;
+	int ret;
+
+	/*
+	 * we must clear the (instruction) debug registers if pmc13.ta bit is cleared
+	 * before they are written (fl_using_dbreg==0) to avoid picking up stale information. 
+	 */
+	if (cnum == 13 && ((*val & 0x1) == 0UL) && ctx->ctx_fl_using_dbreg == 0) {
+
+		/* don't mix debug with perfmon */
+		if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
+
+		/* 
+		 * a count of 0 will mark the debug registers as in use and also
+		 * ensure that they are properly cleared.
+		 */
+		ret = pfm_write_ibr_dbr(1, task, NULL, 0, regs);
+		if (ret) return ret;
+	}
+
+	/*
+	 * we must clear the (data) debug registers if pmc11.pt bit is cleared
+	 * before they are written (fl_using_dbreg==0) to avoid picking up stale information. 
+	 */
+	if (cnum == 11 && ((*val >> 28)& 0x1) == 0 && ctx->ctx_fl_using_dbreg == 0) {
+
+		/* don't mix debug with perfmon */
+		if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
+
+		/* 
+		 * a count of 0 will mark the debug registers as in use and also
+		 * ensure that they are properly cleared.
+		 */
+		ret = pfm_write_ibr_dbr(0, task, NULL, 0, regs);
+		if (ret) return ret;
+	}
+	return 0;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/perfmon_mckinley.h linux-2.4.20/arch/ia64/kernel/perfmon_mckinley.h
--- linux-2.4.19/arch/ia64/kernel/perfmon_mckinley.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/perfmon_mckinley.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,134 @@
+/*
+ * This file contains the McKinley PMU register description tables
+ * and pmc checker used by perfmon.c.
+ *
+ * Copyright (C) 2002  Hewlett Packard Co
+ *               Stephane Eranian <eranian@hpl.hp.com>
+ */
+
+#define RDEP(x)	(1UL<<(x))
+
+#ifndef CONFIG_MCKINLEY
+#error "This file is only valid when CONFIG_MCKINLEY is defined"
+#endif
+
+static int pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
+static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs);
+
+static pfm_reg_desc_t pmc_desc[256]={
+/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 6, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc8  */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc9  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc10 */ { PFM_REG_MONITOR, 4, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc11 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc12 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc13 */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc14 */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc15 */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+};
+
+static pfm_reg_desc_t pmd_desc[256]={
+/* pmd0  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd1  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd2  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd3  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+/* pmd8  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd9  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd10 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd11 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd12 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd13 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd14 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd15 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd16 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd17 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+};
+
+static int
+pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
+{
+	struct thread_struct *th = &task->thread;
+	pfm_context_t *ctx = task->thread.pfm_context;
+	int ret = 0, check_case1 = 0;
+	unsigned long val8 = 0, val14 = 0, val13 = 0;
+
+	/*
+	 * we must clear the debug registers if any pmc13.ena_dbrpX bit is enabled 
+	 * before they are written (fl_using_dbreg==0) to avoid picking up stale information. 
+	 */
+	if (cnum == 13 && (*val & (0xfUL << 45)) && ctx->ctx_fl_using_dbreg == 0) {
+
+		/* don't mix debug with perfmon */
+		if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
+
+		/* 
+		 * a count of 0 will mark the debug registers as in use and also
+		 * ensure that they are properly cleared.
+		 */
+		ret = pfm_write_ibr_dbr(1, task, NULL, 0, regs);
+		if (ret) return ret;
+	}
+	/* 
+	 * we must clear the (instruction) debug registers if any pmc14.ibrpX bit is enabled 
+	 * before they are (fl_using_dbreg==0) to avoid picking up stale information. 
+	 */
+	if (cnum == 14 && ((*val & 0x2222) != 0x2222) && ctx->ctx_fl_using_dbreg == 0) {
+
+		/* don't mix debug with perfmon */
+		if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
+
+		/* 
+		 * a count of 0 will mark the debug registers as in use and also
+		 * ensure that they are properly cleared.
+		 */
+		ret = pfm_write_ibr_dbr(0, task, NULL, 0, regs);
+		if (ret) return ret;
+
+	}
+
+	switch(cnum) {
+		case  4: *val |= 1UL << 23; /* force power enable bit */
+			 break;
+		case  8: val8 = *val;
+			 val13 = th->pmc[13];
+			 val14 = th->pmc[14];
+			 check_case1 = 1;
+			 break;
+		case 13: val8  = th->pmc[8];
+			 val13 = *val;
+			 val14 = th->pmc[14];
+			 check_case1 = 1;
+			 break;
+		case 14: val8  = th->pmc[13];
+			 val13 = th->pmc[13];
+			 val14 = *val;
+			 check_case1 = 1;
+			 break;
+	}
+	/* check illegal configuration which can produce inconsistencies in tagging
+	 * i-side events in L1D and L2 caches
+	 */
+	if (check_case1) {
+		ret =   ((val13 >> 45) & 0xf) == 0 
+		   && ((val8 & 0x1) == 0)
+		   && ((((val14>>1) & 0x3) == 0x2 || ((val14>>1) & 0x3) == 0x0)
+		       ||(((val14>>4) & 0x3) == 0x2 || ((val14>>4) & 0x3) == 0x0));
+
+		if (ret) printk("perfmon: failure check_case1\n");
+	}
+
+	return ret ? -EINVAL : 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/process.c linux-2.4.20/arch/ia64/kernel/process.c
--- linux-2.4.19/arch/ia64/kernel/process.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/process.c	2002-10-29 11:18:40.000000000 +0000
@@ -18,9 +18,9 @@
 #include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
+#include <linux/efi.h>
 
 #include <asm/delay.h>
-#include <asm/efi.h>
 #include <asm/perfmon.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
@@ -174,8 +174,10 @@
 # endif
 #endif
 
+#ifdef CONFIG_IA32_SUPPORT
 	if (IS_IA32_PROCESS(ia64_task_regs(task)))
 		ia32_save_state(task);
+#endif
 }
 
 void
@@ -194,8 +196,10 @@
 # endif
 #endif
 
+#ifdef CONFIG_IA32_SUPPORT
 	if (IS_IA32_PROCESS(ia64_task_regs(task)))
 		ia32_load_state(task);
+#endif
 }
 
 /*
@@ -297,21 +301,24 @@
 
 	/* copy parts of thread_struct: */
 	p->thread.ksp = (unsigned long) child_stack - 16;
+
+	/* stop some PSR bits from being inherited: */
+	child_ptregs->cr_ipsr =  ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
+				  & ~IA64_PSR_BITS_TO_CLEAR);
+
 	/*
-	 * NOTE: The calling convention considers all floating point
-	 * registers in the high partition (fph) to be scratch.  Since
-	 * the only way to get to this point is through a system call,
-	 * we know that the values in fph are all dead.  Hence, there
-	 * is no need to inherit the fph state from the parent to the
-	 * child and all we have to do is to make sure that
-	 * IA64_THREAD_FPH_VALID is cleared in the child.
+	 * NOTE: The calling convention considers all floating point registers in the high
+	 * partition (fph) to be scratch.  Since the only way to get to this point is
+	 * through a system call, we know that the values in fph are all dead.  Hence,
+	 * there is no need to inherit the fph state from the parent to the child and all
+	 * we have to do is to make sure that IA64_THREAD_FPH_VALID is cleared in the
+	 * child.
 	 *
-	 * XXX We could push this optimization a bit further by
-	 * clearing IA64_THREAD_FPH_VALID on ANY system call.
-	 * However, it's not clear this is worth doing.  Also, it
-	 * would be a slight deviation from the normal Linux system
-	 * call behavior where scratch registers are preserved across
-	 * system calls (unless used by the system call itself).
+	 * XXX We could push this optimization a bit further by clearing
+	 * IA64_THREAD_FPH_VALID on ANY system call.  However, it's not clear this is
+	 * worth doing.  Also, it would be a slight deviation from the normal Linux system
+	 * call behavior where scratch registers are preserved across system calls (unless
+	 * used by the system call itself).
 	 */
 #	define THREAD_FLAGS_TO_CLEAR	(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID \
 					 | IA64_THREAD_PM_VALID)
@@ -333,8 +340,11 @@
 	 */
 	atomic_set(&p->thread.pfm_notifiers_check, 0);
 	atomic_set(&p->thread.pfm_owners_check, 0);
+	/* clear list of sampling buffer to free for new task */
+	p->thread.pfm_smpl_buf_list = NULL;
 
-	if (current->thread.pfm_context) retval = pfm_inherit(p, child_ptregs);
+	if (current->thread.pfm_context)
+		retval = pfm_inherit(p, child_ptregs);
 #endif
 	return retval;
 }
@@ -537,14 +547,13 @@
 		ia64_set_fpu_owner(0);
 #endif
 #ifdef CONFIG_PERFMON
-       /* if needed, stop monitoring and flush state to perfmon context */
-	if (current->thread.pfm_context) 
+       /* stop monitoring */
+	if (current->thread.pfm_context)
 		pfm_flush_regs(current);
 
 	/* free debug register resources */
-	if ((current->thread.flags & IA64_THREAD_DBG_VALID) != 0) {
+	if (current->thread.flags & IA64_THREAD_DBG_VALID)
 		pfm_release_debug_registers(current);
-	}
 #endif
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/salinfo.c linux-2.4.20/arch/ia64/kernel/salinfo.c
--- linux-2.4.19/arch/ia64/kernel/salinfo.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/salinfo.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,105 @@
+/*
+ * salinfo.c
+ *
+ * Creates entries in /proc/sal for various system features.
+ *
+ * Copyright (c) 2001 Silicon Graphics, Inc.  All rights reserved.
+ *
+ * 10/30/2001	jbarnes@sgi.com		copied much of Stephane's palinfo
+ *					code to create this file
+ */
+
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+
+#include <asm/sal.h>
+
+MODULE_AUTHOR("Jesse Barnes <jbarnes@sgi.com>");
+MODULE_DESCRIPTION("/proc interface to IA-64 SAL features");
+MODULE_LICENSE("GPL");
+
+static int salinfo_read(char *page, char **start, off_t off, int count, int *eof, void *data);
+
+typedef struct {
+	const char		*name;		/* name of the proc entry */
+	unsigned long           feature;        /* feature bit */
+	struct proc_dir_entry	*entry;		/* registered entry (removal) */
+} salinfo_entry_t;
+
+/*
+ * List {name,feature} pairs for every entry in /proc/sal/<feature>
+ * that this module exports
+ */
+static salinfo_entry_t salinfo_entries[]={
+	{ "bus_lock",           IA64_SAL_PLATFORM_FEATURE_BUS_LOCK, },
+	{ "irq_redirection",	IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT, },
+	{ "ipi_redirection",	IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT, },
+	{ "itc_drift",		IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT, },
+};
+
+#define NR_SALINFO_ENTRIES (sizeof(salinfo_entries)/sizeof(salinfo_entry_t))
+
+/*
+ * One for each feature and one more for the directory entry...
+ */
+static struct proc_dir_entry *salinfo_proc_entries[NR_SALINFO_ENTRIES + 1];
+
+static int __init
+salinfo_init(void)
+{
+	struct proc_dir_entry *salinfo_dir; /* /proc/sal dir entry */
+	struct proc_dir_entry **sdir = salinfo_proc_entries; /* keeps track of every entry */
+	int i;
+
+	salinfo_dir = proc_mkdir("sal", NULL);
+
+	for (i=0; i < NR_SALINFO_ENTRIES; i++) {
+		/* pass the feature bit in question as misc data */
+		*sdir++ = create_proc_read_entry (salinfo_entries[i].name, 0, salinfo_dir,
+						  salinfo_read, (void *)salinfo_entries[i].feature);
+	}
+	*sdir++ = salinfo_dir;
+
+	return 0;
+}
+
+static void __exit
+salinfo_exit(void)
+{
+	int i = 0;
+
+	for (i = 0; i < NR_SALINFO_ENTRIES ; i++) {
+		if (salinfo_proc_entries[i])
+			remove_proc_entry (salinfo_proc_entries[i]->name, NULL);
+	}
+}
+
+/*
+ * 'data' contains an integer that corresponds to the feature we're
+ * testing
+ */
+static int
+salinfo_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	int len = 0;
+
+	MOD_INC_USE_COUNT;
+
+	len = sprintf(page, (sal_platform_features & (unsigned long)data) ? "1\n" : "0\n");
+
+	if (len <= off+count) *eof = 1;
+
+	*start = page + off;
+	len   -= off;
+
+	if (len>count) len = count;
+	if (len<0) len = 0;
+
+	MOD_DEC_USE_COUNT;
+
+	return len;
+}
+
+module_init(salinfo_init);
+module_exit(salinfo_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/setup.c linux-2.4.20/arch/ia64/kernel/setup.c
--- linux-2.4.19/arch/ia64/kernel/setup.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/setup.c	2002-10-29 11:18:33.000000000 +0000
@@ -19,6 +19,7 @@
 #include <linux/config.h>
 #include <linux/init.h>
 
+#include <linux/acpi.h>
 #include <linux/bootmem.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
@@ -28,15 +29,15 @@
 #include <linux/string.h>
 #include <linux/threads.h>
 #include <linux/console.h>
+#include <linux/ioport.h>
+#include <linux/efi.h>
 
-#include <asm/acpi-ext.h>
 #include <asm/ia32.h>
 #include <asm/page.h>
 #include <asm/machvec.h>
 #include <asm/processor.h>
 #include <asm/sal.h>
 #include <asm/system.h>
-#include <asm/efi.h>
 #include <asm/mca.h>
 #include <asm/smp.h>
 
@@ -65,6 +66,8 @@
 
 unsigned long ia64_iobase;	/* virtual address for I/O accesses */
 
+unsigned char aux_device_present = 0xaa;        /* XXX remove this when legacy I/O is gone */
+
 #define COMMAND_LINE_SIZE	512
 
 char saved_command_line[COMMAND_LINE_SIZE]; /* used in proc filesystem */
@@ -283,6 +286,7 @@
 setup_arch (char **cmdline_p)
 {
 	extern unsigned long ia64_iobase;
+	unsigned long phys_iobase;
 
 	unw_init();
 
@@ -292,6 +296,7 @@
 
 	efi_init();
 
+	iomem_resource.end = ~0UL;	/* FIXME probably belongs elsewhere */
 	find_memory();
 
 #if 0
@@ -315,24 +320,23 @@
 #endif
 
 	/*
-	 *  Set `iobase' to the appropriate address in region 6
-	 *    (uncached access range)
+	 *  Set `iobase' to the appropriate address in region 6 (uncached access range).
 	 *
-	 *  The EFI memory map is the "prefered" location to get the I/O port
-	 *  space base, rather the relying on AR.KR0. This should become more
-	 *  clear in future SAL specs. We'll fall back to getting it out of
-	 *  AR.KR0 if no appropriate entry is found in the memory map.
+	 *  The EFI memory map is the "preferred" location to get the I/O port space base,
+	 *  rather the relying on AR.KR0. This should become more clear in future SAL
+	 *  specs. We'll fall back to getting it out of AR.KR0 if no appropriate entry is
+	 *  found in the memory map.
 	 */
-	ia64_iobase = efi_get_iobase();
-	if (ia64_iobase)
+	phys_iobase = efi_get_iobase();
+	if (phys_iobase)
 		/* set AR.KR0 since this is all we use it for anyway */
-		ia64_set_kr(IA64_KR_IO_BASE, ia64_iobase);
+		ia64_set_kr(IA64_KR_IO_BASE, phys_iobase);
 	else {
-		ia64_iobase = ia64_get_kr(IA64_KR_IO_BASE);
+		phys_iobase = ia64_get_kr(IA64_KR_IO_BASE);
 		printk("No I/O port range found in EFI memory map, falling back to AR.KR0\n");
-		printk("I/O port base = 0x%lx\n", ia64_iobase);
+		printk("I/O port base = 0x%lx\n", phys_iobase);
 	}
-	ia64_iobase = __IA64_UNCACHED_OFFSET | (ia64_iobase & ~PAGE_OFFSET);
+	ia64_iobase = (unsigned long) ioremap(phys_iobase, 0);
 
 #ifdef CONFIG_SMP
 	cpu_physical_id(0) = hard_smp_processor_id();
@@ -340,24 +344,31 @@
 
 	cpu_init();	/* initialize the bootstrap CPU */
 
-	if (efi.acpi20) {
-		/* Parse the ACPI 2.0 tables */
-		acpi20_parse(efi.acpi20);
-	} else if (efi.acpi) {
-		/* Parse the ACPI tables */
-		acpi_parse(efi.acpi);
-	}
+#ifdef CONFIG_ACPI_BOOT
+	acpi_boot_init(*cmdline_p);
+#endif
+#ifdef CONFIG_SERIAL_HCDP
 	if (efi.hcdp) {
+		void setup_serial_hcdp(void *);
+
 		/* Setup the serial ports described by HCDP */
 		setup_serial_hcdp(efi.hcdp);
 	}
-
+#endif
 #ifdef CONFIG_VT
-# if defined(CONFIG_VGA_CONSOLE)
-	conswitchp = &vga_con;
-# elif defined(CONFIG_DUMMY_CONSOLE)
+# if defined(CONFIG_DUMMY_CONSOLE)
 	conswitchp = &dummy_con;
 # endif
+# if defined(CONFIG_VGA_CONSOLE)
+	/*
+	 * Non-legacy systems may route legacy VGA MMIO range to system
+	 * memory.  vga_con probes the MMIO hole, so memory looks like
+	 * a VGA device to it.  The EFI memory map can tell us if it's
+	 * memory so we can avoid this problem.
+	 */
+	if (efi_mem_type(0xA0000) != EFI_CONVENTIONAL_MEMORY)
+		conswitchp = &vga_con;
+# endif
 #endif
 
 #ifdef CONFIG_IA64_MCA
@@ -392,7 +403,7 @@
 
 	switch (c->family) {
 	      case 0x07:	memcpy(family, "Itanium", 8); break;
-	      case 0x1f:	memcpy(family, "McKinley", 9); break;
+	      case 0x1f:	memcpy(family, "Itanium 2", 10); break;
 	      default:		sprintf(family, "%u", c->family); break;
 	}
 
@@ -433,7 +444,7 @@
 c_start (struct seq_file *m, loff_t *pos)
 {
 #ifdef CONFIG_SMP
-	while (*pos < NR_CPUS && !(cpu_online_map & (1 << *pos)))
+	while (*pos < NR_CPUS && !(cpu_online_map & (1UL << *pos)))
 		++*pos;
 #endif
 	return *pos < NR_CPUS ? cpu_data(*pos) : NULL;
@@ -570,6 +581,24 @@
 	 */
 	identify_cpu(my_cpu_data);
 
+#ifdef CONFIG_MCKINLEY
+	{
+#define FEATURE_SET 16
+		struct ia64_pal_retval iprv;
+
+		if (my_cpu_data->family == 0x1f) {
+
+			PAL_CALL_PHYS(iprv, PAL_PROC_GET_FEATURES, 0, FEATURE_SET, 0);
+
+			if ((iprv.status == 0) && (iprv.v0 & 0x80) && (iprv.v2 & 0x80)) {
+
+				PAL_CALL_PHYS(iprv, PAL_PROC_SET_FEATURES,
+				              (iprv.v1 | 0x80), FEATURE_SET, 0);
+			}
+		}
+	}
+#endif
+
 	/* Clear the stack memory reserved for pt_regs: */
 	memset(ia64_task_regs(current), 0, sizeof(struct pt_regs));
 
@@ -581,7 +610,7 @@
 	 * shouldn't be affected by this (moral: keep your ia32 locks aligned and you'll
 	 * be fine).
 	 */
-	ia64_set_dcr(  IA64_DCR_DM | IA64_DCR_DP | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_DR
+	ia64_set_dcr(  IA64_DCR_DP | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_DR
 		     | IA64_DCR_DA | IA64_DCR_DD | IA64_DCR_LC);
 #ifndef CONFIG_SMP
 	ia64_set_fpu_owner(0);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/signal.c linux-2.4.20/arch/ia64/kernel/signal.c
--- linux-2.4.19/arch/ia64/kernel/signal.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/signal.c	2002-10-29 11:18:48.000000000 +0000
@@ -143,9 +143,11 @@
 {
 	if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t)))
 		return -EFAULT;
-	if (from->si_code < 0)
-		return __copy_to_user(to, from, sizeof(siginfo_t));
-	else {
+	if (from->si_code < 0) {
+		if (__copy_to_user(to, from, sizeof(siginfo_t)))
+			return -EFAULT;
+		return 0;
+	} else {
 		int err;
 
 		/*
@@ -559,7 +561,7 @@
 				continue;
 
 			switch (signr) {
-			      case SIGCONT: case SIGCHLD: case SIGWINCH:
+			      case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			      case SIGTSTP: case SIGTTIN: case SIGTTOU:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/smp.c linux-2.4.20/arch/ia64/kernel/smp.c
--- linux-2.4.19/arch/ia64/kernel/smp.c	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/smp.c	2002-10-29 11:18:50.000000000 +0000
@@ -31,12 +31,12 @@
 #include <linux/mm.h>
 #include <linux/delay.h>
 #include <linux/cache.h>
+#include <linux/efi.h>
 
 #include <asm/atomic.h>
 #include <asm/bitops.h>
 #include <asm/current.h>
 #include <asm/delay.h>
-#include <asm/efi.h>
 #include <asm/machvec.h>
 
 #include <asm/io.h>
@@ -90,7 +90,7 @@
 handle_IPI (int irq, void *dev_id, struct pt_regs *regs)
 {
 	int this_cpu = smp_processor_id();
-	unsigned long *pending_ipis = &local_cpu_data->ipi_operation;
+	unsigned long *pending_ipis = &local_cpu_data->ipi.operation;
 	unsigned long ops;
 
 	/* Count this now; we may make a call that never returns. */
@@ -149,7 +149,7 @@
 static inline void
 send_IPI_single (int dest_cpu, int op)
 {
-	set_bit(op, &cpu_data(dest_cpu)->ipi_operation);
+	set_bit(op, &cpu_data(dest_cpu)->ipi.operation);
 	platform_send_ipi(dest_cpu, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0);
 }
 
@@ -212,7 +212,7 @@
 	int cpus = 1;
 
 	if (cpuid == smp_processor_id()) {
-		printk(__FUNCTION__" trying to call self\n");
+		printk("%s: trying to call self\n", __FUNCTION__);
 		return -EBUSY;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/smpboot.c linux-2.4.20/arch/ia64/kernel/smpboot.c
--- linux-2.4.19/arch/ia64/kernel/smpboot.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/smpboot.c	2002-10-29 11:18:35.000000000 +0000
@@ -23,13 +23,13 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/spinlock.h>
+#include <linux/efi.h>
 
 #include <asm/atomic.h>
 #include <asm/bitops.h>
 #include <asm/cache.h>
 #include <asm/current.h>
 #include <asm/delay.h>
-#include <asm/efi.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/machvec.h>
@@ -68,6 +68,7 @@
 
 extern void __init calibrate_delay(void);
 extern void start_ap(void);
+extern unsigned long ia64_iobase;
 
 int cpucount;
 
@@ -344,6 +345,11 @@
 	 */
 	ia64_init_itm();
 
+	/*
+	 * Set I/O port base per CPU
+	 */
+	ia64_set_kr(IA64_KR_IO_BASE, __pa(ia64_iobase));
+
 #ifdef CONFIG_IA64_MCA
 	ia64_mca_cmc_vector_setup();	/* Setup vector on AP & enable */
 	ia64_mca_check_errors();	/* For post-failure MCA error logging */
@@ -528,11 +534,11 @@
 
 		printk("Before bogomips.\n");
 		if (!cpucount) {
-			printk(KERN_ERR "Error: only one processor found.\n");
+			printk(KERN_WARNING "Warning: only one processor found.\n");
 		} else {
 			unsigned long bogosum = 0;
   			for (cpu = 0; cpu < NR_CPUS; cpu++)
-				if (cpu_online_map & (1<<cpu))
+				if (cpu_online_map & (1UL << cpu))
 					bogosum += cpu_data(cpu)->loops_per_jiffy;
 
 			printk(KERN_INFO"Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/sys_ia64.c linux-2.4.20/arch/ia64/kernel/sys_ia64.c
--- linux-2.4.19/arch/ia64/kernel/sys_ia64.c	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/sys_ia64.c	2002-10-29 11:18:31.000000000 +0000
@@ -2,8 +2,8 @@
  * This file contains various system calls that have different calling
  * conventions on different platforms.
  *
- * Copyright (C) 1999-2000 Hewlett-Packard Co
- * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2000, 2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #include <linux/config.h>
 #include <linux/errno.h>
@@ -201,15 +201,13 @@
 	if (len == 0)
 		goto out;
 
-	/* don't permit mappings into unmapped space or the virtual page table of a region: */
+	/*
+	 * Don't permit mappings into unmapped space, the virtual page table of a region,
+	 * or across a region boundary.  Note: RGN_MAP_LIMIT is equal to 2^n-PAGE_SIZE
+	 * (for some integer n <= 61) and len > 0.
+	 */
 	roff = rgn_offset(addr);
-	if ((len | roff | (roff + len)) >= RGN_MAP_LIMIT) {
-		addr = -EINVAL;
-		goto out;
-	}
-
-	/* don't permit mappings that would cross a region boundary: */
-	if (rgn_index(addr) != rgn_index(addr + len)) {
+	if ((len > RGN_MAP_LIMIT) || (roff > (RGN_MAP_LIMIT - len))) {
 		addr = -EINVAL;
 		goto out;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/time.c linux-2.4.20/arch/ia64/kernel/time.c
--- linux-2.4.19/arch/ia64/kernel/time.c	2002-02-25 19:37:53.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/time.c	2002-10-29 11:18:34.000000000 +0000
@@ -15,9 +15,9 @@
 #include <linux/sched.h>
 #include <linux/time.h>
 #include <linux/interrupt.h>
+#include <linux/efi.h>
 
 #include <asm/delay.h>
-#include <asm/efi.h>
 #include <asm/hw_irq.h>
 #include <asm/ptrace.h>
 #include <asm/sal.h>
@@ -39,21 +39,22 @@
 	extern unsigned long prof_cpu_mask;
 	extern char _stext;
 
+	if (!prof_buffer)
+		return;
+
 	if (!((1UL << smp_processor_id()) & prof_cpu_mask))
 		return;
 
-	if (prof_buffer && current->pid) {
-		ip -= (unsigned long) &_stext;
-		ip >>= prof_shift;
-		/*
-		 * Don't ignore out-of-bounds IP values silently, put them into the last
-		 * histogram slot, so if present, they will show up as a sharp peak.
-		 */
-		if (ip > prof_len - 1)
-			ip = prof_len - 1;
+	ip -= (unsigned long) &_stext;
+	ip >>= prof_shift;
+	/*
+	 * Don't ignore out-of-bounds IP values silently, put them into the last
+	 * histogram slot, so if present, they will show up as a sharp peak.
+	 */
+	if (ip > prof_len - 1)
+		ip = prof_len - 1;
 
-		atomic_inc((atomic_t *) &prof_buffer[ip]);
-	}
+	atomic_inc((atomic_t *) &prof_buffer[ip]);
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/traps.c linux-2.4.20/arch/ia64/kernel/traps.c
--- linux-2.4.19/arch/ia64/kernel/traps.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/traps.c	2002-10-29 11:18:50.000000000 +0000
@@ -48,10 +48,15 @@
 void __init
 trap_init (void)
 {
-	printk("fpswa interface at %lx\n", ia64_boot_param->fpswa);
-	if (ia64_boot_param->fpswa)
+	if (ia64_boot_param->fpswa) {
 		/* FPSWA fixup: make the interface pointer a kernel virtual address: */
 		fpswa_interface = __va(ia64_boot_param->fpswa);
+		printk("FPSWA interface at 0x%lx, revision %d.%d\n",
+			ia64_boot_param->fpswa,
+			fpswa_interface->revision >> 16,
+			fpswa_interface->revision & 0xffff);
+	} else
+		printk("No FPSWA interface\n");
 }
 
 /*
@@ -185,6 +190,10 @@
 		sig = SIGSEGV; code = __SEGV_PSTKOVF;
 		break;
 
+	      case 0x3f000 ... 0x3ffff:	/* bundle-update in progress */
+		sig = SIGILL; code = __ILL_BNDMOD;
+		break;
+
 	      default:
 		if (break_num < 0x40000 || break_num > 0x100000)
 			die_if_kernel("Bad break", regs, break_num);
@@ -213,7 +222,8 @@
 {
 	struct pt_regs *regs = (struct pt_regs *) &stack;
 
-	printk("<sc%ld(%lx,%lx,%lx,%lx)>\n", regs->r15, arg0, arg1, arg2, arg3);
+	printk("%s(%d): <sc%ld(%lx,%lx,%lx,%lx)>\n", current->comm, current->pid,
+	       regs->r15, arg0, arg1, arg2, arg3);
 	return -ENOSYS;
 }
 
@@ -242,9 +252,9 @@
 		if (fpu_owner)
 			ia64_flush_fph(fpu_owner);
 
-		ia64_set_fpu_owner(current);
 	}
 #endif /* !CONFIG_SMP */
+	ia64_set_fpu_owner(current);
 	if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) {
 		__ia64_load_fpu(current->thread.fph);
 		psr->mfh = 0;
@@ -429,7 +439,7 @@
 	unsigned long code, error = isr;
 	struct siginfo siginfo;
 	char buf[128];
-	int result;
+	int result, sig;
 	static const char *reason[] = {
 		"IA-64 Illegal Operation fault",
 		"IA-64 Privileged Operation fault",
@@ -441,30 +451,14 @@
 		"Unknown fault 13", "Unknown fault 14", "Unknown fault 15"
 	};
 
-#if 0
-	/* this is for minimal trust debugging; yeah this kind of stuff is useful at times... */
-
-	if (vector != 25) {
-		static unsigned long last_time;
-		static char count;
-		unsigned long n = vector;
-		char buf[32], *cp;
-
-		if (jiffies - last_time > 5*HZ)
-			count = 0;
-
-		if (count++ < 5) {
-			last_time = jiffies;
-			cp = buf + sizeof(buf);
-			*--cp = '\0';
-			while (n) {
-				*--cp = "0123456789abcdef"[n & 0xf];
-				n >>= 4;
-			}
-			printk("<0x%s>", cp);
-		}
+	if ((isr & IA64_ISR_NA) && ((isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) {
+		/*
+		 * This fault was due to lfetch.fault, set "ed" bit in the psr to cancel
+		 * the lfetch.
+		 */
+		ia64_psr(regs)->ed = 1;
+		return;
 	}
-#endif
 
 	switch (vector) {
 	      case 24: /* General Exception */
@@ -489,6 +483,30 @@
 		break;
 
 	      case 26: /* NaT Consumption */
+		if (user_mode(regs)) {
+			if (((isr >> 4) & 0xf) == 2) {
+				/* NaT page consumption */
+				sig = SIGSEGV;
+				code = SEGV_ACCERR;
+			} else {
+				/* register NaT consumption */
+				sig = SIGILL;
+				code = ILL_ILLOPN;
+			}
+			siginfo.si_signo = sig;
+			siginfo.si_code = code;
+			siginfo.si_errno = 0;
+			siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
+			siginfo.si_imm = vector;
+			siginfo.si_flags = __ISR_VALID;
+			siginfo.si_isr = isr;
+			force_sig_info(sig, &siginfo, current);
+			return;
+		} else if (done_with_exception(regs))
+			return;
+		sprintf(buf, "NaT consumption");
+		break;
+
 	      case 31: /* Unsupported Data Reference */
 		if (user_mode(regs)) {
 			siginfo.si_signo = SIGILL;
@@ -501,7 +519,7 @@
 			force_sig_info(SIGILL, &siginfo, current);
 			return;
 		}
-		sprintf(buf, (vector == 26) ? "NaT consumption" : "Unsupported data reference");
+		sprintf(buf, "Unsupported data reference");
 		break;
 
 	      case 29: /* Debug */
@@ -518,16 +536,15 @@
 			if (ia64_psr(regs)->is == 0)
 			  ifa = regs->cr_iip;
 #endif
-			siginfo.si_addr = (void *) ifa;
 			break;
-		      case 35: siginfo.si_code = TRAP_BRANCH; break;
-		      case 36: siginfo.si_code = TRAP_TRACE; break;
+		      case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break;
+		      case 36: siginfo.si_code = TRAP_TRACE; ifa = 0; break;
 		}
 		siginfo.si_signo = SIGTRAP;
 		siginfo.si_errno = 0;
 		siginfo.si_flags = 0;
 		siginfo.si_isr = 0;
-		siginfo.si_addr = 0;
+		siginfo.si_addr = (void *) ifa;
 		siginfo.si_imm = 0;
 		force_sig_info(SIGTRAP, &siginfo, current);
 		return;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/unaligned.c linux-2.4.20/arch/ia64/kernel/unaligned.c
--- linux-2.4.19/arch/ia64/kernel/unaligned.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/unaligned.c	2002-10-29 11:18:49.000000000 +0000
@@ -1304,11 +1304,7 @@
 	 * handler into reading an arbitrary kernel addresses...
 	 */
 	if (!user_mode(regs)) {
-#ifdef GAS_HAS_LOCAL_TAGS
-		fix = search_exception_table(regs->cr_iip + ia64_psr(regs)->ri);
-#else
-		fix = search_exception_table(regs->cr_iip);
-#endif
+		fix = SEARCH_EXCEPTION_TABLE(regs);
 	}
 	if (user_mode(regs) || fix.cont) {
 		if ((current->thread.flags & IA64_THREAD_UAC_SIGBUS) != 0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/unwind.c linux-2.4.20/arch/ia64/kernel/unwind.c
--- linux-2.4.19/arch/ia64/kernel/unwind.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/unwind.c	2002-10-29 11:18:48.000000000 +0000
@@ -634,8 +634,8 @@
 	for (reg = hi; reg >= lo; --reg) {
 		if (reg->where == UNW_WHERE_SPILL_HOME) {
 			reg->where = UNW_WHERE_PSPREL;
-			reg->val = 0x10 - *offp;
-			*offp += regsize;
+			*offp -= regsize;
+			reg->val = *offp;
 		}
 	}
 }
@@ -814,7 +814,8 @@
 	}
 	for (i = 0; i < 20; ++i) {
 		if ((frmask & 1) != 0) {
-			set_reg(sr->curr.reg + UNW_REG_F2 + i, UNW_WHERE_SPILL_HOME,
+			int base = (i < 4) ? UNW_REG_F2 : UNW_REG_F16 - 4;
+			set_reg(sr->curr.reg + base + i, UNW_WHERE_SPILL_HOME,
 				sr->region_start + sr->region_len - 1, 0);
 			sr->any_spills = 1;
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/kernel/unwind_i.h linux-2.4.20/arch/ia64/kernel/unwind_i.h
--- linux-2.4.19/arch/ia64/kernel/unwind_i.h	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/kernel/unwind_i.h	2002-10-29 11:18:39.000000000 +0000
@@ -103,7 +103,7 @@
 	unsigned int in_body : 1;	/* are we inside a body (as opposed to a prologue)? */
 	unsigned long flags;		/* see UNW_FLAG_* in unwind.h */
 
-	u8 *imask;			/* imask of of spill_mask record or NULL */
+	u8 *imask;			/* imask of spill_mask record or NULL */
 	unsigned long pr_val;		/* predicate values */
 	unsigned long pr_mask;		/* predicate mask */
 	long spill_offset;		/* psp-relative offset for spill base */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/lib/Makefile linux-2.4.20/arch/ia64/lib/Makefile
--- linux-2.4.19/arch/ia64/lib/Makefile	2001-07-31 17:30:08.000000000 +0000
+++ linux-2.4.20/arch/ia64/lib/Makefile	2002-10-29 11:18:39.000000000 +0000
@@ -11,10 +11,13 @@
 
 obj-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o					\
 	__divdi3.o __udivdi3.o __moddi3.o __umoddi3.o					\
-	checksum.o clear_page.o csum_partial_copy.o copy_page.o				\
-	copy_user.o clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o	\
-	flush.o io.o do_csum.o								\
-	memcpy.o memset.o strlen.o swiotlb.o
+	checksum.o clear_page.o csum_partial_copy.o					\
+	clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o			\
+	flush.o ip_fast_csum.o io.o do_csum.o						\
+	memset.o strlen.o swiotlb.o
+
+obj-$(CONFIG_ITANIUM) += copy_page.o copy_user.o memcpy.o
+obj-$(CONFIG_MCKINLEY) += copy_page_mck.o memcpy_mck.o
 
 IGNORE_FLAGS_OBJS =	__divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \
 			__divdi3.o __udivdi3.o __moddi3.o __umoddi3.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/lib/checksum.c linux-2.4.20/arch/ia64/lib/checksum.c
--- linux-2.4.19/arch/ia64/lib/checksum.c	2001-07-31 17:30:08.000000000 +0000
+++ linux-2.4.20/arch/ia64/lib/checksum.c	2002-10-29 11:18:36.000000000 +0000
@@ -66,15 +66,6 @@
 extern unsigned long do_csum (const unsigned char *, long);
 
 /*
- *	This is a version of ip_compute_csum() optimized for IP headers,
- *	which always checksum on 4 octet boundaries.
- */
-unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
-{
-	return ~do_csum(iph, ihl*4);
-}
-
-/*
  * computes the checksum of a memory block at buff, length len,
  * and adds in "sum" (32-bit)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/lib/clear_page.S linux-2.4.20/arch/ia64/lib/clear_page.S
--- linux-2.4.19/arch/ia64/lib/clear_page.S	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/arch/ia64/lib/clear_page.S	2002-10-29 11:18:32.000000000 +0000
@@ -1,51 +1,77 @@
 /*
- *
- * Optimized function to clear a page of memory.
- *
- * Inputs:
- *	in0:	address of page
- *
- * Output:
- * 	none
- *
- * Copyright (C) 1999-2001 Hewlett-Packard Co
- * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
- * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2002 Hewlett-Packard Co
+ *	Stephane Eranian <eranian@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2002 Ken Chen <kenneth.w.chen@intel.com>
  *
  * 1/06/01 davidm	Tuned for Itanium.
+ * 2/12/02 kchen	Tuned for both Itanium and McKinley
+ * 3/08/02 davidm	Some more tweaking
  */
+#include <linux/config.h>
+
 #include <asm/asmmacro.h>
 #include <asm/page.h>
 
+#ifdef CONFIG_ITANIUM
+# define L3_LINE_SIZE	64	// Itanium L3 line size
+# define PREFETCH_LINES	9	// magic number
+#else
+# define L3_LINE_SIZE	128	// McKinley L3 line size
+# define PREFETCH_LINES	12	// magic number
+#endif
+
 #define saved_lc	r2
-#define dst0		in0
+#define dst_fetch	r3
 #define dst1		r8
 #define dst2		r9
 #define dst3		r10
-#define dst_fetch	r11
+#define dst4		r11
+
+#define dst_last	r31
 
 GLOBAL_ENTRY(clear_page)
 	.prologue
 	.regstk 1,0,0,0
-	mov r16 = PAGE_SIZE/64-1	// -1 = repeat/until
-	;;
+	mov r16 = PAGE_SIZE/L3_LINE_SIZE-1	// main loop count, -1=repeat/until
 	.save ar.lc, saved_lc
 	mov saved_lc = ar.lc
+
 	.body
-	mov ar.lc = r16
-	adds dst1 = 16, dst0
-	adds dst2 = 32, dst0
-	adds dst3 = 48, dst0
-	adds dst_fetch = 512, dst0
+	mov ar.lc = (PREFETCH_LINES - 1)
+	mov dst_fetch = in0
+	adds dst1 = 16, in0
+	adds dst2 = 32, in0
+	;;
+.fetch:	stf.spill.nta [dst_fetch] = f0, L3_LINE_SIZE
+	adds dst3 = 48, in0		// executing this multiple times is harmless
+	br.cloop.sptk.few .fetch
+	;;
+	addl dst_last = (PAGE_SIZE - PREFETCH_LINES*L3_LINE_SIZE), dst_fetch
+	mov ar.lc = r16			// one L3 line per iteration
+	adds dst4 = 64, in0
+	;;
+#ifdef CONFIG_ITANIUM
+	// Optimized for Itanium
+1:	stf.spill.nta [dst1] = f0, 64
+	stf.spill.nta [dst2] = f0, 64
+	cmp.lt p8,p0=dst_fetch, dst_last
+	;;
+#else
+	// Optimized for McKinley
+1:	stf.spill.nta [dst1] = f0, 64
+	stf.spill.nta [dst2] = f0, 64
+	stf.spill.nta [dst3] = f0, 64
+	stf.spill.nta [dst4] = f0, 128
+	cmp.lt p8,p0=dst_fetch, dst_last
 	;;
-1:	stf.spill.nta [dst0] = f0, 64
 	stf.spill.nta [dst1] = f0, 64
 	stf.spill.nta [dst2] = f0, 64
+#endif
 	stf.spill.nta [dst3] = f0, 64
-
-	lfetch [dst_fetch], 64
-	br.cloop.dptk.few 1b
+(p8)	stf.spill.nta [dst_fetch] = f0, L3_LINE_SIZE
+	br.cloop.sptk.few 1b
 	;;
-	mov ar.lc = r2		// restore lc
+	mov ar.lc = saved_lc		// restore lc
 	br.ret.sptk.many rp
 END(clear_page)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/lib/copy_page.S linux-2.4.20/arch/ia64/lib/copy_page.S
--- linux-2.4.19/arch/ia64/lib/copy_page.S	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/arch/ia64/lib/copy_page.S	2002-10-29 11:18:51.000000000 +0000
@@ -30,6 +30,7 @@
 #define tgt2		r23
 #define srcf		r24
 #define tgtf		r25
+#define tgt_last	r26
 
 #define Nrot		((8*PIPE_DEPTH+7)&~7)
 
@@ -55,18 +56,21 @@
 
 	mov src1=in1
 	adds src2=8,in1
+	mov tgt_last = PAGE_SIZE
 	;;
 	adds tgt2=8,in0
 	add srcf=512,in1
 	mov ar.lc=lcount
 	mov tgt1=in0
 	add tgtf=512,in0
+	add tgt_last = tgt_last, in0
 	;;
 1:
 (p[0])	ld8 t1[0]=[src1],16
 (EPI)	st8 [tgt1]=t1[PIPE_DEPTH-1],16
 (p[0])	ld8 t2[0]=[src2],16
 (EPI)	st8 [tgt2]=t2[PIPE_DEPTH-1],16
+	cmp.ltu p6,p0 = tgtf, tgt_last
 	;;
 (p[0])	ld8 t3[0]=[src1],16
 (EPI)	st8 [tgt1]=t3[PIPE_DEPTH-1],16
@@ -83,8 +87,8 @@
 (p[0])	ld8 t8[0]=[src2],16
 (EPI)	st8 [tgt2]=t8[PIPE_DEPTH-1],16
 
-	lfetch [srcf], 64
-	lfetch [tgtf], 64
+(p6)	lfetch [srcf], 64
+(p6)	lfetch [tgtf], 64
 	br.ctop.sptk.few 1b
 	;;
 	mov pr=saved_pr,0xffffffffffff0000	// restore predicates
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/lib/copy_page_mck.S linux-2.4.20/arch/ia64/lib/copy_page_mck.S
--- linux-2.4.19/arch/ia64/lib/copy_page_mck.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/lib/copy_page_mck.S	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,185 @@
+/*
+ * McKinley-optimized version of copy_page().
+ *
+ * Copyright (C) 2002 Hewlett-Packard Co
+ *	David Mosberger <davidm@hpl.hp.com>
+ *
+ * Inputs:
+ *	in0:	address of target page
+ *	in1:	address of source page
+ * Output:
+ *	no return value
+ *
+ * General idea:
+ *	- use regular loads and stores to prefetch data to avoid consuming M-slot just for
+ *	  lfetches => good for in-cache performance
+ *	- avoid l2 bank-conflicts by not storing into the same 16-byte bank within a single
+ *	  cycle
+ *
+ * Principle of operation:
+ *	First, note that L1 has a line-size of 64 bytes and L2 a line-size of 128 bytes.
+ *	To avoid secondary misses in L2, we prefetch both source and destination with a line-size
+ *	of 128 bytes.  When both of these lines are in the L2 and the first half of the
+ *	source line is in L1, we start copying the remaining words.  The second half of the
+ *	source line is prefetched in an earlier iteration, so that by the time we start
+ *	accessing it, it's also present in the L1.
+ *
+ *	We use a software-pipelined loop to control the overall operation.  The pipeline
+ *	has 2*PREFETCH_DIST+K stages.  The first PREFETCH_DIST stages are used for prefetching
+ *	source cache-lines.  The second PREFETCH_DIST stages are used for prefetching destination
+ *	cache-lines, the last K stages are used to copy the cache-line words not copied by
+ *	the prefetches.  The four relevant points in the pipelined are called A, B, C, D:
+ *	p[A] is TRUE if a source-line should be prefetched, p[B] is TRUE if a destination-line
+ *	should be prefetched, p[C] is TRUE if the second half of an L2 line should be brought
+ *	into L1D and p[D] is TRUE if a cacheline needs to be copied.
+ *
+ *	This all sounds very complicated, but thanks to the modulo-scheduled loop support,
+ *	the resulting code is very regular and quite easy to follow (once you get the idea).
+ *
+ *	As a secondary optimization, the first 2*PREFETCH_DIST iterations are implemented
+ *	as the separate .prefetch_loop.  Logically, this loop performs exactly like the
+ *	main-loop (.line_copy), but has all known-to-be-predicated-off instructions removed,
+ *	so that each loop iteration is faster (again, good for cached case).
+ *
+ *	When reading the code, it helps to keep the following picture in mind:
+ *
+ *	       word 0 word 1
+ *            +------+------+---
+ *	      |	v[x] | 	t1  | ^
+ *	      |	t2   |	t3  | |
+ *	      |	t4   |	t5  | |
+ *	      |	t6   |	t7  | | 128 bytes
+ *     	      |	n[y] | 	t9  | |	(L2 cache line)
+ *	      |	t10  | 	t11 | |
+ *	      |	t12  | 	t13 | |
+ *	      |	t14  | 	t15 | v
+ *	      +------+------+---
+ *
+ *	Here, v[x] is copied by the (memory) prefetch.  n[y] is loaded at p[C]
+ *	to fetch the second-half of the L2 cache line into L1, and the tX words are copied in
+ *	an order that avoids bank conflicts.
+ */
+#include <asm/asmmacro.h>
+#include <asm/page.h>
+
+#define PREFETCH_DIST	8		// McKinley sustains 16 outstanding L2 misses (8 ld, 8 st)
+
+#define src0		r2
+#define src1		r3
+#define dst0		r9
+#define dst1		r10
+#define src_pre_mem	r11
+#define dst_pre_mem	r14
+#define src_pre_l2	r15
+#define dst_pre_l2	r16
+#define t1		r17
+#define t2		r18
+#define t3		r19
+#define t4		r20
+#define t5		t1	// alias!
+#define t6		t2	// alias!
+#define t7		t3	// alias!
+#define t9		t5	// alias!
+#define t10		t4	// alias!
+#define t11		t7	// alias!
+#define t12		t6	// alias!
+#define t14		t10	// alias!
+#define t13		r21
+#define t15		r22
+
+#define saved_lc	r23
+#define saved_pr	r24
+
+#define	A	0
+#define B	(PREFETCH_DIST)
+#define C	(B + PREFETCH_DIST)
+#define D	(C + 3)
+#define N	(D + 1)
+#define Nrot	((N + 7) & ~7)
+
+GLOBAL_ENTRY(copy_page)
+	.prologue
+	alloc r8 = ar.pfs, 2, Nrot-2, 0, Nrot
+
+	.rotr v[2*PREFETCH_DIST], n[D-C+1]
+	.rotp p[N]
+
+	.save ar.lc, saved_lc
+	mov saved_lc = ar.lc
+	.save pr, saved_pr
+	mov saved_pr = pr
+	.body
+
+	mov src_pre_mem = in1
+	mov pr.rot = 0x10000
+	mov ar.ec = 1				// special unrolled loop
+
+	mov dst_pre_mem = in0
+	mov ar.lc = 2*PREFETCH_DIST - 1
+
+	add src_pre_l2 = 8*8, in1
+	add dst_pre_l2 = 8*8, in0
+	add src0 = 8, in1			// first t1 src
+	add src1 = 3*8, in1			// first t3 src
+	add dst0 = 8, in0			// first t1 dst
+	add dst1 = 3*8, in0			// first t3 dst
+	mov t1 = (PAGE_SIZE/128) - (2*PREFETCH_DIST) - 1
+	nop.m 0
+	nop.i 0
+	;;
+	// same as .line_copy loop, but with all predicated-off instructions removed:
+.prefetch_loop:
+(p[A])	ld8 v[A] = [src_pre_mem], 128		// M0
+(p[B])	st8 [dst_pre_mem] = v[B], 128		// M2
+	br.ctop.sptk .prefetch_loop
+	;;
+	cmp.eq p16, p0 = r0, r0			// reset p16 to 1 (br.ctop cleared it to zero)
+	mov ar.lc = t1				// with 64KB pages, t1 is too big to fit in 8 bits!
+	mov ar.ec = N				// # of stages in pipeline
+	;;
+.line_copy:
+(p[D])	ld8 t2 = [src0], 3*8			// M0
+(p[D])	ld8 t4 = [src1], 3*8			// M1
+(p[B])	st8 [dst_pre_mem] = v[B], 128		// M2 prefetch dst from memory
+(p[D])	st8 [dst_pre_l2] = n[D-C], 128		// M3 prefetch dst from L2
+	;;
+(p[A])	ld8 v[A] = [src_pre_mem], 128		// M0 prefetch src from memory
+(p[C])	ld8 n[0] = [src_pre_l2], 128		// M1 prefetch src from L2
+(p[D])	st8 [dst0] =  t1, 8			// M2
+(p[D])	st8 [dst1] =  t3, 8			// M3
+	;;
+(p[D])	ld8  t5 = [src0], 8
+(p[D])	ld8  t7 = [src1], 3*8
+(p[D])	st8 [dst0] =  t2, 3*8
+(p[D])	st8 [dst1] =  t4, 3*8
+	;;
+(p[D])	ld8  t6 = [src0], 3*8
+(p[D])	ld8 t10 = [src1], 8
+(p[D])	st8 [dst0] =  t5, 8
+(p[D])	st8 [dst1] =  t7, 3*8
+	;;
+(p[D])	ld8  t9 = [src0], 3*8
+(p[D])	ld8 t11 = [src1], 3*8
+(p[D])	st8 [dst0] =  t6, 3*8
+(p[D])	st8 [dst1] = t10, 8
+	;;
+(p[D])	ld8 t12 = [src0], 8
+(p[D])	ld8 t14 = [src1], 8
+(p[D])	st8 [dst0] =  t9, 3*8
+(p[D])	st8 [dst1] = t11, 3*8
+	;;
+(p[D])	ld8 t13 = [src0], 4*8
+(p[D])	ld8 t15 = [src1], 4*8
+(p[D])	st8 [dst0] = t12, 8
+(p[D])	st8 [dst1] = t14, 8
+	;;
+(p[D-1])ld8  t1 = [src0], 8
+(p[D-1])ld8  t3 = [src1], 8
+(p[D])	st8 [dst0] = t13, 4*8
+(p[D])	st8 [dst1] = t15, 4*8
+	br.ctop.sptk .line_copy
+	;;
+	mov ar.lc = saved_lc
+	mov pr = saved_pr, -1
+	br.ret.sptk.many rp
+END(copy_page)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/lib/copy_user.S linux-2.4.20/arch/ia64/lib/copy_user.S
--- linux-2.4.19/arch/ia64/lib/copy_user.S	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/arch/ia64/lib/copy_user.S	2002-10-29 11:18:34.000000000 +0000
@@ -237,15 +237,17 @@
 .copy_user_bit##rshift:						\
 1:								\
 	EX(.failure_out,(EPI) st8 [dst1]=tmp,8);		\
-(EPI_1) shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift;	\
-	EX(3f,(p16) ld8 val1[0]=[src1],8);			\
+(EPI_1) shrp tmp=val1[PIPE_DEPTH-2],val1[PIPE_DEPTH-1],rshift;	\
+	EX(3f,(p16) ld8 val1[1]=[src1],8);			\
+(p16)	mov val1[0]=r0;						\
 	br.ctop.dptk 1b;					\
 	;;							\
 	br.cond.sptk.many .diff_align_do_tail;			\
 2:								\
 (EPI)	st8 [dst1]=tmp,8;					\
-(EPI_1)	shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift;	\
+(EPI_1)	shrp tmp=val1[PIPE_DEPTH-2],val1[PIPE_DEPTH-1],rshift;	\
 3:								\
+(p16)	mov val1[1]=r0;						\
 (p16)	mov val1[0]=r0;						\
 	br.ctop.dptk 2b;					\
 	;;							\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/lib/do_csum.S linux-2.4.20/arch/ia64/lib/do_csum.S
--- linux-2.4.19/arch/ia64/lib/do_csum.S	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/arch/ia64/lib/do_csum.S	2002-10-29 11:18:33.000000000 +0000
@@ -8,9 +8,14 @@
  *	in0: address of buffer to checksum (char *)
  *	in1: length of the buffer (int)
  *
- * Copyright (C) 1999, 2001 Hewlett-Packard Co
- * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 1999, 2001-2002 Hewlett-Packard Co
+ *	Stephane Eranian <eranian@hpl.hp.com>
  *
+ * 02/04/22	Ken Chen <kenneth.w.chen@intel.com>
+ *		Data locality study on the checksum buffer.
+ *		More optimization cleanup - remove excessive stop bits.
+ * 02/04/08	David Mosberger <davidm@hpl.hp.com>
+ *		More cleanup and tuning.
  * 01/04/18	Jun Nakajima <jun.nakajima@intel.com>
  *		Clean up and optimize and the software pipeline, loading two
  *		back-to-back 8-byte words per loop. Clean up the initialization
@@ -71,8 +76,6 @@
 //	calculating the Internet checksum.
 //
 // NOT YET DONE:
-//	- use the lfetch instruction to augment the chances of the data being in
-//	  the cache when we need it.
 //	- Maybe another algorithm which would take care of the folding at the
 //	  end in a different manner
 //	- Work with people more knowledgeable than me on the network stack
@@ -80,6 +83,12 @@
 //	  type of packet or alignment we get. Like the ip_fast_csum() routine
 //	  where we know we have at least 20bytes worth of data to checksum.
 //	- Do a better job of handling small packets.
+//	- Note on prefetching: it was found that under various load, i.e. ftp read/write,
+//	  nfs read/write, the L1 cache hit rate is at 60% and L2 cache hit rate is at 99.8%
+//	  on the data that buffer points to (partly because the checksum is often preceded by
+//	  a copy_from_user()).  This finding indiate that lfetch will not be beneficial since
+//	  the data is already in the cache.
+//
 
 #define saved_pfs	r11
 #define hmask		r16
@@ -102,10 +111,6 @@
 #define buf		in0
 #define len		in1
 
-#ifndef CONFIG_IA64_LOAD_LATENCY
-#define CONFIG_IA64_LOAD_LATENCY	2
-#endif
-
 #define LOAD_LATENCY	2	// XXX fix me
 
 #if (LOAD_LATENCY != 1) && (LOAD_LATENCY != 2)
@@ -121,69 +126,70 @@
 GLOBAL_ENTRY(do_csum)
 	.prologue
 	.save ar.pfs, saved_pfs
-	alloc saved_pfs=ar.pfs,2,16,1,16
-	.rotr word1[4], word2[4],result1[4],result2[4]
-	.rotp p[PIPE_DEPTH]
+	alloc saved_pfs=ar.pfs,2,16,0,16
+	.rotr word1[4], word2[4],result1[LOAD_LATENCY+2],result2[LOAD_LATENCY+2]
+	.rotp p[PIPE_DEPTH], pC1[2], pC2[2]
 	mov ret0=r0		// in case we have zero length
 	cmp.lt p0,p6=r0,len	// check for zero length or negative (32bit len)
-	;;			// avoid WAW on CFM
-	mov tmp3=0x7		// a temporary mask/value
+	;;
 	add tmp1=buf,len	// last byte's address
-(p6)	br.ret.spnt.many rp	// return if true (hope we can avoid that)
+	.save pr, saved_pr
+	mov saved_pr=pr		// preserve predicates (rotation)
+(p6)	br.ret.spnt.many rp	// return if zero or negative length
 
-	and firstoff=7,buf	// how many bytes off for first1 element
-	tbit.nz p15,p0=buf,0	// is buf an odd address ?
 	mov hmask=-1		// intialize head mask
-	;;
-	andcm first1=buf,tmp3	// 8byte aligned down address of first1 element
+	tbit.nz p15,p0=buf,0	// is buf an odd address?
+	and first1=-8,buf	// 8-byte align down address of first1 element
+
+	and firstoff=7,buf	// how many bytes off for first1 element
 	mov tmask=-1		// initialize tail mask
-	adds tmp2=-1,tmp1	// last-1
+
 	;;
+	adds tmp2=-1,tmp1	// last-1
 	and lastoff=7,tmp1	// how many bytes off for last element
-	andcm last=tmp2,tmp3	// address of word containing last byte
-	.save pr, saved_pr
-	mov saved_pr=pr		// preserve predicates (rotation)
+	;;
+	sub tmp1=8,lastoff	// complement to lastoff
+	and last=-8,tmp2	// address of word containing last byte
 	;;
 	sub tmp3=last,first1	// tmp3=distance from first1 to last
+	.save ar.lc, saved_lc
+	mov saved_lc=ar.lc	// save lc
 	cmp.eq p8,p9=last,first1	// everything fits in one word ?
-	sub tmp1=8,lastoff	// complement to lastoff
-	ld8 firstval=[first1],8	// load,ahead of time, "first1" word
+
+	ld8 firstval=[first1],8	// load, ahead of time, "first1" word
+	and tmp1=7, tmp1	// make sure that if tmp1==8 -> tmp1=0
 	shl tmp2=firstoff,3	// number of bits
 	;;
-	and tmp1=7, tmp1	// make sure that if tmp1==8 -> tmp1=0
-(p9)	ld8 lastval=[last]	// load,ahead of time, "last" word, if needed
+(p9)	ld8 lastval=[last]	// load, ahead of time, "last" word, if needed
+	shl tmp1=tmp1,3		// number of bits
 (p9)	adds tmp3=-8,tmp3	// effectively loaded
 	;;
 (p8)	mov lastval=r0		// we don't need lastval if first1==last
-	shl tmp1=tmp1,3		// number of bits
 	shl hmask=hmask,tmp2	// build head mask, mask off [0,first1off[
-	;;
 	shr.u tmask=tmask,tmp1	// build tail mask, mask off ]8,lastoff]
-	.save ar.lc, saved_lc
-	mov saved_lc=ar.lc	// save lc
 	;;
 	.body
 #define count tmp3
 
 (p8)	and hmask=hmask,tmask	// apply tail mask to head mask if 1 word only
 (p9)	and word2[0]=lastval,tmask	// mask last it as appropriate
-	shr.u count=count,3	// we do 8 bytes per loop (count)
+	shr.u count=count,3	// how many 8-byte?
 	;;
 	// If count is odd, finish this 8-byte word so that we can
 	// load two back-to-back 8-byte words per loop thereafter.
-	tbit.nz p10,p11=count,0		// if (count is odd)
 	and word1[0]=firstval,hmask	// and mask it as appropriate
+	tbit.nz p10,p11=count,0		// if (count is odd)
 	;;
 (p8)	mov result1[0]=word1[0]
 (p9)	add result1[0]=word1[0],word2[0]
 	;;
 	cmp.ltu p6,p0=result1[0],word1[0]	// check the carry
+	cmp.eq.or.andcm p8,p0=0,count		// exit if zero 8-byte
 	;;
 (p6)	adds result1[0]=1,result1[0]
 (p8)	br.cond.dptk .do_csum_exit	// if (within an 8-byte word)
-	;;
 (p11)	br.cond.dptk .do_csum16		// if (count is even)
-	;;
+
 	// Here count is odd.
 	ld8 word1[1]=[first1],8		// load an 8-byte word
 	cmp.eq p9,p10=1,count		// if (count == 1)
@@ -194,58 +200,43 @@
 	cmp.ltu p6,p0=result1[0],word1[1]
 	;;
 (p6)	adds result1[0]=1,result1[0]
-	;;
 (p9)	br.cond.sptk .do_csum_exit	// if (count == 1) exit
 	// Fall through to caluculate the checksum, feeding result1[0] as
 	// the initial value in result1[0].
-	;;
 	//
 	// Calculate the checksum loading two 8-byte words per loop.
 	//
 .do_csum16:
-	mov saved_lc=ar.lc
+	add first2=8,first1
 	shr.u count=count,1	// we do 16 bytes per loop
 	;;
-	cmp.eq p9,p10=r0,count	// if (count == 0)
+	adds count=-1,count
+	mov carry1=r0
+	mov carry2=r0
 	brp.loop.imp 1f,2f
 	;;
-	adds count=-1,count
 	mov ar.ec=PIPE_DEPTH
-	;;
 	mov ar.lc=count	// set lc
-	;;
+	mov pr.rot=1<<16
 	// result1[0] must be initialized in advance.
 	mov result2[0]=r0
 	;;
-	mov pr.rot=1<<16
-	;;
-	mov carry1=r0
-	mov carry2=r0
-	;;
-	add first2=8,first1
-	;;
-(p9)	br.cond.sptk .do_csum_exit
-	;;
-	nop.m	0
-	nop.i	0
-	;;
 	.align 32
 1:
-(ELD_1)	cmp.ltu p31,p0=result1[LOAD_LATENCY],word1[LOAD_LATENCY+1]
-(p32)	adds carry1=1,carry1
-(ELD_1)	cmp.ltu p47,p0=result2[LOAD_LATENCY],word2[LOAD_LATENCY+1]
-(p48)	adds carry2=1,carry2
+(ELD_1)	cmp.ltu pC1[0],p0=result1[LOAD_LATENCY],word1[LOAD_LATENCY+1]
+(pC1[1])adds carry1=1,carry1
+(ELD_1)	cmp.ltu pC2[0],p0=result2[LOAD_LATENCY],word2[LOAD_LATENCY+1]
+(pC2[1])adds carry2=1,carry2
 (ELD)	add result1[LOAD_LATENCY-1]=result1[LOAD_LATENCY],word1[LOAD_LATENCY]
 (ELD)	add result2[LOAD_LATENCY-1]=result2[LOAD_LATENCY],word2[LOAD_LATENCY]
 2:
-(p16)	ld8 word1[0]=[first1],16
-(p16)	ld8 word2[0]=[first2],16
+(p[0])	ld8 word1[0]=[first1],16
+(p[0])	ld8 word2[0]=[first2],16
 	br.ctop.sptk 1b
 	;;
-	// Since len is a 32-bit value, carry cannot be larger than
-	// a 64-bit value.
-(p32)	adds carry1=1,carry1	// since we miss the last one
-(p48)	adds carry2=1,carry2
+	// Since len is a 32-bit value, carry cannot be larger than a 64-bit value.
+(pC1[1])adds carry1=1,carry1	// since we miss the last one
+(pC2[1])adds carry2=1,carry2
 	;;
 	add result1[LOAD_LATENCY+1]=result1[LOAD_LATENCY+1],carry1
 	add result2[LOAD_LATENCY+1]=result2[LOAD_LATENCY+1],carry2
@@ -263,18 +254,15 @@
 (p6)	adds result1[0]=1,result1[0]
 	;;
 .do_csum_exit:
-	movl tmp3=0xffffffff
-	;;
-	// XXX Fixme
 	//
 	// now fold 64 into 16 bits taking care of carry
 	// that's not very good because it has lots of sequentiality
 	//
-	and tmp1=result1[0],tmp3
+	mov tmp3=0xffff
+	zxt4 tmp1=result1[0]
 	shr.u tmp2=result1[0],32
 	;;
 	add result1[0]=tmp1,tmp2
-	shr.u tmp3=tmp3,16
 	;;
 	and tmp1=result1[0],tmp3
 	shr.u tmp2=result1[0],16
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/lib/ip_fast_csum.S linux-2.4.20/arch/ia64/lib/ip_fast_csum.S
--- linux-2.4.19/arch/ia64/lib/ip_fast_csum.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/lib/ip_fast_csum.S	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,90 @@
+/*
+ * Optmized version of the ip_fast_csum() function
+ * Used for calculating IP header checksum
+ *
+ * Return: 16bit checksum, complemented
+ *
+ * Inputs:
+ *      in0: address of buffer to checksum (char *)
+ *      in1: length of the buffer (int)
+ *
+ * Copyright (C) 2002 Intel Corp.
+ * Copyright (C) 2002 Ken Chen <kenneth.w.chen@intel.com>
+ */
+
+#include <asm/asmmacro.h>
+
+/*
+ * Since we know that most likely this function is called with buf aligned
+ * on 4-byte boundary and 20 bytes in length, we can execution rather quickly
+ * versus calling generic version of do_csum, which has lots of overhead in
+ * handling various alignments and sizes.  However, due to lack of constrains
+ * put on the function input argument, cases with alignment not on 4-byte or
+ * size not equal to 20 bytes will be handled by the generic do_csum function.
+ */
+
+#define in0	r32
+#define in1	r33
+#define ret0	r8
+
+GLOBAL_ENTRY(ip_fast_csum)
+	.prologue
+	.body
+	cmp.ne	p6,p7=5,in1	// size other than 20 byte?
+	and	r14=3,in0	// is it aligned on 4-byte?
+	add	r15=4,in0	// second source pointer
+	;;
+	cmp.ne.or.andcm p6,p7=r14,r0
+	;;
+(p7)	ld4	r20=[in0],8
+(p7)	ld4	r21=[r15],8
+(p6)	br.spnt	.generic
+	;;
+	ld4	r22=[in0],8
+	ld4	r23=[r15],8
+	;;
+	ld4	r24=[in0]
+	add	r20=r20,r21
+	add	r22=r22,r23
+	;;
+	add	r20=r20,r22
+	;;
+	add	r20=r20,r24
+	;;
+	shr.u	ret0=r20,16	// now need to add the carry
+	zxt2	r20=r20
+	;;
+	add	r20=ret0,r20
+	;;
+	shr.u	ret0=r20,16	// add carry again
+	zxt2	r20=r20
+	;;
+	add	r20=ret0,r20
+	;;
+	shr.u	ret0=r20,16
+	zxt2	r20=r20
+	;;
+	add	r20=ret0,r20
+	;;
+	andcm	ret0=-1,r20
+	.restore sp		// reset frame state
+	br.ret.sptk.many b0
+	;;
+
+.generic:
+	.prologue
+	.save ar.pfs, r35
+	alloc	r35=ar.pfs,2,2,2,0
+	.save rp, r34
+	mov	r34=b0
+	.body
+	dep.z	out1=in1,2,30
+	mov	out0=in0
+	;;
+	br.call.sptk.many b0=do_csum
+	;;
+	andcm	ret0=-1,ret0
+	mov	ar.pfs=r35
+	mov	b0=r34
+	br.ret.sptk.many b0
+END(ip_fast_csum)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/lib/memcpy_mck.S linux-2.4.20/arch/ia64/lib/memcpy_mck.S
--- linux-2.4.19/arch/ia64/lib/memcpy_mck.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ia64/lib/memcpy_mck.S	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,675 @@
+/*
+ * Itanium 2-optimized version of memcpy and copy_user function
+ *
+ * Inputs:
+ * 	in0:	destination address
+ *	in1:	source address
+ *	in2:	number of bytes to copy
+ * Output:
+ * 	0 if success, or number of byte NOT copied if error occurred.
+ *
+ * Copyright (C) 2002 Intel Corp.
+ * Copyright (C) 2002 Ken Chen <kenneth.w.chen@intel.com>
+ */
+#include <linux/config.h>
+#include <asm/asmmacro.h>
+#include <asm/page.h>
+
+#if __GNUC__ >= 3
+# define EK(y...)	EX(y)
+#else
+# define EK(y,x...)	x
+#endif
+
+GLOBAL_ENTRY(bcopy)
+	.regstk 3,0,0,0
+	mov r8=in0
+	mov in0=in1
+	;;
+	mov in1=r8
+	;;
+END(bcopy)
+
+/* McKinley specific optimization */
+
+#define retval		r8
+#define saved_pfs	r31
+#define saved_lc	r10
+#define saved_pr	r11
+#define saved_in0	r14
+#define saved_in1	r15
+#define saved_in2	r16
+
+#define src0		r2
+#define src1		r3
+#define dst0		r17
+#define dst1		r18
+#define cnt		r9
+
+/* r19-r30 are temp for each code section */
+#define PREFETCH_DIST	8
+#define src_pre_mem	r19
+#define dst_pre_mem	r20
+#define src_pre_l2	r21
+#define dst_pre_l2	r22
+#define t1		r23
+#define t2		r24
+#define t3		r25
+#define t4		r26
+#define t5		t1	// alias!
+#define t6		t2	// alias!
+#define t7		t3	// alias!
+#define n8		r27
+#define t9		t5	// alias!
+#define t10		t4	// alias!
+#define t11		t7	// alias!
+#define t12		t6	// alias!
+#define t14		t10	// alias!
+#define t13		r28
+#define t15		r29
+#define tmp		r30
+
+/* defines for long_copy block */
+#define	A	0
+#define B	(PREFETCH_DIST)
+#define C	(B + PREFETCH_DIST)
+#define D	(C + 1)
+#define N	(D + 1)
+#define Nrot	((N + 7) & ~7)
+
+/* alias */
+#define in0		r32
+#define in1		r33
+#define in2		r34
+
+GLOBAL_ENTRY(memcpy)
+	and	r28=0x7,in0
+	and	r29=0x7,in1
+	mov	f6=f0
+	br.cond.sptk .common_code
+	;;
+END(memcpy)
+GLOBAL_ENTRY(__copy_user)
+	.prologue
+// check dest alignment
+	and	r28=0x7,in0
+	and	r29=0x7,in1
+	mov	f6=f1
+	mov	saved_in0=in0	// save dest pointer
+	mov	saved_in1=in1	// save src pointer
+	mov	saved_in2=in2	// save len
+	;;
+.common_code:
+	cmp.gt	p15,p0=8,in2	// check for small size
+	cmp.ne	p13,p0=0,r28	// check dest alignment
+	cmp.ne	p14,p0=0,r29	// check src alignment
+	add	src0=0,in1
+	sub	r30=8,r28	// for .align_dest
+	mov	retval=r0	// initialize return value
+	;;
+	add	dst0=0,in0
+	add	dst1=1,in0	// dest odd index
+	cmp.le	p6,p0 = 1,r30	// for .align_dest
+(p15)	br.cond.dpnt .memcpy_short
+(p13)	br.cond.dpnt .align_dest
+(p14)	br.cond.dpnt .unaligned_src
+	;;
+
+// both dest and src are aligned on 8-byte boundary
+.aligned_src:
+	.save ar.pfs, saved_pfs
+	alloc	saved_pfs=ar.pfs,3,Nrot-3,0,Nrot
+	.save pr, saved_pr
+	mov	saved_pr=pr
+
+	shr.u	cnt=in2,7	// this much cache line
+	;;
+	cmp.lt	p6,p0=2*PREFETCH_DIST,cnt
+	cmp.lt	p7,p8=1,cnt
+	.save ar.lc, saved_lc
+	mov	saved_lc=ar.lc
+	.body
+	add	cnt=-1,cnt
+	add	src_pre_mem=0,in1	// prefetch src pointer
+	add	dst_pre_mem=0,in0	// prefetch dest pointer
+	;;
+(p7)	mov	ar.lc=cnt	// prefetch count
+(p8)	mov	ar.lc=r0
+(p6)	br.cond.dpnt .long_copy
+	;;
+
+.prefetch:
+	lfetch	  [src_pre_mem], 128
+	lfetch.excl [dst_pre_mem], 128
+	br.cloop.dptk.few .prefetch
+	;;
+
+.medium_copy:
+	and	tmp=31,in2	// copy length after iteration
+	shr.u	r29=in2,5	// number of 32-byte iteration
+	add	dst1=8,dst0	// 2nd dest pointer
+	;;
+	add	cnt=-1,r29	// ctop iteration adjustment
+	cmp.eq	p10,p0=r29,r0	// do we really need to loop?
+	add	src1=8,src0	// 2nd src pointer
+	cmp.le	p6,p0=8,tmp
+	;;
+	cmp.le	p7,p0=16,tmp
+	mov	ar.lc=cnt	// loop setup
+	cmp.eq	p16,p17 = r0,r0
+	mov	ar.ec=2
+(p10)	br.dpnt.few .aligned_src_tail
+	;;
+	.align 32
+1:
+EX(.ex_handler, (p16)	ld8	r34=[src0],16)
+EK(.ex_handler, (p16)	ld8	r38=[src1],16)
+EX(.ex_handler, (p17)	st8	[dst0]=r33,16)
+EK(.ex_handler, (p17)	st8	[dst1]=r37,16)
+	;;
+EX(.ex_handler, (p16)	ld8	r32=[src0],16)
+EK(.ex_handler, (p16)	ld8	r36=[src1],16)
+EX(.ex_handler, (p16)	st8	[dst0]=r34,16)
+EK(.ex_handler, (p16)	st8	[dst1]=r38,16)
+	br.ctop.dptk.few 1b
+	;;
+
+.aligned_src_tail:
+EX(.ex_handler, (p6)	ld8	t1=[src0])
+	mov	ar.lc=saved_lc
+	mov	ar.pfs=saved_pfs
+EX(.ex_hndlr_s, (p7)	ld8	t2=[src1],8)
+	cmp.le	p8,p0=24,tmp
+	and	r21=-8,tmp
+	;;
+EX(.ex_hndlr_s, (p8)	ld8	t3=[src1])
+EX(.ex_handler, (p6)	st8	[dst0]=t1)	// store byte 1
+	and	in2=7,tmp	// remaining length
+EX(.ex_hndlr_d, (p7)	st8	[dst1]=t2,8)	// store byte 2
+	add	src0=src0,r21	// setting up src pointer
+	add	dst0=dst0,r21	// setting up dest pointer
+	;;
+EX(.ex_handler, (p8)	st8	[dst1]=t3)	// store byte 3
+	mov	pr=saved_pr,-1
+	br.dptk.many .memcpy_short
+	;;
+
+/* code taken from copy_page_mck */
+.long_copy:
+	.rotr v[2*PREFETCH_DIST]
+	.rotp p[N]
+
+	mov src_pre_mem = src0
+	mov pr.rot = 0x10000
+	mov ar.ec = 1				// special unrolled loop
+
+	mov dst_pre_mem = dst0
+
+	add src_pre_l2 = 8*8, src0
+	add dst_pre_l2 = 8*8, dst0
+	;;
+	add src0 = 8, src_pre_mem		// first t1 src
+	mov ar.lc = 2*PREFETCH_DIST - 1
+	shr.u cnt=in2,7				// number of lines
+	add src1 = 3*8, src_pre_mem		// first t3 src
+	add dst0 = 8, dst_pre_mem		// first t1 dst
+	add dst1 = 3*8, dst_pre_mem		// first t3 dst
+	;;
+	and tmp=127,in2				// remaining bytes after this block
+	add cnt = -(2*PREFETCH_DIST) - 1, cnt
+	// same as .line_copy loop, but with all predicated-off instructions removed:
+.prefetch_loop:
+EX(.ex_hndlr_lcpy_1, (p[A])	ld8 v[A] = [src_pre_mem], 128)		// M0
+EK(.ex_hndlr_lcpy_1, (p[B])	st8 [dst_pre_mem] = v[B], 128)		// M2
+	br.ctop.sptk .prefetch_loop
+	;;
+	cmp.eq p16, p0 = r0, r0			// reset p16 to 1
+	mov ar.lc = cnt
+	mov ar.ec = N				// # of stages in pipeline
+	;;
+.line_copy:
+EX(.ex_handler,	(p[D])	ld8 t2 = [src0], 3*8)			// M0
+EK(.ex_handler,	(p[D])	ld8 t4 = [src1], 3*8)			// M1
+EX(.ex_handler_lcpy,	(p[B])	st8 [dst_pre_mem] = v[B], 128)		// M2 prefetch dst from memory
+EK(.ex_handler_lcpy,	(p[D])	st8 [dst_pre_l2] = n8, 128)		// M3 prefetch dst from L2
+	;;
+EX(.ex_handler_lcpy,	(p[A])	ld8 v[A] = [src_pre_mem], 128)		// M0 prefetch src from memory
+EK(.ex_handler_lcpy,	(p[C])	ld8 n8 = [src_pre_l2], 128)		// M1 prefetch src from L2
+EX(.ex_handler,	(p[D])	st8 [dst0] =  t1, 8)			// M2
+EK(.ex_handler,	(p[D])	st8 [dst1] =  t3, 8)			// M3
+	;;
+EX(.ex_handler,	(p[D])	ld8  t5 = [src0], 8)
+EK(.ex_handler,	(p[D])	ld8  t7 = [src1], 3*8)
+EX(.ex_handler,	(p[D])	st8 [dst0] =  t2, 3*8)
+EK(.ex_handler,	(p[D])	st8 [dst1] =  t4, 3*8)
+	;;
+EX(.ex_handler,	(p[D])	ld8  t6 = [src0], 3*8)
+EK(.ex_handler,	(p[D])	ld8 t10 = [src1], 8)
+EX(.ex_handler,	(p[D])	st8 [dst0] =  t5, 8)
+EK(.ex_handler,	(p[D])	st8 [dst1] =  t7, 3*8)
+	;;
+EX(.ex_handler,	(p[D])	ld8  t9 = [src0], 3*8)
+EK(.ex_handler,	(p[D])	ld8 t11 = [src1], 3*8)
+EX(.ex_handler,	(p[D])	st8 [dst0] =  t6, 3*8)
+EK(.ex_handler,	(p[D])	st8 [dst1] = t10, 8)
+	;;
+EX(.ex_handler,	(p[D])	ld8 t12 = [src0], 8)
+EK(.ex_handler,	(p[D])	ld8 t14 = [src1], 8)
+EX(.ex_handler,	(p[D])	st8 [dst0] =  t9, 3*8)
+EK(.ex_handler,	(p[D])	st8 [dst1] = t11, 3*8)
+	;;
+EX(.ex_handler,	(p[D])	ld8 t13 = [src0], 4*8)
+EK(.ex_handler,	(p[D])	ld8 t15 = [src1], 4*8)
+EX(.ex_handler,	(p[D])	st8 [dst0] = t12, 8)
+EK(.ex_handler,	(p[D])	st8 [dst1] = t14, 8)
+	;;
+EX(.ex_handler,	(p[C])	ld8  t1 = [src0], 8)
+EK(.ex_handler,	(p[C])	ld8  t3 = [src1], 8)
+EX(.ex_handler,	(p[D])	st8 [dst0] = t13, 4*8)
+EK(.ex_handler,	(p[D])	st8 [dst1] = t15, 4*8)
+	br.ctop.sptk .line_copy
+	;;
+
+	add dst0=-8,dst0
+	add src0=-8,src0
+	mov in2=tmp
+	.restore sp
+	br.sptk.many .medium_copy
+	;;
+
+#define BLOCK_SIZE	128*32
+#define blocksize	r23
+#define curlen		r24
+
+// dest is on 8-byte boundary, src is not. We need to do
+// ld8-ld8, shrp, then st8.  Max 8 byte copy per cycle.
+.unaligned_src:
+	.prologue
+	.save ar.pfs, saved_pfs
+	alloc	saved_pfs=ar.pfs,3,5,0,8
+	.save ar.lc, saved_lc
+	mov	saved_lc=ar.lc
+	.save pr, saved_pr
+	mov	saved_pr=pr
+	.body
+.4k_block:
+	mov	saved_in0=dst0	// need to save all input arguments
+	mov	saved_in2=in2
+	mov	blocksize=BLOCK_SIZE
+	;;
+	cmp.lt	p6,p7=blocksize,in2
+	mov	saved_in1=src0
+	;;
+(p6)	mov	in2=blocksize
+	;;
+	shr.u	r21=in2,7	// this much cache line
+	shr.u	r22=in2,4	// number of 16-byte iteration
+	and	curlen=15,in2	// copy length after iteration
+	and	r30=7,src0	// source alignment
+	;;
+	cmp.lt	p7,p8=1,r21
+	add	cnt=-1,r21
+	;;
+
+	add	src_pre_mem=0,src0	// prefetch src pointer
+	add	dst_pre_mem=0,dst0	// prefetch dest pointer
+	and	src0=-8,src0		// 1st src pointer
+(p7)	mov	ar.lc = r21
+(p8)	mov	ar.lc = r0
+	;;
+	.align 32
+1:	lfetch	  [src_pre_mem], 128
+	lfetch.excl [dst_pre_mem], 128
+	br.cloop.dptk.few 1b
+	;;
+
+	shladd	dst1=r22,3,dst0	// 2nd dest pointer
+	shladd	src1=r22,3,src0	// 2nd src pointer
+	cmp.eq	p8,p9=r22,r0	// do we really need to loop?
+	cmp.le	p6,p7=8,curlen;	// have at least 8 byte remaining?
+	add	cnt=-1,r22	// ctop iteration adjustment
+	;;
+EX(.ex_handler, (p9)	ld8	r33=[src0],8)	// loop primer
+EK(.ex_handler, (p9)	ld8	r37=[src1],8)
+(p8)	br.dpnt.few .noloop
+	;;
+
+// The jump address is calculated based on src alignment. The COPYU
+// macro below need to confine its size to power of two, so an entry
+// can be caulated using shl instead of an expensive multiply. The
+// size is then hard coded by the following #define to match the
+// actual size.  This make it somewhat tedious when COPYU macro gets
+// changed and this need to be adjusted to match.
+#define LOOP_SIZE 6
+1:
+	mov	r29=ip		// jmp_table thread
+	mov	ar.lc=cnt
+	;;
+	add	r29=.jump_table - 1b - (.jmp1-.jump_table), r29
+	shl	r28=r30, LOOP_SIZE	// jmp_table thread
+	mov	ar.ec=2		// loop setup
+	;;
+	add	r29=r29,r28		// jmp_table thread
+	cmp.eq	p16,p17=r0,r0
+	;;
+	mov	b6=r29			// jmp_table thread
+	;;
+	br.cond.sptk.few b6
+
+// for 8-15 byte case
+// We will skip the loop, but need to replicate the side effect
+// that the loop produces.
+.noloop:
+EX(.ex_handler, (p6)	ld8	r37=[src1],8)
+	add	src0=8,src0
+(p6)	shl	r25=r30,3
+	;;
+EX(.ex_handler, (p6)	ld8	r27=[src1])
+(p6)	shr.u	r28=r37,r25
+(p6)	sub	r26=64,r25
+	;;
+(p6)	shl	r27=r27,r26
+	;;
+(p6)	or	r21=r28,r27
+
+.unaligned_src_tail:
+/* check if we have more than blocksize to copy, if so go back */
+	cmp.gt	p8,p0=saved_in2,blocksize
+	;;
+(p8)	add	dst0=saved_in0,blocksize
+(p8)	add	src0=saved_in1,blocksize
+(p8)	sub	in2=saved_in2,blocksize
+(p8)	br.dpnt	.4k_block
+	;;
+
+/* we have up to 15 byte to copy in the tail.
+ * part of work is already done in the jump table code
+ * we are at the following state.
+ * src side:
+ * 
+ *   xxxxxx xx                   <----- r21 has xxxxxxxx already
+ * -------- -------- --------
+ * 0        8        16
+ *          ^
+ *          |
+ *          src1
+ * 
+ * dst
+ * -------- -------- --------
+ * ^
+ * |
+ * dst1
+ */
+EX(.ex_handler, (p6)	st8	[dst1]=r21,8)	// more than 8 byte to copy
+(p6)	add	curlen=-8,curlen	// update length
+	mov	ar.pfs=saved_pfs
+	;;
+	mov	ar.lc=saved_lc
+	mov	pr=saved_pr,-1
+	mov	in2=curlen	// remaining length
+	mov	dst0=dst1	// dest pointer
+	add	src0=src1,r30	// forward by src alignment
+	;;
+
+// 7 byte or smaller.
+.memcpy_short:
+	cmp.le	p8,p9   = 1,in2
+	cmp.le	p10,p11 = 2,in2
+	cmp.le	p12,p13 = 3,in2
+	cmp.le	p14,p15 = 4,in2
+	add	src1=1,src0	// second src pointer
+	add	dst1=1,dst0	// second dest pointer
+	;;
+
+EX(.ex_handler_short, (p8)	ld1	t1=[src0],2)
+EK(.ex_handler_short, (p10)	ld1	t2=[src1],2)
+(p9)	br.ret.dpnt rp		// 0 byte copy
+	;;
+
+EX(.ex_handler_short, (p8)	st1	[dst0]=t1,2)
+EK(.ex_handler_short, (p10)	st1	[dst1]=t2,2)
+(p11)	br.ret.dpnt rp		// 1 byte copy
+
+EX(.ex_handler_short, (p12)	ld1	t3=[src0],2)
+EK(.ex_handler_short, (p14)	ld1	t4=[src1],2)
+(p13)	br.ret.dpnt rp		// 2 byte copy
+	;;
+
+	cmp.le	p6,p7   = 5,in2
+	cmp.le	p8,p9   = 6,in2
+	cmp.le	p10,p11 = 7,in2
+
+EX(.ex_handler_short, (p12)	st1	[dst0]=t3,2)
+EK(.ex_handler_short, (p14)	st1	[dst1]=t4,2)
+(p15)	br.ret.dpnt rp		// 3 byte copy
+	;;
+
+EX(.ex_handler_short, (p6)	ld1	t5=[src0],2)
+EK(.ex_handler_short, (p8)	ld1	t6=[src1],2)
+(p7)	br.ret.dpnt rp		// 4 byte copy
+	;;
+
+EX(.ex_handler_short, (p6)	st1	[dst0]=t5,2)
+EK(.ex_handler_short, (p8)	st1	[dst1]=t6,2)
+(p9)	br.ret.dptk rp		// 5 byte copy
+
+EX(.ex_handler_short, (p10)	ld1	t7=[src0],2)
+(p11)	br.ret.dptk rp		// 6 byte copy
+	;;
+
+EX(.ex_handler_short, (p10)	st1	[dst0]=t7,2)
+	br.ret.dptk rp		// done all cases
+
+
+/* Align dest to nearest 8-byte boundary. We know we have at
+ * least 7 bytes to copy, enough to crawl to 8-byte boundary.
+ * Actual number of byte to crawl depend on the dest alignment.
+ * 7 byte or less is taken care at .memcpy_short
+
+ * src0 - source even index
+ * src1 - source  odd index
+ * dst0 - dest even index
+ * dst1 - dest  odd index
+ * r30  - distance to 8-byte boundary
+ */
+
+.align_dest:
+	add	src1=1,in1	// source odd index
+	cmp.le	p7,p0 = 2,r30	// for .align_dest
+	cmp.le	p8,p0 = 3,r30	// for .align_dest
+EX(.ex_handler_short, (p6)	ld1	t1=[src0],2)
+	cmp.le	p9,p0 = 4,r30	// for .align_dest
+	cmp.le	p10,p0 = 5,r30
+	;;
+EX(.ex_handler_short, (p7)	ld1	t2=[src1],2)
+EK(.ex_handler_short, (p8)	ld1	t3=[src0],2)
+	cmp.le	p11,p0 = 6,r30
+EX(.ex_handler_short, (p6)	st1	[dst0] = t1,2)
+	cmp.le	p12,p0 = 7,r30
+	;;
+EX(.ex_handler_short, (p9)	ld1	t4=[src1],2)
+EK(.ex_handler_short, (p10)	ld1	t5=[src0],2)
+EX(.ex_handler_short, (p7)	st1	[dst1] = t2,2)
+EK(.ex_handler_short, (p8)	st1	[dst0] = t3,2)
+	;;
+EX(.ex_handler_short, (p11)	ld1	t6=[src1],2)
+EK(.ex_handler_short, (p12)	ld1	t7=[src0],2)
+	cmp.eq	p6,p7=r28,r29
+EX(.ex_handler_short, (p9)	st1	[dst1] = t4,2)
+EK(.ex_handler_short, (p10)	st1	[dst0] = t5,2)
+	sub	in2=in2,r30
+	;;
+EX(.ex_handler_short, (p11)	st1	[dst1] = t6,2)
+EK(.ex_handler_short, (p12)	st1	[dst0] = t7)
+	add	dst0=in0,r30	// setup arguments
+	add	src0=in1,r30
+(p6)	br.cond.dptk .aligned_src
+(p7)	br.cond.dpnt .unaligned_src
+	;;
+
+/* main loop body in jump table format */
+#define COPYU(shift)									\
+1:											\
+EX(.ex_handler,  (p16)	ld8	r32=[src0],8);		/* 1 */				\
+EK(.ex_handler,  (p16)	ld8	r36=[src1],8);						\
+		 (p17)	shrp	r35=r33,r34,shift;;	/* 1 */				\
+EX(.ex_handler,  (p6)	ld8	r22=[src1]);	/* common, prime for tail section */	\
+		 nop.m	0;								\
+		 (p16)	shrp	r38=r36,r37,shift;					\
+EX(.ex_handler,  (p17)	st8	[dst0]=r35,8);		/* 1 */				\
+EK(.ex_handler,  (p17)	st8	[dst1]=r39,8);						\
+		 br.ctop.dptk.few 1b;;							\
+		 (p7)	add	src1=-8,src1;	/* back out for <8 byte case */		\
+		 shrp	r21=r22,r38,shift;	/* speculative work */			\
+		 br.sptk.few .unaligned_src_tail /* branch out of jump table */		\
+		 ;;
+	.align 32
+.jump_table:
+	COPYU(8)	// unaligned cases
+.jmp1:
+	COPYU(16)
+	COPYU(24)
+	COPYU(32)
+	COPYU(40)
+	COPYU(48)
+	COPYU(56)
+
+#undef A
+#undef B
+#undef C
+#undef D
+END(memcpy)
+
+/*
+ * Due to lack of local tag support in gcc 2.x assembler, it is not clear which
+ * instruction failed in the bundle.  The exception algorithm is that we
+ * first figure out the faulting address, then detect if there is any
+ * progress made on the copy, if so, redo the copy from last known copied
+ * location up to the faulting address (exclusive). In the copy_from_user
+ * case, remaining byte in kernel buffer will be zeroed.
+ *
+ * Take copy_from_user as an example, in the code there are multiple loads
+ * in a bundle and those multiple loads could span over two pages, the
+ * faulting address is calculated as page_round_down(max(src0, src1)).
+ * This is based on knowledge that if we can access one byte in a page, we
+ * can access any byte in that page.
+ *
+ * predicate used in the exception handler:
+ * p6-p7: direction
+ * p10-p11: src faulting addr calculation
+ * p12-p13: dst faulting addr calculation
+ */
+
+#define A	r19
+#define B	r20
+#define C	r21
+#define D	r22
+#define F	r28
+
+#define memset_arg0	r32
+#define memset_arg2	r33
+
+#define saved_retval	loc0
+#define saved_rtlink	loc1
+#define saved_pfs_stack	loc2
+
+.ex_hndlr_s:
+	add	src0=8,src0
+	br.sptk .ex_handler
+	;;
+.ex_hndlr_d:
+	add	dst0=8,dst0
+	br.sptk .ex_handler
+	;;
+.ex_hndlr_lcpy_1:
+	mov	src1=src_pre_mem
+	mov	dst1=dst_pre_mem
+	cmp.gtu	p10,p11=src_pre_mem,saved_in1
+	cmp.gtu	p12,p13=dst_pre_mem,saved_in0
+	;;
+(p10)	add	src0=8,saved_in1
+(p11)	mov	src0=saved_in1
+(p12)	add	dst0=8,saved_in0
+(p13)	mov	dst0=saved_in0
+	br.sptk	.ex_handler
+.ex_handler_lcpy:
+	// in line_copy block, the preload addresses should always ahead
+	// of the other two src/dst pointers.  Furthermore, src1/dst1 should
+	// always ahead of src0/dst0.
+	mov	src1=src_pre_mem
+	mov	dst1=dst_pre_mem
+.ex_handler:
+	mov	pr=saved_pr,-1		// first restore pr, lc, and pfs
+	mov	ar.lc=saved_lc
+	mov	ar.pfs=saved_pfs
+	;;
+.ex_handler_short: // fault occurred in these sections didn't change pr, lc, pfs
+	cmp.ltu	p6,p7=saved_in0, saved_in1	// get the copy direction
+	cmp.ltu	p10,p11=src0,src1
+	cmp.ltu	p12,p13=dst0,dst1
+	fcmp.eq	p8,p0=f6,f0		// is it memcpy?
+	mov	tmp = dst0
+	;;
+(p11)	mov	src1 = src0		// pick the larger of the two
+(p13)	mov	dst0 = dst1		// make dst0 the smaller one
+(p13)	mov	dst1 = tmp		// and dst1 the larger one
+	;;
+(p6)	dep	F = r0,dst1,0,PAGE_SHIFT // usr dst round down to page boundary
+(p7)	dep	F = r0,src1,0,PAGE_SHIFT // usr src round down to page boundary
+	;;
+(p6)	cmp.le	p14,p0=dst0,saved_in0	// no progress has been made on store
+(p7)	cmp.le	p14,p0=src0,saved_in1	// no progress has been made on load
+	mov	retval=saved_in2
+(p8)	ld1	tmp=[src1]		// force an oops for memcpy call
+(p8)	st1	[dst1]=r0		// force an oops for memcpy call
+(p14)	br.ret.sptk.many rp
+
+/*
+ * The remaining byte to copy is calculated as:
+ *
+ * A =	(faulting_addr - orig_src)	-> len to faulting ld address
+ *	or 
+ * 	(faulting_addr - orig_dst)	-> len to faulting st address
+ * B =	(cur_dst - orig_dst)		-> len copied so far
+ * C =	A - B				-> len need to be copied
+ * D =	orig_len - A			-> len need to be zeroed
+ */
+(p6)	sub	A = F, saved_in0
+(p7)	sub	A = F, saved_in1
+	clrrrb
+	;;
+	alloc	saved_pfs_stack=ar.pfs,3,3,3,0
+	sub	B = dst0, saved_in0	// how many byte copied so far
+	;;
+	sub	C = A, B
+	sub	D = saved_in2, A
+	;;
+	cmp.gt	p8,p0=C,r0		// more than 1 byte?
+	add	memset_arg0=saved_in0, A
+(p6)	mov	memset_arg2=0		// copy_to_user should not call memset
+(p7)	mov	memset_arg2=D		// copy_from_user need to have kbuf zeroed
+	mov	r8=0
+	mov	saved_retval = D
+	mov	saved_rtlink = b0
+
+	add	out0=saved_in0, B
+	add	out1=saved_in1, B
+	mov	out2=C
+(p8)	br.call.sptk.few b0=__copy_user	// recursive call
+	;;
+
+	add	saved_retval=saved_retval,r8	// above might return non-zero value
+	cmp.gt	p8,p0=memset_arg2,r0	// more than 1 byte?
+	mov	out0=memset_arg0	// *s
+	mov	out1=r0			// c
+	mov	out2=memset_arg2	// n
+(p8)	br.call.sptk.few b0=memset
+	;;
+
+	mov	retval=saved_retval
+	mov	ar.pfs=saved_pfs_stack
+	mov	b0=saved_rtlink
+	br.ret.sptk.many rp
+
+/* end of McKinley specific optimization */
+END(__copy_user)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/lib/memset.S linux-2.4.20/arch/ia64/lib/memset.S
--- linux-2.4.19/arch/ia64/lib/memset.S	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/arch/ia64/lib/memset.S	2002-10-29 11:18:40.000000000 +0000
@@ -1,108 +1,362 @@
-/*
- *
- * Optimized version of the standard memset() function
- *
- * Return: none
- *
- * Inputs:
- *	in0:	address of buffer
- * 	in1:	byte value to use for storing
- *	in2:	length of the buffer
- *
- * Copyright (C) 1999, 2001 Hewlett-Packard Co
- * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
- */
+/* Optimized version of the standard memset() function.
+
+   Copyright (c) 2002 Hewlett-Packard Co/CERN
+	Sverre Jarp <Sverre.Jarp@cern.ch>
+
+   Return: dest
+
+   Inputs:
+        in0:    dest
+        in1:    value
+        in2:    count
+
+   The algorithm is fairly straightforward: set byte by byte until we
+   we get to a 16B-aligned address, then loop on 128 B chunks using an
+   early store as prefetching, then loop on 32B chucks, then clear remaining
+   words, finally clear remaining bytes.
+   Since a stf.spill f0 can store 16B in one go, we use this instruction
+   to get peak speed when value = 0.  */
 
 #include <asm/asmmacro.h>
+#undef ret
+
+#define dest		in0
+#define value		in1
+#define	cnt		in2
 
-// arguments
-//
-#define buf		r32
-#define val		r33
-#define len		r34
-
-//
-// local registers
-//
-#define saved_pfs	r14
-#define cnt		r18
-#define buf2		r19
-#define saved_lc	r20
-#define tmp		r21
+#define tmp		r31
+#define save_lc		r30
+#define ptr0		r29
+#define ptr1		r28
+#define ptr2		r27
+#define ptr3		r26
+#define ptr9 		r24
+#define	loopcnt		r23
+#define linecnt		r22
+#define bytecnt		r21
+
+#define fvalue		f6
+
+// This routine uses only scratch predicate registers (p6 - p15)
+#define p_scr		p6			// default register for same-cycle branches
+#define p_nz		p7
+#define p_zr		p8
+#define p_unalgn	p9
+#define p_y		p11
+#define p_n		p12
+#define p_yy		p13
+#define p_nn		p14
+
+#define MIN1		15
+#define MIN1P1HALF	8
+#define LINE_SIZE	128
+#define LSIZE_SH        7			// shift amount
+#define PREF_AHEAD	8
 
 GLOBAL_ENTRY(memset)
+{ .mmi
 	.prologue
-	.save ar.pfs, saved_pfs
- 	alloc saved_pfs=ar.pfs,3,0,0,0	// cnt is sink here
-	cmp.eq p8,p0=r0,len	// check for zero length
-	.save ar.lc, saved_lc
-	mov saved_lc=ar.lc	// preserve ar.lc (slow)
-	;;
-
+	alloc	tmp = ar.pfs, 3, 0, 0, 0
 	.body
+	lfetch.nt1 [dest]			//
+	.save   ar.lc, save_lc
+	mov.i	save_lc = ar.lc
+} { .mmi
+	mov	ret0 = dest			// return value
+	cmp.ne	p_nz, p_zr = value, r0		// use stf.spill if value is zero
+	cmp.eq	p_scr, p0 = cnt, r0
+;; }
+{ .mmi
+	and	ptr2 = -(MIN1+1), dest		// aligned address
+	and	tmp = MIN1, dest		// prepare to check for correct alignment
+	tbit.nz p_y, p_n = dest, 0		// Do we have an odd address? (M_B_U)
+} { .mib
+	mov	ptr1 = dest
+	mux1	value = value, @brcst		// create 8 identical bytes in word
+(p_scr)	br.ret.dpnt.many rp			// return immediately if count = 0
+;; }
+{ .mib
+	cmp.ne	p_unalgn, p0 = tmp, r0		//
+} { .mib
+	sub	bytecnt = (MIN1+1), tmp		// NB: # of bytes to move is 1 higher than loopcnt
+	cmp.gt	p_scr, p0 = 16, cnt		// is it a minimalistic task?
+(p_scr)	br.cond.dptk.many .move_bytes_unaligned	// go move just a few (M_B_U)
+;; }
+{ .mmi
+(p_unalgn) add	ptr1 = (MIN1+1), ptr2		// after alignment
+(p_unalgn) add	ptr2 = MIN1P1HALF, ptr2		// after alignment
+(p_unalgn) tbit.nz.unc p_y, p_n = bytecnt, 3	// should we do a st8 ?
+;; }
+{ .mib
+(p_y)	add	cnt = -8, cnt			//
+(p_unalgn) tbit.nz.unc p_yy, p_nn = bytecnt, 2	// should we do a st4 ?
+} { .mib
+(p_y)	st8	[ptr2] = value,-4		//
+(p_n)	add	ptr2 = 4, ptr2			//
+;; }
+{ .mib
+(p_yy)	add	cnt = -4, cnt			//
+(p_unalgn) tbit.nz.unc p_y, p_n = bytecnt, 1	// should we do a st2 ?
+} { .mib
+(p_yy)	st4	[ptr2] = value,-2		//
+(p_nn)	add	ptr2 = 2, ptr2			//
+;; }
+{ .mmi
+	mov	tmp = LINE_SIZE+1		// for compare
+(p_y)	add	cnt = -2, cnt			//
+(p_unalgn) tbit.nz.unc p_yy, p_nn = bytecnt, 0	// should we do a st1 ?
+} { .mmi
+	setf.sig fvalue=value			// transfer value to FLP side
+(p_y)	st2	[ptr2] = value,-1		//
+(p_n)	add	ptr2 = 1, ptr2			//
+;; }
+
+{ .mmi
+(p_yy)	st1	[ptr2] = value 			//
+  	cmp.gt	p_scr, p0 = tmp, cnt		// is it a minimalistic task?
+} { .mbb
+(p_yy)	add	cnt = -1, cnt			//
+(p_scr)	br.cond.dpnt.many .fraction_of_line	// go move just a few
+;; }
+
+{ .mib
+	nop.m 0
+	shr.u	linecnt = cnt, LSIZE_SH
+(p_zr)	br.cond.dptk.many .l1b			// Jump to use stf.spill
+;; }
+
+	.align 32 // -------------------------- //  L1A: store ahead into cache lines; fill later
+{ .mmi
+	and	tmp = -(LINE_SIZE), cnt		// compute end of range
+	mov	ptr9 = ptr1			// used for prefetching
+	and	cnt = (LINE_SIZE-1), cnt	// remainder
+} { .mmi
+	mov	loopcnt = PREF_AHEAD-1		// default prefetch loop
+	cmp.gt	p_scr, p0 = PREF_AHEAD, linecnt	// check against actual value
+;; }
+{ .mmi
+(p_scr)	add	loopcnt = -1, linecnt		//
+	add	ptr2 = 8, ptr1			// start of stores (beyond prefetch stores)
+	add	ptr1 = tmp, ptr1		// first address beyond total range
+;; }
+{ .mmi
+	add	tmp = -1, linecnt		// next loop count
+	mov.i	ar.lc = loopcnt			//
+;; }
+.pref_l1a:
+{ .mib
+	stf8 [ptr9] = fvalue, 128		// Do stores one cache line apart
+	nop.i	0
+	br.cloop.dptk.few .pref_l1a
+;; }
+{ .mmi
+	add	ptr0 = 16, ptr2			// Two stores in parallel
+	mov.i	ar.lc = tmp			//
+;; }
+.l1ax:
+ { .mmi
+	stf8 [ptr2] = fvalue, 8
+	stf8 [ptr0] = fvalue, 8
+ ;; }
+ { .mmi
+	stf8 [ptr2] = fvalue, 24
+	stf8 [ptr0] = fvalue, 24
+ ;; }
+ { .mmi
+	stf8 [ptr2] = fvalue, 8
+	stf8 [ptr0] = fvalue, 8
+ ;; }
+ { .mmi
+	stf8 [ptr2] = fvalue, 24
+	stf8 [ptr0] = fvalue, 24
+ ;; }
+ { .mmi
+	stf8 [ptr2] = fvalue, 8
+	stf8 [ptr0] = fvalue, 8
+ ;; }
+ { .mmi
+	stf8 [ptr2] = fvalue, 24
+	stf8 [ptr0] = fvalue, 24
+ ;; }
+ { .mmi
+	stf8 [ptr2] = fvalue, 8
+	stf8 [ptr0] = fvalue, 32
+ 	cmp.lt	p_scr, p0 = ptr9, ptr1		// do we need more prefetching?
+ ;; }
+{ .mmb
+	stf8 [ptr2] = fvalue, 24
+(p_scr)	stf8 [ptr9] = fvalue, 128
+	br.cloop.dptk.few .l1ax
+;; }
+{ .mbb
+	cmp.le  p_scr, p0 = 8, cnt		// just a few bytes left ?
+(p_scr) br.cond.dpnt.many  .fraction_of_line	// Branch no. 2
+	br.cond.dpnt.many  .move_bytes_from_alignment	// Branch no. 3
+;; }
+
+	.align 32
+.l1b:	// ------------------------------------ //  L1B: store ahead into cache lines; fill later
+{ .mmi
+	and	tmp = -(LINE_SIZE), cnt		// compute end of range
+	mov	ptr9 = ptr1			// used for prefetching
+	and	cnt = (LINE_SIZE-1), cnt	// remainder
+} { .mmi
+	mov	loopcnt = PREF_AHEAD-1		// default prefetch loop
+	cmp.gt	p_scr, p0 = PREF_AHEAD, linecnt	// check against actual value
+;; }
+{ .mmi
+(p_scr)	add	loopcnt = -1, linecnt
+	add	ptr2 = 16, ptr1			// start of stores (beyond prefetch stores)
+	add	ptr1 = tmp, ptr1		// first address beyond total range
+;; }
+{ .mmi
+	add	tmp = -1, linecnt		// next loop count
+	mov.i	ar.lc = loopcnt
+;; }
+.pref_l1b:
+{ .mib
+	stf.spill [ptr9] = f0, 128		// Do stores one cache line apart
+	nop.i   0
+	br.cloop.dptk.few .pref_l1b
+;; }
+{ .mmi
+	add	ptr0 = 16, ptr2			// Two stores in parallel
+	mov.i	ar.lc = tmp
+;; }
+.l1bx:
+ { .mmi
+	stf.spill [ptr2] = f0, 32
+	stf.spill [ptr0] = f0, 32
+ ;; }
+ { .mmi
+	stf.spill [ptr2] = f0, 32
+	stf.spill [ptr0] = f0, 32
+ ;; }
+ { .mmi
+	stf.spill [ptr2] = f0, 32
+	stf.spill [ptr0] = f0, 64
+ 	cmp.lt	p_scr, p0 = ptr9, ptr1		// do we need more prefetching?
+ ;; }
+{ .mmb
+	stf.spill [ptr2] = f0, 32
+(p_scr)	stf.spill [ptr9] = f0, 128
+	br.cloop.dptk.few .l1bx
+;; }
+{ .mib
+	cmp.gt  p_scr, p0 = 8, cnt		// just a few bytes left ?
+(p_scr)	br.cond.dpnt.many  .move_bytes_from_alignment	//
+;; }
+
+.fraction_of_line:
+{ .mib
+	add	ptr2 = 16, ptr1
+	shr.u	loopcnt = cnt, 5   		// loopcnt = cnt / 32
+;; }
+{ .mib
+	cmp.eq	p_scr, p0 = loopcnt, r0
+	add	loopcnt = -1, loopcnt
+(p_scr)	br.cond.dpnt.many .store_words
+;; }
+{ .mib
+	and	cnt = 0x1f, cnt			// compute the remaining cnt
+	mov.i   ar.lc = loopcnt
+;; }
+	.align 32
+.l2:	// ------------------------------------ //  L2A:  store 32B in 2 cycles
+{ .mmb
+	stf8	[ptr1] = fvalue, 8
+	stf8	[ptr2] = fvalue, 8
+;; } { .mmb
+	stf8	[ptr1] = fvalue, 24
+	stf8	[ptr2] = fvalue, 24
+	br.cloop.dptk.many .l2
+;; }
+.store_words:
+{ .mib
+	cmp.gt	p_scr, p0 = 8, cnt		// just a few bytes left ?
+(p_scr)	br.cond.dpnt.many .move_bytes_from_alignment	// Branch
+;; }
+
+{ .mmi
+	stf8	[ptr1] = fvalue, 8		// store
+	cmp.le	p_y, p_n = 16, cnt
+	add	cnt = -8, cnt			// subtract
+;; }
+{ .mmi
+(p_y)	stf8	[ptr1] = fvalue, 8		// store
+(p_y)	cmp.le.unc p_yy, p_nn = 16, cnt
+(p_y)	add	cnt = -8, cnt			// subtract
+;; }
+{ .mmi						// store
+(p_yy)	stf8	[ptr1] = fvalue, 8
+(p_yy)	add	cnt = -8, cnt			// subtract
+;; }
+
+.move_bytes_from_alignment:
+{ .mib
+	cmp.eq	p_scr, p0 = cnt, r0
+	tbit.nz.unc p_y, p0 = cnt, 2		// should we terminate with a st4 ?
+(p_scr)	br.cond.dpnt.few .restore_and_exit
+;; }
+{ .mib
+(p_y)	st4	[ptr1] = value,4
+	tbit.nz.unc p_yy, p0 = cnt, 1		// should we terminate with a st2 ?
+;; }
+{ .mib
+(p_yy)	st2	[ptr1] = value,2
+	tbit.nz.unc p_y, p0 = cnt, 0		// should we terminate with a st1 ?
+;; }
+
+{ .mib
+(p_y)	st1	[ptr1] = value
+;; }
+.restore_and_exit:
+{ .mib
+	nop.m	0
+	mov.i	ar.lc = save_lc
+	br.ret.sptk.many rp
+;; }
 
-	adds tmp=-1,len		// br.ctop is repeat/until
-	tbit.nz p6,p0=buf,0	// odd alignment
-(p8)	br.ret.spnt.many rp
-
-	cmp.lt p7,p0=16,len	// if len > 16 then long memset
-	mux1 val=val,@brcst	// prepare value
-(p7)	br.cond.dptk .long_memset
-	;;
-	mov ar.lc=tmp		// initialize lc for small count
-	;;			// avoid RAW and WAW on ar.lc
-1:				// worst case 15 cyles, avg 8 cycles
-	st1 [buf]=val,1
-	br.cloop.dptk.few 1b
-	;;				// avoid RAW on ar.lc
-	mov ar.lc=saved_lc
-	mov ar.pfs=saved_pfs
-	br.ret.sptk.many rp	// end of short memset
-
-	// at this point we know we have more than 16 bytes to copy
-	// so we focus on alignment
-.long_memset:
-(p6)	st1 [buf]=val,1		// 1-byte aligned
-(p6)	adds len=-1,len;;	// sync because buf is modified
-	tbit.nz p6,p0=buf,1
-	;;
-(p6)	st2 [buf]=val,2		// 2-byte aligned
-(p6)	adds len=-2,len;;
-	tbit.nz p6,p0=buf,2
-	;;
-(p6)	st4 [buf]=val,4		// 4-byte aligned
-(p6)	adds len=-4,len;;
-	tbit.nz p6,p0=buf,3
-	;;
-(p6)	st8 [buf]=val,8		// 8-byte aligned
-(p6)	adds len=-8,len;;
-	shr.u cnt=len,4		// number of 128-bit (2x64bit) words
-	;;
-	cmp.eq p6,p0=r0,cnt
-	adds tmp=-1,cnt
-(p6)	br.cond.dpnt .dotail	// we have less than 16 bytes left
-	;;
-	adds buf2=8,buf		// setup second base pointer
-	mov ar.lc=tmp
-	;;
-2:				// 16bytes/iteration
-	st8 [buf]=val,16
-	st8 [buf2]=val,16
-	br.cloop.dptk.few 2b
-	;;
-.dotail:			// tail correction based on len only
-	tbit.nz p6,p0=len,3
-	;;
-(p6)	st8 [buf]=val,8		// at least 8 bytes
-	tbit.nz p6,p0=len,2
-	;;
-(p6)	st4 [buf]=val,4		// at least 4 bytes
-	tbit.nz p6,p0=len,1
-	;;
-(p6)	st2 [buf]=val,2		// at least 2 bytes
-	tbit.nz p6,p0=len,0
-	mov ar.lc=saved_lc
-	;;
-(p6)	st1 [buf]=val		// only 1 byte left
+.move_bytes_unaligned:
+{ .mmi
+       .pred.rel "mutex",p_y, p_n
+       .pred.rel "mutex",p_yy, p_nn
+(p_n)	cmp.le  p_yy, p_nn = 4, cnt
+(p_y)	cmp.le  p_yy, p_nn = 5, cnt
+(p_n)	add	ptr2 = 2, ptr1
+} { .mmi
+(p_y)	add	ptr2 = 3, ptr1
+(p_y)	st1	[ptr1] = value, 1		// fill 1 (odd-aligned) byte [15, 14 (or less) left]
+(p_y)	add	cnt = -1, cnt
+;; }
+{ .mmi
+(p_yy)	cmp.le.unc p_y, p0 = 8, cnt
+	add	ptr3 = ptr1, cnt		// prepare last store
+	mov.i	ar.lc = save_lc
+} { .mmi
+(p_yy)	st2	[ptr1] = value, 4		// fill 2 (aligned) bytes
+(p_yy)	st2	[ptr2] = value, 4		// fill 2 (aligned) bytes [11, 10 (o less) left]
+(p_yy)	add	cnt = -4, cnt
+;; }
+{ .mmi
+(p_y)	cmp.le.unc p_yy, p0 = 8, cnt
+	add	ptr3 = -1, ptr3			// last store
+	tbit.nz p_scr, p0 = cnt, 1		// will there be a st2 at the end ?
+} { .mmi
+(p_y)	st2	[ptr1] = value, 4		// fill 2 (aligned) bytes
+(p_y)	st2	[ptr2] = value, 4		// fill 2 (aligned) bytes [7, 6 (or less) left]
+(p_y)	add	cnt = -4, cnt
+;; }
+{ .mmi
+(p_yy)	st2	[ptr1] = value, 4		// fill 2 (aligned) bytes
+(p_yy)	st2	[ptr2] = value, 4		// fill 2 (aligned) bytes [3, 2 (or less) left]
+	tbit.nz p_y, p0 = cnt, 0		// will there be a st1 at the end ?
+} { .mmi
+(p_yy)	add	cnt = -4, cnt
+;; }
+{ .mmb
+(p_scr)	st2	[ptr1] = value			// fill 2 (aligned) bytes
+(p_y)	st1	[ptr3] = value			// fill last byte (using ptr3)
 	br.ret.sptk.many rp
+}
 END(memset)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/lib/swiotlb.c linux-2.4.20/arch/ia64/lib/swiotlb.c
--- linux-2.4.19/arch/ia64/lib/swiotlb.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/lib/swiotlb.c	2002-10-29 11:18:49.000000000 +0000
@@ -277,8 +277,11 @@
 	int gfp = GFP_ATOMIC;
 	void *ret;
 
-	if (!hwdev || hwdev->dma_mask <= 0xffffffff)
-		gfp |= GFP_DMA; /* XXX fix me: should change this to GFP_32BIT or ZONE_32BIT */
+	/*
+	 * Alloc_consistent() is defined to return memory < 4GB, no matter what the DMA
+	 * mask says.
+	 */
+	gfp |= GFP_DMA;	/* XXX fix me: should change this to GFP_32BIT or ZONE_32BIT */
 	ret = (void *)__get_free_pages(gfp, get_order(size));
 	if (!ret)
 		return NULL;
@@ -486,6 +489,17 @@
 	return SG_ENT_PHYS_ADDRESS(sg);
 }
 
+/*
+ * Return whether the given PCI device DMA address mask can be supported properly.  For
+ * example, if your device can only drive the low 24-bits during PCI bus mastering, then
+ * you would pass 0x00ffffff as the mask to this function.
+ */
+int
+swiotlb_pci_dma_supported (struct pci_dev *hwdev, u64 mask)
+{
+	return 1;
+}
+
 EXPORT_SYMBOL(swiotlb_init);
 EXPORT_SYMBOL(swiotlb_map_single);
 EXPORT_SYMBOL(swiotlb_unmap_single);
@@ -496,3 +510,4 @@
 EXPORT_SYMBOL(swiotlb_dma_address);
 EXPORT_SYMBOL(swiotlb_alloc_consistent);
 EXPORT_SYMBOL(swiotlb_free_consistent);
+EXPORT_SYMBOL(swiotlb_pci_dma_supported);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/mm/fault.c linux-2.4.20/arch/ia64/mm/fault.c
--- linux-2.4.19/arch/ia64/mm/fault.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/mm/fault.c	2002-10-29 11:18:50.000000000 +0000
@@ -49,7 +49,6 @@
 	int signal = SIGSEGV, code = SEGV_MAPERR;
 	struct vm_area_struct *vma, *prev_vma;
 	struct mm_struct *mm = current->mm;
-	struct exception_fixup fix;
 	struct siginfo si;
 	unsigned long mask;
 
@@ -59,6 +58,17 @@
 	if (in_interrupt() || !mm)
 		goto no_context;
 
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+	/*
+	 * If fault is in region 5 and we are in the kernel, we may already
+         * have the mmap_sem (VALID_PAGE macro is called during mmap). There
+	 * should be no vma for region 5 addr's anyway, so skip getting the
+	 * semaphore and go directly to the code that handles a bad area.
+  	 */
+	if ((REGION_NUMBER(address) == 5) && !user_mode(regs))
+		goto bad_area_no_up;
+#endif
+
 	down_read(&mm->mmap_sem);
 
 	vma = find_vma_prev(mm, address, &prev_vma);
@@ -138,10 +148,16 @@
 
   bad_area:
 	up_read(&mm->mmap_sem);
-	if (isr & IA64_ISR_SP) {
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+  bad_area_no_up:
+#endif
+	if ((isr & IA64_ISR_SP)
+	    || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH))
+	{
 		/*
-		 * This fault was due to a speculative load set the "ed" bit in the psr to
-		 * ensure forward progress (target register will get a NaT).
+		 * This fault was due to a speculative load or lfetch.fault, set the "ed"
+		 * bit in the psr to ensure forward progress.  (Target register will get a
+		 * NaT for ld.s, lfetch will be canceled.)
 		 */
 		ia64_psr(regs)->ed = 1;
 		return;
@@ -167,15 +183,8 @@
 		return;
 	}
 
-#ifdef GAS_HAS_LOCAL_TAGS
-	fix = search_exception_table(regs->cr_iip + ia64_psr(regs)->ri);
-#else
-	fix = search_exception_table(regs->cr_iip);
-#endif
-	if (fix.cont) {
-		handle_exception(regs, fix);
+	if (done_with_exception(regs))
 		return;
-	}
 
 	/*
 	 * Oops. The kernel tried to access some bad page. We'll have to terminate things
@@ -194,13 +203,11 @@
 	return;
 
   out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (current->pid == 1) {
-		current->policy |= SCHED_YIELD;
-		schedule();
-		down_read(&mm->mmap_sem);
+		yield();
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/mm/init.c linux-2.4.20/arch/ia64/mm/init.c
--- linux-2.4.19/arch/ia64/mm/init.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/mm/init.c	2002-10-29 11:18:39.000000000 +0000
@@ -1,8 +1,8 @@
 /*
  * Initialize MMU support.
  *
- * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -10,13 +10,14 @@
 
 #include <linux/bootmem.h>
 #include <linux/mm.h>
+#include <linux/personality.h>
 #include <linux/reboot.h>
 #include <linux/slab.h>
 #include <linux/swap.h>
+#include <linux/efi.h>
 
 #include <asm/bitops.h>
 #include <asm/dma.h>
-#include <asm/efi.h>
 #include <asm/ia32.h>
 #include <asm/io.h>
 #include <asm/machvec.h>
@@ -37,6 +38,13 @@
 
 static unsigned long totalram_pages;
 
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+unsigned long vmalloc_end = VMALLOC_END_INIT;
+
+static struct page *vmem_map;
+static unsigned long num_dma_physpages;
+#endif
+
 int
 do_check_pgt_cache (int low, int high)
 {
@@ -67,10 +75,9 @@
 	struct vm_area_struct *vma;
 
 	/*
-	 * If we're out of memory and kmem_cache_alloc() returns NULL,
-	 * we simply ignore the problem.  When the process attempts to
-	 * write to the register backing store for the first time, it
-	 * will get a SEGFAULT in this case.
+	 * If we're out of memory and kmem_cache_alloc() returns NULL, we simply ignore
+	 * the problem.  When the process attempts to write to the register backing store
+	 * for the first time, it will get a SEGFAULT in this case.
 	 */
 	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (vma) {
@@ -85,6 +92,19 @@
 		vma->vm_private_data = NULL;
 		insert_vm_struct(current->mm, vma);
 	}
+
+	/* map NaT-page at address zero to speed up speculative dereferencing of NULL: */
+	if (!(current->personality & MMAP_PAGE_ZERO)) {
+		vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+		if (vma) {
+			memset(vma, 0, sizeof(*vma));
+			vma->vm_mm = current->mm;
+			vma->vm_end = PAGE_SIZE;
+			vma->vm_page_prot = __pgprot(pgprot_val(PAGE_READONLY) | _PAGE_MA_NAT);
+			vma->vm_flags = VM_READ | VM_MAYREAD | VM_IO | VM_RESERVED;
+			insert_vm_struct(current->mm, vma);
+		}
+	}
 }
 
 void
@@ -99,7 +119,7 @@
 		free_page(addr);
 		++totalram_pages;
 	}
-	printk (KERN_INFO "Freeing unused kernel memory: %ldkB freed\n",
+	printk(KERN_INFO "Freeing unused kernel memory: %ldkB freed\n",
 		(&__init_end - &__init_begin) >> 10);
 }
 
@@ -141,7 +161,7 @@
 	end = end & PAGE_MASK;
 
 	if (start < end)
-		printk (KERN_INFO "Freeing initrd memory: %ldkB freed\n", (end - start) >> 10);
+		printk(KERN_INFO "Freeing initrd memory: %ldkB freed\n", (end - start) >> 10);
 
 	for (; start < end; start += PAGE_SIZE) {
 		if (!VALID_PAGE(virt_to_page(start)))
@@ -204,6 +224,8 @@
 	printk("Free swap:       %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
 	i = max_mapnr;
 	while (i-- > 0) {
+		if (!VALID_PAGE(mem_map + i))
+			continue;
 		total++;
 		if (PageReserved(mem_map+i))
 			reserved++;
@@ -261,7 +283,7 @@
 void __init
 ia64_mmu_init (void *my_cpu_data)
 {
-	unsigned long flags, rid, pta, impl_va_bits;
+	unsigned long psr, rid, pta, impl_va_bits;
 	extern void __init tlb_init (void);
 #ifdef CONFIG_DISABLE_VHPT
 #	define VHPT_ENABLE_BIT	0
@@ -273,7 +295,7 @@
 	 * Set up the kernel identity mapping for regions 6 and 5.  The mapping for region
 	 * 7 is setup up in _start().
 	 */
-	ia64_clear_ic(flags);
+	psr = ia64_clear_ic();
 
 	rid = ia64_rid(IA64_REGION_ID_KERNEL, __IA64_UNCACHED_OFFSET);
 	ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (IA64_GRANULE_SHIFT << 2));
@@ -287,7 +309,7 @@
 	ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR,
 		 pte_val(mk_pte_phys(__pa(my_cpu_data), PAGE_KERNEL)), PAGE_SHIFT);
 
-	__restore_flags(flags);
+	ia64_set_psr(psr);
 	ia64_srlz_i();
 
 	/*
@@ -335,6 +357,135 @@
 	ia64_tlb_init();
 }
 
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+
+#include <asm/pgtable.h>
+
+static int
+create_mem_map_page_table (u64 start, u64 end, void *arg)
+{
+	unsigned long address, start_page, end_page;
+	struct page *map_start, *map_end;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	/* should we use platform_map_nr here? */
+
+	map_start = vmem_map + MAP_NR_DENSE(start);
+	map_end   = vmem_map + MAP_NR_DENSE(end);
+
+	start_page = (unsigned long) map_start & PAGE_MASK;
+	end_page = PAGE_ALIGN((unsigned long) map_end);
+
+	for (address = start_page; address < end_page; address += PAGE_SIZE) {
+		pgd = pgd_offset_k(address);
+		if (pgd_none(*pgd))
+			pgd_populate(&init_mm, pgd, alloc_bootmem_pages(PAGE_SIZE));
+		pmd = pmd_offset(pgd, address);
+
+		if (pmd_none(*pmd))
+			pmd_populate(&init_mm, pmd, alloc_bootmem_pages(PAGE_SIZE));
+		pte = pte_offset(pmd, address);
+
+		if (pte_none(*pte))
+			set_pte(pte, mk_pte_phys(__pa(alloc_bootmem_pages(PAGE_SIZE)),
+						 PAGE_KERNEL));
+ 	}
+ 	return 0;
+}
+
+struct memmap_init_callback_data {
+	memmap_init_callback_t *memmap_init;
+	struct page *start;
+	struct page *end;
+	int zone;
+	int highmem;
+};
+
+static int
+virtual_memmap_init (u64 start, u64 end, void *arg)
+{
+	struct memmap_init_callback_data *args;
+	struct page *map_start, *map_end;
+
+	args = (struct memmap_init_callback_data *) arg;
+
+	/* Should we use platform_map_nr here? */
+
+	map_start = vmem_map + MAP_NR_DENSE(start);
+	map_end   = vmem_map + MAP_NR_DENSE(end);
+
+	if (map_start < args->start)
+		map_start = args->start;
+	if (map_end > args->end)
+		map_end = args->end;
+
+	/*
+	 * We have to initialize "out of bounds" struct page elements
+	 * that fit completely on the same pages that were allocated
+	 * for the "in bounds" elements because they may be referenced
+	 * later (and found to be "reserved").
+	 */
+	map_start -= ((unsigned long) map_start & (PAGE_SIZE - 1))
+			/ sizeof(struct page);
+	map_end += ((PAGE_ALIGN((unsigned long) map_end) -
+				(unsigned long) map_end)
+			/ sizeof(struct page));
+
+	if (map_start < map_end)
+		(*args->memmap_init)(map_start, map_end, args->zone,
+				     page_to_phys(map_start), args->highmem);
+
+	return 0;
+}
+
+unsigned long
+arch_memmap_init (memmap_init_callback_t *memmap_init, struct page *start,
+	struct page *end, int zone, unsigned long start_paddr, int highmem)
+{
+	struct memmap_init_callback_data args;
+
+	args.memmap_init = memmap_init;
+	args.start = start;
+	args.end = end;
+	args.zone = zone;
+	args.highmem = highmem;
+
+	efi_memmap_walk(virtual_memmap_init, &args);
+
+	return page_to_phys(end);
+}
+
+static int
+count_dma_pages (u64 start, u64 end, void *arg)
+{
+	unsigned long *count = arg;
+
+	if (end <= MAX_DMA_ADDRESS)
+		*count += (end - start) >> PAGE_SHIFT;
+	return 0;
+}
+
+int
+ia64_page_valid (struct page *page)
+{
+	char byte;
+
+	return __get_user(byte, (char *) page) == 0;
+}
+
+#endif /* CONFIG_VIRTUAL_MEM_MAP */
+
+static int
+count_pages (u64 start, u64 end, void *arg)
+{
+	unsigned long *count = arg;
+
+	*count += (end - start) >> PAGE_SHIFT;
+	return 0;
+}
+
 /*
  * Set up the page tables.
  */
@@ -343,13 +494,49 @@
 {
 	unsigned long max_dma, zones_size[MAX_NR_ZONES];
 
-	clear_page((void *) ZERO_PAGE_ADDR);
-
 	/* initialize mem_map[] */
 
 	memset(zones_size, 0, sizeof(zones_size));
 
+	num_physpages = 0;
+	efi_memmap_walk(count_pages, &num_physpages);
+
 	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+	{
+		unsigned long zholes_size[MAX_NR_ZONES];
+		unsigned long map_size;
+
+		memset(zholes_size, 0, sizeof(zholes_size));
+
+		num_dma_physpages = 0;
+		efi_memmap_walk(count_dma_pages, &num_dma_physpages);
+
+		if (max_low_pfn < max_dma) {
+			zones_size[ZONE_DMA] = max_low_pfn;
+			zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
+		} else {
+			zones_size[ZONE_DMA] = max_dma;
+			zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
+			if (num_physpages > num_dma_physpages) {
+				zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
+				zholes_size[ZONE_NORMAL] = ((max_low_pfn - max_dma)
+							    - (num_physpages - num_dma_physpages));
+			}
+		}
+
+		/* allocate virtual mem_map: */
+
+		map_size = PAGE_ALIGN(max_low_pfn*sizeof(struct page));
+		vmalloc_end -= map_size;
+		vmem_map = (struct page *) vmalloc_end;
+		efi_memmap_walk(create_mem_map_page_table, 0);
+
+		free_area_init_node(0, NULL, vmem_map, zones_size, 0, zholes_size);
+		printk("Virtual mem_map starts at 0x%p\n", mem_map);
+	}
+#else /* !CONFIG_VIRTUAL_MEM_MAP */
 	if (max_low_pfn < max_dma)
 		zones_size[ZONE_DMA] = max_low_pfn;
 	else {
@@ -357,15 +544,7 @@
 		zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
 	}
 	free_area_init(zones_size);
-}
-
-static int
-count_pages (u64 start, u64 end, void *arg)
-{
-	unsigned long *count = arg;
-
-	*count += (end - start) >> PAGE_SHIFT;
-	return 0;
+#endif /* !CONFIG_VIRTUAL_MEM_MAP */
 }
 
 static int
@@ -401,9 +580,6 @@
 	if (!mem_map)
 		BUG();
 
-	num_physpages = 0;
-	efi_memmap_walk(count_pages, &num_physpages);
-
 	max_mapnr = max_low_pfn;
 	high_memory = __va(max_low_pfn * PAGE_SIZE);
 
@@ -416,10 +592,10 @@
 	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
 	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
 
-	printk("Memory: %luk/%luk available (%luk code, %luk reserved, %luk data, %luk init)\n",
+	printk(KERN_INFO "Memory: %luk/%luk available (%luk code, %luk reserved, %luk data, %luk init)\n",
 	       (unsigned long) nr_free_pages() << (PAGE_SHIFT - 10),
-	       max_mapnr << (PAGE_SHIFT - 10), codesize >> 10, reserved_pages << (PAGE_SHIFT - 10),
-	       datasize >> 10, initsize >> 10);
+	       num_physpages << (PAGE_SHIFT - 10), codesize >> 10,
+	       reserved_pages << (PAGE_SHIFT - 10), datasize >> 10, initsize >> 10);
 
 	/*
 	 * Allow for enough (cached) page table pages so that we can map the entire memory
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/mm/tlb.c linux-2.4.20/arch/ia64/mm/tlb.c
--- linux-2.4.19/arch/ia64/mm/tlb.c	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/arch/ia64/mm/tlb.c	2002-10-29 11:18:49.000000000 +0000
@@ -79,7 +79,7 @@
 	flush_tlb_all();
 }
 
-static inline void
+void
 ia64_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits)
 {
 	static spinlock_t ptcg_lock = SPIN_LOCK_UNLOCKED;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/sn/fakeprom/README linux-2.4.20/arch/ia64/sn/fakeprom/README
--- linux-2.4.19/arch/ia64/sn/fakeprom/README	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/sn/fakeprom/README	2002-10-29 11:18:40.000000000 +0000
@@ -71,7 +71,7 @@
     1GB*<dn>, where dn is the digit number. The amount of memory
     is 8MB*2**<d>. (If <d> = 0, the memory size is 0).
 
-    SN1 doesnt support dimms this small but small memory systems 
+    SN1 doesn't support dimms this small but small memory systems 
     boot faster on Medusa.
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/sn/fakeprom/fpmem.c linux-2.4.20/arch/ia64/sn/fakeprom/fpmem.c
--- linux-2.4.19/arch/ia64/sn/fakeprom/fpmem.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/sn/fakeprom/fpmem.c	2002-10-29 11:18:38.000000000 +0000
@@ -18,7 +18,7 @@
  */
 
 #include <linux/config.h>
-#include <asm/efi.h>
+#include <linux/efi.h>
 #include "fpmem.h"
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/sn/fakeprom/fw-emu.c linux-2.4.20/arch/ia64/sn/fakeprom/fw-emu.c
--- linux-2.4.19/arch/ia64/sn/fakeprom/fw-emu.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/sn/fakeprom/fw-emu.c	2002-10-29 11:18:34.000000000 +0000
@@ -36,7 +36,7 @@
  * http://oss.sgi.com/projects/GenInfo/NoticeExplan
  */
 #include <linux/config.h>
-#include <asm/efi.h>
+#include <linux/efi.h>
 #include <asm/pal.h>
 #include <asm/sal.h>
 #include <asm/sn/sn_sal.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/sn/io/Makefile linux-2.4.20/arch/ia64/sn/io/Makefile
--- linux-2.4.19/arch/ia64/sn/io/Makefile	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/sn/io/Makefile	2002-10-29 11:18:35.000000000 +0000
@@ -18,7 +18,7 @@
 O_TARGET := sgiio.o
 
 ifeq ($(CONFIG_MODULES),y)
-export-objs = pciio.o hcl.o
+export-objs = pciio.o hcl.o pci_dma.o
 endif
 
 obj-y  := stubs.o sgi_if.o pciio.o xtalk.o xbow.o xswitch.o klgraph_hack.o \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/sn/io/efi-rtc.c linux-2.4.20/arch/ia64/sn/io/efi-rtc.c
--- linux-2.4.19/arch/ia64/sn/io/efi-rtc.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.20/arch/ia64/sn/io/efi-rtc.c	2002-10-29 11:18:32.000000000 +0000
@@ -12,7 +12,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/errno.h>
-#include <asm/efi.h>
+#include <linux/efi.h>
 #include <asm/sn/klclock.h>
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/sn/io/pci_dma.c linux-2.4.20/arch/ia64/sn/io/pci_dma.c
--- linux-2.4.19/arch/ia64/sn/io/pci_dma.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ia64/sn/io/pci_dma.c	2002-10-29 11:18:35.000000000 +0000
@@ -4,6 +4,9 @@
  * for more details.
  *
  * Copyright (C) 2000,2002 Silicon Graphics, Inc. All rights reserved.
+ *
+ * Routines for PCI DMA mapping.  See Documentation/DMA-mapping.txt for
+ * a description of how these routines should be used.
  */
 
 #include <linux/types.h>
@@ -12,6 +15,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/module.h>
 
 #include <asm/delay.h>
 #include <asm/io.h>
@@ -27,15 +31,38 @@
 #include <asm/sn/pci/pci_bus_cvlink.h>
 #include <asm/sn/nag.h>
 
+/* DMA, PIO, and memory allocation flags */
+#ifdef CONFIG_IA64_SGI_SN1
+#define DMA_DATA_FLAGS		( PCIIO_BYTE_STREAM | PCIIO_DMA_DATA )
+#define DMA_CONTROL_FLAGS	( PCIIO_BYTE_STREAM | PCIBR_BARRIER | \
+				  PCIIO_DMA_CMD )
+#elif defined(CONFIG_IA64_SGI_SN2)
+#define DMA_DATA_FLAGS		( PCIIO_DMA_DATA )
+#define DMA_CONTROL_FLAGS	( PCIBR_BARRIER | PCIIO_DMA_CMD )
+#else
+#error need to define DMA mapping flags for this platform
+#endif
+
+/*
+ * For ATE allocations
+ */
 pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t);
 void free_pciio_dmamap(pcibr_dmamap_t);
-struct sn_dma_maps_s *find_sn_dma_map(dma_addr_t, unsigned char);
+static struct sn_dma_maps_s *find_sn_dma_map(dma_addr_t, unsigned char);
+
+/*
+ * Toplogy stuff
+ */
 extern devfs_handle_t busnum_to_pcibr_vhdl[];
 extern nasid_t busnum_to_nid[];
 extern void * busnum_to_atedmamaps[];
 
-/*
- * Get a free pciio_dmamap_t entry.
+/**
+ * get_free_pciio_dmamap - find and allocate an ATE
+ * @pci_bus: PCI bus to get an entry for
+ *
+ * Finds and allocates an ATE on the PCI bus specified
+ * by @pci_bus.
  */
 pciio_dmamap_t
 get_free_pciio_dmamap(devfs_handle_t pci_bus)
@@ -46,7 +73,7 @@
 	/*
 	 * Darn, we need to get the maps allocated for this bus.
 	 */
-	for (i=0; i<MAX_PCI_XWIDGET; i++) {
+	for (i = 0; i < MAX_PCI_XWIDGET; i++) {
 		if (busnum_to_pcibr_vhdl[i] == pci_bus) {
 			sn_dma_map = busnum_to_atedmamaps[i];
 		}
@@ -55,19 +82,21 @@
 	/*
 	 * Now get a free dmamap entry from this list.
 	 */
-	for (i=0; i<MAX_ATE_MAPS; i++, sn_dma_map++) {
+	for (i = 0; i < MAX_ATE_MAPS; i++, sn_dma_map++) {
 		if (!sn_dma_map->dma_addr) {
 			sn_dma_map->dma_addr = -1;
 			return( (pciio_dmamap_t) sn_dma_map );
 		}
 	}
 
-	return(NULL);
-
+	return NULL;
 }
 
-/*
- * Free pciio_dmamap_t entry.
+/**
+ * free_pciio_dmamap - free an ATE
+ * @dma_map: ATE to free
+ *
+ * Frees the ATE specified by @dma_map.
  */
 void
 free_pciio_dmamap(pcibr_dmamap_t dma_map)
@@ -76,177 +105,229 @@
 
 	sn_dma_map = (struct sn_dma_maps_s *) dma_map;
 	sn_dma_map->dma_addr = 0;
+}
+
+/**
+ * find_sn_dma_map - find an ATE associated with @dma_addr and @busnum
+ * @dma_addr: DMA address to look for
+ * @busnum: PCI bus to look on
+ *
+ * Finds the ATE associated with @dma_addr and @busnum.
+ */
+static struct sn_dma_maps_s *
+find_sn_dma_map(dma_addr_t dma_addr, unsigned char busnum)
+{
+
+	struct sn_dma_maps_s *sn_dma_map = NULL;
+	int i;
+
+	sn_dma_map = busnum_to_atedmamaps[busnum];
+
+	for (i = 0; i < MAX_ATE_MAPS; i++, sn_dma_map++) {
+		if (sn_dma_map->dma_addr == dma_addr) {
+			return sn_dma_map;
+		}
+	}
 
+	printk(KERN_WARNING "find_sn_dma_map: Unable find the corresponding "
+	       "dma map\n");
+
+	return NULL;
 }
 
-/*
- * sn_dma_sync: This routine flushes all DMA buffers for the device into the II.
- *	This does not mean that the data is in the "Coherence Domain".  But it 
- *	is very close.
+/**
+ * sn_dma_sync - try to flush DMA buffers into the coherence domain
+ * @hwdev: device to flush
+ *
+ * This routine flushes all DMA buffers for the device into the II of
+ * the destination hub.
+ *
+ * NOTE!: this does not mean that the data is in the "coherence domain",
+ * but it is very close.  In other words, this routine *does not work*
+ * as advertised due to hardware bugs.  That said, it should be good enough for
+ * most situations.
  */
 void
-sn_dma_sync( struct pci_dev *hwdev )
+sn_dma_sync(struct pci_dev *hwdev)
 {
 
 	struct sn_device_sysdata *device_sysdata;
 	volatile unsigned long dummy;
 
 	/*
-	 * It is expected that on IA64 platform, a DMA sync ensures that all 
-	 * the DMA (dma_handle) are complete and coherent.
-	 *	1. Flush Write Buffers from Bridge.
-	 *	2. Flush Xbow Port.
+	 * It is expected that on an IA64 platform, a DMA sync ensures that 
+	 * all the DMA from a particular device is complete and coherent.  We
+	 * try to do this by
+	 *	1. flushing the write wuffers from Bridge
+	 *	2. flushing the Xbow port.
+	 * Unfortunately, this only gets the DMA transactions 'very close' to
+	 * the coherence domain, but not quite in it.
 	 */
 	device_sysdata = (struct sn_device_sysdata *)hwdev->sysdata;
 	dummy = (volatile unsigned long ) *device_sysdata->dma_buf_sync;
 
 	/*
-	 * For the Xbow Port flush, we maybe denied the request because 
-	 * someone else may be flushing the Port .. try again.
+	 * For the Xbow port flush, we maybe denied the request because 
+	 * someone else may be flushing the port .. try again.
 	 */
 	while((volatile unsigned long ) *device_sysdata->xbow_buf_sync) {
 		udelay(2);
 	}
 }
 
-
-struct sn_dma_maps_s *
-find_sn_dma_map(dma_addr_t dma_addr, unsigned char busnum)
-{
-
-	struct sn_dma_maps_s *sn_dma_map = NULL;
-	int i;
-
-	sn_dma_map = busnum_to_atedmamaps[busnum];
-
-	for (i=0; i<MAX_ATE_MAPS; i++, sn_dma_map++) {
-		if (sn_dma_map->dma_addr == dma_addr) {
-			return( sn_dma_map );
-		}
-	}
-
-printk("find_pciio_dmamap: Unable find the corresponding dma map\n");
-
-	return(NULL);
-
-}
-
-/*
- * sn1 platform specific pci_alloc_consistent()
+/**
+ * sn_pci_alloc_consistent - allocate memory for coherent DMA
+ * @hwdev: device to allocate for
+ * @size: size of the region
+ * @dma_handle: DMA (bus) address
+ *
+ * pci_alloc_consistent() returns a pointer to a memory region suitable for
+ * coherent DMA traffic to/from a PCI device.  On SN platforms, this means
+ * that @dma_handle will have the PCIBR_BARRIER and PCIIO_DMA_CMD flags
+ * set.
  *
- * this interface is meant for "command" streams, i.e. called only
- * once for initializing a device, so we don't want prefetching or
- * write gathering turned on, hence the PCIIO_DMA_CMD flag
+ * This interface is usually used for "command" streams (e.g. the command
+ * queue for a SCSI controller).  See Documentation/DMA-mapping.txt for
+ * more information.  Note that this routine should always put a 32 bit
+ * DMA address into @dma_handle.  This is because most other platforms
+ * that are capable of 64 bit PCI DMA transactions can't do 64 bit _coherent_
+ * DMAs, and unfortunately this interface has to cater to the LCD.  Oh well.
+ *
+ * Also known as platform_pci_alloc_consistent() by the IA64 machvec code.
  */
 void *
-sn_pci_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
+sn_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
 {
-        void *ret;
-        int gfp = GFP_ATOMIC;
-	devfs_handle_t    vhdl;
+        void *cpuaddr;
+	devfs_handle_t vhdl;
 	struct sn_device_sysdata *device_sysdata;
-	paddr_t temp_ptr;
+	unsigned long phys_addr;
+	pciio_dmamap_t dma_map = 0;
+	struct sn_dma_maps_s *sn_dma_map;
 
-	*dma_handle = (dma_addr_t) NULL;
+	*dma_handle = 0;
+
+	/* We can't easily support < 32 bit devices */
+	if (IS_PCI32L(hwdev))
+		return NULL;
 
 	/*
-	 * get vertex for the device
+	 * Get hwgraph vertex for the device
 	 */
 	device_sysdata = (struct sn_device_sysdata *) hwdev->sysdata;
 	vhdl = device_sysdata->vhdl;
 
-        if ( (ret = (void *)__get_free_pages(gfp, get_order(size))) ) {
-		memset(ret, 0, size);
-	} else {
-		return(NULL);
-	}
-
-	temp_ptr = (paddr_t) __pa(ret);
-	if (IS_PCIA64(hwdev)) {
+	/*
+	 * Allocate the memory.  FIXME: if we're allocating for
+	 * two devices on the same bus, we should at least try to
+	 * allocate memory in the same 2 GB window to avoid using
+	 * ATEs for the translation.  See the comment above about the
+	 * 32 bit requirement for this function.
+	 */
+	if(!(cpuaddr = (void *)__get_free_pages(GFP_ATOMIC, get_order(size))))
+		return NULL;
 
-		/*
-		 * This device supports 64bits DMA addresses.
-		 */
-#ifdef CONFIG_IA64_SGI_SN1
-		*dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size,
-			PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD
-			| PCIIO_DMA_A64 );
-#else /* SN2 */
-		*dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size,
-			PCIBR_BARRIER | PCIIO_DMA_CMD | PCIIO_DMA_A64 );
-#endif
+	memset(cpuaddr, 0, size); /* have to zero it out */
 
-		return (ret);
-	}
+	/* physical addr. of the memory we just got */
+	phys_addr = __pa(cpuaddr);
 
+	*dma_handle = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size,
+					  DMA_CONTROL_FLAGS);
 	/*
-	 * Devices that supports 32 Bits upto 63 Bits DMA Address gets
-	 * 32 Bits DMA addresses.
-	 *
-	 * First try to get 32 Bit Direct Map Support.
+	 * It is a 32 bit card and we cannot do direct mapping,
+	 * so we use an ATE.
 	 */
-	if (IS_PCI32G(hwdev)) {
-#ifdef CONFIG_IA64_SGI_SN1
-		*dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size,
-			PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD);
-#else /* SN2 */
-		*dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size,
-			PCIBR_BARRIER | PCIIO_DMA_CMD);
-#endif
-
-		if (dma_handle) {
-			return (ret);
-		} else {
-			/*
-			 * We need to map this request by using ATEs.
-			 */
-			printk("sn_pci_alloc_consistent: 32Bits DMA Page Map support not available yet!");
+	if (!(*dma_handle)) {
+		dma_map = pciio_dmamap_alloc(vhdl, NULL, size,
+					     DMA_CONTROL_FLAGS | PCIIO_FIXED);
+		if (!dma_map) {
+			printk(KERN_ERR "sn_pci_alloc_consistent: Unable to "
+			       "allocate anymore 32 bit page map entries.\n");
 			BUG();
 		}
-	}
-
-	if (IS_PCI32L(hwdev)) {
-		/*
-		 * SNIA64 cannot support DMA Addresses smaller than 32 bits.
-		 */
-		return (NULL);
-	}
+		*dma_handle = (dma_addr_t) pciio_dmamap_addr(dma_map,phys_addr,
+							     size);
+		sn_dma_map = (struct sn_dma_maps_s *)dma_map;
+		sn_dma_map->dma_addr = *dma_handle;
+		printk(KERN_INFO "%s: PMU mapping: %p\n", __FUNCTION__,
+		       (void *)*dma_handle);
+	}
+	else
+		printk(KERN_INFO "%s: direct mapping: %p\n", __FUNCTION__,
+		       (void *)*dma_handle);
+	
 
-        return NULL;
+        return cpuaddr;
 }
 
+/**
+ * sn_pci_free_consistent - free memory associated with coherent DMAable region
+ * @hwdev: device to free for
+ * @size: size to free
+ * @vaddr: kernel virtual address to free
+ * @dma_handle: DMA address associated with this region
+ *
+ * Frees the memory allocated by pci_alloc_consistent().  Also known
+ * as platform_pci_free_consistent() by the IA64 machvec code.
+ */
 void
 sn_pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
 {
+	struct sn_dma_maps_s *sn_dma_map = NULL;
+
+	/*
+	 * Get the sn_dma_map entry.
+	 */
+	if (IS_PCI32_MAPPED(dma_handle))
+		sn_dma_map = find_sn_dma_map(dma_handle, hwdev->bus->number);
+
+	/*
+	 * and free it if necessary...
+	 */
+	if (sn_dma_map) {
+		pciio_dmamap_done((pciio_dmamap_t)sn_dma_map);
+		pciio_dmamap_free((pciio_dmamap_t)sn_dma_map);
+		sn_dma_map->dma_addr = (dma_addr_t)NULL;
+	}
 	free_pages((unsigned long) vaddr, get_order(size));
 }
 
-/*
- * On sn1 we use the page entry of the scatterlist to store
- * the physical address corresponding to the given virtual address
+/**
+ * sn_pci_map_sg - map a scatter-gather list for DMA
+ * @hwdev: device to map for
+ * @sg: scatterlist to map
+ * @nents: number of entries
+ * @direction: direction of the DMA transaction
+ *
+ * Maps each entry of @sg for DMA.  Also known as platform_pci_map_sg by the
+ * IA64 machvec code.
  */
 int
-sn_pci_map_sg (struct pci_dev *hwdev,
-                        struct scatterlist *sg, int nents, int direction)
+sn_pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
 {
 
 	int i;
-	devfs_handle_t	vhdl;
+	devfs_handle_t vhdl;
 	dma_addr_t dma_addr;
-	paddr_t temp_ptr;
+	unsigned long phys_addr;
 	struct sn_device_sysdata *device_sysdata;
 	pciio_dmamap_t dma_map;
 
-
-
+	/* can't go anywhere w/o a direction in life */
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
 	/*
-	 * Handle 64 bit cards.
+	 * Get the hwgraph vertex for the device
 	 */
 	device_sysdata = (struct sn_device_sysdata *) hwdev->sysdata;
 	vhdl = device_sysdata->vhdl;
+
+	/*
+	 * Setup a DMA address for each entry in the
+	 * scatterlist.
+	 */
 	for (i = 0; i < nents; i++, sg++) {
 		/* this catches incorrectly written drivers that
                    attempt to map scatterlists that they have
@@ -262,50 +343,37 @@
 			    "%p - this is currently being worked around.\n",
 			    hwdev->slot_name, (void *)sg->address);
 #endif
-			temp_ptr = (u64)sg->address & TO_PHYS_MASK;
+			phys_addr = (u64)sg->address & TO_PHYS_MASK;
 			break;
-		case 0xe: /* a good address, we now map it. */
-			temp_ptr = (paddr_t) __pa(sg->address);
+		default: /* not previously mapped, get the phys. addr */
+			phys_addr = __pa(sg->address);
 			break;
-		default:
-			printk(KERN_ERR
-			       "Very bad address (%p) passed to sn_pci_map_sg\n",
-			       (void *)sg->address);
-			BUG();
 		}
-		sg->page = (char *)NULL;
+		sg->page = NULL;
 		dma_addr = 0;
 
 		/*
-		 * Handle the most common case 64Bit cards.
+		 * Handle the most common case: 64 bit cards.  This
+		 * call should always succeed.
 		 */
 		if (IS_PCIA64(hwdev)) {
-#ifdef CONFIG_IA64_SGI_SN1
-			dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
-				temp_ptr, sg->length,
-				PCIIO_BYTE_STREAM | PCIIO_DMA_DATA |
-				PCIIO_DMA_A64 );
-#else
-			dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
-				temp_ptr, sg->length,
-				PCIIO_DMA_DATA | PCIIO_DMA_A64 );
-#endif
+			dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr,
+						       sg->length,
+						       DMA_DATA_FLAGS | PCIIO_DMA_A64 );
 			sg->address = (char *)dma_addr;
 			continue;
 		}
 
 		/*
-		 * Handle 32Bits and greater cards.
+		 * Handle 32-63 bit cards via direct mapping
 		 */
 		if (IS_PCI32G(hwdev)) {
-#ifdef CONFIG_IA64_SGI_SN1
-			dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
-				temp_ptr, sg->length,
-				PCIIO_BYTE_STREAM | PCIIO_DMA_DATA);
-#else
-			dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
-				temp_ptr, sg->length, PCIIO_DMA_DATA);
-#endif
+			dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr,
+						       sg->length,
+						       DMA_DATA_FLAGS);
+			/*
+			 * See if we got a direct map entry
+			 */
 			if (dma_addr) {
 				sg->address = (char *)dma_addr;
 				continue;
@@ -314,22 +382,18 @@
 		}
 
 		/*
-		 * It is a 32bit card and we cannot do Direct mapping.
-		 * Let's 32Bit Page map the request.
+		 * It is a 32 bit card and we cannot do direct mapping,
+		 * so we use an ATE.
 		 */
-		dma_map = NULL;
-#ifdef CONFIG_IA64_SGI_SN1
-		dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, 
-				PCIIO_BYTE_STREAM | PCIIO_DMA_DATA);
-#else
-		dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, PCIIO_DMA_DATA);
-#endif
+		dma_map = 0;
+		dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length,
+					     DMA_DATA_FLAGS);
 		if (!dma_map) {
-			printk("pci_map_sg: Unable to allocate anymore 32Bits Page Map entries.\n");
+			printk(KERN_ERR "sn_pci_map_sg: Unable to allocate "
+			       "anymore 32 bit page map entries.\n");
 			BUG();
 		}
-		dma_addr = (dma_addr_t)pciio_dmamap_addr(dma_map, temp_ptr, sg->length);
-		/* printk("pci_map_sg: dma_map 0x%p Phys Addr 0x%p dma_addr 0x%p\n", dma_map, temp_ptr, dma_addr); */
+		dma_addr = pciio_dmamap_addr(dma_map, phys_addr, sg->length);
 		sg->address = (char *)dma_addr;
 		sg->page = (char *)dma_map;
 		
@@ -339,30 +403,34 @@
 
 }
 
-/*
- * Unmap a set of streaming mode DMA translations.
- * Again, cpu read rules concerning calls here are the same as for
- * pci_unmap_single() above.
+/**
+ * sn_pci_unmap_sg - unmap a scatter-gather list
+ * @hwdev: device to unmap
+ * @sg: scatterlist to unmap
+ * @nents: number of scatterlist entries
+ * @direction: DMA direction
+ *
+ * Unmap a set of streaming mode DMA translations.  Again, cpu read rules
+ * concerning calls here are the same as for pci_unmap_single() below.  Also
+ * known as sn_pci_unmap_sg() by the IA64 machvec code.
  */
 void
-sn_pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
+sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
 {
 	int i;
 	struct sn_dma_maps_s *sn_dma_map;
 
-
+	/* can't go anywhere w/o a direction in life */
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
-	for (i = 0; i < nelems; i++, sg++)
+	for (i = 0; i < nents; i++, sg++)
 		if (sg->page) {
 			/*
 			 * We maintain the DMA Map pointer in sg->page if 
 			 * it is ever allocated.
 			 */
-			/* phys_to_virt((dma_addr_t)sg->address | ~0x80000000); */
-			/* sg->address = sg->page; */
-			sg->address = (char *)-1;
+			sg->address = 0;
 			sn_dma_map = (struct sn_dma_maps_s *)sg->page;
 			pciio_dmamap_done((pciio_dmamap_t)sn_dma_map);
 			pciio_dmamap_free((pciio_dmamap_t)sn_dma_map);
@@ -372,7 +440,17 @@
 
 }
 
-/*
+/**
+ * sn_pci_map_single - map a single region for DMA
+ * @hwdev: device to map for
+ * @ptr: kernel virtual address of the region to map
+ * @size: size of the region
+ * @direction: DMA direction
+ *
+ * Map the region pointed to by @ptr for DMA and return the
+ * DMA address.   Also known as platform_pci_map_single() by
+ * the IA64 machvec code.
+ *
  * We map this to the one step pciio_dmamap_trans interface rather than
  * the two step pciio_dmamap_alloc/pciio_dmamap_addr because we have
  * no way of saving the dmamap handle from the alloc to later free
@@ -382,20 +460,21 @@
  *       get rid of dev_desc and vhdl (seems redundant given a pci_dev);
  *       figure out how to save dmamap handle so can use two step.
  */
-dma_addr_t sn_pci_map_single (struct pci_dev *hwdev,
-				void *ptr, size_t size, int direction)
+dma_addr_t
+sn_pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
 {
-	devfs_handle_t	vhdl;
+	devfs_handle_t vhdl;
 	dma_addr_t dma_addr;
-	paddr_t temp_ptr;
+	unsigned long phys_addr;
 	struct sn_device_sysdata *device_sysdata;
 	pciio_dmamap_t dma_map = NULL;
 	struct sn_dma_maps_s *sn_dma_map;
 
-
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
+	/* SN cannot support DMA addresses smaller than 32 bits. */
+	if (IS_PCI32L(hwdev)) return 0;
 
 	/*
 	 * find vertex for the device
@@ -407,79 +486,63 @@
 	 * Call our dmamap interface
 	 */
 	dma_addr = 0;
-	temp_ptr = (paddr_t) __pa(ptr);
+	phys_addr = __pa(ptr);
 
 	if (IS_PCIA64(hwdev)) {
 		/*
-		 * This device supports 64bits DMA addresses.
+		 * This device supports 64 bit DMA addresses.
 		 */
-#ifdef CONFIG_IA64_SGI_SN1
-		dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
-			temp_ptr, size,
-			PCIIO_BYTE_STREAM | PCIIO_DMA_DATA | PCIIO_DMA_A64 );
-#else
-		dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
-			temp_ptr, size, PCIIO_DMA_DATA | PCIIO_DMA_A64 );
-#endif
-		return (dma_addr);
+		dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size,
+					       DMA_DATA_FLAGS | PCIIO_DMA_A64);
+		return dma_addr;
 	}
 
 	/*
-	 * Devices that supports 32 Bits upto 63 Bits DMA Address gets
-	 * 32 Bits DMA addresses.
+	 * Devices that supports 32 bit to 63 bit DMA addresses get
+	 * 32 bit DMA addresses.
 	 *
-	 * First try to get 32 Bit Direct Map Support.
+	 * First try to get a 32 bit direct map register.
 	 */
 	if (IS_PCI32G(hwdev)) {
-#ifdef CONFIG_IA64_SGI_SN1
-		dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
-			temp_ptr, size,
-			PCIIO_BYTE_STREAM | PCIIO_DMA_DATA);
-#else
-		dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL,
-			temp_ptr, size, PCIIO_DMA_DATA);
-#endif
-		if (dma_addr) {
-			return (dma_addr);
-		}
+		dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size,
+					       DMA_DATA_FLAGS);
+		if (dma_addr)
+			return dma_addr;
 	}
 
-	if (IS_PCI32L(hwdev)) {
-		/*
-		 * SNIA64 cannot support DMA Addresses smaller than 32 bits.
-		 */
-		return ((dma_addr_t) NULL);
-        }
-
 	/*
-	 * It is a 32bit card and we cannot do Direct mapping.
-	 * Let's 32Bit Page map the request.
+	 * It's a 32 bit card and we cannot do direct mapping so
+	 * let's use the PMU instead.
 	 */
 	dma_map = NULL;
-#ifdef CONFIG_IA64_SGI_SN1
-	dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIIO_BYTE_STREAM | 
-				     PCIIO_DMA_DATA);
-#else
-	dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIIO_DMA_DATA);
-#endif
+	dma_map = pciio_dmamap_alloc(vhdl, NULL, size, DMA_DATA_FLAGS);
+
 	if (!dma_map) {
-		printk("pci_map_single: Unable to allocate anymore 32Bits Page Map entries.\n");
+		printk(KERN_ERR "pci_map_single: Unable to allocate anymore "
+		       "32 bits page map entries.\n");
 		BUG();
 	}
 
-	dma_addr = (dma_addr_t) pciio_dmamap_addr(dma_map, temp_ptr, size);
-	/* printk("pci_map_single: dma_map 0x%p Phys Addr 0x%p dma_addr 0x%p\n", dma_map,
-		temp_ptr, dma_addr); */
+	dma_addr = (dma_addr_t) pciio_dmamap_addr(dma_map, phys_addr, size);
 	sn_dma_map = (struct sn_dma_maps_s *)dma_map;
 	sn_dma_map->dma_addr = dma_addr;
 
 	return ((dma_addr_t)dma_addr);
 }
 
+/**
+ * sn_pci_unmap_single - unmap a region used for DMA
+ * @hwdev: device to unmap
+ * @dma_addr: DMA address to unmap
+ * @size: size of region
+ * @direction: DMA direction
+ *
+ * Unmaps the region pointed to by @dma_addr.  Also known as
+ * platform_pci_unmap_single() by the IA64 machvec code.
+ */
 void
-sn_pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
+sn_pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
 {
-
 	struct sn_dma_maps_s *sn_dma_map = NULL;
 
         if (direction == PCI_DMA_NONE)
@@ -491,37 +554,97 @@
 	if (IS_PCI32_MAPPED(dma_addr))
 		sn_dma_map = find_sn_dma_map(dma_addr, hwdev->bus->number);
 
+	/*
+	 * and free it if necessary...
+	 */
 	if (sn_dma_map) {
 		pciio_dmamap_done((pciio_dmamap_t)sn_dma_map);
 		pciio_dmamap_free((pciio_dmamap_t)sn_dma_map);
 		sn_dma_map->dma_addr = (dma_addr_t)NULL;
 	}
-
 }
 
+/**
+ * sn_pci_dma_sync_single - make sure all DMAs have completed
+ * @hwdev: device to sync
+ * @dma_handle: DMA address to sync
+ * @size: size of region
+ * @direction: DMA direction
+ *
+ * This routine is supposed to sync the DMA region specified
+ * by @dma_handle into the 'coherence domain'.  See sn_dma_sync()
+ * above for more information.   Also known as
+ * platform_pci_dma_sync_single() by the IA64 machvec code.
+ */
 void
-sn_pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
+sn_pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
 {
-	
-        if (direction == PCI_DMA_NONE)
+	if (direction == PCI_DMA_NONE)
                 BUG();
 
 	sn_dma_sync(hwdev);
-
 }
 
+/**
+ * sn_pci_dma_sync_sg - make sure all DMAs have completed
+ * @hwdev: device to sync
+ * @sg: scatterlist to sync
+ * @nents: number of entries in the scatterlist
+ * @direction: DMA direction
+ *
+ * This routine is supposed to sync the DMA regions specified
+ * by @sg into the 'coherence domain'.  See sn_dma_sync()
+ * above for more information.   Also known as
+ * platform_pci_dma_sync_sg() by the IA64 machvec code.
+ */
 void
-sn_pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
+sn_pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
 {
         if (direction == PCI_DMA_NONE)
                 BUG();
 
 	sn_dma_sync(hwdev);
-
 }
 
+/**
+ * sn_dma_address - get the DMA address for the first entry of a scatterlist
+ * @sg: sg to look at
+ *
+ * Gets the DMA address for the scatterlist @sg.  Also known as
+ * platform_dma_address() by the IA64 machvec code.
+ */
 unsigned long
-sn_dma_address (struct scatterlist *sg)
+sn_dma_address(struct scatterlist *sg)
 {
 	return ((unsigned long)sg->address);
 }
+
+/**
+ * sn_dma_supported - test a DMA mask
+ * @hwdev: device to test
+ * @mask: DMA mask to test
+ *
+ * Return whether the given PCI device DMA address mask can be supported
+ * properly.  For example, if your device can only drive the low 24-bits
+ * during PCI bus mastering, then you would pass 0x00ffffff as the mask to
+ * this function.  Of course, SN only supports devices that have 32 or more
+ * address bits.
+ */
+int
+sn_pci_dma_supported(struct pci_dev *hwdev, u64 mask)
+{
+	if (mask < 0xffffffff)
+		return 0;
+	return 1;
+}
+
+EXPORT_SYMBOL(sn_pci_unmap_single);
+EXPORT_SYMBOL(sn_pci_map_single);
+EXPORT_SYMBOL(sn_pci_dma_sync_single);
+EXPORT_SYMBOL(sn_pci_map_sg);
+EXPORT_SYMBOL(sn_pci_unmap_sg);
+EXPORT_SYMBOL(sn_pci_alloc_consistent);
+EXPORT_SYMBOL(sn_pci_free_consistent);
+EXPORT_SYMBOL(sn_dma_address);
+EXPORT_SYMBOL(sn_pci_dma_supported);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/sn/kernel/llsc4.c linux-2.4.20/arch/ia64/sn/kernel/llsc4.c
--- linux-2.4.19/arch/ia64/sn/kernel/llsc4.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ia64/sn/kernel/llsc4.c	2002-10-29 11:18:32.000000000 +0000
@@ -17,7 +17,7 @@
 #include <linux/mm.h>
 #include <linux/delay.h>
 #include <linux/string.h>
-#include <asm/efi.h>
+#include <linux/efi.h>
 #include <asm/page.h>
 #include <linux/threads.h>
 #include <asm/sn/simulator.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/sn/kernel/misctest.c linux-2.4.20/arch/ia64/sn/kernel/misctest.c
--- linux-2.4.19/arch/ia64/sn/kernel/misctest.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ia64/sn/kernel/misctest.c	2002-10-29 11:18:35.000000000 +0000
@@ -75,7 +75,7 @@
 	if (mcatest == 5) {
 		int zzzspec(long);
 		int	i;
-		long	flags, dcr, res, val, addr=0xff00000000UL;
+		long	psr, dcr, res, val, addr=0xff00000000UL;
 
 		dcr = ia64_get_dcr();
 		for (i=0; i<5; i++) {
@@ -87,11 +87,11 @@
 			ia64_set_dcr(dcr);
 			res = ia64_sn_probe_io_slot(0xff00000000UL, 8, &val);
 			printk("zzzspec: probe %ld, 0x%lx\n", res, val);
-			ia64_clear_ic(flags);
+			psr = ia64_clear_ic();
 			ia64_itc(0x2, 0xe00000ff00000000UL,
 			          pte_val(mk_pte_phys(0xff00000000UL,
 				  __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW))), _PAGE_SIZE_256M);
-			local_irq_restore(flags);
+			ia64_set_psr(psr);
 			ia64_srlz_i ();
 		}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/sn/kernel/sn_ksyms.c linux-2.4.20/arch/ia64/sn/kernel/sn_ksyms.c
--- linux-2.4.19/arch/ia64/sn/kernel/sn_ksyms.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ia64/sn/kernel/sn_ksyms.c	2002-10-29 11:18:50.000000000 +0000
@@ -17,15 +17,6 @@
 #include <asm/machvec.h>
 #include <asm/sn/intr.h>
 
-/*
- * other stuff (more to be added later, cleanup then)
- */
-EXPORT_SYMBOL(sn_pci_map_sg);
-EXPORT_SYMBOL(sn_pci_unmap_sg);
-EXPORT_SYMBOL(sn_pci_alloc_consistent);
-EXPORT_SYMBOL(sn_pci_free_consistent);
-EXPORT_SYMBOL(sn_dma_address);
-
 #include <linux/mm.h>
 #include <linux/devfs_fs_kernel.h>
 extern devfs_handle_t          base_io_scsi_ctlr_vhdl[];
@@ -62,6 +53,4 @@
 EXPORT_SYMBOL(sn_send_IPI_phys);
 
 #include <linux/mmzone.h>
-EXPORT_SYMBOL(sn_pci_unmap_single);
-EXPORT_SYMBOL(sn_pci_map_single);
-EXPORT_SYMBOL(sn_pci_dma_sync_single);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/tools/Makefile linux-2.4.20/arch/ia64/tools/Makefile
--- linux-2.4.19/arch/ia64/tools/Makefile	2002-02-25 19:37:53.000000000 +0000
+++ linux-2.4.20/arch/ia64/tools/Makefile	2002-10-29 11:18:30.000000000 +0000
@@ -2,9 +2,9 @@
 
 TARGET	= $(TOPDIR)/include/asm-ia64/offsets.h
 
-all: 
+all:
 
-mrproper:
+mrproper: clean
 
 clean:
 	rm -f print_offsets.s print_offsets offsets.h
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/tools/print_offsets.c linux-2.4.20/arch/ia64/tools/print_offsets.c
--- linux-2.4.19/arch/ia64/tools/print_offsets.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ia64/tools/print_offsets.c	2002-10-29 11:18:49.000000000 +0000
@@ -58,7 +58,8 @@
     { "IA64_TASK_THREAD_OFFSET",	offsetof (struct task_struct, thread) },
     { "IA64_TASK_THREAD_KSP_OFFSET",	offsetof (struct task_struct, thread.ksp) },
 #ifdef CONFIG_PERFMON
-    { "IA64_TASK_PFM_OVFL_BLOCK_RESET_OFFSET",offsetof(struct task_struct, thread.pfm_ovfl_block_reset) },
+    { "IA64_TASK_PFM_OVFL_BLOCK_RESET_OFFSET",
+					offsetof(struct task_struct, thread.pfm_ovfl_block_reset) },
 #endif
     { "IA64_TASK_PID_OFFSET",		offsetof (struct task_struct, pid) },
     { "IA64_TASK_MM_OFFSET",		offsetof (struct task_struct, mm) },
@@ -152,6 +153,7 @@
     { "IA64_SWITCH_STACK_AR_RNAT_OFFSET",	offsetof (struct switch_stack, ar_rnat) },
     { "IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET",	offsetof (struct switch_stack, ar_bspstore) },
     { "IA64_SWITCH_STACK_PR_OFFSET",	offsetof (struct switch_stack, pr) },
+    { "IA64_SIGCONTEXT_IP_OFFSET",	offsetof (struct sigcontext, sc_ip) },
     { "IA64_SIGCONTEXT_AR_BSP_OFFSET",	offsetof (struct sigcontext, sc_ar_bsp) },
     { "IA64_SIGCONTEXT_AR_FPSR_OFFSET", offsetof (struct sigcontext, sc_ar_fpsr) },
     { "IA64_SIGCONTEXT_AR_RNAT_OFFSET",	offsetof (struct sigcontext, sc_ar_rnat) },
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ia64/vmlinux.lds.S linux-2.4.20/arch/ia64/vmlinux.lds.S
--- linux-2.4.19/arch/ia64/vmlinux.lds.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ia64/vmlinux.lds.S	2002-10-29 11:18:35.000000000 +0000
@@ -1,5 +1,6 @@
 #include <linux/config.h>
 
+#include <asm/cache.h>
 #include <asm/page.h>
 #include <asm/system.h>
 
@@ -27,11 +28,6 @@
   .text : AT(ADDR(.text) - PAGE_OFFSET)
     {
 	*(.text.ivt)
-	/* these are not really text pages, but they need to be page aligned: */
-	*(__special_page_section)
-	__start_gate_section = .;
-	*(.text.gate)
-	__stop_gate_section = .;
 	*(.text)
     }
   .text2 : AT(ADDR(.text2) - PAGE_OFFSET)
@@ -44,8 +40,6 @@
 
   /* Read-only data */
 
-  __gp = ALIGN(16) + 0x200000;	/* gp must be 16-byte aligned for exc. table */
-
   /* Global data */
   _data = .;
 
@@ -117,9 +111,13 @@
 	{ *(init_task) }
 
   .data.page_aligned : AT(ADDR(.data.page_aligned) - PAGE_OFFSET)
-        { *(.data.idt) }
+        { *(__special_page_section)
+	  __start_gate_section = .;
+	  *(.text.gate)
+	  __stop_gate_section = .;
+	}
 
-  . = ALIGN(64);
+  . = ALIGN(SMP_CACHE_BYTES);
   .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - PAGE_OFFSET)
         { *(.data.cacheline_aligned) }
 
@@ -130,6 +128,10 @@
   .data : AT(ADDR(.data) - PAGE_OFFSET)
 	{ *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS }
 
+
+  . = ALIGN(16);
+  __gp = . + 0x200000;	/* gp must be 16-byte aligned for exc. table */
+
   .got : AT(ADDR(.got) - PAGE_OFFSET)
 	{ *(.got.plt) *(.got) }
   /* We want the small data sections together, so single-instruction offsets
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/amiga/config.c linux-2.4.20/arch/m68k/amiga/config.c
--- linux-2.4.19/arch/m68k/amiga/config.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/amiga/config.c	2002-10-29 11:18:32.000000000 +0000
@@ -20,6 +20,7 @@
 #include <linux/console.h>
 #include <linux/rtc.h>
 #include <linux/init.h>
+#include <linux/vt_kern.h>
 #ifdef CONFIG_ZORRO
 #include <linux/zorro.h>
 #endif
@@ -128,8 +129,6 @@
 	"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";	/* 0x70 - 0x7f */
 #endif
 
-extern void (*kd_mksound)(unsigned int, unsigned int);
-
 
     /*
      *  Motherboard Resources present in all Amiga models
@@ -390,10 +389,12 @@
     request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]);
 
   mach_sched_init      = amiga_sched_init;
+#ifdef CONFIG_VT
   mach_keyb_init       = amiga_keyb_init;
   mach_kbdrate         = amiga_kbdrate;
   mach_kbd_translate   = amiga_kbd_translate;
-  SYSRQ_KEY            = 0xff;
+  kd_mksound           = amiga_mksound;
+#endif
   mach_init_IRQ        = amiga_init_IRQ;
   mach_default_handler = &amiga_default_handler;
   mach_request_irq     = amiga_request_irq;
@@ -434,8 +435,8 @@
 #ifdef CONFIG_DUMMY_CONSOLE
   conswitchp           = &dummy_con;
 #endif
-  kd_mksound           = amiga_mksound;
 #ifdef CONFIG_MAGIC_SYSRQ
+  SYSRQ_KEY            = 0xff;
   mach_sysrq_key = 0x5f;	     /* HELP */
   mach_sysrq_shift_state = 0x03; /* SHIFT+ALTGR */
   mach_sysrq_shift_mask = 0xff;  /* all modifiers except CapsLock */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/apollo/config.c linux-2.4.20/arch/m68k/apollo/config.c
--- linux-2.4.19/arch/m68k/apollo/config.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/apollo/config.c	2002-10-29 11:18:36.000000000 +0000
@@ -5,6 +5,7 @@
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/rtc.h>
+#include <linux/vt_kern.h>
 
 #include <asm/setup.h>
 #include <asm/bootinfo.h>
@@ -42,7 +43,6 @@
 extern void dn_dummy_waitbut(void);
 extern struct fb_info *dn_fb_init(long *);
 extern void dn_dummy_debug_init(void);
-extern void (*kd_mksound)(unsigned int, unsigned int);
 extern void dn_dummy_video_setup(char *,int *);
 extern void dn_process_int(int irq, struct pt_regs *fp);
 #ifdef CONFIG_HEARTBEAT
@@ -166,8 +166,11 @@
 	dn_setup_model();	
 
 	mach_sched_init=dn_sched_init; /* */
+#ifdef CONFIG_VT
 	mach_keyb_init=dn_keyb_init;
 	mach_kbdrate=dn_dummy_kbdrate;
+	kd_mksound	     = dn_mksound;
+#endif
 	mach_init_IRQ=dn_init_IRQ;
 	mach_default_handler=NULL;
 	mach_request_irq     = dn_request_irq;
@@ -189,7 +192,6 @@
 #ifdef CONFIG_DUMMY_CONSOLE
         conswitchp           = &dummy_con;
 #endif
-	kd_mksound	     = dn_mksound;
 #ifdef CONFIG_HEARTBEAT
   	mach_heartbeat = dn_heartbeat;
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/apollo/dn_ints.c linux-2.4.20/arch/m68k/apollo/dn_ints.c
--- linux-2.4.19/arch/m68k/apollo/dn_ints.c	2001-03-07 03:44:35.000000000 +0000
+++ linux-2.4.20/arch/m68k/apollo/dn_ints.c	2002-10-29 11:18:49.000000000 +0000
@@ -12,11 +12,6 @@
 
 static irq_handler_t dn_irqs[16];
 
-extern void write_keyb_cmd(u_short length, u_char *cmd);
-static char BellOnCommand[] =  { 0xFF, 0x21, 0x81 },
-		    BellOffCommand[] = { 0xFF, 0x21, 0x82 };
-
-extern void dn_serial_print (const char *str);
 void dn_process_int(int irq, struct pt_regs *fp) {
 
 
@@ -120,6 +115,11 @@
 
 }
 
+#ifdef CONFIG_VT
+extern void write_keyb_cmd(u_short length, u_char *cmd);
+static char BellOnCommand[] =  { 0xFF, 0x21, 0x81 },
+		    BellOffCommand[] = { 0xFF, 0x21, 0x82 };
+
 static void dn_nosound (unsigned long ignored) {
 
 	write_keyb_cmd(sizeof(BellOffCommand),BellOffCommand);
@@ -141,6 +141,8 @@
 	else
 		write_keyb_cmd(sizeof(BellOffCommand),BellOffCommand);
 }
+#endif /* CONFIG_VT */
+
 
 void dn_dummy_video_setup(char *options,int *ints) {
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/atari/Makefile linux-2.4.20/arch/m68k/atari/Makefile
--- linux-2.4.19/arch/m68k/atari/Makefile	2000-12-29 22:07:20.000000000 +0000
+++ linux-2.4.20/arch/m68k/atari/Makefile	2002-10-29 11:18:33.000000000 +0000
@@ -11,10 +11,12 @@
 
 export-objs	:= atari_ksyms.o
 
-obj-y		:= config.o time.o debug.o atakeyb.o ataints.o stdma.o \
-			atasound.o joystick.o stram.o atari_ksyms.o
+obj-y		:= config.o time.o debug.o ataints.o stdma.o \
+			atasound.o stram.o atari_ksyms.o
 
-ifdef CONFIG_PCI
+obj-$(CONFIG_VT)	+= atakeyb.o joystick.o
+
+ifeq ($(CONFIG_PCI),y)
 obj-$(CONFIG_HADES)	+= hades-pci.o
 endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/atari/config.c linux-2.4.20/arch/m68k/atari/config.c
--- linux-2.4.19/arch/m68k/atari/config.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/atari/config.c	2002-10-29 11:18:32.000000000 +0000
@@ -31,6 +31,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
+#include <linux/vt_kern.h>
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
@@ -102,7 +103,6 @@
 	"0.\r\000\000\000\000\000\000\000\000\000\000\000\000\000";	/* 0x70 - 0x7f */
 #endif
 
-extern void (*kd_mksound)(unsigned int, unsigned int);
 
 /* I've moved hwreg_present() and hwreg_present_bywrite() out into
  * mm/hwtest.c, to avoid having multiple copies of the same routine
@@ -254,13 +254,13 @@
                                            to 4GB. */
 
     mach_sched_init      = atari_sched_init;
+#ifdef CONFIG_VT
     mach_keyb_init       = atari_keyb_init;
     mach_kbdrate         = atari_kbdrate;
     mach_kbd_translate   = atari_kbd_translate;
-#ifdef CONFIG_MAGIC_SYSRQ
-    SYSRQ_KEY            = 0xff;
-#endif
     mach_kbd_leds        = atari_kbd_leds;
+    kd_mksound		 = atari_mksound;
+#endif
     mach_init_IRQ        = atari_init_IRQ;
     mach_request_irq     = atari_request_irq;
     mach_free_irq        = atari_free_irq;
@@ -278,8 +278,8 @@
     conswitchp	         = &dummy_con;
 #endif
     mach_max_dma_address = 0xffffff;
-    kd_mksound		 = atari_mksound;
 #ifdef CONFIG_MAGIC_SYSRQ
+    SYSRQ_KEY            = 0xff;
     mach_sysrq_key = 98;          /* HELP */
     mach_sysrq_shift_state = 8;   /* Alt */
     mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/bvme6000/config.c linux-2.4.20/arch/m68k/bvme6000/config.c
--- linux-2.4.19/arch/m68k/bvme6000/config.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/bvme6000/config.c	2002-10-29 11:18:32.000000000 +0000
@@ -135,8 +135,10 @@
 
     mach_max_dma_address = 0xffffffff;
     mach_sched_init      = bvme6000_sched_init;
+#ifdef CONFIG_VT
     mach_keyb_init       = bvme6000_keyb_init;
     mach_kbdrate         = bvme6000_kbdrate;
+#endif
     mach_init_IRQ        = bvme6000_init_IRQ;
     mach_gettimeoffset   = bvme6000_gettimeoffset;
     mach_gettod  	 = bvme6000_gettod;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/bvme6000/rtc.c linux-2.4.20/arch/m68k/bvme6000/rtc.c
--- linux-2.4.19/arch/m68k/bvme6000/rtc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/bvme6000/rtc.c	2002-10-29 11:18:32.000000000 +0000
@@ -94,7 +94,7 @@
 
 		leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
 
-		if ((mon > 12) || (day == 0))
+		if ((mon > 12) || (mon < 1) || (day == 0))
 			return -EINVAL;
 
 		if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/config.in linux-2.4.20/arch/m68k/config.in
--- linux-2.4.19/arch/m68k/config.in	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/config.in	2002-10-29 11:18:49.000000000 +0000
@@ -141,7 +141,7 @@
    fi
    dep_tristate '  Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
    if [ "$CONFIG_PRINTER" != "n" ]; then
-      bool '    Support IEEE1284 status readback' CONFIG_PARPORT_1284
+      bool '    IEEE 1284 transfer modes' CONFIG_PARPORT_1284
    fi
 fi
 
@@ -376,6 +376,11 @@
 mainmenu_option next_comment
 comment 'Character devices'
  
+bool 'Virtual terminal' CONFIG_VT
+if [ "$CONFIG_VT" = "y" ]; then
+   bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE
+fi
+
 if [ "$CONFIG_Q40" = "y" ]; then
    tristate 'Q40 Standard/generic serial support' CONFIG_SERIAL
 fi
@@ -391,13 +396,6 @@
    bool '    Support the Bell Technologies HUB6 card' CONFIG_HUB6
 fi
 
-if [ "$CONFIG_VME" = "n" ]; then
-   define_bool CONFIG_VT y
-   if [ "$CONFIG_VT" = "y" ]; then
-      bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE
-   fi
-fi
-
 if [ "$CONFIG_ATARI" = "y" ]; then
    define_bool CONFIG_NVRAM y
 fi
@@ -408,7 +406,7 @@
       define_bool CONFIG_BUSMOUSE y
    fi
 fi
-if [ "$CONFIG_ATARI" = "y" ]; then
+if [ "$CONFIG_ATARI" = "y" -a "$CONFIG_VT" = "y" ]; then
    tristate 'Atari mouse support' CONFIG_ATARIMOUSE
    if [ "$CONFIG_ATARIMOUSE" != "n" ]; then
       define_bool CONFIG_BUSMOUSE y
@@ -430,16 +428,16 @@
    if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then
       tristate 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET_SERIAL
    fi
+   tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232
+   fi
 fi
 if [ "$CONFIG_PARPORT" = "n" ]; then
    if [ "$CONFIG_ZORRO" = "y" ]; then
       tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT
       dep_tristate '  GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
       dep_tristate '  GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
-      tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-        tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232
-      fi
    fi
 fi
 if [ "$CONFIG_MAC" = "y" ]; then
@@ -464,6 +462,20 @@
 if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then
    tristate 'HP DCA serial support' CONFIG_HPDCA
 fi
+if [ "$CONFIG_MVME147" = "y" ]; then
+   bool 'SCC support for MVME147 serial ports' CONFIG_MVME147_SCC
+fi
+if [ "$CONFIG_MVME16x" = "y" ]; then
+   bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167
+   bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC
+fi
+if [ "$CONFIG_BVME6000" = "y" ]; then
+   bool 'SCC support for BVME6000 serial ports' CONFIG_BVME6000_SCC
+fi
+if [ "$CONFIG_APOLLO" = "y" ]; then
+   bool 'Support for DN serial port (dummy)' CONFIG_DN_SERIAL
+   define_tristate CONFIG_SERIAL $CONFIG_DN_SERIAL
+fi 
 
 if [ "$CONFIG_SUN3" = "y" -o "$CONFIG_SUN3X" = "y" ]; then
    bool 'Sun3/3x builtin serial support' CONFIG_SUN3X_ZS
@@ -483,37 +495,16 @@
    define_bool CONFIG_SBUS n
 fi
 
-if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o \
-     "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" -o \
-     "$CONFIG_SUN3" = "y" -o "$CONFIG_SUN3X" = "y" ]; then
-   if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
-        "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_MAC_SCC" = "y" -o \
-        "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
-        "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" -o \
-        "$CONFIG_HPDCA" = "y" -o "$CONFIG_SUN3X_ZS" = "y" -o \
-	"$CONFIG_SERIAL" = "y" ]; then
-      bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
-   fi
-fi
-if [ "$CONFIG_VME" = "y" ]; then
-   define_bool CONFIG_SERIAL_CONSOLE y
-   if [ "$CONFIG_MVME147" = "y" ]; then
-      bool 'SCC support for MVME147 serial ports' CONFIG_MVME147_SCC
-   fi
-   if [ "$CONFIG_MVME16x" = "y" ]; then
-      bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167
-      bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC
-   fi
-   if [ "$CONFIG_BVME6000" = "y" ]; then
-      bool 'SCC support for BVME6000 serial ports' CONFIG_BVME6000_SCC
-   fi
-fi
-if [ "$CONFIG_APOLLO" = "y" ]; then
-   bool 'Support for DN serial port (dummy)' CONFIG_DN_SERIAL
+if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
+     "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_MAC_SCC" = "y" -o \
+     "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o "$CONFIG_GVPIOEXT" = "y" -o \
+     "$CONFIG_MULTIFACE_III_TTY" = "y" -o "$CONFIG_HPDCA" = "y" -o \
+     "$CONFIG_SUN3X_ZS" = "y" -o "$CONFIG_SERIAL" = "y" -o \
+     "$CONFIG_MVME147_SCC" -o "$CONFIG_SERIAL167" = "y" -o \
+     "$CONFIG_MVME162_SCC" -o "$CONFIG_BVME6000_SCC" = "y" -o \
+     "$CONFIG_DN_SERIAL" -o ]; then
    bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
-
-   define_tristate CONFIG_SERIAL $CONFIG_DN_SERIAL
-fi 
+fi
 bool 'Support for user serial device modules' CONFIG_USERIAL
 bool 'Watchdog Timer Support'	CONFIG_WATCHDOG
 if [ "$CONFIG_WATCHDOG" != "n" ]; then
@@ -539,7 +530,7 @@
 mainmenu_option next_comment
 comment 'Sound support'
 
-tristate 'Sound support' CONFIG_SOUND
+tristate 'Sound card support' CONFIG_SOUND
 if [ "$CONFIG_SOUND" != "n" ]; then
    source drivers/sound/dmasound/Config.in
 fi
@@ -547,7 +538,7 @@
 
 source fs/Config.in
 
-if [ "$CONFIG_VME" = "n" ]; then
+if [ "$CONFIG_VT" = "y" ]; then
    mainmenu_option next_comment
    comment 'Console drivers'
    source drivers/video/Config.in
@@ -565,3 +556,5 @@
 fi
 
 endmenu
+
+source lib/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/hp300/config.c linux-2.4.20/arch/m68k/hp300/config.c
--- linux-2.4.19/arch/m68k/hp300/config.c	1999-08-26 19:42:31.000000000 +0000
+++ linux-2.4.20/arch/m68k/hp300/config.c	2002-10-29 11:18:32.000000000 +0000
@@ -17,7 +17,6 @@
 #include <linux/init.h>
 #include <asm/machdep.h>
 #include <asm/blinken.h>
-#include <asm/io.h>                               /* readb() and writeb() */
 #include <asm/hwtest.h>                           /* hwreg_present() */
 
 #include "ints.h"
@@ -29,10 +28,9 @@
 
 #ifdef CONFIG_VT
 extern int hp300_keyb_init(void);
-#else
-/* Dummy function for when there is no keyboard. */
-int __init hp300_keyb_init(void)
+static int hp300_kbdrate(struct kbd_repeat *k)
 {
+  return 0;
 }
 #endif
 
@@ -46,15 +44,6 @@
 }
 #endif
 
-static int hp300_kbdrate(struct kbd_repeat *k)
-{
-  return 0;
-}
-
-static void hp300_kbd_leds(unsigned int leds)
-{
-}
-
 static void hp300_get_model(char *model)
 {
   strcpy(model, "HP9000/300");
@@ -63,9 +52,10 @@
 void __init config_hp300(void)
 {
   mach_sched_init      = hp300_sched_init;
+#ifdef CONFIG_VT
   mach_keyb_init       = hp300_keyb_init;
   mach_kbdrate         = hp300_kbdrate;
-  mach_kbd_leds        = hp300_kbd_leds;
+#endif
   mach_init_IRQ        = hp300_init_IRQ;
   mach_request_irq     = hp300_request_irq;
   mach_free_irq        = hp300_free_irq;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/hp300/hil.c linux-2.4.20/arch/m68k/hp300/hil.c
--- linux-2.4.19/arch/m68k/hp300/hil.c	1999-08-26 19:42:31.000000000 +0000
+++ linux-2.4.20/arch/m68k/hp300/hil.c	2002-10-29 11:18:49.000000000 +0000
@@ -25,12 +25,12 @@
 #define	HIL_BUSY		0x02
 #define	HIL_DATA_RDY		0x01
 
-#define hil_busy()		(readb(HILBASE + HIL_CMD) & HIL_BUSY)
-#define hil_data_available()	(readb(HILBASE + HIL_CMD) & HIL_DATA_RDY)
-#define hil_status()		(readb(HILBASE + HIL_CMD))
-#define hil_command(x)		do { writeb((x), HILBASE + HIL_CMD); } while (0)
-#define hil_read_data()		(readb(HILBASE + HIL_DATA))
-#define hil_write_data(x)	do { writeb((x), HILBASE + HIL_DATA); } while (0)
+#define hil_busy()		(in_8(HILBASE + HIL_CMD) & HIL_BUSY)
+#define hil_data_available()	(in_8(HILBASE + HIL_CMD) & HIL_DATA_RDY)
+#define hil_status()		(in_8(HILBASE + HIL_CMD))
+#define hil_command(x)		out_8(HILBASE + HIL_CMD, (x))
+#define hil_read_data()		(in_8(HILBASE + HIL_DATA))
+#define hil_write_data(x)	out_8(HILBASE + HIL_DATA, (x))
 
 #define	HIL_SETARD		0xA0		/* set auto-repeat delay */
 #define	HIL_SETARR		0xA2		/* set auto-repeat rate */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/hp300/ints.c linux-2.4.20/arch/m68k/hp300/ints.c
--- linux-2.4.19/arch/m68k/hp300/ints.c	1999-09-08 18:59:00.000000000 +0000
+++ linux-2.4.20/arch/m68k/hp300/ints.c	2002-10-29 11:18:34.000000000 +0000
@@ -142,7 +142,9 @@
         }
         /* remove the entry after t: */
         t->next->flags = IRQ_FLG_STD;
-        t->next->dev_id = t->next->devname = t->next->handler = NULL;
+        t->next->dev_id = NULL;
+	t->next->devname = NULL;
+	t->next->handler = NULL;
         t->next = t->next->next;
         
 	spin_unlock_irqrestore(&irqlist_lock, flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/hp300/time.c linux-2.4.20/arch/m68k/hp300/time.c
--- linux-2.4.19/arch/m68k/hp300/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/hp300/time.c	2002-10-29 11:18:49.000000000 +0000
@@ -40,7 +40,7 @@
 {
   unsigned long tmp;
   void (*vector)(int, void *, struct pt_regs *) = dev_id;
-  readb(CLOCKBASE + CLKSR);
+  in_8(CLOCKBASE + CLKSR);
   asm volatile ("movpw %1@(5),%0" : "=d" (tmp) : "a" (CLOCKBASE));
   vector(irq, NULL, regs);
 }
@@ -51,25 +51,25 @@
   unsigned char lsb, msb1, msb2;
   unsigned short ticks;
 
-  msb1 = readb(CLOCKBASE + 5);
-  lsb = readb(CLOCKBASE + 7);
-  msb2 = readb(CLOCKBASE + 5);
+  msb1 = in_8(CLOCKBASE + 5);
+  lsb = in_8(CLOCKBASE + 7);
+  msb2 = in_8(CLOCKBASE + 5);
   if (msb1 != msb2)
     /* A carry happened while we were reading.  Read it again */
-    lsb = readb(CLOCKBASE + 7);
+    lsb = in_8(CLOCKBASE + 7);
   ticks = INTVAL - ((msb2 << 8) | lsb);
   return (USECS_PER_JIFFY * ticks) / INTVAL;
 }
 
 void __init hp300_sched_init(void (*vector)(int, void *, struct pt_regs *))
 {
-  writeb(0x1, CLOCKBASE + CLKCR2);		/* select CR1 */
-  writeb(0x1, CLOCKBASE + CLKCR1);		/* reset */
+  out_8(CLOCKBASE + CLKCR2, 0x1);		/* select CR1 */
+  out_8(CLOCKBASE + CLKCR1, 0x1);		/* reset */
 
   asm volatile(" movpw %0,%1@(5)" : : "d" (INTVAL), "a" (CLOCKBASE));
 
   sys_request_irq(6, hp300_tick, IRQ_FLG_STD, "timer tick", vector);
 
-  writeb(0x1, CLOCKBASE + CLKCR2);		/* select CR1 */
-  writeb(0x40, CLOCKBASE + CLKCR1);		/* enable irq */
+  out_8(CLOCKBASE + CLKCR2, 0x1);		/* select CR1 */
+  out_8(CLOCKBASE + CLKCR1, 0x40);		/* enable irq */
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/kernel/entry.S linux-2.4.20/arch/m68k/kernel/entry.S
--- linux-2.4.19/arch/m68k/kernel/entry.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/kernel/entry.S	2002-10-29 11:18:31.000000000 +0000
@@ -645,6 +645,18 @@
 	.long SYMBOL_NAME(sys_getdents64)	/* 220 */
 	.long SYMBOL_NAME(sys_gettid)
 	.long SYMBOL_NAME(sys_tkill)
+	.long SYMBOL_NAME(sys_setxattr)
+	.long SYMBOL_NAME(sys_lsetxattr)
+	.long SYMBOL_NAME(sys_fsetxattr)	/* 225 */
+	.long SYMBOL_NAME(sys_getxattr)
+	.long SYMBOL_NAME(sys_lgetxattr)
+	.long SYMBOL_NAME(sys_fgetxattr)
+	.long SYMBOL_NAME(sys_listxattr)
+	.long SYMBOL_NAME(sys_llistxattr)	/* 230 */
+	.long SYMBOL_NAME(sys_flistxattr)
+	.long SYMBOL_NAME(sys_removexattr)
+	.long SYMBOL_NAME(sys_lremovexattr)
+	.long SYMBOL_NAME(sys_fremovexattr)
 
 	.rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/kernel/head.S linux-2.4.20/arch/m68k/kernel/head.S
--- linux-2.4.19/arch/m68k/kernel/head.S	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.20/arch/m68k/kernel/head.S	2002-10-29 11:18:40.000000000 +0000
@@ -310,8 +310,11 @@
 .globl SYMBOL_NAME(mvme_bdid)
 #endif
 #ifdef CONFIG_Q40
-.globl SYMBOL_NAME(q40_mem_cptr)	
-#endif		
+.globl SYMBOL_NAME(q40_mem_cptr)
+#endif
+#ifdef CONFIG_HP300
+.globl SYMBOL_NAME(hp300_phys_ram_base)
+#endif
 
 CPUTYPE_040	= 1	/* indicates an 040 */
 CPUTYPE_060	= 2	/* indicates an 060 */
@@ -596,6 +599,64 @@
 __INIT
 ENTRY(__start)
 
+#ifdef CONFIG_HP300
+/* This is a hack.  The HP NetBSD bootloader loads us at an arbitrary
+   address (apparently 0xff002000 in practice) which is not good if we need
+   to be able to map this to VA 0x1000.  We could do it with pagetables but
+   a better solution seems to be to relocate the kernel in physical memory
+   before we start.  
+	
+   So, we copy the entire kernel image (code+data+bss) down to the 16MB
+   boundary that marks the start of RAM.  This is slightly tricky because
+   we must not overwrite the copying code itself. :-)  */
+
+/* 15/5/98.  The start address of physical RAM changes depending on how much
+   RAM is present.  This is actually a blessing in disguise as it provides
+   a way for us to work out the RAM size rather than hardwiring it.  */
+
+	lea	%pc@(_start),%a0
+	movel	%a0,%d6
+	and	#0xffff0000, %d6
+	lea	%pc@(SYMBOL_NAME(hp300_phys_ram_base)),%a0
+	movel	%d6, %a0@
+	movel	%pc@(L(custom)),%a3
+	moveb	#0xfe,%d7
+	moveb	%d7,%a3@(0x1ffff)
+	lea	%pc@(Lcopystart),%a0
+	lea	%pc@(Lcopyend),%a1
+	movel	%d6,%a2			/* Start of physical RAM */
+1:	moveb	%a0@+,%d0
+	moveb	%d0,%a2@+
+	cmpl	%a0,%a1
+	jbne	1b
+	movel	%d6,%a2
+	moveb	#0xfd,%d7
+	moveb	%d7,%a3@(0x1ffff)
+	lea	%pc@(_stext),%a0
+	lea	%pc@(_end),%a1
+	jmp	%a2@
+
+Lcopystart:
+	moveb	#0xf7,%d7
+	moveb	%d7,%a3@(0x1ffff)
+	movel	%d6,%a2	/* Start of kernel */
+	add	#0x1000,%a2
+1:	moveb	%a0@+,%d0
+	moveb	%d0,%a2@+
+	cmpl	%a0,%a1
+	jbne	1b
+	moveb	#0,%d7
+	moveb	%d7,%a3@(0x1ffff)
+	movel	%d6,%a0
+	addl	#Lstart1,%a0
+	jmp	%a0@
+Lcopyend:	
+
+Lstart1:
+	moveb	#0x3f,%d7
+	moveb	%d7,%a3@(0x1ffff)
+#endif /* CONFIG_HP300 */
+
 /*
  * Setup initial stack pointer
  */
@@ -605,6 +666,7 @@
  * Record the CPU and machine type.
  */
 
+#ifndef CONFIG_HP300
 	get_bi_record	BI_MACHTYPE
 	lea	%pc@(SYMBOL_NAME(m68k_machtype)),%a1
 	movel	%a0@,%a1@
@@ -620,6 +682,23 @@
 	get_bi_record	BI_CPUTYPE
 	lea	%pc@(SYMBOL_NAME(m68k_cputype)),%a1
 	movel	%a0@,%a1@
+#else /* CONFIG_HP300 */
+	/* FIXME HP300 doesn't use bootinfo yet */
+	movel	#MACH_HP300,%d4
+	lea	%pc@(SYMBOL_NAME(m68k_machtype)),%a0
+	movel	%d4,%a0@
+	movel	#FPU_68881,%d0
+	lea	%pc@(SYMBOL_NAME(m68k_fputype)),%a0
+	movel	%d0,%a0@
+	movel	#MMU_68030,%d0
+	lea	%pc@(SYMBOL_NAME(m68k_mmutype)),%a0
+	movel	%d0,%a0@
+	movel	#CPU_68030,%d0
+	lea	%pc@(SYMBOL_NAME(m68k_cputype)),%a0
+	movel	%d0,%a0@
+
+	leds(0x1)
+#endif /* CONFIG_HP300 */
 
 #ifdef CONFIG_MAC
 /*
@@ -893,6 +972,9 @@
 
 	putc	'\n'
 	putc	'A'
+#ifdef CONFIG_HP300
+	leds(0x2)
+#endif /* CONFIG_HP300 */
 	dputn	%pc@(L(cputype))
 	dputn	%pc@(SYMBOL_NAME(m68k_supervisor_cachemode))
 	dputn	%pc@(SYMBOL_NAME(m68k_pgtable_cachemode))
@@ -1490,6 +1572,7 @@
 
 	movel	ARG1,%d0
 	lea	%pc@(SYMBOL_NAME(_end)),%a0
+#ifndef CONFIG_HP300
 1:	tstw	%a0@(BIR_TAG)
 	jeq	3f
 	cmpw	%a0@(BIR_TAG),%d0
@@ -1503,6 +1586,7 @@
 3:	moveq	#-1,%d0
 	lea	%a0@(BIR_SIZE),%a0
 4:
+#endif /* CONFIG_HP300 */
 func_return	get_bi_record
 
 
@@ -3286,14 +3370,16 @@
 
 	/* Calculate font size */
 
-#if   defined(FONT_8x8)
+#if   defined(FONT_8x8) && defined(CONFIG_FONT_8x8)
 	lea	%pc@(SYMBOL_NAME(font_vga_8x8)), %a0
-#elif defined(FONT_8x16)
+#elif defined(FONT_8x16) && defined(CONFIG_FONT_8x16)
 	lea	%pc@(SYMBOL_NAME(font_vga_8x16)),%a0
-#elif defined(FONT_6x11)
+#elif defined(FONT_6x11) && defined(CONFIG_FONT_6x11)
 	lea	%pc@(SYMBOL_NAME(font_vga_6x11)),%a0
-#else	/*   (FONT_8x8) default */
+#elif defined(CONFIG_FONT_8x8) /* default *
 	lea	%pc@(SYMBOL_NAME(font_vga_8x8)), %a0
+#else /* no compiled-in font */
+	lea	0,%a0
 #endif
 
 	/*
@@ -3302,6 +3388,8 @@
 	 */
 	lea	%pc@(L(console_font)),%a1
 	movel	%a0,%a1@	/* store pointer to struct fbcon_font_desc in Lconsole_font */
+	tstl	%a0
+	jeq	1f
 
 	/*
 	 *	Calculate global maxs
@@ -3329,7 +3417,7 @@
 	/*
 	 * Initialization is complete
 	 */
-	moveml	%sp@+,%a0-%a4/%d0-%d7
+1:	moveml	%sp@+,%a0-%a4/%d0-%d7
 	rts
 
 L(console_put_stats):
@@ -3415,6 +3503,8 @@
 	lea	%pc@(L(mac_rowbytes)),%a0
 	movel	%a0@,%d5
 	movel	%pc@(L(console_font)),%a0
+	tstl	%a0
+	jeq	1f
 	mulul	%a0@(FBCON_FONT_DESC_HEIGHT),%d5	/* account for # scan lines per character */
 	addal	%d5,%a2
 
@@ -3469,13 +3559,15 @@
 	movel	%d0,%a1@+
 	dbra	%d6,console_scroll_clear_loop
 
-	moveml	%sp@+,%a0-%a4/%d0-%d7
+1:	moveml	%sp@+,%a0-%a4/%d0-%d7
 	rts
 
 
 func_start	console_putc,%a0/%a1/%d0-%d7
 
 	is_not_mac(console_exit)
+	tstl	%pc@(L(console_font))
+	jeq	console_exit
 
 	/* Output character in d7 on console.
 	 */
@@ -3747,7 +3839,12 @@
 __INITDATA
 	.align	4
 
-#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA) || defined(CONFIG_HP300)
+#ifdef CONFIG_HP300
+SYMBOL_NAME_LABEL(hp300_phys_ram_base)
+#endif
+
+#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA) || \
+    defined(CONFIG_HP300) || defined(CONFIG_APOLLO)
 L(custom):
 L(iobase):
 	.long 0
@@ -3838,8 +3935,6 @@
 LSRB0        = 0x10412
 LTHRB0       = 0x10416
 LCPUCTRL     = 0x10100
-L(iobase):
-        .long 0
 #endif
 
 __FINIT
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/kernel/setup.c linux-2.4.20/arch/m68k/kernel/setup.c
--- linux-2.4.19/arch/m68k/kernel/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/kernel/setup.c	2002-10-29 11:18:50.000000000 +0000
@@ -34,6 +34,7 @@
 #endif
 #ifdef CONFIG_ATARI
 #include <asm/atarihw.h>
+#include <asm/atari_stram.h>
 #endif
 #ifdef CONFIG_SUN3X
 #include <asm/dvma.h>
@@ -71,11 +72,12 @@
 
 void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;
 /* machine dependent keyboard functions */
+#ifdef CONFIG_VT
 int (*mach_keyb_init) (void) __initdata = NULL;
 int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
 void (*mach_kbd_leds) (unsigned int) = NULL;
 int (*mach_kbd_translate)(unsigned char scancode, unsigned char *keycode, char raw_mode) = NULL;
-unsigned int SYSRQ_KEY;
+#endif
 /* machine dependent irq functions */
 void (*mach_init_IRQ) (void) __initdata = NULL;
 void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
@@ -104,6 +106,7 @@
 #endif
 
 #ifdef CONFIG_MAGIC_SYSRQ
+unsigned int SYSRQ_KEY;
 int mach_sysrq_key = -1;
 int mach_sysrq_shift_state = 0;
 int mach_sysrq_shift_mask = 0;
@@ -218,8 +221,20 @@
 	int i;
 	char *p, *q;
 
-	/* The bootinfo is located right after the kernel bss */
-	m68k_parse_bootinfo((const struct bi_record *)&_end);
+	if (!MACH_IS_HP300) {
+		/* The bootinfo is located right after the kernel bss */
+		m68k_parse_bootinfo((const struct bi_record *)&_end);
+	} else {
+		/* FIXME HP300 doesn't use bootinfo yet */
+		extern unsigned long hp300_phys_ram_base;
+		unsigned long hp300_mem_size = 0xffffffff-hp300_phys_ram_base;
+		m68k_cputype = CPU_68030;
+		m68k_fputype = FPU_68882;
+		m68k_memory[0].addr = hp300_phys_ram_base;
+		/* 0.5M fudge factor */
+		m68k_memory[0].size = hp300_mem_size-512*1024;
+		m68k_num_memory++;
+	}
 
 	if (CPU_IS_040)
 		m68k_is040or060 = 4;
@@ -372,7 +387,7 @@
 
 #ifdef CONFIG_ATARI
 	if (MACH_IS_ATARI)
-		atari_stram_reserve_pages(availmem);
+		atari_stram_reserve_pages((void *)availmem);
 #endif
 #ifdef CONFIG_SUN3X
 	if (MACH_IS_SUN3X) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/kernel/traps.c linux-2.4.20/arch/m68k/kernel/traps.c
--- linux-2.4.19/arch/m68k/kernel/traps.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/kernel/traps.c	2002-10-29 11:18:47.000000000 +0000
@@ -816,8 +816,9 @@
 
 static inline int kernel_text_address(unsigned long addr)
 {
+#ifdef CONFIG_MODULES
 	struct module *mod;
-	int retval = 0;
+#endif
 	extern char _stext, _etext;
 
 	if (addr >= (unsigned long) &_stext &&
@@ -829,14 +830,12 @@
 		/* mod_bound tests for addr being inside the vmalloc'ed
 		 * module area. Of course it'd be better to test only
 		 * for the .text subset... */
-		if (mod_bound(addr, 0, mod)) {
-			retval = 1;
-			break;
-		}
+		if (mod_bound(addr, 0, mod))
+			return 1;
 	}
 #endif
 
-	return retval;
+	return 0;
 }
 
 void show_trace(unsigned long *stack)
@@ -874,11 +873,14 @@
 	show_trace((unsigned long *)tsk->thread.esp0);
 }
 
-static void dump_stack(struct frame *fp)
+static void show_stack(struct frame *fp)
 {
 	unsigned long *stack, *endstack, addr;
 	int i;
 
+	if (fp == NULL)
+	    fp = (struct frame *)&fp;
+
 	addr = (unsigned long)&fp->un;
 	printk("Frame format=%X ", fp->ptregs.format);
 	switch (fp->ptregs.format) {
@@ -952,6 +954,14 @@
 	printk ("\n");
 }
 
+/*
+ * The architecture-independent backtrace generator
+ */
+void dump_stack(void)
+{
+	show_stack(0);
+}
+
 void bad_super_trap (struct frame *fp)
 {
 	console_verbose();
@@ -1122,7 +1132,7 @@
 
 	printk("Process %s (pid: %d, stackpage=%08lx)\n",
 		current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
-	dump_stack((struct frame *)fp);
+	show_stack((struct frame *)fp);
 	do_exit(SIGSEGV);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/mac/config.c linux-2.4.20/arch/m68k/mac/config.c
--- linux-2.4.19/arch/m68k/mac/config.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/mac/config.c	2002-10-29 11:18:39.000000000 +0000
@@ -21,6 +21,7 @@
 #include <linux/delay.h>
 /* keyb */
 #include <linux/init.h>
+#include <linux/vt_kern.h>
 
 #define BOOTINFO_COMPAT_1_0
 #include <asm/setup.h>
@@ -47,6 +48,8 @@
 struct mac_booter_data mac_bi_data = {0,};
 int mac_bisize = sizeof mac_bi_data;
 
+struct mac_hw_present mac_hw_present;
+
 /* New m68k bootinfo stuff and videobase */
 
 extern int m68k_num_memory;
@@ -76,7 +79,6 @@
 extern void psc_init(void);
 extern void baboon_init(void);
 
-extern void (*kd_mksound)(unsigned int, unsigned int);
 extern void mac_mksound(unsigned int, unsigned int);
 
 extern void nubus_sweep_video(void);
@@ -85,8 +87,6 @@
 extern void mac_debug_init(void);
 extern void mac_debugging_long(int, long);
 
-extern void (*kd_mksound)(unsigned int, unsigned int);
-
 extern int mackbd_init_hw(void);
 extern void mackbd_leds(unsigned int leds);
 extern int mackbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode);
@@ -207,7 +207,7 @@
 	if (!MACH_IS_MAC) {
 	  printk("ERROR: no Mac, but config_mac() called!! \n");
 	}
-	
+
 #ifdef CONFIG_VT
 #ifdef CONFIG_INPUT_ADBHID
 	mach_keyb_init       = mac_hid_init_hw;
@@ -228,9 +228,12 @@
 	mach_keyb_init       = mackbd_init_hw;
 	mach_kbd_leds        = mackbd_leds;
 	mach_kbd_translate   = mackbd_translate;
+#ifdef CONFIG_MAGIC_SYSRQ
 	mach_sysrq_xlate     = mackbd_sysrq_xlate;
 	SYSRQ_KEY = 0x69;
+#endif /* CONFIG_MAGIC_SYSRQ */
 #endif /* CONFIG_INPUT_ADBHID */
+	kd_mksound		 = mac_mksound;
 #endif /* CONFIG_VT */
 
 	mach_sched_init      = mac_sched_init;
@@ -252,12 +255,13 @@
 	mach_reset           = mac_reset;
 	mach_halt            = mac_poweroff;
 	mach_power_off       = mac_poweroff;
+#ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp	         = &dummy_con;
+#endif
 	mach_max_dma_address = 0xffffffff;
 #if 0
 	mach_debug_init	 = mac_debug_init;
 #endif
-	kd_mksound		 = mac_mksound;
 #ifdef CONFIG_HEARTBEAT
 #if 0
 	mach_heartbeat = mac_heartbeat;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/mac/debug.c linux-2.4.20/arch/m68k/mac/debug.c
--- linux-2.4.19/arch/m68k/mac/debug.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/mac/debug.c	2002-10-29 11:18:50.000000000 +0000
@@ -36,7 +36,7 @@
 extern unsigned long mac_videodepth;
 extern unsigned long mac_rowbytes;
 
-extern void mac_serial_print(char *);
+extern void mac_serial_print(const char *);
 
 #define DEBUG_HEADS
 #undef DEBUG_SCREEN
@@ -137,7 +137,7 @@
  * TODO: serial debug code
  */
 
-struct SCC
+struct mac_SCC
  {
   u_char cha_b_ctrl;
   u_char char_dummy1;
@@ -148,7 +148,7 @@
   u_char cha_a_data;
  };
 
-# define scc (*((volatile struct SCC*)mac_bi_data.sccbase))
+# define scc (*((volatile struct mac_SCC*)mac_bi_data.sccbase))
 
 /* Flag that serial port is already initialized and used */
 int mac_SCC_init_done = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/mac/macints.c linux-2.4.20/arch/m68k/mac/macints.c
--- linux-2.4.19/arch/m68k/mac/macints.c	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.20/arch/m68k/mac/macints.c	2002-10-29 11:18:35.000000000 +0000
@@ -249,7 +249,7 @@
 #endif /* SHUTUP_SONIC */
 
 	/* 
-	 * Now register the handlers for the the master IRQ handlers
+	 * Now register the handlers for the master IRQ handlers
 	 * at levels 1-7. Most of the work is done elsewhere.
 	 */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/mac/misc.c linux-2.4.20/arch/m68k/mac/misc.c
--- linux-2.4.19/arch/m68k/mac/misc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/mac/misc.c	2002-10-29 11:18:48.000000000 +0000
@@ -229,8 +229,8 @@
 	do {
 		if (++ct > 10) {
 			printk("via_read_time: couldn't get valid time, "
-			       "last read = 0x%08X and 0x%08X\n", last_result.idata,
-			       result.idata);
+			       "last read = 0x%08lx and 0x%08lx\n",
+			       last_result.idata, result.idata);
 			break;
 		}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/mm/fault.c linux-2.4.20/arch/m68k/mm/fault.c
--- linux-2.4.19/arch/m68k/mm/fault.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/mm/fault.c	2002-10-29 11:18:40.000000000 +0000
@@ -179,14 +179,12 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (current->pid == 1) {
-		current->policy |= SCHED_YIELD;
-		schedule();
-		down_read(&mm->mmap_sem);
+		yield();
 		goto survive;
 	}
-	
+
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/mvme147/config.c linux-2.4.20/arch/m68k/mvme147/config.c
--- linux-2.4.19/arch/m68k/mvme147/config.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/mvme147/config.c	2002-10-29 11:18:35.000000000 +0000
@@ -103,8 +103,10 @@
 {
 	mach_max_dma_address	= 0x01000000;
 	mach_sched_init		= mvme147_sched_init;
+#ifdef CONFIG_VT
 	mach_keyb_init		= mvme147_keyb_init;
 	mach_kbdrate		= mvme147_kbdrate;
+#endif
 	mach_init_IRQ		= mvme147_init_IRQ;
 	mach_gettimeoffset	= mvme147_gettimeoffset;
 	mach_gettod		= mvme147_gettod;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/mvme16x/config.c linux-2.4.20/arch/m68k/mvme16x/config.c
--- linux-2.4.19/arch/m68k/mvme16x/config.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/mvme16x/config.c	2002-10-29 11:18:36.000000000 +0000
@@ -145,14 +145,16 @@
 
     mach_max_dma_address = 0xffffffff;
     mach_sched_init      = mvme16x_sched_init;
+#ifdef CONFIG_VT
     mach_keyb_init       = mvme16x_keyb_init;
     mach_kbdrate         = mvme16x_kbdrate;
+/*  kd_mksound           = mvme16x_mksound; */
+#endif
     mach_init_IRQ        = mvme16x_init_IRQ;
     mach_gettimeoffset   = mvme16x_gettimeoffset;
     mach_gettod  	 = mvme16x_gettod;
     mach_hwclk           = mvme16x_hwclk;
     mach_set_clock_mmss	 = mvme16x_set_clock_mmss;
-/*  kd_mksound           = mvme16x_mksound; */
     mach_reset		 = mvme16x_reset;
     mach_free_irq	 = mvme16x_free_irq;
     mach_process_int	 = mvme16x_process_int;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/q40/config.c linux-2.4.20/arch/m68k/q40/config.c
--- linux-2.4.19/arch/m68k/q40/config.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/q40/config.c	2002-10-29 11:18:47.000000000 +0000
@@ -23,6 +23,7 @@
 #include <linux/major.h>
 #include <linux/serial_reg.h>
 #include <linux/rtc.h>
+#include <linux/vt_kern.h>
 
 #include <asm/io.h>
 #include <asm/rtc.h>
@@ -63,7 +64,6 @@
 extern void q40_waitbut(void);
 void q40_set_vectors (void);
 
-extern void (*kd_mksound)(unsigned int, unsigned int);
 void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ );
 
 extern char *saved_command_line;
@@ -164,42 +164,6 @@
     sprintf(model, "Q40");
 }
 
-/* pasted code to make parport_pc happy */
-extern __inline__ int __get_order(unsigned long size)
-{
-	int order;
-
-	size = (size-1) >> (PAGE_SHIFT-1);
-	order = -1;
-	do {
-		size >>= 1;
-		order++;
-	} while (size);
-	return order;
-}
-void *pci_alloc_consistent(void *hwdev, size_t size,
-			   dma_addr_t *dma_handle)
-{
-	void *ret;
-	int gfp = GFP_ATOMIC;
-
-	ret = (void *)__get_free_pages(gfp, __get_order(size));
-
-	if (ret != NULL) {
-		memset(ret, 0, size);
-		*dma_handle = virt_to_bus(ret);
-	}
-	return ret;
-}
-
-void pci_free_consistent(void *hwdev, size_t size,
-			 void *vaddr, dma_addr_t dma_handle)
-{
-	free_pages((unsigned long)vaddr, __get_order(size));
-}
-/* end pasted code */
-
-
 /* No hardware options on Q40? */
 
 static int q40_get_hardware_list(char *buffer)
@@ -223,8 +187,11 @@
 {
     mach_sched_init      = q40_sched_init;
 
+#ifdef CONFIG_VT
     mach_keyb_init       = q40kbd_init_hw;
     mach_kbd_translate   = q40kbd_translate;
+    kd_mksound             = q40_mksound;
+#endif
     mach_init_IRQ        = q40_init_IRQ;   
     mach_gettimeoffset   = q40_gettimeoffset; 
     mach_gettod  	 = q40_gettod;
@@ -241,7 +208,6 @@
     mach_default_handler = &q40_sys_default_handler;
     mach_get_model       = q40_get_model;
     mach_get_hardware_list = q40_get_hardware_list;
-    kd_mksound             = q40_mksound;
 
 #ifdef CONFIG_MAGIC_SYSRQ
     mach_sysrq_key       = 0x54;
@@ -250,7 +216,9 @@
     mach_heartbeat = q40_heartbeat;
 #endif
     mach_halt = q40_halt;
+#ifdef CONFIG_DUMMY_CONSOLE
     conswitchp = &dummy_con;
+#endif
 
     /* disable a few things that SMSQ might have left enabled */
     q40_disable_irqs();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/sun3/config.c linux-2.4.20/arch/m68k/sun3/config.c
--- linux-2.4.19/arch/m68k/sun3/config.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/sun3/config.c	2002-10-29 11:18:49.000000000 +0000
@@ -141,7 +141,9 @@
         mach_default_handler = &sun3_default_handler;
         mach_request_irq     =  sun3_request_irq;
         mach_free_irq        =  sun3_free_irq;
+#ifdef CONFIG_VT
 //	mach_keyb_init       =  sun3_keyb_init;
+#endif
 	enable_irq     	     =  sun3_enable_irq;
         disable_irq  	     =  sun3_disable_irq;
 	mach_process_int     =  sun3_process_int;
@@ -152,7 +154,7 @@
 	mach_get_model	     =  sun3_get_model;
 	mach_hwclk           =  sun3_hwclk;
 	mach_halt	     =  sun3_halt;
-#if !defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_FB)
+#if !defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_DUMMY_CONSOLE)
 	conswitchp 	     = &dummy_con;
 #endif
 
@@ -165,9 +167,9 @@
 	
 	sun3_bootmem_alloc(memory_start, memory_end);
 
+#ifdef CONFIG_SUN3X_ZS
 	sun_serial_setup();
-
-
+#endif
 }
 
 void __init sun3_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/sun3/mmu_emu.c linux-2.4.20/arch/m68k/sun3/mmu_emu.c
--- linux-2.4.19/arch/m68k/sun3/mmu_emu.c	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.20/arch/m68k/sun3/mmu_emu.c	2002-10-29 11:18:32.000000000 +0000
@@ -52,7 +52,9 @@
 
 /* pointers to the mm structs for each task in each
    context. 0xffffffff is a marker for kernel context */
-struct mm_struct *ctx_alloc[CONTEXTS_NUM] = {0xffffffff, 0, 0, 0, 0, 0, 0, 0};
+struct mm_struct *ctx_alloc[CONTEXTS_NUM] = {
+	(struct mm_struct *)0xffffffff, 0, 0, 0, 0, 0, 0, 0
+};
 /* has this context been mmdrop'd? */
 static unsigned char ctx_avail = CONTEXTS_NUM-1;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/sun3/sbus.c linux-2.4.20/arch/m68k/sun3/sbus.c
--- linux-2.4.19/arch/m68k/sun3/sbus.c	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.20/arch/m68k/sun3/sbus.c	2002-10-29 11:18:31.000000000 +0000
@@ -16,9 +16,9 @@
 
 void __init sbus_init(void)
 {
-
+#ifdef CONFIG_SUN3X_ZS
 	rs_init();
-
+#endif
 }
 
 void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/sun3/sun3ints.c linux-2.4.20/arch/m68k/sun3/sun3ints.c
--- linux-2.4.19/arch/m68k/sun3/sun3ints.c	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.20/arch/m68k/sun3/sun3ints.c	2002-10-29 11:18:40.000000000 +0000
@@ -99,7 +99,7 @@
 };
 static void (*sun3_vechandler[192])(int, void *, struct pt_regs *);
 static void *vec_ids[192];
-static char *vec_names[192];
+static const char *vec_names[192];
 
 static void sun3_inthandle(int irq, void *dev_id, struct pt_regs *fp)
 {
@@ -122,8 +122,8 @@
 	sun3_inthandle, sun3_int5, sun3_inthandle, sun3_int7
 };
 
-static char *dev_names[SYS_IRQS] = { NULL, NULL, NULL, NULL, 
-				     NULL, "timer", NULL, NULL };
+static const char *dev_names[SYS_IRQS] = { NULL, NULL, NULL, NULL,
+					   NULL, "timer", NULL, NULL };
 
 void sun3_init_IRQ(void)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/sun3x/config.c linux-2.4.20/arch/m68k/sun3x/config.c
--- linux-2.4.19/arch/m68k/sun3x/config.c	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.20/arch/m68k/sun3x/config.c	2002-10-29 11:18:31.000000000 +0000
@@ -61,9 +61,11 @@
 	mach_get_irq_list	 = sun3_get_irq_list;
 	mach_max_dma_address = 0xffffffff; /* we can DMA anywhere, whee */
 
+#ifdef CONFIG_VT
 	mach_keyb_init       = sun3x_keyb_init;
 	mach_kbdrate         = sun3x_kbdrate;
 	mach_kbd_leds        = sun3x_kbd_leds;
+#endif
 
 	mach_default_handler = &sun3_default_handler;
 	mach_sched_init      = sun3x_sched_init;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/sun3x/prom.c linux-2.4.20/arch/m68k/sun3x/prom.c
--- linux-2.4.19/arch/m68k/sun3x/prom.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/sun3x/prom.c	2002-10-29 11:18:39.000000000 +0000
@@ -124,7 +124,8 @@
     idprom = &idprom_buffer;
 
     if((idprom->id_machtype & SM_ARCH_MASK) != SM_SUN3X) {
-	    printk("Warning: machine reports strange type %02x\n");
+	    printk("Warning: machine reports strange type %02x\n",
+		   idprom->id_machtype);
 	    printk("Pretending it's a 3/80, but very afraid...\n");
 	    idprom->id_machtype = SM_SUN3X | SM_3_80;
     }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/m68k/sun3x/time.c linux-2.4.20/arch/m68k/sun3x/time.c
--- linux-2.4.19/arch/m68k/sun3x/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/m68k/sun3x/time.c	2002-10-29 11:18:48.000000000 +0000
@@ -62,8 +62,8 @@
 
 int sun3x_hwclk(int set, struct rtc_time *t)
 {
-	volatile struct mostek_dt *h = 
-		(unsigned char *)(SUN3X_EEPROM+M_CONTROL);
+	volatile struct mostek_dt *h =
+		(struct mostek_dt *)(SUN3X_EEPROM+M_CONTROL);
 	unsigned long flags;
 
 	save_and_cli(flags);
@@ -100,6 +100,7 @@
     return 0L;
 }
 
+#if 0
 static void sun3x_timer_tick(int irq, void *dev_id, struct pt_regs *regs)
 {
     void (*vector)(int, void *, struct pt_regs *) = dev_id;
@@ -110,6 +111,7 @@
     
     vector(irq, NULL, regs);
 }
+#endif
 
 void __init sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *))
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/Makefile linux-2.4.20/arch/mips/Makefile
--- linux-2.4.19/arch/mips/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/Makefile	2002-10-29 11:18:31.000000000 +0000
@@ -27,7 +27,7 @@
 endif
 
 #
-# GCC uses -G0 -mabicalls -fpic as default.  We don't want PIC in the kernel
+# GCC uses -G 0 -mabicalls -fpic as default.  We don't want PIC in the kernel
 # code since it only slows down the whole thing.  At some point we might make
 # use of global pointer optimizations but their use of $28 conflicts with
 # the current pointer optimization.
@@ -141,7 +141,17 @@
 endif
 
 #
-# Au1000 (Alchemy Semi PB1500) eval board
+# Au1100 (Alchemy Semi PB1100) eval board
+#
+ifdef CONFIG_MIPS_PB1100
+LIBS          += arch/mips/au1000/pb1100/pb1100.o \
+                 arch/mips/au1000/common/au1000.o
+SUBDIRS       += arch/mips/au1000/pb1100 arch/mips/au1000/common
+LOADADDR      += 0x80100000
+endif
+
+#
+# Au1500 (Alchemy Semi PB1500) eval board
 #
 ifdef CONFIG_MIPS_PB1500
 LIBS		+= arch/mips/au1000/pb1500/pb1500.o \
@@ -257,6 +267,16 @@
 endif
 
 #
+# MIPS SEAD board
+#
+ifdef CONFIG_MIPS_SEAD
+LIBS		+= arch/mips/mips-boards/sead/sead.o \
+		   arch/mips/mips-boards/generic/mipsboards.o
+SUBDIRS		+= arch/mips/mips-boards/generic arch/mips/mips-boards/sead
+LOADADDR	:= 0x80100000
+endif
+
+#
 # Momentum Ocelot board
 #
 ifdef CONFIG_MOMENCO_OCELOT
@@ -269,11 +289,22 @@
 endif
 
 #
+# Momentum Ocelot-G board
+#
+ifdef CONFIG_MOMENCO_OCELOT_G
+# The Ocelot-G setup.o must be linked early - it does the ioremap() for the
+# mips_io_port_base.
+CORE_FILES	+= arch/mips/momentum/ocelot_g/ocelot_g.o
+SUBDIRS		+= arch/mips/momentum/ocelot_g
+LOADADDR	:= 0x80100000
+endif
+
+#
 # NEC DDB Vrc-5074
 #
 ifdef CONFIG_DDB5074
-SUBDIRS		+= arch/mips/ddb5074
-LIBS		+= arch/mips/ddb5074/ddb5074.a
+SUBDIRS		+= arch/mips/ddb5xxx/common arch/mips/ddb5xxx/ddb5074
+LIBS		+= arch/mips/ddb5xxx/common/ddb5xxx.o arch/mips/ddb5xxx/ddb5074/ddb5074.o
 LOADADDR	:= 0x80080000
 endif
 
@@ -294,7 +325,7 @@
 SUBDIRS		+= arch/mips/ddb5xxx/common arch/mips/ddb5xxx/ddb5477
 LIBS		+= arch/mips/ddb5xxx/common/ddb5xxx.o \
 		   arch/mips/ddb5xxx/ddb5477/ddb5477.o
-LOADADDR	:= 0x80080000
+LOADADDR	:= 0x80100000
 endif
 
 #
@@ -308,6 +339,28 @@
 endif
 
 #
+# NEC Eagle/Hawk (VR4122/VR4131) board
+#
+ifdef CONFIG_NEC_EAGLE
+SUBDIRS		+= arch/mips/vr41xx/common \
+		   arch/mips/vr41xx/nec-eagle
+LIBS		+= arch/mips/vr41xx/common/vr41xx.o \
+		   arch/mips/vr41xx/nec-eagle/eagle.o
+LOADADDR	:= 0x80000000
+endif
+
+#
+# ZAO Networks Capcella (VR4131)
+#
+ifdef CONFIG_ZAO_CAPCELLA
+SUBDIRS		+= arch/mips/vr41xx/common \
+		   arch/mips/vr41xx/zao-capcella
+LIBS		+= arch/mips/vr41xx/common/vr41xx.o \
+		   arch/mips/vr41xx/zao-capcella/capcella.o
+LOADADDR	:= 0x80000000
+endif
+
+#
 # Philips Nino
 #
 ifdef CONFIG_NINO
@@ -352,6 +405,14 @@
 endif
 
 #
+# Sibyte CFE firmware
+#
+ifdef CONFIG_SIBYTE_CFE
+LIBS		+= arch/mips/sibyte/cfe/cfe.a
+SUBDIRS		+= arch/mips/sibyte/cfe
+endif
+
+#
 # SB1 Cache Error handler
 #
 ifdef CONFIG_SB1_CACHE_ERROR
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/arc/Makefile linux-2.4.20/arch/mips/arc/Makefile
--- linux-2.4.19/arch/mips/arc/Makefile	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/arch/mips/arc/Makefile	2002-10-29 11:18:35.000000000 +0000
@@ -1,18 +1,13 @@
 #
-# Makefile for the SGI arcs prom monitor library routines
-# under Linux.
+# Makefile for the ARC prom monitor library routines under Linux.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
 L_TARGET = arclib.a
 
-obj-y		+= console.o init.o memory.o tree.o env.o cmdline.o misc.o \
-		   time.o file.o identify.o
+obj-y				+= cmdline.o console.o env.o file.o \
+				   identify.o init.o misc.o time.o tree.o
 
-obj-$(CONFIG_ARC_CONSOLE)   += arc_con.o
+obj-$(CONFIG_ARC_MEMORY)	+= memory.o
+obj-$(CONFIG_ARC_CONSOLE)	+= arc_con.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/arc/arc_con.c linux-2.4.20/arch/mips/arc/arc_con.c
--- linux-2.4.19/arch/mips/arc/arc_con.c	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/arch/mips/arc/arc_con.c	2002-10-29 11:18:40.000000000 +0000
@@ -2,61 +2,49 @@
  * Wrap-around code for a console using the
  * ARC io-routines.
  *
- * Copyright (c) 1998 Harald Koerfgen 
+ * Copyright (c) 1998 Harald Koerfgen
+ * Copyright (c) 2001 Ralf Baechle
+ * Copyright (c) 2002 Thiemo Seufer
  */
-
 #include <linux/tty.h>
 #include <linux/major.h>
 #include <linux/ptrace.h>
 #include <linux/init.h>
 #include <linux/console.h>
 #include <linux/fs.h>
-
-extern char prom_getchar (void);
-extern void prom_printf (char *, ...);
+#include <asm/sgialib.h>
 
 static void prom_console_write(struct console *co, const char *s,
 			       unsigned count)
 {
-	unsigned i;
-
-	/*
-	 *    Now, do each character
-	 */
-	for (i = 0; i < count; i++) {
-		if (*s == 10)
-			prom_printf("%c", 13);
-		prom_printf("%c", *s++);
+	/* Do each character */
+	while (count--) {
+		if (*s == '\n')
+			prom_putchar('\r');
+		prom_putchar(*s++);
 	}
 }
 
-static int prom_console_wait_key(struct console *co)
+static kdev_t prom_console_device(struct console *co)
 {
-	return prom_getchar();
+	return MKDEV(TTY_MAJOR, 64 + co->index);
 }
 
 static int __init prom_console_setup(struct console *co, char *options)
 {
-	return 0;
-}
-
-static kdev_t prom_console_device(struct console *c)
-{
-	return MKDEV(TTY_MAJOR, 64 + c->index);
+	if (prom_flags & PROM_FLAG_USE_AS_CONSOLE)
+		return 0;
+	else
+		return 1;
 }
 
 static struct console arc_cons = {
-	"ttyS",
-	prom_console_write,
-	NULL,
-	prom_console_device,
-	prom_console_wait_key,
-	NULL,
-	prom_console_setup,
-	CON_PRINTBUFFER,
-	-1,
-	0,
-	NULL
+	name:		"ttyS",
+	write:		prom_console_write,
+	device:		prom_console_device,
+	setup:		prom_console_setup,
+	flags:		CON_PRINTBUFFER,
+	index:		-1,
 };
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/arc/cmdline.c linux-2.4.20/arch/mips/arc/cmdline.c
--- linux-2.4.19/arch/mips/arc/cmdline.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/arc/cmdline.c	2002-10-29 11:18:50.000000000 +0000
@@ -1,4 +1,8 @@
 /*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
  * cmdline.c: Kernel command line creation using ARCS argc/argv.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -46,13 +50,13 @@
 		for(i = 0; i < NENTS(used_arc); i++) {
 			int len = strlen(used_arc[i][0]);
 
-			if(!strncmp(prom_argv[actr], used_arc[i][0], len)) {
+			if (!strncmp(prom_argv(actr), used_arc[i][0], len)) {
 			/* Ok, we want it. First append the replacement... */
 				strcat(cp, used_arc[i][1]);
 				cp += strlen(used_arc[i][1]);
 				/* ... and now the argument */
-				s = strstr(prom_argv[actr], "=");
-				if(s) {
+				s = strstr(prom_argv(actr), "=");
+				if (s) {
 					s++;
 					strcpy(cp, s);
 					cp += strlen(s);
@@ -76,7 +80,7 @@
 	actr = 1; /* Always ignore argv[0] */
 
 	cp = &(arcs_cmdline[0]);
-	/* 
+	/*
 	 * Move ARC variables to the beginning to make sure they can be
 	 * overridden by later arguments.
 	 */
@@ -86,12 +90,12 @@
 		for (i = 0; i < NENTS(ignored); i++) {
 			int len = strlen(ignored[i]);
 
-			if(!strncmp(prom_argv[actr], ignored[i], len))
+			if (!strncmp(prom_argv(actr), ignored[i], len))
 				goto pic_cont;
 		}
 		/* Ok, we want it. */
-		strcpy(cp, prom_argv[actr]);
-		cp += strlen(prom_argv[actr]);
+		strcpy(cp, prom_argv(actr));
+		cp += strlen(prom_argv(actr));
 		*cp++ = ' ';
 
 	pic_cont:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/arc/console.c linux-2.4.20/arch/mips/arc/console.c
--- linux-2.4.19/arch/mips/arc/console.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/arc/console.c	2002-10-29 11:18:40.000000000 +0000
@@ -6,13 +6,9 @@
  * Copyright (C) 1996 David S. Miller (dm@sgi.com)
  * Compability with board caches, Ulf Carlsson
  */
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <asm/sgialib.h>
 #include <asm/bcache.h>
-#include <linux/console.h>
-#include <linux/kdev_t.h>
-#include <linux/major.h>
 
 /*
  * IP22 boardcache is not compatible with board caches.  Thus we disable it
@@ -26,18 +22,18 @@
 
 void prom_putchar(char c)
 {
-	long cnt;
-	char it = c;
+	ULONG cnt;
+	CHAR it = c;
 
 	bc_disable();
 	ArcWrite(1, &it, 1, &cnt);
 	bc_enable();
 }
 
-char __init prom_getchar(void)
+char prom_getchar(void)
 {
-	long cnt;
-	char c;
+	ULONG cnt;
+	CHAR c;
 
 	bc_disable();
 	ArcRead(0, &c, 1, &cnt);
@@ -46,24 +42,22 @@
 	return c;
 }
 
-static char ppbuf[1024];
-
 void prom_printf(char *fmt, ...)
 {
 	va_list args;
-	char ch, *bptr;
-	int i;
+	char ppbuf[1024];
+	char *bptr;
 
 	va_start(args, fmt);
-	i = vsprintf(ppbuf, fmt, args);
+	vsprintf(ppbuf, fmt, args);
 
 	bptr = ppbuf;
 
-	while ((ch = *(bptr++)) != 0) {
-		if (ch == '\n')
+	while (*bptr != 0) {
+		if (*bptr == '\n')
 			prom_putchar('\r');
 
-		prom_putchar(ch);
+		prom_putchar(*bptr++);
 	}
 	va_end(args);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/arc/identify.c linux-2.4.20/arch/mips/arc/identify.c
--- linux-2.4.19/arch/mips/arc/identify.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/arc/identify.c	2002-10-29 11:18:34.000000000 +0000
@@ -1,10 +1,14 @@
 /*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
  * identify.c: identify machine by looking up system identifier
  *
  * Copyright (C) 1998 Thomas Bogendoerfer
- * 
+ *
  * This code is based on arch/mips/sgi/kernel/system.c, which is
- * 
+ *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  */
 #include <linux/config.h>
@@ -13,7 +17,6 @@
 #include <linux/types.h>
 #include <linux/string.h>
 
-#include <asm/sgi/sgi.h>
 #include <asm/sgialib.h>
 #include <asm/bootinfo.h>
 
@@ -31,6 +34,21 @@
 		MACH_GROUP_SGI,
 		MACH_SGI_INDY,
 		PROM_FLAG_ARCS
+	}, {	"SGI-IP27",
+		"SGI Origin",
+		MACH_GROUP_SGI,
+		MACH_SGI_IP27,
+		PROM_FLAG_ARCS
+	}, {	"SGI-IP28",
+		"SGI IP28",
+		MACH_GROUP_SGI,
+		MACH_SGI_IP28,
+		PROM_FLAG_ARCS
+	}, {	"SGI-IP32",
+		"SGI IP32",
+		MACH_GROUP_SGI,
+		MACH_SGI_IP32,
+		PROM_FLAG_ARCS
 	}, {	"Microsoft-Jazz",
 		"Jazz MIPS_Magnum_4000",
 		MACH_GROUP_JAZZ,
@@ -51,7 +69,7 @@
 
 int prom_flags;
 
-static struct smatch *__init string_to_mach(const char *s)
+static struct smatch * __init string_to_mach(const char *s)
 {
 	int i;
 
@@ -77,15 +95,16 @@
 	const char *iname;
 
 	/*
-	 * The root component tells us what machine architecture we
-	 * have here.
+	 * The root component tells us what machine architecture we have here.
 	 */
 	p = ArcGetChild(PROM_NULL_COMPONENT);
 	if (p == NULL) {
 #ifdef CONFIG_SGI_IP27
-	/* IP27 PROM bisbehaves, seems to not implement ARC
-	   GetChild().  So we just assume it's an IP27.  */
+		/* IP27 PROM misbehaves, seems to not implement ARC
+		   GetChild().  So we just assume it's an IP27.  */
 		iname = "SGI-IP27";
+#else
+		iname = "Unknown";
 #endif
 	} else
 		iname = (char *) (long) p->iname;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/arc/init.c linux-2.4.20/arch/mips/arc/init.c
--- linux-2.4.19/arch/mips/arc/init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/arc/init.c	2002-10-29 11:18:39.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * This file is subject to the terms and conditions of the GNU General Public+ 
+ * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
@@ -17,20 +17,15 @@
 /* Master romvec interface. */
 struct linux_romvec *romvec;
 int prom_argc;
-char **prom_argv, **prom_envp;
-
-extern void prom_testtree(void);
+LONG *_prom_argv, *_prom_envp;
 
 void __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
 {
-	PSYSTEM_PARAMETER_BLOCK pb;
-	unsigned short prom_vers, prom_rev;
-
+	PSYSTEM_PARAMETER_BLOCK pb = PROMBLOCK;
 	romvec = ROMVECTOR;
-	pb = PROMBLOCK;
 	prom_argc = argc;
-	prom_argv = argv;
-	prom_envp = envp;
+	_prom_argv = (LONG *) argv;
+	_prom_envp = (LONG *) envp;
 
 	if (pb->magic != 0x53435241) {
 		prom_printf("Aieee, bad prom vector magic %08lx\n", pb->magic);
@@ -39,19 +34,14 @@
 	}
 
 	prom_init_cmdline();
-
-	prom_vers = pb->ver;
-	prom_rev = pb->rev;
 	prom_identify_arch();
-	printk("PROMLIB: ARC firmware Version %d Revision %d\n",
-		    prom_vers, prom_rev);
+	printk(KERN_INFO "PROMLIB: ARC firmware Version %d Revision %d\n",
+	       pb->ver, pb->rev);
 	prom_meminit();
 
 #ifdef DEBUG_PROM_INIT
-	{
-		prom_printf("Press a key to reboot\n");
-		(void) prom_getchar();
-		romvec->imode();
-	}
+	prom_printf("Press a key to reboot\n");
+	prom_getchar();
+	ArcEnterInteractiveMode();
 #endif
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/arc/memory.c linux-2.4.20/arch/mips/arc/memory.c
--- linux-2.4.19/arch/mips/arc/memory.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/arc/memory.c	2002-10-29 11:18:33.000000000 +0000
@@ -2,7 +2,14 @@
  * memory.c: PROM library functions for acquiring/using memory descriptors
  *           given to us from the ARCS firmware.
  *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 by David S. Miller
+ * Copyright (C) 1999, 2000, 2001 by Ralf Baechle
+ * Copyright (C) 1999, 2000 by Silicon Graphics, Inc.
+ *
+ * PROM library functions for acquiring/using memory descriptors given to us
+ * from the ARCS firmware.  This is only used when CONFIG_ARC_MEMORY is set
+ * because on some machines like SGI IP27 the ARC memory configuration data
+ * completly bogus and alternate easier to use mechanisms are available.
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -19,8 +26,7 @@
 
 #undef DEBUG
 
-struct linux_mdesc * __init
-ArcGetMemoryDescriptor(struct linux_mdesc *Current)
+struct linux_mdesc * __init ArcGetMemoryDescriptor(struct linux_mdesc *Current)
 {
 	return (struct linux_mdesc *) ARC_CALL1(get_mdesc, Current);
 }
@@ -47,7 +53,8 @@
 	"FirmwarePermanent",
 	"FreeContiguous"
 };
-#define mtypes(a) (prom_flags & PROM_FLAG_ARCS) ? arcs_mtypes[a.arcs] : arc_mtypes[a.arc]
+#define mtypes(a) (prom_flags & PROM_FLAG_ARCS) ? arcs_mtypes[a.arcs] \
+						: arc_mtypes[a.arc]
 #endif
 
 static inline int memtype_classify_arcs (union linux_memtypes type)
@@ -92,7 +99,7 @@
 
 static int __init prom_memtype_classify (union linux_memtypes type)
 {
-	if (prom_flags & PROM_FLAG_ARCS)	/* SGI is ``different'' ...  */
+	if (prom_flags & PROM_FLAG_ARCS)	/* SGI is ``different'' ... */
 		return memtype_classify_arcs(type);
 
 	return memtype_classify_arc(type);
@@ -128,8 +135,7 @@
 	}
 }
 
-void __init
-prom_free_prom_memory (void)
+void __init prom_free_prom_memory (void)
 {
 	unsigned long freed = 0;
 	unsigned long addr;
@@ -149,5 +155,5 @@
 			freed += PAGE_SIZE;
 		}
 	}
-	printk("Freeing prom memory: %ldkb freed\n", freed >> 10);
+	printk(KERN_INFO "Freeing prom memory: %ldkb freed\n", freed >> 10);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/arc/salone.c linux-2.4.20/arch/mips/arc/salone.c
--- linux-2.4.19/arch/mips/arc/salone.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/arc/salone.c	2002-10-29 11:18:51.000000000 +0000
@@ -1,23 +1,24 @@
 /*
- * salone.c: Routines to load into memory and execute stand-along
- *           program images using ARCS PROM firmware.
+ * Routines to load into memory and execute stand-along program images using
+ * ARCS PROM firmware.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  */
 #include <linux/init.h>
 #include <asm/sgialib.h>
 
-long __init prom_load(char *name, unsigned long end, unsigned long *pc, unsigned long *eaddr)
+LONG __init ArcLoad(CHAR *Path, ULONG TopAddr, ULONG *ExecAddr, ULONG *LowAddr)
 {
-	return romvec->load(name, end, pc, eaddr);
+	return ARC_CALL4(load, Path, TopAddr, ExecAddr, LowAddr);
 }
 
-long __init prom_invoke(unsigned long pc, unsigned long sp, long argc, char **argv, char **envp)
+LONG __init ArcInvoke(ULONG ExecAddr, ULONG StackAddr, ULONG Argc, CHAR *Argv[],
+	CHAR *Envp[])
 {
-	return romvec->invoke(pc, sp, argc, argv, envp);
+	return ARC_CALL5(invoke, ExecAddr, StackAddr, Argc, Argv, Envp);
 }
 
-long __init prom_exec(char *name, long argc, char **argv, char **envp)
+LONG __init ArcExecute(CHAR *Path, LONG Argc, CHAR *Argv[], CHAR *Envp[])
 {
-	return romvec->exec(name, argc, argv, envp);
+	return ARC_CALL4(exec, Path, Argc, Argv, Envp);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/common/Makefile linux-2.4.20/arch/mips/au1000/common/Makefile
--- linux-2.4.19/arch/mips/au1000/common/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/common/Makefile	2002-10-29 11:18:50.000000000 +0000
@@ -10,22 +10,20 @@
 # unless it's something special (ie not a .c file).
 #
 
-.S.s:
-	$(CPP) $(CFLAGS) $< -o $*.s
-.S.o:
-	$(CC) $(CFLAGS) -c $< -o $*.o
+USE_STANDARD_AS_RULE := true
 
 all: au1000.o
 
 O_TARGET := au1000.o
 
-export-objs		= prom.o serial.o clocks.o
+export-objs		= prom.o serial.o clocks.o power.o usbdev.o
 
-obj-y := prom.o int-handler.o dma.o irq.o puts.o time.o reset.o power.o clocks.o
+obj-y := prom.o int-handler.o dma.o irq.o puts.o time.o reset.o \
+	clocks.o power.o usbdev.o
 
-obj-$(CONFIG_AU1000_UART) += serial.o             
+obj-$(CONFIG_AU1000_UART) += serial.o
 obj-$(CONFIG_AU1000_USB_DEVICE) += usbdev.o
-obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o             
+obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o
 obj-$(CONFIG_RTC) += rtc.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/common/clocks.c linux-2.4.20/arch/mips/au1000/common/clocks.c
--- linux-2.4.19/arch/mips/au1000/common/clocks.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/common/clocks.c	2002-10-29 11:18:39.000000000 +0000
@@ -75,9 +75,9 @@
 	unsigned int static_cfg0;
 	unsigned int sys_busclk =
 		(get_au1000_speed()/1000) /
-		((int)(inl(SYS_POWERCTRL)&0x03) + 2);
+		((int)(au_readl(SYS_POWERCTRL)&0x03) + 2);
 
-	static_cfg0 = inl(MEM_STCFG0);
+	static_cfg0 = au_readl(MEM_STCFG0);
 
 	if (static_cfg0 & (1<<11))
 		lcd_clock = sys_busclk / 5; /* note: BCLK switching fails with D5 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/common/dbg_io.c linux-2.4.20/arch/mips/au1000/common/dbg_io.c
--- linux-2.4.19/arch/mips/au1000/common/dbg_io.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/common/dbg_io.c	2002-10-29 11:18:39.000000000 +0000
@@ -53,8 +53,8 @@
 #define UART_MOD_CNTRL	0x100	/* Module Control */
 
 /* memory-mapped read/write of the port */
-#define UART16550_READ(y)    (readl(DEBUG_BASE + y) & 0xff)
-#define UART16550_WRITE(y,z) (writel(z&0xff, DEBUG_BASE + y))
+#define UART16550_READ(y)    (au_readl(DEBUG_BASE + y) & 0xff)
+#define UART16550_WRITE(y,z) (au_writel(z&0xff, DEBUG_BASE + y))
 
 extern unsigned long get_au1000_uart_baud_base(void);
 extern unsigned long cal_r4koff(void);
@@ -71,7 +71,7 @@
 	UART16550_WRITE(UART_IER, 0);
 
 	/* set up baud rate */
-	{ 
+	{
 		uint32 divisor;
 
 		/* set divisor */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/common/dma.c linux-2.4.20/arch/mips/au1000/common/dma.c
--- linux-2.4.19/arch/mips/au1000/common/dma.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/common/dma.c	2002-10-29 11:18:31.000000000 +0000
@@ -77,23 +77,22 @@
 	unsigned int fifo_addr;
 	unsigned int dma_mode;
 } dma_dev_table[DMA_NUM_DEV] = {
-	{
-	UART0_ADDR + UART_TX, 0}, {
-	UART0_ADDR + UART_RX, 0}, {
-	0, 0}, {
-	0, 0}, {
-	AC97C_DATA, DMA_DW16 | DMA_NC}, {
-	AC97C_DATA, DMA_DR | DMA_DW16 | DMA_NC}, {
-	UART3_ADDR + UART_TX, DMA_DW8 | DMA_NC}, {
-	UART3_ADDR + UART_RX, DMA_DR | DMA_DW8 | DMA_NC}, {
-	USBD_EP0RD, DMA_DR | DMA_DW8 | DMA_NC}, {
-	USBD_EP0WR, DMA_DW8 | DMA_NC}, {
-	USBD_EP2WR, DMA_DW8 | DMA_NC}, {
-	USBD_EP3WR, DMA_DW8 | DMA_NC}, {
-	USBD_EP4RD, DMA_DR | DMA_DW8 | DMA_NC}, {
-	USBD_EP5RD, DMA_DR | DMA_DW8 | DMA_NC}, {
-	I2S_DATA, DMA_DW32 | DMA_NC}, {
-	I2S_DATA, DMA_DR | DMA_DW32 | DMA_NC}
+	{UART0_ADDR + UART_TX, 0},
+	{UART0_ADDR + UART_RX, 0},
+	{0, 0},
+	{0, 0},
+	{AC97C_DATA, DMA_DW16 },          // coherent
+	{AC97C_DATA, DMA_DR | DMA_DW16 }, // coherent
+	{UART3_ADDR + UART_TX, DMA_DW8 | DMA_NC},
+	{UART3_ADDR + UART_RX, DMA_DR | DMA_DW8 | DMA_NC},
+	{USBD_EP0RD, DMA_DR | DMA_DW8 | DMA_NC},
+	{USBD_EP0WR, DMA_DW8 | DMA_NC},
+	{USBD_EP2WR, DMA_DW8 | DMA_NC},
+	{USBD_EP3WR, DMA_DW8 | DMA_NC},
+	{USBD_EP4RD, DMA_DR | DMA_DW8 | DMA_NC},
+	{USBD_EP5RD, DMA_DR | DMA_DW8 | DMA_NC},
+	{I2S_DATA, DMA_DW32 | DMA_NC},
+	{I2S_DATA, DMA_DR | DMA_DW32 | DMA_NC}
 };
 
 
@@ -105,9 +104,8 @@
 
 	for (i = 0; i < NUM_AU1000_DMA_CHANNELS; i++) {
 		if ((chan = get_dma_chan(i)) != NULL) {
-			len +=
-			    sprintf(buf + len, "%2d: %s\n", i,
-				    chan->dev_str);
+			len += sprintf(buf + len, "%2d: %s\n",
+				       i, chan->dev_str);
 		}
 	}
 
@@ -134,28 +132,32 @@
 
 	printk(KERN_INFO "Au1000 DMA%d Register Dump:\n", dmanr);
 	printk(KERN_INFO "  mode = 0x%08x\n",
-	       inl(chan->io + DMA_MODE_SET));
+	       au_readl(chan->io + DMA_MODE_SET));
 	printk(KERN_INFO "  addr = 0x%08x\n",
-	       inl(chan->io + DMA_PERIPHERAL_ADDR));
+	       au_readl(chan->io + DMA_PERIPHERAL_ADDR));
 	printk(KERN_INFO "  start0 = 0x%08x\n",
-	       inl(chan->io + DMA_BUFFER0_START));
+	       au_readl(chan->io + DMA_BUFFER0_START));
 	printk(KERN_INFO "  start1 = 0x%08x\n",
-	       inl(chan->io + DMA_BUFFER1_START));
+	       au_readl(chan->io + DMA_BUFFER1_START));
 	printk(KERN_INFO "  count0 = 0x%08x\n",
-	       inl(chan->io + DMA_BUFFER0_COUNT));
+	       au_readl(chan->io + DMA_BUFFER0_COUNT));
 	printk(KERN_INFO "  count1 = 0x%08x\n",
-	       inl(chan->io + DMA_BUFFER1_COUNT));
+	       au_readl(chan->io + DMA_BUFFER1_COUNT));
 }
 
 
 /*
  * Finds a free channel, and binds the requested device to it.
  * Returns the allocated channel number, or negative on error.
+ * Requests the DMA done IRQ if irqhandler != NULL.
  */
-int request_au1000_dma(int dev_id, const char *dev_str)
+int request_au1000_dma(int dev_id, const char *dev_str,
+		       void (*irqhandler)(int, void *, struct pt_regs *),
+		       unsigned long irqflags,
+		       void *irq_dev_id)
 {
 	struct dma_chan *chan;
-	int i;
+	int i, ret;
 
 	if (dev_id < 0 || dev_id >= DMA_NUM_DEV)
 		return -EINVAL;
@@ -169,14 +171,30 @@
 
 	chan = &au1000_dma_table[i];
 
+	if (irqhandler) {
+		chan->irq = AU1000_DMA_INT_BASE + i;
+		chan->irq_dev = irq_dev_id;
+		if ((ret = request_irq(chan->irq, irqhandler, irqflags,
+				       dev_str, chan->irq_dev))) {
+			chan->irq = 0;
+			chan->irq_dev = NULL;
+			return ret;
+		}
+	} else {
+		chan->irq = 0;
+		chan->irq_dev = NULL;
+	}
+
 	// fill it in
 	chan->io = DMA_CHANNEL_BASE + i * DMA_CHANNEL_LEN;
-	chan->irq = AU1000_DMA_INT_BASE + i;
 	chan->dev_id = dev_id;
 	chan->dev_str = dev_str;
 	chan->fifo_addr = dma_dev_table[dev_id].fifo_addr;
 	chan->mode = dma_dev_table[dev_id].dma_mode;
 
+	/* initialize the channel before returning */
+	init_dma(i);
+
 	return i;
 }
 
@@ -190,6 +208,10 @@
 	}
 
 	disable_dma(dmanr);
+	if (chan->irq)
+		free_irq(chan->irq, chan->irq_dev);
 
+	chan->irq = 0;
+	chan->irq_dev = NULL;
 	chan->dev_id = -1;
-}				/* free_dma */
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/common/int-handler.S linux-2.4.20/arch/mips/au1000/common/int-handler.S
--- linux-2.4.19/arch/mips/au1000/common/int-handler.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/common/int-handler.S	2002-10-29 11:18:36.000000000 +0000
@@ -9,7 +9,6 @@
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  */
-#include <linux/config.h>
 #include <asm/asm.h>
 #include <asm/mipsregs.h>
 #include <asm/addrspace.h>
@@ -40,30 +39,30 @@
 
 1:
 	andi	a0, t0, CAUSEF_IP2	# Interrupt Controller 0, Request 0
-	beq	a0, zero, 2f	        
-	move	a0,sp  
+	beq	a0, zero, 2f
+	move	a0,sp
 	jal	intc0_req0_irqdispatch
 	j	ret_from_irq
 2:
 	andi	a0, t0, CAUSEF_IP3	# Interrupt Controller 0, Request 1
-	beq	a0, zero, 3f	       
-	move	a0,sp  
+	beq	a0, zero, 3f
+	move	a0,sp
 	jal	intc0_req1_irqdispatch
 	j	ret_from_irq
 3:
 	andi	a0, t0, CAUSEF_IP4	# Interrupt Controller 1, Request 0
-	beq	a0, zero, 4f	       
-	move	a0,sp  
+	beq	a0, zero, 4f
+	move	a0,sp
 	jal	intc1_req0_irqdispatch
 	j	ret_from_irq
 4:
 	andi	a0, t0, CAUSEF_IP5	# Interrupt Controller 1, Request 1
-	beq	a0, zero, 5f	       
-	move	a0, sp  
+	beq	a0, zero, 5f
+	move	a0, sp
 	jal	intc1_req1_irqdispatch
 	j	ret_from_irq
 
-5:	
+5:
 	move	a0, sp
 	j	spurious_interrupt
 END(au1000_IRQ)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/common/irq.c linux-2.4.20/arch/mips/au1000/common/irq.c
--- linux-2.4.19/arch/mips/au1000/common/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/common/irq.c	2002-10-29 11:18:37.000000000 +0000
@@ -51,6 +51,8 @@
 #include <asm/pb1000.h>
 #elif defined(CONFIG_MIPS_PB1500)
 #include <asm/pb1500.h>
+#elif defined(CONFIG_MIPS_PB1100)
+#include <asm/pb1100.h>
 #else
 #error unsupported alchemy board
 #endif
@@ -103,86 +105,86 @@
 	if (irq_nr > AU1000_LAST_INTC0_INT) {
 		switch (type) {
 			case INTC_INT_RISE_EDGE: /* 0:0:1 */
-				outl(1<<(irq_nr-32), IC1_CFG2CLR);
-				outl(1<<(irq_nr-32), IC1_CFG1CLR);
-				outl(1<<(irq_nr-32), IC1_CFG0SET);
+				au_writel(1<<(irq_nr-32), IC1_CFG2CLR);
+				au_writel(1<<(irq_nr-32), IC1_CFG1CLR);
+				au_writel(1<<(irq_nr-32), IC1_CFG0SET);
 				break;
 			case INTC_INT_FALL_EDGE: /* 0:1:0 */
-				outl(1<<(irq_nr-32), IC1_CFG2CLR);
-				outl(1<<(irq_nr-32), IC1_CFG1SET);
-				outl(1<<(irq_nr-32), IC1_CFG0CLR);
+				au_writel(1<<(irq_nr-32), IC1_CFG2CLR);
+				au_writel(1<<(irq_nr-32), IC1_CFG1SET);
+				au_writel(1<<(irq_nr-32), IC1_CFG0CLR);
 				break;
 			case INTC_INT_HIGH_LEVEL: /* 1:0:1 */
-				outl(1<<(irq_nr-32), IC1_CFG2SET);
-				outl(1<<(irq_nr-32), IC1_CFG1CLR);
-				outl(1<<(irq_nr-32), IC1_CFG0SET);
+				au_writel(1<<(irq_nr-32), IC1_CFG2SET);
+				au_writel(1<<(irq_nr-32), IC1_CFG1CLR);
+				au_writel(1<<(irq_nr-32), IC1_CFG0SET);
 				break;
 			case INTC_INT_LOW_LEVEL: /* 1:1:0 */
-				outl(1<<(irq_nr-32), IC1_CFG2SET);
-				outl(1<<(irq_nr-32), IC1_CFG1SET);
-				outl(1<<(irq_nr-32), IC1_CFG0CLR);
+				au_writel(1<<(irq_nr-32), IC1_CFG2SET);
+				au_writel(1<<(irq_nr-32), IC1_CFG1SET);
+				au_writel(1<<(irq_nr-32), IC1_CFG0CLR);
 				break;
 			case INTC_INT_DISABLED: /* 0:0:0 */
-				outl(1<<(irq_nr-32), IC1_CFG0CLR);
-				outl(1<<(irq_nr-32), IC1_CFG1CLR);
-				outl(1<<(irq_nr-32), IC1_CFG2CLR);
+				au_writel(1<<(irq_nr-32), IC1_CFG0CLR);
+				au_writel(1<<(irq_nr-32), IC1_CFG1CLR);
+				au_writel(1<<(irq_nr-32), IC1_CFG2CLR);
 				break;
 			default: /* disable the interrupt */
 				printk("unexpected int type %d (irq %d)\n", type, irq_nr);
-				outl(1<<(irq_nr-32), IC1_CFG0CLR);
-				outl(1<<(irq_nr-32), IC1_CFG1CLR);
-				outl(1<<(irq_nr-32), IC1_CFG2CLR);
+				au_writel(1<<(irq_nr-32), IC1_CFG0CLR);
+				au_writel(1<<(irq_nr-32), IC1_CFG1CLR);
+				au_writel(1<<(irq_nr-32), IC1_CFG2CLR);
 				return;
 		}
 		if (int_req) /* assign to interrupt request 1 */
-			outl(1<<(irq_nr-32), IC1_ASSIGNCLR);
+			au_writel(1<<(irq_nr-32), IC1_ASSIGNCLR);
 		else	     /* assign to interrupt request 0 */
-			outl(1<<(irq_nr-32), IC1_ASSIGNSET);
-		outl(1<<(irq_nr-32), IC1_SRCSET);
-		outl(1<<(irq_nr-32), IC1_MASKCLR);
-		outl(1<<(irq_nr-32), IC1_WAKECLR);
+			au_writel(1<<(irq_nr-32), IC1_ASSIGNSET);
+		au_writel(1<<(irq_nr-32), IC1_SRCSET);
+		au_writel(1<<(irq_nr-32), IC1_MASKCLR);
+		au_writel(1<<(irq_nr-32), IC1_WAKECLR);
 	}
 	else {
 		switch (type) {
 			case INTC_INT_RISE_EDGE: /* 0:0:1 */
-				outl(1<<irq_nr, IC0_CFG2CLR);
-				outl(1<<irq_nr, IC0_CFG1CLR);
-				outl(1<<irq_nr, IC0_CFG0SET);
+				au_writel(1<<irq_nr, IC0_CFG2CLR);
+				au_writel(1<<irq_nr, IC0_CFG1CLR);
+				au_writel(1<<irq_nr, IC0_CFG0SET);
 				break;
 			case INTC_INT_FALL_EDGE: /* 0:1:0 */
-				outl(1<<irq_nr, IC0_CFG2CLR);
-				outl(1<<irq_nr, IC0_CFG1SET);
-				outl(1<<irq_nr, IC0_CFG0CLR);
+				au_writel(1<<irq_nr, IC0_CFG2CLR);
+				au_writel(1<<irq_nr, IC0_CFG1SET);
+				au_writel(1<<irq_nr, IC0_CFG0CLR);
 				break;
 			case INTC_INT_HIGH_LEVEL: /* 1:0:1 */
-				outl(1<<irq_nr, IC0_CFG2SET);
-				outl(1<<irq_nr, IC0_CFG1CLR);
-				outl(1<<irq_nr, IC0_CFG0SET);
+				au_writel(1<<irq_nr, IC0_CFG2SET);
+				au_writel(1<<irq_nr, IC0_CFG1CLR);
+				au_writel(1<<irq_nr, IC0_CFG0SET);
 				break;
 			case INTC_INT_LOW_LEVEL: /* 1:1:0 */
-				outl(1<<irq_nr, IC0_CFG2SET);
-				outl(1<<irq_nr, IC0_CFG1SET);
-				outl(1<<irq_nr, IC0_CFG0CLR);
+				au_writel(1<<irq_nr, IC0_CFG2SET);
+				au_writel(1<<irq_nr, IC0_CFG1SET);
+				au_writel(1<<irq_nr, IC0_CFG0CLR);
 				break;
 			case INTC_INT_DISABLED: /* 0:0:0 */
-				outl(1<<irq_nr, IC0_CFG0CLR);
-				outl(1<<irq_nr, IC0_CFG1CLR);
-				outl(1<<irq_nr, IC0_CFG2CLR);
+				au_writel(1<<irq_nr, IC0_CFG0CLR);
+				au_writel(1<<irq_nr, IC0_CFG1CLR);
+				au_writel(1<<irq_nr, IC0_CFG2CLR);
 				break;
 			default: /* disable the interrupt */
 				printk("unexpected int type %d (irq %d)\n", type, irq_nr);
-				outl(1<<irq_nr, IC0_CFG0CLR);
-				outl(1<<irq_nr, IC0_CFG1CLR);
-				outl(1<<irq_nr, IC0_CFG2CLR);
+				au_writel(1<<irq_nr, IC0_CFG0CLR);
+				au_writel(1<<irq_nr, IC0_CFG1CLR);
+				au_writel(1<<irq_nr, IC0_CFG2CLR);
 				return;
 		}
 		if (int_req) /* assign to interrupt request 1 */
-			outl(1<<irq_nr, IC0_ASSIGNCLR);
+			au_writel(1<<irq_nr, IC0_ASSIGNCLR);
 		else	     /* assign to interrupt request 0 */
-			outl(1<<irq_nr, IC0_ASSIGNSET);
-		outl(1<<irq_nr, IC0_SRCSET);
-		outl(1<<irq_nr, IC0_MASKCLR);
-		outl(1<<irq_nr, IC0_WAKECLR);
+			au_writel(1<<irq_nr, IC0_ASSIGNSET);
+		au_writel(1<<irq_nr, IC0_SRCSET);
+		au_writel(1<<irq_nr, IC0_MASKCLR);
+		au_writel(1<<irq_nr, IC0_WAKECLR);
 	}
 	au_sync();
 }
@@ -191,7 +193,7 @@
 static unsigned int startup_irq(unsigned int irq_nr)
 {
 	local_enable_irq(irq_nr);
-	return 0; 
+	return 0;
 }
 
 
@@ -205,12 +207,12 @@
 inline void local_enable_irq(unsigned int irq_nr)
 {
 	if (irq_nr > AU1000_LAST_INTC0_INT) {
-		outl(1<<(irq_nr-32), IC1_MASKSET);
-		outl(1<<(irq_nr-32), IC1_WAKESET);
+		au_writel(1<<(irq_nr-32), IC1_MASKSET);
+		au_writel(1<<(irq_nr-32), IC1_WAKESET);
 	}
 	else {
-		outl(1<<irq_nr, IC0_MASKSET);
-		outl(1<<irq_nr, IC0_WAKESET);
+		au_writel(1<<irq_nr, IC0_MASKSET);
+		au_writel(1<<irq_nr, IC0_WAKESET);
 	}
 	au_sync();
 }
@@ -219,12 +221,12 @@
 inline void local_disable_irq(unsigned int irq_nr)
 {
 	if (irq_nr > AU1000_LAST_INTC0_INT) {
-		outl(1<<(irq_nr-32), IC1_MASKCLR);
-		outl(1<<(irq_nr-32), IC1_WAKECLR);
+		au_writel(1<<(irq_nr-32), IC1_MASKCLR);
+		au_writel(1<<(irq_nr-32), IC1_WAKECLR);
 	}
 	else {
-		outl(1<<irq_nr, IC0_MASKCLR);
-		outl(1<<irq_nr, IC0_WAKECLR);
+		au_writel(1<<irq_nr, IC0_MASKCLR);
+		au_writel(1<<irq_nr, IC0_WAKECLR);
 	}
 	au_sync();
 }
@@ -233,12 +235,12 @@
 static inline void mask_and_ack_rise_edge_irq(unsigned int irq_nr)
 {
 	if (irq_nr > AU1000_LAST_INTC0_INT) {
-		outl(1<<(irq_nr-32), IC1_RISINGCLR);
-		outl(1<<(irq_nr-32), IC1_MASKCLR);
+		au_writel(1<<(irq_nr-32), IC1_RISINGCLR);
+		au_writel(1<<(irq_nr-32), IC1_MASKCLR);
 	}
 	else {
-		outl(1<<irq_nr, IC0_RISINGCLR);
-		outl(1<<irq_nr, IC0_MASKCLR);
+		au_writel(1<<irq_nr, IC0_RISINGCLR);
+		au_writel(1<<irq_nr, IC0_MASKCLR);
 	}
 	au_sync();
 }
@@ -247,12 +249,12 @@
 static inline void mask_and_ack_fall_edge_irq(unsigned int irq_nr)
 {
 	if (irq_nr > AU1000_LAST_INTC0_INT) {
-		outl(1<<(irq_nr-32), IC1_FALLINGCLR);
-		outl(1<<(irq_nr-32), IC1_MASKCLR);
+		au_writel(1<<(irq_nr-32), IC1_FALLINGCLR);
+		au_writel(1<<(irq_nr-32), IC1_MASKCLR);
 	}
 	else {
-		outl(1<<irq_nr, IC0_FALLINGCLR);
-		outl(1<<irq_nr, IC0_MASKCLR);
+		au_writel(1<<irq_nr, IC0_FALLINGCLR);
+		au_writel(1<<irq_nr, IC0_MASKCLR);
 	}
 	au_sync();
 }
@@ -265,7 +267,7 @@
 	au_sync();
 #if defined(CONFIG_MIPS_PB1000)
 	if (irq_nr == AU1000_GPIO_15) {
-		writew(0x8000, PB1000_MDR); /* ack int */
+		au_writel(0x8000, PB1000_MDR); /* ack int */
 		au_sync();
 	}
 #endif
@@ -279,12 +281,12 @@
 		local_enable_irq(irq_nr);
 	}
 	else {
-		printk("warning: end_irq %d did not enable (%x)\n", 
+		printk("warning: end_irq %d did not enable (%x)\n",
 				irq_nr, irq_desc[irq_nr].status);
 	}
 #if defined(CONFIG_MIPS_PB1000)
 	if (irq_nr == AU1000_GPIO_15) {
-		writew(0x4000, PB1000_MDR); /* enable int */
+		au_writel(0x4000, PB1000_MDR); /* enable int */
 		au_sync();
 	}
 #endif
@@ -297,13 +299,13 @@
 	save_and_cli(flags);
 
 	if (controller) {
-		mask = readl(IC1_MASKSET);
+		mask = au_readl(IC1_MASKSET);
 		for (i=32; i<64; i++) {
 			local_disable_irq(i);
 		}
 	}
 	else {
-		mask = readl(IC0_MASKSET);
+		mask = au_readl(IC0_MASKSET);
 		for (i=0; i<32; i++) {
 			local_disable_irq(i);
 		}
@@ -327,9 +329,9 @@
 		}
 	}
 	if (controller)
-		new_mask = readl(IC1_MASKSET);
+		new_mask = au_readl(IC1_MASKSET);
 	else
-		new_mask = readl(IC0_MASKSET);
+		new_mask = au_readl(IC0_MASKSET);
 
 	restore_flags(flags);
 }
@@ -390,10 +392,6 @@
 
 	init_generic_irq();
 
-	/* override the generic vec0 handler */
-	memcpy((void *)KSEG0, &except_vec0_au1000, 0x80);
-	flush_icache_range(KSEG0, KSEG0 + 0x200);
-	
 	for (i = 0; i <= AU1000_MAX_INTR; i++) {
 		switch (i) {
 			case AU1000_UART0_INT:
@@ -406,6 +404,12 @@
 			case AU1000_SSI1_INT:
 #endif
 
+#ifdef CONFIG_MIPS_PB1100
+			case AU1000_UART1_INT:
+
+			case AU1000_SSI0_INT:
+			case AU1000_SSI1_INT:
+#endif
 		        case AU1000_DMA_INT_BASE:
 		        case AU1000_DMA_INT_BASE+1:
 		        case AU1000_DMA_INT_BASE+2:
@@ -419,9 +423,14 @@
 			case AU1000_IRDA_RX_INT:
 
 			case AU1000_MAC0_DMA_INT:
+#ifdef CONFIG_MIPS_PB1000
 			case AU1000_MAC1_DMA_INT:
-
+#endif
+#ifdef CONFIG_MIPS_PB1500
+			case AU1000_MAC1_DMA_INT:
+#endif
 			case AU1500_GPIO_204:
+
 				setup_local_irq(i, INTC_INT_HIGH_LEVEL, 0);
 				irq_desc[i].handler = &level_irq_type;
 				break;
@@ -441,16 +450,24 @@
 			case AU1500_GPIO_205:
 			case AU1500_GPIO_207:
 #endif
+
+#ifdef CONFIG_MIPS_PB1100
+			case AU1000_GPIO_9: // PCMCIA Card Fully_Interted#
+			case AU1000_GPIO_10: // PCMCIA_STSCHG#
+			case AU1000_GPIO_11: // PCMCIA_IRQ#
+			case AU1000_GPIO_13: // DC_IRQ#
+			case AU1000_GPIO_23: // 2-wire SCL
+#endif
 				setup_local_irq(i, INTC_INT_LOW_LEVEL, 0);
 				irq_desc[i].handler = &level_irq_type;
                                 break;
 			case AU1000_ACSYNC_INT:
 			case AU1000_AC97C_INT:
-		        case AU1000_USB_DEV_REQ_INT:
-		        case AU1000_USB_DEV_SUS_INT:
 			case AU1000_TOY_INT:
 			case AU1000_TOY_MATCH0_INT:
 			case AU1000_TOY_MATCH1_INT:
+		        case AU1000_USB_DEV_SUS_INT:
+		        case AU1000_USB_DEV_REQ_INT:
 			case AU1000_RTC_INT:
 			case AU1000_RTC_MATCH0_INT:
 			case AU1000_RTC_MATCH1_INT:
@@ -478,7 +495,7 @@
 	/* If local serial I/O used for debug port, enter kgdb at once */
 	puts("Waiting for kgdb to connect...");
 	set_debug_traps();
-	breakpoint(); 
+	breakpoint();
 #endif
 }
 
@@ -494,10 +511,21 @@
 	int irq = 0, i;
 	static unsigned long intc0_req0 = 0;
 
-	intc0_req0 |= inl(IC0_REQ0INT);
+	intc0_req0 |= au_readl(IC0_REQ0INT);
 
 	if (!intc0_req0) return;
 
+	/*
+	 * Because of the tight timing of SETUP token to reply
+	 * transactions, the USB devices-side packet complete
+	 * interrupt needs the highest priority.
+	 */
+	if ((intc0_req0 & (1<<AU1000_USB_DEV_REQ_INT))) {
+		intc0_req0 &= ~(1<<AU1000_USB_DEV_REQ_INT);
+		do_IRQ(AU1000_USB_DEV_REQ_INT, regs);
+		return;
+	}
+
 	for (i=0; i<32; i++) {
 		if ((intc0_req0 & (1<<i))) {
 			intc0_req0 &= ~(1<<i);
@@ -514,7 +542,7 @@
 	int irq = 0, i;
 	static unsigned long intc0_req1 = 0;
 
-	intc0_req1 = inl(IC0_REQ1INT);
+	intc0_req1 = au_readl(IC0_REQ1INT);
 
 	if (!intc0_req1) return;
 
@@ -527,7 +555,7 @@
 				counter0_irq(irq, NULL, regs);
 				local_enable_irq(irq);
 			}
-			else 
+			else
 #endif
 			{
 				do_IRQ(irq, regs);
@@ -550,20 +578,20 @@
 	volatile unsigned short levels, mdr;
 	unsigned char ide_status;
 
-	intc1_req0 |= inl(IC1_REQ0INT);
+	intc1_req0 |= au_readl(IC1_REQ0INT);
 
 	if (!intc1_req0) return;
 
-#ifdef CONFIG_MIPS_PB1000
-	writew(1, CPLD_AUX0); /* debug led 0 */
+#if defined(CONFIG_MIPS_PB1000) && defined(DEBUG_IRQ)
+	au_writel(1, CPLD_AUX0); /* debug led 0 */
 #endif
 	for (i=0; i<32; i++) {
 		if ((intc1_req0 & (1<<i))) {
 			intc1_req0 &= ~(1<<i);
-#ifdef CONFIG_MIPS_PB1000
-			writew(2, CPLD_AUX0); /* turn on debug led 1  */
+#if defined(CONFIG_MIPS_PB1000) && defined(DEBUG_IRQ)
+			au_writel(2, CPLD_AUX0); /* turn on debug led 1  */
 			do_IRQ(irq+32, regs);
-			writew(0, CPLD_AUX0); /* turn off debug led 1 */
+			au_writel(0, CPLD_AUX0); /* turn off debug led 1 */
 #else
 			do_IRQ(irq+32, regs);
 #endif
@@ -571,8 +599,8 @@
 		}
 		irq++;
 	}
-#ifdef CONFIG_MIPS_PB1000
-	writew(0, CPLD_AUX0);
+#if defined(CONFIG_MIPS_PB1000) && defined(DEBUG_IRQ)
+	au_writel(0, CPLD_AUX0);
 #endif
 }
 
@@ -582,7 +610,7 @@
 	int irq = 0, i;
 	static unsigned long intc1_req1 = 0;
 
-	intc1_req1 |= inl(IC1_REQ1INT);
+	intc1_req1 |= au_readl(IC1_REQ1INT);
 
 	if (!intc1_req1) return;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/common/power.c linux-2.4.20/arch/mips/au1000/common/power.c
--- linux-2.4.19/arch/mips/au1000/common/power.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/common/power.c	2002-10-29 11:18:31.000000000 +0000
@@ -29,7 +29,7 @@
  *  with this program; if not, write  to the Free Software Foundation, Inc.,
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
-
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
@@ -49,7 +49,7 @@
 #  define DPRINTK(fmt, args...)
 #endif
 
-inline void au1_wait(void);
+extern void au1k_wait(void);
 static void calibrate_delay(void);
 
 extern void set_au1000_speed(unsigned int new_freq);
@@ -81,16 +81,16 @@
 
 	flush_cache_all();
 	/* pin 6 is gpio */
-	writel(readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD);
+	au_writel(au_readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD);
 
 	/* gpio 6 can cause a wake up event */
-	wakeup = readl(SYS_WAKEMSK);
+	wakeup = au_readl(SYS_WAKEMSK);
 	wakeup &= ~(1 << 8);	/* turn off match20 wakeup */
 	wakeup |= 1 << 6;	/* turn on gpio 6 wakeup   */
-	writel(wakeup, SYS_WAKEMSK);
+	au_writel(wakeup, SYS_WAKEMSK);
 
-	writel(1, SYS_WAKESRC);	/* clear cause */
-	writel(1, SYS_SLPPWR);	/* prepare to sleep */
+	au_writel(1, SYS_WAKESRC);	/* clear cause */
+	au_writel(1, SYS_SLPPWR);	/* prepare to sleep */
 
 	__asm__("la $4, 1f\n\t"
 		"lui $5, 0xb190\n\t"
@@ -138,7 +138,7 @@
 		if (retval)
 			return retval;
 		suspend_mode = 1;
-		au1_wait();
+		au1k_wait();
 		retval = pm_send_all(PM_RESUME, (void *) 0);
 	}
 	return retval;
@@ -194,22 +194,22 @@
 		set_au1000_speed(new_cpu_freq);
 		set_au1000_uart_baud_base(new_baud_base);
 
-		old_refresh = readl(MEM_SDREFCFG) & 0x1ffffff;
+		old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff;
 		new_refresh =
 		    ((old_refresh * new_cpu_freq) /
-		     old_cpu_freq) | (readl(MEM_SDREFCFG) & ~0x1ffffff);
+		     old_cpu_freq) | (au_readl(MEM_SDREFCFG) & ~0x1ffffff);
 
-		writel(pll, SYS_CPUPLL);
+		au_writel(pll, SYS_CPUPLL);
 		au_sync_delay(1);
-		writel(new_refresh, MEM_SDREFCFG);
+		au_writel(new_refresh, MEM_SDREFCFG);
 		au_sync_delay(1);
 
 		for (i = 0; i < 4; i++) {
-			if (readl
+			if (au_readl
 			    (UART_BASE + UART_MOD_CNTRL +
 			     i * 0x00100000) == 3) {
 				old_clk =
-				    readl(UART_BASE + UART_CLK +
+				    au_readl(UART_BASE + UART_CLK +
 					  i * 0x00100000);
 				// baud_rate = baud_base/clk
 				baud_rate = old_baud_base / old_clk;
@@ -231,7 +231,7 @@
 					(baud_rate = 9600);
 				// new_clk = new_baud_base/baud_rate
 				new_clk = new_baud_base / baud_rate;
-				writel(new_clk,
+				au_writel(new_clk,
 				       UART_BASE + UART_CLK +
 				       i * 0x00100000);
 				au_sync_delay(10);
@@ -246,7 +246,7 @@
 	 */
 	intc0_mask = save_local_and_disable(0);
 	intc1_mask = save_local_and_disable(1);
-	local_enable_irq(AU1000_TOY_MATCH2);
+	local_enable_irq(AU1000_TOY_MATCH2_INT);
 	restore_flags(flags);
 	calibrate_delay();
 	restore_local_and_enable(0, intc0_mask);
@@ -278,13 +278,6 @@
 
 __initcall(pm_init);
 
-inline void au1_wait(void)
-{
-	__asm__(".set\tmips3\n\t"
-		"wait\n\t"
-		"nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" ".set\tmips0");
-}
-
 
 /*
  * This is right out of init/main.c
@@ -330,12 +323,4 @@
 	}
 }
 
-
-#else				/* CONFIG_PM */
-
-void au1_wait(void)
-{
-	__asm__("nop\n\t" "nop\n\t");
-}
-
 #endif				/* CONFIG_PM */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/common/prom.c linux-2.4.20/arch/mips/au1000/common/prom.c
--- linux-2.4.19/arch/mips/au1000/common/prom.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/common/prom.c	2002-10-29 11:18:49.000000000 +0000
@@ -8,7 +8,7 @@
  * Author: MontaVista Software, Inc.
  *         	ppopov@mvista.com or source@mvista.com
  *
- * This file was derived from Carsten Langgaard's 
+ * This file was derived from Carsten Langgaard's
  * arch/mips/mips-boards/xx files.
  *
  * Carsten Langgaard, carstenl@mips.com
@@ -125,7 +125,7 @@
 		ea[i] = num;
 	}
 }
- 
+
 int get_ethernet_addr(char *ethernet_addr)
 {
 	int i;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/common/reset.c linux-2.4.20/arch/mips/au1000/common/reset.c
--- linux-2.4.19/arch/mips/au1000/common/reset.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/common/reset.c	2002-10-29 11:18:32.000000000 +0000
@@ -27,7 +27,7 @@
  *  with this program; if not, write  to the Free Software Foundation, Inc.,
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
-
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <asm/io.h>
@@ -35,6 +35,7 @@
 #include <asm/processor.h>
 #include <asm/reboot.h>
 #include <asm/system.h>
+#include <asm/au1000.h>
 
 extern int au_sleep(void);
 
@@ -47,40 +48,60 @@
 	switch (prid & 0xFF000000)
 	{
 	case 0x00000000: /* Au1000 */
-		outl(0x02, 0xb0000010); /* ac97_enable */
-		outl(0x08, 0xb017fffc); /* usbh_enable - early errata */
+		au_writel(0x02, 0xb0000010); /* ac97_enable */
+		au_writel(0x08, 0xb017fffc); /* usbh_enable - early errata */
 		asm("sync");
-		outl(0x00, 0xb017fffc); /* usbh_enable */
-		outl(0x00, 0xb0200058); /* usbd_enable */
-		outl(0x00, 0xb0300040); /* ir_enable */
-		outl(0x00, 0xb0520000); /* macen0 */
-		outl(0x00, 0xb0520004); /* macen1 */
-		outl(0x00, 0xb1000008); /* i2s_enable  */
-		outl(0x00, 0xb1100100); /* uart0_enable */
-		outl(0x00, 0xb1200100); /* uart1_enable */
-		outl(0x00, 0xb1300100); /* uart2_enable */
-		outl(0x00, 0xb1400100); /* uart3_enable */
-		outl(0x02, 0xb1600100); /* ssi0_enable */
-		outl(0x02, 0xb1680100); /* ssi1_enable */
-		outl(0x00, 0xb1900020); /* sys_freqctrl0 */
-		outl(0x00, 0xb1900024); /* sys_freqctrl1 */
-		outl(0x00, 0xb1900028); /* sys_clksrc */
-		outl(0x00, 0xb1900100); /* sys_pininputen */
+		au_writel(0x00, 0xb017fffc); /* usbh_enable */
+		au_writel(0x00, 0xb0200058); /* usbd_enable */
+		au_writel(0x00, 0xb0300040); /* ir_enable */
+		au_writel(0x00, 0xb0520000); /* macen0 */
+		au_writel(0x00, 0xb0520004); /* macen1 */
+		au_writel(0x00, 0xb1000008); /* i2s_enable  */
+		au_writel(0x00, 0xb1100100); /* uart0_enable */
+		au_writel(0x00, 0xb1200100); /* uart1_enable */
+		au_writel(0x00, 0xb1300100); /* uart2_enable */
+		au_writel(0x00, 0xb1400100); /* uart3_enable */
+		au_writel(0x02, 0xb1600100); /* ssi0_enable */
+		au_writel(0x02, 0xb1680100); /* ssi1_enable */
+		au_writel(0x00, 0xb1900020); /* sys_freqctrl0 */
+		au_writel(0x00, 0xb1900024); /* sys_freqctrl1 */
+		au_writel(0x00, 0xb1900028); /* sys_clksrc */
+		au_writel(0x00, 0xb1900100); /* sys_pininputen */
 		break;
 	case 0x01000000: /* Au1500 */
-		outl(0x02, 0xb0000010); /* ac97_enable */
-		outl(0x08, 0xb017fffc); /* usbh_enable - early errata */
+		au_writel(0x02, 0xb0000010); /* ac97_enable */
+		au_writel(0x08, 0xb017fffc); /* usbh_enable - early errata */
+		asm("sync");
+		au_writel(0x00, 0xb017fffc); /* usbh_enable */
+		au_writel(0x00, 0xb0200058); /* usbd_enable */
+		au_writel(0x00, 0xb1520000); /* macen0 */
+		au_writel(0x00, 0xb1520004); /* macen1 */
+		au_writel(0x00, 0xb1100100); /* uart0_enable */
+		au_writel(0x00, 0xb1400100); /* uart3_enable */
+		au_writel(0x00, 0xb1900020); /* sys_freqctrl0 */
+		au_writel(0x00, 0xb1900024); /* sys_freqctrl1 */
+		au_writel(0x00, 0xb1900028); /* sys_clksrc */
+		au_writel(0x00, 0xb1900100); /* sys_pininputen */
+		break;
+	case 0x02000000: /* Au1100 */
+		au_writel(0x02, 0xb0000010); /* ac97_enable */
+		au_writel(0x08, 0xb017fffc); /* usbh_enable - early errata */
 		asm("sync");
-		outl(0x00, 0xb017fffc); /* usbh_enable */
-		outl(0x00, 0xb0200058); /* usbd_enable */
-		outl(0x00, 0xb1520000); /* macen0 */
-		outl(0x00, 0xb1520004); /* macen1 */
-		outl(0x00, 0xb1100100); /* uart0_enable */
-		outl(0x00, 0xb1400100); /* uart3_enable */
-		outl(0x00, 0xb1900020); /* sys_freqctrl0 */
-		outl(0x00, 0xb1900024); /* sys_freqctrl1 */
-		outl(0x00, 0xb1900028); /* sys_clksrc */
-		outl(0x00, 0xb1900100); /* sys_pininputen */
+		au_writel(0x00, 0xb017fffc); /* usbh_enable */
+		au_writel(0x00, 0xb0200058); /* usbd_enable */
+		au_writel(0x00, 0xb0300040); /* ir_enable */
+		au_writel(0x00, 0xb0520000); /* macen0 */
+		au_writel(0x00, 0xb1000008); /* i2s_enable  */
+		au_writel(0x00, 0xb1100100); /* uart0_enable */
+		au_writel(0x00, 0xb1200100); /* uart1_enable */
+		au_writel(0x00, 0xb1400100); /* uart3_enable */
+		au_writel(0x02, 0xb1600100); /* ssi0_enable */
+		au_writel(0x02, 0xb1680100); /* ssi1_enable */
+		au_writel(0x00, 0xb1900020); /* sys_freqctrl0 */
+		au_writel(0x00, 0xb1900024); /* sys_freqctrl1 */
+		au_writel(0x00, 0xb1900028); /* sys_clksrc */
+		au_writel(0x00, 0xb1900100); /* sys_pininputen */
+		break;
 
 	default:
 		break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/common/rtc.c linux-2.4.20/arch/mips/au1000/common/rtc.c
--- linux-2.4.19/arch/mips/au1000/common/rtc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/common/rtc.c	2002-10-29 11:18:47.000000000 +0000
@@ -9,19 +9,20 @@
  */
 #include <linux/mc146818rtc.h>
 #include <asm/io.h>
+#include <asm/au1000.h>
 
 #define PB1500_RTC_ADDR 0xAC000000
 
-static unsigned char std_rtc_read_data(unsigned long addr)
+unsigned char std_rtc_read_data(unsigned long offset)
 {
-	addr <<= 2;
-	return readb(addr + PB1500_RTC_ADDR);
+	offset <<= 2;
+	return (u8)(au_readl(offset + PB1500_RTC_ADDR) & 0xff);
 }
 
-static void std_rtc_write_data(unsigned char data, unsigned long addr)
+static void std_rtc_write_data(unsigned char data, unsigned long offset)
 {
-	addr <<= 2;
-	writeb(data, addr + PB1500_RTC_ADDR);
+	offset <<= 2;
+	au_writel(data, offset + PB1500_RTC_ADDR);
 }
 
 static int std_rtc_bcd_mode(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/common/serial.c linux-2.4.20/arch/mips/au1000/common/serial.c
--- linux-2.4.19/arch/mips/au1000/common/serial.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/common/serial.c	2002-10-29 11:18:36.000000000 +0000
@@ -10,7 +10,7 @@
  *  Derived almost entirely from drivers/char/serial.c:
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
- *  Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 
+ *  Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997,
  * 		1998, 1999  Theodore Ts'o
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -63,7 +63,7 @@
 
 #define RS_STROBE_TIME (10*HZ)
 #define RS_ISR_PASS_LIMIT 256
-  
+
 /*
  * End of serial driver configuration section.
  */
@@ -166,10 +166,10 @@
  * UART
  */
 static struct serial_uart_config uart_config[] = {
-	{ "unknown", 1, 0 }, 
-	{ "8250", 1, 0 }, 
-	{ "16450", 1, 0 }, 
-	{ "16550", 1, 0 }, 
+	{ "unknown", 1, 0 },
+	{ "8250", 1, 0 },
+	{ "16450", 1, 0 },
+	{ "16550", 1, 0 },
 	{ 0, 0}
 };
 
@@ -238,15 +238,14 @@
 	return 0;
 }
 
-
 static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset)
 {
-	return (inl(info->port+offset) & 0xffff);
+	return (au_readl(info->port+offset) & 0xffff);
 }
 
 static _INLINE_ void serial_out(struct async_struct *info, int offset, int value)
 {
-	outl(value & 0xffff, info->port+offset);
+	au_writel(value & 0xffff, info->port+offset);
 }
 
 
@@ -275,7 +274,7 @@
 
 	if (serial_paranoia_check(info, tty->device, "rs_stop"))
 		return;
-	
+
 	save_flags(flags); cli();
 	if (info->IER & UART_IER_THRI) {
 		info->IER &= ~UART_IER_THRI;
@@ -288,10 +287,10 @@
 {
 	struct async_struct *info = (struct async_struct *)tty->driver_data;
 	unsigned long flags;
-	
+
 	if (serial_paranoia_check(info, tty->device, "rs_start"))
 		return;
-	
+
 	save_flags(flags); cli();
 	if (info->xmit.head != info->xmit.tail
 	    && info->xmit.buf
@@ -314,7 +313,7 @@
  * rs_interrupt() should try to keep the interrupt handler as fast as
  * possible.  After you are done making modifications, it is not a bad
  * idea to do:
- * 
+ *
  * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
  *
  * and look at the resulting assemble code in serial.s.
@@ -350,7 +349,7 @@
 			goto ignore_char;
 		*tty->flip.char_buf_ptr = ch;
 		icount->rx++;
-		
+
 #ifdef SERIAL_DEBUG_INTR
 		printk("DR%02x:%02x...", ch, *status);
 #endif
@@ -468,7 +467,7 @@
 		serial_out(info, UART_IER, info->IER);
 		return;
 	}
-	
+
 	count = info->xmit_fifo_size;
 	do {
 		serial_out(info, UART_TX, info->xmit.buf[info->xmit.tail]);
@@ -477,7 +476,7 @@
 		if (info->xmit.head == info->xmit.tail)
 			break;
 	} while (--count > 0);
-	
+
 	if (CIRC_CNT(info->xmit.head,
 		     info->xmit.tail,
 		     SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
@@ -499,7 +498,7 @@
 {
 	int	status;
 	struct	async_icount *icount;
-	
+
 	status = serial_in(info, UART_MSR);
 
 	if (status & UART_MSR_ANY_DELTA) {
@@ -526,7 +525,7 @@
 #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
 		printk("ttys%d CD now %s...", info->line,
 		       (status & UART_MSR_DCD) ? "on" : "off");
-#endif		
+#endif
 		if (status & UART_MSR_DCD)
 			wake_up_interruptible(&info->open_wait);
 		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
@@ -573,7 +572,7 @@
 	int status;
 	int pass_counter = 0;
 	struct async_struct * info;
-	
+
 #ifdef SERIAL_DEBUG_INTR
 	printk("rs_interrupt_single(%d)...", irq);
 #endif
@@ -630,7 +629,7 @@
 {
 	struct async_struct	*info = (struct async_struct *) private_;
 	struct tty_struct	*tty;
-	
+
 	tty = info->tty;
 	if (!tty)
 		return;
@@ -750,8 +749,8 @@
 		info->xmit.buf = (unsigned char *) page;
 
 
-	if (inl(UART_MOD_CNTRL + state->port) != 0x3) {
-		outl(3, UART_MOD_CNTRL + state->port);
+	if (au_readl(UART_MOD_CNTRL + state->port) != 0x3) {
+		au_writel(3, UART_MOD_CNTRL + state->port);
 		au_sync_delay(10);
 	}
 #ifdef SERIAL_DEBUG_OPEN
@@ -794,7 +793,7 @@
 			retval = -ENODEV;
 		goto errout;
 	}
-	
+
 	/*
 	 * Allocate the IRQ if necessary
 	 */
@@ -806,7 +805,7 @@
 		if (IRQ_ports[state->irq]) {
 			retval = -EBUSY;
 			goto errout;
-		} else 
+		} else
 			handler = rs_interrupt_single;
 
 		retval = request_irq(state->irq, handler, SA_SHIRQ,
@@ -833,7 +832,7 @@
 	figure_IRQ_timeout(state->irq);
 
 	/*
-	 * Now, initialize the UART 
+	 * Now, initialize the UART
 	 */
 	serial_outp(info, UART_LCR, UART_LCR_WLEN8);
 
@@ -846,13 +845,13 @@
 	}
 	info->MCR |= ALPHA_KLUDGE_MCR; 		/* Don't ask */
 	serial_outp(info, UART_MCR, info->MCR);
-	
+
 	/*
 	 * Finally, enable interrupts
 	 */
 	info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
 	serial_outp(info, UART_IER, info->IER);	/* enable interrupts */
-	
+
 
 	/*
 	 * And clear the interrupt registers again for luck.
@@ -884,7 +883,7 @@
 		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
 			info->tty->alt_speed = 460800;
 	}
-	
+
 	/*
 	 * and set the speed of the serial port
 	 */
@@ -893,7 +892,7 @@
 	info->flags |= ASYNC_INITIALIZED;
 	restore_flags(flags);
 	return 0;
-	
+
 errout:
 	restore_flags(flags);
 	return retval;
@@ -918,7 +917,7 @@
 	printk("Shutting down serial port %d (irq %d)....", info->line,
 	       state->irq);
 #endif
-	
+
 	save_flags(flags); cli(); /* Disable interrupts */
 
 	/*
@@ -926,7 +925,7 @@
 	 * here so the queue might never be waken up
 	 */
 	wake_up_interruptible(&info->delta_msr_wait);
-	
+
 	/*
 	 * First unlink the serial port from the IRQ chain...
 	 */
@@ -937,7 +936,7 @@
 	else
 		IRQ_ports[state->irq] = info->next_port;
 	figure_IRQ_timeout(state->irq);
-	
+
 	/*
 	 * Free the IRQ, if necessary
 	 */
@@ -949,7 +948,7 @@
 			retval = request_irq(state->irq, rs_interrupt_single,
 					     SA_SHIRQ, "serial",
 					     &IRQ_ports[state->irq]);
-			
+
 			if (retval)
 				printk("serial shutdown: request_irq: error %d"
 				       "  Couldn't reacquire IRQ.\n", retval);
@@ -967,28 +966,28 @@
 	serial_outp(info, UART_IER, 0x00);	/* disable all intrs */
 		info->MCR &= ~UART_MCR_OUT2;
 	info->MCR |= ALPHA_KLUDGE_MCR; 		/* Don't ask */
-	
+
 	/* disable break condition */
 	serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
-	
+
 	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
 		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
 	serial_outp(info, UART_MCR, info->MCR);
 
-	/* disable FIFO's */	
+	/* disable FIFO's */
 	serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
 				     UART_FCR_CLEAR_RCVR |
 				     UART_FCR_CLEAR_XMIT));
 	serial_outp(info, UART_FCR, 0);
 
 	(void)serial_in(info, UART_RX);    /* read data port to reset things */
-	
+
 	if (info->tty)
 		set_bit(TTY_IO_ERROR, &info->tty->flags);
 
 	info->flags &= ~ASYNC_INITIALIZED;
 #ifndef CONFIG_REMOTE_DEBUG
-	outl(0, UART_MOD_CNTRL + state->port);
+	au_writel(0, UART_MOD_CNTRL + state->port);
 	au_sync_delay(10);
 #endif
 	restore_flags(flags);
@@ -1076,7 +1075,7 @@
 	/* As a last resort, if the quotient is zero, default to 9600 bps */
 	if (!quot)
 		quot = baud_base / 9600;
-	
+
 	info->quot = quot;
 	info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
 	info->timeout += HZ/50;		/* Add .02 seconds of slop */
@@ -1088,7 +1087,7 @@
 		else
 			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIGGER_8;
 	}
-	
+
 	/* CTS flow control flag and modem status interrupts */
 	info->IER &= ~UART_IER_MSI;
 	if (info->flags & ASYNC_HARDPPS_CD)
@@ -1116,7 +1115,7 @@
 		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
 	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
 		info->read_status_mask |= UART_LSR_BI;
-	
+
 	/*
 	 * Characters to ignore
 	 */
@@ -1126,7 +1125,7 @@
 	if (I_IGNBRK(info->tty)) {
 		info->ignore_status_mask |= UART_LSR_BI;
 		/*
-		 * If we're ignore parity and break indicators, ignore 
+		 * If we're ignore parity and break indicators, ignore
 		 * overruns too.  (For real raw support).
 		 */
 		if (I_IGNPAR(info->tty))
@@ -1173,7 +1172,7 @@
 {
 	struct async_struct *info = (struct async_struct *)tty->driver_data;
 	unsigned long flags;
-				
+
 	if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
 		return;
 
@@ -1195,7 +1194,7 @@
 	int	c, ret = 0;
 	struct async_struct *info = (struct async_struct *)tty->driver_data;
 	unsigned long flags;
-				
+
 	if (serial_paranoia_check(info, tty->device, "rs_write"))
 		return 0;
 
@@ -1278,7 +1277,7 @@
 static int rs_chars_in_buffer(struct tty_struct *tty)
 {
 	struct async_struct *info = (struct async_struct *)tty->driver_data;
-				
+
 	if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
 		return 0;
 	return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
@@ -1288,7 +1287,7 @@
 {
 	struct async_struct *info = (struct async_struct *)tty->driver_data;
 	unsigned long flags;
-	
+
 	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
 		return;
 	save_flags(flags); cli();
@@ -1325,7 +1324,7 @@
 /*
  * ------------------------------------------------------------
  * rs_throttle()
- * 
+ *
  * This routine is called by the upper-layer tty layer to signal that
  * incoming characters should be throttled.
  * ------------------------------------------------------------
@@ -1336,14 +1335,14 @@
 	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
-	
+
 	printk("throttle %s: %d....\n", tty_name(tty, buf),
 	       tty->ldisc.chars_in_buffer(tty));
 #endif
 
 	if (serial_paranoia_check(info, tty->device, "rs_throttle"))
 		return;
-	
+
 	if (I_IXOFF(tty))
 		rs_send_xchar(tty, STOP_CHAR(tty));
 
@@ -1361,14 +1360,14 @@
 	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
-	
+
 	printk("unthrottle %s: %d....\n", tty_name(tty, buf),
 	       tty->ldisc.chars_in_buffer(tty));
 #endif
 
 	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
 		return;
-	
+
 	if (I_IXOFF(tty)) {
 		if (info->x_char)
 			info->x_char = 0;
@@ -1393,7 +1392,7 @@
 {
 	struct serial_struct tmp;
 	struct serial_state *state = info->state;
-   
+
 	if (!retinfo)
 		return -EFAULT;
 	memset(&tmp, 0, sizeof(tmp));
@@ -1439,7 +1438,7 @@
 	change_irq = new_serial.irq != state->irq;
 	change_port = (new_port != ((int) state->port)) ||
 		(new_serial.hub6 != state->hub6);
-  
+
 	if (!capable(CAP_SYS_ADMIN)) {
 		if (change_irq || change_port ||
 		    (new_serial.baud_base != state->baud_base) ||
@@ -1459,7 +1458,7 @@
 
 	new_serial.irq = irq_cannonicalize(new_serial.irq);
 
-	if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || 
+	if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) ||
 	    (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) ||
 	    (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) ||
 	    (new_serial.type == PORT_STARTECH)) {
@@ -1522,7 +1521,7 @@
 			request_region(state->port,8,"serial(set)");
 	}
 
-	
+
 check_and_exit:
 	if (!state->port || !state->type)
 		return 0;
@@ -1555,7 +1554,7 @@
  * 	    release the bus after transmitting. This must be done when
  * 	    the transmit shift register is empty, not be done when the
  * 	    transmit holding register is empty.  This functionality
- * 	    allows an RS485 driver to be written in user space. 
+ * 	    allows an RS485 driver to be written in user space.
  */
 static int get_lsr_info(struct async_struct * info, unsigned int *value)
 {
@@ -1574,7 +1573,7 @@
 	 * avoid a race condition (depending on when the transmit
 	 * interrupt happens).
 	 */
-	if (info->x_char || 
+	if (info->x_char ||
 	    ((CIRC_CNT(info->xmit.head, info->xmit.tail,
 		       SERIAL_XMIT_SIZE) > 0) &&
 	     !info->tty->stopped && !info->tty->hw_stopped))
@@ -1622,7 +1621,7 @@
 		return -EFAULT;
 
 	switch (cmd) {
-	case TIOCMBIS: 
+	case TIOCMBIS:
 		if (arg & TIOCM_RTS)
 			info->MCR |= UART_MCR_RTS;
 		if (arg & TIOCM_DTR)
@@ -1679,13 +1678,13 @@
 static int do_autoconfig(struct async_struct * info)
 {
 	int retval;
-	
+
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
-	
+
 	if (info->state->count > 1)
 		return -EBUSY;
-	
+
 	shutdown(info);
 
 	autoconfig(info->state);
@@ -1702,7 +1701,7 @@
 {
 	struct async_struct * info = (struct async_struct *)tty->driver_data;
 	unsigned long flags;
-	
+
 	if (serial_paranoia_check(info, tty->device, "rs_break"))
 		return;
 
@@ -1725,7 +1724,7 @@
 	struct async_icount cprev, cnow;	/* kernel counter temps */
 	struct serial_icounter_struct icount;
 	unsigned long flags;
-	
+
 	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
 		return -ENODEV;
 
@@ -1735,7 +1734,7 @@
 		if (tty->flags & (1 << TTY_IO_ERROR))
 		    return -EIO;
 	}
-	
+
 	switch (cmd) {
 		case TIOCMGET:
 			return get_modem_info(info, (unsigned int *) arg);
@@ -1760,8 +1759,8 @@
 					 info, sizeof(struct async_struct)))
 				return -EFAULT;
 			return 0;
-				
-			
+
+
 		/*
 		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
 		 * - mask passed in arg for lines of interest
@@ -1784,7 +1783,7 @@
 				save_flags(flags); cli();
 				cnow = info->state->icount; /* atomic copy */
 				restore_flags(flags);
-				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
+				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
 				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
 					return -EIO; /* no change => error */
 				if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
@@ -1797,7 +1796,7 @@
 			}
 			/* NOTREACHED */
 
-		/* 
+		/*
 		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
 		 * Return: write counters to the user passed counter struct
 		 * NB: both 1->0 and 0->1 transitions are counted except for
@@ -1818,7 +1817,7 @@
 			icount.parity = cnow.parity;
 			icount.brk = cnow.brk;
 			icount.buf_overrun = cnow.buf_overrun;
-			
+
 			if (copy_to_user((void *)arg, &icount, sizeof(icount)))
 				return -EFAULT;
 			return 0;
@@ -1839,9 +1838,9 @@
 	struct async_struct *info = (struct async_struct *)tty->driver_data;
 	unsigned long flags;
 	unsigned int cflag = tty->termios->c_cflag;
-	
+
 	if (   (cflag == old_termios->c_cflag)
-	    && (   RELEVANT_IFLAG(tty->termios->c_iflag) 
+	    && (   RELEVANT_IFLAG(tty->termios->c_iflag)
 		== RELEVANT_IFLAG(old_termios->c_iflag)))
 	  return;
 
@@ -1855,12 +1854,12 @@
 		serial_out(info, UART_MCR, info->MCR);
 		restore_flags(flags);
 	}
-	
+
 	/* Handle transition away from B0 status */
 	if (!(old_termios->c_cflag & CBAUD) &&
 	    (cflag & CBAUD)) {
 		info->MCR |= UART_MCR_DTR;
-		if (!(tty->termios->c_cflag & CRTSCTS) || 
+		if (!(tty->termios->c_cflag & CRTSCTS) ||
 		    !test_bit(TTY_THROTTLED, &tty->flags)) {
 			info->MCR |= UART_MCR_RTS;
 		}
@@ -1868,7 +1867,7 @@
 		serial_out(info, UART_MCR, info->MCR);
 		restore_flags(flags);
 	}
-	
+
 	/* Handle turning off CRTSCTS */
 	if ((old_termios->c_cflag & CRTSCTS) &&
 	    !(tty->termios->c_cflag & CRTSCTS)) {
@@ -1880,7 +1879,7 @@
 /*
  * ------------------------------------------------------------
  * rs_close()
- * 
+ *
  * This routine is called when the serial port gets closed.  First, we
  * wait for the last remaining data to be sent.  Then, we unlink its
  * async structure from the interrupt chain if necessary, and we free
@@ -1897,16 +1896,16 @@
 		return;
 
 	state = info->state;
-	
+
 	save_flags(flags); cli();
-	
+
 	if (tty_hung_up_p(filp)) {
 		DBG_CNT("before DEC-hung");
 		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 		return;
 	}
-	
+
 #ifdef SERIAL_DEBUG_OPEN
 	printk("rs_close ttys%d, count = %d\n", info->line, state->count);
 #endif
@@ -1944,7 +1943,7 @@
 	if (info->flags & ASYNC_CALLOUT_ACTIVE)
 		info->state->callout_termios = *tty->termios;
 	/*
-	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * Now we wait for the transmit buffer to clear; and we notify
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	tty->closing = 1;
@@ -1996,7 +1995,7 @@
 	struct async_struct * info = (struct async_struct *)tty->driver_data;
 	unsigned long orig_jiffies, char_time;
 	int lsr;
-	
+
 	if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
 		return;
 
@@ -2011,7 +2010,7 @@
 	 * Set the check interval to be 1/5 of the estimated time to
 	 * send a single character, and make it at least 1.  The check
 	 * interval should also be less than the timeout.
-	 * 
+	 *
 	 * Note: we have to use pretty tight timings here to satisfy
 	 * the NIST-PCTS.
 	 */
@@ -2060,12 +2059,12 @@
 {
 	struct async_struct * info = (struct async_struct *)tty->driver_data;
 	struct serial_state *state = info->state;
-	
+
 	if (serial_paranoia_check(info, tty->device, "rs_hangup"))
 		return;
 
 	state = info->state;
-	
+
 	rs_flush_buffer(tty);
 	if (info->flags & ASYNC_CLOSING)
 		return;
@@ -2125,7 +2124,7 @@
 		info->flags |= ASYNC_CALLOUT_ACTIVE;
 		return 0;
 	}
-	
+
 	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
@@ -2145,7 +2144,7 @@
 		if (tty->termios->c_cflag & CLOCAL)
 			do_clocal = 1;
 	}
-	
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -2181,7 +2180,7 @@
 			if (info->flags & ASYNC_HUP_NOTIFY)
 				retval = -EAGAIN;
 			else
-				retval = -ERESTARTSYS;	
+				retval = -ERESTARTSYS;
 #else
 			retval = -EAGAIN;
 #endif
@@ -2283,7 +2282,7 @@
 	tty->driver_data = info;
 	info->tty = tty;
 	if (serial_paranoia_check(info, tty->device, "rs_open")) {
-		MOD_DEC_USE_COUNT;		
+		MOD_DEC_USE_COUNT;
 		return -ENODEV;
 	}
 
@@ -2344,7 +2343,7 @@
 	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
 		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
 			*tty->termios = info->state->normal_termios;
-		else 
+		else
 			*tty->termios = info->state->callout_termios;
 		change_speed(info, 0);
 	}
@@ -2376,7 +2375,7 @@
 	unsigned long flags;
 
 	ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d",
-		      state->line, uart_config[state->type].name, 
+		      state->line, uart_config[state->type].name,
 		      state->port, state->irq);
 
 	if (!state->port || (state->type == PORT_UNKNOWN)) {
@@ -2399,7 +2398,7 @@
 	save_flags(flags); cli();
 	status = serial_in(info, UART_MSR);
 	control = info != &scr_info ? info->MCR : serial_in(info, UART_MCR);
-	restore_flags(flags); 
+	restore_flags(flags);
 
 	stat_buf[0] = 0;
 	stat_buf[1] = 0;
@@ -2426,12 +2425,12 @@
 
 	if (state->icount.frame)
 		ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
-	
+
 	if (state->icount.parity)
 		ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
-	
+
 	if (state->icount.brk)
-		ret += sprintf(buf+ret, " brk:%d", state->icount.brk);	
+		ret += sprintf(buf+ret, " brk:%d", state->icount.brk);
 
 	if (state->icount.overrun)
 		ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
@@ -2511,15 +2510,15 @@
 	printk("Testing ttyS%d (0x%04lx, 0x%04x)...\n", state->line,
 	       state->port, (unsigned) state->iomem_base);
 #endif
-	
+
 	if (!CONFIGURED_SERIAL_PORT(state))
 		return;
 
-	if (inl(UART_MOD_CNTRL + state->port) != 0x3) {
-		outl(3, UART_MOD_CNTRL + state->port);
+	if (au_readl(UART_MOD_CNTRL + state->port) != 0x3) {
+		au_writel(3, UART_MOD_CNTRL + state->port);
 		au_sync_delay(10);
 	}
-		
+
 	state->type = PORT_16550;
 	info = &scr_info;	/* This is just for serial_{in,out} */
 
@@ -2548,11 +2547,6 @@
 	serial_outp(info, UART_FCR, 0);
 	(void)serial_in(info, UART_RX);
 	serial_outp(info, UART_IER, 0);
-
-#ifndef CONFIG_REMOTE_DEBUG
-	outl(0, UART_MOD_CNTRL + state->port);
-	au_sync_delay(10);
-#endif
 	restore_flags(flags);
 }
 
@@ -2595,7 +2589,7 @@
 	show_serial_version();
 
 	/* Initialize the tty_driver structure */
-	
+
 	memset(&serial_driver, 0, sizeof(struct tty_driver));
 	serial_driver.magic = TTY_DRIVER_MAGIC;
 	serial_driver.driver_name = "serial";
@@ -2637,7 +2631,7 @@
 	serial_driver.send_xchar = rs_send_xchar;
 	serial_driver.wait_until_sent = rs_wait_until_sent;
 	serial_driver.read_proc = rs_read_proc;
-	
+
 	/*
 	 * The callout device is just like normal device except for
 	 * major number and the subtype code.
@@ -2657,7 +2651,7 @@
 		panic("Couldn't register serial driver");
 	if (tty_register_driver(&callout_driver))
 		panic("Couldn't register callout driver");
-	
+
 	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
 		state->baud_base = get_au1000_uart_baud_base();
 		state->magic = SSTATE_MAGIC;
@@ -2668,7 +2662,7 @@
 		state->closing_wait = 30*HZ;
 		state->callout_termios = callout_driver.init_termios;
 		state->normal_termios = serial_driver.init_termios;
-		state->icount.cts = state->icount.dsr = 
+		state->icount.cts = state->icount.dsr =
 			state->icount.rng = state->icount.dcd = 0;
 		state->icount.rx = state->icount.tx = 0;
 		state->icount.frame = state->icount.parity = 0;
@@ -2705,7 +2699,7 @@
  * register_serial and unregister_serial allows for 16x50 serial ports to be
  * configured at run-time, to support PCMCIA modems.
  */
- 
+
 /**
  *	register_serial - configure a 16x50 serial port at runtime
  *	@req: request structure
@@ -2719,7 +2713,7 @@
  *
  *	On success the port is ready to use and the line number is returned.
  */
- 
+
 int register_serial(struct serial_struct *req)
 {
 	int i;
@@ -2784,7 +2778,7 @@
 	      state->iomem_base ? (unsigned long)state->iomem_base :
 	      state->port, state->irq, uart_config[state->type].name);
 	tty_register_devfs(&serial_driver, 0,
-			   serial_driver.minor_start + state->line); 
+			   serial_driver.minor_start + state->line);
 	tty_register_devfs(&callout_driver, 0,
 			   callout_driver.minor_start + state->line);
 	return state->line + SERIAL_DEV_OFFSET;
@@ -2819,7 +2813,7 @@
 	restore_flags(flags);
 }
 
-static void __exit rs_fini(void) 
+static void __exit rs_fini(void)
 {
 	unsigned long flags;
 	int e1, e2;
@@ -2834,7 +2828,7 @@
 		printk("serial: failed to unregister serial driver (%d)\n",
 		       e1);
 	if ((e2 = tty_unregister_driver(&callout_driver)))
-		printk("serial: failed to unregister callout driver (%d)\n", 
+		printk("serial: failed to unregister callout driver (%d)\n",
 		       e2);
 	restore_flags(flags);
 
@@ -2882,7 +2876,7 @@
 
 		if (status & UART_LSR_BI)
 			lsr_break_flag = UART_LSR_BI;
-		
+
 		if (--tmout == 0)
 			break;
 	} while((status & BOTH_EMPTY) != BOTH_EMPTY);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/common/time.c linux-2.4.20/arch/mips/au1000/common/time.c
--- linux-2.4.19/arch/mips/au1000/common/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/common/time.c	2002-10-29 11:18:37.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  * Copyright (C) 2001 MontaVista Software, ppopov@mvista.com
  * Copied and modified Carsten Langgaard's time.c
  *
@@ -123,13 +123,13 @@
 	static int jiffie_drift = 0;
 
 	kstat.irqs[0][irq]++;
-	if (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) {
+	if (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) {
 		/* should never happen! */
 		printk(KERN_WARNING "counter 0 w status eror\n");
 		return;
 	}
 
-	pc0 = inl(SYS_TOYREAD);
+	pc0 = au_readl(SYS_TOYREAD);
 	if (pc0 < last_match20) {
 		/* counter overflowed */
 		time_elapsed = (0xffffffff - last_match20) + pc0;
@@ -146,13 +146,13 @@
 	}
 
 	last_pc0 = pc0;
-	outl(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
+	au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
 	au_sync();
 
 	/* our counter ticks at 10.009765625 ms/tick, we we're running
 	 * almost 10uS too slow per tick.
 	 */
-	 
+
 	if (jiffie_drift >= 999) {
 		jiffie_drift -= 999;
 		do_timer(regs); /* increment jiffies by one */
@@ -160,9 +160,9 @@
 }
 #endif
 
-/* 
+/*
  * Figure out the r4k offset, the amount to increment the compare
- * register for each time tick. 
+ * register for each time tick.
  * Use the Programmable Counter 1 to do this.
  */
 unsigned long cal_r4koff(void)
@@ -176,27 +176,27 @@
 
 	save_and_cli(flags);
 
-	counter = inl(SYS_COUNTER_CNTRL);
-	outl(counter | SYS_CNTRL_EN1, SYS_COUNTER_CNTRL);
+	counter = au_readl(SYS_COUNTER_CNTRL);
+	au_writel(counter | SYS_CNTRL_EN1, SYS_COUNTER_CNTRL);
 
-	while (inl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S);
-	outl(trim_divide-1, SYS_RTCTRIM); /* RTC now ticks at 32.768/16 kHz */
-	while (inl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S);
-
-	while (inl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);
-	outl (0, SYS_TOYWRITE);
-	while (inl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);
+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S);
+	au_writel(trim_divide-1, SYS_RTCTRIM); /* RTC now ticks at 32.768/16 kHz */
+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S);
+
+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);
+	au_writel (0, SYS_TOYWRITE);
+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);
 
-	start = inl(SYS_RTCREAD);
+	start = au_readl(SYS_RTCREAD);
 	start += 2;
 	/* wait for the beginning of a new tick */
-	while (inl(SYS_RTCREAD) < start);
+	while (au_readl(SYS_RTCREAD) < start);
 
 	/* Start r4k counter. */
 	write_32bit_cp0_register(CP0_COUNT, 0);
 	end = start + (32768 / trim_divide)/2; /* wait 0.5 seconds */
 
-	while (end > inl(SYS_RTCREAD));
+	while (end > au_readl(SYS_RTCREAD));
 
 	count = read_32bit_cp0_register(CP0_COUNT);
 	cpu_speed = count * 2;
@@ -215,11 +215,11 @@
 	r4k_offset = cal_r4koff();
 	printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
 
-	//est_freq = 2*r4k_offset*HZ;	
-	est_freq = r4k_offset*HZ;	
+	//est_freq = 2*r4k_offset*HZ;
+	est_freq = r4k_offset*HZ;
 	est_freq += 5000;    /* round */
 	est_freq -= est_freq%10000;
-	printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, 
+	printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
 	       (est_freq%1000000)*100/1000000);
 	set_au1000_speed(est_freq);
 	set_au1000_lcd_clock(); // program the LCD clock
@@ -241,20 +241,20 @@
 	 * counter 0 interrupt as a special irq and it doesn't show
 	 * up under /proc/interrupts.
 	 */
-	while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S);
-	writel(0, SYS_TOYWRITE);
-	while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S);
+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S);
+	au_writel(0, SYS_TOYWRITE);
+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S);
 
-	writel(readl(SYS_WAKEMSK) | (1<<8), SYS_WAKEMSK);
-	writel(~0, SYS_WAKESRC);
+	au_writel(au_readl(SYS_WAKEMSK) | (1<<8), SYS_WAKEMSK);
+	au_writel(~0, SYS_WAKESRC);
 	au_sync();
-	while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
 
 	/* setup match20 to interrupt once every 10ms */
-	last_pc0 = last_match20 = readl(SYS_TOYREAD);
-	writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
+	last_pc0 = last_match20 = au_readl(SYS_TOYREAD);
+	au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
 	au_sync();
-	while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
 	startup_match20_interrupt();
 #endif
 
@@ -282,7 +282,7 @@
 	unsigned long pc0;
 	unsigned long offset;
 
-	pc0 = readl(SYS_TOYREAD);
+	pc0 = au_readl(SYS_TOYREAD);
 	if (pc0 < last_pc0) {
 		offset = 0xffffffff - last_pc0 + pc0;
 		printk("offset over: %x\n", (unsigned)offset);
@@ -291,8 +291,8 @@
 		offset = (unsigned long)(((pc0 - last_pc0) * 305) / 10);
 	}
 	if ((pc0-last_pc0) > 2*MATCH20_INC) {
-		printk("huge offset %x, last_pc0 %x last_match20 %x pc0 %x\n", 
-				(unsigned)offset, (unsigned)last_pc0, 
+		printk("huge offset %x, last_pc0 %x last_match20 %x pc0 %x\n",
+				(unsigned)offset, (unsigned)last_pc0,
 				(unsigned)last_match20, (unsigned)pc0);
 	}
 	au_sync();
@@ -338,7 +338,7 @@
 		 "r" (quotient));
 
 	/*
- 	 * Due to possible jiffies inconsistencies, we need to check 
+ 	 * Due to possible jiffies inconsistencies, we need to check
 	 * the result so that we'll get a timer that is monotonic.
 	 */
 	if (res >= USECS_PER_JIFFY)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/common/usbdev.c linux-2.4.20/arch/mips/au1000/common/usbdev.c
--- linux-2.4.19/arch/mips/au1000/common/usbdev.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/common/usbdev.c	2002-10-29 11:18:32.000000000 +0000
@@ -1,8 +1,8 @@
 /*
  * BRIEF MODULE DESCRIPTION
- *	Au1000 USB Device-Side Serial TTY Driver
+ *	Au1000 USB Device-Side (device layer)
  *
- * Copyright 2001 MontaVista Software Inc.
+ * Copyright 2001-2002 MontaVista Software Inc.
  * Author: MontaVista Software, Inc.
  *		stevel@mvista.com or source@mvista.com
  *
@@ -37,9 +37,6 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/fcntl.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
@@ -53,54 +50,30 @@
 #include <asm/mipsregs.h>
 #include <asm/au1000.h>
 #include <asm/au1000_dma.h>
+#include <asm/au1000_usbdev.h>
 
-/* Module information */
-MODULE_AUTHOR("Steve Longerbeam, stevel@mvista.com, www.mvista.com");
-MODULE_DESCRIPTION("Au1000 USB Device-Side Serial TTY Driver");
-
-#undef USBDEV_PIO
-
-#define SERIAL_TTY_MAJOR 189
+#ifdef DEBUG
+#undef VDEBUG
+#ifdef VDEBUG
+#define vdbg(fmt, arg...) printk(KERN_DEBUG __FILE__ ": " fmt "\n" , ## arg)
+#else
+#define vdbg(fmt, arg...) do {} while (0)
+#endif
+#else
+#define vdbg(fmt, arg...) do {} while (0)
+#endif
 
 #define MAX(a,b)	(((a)>(b))?(a):(b))
 
 #define ALLOC_FLAGS (in_interrupt () ? GFP_ATOMIC : GFP_KERNEL)
 
-#define MAX_NUM_PORTS 2
-
-#define NUM_PORTS 1
-#define NUM_EP 2*NUM_PORTS
-
-#define EP0_MAX_PACKET_SIZE 64
-#define EP2_MAX_PACKET_SIZE 64
-#define EP3_MAX_PACKET_SIZE 64
-#define EP4_MAX_PACKET_SIZE 64
-#define EP5_MAX_PACKET_SIZE 64
-
-#ifdef USBDEV_PIO
 #define EP_FIFO_DEPTH 8
-#endif
 
 typedef enum {
-	ATTACHED = 0,
-	POWERED,
-	DEFAULT,
-	ADDRESS,
-	CONFIGURED
-} dev_state_t;
-
-/* local function prototypes */
-static int serial_open(struct tty_struct *tty, struct file *filp);
-static void serial_close(struct tty_struct *tty, struct file *filp);
-static int serial_write(struct tty_struct *tty, int from_user,
-			const unsigned char *buf, int count);
-static int serial_write_room(struct tty_struct *tty);
-static int serial_chars_in_buffer(struct tty_struct *tty);
-static void serial_throttle(struct tty_struct *tty);
-static void serial_unthrottle(struct tty_struct *tty);
-static int serial_ioctl(struct tty_struct *tty, struct file *file,
-			unsigned int cmd, unsigned long arg);
-static void serial_set_termios (struct tty_struct *tty, struct termios * old);
+	SETUP_STAGE = 0,
+	DATA_STAGE,
+	STATUS_STAGE
+} ep0_stage_t;
 
 typedef struct {
 	int read_fifo;
@@ -110,184 +83,68 @@
 	int write_fifo_status;
 } endpoint_reg_t;
 
-typedef struct pkt {
-	int size;
-	u8 *bufptr;
-	struct pkt *next;
-	u8 buf[0];
-} pkt_t;
-
 typedef struct {
-	pkt_t *head;
-	pkt_t *tail;
+	usbdev_pkt_t *head;
+	usbdev_pkt_t *tail;
 	int count;
 } pkt_list_t;
 
 typedef struct {
+	int active;
 	struct usb_endpoint_descriptor *desc;
 	endpoint_reg_t *reg;
-	// Only one of these are used, unless this is a control ep
+	/* Only one of these are used, unless this is the control ep */
 	pkt_list_t inlist;
 	pkt_list_t outlist;
-	unsigned int indma, outdma;	// DMA channel numbers for IN, OUT
-	int inirq, outirq;	// DMA buffer done irq numbers
+	unsigned int indma, outdma; /* DMA channel numbers for IN, OUT */
+	/* following are extracted from endpoint descriptor for easy access */
 	int max_pkt_size;
+	int type;
+	int direction;
+	/* WE assign endpoint addresses! */
+	int address;
 	spinlock_t lock;
 } endpoint_t;
 
-struct usb_serial_port {
-	struct usb_serial *serial;	/* ptr back to the owner of this port */
-	struct tty_struct *tty;	/* the coresponding tty for this port */
-	unsigned char number;
-	char active;		/* someone has this device open */
-	spinlock_t port_lock;
-
-	endpoint_t ep_bulkin;
-	endpoint_t ep_bulkout;
-
-	wait_queue_head_t write_wait;
-
-	/* task queue for line discipline waking up on send packet complete */
-	struct tq_struct send_complete_tq;
-	/* task queue for line discipline wakeup on receive packet complete */
-	struct tq_struct receive_complete_tq;
-
-	int open_count;		/* number of times this port has been opened */
-};
-
-struct usb_serial {
-	struct tty_driver *tty_driver;	/* the tty_driver for this device */
-	unsigned char minor;	/* the minor number for this device */
-
-	endpoint_t ep_ctrl;
 
-	struct usb_device_descriptor *dev_desc;
-	struct usb_interface_descriptor *if_desc;
-	struct usb_config_descriptor *conf_desc;
-	struct usb_string_descriptor *str_desc[6];
+static struct usb_dev {
+	endpoint_t ep[6];
+	ep0_stage_t ep0_stage;
+
+	struct usb_device_descriptor *   dev_desc;
+	struct usb_interface_descriptor* if_desc;
+	struct usb_config_descriptor *   conf_desc;
+	u8 *                             full_conf_desc;
+	struct usb_string_descriptor *   str_desc[6];
+
+	/* callback to function layer */
+	void (*func_cb)(usbdev_cb_type_t type, unsigned long arg,
+			void *cb_data);
+	void* cb_data;
 
-	struct usb_serial_port port[NUM_PORTS];
-
-	dev_state_t state;	// device state
+	usbdev_state_t state;	// device state
 	int suspended;		// suspended flag
 	int address;		// device address
 	int interface;
+	int num_ep;
 	u8 alternate_setting;
 	u8 configuration;	// configuration value
 	int remote_wakeup_en;
-};
-
-
-static struct usb_device_descriptor dev_desc = {
-	bLength:USB_DT_DEVICE_SIZE,
-	bDescriptorType:USB_DT_DEVICE,
-	bcdUSB:0x0110,		//usb rev 1.0
-	bDeviceClass:USB_CLASS_PER_INTERFACE,	//class    (none)
-	bDeviceSubClass:0x00,	//subclass (none)
-	bDeviceProtocol:0x00,	//protocol (none)
-	bMaxPacketSize0:EP0_MAX_PACKET_SIZE,	//max packet size for ep0
-	idVendor:0x6d04,	//vendor  id
-	idProduct:0x0bc0,	//product id
-	bcdDevice:0x0001,	//BCD rev 0.1
-	iManufacturer:0x01,	//manufactuer string index
-	iProduct:0x02,		//product string index
-	iSerialNumber:0x03,	//serial# string index
-	bNumConfigurations:0x01	//num configurations
-};
-
-static struct usb_endpoint_descriptor ep_desc[] = {
-	{
-	 // EP2, Bulk IN for Port 0
-	      bLength:USB_DT_ENDPOINT_SIZE,
-	      bDescriptorType:USB_DT_ENDPOINT,
-	      bEndpointAddress:USB_DIR_IN | 0x02,
-	      bmAttributes:USB_ENDPOINT_XFER_BULK,
-	      wMaxPacketSize:EP2_MAX_PACKET_SIZE,
-	      bInterval:0x00	// ignored for bulk
-	 },
-	{
-	 // EP4, Bulk OUT for Port 0
-	      bLength:USB_DT_ENDPOINT_SIZE,
-	      bDescriptorType:USB_DT_ENDPOINT,
-	      bEndpointAddress:USB_DIR_OUT | 0x04,
-	      bmAttributes:USB_ENDPOINT_XFER_BULK,
-	      wMaxPacketSize:EP4_MAX_PACKET_SIZE,
-	      bInterval:0x00	// ignored for bulk
-	 },
-	{
-	 // EP3, Bulk IN for Port 1
-	      bLength:USB_DT_ENDPOINT_SIZE,
-	      bDescriptorType:USB_DT_ENDPOINT,
-	      bEndpointAddress:USB_DIR_IN | 0x03,
-	      bmAttributes:USB_ENDPOINT_XFER_BULK,
-	      wMaxPacketSize:EP3_MAX_PACKET_SIZE,
-	      bInterval:0x00	// ignored for bulk
-	 },
-	{
-	 // EP5, Bulk OUT for Port 1
-	      bLength:USB_DT_ENDPOINT_SIZE,
-	      bDescriptorType:USB_DT_ENDPOINT,
-	      bEndpointAddress:USB_DIR_OUT | 0x05,
-	      bmAttributes:USB_ENDPOINT_XFER_BULK,
-	      wMaxPacketSize:EP5_MAX_PACKET_SIZE,
-	      bInterval:0x00	// ignored for bulk
-	 },
-};
-
-static struct usb_interface_descriptor if_desc = {
-	bLength:USB_DT_INTERFACE_SIZE,
-	bDescriptorType:USB_DT_INTERFACE,
-	bInterfaceNumber:0x00,
-	bAlternateSetting:0x00,
-	bNumEndpoints:NUM_EP,
-	bInterfaceClass:0xff,
-	bInterfaceSubClass:0xab,
-	bInterfaceProtocol:0x00,
-	iInterface:0x05
-};
-
-#define CONFIG_DESC_LEN \
- USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE + NUM_EP*USB_DT_ENDPOINT_SIZE
-
-static struct usb_config_descriptor config_desc = {
-	bLength:USB_DT_CONFIG_SIZE,
-	bDescriptorType:USB_DT_CONFIG,
-	wTotalLength:CONFIG_DESC_LEN,
-	bNumInterfaces:0x01,
-	bConfigurationValue:0x01,
-	iConfiguration:0x04,	// configuration string
-	bmAttributes:0xc0,	// self-powered
-	MaxPower:20		// 40 mA
-};
-
-// These strings will be converted to Unicode before sending
-static char *strings[5] = {
-	"Alchemy Semiconductor",
-	"Alchemy Au1000",
-	"1.0",
-	"Au1000 UART Config",
-	"Au1000 UART Interface"
-};
-
-// String[0] is a list of Language IDs supported by this device
-static struct usb_string_descriptor string_desc0 = {
-	bLength:4,
-	bDescriptorType:USB_DT_STRING,
-	wData:{0x0409}		// English, US
-};
+} usbdev;
 
 
 static endpoint_reg_t ep_reg[] = {
 	// FIFO's 0 and 1 are EP0 default control
-	{USBD_EP0RD, USBD_EP0WR, USBD_EP0CS, USBD_EP0RDSTAT, USBD_EP0WRSTAT},
-	// FIFO 2 is EP2, Port 0, bulk IN
+	{USBD_EP0RD, USBD_EP0WR, USBD_EP0CS, USBD_EP0RDSTAT, USBD_EP0WRSTAT },
+	{0},
+	// FIFO 2 is EP2, IN
 	{ -1, USBD_EP2WR, USBD_EP2CS, -1, USBD_EP2WRSTAT },
-	// FIFO 4 is EP4, Port 0, bulk OUT
-	    {USBD_EP4RD, -1, USBD_EP4CS, USBD_EP3WR, -1},
-	// FIFO 3 is EP3, Port 1, bulk IN
-	{ -1, USBD_EP3WRSTAT, USBD_EP3CS, -1, USBD_EP3WRSTAT },
-	// FIFO 5 is EP5, Port 1, bulk OUT
-	    {USBD_EP5RD, -1, USBD_EP5CS, USBD_EP5RDSTAT, -1}
+	// FIFO 3 is EP3, IN
+	{    -1,     USBD_EP3WR, USBD_EP3CS,     -1,         USBD_EP3WRSTAT },
+	// FIFO 4 is EP4, OUT
+	{USBD_EP4RD,     -1,     USBD_EP4CS, USBD_EP4RDSTAT,     -1         },
+	// FIFO 5 is EP5, OUT
+	{USBD_EP5RD,     -1,     USBD_EP5CS, USBD_EP5RDSTAT,     -1         }
 };
 
 static struct {
@@ -297,172 +154,88 @@
 	{ DMA_ID_USBDEV_EP0_TX, "USBDev EP0 IN" },
 	{ DMA_ID_USBDEV_EP0_RX, "USBDev EP0 OUT" },
 	{ DMA_ID_USBDEV_EP2_TX, "USBDev EP2 IN" },
-	{ DMA_ID_USBDEV_EP4_RX, "USBDev EP4 OUT" },
 	{ DMA_ID_USBDEV_EP3_TX, "USBDev EP3 IN" },
+	{ DMA_ID_USBDEV_EP4_RX, "USBDev EP4 OUT" },
 	{ DMA_ID_USBDEV_EP5_RX, "USBDev EP5 OUT" }
 };
 
-static int serial_refcount;
-static struct tty_driver serial_tty_driver;
-static struct tty_struct *serial_tty[1];
-static struct termios *serial_termios[1];
-static struct termios *serial_termios_locked[1];
-static struct usb_serial usbserial;
-
 #define DIR_OUT 0
 #define DIR_IN  (1<<3)
 
-static const u32 au1000_config_table[25] __devinitdata = {
-	0x00,
-	    ((EP0_MAX_PACKET_SIZE & 0x380) >> 7) |
-	    (USB_ENDPOINT_XFER_CONTROL << 4),
-	(EP0_MAX_PACKET_SIZE & 0x7f) << 1,
-	0x00,
-	0x01,
-
-	0x10,
-	    ((EP2_MAX_PACKET_SIZE & 0x380) >> 7) | DIR_IN |
-	    (USB_ENDPOINT_XFER_BULK << 4),
-	(EP2_MAX_PACKET_SIZE & 0x7f) << 1,
-	0x00,
-	0x02,
-
-	0x20,
-	    ((EP3_MAX_PACKET_SIZE & 0x380) >> 7) | DIR_IN |
-	    (USB_ENDPOINT_XFER_BULK << 4),
-	(EP3_MAX_PACKET_SIZE & 0x7f) << 1,
-	0x00,
-	0x03,
-
-	0x30,
-	    ((EP4_MAX_PACKET_SIZE & 0x380) >> 7) | DIR_OUT |
-	    (USB_ENDPOINT_XFER_BULK << 4),
-	(EP4_MAX_PACKET_SIZE & 0x7f) << 1,
-	0x00,
-	0x04,
-
-	0x40,
-	    ((EP5_MAX_PACKET_SIZE & 0x380) >> 7) | DIR_OUT |
-	    (USB_ENDPOINT_XFER_BULK << 4),
-	(EP5_MAX_PACKET_SIZE & 0x7f) << 1,
-	0x00,
-	0x05
-};
-
-static inline endpoint_t *
-fifonum_to_ep(struct usb_serial* serial, int fifo_num)
-{
-	switch (fifo_num) {
-	case 0:
-	case 1:
-		return &serial->ep_ctrl;
-	case 2:
-		return &serial->port[0].ep_bulkin;
-	case 3:
-		return &serial->port[1].ep_bulkin;
-	case 4:
-		return &serial->port[0].ep_bulkout;
-	case 5:
-		return &serial->port[1].ep_bulkout;
-	}
-
-	return NULL;
-}
-
-static inline struct usb_serial_port *
-fifonum_to_port(struct usb_serial* serial, int fifo_num)
-{
-	switch (fifo_num) {
-	case 2:
-	case 4:
-		return &serial->port[0];
-	case 3:
-	case 5:
-		return &serial->port[1];
-	}
-
-	return NULL;
-}
+#define CONTROL_EP USB_ENDPOINT_XFER_CONTROL
+#define BULK_EP    USB_ENDPOINT_XFER_BULK
 
 static inline endpoint_t *
-epnum_to_ep(struct usb_serial* serial, int ep_num)
+epaddr_to_ep(struct usb_dev* dev, int ep_addr)
 {
-	switch (ep_num) {
-	case 0:
-		return &serial->ep_ctrl;
-	case 2:
-		return &serial->port[0].ep_bulkin;
-	case 3:
-		return &serial->port[1].ep_bulkin;
-	case 4:
-		return &serial->port[0].ep_bulkout;
-	case 5:
-		return &serial->port[1].ep_bulkout;
-	}
-
+	if (ep_addr >= 0 && ep_addr < 2)
+		return &dev->ep[0];
+	if (ep_addr < 6)
+		return &dev->ep[ep_addr];
 	return NULL;
 }
 
+static const char* std_req_name[] = {
+	"GET_STATUS",
+	"CLEAR_FEATURE",
+	"RESERVED",
+	"SET_FEATURE",
+	"RESERVED",
+	"SET_ADDRESS",
+	"GET_DESCRIPTOR",
+	"SET_DESCRIPTOR",
+	"GET_CONFIGURATION",
+	"SET_CONFIGURATION",
+	"GET_INTERFACE",
+	"SET_INTERFACE",
+	"SYNCH_FRAME"
+};
 
-static inline int
-port_paranoia_check(struct usb_serial_port *port, const char *function)
+static inline const char*
+get_std_req_name(int req)
 {
-	if (!port) {
-		dbg("%s - port == NULL", function);
-		return -1;
-	}
-	if (!port->serial) {
-		dbg("%s - port->serial == NULL", function);
-		return -1;
-	}
-	if (!port->tty) {
-		dbg("%s - port->tty == NULL", function);
-		return -1;
-	}
-
-	return 0;
+	return (req >= 0 && req <= 12) ? std_req_name[req] : "UNKNOWN";
 }
 
-static inline struct usb_serial*
-get_usb_serial (struct usb_serial_port *port, const char *function)
+#if 0
+static void
+dump_setup(devrequest* s)
 {
-	/* if no port was specified, or it fails a paranoia check */
-	if (!port || port_paranoia_check(port, function)) {
-		/* then say that we dont have a valid usb_serial thing,
-		 * which will end up genrating -ENODEV return values */
-		return NULL;
-	}
-
-	return port->serial;
+	dbg(__FUNCTION__ ": requesttype=%d", s->requesttype);
+	dbg(__FUNCTION__ ": request=%d %s", s->request,
+	    get_std_req_name(s->request));
+	dbg(__FUNCTION__ ": value=0x%04x", s->wValue);
+	dbg(__FUNCTION__ ": index=%d", s->index);
+	dbg(__FUNCTION__ ": length=%d", s->length);
 }
+#endif
 
-
-static inline pkt_t *
-alloc_packet(int data_size)
+static inline usbdev_pkt_t *
+alloc_packet(endpoint_t * ep, int data_size, void* data)
 {
-	pkt_t* pkt = (pkt_t *)kmalloc(sizeof(pkt_t) + data_size, ALLOC_FLAGS);
+	usbdev_pkt_t* pkt =
+		(usbdev_pkt_t *)kmalloc(sizeof(usbdev_pkt_t) + data_size,
+					ALLOC_FLAGS);
 	if (!pkt)
 		return NULL;
+	pkt->ep_addr = ep->address;
 	pkt->size = data_size;
-	pkt->bufptr = pkt->buf;
-#ifndef USBDEV_PIO
-	pkt->bufptr = KSEG1ADDR(pkt->bufptr);
-#endif
+	pkt->status = 0;
 	pkt->next = NULL;
+	if (data)
+		memcpy(pkt->payload, data, data_size);
+
 	return pkt;
 }
 
 
 /*
  * Link a packet to the tail of the enpoint's packet list.
+ * EP spinlock must be held when calling.
  */
 static void
-link_packet(endpoint_t * ep, pkt_list_t * list, pkt_t * pkt)
+link_tail(endpoint_t * ep, pkt_list_t * list, usbdev_pkt_t * pkt)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&ep->lock, flags);
-
 	if (!list->tail) {
 		list->head = list->tail = pkt;
 		list->count = 1;
@@ -471,24 +244,20 @@
 		list->tail = pkt;
 		list->count++;
 	}
-
-	spin_unlock_irqrestore(&ep->lock, flags);
 }
 
 /*
- * Unlink and return a packet from the head of the enpoint's packet list.
+ * Unlink and return a packet from the head of the given packet
+ * list. It is the responsibility of the caller to free the packet.
+ * EP spinlock must be held when calling.
  */
-static pkt_t *
-unlink_packet(endpoint_t * ep, pkt_list_t * list)
+static usbdev_pkt_t *
+unlink_head(pkt_list_t * list)
 {
-	unsigned long flags;
-	pkt_t *pkt;
-
-	spin_lock_irqsave(&ep->lock, flags);
+	usbdev_pkt_t *pkt;
 
 	pkt = list->head;
 	if (!pkt || !list->count) {
-		spin_unlock_irqrestore(&ep->lock, flags);
 		return NULL;
 	}
 
@@ -499,118 +268,107 @@
 	} else
 		list->count--;
 
-	spin_unlock_irqrestore(&ep->lock, flags);
-
 	return pkt;
 }
 
 /*
  * Create and attach a new packet to the tail of the enpoint's
- * packet list.
+ * packet list. EP spinlock must be held when calling.
  */
-static pkt_t *
+static usbdev_pkt_t *
 add_packet(endpoint_t * ep, pkt_list_t * list, int size)
 {
-	pkt_t *pkt = alloc_packet(size);
+	usbdev_pkt_t *pkt = alloc_packet(ep, size, NULL);
 	if (!pkt)
 		return NULL;
 
-	link_packet(ep, list, pkt);
+	link_tail(ep, list, pkt);
 	return pkt;
 }
 
 
 /*
  * Unlink and free a packet from the head of the enpoint's
- * packet list.
+ * packet list. EP spinlock must be held when calling.
  */
 static inline void
-free_packet(endpoint_t * ep, pkt_list_t * list)
+free_packet(pkt_list_t * list)
 {
-	kfree(unlink_packet(ep, list));
+	kfree(unlink_head(list));
 }
 
+/* EP spinlock must be held when calling. */
 static inline void
-flush_pkt_list(endpoint_t * ep, pkt_list_t * list)
+flush_pkt_list(pkt_list_t * list)
 {
 	while (list->count)
-		free_packet(ep, list);
+		free_packet(list);
 }
 
-
+/* EP spinlock must be held when calling */
 static inline void
 flush_write_fifo(endpoint_t * ep)
 {
 	if (ep->reg->write_fifo_status >= 0) {
-		outl_sync(USBDEV_FSTAT_FLUSH, ep->reg->write_fifo_status);
-		udelay(100);
-		outl_sync(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF,
+		au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF |
+			  USBDEV_FSTAT_OF,
 			  ep->reg->write_fifo_status);
+		//udelay(100);
+		//au_writel(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF,
+		//	  ep->reg->write_fifo_status);
 	}
 }
 
-
+/* EP spinlock must be held when calling */
 static inline void
 flush_read_fifo(endpoint_t * ep)
 {
 	if (ep->reg->read_fifo_status >= 0) {
-		outl_sync(USBDEV_FSTAT_FLUSH, ep->reg->read_fifo_status);
-		udelay(100);
-		outl_sync(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF,
+		au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF |
+			  USBDEV_FSTAT_OF,
 			  ep->reg->read_fifo_status);
+		//udelay(100);
+		//au_writel(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF,
+		//	  ep->reg->read_fifo_status);
 	}
 }
 
 
+/* EP spinlock must be held when calling. */
 static void
 endpoint_flush(endpoint_t * ep)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&ep->lock, flags);
-
 	// First, flush all packets
-	flush_pkt_list(ep, &ep->inlist);
-	flush_pkt_list(ep, &ep->outlist);
+	flush_pkt_list(&ep->inlist);
+	flush_pkt_list(&ep->outlist);
 
 	// Now flush the endpoint's h/w FIFO(s)
 	flush_write_fifo(ep);
 	flush_read_fifo(ep);
-
-	spin_unlock_irqrestore(&ep->lock, flags);
 }
 
-
+/* EP spinlock must be held when calling. */
 static void
 endpoint_stall(endpoint_t * ep)
 {
-	unsigned long flags;
 	u32 cs;
 
-	dbg(__FUNCTION__);
-
-	spin_lock_irqsave(&ep->lock, flags);
-
-	cs = inl(ep->reg->ctrl_stat) | USBDEV_CS_STALL;
-	outl_sync(cs, ep->reg->ctrl_stat);
+	warn(__FUNCTION__);
 
-	spin_unlock_irqrestore(&ep->lock, flags);
+	cs = au_readl(ep->reg->ctrl_stat) | USBDEV_CS_STALL;
+	au_writel(cs, ep->reg->ctrl_stat);
 }
 
+/* EP spinlock must be held when calling. */
 static void
 endpoint_unstall(endpoint_t * ep)
 {
-	unsigned long flags;
 	u32 cs;
 
-	dbg(__FUNCTION__);
-
-	spin_lock_irqsave(&ep->lock, flags);
-
-	cs = inl(ep->reg->ctrl_stat) & ~USBDEV_CS_STALL;
-	outl_sync(cs, ep->reg->ctrl_stat);
+	warn(__FUNCTION__);
 
-	spin_unlock_irqrestore(&ep->lock, flags);
+	cs = au_readl(ep->reg->ctrl_stat) & ~USBDEV_CS_STALL;
+	au_writel(cs, ep->reg->ctrl_stat);
 }
 
 static void
@@ -620,147 +378,182 @@
 }
 
 
-#ifdef USBDEV_PIO
+/* EP spinlock must be held when calling. */
 static int
 endpoint_fifo_read(endpoint_t * ep)
 {
-	unsigned long flags;
 	int read_count = 0;
 	u8 *bufptr;
-	pkt_t *pkt = ep->outlist.tail;
+	usbdev_pkt_t *pkt = ep->outlist.tail;
 
 	if (!pkt)
 		return -EINVAL;
 
-	spin_lock_irqsave(&ep->lock, flags);
-
-	bufptr = pkt->bufptr;
-	while (inl(ep->reg->read_fifo_status) & USBDEV_FSTAT_FCNT_MASK) {
-		*bufptr++ = inl(ep->reg->read_fifo) & 0xff;
+	bufptr = &pkt->payload[pkt->size];
+	while (au_readl(ep->reg->read_fifo_status) & USBDEV_FSTAT_FCNT_MASK) {
+		*bufptr++ = au_readl(ep->reg->read_fifo) & 0xff;
 		read_count++;
 		pkt->size++;
 	}
-	pkt->bufptr = bufptr;
 
-	spin_unlock_irqrestore(&ep->lock, flags);
 	return read_count;
 }
 
-
+#if 0
+/* EP spinlock must be held when calling. */
 static int
-endpoint_fifo_write(endpoint_t * ep)
+endpoint_fifo_write(endpoint_t * ep, int index)
 {
-	unsigned long flags;
 	int write_count = 0;
 	u8 *bufptr;
-	pkt_t *pkt = ep->inlist.head;
+	usbdev_pkt_t *pkt = ep->inlist.head;
 
 	if (!pkt)
 		return -EINVAL;
 
-	spin_lock_irqsave(&ep->lock, flags);
-
-	bufptr = pkt->bufptr;
-	while ((inl(ep->reg->write_fifo_status) & USBDEV_FSTAT_FCNT_MASK) <
-	       EP_FIFO_DEPTH) {
-		if (bufptr < pkt->buf + pkt->size) {
-			outl_sync(*bufptr++, ep->reg->write_fifo);
+	bufptr = &pkt->payload[index];
+	while ((au_readl(ep->reg->write_fifo_status) &
+		USBDEV_FSTAT_FCNT_MASK) < EP_FIFO_DEPTH) {
+		if (bufptr < pkt->payload + pkt->size) {
+			au_writel(*bufptr++, ep->reg->write_fifo);
 			write_count++;
 		} else {
 			break;
 		}
 	}
-	pkt->bufptr = bufptr;
 
-	spin_unlock_irqrestore(&ep->lock, flags);
 	return write_count;
 }
-#endif				// USBDEV_PIO
+#endif
 
 /*
  * This routine is called to restart transmission of a packet.
  * The endpoint's TSIZE must be set to the new packet's size,
  * and DMA to the write FIFO needs to be restarted.
+ * EP spinlock must be held when calling.
  */
 static void
 kickstart_send_packet(endpoint_t * ep)
 {
 	u32 cs;
-	pkt_t *pkt = ep->inlist.head;
+	usbdev_pkt_t *pkt = ep->inlist.head;
 
-	dbg(__FUNCTION__ ": pkt=%p", pkt);
+	vdbg(__FUNCTION__ ": ep%d, pkt=%p", ep->address, pkt);
 
-	if (!pkt)
+	if (!pkt) {
+		err(__FUNCTION__ ": head=NULL! list->count=%d",
+		    ep->inlist.count);
 		return;
+	}
+
+	dma_cache_wback_inv((unsigned long)pkt->payload, pkt->size);
 
 	/*
-	 * The write fifo should already be drained if things are
-	 * working right, but flush it anyway just in case.
+	 * make sure FIFO is empty
 	 */
 	flush_write_fifo(ep);
-	cs = inl(ep->reg->ctrl_stat) & USBDEV_CS_STALL;
+
+	cs = au_readl(ep->reg->ctrl_stat) & USBDEV_CS_STALL;
 	cs |= (pkt->size << USBDEV_CS_TSIZE_BIT);
-	outl_sync(cs, ep->reg->ctrl_stat);
-#ifdef USBDEV_PIO
-	endpoint_fifo_write(ep);
-#else
-	disable_dma(ep->indma);
-	if (get_dma_active_buffer(ep->indma)) {
+	au_writel(cs, ep->reg->ctrl_stat);
+
+	if (get_dma_active_buffer(ep->indma) == 1) {
 		set_dma_count1(ep->indma, pkt->size);
-		set_dma_addr1(ep->indma, virt_to_phys(pkt->bufptr));
+		set_dma_addr1(ep->indma, virt_to_phys(pkt->payload));
 		enable_dma_buffer1(ep->indma);	// reenable
 	} else {
 		set_dma_count0(ep->indma, pkt->size);
-		set_dma_addr0(ep->indma, virt_to_phys(pkt->bufptr));
+		set_dma_addr0(ep->indma, virt_to_phys(pkt->payload));
 		enable_dma_buffer0(ep->indma);	// reenable
 	}
-	enable_dma(ep->indma);
-#endif
+	if (dma_halted(ep->indma))
+		start_dma(ep->indma);
 }
 
 
 /*
  * This routine is called when a packet in the inlist has been
  * completed. Frees the completed packet and starts sending the
- * next.
+ * next. EP spinlock must be held when calling.
  */
-static void
+static usbdev_pkt_t *
 send_packet_complete(endpoint_t * ep)
 {
-	if (ep->inlist.head)
-		dbg(__FUNCTION__ ": pkt=%p, ab=%d",
-		    ep->inlist.head, get_dma_active_buffer(ep->indma));
-
-	outl_sync(inl(ep->reg->ctrl_stat) & USBDEV_CS_STALL,
-		  ep->reg->ctrl_stat);
-	//disable_dma(ep->indma);
-	free_packet(ep, &ep->inlist);
+	usbdev_pkt_t *pkt = unlink_head(&ep->inlist);
+
+	if (pkt) {
+		pkt->status =
+			(au_readl(ep->reg->ctrl_stat) & USBDEV_CS_NAK) ?
+			PKT_STATUS_NAK : PKT_STATUS_ACK;
+
+		vdbg(__FUNCTION__ ": ep%d, %s pkt=%p, list count=%d",
+		     ep->address, (pkt->status & PKT_STATUS_NAK) ?
+		     "NAK" : "ACK", pkt, ep->inlist.count);
+	}
+
+	/*
+	 * The write fifo should already be drained if things are
+	 * working right, but flush it anyway just in case.
+	 */
+	flush_write_fifo(ep);
+
 	// begin transmitting next packet in the inlist
-	if (ep->inlist.count)
+	if (ep->inlist.count) {
 		kickstart_send_packet(ep);
-}
+	}
 
+	return pkt;
+}
 
 /*
- * Unlink and return a packet from the head of the given ep's packet
- * outlist. It is the responsibility of the caller to free the packet.
- * The receive complete interrupt adds packets to the tail of this list. 
+ * Add a new packet to the tail of the given ep's packet
+ * inlist. The transmit complete interrupt frees packets from
+ * the head of this list. EP spinlock must be held when calling.
  */
-static pkt_t *
-receive_packet(endpoint_t * ep)
+static int
+send_packet(struct usb_dev* dev, usbdev_pkt_t *pkt, int async)
 {
-	pkt_t *pkt = unlink_packet(ep, &ep->outlist);
-	//dma_cache_inv((unsigned long)pkt->buf, pkt->size);
-	return pkt;
+	pkt_list_t *list;
+	endpoint_t* ep;
+
+	if (!pkt || !(ep = epaddr_to_ep(dev, pkt->ep_addr)))
+		return -EINVAL;
+
+	if (!pkt->size)
+		return 0;
+
+	list = &ep->inlist;
+
+	if (!async && list->count) {
+		halt_dma(ep->indma);
+		flush_pkt_list(list);
+	}
+
+	link_tail(ep, list, pkt);
+
+	vdbg(__FUNCTION__ ": ep%d, pkt=%p, size=%d, list count=%d",
+	     ep->address, pkt, pkt->size, list->count);
+
+	if (list->count == 1) {
+		/*
+		 * if the packet count is one, it means the list was empty,
+		 * and no more data will go out this ep until we kick-start
+		 * it again.
+		 */
+		kickstart_send_packet(ep);
+	}
+
+	return pkt->size;
 }
 
 /*
  * This routine is called to restart reception of a packet.
+ * EP spinlock must be held when calling.
  */
 static void
 kickstart_receive_packet(endpoint_t * ep)
 {
-	pkt_t *pkt;
+	usbdev_pkt_t *pkt;
 
 	// get and link a new packet for next reception
 	if (!(pkt = add_packet(ep, &ep->outlist, ep->max_pkt_size))) {
@@ -768,23 +561,21 @@
 		return;
 	}
 
-	/*
-	 * The read fifo should already be drained if things are
-	 * working right, but flush it anyway just in case.
-	 */
-	flush_read_fifo(ep);
-#ifndef USBDEV_PIO
-	if (get_dma_active_buffer(ep->outdma)) {
+	if (get_dma_active_buffer(ep->outdma) == 1) {
+		clear_dma_done1(ep->outdma);
 		set_dma_count1(ep->outdma, ep->max_pkt_size);
-		set_dma_addr1(ep->outdma, virt_to_phys(pkt->bufptr));
+		set_dma_count0(ep->outdma, 0);
+		set_dma_addr1(ep->outdma, virt_to_phys(pkt->payload));
 		enable_dma_buffer1(ep->outdma);	// reenable
 	} else {
+		clear_dma_done0(ep->outdma);
 		set_dma_count0(ep->outdma, ep->max_pkt_size);
-		set_dma_addr0(ep->outdma, virt_to_phys(pkt->bufptr));
+		set_dma_count1(ep->outdma, 0);
+		set_dma_addr0(ep->outdma, virt_to_phys(pkt->payload));
 		enable_dma_buffer0(ep->outdma);	// reenable
 	}
-	enable_dma(ep->outdma);
-#endif
+	if (dma_halted(ep->outdma))
+		start_dma(ep->outdma);
 }
 
 
@@ -795,404 +586,499 @@
  * remaining DMA counter. Then prepares a new packet for reception
  * and restarts DMA. FIXME: what if another packet comes in
  * on top of the completed packet? Counter would be wrong.
+ * EP spinlock must be held when calling.
  */
-static void
+static usbdev_pkt_t *
 receive_packet_complete(endpoint_t * ep)
 {
-	pkt_t *pkt = ep->outlist.tail;
+	usbdev_pkt_t *pkt = ep->outlist.tail;
+	u32 cs;
+
+	halt_dma(ep->outdma);
+
+	cs = au_readl(ep->reg->ctrl_stat);
 
 	if (!pkt)
-		return;
+		return NULL;
 
-	disable_dma(ep->outdma);
 	pkt->size = ep->max_pkt_size - get_dma_residue(ep->outdma);
-#ifdef USBDEV_PIO
-	pkt->bufptr = pkt->buf;	// reset bufptr
-#endif
-	dbg(__FUNCTION__ ": size=%d", pkt->size);
+	if (pkt->size)
+		dma_cache_inv((unsigned long)pkt->payload, pkt->size);
+	/*
+	 * need to pull out any remaining bytes in the FIFO.
+	 */
+	endpoint_fifo_read(ep);
+	/*
+	 * should be drained now, but flush anyway just in case.
+	 */
+	flush_read_fifo(ep);
+
+	pkt->status = (cs & USBDEV_CS_NAK) ? PKT_STATUS_NAK : PKT_STATUS_ACK;
+	if (ep->address == 0 && (cs & USBDEV_CS_SU))
+		pkt->status |= PKT_STATUS_SU;
+
+	vdbg(__FUNCTION__ ": ep%d, %s pkt=%p, size=%d",
+	     ep->address, (pkt->status & PKT_STATUS_NAK) ?
+	     "NAK" : "ACK", pkt, pkt->size);
 
 	kickstart_receive_packet(ep);
-}
 
+	return pkt;
+}
 
 
 /*
- * Add a new packet to the tail of the given ep's packet
- * inlist. The transmit complete interrupt frees packets from
- * the head of this list.
+ ****************************************************************************
+ * Here starts the standard device request handlers. They are
+ * all called by do_setup() via a table of function pointers.
+ ****************************************************************************
  */
-static int
-send_packet(endpoint_t * ep, u8 * data, int data_len, int from_user)
-{
-	unsigned long flags;
-	pkt_list_t *list = &ep->inlist;
-	pkt_t *pkt;
-
-	if (!data || !data_len)
-		return 0;
 
-	if (!(pkt = alloc_packet(data_len))) {
-		err(__FUNCTION__ ": could not alloc new packet");
-		return -ENOMEM;
+static ep0_stage_t
+do_get_status(struct usb_dev* dev, devrequest* setup)
+{
+	switch (setup->requesttype) {
+	case 0x80:	// Device
+		// FIXME: send device status
+		break;
+	case 0x81:	// Interface
+		// FIXME: send interface status
+		break;
+	case 0x82:	// End Point
+		// FIXME: send endpoint status
+		break;
+	default:
+		// Invalid Command
+		endpoint_stall(&dev->ep[0]); // Stall End Point 0
+		break;
 	}
 
-	if (from_user)
-		copy_from_user(pkt->bufptr, data, data_len);
-	else
-		memcpy(pkt->bufptr, data, data_len);
-	au_sync();
-
-	//dma_cache_wback_inv((unsigned long)pkt->buf, data_len);
+	return STATUS_STAGE;
+}
 
-	link_packet(ep, list, pkt);
+static ep0_stage_t
+do_clear_feature(struct usb_dev* dev, devrequest* setup)
+{
+	switch (setup->requesttype) {
+	case 0x00:	// Device
+		if ((le16_to_cpu(setup->wValue) & 0xff) == 1)
+			dev->remote_wakeup_en = 0;
+	else
+			endpoint_stall(&dev->ep[0]);
+		break;
+	case 0x02:	// End Point
+		if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {
+			endpoint_t *ep =
+				epaddr_to_ep(dev,
+					     le16_to_cpu(setup->index) & 0xff);
+
+			endpoint_unstall(ep);
+			endpoint_reset_datatoggle(ep);
+		} else
+			endpoint_stall(&dev->ep[0]);
+		break;
+	}
 
-	spin_lock_irqsave(&ep->lock, flags);
+	return SETUP_STAGE;
+}
 
-	dbg(__FUNCTION__ ": size=%d, list count=%d", pkt->size, list->count);
+static ep0_stage_t
+do_reserved(struct usb_dev* dev, devrequest* setup)
+{
+	// Invalid request, stall End Point 0
+	endpoint_stall(&dev->ep[0]);
+	return SETUP_STAGE;
+}
 
-	if (list->count == 1) {
-		/*
-		 * if the packet count is one, it means the list was empty,
-		 * and no more data will go out this ep until we kick-start
-		 * it again.
-		 */
-		kickstart_send_packet(ep);
+static ep0_stage_t
+do_set_feature(struct usb_dev* dev, devrequest* setup)
+{
+	switch (setup->requesttype) {
+	case 0x00:	// Device
+		if ((le16_to_cpu(setup->wValue) & 0xff) == 1)
+			dev->remote_wakeup_en = 1;
+		else
+			endpoint_stall(&dev->ep[0]);
+		break;
+	case 0x02:	// End Point
+		if ((le16_to_cpu(setup->vwValue) & 0xff) == 0) {
+			endpoint_t *ep =
+				epaddr_to_ep(dev,
+					     le16_to_cpu(setup->index) & 0xff);
+
+			endpoint_stall(ep);
+		} else
+			endpoint_stall(&dev->ep[0]);
+		break;
 	}
 
-	spin_unlock_irqrestore(&ep->lock, flags);
-	return data_len;
+	return SETUP_STAGE;
 }
 
-
-// SETUP packet request parser
-static void
-process_setup (struct usb_serial* serial, devrequest* setup)
+static ep0_stage_t
+do_set_address(struct usb_dev* dev, devrequest* setup)
 {
-	int desc_len, strnum;
+	int new_state = dev->state;
+	int new_addr = le16_to_cpu(setup->wValue);
 
-	dbg(__FUNCTION__ ": req %d", setup->request);
+	dbg(__FUNCTION__ ": our address=%d", new_addr);
 
-	switch (setup->request) {
-	case USB_REQ_SET_ADDRESS:
-		serial->address = le16_to_cpu(setup->value);
-		dbg(__FUNCTION__ ": our address=%d", serial->address);
-		if (serial->address > 127 || serial->state == CONFIGURED) {
+	if (new_addr > 127) {
 			// usb spec doesn't tell us what to do, so just go to
 			// default state
-			serial->state = DEFAULT;
-			serial->address = 0;
-		} else if (serial->address)
-			serial->state = ADDRESS;
-		else
-			serial->state = DEFAULT;
-		break;
-	case USB_REQ_GET_DESCRIPTOR:
-		desc_len = le16_to_cpu(setup->length);
-		switch (le16_to_cpu(setup->value) >> 8) {
+		new_state = DEFAULT;
+		dev->address = 0;
+	} else if (dev->address != new_addr) {
+		dev->address = new_addr;
+		new_state = ADDRESS;
+	}
+
+	if (dev->state != new_state) {
+		dev->state = new_state;
+		/* inform function layer of usbdev state change */
+		dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data);
+	}
+
+	return SETUP_STAGE;
+}
+
+static ep0_stage_t
+do_get_descriptor(struct usb_dev* dev, devrequest* setup)
+{
+	int strnum, desc_len = le16_to_cpu(setup->length);
+
+		switch (le16_to_cpu(setup->wValue) >> 8) {
 		case USB_DT_DEVICE:
 			// send device descriptor!
-			desc_len = desc_len > serial->dev_desc->bLength ?
-			    serial->dev_desc->bLength : desc_len;
+		desc_len = desc_len > dev->dev_desc->bLength ?
+			dev->dev_desc->bLength : desc_len;
 			dbg("sending device desc, size=%d", desc_len);
-			send_packet(&serial->ep_ctrl, (u8*)serial->dev_desc,
-				    desc_len, 0);
+		send_packet(dev, alloc_packet(&dev->ep[0], desc_len,
+					      dev->dev_desc), 0);
 			break;
 		case USB_DT_CONFIG:
 			// If the config descr index in low-byte of
-			// setup->value	is valid, send config descr,
+			// setup->wValue	is valid, send config descr,
 			// otherwise stall ep0.
-			if ((le16_to_cpu(setup->value) & 0xff) == 0) {
+			if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {
 				// send config descriptor!
 				if (desc_len <= USB_DT_CONFIG_SIZE) {
 					dbg("sending partial config desc, size=%d",
 					     desc_len);
-					send_packet(&serial->ep_ctrl,
-						    (u8*)serial->conf_desc,
-						    desc_len, 0);
+				send_packet(dev,
+					    alloc_packet(&dev->ep[0],
+							 desc_len,
+							 dev->conf_desc),
+					    0);
 				} else {
-					u8 full_conf_desc[CONFIG_DESC_LEN];
-					int i, index = 0;
-					memcpy(&full_conf_desc[index],
-					       serial->conf_desc,
-					       USB_DT_CONFIG_SIZE);
-					index += USB_DT_CONFIG_SIZE;
-					memcpy(&full_conf_desc[index],
-					       serial->if_desc,
-					       USB_DT_INTERFACE_SIZE);
-					index += USB_DT_INTERFACE_SIZE;
-					for (i = 0; i < NUM_PORTS; i++) {
-						memcpy(&full_conf_desc[index],
-						       serial->port[i].ep_bulkin.desc,
-						       USB_DT_ENDPOINT_SIZE);
-						index += USB_DT_ENDPOINT_SIZE;
-						memcpy(&full_conf_desc[index],
-						       serial->port[i].ep_bulkout.desc,
-						       USB_DT_ENDPOINT_SIZE);
-						index += USB_DT_ENDPOINT_SIZE;
-					}
-					dbg("sending whole config desc, size=%d, our size=%d",
-					     desc_len, CONFIG_DESC_LEN);
-					desc_len = desc_len > CONFIG_DESC_LEN ?
-					    CONFIG_DESC_LEN : desc_len;
-					send_packet(&serial->ep_ctrl,
-						    full_conf_desc, desc_len, 0);
+				int len = dev->conf_desc->wTotalLength;
+				dbg("sending whole config desc,"
+				    " size=%d, our size=%d", desc_len, len);
+				desc_len = desc_len > len ? len : desc_len;
+				send_packet(dev,
+					    alloc_packet(&dev->ep[0],
+							 desc_len,
+							 dev->full_conf_desc),
+					    0);
 				}
 			} else
-				endpoint_stall(&serial->ep_ctrl);
+			endpoint_stall(&dev->ep[0]);
 			break;
 		case USB_DT_STRING:
-			// If the string descr index in low-byte of setup->value
+			// If the string descr index in low-byte of setup->wValue
 			// is valid, send string descr, otherwise stall ep0.
-			strnum = le16_to_cpu(setup->value) & 0xff;
+			strnum = le16_to_cpu(setup->wValue) & 0xff;
 			if (strnum >= 0 && strnum < 6) {
 				struct usb_string_descriptor *desc =
-				    serial->str_desc[strnum];
+				dev->str_desc[strnum];
 				desc_len = desc_len > desc->bLength ?
 					desc->bLength : desc_len;
 				dbg("sending string desc %d", strnum);
-				send_packet(&serial->ep_ctrl, (u8 *) desc,
-					    desc_len, 0);
+			send_packet(dev,
+				    alloc_packet(&dev->ep[0], desc_len,
+						 desc), 0);
 			} else
-				endpoint_stall(&serial->ep_ctrl);
+			endpoint_stall(&dev->ep[0]);
 			break;
-		default:	// Invalid request
-			dbg("invalid get desc=%d, stalled",
-			    le16_to_cpu(setup->value) >> 8);
-			endpoint_stall(&serial->ep_ctrl);	// Stall endpoint 0
+	default:
+		// Invalid request
+		err("invalid get desc=%d, stalled",
+			    le16_to_cpu(setup->wValue) >> 8);
+		endpoint_stall(&dev->ep[0]);	// Stall endpoint 0
 			break;
 		}
-		break;
-	case USB_REQ_SET_DESCRIPTOR:
-		// FIXME: anything to set here?
-		break;
-	case USB_REQ_GET_INTERFACE:
+
+	return STATUS_STAGE;
+}
+
+static ep0_stage_t
+do_set_descriptor(struct usb_dev* dev, devrequest* setup)
+{
+	// TODO: implement
+	// there will be an OUT data stage (the descriptor to set)
+	return DATA_STAGE;
+}
+
+static ep0_stage_t
+do_get_configuration(struct usb_dev* dev, devrequest* setup)
+{
+	// send dev->configuration
+	dbg("sending config");
+	send_packet(dev, alloc_packet(&dev->ep[0], 1, &dev->configuration),
+		    0);
+	return STATUS_STAGE;
+}
+
+static ep0_stage_t
+do_set_configuration(struct usb_dev* dev, devrequest* setup)
+{
+	// set active config to low-byte of setup->wValue
+	dev->configuration = le16_to_cpu(setup->wValue) & 0xff;
+	dbg("set config, config=%d", dev->configuration);
+	if (!dev->configuration && dev->state > DEFAULT) {
+		dev->state = ADDRESS;
+		/* inform function layer of usbdev state change */
+		dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data);
+	} else if (dev->configuration == 1) {
+		dev->state = CONFIGURED;
+		/* inform function layer of usbdev state change */
+		dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data);
+	} else {
+		// FIXME: "respond with request error" - how?
+	}
+
+	return SETUP_STAGE;
+}
+
+static ep0_stage_t
+do_get_interface(struct usb_dev* dev, devrequest* setup)
+{
 		// interface must be zero.
-		if ((le16_to_cpu(setup->index) & 0xff) ||
-		    serial->state == ADDRESS) {
+	if ((le16_to_cpu(setup->index) & 0xff) || dev->state == ADDRESS) {
 			// FIXME: respond with "request error". how?
-		} else if (serial->state == CONFIGURED) {
-			// send serial->alternate_setting
+	} else if (dev->state == CONFIGURED) {
+		// send dev->alternate_setting
 			dbg("sending alt setting");
-			send_packet(&serial->ep_ctrl,
-				    &serial->alternate_setting, 1, 0);
+		send_packet(dev, alloc_packet(&dev->ep[0], 1,
+					      &dev->alternate_setting), 0);
 		}
-		break;
-	case USB_REQ_SET_INTERFACE:
-		if (serial->state == ADDRESS) {
+
+	return STATUS_STAGE;
+
+}
+
+static ep0_stage_t
+do_set_interface(struct usb_dev* dev, devrequest* setup)
+{
+	if (dev->state == ADDRESS) {
 			// FIXME: respond with "request error". how?
-		} else if (serial->state == CONFIGURED) {
-			serial->interface = le16_to_cpu(setup->index) & 0xff;
-			serial->alternate_setting =
-			    le16_to_cpu(setup->value) & 0xff;
+	} else if (dev->state == CONFIGURED) {
+		dev->interface = le16_to_cpu(setup->index) & 0xff;
+		dev->alternate_setting =
+			    le16_to_cpu(setup->wValue) & 0xff;
 			// interface and alternate_setting must be zero
-			if (serial->interface || serial->alternate_setting) {
+		if (dev->interface || dev->alternate_setting) {
 				// FIXME: respond with "request error". how?
 			}
 		}
-		break;
-	case USB_REQ_SET_CONFIGURATION:
-		// set active config to low-byte of serial.value
-		serial->configuration = le16_to_cpu(setup->value) & 0xff;
-		dbg("set config, config=%d", serial->configuration);
-		if (!serial->configuration && serial->state > DEFAULT)
-			serial->state = ADDRESS;
-		else if (serial->configuration == 1)
-			serial->state = CONFIGURED;
-		else {
-			// FIXME: "respond with request error" - how?
-		}
-		break;
-	case USB_REQ_GET_CONFIGURATION:
-		// send serial->configuration
-		dbg("sending config");
-		send_packet(&serial->ep_ctrl, &serial->configuration, 1, 0);
-		break;
-	case USB_REQ_GET_STATUS:
-		// FIXME: looks like the h/w handles this one
-		switch (setup->requesttype) {
-		case 0x80:	// Device
-			// FIXME: send device status
-			break;
-		case 0x81:	// Interface
-			// FIXME: send interface status
-			break;
-		case 0x82:	// End Point
-			// FIXME: send endpoint status
-			break;
-		default:	// Invalid Command
-			endpoint_stall(&serial->ep_ctrl);	// Stall End Point 0
-			break;
-		}
-		break;
-	case USB_REQ_CLEAR_FEATURE:
-		switch (setup->requesttype) {
-		case 0x00:	// Device
-			if ((le16_to_cpu(setup->value) & 0xff) == 1)
-				serial->remote_wakeup_en = 0;
-			else
-				endpoint_stall(&serial->ep_ctrl);
-			break;
-		case 0x02:	// End Point
-			if ((le16_to_cpu(setup->value) & 0xff) == 0) {
-				endpoint_t *ep =
-				    epnum_to_ep(serial,
-						    le16_to_cpu(setup->index) & 0xff);
 
-				endpoint_unstall(ep);
-				endpoint_reset_datatoggle(ep);
-			} else
-				endpoint_stall(&serial->ep_ctrl);
-			break;
+	return SETUP_STAGE;
+}
+
+static ep0_stage_t
+do_synch_frame(struct usb_dev* dev, devrequest* setup)
+{
+	// TODO
+	return SETUP_STAGE;
+}
+
+typedef ep0_stage_t (*req_method_t)(struct usb_dev* dev,
+				    devrequest* setup);
+
+
+/* Table of the standard device request handlers */
+static const req_method_t req_method[] = {
+	do_get_status,
+	do_clear_feature,
+	do_reserved,
+	do_set_feature,
+	do_reserved,
+	do_set_address,
+	do_get_descriptor,
+	do_set_descriptor,
+	do_get_configuration,
+	do_set_configuration,
+	do_get_interface,
+	do_set_interface,
+	do_synch_frame
+};
+
+
+// SETUP packet request dispatcher
+static void
+do_setup (struct usb_dev* dev, devrequest* setup)
+{
+	req_method_t m;
+
+	dbg(__FUNCTION__ ": req %d %s", setup->request,
+	    get_std_req_name(setup->request));
+
+	if ((setup->requesttype & USB_TYPE_MASK) != USB_TYPE_STANDARD ||
+	    (setup->requesttype & USB_RECIP_MASK) != USB_RECIP_DEVICE) {
+		err(__FUNCTION__ ": invalid requesttype 0x%02x",
+		    setup->requesttype);
+		return;
 		}
-		break;
-	case USB_REQ_SET_FEATURE:
-		switch (setup->requesttype) {
-		case 0x00:	// Device
-			if ((le16_to_cpu(setup->value) & 0xff) == 1)
-				serial->remote_wakeup_en = 1;
+
+	if ((setup->requesttype & 0x80) == USB_DIR_OUT && setup->length)
+		dbg(__FUNCTION__ ": OUT phase! length=%d", setup->length);
+
+	if (setup->request < sizeof(req_method)/sizeof(req_method_t))
+		m = req_method[setup->request];
 			else
-				endpoint_stall(&serial->ep_ctrl);
-			break;
-		case 0x02:	// End Point
-			if ((le16_to_cpu(setup->value) & 0xff) == 0) {
-				endpoint_t *ep =
-				    epnum_to_ep(serial,
-						    le16_to_cpu(setup->index) & 0xff);
+		m = do_reserved;
 
-				endpoint_stall(ep);
-			} else
-				endpoint_stall(&serial->ep_ctrl);
-			break;
-		}
-		break;
-	default:
-		endpoint_stall(&serial->ep_ctrl);	// Stall End Point 0
-		break;
-	}
+	dev->ep0_stage = (*m)(dev, setup);
 }
 
-
 /*
- * A complete packet (SETUP, DATA0, or DATA1) has been received
- * on the given endpoint's fifo.
+ * A SETUP, DATA0, or DATA1 packet has been received
+ * on the default control endpoint's fifo.
  */
 static void
-process_complete (struct usb_serial* serial, int fifo_num)
+process_ep0_receive (struct usb_dev* dev)
 {
-	endpoint_t *ep = fifonum_to_ep(serial, fifo_num);
-	struct usb_serial_port *port = NULL;
-	pkt_t *pkt = 0;
-	u32 cs;
+	endpoint_t *ep0 = &dev->ep[0];
+	usbdev_pkt_t *pkt;
 
-	cs = inl(ep->reg->ctrl_stat);
+	spin_lock(&ep0->lock);
 
-	switch (fifo_num) {
-	case 0:
-		spin_lock(&ep->lock);
 		// complete packet and prepare a new packet
-		receive_packet_complete(ep);
-
-		// Get it immediately from endpoint.
-		if (!(pkt = receive_packet(ep))) {
-			spin_unlock(&ep->lock);
+	pkt = receive_packet_complete(ep0);
+	if (!pkt) {
+		// FIXME: should  put a warn/err here.
+		spin_unlock(&ep0->lock);
 			return;
 		}
-	
-		// SETUP packet received ?
-		//if (cs & USBDEV_CS_SU) { FIXME: uncomment!
+
+	// unlink immediately from endpoint.
+	unlink_head(&ep0->outlist);
+
+	// override current stage if h/w says it's a setup packet
+	if (pkt->status & PKT_STATUS_SU)
+		dev->ep0_stage = SETUP_STAGE;
+
+	switch (dev->ep0_stage) {
+	case SETUP_STAGE:
+		vdbg("SU bit is %s in setup stage",
+		     (pkt->status & PKT_STATUS_SU) ? "set" : "not set");
+
 			if (pkt->size == sizeof(devrequest)) {
-				devrequest setup;
-			if ((cs & (USBDEV_CS_NAK | USBDEV_CS_ACK)) ==
-			    USBDEV_CS_ACK)
-					dbg("got SETUP");
+#ifdef VDEBUG
+			if (pkt->status & PKT_STATUS_ACK)
+				vdbg("received SETUP");
 				else
-					dbg("got NAK SETUP, cs=%08x", cs);
-			memcpy(&setup, pkt->bufptr, sizeof(devrequest));
-				process_setup(serial, &setup);
-			//} else  FIXME: uncomment!
-			//dbg(__FUNCTION__ ": wrong size SETUP received");
-		} else {
-			// DATAx packet received on endpoint 0
-			// FIXME: will need a state machine for control
-			// OUT transactions
-			dbg("got DATAx on EP0, size=%d, cs=%08x",
-			    pkt->size, cs);
+				vdbg("received NAK SETUP");
+#endif
+			do_setup(dev, (devrequest*)pkt->payload);
+		} else
+			err(__FUNCTION__ ": wrong size SETUP received");
+		break;
+	case DATA_STAGE:
+		/*
+		 * this setup has an OUT data stage. Of the standard
+		 * device requests, only set_descriptor has this stage,
+		 * so this packet is that descriptor. TODO: drop it for
+		 * now, set_descriptor not implemented.
+		 *
+		 * Need to place a byte in the write FIFO here, to prepare
+		 * to send a zero-length DATA ack packet to the host in the
+		 * STATUS stage.
+		 */
+		au_writel(0, ep0->reg->write_fifo);
+		dbg("received OUT stage DATAx on EP0, size=%d", pkt->size);
+		dev->ep0_stage = SETUP_STAGE;
+		break;
+	case STATUS_STAGE:
+		// this setup had an IN data stage, and host is ACK'ing
+		// the packet we sent during that stage.
+		if (pkt->size != 0)
+			warn("received non-zero ACK on EP0??");
+#ifdef VDEBUG
+		else
+			vdbg("received ACK on EP0");
+#endif
+		dev->ep0_stage = SETUP_STAGE;
+		break;
 		}
 
-		spin_unlock(&ep->lock);
+	spin_unlock(&ep0->lock);
 		// we're done processing the packet, free it
 		kfree(pkt);
-		break;
+}
+
+
+/*
+ * A DATA0/1 packet has been received on one of the OUT endpoints (4 or 5)
+ */
+static void
+process_ep_receive (struct usb_dev* dev, endpoint_t *ep)
+{
+	usbdev_pkt_t *pkt;
 
-	case 4:
-	case 5:
-		port = fifonum_to_port(serial, fifo_num);
-		dbg("got DATAx on port %d, cs=%08x", port->number, cs);
 		spin_lock(&ep->lock);
-		receive_packet_complete(ep);
+	pkt = receive_packet_complete(ep);
 		spin_unlock(&ep->lock);
-		// mark a bh to push this data up to the tty
-		queue_task(&port->receive_complete_tq, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
-		break;
 
-	default:
-		break;
-	}
+	dev->func_cb(CB_PKT_COMPLETE, (unsigned long)pkt, dev->cb_data);
 }
 
 
 
-// This ISR needs to ack both the complete and suspend events
+/* This ISR handles the receive complete and suspend events */
 static void
 req_sus_intr (int irq, void *dev_id, struct pt_regs *regs)
 {
-	struct usb_serial *serial = (struct usb_serial *) dev_id;
-	int i;
+	struct usb_dev *dev = (struct usb_dev *) dev_id;
 	u32 status;
 
-	status = inl(USB_DEV_INT_STATUS);
-	outl_sync(status, USB_DEV_INT_STATUS);	// ack'em
+	status = au_readl(USBD_INTSTAT);
+	au_writel(status, USBD_INTSTAT);	// ack'em
 
-#ifdef USBDEV_PIO
-	for (i = 0; i < 6; i++) {
-		if (status & (1 << (USBDEV_INT_HF_BIT + i))) {
-			endpoint_t *ep = fifonum_to_ep(serial, i);
-
-			if (ep->desc->bEndpointAddress & USB_DIR_IN)
-				endpoint_fifo_write(ep);
-			else
-				endpoint_fifo_read(ep);
-		}
-	}
-#endif
-
-	for (i = 0; i < 6; i++) {
-		if (status & (1 << i))
-			process_complete(serial, i);
-	}
+	if (status & (1<<0))
+		process_ep0_receive(dev);
+	if (status & (1<<4))
+		process_ep_receive(dev, &dev->ep[4]);
+	if (status & (1<<5))
+		process_ep_receive(dev, &dev->ep[5]);
 }
 
 
+/* This ISR handles the DMA done events on EP0 */
 static void
-dma_done_ctrl(struct usb_serial* serial)
+dma_done_ep0_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
-	endpoint_t *ep = &serial->ep_ctrl;
+	struct usb_dev *dev = (struct usb_dev *) dev_id;
+	usbdev_pkt_t* pkt;
+	endpoint_t *ep0 = &dev->ep[0];
 	u32 cs0, buff_done;
 
-	spin_lock(&ep->lock);
-	cs0 = inl(ep->reg->ctrl_stat);
+	spin_lock(&ep0->lock);
+	cs0 = au_readl(ep0->reg->ctrl_stat);
 
 	// first check packet transmit done
-	if ((buff_done = get_dma_buffer_done(ep->indma)) != 0) {
-		// transmitted a DATAx packet on control endpoint 0
+	if ((buff_done = get_dma_buffer_done(ep0->indma)) != 0) {
+		// transmitted a DATAx packet during DATA stage
+		// on control endpoint 0
 		// clear DMA done bit
-		if (buff_done == DMA_D0)
-			clear_dma_done0(ep->indma);
-		else
-			clear_dma_done1(ep->indma);
-
-		send_packet_complete(ep);
+		if (buff_done & DMA_D0)
+			clear_dma_done0(ep0->indma);
+		if (buff_done & DMA_D1)
+			clear_dma_done1(ep0->indma);
+
+		pkt = send_packet_complete(ep0);
+		if (pkt)
+			kfree(pkt);
 	}
 
 	/*
@@ -1200,645 +1086,477 @@
 	 * the receive packet complete intr should happen
 	 * before the DMA done intr occurs.
 	 */
-	if ((buff_done = get_dma_buffer_done(ep->outdma)) != 0) {
+	if ((buff_done = get_dma_buffer_done(ep0->outdma)) != 0) {
 		// clear DMA done bit
-		if (buff_done == DMA_D0)
-			clear_dma_done0(ep->outdma);
-		else
-			clear_dma_done1(ep->outdma);
+		if (buff_done & DMA_D0)
+			clear_dma_done0(ep0->outdma);
+		if (buff_done & DMA_D1)
+			clear_dma_done1(ep0->outdma);
+
+		//process_ep0_receive(dev);
 	}
 
-	spin_unlock(&ep->lock);
+	spin_unlock(&ep0->lock);
 }
 
+/* This ISR handles the DMA done events on endpoints 2,3,4,5 */
 static void
-dma_done_port(struct usb_serial_port * port)
+dma_done_ep_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
-	endpoint_t *ep;
+	struct usb_dev *dev = (struct usb_dev *) dev_id;
+	int i;
+
+	for (i = 2; i < 6; i++) {
 	u32 buff_done;
+		usbdev_pkt_t* pkt;
+		endpoint_t *ep = &dev->ep[i];
+
+		if (!ep->active) continue;
 
-	// first check packet transmit done (bulk IN ep)
-	ep = &port->ep_bulkin;
 	spin_lock(&ep->lock);
-	if ((buff_done = get_dma_buffer_done(ep->indma)) != 0) {
-		// transmitted a DATAx packet on the port's bulk IN endpoint
+
+		if (ep->direction == USB_DIR_IN) {
+			buff_done = get_dma_buffer_done(ep->indma);
+			if (buff_done != 0) {
+				// transmitted a DATAx pkt on the IN ep
 		// clear DMA done bit
-		if (buff_done == DMA_D0)
+		if (buff_done & DMA_D0)
 			clear_dma_done0(ep->indma);
-		else
+		if (buff_done & DMA_D1)
 			clear_dma_done1(ep->indma);
 
-		send_packet_complete(ep);
-		// mark a bh to wakeup any tty write system call on the port.
-		queue_task(&port->send_complete_tq, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
-	}
-	spin_unlock(&ep->lock);
+				pkt = send_packet_complete(ep);
 
+				spin_unlock(&ep->lock);
+				dev->func_cb(CB_PKT_COMPLETE,
+					     (unsigned long)pkt,
+					     dev->cb_data);
+				spin_lock(&ep->lock);
+			}
+		} else {
 	/*
-	 * Now check packet receive done (bulk OUT ep). Shouldn't
-	 * get these, the receive packet complete intr should happen
+			 * Check packet receive done (OUT ep). Shouldn't get
+			 * these, the rx packet complete intr should happen
 	 * before the DMA done intr occurs.
 	 */
-	ep = &port->ep_bulkout;
-	spin_lock(&ep->lock);
-	if ((buff_done = get_dma_buffer_done(ep->outdma)) != 0) {
-		// received a DATAx packet on the port's bulk OUT endpoint
+			buff_done = get_dma_buffer_done(ep->outdma);
+			if (buff_done != 0) {
+				// received a DATAx pkt on the OUT ep
 		// clear DMA done bit
-		if (buff_done == DMA_D0)
+		if (buff_done & DMA_D0)
 			clear_dma_done0(ep->outdma);
-		else
+		if (buff_done & DMA_D1)
 			clear_dma_done1(ep->outdma);
-	}
-	spin_unlock(&ep->lock);
-}
-
-
-// This ISR needs to handle dma done events for ALL endpoints!
-static void
-dma_done_intr (int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct usb_serial *serial = (struct usb_serial *) dev_id;
-	int i;
-
-	dma_done_ctrl(serial);
-	for (i = 0; i < NUM_PORTS; i++)
-		dma_done_port(&serial->port[i]);
-}
-
-
-
-/*****************************************************************************
- * Here begins the tty driver interface functions
- *****************************************************************************/
-
-static int serial_open(struct tty_struct *tty, struct file *filp)
-{
-	int portNumber;
-	struct usb_serial_port *port;
-	struct usb_serial *serial = &usbserial;
-	unsigned long flags;
-
-	/* initialize the pointer incase something fails */
-	tty->driver_data = NULL;
-
-	MOD_INC_USE_COUNT;
-
-	/* set up our port structure making the tty driver remember
-	   our port object, and us it */
-	portNumber = MINOR(tty->device) - serial->minor;
-	port = &serial->port[portNumber];
-	tty->driver_data = port;
-	port->tty = tty;
-
-	if (port_paranoia_check(port, __FUNCTION__))
-		return -ENODEV;
-
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	spin_lock_irqsave(&port->port_lock, flags);
-
-	++port->open_count;
-
-	if (!port->active) {
-		port->active = 1;
-
-		/*
-		 * force low_latency on so that our tty_push actually forces
-		 * the data through, otherwise it is scheduled, and with high
-		 * data rates (like with OHCI) data can get lost.
-		 */
-		port->tty->low_latency = 1;
 
+				//process_ep_receive(dev, ep);
 	}
-
-	spin_unlock_irqrestore(&port->port_lock, flags);
-
-	return 0;
-}
-
-
-static void serial_close(struct tty_struct *tty, struct file *filp)
-{
-	struct usb_serial_port *port =
-	    (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial = get_usb_serial(port, __FUNCTION__);
-	unsigned long flags;
-
-	if (!serial)
-		return;
-
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	if (!port->active) {
-		dbg(__FUNCTION__ " - port not opened");
-		return;
 	}
 
-	spin_lock_irqsave(&port->port_lock, flags);
-
-	--port->open_count;
-
-	if (port->open_count <= 0) {
-		port->active = 0;
-		port->open_count = 0;
+		spin_unlock(&ep->lock);
 	}
-
-	spin_unlock_irqrestore(&port->port_lock, flags);
-	MOD_DEC_USE_COUNT;
 }
 
 
-static int serial_write(struct tty_struct *tty, int from_user,
-			const unsigned char *buf, int count)
+/***************************************************************************
+ * Here begins the external interface functions
+ ***************************************************************************
+ */
+
+/*
+ * allocate a new packet
+ */
+int
+usbdev_alloc_packet(int ep_addr, int data_size, usbdev_pkt_t** pkt)
 {
-	struct usb_serial_port *port =
-	    (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial = get_usb_serial(port, __FUNCTION__);
-	endpoint_t *ep = &port->ep_bulkin;
+	endpoint_t * ep = epaddr_to_ep(&usbdev, ep_addr);
+	usbdev_pkt_t* lpkt = NULL;
 
-	if (!serial)
+	if (!ep || !ep->active || ep->address < 2)
 		return -ENODEV;
-
-	if (!port->active) {
-		dbg(__FUNCTION__ " - port not opened");
+	if (data_size > ep->max_pkt_size)
 		return -EINVAL;
-	}
-
-	if (count == 0) {
-		dbg(__FUNCTION__ " - write request of 0 bytes");
-		return (0);
-	}
 
-	count = (count > ep->max_pkt_size) ? ep->max_pkt_size : count;
-	send_packet(ep, (u8 *) buf, count, from_user);
-
-	return (count);
+	lpkt = *pkt = alloc_packet(ep, data_size, NULL);
+	if (!lpkt)
+		return -ENOMEM;
+	return 0;
 }
 
 
-static int serial_write_room(struct tty_struct *tty)
+/*
+ * packet send
+ */
+int
+usbdev_send_packet(int ep_addr, usbdev_pkt_t * pkt)
 {
-	struct usb_serial_port *port =
-	    (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial = get_usb_serial(port, __FUNCTION__);
-	endpoint_t *ep = &port->ep_bulkin;
+	unsigned long flags;
+	int count;
+	endpoint_t * ep;
 
-	if (!serial)
+	if (!pkt || !(ep = epaddr_to_ep(&usbdev, pkt->ep_addr)) ||
+	    !ep->active || ep->address < 2)
 		return -ENODEV;
-
-	if (!port->active) {
-		dbg(__FUNCTION__ " - port not open");
+	if (ep->direction != USB_DIR_IN)
 		return -EINVAL;
-	}
 
-	return ep->max_pkt_size;
-}
+	spin_lock_irqsave(&ep->lock, flags);
+	count = send_packet(&usbdev, pkt, 1);
+	spin_unlock_irqrestore(&ep->lock, flags);
 
+	return count;
+}
 
-static int serial_chars_in_buffer(struct tty_struct *tty)
+/*
+ * packet receive
+ */
+int
+usbdev_receive_packet(int ep_addr, usbdev_pkt_t** pkt)
 {
-	struct usb_serial_port *port =
-	    (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial = get_usb_serial(port, __FUNCTION__);
-	endpoint_t *ep = &port->ep_bulkin;
-	pkt_list_t *list = &ep->inlist;
-	pkt_t *scan;
 	unsigned long flags;
-	int chars = 0;
+	usbdev_pkt_t* lpkt = NULL;
+	endpoint_t *ep = epaddr_to_ep(&usbdev, ep_addr);
 
-	if (!serial)
+	if (!ep || !ep->active || ep->address < 2)
 		return -ENODEV;
-
-	if (!port->active) {
-		dbg(__FUNCTION__ " - port not open");
+	if (ep->direction != USB_DIR_OUT)
 		return -EINVAL;
-	}
 
 	spin_lock_irqsave(&ep->lock, flags);
-	for (scan = list->head; scan; scan = scan->next)
-		chars += scan->size;
+	if (ep->outlist.count > 1)
+		lpkt = unlink_head(&ep->outlist);
 	spin_unlock_irqrestore(&ep->lock, flags);
 
-	return (chars);
-}
-
-
-static void serial_throttle(struct tty_struct *tty)
-{
-	struct usb_serial_port *port =
-	    (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial = get_usb_serial(port, __FUNCTION__);
-
-	if (!serial)
-		return;
-
-	if (!port->active) {
-		dbg(__FUNCTION__ " - port not open");
-		return;
+	if (!lpkt) {
+		/* no packet available */
+		*pkt = NULL;
+		return -ENODATA;
 	}
-	// FIXME: anything to do?
-}
-
-
-static void serial_unthrottle(struct tty_struct *tty)
-{
-	struct usb_serial_port *port =
-	    (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial = get_usb_serial(port, __FUNCTION__);
 
-	if (!serial)
-		return;
+	*pkt = lpkt;
 
-	if (!port->active) {
-		dbg(__FUNCTION__ " - port not open");
-		return;
-	}
-	// FIXME: anything to do?
+	return lpkt->size;
 }
 
 
-static int serial_ioctl(struct tty_struct *tty, struct file *file,
-			unsigned int cmd, unsigned long arg)
+/*
+ * return total queued byte count on the endpoint.
+ */
+int
+usbdev_get_byte_count(int ep_addr)
 {
-	struct usb_serial_port *port =
-	    (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial = get_usb_serial(port, __FUNCTION__);
+        unsigned long flags;
+        pkt_list_t *list;
+        usbdev_pkt_t *scan;
+        int count = 0;
+	endpoint_t * ep = epaddr_to_ep(&usbdev, ep_addr);
 
-	if (!serial)
+	if (!ep || !ep->active || ep->address < 2)
 		return -ENODEV;
 
-	if (!port->active) {
-		dbg(__FUNCTION__ " - port not open");
-		return -ENODEV;
-	}
-	// FIXME: need any IOCTLs?
-
-	return -ENOIOCTLCMD;
-}
-
-
-static void serial_set_termios(struct tty_struct *tty, struct termios *old)
-{
-	struct usb_serial_port *port =
-	    (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial = get_usb_serial(port, __FUNCTION__);
-
-	if (!serial)
-		return;
-
-	if (!port->active) {
-		dbg(__FUNCTION__ " - port not open");
-		return;
-	}
-	// FIXME: anything to do?
-}
-
+	if (ep->direction == USB_DIR_IN) {
+		list = &ep->inlist;
 
-static void serial_break(struct tty_struct *tty, int break_state)
-{
-	struct usb_serial_port *port =
-	    (struct usb_serial_port *) tty->driver_data;
-	struct usb_serial *serial = get_usb_serial(port, __FUNCTION__);
-
-	if (!serial)
-		return;
-
-	if (!port->active) {
-		dbg(__FUNCTION__ " - port not open");
-		return;
-	}
-	// FIXME: anything to do?
-}
-
-
-static void port_send_complete(void *private)
-{
-	struct usb_serial_port *port = (struct usb_serial_port *) private;
-	struct usb_serial *serial = get_usb_serial(port, __FUNCTION__);
-	struct tty_struct *tty;
-
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	if (!serial) {
-		return;
-	}
+		spin_lock_irqsave(&ep->lock, flags);
+		for (scan = list->head; scan; scan = scan->next)
+			count += scan->size;
+		spin_unlock_irqrestore(&ep->lock, flags);
+	} else {
+		list = &ep->outlist;
 
-	tty = port->tty;
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup) {
-		dbg(__FUNCTION__ " - write wakeup call.");
-		(tty->ldisc.write_wakeup) (tty);
+		spin_lock_irqsave(&ep->lock, flags);
+		if (list->count > 1) {
+			for (scan = list->head; scan != list->tail;
+			     scan = scan->next)
+				count += scan->size;
 	}
-
-	wake_up_interruptible(&tty->write_wait);
-}
-
-
-static void port_receive_complete(void *private)
-{
-	struct usb_serial_port *port = (struct usb_serial_port *) private;
-	struct usb_serial *serial = get_usb_serial(port, __FUNCTION__);
-	struct tty_struct *tty = port->tty;
-	pkt_t *pkt;
-	int i;
-
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	if (!serial) {
-		return;
+		spin_unlock_irqrestore(&ep->lock, flags);
 	}
 
-	if (!(pkt = receive_packet(&port->ep_bulkout)))
-		return;
-
-	for (i = 0; i < pkt->size; i++) {
-		/* if we insert more than TTY_FLIPBUF_SIZE characters,
-		   we drop them. */
-		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-			tty_flip_buffer_push(tty);
-		}
-		/* this doesn't actually push the data through
-		   unless tty->low_latency is set */
-		tty_insert_flip_char(tty, pkt->bufptr[i], 0);
-	}
-	tty_flip_buffer_push(tty);
-
-	// we're done processing the packet, free it
-	kfree(pkt);
+	return count;
 }
 
 
-static struct tty_driver serial_tty_driver = {
-	magic:TTY_DRIVER_MAGIC,
-	driver_name:"usbdev-serial",
-	name:"usb/ttsdev/%d",
-	major:SERIAL_TTY_MAJOR,
-	minor_start:0,
-	num:1,
-	type:TTY_DRIVER_TYPE_SERIAL,
-	subtype:SERIAL_TYPE_NORMAL,
-	flags:TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
-	refcount:&serial_refcount,
-	table:serial_tty,
-	termios:serial_termios,
-	termios_locked:serial_termios_locked,
-
-	open:serial_open,
-	close:serial_close,
-	write:serial_write,
-	write_room:serial_write_room,
-	ioctl:serial_ioctl,
-	set_termios:serial_set_termios,
-	throttle:serial_throttle,
-	unthrottle:serial_unthrottle,
-	break_ctl:serial_break,
-	chars_in_buffer:serial_chars_in_buffer,
-};
-
-
-void usbdev_serial_exit(void)
+void
+usbdev_exit(void)
 {
 	endpoint_t *ep;
 	int i;
 
-	outl_sync(0, USB_DEV_INT_ENABLE);	// disable usb dev ints
-	outl_sync(0, USB_DEV_ENABLE);	// disable usb dev
+	au_writel(0, USBD_INTEN);	// disable usb dev ints
+	au_writel(0, USBD_ENABLE);	// disable usb dev
 
-	// first free all control endpoint resources
-	ep = &usbserial.ep_ctrl;
-	free_irq(AU1000_USB_DEV_REQ_INT, &usbserial);
-	free_irq(AU1000_USB_DEV_SUS_INT, &usbserial);
-	free_irq(ep->inirq, &usbserial);
-	//free_irq(ep->outirq, &usbserial);
+	free_irq(AU1000_USB_DEV_REQ_INT, &usbdev);
+	free_irq(AU1000_USB_DEV_SUS_INT, &usbdev);
+
+	// free all control endpoint resources
+	ep = &usbdev.ep[0];
 	free_au1000_dma(ep->indma);
 	free_au1000_dma(ep->outdma);
 	endpoint_flush(ep);
 
-	// now free all port resources
-	for (i = 0; i < NUM_PORTS; i++) {
-		// free port's bulk IN endpoint resources
-		ep = &usbserial.port[i].ep_bulkin;
-		free_irq(ep->inirq, &usbserial);
-		free_au1000_dma(ep->indma);
-		endpoint_flush(ep);
+	// free ep resources
+	for (i = 2; i < 6; i++) {
+		ep = &usbdev.ep[i];
+		if (!ep->active) continue;
 
-		// free port's bulk OUT endpoint resources
-		ep = &usbserial.port[i].ep_bulkout;
-		//free_irq(ep->outirq, &usbserial);
+		if (ep->direction == USB_DIR_IN) {
+			free_au1000_dma(ep->indma);
+		} else {
 		free_au1000_dma(ep->outdma);
+		}
 		endpoint_flush(ep);
-
-		tty_unregister_devfs(&serial_tty_driver, i);
-		info("usbdev serial converter now disconnected from ttyUSBdev%d",
-		     i);
 	}
 
-	kfree(usbserial.str_desc[0]);
-	tty_unregister_driver(&serial_tty_driver);
+	if (usbdev.full_conf_desc)
+		kfree(usbdev.full_conf_desc);
 }
 
-int usbdev_serial_init(void)
-{
-	struct usb_serial_port *port;
+int
+usbdev_init(struct usb_device_descriptor* dev_desc,
+	    struct usb_config_descriptor* config_desc,
+	    struct usb_interface_descriptor* if_desc,
+	    struct usb_endpoint_descriptor* ep_desc,
+	    struct usb_string_descriptor* str_desc[],
+	    void (*cb)(usbdev_cb_type_t, unsigned long, void *),
+	    void* cb_data)
+{
+	endpoint_t *ep0;
+	int i, ret=0;
+	u8* fcd;
+
+	if (dev_desc->bNumConfigurations > 1 ||
+	    config_desc->bNumInterfaces > 1 ||
+	    if_desc->bNumEndpoints > 4) {
+		err("Only one config, one i/f, and no more "
+		    "than 4 ep's allowed");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (!cb) {
+		err("Function-layer callback required");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (dev_desc->bMaxPacketSize0 != USBDEV_EP0_MAX_PACKET_SIZE) {
+		warn("EP0 Max Packet size must be %d",
+		     USBDEV_EP0_MAX_PACKET_SIZE);
+		dev_desc->bMaxPacketSize0 = USBDEV_EP0_MAX_PACKET_SIZE;
+	}
+
+	memset(&usbdev, 0, sizeof(struct usb_dev));
+
+	usbdev.state = DEFAULT;
+	usbdev.dev_desc = dev_desc;
+	usbdev.if_desc = if_desc;
+	usbdev.conf_desc = config_desc;
+	for (i=0; i<6; i++)
+		usbdev.str_desc[i] = str_desc[i];
+	usbdev.func_cb = cb;
+	usbdev.cb_data = cb_data;
+
+	/* Initialize default control endpoint */
+	ep0 = &usbdev.ep[0];
+	ep0->active = 1;
+	ep0->type = CONTROL_EP;
+	ep0->max_pkt_size = USBDEV_EP0_MAX_PACKET_SIZE;
+	spin_lock_init(&ep0->lock);
+	ep0->desc = NULL;	// ep0 has no descriptor
+	ep0->address = 0;
+	ep0->direction = 0;
+	ep0->reg = &ep_reg[0];
+
+	/* Initialize the other requested endpoints */
+	for (i = 0; i < if_desc->bNumEndpoints; i++) {
+		struct usb_endpoint_descriptor* epd = &ep_desc[i];
 	endpoint_t *ep;
-	void *str_desc_buf;
-	int str_desc_len;
-	int i;
 
-	/* register the tty driver */
-	serial_tty_driver.init_termios = tty_std_termios;
-	serial_tty_driver.init_termios.c_cflag =
-	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-
-	if (tty_register_driver(&serial_tty_driver)) {
-		err(__FUNCTION__ ": failed to register tty driver");
-		return -1;
+		if ((epd->bEndpointAddress & 0x80) == USB_DIR_IN) {
+			ep = &usbdev.ep[2];
+			ep->address = 2;
+			if (ep->active) {
+				ep = &usbdev.ep[3];
+				ep->address = 3;
+				if (ep->active) {
+					err("too many IN ep's requested");
+					ret = -ENODEV;
+					goto out;
 	}
-
-	memset(&usbserial, 0, sizeof(struct usb_serial));
-	usbserial.minor = 0;
-
-	usbserial.state = DEFAULT;
-
-	usbserial.dev_desc = &dev_desc;
-	usbserial.if_desc = &if_desc;
-	usbserial.conf_desc = &config_desc;
-
-	/*
-	 * initialize the string descriptors
-	 */
-
-	/* alloc buffer big enough for all string descriptors */
-	str_desc_len = string_desc0.bLength;
-	for (i = 0; i < 5; i++)
-		str_desc_len += 2 + 2 * strlen(strings[i]);
-	str_desc_buf = (void *) kmalloc(str_desc_len, ALLOC_FLAGS);
-	if (!str_desc_buf) {
-		err(__FUNCTION__ ": failed to alloc string descriptors");
-		return -1;
-	}
-
-	usbserial.str_desc[0] = (struct usb_string_descriptor *)str_desc_buf;
-	memcpy(usbserial.str_desc[0], &string_desc0, string_desc0.bLength);
-	usbserial.str_desc[1] = (struct usb_string_descriptor *)
-	    (str_desc_buf + string_desc0.bLength);
-	for (i = 1; i < 6; i++) {
-		struct usb_string_descriptor *desc = usbserial.str_desc[i];
-		char *str = strings[i - 1];
-		int j, str_len = strlen(str);
-
-		desc->bLength = 2 + 2 * str_len;
-		desc->bDescriptorType = USB_DT_STRING;
-		for (j = 0; j < str_len; j++) {
-			desc->wData[j] = (u16) str[j];
-		}
-		if (i < 5)
-			usbserial.str_desc[i + 1] =
-			    (struct usb_string_descriptor *)
-			    ((u8 *) desc + desc->bLength);
-	}
-
-	// request the USB device transfer complete interrupt
-	if (request_irq(AU1000_USB_DEV_REQ_INT, req_sus_intr, SA_SHIRQ,
-			"USBdev req", &usbserial)) {
-		err("Can't get device request intr\n");
-		goto err_out;
-	}
-	// request the USB device suspend interrupt
-	if (request_irq(AU1000_USB_DEV_SUS_INT, req_sus_intr, SA_SHIRQ,
-			"USBdev sus", &usbserial)) {
-		err("Can't get device suspend intr\n");
-		goto err_out;
-	}
-
-	// Initialize default control endpoint
-	ep = &usbserial.ep_ctrl;
-	spin_lock_init(&ep->lock);
-	ep->desc = NULL;	// ep0 has no ep descriptor
-	ep->reg = &ep_reg[0];
-	ep->max_pkt_size = usbserial.dev_desc->bMaxPacketSize0;
-	ep->indma = ep->outdma = -1;
-	if ((ep->indma = request_au1000_dma(ep_dma_id[0].id,
-					    ep_dma_id[0].str)) < 0) {
-		err("Can't get %s DMA\n", ep_dma_id[0].str);
-		goto err_out;
-	}
-	if ((ep->outdma = request_au1000_dma(ep_dma_id[1].id,
-					     ep_dma_id[1].str)) < 0) {
-		err("Can't get %s DMA\n", ep_dma_id[1].str);
-		goto err_out;
-	}
-	ep->inirq = get_dma_done_irq(ep->indma);
-	ep->outirq = get_dma_done_irq(ep->outdma);
-	// allocate EP0's DMA done interrupts.
-	if (request_irq(ep->inirq, dma_done_intr, SA_INTERRUPT,
-			"USBdev ep0 IN", &usbserial)) {
-		err("Can't get ep0 IN dma done irq\n");
-		goto err_out;
 	}
-#if 0
-	if (request_irq(ep->outirq, dma_done_intr, SA_INTERRUPT,
-			"USBdev ep0 OUT", &usbserial)) {
-		err("Can't get ep0 OUT dma done irq\n");
-		goto err_out;
+		} else {
+			ep = &usbdev.ep[4];
+			ep->address = 4;
+			if (ep->active) {
+				ep = &usbdev.ep[5];
+				ep->address = 5;
+				if (ep->active) {
+					err("too many OUT ep's requested");
+					ret = -ENODEV;
+					goto out;
+	}
 	}
-#endif
-
-	/* initialize the devfs nodes for this device and let the user
-	   know what ports we are bound to */
-	for (i = 0; i < NUM_PORTS; ++i) {
-		tty_register_devfs(&serial_tty_driver, 0, i);
-		info("usbdev serial attached to ttyUSBdev%d (or devfs usb/ttsdev/%d)", 
-		     i, i);
-		port = &usbserial.port[i];
-		port->serial = &usbserial;
-		port->number = i;
-		port->send_complete_tq.routine = port_send_complete;
-		port->send_complete_tq.data = port;
-		port->receive_complete_tq.routine = port_receive_complete;
-		port->receive_complete_tq.data = port;
-		spin_lock_init(&port->port_lock);
-
-		// Initialize the port's bulk IN endpoint
-		ep = &port->ep_bulkin;
-		spin_lock_init(&ep->lock);
-		ep->desc = &ep_desc[NUM_PORTS * i];
-		ep->reg = &ep_reg[1 + NUM_PORTS * i];
-		ep->max_pkt_size = ep->desc->wMaxPacketSize;
-		ep->indma = ep->outdma = -1;
-		if ((ep->indma =
-		     request_au1000_dma(ep_dma_id[2+NUM_PORTS*i].id,
-				 ep_dma_id[2 + NUM_PORTS * i].str)) < 0) {
-			err("Can't get %s DMA\n",
-			    ep_dma_id[2 + NUM_PORTS * i].str);
-			goto err_out;
-		}
-		ep->inirq = get_dma_done_irq(ep->indma);
-		if (request_irq(ep->inirq, dma_done_intr, SA_INTERRUPT,
-				"USBdev bulk IN", &usbserial)) {
-			err("Can't get port %d bulk IN dma done irq\n", i);
-			goto err_out;
 		}
-		// Initialize the port's bulk OUT endpoint
-		ep = &port->ep_bulkout;
+
+		ep->active = 1;
+		epd->bEndpointAddress &= ~0x0f;
+		epd->bEndpointAddress |= (u8)ep->address;
+		ep->direction = epd->bEndpointAddress & 0x80;
+		ep->type = epd->bmAttributes & 0x03;
+		ep->max_pkt_size = epd->wMaxPacketSize;
 		spin_lock_init(&ep->lock);
-		ep->desc = &ep_desc[NUM_PORTS * i + 1];
-		ep->reg = &ep_reg[1 + NUM_PORTS * i + 1];
-		ep->max_pkt_size = ep->desc->wMaxPacketSize;
-		ep->indma = ep->outdma = -1;
-		if ((ep->outdma =
-		     request_au1000_dma(ep_dma_id[2+NUM_PORTS*i + 1].id,
-					ep_dma_id[2+NUM_PORTS*i + 1].str)) < 0) {
-			err("Can't get %s DMA\n",
-			    ep_dma_id[2 + NUM_PORTS * i + 1].str);
-			goto err_out;
+		ep->desc = epd;
+		ep->reg = &ep_reg[ep->address];
 		}
-		ep->outirq = get_dma_done_irq(ep->outdma);
-#if 0
-		if (request_irq(ep->outirq, dma_done_intr, SA_INTERRUPT,
-				"USBdev bulk OUT", &usbserial)) {
-			err("Can't get port %d bulk OUT dma done irq\n", i);
-			goto err_out;
-		}
-#endif
+
+	/*
+	 * initialize the full config descriptor
+	 */
+	usbdev.full_conf_desc = fcd = kmalloc(config_desc->wTotalLength,
+					      ALLOC_FLAGS);
+	if (!fcd) {
+		err("failed to alloc full config descriptor");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	memcpy(fcd, config_desc, USB_DT_CONFIG_SIZE);
+	fcd += USB_DT_CONFIG_SIZE;
+	memcpy(fcd, if_desc, USB_DT_INTERFACE_SIZE);
+	fcd += USB_DT_INTERFACE_SIZE;
+	for (i = 0; i < if_desc->bNumEndpoints; i++) {
+		memcpy(fcd, &ep_desc[i], USB_DT_ENDPOINT_SIZE);
+		fcd += USB_DT_ENDPOINT_SIZE;
 	}
 
-	// enable device controller
-	outl_sync(0x0002, USB_DEV_ENABLE);
+	/* Now we're ready to enable the controller */
+	au_writel(0x0002, USBD_ENABLE);
 	udelay(100);
-	outl_sync(0x0003, USB_DEV_ENABLE);
+	au_writel(0x0003, USBD_ENABLE);
 	udelay(100);
-	for (i = 0; i < sizeof(au1000_config_table) / sizeof(u32); ++i)
-		outl_sync(au1000_config_table[i], USB_DEV_CONFIG);
-
-	// Flush the endpoint buffers and FIFOs
-	ep = &usbserial.ep_ctrl;
-	endpoint_flush(ep);
-	// start packet reception on control ep
-	kickstart_receive_packet(ep);
 
-	for (i = 0; i < NUM_PORTS; ++i) {
-		struct usb_serial_port *port = &usbserial.port[i];
-		endpoint_flush(&port->ep_bulkin);
-		endpoint_flush(&port->ep_bulkout);
-		// start packet reception on bulk OUT endpoint
-		kickstart_receive_packet(&port->ep_bulkout);
+	/* build and send config table based on ep descriptors */
+	for (i = 0; i < 6; i++) {
+		endpoint_t *ep;
+		if (i == 1)
+			continue; // skip dummy ep
+		ep = &usbdev.ep[i];
+		if (ep->active) {
+			au_writel((ep->address << 4) | 0x04, USBD_CONFIG);
+			au_writel(((ep->max_pkt_size & 0x380) >> 7) |
+				  (ep->direction >> 4) | (ep->type << 4),
+				  USBD_CONFIG);
+			au_writel((ep->max_pkt_size & 0x7f) << 1, USBD_CONFIG);
+			au_writel(0x00, USBD_CONFIG);
+			au_writel(ep->address, USBD_CONFIG);
+		} else {
+			u8 dir = (i==2 || i==3) ? DIR_IN : DIR_OUT;
+			au_writel((i << 4) | 0x04, USBD_CONFIG);
+			au_writel(((16 & 0x380) >> 7) | dir |
+				  (BULK_EP << 4), USBD_CONFIG);
+			au_writel((16 & 0x7f) << 1, USBD_CONFIG);
+			au_writel(0x00, USBD_CONFIG);
+			au_writel(i, USBD_CONFIG);
+		}
 	}
 
 	/*
 	 * Enable Receive FIFO Complete interrupts only. Transmit
 	 * complete is being handled by the DMA done interrupts.
 	 */
-	outl_sync(0x31, USB_DEV_INT_ENABLE);
+	au_writel(0x31, USBD_INTEN);
 
-	return 0;
+	/*
+	 * Controller is now enabled, request DMA and IRQ
+	 * resources.
+	 */
 
-      err_out:
-	usbdev_serial_exit();
-	return -1;
-}
+	/* request the USB device transfer complete interrupt */
+	if (request_irq(AU1000_USB_DEV_REQ_INT, req_sus_intr, SA_INTERRUPT,
+			"USBdev req", &usbdev)) {
+		err("Can't get device request intr");
+		ret = -ENXIO;
+		goto out;
+	}
+	/* request the USB device suspend interrupt */
+	if (request_irq(AU1000_USB_DEV_SUS_INT, req_sus_intr, SA_INTERRUPT,
+			"USBdev sus", &usbdev)) {
+		err("Can't get device suspend intr");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	/* Request EP0 DMA and IRQ */
+	if ((ep0->indma = request_au1000_dma(ep_dma_id[0].id,
+					     ep_dma_id[0].str,
+					     dma_done_ep0_intr,
+					     SA_INTERRUPT,
+					     &usbdev)) < 0) {
+		err("Can't get %s DMA", ep_dma_id[0].str);
+		ret = -ENXIO;
+		goto out;
+	}
+	if ((ep0->outdma = request_au1000_dma(ep_dma_id[1].id,
+					      ep_dma_id[1].str,
+					      NULL, 0, NULL)) < 0) {
+		err("Can't get %s DMA", ep_dma_id[1].str);
+		ret = -ENXIO;
+		goto out;
+	}
+
+	// Flush the ep0 buffers and FIFOs
+	endpoint_flush(ep0);
+	// start packet reception on ep0
+	kickstart_receive_packet(ep0);
+
+	/* Request DMA and IRQ for the other endpoints */
+	for (i = 2; i < 6; i++) {
+		endpoint_t *ep = &usbdev.ep[i];
+		if (!ep->active)
+			continue;
+
+		// Flush the endpoint buffers and FIFOs
+		endpoint_flush(ep);
 
+		if (ep->direction == USB_DIR_IN) {
+			ep->indma =
+				request_au1000_dma(ep_dma_id[ep->address].id,
+						   ep_dma_id[ep->address].str,
+						   dma_done_ep_intr,
+						   SA_INTERRUPT,
+						   &usbdev);
+			if (ep->indma < 0) {
+				err("Can't get %s DMA",
+				    ep_dma_id[ep->address].str);
+				ret = -ENXIO;
+				goto out;
+			}
+		} else {
+			ep->outdma =
+				request_au1000_dma(ep_dma_id[ep->address].id,
+						   ep_dma_id[ep->address].str,
+						   NULL, 0, NULL);
+			if (ep->outdma < 0) {
+				err("Can't get %s DMA",
+				    ep_dma_id[ep->address].str);
+				ret = -ENXIO;
+				goto out;
+			}
+
+			// start packet reception on OUT endpoint
+			kickstart_receive_packet(ep);
+		}
+	}
+
+ out:
+	if (ret)
+		usbdev_exit();
+	return ret;
+}
 
-module_init(usbdev_serial_init);
-module_exit(usbdev_serial_exit);
+EXPORT_SYMBOL(usbdev_init);
+EXPORT_SYMBOL(usbdev_exit);
+EXPORT_SYMBOL(usbdev_alloc_packet);
+EXPORT_SYMBOL(usbdev_receive_packet);
+EXPORT_SYMBOL(usbdev_send_packet);
+EXPORT_SYMBOL(usbdev_get_byte_count);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/pb1000/Makefile linux-2.4.20/arch/mips/au1000/pb1000/Makefile
--- linux-2.4.19/arch/mips/au1000/pb1000/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/pb1000/Makefile	2002-10-29 11:18:35.000000000 +0000
@@ -10,10 +10,7 @@
 # unless it's something special (ie not a .c file).
 #
 
-.S.s:
-	$(CPP) $(CFLAGS) $< -o $*.s
-.S.o:
-	$(CC) $(CFLAGS) -c $< -o $*.o
+USE_STANDARD_AS_RULE := true
 
 O_TARGET := pb1000.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/pb1000/init.c linux-2.4.20/arch/mips/au1000/pb1000/init.c
--- linux-2.4.19/arch/mips/au1000/pb1000/init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/pb1000/init.c	2002-10-29 11:18:35.000000000 +0000
@@ -34,7 +34,6 @@
 #include <linux/bootmem.h>
 #include <asm/addrspace.h>
 #include <asm/bootinfo.h>
-#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -59,7 +58,7 @@
 	prom_envp = envp;
 
 	mips_machgroup = MACH_GROUP_ALCHEMY;
-	mips_machtype = MACH_PB1000;  
+	mips_machtype = MACH_PB1000;
 
 	prom_init_cmdline();
 	memsize_str = prom_getenv("memsize");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/pb1000/pci_fixup.c linux-2.4.20/arch/mips/au1000/pb1000/pci_fixup.c
--- linux-2.4.19/arch/mips/au1000/pb1000/pci_fixup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/pb1000/pci_fixup.c	2002-10-29 11:18:49.000000000 +0000
@@ -42,7 +42,7 @@
 #ifdef 	DEBUG
 #define	DBG(x...)	printk(x)
 #else
-#define	DBG(x...)	
+#define	DBG(x...)
 #endif
 
 void __init pcibios_fixup_resources(struct pci_dev *dev)
@@ -54,15 +54,15 @@
 {
 	unsigned long pci_mem_start = (unsigned long) PCI_MEM_START;
 
-	writel(0, PCI_BRIDGE_CONFIG); // set extend byte to 0
-	writel(0, SDRAM_MBAR);        // set mbar to 0
-	writel(0x2, SDRAM_CMD);       // enable memory accesses
+	au_writel(0, PCI_BRIDGE_CONFIG); // set extend byte to 0
+	au_writel(0, SDRAM_MBAR);        // set mbar to 0
+	au_writel(0x2, SDRAM_CMD);       // enable memory accesses
 	au_sync_delay(1);
 
 	// set extend byte to mbar of ext slot
-	writel(((pci_mem_start >> 24) & 0xff) |
+	au_writel(((pci_mem_start >> 24) & 0xff) |
 	       (1 << 8 | 1 << 9 | 1 << 10 | 1 << 27), PCI_BRIDGE_CONFIG);
-	DBG("Set bridge config to %x\n", readl(PCI_BRIDGE_CONFIG));
+	DBG("Set bridge config to %x\n", au_readl(PCI_BRIDGE_CONFIG));
 }
 
 void __init pcibios_fixup_irqs(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/pb1000/pci_ops.c linux-2.4.20/arch/mips/au1000/pb1000/pci_ops.c
--- linux-2.4.19/arch/mips/au1000/pb1000/pci_ops.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/pb1000/pci_ops.c	2002-10-29 11:18:35.000000000 +0000
@@ -46,18 +46,18 @@
 #ifdef 	DEBUG
 #define	DBG(x...)	printk(x)
 #else
-#define	DBG(x...)	
+#define	DBG(x...)
 #endif
 
 static struct resource pci_io_resource = {
-	"pci IO space", 
+	"pci IO space",
 	PCI_IO_START,
 	PCI_IO_END,
 	IORESOURCE_IO
 };
 
 static struct resource pci_mem_resource = {
-	"pci memory space", 
+	"pci memory space",
 	PCI_MEM_START,
 	PCI_MEM_END,
 	IORESOURCE_MEM
@@ -74,10 +74,10 @@
 
 /*
  * "Bus 2" is really the first and only external slot on the pb1000.
- * We'll call that bus 0, and limit the accesses to that single 
+ * We'll call that bus 0, and limit the accesses to that single
  * external slot only. The SDRAM is already initialized in setup.c.
  */
-static int config_access(unsigned char access_type, struct pci_dev *dev, 
+static int config_access(unsigned char access_type, struct pci_dev *dev,
 			 unsigned char where, u32 * data)
 {
 	unsigned char bus = dev->bus->number;
@@ -92,18 +92,18 @@
 	config = PCI_CONFIG_BASE | (where & ~0x3);
 
 	if (access_type == PCI_ACCESS_WRITE) {
-		outl(*data, config);
+		au_writel(*data, config);
 	} else {
-		*data = inl(config);
+		*data = au_readl(config);
 	}
 	au_sync_udelay(1);
 
-	DBG("config_access: %d bus %d dev_fn %x at %x *data %x, conf %x\n", 
+	DBG("config_access: %d bus %d dev_fn %x at %x *data %x, conf %x\n",
 			access_type, bus, dev_fn, where, *data, config);
 
-	DBG("bridge config reg: %x (%x)\n", inl(PCI_BRIDGE_CONFIG), *data);
+	DBG("bridge config reg: %x (%x)\n", au_readl(PCI_BRIDGE_CONFIG), *data);
 
-	if (inl(PCI_BRIDGE_CONFIG) & (1 << 16)) {
+	if (au_readl(PCI_BRIDGE_CONFIG) & (1 << 16)) {
 		*data = 0xffffffff;
 		return -1;
 	} else {
@@ -119,7 +119,7 @@
 
 	ret = config_access(PCI_ACCESS_READ, dev, where, &data);
 	*val = data & 0xff;
-	return ret; 
+	return ret;
 }
 
 
@@ -130,7 +130,7 @@
 
 	ret = config_access(PCI_ACCESS_READ, dev, where, &data);
 	*val = data & 0xffff;
-	return ret; 
+	return ret;
 }
 
 static int read_config_dword(struct pci_dev *dev, int where, u32 * val)
@@ -138,14 +138,14 @@
 	int ret;
 
 	ret = config_access(PCI_ACCESS_READ, dev, where, val);
-	return ret; 
+	return ret;
 }
 
 
 static int write_config_byte(struct pci_dev *dev, int where, u8 val)
 {
 	u32 data = 0;
-       
+
 	if (config_access(PCI_ACCESS_READ, dev, where, &data))
 		return -1;
 
@@ -164,11 +164,11 @@
 
 	if (where & 1)
 		return PCIBIOS_BAD_REGISTER_NUMBER;
-       
+
         if (config_access(PCI_ACCESS_READ, dev, where, &data))
 	       return -1;
 
-	data = (data & ~(0xffff << ((where & 3) << 3))) | 
+	data = (data & ~(0xffff << ((where & 3) << 3))) |
 	       (val << ((where & 3) << 3));
 
 	if (config_access(PCI_ACCESS_WRITE, dev, where, &data))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/pb1000/setup.c linux-2.4.20/arch/mips/au1000/pb1000/setup.c
--- linux-2.4.19/arch/mips/au1000/pb1000/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/pb1000/setup.c	2002-10-29 11:18:36.000000000 +0000
@@ -67,7 +67,6 @@
 extern struct ide_ops *ide_ops;
 #endif
 
-void (*__wbflush) (void);
 extern struct rtc_ops no_rtc_ops;
 extern char * __init prom_getcmdline(void);
 extern void au1000_restart(char *);
@@ -76,11 +75,7 @@
 extern struct resource ioport_resource;
 extern struct resource iomem_resource;
 
-
-void au1000_wbflush(void)
-{
-	__asm__ volatile ("sync");
-}
+void __init bus_error_init(void) { /* nothing */ }
 
 void __init au1000_setup(void)
 {
@@ -88,7 +83,7 @@
 	u32 pin_func, static_cfg0;
 	u32 sys_freqctrl, sys_clksrc;
 	u32 prid = read_32bit_cp0_register(CP0_PRID);
-	
+
 	argptr = prom_getcmdline();
 
 	/* Various early Au1000 Errata corrected by this */
@@ -99,15 +94,14 @@
 		argptr = prom_getcmdline();
 		strcat(argptr, " console=ttyS0,115200");
 	}
-#endif	  
+#endif
 
 	rtc_ops = &no_rtc_ops;
-        __wbflush = au1000_wbflush;
 	_machine_restart = au1000_restart;
 	_machine_halt = au1000_halt;
 	_machine_power_off = au1000_power_off;
 
-	// IO/MEM resources. 
+	// IO/MEM resources.
 	set_io_port_base(0);
 	ioport_resource.start = 0x10000000;
 	ioport_resource.end = 0xffffffff;
@@ -121,8 +115,8 @@
 #endif
 
 	// set AUX clock to 12MHz * 8 = 96 MHz
-	outl(8, SYS_AUXPLL);
-	outl(0, SYS_PINSTATERD);
+	au_writel(8, SYS_AUXPLL);
+	au_writel(0, SYS_PINSTATERD);
 	udelay(100);
 
 #if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1000_USB_DEVICE)
@@ -138,19 +132,19 @@
 #endif
 
 	/* zero and disable FREQ2 */
-	sys_freqctrl = inl(SYS_FREQCTRL0);
+	sys_freqctrl = au_readl(SYS_FREQCTRL0);
 	sys_freqctrl &= ~0xFFF00000;
-	outl(sys_freqctrl, SYS_FREQCTRL0);
+	au_writel(sys_freqctrl, SYS_FREQCTRL0);
 
 	/* zero and disable USBH/USBD clocks */
-	sys_clksrc = inl(SYS_CLKSRC);
+	sys_clksrc = au_readl(SYS_CLKSRC);
 	sys_clksrc &= ~0x00007FE0;
-	outl(sys_clksrc, SYS_CLKSRC);
+	au_writel(sys_clksrc, SYS_CLKSRC);
 
-	sys_freqctrl = inl(SYS_FREQCTRL0);
+	sys_freqctrl = au_readl(SYS_FREQCTRL0);
 	sys_freqctrl &= ~0xFFF00000;
 
-	sys_clksrc = inl(SYS_CLKSRC);
+	sys_clksrc = au_readl(SYS_CLKSRC);
 	sys_clksrc &= ~0x00007FE0;
 
 	switch (prid & 0x000000FF)
@@ -159,17 +153,17 @@
 	case 0x01: /* HA */
 	case 0x02: /* HB */
 	/* CPU core freq to 48MHz to slow it way down... */
-	outl(4, SYS_CPUPLL);
+	au_writel(4, SYS_CPUPLL);
 
 	/*
 	 * Setup 48MHz FREQ2 from CPUPLL for USB Host
 	 */
 	/* FRDIV2=3 -> div by 8 of 384MHz -> 48MHz */
 	sys_freqctrl |= ((3<<22) | (1<<21) | (0<<20));
-	outl(sys_freqctrl, SYS_FREQCTRL0);
+	au_writel(sys_freqctrl, SYS_FREQCTRL0);
 
 	/* CPU core freq to 384MHz */
-	outl(0x20, SYS_CPUPLL);
+	au_writel(0x20, SYS_CPUPLL);
 
 	printk("Au1000: 48MHz OHCI workaround enabled\n");
 		break;
@@ -177,7 +171,7 @@
 	default:  /* HC and newer */
 	// FREQ2 = aux/2 = 48 MHz
 	sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20));
-	outl(sys_freqctrl, SYS_FREQCTRL0);
+	au_writel(sys_freqctrl, SYS_FREQCTRL0);
 		break;
 	}
 
@@ -190,64 +184,69 @@
 #ifdef CONFIG_AU1000_USB_DEVICE
 	sys_clksrc |= ((4<<7) | (0<<6) | (0<<5));
 #endif
-	outl(sys_clksrc, SYS_CLKSRC);
+	au_writel(sys_clksrc, SYS_CLKSRC);
 
 #ifdef CONFIG_USB_OHCI
 	// enable host controller and wait for reset done
-	outl(0x08, USB_HOST_CONFIG);
+	au_writel(0x08, USB_HOST_CONFIG);
 	udelay(1000);
-	outl(0x0E, USB_HOST_CONFIG);
+	au_writel(0x0E, USB_HOST_CONFIG);
 	udelay(1000);
-	inl(USB_HOST_CONFIG); // throw away first read
-	while (!(inl(USB_HOST_CONFIG) & 0x10))
-		inl(USB_HOST_CONFIG);
+	au_readl(USB_HOST_CONFIG); // throw away first read
+	while (!(au_readl(USB_HOST_CONFIG) & 0x10))
+		au_readl(USB_HOST_CONFIG);
 #endif
-	
+
 	// configure pins GPIO[14:9] as GPIO
-	pin_func = inl(SYS_PINFUNC) & (u32)(~0x8080);
+	pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8080);
 
 #ifndef CONFIG_AU1000_USB_DEVICE
 	// 2nd USB port is USB host
 	pin_func |= 0x8000;
 #endif
-	outl(pin_func, SYS_PINFUNC);
-	outl(0x2800, SYS_TRIOUTCLR);
-	outl(0x0030, SYS_OUTPUTCLR);
+	au_writel(pin_func, SYS_PINFUNC);
+	au_writel(0x2800, SYS_TRIOUTCLR);
+	au_writel(0x0030, SYS_OUTPUTCLR);
 #endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1000_USB_DEVICE)
 
-	// make gpio 15 an input (for interrupt line) 
-	pin_func = inl(SYS_PINFUNC) & (u32)(~0x100);
-	// we don't need I2S, so make it available for GPIO[31:29] 
+	// make gpio 15 an input (for interrupt line)
+	pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x100);
+	// we don't need I2S, so make it available for GPIO[31:29]
 	pin_func |= (1<<5);
-	outl(pin_func, SYS_PINFUNC);
+	au_writel(pin_func, SYS_PINFUNC);
+
+	au_writel(0x8000, SYS_TRIOUTCLR);
 
-	outl(0x8000, SYS_TRIOUTCLR);
-	
 #ifdef CONFIG_FB
 	conswitchp = &dummy_con;
 #endif
 
-	static_cfg0 = inl(MEM_STCFG0) & (u32)(~0xc00);
-	outl(static_cfg0, MEM_STCFG0);
+	static_cfg0 = au_readl(MEM_STCFG0) & (u32)(~0xc00);
+	au_writel(static_cfg0, MEM_STCFG0);
 
 	// configure RCE2* for LCD
-	outl(0x00000004, MEM_STCFG2);
+	au_writel(0x00000004, MEM_STCFG2);
 
 	// MEM_STTIME2
-	outl(0x09000000, MEM_STTIME2);
+	au_writel(0x09000000, MEM_STTIME2);
 
 	// Set 32-bit base address decoding for RCE2*
-	outl(0x10003ff0, MEM_STADDR2);
+	au_writel(0x10003ff0, MEM_STADDR2);
 
 	// PCI CPLD setup
 	// expand CE0 to cover PCI
-	outl(0x11803e40, MEM_STADDR1);
+	au_writel(0x11803e40, MEM_STADDR1);
+
+	// burst visibility on
+	au_writel(au_readl(MEM_STCFG0) | 0x1000, MEM_STCFG0);
 
-	// burst visibility on 
-	outl(inl(MEM_STCFG0) | 0x1000, MEM_STCFG0);
+	au_writel(0x83, MEM_STCFG1);         // ewait enabled, flash timing
+	au_writel(0x33030a10, MEM_STTIME1);   // slower timing for FPGA
 
-	outl(0x83, MEM_STCFG1);         // ewait enabled, flash timing
-	outl(0x33030a10, MEM_STTIME1);   // slower timing for FPGA
+	/* setup the static bus controller */
+	au_writel(0x00000002, MEM_STCFG3);  /* type = PCMCIA */
+	au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */
+	au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */
 
 #ifdef CONFIG_FB_E1356
 	if ((argptr = strstr(argptr, "video=")) == NULL) {
@@ -258,39 +257,35 @@
 
 
 #ifdef CONFIG_PCI
-	outl(0, PCI_BRIDGE_CONFIG); // set extend byte to 0
-	outl(0, SDRAM_MBAR);        // set mbar to 0
-	outl(0x2, SDRAM_CMD);       // enable memory accesses
+	au_writel(0, PCI_BRIDGE_CONFIG); // set extend byte to 0
+	au_writel(0, SDRAM_MBAR);        // set mbar to 0
+	au_writel(0x2, SDRAM_CMD);       // enable memory accesses
 	au_sync_delay(1);
 #endif
 
 #ifndef CONFIG_SERIAL_NONSTANDARD
 	/* don't touch the default serial console */
-	outl(0, UART0_ADDR + UART_CLK);
+	au_writel(0, UART0_ADDR + UART_CLK);
 #endif
-	outl(0, UART1_ADDR + UART_CLK);
-	outl(0, UART2_ADDR + UART_CLK);
-	outl(0, UART3_ADDR + UART_CLK);
+	au_writel(0, UART1_ADDR + UART_CLK);
+	au_writel(0, UART2_ADDR + UART_CLK);
+	au_writel(0, UART3_ADDR + UART_CLK);
 
 #ifdef CONFIG_BLK_DEV_IDE
-	{
-		argptr = prom_getcmdline();
-		strcat(argptr, " ide0=noprobe");
-	}
 	ide_ops = &std_ide_ops;
 #endif
 
 	// setup irda clocks
 	// aux clock, divide by 2, clock from 2/4 divider
-	writel(readl(SYS_CLKSRC) | 0x7, SYS_CLKSRC);
-	pin_func = inl(SYS_PINFUNC) & (u32)(~(1<<2)); // clear IRTXD
-	outl(pin_func, SYS_PINFUNC);
+	au_writel(au_readl(SYS_CLKSRC) | 0x7, SYS_CLKSRC);
+	pin_func = au_readl(SYS_PINFUNC) & (u32)(~(1<<2)); // clear IRTXD
+	au_writel(pin_func, SYS_PINFUNC);
 
-	while (inl(SYS_COUNTER_CNTRL) & SYS_CNTRL_E0S);
-	outl(SYS_CNTRL_E0 | SYS_CNTRL_EN0, SYS_COUNTER_CNTRL);
+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_E0S);
+	au_writel(SYS_CNTRL_E0 | SYS_CNTRL_EN0, SYS_COUNTER_CNTRL);
 	au_sync();
-	while (inl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S);
-	outl(0, SYS_TOYTRIM);
+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S);
+	au_writel(0, SYS_TOYTRIM);
 
 	/* Enable Au1000 BCLK switching - note: sed1356 must not use
 	 * its BCLK (Au1000 LCLK) for any timings */
@@ -301,7 +296,7 @@
 	case 0x02: /* HB */
 		break;
 	default:  /* HC and newer */
-		outl(0x00000060, 0xb190003c);
+		au_writel(0x00000060, 0xb190003c);
 		break;
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/pb1100/Makefile linux-2.4.20/arch/mips/au1000/pb1100/Makefile
--- linux-2.4.19/arch/mips/au1000/pb1100/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/pb1100/Makefile	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,24 @@
+#
+#  Copyright 2000,2001 MontaVista Software Inc.
+#  Author: MontaVista Software, Inc.
+#     	ppopov@mvista.com or source@mvista.com
+#
+# Makefile for the Alchemy Semiconductor Pb1100 board.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+.S.s:
+	$(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+	$(CC) $(CFLAGS) -c $< -o $*.o
+
+O_TARGET := pb1100.o
+
+obj-y := init.o setup.o
+
+obj-$(CONFIG_PCI) += pci_fixup.o pci_ops.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/pb1100/init.c linux-2.4.20/arch/mips/au1000/pb1100/init.c
--- linux-2.4.19/arch/mips/au1000/pb1100/init.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/pb1100/init.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,73 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Pb1100 board setup
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or source@mvista.com
+ *
+ *  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.
+ */
+
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/bootmem.h>
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+int prom_argc;
+char **prom_argv, **prom_envp;
+extern void  __init prom_init_cmdline(void);
+extern char *prom_getenv(char *envname);
+
+const char *get_system_type(void)
+{
+	return "Alchemy Pb1100";
+}
+
+int __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
+{
+	unsigned char *memsize_str;
+	unsigned long memsize;
+
+	prom_argc = argc;
+	prom_argv = argv;
+	prom_envp = envp;
+
+	mips_machgroup = MACH_GROUP_ALCHEMY;
+	mips_machtype = MACH_PB1100;
+
+	prom_init_cmdline();
+	memsize_str = prom_getenv("memsize");
+	if (!memsize_str) {
+		memsize = 0x04000000;
+	} else {
+		memsize = simple_strtol(memsize_str, NULL, 0);
+	}
+	add_memory_region(0, memsize, BOOT_MEM_RAM);
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/pb1100/pci_fixup.c linux-2.4.20/arch/mips/au1000/pb1100/pci_fixup.c
--- linux-2.4.19/arch/mips/au1000/pb1100/pci_fixup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/pb1100/pci_fixup.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,68 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Board specific pci fixups.
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or source@mvista.com
+ *
+ *  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.
+ */
+#include <linux/config.h>
+
+#ifdef CONFIG_PCI
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/au1000.h>
+#include <asm/pb1100.h>
+
+#undef	DEBUG
+#ifdef 	DEBUG
+#define	DBG(x...)	printk(x)
+#else
+#define	DBG(x...)
+#endif
+
+static void fixup_resource(int r_num, struct pci_dev *dev) ;
+static unsigned long virt_io_addr;
+
+void __init pcibios_fixup_resources(struct pci_dev *dev)
+{
+}
+
+void __init pcibios_fixup(void)
+{
+}
+
+void __init pcibios_fixup_irqs(void)
+{
+}
+
+unsigned int pcibios_assign_all_busses(void)
+{
+	return 0;
+}
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/pb1100/pci_ops.c linux-2.4.20/arch/mips/au1000/pb1100/pci_ops.c
--- linux-2.4.19/arch/mips/au1000/pb1100/pci_ops.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/pb1100/pci_ops.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,57 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Pb1100 specific pci support.
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or source@mvista.com
+ *
+ *  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.
+ */
+#include <linux/config.h>
+
+#ifdef CONFIG_PCI
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/au1000.h>
+#include <asm/pb1100.h>
+#include <asm/pci_channel.h>
+
+#define PCI_ACCESS_READ  0
+#define PCI_ACCESS_WRITE 1
+
+#undef DEBUG
+#ifdef 	DEBUG
+#define	DBG(x...)	printk(x)
+#else
+#define	DBG(x...)
+#endif
+
+struct pci_channel mips_pci_channels[] = {
+	{(struct pci_ops *) NULL, (struct resource *) NULL,
+	 (struct resource *) NULL, (int) NULL, (int) NULL}
+};
+
+#endif /* CONFIG_PCI */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/pb1100/setup.c linux-2.4.20/arch/mips/au1000/pb1100/setup.c
--- linux-2.4.19/arch/mips/au1000/pb1100/setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/pb1100/setup.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,248 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Alchemy Pb1100 board setup.
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or source@mvista.com
+ *
+ *  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.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/mc146818rtc.h>
+#include <linux/delay.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/keyboard.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+#include <asm/pgtable.h>
+#include <asm/au1000.h>
+#include <asm/pb1100.h>
+
+#ifdef CONFIG_USB_OHCI
+// Enable the workaround for the OHCI DoneHead
+// register corruption problem.
+#define CONFIG_AU1000_OHCI_FIX
+#endif
+
+#if defined(CONFIG_AU1000_SERIAL_CONSOLE)
+extern void console_setup(char *, int *);
+char serial_console[20];
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+extern unsigned long initrd_start, initrd_end;
+extern void * __rd_start, * __rd_end;
+#endif
+
+#ifdef CONFIG_BLK_DEV_IDE
+extern struct ide_ops std_ide_ops;
+extern struct ide_ops *ide_ops;
+#endif
+
+#ifdef CONFIG_RTC
+extern struct rtc_ops pb1500_rtc_ops;
+#endif
+
+extern char * __init prom_getcmdline(void);
+extern void au1000_restart(char *);
+extern void au1000_halt(void);
+extern void au1000_power_off(void);
+extern struct resource ioport_resource;
+extern struct resource iomem_resource;
+
+
+void __init bus_error_init(void) { /* nothing */ }
+
+void __init au1100_setup(void)
+{
+	char *argptr;
+	u32 pin_func, static_cfg0;
+	u32 sys_freqctrl, sys_clksrc;
+
+	argptr = prom_getcmdline();
+
+	/* NOTE: The memory map is established by YAMON 2.08+ */
+
+	/* Various early Au1000 Errata corrected by this */
+	set_cp0_config(1<<19); /* Config[OD] */
+
+#ifdef CONFIG_AU1000_SERIAL_CONSOLE
+	if ((argptr = strstr(argptr, "console=")) == NULL) {
+		argptr = prom_getcmdline();
+		strcat(argptr, " console=ttyS0,115200");
+	}
+#endif
+
+#ifdef CONFIG_SOUND_AU1000
+	strcat(argptr, " au1000_audio=vra");
+	argptr = prom_getcmdline();
+#endif
+
+	_machine_restart = au1000_restart;
+	_machine_halt = au1000_halt;
+	_machine_power_off = au1000_power_off;
+
+	// IO/MEM resources.
+	set_io_port_base(0);
+	ioport_resource.start = 0x10000000;
+	ioport_resource.end = 0xffffffff;
+	iomem_resource.start = 0x10000000;
+	iomem_resource.end = 0xffffffff;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+	initrd_start = (unsigned long)&__rd_start;
+	initrd_end = (unsigned long)&__rd_end;
+#endif
+
+	// set AUX clock to 12MHz * 8 = 96 MHz
+	au_writel(8, SYS_AUXPLL);
+	au_writel(0, SYS_PININPUTEN);
+	udelay(100);
+
+#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1000_USB_DEVICE)
+#ifdef CONFIG_USB_OHCI
+	if ((argptr = strstr(argptr, "usb_ohci=")) == NULL) {
+	        char usb_args[80];
+		argptr = prom_getcmdline();
+		memset(usb_args, 0, sizeof(usb_args));
+		sprintf(usb_args, " usb_ohci=base:0x%x,len:0x%x,irq:%d",
+			USB_OHCI_BASE, USB_OHCI_LEN, AU1000_USB_HOST_INT);
+		strcat(argptr, usb_args);
+	}
+#endif
+	// configure pins GPIO[14:9] as GPIO
+	pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x80);
+
+	/* zero and disable FREQ2 */
+	sys_freqctrl = au_readl(SYS_FREQCTRL0);
+	sys_freqctrl &= ~0xFFF00000;
+	au_writel(sys_freqctrl, SYS_FREQCTRL0);
+
+	/* zero and disable USBH/USBD/IrDA clock */
+	sys_clksrc = au_readl(SYS_CLKSRC);
+	sys_clksrc &= ~0x0000001F;
+	au_writel(sys_clksrc, SYS_CLKSRC);
+
+	sys_freqctrl = au_readl(SYS_FREQCTRL0);
+	sys_freqctrl &= ~0xFFF00000;
+
+	sys_clksrc = au_readl(SYS_CLKSRC);
+	sys_clksrc &= ~0x0000001F;
+
+	// FREQ2 = aux/2 = 48 MHz
+	sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20));
+	au_writel(sys_freqctrl, SYS_FREQCTRL0);
+
+	/*
+	 * Route 48MHz FREQ2 into USBH/USBD/IrDA
+	 */
+	sys_clksrc |= ((4<<2) | (0<<1) | 0 );
+	au_writel(sys_clksrc, SYS_CLKSRC);
+
+	/* setup the static bus controller */
+	au_writel(0x00000002, MEM_STCFG3);  /* type = PCMCIA */
+	au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */
+	au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */
+
+	// get USB Functionality pin state (device vs host drive pins)
+	pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
+#ifndef CONFIG_AU1000_USB_DEVICE
+	// 2nd USB port is USB host
+	pin_func |= 0x8000;
+#endif
+	au_writel(pin_func, SYS_PINFUNC);
+#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1000_USB_DEVICE)
+
+#ifdef CONFIG_USB_OHCI
+	// enable host controller and wait for reset done
+	au_writel(0x08, USB_HOST_CONFIG);
+	udelay(1000);
+	au_writel(0x0c, USB_HOST_CONFIG);
+	udelay(1000);
+	au_readl(USB_HOST_CONFIG);
+	while (!(au_readl(USB_HOST_CONFIG) & 0x10))
+	    ;
+	au_readl(USB_HOST_CONFIG);
+#endif
+
+#ifdef CONFIG_FB
+	conswitchp = &dummy_con;
+#endif
+
+#ifdef CONFIG_FB_AU1100
+	if ((argptr = strstr(argptr, "video=")) == NULL) {
+		argptr = prom_getcmdline();
+		/* default panel */
+		strcat(argptr, " video=au1100fb:panel:Sharp_320x240_16");
+	}
+#endif
+
+#ifdef CONFIG_FB_E1356
+	if ((argptr = strstr(argptr, "video=")) == NULL) {
+		argptr = prom_getcmdline();
+		strcat(argptr, " video=e1356fb:system:pb1500");
+	}
+#endif
+
+#ifndef CONFIG_SERIAL_NONSTANDARD
+	/* don't touch the default serial console */
+	au_writel(0, UART0_ADDR + UART_CLK);
+#endif
+	au_writel(0, UART1_ADDR + UART_CLK);
+	au_writel(0, UART3_ADDR + UART_CLK);
+
+#ifdef CONFIG_BLK_DEV_IDE
+	ide_ops = &std_ide_ops;
+#endif
+
+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_E0S);
+	au_writel(SYS_CNTRL_E0 | SYS_CNTRL_EN0, SYS_COUNTER_CNTRL);
+	au_sync();
+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S);
+	au_writel(0, SYS_TOYTRIM);
+
+	au_writel(0x00000060, 0xb190003c);
+
+#ifdef CONFIG_RTC
+	rtc_ops = &pb1500_rtc_ops;
+	// Enable the RTC if not already enabled
+	if (!(readb(0xac000028) & 0x20)) {
+		writeb(readb(0xac000028) | 0x20, 0xac000028);
+		au_sync();
+	}
+	// Put the clock in BCD mode
+	if (readb(0xac00002C) & 0x4) { /* reg B */
+		writeb(readb(0xac00002c) & ~0x4, 0xac00002c);
+		au_sync();
+	}
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/pb1500/Makefile linux-2.4.20/arch/mips/au1000/pb1500/Makefile
--- linux-2.4.19/arch/mips/au1000/pb1500/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/pb1500/Makefile	2002-10-29 11:18:48.000000000 +0000
@@ -10,10 +10,7 @@
 # unless it's something special (ie not a .c file).
 #
 
-.S.s:
-	$(CPP) $(CFLAGS) $< -o $*.s
-.S.o:
-	$(CC) $(CFLAGS) -c $< -o $*.o
+USE_STANDARD_AS_RULE := true
 
 O_TARGET := pb1500.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/pb1500/init.c linux-2.4.20/arch/mips/au1000/pb1500/init.c
--- linux-2.4.19/arch/mips/au1000/pb1500/init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/pb1500/init.c	2002-10-29 11:18:39.000000000 +0000
@@ -34,7 +34,6 @@
 #include <linux/bootmem.h>
 #include <asm/addrspace.h>
 #include <asm/bootinfo.h>
-#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -59,7 +58,7 @@
 	prom_envp = envp;
 
 	mips_machgroup = MACH_GROUP_ALCHEMY;
-	mips_machtype = MACH_PB1500;  
+	mips_machtype = MACH_PB1500;
 
 	prom_init_cmdline();
 	memsize_str = prom_getenv("memsize");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/pb1500/pci_fixup.c linux-2.4.20/arch/mips/au1000/pb1500/pci_fixup.c
--- linux-2.4.19/arch/mips/au1000/pb1500/pci_fixup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/pb1500/pci_fixup.c	2002-10-29 11:18:49.000000000 +0000
@@ -42,7 +42,7 @@
 #ifdef 	DEBUG
 #define	DBG(x...)	printk(x)
 #else
-#define	DBG(x...)	
+#define	DBG(x...)
 #endif
 
 static void fixup_resource(int r_num, struct pci_dev *dev) ;
@@ -57,8 +57,8 @@
 {
 	int i;
 	struct pci_dev *dev;
-	
-	virt_io_addr = (unsigned long)ioremap(Au1500_PCI_IO_START, 
+
+	virt_io_addr = (unsigned long)ioremap(Au1500_PCI_IO_START,
 			Au1500_PCI_IO_END - Au1500_PCI_IO_START + 1);
 
 	if (!virt_io_addr) {
@@ -103,7 +103,7 @@
 	return 0;
 }
 
-static void fixup_resource(int r_num, struct pci_dev *dev) 
+static void fixup_resource(int r_num, struct pci_dev *dev)
 {
 	unsigned long start, size, new_start;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/pb1500/pci_ops.c linux-2.4.20/arch/mips/au1000/pb1500/pci_ops.c
--- linux-2.4.19/arch/mips/au1000/pb1500/pci_ops.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/pb1500/pci_ops.c	2002-10-29 11:18:50.000000000 +0000
@@ -46,19 +46,19 @@
 #ifdef 	DEBUG
 #define	DBG(x...)	printk(x)
 #else
-#define	DBG(x...)	
+#define	DBG(x...)
 #endif
 
 /* TBD */
 static struct resource pci_io_resource = {
-	"pci IO space", 
+	"pci IO space",
 	Au1500_PCI_IO_START,
 	Au1500_PCI_IO_END,
 	IORESOURCE_IO
 };
 
 static struct resource pci_mem_resource = {
-	"pci memory space", 
+	"pci memory space",
 	Au1500_PCI_MEM_START,
 	Au1500_PCI_MEM_END,
 	IORESOURCE_MEM
@@ -73,7 +73,7 @@
 };
 
 static unsigned long cfg_addr;
-static int config_access(unsigned char access_type, struct pci_dev *dev, 
+static int config_access(unsigned char access_type, struct pci_dev *dev,
 			 unsigned char where, u32 * data)
 {
 	unsigned char bus = dev->bus->number;
@@ -82,7 +82,7 @@
 	unsigned long config, status;
 	static int first = 1;
 
-	/* 
+	/*
  	 * 7:3 = slot
  	 * 2:0 = function
 	 */
@@ -95,7 +95,7 @@
 	if (first) {
 		first = 0;
 		cfg_addr = ioremap(Au1500_EXT_CFG, 0x10000000);
-		if (!cfg_addr) 
+		if (!cfg_addr)
 			printk (KERN_ERR "PCI unable to ioremap cfg space\n");
 	}
 
@@ -110,13 +110,13 @@
 	}
 #endif
 
-	writel(((0x2000 << 16) | (readl(Au1500_PCI_STATCMD) & 0xffff)),
+	au_writel(((0x2000 << 16) | (au_readl(Au1500_PCI_STATCMD) & 0xffff)),
 			Au1500_PCI_STATCMD);
-	//writel(readl(Au1500_PCI_CFG) & ~PCI_ERROR, Au1500_PCI_CFG);
+	//au_writel(au_readl(Au1500_PCI_CFG) & ~PCI_ERROR, Au1500_PCI_CFG);
 	au_sync_udelay(1);
 
 	/* setup the lower 31 bits of the 36 bit address */
-	config = cfg_addr | 
+	config = cfg_addr |
 		((1<<device)<<11) | (function << 8) | (where & ~0x3);
 
 #if 0
@@ -125,18 +125,18 @@
 #endif
 
 	if (access_type == PCI_ACCESS_WRITE) {
-		writel(*data, config);
+		au_writel(*data, config);
 	} else {
-		*data = readl(config);
+		*data = au_readl(config);
 	}
 	au_sync_udelay(1);
 
-	DBG("config_access: %d bus %d device %d at %x *data %x, conf %x\n", 
+	DBG("config_access: %d bus %d device %d at %x *data %x, conf %x\n",
 			access_type, bus, device, where, *data, config);
 
 	/* check master abort */
-	status = readl(Au1500_PCI_STATCMD);
-	if (status & (1<<29)) { 
+	status = au_readl(Au1500_PCI_STATCMD);
+	if (status & (1<<29)) {
 		*data = 0xffffffff;
 		return -1;
 	} else if ((status >> 28) & 0xf) {
@@ -159,7 +159,7 @@
         if (where & 1) data >>= 8;
         if (where & 2) data >>= 16;
         *val = data & 0xff;
-	return ret; 
+	return ret;
 }
 
 
@@ -171,7 +171,7 @@
 	ret = config_access(PCI_ACCESS_READ, dev, where, &data);
         if (where & 2) data >>= 16;
         *val = data & 0xffff;
-	return ret; 
+	return ret;
 }
 
 static int read_config_dword(struct pci_dev *dev, int where, u32 * val)
@@ -179,14 +179,14 @@
 	int ret;
 
 	ret = config_access(PCI_ACCESS_READ, dev, where, val);
-	return ret; 
+	return ret;
 }
 
 
 static int write_config_byte(struct pci_dev *dev, int where, u8 val)
 {
 	u32 data = 0;
-       
+
 	if (config_access(PCI_ACCESS_READ, dev, where, &data))
 		return -1;
 
@@ -205,11 +205,11 @@
 
 	if (where & 1)
 		return PCIBIOS_BAD_REGISTER_NUMBER;
-       
+
         if (config_access(PCI_ACCESS_READ, dev, where, &data))
 	       return -1;
 
-	data = (data & ~(0xffff << ((where & 3) << 3))) | 
+	data = (data & ~(0xffff << ((where & 3) << 3))) |
 	       (val << ((where & 3) << 3));
 
 	if (config_access(PCI_ACCESS_WRITE, dev, where, &data))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/au1000/pb1500/setup.c linux-2.4.20/arch/mips/au1000/pb1500/setup.c
--- linux-2.4.19/arch/mips/au1000/pb1500/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/au1000/pb1500/setup.c	2002-10-29 11:18:34.000000000 +0000
@@ -71,7 +71,6 @@
 extern struct rtc_ops pb1500_rtc_ops;
 #endif
 
-void (*__wbflush) (void);
 extern char * __init prom_getcmdline(void);
 extern void au1000_restart(char *);
 extern void au1000_halt(void);
@@ -80,17 +79,14 @@
 extern struct resource iomem_resource;
 
 
-void au1500_wbflush(void)
-{
-	__asm__ volatile ("sync");
-}
+void __init bus_error_init(void) { /* nothing */ }
 
 void __init au1500_setup(void)
 {
 	char *argptr;
 	u32 pin_func, static_cfg0;
 	u32 sys_freqctrl, sys_clksrc;
-	
+
 	argptr = prom_getcmdline();
 
 	/* NOTE: The memory map is established by YAMON 2.08+ */
@@ -103,19 +99,18 @@
 		argptr = prom_getcmdline();
 		strcat(argptr, " console=ttyS0,115200");
 	}
-#endif	  
+#endif
 
 #ifdef CONFIG_SOUND_AU1000
 	strcat(argptr, " au1000_audio=vra");
 	argptr = prom_getcmdline();
 #endif
 
-        __wbflush = au1500_wbflush;
 	_machine_restart = au1000_restart;
 	_machine_halt = au1000_halt;
 	_machine_power_off = au1000_power_off;
 
-	// IO/MEM resources. 
+	// IO/MEM resources.
 	set_io_port_base(0);
 	ioport_resource.start = 0x10000000;
 	ioport_resource.end = 0xffffffff;
@@ -129,8 +124,8 @@
 #endif
 
 	// set AUX clock to 12MHz * 8 = 96 MHz
-	writel(8, SYS_AUXPLL);
-	outl(0, SYS_PINSTATERD);
+	au_writel(8, SYS_AUXPLL);
+	au_writel(0, SYS_PINSTATERD);
 	udelay(100);
 
 #if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1000_USB_DEVICE)
@@ -146,24 +141,24 @@
 #endif
 
 	/* zero and disable FREQ2 */
-	sys_freqctrl = readl(SYS_FREQCTRL0);
+	sys_freqctrl = au_readl(SYS_FREQCTRL0);
 	sys_freqctrl &= ~0xFFF00000;
-	writel(sys_freqctrl, SYS_FREQCTRL0);
+	au_writel(sys_freqctrl, SYS_FREQCTRL0);
 
 	/* zero and disable USBH/USBD clocks */
-	sys_clksrc = readl(SYS_CLKSRC);
+	sys_clksrc = au_readl(SYS_CLKSRC);
 	sys_clksrc &= ~0x00007FE0;
-	writel(sys_clksrc, SYS_CLKSRC);
+	au_writel(sys_clksrc, SYS_CLKSRC);
 
-	sys_freqctrl = readl(SYS_FREQCTRL0);
+	sys_freqctrl = au_readl(SYS_FREQCTRL0);
 	sys_freqctrl &= ~0xFFF00000;
 
-	sys_clksrc = readl(SYS_CLKSRC);
+	sys_clksrc = au_readl(SYS_CLKSRC);
 	sys_clksrc &= ~0x00007FE0;
 
 	// FREQ2 = aux/2 = 48 MHz
 	sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20));
-	writel(sys_freqctrl, SYS_FREQCTRL0);
+	au_writel(sys_freqctrl, SYS_FREQCTRL0);
 
 	/*
 	 * Route 48MHz FREQ2 into USB Host and/or Device
@@ -174,30 +169,30 @@
 #ifdef CONFIG_AU1000_USB_DEVICE
 	sys_clksrc |= ((4<<7) | (0<<6) | (0<<5));
 #endif
-	writel(sys_clksrc, SYS_CLKSRC);
+	au_writel(sys_clksrc, SYS_CLKSRC);
 
 
-	pin_func = readl(SYS_PINFUNC) & (u32)(~0x8000);
+	pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
 #ifndef CONFIG_AU1000_USB_DEVICE
 	// 2nd USB port is USB host
 	pin_func |= 0x8000;
 #endif
-	writel(pin_func, SYS_PINFUNC);
+	au_writel(pin_func, SYS_PINFUNC);
 #endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1000_USB_DEVICE)
 
 
 #ifdef CONFIG_USB_OHCI
 	// enable host controller and wait for reset done
-	writel(0x08, USB_HOST_CONFIG);
+	au_writel(0x08, USB_HOST_CONFIG);
 	udelay(1000);
-	writel(0x0c, USB_HOST_CONFIG);
+	au_writel(0x0c, USB_HOST_CONFIG);
 	udelay(1000);
-	readl(USB_HOST_CONFIG);
-	while (!(readl(USB_HOST_CONFIG) & 0x10))
+	au_readl(USB_HOST_CONFIG);
+	while (!(au_readl(USB_HOST_CONFIG) & 0x10))
 	    ;
-	readl(USB_HOST_CONFIG);
+	au_readl(USB_HOST_CONFIG);
 #endif
-	
+
 #ifdef CONFIG_FB
 	conswitchp = &dummy_con;
 #endif
@@ -205,15 +200,20 @@
 #ifdef CONFIG_FB_E1356
 	if ((argptr = strstr(argptr, "video=")) == NULL) {
 		argptr = prom_getcmdline();
-		strcat(argptr, " video=e1356fb:system:pb1500,mmunalign:1");
+		strcat(argptr, " video=e1356fb:system:pb1500");
+	}
+#elif defined (CONFIG_FB_XPERT98)
+	if ((argptr = strstr(argptr, "video=")) == NULL) {
+		argptr = prom_getcmdline();
+		strcat(argptr, " video=atyfb:1024x768-8@70");
 	}
 #endif // CONFIG_FB_E1356
 
 #ifndef CONFIG_SERIAL_NONSTANDARD
 	/* don't touch the default serial console */
-	writel(0, UART0_ADDR + UART_CLK);
+	au_writel(0, UART0_ADDR + UART_CLK);
 #endif
-	writel(0, UART3_ADDR + UART_CLK);
+	au_writel(0, UART3_ADDR + UART_CLK);
 
 #ifdef CONFIG_BLK_DEV_IDE
 	ide_ops = &std_ide_ops;
@@ -221,35 +221,40 @@
 
 #ifdef CONFIG_PCI
 	// Setup PCI bus controller
-	writel(0, Au1500_PCI_CMEM);
-	writel(0x00003fff, Au1500_CFG_BASE);
-	writel(0xf, Au1500_PCI_CFG);
-	writel(0xf0000000, Au1500_PCI_MWMASK_DEV);
-	writel(0, Au1500_PCI_MWBASE_REV_CCL);
-	writel(0x02a00356, Au1500_PCI_STATCMD);
-	writel(0x00003c04, Au1500_PCI_HDRTYPE);	
-	writel(0x00000008, Au1500_PCI_MBAR);
+	au_writel(0, Au1500_PCI_CMEM);
+	au_writel(0x00003fff, Au1500_CFG_BASE);
+#if defined(__MIPSEB__)
+	au_writel(0xf | (2<<6) | (1<<4), Au1500_PCI_CFG);
+#else
+	au_writel(0xf, Au1500_PCI_CFG);
+#endif
+	au_writel(0xf0000000, Au1500_PCI_MWMASK_DEV);
+	au_writel(0, Au1500_PCI_MWBASE_REV_CCL);
+	au_writel(0x02a00356, Au1500_PCI_STATCMD);
+	au_writel(0x00003c04, Au1500_PCI_HDRTYPE);
+	au_writel(0x00000008, Au1500_PCI_MBAR);
 	au_sync();
 #endif
 
-	while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_E0S);
-	writel(SYS_CNTRL_E0 | SYS_CNTRL_EN0, SYS_COUNTER_CNTRL);
+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_E0S);
+	au_writel(SYS_CNTRL_E0 | SYS_CNTRL_EN0, SYS_COUNTER_CNTRL);
 	au_sync();
-	while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S);
-	outl(0, SYS_TOYTRIM);
+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S);
+	au_writel(0, SYS_TOYTRIM);
 
 	/* Enable BCLK switching */
-	writel(0x00000060, 0xb190003c);
+	au_writel(0x00000060, 0xb190003c);
 
 #ifdef CONFIG_RTC
 	rtc_ops = &pb1500_rtc_ops;
-	// Enable the RTC if not already enabled 
-	if (!(readb(0xac000028) & 0x20)) {
-		writeb(readb(0xac000028) | 0x20, 0xac000028);
+	// Enable the RTC if not already enabled
+	if (!(au_readl(0xac000028) & 0x20)) {
+		printk("enabling clock ...\n");
+		au_writel((au_readl(0xac000028) | 0x20), 0xac000028);
 	}
 	// Put the clock in BCD mode
-	if (readb(0xac00002C) & 0x4) { /* reg B */
-		writeb(readb(0xac00002c) & ~0x4, 0xac00002c);
+	if (readl(0xac00002C) & 0x4) { /* reg B */
+		au_writel(au_readl(0xac00002c) & ~0x4, 0xac00002c);
 		au_sync();
 	}
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/boot/Makefile linux-2.4.20/arch/mips/boot/Makefile
--- linux-2.4.19/arch/mips/boot/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/boot/Makefile	2002-10-29 11:18:34.000000000 +0000
@@ -8,8 +8,6 @@
 
 USE_STANDARD_AS_RULE := true
 
-OBJS  = milo.o a.out.o
-
 #
 # Some DECstations need all possible sections of an ECOFF executable
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/boot/addinitrd.c linux-2.4.20/arch/mips/boot/addinitrd.c
--- linux-2.4.19/arch/mips/boot/addinitrd.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/boot/addinitrd.c	2002-10-29 11:18:33.000000000 +0000
@@ -82,7 +82,7 @@
 		die ("open initrd");
 	if (fstat (fd_initrd, &st) < 0)
 		die ("fstat initrd");
-	loadaddr = ((SWAB(esecs[2].s_vaddr) + SWAB(esecs[2].s_size) 
+	loadaddr = ((SWAB(esecs[2].s_vaddr) + SWAB(esecs[2].s_size)
 			+ MIPS_PAGE_SIZE-1) & ~MIPS_PAGE_MASK) - 8;
 	if (loadaddr < (SWAB(esecs[2].s_vaddr) + SWAB(esecs[2].s_size)))
 		loadaddr += MIPS_PAGE_SIZE;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/boot/elf2ecoff.c linux-2.4.20/arch/mips/boot/elf2ecoff.c
--- linux-2.4.19/arch/mips/boot/elf2ecoff.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/boot/elf2ecoff.c	2002-10-29 11:18:40.000000000 +0000
@@ -49,485 +49,106 @@
 /*
  * Some extra ELF definitions
  */
-#define PT_MIPS_REGINFO 0x70000000      /* Register usage information */
+#define PT_MIPS_REGINFO 0x70000000	/* Register usage information */
 
 /* -------------------------------------------------------------------- */
 
 struct sect {
-  unsigned long vaddr;
-  unsigned long len;
+	unsigned long vaddr;
+	unsigned long len;
 };
 
-void combine (struct sect* base, struct sect* new, int pad);
-int phcmp ();
-char *saveRead (int file, off_t offset, off_t len, char *name);
-void copy (int, int, off_t, off_t);
-int translate_syms (int, int, off_t, off_t, off_t, off_t);
-void convert_elf_hdr (Elf32_Ehdr *);
-void convert_elf_phdrs (Elf32_Phdr *, int);
-void convert_elf_shdrs (Elf32_Shdr *, int);
-void convert_ecoff_filehdr(struct filehdr *);
-void convert_ecoff_aouthdr(struct aouthdr *);
-void convert_ecoff_esecs(struct scnhdr *, int);
-extern int errno;
 int *symTypeTable;
 int must_convert_endian = 0;
 int format_bigendian = 0;
 
-int
-main (int argc, char **argv, char **envp)
+static void copy(int out, int in, off_t offset, off_t size)
 {
-  Elf32_Ehdr ex;
-  Elf32_Phdr *ph;
-  Elf32_Shdr *sh;
-  char *shstrtab;
-  int i, pad;
-  struct sect text, data, bss;
-  struct filehdr efh;
-  struct aouthdr eah;
-  struct scnhdr esecs [6];
-  int infile, outfile;
-  unsigned long cur_vma = ULONG_MAX;
-  int addflag = 0;
-  int nosecs;
-
-  text.len = data.len = bss.len = 0;
-  text.vaddr = data.vaddr = bss.vaddr = 0;
-
-  /* Check args... */
-  if (argc < 3 || argc > 4)
-    {
-    usage:
-      fprintf (stderr,
-	       "usage: elf2aout <elf executable> <a.out executable> [-a]\n");
-      exit (1);
-    }
-  if (argc == 4)
-    {
-      if (strcmp (argv [3], "-a"))
-	goto usage;
-      addflag = 1;
-    }
-
-  /* Try the input file... */
-  if ((infile = open (argv [1], O_RDONLY)) < 0)
-    {
-      fprintf (stderr, "Can't open %s for read: %s\n",
-	       argv [1], strerror (errno));
-      exit (1);
-    }
-
-  /* Read the header, which is at the beginning of the file... */
-  i = read (infile, &ex, sizeof ex);
-  if (i != sizeof ex)
-    {
-      fprintf (stderr, "ex: %s: %s.\n",
-	       argv [1], i ? strerror (errno) : "End of file reached");
-      exit (1);
-    }
-
-  if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
-	format_bigendian = 1;
-
-  if (ntohs (0xaa55) == 0xaa55) {
-	if (!format_bigendian)
-		must_convert_endian = 1;
-  } else {
-	if (format_bigendian)
-		must_convert_endian = 1;
-  }
-  if (must_convert_endian)
-	convert_elf_hdr (&ex);
-
-  /* Read the program headers... */
-  ph = (Elf32_Phdr *)saveRead (infile, ex.e_phoff,
-				ex.e_phnum * sizeof (Elf32_Phdr), "ph");
-  if (must_convert_endian)
-	convert_elf_phdrs (ph, ex.e_phnum);
-  /* Read the section headers... */
-  sh = (Elf32_Shdr *)saveRead (infile, ex.e_shoff,
-				ex.e_shnum * sizeof (Elf32_Shdr), "sh");
-  if (must_convert_endian)
-	convert_elf_shdrs (sh, ex.e_shnum);
-  /* Read in the section string table. */
-  shstrtab = saveRead (infile, sh [ex.e_shstrndx].sh_offset,
-		       sh [ex.e_shstrndx].sh_size, "shstrtab");
-
-  /* Figure out if we can cram the program header into an ECOFF
-     header...  Basically, we can't handle anything but loadable
-     segments, but we can ignore some kinds of segments.  We can't
-     handle holes in the address space.  Segments may be out of order,
-     so we sort them first. */
-
-  qsort (ph, ex.e_phnum, sizeof (Elf32_Phdr), phcmp);
-
-  for (i = 0; i < ex.e_phnum; i++)
-    {
-      /* Section types we can ignore... */
-      if (ph [i].p_type == PT_NULL || ph [i].p_type == PT_NOTE ||
-	  ph [i].p_type == PT_PHDR || ph [i].p_type == PT_MIPS_REGINFO)
-	continue;
-      /* Section types we can't handle... */
-      else if (ph [i].p_type != PT_LOAD)
-        {
-	  fprintf (stderr, "Program header %d type %d can't be converted.\n", 
-			  	ex.e_phnum, ph[i].p_type );
-	  exit (1);
-	}
-      /* Writable (data) segment? */
-      if (ph [i].p_flags & PF_W)
-	{
-	  struct sect ndata, nbss;
+	char ibuf[4096];
+	int remaining, cur, count;
 
-	  ndata.vaddr = ph [i].p_vaddr;
-	  ndata.len = ph [i].p_filesz;
-	  nbss.vaddr = ph [i].p_vaddr + ph [i].p_filesz;
-	  nbss.len = ph [i].p_memsz - ph [i].p_filesz;
+	/* Go to the start of the ELF symbol table... */
+	if (lseek(in, offset, SEEK_SET) < 0) {
+		perror("copy: lseek");
+		exit(1);
+	}
+
+	remaining = size;
+	while (remaining) {
+		cur = remaining;
+		if (cur > sizeof(ibuf))
+			cur = sizeof(ibuf);
+		remaining -= cur;
+		if ((count = read(in, ibuf, cur)) != cur) {
+			fprintf(stderr, "copy: read: %s\n",
+				count ? strerror(errno) :
+				"premature end of file");
+			exit(1);
+		}
+		if ((count = write(out, ibuf, cur)) != cur) {
+			perror("copy: write");
+			exit(1);
+		}
+	}
+}
 
-	  combine (&data, &ndata, 0);
-	  combine (&bss, &nbss, 1);
+/*
+ * Combine two segments, which must be contiguous.   If pad is true, it's
+ * okay for there to be padding between.
+ */
+static void combine(struct sect *base, struct sect *new, int pad)
+{
+	if (!base->len)
+		*base = *new;
+	else if (new->len) {
+		if (base->vaddr + base->len != new->vaddr) {
+			if (pad)
+				base->len = new->vaddr - base->vaddr;
+			else {
+				fprintf(stderr,
+					"Non-contiguous data can't be converted.\n");
+				exit(1);
+			}
+		}
+		base->len += new->len;
 	}
-      else
-	{
-	  struct sect ntxt;
+}
 
-	  ntxt.vaddr = ph [i].p_vaddr;
-	  ntxt.len = ph [i].p_filesz;
+static int phcmp(const void *v1, const void *v2)
+{
+	const Elf32_Phdr *h1 = v1;
+	const Elf32_Phdr *h2 = v2;
 
-	  combine (&text, &ntxt, 0);
-	}
-      /* Remember the lowest segment start address. */
-      if (ph [i].p_vaddr < cur_vma)
-	cur_vma = ph [i].p_vaddr;
-    }
-
-  /* Sections must be in order to be converted... */
-  if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
-      text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr)
-    {
-      fprintf (stderr, "Sections ordering prevents a.out conversion.\n");
-      exit (1);
-    }
-
-  /* If there's a data section but no text section, then the loader
-     combined everything into one section.   That needs to be the
-     text section, so just make the data section zero length following
-     text. */
-  if (data.len && !text.len)
-    {
-      text = data;
-      data.vaddr = text.vaddr + text.len;
-      data.len = 0;
-    }
-
-  /* If there is a gap between text and data, we'll fill it when we copy
-     the data, so update the length of the text segment as represented in
-     a.out to reflect that, since a.out doesn't allow gaps in the program
-     address space. */
-  if (text.vaddr + text.len < data.vaddr)
-    text.len = data.vaddr - text.vaddr;
-
-  /* We now have enough information to cons up an a.out header... */
-  eah.magic = OMAGIC;
-  eah.vstamp = 200;
-  eah.tsize = text.len;
-  eah.dsize = data.len;
-  eah.bsize = bss.len;
-  eah.entry = ex.e_entry;
-  eah.text_start = text.vaddr;
-  eah.data_start = data.vaddr;
-  eah.bss_start = bss.vaddr;
-  eah.gprmask = 0xf3fffffe;
-  memset (&eah.cprmask, '\0', sizeof eah.cprmask);
-  eah.gp_value = 0; /* unused. */
-
-  if (format_bigendian)
-    efh.f_magic = MIPSEBMAGIC;
-  else
-    efh.f_magic = MIPSELMAGIC;
-  if (addflag)
-    nosecs = 6;
-  else
-    nosecs = 3;
-  efh.f_nscns = nosecs;
-  efh.f_timdat = 0;	/* bogus */
-  efh.f_symptr = 0;
-  efh.f_nsyms = 0;
-  efh.f_opthdr = sizeof eah;
-  efh.f_flags = 0x100f; /* Stripped, not sharable. */
-
-  memset (esecs, 0, sizeof esecs);
-  strcpy (esecs [0].s_name, ".text");
-  strcpy (esecs [1].s_name, ".data");
-  strcpy (esecs [2].s_name, ".bss");
-  if (addflag) {
-    strcpy (esecs [3].s_name, ".rdata");
-    strcpy (esecs [4].s_name, ".sdata");
-    strcpy (esecs [5].s_name, ".sbss");
-  }
-  esecs [0].s_paddr = esecs [0].s_vaddr = eah.text_start;
-  esecs [1].s_paddr = esecs [1].s_vaddr = eah.data_start;
-  esecs [2].s_paddr = esecs [2].s_vaddr = eah.bss_start;
-  if (addflag) {
-    esecs [3].s_paddr = esecs [3].s_vaddr = 0;
-    esecs [4].s_paddr = esecs [4].s_vaddr = 0;
-    esecs [5].s_paddr = esecs [5].s_vaddr = 0;
-  }
-  esecs [0].s_size = eah.tsize;
-  esecs [1].s_size = eah.dsize;
-  esecs [2].s_size = eah.bsize;
-  if (addflag) {
-    esecs [3].s_size = 0;
-    esecs [4].s_size = 0;
-    esecs [5].s_size = 0;
-  }
-  esecs [0].s_scnptr = N_TXTOFF (efh, eah);
-  esecs [1].s_scnptr = N_DATOFF (efh, eah);
-#define ECOFF_SEGMENT_ALIGNMENT(a) 0x10
-#define ECOFF_ROUND(s,a) (((s)+(a)-1)&~((a)-1))
-  esecs [2].s_scnptr = esecs [1].s_scnptr +
-	  ECOFF_ROUND (esecs [1].s_size, ECOFF_SEGMENT_ALIGNMENT (&eah));
-  if (addflag) {
-    esecs [3].s_scnptr = 0;
-    esecs [4].s_scnptr = 0;
-    esecs [5].s_scnptr = 0;
-  }
-  esecs [0].s_relptr = esecs [1].s_relptr
-	  = esecs [2].s_relptr = 0;
-  esecs [0].s_lnnoptr = esecs [1].s_lnnoptr
-	  = esecs [2].s_lnnoptr = 0;
-  esecs [0].s_nreloc = esecs [1].s_nreloc = esecs [2].s_nreloc = 0;
-  esecs [0].s_nlnno = esecs [1].s_nlnno = esecs [2].s_nlnno = 0;
-  if (addflag) {
-    esecs [3].s_relptr = esecs [4].s_relptr 
-  	  = esecs [5].s_relptr = 0;
-    esecs [3].s_lnnoptr = esecs [4].s_lnnoptr
-	  = esecs [5].s_lnnoptr = 0;
-    esecs [3].s_nreloc = esecs [4].s_nreloc = esecs [5].s_nreloc = 0;
-    esecs [3].s_nlnno = esecs [4].s_nlnno = esecs [5].s_nlnno = 0;
-  }
-  esecs [0].s_flags = 0x20;
-  esecs [1].s_flags = 0x40;
-  esecs [2].s_flags = 0x82;
-  if (addflag) {
-    esecs [3].s_flags = 0x100;
-    esecs [4].s_flags = 0x200;
-    esecs [5].s_flags = 0x400;
-  }
-
-  /* Make the output file... */
-  if ((outfile = open (argv [2], O_WRONLY | O_CREAT, 0777)) < 0)
-    {
-      fprintf (stderr, "Unable to create %s: %s\n", argv [2], strerror (errno));
-      exit (1);
-    }
-
-  if (must_convert_endian)
-	convert_ecoff_filehdr (&efh);
-  /* Write the headers... */
-  i = write (outfile, &efh, sizeof efh);
-  if (i != sizeof efh)
-    {
-      perror ("efh: write");
-      exit (1);
-
-    for (i = 0; i < nosecs; i++)
-      {
-        printf ("Section %d: %s phys %lx  size %lx  file offset %lx\n", 
-	      i, esecs [i].s_name, esecs [i].s_paddr,
-	      esecs [i].s_size, esecs [i].s_scnptr);
-      }
-    }
-  fprintf (stderr, "wrote %d byte file header.\n", i);
-
-  if (must_convert_endian)
-	convert_ecoff_aouthdr (&eah);
-  i = write (outfile, &eah, sizeof eah);
-  if (i != sizeof eah)
-    {
-      perror ("eah: write");
-      exit (1);
-    }
-  fprintf (stderr, "wrote %d byte a.out header.\n", i);
-
-  if (must_convert_endian)
-	convert_ecoff_esecs (&esecs[0], nosecs);
-  i = write (outfile, &esecs, nosecs * sizeof(struct scnhdr));
-  if (i != nosecs * sizeof(struct scnhdr))
-    {
-      perror ("esecs: write");
-      exit (1);
-    }
-  fprintf (stderr, "wrote %d bytes of section headers.\n", i);
-
-  if (pad = ((sizeof efh + sizeof eah + nosecs * sizeof(struct scnhdr)) & 15))
-    {
-      pad = 16 - pad;
-      i = write (outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
-      if (i < 0)
-	{
-	  perror ("ipad: write");
-	  exit (1);
-	}
-      fprintf (stderr, "wrote %d byte pad.\n", i);
-    }
+	if (h1->p_vaddr > h2->p_vaddr)
+		return 1;
+	else if (h1->p_vaddr < h2->p_vaddr)
+		return -1;
+	else
+		return 0;
+}
 
-  /* Copy the loadable sections.   Zero-fill any gaps less than 64k;
-     complain about any zero-filling, and die if we're asked to zero-fill
-     more than 64k. */
-  for (i = 0; i < ex.e_phnum; i++)
-    {
-      /* Unprocessable sections were handled above, so just verify that
-	 the section can be loaded before copying. */
-      if (ph [i].p_type == PT_LOAD && ph [i].p_filesz)
-	{
-	  if (cur_vma != ph [i].p_vaddr)
-	    {
-	      unsigned long gap = ph [i].p_vaddr - cur_vma;
-	      char obuf [1024];
-	      if (gap > 65536)
-		{
-		  fprintf (stderr, "Intersegment gap (%ld bytes) too large.\n",
-			   gap);
-		  exit (1);
-		}
-	      fprintf (stderr, "Warning: %ld byte intersegment gap.\n", gap);
-	      memset (obuf, 0, sizeof obuf);
-	      while (gap)
-		{
-		  int count = write (outfile, obuf, (gap > sizeof obuf
-						     ? sizeof obuf : gap));
-		  if (count < 0)
-		    {
-		      fprintf (stderr, "Error writing gap: %s\n",
-			       strerror (errno));
-		      exit (1);
-		    }
-		  gap -= count;
-		}
-	    }
-fprintf (stderr, "writing %d bytes...\n", ph [i].p_filesz);
-	  copy (outfile, infile, ph [i].p_offset, ph [i].p_filesz);
-	  cur_vma = ph [i].p_vaddr + ph [i].p_filesz;
-	}
-    }
-
-   /*
-     * Write a page of padding for boot PROMS that read entire pages.
-     * Without this, they may attempt to read past the end of the
-     * data section, incur an error, and refuse to boot.
-     */
-    {
-	char obuf[4096];
-	memset(obuf, 0, sizeof obuf);
-	if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
-	    fprintf(stderr, "Error writing PROM padding: %s\n",
-		    strerror(errno));
-	    exit(1);
-	}
-    }
-
-  /* Looks like we won... */
-  exit (0);
-}
-
-void
-copy (out, in, offset, size)
-     int out, in;
-     off_t offset, size;
-{
-  char ibuf [4096];
-  int remaining, cur, count;
-
-  /* Go to the start of the ELF symbol table... */
-  if (lseek (in, offset, SEEK_SET) < 0)
-    {
-      perror ("copy: lseek");
-      exit (1);
-    }
-
-  remaining = size;
-  while (remaining)
-    {
-      cur = remaining;
-      if (cur > sizeof ibuf)
-	cur = sizeof ibuf;
-      remaining -= cur;
-      if ((count = read (in, ibuf, cur)) != cur)
-	{
-	  fprintf (stderr, "copy: read: %s\n",
-		   count ? strerror (errno) : "premature end of file");
-	  exit (1);
+static char *saveRead(int file, off_t offset, off_t len, char *name)
+{
+	char *tmp;
+	int count;
+	off_t off;
+	if ((off = lseek(file, offset, SEEK_SET)) < 0) {
+		fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
+		exit(1);
 	}
-      if ((count = write (out, ibuf, cur)) != cur)
-	{
-	  perror ("copy: write");
-	  exit (1);
+	if (!(tmp = (char *) malloc(len))) {
+		fprintf(stderr, "%s: Can't allocate %ld bytes.\n", name,
+			len);
+		exit(1);
 	}
-    }
-}
-
-/* Combine two segments, which must be contiguous.   If pad is true, it's
-   okay for there to be padding between. */
-void
-combine (base, new, pad)
-     struct sect *base, *new;
-     int pad;
-{
-  if (!base -> len)
-    *base = *new;
-  else if (new -> len)
-    {
-      if (base -> vaddr + base -> len != new -> vaddr)
-	{
-	  if (pad)
-	    base -> len = new -> vaddr - base -> vaddr;
-	  else
-	    {
-	      fprintf (stderr,
-		       "Non-contiguous data can't be converted.\n");
-	      exit (1);
-	    }
-	}
-      base -> len += new -> len;
-    }
-}
-
-int
-phcmp (h1, h2)
-     Elf32_Phdr *h1, *h2;
-{
-  if (h1 -> p_vaddr > h2 -> p_vaddr)
-    return 1;
-  else if (h1 -> p_vaddr < h2 -> p_vaddr)
-    return -1;
-  else
-    return 0;
-}
-
-char *saveRead (int file, off_t offset, off_t len, char *name)
-{
-  char *tmp;
-  int count;
-  off_t off;
-  if ((off = lseek (file, offset, SEEK_SET)) < 0)
-    {
-      fprintf (stderr, "%s: fseek: %s\n", name, strerror (errno));
-      exit (1);
-    }
-  if (!(tmp = (char *)malloc (len)))
-    {
-      fprintf (stderr, "%s: Can't allocate %ld bytes.\n", name, len);
-      exit (1);
-    }
-  count = read (file, tmp, len);
-  if (count != len)
-    {
-      fprintf (stderr, "%s: read: %s.\n",
-	       name, count ? strerror (errno) : "End of file reached");
-      exit (1);
-    }
-  return tmp;
+	count = read(file, tmp, len);
+	if (count != len) {
+		fprintf(stderr, "%s: read: %s.\n",
+			name,
+			count ? strerror(errno) : "End of file reached");
+		exit(1);
+	}
+	return tmp;
 }
 
 #define swab16(x) \
@@ -542,101 +163,450 @@
 		(((unsigned int)(x) & (unsigned int)0x00ff0000UL) >>  8) | \
 		(((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) ))
 
-void convert_elf_hdr (Elf32_Ehdr *e)
+static void convert_elf_hdr(Elf32_Ehdr * e)
 {
-	e->e_type      = swab16(e->e_type);
-	e->e_machine   = swab16(e->e_machine);
-	e->e_version   = swab32(e->e_version);
-	e->e_entry     = swab32(e->e_entry);
-	e->e_phoff     = swab32(e->e_phoff);
-	e->e_shoff     = swab32(e->e_shoff);
-	e->e_flags     = swab32(e->e_flags);
-	e->e_ehsize    = swab16(e->e_ehsize);
+	e->e_type = swab16(e->e_type);
+	e->e_machine = swab16(e->e_machine);
+	e->e_version = swab32(e->e_version);
+	e->e_entry = swab32(e->e_entry);
+	e->e_phoff = swab32(e->e_phoff);
+	e->e_shoff = swab32(e->e_shoff);
+	e->e_flags = swab32(e->e_flags);
+	e->e_ehsize = swab16(e->e_ehsize);
 	e->e_phentsize = swab16(e->e_phentsize);
-	e->e_phnum     = swab16(e->e_phnum);
+	e->e_phnum = swab16(e->e_phnum);
 	e->e_shentsize = swab16(e->e_shentsize);
-	e->e_shnum     = swab16(e->e_shnum);
-	e->e_shstrndx  = swab16(e->e_shstrndx);
+	e->e_shnum = swab16(e->e_shnum);
+	e->e_shstrndx = swab16(e->e_shstrndx);
 }
 
-void convert_elf_phdrs (Elf32_Phdr *p, int num)
+static void convert_elf_phdrs(Elf32_Phdr * p, int num)
 {
 	int i;
 
-	for (i = 0; i < num; i++,p++) {
-		p->p_type   = swab32(p->p_type);
+	for (i = 0; i < num; i++, p++) {
+		p->p_type = swab32(p->p_type);
 		p->p_offset = swab32(p->p_offset);
-		p->p_vaddr  = swab32(p->p_vaddr);
-		p->p_paddr  = swab32(p->p_paddr);
+		p->p_vaddr = swab32(p->p_vaddr);
+		p->p_paddr = swab32(p->p_paddr);
 		p->p_filesz = swab32(p->p_filesz);
-		p->p_memsz  = swab32(p->p_memsz);
-		p->p_flags  = swab32(p->p_flags);
-		p->p_align  = swab32(p->p_align);
+		p->p_memsz = swab32(p->p_memsz);
+		p->p_flags = swab32(p->p_flags);
+		p->p_align = swab32(p->p_align);
 	}
 
 }
 
-void convert_elf_shdrs (Elf32_Shdr *s, int num)
+static void convert_elf_shdrs(Elf32_Shdr * s, int num)
 {
 	int i;
 
-	for (i = 0; i < num; i++,s++) {
-		s->sh_name      = swab32(s->sh_name);
-		s->sh_type      = swab32(s->sh_type);
-		s->sh_flags     = swab32(s->sh_flags);
-		s->sh_addr      = swab32(s->sh_addr);
-		s->sh_offset    = swab32(s->sh_offset);
-		s->sh_size      = swab32(s->sh_size);
-		s->sh_link      = swab32(s->sh_link);
-		s->sh_info      = swab32(s->sh_info);
+	for (i = 0; i < num; i++, s++) {
+		s->sh_name = swab32(s->sh_name);
+		s->sh_type = swab32(s->sh_type);
+		s->sh_flags = swab32(s->sh_flags);
+		s->sh_addr = swab32(s->sh_addr);
+		s->sh_offset = swab32(s->sh_offset);
+		s->sh_size = swab32(s->sh_size);
+		s->sh_link = swab32(s->sh_link);
+		s->sh_info = swab32(s->sh_info);
 		s->sh_addralign = swab32(s->sh_addralign);
-		s->sh_entsize   = swab32(s->sh_entsize);
+		s->sh_entsize = swab32(s->sh_entsize);
 	}
 }
 
-void convert_ecoff_filehdr(struct filehdr *f)
+static void convert_ecoff_filehdr(struct filehdr *f)
 {
-	f->f_magic  = swab16(f->f_magic);
-	f->f_nscns  = swab16(f->f_nscns);
+	f->f_magic = swab16(f->f_magic);
+	f->f_nscns = swab16(f->f_nscns);
 	f->f_timdat = swab32(f->f_timdat);
 	f->f_symptr = swab32(f->f_symptr);
-	f->f_nsyms  = swab32(f->f_nsyms);
+	f->f_nsyms = swab32(f->f_nsyms);
 	f->f_opthdr = swab16(f->f_opthdr);
-	f->f_flags  = swab16(f->f_flags);
+	f->f_flags = swab16(f->f_flags);
 }
 
-void convert_ecoff_aouthdr(struct aouthdr *a)
+static void convert_ecoff_aouthdr(struct aouthdr *a)
 {
-	a->magic      = swab16(a->magic);
-	a->vstamp     = swab16(a->vstamp);
-	a->tsize      = swab32(a->tsize);
-	a->dsize      = swab32(a->dsize);
-	a->bsize      = swab32(a->bsize);
-	a->entry      = swab32(a->entry);
+	a->magic = swab16(a->magic);
+	a->vstamp = swab16(a->vstamp);
+	a->tsize = swab32(a->tsize);
+	a->dsize = swab32(a->dsize);
+	a->bsize = swab32(a->bsize);
+	a->entry = swab32(a->entry);
 	a->text_start = swab32(a->text_start);
 	a->data_start = swab32(a->data_start);
-	a->bss_start  = swab32(a->bss_start);
-	a->gprmask    = swab32(a->gprmask);
+	a->bss_start = swab32(a->bss_start);
+	a->gprmask = swab32(a->gprmask);
 	a->cprmask[0] = swab32(a->cprmask[0]);
 	a->cprmask[1] = swab32(a->cprmask[1]);
 	a->cprmask[2] = swab32(a->cprmask[2]);
 	a->cprmask[3] = swab32(a->cprmask[3]);
-	a->gp_value   = swab32(a->gp_value);
+	a->gp_value = swab32(a->gp_value);
 }
 
-void convert_ecoff_esecs(struct scnhdr *s, int num)
+static void convert_ecoff_esecs(struct scnhdr *s, int num)
 {
 	int i;
 
 	for (i = 0; i < num; i++, s++) {
-		s->s_paddr   = swab32(s->s_paddr);
-		s->s_vaddr   = swab32(s->s_vaddr);
-		s->s_size    = swab32(s->s_size);
-		s->s_scnptr  = swab32(s->s_scnptr);
-		s->s_relptr  = swab32(s->s_relptr);
+		s->s_paddr = swab32(s->s_paddr);
+		s->s_vaddr = swab32(s->s_vaddr);
+		s->s_size = swab32(s->s_size);
+		s->s_scnptr = swab32(s->s_scnptr);
+		s->s_relptr = swab32(s->s_relptr);
 		s->s_lnnoptr = swab32(s->s_lnnoptr);
-		s->s_nreloc  = swab16(s->s_nreloc);
-		s->s_nlnno   = swab16(s->s_nlnno);
-		s->s_flags   = swab32(s->s_flags);
+		s->s_nreloc = swab16(s->s_nreloc);
+		s->s_nlnno = swab16(s->s_nlnno);
+		s->s_flags = swab32(s->s_flags);
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	Elf32_Ehdr ex;
+	Elf32_Phdr *ph;
+	Elf32_Shdr *sh;
+	char *shstrtab;
+	int i, pad;
+	struct sect text, data, bss;
+	struct filehdr efh;
+	struct aouthdr eah;
+	struct scnhdr esecs[6];
+	int infile, outfile;
+	unsigned long cur_vma = ULONG_MAX;
+	int addflag = 0;
+	int nosecs;
+
+	text.len = data.len = bss.len = 0;
+	text.vaddr = data.vaddr = bss.vaddr = 0;
+
+	/* Check args... */
+	if (argc < 3 || argc > 4) {
+	      usage:
+		fprintf(stderr,
+			"usage: elf2aout <elf executable> <a.out executable> [-a]\n");
+		exit(1);
+	}
+	if (argc == 4) {
+		if (strcmp(argv[3], "-a"))
+			goto usage;
+		addflag = 1;
+	}
+
+	/* Try the input file... */
+	if ((infile = open(argv[1], O_RDONLY)) < 0) {
+		fprintf(stderr, "Can't open %s for read: %s\n",
+			argv[1], strerror(errno));
+		exit(1);
+	}
+
+	/* Read the header, which is at the beginning of the file... */
+	i = read(infile, &ex, sizeof(ex));
+	if (i != sizeof(ex)) {
+		fprintf(stderr, "ex: %s: %s.\n", argv[1],
+			i ? strerror(errno) : "End of file reached");
+		exit(1);
+	}
+
+	if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
+		format_bigendian = 1;
+
+	if (ntohs(0xaa55) == 0xaa55) {
+		if (!format_bigendian)
+			must_convert_endian = 1;
+	} else {
+		if (format_bigendian)
+			must_convert_endian = 1;
+	}
+	if (must_convert_endian)
+		convert_elf_hdr(&ex);
+
+	/* Read the program headers... */
+	ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
+				     ex.e_phnum * sizeof(Elf32_Phdr), "ph");
+	if (must_convert_endian)
+		convert_elf_phdrs(ph, ex.e_phnum);
+	/* Read the section headers... */
+	sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
+				     ex.e_shnum * sizeof(Elf32_Shdr),
+				     "sh");
+	if (must_convert_endian)
+		convert_elf_shdrs(sh, ex.e_shnum);
+	/* Read in the section string table. */
+	shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
+			    sh[ex.e_shstrndx].sh_size, "shstrtab");
+
+	/* Figure out if we can cram the program header into an ECOFF
+	   header...  Basically, we can't handle anything but loadable
+	   segments, but we can ignore some kinds of segments.  We can't
+	   handle holes in the address space.  Segments may be out of order,
+	   so we sort them first. */
+
+	qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
+
+	for (i = 0; i < ex.e_phnum; i++) {
+		/* Section types we can ignore... */
+		if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE ||
+		    ph[i].p_type == PT_PHDR
+		    || ph[i].p_type == PT_MIPS_REGINFO)
+			continue;
+		/* Section types we can't handle... */
+		else if (ph[i].p_type != PT_LOAD) {
+			fprintf(stderr,
+				"Program header %d type %d can't be converted.\n",
+				ex.e_phnum, ph[i].p_type);
+			exit(1);
+		}
+		/* Writable (data) segment? */
+		if (ph[i].p_flags & PF_W) {
+			struct sect ndata, nbss;
+
+			ndata.vaddr = ph[i].p_vaddr;
+			ndata.len = ph[i].p_filesz;
+			nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
+			nbss.len = ph[i].p_memsz - ph[i].p_filesz;
+
+			combine(&data, &ndata, 0);
+			combine(&bss, &nbss, 1);
+		} else {
+			struct sect ntxt;
+
+			ntxt.vaddr = ph[i].p_vaddr;
+			ntxt.len = ph[i].p_filesz;
+
+			combine(&text, &ntxt, 0);
+		}
+		/* Remember the lowest segment start address. */
+		if (ph[i].p_vaddr < cur_vma)
+			cur_vma = ph[i].p_vaddr;
+	}
+
+	/* Sections must be in order to be converted... */
+	if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
+	    text.vaddr + text.len > data.vaddr
+	    || data.vaddr + data.len > bss.vaddr) {
+		fprintf(stderr,
+			"Sections ordering prevents a.out conversion.\n");
+		exit(1);
+	}
+
+	/*
+	 * If there's a data section but no text section, then the loader
+	 * combined everything into one section.   That needs to be the text
+	 * section, so just make the data section zero length following text.
+	 */
+	if (data.len && !text.len) {
+		text = data;
+		data.vaddr = text.vaddr + text.len;
+		data.len = 0;
+	}
+
+	/*
+	 * If there is a gap between text and data, we'll fill it when we copy
+	 * the data, so update the length of the text segment as represented in
+	 * a.out to reflect that, since a.out doesn't allow gaps in the program
+	 * address space.
+	 */
+	if (text.vaddr + text.len < data.vaddr)
+		text.len = data.vaddr - text.vaddr;
+
+	/* We now have enough information to cons up an a.out header... */
+	eah.magic = OMAGIC;
+	eah.vstamp = 200;
+	eah.tsize = text.len;
+	eah.dsize = data.len;
+	eah.bsize = bss.len;
+	eah.entry = ex.e_entry;
+	eah.text_start = text.vaddr;
+	eah.data_start = data.vaddr;
+	eah.bss_start = bss.vaddr;
+	eah.gprmask = 0xf3fffffe;
+	memset(&eah.cprmask, '\0', sizeof(eah.cprmask));
+	eah.gp_value = 0;	/* unused. */
+
+	if (format_bigendian)
+		efh.f_magic = MIPSEBMAGIC;
+	else
+		efh.f_magic = MIPSELMAGIC;
+	if (addflag)
+		nosecs = 6;
+	else
+		nosecs = 3;
+	efh.f_nscns = nosecs;
+	efh.f_timdat = 0;	/* bogus */
+	efh.f_symptr = 0;
+	efh.f_nsyms = 0;
+	efh.f_opthdr = sizeof(eah);
+	efh.f_flags = 0x100f;	/* Stripped, not sharable. */
+
+	memset(esecs, 0, sizeof(esecs));
+	strcpy(esecs[0].s_name, ".text");
+	strcpy(esecs[1].s_name, ".data");
+	strcpy(esecs[2].s_name, ".bss");
+	if (addflag) {
+		strcpy(esecs[3].s_name, ".rdata");
+		strcpy(esecs[4].s_name, ".sdata");
+		strcpy(esecs[5].s_name, ".sbss");
+	}
+	esecs[0].s_paddr = esecs[0].s_vaddr = eah.text_start;
+	esecs[1].s_paddr = esecs[1].s_vaddr = eah.data_start;
+	esecs[2].s_paddr = esecs[2].s_vaddr = eah.bss_start;
+	if (addflag) {
+		esecs[3].s_paddr = esecs[3].s_vaddr = 0;
+		esecs[4].s_paddr = esecs[4].s_vaddr = 0;
+		esecs[5].s_paddr = esecs[5].s_vaddr = 0;
+	}
+	esecs[0].s_size = eah.tsize;
+	esecs[1].s_size = eah.dsize;
+	esecs[2].s_size = eah.bsize;
+	if (addflag) {
+		esecs[3].s_size = 0;
+		esecs[4].s_size = 0;
+		esecs[5].s_size = 0;
 	}
+	esecs[0].s_scnptr = N_TXTOFF(efh, eah);
+	esecs[1].s_scnptr = N_DATOFF(efh, eah);
+#define ECOFF_SEGMENT_ALIGNMENT(a) 0x10
+#define ECOFF_ROUND(s,a) (((s)+(a)-1)&~((a)-1))
+	esecs[2].s_scnptr = esecs[1].s_scnptr +
+	    ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eah));
+	if (addflag) {
+		esecs[3].s_scnptr = 0;
+		esecs[4].s_scnptr = 0;
+		esecs[5].s_scnptr = 0;
+	}
+	esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
+	esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
+	esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
+	esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
+	if (addflag) {
+		esecs[3].s_relptr = esecs[4].s_relptr
+		    = esecs[5].s_relptr = 0;
+		esecs[3].s_lnnoptr = esecs[4].s_lnnoptr
+		    = esecs[5].s_lnnoptr = 0;
+		esecs[3].s_nreloc = esecs[4].s_nreloc = esecs[5].s_nreloc =
+		    0;
+		esecs[3].s_nlnno = esecs[4].s_nlnno = esecs[5].s_nlnno = 0;
+	}
+	esecs[0].s_flags = 0x20;
+	esecs[1].s_flags = 0x40;
+	esecs[2].s_flags = 0x82;
+	if (addflag) {
+		esecs[3].s_flags = 0x100;
+		esecs[4].s_flags = 0x200;
+		esecs[5].s_flags = 0x400;
+	}
+
+	/* Make the output file... */
+	if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
+		fprintf(stderr, "Unable to create %s: %s\n", argv[2],
+			strerror(errno));
+		exit(1);
+	}
+
+	if (must_convert_endian)
+		convert_ecoff_filehdr(&efh);
+	/* Write the headers... */
+	i = write(outfile, &efh, sizeof(efh));
+	if (i != sizeof efh) {
+		perror("efh: write");
+		exit(1);
+	}
+
+	for (i = 0; i < nosecs; i++) {
+		printf("Section %d: %s phys %lx  size %lx  file offset %lx\n",
+		       i, esecs[i].s_name, esecs[i].s_paddr,
+		       esecs[i].s_size, esecs[i].s_scnptr);
+	}
+	fprintf(stderr, "wrote %d byte file header.\n", i);
+
+	if (must_convert_endian)
+		convert_ecoff_aouthdr(&eah);
+	i = write(outfile, &eah, sizeof(eah));
+	if (i != sizeof(eah)) {
+		perror("eah: write");
+		exit(1);
+	}
+	fprintf(stderr, "wrote %d byte a.out header.\n", i);
+
+	if (must_convert_endian)
+		convert_ecoff_esecs(&esecs[0], nosecs);
+	i = write(outfile, &esecs, nosecs * sizeof(struct scnhdr));
+	if (i != nosecs * sizeof(struct scnhdr)) {
+		perror("esecs: write");
+		exit(1);
+	}
+	fprintf(stderr, "wrote %d bytes of section headers.\n", i);
+
+	pad = (sizeof(efh) + sizeof(eah) + nosecs * sizeof(struct scnhdr)) & 15;
+	if (pad) {
+		pad = 16 - pad;
+		i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
+		if (i < 0) {
+			perror("ipad: write");
+			exit(1);
+		}
+		fprintf(stderr, "wrote %d byte pad.\n", i);
+	}
+
+	/*
+	 * Copy the loadable sections.   Zero-fill any gaps less than 64k;
+	 * complain about any zero-filling, and die if we're asked to zero-fill
+	 * more than 64k.
+	 */
+	for (i = 0; i < ex.e_phnum; i++) {
+		/*
+		 * Unprocessable sections were handled above, so just verify
+		 * that the section can be loaded before copying.
+		 */
+		if (ph[i].p_type != PT_LOAD || ph[i].p_filesz == 0)
+			continue;
+
+		if (cur_vma != ph[i].p_vaddr) {
+			unsigned long gap = ph[i].p_vaddr - cur_vma;
+			char obuf[1024];
+
+			if (gap > 65536) {
+				fprintf(stderr, "Intersegment gap (%ld "
+				        "bytes) too large.\n", gap);
+				exit(1);
+			}
+			fprintf(stderr, "Warning: %ld byte intersegment gap.\n",
+					gap);
+			memset(obuf, 0, sizeof(obuf));
+			while (gap) {
+				int count = write(outfile, obuf,
+				   gap > sizeof(obuf) ?  sizeof(obuf) : gap);
+				if (count < 0) {
+					fprintf(stderr,
+						"Error writing gap: %s\n",
+						strerror(errno));
+					exit(1);
+				}
+				gap -= count;
+			}
+		}
+		fprintf(stderr, "writing %d bytes...\n", ph[i].p_filesz);
+		copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz);
+		cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
+	}
+
+	/*
+	 * Write a page of padding for boot PROMS that read entire pages.
+	 * Without this, they may attempt to read past the end of the
+	 * data section, incur an error, and refuse to boot.
+	 */
+	{
+		char obuf[4096];
+		memset(obuf, 0, sizeof(obuf));
+		if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
+			fprintf(stderr, "Error writing PROM padding: %s\n",
+				strerror(errno));
+			exit(1);
+		}
+	}
+
+	/* Looks like we won... */
+	exit(0);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/cobalt/int-handler.S linux-2.4.20/arch/mips/cobalt/int-handler.S
--- linux-2.4.19/arch/mips/cobalt/int-handler.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/cobalt/int-handler.S	2002-10-29 11:18:34.000000000 +0000
@@ -26,8 +26,8 @@
 		SAVE_ALL
 		CLI
 		.set	at
-	
-		/* 
+
+		/*
 		 * Get pending Interrupts
 		 */
 		mfc0	s0,CP0_CAUSE	# get irq mask
@@ -52,30 +52,30 @@
 		j	ret_from_irq
 		 nop
 
-1:	
+1:
 		beq	a0,zero,1f		/* Check IP3 */
 		 andi	a0,s0,CAUSEF_IP4
 
 		/* Ethernet 0 interrupt */
-		li	a0,4
+		li	a0,COBALT_RAQ_ETH0_IRQ
 		jal     do_IRQ
 		 move	a1,sp
 
 		j	ret_from_irq
 		 nop
 
-1:	
+1:
 		beq	a0,zero,1f		/* Check IP4 */
 		 andi	a0,s0,CAUSEF_IP5
 
 		/* Ethernet 1 interrupt */
-		li	a0,13
+		li	a0,COBALT_RAQ_ETH1_IRQ
 		jal     do_IRQ
 		 move	a1,sp
 
 		j	ret_from_irq
 		 nop
-1:	
+1:
 		beq	a0,zero,1f		/* Check IP5 */
 		 andi	a0,s0,CAUSEF_IP7
 
@@ -86,7 +86,7 @@
 
 		j	ret_from_irq
 		 nop
-1:	
+1:
 		beq	a0,zero,1f		/* Check IP7 */
 		  nop
 
@@ -100,4 +100,4 @@
 		 nop
 
 		END(cobalt_handle_int)
-	
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/cobalt/irq.c linux-2.4.20/arch/mips/cobalt/irq.c
--- linux-2.4.19/arch/mips/cobalt/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/cobalt/irq.c	2002-10-29 11:18:33.000000000 +0000
@@ -42,11 +42,12 @@
  *    4   - Tulip 1
  *    5   - 16550 UART
  *    6   - VIA southbridge PIC
- *    7   - PCI
+ *    7   - unused
  *
- * The VIA chip is a master/slave 8259 setup and has the 
+ * The VIA chip is a master/slave 8259 setup and has the
  *  following interrupts
  *    8   - RTC
+ *    9   - PCI
  *    14  - IDE0
  *    15  - IDE1
  *
@@ -61,8 +62,8 @@
 
 #define COBALT_IRQS	16
 
-static unsigned short irqnr_to_type[COBALT_IRQS] = 
-{ CPUINT_LINE(0),  NOINT_LINE,      VIAINT_LINE,  NOINT_LINE, 
+static unsigned short irqnr_to_type[COBALT_IRQS] =
+{ CPUINT_LINE(0),  NOINT_LINE,      VIAINT_LINE,  NOINT_LINE,
   CPUINT_LINE(1),  NOINT_LINE,      NOINT_LINE,   CPUINT_LINE(3),
   VIAINT_LINE,     VIAINT_LINE,     NOINT_LINE,   NOINT_LINE,
   NOINT_LINE,      CPUINT_LINE(2),  VIAINT_LINE,  VIAINT_LINE };
@@ -116,102 +117,20 @@
 	NULL
 };
 
-
-/*
- * Cobalt VIA irq
- */
-
-static void enable_via_irq(unsigned int irq)
-{
-	unsigned long flags;
-
-	save_and_cli(flags);
-	unmask_irq(irq);
-	restore_flags(flags);
-}
-
-static unsigned startup_via_irq(unsigned int irq)
-{
-	enable_via_irq(irq);
-
-	return 0;
-}
-
-static void disable_via_irq(unsigned int irq)
-{
-	unsigned long flags;
-
-	save_and_cli(flags);
-	mask_irq(irq);
-	restore_flags(flags);
-}
-
-#define shutdown_via_irq	disable_via_irq
-#define mask_and_ack_via_irq	disable_via_irq
-
-static void end_via_irq(unsigned int irq)
-{
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-		enable_via_irq(irq);
-}
-
-static struct hw_interrupt_type cobalt_via_irq_type = {
-	"Cobalt VIA",
-	startup_via_irq,
-	shutdown_via_irq,
-	enable_via_irq,
-	disable_via_irq,
-	mask_and_ack_via_irq,
-	end_via_irq,
-	NULL
-};
-
-
-static struct irqaction via_irq2 = {
-	no_action, 0, 0, "slave cascade", NULL, NULL
-};
-
-static struct resource pic1_io_resource = {
-	"VIA PIC Master", 0x20, 0x3f, IORESOURCE_BUSY
-};
-
-static struct resource pic2_io_resource = {
-	"VIA PIC Slave", 0xa0, 0xbf, IORESOURCE_BUSY
-};
-
-
 void __init init_IRQ(void)
 {
 	int i;
 
 	/* Initialise all of the IRQ descriptors */
-	init_generic_irq();
+	init_i8259_irqs();
 
 	/* Map the irqnr to the type int we have */
 	for (i=0; i < COBALT_IRQS; i++) {
 		if (irqnr_to_type[i] >= CPUINT_LINE(0))
 			/* cobalt_cpu_irq_type */
 			irq_desc[i].handler = &cobalt_cpu_irq_type;
-		else if (irqnr_to_type[i] == VIAINT_LINE)
-			/* VIA/8259 irq_type */
-			irq_desc[i].handler = &cobalt_via_irq_type;
-		else {} /* Leave it as disabled/no handler */
 	}
 
-	/* Setup the VIA interrupts */
-	request_resource(&ioport_resource, &pic1_io_resource);
-	request_resource(&ioport_resource, &pic2_io_resource);
-	setup_irq(2, &via_irq2);
-
-	/* This may be too simple.. FIX it later */
-	VIA_PORT_WRITE(0x20, 0x10);
-	VIA_PORT_WRITE(0x21, 0x00);
-	VIA_PORT_WRITE(0x21, 0x00);
-
-	VIA_PORT_WRITE(0xa0, 0x10);
-	VIA_PORT_WRITE(0xa1, 0x00);
-	VIA_PORT_WRITE(0xa1, 0x00);
-
 	/* Mask all cpu interrupts
 	    (except IE4, we already masked those at VIA level) */
 	clear_cp0_status(ST0_IM);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/cobalt/pci.c linux-2.4.20/arch/mips/cobalt/pci.c
--- linux-2.4.19/arch/mips/cobalt/pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/cobalt/pci.c	2002-10-29 11:18:49.000000000 +0000
@@ -19,9 +19,11 @@
 #include <asm/cobalt/cobalt.h>
 #include <asm/pci.h>
 #include <asm/io.h>
- 
+
 #ifdef CONFIG_PCI
 
+int cobalt_board_id;
+
 static void qube_expansion_slot_bist(struct pci_dev *dev)
 {
 	unsigned char ctrl;
@@ -56,6 +58,7 @@
 
 	/* Give it a working IRQ. */
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, COBALT_QUBE_SLOT_IRQ);
+	dev->irq = COBALT_QUBE_SLOT_IRQ;
 
 	/* Fixup base addresses, we only support I/O at the moment. */
 	for(i = 0; i <= 5; i++) {
@@ -119,24 +122,22 @@
 static void qube_raq_tulip_fixup(struct pci_dev *dev)
 {
 	unsigned short pci_cmd;
-	extern int cobalt_is_raq;
 
 	/* Fixup the first tulip located at device PCICONF_ETH0 */
 	if (PCI_SLOT(dev->devfn) == COBALT_PCICONF_ETH0) {
 		/*
-		 * Now tell the Ethernet device that we expect an interrupt at
-		 * IRQ 13 and not the default 189.
-		 *
 		 * The IRQ of the first Tulip is different on Qube and RaQ
 		 */
-		if (!cobalt_is_raq) {
-			/* All Qube's route this the same way. */
+		if (cobalt_board_id == COBALT_BRD_ID_RAQ2) {
+			/* Setup the first Tulip on the RAQ */
 			pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
-                                              COBALT_QUBE_ETH_IRQ);
+					      COBALT_RAQ_ETH0_IRQ);
+			dev->irq = COBALT_RAQ_ETH0_IRQ;
 		} else {
-			/* Setup the first Tulip on the RAQ */
+			/* All Qube's route this the same way. */
 			pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
-                                              COBALT_RAQ_ETH0_IRQ);
+					      COBALT_QUBE_ETH_IRQ);
+			dev->irq = COBALT_QUBE_ETH_IRQ;
 		}
 		dev->resource[0].start = 0x100000;
 		dev->resource[0].end = 0x10007f;
@@ -156,6 +157,7 @@
 		/* Give it it's IRQ. */
 		pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
                                       COBALT_RAQ_ETH1_IRQ);
+		dev->irq = COBALT_RAQ_ETH1_IRQ;
 
 		/* And finally, a usable I/O space allocation, right after what
 		 * the first Tulip uses.
@@ -168,15 +170,15 @@
 static void qube_raq_scsi_fixup(struct pci_dev *dev)
 {
 	unsigned short pci_cmd;
-	extern int cobalt_is_raq;
 
         /*
          * Tell the SCSI device that we expect an interrupt at
          * IRQ 7 and not the default 0.
          */
         pci_write_config_byte(dev, PCI_INTERRUPT_LINE, COBALT_SCSI_IRQ);
+	dev->irq = COBALT_SCSI_IRQ;
 
-	if (cobalt_is_raq) {
+	if (cobalt_board_id == COBALT_BRD_ID_RAQ2) {
 
 		/* Enable the device. */
 		pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
@@ -186,7 +188,8 @@
 		pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
 
 		/* Give it it's RAQ IRQ. */
-		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 4);
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, COBALT_RAQ_SCSI_IRQ);
+		dev->irq = COBALT_RAQ_SCSI_IRQ;
 
 		/* And finally, a usable I/O space allocation, right after what
 		 * the second Tulip uses.
@@ -252,11 +255,11 @@
 };
 
 
-static __inline__ int pci_range_ck(struct pci_dev *dev) 
+static __inline__ int pci_range_ck(struct pci_dev *dev)
 {
-       if ((dev->bus->number == 0) 
-           && ((PCI_SLOT (dev->devfn) == 0) 
-               || ((PCI_SLOT (dev->devfn) > 6) 
+       if ((dev->bus->number == 0)
+           && ((PCI_SLOT (dev->devfn) == 0)
+               || ((PCI_SLOT (dev->devfn) > 6)
                    && (PCI_SLOT (dev->devfn) <= 12))))
 		return 0;  /* OK device number  */
 
@@ -328,7 +331,7 @@
 
 static int
 qube_pci_write_config_word (struct pci_dev *dev,
-                                int where, 
+                                int where,
                                u16 val)
 {
 	unsigned long tmp;
@@ -347,7 +350,7 @@
 
 static int
 qube_pci_write_config_byte (struct pci_dev *dev,
-                                int where, 
+                                int where,
                                u8 val)
 {
 	unsigned long tmp;
@@ -374,8 +377,18 @@
 
 void __init pcibios_init(void)
 {
+	struct pci_dev dev;
+
 	printk("PCI: Probing PCI hardware\n");
 
+	/* Read the cobalt id register out of the PCI config space */
+	dev.devfn = PCI_DEVFN(COBALT_PCICONF_VIA, 0);
+	PCI_CFG_SET(&dev, (VIA_COBALT_BRD_ID_REG & ~0x3));
+	cobalt_board_id = *PCI_CFG_DATA >> ((VIA_COBALT_BRD_ID_REG & 3) * 8);
+	cobalt_board_id = VIA_COBALT_BRD_REG_to_ID(cobalt_board_id);
+
+	printk("Cobalt Board ID: %d\n", cobalt_board_id);
+
 	ioport_resource.start = 0x00000000;
 	ioport_resource.end = 0x0fffffff;
 
@@ -393,7 +406,7 @@
 int pcibios_enable_device(struct pci_dev *dev)
 {
 	u16 cmd, status;
-	
+
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	pci_read_config_word(dev, PCI_STATUS, &status);
 	printk("PCI: Enabling device %s (%04x  %04x)\n", dev->slot_name, cmd, status);
@@ -403,13 +416,13 @@
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-		unsigned long size)
+		unsigned long size, unsigned long align)
 {
 
 	panic("Uhhoh called pcibios_align_resource\n");
 }
 
-void pcibios_update_resource(struct pci_dev *dev, struct resource *root, 
+void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
 		struct resource *res, int resource)
 {
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/cobalt/promcon.c linux-2.4.20/arch/mips/cobalt/promcon.c
--- linux-2.4.19/arch/mips/cobalt/promcon.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/cobalt/promcon.c	2002-10-29 11:18:51.000000000 +0000
@@ -70,7 +70,7 @@
 	ns16550_cons_put_char(kgdb_char, port);
 }
 
-static kdev_t 
+static kdev_t
 ns16550_console_dev(struct console *c)
 {
 	return MKDEV(TTY_MAJOR, 64 + c->index);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/cobalt/reset.c linux-2.4.20/arch/mips/cobalt/reset.c
--- linux-2.4.19/arch/mips/cobalt/reset.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/cobalt/reset.c	2002-10-29 11:18:33.000000000 +0000
@@ -49,14 +49,14 @@
 	/* Blink our cute? little LED (number 3)... */
 	while (1) {
 		led_state = led_state | ( 1 << 3 );
-		LEDSet(led_state);  
+		LEDSet(led_state);
 		mark = jiffies;
 		while (jiffies<(mark+HZ));
 		led_state = led_state & ~( 1 << 3 );
 		LEDSet(led_state);
 		mark = jiffies;
 		while (jiffies<(mark+HZ));
-	} 
+	}
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/cobalt/setup.c linux-2.4.20/arch/mips/cobalt/setup.c
--- linux-2.4.19/arch/mips/cobalt/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/cobalt/setup.c	2002-10-29 11:18:34.000000000 +0000
@@ -35,7 +35,17 @@
 extern struct ide_ops std_ide_ops;
 
 
-char arcs_cmdline[CL_SIZE] = { "console=ttyS0,115200 root=/dev/hda1" };
+char arcs_cmdline[CL_SIZE] = {
+ "console=ttyS0,115200 "
+#ifdef CONFIG_IP_PNP
+ "ip=on "
+#endif
+#ifdef CONFIG_ROOT_NFS
+ "root=/dev/nfs "
+#else
+ "root=/dev/hda1 "
+#endif
+ };
 
 const char *get_system_type(void)
 {
@@ -63,23 +73,19 @@
 	*timer_reg = 500000;
 
 	/* Register our timer interrupt */
-	setup_irq(0, irq);
+	setup_irq(COBALT_TIMER_IRQ, irq);
 
 	/* Enable timer ints */
-	*((volatile unsigned long *) GALILEO_TIMER_CTRL) = 
+	*((volatile unsigned long *) GALILEO_TIMER_CTRL) =
 			(unsigned long) (GALILEO_ENTC0 | GALILEO_SELTC0);
 	/* Unmask timer int */
-	*((volatile unsigned long *) GALILEO_CPU_MASK) = (unsigned long) 0x00000100; 
+	*((volatile unsigned long *) GALILEO_CPU_MASK) = (unsigned long) 0x00000100;
 }
 
 
 void __init bus_error_init(void) { /* nothing */ }
 
 
-int cobalt_serial_present;
-int cobalt_serial_type;
-int cobalt_is_raq;
-
 void __init cobalt_setup(void)
 {
 
@@ -95,21 +101,13 @@
 #endif
         set_io_port_base(0xb0000000);
 
-	/* 
+	/*
 	 * This is a prom style console. We just poke at the
 	 *  UART to make it talk.
 	 * Only use this console if you really screw up and can't
 	 *  get to the stage of setting up a real serial console.
 	 */
 	/*ns16550_setup_console();*/
-
-	/* We have to do this early, here, before the value could
-	 * possibly be overwritten by the bootup sequence.
-	 */
-	cobalt_serial_present = *((unsigned long *) 0xa020001c);
-	cobalt_serial_type    = *((unsigned long *) 0xa0200020);
-	cobalt_is_raq         = (cobalt_serial_present != 0x0
-				 && cobalt_serial_type == 0x1);
 }
 
 /* Prom init. We read our one and only communication with the
@@ -117,7 +115,7 @@
 void __init prom_init(int argc)
 {
 	mips_machgroup = MACH_GROUP_COBALT;
-	
+
 	add_memory_region(0x0, argc & 0x7fffffff, BOOT_MEM_RAM);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/cobalt/via.c linux-2.4.20/arch/mips/cobalt/via.c
--- linux-2.4.19/arch/mips/cobalt/via.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/cobalt/via.c	2002-10-29 11:18:34.000000000 +0000
@@ -18,62 +18,30 @@
 
 extern void do_IRQ(int irq, struct pt_regs * regs);
 
-/* Cached values of VIA PIC masks, we start with cascade enabled */
-static unsigned int cached_irq_mask = 0xfffb;
-
-#define __byte(x,y)	(((unsigned char *)&(y))[x])
-#define cached_21	(__byte(0,cached_irq_mask))
-#define cached_A1	(__byte(1,cached_irq_mask))
-
-
-void mask_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << irq;
-
-	cached_irq_mask |= mask;
-	if (irq & 8) {
-		VIA_PORT_WRITE(0xA1, cached_A1);
-	} else {
-		VIA_PORT_WRITE(0x21, cached_21);
-	}
-}
-
-void unmask_irq(unsigned int irq)
-{
-	unsigned int mask = ~(1 << irq);
-
-	cached_irq_mask &= mask;
-	if (irq & 8) {
-		VIA_PORT_WRITE(0xA1, cached_A1);
-	} else {
-		VIA_PORT_WRITE(0x21, cached_21);
-	}
-}
-
 asmlinkage void via_irq(struct pt_regs *regs)
 {
 	char mstat, sstat;
-  
+
 	/* Read Master Status */
-	VIA_PORT_WRITE(0x20, 0x0C);
-	mstat = VIA_PORT_READ(0x20);
- 
+	outb(0x0C, 0x20);
+	mstat = inb(0x20);
+
 	if (mstat < 0) {
 		mstat &= 0x7f;
-		if (mstat != 2) {     	
+		if (mstat != 2) {
 			do_IRQ(mstat, regs);
-			VIA_PORT_WRITE(0x20, mstat | 0x20);
+			outb(mstat | 0x20, 0x20);
 		} else {
-			sstat = VIA_PORT_READ(0xA0);
+			sstat = inb(0xA0);
 
 			/* Slave interrupt */
-			VIA_PORT_WRITE(0xA0, 0x0C);
-			sstat = VIA_PORT_READ(0xA0);
-   
+			outb(0x0C, 0xA0);
+			sstat = inb(0xA0);
+
 			if (sstat < 0) {
 				do_IRQ((sstat + 8) & 0x7f, regs);
-				VIA_PORT_WRITE(0x20, 0x22);       
-				VIA_PORT_WRITE(0xA0, (sstat & 0x7f) | 0x20);
+				outb(0x22, 0x20);
+				outb((sstat & 0x7f) | 0x20, 0xA0);
 			} else {
 				printk("Spurious slave interrupt...\n");
 			}
@@ -87,13 +55,13 @@
 
 asmlinkage void galileo_irq(struct pt_regs *regs)
 {
-	unsigned long irq_src = *((unsigned long *) GALILEO_INTCAUSE); 
+	unsigned long irq_src = *((unsigned long *) GALILEO_INTCAUSE);
 
 	/* Check for timer irq ... */
 	if (irq_src & GALILEO_T0EXP) {
 		/* Clear the int line */
 		*((volatile unsigned long *) GALILEO_INTCAUSE) = 0;
-		do_IRQ(0, regs);
+		do_IRQ(COBALT_TIMER_IRQ, regs);
 	} else
 		printk("Spurious Galileo interrupt...\n");
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/config-shared.in linux-2.4.20/arch/mips/config-shared.in
--- linux-2.4.19/arch/mips/config-shared.in	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/config-shared.in	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,803 @@
+mainmenu_name "Linux/MIPS Kernel Configuration"
+
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
+mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
+   bool '  Kernel module loader' CONFIG_KMOD
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Machine selection'
+dep_bool 'Support for Acer PICA 1 chipset (EXPERIMENTAL)' CONFIG_ACER_PICA_61 $CONFIG_EXPERIMENTAL
+dep_bool 'Support for Alchemy Semi PB1000 board' CONFIG_MIPS_PB1000 $CONFIG_MIPS32
+if [ "$CONFIG_MIPS_PB1000" = "y" ]; then
+   bool '  Support for PCI AUTO Config' CONFIG_PCI_AUTO
+fi
+dep_bool 'Support for Alchemy Semi PB1100 board' CONFIG_MIPS_PB1100 $CONFIG_MIPS32
+dep_bool 'Support for Alchemy Semi PB1500 board' CONFIG_MIPS_PB1500 $CONFIG_MIPS32
+dep_bool 'Support for Algorithmics P4032 (EXPERIMENTAL)' CONFIG_ALGOR_P4032 $CONFIG_EXPERIMENTAL
+dep_bool 'Support for BAGET MIPS series (EXPERIMENTAL)' CONFIG_BAGET_MIPS $CONFIG_MIPS32 $CONFIG_EXPERIMENTAL
+dep_bool 'Support for Cobalt Server (EXPERIMENTAL)' CONFIG_MIPS_COBALT $CONFIG_EXPERIMENTAL
+dep_bool 'Support for DECstations' CONFIG_DECSTATION $CONFIG_MIPS32
+dep_bool 'Support for Galileo EV64120 Evaluation board (EXPERIMENTAL)' CONFIG_MIPS_EV64120 $CONFIG_EXPERIMENTAL
+if [ "$CONFIG_MIPS_EV64120" = "y" ]; then
+   bool '  Enable Second PCI (PCI1)' CONFIG_EVB_PCI1
+   choice '  Galileo Chip Clock' \
+	"75	CONFIG_SYSCLK_75 \
+	 83.3	CONFIG_SYSCLK_83 \
+	 100	CONFIG_SYSCLK_100" 83.3
+fi
+dep_bool 'Support for Galileo EV96100 Evaluation board (EXPERIMENTAL)' CONFIG_MIPS_EV96100 $CONFIG_EXPERIMENTAL
+bool 'Support for Globespan IVR board' CONFIG_MIPS_IVR
+bool 'Support for Hewlett Packard LaserJet board' CONFIG_HP_LASERJET
+bool 'Support for ITE 8172G board' CONFIG_MIPS_ITE8172
+if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then
+   bool '  Support for older IT8172 (Rev C)' CONFIG_IT8172_REVC
+fi
+dep_bool 'Support for MIPS Atlas board (EXPERIMENTAL)' CONFIG_MIPS_ATLAS $CONFIG_EXPERIMENTAL
+bool 'Support for MIPS Magnum 4000' CONFIG_MIPS_MAGNUM_4000
+dep_bool 'Support for MIPS Malta board (EXPERIMENTAL)' CONFIG_MIPS_MALTA $CONFIG_EXPERIMENTAL
+dep_bool 'Support for MIPS SEAD board (EXPERIMENTAL)' CONFIG_MIPS_SEAD $CONFIG_EXPERIMENTAL
+bool 'Support for Momentum Ocelot board' CONFIG_MOMENCO_OCELOT
+bool 'Support for Momentum Ocelot-G board' CONFIG_MOMENCO_OCELOT_G
+dep_bool 'Support for NEC DDB Vrc-5074 (EXPERIMENTAL)' CONFIG_DDB5074 $CONFIG_EXPERIMENTAL
+bool 'Support for NEC DDB Vrc-5476' CONFIG_DDB5476
+bool 'Support for NEC DDB Vrc-5477' CONFIG_DDB5477
+if [ "$CONFIG_DDB5477" = "y" ]; then
+   int '   bus frequency (in kHZ, 0 for auto-detect)' CONFIG_DDB5477_BUS_FREQUENCY 0
+fi
+bool 'Support for NEC Osprey board' CONFIG_NEC_OSPREY
+bool 'Support for NEC Eagle/Hawk board' CONFIG_NEC_EAGLE
+bool 'Support for Olivetti M700-10' CONFIG_OLIVETTI_M700
+dep_bool 'Support for Philips Nino (EXPERIMENTAL)' CONFIG_NINO $CONFIG_MIPS32 $CONFIG_EXPERIMENTAL
+if [ "$CONFIG_NINO" = "y" ]; then
+   choice 'Nino Model Number' \
+	"Model-300/301/302/319			CONFIG_NINO_4MB \
+	 Model-200/210/312/320/325/350/390	CONFIG_NINO_8MB \
+	 Model-500/510				CONFIG_NINO_16MB" Model-200
+fi
+bool 'Support for SGI IP22 (Indy/Indigo2)' CONFIG_SGI_IP22
+dep_bool 'Support for SGI-IP27 (Origin200/2000)' CONFIG_SGI_IP27 $CONFIG_MIPS64
+if [ "$CONFIG_SGI_IP27" = "y" ]; then
+   bool '  IP27 N-Mode' CONFIG_SGI_SN0_N_MODE
+   bool '  Discontiguous Memory Support' CONFIG_DISCONTIGMEM
+   bool '  NUMA Support' CONFIG_NUMA
+   bool '  Mapped kernel support' CONFIG_MAPPED_KERNEL
+   bool '  Kernel text replication support' CONFIG_REPLICATE_KTEXT
+   bool '  Exception handler replication support' CONFIG_REPLICATE_EXHANDLERS
+   bool '  Multi-Processing support' CONFIG_SMP
+   #bool '  IP27 XXL' CONFIG_SGI_SN0_XXL
+fi
+dep_bool 'Support for SGI-IP32 (O2) (EXPERIMENTAL)' CONFIG_SGI_IP32 $CONFIG_EXPERIMENTAL
+dep_bool 'Support for Broadcom BCM1xxx SOCs (EXPERIMENTAL)' CONFIG_SIBYTE_SB1xxx_SOC $CONFIG_EXPERIMENTAL
+if [ "$CONFIG_SIBYTE_SB1xxx_SOC" = "y" ]; then
+   choice '   BCM1xxx SOC Type' \
+	  "BCM1250          CONFIG_SIBYTE_SB1250" BCM1250
+
+   bool '   Running under simulation' CONFIG_SIMULATION
+   bool '   Booting from CFE' CONFIG_SIBYTE_CFE
+   dep_bool '     Use firmware console' CONFIG_SIBYTE_CFE_CONSOLE $CONFIG_SIBYTE_CFE
+   if [ "$CONFIG_SIBYTE_CFE" = "n" ]; then
+      define_bool CONFIG_SIBYTE_STANDALONE y
+      int  '   Memory size (in megabytes)' CONFIG_SIBYTE_STANDALONE_RAM_SIZE 32
+   fi
+
+   bool '   Support for SB1/SOC profiling - SB1/SCD perf counters' CONFIG_SIBYTE_SB1250_PROF
+   bool '   Support for ZBbus profiling' CONFIG_BCM1250_TBPROF
+
+   if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then
+      if [ "$CONFIG_SIBYTE_STANDALONE" != "y" ]; then
+	 bool '   Multi-Processing support' CONFIG_SMP
+      fi
+   fi
+
+   if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then
+      bool '   Support for BCM1250/BCM112x onchip PCI controller' CONFIG_PCI
+   fi
+
+   if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then
+      bool '   Support for SWARM board' CONFIG_SIBYTE_SWARM
+   fi
+fi
+bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI
+dep_bool 'Support for Toshiba JMR-TX3927 board' CONFIG_TOSHIBA_JMR3927 $CONFIG_MIPS32
+bool 'Support for ZAO Networks Capcella' CONFIG_ZAO_CAPCELLA
+
+dep_bool 'High Memory Support' CONFIG_HIGHMEM $CONFIG_MIPS32
+
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+
+#
+# Select some configuration options automatically based on user selections.
+#
+
+if [ "$CONFIG_ACER_PICA_61" = "y" ]; then
+   define_bool CONFIG_ARC32 y
+   define_bool CONFIG_I8259 y
+   define_bool CONFIG_ISA y
+   define_bool CONFIG_MIPS_JAZZ y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_PC_KEYB y
+   define_bool CONFIG_ROTTEN_IRQ y
+   define_bool CONFIG_OLD_TIME_C y
+fi
+if [ "$CONFIG_MIPS_PB1000" = "y" ]; then
+   define_bool CONFIG_MIPS_AU1000 y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_NEW_PCI y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_PC_KEYB y
+   define_bool CONFIG_SWAP_IO_SPACE y
+   define_bool CONFIG_AU1000_USB_DEVICE y
+fi
+if [ "$CONFIG_MIPS_PB1100" = "y" ]; then
+   define_bool CONFIG_MIPS_AU1000 y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_PCI_AUTO n
+   define_bool CONFIG_NEW_PCI y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_PC_KEYB y
+   define_bool CONFIG_SWAP_IO_SPACE y
+   define_bool CONFIG_AU1000_USB_DEVICE y
+fi
+if [ "$CONFIG_MIPS_PB1500" = "y" ]; then
+   define_bool CONFIG_MIPS_AU1000 y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_NEW_PCI y
+   define_bool CONFIG_PCI_AUTO y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_PC_KEYB y
+   define_bool CONFIG_AU1000_USB_DEVICE y
+fi
+if [ "$CONFIG_ALGOR_P4032" = "y" ]; then
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_OLD_TIME_C y
+fi
+if [ "$CONFIG_MIPS_COBALT" = "y" ]; then
+   define_bool CONFIG_COBALT_LCD y
+   define_bool CONFIG_I8259 y
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_NEW_TIME_C y
+   define_bool CONFIG_NONCOHERENT_IO y
+fi
+if [ "$CONFIG_DECSTATION" = "y" ]; then
+   define_bool CONFIG_IRQ_CPU y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_NONCOHERENT_IO y
+fi
+if [ "$CONFIG_MIPS_EV64120" = "y" ]; then
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_ISA n
+   define_bool CONFIG_MIPS_GT64120 y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_OLD_TIME_C y
+fi
+if [ "$CONFIG_MIPS_EV96100" = "y" ]; then
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_MIPS_GT96100 y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_NEW_PCI y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_PCI_AUTO y
+   define_bool CONFIG_SWAP_IO_SPACE y
+fi
+if [ "$CONFIG_MIPS_IVR" = "y" ]; then
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_PC_KEYB y
+   define_bool CONFIG_NEW_PCI y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_PCI_AUTO y
+   define_bool CONFIG_IT8172_CIR y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_NEW_TIME_C y
+fi
+if [ "$CONFIG_HP_LASERJET" = "y" ]; then
+   define_bool CONFIG_IRQ_CPU y
+   define_bool CONFIG_NEW_TIME_C y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_NEW_PCI y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_PCI y
+   #not yet define_bool CONFIG_PCI_AUTO y
+fi
+if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_IT8712 y
+   define_bool CONFIG_PC_KEYB y
+   define_bool CONFIG_NEW_PCI y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_PCI_AUTO y
+   define_bool CONFIG_IT8172_CIR y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_NEW_TIME_C y
+fi
+if [ "$CONFIG_MIPS_ATLAS" = "y" ]; then
+   define_bool CONFIG_BOOT_ELF32 y
+   define_int CONFIG_L1_CACHE_SHIFT 5
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_NEW_TIME_C y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_SWAP_IO_SPACE y
+fi
+if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \
+     "$CONFIG_OLIVETTI_M700"    = "y" ]; then
+   define_bool CONFIG_ARC32 y
+   define_bool CONFIG_I8259 y
+   define_bool CONFIG_ISA y
+   define_bool CONFIG_FB y
+   define_bool CONFIG_FB_G364 y
+   define_bool CONFIG_MIPS_JAZZ y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_PC_KEYB y
+   define_bool CONFIG_OLD_TIME_C y
+fi
+if [ "$CONFIG_MIPS_MALTA" = "y" ]; then
+   define_bool CONFIG_BOOT_ELF32 y
+   define_bool CONFIG_HAVE_STD_PC_SERIAL_PORT y
+   define_bool CONFIG_I8259 y
+   define_int CONFIG_L1_CACHE_SHIFT 5
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_NEW_TIME_C y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_SWAP_IO_SPACE y
+   define_bool CONFIG_PC_KEYB y
+   define_bool CONFIG_PCI y
+fi
+if [ "$CONFIG_MIPS_SEAD" = "y" ]; then
+   define_int CONFIG_L1_CACHE_SHIFT 5
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_NEW_TIME_C y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_PCI n
+fi
+if [ "$CONFIG_MOMENCO_OCELOT" = "y" ]; then
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_SYSCLK_100 y
+   define_bool CONFIG_SWAP_IO_SPACE y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_OLD_TIME_C y
+fi
+if [ "$CONFIG_MOMENCO_OCELOT_G" = "y" ]; then
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_SYSCLK_100 y
+   define_bool CONFIG_SWAP_IO_SPACE y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_OLD_TIME_C y
+fi
+if [ "$CONFIG_DDB5074" = "y" ]; then
+   define_bool CONFIG_HAVE_STD_PC_SERIAL_PORT y
+   define_bool CONFIG_I8259 y
+   define_bool CONFIG_ISA y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_PC_KEYB y
+   define_bool CONFIG_NEW_TIME_C y
+   define_bool CONFIG_PCI_AUTO y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_IRQ_CPU y
+   define_bool CONFIG_NEW_PCI y
+fi
+if [ "$CONFIG_DDB5476"  = "y" ]; then
+   define_bool CONFIG_ISA y
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_PC_KEYB y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_IRQ_CPU y
+   define_bool CONFIG_I8259 y
+   define_bool CONFIG_HAVE_STD_PC_SERIAL_PORT y
+   define_bool CONFIG_NEW_PCI y
+   define_bool CONFIG_PCI_AUTO y
+   define_bool CONFIG_NEW_TIME_C y
+   define_bool CONFIG_NONCOHERENT_IO y
+fi
+if [ "$CONFIG_DDB5477" = "y" ]; then
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_NEW_TIME_C y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_IRQ_CPU y
+   define_bool CONFIG_NEW_PCI y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_PCI_AUTO y
+   define_bool CONFIG_DUMMY_KEYB y
+   define_bool CONFIG_I8259 y
+fi
+if [ "$CONFIG_NEC_OSPREY" = "y" ]; then
+   define_bool CONFIG_VR4181 y
+   define_bool CONFIG_SERIAL y
+   define_bool CONFIG_SERIAL_MANY_PORTS y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_IRQ_CPU y
+   define_bool CONFIG_NEW_TIME_C y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_DUMMY_KEYB y
+   define_bool CONFIG_SCSI n
+fi
+if [ "$CONFIG_NEC_EAGLE" = "y" ]; then
+   define_bool CONFIG_CPU_VR41XX y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_IRQ_CPU y
+   define_bool CONFIG_NEW_TIME_C y
+   define_bool CONFIG_VR41XX_TIME_C y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_ISA n
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_NEW_PCI y
+   define_bool CONFIG_PCI_AUTO y
+   define_bool CONFIG_DUMMY_KEYB y
+   define_bool CONFIG_SCSI n
+fi
+if [ "$CONFIG_NINO" = "y" ]; then
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_NEW_TIME_C y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_PC_KEYB y
+fi
+if [ "$CONFIG_SGI_IP22" = "y" ]; then
+   define_bool CONFIG_ARC32 y
+   define_bool CONFIG_ARC_CONSOLE y
+   define_bool CONFIG_ARC_MEMORY y
+   define_bool CONFIG_BOARD_SCACHE y
+   define_bool CONFIG_BOOT_ELF32 y
+   define_bool CONFIG_SWAP_IO_SPACE y
+   define_bool CONFIG_IRQ_CPU y
+   define_int CONFIG_L1_CACHE_SHIFT 5
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_NEW_TIME_C y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_PC_KEYB y
+   define_bool CONFIG_SGI y
+fi
+if [ "$CONFIG_SGI_IP27" = "y" ]; then
+   define_bool CONFIG_BOOT_ELF64 y
+   define_bool CONFIG_ARC64 y
+   #define_bool CONFIG_MAPPED_PCI_IO y
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_QL_ISP_A64 y
+   define_int CONFIG_L1_CACHE_SHIFT 7
+fi
+if [ "$CONFIG_SGI_IP32" = "y" ]; then
+   define_bool CONFIG_ARC_MEMORY y
+   define_bool CONFIG_ARC32 y
+   #define_bool CONFIG_BOARD_SCACHE y
+   define_bool CONFIG_BOOT_ELF32 y
+   define_int CONFIG_L1_CACHE_SHIFT 5
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_PC_KEYB y
+   define_bool CONFIG_PCI y
+fi
+if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_NEW_TIME_C y
+   define_bool CONFIG_DUMMY_KEYB y
+   define_bool CONFIG_SWAP_IO_SPACE y
+   define_bool CONFIG_BOOT_ELF32 y
+fi
+if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then
+   define_bool CONFIG_ARC32 y
+   define_bool CONFIG_ARC_MEMORY y
+   define_bool CONFIG_I8259 y
+   define_bool CONFIG_ISA y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_OLD_TIME_C y
+   define_bool CONFIG_PC_KEYB y
+   define_bool CONFIG_PCI y
+fi
+if [ "$CONFIG_TOSHIBA_JMR3927" = "y" ]; then
+   define_bool CONFIG_TOSHIBA_BOARDS y
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_NEW_PCI y
+   define_bool CONFIG_PCI_AUTO y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_NEW_TIME_C y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_SWAP_IO_SPACE y
+   define_bool CONFIG_PC_KEYB y
+fi
+if [ "$CONFIG_ZAO_CAPCELLA" = "y" ]; then
+   define_bool CONFIG_CPU_VR41XX y
+   define_bool CONFIG_CPU_LITTLE_ENDIAN y
+   define_bool CONFIG_NEW_IRQ y
+   define_bool CONFIG_IRQ_CPU y
+   define_bool CONFIG_NEW_TIME_C y
+   define_bool CONFIG_VR41XX_TIME_C y
+   define_bool CONFIG_NONCOHERENT_IO y
+   define_bool CONFIG_ISA n
+   define_bool CONFIG_PCI y
+   define_bool CONFIG_NEW_PCI y
+   define_bool CONFIG_PCI_AUTO y
+   define_bool CONFIG_DUMMY_KEYB y
+   define_bool CONFIG_SCSI n
+fi
+
+if [ "$CONFIG_MIPS_AU1000" != "y" ]; then
+   define_bool CONFIG_MIPS_AU1000 n
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'CPU selection'
+
+choice 'CPU type' \
+	"MIPS32	CONFIG_CPU_MIPS32 \
+	 MIPS64	CONFIG_CPU_MIPS64 \
+	 R3000	CONFIG_CPU_R3000 \
+	 R39XX	CONFIG_CPU_TX39XX \
+	 R41xx	CONFIG_CPU_VR41XX \
+	 R4300	CONFIG_CPU_R4300 \
+	 R4x00	CONFIG_CPU_R4X00 \
+	 R49XX	CONFIG_CPU_TX49XX \
+	 R5000	CONFIG_CPU_R5000 \
+	 R5432	CONFIG_CPU_R5432 \
+	 R6000	CONFIG_CPU_R6000 \
+	 R52xx	CONFIG_CPU_NEVADA \
+	 R8000	CONFIG_CPU_R8000 \
+	 R10000	CONFIG_CPU_R10000 \
+	 RM7000	CONFIG_CPU_RM7000 \
+	 SB1	CONFIG_CPU_SB1" R4x00
+
+if [ "$CONFIG_CPU_R5000" = "y" ]; then
+   define_bool CONFIG_BOARD_SCACHE y
+fi
+
+if [ "$CONFIG_CPU_NEVADA" = "y" ]; then
+   define_bool CONFIG_BOARD_SCACHE y
+fi
+ 
+if [ "$CONFIG_CPU_MIPS32" = "y" ]; then
+   define_bool CONFIG_CPU_HAS_PREFETCH y
+   bool '  Support for Virtual Tagged I-cache' CONFIG_VTAG_ICACHE
+fi
+
+if [ "$CONFIG_CPU_MIPS64" = "y" ]; then
+   define_bool CONFIG_CPU_HAS_PREFETCH y
+   bool '  Support for Virtual Tagged I-cache' CONFIG_VTAG_ICACHE
+fi
+
+if [ "$CONFIG_CPU_RM7000" = "y" ]; then
+   define_bool CONFIG_CPU_HAS_PREFETCH y
+fi
+
+if [ "$CONFIG_CPU_SB1" = "y" ]; then
+   choice 'SB1 Pass' \
+	 "Pass1   CONFIG_CPU_SB1_PASS_1  \
+	  Pass2   CONFIG_CPU_SB1_PASS_2
+	  Pass2.2 CONFIG_CPU_SB1_PASS_2_2" Pass1
+   if [ "$CONFIG_CPU_SB1_PASS_1" = "y" ]; then
+      define_bool CONFIG_SB1_PASS_1_WORKAROUNDS y
+   fi
+   if [ "$CONFIG_CPU_SB1_PASS_2" = "y" ]; then
+      define_bool CONFIG_SB1_PASS_2_WORKAROUNDS y
+   else
+      # Avoid prefetches on Pass 2 (before 2.2)
+      bool '  Enable prefetches' CONFIG_CPU_HAS_PREFETCH
+   fi
+   if [ "$CONFIG_CPU_SB1_PASS_2_2" = "y" ]; then
+      # XXXKW for now, let 2.2 use same WORKAROUNDS flag as pre-2.2
+      define_bool CONFIG_SB1_PASS_2_WORKAROUNDS y
+   fi
+   bool '  Support for SB1 Cache Error handler' CONFIG_SB1_CACHE_ERROR
+   dep_bool '    Ignore recoverable cache errors' CONFIG_SB1_CERR_IGNORE_RECOVERABLE $CONFIG_SB1_CACHE_ERROR
+   dep_bool '    Spin instead of running handler' CONFIG_SB1_CERR_SPIN $CONFIG_SB1_CACHE_ERROR
+   define_bool CONFIG_VTAG_ICACHE y
+fi
+
+if [ "$CONFIG_CPU_R4X00"  = "y" -o \
+     "$CONFIG_CPU_R5000"  = "y" -o \
+     "$CONFIG_CPU_RM7000" = "y" -o \
+     "$CONFIG_CPU_R10000" = "y" -o \
+     "$CONFIG_CPU_SB1"    = "y" -o \
+     "$CONFIG_CPU_MIPS32" = "y" -o \
+     "$CONFIG_CPU_MIPS64" = "y" ]; then
+   dep_bool '  Support for 64-bit physical address space' CONFIG_64BIT_PHYS_ADDR $CONFIG_MIPS32
+fi
+
+dep_bool 'Override CPU Options' CONFIG_CPU_ADVANCED $CONFIG_MIPS32
+if [ "$CONFIG_CPU_ADVANCED" = "y" ]; then
+   bool '  ll/sc Instructions available' CONFIG_CPU_HAS_LLSC
+   bool '  lld/scd Instructions available' CONFIG_CPU_HAS_LLDSCD
+   bool '  Writeback Buffer available' CONFIG_CPU_HAS_WB
+else
+   if [ "$CONFIG_CPU_R3000"  = "y" -o \
+        "$CONFIG_CPU_VR41XX" = "y" -o \
+        "$CONFIG_CPU_TX39XX" = "y" ]; then
+      if [ "$CONFIG_DECSTATION" = "y" ]; then
+	 define_bool CONFIG_CPU_HAS_LLSC n
+	 define_bool CONFIG_CPU_HAS_LLDSCD n
+	 define_bool CONFIG_CPU_HAS_WB y
+      else
+	 define_bool CONFIG_CPU_HAS_LLSC n
+	 define_bool CONFIG_CPU_HAS_LLDSCD n
+	 define_bool CONFIG_CPU_HAS_WB n
+      fi
+   else
+      if [ "$CONFIG_CPU_MIPS32" = "y" ]; then
+	 define_bool CONFIG_CPU_HAS_LLSC y
+	 define_bool CONFIG_CPU_HAS_LLDSCD n
+	 define_bool CONFIG_CPU_HAS_WB n
+      else
+	 define_bool CONFIG_CPU_HAS_LLSC y
+	 define_bool CONFIG_CPU_HAS_LLDSCD y
+	 define_bool CONFIG_CPU_HAS_WB n
+      fi
+   fi
+fi
+if [ "$CONFIG_CPU_R3000" = "y" ]; then
+   define_bool CONFIG_CPU_HAS_SYNC n
+else
+   define_bool CONFIG_CPU_HAS_SYNC y
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'General setup'
+if [ "$CONFIG_DECSTATION"  = "y" -o \
+     "$CONFIG_DDB5074"     = "y" -o \
+     "$CONFIG_NINO"        = "y" -o \
+     "$CONFIG_MIPS_COBALT" = "y" ]; then
+   define_bool CONFIG_CPU_LITTLE_ENDIAN y
+else
+   bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
+fi
+
+if [ "$CONFIG_TOSHIBA_JMR3927" = "y" ]; then
+   bool 'DS1742 BRAM/RTC support' CONFIG_RTC_DS1742
+fi
+
+if [ "$CONFIG_CPU_LITTLE_ENDIAN" = "n" ]; then
+   bool 'Include IRIX binary compatibility' CONFIG_BINFMT_IRIX
+   bool 'Include forward keyboard' CONFIG_FORWARD_KEYBOARD
+fi
+
+if [ "$CONFIG_CPU_R10000" = "y" ]; then
+   dep_bool 'Support for large 64-bit configurations' CONFIG_MIPS_INSANE_LARGE $CONFIG_MIPS64
+fi
+
+if [ "$CONFIG_ARC32" = "y" ]; then
+   bool 'ARC console support' CONFIG_ARC_CONSOLE
+fi
+
+if [ "$CONFIG_SGI_IP22" = "y" ]; then
+   dep_bool 'Indigo-2 (IP22) EISA bus support' CONFIG_IP22_EISA $CONFIG_EXPERIMENTAL
+fi
+
+if [ "$CONFIG_IP22_EISA" = "y" ]; then
+   define_bool CONFIG_EISA y
+   bool '    ISA bus support' CONFIG_ISA
+fi
+
+bool 'Networking support' CONFIG_NET
+
+if [ "$CONFIG_PCI" != "y" ]; then
+   define_bool CONFIG_PCI n
+fi
+
+source drivers/pci/Config.in
+
+if [ "$CONFIG_ISA" != "y" ]; then
+   define_bool CONFIG_ISA n
+   define_bool CONFIG_EISA n
+else
+   define_bool CONFIG_EISA y
+fi
+
+dep_bool 'TURBOchannel support' CONFIG_TC $CONFIG_DECSTATION
+#dep_bool 'Access.Bus support' CONFIG_ACCESSBUS $CONFIG_TC
+
+define_bool CONFIG_MCA n
+define_bool CONFIG_SBUS n
+
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+
+if [ "$CONFIG_HOTPLUG" = "y" ] ; then
+   source drivers/pcmcia/Config.in
+   source drivers/hotplug/Config.in
+else
+   define_bool CONFIG_PCMCIA n
+   define_bool CONFIG_HOTPLUG_PCI n
+fi
+
+bool 'System V IPC' CONFIG_SYSVIPC
+bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+bool 'Sysctl support' CONFIG_SYSCTL
+define_bool CONFIG_KCORE_ELF y
+define_bool CONFIG_KCORE_AOUT n
+define_bool CONFIG_BINFMT_AOUT n
+tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+dep_bool 'Kernel support for Linux/MIPS 32-bit binary compatibility' CONFIG_MIPS32_COMPAT $CONFIG_MIPS64
+define_bool CONFIG_BINFMT_ELF32 $CONFIG_MIPS32_COMPAT
+
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+
+dep_bool 'Power Management support (EXPERIMENTAL)' CONFIG_PM $CONFIG_EXPERIMENTAL $CONFIG_MIPS_AU1000
+endmenu
+
+source drivers/mtd/Config.in
+
+source drivers/parport/Config.in
+
+source drivers/pnp/Config.in
+
+source drivers/block/Config.in
+if [ "$CONFIG_BLK_DEV_INITRD" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'MIPS initrd options'
+   bool '  Embed root filesystem ramdisk into the kernel' CONFIG_EMBEDDED_RAMDISK
+   endmenu
+fi
+
+source drivers/md/Config.in
+
+if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
+fi
+
+source drivers/telephony/Config.in
+
+mainmenu_option next_comment
+comment 'ATA/IDE/MFM/RLL support'
+
+tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
+
+if [ "$CONFIG_IDE" != "n" ]; then
+   source drivers/ide/Config.in
+else
+   define_bool CONFIG_BLK_DEV_IDE_MODES n
+   define_bool CONFIG_BLK_DEV_HD n
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'SCSI support'
+
+tristate 'SCSI support' CONFIG_SCSI
+
+if [ "$CONFIG_SCSI" != "n" ]; then
+   source drivers/scsi/Config.in
+fi
+endmenu
+
+if [ "$CONFIG_PCI" = "y" ]; then
+   source drivers/message/i2o/Config.in
+fi
+
+if [ "$CONFIG_NET" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Network device support'
+
+   bool 'Network device support' CONFIG_NETDEVICES
+   if [ "$CONFIG_NETDEVICES" = "y" ]; then
+      source drivers/net/Config.in
+      if [ "$CONFIG_ATM" = "y" ]; then
+	 source drivers/atm/Config.in
+      fi
+   fi
+   endmenu
+fi
+
+source net/ax25/Config.in
+
+source net/irda/Config.in
+
+if [ "$CONFIG_NET" != "n" ]; then
+   mainmenu_option next_comment
+   comment 'ISDN subsystem'
+
+   tristate 'ISDN support' CONFIG_ISDN
+   if [ "$CONFIG_ISDN" != "n" ]; then
+      source drivers/isdn/Config.in
+   fi
+   endmenu
+fi
+
+if [ "$CONFIG_ISA" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Old CD-ROM drivers (not SCSI, not IDE)'
+
+   bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
+   if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
+      source drivers/cdrom/Config.in
+   fi
+   endmenu
+fi
+
+#
+# input before char - char/joystick depends on it. As does USB.
+#
+source drivers/input/Config.in
+source drivers/char/Config.in
+
+#source drivers/misc/Config.in
+
+if [ "$CONFIG_DECSTATION" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'DECStation Character devices'
+
+   tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL
+   dep_bool '  DZ11 Serial Support' CONFIG_DZ $CONFIG_SERIAL
+   dep_bool '  Z85C30 Serial Support' CONFIG_ZS $CONFIG_SERIAL $CONFIG_TC
+   dep_bool '  Support for console on serial port' CONFIG_SERIAL_CONSOLE $CONFIG_SERIAL
+#   dep_bool 'MAXINE Access.Bus mouse (VSXXX-BB/GB) support' CONFIG_DTOP_MOUSE $CONFIG_ACCESSBUS
+   bool 'Enhanced Real Time Clock Support' CONFIG_RTC
+   endmenu
+fi
+
+if [ "$CONFIG_SGI_IP22" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'SGI Character devices'
+   if [ "$CONFIG_VT" = "y" ]; then
+      tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE
+      if [ "$CONFIG_SGI_NEWPORT_CONSOLE" = "y" ]; then
+	 define_bool CONFIG_FONT_8x16 y
+      fi
+      define_bool CONFIG_DUMMY_CONSOLE y
+   fi
+   endmenu
+fi
+
+source fs/Config.in
+
+source drivers/media/Config.in
+
+if [ "$CONFIG_VT" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Console drivers'
+   bool 'VGA text console' CONFIG_VGA_CONSOLE
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'MDA text console (dual-headed) (EXPERIMENTAL)' CONFIG_MDA_CONSOLE
+      source drivers/video/Config.in
+   fi
+   endmenu
+fi
+
+mainmenu_option next_comment
+comment 'Sound'
+
+tristate 'Sound card support' CONFIG_SOUND
+if [ "$CONFIG_SOUND" != "n" ]; then
+   source drivers/sound/Config.in
+fi
+endmenu
+
+if [ "$CONFIG_SGI_IP22" = "y" ]; then
+   source drivers/sgi/Config.in
+fi
+
+source drivers/usb/Config.in
+
+source net/bluetooth/Config.in
+
+mainmenu_option next_comment
+comment 'Kernel hacking'
+
+bool 'Are you using a crosscompiler' CONFIG_CROSSCOMPILE
+if [ "$CONFIG_SERIAL" = "y" -o "$CONFIG_AU1000_UART" = "y" ]; then
+   bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
+   dep_bool 'Console output to GDB' CONFIG_GDB_CONSOLE $CONFIG_REMOTE_DEBUG
+fi
+bool 'Enable run-time debugging' CONFIG_DEBUG
+bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+if [ "$CONFIG_SMP" != "y" ]; then
+   bool 'Run uncached' CONFIG_MIPS_UNCACHED
+fi
+endmenu
+
+source lib/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/config.in linux-2.4.20/arch/mips/config.in
--- linux-2.4.19/arch/mips/config.in	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/config.in	2002-10-29 11:18:49.000000000 +0000
@@ -4,631 +4,6 @@
 #
 define_bool CONFIG_MIPS y
 define_bool CONFIG_MIPS32 y
+define_bool CONFIG_MIPS64 n
 
-mainmenu_name "Linux/MIPS Kernel Configuration"
-
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
-
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
-   bool '  Kernel module loader' CONFIG_KMOD
-fi
-endmenu
-
-mainmenu_option next_comment
-comment 'Machine selection'
-dep_bool 'Support for Acer PICA 1 chipset (EXPERIMENTAL)' CONFIG_ACER_PICA_61 $CONFIG_EXPERIMENTAL
-bool 'Support for Alchemy Semi PB1000 board' CONFIG_MIPS_PB1000
-if [ "$CONFIG_MIPS_PB1000" = "y" ]; then
-   bool '  Support for PCI AUTO Config' CONFIG_PCI_AUTO
-fi
-bool 'Support for Alchemy Semi PB1500 board' CONFIG_MIPS_PB1500
-dep_bool 'Support for Algorithmics P4032 (EXPERIMENTAL)' CONFIG_ALGOR_P4032 $CONFIG_EXPERIMENTAL
-dep_bool 'Support for BAGET MIPS series (EXPERIMENTAL)' CONFIG_BAGET_MIPS $CONFIG_EXPERIMENTAL
-dep_bool 'Support for Cobalt Server (EXPERIMENTAL)' CONFIG_MIPS_COBALT $CONFIG_EXPERIMENTAL
-bool 'Support for DECstations' CONFIG_DECSTATION
-dep_bool 'Support for Galileo EV64120 Evaluation board (EXPERIMENTAL)' CONFIG_MIPS_EV64120 $CONFIG_EXPERIMENTAL
-if [ "$CONFIG_MIPS_EV64120" = "y" ]; then
-   bool '  Enable Second PCI (PCI1)' CONFIG_EVB_PCI1
-   choice '  Galileo Chip Clock' \
-	"75	CONFIG_SYSCLK_75 \
-	 83.3	CONFIG_SYSCLK_83 \
-	 100	CONFIG_SYSCLK_100" 83.3
-fi
-dep_bool 'Support for Galileo EV96100 Evaluation board (EXPERIMENTAL)' CONFIG_MIPS_EV96100 $CONFIG_EXPERIMENTAL
-bool 'Support for Globespan IVR board' CONFIG_MIPS_IVR
-bool 'Support for Hewlett Packard LaserJet board' CONFIG_HP_LASERJET
-bool 'Support for ITE 8172G board' CONFIG_MIPS_ITE8172
-if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then
-   bool '  Support for older IT8172 (Rev C)' CONFIG_IT8172_REVC
-fi
-dep_bool 'Support for MIPS Atlas board (EXPERIMENTAL)' CONFIG_MIPS_ATLAS $CONFIG_EXPERIMENTAL
-bool 'Support for MIPS Magnum 4000' CONFIG_MIPS_MAGNUM_4000
-dep_bool 'Support for MIPS Malta board (EXPERIMENTAL)' CONFIG_MIPS_MALTA $CONFIG_EXPERIMENTAL
-bool 'Support for Momentum Ocelot board' CONFIG_MOMENCO_OCELOT
-dep_bool 'Support for NEC DDB Vrc-5074 (EXPERIMENTAL)' CONFIG_DDB5074 $CONFIG_EXPERIMENTAL
-bool 'Support for NEC DDB Vrc-5476' CONFIG_DDB5476
-bool 'Support for NEC DDB Vrc-5477' CONFIG_DDB5477
-bool 'Support for NEC Osprey board' CONFIG_NEC_OSPREY
-bool 'Support for Olivetti M700-10' CONFIG_OLIVETTI_M700
-dep_bool 'Support for Philips Nino (EXPERIMENTAL)' CONFIG_NINO $CONFIG_EXPERIMENTAL
-if [ "$CONFIG_NINO" = "y" ]; then
-   choice 'Nino Model Number' \
-	"Model-300/301/302/319			CONFIG_NINO_4MB \
-	 Model-200/210/312/320/325/350/390	CONFIG_NINO_8MB \
-	 Model-500/510				CONFIG_NINO_16MB" Model-200
-fi
-bool 'Support for SGI IP22 (Indy/Indigo2)' CONFIG_SGI_IP22
-dep_bool 'Support for SiByte SB1250 SOC (EXPERIMENTAL)' CONFIG_SIBYTE_SB1250 $CONFIG_EXPERIMENTAL
-if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then
-   bool '  Support for SB1250 onchip PCI controller' CONFIG_PCI
-   bool '  Support for SB1250 profiling - SB1/SCD perf counters' CONFIG_SIBYTE_SB1250_PROF
-   bool '  Support for BCM1250 profiling using trace buffer' CONFIG_BCM1250_TBPROF
-   bool '  Remote debugging (kgdb over UART 1)' CONFIG_REMOTE_DEBUG
-   bool '  Support for SiByte SWARM board' CONFIG_SIBYTE_SWARM
-   if [ "$CONFIG_SIBYTE_SWARM" = "y" ]; then
-      bool '    Running under simulation' CONFIG_SIMULATION
-      bool '    Configure for L3proc Demo' CONFIG_L3DEMO
-      int '    Maximum memory chunks' CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS 16
-      bool '    Multi-Processing support' CONFIG_SMP
-   fi
-fi
-bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI
-bool 'Support for Toshiba JMR-TX3927 board' CONFIG_TOSHIBA_JMR3927
-
-dep_bool 'High Memory Support (EXPERIMENTAL)' CONFIG_HIGHMEM $CONFIG_EXPERIMENTAL
-
-define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
-define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
-
-#
-# Select some configuration options automatically based on user selections.
-#
-
-if [ "$CONFIG_ACER_PICA_61" = "y" ]; then
-   define_bool CONFIG_ARC32 y
-   define_bool CONFIG_I8259 y
-   define_bool CONFIG_ISA y
-   define_bool CONFIG_MIPS_JAZZ y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_PC_KEYB y
-   define_bool CONFIG_ROTTEN_IRQ y
-   define_bool CONFIG_OLD_TIME_C y
-fi
-if [ "$CONFIG_MIPS_PB1000" = "y" ]; then
-   define_bool CONFIG_MIPS_AU1000 y
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_NEW_PCI y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_PC_KEYB y
-   define_int  MAX_HWIFS 1
-fi
-if [ "$CONFIG_MIPS_PB1500" = "y" ]; then
-   define_bool CONFIG_MIPS_AU1000 y
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_PCI_AUTO y
-   define_bool CONFIG_NEW_PCI y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_PC_KEYB y
-fi
-if [ "$CONFIG_ALGOR_P4032" = "y" ]; then
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_OLD_TIME_C y
-fi
-if [ "$CONFIG_MIPS_COBALT" = "y" ]; then
-   define_bool CONFIG_COBALT_LCD y
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_NEW_TIME_C y
-   define_bool CONFIG_NONCOHERENT_IO y
-fi
-if [ "$CONFIG_DECSTATION" = "y" ]; then
-   define_bool CONFIG_IRQ_CPU y
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_NONCOHERENT_IO y
-fi
-if [ "$CONFIG_MIPS_EV64120" = "y" ]; then
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_ISA n
-   define_bool CONFIG_MIPS_GT64120 y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_OLD_TIME_C y
-fi
-if [ "$CONFIG_MIPS_EV96100" = "y" ]; then
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_MIPS_GT96100 y
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_NEW_PCI y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_PCI_AUTO y
-   define_bool CONFIG_SWAP_IO_SPACE y
-fi
-if [ "$CONFIG_MIPS_IVR" = "y" ]; then
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_PC_KEYB y
-   define_bool CONFIG_NEW_PCI y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_PCI_AUTO y
-   define_bool CONFIG_IT8172_CIR y
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_NEW_TIME_C y
-fi
-if [ "$CONFIG_HP_LASERJET" = "y" ]; then
-   define_bool CONFIG_IRQ_CPU y
-   define_bool CONFIG_NEW_TIME_C y
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_NEW_PCI y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_PCI y
-   #not yet define_bool CONFIG_PCI_AUTO y
-fi
-if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_IT8712 y
-   define_bool CONFIG_PC_KEYB y
-   define_bool CONFIG_NEW_PCI y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_PCI_AUTO y
-   define_bool CONFIG_IT8172_CIR y
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_NEW_TIME_C y
-fi
-if [ "$CONFIG_MIPS_ATLAS" = "y" ]; then
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_NEW_TIME_C y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_SWAP_IO_SPACE y
-fi
-if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \
-     "$CONFIG_OLIVETTI_M700" = "y" ]; then
-   define_bool CONFIG_ARC32 y
-   define_bool CONFIG_I8259 y
-   define_bool CONFIG_ISA y
-   define_bool CONFIG_FB y
-   define_bool CONFIG_FB_G364 y
-   define_bool CONFIG_MIPS_JAZZ y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_PC_KEYB y
-   define_bool CONFIG_OLD_TIME_C y
-fi
-if [ "$CONFIG_MIPS_MALTA" = "y" ]; then
-   define_bool CONFIG_I8259 y
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_HAVE_STD_PC_SERIAL_PORT y
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_NEW_TIME_C y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_SWAP_IO_SPACE y
-   define_bool CONFIG_PC_KEYB y
-fi
-if [ "$CONFIG_MOMENCO_OCELOT" = "y" ]; then
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_SYSCLK_100 y
-   define_bool CONFIG_SWAP_IO_SPACE y
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_OLD_TIME_C y
-fi
-if [ "$CONFIG_DDB5074" = "y" ]; then
-   define_bool CONFIG_HAVE_STD_PC_SERIAL_PORT y
-   define_bool CONFIG_I8259 y
-   define_bool CONFIG_ISA y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_PC_KEYB y
-   define_bool CONFIG_ROTTEN_IRQ y
-   define_bool CONFIG_OLD_TIME_C y
-fi
-if [ "$CONFIG_DDB5476"  = "y" ]; then
-   define_bool CONFIG_ISA y
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_PC_KEYB y
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_IRQ_CPU y
-   define_bool CONFIG_I8259 y
-   define_bool CONFIG_HAVE_STD_PC_SERIAL_PORT y
-   define_bool CONFIG_NEW_PCI y
-   define_bool CONFIG_PCI_AUTO y
-   define_bool CONFIG_NEW_TIME_C y
-   define_bool CONFIG_NONCOHERENT_IO y
-fi
-if [ "$CONFIG_DDB5477" = "y" ]; then
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_NEW_TIME_C y
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_IRQ_CPU y
-   define_bool CONFIG_NEW_PCI y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_PCI_AUTO y
-   define_bool CONFIG_DUMMY_KEYB y
-fi
-if [ "$CONFIG_NEC_OSPREY" = "y" ]; then
-   define_bool CONFIG_VR4181 y
-   define_bool CONFIG_SERIAL y
-   define_bool CONFIG_SERIAL_MANY_PORTS y
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_IRQ_CPU y
-   define_bool CONFIG_NEW_TIME_C y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_DUMMY_KEYB y
-   define_bool CONFIG_SCSI n
-fi
-if [ "$CONFIG_NINO" = "y" ]; then
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_NEW_TIME_C y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_PC_KEYB y
-fi
-if [ "$CONFIG_SGI_IP22" = "y" ]; then
-   define_bool CONFIG_ARC32 y
-   define_bool CONFIG_BOARD_SCACHE y
-   define_bool CONFIG_IRQ_CPU y
-   define_bool CONFIG_PC_KEYB y
-   define_bool CONFIG_SGI y
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_NEW_TIME_C y
-   define_bool CONFIG_NONCOHERENT_IO y
-fi
-if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_NEW_TIME_C y
-   define_bool CONFIG_DUMMY_KEYB y
-   define_bool CONFIG_SWAP_IO_SPACE y
-fi
-if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then
-   define_bool CONFIG_ARC32 y
-   define_bool CONFIG_I8259 y
-   define_bool CONFIG_ISA y
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_OLD_TIME_C y
-   define_bool CONFIG_PC_KEYB y
-   define_bool CONFIG_PCI y
-fi
-if [ "$CONFIG_TOSHIBA_JMR3927" = "y" ]; then
-   define_bool CONFIG_TOSHIBA_BOARDS y
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_NEW_PCI y
-   define_bool CONFIG_PCI_AUTO y
-   define_bool CONFIG_NEW_IRQ y
-   define_bool CONFIG_NEW_TIME_C y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_SWAP_IO_SPACE y
-   define_bool CONFIG_PC_KEYB y
-fi
-
-if [ "$CONFIG_MIPS_AU1000" != "y" ]; then
-   define_bool CONFIG_MIPS_AU1000 n
-fi
-endmenu
-
-mainmenu_option next_comment
-comment 'CPU selection'
-
-choice 'CPU type' \
-	"R3000	CONFIG_CPU_R3000 \
-	 R39XX	CONFIG_CPU_TX39XX \
-	 R6000	CONFIG_CPU_R6000 \
-	 R41xx	CONFIG_CPU_VR41XX \
-	 R4300	CONFIG_CPU_R4300 \
-	 R4x00	CONFIG_CPU_R4X00 \
-	 R49XX	CONFIG_CPU_TX49XX \
-	 R5000	CONFIG_CPU_R5000 \
-	 R5432	CONFIG_CPU_R5432 \
-	 RM7000	CONFIG_CPU_RM7000 \
-	 R52xx	CONFIG_CPU_NEVADA \
-	 R10000	CONFIG_CPU_R10000 \
-	 SB1	CONFIG_CPU_SB1 \
-	 MIPS32	CONFIG_CPU_MIPS32 \
-	 MIPS64	CONFIG_CPU_MIPS64" R4x00
-
-if [ "$CONFIG_CPU_MIPS32" = "y" ]; then
-   define_bool CONFIG_CPU_HAS_PREFETCH y
-   bool '  Support for Virtual Tagged I-cache' CONFIG_VTAG_ICACHE
-fi
-
-if [ "$CONFIG_CPU_MIPS64" = "y" ]; then
-   define_bool CONFIG_CPU_HAS_PREFETCH y
-   bool '  Support for Virtual Tagged I-cache' CONFIG_VTAG_ICACHE
-fi
-
-if [ "$CONFIG_CPU_RM7000" = "y" ]; then
-   define_bool CONFIG_CPU_HAS_PREFETCH y
-fi
-
-if [ "$CONFIG_CPU_SB1" = "y" ]; then
-   bool '  Workarounds for pass 1 sb1 bugs' CONFIG_SB1_PASS_1_WORKAROUNDS
-   bool '  Support for SB1 Cache Error handler' CONFIG_SB1_CACHE_ERROR
-   define_bool CONFIG_VTAG_ICACHE y
-   define_bool CONFIG_CPU_HAS_PREFETCH y
-fi
-
-if [ "$CONFIG_CPU_R4X00"  = "y" -o \
-     "$CONFIG_CPU_R5000" = "y" -o \
-     "$CONFIG_CPU_RM7000" = "y" -o \
-     "$CONFIG_CPU_R10000" = "y" -o \
-     "$CONFIG_CPU_SB1" = "y" -o \
-     "$CONFIG_CPU_MIPS32" = "y" -o \
-     "$CONFIG_CPU_MIPS64" = "y" ]; then
-   bool '  Support for 64-bit physical address space' CONFIG_64BIT_PHYS_ADDR
-fi
-
-bool 'Override CPU Options' CONFIG_CPU_ADVANCED
-if [ "$CONFIG_CPU_ADVANCED" = "y" ]; then
-   bool '  ll/sc Instructions available' CONFIG_CPU_HAS_LLSC
-   bool '  lld/scd Instructions available' CONFIG_CPU_HAS_LLDSCD
-   bool '  Writeback Buffer available' CONFIG_CPU_HAS_WB
-else
-   if [ "$CONFIG_CPU_R3000" = "y" -o \
-        "$CONFIG_CPU_VR41XX" = "y" -o    \
-        "$CONFIG_CPU_TX39XX" = "y" ]; then
-      if [ "$CONFIG_DECSTATION" = "y" ]; then
-	 define_bool CONFIG_CPU_HAS_LLSC n
-	 define_bool CONFIG_CPU_HAS_LLDSCD n
-	 define_bool CONFIG_CPU_HAS_WB y
-      else
-	 define_bool CONFIG_CPU_HAS_LLSC n
-	 define_bool CONFIG_CPU_HAS_LLDSCD n
-	 define_bool CONFIG_CPU_HAS_WB n
-      fi
-   else
-      if [ "$CONFIG_CPU_MIPS32" = "y" ]; then
-	 define_bool CONFIG_CPU_HAS_LLSC y
-	 define_bool CONFIG_CPU_HAS_LLDSCD n
-	 define_bool CONFIG_CPU_HAS_WB n
-      else
-	 define_bool CONFIG_CPU_HAS_LLSC y
-	 define_bool CONFIG_CPU_HAS_LLDSCD y
-	 define_bool CONFIG_CPU_HAS_WB n
-      fi
-   fi
-fi
-endmenu
-
-mainmenu_option next_comment
-comment 'General setup'
-if [ "$CONFIG_DECSTATION" = "y" -o \
-     "$CONFIG_DDB5074" = "y" -o    \
-     "$CONFIG_NINO" = "y" -o       \
-     "$CONFIG_MIPS_COBALT" = "y" ]; then
-   define_bool CONFIG_CPU_LITTLE_ENDIAN y
-else
-   bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
-fi
-
-if [ "$CONFIG_TOSHIBA_JMR3927" = "y" ]; then
-       bool 'DS1742 BRAM/RTC support' CONFIG_RTC_DS1742
-fi
-
-if [ "$CONFIG_CPU_LITTLE_ENDIAN" = "n" ]; then
-   bool 'Include IRIX binary compatibility' CONFIG_BINFMT_IRIX
-   bool 'Include forward keyboard' CONFIG_FORWARD_KEYBOARD
-fi
-
-if [ "$CONFIG_ARC32" = "y" ]; then
-   bool 'ARC console support' CONFIG_ARC_CONSOLE
-fi
-
-bool 'Networking support' CONFIG_NET
-
-if [ "$CONFIG_PCI" != "y" ]; then
-   define_bool CONFIG_PCI n
-fi
-
-source drivers/pci/Config.in
-
-if [ "$CONFIG_ISA" != "y" ]; then
-   define_bool CONFIG_ISA n
-   define_bool CONFIG_EISA n
-else
-   define_bool CONFIG_EISA y
-fi
-
-dep_bool 'TURBOchannel support' CONFIG_TC $CONFIG_DECSTATION
-#dep_bool 'Access.Bus support' CONFIG_ACCESSBUS $CONFIG_TC
-
-define_bool CONFIG_MCA n
-define_bool CONFIG_SBUS n
-
-bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
-
-if [ "$CONFIG_HOTPLUG" = "y" ] ; then
-   source drivers/pcmcia/Config.in
-   source drivers/hotplug/Config.in
-else
-   define_bool CONFIG_PCMCIA n
-   define_bool CONFIG_HOTPLUG_PCI n
-fi
-
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
-define_bool CONFIG_KCORE_ELF y
-define_bool CONFIG_KCORE_AOUT n
-define_bool CONFIG_BINFMT_AOUT n
-define_bool CONFIG_BINFMT_ELF y
-tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-
-dep_bool 'Power Management support (EXPERIMENTAL)' CONFIG_PM $CONFIG_EXPERIMENTAL $CONFIG_MIPS_AU1000
-endmenu
-
-source drivers/mtd/Config.in
-
-source drivers/parport/Config.in
-
-source drivers/pnp/Config.in
-
-source drivers/block/Config.in
-if [ "$CONFIG_BLK_DEV_INITRD" = "y" ]; then
-   mainmenu_option next_comment
-   comment 'MIPS initrd options'
-   bool '  Embed root filesystem ramdisk into the kernel' CONFIG_EMBEDDED_RAMDISK
-   endmenu
-fi
-
-source drivers/md/Config.in
-
-if [ "$CONFIG_NET" = "y" ]; then
-   source net/Config.in
-fi
-
-source drivers/telephony/Config.in
-
-if [ "$CONFIG_ISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
-
-   mainmenu_option next_comment
-   comment 'ATA/IDE/MFM/RLL support'
-
-   tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
-
-   if [ "$CONFIG_IDE" != "n" ]; then
-      source drivers/ide/Config.in
-   else
-      define_bool CONFIG_BLK_DEV_IDE_MODES n
-      define_bool CONFIG_BLK_DEV_HD n
-   fi
-   endmenu
-fi
-
-mainmenu_option next_comment
-comment 'SCSI support'
-
-tristate 'SCSI support' CONFIG_SCSI
-
-if [ "$CONFIG_SCSI" != "n" ]; then
-   source drivers/scsi/Config.in
-fi
-endmenu
-
-if [ "$CONFIG_PCI" = "y" ]; then
-   source drivers/message/i2o/Config.in
-fi
-
-if [ "$CONFIG_NET" = "y" ]; then
-   mainmenu_option next_comment
-   comment 'Network device support'
-
-   bool 'Network device support' CONFIG_NETDEVICES
-   if [ "$CONFIG_NETDEVICES" = "y" ]; then
-      source drivers/net/Config.in
-      if [ "$CONFIG_ATM" = "y" ]; then
-	 source drivers/atm/Config.in
-      fi
-   fi
-   endmenu
-fi
-
-source net/ax25/Config.in
-
-source net/irda/Config.in
-
-if [ "$CONFIG_NET" != "n" ]; then
-   mainmenu_option next_comment
-   comment 'ISDN subsystem'
-
-   tristate 'ISDN support' CONFIG_ISDN
-   if [ "$CONFIG_ISDN" != "n" ]; then
-      source drivers/isdn/Config.in
-   fi
-   endmenu
-fi
-
-if [ "$CONFIG_ISA" = "y" ]; then
-   mainmenu_option next_comment
-   comment 'Old CD-ROM drivers (not SCSI, not IDE)'
-
-   bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
-   if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
-      source drivers/cdrom/Config.in
-   fi
-   endmenu
-fi
-
-source drivers/char/Config.in
-
-#source drivers/misc/Config.in
-
-source drivers/media/Config.in
-
-if [ "$CONFIG_DECSTATION" = "y" ]; then
-   mainmenu_option next_comment
-   comment 'DECStation Character devices'
-
-   tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL
-   dep_bool '  DZ11 Serial Support' CONFIG_DZ $CONFIG_SERIAL
-   dep_bool '  Z85C30 Serial Support' CONFIG_ZS $CONFIG_SERIAL $CONFIG_TC
-   dep_bool '  Support for console on serial port' CONFIG_SERIAL_CONSOLE $CONFIG_SERIAL
-#   dep_bool 'MAXINE Access.Bus mouse (VSXXX-BB/GB) support' CONFIG_DTOP_MOUSE $CONFIG_ACCESSBUS
-   bool 'Enhanced Real Time Clock Support' CONFIG_RTC
-   endmenu
-fi
-
-if [ "$CONFIG_SGI_IP22" = "y" ]; then
-   mainmenu_option next_comment
-   comment 'SGI Character devices'
-   if [ "$CONFIG_VT" = "y" ]; then
-      tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE
-      if [ "$CONFIG_SGI_NEWPORT_CONSOLE" = "y" ]; then
-	 define_bool CONFIG_FONT_8x16 y
-      fi
-      define_bool CONFIG_DUMMY_CONSOLE y
-   fi
-   endmenu
-fi
-
-source fs/Config.in
-
-if [ "$CONFIG_VT" = "y" ]; then
-   mainmenu_option next_comment
-   comment 'Console drivers'
-   bool 'VGA text console' CONFIG_VGA_CONSOLE
-   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'MDA text console (dual-headed) (EXPERIMENTAL)' CONFIG_MDA_CONSOLE
-      source drivers/video/Config.in
-   fi
-   endmenu
-fi
-
-mainmenu_option next_comment
-comment 'Sound'
-
-tristate 'Sound card support' CONFIG_SOUND
-if [ "$CONFIG_SOUND" != "n" ]; then
-   source drivers/sound/Config.in
-fi
-endmenu
-
-if [ "$CONFIG_SGI_IP22" = "y" ]; then
-   source drivers/sgi/Config.in
-fi
-
-source drivers/usb/Config.in
-
-source net/bluetooth/Config.in
-
-source drivers/input/Config.in
-
-mainmenu_option next_comment
-comment 'Kernel hacking'
-
-bool 'Are you using a crosscompiler' CONFIG_CROSSCOMPILE
-if [ "$CONFIG_SERIAL" = "y" -o "$CONFIG_AU1000_UART" = "y" ]; then
-  bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
-  dep_bool 'Console output to GDB' CONFIG_GDB_CONSOLE $CONFIG_REMOTE_DEBUG
-fi
-bool 'Enable run-time debugging' CONFIG_DEBUG
-bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
-if [ "$CONFIG_SMP" != "y" ]; then
-   bool 'Run uncached' CONFIG_MIPS_UNCACHED
-fi
-endmenu
+source arch/mips/config-shared.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5074/Makefile linux-2.4.20/arch/mips/ddb5074/Makefile
--- linux-2.4.19/arch/mips/ddb5074/Makefile	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5074/Makefile	2002-10-29 11:18:33.000000000 +0000
@@ -9,10 +9,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 #
 
-.S.s:
-	$(CPP) $(CFLAGS) $< -o $*.s
-.S.o:
-	$(CC) $(CFLAGS) -c $< -o $*.o
+USE_STANDARD_AS_RULE := true
 
 O_TARGET = ddb5074.a
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5074/irq.c linux-2.4.20/arch/mips/ddb5074/irq.c
--- linux-2.4.19/arch/mips/ddb5074/irq.c	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5074/irq.c	2002-10-29 11:18:50.000000000 +0000
@@ -60,9 +60,9 @@
 	 *
 	 *      IRQ1  - keyboard (default set by M1543)
 	 *      IRQ3  - reserved for UART B (default set by M1543) (note that
-	 *              the schematics for the DDB Vrc-5074 board seem to 
-	 *              indicate that IRQ3 is connected to the DS1386 
-	 *              watchdog timer interrupt output so we might have 
+	 *              the schematics for the DDB Vrc-5074 board seem to
+	 *              indicate that IRQ3 is connected to the DS1386
+	 *              watchdog timer interrupt output so we might have
 	 *              a conflict)
 	 *      IRQ4  - reserved for UART A (default set by M1543)
 	 *      IRQ5  - parallel (default set by M1543)
@@ -71,7 +71,7 @@
 	 */
 
 	/*
-	 *  Assing mouse interrupt to IRQ12 
+	 *  Assing mouse interrupt to IRQ12
 	 */
 
 	/* Enter configuration mode */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5074/pci.c linux-2.4.20/arch/mips/ddb5074/pci.c
--- linux-2.4.19/arch/mips/ddb5074/pci.c	2001-09-09 17:43:01.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5074/pci.c	2002-10-29 11:18:40.000000000 +0000
@@ -396,7 +396,7 @@
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-			    unsigned long size)
+			    unsigned long size, unsigned long align)
 {
 	struct pci_dev *dev = data;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5074/setup.c linux-2.4.20/arch/mips/ddb5074/setup.c
--- linux-2.4.19/arch/mips/ddb5074/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5074/setup.c	2002-10-29 11:18:34.000000000 +0000
@@ -25,6 +25,7 @@
 #include <asm/gdb-stub.h>
 #include <asm/nile4.h>
 #include <asm/ddb5074.h>
+#include <asm/traps.h>
 
 
 #ifdef CONFIG_REMOTE_DEBUG
@@ -91,6 +92,10 @@
 		          IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4);
 }
 
+
+void __init bus_error_init(void) { /* nothing */ }
+
+
 void __init ddb_setup(void)
 {
 	extern int panic_timeout;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/common/Makefile linux-2.4.20/arch/mips/ddb5xxx/common/Makefile
--- linux-2.4.19/arch/mips/ddb5xxx/common/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/common/Makefile	2002-10-29 11:18:38.000000000 +0000
@@ -6,10 +6,7 @@
 # unless it's something special (ie not a .c file).
 #
 
-.S.s:
-	$(CPP) $(CFLAGS) $< -o $*.s
-.S.o:
-	$(CC) $(CFLAGS) -c $< -o $*.o
+USE_STANDARD_AS_RULE := true
 
 O_TARGET:= ddb5xxx.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/common/irq.c linux-2.4.20/arch/mips/ddb5xxx/common/irq.c
--- linux-2.4.19/arch/mips/ddb5xxx/common/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/common/irq.c	2002-10-29 11:18:49.000000000 +0000
@@ -13,6 +13,7 @@
  */
 #include <linux/config.h>
 #include <linux/init.h>
+#include <asm/irq.h>
 
 void (*irq_setup)(void);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/common/nile4.c linux-2.4.20/arch/mips/ddb5xxx/common/nile4.c
--- linux-2.4.19/arch/mips/ddb5xxx/common/nile4.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/common/nile4.c	2002-10-29 11:18:49.000000000 +0000
@@ -16,14 +16,13 @@
  ***********************************************************************
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 
 #include <asm/ddb5xxx/ddb5xxx.h>
 
 u32
-ddb_calc_pdar(u32 phys, u32 size, int width, 
+ddb_calc_pdar(u32 phys, u32 size, int width,
 	      int on_memory_bus, int pci_visible)
 {
         u32 maskbits;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/common/prom.c linux-2.4.20/arch/mips/ddb5xxx/common/prom.c
--- linux-2.4.19/arch/mips/ddb5xxx/common/prom.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/common/prom.c	2002-10-29 11:18:36.000000000 +0000
@@ -26,6 +26,8 @@
 
 char arcs_cmdline[CL_SIZE];
 
+void ddb5477_runtime_detection(void);
+
 const char *get_system_type(void)
 {
 	switch (mips_machtype) {
@@ -33,6 +35,8 @@
 	case MACH_NEC_DDB5476:		return "NEC DDB Vrc-5476";
 	case MACH_NEC_DDB5477:		return "NEC DDB Vrc-5477";
 	case MACH_NEC_ROCKHOPPER:	return "NEC Rockhopper";
+	case MACH_NEC_ROCKHOPPERII:	return "NEC RockhopperII";
+	default:			return "Unknown NEC board";
 	}
 }
 
@@ -92,6 +96,13 @@
            around just after that.
          */
 
+	/* We can only use the PCI bus to distinquish between
+	   the Rockhopper and RockhopperII backplanes and this must
+	   wait until ddb5477_board_init() in setup.c after the 5477
+	   is initialized.  So, until then handle
+	   both Rockhopper and RockhopperII backplanes as Rockhopper 1
+	 */
+
         test_offset = (char *)KSEG1ADDR(DEFAULT_LCS1_BASE + 0x800);
         saved_test_byte = *test_offset;
 
@@ -119,7 +130,7 @@
         *test_offset = saved_test_byte;
 
 	/* before we know a better way, we will trust PMON for getting
-	 * RAM size 
+	 * RAM size
 	 */
 	board_ram_size = 1 << (36 - (ddb_in32(DDB_SDRAM0) & 0xf));
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/common/rtc_ds1386.c linux-2.4.20/arch/mips/ddb5xxx/common/rtc_ds1386.c
--- linux-2.4.19/arch/mips/ddb5xxx/common/rtc_ds1386.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/common/rtc_ds1386.c	2002-10-29 11:18:35.000000000 +0000
@@ -24,6 +24,7 @@
 #include <asm/time.h>
 #include <asm/addrspace.h>
 
+#include <asm/mc146818rtc.h>
 #include <asm/debug.h>
 
 #define	EPOCH		2000
@@ -41,7 +42,7 @@
 
 static unsigned long
 rtc_ds1386_get_time(void)
-{	
+{
 	u8 byte;
 	u8 temp;
 	unsigned int year, month, day, hour, minute, second;
@@ -78,7 +79,7 @@
 	return mktime(year, month, day, hour, minute, second);
 }
 
-static int 
+static int
 rtc_ds1386_set_time(unsigned long t)
 {
 	struct rtc_time tm;
@@ -94,6 +95,7 @@
 	/* convert */
 	to_tm(t, &tm);
 
+
 	/* check each field one by one */
 	year = BIN_TO_BCD(tm.tm_year - EPOCH);
 	if (year != READ_RTC(0xA)) {
@@ -136,7 +138,7 @@
 	if (second != READ_RTC(0x1)) {
 		WRITE_RTC(0x1, second);
 	}
-	
+
 	return 0;
 }
 
@@ -144,7 +146,7 @@
 rtc_ds1386_init(unsigned long base)
 {
 	unsigned char byte;
-	
+
 	/* remember the base */
 	rtc_base = base;
 	db_assert((rtc_base & 0xe0000000) == KSEG1);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5074/Makefile linux-2.4.20/arch/mips/ddb5xxx/ddb5074/Makefile
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5074/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5074/Makefile	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,18 @@
+#
+# Makefile for the NEC DDB Vrc-5074 specific kernel interface routines
+# under Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+#
+
+USE_STANDARD_AS_RULE := true
+
+O_TARGET = ddb5074.o
+
+obj-y				+= setup.o irq.o int-handler.o pci.o pci_ops.o nile4_pic.o time.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5074/int-handler.S linux-2.4.20/arch/mips/ddb5xxx/ddb5074/int-handler.S
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5074/int-handler.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5074/int-handler.S	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,120 @@
+/*
+ *  arch/mips/ddb5074/int-handler.S -- NEC DDB Vrc-5074 interrupt handler
+ *
+ *  Based on arch/mips/sgi/kernel/indyIRQ.S
+ *
+ *  Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ *                     Sony Software Development Center Europe (SDCE), Brussels
+ */
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+/* A lot of complication here is taken away because:
+ *
+ * 1) We handle one interrupt and return, sitting in a loop and moving across
+ *    all the pending IRQ bits in the cause register is _NOT_ the answer, the
+ *    common case is one pending IRQ so optimize in that direction.
+ *
+ * 2) We need not check against bits in the status register IRQ mask, that
+ *    would make this routine slow as hell.
+ *
+ * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
+ *    between like BSD spl() brain-damage.
+ *
+ * Furthermore, the IRQs on the INDY look basically (barring software IRQs
+ * which we don't use at all) like:
+ *
+ *	MIPS IRQ	Source
+ *      --------        ------
+ *             0	Software (ignored)
+ *             1        Software (ignored)
+ *             2        Local IRQ level zero
+ *             3        Local IRQ level one
+ *             4        8254 Timer zero
+ *             5        8254 Timer one
+ *             6        Bus Error
+ *             7        R4k timer (what we use)
+ *
+ * We handle the IRQ according to _our_ priority which is:
+ *
+ * Highest ----     R4k Timer
+ *                  Local IRQ zero
+ *                  Local IRQ one
+ *                  Bus Error
+ *                  8254 Timer zero
+ * Lowest  ----     8254 Timer one
+ *
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ */
+
+	.text
+	.set	noreorder
+	.set	noat
+	.align	5
+	NESTED(ddbIRQ, PT_SIZE, sp)
+	SAVE_ALL
+	CLI
+	.set	at
+	mfc0	s0, CP0_CAUSE		# get irq mask
+
+#if 1
+	mfc0	t2,CP0_STATUS		# get enabled interrupts
+	and	s0,t2			# isolate allowed ones
+#endif
+	/* First we check for r4k counter/timer IRQ. */
+	andi	a0, s0, CAUSEF_IP2	# delay slot, check local level zero
+	beq	a0, zero, 1f
+	 andi	a0, s0, CAUSEF_IP3	# delay slot, check local level one
+
+	/* Wheee, local level zero interrupt. */
+	jal	ddb_local0_irqdispatch
+	 move	a0, sp			# delay slot
+
+	j	ret_from_irq
+	 nop				# delay slot
+
+1:
+	beq	a0, zero, 1f
+	 andi	a0, s0, CAUSEF_IP6	# delay slot, check bus error
+
+	/* Wheee, local level one interrupt. */
+	move	a0, sp
+	jal	ddb_local1_irqdispatch
+	 nop
+
+	j	ret_from_irq
+	 nop
+
+1:
+	beq	a0, zero, 1f
+	 nop
+
+	/* Wheee, an asynchronous bus error... */
+	move	a0, sp
+	jal	ddb_buserror_irq
+	 nop
+
+	j	ret_from_irq
+	 nop
+
+1:
+	/* Here by mistake?  This is possible, what can happen
+	 * is that by the time we take the exception the IRQ
+	 * pin goes low, so just leave if this is the case.
+	 */
+	andi	a0, s0, (CAUSEF_IP4 | CAUSEF_IP5)
+	beq	a0, zero, 1f
+
+	/* Must be one of the 8254 timers... */
+	move	a0, sp
+	jal	ddb_8254timer_irq
+	 nop
+1:
+	j	ret_from_irq
+	 nop
+	END(ddbIRQ)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5074/irq.c linux-2.4.20/arch/mips/ddb5xxx/ddb5074/irq.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5074/irq.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5074/irq.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,174 @@
+/*
+ *  arch/mips/ddb5074/irq.c -- NEC DDB Vrc-5074 interrupt routines
+ *
+ *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ *                     Sony Software Development Center Europe (SDCE), Brussels
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/irq_cpu.h>
+#include <asm/ptrace.h>
+#include <asm/nile4.h>
+#include <asm/ddb5xxx/ddb5xxx.h>
+#include <asm/ddb5xxx/ddb5074.h>
+
+
+extern void __init i8259_init(void);
+extern void init_i8259_irqs (void);
+extern void i8259_disable_irq(unsigned int irq_nr);
+extern void i8259_enable_irq(unsigned int irq_nr);
+
+extern asmlinkage void ddbIRQ(void);
+extern asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs);
+extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs);
+
+static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL };
+
+#define M1543_PNP_CONFIG	0x03f0	/* PnP Config Port */
+#define M1543_PNP_INDEX		0x03f0	/* PnP Index Port */
+#define M1543_PNP_DATA		0x03f1	/* PnP Data Port */
+
+#define M1543_PNP_ALT_CONFIG	0x0370	/* Alternative PnP Config Port */
+#define M1543_PNP_ALT_INDEX	0x0370	/* Alternative PnP Index Port */
+#define M1543_PNP_ALT_DATA	0x0371	/* Alternative PnP Data Port */
+
+#define M1543_INT1_MASTER_CTRL	0x0020	/* INT_1 (master) Control Register */
+#define M1543_INT1_MASTER_MASK	0x0021	/* INT_1 (master) Mask Register */
+
+#define M1543_INT1_SLAVE_CTRL	0x00a0	/* INT_1 (slave) Control Register */
+#define M1543_INT1_SLAVE_MASK	0x00a1	/* INT_1 (slave) Mask Register */
+
+#define M1543_INT1_MASTER_ELCR	0x04d0	/* INT_1 (master) Edge/Level Control */
+#define M1543_INT1_SLAVE_ELCR	0x04d1	/* INT_1 (slave) Edge/Level Control */
+
+
+static void m1543_irq_setup(void)
+{
+	/*
+	 *  The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13.  Not all
+	 *  the possible IO sources in the M1543 are in use by us.  We will
+	 *  use the following mapping:
+	 *
+	 *      IRQ1  - keyboard (default set by M1543)
+	 *      IRQ3  - reserved for UART B (default set by M1543) (note that
+	 *              the schematics for the DDB Vrc-5074 board seem to
+	 *              indicate that IRQ3 is connected to the DS1386
+	 *              watchdog timer interrupt output so we might have
+	 *              a conflict)
+	 *      IRQ4  - reserved for UART A (default set by M1543)
+	 *      IRQ5  - parallel (default set by M1543)
+	 *      IRQ8  - DS1386 time of day (RTC) interrupt
+	 *      IRQ12 - mouse
+	 */
+
+	/*
+	 *  Assing mouse interrupt to IRQ12
+	 */
+
+	/* Enter configuration mode */
+	outb(0x51, M1543_PNP_CONFIG);
+	outb(0x23, M1543_PNP_CONFIG);
+
+	/* Select logical device 7 (Keyboard) */
+	outb(0x07, M1543_PNP_INDEX);
+	outb(0x07, M1543_PNP_DATA);
+
+	/* Select IRQ12 */
+	outb(0x72, M1543_PNP_INDEX);
+	outb(0x0c, M1543_PNP_DATA);
+
+	outb(0x30, M1543_PNP_INDEX);
+	printk("device 7, 0x30: %02x\n",inb(M1543_PNP_DATA));
+
+	outb(0x70, M1543_PNP_INDEX);
+	printk("device 7, 0x70: %02x\n",inb(M1543_PNP_DATA));
+
+	/* Leave configration mode */
+	outb(0xbb, M1543_PNP_CONFIG);
+
+
+}
+
+void ddb_local0_irqdispatch(struct pt_regs *regs)
+{
+	u32 mask;
+	int nile4_irq;
+
+	mask = nile4_get_irq_stat(0);
+
+	/* Handle the timer interrupt first */
+#if 0
+	if (mask & (1 << NILE4_INT_GPT)) {
+		do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs);
+		mask &= ~(1 << NILE4_INT_GPT);
+	}
+#endif
+	for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1)
+		if (mask & 1) {
+			if (nile4_irq == NILE4_INT_INTE) {
+				int i8259_irq;
+
+				nile4_clear_irq(NILE4_INT_INTE);
+				i8259_irq = nile4_i8259_iack();
+				do_IRQ(i8259_irq, regs);
+			} else
+				do_IRQ(nile4_to_irq(nile4_irq), regs);
+
+		}
+}
+
+void ddb_local1_irqdispatch(void)
+{
+	printk("ddb_local1_irqdispatch called\n");
+}
+
+void ddb_buserror_irq(void)
+{
+	printk("ddb_buserror_irq called\n");
+}
+
+void ddb_8254timer_irq(void)
+{
+	printk("ddb_8254timer_irq called\n");
+}
+
+void __init ddb_irq_setup(void)
+{
+#ifdef CONFIG_REMOTE_DEBUG
+	if (remote_debug)
+		set_debug_traps();
+	breakpoint();		/* you may move this line to whereever you want :-) */
+#endif
+
+	/* setup cascade interrupts */
+	setup_irq(NILE4_IRQ_BASE  + NILE4_INT_INTE, &irq_cascade);
+	setup_irq(CPU_IRQ_BASE + CPU_NILE4_CASCADE, &irq_cascade);
+
+	set_except_vector(0, ddbIRQ);
+
+	nile4_irq_setup(NILE4_IRQ_BASE);
+	m1543_irq_setup();
+	init_i8259_irqs();
+
+
+	printk("CPU_IRQ_BASE: %d\n",CPU_IRQ_BASE);
+
+	mips_cpu_irq_init(CPU_IRQ_BASE);
+
+	printk("enabling 8259 cascade\n");
+
+	ddb5074_led_hex(0);
+
+	/* Enable the interrupt cascade */
+	nile4_enable_irq(NILE4_IRQ_BASE+IRQ_I8259_CASCADE);
+
+
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5074/nile4_pic.c linux-2.4.20/arch/mips/ddb5xxx/ddb5074/nile4_pic.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5074/nile4_pic.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5074/nile4_pic.c	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,288 @@
+/*
+ *  arch/mips/ddb5476/nile4.c --
+ *  	low-level PIC code for NEC Vrc-5476 (Nile 4)
+ *
+ *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ *                     Sony Software Development Center Europe (SDCE), Brussels
+ *
+ *  Copyright 2001 MontaVista Software Inc.
+ *  Author: jsun@mvista.com or jsun@junsun.net
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/addrspace.h>
+
+#include <asm/ddb5xxx/ddb5xxx.h>
+
+static int irq_base;
+
+/*
+ *  Interrupt Programming
+ */
+void nile4_map_irq(int nile4_irq, int cpu_irq)
+{
+	u32 offset, t;
+
+	offset = DDB_INTCTRL;
+	if (nile4_irq >= 8) {
+		offset += 4;
+		nile4_irq -= 8;
+	}
+	t = ddb_in32(offset);
+	t &= ~(7 << (nile4_irq * 4));
+	t |= cpu_irq << (nile4_irq * 4);
+	ddb_out32(offset, t);
+}
+
+void nile4_map_irq_all(int cpu_irq)
+{
+	u32 all, t;
+
+	all = cpu_irq;
+	all |= all << 4;
+	all |= all << 8;
+	all |= all << 16;
+	t = ddb_in32(DDB_INTCTRL);
+	t &= 0x88888888;
+	t |= all;
+	ddb_out32(DDB_INTCTRL, t);
+	t = ddb_in32(DDB_INTCTRL + 4);
+	t &= 0x88888888;
+	t |= all;
+	ddb_out32(DDB_INTCTRL + 4, t);
+}
+
+void nile4_enable_irq(unsigned int nile4_irq)
+{
+	u32 offset, t;
+
+	nile4_irq-=irq_base;
+
+	ddb5074_led_hex(8);
+
+	offset = DDB_INTCTRL;
+	if (nile4_irq >= 8) {
+		offset += 4;
+		nile4_irq -= 8;
+	}
+	ddb5074_led_hex(9);
+	t = ddb_in32(offset);
+	ddb5074_led_hex(0xa);
+	t |= 8 << (nile4_irq * 4);
+	ddb_out32(offset, t);
+	ddb5074_led_hex(0xb);
+}
+
+void nile4_disable_irq(unsigned int nile4_irq)
+{
+	u32 offset, t;
+
+	nile4_irq-=irq_base;
+
+	offset = DDB_INTCTRL;
+	if (nile4_irq >= 8) {
+		offset += 4;
+		nile4_irq -= 8;
+	}
+	t = ddb_in32(offset);
+	t &= ~(8 << (nile4_irq * 4));
+	ddb_out32(offset, t);
+}
+
+void nile4_disable_irq_all(void)
+{
+	ddb_out32(DDB_INTCTRL, 0);
+	ddb_out32(DDB_INTCTRL + 4, 0);
+}
+
+u16 nile4_get_irq_stat(int cpu_irq)
+{
+	return ddb_in16(DDB_INTSTAT0 + cpu_irq * 2);
+}
+
+void nile4_enable_irq_output(int cpu_irq)
+{
+	u32 t;
+
+	t = ddb_in32(DDB_INTSTAT1 + 4);
+	t |= 1 << (16 + cpu_irq);
+	ddb_out32(DDB_INTSTAT1, t);
+}
+
+void nile4_disable_irq_output(int cpu_irq)
+{
+	u32 t;
+
+	t = ddb_in32(DDB_INTSTAT1 + 4);
+	t &= ~(1 << (16 + cpu_irq));
+	ddb_out32(DDB_INTSTAT1, t);
+}
+
+void nile4_set_pci_irq_polarity(int pci_irq, int high)
+{
+	u32 t;
+
+	t = ddb_in32(DDB_INTPPES);
+	if (high)
+		t &= ~(1 << (pci_irq * 2));
+	else
+		t |= 1 << (pci_irq * 2);
+	ddb_out32(DDB_INTPPES, t);
+}
+
+void nile4_set_pci_irq_level_or_edge(int pci_irq, int level)
+{
+	u32 t;
+
+	t = ddb_in32(DDB_INTPPES);
+	if (level)
+		t |= 2 << (pci_irq * 2);
+	else
+		t &= ~(2 << (pci_irq * 2));
+	ddb_out32(DDB_INTPPES, t);
+}
+
+void nile4_clear_irq(int nile4_irq)
+{
+	nile4_irq-=irq_base;
+	ddb_out32(DDB_INTCLR, 1 << nile4_irq);
+}
+
+void nile4_clear_irq_mask(u32 mask)
+{
+	ddb_out32(DDB_INTCLR, mask);
+}
+
+u8 nile4_i8259_iack(void)
+{
+	u8 irq;
+	u32 reg;
+
+	/* Set window 0 for interrupt acknowledge */
+	reg = ddb_in32(DDB_PCIINIT0);
+
+	ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IACK, 0, DDB_PCI_ACCESS_32);
+	irq = *(volatile u8 *) KSEG1ADDR(DDB_PCI_IACK_BASE);
+	/* restore window 0 for PCI I/O space */
+	// ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IO, 0, DDB_PCI_ACCESS_32);
+	ddb_out32(DDB_PCIINIT0, reg);
+
+	/* i8269.c set the base vector to be 0x0 */
+	return irq ;
+}
+
+static unsigned int nile4_irq_startup(unsigned int irq) {
+
+	nile4_enable_irq(irq);
+	return 0;
+
+}
+
+static void nile4_ack_irq(unsigned int irq) {
+
+    ddb5074_led_hex(4);
+
+	nile4_clear_irq(irq);
+    ddb5074_led_hex(2);
+	nile4_disable_irq(irq);
+
+    ddb5074_led_hex(0);
+}
+
+static void nile4_irq_end(unsigned int irq) {
+
+	ddb5074_led_hex(3);
+	if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+	ddb5074_led_hex(5);
+		nile4_enable_irq(irq);
+	ddb5074_led_hex(7);
+	}
+
+	ddb5074_led_hex(1);
+}
+
+#define nile4_irq_shutdown nile4_disable_irq
+
+static hw_irq_controller nile4_irq_controller = {
+    "nile4",
+    nile4_irq_startup,
+    nile4_irq_shutdown,
+    nile4_enable_irq,
+    nile4_disable_irq,
+    nile4_ack_irq,
+    nile4_irq_end,
+    NULL
+};
+
+void nile4_irq_setup(u32 base) {
+
+	int i;
+	extern irq_desc_t irq_desc[];
+
+	irq_base=base;
+
+	/* Map all interrupts to CPU int #0 */
+	nile4_map_irq_all(0);
+
+	/* PCI INTA#-E# must be level triggered */
+	nile4_set_pci_irq_level_or_edge(0, 1);
+	nile4_set_pci_irq_level_or_edge(1, 1);
+	nile4_set_pci_irq_level_or_edge(2, 1);
+	nile4_set_pci_irq_level_or_edge(3, 1);
+	nile4_set_pci_irq_level_or_edge(4, 1);
+
+	/* PCI INTA#-D# must be active low, INTE# must be active high */
+	nile4_set_pci_irq_polarity(0, 0);
+	nile4_set_pci_irq_polarity(1, 0);
+	nile4_set_pci_irq_polarity(2, 0);
+	nile4_set_pci_irq_polarity(3, 0);
+	nile4_set_pci_irq_polarity(4, 1);
+
+
+	for (i = 0; i < 16; i++) {
+		nile4_clear_irq(i);
+		nile4_disable_irq(i);
+	}
+
+	/* Enable CPU int #0 */
+	nile4_enable_irq_output(0);
+
+	for (i= base; i< base + NUM_NILE4_INTERRUPTS; i++) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].action = NULL;
+		irq_desc[i].depth = 1;
+		irq_desc[i].handler = &nile4_irq_controller;
+	}
+
+}
+
+#if defined(CONFIG_LL_DEBUG)
+void nile4_dump_irq_status(void)
+{
+	printk(KERN_DEBUG "
+	       CPUSTAT = %p:%p\n", (void *) ddb_in32(DDB_CPUSTAT + 4),
+	       (void *) ddb_in32(DDB_CPUSTAT));
+	printk(KERN_DEBUG "
+	       INTCTRL = %p:%p\n", (void *) ddb_in32(DDB_INTCTRL + 4),
+	       (void *) ddb_in32(DDB_INTCTRL));
+	printk(KERN_DEBUG
+	       "INTSTAT0 = %p:%p\n",
+	       (void *) ddb_in32(DDB_INTSTAT0 + 4),
+	       (void *) ddb_in32(DDB_INTSTAT0));
+	printk(KERN_DEBUG
+	       "INTSTAT1 = %p:%p\n",
+	       (void *) ddb_in32(DDB_INTSTAT1 + 4),
+	       (void *) ddb_in32(DDB_INTSTAT1));
+	printk(KERN_DEBUG
+	       "INTCLR = %p:%p\n", (void *) ddb_in32(DDB_INTCLR + 4),
+	       (void *) ddb_in32(DDB_INTCLR));
+	printk(KERN_DEBUG
+	       "INTPPES = %p:%p\n", (void *) ddb_in32(DDB_INTPPES + 4),
+	       (void *) ddb_in32(DDB_INTPPES));
+}
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5074/pci.c linux-2.4.20/arch/mips/ddb5xxx/ddb5074/pci.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5074/pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5074/pci.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,130 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+#include <asm/pci_channel.h>
+#include <asm/debug.h>
+
+#include <asm/ddb5xxx/ddb5xxx.h>
+
+static struct resource extpci_io_resource = {
+    "pci IO space",
+    0x1000,             /* leave some room for ISA bus */
+    DDB_PCI_IO_SIZE -1,
+    IORESOURCE_IO};
+
+static struct resource extpci_mem_resource = {
+    "pci memory space",
+    DDB_PCI_MEM_BASE + 0x00100000,  /* leave 1 MB for RTC */
+    DDB_PCI_MEM_BASE + DDB_PCI_MEM_SIZE -1,
+    IORESOURCE_MEM};
+
+extern struct pci_ops ddb5476_ext_pci_ops;
+
+struct pci_channel mips_pci_channels[] = {
+    { &ddb5476_ext_pci_ops, &extpci_io_resource, &extpci_mem_resource },
+    { NULL, NULL, NULL}
+};
+
+#define     PCI_EXT_INTA        8
+#define     PCI_EXT_INTB        9
+#define     PCI_EXT_INTC        10
+#define     PCI_EXT_INTD        11
+#define     PCI_EXT_INTE        12
+
+#define     MAX_SLOT_NUM        14
+
+static unsigned char irq_map[MAX_SLOT_NUM] = {
+	/* SLOT:  0 */ nile4_to_irq(PCI_EXT_INTE),
+	/* SLOT:  1 */ nile4_to_irq(PCI_EXT_INTA),
+	/* SLOT:  2 */ nile4_to_irq(PCI_EXT_INTA),
+	/* SLOT:  3 */ nile4_to_irq(PCI_EXT_INTB),
+	/* SLOT:  4 */ nile4_to_irq(PCI_EXT_INTC),
+	/* SLOT:  5 */ nile4_to_irq(NILE4_INT_UART),
+	/* SLOT:  6 */ 0xff,
+	/* SLOT:  7 */ 0xff,
+	/* SLOT:  8 */ 0xff,
+	/* SLOT:  9 */ 0xff,
+	/* SLOT:  10 */ nile4_to_irq(PCI_EXT_INTE),
+	/* SLOT:  11 */ 0xff,
+	/* SLOT:  12 */ 0xff,
+	/* SLOT:  13 */ nile4_to_irq(PCI_EXT_INTE),
+};
+
+void __init pcibios_fixup_irqs(void) {
+
+	struct pci_dev *dev;
+	int slot_num;
+
+	pci_for_each_dev(dev) {
+		slot_num = PCI_SLOT(dev->devfn);
+		db_assert(slot_num < MAX_SLOT_NUM);
+printk("irq_map[%d]: %02x\n",slot_num, irq_map[slot_num]);
+		db_assert(irq_map[slot_num] != 0xff);
+
+		pci_write_config_byte(dev,
+							PCI_INTERRUPT_LINE,
+							irq_map[slot_num]);
+
+		dev->irq = irq_map[slot_num];
+	}
+}
+
+void __init ddb_pci_reset_bus(void)
+{
+    u32 temp;
+
+    /*
+     * I am not sure about the "official" procedure, the following
+     * steps work as far as I know:
+     * We first set PCI cold reset bit (bit 31) in PCICTRL-H.
+     * Then we clear the PCI warm reset bit (bit 30) to 0 in PCICTRL-H.
+     * The same is true for both PCI channels.
+     */
+    temp = ddb_in32(DDB_PCICTRL+4);
+    temp |= 0x80000000;
+    ddb_out32(DDB_PCICTRL+4, temp);
+    temp &= ~0xc0000000;
+    ddb_out32(DDB_PCICTRL+4, temp);
+
+}
+
+unsigned __init int pcibios_assign_all_busses(void)
+{
+    /* we hope pci_auto has assigned the bus numbers to all buses */
+    return 1;
+}
+
+void __init pcibios_fixup_resources(struct pci_dev *dev)
+{
+}
+
+void __init pcibios_fixup(void)
+{
+	struct pci_dev *dev;
+
+	pci_for_each_dev(dev) {
+		if (dev->vendor == PCI_VENDOR_ID_AL &&
+			dev->device == PCI_DEVICE_ID_AL_M7101) {
+				/*
+				 * It's nice to have the LEDs on the GPIO pins
+				 * available for debugging
+				 */
+				extern struct pci_dev *pci_pmu;
+				u8 t8;
+
+				pci_pmu = dev;  /* for LEDs D2 and D3 */
+				/* Program the lines for LEDs D2 and D3 to output */
+				pci_read_config_byte(dev, 0x7d, &t8);
+				t8 |= 0xc0;
+				pci_write_config_byte(dev, 0x7d, t8);
+				/* Turn LEDs D2 and D3 off */
+				pci_read_config_byte(dev, 0x7e, &t8);
+				t8 |= 0xc0;
+				pci_write_config_byte(dev, 0x7e, t8);
+
+		}
+	}
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5074/pci_ops.c linux-2.4.20/arch/mips/ddb5xxx/ddb5074/pci_ops.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5074/pci_ops.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5074/pci_ops.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * arch/mips/ddb5xxx/ddb5476/pci_ops.c
+ *     Define the pci_ops for DB5477.
+ *
+ * Much of the code is derived from the original DDB5074 port by
+ * Geert Uytterhoeven <geert@sonycom.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <asm/addrspace.h>
+#include <asm/debug.h>
+
+#include <asm/ddb5xxx/ddb5xxx.h>
+
+/*
+ * config_swap structure records what set of pdar/pmr are used
+ * to access pci config space.  It also provides a place hold the
+ * original values for future restoring.
+ */
+struct pci_config_swap {
+	u32 	pdar;
+	u32	pmr;
+	u32	config_base;
+	u32	config_size;
+	u32	pdar_backup;
+	u32	pmr_backup;
+};
+
+/*
+ * On DDB5476, we have one set of swap registers
+ */
+struct pci_config_swap ext_pci_swap = {
+	DDB_PCIW0,
+	DDB_PCIINIT0,
+	DDB_PCI_CONFIG_BASE,
+	DDB_PCI_CONFIG_SIZE
+};
+
+static int pci_config_workaround=1;
+
+/*
+ * access config space
+ */
+static inline u32 ddb_access_config_base(struct pci_config_swap *swap,
+					 u32 bus,/* 0 means top level bus */
+					 u32 slot_num)
+{
+	u32 pci_addr = 0;
+	u32 pciinit_offset = 0;
+        u32 virt_addr = swap->config_base;
+	u32 option;
+
+	if (pci_config_workaround) {
+		if (slot_num == 5) slot_num = 14;
+	}
+	else {
+		if (slot_num == 5) return DDB_BASE + DDB_PCI_BASE;
+	}
+
+	/* minimum pdar (window) size is 2MB */
+	db_assert(swap->config_size >= (2 << 20));
+
+	db_assert(slot_num < (1 << 5));
+	db_assert(bus < (1 << 8));
+
+	/* backup registers */
+	swap->pdar_backup = ddb_in32(swap->pdar);
+	swap->pmr_backup = ddb_in32(swap->pmr);
+
+	/* set the pdar (pci window) register */
+	ddb_set_pdar(swap->pdar,
+		     swap->config_base,
+		     swap->config_size,
+		     32,	/* 32 bit wide */
+		     0,		/* not on local memory bus */
+		     0);	/* not visible from PCI bus (N/A) */
+
+	/*
+	 * calcuate the absolute pci config addr;
+	 * according to the spec, we start scanning from adr:11 (0x800)
+	 */
+	if (bus == 0) {
+		/* type 0 config */
+		pci_addr = 0x00040000 << slot_num;
+	} else {
+		/* type 1 config */
+		pci_addr = 0x00040000 << slot_num;
+		panic("ddb_access_config_base: we don't support type 1 config Yet");
+	}
+
+	/*
+	 * if pci_addr is less than pci config window size,  we set
+	 * pciinit_offset to 0 and adjust the virt_address.
+	 * Otherwise we will try to adjust pciinit_offset.
+	 */
+	if (pci_addr < swap->config_size) {
+		virt_addr = KSEG1ADDR(swap->config_base + pci_addr);
+		pciinit_offset = 0;
+	} else {
+		db_assert( (pci_addr & (swap->config_size - 1)) == 0);
+		virt_addr = KSEG1ADDR(swap->config_base);
+		pciinit_offset = pci_addr;
+	}
+
+	/* set the pmr register */
+	option = DDB_PCI_ACCESS_32;
+	if (bus != 0) option |= DDB_PCI_CFGTYPE1;
+	ddb_set_pmr(swap->pmr, DDB_PCICMD_CFG, pciinit_offset, option);
+
+	return virt_addr;
+}
+
+static inline void ddb_close_config_base(struct pci_config_swap *swap)
+{
+	ddb_out32(swap->pdar, swap->pdar_backup);
+	ddb_out32(swap->pmr, swap->pmr_backup);
+}
+
+static int read_config_dword(struct pci_config_swap *swap,
+			     struct pci_dev *dev,
+			     u32 where,
+			     u32 *val)
+{
+	u32 bus, slot_num, func_num;
+	u32 base;
+
+	db_assert((where & 3) == 0);
+	db_assert(where < (1 << 8));
+
+	/* check if the bus is top-level */
+	if (dev->bus->parent != NULL) {
+		bus = dev->bus->number;
+		db_assert(bus != 0);
+	} else {
+		bus = 0;
+	}
+
+	slot_num = PCI_SLOT(dev->devfn);
+	func_num = PCI_FUNC(dev->devfn);
+	base = ddb_access_config_base(swap, bus, slot_num);
+	*val = *(volatile u32*) (base + (func_num << 8) + where);
+	ddb_close_config_base(swap);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int read_config_word(struct pci_config_swap *swap,
+			    struct pci_dev *dev,
+			    u32 where,
+			    u16 *val)
+{
+        int status;
+        u32 result;
+
+	db_assert((where & 1) == 0);
+
+        status = read_config_dword(swap, dev, where & ~3, &result);
+        if (where & 2) result >>= 16;
+        *val = result & 0xffff;
+        return status;
+}
+
+static int read_config_byte(struct pci_config_swap *swap,
+			    struct pci_dev *dev,
+			    u32 where,
+			    u8 *val)
+{
+        int status;
+        u32 result;
+
+        status = read_config_dword(swap, dev, where & ~3, &result);
+        if (where & 1) result >>= 8;
+        if (where & 2) result >>= 16;
+        *val = result & 0xff;
+        return status;
+}
+
+static int write_config_dword(struct pci_config_swap *swap,
+			      struct pci_dev *dev,
+			      u32 where,
+			      u32 val)
+{
+	u32 bus, slot_num, func_num;
+	u32 base;
+
+	db_assert((where & 3) == 0);
+	db_assert(where < (1 << 8));
+
+	/* check if the bus is top-level */
+	if (dev->bus->parent != NULL) {
+		bus = dev->bus->number;
+		db_assert(bus != 0);
+	} else {
+		bus = 0;
+	}
+
+	slot_num = PCI_SLOT(dev->devfn);
+	func_num = PCI_FUNC(dev->devfn);
+	base = ddb_access_config_base(swap, bus, slot_num);
+	*(volatile u32*) (base + (func_num << 8) + where) = val;
+	ddb_close_config_base(swap);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int write_config_word(struct pci_config_swap *swap,
+			     struct pci_dev *dev,
+			     u32 where,
+			     u16 val)
+{
+	int status, shift=0;
+	u32 result;
+
+	db_assert((where & 1) == 0);
+
+	status = read_config_dword(swap, dev, where & ~3, &result);
+	if (status != PCIBIOS_SUCCESSFUL) return status;
+
+        if (where & 2)
+                shift += 16;
+        result &= ~(0xffff << shift);
+        result |= val << shift;
+        return write_config_dword(swap, dev, where & ~3, result);
+}
+
+static int write_config_byte(struct pci_config_swap *swap,
+			     struct pci_dev *dev,
+			     u32 where,
+			     u8 val)
+{
+	int status, shift=0;
+	u32 result;
+
+	status = read_config_dword(swap, dev, where & ~3, &result);
+	if (status != PCIBIOS_SUCCESSFUL) return status;
+
+        if (where & 2)
+                shift += 16;
+        if (where & 1)
+                shift += 8;
+        result &= ~(0xff << shift);
+        result |= val << shift;
+        return write_config_dword(swap, dev, where & ~3, result);
+}
+
+#define	MAKE_PCI_OPS(prefix, rw, unitname, unittype, pciswap) \
+static int prefix##_##rw##_config_##unitname(struct pci_dev *dev, int where, unittype val) \
+{ \
+     return rw##_config_##unitname(pciswap, \
+                                   dev, \
+                                   where, \
+                                   val); \
+}
+
+MAKE_PCI_OPS(extpci, read, byte, u8 *, &ext_pci_swap)
+MAKE_PCI_OPS(extpci, read, word, u16 *, &ext_pci_swap)
+MAKE_PCI_OPS(extpci, read, dword, u32 *, &ext_pci_swap)
+
+MAKE_PCI_OPS(extpci, write, byte, u8, &ext_pci_swap)
+MAKE_PCI_OPS(extpci, write, word, u16, &ext_pci_swap)
+MAKE_PCI_OPS(extpci, write, dword, u32, &ext_pci_swap)
+
+struct pci_ops ddb5476_ext_pci_ops ={
+	extpci_read_config_byte,
+	extpci_read_config_word,
+	extpci_read_config_dword,
+	extpci_write_config_byte,
+	extpci_write_config_word,
+	extpci_write_config_dword
+};
+
+
+#if defined(CONFIG_DEBUG)
+void jsun_scan_pci_bus(void)
+{
+	struct pci_bus bus;
+	struct pci_dev dev;
+	unsigned int devfn;
+	int j;
+
+	pci_config_workaround = 0;
+
+	bus.parent = NULL;	/* we scan the top level only */
+	dev.bus = &bus;
+	dev.sysdata = NULL;
+
+	/* scan ext pci bus and io pci bus*/
+	for (j=0; j< 1; j++) {
+		printk(KERN_INFO "scan ddb5476 external PCI bus:\n");
+		bus.ops = &ddb5476_ext_pci_ops;
+
+		for (devfn = 0; devfn < 0x100; devfn += 8) {
+			u32 temp;
+			u16 temp16;
+			u8 temp8;
+			int i;
+
+			dev.devfn = devfn;
+			db_verify(pci_read_config_dword(&dev, 0, &temp),
+				    == PCIBIOS_SUCCESSFUL);
+			if (temp == 0xffffffff) continue;
+
+			printk(KERN_INFO "slot %d: (addr %d) \n", devfn/8,
+			       11+devfn/8);
+
+			/* verify read word and byte */
+			db_verify(pci_read_config_word(&dev, 2, &temp16),
+				  == PCIBIOS_SUCCESSFUL);
+			db_assert(temp16 == (temp >> 16));
+			db_verify(pci_read_config_byte(&dev, 3, &temp8),
+				  == PCIBIOS_SUCCESSFUL);
+			db_assert(temp8 == (temp >> 24));
+			db_verify(pci_read_config_byte(&dev, 1, &temp8),
+				  == PCIBIOS_SUCCESSFUL);
+			db_assert(temp8 == ((temp >> 8) & 0xff));
+
+			for (i=0; i < 16; i++) {
+				if ((i%4) == 0)
+					printk(KERN_INFO);
+				db_verify(pci_read_config_dword(&dev, i*4, &temp),
+					  == PCIBIOS_SUCCESSFUL);
+				printk("\t%08X", temp);
+				if ((i%4) == 3)
+					printk("\n");
+			}
+		}
+	}
+
+	pci_config_workaround = 1;
+}
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5074/setup.c linux-2.4.20/arch/mips/ddb5xxx/ddb5074/setup.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5074/setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5074/setup.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,275 @@
+/*
+ *  arch/mips/ddb5074/setup.c -- NEC DDB Vrc-5074 setup routines
+ *
+ *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ *                     Sony Software Development Center Europe (SDCE), Brussels
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kbd_ll.h>
+#include <linux/kernel.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/console.h>
+#include <linux/sched.h>
+#include <linux/mc146818rtc.h>
+#include <linux/pc_keyb.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+
+#include <asm/addrspace.h>
+#include <asm/bcache.h>
+#include <asm/keyboard.h>
+#include <asm/irq.h>
+#include <asm/reboot.h>
+#include <asm/gdb-stub.h>
+#include <asm/time.h>
+#include <asm/nile4.h>
+#include <asm/ddb5xxx/ddb5074.h>
+#include <asm/ddb5xxx/ddb5xxx.h>
+
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void rs_kgdb_hook(int);
+extern void breakpoint(void);
+#endif
+
+#if defined(CONFIG_SERIAL_CONSOLE)
+extern void console_setup(char *);
+#endif
+
+extern struct ide_ops std_ide_ops;
+extern struct kbd_ops std_kbd_ops;
+extern struct rtc_ops ddb_rtc_ops;
+
+static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000;
+
+static void ddb_machine_restart(char *command)
+{
+	u32 t;
+
+	/* PCI cold reset */
+	t = nile4_in32(NILE4_PCICTRL + 4);
+	t |= 0x40000000;
+	nile4_out32(NILE4_PCICTRL + 4, t);
+	/* CPU cold reset */
+	t = nile4_in32(NILE4_CPUSTAT);
+	t |= 1;
+	nile4_out32(NILE4_CPUSTAT, t);
+	/* Call the PROM */
+	back_to_prom();
+}
+
+static void ddb_machine_halt(void)
+{
+	printk("DDB Vrc-5074 halted.\n");
+	do {
+	} while (1);
+}
+
+static void ddb_machine_power_off(void)
+{
+	printk("DDB Vrc-5074 halted. Please turn off the power.\n");
+	do {
+	} while (1);
+}
+
+extern void ddb_irq_setup(void);
+extern void rtc_ds1386_init(unsigned long base);
+
+extern void (*board_timer_setup) (struct irqaction * irq);
+
+void __init bus_error_init(void)
+{
+}
+
+static void __init ddb_timer_init(struct irqaction *irq)
+{
+	/* set the clock to 1 Hz */
+	nile4_out32(NILE4_T2CTRL, 1000000);
+	/* enable the General-Purpose Timer */
+	nile4_out32(NILE4_T2CTRL + 4, 0x00000001);
+	/* reset timer */
+	nile4_out32(NILE4_T2CNTR, 0);
+	/* enable interrupt */
+	setup_irq(nile4_to_irq(NILE4_INT_GPT), irq);
+	nile4_enable_irq(nile4_to_irq(NILE4_INT_GPT));
+	change_cp0_status(ST0_IM,
+		          IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4);
+
+}
+
+static void __init ddb_time_init(void)
+{
+    /* we have ds1396 RTC chip */
+	rtc_ds1386_init(KSEG1ADDR(DDB_PCI_MEM_BASE));
+}
+
+
+
+void __init ddb_setup(void)
+{
+	extern int panic_timeout;
+
+	irq_setup = ddb_irq_setup;
+	set_io_port_base(NILE4_PCI_IO_BASE);
+	isa_slot_offset = NILE4_PCI_MEM_BASE;
+	board_timer_setup = ddb_timer_init;
+	board_time_init = ddb_time_init;
+
+
+	_machine_restart = ddb_machine_restart;
+	_machine_halt = ddb_machine_halt;
+	_machine_power_off = ddb_machine_power_off;
+
+#ifdef CONFIG_BLK_DEV_IDE
+	ide_ops = &std_ide_ops;
+#endif
+
+#ifdef CONFIG_PC_KEYB
+    kbd_ops = &std_kbd_ops;
+#endif
+
+	rtc_ops = &ddb_rtc_ops;
+
+    ddb_out32(DDB_BAR0, 0);
+
+	ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IO, 0, 0x10);
+	ddb_set_pmr(DDB_PCIINIT1, DDB_PCICMD_MEM, DDB_PCI_MEM_BASE , 0x10);
+
+#ifdef CONFIG_FB
+    conswitchp = &dummy_con;
+#endif
+
+	/* Reboot on panic */
+	panic_timeout = 180;
+}
+
+
+#define USE_NILE4_SERIAL	0
+
+#if USE_NILE4_SERIAL
+#define ns16550_in(reg)		nile4_in8((reg)*8)
+#define ns16550_out(reg, val)	nile4_out8((reg)*8, (val))
+#else
+#define NS16550_BASE		(NILE4_PCI_IO_BASE+0x03f8)
+static inline u8 ns16550_in(u32 reg)
+{
+	return *(volatile u8 *) (NS16550_BASE + reg);
+}
+
+static inline void ns16550_out(u32 reg, u8 val)
+{
+	*(volatile u8 *) (NS16550_BASE + reg) = val;
+}
+#endif
+
+#define NS16550_RBR		0
+#define NS16550_THR		0
+#define NS16550_DLL		0
+#define NS16550_IER		1
+#define NS16550_DLM		1
+#define NS16550_FCR		2
+#define NS16550_IIR		2
+#define NS16550_LCR		3
+#define NS16550_MCR		4
+#define NS16550_LSR		5
+#define NS16550_MSR		6
+#define NS16550_SCR		7
+
+#define NS16550_LSR_DR		0x01	/* Data ready */
+#define NS16550_LSR_OE		0x02	/* Overrun */
+#define NS16550_LSR_PE		0x04	/* Parity error */
+#define NS16550_LSR_FE		0x08	/* Framing error */
+#define NS16550_LSR_BI		0x10	/* Break */
+#define NS16550_LSR_THRE	0x20	/* Xmit holding register empty */
+#define NS16550_LSR_TEMT	0x40	/* Xmitter empty */
+#define NS16550_LSR_ERR		0x80	/* Error */
+
+
+void _serinit(void)
+{
+#if USE_NILE4_SERIAL
+	ns16550_out(NS16550_LCR, 0x80);
+	ns16550_out(NS16550_DLM, 0x00);
+	ns16550_out(NS16550_DLL, 0x36);	/* 9600 baud */
+	ns16550_out(NS16550_LCR, 0x00);
+	ns16550_out(NS16550_LCR, 0x03);
+	ns16550_out(NS16550_FCR, 0x47);
+#else
+	/* done by PMON */
+#endif
+}
+
+void _putc(char c)
+{
+	while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE));
+	ns16550_out(NS16550_THR, c);
+	if (c == '\n') {
+		while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE));
+		ns16550_out(NS16550_THR, '\r');
+	}
+}
+
+void _puts(const char *s)
+{
+	char c;
+	while ((c = *s++))
+		_putc(c);
+}
+
+char _getc(void)
+{
+	while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR));
+	return ns16550_in(NS16550_RBR);
+}
+
+int _testc(void)
+{
+	return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0;
+}
+
+
+/*
+ *  Hexadecimal 7-segment LED
+ */
+void ddb5074_led_hex(int hex)
+{
+	outb(hex, 0x80);
+}
+
+
+/*
+ *  LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543
+ */
+struct pci_dev *pci_pmu = NULL;
+
+void ddb5074_led_d2(int on)
+{
+	u8 t;
+
+	if (pci_pmu) {
+		pci_read_config_byte(pci_pmu, 0x7e, &t);
+		if (on)
+			t &= 0x7f;
+		else
+			t |= 0x80;
+		pci_write_config_byte(pci_pmu, 0x7e, t);
+	}
+}
+
+void ddb5074_led_d3(int on)
+{
+	u8 t;
+
+	if (pci_pmu) {
+		pci_read_config_byte(pci_pmu, 0x7e, &t);
+		if (on)
+			t &= 0xbf;
+		else
+			t |= 0x40;
+		pci_write_config_byte(pci_pmu, 0x7e, t);
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5074/time.c linux-2.4.20/arch/mips/ddb5xxx/ddb5074/time.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5074/time.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5074/time.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,33 @@
+/*
+ *  arch/mips/ddb5074/time.c -- Timer routines
+ *
+ *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ *                     Sony Software Development Center Europe (SDCE), Brussels
+ *
+ */
+#include <linux/init.h>
+#include <asm/mc146818rtc.h>
+#include <asm/ddb5xxx/ddb5074.h>
+#include <asm/ddb5xxx/ddb5xxx.h>
+
+
+static unsigned char ddb_rtc_read_data(unsigned long addr)
+{
+	return *(volatile unsigned char *)(KSEG1ADDR(DDB_PCI_MEM_BASE)+addr);
+}
+
+static void ddb_rtc_write_data(unsigned char data, unsigned long addr)
+{
+ 	*(volatile unsigned char *)(KSEG1ADDR(DDB_PCI_MEM_BASE)+addr)=data;
+}
+
+static int ddb_rtc_bcd_mode(void)
+{
+	return 1;
+}
+
+struct rtc_ops ddb_rtc_ops = {
+	ddb_rtc_read_data,
+	ddb_rtc_write_data,
+	ddb_rtc_bcd_mode
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5476/Makefile linux-2.4.20/arch/mips/ddb5xxx/ddb5476/Makefile
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5476/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5476/Makefile	2002-10-29 11:18:31.000000000 +0000
@@ -9,10 +9,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 #
 
-.S.s:
-	$(CPP) $(CFLAGS) $< -o $*.s
-.S.o:
-	$(CC) $(CFLAGS) -c $< -o $*.o
+USE_STANDARD_AS_RULE := true
 
 O_TARGET = ddb5476.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5476/int-handler.S linux-2.4.20/arch/mips/ddb5xxx/ddb5476/int-handler.S
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5476/int-handler.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5476/int-handler.S	2002-10-29 11:18:35.000000000 +0000
@@ -9,8 +9,6 @@
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  */
-#include <linux/config.h>
-
 #include <asm/asm.h>
 #include <asm/mipsregs.h>
 #include <asm/addrspace.h>
@@ -30,7 +28,7 @@
 	CLI
 	.set	at
 	.set	noreorder
-	mfc0	t0, CP0_CAUSE  
+	mfc0	t0, CP0_CAUSE
 	mfc0	t2, CP0_STATUS
 
 	and	t0, t2
@@ -64,13 +62,13 @@
 
 	.align	5
 
-ll_cpu_ip0:	
+ll_cpu_ip0:
 	li	a0, CPU_IRQ_BASE + 0
 	move	a1, sp
 	jal	do_IRQ
 	j	ret_from_irq
 
-ll_cpu_ip1:	
+ll_cpu_ip1:
 	li	a0, CPU_IRQ_BASE + 1
 	move	a1, sp
 	jal	do_IRQ
@@ -81,25 +79,25 @@
 	jal	vrc5476_irq_dispatch
 	j	ret_from_irq
 
-ll_cpu_ip3:	
+ll_cpu_ip3:
 	li	a0, CPU_IRQ_BASE + 3
 	move	a1, sp
 	jal	do_IRQ
 	j	ret_from_irq
 
-ll_cpu_ip4:	
+ll_cpu_ip4:
 	li	a0, CPU_IRQ_BASE + 4
 	move	a1, sp
 	jal	do_IRQ
 	j	ret_from_irq
 
-ll_cpu_ip5:	
+ll_cpu_ip5:
 	li	a0, CPU_IRQ_BASE + 5
 	move	a1, sp
 	jal	do_IRQ
 	j	ret_from_irq
 
-ll_cpu_ip6:	
+ll_cpu_ip6:
 	li	a0, CPU_IRQ_BASE + 6
 	move	a1, sp
 	jal	do_IRQ
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5476/irq.c linux-2.4.20/arch/mips/ddb5xxx/ddb5476/irq.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5476/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5476/irq.c	2002-10-29 11:18:40.000000000 +0000
@@ -9,7 +9,6 @@
  * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
  *
  */
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/types.h>
@@ -46,9 +45,9 @@
 	 *
 	 *      IRQ1  - keyboard (default set by M1543)
 	 *      IRQ3  - reserved for UART B (default set by M1543) (note that
-	 *              the schematics for the DDB Vrc-5476 board seem to 
-	 *              indicate that IRQ3 is connected to the DS1386 
-	 *              watchdog timer interrupt output so we might have 
+	 *              the schematics for the DDB Vrc-5476 board seem to
+	 *              indicate that IRQ3 is connected to the DS1386
+	 *              watchdog timer interrupt output so we might have
 	 *              a conflict)
 	 *      IRQ4  - reserved for UART A (default set by M1543)
 	 *      IRQ5  - parallel (default set by M1543)
@@ -60,7 +59,7 @@
 	 */
 
 	/*
-	 *  Assing mouse interrupt to IRQ12 
+	 *  Assing mouse interrupt to IRQ12
 	 */
 
 	/* Enter configuration mode */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5476/nile4_pic.c linux-2.4.20/arch/mips/ddb5xxx/ddb5476/nile4_pic.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5476/nile4_pic.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5476/nile4_pic.c	2002-10-29 11:18:48.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  arch/mips/ddb5476/nile4.c -- 
+ *  arch/mips/ddb5476/nile4.c --
  *  	low-level PIC code for NEC Vrc-5476 (Nile 4)
  *
  *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
@@ -9,6 +9,7 @@
  *  Author: jsun@mvista.com or jsun@junsun.net
  *
  */
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5476/pci.c linux-2.4.20/arch/mips/ddb5xxx/ddb5476/pci.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5476/pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5476/pci.c	2002-10-29 11:18:34.000000000 +0000
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -9,13 +10,13 @@
 #include <asm/ddb5xxx/ddb5xxx.h>
 
 static struct resource extpci_io_resource = {
-	"pci IO space", 
+	"pci IO space",
 	0x1000,				/* leave some room for ISA bus */
 	DDB_PCI_IO_SIZE -1,
 	IORESOURCE_IO};
 
 static struct resource extpci_mem_resource = {
-	"pci memory space", 
+	"pci memory space",
 	DDB_PCI_MEM_BASE + 0x00100000,	/* leave 1 MB for RTC */
 	DDB_PCI_MEM_BASE + DDB_PCI_MEM_SIZE -1,
 	IORESOURCE_MEM};
@@ -31,7 +32,7 @@
 /*
  * we fix up irqs based on the slot number.
  * The first entry is at AD:11.
- * 
+ *
  * This does not work for devices on sub-buses yet.
  */
 
@@ -92,7 +93,7 @@
 		db_assert(slot_num < MAX_SLOT_NUM);
 		db_assert(irq_map[slot_num] != 0xff);
 
-		pci_write_config_byte(dev, 
+		pci_write_config_byte(dev,
 				      PCI_INTERRUPT_LINE,
 				      irq_map[slot_num]);
 		dev->irq = irq_map[slot_num];
@@ -104,7 +105,7 @@
 #endif
 
 void __init ddb_pci_reset_bus(void)
-{	
+{
 	u32 temp;
 
 	/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5476/pci_ops.c linux-2.4.20/arch/mips/ddb5xxx/ddb5476/pci_ops.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5476/pci_ops.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5476/pci_ops.c	2002-10-29 11:18:36.000000000 +0000
@@ -5,7 +5,7 @@
  * arch/mips/ddb5xxx/ddb5476/pci_ops.c
  *     Define the pci_ops for DB5477.
  *
- * Much of the code is derived from the original DDB5074 port by 
+ * Much of the code is derived from the original DDB5074 port by
  * Geert Uytterhoeven <geert@sonycom.com>
  *
  * This program is free software; you can redistribute  it and/or modify it
@@ -43,7 +43,7 @@
  * On DDB5476, we have one set of swap registers
  */
 struct pci_config_swap ext_pci_swap = {
-	DDB_PCIW0,  
+	DDB_PCIW0,
 	DDB_PCIINIT0,
 	DDB_PCI_CONFIG_BASE,
 	DDB_PCI_CONFIG_SIZE
@@ -53,7 +53,7 @@
 
 /*
  * access config space
- */	
+ */
 static inline u32 ddb_access_config_base(struct pci_config_swap *swap,
 					 u32 bus,/* 0 means top level bus */
 					 u32 slot_num)
@@ -66,7 +66,7 @@
 	if (pci_config_workaround) {
 		/* [jsun] work around Vrc5476 controller itself, returnning
 		 * slot 0 essentially makes vrc5476 invisible
-		 */ 
+		 */
 		if (slot_num == 12) slot_num = 0;
 
 #if 0
@@ -77,7 +77,7 @@
 	} else {
 		/* now we have to be hornest, returning the true
 		 * PCI config headers for vrc5476
-		 */ 
+		 */
 		if (slot_num == 12) {
 			swap->pdar_backup = ddb_in32(swap->pdar);
 			swap->pmr_backup = ddb_in32(swap->pmr);
@@ -103,10 +103,10 @@
 		     0,		/* not on local memory bus */
 		     0);	/* not visible from PCI bus (N/A) */
 
-	/* 
-	 * calcuate the absolute pci config addr; 
+	/*
+	 * calcuate the absolute pci config addr;
 	 * according to the spec, we start scanning from adr:11 (0x800)
-	 */ 
+	 */
 	if (bus == 0) {
 		/* type 0 config */
 		pci_addr = 0x800 << slot_num;
@@ -224,7 +224,7 @@
 	slot_num = PCI_SLOT(dev->devfn);
 	func_num = PCI_FUNC(dev->devfn);
 	base = ddb_access_config_base(swap, bus, slot_num);
-	*(volatile u32*) (base + (func_num << 8) + where) = val; 
+	*(volatile u32*) (base + (func_num << 8) + where) = val;
 	ddb_close_config_base(swap);
 	return PCIBIOS_SUCCESSFUL;
 }
@@ -314,7 +314,7 @@
 	for (j=0; j< 1; j++) {
 		printk(KERN_INFO "scan ddb5476 external PCI bus:\n");
 		bus.ops = &ddb5476_ext_pci_ops;
-	
+
 		for (devfn = 0; devfn < 0x100; devfn += 8) {
 			u32 temp;
 			u16 temp16;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5476/setup.c linux-2.4.20/arch/mips/ddb5xxx/ddb5476/setup.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5476/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5476/setup.c	2002-10-29 11:18:34.000000000 +0000
@@ -25,6 +25,7 @@
 #include <asm/gdb-stub.h>
 #include <asm/time.h>
 #include <asm/debug.h>
+#include <asm/traps.h>
 
 #include <asm/ddb5xxx/ddb5xxx.h>
 
@@ -138,11 +139,15 @@
 	{ "Nile 4", DDB_BASE, DDB_BASE + DDB_SIZE - 1, IORESOURCE_BUSY}
 };
 
+
+void __init bus_error_init(void) { /* nothing */ }
+
+
 static void ddb5476_board_init(void);
 extern void ddb5476_irq_setup(void);
 extern void (*irq_setup)(void);
 
-void __init 
+void __init
 ddb_setup(void)
 {
 	extern int panic_timeout;
@@ -197,7 +202,7 @@
  * We don't trust bios.  We essentially does hardware re-initialization
  * as complete as possible, as far as we know we can safely do.
  */
-static void 
+static void
 ddb5476_board_init(void)
 {
 	/* ----------- setup PDARs ------------ */
@@ -240,7 +245,7 @@
 	/* this is problematic - it will reset Aladin which cause we loose
 	 * serial port, and we don't know how to set up Aladin chip again.
 	 */
-	// ddb_pci_reset_bus(); 
+	// ddb_pci_reset_bus();
 
 	ddb_out32(DDB_BAR0, 0x00000008);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c linux-2.4.20/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c	2002-10-29 11:18:33.000000000 +0000
@@ -62,7 +62,7 @@
 	NULL				/* no affinity stuff for UP */
 };
 
-void __init 
+void __init
 vrc5476_irq_init(u32 base)
 {
 	extern irq_desc_t irq_desc[];
@@ -78,7 +78,7 @@
 }
 
 
-asmlinkage void 
+asmlinkage void
 vrc5476_irq_dispatch(struct pt_regs *regs)
 {
 	extern unsigned int do_IRQ(int irq, struct pt_regs *regs);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5477/Makefile linux-2.4.20/arch/mips/ddb5xxx/ddb5477/Makefile
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5477/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5477/Makefile	2002-10-29 11:18:35.000000000 +0000
@@ -6,10 +6,7 @@
 # unless it's something special (ie not a .c file).
 #
 
-.S.s:
-	$(CPP) $(CFLAGS) $< -o $*.s
-.S.o:
-	$(CC) $(CFLAGS) -c $< -o $*.o
+USE_STANDARD_AS_RULE := true
 
 O_TARGET:= ddb5477.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5477/debug.c linux-2.4.20/arch/mips/ddb5xxx/ddb5477/debug.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5477/debug.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5477/debug.c	2002-10-29 11:18:34.000000000 +0000
@@ -30,9 +30,9 @@
 
 	printk("\nshow regs: %s\n", name);
 	for(i=0;regs[i].regname!= NULL; i++) {
-		printk("%-16s= %08x\t\t(@%08x)\n", 
-		       regs[i].regname, 
-		       *(unsigned *)(regs[i].regaddr), 
+		printk("%-16s= %08x\t\t(@%08x)\n",
+		       regs[i].regname,
+		       *(unsigned *)(regs[i].regaddr),
 		       regs[i].regaddr);
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5477/int-handler.S linux-2.4.20/arch/mips/ddb5xxx/ddb5477/int-handler.S
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5477/int-handler.S	2001-09-09 17:43:01.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5477/int-handler.S	2002-10-29 11:18:33.000000000 +0000
@@ -9,8 +9,6 @@
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  */
-#include <linux/config.h>
-
 #include <asm/asm.h>
 #include <asm/mipsregs.h>
 #include <asm/addrspace.h>
@@ -28,14 +26,14 @@
 	CLI
 	.set	at
 	.set	noreorder
-	mfc0	t0, CP0_CAUSE  
+	mfc0	t0, CP0_CAUSE
 	mfc0	t2, CP0_STATUS
 
 	and	t0, t2
-       
+
 	andi	t1, t0, STATUSF_IP7	/* cpu timer */
 	bnez	t1, ll_cputimer_irq
-	andi	t1, t0, (STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6 ) 
+	andi	t1, t0, (STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6 )
 	bnez	t1, ll_vrc5477_irq
 	andi	t1, t0, STATUSF_IP0	/* software int 0 */
 	bnez	t1, ll_cpu_ip0
@@ -51,7 +49,7 @@
 
 	.align	5
 
-ll_vrc5477_irq:	
+ll_vrc5477_irq:
 	move	a0, sp
 	jal	vrc5477_irq_dispatch
 	j	ret_from_irq
@@ -63,13 +61,13 @@
 	j	ret_from_irq
 
 
-ll_cpu_ip0:	
+ll_cpu_ip0:
 	li	a0, 0
 	move	a1, sp
 	jal	do_IRQ
 	j	ret_from_irq
 
-ll_cpu_ip1:	
+ll_cpu_ip1:
 	li	a0, 1
 	move	a1, sp
 	jal	do_IRQ
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5477/irq.c linux-2.4.20/arch/mips/ddb5xxx/ddb5477/irq.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5477/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5477/irq.c	2002-10-29 11:18:33.000000000 +0000
@@ -19,6 +19,8 @@
 #include <asm/system.h>
 #include <asm/mipsregs.h>
 #include <asm/debug.h>
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
 
 #include <asm/ddb5xxx/ddb5xxx.h>
 
@@ -37,7 +39,7 @@
  *	7 - 	cpu timer (used by default)
  *
  *  8-39: 32 Vrc5477 interrupt sources
- *	(refer to the Vrc5477 manual)	
+ *	(refer to the Vrc5477 manual)
  */
 
 #define	PCI0			DDB_INTPPES0
@@ -55,7 +57,7 @@
 #define	INTD			3
 #define	INTE			4
 
-static inline void 
+static inline void
 set_pci_int_attr(u32 pci, u32 intn, u32 active, u32 trigger)
 {
 	u32 reg_value;
@@ -63,22 +65,25 @@
 
 	reg_value = ddb_in32(pci);
 	reg_bitmask = 0x3 << (intn * 2);
-	
+
 	reg_value &= ~reg_bitmask;
 	reg_value |= (active | trigger) << (intn * 2);
 	ddb_out32(pci, reg_value);
 }
 
+extern void init_i8259_irqs (void);
 extern void vrc5477_irq_init(u32 base);
 extern void mips_cpu_irq_init(u32 base);
 extern asmlinkage void ddb5477_handle_int(void);
+extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
+static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL };
 
 void
 ddb5477_irq_setup(void)
 {
 	db_run(printk("ddb5477_irq_setup invoked.\n"));
 
-	/* by default, we disable all interrupts and route all vrc5477 
+	/* by default, we disable all interrupts and route all vrc5477
 	 * interrupts to pin 0 (irq 2) */
 	ddb_out32(DDB_INTCTRL0, 0);
 	ddb_out32(DDB_INTCTRL1, 0);
@@ -91,7 +96,10 @@
 	/* setup PCI interrupt attributes */
 	set_pci_int_attr(PCI0, INTA, ACTIVE_LOW, LEVEL_SENSE);
 	set_pci_int_attr(PCI0, INTB, ACTIVE_LOW, LEVEL_SENSE);
-	set_pci_int_attr(PCI0, INTC, ACTIVE_LOW, LEVEL_SENSE);
+	if (mips_machtype == MACH_NEC_ROCKHOPPERII)
+		set_pci_int_attr(PCI0, INTC, ACTIVE_HIGH, LEVEL_SENSE);
+	else
+		set_pci_int_attr(PCI0, INTC, ACTIVE_LOW, LEVEL_SENSE);
 	set_pci_int_attr(PCI0, INTD, ACTIVE_LOW, LEVEL_SENSE);
 	set_pci_int_attr(PCI0, INTE, ACTIVE_LOW, LEVEL_SENSE);
 
@@ -101,9 +109,9 @@
 	set_pci_int_attr(PCI1, INTD, ACTIVE_LOW, LEVEL_SENSE);
 	set_pci_int_attr(PCI1, INTE, ACTIVE_LOW, LEVEL_SENSE);
 
-	/* 
+	/*
 	 * for debugging purpose, we enable several error interrupts
-	 * and route them to pin 1. (IP3) 
+	 * and route them to pin 1. (IP3)
 	 */
 	/* cpu parity check - 0 */
 	ll_vrc5477_irq_route(0, 1); ll_vrc5477_irq_enable(0);
@@ -121,13 +129,34 @@
 	ll_vrc5477_irq_route(31, 1); ll_vrc5477_irq_enable(31);
 
 	/* init all controllers */
-	mips_cpu_irq_init(0);
-	vrc5477_irq_init(8);
+	init_i8259_irqs();
+	mips_cpu_irq_init(CPU_IRQ_BASE);
+	vrc5477_irq_init(VRC5477_IRQ_BASE);
+
+
+	/* setup cascade interrupts */
+	setup_irq(VRC5477_IRQ_BASE + VRC5477_I8259_CASCADE, &irq_cascade);
+	setup_irq(CPU_IRQ_BASE + CPU_VRC5477_CASCADE, &irq_cascade);
 
 	/* hook up the first-level interrupt handler */
 	set_except_vector(0, ddb5477_handle_int);
 }
 
+u8 i8259_interrupt_ack(void)
+{
+	u8 irq;
+	u32 reg;
+
+	/* Set window 0 for interrupt acknowledge */
+	reg = ddb_in32(DDB_PCIINIT10);
+
+	ddb_set_pmr(DDB_PCIINIT10, DDB_PCICMD_IACK, 0, DDB_PCI_ACCESS_32);
+	irq = *(volatile u8 *) KSEG1ADDR(DDB_PCI_IACK_BASE);
+	ddb_out32(DDB_PCIINIT10, reg);
+
+	/* i8259.c set the base vector to be 0x0 */
+	return irq + I8259_IRQ_BASE;
+}
 /*
  * the first level int-handler will jump here if it is a vrc5477 irq
  */
@@ -154,10 +183,21 @@
 	}
 
 	intStatus = ddb_in32(DDB_INT0STAT);
+
+	if (mips_machtype == MACH_NEC_ROCKHOPPERII) {
+		/* check for i8259 interrupts */
+		if (intStatus & (1 << VRC5477_I8259_CASCADE)) {
+			int i8259_irq = i8259_interrupt_ack();
+			do_IRQ(I8259_IRQ_BASE + i8259_irq, regs);
+			return;
+		}
+	}
+
 	for (i=0, bitmask=1; i<= NUM_5477_IRQS; bitmask <<=1, i++) {
 		/* do we need to "and" with the int mask? */
 		if (intStatus & bitmask) {
-			do_IRQ(8 + i, regs);
+			do_IRQ(VRC5477_IRQ_BASE + i, regs);
+			return;
 		}
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5477/irq_5477.c linux-2.4.20/arch/mips/ddb5xxx/ddb5477/irq_5477.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5477/irq_5477.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5477/irq_5477.c	2002-10-29 11:18:35.000000000 +0000
@@ -18,6 +18,7 @@
  * This file exports one function:
  *	vrc5477_irq_init(u32 irq_base);
  */
+
 #include <linux/interrupt.h>
 #include <linux/types.h>
 #include <linux/ptrace.h>
@@ -32,7 +33,7 @@
 static int vrc5477_irq_base = -1;
 
 
-static void 
+static void
 vrc5477_irq_enable(unsigned int irq)
 {
 	db_assert(vrc5477_irq_base != -1);
@@ -42,7 +43,7 @@
 	ll_vrc5477_irq_enable(irq - vrc5477_irq_base);
 }
 
-static void 
+static void
 vrc5477_irq_disable(unsigned int irq)
 {
 	db_assert(vrc5477_irq_base != -1);
@@ -99,7 +100,7 @@
 	NULL			/* no affinity stuff for UP */
 };
 
-void 
+void
 vrc5477_irq_init(u32 irq_base)
 {
 	extern irq_desc_t irq_desc[];
@@ -111,17 +112,8 @@
 		irq_desc[i].depth = 1;
 		irq_desc[i].handler = &vrc5477_irq_controller;
 	}
-	
-	vrc5477_irq_base = irq_base;
-}
 
-
-int vrc5477_irq_to_irq(int irq)
-{
-	db_assert(irq >= 0);
-	db_assert(irq < NUM_5477_IRQ);
-
-	return irq + vrc5477_irq_base;
+	vrc5477_irq_base = irq_base;
 }
 
 void ll_vrc5477_irq_route(int vrc5477_irq, int ip)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5477/pci.c linux-2.4.20/arch/mips/ddb5xxx/ddb5477/pci.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5477/pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5477/pci.c	2002-10-29 11:18:47.000000000 +0000
@@ -11,36 +11,38 @@
  *
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/pci.h>
 
+#include <asm/bootinfo.h>
 #include <asm/pci_channel.h>
 #include <asm/debug.h>
 
 #include <asm/ddb5xxx/ddb5xxx.h>
 
 static struct resource extpci_io_resource = {
-	"ext pci IO space", 
-	DDB_PCI0_IO_BASE - DDB_PCI_IO_BASE,
+	"ext pci IO space",
+	DDB_PCI0_IO_BASE - DDB_PCI_IO_BASE + 0x4000,
 	DDB_PCI0_IO_BASE - DDB_PCI_IO_BASE + DDB_PCI0_IO_SIZE -1,
 	IORESOURCE_IO};
 
 static struct resource extpci_mem_resource = {
-	"ext pci memory space", 
-	DDB_PCI0_MEM_BASE,
+	"ext pci memory space",
+	DDB_PCI0_MEM_BASE + 0x100000,
 	DDB_PCI0_MEM_BASE + DDB_PCI0_MEM_SIZE -1,
 	IORESOURCE_MEM};
 
 static struct resource iopci_io_resource = {
-	"io pci IO space", 
+	"io pci IO space",
 	DDB_PCI1_IO_BASE - DDB_PCI_IO_BASE,
 	DDB_PCI1_IO_BASE - DDB_PCI_IO_BASE + DDB_PCI1_IO_SIZE -1,
 	IORESOURCE_IO};
 
 static struct resource iopci_mem_resource = {
-	"ext pci memory space", 
+	"ext pci memory space",
 	DDB_PCI1_MEM_BASE,
 	DDB_PCI1_MEM_BASE + DDB_PCI1_MEM_SIZE -1,
 	IORESOURCE_MEM};
@@ -59,79 +61,108 @@
  * we fix up irqs based on the slot number.
  * The first entry is at AD:11.
  * Fortunately this works because, although we have two pci buses,
- * they all have different slot numbers.
- * 
- * This does not work for devices on sub-buses.
+ * they all have different slot numbers (except for rockhopper slot 20
+ * which is handled below).
  *
- * Note that the irq number in the array is relative number in vrc5477.
- * We need to translate it to global irq number.
  */
 
 /*
- * irq mapping : PCI int # -> vrc5477 irq #
- * based on vrc5477 manual page 46
- */
-#define		PCI_EXT_INTA		8
-#define		PCI_EXT_INTB		9
-#define		PCI_EXT_INTC		10
-#define		PCI_EXT_INTD		11
-#define		PCI_EXT_INTE		12
-
-#define		PCI_IO_INTA		16
-#define		PCI_IO_INTB		17
-#define		PCI_IO_INTC		18
-#define		PCI_IO_INTD		19
-
-/* 
- * irq mapping : device -> pci int #, 
+ * irq mapping : device -> pci int # -> vrc4377 irq# ,
  * ddb5477 board manual page 4  and vrc5477 manual page 46
  */
-#define		INT_ONBOARD_TULIP	PCI_EXT_INTA
-#define		INT_SLOT1		PCI_EXT_INTB
-#define		INT_SLOT2		PCI_EXT_INTC
-#define		INT_SLOT3		PCI_EXT_INTD
-#define		INT_SLOT4		PCI_EXT_INTE
-
-#define		INT_USB_HOST		PCI_IO_INTA
-#define		INT_USB_PERI		PCI_IO_INTB
-#define		INT_AC97		PCI_IO_INTC
 
 /*
  * based on ddb5477 manual page 11
  */
 #define		MAX_SLOT_NUM		21
 static unsigned char irq_map[MAX_SLOT_NUM] = {
-	/* AD:11 */ 0xff, 0xff, 0xff, 0xff, 
-	/* AD:15 */ INT_ONBOARD_TULIP, INT_SLOT1, INT_SLOT2, INT_SLOT3,
-	/* AD:19 */ INT_SLOT4, 0xff, 0xff, 0xff,
-	/* AD:23 */ 0xff, 0xff, 0xff, 0xff,
-	/* AD:27 */ 0xff, 0xff, INT_AC97, INT_USB_PERI, 
-	/* AD:31 */ INT_USB_HOST
+	/* SLOT:  0, AD:11 */ 0xff,
+	/* SLOT:  1, AD:12 */ 0xff,
+	/* SLOT:  2, AD:13 */ 0xff,
+	/* SLOT:  3, AD:14 */ 0xff,
+	/* SLOT:  4, AD:15 */ VRC5477_IRQ_INTA,       /* onboard tulip */
+	/* SLOT:  5, AD:16 */ VRC5477_IRQ_INTB,       /* slot 1 */
+	/* SLOT:  6, AD:17 */ VRC5477_IRQ_INTC,       /* slot 2 */
+	/* SLOT:  7, AD:18 */ VRC5477_IRQ_INTD,       /* slot 3 */
+	/* SLOT:  8, AD:19 */ VRC5477_IRQ_INTE,       /* slot 4 */
+	/* SLOT:  9, AD:20 */ 0xff,
+	/* SLOT: 10, AD:21 */ 0xff,
+	/* SLOT: 11, AD:22 */ 0xff,
+	/* SLOT: 12, AD:23 */ 0xff,
+	/* SLOT: 13, AD:24 */ 0xff,
+	/* SLOT: 14, AD:25 */ 0xff,
+	/* SLOT: 15, AD:26 */ 0xff,
+	/* SLOT: 16, AD:27 */ 0xff,
+	/* SLOT: 17, AD:28 */ 0xff,
+	/* SLOT: 18, AD:29 */ VRC5477_IRQ_IOPCI_INTC, /* vrc5477 ac97 */
+	/* SLOT: 19, AD:30 */ VRC5477_IRQ_IOPCI_INTB, /* vrc5477 usb peri */
+	/* SLOT: 20, AD:31 */ VRC5477_IRQ_IOPCI_INTA, /* vrc5477 usb host */
+};
+static unsigned char rockhopperII_irq_map[MAX_SLOT_NUM] = {
+	/* SLOT:  0, AD:11 */ 0xff,
+	/* SLOT:  1, AD:12 */ VRC5477_IRQ_INTB,       /* onboard AMD PCNET */
+	/* SLOT:  2, AD:13 */ 0xff,
+	/* SLOT:  3, AD:14 */ 0xff,
+	/* SLOT:  4, AD:15 */ 14,                     /* M5229 ide ISA irq */
+	/* SLOT:  5, AD:16 */ VRC5477_IRQ_INTD,       /* slot 3 */
+	/* SLOT:  6, AD:17 */ VRC5477_IRQ_INTA,       /* slot 4 */
+	/* SLOT:  7, AD:18 */ VRC5477_IRQ_INTD,       /* slot 5 */
+	/* SLOT:  8, AD:19 */ 0,                      /* M5457 modem nop */
+	/* SLOT:  9, AD:20 */ VRC5477_IRQ_INTA,       /* slot 2 */
+	/* SLOT: 10, AD:21 */ 0xff,
+	/* SLOT: 11, AD:22 */ 0xff,
+	/* SLOT: 12, AD:23 */ 0xff,
+	/* SLOT: 13, AD:24 */ 0xff,
+	/* SLOT: 14, AD:25 */ 0xff,
+	/* SLOT: 15, AD:26 */ 0xff,
+	/* SLOT: 16, AD:27 */ 0xff,
+	/* SLOT: 17, AD:28 */ 0,                      /* M7101 PMU nop */
+	/* SLOT: 18, AD:29 */ VRC5477_IRQ_IOPCI_INTC, /* vrc5477 ac97 */
+	/* SLOT: 19, AD:30 */ VRC5477_IRQ_IOPCI_INTB, /* vrc5477 usb peri */
+	/* SLOT: 20, AD:31 */ VRC5477_IRQ_IOPCI_INTA, /* vrc5477 usb host */
 };
 
-extern int vrc5477_irq_to_irq(int irq);
 void __init pcibios_fixup_irqs(void)
 {
         struct pci_dev *dev;
         int slot_num;
+        unsigned char *slot_irq_map;
+        unsigned char irq;
+
+	if (mips_machtype == MACH_NEC_ROCKHOPPERII)
+		slot_irq_map = rockhopperII_irq_map;
+	else
+		slot_irq_map = irq_map;
+
 
 	pci_for_each_dev(dev) {
 		slot_num = PCI_SLOT(dev->devfn);
-
-               /* we don't do IRQ fixup for sub-bus yet */
-               if (dev->bus->parent != NULL) {
-                       db_run(printk("Don't know how to fixup irq for PCI device %d on sub-bus %d\n",
-                                       slot_num, dev->bus->number));
-                       continue;
-               }
+		irq = slot_irq_map[slot_num];
 
 		db_assert(slot_num < MAX_SLOT_NUM);
-		db_assert(irq_map[slot_num] != 0xff);
 
-		pci_write_config_byte(dev, 
+                db_assert(irq != 0xff);
+
+		pci_write_config_byte(dev,
 				      PCI_INTERRUPT_LINE,
-				      irq_map[slot_num]);
-		dev->irq = vrc5477_irq_to_irq(irq_map[slot_num]);
+				      irq);
+
+		dev->irq = irq;
+
+		if (mips_machtype == MACH_NEC_ROCKHOPPERII) {
+			/* hack to distinquish overlapping slot 20s, one
+			 * on bus 0 (ALI USB on the M1535 on the backplane),
+			 * and one on bus 2 (NEC USB controller on the CPU board)
+			 * Make the M1535 USB - ISA IRQ number 9.
+			 */
+			if (slot_num == 20 && dev->bus->number == 0) {
+				pci_write_config_byte(dev,
+						      PCI_INTERRUPT_LINE,
+						      9);
+				dev->irq = 9;
+			}
+		}
+
 	}
 }
 
@@ -139,8 +170,8 @@
 extern void jsun_scan_pci_bus(void);
 extern void jsun_assign_pci_resource(void);
 #endif
-void __init ddb_pci_reset_bus(void)
-{	
+void ddb_pci_reset_bus(void)
+{
 	u32 temp;
 
 	/*
@@ -175,5 +206,43 @@
 
 void __init pcibios_fixup(void)
 {
+	if (mips_machtype == MACH_NEC_ROCKHOPPERII) {
+		struct pci_dev *dev;
+
+#define M1535_CONFIG_PORT 0x3f0
+#define M1535_INDEX_PORT  0x3f0
+#define M1535_DATA_PORT   0x3f1
+
+		printk("Configuring ALI M1535 Super I/O mouse irq.\n");
+
+		request_region(M1535_CONFIG_PORT, 2, "M1535 Super I/O config");
+
+		/* Enter config mode. */
+		outb(0x51, M1535_CONFIG_PORT);
+		outb(0x23, M1535_CONFIG_PORT);
+
+		/* Select device 0x07. */
+		outb(0x07, M1535_INDEX_PORT);
+		outb(0x07, M1535_DATA_PORT);
+
+		/* Set mouse irq (register 0x72) to 12. */
+		outb(0x72, M1535_INDEX_PORT);
+		outb(0x0c, M1535_DATA_PORT);
+
+		/* Exit config mode. */
+		outb(0xbb, M1535_CONFIG_PORT);
+
+		pci_for_each_dev(dev) {
+			if(dev->vendor == PCI_VENDOR_ID_AL)
+				if(dev->device == PCI_DEVICE_ID_AL_M1535
+				    || dev->device == PCI_DEVICE_ID_AL_M1533) {
+				u8 old;
+				printk("Enabling ALI M1533/35 PS2 keyboard/mouse.\n");
+				pci_read_config_byte(dev, 0x41, &old);
+				pci_write_config_byte(dev, 0x41, old | 0xd0);
+			}
+		}
+
+	}
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5477/pci_ops.c linux-2.4.20/arch/mips/ddb5xxx/ddb5477/pci_ops.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5477/pci_ops.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5477/pci_ops.c	2002-10-29 11:18:31.000000000 +0000
@@ -5,7 +5,7 @@
  * arch/mips/ddb5xxx/ddb5477/pci_ops.c
  *     Define the pci_ops for DB5477.
  *
- * Much of the code is derived from the original DDB5074 port by 
+ * Much of the code is derived from the original DDB5074 port by
  * Geert Uytterhoeven <geert@sonycom.com>
  *
  * This program is free software; you can redistribute  it and/or modify it
@@ -48,13 +48,13 @@
  * On DDB5477, we have two sets of swap registers, for ext PCI and IOPCI.
  */
 struct pci_config_swap ext_pci_swap = {
-	DDB_PCIW0,  
+	DDB_PCIW0,
 	DDB_PCIINIT00,
 	DDB_PCI0_CONFIG_BASE,
 	DDB_PCI0_CONFIG_SIZE
 };
 struct pci_config_swap io_pci_swap = {
-	DDB_IOPCIW0,  
+	DDB_IOPCIW0,
 	DDB_PCIINIT01,
 	DDB_PCI1_CONFIG_BASE,
 	DDB_PCI1_CONFIG_SIZE
@@ -63,7 +63,7 @@
 
 /*
  * access config space
- */	
+ */
 static inline u32 ddb_access_config_base(struct pci_config_swap *swap,
 					 u32 bus,/* 0 means top level bus */
 					 u32 slot_num)
@@ -91,10 +91,10 @@
 		     0,		/* not on local memory bus */
 		     0);	/* not visible from PCI bus (N/A) */
 
-	/* 
-	 * calcuate the absolute pci config addr; 
+	/*
+	 * calcuate the absolute pci config addr;
 	 * according to the spec, we start scanning from adr:11 (0x800)
-	 */ 
+	 */
 	if (bus == 0) {
 		/* type 0 config */
 		pci_addr = 0x800 << slot_num;
@@ -211,7 +211,7 @@
 	slot_num = PCI_SLOT(dev->devfn);
 	func_num = PCI_FUNC(dev->devfn);
 	base = ddb_access_config_base(swap, bus, slot_num);
-	*(volatile u32*) (base + (func_num << 8) + where) = val; 
+	*(volatile u32*) (base + (func_num << 8) + where) = val;
 	ddb_close_config_base(swap);
 	return PCIBIOS_SUCCESSFUL;
 }
@@ -300,114 +300,3 @@
 	iopci_write_config_dword
 };
 
-#if defined(CONFIG_DEBUG)
-void jsun_scan_pci_bus(void)
-{
-	struct pci_bus bus;
-	struct pci_dev dev;
-	unsigned int devfn;
-	int j;
-
-	bus.parent = NULL;	/* we scan the top level only */
-	dev.bus = &bus;
-	dev.sysdata = NULL;
-
-	/* scan ext pci bus and io pci bus*/
-	for (j=0; j< 2; j++) {
-		if (j ==  0) {
-			printk("scan ddb5477 external PCI bus:\n");
-			bus.ops = &ddb5477_ext_pci_ops;
-		} else {
-			printk("scan ddb5477 IO PCI bus:\n");
-			bus.ops = &ddb5477_io_pci_ops;
-		}
-	
-		for (devfn = 0; devfn < 0x100; devfn += 8) {
-			u32 temp;
-			u16 temp16;
-			u8 temp8;
-			int i;
-
-			dev.devfn = devfn;
-			db_verify(pci_read_config_dword(&dev, 0, &temp),
-				  == PCIBIOS_SUCCESSFUL);
-			if (temp == 0xffffffff) continue;
-
-			printk("slot %d: (addr %d) \n", devfn/8, 11+devfn/8);
-
-			/* verify read word and byte */
-			db_verify(pci_read_config_word(&dev, 2, &temp16),
-				  == PCIBIOS_SUCCESSFUL);
-			db_assert(temp16 == (temp >> 16));
-			db_verify(pci_read_config_byte(&dev, 3, &temp8),
-				  == PCIBIOS_SUCCESSFUL);
-			db_assert(temp8 == (temp >> 24));
-			db_verify(pci_read_config_byte(&dev, 1, &temp8),
-				  == PCIBIOS_SUCCESSFUL);
-			db_assert(temp8 == ((temp >> 8) & 0xff));
-
-			for (i=0; i < 16; i++) {
-				db_verify(pci_read_config_dword(&dev, i*4, &temp),
-					  == PCIBIOS_SUCCESSFUL);
-				printk("\t%08X", temp);
-				if ((i%4) == 3) printk("\n");
-			}
-		}
-	}
-}
-
-
-static void jsun_hardcode_pci_resources_eepro(void)
-{
-	struct pci_bus bus;
-	struct pci_dev dev;
-	u32 temp;
-
-	bus.parent = NULL;	/* we scan the top level only */
-	bus.ops = &ddb5477_ext_pci_ops;
-	dev.bus = &bus;
-	dev.sysdata = NULL;
-
-	/* for slot 5 (ext pci 1) eepro card */
-	dev.devfn = 5*8;
-	pci_read_config_dword(&dev, 0, &temp);
-	db_assert(temp == 0x12298086);
-
-	pci_write_config_dword(&dev, PCI_BASE_ADDRESS_0, DDB_PCI0_MEM_BASE);
-	pci_write_config_dword(&dev, PCI_BASE_ADDRESS_1, 0);
-	pci_write_config_dword(&dev, PCI_BASE_ADDRESS_2, DDB_PCI0_MEM_BASE+0x100000);
-	pci_write_config_dword(&dev, PCI_INTERRUPT_LINE, 17);
-}
-
-static void jsun_hardcode_pci_resources_onboard_tulip(void)
-{
-	struct pci_bus bus;
-	struct pci_dev dev;
-	u32 temp;
-
-	bus.parent = NULL;	/* we scan the top level only */
-	bus.ops = &ddb5477_ext_pci_ops;
-	dev.bus = &bus;
-	dev.sysdata = NULL;
-
-	/* for slot 4 on board ether chip */
-	dev.devfn = 4*8;
-	pci_read_config_dword(&dev, 0, &temp);
-	db_assert(temp == 0x00191011);
-
-	pci_write_config_dword(&dev, PCI_BASE_ADDRESS_0, 0x1000);
-	pci_write_config_dword(&dev, PCI_BASE_ADDRESS_1, DDB_PCI0_MEM_BASE);
-	pci_write_config_dword(&dev, PCI_INTERRUPT_LINE, 16);
-}
-
-static void jsun_hardcode_pci_resources(void)
-{
-	jsun_hardcode_pci_resources_onboard_tulip();
-}
-
-void jsun_assign_pci_resource(void)
-{
-	jsun_hardcode_pci_resources();
-}
-
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/ddb5xxx/ddb5477/setup.c linux-2.4.20/arch/mips/ddb5xxx/ddb5477/setup.c
--- linux-2.4.19/arch/mips/ddb5xxx/ddb5477/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/ddb5xxx/ddb5477/setup.c	2002-10-29 11:18:36.000000000 +0000
@@ -24,6 +24,7 @@
 #include <linux/ioport.h>
 #include <linux/param.h>	/* for HZ */
 
+#include <asm/cpu.h>
 #include <asm/bootinfo.h>
 #include <asm/addrspace.h>
 #include <asm/time.h>
@@ -31,7 +32,11 @@
 #include <asm/irq.h>
 #include <asm/reboot.h>
 #include <asm/gdb-stub.h>
+#include <asm/traps.h>
 #include <asm/debug.h>
+#ifdef CONFIG_PC_KEYB
+#include <asm/keyboard.h>
+#endif
 
 #include <asm/ddb5xxx/ddb5xxx.h>
 
@@ -40,15 +45,13 @@
 
 // #define	USE_CPU_COUNTER_TIMER	/* whether we use cpu counter */
 
-#ifdef USE_CPU_COUNTER_TIMER
-#define	CPU_COUNTER_FREQUENCY		83000000
-#else
-/* otherwise we use special timer 1 */
-#define	SP_TIMER_FREQUENCY		83000000
+#ifndef USE_CPU_COUNTER_TIMER
 #define	SP_TIMER_BASE			DDB_SPT1CTRL_L
-#define	SP_TIMER_IRQ			(8 + 6)
+#define	SP_TIMER_IRQ			VRC5477_IRQ_SPT1
 #endif
 
+static int bus_frequency = CONFIG_DDB5477_BUS_FREQUENCY*1000;
+
 static void ddb_machine_restart(char *command)
 {
 	static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000;
@@ -79,19 +82,71 @@
 	while (1);
 }
 
+static unsigned int __init detect_bus_frequency(unsigned long rtc_base)
+{
+	unsigned int freq;
+	unsigned char c;
+	unsigned int t1, t2;
+	unsigned i;
+	unsigned preset_freq[]={
+		0,        83330000, 100000000, 124000000,133300000, 0xffffffff};
+
+	ddb_out32(SP_TIMER_BASE, 0xffffffff);
+	ddb_out32(SP_TIMER_BASE+4, 0x1);
+	ddb_out32(SP_TIMER_BASE+8, 0xffffffff);
+	c= *(volatile unsigned char*)rtc_base;
+	for(i=0; (i<100000000) && (c == *(volatile unsigned char*)rtc_base); i++);
+
+	if (c == *(volatile unsigned char*)rtc_base) {
+		printk("Failed to detect bus frequency.  Use default 83.3MHz.\n");
+		return 83333000;
+	}
+
+	/* we are now at the turn of 1/100th second */
+	t1 = ddb_in32(SP_TIMER_BASE+8);
+
+	c= *(volatile unsigned char*)rtc_base;
+	while (c == *(volatile unsigned char*)rtc_base);
+
+	/* we are now at the turn of another 1/100th second */
+	t2 = ddb_in32(SP_TIMER_BASE+8);
+	ddb_out32(SP_TIMER_BASE+4, 0x0);	/* disable it again */
+	freq = (t1 - t2)*100;
+
+	/* find the nearest preset freq */
+	for (i=0; freq > preset_freq[i+1]; i++);
+	if ((freq - preset_freq[i]) >= (preset_freq[i+1]-freq))
+		i++;
+
+	printk("DDB bus frequency detection : %d -> %d\n", freq, preset_freq[i]);
+	return preset_freq[i];
+}
+
 extern void rtc_ds1386_init(unsigned long base);
 static void __init ddb_time_init(void)
 {
-#if defined(USE_CPU_COUNTER_TIMER)
-	mips_counter_frequency = CPU_COUNTER_FREQUENCY;
-#endif
+	unsigned long rtc_base;
+	unsigned int i;
 
 	/* we have ds1396 RTC chip */
-	if (mips_machtype == MACH_NEC_ROCKHOPPER) {
-		rtc_ds1386_init(KSEG1ADDR(DDB_LCS2_BASE));
+	if (mips_machtype == MACH_NEC_ROCKHOPPER
+	   ||  mips_machtype == MACH_NEC_ROCKHOPPERII) {
+		rtc_base = KSEG1ADDR(DDB_LCS2_BASE);
 	} else {
-		rtc_ds1386_init(KSEG1ADDR(DDB_LCS1_BASE));
+		rtc_base = KSEG1ADDR(DDB_LCS1_BASE);
+	}
+	rtc_ds1386_init(rtc_base);
+
+	/* do we need to do run-time detection of bus speed? */
+	if (bus_frequency == 0) {
+		bus_frequency = detect_bus_frequency(rtc_base);
 	}
+
+	/* mips_counter_frequency is 1/2 of the cpu core freq */
+	i =  (read_32bit_cp0_register(CP0_CONFIG) >> 28 ) & 7;
+	if ((mips_cpu.cputype == CPU_R5432) && (i == 3))
+		i = 4;
+	mips_counter_frequency = bus_frequency*(i+4)/4;
 }
 
 extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
@@ -101,7 +156,7 @@
 	unsigned int count;
 
         /* we are using the cpu counter for timer interrupts */
-	setup_irq(7, irq);
+	setup_irq(CPU_IRQ_BASE + 7, irq);
 
         /* to generate the first timer interrupt */
         count = read_32bit_cp0_register(CP0_COUNT);
@@ -109,24 +164,32 @@
 
 #else
 
-	/* if we don't use Special purpose timer 1 */
-	ddb_out32(SP_TIMER_BASE, SP_TIMER_FREQUENCY/HZ);
+	/* if we use Special purpose timer 1 */
+	ddb_out32(SP_TIMER_BASE, bus_frequency/HZ);
 	ddb_out32(SP_TIMER_BASE+4, 0x1);
 	setup_irq(SP_TIMER_IRQ, irq);
 
 #endif
 }
 
+void __init bus_error_init(void) { /* nothing */ }
+
 static void ddb5477_board_init(void);
 extern void ddb5477_irq_setup(void);
 
 #if defined(CONFIG_BLK_DEV_INITRD)
 extern unsigned long __rd_start, __rd_end, initrd_start, initrd_end;
-#endif 
+#endif
 
 void __init ddb_setup(void)
 {
 	extern int panic_timeout;
+#ifdef CONFIG_BLK_DEV_IDE
+	extern struct ide_ops std_ide_ops;
+#endif
+
+	/* initialize board - we don't trust the loader */
+        ddb5477_board_init();
 
 	irq_setup = ddb5477_irq_setup;
 	set_io_port_base(KSEG1ADDR(DDB_PCI_IO_BASE));
@@ -141,17 +204,19 @@
 	/* setup resource limits */
 	ioport_resource.end = DDB_PCI0_IO_SIZE + DDB_PCI1_IO_SIZE - 1;
 	iomem_resource.end = 0xffffffff;
-	
+
 	/* Reboot on panic */
 	panic_timeout = 180;
 
+#ifdef CONFIG_BLK_DEV_IDE
+	ide_ops = &std_ide_ops;
+#endif
+
+
 #ifdef CONFIG_FB
 	conswitchp = &dummy_con;
 #endif
 
-	/* initialize board - we don't trust the loader */
-	ddb5477_board_init();
-
 #if defined(CONFIG_BLK_DEV_INITRD)
 	ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
 	initrd_start = (unsigned long)&__rd_start;
@@ -161,10 +226,13 @@
 
 static void __init ddb5477_board_init()
 {
+#ifdef CONFIG_PC_KEYB
+	extern struct kbd_ops std_kbd_ops;
+#endif
 	/* ----------- setup PDARs ------------ */
 
 	/* SDRAM should have been set */
-	db_assert(ddb_in32(DDB_SDRAM0) == 
+	db_assert(ddb_in32(DDB_SDRAM0) ==
 		    ddb_calc_pdar(DDB_SDRAM_BASE, board_ram_size, 32, 0, 1));
 
 	/* SDRAM1 should be turned off.  What is this for anyway ? */
@@ -193,11 +261,11 @@
 	}
 
 	/* verify VRC5477 base addr */
-	db_assert(ddb_in32(DDB_VRC5477) == 
+	db_assert(ddb_in32(DDB_VRC5477) ==
 		  ddb_calc_pdar(DDB_VRC5477_BASE, DDB_VRC5477_SIZE, 32, 0, 1));
-	
+
 	/* verify BOOT ROM addr */
-	db_assert(ddb_in32(DDB_BOOTCS) == 
+	db_assert(ddb_in32(DDB_BOOTCS) ==
 		  ddb_calc_pdar(DDB_BOOTCS_BASE, DDB_BOOTCS_SIZE, 8, 0, 0));
 
 	/* setup PCI windows - window0 for MEM/config, window1 for IO */
@@ -232,7 +300,7 @@
 	ddb_out32(DDB_BAR51, 0xffffffff);
 	ddb_out32(DDB_BARB1, 0xffffffff);
 
-	/* 
+	/*
 	 * We use pci master register 0  for memory space / config space
 	 * And we use register 1 for IO space.
 	 * Note that for memory space, we bump up the pci base address
@@ -240,22 +308,49 @@
 	 * For PCI IO space, it starts from 0 in PCI IO space but with
 	 * DDB_xx_IO_BASE in CPU physical address space.
 	 */
-	ddb_set_pmr(DDB_PCIINIT00, DDB_PCICMD_MEM, DDB_PCI0_MEM_BASE, 
+	ddb_set_pmr(DDB_PCIINIT00, DDB_PCICMD_MEM, DDB_PCI0_MEM_BASE,
 		    DDB_PCI_ACCESS_32);
 	ddb_set_pmr(DDB_PCIINIT10, DDB_PCICMD_IO, 0, DDB_PCI_ACCESS_32);
 
-	ddb_set_pmr(DDB_PCIINIT01, DDB_PCICMD_MEM, DDB_PCI1_MEM_BASE, 
+	ddb_set_pmr(DDB_PCIINIT01, DDB_PCICMD_MEM, DDB_PCI1_MEM_BASE,
 		    DDB_PCI_ACCESS_32);
-	ddb_set_pmr(DDB_PCIINIT11, DDB_PCICMD_IO, DDB_PCI0_IO_SIZE, 
+	ddb_set_pmr(DDB_PCIINIT11, DDB_PCICMD_IO, DDB_PCI0_IO_SIZE,
                     DDB_PCI_ACCESS_32);
 
-	
+
 	/* PCI cross window should be set properly */
 	ddb_set_pdar(DDB_BARP00, DDB_PCI1_MEM_BASE, DDB_PCI1_MEM_SIZE, 32, 0, 1);
 	ddb_set_pdar(DDB_BARP10, DDB_PCI1_IO_BASE, DDB_PCI1_IO_SIZE, 32, 0, 1);
 	ddb_set_pdar(DDB_BARP01, DDB_PCI0_MEM_BASE, DDB_PCI0_MEM_SIZE, 32, 0, 1);
 	ddb_set_pdar(DDB_BARP11, DDB_PCI0_IO_BASE, DDB_PCI0_IO_SIZE, 32, 0, 1);
 
+	if (mips_machtype == MACH_NEC_ROCKHOPPER
+	   ||  mips_machtype == MACH_NEC_ROCKHOPPERII) {
+		/* Disable bus diagnostics. */
+		ddb_out32(DDB_PCICTL0_L, 0);
+		ddb_out32(DDB_PCICTL0_H, 0);
+		ddb_out32(DDB_PCICTL1_L, 0);
+		ddb_out32(DDB_PCICTL1_H, 0);
+	}
+
+	if (mips_machtype == MACH_NEC_ROCKHOPPER) {
+		u16			vid;
+		struct pci_bus		bus;
+		struct pci_dev		dev_m1533;
+		extern struct pci_ops 	ddb5477_ext_pci_ops;
+
+		bus.parent      = NULL;    /* we scan the top level only */
+		bus.ops         = &ddb5477_ext_pci_ops;
+		dev_m1533.bus         = &bus;
+		dev_m1533.sysdata     = NULL;
+		dev_m1533.devfn       = 7*8;     // slot 7: M1533 SouthBridge.
+		pci_read_config_word(&dev_m1533, 0, &vid);
+		if (vid == PCI_VENDOR_ID_AL) {
+			printk("Changing mips_machtype to MACH_NEC_ROCKHOPPERII\n");
+			mips_machtype = MACH_NEC_ROCKHOPPERII;
+		}
+	}
+
 	/* enable USB input buffers */
 	ddb_out32(DDB_PIBMISC, 0x00000007);
 
@@ -263,9 +358,83 @@
 	ddb_out32(DDB_GIUFUNSEL, 0x0);
 	// ddb_out32(DDB_GIUFUNSEL, 0xfe0fcfff);  /* NEC recommanded value */
 
-	if (mips_machtype == MACH_NEC_ROCKHOPPER) {
+	if (mips_machtype == MACH_NEC_ROCKHOPPERII) {
+#ifdef CONFIG_PC_KEYB
+	printk("kdb_ops is std\n");
+	kbd_ops = &std_kbd_ops;
+#endif
+	}
+
+	if (mips_machtype == MACH_NEC_ROCKHOPPERII) {
+
+		/* enable IDE controller on Ali chip (south bridge) */
+		u8			temp8;
+		struct pci_bus		bus;
+		struct pci_dev		dev_m1533;
+		struct pci_dev		dev_m5229;
+		extern struct pci_ops 	ddb5477_ext_pci_ops;
+
+		/* Setup M1535 registers */
+		bus.parent      = NULL;    /* we scan the top level only */
+		bus.ops         = &ddb5477_ext_pci_ops;
+		dev_m1533.bus         = &bus;
+		dev_m1533.sysdata     = NULL;
+		dev_m1533.devfn       = 7*8;     // slot 7: M1533 SouthBridge.
+
+		/* setup IDE controller
+		 * enable IDE controller (bit 6 - 1)
+		 * IDE IDSEL to be addr:A15 (bit 4:5 - 11)
+		 * disable IDE ATA Secondary Bus Signal Pad Control (bit 3 - 0)
+		 * enable IDE ATA Primary Bus Signal Pad Control (bit 2 - 1)
+		 */
+		pci_write_config_byte(&dev_m1533, 0x58, 0x74);
+
+		/*
+		 * positive decode (bit6 -0)
+		 * enable IDE controler interrupt (bit 4 -1)
+		 * setup SIRQ to point to IRQ 14 (bit 3:0 - 1101)
+		 */
+		pci_write_config_byte(&dev_m1533, 0x44, 0x1d);
+
+		/* Setup M5229 registers */
+		dev_m5229.bus = &bus;
+		dev_m5229.sysdata = NULL;
+		dev_m5229.devfn = 4*8;  	// slot 4 (AD15): M5229 IDE
+
+		/*
+		 * enable IDE in the M5229 config register 0x50 (bit 0 - 1)
+		 * M5229 IDSEL is addr:15; see above setting
+		 */
+		pci_read_config_byte(&dev_m5229, 0x50, &temp8);
+		pci_write_config_byte(&dev_m5229, 0x50, temp8 | 0x1);
+
+		/*
+		 * enable bus master (bit 2)  and IO decoding  (bit 0)
+		 */
+		pci_read_config_byte(&dev_m5229, 0x04, &temp8);
+		pci_write_config_byte(&dev_m5229, 0x04, temp8 | 0x5);
+
+		/*
+		 * enable native, copied from arch/ppc/k2boot/head.S
+		 * TODO - need volatile, need to be portable
+		 */
+		pci_write_config_byte(&dev_m5229, 0x09, 0xef);
+
+		/* Set Primary Channel Command Block Timing */
+		pci_write_config_byte(&dev_m5229, 0x59, 0x31);
+
+		/*
+		 * Enable primary channel 40-pin cable
+		 * M5229 register 0x4a (bit 0)
+		 */
+		pci_read_config_byte(&dev_m5229, 0x4a, &temp8);
+		pci_write_config_byte(&dev_m5229, 0x4a, temp8 | 0x1);
+	}
+
+	if (mips_machtype == MACH_NEC_ROCKHOPPER
+	   ||  mips_machtype == MACH_NEC_ROCKHOPPERII) {
 		printk("lcd44780: initializing\n");
 		lcd44780_init();
-		lcd44780_puts("Linux/MIPS rolls");
+		lcd44780_puts("MontaVista Linux");
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/dec/Makefile linux-2.4.20/arch/mips/dec/Makefile
--- linux-2.4.19/arch/mips/dec/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/dec/Makefile	2002-10-29 11:18:36.000000000 +0000
@@ -14,9 +14,10 @@
 
 export-objs := setup.o wbflush.o
 obj-y	 := int-handler.o ioasic-irq.o kn02-irq.o reset.o rtc-dec.o setup.o \
-	time.o wbflush.o
+	time.o
 
 obj-$(CONFIG_PROM_CONSOLE)	+= promcon.o
+obj-$(CONFIG_CPU_HAS_WB)	+= wbflush.o
 
 int-handler.o:	int-handler.S
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/dec/int-handler.S linux-2.4.20/arch/mips/dec/int-handler.S
--- linux-2.4.19/arch/mips/dec/int-handler.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/dec/int-handler.S	2002-10-29 11:18:33.000000000 +0000
@@ -240,7 +240,7 @@
 		srl	t0,IO_INR_DMA
 		li	t1,IO_IRQ_DMA>>IO_INR_DMA # mask
 		li	t2,8			# nr of bits / 2
-		
+
 		/*
 		 * Find irq with highest priority.
 		 * Highest irq number takes precedence.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/dec/ioasic-irq.c linux-2.4.20/arch/mips/dec/ioasic-irq.c
--- linux-2.4.19/arch/mips/dec/ioasic-irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/dec/ioasic-irq.c	2002-10-29 11:18:35.000000000 +0000
@@ -84,6 +84,7 @@
 	spin_lock(&ioasic_lock);
 	mask_ioasic_irq(irq);
 	spin_unlock(&ioasic_lock);
+	fast_iob();
 }
 
 static inline void end_ioasic_irq(unsigned int irq)
@@ -119,6 +120,7 @@
 static inline void end_ioasic_dma_irq(unsigned int irq)
 {
 	clear_ioasic_irq(irq);
+	fast_iob();
 	end_ioasic_irq(irq);
 }
 
@@ -142,6 +144,7 @@
 
 	/* Mask interrupts. */
 	ioasic_write(SIMR, 0);
+	fast_iob();
 
 	for (i = base; i < base + IO_INR_DMA; i++) {
 		irq_desc[i].status = IRQ_DISABLED;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/dec/irq.c linux-2.4.20/arch/mips/dec/irq.c
--- linux-2.4.19/arch/mips/dec/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/dec/irq.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,307 +0,0 @@
-/*
- * Code to handle DECstation IRQs plus some generic interrupt stuff.
- *
- * Copyright (C) 1992 Linus Torvalds
- * Copyright (C) 1994, 1995, 1996, 1997, 2000 Ralf Baechle
- */
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-
-#include <asm/bitops.h>
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/mipsregs.h>
-#include <asm/system.h>
-
-#include <asm/dec/interrupts.h>
-
-extern void dec_init_kn01(void);
-extern void dec_init_kn230(void);
-extern void dec_init_kn02(void);
-extern void dec_init_kn02ba(void);
-extern void dec_init_kn02ca(void);
-extern void dec_init_kn03(void);
-
-extern asmlinkage void decstation_handle_int(void);
-
-atomic_t irq_err_count;
-
-static inline void mask_irq(unsigned int irq_nr)
-{
-	unsigned int dummy;
-
-	if (dec_interrupt[irq_nr].iemask) {	/* This is an ASIC interrupt    */
-		*imr &= ~dec_interrupt[irq_nr].iemask;
-		dummy = *imr;
-		dummy = *imr;
-	} else			/* This is a cpu interrupt        */
-		change_cp0_status(ST0_IM,
-				  read_32bit_cp0_register(CP0_STATUS) &
-				  ~dec_interrupt[irq_nr].cpu_mask);
-}
-
-static inline void unmask_irq(unsigned int irq_nr)
-{
-	unsigned int dummy;
-
-	if (dec_interrupt[irq_nr].iemask) {	/* This is an ASIC interrupt    */
-		*imr |= dec_interrupt[irq_nr].iemask;
-		dummy = *imr;
-		dummy = *imr;
-	}
-	change_cp0_status(ST0_IM,
-			  read_32bit_cp0_register(CP0_STATUS) |
-			  dec_interrupt[irq_nr].cpu_mask);
-}
-
-void disable_irq(unsigned int irq_nr)
-{
-	unsigned long flags;
-
-	save_and_cli(flags);
-	mask_irq(irq_nr);
-	restore_flags(flags);
-}
-
-void enable_irq(unsigned int irq_nr)
-{
-	unsigned long flags;
-
-	save_and_cli(flags);
-	unmask_irq(irq_nr);
-	restore_flags(flags);
-}
-
-/*
- * Pointers to the low-level handlers: first the general ones, then the
- * fast ones, then the bad ones.
- */
-extern void interrupt(void);
-
-static struct irqaction *irq_action[32] = {
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
-};
-
-int get_irq_list(char *buf)
-{
-	int i, len = 0;
-	struct irqaction *action;
-
-	for (i = 0; i < 32; i++) {
-		action = irq_action[i];
-		if (!action)
-			continue;
-		len += sprintf(buf + len, "%2d: %8d %c %s",
-			       i, kstat.irqs[0][i],
-			       (action->flags & SA_INTERRUPT) ? '+' : ' ',
-			       action->name);
-		for (action = action->next; action; action = action->next) {
-			len += sprintf(buf + len, ",%s %s",
-				       (action->
-					flags & SA_INTERRUPT) ? " +" : "",
-				       action->name);
-		}
-		len += sprintf(buf + len, "\n");
-	}
-	return len;
-}
-
-/*
- * do_IRQ handles IRQ's that have been installed without the
- * SA_INTERRUPT flag: it uses the full signal-handling return
- * and runs with other interrupts enabled. All relatively slow
- * IRQ's should use this format: notably the keyboard/timer
- * routines.
- */
-asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
-{
-	struct irqaction *action;
-	int do_random, cpu;
-
-	cpu = smp_processor_id();
-	irq_enter(cpu, irq);
-	kstat.irqs[cpu][irq]++;
-
-	mask_irq(irq);
-	action = *(irq + irq_action);
-	if (action) {
-		if (!(action->flags & SA_INTERRUPT))
-			__sti();
-		action = *(irq + irq_action);
-		do_random = 0;
-		do {
-			do_random |= action->flags;
-			action->handler(irq, action->dev_id, regs);
-			action = action->next;
-		} while (action);
-		if (do_random & SA_SAMPLE_RANDOM)
-			add_interrupt_randomness(irq);
-		__cli();
-		unmask_irq(irq);
-	}
-	irq_exit(cpu, irq);
-
-	if (softirq_pending(cpu))
-		do_softirq();
-}
-
-/*
- * Idea is to put all interrupts
- * in a single table and differenciate them just by number.
- */
-int setup_dec_irq(int irq, struct irqaction *new)
-{
-	int shared = 0;
-	struct irqaction *old, **p;
-	unsigned long flags;
-
-	p = irq_action + irq;
-	if ((old = *p) != NULL) {
-		/* Can't share interrupts unless both agree to */
-		if (!(old->flags & new->flags & SA_SHIRQ))
-			return -EBUSY;
-
-		/* Can't share interrupts unless both are same type */
-		if ((old->flags ^ new->flags) & SA_INTERRUPT)
-			return -EBUSY;
-
-		/* add new interrupt at end of irq queue */
-		do {
-			p = &old->next;
-			old = *p;
-		} while (old);
-		shared = 1;
-	}
-	if (new->flags & SA_SAMPLE_RANDOM)
-		rand_initialize_irq(irq);
-
-	save_and_cli(flags);
-	*p = new;
-
-	if (!shared) {
-		unmask_irq(irq);
-	}
-	restore_flags(flags);
-	return 0;
-}
-
-int request_irq(unsigned int irq,
-		void (*handler) (int, void *, struct pt_regs *),
-		unsigned long irqflags, const char *devname, void *dev_id)
-{
-	int retval;
-	struct irqaction *action;
-
-	if (irq >= 32)
-		return -EINVAL;
-	if (!handler)
-		return -EINVAL;
-
-	action =
-	    (struct irqaction *) kmalloc(sizeof(struct irqaction),
-					 GFP_KERNEL);
-	if (!action)
-		return -ENOMEM;
-
-	action->handler = handler;
-	action->flags = irqflags;
-	action->mask = 0;
-	action->name = devname;
-	action->next = NULL;
-	action->dev_id = dev_id;
-
-	retval = setup_dec_irq(irq, action);
-
-	if (retval)
-		kfree(action);
-	return retval;
-}
-
-void free_irq(unsigned int irq, void *dev_id)
-{
-	struct irqaction *action, **p;
-	unsigned long flags;
-
-	if (irq > 39) {
-		printk("Trying to free IRQ%d\n", irq);
-		return;
-	}
-	for (p = irq + irq_action; (action = *p) != NULL;
-	     p = &action->next) {
-		if (action->dev_id != dev_id)
-			continue;
-
-		/* Found it - now free it */
-		save_and_cli(flags);
-		*p = action->next;
-		if (!irq[irq_action])
-			mask_irq(irq);
-		restore_flags(flags);
-		kfree(action);
-		return;
-	}
-	printk("Trying to free free IRQ%d\n", irq);
-}
-
-unsigned long probe_irq_on(void)
-{
-	/* TODO */
-	return 0;
-}
-
-int probe_irq_off(unsigned long irqs)
-{
-	/* TODO */
-	return 0;
-}
-
-void init_irq_proc(void)
-{
-	/* Nothing, for now.  */
-}
-
-void __init init_IRQ(void)
-{
-	switch (mips_machtype) {
-	case MACH_DS23100:
-		dec_init_kn01();
-		break;
-	case MACH_DS5100:	/*  DS5100 MIPSMATE */
-		dec_init_kn230();
-		break;
-	case MACH_DS5000_200:	/* DS5000 3max */
-		dec_init_kn02();
-		break;
-	case MACH_DS5000_1XX:	/* DS5000/100 3min */
-		dec_init_kn02ba();
-		break;
-	case MACH_DS5000_2X0:	/* DS5000/240 3max+ */
-		dec_init_kn03();
-		break;
-	case MACH_DS5000_XX:	/* Personal DS5000/2x */
-		dec_init_kn02ca();
-		break;
-	case MACH_DS5800:	/* DS5800 Isis */
-		panic("Don't know how to set this up!");
-		break;
-	case MACH_DS5400:	/* DS5400 MIPSfair */
-		panic("Don't know how to set this up!");
-		break;
-	case MACH_DS5500:	/* DS5500 MIPSfair-2 */
-		panic("Don't know how to set this up!");
-		break;
-	}
-	set_except_vector(0, decstation_handle_int);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/dec/kn02-irq.c linux-2.4.20/arch/mips/dec/kn02-irq.c
--- linux-2.4.19/arch/mips/dec/kn02-irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/dec/kn02-irq.c	2002-10-29 11:18:33.000000000 +0000
@@ -83,6 +83,7 @@
 	spin_lock(&kn02_lock);
 	mask_kn02_irq(irq);
 	spin_unlock(&kn02_lock);
+	iob();
 }
 
 static void end_kn02_irq(unsigned int irq)
@@ -113,6 +114,7 @@
 	/* Mask interrupts and preset write-only bits. */
 	cached_kn02_csr = (*csr & ~0xff0000) | 0xff;
 	*csr = cached_kn02_csr;
+	iob();
 
 	for (i = base; i < base + KN02_IRQ_LINES; i++) {
 		irq_desc[i].status = IRQ_DISABLED;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/dec/prom/identify.c linux-2.4.20/arch/mips/dec/prom/identify.c
--- linux-2.4.19/arch/mips/dec/prom/identify.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/dec/prom/identify.c	2002-10-29 11:18:38.000000000 +0000
@@ -21,7 +21,7 @@
 
 extern unsigned long mips_machtype;
 const char *get_system_type(void)
-{ 
+{
 	static char system[32];
 	int called = 0;
 	const char *dec_system_strings[] = { "unknown", "DECstation 2100/3100",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/dec/prom/init.c linux-2.4.20/arch/mips/dec/prom/init.c
--- linux-2.4.19/arch/mips/dec/prom/init.c	2001-09-09 17:43:01.000000000 +0000
+++ linux-2.4.20/arch/mips/dec/prom/init.c	2002-10-29 11:18:48.000000000 +0000
@@ -77,7 +77,7 @@
 		pmax_read = (int (*)(int, void *, int)) PMAX_PROM_READ;
 		pmax_close = (int (*)(int)) PMAX_PROM_CLOSE;
 	}
-} 
+}
 
 int __init prom_init(int argc, char **argv,
 	       unsigned long magic, int *prom_vec)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/dec/prom/prom.h linux-2.4.20/arch/mips/dec/prom/prom.h
--- linux-2.4.19/arch/mips/dec/prom/prom.h	1999-06-26 00:40:12.000000000 +0000
+++ linux-2.4.20/arch/mips/dec/prom/prom.h	2002-10-29 11:18:34.000000000 +0000
@@ -1,11 +1,11 @@
-/*  
+/*
  * Miscellaneous definitions used to call the routines contained in the boot
  * PROMs on various models of DECSTATION's.
  * the rights to redistribute these changes.
  */
 
-#ifndef __ASM_DEC_PROM_H 
-#define __ASM_DEC_PROM_H 
+#ifndef __ASM_DEC_PROM_H
+#define __ASM_DEC_PROM_H
 
 /*
  * PMAX/3MAX PROM entry points for DS2100/3100's and DS5000/2xx's.  Many of
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/dec/promcon.c linux-2.4.20/arch/mips/dec/promcon.c
--- linux-2.4.19/arch/mips/dec/promcon.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/dec/promcon.c	2002-10-29 11:18:48.000000000 +0000
@@ -2,7 +2,7 @@
  * Wrap-around code for a console using the
  * DECstation PROM io-routines.
  *
- * Copyright (c) 1998 Harald Koerfgen 
+ * Copyright (c) 1998 Harald Koerfgen
  */
 
 #include <linux/tty.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/dec/rtc-dec.c linux-2.4.20/arch/mips/dec/rtc-dec.c
--- linux-2.4.19/arch/mips/dec/rtc-dec.c	2001-09-09 17:43:01.000000000 +0000
+++ linux-2.4.20/arch/mips/dec/rtc-dec.c	2002-10-29 11:18:36.000000000 +0000
@@ -3,33 +3,35 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * RTC routines for DECstation style attached Dallas chip.
+ * RTC routines for DECstation style attached Dallas DS1287 chip.
  *
  * Copyright (C) 1998, 2001 by Ralf Baechle
  * Copyright (C) 1998 by Harald Koerfgen
+ * Copyright (C) 2002  Maciej W. Rozycki
  */
+
 #include <linux/mc146818rtc.h>
+#include <linux/types.h>
 
-extern char *dec_rtc_base;
+volatile u8 *dec_rtc_base;
 
 static unsigned char dec_rtc_read_data(unsigned long addr)
 {
-    return (dec_rtc_base[addr * 4]);
+	return dec_rtc_base[addr * 4];
 }
 
 static void dec_rtc_write_data(unsigned char data, unsigned long addr)
 {
-    dec_rtc_base[addr * 4] = data;
+	dec_rtc_base[addr * 4] = data;
 }
 
 static int dec_rtc_bcd_mode(void)
 {
-    return 0;
+	return 0;
 }
 
-struct rtc_ops dec_rtc_ops =
-{
-    &dec_rtc_read_data,
-    &dec_rtc_write_data,
-    &dec_rtc_bcd_mode
+struct rtc_ops dec_rtc_ops = {
+	&dec_rtc_read_data,
+	&dec_rtc_write_data,
+	&dec_rtc_bcd_mode
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/dec/setup.c linux-2.4.20/arch/mips/dec/setup.c
--- linux-2.4.19/arch/mips/dec/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/dec/setup.c	2002-10-29 11:18:37.000000000 +0000
@@ -25,6 +25,7 @@
 #include <asm/mipsregs.h>
 #include <asm/reboot.h>
 #include <asm/traps.h>
+#include <asm/wbflush.h>
 
 #include <asm/dec/interrupts.h>
 #include <asm/dec/kn01.h>
@@ -45,10 +46,8 @@
 
 extern asmlinkage void decstation_handle_int(void);
 
-
-char *dec_rtc_base = (void *) KN01_RTC_BASE; /* Assume DS2100/3100 initially */
-
 volatile u32 *ioasic_base;
+unsigned long dec_kn_slot_size;
 
 /*
  * IRQ routing and priority tables.  Priorites are set as follows:
@@ -71,7 +70,7 @@
  *
  * * -- shared with SCSI
  */
- 
+
 int dec_interrupt[DEC_NR_INTS] = {
 	[0 ... DEC_NR_INTS - 1] = -1
 };
@@ -89,10 +88,6 @@
 static struct irqaction haltirq = {dec_intr_halt, 0, 0, "halt", NULL, NULL};
 
 
-extern void wbflush_setup(void);
-
-extern struct rtc_ops dec_rtc_ops;
-
 void (*board_time_init) (struct irqaction * irq);
 
 
@@ -208,7 +203,8 @@
 void __init dec_init_kn01(void)
 {
 	/* Setup some memory addresses. */
-	dec_rtc_base = (char *) KN01_RTC_BASE;
+	dec_rtc_base = (void *)KN01_RTC_BASE;
+	dec_kn_slot_size = KN01_SLOT_SIZE;
 
 	/* IRQ routing. */
 	memcpy(&dec_interrupt, &kn01_interrupt,
@@ -286,7 +282,8 @@
 void __init dec_init_kn230(void)
 {
 	/* Setup some memory addresses. */
-	dec_rtc_base = (char *) KN01_RTC_BASE;
+	dec_rtc_base = (void *)KN01_RTC_BASE;
+	dec_kn_slot_size = KN01_SLOT_SIZE;
 
 	/* IRQ routing. */
 	memcpy(&dec_interrupt, &kn230_interrupt,
@@ -379,7 +376,8 @@
 void __init dec_init_kn02(void)
 {
 	/* Setup some memory addresses. */
-	dec_rtc_base = (char *) KN02_RTC_BASE;
+	dec_rtc_base = (void *)KN02_RTC_BASE;
+	dec_kn_slot_size = KN02_SLOT_SIZE;
 
 	/* IRQ routing. */
 	memcpy(&dec_interrupt, &kn02_interrupt,
@@ -426,7 +424,7 @@
 	[DEC_IRQ_TC2]		= DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC2),
 	[DEC_IRQ_TIMER]		= -1,
 	[DEC_IRQ_VIDEO]		= -1,
-	[DEC_IRQ_ASC_MERR]	= IO_IRQ_NR(IO_INR_LANCE_MERR),
+	[DEC_IRQ_ASC_MERR]	= IO_IRQ_NR(IO_INR_ASC_MERR),
 	[DEC_IRQ_ASC_ERR]	= IO_IRQ_NR(IO_INR_ASC_ERR),
 	[DEC_IRQ_ASC_DMA]	= IO_IRQ_NR(IO_INR_ASC_DMA),
 	[DEC_IRQ_FLOPPY_ERR]	= -1,
@@ -483,8 +481,9 @@
 void __init dec_init_kn02ba(void)
 {
 	/* Setup some memory addresses. */
-	ioasic_base = (void *) KN02BA_IOASIC_BASE;
-	dec_rtc_base = (char *) KN02BA_RTC_BASE;
+	ioasic_base = (void *)KN02BA_IOASIC_BASE;
+	dec_rtc_base = (void *)KN02BA_RTC_BASE;
+	dec_kn_slot_size = IOASIC_SLOT_SIZE;
 
 	/* IRQ routing. */
 	memcpy(&dec_interrupt, &kn02ba_interrupt,
@@ -584,8 +583,9 @@
 void __init dec_init_kn02ca(void)
 {
 	/* Setup some memory addresses. */
-	ioasic_base = (void *) KN02CA_IOASIC_BASE;
-	dec_rtc_base = (char *) KN02CA_RTC_BASE;
+	ioasic_base = (void *)KN02CA_IOASIC_BASE;
+	dec_rtc_base = (void *)KN02CA_RTC_BASE;
+	dec_kn_slot_size = IOASIC_SLOT_SIZE;
 
 	/* IRQ routing. */
 	memcpy(&dec_interrupt, &kn02ca_interrupt,
@@ -659,9 +659,9 @@
 		{ i: DEC_CPU_IRQ_NR(KN03_CPU_INR_MEMORY) } },
 	{ { i: DEC_CPU_IRQ_MASK(KN03_CPU_INR_RTC) },
 		{ i: DEC_CPU_IRQ_NR(KN03_CPU_INR_RTC) } },
-	{ { i: DEC_CPU_IRQ_MASK(KN03_CPU_INR_CASCADE) }, 
+	{ { i: DEC_CPU_IRQ_MASK(KN03_CPU_INR_CASCADE) },
 		{ p: kn03_io_int } },
-	{ { i: DEC_CPU_IRQ_ALL }, 
+	{ { i: DEC_CPU_IRQ_ALL },
 		{ p: cpu_all_int } },
 };
 
@@ -689,12 +689,13 @@
 void __init dec_init_kn03(void)
 {
 	/* Setup some memory addresses.  */
-	ioasic_base = (void *) KN03_IOASIC_BASE;
-	dec_rtc_base = (char *) KN03_RTC_BASE;
+	ioasic_base = (void *)KN03_IOASIC_BASE;
+	dec_rtc_base = (void *)KN03_RTC_BASE;
+	dec_kn_slot_size = IOASIC_SLOT_SIZE;
 
 	/* IRQ routing. */
 	memcpy(&dec_interrupt, &kn03_interrupt,
-		sizeof(kn03_interrupt));	
+		sizeof(kn03_interrupt));
 
 	/* CPU IRQ priorities. */
 	memcpy(&cpu_mask_nr_tbl, &kn03_cpu_mask_nr_tbl,
@@ -760,4 +761,7 @@
 		setup_irq(dec_interrupt[DEC_IRQ_HALT], &haltirq);
 }
 
+EXPORT_SYMBOL(ioasic_base);
+EXPORT_SYMBOL(dec_rtc_base);
+EXPORT_SYMBOL(dec_kn_slot_size);
 EXPORT_SYMBOL(dec_interrupt);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/dec/time.c linux-2.4.20/arch/mips/dec/time.c
--- linux-2.4.19/arch/mips/dec/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/dec/time.c	2002-10-29 11:18:35.000000000 +0000
@@ -110,7 +110,7 @@
 		: "r" (count), "r" (quotient));
 
 	/*
-	 * Due to possible jiffies inconsistencies, we need to check 
+	 * Due to possible jiffies inconsistencies, we need to check
 	 * the result so that we'll get a timer that is monotonic.
 	 */
 	if (res >= USECS_PER_JIFFY)
@@ -160,9 +160,9 @@
 	return res;
 }
 
-/* This function must be called with interrupts disabled 
+/* This function must be called with interrupts disabled
  * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
- * 
+ *
  * However, the pc-audio speaker driver changes the divisor so that
  * it gets interrupted rather more often - it loads 64 into the
  * counter rather than 11932! This has an adverse impact on
@@ -176,7 +176,7 @@
  * using either the RTC or the 8253 timer. The decision would be
  * based on whether there was any other device around that needed
  * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
- * and then do some jiggery to have a version of do_timer that 
+ * and then do some jiggery to have a version of do_timer that
  * advanced the clock by 1/1024 s. Every time that reached over 1/100
  * of a second, then do all the old code. If the time was kept correct
  * then do_gettimeoffset could just return 0 - there is no low order
@@ -187,7 +187,7 @@
  * often than every 120 us or so.
  *
  * Anyway, this needs more thought....          pjsg (1993-08-28)
- * 
+ *
  * If you are really that interested, you should be reading
  * comp.protocols.time.ntp!
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/dec/wbflush.c linux-2.4.20/arch/mips/dec/wbflush.c
--- linux-2.4.19/arch/mips/dec/wbflush.c	2001-10-05 19:06:51.000000000 +0000
+++ linux-2.4.20/arch/mips/dec/wbflush.c	2002-10-29 11:18:49.000000000 +0000
@@ -11,15 +11,18 @@
  * for more details.
  *
  * Copyright (C) 1998 Harald Koerfgen
+ * Copyright (C) 2002 Maciej W. Rozycki
  */
 
-#include <asm/bootinfo.h>
 #include <linux/init.h>
 
+#include <asm/bootinfo.h>
+#include <asm/system.h>
+#include <asm/wbflush.h>
+
 static void wbflush_kn01(void);
 static void wbflush_kn210(void);
-static void wbflush_kn02ba(void);
-static void wbflush_kn03(void);
+static void wbflush_mips(void);
 
 void (*__wbflush) (void);
 
@@ -27,28 +30,23 @@
 {
 	switch (mips_machtype) {
 	case MACH_DS23100:
-	    __wbflush = wbflush_kn01;
-	    break;
-	case MACH_DS5100:	/*  DS5100 MIPSMATE */
-	    __wbflush = wbflush_kn210;
-	    break;
 	case MACH_DS5000_200:	/* DS5000 3max */
-	    __wbflush = wbflush_kn01;
-	    break;
+		__wbflush = wbflush_kn01;
+		break;
+	case MACH_DS5100:	/* DS5100 MIPSMATE */
+		__wbflush = wbflush_kn210;
+		break;
 	case MACH_DS5000_1XX:	/* DS5000/100 3min */
-	    __wbflush = wbflush_kn02ba;
-	    break;
-	case MACH_DS5000_2X0:	/* DS5000/240 3max+ */
-	    __wbflush = wbflush_kn03;
-	    break;
 	case MACH_DS5000_XX:	/* Personal DS5000/2x */
-	    __wbflush = wbflush_kn02ba;
-	    break;
+	case MACH_DS5000_2X0:	/* DS5000/240 3max+ */
+	default:
+		__wbflush = wbflush_mips;
+		break;
 	}
 }
 
 /*
- * For the DS3100 and DS5000/200 the writeback buffer functions
+ * For the DS3100 and DS5000/200 the R2020/R3220 writeback buffer functions
  * as part of Coprocessor 0.
  */
 static void wbflush_kn01(void)
@@ -78,29 +76,16 @@
 	"mtc0\t$2,$12\n\t"
 	"nop\n\t"
 	".set\tpop"
-  : : :"$2", "$3");
-}
-
-/*
- * Looks like some magic with the System Interrupt Mask Register
- * in the famous IOASIC for kmins and maxines.
- */
-static void wbflush_kn02ba(void)
-{
-    asm(".set\tpush\n\t"
-	".set\tnoreorder\n\t"
-	"lui\t$2,0xbc04\n\t"
-	"lw\t$3,0x120($2)\n\t"
-	"lw\t$3,0x120($2)\n\t"
-	".set\tpop"
-  : : :"$2", "$3");
+	: : : "$2", "$3");
 }
 
 /*
- * The DS500/2x0 doesnt need to write back the WB.
+ * I/O ASIC systems use a standard writeback buffer that gets flushed
+ * upon an uncached read.
  */
-static void wbflush_kn03(void)
+static void wbflush_mips(void)
 {
+	__fast_iob();
 }
 
 #include <linux/module.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig linux-2.4.20/arch/mips/defconfig
--- linux-2.4.19/arch/mips/defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig	2002-10-29 11:18:33.000000000 +0000
@@ -3,6 +3,7 @@
 #
 CONFIG_MIPS=y
 CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
 
 #
 # Code maturity level options
@@ -21,6 +22,7 @@
 #
 # CONFIG_ACER_PICA_61 is not set
 # CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
 # CONFIG_MIPS_PB1500 is not set
 # CONFIG_ALGOR_P4032 is not set
 # CONFIG_BAGET_MIPS is not set
@@ -34,53 +36,68 @@
 # CONFIG_MIPS_ATLAS is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
 # CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
 # CONFIG_DDB5074 is not set
 # CONFIG_DDB5476 is not set
 # CONFIG_DDB5477 is not set
 # CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
 # CONFIG_OLIVETTI_M700 is not set
 # CONFIG_NINO is not set
 CONFIG_SGI_IP22=y
-# CONFIG_SIBYTE_SB1250 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
 # CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_ARC32=y
+CONFIG_ARC_CONSOLE=y
+CONFIG_ARC_MEMORY=y
 CONFIG_BOARD_SCACHE=y
+CONFIG_BOOT_ELF32=y
+CONFIG_SWAP_IO_SPACE=y
 CONFIG_IRQ_CPU=y
-CONFIG_PC_KEYB=y
-CONFIG_SGI=y
+CONFIG_L1_CACHE_SHIFT=5
+CONFIG_NONCOHERENT_IO=y
 CONFIG_NEW_IRQ=y
 CONFIG_NEW_TIME_C=y
 CONFIG_NONCOHERENT_IO=y
+CONFIG_PC_KEYB=y
+CONFIG_SGI=y
 # CONFIG_MIPS_AU1000 is not set
 
 #
 # CPU selection
 #
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
 CONFIG_CPU_R5000=y
 # CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
-# CONFIG_CPU_MIPS32 is not set
-# CONFIG_CPU_MIPS64 is not set
+CONFIG_BOARD_SCACHE=y
 # CONFIG_64BIT_PHYS_ADDR is not set
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_LLDSCD=y
 # CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
@@ -88,7 +105,8 @@
 # CONFIG_CPU_LITTLE_ENDIAN is not set
 CONFIG_BINFMT_IRIX=y
 CONFIG_FORWARD_KEYBOARD=y
-# CONFIG_ARC_CONSOLE is not set
+CONFIG_ARC_CONSOLE=y
+# CONFIG_IP22_EISA is not set
 CONFIG_NET=y
 # CONFIG_PCI is not set
 # CONFIG_ISA is not set
@@ -106,6 +124,8 @@
 # CONFIG_KCORE_AOUT is not set
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PM is not set
 
@@ -140,6 +160,7 @@
 # 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)
@@ -219,6 +240,13 @@
 # CONFIG_PHONE_IXJ_PCMCIA is not set
 
 #
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
 # SCSI support
 #
 CONFIG_SCSI=y
@@ -321,6 +349,7 @@
 #
 # 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
@@ -367,6 +396,15 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -419,7 +457,6 @@
 # CONFIG_EUROTECH_WDT is not set
 # CONFIG_IB700_WDT is not set
 # CONFIG_WAFER_WDT is not set
-CONFIG_INDYDOG=y
 # CONFIG_I810_TCO is not set
 # CONFIG_MIXCOMWD is not set
 # CONFIG_60XX_WDT is not set
@@ -430,6 +467,7 @@
 # CONFIG_WDTPCI is not set
 # CONFIG_MACHZ_WDT is not set
 CONFIG_INDYDOG=y
+# CONFIG_AMD7XX_TCO is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -444,11 +482,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # SGI Character devices
 #
 CONFIG_SGI_NEWPORT_CONSOLE=y
@@ -468,6 +501,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -485,6 +520,9 @@
 CONFIG_ISO9660_FS=y
 # 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
@@ -515,6 +553,7 @@
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
@@ -528,7 +567,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -548,10 +586,16 @@
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Console drivers
 #
 # CONFIG_VGA_CONSOLE is not set
@@ -586,18 +630,15 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
 # CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig-atlas linux-2.4.20/arch/mips/defconfig-atlas
--- linux-2.4.19/arch/mips/defconfig-atlas	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig-atlas	2002-10-29 11:18:37.000000000 +0000
@@ -3,6 +3,7 @@
 #
 CONFIG_MIPS=y
 CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
 
 #
 # Code maturity level options
@@ -19,6 +20,7 @@
 #
 # CONFIG_ACER_PICA_61 is not set
 # CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
 # CONFIG_MIPS_PB1500 is not set
 # CONFIG_ALGOR_P4032 is not set
 # CONFIG_BAGET_MIPS is not set
@@ -32,20 +34,28 @@
 CONFIG_MIPS_ATLAS=y
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
 # CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
 # CONFIG_DDB5074 is not set
 # CONFIG_DDB5476 is not set
 # CONFIG_DDB5477 is not set
 # CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
 # CONFIG_OLIVETTI_M700 is not set
 # CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
-# CONFIG_SIBYTE_SB1250 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
 # CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_BOOT_ELF32=y
+CONFIG_L1_CACHE_SHIFT=5
 CONFIG_NEW_IRQ=y
 CONFIG_NEW_TIME_C=y
 CONFIG_NONCOHERENT_IO=y
@@ -56,32 +66,36 @@
 #
 # CPU selection
 #
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS64 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
-CONFIG_CPU_R5000=y
+# CONFIG_CPU_R5000 is not set
 # CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
-# CONFIG_CPU_MIPS32 is not set
-# CONFIG_CPU_MIPS64 is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_VTAG_ICACHE is not set
 # CONFIG_64BIT_PHYS_ADDR is not set
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
-CONFIG_CPU_HAS_LLDSCD=y
+# CONFIG_CPU_HAS_LLDSCD is not set
 # CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
 #
 # CONFIG_CPU_LITTLE_ENDIAN is not set
-CONFIG_BINFMT_IRIX=y
+# CONFIG_BINFMT_IRIX is not set
 # CONFIG_FORWARD_KEYBOARD is not set
 CONFIG_NET=y
 # CONFIG_PCI_NAMES is not set
@@ -95,11 +109,13 @@
 # CONFIG_HOTPLUG_PCI is not set
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
 CONFIG_KCORE_ELF=y
 # CONFIG_KCORE_AOUT is not set
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PM is not set
 
@@ -130,11 +146,12 @@
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -151,13 +168,14 @@
 #
 # Networking options
 #
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK_DEV=y
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
 CONFIG_IP_PNP=y
 # CONFIG_IP_PNP_DHCP is not set
@@ -165,6 +183,7 @@
 # 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 is not set
@@ -273,8 +292,14 @@
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_NCR53C8XX=y
 # CONFIG_SCSI_SYM53C8XX is not set
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
@@ -330,7 +355,38 @@
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_HP100 is not set
 # CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_TULIP is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_WINBOND_840 is not set
+CONFIG_LAN_SAA9730=y
 # CONFIG_NET_POCKET is not set
 
 #
@@ -338,6 +394,7 @@
 #
 # 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
@@ -384,6 +441,15 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -424,7 +490,7 @@
 #
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
-CONFIG_RTC=y
+# CONFIG_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -437,15 +503,10 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
@@ -454,6 +515,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -462,7 +525,7 @@
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
 # CONFIG_VFAT_FS is not set
-CONFIG_EFS_FS=y
+# CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
@@ -471,6 +534,9 @@
 # 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
@@ -497,12 +563,14 @@
 # CONFIG_CODA_FS is not set
 # CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
+CONFIG_NFS_V3=y
 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
@@ -514,17 +582,35 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
 #
-# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
 CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Sound
 #
 # CONFIG_SOUND is not set
@@ -540,15 +626,6 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
@@ -557,3 +634,9 @@
 # CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig-capcella linux-2.4.20/arch/mips/defconfig-capcella
--- linux-2.4.19/arch/mips/defconfig-capcella	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig-capcella	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,645 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MIPS=y
+CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Machine selection
+#
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_ALGOR_P4032 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+CONFIG_ZAO_CAPCELLA=y
+# CONFIG_HIGHMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_CPU_VR41XX=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_NEW_IRQ=y
+CONFIG_IRQ_CPU=y
+CONFIG_NEW_TIME_C=y
+CONFIG_VR41XX_TIME_C=y
+CONFIG_NONCOHERENT_IO=y
+# CONFIG_ISA is not set
+CONFIG_PCI=y
+CONFIG_NEW_PCI=y
+CONFIG_PCI_AUTO=y
+CONFIG_DUMMY_KEYB=y
+# CONFIG_SCSI is not set
+# CONFIG_MIPS_AU1000 is not set
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_SB1 is not set
+# CONFIG_CPU_ADVANCED is not set
+# CONFIG_CPU_HAS_LLSC is not set
+# CONFIG_CPU_HAS_LLDSCD is not set
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
+
+#
+# General setup
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_NET=y
+# CONFIG_PCI_NAMES is not set
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_TC is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+# CONFIG_HOTPLUG_PCI is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# 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=y
+CONFIG_NETLINK_DEV=y
+# 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 is not set
+CONFIG_IP_PNP_BOOTP=y
+# 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 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+# CONFIG_PHONE_IXJ_PCMCIA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# 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_SUNLANCE is not set
+# CONFIG_HAPPYMEAL 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 is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_TULIP is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+CONFIG_8139TOO=y
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_LAN_SAA9730 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+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 is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE 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_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_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_INDYDOG is not set
+# CONFIG_AMD7XX_TCO 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
+# CONFIG_DRM is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+# 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_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=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
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=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=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Console drivers
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+CONFIG_CROSSCOMPILE=y
+# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_GDB_CONSOLE is not set
+# CONFIG_DEBUG is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig-cobalt linux-2.4.20/arch/mips/defconfig-cobalt
--- linux-2.4.19/arch/mips/defconfig-cobalt	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig-cobalt	2002-10-29 11:18:49.000000000 +0000
@@ -3,6 +3,7 @@
 #
 CONFIG_MIPS=y
 CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
 
 #
 # Code maturity level options
@@ -19,6 +20,7 @@
 #
 # CONFIG_ACER_PICA_61 is not set
 # CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
 # CONFIG_MIPS_PB1500 is not set
 # CONFIG_ALGOR_P4032 is not set
 # CONFIG_BAGET_MIPS is not set
@@ -32,21 +34,28 @@
 # CONFIG_MIPS_ATLAS is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
 # CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
 # CONFIG_DDB5074 is not set
 # CONFIG_DDB5476 is not set
 # CONFIG_DDB5477 is not set
 # CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
 # CONFIG_OLIVETTI_M700 is not set
 # CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
-# CONFIG_SIBYTE_SB1250 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
 # CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_COBALT_LCD=y
+CONFIG_I8259=y
 CONFIG_PCI=y
 CONFIG_NEW_IRQ=y
 CONFIG_NEW_TIME_C=y
@@ -56,25 +65,28 @@
 #
 # CPU selection
 #
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
 # CONFIG_CPU_R5000 is not set
 # CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_R6000 is not set
 CONFIG_CPU_NEVADA=y
+# CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
-# CONFIG_CPU_MIPS32 is not set
-# CONFIG_CPU_MIPS64 is not set
+CONFIG_BOARD_SCACHE=y
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_LLDSCD=y
 # CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
@@ -97,6 +109,8 @@
 # CONFIG_KCORE_AOUT is not set
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PM is not set
 
@@ -131,6 +145,7 @@
 # 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)
@@ -271,6 +286,8 @@
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_PIIX_TUNING is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
@@ -341,13 +358,13 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_TULIP=y
-# CONFIG_TC35815 is not set
 # CONFIG_TULIP_MWI is not set
 # CONFIG_TULIP_MMIO is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -359,11 +376,12 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -375,6 +393,7 @@
 #
 # 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
@@ -421,6 +440,15 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -474,11 +502,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -491,6 +514,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -508,6 +533,9 @@
 # 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
@@ -538,6 +566,7 @@
 # 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=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
@@ -551,7 +580,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -571,10 +599,16 @@
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Sound
 #
 # CONFIG_SOUND is not set
@@ -590,15 +624,6 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
@@ -607,3 +632,9 @@
 # CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig-ddb5476 linux-2.4.20/arch/mips/defconfig-ddb5476
--- linux-2.4.19/arch/mips/defconfig-ddb5476	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig-ddb5476	2002-10-29 11:18:39.000000000 +0000
@@ -3,6 +3,7 @@
 #
 CONFIG_MIPS=y
 CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
 
 #
 # Code maturity level options
@@ -10,39 +11,49 @@
 CONFIG_EXPERIMENTAL=y
 
 #
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
 # Machine selection
 #
 # CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
 # CONFIG_ALGOR_P4032 is not set
 # CONFIG_BAGET_MIPS is not set
 # CONFIG_MIPS_COBALT is not set
 # CONFIG_DECSTATION is not set
-# CONFIG_DDB5074 is not set
 # CONFIG_MIPS_EV64120 is not set
 # CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_MIPS_ITE8172 is not set
 # CONFIG_MIPS_ATLAS is not set
-# CONFIG_MIPS_MALTA is not set
-# CONFIG_NINO is not set
-# CONFIG_SIBYTE_SB1250 is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
 # CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_DDB5074 is not set
 CONFIG_DDB5476=y
 # CONFIG_DDB5477 is not set
 # CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
 # CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
 # CONFIG_SNI_RM200_PCI is not set
-# CONFIG_MIPS_ITE8172 is not set
-# CONFIG_MIPS_IVR is not set
-# CONFIG_MIPS_PB1000 is not set
-# CONFIG_MIPS_PB1500 is not set
 # CONFIG_TOSHIBA_JMR3927 is not set
-# CONFIG_HP_LASERJET is not set
+# CONFIG_ZAO_CAPCELLA is not set
 # CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
 CONFIG_ISA=y
 CONFIG_PCI=y
 CONFIG_PC_KEYB=y
@@ -54,59 +65,57 @@
 CONFIG_PCI_AUTO=y
 CONFIG_NEW_TIME_C=y
 CONFIG_NONCOHERENT_IO=y
-CONFIG_EISA=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
+# CONFIG_MIPS_AU1000 is not set
 
 #
 # CPU selection
 #
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
 # CONFIG_CPU_R5000 is not set
 CONFIG_CPU_R5432=y
-# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
-# CONFIG_CPU_MIPS32 is not set
-# CONFIG_CPU_MIPS64 is not set
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_LLDSCD=y
 # CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
 #
 CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_KCORE_ELF=y
-CONFIG_ELF_KERNEL=y
-# CONFIG_BINFMT_AOUT is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
 CONFIG_NET=y
 # CONFIG_PCI_NAMES is not set
+CONFIG_EISA=y
+# CONFIG_TC is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_PCMCIA is not set
 # CONFIG_HOTPLUG_PCI is not set
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -119,6 +128,12 @@
 # CONFIG_PARPORT 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
@@ -126,11 +141,14 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -175,6 +193,11 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -192,6 +215,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # Telephony Support
 #
 # CONFIG_PHONE is not set
@@ -215,6 +243,7 @@
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -229,6 +258,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -240,12 +270,15 @@
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 # CONFIG_BLK_DEV_IDEDMA_PCI is not set
-# CONFIG_BLK_DEV_ADMA is not set
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 # CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_IDEDMA_ONLYDISK is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+# CONFIG_BLK_DEV_ADMA is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -253,11 +286,14 @@
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_PIIX_TUNING is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
@@ -330,13 +366,13 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_TULIP=y
-# CONFIG_TC35815 is not set
 # CONFIG_TULIP_MWI is not set
 # CONFIG_TULIP_MMIO is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 CONFIG_EEPRO100=y
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -348,11 +384,12 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -364,11 +401,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -414,6 +453,15 @@
 # CONFIG_CD_NO_IDESCSI is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -438,6 +486,7 @@
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
 
 #
 # Joysticks
@@ -457,7 +506,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -472,11 +520,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -489,6 +532,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -502,10 +547,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-# CONFIG_RAMFS 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
@@ -536,6 +584,7 @@
 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_SMB_FS is not set
@@ -549,7 +598,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -560,6 +608,11 @@
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Console drivers
 #
 # CONFIG_VGA_CONSOLE is not set
@@ -573,15 +626,18 @@
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_CLGEN is not set
 # CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
 # CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_MATROX is not set
 # CONFIG_FB_ATY is not set
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
 CONFIG_FB_3DFX=y
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_E1356 is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -603,116 +659,9 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-
-#
-#   SCSI support is needed for USB Storage
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
+# Bluetooth support
 #
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
+# CONFIG_BLUEZ is not set
 
 #
 # Kernel hacking
@@ -723,3 +672,9 @@
 CONFIG_DEBUG=y
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig-ddb5477 linux-2.4.20/arch/mips/defconfig-ddb5477
--- linux-2.4.19/arch/mips/defconfig-ddb5477	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig-ddb5477	2002-10-29 11:18:35.000000000 +0000
@@ -3,6 +3,7 @@
 #
 CONFIG_MIPS=y
 CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
 
 #
 # Code maturity level options
@@ -10,39 +11,50 @@
 CONFIG_EXPERIMENTAL=y
 
 #
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
 # Machine selection
 #
 # CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
 # CONFIG_ALGOR_P4032 is not set
 # CONFIG_BAGET_MIPS is not set
 # CONFIG_MIPS_COBALT is not set
 # CONFIG_DECSTATION is not set
-# CONFIG_DDB5074 is not set
 # CONFIG_MIPS_EV64120 is not set
 # CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_MIPS_ITE8172 is not set
 # CONFIG_MIPS_ATLAS is not set
-# CONFIG_MIPS_MALTA is not set
-# CONFIG_NINO is not set
-# CONFIG_SIBYTE_SB1250 is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
 # CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_DDB5074 is not set
 # CONFIG_DDB5476 is not set
 CONFIG_DDB5477=y
+CONFIG_DDB5477_BUS_FREQUENCY=0
 # CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
 # CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
 # CONFIG_SNI_RM200_PCI is not set
-# CONFIG_MIPS_ITE8172 is not set
-# CONFIG_MIPS_IVR is not set
-# CONFIG_MIPS_PB1000 is not set
-# CONFIG_MIPS_PB1500 is not set
 # CONFIG_TOSHIBA_JMR3927 is not set
-# CONFIG_HP_LASERJET is not set
+# CONFIG_ZAO_CAPCELLA is not set
 # CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
 CONFIG_PCI=y
 CONFIG_NEW_TIME_C=y
 CONFIG_NEW_IRQ=y
@@ -51,54 +63,59 @@
 CONFIG_NONCOHERENT_IO=y
 CONFIG_PCI_AUTO=y
 CONFIG_DUMMY_KEYB=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
+CONFIG_I8259=y
+# CONFIG_MIPS_AU1000 is not set
 
 #
 # CPU selection
 #
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
 # CONFIG_CPU_R5000 is not set
 CONFIG_CPU_R5432=y
-# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
-# CONFIG_CPU_MIPS32 is not set
-# CONFIG_CPU_MIPS64 is not set
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_LLDSCD=y
 # CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
 #
 CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_KCORE_ELF=y
-CONFIG_ELF_KERNEL=y
-# CONFIG_BINFMT_AOUT is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
 CONFIG_NET=y
 # CONFIG_PCI_NAMES is not set
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_TC is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_PCMCIA is not set
 # CONFIG_HOTPLUG_PCI is not set
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -111,6 +128,12 @@
 # CONFIG_PARPORT 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
@@ -118,11 +141,14 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -167,6 +193,11 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -184,6 +215,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # Telephony Support
 #
 # CONFIG_PHONE is not set
@@ -243,18 +279,18 @@
 # CONFIG_HP100 is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
+CONFIG_PCNET32=y
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_TULIP=y
-# CONFIG_TC35815 is not set
 # CONFIG_TULIP_MWI is not set
 # CONFIG_TULIP_MMIO is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -266,11 +302,12 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -282,11 +319,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -327,9 +366,13 @@
 # CONFIG_ISDN is not set
 
 #
-# Old CD-ROM drivers (not SCSI, not IDE)
+# Input core support
 #
-# CONFIG_CD_NO_IDESCSI is not set
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
 
 #
 # Character devices
@@ -371,7 +414,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -386,11 +428,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -403,6 +440,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -416,10 +455,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-# CONFIG_RAMFS 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
@@ -450,6 +492,7 @@
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
@@ -463,7 +506,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -474,9 +516,15 @@
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Sound
 #
 CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
@@ -488,10 +536,10 @@
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
-# CONFIG_SOUND_HAL2 is not set
 CONFIG_SOUND_VRC5477=y
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
@@ -507,116 +555,9 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-
-#
-#   SCSI support is needed for USB Storage
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
+# Bluetooth support
 #
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
+# CONFIG_BLUEZ is not set
 
 #
 # Kernel hacking
@@ -627,3 +568,9 @@
 CONFIG_DEBUG=y
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig-decstation linux-2.4.20/arch/mips/defconfig-decstation
--- linux-2.4.19/arch/mips/defconfig-decstation	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig-decstation	2002-10-29 11:18:48.000000000 +0000
@@ -3,6 +3,7 @@
 #
 CONFIG_MIPS=y
 CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
 
 #
 # Code maturity level options
@@ -21,6 +22,7 @@
 #
 # CONFIG_ACER_PICA_61 is not set
 # CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
 # CONFIG_MIPS_PB1500 is not set
 # CONFIG_ALGOR_P4032 is not set
 # CONFIG_BAGET_MIPS is not set
@@ -34,17 +36,23 @@
 # CONFIG_MIPS_ATLAS is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
 # CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
 # CONFIG_DDB5074 is not set
 # CONFIG_DDB5476 is not set
 # CONFIG_DDB5477 is not set
 # CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
 # CONFIG_OLIVETTI_M700 is not set
 # CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
-# CONFIG_SIBYTE_SB1250 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
 # CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
@@ -56,25 +64,27 @@
 #
 # CPU selection
 #
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
 CONFIG_CPU_R3000=y
 # CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
 # CONFIG_CPU_R5000 is not set
 # CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
-# CONFIG_CPU_MIPS32 is not set
-# CONFIG_CPU_MIPS64 is not set
 # CONFIG_CPU_ADVANCED is not set
 # CONFIG_CPU_HAS_LLSC is not set
 # CONFIG_CPU_HAS_LLDSCD is not set
 CONFIG_CPU_HAS_WB=y
+# CONFIG_CPU_HAS_SYNC is not set
 
 #
 # General setup
@@ -97,6 +107,8 @@
 # CONFIG_KCORE_AOUT is not set
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PM is not set
 
@@ -131,6 +143,7 @@
 # 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)
@@ -209,6 +222,13 @@
 # CONFIG_PHONE_IXJ_PCMCIA is not set
 
 #
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
 # SCSI support
 #
 CONFIG_SCSI=y
@@ -310,6 +330,7 @@
 #
 # 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
@@ -356,6 +377,15 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -409,11 +439,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # DECStation Character devices
 #
 CONFIG_SERIAL=y
@@ -435,6 +460,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -452,6 +479,9 @@
 # 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
@@ -482,6 +512,7 @@
 # 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
@@ -495,7 +526,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -515,10 +545,16 @@
 # CONFIG_SGI_PARTITION is not set
 CONFIG_ULTRIX_PARTITION=y
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Sound
 #
 # CONFIG_SOUND is not set
@@ -534,15 +570,6 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
@@ -551,3 +578,9 @@
 # CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig-eagle linux-2.4.20/arch/mips/defconfig-eagle
--- linux-2.4.19/arch/mips/defconfig-eagle	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig-eagle	2002-10-29 11:18:38.000000000 +0000
@@ -0,0 +1,677 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MIPS=y
+CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Machine selection
+#
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_ALGOR_P4032 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+CONFIG_NEC_EAGLE=y
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_CPU_VR41XX=y
+CONFIG_NEW_IRQ=y
+CONFIG_IRQ_CPU=y
+CONFIG_NEW_TIME_C=y
+CONFIG_VR41XX_TIME_C=y
+CONFIG_NONCOHERENT_IO=y
+# CONFIG_ISA is not set
+CONFIG_PCI=y
+CONFIG_NEW_PCI=y
+CONFIG_PCI_AUTO=y
+CONFIG_DUMMY_KEYB=y
+# CONFIG_SCSI is not set
+# CONFIG_MIPS_AU1000 is not set
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_SB1 is not set
+# CONFIG_CPU_ADVANCED is not set
+# CONFIG_CPU_HAS_LLSC is not set
+# CONFIG_CPU_HAS_LLDSCD is not set
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
+
+#
+# General setup
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_NET=y
+# CONFIG_PCI_NAMES is not set
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_TC is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+# CONFIG_HOTPLUG_PCI is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_PARTITIONS is not set
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+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 is not set
+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 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD 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 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=y
+CONFIG_MTD_PHYSMAP_START=1c000000
+CONFIG_MTD_PHYSMAP_LEN=2000000
+CONFIG_MTD_PHYSMAP_BUSWIDTH=4
+# CONFIG_MTD_PB1000 is not set
+# CONFIG_MTD_PB1500 is not set
+# CONFIG_MTD_PB1100 is not set
+# CONFIG_MTD_CSTM_MIPS_IXX is not set
+# CONFIG_MTD_OCELOT is not set
+# CONFIG_MTD_PCI is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_MS02NV is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# 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
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# 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=y
+CONFIG_NETLINK_DEV=y
+# 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 is not set
+CONFIG_IP_PNP_BOOTP=y
+# 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 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+# CONFIG_PHONE_IXJ_PCMCIA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# 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_SUNLANCE is not set
+# CONFIG_HAPPYMEAL 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 is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=y
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_TULIP is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_LAN_SAA9730 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+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 is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE 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_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_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_INDYDOG is not set
+# CONFIG_AMD7XX_TCO 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
+# CONFIG_DRM is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+# 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_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=y
+CONFIG_JFFS_FS_VERBOSE=0
+# CONFIG_JFFS_PROC_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# 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=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
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=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=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Console drivers
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+CONFIG_CROSSCOMPILE=y
+# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_GDB_CONSOLE is not set
+# CONFIG_DEBUG is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig-ev64120 linux-2.4.20/arch/mips/defconfig-ev64120
--- linux-2.4.19/arch/mips/defconfig-ev64120	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig-ev64120	2002-10-29 11:18:34.000000000 +0000
@@ -3,6 +3,7 @@
 #
 CONFIG_MIPS=y
 CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
 
 #
 # Code maturity level options
@@ -21,6 +22,7 @@
 #
 # CONFIG_ACER_PICA_61 is not set
 # CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
 # CONFIG_MIPS_PB1500 is not set
 # CONFIG_ALGOR_P4032 is not set
 # CONFIG_BAGET_MIPS is not set
@@ -38,17 +40,23 @@
 # CONFIG_MIPS_ATLAS is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
 # CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
 # CONFIG_DDB5074 is not set
 # CONFIG_DDB5476 is not set
 # CONFIG_DDB5477 is not set
 # CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
 # CONFIG_OLIVETTI_M700 is not set
 # CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
-# CONFIG_SIBYTE_SB1250 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
 # CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
@@ -62,26 +70,29 @@
 #
 # CPU selection
 #
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
 CONFIG_CPU_R5000=y
 # CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
-# CONFIG_CPU_MIPS32 is not set
-# CONFIG_CPU_MIPS64 is not set
+CONFIG_BOARD_SCACHE=y
 # CONFIG_64BIT_PHYS_ADDR is not set
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_LLDSCD=y
 # CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
@@ -106,6 +117,8 @@
 # CONFIG_KCORE_AOUT is not set
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PM is not set
 
@@ -140,6 +153,7 @@
 # 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)
@@ -274,11 +288,11 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_TULIP is not set
-# CONFIG_TC35815 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -290,11 +304,12 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -306,6 +321,7 @@
 #
 # 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
@@ -359,6 +375,15 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -412,11 +437,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -429,6 +449,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -446,6 +468,9 @@
 # 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
@@ -476,6 +501,7 @@
 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_SMB_FS is not set
@@ -489,7 +515,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -500,6 +525,11 @@
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Sound
 #
 # CONFIG_SOUND is not set
@@ -515,15 +545,6 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
@@ -532,3 +553,9 @@
 # CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig-ev96100 linux-2.4.20/arch/mips/defconfig-ev96100
--- linux-2.4.19/arch/mips/defconfig-ev96100	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig-ev96100	2002-10-29 11:18:35.000000000 +0000
@@ -3,6 +3,7 @@
 #
 CONFIG_MIPS=y
 CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
 
 #
 # Code maturity level options
@@ -21,6 +22,7 @@
 #
 # CONFIG_ACER_PICA_61 is not set
 # CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
 # CONFIG_MIPS_PB1500 is not set
 # CONFIG_ALGOR_P4032 is not set
 # CONFIG_BAGET_MIPS is not set
@@ -34,17 +36,23 @@
 # CONFIG_MIPS_ATLAS is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
 # CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
 # CONFIG_DDB5074 is not set
 # CONFIG_DDB5476 is not set
 # CONFIG_DDB5477 is not set
 # CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
 # CONFIG_OLIVETTI_M700 is not set
 # CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
-# CONFIG_SIBYTE_SB1250 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
 # CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
@@ -60,27 +68,29 @@
 #
 # CPU selection
 #
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
 # CONFIG_CPU_R5000 is not set
 # CONFIG_CPU_R5432 is not set
-CONFIG_CPU_RM7000=y
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+CONFIG_CPU_RM7000=y
 # CONFIG_CPU_SB1 is not set
-# CONFIG_CPU_MIPS32 is not set
-# CONFIG_CPU_MIPS64 is not set
 CONFIG_CPU_HAS_PREFETCH=y
 # CONFIG_64BIT_PHYS_ADDR is not set
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_LLDSCD=y
 # CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
@@ -105,6 +115,8 @@
 # CONFIG_KCORE_AOUT is not set
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PM is not set
 
@@ -139,6 +151,7 @@
 # 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)
@@ -274,13 +287,13 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_TULIP=y
-# CONFIG_TC35815 is not set
 # CONFIG_TULIP_MWI is not set
 # CONFIG_TULIP_MMIO is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -292,11 +305,12 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -308,6 +322,7 @@
 #
 # 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
@@ -354,6 +369,15 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -407,11 +431,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -424,6 +443,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -441,6 +462,9 @@
 # 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
@@ -471,6 +495,7 @@
 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_SMB_FS is not set
@@ -484,7 +509,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -495,6 +519,11 @@
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Sound
 #
 # CONFIG_SOUND is not set
@@ -510,15 +539,6 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
@@ -527,3 +547,9 @@
 # CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig-ip22 linux-2.4.20/arch/mips/defconfig-ip22
--- linux-2.4.19/arch/mips/defconfig-ip22	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig-ip22	2002-10-29 11:18:51.000000000 +0000
@@ -3,6 +3,7 @@
 #
 CONFIG_MIPS=y
 CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
 
 #
 # Code maturity level options
@@ -21,6 +22,7 @@
 #
 # CONFIG_ACER_PICA_61 is not set
 # CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
 # CONFIG_MIPS_PB1500 is not set
 # CONFIG_ALGOR_P4032 is not set
 # CONFIG_BAGET_MIPS is not set
@@ -34,53 +36,68 @@
 # CONFIG_MIPS_ATLAS is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
 # CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
 # CONFIG_DDB5074 is not set
 # CONFIG_DDB5476 is not set
 # CONFIG_DDB5477 is not set
 # CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
 # CONFIG_OLIVETTI_M700 is not set
 # CONFIG_NINO is not set
 CONFIG_SGI_IP22=y
-# CONFIG_SIBYTE_SB1250 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
 # CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_ARC32=y
+CONFIG_ARC_CONSOLE=y
+CONFIG_ARC_MEMORY=y
 CONFIG_BOARD_SCACHE=y
+CONFIG_BOOT_ELF32=y
+CONFIG_SWAP_IO_SPACE=y
 CONFIG_IRQ_CPU=y
-CONFIG_PC_KEYB=y
-CONFIG_SGI=y
+CONFIG_L1_CACHE_SHIFT=5
+CONFIG_NONCOHERENT_IO=y
 CONFIG_NEW_IRQ=y
 CONFIG_NEW_TIME_C=y
 CONFIG_NONCOHERENT_IO=y
+CONFIG_PC_KEYB=y
+CONFIG_SGI=y
 # CONFIG_MIPS_AU1000 is not set
 
 #
 # CPU selection
 #
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
 CONFIG_CPU_R5000=y
 # CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
-# CONFIG_CPU_MIPS32 is not set
-# CONFIG_CPU_MIPS64 is not set
+CONFIG_BOARD_SCACHE=y
 # CONFIG_64BIT_PHYS_ADDR is not set
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_LLDSCD=y
 # CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
@@ -88,7 +105,8 @@
 # CONFIG_CPU_LITTLE_ENDIAN is not set
 CONFIG_BINFMT_IRIX=y
 CONFIG_FORWARD_KEYBOARD=y
-# CONFIG_ARC_CONSOLE is not set
+CONFIG_ARC_CONSOLE=y
+# CONFIG_IP22_EISA is not set
 CONFIG_NET=y
 # CONFIG_PCI is not set
 # CONFIG_ISA is not set
@@ -106,6 +124,8 @@
 # CONFIG_KCORE_AOUT is not set
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PM is not set
 
@@ -140,6 +160,7 @@
 # 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)
@@ -219,6 +240,13 @@
 # CONFIG_PHONE_IXJ_PCMCIA is not set
 
 #
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
 # SCSI support
 #
 CONFIG_SCSI=y
@@ -321,6 +349,7 @@
 #
 # 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
@@ -367,6 +396,15 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -419,7 +457,6 @@
 # CONFIG_EUROTECH_WDT is not set
 # CONFIG_IB700_WDT is not set
 # CONFIG_WAFER_WDT is not set
-CONFIG_INDYDOG=y
 # CONFIG_I810_TCO is not set
 # CONFIG_MIXCOMWD is not set
 # CONFIG_60XX_WDT is not set
@@ -430,6 +467,7 @@
 # CONFIG_WDTPCI is not set
 # CONFIG_MACHZ_WDT is not set
 CONFIG_INDYDOG=y
+# CONFIG_AMD7XX_TCO is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -444,11 +482,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # SGI Character devices
 #
 CONFIG_SGI_NEWPORT_CONSOLE=y
@@ -468,6 +501,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -485,6 +520,9 @@
 CONFIG_ISO9660_FS=y
 # 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
@@ -515,6 +553,7 @@
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
@@ -528,7 +567,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -548,10 +586,16 @@
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Console drivers
 #
 # CONFIG_VGA_CONSOLE is not set
@@ -586,18 +630,15 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
 # CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig-malta linux-2.4.20/arch/mips/defconfig-malta
--- linux-2.4.19/arch/mips/defconfig-malta	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig-malta	2002-10-29 11:18:35.000000000 +0000
@@ -3,6 +3,7 @@
 #
 CONFIG_MIPS=y
 CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
 
 #
 # Code maturity level options
@@ -19,6 +20,7 @@
 #
 # CONFIG_ACER_PICA_61 is not set
 # CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
 # CONFIG_MIPS_PB1500 is not set
 # CONFIG_ALGOR_P4032 is not set
 # CONFIG_BAGET_MIPS is not set
@@ -32,48 +34,57 @@
 # CONFIG_MIPS_ATLAS is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
 CONFIG_MIPS_MALTA=y
+# CONFIG_MIPS_SEAD is not set
 # CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
 # CONFIG_DDB5074 is not set
 # CONFIG_DDB5476 is not set
 # CONFIG_DDB5477 is not set
 # CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
 # CONFIG_OLIVETTI_M700 is not set
 # CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
-# CONFIG_SIBYTE_SB1250 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
 # CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_I8259=y
-CONFIG_PCI=y
+CONFIG_BOOT_ELF32=y
 CONFIG_HAVE_STD_PC_SERIAL_PORT=y
+CONFIG_I8259=y
+CONFIG_L1_CACHE_SHIFT=5
 CONFIG_NEW_IRQ=y
 CONFIG_NEW_TIME_C=y
 CONFIG_NONCOHERENT_IO=y
 CONFIG_SWAP_IO_SPACE=y
 CONFIG_PC_KEYB=y
+CONFIG_PCI=y
 # CONFIG_MIPS_AU1000 is not set
 
 #
 # CPU selection
 #
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS64 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
 # CONFIG_CPU_R5000 is not set
 # CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
-CONFIG_CPU_MIPS32=y
-# CONFIG_CPU_MIPS64 is not set
 CONFIG_CPU_HAS_PREFETCH=y
 # CONFIG_VTAG_ICACHE is not set
 # CONFIG_64BIT_PHYS_ADDR is not set
@@ -81,6 +92,7 @@
 CONFIG_CPU_HAS_LLSC=y
 # CONFIG_CPU_HAS_LLDSCD is not set
 # CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
@@ -98,11 +110,13 @@
 # CONFIG_HOTPLUG_PCI is not set
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
 CONFIG_KCORE_ELF=y
 # CONFIG_KCORE_AOUT is not set
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PM is not set
 
@@ -138,6 +152,7 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -339,11 +354,11 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_TULIP is not set
-# CONFIG_TC35815 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -355,11 +370,12 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -371,6 +387,7 @@
 #
 # 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
@@ -417,6 +434,15 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -470,11 +496,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -487,6 +508,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -504,6 +527,9 @@
 # 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
@@ -534,6 +560,7 @@
 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_SMB_FS is not set
@@ -547,7 +574,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -558,6 +584,11 @@
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Sound
 #
 # CONFIG_SOUND is not set
@@ -573,15 +604,6 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
@@ -590,3 +612,9 @@
 # CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig-pb1000 linux-2.4.20/arch/mips/defconfig-pb1000
--- linux-2.4.19/arch/mips/defconfig-pb1000	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig-pb1000	2002-10-29 11:18:37.000000000 +0000
@@ -3,6 +3,7 @@
 #
 CONFIG_MIPS=y
 CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
 
 #
 # Code maturity level options
@@ -22,6 +23,7 @@
 # CONFIG_ACER_PICA_61 is not set
 CONFIG_MIPS_PB1000=y
 CONFIG_PCI_AUTO=y
+# CONFIG_MIPS_PB1100 is not set
 # CONFIG_MIPS_PB1500 is not set
 # CONFIG_ALGOR_P4032 is not set
 # CONFIG_BAGET_MIPS is not set
@@ -35,17 +37,23 @@
 # CONFIG_MIPS_ATLAS is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
 # CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
 # CONFIG_DDB5074 is not set
 # CONFIG_DDB5476 is not set
 # CONFIG_DDB5477 is not set
 # CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
 # CONFIG_OLIVETTI_M700 is not set
 # CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
-# CONFIG_SIBYTE_SB1250 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
 # CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
@@ -55,33 +63,36 @@
 CONFIG_NEW_PCI=y
 CONFIG_NONCOHERENT_IO=y
 CONFIG_PC_KEYB=y
-MAX_HWIFS=1
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_AU1000_USB_DEVICE=y
 
 #
 # CPU selection
 #
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS64 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
 # CONFIG_CPU_R5000 is not set
 # CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
-CONFIG_CPU_MIPS32=y
-# CONFIG_CPU_MIPS64 is not set
 CONFIG_CPU_HAS_PREFETCH=y
 # CONFIG_VTAG_ICACHE is not set
-# CONFIG_64BIT_PHYS_ADDR is not set
+CONFIG_64BIT_PHYS_ADDR=y
 CONFIG_CPU_ADVANCED=y
 CONFIG_CPU_HAS_LLSC=y
 # CONFIG_CPU_HAS_LLDSCD is not set
 CONFIG_CPU_HAS_WB=y
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
@@ -105,6 +116,7 @@
 # CONFIG_I82092 is not set
 # CONFIG_I82365 is not set
 CONFIG_PCMCIA_AU1000=m
+CONFIG_PCMCIA_PB1X00=y
 
 #
 # PCI Hotplug Support
@@ -120,6 +132,8 @@
 # CONFIG_KCORE_AOUT is not set
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PM is not set
 
@@ -163,6 +177,7 @@
 # CONFIG_MTD_PHYSMAP is not set
 CONFIG_MTD_PB1000=y
 # CONFIG_MTD_PB1500 is not set
+# CONFIG_MTD_PB1100 is not set
 # CONFIG_MTD_CSTM_MIPS_IXX is not set
 # CONFIG_MTD_OCELOT is not set
 # CONFIG_MTD_PCI is not set
@@ -211,10 +226,11 @@
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
-CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -396,6 +412,7 @@
 #
 # 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
@@ -429,7 +446,18 @@
 #
 # PCMCIA network device support
 #
-# CONFIG_NET_PCMCIA is not set
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+# CONFIG_PCMCIA_PCNET is not set
+# CONFIG_PCMCIA_AXNET is not set
+# CONFIG_PCMCIA_NMCLAN is not set
+# CONFIG_PCMCIA_SMC91C92 is not set
+# CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_ARCNET_COM20020_CS is not set
+# CONFIG_PCMCIA_IBMTR is not set
+# CONFIG_NET_PCMCIA_RADIO is not set
 
 #
 # Amateur Radio support
@@ -439,7 +467,49 @@
 #
 # IrDA (infrared) support
 #
-# CONFIG_IRDA is not set
+CONFIG_IRDA=y
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+# CONFIG_IRNET is not set
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+CONFIG_AU1000_FIR=m
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
 
 #
 # ISDN subsystem
@@ -447,9 +517,19 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
-# CONFIG_VT is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
 # CONFIG_SERIAL is not set
 # CONFIG_SERIAL_EXTENDED is not set
 CONFIG_SERIAL_NONSTANDARD=y
@@ -463,6 +543,7 @@
 # CONFIG_MOXA_SMARTIO is not set
 # CONFIG_ISI is not set
 # CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
 # CONFIG_N_HDLC is not set
 # CONFIG_RISCOM8 is not set
 # CONFIG_SPECIALIX is not set
@@ -473,6 +554,8 @@
 # CONFIG_SERIAL_TX3912_CONSOLE is not set
 CONFIG_AU1000_UART=y
 CONFIG_AU1000_SERIAL_CONSOLE=y
+# CONFIG_AU1000_USB_TTY is not set
+# CONFIG_AU1000_USB_RAW is not set
 # CONFIG_TXX927_SERIAL is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
@@ -523,15 +606,11 @@
 # PCMCIA character devices
 #
 # CONFIG_PCMCIA_SERIAL_CS is not set
+# CONFIG_SYNCLINK_CS is not set
 CONFIG_AU1000_GPIO=y
 # CONFIG_TS_AU1000_ADS7846 is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -544,6 +623,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -562,6 +643,9 @@
 # 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
@@ -592,6 +676,7 @@
 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_SMB_FS is not set
@@ -605,7 +690,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -616,9 +700,67 @@
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Console drivers
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_CLGEN is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+CONFIG_FB_E1356=y
+CONFIG_PB1000_CRT=y
+# CONFIG_PB1000_NTSC is not set
+# CONFIG_PB1000_TFT 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 is not set
+# CONFIG_FBCON_CFB32 is not set
+# 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
+
+#
 # Sound
 #
 CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
@@ -630,6 +772,7 @@
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
@@ -653,15 +796,6 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
@@ -670,3 +804,9 @@
 # CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig-pb1100 linux-2.4.20/arch/mips/defconfig-pb1100
--- linux-2.4.19/arch/mips/defconfig-pb1100	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig-pb1100	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,874 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MIPS=y
+CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Machine selection
+#
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_PB1000 is not set
+CONFIG_MIPS_PB1100=y
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_ALGOR_P4032 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_MIPS_AU1000=y
+CONFIG_NEW_IRQ=y
+CONFIG_PCI=y
+# CONFIG_PCI_AUTO is not set
+CONFIG_NEW_PCI=y
+CONFIG_NONCOHERENT_IO=y
+CONFIG_PC_KEYB=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_AU1000_USB_DEVICE=y
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_VTAG_ICACHE is not set
+CONFIG_64BIT_PHYS_ADDR=y
+CONFIG_CPU_ADVANCED=y
+CONFIG_CPU_HAS_LLSC=y
+# CONFIG_CPU_HAS_LLDSCD is not set
+CONFIG_CPU_HAS_WB=y
+CONFIG_CPU_HAS_SYNC=y
+
+#
+# General setup
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_NET=y
+CONFIG_PCI_NAMES=y
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_TC is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_CARDBUS is not set
+# CONFIG_TCIC is not set
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+CONFIG_PCMCIA_AU1000=m
+CONFIG_PCMCIA_PB1X00=y
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+# CONFIG_HOTPLUG_PCI_ACPI is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
+
+#
+# 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
+
+#
+# User Modules And Translation Layers
+#
+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 is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD 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 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_PB1000 is not set
+# CONFIG_MTD_PB1500 is not set
+# CONFIG_MTD_PB1100 is not set
+# CONFIG_MTD_CSTM_MIPS_IXX is not set
+# CONFIG_MTD_OCELOT is not set
+# CONFIG_MTD_PCI is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_MS02NV is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# 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
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=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=y
+# CONFIG_NETFILTER_DEBUG 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 is not set
+CONFIG_IP_PNP_BOOTP=y
+# 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 is not set
+
+#
+#   IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_CONNTRACK is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+# CONFIG_PHONE_IXJ_PCMCIA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+CONFIG_BLK_DEV_IDECS=m
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# 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_MIPS_AU1000_ENET=y
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL 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 is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+# CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPPOE=m
+# 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
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+# CONFIG_PCMCIA_PCNET is not set
+# CONFIG_PCMCIA_AXNET is not set
+# CONFIG_PCMCIA_NMCLAN is not set
+# CONFIG_PCMCIA_SMC91C92 is not set
+# CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_ARCNET_COM20020_CS is not set
+# CONFIG_PCMCIA_IBMTR is not set
+# CONFIG_NET_PCMCIA_RADIO is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+CONFIG_IRDA=y
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+# CONFIG_IRNET is not set
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+CONFIG_AU1000_FIR=y
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_DIGI is not set
+# CONFIG_ESPSERIAL is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV is not set
+# CONFIG_SERIAL_TX3912 is not set
+# CONFIG_SERIAL_TX3912_CONSOLE is not set
+CONFIG_AU1000_UART=y
+CONFIG_AU1000_SERIAL_CONSOLE=y
+# CONFIG_AU1000_USB_TTY is not set
+# CONFIG_AU1000_USB_RAW is not set
+# CONFIG_TXX927_SERIAL is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_PCMCIA_SERIAL_CS is not set
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_AU1000_GPIO is not set
+# CONFIG_TS_AU1000_ADS7846 is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_REISERFS_FS=m
+# 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_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+# 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=m
+CONFIG_JFFS_FS_VERBOSE=0
+CONFIG_JFFS_PROC_FS=y
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_CRAMFS=m
+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
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=m
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT 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=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Console drivers
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_CLGEN is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_E1356 is not set
+# CONFIG_FB_AU1100 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 is not set
+# CONFIG_FBCON_CFB32 is not set
+# 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
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+CONFIG_SOUND_AU1000=y
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+CONFIG_CROSSCOMPILE=y
+# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_GDB_CONSOLE is not set
+# CONFIG_DEBUG is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig-pb1500 linux-2.4.20/arch/mips/defconfig-pb1500
--- linux-2.4.19/arch/mips/defconfig-pb1500	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig-pb1500	2002-10-29 11:18:37.000000000 +0000
@@ -3,6 +3,7 @@
 #
 CONFIG_MIPS=y
 CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
 
 #
 # Code maturity level options
@@ -21,6 +22,7 @@
 #
 # CONFIG_ACER_PICA_61 is not set
 # CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
 CONFIG_MIPS_PB1500=y
 # CONFIG_ALGOR_P4032 is not set
 # CONFIG_BAGET_MIPS is not set
@@ -34,46 +36,54 @@
 # CONFIG_MIPS_ATLAS is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
 # CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
 # CONFIG_DDB5074 is not set
 # CONFIG_DDB5476 is not set
 # CONFIG_DDB5477 is not set
 # CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
 # CONFIG_OLIVETTI_M700 is not set
 # CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
-# CONFIG_SIBYTE_SB1250 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
 # CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_MIPS_AU1000=y
 CONFIG_NEW_IRQ=y
 CONFIG_PCI=y
-CONFIG_PCI_AUTO=y
 CONFIG_NEW_PCI=y
+CONFIG_PCI_AUTO=y
 CONFIG_NONCOHERENT_IO=y
 CONFIG_PC_KEYB=y
+CONFIG_AU1000_USB_DEVICE=y
 
 #
 # CPU selection
 #
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS64 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
 # CONFIG_CPU_R5000 is not set
 # CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
-CONFIG_CPU_MIPS32=y
-# CONFIG_CPU_MIPS64 is not set
 CONFIG_CPU_HAS_PREFETCH=y
 # CONFIG_VTAG_ICACHE is not set
 # CONFIG_64BIT_PHYS_ADDR is not set
@@ -81,6 +91,7 @@
 CONFIG_CPU_HAS_LLSC=y
 # CONFIG_CPU_HAS_LLDSCD is not set
 CONFIG_CPU_HAS_WB=y
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
@@ -119,6 +130,8 @@
 # CONFIG_KCORE_AOUT is not set
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PM is not set
 
@@ -162,6 +175,7 @@
 # CONFIG_MTD_PHYSMAP is not set
 # CONFIG_MTD_PB1000 is not set
 CONFIG_MTD_PB1500=y
+# CONFIG_MTD_PB1100 is not set
 CONFIG_MTD_PB1500_BOOT=y
 # CONFIG_MTD_PB1500_USER is not set
 # CONFIG_MTD_CSTM_MIPS_IXX is not set
@@ -216,6 +230,7 @@
 # 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)
@@ -371,6 +386,8 @@
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 CONFIG_BLK_DEV_HPT366=y
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_PIIX_TUNING is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
@@ -442,11 +459,11 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_TULIP is not set
-# CONFIG_TC35815 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -458,11 +475,12 @@
 CONFIG_8139TOO_PIO=y
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -474,6 +492,7 @@
 #
 # 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
@@ -543,6 +562,17 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_KEYBDEV=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -560,6 +590,7 @@
 # CONFIG_MOXA_SMARTIO is not set
 # CONFIG_ISI is not set
 # CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
 # CONFIG_N_HDLC is not set
 # CONFIG_RISCOM8 is not set
 # CONFIG_SPECIALIX is not set
@@ -570,6 +601,8 @@
 # CONFIG_SERIAL_TX3912_CONSOLE is not set
 CONFIG_AU1000_UART=y
 CONFIG_AU1000_SERIAL_CONSOLE=y
+# CONFIG_AU1000_USB_TTY is not set
+# CONFIG_AU1000_USB_RAW is not set
 # CONFIG_TXX927_SERIAL is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
@@ -642,15 +675,11 @@
 # PCMCIA character devices
 #
 # CONFIG_PCMCIA_SERIAL_CS is not set
+# CONFIG_SYNCLINK_CS is not set
 # CONFIG_AU1000_GPIO is not set
 # CONFIG_TS_AU1000_ADS7846 is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -663,6 +692,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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=y
 CONFIG_JBD=y
@@ -683,6 +714,9 @@
 # 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
@@ -713,6 +747,7 @@
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=m
 # CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_SMB_FS=m
@@ -727,7 +762,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-CONFIG_ZLIB_FS_INFLATE=m
 
 #
 # Partition Types
@@ -780,6 +814,11 @@
 # CONFIG_NLS_UTF8 is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Console drivers
 #
 # CONFIG_VGA_CONSOLE is not set
@@ -804,6 +843,7 @@
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_E1356 is not set
 # CONFIG_FB_VIRTUAL is not set
 CONFIG_FBCON_ADVANCED=y
 # CONFIG_FBCON_MFB is not set
@@ -831,6 +871,7 @@
 # Sound
 #
 CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
@@ -842,6 +883,7 @@
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
@@ -881,6 +923,7 @@
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_EMI26 is not set
 # CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
 
 #
 #   SCSI support is needed for USB Storage
@@ -893,6 +936,7 @@
 # CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_HP8200e is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
@@ -903,6 +947,7 @@
 CONFIG_USB_HID=y
 # CONFIG_USB_HIDINPUT is not set
 # CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
 
 #
@@ -941,39 +986,15 @@
 # USB Serial Converter support
 #
 # CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
 
 #
 # USB Miscellaneous drivers
 #
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
 # CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
 
 #
 # Bluetooth support
@@ -981,17 +1002,6 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-CONFIG_INPUT=y
-CONFIG_INPUT_KEYBDEV=y
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-CONFIG_INPUT_EVDEV=y
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
@@ -1000,3 +1010,9 @@
 # CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig-sb1250-swarm linux-2.4.20/arch/mips/defconfig-sb1250-swarm
--- linux-2.4.19/arch/mips/defconfig-sb1250-swarm	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig-sb1250-swarm	2002-10-29 11:18:51.000000000 +0000
@@ -3,6 +3,7 @@
 #
 CONFIG_MIPS=y
 CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
 
 #
 # Code maturity level options
@@ -21,6 +22,7 @@
 #
 # CONFIG_ACER_PICA_61 is not set
 # CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
 # CONFIG_MIPS_PB1500 is not set
 # CONFIG_ALGOR_P4032 is not set
 # CONFIG_BAGET_MIPS is not set
@@ -34,26 +36,32 @@
 # CONFIG_MIPS_ATLAS is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
 # CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
 # CONFIG_DDB5074 is not set
 # CONFIG_DDB5476 is not set
 # CONFIG_DDB5477 is not set
 # CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
 # CONFIG_OLIVETTI_M700 is not set
 # CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+CONFIG_SIBYTE_SB1xxx_SOC=y
 CONFIG_SIBYTE_SB1250=y
-# CONFIG_PCI is not set
+# CONFIG_SIMULATION is not set
+CONFIG_SIBYTE_CFE=y
+# CONFIG_SIBYTE_CFE_CONSOLE is not set
 # CONFIG_SIBYTE_SB1250_PROF is not set
 # CONFIG_BCM1250_TBPROF is not set
-# CONFIG_REMOTE_DEBUG is not set
-CONFIG_SIBYTE_SWARM=y
-# CONFIG_SIMULATION is not set
-# CONFIG_L3DEMO is not set
-CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS=16
 CONFIG_SMP=y
+# CONFIG_PCI is not set
+CONFIG_SIBYTE_SWARM=y
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
 # CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
@@ -61,35 +69,43 @@
 CONFIG_NEW_TIME_C=y
 CONFIG_DUMMY_KEYB=y
 CONFIG_SWAP_IO_SPACE=y
+CONFIG_BOOT_ELF32=y
 # CONFIG_MIPS_AU1000 is not set
 
 #
 # CPU selection
 #
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
 # CONFIG_CPU_R5000 is not set
 # CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 CONFIG_CPU_SB1=y
-# CONFIG_CPU_MIPS32 is not set
-# CONFIG_CPU_MIPS64 is not set
+CONFIG_CPU_SB1_PASS_1=y
+# CONFIG_CPU_SB1_PASS_2 is not set
+# CONFIG_CPU_SB1_PASS_2_2 is not set
 CONFIG_SB1_PASS_1_WORKAROUNDS=y
+CONFIG_CPU_HAS_PREFETCH=y
 CONFIG_SB1_CACHE_ERROR=y
+CONFIG_SB1_CERR_IGNORE_RECOVERABLE=y
+# CONFIG_SB1_CERR_SPIN is not set
 CONFIG_VTAG_ICACHE=y
-CONFIG_CPU_HAS_PREFETCH=y
 # CONFIG_64BIT_PHYS_ADDR is not set
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_LLDSCD=y
 # CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
@@ -109,11 +125,13 @@
 # CONFIG_HOTPLUG_PCI is not set
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
 CONFIG_KCORE_ELF=y
 # CONFIG_KCORE_AOUT is not set
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PM is not set
 
@@ -148,6 +166,7 @@
 # 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)
@@ -222,6 +241,13 @@
 # CONFIG_PHONE_IXJ_PCMCIA is not set
 
 #
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
 # SCSI support
 #
 # CONFIG_SCSI is not set
@@ -246,7 +272,6 @@
 #
 CONFIG_NET_ETHERNET=y
 CONFIG_NET_SB1250_MAC=y
-CONFIG_NET_SB1250_MAC=y
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
@@ -264,6 +289,7 @@
 #
 # 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
@@ -310,6 +336,15 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -326,6 +361,7 @@
 # CONFIG_MOXA_SMARTIO is not set
 # CONFIG_ISI is not set
 # CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
 # CONFIG_N_HDLC is not set
 # CONFIG_RISCOM8 is not set
 # CONFIG_SPECIALIX is not set
@@ -334,7 +370,6 @@
 # CONFIG_STALDRV is not set
 # CONFIG_SERIAL_TX3912 is not set
 # CONFIG_SERIAL_TX3912_CONSOLE is not set
-# CONFIG_AU1000_UART is not set
 # CONFIG_TXX927_SERIAL is not set
 CONFIG_SIBYTE_SB1250_DUART=y
 CONFIG_SIBYTE_SB1250_DUART_CONSOLE=y
@@ -387,11 +422,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -404,6 +434,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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=y
 CONFIG_JBD=y
@@ -421,6 +453,9 @@
 # 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
@@ -451,6 +486,7 @@
 # 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=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -465,7 +501,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -476,6 +511,11 @@
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Sound
 #
 # CONFIG_SOUND is not set
@@ -491,17 +531,14 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
 # CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/defconfig-sead linux-2.4.20/arch/mips/defconfig-sead
--- linux-2.4.19/arch/mips/defconfig-sead	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/defconfig-sead	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,363 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MIPS=y
+CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Machine selection
+#
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_ALGOR_P4032 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MIPS_MALTA is not set
+CONFIG_MIPS_SEAD=y
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_L1_CACHE_SHIFT=5
+CONFIG_NEW_IRQ=y
+CONFIG_NEW_TIME_C=y
+CONFIG_NONCOHERENT_IO=y
+# CONFIG_PCI is not set
+# CONFIG_MIPS_AU1000 is not set
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_VTAG_ICACHE is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+# CONFIG_CPU_HAS_LLDSCD is not set
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
+
+#
+# General setup
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_NET is not set
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_TC is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=18432
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_STATS is not set
+
+#
+# MIPS initrd options
+#
+CONFIG_EMBEDDED_RAMDISK=y
+
+#
+# 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
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+# CONFIG_PHONE_IXJ_PCMCIA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG 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
+# CONFIG_DRM is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_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 is not set
+# 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_NCPFS_NLS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Kernel hacking
+#
+CONFIG_CROSSCOMPILE=y
+# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_GDB_CONSOLE is not set
+# CONFIG_DEBUG is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/cntmr.c linux-2.4.20/arch/mips/galileo-boards/ev64120/cntmr.c
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/cntmr.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/cntmr.c	2002-10-29 11:18:48.000000000 +0000
@@ -25,7 +25,7 @@
 * cntTmrStart - Starts a counter/timer with given an initiate value.
 *
 * INPUTS:  unsigned int countNum - Selects one of the 8 counters/timers.
-*          unsigned int countValue - Initial value for count down. 
+*          unsigned int countValue - Initial value for count down.
 *          CNT_TMR_OP_MODES opMode - Set Mode, Counter or Timer.
 *
 * RETURNS: false if one of the parameters is erroneous, true otherwise.
@@ -63,11 +63,11 @@
 }
 
 /********************************************************************
-* cntTmrDisable - Disables the timer/counter operation and return its 
+* cntTmrDisable - Disables the timer/counter operation and return its
 *                 value.
 *
 * INPUTS:  unsigned int countNum - Selects one of the 8 counters/timers.
-* RETURNS: The counter/timer value (unsigned int), if any of the arguments are 
+* RETURNS: The counter/timer value (unsigned int), if any of the arguments are
 *          erroneous return 0.
 *********************************************************************/
 
@@ -166,10 +166,10 @@
 *                 or as a timer. (for more details on the different between
 *                 those two modes is written in the Data Sheet).
 *                 NOTE: This function only set the counter/timer mode and
-*                 don't enable it. 
+*                 don't enable it.
 *                 Be aware: If this function try to load value to an enabled
 *                           counter/timer it terminate with false.
-* 
+*
 * INPUTS:  unsigned int countNum - Selects one of the 8 counters/timers.
 *          CNT_TMR_OP_MODES opMode - TIMER or COUNTER mode.
 * RETURNS: false if one of the parameters is erroneous true otherwise .
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/Makefile linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/Makefile
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/Makefile	2002-10-29 11:18:39.000000000 +0000
@@ -11,13 +11,13 @@
 #
 #   The system comes in three forms:
 #
-#       1. - ramsys - 
+#       1. - ramsys -
 #          to be loaded into ram then run. When run
 #          it decompresses the kernel housed in its internal
 #          data structures and then jumps to the image which
 #          results in a linux kernel boot.
 #
-#       2. - flashsys - 
+#       2. - flashsys -
 #          to be loaded into ram so that it can be
 #          burned into the onboard flash. Then the board jumpers
 #          can be switched so that the next power cycle caused
@@ -26,10 +26,10 @@
 #          Note: burner.srec is the utility that will allow
 #          the user to get this image into flash.
 #
-#       3. - flashsys2 - 
+#       3. - flashsys2 -
 #          to be loaded into ram so that it can be
 #          burned into the onboard flash. Then on each power
-#          cycle when the standard PMON prompt is presented 
+#          cycle when the standard PMON prompt is presented
 #          the user can type `call 0xbf000000` to invoke
 #          the system in flash which then proceeds as
 #          described by #1 above.
@@ -75,7 +75,7 @@
 	gcc -o doit doit.c
 
 piggy.gz: $(SYSTEM)
-	rm -f piggy piggy.gz 
+	rm -f piggy piggy.gz
 	$(OBJCOPY) -S -O binary $(SYSTEM) piggy
 	gzip -f -9 < piggy > piggy.gz
 
@@ -89,7 +89,7 @@
 
 ramsys.srec : $(OBJECTS_ramsys) ld.script.gal
 	@# Note: this image is intended to run out of ram. No flash involved.
-	$(LD) -T ld.script.gal -o ramsys $(OBJECTS_ramsys) 
+	$(LD) -T ld.script.gal -o ramsys $(OBJECTS_ramsys)
 	$(NM) ramsys | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System_ramsys.map
 	$(OBJCOPY) -O srec ramsys ramsys.srec
 	cp ramsys.srec $(TOPDIR)/.
@@ -97,7 +97,7 @@
 flashsys.srec : $(OBJECTS_flashsys) ld.sys.big.Flash
 	@# Note1: Use the burn utility to get this image into flash.
 	@# Note2: This image is intended to run out of flash as invoked
-	@# directly at powerup when EVB64120A jumpers are configured to 
+	@# directly at powerup when EVB64120A jumpers are configured to
 	@# bypass the onboard eprom.
 	@# Assumes that 0xBFC00000 is the bootup run address (normal MIPS).
 	@# And assumes that EVB64120A jumber J11 is added to the board and jumber
@@ -105,8 +105,8 @@
 	@# the jumper settings the system will execute at address 0xBFC00000,
 	@# as normal, yet that address will map to the onboard eeprom instead
 	@# of the onboard flash.
-	@# 
-	$(LD) -T ld.sys.big.Flash -o flashsys $(OBJECTS_flashsys) 
+	@#
+	$(LD) -T ld.sys.big.Flash -o flashsys $(OBJECTS_flashsys)
 	$(NM) flashsys | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | sort > System_flashsys.map
 	@#
 	@# Next, Create the image that we want to place in the flash part.
@@ -125,7 +125,7 @@
 	@# to the board's ram it will land starting at address 0xA0300000
 	@# because this is where we have choosen to have the image temporarily sit
 	@# while we subsequently burn it (using some method not revealed here) into
-	@# the board's flash. After the burn the system can be setup (via jumpers) 
+	@# the board's flash. After the burn the system can be setup (via jumpers)
 	@# to boot this image directory from the flash part.
 	$(OBJCOPY) -O srec --adjust-vma=0xe0700000 flashsys.temp flashsys.srec
 	cp flashsys.srec $(TOPDIR)/.
@@ -139,8 +139,8 @@
 	@# the standard location such that the board boots out of onboard
 	@# eprom. From the PMON prompt the user can type `call 0xbf000000`
 	@# to transfer control to the image we are constructing here.
-	@# 
-	$(LD) -T ld.sys.big.Flash2 -o flashsys2 $(OBJECTS_flashsys2) 
+	@#
+	$(LD) -T ld.sys.big.Flash2 -o flashsys2 $(OBJECTS_flashsys2)
 	$(NM) flashsys2 | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | sort > System_flashsys2.map
 	@#
 	@# Next, Create the image that we want to place in the flash part.
@@ -168,7 +168,7 @@
 burner.srec : $(OBJECTS_burner) ld.sys.big.burner
 	@# This utility can be used to burn the flashsys.srec or flashsys2.srec
 	@# into the EVB64120A's on board flash part (1Meg minimum).
-	$(LD) -T ld.sys.big.burner -o burner $(OBJECTS_burner) 
+	$(LD) -T ld.sys.big.burner -o burner $(OBJECTS_burner)
 	$(NM) burner | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System_burner.map
 	$(OBJCOPY) -O srec burner burner.srec
 	cp burner.srec $(TOPDIR)/.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/README linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/README
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/README	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/README	2002-10-29 11:18:31.000000000 +0000
@@ -21,13 +21,13 @@
   Four systems are availalbe for download to the EVB64120A
   board.
 
-   1. - ramsys - 
+   1. - ramsys -
       To be loaded into ram then run. When run
       it decompresses the "vmlinux" kernel housed in its internal
       data structures and then jumps to the image which
       results in a linux kernel boot.
 
-   2. - flashsys - 
+   2. - flashsys -
       To be loaded into ram so that it can be
       burned into the onboard flash. Then the board jumpers
       can be switched so that the next power cycle caused
@@ -36,10 +36,10 @@
       Note: burner.srec is the utility that will allow
       the user to get this image into flash.
 
-   3. - flashsys2 - 
+   3. - flashsys2 -
       To be loaded into ram so that it can be
       burned into the onboard flash. Then on each power
-      cycle when the standard PMON prompt is presented 
+      cycle when the standard PMON prompt is presented
       the user can type `call 0xbf000000` to invoke
       the system in flash which then proceeds as
       described by #1 above.
@@ -53,8 +53,8 @@
 ==========================
 
   In this scenario the compressed system is downloaded
-  into ram and run directly from there. No flash is involved 
-  in this scenario. Naturally, the download must be repeated 
+  into ram and run directly from there. No flash is involved
+  in this scenario. Naturally, the download must be repeated
   on every power cycle.
 
   1. At the PMON prompt type `load`
@@ -69,7 +69,7 @@
 ========================================
 
   In this scenario vmlinux runs out of flash code
-  automatically on every power up. This means that 
+  automatically on every power up. This means that
   standard PMON code (of eprom) never runs.
 
   1. Place the boot jumpers in the Boot-from-eprom
@@ -77,7 +77,7 @@
      are found when booting PMON.
 
      Jumper settings. J11 - Removed
-                      J20 - Moved from the 1&2 position to 
+                      J20 - Moved from the 1&2 position to
                             the 2&3 position instead
 
   2. Use PMON to "load" the burner.srec image and then
@@ -89,12 +89,12 @@
      utility. The utililty will indicate when the burn
      process has completed.
 
-  4. Now switch off power and change the jumpers to 
+  4. Now switch off power and change the jumpers to
      the boot-from-flash position. The next power cycle
      will run the flash based system automatically.
 
      Jumper settings. J11 - Added.
-                      J20 - Moved from the 2&3 position to 
+                      J20 - Moved from the 2&3 position to
                             the 1&2 position instead
 
 Example: Running from flash: Scenario #2
@@ -111,7 +111,7 @@
      are found when booting PMON.
 
      Jumper settings. J11 - Removed
-                      J20 - Moved from the 1&2 position to 
+                      J20 - Moved from the 1&2 position to
                             the 2&3 position instead
 
   2. Use PMON to "load" the burner.srec image and then
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/burner.c linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/burner.c
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/burner.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/burner.c	2002-10-29 11:18:33.000000000 +0000
@@ -3,7 +3,7 @@
  *
  *  By RidgeRun Inc (Leveraged from Galileo's main.c, misc.c, etc).
  *
- *  Burn image from ram to flash 
+ *  Burn image from ram to flash
  *  For use with Galileo EVB64120A MIPS eval board.
  */
 #include <asm/types.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/doit.c linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/doit.c
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/doit.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/doit.c	2002-10-29 11:18:48.000000000 +0000
@@ -12,7 +12,7 @@
  *
  *    Example Usage:
  *       ./doit < piggy.gz > piggy.S
- *       
+ *
  */
 
 #include <stdio.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/flashdrv.c linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/flashdrv.c
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/flashdrv.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/flashdrv.c	2002-10-29 11:18:40.000000000 +0000
@@ -29,14 +29,14 @@
 
 /******************************************************************************
 * Those two tables contain the supported flash devices information needed by
-* the driver: 
-* The first table "flashParametrs" starts with 10 shared fields 
+* the driver:
+* The first table "flashParametrs" starts with 10 shared fields
 *  (currently 6 are reserved):
 *   index 0 => Pointer to an entry in the second table list
 *   index 1 => baseAddress - Flash memory device base address.
-*   index 2 => width - 1, 2, 4 or 8 Bytes. 
+*   index 2 => width - 1, 2, 4 or 8 Bytes.
 *   index 3 => mode - PURE8, X8 or X16 flash configuration (for X16 devices only)
-* The second table (flashTypes) contains: 
+* The second table (flashTypes) contains:
 * Entry`s structure:
 *   Manufacture ID,Device ID,number of sectors,list of sector`s sizes
 *   (in Kbytes starting with sector number 0).
@@ -120,14 +120,14 @@
 };
 
 /********************************************************************
-* flashInit - Initializes the FLASH memory driver`s parameters, this function 
+* flashInit - Initializes the FLASH memory driver`s parameters, this function
 *             must be called at least once before using the FLASH memory.
 *             If you are changing the FLASH base address call this function
 *             again.
 *
 * INPUTS:     unsigned int flashBaseAddress - The flash base Address.
 *             unsigned int flashWidth - Flash bus width in Bytes: 1,2,4 or 8.
-*             flashMode - PURE8, X8 or X16. 
+*             flashMode - PURE8, X8 or X16.
 * RETURNS:    Flash Size, zero when operation (flashInit) failed.
 *********************************************************************/
 unsigned int flashInit(unsigned int flashBaseAddress,
@@ -229,10 +229,10 @@
 		break;
 
 	}
-	/* Try to locate the device in the supported flashes list (FLASH_TYPE). 
-	   according to the keys: 
+	/* Try to locate the device in the supported flashes list (FLASH_TYPE).
+	   according to the keys:
 	   1) mfrId - manufactor ID.
-	   2) devId - device ID.  
+	   2) devId - device ID.
 	 */
 
 	while (true) {
@@ -266,9 +266,9 @@
 
 /********************************************************************
 * flashReset - Resets the Flash memory (FLASH`s internal protocol reset).
-*                
-* INTPUTS:  N/A    
-* OUTPUT:   N/A  
+*
+* INTPUTS:  N/A
+* OUTPUT:   N/A
 *********************************************************************/
 void flashReset()
 {
@@ -771,7 +771,7 @@
 * flashWriteWord - Write 32Bit to the FLASH memory at the given offset from the
 *                  FLASH base address.
 *   			   address 0 = 0x00000000 !!
-*				   Attention!!! data "0" cannot be programed back to 
+*				   Attention!!! data "0" cannot be programed back to
 *                  "1" (only by first performing an earase operation).
 *                  The function takes care of Big/Little endian conversion
 *
@@ -899,7 +899,7 @@
 				}
 			}
 			break;
-		case 2:	/* Split the 32 bit write into two 8/16 bit Writings 
+		case 2:	/* Split the 32 bit write into two 8/16 bit Writings
 				   (16bit width). */
 			if (FLASH_MODE == X16) {
 				FirstData = 0xaa;	/* Data for the First  Cycle    */
@@ -1269,7 +1269,7 @@
 }
 
 /********************************************************************
-* flashReadWord - Read 32Bit from the FLASH memory at a given offset 
+* flashReadWord - Read 32Bit from the FLASH memory at a given offset
 *                 from the FLASH base address.
 * 				  address 0 = 0x00000000 !!
 *                 The function takes care of Big/Little endian conversion
@@ -1288,7 +1288,7 @@
 * flashInWhichSector - Returns the sector`s number at which offset is at.
 *
 * INPUTS:  Offset
-* RETURNS: Sector number,or 0xffffffff in case the address is out of range or 
+* RETURNS: Sector number,or 0xffffffff in case the address is out of range or
 *          flash wasn't initialize.
 *********************************************************************/
 unsigned int flashInWhichSector(unsigned int offset)
@@ -1317,7 +1317,7 @@
 * flashGetSectorSize - When given a Valid sector Number returns its Size.
 *
 * INPUTS:  unsigned int sectorNumber.
-* RETURNS: Sector size. (if Sector number isn't valid or flash wasn't 
+* RETURNS: Sector size. (if Sector number isn't valid or flash wasn't
 *          initialize return 0.)
 *********************************************************************/
 unsigned int flashGetSectorSize(unsigned int sectorNumber)
@@ -1484,7 +1484,7 @@
 
 /********************************************************************
 * flashWriteShort - write 16bit data to a given flash offset.
-*                  It reads the whole word 32bit wide, modify the  short 
+*                  It reads the whole word 32bit wide, modify the  short
 *                  and write back the word.
 *
 * INPUTS:  unsigned int offset - required offset to be write to.
@@ -1520,7 +1520,7 @@
 
 /********************************************************************
 * flashWriteChar - write one charecter (8 bit) to a given flash offset.
-*                  It reads the whole word 32bit wide, modify the charecter 
+*                  It reads the whole word 32bit wide, modify the charecter
 *                  and write back the word.
 *
 * INPUTS:  unsigned int offset - required offset to be write to.
@@ -1548,7 +1548,7 @@
 
 /********************************************************************
 * flashGetNumOfSectors - write one charecter (8 bit) to a given flash offset.
-*                        It reads the whole word 32bit wide, modify the  
+*                        It reads the whole word 32bit wide, modify the
 *                        charecter and write back the word.
 *
 * INPUTS:  N/A.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/head.S linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/head.S
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/head.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/head.S	2002-10-29 11:18:31.000000000 +0000
@@ -9,11 +9,11 @@
 	.text
 NESTED(startup, 16, sp)
 	.set	noreorder
-        
+
 	jal decompress_kernel
 	nop
-        
+
         jal kernel_location_start+0x584
         nop
-        
+
 	END(startup)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/ld.script.gal linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/ld.script.gal
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/ld.script.gal	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/ld.script.gal	2002-10-29 11:18:31.000000000 +0000
@@ -1,8 +1,8 @@
 OUTPUT_FORMAT("elf32-bigmips")
 OUTPUT_ARCH(mips)
 ENTRY(startup)
-SECTIONS 
-{ 
+SECTIONS
+{
   kernel_location_start = 0x80100000;
   . = 0x80400000;
   .text : {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.Flash linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.Flash
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.Flash	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.Flash	2002-10-29 11:18:49.000000000 +0000
@@ -6,7 +6,7 @@
 {
   . = 0xBFC00000;
   .got : {*(.got)}
-  .reset : { 
+  .reset : {
     sbdreset = ABSOLUTE(.);
     sbdreset_evb64120A.o
     evb64120A_Setup.o /* <-- Note: contains xfer.c contents as well.. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.Flash2 linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.Flash2
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.Flash2	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.Flash2	2002-10-29 11:18:34.000000000 +0000
@@ -6,7 +6,7 @@
 {
   . = 0xBF000000;
   .got : {*(.got)}
-  .reset : { 
+  .reset : {
     xfer.o
   }
   kernel_location_start = 0x80100000;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/meminit.S linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/meminit.S
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/meminit.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/meminit.S	2002-10-29 11:18:39.000000000 +0000
@@ -1,8 +1,8 @@
-/* 
- * Define BUSWIDTH to usually be real buswidth X 2 (i.e assuming 
+/*
+ * Define BUSWIDTH to usually be real buswidth X 2 (i.e assuming
  * 2-way interleaving).  This is so that the test pattern and
  * inverted pattern are written to the same bank of memory, which
- * prevents us reading back data sitting in the dram buffers and 
+ * prevents us reading back data sitting in the dram buffers and
  * getting a false match.
  */
 
@@ -17,11 +17,11 @@
 #ifndef RAM_BASE
 #define RAM_BASE	KSEG1_BASE
 #endif
-			
+
 #ifndef MEMSTART
 #define MEMSTART	0x0		/* start of physical memory */
 #endif
-		
+
 #ifndef MEMINCR
 # define MEMINCR	0x10000		/* work up in 64Kb increments */
 #endif
@@ -36,13 +36,13 @@
 
 	li	t0,RAM_BASE+MEMSTART	# start at bottom of phys mem
 	move	t1,t0			# remember start address
-	li	t2,0xaa55aa55		# pattern 
+	li	t2,0xaa55aa55		# pattern
 	not	t3,t2			# ~pattern
 
 	move	t7,k0
 	la	t4,.fail		# bus error exception catcher
-	addu	k0,t4,s8		# RELOC 
-	
+	addu	k0,t4,s8		# RELOC
+
 	/* fill first 64Kb with zero (for cache init) */
 	move	t4,t0
 	li	t5,0x10000
@@ -55,7 +55,7 @@
 	bnez	t5,1b
 
 .loop:
-        addu    t0,MEMINCR		
+        addu    t0,MEMINCR
 	move	t4,t0
 
 	/* store pattern in bank 0, line 0 */
@@ -109,25 +109,25 @@
 
 
 /*
- * We must often initialise memory so that it has good parity/ecc, 
+ * We must often initialise memory so that it has good parity/ecc,
  * and this must be done before the caches are used.
  */
 
 /*
 	clear_mem (size)
 	  - clear memory from RAM_BASE+MEMSTART to RAM_BASE+MEMSTART+size
-	clear_mem_range (size, start)  
+	clear_mem_range (size, start)
 	  - clear memory from start to start+size
 */
 
 SLEAF(clear_mem)
 	li	a1,RAM_BASE+MEMSTART	# start at bottom of phys mem
-clear_mem_range:	
+clear_mem_range:
 	beqz	a0,9f
-	addu	a0,a1			# end of memory 
-	
+	addu	a0,a1			# end of memory
+
 	/* XXX should run cached, but caches may not be initialised yet */
-	.set noreorder	
+	.set noreorder
 #if __mips >= 3
 1:	sd	zero,0(a1)
 	sd	zero,8(a1)
@@ -139,7 +139,7 @@
 	addu	a1,64
 	bne	a1,a0,1b
 	sd	zero,-8(a1)		# BDSLOT
-#else	
+#else
 1:	sw	zero,0(a1)
 	sw	zero,4(a1)
 	sw	zero,8(a1)
@@ -158,7 +158,7 @@
 	addu	a1,64
 	bne	a1,a0,1b
 	sw	zero,-4(a1)		# BDSLOT
-#endif	
+#endif
 	.set	reorder
 
 9:	j	ra
@@ -172,7 +172,7 @@
         mtc0	zero,C0_PGMASK
 	li	t8,K1BASE		/* tlbhi  = impossible vpn */
 	li	t9,(NTLBENTRIES-1)	/* index */
-	
+
 	.set noreorder
 	nop
 1:	mtc0	t8,C0_TLBHI
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/memory.c linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/memory.c
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/memory.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/memory.c	2002-10-29 11:18:48.000000000 +0000
@@ -8,7 +8,7 @@
 SDRAM memory and devices windows, please pay attention to overlapping windows
 since the function do not take care of that for you.
 When remapping the SDRAM or devices memory space pay attention to the PCI
-mappings and make sure to coordinate between the two interfaces!!!           
+mappings and make sure to coordinate between the two interfaces!!!
 */
 
 /* includes */
@@ -26,7 +26,7 @@
 *      - If the memory bank size is 0 then this base address has no meaning !!!
 *
 * INPUTS:  MEMORY_BANK bank - SDRAM Bank number.
-* OUTPUT:  N/A  
+* OUTPUT:  N/A
 * RETURNS: Memory bank base address.
 *********************************************************************/
 unsigned int getMemoryBankBaseAddress(MEMORY_BANK bank)
@@ -45,7 +45,7 @@
 *           - If the device size is 0 then this base address has no meaning!!!
 *
 * INPUT:   DEVICE device - Bank number.
-* OUTPUT:  N/A  
+* OUTPUT:  N/A
 * RETURNS: Device base address.
 *********************************************************************/
 unsigned int getDeviceBaseAddress(DEVICE device)
@@ -83,7 +83,7 @@
 * getDeviceSize - Extract the size of a device memory space
 *
 * INPUT:    DEVICE device - Device number
-* OUTPUT:   N/A  
+* OUTPUT:   N/A
 * RETURNS:  Size of a device memory space.
 *********************************************************************/
 unsigned int getDeviceSize(DEVICE device)
@@ -103,10 +103,10 @@
 * getDeviceWidth - A device can be with: 1,2,4 or 8 Bytes data width.
 *                  The width is determine in registers: 'Device Parameters'
 *                  registers (0x45c, 0x460, 0x464, 0x468, 0x46c - for each device.
-*                  at bits: [21:20].                  
+*                  at bits: [21:20].
 *
 * INPUT:    DEVICE device - Device number
-* OUTPUT:   N/A  
+* OUTPUT:   N/A
 * RETURNS:  Device width in Bytes (1,2,4, or 8), 0 if error had occurred.
 *********************************************************************/
 unsigned int getDeviceWidth(DEVICE device)
@@ -132,9 +132,9 @@
 
 /********************************************************************
 * mapMemoryBanks0and1 - Sets new bases and boundaries for memory banks 0 and 1
-*                     - Pay attention to the PCI mappings and make sure to 
+*                     - Pay attention to the PCI mappings and make sure to
 *                       coordinate between the two interfaces!!!
-*                     - It is the programmer`s responsibility to make sure 
+*                     - It is the programmer`s responsibility to make sure
 *                       there are no conflicts with other memory spaces!!!
 *                     - If a bank needs to be closed , give it a 0 length
 *
@@ -143,7 +143,7 @@
 *         unsigned int bank0Length - required bank 0 size.
 *         unsigned int bank1Base - required bank 1 base address.
 *         unsigned int bank1Length - required bank 1 size.
-* RETURNS: true on success, false on failure or if one of the parameters is 
+* RETURNS: true on success, false on failure or if one of the parameters is
 *          erroneous.
 *********************************************************************/
 bool mapMemoryBanks0and1(unsigned int bank0Base, unsigned int bank0Length,
@@ -205,7 +205,7 @@
 
 /********************************************************************
 * mapMemoryBanks2and3 - Sets new bases and boundaries for memory banks 2 and 3
-*                     - Pay attention to the PCI mappings and make sure to  
+*                     - Pay attention to the PCI mappings and make sure to
 *                       coordinate between the two interfaces!!!
 *                     - It`s the programmer`s responsibility to make sure there
 *                       are no conflicts with other memory spaces!!!
@@ -216,7 +216,7 @@
 *         unsigned int bank2Length - required bank 2 size.
 *         unsigned int bank3Base - required bank 3 base address.
 *         unsigned int bank3Length - required bank 3 size.
-* RETURNS: true on success, false on failure or if one of the parameters is 
+* RETURNS: true on success, false on failure or if one of the parameters is
 *          erroneous.
 *********************************************************************/
 bool mapMemoryBanks2and3(unsigned int bank2Base, unsigned int bank2Length,
@@ -278,9 +278,9 @@
 }
 
 /********************************************************************
-* mapDevices0_1and2MemorySpace - Sets new bases and boundaries for devices 0,1 
+* mapDevices0_1and2MemorySpace - Sets new bases and boundaries for devices 0,1
 *                                and 2
-*                     - Pay attention to the PCI mappings and make sure to 
+*                     - Pay attention to the PCI mappings and make sure to
 *                        coordinate between the two interfaces!!!
 *                     - It`s the programmer`s responsibility to make sure there
 *                       are no conflicts with other memory spaces!!!
@@ -289,11 +289,11 @@
 *
 * INPUTS: unsigned int device0Base - required cs_0 base address.
 *         unsigned int device0Length - required cs_0 size.
-*         unsigned int device1Base - required cs_1 base address. 
-*         unsigned int device1Length - required cs_0 size.       
-*         unsigned int device2Base - required cs_2 base address. 
-*         unsigned int device2Length - required cs_2 size.       
-* RETURNS: true on success, false on failure or if one of the parameters is 
+*         unsigned int device1Base - required cs_1 base address.
+*         unsigned int device1Length - required cs_0 size.
+*         unsigned int device2Base - required cs_2 base address.
+*         unsigned int device2Length - required cs_2 size.
+* RETURNS: true on success, false on failure or if one of the parameters is
 *          erroneous.
 *********************************************************************/
 bool mapDevices0_1and2MemorySpace(unsigned int device0Base,
@@ -431,11 +431,11 @@
 }
 
 /********************************************************************
-* mapDevices3andBootMemorySpace - Sets new bases and boundaries for devices: 
+* mapDevices3andBootMemorySpace - Sets new bases and boundaries for devices:
 *                                 3 and boot
-*                     - Pay attention to the PCI mappings and make sure to 
+*                     - Pay attention to the PCI mappings and make sure to
 *                       coordinate between the two interfaces!!!
-*                     - It is the programmer`s responsibility to make sure 
+*                     - It is the programmer`s responsibility to make sure
 *                       there are no conflicts with other memory spaces!!!
 *                     - If a device needs to be closed , give it a 0 length.
 *
@@ -501,7 +501,7 @@
 }
 
 /********************************************************************
-* modifyDeviceParameters - This function can be used to modify a device`s 
+* modifyDeviceParameters - This function can be used to modify a device`s
 *                          parameters.
 *                        - Be advised to check the spec before modifying them.
 * Inputs:
@@ -579,8 +579,8 @@
 }
 
 /********************************************************************
-* remapAddress - This fubction used for address remapping 
-* Inputs:      - regOffset: remap register 
+* remapAddress - This fubction used for address remapping
+* Inputs:      - regOffset: remap register
 *                remapHeader : remapped address
 * Returns: false if one of the parameters is erroneous,true otherwise.
 *********************************************************************/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/misc.c linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/misc.c
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/misc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/misc.c	2002-10-29 11:18:37.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * arch/mips/galileo/misc.c
- * 
- * This is a collection of several routines from gzip-1.0.3 
+ *
+ * This is a collection of several routines from gzip-1.0.3
  * adapted for Linux.
  *
  * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/pci.c linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/pci.c
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/pci.c	2002-10-29 11:18:33.000000000 +0000
@@ -25,12 +25,12 @@
 
 /********************************************************************
 * pci0ScanDevices   - This function scan PCI0 bus, if found any device on
-*                     this bus it interrogate the Device for the information 
+*                     this bus it interrogate the Device for the information
 *                     it can discover.
-*                     The fields with all information are the following: 
+*                     The fields with all information are the following:
 *    char            type[20];
 *    unsigned int    deviceNum;
-*    unsigned int    venID;                                            
+*    unsigned int    venID;
 *    unsigned int    deviceID;
 *    unsigned int    bar0Base;
 *    unsigned int    bar0Size;
@@ -44,7 +44,7 @@
 *    unsigned int    bar4Size;
 *    unsigned int    bar5Base;
 *    unsigned int    bar5Size;
-* 
+*
 * Inputs:   PCI0_DEVICE* pci0Detect - Pointer to an array of STRUCT PCI0_DEVICE.
 *           unsigned int numberOfElment - The PCI0_DEVICE Array length.
 * Output:   None.
@@ -307,12 +307,12 @@
 
 /********************************************************************
 * pci1ScanDevices   - This function scan PCI1 bus, if found any device on
-*                     this bus it interrogate the Device for the information 
+*                     this bus it interrogate the Device for the information
 *                     it can discover.
-*                     The fields with all information are the following: 
+*                     The fields with all information are the following:
 *    char            type[20];
 *    unsigned int    deviceNum;
-*    unsigned int    venID;                                            
+*    unsigned int    venID;
 *    unsigned int    deviceID;
 *    unsigned int    bar0Base;
 *    unsigned int    bar0Size;
@@ -326,8 +326,8 @@
 *    unsigned int    bar4Size;
 *    unsigned int    bar5Base;
 *    unsigned int    bar5Size;
-* 
-* Inputs:   Pointer to an array of STRUCT PCI1_DEVICE. 
+*
+* Inputs:   Pointer to an array of STRUCT PCI1_DEVICE.
 * Output:   None.
 *********************************************************************/
 
@@ -562,12 +562,12 @@
 
 /********************************************************************
 * pci0WriteConfigReg - Write to a PCI configuration register
-*                    - Make sure the GT is configured as a master before 
+*                    - Make sure the GT is configured as a master before
 *                      writingto another device on the PCI.
 *                    - The function takes care of Big/Little endian conversion.
-* Inputs:   unsigned int regOffset: The register offset as it apears in the GT spec 
+* Inputs:   unsigned int regOffset: The register offset as it apears in the GT spec
 *                   (or any other PCI device spec)
-*           pciDevNum: The device number needs to be addressed.                
+*           pciDevNum: The device number needs to be addressed.
 *
 *  Configuration Address 0xCF8:
 *
@@ -604,9 +604,9 @@
 *                   - Make sure the GT is configured as a master before writing
 *                     to another device on the PCI.
 *                   - The function takes care of Big/Little endian conversion.
-* Inputs:   unsigned int regOffset: The register offset as it apears in the  
+* Inputs:   unsigned int regOffset: The register offset as it apears in the
 *           GT spec (or any other PCI device spec)
-*           pciDevNum: The device number needs to be addressed.                
+*           pciDevNum: The device number needs to be addressed.
 *
 *  Configuration Address 0xCF8:
 *
@@ -626,7 +626,7 @@
 	pciDevNum = pciDevNum << 11;
 	regOffset = regOffset & 0x0fffffff;
 	if (pciDevNum == SELF) {	/* This board */
-		/* when configurating our own PCI 1 L-unit the access is through  
+		/* when configurating our own PCI 1 L-unit the access is through
 		   the PCI 0 interface with reg number = reg number + 0x80 */
 		DataForRegCf8 =
 		    (regOffset | pciDevNum | functionNum | 0x80) | BIT31;
@@ -647,13 +647,13 @@
 
 /********************************************************************
 * pci0ReadConfigReg  - Read from a PCI0 configuration register
-*                    - Make sure the GT is configured as a master before 
+*                    - Make sure the GT is configured as a master before
 *                      reading from another device on the PCI.
 *                   - The function takes care of Big/Little endian conversion.
 * INPUTS:   regOffset: The register offset as it apears in the GT spec (or PCI
 *                        spec)
-*           pciDevNum: The device number needs to be addressed.                
-* RETURNS: data , if the data == 0xffffffff check the master abort bit in the 
+*           pciDevNum: The device number needs to be addressed.
+* RETURNS: data , if the data == 0xffffffff check the master abort bit in the
 *                 cause register to make sure the data is valid
 *
 *  Configuration Address 0xCF8:
@@ -690,13 +690,13 @@
 
 /********************************************************************
 * pci1ReadConfigReg  - Read from a PCI1 configuration register
-*                    - Make sure the GT is configured as a master before 
+*                    - Make sure the GT is configured as a master before
 *                      reading from another device on the PCI.
 *                   - The function takes care of Big/Little endian conversion.
 * INPUTS:   regOffset: The register offset as it apears in the GT spec (or PCI
 *                        spec)
-*           pciDevNum: The device number needs to be addressed.                
-* RETURNS: data , if the data == 0xffffffff check the master abort bit in the 
+*           pciDevNum: The device number needs to be addressed.
+* RETURNS: data , if the data == 0xffffffff check the master abort bit in the
 *                 cause register to make sure the data is valid
 *
 *  Configuration Address 0xCF8:
@@ -718,7 +718,7 @@
 	pciDevNum = pciDevNum << 11;
 	regOffset = regOffset & 0x0fffffff;
 	if (pciDevNum == SELF) {	/* This board */
-		/* when configurating our own PCI 1 L-unit the access is through  
+		/* when configurating our own PCI 1 L-unit the access is through
 		   the PCI 0 interface with reg number = reg number + 0x80 */
 		DataForRegCf8 =
 		    (regOffset | pciDevNum | functionNum | 0x80) | BIT31;
@@ -1058,7 +1058,7 @@
 }
 
 /********************************************************************
-* pci0MapInternalRegSpace - Maps the internal registers memory space for the 
+* pci0MapInternalRegSpace - Maps the internal registers memory space for the
 *                           slave.
 *                           Stays the same for all GT devices Disco include
 * Inputs: base of pci0 internal register
@@ -1078,7 +1078,7 @@
 }
 
 /********************************************************************
-* pci1MapInternalRegSpace - Maps the internal registers memory space for the 
+* pci1MapInternalRegSpace - Maps the internal registers memory space for the
 *                           slave.
 *                           Stays the same for all GT devices Disco include
 * Inputs: base of pci1 internal register
@@ -1098,7 +1098,7 @@
 }
 
 /********************************************************************
-* pci0MapInternalRegIOSpace - Maps the internal registers IO space for the 
+* pci0MapInternalRegIOSpace - Maps the internal registers IO space for the
 *                             slave.
 *                             Stays the same for all GT devices Disco include
 * Inputs: base of pci0 internal io register
@@ -1117,7 +1117,7 @@
 }
 
 /********************************************************************
-* pci0MapInternalRegIOSpace - Maps the internal registers IO space for the 
+* pci0MapInternalRegIOSpace - Maps the internal registers IO space for the
 *                             slave.
 *                             Stays the same for all GT devices Disco include
 * Inputs: base of pci1 internal io register
@@ -1137,7 +1137,7 @@
 
 /********************************************************************
 * pci0MapMemoryBanks0_1 - Maps PCI0 memory banks 0 and 1 for the slave.
-*                         for Discovery we need two function: SCS0 & SCS1 
+*                         for Discovery we need two function: SCS0 & SCS1
 *                         (instead of SCS[1:0])
 * Inputs: base and size of pci0 dram
 *********************************************************************/
@@ -1163,7 +1163,7 @@
 
 /********************************************************************
 * pci1MapMemoryBanks0_1 - Maps PCI1 memory banks 0 and 1 for the slave.
-*                         for Discovery we need two function: SCS0 & SCS1 
+*                         for Discovery we need two function: SCS0 & SCS1
 *                         (instead of SCS[1:0])
 * Inputs: base and size of pci1 dram
 *********************************************************************/
@@ -1188,7 +1188,7 @@
 
 /********************************************************************
 * pci0MapMemoryBanks2_3 - Maps PCI0 memory banks 2 and 3 for the slave.
-*                         for Discovery we need two function: SCS2 & SCS3 
+*                         for Discovery we need two function: SCS2 & SCS3
 *                         (instead of SCS[3:2])
 * Inputs: base and size of pci0 dram
 *********************************************************************/
@@ -1213,7 +1213,7 @@
 
 /********************************************************************
 * pci1MapMemoryBanks2_3 - Maps PCI1 memory banks 2 and 3 for the slave.
-*                         for Discovery we need two function: SCS2 & SCS3 
+*                         for Discovery we need two function: SCS2 & SCS3
 *                         (instead of SCS[3:2])
 * Inputs: base and size of pci1 dram
 *********************************************************************/
@@ -1237,7 +1237,7 @@
 }
 
 /********************************************************************
-* pci0MapDevices0_1and2MemorySpace - Maps PCI0 devices 0,1 and 2 memory spaces 
+* pci0MapDevices0_1and2MemorySpace - Maps PCI0 devices 0,1 and 2 memory spaces
 *                                    for the slave.
 *                                    For the Discovery there are 3 separate
 *                                    fucnction's
@@ -1260,7 +1260,7 @@
 }
 
 /********************************************************************
-* pci1MapDevices0_1and2MemorySpace - Maps PCI1 devices 0,1 and 2 memory spaces 
+* pci1MapDevices0_1and2MemorySpace - Maps PCI1 devices 0,1 and 2 memory spaces
 *                                    for the slave.
 *                                    For the Discovery there are 3 separate
 *                                    fucnction's
@@ -1282,9 +1282,9 @@
 }
 
 /********************************************************************
-* pci0MapDevices3andBootMemorySpace - Maps PCI0 devices 3 and boot memory 
+* pci0MapDevices3andBootMemorySpace - Maps PCI0 devices 3 and boot memory
 *                                     spaces for the slave.
-*                                     For the Discovery there are 2 separate 
+*                                     For the Discovery there are 2 separate
 *                                     fucnction's
 * Inputs: base and length of pci0 device3/ boot
 *********************************************************************/
@@ -1309,9 +1309,9 @@
 }
 
 /********************************************************************
-* pci1MapDevices3andBootMemorySpace - Maps PCI1 devices 3 and boot memory 
+* pci1MapDevices3andBootMemorySpace - Maps PCI1 devices 3 and boot memory
 *                                     spaces for the slave.
-*                                     For the Discovery there are 2 separate 
+*                                     For the Discovery there are 2 separate
 *                                     fucnction's
 * Inputs: base and length of pci1 device3/ boot
 *********************************************************************/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/pci_etherboot.c linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/pci_etherboot.c
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/pci_etherboot.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/pci_etherboot.c	2002-10-29 11:18:31.000000000 +0000
@@ -21,7 +21,7 @@
 	if ((bus == 0) && (dev >= 0) && (dev < 30))
 		return 0;	// Bus/Device Number OK
 
-	return -1;		// Bus/Device Number not OK  
+	return -1;		// Bus/Device Number not OK
 }
 
 /********************************************************************
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/sbdreset_evb64120A.S linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/sbdreset_evb64120A.S
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/compressed/sbdreset_evb64120A.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/compressed/sbdreset_evb64120A.S	2002-10-29 11:18:31.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * Copyright 1997 Algorithmics Ltd
  *	All Rights Reserved
- *	
+ *
  * gal9/sbdreset.sx -- low level board dependent routines
  */
 
@@ -23,29 +23,29 @@
 
 #include "gt64011.h"
 #include "ns16550.h"
-			
+
 #ifdef GALILEO_PORT // miniBios crack
 #define C0_CONFIG CP0_CONFIG
 #define C0_STATUS CP0_STATUS
 #define C0_TLBLO0 CP0_ENTRYLO0
 #define C0_TLBLO1 CP0_ENTRYLO1
 #define C0_PGMASK CP0_PAGEMASK
-#define C0_TLBHI CP0_ENTRYHI 
+#define C0_TLBHI CP0_ENTRYHI
 #define C0_INX CP0_INDEX
 #define NTLBENTRIES     48
-        
-        
+
+
 #define CFG_IB CONF_IB
 #define CFG_DB CONF_DB
 #define CFG_C_NONCOHERENT CONF_CM_CACHABLE_NONCOHERENT
-#define C0_SR CP0_STATUS        
+#define C0_SR CP0_STATUS
 #define SR_DE ST0_DE
 
-        
+
         #define SLEAF(x) LEAF(x)
         #define SEND(x) END(x)
         #define XLEAF(x) LEAF(x)
-        #define SBD_DISPLAY(a,b,c,d,e) ; 
+        #define SBD_DISPLAY(a,b,c,d,e) ;
 
 #define K0BASE          0x80000000
 #define K0SIZE          0x20000000
@@ -70,7 +70,7 @@
 #endif
 
 #define MB	0x100000
-				
+
 #define MemTypeNone		0x8000
 #define MemRasMask		0x0f00
 #define MemRasShift		8
@@ -85,7 +85,7 @@
 #define bank3	s5
 #define memtop	s6
 #define membase	s7
-	
+
 /*#if #endian(big)	*/
 #ifdef __MIPSEB__
 
@@ -104,9 +104,9 @@
 #else
 #define HTOLL(sr,tr)
 #endif
-				
+
 #undef DBGSBD
-	
+
 #ifdef DBGSBD
 #define DBG(s) \
 	.rdata ; \
@@ -114,7 +114,7 @@
 	.text ; \
 	la	a0, 88b ; \
 	jal	_dbgmsg
-	
+
 LEAF(_dbgmsg)
 	.set noat
 	li	AT,PHYS_TO_K1(NS16550_CHANB)
@@ -123,13 +123,13 @@
 	.set noreorder;	nop; nop; nop; nop; nop; nop; nop; nop; .set reorder
 	and	v1,LSR_TXRDY
 	beqz	v1,waitrdy
-	
+
 	lbu	v1,(a0)
 	addu	a0,1
 	beqz	v1,9f
 	sb	v1,DATA(AT)
 	.set noreorder;	nop; nop; nop; nop; nop; nop; nop; nop; .set reorder
-	b	waitrdy	
+	b	waitrdy
 9:	j	ra
 	.set at
 END(_dbgmsg)
@@ -142,7 +142,7 @@
 	.set noreorder;	nop; nop; nop; nop; nop; nop; nop; nop; .set reorder
 	and	t1,LSR_TXRDY
 	beqz	t1,1b
-	
+
 	srl	t1,a0,28
 	addu	t1,'0'
 	ble	t1,'9',2f
@@ -153,11 +153,11 @@
 	sll	a0,4
 	sub	t0,1
 	bnez	t0,1b
-		
+
 	j	ra
 	.set at
 END(_dbghex)
-	
+
 	.rdata
 initb_str:
 	.byte	9,0x40	/* Reset CH B */
@@ -171,7 +171,7 @@
 	.byte	0,0x10
 	.byte	14,0x01	/* enable baud rate gen. */
 	.byte	15,0x00	/* known state for reg 15 */
-	
+
 	.byte	14,0x00	/* disable baud rate gen. */
 	.byte	12,0x0a /* 0x0a	= 9600 baud time const. - lower 8 bits */
 	.byte	13,0x00	/* 9600 buad time const. - upper 8 bits */
@@ -179,7 +179,7 @@
 	.byte	0xff
 
 	.text
-	
+
 SLEAF(_dbginit)
         /*
         li	v0,PHYS_TO_K1(NS16550_CHANB)
@@ -194,27 +194,27 @@
         */
         jal     init_ns16550_chan_b # Debug channel
 	j	ra
-SEND(_dbginit)		
+SEND(_dbginit)
 #else
-#define DBG(s)		
+#define DBG(s)
 #endif
-		
+
 LEAF(sbdreset)
 	move	rasave,ra
 
 	/* if launched by ITROM, leave Config alone */
-#ifndef ITBASE	
+#ifndef ITBASE
 	/* set config register for 32b/32b cachelines, kseg0 cacheable */
 	mfc0	t1,C0_CONFIG
 	and	t1,~0x3f		# set bits 5..0 only
 	or	t1,CFG_IB | CFG_DB | CFG_C_NONCOHERENT
 	mtc0	t1,C0_CONFIG
-#endif	
+#endif
+
+       /* Initialize stack pointer to 6MB address */
+         li sp,0xa0600000
 
-       /* Initialize stack pointer to 6MB address */        
-         li sp,0xa0600000 
 
-        
         /*
 	 * slight amount of kludgery here to stop RAM resident
 	 * program from overwriting itself...
@@ -248,23 +248,23 @@
 #define GT_INTERNAL_REG_BASE 0xb4000000
 
         li      p64011, PA_TO_KVA1(GT64011_BASE)
-         
+
         li  v0,0xb400046c       /* Boot Device */
         lw  t0,0(v0)
         and t0,0x00003000       /* Keep the correct boot size */
 	or  t0,htoll(0x3847de70)
 	sw  t0,0(v0)
-        
+
         li  v0,0xb4000468       /* CS3 Device - 16 bit FLASH memory */
         li  t0,htoll(0x3859e6e8)
 	sw  t0,0(v0)
-        
-                
+
+
         li  v0,0xb4000c84       /* PCI 1 timeout register */
         li  t0,htoll(0xffff)
 	sw  t0,0(v0)
-        
-                
+
+
         li  v0,0xb4000c3c       /* Enable I/O response on PCI0 */
         li  t0,htoll(0x7)
 	sw  t0,0(v0)
@@ -274,14 +274,14 @@
 	sw  t0,0(v0)
 
         /* GT-64120 Initialization */
-        
-        li      p64011, PA_TO_KVA1(GT64011_BASE)	
+
+        li      p64011, PA_TO_KVA1(GT64011_BASE)
 
         /*********************************************************************/
         /************************* SDRAM initializing ************************/
         /******************************* START *******************************/
-        
-        
+
+
                                         /* SDRAM banks 0,1,2,3 parameters               */
         li      t0,htoll(0x01908200)    /* - Standard Monitor: Interleave enabled       */
         li      v0,0xb4000448           /* - Registered SDRAM (Bit 23)                  */
@@ -292,76 +292,76 @@
                                         /* - No ECC                                     */
                                         /* - No ByPass                                  */
                                         /* - Burst length: 8                            */
-        
+
         /* Detect whether we have a 16,64,128 or 256 Mbit SDRAM on DIMM0 */
         /* Set bank0`s range to: 0 - 0x10000000 (256 MByte)     */
 _DIMM0:
-        li  v0,0xb4000008      
+        li  v0,0xb4000008
 	li  t0,htoll(0x0)
 	sw  t0,0(v0)
-        
-        li  v0,0xb4000010      
+
+        li  v0,0xb4000010
 	li  t0,htoll(0x7f)
 	sw  t0,0(v0)
-        
+
         /* Close banks 2 and 3 */
-        li  v0,0xb4000018      
+        li  v0,0xb4000018
 	li  t0,htoll(0x7ff)
 	sw  t0,0(v0)
-        li  v0,0xb4000020      
+        li  v0,0xb4000020
 	li  t0,htoll(0x00)
 	sw  t0,0(v0)
-        
+
         /* Extend bank0 to 0x10000000 and Close bank1,2 and 3 */
         DBG("Extend bank0 to 0x10000000 and Close bank1,2 and 3...\r\n")
-        li  v0,0xb4000400      
+        li  v0,0xb4000400
 	li  t0,htoll(0x0)
 	sw  t0,0(v0)
-        li  v0,0xb4000404      
+        li  v0,0xb4000404
 	li  t0,htoll(0xff)
 	sw  t0,0(v0)
-        li  v0,0xb4000408      
+        li  v0,0xb4000408
 	li  t0,htoll(0xff)
-	sw  t0,0(v0)   
-        li  v0,0xb400040c      
+	sw  t0,0(v0)
+        li  v0,0xb400040c
 	li  t0,htoll(0x00)
 	sw  t0,0(v0)
-        li  v0,0xb4000410      
+        li  v0,0xb4000410
 	li  t0,htoll(0xff)
-	sw  t0,0(v0)   
-        li  v0,0xb4000414      
+	sw  t0,0(v0)
+        li  v0,0xb4000414
 	li  t0,htoll(0x00)
 	sw  t0,0(v0)
-        li  v0,0xb4000418      
+        li  v0,0xb4000418
 	li  t0,htoll(0xff)
-	sw  t0,0(v0)   
-        li  v0,0xb400041c      
+	sw  t0,0(v0)
+        li  v0,0xb400041c
 	li  t0,htoll(0x00)
-	sw  t0,0(v0)        
+	sw  t0,0(v0)
 
         /* Configure bank0 to 256 Mbit */
         DBG("Configure bank0 to 256 Mbit...\r\n")
-        li  v0,0xb400044c      
+        li  v0,0xb400044c
 	li  t0,htoll(0x00004c69)
         sw  t0,0(v0)
-        
+
         /* Config the SDRAM banks decode system */
-	li  v0,0xb400047c      
+	li  v0,0xb400047c
 	li  t0,htoll(2)
 	sw  t0,0(v0)
- 
-        li  v0,0xb4000474        
+
+        li  v0,0xb4000474
 	li  t0,htoll(0x3)
 	sw  t0,0(v0)
-        
+
         li  v0,0xa0000000
         li  t0,0
         sw  t0,0(v0)
-        
-        li  v0,0xb4000474        
+
+        li  v0,0xb4000474
 	li  t0,htoll(0x0)
-	sw  t0,0(v0)      
-        
+	sw  t0,0(v0)
+
         /* Write to address 0x2000000 and check if 0x00000000 is being written too */
         DBG("Write to address 0x2000000 and check if 0x00000000 is being written too...\r\n")
         li  v0,0xa0000000
@@ -372,7 +372,7 @@
         bne t1,v0,1b
 
         /* The address should activate Dadr12 */
-        li  v0,0xa2000000      
+        li  v0,0xa2000000
 	li  t0,0x11111111
         sw  t0,0(v0)
         li  v0,0xa0000010
@@ -387,7 +387,7 @@
         li    v0,0x11111111
         lw    t0,(t0)
         bne   t0,v0,_256MBIT
-        
+
         /* Write to address 0x1000 and check if 0x00000000 is being written too */
         DBG("Write to address 0x1000 and check if 0x00000000 is being written too...\r\n")
         li  v0,0xa0000000
@@ -398,7 +398,7 @@
         bne t1,v0,1b
 
         /* The address should activate bank select1*/
-        li  v0,0xa0001000      
+        li  v0,0xa0001000
 	li  t0,0x11111111
         sw  t0,0(v0)
         li  v0,0xa0000010
@@ -425,7 +425,7 @@
 
         /* The address should activate Dadr9 which on the column cycle is in active with 64 Mbit
            device */
-        li  v0,0xa8000000      
+        li  v0,0xa8000000
 	li  t0,0x11111111
         sw  t0,0(v0)
         li  v0,0xa0000010
@@ -441,11 +441,11 @@
         lw    t0,(t0)
         beq   t0,v0,_64MBIT
         b     _128MBIT
-        
+
 _16MBIT:
         DBG("16 Mbit SDRAM detected...\r\n")
         /* In 16 Mbit SDRAM we must use 2 way bank interleaving!!! */
-        li  v0,0xb4000810      
+        li  v0,0xb4000810
 	li  t0,htoll(16)
 	sw  t0,0(v0)
         li  t1,htoll(0x00000449)
@@ -454,7 +454,7 @@
 _64MBIT:
         DBG("64 Mbit SDRAM detected...\r\n")
         /* In 64 Mbit SDRAM we must use 4 way bank interleaving!!! */
-        li  v0,0xb4000810      
+        li  v0,0xb4000810
 	li  t0,htoll(64)
 	sw  t0,0(v0)
         li  t1,htoll(0x00000c69)
@@ -463,7 +463,7 @@
 _128MBIT:
         DBG("128 Mbit SDRAM detected...\r\n")
         /* In 128 Mbit SDRAM we must use 4 way bank interleaving!!! */
-        li  v0,0xb4000810      
+        li  v0,0xb4000810
 	li  t0,htoll(128)
 	sw  t0,0(v0)
         li  t1,htoll(0x00000c69)
@@ -472,85 +472,85 @@
 _256MBIT:
         DBG("256 Mbit SDRAM detected...\r\n")
         /* In 256 Mbit SDRAM we must use 4 way bank interleaving!!! */
-        li  v0,0xb4000810      
+        li  v0,0xb4000810
 	li  t0,htoll(256)
 	sw  t0,0(v0)
         li  t1,htoll(0x00004c69)
         b   _DIMM1
-        
-_DIMM1:        
+
+_DIMM1:
         li  v0,0xb400044c
         sw  t1,0(v0)  # Bank0
-        sw  t1,4(v0)  # Bank1           
-        
+        sw  t1,4(v0)  # Bank1
+
         /* Detect whether we have a 16,64,128 or 256 Mbit SDRAM on DIMM1 */
         /* Close banks 0 and 1 */
-        li  v0,0xb4000008      
+        li  v0,0xb4000008
 	li  t0,htoll(0xff)
 	sw  t0,0(v0)
-        
-        li  v0,0xb4000010      
+
+        li  v0,0xb4000010
 	li  t0,htoll(0x0)
 	sw  t0,0(v0)
-        
+
         /* Set bank2`s range to: 0 - 0x10000000 (256 MByte)     */
-        li  v0,0xb4000018      
+        li  v0,0xb4000018
 	li  t0,htoll(0x0)
 	sw  t0,0(v0)
-        li  v0,0xb4000020      
+        li  v0,0xb4000020
 	li  t0,htoll(0x7f)
 	sw  t0,0(v0)
-        
+
         /* Extend bank2 to 0x10000000 and Close bank0,1 and 3 */
         DBG("Extend bank2 to 0x10000000 and Close banks 0,1 and 3...\r\n")
-        li  v0,0xb4000400      
+        li  v0,0xb4000400
 	li  t0,htoll(0xff)
 	sw  t0,0(v0)
-        li  v0,0xb4000404      
+        li  v0,0xb4000404
 	li  t0,htoll(0x00)
 	sw  t0,0(v0)
-        li  v0,0xb4000408      
+        li  v0,0xb4000408
 	li  t0,htoll(0xff)
-	sw  t0,0(v0)   
-        li  v0,0xb400040c      
+	sw  t0,0(v0)
+        li  v0,0xb400040c
 	li  t0,htoll(0x00)
 	sw  t0,0(v0)
-        li  v0,0xb4000410      
+        li  v0,0xb4000410
 	li  t0,htoll(0x00)
-	sw  t0,0(v0)   
-        li  v0,0xb4000414      
+	sw  t0,0(v0)
+        li  v0,0xb4000414
 	li  t0,htoll(0xff)
 	sw  t0,0(v0)
-        li  v0,0xb4000418      
+        li  v0,0xb4000418
 	li  t0,htoll(0xff)
-	sw  t0,0(v0)   
-        li  v0,0xb400041c      
+	sw  t0,0(v0)
+        li  v0,0xb400041c
 	li  t0,htoll(0x00)
-	sw  t0,0(v0)        
+	sw  t0,0(v0)
 
         /* Configure bank2 to 256 Mbit */
         DBG("Configure bank2 to 256 Mbit...\r\n")
-        li  v0,0xb4000454      
+        li  v0,0xb4000454
 	li  t0,htoll(0x00004c69)
         sw  t0,0(v0)
-        
+
         /* Config the SDRAM banks decode system */
-	li  v0,0xb400047c      
+	li  v0,0xb400047c
 	li  t0,htoll(2)
 	sw  t0,0(v0)
- 
-        li  v0,0xb4000474        
+
+        li  v0,0xb4000474
 	li  t0,htoll(0x3)
 	sw  t0,0(v0)
-        
+
         li  v0,0xa0000000
         li  t0,0
         sw  t0,0(v0)
-        
-        li  v0,0xb4000474        
+
+        li  v0,0xb4000474
 	li  t0,htoll(0x0)
-	sw  t0,0(v0)      
-        
+	sw  t0,0(v0)
+
         /* Write to address 0x2000000 and check if 0x00000000 is being written too */
         DBG("Write to address 0x2000000 and check if 0x00000000 is being written too...\r\n")
         li  v0,0xa0000000
@@ -561,7 +561,7 @@
         bne t1,v0,1b
 
         /* The address should activate Dadr12 */
-        li  v0,0xa2000000      
+        li  v0,0xa2000000
 	li  t0,0x11111111
         sw  t0,0(v0)
         li  v0,0xa0000010
@@ -576,7 +576,7 @@
         li    v0,0x11111111
         lw    t0,(t0)
         bne   t0,v0,_256MBIT2
-        
+
         /* Write to address 0x1000 and check if 0x00000000 is being written too */
         DBG("Write to address 0x1000 and check if 0x00000000 is being written too...\r\n")
         li  v0,0xa0000000
@@ -587,7 +587,7 @@
         bne t1,v0,1b
 
         /* The address should activate bank select1*/
-        li  v0,0xa0001000      
+        li  v0,0xa0001000
 	li  t0,0x11111111
         sw  t0,0(v0)
         li  v0,0xa0000010
@@ -614,7 +614,7 @@
 
         /* The address should activate Dadr9 which on the column cycle is in active with 64 Mbit
            device */
-        li  v0,0xa8000000      
+        li  v0,0xa8000000
 	li  t0,0x11111111
         sw  t0,0(v0)
         li  v0,0xa0000010
@@ -630,11 +630,11 @@
         lw    t0,(t0)
         beq   t0,v0,_64MBIT2
         b     _128MBIT2
-        
+
 _16MBIT2:
         DBG("16 Mbit SDRAM detected...\r\n")
         /* In 16 Mbit SDRAM we must use 2 way bank interleaving!!! */
-        li  v0,0xb4000814      
+        li  v0,0xb4000814
 	li  t0,htoll(16)
 	sw  t0,0(v0)
         li  t1,htoll(0x00000449)
@@ -643,7 +643,7 @@
 _64MBIT2:
         DBG("64 Mbit SDRAM detected...\r\n")
         /* In 64 Mbit SDRAM we must use 4 way bank interleaving!!! */
-        li  v0,0xb4000814      
+        li  v0,0xb4000814
 	li  t0,htoll(64)
 	sw  t0,0(v0)
         li  t1,htoll(0x00000c69)
@@ -652,7 +652,7 @@
 _128MBIT2:
         DBG("128 Mbit SDRAM detected...\r\n")
         /* In 128 Mbit SDRAM we must use 4 way bank interleaving!!! */
-        li  v0,0xb4000814      
+        li  v0,0xb4000814
 	li  t0,htoll(128)
 	sw  t0,0(v0)
         li  t1,htoll(0x00000c69)
@@ -661,104 +661,104 @@
 _256MBIT2:
         DBG("256 Mbit SDRAM detected...\r\n")
         /* In 256 Mbit SDRAM we must use 4 way bank interleaving!!! */
-        li  v0,0xb4000814      
+        li  v0,0xb4000814
 	li  t0,htoll(256)
 	sw  t0,0(v0)
         li  t1,htoll(0x00004c69)
         b   _INIT_SDRAM
 
-_INIT_SDRAM:        
+_INIT_SDRAM:
         /* Restore defaults */
         DBG("Restoring defaults...\r\n")
-        li  v0,0xb4000404      
+        li  v0,0xb4000404
 	li  t0,htoll(0x07)
 	sw  t0,0(v0)
-        li  v0,0xb4000408      
+        li  v0,0xb4000408
 	li  t0,htoll(0x08)
 	sw  t0,0(v0)
-        li  v0,0xb400040c      
+        li  v0,0xb400040c
 	li  t0,htoll(0x0f)
 	sw  t0,0(v0)
-        li  v0,0xb4000410      
+        li  v0,0xb4000410
 	li  t0,htoll(0x10)
-	sw  t0,0(v0)   
-        li  v0,0xb4000414      
+	sw  t0,0(v0)
+        li  v0,0xb4000414
 	li  t0,htoll(0x17)
 	sw  t0,0(v0)
-        li  v0,0xb4000418      
+        li  v0,0xb4000418
 	li  t0,htoll(0x18)
-	sw  t0,0(v0)   
-        li  v0,0xb400041c      
+	sw  t0,0(v0)
+        li  v0,0xb400041c
 	li  t0,htoll(0x1f)
 	sw  t0,0(v0)
-        li  v0,0xb4000010      
+        li  v0,0xb4000010
 	li  t0,htoll(0x07)
 	sw  t0,0(v0)
-        li  v0,0xb4000018      
+        li  v0,0xb4000018
 	li  t0,htoll(0x008)
 	sw  t0,0(v0)
-        li  v0,0xb4000020      
+        li  v0,0xb4000020
 	li  t0,htoll(0x0f)
-	sw  t0,0(v0)        
-        
+	sw  t0,0(v0)
+
         li  v0,0xb400044c
         sw  t1,8(v0)  # Bank2
         sw  t1,12(v0) # Bank3
-        
-        li  v0,0xb4000474        
+
+        li  v0,0xb4000474
 	li  t0,htoll(0x3)
 	sw  t0,0(v0)
-        
+
         li  v0,0xa0000000
         li  t0,0
         sw  t0,0(v0)
-        
-        li  v0,0xb4000474        
+
+        li  v0,0xb4000474
 	li  t0,htoll(0x0)
 	sw  t0,0(v0)
-        
-        li  v0,0xb4000474        
+
+        li  v0,0xb4000474
 	li  t0,htoll(0x3)
 	sw  t0,0(v0)
-        
+
         li  v0,0xa0800000
         li  t0,0
         sw  t0,0(v0)
-        
-        li  v0,0xb4000474        
+
+        li  v0,0xb4000474
 	li  t0,htoll(0x0)
 	sw  t0,0(v0)
-        
-        li  v0,0xb4000474        
+
+        li  v0,0xb4000474
 	li  t0,htoll(0x3)
 	sw  t0,0(v0)
-        
+
         li  v0,0xa1000000
         li  t0,0
         sw  t0,0(v0)
-        
-        li  v0,0xb4000474        
+
+        li  v0,0xb4000474
 	li  t0,htoll(0x0)
 	sw  t0,0(v0)
-        
-        li  v0,0xb4000474        
+
+        li  v0,0xb4000474
 	li  t0,htoll(0x3)
 	sw  t0,0(v0)
-        
+
         li  v0,0xa1800000
         li  t0,0
         sw  t0,0(v0)
-        
-        li  v0,0xb4000474        
+
+        li  v0,0xb4000474
 	li  t0,htoll(0x0)
 	sw  t0,0(v0)
-        
+
         /*********************************************************************/
         /************************* SDRAM initializing ************************/
         /******************************* END *********************************/
-        
+
         li      p64011, PA_TO_KVA1(GT64011_BASE)
-        
+
         li      t0,htoll(0x00000000)    /* RAS[1:0] low decode address */
         sw      t0,0x008(p64011)
 
@@ -794,8 +794,8 @@
 
         li      t0,htoll(0x0000001f)    /* RAS[3] High Decode Address <<<<<< 1*/
         sw      t0,0x41c(p64011)
-	
-#ifdef DBGSBD	
+
+#ifdef DBGSBD
 #define DREG(str,rname) \
 	DBG(str); \
 	DBG(":\t") ;			\
@@ -803,7 +803,7 @@
 	HTOLL(a0,t0) ;			\
 	jal	_dbghex ;		\
 	DBG("\r\n")
-	
+
 	DBG("GT-64120 settings:\r\n")
         DREG("DRAMPAR_BANK0   (44c)",GT_DRAMPAR_BANK0)
         DREG("DRAMPAR_BANK1   (450)",GT_DRAMPAR_BANK1)
@@ -828,7 +828,7 @@
         DREG("GT_DEVPAR_BANK3 (468)",GT_DEVPAR_BANK3)
         DREG("GT_IPCI_TOR     (c04)",GT_IPCI_TOR)
 #endif
-		
+
 	/* we can now initialise the caches for a fast clear_mem */
 	SBD_DISPLAY ('C','A','C','H',CHKPNT_CACH)
 	DBG("init_cache\r\n")
@@ -839,7 +839,7 @@
 	/* initialise tlb */
 	SBD_DISPLAY ('I','T','L','B', CHKPNT_ITLB)
 	DBG("init_tlb\r\n")
-//	bal	init_tlb 
+//	bal	init_tlb
 
 //	DBG("sbdreset completed\r\n")
 //	move	ra,rasave
@@ -928,7 +928,7 @@
 
 LEAF(sbdberrenb)
 	mfc0	v0,C0_SR
-	li	t0,SR_DE	
+	li	t0,SR_DE
 	bnez	a0,1f
 	or	t1,v0,t0	# disable cache/parity errors (SR_DE = 1)
 	b	2f
@@ -966,7 +966,7 @@
 1:	mul	a0,t1
 	subu	a0,15		# approx number of loops so far
 
-	.set	noreorder	
+	.set	noreorder
 	.set	nomacro
 	nop
 2:	bgtz	a0,2b
@@ -981,7 +981,7 @@
 
 
 LEAF(mips_cycle)
-	.set	noreorder	
+	.set	noreorder
 	.set	nomacro
 1:	bgtz	a0,1b
 	subu	a0,1
@@ -992,7 +992,7 @@
 
 LEAF(init_ns16550_chan_b)
 	# enable 16550 fifo if it is there
-        li      a0,NS16550_CHANB 
+        li      a0,NS16550_CHANB
         li	t0,FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4
 	sb	t0,FIFO(a0)
 
@@ -1002,25 +1002,25 @@
 	li	t0,CFCR_DLAB			# select brtc divisor
 	sb	t0,CFCR(a0)
 	sb	t2,DATA(a0)			# store divisor lsb
-	srl	t2,8	
+	srl	t2,8
 	sb	t2,IER(a0)			# store divisor msb
 
 	li	t0,CFCR_8BITS			# set 8N1 mode
 	sb	t0,CFCR(a0)
 
-	li	t0,MCR_DTR|MCR_RTS # Galileo |MCR_IENABLE	# enable DTR & RTS 
+	li	t0,MCR_DTR|MCR_RTS # Galileo |MCR_IENABLE	# enable DTR & RTS
   	sb	t0,MCR(a0)
- 	li	t0,0 # Galileo IER_ERXRDY			# enable receive interrupt(!) 
+ 	li	t0,0 # Galileo IER_ERXRDY			# enable receive interrupt(!)
 	sb	t0,IER(a0)
 
 	move	v0,zero				# indicate success
 	j	ra
-	
+
 END(init_ns16550_chan_b)
 
 LEAF(init_ns16550_chan_a)
 	# enable 16550 fifo if it is there
-        li      a0,NS16550_CHANA 
+        li      a0,NS16550_CHANA
         li	t0,FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4
 	sb	t0,FIFO(a0)
 
@@ -1030,20 +1030,20 @@
 	li	t0,CFCR_DLAB			# select brtc divisor
 	sb	t0,CFCR(a0)
 	sb	t2,DATA(a0)			# store divisor lsb
-	srl	t2,8	
+	srl	t2,8
 	sb	t2,IER(a0)			# store divisor msb
 
 	li	t0,CFCR_8BITS			# set 8N1 mode
 	sb	t0,CFCR(a0)
 
-	li	t0,MCR_DTR|MCR_RTS # Galileo |MCR_IENABLE	# enable DTR & RTS 
+	li	t0,MCR_DTR|MCR_RTS # Galileo |MCR_IENABLE	# enable DTR & RTS
   	sb	t0,MCR(a0)
- 	li	t0,0 # Galileo IER_ERXRDY			# enable receive interrupt(!) 
+ 	li	t0,0 # Galileo IER_ERXRDY			# enable receive interrupt(!)
 	sb	t0,IER(a0)
 
 	move	v0,zero				# indicate success
 	j	ra
-	
+
 END(init_ns16550_chan_a)
 
 #endif /* EVB64120A */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/dma.c linux-2.4.20/arch/mips/galileo-boards/ev64120/dma.c
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/dma.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/dma.c	2002-10-29 11:18:35.000000000 +0000
@@ -6,7 +6,7 @@
 DESCRIPTION
 This file gives the user a complete interface to the powerful DMA engines,
 including functions for controling the priority mechanism.
-To fully understand the capabilities of the DMA engines please spare some 
+To fully understand the capabilities of the DMA engines please spare some
 time to go trough the spec.
 */
 
@@ -20,11 +20,11 @@
 #include "DMA.h"
 #endif
 /********************************************************************
-* dmaCommand - Write a command to a DMA channel 
+* dmaCommand - Write a command to a DMA channel
 *
 * Inputs: DMA_ENGINE channel - choosing one of the four engine.
 *         unsigned int command - The command to be written to the control register.
-* Returns: false if one of the parameters is erroneous else returns true. 
+* Returns: false if one of the parameters is erroneous else returns true.
 *********************************************************************/
 
 bool dmaCommand(DMA_ENGINE channel, unsigned int command)
@@ -39,14 +39,14 @@
 * dmaTransfer - transfer data from sourceAddr to destAddr on DMA channel
 * Inputs:
 *   DMA_RECORED *nextRecoredPointer: If we are using chain mode DMA transfer,
-*   then this pointer should point to the next recored,otherwise it should be 
+*   then this pointer should point to the next recored,otherwise it should be
 *   NULL.
-*   VERY IMPORTANT !!! When using chain mode, the records must be 16 Bytes 
-*   aligned, the function will take care of that for you, but you need to 
+*   VERY IMPORTANT !!! When using chain mode, the records must be 16 Bytes
+*   aligned, the function will take care of that for you, but you need to
 *   allocate one more record for that, meaning: if you are having 3 records ,
 *   declare 4 (see the example bellow) and start using the second one.
 *   Example:
-*   Performing a chain mode DMA transfer(Copy a 1/4 mega of data using 
+*   Performing a chain mode DMA transfer(Copy a 1/4 mega of data using
 *   chain mode DMA):
 *    DMA_RECORED dmaRecoredArray[4];
 *    dmaRecoredArray[1].ByteCnt = _64KB;
@@ -149,10 +149,10 @@
 
 
 /********************************************************************
-* changeDmaPriority - update the arbiter`s priority for channels 0-3 
+* changeDmaPriority - update the arbiter`s priority for channels 0-3
 *
-* Inputs: priority  for channels 0-1, priority  for channels 2-3, 
-          priority for groups and other priority options   
+* Inputs: priority  for channels 0-1, priority  for channels 2-3,
+          priority for groups and other priority options
 * RETURNS: false if one of the parameters is erroneous and true else
 *********************************************************************/
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/i2o.c linux-2.4.20/arch/mips/galileo-boards/ev64120/i2o.c
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/i2o.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/i2o.c	2002-10-29 11:18:49.000000000 +0000
@@ -21,7 +21,7 @@
 *                     the CPU.
 *                     The messaging unit contains two sets of registers
 *                     so, actually it can receive a 64 bit message.
-* 
+*
 * INPUTS: I2O_MESSAGE_REG messageRegNum - Selected set (0 or 1) register.
 * OUTPUT: N/A.
 * RETURNS: Data received from the remote agent.
@@ -37,12 +37,12 @@
 
 
 /********************************************************************
-* checkInboundIntAndClear - When a message is received an interrupt is 
+* checkInboundIntAndClear - When a message is received an interrupt is
 *                           generated, to enable polling instead the use of
 *                           an interrupt handler the user can use this fuction.
 *                           You will need to mask the incomming interrupt for
 *                           proper use.
-* 
+*
 * INPUTS: I2O_MESSAGE_REG messageRegNum - Selected set (0 or 1) register.
 * OUTPUT: N/A.
 * RETURNS: true if the corresponding bit in the cause register is set otherwise
@@ -76,9 +76,9 @@
 *                     the PCI agent.
 *                     The messaging unit contains two sets of registers
 *                     so, actually it can send a 64 bit message.
-* 
+*
 * INPUTS: I2O_MESSAGE_REG messageRegNum - Selected set (0 or 1) register.
-*         unsigned int message - Message to be sent.   
+*         unsigned int message - Message to be sent.
 * OUTPUT: N/A.
 * RETURNS: true.
 *********************************************************************/
@@ -94,7 +94,7 @@
 * checkOutboundInt - When the CPU sends a message to the Outbound
 *                    register it generates an interrupt which is refelcted on
 *                    the Outbound Interrupt cause register, the interrupt can
-*                    be cleard only by the PCI agent which read the message. 
+*                    be cleard only by the PCI agent which read the message.
 *                    After sending the message you can acknowledge it by
 *                    monitoring the corresponding bit in the cause register.
 *
@@ -124,8 +124,8 @@
 /********************************************************************
 * maskInBoundMessageInterrupt - Mask the inbound interrupt, when masking
 *                               the interrupt you can work in polling mode
-*                               using the checkInboundIntAndClear function. 
-* 
+*                               using the checkInboundIntAndClear function.
+*
 * INPUTS: I2O_MESSAGE_REG messageRegNum - Selected set (0 or 1) register.
 * OUTPUT: N/A.
 * RETURNS: true.
@@ -146,8 +146,8 @@
 }
 
 /********************************************************************
-* enableInBoundMessageInterrupt - unMask the inbound interrupt. 
-* 
+* enableInBoundMessageInterrupt - unMask the inbound interrupt.
+*
 * INPUTS: I2O_MESSAGE_REG messageRegNum - Selected set (0 or 1) register.
 * OUTPUT: N/A.
 * RETURNS: true.
@@ -170,8 +170,8 @@
 /********************************************************************
 * maskOutboundMessageInterrupt - Mask the out bound interrupt, when doing so
 *                           the PCI agent needs to poll on the interrupt
-*                           cause register to monitor an incoming message. 
-* 
+*                           cause register to monitor an incoming message.
+*
 * INPUTS: I2O_MESSAGE_REG messageRegNum - Selected set (0 or 1) register.
 * OUTPUT: N/A.
 * RETURNS: true.
@@ -194,8 +194,8 @@
 /********************************************************************
 * enableOutboundMessageInterrupt - Mask the out bound interrupt, when doing so
 *                           the PCI agent needs to poll on the interrupt
-*                           cause register to monitor an incoming message. 
-* 
+*                           cause register to monitor an incoming message.
+*
 * INPUTS: I2O_MESSAGE_REG messageRegNum - Selected set (0 or 1) register.
 * OUTPUT: N/A.
 * RETURNS: true.
@@ -216,13 +216,13 @@
 }
 
 /********************************************************************
-* initiateOutBoundDoorBellInt - Setting a bit in this register to '1' by the 
+* initiateOutBoundDoorBellInt - Setting a bit in this register to '1' by the
 *                       CPU generates a PCI interrupt (if it is not masked by
 *                       the Outbound interrupt Mask register)
 *                       Only the PCI agent which recieved the interrupt can
 *                       clear it, only after clearing all the bits the
 *                       interrupt will be de-asserted.
-* 
+*
 * INPUTS: unsigned int data - Requested interrupt bits.
 * OUTPUT: N/A.
 * RETURNS: true.
@@ -236,7 +236,7 @@
 /********************************************************************
 * readInBoundDoorBellInt - Read the in bound door bell interrupt cause
 *                          register.
-* 
+*
 * OUTPUT:  N/A.
 * RETURNS: The 32 bit interrupt cause register.
 *********************************************************************/
@@ -253,7 +253,7 @@
 *                           only by the CPU. The interrupt will be de-asserted
 *                           only if all the bits which where set by the PCI
 *                           agent are cleared.
-* 
+*
 * INPUTS:  unsigned int data - Bits to be cleared.
 * OUTPUT:  N/A.
 * RETURNS: true.
@@ -282,11 +282,11 @@
 }
 
 /********************************************************************
-* isOutBoundDoorBellInterruptSet - Check if out bound Doorbell Interrupt is 
+* isOutBoundDoorBellInterruptSet - Check if out bound Doorbell Interrupt is
 *                                  set, can be used for acknowledging interrupt
 *                                  handling by the agent who recieived the
-*                                  interrupt. 
-* 
+*                                  interrupt.
+*
 * INPUTS:  N/A.
 * OUTPUT:  N/A.
 * RETURNS: true if the corresponding bit in the cause register is set otherwise
@@ -354,7 +354,7 @@
 
 /********************************************************************
 * circularQueueEnable - Initialize the I2O messaging mechanism.
-* 
+*
 * INPUTS:   CIRCULE_QUEUE_SIZE cirQueSize - Bits 5:1 in the:
 *           Queue Control Register, Offset 0x50 (0x1c50).
 *           Defines the queues size (refer to the data sheet
@@ -364,7 +364,7 @@
 *           Inbound Free = queueBaseAddr
 *           Inbound Post = queueBaseAddr + cirQueSize
 *           Outbound Post = queueBaseAddr + cirQueSize
-*           
+*
 * OUTPUT:  N/A.
 * RETURNS: true.
 *
@@ -410,10 +410,10 @@
 }
 
 /********************************************************************
-* inBoundPostQueuePop - Two actions are being taken upon pop: 
+* inBoundPostQueuePop - Two actions are being taken upon pop:
 *           1) Getting out the data from the Queue`s head.
 *           2) Increment the tail pointer in a cyclic way (The HEAD is
-*              incremented automaticaly by the GT) 
+*              incremented automaticaly by the GT)
 *
 * INPUTS:  N/A.
 * OUTPUT:  N/A.
@@ -469,7 +469,7 @@
 
 /********************************************************************
 * clearInBoundPostQueueInterrupt - Clears the Post queue interrupt.
-* 
+*
 * INPUTS:  N/A.
 * OUTPUT:  N/A.
 * RETURNS: true.
@@ -486,7 +486,7 @@
 *
 * INPUTS:  N/A.
 * OUTPUT:  N/A.
-* RETURNS: 
+* RETURNS:
 *********************************************************************/
 void maskInBoundPostQueueInterrupt()
 {
@@ -501,7 +501,7 @@
 /********************************************************************
 * enableInBoundPostQueueInterrupt - Enable interrupt when ever there is a new
 *                                   message from the PCI agent.
-* 
+*
 * INPUTS:  N/A.
 * OUTPUT:  N/A.
 * RETURNS:
@@ -516,11 +516,11 @@
 }
 
 /********************************************************************
-* inBoundFreeQueuePush - Two actions are being taken upon push: 
+* inBoundFreeQueuePush - Two actions are being taken upon push:
 *           1) Place the user`s data on the Queue`s head.
 *           2) Increment the haed pointer in a cyclic way (The tail is
 *              decremented automaticaly by the GT)
-* 
+*
 * INPUTS:  unsigned int data - Data to be placed in the queue.
 * OUTPUT:  N/A.
 * RETURNS: true.
@@ -558,7 +558,7 @@
 * isInBoundFreeQueueEmpty - Check if Inbound Free Queue Empty.
 *                           Can be used for acknowledging the messages
 *                           being sent by us to the PCI agent.
-* 
+*
 * INPUTS:  N/A.
 * OUTPUT:  N/A.
 * RETURNS: true if the queue is empty , otherwise false.
@@ -579,12 +579,12 @@
 }
 
 /********************************************************************
-* outBoundPostQueuePush  - Two actions are being taken upon push: 
+* outBoundPostQueuePush  - Two actions are being taken upon push:
 *           1) Place the user`s data on the Queue`s head.
 *           2) Increment the haed pointer in a cyclic way (The tail is
 *              decremented automaticaly by the GT when the Agent on the
 *              PCI have read data from the Outbound Port).
-* 
+*
 * INPUTS:  unsigned int data - Data to be placed in the queue`s head.
 * OUTPUT:  N/A.
 * RETURNS: true.
@@ -622,7 +622,7 @@
 * isOutBoundPostQueueEmpty - Check if Outbound Post Queue Empty.
 *                            Can be used for acknowledging the messages
 *                            being sent by us to the PCI agent.
-* 
+*
 * INPUTS:  N/A.
 * OUTPUT:  N/A.
 * RETURNS: true if the queue is empty , otherwise false.
@@ -643,11 +643,11 @@
 }
 
 /********************************************************************
-* outBoundFreeQueuePop - Two actions are being taken upon pop: 
+* outBoundFreeQueuePop - Two actions are being taken upon pop:
 *           1) Getting out the data from the Queue`s head.
 *           2) Increment the tail pointer in a cyclic way (The HEAD is
 *              incremented automaticaly by the GT)
-* 
+*
 * INPUTS:  N/A.
 * OUTPUT:  N/A.
 * RETURNS: Data pointed by tail.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/int-handler.S linux-2.4.20/arch/mips/galileo-boards/ev64120/int-handler.S
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/int-handler.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/int-handler.S	2002-10-29 11:18:37.000000000 +0000
@@ -21,11 +21,11 @@
 		SAVE_ALL
 		CLI
 		.set	at
-		mfc0	t0,CP0_CAUSE  
+		mfc0	t0,CP0_CAUSE
 		mfc0	t2,CP0_STATUS
 
 		and	t0,t2
-        
+
 		andi	t1,t0,STATUSF_IP4 /* int2 hardware line (timer) */
 		bnez	t1,ll_galileo_irq
 		andi	t1,t0,STATUSF_IP2 /* int0 hardware line */
@@ -42,7 +42,7 @@
 		j	spurious_interrupt
 		nop
 		END(galileo_handle_int)
-	
+
 
 		.align	5
 		.set	reorder
@@ -57,7 +57,7 @@
 		.align	5
 		.set	reorder
 ll_compare_irq:
-		li 	a0,7	
+		li 	a0,7
 		move	a1,sp
 		jal	do_IRQ
 		nop
@@ -76,7 +76,7 @@
 #if 0
 		.align	5
 		.set	reorder
-ll_pci_intB:	
+ll_pci_intB:
 		move 	a0,sp
 		jal	pci_intB
 		nop
@@ -85,14 +85,14 @@
 
 		.align	5
 		.set	reorder
-ll_pci_intC:	
+ll_pci_intC:
 		move 	a0,sp
 		jal	pci_intC
 		nop
 		j	ret_from_irq
 		nop
 #endif
-        
+
 		.align	5
 		.set	reorder
 ll_pci_intD:
@@ -101,10 +101,10 @@
 		nop
 		j	ret_from_irq
 		nop
-	
+
 		.align	5
 		.set	reorder
-ll_serial_irq:	
+ll_serial_irq:
 		li	a0,6
 		move	a1,sp
 		jal	do_IRQ
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/irq-handler.c linux-2.4.20/arch/mips/galileo-boards/ev64120/irq-handler.c
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/irq-handler.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/irq-handler.c	2002-10-29 11:18:34.000000000 +0000
@@ -33,8 +33,8 @@
  * the interrupt service routine is called.
  *
  * Inputs :
- * int_cause - The interrupt cause number. In EVB64120 two parameters 
- *             are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH. 
+ * int_cause - The interrupt cause number. In EVB64120 two parameters
+ *             are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH.
  * bit_num   - Indicates which bit number in the cause register
  * isr_ptr   - Pointer to the interrupt service routine
  *
@@ -52,7 +52,7 @@
  * Enables the IRQ on Galileo Chip
  *
  * Inputs :
- * int_cause -  The interrupt cause number. In EVB64120 two parameters 
+ * int_cause -  The interrupt cause number. In EVB64120 two parameters
  *            are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH.
  * bit_num   - Indicates which bit number in the cause register
  *
@@ -77,7 +77,7 @@
  * Disables the IRQ on Galileo Chip
  *
  * Inputs :
- * int_cause -  The interrupt cause number. In EVB64120 two parameters 
+ * int_cause -  The interrupt cause number. In EVB64120 two parameters
  *            are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH.
  * bit_num   - Indicates which bit number in the cause register
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/irq.c linux-2.4.20/arch/mips/galileo-boards/ev64120/irq.c
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/irq.c	2002-10-29 11:18:40.000000000 +0000
@@ -65,7 +65,7 @@
 /*  Duplicate interrupt handlers.  */
 /********************************************************************
  *pci_int(A/B/C/D) -
- *	
+ *
  *Calls all the handlers connected to PCI interrupt A/B/C/D
  *
  *Inputs :
@@ -175,7 +175,7 @@
 	end:no_irq_enable_disable,
 };
 
-//      ack:            no_irq_ack,                re-enable later -- SKJ  
+//      ack:            no_irq_ack,                re-enable later -- SKJ
 
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/pci_bios.c linux-2.4.20/arch/mips/galileo-boards/ev64120/pci_bios.c
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/pci_bios.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/pci_bios.c	2002-10-29 11:18:35.000000000 +0000
@@ -441,7 +441,7 @@
  * pci_range_ck -
  *
  * Check if the pci device that are trying to access does really exists
- * on the evaluation board.  
+ * on the evaluation board.
  *
  * Inputs :
  * bus - bus number (0 for PCI 0 ; 1 for PCI 1)
@@ -455,18 +455,18 @@
 	//DBG(KERN_INFO "p_r_c %d %d\n",bus,dev);
 	if (((bus == 0) || (bus == 1)) && (dev >= 6) && (dev <= 8))
 		return 0;	// Bus/Device Number OK
-	return -1;		// Bus/Device Number not OK  
+	return -1;		// Bus/Device Number not OK
 }
 
 /*
  * pciXReadConfigReg  - Read from a PCI configuration register
- *                    - Make sure the GT is configured as a master before 
+ *                    - Make sure the GT is configured as a master before
  *                      reading from another device on the PCI.
  *                   - The function takes care of Big/Little endian conversion.
  * INPUTS:   regOffset: The register offset as it apears in the GT spec (or PCI
  *                        spec)
- *           pciDevNum: The device number needs to be addressed.                
- * RETURNS: data , if the data == 0xffffffff check the master abort bit in the 
+ *           pciDevNum: The device number needs to be addressed.
+ * RETURNS: data , if the data == 0xffffffff check the master abort bit in the
  *                 cause register to make sure the data is valid
  *
  *  Configuration Address 0xCF8:
@@ -518,7 +518,7 @@
 	   to stabilize, so the READ can work.
 	 */
 	if (PCI_SLOT(device->devfn) == SELF) {	/* This board */
-		/* when configurating our own PCI 1 L-unit the access is through  
+		/* when configurating our own PCI 1 L-unit the access is through
 		   the PCI 0 interface with reg number = reg number + 0x80 */
 		DataForRegCf8 |= 0x80;
 		GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8);
@@ -538,13 +538,13 @@
 
 /*
  * pciXWriteConfigReg - Write to a PCI configuration register
- *                    - Make sure the GT is configured as a master before 
+ *                    - Make sure the GT is configured as a master before
  *                      writingto another device on the PCI.
  *                    - The function takes care of Big/Little endian conversion.
  * Inputs:   unsigned int regOffset: The register offset as it apears in the
- *           GT spec 
+ *           GT spec
  *                   (or any other PCI device spec)
- *           pciDevNum: The device number needs to be addressed.                
+ *           pciDevNum: The device number needs to be addressed.
  *
  *  Configuration Address 0xCF8:
  *
@@ -584,7 +584,7 @@
 	   to stabilize, so the WRITE can work.
 	 */
 	if (PCI_SLOT(device->devfn) == SELF) {	/* This board */
-		/* when configurating our own PCI 1 L-unit the access is through  
+		/* when configurating our own PCI 1 L-unit the access is through
 		   the PCI 0 interface with reg number = reg number + 0x80 */
 		DataForRegCf8 |= 0x80;
 		GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8);
@@ -906,7 +906,7 @@
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-			    unsigned long size)
+			    unsigned long size, unsigned long align)
 {
 	struct pci_dev *dev = data;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/promcon.c linux-2.4.20/arch/mips/galileo-boards/ev64120/promcon.c
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/promcon.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/promcon.c	2002-10-29 11:18:40.000000000 +0000
@@ -5,7 +5,7 @@
  * Copyright (c) 1999 Ulf Carlsson
  *
  * Derived from DECstation promcon.c
- * Copyright (c) 1998 Harald Koerfgen 
+ * Copyright (c) 1998 Harald Koerfgen
  */
 #include <linux/tty.h>
 #include <linux/major.h>
@@ -51,8 +51,8 @@
 
 void gal_serial_console_init(void)
 {
-	//  serial_init(); 
-	//serial_set(115200); 
+	//  serial_init();
+	//serial_set(115200);
 
 	register_console(&sercons);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/serialGT.c linux-2.4.20/arch/mips/galileo-boards/ev64120/serialGT.c
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/serialGT.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/serialGT.c	2002-10-29 11:18:48.000000000 +0000
@@ -3,7 +3,7 @@
  *
  * BRIEF MODULE DESCRIPTION
  *  Low Level Serial Port control for use
- *  with the Galileo EVB64120A MIPS eval board and 
+ *  with the Galileo EVB64120A MIPS eval board and
  *  its on board two channel 16552 Uart.
  *
  * Copyright (C) 2000 RidgeRun, Inc.
@@ -139,7 +139,7 @@
 
 #if 0
 	/*
-	 * Set baud rate 
+	 * Set baud rate
 	 */
 	outreg(channel, LCR, LCR_DLAB | sav_lcr);
 	//  outreg(DLL,(XTAL/(16*2*(baud))-2));
@@ -149,7 +149,7 @@
 #else
 	/*
 	 * Note: Set baud rate, hardcoded here for rate of 115200
-	 * since became unsure of above "buad rate" algorithm (??). 
+	 * since became unsure of above "buad rate" algorithm (??).
 	 */
 	outreg(channel, LCR, 0x83);
 	outreg(channel, DLM, 0x00);	// See note above
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev64120/setup.c linux-2.4.20/arch/mips/galileo-boards/ev64120/setup.c
--- linux-2.4.19/arch/mips/galileo-boards/ev64120/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev64120/setup.c	2002-10-29 11:18:30.000000000 +0000
@@ -61,7 +61,7 @@
 extern void galileo_machine_restart(char *command);
 extern void galileo_machine_halt(void);
 extern void galileo_machine_power_off(void);
-/* 
+/*
  *This structure holds pointers to the pci configuration space accesses
  *and interrupts allocating routine for device over the PCI
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev96100/init.c linux-2.4.20/arch/mips/galileo-boards/ev96100/init.c
--- linux-2.4.19/arch/mips/galileo-boards/ev96100/init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev96100/init.c	2002-10-29 11:18:37.000000000 +0000
@@ -3,7 +3,7 @@
  * Author: MontaVista Software, Inc.
  *         	ppopov@mvista.com or source@mvista.com
  *
- * This file was derived from Carsten Langgaard's 
+ * This file was derived from Carsten Langgaard's
  * arch/mips/mips-boards/generic/generic.c
  *
  * Carsten Langgaard, carstenl@mips.com
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev96100/irq.c linux-2.4.20/arch/mips/galileo-boards/ev96100/irq.c
--- linux-2.4.19/arch/mips/galileo-boards/ev96100/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev96100/irq.c	2002-10-29 11:18:39.000000000 +0000
@@ -3,7 +3,7 @@
  * Author: MontaVista Software, Inc.
  *         	ppopov@mvista.com or source@mvista.com
  *
- * This file was derived from Carsten Langgaard's 
+ * This file was derived from Carsten Langgaard's
  * arch/mips/mips-boards/atlas/atlas_int.c.
  *
  * Carsten Langgaard, carstenl@mips.com
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev96100/pci_fixups.c linux-2.4.20/arch/mips/galileo-boards/ev96100/pci_fixups.c
--- linux-2.4.19/arch/mips/galileo-boards/ev96100/pci_fixups.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev96100/pci_fixups.c	2002-10-29 11:18:35.000000000 +0000
@@ -72,19 +72,19 @@
 		pci_read_config_dword(dev, PCI_SUBSYSTEM_VENDOR_ID, &vendor);
 
 #ifdef DEBUG
-		printk("devfn %x, slot %d devid %x\n", 
+		printk("devfn %x, slot %d devid %x\n",
 				dev->devfn, slot, gt_devid);
 #endif
 
 		/* fixup irq line based on slot # */
 		if (slot == 8) {
 			dev->irq = 5;
-			pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 
+			pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
 					dev->irq);
 		}
 		else if (slot == 9) {
 			dev->irq = 2;
-			pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 
+			pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
 					dev->irq);
 		}
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev96100/pci_ops.c linux-2.4.20/arch/mips/galileo-boards/ev96100/pci_ops.c
--- linux-2.4.19/arch/mips/galileo-boards/ev96100/pci_ops.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev96100/pci_ops.c	2002-10-29 11:18:31.000000000 +0000
@@ -7,7 +7,7 @@
  * Author: MontaVista Software, Inc.
  *         	ppopov@mvista.com or source@mvista.com
  *
- * This file was derived from Carsten Langgaard's 
+ * This file was derived from Carsten Langgaard's
  * arch/mips/mips-boards/generic/pci.c
  *
  * Carsten Langgaard, carstenl@mips.com
@@ -63,13 +63,13 @@
 #define GT_PCI_IO_BASE     0x10000000
 #define GT_PCI_IO_SIZE     0x02000000
 static struct resource pci_io_resource = {
-	"io pci IO space", 
+	"io pci IO space",
 	0x10000000,
 	0x10000000 + 0x02000000,
 	IORESOURCE_IO};
 
 static struct resource pci_mem_resource = {
-	"ext pci memory space", 
+	"ext pci memory space",
 	0x12000000,
 	0x12000000 + 0x02000000,
 	IORESOURCE_MEM};
@@ -95,11 +95,11 @@
         }
 
 	/* Clear cause register bits */
-	GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | 
+	GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
 	                             GT_INTRCAUSE_TARABORT0_BIT));
 
 	/* Setup address */
-	GT_WRITE(GT_PCI0_CFGADDR_OFS,  
+	GT_WRITE(GT_PCI0_CFGADDR_OFS,
 		 (bus         << GT_PCI0_CFGADDR_BUSNUM_SHF)   |
 		 (dev_fn      << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
 		 ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF)   |
@@ -112,7 +112,7 @@
 		*data = le32_to_cpu(*data);
 		}
 		GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
-	} 
+	}
         else {
 		GT_READ(GT_PCI0_CFGDATA_OFS, *data);
 		if (dev_fn != 0) {
@@ -131,7 +131,7 @@
 	        /* Error occured */
 
 	        /* Clear bits */
-	        GT_WRITE( GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | 
+	        GT_WRITE( GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
 					      GT_INTRCAUSE_TARABORT0_BIT) );
 
 		if (access_type == PCI_ACCESS_READ) {
@@ -158,7 +158,7 @@
 	}
 
 	*val = (data >> ((where & 3) << 3)) & 0xff;
-        DBG("cfg read byte: bus %d dev_fn %x where %x: val %x\n", 
+        DBG("cfg read byte: bus %d dev_fn %x where %x: val %x\n",
                 dev->bus->number, dev->devfn, where, *val);
 
 	return PCIBIOS_SUCCESSFUL;
@@ -179,7 +179,7 @@
 	}
 
 	*val = (data >> ((where & 3) << 3)) & 0xffff;
-        DBG("cfg read word: bus %d dev_fn %x where %x: val %x\n", 
+        DBG("cfg read word: bus %d dev_fn %x where %x: val %x\n",
                 dev->bus->number, dev->devfn, where, *val);
 
 	return PCIBIOS_SUCCESSFUL;
@@ -192,14 +192,14 @@
 
 	if (where & 3)
 		return PCIBIOS_BAD_REGISTER_NUMBER;
-	
+
 	if (gt96100_config_access(PCI_ACCESS_READ, dev, where, &data)) {
 		*val = 0xffffffff;
 		return -1;
 	}
 
 	*val = data;
-        DBG("cfg read dword: bus %d dev_fn %x where %x: val %x\n", 
+        DBG("cfg read dword: bus %d dev_fn %x where %x: val %x\n",
                 dev->bus->number, dev->devfn, where, *val);
 
 	return PCIBIOS_SUCCESSFUL;
@@ -210,13 +210,13 @@
 write_config_byte (struct pci_dev *dev, int where, u8 val)
 {
 	u32 data = 0;
-       
+
 	if (gt96100_config_access(PCI_ACCESS_READ, dev, where, &data))
 		return -1;
 
 	data = (data & ~(0xff << ((where & 3) << 3))) |
 	       (val << ((where & 3) << 3));
-        DBG("cfg write byte: bus %d dev_fn %x where %x: val %x\n", 
+        DBG("cfg write byte: bus %d dev_fn %x where %x: val %x\n",
                 dev->bus->number, dev->devfn, where, val);
 
 	if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &data))
@@ -232,13 +232,13 @@
 
 	if (where & 1)
 		return PCIBIOS_BAD_REGISTER_NUMBER;
-       
+
         if (gt96100_config_access(PCI_ACCESS_READ, dev, where, &data))
 	       return -1;
 
-	data = (data & ~(0xffff << ((where & 3) << 3))) | 
+	data = (data & ~(0xffff << ((where & 3) << 3))) |
 	       (val << ((where & 3) << 3));
-        DBG("cfg write word: bus %d dev_fn %x where %x: val %x\n", 
+        DBG("cfg write word: bus %d dev_fn %x where %x: val %x\n",
                 dev->bus->number, dev->devfn, where, val);
 
 	if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &data))
@@ -256,7 +256,7 @@
 
 	if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &val))
 	       return -1;
-        DBG("cfg write dword: bus %d dev_fn %x where %x: val %x\n", 
+        DBG("cfg write dword: bus %d dev_fn %x where %x: val %x\n",
                 dev->bus->number, dev->devfn, where, val);
 
 	return PCIBIOS_SUCCESSFUL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev96100/setup.c linux-2.4.20/arch/mips/galileo-boards/ev96100/setup.c
--- linux-2.4.19/arch/mips/galileo-boards/ev96100/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev96100/setup.c	2002-10-29 11:18:50.000000000 +0000
@@ -7,7 +7,7 @@
  * Author: MontaVista Software, Inc.
  *         	ppopov@mvista.com or source@mvista.com
  *
- * This file was derived from Carsten Langgaard's 
+ * This file was derived from Carsten Langgaard's
  * arch/mips/mips-boards/atlas/atlas_setup.c.
  *
  * Carsten Langgaard, carstenl@mips.com
@@ -52,8 +52,6 @@
 #include <asm/galileo-boards/ev96100int.h>
 
 
-void (*__wbflush) (void);
-
 #if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE)
 extern void console_setup(char *, int *);
 char serial_console[20];
@@ -65,11 +63,6 @@
 extern struct rtc_ops no_rtc_ops;
 extern struct resource ioport_resource;
 
-static void rm7000_wbflush(void)
-{
-	 __asm__ __volatile__ ("sync");
-}
-
 unsigned char mac_0_1[12];
 
 
@@ -83,7 +76,6 @@
 	char *argptr;
 
 	clear_cp0_status(ST0_FR);
-        __wbflush = rm7000_wbflush;
 
         if (config & 0x8) {
             printk("Secondary cache is enabled\n");
@@ -144,7 +136,7 @@
 		argptr = prom_getcmdline();
 		strcat(argptr, " console=ttyS0,115200");
 	}
-#endif	  
+#endif
 
 	rtc_ops = &no_rtc_ops;
 	mips_reboot_setup();
@@ -157,15 +149,15 @@
 #endif
 
 
-	/* 
-	 * setup gt controller master bit so we can do config cycles 
+	/*
+	 * setup gt controller master bit so we can do config cycles
 	 */
 
 	/* Clear cause register bits */
-	GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | 
+	GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
 	                             GT_INTRCAUSE_TARABORT0_BIT));
 	/* Setup address */
-	GT_WRITE(GT_PCI0_CFGADDR_OFS,  
+	GT_WRITE(GT_PCI0_CFGADDR_OFS,
 		 (0      << GT_PCI0_CFGADDR_BUSNUM_SHF)   |
 		 (0      << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
 		 ((PCI_COMMAND / 4) << GT_PCI0_CFGADDR_REGNUM_SHF)   |
@@ -174,9 +166,9 @@
 	udelay(2);
 	tmp = le32_to_cpu(*(volatile u32 *)(MIPS_GT_BASE+GT_PCI0_CFGDATA_OFS));
 
-	tmp |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | 
+	tmp |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
 		PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
-	GT_WRITE(GT_PCI0_CFGADDR_OFS,  
+	GT_WRITE(GT_PCI0_CFGADDR_OFS,
 		 (0      << GT_PCI0_CFGADDR_BUSNUM_SHF)   |
 		 (0      << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
 		 ((PCI_COMMAND / 4) << GT_PCI0_CFGADDR_REGNUM_SHF)   |
@@ -185,7 +177,7 @@
 	*(volatile u32 *)(MIPS_GT_BASE+GT_PCI0_CFGDATA_OFS) = cpu_to_le32(tmp);
 
 	/* Setup address */
-	GT_WRITE(GT_PCI0_CFGADDR_OFS,  
+	GT_WRITE(GT_PCI0_CFGADDR_OFS,
 		 (0      << GT_PCI0_CFGADDR_BUSNUM_SHF)   |
 		 (0      << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
 		 ((PCI_COMMAND / 4) << GT_PCI0_CFGADDR_REGNUM_SHF)   |
@@ -195,12 +187,12 @@
 	tmp = le32_to_cpu(*(volatile u32 *)(MIPS_GT_BASE+GT_PCI0_CFGDATA_OFS));
 }
 
-unsigned short get_gt_devid() 
+unsigned short get_gt_devid()
 {
 	u32 gt_devid;
 
 	/* Figure out if this is a gt96100 or gt96100A */
-	GT_WRITE(GT_PCI0_CFGADDR_OFS,  
+	GT_WRITE(GT_PCI0_CFGADDR_OFS,
 		 (0      << GT_PCI0_CFGADDR_BUSNUM_SHF)   |
 		 (0      << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
 		 ((PCI_VENDOR_ID / 4) << GT_PCI0_CFGADDR_REGNUM_SHF)   |
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/ev96100/time.c linux-2.4.20/arch/mips/galileo-boards/ev96100/time.c
--- linux-2.4.19/arch/mips/galileo-boards/ev96100/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/ev96100/time.c	2002-10-29 11:18:40.000000000 +0000
@@ -7,7 +7,7 @@
  * Author: MontaVista Software, Inc.
  *         	ppopov@mvista.com or source@mvista.com
  *
- * This file was derived from Carsten Langgaard's 
+ * This file was derived from Carsten Langgaard's
  * arch/mips/mips-boards/atlas/atlas_rtc.c.
  *
  * Carsten Langgaard, carstenl@mips.com
@@ -67,9 +67,9 @@
 
 
 
-/* 
+/*
  * Figure out the r4k offset, the amount to increment the compare
- * register for each time tick. 
+ * register for each time tick.
  * Use the RTC to calculate offset.
  */
 static unsigned long __init cal_r4koff(void)
@@ -104,10 +104,10 @@
 
 	r4k_offset = cal_r4koff();
 
-	est_freq = 2*r4k_offset*HZ;	
+	est_freq = 2*r4k_offset*HZ;
 	est_freq += 5000;    /* round */
 	est_freq -= est_freq%10000;
-	printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, 
+	printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
 	       (est_freq%1000000)*100/1000000);
 	r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
 
@@ -184,7 +184,7 @@
 		 "r" (quotient));
 
 	/*
- 	 * Due to possible jiffies inconsistencies, we need to check 
+ 	 * Due to possible jiffies inconsistencies, we need to check
 	 * the result so that we'll get a timer that is monotonic.
 	 */
 	if (res >= USECS_PER_JIFFY)
@@ -260,7 +260,7 @@
 		r4k_cur += r4k_offset;
 		ack_r4ktimer(r4k_cur);
 
-	} while (((unsigned long)read_32bit_cp0_register(CP0_COUNT) 
+	} while (((unsigned long)read_32bit_cp0_register(CP0_COUNT)
                     - r4k_cur) < 0x7fffffff);
 	return;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/generic/Makefile linux-2.4.20/arch/mips/galileo-boards/generic/Makefile
--- linux-2.4.19/arch/mips/galileo-boards/generic/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/generic/Makefile	2002-10-29 11:18:47.000000000 +0000
@@ -7,12 +7,12 @@
 # This program is free software; you can distribute it and/or modify it
 # under the terms of the GNU General Public License (Version 2) as
 # published by the Free Software Foundation.
-# 
+#
 # This program is distributed in the hope 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.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/galileo-boards/generic/reset.c linux-2.4.20/arch/mips/galileo-boards/generic/reset.c
--- linux-2.4.19/arch/mips/galileo-boards/generic/reset.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/galileo-boards/generic/reset.c	2002-10-29 11:18:48.000000000 +0000
@@ -6,7 +6,7 @@
  * Author: MontaVista Software, Inc.
  *         	ppopov@mvista.com or source@mvista.com
  *
- * This file was derived from Carsten Langgaard's 
+ * This file was derived from Carsten Langgaard's
  * arch/mips/mips-boards/generic/reset.c
  *
  * Carsten Langgaard, carstenl@mips.com
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/gt64120/common/pci.c linux-2.4.20/arch/mips/gt64120/common/pci.c
--- linux-2.4.19/arch/mips/gt64120/common/pci.c	2001-09-09 17:43:01.000000000 +0000
+++ linux-2.4.20/arch/mips/gt64120/common/pci.c	2002-10-29 11:18:40.000000000 +0000
@@ -886,7 +886,7 @@
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-			    unsigned long size)
+			    unsigned long size, unsigned long align)
 {
 	struct pci_dev *dev = data;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/Makefile linux-2.4.20/arch/mips/kernel/Makefile
--- linux-2.4.19/arch/mips/kernel/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/Makefile	2002-10-29 11:18:39.000000000 +0000
@@ -12,13 +12,12 @@
 
 O_TARGET := kernel.o
 
-export-objs			= irq.o pci-dma.o setup.o smp.o mips_ksyms.o \
-				  old-irq.o
+export-objs	= irq.o pci-dma.o setup.o smp.o mips_ksyms.o old-irq.o
+
+obj-y		+= branch.o cpu-probe.o process.o signal.o entry.o traps.o \
+		   ptrace.o vm86.o ioport.o reset.o semaphore.o setup.o \
+		   syscall.o sysmips.o ipc.o scall_o32.o unaligned.o
 
-obj-y				+= branch.o process.o signal.o entry.o \
-				   traps.o ptrace.o vm86.o ioport.o reset.o \
-				   semaphore.o setup.o syscall.o sysmips.o \
-				   ipc.o scall_o32.o unaligned.o
 obj-$(CONFIG_MODULES)		+= mips_ksyms.o
 
 obj-$(CONFIG_CPU_R3000)		+= r2300_fpu.o r2300_switch.o
@@ -54,14 +53,14 @@
 
 obj-$(CONFIG_BINFMT_IRIX)	+= irixelf.o irixioctl.o irixsig.o sysirix.o \
 				   irixinv.o
-obj-$(CONFIG_REMOTE_DEBUG)	+= gdb-low.o gdb-stub.o 
+obj-$(CONFIG_REMOTE_DEBUG)	+= gdb-low.o gdb-stub.o
 obj-$(CONFIG_PROC_FS)		+= proc.o
 
 obj-$(CONFIG_NEW_PCI)		+= pci.o
+obj-$(CONFIG_PCI_AUTO)		+= pci_auto.o
 ifndef CONFIG_MAPPED_PCI_IO
 obj-y				+= pci-dma.o
 endif
-obj-$(CONFIG_PCI_AUTO)		+= pci_auto.o
 
 entry.o: entry.S
 head.o: head.S
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/cpu-probe.c linux-2.4.20/arch/mips/kernel/cpu-probe.c
--- linux-2.4.19/arch/mips/kernel/cpu-probe.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/cpu-probe.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,489 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <asm/bugs.h>
+#include <asm/cpu.h>
+#include <asm/mipsregs.h>
+
+/*
+ * Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
+ * the implementation of the "wait" feature differs between CPU families. This
+ * points to the function that implements CPU specific wait.
+ * The wait instruction stops the pipeline and reduces the power consumption of
+ * the CPU very much.
+ */
+void (*cpu_wait)(void) = NULL;
+
+static void r3081_wait(void)
+{
+	unsigned long cfg = read_32bit_cp0_register(CP0_CONF);
+	write_32bit_cp0_register(CP0_CONF, cfg|CONF_HALT);
+}
+
+static void r39xx_wait(void)
+{
+	unsigned long cfg = read_32bit_cp0_register(CP0_CONF);
+	write_32bit_cp0_register(CP0_CONF, cfg|TX39_CONF_HALT);
+}
+
+static void r4k_wait(void)
+{
+	__asm__(".set\tmips3\n\t"
+		"wait\n\t"
+		".set\tmips0");
+}
+
+void au1k_wait(void)
+{
+#ifdef CONFIG_PM
+	/* using the wait instruction makes CP0 counter unusable */
+	__asm__(".set\tmips3\n\t"
+		"wait\n\t"
+		"nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" ".set\tmips0");
+#else
+	__asm__("nop\n\t" "nop\n\t");
+#endif
+}
+
+static inline void check_wait(void)
+{
+	printk("Checking for 'wait' instruction... ");
+	switch(mips_cpu.cputype) {
+	case CPU_R3081:
+	case CPU_R3081E:
+		cpu_wait = r3081_wait;
+		printk(" available.\n");
+		break;
+	case CPU_TX3927:
+	case CPU_TX39XX:
+		cpu_wait = r39xx_wait;
+		printk(" available.\n");
+		break;
+	case CPU_R4200:
+/*	case CPU_R4300: */
+	case CPU_R4600:
+	case CPU_R4640:
+	case CPU_R4650:
+	case CPU_R4700:
+	case CPU_R5000:
+	case CPU_NEVADA:
+	case CPU_RM7000:
+	case CPU_TX49XX:
+	case CPU_4KC:
+	case CPU_4KEC:
+	case CPU_4KSC:
+	case CPU_5KC:
+/*	case CPU_20KC:*/
+		cpu_wait = r4k_wait;
+		printk(" available.\n");
+		break;
+	case CPU_AU1000:
+	case CPU_AU1100:
+	case CPU_AU1500:
+		cpu_wait = au1k_wait;
+		printk(" available.\n");
+		break;
+	default:
+		printk(" unavailable.\n");
+		break;
+	}
+}
+
+void __init check_bugs(void)
+{
+	check_wait();
+}
+
+/*
+ * Probe whether cpu has config register by trying to play with
+ * alternate cache bit and see whether it matters.
+ * It's used by cpu_probe to distinguish between R3000A and R3081.
+ */
+static inline int cpu_has_confreg(void)
+{
+#ifdef CONFIG_CPU_R3000
+	extern unsigned long r3k_cache_size(unsigned long);
+	unsigned long size1, size2;
+	unsigned long cfg = read_32bit_cp0_register(CP0_CONF);
+
+	size1 = r3k_cache_size(ST0_ISC);
+	write_32bit_cp0_register(CP0_CONF, cfg^CONF_AC);
+	size2 = r3k_cache_size(ST0_ISC);
+	write_32bit_cp0_register(CP0_CONF, cfg);
+	return size1 != size2;
+#else
+	return 0;
+#endif
+}
+
+/*
+ * Get the FPU Implementation/Revision.
+ */
+static inline unsigned long cpu_get_fpu_id(void)
+{
+	unsigned long tmp, fpu_id;
+
+	tmp = read_32bit_cp0_register(CP0_STATUS);
+	__enable_fpu();
+	fpu_id = read_32bit_cp1_register(CP1_REVISION);
+	write_32bit_cp0_register(CP0_STATUS, tmp);
+	return fpu_id;
+}
+
+/*
+ * Check the CPU has an FPU the official way.
+ */
+static inline int cpu_has_fpu(void)
+{
+	return ((cpu_get_fpu_id() & 0xff00) != FPIR_IMP_NONE);
+}
+
+/* declaration of the global struct */
+struct mips_cpu mips_cpu = {
+    processor_id:	PRID_IMP_UNKNOWN,
+    fpu_id:		FPIR_IMP_NONE,
+    cputype:		CPU_UNKNOWN
+};
+
+/* Shortcut for assembler access to mips_cpu.options */
+int *cpuoptions = &mips_cpu.options;
+
+#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4KTLB \
+		| MIPS_CPU_COUNTER | MIPS_CPU_CACHE_CDEX)
+
+__init void cpu_probe(void)
+{
+#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
+	unsigned long config0 = read_32bit_cp0_register(CP0_CONFIG);
+	unsigned long config1;
+
+        if (config0 & (1 << 31)) {
+		/* MIPS32 or MIPS64 compliant CPU. Read Config 1 register. */
+		mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+			MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | MIPS_CPU_DIVEC;
+		config1 = read_mips32_cp0_config1();
+		if (config1 & (1 << 3))
+			mips_cpu.options |= MIPS_CPU_WATCH;
+		if (config1 & (1 << 2))
+			mips_cpu.options |= MIPS_CPU_MIPS16;
+		if (config1 & (1 << 1))
+			mips_cpu.options |= MIPS_CPU_EJTAG;
+		if (config1 & 1) {
+			mips_cpu.options |= MIPS_CPU_FPU;
+#if defined(CONFIG_CPU_MIPS64)
+			mips_cpu.options |= MIPS_CPU_32FPR;
+#endif
+		}
+		mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT;
+	}
+#endif
+	mips_cpu.processor_id = read_32bit_cp0_register(CP0_PRID);
+	switch (mips_cpu.processor_id & 0xff0000) {
+	case PRID_COMP_LEGACY:
+		switch (mips_cpu.processor_id & 0xff00) {
+		case PRID_IMP_R2000:
+			mips_cpu.cputype = CPU_R2000;
+			mips_cpu.isa_level = MIPS_CPU_ISA_I;
+			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_NOFPUEX;
+			if (cpu_has_fpu())
+				mips_cpu.options |= MIPS_CPU_FPU;
+			mips_cpu.tlbsize = 64;
+			break;
+		case PRID_IMP_R3000:
+			if ((mips_cpu.processor_id & 0xff) == PRID_REV_R3000A)
+				if (cpu_has_confreg())
+					mips_cpu.cputype = CPU_R3081E;
+				else
+					mips_cpu.cputype = CPU_R3000A;
+			else
+				mips_cpu.cputype = CPU_R3000;
+			mips_cpu.isa_level = MIPS_CPU_ISA_I;
+			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_NOFPUEX;
+			if (cpu_has_fpu())
+				mips_cpu.options |= MIPS_CPU_FPU;
+			mips_cpu.tlbsize = 64;
+			break;
+		case PRID_IMP_R4000:
+			if ((mips_cpu.processor_id & 0xff) == PRID_REV_R4400)
+				mips_cpu.cputype = CPU_R4400SC;
+			else
+				mips_cpu.cputype = CPU_R4000SC;
+			mips_cpu.isa_level = MIPS_CPU_ISA_III;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+			                   MIPS_CPU_32FPR | MIPS_CPU_WATCH |
+			                   MIPS_CPU_VCE;
+			mips_cpu.tlbsize = 48;
+			break;
+                case PRID_IMP_VR41XX:
+			switch (mips_cpu.processor_id & 0xf0) {
+#ifndef CONFIG_VR4181
+			case PRID_REV_VR4111:
+				mips_cpu.cputype = CPU_VR4111;
+				break;
+#else
+			case PRID_REV_VR4181:
+				mips_cpu.cputype = CPU_VR4181;
+				break;
+#endif
+			case PRID_REV_VR4121:
+				mips_cpu.cputype = CPU_VR4121;
+				break;
+			case PRID_REV_VR4122:
+				if ((mips_cpu.processor_id & 0xf) < 0x3)
+					mips_cpu.cputype = CPU_VR4122;
+				else
+					mips_cpu.cputype = CPU_VR4181A;
+				break;
+			case PRID_REV_VR4131:
+				mips_cpu.cputype = CPU_VR4131;
+				mips_cpu.icache.ways = 2;
+				mips_cpu.dcache.ways = 2;
+				break;
+			default:
+				printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n");
+				mips_cpu.cputype = CPU_VR41XX;
+				break;
+			}
+                        mips_cpu.isa_level = MIPS_CPU_ISA_III;
+                        mips_cpu.options = R4K_OPTS;
+                        mips_cpu.tlbsize = 32;
+                        break;
+		case PRID_IMP_R4300:
+			mips_cpu.cputype = CPU_R4300;
+			mips_cpu.isa_level = MIPS_CPU_ISA_III;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+					   MIPS_CPU_32FPR;
+			mips_cpu.tlbsize = 32;
+			break;
+		case PRID_IMP_R4600:
+			mips_cpu.cputype = CPU_R4600;
+			mips_cpu.isa_level = MIPS_CPU_ISA_III;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
+			mips_cpu.tlbsize = 48;
+			break;
+		#if 0
+ 		case PRID_IMP_R4650:
+			/*
+			 * This processor doesn't have an MMU, so it's not
+			 * "real easy" to run Linux on it. It is left purely
+			 * for documentation.  Commented out because it shares
+			 * it's c0_prid id number with the TX3900.
+			 */
+	 		mips_cpu.cputype = CPU_R4650;
+		 	mips_cpu.isa_level = MIPS_CPU_ISA_III;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
+		        mips_cpu.tlbsize = 48;
+			break;
+		#endif
+		case PRID_IMP_TX39:
+			mips_cpu.isa_level = MIPS_CPU_ISA_I;
+			mips_cpu.options = MIPS_CPU_TLB;
+
+			if ((mips_cpu.processor_id & 0xf0) ==
+			    (PRID_REV_TX3927 & 0xf0)) {
+				mips_cpu.cputype = CPU_TX3927;
+				mips_cpu.tlbsize = 64;
+				mips_cpu.icache.ways = 2;
+				mips_cpu.dcache.ways = 2;
+			} else {
+				switch (mips_cpu.processor_id & 0xff) {
+				case PRID_REV_TX3912:
+					mips_cpu.cputype = CPU_TX3912;
+					mips_cpu.tlbsize = 32;
+					break;
+				case PRID_REV_TX3922:
+					mips_cpu.cputype = CPU_TX3922;
+					mips_cpu.tlbsize = 64;
+					break;
+				default:
+					mips_cpu.cputype = CPU_UNKNOWN;
+					break;
+				}
+			}
+			break;
+		case PRID_IMP_R4700:
+			mips_cpu.cputype = CPU_R4700;
+			mips_cpu.isa_level = MIPS_CPU_ISA_III;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+			                   MIPS_CPU_32FPR;
+			mips_cpu.tlbsize = 48;
+			break;
+		case PRID_IMP_TX49:
+			mips_cpu.cputype = CPU_TX49XX;
+			mips_cpu.isa_level = MIPS_CPU_ISA_III;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+			                   MIPS_CPU_32FPR;
+			mips_cpu.tlbsize = 48;
+			mips_cpu.icache.ways = 4;
+			mips_cpu.dcache.ways = 4;
+			break;
+		case PRID_IMP_R5000:
+			mips_cpu.cputype = CPU_R5000;
+			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+			                   MIPS_CPU_32FPR;
+			mips_cpu.tlbsize = 48;
+			break;
+		case PRID_IMP_R5432:
+			mips_cpu.cputype = CPU_R5432;
+			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+			                   MIPS_CPU_32FPR | MIPS_CPU_WATCH;
+			mips_cpu.tlbsize = 48;
+			break;
+		case PRID_IMP_R5500:
+			mips_cpu.cputype = CPU_R5500;
+			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+			                   MIPS_CPU_32FPR | MIPS_CPU_WATCH;
+			mips_cpu.tlbsize = 48;
+			break;
+		case PRID_IMP_NEVADA:
+			mips_cpu.cputype = CPU_NEVADA;
+			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+			                   MIPS_CPU_32FPR | MIPS_CPU_DIVEC;
+			mips_cpu.tlbsize = 48;
+			mips_cpu.icache.ways = 2;
+			mips_cpu.dcache.ways = 2;
+			break;
+		case PRID_IMP_R6000:
+			mips_cpu.cputype = CPU_R6000;
+			mips_cpu.isa_level = MIPS_CPU_ISA_II;
+			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU;
+			mips_cpu.tlbsize = 32;
+			break;
+		case PRID_IMP_R6000A:
+			mips_cpu.cputype = CPU_R6000A;
+			mips_cpu.isa_level = MIPS_CPU_ISA_II;
+			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU;
+			mips_cpu.tlbsize = 32;
+			break;
+		case PRID_IMP_RM7000:
+			mips_cpu.cputype = CPU_RM7000;
+			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+			                   MIPS_CPU_32FPR;
+			/*
+			 * Undocumented RM7000:  Bit 29 in the info register of
+			 * the RM7000 v2.0 indicates if the TLB has 48 or 64
+			 * entries.
+			 *
+			 * 29      1 =>    64 entry JTLB
+			 *         0 =>    48 entry JTLB
+			 */
+			mips_cpu.tlbsize = (get_info() & (1 << 29)) ? 64 : 48;
+			break;
+		case PRID_IMP_R8000:
+			mips_cpu.cputype = CPU_R8000;
+			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+				           MIPS_CPU_FPU | MIPS_CPU_32FPR;
+			mips_cpu.tlbsize = 384;      /* has weird TLB: 3-way x 128 */
+			break;
+		case PRID_IMP_R10000:
+			mips_cpu.cputype = CPU_R10000;
+			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+				           MIPS_CPU_FPU | MIPS_CPU_32FPR |
+				           MIPS_CPU_COUNTER | MIPS_CPU_WATCH;
+			mips_cpu.tlbsize = 64;
+			break;
+		case PRID_IMP_R12000:
+			mips_cpu.cputype = CPU_R12000;
+			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+				           MIPS_CPU_FPU | MIPS_CPU_32FPR |
+				           MIPS_CPU_COUNTER | MIPS_CPU_WATCH;
+			mips_cpu.tlbsize = 64;
+			break;
+		default:
+			mips_cpu.cputype = CPU_UNKNOWN;
+			break;
+		}
+		break;
+#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
+	case PRID_COMP_MIPS:
+		switch (mips_cpu.processor_id & 0xff00) {
+		case PRID_IMP_4KC:
+			mips_cpu.cputype = CPU_4KC;
+			mips_cpu.isa_level = MIPS_CPU_ISA_M32;
+			break;
+		case PRID_IMP_4KEC:
+			mips_cpu.cputype = CPU_4KEC;
+			mips_cpu.isa_level = MIPS_CPU_ISA_M32;
+			break;
+		case PRID_IMP_4KSC:
+			mips_cpu.cputype = CPU_4KSC;
+			mips_cpu.isa_level = MIPS_CPU_ISA_M32;
+			break;
+		case PRID_IMP_5KC:
+			mips_cpu.cputype = CPU_5KC;
+			mips_cpu.isa_level = MIPS_CPU_ISA_M64;
+			break;
+		case PRID_IMP_20KC:
+			mips_cpu.cputype = CPU_20KC;
+			mips_cpu.isa_level = MIPS_CPU_ISA_M64;
+			break;
+		default:
+			mips_cpu.cputype = CPU_UNKNOWN;
+			break;
+		}
+		break;
+	case PRID_COMP_ALCHEMY:
+		switch (mips_cpu.processor_id & 0xff00) {
+		case PRID_IMP_AU1_REV1:
+		case PRID_IMP_AU1_REV2:
+			switch ((mips_cpu.processor_id >> 24) & 0xff) {
+			case 0:
+ 				mips_cpu.cputype = CPU_AU1000;
+				break;
+			case 1:
+				mips_cpu.cputype = CPU_AU1500;
+				break;
+			case 2:
+				mips_cpu.cputype = CPU_AU1100;
+				break;
+			default:
+				panic("Unknown Au Core!");
+				break;
+			}
+			mips_cpu.isa_level = MIPS_CPU_ISA_M32;
+ 			break;
+		default:
+			mips_cpu.cputype = CPU_UNKNOWN;
+			break;
+		}
+		break;
+#endif /* CONFIG_CPU_MIPS32 */
+	case PRID_COMP_SIBYTE:
+		switch (mips_cpu.processor_id & 0xff00) {
+		case PRID_IMP_SB1:
+			mips_cpu.cputype = CPU_SB1;
+			mips_cpu.isa_level = MIPS_CPU_ISA_M64;
+			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+			                   MIPS_CPU_COUNTER | MIPS_CPU_DIVEC |
+			                   MIPS_CPU_MCHECK;
+#ifndef CONFIG_SB1_PASS_1_WORKAROUNDS
+			/* FPU in pass1 is known to have issues. */
+			mips_cpu.options |= MIPS_CPU_FPU;
+#endif
+			break;
+		default:
+			mips_cpu.cputype = CPU_UNKNOWN;
+			break;
+		}
+		break;
+	default:
+		mips_cpu.cputype = CPU_UNKNOWN;
+	}
+	if (mips_cpu.options & MIPS_CPU_FPU)
+		mips_cpu.fpu_id = cpu_get_fpu_id();
+}
+
+__init void cpu_report(void)
+{
+	printk("CPU revision is: %08x\n", mips_cpu.processor_id);
+	if (mips_cpu.options & MIPS_CPU_FPU)
+		printk("FPU revision is: %08x\n", mips_cpu.fpu_id);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/entry.S linux-2.4.20/arch/mips/kernel/entry.S
--- linux-2.4.19/arch/mips/kernel/entry.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/entry.S	2002-10-29 11:18:34.000000000 +0000
@@ -26,48 +26,29 @@
 #include <asm/unistd.h>
 #include <asm/isadep.h>
 
-/* This duplicates the definition from <linux/sched.h> */
-#define PT_TRACESYS	0x00000002		/* tracing system calls */
-
 
 		.text
 		.align 4
 		.set	push
 		.set	reorder
-EXPORT(ret_from_fork)
-		move	a0, v0			# prev
-		jal	schedule_tail
-		lw	t0, TASK_PTRACE($28)	# syscall tracing enabled?
-		andi	t0, PT_TRACESYS
-		bnez	t0, tracesys_exit
-		j	ret_from_sys_call
-
-tracesys_exit:	jal	syscall_trace
-		b	ret_from_sys_call
-
-EXPORT(ret_from_irq)
-EXPORT(ret_from_exception)
+FEXPORT(ret_from_irq)
+FEXPORT(ret_from_exception)
 		lw	t0, PT_STATUS(sp)	# returning to kernel mode?
 		andi	t0, t0, KU_USER
-		bnez	t0, ret_from_sys_call
-		j	restore_all
-
-reschedule:	jal	schedule 
-
-EXPORT(ret_from_sys_call)
-		.type	ret_from_irq,@function
+		beqz	t0, restore_all
 
+FEXPORT(ret_from_sys_call)		# here to prevent code duplication
+ret_from_schedule:
 		mfc0	t0, CP0_STATUS	# need_resched and signals atomic test
 		ori	t0, t0, 1
 		xori	t0, t0, 1
 		mtc0	t0, CP0_STATUS
-		nop; nop; nop
+		SSNOP; SSNOP; SSNOP
 
 		lw	v0, TASK_NEED_RESCHED($28)
 		lw	v1, TASK_SIGPENDING($28)
 		bnez	v0, reschedule
 		bnez	v1, signal_return
-		FEXPORT(restore_all)
 restore_all:	.set	noat
 		RESTORE_ALL_AND_RET
 		.set	at
@@ -85,6 +66,10 @@
 		jal	do_signal
 		b	restore_all
 
+reschedule:
+		jal	schedule
+		b	ret_from_schedule
+
 /*
  * Common spurious interrupt handler.
  */
@@ -100,35 +85,38 @@
 		addiu   t0,1
 		sw      t0,%lo(irq_err_count)(t1)
 		j	ret_from_irq
-		END(spurious_interrupt)
+END(spurious_interrupt)
 
 		__INIT
 
 		.set	reorder
 
-		NESTED(except_vec1_generic, 0, sp)
+NESTED(except_vec1_generic, 0, sp)
 		PANIC("Exception vector 1 called")
-		END(except_vec1_generic)
+END(except_vec1_generic)
 
 		/*
 		 * General exception vector.  Used for all CPUs except R4000
 		 * and R4400 SC and MC versions.
 		 */
-		NESTED(except_vec3_generic, 0, sp)
+NESTED(except_vec3_generic, 0, sp)
 		mfc0	k1, CP0_CAUSE
 		la	k0, exception_handlers
 		andi	k1, k1, 0x7c
 		addu	k0, k0, k1
 		lw	k0, (k0)
 		jr	k0
-		END(except_vec3_generic)
+END(except_vec3_generic)
 		.set	at
 
 		/* General exception vector R4000 version. */
-		NESTED(except_vec3_r4000, 0, sp)
+NESTED(except_vec3_r4000, 0, sp)
 		.set	push
 		.set    mips3
 		.set	noat
+#if defined(R5432_CP0_INTERRUPT_WAR)
+		mfc0	k0, CP0_INDEX
+#endif
 		mfc0	k1, CP0_CAUSE
 		li	k0, 31<<2
 		andi	k1, k1, 0x7c
@@ -174,7 +162,7 @@
 #endif
 		eret
 		.set    pop
-		END(except_vec3_r4000)
+END(except_vec3_r4000)
 
 		__FINIT
 
@@ -221,10 +209,10 @@
 		.previous;
 #define BUILD_HANDLER(exception,handler,clear,verbose)                  \
 		.align	5;                                              \
-		NESTED(handle_##exception, PT_SIZE, sp);                \
+NESTED(handle_##exception, PT_SIZE, sp);		                \
 		.set	noat;                                           \
 		SAVE_ALL;                                               \
-		FEXPORT(handle_##exception##_int);			\
+FEXPORT(handle_##exception##_int);					\
 		__BUILD_clear_##clear(exception);                       \
 		.set	at;                                             \
 		__BUILD_##verbose(exception);                           \
@@ -232,7 +220,7 @@
 		 move	a0, sp;                                         \
 		j	ret_from_exception;                             \
 		 nop;                                                   \
-		END(handle_##exception)
+END(handle_##exception)
 
 		BUILD_HANDLER(adel,ade,ade,silent)		/* #4  */
 		BUILD_HANDLER(ades,ade,ade,silent)		/* #5  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/gdb-low.S linux-2.4.20/arch/mips/kernel/gdb-low.S
--- linux-2.4.19/arch/mips/kernel/gdb-low.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/gdb-low.S	2002-10-29 11:18:34.000000000 +0000
@@ -97,7 +97,7 @@
 		sw	ra,GDB_FR_REG31(sp)
 
 		CLI				/* disable interrupts */
-		
+
 /*
  * Followed by the floating point registers
  */
@@ -211,7 +211,7 @@
 		lw	v0,GDB_FR_CP0_CONTEXT(sp)
 		mtc0	v1,CP0_INDEX
 		mtc0	v0,CP0_CONTEXT
-		
+
 
 /*
  * Next, the floating point registers
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/gdb-stub.c linux-2.4.20/arch/mips/kernel/gdb-stub.c
--- linux-2.4.19/arch/mips/kernel/gdb-stub.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/gdb-stub.c	2002-10-29 11:18:50.000000000 +0000
@@ -62,7 +62,7 @@
  * Host:                  Reply:
  * $m0,10#2a               +$00010203040506070809101112131415#42
  *
- * 
+ *
  *  ==============
  *  MORE EXAMPLES:
  *  ==============
@@ -72,11 +72,11 @@
  *  going. In this scenario the host machine was a PC and the
  *  target platform was a Galileo EVB64120A MIPS evaluation
  *  board.
- *   
+ *
  *  Step 1:
  *  First download gdb-5.0.tar.gz from the internet.
  *  and then build/install the package.
- * 
+ *
  *  Example:
  *    $ tar zxf gdb-5.0.tar.gz
  *    $ cd gdb-5.0
@@ -85,35 +85,35 @@
  *    $ install
  *    $ which mips-linux-elf-gdb
  *    /usr/local/bin/mips-linux-elf-gdb
- * 
+ *
  *  Step 2:
  *  Configure linux for remote debugging and build it.
- * 
+ *
  *  Example:
  *    $ cd ~/linux
  *    $ make menuconfig <go to "Kernel Hacking" and turn on remote debugging>
  *    $ make dep; make vmlinux
- * 
+ *
  *  Step 3:
  *  Download the kernel to the remote target and start
- *  the kernel running. It will promptly halt and wait 
+ *  the kernel running. It will promptly halt and wait
  *  for the host gdb session to connect. It does this
- *  since the "Kernel Hacking" option has defined 
+ *  since the "Kernel Hacking" option has defined
  *  CONFIG_REMOTE_DEBUG which in turn enables your calls
  *  to:
  *     set_debug_traps();
  *     breakpoint();
- * 
+ *
  *  Step 4:
  *  Start the gdb session on the host.
- * 
+ *
  *  Example:
  *    $ mips-linux-elf-gdb vmlinux
  *    (gdb) set remotebaud 115200
  *    (gdb) target remote /dev/ttyS1
- *    ...at this point you are connected to 
+ *    ...at this point you are connected to
  *       the remote target and can use gdb
- *       in the normal fasion. Setting 
+ *       in the normal fasion. Setting
  *       breakpoints, single stepping,
  *       printing variables, etc.
  *
@@ -213,7 +213,7 @@
 		checksum = 0;
 		xmitcsum = -1;
 		count = 0;
-	
+
 		/*
 		 * now, read until a # or end of buffer is found
 		 */
@@ -378,7 +378,7 @@
 	save_and_cli(flags);
 	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
 		saved_vectors[ht->tt] = set_except_vector(ht->tt, trap_low);
-  
+
 	putDebugChar('+'); /* 'hello world' */
 	/*
 	 * In case GDB is started before us, ack any packets
@@ -547,7 +547,7 @@
 		targ += 4 + (insn.i_format.simmediate << 2);
 		break;
 	}
-				
+
 	if (is_branch) {
 		i = 0;
 		if (is_cond && targ != (regs->cp0_epc + 8)) {
@@ -567,7 +567,7 @@
 
 /*
  *  If asynchronously interrupted by gdb, then we need to set a breakpoint
- *  at the interrupted instruction so that we wind up stopped with a 
+ *  at the interrupted instruction so that we wind up stopped with a
  *  reasonable stack frame.
  */
 static struct gdb_bp_save async_bp;
@@ -595,11 +595,11 @@
 	char *ptr;
 	unsigned long *stack;
 
-#if 0	
+#if 0
 	printk("in handle_exception()\n");
 	show_gdbregs(regs);
 #endif
-	
+
 	/*
 	 * First check trap type. If this is CPU_UNUSABLE and CPU_ID is 1,
 	 * the simply switch the FPU on and return since this is no error
@@ -619,7 +619,7 @@
 	/*
 	 * If we're in breakpoint() increment the PC
 	 */
-	if (trap == 9 && regs->cp0_epc == (unsigned long)breakinst)		
+	if (trap == 9 && regs->cp0_epc == (unsigned long)breakinst)
 		regs->cp0_epc += 4;
 
 	/*
@@ -629,7 +629,7 @@
 	if (step_bp[0].addr) {
 		*(unsigned *)step_bp[0].addr = step_bp[0].val;
 		step_bp[0].addr = 0;
-		    
+
 		if (step_bp[1].addr) {
 			*(unsigned *)step_bp[1].addr = step_bp[1].val;
 			step_bp[1].addr = 0;
@@ -723,7 +723,7 @@
 			ptr = mem2hex((char *)&regs->frame_ptr, ptr, 2*4, 0); /* frp */
 			ptr = mem2hex((char *)&regs->cp0_index, ptr, 16*4, 0); /* cp0 */
 			break;
-	  
+
 		/*
 		 * set the value of the CPU registers - return OK
 		 * FIXME: Needs to be written
@@ -769,7 +769,7 @@
 		/*
 		 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK
 		 */
-		case 'M': 
+		case 'M':
 			ptr = &input_buffer[1];
 
 			if (hexToInt(&ptr, &addr)
@@ -788,13 +788,13 @@
 		/*
 		 * cAA..AA    Continue at address AA..AA(optional)
 		 */
-		case 'c':    
+		case 'c':
 			/* try to read optional parameter, pc unchanged if no parm */
 
 			ptr = &input_buffer[1];
 			if (hexToInt(&ptr, &addr))
 				regs->cp0_epc = addr;
-	  
+
 			/*
 			 * Need to flush the instruction cache here, as we may
 			 * have deposited a breakpoint, and the icache probably
@@ -843,7 +843,7 @@
 		 */
 		case 'b':
 		{
-#if 0				
+#if 0
 			int baudrate;
 			extern void set_timer_3();
 
@@ -934,7 +934,7 @@
 		int i = (l>8)?8:l;
 		mem2hex((char *)str, &outbuf[1], i, 0);
 		outbuf[(i*2)+1]=0;
-		putpacket(outbuf); 
+		putpacket(outbuf);
 		str += i;
 		l -= i;
 	}
@@ -962,5 +962,5 @@
 {
 	register_console(&gdb_console);
 }
-     
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/head.S linux-2.4.20/arch/mips/kernel/head.S
--- linux-2.4.19/arch/mips/kernel/head.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/head.S	2002-10-29 11:18:33.000000000 +0000
@@ -35,6 +35,10 @@
 		 */
 		.fill	0x400
 
+		/* The following two symbols are used for kernel profiling. */
+		EXPORT(stext)
+		EXPORT(_stext)
+
 		__INIT
 
 		/* Cache Error */
@@ -81,7 +85,7 @@
 		 * The EJTAG debug exception entry point is 0xbfc00480, which
 		 * normally is in the boot PROM, so the boot PROM must do a
 		 * unconditional jump to this vector.
-		 */	
+		 */
 		NESTED(except_vec_ejtag_debug, 0, sp)
 		j	ejtag_debug_handler
 		 nop
@@ -94,7 +98,7 @@
 		.set	noat
 		.set	noreorder
 		mtc0	k0, CP0_DESAVE
-		mfc0	k0, CP0_DEBUG	
+		mfc0	k0, CP0_DEBUG
 
 		sll	k0, k0, 30	# Check for SDBBP.
 		bgez	k0, ejtag_return
@@ -106,15 +110,15 @@
 		 move	a0, sp
 		RESTORE_ALL
 		la	k0, ejtag_debug_buffer
-		lw	k1, 0(k0)	
+		lw	k1, 0(k0)
 
 ejtag_return:
-		mfc0	k0, CP0_DESAVE	
+		mfc0	k0, CP0_DESAVE
 		.word	0x4200001f     # DERET, return from EJTAG debug exception.
 		 nop
 		.set	at
 		END(ejtag_debug_handler)
-	
+
 		/*
 		* NMI debug exception handler for MIPS reference boards.
 		* The NMI debug exception entry point is 0xbfc00000, which
@@ -137,16 +141,13 @@
 		eret
 		.set    at
 		.set    mips0
-		END(nmi_handler)	
+		END(nmi_handler)
 
 		/*
 		 * Kernel entry point
 		 */
 		NESTED(kernel_entry, 16, sp)
 		.set	noreorder
-		/* The following two symbols are used for kernel profiling. */
-		EXPORT(stext)
-		EXPORT(_stext)
 
 		/*
 		 * Stack for kernel and init, current variable
@@ -178,7 +179,7 @@
 
 /*
  * SMP slave cpus entry point.  Board specific code for bootstrap calls this
- * function after setting up the stack and gp registers. 
+ * function after setting up the stack and gp registers.
  */
 		LEAF(smp_bootstrap)
 		.set push
@@ -198,13 +199,13 @@
 		__FINIT
 
 		/*
-		 * This buffer is reserved for the use of the EJTAG debug 
+		 * This buffer is reserved for the use of the EJTAG debug
 		 * handler.
 		 */
 		.data
 		EXPORT(ejtag_debug_buffer)
 		.fill	4
-	
+
 		.comm	kernelsp,    NR_CPUS * 8, 8
 		.comm	pgd_current, NR_CPUS * 8, 8
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/i8259.c linux-2.4.20/arch/mips/kernel/i8259.c
--- linux-2.4.19/arch/mips/kernel/i8259.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/i8259.c	2002-10-29 11:18:33.000000000 +0000
@@ -42,7 +42,7 @@
 void mask_and_ack_8259A(unsigned int);
 
 static unsigned int startup_8259A_irq(unsigned int irq)
-{ 
+{
 	enable_8259A_irq(irq);
 
 	return 0; /* never anything pending */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/ipc.c linux-2.4.20/arch/mips/kernel/ipc.c
--- linux-2.4.19/arch/mips/kernel/ipc.c	2000-02-25 06:52:30.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/ipc.c	2002-10-29 11:18:33.000000000 +0000
@@ -45,7 +45,7 @@
 	}
 
 	case MSGSND:
-		return sys_msgsnd (first, (struct msgbuf *) ptr, 
+		return sys_msgsnd (first, (struct msgbuf *) ptr,
 				   second, third);
 	case MSGRCV:
 		switch (version) {
@@ -53,9 +53,9 @@
 			struct ipc_kludge tmp;
 			if (!ptr)
 				return -EINVAL;
-			
+
 			if (copy_from_user(&tmp,
-					   (struct ipc_kludge *) ptr, 
+					   (struct ipc_kludge *) ptr,
 					   sizeof (tmp)))
 				return -EFAULT;
 			return sys_msgrcv (first, tmp.msgp, second,
@@ -85,7 +85,7 @@
 				return -EINVAL;
 			return sys_shmat (first, (char *) ptr, second, (ulong *) third);
 		}
-	case SHMDT: 
+	case SHMDT:
 		return sys_shmdt ((char *)ptr);
 	case SHMGET:
 		return sys_shmget (first, second, third);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/irixelf.c linux-2.4.20/arch/mips/kernel/irixelf.c
--- linux-2.4.19/arch/mips/kernel/irixelf.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/irixelf.c	2002-10-29 11:18:48.000000000 +0000
@@ -128,7 +128,7 @@
 {
 	start = PAGE_ALIGN(start);
 	end = PAGE_ALIGN(end);
-	if (end <= start) 
+	if (end <= start)
 		return;
 	do_brk(start, end - start);
 }
@@ -158,7 +158,7 @@
 	elf_caddr_t *argv;
 	elf_caddr_t *envp;
 	elf_addr_t *sp, *csp;
-	
+
 #ifdef DEBUG_ELF
 	printk("create_irix_tables: p[%p] argc[%d] envc[%d] "
 	       "load_addr[%08x] interp_load_addr[%08x]\n",
@@ -247,7 +247,7 @@
 	elf_bss = 0;
 	last_bss = 0;
 	error = load_addr = 0;
-	
+
 #ifdef DEBUG_ELF
 	print_elfhdr(interp_elf_ex);
 #endif
@@ -268,7 +268,7 @@
 	    return 0xffffffff;
 	}
 
-	elf_phdata =  (struct elf_phdr *) 
+	elf_phdata =  (struct elf_phdr *)
 		kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum,
 			GFP_KERNEL);
 
@@ -394,7 +394,7 @@
 		return -ENOEXEC;
 
 	/* First of all, some simple consistency checks */
-	if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) || 
+	if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) ||
 	    !irix_elf_check_arch(ehp) || !bprm->file->f_op->mmap) {
 		return -ENOEXEC;
 	}
@@ -558,7 +558,7 @@
 }
 
 /*
- * IRIX maps a page at 0x200000 that holds information about the 
+ * IRIX maps a page at 0x200000 that holds information about the
  * process and the system, here we map the page and fill the
  * structure
  */
@@ -568,7 +568,7 @@
 	struct prda *pp;
 
 	v =  do_brk (PRDA_ADDRESS, PAGE_SIZE);
-	
+
 	if (v < 0)
 		return;
 
@@ -579,9 +579,9 @@
 
 	/* We leave the rest set to zero */
 }
-	
 
-	
+
+
 /* These are the functions used to load ELF style executables and shared
  * libraries.  There is no binary dependent code anywhere else.
  */
@@ -596,7 +596,7 @@
 	int retval, has_interp, has_ephdr, size, i;
 	char *elf_interpreter;
 	mm_segment_t old_fs;
-	
+
 	load_addr = 0;
 	has_interp = has_ephdr = 0;
 	elf_ihdr = elf_ephdr = 0;
@@ -685,7 +685,7 @@
 	current->mm->mmap = NULL;
 	current->flags &= ~PF_FORKNOEXEC;
 	elf_entry = (unsigned int) elf_ex.e_entry;
-	
+
 	/* Do this so that we can load the interpreter, if need be.  We will
 	 * change some of these later.
 	 */
@@ -724,7 +724,7 @@
 	set_binfmt(&irix_format);
 	compute_creds(bprm);
 	current->flags &= ~PF_FORKNOEXEC;
-	bprm->p = (unsigned long) 
+	bprm->p = (unsigned long)
 	  create_irix_tables((char *)bprm->p, bprm->argc, bprm->envc,
 			(elf_interpreter ? &elf_ex : NULL),
 			load_addr, interp_load_addr, regs, elf_ephdr);
@@ -812,30 +812,30 @@
 	if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
 	   !irix_elf_check_arch(&elf_ex) || !file->f_op->mmap)
 		return -ENOEXEC;
-	
+
 	/* Now read in all of the header information. */
 	if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
 		return -ENOEXEC;
-	
-	elf_phdata =  (struct elf_phdr *) 
+
+	elf_phdata =  (struct elf_phdr *)
 		kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
 	if (elf_phdata == NULL)
 		return -ENOMEM;
-	
+
 	retval = kernel_read(file, elf_ex.e_phoff, (char *) elf_phdata,
 			   sizeof(struct elf_phdr) * elf_ex.e_phnum);
-	
+
 	j = 0;
 	for(i=0; i<elf_ex.e_phnum; i++)
 		if((elf_phdata + i)->p_type == PT_LOAD) j++;
-	
+
 	if(j != 1)  {
 		kfree(elf_phdata);
 		return -ENOEXEC;
 	}
-	
+
 	while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
-	
+
 	/* Now use mmap to map the library into memory. */
 	down_write(&current->mm->mmap_sem);
 	error = do_mmap(file,
@@ -863,7 +863,7 @@
 	kfree(elf_phdata);
 	return 0;
 }
-	
+
 /* Called through irix_syssgi() to map an elf image given an FD,
  * a phdr ptr USER_PHDRP in userspace, and a count CNT telling how many
  * phdrs there are in the USER_PHDRP array.  We return the vaddr the
@@ -1026,7 +1026,7 @@
 	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
 	DUMP_WRITE(men->data, men->datasz);
 	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
-	
+
 	return 1;
 
 end_coredump:
@@ -1072,13 +1072,13 @@
 		if (maydump(vma))
 		{
 			int sz = vma->vm_end-vma->vm_start;
-		
+
 			if (size+sz >= limit)
 				break;
 			else
 				size += sz;
 		}
-		
+
 		segs++;
 	}
 #ifdef DEBUG
@@ -1105,7 +1105,7 @@
 	elf.e_shentsize = 0;
 	elf.e_shnum = 0;
 	elf.e_shstrndx = 0;
-	
+
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 
@@ -1147,7 +1147,7 @@
 	} else {
 		*(struct pt_regs *)&prstatus.pr_reg = *regs;
 	}
-	
+
 	notes[1].name = "CORE";
 	notes[1].type = NT_PRPSINFO;
 	notes[1].datasz = sizeof(psinfo);
@@ -1164,7 +1164,7 @@
 		int i, len;
 
 		set_fs(fs);
-		
+
 		len = current->mm->arg_end - current->mm->arg_start;
 		len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len;
 		copy_from_user(&psinfo.pr_psargs,
@@ -1201,7 +1201,7 @@
 
 		for(i = 0; i < numnote; i++)
 			sz += notesize(&notes[i]);
-		
+
 		phdr.p_type = PT_NOTE;
 		phdr.p_offset = offset;
 		phdr.p_vaddr = 0;
@@ -1217,7 +1217,7 @@
 
 	/* Page-align dumped data. */
 	dataoff = offset = roundup(offset, PAGE_SIZE);
-	
+
 	/* Write program headers for segments dump. */
 	for(vma = current->mm->mmap, i = 0;
 		i < segs && vma != NULL; vma = vma->vm_next) {
@@ -1227,7 +1227,7 @@
 		i++;
 
 		sz = vma->vm_end - vma->vm_start;
-		
+
 		phdr.p_type = PT_LOAD;
 		phdr.p_offset = offset;
 		phdr.p_vaddr = vma->vm_start;
@@ -1246,17 +1246,17 @@
 	for(i = 0; i < numnote; i++)
 		if (!writenote(&notes[i], file))
 			goto end_coredump;
-	
+
 	set_fs(fs);
 
 	DUMP_SEEK(dataoff);
-	
+
 	for(i = 0, vma = current->mm->mmap;
 	    i < segs && vma != NULL;
 	    vma = vma->vm_next) {
 		unsigned long addr = vma->vm_start;
 		unsigned long len = vma->vm_end - vma->vm_start;
-		
+
 		if (!maydump(vma))
 			continue;
 		i++;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/irixinv.c linux-2.4.20/arch/mips/kernel/irixinv.c
--- linux-2.4.19/arch/mips/kernel/irixinv.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/irixinv.c	2002-10-29 11:18:32.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * Support the inventory interface for IRIX binaries
  * This is invoked before the mm layer is working, so we do not
- * use the linked lists for the inventory yet. 
+ * use the linked lists for the inventory yet.
  *
  * Miguel de Icaza, 1997.
  */
@@ -23,7 +23,7 @@
 
 	if (inventory_items == MAX_INVENTORY)
 		return;
-	
+
 	ni->inv_class      = class;
 	ni->inv_type       = type;
 	ni->inv_controller = controller;
@@ -57,7 +57,7 @@
 	 * most likely this will not let just anyone run the X server
 	 * until we put the right values all over the place
 	 */
-	 
+
 	add_to_inventory (10, 3, 0, 0, 16400);
 	add_to_inventory (1, 1, 150, -1, 12);
 	add_to_inventory (1, 3, 0, 0, 8976);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/irixsig.c linux-2.4.20/arch/mips/kernel/irixsig.c
--- linux-2.4.19/arch/mips/kernel/irixsig.c	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/irixsig.c	2002-10-29 11:18:35.000000000 +0000
@@ -379,7 +379,7 @@
 }
 #endif
 
-asmlinkage int 
+asmlinkage int
 irix_sigaction(int sig, const struct sigaction *act,
 	      struct sigaction *oact, void *trampoline)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/irq.c linux-2.4.20/arch/mips/kernel/irq.c
--- linux-2.4.19/arch/mips/kernel/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/irq.c	2002-10-29 11:18:33.000000000 +0000
@@ -31,6 +31,8 @@
 irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
 	{ [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}};
 
+static void register_irq_proc (unsigned int irq);
+
 /*
  * Special irq handlers.
  */
@@ -48,7 +50,7 @@
 {
 	/*
 	 * 'what should we do if we get a hw irq event on an illegal vector'.
-	 * each architecture has to answer this themselves, it doesnt deserve
+	 * each architecture has to answer this themselves, it doesn't deserve
 	 * a generic callback i think.
 	 */
 	printk("unexpected interrupt %d\n", irq);
@@ -87,7 +89,7 @@
 
 	for (i = 0 ; i < NR_IRQS ; i++) {
 		action = irq_desc[i].action;
-		if (!action) 
+		if (!action)
 			continue;
 		p += sprintf(p, "%3d: ",i);
 #ifndef CONFIG_SMP
@@ -198,12 +200,12 @@
 }
 
 /*
- * A global "cli()" while in an interrupt context turns into just a local 
- * cli(). Interrupts should use spinlocks for the (very unlikely) case that 
+ * A global "cli()" while in an interrupt context turns into just a local
+ * cli(). Interrupts should use spinlocks for the (very unlikely) case that
  * they ever want to protect against each other.
- * 
- * If we already have local interrupts disabled, this will not turn a local 
- * disable into a global one (problems with spinlocks: this makes 
+ *
+ * If we already have local interrupts disabled, this will not turn a local
+ * disable into a global one (problems with spinlocks: this makes
  * save_flags+cli+sti usable inside a spinlock).
  */
 
@@ -317,9 +319,9 @@
  * Generic enable/disable code: this just calls
  * down into the PIC-specific version for the actual
  * hardware disable after having gotten the irq
- * controller lock. 
+ * controller lock.
  */
- 
+
 /**
  *	disable_irq_nosync - disable an irq without waiting
  *	@irq: Interrupt to disable
@@ -330,7 +332,7 @@
  *
  *	This function may be called from IRQ context.
  */
- 
+
 void inline disable_irq_nosync(unsigned int irq)
 {
 	irq_desc_t *desc = irq_desc + irq;
@@ -356,7 +358,7 @@
  *
  *	This function may be called - with care - from IRQ context.
  */
- 
+
 void disable_irq(unsigned int irq)
 {
 	disable_irq_nosync(irq);
@@ -377,7 +379,7 @@
  *
  *	This function may be called from IRQ context.
  */
- 
+
 void enable_irq(unsigned int irq)
 {
 	irq_desc_t *desc = irq_desc + irq;
@@ -412,7 +414,7 @@
  */
 asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs)
 {
-	/* 
+	/*
 	 * We ack quickly, we don't want the irq controller
 	 * thinking we're snobs just because some other CPU has
 	 * disabled global interrupts (we have already done the
@@ -472,7 +474,7 @@
 		spin_unlock(&desc->lock);
 		handle_IRQ_event(irq, regs, action);
 		spin_lock(&desc->lock);
-		
+
 		if (!(desc->status & IRQ_PENDING))
 			break;
 		desc->status &= ~IRQ_PENDING;
@@ -502,7 +504,7 @@
  *	This call allocates interrupt resources and enables the
  *	interrupt line and IRQ handling. From the point this
  *	call is made your handler function may be invoked. Since
- *	your handler function must clear any interrupt the board 
+ *	your handler function must clear any interrupt the board
  *	raises, you must take care both to initialise your hardware
  *	and to set up the interrupt handler in the right order.
  *
@@ -522,10 +524,10 @@
  *	SA_SAMPLE_RANDOM	The interrupt can be used for entropy
  *
  */
- 
-int request_irq(unsigned int irq, 
+
+int request_irq(unsigned int irq,
 		void (*handler)(int, void *, struct pt_regs *),
-		unsigned long irqflags, 
+		unsigned long irqflags,
 		const char * devname,
 		void *dev_id)
 {
@@ -580,12 +582,12 @@
  *	does not return until any executing interrupts for this IRQ
  *	have completed.
  *
- *	This function may be called from interrupt context. 
+ *	This function may be called from interrupt context.
  *
  *	Bugs: Attempting to free an irq in a handler for the same irq hangs
  *	      the machine.
  */
- 
+
 void free_irq(unsigned int irq, void *dev_id)
 {
 	irq_desc_t *desc;
@@ -646,7 +648,7 @@
  *	and a mask of potential interrupt lines is returned.
  *
  */
- 
+
 unsigned long probe_irq_on(void)
 {
 	unsigned int i;
@@ -655,15 +657,15 @@
 	unsigned long delay;
 
 	down(&probe_sem);
-	/* 
+	/*
 	 * something may have generated an irq long ago and we want to
-	 * flush such a longstanding irq before considering it as spurious. 
+	 * flush such a longstanding irq before considering it as spurious.
 	 */
 	for (i = NR_IRQS-1; i > 0; i--)  {
 		desc = irq_desc + i;
 
 		spin_lock_irq(&desc->lock);
-		if (!irq_desc[i].action) 
+		if (!irq_desc[i].action)
 			irq_desc[i].handler->startup(i);
 		spin_unlock_irq(&desc->lock);
 	}
@@ -725,7 +727,7 @@
  * Return a mask of triggered interrupts (this
  * can handle only legacy ISA interrupts).
  */
- 
+
 /**
  *	probe_irq_mask - scan a bitmap of interrupt lines
  *	@val:	mask of interrupts to consider
@@ -787,7 +789,7 @@
  *	nothing prevents two IRQ probe callers from overlapping. The
  *	results of this are non-optimal.
  */
- 
+
 int probe_irq_off(unsigned long val)
 {
 	int i, irq_found, nr_irqs;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/irq_cpu.c linux-2.4.20/arch/mips/kernel/irq_cpu.c
--- linux-2.4.19/arch/mips/kernel/irq_cpu.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/irq_cpu.c	2002-10-29 11:18:35.000000000 +0000
@@ -13,7 +13,7 @@
 /*
  * Almost all MIPS CPUs define 8 interrupt sources.  They are typically
  * level triggered (i.e., cannot be cleared from CPU; must be cleared from
- * device).  The first two are software interrupts.  The last one is 
+ * device).  The first two are software interrupts.  The last one is
  * usually the CPU timer interrupt if counter register is present or, for
  * CPUs with an external FPU, by convention it's the FPU exception interrupt.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/mips_ksyms.c linux-2.4.20/arch/mips/kernel/mips_ksyms.c
--- linux-2.4.19/arch/mips/kernel/mips_ksyms.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/mips_ksyms.c	2002-10-29 11:18:34.000000000 +0000
@@ -43,7 +43,9 @@
 extern long __strnlen_user_asm(const char *s);
 
 EXPORT_SYMBOL(mips_machtype);
+#ifdef CONFIG_EISA
 EXPORT_SYMBOL(EISA_bus);
+#endif
 
 /*
  * String functions
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/old-irq.c linux-2.4.20/arch/mips/kernel/old-irq.c
--- linux-2.4.19/arch/mips/kernel/old-irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/old-irq.c	2002-10-29 11:18:48.000000000 +0000
@@ -130,7 +130,7 @@
 
 	for (i = 0 ; i < 32 ; i++) {
 		action = irq_action[i];
-		if (!action) 
+		if (!action)
 			continue;
 		len += sprintf(buf+len, "%2d: %8d %c %s",
 			i, kstat.irqs[0][i],
@@ -286,7 +286,7 @@
  * specific variants.  For now we still use this as broken as it is because
  * it used to work ...
  */
-int request_irq(unsigned int irq, 
+int request_irq(unsigned int irq,
 		void (*handler)(int, void *, struct pt_regs *),
 		unsigned long irqflags, const char * devname, void *dev_id)
 {
@@ -315,7 +315,7 @@
 		kfree(action);
 	return retval;
 }
-		
+
 void free_irq(unsigned int irq, void *dev_id)
 {
 	struct irqaction * action, **p;
@@ -386,7 +386,7 @@
 	outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
 	outb(0x01, 0x21); /* Select 8086 mode */
 	outb(0xff, 0x21); /* Mask all */
-        
+
 	/* Init slave interrupt controller */
 	outb(0x11, 0xa0); /* Start init sequence */
 	outb(0x08, 0xa1); /* Vector base */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/old-time.c linux-2.4.20/arch/mips/kernel/old-time.c
--- linux-2.4.19/arch/mips/kernel/old-time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/old-time.c	2002-10-29 11:18:49.000000000 +0000
@@ -106,7 +106,7 @@
 		 "r" (quotient));
 
 	/*
- 	 * Due to possible jiffies inconsistencies, we need to check 
+ 	 * Due to possible jiffies inconsistencies, we need to check
 	 * the result so that we'll get a timer that is monotonic.
 	 */
 	if (res >= USECS_PER_JIFFY)
@@ -115,9 +115,9 @@
 	return res;
 }
 
-/* This function must be called with interrupts disabled 
+/* This function must be called with interrupts disabled
  * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
- * 
+ *
  * However, the pc-audio speaker driver changes the divisor so that
  * it gets interrupted rather more often - it loads 64 into the
  * counter rather than 11932! This has an adverse impact on
@@ -131,7 +131,7 @@
  * using either the RTC or the 8253 timer. The decision would be
  * based on whether there was any other device around that needed
  * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
- * and then do some jiggery to have a version of do_timer that 
+ * and then do some jiggery to have a version of do_timer that
  * advanced the clock by 1/1024 s. Every time that reached over 1/100
  * of a second, then do all the old code. If the time was kept correct
  * then do_gettimeoffset could just return 0 - there is no low order
@@ -142,7 +142,7 @@
  * often than every 120 us or so.
  *
  * Anyway, this needs more thought....		pjsg (1993-08-28)
- * 
+ *
  * If you are really that interested, you should be reading
  * comp.protocols.time.ntp!
  */
@@ -157,7 +157,7 @@
 	static unsigned long jiffies_p;
 
 	/*
-	 * cache volatile jiffies temporarily; we have IRQs turned off. 
+	 * cache volatile jiffies temporarily; we have IRQs turned off.
 	 */
 	unsigned long jiffies_t;
 
@@ -167,7 +167,7 @@
 	count = inb_p(0x40);	/* read the latched count */
 
 	/*
-	 * We do this guaranteed double memory access instead of a _p 
+	 * We do this guaranteed double memory access instead of a _p
 	 * postfix in the previous port access. Wheee, hackady hack
 	 */
 	jiffies_t = jiffies;
@@ -192,7 +192,7 @@
 			/* assumption about timer being IRQ1 */
 			if (inb(0x20) & 0x01) {
 				/*
-				 * We cannot detect lost timer interrupts ... 
+				 * We cannot detect lost timer interrupts ...
 				 * well, that's why we call them lost, don't we? :)
 				 * [hmm, on the Pentium and Alpha we can ... sort of]
 				 */
@@ -348,7 +348,7 @@
 	    ddb5074_led_d2(1);
 	else if (cnt == 7 || cnt == dist+7)
 	    ddb5074_led_d2(0);
-	
+
 	if (++cnt > period) {
 	    cnt = 0;
 	    /* The hyperbolic function below modifies the heartbeat period
@@ -383,7 +383,7 @@
 	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
 	 * called as close as possible to 500 ms before the new second starts.
 	 */
-	read_lock (&xtime_lock); 
+	read_lock (&xtime_lock);
 	if ((time_status & STA_UNSYNC) == 0 &&
 	    xtime.tv_sec > last_rtc_update + 660 &&
 	    xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
@@ -402,10 +402,10 @@
 	 * look closely for now..
 	 */
 	/*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */
-	read_unlock (&xtime_lock); 
+	read_unlock (&xtime_lock);
 }
 
-static inline void 
+static inline void
 r4k_timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	unsigned int count;
@@ -425,7 +425,7 @@
 	 * we need only ask for the next in r4k_interval counts. On other
 	 * archs we have a real timer, so we don't want this.
 	 */
-	write_32bit_cp0_register (CP0_COMPARE, 
+	write_32bit_cp0_register (CP0_COMPARE,
 				  (unsigned long) (count + r4k_interval));
         kstat.irqs[0][irq]++;
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/pci-dma.c linux-2.4.20/arch/mips/kernel/pci-dma.c
--- linux-2.4.19/arch/mips/kernel/pci-dma.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/pci-dma.c	2002-10-29 11:18:32.000000000 +0000
@@ -22,17 +22,19 @@
 	void *ret;
 	int gfp = GFP_ATOMIC;
 
+#ifdef CONFIG_ISA
 	if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
 		gfp |= GFP_DMA;
+#endif
 	ret = (void *) __get_free_pages(gfp, get_order(size));
 
 	if (ret != NULL) {
 		memset(ret, 0, size);
+		*dma_handle = bus_to_baddr(hwdev->bus->number, __pa(ret));
 #ifdef CONFIG_NONCOHERENT_IO
 		dma_cache_wback_inv((unsigned long) ret, size);
-		ret = KSEG1ADDR(ret);
+		ret = UNCAC_ADDR(ret);
 #endif
-		*dma_handle = virt_to_bus(ret);
 	}
 
 	return ret;
@@ -44,7 +46,7 @@
 	unsigned long addr = (unsigned long) vaddr;
 
 #ifdef CONFIG_NONCOHERENT_IO
-	addr = KSEG0ADDR(addr);
+	addr = CAC_ADDR(addr);
 #endif
 	free_pages(addr, get_order(size));
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/pci.c linux-2.4.20/arch/mips/kernel/pci.c
--- linux-2.4.19/arch/mips/kernel/pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/pci.c	2002-10-29 11:18:33.000000000 +0000
@@ -162,7 +162,8 @@
 }
 
 void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res, unsigned long size,
+		       unsigned long align)
 {
 	/* this should not be called */
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/pci_auto.c linux-2.4.20/arch/mips/kernel/pci_auto.c
--- linux-2.4.19/arch/mips/kernel/pci_auto.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/pci_auto.c	2002-10-29 11:18:50.000000000 +0000
@@ -42,7 +42,7 @@
 #ifdef 	DEBUG
 #define	DBG(x...)	printk(x)
 #else
-#define	DBG(x...)	
+#define	DBG(x...)
 #endif
 
 /*
@@ -95,7 +95,7 @@
 static u32 pciauto_lower_memspc;
 static u32 pciauto_upper_memspc;
 
-void __init 
+void __init
 pciauto_setup_bars(struct pci_channel *hose,
 		   int top_bus,
 		   int current_bus,
@@ -144,7 +144,7 @@
 			    PCI_BASE_ADDRESS_MEM_TYPE_64)
 				found_mem64 = 1;
 
-			addr_mask = PCI_BASE_ADDRESS_MEM_MASK;		
+			addr_mask = PCI_BASE_ADDRESS_MEM_MASK;
 			upper_limit = &pciauto_upper_memspc;
 			lower_limit = &pciauto_lower_memspc;
 			DBG("        Mem");
@@ -160,22 +160,22 @@
 		if ((bar_value + bar_size) > *upper_limit) {
 			if (bar_response & PCI_BASE_ADDRESS_SPACE) {
 				if (io_resource_inuse->child) {
-					io_resource_inuse = 
+					io_resource_inuse =
 						io_resource_inuse->child;
-					pciauto_lower_iospc = 
+					pciauto_lower_iospc =
 						io_resource_inuse->start;
-					pciauto_upper_iospc = 
+					pciauto_upper_iospc =
 						io_resource_inuse->end + 1;
 					goto retry;
 				}
 
 			} else {
 				if (mem_resource_inuse->child) {
-					mem_resource_inuse = 
+					mem_resource_inuse =
 						mem_resource_inuse->child;
-					pciauto_lower_memspc = 
+					pciauto_lower_memspc =
 						mem_resource_inuse->start;
-					pciauto_upper_memspc = 
+					pciauto_upper_memspc =
 						mem_resource_inuse->end + 1;
 					goto retry;
 				}
@@ -194,7 +194,7 @@
 		 * If we are a 64-bit decoder then increment to the
 		 * upper 32 bits of the bar and force it to locate
 		 * in the lower 4GB of memory.
-		 */ 
+		 */
 		if (found_mem64) {
 			bar += 4;
 			early_write_config_dword(hose, top_bus,
@@ -295,12 +295,12 @@
 	int devfn_stop = 0xff;
 
 	sub_bus = current_bus;
-	
+
 	if (hose->first_devfn)
 		devfn_start = hose->first_devfn;
 	if (hose->last_devfn)
 		devfn_stop = hose->last_devfn;
-	
+
 	for (pci_devfn=devfn_start; pci_devfn<devfn_stop; pci_devfn++) {
 
 		if (PCI_FUNC(pci_devfn) && !found_multi)
@@ -387,7 +387,7 @@
 	pciauto_upper_memspc = mem_resource_inuse->end + 1;
 	DBG("Autoconfig PCI channel 0x%p\n", hose);
 	DBG("Scanning bus %.2x, I/O 0x%.8x:0x%.8x, Mem 0x%.8x:0x%.8x\n",
-		busno, pciauto_lower_iospc, pciauto_upper_iospc, 
+		busno, pciauto_lower_iospc, pciauto_upper_iospc,
 		pciauto_lower_memspc, pciauto_upper_memspc);
 
 	return pciauto_bus_scan(hose, busno, busno);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/proc.c linux-2.4.20/arch/mips/kernel/proc.c
--- linux-2.4.19/arch/mips/kernel/proc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/proc.c	2002-10-29 11:18:35.000000000 +0000
@@ -67,7 +67,13 @@
 	[CPU_R5500]	"R5500",
 	[CPU_TX49XX]	"TX49xx",
 	[CPU_TX39XX]	"TX39xx",
-	[CPU_20KC]	"MIPS 20Kc"
+	[CPU_20KC]	"MIPS 20Kc",
+	[CPU_VR4111]	"NEC VR4111",
+	[CPU_VR4121]	"NEC VR4121",
+	[CPU_VR4122]	"NEC VR4122",
+	[CPU_VR4131]	"NEC VR4131",
+	[CPU_VR4181]	"NEC VR4181",
+	[CPU_VR4181A]	"NEC VR4181A"
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/process.c linux-2.4.20/arch/mips/kernel/process.c
--- linux-2.4.19/arch/mips/kernel/process.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/process.c	2002-10-29 11:18:39.000000000 +0000
@@ -77,7 +77,6 @@
 {
 	struct pt_regs * childregs;
 	long childksp;
-	extern void save_fp(void*);
 
 	childksp = (unsigned long)p + KERNEL_STACK_SIZE - 32;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/ptrace.c linux-2.4.20/arch/mips/kernel/ptrace.c
--- linux-2.4.19/arch/mips/kernel/ptrace.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/ptrace.c	2002-10-29 11:18:40.000000000 +0000
@@ -84,7 +84,7 @@
 		goto out_tsk;
 
 	switch (request) {
-	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+	case PTRACE_PEEKTEXT: /* read word at location addr. */
 	case PTRACE_PEEKDATA: {
 		unsigned long tmp;
 		int copied;
@@ -119,7 +119,7 @@
 			 	if(!(mips_cpu.options & MIPS_CPU_FPU)) {
 					fregs = (unsigned long long *)
 						child->thread.fpu.soft.regs;
-				} else 
+				} else
 					if (last_task_used_math == child) {
 						__enable_fpu();
 						save_fp(child);
@@ -132,11 +132,6 @@
 				 * order bits of the values stored in the even
 				 * registers - unless we're using r2k_switch.S.
 				 */
-#ifdef CONFIG_CPU_R3000
-				if (mips_cpu.options & MIPS_CPU_FPU)
-					tmp = *(unsigned long *)(fregs + addr);
-				else
-#endif
 				if (addr & 1)
 					tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32);
 				else
@@ -258,7 +253,7 @@
 			regs->lo = data;
 			break;
 		case FPC_CSR:
-			if (!(mips_cpu.options & MIPS_CPU_FPU)) 
+			if (!(mips_cpu.options & MIPS_CPU_FPU))
 				child->thread.fpu.soft.sr = data;
 			else
 				child->thread.fpu.hard.control = data;
@@ -287,8 +282,8 @@
 		}
 
 	/*
-	 * make the child exit.  Best I can do is send it a sigkill. 
-	 * perhaps it should be put in the status that it wants to 
+	 * make the child exit.  Best I can do is send it a sigkill.
+	 * perhaps it should be put in the status that it wants to
 	 * exit.
 	 */
 	case PTRACE_KILL:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/r4k_switch.S linux-2.4.20/arch/mips/kernel/r4k_switch.S
--- linux-2.4.19/arch/mips/kernel/r4k_switch.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/r4k_switch.S	2002-10-29 11:18:50.000000000 +0000
@@ -46,16 +46,16 @@
 	move	$28, a1
 	CPU_RESTORE_NONSCRATCH($28)
 	addiu	t0, $28, KERNEL_STACK_SIZE-32
-#ifdef CONFIG_SMP	 
+#ifdef CONFIG_SMP
 	mfc0	a3, CP0_CONTEXT
 	la	t1, kernelsp
 	srl	a3, 23
 	sll	a3, 2
 	addu	t1, a3, t1
-	sw	t0, (t1)	
+	sw	t0, (t1)
 #else
 	sw	t0, kernelsp
-#endif 
+#endif
 	mfc0	t1, CP0_STATUS		/* Do we really need this? */
 	li	a3, 0xff00
 	and	t1, a3
@@ -80,6 +80,7 @@
 	li	t3, ST0_CU1
 	or	t0, t3
 	mtc0	t0, CP0_STATUS
+	FPU_ENABLE_HAZARD
 
 	beqz	a0, 2f				# Save floating point state
 	 nor	t3, zero, t3
@@ -129,6 +130,7 @@
 	li	t1, ST0_CU1
 	or	t0, t1
 	mtc0	t0, CP0_STATUS
+	FPU_ENABLE_HAZARD
 
 	li	t1, FPU_DEFAULT
 	ctc1	t1, fcr31
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/scall_o32.S linux-2.4.20/arch/mips/kernel/scall_o32.S
--- linux-2.4.19/arch/mips/kernel/scall_o32.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/scall_o32.S	2002-10-29 11:18:49.000000000 +0000
@@ -38,7 +38,7 @@
 	sll	t0, v0, 2
 	lw	t2, sys_call_table(t0)	# syscall routine
 	lbu	t3, sys_narg_table(v0)	# number of arguments
-	beqz	t2, illegal_syscall;
+	beqz	t2, illegal_syscall
 
 	subu	t0, t3, 5		# 5 or more arguments?
 	sw	a3, PT_R26(sp)		# save a3 for syscall restarting
@@ -47,7 +47,7 @@
 stack_done:
         sw      a3, PT_R26(sp)          # save for syscall restart
 	lw	t0, TASK_PTRACE($28)	# syscall tracing enabled?
-	andi	t0, PT_TRACESYS
+	andi	t0, _PT_TRACESYS
 	bnez	t0, trace_a_syscall
 
 	jalr	t2			# Do The Real Thing (TM)
@@ -61,20 +61,41 @@
 	sw	v0, PT_R0(sp)		# set flag for syscall restarting
 1:	sw	v0, PT_R2(sp)		# result
 
-EXPORT(o32_ret_from_sys_call)
+fast_ret_from_sys_call:
+ret_from_schedule:
 	mfc0	t0, CP0_STATUS		# need_resched and signals atomic test
 	ori	t0, t0, 1
 	xori	t0, t0, 1
 	mtc0	t0, CP0_STATUS
+	SSNOP; SSNOP; SSNOP
 
 	lw	t2, TASK_NEED_RESCHED($28)
-	bnez	t2, o32_reschedule
 	lw	v0, TASK_SIGPENDING($28)
+	bnez	t2, reschedule
 	bnez	v0, signal_return
 restore_all:
 	RESTORE_SOME
 	RESTORE_SP_AND_RET
 
+/* ------------------------------------------------------------------------ */
+
+FEXPORT(ret_from_fork)
+	move	a0, v0			# prev
+	jal	schedule_tail
+	lw	t0, TASK_PTRACE($28)	# syscall tracing enabled?
+	andi	t0, _PT_TRACESYS
+	bnez	t0, tracesys_exit
+
+static_ret_from_sys_call:
+	RESTORE_STATIC
+	j	fast_ret_from_sys_call
+
+/* ------------------------------------------------------------------------ */
+
+/* ret_from_sys_call should be here but is in entry.S.  */
+
+/* ------------------------------------------------------------------------ */
+
 /* Put this behind restore_all for the sake of the branch prediction.  */
 signal_return:
 	.type	signal_return, @function
@@ -87,11 +108,14 @@
 	move	a0, zero
 	move	a1, sp
 	jal	do_signal
+	RESTORE_STATIC
 	b	restore_all
 
-o32_reschedule:
+/* ------------------------------------------------------------------------ */
+
+reschedule:
 	jal	schedule
-	b	o32_ret_from_sys_call
+	b	ret_from_schedule
 
 /* ------------------------------------------------------------------------ */
 
@@ -116,8 +140,9 @@
 	sw	v0, PT_R0(sp)		# set flag for syscall restarting
 1:	sw	v0, PT_R2(sp)		# result
 
+tracesys_exit:
 	jal	syscall_trace
-	j	ret_from_sys_call
+	j	static_ret_from_sys_call
 
 /* ------------------------------------------------------------------------ */
 
@@ -136,7 +161,7 @@
 	bltz	t0, bad_stack		# -> sp is bad
 
 	lw	t0, PT_R29(sp)		# get old user stack pointer
-	la	t1, 3f			# copy 1 to 2 arguments
+	PTR_LA	t1, 3f			# copy 1 to 2 arguments
 	sll	t3, t3, 4
 	subu	t1, t3
 	jr	t1
@@ -150,6 +175,7 @@
 	 */
 	.set    push
 	.set    noreorder
+	.set	nomacro
 1:	lw	t1, 20(t0)		# argument #6 from usp
 	nop
 	sw	t1, 20(sp)
@@ -158,43 +184,58 @@
 	nop
 	sw	t1, 16(sp)
 	nop
-	.set	pop
+3:	.set	pop
 
-3:	j	stack_done		# go back
+	j	stack_done		# go back
 
 	.section __ex_table,"a"
 	PTR	1b,bad_stack
 	PTR	2b,bad_stack
 	.previous
 
+/* ------------------------------------------------------------------------ */
+
 	/*
 	 * The stackpointer for a call with more than 4 arguments is bad.
 	 * We probably should handle this case a bit more drastic.
 	 */
 bad_stack:
-	negu	v0				# error
+	negu	v0			# error
 	sw	v0, PT_R0(sp)
 	sw	v0, PT_R2(sp)
-	li	t0, 1				# set error flag
+	li	t0, 1			# set error flag
 	sw	t0, PT_R7(sp)
-	j	ret_from_sys_call
+	j	fast_ret_from_sys_call
+
+/* ------------------------------------------------------------------------ */
 
 	/*
 	 * The system call does not exist in this kernel
 	 */
 illegal_syscall:
-	li	v0, ENOSYS			# error
+	lw	t0, TASK_PTRACE($28)	# syscall tracing enabled?
+	andi	t0, _PT_TRACESYS
+	beqz	t0, 1f
+
+	SAVE_STATIC
+	jal	syscall_trace
+	li	t0, _PT_TRACESYS
+
+1:	li	v0, ENOSYS		# error
+	sw	v0, PT_R0(sp)		# set flag for syscall restarting
 	sw	v0, PT_R2(sp)
-	li	t0, 1				# set error flag
-	sw	t0, PT_R7(sp)
-	j	ret_from_sys_call
-	END(handle_sys)
+	li	t1, 1			# set error flag
+	sw	t1, PT_R7(sp)
+	bnez	t0, tracesys_exit
 
-	LEAF(mips_atomic_set)
-	andi	v0, a1, 3			# must be word aligned
+	j	fast_ret_from_sys_call
+END(handle_sys)
+
+LEAF(mips_atomic_set)
+	andi	v0, a1, 3		# must be word aligned
 	bnez	v0, bad_alignment
 
-	lw	v1, THREAD_CURDS($28)		# in legal address range?
+	lw	v1, THREAD_CURDS($28)	# in legal address range?
 	addiu	a0, a1, 4
 	or	a0, a0, a1
 	and	a0, a0, v1
@@ -236,19 +277,17 @@
 	.previous
 #endif
 
+	sw	zero, PT_R7(sp)		# success
 	sw	v0, PT_R2(sp)		# result
-1:
 
 	/* Success, so skip usual error handling garbage.  */
 	lw	t0, TASK_PTRACE($28)	# syscall tracing enabled?
-	andi	t0, PT_TRACESYS
-	bnez	t0, 1f
-	b	o32_ret_from_sys_call
+	andi	t0, _PT_TRACESYS
+	beqz	t0, fast_ret_from_sys_call
 
-1:	SAVE_STATIC
+	SAVE_STATIC
 	jal	syscall_trace
-	li	a3, 0			# success
-	j	ret_from_sys_call
+	j	static_ret_from_sys_call
 
 no_mem:	li	v0, -ENOMEM
 	jr	ra
@@ -260,40 +299,40 @@
 bad_alignment:
 	li	v0, -EINVAL
 	jr	ra
-	END(mips_atomic_set)	
+END(mips_atomic_set)
 
-	LEAF(sys_sysmips)
+LEAF(sys_sysmips)
 	beq	a0, MIPS_ATOMIC_SET, mips_atomic_set
 	j	_sys_sysmips
-	END(sys_sysmips)
+END(sys_sysmips)
 
-	LEAF(sys_syscall)
-	lw	t0, PT_R29(sp)			# user sp
+LEAF(sys_syscall)
+	lw	t0, PT_R29(sp)		# user sp
 
 	sltu	v0, a0, __NR_Linux + __NR_Linux_syscalls + 1
 	beqz	v0, enosys
 
-	sll	v0, t1, 2
+	sll	v0, a0, 2
 	la	v1, sys_syscall
-	lw	t2, sys_call_table(v0)		# function pointer
-	lbu	t4, sys_narg_table(t1)		# number of arguments
+	lw	t2, sys_call_table(v0)	# function pointer
+	lbu	t4, sys_narg_table(a0)	# number of arguments
 
 	li	v0, -EINVAL
-	beq	t2, v1, out			# do not recurse
+	beq	t2, v1, out		# do not recurse
 
-	beqz	t2, enosys			# null function pointer?
+	beqz	t2, enosys		# null function pointer?
 
-	andi	v0, t0, 0x3			# unaligned stack pointer?
+	andi	v0, t0, 0x3		# unaligned stack pointer?
 	bnez	v0, sigsegv
 
-	addu	v0, t0, 16			# v0 = usp + 16
-	addu	t1, v0, 12			# 3 32-bit arguments
+	addu	v0, t0, 16		# v0 = usp + 16
+	addu	t1, v0, 12		# 3 32-bit arguments
 	lw	v1, THREAD_CURDS($28)
 	or	v0, v0, t1
 	and	v1, v1, v0
 	bltz	v1, efault
 
-	move	a0, a1				# shit argument registers
+	move	a0, a1			# shift argument registers
 	move	a1, a2
 	move	a2, a3
 
@@ -307,11 +346,11 @@
 	.word	3b, efault
 	.previous
 
-	sw	t3, 16(sp)			# put into new stackframe
+	sw	t3, 16(sp)		# put into new stackframe
 	sw	t4, 20(sp)
 
-	bnez	t4, 1f				# zero arguments?
-	addu	a0, sp, 32			# then pass sp in a0
+	bnez	t4, 1f			# zero arguments?
+	addu	a0, sp, 32		# then pass sp in a0
 1:
 
 	sw	t3, 16(sp)
@@ -331,4 +370,4 @@
 efault:	li	v0, -EFAULT
 
 out:	jr	ra
-	END(sys_syscall)
+END(sys_syscall)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/setup.c linux-2.4.20/arch/mips/kernel/setup.c
--- linux-2.4.19/arch/mips/kernel/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/setup.c	2002-10-29 11:18:34.000000000 +0000
@@ -44,22 +44,15 @@
 #endif
 
 /*
- * Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
- * the implementation of the "wait" feature differs between CPU families. This
- * points to the function that implements CPU specific wait. 
- * The wait instruction stops the pipeline and reduces the power consumption of
- * the CPU very much.
- */
-void (*cpu_wait)(void) = NULL;
-
-/*
  * There are several bus types available for MIPS machines.  "RISC PC"
  * type machines have ISA, EISA, VLB or PCI available, DECstations
  * have Turbochannel or Q-Bus, SGI has GIO, there are lots of VME
  * boxes ...
  * This flag is set if a EISA slots are available.
  */
+#ifdef CONFIG_EISA
 int EISA_bus = 0;
+#endif
 
 struct screen_info screen_info;
 
@@ -122,403 +115,9 @@
 static struct resource code_resource = { "Kernel code" };
 static struct resource data_resource = { "Kernel data" };
 
-static inline void check_wait(void)
-{
-	printk("Checking for 'wait' instruction... ");
-	switch(mips_cpu.cputype) {
-	case CPU_R3081:
-	case CPU_R3081E:
-		cpu_wait = r3081_wait;
-		printk(" available.\n");
-		break;
-	case CPU_TX3927:
-	case CPU_TX39XX:
-		cpu_wait = r39xx_wait;
-		printk(" available.\n");
-		break;
-	case CPU_R4200: 
-/*	case CPU_R4300: */
-	case CPU_R4600: 
-	case CPU_R4640: 
-	case CPU_R4650: 
-	case CPU_R4700: 
-	case CPU_R5000: 
-	case CPU_NEVADA:
-	case CPU_RM7000:
-	case CPU_TX49XX:
-	case CPU_4KC:
-	case CPU_4KEC:
-	case CPU_4KSC:
-	case CPU_5KC:
-/*	case CPU_20KC:*/
-		cpu_wait = r4k_wait;
-		printk(" available.\n");
-		break;
-	default:
-		printk(" unavailable.\n");
-		break;
-	}
-}
-
-void __init check_bugs(void)
-{
-	check_wait();
-}
-
-/*
- * Probe whether cpu has config register by trying to play with
- * alternate cache bit and see whether it matters.
- * It's used by cpu_probe to distinguish between R3000A and R3081.
- */
-static inline int cpu_has_confreg(void)
-{
-#ifdef CONFIG_CPU_R3000
-	extern unsigned long r3k_cache_size(unsigned long);
-	unsigned long size1, size2; 
-	unsigned long cfg = read_32bit_cp0_register(CP0_CONF);
-
-	size1 = r3k_cache_size(ST0_ISC);
-	write_32bit_cp0_register(CP0_CONF, cfg^CONF_AC);
-	size2 = r3k_cache_size(ST0_ISC);
-	write_32bit_cp0_register(CP0_CONF, cfg);
-	return size1 != size2;
-#else
-	return 0;
-#endif
-}
-
-/*
- * Get the FPU Implementation/Revision.
- */
-static inline unsigned long cpu_get_fpu_id(void)
-{
-	unsigned long tmp, fpu_id;
-
-	tmp = read_32bit_cp0_register(CP0_STATUS);
-	__enable_fpu();
-	fpu_id = read_32bit_cp1_register(CP1_REVISION);
-	write_32bit_cp0_register(CP0_STATUS, tmp);
-	return fpu_id;
-}
-
-/*
- * Check the CPU has an FPU the official way.
- */
-static inline int cpu_has_fpu(void)
-{
-	return ((cpu_get_fpu_id() & 0xff00) != FPIR_IMP_NONE);
-}
-
-/* declaration of the global struct */
-struct mips_cpu mips_cpu = {
-    processor_id:	PRID_IMP_UNKNOWN,
-    fpu_id:		FPIR_IMP_NONE,
-    cputype:		CPU_UNKNOWN
-};
-
-/* Shortcut for assembler access to mips_cpu.options */
-int *cpuoptions = &mips_cpu.options;
-
-#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4KTLB \
-		| MIPS_CPU_COUNTER | MIPS_CPU_CACHE_CDEX)
-
-static inline void cpu_probe(void)
-{
-#ifdef CONFIG_CPU_MIPS32
-	unsigned long config0 = read_32bit_cp0_register(CP0_CONFIG);
-	unsigned long config1;
-
-        if (config0 & (1 << 31)) {
-		/* MIPS32 compliant CPU. Read Config 1 register. */
-		mips_cpu.isa_level = MIPS_CPU_ISA_M32;
-		mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | 
-			MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | MIPS_CPU_DIVEC;
-		config1 = read_mips32_cp0_config1();
-		if (config1 & (1 << 3))
-			mips_cpu.options |= MIPS_CPU_WATCH;
-		if (config1 & (1 << 2))
-			mips_cpu.options |= MIPS_CPU_MIPS16;
-		if (config1 & (1 << 1))
-			mips_cpu.options |= MIPS_CPU_EJTAG;
-		if (config1 & 1)
-			mips_cpu.options |= MIPS_CPU_FPU;
-		mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT;
-	}
-#endif
-	mips_cpu.processor_id = read_32bit_cp0_register(CP0_PRID);
-	switch (mips_cpu.processor_id & 0xff0000) {
-	case PRID_COMP_LEGACY:
-		switch (mips_cpu.processor_id & 0xff00) {
-		case PRID_IMP_R2000:
-			mips_cpu.cputype = CPU_R2000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_I;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_NOFPUEX;
-			if (cpu_has_fpu())
-				mips_cpu.options |= MIPS_CPU_FPU;
-			mips_cpu.tlbsize = 64;
-			break;
-		case PRID_IMP_R3000:
-			if ((mips_cpu.processor_id & 0xff) == PRID_REV_R3000A)
-				if (cpu_has_confreg())
-					mips_cpu.cputype = CPU_R3081E;
-				else
-					mips_cpu.cputype = CPU_R3000A;
-			else
-				mips_cpu.cputype = CPU_R3000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_I;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_NOFPUEX;
-			if (cpu_has_fpu())
-				mips_cpu.options |= MIPS_CPU_FPU;
-			mips_cpu.tlbsize = 64;
-			break;
-		case PRID_IMP_R4000:
-			if ((mips_cpu.processor_id & 0xff) == PRID_REV_R4400)
-				mips_cpu.cputype = CPU_R4400SC;
-			else
-				mips_cpu.cputype = CPU_R4000SC;
-			mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR | MIPS_CPU_WATCH |
-			                   MIPS_CPU_VCE;
-			mips_cpu.tlbsize = 48;
-			break;
-                case PRID_IMP_VR41XX:
-                        mips_cpu.cputype = CPU_VR41XX;
-                        mips_cpu.isa_level = MIPS_CPU_ISA_III;
-                        mips_cpu.options = R4K_OPTS;
-                        mips_cpu.tlbsize = 32;
-                        break;
-		case PRID_IMP_R4300:
-			mips_cpu.cputype = CPU_R4300;
-			mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-					   MIPS_CPU_32FPR;
-			mips_cpu.tlbsize = 32;
-			break;
-		case PRID_IMP_R4600:
-			mips_cpu.cputype = CPU_R4600;
-			mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
-			mips_cpu.tlbsize = 48;
-			break;
-		#if 0
- 		case PRID_IMP_R4650:
-			/*
-			 * This processor doesn't have an MMU, so it's not
-			 * "real easy" to run Linux on it. It is left purely
-			 * for documentation.  Commented out because it shares
-			 * it's c0_prid id number with the TX3900.
-			 */
-	 		mips_cpu.cputype = CPU_R4650;
-		 	mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
-		        mips_cpu.tlbsize = 48;
-			break;
-		#endif
-		case PRID_IMP_TX39:
-			mips_cpu.isa_level = MIPS_CPU_ISA_I;
-			mips_cpu.options = MIPS_CPU_TLB;
-
-			if ((mips_cpu.processor_id & 0xf0) ==
-			    (PRID_REV_TX3927 & 0xf0)) {
-				mips_cpu.cputype = CPU_TX3927;
-				mips_cpu.tlbsize = 64;
-				mips_cpu.icache.ways = 2;
-				mips_cpu.dcache.ways = 2;
-			} else {
-				switch (mips_cpu.processor_id & 0xff) {
-				case PRID_REV_TX3912:
-					mips_cpu.cputype = CPU_TX3912;
-					mips_cpu.tlbsize = 32;
-					break;
-				case PRID_REV_TX3922:
-					mips_cpu.cputype = CPU_TX3922;
-					mips_cpu.tlbsize = 64;
-					break;
-				default:
-					mips_cpu.cputype = CPU_UNKNOWN;
-					break;
-				}
-			}
-			break;
-		case PRID_IMP_R4700:
-			mips_cpu.cputype = CPU_R4700;
-			mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR;
-			mips_cpu.tlbsize = 48;
-			break;
-		case PRID_IMP_TX49:
-			mips_cpu.cputype = CPU_TX49XX;
-			mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR;
-			mips_cpu.tlbsize = 48;
-			mips_cpu.icache.ways = 4;
-			mips_cpu.dcache.ways = 4;
-			break;
-		case PRID_IMP_R5000:
-			mips_cpu.cputype = CPU_R5000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV; 
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR;
-			mips_cpu.tlbsize = 48;
-			break;
-		case PRID_IMP_R5432:
-			mips_cpu.cputype = CPU_R5432;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV; 
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR | MIPS_CPU_WATCH;
-			mips_cpu.tlbsize = 48;
-			break;
-		case PRID_IMP_R5500:
-			mips_cpu.cputype = CPU_R5500;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV; 
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR | MIPS_CPU_WATCH;
-			mips_cpu.tlbsize = 48;
-			break;
-		case PRID_IMP_NEVADA:
-			mips_cpu.cputype = CPU_NEVADA;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV; 
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR | MIPS_CPU_DIVEC;
-			mips_cpu.tlbsize = 48;
-			mips_cpu.icache.ways = 2;
-			mips_cpu.dcache.ways = 2;
-			break;
-		case PRID_IMP_R6000:
-			mips_cpu.cputype = CPU_R6000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_II;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU;
-			mips_cpu.tlbsize = 32;
-			break;
-		case PRID_IMP_R6000A:
-			mips_cpu.cputype = CPU_R6000A;
-			mips_cpu.isa_level = MIPS_CPU_ISA_II;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU;
-			mips_cpu.tlbsize = 32;
-			break;
-		case PRID_IMP_RM7000:
-			mips_cpu.cputype = CPU_RM7000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR;
-			/*
-			 * Undocumented RM7000:  Bit 29 in the info register of
-			 * the RM7000 v2.0 indicates if the TLB has 48 or 64
-			 * entries.
-			 *
-			 * 29      1 =>    64 entry JTLB
-			 *         0 =>    48 entry JTLB
-			 */
-			mips_cpu.tlbsize = (get_info() & (1 << 29)) ? 64 : 48;
-			break;
-		case PRID_IMP_R8000:
-			mips_cpu.cputype = CPU_R8000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
-				           MIPS_CPU_FPU | MIPS_CPU_32FPR;
-			mips_cpu.tlbsize = 384;      /* has wierd TLB: 3-way x 128 */
-			break;
-		case PRID_IMP_R10000:
-			mips_cpu.cputype = CPU_R10000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | 
-				           MIPS_CPU_FPU | MIPS_CPU_32FPR | 
-				           MIPS_CPU_COUNTER | MIPS_CPU_WATCH;
-			mips_cpu.tlbsize = 64;
-			break;
-		case PRID_IMP_R12000:
-			mips_cpu.cputype = CPU_R12000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | 
-				           MIPS_CPU_FPU | MIPS_CPU_32FPR | 
-				           MIPS_CPU_COUNTER | MIPS_CPU_WATCH;
-			mips_cpu.tlbsize = 64;
-			break;
-		default:
-			mips_cpu.cputype = CPU_UNKNOWN;
-			break;
-		}
-		break;
-#ifdef CONFIG_CPU_MIPS32
-	case PRID_COMP_MIPS:
-		switch (mips_cpu.processor_id & 0xff00) {
-		case PRID_IMP_4KC:
-			mips_cpu.cputype = CPU_4KC;
-			break;
-		case PRID_IMP_4KEC:
-			mips_cpu.cputype = CPU_4KEC;
-			break;
-		case PRID_IMP_4KSC:
-			mips_cpu.cputype = CPU_4KSC;
-			break;
-		case PRID_IMP_5KC:
-			mips_cpu.cputype = CPU_5KC;
-			mips_cpu.isa_level = MIPS_CPU_ISA_M64;
-			break;
-		case PRID_IMP_20KC:
-			mips_cpu.cputype = CPU_20KC;
-			mips_cpu.isa_level = MIPS_CPU_ISA_M64;
-			break;
-		default:
-			mips_cpu.cputype = CPU_UNKNOWN;
-			break;
-		}		
-		break;
-	case PRID_COMP_ALCHEMY:
-		switch (mips_cpu.processor_id & 0xff00) {
-		case PRID_IMP_AU1_REV1:
-		case PRID_IMP_AU1_REV2:
-			if (mips_cpu.processor_id & 0xff000000)
-				mips_cpu.cputype = CPU_AU1500;
-			else
-				mips_cpu.cputype = CPU_AU1000;
-			break;
-		default:
-			mips_cpu.cputype = CPU_UNKNOWN;
-			break;
-		}
-		break;
-#endif /* CONFIG_CPU_MIPS32 */
-	case PRID_COMP_SIBYTE:
-		switch (mips_cpu.processor_id & 0xff00) {
-		case PRID_IMP_SB1:
-			mips_cpu.cputype = CPU_SB1;
-			mips_cpu.isa_level = MIPS_CPU_ISA_M64;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
-			                   MIPS_CPU_COUNTER | MIPS_CPU_DIVEC |
-			                   MIPS_CPU_MCHECK;
-#ifndef CONFIG_SB1_PASS_1_WORKAROUNDS
-			/* FPU in pass1 is known to have issues. */
-			mips_cpu.options |= MIPS_CPU_FPU;
-#endif
-			break;
-		default:
-			mips_cpu.cputype = CPU_UNKNOWN;
-			break;
-		}
-		break;
-	default:
-		mips_cpu.cputype = CPU_UNKNOWN;
-	}
-	if (mips_cpu.options & MIPS_CPU_FPU)
-		mips_cpu.fpu_id = cpu_get_fpu_id();
-}
-
-static inline void cpu_report(void)
-{
-	printk("CPU revision is: %08x\n", mips_cpu.processor_id);
-	if (mips_cpu.options & MIPS_CPU_FPU)
-		printk("FPU revision is: %08x\n", mips_cpu.fpu_id);
-}
-
 asmlinkage void __init
 init_arch(int argc, char **argv, char **envp, int *prom_vec)
 {
-	unsigned int s;
-
 	/* Determine which MIPS variant we are running on. */
 	cpu_probe();
 
@@ -650,10 +249,14 @@
 	void ip22_setup(void);
         void ev96100_setup(void);
 	void malta_setup(void);
+	void sead_setup(void);
 	void ikos_setup(void);
 	void momenco_ocelot_setup(void);
+	void momenco_ocelot_g_setup(void);
 	void nino_setup(void);
 	void nec_osprey_setup(void);
+	void nec_eagle_setup(void);
+	void zao_capcella_setup(void);
 	void jmr3927_setup(void);
  	void it8172_setup(void);
 	void swarm_setup(void);
@@ -679,13 +282,13 @@
 #ifdef CONFIG_PC_KEYB
 	kbd_ops = &no_kbd_ops;
 #endif
-	
+
 	rtc_ops = &no_rtc_ops;
 
 	switch(mips_machgroup)
 	{
 #ifdef CONFIG_BAGET_MIPS
-	case MACH_GROUP_BAGET: 
+	case MACH_GROUP_BAGET:
 		baget_setup();
 		break;
 #endif
@@ -719,6 +322,16 @@
 		momenco_ocelot_setup();
 		break;
 #endif
+#ifdef CONFIG_MOMENCO_OCELOT_G
+	case MACH_GROUP_MOMENCO:
+		momenco_ocelot_g_setup();
+		break;
+#endif
+#ifdef CONFIG_MIPS_SEAD
+	case MACH_GROUP_UNKNOWN:
+		sead_setup();
+		break;
+#endif
 #ifdef CONFIG_SGI_IP22
 	/* As of now this is only IP22.  */
 	case MACH_GROUP_SGI:
@@ -745,9 +358,25 @@
                ddb_setup();
                break;
 #endif
-#ifdef CONFIG_NEC_OSPREY
+#ifdef CONFIG_CPU_VR41XX
 	case MACH_GROUP_NEC_VR41XX:
-		nec_osprey_setup();
+		switch (mips_machtype) {
+#ifdef CONFIG_NEC_OSPREY
+		case MACH_NEC_OSPREY:
+			nec_osprey_setup();
+			break;
+#endif
+#ifdef CONFIG_NEC_EAGLE
+		case MACH_NEC_EAGLE:
+			nec_eagle_setup();
+			break;
+#endif
+#ifdef CONFIG_ZAO_CAPCELLA
+		case MACH_ZAO_CAPCELLA:
+			zao_capcella_setup();
+			break;
+#endif
+		}
 		break;
 #endif
 #ifdef CONFIG_MIPS_EV96100
@@ -765,7 +394,7 @@
 	case  MACH_GROUP_GLOBESPAN:
 		it8172_setup();
 		break;
-#endif  
+#endif
 #ifdef CONFIG_NINO
 	case MACH_GROUP_PHILIPS:
 		nino_setup();
@@ -776,6 +405,11 @@
 		au1000_setup();
 		break;
 #endif
+#ifdef CONFIG_MIPS_PB1100
+	case MACH_GROUP_ALCHEMY:
+		au1100_setup();
+		break;
+#endif
 #ifdef CONFIG_MIPS_PB1500
 	case MACH_GROUP_ALCHEMY:
 		au1500_setup();
@@ -815,8 +449,8 @@
 #define MAXMEM_PFN	PFN_DOWN(MAXMEM)
 
 #ifdef CONFIG_BLK_DEV_INITRD
-	tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8; 
-	if (tmp < (unsigned long)&_end) 
+	tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8;
+	if (tmp < (unsigned long)&_end)
 		tmp += PAGE_SIZE;
 	initrd_header = (unsigned long *)tmp;
 	if (initrd_header[0] == 0x494E5244) {
@@ -952,17 +586,17 @@
 	}
 	initrd_below_start_ok = 1;
 	if (initrd_start) {
-		unsigned long initrd_size = ((unsigned char *)initrd_end) - ((unsigned char *)initrd_start); 
+		unsigned long initrd_size = ((unsigned char *)initrd_end) - ((unsigned char *)initrd_start);
 		printk("Initial ramdisk at: 0x%p (%lu bytes)\n",
-		       (void *)initrd_start, 
+		       (void *)initrd_start,
 		       initrd_size);
-		if ((void *)initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) {
+		if (PHYSADDR(initrd_end) > PFN_PHYS(max_low_pfn)) {
 			printk("initrd extends beyond end of memory "
 			       "(0x%lx > 0x%p)\ndisabling initrd\n",
-			       initrd_end,
-			       phys_to_virt(PFN_PHYS(max_low_pfn)));
+			       PHYSADDR(initrd_end),
+			       PFN_PHYS(max_low_pfn));
 			initrd_start = initrd_end = 0;
-		} 
+		}
 	}
 #endif /* CONFIG_BLK_DEV_INITRD  */
 
@@ -1013,25 +647,6 @@
 	}
 }
 
-void r3081_wait(void) 
-{
-	unsigned long cfg = read_32bit_cp0_register(CP0_CONF);
-	write_32bit_cp0_register(CP0_CONF, cfg|CONF_HALT);
-}
-
-void r39xx_wait(void)
-{
-	unsigned long cfg = read_32bit_cp0_register(CP0_CONF);
-	write_32bit_cp0_register(CP0_CONF, cfg|TX39_CONF_HALT);
-}
-
-void r4k_wait(void)
-{
-	__asm__(".set\tmips3\n\t"
-		"wait\n\t"
-		".set\tmips0");
-}
-
 static int __init fpu_disable(char *s)
 {
 	mips_cpu.options &= ~MIPS_CPU_FPU;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/signal.c linux-2.4.20/arch/mips/kernel/signal.c
--- linux-2.4.19/arch/mips/kernel/signal.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/signal.c	2002-10-29 11:18:49.000000000 +0000
@@ -17,14 +17,14 @@
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/wait.h>
-#include <linux/ptrace.h>
 #include <linux/unistd.h>
 
 #include <asm/asm.h>
 #include <asm/bitops.h>
 #include <asm/cpu.h>
+#include <asm/offset.h>
 #include <asm/pgalloc.h>
-#include <asm/stackframe.h>
+#include <asm/ptrace.h>
 #include <asm/uaccess.h>
 #include <asm/ucontext.h>
 
@@ -190,7 +190,7 @@
 	u64 *pfreg = &current->thread.fpu.soft.regs[0];
 	int err = 0;
 
-	/* 
+	/*
 	 * Copy all 32 64-bit values, for two reasons.  First, the R3000 and
 	 * R4000/MIPS32 kernels use the thread FP register storage differently,
 	 * such that a full copy is essentially necessary to support both.
@@ -416,15 +416,15 @@
 		goto out;
 
 	/* There exists FP thread state that may be trashed by signal */
-	if (owned_fp) {	
+	if (owned_fp) {
 		/* fp is active.  Save context from FPU */
 		err |= save_fp_context(sc);
 		goto out;
 	}
 
-	/* 
-	 * Someone else has FPU. 
-	 * Copy Thread context into signal context 
+	/*
+	 * Someone else has FPU.
+	 * Copy Thread context into signal context
 	 */
 	err |= save_thread_fp_context(sc);
 
@@ -443,7 +443,7 @@
 	/* Default to using normal stack */
 	sp = regs->regs[29];
 
-	/* 
+	/*
  	 * FPU emulator may have it's own trampoline active just
  	 * above the user stack, 16-bytes before the next lowest
  	 * 16 byte boundary.  Try to avoid trashing it.
@@ -508,8 +508,9 @@
 	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
 
 #if DEBUG_SIG
-	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%p ra=0x%p\n",
-	       current->comm, current->pid, frame, regs->cp0_epc, frame->code);
+	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
+	       current->comm, current->pid,
+	       frame, regs->cp0_epc, frame->sf_code);
 #endif
         return;
 
@@ -583,8 +584,9 @@
 	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
 
 #if DEBUG_SIG
-	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%p ra=0x%p\n",
-	       current->comm, current->pid, frame, regs->cp0_epc, frame->code);
+	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
+	       current->comm, current->pid,
+	       frame, regs->cp0_epc, frame->rs_code);
 #endif
 	return;
 
@@ -708,7 +710,7 @@
 				continue;
 
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
@@ -732,10 +734,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/smp.c linux-2.4.20/arch/mips/kernel/smp.c
--- linux-2.4.19/arch/mips/kernel/smp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/smp.c	2002-10-29 11:18:34.000000000 +0000
@@ -8,7 +8,7 @@
  * 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.
@@ -17,17 +17,18 @@
  * Copyright (C) 2000, 2001 Ralf Baechle
  * Copyright (C) 2000, 2001 Silicon Graphics, Inc.
  * Copyright (C) 2000, 2001 Broadcom Corporation
- */ 
+ */
+#include <linux/config.h>
 #include <linux/cache.h>
+#include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/threads.h>
-#include <linux/time.h>
 #include <linux/module.h>
+#include <linux/time.h>
 #include <linux/timex.h>
 #include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
 
 #include <asm/atomic.h>
 #include <asm/cpu.h>
@@ -36,23 +37,22 @@
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 #include <asm/mmu_context.h>
-#include <asm/delay.h>
 #include <asm/smp.h>
 
-/* Ze Big Kernel Lock! */
+/* The 'big kernel lock' */
 spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
-int smp_threads_ready;
+int smp_threads_ready;	/* Not used */
 atomic_t smp_commenced = ATOMIC_INIT(0);
-int smp_num_cpus = 1;			/* Number that came online.  */
-cpumask_t cpu_online_map;		/* Bitmask of currently online CPUs */
-int __cpu_number_map[NR_CPUS];
-int __cpu_logical_map[NR_CPUS];
 struct cpuinfo_mips cpu_data[NR_CPUS];
-void (*volatile smp_cpu0_finalize)(void);
 
 // static atomic_t cpus_booted = ATOMIC_INIT(0);
 atomic_t cpus_booted = ATOMIC_INIT(0);
 
+int smp_num_cpus = 1;			/* Number that came online.  */
+cpumask_t cpu_online_map;		/* Bitmask of currently online CPUs */
+int __cpu_number_map[NR_CPUS];
+int __cpu_logical_map[NR_CPUS];
+cycles_t cacheflush_time;
 
 /* These are defined by the board-specific code. */
 
@@ -65,13 +65,13 @@
 
 /*
  * Clear all undefined state in the cpu, set up sp and gp to the passed
- * values, and kick the cpu into smp_bootstrap(); 
+ * values, and kick the cpu into smp_bootstrap();
  */
 void prom_boot_secondary(int cpu, unsigned long sp, unsigned long gp);
 
 /*
  *  After we've done initial boot, this function is called to allow the
- *  board code to clean up state, if needed 
+ *  board code to clean up state, if needed
  */
 void prom_init_secondary(void);
 
@@ -81,6 +81,21 @@
  */
 int prom_setup_smp(void);
 
+void prom_smp_finish(void);
+
+static void smp_tune_scheduling(void)
+{
+}
+
+void __init smp_callin(void)
+{
+#if 0
+	calibrate_delay();
+	smp_store_cpu_info(cpuid);
+#endif
+}
+
+#ifndef CONFIG_SGI_IP27
 /*
  * Hook for doing final board-specific setup after the generic smp setup
  * is done
@@ -96,7 +111,6 @@
 	 * XXX parity protection should be folded in here when it's converted
 	 * to an option instead of something based on .cputype
 	 */
-
 	pgd_current[cpu] = init_mm.pgd;
 	cpu_data[cpu].udelay_val = loops_per_jiffy;
 	prom_smp_finish();
@@ -106,6 +120,7 @@
 	while (!atomic_read(&smp_commenced));
 	cpu_idle();
 }
+#endif /* CONFIG_SGI_IP27 */
 
 void __init smp_commence(void)
 {
@@ -113,6 +128,11 @@
 	atomic_set(&smp_commenced, 1);
 }
 
+/*
+ * this function sends a 'reschedule' IPI to another CPU.
+ * it goes straight through and wastes no time serializing
+ * anything. Worst case is that we lose a reschedule ...
+ */
 void smp_send_reschedule(int cpu)
 {
 	core_send_ipi(cpu, SMP_RESCHEDULE_YOURSELF);
@@ -123,11 +143,17 @@
 struct call_data_struct *call_data;
 
 /*
- * The caller of this wants the passed function to run on every cpu.  If wait
- * is set, wait until all cpus have finished the function before returning.
- * The lock is here to protect the call structure.
+ * Run a function on all other CPUs.
+ *  <func>      The function to run. This must be fast and non-blocking.
+ *  <info>      An arbitrary pointer to pass to the function.
+ *  <retry>     If true, keep retrying until ready.
+ *  <wait>      If true, wait until function has completed on other CPUs.
+ *  [RETURNS]   0 on success, else a negative status code.
+ *
+ * Does not return until remote CPUs are nearly ready to execute <func>
+ * or are or have executed.
  */
-int smp_call_function (void (*func) (void *info), void *info, int retry, 
+int smp_call_function (void (*func) (void *info), void *info, int retry,
 								int wait)
 {
 	struct call_data_struct data;
@@ -174,14 +200,14 @@
 
 	irq_enter(cpu, 0);	/* XXX choose an irq number? */
 	/*
-	 * Notify initiating CPU that I've grabbed the data
-	 * and am about to execute the function
+	 * Notify initiating CPU that I've grabbed the data and am
+	 * about to execute the function.
 	 */
 	mb();
 	atomic_inc(&call_data->started);
 
 	/*
-	 * At this point the info structure may be out of scope unless wait==1
+	 * At this point the info structure may be out of scope unless wait==1.
 	 */
 	(*func)(info);
 	if (wait) {
@@ -193,18 +219,23 @@
 
 static void stop_this_cpu(void *dummy)
 {
-	int cpu = smp_processor_id();
-	if (cpu)
-		for (;;);		/* XXX Use halt like i386 */
-
-	/* XXXKW this isn't quite there yet */
-	while (!smp_cpu0_finalize) ;
-	smp_cpu0_finalize();
+	/*
+	 * Remove this CPU:
+	 */
+	clear_bit(smp_processor_id(), &cpu_online_map);
+	/* May need to service _machine_restart IPI */
+	__sti();
+	/* XXXKW wait if available? */
+	for (;;);
 }
 
 void smp_send_stop(void)
 {
 	smp_call_function(stop_this_cpu, NULL, 1, 0);
+	/*
+	 * Fix me: this prevents future IPIs, for example that would
+	 * cause a restart to happen on CPU0.
+	 */
 	smp_num_cpus = 1;
 }
 
@@ -231,11 +262,11 @@
 }
 
 /*
- * The following tlb flush calls are invoked when old translations are 
+ * The following tlb flush calls are invoked when old translations are
  * being torn down, or pte attributes are changing. For single threaded
  * address spaces, a new context is obtained on the current cpu, and tlb
  * context on other cpus are invalidated to force a new context allocation
- * at switch_mm time, should the mm ever be used on other cpus. For 
+ * at switch_mm time, should the mm ever be used on other cpus. For
  * multithreaded address spaces, intercpu interrupts have to be sent.
  * Another case where intercpu interrupts are required is when the target
  * mm might be active on another cpu (eg debuggers doing the flushes on
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/syscall.c linux-2.4.20/arch/mips/kernel/syscall.c
--- linux-2.4.19/arch/mips/kernel/syscall.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/syscall.c	2002-10-29 11:18:35.000000000 +0000
@@ -221,7 +221,7 @@
 		return -EFAULT;
 	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
 		return -EFAULT;
-  
+
 	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
 	error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
 	error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/syscalls.h linux-2.4.20/arch/mips/kernel/syscalls.h
--- linux-2.4.19/arch/mips/kernel/syscalls.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/syscalls.h	2002-10-29 11:18:32.000000000 +0000
@@ -221,7 +221,7 @@
 SYS(sys_capget, 2)
 SYS(sys_capset, 2)				/* 4205 */
 SYS(sys_sigaltstack, 0)
-SYS(sys_sendfile, 3)
+SYS(sys_sendfile, 4)
 SYS(sys_ni_syscall, 0)
 SYS(sys_ni_syscall, 0)
 SYS(sys_mmap2, 6)				/* 4210 */
@@ -238,18 +238,18 @@
 SYS(sys_ni_syscall, 0)
 SYS(sys_gettid, 0)
 SYS(sys_readahead, 5)
-SYS(sys_ni_syscall, 0)				/* reserved for setxattr */
-SYS(sys_ni_syscall, 0)				/* 4225 res. for lsetxattr */
-SYS(sys_ni_syscall, 0)				/* reserved for fsetxattr */
-SYS(sys_ni_syscall, 0)				/* reserved for getxattr */
-SYS(sys_ni_syscall, 0)				/* reserved for lgetxattr */
-SYS(sys_ni_syscall, 0)				/* reserved for fgetxattr */
-SYS(sys_ni_syscall, 0)				/* 4230 res. for listxattr */
-SYS(sys_ni_syscall, 0)				/* reserved for llistxattr */
-SYS(sys_ni_syscall, 0)				/* reserved for flistxattr */
-SYS(sys_ni_syscall, 0)				/* reserved for removexattr */
-SYS(sys_ni_syscall, 0)				/* reserved for lremovexattr */
-SYS(sys_ni_syscall, 0)				/* 4235 res. for fremovexattr */
+SYS(sys_setxattr, 5)
+SYS(sys_lsetxattr, 5)				/* 4225 */
+SYS(sys_fsetxattr, 5)
+SYS(sys_getxattr, 4)
+SYS(sys_lgetxattr, 4)
+SYS(sys_fgetxattr, 4)
+SYS(sys_listxattr, 3)				/* 4230 */
+SYS(sys_llistxattr, 3)
+SYS(sys_flistxattr, 3)
+SYS(sys_removexattr, 2)
+SYS(sys_lremovexattr, 2)
+SYS(sys_fremovexattr, 2)			/* 4235 */
 SYS(sys_tkill, 2)
 SYS(sys_ni_syscall, 0)				/* res. for sendfile64 */
 SYS(sys_ni_syscall, 0)				/* res. for futex */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/sysirix.c linux-2.4.20/arch/mips/kernel/sysirix.c
--- linux-2.4.19/arch/mips/kernel/sysirix.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/sysirix.c	2002-10-29 11:18:50.000000000 +0000
@@ -109,7 +109,7 @@
 		if (error)
 			error = (task->run_list.next != NULL);
 		read_unlock(&tasklist_lock);
-		/* Can _your_ OS find this out that fast? */ 
+		/* Can _your_ OS find this out that fast? */
 		break;
 	}
 
@@ -332,7 +332,7 @@
 		       current->comm, current->pid, name, value, retval);
 /*		if (retval == PROM_ENOENT)
 		  	retval = -ENOENT; */
-		break;				   
+		break;
 	}
 #endif
 
@@ -505,7 +505,7 @@
 		}
 		break;
 	}
-	
+
 	default:
 		printk("irix_syssgi: Unsupported command %d\n", (int)cmd);
 		retval = -EINVAL;
@@ -1071,7 +1071,7 @@
 		if (flags & IRIX_MAP_AUTOGROW) {
 			unsigned long old_pos;
 			long max_size = offset + len;
-			
+
 			if (max_size > file->f_dentry->d_inode->i_size) {
 				old_pos = sys_lseek (fd, max_size - 1, 0);
 				sys_write (fd, "", 1);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/sysmips.c linux-2.4.20/arch/mips/kernel/sysmips.c
--- linux-2.4.19/arch/mips/kernel/sysmips.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/sysmips.c	2002-10-29 11:18:35.000000000 +0000
@@ -61,13 +61,13 @@
 		name = (char *) arg1;
 
 		len = strncpy_from_user(nodename, name, sizeof(nodename));
-		if (len < 0) 
+		if (len < 0)
 			return -EFAULT;
 
 		down_write(&uts_sem);
 		strncpy(system_utsname.nodename, name, len);
+		system_utsname.nodename[len] = '\0';
 		up_write(&uts_sem);
-		system_utsname.nodename[len] = '\0'; 
 		return 0;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/time.c linux-2.4.20/arch/mips/kernel/time.c
--- linux-2.4.19/arch/mips/kernel/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/time.c	2002-10-29 11:18:39.000000000 +0000
@@ -2,8 +2,8 @@
  * Copyright 2001 MontaVista Software Inc.
  * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
  *
- * Common time service routines for MIPS machines. See 
- * Documents/MIPS/README.txt. 
+ * Common time service routines for MIPS machines. See
+ * Documents/MIPS/README.txt.
  *
  * 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
@@ -289,9 +289,9 @@
 
 /*
  * local_timer_interrupt() does profiling and process accounting
- * on a per-CPU basis.  
+ * on a per-CPU basis.
  *
- * In UP mode, it is invoked from the (global) timer_interrupt.  
+ * In UP mode, it is invoked from the (global) timer_interrupt.
  *
  * In SMP mode, it might invoked by per-CPU timer interrupt, or
  * a broadcasted inter-processor interrupt which itself is triggered
@@ -368,7 +368,7 @@
 		if (rtc_set_time(xtime.tv_sec) == 0) {
 			last_rtc_update = xtime.tv_sec;
 		} else {
-			last_rtc_update = xtime.tv_sec - 600; 
+			last_rtc_update = xtime.tv_sec - 600;
 			/* do it again in 60 s */
 		}
 	}
@@ -384,9 +384,9 @@
 	}
 
 #if !defined(CONFIG_SMP)
-	/* 
+	/*
 	 * In UP mode, we call local_timer_interrupt() to do profiling
-	 * and process accouting.  
+	 * and process accouting.
 	 *
 	 * In SMP mode, local_timer_interrupt() is invoked by appropriate
 	 * low-level local timer interrupt handler.
@@ -396,7 +396,7 @@
 #else	/* CONFIG_SMP */
 
 	if (emulate_local_timer_interrupt) {
-		/* 
+		/*
 		 * this is the place where we send out inter-process
 		 * interrupts and let each CPU do its own profiling
 		 * and process accouting.
@@ -418,7 +418,7 @@
 
 	/* we keep interrupt disabled all the time */
 	timer_interrupt(irq, NULL, regs);
-	
+
 	irq_exit(cpu, irq);
 
 	if (softirq_pending(cpu))
@@ -434,7 +434,7 @@
 
 	/* we keep interrupt disabled all the time */
 	local_timer_interrupt(irq, NULL, regs);
-	
+
 	irq_exit(cpu, irq);
 
 	if (softirq_pending(cpu))
@@ -444,19 +444,19 @@
 /*
  * time_init() - it does the following things.
  *
- * 1) board_time_init() - 
- * 	a) (optional) set up RTC routines, 
+ * 1) board_time_init() -
+ * 	a) (optional) set up RTC routines,
  *      b) (optional) calibrate and set the mips_counter_frequency
  *	    (only needed if you intended to use fixed_rate_gettimeoffset
  *	     or use cpu counter as timer interrupt source)
  * 2) setup xtime based on rtc_get_time().
  * 3) choose a appropriate gettimeoffset routine.
  * 4) calculate a couple of cached variables for later usage
- * 5) board_timer_setup() - 
+ * 5) board_timer_setup() -
  *	a) (optional) over-write any choices made above by time_init().
  *	b) machine specific code should setup the timer irqaction.
  *	c) enable the timer interrupt
- */ 
+ */
 
 void (*board_time_init)(void) = NULL;
 void (*board_timer_setup)(struct irqaction *irq) = NULL;
@@ -497,10 +497,12 @@
 		/* we need to calibrate the counter but we *do* have
 		 * 64-bit division. */
 		do_gettimeoffset = calibrate_div64_gettimeoffset;
-	}	
+	}
 
 	/* caclulate cache parameters */
 	if (mips_counter_frequency) {
+		u32 count;
+
 		cycles_per_jiffy = mips_counter_frequency / HZ;
 
 		/* sll32_usecs_per_cycle = 10^6 * 2^32 / mips_counter_freq */
@@ -508,16 +510,24 @@
 		sll32_usecs_per_cycle = mips_counter_frequency / 100000;
 		sll32_usecs_per_cycle = 0xffffffff / sll32_usecs_per_cycle;
 		sll32_usecs_per_cycle *= 10;
+
+		/*
+		 * For those using cpu counter as timer,  this sets up the
+		 * first interrupt
+		 */
+		count = read_32bit_cp0_register(CP0_COUNT);
+		write_32bit_cp0_register (CP0_COMPARE,
+					  count + cycles_per_jiffy);
 	}
 
-	/* 
+	/*
 	 * Call board specific timer interrupt setup.
 	 *
-	 * this pointer must be setup in machine setup routine. 
+	 * this pointer must be setup in machine setup routine.
 	 *
 	 * Even if the machine choose to use low-level timer interrupt,
 	 * it still needs to setup the timer_irqaction.
-	 * In that case, it might be better to set timer_irqaction.handler 
+	 * In that case, it might be better to set timer_irqaction.handler
 	 * to be NULL function so that we are sure the high-level code
 	 * is not invoked accidentally.
 	 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/traps.c linux-2.4.20/arch/mips/kernel/traps.c
--- linux-2.4.19/arch/mips/kernel/traps.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/traps.c	2002-10-29 11:18:39.000000000 +0000
@@ -32,6 +32,7 @@
 #include <asm/io.h>
 #include <asm/siginfo.h>
 #include <asm/watch.h>
+#include <asm/types.h>
 #include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/uaccess.h>
@@ -64,7 +65,8 @@
 extern asmlinkage void handle_mcheck(void);
 extern asmlinkage void handle_reserved(void);
 
-extern int fpu_emulator_cop1Handler(struct pt_regs *);
+extern int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp,
+	struct mips_fpu_soft_struct *ctx);
 
 char watch_available = 0;
 
@@ -180,61 +182,95 @@
 }
 
 /*
+ * If the address is either in the .text section of the
+ * kernel, or in the vmalloc'ed module regions, it *may*
+ * be the address of a calling routine
+ */
+
+#ifdef CONFIG_MODULES
+
+extern struct module *module_list;
+extern struct module kernel_module;
+
+static inline int kernel_text_address(long addr)
+{
+	extern char _stext, _etext;
+	int retval = 0;
+	struct module *mod;
+
+	if (addr >= (long) &_stext && addr <= (long) &_etext)
+		return 1;
+
+	for (mod = module_list; mod != &kernel_module; mod = mod->next) {
+		/* mod_bound tests for addr being inside the vmalloc'ed
+		 * module area. Of course it'd be better to test only
+		 * for the .text subset... */
+		if (mod_bound(addr, 0, mod)) {
+			retval = 1;
+			break;
+		}
+	}
+
+	return retval;
+}
+
+#else
+
+static inline int kernel_text_address(long addr)
+{
+	extern char _stext, _etext;
+
+	return (addr >= (long) &_stext && addr <= (long) &_etext);
+}
+
+#endif
+
+/*
  * This routine abuses get_user()/put_user() to reference pointers
  * with at least a bit of error checking ...
  */
-void show_stack(unsigned int *sp)
+void show_stack(long *sp)
 {
 	int i;
-	unsigned int *stack;
+	long stackdata;
 
-	stack = sp ? sp : (unsigned int *)&sp;
-	i = 0;
+	sp = sp ? sp : (long *)&sp;
 
-	printk("Stack:");
-	while ((unsigned long) stack & (PAGE_SIZE - 1)) {
-		unsigned long stackdata;
-
-		if (__get_user(stackdata, stack++)) {
-			printk(" (Bad stack address)");
+	printk("Stack:   ");
+	i = 1;
+	while ((long) sp & (PAGE_SIZE - 1)) {
+		if (i && ((i % 8) == 0))
+			printk("\n");
+		if (i > 40) {
+			printk(" ...");
 			break;
 		}
 
-		printk(" %08lx", stackdata);
-
-		if (++i > 40) {
-			printk(" ...");
+		if (__get_user(stackdata, sp++)) {
+			printk(" (Bad stack address)");
 			break;
 		}
 
-		if (i % 8 == 0)
-			printk("\n      ");
+		printk(" %08lx", stackdata);
+		i++;
 	}
+	printk("\n");
 }
 
-void show_trace(unsigned int *sp)
+void show_trace(long *sp)
 {
 	int i;
-	int column = 0;
-	unsigned int *stack;
-	unsigned long kernel_start, kernel_end;
-	unsigned long module_start, module_end;
-	extern char _stext, _etext;
+	long addr;
 
-	stack = sp ? sp : (unsigned int *) &sp;
-	i = 0;
+	sp = sp ? sp : (long *) &sp;
 
-	kernel_start = (unsigned long) &_stext;
-	kernel_end = (unsigned long) &_etext;
-	module_start = VMALLOC_START;
-	module_end = module_start + MODULE_RANGE;
+	printk("Call Trace:  ");
+	i = 1;
+	while ((long) sp & (PAGE_SIZE - 1)) {
 
-	printk("\nCall Trace:");
-
-	while ((unsigned long) stack & (PAGE_SIZE -1)) {
-		unsigned long addr;
-
-		if (__get_user(addr, stack++)) {
+		if (__get_user(addr, sp++)) {
+			if (i && ((i % 6) == 0))
+				printk("\n");
 			printk(" (Bad stack address)\n");
 			break;
 		}
@@ -248,27 +284,24 @@
 		 * out the call path that was taken.
 		 */
 
-		if ((addr >= kernel_start && addr < kernel_end) ||
-		    (addr >= module_start && addr < module_end)) { 
-
-			printk(" [<%08lx>]", addr);
-			if (column++ == 5) {
+		if (kernel_text_address(addr)) {
+			if (i && ((i % 6) == 0))
 				printk("\n");
-				column = 0;
-			}
-			if (++i > 40) {
+			if (i > 40) {
 				printk(" ...");
 				break;
 			}
+
+			printk(" [<%08lx>]", addr);
+			i++;
 		}
 	}
-	if (column != 0)
-		printk("\n");
+	printk("\n");
 }
 
 void show_trace_task(struct task_struct *tsk)
 {
-	show_trace((unsigned int *)tsk->thread.reg29);
+	show_trace((long *)tsk->thread.reg29);
 }
 
 void show_code(unsigned int *pc)
@@ -320,33 +353,33 @@
 	show_regs(regs);
 	printk("Process %s (pid: %d, stackpage=%08lx)\n",
 		current->comm, current->pid, (unsigned long) current);
-	show_stack((unsigned int *) regs->regs[29]);
-	show_trace((unsigned int *) regs->regs[29]);
+	show_stack((long *) regs->regs[29]);
+	show_trace((long *) regs->regs[29]);
 	show_code((unsigned int *) regs->cp0_epc);
 	printk("\n");
 }
 
 static spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
 
-void __die(const char * str, struct pt_regs * regs, const char *where,
-           unsigned long line)
+void __die(const char * str, struct pt_regs * regs, const char * file,
+	   const char * func, unsigned long line)
 {
 	console_verbose();
 	spin_lock_irq(&die_lock);
 	printk("%s", str);
-	if (where)
-		printk(" in %s, line %ld", where, line);
+	if (file && func)
+		printk(" in %s:%s, line %ld", file, func, line);
 	printk(":\n");
 	show_registers(regs);
 	spin_unlock_irq(&die_lock);
 	do_exit(SIGSEGV);
 }
 
-void __die_if_kernel(const char * str, struct pt_regs * regs, const char *where,
-	unsigned long line)
+void __die_if_kernel(const char * str, struct pt_regs * regs,
+		     const char * file, const char * func, unsigned long line)
 {
 	if (!user_mode(regs))
-		__die(str, regs, where, line);
+		__die(str, regs, file, func, line);
 }
 
 extern const struct exception_table_entry __start___dbe_table[];
@@ -461,10 +494,16 @@
 
 asmlinkage void do_ov(struct pt_regs *regs)
 {
+	siginfo_t info;
+
 	if (compute_return_epc(regs))
 		return;
 
-	force_sig(SIGFPE, current);
+	info.si_code = FPE_INTOVF;
+	info.si_signo = SIGFPE;
+	info.si_errno = 0;
+	info.si_addr = (void *)regs->cp0_epc;
+	force_sig_info(SIGFPE, &info, current);
 }
 
 /*
@@ -473,27 +512,26 @@
 asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
 {
 	if (fcr31 & FPU_CSR_UNI_X) {
-		extern void save_fp(struct task_struct *);
-		extern void restore_fp(struct task_struct *);
 		int sig;
+
 		/*
-	 	 * Unimplemented operation exception.  If we've got the
-	 	 * full software emulator on-board, let's use it...
+	 	 * Unimplemented operation exception.  If we've got the full
+		 * software emulator on-board, let's use it...
 		 *
-		 * Force FPU to dump state into task/thread context.
-		 * We're moving a lot of data here for what is probably
-		 * a single instruction, but the alternative is to 
-		 * pre-decode the FP register operands before invoking
-		 * the emulator, which seems a bit extreme for what
-		 * should be an infrequent event.
+		 * Force FPU to dump state into task/thread context.  We're
+		 * moving a lot of data here for what is probably a single
+		 * instruction, but the alternative is to pre-decode the FP
+		 * register operands before invoking the emulator, which seems
+		 * a bit extreme for what should be an infrequent event.
 		 */
 		save_fp(current);
-	
+
 		/* Run the emulator */
-		sig = fpu_emulator_cop1Handler(regs);
+		sig = fpu_emulator_cop1Handler (0, regs,
+			&current->thread.fpu.soft);
 
-		/* 
-		 * We can't allow the emulated instruction to leave any of 
+		/*
+		 * We can't allow the emulated instruction to leave any of
 		 * the cause bit set in $fcr31.
 		 */
 		current->thread.fpu.soft.sr &= ~FPU_CSR_ALL_X;
@@ -504,8 +542,8 @@
 		/* If something went wrong, signal */
 		if (sig)
 		{
-			/* 
-			 * Return EPC is not calculated in the FPU emulator, 
+			/*
+			 * Return EPC is not calculated in the FPU emulator,
 			 * if a signal is being send. So we calculate it here.
 			 */
 			compute_return_epc(regs);
@@ -522,9 +560,9 @@
 
 static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode)
 {
-	unsigned int *epc;
+	unsigned long *epc;
 
-	epc = (unsigned int *) regs->cp0_epc +
+	epc = (unsigned long *) regs->cp0_epc +
 	      ((regs->cp0_cause & CAUSEF_BD) != 0);
 	if (!get_user(*opcode, epc))
 		return 0;
@@ -535,14 +573,11 @@
 
 asmlinkage void do_bp(struct pt_regs *regs)
 {
-	siginfo_t info;
 	unsigned int opcode, bcode;
-	unsigned int *epc;
+	siginfo_t info;
 
-	epc = (unsigned int *) regs->cp0_epc +
-	      ((regs->cp0_cause & CAUSEF_BD) != 0);
-	if (get_user(opcode, epc))
-		goto sigsegv;
+	if (get_insn_opcode(regs, &opcode))
+		return;
 
 	/*
 	 * There is the ancient bug in the MIPS assemblers that the break
@@ -572,35 +607,30 @@
 	default:
 		force_sig(SIGTRAP, current);
 	}
-	return;
-
-sigsegv:
-	force_sig(SIGSEGV, current);
 }
 
 asmlinkage void do_tr(struct pt_regs *regs)
 {
 	siginfo_t info;
-	unsigned int opcode, bcode;
-	unsigned *epc;
+	unsigned int opcode, tcode = 0;
 
-	epc = (unsigned int *) regs->cp0_epc +
-	      ((regs->cp0_cause & CAUSEF_BD) != 0);
-	if (get_user(opcode, epc))
-		goto sigsegv;
+	if (get_insn_opcode(regs, &opcode))
+		return;
 
-	bcode = ((opcode >> 6) & ((1 << 20) - 1));
+	/* Immediate versions don't provide a code.  */
+	if (!(opcode & OPCODE))
+		tcode = ((opcode >> 6) & ((1 << 20) - 1));
 
 	/*
-	 * (A short test says that IRIX 5.3 sends SIGTRAP for all break
-	 * insns, even for break codes that indicate arithmetic failures.
+	 * (A short test says that IRIX 5.3 sends SIGTRAP for all trap
+	 * insns, even for trap codes that indicate arithmetic failures.
 	 * Weird ...)
 	 * But should we continue the brokenness???  --macro
 	 */
-	switch (bcode) {
+	switch (tcode) {
 	case 6:
 	case 7:
-		if (bcode == 7)
+		if (tcode == 7)
 			info.si_code = FPE_INTDIV;
 		else
 			info.si_code = FPE_INTOVF;
@@ -612,10 +642,6 @@
 	default:
 		force_sig(SIGTRAP, current);
 	}
-	return;
-
-sigsegv:
-	force_sig(SIGSEGV, current);
 }
 
 /*
@@ -627,8 +653,7 @@
  */
 asmlinkage void do_ri(struct pt_regs *regs)
 {
-	if (!user_mode(regs))
-		BUG();
+	die_if_kernel("Reserved instruction in kernel code", regs);
 
 #ifndef CONFIG_CPU_HAS_LLSC
 
@@ -660,9 +685,6 @@
 asmlinkage void do_cpu(struct pt_regs *regs)
 {
 	unsigned int cpid;
-	extern void lazy_fpu_switch(void *);
-	extern void save_fp(struct task_struct *);
-	extern void init_fpu(void);
 	void fpu_emulator_init_fpu(void);
 	int sig;
 
@@ -696,12 +718,11 @@
 			current->used_math = 1;
 		}
 	}
-	sig = fpu_emulator_cop1Handler(regs);
+	sig = fpu_emulator_cop1Handler(0, regs, &current->thread.fpu.soft);
 	last_task_used_math = current;
-	if (sig)
-	{
-		/* 
-		 * Return EPC is not calculated in the FPU emulator, if 
+	if (sig) {
+		/*
+		 * Return EPC is not calculated in the FPU emulator, if
 		 * a signal is being send. So we calculate it here.
 		 */
 		compute_return_epc(regs);
@@ -738,8 +759,14 @@
 asmlinkage void do_mcheck(struct pt_regs *regs)
 {
 	show_regs(regs);
-	panic("Caught Machine Check exception - probably caused by multiple "
-	      "matching entries in the TLB.");
+	dump_tlb_all();
+	/*
+	 * Some chips may have other causes of machine check (e.g. SB1
+	 * graduation timer)
+	 */
+	panic("Caught Machine Check exception - %scaused by multiple "
+	      "matching entries in the TLB.",
+	      (regs->cp0_status & ST0_TS) ? "" : "not ");
 }
 
 asmlinkage void do_reserved(struct pt_regs *regs)
@@ -774,7 +801,7 @@
 		       "MIPS 5KC CPUs.\n");
 		write_32bit_cp0_register(CP0_ECC,
 		                         read_32bit_cp0_register(CP0_ECC)
-		                         | 0x80000000); 
+		                         | 0x80000000);
 		break;
 	default:
 		break;
@@ -827,9 +854,9 @@
         printk("SDBBP EJTAG debug exception - not handled yet, just ignored!\n");
         depc = read_32bit_cp0_register(CP0_DEPC);
         debug = read_32bit_cp0_register(CP0_DEBUG);
-        printk("DEPC = %08x, DEBUG = %08x\n", depc, debug); 
+        printk("DEPC = %08x, DEBUG = %08x\n", depc, debug);
         if (debug & 0x80000000) {
-                /* 
+                /*
                  * In branch delay slot.
                  * We cheat a little bit here and use EPC to calculate the
                  * debug return address (DEPC). EPC is restored after the
@@ -869,10 +896,10 @@
  */
 void *set_except_vector(int n, void *addr)
 {
-	unsigned handler = (unsigned long) addr;
-	unsigned old_handler = exception_handlers[n];
-	exception_handlers[n] = handler;
+	unsigned long handler = (unsigned long) addr;
+	unsigned long old_handler = exception_handlers[n];
 
+	exception_handlers[n] = handler;
 	if (n == 0 && mips_cpu.options & MIPS_CPU_DIVEC) {
 		*(volatile u32 *)(KSEG0+0x200) = 0x08000000 |
 		                                 (0x03ffffff & (handler >> 2));
@@ -928,8 +955,8 @@
 	for (i = 0; i <= 31; i++)
 		set_except_vector(i, handle_reserved);
 
-	/* 
-	 * Copy the EJTAG debug exception vector handler code to it's final 
+	/*
+	 * Copy the EJTAG debug exception vector handler code to it's final
 	 * destination.
 	 */
 	if (mips_cpu.options & MIPS_CPU_EJTAG)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/kernel/unaligned.c linux-2.4.20/arch/mips/kernel/unaligned.c
--- linux-2.4.19/arch/mips/kernel/unaligned.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/kernel/unaligned.c	2002-10-29 11:18:32.000000000 +0000
@@ -41,7 +41,7 @@
  *
  * #include <stdio.h>
  * #include <asm/sysmips.h>
- * 
+ *
  * struct foo {
  *         unsigned char bar[8];
  * };
@@ -368,7 +368,7 @@
 	unsigned long pc;
 	extern int do_dsemulret(struct pt_regs *);
 
-	/* 
+	/*
 	 * Address errors may be deliberately induced
 	 * by the FPU emulator to take retake control
 	 * of the CPU after executing the instruction
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/lib/Makefile linux-2.4.20/arch/mips/lib/Makefile
--- linux-2.4.19/arch/mips/lib/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/lib/Makefile	2002-10-29 11:18:32.000000000 +0000
@@ -12,9 +12,9 @@
 				   strnlen_user.o
 
 ifeq ($(CONFIG_CPU_R3000)$(CONFIG_CPU_TX39XX),y)
-  obj-y	+= r3k_dump_tlb.o 
+  obj-y	+= r3k_dump_tlb.o
 else
-  obj-y	+= dump_tlb.o 
+  obj-y	+= dump_tlb.o
 endif
 
 obj-$(CONFIG_BLK_DEV_FD)	+= floppy-no.o floppy-std.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/lib/csum_partial_copy.c linux-2.4.20/arch/mips/lib/csum_partial_copy.c
--- linux-2.4.19/arch/mips/lib/csum_partial_copy.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/lib/csum_partial_copy.c	2002-10-29 11:18:47.000000000 +0000
@@ -23,7 +23,7 @@
 /*
  * copy while checksumming, otherwise like csum_partial
  */
-unsigned int csum_partial_copy(const char *src, char *dst, 
+unsigned int csum_partial_copy(const char *src, char *dst,
                                int len, unsigned int sum)
 {
 	/*
@@ -51,6 +51,6 @@
 		memset(dst + len - missing, 0, missing);
 		*err_ptr = -EFAULT;
 	}
-		
+
 	return csum_partial(dst, len, sum);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/lib/floppy-std.c linux-2.4.20/arch/mips/lib/floppy-std.c
--- linux-2.4.19/arch/mips/lib/floppy-std.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/lib/floppy-std.c	2002-10-29 11:18:33.000000000 +0000
@@ -111,8 +111,8 @@
 }
 
 static void std_fd_dma_mem_free(unsigned long addr, unsigned long size)
-{       
-	free_pages(addr, get_order(size));	
+{
+	free_pages(addr, get_order(size));
 }
 
 static unsigned long std_fd_drive_type(unsigned long n)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/lib/ide-no.c linux-2.4.20/arch/mips/lib/ide-no.c
--- linux-2.4.19/arch/mips/lib/ide-no.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/lib/ide-no.c	2002-10-29 11:18:36.000000000 +0000
@@ -35,7 +35,7 @@
                               void *dev_id)
 {
 	panic("no_no_ide_request_irq called - shouldn't happen");
-}			
+}
 
 static void no_ide_free_irq(unsigned int irq, void *dev_id)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/lib/ide-std.c linux-2.4.20/arch/mips/lib/ide-std.c
--- linux-2.4.19/arch/mips/lib/ide-std.c	2001-09-09 17:43:01.000000000 +0000
+++ linux-2.4.20/arch/mips/lib/ide-std.c	2002-10-29 11:18:48.000000000 +0000
@@ -68,7 +68,7 @@
                                 void *dev_id)
 {
 	return request_irq(irq, handler, flags, device, dev_id);
-}			
+}
 
 static void std_ide_free_irq(unsigned int irq, void *dev_id)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/lib/memcpy.S linux-2.4.20/arch/mips/lib/memcpy.S
--- linux-2.4.19/arch/mips/lib/memcpy.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/lib/memcpy.S	2002-10-29 11:18:32.000000000 +0000
@@ -249,7 +249,7 @@
 EXC(	LOAD	 t0, 0(src),		l_exc)
 	ADD	src, src, NBYTES
 	SUB	len, len, NBYTES
-EXC(	STORE	t0, 0(dst),		s_exc)
+EXC(	STORE	t0, 0(dst),		s_exc_p1u)
 	bne	rem, len, 1b
 	 ADD	dst, dst, NBYTES
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/lib/memset.S linux-2.4.20/arch/mips/lib/memset.S
--- linux-2.4.19/arch/mips/lib/memset.S	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips/lib/memset.S	2002-10-29 11:18:48.000000000 +0000
@@ -54,7 +54,6 @@
 1:
 
 EXPORT(__bzero)
-	.type   __bzero, @function
 	sltiu	t0, a2, 4			/* very small region? */
 	bnez	t0, small_memset
 	 andi	t0, a0, 3			/* aligned? */
@@ -84,13 +83,17 @@
 	.set	noreorder
 
 memset_partial:
-	la	t1, 2f				/* where to start */
+	PTR_LA	t1, 2f				/* where to start */
 	subu	t1, t0
 	jr	t1
 	 addu	a0, t0				/* dest ptr */
 
+	.set	push
+	.set	noreorder
+	.set	nomacro
 	F_FILL64(a0, -64, a1, partial_fixup)	/* ... but first do wrds ... */
-2:	andi	a2, 3				/* 0 <= n <= 3 to go */
+2:	.set	pop
+	andi	a2, 3				/* 0 <= n <= 3 to go */
 
 	beqz	a2, 1f
 	 addu	a0, a2				/* What's left */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/lib/strlen_user.S linux-2.4.20/arch/mips/lib/strlen_user.S
--- linux-2.4.19/arch/mips/lib/strlen_user.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/lib/strlen_user.S	2002-10-29 11:18:50.000000000 +0000
@@ -27,7 +27,7 @@
 	and	v0, a0
 	bltz	v0, fault
 
-EXPORT(__strlen_user_nocheck_asm)
+FEXPORT(__strlen_user_nocheck_asm)
 	move	v0, a0
 1:	EX(lb, t0, (v0), fault)
 	addiu	v0, 1
@@ -36,9 +36,5 @@
 	jr	ra
 	END(__strlen_user_asm)
 
-	.section __ex_table,"a"
-	PTR	1b, fault
-	.previous
-
 fault:	move	v0, zero
 	jr	ra
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/lib/strnlen_user.S linux-2.4.20/arch/mips/lib/strnlen_user.S
--- linux-2.4.19/arch/mips/lib/strnlen_user.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/lib/strnlen_user.S	2002-10-29 11:18:35.000000000 +0000
@@ -31,7 +31,7 @@
 	and	v0, a0
 	bltz	v0, fault
 
-EXPORT(__strnlen_user_nocheck_asm)
+FEXPORT(__strnlen_user_nocheck_asm)
 	.type	__strnlen_user_nocheck_asm,@function
 	move	v0, a0
 	addu	a1, a0			# stop pointer
@@ -45,9 +45,5 @@
 	jr	ra
 	END(__strnlen_user_asm)
 
-	.section	__ex_table,"a"
-	PTR		1b, fault
-	.previous
-
 fault:	move	v0, zero
 	jr	ra
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/lib/tinycon.c linux-2.4.20/arch/mips/lib/tinycon.c
--- linux-2.4.19/arch/mips/lib/tinycon.c	1997-06-26 19:33:37.000000000 +0000
+++ linux-2.4.20/arch/mips/lib/tinycon.c	2002-10-29 11:18:48.000000000 +0000
@@ -38,7 +38,7 @@
   cursor_y = 0;
 
   vram_addr = (unsigned short *)0xb00b8000;
-  
+
   console_needs_init = 0;
 }
 
@@ -87,7 +87,7 @@
     *(caddr++) = *(caddr + size_x);
 
   /* blank last line */
-  
+
   caddr = vram_addr + (size_x * (size_y-1));
   for(i=0; i<size_x; i++)
     *(caddr++) = (*caddr & 0xff00) | (unsigned short) ' ';
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/Makefile linux-2.4.20/arch/mips/math-emu/Makefile
--- linux-2.4.19/arch/mips/math-emu/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/Makefile	2002-10-29 11:18:31.000000000 +0000
@@ -16,6 +16,6 @@
 	   dp_tint.o dp_fint.o dp_tlong.o dp_flong.o sp_frexp.o sp_modf.o \
 	   sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_logb.o \
 	   sp_scalb.o sp_simple.o sp_tint.o sp_fint.o sp_tlong.o sp_flong.o \
-	   dp_sqrt.o sp_sqrt.o kernel_linkage.o
+	   dp_sqrt.o sp_sqrt.o kernel_linkage.o dsemul.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/cp1emu.c linux-2.4.20/arch/mips/math-emu/cp1emu.c
--- linux-2.4.19/arch/mips/math-emu/cp1emu.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/cp1emu.c	2002-10-29 11:18:50.000000000 +0000
@@ -1,6 +1,6 @@
 /*
  * cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator
- * 
+ *
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
  * http://www.algor.co.uk
@@ -23,38 +23,30 @@
  *
  * A complete emulator for MIPS coprocessor 1 instructions.  This is
  * required for #float(switch) or #float(trap), where it catches all
- * COP1 instructions via the "CoProcessor Unusable" exception.  
+ * COP1 instructions via the "CoProcessor Unusable" exception.
  *
  * More surprisingly it is also required for #float(ieee), to help out
  * the hardware fpu at the boundaries of the IEEE-754 representation
  * (denormalised values, infinities, underflow, etc).  It is made
  * quite nasty because emulation of some non-COP1 instructions is
  * required, e.g. in branch delay slots.
- * 
- * Note if you know that you won't have an fpu, then you'll get much 
+ *
+ * Note if you know that you won't have an fpu, then you'll get much
  * better performance by compiling with -msoft-float!
  */
-#include <linux/compiler.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-
-#include <asm/asm.h>
-#include <asm/branch.h>
+#include <asm/inst.h>
 #include <asm/bootinfo.h>
-#include <asm/byteorder.h>
 #include <asm/cpu.h>
-#include <asm/inst.h>
-#include <asm/uaccess.h>
 #include <asm/processor.h>
+#include <asm/ptrace.h>
+#include <asm/signal.h>
 #include <asm/mipsregs.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-
 #include <asm/fpu_emulator.h>
+#include <asm/uaccess.h>
+#include <asm/branch.h>
 
 #include "ieee754.h"
+#include "dsemul.h"
 
 /* Strap kernel emulator for full MIPS IV emulation */
 
@@ -63,20 +55,14 @@
 #endif
 #define __mips 4
 
-typedef void *vaddr_t;
-
-/* Function which emulates the instruction in a branch delay slot. */
-
-static int mips_dsemul(struct pt_regs *, mips_instruction, unsigned long);
-
 /* Function which emulates a floating point instruction. */
 
 static int fpu_emu(struct pt_regs *, struct mips_fpu_soft_struct *,
-	 mips_instruction);
+	mips_instruction);
 
 #if __mips >= 4 && __mips != 32
 static int fpux_emu(struct pt_regs *,
-		    struct mips_fpu_soft_struct *, mips_instruction);
+	struct mips_fpu_soft_struct *, mips_instruction);
 #endif
 
 /* Further private data for which no space exists in mips_fpu_soft_struct */
@@ -108,8 +94,7 @@
 #endif
 
 
-
-/* 
+/*
  * Redundant with logic already in kernel/branch.c,
  * embedded in compute_return_epc.  At some point,
  * a single subroutine should be used across both
@@ -165,46 +150,70 @@
 	return 0;
 }
 
-#define REG_TO_VA (vaddr_t)
-#define VA_TO_REG (unsigned long)
-
 /*
  * In the Linux kernel, we support selection of FPR format on the
  * basis of the Status.FR bit.  This does imply that, if a full 32
  * FPRs are desired, there needs to be a flip-flop that can be written
- * to one at that bit position.  In any case, normal MIPS ABI uses
+ * to one at that bit position.  In any case, O32 MIPS ABI uses
  * only the even FPRs (Status.FR = 0).
  */
 
 #define CP0_STATUS_FR_SUPPORT
 
+#ifdef CP0_STATUS_FR_SUPPORT
+#define FR_BIT ST0_FR
+#else
+#define FR_BIT 0
+#endif
+
+#define SIFROMREG(si,x)	((si) = \
+			(xcp->cp0_status & FR_BIT) || !(x & 1) ? \
+			(int)ctx->regs[x] : \
+			(int)(ctx->regs[x & ~1] >> 32 ))
+#define SITOREG(si,x)	(ctx->regs[x & ~((xcp->cp0_status & FR_BIT) == 0)] = \
+			(xcp->cp0_status & FR_BIT) || !(x & 1) ? \
+			ctx->regs[x & ~1] >> 32 << 32 | (u32)(si) : \
+			ctx->regs[x & ~1] << 32 >> 32 | (u64)(si) << 32)
+
+#define DIFROMREG(di,x)	((di) = \
+			ctx->regs[x & ~((xcp->cp0_status & FR_BIT) == 0)])
+#define DITOREG(di,x)	(ctx->regs[x & ~((xcp->cp0_status & FR_BIT) == 0)] \
+			= (di))
+#define DIFROMREG(di,x)	((di) = \
+			ctx->regs[x & ~((xcp->cp0_status & FR_BIT) == 0)])
+#define DITOREG(di,x)	(ctx->regs[x & ~((xcp->cp0_status & FR_BIT) == 0)] \
+			= (di))
+
+#define SPFROMREG(sp,x)	SIFROMREG((sp).bits,x)
+#define SPTOREG(sp,x)	SITOREG((sp).bits,x)
+#define DPFROMREG(dp,x)	DIFROMREG((dp).bits,x)
+#define DPTOREG(dp,x)	DITOREG((dp).bits,x)
+
 /*
  * Emulate the single floating point instruction pointed at by EPC.
  * Two instructions if the instruction is in a branch delay slot.
  */
 
-static int cop1Emulate(struct pt_regs *regs, struct mips_fpu_soft_struct *ctx)
+static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx)
 {
-	vaddr_t emulpc, contpc;
 	mips_instruction ir;
+	vaddr_t emulpc, contpc;
 	unsigned int cond;
-	int err = 0;
 
-	err = get_user(ir, (mips_instruction *) regs->cp0_epc);
-	if (err) {
+	if (get_user(ir, (mips_instruction *) REG_TO_VA xcp->cp0_epc)) {
 		fpuemuprivate.stats.errors++;
 		return SIGBUS;
 	}
 
 	/* XXX NEC Vr54xx bug workaround */
-	if ((regs->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir))
-		regs->cp0_cause &= ~CAUSEF_BD;
+	if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir))
+		xcp->cp0_cause &= ~CAUSEF_BD;
 
-	if (regs->cp0_cause & CAUSEF_BD) {
+	if (xcp->cp0_cause & CAUSEF_BD) {
 		/*
 		 * The instruction to be emulated is in a branch delay slot
 		 * which means that we have to  emulate the branch instruction
-		 * BEFORE we do the cop1 instruction. 
+		 * BEFORE we do the cop1 instruction.
 		 *
 		 * This branch could be a COP1 branch, but in that case we
 		 * would have had a trap for that instruction, and would not
@@ -213,368 +222,206 @@
 		 * Linux MIPS branch emulator operates on context, updating the
 		 * cp0_epc.
 		 */
-		emulpc = REG_TO_VA(regs->cp0_epc + 4);	/* Snapshot emulation target */
+		emulpc = REG_TO_VA(xcp->cp0_epc + 4);	/* Snapshot emulation target */
 
-		if (__compute_return_epc(regs)) {
+		if (__compute_return_epc(xcp)) {
 #ifdef CP1DBG
 			printk("failed to emulate branch at %p\n",
-				    REG_TO_VA(regs->cp0_epc));
+				REG_TO_VA(xcp->cp0_epc));
 #endif
 			return SIGILL;
 		}
-		err = get_user(ir, (mips_instruction *) emulpc);
-		if (err) {
+		if (get_user(ir, (mips_instruction *) emulpc)) {
 			fpuemuprivate.stats.errors++;
 			return SIGBUS;
 		}
 		/* __computer_return_epc() will have updated cp0_epc */
-		contpc = REG_TO_VA regs->cp0_epc;
+		contpc = REG_TO_VA xcp->cp0_epc;
 		/* In order not to confuse ptrace() et al, tweak context */
-		regs->cp0_epc = VA_TO_REG emulpc - 4;
-	} else {
-		emulpc = REG_TO_VA regs->cp0_epc;
-		contpc = REG_TO_VA regs->cp0_epc + 4;
+		xcp->cp0_epc = VA_TO_REG emulpc - 4;
+	}
+	else {
+		emulpc = REG_TO_VA xcp->cp0_epc;
+		contpc = REG_TO_VA(xcp->cp0_epc + 4);
 	}
 
-emul:
+      emul:
 	fpuemuprivate.stats.emulated++;
 	switch (MIPSInst_OPCODE(ir)) {
-#ifdef CP0_STATUS_FR_SUPPORT
-		/* R4000+ 64-bit fpu registers */
 #ifndef SINGLE_ONLY_FPU
-	case ldc1_op:
-		{
-			u64 *va = REG_TO_VA(regs->regs[MIPSInst_RS(ir)]) +
-			          MIPSInst_SIMM(ir);
-			int ft = MIPSInst_RT(ir);
-
-			if (!(regs->cp0_status & ST0_FR))
-				ft &= ~1;
-			err = get_user(ctx->regs[ft], va);
-			fpuemuprivate.stats.loads++;
-			if (err) {
-				fpuemuprivate.stats.errors++;
-				return SIGBUS;
-			}
+	case ldc1_op:{
+		u64 *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)] +
+			MIPSInst_SIMM(ir));
+		u64 val;
+
+		fpuemuprivate.stats.loads++;
+		if (get_user(val, va)) {
+			fpuemuprivate.stats.errors++;
+			return SIGBUS;
 		}
+		DITOREG(val, MIPSInst_RT(ir));
 		break;
+	}
 
-	case sdc1_op:
-		{
-			fpureg_t *va = REG_TO_VA(regs->regs[MIPSInst_RS(ir)]) +
-			               MIPSInst_SIMM(ir);
-			int ft = MIPSInst_RT(ir);
-
-			if (!(regs->cp0_status & ST0_FR))
-				ft &= ~1;
-			fpuemuprivate.stats.stores++;
-			if (put_user(ctx->regs[ft], va)) {
-				fpuemuprivate.stats.errors++;
-				return SIGBUS;
-			}
+	case sdc1_op:{
+		u64 *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)] +
+			MIPSInst_SIMM(ir));
+		u64 val;
+
+		fpuemuprivate.stats.stores++;
+		DIFROMREG(val, MIPSInst_RT(ir));
+		if (put_user(val, va)) {
+			fpuemuprivate.stats.errors++;
+			return SIGBUS;
 		}
 		break;
+	}
 #endif
 
-	case lwc1_op:
-		{
-			u32 *va = REG_TO_VA(regs->regs[MIPSInst_RS(ir)]) +
-			               MIPSInst_SIMM(ir);
-			int ft = MIPSInst_RT(ir);
-			u32 val;
+	case lwc1_op:{
+		u32 *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)] +
+			MIPSInst_SIMM(ir));
+		u32 val;
 
-			fpuemuprivate.stats.loads++;
-			err = get_user(val, va);
-			if (err) {
-				fpuemuprivate.stats.errors++;
-				return SIGBUS;
-			}
-			if (regs->cp0_status & ST0_FR) {
-				/* load whole register */
-				ctx->regs[ft] = (s64) val;
-			} else if (ft & 1) {
-				/* load to m.s. 32 bits */
-#ifdef SINGLE_ONLY_FPU
-				/* illegal register in single-float mode */
-				return SIGILL;
-#else
-				ctx->regs[(ft & ~1)] &= 0xffffffff;
-				ctx->regs[(ft & ~1)] |= (fpureg_t) val << 32;
-#endif
-			} else {
-				/* load to l.s. 32 bits */
-				ctx->regs[ft] &= ~0xffffffffLL;
-				ctx->regs[ft] |= val;
-			}
+		fpuemuprivate.stats.loads++;
+		if (get_user(val, va)) {
+			fpuemuprivate.stats.errors++;
+			return SIGBUS;
 		}
-		break;
-
-	case swc1_op:
-		{
-			u32 *va = REG_TO_VA(regs->regs[MIPSInst_RS(ir)]) +
-			          MIPSInst_SIMM(ir);
-			unsigned int val;
-			int ft = MIPSInst_RT(ir);
-
-			fpuemuprivate.stats.stores++;
-			if (regs->cp0_status & ST0_FR) {
-				/* store whole register */
-				val = ctx->regs[ft];
-			} else if (ft & 1) {
 #ifdef SINGLE_ONLY_FPU
-				/* illegal register in single-float mode */
-				return SIGILL;
-#else
-				/* store from m.s. 32 bits */
-				val = ctx->regs[(ft & ~1)] >> 32;
-#endif
-			} else {
-				/* store from l.s. 32 bits */
-				val = ctx->regs[ft];
-			}
-			if (put_user(val, va)) {
-				fpuemuprivate.stats.errors++;
-				return SIGBUS;
-			}
-		}
-		break;
-#else				/* old 32-bit fpu registers */
-	case lwc1_op:
-		{
-			u32 *va = REG_TO_VA(regs->regs[MIPSInst_RS(ir)]) +
-			          MIPSInst_SIMM(ir);
-			err = get_user(ctx->regs[MIPSInst_RT(ir)], va);
-
-			fpuemuprivate.stats.loads++;
-			if (err) {
-				fpuemuprivate.stats.errors++;
-				return SIGBUS;
-			}
-		}
-		break;
-
-	case swc1_op:
-		{
-			u32 *va = REG_TO_VA(regs->regs[MIPSInst_RS(ir)]) +
-			          MIPSInst_SIMM(ir);
-			fpuemuprivate.stats.stores++;
-			if (put_user(ctx->regs[MIPSInst_RT(ir)], va)) {
-				fpuemuprivate.stats.errors++;
-				return SIGBUS;
-			}
+		if (MIPSInst_RT(ir) & 1) {
+			/* illegal register in single-float mode */
+			return SIGILL;
 		}
-		break;
-	case ldc1_op:
-		{
-			u32 *va = REG_TO_VA(regs->regs[MIPSInst_RS(ir)])
-			    + MIPSInst_SIMM(ir);
-			unsigned int rt = MIPSInst_RT(ir) & ~1;
-			int errs = 0;
-			fpuemuprivate.stats.loads++;
-#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
-			err = get_user(ctx->regs[rt + 1], va + 0);
-			err |= get_user(ctx->regs[rt + 0], va + 1);
-#else
-			err = get_user(ctx->regs[rt + 0], va + 0);
-			err |= get_user(ctx->regs[rt + 1], va + 1);
 #endif
-			if (err)
-				return SIGBUS;
-		}
+		SITOREG(val, MIPSInst_RT(ir));
 		break;
+	}
 
-	case sdc1_op:
-		{
-			u32 *va = REG_TO_VA(regs->regs[MIPSInst_RS(ir)]) +
-			          MIPSInst_SIMM(ir);
-			unsigned int rt = MIPSInst_RT(ir) & ~1;
+	case swc1_op:{
+		u32 *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)] +
+			MIPSInst_SIMM(ir));
+		u32 val;
 
-			fpuemuprivate.stats.stores++;
-#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
-			if (put_user(ctx->regs[rt + 1], va + 0)
-			    || put_user(ctx->regs[rt + 0], va + 1))
-				return SIGBUS;
-#else
-			if (put_user(ctx->regs[rt + 0], va + 0)
-			    || put_user(ctx->regs[rt + 1], va + 1))
-				return SIGBUS;
+		fpuemuprivate.stats.stores++;
+#ifdef SINGLE_ONLY_FPU
+		if (MIPSInst_RT(ir) & 1) {
+			/* illegal register in single-float mode */
+			return SIGILL;
+		}
 #endif
+		SIFROMREG(val, MIPSInst_RT(ir));
+		if (put_user(val, va)) {
+			fpuemuprivate.stats.errors++;
+			return SIGBUS;
 		}
 		break;
-#endif
+	}
 
 	case cop1_op:
 		switch (MIPSInst_RS(ir)) {
 
-#ifdef CP0_STATUS_FR_SUPPORT
 #if __mips64 && !defined(SINGLE_ONLY_FPU)
 		case dmfc_op:
 			/* copregister fs -> gpr[rt] */
 			if (MIPSInst_RT(ir) != 0) {
-				int fs = MIPSInst_RD(ir);
-				if (!(regs->cp0_status & ST0_FR))
-					fs &= ~1;
-				regs->regs[MIPSInst_RT(ir)] = ctx->regs[fs];
+				DIFROMREG(xcp->regs[MIPSInst_RT(ir)],
+					MIPSInst_RD(ir));
 			}
 			break;
 
-		case dmtc_op: {
+		case dmtc_op:
 			/* copregister fs <- rt */
-				fpureg_t value;
-				int fs = MIPSInst_RD(ir);
-				if (!(regs->cp0_status & ST0_FR))
-					fs &= ~1;
-				value =
-				    (MIPSInst_RT(ir) ==
-				     0) ? 0 : regs->regs[MIPSInst_RT(ir)];
-				ctx->regs[fs] = value;
+			DITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir));
 			break;
-		}
 #endif
 
 		case mfc_op:
 			/* copregister rd -> gpr[rt] */
-			if (MIPSInst_RT(ir) != 0) {
-				/* default value from l.s. 32 bits */
-				int value = ctx->regs[MIPSInst_RD(ir)];
-				if (MIPSInst_RD(ir) & 1) {
 #ifdef SINGLE_ONLY_FPU
-					/* illegal register in single-float mode */
-					return SIGILL;
-#else
-					if (!(regs->cp0_status & ST0_FR)) {
-						/* move from m.s. 32 bits */
-						value =
-						    ctx->
-						    regs[MIPSInst_RD(ir) &
-							 ~1] >> 32;
-					}
-#endif
-				}
-				regs->regs[MIPSInst_RT(ir)] = value;
+			if (MIPSInst_RD(ir) & 1) {
+				/* illegal register in single-float mode */
+				return SIGILL;
 			}
-			break;
-
-		case mtc_op:
-			/* copregister rd <- rt */
-			{
-				fpureg_t value;
-				if (MIPSInst_RT(ir) == 0)
-					value = 0;
-				else
-					value =
-					    (unsigned int) regs->
-					    regs[MIPSInst_RT(ir)];
-				if (MIPSInst_RD(ir) & 1) {
-#ifdef SINGLE_ONLY_FPU
-					/* illegal register in single-float mode */
-					return SIGILL;
-#else
-					if (!(regs->cp0_status & ST0_FR)) {
-						/* move to m.s. 32 bits */
-						ctx->
-						    regs[
-							 (MIPSInst_RD(ir) &
-							  ~1)] &=
-						    0xffffffff;
-						ctx->
-						    regs[
-							 (MIPSInst_RD(ir) &
-							  ~1)] |=
-						    value << 32;
-						break;
-					}
 #endif
-				}
-				/* move to l.s. 32 bits */
-				ctx->regs[MIPSInst_RD(ir)] &=
-				    ~0xffffffffLL;
-				ctx->regs[MIPSInst_RD(ir)] |= value;
-			}
-			break;
-#else
-
-		case mfc_op:
-			/* copregister rd -> gpr[rt] */
 			if (MIPSInst_RT(ir) != 0) {
-				unsigned value =
-				    ctx->regs[MIPSInst_RD(ir)];
-				regs->regs[MIPSInst_RT(ir)] = value;
+				SIFROMREG(xcp->regs[MIPSInst_RT(ir)],
+					MIPSInst_RD(ir));
 			}
 			break;
 
 		case mtc_op:
 			/* copregister rd <- rt */
-			{
-				unsigned value;
-				value =
-				    (MIPSInst_RT(ir) ==
-				     0) ? 0 : regs->regs[MIPSInst_RT(ir)];
-				ctx->regs[MIPSInst_RD(ir)] = value;
+#ifdef SINGLE_ONLY_FPU
+			if (MIPSInst_RD(ir) & 1) {
+				/* illegal register in single-float mode */
+				return SIGILL;
 			}
-			break;
 #endif
+			SITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir));
+			break;
 
-		case cfc_op:
+		case cfc_op:{
 			/* cop control register rd -> gpr[rt] */
-			{
-				unsigned value;
+			u32 value;
 
-				if (MIPSInst_RD(ir) == FPCREG_CSR) {
-					value = ctx->sr;
+			if (ir == CP1UNDEF) {
+				return do_dsemulret(xcp);
+			}
+			if (MIPSInst_RD(ir) == FPCREG_CSR) {
+				value = ctx->sr;
 #ifdef CSRTRACE
-					printk
-					    ("%p gpr[%d]<-csr=%08x\n",
-					     REG_TO_VA(regs->cp0_epc),
-					     MIPSInst_RT(ir), value);
+				printk("%p gpr[%d]<-csr=%08x\n",
+					REG_TO_VA(xcp->cp0_epc),
+					MIPSInst_RT(ir), value);
 #endif
-				} else if (MIPSInst_RD(ir) == FPCREG_RID)
-					value = 0;
-				else
-					value = 0;
-				if (MIPSInst_RT(ir))
-					regs->regs[MIPSInst_RT(ir)] = value;
 			}
+			else if (MIPSInst_RD(ir) == FPCREG_RID)
+				value = 0;
+			else
+				value = 0;
+			if (MIPSInst_RT(ir))
+				xcp->regs[MIPSInst_RT(ir)] = value;
 			break;
+		}
 
-		case ctc_op:
+		case ctc_op:{
 			/* copregister rd <- rt */
-			{
-				unsigned value;
-
-				if (MIPSInst_RT(ir) == 0)
-					value = 0;
-				else
-					value = regs->regs[MIPSInst_RT(ir)];
+			u32 value;
 
-				/* we only have one writable control reg
-				 */
-				if (MIPSInst_RD(ir) == FPCREG_CSR) {
+			if (MIPSInst_RT(ir) == 0)
+				value = 0;
+			else
+				value = xcp->regs[MIPSInst_RT(ir)];
+
+			/* we only have one writable control reg
+			 */
+			if (MIPSInst_RD(ir) == FPCREG_CSR) {
 #ifdef CSRTRACE
-					printk
-					    ("%p gpr[%d]->csr=%08x\n",
-					     REG_TO_VA(regs->cp0_epc),
-					     MIPSInst_RT(ir), value);
-#endif
-					ctx->sr = value;
-					/* copy new rounding mode and
-					   flush bit to ieee library state! */
-					ieee754_csr.nod =
-					    (ctx->sr & 0x1000000) != 0;
-					ieee754_csr.rm =
-					    ieee_rm[value & 0x3];
-				}
+				printk("%p gpr[%d]->csr=%08x\n",
+					REG_TO_VA(xcp->cp0_epc),
+					MIPSInst_RT(ir), value);
+#endif
+				ctx->sr = value;
+				/* copy new rounding mode and
+				   flush bit to ieee library state! */
+				ieee754_csr.nod = (ctx->sr & 0x1000000) != 0;
+				ieee754_csr.rm = ieee_rm[value & 0x3];
+			}
+			if ((ctx->sr >> 5) & ctx->sr & FPU_CSR_ALL_E) {
+				return SIGFPE;
 			}
 			break;
+		}
 
-		case bc_op: {
+		case bc_op:{
 			int likely = 0;
 
-			if (regs->cp0_cause & CAUSEF_BD)
+			if (xcp->cp0_cause & CAUSEF_BD)
 				return SIGILL;
 
 #if __mips >= 4
-			cond = ctx-> sr & fpucondbit[MIPSInst_RT(ir) >> 2];
+			cond = ctx->sr & fpucondbit[MIPSInst_RT(ir) >> 2];
 #else
 			cond = ctx->sr & FPU_CSR_COND;
 #endif
@@ -593,16 +440,18 @@
 				return SIGILL;
 			}
 
-			regs->cp0_cause |= CAUSEF_BD;
+			xcp->cp0_cause |= CAUSEF_BD;
 			if (cond) {
-				/* branch taken: emulate dslot instruction */
-				regs->cp0_epc += 4;
-				contpc = REG_TO_VA regs->cp0_epc +
-				                   (MIPSInst_SIMM(ir) << 2);
-
-				err = get_user(ir,
-					(mips_instruction *)regs->cp0_epc);
-				if (err) {
+				/* branch taken: emulate dslot
+				 * instruction
+				 */
+				xcp->cp0_epc += 4;
+				contpc = REG_TO_VA
+					(xcp->cp0_epc +
+					(MIPSInst_SIMM(ir) << 2));
+
+				if (get_user(ir, (mips_instruction *)
+						REG_TO_VA xcp->cp0_epc)) {
 					fpuemuprivate.stats.errors++;
 					return SIGBUS;
 				}
@@ -629,49 +478,50 @@
 				}
 
 				/*
-				 * Single step the non-cp1 instruction in the
-				 * dslot
+				 * Single step the non-cp1
+				 * instruction in the dslot
 				 */
-				return mips_dsemul(regs, ir, contpc);
-			} else {
+				return mips_dsemul(xcp, ir, VA_TO_REG contpc);
+			}
+			else {
 				/* branch not taken */
 				if (likely) {
 					/*
-					 * branch likely nullifies dslot if not
-					 * taken
+					 * branch likely nullifies
+					 * dslot if not taken
 					 */
-					regs->cp0_epc += 4;
+					xcp->cp0_epc += 4;
 					contpc += 4;
 					/*
-					 * else continue & execute dslot as
-					 * normal insn
+					 * else continue & execute
+					 * dslot as normal insn
 					 */
 				}
 			}
 			break;
 		}
 
-		default: {
-			int sig;
-
+		default:
 			if (!(MIPSInst_RS(ir) & 0x10))
 				return SIGILL;
+			{
+				int sig;
 
-			/* a real fpu computation instruction */
-				if ((sig = fpu_emu(regs, ctx, ir)))
+				/* a real fpu computation instruction */
+				if ((sig = fpu_emu(xcp, ctx, ir)))
 					return sig;
 			}
 		}
 		break;
 
 #if __mips >= 4 && __mips != 32
-	case cop1x_op:
-		{
-			int sig;
-			if ((sig = fpux_emu(regs, ctx, ir)))
-				return sig;
-		}
+	case cop1x_op:{
+		int sig;
+
+		if ((sig = fpux_emu(xcp, ctx, ir)))
+			return sig;
 		break;
+	}
 #endif
 
 #if __mips >= 4
@@ -681,7 +531,7 @@
 		cond = fpucondbit[MIPSInst_RT(ir) >> 2];
 		if (((ctx->sr & cond) != 0) != ((MIPSInst_RT(ir) & 1) != 0))
 			return 0;
-		regs->regs[MIPSInst_RD(ir)] = regs->regs[MIPSInst_RS(ir)];
+		xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)];
 		break;
 #endif
 
@@ -690,194 +540,26 @@
 	}
 
 	/* we did it !! */
-	regs->cp0_epc = VA_TO_REG(contpc);
-	regs->cp0_cause &= ~CAUSEF_BD;
+	xcp->cp0_epc = VA_TO_REG(contpc);
+	xcp->cp0_cause &= ~CAUSEF_BD;
 	return 0;
 }
 
 /*
- * Emulate the arbritrary instruction ir at xcp->cp0_epc.  Required when
- * we have to emulate the instruction in a COP1 branch delay slot.  Do
- * not change cp0_epc due to the instruction
- *
- * According to the spec:
- * 1) it shouldnt be a branch :-)
- * 2) it can be a COP instruction :-(
- * 3) if we are tring to run a protected memory space we must take
- *    special care on memory access instructions :-(
- */
-
-/*
- * "Trampoline" return routine to catch exception following
- *  execution of delay-slot instruction execution.
- */
-
-/* Instruction inserted following delay slot instruction to force trap */
-#define AdELOAD 0x8c000001	/* lw $0,1($0) */
-
-/* Instruction inserted following the AdELOAD to further tag the sequence */
-#define BD_COOKIE 0x0000bd36	/* tne $0,$0 with baggage */
-
-struct emuframe {
-	mips_instruction	emul;
-	mips_instruction	adel;
-	mips_instruction	cookie;
-	unsigned long	epc;
-};
-
-int do_dsemulret(struct pt_regs *xcp)
-{
-	struct emuframe *fr;
-	unsigned long epc;
-	u32 insn, cookie;
-	int err = 0;
-
-	fr = (struct emuframe *) (xcp->cp0_epc - sizeof(mips_instruction));
-
-	/* 
-	 * If we can't even access the area, something is very wrong, but we'll
-	 * leave that to the default handling
-	 */
-	if (verify_area(VERIFY_READ, fr, sizeof(struct emuframe)))
-		return 0;
-
-	/*
-	 * Do some sanity checking on the stackframe:
-	 *
-	 *  - Is the instruction pointed to by the EPC an AdELOAD?
-	 *  - Is the following memory word the BD_COOKIE?
-	 */
-	err = __get_user(insn, &fr->adel);
-	err |= __get_user(cookie, &fr->cookie);
-
-	if (unlikely(err || (insn != AdELOAD) || (cookie != BD_COOKIE))) {
-		fpuemuprivate.stats.errors++;
-
-		return 0;
-	}
-
-	/* 
-	 * At this point, we are satisfied that it's a BD emulation trap.  Yes,
-	 * a user might have deliberately put two malformed and useless
-	 * instructions in a row in his program, in which case he's in for a
-	 * nasty surprise - the next instruction will be treated as a
-	 * continuation address!  Alas, this seems to be the only way that we
-	 * can handle signals, recursion, and longjmps() in the context of
-	 * emulating the branch delay instruction.
-	 */
-
-#ifdef DSEMUL_TRACE
-	printk("desemulret\n");
-#endif
-	if (__get_user(epc, &fr->epc)) {		/* Saved EPC */
-		/* This is not a good situation to be in */
-		force_sig(SIGBUS, current);
-
-		return 1;
-	}
-
-	/* Set EPC to return to post-branch instruction */
-	xcp->cp0_epc = epc;
-
-	return 1;
-}
-
-static int mips_dsemul(struct pt_regs *regs, mips_instruction ir,
-	unsigned long cpc)
-{
-	extern asmlinkage void handle_dsemulret(void);
-	mips_instruction *dsemul_insns;
-	struct emuframe *fr;
-	int err;
-
-	if (ir == 0) {		/* a nop is easy */
-		regs->cp0_epc = cpc;
-		regs->cp0_cause &= ~CAUSEF_BD;
-		return 0;
-	}
-#ifdef DSEMUL_TRACE
-	printk("desemul %lx %lx\n", regs->cp0_epc, cpc);
-
-#endif
- 
-	/* 
-	 * The strategy is to push the instruction onto the user stack 
-	 * and put a trap after it which we can catch and jump to 
-	 * the required address any alternative apart from full 
-	 * instruction emulation!!.
-	 *
-	 * Algorithmics used a system call instruction, and
-	 * borrowed that vector.  MIPS/Linux version is a bit
-	 * more heavyweight in the interests of portability and
-	 * multiprocessor support.  We flag the thread for special
-	 * handling in the unaligned access handler and force an
-	 * address error excpetion.
-	 */
-
-	/* Ensure that the two instructions are in the same cache line */
-	dsemul_insns = (mips_instruction *) (regs->regs[29] & ~0xf);
-	dsemul_insns -= 4;	/* Retain 16-byte alignment */
-	fr = (struct emuframe *) dsemul_insns;
-
-	/* Verify that the stack pointer is not competely insane */
-	if (unlikely(verify_area(VERIFY_WRITE, fr, sizeof(struct emuframe))))
-		return SIGBUS;
-
-	err = __put_user(ir, &dsemul_insns[0]);
-	err |= __put_user((mips_instruction)AdELOAD, &fr->adel);
-	err |= __put_user((mips_instruction)BD_COOKIE, &fr->cookie);
-	err |= __put_user(cpc, &fr->epc);
-
-	if (unlikely(err)) {
-		fpuemuprivate.stats.errors++;
-		return SIGBUS;
-	}
-
-	regs->cp0_epc = VA_TO_REG & dsemul_insns[0];
-
-	flush_cache_sigtramp((unsigned long)&fr->adel);
-
-	return SIGILL;		/* force out of emulation loop */
-}
-
-/* 
  * Conversion table from MIPS compare ops 48-63
- * cond = ieee754dp_cmp(x,y,IEEE754_UN);
+ * cond = ieee754dp_cmp(x,y,IEEE754_UN,sig);
  */
 static const unsigned char cmptab[8] = {
-	0,					/* cmp_0 (sig) cmp_sf */
-	IEEE754_CUN,				/* cmp_un (sig) cmp_ngle */
-	IEEE754_CEQ,				/* cmp_eq (sig) cmp_seq */
-	IEEE754_CEQ | IEEE754_CUN,		/* cmp_ueq (sig) cmp_ngl  */
-	IEEE754_CLT,				/* cmp_olt (sig) cmp_lt */
-	IEEE754_CLT | IEEE754_CUN,		/* cmp_ult (sig) cmp_nge */
-	IEEE754_CLT | IEEE754_CEQ,		/* cmp_ole (sig) cmp_le */
-	IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */
+	0,			/* cmp_0 (sig) cmp_sf */
+	IEEE754_CUN,		/* cmp_un (sig) cmp_ngle */
+	IEEE754_CEQ,		/* cmp_eq (sig) cmp_seq */
+	IEEE754_CEQ | IEEE754_CUN,	/* cmp_ueq (sig) cmp_ngl  */
+	IEEE754_CLT,		/* cmp_olt (sig) cmp_lt */
+	IEEE754_CLT | IEEE754_CUN,	/* cmp_ult (sig) cmp_nge */
+	IEEE754_CLT | IEEE754_CEQ,	/* cmp_ole (sig) cmp_le */
+	IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN,	/* cmp_ule (sig) cmp_ngt */
 };
 
-#define SIFROMREG(si,x)	((si) = ctx->regs[x])
-#define SITOREG(si,x)	(ctx->regs[x] = (int)(si))
-
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
-#define DIFROMREG(di,x)	((di) = ctx->regs[x])
-#define DITOREG(di,x)	(ctx->regs[x] = (di))
-#endif
-
-#define SPFROMREG(sp,x)	((sp).bits = ctx->regs[x])
-#define SPTOREG(sp,x)	(ctx->regs[x] = (sp).bits)
-
-#ifdef CP0_STATUS_FR_SUPPORT
-#define DPFROMREG(dp,x)	((dp).bits = \
-	ctx->regs[(xcp->cp0_status & ST0_FR) ? x : (x & ~1)])
-#define DPTOREG(dp,x)	(ctx->regs[(xcp->cp0_status & ST0_FR) ? x : (x & ~1)] \
-	= (dp).bits)
-#else
-/* Beware: MIPS COP1 doubles are always little_word endian in registers */
-#define DPFROMREG(dp,x)	\
-	((dp).bits = ((u64)ctx->regs[(x)+1] << 32) | ctx->regs[x])
-#define DPTOREG(dp,x) \
-	(ctx->regs[x] = (dp).bits, ctx->regs[(x)+1] = (dp).bits >> 32)
-#endif
 
 #if __mips >= 4 && __mips != 32
 
@@ -889,17 +571,17 @@
 static ieee754##p fpemu_##p##_##name (ieee754##p r, ieee754##p s, \
     ieee754##p t) \
 { \
-    struct ieee754_csr ieee754_csr_save; \
-    s = f1 (s, t); \
-    ieee754_csr_save = ieee754_csr; \
-    s = f2 (s, r); \
-    ieee754_csr_save.cx |= ieee754_csr.cx; \
-    ieee754_csr_save.sx |= ieee754_csr.sx; \
-    s = f3 (s); \
-    ieee754_csr.cx |= ieee754_csr_save.cx; \
-    ieee754_csr.sx |= ieee754_csr_save.sx; \
-    return s; \
-}    
+	struct ieee754_csr ieee754_csr_save; \
+	s = f1 (s, t); \
+	ieee754_csr_save = ieee754_csr; \
+	s = f2 (s, r); \
+	ieee754_csr_save.cx |= ieee754_csr.cx; \
+	ieee754_csr_save.sx |= ieee754_csr.sx; \
+	s = f3 (s); \
+	ieee754_csr.cx |= ieee754_csr_save.cx; \
+	ieee754_csr.sx |= ieee754_csr_save.sx; \
+	return s; \
+}
 
 static ieee754dp fpemu_dp_recip(ieee754dp d)
 {
@@ -921,233 +603,184 @@
 	return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s));
 }
 
-DEF3OP(madd, sp, ieee754sp_mul, ieee754sp_add, );
-DEF3OP(msub, sp, ieee754sp_mul, ieee754sp_sub, );
+DEF3OP(madd, sp, ieee754sp_mul, ieee754sp_add,);
+DEF3OP(msub, sp, ieee754sp_mul, ieee754sp_sub,);
 DEF3OP(nmadd, sp, ieee754sp_mul, ieee754sp_add, ieee754sp_neg);
 DEF3OP(nmsub, sp, ieee754sp_mul, ieee754sp_sub, ieee754sp_neg);
-DEF3OP(madd, dp, ieee754dp_mul, ieee754dp_add, );
-DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, );
+DEF3OP(madd, dp, ieee754dp_mul, ieee754dp_add,);
+DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub,);
 DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg);
 DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg);
 
 static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
-                    mips_instruction ir)
+	mips_instruction ir)
 {
 	unsigned rcsr = 0;	/* resulting csr */
 
 	fpuemuprivate.stats.cp1xops++;
 
 	switch (MIPSInst_FMA_FFMT(ir)) {
-	case s_fmt:		/* 0 */
-		{
-			ieee754sp(*handler) (ieee754sp, ieee754sp,
-					     ieee754sp);
-			ieee754sp fd, fr, fs, ft;
-
-			switch (MIPSInst_FUNC(ir)) {
-			case lwxc1_op:
-				{
-					u32 *va = REG_TO_VA(
-						xcp->regs[MIPSInst_FR(ir)] +
-						xcp->regs[MIPSInst_FT(ir)]);
-					fpureg_t val;
-
-					if (get_user(val, va)) {
-						fpuemuprivate.stats.errors++;
-						return SIGBUS;
-					}
-					if (xcp->cp0_status & ST0_FR) {
-						/* load whole register */
-						ctx->regs[MIPSInst_FD(ir)] =
-						    val;
-					} else if (MIPSInst_FD(ir) & 1) {
-						/* load to m.s. 32 bits */
-#if defined(SINGLE_ONLY_FPU)
-						/* illegal register in single-float mode */
-						return SIGILL;
-#else
-						ctx->
-						    regs[
-							 (MIPSInst_FD(ir) &
-							  ~1)] &=
-						    0xffffffff;
-						ctx->
-						    regs[
-							 (MIPSInst_FD(ir) &
-							  ~1)] |=
-						    val << 32;
-#endif
-					} else {
-						/* load to l.s. 32 bits */
-						ctx->
-						    regs[MIPSInst_FD(ir)]
-						    &= ~0xffffffffLL;
-						ctx->
-						    regs[MIPSInst_FD(ir)]
-						    |= val;
-					}
-				}
-				break;
+	case s_fmt:{		/* 0 */
 
-			case swxc1_op:
-				{
-					u32 *va = REG_TO_VA(
-						xcp->regs[MIPSInst_FR(ir)] +
-						xcp->regs[MIPSInst_FT(ir)]);
-					unsigned int val;
-
-					if (xcp->cp0_status & ST0_FR) {
-						/* store whole register */
-						val = ctx->regs[MIPSInst_FS(ir)];
-					} else if (MIPSInst_FS(ir) & 1) {
-#if defined(SINGLE_ONLY_FPU)
-						/* illegal register in single-float mode */
-						return SIGILL;
-#else
-						/* store from m.s. 32 bits */
-						val = ctx->regs[(MIPSInst_FS(ir) & ~1)] >> 32;
+		ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp);
+		ieee754sp fd, fr, fs, ft;
+		u32 *va;
+		u32 val;
+
+		switch (MIPSInst_FUNC(ir)) {
+		case lwxc1_op:
+			va = REG_TO_VA(xcp->regs[MIPSInst_FR(ir)] +
+				xcp->regs[MIPSInst_FT(ir)]);
+
+			fpuemuprivate.stats.loads++;
+			if (get_user(val, va)) {
+				fpuemuprivate.stats.errors++;
+				return SIGBUS;
+			}
+#ifdef SINGLE_ONLY_FPU
+			if (MIPSInst_FD(ir) & 1) {
+				/* illegal register in single-float
+				 * mode
+				 */
+				return SIGILL;
+			}
 #endif
-					} else {
-						/* store from l.s. 32 bits */
-						val =
-						    ctx->
-						    regs[MIPSInst_FS(ir)];
-					}
-					if (put_user(val, va)) {
-						fpuemuprivate.stats.errors++;
-						return SIGBUS;
-					}
-				}
-				break;
+			SITOREG(val, MIPSInst_FD(ir));
+			break;
 
-			case madd_s_op:
-				handler = fpemu_sp_madd;
-				goto scoptop;
-			case msub_s_op:
-				handler = fpemu_sp_msub;
-				goto scoptop;
-			case nmadd_s_op:
-				handler = fpemu_sp_nmadd;
-				goto scoptop;
-			case nmsub_s_op:
-				handler = fpemu_sp_nmsub;
-				goto scoptop;
+		case swxc1_op:
+			va = REG_TO_VA(xcp->regs[MIPSInst_FR(ir)] +
+				xcp->regs[MIPSInst_FT(ir)]);
 
-			      scoptop:
-				SPFROMREG(fr, MIPSInst_FR(ir));
-				SPFROMREG(fs, MIPSInst_FS(ir));
-				SPFROMREG(ft, MIPSInst_FT(ir));
-				fd = (*handler) (fr, fs, ft);
-				SPTOREG(fd, MIPSInst_FD(ir));
+			fpuemuprivate.stats.stores++;
+#ifdef SINGLE_ONLY_FPU
+			if (MIPSInst_FS(ir) & 1) {
+				/* illegal register in single-float
+				 * mode
+				 */
+				return SIGILL;
+			}
+#endif
 
-			      copcsr:
-				if (ieee754_cxtest(IEEE754_INEXACT))
-					rcsr |=
-					    FPU_CSR_INE_X | FPU_CSR_INE_S;
-				if (ieee754_cxtest(IEEE754_UNDERFLOW))
-					rcsr |=
-					    FPU_CSR_UDF_X | FPU_CSR_UDF_S;
-				if (ieee754_cxtest(IEEE754_OVERFLOW))
-					rcsr |=
-					    FPU_CSR_OVF_X | FPU_CSR_OVF_S;
-				if (ieee754_cxtest
-				    (IEEE754_INVALID_OPERATION)) rcsr |=
-					    FPU_CSR_INV_X | FPU_CSR_INV_S;
-
-				ctx->sr =
-				    (ctx->sr & ~FPU_CSR_ALL_X) | rcsr;
-				if (ieee754_csr.nod)
-				    ctx->sr |= 0x1000000;
-				if ((ctx->sr >> 5) & ctx->
-				    sr & FPU_CSR_ALL_E) {
-		/*printk ("SIGFPE: fpu csr = %08x\n",ctx->sr); */
-					return SIGFPE;
-				}
+			SIFROMREG(val, MIPSInst_FS(ir));
+			if (put_user(val, va)) {
+				fpuemuprivate.stats.errors++;
+				return SIGBUS;
+			}
+			break;
 
-				break;
+		case madd_s_op:
+			handler = fpemu_sp_madd;
+			goto scoptop;
+		case msub_s_op:
+			handler = fpemu_sp_msub;
+			goto scoptop;
+		case nmadd_s_op:
+			handler = fpemu_sp_nmadd;
+			goto scoptop;
+		case nmsub_s_op:
+			handler = fpemu_sp_nmsub;
+			goto scoptop;
 
-			default:
-				return SIGILL;
+		      scoptop:
+			SPFROMREG(fr, MIPSInst_FR(ir));
+			SPFROMREG(fs, MIPSInst_FS(ir));
+			SPFROMREG(ft, MIPSInst_FT(ir));
+			fd = (*handler) (fr, fs, ft);
+			SPTOREG(fd, MIPSInst_FD(ir));
+
+		      copcsr:
+			if (ieee754_cxtest(IEEE754_INEXACT))
+				rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
+			if (ieee754_cxtest(IEEE754_UNDERFLOW))
+				rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
+			if (ieee754_cxtest(IEEE754_OVERFLOW))
+				rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
+			if (ieee754_cxtest(IEEE754_INVALID_OPERATION))
+				rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;
+
+			ctx->sr = (ctx->sr & ~FPU_CSR_ALL_X) | rcsr;
+			if (ieee754_csr.nod)
+				ctx->sr |= 0x1000000;
+			if ((ctx->sr >> 5) & ctx->sr & FPU_CSR_ALL_E) {
+				/*printk ("SIGFPE: fpu csr = %08x\n",
+				   ctx->sr); */
+				return SIGFPE;
 			}
+
+			break;
+
+		default:
+			return SIGILL;
 		}
 		break;
+	}
 
-#if !defined(SINGLE_ONLY_FPU)
-	case d_fmt:		/* 1 */
-		{
-			ieee754dp(*handler) (ieee754dp, ieee754dp,
-					     ieee754dp);
-			ieee754dp fd, fr, fs, ft;
-
-			switch (MIPSInst_FUNC(ir)) {
-			case ldxc1_op:
-				{
-					u64 *va = REG_TO_VA(
-						xcp->regs[MIPSInst_FR(ir)] +
-						xcp->regs[MIPSInst_FT(ir)]);
-					u64 val;
-
-					if (get_user(val, va)) {
-						fpuemuprivate.stats.errors++;
-						return SIGBUS;
-					}
-					ctx->regs[MIPSInst_FD(ir)] = val;
-				}
-				break;
+#ifndef SINGLE_ONLY_FPU
+	case d_fmt:{		/* 1 */
+		ieee754dp(*handler) (ieee754dp, ieee754dp, ieee754dp);
+		ieee754dp fd, fr, fs, ft;
+		u64 *va;
+		u64 val;
 
-			case sdxc1_op:
-				{
-					u64 *va = REG_TO_VA(
-						xcp->regs[MIPSInst_FR(ir)] +
-						xcp->regs[MIPSInst_FT(ir)]);
-					u64 val;
-
-					val = ctx->regs[MIPSInst_FS(ir)];
-					if (put_user(val, va)) {
-						fpuemuprivate.stats.errors++;
-						return SIGBUS;
-					}
-				}
-				break;
+		switch (MIPSInst_FUNC(ir)) {
+		case ldxc1_op:
+			va = REG_TO_VA(xcp->regs[MIPSInst_FR(ir)] +
+				xcp->regs[MIPSInst_FT(ir)]);
 
-			case madd_d_op:
-				handler = fpemu_dp_madd;
-				goto dcoptop;
-
-			case msub_d_op:
-				handler = fpemu_dp_msub;
-				goto dcoptop;
-
-			case nmadd_d_op:
-				handler = fpemu_dp_nmadd;
-				goto dcoptop;
-
-			case nmsub_d_op:
-				handler = fpemu_dp_nmsub;
-				goto dcoptop;
+			fpuemuprivate.stats.loads++;
+			if (get_user(val, va)) {
+				fpuemuprivate.stats.errors++;
+				return SIGBUS;
+			}
+			DITOREG(val, MIPSInst_FD(ir));
+			break;
 
-			      dcoptop:
-				DPFROMREG(fr, MIPSInst_FR(ir));
-				DPFROMREG(fs, MIPSInst_FS(ir));
-				DPFROMREG(ft, MIPSInst_FT(ir));
-				fd = (*handler) (fr, fs, ft);
-				DPTOREG(fd, MIPSInst_FD(ir));
-				goto copcsr;
+		case sdxc1_op:
+			va = REG_TO_VA(xcp->regs[MIPSInst_FR(ir)] +
+				xcp->regs[MIPSInst_FT(ir)]);
 
-			default:
-				return SIGILL;
+			fpuemuprivate.stats.stores++;
+			DIFROMREG(val, MIPSInst_FS(ir));
+			if (put_user(val, va)) {
+				fpuemuprivate.stats.errors++;
+				return SIGBUS;
 			}
+			break;
+
+		case madd_d_op:
+			handler = fpemu_dp_madd;
+			goto dcoptop;
+		case msub_d_op:
+			handler = fpemu_dp_msub;
+			goto dcoptop;
+		case nmadd_d_op:
+			handler = fpemu_dp_nmadd;
+			goto dcoptop;
+		case nmsub_d_op:
+			handler = fpemu_dp_nmsub;
+			goto dcoptop;
+
+		      dcoptop:
+			DPFROMREG(fr, MIPSInst_FR(ir));
+			DPFROMREG(fs, MIPSInst_FS(ir));
+			DPFROMREG(ft, MIPSInst_FT(ir));
+			fd = (*handler) (fr, fs, ft);
+			DPTOREG(fd, MIPSInst_FD(ir));
+			goto copcsr;
+
+		default:
+			return SIGILL;
 		}
 		break;
+	}
 #endif
 
 	case 0x7:		/* 7 */
-		{
-			if (MIPSInst_FUNC(ir) != pfetch_op) {
-				return SIGILL;
-			}
-			/* ignore prefx operation */
+		if (MIPSInst_FUNC(ir) != pfetch_op) {
+			return SIGILL;
 		}
+		/* ignore prefx operation */
 		break;
 
 	default:
@@ -1164,7 +797,7 @@
  * Emulate a single COP1 arithmetic instruction.
  */
 static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
-                   mips_instruction ir)
+	mips_instruction ir)
 {
 	int rfmt;		/* resulting format */
 	unsigned rcsr = 0;	/* resulting csr */
@@ -1174,49 +807,52 @@
 		ieee754sp s;
 		int w;
 #if __mips64
-		long long l;
+		s64 l;
 #endif
 	} rv;			/* resulting value */
 
 	fpuemuprivate.stats.cp1ops++;
 	switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) {
-	case s_fmt: {		/* 0 */
-		ieee754sp(*handler) ();
+	case s_fmt:{		/* 0 */
+		union {
+			ieee754sp(*b) (ieee754sp, ieee754sp);
+			ieee754sp(*u) (ieee754sp);
+		} handler;
 
 		switch (MIPSInst_FUNC(ir)) {
 			/* binary ops */
 		case fadd_op:
-			handler = ieee754sp_add;
+			handler.b = ieee754sp_add;
 			goto scopbop;
 		case fsub_op:
-			handler = ieee754sp_sub;
+			handler.b = ieee754sp_sub;
 			goto scopbop;
 		case fmul_op:
-			handler = ieee754sp_mul;
+			handler.b = ieee754sp_mul;
 			goto scopbop;
 		case fdiv_op:
-			handler = ieee754sp_div;
+			handler.b = ieee754sp_div;
 			goto scopbop;
 
 			/* unary  ops */
 #if __mips >= 2 || __mips64
 		case fsqrt_op:
-			handler = ieee754sp_sqrt;
+			handler.u = ieee754sp_sqrt;
 			goto scopuop;
 #endif
 #if __mips >= 4 && __mips != 32
 		case frsqrt_op:
-			handler = fpemu_sp_rsqrt;
+			handler.u = fpemu_sp_rsqrt;
 			goto scopuop;
 		case frecip_op:
-			handler = fpemu_sp_recip;
+			handler.u = fpemu_sp_recip;
 			goto scopuop;
 #endif
 #if __mips >= 4
 		case fmovc_op:
 			cond = fpucondbit[MIPSInst_FT(ir) >> 2];
 			if (((ctx->sr & cond) != 0) !=
-			    ((MIPSInst_FT(ir) & 1) != 0))
+				((MIPSInst_FT(ir) & 1) != 0))
 				return 0;
 			SPFROMREG(rv.s, MIPSInst_FS(ir));
 			break;
@@ -1232,10 +868,10 @@
 			break;
 #endif
 		case fabs_op:
-			handler = ieee754sp_abs;
+			handler.u = ieee754sp_abs;
 			goto scopuop;
 		case fneg_op:
-			handler = ieee754sp_neg;
+			handler.u = ieee754sp_neg;
 			goto scopuop;
 		case fmov_op:
 			/* an easy one */
@@ -1243,25 +879,25 @@
 			goto copcsr;
 
 			/* binary op on handler */
-scopbop:
+		      scopbop:
 			{
 				ieee754sp fs, ft;
 
 				SPFROMREG(fs, MIPSInst_FS(ir));
 				SPFROMREG(ft, MIPSInst_FT(ir));
 
-				rv.s = (*handler) (fs, ft);
+				rv.s = (*handler.b) (fs, ft);
 				goto copcsr;
 			}
-scopuop:
+		      scopuop:
 			{
 				ieee754sp fs;
 
 				SPFROMREG(fs, MIPSInst_FS(ir));
-				rv.s = (*handler) (fs);
+				rv.s = (*handler.u) (fs);
 				goto copcsr;
 			}
-copcsr:
+		      copcsr:
 			if (ieee754_cxtest(IEEE754_INEXACT))
 				rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
 			if (ieee754_cxtest(IEEE754_UNDERFLOW))
@@ -1270,15 +906,14 @@
 				rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
 			if (ieee754_cxtest(IEEE754_ZERO_DIVIDE))
 				rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S;
-			if (ieee754_cxtest
-				(IEEE754_INVALID_OPERATION)) rcsr |=
-					    FPU_CSR_INV_X | FPU_CSR_INV_S;
-				break;
+			if (ieee754_cxtest(IEEE754_INVALID_OPERATION))
+				rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;
+			break;
 
-				/* unary conv ops */
+			/* unary conv ops */
 		case fcvts_op:
 			return SIGILL;	/* not defined */
-		case fcvtd_op: {
+		case fcvtd_op:{
 #ifdef SINGLE_ONLY_FPU
 			return SIGILL;	/* not defined */
 #else
@@ -1290,7 +925,7 @@
 			goto copcsr;
 		}
 #endif
-		case fcvtw_op: {
+		case fcvtw_op:{
 			ieee754sp fs;
 
 			SPFROMREG(fs, MIPSInst_FS(ir));
@@ -1303,7 +938,7 @@
 		case fround_op:
 		case ftrunc_op:
 		case fceil_op:
-		case ffloor_op: {
+		case ffloor_op:{
 			unsigned int oldrm = ieee754_csr.rm;
 			ieee754sp fs;
 
@@ -1317,7 +952,7 @@
 #endif /* __mips >= 2 */
 
 #if __mips64 && !defined(SINGLE_ONLY_FPU)
-		case fcvtl_op: {
+		case fcvtl_op:{
 			ieee754sp fs;
 
 			SPFROMREG(fs, MIPSInst_FS(ir));
@@ -1329,7 +964,7 @@
 		case froundl_op:
 		case ftruncl_op:
 		case fceill_op:
-		case ffloorl_op: {
+		case ffloorl_op:{
 			unsigned int oldrm = ieee754_csr.rm;
 			ieee754sp fs;
 
@@ -1349,14 +984,17 @@
 
 				SPFROMREG(fs, MIPSInst_FS(ir));
 				SPFROMREG(ft, MIPSInst_FT(ir));
-				rv.w = ieee754sp_cmp(fs, ft, cmptab[cmpop & 0x7]);
+				rv.w = ieee754sp_cmp(fs, ft,
+					cmptab[cmpop & 0x7], cmpop & 0x8);
 				rfmt = -1;
-				if ((cmpop & 0x8) && ieee754_cxtest(IEEE754_INVALID_OPERATION))
+				if ((cmpop & 0x8) && ieee754_cxtest
+					(IEEE754_INVALID_OPERATION))
 					rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
 				else
 					goto copcsr;
 
-			} else {
+			}
+			else {
 				return SIGILL;
 			}
 			break;
@@ -1364,43 +1002,47 @@
 		break;
 	}
 
-#if !defined(SINGLE_ONLY_FPU)
-	case d_fmt: {
-		ieee754dp(*handler) ();
+#ifndef SINGLE_ONLY_FPU
+	case d_fmt:{
+		union {
+			ieee754dp(*b) (ieee754dp, ieee754dp);
+			ieee754dp(*u) (ieee754dp);
+		} handler;
 
 		switch (MIPSInst_FUNC(ir)) {
 			/* binary ops */
 		case fadd_op:
-			handler = ieee754dp_add;
+			handler.b = ieee754dp_add;
 			goto dcopbop;
 		case fsub_op:
-			handler = ieee754dp_sub;
+			handler.b = ieee754dp_sub;
 			goto dcopbop;
 		case fmul_op:
-			handler = ieee754dp_mul;
+			handler.b = ieee754dp_mul;
 			goto dcopbop;
 		case fdiv_op:
-			handler = ieee754dp_div;
+			handler.b = ieee754dp_div;
 			goto dcopbop;
 
 			/* unary  ops */
 #if __mips >= 2 || __mips64
 		case fsqrt_op:
-			handler = ieee754dp_sqrt;
+			handler.u = ieee754dp_sqrt;
 			goto dcopuop;
 #endif
 #if __mips >= 4 && __mips != 32
 		case frsqrt_op:
-			handler = fpemu_dp_rsqrt;
+			handler.u = fpemu_dp_rsqrt;
 			goto dcopuop;
 		case frecip_op:
-			handler = fpemu_dp_recip;
+			handler.u = fpemu_dp_recip;
 			goto dcopuop;
 #endif
 #if __mips >= 4
 		case fmovc_op:
 			cond = fpucondbit[MIPSInst_FT(ir) >> 2];
-			if (((ctx->sr & cond) != 0) != ((MIPSInst_FT(ir) & 1) != 0))
+			if (((ctx->sr & cond) != 0) !=
+				((MIPSInst_FT(ir) & 1) != 0))
 				return 0;
 			DPFROMREG(rv.d, MIPSInst_FS(ir));
 			break;
@@ -1416,11 +1058,11 @@
 			break;
 #endif
 		case fabs_op:
-			handler = ieee754dp_abs;
+			handler.u = ieee754dp_abs;
 			goto dcopuop;
 
 		case fneg_op:
-			handler = ieee754dp_neg;
+			handler.u = ieee754dp_neg;
 			goto dcopuop;
 
 		case fmov_op:
@@ -1429,27 +1071,25 @@
 			goto copcsr;
 
 			/* binary op on handler */
-dcopbop:
-			{
+		      dcopbop:{
 				ieee754dp fs, ft;
 
 				DPFROMREG(fs, MIPSInst_FS(ir));
 				DPFROMREG(ft, MIPSInst_FT(ir));
 
-				rv.d = (*handler) (fs, ft);
+				rv.d = (*handler.b) (fs, ft);
 				goto copcsr;
 			}
-dcopuop:
-			{
+		      dcopuop:{
 				ieee754dp fs;
 
 				DPFROMREG(fs, MIPSInst_FS(ir));
-				rv.d = (*handler) (fs);
+				rv.d = (*handler.u) (fs);
 				goto copcsr;
 			}
 
-		/* unary conv ops */
-		case fcvts_op: {
+			/* unary conv ops */
+		case fcvts_op:{
 			ieee754dp fs;
 
 			DPFROMREG(fs, MIPSInst_FS(ir));
@@ -1460,7 +1100,7 @@
 		case fcvtd_op:
 			return SIGILL;	/* not defined */
 
-		case fcvtw_op: {
+		case fcvtw_op:{
 			ieee754dp fs;
 
 			DPFROMREG(fs, MIPSInst_FS(ir));
@@ -1473,7 +1113,7 @@
 		case fround_op:
 		case ftrunc_op:
 		case fceil_op:
-		case ffloor_op: {
+		case ffloor_op:{
 			unsigned int oldrm = ieee754_csr.rm;
 			ieee754dp fs;
 
@@ -1487,7 +1127,7 @@
 #endif
 
 #if __mips64 && !defined(SINGLE_ONLY_FPU)
-		case fcvtl_op: {
+		case fcvtl_op:{
 			ieee754dp fs;
 
 			DPFROMREG(fs, MIPSInst_FS(ir));
@@ -1499,7 +1139,7 @@
 		case froundl_op:
 		case ftruncl_op:
 		case fceill_op:
-		case ffloorl_op: {
+		case ffloorl_op:{
 			unsigned int oldrm = ieee754_csr.rm;
 			ieee754dp fs;
 
@@ -1519,33 +1159,42 @@
 
 				DPFROMREG(fs, MIPSInst_FS(ir));
 				DPFROMREG(ft, MIPSInst_FT(ir));
-				rv.w = ieee754dp_cmp(fs, ft, cmptab[cmpop & 0x7]);
+				rv.w = ieee754dp_cmp(fs, ft,
+					cmptab[cmpop & 0x7], cmpop & 0x8);
 				rfmt = -1;
-				if ((cmpop & 0x8) && ieee754_cxtest (IEEE754_INVALID_OPERATION))
+				if ((cmpop & 0x8)
+					&&
+					ieee754_cxtest
+					(IEEE754_INVALID_OPERATION))
 					rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
 				else
 					goto copcsr;
 
-			} else {
+			}
+			else {
 				return SIGILL;
 			}
 			break;
 		}
 		break;
 	}
-#endif /* !defined(SINGLE_ONLY_FPU) */
+#endif /* ifndef SINGLE_ONLY_FPU */
+
+	case w_fmt:{
+		ieee754sp fs;
 
-	case w_fmt: {
 		switch (MIPSInst_FUNC(ir)) {
 		case fcvts_op:
 			/* convert word to single precision real */
-			rv.s = ieee754sp_fint(ctx-> regs[MIPSInst_FS(ir)]);
+			SPFROMREG(fs, MIPSInst_FS(ir));
+			rv.s = ieee754sp_fint(fs.bits);
 			rfmt = s_fmt;
 			goto copcsr;
-#if !defined(SINGLE_ONLY_FPU)
+#ifndef SINGLE_ONLY_FPU
 		case fcvtd_op:
 			/* convert word to double precision real */
-			rv.d = ieee754dp_fint(ctx-> regs[MIPSInst_FS(ir)]);
+			SPFROMREG(fs, MIPSInst_FS(ir));
+			rv.d = ieee754dp_fint(fs.bits);
 			rfmt = d_fmt;
 			goto copcsr;
 #endif
@@ -1556,16 +1205,16 @@
 	}
 
 #if __mips64 && !defined(SINGLE_ONLY_FPU)
-	case l_fmt: {
+	case l_fmt:{
 		switch (MIPSInst_FUNC(ir)) {
 		case fcvts_op:
 			/* convert long to single precision real */
-			rv.s = ieee754sp_flong(ctx-> regs[MIPSInst_FS(ir)]);
+			rv.s = ieee754sp_flong(ctx->regs[MIPSInst_FS(ir)]);
 			rfmt = s_fmt;
 			goto copcsr;
 		case fcvtd_op:
 			/* convert long to double precision real */
-			rv.d = ieee754dp_flong(ctx-> regs[MIPSInst_FS(ir)]);
+			rv.d = ieee754dp_flong(ctx->regs[MIPSInst_FS(ir)]);
 			rfmt = d_fmt;
 			goto copcsr;
 		default:
@@ -1592,11 +1241,11 @@
 		return SIGFPE;
 	}
 
-	/* 
+	/*
 	 * Now we can safely write the result back to the register file.
 	 */
 	switch (rfmt) {
-	case -1: {
+	case -1:{
 #if __mips >= 4
 		cond = fpucondbit[MIPSInst_FD(ir) >> 2];
 #else
@@ -1608,7 +1257,7 @@
 			ctx->sr &= ~cond;
 		break;
 	}
-#if !defined(SINGLE_ONLY_FPU)
+#ifndef SINGLE_ONLY_FPU
 	case d_fmt:
 		DPTOREG(rv.d, MIPSInst_FD(ir));
 		break;
@@ -1631,16 +1280,10 @@
 	return 0;
 }
 
-
-/*
- * Emulate the floating point instruction at EPC, and continue to run until we
- * hit a non-fp instruction, or a backward branch.  This cuts down dramatically
- * on the per instruction exception overhead.
- */
-int fpu_emulator_cop1Handler(struct pt_regs *xcp)
+int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp,
+	struct mips_fpu_soft_struct *ctx)
 {
-	struct mips_fpu_soft_struct *ctx = &current->thread.fpu.soft;
-	unsigned long oldepc, prevepc;
+	gpreg_t oldepc, prevepc;
 	mips_instruction insn, *insnp;
 	int sig = 0;
 
@@ -1652,9 +1295,10 @@
 		 * This is a braindead way to do it but the only sane way I
 		 * found to keep the 64-bit egcs 1.1.2 from crashing.
 		 */
-		insnp = (mips_instruction *) xcp->cp0_epc;
+		insnp = (mips_instruction *) REG_TO_VA xcp->cp0_epc;
+
 		if (verify_area(VERIFY_READ, insnp, 4) ||
-		    __get_user(insn, insnp)) {
+			__get_user(insn, insnp)) {
 			fpuemuprivate.stats.errors++;
 			return SIGBUS;
 		}
@@ -1673,9 +1317,13 @@
 			break;
 		if (sig)
 			break;
-
+#ifdef STANDALONE_EMULATOR
+		if (xcptno == EX_FPE)
+			break;
+#else
 		if (current->need_resched)
 			schedule();
+#endif
 	} while (xcp->cp0_epc > prevepc);
 
 	/* SIGILL indicates a non-fpu instruction */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/dp_add.c linux-2.4.20/arch/mips/math-emu/dp_add.c
--- linux-2.4.19/arch/mips/math-emu/dp_add.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/dp_add.c	2002-10-29 11:18:35.000000000 +0000
@@ -70,7 +70,7 @@
 		return x;
 
 
-		/* Inifity handeling 
+		/* Inifity handeling
 		 */
 
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
@@ -89,7 +89,7 @@
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
 		return x;
 
-		/* Zero handeling 
+		/* Zero handeling
 		 */
 
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/dp_cmp.c linux-2.4.20/arch/mips/math-emu/dp_cmp.c
--- linux-2.4.19/arch/mips/math-emu/dp_cmp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/dp_cmp.c	2002-10-29 11:18:35.000000000 +0000
@@ -27,7 +27,7 @@
 
 #include "ieee754dp.h"
 
-int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp)
+int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp, int sig)
 {
 	COMPXDP;
 	COMPYDP;
@@ -39,18 +39,18 @@
 	CLEARCX;	/* Even clear inexact flag here */
 
 	if (ieee754dp_isnan(x) || ieee754dp_isnan(y)) {
-		if (xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN)
+		if (sig || xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN)
 			SETCX(IEEE754_INVALID_OPERATION);
 		if (cmp & IEEE754_CUN)
 			return 1;
 		if (cmp & (IEEE754_CLT | IEEE754_CGT)) {
-			if (SETCX(IEEE754_INVALID_OPERATION))
+			if (sig && SETCX(IEEE754_INVALID_OPERATION))
 				return ieee754si_xcpt(0, "fcmpf", x);
 		}
 		return 0;
 	} else {
-		long long int vx = x.bits;
-		long long int vy = y.bits;
+		s64 vx = x.bits;
+		s64 vy = y.bits;
 
 		if (vx < 0)
 			vx = -vx ^ DP_SIGN_BIT;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/dp_div.c linux-2.4.20/arch/mips/math-emu/dp_div.c
--- linux-2.4.19/arch/mips/math-emu/dp_div.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/dp_div.c	2002-10-29 11:18:32.000000000 +0000
@@ -69,7 +69,7 @@
 		return x;
 
 
-		/* Infinity handeling 
+		/* Infinity handeling
 		 */
 
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
@@ -86,7 +86,7 @@
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
 		return ieee754dp_inf(xs ^ ys);
 
-		/* Zero handeling 
+		/* Zero handeling
 		 */
 
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
@@ -126,9 +126,9 @@
 	{
 		/* now the dirty work */
 
-		unsigned long long rm = 0;
+		u64 rm = 0;
 		int re = xe - ye;
-		unsigned long long bm;
+		u64 bm;
 
 		for (bm = DP_MBIT(DP_MBITS + 2); bm; bm >>= 1) {
 			if (xm >= ym) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/dp_flong.c linux-2.4.20/arch/mips/math-emu/dp_flong.c
--- linux-2.4.19/arch/mips/math-emu/dp_flong.c	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/dp_flong.c	2002-10-29 11:18:33.000000000 +0000
@@ -27,7 +27,7 @@
 
 #include "ieee754dp.h"
 
-ieee754dp ieee754dp_flong(long long x)
+ieee754dp ieee754dp_flong(s64 x)
 {
 	COMPXDP;
 
@@ -67,9 +67,9 @@
 	DPNORMRET1(xs, xe, xm, "dp_flong", x);
 }
 
-ieee754dp ieee754dp_fulong(unsigned long long u)
+ieee754dp ieee754dp_fulong(u64 u)
 {
-	if ((long long) u < 0)
+	if ((s64) u < 0)
 		return ieee754dp_add(ieee754dp_1e63(),
 				     ieee754dp_flong(u & ~(1ULL << 63)));
 	return ieee754dp_flong(u);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/dp_frexp.c linux-2.4.20/arch/mips/math-emu/dp_frexp.c
--- linux-2.4.19/arch/mips/math-emu/dp_frexp.c	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/dp_frexp.c	2002-10-29 11:18:35.000000000 +0000
@@ -27,7 +27,7 @@
 
 #include "ieee754dp.h"
 
-/* close to ieeep754dp_logb 
+/* close to ieeep754dp_logb
 */
 ieee754dp ieee754dp_frexp(ieee754dp x, int *eptr)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/dp_fsp.c linux-2.4.20/arch/mips/math-emu/dp_fsp.c
--- linux-2.4.19/arch/mips/math-emu/dp_fsp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/dp_fsp.c	2002-10-29 11:18:33.000000000 +0000
@@ -44,7 +44,7 @@
 	case IEEE754_CLASS_QNAN:
 		return ieee754dp_nanxcpt(builddp(xs,
 						 DP_EMAX + 1 + DP_EBIAS,
-						 ((unsigned long long) xm
+						 ((u64) xm
 						  << (DP_MBITS -
 						      SP_MBITS))), "fsp",
 					 x);
@@ -70,5 +70,5 @@
 	xm &= ~SP_HIDDEN_BIT;
 
 	return builddp(xs, xe + DP_EBIAS,
-		       (unsigned long long) xm << (DP_MBITS - SP_MBITS));
+		       (u64) xm << (DP_MBITS - SP_MBITS));
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/dp_modf.c linux-2.4.20/arch/mips/math-emu/dp_modf.c
--- linux-2.4.19/arch/mips/math-emu/dp_modf.c	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/dp_modf.c	2002-10-29 11:18:32.000000000 +0000
@@ -59,7 +59,7 @@
 		*ip = x;
 		return ieee754dp_zero(xs);
 	}
-	/* generate ipart mantissa by clearing bottom bits 
+	/* generate ipart mantissa by clearing bottom bits
 	 */
 	*ip = builddp(xs, xe + DP_EBIAS,
 		      ((xm >> (DP_MBITS - xe)) << (DP_MBITS - xe)) &
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/dp_mul.c linux-2.4.20/arch/mips/math-emu/dp_mul.c
--- linux-2.4.19/arch/mips/math-emu/dp_mul.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/dp_mul.c	2002-10-29 11:18:39.000000000 +0000
@@ -111,7 +111,7 @@
 	{
 		int re = xe + ye;
 		int rs = xs ^ ys;
-		unsigned long long rm;
+		u64 rm;
 
 		/* shunt to top of word */
 		xm <<= 64 - (DP_MBITS + 1);
@@ -121,23 +121,23 @@
 		 */
 
 		/* 32 * 32 => 64 */
-#define DPXMULT(x,y)	((unsigned long long)(x) * (unsigned long long)y)
+#define DPXMULT(x,y)	((u64)(x) * (u64)y)
 
 		{
 			unsigned lxm = xm;
 			unsigned hxm = xm >> 32;
 			unsigned lym = ym;
 			unsigned hym = ym >> 32;
-			unsigned long long lrm;
-			unsigned long long hrm;
+			u64 lrm;
+			u64 hrm;
 
 			lrm = DPXMULT(lxm, lym);
 			hrm = DPXMULT(hxm, hym);
 
 			{
-				unsigned long long t = DPXMULT(lxm, hym);
+				u64 t = DPXMULT(lxm, hym);
 				{
-					unsigned long long at =
+					u64 at =
 					    lrm + (t << 32);
 					hrm += at < lrm;
 					lrm = at;
@@ -146,9 +146,9 @@
 			}
 
 			{
-				unsigned long long t = DPXMULT(hxm, lym);
+				u64 t = DPXMULT(hxm, lym);
 				{
-					unsigned long long at =
+					u64 at =
 					    lrm + (t << 32);
 					hrm += at < lrm;
 					lrm = at;
@@ -161,7 +161,7 @@
 		/*
 		 * sticky shift down to normal rounding precision
 		 */
-		if ((signed long long) rm < 0) {
+		if ((s64) rm < 0) {
 			rm =
 			    (rm >> (64 - (DP_MBITS + 1 + 3))) |
 			    ((rm << (DP_MBITS + 1 + 3)) != 0);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/dp_sqrt.c linux-2.4.20/arch/mips/math-emu/dp_sqrt.c
--- linux-2.4.19/arch/mips/math-emu/dp_sqrt.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/dp_sqrt.c	2002-10-29 11:18:36.000000000 +0000
@@ -99,7 +99,7 @@
 	yh = y.bits >> 32;
 	yh = (yh >> 1) + 0x1ff80000;
 	yh = yh - table[(yh >> 15) & 31];
-	y.bits = ((unsigned long long) yh << 32) | (y.bits & 0xffffffff);
+	y.bits = ((u64) yh << 32) | (y.bits & 0xffffffff);
 
 	/* Heron's rule once with correction to improve to ~18 sig. bits */
 	/* t=x/y; y=y+t; py[n0]=py[n0]-0x00100006; py[n1]=0; */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/dp_sub.c linux-2.4.20/arch/mips/math-emu/dp_sub.c
--- linux-2.4.19/arch/mips/math-emu/dp_sub.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/dp_sub.c	2002-10-29 11:18:34.000000000 +0000
@@ -69,7 +69,7 @@
 		return x;
 
 
-		/* Inifity handeling 
+		/* Inifity handeling
 		 */
 
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
@@ -88,7 +88,7 @@
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
 		return x;
 
-		/* Zero handeling 
+		/* Zero handeling
 		 */
 
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
@@ -180,7 +180,7 @@
 				return ieee754dp_zero(0);	/* other round modes   => sign = 1 */
 		}
 
-		/* normalize to rounding precision 
+		/* normalize to rounding precision
 		 */
 		while ((xm >> (DP_MBITS + 3)) == 0) {
 			xm <<= 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/dp_tint.c linux-2.4.20/arch/mips/math-emu/dp_tint.c
--- linux-2.4.19/arch/mips/math-emu/dp_tint.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/dp_tint.c	2002-10-29 11:18:32.000000000 +0000
@@ -49,10 +49,7 @@
 	case IEEE754_CLASS_NORM:
 		break;
 	}
-	if (xe >= 31) {
-		/* look for valid corner case */
-		if (xe == 31 && xs && xm == DP_HIDDEN_BIT)
-			return -2147483648;
+	if (xe > 31) {
 		/* Set invalid. We will only use overflow for floating
 		   point overflow */
 		SETCX(IEEE754_INVALID_OPERATION);
@@ -62,7 +59,7 @@
 	if (xe > DP_MBITS) {
 		xm <<= xe - DP_MBITS;
 	} else if (xe < DP_MBITS) {
-		unsigned long long residue;
+		u64 residue;
 		int round;
 		int sticky;
 		int odd;
@@ -98,7 +95,8 @@
 				xm++;
 			break;
 		}
-		if ((xm >> 31) != 0) {
+		/* look for valid corner case 0x80000000 */
+		if ((xm >> 31) != 0 && (xs == 0 || xm != 0x80000000)) {
 			/* This can happen after rounding */
 			SETCX(IEEE754_INVALID_OPERATION);
 			return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/dp_tlong.c linux-2.4.20/arch/mips/math-emu/dp_tlong.c
--- linux-2.4.19/arch/mips/math-emu/dp_tlong.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/dp_tlong.c	2002-10-29 11:18:39.000000000 +0000
@@ -27,7 +27,7 @@
 
 #include "ieee754dp.h"
 
-long long ieee754dp_tlong(ieee754dp x)
+s64 ieee754dp_tlong(ieee754dp x)
 {
 	COMPXDP;
 
@@ -49,9 +49,9 @@
 		break;
 	}
 	if (xe >= 63) {
-		/* look for valid corner case */ 
+		/* look for valid corner case */
 		if (xe == 63 && xs && xm == DP_HIDDEN_BIT)
-			return -9223372036854775808LL;
+			return -0x8000000000000000LL;
 		/* Set invalid. We will only use overflow for floating
 		   point overflow */
 		SETCX(IEEE754_INVALID_OPERATION);
@@ -61,7 +61,7 @@
 	if (xe > DP_MBITS) {
 		xm <<= xe - DP_MBITS;
 	} else if (xe < DP_MBITS) {
-		unsigned long long residue;
+		u64 residue;
 		int round;
 		int sticky;
 		int odd;
@@ -73,7 +73,11 @@
 			xm = 0;
 		}
 		else {
-			residue = xm << (64 - DP_MBITS + xe);
+			/* Shifting a u64 64 times does not work,
+			* so we do it in two steps. Be aware that xe
+			* may be -1 */
+			residue = xm << (xe + 1);
+			residue <<= 63 - DP_MBITS;
 			round = (residue >> 63) != 0;
 			sticky = (residue << 1) != 0;
 			xm >>= DP_MBITS - xe;
@@ -110,14 +114,14 @@
 }
 
 
-unsigned long long ieee754dp_tulong(ieee754dp x)
+u64 ieee754dp_tulong(ieee754dp x)
 {
 	ieee754dp hb = ieee754dp_1e63();
 
 	/* what if x < 0 ?? */
 	if (ieee754dp_lt(x, hb))
-		return (unsigned long long) ieee754dp_tlong(x);
+		return (u64) ieee754dp_tlong(x);
 
-	return (unsigned long long) ieee754dp_tlong(ieee754dp_sub(x, hb)) |
+	return (u64) ieee754dp_tlong(ieee754dp_sub(x, hb)) |
 	    (1ULL << 63);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/dsemul.c linux-2.4.20/arch/mips/math-emu/dsemul.c
--- linux-2.4.19/arch/mips/math-emu/dsemul.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/dsemul.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,173 @@
+#include <linux/compiler.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/asm.h>
+#include <asm/bootinfo.h>
+#include <asm/byteorder.h>
+#include <asm/cpu.h>
+#include <asm/inst.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/branch.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+
+#include <asm/fpu_emulator.h>
+
+#include "ieee754.h"
+#include "dsemul.h"
+
+/* Strap kernel emulator for full MIPS IV emulation */
+
+#ifdef __mips
+#undef __mips
+#endif
+#define __mips 4
+
+extern struct mips_fpu_emulator_private fpuemuprivate;
+
+
+/*
+ * Emulate the arbritrary instruction ir at xcp->cp0_epc.  Required when
+ * we have to emulate the instruction in a COP1 branch delay slot.  Do
+ * not change cp0_epc due to the instruction
+ *
+ * According to the spec:
+ * 1) it shouldnt be a branch :-)
+ * 2) it can be a COP instruction :-(
+ * 3) if we are tring to run a protected memory space we must take
+ *    special care on memory access instructions :-(
+ */
+
+/*
+ * "Trampoline" return routine to catch exception following
+ *  execution of delay-slot instruction execution.
+ */
+
+struct emuframe {
+	mips_instruction	emul;
+	mips_instruction	badinst;
+	mips_instruction	cookie;
+	gpreg_t			epc;
+};
+
+int mips_dsemul(struct pt_regs *regs, mips_instruction ir, gpreg_t cpc)
+{
+	extern asmlinkage void handle_dsemulret(void);
+	mips_instruction *dsemul_insns;
+	struct emuframe *fr;
+	int err;
+
+	if (ir == 0) {		/* a nop is easy */
+		regs->cp0_epc = cpc;
+		regs->cp0_cause &= ~CAUSEF_BD;
+		return 0;
+	}
+#ifdef DSEMUL_TRACE
+	printk("dsemul %lx %lx\n", regs->cp0_epc, cpc);
+
+#endif
+
+	/*
+	 * The strategy is to push the instruction onto the user stack
+	 * and put a trap after it which we can catch and jump to
+	 * the required address any alternative apart from full
+	 * instruction emulation!!.
+	 *
+	 * Algorithmics used a system call instruction, and
+	 * borrowed that vector.  MIPS/Linux version is a bit
+	 * more heavyweight in the interests of portability and
+	 * multiprocessor support.  For Linux we generate a
+	 * an unaligned access and force an address error exception.
+	 *
+	 * For embedded systems (stand-alone) we prefer to use a
+	 * non-existing CP1 instruction. This prevents us from emulating
+	 * branches, but gives us a cleaner interface to the exception
+	 * handler (single entry point).
+	 */
+
+	/* Ensure that the two instructions are in the same cache line */
+	dsemul_insns = (mips_instruction *) REG_TO_VA ((regs->regs[29] - sizeof(struct emuframe)) & ~0x7);
+	fr = (struct emuframe *) dsemul_insns;
+
+	/* Verify that the stack pointer is not competely insane */
+	if (unlikely(verify_area(VERIFY_WRITE, fr, sizeof(struct emuframe))))
+		return SIGBUS;
+
+	err = __put_user(ir, &fr->emul);
+	err |= __put_user((mips_instruction)BADINST, &fr->badinst);
+	err |= __put_user((mips_instruction)BD_COOKIE, &fr->cookie);
+	err |= __put_user(cpc, &fr->epc);
+
+	if (unlikely(err)) {
+		fpuemuprivate.stats.errors++;
+		return SIGBUS;
+	}
+
+	regs->cp0_epc = VA_TO_REG & fr->emul;
+
+	flush_cache_sigtramp((unsigned long)&fr->badinst);
+
+	return SIGILL;		/* force out of emulation loop */
+}
+
+int do_dsemulret(struct pt_regs *xcp)
+{
+	struct emuframe *fr;
+	gpreg_t epc;
+	u32 insn, cookie;
+	int err = 0;
+
+	fr = (struct emuframe *) (xcp->cp0_epc - sizeof(mips_instruction));
+
+	/*
+	 * If we can't even access the area, something is very wrong, but we'll
+	 * leave that to the default handling
+	 */
+	if (verify_area(VERIFY_READ, fr, sizeof(struct emuframe)))
+		return 0;
+
+	/*
+	 * Do some sanity checking on the stackframe:
+	 *
+	 *  - Is the instruction pointed to by the EPC an BADINST?
+	 *  - Is the following memory word the BD_COOKIE?
+	 */
+	err = __get_user(insn, &fr->badinst);
+	err |= __get_user(cookie, &fr->cookie);
+
+	if (unlikely(err || (insn != BADINST) || (cookie != BD_COOKIE))) {
+		fpuemuprivate.stats.errors++;
+
+		return 0;
+	}
+
+	/*
+	 * At this point, we are satisfied that it's a BD emulation trap.  Yes,
+	 * a user might have deliberately put two malformed and useless
+	 * instructions in a row in his program, in which case he's in for a
+	 * nasty surprise - the next instruction will be treated as a
+	 * continuation address!  Alas, this seems to be the only way that we
+	 * can handle signals, recursion, and longjmps() in the context of
+	 * emulating the branch delay instruction.
+	 */
+
+#ifdef DSEMUL_TRACE
+	printk("dsemulret\n");
+#endif
+	if (__get_user(epc, &fr->epc)) {		/* Saved EPC */
+		/* This is not a good situation to be in */
+		force_sig(SIGBUS, current);
+
+		return 0;
+	}
+
+	/* Set EPC to return to post-branch instruction */
+	xcp->cp0_epc = epc;
+
+	return 1;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/dsemul.h linux-2.4.20/arch/mips/math-emu/dsemul.h
--- linux-2.4.19/arch/mips/math-emu/dsemul.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/dsemul.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,23 @@
+typedef long gpreg_t;
+typedef void *vaddr_t;
+
+#define REG_TO_VA (vaddr_t)
+#define VA_TO_REG (gpreg_t)
+
+int mips_dsemul(struct pt_regs *regs, mips_instruction ir, gpreg_t cpc);
+int do_dsemulret(struct pt_regs *xcp);
+
+/* Instruction which will always cause an address error */
+#define AdELOAD 0x8c000001	/* lw $0,1($0) */
+/* Instruction which will plainly cause a CP1 exception when FPU is disabled */
+#define CP1UNDEF 0x44400001    /* cfc1 $0,$0 undef  */
+
+/* Instruction inserted following the badinst to further tag the sequence */
+#define BD_COOKIE 0x0000bd36 /* tne $0,$0 with baggage */
+
+/* Setup which instruction to use for trampoline */
+#ifdef STANDALONE_EMULATOR
+#define BADINST CP1UNDEF
+#else
+#define BADINST AdELOAD
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/ieee754.c linux-2.4.20/arch/mips/math-emu/ieee754.c
--- linux-2.4.19/arch/mips/math-emu/ieee754.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/ieee754.c	2002-10-29 11:18:32.000000000 +0000
@@ -3,7 +3,7 @@
  *
  * BUGS
  * not much dp done
- * doesnt generate IEEE754_INEXACT
+ * doesn't generate IEEE754_INEXACT
  *
  */
 /*
@@ -50,7 +50,7 @@
 	"SNaN",
 };
 
-/* the control status register 
+/* the control status register
 */
 struct ieee754_csr ieee754_csr;
 
@@ -123,7 +123,7 @@
 	return ax.rv.si;
 }
 
-long long ieee754di_xcpt(long long r, const char *op, ...)
+s64 ieee754di_xcpt(s64 r, const char *op, ...)
 {
 	struct ieee754xctx ax;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/ieee754.h linux-2.4.20/arch/mips/math-emu/ieee754.h
--- linux-2.4.19/arch/mips/math-emu/ieee754.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/ieee754.h	2002-10-29 11:18:33.000000000 +0000
@@ -26,7 +26,7 @@
 
 /**************************************************************************
  *  Nov 7, 2000
- *  Modification to allow integration with Linux kernel 
+ *  Modification to allow integration with Linux kernel
  *
  *  Kevin D. Kissell, kevink@mips.com and Carsten Langgard, carstenl@mips.com
  *  Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
@@ -36,8 +36,8 @@
 /* Going from Algorithmics to Linux native environment, add this */
 #include <linux/types.h>
 
-/* 
- * Not very pretty, but the Linux kernel's normal va_list definition 
+/*
+ * Not very pretty, but the Linux kernel's normal va_list definition
  * does not allow it to be used as a structure element, as it is here.
  */
 #ifndef _STDARG_H
@@ -71,18 +71,18 @@
 typedef union _ieee754dp {
 	struct ieee754dp_konst oparts;
 	struct {
-		unsigned long long mant:52;
+		u64 mant:52;
 		unsigned int bexp:11;
 		unsigned int sign:1;
 	} parts;
-	unsigned long long bits;
+	u64 bits;
 	double d;
 } ieee754dp;
 
 typedef union _ieee754sp {
 	struct ieee754sp_konst parts;
 	float f;
-	unsigned long bits;
+	u32 bits;
 } ieee754sp;
 #endif
 
@@ -98,10 +98,10 @@
 	struct {
 		unsigned int sign:1;
 		unsigned int bexp:11;
-		unsigned long long mant:52;
+		u64 mant:52;
 	} parts;
 	double d;
-	unsigned long long bits;
+	u64 bits;
 } ieee754dp;
 
 struct ieee754sp_konst {
@@ -113,7 +113,7 @@
 typedef union _ieee754sp {
 	struct ieee754sp_konst parts;
 	float f;
-	unsigned long bits;
+	u32 bits;
 } ieee754sp;
 #endif
 
@@ -138,16 +138,16 @@
 
 ieee754sp ieee754sp_fint(int x);
 ieee754sp ieee754sp_funs(unsigned x);
-ieee754sp ieee754sp_flong(long long x);
-ieee754sp ieee754sp_fulong(unsigned long long x);
+ieee754sp ieee754sp_flong(s64 x);
+ieee754sp ieee754sp_fulong(u64 x);
 ieee754sp ieee754sp_fdp(ieee754dp x);
 
 int ieee754sp_tint(ieee754sp x);
 unsigned int ieee754sp_tuns(ieee754sp x);
-long long ieee754sp_tlong(ieee754sp x);
-unsigned long long ieee754sp_tulong(ieee754sp x);
+s64 ieee754sp_tlong(ieee754sp x);
+u64 ieee754sp_tulong(ieee754sp x);
 
-int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cop);
+int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cop, int sig);
 /*
  * basic sp math
  */
@@ -179,14 +179,14 @@
 ieee754dp ieee754dp_neg(ieee754dp x);
 ieee754dp ieee754dp_scalb(ieee754dp x, int);
 
-/* return exponent as integer in floating point format 
+/* return exponent as integer in floating point format
  */
 ieee754dp ieee754dp_logb(ieee754dp x);
 
 ieee754dp ieee754dp_fint(int x);
 ieee754dp ieee754dp_funs(unsigned x);
-ieee754dp ieee754dp_flong(long long x);
-ieee754dp ieee754dp_fulong(unsigned long long x);
+ieee754dp ieee754dp_flong(s64 x);
+ieee754dp ieee754dp_fulong(u64 x);
 ieee754dp ieee754dp_fsp(ieee754sp x);
 
 ieee754dp ieee754dp_ceil(ieee754dp x);
@@ -195,10 +195,10 @@
 
 int ieee754dp_tint(ieee754dp x);
 unsigned int ieee754dp_tuns(ieee754dp x);
-long long ieee754dp_tlong(ieee754dp x);
-unsigned long long ieee754dp_tulong(ieee754dp x);
+s64 ieee754dp_tlong(ieee754dp x);
+u64 ieee754dp_tulong(ieee754dp x);
 
-int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cop);
+int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cop, int sig);
 /*
  * basic sp math
  */
@@ -214,7 +214,7 @@
 
 
 
-/* 5 types of floating point number 
+/* 5 types of floating point number
 */
 #define IEEE754_CLASS_NORM	0x00
 #define IEEE754_CLASS_ZERO	0x01
@@ -238,7 +238,7 @@
 #define IEEE754_CGT	0x04
 #define IEEE754_CUN	0x08
 
-/* rounding mode 
+/* rounding mode
 */
 #define IEEE754_RN	0	/* round to nearest */
 #define IEEE754_RZ	1	/* round toward zero  */
@@ -253,65 +253,65 @@
 */
 static __inline int ieee754sp_eq(ieee754sp x, ieee754sp y)
 {
-	return ieee754sp_cmp(x, y, IEEE754_CEQ);
+	return ieee754sp_cmp(x, y, IEEE754_CEQ, 0);
 }
 
 static __inline int ieee754sp_ne(ieee754sp x, ieee754sp y)
 {
 	return ieee754sp_cmp(x, y,
-			     IEEE754_CLT | IEEE754_CGT | IEEE754_CUN);
+			     IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 0);
 }
 
 static __inline int ieee754sp_lt(ieee754sp x, ieee754sp y)
 {
-	return ieee754sp_cmp(x, y, IEEE754_CLT);
+	return ieee754sp_cmp(x, y, IEEE754_CLT, 0);
 }
 
 static __inline int ieee754sp_le(ieee754sp x, ieee754sp y)
 {
-	return ieee754sp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ);
+	return ieee754sp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ, 0);
 }
 
 static __inline int ieee754sp_gt(ieee754sp x, ieee754sp y)
 {
-	return ieee754sp_cmp(x, y, IEEE754_CGT);
+	return ieee754sp_cmp(x, y, IEEE754_CGT, 0);
 }
 
 
 static __inline int ieee754sp_ge(ieee754sp x, ieee754sp y)
 {
-	return ieee754sp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ);
+	return ieee754sp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ, 0);
 }
 
 static __inline int ieee754dp_eq(ieee754dp x, ieee754dp y)
 {
-	return ieee754dp_cmp(x, y, IEEE754_CEQ);
+	return ieee754dp_cmp(x, y, IEEE754_CEQ, 0);
 }
 
 static __inline int ieee754dp_ne(ieee754dp x, ieee754dp y)
 {
 	return ieee754dp_cmp(x, y,
-			     IEEE754_CLT | IEEE754_CGT | IEEE754_CUN);
+			     IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 0);
 }
 
 static __inline int ieee754dp_lt(ieee754dp x, ieee754dp y)
 {
-	return ieee754dp_cmp(x, y, IEEE754_CLT);
+	return ieee754dp_cmp(x, y, IEEE754_CLT, 0);
 }
 
 static __inline int ieee754dp_le(ieee754dp x, ieee754dp y)
 {
-	return ieee754dp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ);
+	return ieee754dp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ, 0);
 }
 
 static __inline int ieee754dp_gt(ieee754dp x, ieee754dp y)
 {
-	return ieee754dp_cmp(x, y, IEEE754_CGT);
+	return ieee754dp_cmp(x, y, IEEE754_CGT, 0);
 }
 
 static __inline int ieee754dp_ge(ieee754dp x, ieee754dp y)
 {
-	return ieee754dp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ);
+	return ieee754dp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ, 0);
 }
 
 
@@ -321,7 +321,7 @@
 char *ieee754dp_tstr(ieee754dp x, int prec, int fmt, int af);
 
 
-/* the control status register 
+/* the control status register
 */
 struct ieee754_csr {
 	unsigned pad:13;
@@ -350,7 +350,7 @@
 	return (ieee754_csr.cx);
 }
 
-/* test for current exception condition 
+/* test for current exception condition
  */
 static __inline int ieee754_cxtest(unsigned n)
 {
@@ -372,7 +372,7 @@
 	return (ieee754_csr.sx = 0);
 }
 
-/* test for sticky exception condition 
+/* test for sticky exception condition
  */
 static __inline int ieee754_sxtest(unsigned n)
 {
@@ -450,13 +450,13 @@
 #define ieee754sp_1e63() \
   (ieee754sp_spcvals[IEEE754_SPCVAL_P1E63])
 
-/* indefinite integer value 
+/* indefinite integer value
 */
 #define ieee754si_indef()	INT_MAX
 #ifdef LONG_LONG_MAX
 #define ieee754di_indef()	LONG_LONG_MAX
 #else
-#define ieee754di_indef()	((long long)(~0ULL>>1))
+#define ieee754di_indef()	((s64)(~0ULL>>1))
 #endif
 
 /* IEEE exception context, passed to handler */
@@ -470,7 +470,7 @@
 		ieee754xp xp;	/* extended precision */
 #endif
 		int si;		/* standard signed integer (32bits) */
-		long long di;	/* extended signed integer (64bits) */
+		s64 di;		/* extended signed integer (64bits) */
 	} rv;			/* default result format implied by op */
 	va_list ap;
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/ieee754d.c linux-2.4.20/arch/mips/math-emu/ieee754d.c
--- linux-2.4.19/arch/mips/math-emu/ieee754d.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/ieee754d.c	2002-10-29 11:18:49.000000000 +0000
@@ -20,7 +20,7 @@
  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  *
  *  Nov 7, 2000
- *  Modified to build and operate in Linux kernel environment. 
+ *  Modified to build and operate in Linux kernel environment.
  *
  *  Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
  *  Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
@@ -39,12 +39,12 @@
 #define SP_EMAX		127
 #define SP_FBITS	23
 
-#define DP_MBIT(x)	((unsigned long long)1 << (x))
+#define DP_MBIT(x)	((u64)1 << (x))
 #define DP_HIDDEN_BIT	DP_MBIT(DP_FBITS)
 #define DP_SIGN_BIT	DP_MBIT(63)
 
 
-#define SP_MBIT(x)	((unsigned long)1 << (x))
+#define SP_MBIT(x)	((u32)1 << (x))
 #define SP_HIDDEN_BIT	SP_MBIT(SP_FBITS)
 #define SP_SIGN_BIT	SP_MBIT(31)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/ieee754dp.c linux-2.4.20/arch/mips/math-emu/ieee754dp.c
--- linux-2.4.19/arch/mips/math-emu/ieee754dp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/ieee754dp.c	2002-10-29 11:18:49.000000000 +0000
@@ -98,9 +98,9 @@
 }
 
 
-static unsigned long long get_rounding(int sn, unsigned long long xm)
+static u64 get_rounding(int sn, u64 xm)
 {
-	/* inexact must round of 3 bits 
+	/* inexact must round of 3 bits
 	 */
 	if (xm & (DP_MBIT(3) - 1)) {
 		switch (ieee754_csr.rm) {
@@ -129,7 +129,7 @@
  * xe is an unbiased exponent
  * xm is 3bit extended precision value.
  */
-ieee754dp ieee754dp_format(int sn, int xe, unsigned long long xm)
+ieee754dp ieee754dp_format(int sn, int xe, u64 xm)
 {
 	assert(xm);		/* we dont gen exact zeros (probably should) */
 
@@ -174,7 +174,7 @@
 			xe++;
 		}
 		else {
-			/* sticky right shift es bits 
+			/* sticky right shift es bits
 			 */
 			xm = XDPSRS(xm, es);
 			xe += es;
@@ -188,10 +188,10 @@
 			SETCX(IEEE754_UNDERFLOW);
 		}
 
-		/* inexact must round of 3 bits 
+		/* inexact must round of 3 bits
 		 */
 		xm = get_rounding(sn, xm);
-		/* adjust exponent for rounding add overflowing 
+		/* adjust exponent for rounding add overflowing
 		 */
 		if (xm >> (DP_MBITS + 3 + 1)) {
 			/* add causes mantissa overflow */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/ieee754dp.h linux-2.4.20/arch/mips/math-emu/ieee754dp.h
--- linux-2.4.19/arch/mips/math-emu/ieee754dp.h	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/ieee754dp.h	2002-10-29 11:18:32.000000000 +0000
@@ -1,4 +1,4 @@
-/* 
+/*
  * IEEE754 floating point
  * double precision internal header file
  */
@@ -46,7 +46,7 @@
 #define DPDNORMX	DPDNORMx(xm,xe)
 #define DPDNORMY	DPDNORMx(ym,ye)
 
-static __inline ieee754dp builddp(int s, int bx, unsigned long long m)
+static __inline ieee754dp builddp(int s, int bx, u64 m)
 {
 	ieee754dp r;
 
@@ -64,11 +64,11 @@
 extern int ieee754dp_isnan(ieee754dp);
 extern int ieee754dp_issnan(ieee754dp);
 extern int ieee754si_xcpt(int, const char *, ...);
-extern long long ieee754di_xcpt(long long, const char *, ...);
+extern s64 ieee754di_xcpt(s64, const char *, ...);
 extern ieee754dp ieee754dp_xcpt(ieee754dp, const char *, ...);
 extern ieee754dp ieee754dp_nanxcpt(ieee754dp, const char *, ...);
 extern ieee754dp ieee754dp_bestnan(ieee754dp, ieee754dp);
-extern ieee754dp ieee754dp_format(int, int, unsigned long long);
+extern ieee754dp ieee754dp_format(int, int, u64);
 
 
 #define DPNORMRET2(s,e,m,name,a0,a1) \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/ieee754int.h linux-2.4.20/arch/mips/math-emu/ieee754int.h
--- linux-2.4.19/arch/mips/math-emu/ieee754int.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/ieee754int.h	2002-10-29 11:18:48.000000000 +0000
@@ -1,4 +1,4 @@
-/* 
+/*
  * IEEE754 floating point
  * common internal header file
  */
@@ -38,11 +38,11 @@
 #define SP_EMAX		127
 #define SP_MBITS	23
 
-#define DP_MBIT(x)	((unsigned long long)1 << (x))
+#define DP_MBIT(x)	((u64)1 << (x))
 #define DP_HIDDEN_BIT	DP_MBIT(DP_MBITS)
 #define DP_SIGN_BIT	DP_MBIT(63)
 
-#define SP_MBIT(x)	((unsigned long)1 << (x))
+#define SP_MBIT(x)	((u32)1 << (x))
 #define SP_HIDDEN_BIT	SP_MBIT(SP_MBITS)
 #define SP_SIGN_BIT	SP_MBIT(31)
 
@@ -102,10 +102,10 @@
 
 
 #define COMPXDP \
-unsigned long long xm; int xe; int xs; int xc
+u64 xm; int xe; int xs; int xc
 
 #define COMPYDP \
-unsigned long long ym; int ye; int ys; int yc
+u64 ym; int ye; int ys; int yc
 
 #define EXPLODEDP(v,vc,vs,ve,vm) \
 {\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/ieee754sp.c linux-2.4.20/arch/mips/math-emu/ieee754sp.c
--- linux-2.4.19/arch/mips/math-emu/ieee754sp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/ieee754sp.c	2002-10-29 11:18:36.000000000 +0000
@@ -101,7 +101,7 @@
 
 static unsigned get_rounding(int sn, unsigned xm)
 {
-	/* inexact must round of 3 bits 
+	/* inexact must round of 3 bits
 	 */
 	if (xm & (SP_MBIT(3) - 1)) {
 		switch (ieee754_csr.rm) {
@@ -175,7 +175,7 @@
 			xe++;
 		}
 		else {
-			/* sticky right shift es bits 
+			/* sticky right shift es bits
 			 */
 			SPXSRSXn(es);
 			assert((xm & (SP_HIDDEN_BIT << 3)) == 0);
@@ -188,10 +188,10 @@
 			SETCX(IEEE754_UNDERFLOW);
 		}
 
-		/* inexact must round of 3 bits 
+		/* inexact must round of 3 bits
 		 */
 		xm = get_rounding(sn, xm);
-		/* adjust exponent for rounding add overflowing 
+		/* adjust exponent for rounding add overflowing
 		 */
 		if (xm >> (SP_MBITS + 1 + 3)) {
 			/* add causes mantissa overflow */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/ieee754sp.h linux-2.4.20/arch/mips/math-emu/ieee754sp.h
--- linux-2.4.19/arch/mips/math-emu/ieee754sp.h	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/ieee754sp.h	2002-10-29 11:18:31.000000000 +0000
@@ -1,4 +1,4 @@
-/* 
+/*
  * IEEE754 floating point
  * double precision internal header file
  */
@@ -70,7 +70,7 @@
 extern int ieee754sp_isnan(ieee754sp);
 extern int ieee754sp_issnan(ieee754sp);
 extern int ieee754si_xcpt(int, const char *, ...);
-extern long long ieee754di_xcpt(long long, const char *, ...);
+extern s64 ieee754di_xcpt(s64, const char *, ...);
 extern ieee754sp ieee754sp_xcpt(ieee754sp, const char *, ...);
 extern ieee754sp ieee754sp_nanxcpt(ieee754sp, const char *, ...);
 extern ieee754sp ieee754sp_bestnan(ieee754sp, ieee754sp);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/ieee754xcpt.c linux-2.4.20/arch/mips/math-emu/ieee754xcpt.c
--- linux-2.4.19/arch/mips/math-emu/ieee754xcpt.c	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/ieee754xcpt.c	2002-10-29 11:18:33.000000000 +0000
@@ -23,7 +23,7 @@
 
 /**************************************************************************
  *  Nov 7, 2000
- *  Added preprocessor hacks to map to Linux kernel diagnostics. 
+ *  Added preprocessor hacks to map to Linux kernel diagnostics.
  *
  *  Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
  *  Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/kernel_linkage.c linux-2.4.20/arch/mips/math-emu/kernel_linkage.c
--- linux-2.4.19/arch/mips/math-emu/kernel_linkage.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/kernel_linkage.c	2002-10-29 11:18:32.000000000 +0000
@@ -39,7 +39,7 @@
 {
 	static int first = 1;
 	int i;
- 
+
 	if (first) {
 		first = 0;
 		printk("Algorithmics/MIPS FPU Emulator v1.5\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/sp_add.c linux-2.4.20/arch/mips/math-emu/sp_add.c
--- linux-2.4.19/arch/mips/math-emu/sp_add.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/sp_add.c	2002-10-29 11:18:35.000000000 +0000
@@ -69,7 +69,7 @@
 		return x;
 
 
-		/* Inifity handeling 
+		/* Inifity handeling
 		 */
 
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
@@ -88,7 +88,7 @@
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
 		return x;
 
-		/* Zero handeling 
+		/* Zero handeling
 		 */
 
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/sp_cmp.c linux-2.4.20/arch/mips/math-emu/sp_cmp.c
--- linux-2.4.19/arch/mips/math-emu/sp_cmp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/sp_cmp.c	2002-10-29 11:18:31.000000000 +0000
@@ -27,7 +27,7 @@
 
 #include "ieee754sp.h"
 
-int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp)
+int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp, int sig)
 {
 	COMPXSP;
 	COMPYSP;
@@ -39,12 +39,12 @@
 	CLEARCX;	/* Even clear inexact flag here */
 
 	if (ieee754sp_isnan(x) || ieee754sp_isnan(y)) {
-		if (xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN)
+		if (sig || xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN)
 			SETCX(IEEE754_INVALID_OPERATION);
 		if (cmp & IEEE754_CUN)
 			return 1;
 		if (cmp & (IEEE754_CLT | IEEE754_CGT)) {
-			if (SETCX(IEEE754_INVALID_OPERATION))
+			if (sig && SETCX(IEEE754_INVALID_OPERATION))
 				return ieee754si_xcpt(0, "fcmpf", x);
 		}
 		return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/sp_div.c linux-2.4.20/arch/mips/math-emu/sp_div.c
--- linux-2.4.19/arch/mips/math-emu/sp_div.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/sp_div.c	2002-10-29 11:18:49.000000000 +0000
@@ -69,7 +69,7 @@
 		return x;
 
 
-		/* Infinity handeling 
+		/* Infinity handeling
 		 */
 
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
@@ -86,7 +86,7 @@
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
 		return ieee754sp_inf(xs ^ ys);
 
-		/* Zero handeling 
+		/* Zero handeling
 		 */
 
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/sp_fdp.c linux-2.4.20/arch/mips/math-emu/sp_fdp.c
--- linux-2.4.19/arch/mips/math-emu/sp_fdp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/sp_fdp.c	2002-10-29 11:18:40.000000000 +0000
@@ -43,7 +43,7 @@
 		SETCX(IEEE754_INVALID_OPERATION);
 		return ieee754sp_nanxcpt(ieee754sp_indef(), "fdp");
 	case IEEE754_CLASS_QNAN:
-		nan = buildsp(xs, SP_EMAX + 1 + SP_EBIAS, (unsigned long)
+		nan = buildsp(xs, SP_EMAX + 1 + SP_EBIAS, (u32)
 				(xm >> (DP_MBITS - SP_MBITS)));
 		if (!ieee754sp_isnan(nan))
 			nan = ieee754sp_indef();
@@ -57,7 +57,7 @@
 		SETCX(IEEE754_UNDERFLOW);
 		SETCX(IEEE754_INEXACT);
 		if ((ieee754_csr.rm == IEEE754_RU && !xs) ||
-		    (ieee754_csr.rm == IEEE754_RD && xs))
+				(ieee754_csr.rm == IEEE754_RD && xs))
 			return ieee754sp_xcpt(ieee754sp_mind(xs), "fdp", x);
 		return ieee754sp_xcpt(ieee754sp_zero(xs), "fdp", x);
 	case IEEE754_CLASS_NORM:
@@ -65,9 +65,9 @@
 	}
 
 	{
-		unsigned long rm;
+		u32 rm;
 
-		/* convert from DP_MBITS to SP_MBITS+3 with sticky right shift 
+		/* convert from DP_MBITS to SP_MBITS+3 with sticky right shift
 		 */
 		rm = (xm >> (DP_MBITS - (SP_MBITS + 3))) |
 		    ((xm << (64 - (DP_MBITS - (SP_MBITS + 3)))) != 0);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/sp_fint.c linux-2.4.20/arch/mips/math-emu/sp_fint.c
--- linux-2.4.19/arch/mips/math-emu/sp_fint.c	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/sp_fint.c	2002-10-29 11:18:36.000000000 +0000
@@ -52,13 +52,13 @@
 	xe = SP_MBITS + 3;
 
 	if (xm >> (SP_MBITS + 1 + 3)) {
-		/* shunt out overflow bits 
+		/* shunt out overflow bits
 		 */
 		while (xm >> (SP_MBITS + 1 + 3)) {
 			SPXSRSX1();
 		}
 	} else {
-		/* normalize in grs extended single precision 
+		/* normalize in grs extended single precision
 		 */
 		while ((xm >> (SP_MBITS + 3)) == 0) {
 			xm <<= 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/sp_flong.c linux-2.4.20/arch/mips/math-emu/sp_flong.c
--- linux-2.4.19/arch/mips/math-emu/sp_flong.c	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/sp_flong.c	2002-10-29 11:18:35.000000000 +0000
@@ -27,7 +27,7 @@
 
 #include "ieee754sp.h"
 
-ieee754sp ieee754sp_flong(long long x)
+ieee754sp ieee754sp_flong(s64 x)
 {
 	COMPXDP;		/* <--- need 64-bit mantissa temp */
 
@@ -52,7 +52,7 @@
 	xe = SP_MBITS + 3;
 
 	if (xm >> (SP_MBITS + 1 + 3)) {
-		/* shunt out overflow bits 
+		/* shunt out overflow bits
 		 */
 		while (xm >> (SP_MBITS + 1 + 3)) {
 			SPXSRSX1();
@@ -68,9 +68,9 @@
 }
 
 
-ieee754sp ieee754sp_fulong(unsigned long long u)
+ieee754sp ieee754sp_fulong(u64 u)
 {
-	if ((long long) u < 0)
+	if ((s64) u < 0)
 		return ieee754sp_add(ieee754sp_1e63(),
 				     ieee754sp_flong(u & ~(1ULL << 63)));
 	return ieee754sp_flong(u);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/sp_frexp.c linux-2.4.20/arch/mips/math-emu/sp_frexp.c
--- linux-2.4.19/arch/mips/math-emu/sp_frexp.c	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/sp_frexp.c	2002-10-29 11:18:30.000000000 +0000
@@ -27,7 +27,7 @@
 
 #include "ieee754sp.h"
 
-/* close to ieeep754sp_logb 
+/* close to ieeep754sp_logb
 */
 ieee754sp ieee754sp_frexp(ieee754sp x, int *eptr)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/sp_modf.c linux-2.4.20/arch/mips/math-emu/sp_modf.c
--- linux-2.4.19/arch/mips/math-emu/sp_modf.c	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/sp_modf.c	2002-10-29 11:18:39.000000000 +0000
@@ -59,7 +59,7 @@
 		*ip = x;
 		return ieee754sp_zero(xs);
 	}
-	/* generate ipart mantissa by clearing bottom bits 
+	/* generate ipart mantissa by clearing bottom bits
 	 */
 	*ip = buildsp(xs, xe + SP_EBIAS,
 		      ((xm >> (SP_MBITS - xe)) << (SP_MBITS - xe)) &
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/sp_sub.c linux-2.4.20/arch/mips/math-emu/sp_sub.c
--- linux-2.4.19/arch/mips/math-emu/sp_sub.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/sp_sub.c	2002-10-29 11:18:37.000000000 +0000
@@ -69,7 +69,7 @@
 		return x;
 
 
-		/* Inifity handeling 
+		/* Inifity handeling
 		 */
 
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
@@ -88,7 +88,7 @@
 	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
 		return x;
 
-		/* Zero handeling 
+		/* Zero handeling
 		 */
 
 	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
@@ -173,7 +173,7 @@
 			else
 				return ieee754sp_zero(0);	/* other round modes   => sign = 1 */
 
-		/* normalize to rounding precision 
+		/* normalize to rounding precision
 		 */
 		while ((xm >> (SP_MBITS + 3)) == 0) {
 			xm <<= 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/sp_tint.c linux-2.4.20/arch/mips/math-emu/sp_tint.c
--- linux-2.4.19/arch/mips/math-emu/sp_tint.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/sp_tint.c	2002-10-29 11:18:40.000000000 +0000
@@ -52,7 +52,7 @@
 	if (xe >= 31) {
 		/* look for valid corner case */
 		if (xe == 31 && xs && xm == SP_HIDDEN_BIT)
-			return -2147483648;
+			return -0x80000000;
 		/* Set invalid. We will only use overflow for floating
 		   point overflow */
 		SETCX(IEEE754_INVALID_OPERATION);
@@ -62,7 +62,7 @@
 	if (xe > SP_MBITS) {
 		xm <<= xe - SP_MBITS;
 	} else {
-		unsigned long residue;
+		u32 residue;
 		int round;
 		int sticky;
 		int odd;
@@ -74,7 +74,11 @@
 			xm = 0;
 		}
 		else {
-			residue = xm << (32 - SP_MBITS + xe);
+			/* Shifting a u32 32 times does not work,
+			* so we do it in two steps. Be aware that xe
+			* may be -1 */
+			residue = xm << (xe + 1);
+			residue <<= 31 - SP_MBITS;
 			round = (residue >> 31) != 0;
 			sticky = (residue << 1) != 0;
 			xm >>= SP_MBITS - xe;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/math-emu/sp_tlong.c linux-2.4.20/arch/mips/math-emu/sp_tlong.c
--- linux-2.4.19/arch/mips/math-emu/sp_tlong.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/math-emu/sp_tlong.c	2002-10-29 11:18:40.000000000 +0000
@@ -27,7 +27,7 @@
 
 #include "ieee754sp.h"
 
-long long ieee754sp_tlong(ieee754sp x)
+s64 ieee754sp_tlong(ieee754sp x)
 {
 	COMPXDP;		/* <-- need 64-bit mantissa tmp */
 
@@ -51,7 +51,7 @@
 	if (xe >= 63) {
 		/* look for valid corner case */
 		if (xe == 63 && xs && xm == SP_HIDDEN_BIT)
-			return -9223372036854775808LL;
+			return -0x8000000000000000LL;
 		/* Set invalid. We will only use overflow for floating
 		   point overflow */
 		SETCX(IEEE754_INVALID_OPERATION);
@@ -61,7 +61,7 @@
 	if (xe > SP_MBITS) {
 		xm <<= xe - SP_MBITS;
 	} else if (xe < SP_MBITS) {
-		unsigned long residue;
+		u32 residue;
 		int round;
 		int sticky;
 		int odd;
@@ -98,7 +98,7 @@
 		if ((xm >> 63) != 0) {
 			/* This can happen after rounding */
 			SETCX(IEEE754_INVALID_OPERATION);
-			return ieee754si_xcpt(ieee754di_indef(), "sp_tlong", x);
+			return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x);
 		}
 		if (round || sticky)
 			SETCX(IEEE754_INEXACT);
@@ -110,14 +110,14 @@
 }
 
 
-unsigned long long ieee754sp_tulong(ieee754sp x)
+u64 ieee754sp_tulong(ieee754sp x)
 {
 	ieee754sp hb = ieee754sp_1e63();
 
 	/* what if x < 0 ?? */
 	if (ieee754sp_lt(x, hb))
-		return (unsigned long long) ieee754sp_tlong(x);
+		return (u64) ieee754sp_tlong(x);
 
-	return (unsigned long long) ieee754sp_tlong(ieee754sp_sub(x, hb)) |
+	return (u64) ieee754sp_tlong(ieee754sp_sub(x, hb)) |
 	    (1ULL << 63);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/atlas/Makefile linux-2.4.20/arch/mips/mips-boards/atlas/Makefile
--- linux-2.4.19/arch/mips/mips-boards/atlas/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/atlas/Makefile	2002-10-29 11:18:50.000000000 +0000
@@ -7,12 +7,12 @@
 # This program is free software; you can distribute it and/or modify it
 # under the terms of the GNU General Public License (Version 2) as
 # published by the Free Software Foundation.
-# 
+#
 # This program is distributed in the hope 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.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/atlas/atlas_int.c linux-2.4.20/arch/mips/mips-boards/atlas/atlas_int.c
--- linux-2.4.19/arch/mips/mips-boards/atlas/atlas_int.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/atlas/atlas_int.c	2002-10-29 11:18:49.000000000 +0000
@@ -19,7 +19,7 @@
  *
  * ########################################################################
  *
- * Routines for generic manipulation of the interrupts found on the MIPS 
+ * Routines for generic manipulation of the interrupts found on the MIPS
  * Atlas board.
  *
  */
@@ -104,7 +104,7 @@
 	unsigned long int_status;
 	int irq, cpu = smp_processor_id();
 
-	int_status = atlas_hw0_icregs->intstatus; 
+	int_status = atlas_hw0_icregs->intstatus;
 
 	/* if int_status == 0, then the interrupt has already been cleared */
 	if (int_status == 0)
@@ -127,7 +127,7 @@
 	action->handler(irq, action->dev_id, regs);
 	irq_exit(cpu, irq);
 
-	return;		
+	return;
 }
 
 #ifdef CONFIG_REMOTE_DEBUG
@@ -139,11 +139,11 @@
 {
 	int i;
 
-	/* 
-	 * Mask out all interrupt by writing "1" to all bit position in 
-	 * the interrupt reset reg. 
+	/*
+	 * Mask out all interrupt by writing "1" to all bit position in
+	 * the interrupt reset reg.
 	 */
-	atlas_hw0_icregs->intrsten = 0xffffffff;    
+	atlas_hw0_icregs->intrsten = 0xffffffff;
 
 	/* Now safe to set the exception vector. */
 	set_except_vector(0, mipsIRQ);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/atlas/atlas_setup.c linux-2.4.20/arch/mips/mips-boards/atlas/atlas_setup.c
--- linux-2.4.19/arch/mips/mips-boards/atlas/atlas_setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/atlas/atlas_setup.c	2002-10-29 11:18:31.000000000 +0000
@@ -59,6 +59,8 @@
 }
 
 extern void mips_time_init(void);
+extern void mips_timer_setup(struct irqaction *irq);
+extern unsigned long mips_rtc_get_time(void);
 
 void __init atlas_setup(void)
 {
@@ -86,7 +88,7 @@
 		prom_printf("Config serial console: %s\n", serial_console);
 		console_setup(serial_console, NULL);
 	}
-#endif	  
+#endif
 
 #ifdef CONFIG_REMOTE_DEBUG
 	argptr = prom_getcmdline();
@@ -124,6 +126,8 @@
 
 	rtc_ops = &atlas_rtc_ops;
 	board_time_init = mips_time_init;
+	board_timer_setup = mips_timer_setup;
+	rtc_get_time = mips_rtc_get_time;
 
 	mips_reboot_setup();
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/generic/Makefile linux-2.4.20/arch/mips/mips-boards/generic/Makefile
--- linux-2.4.19/arch/mips/mips-boards/generic/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/generic/Makefile	2002-10-29 11:18:49.000000000 +0000
@@ -5,12 +5,12 @@
 # This program is free software; you can distribute it and/or modify it
 # under the terms of the GNU General Public License (Version 2) as
 # published by the Free Software Foundation.
-# 
+#
 # This program is distributed in the hope 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.
@@ -28,7 +28,9 @@
 O_TARGET := mipsboards.o
 
 obj-y				:= mipsIRQ.o reset.o display.o init.o \
-				   memory.o printf.o cmdline.o time.o
+				   memory.o printf.o cmdline.o
+obj-$(CONFIG_MIPS_ATLAS)	+= time.o
+obj-$(CONFIG_MIPS_MALTA)	+= time.o
 obj-$(CONFIG_PCI)		+= pci.o
 obj-$(CONFIG_REMOTE_DEBUG)	+= gdb_hook.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/generic/display.c linux-2.4.20/arch/mips/mips-boards/generic/display.c
--- linux-2.4.19/arch/mips/mips-boards/generic/display.c	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/generic/display.c	2002-10-29 11:18:49.000000000 +0000
@@ -18,7 +18,7 @@
  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  *
  * ########################################################################
- * 
+ *
  * Display routines for display messages in MIPS boards ascii display.
  *
  */
@@ -39,9 +39,11 @@
 	}
 }
 
+#ifndef CONFIG_MIPS_SEAD
 void mips_display_word(unsigned int num)
 {
         volatile unsigned int *display = (void *)ASCII_DISPLAY_WORD_BASE;
-	
+
 	*display = num;
 }
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/generic/gdb_hook.c linux-2.4.20/arch/mips/mips-boards/generic/gdb_hook.c
--- linux-2.4.19/arch/mips/mips-boards/generic/gdb_hook.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/generic/gdb_hook.c	2002-10-29 11:18:38.000000000 +0000
@@ -67,28 +67,28 @@
 	serial_in(&kdb_port_info, UART_MSR);
 
 	/*
-	 * Now, initialize the UART 
+	 * Now, initialize the UART
 	 */
 	serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
 	if (kdb_port_info.flags & ASYNC_FOURPORT) {
 		kdb_port_info.MCR = UART_MCR_DTR | UART_MCR_RTS;
 		t = UART_MCR_DTR | UART_MCR_OUT1;
 	} else {
-		kdb_port_info.MCR 
+		kdb_port_info.MCR
 			= UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
 		t = UART_MCR_DTR | UART_MCR_RTS;
 	}
 
 	kdb_port_info.MCR = t;		/* no interrupts, please */
 	serial_out(&kdb_port_info, UART_MCR, kdb_port_info.MCR);
-	
+
 	/*
 	 * and set the speed of the serial port
 	 * (currently hardwired to 9600 8N1
 	 */
 
 	/* baud rate is fixed to 9600 (is this sufficient?)*/
-	t = kdb_port_info.state->baud_base / 9600;	
+	t = kdb_port_info.state->baud_base / 9600;
 	/* set DLAB */
 	serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
 	serial_out(&kdb_port_info, UART_DLL, t & 0xff);/* LS of divisor */
@@ -102,7 +102,7 @@
 	return generic_putDebugChar(c);
 }
 
-char getDebugChar(void) 
+char getDebugChar(void)
 {
 	return generic_getDebugChar();
 }
@@ -156,7 +156,7 @@
 
 static int saa9730_kgdb_active = 0;
 
-void saa9730_kgdb_hook(void) 
+void saa9730_kgdb_hook(void)
 {
         volatile unsigned char t;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/generic/init.c linux-2.4.20/arch/mips/mips-boards/generic/init.c
--- linux-2.4.19/arch/mips/mips-boards/generic/init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/generic/init.c	2002-10-29 11:18:32.000000000 +0000
@@ -54,8 +54,8 @@
 {
 	/*
 	 * Return a pointer to the given environment variable.
-	 * In 64-bit mode: we're using 64-bit pointers, but all pointers 
-	 * in the PROM structures are only 32-bit, so we need some 
+	 * In 64-bit mode: we're using 64-bit pointers, but all pointers
+	 * in the PROM structures are only 32-bit, so we need some
 	 * workarounds, if we are running in 64-bit mode.
 	 */
 	int i, index=0;
@@ -95,7 +95,7 @@
 		ea[i] = num;
 	}
 }
- 
+
 int get_ethernet_addr(char *ethernet_addr)
 {
         char *ethaddr_str;
@@ -135,7 +135,7 @@
 	case MIPS_REVISION_CORID_CORE_LV:
 	case MIPS_REVISION_CORID_CORE_FPGA:
 		/*
-		 * Setup the North bridge to do Master byte-lane swapping 
+		 * Setup the North bridge to do Master byte-lane swapping
 		 * when running in bigendian.
 		 */
 #if defined(__MIPSEL__)
@@ -149,15 +149,15 @@
 		set_io_port_base(MALTA_GT_PORT_BASE);
 #else
 		set_io_port_base(KSEG1);
-#endif		
+#endif
 
 		break;
 	case MIPS_REVISION_CORID_BONITO64:
 	case MIPS_REVISION_CORID_CORE_20K:
-		/* 
+		/*
 		 * Disable Bonito IOBC.
 		 */
-		BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG & 
+		BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG &
 			~(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
 			  BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
 
@@ -166,12 +166,12 @@
 		 * when running in bigendian.
 		 */
 #if defined(__MIPSEL__)
-		BONITO_BONGENCFG = BONITO_BONGENCFG & 
-			~(BONITO_BONGENCFG_MSTRBYTESWAP | 
+		BONITO_BONGENCFG = BONITO_BONGENCFG &
+			~(BONITO_BONGENCFG_MSTRBYTESWAP |
 			  BONITO_BONGENCFG_BYTESWAP);
 #else
-		BONITO_BONGENCFG = BONITO_BONGENCFG | 
-			BONITO_BONGENCFG_MSTRBYTESWAP | 
+		BONITO_BONGENCFG = BONITO_BONGENCFG |
+			BONITO_BONGENCFG_MSTRBYTESWAP |
 			BONITO_BONGENCFG_BYTESWAP;
 #endif
 
@@ -187,7 +187,7 @@
 #if defined(__MIPSEL__)
 		MSC_WRITE(MSC01_PCI_SWAP, MSC01_PCI_SWAP_NOSWAP);
 #else
-		MSC_WRITE(MSC01_PCI_SWAP, 
+		MSC_WRITE(MSC01_PCI_SWAP,
 			  MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_IO_SHF |
 			  MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_MEM_SHF |
 			  MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_BAR0_SHF);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/generic/memory.c linux-2.4.20/arch/mips/mips-boards/generic/memory.c
--- linux-2.4.19/arch/mips/mips-boards/generic/memory.c	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/generic/memory.c	2002-10-29 11:18:33.000000000 +0000
@@ -19,9 +19,9 @@
  *
  * ########################################################################
  *
- * PROM library functions for acquiring/using memory descriptors given to 
+ * PROM library functions for acquiring/using memory descriptors given to
  * us from the YAMON.
- * 
+ *
  */
 #include <linux/config.h>
 #include <linux/init.h>
@@ -83,11 +83,11 @@
 	mdesc[1].size = 0x000ef000;
 
 #if (CONFIG_MIPS_MALTA)
-	/* 
+	/*
 	 * The area 0x000f0000-0x000fffff is allocated for BIOS memory by the
-	 * south bridge and PCI access always forwarded to the ISA Bus and 
+	 * south bridge and PCI access always forwarded to the ISA Bus and
 	 * BIOSCS# is always generated.
-	 * This mean that this area can't be used as DMA memory for PCI 
+	 * This mean that this area can't be used as DMA memory for PCI
 	 * devices.
 	 */
 	mdesc[2].type = yamon_dontuse;
@@ -148,7 +148,7 @@
 		size = p->size;
 
 		add_memory_region(base, size, type);
-                p++; 
+                p++;
 	}
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/generic/mipsIRQ.S linux-2.4.20/arch/mips/mips-boards/generic/mipsIRQ.S
--- linux-2.4.19/arch/mips/mips-boards/generic/mipsIRQ.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/generic/mipsIRQ.S	2002-10-29 11:18:36.000000000 +0000
@@ -59,7 +59,7 @@
  * Note: On the SEAD board thing are a little bit different.
  *       Here IRQ 2 (hw0) is wired to the UART0 and IRQ 3 (hw1) is wired
  *       wired to UART1.
- *	
+ *
  * We handle the IRQ according to _our_ priority which is:
  *
  * Highest ----     R4k Timer
@@ -78,7 +78,9 @@
 	CLI
 	.set	at
 
-	mfc0	s0, CP0_CAUSE		# get irq mask
+	mfc0	s0, CP0_CAUSE		# get irq bits
+	mfc0	s1, CP0_STATUS		# get irq mask
+	and	s0, s1
 
 	/* First we check for r4k counter/timer IRQ. */
 	andi	a0, s0, CAUSEF_IP7
@@ -94,14 +96,14 @@
 	 nop
 
 1:
-#if defined(CONFIG_MIPS_SEAD) 	
+#if defined(CONFIG_MIPS_SEAD)
 	beq	a0, zero, 1f
 	 andi	a0, s0, CAUSEF_IP3	# delay slot, check hw1 interrupt
 #else
 	beq	a0, zero, 1f		# delay slot, check hw3 interrupt
- 	 andi	a0, s0, CAUSEF_IP5	
+ 	 andi	a0, s0, CAUSEF_IP5
 #endif
-	
+
 	/* Wheee, combined hardware level zero interrupt. */
 #if defined(CONFIG_MIPS_ATLAS)
 	jal	atlas_hw0_irqdispatch
@@ -110,7 +112,7 @@
 #elif defined(CONFIG_MIPS_SEAD)
 	jal	sead_hw0_irqdispatch
 #else
-#error "MIPS board not supported\n"	
+#error "MIPS board not supported\n"
 #endif
 	 move	a0, sp			# delay slot
 
@@ -118,24 +120,24 @@
 	 nop				# delay slot
 
 1:
-#if defined(CONFIG_MIPS_SEAD) 	
+#if defined(CONFIG_MIPS_SEAD)
 	beq	a0, zero, 1f
 	 andi	a0, s0, CAUSEF_IP5	# delay slot, check hw3 interrupt
 	jal	sead_hw1_irqdispatch
-	 move	a0, sp			# delay slot	
+	 move	a0, sp			# delay slot
 	j	ret_from_irq
 	 nop				# delay slot
-1:	
-#endif	
-
+1:
+#endif
+#if defined(CONFIG_MIPS_MALTA)
 	beq	a0, zero, 1f            # check hw3 (coreHI) interrupt
 	 nop
 	jal	corehi_irqdispatch
-	 move	a0, sp			
+	 move	a0, sp
 	j	ret_from_irq
-	 nop				
-1:	
-
+	 nop
+1:
+#endif
 	/*
 	 * Here by mistake?  This is possible, what can happen is that by the
 	 * time we take the exception the IRQ pin goes low, so just leave if
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/generic/pci.c linux-2.4.20/arch/mips/mips-boards/generic/pci.c
--- linux-2.4.19/arch/mips/mips-boards/generic/pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/generic/pci.c	2002-10-29 11:18:38.000000000 +0000
@@ -72,12 +72,12 @@
 
 		/* Clear cause register bits */
 		GT_READ(GT_INTRCAUSE_OFS, intr);
-		GT_WRITE(GT_INTRCAUSE_OFS, intr & 
-			 ~(GT_INTRCAUSE_MASABORT0_BIT | 
+		GT_WRITE(GT_INTRCAUSE_OFS, intr &
+			 ~(GT_INTRCAUSE_MASABORT0_BIT |
 			   GT_INTRCAUSE_TARABORT0_BIT));
 
 		/* Setup address */
-		GT_WRITE(GT_PCI0_CFGADDR_OFS, 
+		GT_WRITE(GT_PCI0_CFGADDR_OFS,
 			 (bus         << GT_PCI0_CFGADDR_BUSNUM_SHF)   |
 			 (dev_fn      << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
 			 ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF)   |
@@ -85,9 +85,9 @@
 
 		if (access_type == PCI_ACCESS_WRITE) {
 			if (bus == 0 && dev_fn == 0) {
-				/* 
-				 * The Galileo system controller is acting 
-				 * differently than other devices. 
+				/*
+				 * The Galileo system controller is acting
+				 * differently than other devices.
 				 */
 				GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
 			} else {
@@ -95,9 +95,9 @@
 			}
 		} else {
 			if (bus == 0 && dev_fn == 0) {
-				/* 
-				 * The Galileo system controller is acting 
-				 * differently than other devices. 
+				/*
+				 * The Galileo system controller is acting
+				 * differently than other devices.
 				 */
 				GT_READ(GT_PCI0_CFGDATA_OFS, *data);
 			} else {
@@ -108,15 +108,15 @@
 		/* Check for master or target abort */
 		GT_READ(GT_INTRCAUSE_OFS, intr);
 
-		if (intr & (GT_INTRCAUSE_MASABORT0_BIT | 
+		if (intr & (GT_INTRCAUSE_MASABORT0_BIT |
 			    GT_INTRCAUSE_TARABORT0_BIT))
 		{
 			/* Error occured */
 
 			/* Clear bits */
 			GT_READ(GT_INTRCAUSE_OFS, intr);
-			GT_WRITE(GT_INTRCAUSE_OFS, intr & 
-				 ~(GT_INTRCAUSE_MASABORT0_BIT | 
+			GT_WRITE(GT_INTRCAUSE_OFS, intr &
+				 ~(GT_INTRCAUSE_MASABORT0_BIT |
 				   GT_INTRCAUSE_TARABORT0_BIT));
 
 			return -1;
@@ -133,12 +133,12 @@
 		}
 
 		/* Clear cause register bits */
-		BONITO_PCICMD |= (BONITO_PCICMD_MABORT_CLR | 
+		BONITO_PCICMD |= (BONITO_PCICMD_MABORT_CLR |
 				  BONITO_PCICMD_MTABORT_CLR);
 
-		/* 
-		 * Setup pattern to be used as PCI "address" for 
-		 * Type 0 cycle 
+		/*
+		 * Setup pattern to be used as PCI "address" for
+		 * Type 0 cycle
 		 */
 		if (bus == 0) {
 		        /* IDSEL */
@@ -153,10 +153,10 @@
 
 		/* Function (same for Type 0/1) */
 		pci_addr |= PCI_FUNC(dev_fn) << PCI_CFG_TYPE0_FUNC_SHF;
-		
+
 		/* Register number (same for Type 0/1) */
 		pci_addr |= (where & ~0x3) << PCI_CFG_TYPE0_REG_SHF;
-		
+
 		if (bus == 0) {
 		        /* Type 0 */
 		        BONITO_PCIMAP_CFG = pci_addr >> 16;
@@ -164,7 +164,7 @@
 		        /* Type 1 */
 		        BONITO_PCIMAP_CFG = (pci_addr >> 16) | 0x10000;
 		}
-	  
+
 		/* Flush Bonito register block */
 		dummy = BONITO_PCIMAP_CFG;
 		__asm__ __volatile__(
@@ -176,28 +176,28 @@
 
 		/* Perform access */
 		if (access_type == PCI_ACCESS_WRITE) {
-		        *(volatile u32 *)(KSEG1ADDR(BONITO_PCICFG_BASE + 
+		        *(volatile u32 *)(KSEG1ADDR(BONITO_PCICFG_BASE +
 					  (pci_addr & 0xffff))) = *(u32 *)data;
 
 			/* Wait till done */
 			while (BONITO_PCIMSTAT & 0xF)
 			        ;
 		} else {
-		        *(u32 *)data = 
-			  *(volatile u32 *)(KSEG1ADDR(BONITO_PCICFG_BASE + 
+		        *(u32 *)data =
+			  *(volatile u32 *)(KSEG1ADDR(BONITO_PCICFG_BASE +
 					    (pci_addr & 0xffff)));
 		}
 
 		/* Detect Master/Target abort */
-		if (BONITO_PCICMD & (BONITO_PCICMD_MABORT_CLR | 
+		if (BONITO_PCICMD & (BONITO_PCICMD_MABORT_CLR |
 				     BONITO_PCICMD_MTABORT_CLR) )
 		{
 		        /* Error occurred */
 
 		        /* Clear bits */
-		        BONITO_PCICMD |= (BONITO_PCICMD_MABORT_CLR | 
+		        BONITO_PCICMD |= (BONITO_PCICMD_MABORT_CLR |
 					  BONITO_PCICMD_MTABORT_CLR);
-    
+
 			return -1;
 		}
 	        break;
@@ -210,8 +210,8 @@
 		}
 
 		/* Clear status register bits. */
-		MSC_WRITE(MSC01_PCI_INTSTAT, 
-			  (MSC01_PCI_INTCFG_MA_BIT | 
+		MSC_WRITE(MSC01_PCI_INTSTAT,
+			  (MSC01_PCI_INTCFG_MA_BIT |
 			   MSC01_PCI_INTCFG_TA_BIT));
 
 		/* Setup address */
@@ -236,7 +236,7 @@
 
 		/* Detect Master/Target abort */
 		MSC_READ(MSC01_PCI_INTSTAT, intr);
-		if (intr & (MSC01_PCI_INTCFG_MA_BIT | 
+		if (intr & (MSC01_PCI_INTCFG_MA_BIT |
 			    MSC01_PCI_INTCFG_TA_BIT))
 		{
 		        /* Error occurred */
@@ -244,7 +244,7 @@
 		        /* Clear bits */
 			MSC_READ(MSC01_PCI_INTSTAT, intr);
 			MSC_WRITE(MSC01_PCI_INTSTAT,
-				  (MSC01_PCI_INTCFG_MA_BIT | 
+				  (MSC01_PCI_INTCFG_MA_BIT |
 				   MSC01_PCI_INTCFG_TA_BIT));
 
 			return -1;
@@ -300,7 +300,7 @@
 
 	if (where & 3)
 		return PCIBIOS_BAD_REGISTER_NUMBER;
-	
+
 	if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
 		return -1;
 
@@ -314,7 +314,7 @@
 mips_pcibios_write_config_byte (struct pci_dev *dev, int where, u8 val)
 {
 	u32 data = 0;
-       
+
 	if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
 		return -1;
 
@@ -334,11 +334,11 @@
 
 	if (where & 1)
 		return PCIBIOS_BAD_REGISTER_NUMBER;
-       
+
         if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
 	       return -1;
 
-	data = (data & ~(0xffff << ((where & 3) << 3))) | 
+	data = (data & ~(0xffff << ((where & 3) << 3))) |
 	       (val << ((where & 3) << 3));
 
 	if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data))
@@ -369,6 +369,55 @@
 	mips_pcibios_write_config_dword
 };
 
+int mips_pcibios_iack(void)
+{
+	int irq;
+        u32 dummy;
+
+	/*
+	 * Determine highest priority pending interrupt by performing
+	 * a PCI Interrupt Acknowledge cycle.
+	 */
+	switch(mips_revision_corid) {
+	case MIPS_REVISION_CORID_QED_RM5261:
+	case MIPS_REVISION_CORID_CORE_LV:
+	case MIPS_REVISION_CORID_CORE_FPGA:
+	case MIPS_REVISION_CORID_CORE_MSC:
+		if (mips_revision_corid == MIPS_REVISION_CORID_CORE_MSC)
+			MSC_READ(MSC01_PCI_IACK, irq);
+		else
+			GT_READ(GT_PCI0_IACK_OFS, irq);
+		irq &= 0xff;
+		break;
+	case MIPS_REVISION_CORID_BONITO64:
+	case MIPS_REVISION_CORID_CORE_20K:
+		/* The following will generate a PCI IACK cycle on the
+		 * Bonito controller. It's a little bit kludgy, but it
+		 * was the easiest way to implement it in hardware at
+		 * the given time.
+		 */
+		BONITO_PCIMAP_CFG = 0x20000;
+
+		/* Flush Bonito register block */
+		dummy = BONITO_PCIMAP_CFG;
+		__asm__ __volatile__(
+			".set\tnoreorder\n\t"
+			".set\tnoat\n\t"
+			"sync\n\t"
+			".set\tat\n\t"
+			".set\treorder");
+
+		irq = *(volatile u32 *)(KSEG1ADDR(BONITO_PCICFG_BASE));
+		irq &= 0xff;
+		BONITO_PCIMAP_CFG = 0;
+		break;
+	default:
+	        printk("Unknown Core card, don't know the system controller.\n");
+		return -1;
+	}
+	return irq;
+}
+
 void __init pcibios_init(void)
 {
 #ifdef CONFIG_MIPS_MALTA
@@ -383,11 +432,11 @@
 	case MIPS_REVISION_CORID_QED_RM5261:
 	case MIPS_REVISION_CORID_CORE_LV:
 	case MIPS_REVISION_CORID_CORE_FPGA:
-		/* 
-		 * Due to a bug in the Galileo system controller, we need 
+		/*
+		 * Due to a bug in the Galileo system controller, we need
 		 * to setup the PCI BAR for the Galileo internal registers.
-		 * This should be done in the bios/bootprom and will be 
-		 * fixed in a later revision of YAMON (the MIPS boards 
+		 * This should be done in the bios/bootprom and will be
+		 * fixed in a later revision of YAMON (the MIPS boards
 		 * boot prom).
 		 */
 		GT_WRITE(GT_PCI0_CFGADDR_OFS,
@@ -398,7 +447,7 @@
 			 GT_PCI0_CFGADDR_CONFIGEN_BIT );
 
 		/* Perform the write */
-		GT_WRITE( GT_PCI0_CFGDATA_OFS, PHYSADDR(MIPS_GT_BASE)); 
+		GT_WRITE( GT_PCI0_CFGDATA_OFS, PHYSADDR(MIPS_GT_BASE));
 		break;
 	}
 
@@ -428,15 +477,15 @@
 		}
 	}
 
-	/* 
-	 * Activate Floppy Controller in the SMSC FDC37M817 Super I/O 
+	/*
+	 * Activate Floppy Controller in the SMSC FDC37M817 Super I/O
 	 * Controller.
 	 * This should be done in the bios/bootprom and will be fixed in
          * a later revision of YAMON (the MIPS boards boot prom).
 	 */
 	/* Entering config state. */
-	SMSC_WRITE(SMSC_CONFIG_ENTER, SMSC_CONFIG_REG); 
-       
+	SMSC_WRITE(SMSC_CONFIG_ENTER, SMSC_CONFIG_REG);
+
 	/* Activate floppy controller. */
 	SMSC_WRITE(SMSC_CONFIG_DEVNUM, SMSC_CONFIG_REG);
 	SMSC_WRITE(SMSC_CONFIG_DEVNUM_FLOPPY, SMSC_DATA_REG);
@@ -456,7 +505,8 @@
 }
 
 void __init
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res, unsigned long size,
+		       unsigned long align)
 {
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/generic/printf.c linux-2.4.20/arch/mips/mips-boards/generic/printf.c
--- linux-2.4.19/arch/mips/mips-boards/generic/printf.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/generic/printf.c	2002-10-29 11:18:34.000000000 +0000
@@ -32,20 +32,20 @@
 #include <asm/serial.h>
 
 
-#ifdef CONFIG_MIPS_ATLAS 
-/* 
- * Atlas registers are memory mapped on 64-bit aligned boundaries and 
+#if defined(CONFIG_MIPS_ATLAS) || defined(CONFIG_MIPS_SEAD)
+/*
+ * Atlas registers are memory mapped on 64-bit aligned boundaries and
  * only word access are allowed.
  * When reading the UART 8 bit registers only the LSB are valid.
  */
 unsigned int atlas_serial_in(struct async_struct *info, int offset)
 {
-	return inl(info->port + offset*8) & 0xff;
+	return (*(volatile unsigned int *)(info->port + mips_io_port_base + offset*8) & 0xff);
 }
 
 void atlas_serial_out(struct async_struct *info, int offset, int value)
 {
-	outl(value, info->port + offset*8);
+	*(volatile unsigned int *)(info->port + mips_io_port_base + offset*8) = value;
 }
 
 #define serial_in  atlas_serial_in
@@ -70,8 +70,8 @@
 };
 
 /*
- * Hooks to fake "prom" console I/O before devices 
- * are fully initialized. 
+ * Hooks to fake "prom" console I/O before devices
+ * are fully initialized.
  */
 static struct async_struct prom_port_info = {0};
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/generic/time.c linux-2.4.20/arch/mips/mips-boards/generic/time.c
--- linux-2.4.19/arch/mips/mips-boards/generic/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/generic/time.c	2002-10-29 11:18:49.000000000 +0000
@@ -35,6 +35,7 @@
 #include <asm/hardirq.h>
 #include <asm/div64.h>
 #include <asm/cpu.h>
+#include <asm/time.h>
 
 #include <linux/interrupt.h>
 #include <linux/mc146818rtc.h>
@@ -46,8 +47,6 @@
 static unsigned int r4k_offset; /* Amount to increment compare reg each time */
 static unsigned int r4k_cur;    /* What counter should be at next timer irq */
 
-extern unsigned int mips_counter_frequency;
-
 #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
 
 #if defined(CONFIG_MIPS_ATLAS)
@@ -57,7 +56,7 @@
 static char display_string[] = "        LINUX ON MALTA       ";
 #endif
 static unsigned int display_count = 0;
-#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8) 
+#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8)
 
 #define MIPS_CPU_TIMER_IRQ 7
 
@@ -71,13 +70,6 @@
 
 void mips_timer_interrupt(struct pt_regs *regs)
 {
-	int cpu = smp_processor_id();
-	int irq = MIPS_CPU_TIMER_IRQ;
-
-	irq_enter(cpu, irq);
-	kstat.irqs[cpu][irq]++;
-	timer_interrupt(irq, NULL, regs);
-
 	if ((timer_tick_count++ % HZ) == 0) {
 		mips_display_message(&display_string[display_count++]);
 		if (display_count == MAX_DISPLAY_COUNT)
@@ -85,15 +77,12 @@
 
 	}
 
-	irq_exit(cpu, irq);
-
-	if (softirq_pending(cpu))
-		do_softirq();
+	ll_timer_interrupt(MIPS_CPU_TIMER_IRQ, regs);
 }
 
-/* 
+/*
  * Figure out the r4k offset, the amount to increment the compare
- * register for each time tick. 
+ * register for each time tick.
  * Use the RTC to calculate offset.
  */
 static unsigned int __init cal_r4koff(void)
@@ -141,7 +130,7 @@
 		if ((hour & 0xf) == 0xc)
 		        hour &= 0x80;
 	        if (hour & 0x80)
-		        hour = (hour & 0xf) + 12;     
+		        hour = (hour & 0xf) + 12;
 	}
 	day = CMOS_READ(RTC_DAY_OF_MONTH);
 	mon = CMOS_READ(RTC_MONTH);
@@ -162,14 +151,14 @@
 
 	__save_and_cli(flags);
 
-        /* Set Data mode - binary. */ 
+        /* Set Data mode - binary. */
         CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL);
 
 	printk("calculating r4koff... ");
 	r4k_offset = cal_r4koff();
 	printk("%08x(%d)\n", r4k_offset, r4k_offset);
 
-        if ((read_32bit_cp0_register(CP0_PRID) & 0xffff00) == 
+        if ((read_32bit_cp0_register(CP0_PRID) & 0xffff00) ==
 	    (PRID_COMP_MIPS | PRID_IMP_20KC))
 		est_freq = r4k_offset*HZ;
 	else
@@ -177,7 +166,7 @@
 
 	est_freq += 5000;    /* round */
 	est_freq -= est_freq%10000;
-	printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, 
+	printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
 	       (est_freq%1000000)*100/1000000);
 
 	__restore_flags(flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/malta/Makefile linux-2.4.20/arch/mips/mips-boards/malta/Makefile
--- linux-2.4.19/arch/mips/mips-boards/malta/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/malta/Makefile	2002-10-29 11:18:31.000000000 +0000
@@ -7,12 +7,12 @@
 # This program is free software; you can distribute it and/or modify it
 # under the terms of the GNU General Public License (Version 2) as
 # published by the Free Software Foundation.
-# 
+#
 # This program is distributed in the hope 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.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/malta/malta_int.c linux-2.4.20/arch/mips/mips-boards/malta/malta_int.c
--- linux-2.4.19/arch/mips/mips-boards/malta/malta_int.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/malta/malta_int.c	2002-10-29 11:18:35.000000000 +0000
@@ -16,9 +16,9 @@
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  *
- * Routines for generic manipulation of the interrupts found on the MIPS 
+ * Routines for generic manipulation of the interrupts found on the MIPS
  * Malta board.
- * The interrupt controller is located in the South Bridge a PIIX4 device 
+ * The interrupt controller is located in the South Bridge a PIIX4 device
  * with two internal 82C95 interrupt controllers.
  */
 #include <linux/config.h>
@@ -41,207 +41,49 @@
 extern asmlinkage void mipsIRQ(void);
 extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs);
 extern void init_i8259_irqs (void);
-
-void enable_mips_irq(unsigned int irq);
-void disable_mips_irq(unsigned int irq);
+extern int mips_pcibios_iack(void);
 
 static spinlock_t mips_irq_lock = SPIN_LOCK_UNLOCKED;
 
-static void end_mips_irq (unsigned int irq)
-{
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-		enable_mips_irq(irq);
-}
-
-#define shutdown_mips_irq	disable_mips_irq
-
-void mask_and_ack_mips_irq(unsigned int irq);
-
-static unsigned int startup_mips_irq(unsigned int irq)
-{ 
-	enable_mips_irq(irq);
-
-	return 0; /* never anything pending */
-}
-
-static struct hw_interrupt_type mips_irq_type = {
-	"XT-PIC",
-	startup_mips_irq,
-	shutdown_mips_irq,
-	enable_mips_irq,
-	disable_mips_irq,
-	mask_and_ack_mips_irq,
-	end_mips_irq,
-	NULL
-};
-
-/*
- * This contains the interrupt mask for both 82C59 interrupt controllers.
- */
-static unsigned int cached_int_mask = 0xffff;
-
-void disable_mips_irq(unsigned int irq_nr)
-{
-        unsigned long flags;
-
-	if(irq_nr >= MALTAINT_END) {
-		printk("whee, invalid irq_nr %d\n", irq_nr);
-		panic("IRQ, you lose...");
-	}
-
-	spin_lock_irqsave(&mips_irq_lock, flags);
-	cached_int_mask |= (1 << irq_nr);
-	if (irq_nr & 8) {
-	        outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1);
-	} else {
-		outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1);
-	}
-	spin_unlock_irqrestore(&mips_irq_lock, flags);
-}
-
-void enable_mips_irq(unsigned int irq_nr)
-{
-        unsigned long flags;
-
-	if(irq_nr >= MALTAINT_END) {
-		printk("whee, invalid irq_nr %d\n", irq_nr);
-		panic("IRQ, you lose...");
-	}
-
-	spin_lock_irqsave(&mips_irq_lock, flags);
-	cached_int_mask &= ~(1 << irq_nr);
-	if (irq_nr & 8) {
-		outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1);
-
-		/* Enable irq 2 (cascade interrupt). */
-	        cached_int_mask &= ~(1 << 2); 
-		outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1);
-	} else {
-		outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1);
-	}	
-	spin_unlock_irqrestore(&mips_irq_lock, flags);
-}
-
-void mask_and_ack_mips_irq(unsigned int irq)
-{
-        unsigned long flags;
-
-	spin_lock_irqsave(&mips_irq_lock, flags);
-	if (irq & 8) {
-	        /* Non specific EOI to cascade */
-		outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI | PIIX4_OCW2_ILS_2, 
-		     PIIX4_ICTLR1_OCW2);
-
-		outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI, PIIX4_ICTLR2_OCW2);
-	} else {
-		outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI, PIIX4_ICTLR1_OCW2);
-	}
-	spin_unlock_irqrestore(&mips_irq_lock, flags);
-}
-
 static inline int get_int(int *irq)
 {
-	unsigned char irr;
-	
-	switch(mips_revision_corid) {
-	case MIPS_REVISION_CORID_QED_RM5261:
-	case MIPS_REVISION_CORID_CORE_LV:
-	case MIPS_REVISION_CORID_CORE_FPGA:
-	case MIPS_REVISION_CORID_CORE_MSC:
-		/*  
-		 * Determine highest priority pending interrupt by performing
-		 * a PCI Interrupt Acknowledge cycle.
-		 */
-		if (mips_revision_corid == MIPS_REVISION_CORID_CORE_MSC)
-			MSC_READ(MSC01_PCI_IACK, *irq);
-		else
-			GT_READ(GT_PCI0_IACK_OFS, *irq);
-		*irq &= 0xFF;
-
-		/*  
-		 * IRQ7 is used to detect spurious interrupts.
-		 * The interrupt acknowledge cycle returns IRQ7, if no 
-		 * interrupts is requested.
-		 * We can differentiate between this situation and a
-		 * "Normal" IRQ7 by reading the ISR.
-		 */
-		if (*irq == 7) 
-		{
-			outb(PIIX4_OCW3_SEL | PIIX4_OCW3_ISR, 
-			     PIIX4_ICTLR1_OCW3);
-			if (!(inb(PIIX4_ICTLR1_OCW3) & (1 << 7))) {
-				printk("We got a spurious interrupt from PIIX4.\n");
-				atomic_inc(&irq_err_count);
-				return -1;    /* Spurious interrupt. */
-			}
-		}
-		break;
+	unsigned long flags;
 
-	case MIPS_REVISION_CORID_BONITO64:
-	case MIPS_REVISION_CORID_CORE_20K:
-	        /*
-		 * Determine highest priority pending interrupt by reading 
-		 * the IRR register of controller 1.
-		 */
+	spin_lock_irqsave(&mips_irq_lock, flags);
 
-		outb(PIIX4_OCW3_SEL | PIIX4_OCW3_IRR, PIIX4_ICTLR1_OCW3);
-		irr = inb(PIIX4_ICTLR1_OCW3) & ~(cached_int_mask & 0xff);
+	*irq = mips_pcibios_iack();
 
-		if (!irr) {
-		        printk("We got a spurious interrupt from PIIX4.\n");
+	/*
+	 * IRQ7 is used to detect spurious interrupts.
+	 * The interrupt acknowledge cycle returns IRQ7, if no
+	 * interrupts is requested.
+	 * We can differentiate between this situation and a
+	 * "Normal" IRQ7 by reading the ISR.
+	 */
+	if (*irq == 7)
+	{
+		outb(PIIX4_OCW3_SEL | PIIX4_OCW3_ISR,
+		     PIIX4_ICTLR1_OCW3);
+		if (!(inb(PIIX4_ICTLR1_OCW3) & (1 << 7))) {
+			spin_unlock_irqrestore(&mips_irq_lock, flags);
+			printk("We got a spurious interrupt from PIIX4.\n");
 			atomic_inc(&irq_err_count);
-			return -1;   /* Spurious interrupt. */
-		}
-		*irq = 0;
-		while ((*irq < 7) && !(irr & 0x01)) {
-		        (*irq)++;
-			irr >>= 1;
+			return -1;    /* Spurious interrupt. */
 		}
-
-		if (*irq == 2)
-		{
-		        /*
-			 * Determine highest priority pending interrupt by 
-			 * reading the IRR register of controller 1.
-			 */
-		        outb(PIIX4_OCW3_SEL | PIIX4_OCW3_IRR, 
-			     PIIX4_ICTLR2_OCW3);
-			irr = inb(PIIX4_ICTLR2_OCW3) & 
-			~((cached_int_mask >> 8) & 0xff);
-
-			*irq = 8;
-			while ((*irq < 15) && !(irr & 0x01)) {
-			        (*irq)++;
-				irr >>= 1;
-			}
-		}
-		break;
-	default:
-	        printk("Unknown Core card, don't know the system controller.\n");
-		return -1;
 	}
 
+	spin_unlock_irqrestore(&mips_irq_lock, flags);
+
 	return 0;
 }
 
 void malta_hw0_irqdispatch(struct pt_regs *regs)
 {
 	int irq;
-	struct irqaction *action;
 
 	if (get_int(&irq))
 	        return;  /* interrupt has already been cleared */
 
-	switch(mips_revision_corid) {
-	case MIPS_REVISION_CORID_BONITO64:
-	case MIPS_REVISION_CORID_CORE_20K:
-		action = irq_desc[irq].action;
-		if (!action)
-			return;
-		action->flags |= SA_INTERRUPT;
-		break;
-	}
-	
 	do_IRQ(irq, regs);
 }
 
@@ -288,38 +130,9 @@
 
 void __init init_IRQ(void)
 {
-	unsigned int i;
-
 	set_except_vector(0, mipsIRQ);
 	init_generic_irq();
-	
-	switch(mips_revision_corid) {
-	case MIPS_REVISION_CORID_QED_RM5261:
-	case MIPS_REVISION_CORID_CORE_LV:
-	case MIPS_REVISION_CORID_CORE_FPGA:
-	case MIPS_REVISION_CORID_CORE_MSC:
-		init_i8259_irqs();
-		break;
-	case MIPS_REVISION_CORID_BONITO64:
-	case MIPS_REVISION_CORID_CORE_20K:
-		/* 
-		 * Mask out all interrupt by writing "1" to all bit position 
-		 * in the IMR register. 
-		 */
-		outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1);
-		outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1);
-
-		for (i = 0; i < 16; i++) {
-			irq_desc[i].status = IRQ_DISABLED;
-			irq_desc[i].action = 0;
-			irq_desc[i].depth = 1;
-			irq_desc[i].handler = &mips_irq_type;
-		}
-		break;
-	default:
-	        printk("Unknown Core card, don't know the system controller.\n");
-		return;
-	}
+	init_i8259_irqs();
 
 #ifdef CONFIG_REMOTE_DEBUG
 	if (remote_debug) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/malta/malta_setup.c linux-2.4.20/arch/mips/mips-boards/malta/malta_setup.c
--- linux-2.4.19/arch/mips/mips-boards/malta/malta_setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/malta/malta_setup.c	2002-10-29 11:18:48.000000000 +0000
@@ -104,7 +104,7 @@
 	for (i = 0; i < STANDARD_IO_RESOURCES; i++)
 		request_resource(&ioport_resource, standard_io_resources+i);
 
-	/* 
+	/*
 	 * Enable DMA channel 4 (cascade channel) in the PIIX4 south bridge.
 	 */
 	enable_dma(4);
@@ -145,14 +145,6 @@
 	if ((argptr = strstr(argptr, "nofpu")) != NULL)
 		mips_cpu.options &= ~MIPS_CPU_FPU;
 
-        /* 
-	 * For some reason the irq probing doesn't work on the 
-	 * Bonito controller.
-	 * For now this work just fine.
-	 */
-	argptr = prom_getcmdline();
-	strcat(argptr, " ide0=0x1f0,0x3f6,14");
-		
 	rtc_ops = &malta_rtc_ops;
 
 #ifdef CONFIG_BLK_DEV_IDE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/sead/Makefile linux-2.4.20/arch/mips/mips-boards/sead/Makefile
--- linux-2.4.19/arch/mips/mips-boards/sead/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/sead/Makefile	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,40 @@
+#
+# Carsten Langgaard, carstenl@mips.com
+# Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
+#
+# ########################################################################
+#
+# This program is free software; you can distribute it and/or modify it
+# under the terms of the GNU General Public License (Version 2) as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope 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.
+#
+# #######################################################################
+#
+# Makefile for the MIPS SEAD specific kernel interface routines
+# under Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+USE_STANDARD_AS_RULE := true
+
+all: sead.o
+
+O_TARGET := sead.o
+
+obj-y	:= sead_int.o sead_setup.o sead_time.o
+
+include $(TOPDIR)/Rules.make
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/sead/sead_int.c linux-2.4.20/arch/mips/mips-boards/sead/sead_int.c
--- linux-2.4.19/arch/mips/mips-boards/sead/sead_int.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/sead/sead_int.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,116 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ *
+ * Routines for generic manipulation of the interrupts found on the MIPS
+ * Sead board.
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/irq.h>
+#include <asm/mips-boards/sead.h>
+#include <asm/mips-boards/seadint.h>
+
+extern asmlinkage void mipsIRQ(void);
+extern void do_IRQ(int irq, struct pt_regs *regs);
+
+void disable_sead_irq(unsigned int irq_nr)
+{
+	if (irq_nr == SEADINT_UART0)
+		clear_cp0_status(0x00000400);
+	else
+		if (irq_nr == SEADINT_UART1)
+			clear_cp0_status(0x00000800);
+}
+
+void enable_sead_irq(unsigned int irq_nr)
+{
+	if (irq_nr == SEADINT_UART0)
+		set_cp0_status(0x00000400);
+	else
+		if (irq_nr == SEADINT_UART1)
+			set_cp0_status(0x00000800);
+}
+
+static unsigned int startup_sead_irq(unsigned int irq)
+{
+	enable_sead_irq(irq);
+	return 0; /* never anything pending */
+}
+
+#define shutdown_sead_irq	disable_sead_irq
+
+#define mask_and_ack_sead_irq disable_sead_irq
+
+static void end_sead_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		enable_sead_irq(irq);
+}
+
+static struct hw_interrupt_type sead_irq_type = {
+	"SEAD",
+	startup_sead_irq,
+	shutdown_sead_irq,
+	enable_sead_irq,
+	disable_sead_irq,
+	mask_and_ack_sead_irq,
+	end_sead_irq,
+	NULL
+};
+
+void sead_hw0_irqdispatch(struct pt_regs *regs)
+{
+	do_IRQ(0, regs);
+}
+
+void sead_hw1_irqdispatch(struct pt_regs *regs)
+{
+	do_IRQ(1, regs);
+}
+
+void __init init_IRQ(void)
+{
+	int i;
+
+        /*
+         * Mask out all interrupt
+	 */
+	clear_cp0_status(0x0000ff00);
+
+	/* Now safe to set the exception vector. */
+	set_except_vector(0, mipsIRQ);
+
+	init_generic_irq();
+
+	for (i = 0; i <= SEADINT_END; i++) {
+		irq_desc[i].status	= IRQ_DISABLED;
+		irq_desc[i].action	= NULL;
+		irq_desc[i].depth	= 1;
+		irq_desc[i].lock	= SPIN_LOCK_UNLOCKED;
+		irq_desc[i].handler	= &sead_irq_type;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/sead/sead_setup.c linux-2.4.20/arch/mips/mips-boards/sead/sead_setup.c
--- linux-2.4.19/arch/mips/mips-boards/sead/sead_setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/sead/sead_setup.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,81 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * SEAD specific setup.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/mc146818rtc.h>
+#include <linux/ioport.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mips-boards/generic.h>
+#include <asm/mips-boards/prom.h>
+#include <asm/mips-boards/seadint.h>
+#include <asm/time.h>
+
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE)
+extern void console_setup(char *, int *);
+char serial_console[20];
+#endif
+
+extern void mips_reboot_setup(void);
+extern void mips_time_init(void);
+extern void mips_timer_setup(struct irqaction *irq);
+
+const char *get_system_type(void)
+{
+	return "MIPS SEAD";
+}
+
+void __init bus_error_init(void)
+{
+}
+
+void __init sead_setup(void)
+{
+	char *argptr;
+
+	ioport_resource.end = 0x7fffffff;
+
+#ifdef CONFIG_SERIAL_CONSOLE
+	argptr = prom_getcmdline();
+	if ((argptr = strstr(argptr, "console=ttyS0")) == NULL) {
+		int i = 0;
+		char *s = prom_getenv("modetty0");
+		while(s[i] >= '0' && s[i] <= '9')
+			i++;
+		strcpy(serial_console, "ttyS0,");
+		strncpy(serial_console + 6, s, i);
+		prom_printf("Config serial console: %s\n", serial_console);
+		console_setup(serial_console, NULL);
+	}
+#endif
+
+	argptr = prom_getcmdline();
+
+	if ((argptr = strstr(argptr, "nofpu")) != NULL)
+		mips_cpu.options &= ~MIPS_CPU_FPU;
+
+	board_time_init = mips_time_init;
+	board_timer_setup = mips_timer_setup;
+
+	mips_reboot_setup();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mips-boards/sead/sead_time.c linux-2.4.20/arch/mips/mips-boards/sead/sead_time.c
--- linux-2.4.19/arch/mips/mips-boards/sead/sead_time.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/mips-boards/sead/sead_time.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,149 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ *
+ * Setting up the clock on the MIPS boards.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+
+#include <asm/mipsregs.h>
+#include <asm/ptrace.h>
+#include <asm/hardirq.h>
+#include <asm/cpu.h>
+
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+
+#include <asm/mips-boards/generic.h>
+#include <asm/mips-boards/prom.h>
+
+extern volatile unsigned long wall_jiffies;
+
+static unsigned long r4k_offset; /* Amount to increment compare reg each time */
+static unsigned long r4k_cur;    /* What counter should be at next timer irq */
+extern rwlock_t xtime_lock;
+
+#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ5)
+
+static char display_string[] = "        LINUX ON SEAD       ";
+
+static unsigned int display_count = 0;
+#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8)
+
+#define MIPS_CPU_TIMER_IRQ 7
+
+static unsigned int timer_tick_count=0;
+
+static inline void ack_r4ktimer(unsigned long newval)
+{
+	write_32bit_cp0_register(CP0_COMPARE, newval);
+}
+
+/*
+ * There are a lot of conceptually broken versions of the MIPS timer interrupt
+ * handler floating around.  This one is rather different, but the algorithm
+ * is provably more robust.
+ */
+void mips_timer_interrupt(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+	int irq = MIPS_CPU_TIMER_IRQ;
+
+	irq_enter(cpu, irq);
+
+	do {
+		kstat.irqs[cpu][irq]++;
+		do_timer(regs);
+
+		if ((timer_tick_count++ % HZ) == 0) {
+		    mips_display_message(&display_string[display_count++]);
+		    if (display_count == MAX_DISPLAY_COUNT)
+		        display_count = 0;
+		}
+
+		r4k_cur += r4k_offset;
+		ack_r4ktimer(r4k_cur);
+
+	} while (((unsigned long)read_32bit_cp0_register(CP0_COUNT)
+	         - r4k_cur) < 0x7fffffff);
+
+	irq_exit(cpu, irq);
+	if (softirq_pending(cpu))
+		do_softirq();
+}
+
+/*
+ * Figure out the r4k offset, the amount to increment the compare
+ * register for each time tick.
+ */
+static unsigned long __init cal_r4koff(void)
+{
+	/*
+	 * The SEAD board doesn't have a real time clock, so we can't
+	 * really calculate the timer offset.
+	 * For now we hardwire the SEAD board frequency to 12MHz.
+	 */
+	return(6000000/HZ);
+}
+
+void __init mips_time_init(void)
+{
+        unsigned int est_freq, flags;
+
+	__save_and_cli(flags);
+
+        /* Start r4k counter. */
+        write_32bit_cp0_register(CP0_COUNT, 0);
+
+	printk("calculating r4koff... ");
+	r4k_offset = cal_r4koff();
+	printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
+
+        if ((read_32bit_cp0_register(CP0_PRID) & 0xffff00) ==
+	    (PRID_COMP_MIPS | PRID_IMP_20KC))
+		est_freq = r4k_offset*HZ;
+	else
+		est_freq = 2*r4k_offset*HZ;
+
+	est_freq += 5000;    /* round */
+	est_freq -= est_freq%10000;
+	printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
+	       (est_freq%1000000)*100/1000000);
+
+	__restore_flags(flags);
+}
+
+void __init mips_timer_setup(struct irqaction *irq)
+{
+	/* we are using the cpu counter for timer interrupts */
+	irq->handler = no_action;     /* we use our own handler */
+	setup_irq(MIPS_CPU_TIMER_IRQ, irq);
+
+        /* to generate the first timer interrupt */
+	r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
+	write_32bit_cp0_register(CP0_COMPARE, r4k_cur);
+	set_cp0_status(ALLINTS);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/Makefile linux-2.4.20/arch/mips/mm/Makefile
--- linux-2.4.19/arch/mips/mm/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/Makefile	2002-10-29 11:18:32.000000000 +0000
@@ -20,8 +20,10 @@
 obj-$(CONFIG_CPU_R4300)		+= pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o
 obj-$(CONFIG_CPU_R4X00)		+= pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o
 obj-$(CONFIG_CPU_VR41XX)	+= pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o
-obj-$(CONFIG_CPU_R5000)		+= pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o
-obj-$(CONFIG_CPU_NEVADA)	+= pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o
+obj-$(CONFIG_CPU_R5000)		+= pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o \
+				   r5k-sc.o
+obj-$(CONFIG_CPU_NEVADA)	+= pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o \
+				   r5k-sc.o
 obj-$(CONFIG_CPU_R5432)		+= pg-r5432.o c-r5432.o tlb-r4k.o tlbex-r4k.o
 obj-$(CONFIG_CPU_RM7000)	+= pg-rm7k.o c-rm7k.o tlb-r4k.o tlbex-r4k.o
 obj-$(CONFIG_CPU_R10000)	+= pg-andes.o c-andes.o tlb-r4k.o tlbex-r4k.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/c-andes.c linux-2.4.20/arch/mips/mm/c-andes.c
--- linux-2.4.19/arch/mips/mm/c-andes.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/c-andes.c	2002-10-29 11:18:48.000000000 +0000
@@ -124,6 +124,6 @@
 			printk("Unknown L2 line size\n");
 			while(1);
 	}
-    
+
         flush_cache_l1();
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/c-mips32.c linux-2.4.20/arch/mips/mm/c-mips32.c
--- linux-2.4.19/arch/mips/mm/c-mips32.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/c-mips32.c	2002-10-29 11:18:32.000000000 +0000
@@ -424,33 +424,33 @@
 	unsigned int lsize;
 
         if (!(config & (1 << 31))) {
-	        /* 
-		 * Not a MIPS32 complainant CPU. 
+	        /*
+		 * Not a MIPS32 complainant CPU.
 		 * Config 1 register not supported, we assume R4k style.
 		 */
 	        icache_size = 1 << (12 + ((config >> 9) & 7));
 		ic_lsize = 16 << ((config >> 5) & 1);
 		mips_cpu.icache.linesz = ic_lsize;
-		
-		/* 
+
+		/*
 		 * We cannot infer associativity - assume direct map
 		 * unless probe template indicates otherwise
 		 */
 		if(!mips_cpu.icache.ways) mips_cpu.icache.ways = 1;
-		mips_cpu.icache.sets = 
+		mips_cpu.icache.sets =
 			(icache_size / ic_lsize) / mips_cpu.icache.ways;
 	} else {
-	       config1 = read_mips32_cp0_config1(); 
+	       config1 = read_mips32_cp0_config1();
 
 	       if ((lsize = ((config1 >> 19) & 7)))
 		       mips_cpu.icache.linesz = 2 << lsize;
-	       else 
+	       else
 		       mips_cpu.icache.linesz = lsize;
 	       mips_cpu.icache.sets = 64 << ((config1 >> 22) & 7);
 	       mips_cpu.icache.ways = 1 + ((config1 >> 16) & 7);
 
 	       ic_lsize = mips_cpu.icache.linesz;
-	       icache_size = mips_cpu.icache.sets * mips_cpu.icache.ways * 
+	       icache_size = mips_cpu.icache.sets * mips_cpu.icache.ways *
 		             ic_lsize;
 	}
 	printk("Primary instruction cache %dkb, linesize %d bytes (%d ways)\n",
@@ -463,32 +463,32 @@
 	unsigned int lsize;
 
         if (!(config & (1 << 31))) {
-	        /* 
-		 * Not a MIPS32 complainant CPU. 
+	        /*
+		 * Not a MIPS32 complainant CPU.
 		 * Config 1 register not supported, we assume R4k style.
-		 */  
+		 */
 		dcache_size = 1 << (12 + ((config >> 6) & 7));
 		dc_lsize = 16 << ((config >> 4) & 1);
 		mips_cpu.dcache.linesz = dc_lsize;
-		/* 
+		/*
 		 * We cannot infer associativity - assume direct map
 		 * unless probe template indicates otherwise
 		 */
 		if(!mips_cpu.dcache.ways) mips_cpu.dcache.ways = 1;
-		mips_cpu.dcache.sets = 
+		mips_cpu.dcache.sets =
 			(dcache_size / dc_lsize) / mips_cpu.dcache.ways;
 	} else {
 	        config1 = read_mips32_cp0_config1();
 
 		if ((lsize = ((config1 >> 10) & 7)))
 		        mips_cpu.dcache.linesz = 2 << lsize;
-		else 
+		else
 		        mips_cpu.dcache.linesz= lsize;
 		mips_cpu.dcache.sets = 64 << ((config1 >> 13) & 7);
 		mips_cpu.dcache.ways = 1 + ((config1 >> 7) & 7);
 
 		dc_lsize = mips_cpu.dcache.linesz;
-		dcache_size = 
+		dcache_size =
 			mips_cpu.dcache.sets * mips_cpu.dcache.ways
 			* dc_lsize;
 	}
@@ -638,12 +638,12 @@
 
 	if (sc_present) {
 	  	mips_cpu.scache.linesz = sc_lsize;
-		/* 
+		/*
 		 * We cannot infer associativity - assume direct map
 		 * unless probe template indicates otherwise
 		 */
 		if(!mips_cpu.scache.ways) mips_cpu.scache.ways = 1;
-		mips_cpu.scache.sets = 
+		mips_cpu.scache.sets =
 		  (scache_size / sc_lsize) / mips_cpu.scache.ways;
 
 		setup_scache_funcs();
@@ -657,11 +657,7 @@
 {
 	unsigned long config = read_32bit_cp0_register(CP0_CONFIG);
 
-#ifdef CONFIG_MIPS_UNCACHED
-	change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
-#else
-	change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT);
-#endif
+	change_cp0_config(CONF_CM_CMASK, CONF_CM_DEFAULT);
 
 	probe_icache(config);
 	probe_dcache(config);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/c-r3k.c linux-2.4.20/arch/mips/mm/c-r3k.c
--- linux-2.4.19/arch/mips/mm/c-r3k.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/c-r3k.c	2002-10-29 11:18:48.000000000 +0000
@@ -19,7 +19,6 @@
 #include <asm/system.h>
 #include <asm/isadep.h>
 #include <asm/io.h>
-#include <asm/wbflush.h>
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
 
@@ -50,8 +49,8 @@
 		for (size = 128; size <= 0x40000; size <<= 1)
 			*(p + size) = 0;
 		*p = -1;
-		for (size = 128; 
-		     (size <= 0x40000) && (*(p + size) == 0); 
+		for (size = 128;
+		     (size <= 0x40000) && (*(p + size) == 0);
 		     size <<= 1)
 			;
 		if (size > 0x40000)
@@ -97,7 +96,7 @@
 	dcache_size = r3k_cache_size(ST0_ISC);
 	if (dcache_size)
 		dcache_lsize = r3k_cache_lsize(ST0_ISC);
-	
+
 
 	icache_size = r3k_cache_size(ST0_ISC|ST0_SWC);
 	if (icache_size)
@@ -239,7 +238,7 @@
 static inline void r3k_flush_cache_all(void)
 {
 }
- 
+
 static inline void r3k___flush_cache_all(void)
 {
 	r3k_flush_icache_range(KSEG0, KSEG0 + icache_size);
@@ -314,7 +313,7 @@
 
 static void r3k_dma_cache_wback_inv(unsigned long start, unsigned long size)
 {
-	wbflush();
+	iob();
 	r3k_flush_dcache_range(start, start + size);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/c-r4k.c linux-2.4.20/arch/mips/mm/c-r4k.c
--- linux-2.4.19/arch/mips/mm/c-r4k.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/c-r4k.c	2002-10-29 11:18:50.000000000 +0000
@@ -1150,12 +1150,6 @@
 	}
 }
 
-static void
-r4k_dma_cache_wback(unsigned long addr, unsigned long size)
-{
-	panic("r4k_dma_cache called - should not happen.");
-}
-
 /*
  * While we're protected against bad userland addresses we don't care
  * very much about what happens in that case.  Usually a segmentation
@@ -1200,6 +1194,12 @@
 {
         switch (mips_cpu.cputype) {
         case CPU_VR41XX:
+        case CPU_VR4111:
+        case CPU_VR4121:
+        case CPU_VR4122:
+        case CPU_VR4131:
+        case CPU_VR4181:
+        case CPU_VR4181A:
                 icache_size = 1 << (10 + ((config >> 9) & 7));
                 break;
         default:
@@ -1216,6 +1216,12 @@
 {
         switch (mips_cpu.cputype) {
         case CPU_VR41XX:
+        case CPU_VR4111:
+        case CPU_VR4121:
+        case CPU_VR4122:
+        case CPU_VR4131:
+        case CPU_VR4181:
+        case CPU_VR4181A:
                 dcache_size = 1 << (10 + ((config >> 6) & 7));
                 break;
         default:
@@ -1358,7 +1364,7 @@
 	_flush_icache_page = r4k_flush_icache_page_p;
 
 	_dma_cache_wback_inv = r4k_dma_cache_wback_inv_pc;
-	_dma_cache_wback = r4k_dma_cache_wback;
+	_dma_cache_wback = r4k_dma_cache_wback_inv_pc;
 	_dma_cache_inv = r4k_dma_cache_inv_pc;
 }
 
@@ -1441,7 +1447,7 @@
 	___flush_cache_all = _flush_cache_all;
 	_flush_icache_page = r4k_flush_icache_page_s;
 	_dma_cache_wback_inv = r4k_dma_cache_wback_inv_sc;
-	_dma_cache_wback = r4k_dma_cache_wback;
+	_dma_cache_wback = r4k_dma_cache_wback_inv_sc;
 	_dma_cache_inv = r4k_dma_cache_inv_sc;
 }
 
@@ -1456,23 +1462,31 @@
 	probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache));
 	sc_present = probe_scache_kseg1(config);
 
-	if (sc_present) {
-		setup_scache_funcs();
+	if (!sc_present) {
+		setup_noscache_funcs();
 		return;
 	}
 
-	setup_noscache_funcs();
+	switch(mips_cpu.cputype) {
+	case CPU_R5000:
+	case CPU_NEVADA:
+			setup_noscache_funcs();
+#if defined(CONFIG_CPU_R5000) || defined(CONFIG_CPU_NEVADA)
+			r5k_sc_init();
+#endif
+			break;
+	default:
+			setup_scache_funcs();
+	}
+
+
 }
 
 void __init ld_mmu_r4xx0(void)
 {
 	unsigned long config = read_32bit_cp0_register(CP0_CONFIG);
 
-#ifdef CONFIG_MIPS_UNCACHED
-	change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
-#else
-	change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT);
-#endif
+	change_cp0_config(CONF_CM_CMASK | CONF_CU, CONF_CM_DEFAULT);
 
 	probe_icache(config);
 	probe_dcache(config);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/c-r5432.c linux-2.4.20/arch/mips/mm/c-r5432.c
--- linux-2.4.19/arch/mips/mm/c-r5432.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/c-r5432.c	2002-10-29 11:18:36.000000000 +0000
@@ -352,7 +352,7 @@
 	blast_dcache32_page((unsigned long)page_address(page));
 }
 
-static void 
+static void
 r5432_flush_icache_range(unsigned long start, unsigned long end)
 {
 	r5432_flush_cache_all_d32i32();
@@ -455,7 +455,7 @@
 {
 	unsigned long config = read_32bit_cp0_register(CP0_CONFIG);
 
-	change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT);
+	change_cp0_config(CONF_CM_CMASK, CONF_CM_DEFAULT);
 
 	probe_icache(config);
 	probe_dcache(config);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/c-rm7k.c linux-2.4.20/arch/mips/mm/c-rm7k.c
--- linux-2.4.19/arch/mips/mm/c-rm7k.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/c-rm7k.c	2002-10-29 11:18:32.000000000 +0000
@@ -139,7 +139,7 @@
 		a += sc_lsize;
 	}
 
-	if (!rm7k_tcache_enabled) 
+	if (!rm7k_tcache_enabled)
 		return;
 
 	a = addr & ~(tc_pagesize - 1);
@@ -150,7 +150,7 @@
 		a += tc_pagesize;
 	}
 }
-	       
+
 static void
 rm7k_dma_cache_inv(unsigned long addr, unsigned long size)
 {
@@ -165,7 +165,7 @@
 		a += sc_lsize;
 	}
 
-	if (!rm7k_tcache_enabled) 
+	if (!rm7k_tcache_enabled)
 		return;
 
 	a = addr & ~(tc_pagesize - 1);
@@ -210,10 +210,10 @@
 }
 
 
-/* 
+/*
  * This function is executed in the uncached segment KSEG1.
  * It must not touch the stack, because the stack pointer still points
- * into KSEG0. 
+ * into KSEG0.
  *
  * Three options:
  *	- Write it in assembly and guarantee that we don't use the stack.
@@ -228,12 +228,12 @@
 static __init void setup_scache(void)
 {
 	int register i;
-	
+
 	set_cp0_config(1<<3 /* CONF_SE */);
 
 	set_taglo(0);
 	set_taghi(0);
-	
+
 	for (i=0; i<scache_size; i+=sc_lsize) {
 		__asm__ __volatile__ (
 		      ".set noreorder\n\t"
@@ -265,7 +265,7 @@
 	func();
 	printk("Done\n");
 }
- 
+
 static inline void probe_tcache(unsigned long config)
 {
 	if ((config >> 17) & 1)
@@ -275,10 +275,10 @@
 	 * magic necessary to turn it on, and blindly asking the CPU to
 	 * start using it would may give cache errors.
 	 *
-	 * Also, board-specific knowledge may allow us to use the 
+	 * Also, board-specific knowledge may allow us to use the
 	 * CACHE Flash_Invalidate_T instruction if the tag RAM supports
 	 * it, and may specify the size of the L3 cache so we don't have
-	 * to probe it. 
+	 * to probe it.
 	 */
 	printk(KERN_INFO "Tertiary cache present, %s enabled\n",
 	       config&(1<<12) ? "already" : "not (yet)");
@@ -319,9 +319,7 @@
 			: "r" (addr), "i" (Index_Store_Tag_I), "i" (Fill));
 	}
 
-#ifndef CONFIG_MIPS_UNCACHED
-	change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT);
-#endif
+	change_cp0_config(CONF_CM_CMASK, CONF_CM_DEFAULT);
 
 	probe_icache(config);
 	probe_dcache(config);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/c-sb1.c linux-2.4.20/arch/mips/mm/c-sb1.c
--- linux-2.4.19/arch/mips/mm/c-sb1.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/c-sb1.c	2002-10-29 11:18:49.000000000 +0000
@@ -12,11 +12,11 @@
  * 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.
- */ 
+ */
 #include <linux/config.h>
 #include <linux/init.h>
 #include <asm/mmu_context.h>
@@ -63,7 +63,7 @@
  * if we miss in the icache, and have dirty data in the
  * L1 dcache, then we'll go out to memory (or the L2) and
  * get the not-as-recent data.
- * 
+ *
  * So the only time we have to flush the dcache is when
  * we're flushing the icache.  Since the L2 is fully
  * coherent to everything, including I/O, we never have
@@ -80,7 +80,7 @@
 	 * Haven't worried too much about speed here; given that we're flushing
 	 * the icache, the time to invalidate is dwarfed by the time it's going
 	 * to take to refill it.  Register usage:
-	 * 
+	 *
 	 * $1 - moving cache index
 	 * $2 - set count
 	 */
@@ -104,7 +104,7 @@
 		".set noreorder             \n"
 		".set mips2                 \n"
 		"sync                       \n"
-#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS		/* Bug 1384 */			
+#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS		/* Bug 1384 */
 		"sync                       \n"
 #endif
 		".set pop                   \n");
@@ -160,7 +160,7 @@
 		".set noreorder             \n"
 		".set noat                  \n"
 		".set mips4                 \n"
-		"     move   $1, %0         \n" 
+		"     move   $1, %0         \n"
 		"1:                         \n"
 #ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
 		".align 3                   \n"
@@ -199,7 +199,7 @@
 		".set noreorder             \n"
 		".set noat                  \n"
 		".set mips4                 \n"
-		"     move   $1, %0         \n" 
+		"     move   $1, %0         \n"
 		".align 3                   \n"
 		"1:   cache  %3, (0<<13)($1) \n" /* Index-inval this address */
 		"     cache  %3, (1<<13)($1) \n" /* Index-inval this address */
@@ -279,9 +279,9 @@
 static inline void protected_writeback_dcache_line(unsigned long addr)
 {
 #ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
-	/* Have to be sure the TLB entry exists for the cache op, 
+	/* Have to be sure the TLB entry exists for the cache op,
 	   so we have to be sure that nothing happens in between the
-	   lw and the cache op 
+	   lw and the cache op
 	*/
 	unsigned long flags;
 	local_irq_save(flags);
@@ -371,7 +371,7 @@
 	 * Haven't worried too much about speed here; given that we're flushing
 	 * the icache, the time to invalidate is dwarfed by the time it's going
 	 * to take to refill it.  Register usage:
-	 * 
+	 *
 	 * $1 - moving cache index
 	 * $2 - set count
 	 */
@@ -403,23 +403,23 @@
 
 /*
  * This only needs to make sure stores done up to this
- * point are visible to other agents outside the CPU.  Given 
- * the coherent nature of the ZBbus, all that's required here is 
+ * point are visible to other agents outside the CPU.  Given
+ * the coherent nature of the ZBbus, all that's required here is
  * a sync to make sure the data gets out to the caches and is
- * visible to an arbitrary A Phase from an external agent 
- *   
+ * visible to an arbitrary A Phase from an external agent
+ *
  * Actually, I'm not even sure that's necessary; the semantics
  * of this function aren't clear.  If it's supposed to serve as
- * a memory barrier, this is needed.  If it's only meant to 
+ * a memory barrier, this is needed.  If it's only meant to
  * prevent data from being invisible to non-cpu memory accessors
- * for some indefinite period of time (e.g. in a non-coherent 
+ * for some indefinite period of time (e.g. in a non-coherent
  * dcache) then this function would be a complete nop.
  */
 static void sb1_flush_page_to_ram(struct page *page)
 {
 	__asm__ __volatile__(
 		"     sync  \n"  /* Short pipe */
-		:::"memory");	
+		:::"memory");
 }
 
 /*
@@ -433,13 +433,13 @@
  * 6 - 4096
  * 7 - Reserved
  */
-  
+
 static unsigned int decode_cache_sets(unsigned int config_field)
 {
 	if (config_field == 7) {
 		/* JDCXXX - Find a graceful way to abort. */
 		return 0;
-	} 
+	}
 	return (1<<(config_field + 6));
 }
 
@@ -462,7 +462,7 @@
 	} else if (config_field == 7) {
 		/* JDCXXX - Find a graceful way to abort. */
 		return 0;
-	} 
+	}
 	return (1<<(config_field + 1));
 }
 
@@ -519,6 +519,6 @@
 	_flush_cache_sigtramp = sb1_flush_cache_sigtramp;
 	_flush_icache_all = sb1_flush_icache_all;
 
-	change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_COW);
+	change_cp0_config(CONF_CM_CMASK, CONF_CM_DEFAULT);
 	flush_cache_all();
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/c-tx39.c linux-2.4.20/arch/mips/mm/c-tx39.c
--- linux-2.4.19/arch/mips/mm/c-tx39.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/c-tx39.c	2002-10-29 11:18:30.000000000 +0000
@@ -20,7 +20,6 @@
 #include <asm/system.h>
 #include <asm/isadep.h>
 #include <asm/io.h>
-#include <asm/wbflush.h>
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
 
@@ -63,8 +62,8 @@
 static void tx39h_dma_cache_wback_inv(unsigned long addr, unsigned long size)
 {
 	unsigned long end, a;
-	wbflush();
 
+	iob();
 	a = addr & ~(dcache_lsize - 1);
 	end = (addr + size) & ~(dcache_lsize - 1);
 	while (1) {
@@ -89,7 +88,7 @@
 	write_32bit_cp0_register(CP0_CONF, config);
 	__restore_flags(flags);
 }
- 
+
 static void tx39_flush_cache_mm(struct mm_struct *mm)
 {
 	if(mm->context != 0) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/c-tx49.c linux-2.4.20/arch/mips/mm/c-tx49.c
--- linux-2.4.19/arch/mips/mm/c-tx49.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/c-tx49.c	2002-10-29 11:18:34.000000000 +0000
@@ -387,11 +387,7 @@
 	if (mips_configk0 != -1)
 		change_cp0_config(CONF_CM_CMASK, mips_configk0);
 	else
-#ifdef CONFIG_MIPS_UNCACHED
-		change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
-#else
-		change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT);
-#endif
+		change_cp0_config(CONF_CM_CMASK, CONF_CM_DEFAULT);
 
 	probe_icache(config);
 	probe_dcache(config);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/extable.c linux-2.4.20/arch/mips/mm/extable.c
--- linux-2.4.19/arch/mips/mm/extable.c	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/extable.c	2002-10-29 11:18:48.000000000 +0000
@@ -36,14 +36,13 @@
 search_exception_table(unsigned long addr)
 {
 	unsigned long ret = 0;
-	
+
 #ifndef CONFIG_MODULES
 	/* There is only the kernel to search.  */
 	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
 	return ret;
 #else
 	unsigned long flags;
-
 	/* The kernel is the last "module" -- no need to treat it special.  */
 	struct module *mp;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/fault.c linux-2.4.20/arch/mips/mm/fault.c
--- linux-2.4.19/arch/mips/mm/fault.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/fault.c	2002-10-29 11:18:35.000000000 +0000
@@ -211,13 +211,11 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
-		tsk->policy |= SCHED_YIELD;
-		schedule();
-		down_read(&mm->mmap_sem);
+		yield();
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk(KERN_NOTICE "VM: killing process %s\n", tsk->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/init.c linux-2.4.20/arch/mips/mm/init.c
--- linux-2.4.19/arch/mips/mm/init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/init.c	2002-10-29 11:18:49.000000000 +0000
@@ -67,9 +67,9 @@
 {
 	unsigned long order, size;
 	struct page *page;
-	if(mips_cpu.options & MIPS_CPU_VCE) 
+	if(mips_cpu.options & MIPS_CPU_VCE)
 		order = 3;
-	else 
+	else
 		order = 0;
 
 	empty_zero_page = __get_free_pages(GFP_KERNEL, order);
@@ -367,7 +367,7 @@
 	unsigned long addr;
 
 	prom_free_prom_memory ();
-    
+
 	addr = (unsigned long) &__init_begin;
 	while (addr < (unsigned long) &__init_end) {
 		ClearPageReserved(virt_to_page(addr));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/ioremap.c linux-2.4.20/arch/mips/mm/ioremap.c
--- linux-2.4.19/arch/mips/mm/ioremap.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/ioremap.c	2002-10-29 11:18:40.000000000 +0000
@@ -122,10 +122,11 @@
 		return NULL;
 
 	/*
-	 * Map objects in the low 512mb of address space using KSEG1, otherwise
-	 * map using page tables.
+	 * Map uncached objects in the low 512mb of address space using KSEG1,
+	 * otherwise map using page tables.
 	 */
-	if (IS_LOW512(phys_addr) && IS_LOW512(last_addr))
+	if (IS_LOW512(phys_addr) && IS_LOW512(last_addr) &&
+	    flags == _CACHE_UNCACHED)
 		return (void *) KSEG1ADDR(phys_addr);
 
 	/*
@@ -137,7 +138,7 @@
 
 		t_addr = __va(phys_addr);
 		t_end = t_addr + (size - 1);
-	   
+
 		for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++)
 			if(!PageReserved(page))
 				return NULL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/loadmmu.c linux-2.4.20/arch/mips/mm/loadmmu.c
--- linux-2.4.19/arch/mips/mm/loadmmu.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/loadmmu.c	2002-10-29 11:18:34.000000000 +0000
@@ -119,6 +119,7 @@
 #endif
 #ifdef CONFIG_CPU_R10000
 	case CPU_R10000:
+	case CPU_R12000:
 		ld_mmu_andes();
 		r4k_tlb_init();
 		break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/pg-r4k.S linux-2.4.20/arch/mips/mm/pg-r4k.S
--- linux-2.4.19/arch/mips/mm/pg-r4k.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/pg-r4k.S	2002-10-29 11:18:48.000000000 +0000
@@ -83,10 +83,10 @@
  *      Hit_Invalidate_D and Create_Dirty_Excl_D should only be
  *      executed if there is no other dcache activity. If the dcache is
  *      accessed for another instruction immeidately preceding when these
- *      cache instructions are executing, it is possible that the dcache 
- *      tag match outputs used by these cache instructions will be 
+ *      cache instructions are executing, it is possible that the dcache
+ *      tag match outputs used by these cache instructions will be
  *      incorrect. These cache instructions should be preceded by at least
- *      four instructions that are not any kind of load or store 
+ *      four instructions that are not any kind of load or store
  *      instruction.
  *
  *      This is not allowed:    lw
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/pg-sb1.c linux-2.4.20/arch/mips/mm/pg-sb1.c
--- linux-2.4.19/arch/mips/mm/pg-sb1.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/pg-sb1.c	2002-10-29 11:18:49.000000000 +0000
@@ -2,7 +2,7 @@
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org)
  * Copyright (C) 2000 Sibyte
- * 
+ *
  * Written by Justin Carlson (carlson@sibyte.com)
  *
  *
@@ -15,11 +15,11 @@
  * 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.
- */ 
+ */
 #include <linux/config.h>
 #include <asm/page.h>
 
@@ -39,7 +39,7 @@
 	   performance model */
 
 	/* We prefetch 4 lines ahead.  We're also "cheating" slightly here...
-	   since we know we're on an SB1, we force the assembler to take 
+	   since we know we're on an SB1, we force the assembler to take
 	   64-bit operands to speed things up */
 	__asm__ __volatile__(
 		".set push                  \n"
@@ -47,15 +47,19 @@
 		".set noat                  \n"
 		".set mips4                 \n"
 		"     addiu     $1, %0, %2  \n"  /* Calculate the end of the page to clear */
+#ifdef CONFIG_CPU_HAS_PREFETCH
 		"     pref       " SB1_PREF_STORE_STREAMED_HINT ",  0(%0)  \n"  /* Prefetch the first 4 lines */
-		"     pref       " SB1_PREF_STORE_STREAMED_HINT ", 32(%0)  \n"  
-		"     pref       " SB1_PREF_STORE_STREAMED_HINT ", 64(%0)  \n"  
-		"     pref       " SB1_PREF_STORE_STREAMED_HINT ", 96(%0)  \n"  
+		"     pref       " SB1_PREF_STORE_STREAMED_HINT ", 32(%0)  \n"
+		"     pref       " SB1_PREF_STORE_STREAMED_HINT ", 64(%0)  \n"
+		"     pref       " SB1_PREF_STORE_STREAMED_HINT ", 96(%0)  \n"
+#endif
 		"1:   sd        $0,  0(%0)  \n"  /* Throw out a cacheline of 0's */
 		"     sd        $0,  8(%0)  \n"
 		"     sd        $0, 16(%0)  \n"
 		"     sd        $0, 24(%0)  \n"
+#ifdef CONFIG_CPU_HAS_PREFETCH
 		"     pref       " SB1_PREF_STORE_STREAMED_HINT ",128(%0)  \n"  /* Prefetch 4 lines ahead     */
+#endif
 		"     bne       $1, %0, 1b  \n"
 		"     addiu     %0, %0, 32  \n"  /* Next cacheline (This instruction better be short piped!) */
 		".set pop                   \n"
@@ -71,7 +75,7 @@
 
 	/* This should be optimized in assembly...can't use ld/sd, though,
 	 * because the top 32 bits could be nuked if we took an interrupt
-	 * during the routine.	And this is not a good place to be cli()'ing 
+	 * during the routine.	And this is not a good place to be cli()'ing
 	 */
 
 	/* The pref's used here are using "streaming" hints, which cause the
@@ -87,12 +91,14 @@
 		".set noat                  \n"
 		".set mips4                 \n"
 		"     addiu     $1, %0, %4  \n"  /* Calculate the end of the page to copy */
+#ifdef CONFIG_CPU_HAS_PREFETCH
 		"     pref       " SB1_PREF_LOAD_STREAMED_HINT  ",  0(%0)  \n"  /* Prefetch the first 3 lines */
-		"     pref       " SB1_PREF_STORE_STREAMED_HINT ",  0(%1)  \n"  
+		"     pref       " SB1_PREF_STORE_STREAMED_HINT ",  0(%1)  \n"
 		"     pref       " SB1_PREF_LOAD_STREAMED_HINT  ",  32(%0) \n"
-		"     pref       " SB1_PREF_STORE_STREAMED_HINT ",  32(%1) \n"  
+		"     pref       " SB1_PREF_STORE_STREAMED_HINT ",  32(%1) \n"
 		"     pref       " SB1_PREF_LOAD_STREAMED_HINT  ",  64(%0) \n"
-		"     pref       " SB1_PREF_STORE_STREAMED_HINT ",  64(%1) \n"  
+		"     pref       " SB1_PREF_STORE_STREAMED_HINT ",  64(%1) \n"
+#endif
 		"1:   lw        $2,  0(%0)  \n"  /* Block copy a cacheline */
 		"     lw        $3,  4(%0)  \n"
 		"     lw        $4,  8(%0)  \n"
@@ -101,22 +107,24 @@
 		"     lw        $7, 20(%0)  \n"
 		"     lw        $8, 24(%0)  \n"
 		"     lw        $9, 28(%0)  \n"
+#ifdef CONFIG_CPU_HAS_PREFETCH
 		"     pref       " SB1_PREF_LOAD_STREAMED_HINT  ", 96(%0)  \n"  /* Prefetch ahead         */
 		"     pref       " SB1_PREF_STORE_STREAMED_HINT ", 96(%1)  \n"
-		"     sw        $2,  0(%1)  \n"  
+#endif
+		"     sw        $2,  0(%1)  \n"
 		"     sw        $3,  4(%1)  \n"
 		"     sw        $4,  8(%1)  \n"
 		"     sw        $5, 12(%1)  \n"
 		"     sw        $6, 16(%1)  \n"
 		"     sw        $7, 20(%1)  \n"
 		"     sw        $8, 24(%1)  \n"
-		"     sw        $9, 28(%1)  \n"		
+		"     sw        $9, 28(%1)  \n"
 		"     addiu     %1, %1, 32  \n"  /* Next cacheline */
 		"     nop                   \n"  /* Force next add to short pipe */
 		"     nop                   \n"  /* Force next add to short pipe */
 		"     bne       $1, %0, 1b  \n"
 		"     addiu     %0, %0, 32  \n"  /* Next cacheline */
-		".set pop                   \n" 
+		".set pop                   \n"
 		:"=r" (to),
 		"=r" (from)
 		:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/r5k-sc.c linux-2.4.20/arch/mips/mm/r5k-sc.c
--- linux-2.4.19/arch/mips/mm/r5k-sc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/r5k-sc.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org),
+ * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com).
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/mipsregs.h>
+#include <asm/bcache.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/mmu_context.h>
+#include <asm/cacheops.h>
+
+/* Secondary cache size in bytes, if present.  */
+static unsigned long scache_size;
+
+#define SC_LINE 32
+#define SC_PAGE (128*SC_LINE)
+
+#define cache_op(base,op)                   \
+__asm__ __volatile__("				\
+		.set noreorder;                 \
+		.set mips3;                     \
+		cache %1, (%0);                 \
+		.set mips0;                     \
+		.set reorder"                   \
+		:                               \
+		: "r" (base),                   \
+		  "i" (op));
+
+static inline void blast_r5000_scache(void)
+{
+	unsigned long start = KSEG0;
+	unsigned long end = KSEG0 + scache_size;
+
+	while(start < end) {
+		cache_op(start, R5K_Page_Invalidate_S);
+		start += SC_PAGE;
+	}
+}
+
+static void r5k_dma_cache_inv_sc(unsigned long addr, unsigned long size)
+{
+	unsigned long end, a;
+
+	if (size >= scache_size) {
+		blast_r5000_scache();
+		return;
+	}
+
+	/* On the R5000 secondary cache we cannot
+	 * invalidate less than a page at a time.
+	 * The secondary cache is physically indexed, write-through.
+	 */
+	a = addr & ~(SC_PAGE - 1);
+	end = (addr + size - 1) & ~(SC_PAGE - 1);
+	while (a <= end) {
+		cache_op(a, R5K_Page_Invalidate_S);
+		a += SC_PAGE;
+	}
+}
+
+static void r5k_sc_enable(void)
+{
+        unsigned long flags;
+
+	__save_and_cli(flags);
+	change_cp0_config(CONF_SE, CONF_SE);
+	blast_r5000_scache();
+	__restore_flags(flags);
+}
+
+static void r5k_sc_disable(void)
+{
+        unsigned long flags;
+
+	__save_and_cli(flags);
+	blast_r5000_scache();
+	change_cp0_config(CONF_SE, 0);
+	__restore_flags(flags);
+}
+
+static inline int __init r5k_sc_probe(void)
+{
+	unsigned long config = read_32bit_cp0_register(CP0_CONFIG);
+
+	if(config & CONF_SC)
+		return(0);
+
+	scache_size = (512*1024) << ((config >> 20)&3);
+
+	printk("R5000 SCACHE size %ldK, linesize 32 bytes.\n",
+			scache_size >> 10);
+
+	return 1;
+}
+
+struct bcache_ops r5k_sc_ops = {
+	r5k_sc_enable,
+	r5k_sc_disable,
+	r5k_dma_cache_inv_sc,
+	r5k_dma_cache_inv_sc
+};
+
+void __init r5k_sc_init(void)
+{
+	if (r5k_sc_probe()) {
+		r5k_sc_enable();
+		bcops = &r5k_sc_ops;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/tlb-r3k.c linux-2.4.20/arch/mips/mm/tlb-r3k.c
--- linux-2.4.19/arch/mips/mm/tlb-r3k.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/tlb-r3k.c	2002-10-29 11:18:33.000000000 +0000
@@ -20,7 +20,6 @@
 #include <asm/system.h>
 #include <asm/isadep.h>
 #include <asm/io.h>
-#include <asm/wbflush.h>
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
 
@@ -200,12 +199,12 @@
 	unsigned long flags;
 	unsigned long old_ctx;
 	static unsigned long wired = 0;
-	
+
 #ifdef CONFIG_CPU_TX39XX
 	if (r3k_have_wired_reg) {
 		unsigned long old_pagemask;
 		unsigned long w;
-	
+
 #ifdef DEBUG_TLB
 		printk("[tlbwired]");
 		printk("ently lo0 %8x, hi %8x\n, pagemask %8x\n",
@@ -226,7 +225,7 @@
 		set_entryhi(entryhi);
 		set_entrylo0(entrylo0);
 		tlb_write_indexed();
-    
+
 		set_entryhi(old_ctx);
 		set_pagemask (old_pagemask);
 		local_flush_tlb_all();
@@ -244,7 +243,7 @@
 		wired++;
 		tlb_write_indexed();
 		set_entryhi(old_ctx);
-	        local_flush_tlb_all();    
+	        local_flush_tlb_all();
 		__restore_flags(flags);
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/tlb-r4k.c linux-2.4.20/arch/mips/mm/tlb-r4k.c
--- linux-2.4.19/arch/mips/mm/tlb-r4k.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/tlb-r4k.c	2002-10-29 11:18:31.000000000 +0000
@@ -119,12 +119,11 @@
 				idx = get_index();
 				set_entrylo0(0);
 				set_entrylo1(0);
-				set_entryhi(KSEG0);
 				if (idx < 0)
 					continue;
-				BARRIER;
 				/* Make sure all entries differ. */
-				set_entryhi(KSEG0+idx*0x2000);
+				set_entryhi(KSEG0 + idx*0x2000);
+				BARRIER;
 				tlb_write_indexed();
 				BARRIER;
 			}
@@ -271,19 +270,19 @@
 	wired = get_wired();
 	set_wired(wired + 1);
 	set_index(wired);
-	BARRIER;    
+	BARRIER;
 	set_pagemask(pagemask);
 	set_entryhi(entryhi);
 	set_entrylo0(entrylo0);
 	set_entrylo1(entrylo1);
-	BARRIER;    
+	BARRIER;
 	tlb_write_indexed();
-	BARRIER;    
-    
+	BARRIER;
+
 	set_entryhi(old_ctx);
-	BARRIER;    
+	BARRIER;
 	set_pagemask(old_pagemask);
-	local_flush_tlb_all();    
+	local_flush_tlb_all();
 	__restore_flags(flags);
 }
 
@@ -316,17 +315,17 @@
 	}
 
 	set_index(temp_tlb_entry);
-	BARRIER;    
+	BARRIER;
 	set_pagemask(pagemask);
 	set_entryhi(entryhi);
 	set_entrylo0(entrylo0);
 	set_entrylo1(entrylo1);
-	BARRIER;    
+	BARRIER;
 	tlb_write_indexed();
-	BARRIER;    
-    
+	BARRIER;
+
 	set_entryhi(old_ctx);
-	BARRIER;    
+	BARRIER;
 	set_pagemask(old_pagemask);
 out:
 	__restore_flags(flags);
@@ -339,11 +338,11 @@
 
 	prid = read_32bit_cp0_register(CP0_PRID) & 0xff00;
 	if (prid == PRID_IMP_RM7000 || !(config & (1 << 31)))
-		/* 
+		/*
 		 * Not a MIPS32 complianant CPU.  Config 1 register not
 		 * supported, we assume R4k style.  Cpu probing already figured
 		 * out the number of tlb entries.
-		 */  
+		 */
 		return;
 
 	config1 = read_mips32_cp0_config1();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/tlb-sb1.c linux-2.4.20/arch/mips/mm/tlb-sb1.c
--- linux-2.4.19/arch/mips/mm/tlb-sb1.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/tlb-sb1.c	2002-10-29 11:18:48.000000000 +0000
@@ -12,11 +12,11 @@
  * 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.
- */ 
+ */
 #include <linux/config.h>
 #include <asm/mmu_context.h>
 #include <asm/bootinfo.h>
@@ -38,13 +38,13 @@
 		"     tlbr             \n"
 		"     dmfc0  $1, $10   \n"
 		"     dsrl32 %0, $1, 0 \n"
-		"     sra    %1, $1, 0 \n"
+		"     sll    %1, $1, 0 \n"
 		"     dmfc0  $1, $2    \n"
 		"     dsrl32 %2, $1, 0 \n"
-		"     sra    %3, $1, 0 \n"
+		"     sll    %3, $1, 0 \n"
 		"     dmfc0  $1, $3    \n"
 		"     dsrl32 %4, $1, 0 \n"
-		"     sra    %5, $1, 0 \n"
+		"     sll    %5, $1, 0 \n"
 		"     mfc0   %6, $5    \n"
 		".set pop              \n"
 		: "=r" (entryhihi),
@@ -63,7 +63,11 @@
 
 void sb1_dump_tlb(void)
 {
+	unsigned long old_ctx;
+	unsigned long flags;
 	int entry;
+	__save_and_cli(flags);
+	old_ctx = get_entryhi();
 	printk("Current TLB registers state:\n"
 	       "      EntryHi       EntryLo0          EntryLo1     PageMask  Index\n"
 	       "--------------------------------------------------------------------\n");
@@ -83,6 +87,8 @@
 		dump_cur_tlb_regs();
 	}
 	printk("\n");
+	set_entryhi(old_ctx);
+	__restore_flags(flags);
 }
 
 void local_flush_tlb_all(void)
@@ -102,12 +108,12 @@
 		tlb_write_indexed();
 	}
 	set_entryhi(old_ctx);
-	__restore_flags(flags);	
+	__restore_flags(flags);
 }
 
 
 /*
- * Use a bogus region of memory (starting at 0) to sanitize the TLB's.  
+ * Use a bogus region of memory (starting at 0) to sanitize the TLB's.
  * Use increments of the maximum page size (16MB), and check for duplicate
  * entries before doing a given write.  Then, when we're safe from collisions
  * with the firmware, go back and give all the entries invalid addresses with
@@ -209,7 +215,7 @@
 		set_entrylo1(0);
 		if(idx < 0)
 			goto finish;
-		/* Make sure all entries differ. */  
+		/* Make sure all entries differ. */
 		set_entryhi(KSEG0+(idx<<(PAGE_SHIFT+1)));
 		tlb_write_indexed();
 	finish:
@@ -299,7 +305,7 @@
 	/*
 	 * We don't know what state the firmware left the TLB's in, so this is
 	 * the ultra-conservative way to flush the TLB's and avoid machine
-	 * check exceptions due to duplicate TLB entries 
+	 * check exceptions due to duplicate TLB entries
 	 */
 	sb1_sanitize_tlb();
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/tlbex-r3k.S linux-2.4.20/arch/mips/mm/tlbex-r3k.S
--- linux-2.4.19/arch/mips/mm/tlbex-r3k.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/tlbex-r3k.S	2002-10-29 11:18:35.000000000 +0000
@@ -112,7 +112,7 @@
 	.set	push;       \
 	.set	reorder;    \
 	 lw	pte, (ptr); \
-	.set	pop; 
+	.set	pop;
 
 	/* Make PTE valid, store result in PTR. */
 #define PTE_MAKEVALID(pte, ptr) \
@@ -130,7 +130,7 @@
 	.set    reorder;    \
 	lw      pte, (ptr); \
 	.set    pop;
- 
+
 
 	/* Make PTE writable, update software status bits as well,
 	 * then store at PTR.
@@ -160,7 +160,7 @@
 	nop; \
 	jr	reg; \
 	 rfe
-			
+
 	.set	noreorder
 
 	.align	5
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/tlbex-r4k.S linux-2.4.20/arch/mips/mm/tlbex-r4k.S
--- linux-2.4.19/arch/mips/mm/tlbex-r4k.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/tlbex-r4k.S	2002-10-29 11:18:36.000000000 +0000
@@ -56,7 +56,7 @@
 #define GET_PTE_OFF(reg)	srl	reg, reg, 1
 #endif
 
-/*	
+/*
  * These handlers much be written in a relocatable manner
  * because based upon the cpu type an arbitrary one of the
  * following pieces of code will be copied to the KSEG0
@@ -74,9 +74,9 @@
 	sll	k1, 2				# log2(sizeof(pgd_t)
 	addu	k1, k0, k1
 	lw	k1, (k1)
-#else 
+#else
 	lw	k1, pgd_current			# get pgd pointer
-#endif	
+#endif
 	mfc0	k0, CP0_BADVADDR		# Get faulting address
 	srl	k0, k0, _PGDIR_SHIFT		# get pgd only bits
 
@@ -295,29 +295,6 @@
 	END(except_vec0_r4k_MP250MHZhwbug)
 #endif
 
-#ifdef CONFIG_MIPS_AU1000
-	/* TLB refill, EXL == 0, Au1000 version */
-        /* we'll worry about smp later */
-	.set	noreorder
-	.set	noat
-	LEAF(except_vec0_au1000)
-	.set	mips3
-	mfc0	k0, CP0_BADVADDR		# Get faulting address
-	srl	k0, k0, _PGDIR_SHIFT		# get pgd only bits
-	lw	k1, pgd_current			# get pgd pointer
-	sll	k0, k0, 2			# log2(sizeof(pgd_t)
-	addu	k1, k1, k0			# add in pgd offset
-	mfc0	k0, CP0_CONTEXT			# get context reg
-	lw	k1, (k1)
-#ifndef CONFIG_64BIT_PHYS_ADDR
-	srl	k0, k0, 1			# get pte offset
-#endif
-	and	k0, k0, PTEP_INDX_MSK
-	addu	k1, k1, k0			# add in offset
-	j	translate_pte
-	nop
-	END(except_vec0_au1000)
-#endif
 
 
 	__FINIT
@@ -337,7 +314,7 @@
 	srl     ptr, 23;             \
 	sll     ptr, 2;              \
 	addu    ptr, scratch, ptr;   \
-	lw      ptr, (ptr);          
+	lw      ptr, (ptr);
 #else
 #define GET_PGD(scratch, ptr)    \
 	lw	ptr, pgd_current;
@@ -461,7 +438,7 @@
 	 tlbwi
 1:
 	nop
-	.set	mips3	
+	.set	mips3
 	eret
 	.set	mips0
 #endif
@@ -527,184 +504,3 @@
 	DO_FAULT(1)
 	END(handle_mod)
 
-#ifdef CONFIG_MIPS_AU1000
-
-#ifdef CONFIG_MIPS_PB1500
-#define PSEUDO_ADDR_BASE 0x20000000
-#endif
-
-#ifdef CONFIG_MIPS_PB1000
-#define PSEUDO_ADDR_BASE 0xC0000000
-#endif
-
-/*
- * On entry k0 contains the pte with the pseudo address.
- * On exit, k0 contains the "real" address, which is a
- * 36 bit physicall address.
- * This function is called only after it has been 
- * determined that the pte is a pseudo physical address.
- *
- * Destroys k0, k1, and at. It's assumed that the calling
- * function will preserve those.
- */
-LEAF(get_real_pte)
-	.set	mips3
-	.set	at
-
-	li	k1, 0xe0000000          # check lcd 
-	bltu	k0, k1, check_pcmcia_socket_1
-	nop
-	# lcd pseudo access
-	li	k1, 0x0fffffff
-	and	k0, k0, k1              # get offset
-#ifdef CONFIG_MIPS_PB1500
-	lui	k1, 0x1b00
-	addu	k0, k0, k1
-#endif
-	srl	k0, k0, 6
-	lui	k1, 0xe000>>2
-	or	k0, k0, k1
-	j	ra
-	nop
-check_pcmcia_socket_1:
-	li	k1, 0xD0000000
-	bltu	k0, k1, pcmcia_socket_0
-	nop
-	# famous last words, should not happen ...
-1:	
-	b 1b       # fixme -- to something a little more useful
-	# pcmcia socket 1 pseudo access
-
-pcmcia_socket_0:
-	# check mem access
-	li	k1, 0xC8000000
-	bltu	k0, k1, check_attr
-	# handle pseudo memory access
-	li	k1, 0x00ffffff
-	and	k1, k0, k1              # get access offset
-	lui	k0, 0x8000
-	or	k0, k0, k1              
-	# now we have the correct even pte ... bits 31:0
-	srl	k0, k0, 6
-	lui	k1, 0xf000>>2
-	or	k0, k0, k1
-	j	ra                      # done
-	nop
-check_attr:
-	li	k1, 0xC4000000
-	bltu	k0, k1, io_access
-	# handle pseudo attribute access
-	li	k1, 0x00ffffff
-	and	k1, k0, k1              # get access offset
-	lui	k0, 0x4000
-	or	k0, k0, k1              
-	# now we have the correct even pte ... bits 31:0
-	srl	k0, k0, 6
-	lui	k1, 0xf000>>2
-	or	k0, k0, k1
-	j	ra                      # done
-	nop
-io_access:
-#ifdef CONFIG_MIPS_PB1500
-	li	k1, 0xC0000000
-	bltu	k0, k1, pci_access
-#endif
-	# handle pseudo io access
-	li	k1, 0x00ffffff
-	and	k0, k0, k1              # get access offset
-	# now we have the correct even pte ... bits 31:0
-	srl	k0, k0, 6
-	lui	k1, 0xf000>>2
-	or	k0, k0, k1
-	j	ra                      # done
-	nop
-#ifdef CONFIG_MIPS_PB1500
-pci_access:
-	li	k1, 0x80000000
-	bltu	k0, k1, pci_io_access
-	lui	k1, 0x4000>>2
-	# handle pseudo pci mem access
-	srl	k0, k0, 6
-	or	k0, k0, k1
-	j	ra                      # done
-	nop
-pci_io_access:
-	li	k1, 0x70000000
-	bltu	k0, k1, pci_cfg_access
-	lui	k1, 0x5000>>2
-	# handle pseudo pci io access
-	srl	k0, k0, 6
-	or	k0, k0, k1
-	j	ra                      # done
-	nop
-pci_cfg_access:
-	# handle pseudo pci ext cfg access
-	li	k1, 0x0fffffff
-	and	k0, k0, k1              # get access offset
-	srl	k0, k0, 6
-	lui	k1, 0x6000>>2
-	or	k0, k0, k1
-	j	ra                      # done
-	nop
-#endif
-	.set	noat
-END(get_real_pte)
-
-/*
- * On entry k1 contains pte pointer. Clobbers only k0 and k1.
- */
-	LEAF(translate_pte)
-	.set	mips3
-	lui	k0, %hi(__saved_at)
-	.set	noat
-	sw	$at, %lo(__saved_at)(k0)	# save at
-	.set	at
-	sw	k1, %lo(__saved_pte)(k0)	# save pte pointer
-	sw	ra, %lo(__saved_ra)(k0)		# save ra
-	lw	k0, 0(k1)			# get even pte
-
-	li	k1, PSEUDO_ADDR_BASE   		# check pseudo addr
-	bltu	k0, k1, 1f
-	nop
-	bal	get_real_pte
-	nop
-	b	2f
-	nop
-1:
-	srl	k0, k0, 6
-2:
-	mtc0	k0, CP0_ENTRYLO0		# load it
-
-	lui	k1, %hi(__saved_pte)
-	lw	k1, %lo(__saved_pte)(k1)	# recover pte pointer
-	lw	k0, 4(k1)			# get odd pte
-
-	li	k1, PSEUDO_ADDR_BASE   		# check pseudo addr
-	bltu	k0, k1, 1f
-	nop
-	bal	get_real_pte
-	nop
-	b	2f
-	nop
-
-1:
-	srl	k0, k0, 6			# convert to entrylo0
-2:
-	mtc0	k0, CP0_ENTRYLO1		# load it
-	nop
-	b	1f
-	tlbwr					# write random tlb entry
-1:
-	lui	k0, %hi(__saved_at)
-	.set	noat
-	lw	$at, %lo(__saved_at)(k0)	# restore at
-	.set	at
-	lw	ra, %lo(__saved_ra)(k0)		# restore ra
-	eret					# return from trap
-	.set	noat
-	END(translate_pte)
-
-__saved_at:	PTR	0
-__saved_pte:	PTR	0
-__saved_ra:	PTR	0
-#endif	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/mm/umap.c linux-2.4.20/arch/mips/mm/umap.c
--- linux-2.4.19/arch/mips/mm/umap.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/mm/umap.c	2002-10-29 11:18:36.000000000 +0000
@@ -53,7 +53,7 @@
 		address += PAGE_SIZE;
 		pte++;
 	} while (address < end);
-						  
+
 }
 
 static inline void
@@ -80,7 +80,7 @@
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
 	} while (address < end);
-		
+
 }
 
 /*
@@ -138,7 +138,7 @@
 
 /*
  * maps a range of vmalloc()ed memory into the requested pages. the old
- * mappings are removed. 
+ * mappings are removed.
  */
 static inline void
 vmap_pte_range (pte_t *pte, unsigned long address, unsigned long size, unsigned long vaddr)
@@ -147,7 +147,7 @@
 	pgd_t *vdir;
 	pmd_t *vpmd;
 	pte_t *vpte;
-	
+
 	address &= ~PMD_MASK;
 	end = address + size;
 	if (end > PMD_SIZE)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/momentum/ocelot_g/Makefile linux-2.4.20/arch/mips/momentum/ocelot_g/Makefile
--- linux-2.4.19/arch/mips/momentum/ocelot_g/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/momentum/ocelot_g/Makefile	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,20 @@
+#
+# Makefile for Momentum Computer's Ocelot-G board.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+.S.s:
+	$(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+	$(CC) $(CFLAGS) -c $< -o $*.o
+
+O_TARGET:= ocelot_g.o
+
+obj-y	 += gt-irq.o pci-irq.o pci.o int-handler.o irq.o prom.o reset.o setup.o
+
+obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/momentum/ocelot_g/dbg_io.c linux-2.4.20/arch/mips/momentum/ocelot_g/dbg_io.c
--- linux-2.4.19/arch/mips/momentum/ocelot_g/dbg_io.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/momentum/ocelot_g/dbg_io.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,126 @@
+#include <linux/config.h>
+
+#if defined(CONFIG_REMOTE_DEBUG)
+
+#include <asm/serial.h> /* For the serial port location and base baud */
+
+/* --- CONFIG --- */
+
+typedef unsigned char uint8;
+typedef unsigned int uint32;
+
+/* --- END OF CONFIG --- */
+
+#define         UART16550_BAUD_2400             2400
+#define         UART16550_BAUD_4800             4800
+#define         UART16550_BAUD_9600             9600
+#define         UART16550_BAUD_19200            19200
+#define         UART16550_BAUD_38400            38400
+#define         UART16550_BAUD_57600            57600
+#define         UART16550_BAUD_115200           115200
+
+#define         UART16550_PARITY_NONE           0
+#define         UART16550_PARITY_ODD            0x08
+#define         UART16550_PARITY_EVEN           0x18
+#define         UART16550_PARITY_MARK           0x28
+#define         UART16550_PARITY_SPACE          0x38
+
+#define         UART16550_DATA_5BIT             0x0
+#define         UART16550_DATA_6BIT             0x1
+#define         UART16550_DATA_7BIT             0x2
+#define         UART16550_DATA_8BIT             0x3
+
+#define         UART16550_STOP_1BIT             0x0
+#define         UART16550_STOP_2BIT             0x4
+
+/* ----------------------------------------------------- */
+
+/* === CONFIG === */
+
+/* [jsun] we use the second serial port for kdb */
+#define         BASE                    OCELOT_SERIAL1_BASE
+#define         MAX_BAUD                OCELOT_BASE_BAUD
+
+/* === END OF CONFIG === */
+
+#define         REG_OFFSET              4
+
+/* register offset */
+#define         OFS_RCV_BUFFER          0
+#define         OFS_TRANS_HOLD          0
+#define         OFS_SEND_BUFFER         0
+#define         OFS_INTR_ENABLE         (1*REG_OFFSET)
+#define         OFS_INTR_ID             (2*REG_OFFSET)
+#define         OFS_DATA_FORMAT         (3*REG_OFFSET)
+#define         OFS_LINE_CONTROL        (3*REG_OFFSET)
+#define         OFS_MODEM_CONTROL       (4*REG_OFFSET)
+#define         OFS_RS232_OUTPUT        (4*REG_OFFSET)
+#define         OFS_LINE_STATUS         (5*REG_OFFSET)
+#define         OFS_MODEM_STATUS        (6*REG_OFFSET)
+#define         OFS_RS232_INPUT         (6*REG_OFFSET)
+#define         OFS_SCRATCH_PAD         (7*REG_OFFSET)
+
+#define         OFS_DIVISOR_LSB         (0*REG_OFFSET)
+#define         OFS_DIVISOR_MSB         (1*REG_OFFSET)
+
+
+/* memory-mapped read/write of the port */
+#define         UART16550_READ(y)    (*((volatile uint8*)(BASE + y)))
+#define         UART16550_WRITE(y, z)  ((*((volatile uint8*)(BASE + y))) = z)
+
+void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
+{
+	/* disable interrupts */
+	UART16550_WRITE(OFS_INTR_ENABLE, 0);
+
+	/* set up buad rate */
+	{
+		uint32 divisor;
+
+		/* set DIAB bit */
+		UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
+
+		/* set divisor */
+		divisor = MAX_BAUD / baud;
+		UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
+		UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8);
+
+		/* clear DIAB bit */
+		UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
+	}
+
+	/* set data format */
+	UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
+}
+
+static int remoteDebugInitialized = 0;
+
+uint8 getDebugChar(void)
+{
+	if (!remoteDebugInitialized) {
+		remoteDebugInitialized = 1;
+		debugInit(UART16550_BAUD_38400,
+			  UART16550_DATA_8BIT,
+			  UART16550_PARITY_NONE, UART16550_STOP_1BIT);
+	}
+
+	while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
+	return UART16550_READ(OFS_RCV_BUFFER);
+}
+
+
+int putDebugChar(uint8 byte)
+{
+	if (!remoteDebugInitialized) {
+		remoteDebugInitialized = 1;
+		debugInit(UART16550_BAUD_38400,
+			  UART16550_DATA_8BIT,
+			  UART16550_PARITY_NONE, UART16550_STOP_1BIT);
+	}
+
+	while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0);
+	UART16550_WRITE(OFS_SEND_BUFFER, byte);
+	return 1;
+}
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/momentum/ocelot_g/gt-irq.c linux-2.4.20/arch/mips/momentum/ocelot_g/gt-irq.c
--- linux-2.4.19/arch/mips/momentum/ocelot_g/gt-irq.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/momentum/ocelot_g/gt-irq.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,294 @@
+/*
+ *
+ * Copyright 2002 Momentum Computer
+ * Author: mdharm@momenco.com
+ *
+ * arch/mips/momentum/ocelot_g/gt_irq.c
+ *     Interrupt routines for gt64240.  Currently it only handles timer irq.
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <asm/ptrace.h>
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <asm/io.h>
+#include "gt64240.h"
+
+unsigned long bus_clock;
+
+/*
+ * These are interrupt handlers for the GT on-chip interrupts.  They
+ * all come in to the MIPS on a single interrupt line, and have to
+ * be handled and ack'ed differently than other MIPS interrupts.
+ */
+
+#if CURRENTLY_UNUSED
+
+struct tq_struct irq_handlers[MAX_CAUSE_REGS][MAX_CAUSE_REG_WIDTH];
+void hook_irq_handler(int int_cause, int bit_num, void *isr_ptr);
+
+/*
+ * Hooks IRQ handler to the system. When the system is interrupted
+ * the interrupt service routine is called.
+ *
+ * Inputs :
+ * int_cause - The interrupt cause number. In EVB64120 two parameters
+ *             are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH.
+ * bit_num   - Indicates which bit number in the cause register
+ * isr_ptr   - Pointer to the interrupt service routine
+ */
+void hook_irq_handler(int int_cause, int bit_num, void *isr_ptr)
+{
+	irq_handlers[int_cause][bit_num].routine = isr_ptr;
+}
+
+
+/*
+ * Enables the IRQ on Galileo Chip
+ *
+ * Inputs :
+ * int_cause - The interrupt cause number. In EVB64120 two parameters
+ *             are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH.
+ * bit_num   - Indicates which bit number in the cause register
+ *
+ * Outputs :
+ * 1 if succesful, 0 if failure
+ */
+int enable_galileo_irq(int int_cause, int bit_num)
+{
+	if (int_cause == INT_CAUSE_MAIN)
+		SET_REG_BITS(CPU_INTERRUPT_MASK_REGISTER, (1 << bit_num));
+	else if (int_cause == INT_CAUSE_HIGH)
+		SET_REG_BITS(CPU_HIGH_INTERRUPT_MASK_REGISTER,
+			     (1 << bit_num));
+	else
+		return 0;
+
+	return 1;
+}
+
+/*
+ * Disables the IRQ on Galileo Chip
+ *
+ * Inputs :
+ * int_cause - The interrupt cause number. In EVB64120 two parameters
+ *             are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH.
+ * bit_num   - Indicates which bit number in the cause register
+ *
+ * Outputs :
+ * 1 if succesful, 0 if failure
+ */
+int disable_galileo_irq(int int_cause, int bit_num)
+{
+	if (int_cause == INT_CAUSE_MAIN)
+		RESET_REG_BITS(CPU_INTERRUPT_MASK_REGISTER,
+			       (1 << bit_num));
+	else if (int_cause == INT_CAUSE_HIGH)
+		RESET_REG_BITS(CPU_HIGH_INTERRUPT_MASK_REGISTER,
+			       (1 << bit_num));
+	else
+		return 0;
+	return 1;
+}
+#endif				/*  UNUSED  */
+
+/*
+ * Interrupt handler for interrupts coming from the Galileo chip via P0_INT#.
+ *
+ * We route the timer interrupt to P0_INT# (IRQ 6), and that's all this
+ * routine can handle, for now.
+ *
+ * In the future, we'll route more interrupts to this pin, and that's why
+ * we keep this particular structure in the function.
+ */
+
+static void gt64240_p0int_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	uint32_t irq_src, irq_src_mask;
+	int handled;
+
+	/* get the low interrupt cause register */
+	GT_READ(LOW_INTERRUPT_CAUSE_REGISTER, &irq_src);
+
+	/* get the mask register for this pin */
+	GT_READ(PCI_0INTERRUPT_CAUSE_MASK_REGISTER_LOW, &irq_src_mask);
+
+	/* mask off only the interrupts we're interested in */
+	irq_src = irq_src & irq_src_mask;
+
+	handled = 0;
+
+	/* Check for timer interrupt */
+	if (irq_src & 0x00000100) {
+		handled = 1;
+		irq_src &= ~0x00000100;
+
+		/* Clear any pending cause bits */
+		GT_WRITE(TIMER_COUNTER_0_3_INTERRUPT_CAUSE, 0x0);
+
+		/* handle the timer call */
+		do_timer(regs);
+	}
+
+	if (irq_src) {
+		printk(KERN_INFO
+		       "UNKNOWN P0_INT# interrupt received, irq_src=0x%x\n",
+		       irq_src);
+	}
+}
+
+/*
+ * Interrupt handler for interrupts coming from the Galileo chip.
+ * It could be built in ethernet ports etc...
+ */
+static void gt64240_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned int irq_src, int_high_src, irq_src_mask,
+	    int_high_src_mask;
+	int handled;
+
+#if 0
+	GT_READ(GT_INTRCAUSE_OFS, &irq_src);
+	GT_READ(GT_INTRMASK_OFS, &irq_src_mask);
+	GT_READ(GT_HINTRCAUSE_OFS, &int_high_src);
+	GT_READ(GT_HINTRMASK_OFS, &int_high_src_mask);
+#endif
+	irq_src = irq_src & irq_src_mask;
+	int_high_src = int_high_src & int_high_src_mask;
+
+	handled = 0;
+
+	/* Execute all interrupt handlers */
+	/* Check for timer interrupt */
+	if (irq_src & 0x00000800) {
+		handled = 1;
+		irq_src &= ~0x00000800;
+		//    RESET_REG_BITS (INTERRUPT_CAUSE_REGISTER,BIT8);
+		do_timer(regs);
+	}
+
+	if (irq_src) {
+		printk(KERN_INFO
+		       "Other Galileo interrupt received irq_src %x\n",
+		       irq_src);
+#if CURRENTLY_UNUSED
+		for (count = 0; count < MAX_CAUSE_REG_WIDTH; count++) {
+			if (irq_src & (1 << count)) {
+				if (irq_handlers[INT_CAUSE_MAIN][count].
+				    routine) {
+					queue_task(&irq_handlers
+						   [INT_CAUSE_MAIN][count],
+						   &tq_immediate);
+					mark_bh(IMMEDIATE_BH);
+					handled = 1;
+				}
+			}
+		}
+#endif				/*  UNUSED  */
+	}
+#if 0
+	GT_WRITE(GT_INTRCAUSE_OFS, 0);
+	GT_WRITE(GT_HINTRCAUSE_OFS, 0);
+#endif
+
+#undef GALILEO_I2O
+#ifdef GALILEO_I2O
+	/*
+	 * Future I2O support.  We currently attach I2O interrupt handlers to
+	 * the Galileo interrupt (int 4) and handle them in do_IRQ.
+	 */
+	if (isInBoundDoorBellInterruptSet()) {
+		printk(KERN_INFO "I2O doorbell interrupt received.\n");
+		handled = 1;
+	}
+
+	if (isInBoundPostQueueInterruptSet()) {
+		printk(KERN_INFO "I2O Queue interrupt received.\n");
+		handled = 1;
+	}
+
+	/*
+	 * This normally would be outside of the ifdef, but since we're
+	 * handling I2O outside of this handler, this printk shows up every
+	 * time we get a valid I2O interrupt.  So turn this off for now.
+	 */
+	if (handled == 0) {
+		if (counter < 50) {
+			printk("Spurious Galileo interrupt...\n");
+			counter++;
+		}
+	}
+#endif
+}
+
+/*
+ * Initializes timer using galileo's built in timer.
+ */
+
+/*
+ * This will ignore the standard MIPS timer interrupt handler
+ * that is passed in as *irq (=irq0 in ../kernel/time.c).
+ * We will do our own timer interrupt handling.
+ */
+void gt64240_time_init(void)
+{
+	extern irq_desc_t irq_desc[NR_IRQS];
+	static struct irqaction timer;
+
+	/* Stop the timer -- we'll use timer #0 */
+	GT_WRITE(TIMER_COUNTER_0_3_CONTROL, 0x0);
+
+	/* Load timer value for 100 Hz */
+	GT_WRITE(TIMER_COUNTER0, bus_clock / 100);
+
+	/*
+	 * Create the IRQ structure entry for the timer.  Since we're too early
+	 * in the boot process to use the "request_irq()" call, we'll hard-code
+	 * the values to the correct interrupt line.
+	 */
+	timer.handler = &gt64240_p0int_irq;
+	timer.flags = SA_SHIRQ | SA_INTERRUPT;
+	timer.name = "timer";
+	timer.dev_id = NULL;
+	timer.next = NULL;
+	timer.mask = 0;
+	irq_desc[6].action = &timer;
+
+	enable_irq(6);
+
+	/* Clear any pending cause bits */
+	GT_WRITE(TIMER_COUNTER_0_3_INTERRUPT_CAUSE, 0x0);
+
+	/* Enable the interrupt for timer 0 */
+	GT_WRITE(TIMER_COUNTER_0_3_INTERRUPT_MASK, 0x1);
+
+	/* Enable the timer interrupt for GT-64240 pin P0_INT# */
+	GT_WRITE (PCI_0INTERRUPT_CAUSE_MASK_REGISTER_LOW, 0x100);
+
+	/* Configure and start the timer */
+	GT_WRITE(TIMER_COUNTER_0_3_CONTROL, 0x3);
+}
+
+void gt64240_irq_init(void)
+{
+#if CURRENTLY_UNUSED
+	int i, j;
+
+	/* Reset irq handlers pointers to NULL */
+	for (i = 0; i < MAX_CAUSE_REGS; i++) {
+		for (j = 0; j < MAX_CAUSE_REG_WIDTH; j++) {
+			irq_handlers[i][j].next = NULL;
+			irq_handlers[i][j].sync = 0;
+			irq_handlers[i][j].routine = NULL;
+			irq_handlers[i][j].data = NULL;
+		}
+	}
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/momentum/ocelot_g/gt64240.h linux-2.4.20/arch/mips/momentum/ocelot_g/gt64240.h
--- linux-2.4.19/arch/mips/momentum/ocelot_g/gt64240.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/momentum/ocelot_g/gt64240.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,1238 @@
+/* gt64240r.h - GT-64240 Internal registers definition file */
+
+/* Copyright - Galileo technology. */
+
+#ifndef __INCgt64240rh
+#define __INCgt64240rh
+
+#define GTREG(v)        (((v) & 0xff) << 24) | (((v) & 0xff00) << 8) | \
+                        (((v) >> 24) & 0xff) | (((v) >> 8) & 0xff00)
+
+#if 0
+#define GTREG_SHORT(X)	(((X) << 8) | ((X) >> 8))
+
+#define LONG_GTREG(X)	((l64) \
+			(((X)&0x00000000000000ffULL) << 56) | \
+			(((X)&0x000000000000ff00ULL) << 40) | \
+			(((X)&0x0000000000ff0000ULL) << 24) | \
+			(((X)&0x00000000ff000000ULL) << 8)  | \
+			(((X)&0x000000ff00000000ULL) >> 8)  | \
+			(((X)&0x0000ff0000000000ULL) >> 24) | \
+			(((X)&0x00ff000000000000ULL) >> 40) | \
+			(((X)&0xff00000000000000ULL) >> 56))
+#endif
+
+#include "gt64240_dep.h"
+
+/****************************************/
+/* CPU Control Registers		*/
+/****************************************/
+
+#define CPU_CONFIGURATION					0x000
+#define CPU_MODE						0x120
+#define CPU_READ_RESPONSE_CROSSBAR_LOW				0x170
+#define CPU_READ_RESPONSE_CROSSBAR_HIGH				0x178
+
+/****************************************/
+/* Processor Address Space		*/
+/****************************************/
+
+/* Sdram's BAR'S */
+#define SCS_0_LOW_DECODE_ADDRESS				0x008
+#define SCS_0_HIGH_DECODE_ADDRESS				0x010
+#define SCS_1_LOW_DECODE_ADDRESS				0x208
+#define SCS_1_HIGH_DECODE_ADDRESS				0x210
+#define SCS_2_LOW_DECODE_ADDRESS				0x018
+#define SCS_2_HIGH_DECODE_ADDRESS				0x020
+#define SCS_3_LOW_DECODE_ADDRESS				0x218
+#define SCS_3_HIGH_DECODE_ADDRESS				0x220
+/* Devices BAR'S */
+#define CS_0_LOW_DECODE_ADDRESS					0x028
+#define CS_0_HIGH_DECODE_ADDRESS				0x030
+#define CS_1_LOW_DECODE_ADDRESS					0x228
+#define CS_1_HIGH_DECODE_ADDRESS				0x230
+#define CS_2_LOW_DECODE_ADDRESS					0x248
+#define CS_2_HIGH_DECODE_ADDRESS				0x250
+#define CS_3_LOW_DECODE_ADDRESS					0x038
+#define CS_3_HIGH_DECODE_ADDRESS				0x040
+#define BOOTCS_LOW_DECODE_ADDRESS				0x238
+#define BOOTCS_HIGH_DECODE_ADDRESS				0x240
+
+#define PCI_0I_O_LOW_DECODE_ADDRESS				0x048
+#define PCI_0I_O_HIGH_DECODE_ADDRESS				0x050
+#define PCI_0MEMORY0_LOW_DECODE_ADDRESS				0x058
+#define PCI_0MEMORY0_HIGH_DECODE_ADDRESS			0x060
+#define PCI_0MEMORY1_LOW_DECODE_ADDRESS				0x080
+#define PCI_0MEMORY1_HIGH_DECODE_ADDRESS			0x088
+#define PCI_0MEMORY2_LOW_DECODE_ADDRESS				0x258
+#define PCI_0MEMORY2_HIGH_DECODE_ADDRESS			0x260
+#define PCI_0MEMORY3_LOW_DECODE_ADDRESS				0x280
+#define PCI_0MEMORY3_HIGH_DECODE_ADDRESS			0x288
+
+#define PCI_1I_O_LOW_DECODE_ADDRESS				0x090
+#define PCI_1I_O_HIGH_DECODE_ADDRESS				0x098
+#define PCI_1MEMORY0_LOW_DECODE_ADDRESS				0x0a0
+#define PCI_1MEMORY0_HIGH_DECODE_ADDRESS			0x0a8
+#define PCI_1MEMORY1_LOW_DECODE_ADDRESS				0x0b0
+#define PCI_1MEMORY1_HIGH_DECODE_ADDRESS			0x0b8
+#define PCI_1MEMORY2_LOW_DECODE_ADDRESS				0x2a0
+#define PCI_1MEMORY2_HIGH_DECODE_ADDRESS			0x2a8
+#define PCI_1MEMORY3_LOW_DECODE_ADDRESS				0x2b0
+#define PCI_1MEMORY3_HIGH_DECODE_ADDRESS			0x2b8
+
+#define INTERNAL_SPACE_DECODE					0x068
+
+#define CPU_0_LOW_DECODE_ADDRESS                            0x290
+#define CPU_0_HIGH_DECODE_ADDRESS                           0x298
+#define CPU_1_LOW_DECODE_ADDRESS                            0x2c0
+#define CPU_1_HIGH_DECODE_ADDRESS                           0x2c8
+
+#define PCI_0I_O_ADDRESS_REMAP					0x0f0
+#define PCI_0MEMORY0_ADDRESS_REMAP  				0x0f8
+#define PCI_0MEMORY0_HIGH_ADDRESS_REMAP				0x320
+#define PCI_0MEMORY1_ADDRESS_REMAP  				0x100
+#define PCI_0MEMORY1_HIGH_ADDRESS_REMAP				0x328
+#define PCI_0MEMORY2_ADDRESS_REMAP  				0x2f8
+#define PCI_0MEMORY2_HIGH_ADDRESS_REMAP				0x330
+#define PCI_0MEMORY3_ADDRESS_REMAP  			  	0x300
+#define PCI_0MEMORY3_HIGH_ADDRESS_REMAP			   	0x338
+
+#define PCI_1I_O_ADDRESS_REMAP					0x108
+#define PCI_1MEMORY0_ADDRESS_REMAP  				0x110
+#define PCI_1MEMORY0_HIGH_ADDRESS_REMAP				0x340
+#define PCI_1MEMORY1_ADDRESS_REMAP  				0x118
+#define PCI_1MEMORY1_HIGH_ADDRESS_REMAP				0x348
+#define PCI_1MEMORY2_ADDRESS_REMAP  				0x310
+#define PCI_1MEMORY2_HIGH_ADDRESS_REMAP				0x350
+#define PCI_1MEMORY3_ADDRESS_REMAP  				0x318
+#define PCI_1MEMORY3_HIGH_ADDRESS_REMAP				0x358
+
+/****************************************/
+/* CPU Sync Barrier             		*/
+/****************************************/
+
+#define PCI_0SYNC_BARIER_VIRTUAL_REGISTER			0x0c0
+#define PCI_1SYNC_BARIER_VIRTUAL_REGISTER			0x0c8
+
+
+/****************************************/
+/* CPU Access Protect             		*/
+/****************************************/
+
+#define CPU_LOW_PROTECT_ADDRESS_0                           0X180
+#define CPU_HIGH_PROTECT_ADDRESS_0                          0X188
+#define CPU_LOW_PROTECT_ADDRESS_1                           0X190
+#define CPU_HIGH_PROTECT_ADDRESS_1                          0X198
+#define CPU_LOW_PROTECT_ADDRESS_2                           0X1a0
+#define CPU_HIGH_PROTECT_ADDRESS_2                          0X1a8
+#define CPU_LOW_PROTECT_ADDRESS_3                           0X1b0
+#define CPU_HIGH_PROTECT_ADDRESS_3                          0X1b8
+#define CPU_LOW_PROTECT_ADDRESS_4                           0X1c0
+#define CPU_HIGH_PROTECT_ADDRESS_4                          0X1c8
+#define CPU_LOW_PROTECT_ADDRESS_5                           0X1d0
+#define CPU_HIGH_PROTECT_ADDRESS_5                          0X1d8
+#define CPU_LOW_PROTECT_ADDRESS_6                           0X1e0
+#define CPU_HIGH_PROTECT_ADDRESS_6                          0X1e8
+#define CPU_LOW_PROTECT_ADDRESS_7                           0X1f0
+#define CPU_HIGH_PROTECT_ADDRESS_7                          0X1f8
+
+
+/****************************************/
+/*          Snoop Control          		*/
+/****************************************/
+
+#define SNOOP_BASE_ADDRESS_0                                0x380
+#define SNOOP_TOP_ADDRESS_0                                 0x388
+#define SNOOP_BASE_ADDRESS_1                                0x390
+#define SNOOP_TOP_ADDRESS_1                                 0x398
+#define SNOOP_BASE_ADDRESS_2                                0x3a0
+#define SNOOP_TOP_ADDRESS_2                                 0x3a8
+#define SNOOP_BASE_ADDRESS_3                                0x3b0
+#define SNOOP_TOP_ADDRESS_3                                 0x3b8
+
+/****************************************/
+/*          CPU Error Report       		*/
+/****************************************/
+
+#define CPU_ERROR_ADDRESS_LOW 				    0x070
+#define CPU_ERROR_ADDRESS_HIGH 				    0x078
+#define CPU_ERROR_DATA_LOW                                  0x128
+#define CPU_ERROR_DATA_HIGH                                 0x130
+#define CPU_ERROR_PARITY                                    0x138
+#define CPU_ERROR_CAUSE                                     0x140
+#define CPU_ERROR_MASK                                      0x148
+
+/****************************************/
+/*          Pslave Debug           		*/
+/****************************************/
+
+#define X_0_ADDRESS                                         0x360
+#define X_0_COMMAND_ID                                      0x368
+#define X_1_ADDRESS                                         0x370
+#define X_1_COMMAND_ID                                      0x378
+#define WRITE_DATA_LOW                                      0x3c0
+#define WRITE_DATA_HIGH                                     0x3c8
+#define WRITE_BYTE_ENABLE                                   0X3e0
+#define READ_DATA_LOW                                       0x3d0
+#define READ_DATA_HIGH                                      0x3d8
+#define READ_ID                                             0x3e8
+
+
+/****************************************/
+/* SDRAM and Device Address Space	*/
+/****************************************/
+
+
+/****************************************/
+/* SDRAM Configuration			*/
+/****************************************/
+
+#define SDRAM_CONFIGURATION	 			0x448
+#define SDRAM_OPERATION_MODE				0x474
+#define SDRAM_ADDRESS_DECODE				0x47C
+#define SDRAM_TIMING_PARAMETERS                         0x4b4
+#define SDRAM_UMA_CONTROL                               0x4a4
+#define SDRAM_CROSS_BAR_CONTROL_LOW                     0x4a8
+#define SDRAM_CROSS_BAR_CONTROL_HIGH                    0x4ac
+#define SDRAM_CROSS_BAR_TIMEOUT                         0x4b0
+
+
+/****************************************/
+/* SDRAM Parameters			*/
+/****************************************/
+
+#define SDRAM_BANK0PARAMETERS				0x44C
+#define SDRAM_BANK1PARAMETERS				0x450
+#define SDRAM_BANK2PARAMETERS				0x454
+#define SDRAM_BANK3PARAMETERS				0x458
+
+
+/****************************************/
+/* SDRAM Error Report 			*/
+/****************************************/
+
+#define SDRAM_ERROR_DATA_LOW                            0x484
+#define SDRAM_ERROR_DATA_HIGH                           0x480
+#define SDRAM_AND_DEVICE_ERROR_ADDRESS                  0x490
+#define SDRAM_RECEIVED_ECC                              0x488
+#define SDRAM_CALCULATED_ECC                            0x48c
+#define SDRAM_ECC_CONTROL                               0x494
+#define SDRAM_ECC_ERROR_COUNTER                         0x498
+
+
+/****************************************/
+/* SDunit Debug (for internal use)	*/
+/****************************************/
+
+#define X0_ADDRESS                                      0x500
+#define X0_COMMAND_AND_ID                               0x504
+#define X0_WRITE_DATA_LOW                               0x508
+#define X0_WRITE_DATA_HIGH                              0x50c
+#define X0_WRITE_BYTE_ENABLE                            0x518
+#define X0_READ_DATA_LOW                                0x510
+#define X0_READ_DATA_HIGH                               0x514
+#define X0_READ_ID                                      0x51c
+#define X1_ADDRESS                                      0x520
+#define X1_COMMAND_AND_ID                               0x524
+#define X1_WRITE_DATA_LOW                               0x528
+#define X1_WRITE_DATA_HIGH                              0x52c
+#define X1_WRITE_BYTE_ENABLE                            0x538
+#define X1_READ_DATA_LOW                                0x530
+#define X1_READ_DATA_HIGH                               0x534
+#define X1_READ_ID                                      0x53c
+#define X0_SNOOP_ADDRESS                                0x540
+#define X0_SNOOP_COMMAND                                0x544
+#define X1_SNOOP_ADDRESS                                0x548
+#define X1_SNOOP_COMMAND                                0x54c
+
+
+/****************************************/
+/* Device Parameters			*/
+/****************************************/
+
+#define DEVICE_BANK0PARAMETERS				0x45c
+#define DEVICE_BANK1PARAMETERS				0x460
+#define DEVICE_BANK2PARAMETERS				0x464
+#define DEVICE_BANK3PARAMETERS				0x468
+#define DEVICE_BOOT_BANK_PARAMETERS			0x46c
+#define DEVICE_CONTROL                                  0x4c0
+#define DEVICE_CROSS_BAR_CONTROL_LOW                    0x4c8
+#define DEVICE_CROSS_BAR_CONTROL_HIGH                   0x4cc
+#define DEVICE_CROSS_BAR_TIMEOUT                        0x4c4
+
+
+/****************************************/
+/* Device Interrupt 			*/
+/****************************************/
+
+#define DEVICE_INTERRUPT_CAUSE                              0x4d0
+#define DEVICE_INTERRUPT_MASK                               0x4d4
+#define DEVICE_ERROR_ADDRESS                                0x4d8
+
+/****************************************/
+/* DMA Record				*/
+/****************************************/
+
+#define CHANNEL0_DMA_BYTE_COUNT					0x800
+#define CHANNEL1_DMA_BYTE_COUNT	 				0x804
+#define CHANNEL2_DMA_BYTE_COUNT	 				0x808
+#define CHANNEL3_DMA_BYTE_COUNT	 				0x80C
+#define CHANNEL4_DMA_BYTE_COUNT					0x900
+#define CHANNEL5_DMA_BYTE_COUNT	 				0x904
+#define CHANNEL6_DMA_BYTE_COUNT	 				0x908
+#define CHANNEL7_DMA_BYTE_COUNT	 				0x90C
+#define CHANNEL0_DMA_SOURCE_ADDRESS				0x810
+#define CHANNEL1_DMA_SOURCE_ADDRESS				0x814
+#define CHANNEL2_DMA_SOURCE_ADDRESS				0x818
+#define CHANNEL3_DMA_SOURCE_ADDRESS				0x81C
+#define CHANNEL4_DMA_SOURCE_ADDRESS				0x910
+#define CHANNEL5_DMA_SOURCE_ADDRESS				0x914
+#define CHANNEL6_DMA_SOURCE_ADDRESS				0x918
+#define CHANNEL7_DMA_SOURCE_ADDRESS				0x91C
+#define CHANNEL0_DMA_DESTINATION_ADDRESS			0x820
+#define CHANNEL1_DMA_DESTINATION_ADDRESS			0x824
+#define CHANNEL2_DMA_DESTINATION_ADDRESS			0x828
+#define CHANNEL3_DMA_DESTINATION_ADDRESS			0x82C
+#define CHANNEL4_DMA_DESTINATION_ADDRESS			0x920
+#define CHANNEL5_DMA_DESTINATION_ADDRESS			0x924
+#define CHANNEL6_DMA_DESTINATION_ADDRESS			0x928
+#define CHANNEL7_DMA_DESTINATION_ADDRESS			0x92C
+#define CHANNEL0NEXT_RECORD_POINTER				0x830
+#define CHANNEL1NEXT_RECORD_POINTER				0x834
+#define CHANNEL2NEXT_RECORD_POINTER				0x838
+#define CHANNEL3NEXT_RECORD_POINTER				0x83C
+#define CHANNEL4NEXT_RECORD_POINTER				0x930
+#define CHANNEL5NEXT_RECORD_POINTER				0x934
+#define CHANNEL6NEXT_RECORD_POINTER				0x938
+#define CHANNEL7NEXT_RECORD_POINTER				0x93C
+#define CHANNEL0CURRENT_DESCRIPTOR_POINTER			0x870
+#define CHANNEL1CURRENT_DESCRIPTOR_POINTER			0x874
+#define CHANNEL2CURRENT_DESCRIPTOR_POINTER			0x878
+#define CHANNEL3CURRENT_DESCRIPTOR_POINTER			0x87C
+#define CHANNEL4CURRENT_DESCRIPTOR_POINTER			0x970
+#define CHANNEL5CURRENT_DESCRIPTOR_POINTER			0x974
+#define CHANNEL6CURRENT_DESCRIPTOR_POINTER			0x978
+#define CHANNEL7CURRENT_DESCRIPTOR_POINTER			0x97C
+#define CHANNEL0_DMA_SOURCE_HIGH_PCI_ADDRESS			0x890
+#define CHANNEL1_DMA_SOURCE_HIGH_PCI_ADDRESS			0x894
+#define CHANNEL2_DMA_SOURCE_HIGH_PCI_ADDRESS			0x898
+#define CHANNEL3_DMA_SOURCE_HIGH_PCI_ADDRESS			0x89c
+#define CHANNEL4_DMA_SOURCE_HIGH_PCI_ADDRESS			0x990
+#define CHANNEL5_DMA_SOURCE_HIGH_PCI_ADDRESS			0x994
+#define CHANNEL6_DMA_SOURCE_HIGH_PCI_ADDRESS			0x998
+#define CHANNEL7_DMA_SOURCE_HIGH_PCI_ADDRESS			0x99c
+#define CHANNEL0_DMA_DESTINATION_HIGH_PCI_ADDRESS		0x8a0
+#define CHANNEL1_DMA_DESTINATION_HIGH_PCI_ADDRESS		0x8a4
+#define CHANNEL2_DMA_DESTINATION_HIGH_PCI_ADDRESS		0x8a8
+#define CHANNEL3_DMA_DESTINATION_HIGH_PCI_ADDRESS		0x8ac
+#define CHANNEL4_DMA_DESTINATION_HIGH_PCI_ADDRESS		0x9a0
+#define CHANNEL5_DMA_DESTINATION_HIGH_PCI_ADDRESS		0x9a4
+#define CHANNEL6_DMA_DESTINATION_HIGH_PCI_ADDRESS		0x9a8
+#define CHANNEL7_DMA_DESTINATION_HIGH_PCI_ADDRESS		0x9ac
+#define CHANNEL0_DMA_NEXT_RECORD_POINTER_HIGH_PCI_ADDRESS	0x8b0
+#define CHANNEL1_DMA_NEXT_RECORD_POINTER_HIGH_PCI_ADDRESS	0x8b4
+#define CHANNEL2_DMA_NEXT_RECORD_POINTER_HIGH_PCI_ADDRESS	0x8b8
+#define CHANNEL3_DMA_NEXT_RECORD_POINTER_HIGH_PCI_ADDRESS	0x8bc
+#define CHANNEL4_DMA_NEXT_RECORD_POINTER_HIGH_PCI_ADDRESS	0x9b0
+#define CHANNEL5_DMA_NEXT_RECORD_POINTER_HIGH_PCI_ADDRESS	0x9b4
+#define CHANNEL6_DMA_NEXT_RECORD_POINTER_HIGH_PCI_ADDRESS	0x9b8
+#define CHANNEL7_DMA_NEXT_RECORD_POINTER_HIGH_PCI_ADDRESS	0x9bc
+
+/****************************************/
+/* DMA Channel Control			*/
+/****************************************/
+
+#define CHANNEL0CONTROL 					0x840
+#define CHANNEL0CONTROL_HIGH					0x880
+
+#define CHANNEL1CONTROL 					0x844
+#define CHANNEL1CONTROL_HIGH					0x884
+
+#define CHANNEL2CONTROL 					0x848
+#define CHANNEL2CONTROL_HIGH					0x888
+
+#define CHANNEL3CONTROL 					0x84C
+#define CHANNEL3CONTROL_HIGH					0x88C
+
+#define CHANNEL4CONTROL 					0x940
+#define CHANNEL4CONTROL_HIGH					0x980
+
+#define CHANNEL5CONTROL 					0x944
+#define CHANNEL5CONTROL_HIGH					0x984
+
+#define CHANNEL6CONTROL 					0x948
+#define CHANNEL6CONTROL_HIGH					0x988
+
+#define CHANNEL7CONTROL 					0x94C
+#define CHANNEL7CONTROL_HIGH					0x98C
+
+
+/****************************************/
+/* DMA Arbiter				*/
+/****************************************/
+
+#define ARBITER_CONTROL_0_3					0x860
+#define ARBITER_CONTROL_4_7					0x960
+
+
+/****************************************/
+/* DMA Interrupt			*/
+/****************************************/
+
+#define CHANELS0_3_INTERRUPT_CAUSE				0x8c0
+#define CHANELS0_3_INTERRUPT_MASK				0x8c4
+#define CHANELS0_3_ERROR_ADDRESS				0x8c8
+#define CHANELS0_3_ERROR_SELECT					0x8cc
+#define CHANELS4_7_INTERRUPT_CAUSE				0x9c0
+#define CHANELS4_7_INTERRUPT_MASK				0x9c4
+#define CHANELS4_7_ERROR_ADDRESS				0x9c8
+#define CHANELS4_7_ERROR_SELECT					0x9cc
+
+
+/****************************************/
+/* DMA Debug (for internal use)         */
+/****************************************/
+
+#define DMA_X0_ADDRESS                                      0x8e0
+#define DMA_X0_COMMAND_AND_ID                               0x8e4
+#define DMA_X0_WRITE_DATA_LOW                               0x8e8
+#define DMA_X0_WRITE_DATA_HIGH                              0x8ec
+#define DMA_X0_WRITE_BYTE_ENABLE                            0x8f8
+#define DMA_X0_READ_DATA_LOW                                0x8f0
+#define DMA_X0_READ_DATA_HIGH                               0x8f4
+#define DMA_X0_READ_ID                                      0x8fc
+#define DMA_X1_ADDRESS                                      0x9e0
+#define DMA_X1_COMMAND_AND_ID                               0x9e4
+#define DMA_X1_WRITE_DATA_LOW                               0x9e8
+#define DMA_X1_WRITE_DATA_HIGH                              0x9ec
+#define DMA_X1_WRITE_BYTE_ENABLE                            0x9f8
+#define DMA_X1_READ_DATA_LOW                                0x9f0
+#define DMA_X1_READ_DATA_HIGH                               0x9f4
+#define DMA_X1_READ_ID                                      0x9fc
+
+/****************************************/
+/* Timer_Counter 						*/
+/****************************************/
+
+#define TIMER_COUNTER0						0x850
+#define TIMER_COUNTER1						0x854
+#define TIMER_COUNTER2						0x858
+#define TIMER_COUNTER3						0x85C
+#define TIMER_COUNTER_0_3_CONTROL				0x864
+#define TIMER_COUNTER_0_3_INTERRUPT_CAUSE			0x868
+#define TIMER_COUNTER_0_3_INTERRUPT_MASK      			0x86c
+#define TIMER_COUNTER4						0x950
+#define TIMER_COUNTER5						0x954
+#define TIMER_COUNTER6						0x958
+#define TIMER_COUNTER7						0x95C
+#define TIMER_COUNTER_4_7_CONTROL				0x964
+#define TIMER_COUNTER_4_7_INTERRUPT_CAUSE			0x968
+#define TIMER_COUNTER_4_7_INTERRUPT_MASK      			0x96c
+
+/****************************************/
+/* PCI Slave Address Decoding           */
+/****************************************/
+
+#define PCI_0SCS_0_BANK_SIZE					0xc08
+#define PCI_1SCS_0_BANK_SIZE					0xc88
+#define PCI_0SCS_1_BANK_SIZE					0xd08
+#define PCI_1SCS_1_BANK_SIZE					0xd88
+#define PCI_0SCS_2_BANK_SIZE					0xc0c
+#define PCI_1SCS_2_BANK_SIZE					0xc8c
+#define PCI_0SCS_3_BANK_SIZE					0xd0c
+#define PCI_1SCS_3_BANK_SIZE					0xd8c
+#define PCI_0CS_0_BANK_SIZE				    	0xc10
+#define PCI_1CS_0_BANK_SIZE				    	0xc90
+#define PCI_0CS_1_BANK_SIZE				    	0xd10
+#define PCI_1CS_1_BANK_SIZE				    	0xd90
+#define PCI_0CS_2_BANK_SIZE				    	0xd18
+#define PCI_1CS_2_BANK_SIZE				    	0xd98
+#define PCI_0CS_3_BANK_SIZE			       		0xc14
+#define PCI_1CS_3_BANK_SIZE			       		0xc94
+#define PCI_0CS_BOOT_BANK_SIZE					0xd14
+#define PCI_1CS_BOOT_BANK_SIZE					0xd94
+#define PCI_0P2P_MEM0_BAR_SIZE                              0xd1c
+#define PCI_1P2P_MEM0_BAR_SIZE                              0xd9c
+#define PCI_0P2P_MEM1_BAR_SIZE                              0xd20
+#define PCI_1P2P_MEM1_BAR_SIZE                              0xda0
+#define PCI_0P2P_I_O_BAR_SIZE                               0xd24
+#define PCI_1P2P_I_O_BAR_SIZE                               0xda4
+#define PCI_0CPU_BAR_SIZE                                   0xd28
+#define PCI_1CPU_BAR_SIZE                                   0xda8
+#define PCI_0DAC_SCS_0_BANK_SIZE                            0xe00
+#define PCI_1DAC_SCS_0_BANK_SIZE                            0xe80
+#define PCI_0DAC_SCS_1_BANK_SIZE                            0xe04
+#define PCI_1DAC_SCS_1_BANK_SIZE                            0xe84
+#define PCI_0DAC_SCS_2_BANK_SIZE                            0xe08
+#define PCI_1DAC_SCS_2_BANK_SIZE                            0xe88
+#define PCI_0DAC_SCS_3_BANK_SIZE                            0xe0c
+#define PCI_1DAC_SCS_3_BANK_SIZE                            0xe8c
+#define PCI_0DAC_CS_0_BANK_SIZE                             0xe10
+#define PCI_1DAC_CS_0_BANK_SIZE                             0xe90
+#define PCI_0DAC_CS_1_BANK_SIZE                             0xe14
+#define PCI_1DAC_CS_1_BANK_SIZE                             0xe94
+#define PCI_0DAC_CS_2_BANK_SIZE                             0xe18
+#define PCI_1DAC_CS_2_BANK_SIZE                             0xe98
+#define PCI_0DAC_CS_3_BANK_SIZE                             0xe1c
+#define PCI_1DAC_CS_3_BANK_SIZE                             0xe9c
+#define PCI_0DAC_BOOTCS_BANK_SIZE                           0xe20
+#define PCI_1DAC_BOOTCS_BANK_SIZE                           0xea0
+#define PCI_0DAC_P2P_MEM0_BAR_SIZE                          0xe24
+#define PCI_1DAC_P2P_MEM0_BAR_SIZE                          0xea4
+#define PCI_0DAC_P2P_MEM1_BAR_SIZE                          0xe28
+#define PCI_1DAC_P2P_MEM1_BAR_SIZE                          0xea8
+#define PCI_0DAC_CPU_BAR_SIZE                               0xe2c
+#define PCI_1DAC_CPU_BAR_SIZE                               0xeac
+#define PCI_0EXPANSION_ROM_BAR_SIZE                         0xd2c
+#define PCI_1EXPANSION_ROM_BAR_SIZE                         0xdac
+#define PCI_0BASE_ADDRESS_REGISTERS_ENABLE 			0xc3c
+#define PCI_1BASE_ADDRESS_REGISTERS_ENABLE 			0xcbc
+#define PCI_0SCS_0_BASE_ADDRESS_REMAP				0xc48
+#define PCI_1SCS_0_BASE_ADDRESS_REMAP				0xcc8
+#define PCI_0SCS_1_BASE_ADDRESS_REMAP				0xd48
+#define PCI_1SCS_1_BASE_ADDRESS_REMAP				0xdc8
+#define PCI_0SCS_2_BASE_ADDRESS_REMAP				0xc4c
+#define PCI_1SCS_2_BASE_ADDRESS_REMAP				0xccc
+#define PCI_0SCS_3_BASE_ADDRESS_REMAP				0xd4c
+#define PCI_1SCS_3_BASE_ADDRESS_REMAP				0xdcc
+#define PCI_0CS_0_BASE_ADDRESS_REMAP				0xc50
+#define PCI_1CS_0_BASE_ADDRESS_REMAP				0xcd0
+#define PCI_0CS_1_BASE_ADDRESS_REMAP				0xd50
+#define PCI_1CS_1_BASE_ADDRESS_REMAP				0xdd0
+#define PCI_0CS_2_BASE_ADDRESS_REMAP				0xd58
+#define PCI_1CS_2_BASE_ADDRESS_REMAP				0xdd8
+#define PCI_0CS_3_BASE_ADDRESS_REMAP           			0xc54
+#define PCI_1CS_3_BASE_ADDRESS_REMAP           			0xcd4
+#define PCI_0CS_BOOTCS_BASE_ADDRESS_REMAP      			0xd54
+#define PCI_1CS_BOOTCS_BASE_ADDRESS_REMAP      			0xdd4
+#define PCI_0P2P_MEM0_BASE_ADDRESS_REMAP_LOW                0xd5c
+#define PCI_1P2P_MEM0_BASE_ADDRESS_REMAP_LOW                0xddc
+#define PCI_0P2P_MEM0_BASE_ADDRESS_REMAP_HIGH               0xd60
+#define PCI_1P2P_MEM0_BASE_ADDRESS_REMAP_HIGH               0xde0
+#define PCI_0P2P_MEM1_BASE_ADDRESS_REMAP_LOW                0xd64
+#define PCI_1P2P_MEM1_BASE_ADDRESS_REMAP_LOW                0xde4
+#define PCI_0P2P_MEM1_BASE_ADDRESS_REMAP_HIGH               0xd68
+#define PCI_1P2P_MEM1_BASE_ADDRESS_REMAP_HIGH               0xde8
+#define PCI_0P2P_I_O_BASE_ADDRESS_REMAP                     0xd6c
+#define PCI_1P2P_I_O_BASE_ADDRESS_REMAP                     0xdec
+#define PCI_0CPU_BASE_ADDRESS_REMAP                         0xd70
+#define PCI_1CPU_BASE_ADDRESS_REMAP                         0xdf0
+#define PCI_0DAC_SCS_0_BASE_ADDRESS_REMAP                   0xf00
+#define PCI_1DAC_SCS_0_BASE_ADDRESS_REMAP                   0xff0
+#define PCI_0DAC_SCS_1_BASE_ADDRESS_REMAP                   0xf04
+#define PCI_1DAC_SCS_1_BASE_ADDRESS_REMAP                   0xf84
+#define PCI_0DAC_SCS_2_BASE_ADDRESS_REMAP                   0xf08
+#define PCI_1DAC_SCS_2_BASE_ADDRESS_REMAP                   0xf88
+#define PCI_0DAC_SCS_3_BASE_ADDRESS_REMAP                   0xf0c
+#define PCI_1DAC_SCS_3_BASE_ADDRESS_REMAP                   0xf8c
+#define PCI_0DAC_CS_0_BASE_ADDRESS_REMAP                    0xf10
+#define PCI_1DAC_CS_0_BASE_ADDRESS_REMAP                    0xf90
+#define PCI_0DAC_CS_1_BASE_ADDRESS_REMAP                    0xf14
+#define PCI_1DAC_CS_1_BASE_ADDRESS_REMAP                    0xf94
+#define PCI_0DAC_CS_2_BASE_ADDRESS_REMAP                    0xf18
+#define PCI_1DAC_CS_2_BASE_ADDRESS_REMAP                    0xf98
+#define PCI_0DAC_CS_3_BASE_ADDRESS_REMAP                    0xf1c
+#define PCI_1DAC_CS_3_BASE_ADDRESS_REMAP                    0xf9c
+#define PCI_0DAC_BOOTCS_BASE_ADDRESS_REMAP                  0xf20
+#define PCI_1DAC_BOOTCS_BASE_ADDRESS_REMAP                  0xfa0
+#define PCI_0DAC_P2P_MEM0_BASE_ADDRESS_REMAP_LOW            0xf24
+#define PCI_1DAC_P2P_MEM0_BASE_ADDRESS_REMAP_LOW            0xfa4
+#define PCI_0DAC_P2P_MEM0_BASE_ADDRESS_REMAP_HIGH           0xf28
+#define PCI_1DAC_P2P_MEM0_BASE_ADDRESS_REMAP_HIGH           0xfa8
+#define PCI_0DAC_P2P_MEM1_BASE_ADDRESS_REMAP_LOW            0xf2c
+#define PCI_1DAC_P2P_MEM1_BASE_ADDRESS_REMAP_LOW            0xfac
+#define PCI_0DAC_P2P_MEM1_BASE_ADDRESS_REMAP_HIGH           0xf30
+#define PCI_1DAC_P2P_MEM1_BASE_ADDRESS_REMAP_HIGH           0xfb0
+#define PCI_0DAC_CPU_BASE_ADDRESS_REMAP                     0xf34
+#define PCI_1DAC_CPU_BASE_ADDRESS_REMAP                     0xfb4
+#define PCI_0EXPANSION_ROM_BASE_ADDRESS_REMAP               0xf38
+#define PCI_1EXPANSION_ROM_BASE_ADDRESS_REMAP               0xfb8
+#define PCI_0ADDRESS_DECODE_CONTROL                         0xd3c
+#define PCI_1ADDRESS_DECODE_CONTROL                         0xdbc
+
+/****************************************/
+/* PCI Control                          */
+/****************************************/
+
+#define PCI_0COMMAND						0xc00
+#define PCI_1COMMAND						0xc80
+#define PCI_0MODE                                           0xd00
+#define PCI_1MODE                                           0xd80
+#define PCI_0TIMEOUT_RETRY					0xc04
+#define PCI_1TIMEOUT_RETRY					0xc84
+#define PCI_0READ_BUFFER_DISCARD_TIMER                      0xd04
+#define PCI_1READ_BUFFER_DISCARD_TIMER                      0xd84
+#define MSI_0TRIGGER_TIMER                                  0xc38
+#define MSI_1TRIGGER_TIMER                                  0xcb8
+#define PCI_0ARBITER_CONTROL                                0x1d00
+#define PCI_1ARBITER_CONTROL                                0x1d80
+/* changing untill here */
+#define PCI_0CROSS_BAR_CONTROL_LOW                           0x1d08
+#define PCI_0CROSS_BAR_CONTROL_HIGH                          0x1d0c
+#define PCI_0CROSS_BAR_TIMEOUT                               0x1d04
+#define PCI_0READ_RESPONSE_CROSS_BAR_CONTROL_LOW             0x1d18
+#define PCI_0READ_RESPONSE_CROSS_BAR_CONTROL_HIGH            0x1d1c
+#define PCI_0SYNC_BARRIER_VIRTUAL_REGISTER                   0x1d10
+#define PCI_0P2P_CONFIGURATION                               0x1d14
+#define PCI_0ACCESS_CONTROL_BASE_0_LOW                       0x1e00
+#define PCI_0ACCESS_CONTROL_BASE_0_HIGH                      0x1e04
+#define PCI_0ACCESS_CONTROL_TOP_0                            0x1e08
+#define PCI_0ACCESS_CONTROL_BASE_1_LOW                       0c1e10
+#define PCI_0ACCESS_CONTROL_BASE_1_HIGH                      0x1e14
+#define PCI_0ACCESS_CONTROL_TOP_1                            0x1e18
+#define PCI_0ACCESS_CONTROL_BASE_2_LOW                       0c1e20
+#define PCI_0ACCESS_CONTROL_BASE_2_HIGH                      0x1e24
+#define PCI_0ACCESS_CONTROL_TOP_2                            0x1e28
+#define PCI_0ACCESS_CONTROL_BASE_3_LOW                       0c1e30
+#define PCI_0ACCESS_CONTROL_BASE_3_HIGH                      0x1e34
+#define PCI_0ACCESS_CONTROL_TOP_3                            0x1e38
+#define PCI_0ACCESS_CONTROL_BASE_4_LOW                       0c1e40
+#define PCI_0ACCESS_CONTROL_BASE_4_HIGH                      0x1e44
+#define PCI_0ACCESS_CONTROL_TOP_4                            0x1e48
+#define PCI_0ACCESS_CONTROL_BASE_5_LOW                       0c1e50
+#define PCI_0ACCESS_CONTROL_BASE_5_HIGH                      0x1e54
+#define PCI_0ACCESS_CONTROL_TOP_5                            0x1e58
+#define PCI_0ACCESS_CONTROL_BASE_6_LOW                       0c1e60
+#define PCI_0ACCESS_CONTROL_BASE_6_HIGH                      0x1e64
+#define PCI_0ACCESS_CONTROL_TOP_6                            0x1e68
+#define PCI_0ACCESS_CONTROL_BASE_7_LOW                       0c1e70
+#define PCI_0ACCESS_CONTROL_BASE_7_HIGH                      0x1e74
+#define PCI_0ACCESS_CONTROL_TOP_7                            0x1e78
+#define PCI_1CROSS_BAR_CONTROL_LOW                           0x1d88
+#define PCI_1CROSS_BAR_CONTROL_HIGH                          0x1d8c
+#define PCI_1CROSS_BAR_TIMEOUT                               0x1d84
+#define PCI_1READ_RESPONSE_CROSS_BAR_CONTROL_LOW             0x1d98
+#define PCI_1READ_RESPONSE_CROSS_BAR_CONTROL_HIGH            0x1d9c
+#define PCI_1SYNC_BARRIER_VIRTUAL_REGISTER                   0x1d90
+#define PCI_1P2P_CONFIGURATION                               0x1d94
+#define PCI_1ACCESS_CONTROL_BASE_0_LOW                       0x1e80
+#define PCI_1ACCESS_CONTROL_BASE_0_HIGH                      0x1e84
+#define PCI_1ACCESS_CONTROL_TOP_0                            0x1e88
+#define PCI_1ACCESS_CONTROL_BASE_1_LOW                       0c1e90
+#define PCI_1ACCESS_CONTROL_BASE_1_HIGH                      0x1e94
+#define PCI_1ACCESS_CONTROL_TOP_1                            0x1e98
+#define PCI_1ACCESS_CONTROL_BASE_2_LOW                       0c1ea0
+#define PCI_1ACCESS_CONTROL_BASE_2_HIGH                      0x1ea4
+#define PCI_1ACCESS_CONTROL_TOP_2                            0x1ea8
+#define PCI_1ACCESS_CONTROL_BASE_3_LOW                       0c1eb0
+#define PCI_1ACCESS_CONTROL_BASE_3_HIGH                      0x1eb4
+#define PCI_1ACCESS_CONTROL_TOP_3                            0x1eb8
+#define PCI_1ACCESS_CONTROL_BASE_4_LOW                       0c1ec0
+#define PCI_1ACCESS_CONTROL_BASE_4_HIGH                      0x1ec4
+#define PCI_1ACCESS_CONTROL_TOP_4                            0x1ec8
+#define PCI_1ACCESS_CONTROL_BASE_5_LOW                       0c1ed0
+#define PCI_1ACCESS_CONTROL_BASE_5_HIGH                      0x1ed4
+#define PCI_1ACCESS_CONTROL_TOP_5                            0x1ed8
+#define PCI_1ACCESS_CONTROL_BASE_6_LOW                       0c1ee0
+#define PCI_1ACCESS_CONTROL_BASE_6_HIGH                      0x1ee4
+#define PCI_1ACCESS_CONTROL_TOP_6                            0x1ee8
+#define PCI_1ACCESS_CONTROL_BASE_7_LOW                       0c1ef0
+#define PCI_1ACCESS_CONTROL_BASE_7_HIGH                      0x1ef4
+#define PCI_1ACCESS_CONTROL_TOP_7                            0x1ef8
+
+/****************************************/
+/* PCI Snoop Control                    */
+/****************************************/
+
+#define PCI_0SNOOP_CONTROL_BASE_0_LOW                        0x1f00
+#define PCI_0SNOOP_CONTROL_BASE_0_HIGH                       0x1f04
+#define PCI_0SNOOP_CONTROL_TOP_0                             0x1f08
+#define PCI_0SNOOP_CONTROL_BASE_1_0_LOW                      0x1f10
+#define PCI_0SNOOP_CONTROL_BASE_1_0_HIGH                     0x1f14
+#define PCI_0SNOOP_CONTROL_TOP_1                             0x1f18
+#define PCI_0SNOOP_CONTROL_BASE_2_0_LOW                      0x1f20
+#define PCI_0SNOOP_CONTROL_BASE_2_0_HIGH                     0x1f24
+#define PCI_0SNOOP_CONTROL_TOP_2                             0x1f28
+#define PCI_0SNOOP_CONTROL_BASE_3_0_LOW                      0x1f30
+#define PCI_0SNOOP_CONTROL_BASE_3_0_HIGH                     0x1f34
+#define PCI_0SNOOP_CONTROL_TOP_3                             0x1f38
+#define PCI_1SNOOP_CONTROL_BASE_0_LOW                        0x1f80
+#define PCI_1SNOOP_CONTROL_BASE_0_HIGH                       0x1f84
+#define PCI_1SNOOP_CONTROL_TOP_0                             0x1f88
+#define PCI_1SNOOP_CONTROL_BASE_1_0_LOW                      0x1f90
+#define PCI_1SNOOP_CONTROL_BASE_1_0_HIGH                     0x1f94
+#define PCI_1SNOOP_CONTROL_TOP_1                             0x1f98
+#define PCI_1SNOOP_CONTROL_BASE_2_0_LOW                      0x1fa0
+#define PCI_1SNOOP_CONTROL_BASE_2_0_HIGH                     0x1fa4
+#define PCI_1SNOOP_CONTROL_TOP_2                             0x1fa8
+#define PCI_1SNOOP_CONTROL_BASE_3_0_LOW                      0x1fb0
+#define PCI_1SNOOP_CONTROL_BASE_3_0_HIGH                     0x1fb4
+#define PCI_1SNOOP_CONTROL_TOP_3                             0x1fb8
+
+/****************************************/
+/* PCI Configuration Address            */
+/****************************************/
+
+#define PCI_0CONFIGURATION_ADDRESS 				0xcf8
+#define PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER           	0xcfc
+#define PCI_1CONFIGURATION_ADDRESS 				0xc78
+#define PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER           	0xc7c
+#define PCI_0INTERRUPT_ACKNOWLEDGE_VIRTUAL_REGISTER		0xc34
+#define PCI_1INTERRUPT_ACKNOWLEDGE_VIRTUAL_REGISTER		0xcb4
+
+/****************************************/
+/* PCI Error Report                     */
+/****************************************/
+
+#define PCI_0SERR_MASK						 0xc28
+#define PCI_0ERROR_ADDRESS_LOW                               0x1d40
+#define PCI_0ERROR_ADDRESS_HIGH                              0x1d44
+#define PCI_0ERROR_DATA_LOW                                  0x1d48
+#define PCI_0ERROR_DATA_HIGH                                 0x1d4c
+#define PCI_0ERROR_COMMAND                                   0x1d50
+#define PCI_0ERROR_CAUSE                                     0x1d58
+#define PCI_0ERROR_MASK                                      0x1d5c
+
+#define PCI_1SERR_MASK						 0xca8
+#define PCI_1ERROR_ADDRESS_LOW                               0x1dc0
+#define PCI_1ERROR_ADDRESS_HIGH                              0x1dc4
+#define PCI_1ERROR_DATA_LOW                                  0x1dc8
+#define PCI_1ERROR_DATA_HIGH                                 0x1dcc
+#define PCI_1ERROR_COMMAND                                   0x1dd0
+#define PCI_1ERROR_CAUSE                                     0x1dd8
+#define PCI_1ERROR_MASK                                      0x1ddc
+
+
+/****************************************/
+/* Lslave Debug  (for internal use)     */
+/****************************************/
+
+#define L_SLAVE_X0_ADDRESS                                  0x1d20
+#define L_SLAVE_X0_COMMAND_AND_ID                           0x1d24
+#define L_SLAVE_X1_ADDRESS                                  0x1d28
+#define L_SLAVE_X1_COMMAND_AND_ID                           0x1d2c
+#define L_SLAVE_WRITE_DATA_LOW                              0x1d30
+#define L_SLAVE_WRITE_DATA_HIGH                             0x1d34
+#define L_SLAVE_WRITE_BYTE_ENABLE                           0x1d60
+#define L_SLAVE_READ_DATA_LOW                               0x1d38
+#define L_SLAVE_READ_DATA_HIGH                              0x1d3c
+#define L_SLAVE_READ_ID                                     0x1d64
+
+/****************************************/
+/* PCI Configuration Function 0         */
+/****************************************/
+
+#define PCI_DEVICE_AND_VENDOR_ID 				0x000
+#define PCI_STATUS_AND_COMMAND					0x004
+#define PCI_CLASS_CODE_AND_REVISION_ID			        0x008
+#define PCI_BIST_HEADER_TYPE_LATENCY_TIMER_CACHE_LINE 		0x00C
+#define PCI_SCS_0_BASE_ADDRESS	    				0x010
+#define PCI_SCS_1_BASE_ADDRESS 					0x014
+#define PCI_SCS_2_BASE_ADDRESS 					0x018
+#define PCI_SCS_3_BASE_ADDRESS      				0x01C
+#define PCI_INTERNAL_REGISTERS_MEMORY_MAPPED_BASE_ADDRESS	0x020
+#define PCI_INTERNAL_REGISTERS_I_OMAPPED_BASE_ADDRESS		0x024
+#define PCI_SUBSYSTEM_ID_AND_SUBSYSTEM_VENDOR_ID		0x02C
+#define PCI_EXPANSION_ROM_BASE_ADDRESS_REGISTER			0x030
+#define PCI_CAPABILTY_LIST_POINTER                          0x034
+#define PCI_INTERRUPT_PIN_AND_LINE 			    0x03C
+#define PCI_POWER_MANAGEMENT_CAPABILITY                     0x040
+#define PCI_POWER_MANAGEMENT_STATUS_AND_CONTROL             0x044
+#define PCI_VPD_ADDRESS                                     0x048
+#define PCI_VPD_DATA                                        0X04c
+#define PCI_MSI_MESSAGE_CONTROL                             0x050
+#define PCI_MSI_MESSAGE_ADDRESS                             0x054
+#define PCI_MSI_MESSAGE_UPPER_ADDRESS                       0x058
+#define PCI_MSI_MESSAGE_DATA                                0x05c
+#define PCI_COMPACT_PCI_HOT_SWAP_CAPABILITY                 0x058
+
+/****************************************/
+/* PCI Configuration Function 1         */
+/****************************************/
+
+#define PCI_CS_0_BASE_ADDRESS	    				0x110
+#define PCI_CS_1_BASE_ADDRESS 					0x114
+#define PCI_CS_2_BASE_ADDRESS 					0x118
+#define PCI_CS_3_BASE_ADDRESS     				0x11c
+#define PCI_BOOTCS_BASE_ADDRESS                     	    0x120
+
+/****************************************/
+/* PCI Configuration Function 2         */
+/****************************************/
+
+#define PCI_P2P_MEM0_BASE_ADDRESS	    			0x210
+#define PCI_P2P_MEM1_BASE_ADDRESS 				0x214
+#define PCI_P2P_I_O_BASE_ADDRESS 				0x218
+#define PCI_CPU_BASE_ADDRESS      				0x21c
+
+/****************************************/
+/* PCI Configuration Function 4         */
+/****************************************/
+
+#define PCI_DAC_SCS_0_BASE_ADDRESS_LOW 				0x410
+#define PCI_DAC_SCS_0_BASE_ADDRESS_HIGH			 	0x414
+#define PCI_DAC_SCS_1_BASE_ADDRESS_LOW   			0x418
+#define PCI_DAC_SCS_1_BASE_ADDRESS_HIGH  		    0x41c
+#define PCI_DAC_P2P_MEM0_BASE_ADDRESS_LOW              	    0x420
+#define PCI_DAC_P2P_MEM0_BASE_ADDRESS_HIGH             	    0x424
+
+
+/****************************************/
+/* PCI Configuration Function 5         */
+/****************************************/
+
+#define PCI_DAC_SCS_2_BASE_ADDRESS_LOW 				0x510
+#define PCI_DAC_SCS_2_BASE_ADDRESS_HIGH				0x514
+#define PCI_DAC_SCS_3_BASE_ADDRESS_LOW   		 	0x518
+#define PCI_DAC_SCS_3_BASE_ADDRESS_HIGH  		 	0x51c
+#define PCI_DAC_P2P_MEM1_BASE_ADDRESS_LOW              	    0x520
+#define PCI_DAC_P2P_MEM1_BASE_ADDRESS_HIGH             	    0x524
+
+
+/****************************************/
+/* PCI Configuration Function 6         */
+/****************************************/
+
+#define PCI_DAC_CS_0_BASE_ADDRESS_LOW 				0x610
+#define PCI_DAC_CS_0_BASE_ADDRESS_HIGH				0x614
+#define PCI_DAC_CS_1_BASE_ADDRESS_LOW   			0x618
+#define PCI_DAC_CS_1_BASE_ADDRESS_HIGH  			0x61c
+#define PCI_DAC_CS_2_BASE_ADDRESS_LOW            	        0x620
+#define PCI_DAC_CS_2_BASE_ADDRESS_HIGH           	        0x624
+
+/****************************************/
+/* PCI Configuration Function 7         */
+/****************************************/
+
+#define PCI_DAC_CS_3_BASE_ADDRESS_LOW 				0x710
+#define PCI_DAC_CS_3_BASE_ADDRESS_HIGH			 	0x714
+#define PCI_DAC_BOOTCS_BASE_ADDRESS_LOW   		 	0x718
+#define PCI_DAC_BOOTCS_BASE_ADDRESS_HIGH  			0x71c
+#define PCI_DAC_CPU_BASE_ADDRESS_LOW            	        0x720
+#define PCI_DAC_CPU_BASE_ADDRESS_HIGH           	        0x724
+
+/****************************************/
+/* Interrupts	  			*/
+/****************************************/
+
+#define LOW_INTERRUPT_CAUSE_REGISTER   				0xc18
+#define HIGH_INTERRUPT_CAUSE_REGISTER				0xc68
+#define CPU_INTERRUPT_MASK_REGISTER_LOW				0xc1c
+#define CPU_INTERRUPT_MASK_REGISTER_HIGH			0xc6c
+#define CPU_SELECT_CAUSE_REGISTER				0xc70
+#define PCI_0INTERRUPT_CAUSE_MASK_REGISTER_LOW			0xc24
+#define PCI_0INTERRUPT_CAUSE_MASK_REGISTER_HIGH			0xc64
+#define PCI_0SELECT_CAUSE                                   0xc74
+#define PCI_1INTERRUPT_CAUSE_MASK_REGISTER_LOW			0xca4
+#define PCI_1INTERRUPT_CAUSE_MASK_REGISTER_HIGH			0xce4
+#define PCI_1SELECT_CAUSE                                   0xcf4
+#define CPU_INT_0_MASK                                      0xe60
+#define CPU_INT_1_MASK                                      0xe64
+#define CPU_INT_2_MASK                                      0xe68
+#define CPU_INT_3_MASK                                      0xe6c
+
+/****************************************/
+/* I20 Support registers		*/
+/****************************************/
+
+#define INBOUND_MESSAGE_REGISTER0_PCI0_SIDE			0x010
+#define INBOUND_MESSAGE_REGISTER1_PCI0_SIDE  			0x014
+#define OUTBOUND_MESSAGE_REGISTER0_PCI0_SIDE 			0x018
+#define OUTBOUND_MESSAGE_REGISTER1_PCI0_SIDE  			0x01C
+#define INBOUND_DOORBELL_REGISTER_PCI0_SIDE  			0x020
+#define INBOUND_INTERRUPT_CAUSE_REGISTER_PCI0_SIDE  		0x024
+#define INBOUND_INTERRUPT_MASK_REGISTER_PCI0_SIDE		0x028
+#define OUTBOUND_DOORBELL_REGISTER_PCI0_SIDE 			0x02C
+#define OUTBOUND_INTERRUPT_CAUSE_REGISTER_PCI0_SIDE   		0x030
+#define OUTBOUND_INTERRUPT_MASK_REGISTER_PCI0_SIDE   		0x034
+#define INBOUND_QUEUE_PORT_VIRTUAL_REGISTER_PCI0_SIDE  		0x040
+#define OUTBOUND_QUEUE_PORT_VIRTUAL_REGISTER_PCI0_SIDE   	0x044
+#define QUEUE_CONTROL_REGISTER_PCI0_SIDE 			0x050
+#define QUEUE_BASE_ADDRESS_REGISTER_PCI0_SIDE 			0x054
+#define INBOUND_FREE_HEAD_POINTER_REGISTER_PCI0_SIDE		0x060
+#define INBOUND_FREE_TAIL_POINTER_REGISTER_PCI0_SIDE  		0x064
+#define INBOUND_POST_HEAD_POINTER_REGISTER_PCI0_SIDE 		0x068
+#define INBOUND_POST_TAIL_POINTER_REGISTER_PCI0_SIDE 		0x06C
+#define OUTBOUND_FREE_HEAD_POINTER_REGISTER_PCI0_SIDE		0x070
+#define OUTBOUND_FREE_TAIL_POINTER_REGISTER_PCI0_SIDE		0x074
+#define OUTBOUND_POST_HEAD_POINTER_REGISTER_PCI0_SIDE		0x0F8
+#define OUTBOUND_POST_TAIL_POINTER_REGISTER_PCI0_SIDE		0x0FC
+
+#define INBOUND_MESSAGE_REGISTER0_PCI1_SIDE				0x090
+#define INBOUND_MESSAGE_REGISTER1_PCI1_SIDE  				0x094
+#define OUTBOUND_MESSAGE_REGISTER0_PCI1_SIDE 				0x098
+#define OUTBOUND_MESSAGE_REGISTER1_PCI1_SIDE  				0x09C
+#define INBOUND_DOORBELL_REGISTER_PCI1_SIDE  				0x0A0
+#define INBOUND_INTERRUPT_CAUSE_REGISTER_PCI1_SIDE  		0x0A4
+#define INBOUND_INTERRUPT_MASK_REGISTER_PCI1_SIDE			0x0A8
+#define OUTBOUND_DOORBELL_REGISTER_PCI1_SIDE 				0x0AC
+#define OUTBOUND_INTERRUPT_CAUSE_REGISTER_PCI1_SIDE   		0x0B0
+#define OUTBOUND_INTERRUPT_MASK_REGISTER_PCI1_SIDE   		0x0B4
+#define INBOUND_QUEUE_PORT_VIRTUAL_REGISTER_PCI1_SIDE  		0x0C0
+#define OUTBOUND_QUEUE_PORT_VIRTUAL_REGISTER_PCI1_SIDE   	0x0C4
+#define QUEUE_CONTROL_REGISTER_PCI1_SIDE 				0x0D0
+#define QUEUE_BASE_ADDRESS_REGISTER_PCI1_SIDE 				0x0D4
+#define INBOUND_FREE_HEAD_POINTER_REGISTER_PCI1_SIDE		0x0E0
+#define INBOUND_FREE_TAIL_POINTER_REGISTER_PCI1_SIDE  		0x0E4
+#define INBOUND_POST_HEAD_POINTER_REGISTER_PCI1_SIDE 		0x0E8
+#define INBOUND_POST_TAIL_POINTER_REGISTER_PCI1_SIDE 		0x0EC
+#define OUTBOUND_FREE_HEAD_POINTER_REGISTER_PCI1_SIDE		0x0F0
+#define OUTBOUND_FREE_TAIL_POINTER_REGISTER_PCI1_SIDE		0x0F4
+#define OUTBOUND_POST_HEAD_POINTER_REGISTER_PCI1_SIDE		0x078
+#define OUTBOUND_POST_TAIL_POINTER_REGISTER_PCI1_SIDE		0x07C
+
+#define INBOUND_MESSAGE_REGISTER0_CPU0_SIDE				0X1C10
+#define INBOUND_MESSAGE_REGISTER1_CPU0_SIDE  				0X1C14
+#define OUTBOUND_MESSAGE_REGISTER0_CPU0_SIDE 				0X1C18
+#define OUTBOUND_MESSAGE_REGISTER1_CPU0_SIDE  				0X1C1C
+#define INBOUND_DOORBELL_REGISTER_CPU0_SIDE  				0X1C20
+#define INBOUND_INTERRUPT_CAUSE_REGISTER_CPU0_SIDE  		0X1C24
+#define INBOUND_INTERRUPT_MASK_REGISTER_CPU0_SIDE			0X1C28
+#define OUTBOUND_DOORBELL_REGISTER_CPU0_SIDE 				0X1C2C
+#define OUTBOUND_INTERRUPT_CAUSE_REGISTER_CPU0_SIDE   		0X1C30
+#define OUTBOUND_INTERRUPT_MASK_REGISTER_CPU0_SIDE   		0X1C34
+#define INBOUND_QUEUE_PORT_VIRTUAL_REGISTER_CPU0_SIDE  		0X1C40
+#define OUTBOUND_QUEUE_PORT_VIRTUAL_REGISTER_CPU0_SIDE   	0X1C44
+#define QUEUE_CONTROL_REGISTER_CPU0_SIDE 				0X1C50
+#define QUEUE_BASE_ADDRESS_REGISTER_CPU0_SIDE 				0X1C54
+#define INBOUND_FREE_HEAD_POINTER_REGISTER_CPU0_SIDE		0X1C60
+#define INBOUND_FREE_TAIL_POINTER_REGISTER_CPU0_SIDE  		0X1C64
+#define INBOUND_POST_HEAD_POINTER_REGISTER_CPU0_SIDE 		0X1C68
+#define INBOUND_POST_TAIL_POINTER_REGISTER_CPU0_SIDE 		0X1C6C
+#define OUTBOUND_FREE_HEAD_POINTER_REGISTER_CPU0_SIDE		0X1C70
+#define OUTBOUND_FREE_TAIL_POINTER_REGISTER_CPU0_SIDE		0X1C74
+#define OUTBOUND_POST_HEAD_POINTER_REGISTER_CPU0_SIDE		0X1CF8
+#define OUTBOUND_POST_TAIL_POINTER_REGISTER_CPU0_SIDE		0X1CFC
+
+#define INBOUND_MESSAGE_REGISTER0_CPU1_SIDE				0X1C90
+#define INBOUND_MESSAGE_REGISTER1_CPU1_SIDE  				0X1C94
+#define OUTBOUND_MESSAGE_REGISTER0_CPU1_SIDE 				0X1C98
+#define OUTBOUND_MESSAGE_REGISTER1_CPU1_SIDE  				0X1C9C
+#define INBOUND_DOORBELL_REGISTER_CPU1_SIDE  				0X1CA0
+#define INBOUND_INTERRUPT_CAUSE_REGISTER_CPU1_SIDE  		0X1CA4
+#define INBOUND_INTERRUPT_MASK_REGISTER_CPU1_SIDE			0X1CA8
+#define OUTBOUND_DOORBELL_REGISTER_CPU1_SIDE 				0X1CAC
+#define OUTBOUND_INTERRUPT_CAUSE_REGISTER_CPU1_SIDE   		0X1CB0
+#define OUTBOUND_INTERRUPT_MASK_REGISTER_CPU1_SIDE   		0X1CB4
+#define INBOUND_QUEUE_PORT_VIRTUAL_REGISTER_CPU1_SIDE  		0X1CC0
+#define OUTBOUND_QUEUE_PORT_VIRTUAL_REGISTER_CPU1_SIDE   	0X1CC4
+#define QUEUE_CONTROL_REGISTER_CPU1_SIDE 				0X1CD0
+#define QUEUE_BASE_ADDRESS_REGISTER_CPU1_SIDE 				0X1CD4
+#define INBOUND_FREE_HEAD_POINTER_REGISTER_CPU1_SIDE		0X1CE0
+#define INBOUND_FREE_TAIL_POINTER_REGISTER_CPU1_SIDE  		0X1CE4
+#define INBOUND_POST_HEAD_POINTER_REGISTER_CPU1_SIDE 		0X1CE8
+#define INBOUND_POST_TAIL_POINTER_REGISTER_CPU1_SIDE 		0X1CEC
+#define OUTBOUND_FREE_HEAD_POINTER_REGISTER_CPU1_SIDE		0X1CF0
+#define OUTBOUND_FREE_TAIL_POINTER_REGISTER_CPU1_SIDE		0X1CF4
+#define OUTBOUND_POST_HEAD_POINTER_REGISTER_CPU1_SIDE		0X1C78
+#define OUTBOUND_POST_TAIL_POINTER_REGISTER_CPU1_SIDE		0X1C7C
+
+/****************************************/
+/* Communication Unit Registers         */
+/****************************************/
+
+#define ETHERNET_0_ADDRESS_CONTROL_LOW
+#define ETHERNET_0_ADDRESS_CONTROL_HIGH                     0xf204
+#define ETHERNET_0_RECEIVE_BUFFER_PCI_HIGH_ADDRESS          0xf208
+#define ETHERNET_0_TRANSMIT_BUFFER_PCI_HIGH_ADDRESS         0xf20c
+#define ETHERNET_0_RECEIVE_DESCRIPTOR_PCI_HIGH_ADDRESS      0xf210
+#define ETHERNET_0_TRANSMIT_DESCRIPTOR_PCI_HIGH_ADDRESS     0xf214
+#define ETHERNET_0_HASH_TABLE_PCI_HIGH_ADDRESS              0xf218
+#define ETHERNET_1_ADDRESS_CONTROL_LOW                      0xf220
+#define ETHERNET_1_ADDRESS_CONTROL_HIGH                     0xf224
+#define ETHERNET_1_RECEIVE_BUFFER_PCI_HIGH_ADDRESS          0xf228
+#define ETHERNET_1_TRANSMIT_BUFFER_PCI_HIGH_ADDRESS         0xf22c
+#define ETHERNET_1_RECEIVE_DESCRIPTOR_PCI_HIGH_ADDRESS      0xf230
+#define ETHERNET_1_TRANSMIT_DESCRIPTOR_PCI_HIGH_ADDRESS     0xf234
+#define ETHERNET_1_HASH_TABLE_PCI_HIGH_ADDRESS              0xf238
+#define ETHERNET_2_ADDRESS_CONTROL_LOW                      0xf240
+#define ETHERNET_2_ADDRESS_CONTROL_HIGH                     0xf244
+#define ETHERNET_2_RECEIVE_BUFFER_PCI_HIGH_ADDRESS          0xf248
+#define ETHERNET_2_TRANSMIT_BUFFER_PCI_HIGH_ADDRESS         0xf24c
+#define ETHERNET_2_RECEIVE_DESCRIPTOR_PCI_HIGH_ADDRESS      0xf250
+#define ETHERNET_2_TRANSMIT_DESCRIPTOR_PCI_HIGH_ADDRESS     0xf254
+#define ETHERNET_2_HASH_TABLE_PCI_HIGH_ADDRESS              0xf258
+#define MPSC_0_ADDRESS_CONTROL_LOW                          0xf280
+#define MPSC_0_ADDRESS_CONTROL_HIGH                         0xf284
+#define MPSC_0_RECEIVE_BUFFER_PCI_HIGH_ADDRESS              0xf288
+#define MPSC_0_TRANSMIT_BUFFER_PCI_HIGH_ADDRESS             0xf28c
+#define MPSC_0_RECEIVE_DESCRIPTOR_PCI_HIGH_ADDRESS          0xf290
+#define MPSC_0_TRANSMIT_DESCRIPTOR_PCI_HIGH_ADDRESS         0xf294
+#define MPSC_1_ADDRESS_CONTROL_LOW                          0xf2a0
+#define MPSC_1_ADDRESS_CONTROL_HIGH                         0xf2a4
+#define MPSC_1_RECEIVE_BUFFER_PCI_HIGH_ADDRESS              0xf2a8
+#define MPSC_1_TRANSMIT_BUFFER_PCI_HIGH_ADDRESS             0xf2ac
+#define MPSC_1_RECEIVE_DESCRIPTOR_PCI_HIGH_ADDRESS          0xf2b0
+#define MPSC_1_TRANSMIT_DESCRIPTOR_PCI_HIGH_ADDRESS         0xf2b4
+#define MPSC_2_ADDRESS_CONTROL_LOW                          0xf2c0
+#define MPSC_2_ADDRESS_CONTROL_HIGH                         0xf2c4
+#define MPSC_2_RECEIVE_BUFFER_PCI_HIGH_ADDRESS              0xf2c8
+#define MPSC_2_TRANSMIT_BUFFER_PCI_HIGH_ADDRESS             0xf2cc
+#define MPSC_2_RECEIVE_DESCRIPTOR_PCI_HIGH_ADDRESS          0xf2d0
+#define MPSC_2_TRANSMIT_DESCRIPTOR_PCI_HIGH_ADDRESS         0xf2d4
+#define SERIAL_INIT_PCI_HIGH_ADDRESS                        0xf320
+#define SERIAL_INIT_LAST_DATA                               0xf324
+#define SERIAL_INIT_STATUS_AND_CONTROL                      0xf328
+#define COMM_UNIT_ARBITER_CONTROL                           0xf300
+#define COMM_UNIT_CROSS_BAR_TIMEOUT                         0xf304
+#define COMM_UNIT_INTERRUPT_CAUSE                           0xf310
+#define COMM_UNIT_INTERRUPT_MASK                            0xf314
+#define COMM_UNIT_ERROR_ADDRESS                             0xf314
+
+/****************************************/
+/* Cunit Debug  (for internal use)     */
+/****************************************/
+
+#define CUNIT_ADDRESS                                       0xf340
+#define CUNIT_COMMAND_AND_ID                                0xf344
+#define CUNIT_WRITE_DATA_LOW                                0xf348
+#define CUNIT_WRITE_DATA_HIGH                               0xf34c
+#define CUNIT_WRITE_BYTE_ENABLE                             0xf358
+#define CUNIT_READ_DATA_LOW                                 0xf350
+#define CUNIT_READ_DATA_HIGH                                0xf354
+#define CUNIT_READ_ID                                       0xf35c
+
+/****************************************/
+/* Fast Ethernet Unit Registers         */
+/****************************************/
+
+/* Ethernet */
+
+#define ETHERNET_PHY_ADDRESS_REGISTER                       0x2000
+#define ETHERNET_SMI_REGISTER                               0x2010
+
+/* Ethernet 0 */
+
+#define ETHERNET0_PORT_CONFIGURATION_REGISTER               0x2400
+#define ETHERNET0_PORT_CONFIGURATION_EXTEND_REGISTER        0x2408
+#define ETHERNET0_PORT_COMMAND_REGISTER                     0x2410
+#define ETHERNET0_PORT_STATUS_REGISTER                      0x2418
+#define ETHERNET0_SERIAL_PARAMETRS_REGISTER                 0x2420
+#define ETHERNET0_HASH_TABLE_POINTER_REGISTER               0x2428
+#define ETHERNET0_FLOW_CONTROL_SOURCE_ADDRESS_LOW           0x2430
+#define ETHERNET0_FLOW_CONTROL_SOURCE_ADDRESS_HIGH          0x2438
+#define ETHERNET0_SDMA_CONFIGURATION_REGISTER               0x2440
+#define ETHERNET0_SDMA_COMMAND_REGISTER                     0x2448
+#define ETHERNET0_INTERRUPT_CAUSE_REGISTER                  0x2450
+#define ETHERNET0_INTERRUPT_MASK_REGISTER                   0x2458
+#define ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER0              0x2480
+#define ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER1              0x2484
+#define ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER2              0x2488
+#define ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER3              0x248c
+#define ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER0            0x24a0
+#define ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER1            0x24a4
+#define ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER2            0x24a8
+#define ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER3            0x24ac
+#define ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER0            0x24e0
+#define ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER1            0x24e4
+#define ETHERNET0_MIB_COUNTER_BASE                          0x2500
+
+/* Ethernet 1 */
+
+#define ETHERNET1_PORT_CONFIGURATION_REGISTER               0x2800
+#define ETHERNET1_PORT_CONFIGURATION_EXTEND_REGISTER        0x2808
+#define ETHERNET1_PORT_COMMAND_REGISTER                     0x2810
+#define ETHERNET1_PORT_STATUS_REGISTER                      0x2818
+#define ETHERNET1_SERIAL_PARAMETRS_REGISTER                 0x2820
+#define ETHERNET1_HASH_TABLE_POINTER_REGISTER               0x2828
+#define ETHERNET1_FLOW_CONTROL_SOURCE_ADDRESS_LOW           0x2830
+#define ETHERNET1_FLOW_CONTROL_SOURCE_ADDRESS_HIGH          0x2838
+#define ETHERNET1_SDMA_CONFIGURATION_REGISTER               0x2840
+#define ETHERNET1_SDMA_COMMAND_REGISTER                     0x2848
+#define ETHERNET1_INTERRUPT_CAUSE_REGISTER                  0x2850
+#define ETHERNET1_INTERRUPT_MASK_REGISTER                   0x2858
+#define ETHERNET1_FIRST_RX_DESCRIPTOR_POINTER0              0x2880
+#define ETHERNET1_FIRST_RX_DESCRIPTOR_POINTER1              0x2884
+#define ETHERNET1_FIRST_RX_DESCRIPTOR_POINTER2              0x2888
+#define ETHERNET1_FIRST_RX_DESCRIPTOR_POINTER3              0x288c
+#define ETHERNET1_CURRENT_RX_DESCRIPTOR_POINTER0            0x28a0
+#define ETHERNET1_CURRENT_RX_DESCRIPTOR_POINTER1            0x28a4
+#define ETHERNET1_CURRENT_RX_DESCRIPTOR_POINTER2            0x28a8
+#define ETHERNET1_CURRENT_RX_DESCRIPTOR_POINTER3            0x28ac
+#define ETHERNET1_CURRENT_TX_DESCRIPTOR_POINTER0            0x28e0
+#define ETHERNET1_CURRENT_TX_DESCRIPTOR_POINTER1            0x28e4
+#define ETHERNET1_MIB_COUNTER_BASE                          0x2900
+
+/* Ethernet 2 */
+
+#define ETHERNET2_PORT_CONFIGURATION_REGISTER               0x2c00
+#define ETHERNET2_PORT_CONFIGURATION_EXTEND_REGISTER        0x2c08
+#define ETHERNET2_PORT_COMMAND_REGISTER                     0x2c10
+#define ETHERNET2_PORT_STATUS_REGISTER                      0x2c18
+#define ETHERNET2_SERIAL_PARAMETRS_REGISTER                 0x2c20
+#define ETHERNET2_HASH_TABLE_POINTER_REGISTER               0x2c28
+#define ETHERNET2_FLOW_CONTROL_SOURCE_ADDRESS_LOW           0x2c30
+#define ETHERNET2_FLOW_CONTROL_SOURCE_ADDRESS_HIGH          0x2c38
+#define ETHERNET2_SDMA_CONFIGURATION_REGISTER               0x2c40
+#define ETHERNET2_SDMA_COMMAND_REGISTER                     0x2c48
+#define ETHERNET2_INTERRUPT_CAUSE_REGISTER                  0x2c50
+#define ETHERNET2_INTERRUPT_MASK_REGISTER                   0x2c58
+#define ETHERNET2_FIRST_RX_DESCRIPTOR_POINTER0              0x2c80
+#define ETHERNET2_FIRST_RX_DESCRIPTOR_POINTER1              0x2c84
+#define ETHERNET2_FIRST_RX_DESCRIPTOR_POINTER2              0x2c88
+#define ETHERNET2_FIRST_RX_DESCRIPTOR_POINTER3              0x2c8c
+#define ETHERNET2_CURRENT_RX_DESCRIPTOR_POINTER0            0x2ca0
+#define ETHERNET2_CURRENT_RX_DESCRIPTOR_POINTER1            0x2ca4
+#define ETHERNET2_CURRENT_RX_DESCRIPTOR_POINTER2            0x2ca8
+#define ETHERNET2_CURRENT_RX_DESCRIPTOR_POINTER3            0x2cac
+#define ETHERNET2_CURRENT_TX_DESCRIPTOR_POINTER0            0x2ce0
+#define ETHERNET2_CURRENT_TX_DESCRIPTOR_POINTER1            0x2ce4
+#define ETHERNET2_MIB_COUNTER_BASE                          0x2d00
+
+/****************************************/
+/* SDMA Registers                       */
+/****************************************/
+
+#define SDMA_GROUP_CONFIGURATION_REGISTER                   0xb1f0
+#define CHANNEL0_CONFIGURATION_REGISTER                     0x4000
+#define CHANNEL0_COMMAND_REGISTER                           0x4008
+#define CHANNEL0_RX_CMD_STATUS                              0x4800
+#define CHANNEL0_RX_PACKET_AND_BUFFER_SIZES                 0x4804
+#define CHANNEL0_RX_BUFFER_POINTER                          0x4808
+#define CHANNEL0_RX_NEXT_POINTER                            0x480c
+#define CHANNEL0_CURRENT_RX_DESCRIPTOR_POINTER              0x4810
+#define CHANNEL0_TX_CMD_STATUS                              0x4C00
+#define CHANNEL0_TX_PACKET_SIZE                             0x4C04
+#define CHANNEL0_TX_BUFFER_POINTER                          0x4C08
+#define CHANNEL0_TX_NEXT_POINTER                            0x4C0c
+#define CHANNEL0_CURRENT_TX_DESCRIPTOR_POINTER              0x4c10
+#define CHANNEL0_FIRST_TX_DESCRIPTOR_POINTER                0x4c14
+#define CHANNEL1_CONFIGURATION_REGISTER                     0x6000
+#define CHANNEL1_COMMAND_REGISTER                           0x6008
+#define CHANNEL1_RX_CMD_STATUS                              0x6800
+#define CHANNEL1_RX_PACKET_AND_BUFFER_SIZES                 0x6804
+#define CHANNEL1_RX_BUFFER_POINTER                          0x6808
+#define CHANNEL1_RX_NEXT_POINTER                            0x680c
+#define CHANNEL1_CURRENT_RX_DESCRIPTOR_POINTER              0x6810
+#define CHANNEL1_TX_CMD_STATUS                              0x6C00
+#define CHANNEL1_TX_PACKET_SIZE                             0x6C04
+#define CHANNEL1_TX_BUFFER_POINTER                          0x6C08
+#define CHANNEL1_TX_NEXT_POINTER                            0x6C0c
+#define CHANNEL1_CURRENT_RX_DESCRIPTOR_POINTER              0x6810
+#define CHANNEL1_CURRENT_TX_DESCRIPTOR_POINTER              0x6c10
+#define CHANNEL1_FIRST_TX_DESCRIPTOR_POINTER                0x6c14
+
+/* SDMA Interrupt */
+
+#define SDMA_CAUSE                                          0xb820
+#define SDMA_MASK                                           0xb8a0
+
+
+/****************************************/
+/* Baude Rate Generators Registers      */
+/****************************************/
+
+/* BRG 0 */
+
+#define BRG0_CONFIGURATION_REGISTER                         0xb200
+#define BRG0_BAUDE_TUNING_REGISTER                          0xb204
+
+/* BRG 1 */
+
+#define BRG1_CONFIGURATION_REGISTER                         0xb208
+#define BRG1_BAUDE_TUNING_REGISTER                          0xb20c
+
+/* BRG 2 */
+
+#define BRG2_CONFIGURATION_REGISTER                         0xb210
+#define BRG2_BAUDE_TUNING_REGISTER                          0xb214
+
+/* BRG Interrupts */
+
+#define BRG_CAUSE_REGISTER                                  0xb834
+#define BRG_MASK_REGISTER                                   0xb8b4
+
+/* MISC */
+
+#define MAIN_ROUTING_REGISTER                               0xb400
+#define RECEIVE_CLOCK_ROUTING_REGISTER                      0xb404
+#define TRANSMIT_CLOCK_ROUTING_REGISTER                     0xb408
+#define COMM_UNIT_ARBITER_CONFIGURATION_REGISTER            0xb40c
+#define WATCHDOG_CONFIGURATION_REGISTER                     0xb410
+#define WATCHDOG_VALUE_REGISTER                             0xb414
+
+
+/****************************************/
+/* Flex TDM Registers                   */
+/****************************************/
+
+/* FTDM Port */
+
+#define FLEXTDM_TRANSMIT_READ_POINTER                       0xa800
+#define FLEXTDM_RECEIVE_READ_POINTER                        0xa804
+#define FLEXTDM_CONFIGURATION_REGISTER                      0xa808
+#define FLEXTDM_AUX_CHANNELA_TX_REGISTER                    0xa80c
+#define FLEXTDM_AUX_CHANNELA_RX_REGISTER                    0xa810
+#define FLEXTDM_AUX_CHANNELB_TX_REGISTER                    0xa814
+#define FLEXTDM_AUX_CHANNELB_RX_REGISTER                    0xa818
+
+/* FTDM Interrupts */
+
+#define FTDM_CAUSE_REGISTER                                 0xb830
+#define FTDM_MASK_REGISTER                                  0xb8b0
+
+
+/****************************************/
+/* GPP Interface Registers              */
+/****************************************/
+
+#define GPP_IO_CONTROL                                      0xf100
+#define GPP_LEVEL_CONTROL                                   0xf110
+#define GPP_VALUE                                           0xf104
+#define GPP_INTERRUPT_CAUSE                                 0xf108
+#define GPP_INTERRUPT_MASK                                  0xf10c
+
+#define MPP_CONTROL0                                        0xf000
+#define MPP_CONTROL1                                        0xf004
+#define MPP_CONTROL2                                        0xf008
+#define MPP_CONTROL3                                        0xf00c
+#define DEBUG_PORT_MULTIPLEX                                0xf014
+#define SERIAL_PORT_MULTIPLEX                               0xf010
+
+/****************************************/
+/* I2C Registers                        */
+/****************************************/
+
+#define I2C_SLAVE_ADDRESS                                   0xc000
+#define I2C_EXTENDED_SLAVE_ADDRESS                          0xc040
+#define I2C_DATA                                            0xc004
+#define I2C_CONTROL                                         0xc008
+#define I2C_STATUS_BAUDE_RATE                               0xc00C
+#define I2C_SOFT_RESET                                      0xc01c
+
+/****************************************/
+/* MPSC Registers                       */
+/****************************************/
+
+/* MPSC0  */
+
+#define MPSC0_MAIN_CONFIGURATION_LOW                        0x8000
+#define MPSC0_MAIN_CONFIGURATION_HIGH                       0x8004
+#define MPSC0_PROTOCOL_CONFIGURATION                        0x8008
+#define CHANNEL0_REGISTER1                                  0x800c
+#define CHANNEL0_REGISTER2                                  0x8010
+#define CHANNEL0_REGISTER3                                  0x8014
+#define CHANNEL0_REGISTER4                                  0x8018
+#define CHANNEL0_REGISTER5                                  0x801c
+#define CHANNEL0_REGISTER6                                  0x8020
+#define CHANNEL0_REGISTER7                                  0x8024
+#define CHANNEL0_REGISTER8                                  0x8028
+#define CHANNEL0_REGISTER9                                  0x802c
+#define CHANNEL0_REGISTER10                                 0x8030
+#define CHANNEL0_REGISTER11                                 0x8034
+
+/* MPSC1  */
+
+#define MPSC1_MAIN_CONFIGURATION_LOW                        0x9000
+#define MPSC1_MAIN_CONFIGURATION_HIGH                       0x9004
+#define MPSC1_PROTOCOL_CONFIGURATION                        0x9008
+#define CHANNEL1_REGISTER1                                  0x900c
+#define CHANNEL1_REGISTER2                                  0x9010
+#define CHANNEL1_REGISTER3                                  0x9014
+#define CHANNEL1_REGISTER4                                  0x9018
+#define CHANNEL1_REGISTER5                                  0x901c
+#define CHANNEL1_REGISTER6                                  0x9020
+#define CHANNEL1_REGISTER7                                  0x9024
+#define CHANNEL1_REGISTER8                                  0x9028
+#define CHANNEL1_REGISTER9                                  0x902c
+#define CHANNEL1_REGISTER10                                 0x9030
+#define CHANNEL1_REGISTER11                                 0x9034
+
+/* MPSCs Interupts  */
+
+#define MPSC0_CAUSE                                         0xb804
+#define MPSC0_MASK                                          0xb884
+#define MPSC1_CAUSE                                         0xb80c
+#define MPSC1_MASK                                          0xb88c
+
+#endif /* __INCgt64240rh */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/momentum/ocelot_g/gt64240_dep.h linux-2.4.20/arch/mips/momentum/ocelot_g/gt64240_dep.h
--- linux-2.4.19/arch/mips/momentum/ocelot_g/gt64240_dep.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/momentum/ocelot_g/gt64240_dep.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,57 @@
+/***********************************************************************
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * arch/mips/gt64240/gt64240-dep.h
+ *     Board-dependent definitions for GT-64120 chip.
+ *
+ * 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.
+ ***********************************************************************
+ */
+
+#ifndef _ASM_GT64240_DEP_H
+#define _ASM_GT64240_DEP_H
+
+#include <asm/addrspace.h>		/* for KSEG1ADDR() */
+#include <asm/byteorder.h>		/* for cpu_to_le32() */
+
+/*
+ * PCI address allocation
+ */
+#if 0
+#define GT_PCI_MEM_BASE    (0x22000000)
+#define GT_PCI_MEM_SIZE    GT_DEF_PCI0_MEM0_SIZE
+#define GT_PCI_IO_BASE     (0x20000000)
+#define GT_PCI_IO_SIZE     GT_DEF_PCI0_IO_SIZE
+#endif
+
+extern unsigned long gt64240_base;
+
+#define GT64240_BASE       (gt64240_base)
+
+/*
+ * Because of an error/peculiarity in the Galileo chip, we need to swap the
+ * bytes when running bigendian.
+ */
+
+#define GT_WRITE(ofs, data)  \
+        *(volatile u32 *)(GT64240_BASE+(ofs)) = cpu_to_le32(data)
+#define GT_READ(ofs, data)   \
+        *(data) = le32_to_cpu(*(volatile u32 *)(GT64240_BASE+(ofs)))
+#define GT_READ_DATA(ofs)    \
+        le32_to_cpu(*(volatile u32 *)(GT64240_BASE+(ofs)))
+
+#define GT_WRITE_16(ofs, data)  \
+        *(volatile u16 *)(GT64240_BASE+(ofs)) = cpu_to_le16(data)
+#define GT_READ_16(ofs, data)   \
+        *(data) = le16_to_cpu(*(volatile u16 *)(GT64240_BASE+(ofs)))
+
+#define GT_WRITE_8(ofs, data)  \
+        *(volatile u8 *)(GT64240_BASE+(ofs)) = data
+#define GT_READ_8(ofs, data)   \
+        *(data) = *(volatile u8 *)(GT64240_BASE+(ofs))
+
+#endif  /* _ASM_GT64120_MOMENCO_OCELOT_GT64120_DEP_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/momentum/ocelot_g/int-handler.S linux-2.4.20/arch/mips/momentum/ocelot_g/int-handler.S
--- linux-2.4.19/arch/mips/momentum/ocelot_g/int-handler.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/momentum/ocelot_g/int-handler.S	2002-10-29 11:18:51.000000000 +0000
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ *
+ * First-level interrupt dispatcher for ocelot board.
+ *
+ * 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.
+ */
+#define __ASSEMBLY__
+#include <linux/config.h>
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+/*
+ * first level interrupt dispatcher for ocelot board -
+ * We check for the timer first, then check PCI ints A and D.
+ * Then check for serial IRQ and fall through.
+ */
+		.align	5
+		NESTED(ocelot_handle_int, PT_SIZE, sp)
+		SAVE_ALL
+		CLI
+		.set	at
+		mfc0	t0, CP0_CAUSE
+		mfc0	t2, CP0_STATUS
+
+		and	t0, t2
+
+		 andi	t1, t0, STATUSF_IP2	/* int0 hardware line */
+		bnez	t1, ll_pri_enet_irq
+		 andi	t1, t0, STATUSF_IP3	/* int1 hardware line */
+		bnez	t1, ll_sec_enet_irq
+		 andi	t1, t0, STATUSF_IP4	/* int2 hardware line */
+		bnez	t1, ll_uart_irq
+		 andi	t1, t0, STATUSF_IP5	/* int3 hardware line */
+		bnez	t1, ll_cpci_irq
+		 andi	t1, t0, STATUSF_IP6	/* int4 hardware line */
+		bnez	t1, ll_galileo_p0_irq
+		 andi	t1, t0, STATUSF_IP7	/* cpu timer */
+		bnez	t1, ll_cputimer_irq
+
+                /* now look at the extended interrupts */
+		mfc0	t0, CP0_CAUSE
+		cfc0	t1, CP0_S1_INTCONTROL
+
+		/* shift the mask 8 bits left to line up the bits */
+		 sll	t2, t1, 8
+
+		 and	t0, t2
+		 srl	t0, t0, 16
+
+		 andi	t1, t0, STATUSF_IP8	/* int6 hardware line */
+		bnez	t1, ll_galileo_p1_irq
+		 andi	t1, t0, STATUSF_IP9	/* int7 hardware line */
+		bnez	t1, ll_pmc_irq
+		 andi	t1, t0, STATUSF_IP10	/* int8 hardware line */
+		bnez	t1, ll_cpci_abcd_irq
+		 andi	t1, t0, STATUSF_IP11	/* int9 hardware line */
+		bnez	t1, ll_testpoint_irq
+
+		.set	reorder
+
+		/* wrong alarm or masked ... */
+		j	spurious_interrupt
+		nop
+		END(ocelot_handle_int)
+
+		.align	5
+ll_pri_enet_irq:
+		li	a0, 2
+		move	a1, sp
+		jal	do_IRQ
+		j	ret_from_irq
+
+ll_sec_enet_irq:
+		li	a0, 3
+		move	a1, sp
+		jal	do_IRQ
+		j	ret_from_irq
+
+ll_uart_irq:
+		li	a0, 4
+		move	a1, sp
+		jal	do_IRQ
+		j	ret_from_irq
+
+ll_cpci_irq:
+		li	a0, 5
+		move	a1, sp
+		jal	do_IRQ
+		j	ret_from_irq
+
+ll_galileo_p0_irq:
+		li	a0, 6
+		move	a1, sp
+		jal	do_IRQ
+		j	ret_from_irq
+
+ll_cputimer_irq:
+		li	a0, 7
+		move	a1, sp
+		jal	do_IRQ
+		j	ret_from_irq
+
+ll_galileo_p1_irq:
+		li	a0, 8
+		move	a1, sp
+		jal	do_IRQ
+		j	ret_from_irq
+
+ll_pmc_irq:
+		li	a0, 9
+		move	a1, sp
+		jal	do_IRQ
+		j	ret_from_irq
+
+ll_cpci_abcd_irq:
+		li	a0, 10
+		move	a1, sp
+		jal	do_IRQ
+		j	ret_from_irq
+
+ll_testpoint_irq:
+		li	a0, 11
+		move	a1, sp
+		jal	do_IRQ
+		j	ret_from_irq
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/momentum/ocelot_g/irq.c linux-2.4.20/arch/mips/momentum/ocelot_g/irq.c
--- linux-2.4.19/arch/mips/momentum/ocelot_g/irq.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/momentum/ocelot_g/irq.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2000 RidgeRun, Inc.
+ * Author: RidgeRun, Inc.
+ *   glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ * Copyright (C) 2000, 2001 Ralf Baechle (ralf@gnu.org)
+ *
+ *  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.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <asm/bitops.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+
+
+static spinlock_t rm7000_irq_lock = SPIN_LOCK_UNLOCKED;
+
+/* Function for careful CP0 interrupt mask access */
+static inline void modify_cp0_intmask(unsigned clr_mask_in, unsigned set_mask_in)
+{
+	unsigned long status;
+	unsigned clr_mask;
+	unsigned set_mask;
+
+	/* do the low 8 bits first */
+	clr_mask = 0xff & clr_mask_in;
+	set_mask = 0xff & set_mask_in;
+	status = read_32bit_cp0_register(CP0_STATUS);
+	status &= ~((clr_mask & 0xFF) << 8);
+	status |= (set_mask & 0xFF) << 8;
+	write_32bit_cp0_register(CP0_STATUS, status);
+
+	/* do the high 8 bits */
+	clr_mask = 0xff & (clr_mask_in >> 8);
+	set_mask = 0xff & (set_mask_in >> 8);
+	status = read_32bit_cp0_set1_register(CP0_S1_INTCONTROL);
+	status &= ~((clr_mask & 0xFF) << 8);
+	status |= (set_mask & 0xFF) << 8;
+	write_32bit_cp0_set1_register(CP0_S1_INTCONTROL, status);
+}
+
+static inline void mask_irq(unsigned int irq)
+{
+	modify_cp0_intmask(irq, 0);
+}
+
+static inline void unmask_irq(unsigned int irq)
+{
+	modify_cp0_intmask(0, irq);
+}
+
+static void enable_cp7000_irq(unsigned int irq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&rm7000_irq_lock, flags);
+	unmask_irq(1 << irq);
+	spin_unlock_irqrestore(&rm7000_irq_lock, flags);
+}
+
+static unsigned int startup_cp7000_irq(unsigned int irq)
+{
+	enable_cp7000_irq(irq);
+
+	return 0;				/* never anything pending */
+}
+
+static void disable_cp7000_irq(unsigned int irq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&rm7000_irq_lock, flags);
+	mask_irq(1 << irq);
+	spin_unlock_irqrestore(&rm7000_irq_lock, flags);
+}
+
+#define shutdown_cp7000_irq disable_cp7000_irq
+
+static void mask_and_ack_cp7000_irq(unsigned int irq)
+{
+	mask_irq(1 << irq);
+}
+
+static void end_cp7000_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		unmask_irq(1 << irq);
+}
+
+static struct hw_interrupt_type cp7000_hpcdma_irq_type = {
+	"CP7000",
+	startup_cp7000_irq,
+	shutdown_cp7000_irq,
+	enable_cp7000_irq,
+	disable_cp7000_irq,
+	mask_and_ack_cp7000_irq,
+	end_cp7000_irq,
+	NULL
+};
+
+
+extern asmlinkage void ocelot_handle_int(void);
+extern void gt64240_irq_init(void);
+
+void __init init_IRQ(void)
+{
+	int i;
+
+	/*
+	 * Clear all of the interrupts while we change the able around a bit.
+	 * int-handler is not on bootstrap
+	 */
+	clear_cp0_status(ST0_IM | ST0_BEV);
+	__cli();
+
+	/* Sets the first-level interrupt dispatcher. */
+	set_except_vector(0, ocelot_handle_int);
+	init_generic_irq();
+
+	for (i = 0; i <= 15; i++) {
+		irq_desc[i].status	= IRQ_DISABLED;
+		irq_desc[i].action	= 0;
+		irq_desc[i].depth	= 1;
+		irq_desc[i].handler	= &cp7000_hpcdma_irq_type;
+	}
+
+	gt64240_irq_init();
+
+#ifdef CONFIG_REMOTE_DEBUG
+	printk("start kgdb ...\n");
+	set_debug_traps();
+	breakpoint();	/* you may move this line to whereever you want :-) */
+#endif
+#ifdef CONFIG_GDB_CONSOLE
+	register_gdb_console();
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/momentum/ocelot_g/ocelot_pld.h linux-2.4.20/arch/mips/momentum/ocelot_g/ocelot_pld.h
--- linux-2.4.19/arch/mips/momentum/ocelot_g/ocelot_pld.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/momentum/ocelot_g/ocelot_pld.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,34 @@
+/*
+ * Ocelot Board Register Definitions
+ *
+ * (C) 2001 Red Hat, Inc.
+ *
+ * GPL'd
+ */
+#ifndef __MOMENCO_OCELOT_PLD_H__
+#define __MOMENCO_OCELOT_PLD_H__
+
+#if 0
+#define OCELOT_CS0_ADDR (0xe0020000)
+#else
+#define OCELOT_CS0_ADDR (0xfc000000)
+#endif
+
+#define OCELOT_REG_BOARDREV (0)
+#define OCELOT_REG_PLD1_ID (1)
+#define OCELOT_REG_PLD2_ID (2)
+#define OCELOT_REG_RESET_STATUS (3)
+#define OCELOT_REG_BOARD_STATUS (4)
+#define OCELOT_REG_CPCI_ID (5)
+#define OCELOT_REG_I2C_CTRL (8)
+#define OCELOT_REG_EEPROM_MODE (9)
+#define OCELOT_REG_INTMASK (10)
+#define OCELOT_REG_INTSTATUS (11)
+#define OCELOT_REG_INTSET (12)
+#define OCELOT_REG_INTCLR (13)
+
+#define OCELOT_PLD_WRITE(x, y) writeb(x, OCELOT_CS0_ADDR + OCELOT_REG_##y)
+#define OCELOT_PLD_READ(x) readb(OCELOT_CS0_ADDR + OCELOT_REG_##x)
+
+
+#endif /* __MOMENCO_OCELOT_PLD_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/momentum/ocelot_g/pci-irq.c linux-2.4.20/arch/mips/momentum/ocelot_g/pci-irq.c
--- linux-2.4.19/arch/mips/momentum/ocelot_g/pci-irq.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/momentum/ocelot_g/pci-irq.c	2002-10-29 11:18:51.000000000 +0000
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2002 Momentum Computer Inc.
+ * Author: Matthew Dharm <mdharm@momenco.com>
+ *
+ * Based on work for the Linux port to the Ocelot board, which is
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * arch/mips/momentum/ocelot_g/pci.c
+ *     Board-specific PCI routines for gt64240 controller.
+ *
+ * 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.
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <asm/pci.h>
+
+
+void __init gt64240_board_pcibios_fixup_bus(struct pci_bus *bus)
+{
+	struct pci_bus *current_bus = bus;
+	struct pci_dev *devices;
+	struct list_head *devices_link;
+	u16 cmd;
+
+	/* loop over all known devices on this bus */
+	list_for_each(devices_link, &(current_bus->devices)) {
+
+		devices = pci_dev_b(devices_link);
+		if (devices == NULL)
+			continue;
+
+		if ((current_bus->number == 0) &&
+				PCI_SLOT(devices->devfn) == 1) {
+			/* Intel 82543 Gigabit MAC */
+			devices->irq = 2;       /* irq_nr is 2 for INT0 */
+		} else if ((current_bus->number == 0) &&
+				PCI_SLOT(devices->devfn) == 2) {
+			/* Intel 82543 Gigabit MAC */
+			devices->irq = 3;       /* irq_nr is 3 for INT1 */
+		} else if ((current_bus->number == 1) &&
+				PCI_SLOT(devices->devfn) == 3) {
+			/* Intel 21555 bridge */
+			devices->irq = 5;       /* irq_nr is 8 for INT6 */
+		} else if ((current_bus->number == 1) &&
+				PCI_SLOT(devices->devfn) == 4) {
+			/* PMC Slot */
+			devices->irq = 9;       /* irq_nr is 9 for INT7 */
+		} else {
+			/* We don't have assign interrupts for other devices. */
+			devices->irq = 0xff;
+		}
+
+		/* Assign an interrupt number for the device */
+		bus->ops->write_byte(devices, PCI_INTERRUPT_LINE, devices->irq);
+
+		/* enable master for everything but the GT-64240 */
+		if (((current_bus->number != 0) && (current_bus->number != 1))
+				|| (PCI_SLOT(devices->devfn) != 0)) {
+			bus->ops->read_word(devices, PCI_COMMAND, &cmd);
+			cmd |= PCI_COMMAND_MASTER;
+			bus->ops->write_word(devices, PCI_COMMAND, cmd);
+		}
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/momentum/ocelot_g/pci.c linux-2.4.20/arch/mips/momentum/ocelot_g/pci.c
--- linux-2.4.19/arch/mips/momentum/ocelot_g/pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/momentum/ocelot_g/pci.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,568 @@
+/*
+ * Copyright 2002 Momentum Computer
+ * Author: Matthew Dharm <mdharm@momenco.com>
+ *
+ *  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.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <asm/pci.h>
+#include <asm/io.h>
+#include "gt64240.h"
+
+#include <linux/init.h>
+
+#ifdef CONFIG_PCI
+
+#define SELF 0
+#define MASTER_ABORT_BIT 0x100
+
+/*
+ * These functions and structures provide the BIOS scan and mapping of the PCI
+ * devices.
+ */
+
+#define MAX_PCI_DEVS 10
+
+void gt64240_board_pcibios_fixup_bus(struct pci_bus* c);
+
+/*  Functions to implement "pci ops"  */
+static int galileo_pcibios_read_config_word(struct pci_dev *dev,
+					    int offset, u16 * val);
+static int galileo_pcibios_read_config_byte(struct pci_dev *dev,
+					    int offset, u8 * val);
+static int galileo_pcibios_read_config_dword(struct pci_dev *dev,
+					     int offset, u32 * val);
+static int galileo_pcibios_write_config_byte(struct pci_dev *dev,
+					     int offset, u8 val);
+static int galileo_pcibios_write_config_word(struct pci_dev *dev,
+					     int offset, u16 val);
+static int galileo_pcibios_write_config_dword(struct pci_dev *dev,
+					      int offset, u32 val);
+static void galileo_pcibios_set_master(struct pci_dev *dev);
+
+/*
+ *  General-purpose PCI functions.
+ */
+
+
+/*
+ * pci_range_ck -
+ *
+ * Check if the pci device that are trying to access does really exists
+ * on the evaluation board.
+ *
+ * Inputs :
+ * bus - bus number (0 for PCI 0 ; 1 for PCI 1)
+ * dev - number of device on the specific pci bus
+ *
+ * Outpus :
+ * 0 - if OK , 1 - if failure
+ */
+static __inline__ int pci_range_ck(unsigned char bus, unsigned char dev)
+{
+	/* Accessing device 31 crashes the GT-64240. */
+	if (dev < 5)
+		return 0;
+	return -1;
+}
+
+/*
+ * galileo_pcibios_(read/write)_config_(dword/word/byte) -
+ *
+ * reads/write a dword/word/byte register from the configuration space
+ * of a device.
+ *
+ * Note that bus 0 and bus 1 are local, and we assume all other busses are
+ * bridged from bus 1.  This is a safe assumption, since any other
+ * configuration will require major modifications to the CP7000G
+ *
+ * Inputs :
+ * bus - bus number
+ * dev - device number
+ * offset - register offset in the configuration space
+ * val - value to be written / read
+ *
+ * Outputs :
+ * PCIBIOS_SUCCESSFUL when operation was succesfull
+ * PCIBIOS_DEVICE_NOT_FOUND when the bus or dev is errorneous
+ * PCIBIOS_BAD_REGISTER_NUMBER when accessing non aligned
+ */
+
+static int galileo_pcibios_read_config_dword(struct pci_dev *device,
+					      int offset, u32* val)
+{
+	int dev, bus, func;
+	uint32_t address_reg, data_reg;
+	uint32_t address;
+
+	bus = device->bus->number;
+	dev = PCI_SLOT(device->devfn);
+	func = PCI_FUNC(device->devfn);
+
+	/* verify the range */
+	if (pci_range_ck(bus, dev))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/* select the GT-64240 registers to communicate with the PCI bus */
+	if (bus == 0) {
+		address_reg = PCI_0CONFIGURATION_ADDRESS;
+		data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER;
+		GT_WRITE(PCI_0ERROR_CAUSE, ~MASTER_ABORT_BIT);
+	} else {
+		address_reg = PCI_1CONFIGURATION_ADDRESS;
+		data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER;
+		GT_WRITE(PCI_1ERROR_CAUSE, ~MASTER_ABORT_BIT);
+		if (bus == 1)
+			bus = 0;
+	}
+
+	address = (bus << 16) | (dev << 11) | (func << 8) |
+		(offset & 0xfc) | 0x80000000;
+
+	/* start the configuration cycle */
+	GT_WRITE(address_reg, address);
+
+	/* read the data */
+	GT_READ(data_reg, val);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int galileo_pcibios_read_config_word(struct pci_dev *device,
+					     int offset, u16* val)
+{
+	int dev, bus, func;
+	uint32_t address_reg, data_reg;
+	uint32_t address;
+
+	bus = device->bus->number;
+	dev = PCI_SLOT(device->devfn);
+	func = PCI_FUNC(device->devfn);
+
+	/* verify the range */
+	if (pci_range_ck(bus, dev))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/* select the GT-64240 registers to communicate with the PCI bus */
+	if (bus == 0) {
+		address_reg = PCI_0CONFIGURATION_ADDRESS;
+		data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER;
+		GT_WRITE(PCI_0ERROR_CAUSE, ~MASTER_ABORT_BIT);
+	} else {
+		address_reg = PCI_1CONFIGURATION_ADDRESS;
+		data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER;
+		GT_WRITE(PCI_1ERROR_CAUSE, ~MASTER_ABORT_BIT);
+		if (bus == 1)
+			bus = 0;
+	}
+
+	address = (bus << 16) | (dev << 11) | (func << 8) |
+		(offset & 0xfc) | 0x80000000;
+
+	/* start the configuration cycle */
+	GT_WRITE(address_reg, address);
+
+	/* read the data */
+	GT_READ_16(data_reg + (offset & 0x3), val);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int galileo_pcibios_read_config_byte(struct pci_dev *device,
+					     int offset, u8* val)
+{
+	int dev, bus, func;
+	uint32_t address_reg, data_reg;
+	uint32_t address;
+
+	bus = device->bus->number;
+	dev = PCI_SLOT(device->devfn);
+	func = PCI_FUNC(device->devfn);
+
+	/* verify the range */
+	if (pci_range_ck(bus, dev))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/* select the GT-64240 registers to communicate with the PCI bus */
+	if (bus == 0) {
+		address_reg = PCI_0CONFIGURATION_ADDRESS;
+		data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER;
+	} else {
+		address_reg = PCI_1CONFIGURATION_ADDRESS;
+		data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER;
+		if (bus == 1)
+			bus = 0;
+	}
+
+	address = (bus << 16) | (dev << 11) | (func << 8) |
+		(offset & 0xfc) | 0x80000000;
+
+	/* start the configuration cycle */
+	GT_WRITE(address_reg, address);
+
+	/* write the data */
+	GT_READ_8(data_reg + (offset & 0x3), val);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int galileo_pcibios_write_config_dword(struct pci_dev *device,
+					      int offset, u32 val)
+{
+	int dev, bus, func;
+	uint32_t address_reg, data_reg;
+	uint32_t address;
+
+	bus = device->bus->number;
+	dev = PCI_SLOT(device->devfn);
+	func = PCI_FUNC(device->devfn);
+
+	/* verify the range */
+	if (pci_range_ck(bus, dev))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/* select the GT-64240 registers to communicate with the PCI bus */
+	if (bus == 0) {
+		address_reg = PCI_0CONFIGURATION_ADDRESS;
+		data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER;
+	} else {
+		address_reg = PCI_1CONFIGURATION_ADDRESS;
+		data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER;
+		if (bus == 1)
+			bus = 0;
+	}
+
+	address = (bus << 16) | (dev << 11) | (func << 8) |
+		(offset & 0xfc) | 0x80000000;
+
+	/* start the configuration cycle */
+	GT_WRITE(address_reg, address);
+
+	/* write the data */
+	GT_WRITE(data_reg, val);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int galileo_pcibios_write_config_word(struct pci_dev *device,
+					     int offset, u16 val)
+{
+	int dev, bus, func;
+	uint32_t address_reg, data_reg;
+	uint32_t address;
+
+	bus = device->bus->number;
+	dev = PCI_SLOT(device->devfn);
+	func = PCI_FUNC(device->devfn);
+
+	/* verify the range */
+	if (pci_range_ck(bus, dev))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/* select the GT-64240 registers to communicate with the PCI bus */
+	if (bus == 0) {
+		address_reg = PCI_0CONFIGURATION_ADDRESS;
+		data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER;
+	} else {
+		address_reg = PCI_1CONFIGURATION_ADDRESS;
+		data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER;
+		if (bus == 1)
+			bus = 0;
+	}
+
+	address = (bus << 16) | (dev << 11) | (func << 8) |
+		(offset & 0xfc) | 0x80000000;
+
+	/* start the configuration cycle */
+	GT_WRITE(address_reg, address);
+
+	/* write the data */
+	GT_WRITE_16(data_reg + (offset & 0x3), val);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int galileo_pcibios_write_config_byte(struct pci_dev *device,
+					     int offset, u8 val)
+{
+	int dev, bus, func;
+	uint32_t address_reg, data_reg;
+	uint32_t address;
+
+	bus = device->bus->number;
+	dev = PCI_SLOT(device->devfn);
+	func = PCI_FUNC(device->devfn);
+
+	/* verify the range */
+	if (pci_range_ck(bus, dev))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/* select the GT-64240 registers to communicate with the PCI bus */
+	if (bus == 0) {
+		address_reg = PCI_0CONFIGURATION_ADDRESS;
+		data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER;
+	} else {
+		address_reg = PCI_1CONFIGURATION_ADDRESS;
+		data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER;
+		if (bus == 1)
+			bus = 0;
+	}
+
+	address = (bus << 16) | (dev << 11) | (func << 8) |
+		(offset & 0xfc) | 0x80000000;
+
+	/* start the configuration cycle */
+	GT_WRITE(address_reg, address);
+
+	/* write the data */
+	GT_WRITE_8(data_reg + (offset & 0x3), val);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static void galileo_pcibios_set_master(struct pci_dev *dev)
+{
+	u16 cmd;
+
+	galileo_pcibios_read_config_word(dev, PCI_COMMAND, &cmd);
+	cmd |= PCI_COMMAND_MASTER;
+	galileo_pcibios_write_config_word(dev, PCI_COMMAND, cmd);
+}
+
+/*  Externally-expected functions.  Do not change function names  */
+
+int pcibios_enable_resources(struct pci_dev *dev)
+{
+	u16 cmd, old_cmd;
+	u8 tmp1;
+	int idx;
+	struct resource *r;
+
+	galileo_pcibios_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for (idx = 0; idx < 6; idx++) {
+		r = &dev->resource[idx];
+		if (!r->start && r->end) {
+			printk(KERN_ERR
+			       "PCI: Device %s not available because of "
+			       "resource collisions\n", dev->slot_name);
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (cmd != old_cmd) {
+		galileo_pcibios_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+
+	/*
+	 * Let's fix up the latency timer and cache line size here.  Cache
+	 * line size = 32 bytes / sizeof dword (4) = 8.
+	 * Latency timer must be > 8.  32 is random but appears to work.
+	 */
+	galileo_pcibios_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &tmp1);
+	if (tmp1 != 8) {
+		printk(KERN_WARNING "PCI setting cache line size to 8 from "
+		       "%d\n", tmp1);
+		galileo_pcibios_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+						  8);
+	}
+	galileo_pcibios_read_config_byte(dev, PCI_LATENCY_TIMER, &tmp1);
+	if (tmp1 < 32) {
+		printk(KERN_WARNING "PCI setting latency timer to 32 from %d\n",
+		       tmp1);
+		galileo_pcibios_write_config_byte(dev, PCI_LATENCY_TIMER,
+						  32);
+	}
+
+	return 0;
+}
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+	return pcibios_enable_resources(dev);
+}
+
+void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+			     struct resource *res, int resource)
+{
+	u32 new, check;
+	int reg;
+
+	return;
+
+#if 0
+	new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
+	if (resource < 6) {
+		reg = PCI_BASE_ADDRESS_0 + 4 * resource;
+	} else if (resource == PCI_ROM_RESOURCE) {
+		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+		reg = dev->rom_base_reg;
+	} else {
+		/*
+		 * Somebody might have asked allocation of a non-standard
+		 * resource
+		 */
+		return;
+	}
+
+	pci_write_config_dword(dev, reg, new);
+	pci_read_config_dword(dev, reg, &check);
+	if ((new ^ check) &
+	    ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK :
+	     PCI_BASE_ADDRESS_MEM_MASK)) {
+		printk(KERN_ERR "PCI: Error while updating region "
+		       "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
+		       new, check);
+	}
+#endif
+}
+
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size, unsigned long align)
+{
+	struct pci_dev *dev = data;
+
+	if (res->flags & IORESOURCE_IO) {
+		unsigned long start = res->start;
+
+		/* We need to avoid collisions with `mirrored' VGA ports
+		   and other strange ISA hardware, so we always want the
+		   addresses kilobyte aligned.  */
+		if (size > 0x100) {
+			printk(KERN_ERR "PCI: I/O Region %s/%d too large"
+			       " (%ld bytes)\n", dev->slot_name,
+			        dev->resource - res, size);
+		}
+
+		start = (start + 1024 - 1) & ~(1024 - 1);
+		res->start = start;
+	}
+}
+
+struct pci_ops galileo_pci_ops = {
+	galileo_pcibios_read_config_byte,
+	galileo_pcibios_read_config_word,
+	galileo_pcibios_read_config_dword,
+	galileo_pcibios_write_config_byte,
+	galileo_pcibios_write_config_word,
+	galileo_pcibios_write_config_dword
+};
+
+struct pci_fixup pcibios_fixups[] = {
+	{0}
+};
+
+void __init pcibios_fixup_bus(struct pci_bus *c)
+{
+	gt64240_board_pcibios_fixup_bus(c);
+}
+
+
+/********************************************************************
+* pci0P2PConfig - This function set the PCI_0 P2P configurate.
+*                 For more information on the P2P read PCI spec.
+*
+* Inputs:  unsigned int SecondBusLow - Secondery PCI interface Bus Range Lower
+*                                      Boundry.
+*          unsigned int SecondBusHigh - Secondry PCI interface Bus Range upper
+*                                      Boundry.
+*          unsigned int busNum - The CPI bus number to which the PCI interface
+*                                      is connected.
+*          unsigned int devNum - The PCI interface's device number.
+*
+* Returns:  true.
+*/
+void pci0P2PConfig(unsigned int SecondBusLow,unsigned int SecondBusHigh,
+                   unsigned int busNum,unsigned int devNum)
+{
+	uint32_t regData;
+
+	regData = (SecondBusLow & 0xff) | ((SecondBusHigh & 0xff) << 8) |
+			((busNum & 0xff) << 16) | ((devNum & 0x1f) << 24);
+	GT_WRITE(PCI_0P2P_CONFIGURATION, regData);
+}
+
+/********************************************************************
+* pci1P2PConfig - This function set the PCI_1 P2P configurate.
+*                 For more information on the P2P read PCI spec.
+*
+* Inputs:  unsigned int SecondBusLow - Secondery PCI interface Bus Range Lower
+*               Boundry.
+*          unsigned int SecondBusHigh - Secondry PCI interface Bus Range upper
+*               Boundry.
+*          unsigned int busNum - The CPI bus number to which the PCI interface
+*               is connected.
+*          unsigned int devNum - The PCI interface's device number.
+*
+* Returns:  true.
+*/
+void pci1P2PConfig(unsigned int SecondBusLow,unsigned int SecondBusHigh,
+                   unsigned int busNum,unsigned int devNum)
+{
+	uint32_t regData;
+
+	regData = (SecondBusLow & 0xff) | ((SecondBusHigh & 0xff) << 8) |
+			((busNum & 0xff) << 16) | ((devNum & 0x1f) << 24);
+	GT_WRITE(PCI_1P2P_CONFIGURATION, regData);
+}
+
+#define PCI0_STATUS_COMMAND_REG                 0x4
+#define PCI1_STATUS_COMMAND_REG                 0x84
+
+void __init pcibios_init(void)
+{
+	/* Reset PCI I/O and PCI MEM values */
+	ioport_resource.start = 0xe0000000;
+	ioport_resource.end   = 0xe0000000 + 0x20000000 - 1;
+	iomem_resource.start  = 0xc0000000;
+	iomem_resource.end    = 0xc0000000 + 0x20000000 - 1;
+
+	pci_scan_bus(0, &galileo_pci_ops, NULL);
+	pci_scan_bus(1, &galileo_pci_ops, NULL);
+}
+
+/*
+ * for parsing "pci=" kernel boot arguments.
+ */
+char *pcibios_setup(char *str)
+{
+        printk(KERN_INFO "rr: pcibios_setup\n");
+        /* Nothing to do for now.  */
+
+        return str;
+}
+
+unsigned __init int pcibios_assign_all_busses(void)
+{
+	return 1;
+}
+
+#endif	/* CONFIG_PCI */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/momentum/ocelot_g/prom.c linux-2.4.20/arch/mips/momentum/ocelot_g/prom.c
--- linux-2.4.19/arch/mips/momentum/ocelot_g/prom.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/momentum/ocelot_g/prom.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2002 Momentum Computer Inc.
+ * Author: Matthew Dharm <mdharm@momenco.com>
+ *
+ * Based on Ocelot Linux port, which is
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ *
+ * 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.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/bootmem.h>
+
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+#include "gt64240.h"
+#include "ocelot_pld.h"
+
+struct callvectors {
+	int	(*open) (char*, int, int);
+	int	(*close) (int);
+	int	(*read) (int, void*, int);
+	int	(*write) (int, void*, int);
+	off_t	(*lseek) (int, off_t, int);
+	int	(*printf) (const char*, ...);
+	void	(*cacheflush) (void);
+	char*	(*gets) (char*);
+};
+
+struct callvectors* debug_vectors;
+char arcs_cmdline[CL_SIZE];
+
+extern unsigned long gt64240_base;
+extern unsigned long bus_clock;
+
+#ifdef CONFIG_GALILLEO_GT64240_ETH
+extern unsigned char prom_mac_addr_base[6];
+#endif
+
+const char *get_system_type(void)
+{
+	return "Momentum Ocelot";
+}
+
+/* [jsun@junsun.net] PMON passes arguments in C main() style */
+void __init prom_init(int argc, char **arg, char** env, struct callvectors *cv)
+{
+	int i;
+	uint32_t tmp;
+
+	/* save the PROM vectors for debugging use */
+	debug_vectors = cv;
+
+	/* arg[0] is "g", the rest is boot parameters */
+	arcs_cmdline[0] = '\0';
+	for (i = 1; i < argc; i++) {
+		if (strlen(arcs_cmdline) + strlen(arg[i] + 1)
+		    >= sizeof(arcs_cmdline))
+			break;
+		strcat(arcs_cmdline, arg[i]);
+		strcat(arcs_cmdline, " ");
+	}
+
+	mips_machgroup = MACH_GROUP_MOMENCO;
+	mips_machtype = MACH_MOMENCO_OCELOT_G;
+
+#ifdef CONFIG_GALILLEO_GT64240_ETH
+	/* get the base MAC address for on-board ethernet ports */
+	memcpy(prom_mac_addr_base, (void*)0xfc807cf2, 6);
+#endif
+
+	while (*env) {
+		if (strncmp("gtbase", *env, strlen("gtbase")) == 0) {
+			gt64240_base = simple_strtol(*env + strlen("gtbase="),
+							NULL, 16);
+		}
+		if (strncmp("busclock", *env, strlen("busclock")) == 0) {
+			bus_clock = simple_strtol(*env + strlen("busclock="),
+							NULL, 10);
+		}
+		*env++;
+	}
+
+	debug_vectors->printf("Booting Linux kernel...\n");
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
+
+void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
+{
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/momentum/ocelot_g/reset.c linux-2.4.20/arch/mips/momentum/ocelot_g/reset.c
--- linux-2.4.19/arch/mips/momentum/ocelot_g/reset.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/momentum/ocelot_g/reset.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 1997, 2001 Ralf Baechle
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/reboot.h>
+#include <asm/system.h>
+#include <linux/delay.h>
+
+void momenco_ocelot_restart(char *command)
+{
+	void *nvram = ioremap_nocache(0x2c807000, 0x1000);
+
+	if (!nvram) {
+		printk(KERN_NOTICE "ioremap of reset register failed\n");
+		return;
+	}
+	writeb(0x84, nvram + 0xff7); /* Ask the NVRAM/RTC/watchdog chip to
+					assert reset in 1/16 second */
+	mdelay(10+(1000/16));
+	iounmap(nvram);
+	printk(KERN_NOTICE "Watchdog reset failed\n");
+}
+
+void momenco_ocelot_halt(void)
+{
+	printk(KERN_NOTICE "\n** You can safely turn off the power\n");
+	while (1)
+		__asm__(".set\tmips3\n\t"
+	                "wait\n\t"
+			".set\tmips0");
+}
+
+void momenco_ocelot_power_off(void)
+{
+	momenco_ocelot_halt();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/momentum/ocelot_g/setup.c linux-2.4.20/arch/mips/momentum/ocelot_g/setup.c
--- linux-2.4.19/arch/mips/momentum/ocelot_g/setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/momentum/ocelot_g/setup.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,258 @@
+/*
+ * setup.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ * Momentum Computer Ocelot-G (CP7000G) - board dependent boot routines
+ *
+ * Copyright (C) 1996, 1997, 2001  Ralf Baechle
+ * Copyright (C) 2000 RidgeRun, Inc.
+ * Copyright (C) 2001 Red Hat, Inc.
+ * Copyright (C) 2002 Momentum Computer
+ *
+ * Author: Matthew Dharm, Momentum Computer
+ *   mdharm@momenco.com
+ *
+ * Author: RidgeRun, Inc.
+ *   glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ *
+ *  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.
+ *
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mc146818rtc.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/timex.h>
+#include <linux/vmalloc.h>
+#include <asm/time.h>
+#include <asm/bootinfo.h>
+#include <asm/page.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pci.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+#include <asm/reboot.h>
+#include <asm/mc146818rtc.h>
+#include <linux/version.h>
+#include <linux/bootmem.h>
+#include <linux/blk.h>
+#include "gt64240.h"
+#include "ocelot_pld.h"
+
+extern struct rtc_ops no_rtc_ops;
+
+unsigned long gt64240_base;
+
+/* These functions are used for rebooting or halting the machine*/
+extern void momenco_ocelot_restart(char *command);
+extern void momenco_ocelot_halt(void);
+extern void momenco_ocelot_power_off(void);
+
+extern void gt64240_time_init(void);
+extern void momenco_ocelot_irq_setup(void);
+
+static char reset_reason;
+
+#define ENTRYLO(x) ((pte_val(mk_pte_phys((x), PAGE_KERNEL_UNCACHED)) >> 6)|1)
+
+static void __init setup_l3cache(unsigned long size);
+
+void __init bus_error_init(void) { /* nothing */ }
+
+/* setup code for a handoff from a version 2 PMON 2000 PROM */
+void PMON_v2_setup(void)
+{
+	/* A wired TLB entry for the GT64240 and the serial port. The
+	   GT64240 is going to be hit on every IRQ anyway - there's
+	   absolutely no point in letting it be a random TLB entry, as
+	   it'll just cause needless churning of the TLB. And we use
+	   the other half for the serial port, which is just a PITA
+	   otherwise :)
+
+		Device			Physical	Virtual
+		GT64240 Internal Regs	0xf4000000	0xe0000000
+		UARTs (CS2)		0xfd000000	0xe0001000
+	*/
+	add_wired_entry(ENTRYLO(0xf4000000), ENTRYLO(0xf4010000), 0xf4000000, PM_64K);
+	add_wired_entry(ENTRYLO(0xfd000000), ENTRYLO(0xfd001000), 0xfd000000, PM_4K);
+
+	/* Also a temporary entry to let us talk to the Ocelot PLD and NVRAM
+	   in the CS[012] region. We can't use ioremap() yet. The NVRAM
+	   is a ST M48T37Y, which includes NVRAM, RTC, and Watchdog functions.
+
+		Ocelot PLD (CS0)	0xfc000000	0xe0020000
+		NVRAM (CS1)		0xfc800000	0xe0030000
+	*/
+	add_temporary_entry(ENTRYLO(0xfc000000), ENTRYLO(0xfc010000), 0xfc000000, PM_64K);
+	add_temporary_entry(ENTRYLO(0xfc800000), ENTRYLO(0xfc810000), 0xfc800000, PM_64K);
+
+	gt64240_base = 0xf4000000;
+}
+
+void __init momenco_ocelot_g_setup(void)
+{
+	void (*l3func)(unsigned long)=KSEG1ADDR(&setup_l3cache);
+	unsigned int tmpword;
+
+	board_time_init = gt64240_time_init;
+
+	_machine_restart = momenco_ocelot_restart;
+	_machine_halt = momenco_ocelot_halt;
+	_machine_power_off = momenco_ocelot_power_off;
+
+	/*
+	 * initrd_start = (ulong)ocelot_initrd_start;
+	 * initrd_end = (ulong)ocelot_initrd_start + (ulong)ocelot_initrd_size;
+	 * initrd_below_start_ok = 1;
+	 */
+	rtc_ops = &no_rtc_ops;
+
+	/* do handoff reconfiguration */
+	PMON_v2_setup();
+
+	/* Turn off the Bit-Error LED */
+	OCELOT_PLD_WRITE(0x80, INTCLR);
+
+	tmpword = OCELOT_PLD_READ(BOARDREV);
+	if (tmpword < 26)
+		printk("Momenco Ocelot-G: Board Assembly Rev. %c\n", 'A'+tmpword);
+	else
+		printk("Momenco Ocelot-G: Board Assembly Revision #0x%x\n", tmpword);
+
+	tmpword = OCELOT_PLD_READ(PLD1_ID);
+	printk("PLD 1 ID: %d.%d\n", tmpword>>4, tmpword&15);
+	tmpword = OCELOT_PLD_READ(PLD2_ID);
+	printk("PLD 2 ID: %d.%d\n", tmpword>>4, tmpword&15);
+	tmpword = OCELOT_PLD_READ(RESET_STATUS);
+	printk("Reset reason: 0x%x\n", tmpword);
+	reset_reason = tmpword;
+	OCELOT_PLD_WRITE(0xff, RESET_STATUS);
+
+	tmpword = OCELOT_PLD_READ(BOARD_STATUS);
+	printk("Board Status register: 0x%02x\n", tmpword);
+	printk("  - User jumper: %s\n", (tmpword & 0x80)?"installed":"absent");
+	printk("  - Boot flash write jumper: %s\n", (tmpword&0x40)?"installed":"absent");
+	printk("  - Tulip PHY %s connected\n", (tmpword&0x10)?"is":"not");
+	printk("  - L3 Cache size: %d MiB\n", (1<<((tmpword&12) >> 2))&~1);
+	printk("  - SDRAM size: %d MiB\n", 1<<(6+(tmpword&3)));
+
+	if (tmpword&12)
+		l3func((1<<(((tmpword&12) >> 2)+20)));
+
+	switch(tmpword &3) {
+	case 3:
+		/* 512MiB -- two banks of 256MiB */
+		add_memory_region(  0x0<<20, 0x100<<20, BOOT_MEM_RAM);
+/*
+		add_memory_region(0x100<<20, 0x100<<20, BOOT_MEM_RAM);
+*/
+		break;
+	case 2:
+		/* 256MiB -- two banks of 128MiB */
+		add_memory_region( 0x0<<20, 0x80<<20, BOOT_MEM_RAM);
+		add_memory_region(0x80<<20, 0x80<<20, BOOT_MEM_RAM);
+		break;
+	case 1:
+		/* 128MiB -- 64MiB per bank */
+		add_memory_region( 0x0<<20, 0x40<<20, BOOT_MEM_RAM);
+		add_memory_region(0x40<<20, 0x40<<20, BOOT_MEM_RAM);
+		break;
+	case 0:
+		/* 64MiB */
+		add_memory_region( 0x0<<20, 0x40<<20, BOOT_MEM_RAM);
+		break;
+	}
+
+	/* FIXME: Fix up the DiskOnChip mapping */
+	GT_WRITE(0x468, 0xfef73);
+}
+
+extern int rm7k_tcache_enabled;
+/*
+ * This runs in KSEG1. See the verbiage in rm7k.c::probe_scache()
+ */
+#define Page_Invalidate_T 0x16
+static void __init setup_l3cache(unsigned long size)
+{
+	int register i;
+	unsigned long tmp;
+
+	printk("Enabling L3 cache...");
+
+	/* Enable the L3 cache in the GT64120A's CPU Configuration register */
+	GT_READ(0, &tmp);
+	GT_WRITE(0, tmp | (1<<14));
+
+	/* Enable the L3 cache in the CPU */
+	set_cp0_config(1<<12 /* CONF_TE */);
+
+	/* Clear the cache */
+	set_taglo(0);
+	set_taghi(0);
+
+	for (i=0; i < size; i+= 4096) {
+		__asm__ __volatile__ (
+			".set noreorder\n\t"
+			".set mips3\n\t"
+			"cache %1, (%0)\n\t"
+			".set mips0\n\t"
+			".set reorder"
+			:
+			: "r" (KSEG0ADDR(i)),
+			  "i" (Page_Invalidate_T));
+	}
+
+	/* Let the RM7000 MM code know that the tertiary cache is enabled */
+	rm7k_tcache_enabled = 1;
+
+	printk("Done\n");
+}
+
+
+/* This needs to be one of the first initcalls, because no I/O port access
+   can work before this */
+
+static int io_base_ioremap(void)
+{
+	/* we're mapping PCI accesses from 0xc0000000 to 0xf0000000 */
+	void *io_remap_range = ioremap(0xc0000000, 0x30000000);
+
+	if (!io_remap_range) {
+		panic("Could not ioremap I/O port range");
+	}
+	printk("io_remap_range set at 0x%08x\n", (uint32_t)io_remap_range);
+	set_io_port_base(io_remap_range - 0xc0000000);
+
+	return 0;
+}
+
+module_init(io_base_ioremap);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip22/Makefile linux-2.4.20/arch/mips/sgi-ip22/Makefile
--- linux-2.4.19/arch/mips/sgi-ip22/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip22/Makefile	2002-10-29 11:18:50.000000000 +0000
@@ -18,6 +18,7 @@
          ip22-gio.o ip22-rtc.o ip22-reset.o ip22-system.o ip22-setup.o
 
 obj-$(CONFIG_BOARD_SCACHE)	+= ip22-sc.o
+obj-$(CONFIG_IP22_EISA)		+= ip22-eisa.o
 
 ip22-irq.o: ip22-irq.S
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip22/ip22-berr.c linux-2.4.20/arch/mips/sgi-ip22/ip22-berr.c
--- linux-2.4.19/arch/mips/sgi-ip22/ip22-berr.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip22/ip22-berr.c	2002-10-29 11:18:50.000000000 +0000
@@ -24,7 +24,7 @@
 
 static void save_and_clear_buserr(void)
 {
-	/* save memory controler's error status registers */ 
+	/* save memory controler's error status registers */
 	cpu_err_addr = mcmisc_regs->cerr;
 	cpu_err_stat = mcmisc_regs->cstat;
 	gio_err_addr = mcmisc_regs->gerr;
@@ -34,8 +34,8 @@
 }
 
 /*
- * MC sends an interrupt whenever bus or parity errors occur. In addition, 
- * if the error happened during a CPU read, it also asserts the bus error 
+ * MC sends an interrupt whenever bus or parity errors occur. In addition,
+ * if the error happened during a CPU read, it also asserts the bus error
  * pin on the R4K. Code in bus error handler save the MC bus error registers
  * and then clear the interrupt when this happens.
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip22/ip22-eisa.c linux-2.4.20/arch/mips/sgi-ip22/ip22-eisa.c
--- linux-2.4.19/arch/mips/sgi-ip22/ip22-eisa.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip22/ip22-eisa.c	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,300 @@
+/*
+ * Basic EISA bus support for the SGI Indigo-2.
+ *
+ * (C) 2002 Pascal Dameme <netinet@freesurf.fr>
+ *      and Marc Zyngier <mzyngier@freesurf.fr>
+ *
+ * This code is released under both the GPL version 2 and BSD
+ * licenses.  Either license may be used.
+ *
+ * This code offers a very basic support for this EISA bus present in
+ * the SGI Indigo-2. It currently only supports PIO (forget about DMA
+ * for the time being). This is enough for a low-end ethernet card,
+ * but forget about your favorite SCSI card...
+ *
+ * TODO :
+ * - Fix bugs...
+ * - Add ISA support
+ * - Add DMA (yeah, right...).
+ * - Fix more bugs.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/sgi/sgint23.h>
+
+extern int EISA_bus;
+extern void do_IRQ(int irq, struct pt_regs *regs);
+
+#define EISA_MAX_SLOTS		  4
+#define EISA_MAX_IRQ             16
+
+#define EISA_TO_PHYS(x)  (0x00080000 | (x))
+#define EISA_TO_KSEG1(x) ((void *) KSEG1ADDR(EISA_TO_PHYS((x))))
+
+#define EIU_MODE_REG     0x0009ffc0
+#define EIU_STAT_REG     0x0009ffc4
+#define EIU_PREMPT_REG   0x0009ffc8
+#define EIU_QUIET_REG    0x0009ffcc
+#define EIU_INTRPT_ACK   0x00090004
+
+#define EISA_DMA1_STATUS            8
+#define EISA_INT1_CTRL           0x20
+#define EISA_INT1_MASK           0x21
+#define EISA_INT2_CTRL           0xA0
+#define EISA_INT2_MASK           0xA1
+#define EISA_DMA2_STATUS         0xD0
+#define EISA_DMA2_WRITE_SINGLE   0xD4
+#define EISA_EXT_NMI_RESET_CTRL 0x461
+#define EISA_INT1_EDGE_LEVEL    0x4D0
+#define EISA_INT2_EDGE_LEVEL    0x4D1
+#define EISA_VENDOR_ID_OFFSET   0xC80
+
+#define EIU_WRITE_32(x,y) { *((u32 *) KSEG1ADDR(x)) = (u32) (y); mb(); }
+#define EIU_READ_8(x) *((u8 *) KSEG1ADDR(x))
+#define EISA_WRITE_8(x,y) { *((u8 *) EISA_TO_KSEG1(x)) = (u8) (y); mb(); }
+#define EISA_READ_8(x) *((u8 *) EISA_TO_KSEG1(x))
+
+static char *decode_eisa_sig(u8 * sig)
+{
+	static char sig_str[8];
+	u16 rev;
+
+	if (sig[0] & 0x80)
+		return NULL;
+
+	sig_str[0] = ((sig[0] >> 2) & 0x1f) + ('A' - 1);
+	sig_str[1] = (((sig[0] & 3) << 3) | (sig[1] >> 5)) + ('A' - 1);
+	sig_str[2] = (sig[1] & 0x1f) + ('A' - 1);
+	rev = (sig[2] << 8) | sig[3];
+	sprintf(sig_str + 3, "%04X", rev);
+
+	return sig_str;
+}
+
+static void ip22_eisa_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	u8 eisa_irq;
+	u8 dma1, dma2;
+
+	eisa_irq = EIU_READ_8(EIU_INTRPT_ACK);
+	dma1 = EISA_READ_8(EISA_DMA1_STATUS);
+	dma2 = EISA_READ_8(EISA_DMA2_STATUS);
+
+	if (eisa_irq >= EISA_MAX_IRQ) {
+		/* Oops, Bad Stuff Happened... */
+		printk("eisa_irq %d out of bound\n", eisa_irq);
+
+		EISA_WRITE_8(EISA_INT2_CTRL, 0x20);
+		EISA_WRITE_8(EISA_INT1_CTRL, 0x20);
+	} else
+		do_IRQ(eisa_irq, regs);
+}
+
+static void enable_eisa1_irq(unsigned int irq)
+{
+	unsigned long flags;
+	u8 mask;
+
+	save_and_cli(flags);
+
+	mask = EISA_READ_8(EISA_INT1_MASK);
+	mask &= ~((u8) (1 << irq));
+	EISA_WRITE_8(EISA_INT1_MASK, mask);
+
+	restore_flags(flags);
+}
+
+static unsigned int startup_eisa1_irq(unsigned int irq)
+{
+	u8 edge;
+
+	/* Only use edge interrupts for EISA */
+
+	edge = EISA_READ_8(EISA_INT1_EDGE_LEVEL);
+	edge &= ~((u8) (1 << irq));
+	EISA_WRITE_8(EISA_INT1_EDGE_LEVEL, edge);
+
+	enable_eisa1_irq(irq);
+	return 0;
+}
+
+static void disable_eisa1_irq(unsigned int irq)
+{
+	u8 mask;
+
+	mask = EISA_READ_8(EISA_INT1_MASK);
+	mask |= ((u8) (1 << irq));
+	EISA_WRITE_8(EISA_INT1_MASK, mask);
+}
+
+#define shutdown_eisa1_irq	disable_eisa1_irq
+
+static void mask_and_ack_eisa1_irq(unsigned int irq)
+{
+	disable_eisa1_irq(irq);
+
+	EISA_WRITE_8(EISA_INT1_CTRL, 0x20);
+}
+
+static void end_eisa1_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		enable_eisa1_irq(irq);
+}
+
+static struct hw_interrupt_type ip22_eisa1_irq_type = {
+	"IP22 EISA",
+	startup_eisa1_irq,
+	shutdown_eisa1_irq,
+	enable_eisa1_irq,
+	disable_eisa1_irq,
+	mask_and_ack_eisa1_irq,
+	end_eisa1_irq,
+	NULL
+};
+
+static void enable_eisa2_irq(unsigned int irq)
+{
+	unsigned long flags;
+	u8 mask;
+
+	save_and_cli(flags);
+
+	mask = EISA_READ_8(EISA_INT2_MASK);
+	mask &= ~((u8) (1 << (irq - 8)));
+	EISA_WRITE_8(EISA_INT2_MASK, mask);
+
+	restore_flags(flags);
+}
+
+static unsigned int startup_eisa2_irq(unsigned int irq)
+{
+	u8 edge;
+
+	/* Only use edge interrupts for EISA */
+
+	edge = EISA_READ_8(EISA_INT2_EDGE_LEVEL);
+	edge &= ~((u8) (1 << (irq - 8)));
+	EISA_WRITE_8(EISA_INT2_EDGE_LEVEL, edge);
+
+	enable_eisa2_irq(irq);
+	return 0;
+}
+
+static void disable_eisa2_irq(unsigned int irq)
+{
+	u8 mask;
+
+	mask = EISA_READ_8(EISA_INT2_MASK);
+	mask |= ((u8) (1 << (irq - 8)));
+	EISA_WRITE_8(EISA_INT2_MASK, mask);
+}
+
+#define shutdown_eisa2_irq	disable_eisa2_irq
+
+static void mask_and_ack_eisa2_irq(unsigned int irq)
+{
+	disable_eisa2_irq(irq);
+
+	EISA_WRITE_8(EISA_INT2_CTRL, 0x20);
+	EISA_WRITE_8(EISA_INT1_CTRL, 0x20);
+}
+
+static void end_eisa2_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		enable_eisa2_irq(irq);
+}
+
+static struct hw_interrupt_type ip22_eisa2_irq_type = {
+	"IP22 EISA",
+	startup_eisa2_irq,
+	shutdown_eisa2_irq,
+	enable_eisa2_irq,
+	disable_eisa2_irq,
+	mask_and_ack_eisa2_irq,
+	end_eisa2_irq,
+	NULL
+};
+
+static struct irqaction eisa_action = {
+	ip22_eisa_intr, 0, 0, "EISA", NULL, NULL
+};
+
+static struct irqaction cascade_action = {
+	no_action, 0, 0, "EISA cascade", NULL, NULL
+};
+
+int __init ip22_eisa_init(void)
+{
+	int i, c;
+	char *str;
+	u8 *slot_addr;
+
+	printk("EISA: Probing bus...\n");
+	for (c = 0, i = 1; i <= EISA_MAX_SLOTS; i++) {
+		slot_addr =
+		    (u8 *) EISA_TO_KSEG1((0x1000 * i) +
+					 EISA_VENDOR_ID_OFFSET);
+		if ((str = decode_eisa_sig(slot_addr))) {
+			printk("EISA: slot %d : %s detected.\n", i, str);
+			c++;
+		}
+	}
+	printk("EISA: Detected %d card%s.\n", c, c < 2 ? "" : "s");
+#ifdef CONFIG_ISA
+	printk("ISA support compiled in.\n");
+#endif
+
+	/* Warning : BlackMagicAhead(tm).
+	   Please wave your favorite dead chicken over the busses */
+
+	/* First say hello to the EIU */
+	EIU_WRITE_32(EIU_PREMPT_REG, 0x0000FFFF);
+	EIU_WRITE_32(EIU_QUIET_REG, 1);
+	EIU_WRITE_32(EIU_MODE_REG, 0x40f3c07F);
+
+	/* Now be nice to the EISA chipset */
+	EISA_WRITE_8(EISA_EXT_NMI_RESET_CTRL, 1);
+	for (i = 0; i < 10000; i++);	/* Wait long enough for the dust to settle */
+	EISA_WRITE_8(EISA_EXT_NMI_RESET_CTRL, 0);
+	EISA_WRITE_8(EISA_INT1_CTRL, 0x11);
+	EISA_WRITE_8(EISA_INT2_CTRL, 0x11);
+	EISA_WRITE_8(EISA_INT1_MASK, 0);
+	EISA_WRITE_8(EISA_INT2_MASK, 8);
+	EISA_WRITE_8(EISA_INT1_MASK, 4);
+	EISA_WRITE_8(EISA_INT2_MASK, 2);
+	EISA_WRITE_8(EISA_INT1_MASK, 1);
+	EISA_WRITE_8(EISA_INT2_MASK, 1);
+	EISA_WRITE_8(EISA_INT1_MASK, 0xfb);
+	EISA_WRITE_8(EISA_INT2_MASK, 0xff);
+	EISA_WRITE_8(EISA_DMA2_WRITE_SINGLE, 0);
+
+	for (i = SGINT_EISA; i < (SGINT_EISA + EISA_MAX_IRQ); i++) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].action = 0;
+		irq_desc[i].depth = 1;
+		if (i < (SGINT_EISA + 8))
+			irq_desc[i].handler = &ip22_eisa1_irq_type;
+		else
+			irq_desc[i].handler = &ip22_eisa2_irq_type;
+	}
+
+	/* Cannot use request_irq because of kmalloc not being ready at such
+	 * an early stage. Yes, I've been bitten... */
+	setup_irq(SGI_EISA_IRQ, &eisa_action);
+	setup_irq(SGINT_EISA + 2, &cascade_action);
+
+	EISA_bus = 1;
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip22/ip22-gio.c linux-2.4.20/arch/mips/sgi-ip22/ip22-gio.c
--- linux-2.4.19/arch/mips/sgi-ip22/ip22-gio.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip22/ip22-gio.c	2002-10-29 11:18:35.000000000 +0000
@@ -1,6 +1,6 @@
-/* 
+/*
  * ip22-gio.c: Support for GIO64 bus (inspired by PCI code)
- * 
+ *
  * Copyright (C) 2002 Ladislav Michl
  */
 
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 
+#include <asm/addrspace.h>
 #include <asm/sgi/sgimc.h>
 #include <asm/sgi/sgigio.h>
 
@@ -67,7 +68,7 @@
 {
 	int i;
 	char *p = buf;
-	
+
 	p += sprintf(p, "GIO devices found:\n");
 	for (i = 0; i < GIO_NUM_SLOTS; i++) {
 		if (gio_slot[i].flags & GIO_NO_DEVICE)
@@ -77,7 +78,7 @@
 		p += sprintf(p, "    BaseAddr 0x%08lx, MapSize 0x%08x\n",
 			     gio_slot[i].base_addr, gio_slot[i].map_size);
 	}
-	
+
 	return p - buf;
 }
 
@@ -92,7 +93,7 @@
  * @from: Previous GIO device found in search, or %NULL for new search.
  *
  * Iterates through the list of known GIO devices. If a GIO device is found
- * with a matching @device, a pointer to its device structure is returned. 
+ * with a matching @device, a pointer to its device structure is returned.
  * Otherwise, %NULL is returned.
  * A new search is initiated by passing %NULL to the @from argument.
  * Otherwise if @from is not %NULL, searches continue from next device.
@@ -101,12 +102,12 @@
 gio_find_device(unsigned char device, const struct gio_dev *from)
 {
 	int i;
-	
+
 	for (i = (from) ? from->slot_number : 0; i < GIO_NUM_SLOTS; i++)
-		if (!(gio_slot[i].flags & GIO_NO_DEVICE) && 
+		if (!(gio_slot[i].flags & GIO_NO_DEVICE) &&
 		   (device == GIO_ANY_ID || device == gio_slot[i].device))
 			return &gio_slot[i];
-	
+
 	return NULL;
 }
 
@@ -119,7 +120,7 @@
 
 extern int ip22_baddr(unsigned int *val, unsigned long addr);
 
-/** 
+/**
  * sgigio_init - scan the GIO space and figure out what hardware is actually
  * present.
  */
@@ -146,7 +147,7 @@
 		printk("GIO: Card 0x%02x @ 0x%08lx\n", gio_slot[i].device,
 			gio_slot[i].base_addr);
 	}
-	
+
 	if (!found)
 		printk("GIO: No GIO cards present.\n");
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip22/ip22-int.c linux-2.4.20/arch/mips/sgi-ip22/ip22-int.c
--- linux-2.4.19/arch/mips/sgi-ip22/ip22-int.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip22/ip22-int.c	2002-10-29 11:18:35.000000000 +0000
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org)
- * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) 
+ * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu)
  *                    - Indigo2 changes
  *                    - Interrupt handling fixes
  * Copyright (C) 2001 Ladislav Michl (ladis@psi.cz)
@@ -20,7 +20,6 @@
 
 #include <asm/mipsregs.h>
 #include <asm/addrspace.h>
-#include <asm/gdb-stub.h>
 
 #include <asm/sgi/sgint23.h>
 #include <asm/sgi/sgihpc.h>
@@ -41,6 +40,7 @@
 
 extern asmlinkage void indyIRQ(void);
 extern void do_IRQ(int irq, struct pt_regs *regs);
+extern int ip22_eisa_init (void);
 
 static void enable_local0_irq(unsigned int irq)
 {
@@ -187,7 +187,7 @@
 {
 #ifdef I_REALLY_NEED_THIS_IRQ
 	unsigned long flags;
-	
+
 	save_and_cli(flags);
 	ioc_icontrol->imask1 |= (1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1));
 	ioc_icontrol->cmeimask1 |= (1 << (irq - SGINT_LOCAL3));
@@ -276,7 +276,7 @@
 	/* if irq == 0, then the interrupt has already been cleared */
 	if (irq)
 		do_IRQ(irq, regs);
-	return;	
+	return;
 }
 
 extern void be_ip22_interrupt(int irq, struct pt_regs *regs);
@@ -292,11 +292,11 @@
 	irq_exit(cpu, irq);
 }
 
-static struct irqaction local0_cascade = 
+static struct irqaction local0_cascade =
 	{ no_action, SA_INTERRUPT, 0, "local0 cascade", NULL, NULL };
-static struct irqaction local1_cascade = 
+static struct irqaction local1_cascade =
 	{ no_action, SA_INTERRUPT, 0, "local1 cascade", NULL, NULL };
-static struct irqaction buserr = 
+static struct irqaction buserr =
 	{ no_action, SA_INTERRUPT, 0, "Bus Error", NULL, NULL };
 static struct irqaction map0_cascade =
 	{ no_action, SA_INTERRUPT, 0, "mappable0 cascade", NULL, NULL };
@@ -409,10 +409,14 @@
 	setup_irq(SGI_LOCAL_0_IRQ, &local0_cascade);
 	setup_irq(SGI_LOCAL_1_IRQ, &local1_cascade);
 	setup_irq(SGI_BUSERR_IRQ, &buserr);
-	
+
 	/* cascade in cascade. i love Indy ;-) */
 	setup_irq(SGI_MAP_0_IRQ, &map0_cascade);
 #ifdef I_REALLY_NEED_THIS_IRQ
 	setup_irq(SGI_MAP_1_IRQ, &map1_cascade);
 #endif
+#ifdef CONFIG_IP22_EISA
+	if (!sgi_guiness)	/* Only Indigo-2 have EISA stuff */
+	        ip22_eisa_init ();
+#endif
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip22/ip22-irq.S linux-2.4.20/arch/mips/sgi-ip22/ip22-irq.S
--- linux-2.4.19/arch/mips/sgi-ip22/ip22-irq.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip22/ip22-irq.S	2002-10-29 11:18:48.000000000 +0000
@@ -65,10 +65,8 @@
 	 andi	a0, s0, CAUSEF_IP2	# delay slot, check local level zero
 
 	/* Wheee, a timer interrupt. */
-	move	a0, sp
 	jal	indy_r4k_timer_interrupt
-	 nop				# delay slot
-
+	 move	a0, sp			# delay slot
 	j	ret_from_irq
 	 nop				# delay slot
 
@@ -88,38 +86,33 @@
 	 andi	a0, s0, CAUSEF_IP6	# delay slot, check bus error
 
 	/* Wheee, local level one interrupt. */
-	move	a0, sp
 	jal	indy_local1_irqdispatch
-	 nop
-
+	 move	a0, sp			# delay slot
 	j	ret_from_irq
-	 nop
+	 nop				# delay slot
 
 1:
 	beq	a0, zero, 1f
-	 nop
+	 andi	a0, s0, (CAUSEF_IP4 | CAUSEF_IP5)	# delay slot
 
 	/* Wheee, an asynchronous bus error... */
-	move	a0, sp
 	jal	indy_buserror_irq
-	 nop
-
+	 move	a0, sp			# delay slot
 	j	ret_from_irq
-	 nop
+	 nop				# delay slot
 
 1:
 	/* Here by mistake? It is possible, that by the time we take
-	 * the exception the IRQ pin goes low, so just leave if this 
+	 * the exception the IRQ pin goes low, so just leave if this
 	 * is the case.
 	 */
-	andi	a0, s0, (CAUSEF_IP4 | CAUSEF_IP5)
 	beq	a0, zero, 1f
+	 nop			  	# delay slot
 
 	/* Must be one of the 8254 timers... */
-	move	a0, sp
 	jal	indy_8254timer_irq
-	 nop
+	 move	a0, sp			# delay slot
 1:
 	j	ret_from_irq
-	 nop
+	 nop				# delay slot
 	END(indyIRQ)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip22/ip22-mc.c linux-2.4.20/arch/mips/sgi-ip22/ip22-mc.c
--- linux-2.4.19/arch/mips/sgi-ip22/ip22-mc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip22/ip22-mc.c	2002-10-29 11:18:31.000000000 +0000
@@ -16,10 +16,15 @@
 
 /* #define DEBUG_SGIMC */
 
+#ifdef DEBUG_SGIMC
+extern void prom_printf(char *fmt, ...);
+#endif
+
 struct sgimc_misc_ctrl *mcmisc_regs;
 struct sgimc_dma_ctrl *dmactrlregs;
 u32 *rpsscounter;
 
+#ifdef DEBUG_SGIMC
 static inline char *mconfig_string(unsigned long val)
 {
 	switch(val & SGIMC_MCONFIG_RMASK) {
@@ -45,6 +50,7 @@
 		return "wheee, unknown";
 	}
 }
+#endif
 
 void __init sgimc_init(void)
 {
@@ -82,12 +88,12 @@
 	/* Place the MC into a known state.  This must be done before
 	 * interrupts are first enabled etc.
 	 */
-	
+
 	/* Step 0: Make sure we turn off the watchdog in case it's
 	 *         still running (which might be the case after a
 	 *         soft reboot).
 	 */
-	tmpreg = mcmisc_regs->cpuctrl0; 
+	tmpreg = mcmisc_regs->cpuctrl0;
 	tmpreg &= ~SGIMC_CCTRL0_WDOG;
 	mcmisc_regs->cpuctrl0 = tmpreg;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip22/ip22-reset.c linux-2.4.20/arch/mips/sgi-ip22/ip22-reset.c
--- linux-2.4.19/arch/mips/sgi-ip22/ip22-reset.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip22/ip22-reset.c	2002-10-29 11:18:37.000000000 +0000
@@ -58,7 +58,7 @@
 static void sgi_machine_power_off(void)
 {
 	unsigned char val;
-	
+
 	cli();
 
 	/* Disable watchdog */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip22/ip22-sc.c linux-2.4.20/arch/mips/sgi-ip22/ip22-sc.c
--- linux-2.4.19/arch/mips/sgi-ip22/ip22-sc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip22/ip22-sc.c	2002-10-29 11:18:35.000000000 +0000
@@ -34,7 +34,8 @@
 	unsigned long tmp;
 
 	__asm__ __volatile__(
-	".set\tnoreorder\t\t\t# indy_sc_wipe\n\t"
+	".set\tpush\t\t\t# indy_sc_wipe\n\t"
+	".set\tnoreorder\n\t"
 	".set\tmips3\n\t"
 	".set\tnoat\n\t"
 	"mfc0\t%2, $12\n\t"
@@ -48,12 +49,11 @@
 
 	"1:\tsw\t$0, 0(%0)\n\t"
 	"bne\t%0, %1, 1b\n\t"
-	"daddu\t%0, 32\n\t"
+	" daddu\t%0, 32\n\t"
 
 	"mtc0\t%2, $12\t\t\t# Back to 32 bit\n\t"
 	"nop; nop; nop; nop;\n\t"
-	".set\tmips0\n\t"
-	".set\treorder"
+	".set\tpop"
 	: "=r" (first), "=r" (last), "=&r" (tmp)
 	: "0" (first), "1" (last));
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip22/ip22-setup.c linux-2.4.20/arch/mips/sgi-ip22/ip22-setup.c
--- linux-2.4.19/arch/mips/sgi-ip22/ip22-setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip22/ip22-setup.c	2002-10-29 11:18:33.000000000 +0000
@@ -28,6 +28,7 @@
 #include <asm/sgi/sgint23.h>
 #include <asm/time.h>
 #include <asm/gdb-stub.h>
+#include <asm/io.h>
 #include <asm/traps.h>
 
 #ifdef CONFIG_REMOTE_DEBUG
@@ -133,9 +134,7 @@
 
 void __init ip22_setup(void)
 {
-#ifdef CONFIG_SERIAL_CONSOLE
 	char *ctype;
-#endif
 #ifdef CONFIG_REMOTE_DEBUG
 	char *kgdb_ttyd;
 #endif
@@ -155,19 +154,27 @@
 #endif
 	conswitchp = NULL;
 
-#ifdef CONFIG_SERIAL_CONSOLE
+	/* Set the IO space to some sane value */
+	set_io_port_base (KSEG1ADDR (0x00080000));
+
 	/* ARCS console environment variable is set to "g?" for
 	 * graphics console, it is set to "d" for the first serial
 	 * line and "d2" for the second serial line.
 	 */
 	ctype = ArcGetEnvironmentVariable("console");
-	if(*ctype == 'd') {
-		if(*(ctype+1)=='2')
-			console_setup ("ttyS1");
+	if (*ctype == 'd') {
+#ifdef CONFIG_SERIAL_CONSOLE
+		if(*(ctype + 1) == '2')
+			console_setup("ttyS1");
 		else
-			console_setup ("ttyS0");
-	}
+			console_setup("ttyS0");
+#endif
+	} else {
+#ifdef CONFIG_ARC_CONSOLE
+		prom_flags &= PROM_FLAG_USE_AS_CONSOLE;
+		console_setup("ttyS0");
 #endif
+	}
 
 #ifdef CONFIG_REMOTE_DEBUG
 	kgdb_ttyd = prom_getcmdline();
@@ -190,20 +197,19 @@
 	}
 #endif
 
-#ifdef CONFIG_ARC_CONSOLE
-	console_setup("ttyS0");
-#endif
- 
 	sgi_volume_set(simple_strtoul(ArcGetEnvironmentVariable("volume"), NULL, 10));
 
-	{
-	  unsigned long *gfxinfo;
-	  long (*__vec)(void) = (void *) *(long *)((PROMBLOCK)->pvector + 0x20);
-	  gfxinfo = (unsigned long *)__vec();
-	  sgi_gfxaddr = gfxinfo[1] >= 0xa0000000 && gfxinfo[1] <= 0xc0000000 ? gfxinfo[1] - 0xa0000000 : 0;
-	}
 #ifdef CONFIG_VT
 #ifdef CONFIG_SGI_NEWPORT_CONSOLE
+	{
+		unsigned long *gfxinfo;
+		long (*__vec)(void) = (void *) *(long *)((PROMBLOCK)->pvector + 0x20);
+
+		gfxinfo = (unsigned long *)__vec();
+		sgi_gfxaddr = ((gfxinfo[1] >= 0xa0000000
+			       && gfxinfo[1] <= 0xc0000000)
+			       ? gfxinfo[1] - 0xa0000000 : 0);
+	}
 	/* newport addresses? */
 	if (sgi_gfxaddr == 0x1f0f0000 || sgi_gfxaddr == 0x1f4f0000) {
 		conswitchp = &newport_con;
@@ -223,9 +229,11 @@
 		conswitchp = &dummy_con;
 	}
 #else
+#ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
 #endif
 #endif
+#endif
 
 	rtc_ops = &indy_rtc_ops;
 	kbd_ops = &sgi_kbd_ops;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip22/ip22-system.c linux-2.4.20/arch/mips/sgi-ip22/ip22-system.c
--- linux-2.4.19/arch/mips/sgi-ip22/ip22-system.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip22/ip22-system.c	2002-10-29 11:18:34.000000000 +0000
@@ -34,7 +34,7 @@
 
 static int __init string_to_cpu(char *s)
 {
-	long cnt;
+	ULONG cnt;
 	char c;
 	int i;
 
@@ -57,7 +57,7 @@
 {
 	pcomponent *p, *toplev, *cpup = 0;
 	int cputype = -1;
-	long cnt;
+	ULONG cnt;
 	char c;
 
 
@@ -79,9 +79,9 @@
 				ArcRead(0, &c, 1, &cnt);
 				ArcEnterInteractiveMode();
 			}
-			printk("CPU: %s ", p->iname);
+			printk("CPU: %s ", (char *)p->iname);
 			cpup = p;
-			cputype = string_to_cpu(cpup->iname);
+			cputype = string_to_cpu((char *)cpup->iname);
 		}
 		p = ArcGetPeer(p);
 	}
@@ -97,7 +97,7 @@
 		case processor:
 			switch(p->type) {
 			case Fpu:
-				printk("FPU<%s> ", p->iname);
+				printk("FPU<%s> ", (char *)p->iname);
 				break;
 
 			default:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip22/ip22-time.c linux-2.4.20/arch/mips/sgi-ip22/ip22-time.c
--- linux-2.4.19/arch/mips/sgi-ip22/ip22-time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip22/ip22-time.c	2002-10-29 11:18:48.000000000 +0000
@@ -3,10 +3,10 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Time operations for IP22 machines. Original code may come from 
+ * Time operations for IP22 machines. Original code may come from
  * Ralf Baechle or David S. Miller (sorry guys, i'm really not sure)
  *
- * Copyright (C) 2001 by Ladislav Michl 
+ * Copyright (C) 2001 by Ladislav Michl
  */
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
@@ -28,7 +28,7 @@
  * uses 0 to 11.
  */
 static unsigned long indy_rtc_get_time(void)
-{	
+{
 	unsigned char yrs, mon, day, hrs, min, sec;
 	unsigned char save_control;
 
@@ -97,8 +97,8 @@
 static unsigned long dosample(volatile unsigned char *tcwp,
 			      volatile unsigned char *tc2p)
 {
-	unsigned long ct0, ct1;
-	unsigned char msb, lsb;
+	u32 ct0, ct1;
+	volatile u8 msb, lsb;
 
 	/* Start the counter. */
 	*tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MRGEN);
@@ -127,8 +127,8 @@
 	return ((ct1 - ct0) / 5000) * 5000;
 }
 
-/* 
- * Here we need to calibrate the cycle counter to at least be close. 
+/*
+ * Here we need to calibrate the cycle counter to at least be close.
  */
 void indy_time_init(void)
 {
@@ -165,7 +165,7 @@
 	if (r4k_ticks[0] != r4k_ticks[1]) {
 		printk ("warning: timer counts differ, retrying...");
 		r4k_ticks[2] = dosample (tcwp, tc2p);
-		if (r4k_ticks[2] == r4k_ticks[0] 
+		if (r4k_ticks[2] == r4k_ticks[0]
 		    || r4k_ticks[2] == r4k_ticks[1])
 			r4k_tick = r4k_ticks[2];
 		else {
@@ -179,12 +179,12 @@
 	printk("%d [%d.%02d MHz CPU]\n", (int) r4k_tick,
 		(int) (r4k_tick / 5000), (int) (r4k_tick % 5000) / 50);
 
-	mips_counter_frequency = r4k_tick * HZ;	
-	
+	mips_counter_frequency = r4k_tick * HZ;
+
 	/* HACK ALERT! This get's called after traps initialization
 	 * We piggyback the initialization of GIO bus here even though
 	 * it is technically not related with the timer in any way.
-	 * Doing it from ip22_setup wouldn't work since traps aren't 
+	 * Doing it from ip22_setup wouldn't work since traps aren't
 	 * initialized yet.
 	 */
 	sgigio_init();
@@ -225,7 +225,7 @@
 static void indy_timer_setup(struct irqaction *irq)
 {
 	unsigned long count;
-	
+
 	/* over-write the handler, we use our own way */
 	irq->handler = no_action;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip27/Makefile linux-2.4.20/arch/mips/sgi-ip27/Makefile
--- linux-2.4.19/arch/mips/sgi-ip27/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip27/Makefile	2002-10-29 11:18:38.000000000 +0000
@@ -0,0 +1,15 @@
+#
+# Makefile for the IP27 specific kernel interface routines under Linux.
+#
+
+USE_STANDARD_AS_RULE := true
+
+O_TARGET = ip27.o
+
+export-objs		= ip27-rtc.o
+
+obj-y	:= ip27-berr.o ip27-console.o ip27-irq.o ip27-init.o ip27-irq-glue.o \
+	   ip27-klconfig.o ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-pci.o \
+	   ip27-reset.o ip27-setup.o ip27-timer.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip27/TODO linux-2.4.20/arch/mips/sgi-ip27/TODO
--- linux-2.4.19/arch/mips/sgi-ip27/TODO	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip27/TODO	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,23 @@
+1. Need to figure out why PCI writes to the IOC3 hang, and if it is okay
+not to write to the IOC3 ever.
+2. Need to figure out RRB allocation in bridge_startup().
+3. Need to figure out why address swaizzling is needed in inw/outw for
+Qlogic scsi controllers.
+4. Need to integrate ip27-klconfig.c:find_lboard and
+ip27-init.c:find_lbaord_real. DONE
+5. Is it okay to set calias space on all nodes as 0, instead of 8k as
+in irix?
+6. Investigate why things do not work without the setup_test() call
+being invoked on all nodes in ip27-memory.c.
+7. Too many CLIs in the locore handlers :
+For the low level handlers set up by set_except_vector(),
+__tlb_refill_debug_tramp, __xtlb_refill_debug_tramp and cacheerror,
+investigate whether the code should do CLI, STI or KMODE.
+8. Too many do_page_faults invoked - investigate.
+9. start_thread must turn off UX64 ... and define tlb_refill_debug.
+10. Need a bad pmd table, bad pte table. __bad_pmd_table/__bad_pagetable
+does not agree with pgd_bad/pmd_bad.
+11. All intrs (ip27_do_irq handlers) are targetted at cpu A on the node.
+This might need to change later. Only the timer intr is set up to be
+received on both Cpu A and B. (ip27_do_irq()/bridge_startup())
+13. Cache flushing (specially the SMP version) has to be investigated.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip27/ip27-berr.c linux-2.4.20/arch/mips/sgi-ip27/ip27-berr.c
--- linux-2.4.19/arch/mips/sgi-ip27/ip27-berr.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip27/ip27-berr.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,93 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994, 1995, 1996, 1999, 2000 by Ralf Baechle
+ * Copyright (C) 1999, 2000 by Silicon Graphics
+ * Copyright (C) 2002  Maciej W. Rozycki
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/module.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/arch.h>
+#include <asm/sn/sn0/hub.h>
+#include <asm/traps.h>
+#include <asm/uaccess.h>
+
+extern void dump_tlb_addr(unsigned long addr);
+extern void dump_tlb_all(void);
+
+static void dump_hub_information(unsigned long errst0, unsigned long errst1)
+{
+	static char *err_type[2][8] = {
+		{ NULL, "Uncached Partial Read PRERR", "DERR", "Read Timeout",
+		  NULL, NULL, NULL, NULL },
+		{ "WERR", "Uncached Partial Write", "PWERR", "Write Timeout",
+		  NULL, NULL, NULL, NULL }
+	};
+	int wrb = errst1 & PI_ERR_ST1_WRBRRB_MASK;
+
+	if (!(errst0 & PI_ERR_ST0_VALID_MASK)) {
+		printk("Hub does not contain valid error information\n");
+		return;
+	}
+
+
+	printk("Hub has valid error information:\n");
+	if (errst0 & PI_ERR_ST0_OVERRUN_MASK)
+		printk("Overrun is set.  Error stack may contain additional "
+		       "information.\n");
+	printk("Hub error address is %08lx\n",
+	       (errst0 & PI_ERR_ST0_ADDR_MASK) >> (PI_ERR_ST0_ADDR_SHFT - 3));
+	printk("Incoming message command 0x%lx\n",
+	       (errst0 & PI_ERR_ST0_CMD_MASK) >> PI_ERR_ST0_CMD_SHFT);
+	printk("Supplemental field of incoming message is 0x%lx\n",
+	       (errst0 & PI_ERR_ST0_SUPPL_MASK) >> PI_ERR_ST0_SUPPL_SHFT);
+	printk("T5 Rn (for RRB only) is 0x%lx\n",
+	       (errst0 & PI_ERR_ST0_REQNUM_MASK) >> PI_ERR_ST0_REQNUM_SHFT);
+	printk("Error type is %s\n", err_type[wrb]
+	       [(errst0 & PI_ERR_ST0_TYPE_MASK) >> PI_ERR_ST0_TYPE_SHFT]
+		? : "invalid");
+}
+
+int be_ip27_handler(struct pt_regs *regs, int is_fixup)
+{
+	unsigned long errst0, errst1;
+	int data = regs->cp0_cause & 4;
+	int cpu = LOCAL_HUB_L(PI_CPU_NUM);
+
+	if (is_fixup)
+		return MIPS_BE_FIXUP;
+
+	printk("Slice %c got %cbe at 0x%lx\n", 'A' + cpu, data ? 'd' : 'i',
+	       regs->cp0_epc);
+	printk("Hub information:\n");
+	printk("ERR_INT_PEND = 0x%06lx\n", LOCAL_HUB_L(PI_ERR_INT_PEND));
+	errst0 = LOCAL_HUB_L(cpu ? PI_ERR_STATUS0_B : PI_ERR_STATUS0_A);
+	errst1 = LOCAL_HUB_L(cpu ? PI_ERR_STATUS1_B : PI_ERR_STATUS1_A);
+	dump_hub_information(errst0, errst1);
+	show_regs(regs);
+	dump_tlb_all();
+	while(1);
+	force_sig(SIGBUS, current);
+}
+
+void __init bus_error_init(void)
+{
+	/* XXX Initialize all the Hub & Bridge error handling here.  */
+	int cpu = LOCAL_HUB_L(PI_CPU_NUM);
+	int cpuoff = cpu << 8;
+
+	be_board_handler = be_ip27_handler;
+
+	LOCAL_HUB_S(PI_ERR_INT_PEND,
+	            cpu ? PI_ERR_CLEAR_ALL_B : PI_ERR_CLEAR_ALL_A);
+	LOCAL_HUB_S(PI_ERR_INT_MASK_A + cpuoff, 0);
+	LOCAL_HUB_S(PI_ERR_STACK_ADDR_A + cpuoff, 0);
+	LOCAL_HUB_S(PI_ERR_STACK_SIZE, 0);	/* Disable error stack */
+	LOCAL_HUB_S(PI_SYSAD_ERRCHK_EN, PI_SYSAD_CHECK_ALL);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip27/ip27-console.c linux-2.4.20/arch/mips/sgi-ip27/ip27-console.c
--- linux-2.4.19/arch/mips/sgi-ip27/ip27-console.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip27/ip27-console.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,58 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 Ralf Baechle
+ */
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/sn0/hub.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/ioc3.h>
+#include <asm/sn/sn_private.h>
+
+void prom_putchar(char c)
+{
+	struct ioc3 *ioc3;
+	struct ioc3_uartregs *uart;
+
+	ioc3 = (struct ioc3 *)KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base;
+	uart = &ioc3->sregs.uarta;
+
+	while ((uart->iu_lsr & 0x20) == 0);
+	uart->iu_thr = c;
+}
+
+char __init prom_getchar(void)
+{
+	return 0;
+}
+
+static void
+ip27prom_console_write(struct console *con, const char *s, unsigned n)
+{
+	prom_printf("%s", s);
+}
+
+static kdev_t
+ip27prom_console_dev(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+static struct console ip27_prom_console = {
+    name:	"prom",
+    write:	ip27prom_console_write,
+    device:	ip27prom_console_dev,
+    flags:	CON_PRINTBUFFER,
+    index:	-1,
+};
+
+__init void ip27_setup_console(void)
+{
+	register_console(&ip27_prom_console);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip27/ip27-init.c linux-2.4.20/arch/mips/sgi-ip27/ip27-init.c
--- linux-2.4.19/arch/mips/sgi-ip27/ip27-init.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip27/ip27-init.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,838 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * Copyright (C) 2000 - 2001 by Kanoj Sarcar (kanoj@sgi.com)
+ * Copyright (C) 2000 - 2001 by Silicon Graphics, Inc.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/mmzone.h>	/* for numnodes */
+#include <linux/mm.h>
+#include <asm/cpu.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/sn/types.h>
+#include <asm/sn/sn0/addrs.h>
+#include <asm/sn/sn0/hubni.h>
+#include <asm/sn/sn0/hubio.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/ioc3.h>
+#include <asm/mipsregs.h>
+#include <asm/sn/gda.h>
+#include <asm/sn/intr.h>
+#include <asm/current.h>
+#include <asm/smp.h>
+#include <asm/processor.h>
+#include <asm/mmu_context.h>
+#include <asm/sn/launch.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/sn0/ip27.h>
+#include <asm/sn/mapped_kernel.h>
+#include <asm/sn/sn0/addrs.h>
+#include <asm/sn/gda.h>
+
+#define CPU_NONE		(cpuid_t)-1
+
+/*
+ * The following should work till 64 nodes, ie 128p SN0s.
+ */
+#define CNODEMASK_CLRALL(p)	(p) = 0
+#define CNODEMASK_TSTB(p, bit)	((p) & (1ULL << (bit)))
+#define CNODEMASK_SETB(p, bit)	((p) |= 1ULL << (bit))
+
+cpumask_t	boot_cpumask;
+hubreg_t	region_mask = 0;
+static int	fine_mode = 0;
+int		maxcpus;
+static spinlock_t hub_mask_lock = SPIN_LOCK_UNLOCKED;
+static cnodemask_t hub_init_mask;
+static atomic_t numstarted = ATOMIC_INIT(1);
+static int router_distance;
+nasid_t master_nasid = INVALID_NASID;
+
+cnodeid_t	nasid_to_compact_node[MAX_NASIDS];
+nasid_t		compact_to_nasid_node[MAX_COMPACT_NODES];
+cnodeid_t	cpuid_to_compact_node[MAXCPUS];
+char		node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
+
+hubreg_t get_region(cnodeid_t cnode)
+{
+	if (fine_mode)
+		return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_FINEREG_SHFT;
+	else
+		return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_COARSEREG_SHFT;
+}
+
+static void gen_region_mask(hubreg_t *region_mask, int maxnodes)
+{
+	cnodeid_t cnode;
+
+	(*region_mask) = 0;
+	for (cnode = 0; cnode < maxnodes; cnode++) {
+		(*region_mask) |= 1ULL << get_region(cnode);
+	}
+}
+
+int is_fine_dirmode(void)
+{
+	return (((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK)
+		>> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE);
+}
+
+nasid_t get_actual_nasid(lboard_t *brd)
+{
+	klhub_t *hub;
+
+	if (!brd)
+		return INVALID_NASID;
+
+	/* find out if we are a completely disabled brd. */
+	hub  = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
+	if (!hub)
+		return INVALID_NASID;
+	if (!(hub->hub_info.flags & KLINFO_ENABLE))	/* disabled node brd */
+		return hub->hub_info.physid;
+	else
+		return brd->brd_nasid;
+}
+
+/* Tweak this for maximum number of CPUs to activate */
+static int max_cpus = NR_CPUS;
+
+int do_cpumask(cnodeid_t cnode, nasid_t nasid, cpumask_t *boot_cpumask,
+							int *highest)
+{
+	static int tot_cpus_found = 0;
+	lboard_t *brd;
+	klcpu_t *acpu;
+	int cpus_found = 0;
+	cpuid_t cpuid;
+
+	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
+
+	do {
+		acpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU);
+		while (acpu) {
+			cpuid = acpu->cpu_info.virtid;
+			/* cnode is not valid for completely disabled brds */
+			if (get_actual_nasid(brd) == brd->brd_nasid)
+				cpuid_to_compact_node[cpuid] = cnode;
+			if (cpuid > *highest)
+				*highest = cpuid;
+			/* Only let it join in if it's marked enabled */
+			if ((acpu->cpu_info.flags & KLINFO_ENABLE) &&
+						(tot_cpus_found != max_cpus)) {
+				CPUMASK_SETB(*boot_cpumask, cpuid);
+				cpus_found++;
+				tot_cpus_found++;
+			}
+			acpu = (klcpu_t *)find_component(brd, (klinfo_t *)acpu,
+								KLSTRUCT_CPU);
+		}
+		brd = KLCF_NEXT(brd);
+		if (brd)
+			brd = find_lboard(brd,KLTYPE_IP27);
+		else
+			break;
+	} while (brd);
+
+	return cpus_found;
+}
+
+cpuid_t cpu_node_probe(cpumask_t *boot_cpumask, int *numnodes)
+{
+	int i, cpus = 0, highest = 0;
+	gda_t *gdap = GDA;
+	nasid_t nasid;
+
+	/*
+	 * Initialize the arrays to invalid nodeid (-1)
+	 */
+	for (i = 0; i < MAX_COMPACT_NODES; i++)
+		compact_to_nasid_node[i] = INVALID_NASID;
+	for (i = 0; i < MAX_NASIDS; i++)
+		nasid_to_compact_node[i] = INVALID_CNODEID;
+	for (i = 0; i < MAXCPUS; i++)
+		cpuid_to_compact_node[i] = INVALID_CNODEID;
+
+	*numnodes = 0;
+	for (i = 0; i < MAX_COMPACT_NODES; i++) {
+		if ((nasid = gdap->g_nasidtable[i]) == INVALID_NASID) {
+			break;
+		} else {
+			compact_to_nasid_node[i] = nasid;
+			nasid_to_compact_node[nasid] = i;
+			(*numnodes)++;
+			cpus += do_cpumask(i, nasid, boot_cpumask, &highest);
+		}
+	}
+
+	/*
+	 * Cpus are numbered in order of cnodes. Currently, disabled
+	 * cpus are not numbered.
+	 */
+
+	return(highest + 1);
+}
+
+int cpu_enabled(cpuid_t cpu)
+{
+	if (cpu == CPU_NONE)
+		return 0;
+	return (CPUMASK_TSTB(boot_cpumask, cpu) != 0);
+}
+
+void mlreset (void)
+{
+	int i;
+	void init_topology_matrix(void);
+	void dump_topology(void);
+
+
+	master_nasid = get_nasid();
+	fine_mode = is_fine_dirmode();
+
+	/*
+	 * Probe for all CPUs - this creates the cpumask and
+	 * sets up the mapping tables.
+	 */
+	CPUMASK_CLRALL(boot_cpumask);
+	maxcpus = cpu_node_probe(&boot_cpumask, &numnodes);
+	printk("Discovered %d cpus on %d nodes\n", maxcpus, numnodes);
+
+	init_topology_matrix();
+	dump_topology();
+
+	gen_region_mask(&region_mask, numnodes);
+	CNODEMASK_CLRALL(hub_init_mask);
+
+	setup_replication_mask(numnodes);
+
+	/*
+	 * Set all nodes' calias sizes to 8k
+	 */
+	for (i = 0; i < numnodes; i++) {
+		nasid_t nasid;
+
+		nasid = COMPACT_TO_NASID_NODEID(i);
+
+		/*
+		 * Always have node 0 in the region mask, otherwise
+		 * CALIAS accesses get exceptions since the hub
+		 * thinks it is a node 0 address.
+		 */
+		REMOTE_HUB_S(nasid, PI_REGION_PRESENT, (region_mask | 1));
+#ifdef CONFIG_REPLICATE_EXHANDLERS
+		REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_8K);
+#else
+		REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_0);
+#endif
+
+#ifdef LATER
+		/*
+		 * Set up all hubs to have a big window pointing at
+		 * widget 0. Memory mode, widget 0, offset 0
+		 */
+		REMOTE_HUB_S(nasid, IIO_ITTE(SWIN0_BIGWIN),
+			((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) |
+			(0 << IIO_ITTE_WIDGET_SHIFT)));
+#endif
+	}
+}
+
+
+void intr_clear_bits(nasid_t nasid, volatile hubreg_t *pend, int base_level,
+							char *name)
+{
+	volatile hubreg_t bits;
+	int i;
+
+	/* Check pending interrupts */
+	if ((bits = HUB_L(pend)) != 0)
+		for (i = 0; i < N_INTPEND_BITS; i++)
+			if (bits & (1 << i))
+				LOCAL_HUB_CLR_INTR(base_level + i);
+}
+
+void intr_clear_all(nasid_t nasid)
+{
+	REMOTE_HUB_S(nasid, PI_INT_MASK0_A, 0);
+	REMOTE_HUB_S(nasid, PI_INT_MASK0_B, 0);
+	REMOTE_HUB_S(nasid, PI_INT_MASK1_A, 0);
+	REMOTE_HUB_S(nasid, PI_INT_MASK1_B, 0);
+	intr_clear_bits(nasid, REMOTE_HUB_ADDR(nasid, PI_INT_PEND0),
+		INT_PEND0_BASELVL, "INT_PEND0");
+	intr_clear_bits(nasid, REMOTE_HUB_ADDR(nasid, PI_INT_PEND1),
+		INT_PEND1_BASELVL, "INT_PEND1");
+}
+
+void sn_mp_setup(void)
+{
+	cnodeid_t	cnode;
+#if 0
+	cpuid_t		cpu;
+#endif
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+#if 0
+		init_platform_nodepda();
+#endif
+		intr_clear_all(COMPACT_TO_NASID_NODEID(cnode));
+	}
+#if 0
+	for (cpu = 0; cpu < maxcpus; cpu++) {
+		init_platform_pda();
+	}
+#endif
+}
+
+void per_hub_init(cnodeid_t cnode)
+{
+	extern void pcibr_setup(cnodeid_t);
+	cnodemask_t	done;
+	nasid_t		nasid;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+	spin_lock(&hub_mask_lock);
+	/* Test our bit. */
+	if (!(done = CNODEMASK_TSTB(hub_init_mask, cnode))) {
+		/* Turn our bit on in the mask. */
+		CNODEMASK_SETB(hub_init_mask, cnode);
+		/*
+	 	 * Do the actual initialization if it hasn't been done yet.
+	 	 * We don't need to hold a lock for this work.
+	 	 */
+		/*
+		 * Set CRB timeout at 5ms, (< PI timeout of 10ms)
+		 */
+		REMOTE_HUB_S(nasid, IIO_ICTP, 0x800);
+		REMOTE_HUB_S(nasid, IIO_ICTO, 0xff);
+		hub_rtc_init(cnode);
+		pcibr_setup(cnode);
+#ifdef CONFIG_REPLICATE_EXHANDLERS
+		/*
+		 * If this is not a headless node initialization,
+		 * copy over the caliased exception handlers.
+		 */
+		if (get_compact_nodeid() == cnode) {
+			extern char except_vec0, except_vec1_r10k;
+			extern char except_vec2_generic, except_vec3_generic;
+
+			memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic,
+								0x80);
+			memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic,
+								0x80);
+			memcpy((void *)KSEG0, &except_vec0, 0x80);
+			memcpy((void *)KSEG0 + 0x080, &except_vec1_r10k, 0x80);
+			memcpy((void *)(KSEG0 + 0x100), (void *) KSEG0, 0x80);
+			memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic,
+								0x100);
+			flush_cache_l1();
+			flush_cache_l2();
+		}
+#endif
+	}
+	spin_unlock(&hub_mask_lock);
+}
+
+/*
+ * This is similar to hard_smp_processor_id().
+ */
+cpuid_t getcpuid(void)
+{
+	klcpu_t *klcpu;
+
+	klcpu = nasid_slice_to_cpuinfo(get_nasid(),LOCAL_HUB_L(PI_CPU_NUM));
+	return klcpu->cpu_info.virtid;
+}
+
+void per_cpu_init(void)
+{
+	extern void install_cpu_nmi_handler(int slice);
+	extern void load_mmu(void);
+	static int is_slave = 0;
+	int cpu = smp_processor_id();
+	cnodeid_t cnode = get_compact_nodeid();
+
+	TLBMISS_HANDLER_SETUP();
+#if 0
+	intr_init();
+#endif
+	clear_cp0_status(ST0_IM);
+	per_hub_init(cnode);
+	cpu_time_init();
+	if (smp_processor_id())	/* master can't do this early, no kmalloc */
+		install_cpuintr(cpu);
+	/* Install our NMI handler if symmon hasn't installed one. */
+	install_cpu_nmi_handler(cputoslice(cpu));
+#if 0
+	install_tlbintr(cpu);
+#endif
+	set_cp0_status(SRB_DEV0 | SRB_DEV1);
+	if (is_slave) {
+		clear_cp0_status(ST0_BEV);
+		if (mips_cpu.isa_level == MIPS_CPU_ISA_IV)
+			set_cp0_status(ST0_XX);
+		set_cp0_status(ST0_KX|ST0_SX|ST0_UX);
+		sti();
+		load_mmu();
+		atomic_inc(&numstarted);
+	} else {
+		is_slave = 1;
+	}
+}
+
+cnodeid_t get_compact_nodeid(void)
+{
+	nasid_t nasid;
+
+	nasid = get_nasid();
+	/*
+	 * Map the physical node id to a virtual node id (virtual node ids
+	 * are contiguous).
+	 */
+	return NASID_TO_COMPACT_NODEID(nasid);
+}
+
+#ifdef CONFIG_SMP
+
+/*
+ * Takes as first input the PROM assigned cpu id, and the kernel
+ * assigned cpu id as the second.
+ */
+static void alloc_cpupda(cpuid_t cpu, int cpunum)
+{
+	cnodeid_t	node;
+	nasid_t		nasid;
+
+	node = get_cpu_cnode(cpu);
+	nasid = COMPACT_TO_NASID_NODEID(node);
+
+	cputonasid(cpunum) = nasid;
+	cputocnode(cpunum) = node;
+	cputoslice(cpunum) = get_cpu_slice(cpu);
+	cpu_data[cpunum].p_cpuid = cpu;
+}
+
+static volatile cpumask_t boot_barrier;
+
+void __init start_secondary(void)
+{
+	CPUMASK_CLRB(boot_barrier, getcpuid());	/* needs atomicity */
+	per_cpu_init();
+	per_cpu_trap_init();
+#if 0
+	ecc_init();
+	bte_lateinit();
+	init_mfhi_war();
+#endif
+	local_flush_tlb_all();
+	flush_cache_l1();
+	flush_cache_l2();
+	start_secondary();
+}
+
+__init void allowboot(void)
+{
+	int		num_cpus = 0;
+	cpuid_t		cpu, mycpuid = getcpuid();
+	cnodeid_t	cnode;
+	extern void	smp_bootstrap(void);
+
+	sn_mp_setup();
+	/* Master has already done per_cpu_init() */
+	install_cpuintr(smp_processor_id());
+#if 0
+	bte_lateinit();
+	ecc_init();
+#endif
+
+	replicate_kernel_text(numnodes);
+	boot_barrier = boot_cpumask;
+	/* Launch slaves. */
+	for (cpu = 0; cpu < maxcpus; cpu++) {
+		if (cpu == mycpuid) {
+			alloc_cpupda(cpu, num_cpus);
+			num_cpus++;
+			/* We're already started, clear our bit */
+			CPUMASK_CLRB(boot_barrier, cpu);
+			continue;
+		}
+
+		/* Skip holes in CPU space */
+		if (CPUMASK_TSTB(boot_cpumask, cpu)) {
+			struct task_struct *p;
+
+			/*
+			 * The following code is purely to make sure
+			 * Linux can schedule processes on this slave.
+			 */
+			kernel_thread(0, NULL, CLONE_PID);
+			p = init_task.prev_task;
+			sprintf(p->comm, "%s%d", "Idle", num_cpus);
+			init_tasks[num_cpus] = p;
+			alloc_cpupda(cpu, num_cpus);
+			del_from_runqueue(p);
+			p->processor = num_cpus;
+			p->cpus_runnable = 1 << num_cpus; /* we schedule the first task manually */
+			unhash_process(p);
+			/* Attach to the address space of init_task. */
+			atomic_inc(&init_mm.mm_count);
+			p->active_mm = &init_mm;
+
+			/*
+		 	 * Launch a slave into smp_bootstrap().
+		 	 * It doesn't take an argument, and we
+			 * set sp to the kernel stack of the newly
+			 * created idle process, gp to the proc struct
+			 * (so that current-> works).
+		 	 */
+			LAUNCH_SLAVE(cputonasid(num_cpus),cputoslice(num_cpus),
+				(launch_proc_t)MAPPED_KERN_RW_TO_K0(smp_bootstrap),
+				0, (void *)((unsigned long)p +
+				KERNEL_STACK_SIZE - 32), (void *)p);
+
+			/*
+			 * Now optimistically set the mapping arrays. We
+			 * need to wait here, verify the cpu booted up, then
+			 * fire up the next cpu.
+			 */
+			__cpu_number_map[cpu] = num_cpus;
+			__cpu_logical_map[num_cpus] = cpu;
+			CPUMASK_SETB(cpu_online_map, cpu);
+			num_cpus++;
+			/*
+			 * Wait this cpu to start up and initialize its hub,
+			 * and discover the io devices it will control.
+			 *
+			 * XXX: We really want to fire up launch all the CPUs
+			 * at once.  We have to preserve the order of the
+			 * devices on the bridges first though.
+			 */
+			while(atomic_read(&numstarted) != num_cpus);
+		}
+	}
+
+
+#ifdef LATER
+	Wait logic goes here.
+#endif
+	for (cnode = 0; cnode < numnodes; cnode++) {
+#if 0
+		if (cnodetocpu(cnode) == -1) {
+			printk("Initializing headless hub,cnode %d", cnode);
+			per_hub_init(cnode);
+		}
+#endif
+	}
+#if 0
+	cpu_io_setup();
+	init_mfhi_war();
+#endif
+	smp_num_cpus = num_cpus;
+}
+
+void __init smp_boot_cpus(void)
+{
+	extern void allowboot(void);
+
+	init_new_context(current, &init_mm);
+	current->processor = 0;
+	init_idle();
+	smp_tune_scheduling();
+	allowboot();
+}
+
+#else /* CONFIG_SMP */
+void __init start_secondary(void)
+{
+	/* XXX Why do we need this empty definition at all?  */
+}
+#endif /* CONFIG_SMP */
+
+
+#define	rou_rflag	rou_flags
+
+void
+router_recurse(klrou_t *router_a, klrou_t *router_b, int depth)
+{
+	klrou_t *router;
+	lboard_t *brd;
+	int	port;
+
+	if (router_a->rou_rflag == 1)
+		return;
+
+	if (depth >= router_distance)
+		return;
+
+	router_a->rou_rflag = 1;
+
+	for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
+		if (router_a->rou_port[port].port_nasid == INVALID_NASID)
+			continue;
+
+		brd = (lboard_t *)NODE_OFFSET_TO_K0(
+			router_a->rou_port[port].port_nasid,
+			router_a->rou_port[port].port_offset);
+
+		if (brd->brd_type == KLTYPE_ROUTER) {
+			router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
+			if (router == router_b) {
+				if (depth < router_distance)
+					router_distance = depth;
+			}
+			else
+				router_recurse(router, router_b, depth + 1);
+		}
+	}
+
+	router_a->rou_rflag = 0;
+}
+
+int
+node_distance(nasid_t nasid_a, nasid_t nasid_b)
+{
+	nasid_t nasid;
+	cnodeid_t cnode;
+	lboard_t *brd, *dest_brd;
+	int port;
+	klrou_t *router, *router_a = NULL, *router_b = NULL;
+
+	/* Figure out which routers nodes in question are connected to */
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+		if (nasid == -1) continue;
+
+		brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
+					KLTYPE_ROUTER);
+
+		if (!brd)
+			continue;
+
+		do {
+			if (brd->brd_flags & DUPLICATE_BOARD)
+				continue;
+
+			router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
+			router->rou_rflag = 0;
+
+			for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
+				if (router->rou_port[port].port_nasid == INVALID_NASID)
+					continue;
+
+				dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
+					router->rou_port[port].port_nasid,
+					router->rou_port[port].port_offset);
+
+				if (dest_brd->brd_type == KLTYPE_IP27) {
+					if (dest_brd->brd_nasid == nasid_a)
+						router_a = router;
+					if (dest_brd->brd_nasid == nasid_b)
+						router_b = router;
+				}
+			}
+
+		} while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
+	}
+
+	if (router_a == NULL) {
+		printk("node_distance: router_a NULL\n");
+		return -1;
+	}
+	if (router_b == NULL) {
+		printk("node_distance: router_b NULL\n");
+		return -1;
+	}
+
+	if (nasid_a == nasid_b)
+		return 0;
+
+	if (router_a == router_b)
+		return 1;
+
+	router_distance = 100;
+	router_recurse(router_a, router_b, 2);
+
+	return router_distance;
+}
+
+void
+init_topology_matrix(void)
+{
+	nasid_t nasid, nasid2;
+	cnodeid_t row, col;
+
+	for (row = 0; row < MAX_COMPACT_NODES; row++)
+		for (col = 0; col < MAX_COMPACT_NODES; col++)
+			node_distances[row][col] = -1;
+
+	for (row = 0; row < numnodes; row++) {
+		nasid = COMPACT_TO_NASID_NODEID(row);
+		for (col = 0; col < numnodes; col++) {
+			nasid2 = COMPACT_TO_NASID_NODEID(col);
+			node_distances[row][col] = node_distance(nasid, nasid2);
+		}
+	}
+}
+
+void
+dump_topology(void)
+{
+	nasid_t nasid;
+	cnodeid_t cnode;
+	lboard_t *brd, *dest_brd;
+	int port;
+	int router_num = 0;
+	klrou_t *router;
+	cnodeid_t row, col;
+
+	printk("************** Topology ********************\n");
+
+	printk("    ");
+	for (col = 0; col < numnodes; col++)
+		printk("%02d ", col);
+	printk("\n");
+	for (row = 0; row < numnodes; row++) {
+		printk("%02d  ", row);
+		for (col = 0; col < numnodes; col++)
+			printk("%2d ", node_distances[row][col]);
+		printk("\n");
+	}
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+		if (nasid == -1) continue;
+
+		brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
+					KLTYPE_ROUTER);
+
+		if (!brd)
+			continue;
+
+		do {
+			if (brd->brd_flags & DUPLICATE_BOARD)
+				continue;
+			printk("Router %d:", router_num);
+			router_num++;
+
+			router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
+
+			for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
+				if (router->rou_port[port].port_nasid == INVALID_NASID)
+					continue;
+
+				dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
+					router->rou_port[port].port_nasid,
+					router->rou_port[port].port_offset);
+
+				if (dest_brd->brd_type == KLTYPE_IP27)
+					printk(" %d", dest_brd->brd_nasid);
+				if (dest_brd->brd_type == KLTYPE_ROUTER)
+					printk(" r");
+			}
+			printk("\n");
+
+		} while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
+	}
+}
+
+#if 0
+#define		brd_widgetnum	brd_slot
+#define NODE_OFFSET_TO_KLINFO(n,off)    ((klinfo_t*) TO_NODE_CAC(n,off))
+void
+dump_klcfg(void)
+{
+	cnodeid_t       cnode;
+	int i;
+	nasid_t         nasid;
+	lboard_t        *lbptr;
+	gda_t           *gdap;
+
+	gdap = (gda_t *)GDA_ADDR(get_nasid());
+	if (gdap->g_magic != GDA_MAGIC) {
+		printk("dumpklcfg_cmd: Invalid GDA MAGIC\n");
+		return;
+	}
+
+	for (cnode = 0; cnode < MAX_COMPACT_NODES; cnode ++) {
+		nasid = gdap->g_nasidtable[cnode];
+
+		if (nasid == INVALID_NASID)
+			continue;
+
+		printk("\nDumpping klconfig Nasid %d:\n", nasid);
+
+		lbptr = KL_CONFIG_INFO(nasid);
+
+		while (lbptr) {
+			printk("    %s, Nasid %d, Module %d, widget 0x%x, partition %d, NIC 0x%x lboard 0x%lx",
+				"board name here", /* BOARD_NAME(lbptr->brd_type), */
+				lbptr->brd_nasid, lbptr->brd_module,
+				lbptr->brd_widgetnum,
+				lbptr->brd_partition,
+				(lbptr->brd_nic), lbptr);
+			if (lbptr->brd_flags & DUPLICATE_BOARD)
+				printk(" -D");
+			printk("\n");
+			for (i = 0; i < lbptr->brd_numcompts; i++) {
+				klinfo_t *kli;
+				kli = NODE_OFFSET_TO_KLINFO(NASID_GET(lbptr), lbptr->brd_compts[i]);
+				printk("        type %2d, flags 0x%04x, diagval %3d, physid %4d, virtid %2d: %s\n",
+					kli->struct_type,
+					kli->flags,
+					kli->diagval,
+					kli->physid,
+					kli->virtid,
+					"comp. name here");
+					/* COMPONENT_NAME(kli->struct_type)); */
+			}
+			lbptr = KLCF_NEXT(lbptr);
+		}
+	}
+	printk("\n");
+
+	/* Useful to print router maps also */
+
+	for (cnode = 0; cnode < MAX_COMPACT_NODES; cnode ++) {
+		klrou_t *kr;
+		int i;
+
+        	nasid = gdap->g_nasidtable[cnode];
+        	if (nasid == INVALID_NASID)
+            		continue;
+        	lbptr = KL_CONFIG_INFO(nasid);
+
+        	while (lbptr) {
+
+			lbptr = find_lboard_class(lbptr, KLCLASS_ROUTER);
+			if(!lbptr)
+				break;
+			if (!KL_CONFIG_DUPLICATE_BOARD(lbptr)) {
+				printk("%llx -> \n", lbptr->brd_nic);
+				kr = (klrou_t *)find_first_component(lbptr,
+					KLSTRUCT_ROU);
+				for (i = 1; i <= MAX_ROUTER_PORTS; i++) {
+					printk("[%d, %llx]; ",
+						kr->rou_port[i].port_nasid,
+						kr->rou_port[i].port_offset);
+				}
+				printk("\n");
+			}
+			lbptr = KLCF_NEXT(lbptr);
+        	}
+        	printk("\n");
+    	}
+
+	dump_topology();
+}
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip27/ip27-irq-glue.S linux-2.4.20/arch/mips/sgi-ip27/ip27-irq-glue.S
--- linux-2.4.19/arch/mips/sgi-ip27/ip27-irq-glue.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip27/ip27-irq-glue.S	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,64 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999 Ralf Baechle
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ */
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+	.text
+	.set	noat
+	.align	5
+NESTED(ip27_irq, PT_SIZE, sp)
+	SAVE_ALL
+	CLI
+	.set	at
+
+	/* IP27 may signal interrupt which we're not interested in.
+	   Mask them out.  */
+	mfc0	s0, CP0_CAUSE
+	mfc0	t0, CP0_STATUS
+	and	s0, t0
+
+	/* First check for RT interrupt.  */
+	andi	a0, s0, CAUSEF_IP4
+	beqz	a0, 1f
+
+	/* Ok, a timer interrupt. */
+	move	a0, sp
+	jal	rt_timer_interrupt
+
+	j	ret_from_irq
+
+1:	andi	a0, s0, (CAUSEF_IP2 | CAUSEF_IP3)
+	beqz	a0, 1f
+
+	/* ... a device interrupt ...  */
+	move	a0, sp
+	jal	ip27_do_irq
+
+	j	ret_from_irq
+
+1:
+#if 1
+	mfc0	a1, CP0_STATUS
+	srl	a1, a1, 8
+	andi	a1, 0xff
+
+	mfc0	a2, CP0_CAUSE
+	srl	a2, a2, 8
+	andi	a2, 0xff
+
+	move	a3, s0
+	PRINT("Spurious interrupt, c0_status = %02x, c0_cause = %02x, pending %02x.\n")
+	ld	a1, PT_EPC(sp)
+0:	b	0b
+#endif
+
+	j	ret_from_irq
+	END(ip27_irq)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip27/ip27-irq.c linux-2.4.20/arch/mips/sgi-ip27/ip27-irq.c
--- linux-2.4.19/arch/mips/sgi-ip27/ip27-irq.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip27/ip27-irq.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,487 @@
+/*
+ * ip27-irq.c: Highlevel interrupt handling for IP27 architecture.
+ *
+ * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 1999 - 2001 Kanoj Sarcar
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+
+#include <asm/bitops.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/pci/bridge.h>
+#include <asm/sn/sn0/hub.h>
+#include <asm/sn/sn0/ip27.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/agent.h>
+#include <asm/sn/arch.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/intr_public.h>
+
+
+#undef DEBUG_IRQ
+#ifdef DEBUG_IRQ
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/* These should die */
+unsigned char bus_to_wid[256];	/* widget id for linux pci bus */
+unsigned char bus_to_nid[256];	/* nasid for linux pci bus */
+unsigned char num_bridges;	/* number of bridges in the system */
+
+/*
+ * Linux has a controller-independent x86 interrupt architecture.
+ * every controller has a 'controller-template', that is used
+ * by the main code to do the right thing. Each driver-visible
+ * interrupt source is transparently wired to the apropriate
+ * controller. Thus drivers need not be aware of the
+ * interrupt-controller.
+ *
+ * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
+ * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
+ * (IO-APICs assumed to be messaging to Pentium local-APICs)
+ *
+ * the code is designed to be easily extended with new/different
+ * interrupt controllers, without having to do assembly magic.
+ */
+
+extern asmlinkage void ip27_irq(void);
+extern void do_IRQ(int irq, struct pt_regs *regs);
+
+extern int irq_to_bus[], irq_to_slot[], bus_to_cpu[];
+int intr_connect_level(int cpu, int bit);
+int intr_disconnect_level(int cpu, int bit);
+
+/*
+ * There is a single intpend register per node, and we want to have
+ * distinct levels for intercpu intrs for both cpus A and B on a node.
+ */
+int node_level_to_irq[MAX_COMPACT_NODES][PERNODE_LEVELS];
+
+/*
+ * use these macros to get the encoded nasid and widget id
+ * from the irq value
+ */
+#define IRQ_TO_BUS(i)			irq_to_bus[(i)]
+#define IRQ_TO_CPU(i)			bus_to_cpu[IRQ_TO_BUS(i)]
+#define NASID_FROM_PCI_IRQ(i)		bus_to_nid[IRQ_TO_BUS(i)]
+#define WID_FROM_PCI_IRQ(i)		bus_to_wid[IRQ_TO_BUS(i)]
+#define	SLOT_FROM_PCI_IRQ(i)		irq_to_slot[i]
+
+static inline int alloc_level(cpuid_t cpunum, int irq)
+{
+	cnodeid_t nodenum = CPUID_TO_COMPACT_NODEID(cpunum);
+	int j = LEAST_LEVEL + 3;	/* resched & crosscall entries taken */
+
+	while (++j < PERNODE_LEVELS) {
+		if (node_level_to_irq[nodenum][j] == -1) {
+			node_level_to_irq[nodenum][j] = irq;
+			return j;
+		}
+	}
+	printk("Cpu %ld flooded with devices\n", cpunum);
+	while(1);
+	return -1;
+}
+
+static inline int find_level(cpuid_t *cpunum, int irq)
+{
+	int j;
+	cnodeid_t nodenum = INVALID_CNODEID;
+
+	while (++nodenum < MAX_COMPACT_NODES) {
+		j = LEAST_LEVEL + 3;	/* resched & crosscall entries taken */
+		while (++j < PERNODE_LEVELS)
+			if (node_level_to_irq[nodenum][j] == irq) {
+				*cpunum = 0;	/* XXX Fixme */
+				return(j);
+			}
+	}
+	printk("Could not identify cpu/level for irq %d\n", irq);
+	while(1);
+	return(-1);
+}
+
+/*
+ * Find first bit set
+ */
+static int ms1bit(unsigned long x)
+{
+	int b = 0, s;
+
+	s = 16; if (x >> 16 == 0) s = 0; b += s; x >>= s;
+	s =  8; if (x >>  8 == 0) s = 0; b += s; x >>= s;
+	s =  4; if (x >>  4 == 0) s = 0; b += s; x >>= s;
+	s =  2; if (x >>  2 == 0) s = 0; b += s; x >>= s;
+	s =  1; if (x >>  1 == 0) s = 0; b += s;
+
+	return b;
+}
+
+/*
+ * This code is unnecessarily complex, because we do SA_INTERRUPT
+ * intr enabling. Basically, once we grab the set of intrs we need
+ * to service, we must mask _all_ these interrupts; firstly, to make
+ * sure the same intr does not intr again, causing recursion that
+ * can lead to stack overflow. Secondly, we can not just mask the
+ * one intr we are do_IRQing, because the non-masked intrs in the
+ * first set might intr again, causing multiple servicings of the
+ * same intr. This effect is mostly seen for intercpu intrs.
+ * Kanoj 05.13.00
+ */
+void ip27_do_irq(struct pt_regs *regs)
+{
+	int irq, swlevel;
+	hubreg_t pend0, mask0;
+	cpuid_t thiscpu = smp_processor_id();
+	int pi_int_mask0 = ((cputoslice(thiscpu) == 0) ?
+					PI_INT_MASK0_A : PI_INT_MASK0_B);
+
+	/* copied from Irix intpend0() */
+	while (((pend0 = LOCAL_HUB_L(PI_INT_PEND0)) &
+				(mask0 = LOCAL_HUB_L(pi_int_mask0))) != 0) {
+		pend0 &= mask0;		/* Pick intrs we should look at */
+		if (pend0) {
+			/* Prevent any of the picked intrs from recursing */
+			LOCAL_HUB_S(pi_int_mask0, mask0 & ~(pend0));
+			do {
+				swlevel = ms1bit(pend0);
+				LOCAL_HUB_CLR_INTR(swlevel);
+				/* "map" swlevel to irq */
+				irq = LEVEL_TO_IRQ(thiscpu, swlevel);
+				do_IRQ(irq, regs);
+				/* clear bit in pend0 */
+				pend0 ^= 1ULL << swlevel;
+			} while(pend0);
+			/* Now allow the set of serviced intrs again */
+			LOCAL_HUB_S(pi_int_mask0, mask0);
+			LOCAL_HUB_L(PI_INT_PEND0);
+		}
+	}
+}
+
+
+/* Startup one of the (PCI ...) IRQs routes over a bridge.  */
+static unsigned int startup_bridge_irq(unsigned int irq)
+{
+	bridgereg_t device;
+	bridge_t *bridge;
+	int pin, swlevel;
+	cpuid_t cpu;
+	nasid_t master = NASID_FROM_PCI_IRQ(irq);
+
+	if (irq < BASE_PCI_IRQ)
+		return 0;
+
+        bridge = (bridge_t *) NODE_SWIN_BASE(master, WID_FROM_PCI_IRQ(irq));
+	pin = SLOT_FROM_PCI_IRQ(irq);
+	cpu = IRQ_TO_CPU(irq);
+
+	DBG("bridge_startup(): irq= 0x%x  pin=%d\n", irq, pin);
+	/*
+	 * "map" irq to a swlevel greater than 6 since the first 6 bits
+	 * of INT_PEND0 are taken
+	 */
+	swlevel = alloc_level(cpu, irq);
+	intr_connect_level(cpu, swlevel);
+
+	bridge->b_int_addr[pin].addr = (0x20000 | swlevel | (master << 8));
+	bridge->b_int_enable |= (1 << pin);
+	/* more stuff in int_enable reg */
+	bridge->b_int_enable |= 0x7ffffe00;
+
+	/*
+	 * XXX This only works if b_int_device is initialized to 0!
+	 * We program the bridge to have a 1:1 mapping between devices
+	 * (slots) and intr pins.
+	 */
+	device = bridge->b_int_device;
+	device |= (pin << (pin*3));
+	bridge->b_int_device = device;
+
+        bridge->b_widget.w_tflush;                      /* Flush */
+
+        return 0;       /* Never anything pending.  */
+}
+
+/* Shutdown one of the (PCI ...) IRQs routes over a bridge.  */
+static unsigned int shutdown_bridge_irq(unsigned int irq)
+{
+	bridge_t *bridge;
+	int pin, swlevel;
+	cpuid_t cpu;
+
+	if (irq < BASE_PCI_IRQ)
+		return 0;
+
+	bridge = (bridge_t *) NODE_SWIN_BASE(NASID_FROM_PCI_IRQ(irq),
+	                                     WID_FROM_PCI_IRQ(irq));
+	DBG("bridge_shutdown: irq 0x%x\n", irq);
+	pin = SLOT_FROM_PCI_IRQ(irq);
+
+	/*
+	 * map irq to a swlevel greater than 6 since the first 6 bits
+	 * of INT_PEND0 are taken
+	 */
+	swlevel = find_level(&cpu, irq);
+	intr_disconnect_level(cpu, swlevel);
+	LEVEL_TO_IRQ(cpu, swlevel) = -1;
+
+	bridge->b_int_enable &= ~(1 << pin);
+	bridge->b_widget.w_tflush;                      /* Flush */
+
+	return 0;       /* Never anything pending.  */
+}
+
+static inline void enable_bridge_irq(unsigned int irq)
+{
+	/* All the braindamage happens magically for us in ip27_do_irq */
+}
+
+static void disable_bridge_irq(unsigned int irq)
+{
+	/* All the braindamage happens magically for us in ip27_do_irq */
+}
+
+static void mask_and_ack_bridge_irq(unsigned int irq)
+{
+	/* All the braindamage happens magically for us in ip27_do_irq */
+}
+
+static void end_bridge_irq (unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		enable_bridge_irq(irq);
+}
+
+static struct hw_interrupt_type bridge_irq_type = {
+	"bridge",
+	startup_bridge_irq,
+	shutdown_bridge_irq,
+	enable_bridge_irq,
+	disable_bridge_irq,
+	mask_and_ack_bridge_irq,
+	end_bridge_irq
+};
+
+void irq_debug(void)
+{
+	bridge_t *bridge = (bridge_t *) 0x9200000008000000;
+
+	printk("bridge->b_int_status = 0x%x\n", bridge->b_int_status);
+	printk("bridge->b_int_enable = 0x%x\n", bridge->b_int_enable);
+	printk("PI_INT_PEND0   = 0x%lx\n", LOCAL_HUB_L(PI_INT_PEND0));
+	printk("PI_INT_MASK0_A = 0x%lx\n", LOCAL_HUB_L(PI_INT_MASK0_A));
+}
+
+void __init init_IRQ(void)
+{
+	int i;
+
+	set_except_vector(0, ip27_irq);
+
+	/*
+	 * Right now the bridge irq is our kitchen sink interrupt type
+	 */
+	for (i = 0; i <= NR_IRQS; i++) {
+		irq_desc[i].status	= IRQ_DISABLED;
+		irq_desc[i].action	= 0;
+		irq_desc[i].depth	= 1;
+		irq_desc[i].handler	= &bridge_irq_type;
+	}
+}
+
+/*
+ * Get values that vary depending on which CPU and bit we're operating on.
+ */
+static hub_intmasks_t *intr_get_ptrs(cpuid_t cpu, int bit, int *new_bit,
+				hubreg_t **intpend_masks, int *ip)
+{
+	hub_intmasks_t *hub_intmasks;
+
+	hub_intmasks = &cpu_data[cpu].p_intmasks;
+	if (bit < N_INTPEND_BITS) {
+		*intpend_masks = hub_intmasks->intpend0_masks;
+		*ip = 0;
+		*new_bit = bit;
+	} else {
+		*intpend_masks = hub_intmasks->intpend1_masks;
+		*ip = 1;
+		*new_bit = bit - N_INTPEND_BITS;
+	}
+	return hub_intmasks;
+}
+
+int intr_connect_level(int cpu, int bit)
+{
+	int ip;
+	int slice = cputoslice(cpu);
+	volatile hubreg_t *mask_reg;
+	hubreg_t *intpend_masks;
+	nasid_t nasid = COMPACT_TO_NASID_NODEID(cputocnode(cpu));
+
+	(void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks, &ip);
+
+	/* Make sure it's not already pending when we connect it. */
+	REMOTE_HUB_CLR_INTR(nasid, bit + ip * N_INTPEND_BITS);
+
+	intpend_masks[0] |= (1ULL << (u64)bit);
+
+	if (ip == 0) {
+		mask_reg = REMOTE_HUB_ADDR(nasid, PI_INT_MASK0_A +
+				PI_INT_MASK_OFFSET * slice);
+	} else {
+		mask_reg = REMOTE_HUB_ADDR(nasid, PI_INT_MASK1_A +
+				PI_INT_MASK_OFFSET * slice);
+	}
+	HUB_S(mask_reg, intpend_masks[0]);
+	return(0);
+}
+
+int intr_disconnect_level(int cpu, int bit)
+{
+	int ip;
+	int slice = cputoslice(cpu);
+	volatile hubreg_t *mask_reg;
+	hubreg_t *intpend_masks;
+	nasid_t nasid = COMPACT_TO_NASID_NODEID(cputocnode(cpu));
+
+	(void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks, &ip);
+	intpend_masks[0] &= ~(1ULL << (u64)bit);
+	if (ip == 0) {
+		mask_reg = REMOTE_HUB_ADDR(nasid, PI_INT_MASK0_A +
+				PI_INT_MASK_OFFSET * slice);
+	} else {
+		mask_reg = REMOTE_HUB_ADDR(nasid, PI_INT_MASK1_A +
+				PI_INT_MASK_OFFSET * slice);
+	}
+	HUB_S(mask_reg, intpend_masks[0]);
+	return(0);
+}
+
+
+void handle_resched_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* Nothing, the return from intr will work for us */
+}
+
+#ifdef CONFIG_SMP
+
+void core_send_ipi(int destid, unsigned int action)
+{
+	int irq;
+
+#if (CPUS_PER_NODE == 2)
+	switch (action) {
+		case SMP_RESCHEDULE_YOURSELF:
+			irq = CPU_RESCHED_A_IRQ;
+			break;
+		case SMP_CALL_FUNCTION:
+			irq = CPU_CALL_A_IRQ;
+			break;
+		default:
+			panic("sendintr");
+	}
+	irq += cputoslice(destid);
+
+	/*
+	 * Convert the compact hub number to the NASID to get the correct
+	 * part of the address space.  Then set the interrupt bit associated
+	 * with the CPU we want to send the interrupt to.
+	 */
+	REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cputocnode(destid)),
+			FAST_IRQ_TO_LEVEL(irq));
+#else
+	<< Bomb!  Must redefine this for more than 2 CPUS. >>
+#endif
+}
+
+#endif
+
+extern void smp_call_function_interrupt(void);
+
+void install_cpuintr(int cpu)
+{
+#ifdef CONFIG_SMP
+#if (CPUS_PER_NODE == 2)
+	static int done = 0;
+
+	/*
+	 * This is a hack till we have a pernode irqlist. Currently,
+	 * just have the master cpu set up the handlers for the per
+	 * cpu irqs.
+	 */
+	if (done == 0) {
+		int j;
+
+		if (request_irq(CPU_RESCHED_A_IRQ, handle_resched_intr,
+							0, "resched", 0))
+			panic("intercpu intr unconnectible");
+		if (request_irq(CPU_RESCHED_B_IRQ, handle_resched_intr,
+							0, "resched", 0))
+			panic("intercpu intr unconnectible");
+		if (request_irq(CPU_CALL_A_IRQ, smp_call_function_interrupt,
+							0, "callfunc", 0))
+			panic("intercpu intr unconnectible");
+		if (request_irq(CPU_CALL_B_IRQ, smp_call_function_interrupt,
+							0, "callfunc", 0))
+			panic("intercpu intr unconnectible");
+
+		for (j = 0; j < PERNODE_LEVELS; j++)
+			LEVEL_TO_IRQ(0, j) = -1;
+		LEVEL_TO_IRQ(0, FAST_IRQ_TO_LEVEL(CPU_RESCHED_A_IRQ)) =
+							CPU_RESCHED_A_IRQ;
+		LEVEL_TO_IRQ(0, FAST_IRQ_TO_LEVEL(CPU_RESCHED_B_IRQ)) =
+							CPU_RESCHED_B_IRQ;
+		LEVEL_TO_IRQ(0, FAST_IRQ_TO_LEVEL(CPU_CALL_A_IRQ)) =
+							CPU_CALL_A_IRQ;
+		LEVEL_TO_IRQ(0, FAST_IRQ_TO_LEVEL(CPU_CALL_B_IRQ)) =
+							CPU_CALL_B_IRQ;
+		for (j = 1; j < MAX_COMPACT_NODES; j++)
+			memcpy(&node_level_to_irq[j][0],
+			&node_level_to_irq[0][0],
+			sizeof(node_level_to_irq[0][0])*PERNODE_LEVELS);
+
+		done = 1;
+	}
+
+	intr_connect_level(cpu, FAST_IRQ_TO_LEVEL(CPU_RESCHED_A_IRQ +
+							cputoslice(cpu)));
+	intr_connect_level(cpu, FAST_IRQ_TO_LEVEL(CPU_CALL_A_IRQ +
+							cputoslice(cpu)));
+#else /* CPUS_PER_NODE */
+#error Must redefine this for more than 2 CPUS.
+#endif /* CPUS_PER_NODE */
+#endif /* CONFIG_SMP */
+}
+
+void install_tlbintr(int cpu)
+{
+#if 0
+	int intr_bit = N_INTPEND_BITS + TLB_INTR_A + cputoslice(cpu);
+
+	intr_connect_level(cpu, intr_bit);
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip27/ip27-klconfig.c linux-2.4.20/arch/mips/sgi-ip27/ip27-klconfig.c
--- linux-2.4.19/arch/mips/sgi-ip27/ip27-klconfig.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip27/ip27-klconfig.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/param.h>
+#include <linux/timex.h>
+#include <linux/mm.h>
+
+#include <asm/sn/klconfig.h>
+#include <asm/sn/arch.h>
+#include <asm/sn/gda.h>
+
+klinfo_t *find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type)
+{
+	int index, j;
+
+	if (kli == (klinfo_t *)NULL) {
+		index = 0;
+	} else {
+		for (j = 0; j < KLCF_NUM_COMPS(brd); j++)
+			if (kli == KLCF_COMP(brd, j))
+				break;
+		index = j;
+		if (index == KLCF_NUM_COMPS(brd)) {
+			printk("find_component: Bad pointer: 0x%p\n", kli);
+			return (klinfo_t *)NULL;
+		}
+		index++;		/* next component */
+	}
+
+	for (; index < KLCF_NUM_COMPS(brd); index++) {
+		kli = KLCF_COMP(brd, index);
+		if (KLCF_COMP_TYPE(kli) == struct_type)
+			return kli;
+	}
+
+	/* Didn't find it. */
+	return (klinfo_t *)NULL;
+}
+
+klinfo_t *find_first_component(lboard_t *brd, unsigned char struct_type)
+{
+	return find_component(brd, (klinfo_t *)NULL, struct_type);
+}
+
+lboard_t * find_lboard(lboard_t *start, unsigned char brd_type)
+{
+	/* Search all boards stored on this node. */
+	while (start) {
+		if (start->brd_type == brd_type)
+			return start;
+		start = KLCF_NEXT(start);
+	}
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+lboard_t * find_lboard_class(lboard_t *start, unsigned char brd_type)
+{
+	/* Search all boards stored on this node. */
+	while (start) {
+		if (KLCLASS(start->brd_type) == KLCLASS(brd_type))
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+cnodeid_t get_cpu_cnode(cpuid_t cpu)
+{
+	return CPUID_TO_COMPACT_NODEID(cpu);
+}
+
+klcpu_t * nasid_slice_to_cpuinfo(nasid_t nasid, int slice)
+{
+	lboard_t *brd;
+	klcpu_t *acpu;
+
+	if (!(brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27)))
+		return (klcpu_t *)NULL;
+
+	if (!(acpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU)))
+		return (klcpu_t *)NULL;
+
+	do {
+		if ((acpu->cpu_info.physid) == slice)
+			return acpu;
+	} while ((acpu = (klcpu_t *)find_component(brd, (klinfo_t *)acpu,
+								KLSTRUCT_CPU)));
+	return (klcpu_t *)NULL;
+}
+
+klcpu_t * sn_get_cpuinfo(cpuid_t cpu)
+{
+	nasid_t nasid;
+	int slice;
+	klcpu_t *acpu;
+	gda_t *gdap = GDA;
+	cnodeid_t cnode;
+
+	if (!(cpu < MAXCPUS)) {
+		printk("sn_get_cpuinfo: illegal cpuid 0x%lx\n", cpu);
+		return NULL;
+	}
+
+	cnode = get_cpu_cnode(cpu);
+	if (cnode == INVALID_CNODEID)
+		return NULL;
+
+	if ((nasid = gdap->g_nasidtable[cnode]) == INVALID_NASID)
+		return NULL;
+
+	for (slice = 0; slice < CPUS_PER_NODE; slice++) {
+		acpu = nasid_slice_to_cpuinfo(nasid, slice);
+		if (acpu && acpu->cpu_info.virtid == cpu)
+			return acpu;
+	}
+	return NULL;
+}
+
+int get_cpu_slice(cpuid_t cpu)
+{
+	klcpu_t *acpu;
+
+	if ((acpu = sn_get_cpuinfo(cpu)) == NULL)
+		return -1;
+	return acpu->cpu_info.physid;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip27/ip27-klnuma.c linux-2.4.20/arch/mips/sgi-ip27/ip27-klnuma.c
--- linux-2.4.19/arch/mips/sgi-ip27/ip27-klnuma.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip27/ip27-klnuma.c	2002-10-29 11:18:38.000000000 +0000
@@ -0,0 +1,143 @@
+/*
+ * Ported from IRIX to Linux by Kanoj Sarcar, 06/08/00.
+ * Copyright 2000 - 2001 Silicon Graphics, Inc.
+ * Copyright 2000 - 2001 Kanoj Sarcar (kanoj@sgi.com)
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/mmzone.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/page.h>
+#include <asm/smp.h>
+#include <asm/sn/types.h>
+#include <asm/sn/arch.h>
+#include <asm/sn/gda.h>
+#include <asm/mmzone.h>
+#include <asm/sn/klkernvars.h>
+#include <asm/sn/mapped_kernel.h>
+#include <asm/sn/sn_private.h>
+
+extern char _end;
+static cpumask_t ktext_repmask;
+
+/*
+ * XXX - This needs to be much smarter about where it puts copies of the
+ * kernel.  For example, we should never put a copy on a headless node,
+ * and we should respect the topology of the machine.
+ */
+void __init setup_replication_mask(int maxnodes)
+{
+	static int 	numa_kernel_replication_ratio;
+	cnodeid_t	cnode;
+
+	/* Set only the master cnode's bit.  The master cnode is always 0. */
+	CPUMASK_CLRALL(ktext_repmask);
+	CPUMASK_SETB(ktext_repmask, 0);
+
+	numa_kernel_replication_ratio = 0;
+#ifdef CONFIG_REPLICATE_KTEXT
+#ifndef CONFIG_MAPPED_KERNEL
+#error Kernel replication works with mapped kernel support. No calias support.
+#endif
+	numa_kernel_replication_ratio = 1;
+#endif
+
+	for (cnode = 1; cnode < numnodes; cnode++) {
+		/* See if this node should get a copy of the kernel */
+		if (numa_kernel_replication_ratio &&
+		    !(cnode % numa_kernel_replication_ratio)) {
+
+			/* Advertise that we have a copy of the kernel */
+			CPUMASK_SETB(ktext_repmask, cnode);
+		}
+	}
+
+	/* Set up a GDA pointer to the replication mask. */
+	GDA->g_ktext_repmask = &ktext_repmask;
+}
+
+
+static __init void set_ktext_source(nasid_t client_nasid, nasid_t server_nasid)
+{
+	kern_vars_t *kvp;
+	cnodeid_t client_cnode;
+
+	client_cnode = NASID_TO_COMPACT_NODEID(client_nasid);
+
+	kvp = &(PLAT_NODE_DATA(client_cnode)->kern_vars);
+
+	KERN_VARS_ADDR(client_nasid) = (unsigned long)kvp;
+
+	kvp->kv_magic = KV_MAGIC;
+
+	kvp->kv_ro_nasid = server_nasid;
+	kvp->kv_rw_nasid = master_nasid;
+	kvp->kv_ro_baseaddr = NODE_CAC_BASE(server_nasid);
+	kvp->kv_rw_baseaddr = NODE_CAC_BASE(master_nasid);
+	printk("REPLICATION: ON nasid %d, ktext from nasid %d, kdata from nasid %d\n", client_nasid, server_nasid, master_nasid);
+}
+
+/* XXX - When the BTE works, we should use it instead of this. */
+static __init void copy_kernel(nasid_t dest_nasid)
+{
+	extern char _stext, _etext;
+	unsigned long dest_kern_start, source_start, source_end, kern_size;
+
+	source_start = (unsigned long)&_stext;
+	source_end = (unsigned long)&_etext;
+	kern_size = source_end - source_start;
+
+	dest_kern_start = CHANGE_ADDR_NASID(MAPPED_KERN_RO_TO_K0(source_start),
+					    dest_nasid);
+	memcpy((void *)dest_kern_start, (void *)source_start, kern_size);
+}
+
+void __init replicate_kernel_text(int maxnodes)
+{
+	cnodeid_t cnode;
+	nasid_t client_nasid;
+	nasid_t server_nasid;
+
+	server_nasid = master_nasid;
+
+	/* Record where the master node should get its kernel text */
+	set_ktext_source(master_nasid, master_nasid);
+
+	for (cnode = 1; cnode < maxnodes; cnode++) {
+		client_nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+		/* Check if this node should get a copy of the kernel */
+		if (CPUMASK_TSTB(ktext_repmask, cnode)) {
+			server_nasid = client_nasid;
+			copy_kernel(server_nasid);
+		}
+
+		/* Record where this node should get its kernel text */
+		set_ktext_source(client_nasid, server_nasid);
+	}
+}
+
+/*
+ * Return pfn of first free page of memory on a node. PROM may allocate
+ * data structures on the first couple of pages of the first slot of each
+ * node. If this is the case, getfirstfree(node) > getslotstart(node, 0).
+ */
+pfn_t node_getfirstfree(cnodeid_t cnode)
+{
+	unsigned long loadbase = CKSEG0;
+	nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
+	unsigned long offset;
+
+#ifdef CONFIG_MAPPED_KERNEL
+	loadbase = CKSSEG + 16777216;
+#endif
+	offset = PAGE_ALIGN((unsigned long)(&_end)) - loadbase;
+	if ((cnode == 0) || (CPUMASK_TSTB(ktext_repmask, cnode)))
+		return (TO_NODE(nasid, offset) >> PAGE_SHIFT);
+	else
+		return (KDM_TO_PHYS(PAGE_ALIGN(SYMMON_STK_ADDR(nasid, 0))) >>
+								PAGE_SHIFT);
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip27/ip27-memory.c linux-2.4.20/arch/mips/sgi-ip27/ip27-memory.c
--- linux-2.4.19/arch/mips/sgi-ip27/ip27-memory.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip27/ip27-memory.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,344 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000 by Ralf Baechle
+ * Copyright (C) 2000 by Silicon Graphics, Inc.
+ *
+ * On SGI IP27 the ARC memory configuration data is completly bogus but
+ * alternate easier to use mechanisms are available.
+ */
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/swap.h>
+
+#include <asm/page.h>
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/sn/types.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/arch.h>
+#include <asm/mmzone.h>
+
+/* ip27-klnuma.c   */
+extern pfn_t node_getfirstfree(cnodeid_t cnode);
+
+#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define SLOT_IGNORED	0xffff
+
+short slot_lastfilled_cache[MAX_COMPACT_NODES];
+unsigned short slot_psize_cache[MAX_COMPACT_NODES][MAX_MEM_SLOTS];
+static pfn_t numpages;
+
+plat_pg_data_t *plat_node_data[MAX_COMPACT_NODES];
+bootmem_data_t plat_node_bdata[MAX_COMPACT_NODES];
+
+int numa_debug(void)
+{
+	printk("NUMA debug\n");
+	*(int *)0 = 0;
+	return(0);
+}
+
+/*
+ * Return the number of pages of memory provided by the given slot
+ * on the specified node.
+ */
+pfn_t slot_getsize(cnodeid_t node, int slot)
+{
+	return (pfn_t) slot_psize_cache[node][slot];
+}
+
+/*
+ * Return highest slot filled
+ */
+int node_getlastslot(cnodeid_t node)
+{
+	return (int) slot_lastfilled_cache[node];
+}
+
+/*
+ * Return the pfn of the last free page of memory on a node.
+ */
+pfn_t node_getmaxclick(cnodeid_t node)
+{
+	pfn_t	slot_psize;
+	int	slot;
+
+	/*
+	 * Start at the top slot. When we find a slot with memory in it,
+	 * that's the winner.
+	 */
+	for (slot = (node_getnumslots(node) - 1); slot >= 0; slot--) {
+		if ((slot_psize = slot_getsize(node, slot))) {
+			if (slot_psize == SLOT_IGNORED)
+				continue;
+			/* Return the basepfn + the slot size, minus 1. */
+			return slot_getbasepfn(node, slot) + slot_psize - 1;
+		}
+	}
+
+	/*
+	 * If there's no memory on the node, return 0. This is likely
+	 * to cause problems.
+	 */
+	return (pfn_t)0;
+}
+
+static pfn_t slot_psize_compute(cnodeid_t node, int slot)
+{
+	nasid_t nasid;
+	lboard_t *brd;
+	klmembnk_t *banks;
+	unsigned long size;
+
+	nasid = COMPACT_TO_NASID_NODEID(node);
+	/* Find the node board */
+	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
+	if (!brd)
+		return 0;
+
+	/* Get the memory bank structure */
+	banks = (klmembnk_t *)find_first_component(brd, KLSTRUCT_MEMBNK);
+	if (!banks)
+		return 0;
+
+	/* Size in _Megabytes_ */
+	size = (unsigned long)banks->membnk_bnksz[slot/4];
+
+	/* hack for 128 dimm banks */
+	if (size <= 128) {
+		if (slot%4 == 0) {
+			size <<= 20;		/* size in bytes */
+			return(size >> PAGE_SHIFT);
+		} else {
+			return 0;
+		}
+	} else {
+		size /= 4;
+		size <<= 20;
+		return(size >> PAGE_SHIFT);
+	}
+}
+
+pfn_t szmem(pfn_t fpage, pfn_t maxpmem)
+{
+	cnodeid_t node;
+	int slot, numslots;
+	pfn_t num_pages = 0, slot_psize;
+	pfn_t slot0sz = 0, nodebytes;	/* Hack to detect problem configs */
+	int ignore;
+
+	for (node = 0; node < numnodes; node++) {
+		numslots = node_getnumslots(node);
+		ignore = nodebytes = 0;
+		for (slot = 0; slot < numslots; slot++) {
+			slot_psize = slot_psize_compute(node, slot);
+			if (slot == 0) slot0sz = slot_psize;
+			/*
+			 * We need to refine the hack when we have replicated
+			 * kernel text.
+			 */
+			nodebytes += SLOT_SIZE;
+			if ((nodebytes >> PAGE_SHIFT) * (sizeof(struct page)) >
+						(slot0sz << PAGE_SHIFT))
+				ignore = 1;
+			if (ignore && slot_psize) {
+				printk("Ignoring slot %d onwards on node %d\n",
+								slot, node);
+				slot_psize_cache[node][slot] = SLOT_IGNORED;
+				slot = numslots;
+				continue;
+			}
+			num_pages += slot_psize;
+			slot_psize_cache[node][slot] =
+					(unsigned short) slot_psize;
+			if (slot_psize)
+				slot_lastfilled_cache[node] = slot;
+		}
+	}
+	if (maxpmem)
+		return((maxpmem > num_pages) ? num_pages : maxpmem);
+	else
+		return num_pages;
+}
+
+/*
+ * Currently, the intranode memory hole support assumes that each slot
+ * contains at least 32 MBytes of memory. We assume all bootmem data
+ * fits on the first slot.
+ */
+void __init prom_meminit(void)
+{
+	extern void mlreset(void);
+	cnodeid_t node;
+	pfn_t slot_firstpfn, slot_lastpfn, slot_freepfn;
+	unsigned long bootmap_size;
+	int node_datasz;
+
+	node_datasz = PFN_UP(sizeof(plat_pg_data_t));
+	mlreset();
+	numpages = szmem(0, 0);
+	for (node = (numnodes - 1); node >= 0; node--) {
+		slot_firstpfn = slot_getbasepfn(node, 0);
+		slot_lastpfn = slot_firstpfn + slot_getsize(node, 0);
+		slot_freepfn = node_getfirstfree(node);
+		/* Foll line hack for non discontigmem; remove once discontigmem
+		 * becomes the default. */
+		max_low_pfn = (slot_lastpfn - slot_firstpfn);
+
+		/*
+		 * Allocate the node data structure on the node first.
+		 */
+		plat_node_data[node] = (plat_pg_data_t *)(__va(slot_freepfn \
+							<< PAGE_SHIFT));
+		NODE_DATA(node)->bdata = plat_node_bdata + node;
+		slot_freepfn += node_datasz;
+	  	bootmap_size = init_bootmem_node(NODE_DATA(node), slot_freepfn,
+						slot_firstpfn, slot_lastpfn);
+		free_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
+				(slot_lastpfn - slot_firstpfn) << PAGE_SHIFT);
+		reserve_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
+		  ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size);
+	}
+	printk("Total memory probed : 0x%lx pages\n", numpages);
+}
+
+int __init page_is_ram(unsigned long pagenr)
+{
+        return 1;
+}
+
+void __init
+prom_free_prom_memory (void)
+{
+	/* We got nothing to free here ...  */
+}
+
+#ifdef CONFIG_DISCONTIGMEM
+
+static pfn_t pagenr = 0;
+
+void __init paging_init(void)
+{
+	pmd_t *pmd = kpmdtbl;
+	pte_t *pte = kptbl;
+
+	cnodeid_t node;
+	unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
+	int i;
+
+	/* Initialize the entire pgd.  */
+	pgd_init((unsigned long)swapper_pg_dir);
+	pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table);
+	memset((void *)invalid_pte_table, 0, sizeof(pte_t) * PTRS_PER_PTE);
+
+	/* This is for vmalloc  */
+	memset((void *)kptbl, 0, PAGE_SIZE << PGD_ORDER);
+	memset((void *)kpmdtbl, 0, PAGE_SIZE);
+	pgd_set(swapper_pg_dir, kpmdtbl);
+	for (i = 0; i < (1 << PGD_ORDER); pmd++,i++,pte+=PTRS_PER_PTE)
+		pmd_val(*pmd) = (unsigned long)pte;
+
+	for (node = 0; node < numnodes; node++) {
+		pfn_t start_pfn = slot_getbasepfn(node, 0);
+		pfn_t end_pfn = node_getmaxclick(node);
+
+		zones_size[ZONE_DMA] = end_pfn + 1 - start_pfn;
+		free_area_init_node(node, NODE_DATA(node), 0, zones_size,
+						start_pfn << PAGE_SHIFT, 0);
+		if ((PLAT_NODE_DATA_STARTNR(node) +
+					PLAT_NODE_DATA_SIZE(node)) > pagenr)
+			pagenr = PLAT_NODE_DATA_STARTNR(node) +
+					PLAT_NODE_DATA_SIZE(node);
+	}
+}
+
+void __init mem_init(void)
+{
+	extern char _stext, _etext, _fdata, _edata;
+	extern char __init_begin, __init_end;
+	extern unsigned long totalram_pages;
+	extern unsigned long setup_zero_pages(void);
+	cnodeid_t nid;
+	unsigned long tmp;
+	unsigned long codesize, datasize, initsize;
+	int slot, numslots;
+	struct page *pg, *pslot;
+	pfn_t pgnr;
+
+	num_physpages = numpages;	/* memory already sized by szmem */
+	max_mapnr = pagenr;		/* already found during paging_init */
+	high_memory = (void *) __va(max_mapnr << PAGE_SHIFT);
+
+	for (nid = 0; nid < numnodes; nid++) {
+
+		/*
+		 * Hack till free_area_init_core() zeroes free_pages
+		 */
+		for (tmp = 0; tmp < MAX_NR_ZONES; tmp++)
+			PLAT_NODE_DATA(nid)->gendata.node_zones[tmp].free_pages=0;
+		/*
+	 	 * This will free up the bootmem, ie, slot 0 memory.
+	 	 */
+		totalram_pages += free_all_bootmem_node(NODE_DATA(nid));
+
+		/*
+		 * We need to manually do the other slots.
+		 */
+		pg = NODE_DATA(nid)->node_mem_map + slot_getsize(nid, 0);
+		pgnr = PLAT_NODE_DATA_STARTNR(nid) + slot_getsize(nid, 0);
+		numslots = node_getlastslot(nid);
+		for (slot = 1; slot <= numslots; slot++) {
+			pslot = NODE_DATA(nid)->node_mem_map +
+			   slot_getbasepfn(nid, slot) - slot_getbasepfn(nid, 0);
+
+			/*
+			 * Mark holes in previous slot. May also want to
+			 * free up the pages that hold the memmap entries.
+			 */
+			while (pg < pslot) {
+				pg++; pgnr++;
+			}
+
+			/*
+			 * Free valid memory in current slot.
+			 */
+			pslot += slot_getsize(nid, slot);
+			while (pg < pslot) {
+				if (!page_is_ram(pgnr))
+					continue;
+				ClearPageReserved(pg);
+				atomic_set(&pg->count, 1);
+				__free_page(pg);
+				totalram_pages++;
+				pg++; pgnr++;
+			}
+		}
+	}
+
+	totalram_pages -= setup_zero_pages();	/* This comes from node 0 */
+
+	codesize =  (unsigned long) &_etext - (unsigned long) &_stext;
+	datasize =  (unsigned long) &_edata - (unsigned long) &_fdata;
+	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
+
+	tmp = (unsigned long) nr_free_pages();
+	printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, "
+		"%ldk data, %ldk init)\n",
+		tmp << (PAGE_SHIFT-10),
+		num_physpages << (PAGE_SHIFT-10),
+		codesize >> 10,
+		(num_physpages - tmp) << (PAGE_SHIFT-10),
+		datasize >> 10,
+		initsize >> 10);
+}
+
+#endif /* CONFIG_DISCONTIGMEM */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip27/ip27-nmi.c linux-2.4.20/arch/mips/sgi-ip27/ip27-nmi.c
--- linux-2.4.19/arch/mips/sgi-ip27/ip27-nmi.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip27/ip27-nmi.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,168 @@
+#include <linux/kernel.h>
+#include <linux/mmzone.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include <asm/atomic.h>
+#include <asm/sn/types.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/nmi.h>
+#include <asm/sn/arch.h>
+#include <asm/sn/sn0/hub.h>
+
+#if 0
+#define NODE_NUM_CPUS(n)	CNODE_NUM_CPUS(n)
+#else
+#define NODE_NUM_CPUS(n)	CPUS_PER_NODE
+#endif
+
+#define CNODEID_NONE (cnodeid_t)-1
+#define enter_panic_mode()	spin_lock(&nmi_lock)
+
+typedef unsigned long machreg_t;
+
+spinlock_t nmi_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Lets see what else we need to do here. Set up sp, gp?
+ */
+void nmi_dump(void)
+{
+	void cont_nmi_dump(void);
+
+	cont_nmi_dump();
+}
+
+void install_cpu_nmi_handler(int slice)
+{
+	nmi_t *nmi_addr;
+
+	nmi_addr = (nmi_t *)NMI_ADDR(get_nasid(), slice);
+	if (nmi_addr->call_addr)
+		return;
+	nmi_addr->magic = NMI_MAGIC;
+	nmi_addr->call_addr = (void *)nmi_dump;
+	nmi_addr->call_addr_c =
+		(void *)(~((unsigned long)(nmi_addr->call_addr)));
+	nmi_addr->call_parm = 0;
+}
+
+/*
+ * Copy the cpu registers which have been saved in the IP27prom format
+ * into the eframe format for the node under consideration.
+ */
+
+void
+nmi_cpu_eframe_save(nasid_t nasid,
+		    int	    slice)
+{
+	int 		i, numberof_nmi_cpu_regs;
+	machreg_t	*prom_format;
+
+	/* Get the total number of registers being saved by the prom */
+	numberof_nmi_cpu_regs = sizeof(struct reg_struct) / sizeof(machreg_t);
+
+	/* Get the pointer to the current cpu's register set. */
+	prom_format =
+	    (machreg_t *)(TO_UNCAC(TO_NODE(nasid, IP27_NMI_KREGS_OFFSET)) +
+			  slice * IP27_NMI_KREGS_CPU_SIZE);
+
+	printk("NMI nasid %d: slice %d\n", nasid, slice);
+	for (i = 0; i < numberof_nmi_cpu_regs; i++)
+		printk("0x%lx  ", prom_format[i]);
+	printk("\n\n");
+}
+
+/*
+ * Copy the cpu registers which have been saved in the IP27prom format
+ * into the eframe format for the node under consideration.
+ */
+void
+nmi_node_eframe_save(cnodeid_t  cnode)
+{
+	int		cpu;
+	nasid_t		nasid;
+
+	/* Make sure that we have a valid node */
+	if (cnode == CNODEID_NONE)
+		return;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+	if (nasid == INVALID_NASID)
+		return;
+
+	/* Save the registers into eframe for each cpu */
+	for(cpu = 0; cpu < NODE_NUM_CPUS(cnode); cpu++)
+		nmi_cpu_eframe_save(nasid, cpu);
+}
+
+/*
+ * Save the nmi cpu registers for all cpus in the system.
+ */
+void
+nmi_eframes_save(void)
+{
+	cnodeid_t	cnode;
+
+	for(cnode = 0 ; cnode < numnodes; cnode++)
+		nmi_node_eframe_save(cnode);
+}
+
+void
+cont_nmi_dump(void)
+{
+#ifndef REAL_NMI_SIGNAL
+	static atomic_t nmied_cpus = ATOMIC_INIT(0);
+
+	atomic_inc(&nmied_cpus);
+#endif
+	/*
+	 * Use enter_panic_mode to allow only 1 cpu to proceed
+	 */
+	enter_panic_mode();
+
+#ifdef REAL_NMI_SIGNAL
+	/*
+	 * Wait up to 15 seconds for the other cpus to respond to the NMI.
+	 * If a cpu has not responded after 10 sec, send it 1 additional NMI.
+	 * This is for 2 reasons:
+	 *	- sometimes a MMSC fail to NMI all cpus.
+	 *	- on 512p SN0 system, the MMSC will only send NMIs to
+	 *	  half the cpus. Unfortunately, we dont know which cpus may be
+	 *	  NMIed - it depends on how the site chooses to configure.
+	 *
+	 * Note: it has been measure that it takes the MMSC up to 2.3 secs to
+	 * send NMIs to all cpus on a 256p system.
+	 */
+	for (i=0; i < 1500; i++) {
+		for (node=0; node < numnodes; node++)
+			if (NODEPDA(node)->dump_count == 0)
+				break;
+		if (node == numnodes)
+			break;
+		if (i == 1000) {
+			for (node=0; node < numnodes; node++)
+				if (NODEPDA(node)->dump_count == 0) {
+					cpu = CNODE_TO_CPU_BASE(node);
+					for (n=0; n < CNODE_NUM_CPUS(node); cpu++, n++) {
+						CPUMASK_SETB(nmied_cpus, cpu);
+						/*
+						 * cputonasid, cputoslice
+						 * needs kernel cpuid
+						 */
+						SEND_NMI((cputonasid(cpu)), (cputoslice(cpu)));
+					}
+				}
+
+		}
+		udelay(10000);
+	}
+#else
+	while (atomic_read(&nmied_cpus) != smp_num_cpus);
+#endif
+
+	/*
+	 * Save the nmi cpu registers for all cpu in the eframe format.
+	 */
+	nmi_eframes_save();
+	LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip27/ip27-pci.c linux-2.4.20/arch/mips/sgi-ip27/ip27-pci.c
--- linux-2.4.19/arch/mips/sgi-ip27/ip27-pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip27/ip27-pci.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,429 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/sn/arch.h>
+#include <asm/pci/bridge.h>
+#include <asm/paccess.h>
+#include <asm/sn/sn0/ip27.h>
+#include <asm/sn/sn0/hub.h>
+
+/*
+ * Max #PCI busses we can handle; ie, max #PCI bridges.
+ */
+#define MAX_PCI_BUSSES		40
+
+/*
+ * Max #PCI devices (like scsi controllers) we handle on a bus.
+ */
+#define MAX_DEVICES_PER_PCIBUS	8
+
+/*
+ * No locking needed until PCI initialization is done parallely.
+ */
+int irqstore[MAX_PCI_BUSSES][MAX_DEVICES_PER_PCIBUS];
+int lastirq = BASE_PCI_IRQ;
+
+/*
+ * Translate from irq to software PCI bus number and PCI slot.
+ */
+int irq_to_bus[MAX_PCI_BUSSES * MAX_DEVICES_PER_PCIBUS];
+int irq_to_slot[MAX_PCI_BUSSES * MAX_DEVICES_PER_PCIBUS];
+
+/*
+ * The Bridge ASIC supports both type 0 and type 1 access.  Type 1 is
+ * not really documented, so right now I can't write code which uses it.
+ * Therefore we use type 0 accesses for now even though they won't work
+ * correcly for PCI-to-PCI bridges.
+ */
+#define CF0_READ_PCI_CFG(dev,where,value,bm,mask)			\
+do {									\
+	bridge_t *bridge;                                               \
+	int slot = PCI_SLOT(dev->devfn);				\
+	int fn = PCI_FUNC(dev->devfn);					\
+	volatile u32 *addr;						\
+	u32 cf, __bit;							\
+	unsigned int bus_id = (unsigned) dev->bus->number;              \
+									\
+	bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[bus_id],        \
+                                             bus_to_wid[bus_id]);       \
+                                                                        \
+	if (dev->vendor == PCI_VENDOR_ID_SGI				\
+	    && dev->device == PCI_DEVICE_ID_SGI_IOC3			\
+	    && ((where >= 0x14 && where < 0x40) || (where >= 0x48))) {	\
+		*value = 0;						\
+		return PCIBIOS_SUCCESSFUL;				\
+	}								\
+									\
+	__bit = (((where) & (bm)) << 3);				\
+	addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];	\
+	if (get_dbe(cf, addr))						\
+		return PCIBIOS_DEVICE_NOT_FOUND;			\
+	*value = (cf >> __bit) & (mask);				\
+	return PCIBIOS_SUCCESSFUL;					\
+} while (0)
+
+static int
+pci_conf0_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	CF0_READ_PCI_CFG(dev,where,value,3,0xff);
+}
+
+static int
+pci_conf0_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	CF0_READ_PCI_CFG(dev,where,value,2,0xffff);
+}
+
+static int
+pci_conf0_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	CF0_READ_PCI_CFG(dev,where,value,0,0xffffffff);
+}
+
+#define CF0_WRITE_PCI_CFG(dev,where,value,bm,mask)			\
+do {									\
+	bridge_t *bridge;                                               \
+	int slot = PCI_SLOT(dev->devfn);				\
+	int fn = PCI_FUNC(dev->devfn);					\
+	volatile u32 *addr;						\
+	u32 cf, __bit;							\
+	unsigned int bus_id = (unsigned) dev->bus->number;              \
+									\
+	bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[bus_id],        \
+                                             bus_to_wid[bus_id]);       \
+                                                                        \
+	if (dev->vendor == PCI_VENDOR_ID_SGI				\
+	    && dev->device == PCI_DEVICE_ID_SGI_IOC3			\
+	    && ((where >= 0x14 && where < 0x40) || (where >= 0x48)))	\
+		return PCIBIOS_SUCCESSFUL;				\
+									\
+	__bit = (((where) & (bm)) << 3);				\
+	addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];	\
+	if (get_dbe(cf, addr))						\
+		return PCIBIOS_DEVICE_NOT_FOUND;			\
+	cf &= (~mask);							\
+	cf |= (value);							\
+	put_dbe(cf, addr);						\
+	return PCIBIOS_SUCCESSFUL;					\
+} while (0)
+
+static int
+pci_conf0_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	CF0_WRITE_PCI_CFG(dev,where,value,3,0xff);
+}
+
+static int
+pci_conf0_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	CF0_WRITE_PCI_CFG(dev,where,value,2,0xffff);
+}
+
+static int
+pci_conf0_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	CF0_WRITE_PCI_CFG(dev,where,value,0,0xffffffff);
+}
+
+
+static struct pci_ops bridge_pci_ops = {
+	pci_conf0_read_config_byte,
+	pci_conf0_read_config_word,
+	pci_conf0_read_config_dword,
+	pci_conf0_write_config_byte,
+	pci_conf0_write_config_word,
+	pci_conf0_write_config_dword
+};
+
+void __init pcibios_init(void)
+{
+	struct pci_ops *ops = &bridge_pci_ops;
+	int	i;
+
+	ioport_resource.end = ~0UL;
+	iomem_resource.end = ~0UL;
+
+	for (i=0; i<num_bridges; i++) {
+		printk("PCI: Probing PCI hardware on host bus %2d.\n", i);
+		pci_scan_bus(i, ops, NULL);
+	}
+}
+
+static inline u8
+bridge_swizzle(u8 pin, u8 slot)
+{
+	return (((pin-1) + slot) % 4) + 1;
+}
+
+static u8 __init
+pci_swizzle(struct pci_dev *dev, u8 *pinp)
+{
+	u8 pin = *pinp;
+
+	while (dev->bus->self) {	/* Move up the chain of bridges. */
+		pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
+		dev = dev->bus->self;
+	}
+	*pinp = pin;
+
+	return PCI_SLOT(dev->devfn);
+}
+
+/*
+ * All observed requests have pin == 1. We could have a global here, that
+ * gets incremented and returned every time - unfortunately, pci_map_irq
+ * may be called on the same device over and over, and need to return the
+ * same value. On O2000, pin can be 0 or 1, and PCI slots can be [0..7].
+ *
+ * A given PCI device, in general, should be able to intr any of the cpus
+ * on any one of the hubs connected to its xbow.
+ */
+static int __init
+pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	if ((dev->bus->number >= MAX_PCI_BUSSES)
+	    || (pin != 1)
+	    || (slot >= MAX_DEVICES_PER_PCIBUS))
+		panic("Increase supported PCI busses %d,%d,%d",
+		      dev->bus->number, slot, pin);
+
+	/*
+	 * Already assigned? Then return previously assigned value ...
+	 */
+	if (irqstore[dev->bus->number][slot])
+		return irqstore[dev->bus->number][slot];
+
+	irq_to_bus[lastirq] = dev->bus->number;
+	irq_to_slot[lastirq] = slot;
+	irqstore[dev->bus->number][slot] = lastirq;
+	lastirq++;
+	return lastirq - 1;
+}
+
+void __init
+pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+void __init
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+                        struct resource *res, int resource)
+{
+	unsigned long where, size;
+	u32 reg;
+
+	where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	size = res->end - res->start;
+	pci_read_config_dword(dev, where, &reg);
+	reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
+	pci_write_config_dword(dev, where, reg);
+}
+
+void __init
+pcibios_fixup_bus(struct pci_bus *b)
+{
+	pci_fixup_irqs(pci_swizzle, pci_map_irq);
+}
+
+void __init
+pcibios_fixup_pbus_ranges(struct pci_bus * bus,
+                          struct pbus_set_ranges_data * ranges)
+{
+	ranges->io_start  -= bus->resource[0]->start;
+	ranges->io_end    -= bus->resource[0]->start;
+	ranges->mem_start -= bus->resource[1]->start;
+	ranges->mem_end   -= bus->resource[1]->start;
+}
+
+int __init
+pcibios_enable_device(struct pci_dev *dev)
+{
+	/* Not needed, since we enable all devices at startup.  */
+	return 0;
+}
+
+void __init
+pcibios_align_resource(void *data, struct resource *res, unsigned long size,
+		       unsigned long align)
+{
+}
+
+unsigned __init int pcibios_assign_all_busses(void)
+{
+	return 0;
+}
+
+char * __init
+pcibios_setup(char *str)
+{
+	/* Nothing to do for now.  */
+
+	return str;
+}
+
+/*
+ * Device might live on a subordinate PCI bus.  XXX Walk up the chain of buses
+ * to find the slot number in sense of the bridge device register.
+ * XXX This also means multiple devices might rely on conflicting bridge
+ * settings.
+ */
+
+static void __init
+pci_disable_swapping(struct pci_dev *dev)
+{
+	unsigned int bus_id = (unsigned) dev->bus->number;
+	bridge_t *bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[bus_id],
+	                                               bus_to_wid[bus_id]);
+	int		slot = PCI_SLOT(dev->devfn);
+
+	/* Turn off byte swapping */
+	bridge->b_device[slot].reg &= ~BRIDGE_DEV_SWAP_DIR;
+	bridge->b_widget.w_tflush;		/* Flush */
+}
+
+static void __init
+pci_enable_swapping(struct pci_dev *dev)
+{
+	unsigned int bus_id = (unsigned) dev->bus->number;
+	bridge_t *bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[bus_id],
+	                                               bus_to_wid[bus_id]);
+	int		slot = PCI_SLOT(dev->devfn);
+
+	/* Turn on byte swapping */
+	bridge->b_device[slot].reg |= BRIDGE_DEV_SWAP_DIR;
+	bridge->b_widget.w_tflush;		/* Flush */
+}
+
+static void __init
+pci_fixup_ioc3(struct pci_dev *d)
+{
+	unsigned long bus_id = (unsigned) d->bus->number;
+
+	printk("PCI: Fixing base addresses for IOC3 device %s\n", d->slot_name);
+
+	d->resource[0].start |= NODE_OFFSET(bus_to_nid[bus_id]);
+	d->resource[0].end   |= NODE_OFFSET(bus_to_nid[bus_id]);
+
+	pci_disable_swapping(d);
+}
+
+static void __init
+pci_fixup_isp1020(struct pci_dev *d)
+{
+	unsigned short command;
+
+	d->resource[0].start |= ((unsigned long)(bus_to_nid[d->bus->number])<<32);
+	printk("PCI: Fixing isp1020 in [bus:slot.fn] %s\n", d->slot_name);
+
+	/*
+	 * Configure device to allow bus mastering, i/o and memory mapping.
+	 * Older qlogicisp driver expects to have the IO space enable
+	 * bit set. Things stop working if we program the controllers as not
+	 * having PCI_COMMAND_MEMORY, so we have to fudge the mem_flags.
+	 */
+
+	pci_set_master(d);
+	pci_read_config_word(d, PCI_COMMAND, &command);
+	command |= PCI_COMMAND_MEMORY;
+	command |= PCI_COMMAND_IO;
+	pci_write_config_word(d, PCI_COMMAND, command);
+	d->resource[1].flags |= 1;
+
+	pci_enable_swapping(d);
+}
+
+static void __init
+pci_fixup_isp2x00(struct pci_dev *d)
+{
+	unsigned int bus_id = (unsigned) d->bus->number;
+	bridge_t *bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[bus_id],
+				     bus_to_wid[bus_id]);
+	bridgereg_t 	devreg;
+	int		i;
+	int		slot = PCI_SLOT(d->devfn);
+	unsigned int	start;
+	unsigned short command;
+
+	printk("PCI: Fixing isp2x00 in [bus:slot.fn] %s\n", d->slot_name);
+
+	/* set the resource struct for this device */
+	start = (u32) (u64)bridge;	/* yes, we want to lose the upper 32 bits here */
+	start |= BRIDGE_DEVIO(slot);
+
+	d->resource[0].start = start;
+	d->resource[0].end = d->resource[0].start + 0xff;
+	d->resource[0].flags = IORESOURCE_IO;
+
+	d->resource[1].start = start;
+	d->resource[1].end = d->resource[0].start + 0xfff;
+	d->resource[1].flags = IORESOURCE_MEM;
+
+	/*
+	 * set the bridge device(x) reg for this device
+	 */
+	devreg = bridge->b_device[slot].reg;
+	/* point device(x) to it appropriate small window */
+	devreg &= ~BRIDGE_DEV_OFF_MASK;
+	devreg |= (start >> 20) & BRIDGE_DEV_OFF_MASK;
+	bridge->b_device[slot].reg = devreg;
+
+	pci_enable_swapping(d);
+
+	/* set card's base addr reg */
+	//pci_conf0_write_config_dword(d, PCI_BASE_ADDRESS_0, 0x500001);
+	//pci_conf0_write_config_dword(d, PCI_BASE_ADDRESS_1, 0x8b00000);
+	//pci_conf0_write_config_dword(d, PCI_ROM_ADDRESS, 0x8b20000);
+
+	/* I got these from booting irix on system...*/
+	pci_conf0_write_config_dword(d, PCI_BASE_ADDRESS_0, 0x200001);
+	//pci_conf0_write_config_dword(d, PCI_BASE_ADDRESS_1, 0xf800000);
+	pci_conf0_write_config_dword(d, PCI_ROM_ADDRESS,   0x10200000);
+
+	pci_conf0_write_config_dword(d, PCI_BASE_ADDRESS_1, start);
+	//pci_conf0_write_config_dword(d, PCI_ROM_ADDRESS, (start | 0x20000));
+
+	/* set cache line size */
+	pci_conf0_write_config_dword(d, PCI_CACHE_LINE_SIZE, 0xf080);
+
+	/* set pci bus timeout */
+	bridge->b_bus_timeout |= BRIDGE_BUS_PCI_RETRY_HLD(0x3);
+	bridge->b_wid_tflush;
+	printk("PCI: bridge bus timeout= 0x%x \n", bridge->b_bus_timeout);
+
+	/* set host error field */
+	bridge->b_int_host_err = 0x44;
+	bridge->b_wid_tflush;
+
+	bridge->b_wid_tflush;   	/* wait until Bridge PIO complete */
+	for (i=0; i<8; i++)
+		printk("PCI: device(%d)= 0x%x\n",i,bridge->b_device[i].reg);
+
+	/* configure device to allow bus mastering, i/o and memory mapping */
+	pci_set_master(d);
+	pci_read_config_word(d, PCI_COMMAND, &command);
+	command |= PCI_COMMAND_MEMORY;
+	command |= PCI_COMMAND_IO;
+	pci_write_config_word(d, PCI_COMMAND, command);
+	/*d->resource[1].flags |= 1;*/
+}
+
+struct pci_fixup pcibios_fixups[] = {
+	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
+	  pci_fixup_ioc3 },
+	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020,
+	  pci_fixup_isp1020 },
+	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100,
+	  pci_fixup_isp2x00 },
+	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200,
+	  pci_fixup_isp2x00 },
+	{ 0 }
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip27/ip27-reset.c linux-2.4.20/arch/mips/sgi-ip27/ip27-reset.c
--- linux-2.4.19/arch/mips/sgi-ip27/ip27-reset.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip27/ip27-reset.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,80 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Reset an IP27.
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000 by Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/smp.h>
+#include <linux/mmzone.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/reboot.h>
+#include <asm/system.h>
+#include <asm/sgialib.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/arch.h>
+#include <asm/sn/gda.h>
+#include <asm/sn/sn0/hub.h>
+
+void machine_restart(char *command) __attribute__((noreturn));
+void machine_halt(void) __attribute__((noreturn));
+void machine_power_off(void) __attribute__((noreturn));
+
+#define noreturn while(1);				/* Silence gcc.  */
+
+/* XXX How to pass the reboot command to the firmware??? */
+static void ip27_machine_restart(char *command)
+{
+#if 0
+	int i;
+#endif
+
+	printk("Reboot started from CPU %d\n", smp_processor_id());
+#ifdef CONFIG_SMP
+	smp_send_stop();
+#endif
+#if 0
+	for (i = 0; i < numnodes; i++)
+		REMOTE_HUB_S(COMPACT_TO_NASID_NODEID(i), PROMOP_REG,
+							PROMOP_REBOOT);
+#else
+	LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET);
+#endif
+	noreturn;
+}
+
+static void ip27_machine_halt(void)
+{
+	int i;
+
+#ifdef CONFIG_SMP
+	smp_send_stop();
+#endif
+	for (i = 0; i < numnodes; i++)
+		REMOTE_HUB_S(COMPACT_TO_NASID_NODEID(i), PROMOP_REG,
+							PROMOP_RESTART);
+	LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET);
+	noreturn;
+}
+
+static void ip27_machine_power_off(void)
+{
+	/* To do ...  */
+	noreturn;
+}
+
+void ip27_reboot_setup(void)
+{
+	_machine_restart = ip27_machine_restart;
+	_machine_halt = ip27_machine_halt;
+	_machine_power_off = ip27_machine_power_off;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip27/ip27-rtc.c linux-2.4.20/arch/mips/sgi-ip27/ip27-rtc.c
--- linux-2.4.19/arch/mips/sgi-ip27/ip27-rtc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip27/ip27-rtc.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,334 @@
+/*
+ *	Driver for the SGS-Thomson M48T35 Timekeeper RAM chip
+ *
+ *	Real Time Clock interface for Linux
+ *
+ *	TODO: Implement periodic interrupts.
+ *
+ *	Copyright (C) 2000 Silicon Graphics, Inc.
+ *	Written by Ulf Carlsson (ulfc@engr.sgi.com)
+ *
+ *	Based on code written by Paul Gortmaker.
+ *
+ *	This driver allows use of the real time clock (built into
+ *	nearly all computers) from user space. It exports the /dev/rtc
+ *	interface supporting various ioctl() and also the /proc/rtc
+ *	pseudo-file for status information.
+ *
+ *	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.
+ *
+ */
+
+#define RTC_VERSION		"1.09b"
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
+
+#include <asm/m48t35.h>
+#include <asm/sn/ioc3.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn0/ip27.h>
+#include <asm/sn/sn0/hub.h>
+
+static int rtc_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg);
+
+static int rtc_read_proc(char *page, char **start, off_t off,
+                         int count, int *eof, void *data);
+
+static void get_rtc_time(struct rtc_time *rtc_tm);
+
+/*
+ *	Bits in rtc_status. (6 bits of room for future expansion)
+ */
+
+#define RTC_IS_OPEN		0x01	/* means /dev/rtc is in use	*/
+#define RTC_TIMER_ON		0x02	/* missed irq timer active	*/
+
+static unsigned char rtc_status;	/* bitmapped status byte.	*/
+static spinlock_t rtc_status_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long rtc_freq;	/* Current periodic IRQ rate	*/
+static struct m48t35_rtc *rtc;
+
+/*
+ *	If this driver ever becomes modularised, it will be really nice
+ *	to make the epoch retain its value across module reload...
+ */
+
+static unsigned long epoch = 1970;	/* year corresponding to 0x00	*/
+
+static const unsigned char days_in_mo[] =
+{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		     unsigned long arg)
+{
+
+	struct rtc_time wtime;
+
+	switch (cmd) {
+	case RTC_RD_TIME:	/* Read the time/date from RTC	*/
+	{
+		get_rtc_time(&wtime);
+		break;
+	}
+	case RTC_SET_TIME:	/* Set the RTC */
+	{
+		struct rtc_time rtc_tm;
+		unsigned char mon, day, hrs, min, sec, leap_yr;
+		unsigned int yrs;
+		unsigned long flags;
+
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
+				   sizeof(struct rtc_time)))
+			return -EFAULT;
+
+		yrs = rtc_tm.tm_year + 1900;
+		mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
+		day = rtc_tm.tm_mday;
+		hrs = rtc_tm.tm_hour;
+		min = rtc_tm.tm_min;
+		sec = rtc_tm.tm_sec;
+
+		if (yrs < 1970)
+			return -EINVAL;
+
+		leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
+
+		if ((mon > 12) || (day == 0))
+			return -EINVAL;
+
+		if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
+			return -EINVAL;
+
+		if ((hrs >= 24) || (min >= 60) || (sec >= 60))
+			return -EINVAL;
+
+		if ((yrs -= epoch) > 255)    /* They are unsigned */
+			return -EINVAL;
+
+		save_flags(flags);
+		cli();
+		if (yrs > 169) {
+			restore_flags(flags);
+			return -EINVAL;
+		}
+		if (yrs >= 100)
+			yrs -= 100;
+
+		BIN_TO_BCD(sec);
+		BIN_TO_BCD(min);
+		BIN_TO_BCD(hrs);
+		BIN_TO_BCD(day);
+		BIN_TO_BCD(mon);
+		BIN_TO_BCD(yrs);
+
+		rtc->control &= ~M48T35_RTC_SET;
+		rtc->year = yrs;
+		rtc->month = mon;
+		rtc->date = day;
+		rtc->hour = hrs;
+		rtc->min = min;
+		rtc->sec = sec;
+		rtc->control &= ~M48T35_RTC_SET;
+
+		restore_flags(flags);
+		return 0;
+	}
+	default:
+		return -EINVAL;
+	}
+	return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
+}
+
+/*
+ *	We enforce only one user at a time here with the open/close.
+ *	Also clear the previous interrupt data on an open, and clean
+ *	up things on a close.
+ */
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+	spin_lock(rtc_status_lock);
+
+	if (rtc_status & RTC_IS_OPEN) {
+		spin_unlock(rtc_status_lock);
+		return -EBUSY;
+	}
+
+	rtc_status |= RTC_IS_OPEN;
+	spin_unlock(rtc_status_lock);
+
+	return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+	/*
+	 * Turn off all interrupts once the device is no longer
+	 * in use, and clear the data.
+	 */
+
+	spin_lock(rtc_status_lock);
+	rtc_status &= ~RTC_IS_OPEN;
+	spin_unlock(rtc_status_lock);
+
+	return 0;
+}
+
+/*
+ *	The various file operations we support.
+ */
+
+static struct file_operations rtc_fops = {
+	owner:		THIS_MODULE,
+	ioctl:		rtc_ioctl,
+	open:		rtc_open,
+	release:	rtc_release,
+};
+
+static struct miscdevice rtc_dev=
+{
+	RTC_MINOR,
+	"rtc",
+	&rtc_fops
+};
+
+static int __init rtc_init(void)
+{
+	unsigned long flags;
+	nasid_t nid;
+
+	nid = get_nasid();
+	rtc = (struct m48t35_rtc *)
+	    KL_CONFIG_CH_CONS_INFO(nid)->memory_base + IOC3_BYTEBUS_DEV0;
+
+	printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);
+	if (misc_register(&rtc_dev))
+		return -ENODEV;
+	create_proc_read_entry ("rtc", 0, NULL, rtc_read_proc, NULL);
+
+	save_flags(flags);
+	cli();
+	restore_flags(flags);
+	rtc_freq = 1024;
+	return 0;
+}
+
+static void __exit rtc_exit (void)
+{
+	/* interrupts and timer disabled at this point by rtc_release */
+
+	remove_proc_entry ("rtc", NULL);
+	misc_deregister(&rtc_dev);
+}
+
+module_init(rtc_init);
+module_exit(rtc_exit);
+EXPORT_NO_SYMBOLS;
+
+/*
+ *	Info exported via "/proc/rtc".
+ */
+
+static int rtc_get_status(char *buf)
+{
+	char *p;
+	struct rtc_time tm;
+
+	/*
+	 * Just emulate the standard /proc/rtc
+	 */
+
+	p = buf;
+
+	get_rtc_time(&tm);
+
+	/*
+	 * There is no way to tell if the luser has the RTC set for local
+	 * time or for Universal Standard Time (GMT). Probably local though.
+	 */
+	p += sprintf(p,
+		     "rtc_time\t: %02d:%02d:%02d\n"
+		     "rtc_date\t: %04d-%02d-%02d\n"
+	 	     "rtc_epoch\t: %04lu\n"
+		     "24hr\t\t: yes\n",
+		     tm.tm_hour, tm.tm_min, tm.tm_sec,
+		     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
+
+	return  p - buf;
+}
+
+static int rtc_read_proc(char *page, char **start, off_t off,
+                                 int count, int *eof, void *data)
+{
+        int len = rtc_get_status(page);
+        if (len <= off+count) *eof = 1;
+        *start = page + off;
+        len -= off;
+        if (len>count) len = count;
+        if (len<0) len = 0;
+        return len;
+}
+
+static void get_rtc_time(struct rtc_time *rtc_tm)
+{
+
+	unsigned long flags;
+
+	/*
+	 * Do we need to wait for the last update to finish?
+	 */
+
+	/*
+	 * Only the values that we read from the RTC are set. We leave
+	 * tm_wday, tm_yday and tm_isdst untouched. Even though the
+	 * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
+	 * by the RTC when initially set to a non-zero value.
+	 */
+	save_flags(flags);
+	cli();
+        rtc->control |= M48T35_RTC_READ;
+	rtc_tm->tm_sec = rtc->sec;
+	rtc_tm->tm_min = rtc->min;
+	rtc_tm->tm_hour = rtc->hour;
+	rtc_tm->tm_mday = rtc->date;
+	rtc_tm->tm_mon = rtc->month;
+	rtc_tm->tm_year = rtc->year;
+	rtc->control &= ~M48T35_RTC_READ;
+	restore_flags(flags);
+
+	BCD_TO_BIN(rtc_tm->tm_sec);
+	BCD_TO_BIN(rtc_tm->tm_min);
+	BCD_TO_BIN(rtc_tm->tm_hour);
+	BCD_TO_BIN(rtc_tm->tm_mday);
+	BCD_TO_BIN(rtc_tm->tm_mon);
+	BCD_TO_BIN(rtc_tm->tm_year);
+
+	/*
+	 * Account for differences between how the RTC uses the values
+	 * and how they are defined in a struct rtc_time;
+	 */
+	if ((rtc_tm->tm_year += (epoch - 1900)) <= 69)
+		rtc_tm->tm_year += 100;
+
+	rtc_tm->tm_mon--;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip27/ip27-setup.c linux-2.4.20/arch/mips/sgi-ip27/ip27-setup.c
--- linux-2.4.19/arch/mips/sgi-ip27/ip27-setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip27/ip27-setup.c	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,314 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * SGI IP27 specific setup.
+ *
+ * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
+ * Copyright (C) 1999, 2000 Silcon Graphics, Inc.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+
+#include <asm/io.h>
+#include <asm/sn/types.h>
+#include <asm/sn/sn0/addrs.h>
+#include <asm/sn/sn0/hubni.h>
+#include <asm/sn/sn0/hubio.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/ioc3.h>
+#include <asm/time.h>
+#include <asm/mipsregs.h>
+#include <asm/sn/arch.h>
+#include <asm/sn/sn_private.h>
+#include <asm/pci/bridge.h>
+#include <asm/paccess.h>
+#include <asm/sn/sn0/ip27.h>
+
+/* Check against user dumbness.  */
+#ifdef CONFIG_VT
+#error CONFIG_VT not allowed for IP27.
+#endif
+
+#undef DEBUG_SETUP
+#ifdef DEBUG_SETUP
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/*
+ * get_nasid() returns the physical node id number of the caller.
+ */
+nasid_t
+get_nasid(void)
+{
+	return (nasid_t)((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_NODEID_MASK)
+	                 >> NSRI_NODEID_SHFT);
+}
+
+/* Extracted from the IOC3 meta driver.  FIXME.  */
+static inline void ioc3_sio_init(void)
+{
+	struct ioc3 *ioc3;
+	nasid_t nid;
+        long loops;
+
+	nid = get_nasid();
+	ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base;
+
+	ioc3->sscr_a = 0;			/* PIO mode for uarta.  */
+	ioc3->sscr_b = 0;			/* PIO mode for uartb.  */
+	ioc3->sio_iec = ~0;
+	ioc3->sio_ies = (SIO_IR_SA_INT | SIO_IR_SB_INT);
+
+	loops=1000000; while(loops--);
+	ioc3->sregs.uarta.iu_fcr = 0;
+	ioc3->sregs.uartb.iu_fcr = 0;
+	loops=1000000; while(loops--);
+}
+
+static inline void ioc3_eth_init(void)
+{
+	struct ioc3 *ioc3;
+	nasid_t nid;
+
+	nid = get_nasid();
+	ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base;
+
+	ioc3->eier = 0;
+}
+
+/* Try to catch kernel missconfigurations and give user an indication what
+   option to select.  */
+static void __init verify_mode(void)
+{
+	int n_mode;
+
+	n_mode = LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_MORENODES_MASK;
+	printk("Machine is in %c mode.\n", n_mode ? 'N' : 'M');
+#ifdef CONFIG_SGI_SN0_N_MODE
+	if (!n_mode)
+		panic("Kernel compiled for M mode.");
+#else
+	if (n_mode)
+		panic("Kernel compiled for N mode.");
+#endif
+}
+
+#define XBOW_WIDGET_PART_NUM    0x0
+#define XXBOW_WIDGET_PART_NUM   0xd000          /* Xbridge */
+#define BASE_XBOW_PORT  	8     /* Lowest external port */
+
+unsigned int bus_to_cpu[256];
+unsigned long bus_to_baddr[256];
+
+void __init pcibr_setup(cnodeid_t nid)
+{
+	int 			i, start, num;
+	unsigned long		masterwid;
+	bridge_t 		*bridge;
+	volatile u64 		hubreg;
+	nasid_t	 		nasid, masternasid;
+	xwidget_part_num_t	partnum;
+	widgetreg_t 		widget_id;
+	static spinlock_t	pcibr_setup_lock = SPIN_LOCK_UNLOCKED;
+
+	/*
+	 * If the master is doing this for headless node, nothing to do.
+	 * This is because currently we require at least one of the hubs
+	 * (master hub) connected to the xbow to have at least one enabled
+	 * cpu to receive intrs. Else we need an array bus_to_intrnasid[]
+	 * that bridge_startup() needs to use to target intrs. All dma is
+	 * routed thru the widget of the master hub. The master hub wid
+	 * is selectable by WIDGET_A below.
+	 */
+	if (nid != get_compact_nodeid())
+		return;
+	/*
+	 * find what's on our local node
+	 */
+	spin_lock(&pcibr_setup_lock);
+	start = num_bridges;		/* Remember where we start from */
+	nasid = COMPACT_TO_NASID_NODEID(nid);
+	hubreg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
+	if (hubreg & IIO_LLP_CSR_IS_UP) {
+		/* link is up */
+		widget_id = *(volatile widgetreg_t *)
+                        (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
+		partnum = XWIDGET_PART_NUM(widget_id);
+		printk("Cpu %d, Nasid 0x%x, pcibr_setup(): found partnum= 0x%x",
+					smp_processor_id(), nasid, partnum);
+		if (partnum == BRIDGE_WIDGET_PART_NUM) {
+			/*
+			 * found direct connected bridge so must be Origin200
+			 */
+			printk("...is bridge\n");
+			num_bridges = 1;
+        		bus_to_wid[0] = 0x8;
+			bus_to_nid[0] = 0;
+			masterwid = 0xa;
+			bus_to_baddr[0] = 0xa100000000000000UL;
+		} else if (partnum == XBOW_WIDGET_PART_NUM) {
+			lboard_t *brd;
+			klxbow_t *xbow_p;
+			/*
+			 * found xbow, so may have multiple bridges
+			 * need to probe xbow
+			 */
+			printk("...is xbow\n");
+
+			if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid),
+                                   KLTYPE_MIDPLANE8)) == NULL)
+				printk("argh\n");
+			else
+				printk("brd = 0x%lx\n", (unsigned long) brd);
+			if ((xbow_p = (klxbow_t *)
+			     find_component(brd, NULL, KLSTRUCT_XBOW)) == NULL)
+				printk("argh\n");
+			else {
+			   /*
+			    * Okay, here's a xbow. Lets arbitrate and find
+			    * out if we should initialize it. Set enabled
+			    * hub connected at highest or lowest widget as
+			    * master.
+			    */
+#ifdef WIDGET_A
+			   i = HUB_WIDGET_ID_MAX + 1;
+			   do {
+				i--;
+			   } while ((!XBOW_PORT_TYPE_HUB(xbow_p, i)) ||
+					(!XBOW_PORT_IS_ENABLED(xbow_p, i)));
+#else
+			   i = HUB_WIDGET_ID_MIN - 1;
+			   do {
+				i++;
+			   } while ((!XBOW_PORT_TYPE_HUB(xbow_p, i)) ||
+					(!XBOW_PORT_IS_ENABLED(xbow_p, i)));
+#endif
+			   masterwid = i;
+			   masternasid = XBOW_PORT_NASID(xbow_p, i);
+			   if (nasid == masternasid)
+			   for (i=HUB_WIDGET_ID_MIN; i<=HUB_WIDGET_ID_MAX; i++) {
+				if (!XBOW_PORT_IS_ENABLED(xbow_p, i))
+					continue;
+				if (XBOW_PORT_TYPE_IO(xbow_p, i)) {
+				   widget_id = *(volatile widgetreg_t *)
+                        		   (RAW_NODE_SWIN_BASE(nasid, i) + WIDGET_ID);
+				   partnum = XWIDGET_PART_NUM(widget_id);
+				   if (partnum == BRIDGE_WIDGET_PART_NUM) {
+					printk("widget 0x%x is a bridge\n", i);
+					bus_to_wid[num_bridges] = i;
+					bus_to_nid[num_bridges] = nasid;
+					bus_to_baddr[num_bridges] = ((masterwid << 60) | (1UL << 56));	/* Barrier set */
+					num_bridges++;
+				   }
+				}
+			   }
+			}
+		} else if (partnum == XXBOW_WIDGET_PART_NUM) {
+			/*
+			 * found xbridge, assume ibrick for now
+			 */
+			printk("...is xbridge\n");
+        		bus_to_wid[0] = 0xb;
+        		bus_to_wid[1] = 0xe;
+        		bus_to_wid[2] = 0xf;
+
+        		bus_to_nid[0] = 0;
+        		bus_to_nid[1] = 0;
+        		bus_to_nid[2] = 0;
+
+			bus_to_baddr[0] = 0xa100000000000000UL;
+			bus_to_baddr[1] = 0xa100000000000000UL;
+			bus_to_baddr[2] = 0xa100000000000000UL;
+			masterwid = 0xa;
+			num_bridges = 3;
+		}
+	}
+	num = num_bridges - start;
+	spin_unlock(&pcibr_setup_lock);
+	/*
+         * set bridge registers
+         */
+	for (i = start; i < (start + num); i++) {
+
+		DBG("pcibr_setup: bus= %d  bus_to_wid[%2d]= %d  bus_to_nid[%2d]= %d\n",
+                        i, i, bus_to_wid[i], i, bus_to_nid[i]);
+
+		bus_to_cpu[i] = smp_processor_id();
+		/*
+		 * point to this bridge
+		 */
+		bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[i],bus_to_wid[i]);
+		/*
+	 	 * Clear all pending interrupts.
+	 	 */
+		bridge->b_int_rst_stat = (BRIDGE_IRR_ALL_CLR);
+		/*
+	 	 * Until otherwise set up, assume all interrupts are from slot 0
+	 	 */
+		bridge->b_int_device = (u32) 0x0;
+		/*
+	 	 * swap pio's to pci mem and io space (big windows)
+	 	 */
+		bridge->b_wid_control |= BRIDGE_CTRL_IO_SWAP;
+		bridge->b_wid_control |= BRIDGE_CTRL_MEM_SWAP;
+
+		/*
+		 * Hmm...  IRIX sets additional bits in the address which
+		 * are documented as reserved in the bridge docs.
+		 */
+		bridge->b_int_mode = 0x0;		/* Don't clear ints */
+		bridge->b_wid_int_upper = 0x8000 | (masterwid << 16);
+		bridge->b_wid_int_lower = 0x01800090;	/* PI_INT_PEND_MOD off*/
+		bridge->b_dir_map = (masterwid << 20);	/* DMA */
+		bridge->b_int_enable = 0;
+
+		bridge->b_wid_tflush;     /* wait until Bridge PIO complete */
+	}
+}
+
+extern void ip27_setup_console(void);
+extern void ip27_time_init(void);
+
+void __init ip27_setup(void)
+{
+	nasid_t nid;
+	hubreg_t p, e;
+
+	ip27_setup_console();
+
+	num_bridges = 0;
+	/*
+	 * hub_rtc init and cpu clock intr enabled for later calibrate_delay.
+	 */
+	DBG("ip27_setup(): Entered.\n");
+	nid = get_nasid();
+	printk("IP27: Running on node %d.\n", nid);
+
+	p = LOCAL_HUB_L(PI_CPU_PRESENT_A) & 1;
+	e = LOCAL_HUB_L(PI_CPU_ENABLE_A) & 1;
+	printk("Node %d has %s primary CPU%s.\n", nid,
+	       p ? "a" : "no",
+	       e ? ", CPU is running" : "");
+
+	p = LOCAL_HUB_L(PI_CPU_PRESENT_B) & 1;
+	e = LOCAL_HUB_L(PI_CPU_ENABLE_B) & 1;
+	printk("Node %d has %s secondary CPU%s.\n", nid,
+	       p ? "a" : "no",
+	       e ? ", CPU is running" : "");
+
+	verify_mode();
+	ioc3_sio_init();
+	ioc3_eth_init();
+	per_cpu_init();
+
+	mips_io_port_base = IO_BASE;
+	board_time_init = ip27_time_init;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip27/ip27-timer.c linux-2.4.20/arch/mips/sgi-ip27/ip27-timer.c
--- linux-2.4.19/arch/mips/sgi-ip27/ip27-timer.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip27/ip27-timer.c	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,239 @@
+/*
+ * Copytight (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
+ * Copytight (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/param.h>
+#include <linux/timex.h>
+#include <linux/mm.h>
+
+#include <asm/time.h>
+#include <asm/pgtable.h>
+#include <asm/sgialib.h>
+#include <asm/sn/ioc3.h>
+#include <asm/m48t35.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/arch.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/sn0/ip27.h>
+#include <asm/sn/sn0/hub.h>
+
+/*
+ * This is a hack; we really need to figure these values out dynamically
+ *
+ * Since 800 ns works very well with various HUB frequencies, such as
+ * 360, 380, 390 and 400 MHZ, we use 800 ns rtc cycle time.
+ *
+ * Ralf: which clock rate is used to feed the counter?
+ */
+#define NSEC_PER_CYCLE		800
+#define NSEC_PER_SEC		1000000000
+#define CYCLES_PER_SEC		(NSEC_PER_SEC/NSEC_PER_CYCLE)
+#define CYCLES_PER_JIFFY	(CYCLES_PER_SEC/HZ)
+
+static unsigned long ct_cur[NR_CPUS];	/* What counter should be at next timer irq */
+static long last_rtc_update;		/* Last time the rtc clock got updated */
+
+extern rwlock_t xtime_lock;
+extern volatile unsigned long wall_jiffies;
+
+
+static int set_rtc_mmss(unsigned long nowtime)
+{
+	int retval = 0;
+	int real_seconds, real_minutes, cmos_minutes;
+	struct m48t35_rtc *rtc;
+	nasid_t nid;
+
+	nid = get_nasid();
+	rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base +
+							IOC3_BYTEBUS_DEV0);
+
+	rtc->control |= M48T35_RTC_READ;
+	cmos_minutes = rtc->min;
+	BCD_TO_BIN(cmos_minutes);
+	rtc->control &= ~M48T35_RTC_READ;
+
+	/*
+	 * Since we're only adjusting minutes and seconds, don't interfere with
+	 * hour overflow. This avoids messing with unknown time zones but
+	 * requires your RTC not to be off by more than 15 minutes
+	 */
+	real_seconds = nowtime % 60;
+	real_minutes = nowtime / 60;
+	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+		real_minutes += 30;	/* correct for half hour time zone */
+	real_minutes %= 60;
+
+	if (abs(real_minutes - cmos_minutes) < 30) {
+		BIN_TO_BCD(real_seconds);
+		BIN_TO_BCD(real_minutes);
+		rtc->control |= M48T35_RTC_SET;
+		rtc->sec = real_seconds;
+		rtc->min = real_minutes;
+		rtc->control &= ~M48T35_RTC_SET;
+	} else {
+		printk(KERN_WARNING
+		       "set_rtc_mmss: can't update from %d to %d\n",
+		       cmos_minutes, real_minutes);
+		retval = -1;
+	}
+
+	return retval;
+}
+
+void rt_timer_interrupt(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+	int cpuA = ((cputoslice(cpu)) == 0);
+	int irq = 9;				/* XXX Assign number */
+
+	irq_enter(cpu, irq);
+	write_lock(&xtime_lock);
+
+again:
+	LOCAL_HUB_S(cpuA ? PI_RT_PEND_A : PI_RT_PEND_B, 0);	/* Ack  */
+	ct_cur[cpu] += CYCLES_PER_JIFFY;
+	LOCAL_HUB_S(cpuA ? PI_RT_COMPARE_A : PI_RT_COMPARE_B, ct_cur[cpu]);
+
+	if (LOCAL_HUB_L(PI_RT_COUNT) >= ct_cur[cpu])
+		goto again;
+
+	kstat.irqs[cpu][irq]++;		/* kstat only for bootcpu? */
+
+	if (cpu == 0)
+		do_timer(regs);
+
+#ifdef CONFIG_SMP
+	update_process_times(user_mode(regs));
+#endif /* CONFIG_SMP */
+
+	/*
+	 * If we have an externally synchronized Linux clock, then update
+	 * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+	 * called as close as possible to when a second starts.
+	 */
+	if ((time_status & STA_UNSYNC) == 0 &&
+	    xtime.tv_sec > last_rtc_update + 660) {
+		if (xtime.tv_usec >= 1000000 - ((unsigned) tick) / 2) {
+			if (set_rtc_mmss(xtime.tv_sec + 1) == 0)
+				last_rtc_update = xtime.tv_sec;
+			else
+				last_rtc_update = xtime.tv_sec - 600;
+		} else if (xtime.tv_usec <= ((unsigned) tick) / 2) {
+			if (set_rtc_mmss(xtime.tv_sec) == 0)
+				last_rtc_update = xtime.tv_sec;
+			else
+				last_rtc_update = xtime.tv_sec - 600;
+		}
+        }
+
+	write_unlock(&xtime_lock);
+	irq_exit(cpu, irq);
+
+	if (softirq_pending(cpu))
+		do_softirq();
+}
+
+unsigned long ip27_do_gettimeoffset(void)
+{
+	unsigned long ct_cur1;
+	ct_cur1 = REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT) + CYCLES_PER_JIFFY;
+	return (ct_cur1 - ct_cur[0]) * NSEC_PER_CYCLE / 1000;
+}
+
+/* Includes for ioc3_init().  */
+#include <asm/sn/types.h>
+#include <asm/sn/sn0/addrs.h>
+#include <asm/sn/sn0/hubni.h>
+#include <asm/sn/sn0/hubio.h>
+#include <asm/pci/bridge.h>
+
+static __init unsigned long get_m48t35_time(void)
+{
+        unsigned int year, month, date, hour, min, sec;
+	struct m48t35_rtc *rtc;
+	nasid_t nid;
+
+	nid = get_nasid();
+	rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base +
+							IOC3_BYTEBUS_DEV0);
+
+	rtc->control |= M48T35_RTC_READ;
+	sec = rtc->sec;
+	min = rtc->min;
+	hour = rtc->hour;
+	date = rtc->date;
+	month = rtc->month;
+	year = rtc->year;
+	rtc->control &= ~M48T35_RTC_READ;
+
+        BCD_TO_BIN(sec);
+        BCD_TO_BIN(min);
+        BCD_TO_BIN(hour);
+        BCD_TO_BIN(date);
+        BCD_TO_BIN(month);
+        BCD_TO_BIN(year);
+
+        year += 1970;
+
+        return mktime(year, month, date, hour, min, sec);
+}
+
+void __init ip27_time_init(void)
+{
+	xtime.tv_sec = get_m48t35_time();
+	xtime.tv_usec = 0;
+
+	do_gettimeoffset = ip27_do_gettimeoffset;
+}
+
+void __init cpu_time_init(void)
+{
+	lboard_t *board;
+	klcpu_t *cpu;
+	int cpuid;
+
+	/* Don't use ARCS.  ARCS is fragile.  Klconfig is simple and sane.  */
+	board = find_lboard(KL_CONFIG_INFO(get_nasid()), KLTYPE_IP27);
+	if (!board)
+		panic("Can't find board info for myself.");
+
+	cpuid = LOCAL_HUB_L(PI_CPU_NUM) ? IP27_CPU0_INDEX : IP27_CPU1_INDEX;
+	cpu = (klcpu_t *) KLCF_COMP(board, cpuid);
+	if (!cpu)
+		panic("No information about myself?");
+
+	printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed);
+
+	set_cp0_status(SRB_TIMOCLK);
+}
+
+void __init hub_rtc_init(cnodeid_t cnode)
+{
+	/*
+	 * We only need to initialize the current node.
+	 * If this is not the current node then it is a cpuless
+	 * node and timeouts will not happen there.
+	 */
+	if (get_compact_nodeid() == cnode) {
+		int cpu = smp_processor_id();
+		LOCAL_HUB_S(PI_RT_EN_A, 1);
+		LOCAL_HUB_S(PI_RT_EN_B, 1);
+		LOCAL_HUB_S(PI_PROF_EN_A, 0);
+		LOCAL_HUB_S(PI_PROF_EN_B, 0);
+		ct_cur[cpu] = CYCLES_PER_JIFFY;
+		LOCAL_HUB_S(PI_RT_COMPARE_A, ct_cur[cpu]);
+		LOCAL_HUB_S(PI_RT_COUNT, 0);
+		LOCAL_HUB_S(PI_RT_PEND_A, 0);
+		LOCAL_HUB_S(PI_RT_COMPARE_B, ct_cur[cpu]);
+		LOCAL_HUB_S(PI_RT_COUNT, 0);
+		LOCAL_HUB_S(PI_RT_PEND_B, 0);
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip32/Makefile linux-2.4.20/arch/mips/sgi-ip32/Makefile
--- linux-2.4.19/arch/mips/sgi-ip32/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip32/Makefile	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,22 @@
+#
+# Makefile for the SGI specific kernel interface routines
+# under Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+USE_STANDARD_AS_RULE := true
+
+O_TARGET := ip32-kern.a
+
+all: ip32-kern.a ip32-irq-glue.o
+
+obj-y	+= ip32-berr.o ip32-rtc.o ip32-setup.o ip32-irq.o ip32-irq-glue.o \
+	   ip32-timer.o crime.o ip32-reset.o
+
+obj-$(CONFIG_PCI)   += ip32-pci.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip32/crime.c linux-2.4.20/arch/mips/sgi-ip32/crime.c
--- linux-2.4.19/arch/mips/sgi-ip32/crime.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip32/crime.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,49 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 Keith M Wesolowski
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/ip32/crime.h>
+#include <asm/ptrace.h>
+
+void __init crime_init (void)
+{
+	u64 id = crime_read_64 (CRIME_ID);
+	u64 rev = id & CRIME_ID_REV;
+
+	id = (id & CRIME_ID_IDBITS) >> 4;
+
+	printk ("CRIME id %1lx rev %ld detected at %016lx\n", id, rev,
+		(unsigned long) CRIME_BASE);
+}
+
+/* XXX Like on Sun, these give us various useful information to printk. */
+void crime_memerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+	u64 memerr = crime_read_64 (CRIME_MEM_ERROR_STAT);
+	u64 addr = crime_read_64 (CRIME_MEM_ERROR_ADDR);
+	memerr &= CRIME_MEM_ERROR_STAT_MASK;
+
+	printk ("CRIME memory error at physaddr 0x%08lx status %08lx\n",
+		addr << 2, memerr);
+
+	crime_write_64 (CRIME_MEM_ERROR_STAT, 0);
+}
+
+void crime_cpuerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+	u64 cpuerr = crime_read_64 (CRIME_CPU_ERROR_STAT);
+	u64 addr = crime_read_64 (CRIME_CPU_ERROR_ADDR);
+	cpuerr &= CRIME_CPU_ERROR_MASK;
+	addr <<= 2UL;
+
+	printk ("CRIME CPU interface error detected at %09lx status %08lx\n",
+		addr, cpuerr);
+
+	crime_write_64 (CRIME_CPU_ERROR_STAT, 0);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip32/ip32-berr.c linux-2.4.20/arch/mips/sgi-ip32/ip32-berr.c
--- linux-2.4.19/arch/mips/sgi-ip32/ip32-berr.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip32/ip32-berr.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,36 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994, 1995, 1996, 1999, 2000 by Ralf Baechle
+ * Copyright (C) 1999, 2000 by Silicon Graphics
+ * Copyright (C) 2002  Maciej W. Rozycki
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/traps.h>
+#include <asm/uaccess.h>
+#include <asm/addrspace.h>
+#include <asm/ptrace.h>
+
+int
+be_ip32_handler(struct pt_regs *regs, int is_fixup)
+{
+	int data = regs->cp0_cause & 4;
+
+	if (is_fixup)
+		return MIPS_BE_FIXUP;
+
+	printk("Got %cbe at 0x%lx\n", data ? 'd' : 'i', regs->cp0_epc);
+	show_regs(regs);
+	dump_tlb_all();
+	while(1);
+	force_sig(SIGBUS, current);
+}
+
+void __init
+bus_error_init(void)
+{
+	be_board_handler = be_ip32_handler;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip32/ip32-irq-glue.S linux-2.4.20/arch/mips/sgi-ip32/ip32-irq-glue.S
--- linux-2.4.19/arch/mips/sgi-ip32/ip32-irq-glue.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip32/ip32-irq-glue.S	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,87 @@
+/*
+ * Low level interrupt handler for the SGI O2 aka IP32 aka Moosehead
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000 Harald Koerfgen
+ * Copyright (C) 2001 Keith M Wesolowski
+ */
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/stackframe.h>
+#include <asm/addrspace.h>
+#include <asm/ip32/ip32_ints.h>
+
+		.text
+		.set    noreorder
+		.set    noat
+		.align  5
+		NESTED(ip32_handle_int, PT_SIZE, ra)
+		.set    noat
+		SAVE_ALL
+		CLI			# TEST: interrupts should be off
+		.set    at
+		.set    noreorder
+
+		mfc0	s0,CP0_CAUSE
+
+		andi	t1, s0, IE_IRQ0
+		bnez	t1, handle_irq0
+		 andi	t1, s0, IE_IRQ1
+		bnez	t1, handle_irq1
+		 andi	t1, s0, IE_IRQ2
+		bnez	t1, handle_irq2
+		 andi	t1, s0, IE_IRQ3
+		bnez	t1, handle_irq3
+		 andi	t1, s0, IE_IRQ4
+		bnez	t1, handle_irq4
+		 andi	t1, s0, IE_IRQ5
+		bnez	t1, handle_irq5
+		 nop
+
+		/* Either someone has triggered the "software interrupts"
+		 * or we lost an interrupt somehow.  Ignore it.
+		 */
+		j	ret_from_irq
+		 nop
+
+handle_irq0:
+		jal	ip32_irq0
+		 move	a0, sp
+		j	ret_from_irq
+		 nop
+
+handle_irq1:
+		jal	ip32_irq1
+		 move	a0, sp
+		j	ret_from_irq
+		 nop
+
+handle_irq2:
+		jal	ip32_irq2
+		 move	a0, sp
+		j	ret_from_irq
+		 nop
+
+handle_irq3:
+		jal	ip32_irq3
+		 move	a0, sp
+		j	ret_from_irq
+		 nop
+
+handle_irq4:
+		jal	ip32_irq4
+		 move	a0, sp
+		j	ret_from_irq
+		 nop
+
+handle_irq5:
+		jal	ip32_irq5
+		move	a0, sp
+		j	ret_from_irq
+		 nop
+
+		END(ip32_handle_int)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip32/ip32-irq.c linux-2.4.20/arch/mips/sgi-ip32/ip32-irq.c
--- linux-2.4.19/arch/mips/sgi-ip32/ip32-irq.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip32/ip32-irq.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,584 @@
+/*
+ * Code to handle IP32 IRQs
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000 Harald Koerfgen
+ * Copyright (C) 2001 Keith M Wesolowski
+ */
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+
+#include <asm/bitops.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/ip32/ip32_ints.h>
+#include <asm/ip32/crime.h>
+#include <asm/ip32/mace.h>
+#include <asm/signal.h>
+
+#undef DEBUG_IRQ
+#ifdef DEBUG_IRQ
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/* O2 irq map
+ *
+ * IP0 -> software (ignored)
+ * IP1 -> software (ignored)
+ * IP2 -> (irq0) C crime 1.1 all interrupts; crime 1.5 ???
+ * IP3 -> (irq1) X unknown
+ * IP4 -> (irq2) X unknown
+ * IP5 -> (irq3) X unknown
+ * IP6 -> (irq4) X unknown
+ * IP7 -> (irq5) 0 CPU count/compare timer (system timer)
+ *
+ * crime: (C)
+ *
+ * CRIME_INT_STAT 31:0:
+ *
+ * 0 -> 1 Video in 1
+ * 1 -> 2 Video in 2
+ * 2 -> 3 Video out
+ * 3 -> 4 Mace ethernet
+ * 4 -> S  SuperIO sub-interrupt
+ * 5 -> M  Miscellaneous sub-interrupt
+ * 6 -> A  Audio sub-interrupt
+ * 7 -> 8  PCI bridge errors
+ * 8 -> 9  PCI SCSI aic7xxx 0
+ * 9 -> 10  PCI SCSI aic7xxx 1
+ * 10 -> 11 PCI slot 0
+ * 11 -> 12 unused (PCI slot 1)
+ * 12 -> 13 unused (PCI slot 2)
+ * 13 -> 14 unused (PCI shared 0)
+ * 14 -> 15 unused (PCI shared 1)
+ * 15 -> 16 unused (PCI shared 2)
+ * 16 -> 17 GBE0 (E)
+ * 17 -> 18 GBE1 (E)
+ * 18 -> 19 GBE2 (E)
+ * 19 -> 20 GBE3 (E)
+ * 20 -> 21 CPU errors
+ * 21 -> 22 Memory errors
+ * 22 -> 23 RE empty edge (E)
+ * 23 -> 24 RE full edge (E)
+ * 24 -> 25 RE idle edge (E)
+ * 25 -> 26 RE empty level
+ * 26 -> 27 RE full level
+ * 27 -> 28 RE idle level
+ * 28 -> 29  unused (software 0) (E)
+ * 29 -> 30  unused (software 1) (E)
+ * 30 -> 31  unused (software 2) - crime 1.5 CPU SysCorError (E)
+ * 31 -> 32 VICE
+ *
+ * S, M, A: Use the MACE ISA interrupt register
+ * MACE_ISA_INT_STAT 31:0
+ *
+ * 0-7 -> 33-40 Audio
+ * 8 -> 41 RTC
+ * 9 -> 42 Keyboard
+ * 10 -> X Keyboard polled
+ * 11 -> 44 Mouse
+ * 12 -> X Mouse polled
+ * 13-15 -> 46-48 Count/compare timers
+ * 16-19 -> 49-52 Parallel (16 E)
+ * 20-25 -> 53-58 Serial 1 (22 E)
+ * 26-31 -> 59-64 Serial 2 (28 E)
+ *
+ * Note that this means IRQs 5-7, 43, and 45 do not exist.  This is a
+ * different IRQ map than IRIX uses, but that's OK as Linux irq handling
+ * is quite different anyway.
+ */
+
+/* Some initial interrupts to set up */
+extern void crime_memerr_intr (unsigned int irq, void *dev_id,
+			       struct pt_regs *regs);
+extern void crime_cpuerr_intr (unsigned int irq, void *dev_id,
+			       struct pt_regs *regs);
+
+struct irqaction memerr_irq = { crime_memerr_intr, SA_INTERRUPT,
+			       0, "CRIME memory error", NULL,
+			       NULL };
+struct irqaction cpuerr_irq = { crime_cpuerr_intr, SA_INTERRUPT,
+			       0, "CRIME CPU error", NULL,
+			       NULL };
+
+extern void ip32_handle_int (void);
+asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs);
+
+/*
+ * For interrupts wired from a single device to the CPU.  Only the clock
+ * uses this it seems, which is IRQ 0 and IP7.
+ */
+
+static void enable_cpu_irq(unsigned int irq)
+{
+	set_cp0_status(STATUSF_IP7);
+}
+
+static unsigned int startup_cpu_irq(unsigned int irq)
+{
+	enable_cpu_irq(irq);
+	return 0;
+}
+
+static void disable_cpu_irq(unsigned int irq)
+{
+	clear_cp0_status(STATUSF_IP7);
+}
+
+static void end_cpu_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		enable_cpu_irq (irq);
+}
+
+#define shutdown_cpu_irq disable_cpu_irq
+#define mask_and_ack_cpu_irq disable_cpu_irq
+
+static struct hw_interrupt_type ip32_cpu_interrupt = {
+	"IP32 CPU",
+	startup_cpu_irq,
+	shutdown_cpu_irq,
+	enable_cpu_irq,
+	disable_cpu_irq,
+	mask_and_ack_cpu_irq,
+	end_cpu_irq,
+	NULL
+};
+
+/*
+ * This is for pure CRIME interrupts - ie not MACE.  The advantage?
+ * We get to split the register in half and do faster lookups.
+ */
+
+static void enable_crime_irq(unsigned int irq)
+{
+	u64 crime_mask;
+	unsigned long flags;
+
+	save_and_cli(flags);
+	crime_mask = crime_read_64(CRIME_INT_MASK);
+	crime_mask |= 1 << (irq - 1);
+	crime_write_64(CRIME_INT_MASK, crime_mask);
+	restore_flags(flags);
+}
+
+static unsigned int startup_crime_irq(unsigned int irq)
+{
+	enable_crime_irq(irq);
+	return 0; /* This is probably not right; we could have pending irqs */
+}
+
+static void disable_crime_irq(unsigned int irq)
+{
+	u64 crime_mask;
+	unsigned long flags;
+
+	save_and_cli(flags);
+	crime_mask = crime_read_64(CRIME_INT_MASK);
+	crime_mask &= ~(1 << (irq - 1));
+	crime_write_64(CRIME_INT_MASK, crime_mask);
+	restore_flags(flags);
+}
+
+static void mask_and_ack_crime_irq (unsigned int irq)
+{
+	u64 crime_mask;
+	unsigned long flags;
+
+	/* Edge triggered interrupts must be cleared. */
+	if ((irq >= CRIME_GBE0_IRQ && irq <= CRIME_GBE3_IRQ)
+	    || (irq >= CRIME_RE_EMPTY_E_IRQ && irq <= CRIME_RE_IDLE_E_IRQ)
+	    || (irq >= CRIME_SOFT0_IRQ && irq <= CRIME_SOFT2_IRQ)) {
+		save_and_cli(flags);
+		crime_mask = crime_read_64(CRIME_HARD_INT);
+		crime_mask &= ~(1 << (irq - 1));
+		crime_write_64(CRIME_HARD_INT, crime_mask);
+		restore_flags(flags);
+	}
+	disable_crime_irq(irq);
+}
+
+static void end_crime_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		enable_crime_irq (irq);
+}
+
+#define shutdown_crime_irq disable_crime_irq
+
+static struct hw_interrupt_type ip32_crime_interrupt = {
+	"IP32 CRIME",
+	startup_crime_irq,
+	shutdown_crime_irq,
+	enable_crime_irq,
+	disable_crime_irq,
+	mask_and_ack_crime_irq,
+	end_crime_irq,
+	NULL
+};
+
+/*
+ * This is for MACE PCI interrupts.  We can decrease bus traffic by masking
+ * as close to the source as possible.  This also means we can take the
+ * next chunk of the CRIME register in one piece.
+ */
+
+static void enable_macepci_irq(unsigned int irq)
+{
+	u32 mace_mask;
+	u64 crime_mask;
+	unsigned long flags;
+
+	save_and_cli(flags);
+	mace_mask = mace_read_32(MACEPCI_CONTROL);
+	mace_mask |= MACEPCI_CONTROL_INT(irq - 9);
+	mace_write_32(MACEPCI_CONTROL, mace_mask);
+	/*
+	 * In case the CRIME interrupt isn't enabled, we must enable it;
+	 * however, we never disable interrupts at that level.
+	 */
+	crime_mask = crime_read_64(CRIME_INT_MASK);
+	crime_mask |= 1 << (irq - 1);
+	crime_write_64(CRIME_INT_MASK, crime_mask);
+	restore_flags(flags);
+}
+
+static unsigned int startup_macepci_irq(unsigned int irq)
+{
+	enable_macepci_irq (irq);
+
+	return 0; /* XXX */
+}
+
+static void disable_macepci_irq(unsigned int irq)
+{
+	u32 mace_mask;
+	unsigned long flags;
+
+	save_and_cli(flags);
+	mace_mask = mace_read_32(MACEPCI_CONTROL);
+	mace_mask &= ~MACEPCI_CONTROL_INT(irq - 9);
+	mace_write_32(MACEPCI_CONTROL, mace_mask);
+	restore_flags(flags);
+}
+
+static void end_macepci_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		enable_macepci_irq (irq);
+}
+
+#define shutdown_macepci_irq disable_macepci_irq
+#define mask_and_ack_macepci_irq disable_macepci_irq
+
+static struct hw_interrupt_type ip32_macepci_interrupt = {
+	"IP32 MACE PCI",
+	startup_macepci_irq,
+	shutdown_macepci_irq,
+	enable_macepci_irq,
+	disable_macepci_irq,
+	mask_and_ack_macepci_irq,
+	end_macepci_irq,
+	NULL
+};
+
+/* This is used for MACE ISA interrupts.  That means bits 4-6 in the
+ * CRIME register.
+ */
+
+static void enable_maceisa_irq (unsigned int irq)
+{
+	u64 crime_mask;
+	u32 mace_mask;
+	unsigned int crime_int = 0;
+	unsigned long flags;
+
+	DBG ("maceisa enable: %u\n", irq);
+
+	switch (irq) {
+	case MACEISA_AUDIO_SW_IRQ ... MACEISA_AUDIO3_MERR_IRQ:
+		crime_int = MACE_AUDIO_INT;
+		break;
+	case MACEISA_RTC_IRQ ... MACEISA_TIMER2_IRQ:
+		crime_int = MACE_MISC_INT;
+		break;
+	case MACEISA_PARALLEL_IRQ ... MACEISA_SERIAL2_RDMAOR_IRQ:
+		crime_int = MACE_SUPERIO_INT;
+		break;
+	}
+	DBG ("crime_int %016lx enabled\n", crime_int);
+	save_and_cli(flags);
+	crime_mask = crime_read_64(CRIME_INT_MASK);
+	crime_mask |= crime_int;
+	crime_write_64(CRIME_INT_MASK, crime_mask);
+	mace_mask = mace_read_32(MACEISA_INT_MASK);
+	mace_mask |= 1 << (irq - 33);
+	mace_write_32(MACEISA_INT_MASK, mace_mask);
+	restore_flags(flags);
+}
+
+static unsigned int startup_maceisa_irq (unsigned int irq)
+{
+	enable_maceisa_irq(irq);
+	return 0;
+}
+
+static void disable_maceisa_irq(unsigned int irq)
+{
+	u32 mace_mask;
+	unsigned long flags;
+
+	save_and_cli (flags);
+	mace_mask = mace_read_32(MACEISA_INT_MASK);
+	mace_mask &= ~(1 << (irq - 33));
+	mace_write_32(MACEISA_INT_MASK, mace_mask);
+	restore_flags(flags);
+}
+
+static void mask_and_ack_maceisa_irq(unsigned int irq)
+{
+	u32 mace_mask;
+	unsigned long flags;
+
+	switch (irq) {
+	case MACEISA_PARALLEL_IRQ:
+	case MACEISA_SERIAL1_TDMAPR_IRQ:
+	case MACEISA_SERIAL2_TDMAPR_IRQ:
+		save_and_cli(flags);
+		mace_mask = mace_read_32(MACEISA_INT_STAT);
+		mace_mask &= ~(1 << (irq - 33));
+		mace_write_32(MACEISA_INT_STAT, mace_mask);
+		restore_flags(flags);
+		break;
+	}
+	disable_maceisa_irq(irq);
+}
+
+static void end_maceisa_irq(unsigned irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		enable_maceisa_irq (irq);
+}
+
+#define shutdown_maceisa_irq disable_maceisa_irq
+
+static struct hw_interrupt_type ip32_maceisa_interrupt = {
+	"IP32 MACE ISA",
+	startup_maceisa_irq,
+	shutdown_maceisa_irq,
+	enable_maceisa_irq,
+	disable_maceisa_irq,
+	mask_and_ack_maceisa_irq,
+	end_maceisa_irq,
+	NULL
+};
+
+/* This is used for regular non-ISA, non-PCI MACE interrupts.  That means
+ * bits 0-3 and 7 in the CRIME register.
+ */
+
+static void enable_mace_irq(unsigned int irq)
+{
+	u64 crime_mask;
+	unsigned long flags;
+
+	save_and_cli (flags);
+	crime_mask = crime_read_64 (CRIME_INT_MASK);
+	crime_mask |= 1 << (irq - 1);
+	crime_write_64 (CRIME_INT_MASK, crime_mask);
+	restore_flags (flags);
+}
+
+static unsigned int startup_mace_irq(unsigned int irq)
+{
+	enable_mace_irq(irq);
+	return 0;
+}
+
+static void disable_mace_irq(unsigned int irq)
+{
+	u64 crime_mask;
+	unsigned long flags;
+
+	save_and_cli (flags);
+	crime_mask = crime_read_64 (CRIME_INT_MASK);
+	crime_mask &= ~(1 << (irq - 1));
+	crime_write_64 (CRIME_INT_MASK, crime_mask);
+	restore_flags(flags);
+}
+
+static void end_mace_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		enable_mace_irq (irq);
+}
+
+#define shutdown_mace_irq disable_mace_irq
+#define mask_and_ack_mace_irq disable_mace_irq
+
+static struct hw_interrupt_type ip32_mace_interrupt = {
+	"IP32 MACE",
+	startup_mace_irq,
+	shutdown_mace_irq,
+	enable_mace_irq,
+	disable_mace_irq,
+	mask_and_ack_mace_irq,
+	end_mace_irq,
+	NULL
+};
+
+static void ip32_unknown_interrupt (struct pt_regs *regs)
+{
+	u64 crime;
+	u32 mace;
+
+	printk ("Unknown interrupt occurred!\n");
+	printk ("cp0_status: %08x\tcp0_cause: %08x\n",
+		read_32bit_cp0_register (CP0_STATUS),
+		read_32bit_cp0_register (CP0_CAUSE));
+	crime = crime_read_64 (CRIME_INT_MASK);
+	printk ("CRIME interrupt mask: %016lx\n", crime);
+	crime = crime_read_64 (CRIME_INT_STAT);
+	printk ("CRIME interrupt status: %016lx\n", crime);
+	crime = crime_read_64 (CRIME_HARD_INT);
+	printk ("CRIME hardware interrupt register: %016lx\n", crime);
+	mace = mace_read_32 (MACEISA_INT_MASK);
+	printk ("MACE ISA interrupt mask: %08x\n", mace);
+	mace = mace_read_32 (MACEISA_INT_STAT);
+	printk ("MACE ISA interrupt status: %08x\n", mace);
+	mace = mace_read_32 (MACEPCI_CONTROL);
+	printk ("MACE PCI control register: %08x\n", mace);
+
+	printk("Register dump:\n");
+	show_regs(regs);
+
+	printk("Please mail this report to linux-mips@oss.sgi.com\n");
+	printk("Spinning...");
+	while(1) ;
+}
+
+/* CRIME 1.1 appears to deliver all interrupts to this one pin. */
+void ip32_irq0(struct pt_regs *regs)
+{
+	u64 crime_int;
+	u64 crime_mask;
+	int irq = 0;
+	unsigned long flags;
+
+	save_and_cli (flags);
+	/* disable crime interrupts */
+	crime_mask = crime_read_64(CRIME_INT_MASK);
+	crime_write_64(CRIME_INT_MASK, 0);
+
+	crime_int = crime_read_64(CRIME_INT_STAT);
+
+	if (crime_int & CRIME_MACE_INT_MASK) {
+		crime_int &= CRIME_MACE_INT_MASK;
+		irq = ffs (crime_int);
+	} else if (crime_int & CRIME_MACEISA_INT_MASK) {
+		u32 mace_int;
+		mace_int = mace_read_32 (MACEISA_INT_STAT);
+		if (mace_int == 0)
+			irq = 0;
+		else
+			irq = ffs (mace_int) + 32;
+	} else if (crime_int & CRIME_MACEPCI_INT_MASK) {
+		crime_int &= CRIME_MACEPCI_INT_MASK;
+		crime_int >>= 8;
+		irq = ffs (crime_int) + 8;
+	} else if (crime_int & 0xffff0000) {
+		crime_int >>= 16;
+		irq = ffs (crime_int) + 16;
+	}
+	if (irq == 0)
+		ip32_unknown_interrupt(regs);
+	DBG("*irq %u*\n", irq);
+	do_IRQ(irq, regs);
+
+	/* enable crime interrupts */
+	crime_write_64(CRIME_INT_MASK, crime_mask);
+	restore_flags (flags);
+}
+
+void ip32_irq1(struct pt_regs *regs)
+{
+	ip32_unknown_interrupt (regs);
+}
+
+void ip32_irq2(struct pt_regs *regs)
+{
+	ip32_unknown_interrupt (regs);
+}
+
+void ip32_irq3(struct pt_regs *regs)
+{
+	ip32_unknown_interrupt (regs);
+}
+
+void ip32_irq4(struct pt_regs *regs)
+{
+	ip32_unknown_interrupt (regs);
+}
+
+void ip32_irq5(struct pt_regs *regs)
+{
+	do_IRQ (CLOCK_IRQ, regs);
+}
+
+void __init init_IRQ(void)
+{
+	unsigned int irq;
+	int i;
+
+	/* Install our interrupt handler, then clear and disable all
+	 * CRIME and MACE interrupts.
+	 */
+	crime_write_64(CRIME_INT_MASK, 0);
+	crime_write_64(CRIME_HARD_INT, 0);
+	crime_write_64(CRIME_SOFT_INT, 0);
+	mace_write_32(MACEISA_INT_STAT, 0);
+	mace_write_32(MACEISA_INT_MASK, 0);
+	set_except_vector(0, ip32_handle_int);
+
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc[i].status  = IRQ_DISABLED;
+		irq_desc[i].action  = NULL;
+		irq_desc[i].depth   = 1;
+		irq_desc[i].handler = &no_irq_type;
+	}
+
+	for (irq = 0; irq <= IP32_IRQ_MAX; irq++) {
+		hw_irq_controller *controller;
+
+		if (irq == CLOCK_IRQ)
+			controller = &ip32_cpu_interrupt;
+		else if (irq <= MACE_PCI_BRIDGE_IRQ && irq >= MACE_VID_IN1_IRQ)
+			controller = &ip32_mace_interrupt;
+		else if (irq <= MACEPCI_SHARED2_IRQ && irq >= MACEPCI_SCSI0_IRQ)
+			controller = &ip32_macepci_interrupt;
+		else if (irq <= CRIME_VICE_IRQ && irq >= CRIME_GBE0_IRQ)
+			controller = &ip32_crime_interrupt;
+		else
+			controller = &ip32_maceisa_interrupt;
+
+		irq_desc[irq].status = IRQ_DISABLED;
+		irq_desc[irq].action = 0;
+		irq_desc[irq].depth = 0;
+		irq_desc[irq].handler = controller;
+	}
+	setup_irq(CRIME_MEMERR_IRQ, &memerr_irq);
+	setup_irq(CRIME_CPUERR_IRQ, &cpuerr_irq);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip32/ip32-pci.c linux-2.4.20/arch/mips/sgi-ip32/ip32-pci.c
--- linux-2.4.19/arch/mips/sgi-ip32/ip32-pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip32/ip32-pci.c	2002-10-29 11:18:51.000000000 +0000
@@ -0,0 +1,460 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000, 2001 Keith M Wesolowski
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <asm/pci.h>
+#include <asm/ip32/mace.h>
+#include <asm/ip32/crime.h>
+#include <asm/ip32/ip32_ints.h>
+#include <linux/delay.h>
+
+#undef DEBUG_MACE_PCI
+
+/*
+ * O2 has up to 5 PCI devices connected into the MACE bridge.  The device
+ * map looks like this:
+ *
+ * 0  aic7xxx 0
+ * 1  aic7xxx 1
+ * 2  expansion slot
+ * 3  N/C
+ * 4  N/C
+ */
+
+#define chkslot(dev)							\
+do {									\
+	if ((dev)->bus->number > 0 || PCI_SLOT ((dev)->devfn) < 1	\
+	    || PCI_SLOT ((dev)->devfn) > 3)				\
+		return PCIBIOS_DEVICE_NOT_FOUND;			\
+} while (0)
+
+#define mkaddr(dev, where) \
+((((dev)->devfn & 0xffUL) << 8) | ((where) & 0xfcUL))
+
+void macepci_error (int irq, void *dev, struct pt_regs *regs);
+
+static int macepci_read_config_byte (struct pci_dev *dev, int where,
+				     u8 *val)
+{
+	*val = 0xff;
+	chkslot (dev);
+	mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where));
+	*val = mace_read_8 (MACEPCI_CONFIG_DATA + ((where & 3UL) ^ 3UL));
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int macepci_read_config_word (struct pci_dev *dev, int where,
+				     u16 *val)
+{
+	*val = 0xffff;
+	chkslot (dev);
+	if (where & 1)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+ 	mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where));
+	*val = mace_read_16 (MACEPCI_CONFIG_DATA + ((where & 2UL) ^ 2UL));
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int macepci_read_config_dword (struct pci_dev *dev, int where,
+				      u32 *val)
+{
+	*val = 0xffffffff;
+	chkslot (dev);
+	if (where & 3)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where));
+	*val = mace_read_32 (MACEPCI_CONFIG_DATA);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int macepci_write_config_byte (struct pci_dev *dev, int where,
+				      u8 val)
+{
+	chkslot (dev);
+	mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where));
+	mace_write_8 (MACEPCI_CONFIG_DATA + ((where & 3UL) ^ 3UL), val);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int macepci_write_config_word (struct pci_dev *dev, int where,
+				      u16 val)
+{
+	chkslot (dev);
+	if (where & 1)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where));
+	mace_write_16 (MACEPCI_CONFIG_DATA + ((where & 2UL) ^ 2UL), val);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int macepci_write_config_dword (struct pci_dev *dev, int where,
+                                          u32 val)
+{
+	chkslot (dev);
+	if (where & 3)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where));
+	mace_write_32 (MACEPCI_CONFIG_DATA, val);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops macepci_ops = {
+	macepci_read_config_byte,
+	macepci_read_config_word,
+	macepci_read_config_dword,
+	macepci_write_config_byte,
+	macepci_write_config_word,
+	macepci_write_config_dword
+};
+
+struct pci_fixup pcibios_fixups[] = { { 0 } };
+
+void __init pcibios_init (void)
+{
+	struct pci_dev *dev;
+	u32 start, size;
+	u16 cmd;
+	u32 base_io = 0x3000; /* The first i/o address to assign after SCSI */
+	u32 base_mem = 0x80100000; /* Likewise */
+	u32 rev = mace_read_32 (MACEPCI_REV);
+	int i;
+
+	printk ("MACE: PCI rev %d detected at %016lx\n", rev,
+		(u64) MACE_BASE + MACE_PCI);
+
+	/* These are *bus* addresses */
+	ioport_resource.start = 0;
+	ioport_resource.end = 0xffffffffUL;
+	iomem_resource.start = 0x80000000UL;
+	iomem_resource.end = 0xffffffffUL;
+
+	/* Clear any outstanding errors and enable interrupts */
+	mace_write_32 (MACEPCI_ERROR_ADDR, 0);
+	mace_write_32 (MACEPCI_ERROR_FLAGS, 0);
+	mace_write_32 (MACEPCI_CONTROL, 0xff008500);
+	crime_write_64 (CRIME_HARD_INT, 0UL);
+	crime_write_64 (CRIME_SOFT_INT, 0UL);
+	crime_write_64 (CRIME_INT_STAT, 0x000000000000ff00UL);
+
+	if (request_irq (MACE_PCI_BRIDGE_IRQ, macepci_error, 0,
+			 "MACE PCI error", NULL))
+		panic("PCI bridge can't get interrupt; can't happen.");
+
+	pci_scan_bus (0, &macepci_ops, NULL);
+
+#ifdef DEBUG_MACE_PCI
+	pci_for_each_dev (dev) {
+		printk ("Device: %d/%d/%d ARCS-assigned bus resource map\n",
+			dev->bus->number, PCI_SLOT (dev->devfn),
+			PCI_FUNC (dev->devfn));
+		for (i=0; i < DEVICE_COUNT_RESOURCE; i++) {
+			if (dev->resource[i].start == 0)
+				continue;
+			printk ("%d: %016lx - %016lx (flags %04lx)\n",
+				i, dev->resource[i].start,
+				dev->resource[i].end, dev->resource[i].flags);
+		}
+	}
+#endif
+	/*
+	 * Assign sane resources to and enable all devices.  The requirement
+	 * for the SCSI controllers is well-known: a 256-byte I/O region
+	 * which we must assign, and a 1-page memory region which is
+	 * assigned by the system firmware.
+	 */
+	pci_for_each_dev (dev) {
+		switch (PCI_SLOT (dev->devfn)) {
+		case 1: /* SCSI bus 0 */
+			dev->resource[0].start = 0x1000UL;
+			dev->resource[0].end = 0x10ffUL;
+			break;
+		case 2: /* SCSI bus 1 */
+			dev->resource[0].start = 0x2000UL;
+			dev->resource[0].end = 0x20ffUL;
+			break;
+		default: /* Slots - I guess we have only 1 */
+			for (i=0; i < 6; i++) {
+				size = dev->resource[i].end
+					- dev->resource[i].start;
+				if (!size
+				    || !(dev->resource[i].flags
+					 & (IORESOURCE_IO|IORESOURCE_MEM))) {
+					dev->resource[i].start
+						= dev->resource[i].end = 0UL;
+					continue;
+				}
+				if (dev->resource[i].flags & IORESOURCE_IO) {
+					dev->resource[i].start = base_io;
+					base_io += PAGE_ALIGN (size);
+				} else {
+					dev->resource[i].start = base_mem;
+					base_mem += 0x100000UL;
+				}
+				dev->resource[i].end =
+					dev->resource[i].start + size;
+			}
+			break;
+		}
+		for (i=0; i < 6; i++) {
+			if (dev->resource[i].start == 0)
+				continue;
+			start = dev->resource[i].start;
+			if (dev->resource[i].flags & IORESOURCE_IO)
+				start |= 1;
+			pci_write_config_dword (dev,
+				PCI_BASE_ADDRESS_0 + (i << 2), (u32) start);
+		}
+		pci_write_config_byte (dev, PCI_CACHE_LINE_SIZE, 0x20);
+		pci_write_config_byte (dev, PCI_LATENCY_TIMER, 0x30);
+		pci_read_config_word (dev, PCI_COMMAND, &cmd);
+		cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_SPECIAL | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY);
+		pci_write_config_word (dev, PCI_COMMAND, cmd);
+		pci_set_master (dev);
+	}
+        /*
+         * Fixup O2 PCI slot. Bad hack.
+         */
+/*        devtag = pci_make_tag(0, 0, 3, 0);
+
+        slot = macepci_conf_read(0, devtag, PCI_COMMAND_STATUS_REG);
+        slot |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE;
+        macepci_conf_write(0, devtag, PCI_COMMAND_STATUS_REG, slot);
+
+        slot = macepci_conf_read(0, devtag, PCI_MAPREG_START);
+        if (slot == 0xffffffe1)
+                macepci_conf_write(0, devtag, PCI_MAPREG_START, 0x00001000);
+
+        slot = macepci_conf_read(0, devtag, PCI_MAPREG_START + (2 << 2));
+        if ((slot & 0xffff0000) == 0) {
+                slot += 0x00010000;
+                macepci_conf_write(0, devtag, PCI_MAPREG_START + (2 << 2),
+                    0x00000000);
+        }
+ */
+#ifdef DEBUG_MACE_PCI
+	printk ("Triggering PCI bridge interrupt...\n");
+	mace_write_32 (MACEPCI_ERROR_FLAGS, MACEPCI_ERROR_INTERRUPT_TEST);
+
+	pci_for_each_dev (dev) {
+		printk ("Device: %d/%d/%d final bus resource map\n",
+			dev->bus->number, PCI_SLOT (dev->devfn),
+			PCI_FUNC (dev->devfn));
+		for (i=0; i < DEVICE_COUNT_RESOURCE; i++) {
+			if (dev->resource[i].start == 0)
+				continue;
+			printk ("%d: %016lx - %016lx (flags %04lx)\n",
+				i, dev->resource[i].start,
+				dev->resource[i].end, dev->resource[i].flags);
+		}
+	}
+#endif
+}
+
+/*
+ * Given a PCI slot number (a la PCI_SLOT(...)) and the interrupt pin of
+ * the device (1-4 => A-D), tell what irq to use.  Note that we don't
+ * in theory have slots 4 and 5, and we never normally use the shared
+ * irqs.  I suppose a device without a pin A will thank us for doing it
+ * right if there exists such a broken piece of crap.
+ */
+static int __init macepci_map_irq (struct pci_dev *dev, u8 slot, u8 pin)
+{
+	chkslot (dev);
+	if (pin == 0)
+		pin = 1;
+	switch (slot) {
+	case 1:
+		return MACEPCI_SCSI0_IRQ;
+	case 2:
+		return MACEPCI_SCSI1_IRQ;
+	case 3:
+		switch (pin) {
+		case 2:
+			return MACEPCI_SHARED0_IRQ;
+		case 3:
+			return MACEPCI_SHARED1_IRQ;
+		case 4:
+			return MACEPCI_SHARED2_IRQ;
+		case 1:
+		default:
+			return MACEPCI_SLOT0_IRQ;
+		}
+	case 4:
+		switch (pin) {
+		case 2:
+			return MACEPCI_SHARED2_IRQ;
+		case 3:
+			return MACEPCI_SHARED0_IRQ;
+		case 4:
+			return MACEPCI_SHARED1_IRQ;
+		case 1:
+		default:
+			return MACEPCI_SLOT1_IRQ;
+		}
+		return MACEPCI_SLOT1_IRQ;
+	case 5:
+		switch (pin) {
+		case 2:
+			return MACEPCI_SHARED1_IRQ;
+		case 3:
+			return MACEPCI_SHARED2_IRQ;
+		case 4:
+			return MACEPCI_SHARED0_IRQ;
+		case 1:
+		default:
+			return MACEPCI_SLOT2_IRQ;
+		}
+	default:
+		return 0;
+	}
+}
+
+/*
+ * It's not entirely clear what this does in a system with no bridges.
+ * In any case, bridges are not supported by Linux in O2.
+ */
+static u8 __init macepci_swizzle (struct pci_dev *dev, u8 *pinp)
+{
+	if (PCI_SLOT (dev->devfn) == 2)
+		*pinp = 2;
+	else
+		*pinp = 1;
+	return PCI_SLOT (dev->devfn);
+}
+
+/* All devices are enabled during initialization. */
+int pcibios_enable_device (struct pci_dev *dev)
+{
+	return PCIBIOS_SUCCESSFUL;
+}
+
+char * __init pcibios_setup (char *str)
+{
+	return str;
+}
+
+void __init pcibios_align_resource (void *data, struct resource *res,
+				    unsigned long size, unsigned long align)
+{
+}
+
+void __init pcibios_update_resource (struct pci_dev *dev, struct resource *root,
+				     struct resource *res, int resource)
+{
+}
+
+void __init pcibios_update_irq (struct pci_dev *dev, int irq)
+{
+	pci_write_config_byte (dev, PCI_INTERRUPT_LINE, irq);
+}
+
+void __init pcibios_fixup_bus (struct pci_bus *b)
+{
+	pci_fixup_irqs (macepci_swizzle, macepci_map_irq);
+}
+
+/* XXX anybody know what this is supposed to do? */
+void __init pcibios_fixup_pbus_ranges(struct pci_bus * bus,
+				      struct pbus_set_ranges_data * ranges)
+{
+	ranges->io_start -= bus->resource[0]->start;
+	ranges->io_end -= bus->resource[0]->start;
+	ranges->mem_start -= bus->resource[1]->start;
+	ranges->mem_end -= bus->resource[1]->start;
+}
+
+/*
+ * Handle errors from the bridge.  This includes master and target aborts,
+ * various command and address errors, and the interrupt test.  This gets
+ * registered on the bridge error irq.  It's conceivable that some of these
+ * conditions warrant a panic.  Anybody care to say which ones?
+ */
+void macepci_error (int irq, void *dev, struct pt_regs *regs) {
+	u32 flags, error_addr;
+	char space;
+
+	flags = mace_read_32 (MACEPCI_ERROR_FLAGS);
+	error_addr = mace_read_32 (MACEPCI_ERROR_ADDR);
+
+	if (flags & MACEPCI_ERROR_MEMORY_ADDR)
+		space = 'M';
+	else if (flags & MACEPCI_ERROR_CONFIG_ADDR)
+		space = 'C';
+	else space = 'X';
+
+	if (flags & MACEPCI_ERROR_MASTER_ABORT) {
+		printk ("MACEPCI: Master abort at 0x%08x (%c)\n", error_addr,
+			space);
+		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
+			       & ~MACEPCI_ERROR_MASTER_ABORT);
+	}
+	if (flags & MACEPCI_ERROR_TARGET_ABORT) {
+		printk ("MACEPCI: Target abort at 0x%08x (%c)\n", error_addr,
+			space);
+		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
+			       & ~MACEPCI_ERROR_TARGET_ABORT);
+	}
+	if (flags & MACEPCI_ERROR_DATA_PARITY_ERR) {
+		printk ("MACEPCI: Data parity error at 0x%08x (%c)\n",
+			error_addr, space);
+		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
+			       & ~MACEPCI_ERROR_DATA_PARITY_ERR);
+	}
+	if (flags & MACEPCI_ERROR_RETRY_ERR) {
+		printk ("MACEPCI: Retry error at 0x%08x (%c)\n", error_addr,
+			space);
+		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
+			       & ~MACEPCI_ERROR_RETRY_ERR);
+	}
+	if (flags & MACEPCI_ERROR_ILLEGAL_CMD) {
+		printk ("MACEPCI: Illegal command at 0x%08x (%c)\n",
+			error_addr, space);
+		mace_write_32 (MACEPCI_ERROR_FLAGS,
+			       flags & ~MACEPCI_ERROR_ILLEGAL_CMD);
+	}
+	if (flags & MACEPCI_ERROR_SYSTEM_ERR) {
+		printk ("MACEPCI: System error at 0x%08x (%c)\n",
+			error_addr, space);
+		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
+			       & ~MACEPCI_ERROR_SYSTEM_ERR);
+	}
+	if (flags & MACEPCI_ERROR_PARITY_ERR) {
+		printk ("MACEPCI: Parity error at 0x%08x (%c)\n", error_addr,
+			space);
+		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
+			       & ~MACEPCI_ERROR_PARITY_ERR);
+	}
+	if (flags & MACEPCI_ERROR_OVERRUN) {
+		printk ("MACEPCI: Overrun error at 0x%08x (%c)\n",
+			error_addr, space);
+		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
+			       & ~MACEPCI_ERROR_OVERRUN);
+	}
+	if (flags & MACEPCI_ERROR_SIG_TABORT) {
+		printk ("MACEPCI: Signaled target abort (clearing)\n");
+		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
+			       & ~MACEPCI_ERROR_SIG_TABORT);
+	}
+	if (flags & MACEPCI_ERROR_INTERRUPT_TEST) {
+		printk ("MACEPCI: Interrupt test triggered (clearing)\n");
+		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
+			       & ~MACEPCI_ERROR_INTERRUPT_TEST);
+	}
+}
+unsigned __init int pcibios_assign_all_busses(void)
+{
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip32/ip32-reset.c linux-2.4.20/arch/mips/sgi-ip32/ip32-reset.c
--- linux-2.4.19/arch/mips/sgi-ip32/ip32-reset.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip32/ip32-reset.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,34 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 Keith M Wesolowski
+ * Copyright (C) 2001 Paul Mundt
+ */
+#include <linux/init.h>
+
+#include <asm/reboot.h>
+#include <asm/sgialib.h>
+
+static void ip32_machine_restart(char *cmd)
+{
+	ArcReboot();
+}
+
+static inline void ip32_machine_halt(void)
+{
+	ArcEnterInteractiveMode();
+}
+
+static void ip32_machine_power_off(void)
+{
+	ip32_machine_halt();
+}
+
+void __init ip32_reboot_setup(void)
+{
+	_machine_restart = ip32_machine_restart;
+	_machine_halt = ip32_machine_halt;
+	_machine_power_off = ip32_machine_power_off;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip32/ip32-rtc.c linux-2.4.20/arch/mips/sgi-ip32/ip32-rtc.c
--- linux-2.4.19/arch/mips/sgi-ip32/ip32-rtc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip32/ip32-rtc.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,32 @@
+/*
+ * RTC routines for IP32 style attached Dallas chip.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000 Harald Koerfgen
+ */
+#include <linux/mc146818rtc.h>
+#include <asm/ip32/mace.h>
+
+static unsigned char ip32_rtc_read_data(unsigned long addr)
+{
+	return (unsigned char) mace_read_8 (MACEISA_RTC_BASE + (addr << 8));
+}
+
+static void ip32_rtc_write_data(unsigned char data, unsigned long addr)
+{
+	mace_write_8 (MACEISA_RTC_BASE + (addr << 8), data);
+}
+
+static int ip32_rtc_bcd_mode(void)
+{
+	return 0;
+}
+
+struct rtc_ops ip32_rtc_ops = {
+	&ip32_rtc_read_data,
+	&ip32_rtc_write_data,
+	&ip32_rtc_bcd_mode
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip32/ip32-setup.c linux-2.4.20/arch/mips/sgi-ip32/ip32-setup.c
--- linux-2.4.19/arch/mips/sgi-ip32/ip32-setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip32/ip32-setup.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,102 @@
+/*
+ * IP32 basic setup
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000 Harald Koerfgen
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/mc146818rtc.h>
+#include <linux/param.h>
+#include <linux/init.h>
+
+#include <asm/time.h>
+#include <asm/mipsregs.h>
+#include <asm/bootinfo.h>
+#include <asm/mmu_context.h>
+#include <asm/ip32/crime.h>
+#include <asm/ip32/mace.h>
+#include <asm/ip32/ip32_ints.h>
+#include <asm/sgialib.h>
+
+extern struct rtc_ops ip32_rtc_ops;
+extern u32 cc_interval;
+
+#ifdef CONFIG_SGI_O2MACE_ETH
+
+/*
+ * This is taken care of in here 'cause they say using Arc later on is
+ * problematic
+ */
+extern char o2meth_eaddr[8];
+static inline unsigned char str2hexnum(unsigned char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	return 0; /* foo */
+}
+
+static inline void str2eaddr(unsigned char *ea, unsigned char *str)
+{
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		unsigned char num;
+
+		if(*str == ':')
+			str++;
+		num = str2hexnum(*str++) << 4;
+		num |= (str2hexnum(*str++));
+		ea[i] = num;
+	}
+}
+#endif
+
+extern void ip32_time_init(void);
+
+void __init ip32_setup(void)
+{
+#ifdef CONFIG_SERIAL_CONSOLE
+	char *ctype;
+#endif
+	TLBMISS_HANDLER_SETUP ();
+
+	mips_io_port_base = UNCACHEDADDR(MACEPCI_HI_IO);;
+
+#ifdef CONFIG_SERIAL_CONSOLE
+	ctype = ArcGetEnvironmentVariable("console");
+	if (*ctype == 'd') {
+		if (ctype[1] == '2')
+			console_setup ("ttyS1");
+		else
+			console_setup ("ttyS0");
+	}
+#endif
+#ifdef CONFIG_SGI_O2MACE_ETH
+	{
+		char *mac=ArcGetEnvironmentVariable("eaddr");
+		str2eaddr(o2meth_eaddr, mac);
+	}
+#endif
+
+#ifdef CONFIG_VT
+	conswitchp = &dummy_con;
+#endif
+
+	rtc_ops = &ip32_rtc_ops;
+	board_time_init = ip32_time_init;
+
+	crime_init ();
+}
+
+int __init page_is_ram (unsigned long pagenr)
+{
+	/* XXX: to do? */
+	return 1;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sgi-ip32/ip32-timer.c linux-2.4.20/arch/mips/sgi-ip32/ip32-timer.c
--- linux-2.4.19/arch/mips/sgi-ip32/ip32-timer.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sgi-ip32/ip32-timer.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,238 @@
+/*
+ * IP32 timer calibration
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 Keith M Wesolowski
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+#include <linux/timex.h>
+
+#include <asm/mipsregs.h>
+#include <asm/param.h>
+#include <asm/ip32/crime.h>
+#include <asm/ip32/ip32_ints.h>
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
+#include <asm/mipsregs.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+extern volatile unsigned long wall_jiffies;
+extern rwlock_t xtime_lock;
+
+u32 cc_interval;
+
+/* Cycle counter value at the previous timer interrupt.. */
+static unsigned int timerhi, timerlo;
+
+/* An arbitrary time; this can be decreased if reliability looks good */
+#define WAIT_MS 10
+#define PER_MHZ (1000000 / 2 / HZ)
+/*
+ * Change this if you have some constant time drift
+ */
+#define USECS_PER_JIFFY (1000000/HZ)
+
+
+void __init ip32_timer_setup (struct irqaction *irq)
+{
+	u64 crime_time;
+	u32 cc_tick;
+
+	printk("Calibrating system timer... ");
+
+	crime_time = crime_read_64 (CRIME_TIME) & CRIME_TIME_MASK;
+	cc_tick = read_32bit_cp0_register (CP0_COUNT);
+
+	while ((crime_read_64 (CRIME_TIME) & CRIME_TIME_MASK) - crime_time
+		< WAIT_MS * 1000000 / CRIME_NS_PER_TICK)
+		;
+	cc_tick = read_32bit_cp0_register (CP0_COUNT) - cc_tick;
+	cc_interval = cc_tick / HZ * (1000 / WAIT_MS);
+	/* The round-off seems unnecessary; in testing, the error of the
+	 * above procedure is < 100 ticks, which means it gets filtered
+	 * out by the HZ adjustment.
+	 */
+	cc_interval = (cc_interval / PER_MHZ) * PER_MHZ;
+
+	printk("%d MHz CPU detected\n", (int) (cc_interval / PER_MHZ));
+
+	setup_irq (CLOCK_IRQ, irq);
+}
+
+struct irqaction irq0  = { NULL, SA_INTERRUPT, 0,
+			   "timer", NULL, NULL};
+
+void cc_timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	u32 count;
+
+	/*
+	 * The cycle counter is only 32 bit which is good for about
+	 * a minute at current count rates of upto 150MHz or so.
+	 */
+	count = read_32bit_cp0_register(CP0_COUNT);
+	timerhi += (count < timerlo);	/* Wrap around */
+	timerlo = count;
+
+	write_32bit_cp0_register (CP0_COMPARE,
+				  (u32) (count + cc_interval));
+	kstat.irqs[0][irq]++;
+	do_timer (regs);
+
+	if (!jiffies)
+	{
+		/*
+		 * If jiffies has overflowed in this timer_interrupt we must
+		 * update the timer[hi]/[lo] to make do_fast_gettimeoffset()
+		 * quotient calc still valid. -arca
+		 */
+		timerhi = timerlo = 0;
+	}
+}
+
+/*
+ * On MIPS only R4000 and better have a cycle counter.
+ *
+ * FIXME: Does playing with the RP bit in c0_status interfere with this code?
+ */
+static unsigned long do_gettimeoffset(void)
+{
+	u32 count;
+	unsigned long res, tmp;
+
+	/* Last jiffy when do_fast_gettimeoffset() was called. */
+	static unsigned long last_jiffies;
+	u32 quotient;
+
+	/*
+	 * Cached "1/(clocks per usec)*2^32" value.
+	 * It has to be recalculated once each jiffy.
+	 */
+	static u32 cached_quotient;
+
+	tmp = jiffies;
+
+	quotient = cached_quotient;
+
+	if (tmp && last_jiffies != tmp) {
+		last_jiffies = tmp;
+		__asm__(".set\tnoreorder\n\t"
+			".set\tnoat\n\t"
+			".set\tmips3\n\t"
+			"lwu\t%0,%2\n\t"
+			"dsll32\t$1,%1,0\n\t"
+			"or\t$1,$1,%0\n\t"
+			"ddivu\t$0,$1,%3\n\t"
+			"mflo\t$1\n\t"
+			"dsll32\t%0,%4,0\n\t"
+			"nop\n\t"
+			"ddivu\t$0,%0,$1\n\t"
+			"mflo\t%0\n\t"
+			".set\tmips0\n\t"
+			".set\tat\n\t"
+			".set\treorder"
+			:"=&r" (quotient)
+			:"r" (timerhi),
+			 "m" (timerlo),
+			 "r" (tmp),
+			 "r" (USECS_PER_JIFFY)
+			:"$1");
+		cached_quotient = quotient;
+	}
+
+	/* Get last timer tick in absolute kernel time */
+	count = read_32bit_cp0_register(CP0_COUNT);
+
+	/* .. relative to previous jiffy (32 bits is enough) */
+	count -= timerlo;
+
+	__asm__("multu\t%1,%2\n\t"
+		"mfhi\t%0"
+		:"=r" (res)
+		:"r" (count),
+		 "r" (quotient));
+
+	/*
+ 	 * Due to possible jiffies inconsistencies, we need to check
+	 * the result so that we'll get a timer that is monotonic.
+	 */
+	if (res >= USECS_PER_JIFFY)
+		res = USECS_PER_JIFFY-1;
+
+	return res;
+}
+
+void __init ip32_time_init(void)
+{
+	unsigned int epoch = 0, year, mon, day, hour, min, sec;
+	int i;
+
+	/* The Linux interpretation of the CMOS clock register contents:
+	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+	 * RTC registers show the second which has precisely just started.
+	 * Let's hope other operating systems interpret the RTC the same way.
+	 */
+	/* read RTC exactly on falling edge of update flag */
+	for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
+		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+			break;
+	for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms */
+		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+			break;
+	do { /* Isn't this overkill ? UIP above should guarantee consistency */
+		sec = CMOS_READ(RTC_SECONDS);
+		min = CMOS_READ(RTC_MINUTES);
+		hour = CMOS_READ(RTC_HOURS);
+		day = CMOS_READ(RTC_DAY_OF_MONTH);
+		mon = CMOS_READ(RTC_MONTH);
+		year = CMOS_READ(RTC_YEAR);
+	} while (sec != CMOS_READ(RTC_SECONDS));
+	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BCD_TO_BIN(sec);
+		BCD_TO_BIN(min);
+		BCD_TO_BIN(hour);
+		BCD_TO_BIN(day);
+		BCD_TO_BIN(mon);
+		BCD_TO_BIN(year);
+	}
+
+	/* Attempt to guess the epoch.  This is the same heuristic as in
+	 * rtc.c so no stupid things will happen to timekeeping.  Who knows,
+	 * maybe Ultrix also uses 1952 as epoch ...
+	 */
+	if (year > 10 && year < 44)
+		epoch = 1980;
+	else if (year < 96)
+		epoch = 1952;
+	year += epoch;
+
+	write_lock_irq (&xtime_lock);
+	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
+	xtime.tv_usec = 0;
+	write_unlock_irq (&xtime_lock);
+
+	write_32bit_cp0_register(CP0_COUNT, 0);
+	irq0.handler = cc_timer_interrupt;
+
+	ip32_timer_setup (&irq0);
+
+#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
+	/* Set ourselves up for future interrupts */
+        write_32bit_cp0_register(CP0_COMPARE,
+				 read_32bit_cp0_register(CP0_COUNT)
+				 + cc_interval);
+        change_cp0_status(ST0_IM, ALLINTS);
+	sti ();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/cfe/Makefile linux-2.4.20/arch/mips/sibyte/cfe/Makefile
--- linux-2.4.19/arch/mips/sibyte/cfe/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/cfe/Makefile	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,8 @@
+USE_STANDARD_AS_RULE := true
+
+L_TARGET = cfe.a
+
+obj-y			= cfe_api.o setup.o
+obj-$(CONFIG_SMP)	+= smp.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/cfe/cfe_api.c linux-2.4.20/arch/mips/sibyte/cfe/cfe_api.c
--- linux-2.4.19/arch/mips/sibyte/cfe/cfe_api.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/cfe/cfe_api.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) 2000, 2001 Broadcom Corporation
+ *
+ * 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.
+ */
+
+/*  *********************************************************************
+    *  Broadcom Common Firmware Environment (CFE)
+    *
+    *  Device Function stubs			File: cfe_api.c
+    *
+    *  This module contains device function stubs (small routines to
+    *  call the standard "iocb" interface entry point to CFE).
+    *  There should be one routine here per iocb function call.
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    ********************************************************************* */
+
+
+#include "cfe_xiocb.h"
+#include "cfe_api.h"
+
+static long cfe_console_handle = -1;
+static int (*cfe_dispfunc)(long handle,cfe_xiocb_t *xiocb) = 0;
+static cfe_xuint_t cfe_handle = 0;
+
+/*
+ * This macro makes a "signed 64-bit pointer" - basically extending a regular
+ * pointer to its 64-bit compatibility space equivalent.
+ */
+#define BIGPTR(x) (long long) (long) (x)
+
+typedef unsigned long intptr_t;
+
+int cfe_init(cfe_xuint_t handle)
+{
+	if ((*((unsigned int *) (int) CFE_APISEAL) == CFE_EPTSEAL) ||
+	    (*((unsigned int *) (int) CFE_APISEAL_RE) == CFE_EPTSEAL) ||
+	    (*((unsigned int *) (int) CFE_APISEAL_OLD) == CFE_EPTSEAL)) {
+		cfe_dispfunc = (cfe_xptr_t) (int) CFE_APIENTRY;
+		if (handle) cfe_handle = handle;
+		return 0;
+	} else {
+		return -1;
+	}
+}
+
+int cfe_iocb_dispatch(cfe_xiocb_t *xiocb);
+int cfe_iocb_dispatch(cfe_xiocb_t *xiocb)
+{
+	if (!cfe_dispfunc) return -1;
+	return (*cfe_dispfunc)(cfe_handle,xiocb);
+}
+
+static int cfe_strlen(char *name)
+{
+	int count = 0;
+
+	while (*name) {
+		count++;
+		name++;
+	}
+
+	return count;
+}
+
+int cfe_open(char *name)
+{
+	cfe_xiocb_t xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_DEV_OPEN;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(xiocb_buffer_t);
+	xiocb.plist.xiocb_buffer.buf_offset = 0;
+	xiocb.plist.xiocb_buffer.buf_ptr = BIGPTR(name);
+	xiocb.plist.xiocb_buffer.buf_length = cfe_strlen(name);
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return (xiocb.xiocb_status < 0) ? xiocb.xiocb_status : xiocb.xiocb_handle;
+}
+
+int cfe_close(int handle)
+{
+	cfe_xiocb_t xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_DEV_CLOSE;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = handle;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = 0;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return (xiocb.xiocb_status);
+
+}
+
+int cfe_readblk(int handle,cfe_xint_t offset,unsigned char *buffer,int length)
+{
+	cfe_xiocb_t xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_DEV_READ;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = handle;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(xiocb_buffer_t);
+	xiocb.plist.xiocb_buffer.buf_offset = offset;
+	xiocb.plist.xiocb_buffer.buf_ptr = BIGPTR(buffer);
+	xiocb.plist.xiocb_buffer.buf_length = length;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return (xiocb.xiocb_status < 0) ? xiocb.xiocb_status : xiocb.plist.xiocb_buffer.buf_retlen;
+}
+
+int cfe_read(int handle,unsigned char *buffer,int length)
+{
+	return cfe_readblk(handle,0,buffer,length);
+}
+
+
+int cfe_writeblk(int handle,cfe_xint_t offset,unsigned char *buffer,int length)
+{
+	cfe_xiocb_t xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_DEV_WRITE;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = handle;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(xiocb_buffer_t);
+	xiocb.plist.xiocb_buffer.buf_offset = offset;
+	xiocb.plist.xiocb_buffer.buf_ptr = BIGPTR(buffer);
+	xiocb.plist.xiocb_buffer.buf_length = length;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return (xiocb.xiocb_status < 0) ? xiocb.xiocb_status : xiocb.plist.xiocb_buffer.buf_retlen;
+}
+
+int cfe_write(int handle,unsigned char *buffer,int length)
+{
+	return cfe_writeblk(handle,0,buffer,length);
+}
+
+
+int cfe_ioctl(int handle,unsigned int ioctlnum,unsigned char *buffer,int length,int *retlen)
+{
+	cfe_xiocb_t xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_DEV_IOCTL;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = handle;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(xiocb_buffer_t);
+	xiocb.plist.xiocb_buffer.buf_ioctlcmd = (cfe_xint_t) ioctlnum;
+	xiocb.plist.xiocb_buffer.buf_ptr = BIGPTR(buffer);
+	xiocb.plist.xiocb_buffer.buf_length = length;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	if (retlen) *retlen = xiocb.plist.xiocb_buffer.buf_retlen;
+	return xiocb.xiocb_status;
+}
+
+int cfe_inpstat(int handle)
+{
+	cfe_xiocb_t xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_DEV_INPSTAT;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = handle;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(xiocb_inpstat_t);
+	xiocb.plist.xiocb_inpstat.inp_status = 0;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	if (xiocb.xiocb_status < 0) return xiocb.xiocb_status;
+
+	return xiocb.plist.xiocb_inpstat.inp_status;
+
+}
+
+long long cfe_getticks(void)
+{
+	cfe_xiocb_t xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_FW_GETTIME;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(xiocb_time_t);
+	xiocb.plist.xiocb_time.ticks = 0;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return xiocb.plist.xiocb_time.ticks;
+
+}
+
+int cfe_getenv(char *name,char *dest,int destlen)
+{
+	cfe_xiocb_t xiocb;
+
+	*dest = 0;
+
+	xiocb.xiocb_fcode = CFE_CMD_ENV_GET;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(xiocb_envbuf_t);
+	xiocb.plist.xiocb_envbuf.enum_idx = 0;
+	xiocb.plist.xiocb_envbuf.name_ptr = BIGPTR(name);
+	xiocb.plist.xiocb_envbuf.name_length = cfe_strlen(name);
+	xiocb.plist.xiocb_envbuf.val_ptr = BIGPTR(dest);
+	xiocb.plist.xiocb_envbuf.val_length = destlen;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return xiocb.xiocb_status;
+}
+
+int cfe_setenv(char *name,char *val)
+{
+	cfe_xiocb_t xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_ENV_SET;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(xiocb_envbuf_t);
+	xiocb.plist.xiocb_envbuf.enum_idx = 0;
+	xiocb.plist.xiocb_envbuf.name_ptr = BIGPTR(name);
+	xiocb.plist.xiocb_envbuf.name_length = cfe_strlen(name);
+	xiocb.plist.xiocb_envbuf.val_ptr = BIGPTR(val);
+	xiocb.plist.xiocb_envbuf.val_length = cfe_strlen(val);
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return xiocb.xiocb_status;
+}
+
+int cfe_enummem(long idx, unsigned long long *addr, unsigned long long *size, long *type)
+{
+	cfe_xiocb_t xiocb;
+	xiocb.xiocb_fcode = CFE_CMD_FW_MEMENUM;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(xiocb_meminfo_t);
+	xiocb.plist.xiocb_meminfo.mi_idx = idx;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	(*addr) = xiocb.plist.xiocb_meminfo.mi_addr;
+	(*size) = xiocb.plist.xiocb_meminfo.mi_size;
+	(*type) = xiocb.plist.xiocb_meminfo.mi_type;
+
+	return xiocb.xiocb_status;
+}
+
+
+int cfe_enumenv(int idx,char *name,int namelen,char *val,int vallen)
+{
+	cfe_xiocb_t xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_ENV_SET;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(xiocb_envbuf_t);
+	xiocb.plist.xiocb_envbuf.enum_idx = idx;
+	xiocb.plist.xiocb_envbuf.name_ptr = BIGPTR(name);
+	xiocb.plist.xiocb_envbuf.name_length = namelen;
+	xiocb.plist.xiocb_envbuf.val_ptr = BIGPTR(val);
+	xiocb.plist.xiocb_envbuf.val_length = vallen;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return xiocb.xiocb_status;
+}
+
+int cfe_exit(int warm, int status)
+{
+	cfe_xiocb_t xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_FW_RESTART;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = warm ? CFE_FLG_WARMSTART : 0;
+	xiocb.xiocb_psize = sizeof(xiocb_exitstat_t);
+	xiocb.plist.xiocb_exitstat.status = (cfe_xint_t) status;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return (xiocb.xiocb_status);
+}
+
+int cfe_flushcache(int flg)
+{
+	cfe_xiocb_t xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_FW_FLUSHCACHE;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = flg;
+	xiocb.xiocb_psize = 0;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return xiocb.xiocb_status;
+}
+
+int cfe_getstdhandle(int flg)
+{
+	cfe_xiocb_t xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_DEV_GETHANDLE;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = flg;
+	xiocb.xiocb_psize = 0;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return (xiocb.xiocb_status < 0) ? xiocb.xiocb_status : xiocb.xiocb_handle;
+
+}
+
+int cfe_start_cpu(int cpu, void (*fn)(void), long sp, long gp, long a1)
+{
+	cfe_xiocb_t xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_FW_CPUCTL;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags  = 0;
+	xiocb.xiocb_psize = sizeof(xiocb_cpuctl_t);
+	xiocb.plist.xiocb_cpuctl.cpu_number = cpu;
+	xiocb.plist.xiocb_cpuctl.cpu_command = CFE_CPU_CMD_START;
+	xiocb.plist.xiocb_cpuctl.gp_val = gp;
+	xiocb.plist.xiocb_cpuctl.sp_val = sp;
+	xiocb.plist.xiocb_cpuctl.a1_val = a1;
+	xiocb.plist.xiocb_cpuctl.start_addr = (long)fn;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return xiocb.xiocb_status;
+}
+
+
+int cfe_stop_cpu(int cpu)
+{
+	cfe_xiocb_t xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_FW_CPUCTL;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags  = 0;
+	xiocb.xiocb_psize = sizeof(xiocb_cpuctl_t);
+	xiocb.plist.xiocb_cpuctl.cpu_number = cpu;
+	xiocb.plist.xiocb_cpuctl.cpu_command = CFE_CPU_CMD_STOP;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return xiocb.xiocb_status;
+}
+
+void cfe_open_console()
+{
+	cfe_console_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
+}
+
+void cfe_console_print(const char *str, int len)
+{
+	int res;
+
+	if (cfe_console_handle != -1) {
+		do {
+			res = cfe_writeblk(cfe_console_handle, 0, str, len);
+			if (res < 0)
+				break;
+			str += res;
+			len -= res;
+		} while (len);
+	}
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/cfe/cfe_api.h linux-2.4.20/arch/mips/sibyte/cfe/cfe_api.h
--- linux-2.4.19/arch/mips/sibyte/cfe/cfe_api.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/cfe/cfe_api.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2000, 2001 Broadcom Corporation
+ *
+ * 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.
+ */
+
+/*  *********************************************************************
+    *  Broadcom Common Firmware Environment (CFE)
+    *
+    *  Device function prototypes		File: cfe_api.h
+    *
+    *  This module contains prototypes for cfe_devfuncs.c, a set
+    *  of wrapper routines to the IOCB interface.  This file,
+    *  along with cfe_api.c, can be incorporated into programs
+    *  that need to call CFE.
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    ********************************************************************* */
+
+#include <linux/config.h>
+
+#define CFE_EPTSEAL 0x43464531
+#ifdef CONFIG_MIPS_UNCACHED
+#define CFE_APIENTRY    0xBFC00500
+#define CFE_APISEAL     0xBFC004E0
+#define CFE_APISEAL_RE  0xBFC004E8
+#define CFE_APISEAL_OLD 0xBFC00508
+#else
+#define CFE_APIENTRY    0x9FC00500
+#define CFE_APISEAL     0x9FC004E0
+#define CFE_APISEAL_RE  0x9FC004E8
+#define CFE_APISEAL_OLD 0x9FC00508
+#endif
+
+#ifndef __ASSEMBLER__
+int cfe_init(cfe_xuint_t handle);
+int cfe_open(char *name);
+int cfe_close(int handle);
+int cfe_readblk(int handle,cfe_xint_t offset,unsigned char *buffer,int length);
+int cfe_read(int handle,unsigned char *buffer,int length);
+int cfe_writeblk(int handle,cfe_xint_t offset,unsigned char *buffer,int length);
+int cfe_write(int handle,unsigned char *buffer,int length);
+int cfe_ioctl(int handle,unsigned int ioctlnum,unsigned char *buffer,int length,int *retlen);
+int cfe_inpstat(int handle);
+int cfe_enumenv(int idx,char *name,int namelen,char *val,int vallen);
+int cfe_enummem(long idx, unsigned long long *addr, unsigned long long *size, long *type);
+int cfe_setenv(char *name,char *val);
+int cfe_getenv(char *name,char *dest,int destlen);
+long long cfe_getticks(void);
+int cfe_exit(int warm, int status);
+int cfe_flushcache(int flg);
+int cfe_getstdhandle(int flg);
+int cfe_start_cpu(int cpu, void (*fn)(void), long sp, long gp, long a1);
+int cfe_stop_cpu(int cpu);
+
+void cfe_open_console(void);
+void cfe_console_print(const char *, int);
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/cfe/cfe_error.h linux-2.4.20/arch/mips/sibyte/cfe/cfe_error.h
--- linux-2.4.19/arch/mips/sibyte/cfe/cfe_error.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/cfe/cfe_error.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2000, 2001 Broadcom Corporation
+ *
+ * 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.
+ */
+
+/*  *********************************************************************
+    *  Broadcom Common Firmware Environment (CFE)
+    *
+    *  Error codes				File: cfe_error.h
+    *
+    *  CFE's global error code list is here.
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    ********************************************************************* */
+
+
+
+
+#define CFE_OK			 0
+#define CFE_ERR                 -1	/* generic error */
+#define CFE_ERR_INV_COMMAND	-2
+#define CFE_ERR_EOF		-3
+#define CFE_ERR_IOERR		-4
+#define CFE_ERR_NOMEM		-5
+#define CFE_ERR_DEVNOTFOUND	-6
+#define CFE_ERR_DEVOPEN		-7
+#define CFE_ERR_INV_PARAM	-8
+#define CFE_ERR_ENVNOTFOUND	-9
+#define CFE_ERR_ENVREADONLY	-10
+
+#define CFE_ERR_NOTELF		-11
+#define CFE_ERR_NOT32BIT 	-12
+#define CFE_ERR_WRONGENDIAN 	-13
+#define CFE_ERR_BADELFVERS 	-14
+#define CFE_ERR_NOTMIPS 	-15
+#define CFE_ERR_BADELFFMT 	-16
+#define CFE_ERR_BADADDR 	-17
+
+#define CFE_ERR_FILENOTFOUND	-18
+#define CFE_ERR_UNSUPPORTED	-19
+
+#define CFE_ERR_HOSTUNKNOWN	-20
+
+#define CFE_ERR_TIMEOUT		-21
+
+#define CFE_ERR_PROTOCOLERR	-22
+
+#define CFE_ERR_NETDOWN		-23
+#define CFE_ERR_NONAMESERVER	-24
+
+#define CFE_ERR_NOHANDLES	-25
+#define CFE_ERR_ALREADYBOUND	-26
+
+#define CFE_ERR_CANNOTSET	-27
+#define CFE_ERR_NOMORE		-28
+#define CFE_ERR_BADFILESYS	-29
+#define CFE_ERR_FSNOTAVAIL	-30
+
+#define CFE_ERR_INVBOOTBLOCK	-31
+#define CFE_ERR_WRONGDEVTYPE	-32
+#define CFE_ERR_BBCHECKSUM	-33
+#define CFE_ERR_BOOTPROGCHKSUM	-34
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/cfe/cfe_xiocb.h linux-2.4.20/arch/mips/sibyte/cfe/cfe_xiocb.h
--- linux-2.4.19/arch/mips/sibyte/cfe/cfe_xiocb.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/cfe/cfe_xiocb.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2000, 2001 Broadcom Corporation
+ *
+ * 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.
+ */
+
+/*  *********************************************************************
+    *  Broadcom Common Firmware Environment (CFE)
+    *
+    *  IOCB definitions				File: cfe_iocb.h
+    *
+    *  This module describes CFE's IOCB structure, the main
+    *  data structure used to communicate API requests with CFE.
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    ********************************************************************* */
+
+/*  *********************************************************************
+    *  Constants
+    ********************************************************************* */
+
+#define CFE_CMD_FW_GETINFO	0
+#define CFE_CMD_FW_RESTART	1
+#define CFE_CMD_FW_BOOT		2
+#define CFE_CMD_FW_CPUCTL	3
+#define CFE_CMD_FW_GETTIME      4
+#define CFE_CMD_FW_MEMENUM	5
+#define CFE_CMD_FW_FLUSHCACHE	6
+
+#define CFE_CMD_DEV_GETHANDLE	9
+#define CFE_CMD_DEV_ENUM	10
+#define CFE_CMD_DEV_OPEN	11
+#define CFE_CMD_DEV_INPSTAT	12
+#define CFE_CMD_DEV_READ	13
+#define CFE_CMD_DEV_WRITE	14
+#define CFE_CMD_DEV_IOCTL	15
+#define CFE_CMD_DEV_CLOSE	16
+#define CFE_CMD_DEV_GETINFO	17
+
+#define CFE_CMD_ENV_ENUM	20
+#define CFE_CMD_ENV_GET		22
+#define CFE_CMD_ENV_SET		23
+#define CFE_CMD_ENV_DEL		24
+
+#define CFE_CMD_MAX		32
+
+#define CFE_MI_RESERVED	0		/* memory is reserved, do not use */
+#define CFE_MI_AVAILABLE 1		/* memory is available */
+
+#define CFE_FLG_WARMSTART 0x00000001
+
+#define CFE_FLG_ENV_PERMANENT 0x00000001
+
+#define CFE_CPU_CMD_START 1
+#define CFE_CPU_CMD_STOP 0
+
+#define CFE_STDHANDLE_CONSOLE	0
+
+#define CFE_DEV_NETWORK 	1
+#define CFE_DEV_DISK		2
+#define CFE_DEV_FLASH		3
+#define CFE_DEV_SERIAL		4
+#define CFE_DEV_CPU		5
+#define CFE_DEV_NVRAM		6
+#define CFE_DEV_OTHER		7
+#define CFE_DEV_MASK		0x0F
+
+#define CFE_CACHE_FLUSH_D	1
+#define CFE_CACHE_INVAL_I	2
+#define CFE_CACHE_INVAL_D	4
+#define CFE_CACHE_INVAL_L2	8
+
+/*  *********************************************************************
+    *  Structures
+    ********************************************************************* */
+
+typedef unsigned long long cfe_xuint_t;
+typedef long long cfe_xint_t;
+typedef long long cfe_xptr_t;
+
+typedef struct xiocb_buffer_s {
+    cfe_xuint_t   buf_offset;		/* offset on device (bytes) */
+    cfe_xptr_t 	  buf_ptr;		/* pointer to a buffer */
+    cfe_xuint_t   buf_length;		/* length of this buffer */
+    cfe_xuint_t   buf_retlen;		/* returned length (for read ops) */
+    cfe_xuint_t   buf_ioctlcmd;		/* IOCTL command (used only for IOCTLs) */
+} xiocb_buffer_t;
+
+#define buf_devflags buf_ioctlcmd	/* returned device info flags */
+
+typedef struct xiocb_inpstat_s {
+    cfe_xuint_t inp_status;		/* 1 means input available */
+} xiocb_inpstat_t;
+
+typedef struct xiocb_envbuf_s {
+    cfe_xint_t enum_idx;		/* 0-based enumeration index */
+    cfe_xptr_t name_ptr;		/* name string buffer */
+    cfe_xint_t name_length;		/* size of name buffer */
+    cfe_xptr_t val_ptr;			/* value string buffer */
+    cfe_xint_t val_length;		/* size of value string buffer */
+} xiocb_envbuf_t;
+
+typedef struct xiocb_cpuctl_s {
+    cfe_xuint_t  cpu_number;		/* cpu number to control */
+    cfe_xuint_t  cpu_command;		/* command to issue to CPU */
+    cfe_xuint_t  start_addr;		/* CPU start address */
+    cfe_xuint_t  gp_val;		/* starting GP value */
+    cfe_xuint_t  sp_val;		/* starting SP value */
+    cfe_xuint_t  a1_val;		/* starting A1 value */
+} xiocb_cpuctl_t;
+
+typedef struct xiocb_time_s {
+    cfe_xint_t ticks;			/* current time in ticks */
+} xiocb_time_t;
+
+typedef struct xiocb_exitstat_s {
+    cfe_xint_t status;
+} xiocb_exitstat_t;
+
+typedef struct xiocb_meminfo_s {
+    cfe_xint_t  mi_idx;			/* 0-based enumeration index */
+    cfe_xint_t  mi_type;		/* type of memory block */
+    cfe_xuint_t mi_addr;		/* physical start address */
+    cfe_xuint_t mi_size;		/* block size */
+} xiocb_meminfo_t;
+
+#define CFE_FWI_64BIT		0x00000001
+#define CFE_FWI_32BIT		0x00000002
+#define CFE_FWI_RELOC		0x00000004
+#define CFE_FWI_UNCACHED	0x00000008
+#define CFE_FWI_MULTICPU	0x00000010
+#define CFE_FWI_FUNCSIM		0x00000020
+#define CFE_FWI_RTLSIM		0x00000040
+
+typedef struct xiocb_fwinfo_s {
+    cfe_xint_t fwi_version;		/* major, minor, eco version */
+    cfe_xint_t fwi_totalmem;		/* total installed mem */
+    cfe_xint_t fwi_flags;		/* various flags */
+    cfe_xint_t fwi_boardid;		/* board ID */
+    cfe_xint_t fwi_bootarea_va;		/* VA of boot area */
+    cfe_xint_t fwi_bootarea_pa;		/* PA of boot area */
+    cfe_xint_t fwi_bootarea_size;	/* size of boot area */
+    cfe_xint_t fwi_reserved1;
+    cfe_xint_t fwi_reserved2;
+    cfe_xint_t fwi_reserved3;
+} xiocb_fwinfo_t,cfe_fwinfo_t;
+
+typedef struct cfe_xiocb_s {
+    cfe_xuint_t xiocb_fcode;		/* IOCB function code */
+    cfe_xint_t  xiocb_status;		/* return status */
+    cfe_xint_t  xiocb_handle;		/* file/device handle */
+    cfe_xuint_t xiocb_flags;		/* flags for this IOCB */
+    cfe_xuint_t xiocb_psize;		/* size of parameter list */
+    union {
+	xiocb_buffer_t  xiocb_buffer;	/* buffer parameters */
+	xiocb_inpstat_t xiocb_inpstat;	/* input status parameters */
+	xiocb_envbuf_t  xiocb_envbuf;	/* environment function parameters */
+	xiocb_cpuctl_t  xiocb_cpuctl;	/* CPU control parameters */
+	xiocb_time_t    xiocb_time;	/* timer parameters */
+	xiocb_meminfo_t xiocb_meminfo;	/* memory arena info parameters */
+	xiocb_fwinfo_t  xiocb_fwinfo;	/* firmware information */
+	xiocb_exitstat_t xiocb_exitstat; /* Exit status */
+    } plist;
+} cfe_xiocb_t;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/cfe/setup.c linux-2.4.20/arch/mips/sibyte/cfe/setup.c
--- linux-2.4.19/arch/mips/sibyte/cfe/setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/cfe/setup.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2000, 2001 Broadcom Corporation
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/blk.h>
+#include <linux/bootmem.h>
+#include <linux/smp.h>
+#include <linux/console.h>
+
+#include <asm/bootinfo.h>
+#include <asm/reboot.h>
+#include <asm/sibyte/board.h>
+
+#include "cfe_xiocb.h"
+#include "cfe_api.h"
+#include "cfe_error.h"
+
+/* Max ram addressable in 32-bit segments */
+#ifdef CONFIG_MIPS64
+#define MAX_RAM_SIZE (~0ULL)
+#else
+#ifdef CONFIG_HIGHMEM
+#ifdef CONFIG_64BIT_PHYS_ADDR
+#define MAX_RAM_SIZE (~0ULL)
+#else
+#define MAX_RAM_SIZE (0xffffffffULL)
+#endif
+#else
+#define MAX_RAM_SIZE (0x1fffffffULL)
+#endif
+#endif
+
+#define SB1250_DUART_MINOR_BASE		192 /* XXXKW put this somewhere sane */
+#define SB1250_PROMICE_MINOR_BASE	191 /* XXXKW put this somewhere sane */
+kdev_t cfe_consdev;
+
+#define SIBYTE_MAX_MEM_REGIONS 8
+phys_t board_mem_region_addrs[SIBYTE_MAX_MEM_REGIONS];
+phys_t board_mem_region_sizes[SIBYTE_MAX_MEM_REGIONS];
+unsigned int board_mem_region_count;
+
+/* This is the kernel command line.  Actually, it's
+   copied, eventually, to command_line, and looks to be
+   quite redundant.  But not something to fix just now */
+extern char arcs_cmdline[];
+
+#ifdef CONFIG_EMBEDDED_RAMDISK
+/* These are symbols defined by the ramdisk linker script */
+extern unsigned char __rd_start;
+extern unsigned char __rd_end;
+#endif
+
+#ifdef CONFIG_SMP
+static int reboot_smp = 0;
+#endif
+
+static void cfe_linux_exit(void)
+{
+#ifdef CONFIG_SMP
+	if (smp_processor_id()) {
+		if (reboot_smp) {
+			/* Don't repeat the process from another CPU */
+			for (;;);
+		} else {
+			/* Get CPU 0 to do the cfe_exit */
+			reboot_smp = 1;
+			smp_call_function((void *)_machine_restart, NULL, 1, 0);
+			for (;;);
+		}
+	}
+#endif
+	printk("passing control back to CFE\n");
+	cfe_exit(1, 0);
+	printk("cfe_exit returned??\n");
+	while(1);
+}
+
+static __init void prom_meminit(void)
+{
+	u64 addr, size; /* regardless of 64BIT_PHYS_ADDR */
+	long type;
+	unsigned int idx;
+	int rd_flag;
+#ifdef CONFIG_BLK_DEV_INITRD
+	unsigned long initrd_pstart;
+	unsigned long initrd_pend;
+
+#ifdef CONFIG_EMBEDDED_RAMDISK
+	/* If we're using an embedded ramdisk, then __rd_start and __rd_end
+	   are defined by the linker to be on either side of the ramdisk
+	   area.  Otherwise, initrd_start should be defined by kernel command
+	   line arguments */
+	if (initrd_start == 0) {
+		initrd_start = (unsigned long)&__rd_start;
+		initrd_end = (unsigned long)&__rd_end;
+	}
+#endif
+
+	initrd_pstart = __pa(initrd_start);
+	initrd_pend = __pa(initrd_end);
+	if (initrd_start &&
+	    ((initrd_pstart > MAX_RAM_SIZE)
+	     || (initrd_pend > MAX_RAM_SIZE))) {
+		panic("initrd out of addressable memory");
+	}
+
+#endif /* INITRD */
+
+	for (idx = 0; cfe_enummem(idx, &addr, &size, &type) != CFE_ERR_NOMORE;
+	     idx++) {
+		rd_flag = 0;
+		if (type == CFE_MI_AVAILABLE) {
+			/*
+			 * See if this block contains (any portion of) the
+			 * ramdisk
+			 */
+#ifdef CONFIG_BLK_DEV_INITRD
+			if (initrd_start) {
+				if ((initrd_pstart > addr) &&
+				    (initrd_pstart < (addr + size))) {
+					add_memory_region(addr,
+					                  initrd_pstart - addr,
+					                  BOOT_MEM_RAM);
+					rd_flag = 1;
+				}
+				if ((initrd_pend > addr) &&
+				    (initrd_pend < (addr + size))) {
+					add_memory_region(initrd_pend,
+						(addr + size) - initrd_pend,
+						 BOOT_MEM_RAM);
+					rd_flag = 1;
+				}
+			}
+#endif
+			if (!rd_flag) {
+				if (addr > MAX_RAM_SIZE)
+					continue;
+				if (addr+size > MAX_RAM_SIZE)
+					size = MAX_RAM_SIZE - (addr+size) + 1;
+				/*
+				 * memcpy/__copy_user prefetch, which
+				 * will cause a bus error for
+				 * KSEG/KUSEG addrs not backed by RAM.
+				 * Hence, reserve some padding for the
+				 * prefetch distance.
+				 */
+				if (size > 512)
+					size -= 512;
+				add_memory_region(addr, size, BOOT_MEM_RAM);
+			}
+			board_mem_region_addrs[board_mem_region_count] = addr;
+			board_mem_region_sizes[board_mem_region_count] = size;
+			board_mem_region_count++;
+			if (board_mem_region_count ==
+			    SIBYTE_MAX_MEM_REGIONS) {
+				/*
+				 * Too many regions.  Need to configure more
+				 */
+				while(1);
+			}
+		}
+	}
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start) {
+		add_memory_region(initrd_pstart, initrd_pend - initrd_pstart,
+				  BOOT_MEM_RESERVED);
+	}
+#endif
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+static int __init initrd_setup(char *str)
+{
+	/*
+	 *Initrd location comes in the form "<hex size of ramdisk in bytes>@<location in memory>"
+	 *  e.g. initrd=3abfd@80010000.  This is set up by the loader.
+	 */
+	char *tmp, *endptr;
+	unsigned long initrd_size;
+	for (tmp = str; *tmp != '@'; tmp++) {
+		if (!*tmp) {
+			goto fail;
+		}
+	}
+	*tmp = 0;
+	tmp++;
+	if (!*tmp) {
+		goto fail;
+	}
+	initrd_size = simple_strtol(str, &endptr, 16);
+	if (*endptr) {
+		*(tmp-1) = '@';
+		goto fail;
+	}
+	*(tmp-1) = '@';
+	initrd_start = simple_strtol(tmp, &endptr, 16);
+	if (*endptr) {
+		goto fail;
+	}
+	initrd_end = initrd_start + initrd_size;
+	printk("Found initrd of %lx@%lx\n", initrd_size, initrd_start);
+	return 1;
+ fail:
+	printk("Bad initrd argument.  Disabling initrd\n");
+	initrd_start = 0;
+	initrd_end = 0;
+	return 1;
+}
+
+#endif
+
+/*
+ * prom_init is called just after the cpu type is determined, from init_arch()
+ */
+__init int prom_init(int argc, char **argv, char **envp, int *prom_vec)
+{
+	_machine_restart   = (void (*)(char *))cfe_linux_exit;
+	_machine_halt      = cfe_linux_exit;
+	_machine_power_off = cfe_linux_exit;
+
+	/*
+	 * This should go away.  Detect if we're booting
+	 * straight from cfe without a loader.  If we
+	 * are, then we've got a prom vector in a0.  Otherwise,
+	 * argc (and argv and envp, for that matter) will be 0)
+	 */
+	if (argc < 0) {
+		prom_vec = (int *)argc;
+	}
+	cfe_init((long)prom_vec);
+	cfe_open_console();
+	if (cfe_getenv("LINUX_CMDLINE", arcs_cmdline, CL_SIZE) < 0) {
+		if (argc < 0) {
+			/*
+			 * It's OK for direct boot to not provide a
+			 *  command line
+			 */
+			strcpy(arcs_cmdline, "root=/dev/ram0 ");
+#ifdef CONFIG_SIBYTE_PTSWARM
+			strcat(arcs_cmdline, "console=ttyS0,115200 ");
+#endif
+		} else {
+			/* The loader should have set the command line */
+			panic("LINUX_CMDLINE not defined in cfe.");
+		}
+	}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	{
+		char *ptr;
+		/* Need to find out early whether we've got an initrd.  So scan
+		   the list looking now */
+		for (ptr = arcs_cmdline; *ptr; ptr++) {
+			while (*ptr == ' ') {
+				ptr++;
+			}
+			if (!strncmp(ptr, "initrd=", 7)) {
+				initrd_setup(ptr+7);
+				break;
+			} else {
+				while (*ptr && (*ptr != ' ')) {
+					ptr++;
+				}
+			}
+		}
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	/* Not sure this is needed, but it's the safe way. */
+	arcs_cmdline[CL_SIZE-1] = 0;
+
+	mips_machgroup = MACH_GROUP_SIBYTE;
+	prom_meminit();
+
+	return 0;
+}
+
+void prom_free_prom_memory(void)
+{
+	/* Not sure what I'm supposed to do here.  Nothing, I think */
+}
+
+int page_is_ram(unsigned long pagenr)
+{
+	phys_t addr = pagenr << PAGE_SHIFT;
+	int i;
+	for (i = 0; i < board_mem_region_count; i++) {
+		if ((addr >= board_mem_region_addrs[i])
+		    && (addr < (board_mem_region_addrs[i] + board_mem_region_sizes[i]))) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
+#ifdef CONFIG_SIBYTE_CFE_CONSOLE
+
+static void cfe_console_write(struct console *cons, const char *str,
+                              unsigned int count)
+{
+	int i, last;
+
+	for (i=0,last=0; i<count; i++) {
+		if (!str[i])
+			/* XXXKW can/should this ever happen? */
+			panic("cfe_console_write with NULL");
+		if (str[i] == '\n') {
+			cfe_console_print(&str[last], i-last);
+			cfe_console_print("\r", 1);
+			last = i;
+		}
+	}
+	if (last != count)
+		cfe_console_print(&str[last], count-last);
+}
+
+static kdev_t cfe_console_device(struct console *c)
+{
+	return cfe_consdev;
+}
+
+static int cfe_console_setup(struct console *cons, char *str)
+{
+	char consdev[32];
+	cfe_open_console();
+	/* XXXKW think about interaction with 'console=' cmdline arg */
+	/* If none of the console options are configured, the build will break. */
+	if (cfe_getenv("BOOT_CONSOLE", consdev, 32) >= 0) {
+#ifdef CONFIG_SIBYTE_SB1250_DUART
+		if (!strcmp(consdev, "uart0")) {
+			setleds("u0cn");
+			cfe_consdev = MKDEV(TTY_MAJOR, SB1250_DUART_MINOR_BASE + 0);
+#ifndef CONFIG_SIBYTE_SB1250_DUART_NO_PORT_1
+		} else if (!strcmp(consdev, "uart1")) {
+			setleds("u1cn");
+			cfe_consdev = MKDEV(TTY_MAJOR, SB1250_DUART_MINOR_BASE + 1);
+#endif
+#endif
+#ifdef CONFIG_VGA_CONSOLE
+		} else if (!strcmp(consdev, "pcconsole0")) {
+			setleds("pccn");
+			cfe_consdev = MKDEV(TTY_MAJOR, 0);
+#endif
+#ifdef CONFIG_PROMICE
+		} else if (!strcmp(consdev, "promice0")) {
+			setleds("picn");
+			cfe_consdev = MKDEV(TTY_MAJOR, SB1250_PROMICE_MINOR_BASE);
+#endif
+		} else
+			return -ENODEV;
+	}
+	return 0;
+}
+
+static struct console sb1250_cfe_cons = {
+	name:		"cfe",
+	write:		cfe_console_write,
+	device:		cfe_console_device,
+	setup:		cfe_console_setup,
+	flags:		CON_PRINTBUFFER,
+	index:		-1,
+};
+
+void __init sb1250_cfe_console_init(void)
+{
+	register_console(&sb1250_cfe_cons);
+}
+
+#endif /* CONFIG_SIBYTE_CFE_CONSOLE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/cfe/smp.c linux-2.4.20/arch/mips/sibyte/cfe/smp.c
--- linux-2.4.19/arch/mips/sibyte/cfe/smp.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/cfe/smp.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2000, 2001 Broadcom Corporation
+ *
+ * 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.
+ */
+
+#include <linux/sched.h>
+#include <linux/smp.h>
+
+#include <asm/mipsregs.h>
+
+#include "cfe_xiocb.h"
+#include "cfe_api.h"
+#include "cfe_error.h"
+
+extern void asmlinkage smp_bootstrap(void);
+
+/* Boot all other cpus in the system, initialize them, and
+   bring them into the boot fn */
+int prom_boot_secondary(int cpu, unsigned long sp, unsigned long gp)
+{
+	int retval;
+
+	retval = cfe_start_cpu(cpu, &smp_bootstrap, sp, gp, 0);
+	if (retval != 0) {
+		printk("cfe_start_cpu(%i) returned %i\n" , cpu, retval);
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
+void prom_init_secondary(void)
+{
+	/* Set up kseg0 to be cachable coherent */
+	clear_cp0_config(CONF_CM_CMASK);
+	set_cp0_config(0x5);
+
+	/* Enable interrupts for lines 0-4 */
+	clear_cp0_status(0xe000);
+	set_cp0_status(0x1f01);
+}
+
+/*
+ * Set up state, return the total number of cpus in the system, including
+ * the master
+ */
+int prom_setup_smp(void)
+{
+	int i;
+	int num_cpus = 1;
+
+	/* Use CFE to find out how many CPUs are available */
+	for (i=1; i<NR_CPUS; i++) {
+		if (cfe_stop_cpu(i) == 0) {
+			num_cpus++;
+		}
+	}
+	printk("Detected %i available CPU(s)\n", num_cpus);
+	return num_cpus;
+}
+
+void prom_smp_finish(void)
+{
+	extern void sb1250_smp_finish(void);
+	sb1250_smp_finish();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/sb1/cache_err_handler.S linux-2.4.20/arch/mips/sibyte/sb1/cache_err_handler.S
--- linux-2.4.19/arch/mips/sibyte/sb1/cache_err_handler.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/sb1/cache_err_handler.S	2002-10-29 11:18:49.000000000 +0000
@@ -10,7 +10,7 @@
  * 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.
@@ -20,6 +20,7 @@
 #include <asm/asm.h>
 #include <asm/regdef.h>
 #include <asm/mipsregs.h>
+#include <asm/sibyte/board.h>
 
 	.text
 	/* Special Cache Error handler for SB1 for now */
@@ -36,13 +37,12 @@
 	#.set	mips64
 	.set	mips4
 	.set	reorder
-	# look for signature of spurious CErr
+#ifdef CONFIG_SB1_CERR_IGNORE_RECOVERABLE
 	mfc0	k1, $26				# mfc0	k1, $26, 0
 	# check if error was recoverable
 	# XXXKW - count them
 	bltz	k1, leave_cerr
-	 nop
-
+#endif
 #ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
 	# look for signature of spurious CErr
 	lui	k0, 0x4000
@@ -51,13 +51,32 @@
 	lui	k0, 0xffe0
 	and	k1, k0, k1
 	lui	k0, 0x0200
-	bne	k0, k1, real_cerr
-	 nop
+	beq	k0, k1, leave_cerr
+	# XXXKW - count them
+#endif
+
+real_cerr:
+#ifdef CONFIG_SB1_CERR_SPIN
+        setleds(k0,k1,'C','E','R','R')
+
+1:	b	1b
 #else
-	j	real_cerr
-	 nop
+	mfc0	k0,CP0_CONFIG
+	li	k1,~CONF_CM_CMASK
+	and	k0,k0,k1
+	ori	k0,k0,CONF_CM_UNCACHED
+	mtc0	k0,CP0_CONFIG
+
+	SSNOP
+	SSNOP
+	SSNOP
+	SSNOP
+	bnezl	$0, 1f
+1:
+	j	sb1_cache_error
 #endif
-	# XXXKW - count spurious errors
+
+#if defined(CONFIG_SB1_PASS_1_WORKAROUNDS) || defined(CONFIG_SB1_CERR_IGNORE_RECOVERABLE)
 leave_cerr:
 	# clear/unlock the registers
 	mtc0	zero, $26			# mtc0	zero, $26, 0
@@ -65,23 +84,7 @@
 	.word	0x4080d801			# mtc0	zero, $27, 1
 	.word	0x4080d803			# mtc0	zero, $27, 3
 	eret
-
-real_cerr:
-	mfc0	k0, CP0_CONFIG
-	li	k1, ~CONF_CM_CMASK
-	and	k0, k0, k1
-	ori	k0, k0, CONF_CM_UNCACHED
-	mtc0	k0, CP0_CONFIG
-	/* Give it a few cycles to sink in... */
-	sll     zero, zero, 0x1			# ssnop
-	sll     zero, zero, 0x1			# ssnop
-	sll     zero, zero, 0x1			# ssnop
-	sll     zero, zero, 0x1			# ssnop
-	sll     zero, zero, 0x1			# ssnop
-	sll     zero, zero, 0x1			# ssnop
-
-	j	sb1_cache_error
-	 nop
+#endif
 
 	.set	pop
 	END(except_vec2_sb1)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/sb1/cache_error.c linux-2.4.20/arch/mips/sibyte/sb1/cache_error.c
--- linux-2.4.19/arch/mips/sibyte/sb1/cache_error.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/sb1/cache_error.c	2002-10-29 11:18:49.000000000 +0000
@@ -16,10 +16,14 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
-#include <linux/kernel.h>
+#include <linux/sched.h>
 #include <asm/mipsregs.h>
 
 /* SB1 definitions */
+
+/* XXX should come from config1 XXX */
+#define SB1_CACHE_INDEX_MASK   0x1fe0
+
 #define CP0_ERRCTL_RECOVERABLE (1 << 31)
 #define CP0_ERRCTL_DCACHE      (1 << 30)
 #define CP0_ERRCTL_ICACHE      (1 << 29)
@@ -30,7 +34,9 @@
 #define CP0_CERRI_TAG_PARITY   (1 << 29)
 #define CP0_CERRI_DATA_PARITY  (1 << 28)
 #define CP0_CERRI_EXTERNAL     (1 << 26)
-#define CP0_CERRI_CACHE_IDX    (0xff << 5)
+
+#define CP0_CERRI_IDX_VALID(c) (!((c) & CP0_CERRI_EXTERNAL))
+#define CP0_CERRI_DATA         (CP0_CERRI_DATA_PARITY)
 
 #define CP0_CERRD_MULTIPLE     (1 << 31)
 #define CP0_CERRD_TAG_STATE    (1 << 30)
@@ -43,38 +49,463 @@
 #define CP0_CERRD_FILLWB       (1 << 23)
 #define CP0_CERRD_COHERENCY    (1 << 22)
 #define CP0_CERRD_DUPTAG       (1 << 21)
-#define CP0_CERRD_CACHE_IDX    (0xff << 5)
 
-asmlinkage void sb1_cache_error(void)
+#define CP0_CERRD_DPA_VALID(c) (!((c) & CP0_CERRD_EXTERNAL))
+#define CP0_CERRD_IDX_VALID(c) \
+   (((c) & (CP0_CERRD_LOAD | CP0_CERRD_STORE)) ? (!((c) & CP0_CERRD_EXTERNAL)) : 0)
+#define CP0_CERRD_CAUSES \
+   (CP0_CERRD_LOAD | CP0_CERRD_STORE | CP0_CERRD_FILLWB | CP0_CERRD_COHERENCY | CP0_CERRD_DUPTAG)
+#define CP0_CERRD_TYPES \
+   (CP0_CERRD_TAG_STATE | CP0_CERRD_TAG_ADDRESS | CP0_CERRD_DATA_SBE | CP0_CERRD_DATA_DBE | CP0_CERRD_EXTERNAL)
+#define CP0_CERRD_DATA         (CP0_CERRD_DATA_SBE | CP0_CERRD_DATA_DBE)
+
+static uint32_t	extract_ic(unsigned short addr, int data);
+static uint32_t	extract_dc(unsigned short addr, int data);
+
+spinlock_t in_cacheerr = SPIN_LOCK_UNLOCKED;
+
+static inline void breakout_errctl(unsigned int val)
 {
-	unsigned int errctl, cerr_i, cerr_d, cerr_dpa;
-	unsigned long eepc;
+	if (val & CP0_ERRCTL_RECOVERABLE)
+		printk(" recoverable");
+	if (val & CP0_ERRCTL_DCACHE)
+		printk(" dcache");
+	if (val & CP0_ERRCTL_ICACHE)
+		printk(" icache");
+	if (val & CP0_ERRCTL_MULTIBUS)
+		printk(" multiple-buserr");
+	printk("\n");
+}
 
-	eepc = get_errorepc();
+static inline void breakout_cerri(unsigned int val)
+{
+	if (val & CP0_CERRI_TAG_PARITY)
+		printk(" tag-parity");
+	if (val & CP0_CERRI_DATA_PARITY)
+		printk(" data-parity");
+	if (val & CP0_CERRI_EXTERNAL)
+		printk(" external");
+	printk("\n");
+}
+
+static inline void breakout_cerrd(unsigned int val)
+{
+	switch (val & CP0_CERRD_CAUSES) {
+	case CP0_CERRD_LOAD:
+		printk(" load,");
+		break;
+	case CP0_CERRD_STORE:
+		printk(" store,");
+		break;
+	case CP0_CERRD_FILLWB:
+		printk(" fill/wb,");
+		break;
+	case CP0_CERRD_COHERENCY:
+		printk(" coherency,");
+		break;
+	case CP0_CERRD_DUPTAG:
+		printk(" duptags,");
+		break;
+	default:
+		printk(" NO CAUSE,");
+		break;
+	}
+	if (!(val & CP0_CERRD_TYPES))
+		printk(" NO TYPE");
+	else {
+		if (val & CP0_CERRD_MULTIPLE)
+			printk(" multi-err");
+		if (val & CP0_CERRD_TAG_STATE)
+			printk(" tag-state");
+		if (val & CP0_CERRD_TAG_ADDRESS)
+			printk(" tag-address");
+		if (val & CP0_CERRD_DATA_SBE)
+			printk(" data-SBE");
+		if (val & CP0_CERRD_DATA_DBE)
+			printk(" data-DBE");
+		if (val & CP0_CERRD_EXTERNAL)
+			printk(" external");
+	}
+	printk("\n");
+}
 
+asmlinkage void sb1_cache_error(void)
+{
+	uint64_t cerr_dpa;
+	uint32_t errctl, cerr_i, cerr_d, dpalo, dpahi, eepc, res;
+
+	/* Prevent re-entrance in the SMP case */
+	spin_lock(&in_cacheerr);
+	printk("Cache error exception on CPU %x:\n",
+	       (read_32bit_cp0_register(CP0_PRID) >> 25) & 0x7);
 	__asm__ __volatile__ (
-		".set push\n"
-		"#.set mips64\n"
-		".set mips4\n"
-		".word 0x4001D000; move %0, $1; # mfc0 %0, $26, 0\n"
-		".word 0x4001D800; move %1, $1; # mfc0 %1, $27, 0\n"
-		".word 0x4001D801; move %2, $1; # mfc0 %2, $27, 1\n"
-		".word 0x4001D803; move %3, $1; # mfc0 %3, $27, 3\n"
+		".set push\n\t"
+		".set mips64\n\t"
+		".set noat\n\t"
+		"mfc0   %0, $26, 0\n\t"
+		"mfc0   %1, $27, 0\n\t"
+		"mfc0   %2, $27, 1\n\t"
+		"dmfc0  $1, $27, 3\n\t"
+		"dsrl32 %3, $1, 0 \n\t"
+		"sll    %4, $1, 0 \n\t"
+		"mfc0   %5, $30\n\t"
 		".set pop\n"
-		: "=r" (errctl), "=r" (cerr_i),
-		  "=r" (cerr_d), "=r" (cerr_dpa));
+		: "=r" (errctl), "=r" (cerr_i), "=r" (cerr_d),
+		  "=r" (dpahi), "=r" (dpalo), "=r" (eepc));
+	cerr_dpa = (((uint64_t)dpahi) << 32) | dpalo;
+	printk(" cp0_errorepc ==   %08x\n", eepc);
+	printk(" cp0_errctl   ==   %08x", errctl);
+	breakout_errctl(errctl);
+	if (errctl & CP0_ERRCTL_ICACHE) {
+		printk(" cp0_cerr_i   ==   %08x", cerr_i);
+		breakout_cerri(cerr_i);
+		if (CP0_CERRI_IDX_VALID(cerr_i)) {
+			if ((eepc & SB1_CACHE_INDEX_MASK) != (cerr_i & SB1_CACHE_INDEX_MASK))
+				printk(" cerr_i idx doesn't match eepc\n");
+			else {
+				res = extract_ic(cerr_i & SB1_CACHE_INDEX_MASK,
+						 (cerr_i & CP0_CERRI_DATA) != 0);
+				if (!(res & cerr_i))
+					printk("...didn't see indicated icache problem\n");
+			}
+		}
+	}
+	if (errctl & CP0_ERRCTL_DCACHE) {
+		printk(" cp0_cerr_d   ==   %08x", cerr_d);
+		breakout_cerrd(cerr_d);
+		if (CP0_CERRD_DPA_VALID(cerr_d)) {
+			printk(" cp0_cerr_dpa == %010llx\n", cerr_dpa);
+			if (!CP0_CERRD_IDX_VALID(cerr_d)) {
+				res = extract_dc(cerr_dpa & SB1_CACHE_INDEX_MASK,
+						 (cerr_d & CP0_CERRD_DATA) != 0);
+				if (!(res & cerr_d))
+					printk("...didn't see indicated dcache problem\n");
+			} else {
+				if ((cerr_dpa & SB1_CACHE_INDEX_MASK) != (cerr_d & SB1_CACHE_INDEX_MASK))
+					printk(" cerr_d idx doesn't match cerr_dpa\n");
+				else {
+					res = extract_dc(cerr_d & SB1_CACHE_INDEX_MASK,
+							 (cerr_d & CP0_CERRD_DATA) != 0);
+					if (!(res & cerr_d))
+						printk("...didn't see indicated problem\n");
+				}
+			}
+		}
+	}
 
-	printk("Cache error exception:\n");
-	printk(" cp0_errorepc == 0x%0lx\n", eepc);
-	printk(" cp0_errctl   == 0x%08x\n", errctl);
+	while (1);
+	/*
+	 * This tends to make things get really ugly; let's just stall instead.
+	 *    panic("Can't handle the cache error!");
+	 */
+}
 
-	if (errctl & CP0_ERRCTL_DCACHE) {
-		printk(" cp0_cerr_d   == 0x%08x\n", cerr_d);
-		printk(" cp0_cerr_dpa == 0x%08x\n", cerr_dpa);
+
+/* Parity lookup table. */
+static const uint8_t parity[256] = {
+	0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+	1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+	1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+	0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+	1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+	0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+	0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+	1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
+};
+
+/* Masks to select bits for Hamming parity, mask_72_64[i] for bit[i] */
+static const uint64_t mask_72_64[8] = {
+	0x0738C808099264FFL,
+	0x38C808099264FF07L,
+	0xC808099264FF0738L,
+	0x08099264FF0738C8L,
+	0x099264FF0738C808L,
+	0x9264FF0738C80809L,
+	0x64FF0738C8080992L,
+	0xFF0738C808099264L
+};
+
+/* Calculate the parity on a range of bits */
+static char range_parity(uint64_t dword, int max, int min)
+{
+	char parity = 0;
+	int i;
+	dword >>= min;
+	for (i=max-min; i>=0; i--) {
+		if (dword & 0x1)
+			parity = !parity;
+		dword >>= 1;
 	}
-	if (errctl & CP0_ERRCTL_ICACHE) {
-		printk(" cp0_cerr_i   == 0x%08x\n", cerr_i);
+	return parity;
+}
+
+/* Calculate the 4-bit even byte-parity for an instruction */
+static unsigned char inst_parity(uint32_t word)
+{
+	int i, j;
+	char parity = 0;
+	for (j=0; j<4; j++) {
+		char byte_parity = 0;
+		for (i=0; i<8; i++) {
+			if (word & 0x80000000)
+				byte_parity = !byte_parity;
+			word <<= 1;
+		}
+		parity <<= 1;
+		parity |= byte_parity;
 	}
+	return parity;
+}
+
+static uint32_t extract_ic(unsigned short addr, int data)
+{
+	unsigned short way;
+	int valid;
+	uint64_t taglo, va, tlo_tmp;
+	uint32_t taghi, taglolo, taglohi;
+	uint8_t lru;
+	int res = 0;
+
+	printk("Icache index 0x%04x  ", addr);
+	for (way = 0; way < 4; way++) {
+		/* Index-load-tag-I */
+		__asm__ __volatile__ (
+			".set push        \n\t"
+			".set noreorder   \n\t"
+			".set mips64      \n\t"
+			".set noat        \n\t"
+			"cache  4, 0(%3)  \n\t"
+			"mfc0   %0, $29, 0\n\t"
+			"dmfc0  $1, $28, 0\n\t"
+			"dsrl32 %1, $1, 0 \n\t"
+			"sll    %2, $1, 0 \n\t"
+			".set pop         \n"
+			: "=r" (taghi), "=r" (taglohi),
+			  "=r" (taglolo)
+			: "r" ((way << 13) | addr));
+		taglo = ((unsigned long long)taglohi << 32) | taglolo;
+		if (way == 0) {
+			lru = (taghi >> 14) & 0xff;
+			printk("[Bank %d Set 0x%02x]  LRU > %d %d %d %d > MRU\n",
+			       ((addr >> 5) & 0x3), /* bank */
+			       ((addr >> 7) & 0x3f), /* index */
+			       (lru & 0x3),
+			       ((lru >> 2) & 0x3),
+			       ((lru >> 4) & 0x3),
+			       ((lru >> 6) & 0x3));
+		}
+		va = (taglo & 0xC0000FFFFFFFE000) | addr;
+		if ((taglo & (1 << 31)) && (((taglo >> 62) & 0x3) == 3))
+			va |= 0x3FFFF00000000000;
+		valid = ((taghi >> 29) & 1);
+		if (valid) {
+			tlo_tmp = taglo & 0xfff3ff;
+			if (((taglo >> 10) & 1) ^ range_parity(tlo_tmp, 23, 0)) {
+				printk("   ** bad parity in VTag0/G/ASID\n");
+				res |= CP0_CERRI_TAG_PARITY;
+			}
+			if (((taglo >> 11) & 1) ^ range_parity(taglo, 63, 24)) {
+				printk("   ** bad parity in R/VTag1\n");
+				res |= CP0_CERRI_TAG_PARITY;
+			}
+		}
+		if (valid ^ ((taghi >> 27) & 1)) {
+			printk("   ** bad parity for valid bit\n");
+			res |= CP0_CERRI_TAG_PARITY;
+		}
+		printk(" %d  [VA %016llx]  [Vld? %d]  raw tags: %08X-%016llX\n",
+		       way, va, valid, taghi, taglo);
+
+		if (data) {
+			uint32_t datahi, insta, instb;
+			uint8_t predecode;
+			int offset;
 
-	panic("Can't handle the cache error!");
+			/* (hit all banks and ways) */
+			for (offset = 0; offset < 4; offset++) {
+				/* Index-load-data-I */
+				__asm__ __volatile__ (
+					".set push        \n\t"
+					".set noreorder   \n\t"
+					".set mips64      \n\t"
+					".set noat        \n\t"
+					"cache  6, 0(%3)  \n\t"
+					"mfc0   %0, $29, 1\n\t"
+					"dmfc0  $1, $28, 1\n\t"
+					"dsrl32 %1, $1, 0 \n\t"
+					"sll    %2, $1, 0 \n\t"
+					".set pop         \n"
+					: "=r" (datahi), "=r" (insta),
+					  "=r" (instb)
+					: "r" ((way << 13) | addr | (offset << 3)));
+				predecode = (datahi >> 8) & 0xff;
+				if (((datahi >> 16) & 1) != (uint32_t)range_parity(predecode, 7, 0)) {
+					printk("   ** bad parity in predecode\n");
+					res |= CP0_CERRI_DATA_PARITY;
+				}
+				/* XXXKW should/could check predecode bits themselves */
+				if (((datahi >> 4) & 0xf) ^ inst_parity(insta)) {
+					printk("   ** bad parity in instruction a\n");
+					res |= CP0_CERRI_DATA_PARITY;
+				}
+				if ((datahi & 0xf) ^ inst_parity(instb)) {
+					printk("   ** bad parity in instruction b\n");
+					res |= CP0_CERRI_DATA_PARITY;
+				}
+				printk("  %05X-%08X%08X", datahi, insta, instb);
+			}
+			printk("\n");
+		}
+	}
+	return res;
+}
+
+/* Compute the ECC for a data doubleword */
+static uint8_t dc_ecc(uint64_t dword)
+{
+	uint64_t t;
+	uint32_t w;
+	uint8_t  p;
+	int      i;
+
+	p = 0;
+	for (i = 7; i >= 0; i--)
+	{
+		p <<= 1;
+		t = dword & mask_72_64[i];
+		w = (uint32_t)(t >> 32);
+		p ^= (parity[w>>24] ^ parity[(w>>16) & 0xFF]
+		      ^ parity[(w>>8) & 0xFF] ^ parity[w & 0xFF]);
+		w = (uint32_t)(t & 0xFFFFFFFF);
+		p ^= (parity[w>>24] ^ parity[(w>>16) & 0xFF]
+		      ^ parity[(w>>8) & 0xFF] ^ parity[w & 0xFF]);
+	}
+	return p;
+}
+
+struct dc_state {
+	unsigned char val;
+	char *name;
+};
+
+static struct dc_state dc_states[] = {
+	{ 0x00, "INVALID" },
+	{ 0x0f, "COH-SHD" },
+	{ 0x13, "NCO-E-C" },
+	{ 0x19, "NCO-E-D" },
+	{ 0x16, "COH-E-C" },
+	{ 0x1c, "COH-E-D" },
+	{ 0xff, "*ERROR*" }
+};
+
+#define DC_TAG_VALID(state) \
+    (((state) == 0xf) || ((state) == 0x13) || ((state) == 0x19) || ((state == 0x16)) || ((state) == 0x1c))
+
+static char *dc_state_str(unsigned char state)
+{
+	struct dc_state *dsc = dc_states;
+	while (dsc->val != 0xff) {
+		if (dsc->val == state)
+			break;
+		dsc++;
+	}
+	return dsc->name;
+}
+
+static uint32_t extract_dc(unsigned short addr, int data)
+{
+	int valid, way;
+	unsigned char state;
+	uint64_t taglo, pa;
+	uint32_t taghi, taglolo, taglohi;
+	uint8_t ecc, lru;
+	int res = 0;
+
+	printk("Dcache index 0x%04x  ", addr);
+	for (way = 0; way < 4; way++) {
+		/* Index-load-tag-D */
+		__asm__ __volatile__ (
+			".set push        \n\t"
+			".set noreorder   \n\t"
+			".set mips64      \n\t"
+			".set noat        \n\t"
+			"cache  5, 0(%3)  \n\t"
+			"mfc0   %0, $29, 2\n\t"
+			"dmfc0  $1, $28, 2\n\t"
+			"dsrl32 %1, $1, 0 \n\t"
+			"sll    %2, $1, 0 \n\t"
+			".set pop         \n"
+			: "=r" (taghi), "=r" (taglohi),
+			  "=r" (taglolo)
+			: "r" ((way << 13) | addr));
+
+		taglo = ((unsigned long long)taglohi << 32) | taglolo;
+		pa = (taglo & 0xFFFFFFE000) | addr;
+		if (way == 0) {
+			lru = (taghi >> 14) & 0xff;
+			printk("[Bank %d Set 0x%02x]  LRU > %d %d %d %d > MRU\n",
+			       ((addr >> 11) & 0x2) | ((addr >> 5) & 1), /* bank */
+			       ((addr >> 6) & 0x3f), /* index */
+			       (lru & 0x3),
+			       ((lru >> 2) & 0x3),
+			       ((lru >> 4) & 0x3),
+			       ((lru >> 6) & 0x3));
+		}
+		state = (taghi >> 25) & 0x1f;
+		valid = DC_TAG_VALID(state);
+		printk(" %d  [PA %010llx]  [state %s (%02x)]  raw tags: %08X-%016llX\n",
+		       way, pa, dc_state_str(state), state, taghi, taglo);
+		if (valid) {
+			if (((taglo >> 11) & 1) ^ range_parity(taglo, 39, 26)) {
+				printk("   ** bad parity in PTag1\n");
+				res |= CP0_CERRD_TAG_ADDRESS;
+			}
+			if (((taglo >> 10) & 1) ^ range_parity(taglo, 25, 13)) {
+				printk("   ** bad parity in PTag0\n");
+				res |= CP0_CERRD_TAG_ADDRESS;
+			}
+		} else {
+			res |= CP0_CERRD_TAG_STATE;
+		}
+
+		if (data) {
+			uint64_t datalo;
+			uint32_t datalohi, datalolo, datahi;
+			int offset;
+
+			for (offset = 0; offset < 4; offset++) {
+				/* Index-load-data-D */
+				__asm__ __volatile__ (
+					".set push        \n\t"
+					".set noreorder   \n\t"
+					".set mips64      \n\t"
+					".set noat        \n\t"
+					"cache  7, 0(%3)  \n\t"
+					"mfc0   %0, $29, 3\n\t"
+					"dmfc0  $1, $28, 3\n\t"
+					"dsrl32 %1, $1, 0 \n\t"
+					"sll    %2, $1, 0 \n\t"
+					".set pop         \n"
+					: "=r" (datahi), "=r" (datalohi),
+					"=r" (datalolo)
+					: "r" ((way << 13) | addr | (offset << 3)));
+				datalo = ((unsigned long long)datalohi << 32) | datalolo;
+				ecc = dc_ecc(datalo);
+				if (ecc != datahi) {
+					int bits = 0;
+					printk("  ** bad ECC (%02x %02x) ->",
+					       datahi, ecc);
+					ecc ^= datahi;
+					while (ecc) {
+						if (ecc & 1) bits++;
+						ecc >>= 1;
+					}
+					res |= (bits == 1) ? CP0_CERRD_DATA_SBE : CP0_CERRD_DATA_DBE;
+				}
+				printk("  %02X-%016llX", datahi, datalo);
+			}
+			printk("\n");
+		}
+	}
+	return res;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/sb1250/Makefile linux-2.4.20/arch/mips/sibyte/sb1250/Makefile
--- linux-2.4.19/arch/mips/sibyte/sb1250/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/sb1250/Makefile	2002-10-29 11:18:33.000000000 +0000
@@ -2,11 +2,12 @@
 
 O_TARGET := sb1250.o
 
-obj-y := irq.o irq_handler.o time.o
+obj-y := setup.o irq.o irq_handler.o time.o
 
 obj-$(CONFIG_PCI)		+= pci.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_BCM1250_TBPROF)	+= bcm1250_tbprof.o
 obj-$(CONFIG_MIPS32)		+= lib_hssubr.o
+obj-$(CONFIG_SIBYTE_STANDALONE)	+= prom.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/sb1250/bcm1250_tbprof.c linux-2.4.20/arch/mips/sibyte/sb1250/bcm1250_tbprof.c
--- linux-2.4.19/arch/mips/sibyte/sb1250/bcm1250_tbprof.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/sb1250/bcm1250_tbprof.c	2002-10-29 11:18:32.000000000 +0000
@@ -10,7 +10,7 @@
  * 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.
@@ -50,20 +50,26 @@
  * overflow.
  *
  * We map the interrupt for trace_buffer_freeze to handle it on CPU 0.
- * 
+ *
  ************************************************************************/
 
-/* Once per second on a 500 Mhz 1250 */
-#define TB_PERIOD 250000000ULL
+/* 100 samples per second on a 500 Mhz 1250 */
+#define TB_PERIOD 2500000ULL
 
 static void arm_tb(void)
 {
+        unsigned long long scdperfcnt;
 	unsigned long long next = (1ULL << 40) - TB_PERIOD;
 	/* Generate an SCD_PERFCNT interrupt in TB_PERIOD Zclks to
 	   trigger start of trace.  XXX vary sampling period */
 	out64(0, KSEG1 + A_SCD_PERF_CNT_1);
-	out64(in64(KSEG1 + A_SCD_PERF_CNT_CFG) | // keep counters 0,2,3 as is
+	scdperfcnt = in64(KSEG1 + A_SCD_PERF_CNT_CFG);
+	/* Unfortunately, in Pass 2 we must clear all counters to knock down
+	   a previous interrupt request.  This means that bus profiling
+	   requires ALL of the SCD perf counters. */
+	out64((scdperfcnt & ~M_SPC_CFG_SRC1) | // keep counters 0,2,3 as is
 		   M_SPC_CFG_ENABLE |		 // enable counting
+		   M_SPC_CFG_CLEAR |		 // clear all counters
 		   V_SPC_CFG_SRC1(1),		 // counter 1 counts cycles
 	      KSEG1 + A_SCD_PERF_CNT_CFG);
 	out64(next, KSEG1 + A_SCD_PERF_CNT_1);
@@ -150,17 +156,17 @@
 	out64(0, KSEG1 + A_ADDR_TRAP_UP_1);
 	out64(0, KSEG1 + A_ADDR_TRAP_UP_2);
 	out64(0, KSEG1 + A_ADDR_TRAP_UP_3);
-	
+
 	out64(0, KSEG1 + A_ADDR_TRAP_DOWN_0);
 	out64(0, KSEG1 + A_ADDR_TRAP_DOWN_1);
 	out64(0, KSEG1 + A_ADDR_TRAP_DOWN_2);
 	out64(0, KSEG1 + A_ADDR_TRAP_DOWN_3);
-	
+
 	out64(0, KSEG1 + A_ADDR_TRAP_CFG_0);
 	out64(0, KSEG1 + A_ADDR_TRAP_CFG_1);
 	out64(0, KSEG1 + A_ADDR_TRAP_CFG_2);
 	out64(0, KSEG1 + A_ADDR_TRAP_CFG_3);
-	
+
 	/* Initialize Trace Event 0-7 */
 	//				when interrupt
 	out64(M_SCD_TREVT_INTERRUPT, KSEG1 + A_SCD_TRACE_EVENT_0);
@@ -171,7 +177,7 @@
 	out64(0, KSEG1 + A_SCD_TRACE_EVENT_5);
 	out64(0, KSEG1 + A_SCD_TRACE_EVENT_6);
 	out64(0, KSEG1 + A_SCD_TRACE_EVENT_7);
-	
+
 	/* Initialize Trace Sequence 0-7 */
 	//				     Start on event 0 (interrupt)
 	out64(V_SCD_TRSEQ_FUNC_START|0x0fff,
@@ -252,7 +258,7 @@
 static int sbprof_tb_release(struct inode *inode, struct file *filp)
 {
 	int minor;
-	
+
 	minor = MINOR(inode->i_rdev);
 	if (minor != 0 || sbp == NULL) {
 		return -ENODEV;
@@ -269,7 +275,7 @@
 	return 0;
 }
 
-static ssize_t sbprof_tb_read(struct file *filp, char *buf, 
+static ssize_t sbprof_tb_read(struct file *filp, char *buf,
 			   size_t size, loff_t *offp)
 {
 	int cur_sample, sample_off, cur_count, sample_left;
@@ -309,9 +315,9 @@
 #define SBPROF_ZBSTOP	_IOW('s', 1, int)
 #define SBPROF_ZBFULL	_IOW('s', 2, int)
 
-static int sbprof_tb_ioctl(struct inode *inode, 
+static int sbprof_tb_ioctl(struct inode *inode,
 			struct file *filp,
-			unsigned int command, 
+			unsigned int command,
 			unsigned long arg)
 {
 	int error = 0;
@@ -346,7 +352,7 @@
 
 static devfs_handle_t devfs_handle;
 
-static int __init sbprof_tb_init(void) 
+static int __init sbprof_tb_init(void)
 {
 	if (devfs_register_chrdev(SBPROF_TB_MAJOR, DEVNAME, &sbprof_tb_fops)) {
 		printk(KERN_WARNING DEVNAME ": initialization failed (dev %d)\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/sb1250/bcm1250_tbprof.h linux-2.4.20/arch/mips/sibyte/sb1250/bcm1250_tbprof.h
--- linux-2.4.19/arch/mips/sibyte/sb1250/bcm1250_tbprof.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/sb1250/bcm1250_tbprof.h	2002-10-29 11:18:33.000000000 +0000
@@ -10,7 +10,7 @@
  * 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.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/sb1250/irq.c linux-2.4.20/arch/mips/sibyte/sb1250/irq.c
--- linux-2.4.19/arch/mips/sibyte/sb1250/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/sb1250/irq.c	2002-10-29 11:18:51.000000000 +0000
@@ -10,7 +10,7 @@
  * 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.
@@ -23,21 +23,24 @@
 #include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+
 #include <asm/errno.h>
 #include <asm/signal.h>
 #include <asm/system.h>
 #include <asm/ptrace.h>
+
 #include <asm/sibyte/sb1250_regs.h>
 #include <asm/sibyte/sb1250_int.h>
+#include <asm/sibyte/sb1250_uart.h>
 #include <asm/sibyte/sb1250_scd.h>
 #include <asm/sibyte/sb1250.h>
 #include <asm/sibyte/64bit.h>
 
 /*
- * These are the routines that handle all the low level interrupt stuff. 
+ * These are the routines that handle all the low level interrupt stuff.
  * Actions handled here are: initialization of the interrupt map, requesting of
  * interrupt lines by handlers, dispatching if interrupts to handlers, probing
- * for interrupt lines 
+ * for interrupt lines
  */
 
 
@@ -50,6 +53,15 @@
 
 #ifdef CONFIG_REMOTE_DEBUG
 extern void breakpoint(void);
+extern void set_debug_traps(void);
+
+/* kgdb is on when configured.  Pass "nokgdb" kernel arg to turn it off */
+static int kgdb_flag = 1;
+static int __init nokgdb(char *str)
+{
+	kgdb_flag = 0;
+}
+__setup("nokgdb", nokgdb);
 #endif
 
 #define NR_IRQS 64
@@ -155,11 +167,44 @@
 }
 
 
+static void sb1250_dummy_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static struct irqaction sb1250_dummy_action = {
+	handler: sb1250_dummy_handler,
+	flags:   0,
+	mask:    0,
+	name:    "sb1250-private",
+	next:    NULL,
+	dev_id:  0
+};
+
+int sb1250_steal_irq(int irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	unsigned long flags;
+	int retval = 0;
+
+	if (irq >= NR_IRQS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&desc->lock,flags);
+	/* Don't allow sharing at all for these */
+	if (desc->action != NULL)
+		retval = -EBUSY;
+	else {
+		desc->action = &sb1250_dummy_action;
+		desc->depth = 0;
+	}
+	spin_unlock_irqrestore(&desc->lock,flags);
+}
+
 /*
  *  init_IRQ is called early in the boot sequence from init/main.c.  It
  *  is responsible for setting up the interrupt mapper and installing the
  *  handler that will be responsible for dispatching interrupts to the
- *  "right" place. 
+ *  "right" place.
  */
 /*
  * For now, map all interrupts to IP[2].  We could save
@@ -167,10 +212,10 @@
  * IP lines, but keep it simple for bringup.  We'll also direct
  * all interrupts to a single CPU; we should probably route
  * PCI and LDT to one cpu and everything else to the other
- * to balance the load a bit. 
- * 
+ * to balance the load a bit.
+ *
  * On the second cpu, everything is set to IP5, which is
- * ignored, EXCEPT the mailbox interrupt.  That one is 
+ * ignored, EXCEPT the mailbox interrupt.  That one is
  * set to IP[2] so it is handled.  This is needed so we
  * can do cross-cpu function calls, as requred by SMP
  */
@@ -178,12 +223,16 @@
 #define IMR_IP2_VAL	K_INT_MAP_I0
 #define IMR_IP3_VAL	K_INT_MAP_I1
 #define IMR_IP4_VAL	K_INT_MAP_I2
+#define IMR_IP5_VAL	K_INT_MAP_I3
+#define IMR_IP6_VAL	K_INT_MAP_I4
 
 void __init init_IRQ(void)
 {
 
 	unsigned int i;
 	u64 tmp;
+	unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
+		STATUSF_IP1 | STATUSF_IP0;
 
 	/* Default everything to IP2 */
 	for (i = 0; i < NR_IRQS; i++) {	/* was I0 */
@@ -220,26 +269,60 @@
 	out64(tmp, KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MASK));
 	out64(tmp, KSEG1 + A_IMR_REGISTER(1, R_IMR_INTERRUPT_MASK));
 
+	sb1250_steal_irq(K_INT_MBOX_0);
+
 	/*
-	 * Note that the timer interrupts are also mapped, but this is 
+	 * Note that the timer interrupts are also mapped, but this is
 	 * done in sb1250_time_init()
 	 */
 
-#ifdef CONFIG_SIBYTE_SB1250_PROF
-	/* Enable IP[7,4:0], disable the rest */
-	clear_cp0_status(0x6000);
-	set_cp0_status(0x9f00);
-#else
-	/* Enable IP[4:0], disable the rest */
-	clear_cp0_status(0xe000);
-	set_cp0_status(0x1f00);
+#ifdef CONFIG_BCM1250_PROF
+	imask |= STATUSF_IP7;
+#endif
+#ifdef CONFIG_REMOTE_DEBUG
+	imask |= STATUSF_IP6;
 #endif
+	/* Enable necessary IPs, disable the rest */
+	change_cp0_status(ST0_IM, imask);
 	set_except_vector(0, sb1250_irq_handler);
 
 #ifdef CONFIG_REMOTE_DEBUG
-	/* If local serial I/O used for debug port, enter kgdb at once */
-//      puts("Waiting for kgdb to connect...");
-	set_debug_traps();
-	breakpoint();
+	if (kgdb_flag) {
+		/* Setup uart 1 settings, mapper */
+		out64(M_DUART_IMR_BRK, KSEG1 + A_DUART + R_DUART_IMR_B);
+
+		out64(IMR_IP6_VAL,
+			KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) + (K_INT_UART_1<<3));
+		tmp = in64(KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MASK));
+		tmp &= ~(1<<K_INT_UART_1);
+		out64(tmp, KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MASK));
+
+		set_debug_traps();
+		breakpoint();
+	}
 #endif
 }
+
+#ifdef CONFIG_REMOTE_DEBUG
+
+#include <linux/delay.h>
+
+extern void set_async_breakpoint(unsigned int epc);
+
+#define duart_out(reg, val)     out64(val, KSEG1 + A_DUART_CHANREG(1,reg))
+#define duart_in(reg)           in64(KSEG1 + A_DUART_CHANREG(1,reg))
+
+void sb1250_kgdb_interrupt(struct pt_regs *regs)
+{
+	/*
+	 * Clear break-change status (allow some time for the remote
+	 * host to stop the break, since we would see another
+	 * interrupt on the end-of-break too)
+	 */
+	mdelay(500);
+	duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT |
+				M_DUART_RX_EN | M_DUART_TX_EN);
+	if (!user_mode(regs))
+		set_async_breakpoint(regs->cp0_epc);
+}
+#endif 	/* CONFIG_REMOTE_DEBUG */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/sb1250/irq_handler.S linux-2.4.20/arch/mips/sibyte/sb1250/irq_handler.S
--- linux-2.4.19/arch/mips/sibyte/sb1250/irq_handler.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/sb1250/irq_handler.S	2002-10-29 11:18:35.000000000 +0000
@@ -10,12 +10,12 @@
  * 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.
  */
- 
+
 /*
  * sb1250_handle_int() is the routine that is actually called when an interrupt
  * occurs.  It is installed as the exception vector handler in init_IRQ() in
@@ -23,10 +23,10 @@
  *
  * In the handle we figure out which interrupts need handling, and use that to
  * call the dispatcher, which will take care of actually calling registered
- * handlers 
- * 
+ * handlers
+ *
  * Note that we take care of all raised interrupts in one go at the handler.
- * This is more BSDish than the Indy code, and also, IMHO, more sane. 
+ * This is more BSDish than the Indy code, and also, IMHO, more sane.
  */
 #include <linux/config.h>
 
@@ -40,15 +40,15 @@
 #include <asm/sibyte/sb1250_regs.h>
 #include <asm/sibyte/sb1250_int.h>
 
-/* 
+/*
  * What a pain. We have to be really careful saving the upper 32 bits of any
- * register across function calls if we don't want them trashed--since were 
+ * register across function calls if we don't want them trashed--since were
  * running in -o32, the calling routing never saves the full 64 bits of a
  * register across a function call.  Being the interrupt handler, we're
  * guaranteed that interrupts are disabled during this code so we don't have
  * to worry about random interrupts blasting the high 32 bits.
  */
- 
+
 	.text
 	.set	push
 	.set	noreorder
@@ -77,8 +77,13 @@
 	mfc0	a0, CP0_EPC
 	jal	sbprof_cpu_intr
 	 addu	a0, a0, t1		/* a0 = EPC + (BD ? 4 :	0) */
+	/* Re-enable interrupts here so that events due to sbprof_cpu_intr
+	   get charged to ret_from_irq (via a recursive interrupt)
+	   rather than the restart pc. */
+	mfc0	t0, CP0_STATUS
+	or	t0, ST0_IE
 	j	ret_from_irq
-	 nop				# delay slot
+	 mtc0	t0, CP0_STATUS		# delay slot
 0:
 #endif
 	/* Timer interrupt is routed to IP[4] */
@@ -97,12 +102,24 @@
 	beqz	 t1, 2f
          nop
 	jal	 sb1250_mailbox_interrupt
-	 move    a0, sp		
+	 move    a0, sp
 	j	ret_from_irq
 	 nop				# delay slot
 2:
 #endif
 
+#ifdef CONFIG_REMOTE_DEBUG
+	/* KGDB (uart 1) interrupt is routed to IP[6] */
+	andi	t1, s0, CAUSEF_IP6
+	beqz	t1, 1f
+	nop                            # delay slot
+	jal	sb1250_kgdb_interrupt
+         move	a0, sp
+	j	ret_from_irq
+	nop                            # delay slot
+1:
+#endif
+
 	and      t1, s0, CAUSEF_IP2
 	beqz     t1, 4f
 	 nop
@@ -120,7 +137,7 @@
 3:	#dclz	s1, s0		/* Find the next interrupt */
 	.word   0x72118824	# dclz s1, s0
 	dsubu	a0, zero, s1
-	daddiu	a0, a0, 63     
+	daddiu	a0, a0, 63
 	jal	 do_IRQ
 	 nop
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/sb1250/lib_hssubr.S linux-2.4.20/arch/mips/sibyte/sb1250/lib_hssubr.S
--- linux-2.4.19/arch/mips/sibyte/sb1250/lib_hssubr.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/sb1250/lib_hssubr.S	2002-10-29 11:18:33.000000000 +0000
@@ -10,7 +10,7 @@
  * 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.
@@ -22,7 +22,7 @@
 
 		 .set mips64
 
-#define HAZARD SSNOP ; SSNOP ; SSNOP ; SSNOP ; SSNOP ; SSNOP ; SSNOP 
+#define HAZARD SSNOP ; SSNOP ; SSNOP ; SSNOP ; SSNOP ; SSNOP ; SSNOP
 
 
 /*  *********************************************************************
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/sb1250/lib_hssubr.h linux-2.4.20/arch/mips/sibyte/sb1250/lib_hssubr.h
--- linux-2.4.19/arch/mips/sibyte/sb1250/lib_hssubr.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/sb1250/lib_hssubr.h	2002-10-29 11:18:48.000000000 +0000
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2000, 2001 Broadcom Corporation
+ * Copyright (C) 2002 Ralf Baechle
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -10,45 +11,71 @@
  * 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.
  */
-
 #ifndef _LIB_HSSUBR_H
 #define _LIB_HSSUBR_H
 
-/*
- * If __long64 we can do this via macros.  Otherwise, call
- * the magic functions.
- */
-
-#if __long64
+#include <linux/config.h>
+#include <asm/addrspace.h>
 
 typedef long hsaddr_t;
 
-#define hs_write8(a,b) *((volatile uint8_t *) (a)) = (b)
-#define hs_write16(a,b) *((volatile uint16_t *) (a)) = (b)
-#define hs_write32(a,b) *((volatile uint32_t *) (a)) = (b)
-#define hs_write64(a,b) *((volatile uint32_t *) (a)) = (b)
-#define hs_read8(a) *((volatile uint8_t *) (a))
-#define hs_read16(a) *((volatile uint16_t *) (a))
-#define hs_read32(a) *((volatile uint32_t *) (a))
-#define hs_read64(a) *((volatile uint64_t *) (a))
+#ifdef CONFIG_MIPS64
 
-#else	/* not __long64 */
-
-typedef long hsaddr_t;
-
-extern void hs_write8(hsaddr_t a,uint8_t b);
-extern void hs_write16(hsaddr_t a,uint16_t b);
-extern void hs_write32(hsaddr_t a,uint32_t b);
-extern void hs_write64(hsaddr_t a,uint64_t b);
+static inline void hs_write8(hsaddr_t a, uint8_t b)
+{
+	*(volatile uint8_t *) a = PHYS_TO_XKSEG_UNCACHED(b);
+}
+
+static inline void hs_write16(hsaddr_t a, uint16_t b)
+{
+	*(volatile uint16_t *) a = PHYS_TO_XKSEG_UNCACHED(b);
+}
+
+static inline void hs_write32(hsaddr_t a, uint32_t b)
+{
+	*(volatile uint32_t *) a = PHYS_TO_XKSEG_UNCACHED(b);
+}
+
+static inline void hs_write64(hsaddr_t a, uint64_t b)
+{
+	*(volatile uint32_t *) a = PHYS_TO_XKSEG_UNCACHED(b);
+}
+
+static inline uint8_t hs_read8(hsaddr_t a)
+{
+	return *(volatile uint8_t *) a;
+}
+
+static inline uint16_t hs_read16(hsaddr_t a)
+{
+	return *(volatile uint16_t *) a;
+}
+
+static inline uint32_t hs_read32(hsaddr_t a)
+{
+	return *(volatile uint32_t *) a;
+}
+
+static inline uint64_t hs_read64(hsaddr_t a)
+{
+	return *(volatile uint64_t *) a;
+}
+
+#else	/* just CONFIG_MIPS32 */
+
+extern void hs_write8(hsaddr_t a, uint8_t b);
+extern void hs_write16(hsaddr_t a, uint16_t b);
+extern void hs_write32(hsaddr_t a, uint32_t b);
+extern void hs_write64(hsaddr_t a, uint64_t b);
 extern uint8_t hs_read8(hsaddr_t a);
 extern uint16_t hs_read16(hsaddr_t a);
 extern uint32_t hs_read32(hsaddr_t a);
 extern uint64_t hs_read64(hsaddr_t a);
 #endif
 
-#endif
+#endif /* _LIB_HSSUBR_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/sb1250/pci.c linux-2.4.20/arch/mips/sibyte/sb1250/pci.c
--- linux-2.4.19/arch/mips/sibyte/sb1250/pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/sb1250/pci.c	2002-10-29 11:18:33.000000000 +0000
@@ -10,20 +10,20 @@
  * 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.
  */
 
 /*
- * SB1250-specific PCI support
+ * BCM1250-specific PCI support
  *
  * This module provides the glue between Linux's PCI subsystem
  * and the hardware.  We basically provide glue for accessing
  * configuration space, and set up the translation for I/O
  * space accesses.
- * 
+ *
  * To access configuration space, we call some assembly-level
  * stubs that flip the KX bit on and off in the status
  * register, and do XKSEG addressed memory accesses there.
@@ -41,9 +41,11 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/mm.h>
+#include <linux/console.h>
 
 #include <asm/sibyte/sb1250_defs.h>
 #include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_scd.h>
 #include <asm/io.h>
 
 #include "lib_hssubr.h"
@@ -56,11 +58,8 @@
 #define CFGOFFSET(bus,devfn,where) (((bus)<<16)+((devfn)<<8)+(where))
 
 /*
- * Using the above offset, this macro calcuates the actual
- * address.  Note that the physical address is not accessible
- * without remapping or setting KX.  We use 'match bits'
- * as our endian policy to guarantee that 32-bit accesses
- * look the same from either endianness.
+ * Using the above offset, this macro calcuates the physical address in the
+ * config space.
  */
 #define CFGADDR(dev,where) (A_PHYS_LDTPCI_CFG_MATCH_BITS + \
 			    CFGOFFSET(dev->bus->number,dev->devfn,where))
@@ -68,17 +67,22 @@
 /*
  * Read/write 32-bit values in config space.
  */
+static inline u32 READCFG32(u32 addr)
+{
+	hs_read32(addr & ~3);
+}
 
-#define READCFG32(addr) hs_read32((addr)&~3)
-#define WRITECFG32(addr,data) hs_write32(((addr)&~3),(data))
+static inline void WRITECFG32(u32 addr, u32 data)
+{
+	return hs_write32(addr & ~3,(data));
+}
 
 /*
- * This variable is the KSEG2 (kernel virtual) mapping
- * of the ISA/PCI I/O space area.  We map 64K here and
- * the offsets from this address get treated with "match bytes" 
- * policy to make everything look little-endian.  So, 
- * you need to also set CONFIG_SWAP_IO_SPACE, but this is the 
- * combination that works correctly with most of Linux's drivers.
+ * This variable is the KSEG2 (kernel virtual) mapping of the ISA/PCI I/O
+ * space area.  We map 64K here and the offsets from this address get treated
+ * with "match bytes" policy to make everything look little-endian.  So, you
+ * need to also set CONFIG_SWAP_IO_SPACE, but this is the combination that
+ * works correctly with most of Linux's drivers.
  */
 
 #define PCI_BUS_ENABLED	1
@@ -153,7 +157,6 @@
 	if (where & 3)
 		return PCIBIOS_BAD_REGISTER_NUMBER;
 
-
 	data = READCFG32(cfgaddr);
 
 	/*
@@ -232,12 +235,14 @@
 void __init pcibios_init(void)
 {
 	uint32_t cmdreg;
+	uint64_t reg;
 
 	/*
 	 * See if the PCI bus has been configured by the firmware.
 	 */
 
-	cmdreg = READCFG32((A_PCI_TYPE00_HEADER | MATCH_BITS) + PCI_COMMAND);
+	cmdreg = READCFG32((A_PCI_TYPE00_HEADER | MATCH_BITS) +
+			   PCI_COMMAND);
 
 	if (!(cmdreg & PCI_COMMAND_MASTER)) {
 		printk
@@ -245,22 +250,31 @@
 		return;
 	}
 
+	reg = *((volatile uint64_t *) KSEG1ADDR(A_SCD_SYSTEM_CFG));
+	if (!(reg & M_SYS_PCI_HOST)) {
+		printk("PCI: Skipping PCI probe.  Processor is in PCI device mode.\n");
+		return;
+	}
+
 	sb1250_bus_status |= PCI_BUS_ENABLED;
 
-	/* 
-	 * Establish a mapping from KSEG2 (kernel virtual) to PCI I/O space 
+	/*
+	 * Establish a mapping from KSEG2 (kernel virtual) to PCI I/O space
 	 * Use "match bytes", even though this exposes endianness.
 	 * big-endian Linuxes will have CONFIG_SWAP_IO_SPACE set.
 	 */
 
 	set_io_port_base(ioremap(A_PHYS_LDTPCI_IO_MATCH_BYTES, 65536));
+	isa_slot_offset = (unsigned long)
+		ioremap(A_PHYS_LDTPCI_IO_MATCH_BYTES_32, 1024*1024);
 
 	/*
 	 * Also check the LDT bridge's enable, just in case we didn't
 	 * initialize that one.
 	 */
 
-	cmdreg = READCFG32((A_PCI_TYPE01_HEADER | MATCH_BITS) + PCI_COMMAND);
+	cmdreg = READCFG32((A_PCI_TYPE01_HEADER | MATCH_BITS) +
+			   PCI_COMMAND);
 
 	if (cmdreg & PCI_COMMAND_MASTER) {
 		sb1250_bus_status |= LDT_BUS_ENABLED;
@@ -271,6 +285,9 @@
 	printk("PCI: Probing PCI hardware on host bus 0.\n");
 	pci_scan_bus(0, &sb1250_pci_ops, NULL);
 
+#ifdef CONFIG_VGA_CONSOLE
+	take_over_console(&vga_con,0,MAX_NR_CONSOLES-1,1);
+#endif
 }
 
 int pcibios_enable_device(struct pci_dev *dev)
@@ -280,7 +297,7 @@
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-                            unsigned long size)
+		       unsigned long size, unsigned long align)
 {
 }
 
@@ -296,7 +313,7 @@
 };
 
 void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
-			struct resource *res, int resource)
+	struct resource *res, int resource)
 {
 	unsigned long where, size;
 	u32 reg;
@@ -312,7 +329,7 @@
  *  Called after each bus is probed, but before its children
  *  are examined.
  */
-void pcibios_fixup_bus(struct pci_bus *b)
+void __devinit pcibios_fixup_bus(struct pci_bus *b)
 {
 	pci_read_bridge_bases(b);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/sb1250/prom.c linux-2.4.20/arch/mips/sibyte/sb1250/prom.c
--- linux-2.4.19/arch/mips/sibyte/sb1250/prom.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/sb1250/prom.c	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2000, 2001 Broadcom Corporation
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/blk.h>
+#include <linux/bootmem.h>
+#include <linux/smp.h>
+
+#include <asm/bootinfo.h>
+#include <asm/reboot.h>
+
+extern char arcs_cmdline[];
+
+#ifdef CONFIG_EMBEDDED_RAMDISK
+/* These are symbols defined by the ramdisk linker script */
+extern unsigned char __rd_start;
+extern unsigned char __rd_end;
+#endif
+
+#define MAX_RAM_SIZE ((CONFIG_SIBYTE_STANDALONE_RAM_SIZE * 1024 * 1024) - 1)
+
+static __init void prom_meminit(void)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+	unsigned long initrd_pstart;
+	unsigned long initrd_pend;
+
+#ifdef CONFIG_EMBEDDED_RAMDISK
+	/* If we're using an embedded ramdisk, then __rd_start and __rd_end
+	   are defined by the linker to be on either side of the ramdisk
+	   area.  Otherwise, initrd_start should be defined by kernel command
+	   line arguments */
+	if (initrd_start == 0) {
+		initrd_start = (unsigned long)&__rd_start;
+		initrd_end = (unsigned long)&__rd_end;
+	}
+#endif
+
+	initrd_pstart = __pa(initrd_start);
+	initrd_pend = __pa(initrd_end);
+	if (initrd_start &&
+	    ((initrd_pstart > MAX_RAM_SIZE)
+	     || (initrd_pend > MAX_RAM_SIZE))) {
+		panic("initrd out of addressable memory");
+	}
+
+	add_memory_region(0, initrd_pstart,
+			  BOOT_MEM_RAM);
+	add_memory_region(initrd_pstart, initrd_pend - initrd_pstart,
+			  BOOT_MEM_RESERVED);
+	add_memory_region(initrd_pend,
+			  (CONFIG_SIBYTE_STANDALONE_RAM_SIZE * 1024 * 1024) - initrd_pend,
+			  BOOT_MEM_RAM);
+#else
+	add_memory_region(0, CONFIG_SIBYTE_STANDALONE_RAM_SIZE * 1024 * 1024,
+			  BOOT_MEM_RAM);
+#endif
+}
+
+void prom_cpu0_exit(void *unused)
+{
+        while (1) ;
+}
+
+static void prom_linux_exit(void)
+{
+#ifdef CONFIG_SMP
+	if (smp_processor_id()) {
+		smp_call_function(prom_cpu0_exit,NULL,1,1);
+	}
+#endif
+	while(1);
+}
+
+/*
+ * prom_init is called just after the cpu type is determined, from init_arch()
+ */
+__init int prom_init(int argc, char **argv, char **envp, int *prom_vec)
+{
+	_machine_restart   = (void (*)(char *))prom_linux_exit;
+	_machine_halt      = prom_linux_exit;
+	_machine_power_off = prom_linux_exit;
+
+	strcpy(arcs_cmdline, "root=/dev/ram0 ");
+
+	mips_machgroup = MACH_GROUP_SIBYTE;
+	prom_meminit();
+
+	return 0;
+}
+
+void prom_free_prom_memory(void)
+{
+	/* Not sure what I'm supposed to do here.  Nothing, I think */
+}
+
+int page_is_ram(unsigned long pagenr)
+{
+	phys_t addr = pagenr << PAGE_SHIFT;
+	return (addr < (CONFIG_SIBYTE_STANDALONE_RAM_SIZE * 1024 * 1024));
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/sb1250/setup.c linux-2.4.20/arch/mips/sibyte/sb1250/setup.c
--- linux-2.4.19/arch/mips/sibyte/sb1250/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/sb1250/setup.c	2002-10-29 11:18:39.000000000 +0000
@@ -10,58 +10,45 @@
  * 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.
  */
 
-/* Setup code likely to be common to all SB1250 platforms */
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/hdreg.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/utsname.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/bootmem.h>
-#ifdef CONFIG_BLK_DEV_RAM
-#include <linux/blk.h>
-#endif
-#include <linux/ide.h>
-#ifdef CONFIG_RTC
-#include <linux/timex.h>
-#endif
-
-#include <asm/asm.h>
-#include <asm/bootinfo.h>
-#include <asm/cachectl.h>
-#include <asm/cpu.h>
-#include <asm/io.h>
-#include <asm/stackframe.h>
-#include <asm/system.h>
-#include <asm/cpu.h>
-#include <asm/mmu_context.h>
-#include <asm/sibyte/swarm.h>
-#include <asm/sibyte/sb1250_defs.h>
+#include <asm/sibyte/sb1250.h>
 #include <asm/sibyte/sb1250_regs.h>
- 
+#include <asm/sibyte/sb1250_scd.h>
+#include <asm/sibyte/64bit.h>
 
-/* 
- *
- */
+/* Setup code likely to be common to all BCM1250 platforms */
 
+unsigned int sb1250_pass;
 
 void sb1250_setup(void)
 {
+	int bad_config = 0;
+
+	sb1250_pass = G_SYS_REVISION(in64(IO_SPACE_BASE | A_SCD_SYSTEM_REVISION));
+	/* sb1250_pass is more specific than "1", "2" etc.  There are
+           many revision numbers corresponding to "Pass 2". */
+	switch(sb1250_pass) {
+	case 1:
+#ifndef CONFIG_SB1_PASS_1_WORKAROUNDS
+		printk("@@@@ This is a pass 1 board, and the kernel doesn't have the proper workarounds compiled in. @@@@");
+		bad_config = 1;
+#endif
+		break;
+	default:
+#if defined(CONFIG_CPU_HAS_PREFETCH) || !defined(CONFIG_SB1_PASS_2_WORKAROUNDS)
+		printk("@@@@ This is a pass 2 board, and the kernel doesn't have the proper workarounds compiled in. @@@@");
+		printk("@@@@ Prefetches are enabled in this kernel, but are buggy on this board.  @@@@");
+		bad_config = 1;
+#endif
+		break;
+	}
+	/* XXXKW this is too early for panic/printk to actually do much! */
+	if (bad_config) {
+		panic("Invalid configuration for this pass.");
+	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/sb1250/smp.c linux-2.4.20/arch/mips/sibyte/sb1250/smp.c
--- linux-2.4.19/arch/mips/sibyte/sb1250/smp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/sb1250/smp.c	2002-10-29 11:18:40.000000000 +0000
@@ -10,18 +10,24 @@
  * 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.
  */
 
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/mmu_context.h>
 #include <asm/sibyte/64bit.h>
 #include <asm/sibyte/sb1250.h>
 #include <asm/sibyte/sb1250_regs.h>
-#include <asm/addrspace.h>
-#include <asm/smp.h>
-#include <linux/sched.h>
+#include <asm/sibyte/sb1250_int.h>
+
+extern void smp_call_function_interrupt(void);
 
 /*
  * These are routines for dealing with the sb1250 smp capabilities
@@ -29,17 +35,17 @@
  */
 
 static u64 mailbox_set_regs[] = {
-	KSEG1 + A_IMR_CPU0_BASE + R_IMR_MAILBOX_SET_CPU, 
+	KSEG1 + A_IMR_CPU0_BASE + R_IMR_MAILBOX_SET_CPU,
 	KSEG1 + A_IMR_CPU1_BASE + R_IMR_MAILBOX_SET_CPU
 };
 
 static u64 mailbox_clear_regs[] = {
-	KSEG1 + A_IMR_CPU0_BASE + R_IMR_MAILBOX_CLR_CPU, 
+	KSEG1 + A_IMR_CPU0_BASE + R_IMR_MAILBOX_CLR_CPU,
 	KSEG1 + A_IMR_CPU1_BASE + R_IMR_MAILBOX_CLR_CPU
 };
 
 static u64 mailbox_regs[] = {
-	KSEG1 + A_IMR_CPU0_BASE + R_IMR_MAILBOX_CPU, 
+	KSEG1 + A_IMR_CPU0_BASE + R_IMR_MAILBOX_CPU,
 	KSEG1 + A_IMR_CPU1_BASE + R_IMR_MAILBOX_CPU
 };
 
@@ -66,7 +72,8 @@
 {
 	int cpu = smp_processor_id();
 	unsigned int action;
-	
+
+	kstat.irqs[cpu][K_INT_MBOX_0]++;
 	/* Load the mailbox register to figure out what we're supposed to do */
 	action = (in64(mailbox_regs[cpu]) >> 48) & 0xffff;
 
@@ -82,3 +89,68 @@
 		smp_call_function_interrupt();
 	}
 }
+
+extern atomic_t cpus_booted;
+extern int prom_setup_smp(void);
+extern int prom_boot_secondary(int cpu, unsigned long sp, unsigned long gp);
+
+void __init smp_boot_cpus(void)
+{
+	int i;
+	int cur_cpu = 0;
+
+	smp_num_cpus = prom_setup_smp();
+	init_new_context(current, &init_mm);
+	current->processor = 0;
+	cpu_data[0].udelay_val = loops_per_jiffy;
+	cpu_data[0].asid_cache = ASID_FIRST_VERSION;
+	CPUMASK_CLRALL(cpu_online_map);
+	CPUMASK_SETB(cpu_online_map, 0);
+	atomic_set(&cpus_booted, 1);  /* Master CPU is already booted... */
+	init_idle();
+
+	/*
+	 * This loop attempts to compensate for "holes" in the CPU
+	 * numbering.  It's overkill, but general.
+	 */
+	for (i = 1; i < smp_num_cpus; ) {
+		struct task_struct *p;
+		struct pt_regs regs;
+		int retval;
+		printk("Starting CPU %d... ", i);
+
+		/* Spawn a new process normally.  Grab a pointer to
+		   its task struct so we can mess with it */
+		do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0);
+		p = init_task.prev_task;
+
+		/* Schedule the first task manually */
+		p->processor = i;
+		p->cpus_runnable = 1 << i; /* we schedule the first task manually */
+
+		/* Attach to the address space of init_task. */
+		atomic_inc(&init_mm.mm_count);
+		p->active_mm = &init_mm;
+		init_tasks[i] = p;
+
+		del_from_runqueue(p);
+		unhash_process(p);
+
+		do {
+			/* Iterate until we find a CPU that comes up */
+			cur_cpu++;
+			retval = prom_boot_secondary(cur_cpu,
+					    (unsigned long)p + KERNEL_STACK_SIZE - 32,
+					    (unsigned long)p);
+		} while (!retval && (cur_cpu < NR_CPUS));
+		if (retval) {
+			i++;
+		} else {
+			panic("CPU discovery disaster");
+		}
+	}
+
+	/* Wait for everyone to come up */
+	while (atomic_read(&cpus_booted) != smp_num_cpus);
+	smp_threads_ready = 1;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/sb1250/time.c linux-2.4.20/arch/mips/sibyte/sb1250/time.c
--- linux-2.4.19/arch/mips/sibyte/sb1250/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/sb1250/time.c	2002-10-29 11:18:35.000000000 +0000
@@ -10,17 +10,17 @@
  * 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.
  */
 
-/* 
+/*
  * These are routines to set up and handle interrupts from the
  * sb1250 general purpose timer 0.  We're using the timer as a
  * system clock, so we set it up to run at 100 Hz.  On every
- * interrupt, we update our idea of what the time of day is, 
+ * interrupt, we update our idea of what the time of day is,
  * then call do_timer() in the architecture-independent kernel
  * code to do general bookkeeping (e.g. update jiffies, run
  * bottom halves, etc.)
@@ -29,6 +29,7 @@
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
+#include <linux/kernel_stat.h>
 
 #include <asm/irq.h>
 #include <asm/ptrace.h>
@@ -46,6 +47,8 @@
 #define IMR_IP3_VAL	K_INT_MAP_I1
 #define IMR_IP4_VAL	K_INT_MAP_I2
 
+extern int sb1250_steal_irq(int irq);
+
 void sb1250_time_init(void)
 {
 	int cpu = smp_processor_id();
@@ -55,11 +58,16 @@
 		BUG();
 	}
 
+	if (!cpu) {
+		/* Use our own gettimeoffset() routine */
+		do_gettimeoffset = sb1250_gettimeoffset;
+	}
+
 	sb1250_mask_irq(cpu, K_INT_TIMER_0 + cpu);
-	
+
 	/* Map the timer interrupt to ip[4] of this cpu */
-	out64(IMR_IP4_VAL, KSEG1 + A_IMR_REGISTER(cpu, R_IMR_INTERRUPT_MAP_BASE) 
-	      + ((K_INT_TIMER_0 + cpu)<<3)); 
+	out64(IMR_IP4_VAL, KSEG1 + A_IMR_REGISTER(cpu, R_IMR_INTERRUPT_MAP_BASE)
+	      + ((K_INT_TIMER_0 + cpu)<<3));
 
 	/* the general purpose timer ticks at 1 Mhz independent if the rest of the system */
 	/* Disable the timer and set up the count */
@@ -77,6 +85,7 @@
 	      KSEG1 + A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
 
 	sb1250_unmask_irq(cpu, K_INT_TIMER_0 + cpu);
+	sb1250_steal_irq(K_INT_TIMER_0 + cpu);
 	/*
 	 * This interrupt is "special" in that it doesn't use the request_irq
 	 * way to hook the irq line.  The timer interrupt is initialized early
@@ -91,9 +100,10 @@
 {
 	int cpu = smp_processor_id();
 
+	kstat.irqs[cpu][K_INT_TIMER_0+cpu]++;
 	/* Reset the timer */
 	out64(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS,
-	      KSEG1 + A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));  
+	      KSEG1 + A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
 
 	/*
 	 * CPU 0 handles the global timer interrupt job
@@ -107,3 +117,17 @@
 	 */
 	ll_local_timer_interrupt(0, regs);
 }
+
+/*
+ * We use our own do_gettimeoffset() instead of the generic one,
+ * because the generic one does not work for SMP case.
+ * In addition, since we use general timer 0 for system time,
+ * we can get accurate intra-jiffy offset without calibration.
+ */
+unsigned long sb1250_gettimeoffset(void)
+{
+	unsigned long count =
+		in64(KSEG1 + A_SCD_TIMER_REGISTER(0, R_SCD_TIMER_CNT));
+
+	return 1000000/HZ - count;
+ }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/swarm/Makefile linux-2.4.20/arch/mips/sibyte/swarm/Makefile
--- linux-2.4.19/arch/mips/sibyte/swarm/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/swarm/Makefile	2002-10-29 11:18:32.000000000 +0000
@@ -2,9 +2,7 @@
 
 all: sbswarm.a
 
-OBJS-y                   = setup.o cmdline.o memory.o cfe_api.o rtc_xicor1241.o
-
-OBJS-$(CONFIG_SMP)      += smp.o
+OBJS-y                   = setup.o cmdline.o rtc_xicor1241.o
 
 OBJS-$(CONFIG_L3DEMO)   += procl3switch.o l3procbootstrap.o l3proc.o
 OBJS-$(CONFIG_REMOTE_DEBUG) += dbg_io.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/swarm/cfe_api.c linux-2.4.20/arch/mips/sibyte/swarm/cfe_api.c
--- linux-2.4.19/arch/mips/sibyte/swarm/cfe_api.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/swarm/cfe_api.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,402 +0,0 @@
-/*
- * Copyright (C) 2000, 2001 Broadcom Corporation
- *
- * 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.
- */
-
-/*  *********************************************************************
-    *  Broadcom Common Firmware Environment (CFE)
-    *  
-    *  Device Function stubs			File: cfe_api.c
-    *  
-    *  This module contains device function stubs (small routines to
-    *  call the standard "iocb" interface entry point to CFE).
-    *  There should be one routine here per iocb function call.
-    *  
-    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
-    *  
-    ********************************************************************* */
-
-
-#include "cfe_xiocb.h"
-#include "cfe_api.h"
-#include <linux/string.h>
-
-static long cfe_console_handle = -1;
-static int (*cfe_dispfunc)(long handle,cfe_xiocb_t *xiocb) = 0;
-static cfe_xuint_t cfe_handle = 0;
-
-/*
- * This macro makes a "signed 64-bit pointer" - basically extending a regular
- * pointer to its 64-bit compatibility space equivalent. 
- */
-#define BIGPTR(x) (long long) (long) (x)
-
-typedef unsigned long intptr_t;
-
-int cfe_init(cfe_xuint_t handle)
-{
-	unsigned int *sealloc = (unsigned int *) (intptr_t) (int)  CFE_APISEAL;
-	if (*sealloc != CFE_EPTSEAL) return -1;
-	cfe_dispfunc = (void *) (cfe_xptr_t) (int) CFE_APIENTRY;
-	if (handle) cfe_handle = handle;
-	return 0;
-}
-
-int cfe_iocb_dispatch(cfe_xiocb_t *xiocb);
-int cfe_iocb_dispatch(cfe_xiocb_t *xiocb)
-{
-	if (!cfe_dispfunc) return -1;
-	return (*cfe_dispfunc)(cfe_handle,xiocb);
-}
-
-static int cfe_strlen(char *name)
-{
-	int count = 0;
-	
-	while (*name) {
-		count++;
-		name++;
-	}
-	
-	return count;
-}
-
-int cfe_open(char *name)
-{
-	cfe_xiocb_t xiocb;
-	
-	xiocb.xiocb_fcode = CFE_CMD_DEV_OPEN;
-	xiocb.xiocb_status = 0;
-	xiocb.xiocb_handle = 0;
-	xiocb.xiocb_flags = 0;
-	xiocb.xiocb_psize = sizeof(xiocb_buffer_t);
-	xiocb.plist.xiocb_buffer.buf_offset = 0;
-	xiocb.plist.xiocb_buffer.buf_ptr = BIGPTR(name);
-	xiocb.plist.xiocb_buffer.buf_length = cfe_strlen(name);
-	
-	cfe_iocb_dispatch(&xiocb);
-	
-	return (xiocb.xiocb_status < 0) ? xiocb.xiocb_status : xiocb.xiocb_handle;
-}
-
-int cfe_close(int handle)
-{
-	cfe_xiocb_t xiocb;
-	
-	xiocb.xiocb_fcode = CFE_CMD_DEV_CLOSE;
-	xiocb.xiocb_status = 0;
-	xiocb.xiocb_handle = handle;
-	xiocb.xiocb_flags = 0;
-	xiocb.xiocb_psize = 0;
-	
-	cfe_iocb_dispatch(&xiocb);
-	
-	return (xiocb.xiocb_status);
-	
-}
-
-int cfe_readblk(int handle,cfe_xint_t offset,unsigned char *buffer,int length)
-{
-	cfe_xiocb_t xiocb;
-	
-	xiocb.xiocb_fcode = CFE_CMD_DEV_READ;
-	xiocb.xiocb_status = 0;
-	xiocb.xiocb_handle = handle;
-	xiocb.xiocb_flags = 0;
-	xiocb.xiocb_psize = sizeof(xiocb_buffer_t);
-	xiocb.plist.xiocb_buffer.buf_offset = offset;
-	xiocb.plist.xiocb_buffer.buf_ptr = BIGPTR(buffer);
-	xiocb.plist.xiocb_buffer.buf_length = length;
-	
-	cfe_iocb_dispatch(&xiocb);
-	
-	return (xiocb.xiocb_status < 0) ? xiocb.xiocb_status : xiocb.plist.xiocb_buffer.buf_retlen;
-}
-
-int cfe_read(int handle,unsigned char *buffer,int length)
-{
-	return cfe_readblk(handle,0,buffer,length);
-}
-
-
-int cfe_writeblk(int handle,cfe_xint_t offset,unsigned char *buffer,int length)
-{
-	cfe_xiocb_t xiocb;
-	
-	xiocb.xiocb_fcode = CFE_CMD_DEV_WRITE;
-	xiocb.xiocb_status = 0;
-	xiocb.xiocb_handle = handle;
-	xiocb.xiocb_flags = 0;
-	xiocb.xiocb_psize = sizeof(xiocb_buffer_t);
-	xiocb.plist.xiocb_buffer.buf_offset = offset;
-	xiocb.plist.xiocb_buffer.buf_ptr = BIGPTR(buffer);
-	xiocb.plist.xiocb_buffer.buf_length = length;
-	
-	cfe_iocb_dispatch(&xiocb);
-	
-	return (xiocb.xiocb_status < 0) ? xiocb.xiocb_status : xiocb.plist.xiocb_buffer.buf_retlen;
-}
-
-int cfe_write(int handle,unsigned char *buffer,int length)
-{
-	return cfe_writeblk(handle,0,buffer,length);
-}
-
-
-int cfe_ioctl(int handle,unsigned int ioctlnum,unsigned char *buffer,int length,int *retlen)
-{
-	cfe_xiocb_t xiocb;
-	
-	xiocb.xiocb_fcode = CFE_CMD_DEV_IOCTL;
-	xiocb.xiocb_status = 0;
-	xiocb.xiocb_handle = handle;
-	xiocb.xiocb_flags = 0;
-	xiocb.xiocb_psize = sizeof(xiocb_buffer_t);
-	xiocb.plist.xiocb_buffer.buf_ioctlcmd = (cfe_xint_t) ioctlnum;
-	xiocb.plist.xiocb_buffer.buf_ptr = BIGPTR(buffer);
-	xiocb.plist.xiocb_buffer.buf_length = length;
-	
-	cfe_iocb_dispatch(&xiocb);
-	
-	if (retlen) *retlen = xiocb.plist.xiocb_buffer.buf_retlen;
-	return xiocb.xiocb_status;
-}
-
-int cfe_inpstat(int handle)
-{
-	cfe_xiocb_t xiocb;
-	
-	xiocb.xiocb_fcode = CFE_CMD_DEV_INPSTAT;
-	xiocb.xiocb_status = 0;
-	xiocb.xiocb_handle = handle;
-	xiocb.xiocb_flags = 0;
-	xiocb.xiocb_psize = sizeof(xiocb_inpstat_t);
-	xiocb.plist.xiocb_inpstat.inp_status = 0;
-	
-	cfe_iocb_dispatch(&xiocb);
-	
-	if (xiocb.xiocb_status < 0) return xiocb.xiocb_status;
-	
-	return xiocb.plist.xiocb_inpstat.inp_status;
-	
-}
-
-long long cfe_getticks(void)
-{
-	cfe_xiocb_t xiocb;
-	
-	xiocb.xiocb_fcode = CFE_CMD_FW_GETTIME;
-	xiocb.xiocb_status = 0;
-	xiocb.xiocb_handle = 0;
-	xiocb.xiocb_flags = 0;
-	xiocb.xiocb_psize = sizeof(xiocb_time_t);
-	xiocb.plist.xiocb_time.ticks = 0;
-	
-	cfe_iocb_dispatch(&xiocb);
-	
-	return xiocb.plist.xiocb_time.ticks;
-	
-}
-
-int cfe_getenv(char *name,char *dest,int destlen)
-{
-	cfe_xiocb_t xiocb;
-	
-	*dest = 0;
-	
-	xiocb.xiocb_fcode = CFE_CMD_ENV_GET;
-	xiocb.xiocb_status = 0;
-	xiocb.xiocb_handle = 0;
-	xiocb.xiocb_flags = 0;
-	xiocb.xiocb_psize = sizeof(xiocb_envbuf_t);
-	xiocb.plist.xiocb_envbuf.enum_idx = 0;
-	xiocb.plist.xiocb_envbuf.name_ptr = BIGPTR(name);
-	xiocb.plist.xiocb_envbuf.name_length = cfe_strlen(name);
-	xiocb.plist.xiocb_envbuf.val_ptr = BIGPTR(dest);
-	xiocb.plist.xiocb_envbuf.val_length = destlen;
-	
-	cfe_iocb_dispatch(&xiocb);
-	
-	return xiocb.xiocb_status;
-}
-
-int cfe_setenv(char *name,char *val)
-{
-	cfe_xiocb_t xiocb;
-	
-	xiocb.xiocb_fcode = CFE_CMD_ENV_SET;
-	xiocb.xiocb_status = 0;
-	xiocb.xiocb_handle = 0;
-	xiocb.xiocb_flags = 0;
-	xiocb.xiocb_psize = sizeof(xiocb_envbuf_t);
-	xiocb.plist.xiocb_envbuf.enum_idx = 0;
-	xiocb.plist.xiocb_envbuf.name_ptr = BIGPTR(name);
-	xiocb.plist.xiocb_envbuf.name_length = cfe_strlen(name);
-	xiocb.plist.xiocb_envbuf.val_ptr = BIGPTR(val);
-	xiocb.plist.xiocb_envbuf.val_length = cfe_strlen(val);
-	
-	cfe_iocb_dispatch(&xiocb);
-	
-	return xiocb.xiocb_status;
-}
-
-int cfe_enummem(long idx, unsigned long long *addr, unsigned long long *size, long *type)
-{
-	cfe_xiocb_t xiocb;
-	xiocb.xiocb_fcode = CFE_CMD_FW_MEMENUM;
-	xiocb.xiocb_status = 0;
-	xiocb.xiocb_handle = 0;
-	xiocb.xiocb_flags = 0;
-	xiocb.xiocb_psize = sizeof(xiocb_meminfo_t);
-	xiocb.plist.xiocb_meminfo.mi_idx = idx;
-	
-	cfe_iocb_dispatch(&xiocb);
-	
-	(*addr) = xiocb.plist.xiocb_meminfo.mi_addr;
-	(*size) = xiocb.plist.xiocb_meminfo.mi_size;
-	(*type) = xiocb.plist.xiocb_meminfo.mi_type;
-
-	return xiocb.xiocb_status;
-}
-
-
-int cfe_enumenv(int idx,char *name,int namelen,char *val,int vallen)
-{
-	cfe_xiocb_t xiocb;
-	
-	xiocb.xiocb_fcode = CFE_CMD_ENV_SET;
-	xiocb.xiocb_status = 0;
-	xiocb.xiocb_handle = 0;
-	xiocb.xiocb_flags = 0;
-	xiocb.xiocb_psize = sizeof(xiocb_envbuf_t);
-	xiocb.plist.xiocb_envbuf.enum_idx = idx;
-	xiocb.plist.xiocb_envbuf.name_ptr = BIGPTR(name);
-	xiocb.plist.xiocb_envbuf.name_length = namelen;
-	xiocb.plist.xiocb_envbuf.val_ptr = BIGPTR(val);
-	xiocb.plist.xiocb_envbuf.val_length = vallen;
-	
-	cfe_iocb_dispatch(&xiocb);
-	
-	return xiocb.xiocb_status;
-}
-
-int cfe_exit(int warm, int status)
-{
-	cfe_xiocb_t xiocb;
-	
-	xiocb.xiocb_fcode = CFE_CMD_FW_RESTART;
-	xiocb.xiocb_status = 0;
-	xiocb.xiocb_handle = 0;
-	xiocb.xiocb_flags = warm ? CFE_FLG_WARMSTART : 0;
-	xiocb.xiocb_psize = sizeof(xiocb_exitstat_t);
-	xiocb.plist.xiocb_exitstat.status = (cfe_xint_t) status;
-	
-	cfe_iocb_dispatch(&xiocb);
-	
-	return (xiocb.xiocb_status);
-}
-
-int cfe_flushcache(int flg)
-{
-	cfe_xiocb_t xiocb;
-	
-	xiocb.xiocb_fcode = CFE_CMD_FW_FLUSHCACHE;
-	xiocb.xiocb_status = 0;
-	xiocb.xiocb_handle = 0;
-	xiocb.xiocb_flags = flg;
-	xiocb.xiocb_psize = 0;
-	
-	cfe_iocb_dispatch(&xiocb);
-	
-	return xiocb.xiocb_status;
-}
-
-int cfe_getstdhandle(int flg)
-{
-	cfe_xiocb_t xiocb;
-	
-	xiocb.xiocb_fcode = CFE_CMD_DEV_GETHANDLE;
-	xiocb.xiocb_status = 0;
-	xiocb.xiocb_handle = 0;
-	xiocb.xiocb_flags = flg;
-	xiocb.xiocb_psize = 0;
-	
-	cfe_iocb_dispatch(&xiocb);
-	
-	return (xiocb.xiocb_status < 0) ? xiocb.xiocb_status : xiocb.xiocb_handle;
-	
-}
-
-int cfe_start_cpu(int cpu, void (*fn)(void), long sp, long gp, long a1)
-{
-	cfe_xiocb_t xiocb;
-	
-	xiocb.xiocb_fcode = CFE_CMD_FW_CPUCTL;
-	xiocb.xiocb_status = 0;
-	xiocb.xiocb_handle = 0;
-	xiocb.xiocb_flags  = 0;
-	xiocb.xiocb_psize = sizeof(xiocb_cpuctl_t);
-	xiocb.plist.xiocb_cpuctl.cpu_number = cpu;
-	xiocb.plist.xiocb_cpuctl.cpu_command = CFE_CPU_CMD_START;
-	xiocb.plist.xiocb_cpuctl.gp_val = gp;
-	xiocb.plist.xiocb_cpuctl.sp_val = sp;
-	xiocb.plist.xiocb_cpuctl.a1_val = a1;
-	xiocb.plist.xiocb_cpuctl.start_addr = (long)fn;
-	
-	cfe_iocb_dispatch(&xiocb);
-	
-	return xiocb.xiocb_status;
-}
-
-
-int cfe_stop_cpu(int cpu)
-{
-	cfe_xiocb_t xiocb;
-	
-	xiocb.xiocb_fcode = CFE_CMD_FW_CPUCTL;
-	xiocb.xiocb_status = 0;
-	xiocb.xiocb_handle = 0;
-	xiocb.xiocb_flags  = 0;
-	xiocb.xiocb_psize = sizeof(xiocb_cpuctl_t);
-	xiocb.plist.xiocb_cpuctl.cpu_number = cpu;
-	xiocb.plist.xiocb_cpuctl.cpu_command = CFE_CPU_CMD_STOP;
-	
-	cfe_iocb_dispatch(&xiocb);
-	
-	return xiocb.xiocb_status;
-}
-
-void cfe_open_console()
-{
-	cfe_console_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
-}
-
-void cfe_console_print(char *str)
-{
-	int len = strlen(str);
-	int res;
-
-	if (cfe_console_handle != -1) {
-		do {
-			res = cfe_writeblk(cfe_console_handle, 0, str, len);
-			if (res < 0)
-				break;
-			str += res;
-			len -= res;
-		} while (len);
-	}
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/swarm/cfe_api.h linux-2.4.20/arch/mips/sibyte/swarm/cfe_api.h
--- linux-2.4.19/arch/mips/sibyte/swarm/cfe_api.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/swarm/cfe_api.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2000, 2001 Broadcom Corporation
- *
- * 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.
- */
-
-/*  *********************************************************************
-    *  Broadcom Common Firmware Environment (CFE)
-    *  
-    *  Device function prototypes		File: cfe_api.h
-    *  
-    *  This module contains prototypes for cfe_devfuncs.c, a set
-    *  of wrapper routines to the IOCB interface.  This file,
-    *  along with cfe_api.c, can be incorporated into programs
-    *  that need to call CFE.
-    *  
-    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
-    *  
-    ********************************************************************* */
-
-
-#define CFE_EPTSEAL 0x43464531
-#define CFE_APIENTRY 0x9FC00500
-#define CFE_APISEAL  0x9FC00508
-
-#ifndef __ASSEMBLY__
-int cfe_init(cfe_xuint_t handle);
-int cfe_open(char *name);
-int cfe_close(int handle);
-int cfe_readblk(int handle,cfe_xint_t offset,unsigned char *buffer,int length);
-int cfe_read(int handle,unsigned char *buffer,int length);
-int cfe_writeblk(int handle,cfe_xint_t offset,unsigned char *buffer,int length);
-int cfe_write(int handle,unsigned char *buffer,int length);
-int cfe_ioctl(int handle,unsigned int ioctlnum,unsigned char *buffer,int length,int *retlen);
-int cfe_inpstat(int handle);
-int cfe_enumenv(int idx,char *name,int namelen,char *val,int vallen);
-int cfe_enummem(long idx, unsigned long long *addr, unsigned long long *size, long *type);
-int cfe_setenv(char *name,char *val);
-int cfe_getenv(char *name,char *dest,int destlen);
-long long cfe_getticks(void);
-int cfe_exit(int warm, int status);
-int cfe_flushcache(int flg);
-int cfe_getstdhandle(int flg);
-int cfe_start_cpu(int cpu, void (*fn)(void), long sp, long gp, long a1);
-int cfe_stop_cpu(int cpu);
-
-void cfe_open_console(void);
-void cfe_console_print(char *);
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/swarm/cfe_error.h linux-2.4.20/arch/mips/sibyte/swarm/cfe_error.h
--- linux-2.4.19/arch/mips/sibyte/swarm/cfe_error.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/swarm/cfe_error.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2000, 2001 Broadcom Corporation
- *
- * 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.
- */
-
-/*  *********************************************************************
-    *  Broadcom Common Firmware Environment (CFE)
-    *  
-    *  Error codes				File: cfe_error.h
-    *  
-    *  CFE's global error code list is here.
-    *  
-    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
-    *  
-    ********************************************************************* */
-
-
-
-
-#define CFE_OK			 0
-#define CFE_ERR                 -1	/* generic error */
-#define CFE_ERR_INV_COMMAND	-2
-#define CFE_ERR_EOF		-3
-#define CFE_ERR_IOERR		-4
-#define CFE_ERR_NOMEM		-5
-#define CFE_ERR_DEVNOTFOUND	-6
-#define CFE_ERR_DEVOPEN		-7
-#define CFE_ERR_INV_PARAM	-8
-#define CFE_ERR_ENVNOTFOUND	-9
-#define CFE_ERR_ENVREADONLY	-10
-
-#define CFE_ERR_NOTELF		-11
-#define CFE_ERR_NOT32BIT 	-12
-#define CFE_ERR_WRONGENDIAN 	-13
-#define CFE_ERR_BADELFVERS 	-14
-#define CFE_ERR_NOTMIPS 	-15
-#define CFE_ERR_BADELFFMT 	-16
-#define CFE_ERR_BADADDR 	-17
-
-#define CFE_ERR_FILENOTFOUND	-18
-#define CFE_ERR_UNSUPPORTED	-19
-
-#define CFE_ERR_HOSTUNKNOWN	-20
-
-#define CFE_ERR_TIMEOUT		-21
-
-#define CFE_ERR_PROTOCOLERR	-22
-
-#define CFE_ERR_NETDOWN		-23
-#define CFE_ERR_NONAMESERVER	-24
-
-#define CFE_ERR_NOHANDLES	-25
-#define CFE_ERR_ALREADYBOUND	-26
-
-#define CFE_ERR_CANNOTSET	-27
-#define CFE_ERR_NOMORE		-28
-#define CFE_ERR_BADFILESYS	-29
-#define CFE_ERR_FSNOTAVAIL	-30
-
-#define CFE_ERR_INVBOOTBLOCK	-31
-#define CFE_ERR_WRONGDEVTYPE	-32
-#define CFE_ERR_BBCHECKSUM	-33
-#define CFE_ERR_BOOTPROGCHKSUM	-34
-
-
-
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/swarm/cfe_xiocb.h linux-2.4.20/arch/mips/sibyte/swarm/cfe_xiocb.h
--- linux-2.4.19/arch/mips/sibyte/swarm/cfe_xiocb.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/swarm/cfe_xiocb.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2000, 2001 Broadcom Corporation
- *
- * 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.
- */
-
-/*  *********************************************************************
-    *  Broadcom Common Firmware Environment (CFE)
-    *  
-    *  IOCB definitions				File: cfe_iocb.h
-    *  
-    *  This module describes CFE's IOCB structure, the main
-    *  data structure used to communicate API requests with CFE.
-    *  
-    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
-    *  
-    ********************************************************************* */
-
-/*  *********************************************************************
-    *  Constants
-    ********************************************************************* */
-
-#define CFE_CMD_FW_GETINFO	0
-#define CFE_CMD_FW_RESTART	1
-#define CFE_CMD_FW_BOOT		2
-#define CFE_CMD_FW_CPUCTL	3
-#define CFE_CMD_FW_GETTIME      4
-#define CFE_CMD_FW_MEMENUM	5
-#define CFE_CMD_FW_FLUSHCACHE	6
-
-#define CFE_CMD_DEV_GETHANDLE	9
-#define CFE_CMD_DEV_ENUM	10
-#define CFE_CMD_DEV_OPEN	11
-#define CFE_CMD_DEV_INPSTAT	12
-#define CFE_CMD_DEV_READ	13
-#define CFE_CMD_DEV_WRITE	14
-#define CFE_CMD_DEV_IOCTL	15
-#define CFE_CMD_DEV_CLOSE	16
-#define CFE_CMD_DEV_GETINFO	17
-
-#define CFE_CMD_ENV_ENUM	20
-#define CFE_CMD_ENV_GET		22
-#define CFE_CMD_ENV_SET		23
-#define CFE_CMD_ENV_DEL		24
-
-#define CFE_CMD_MAX		32
-
-#define CFE_MI_RESERVED	0		/* memory is reserved, do not use */
-#define CFE_MI_AVAILABLE 1		/* memory is available */
-
-#define CFE_FLG_WARMSTART 0x00000001
-
-#define CFE_FLG_ENV_PERMANENT 0x00000001
-
-#define CFE_CPU_CMD_START 1
-#define CFE_CPU_CMD_STOP 0
-
-#define CFE_STDHANDLE_CONSOLE	0
-
-#define CFE_DEV_NETWORK 	1
-#define CFE_DEV_DISK		2
-#define CFE_DEV_FLASH		3
-#define CFE_DEV_SERIAL		4
-#define CFE_DEV_CPU		5
-#define CFE_DEV_NVRAM		6
-#define CFE_DEV_OTHER		7
-#define CFE_DEV_MASK		0x0F
-
-#define CFE_CACHE_FLUSH_D	1
-#define CFE_CACHE_INVAL_I	2
-#define CFE_CACHE_INVAL_D	4
-#define CFE_CACHE_INVAL_L2	8
-
-/*  *********************************************************************
-    *  Structures
-    ********************************************************************* */
-
-typedef unsigned long long cfe_xuint_t;
-typedef long long cfe_xint_t;
-typedef long long cfe_xptr_t;
-
-typedef struct xiocb_buffer_s {
-    cfe_xuint_t   buf_offset;		/* offset on device (bytes) */
-    cfe_xptr_t 	  buf_ptr;		/* pointer to a buffer */
-    cfe_xuint_t   buf_length;		/* length of this buffer */
-    cfe_xuint_t   buf_retlen;		/* returned length (for read ops) */
-    cfe_xuint_t   buf_ioctlcmd;		/* IOCTL command (used only for IOCTLs) */
-} xiocb_buffer_t;
-
-#define buf_devflags buf_ioctlcmd	/* returned device info flags */
-
-typedef struct xiocb_inpstat_s {
-    cfe_xuint_t inp_status;		/* 1 means input available */
-} xiocb_inpstat_t;
-
-typedef struct xiocb_envbuf_s {
-    cfe_xint_t enum_idx;		/* 0-based enumeration index */
-    cfe_xptr_t name_ptr;		/* name string buffer */
-    cfe_xint_t name_length;		/* size of name buffer */
-    cfe_xptr_t val_ptr;			/* value string buffer */
-    cfe_xint_t val_length;		/* size of value string buffer */
-} xiocb_envbuf_t;
-
-typedef struct xiocb_cpuctl_s {
-    cfe_xuint_t  cpu_number;		/* cpu number to control */
-    cfe_xuint_t  cpu_command;		/* command to issue to CPU */
-    cfe_xuint_t  start_addr;		/* CPU start address */
-    cfe_xuint_t  gp_val;		/* starting GP value */
-    cfe_xuint_t  sp_val;		/* starting SP value */
-    cfe_xuint_t  a1_val;		/* starting A1 value */
-} xiocb_cpuctl_t;
-
-typedef struct xiocb_time_s {
-    cfe_xint_t ticks;			/* current time in ticks */
-} xiocb_time_t;
-
-typedef struct xiocb_exitstat_s {
-    cfe_xint_t status;
-} xiocb_exitstat_t;
-
-typedef struct xiocb_meminfo_s {
-    cfe_xint_t  mi_idx;			/* 0-based enumeration index */
-    cfe_xint_t  mi_type;		/* type of memory block */
-    cfe_xuint_t mi_addr;		/* physical start address */
-    cfe_xuint_t mi_size;		/* block size */
-} xiocb_meminfo_t;
-
-#define CFE_FWI_64BIT		0x00000001
-#define CFE_FWI_32BIT		0x00000002
-#define CFE_FWI_RELOC		0x00000004
-#define CFE_FWI_UNCACHED	0x00000008
-#define CFE_FWI_MULTICPU	0x00000010
-#define CFE_FWI_FUNCSIM		0x00000020
-#define CFE_FWI_RTLSIM		0x00000040
-
-typedef struct xiocb_fwinfo_s {
-    cfe_xint_t fwi_version;		/* major, minor, eco version */
-    cfe_xint_t fwi_totalmem;		/* total installed mem */
-    cfe_xint_t fwi_flags;		/* various flags */
-    cfe_xint_t fwi_boardid;		/* board ID */
-    cfe_xint_t fwi_bootarea_va;		/* VA of boot area */
-    cfe_xint_t fwi_bootarea_pa;		/* PA of boot area */
-    cfe_xint_t fwi_bootarea_size;	/* size of boot area */
-    cfe_xint_t fwi_reserved1;
-    cfe_xint_t fwi_reserved2;
-    cfe_xint_t fwi_reserved3;
-} xiocb_fwinfo_t,cfe_fwinfo_t;
-
-typedef struct cfe_xiocb_s {
-    cfe_xuint_t xiocb_fcode;		/* IOCB function code */
-    cfe_xint_t  xiocb_status;		/* return status */
-    cfe_xint_t  xiocb_handle;		/* file/device handle */
-    cfe_xuint_t xiocb_flags;		/* flags for this IOCB */
-    cfe_xuint_t xiocb_psize;		/* size of parameter list */
-    union {
-	xiocb_buffer_t  xiocb_buffer;	/* buffer parameters */
-	xiocb_inpstat_t xiocb_inpstat;	/* input status parameters */
-	xiocb_envbuf_t  xiocb_envbuf;	/* environment function parameters */
-	xiocb_cpuctl_t  xiocb_cpuctl;	/* CPU control parameters */
-	xiocb_time_t    xiocb_time;	/* timer parameters */
-	xiocb_meminfo_t xiocb_meminfo;	/* memory arena info parameters */
-	xiocb_fwinfo_t  xiocb_fwinfo;	/* firmware information */
-	xiocb_exitstat_t xiocb_exitstat; /* Exit status */
-    } plist;
-} cfe_xiocb_t;
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/swarm/cmdline.c linux-2.4.20/arch/mips/sibyte/swarm/cmdline.c
--- linux-2.4.19/arch/mips/sibyte/swarm/cmdline.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/swarm/cmdline.c	2002-10-29 11:18:32.000000000 +0000
@@ -10,7 +10,7 @@
  * 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.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/swarm/memory.c linux-2.4.20/arch/mips/sibyte/swarm/memory.c
--- linux-2.4.19/arch/mips/sibyte/swarm/memory.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/swarm/memory.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2000, 2001 Broadcom Corporation
- *
- * 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.
- */
-
-/*
- * Memory related routines 
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <asm/page.h>
-
-extern phys_t swarm_mem_region_addrs[];
-extern phys_t swarm_mem_region_sizes[];
-extern unsigned int swarm_mem_region_count;
-
-int page_is_ram(unsigned long pagenr)
-{
-	phys_t addr = pagenr << PAGE_SHIFT;
-#ifdef CONFIG_SWARM_STANDALONE
-	if (addr < (CONFIG_SIBYTE_SWARM_RAM_SIZE * 1024 * 1024)) {
-		return 1;
-	}
-#else
-	int i;
-	for (i = 0; i < swarm_mem_region_count; i++) {
-		if ((addr >= swarm_mem_region_addrs[i]) 
-		    && (addr < (swarm_mem_region_addrs[i] + swarm_mem_region_sizes[i]))) {
-			return 1;
-		}
-	}
-#endif
-	return 0;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/swarm/rtc.c linux-2.4.20/arch/mips/sibyte/swarm/rtc.c
--- linux-2.4.19/arch/mips/sibyte/swarm/rtc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/swarm/rtc.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2000, 2001 Broadcom Corporation
- *
- * 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.
- */
-
-/*
- *  Not really sure what is supposed to be here, yet 
- */
-
-#include <linux/spinlock.h>
-#include <linux/mc146818rtc.h>
-
-static unsigned char swarm_rtc_read_data(unsigned long addr)
-{
-	return 0;
-}
-
-static void swarm_rtc_write_data(unsigned char data, unsigned long addr)
-{
-}
-
-static int swarm_rtc_bcd_mode(void)
-{
-	return 0;
-}
-
-struct rtc_ops swarm_rtc_ops = {
-	&swarm_rtc_read_data,
-	&swarm_rtc_write_data,
-	&swarm_rtc_bcd_mode
-};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/swarm/rtc_xicor1241.c linux-2.4.20/arch/mips/sibyte/swarm/rtc_xicor1241.c
--- linux-2.4.19/arch/mips/sibyte/swarm/rtc_xicor1241.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/swarm/rtc_xicor1241.c	2002-10-29 11:18:35.000000000 +0000
@@ -125,7 +125,7 @@
 	/* trivial ones */
 	BIN_TO_BCD(tm.tm_sec);
 	xicor_write(X1241REG_SC, tm.tm_sec);
-	
+
 	BIN_TO_BCD(tm.tm_min);
 	xicor_write(X1241REG_MN, tm.tm_min);
 
@@ -189,7 +189,7 @@
 	mon = xicor_read(X1241REG_MO);
 	year = xicor_read(X1241REG_YR);
 	y2k = xicor_read(X1241REG_Y2K);
- 
+
 	BCD_TO_BIN(day);
 	BCD_TO_BIN(mon);
 	BCD_TO_BIN(year);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/swarm/setup.c linux-2.4.20/arch/mips/sibyte/swarm/setup.c
--- linux-2.4.19/arch/mips/sibyte/swarm/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/swarm/setup.c	2002-10-29 11:18:32.000000000 +0000
@@ -10,219 +10,58 @@
  * 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.
  */
 
 /*
- * Setup code for the SWARM board 
+ * Setup code for the SWARM board
  */
-#include <linux/config.h>
+
 #include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/bootmem.h>
 #include <linux/blk.h>
 #include <linux/init.h>
 #include <linux/ide.h>
+#include <linux/console.h>
 
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/bootinfo.h>
-#include <asm/addrspace.h>
-#include <asm/sibyte/swarm.h>
-#include <asm/sibyte/sb1250.h>
-#include <asm/sibyte/sb1250_defs.h>
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/swarm_ide.h>
 #include <asm/reboot.h>
 #include <asm/time.h>
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_genbus.h>
+#include <asm/sibyte/64bit.h>
+#include <asm/sibyte/swarm.h>
 
-#include "cfe_xiocb.h"
-#include "cfe_api.h"
-#include "cfe_error.h"
-
-extern int cfe_console_handle;
+extern struct rtc_ops *rtc_ops;
+extern struct rtc_ops swarm_rtc_ops;
 
-#ifdef CONFIG_BLK_DEV_IDE_SWARM
-extern struct ide_ops *ide_ops;
+#ifdef CONFIG_BLK_DEV_IDE
+extern struct ide_ops std_ide_ops;
+#ifdef CONFIG_BLK_DEV_IDE_SIBYTE
+extern struct ide_ops sibyte_ide_ops;
+#endif
 #endif
-
 
 #ifdef CONFIG_L3DEMO
 extern void *l3info;
 #endif
 
-/* Max ram addressable in 32-bit segments */
-#ifdef CONFIG_HIGHMEM
-#ifdef CONFIG_64BIT_PHYS_ADDR
-#define MAX_RAM_SIZE (~0ULL)
-#else
-#define MAX_RAM_SIZE (0xffffffffULL)
-#endif
-#else
-#ifdef CONFIG_MIPS64
-#define MAX_RAM_SIZE (~0ULL)
-#else
-#define MAX_RAM_SIZE (0x1fffffffULL)
-#endif
-#endif
-
-
-#ifndef CONFIG_SWARM_STANDALONE
-
-phys_t swarm_mem_region_addrs[CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS];
-phys_t swarm_mem_region_sizes[CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS];
-unsigned int swarm_mem_region_count;
-
-#endif
+static unsigned char *led_ptr;
+#define LED_BASE_ADDR (A_IO_EXT_REG(R_IO_EXT_REG(R_IO_EXT_START_ADDR, LEDS_CS)))
+#define setled(index, c) led_ptr[(3-((index)&3)) << 3] = (c)
 
 const char *get_system_type(void)
 {
 	return "SiByte Swarm";
 }
 
-#ifdef CONFIG_BLK_DEV_IDE_SWARM
-static int swarm_ide_default_irq(ide_ioreg_t base)
-{
-        return 0;
-}
-
-static ide_ioreg_t swarm_ide_default_io_base(int index)
-{
-        return 0;
-}
-
-static void swarm_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port,
-                                     ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t reg = data_port;
-	int i;
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg;
-		reg += 1;
-	}
-	if (ctrl_port) {
-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-	} else {
-		hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
-	}
-	if (irq != NULL)
-		*irq = 0;
-	hw->io_ports[IDE_IRQ_OFFSET] = 0;
-}
-
-static int swarm_ide_request_irq(unsigned int irq,
-                                void (*handler)(int,void *, struct pt_regs *),
-                                unsigned long flags, const char *device,
-                                void *dev_id)
-{
-	return request_irq(irq, handler, flags, device, dev_id);
-}			
-
-static void swarm_ide_free_irq(unsigned int irq, void *dev_id)
-{
-	free_irq(irq, dev_id);
-}
-
-static int swarm_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-    /* Note: "check_region" and friends do conflict management on ISA I/O
-       space.  Our disk is not in that space, so this check won't work */
-    /* return check_region(from, extent); */
-    return 0;
-}
-
-static void swarm_ide_request_region(ide_ioreg_t from, unsigned int extent,
-                                    const char *name)
-{
-    /* request_region(from, extent, name); */
-}
-
-static void swarm_ide_release_region(ide_ioreg_t from, unsigned int extent)
-{
-    /* release_region(from, extent); */
-}
-
-
-void swarm_ideproc(ide_ide_action_t action, ide_drive_t *drive,
-		   void *buffer, unsigned int count)
-{
-	/*  slow? vlb_sync? */
-	switch (action) {
-	case ideproc_ide_input_data:
-		if (drive->io_32bit) {
-			swarm_insl(IDE_DATA_REG, buffer, count);
-		} else {
-			swarm_insw(IDE_DATA_REG, buffer, count<<1);
-		}
-		break;
-	case ideproc_ide_output_data:
-		if (drive->io_32bit) {
-			swarm_outsl(IDE_DATA_REG, buffer, count);
-		} else {
-			swarm_outsw(IDE_DATA_REG, buffer, count<<1);
-		}
-		break;
-	case ideproc_atapi_input_bytes:
-		count++;
-		if (drive->io_32bit) {
-			swarm_insl(IDE_DATA_REG, buffer, count>>2);
-		} else {
-			swarm_insw(IDE_DATA_REG, buffer, count>>1);
-		}
-		if ((count & 3) >= 2)
-			swarm_insw(IDE_DATA_REG, (char *)buffer + (count & ~3), 1);
-		break;
-	case ideproc_atapi_output_bytes:
-		count++;
-		if (drive->io_32bit) {
-			swarm_outsl(IDE_DATA_REG, buffer, count>>2);
-		} else {
-			swarm_outsw(IDE_DATA_REG, buffer, count>>1);
-		}
-		if ((count & 3) >= 2)
-			swarm_outsw(IDE_DATA_REG, (char *)buffer + (count & ~3), 1);
-		break;
-	}
-}
-
-struct ide_ops swarm_ide_ops = {
-	&swarm_ide_default_irq,
-	&swarm_ide_default_io_base,
-	&swarm_ide_init_hwif_ports,
-	&swarm_ide_request_irq,
-	&swarm_ide_free_irq,
-	&swarm_ide_check_region,
-	&swarm_ide_request_region,
-	&swarm_ide_release_region
-};
-#endif
-
-
-#ifdef CONFIG_SMP
-static void smp_cpu0_exit(void *unused)
-{
-	printk("swarm_linux_exit called (cpu1) - passing control back to CFE\n");
-	cfe_exit(1,0);
-}
-#endif
-
-static void swarm_linux_exit(void)
-{
-#ifdef CONFIG_SMP
-	if (smp_processor_id()) {
-		smp_call_function(smp_cpu0_exit,NULL,1,1);
-		while(1);
-	}
-#endif
-	printk("swarm_linux_exit called...passing control back to CFE\n");
-	cfe_exit(1, 0);
-	printk("cfe_exit returned??\n");
-	while(1);
-}
 
 void __init bus_error_init(void)
 {
@@ -230,7 +69,7 @@
 
 void __init swarm_timer_setup(struct irqaction *irq)
 {
-        /* 
+        /*
          * we don't set up irqaction, because we will deliver timer
          * interrupts through low-level (direct) meachanism.
          */
@@ -240,12 +79,15 @@
 }
 
 extern int xicor_set_time(unsigned long);
-extern unsigned int xicor_get_time(void);
+extern unsigned long xicor_get_time(void);
+extern void sb1250_setup(void);
 
 void __init swarm_setup(void)
 {
 	extern int panic_timeout;
 
+	sb1250_setup();
+
 	panic_timeout = 5;  /* For debug.  */
 
         board_timer_setup = swarm_timer_setup;
@@ -253,10 +95,6 @@
         rtc_get_time = xicor_get_time;
         rtc_set_time = xicor_set_time;
 
-	_machine_restart   = (void (*)(char *))swarm_linux_exit;
-	_machine_halt      = swarm_linux_exit;
-	_machine_power_off = swarm_linux_exit;
-
 #ifdef CONFIG_L3DEMO
 	if (l3info != NULL) {
 		printk("\n");
@@ -268,231 +106,58 @@
 #else
 	       "board"
 #endif
-	       " runs\n");
-
-#ifdef CONFIG_BLK_DEV_IDE_SWARM
-	ide_ops = &swarm_ide_ops;
+	       " runs "
+#ifdef CONFIG_SIBYTE_CFE
+	       "with"
+#else
+	       "without"
 #endif
-}  
+	       " CFE\n");
 
-/* This is the kernel command line.  Actually, it's 
-   copied, eventually, to command_line, and looks to be
-   quite redundant.  But not something to fix just now */
-extern char arcs_cmdline[];
-
-#ifdef CONFIG_EMBEDDED_RAMDISK
-/* These are symbols defined by the ramdisk linker script */
-extern unsigned char __rd_start;
-extern unsigned char __rd_end;  
+#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_SIBYTE
+	ide_ops = &sibyte_ide_ops;
+#else
+	ide_ops = &std_ide_ops;
 #endif
-
-static __init void prom_meminit(void)
-{
-	u64 addr, size; /* regardless of 64BIT_PHYS_ADDR */
-	long type;
-	unsigned int idx;
-	int rd_flag;
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	unsigned long initrd_pstart; 
-	unsigned long initrd_pend; 
-
-#ifdef CONFIG_EMBEDDED_RAMDISK
-	/* If we're using an embedded ramdisk, then __rd_start and __rd_end
-	   are defined by the linker to be on either side of the ramdisk
-	   area.  Otherwise, initrd_start should be defined by kernel command
-	   line arguments */
-	if (initrd_start == 0) {
-		initrd_start = (unsigned long)&__rd_start;
-		initrd_end = (unsigned long)&__rd_end;
-	}
 #endif
 
-	initrd_pstart = __pa(initrd_start);
-	initrd_pend = __pa(initrd_end);
-	if (initrd_start &&
-	    ((initrd_pstart > MAX_RAM_SIZE)
-	     || (initrd_pend > MAX_RAM_SIZE))) {
-		setleds("INRD");
-		panic("initrd out of addressable memory");
-	}
-       
-#endif /* INITRD */
-		
-	for (idx = 0; cfe_enummem(idx, &addr, &size, &type) != CFE_ERR_NOMORE;
-	     idx++) {
-		rd_flag = 0;
-		if (type == CFE_MI_AVAILABLE) {
-			/*
-			 * See if this block contains (any portion of) the
-			 * ramdisk
-			 */
-#ifdef CONFIG_BLK_DEV_INITRD
-			if (initrd_start) {
-				if ((initrd_pstart > addr) &&
-				    (initrd_pstart < (addr + size))) {
-					add_memory_region(addr,
-					                  initrd_pstart - addr,
-					                  BOOT_MEM_RAM);
-					rd_flag = 1;
-				}
-				if ((initrd_pend > addr) &&
-				    (initrd_pend < (addr + size))) {
-					add_memory_region(initrd_pend,
-						(addr + size) - initrd_pend,
-						 BOOT_MEM_RAM);
-					rd_flag = 1;
-				}
-			}
-#endif
-			if (!rd_flag) {
-				if (addr > MAX_RAM_SIZE)
-					continue;
-				if (addr+size > MAX_RAM_SIZE)
-					size = MAX_RAM_SIZE - (addr+size) + 1;
-				add_memory_region(addr, size, BOOT_MEM_RAM);
-			}
-			swarm_mem_region_addrs[swarm_mem_region_count] = addr;
-			swarm_mem_region_sizes[swarm_mem_region_count] = size;
-			swarm_mem_region_count++;
-			if (swarm_mem_region_count ==
-			    CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS) {
-				/*
-				 * Too many regions.  Need to configure more
-				 */
-				while(1);
-			}
-		}
-	}
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (initrd_start) {
-		add_memory_region(initrd_pstart, initrd_pend - initrd_pstart,
-		                 BOOT_MEM_RESERVED);
-	}
+	/* Set up the LED base address */
+#ifdef __MIPSEL__
+	/* Pass1 workaround (bug 1624) */
+	if (sb1250_pass == K_SYS_REVISION_PASS1)
+		led_ptr = (unsigned char *)
+			((unsigned long)(KSEG1 | (G_IO_START_ADDR(csr_in32(4+(KSEG1|LED_BASE_ADDR))) << S_IO_ADDRBASE))+0x20);
+	else
+#endif
+		led_ptr = (unsigned char *)
+			((unsigned long)(KSEG1 | (G_IO_START_ADDR(csr_in32(KSEG1|LED_BASE_ADDR)) << S_IO_ADDRBASE))+0x20);
+
+#ifdef CONFIG_VT
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+	screen_info = (struct screen_info) {
+		0, 0,           /* orig-x, orig-y */
+		0,              /* unused */
+		52,             /* orig_video_page */
+		3,              /* orig_video_mode */
+		80,             /* orig_video_cols */
+		4626, 3, 9,     /* unused, ega_bx, unused */
+		25,             /* orig_video_lines */
+		0x22,           /* orig_video_isVGA */
+		16              /* orig_video_points */
+       };
+       /* XXXKW for CFE, get lines/cols from environment */
 #endif
 }
 
-
-#ifdef CONFIG_BLK_DEV_INITRD
-static int __init initrd_setup(char *str)
-{
-	/* 
-	 *Initrd location comes in the form "<hex size of ramdisk in bytes>@<location in memory>"
-	 *  e.g. initrd=3abfd@80010000.  This is set up by the loader.
-	 */
-	char *tmp, *endptr;
-	unsigned long initrd_size;
-	for (tmp = str; *tmp != '@'; tmp++) {
-		if (!*tmp) {
-			goto fail;
-		}
-	}
-	*tmp = 0;
-	tmp++;
-	if (!*tmp) {
-		goto fail;
-	}
-	initrd_size = simple_strtol(str, &endptr, 16);
-	if (*endptr) {
-		goto fail;
-	}
-	initrd_start = simple_strtol(tmp, &endptr, 16);
-	if (*endptr) {
-		goto fail;
-	}
-	initrd_end = initrd_start + initrd_size;
-	printk("Found initrd of %lx@%lx\n", initrd_size, initrd_start);
-	return 1;
- fail:
-	printk("Bad initrd argument.  Disabling initrd\n");
-	initrd_start = 0;
-	initrd_end = 0;
-	return 1;
-}
-
-#endif
-
-/*
- * prom_init is called just after the cpu type is determined, from init_arch()
- */
-__init int prom_init(int argc, char **argv, char **envp, int *prom_vec)
-{
-	/* 
-	 * This should go away.  Detect if we're booting
-	 * straight from cfe without a loader.  If we
-	 * are, then we've got a prom vector in a0.  Otherwise,
-	 * argc (and argv and envp, for that matter) will be 0) 
-	 */
-	if (argc < 0) {
-		prom_vec = (int *)argc;
-	}
-	cfe_init((long)prom_vec);
-	cfe_open_console();
-	if (cfe_getenv("LINUX_CMDLINE", arcs_cmdline, CL_SIZE) < 0) {
-		if (argc < 0) {
-			/*
-			 * It's OK for direct boot to not provide a
-			 *  command line
-			 */
-			strcpy(arcs_cmdline, "root=/dev/ram0 ");
-		} else {
-			/* The loader should have set the command line */
-			setleds("CMDL");
-			panic("LINUX_CMDLINE not defined in cfe.");
-		}
-	}
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	{
-		char *ptr;
-		/* Need to find out early whether we've got an initrd.  So scan
-		   the list looking now */
-		for (ptr = arcs_cmdline; *ptr; ptr++) {
-			while (*ptr == ' ') {
-				ptr++;
-			}
-			if (!strncmp(ptr, "initrd=", 7)) {
-				initrd_setup(ptr+7);
-				break;
-			} else {
-				while (*ptr && (*ptr != ' ')) {
-					ptr++;
-				}
-			}
-		}
-	}
-#endif /* CONFIG_BLK_DEV_INITRD */
-
-	/* Not sure this is needed, but it's the safe way. */
-	arcs_cmdline[CL_SIZE-1] = 0;
-
-	mips_machgroup = MACH_GROUP_SIBYTE;
-	prom_meminit();
-
-	return 0;
-}
-
-void prom_free_prom_memory(void)
-{
-	/* Not sure what I'm supposed to do here.  Nothing, I think */
-}
-
-static void setled(unsigned int index, char c) 
-{
-	volatile unsigned char *led_ptr;
-
-	led_ptr = (unsigned char *)(IO_SPACE_BASE | LED_BASE_ADDR);
-	if (index < 4) {
-		led_ptr[(3-index)<<3] = c;
-	}
-}
-
 void setleds(char *str)
 {
 	int i;
 	for (i = 0; i < 4; i++) {
 		if (!str[i]) {
-			for (; i < 4; i++) { 
+			for (; i < 4; i++) {
 				setled(' ', str[i]);
 			}
 		} else {
@@ -516,27 +181,27 @@
 	setleds("    ");
 }
 
-static void move_leds(unsigned long arg) 
+static void move_leds(unsigned long arg)
 {
 	int i;
 	unsigned char *tmp = led_msg_ptr;
 	for (i = 0; i < 4; i++) {
 		setled(i, *tmp);
 		tmp++;
-		if (!*tmp) { 
-			tmp = led_msg; 
+		if (!*tmp) {
+			tmp = led_msg;
 		}
 	}
 	led_msg_ptr++;
-	if (!*led_msg_ptr) { 
- 		led_msg_ptr = led_msg; 
+	if (!*led_msg_ptr) {
+ 		led_msg_ptr = led_msg;
 	}
 	del_timer(&led_timer);
 	led_timer.expires = jiffies + (HZ/8);
 	add_timer(&led_timer);
 }
 
-void hack_leds(void) 
+void hack_leds(void)
 {
 	init_timer(&led_timer);
 	led_timer.expires = jiffies + (HZ/8);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/swarm/smp.c linux-2.4.20/arch/mips/sibyte/swarm/smp.c
--- linux-2.4.19/arch/mips/sibyte/swarm/smp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/swarm/smp.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2001 Broadcom Corporation
- *
- * 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.
- */
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-
-#include <asm/sibyte/sb1250.h>
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/sb1250_int.h>
-#include <asm/mipsregs.h>
-#include <asm/mmu_context.h>
-
-#include "cfe_xiocb.h"
-#include "cfe_api.h"
-
-extern void asmlinkage smp_bootstrap(void);
-
-/* Boot all other cpus in the system, initialize them, and
-   bring them into the boot fn */
-int prom_boot_secondary(int cpu, unsigned long sp, unsigned long gp)
-{
-	int retval;
-	
-	retval = cfe_start_cpu(cpu, &smp_bootstrap, sp, gp, 0);
-	if (retval != 0) {
-		printk("cfe_start_cpu(%i) returned %i\n" , cpu, retval);
-		return 0;
-	} else {
-		return 1;
-	}
-}
-
-
-void prom_init_secondary(void)
-{
-	/* Set up kseg0 to be cachable coherent */
-	clear_cp0_config(CONF_CM_CMASK);
-	set_cp0_config(0x5);
-
-	/* Enable interrupts for lines 0-4 */
-	clear_cp0_status(0xe000);
-	set_cp0_status(0x1f01);
-}
-
-
-/*
- * Set up state, return the total number of cpus in the system, including
- * the master
- */
-int prom_setup_smp(void)
-{
-	int i;
-	int num_cpus = 1;
-
-	/* Use CFE to find out how many CPUs are available */
-	for (i=1; i<NR_CPUS; i++) {
-		if (cfe_stop_cpu(i) == 0) {
-			num_cpus++;
-		}
-	}
-	printk("Detected %i available CPU(s)\n", num_cpus);
-	return num_cpus;
-}
-
-void prom_smp_finish(void)
-{
-	extern void sb1250_smp_finish(void);
-	sb1250_smp_finish();
-}
-
-/*
- * XXX This is really halfway portable code and halfway system specific code.
- * XXX Seems like some of this is CPU-specific, too - rather than board/system.
- */
-extern atomic_t cpus_booted;
-
-void __init smp_boot_cpus(void)
-{
-	int i;
-	int cur_cpu = 0;
-
-	smp_num_cpus = prom_setup_smp();
-	init_new_context(current, &init_mm);
-	current->processor = 0;
-	cpu_data[0].udelay_val = loops_per_jiffy;
-	cpu_data[0].asid_cache = ASID_FIRST_VERSION;
-	CPUMASK_CLRALL(cpu_online_map);
-	CPUMASK_SETB(cpu_online_map, 0);
-	atomic_set(&cpus_booted, 1);  /* Master CPU is already booted... */
-	__cpu_number_map[0] = 0;
-	__cpu_logical_map[0] = 0;
-	init_idle();
-
-	/* 
-	 * This loop attempts to compensate for "holes" in the CPU
-	 * numbering.  It's overkill, but general.
-	 */
-	for (i = 1; i < smp_num_cpus; ) {
-		struct task_struct *p;
-		struct pt_regs regs;
-		int retval;
-		printk("Starting CPU %d... ", i);
-
-		/* Spawn a new process normally.  Grab a pointer to
-		   its task struct so we can mess with it */
-		do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0);
-		p = init_task.prev_task;
-
-		/* Schedule the first task manually */
-		p->processor = i;
-		p->cpus_runnable = 1 << i; /* we schedule the first task manually */
-
-		/* Attach to the address space of init_task. */
-		atomic_inc(&init_mm.mm_count);
-		p->active_mm = &init_mm;
-		init_tasks[i] = p;
-
-		del_from_runqueue(p);
-		unhash_process(p);
-
-		do {
-			/* Iterate until we find a CPU that comes up */
-			cur_cpu++;
-			retval = prom_boot_secondary(cur_cpu,
-					    (unsigned long)p + KERNEL_STACK_SIZE - 32,
-					    (unsigned long)p);
-			__cpu_number_map[i] = i;
-			__cpu_logical_map[i] = i;
-		} while (!retval && (cur_cpu < NR_CPUS));
-		if (retval) {
-			i++;
-		} else {
-			panic("CPU discovery disaster");
-		}
-
-#if 0
-		/* This is copied from the ip-27 code in the mips64 tree */
-
-		struct task_struct *p;
-
-		/*
-		 * The following code is purely to make sure
-		 * Linux can schedule processes on this slave.
-		 */
-		kernel_thread(0, NULL, CLONE_PID);
-		p = init_task.prev_task;
-		sprintf(p->comm, "%s%d", "Idle", i);
-		init_tasks[i] = p;
-		p->processor = i;
-		p->cpus_runnable = 1 << i; /* we schedule the first task manually */
-		del_from_runqueue(p);
-		unhash_process(p);
-		/* Attach to the address space of init_task. */
-		atomic_inc(&init_mm.mm_count);
-		p->active_mm = &init_mm;
-		prom_boot_secondary(i, 
-				    (unsigned long)p + KERNEL_STACK_SIZE - 32,
-				    (unsigned long)p);
-#endif
-	}
-
-	/* Wait for everyone to come up */
-	while (atomic_read(&cpus_booted) != smp_num_cpus);
-
-	smp_threads_ready = 1;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sibyte/swarm/time.c linux-2.4.20/arch/mips/sibyte/swarm/time.c
--- linux-2.4.19/arch/mips/sibyte/swarm/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sibyte/swarm/time.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 2000, 2001 Broadcom Corporation
- *
- * 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.
- */
-
-/* 
- * Time routines for the swarm board.  We pass all the hard stuff
- * through to the sb1250 handling code.  Only thing we really keep
- * track of here is what time of day we think it is.  And we don't
- * really even do a good job of that...
- */
-#include <linux/init.h>
-#include <linux/time.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <asm/system.h>
-#include <asm/addrspace.h>
-
-#include <asm/sibyte/64bit.h>
-#include <asm/sibyte/sb1250.h>
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/sb1250_smbus.h>
-
-extern rwlock_t xtime_lock;
-
-/* Xicor 1241 definitions */
-
-/*
- * Register bits
- */
-
-#define X1241REG_SR_BAT	0x80		/* currently on battery power */
-#define X1241REG_SR_RWEL 0x04		/* r/w latch is enabled, can write RTC */
-#define X1241REG_SR_WEL 0x02		/* r/w latch is unlocked, can enable r/w now */
-#define X1241REG_SR_RTCF 0x01		/* clock failed */
-#define X1241REG_BL_BP2 0x80		/* block protect 2 */
-#define X1241REG_BL_BP1 0x40		/* block protect 1 */
-#define X1241REG_BL_BP0 0x20		/* block protect 0 */
-#define X1241REG_BL_WD1	0x10
-#define X1241REG_BL_WD0	0x08
-#define X1241REG_HR_MIL 0x80		/* military time format */
-
-/*
- * Register numbers
- */
-
-#define X1241REG_BL	0x10		/* block protect bits */
-#define X1241REG_INT	0x11		/*  */
-#define X1241REG_SC	0x30		/* Seconds */
-#define X1241REG_MN	0x31		/* Minutes */
-#define X1241REG_HR	0x32		/* Hours */
-#define X1241REG_DT	0x33		/* Day of month */
-#define X1241REG_MO	0x34		/* Month */
-#define X1241REG_YR	0x35		/* Year */
-#define X1241REG_DW	0x36		/* Day of Week */
-#define X1241REG_Y2K	0x37		/* Year 2K */
-#define X1241REG_SR	0x3F		/* Status register */
-
-#define X1241_CCR_ADDRESS	0x6F
-
-#define SMB_CSR(reg) (KSEG1 | A_SMB_REGISTER(1, reg))
-
-static int xicor_read(uint8_t addr)
-{
-        while (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
-                ;
-
-	out64((addr >> 8) & 0x7, SMB_CSR(R_SMB_CMD));
-	out64((addr & 0xff), SMB_CSR(R_SMB_DATA));
-	out64((V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR2BYTE), SMB_CSR(R_SMB_START));
-
-        while (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
-                ;
-
-	out64((V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_RD1BYTE), SMB_CSR(R_SMB_START));
-
-        while (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
-                ;
-
-        if (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) {
-                /* Clear error bit by writing a 1 */
-                out64(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
-                return -1;
-        }
-
-	return (in64(SMB_CSR(R_SMB_DATA)) & 0xff);
-}
-
-static int xicor_write(uint8_t addr, int b)
-{
-        while (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
-                ;
-
-	out64(addr, SMB_CSR(R_SMB_CMD));
-	out64((addr & 0xff) | ((b & 0xff) << 8), SMB_CSR(R_SMB_DATA));
-	out64(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR3BYTE,
-	      SMB_CSR(R_SMB_START));
-
-        while (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
-                ;
-
-        if (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) {
-                /* Clear error bit by writing a 1 */
-                out64(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
-                return -1;
-        } else {
-		return 0;
-	}
-}
-
-#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
-#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
-
-/*
- * In order to set the CMOS clock precisely, set_rtc_mmss has to be
- * called 500 ms after the second nowtime has started, because when
- * nowtime is written into the registers of the CMOS clock, it will
- * jump to the next second precisely 500 ms later. Check the Motorola
- * MC146818A or Dallas DS12887 data sheet for details.
- *
- * BUG: This routine does not handle hour overflow properly; it just
- *      sets the minutes. Usually you'll only notice that after reboot!
- */
-int set_rtc_mmss(unsigned long nowtime)
-{
-	int retval = 0;
-	int real_seconds, real_minutes, cmos_minutes;
-
-	cmos_minutes = xicor_read(X1241REG_MN);
-	BCD_TO_BIN(cmos_minutes);
-
-	/*
-	 * since we're only adjusting minutes and seconds,
-	 * don't interfere with hour overflow. This avoids
-	 * messing with unknown time zones but requires your
-	 * RTC not to be off by more than 15 minutes
-	 */
-	real_seconds = nowtime % 60;
-	real_minutes = nowtime / 60;
-	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
-		real_minutes += 30;		/* correct for half hour time zone */
-	real_minutes %= 60;
-
-	/* unlock writes to the CCR */
-	xicor_write(X1241REG_SR, X1241REG_SR_WEL);
-	xicor_write(X1241REG_SR, X1241REG_SR_WEL | X1241REG_SR_RWEL);
-
-	if (abs(real_minutes - cmos_minutes) < 30) {
-		BIN_TO_BCD(real_seconds);
-		BIN_TO_BCD(real_minutes);
-		xicor_write(X1241REG_SC, real_seconds);
-		xicor_write(X1241REG_MN, real_minutes);
-	} else {
-		printk(KERN_WARNING
-		       "set_rtc_mmss: can't update from %d to %d\n",
-		       cmos_minutes, real_minutes);
-		retval = -1;
-	}
-
-	xicor_write(X1241REG_SR, 0);
-
-	printk("set_rtc_mmss: %02d:%02d\n", real_minutes, real_seconds);
-
-	return retval;
-}
-
-static unsigned long __init get_swarm_time(void)
-{
-	unsigned int year, mon, day, hour, min, sec, y2k;
-
-	sec = xicor_read(X1241REG_SC);
-	min = xicor_read(X1241REG_MN);
-	hour = xicor_read(X1241REG_HR);
-
-	if (hour & X1241REG_HR_MIL) {
-		hour &= 0x3f;
-	} else {
-		if (hour & 0x20)
-			hour = (hour & 0xf) + 0x12;
-	}
-
-	BCD_TO_BIN(sec);
-	BCD_TO_BIN(min);
-	BCD_TO_BIN(hour);
-
-	day = xicor_read(X1241REG_DT);
-	mon = xicor_read(X1241REG_MO);
-	year = xicor_read(X1241REG_YR);
-	y2k = xicor_read(X1241REG_Y2K);
- 
-	BCD_TO_BIN(day);
-	BCD_TO_BIN(mon);
-	BCD_TO_BIN(year);
-	BCD_TO_BIN(y2k);
-
-	year += (y2k * 100);
-
-	return mktime(year, mon, day, hour, min, sec);
-}
-
-/*
- *  Bring up the timer at 100 Hz.  
- */
-void __init swarm_time_init(void)
-{
-	unsigned int flags;
-	int status;
-
-	/* Set up the scd general purpose timer 0 to cpu 0 */
-	sb1250_time_init();
-
-	/* Establish communication with the Xicor 1241 RTC */
-	/* XXXKW how do I share the SMBus with the I2C subsystem? */
-
-	out64(K_SMB_FREQ_400KHZ, SMB_CSR(R_SMB_FREQ));
-	out64(0, SMB_CSR(R_SMB_CONTROL));
-
-	if ((status = xicor_read(X1241REG_SR_RTCF)) < 0) {
-		printk("x1241: couldn't detect on SWARM SMBus 1\n");
-	} else {
-		if (status & X1241REG_SR_RTCF)
-			printk("x1241: battery failed -- time is probably wrong\n");
-		write_lock_irqsave (&xtime_lock, flags);
-		xtime.tv_sec = get_swarm_time();
-		xtime.tv_usec = 0;
-		write_unlock_irqrestore(&xtime_lock, flags);
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/sni/pci.c linux-2.4.20/arch/mips/sni/pci.c
--- linux-2.4.19/arch/mips/sni/pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/sni/pci.c	2002-10-29 11:18:48.000000000 +0000
@@ -199,7 +199,8 @@
 }
 
 void __init
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res, unsigned long size,
+		       unsigned long align)
 {
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/tools/Makefile linux-2.4.20/arch/mips/tools/Makefile
--- linux-2.4.19/arch/mips/tools/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/tools/Makefile	2002-10-29 11:18:34.000000000 +0000
@@ -17,9 +17,8 @@
 
 clean:
 	rm -f offset.[hs] $(TARGET).new
-	
-mrproper:	
-	rm -f offset.[hs] $(TARGET).new
+
+mrproper: clean
 	rm -f $(TARGET)
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/tools/offset.c linux-2.4.20/arch/mips/tools/offset.c
--- linux-2.4.19/arch/mips/tools/offset.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips/tools/offset.c	2002-10-29 11:18:34.000000000 +0000
@@ -2,8 +2,8 @@
  * offset.c: Calculate pt_regs and task_struct offsets.
  *
  * Copyright (C) 1996 David S. Miller
- * Copyright (C) 1997, 1998, 1999 Ralf Baechle
- * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  *
  * Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
  * Copyright (C) 2000 MIPS Technologies, Inc.
@@ -82,15 +82,16 @@
 	text("/* MIPS task_struct offsets. */");
 	offset("#define TASK_STATE         ", struct task_struct, state);
 	offset("#define TASK_FLAGS         ", struct task_struct, flags);
+	constant("  #define _PT_TRACESYS        ", PT_TRACESYS);
 	offset("#define TASK_SIGPENDING    ", struct task_struct, sigpending);
 	offset("#define TASK_NEED_RESCHED  ", struct task_struct, need_resched);
 	offset("#define TASK_PTRACE        ", struct task_struct, ptrace);
 	offset("#define TASK_COUNTER       ", struct task_struct, counter);
 	offset("#define TASK_NICE          ", struct task_struct, nice);
 	offset("#define TASK_MM            ", struct task_struct, mm);
+	offset("#define TASK_PROCESSOR     ", struct task_struct, processor);
 	offset("#define TASK_PID           ", struct task_struct, pid);
 	size(  "#define TASK_STRUCT_SIZE   ", struct task_struct);
-	constant("#define PT_TRACESYS        ", PT_TRACESYS);
 	linefeed;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/common/Makefile linux-2.4.20/arch/mips/vr41xx/common/Makefile
--- linux-2.4.19/arch/mips/vr41xx/common/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/common/Makefile	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,21 @@
+#
+# Makefile for common code of the NEC VR4100 series.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+USE_STANDARD_AS_RULE := true
+
+all: vr41xx.o
+
+O_TARGET := vr41xx.o
+
+obj-y := bcu.o cmu.o giu.o icu.o int-handler.o reset.o
+
+obj-$(CONFIG_PCI)		+= pciu.o
+obj-$(CONFIG_SERIAL)		+= serial.o
+obj-$(CONFIG_VR41XX_TIME_C)	+= time.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/common/bcu.c linux-2.4.20/arch/mips/vr41xx/common/bcu.c
--- linux-2.4.19/arch/mips/vr41xx/common/bcu.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/common/bcu.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,206 @@
+/*
+ * FILE NAME
+ *	arch/mips/vr41xx/common/bcu.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Bus Control Unit routines for the NEC VR4100 series.
+ *
+ * Author: Yoichi Yuasa
+ *         yyuasa@mvista.com or source@mvista.com
+ *
+ * Copyright 2002 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.
+ */
+/*
+ * Changes:
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - Added support for NEC VR4111 and VR4121.
+ *
+ *  Paul Mundt <lethal@chaoticdreams.org>
+ *  - Calculate mips_counter_frequency properly on VR4131.
+ *
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - New creation, NEC VR4122 and VR4131 are supported.
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <asm/addrspace.h>
+#include <asm/cpu.h>
+#include <asm/io.h>
+#include <asm/time.h>
+#include <asm/vr41xx/vr41xx.h>
+
+#define VR4111_CLKSPEEDREG	KSEG1ADDR(0x0b000014)
+#define VR4122_CLKSPEEDREG	KSEG1ADDR(0x0f000014)
+#define VR4131_CLKSPEEDREG	VR4122_CLKSPEEDREG
+ #define CLKSP(x)		((x) & 0x001f)
+
+ #define DIV2B			0x8000
+ #define DIV3B			0x4000
+ #define DIV4B			0x2000
+
+ #define DIVT(x)		(((x) & 0xf000) >> 12)
+ #define DIVVT(x)		(((x) & 0x0f00) >> 8)
+
+ #define TDIVMODE(x)		(2 << (((x) & 0x1000) >> 12))
+ #define VTDIVMODE(x)		(((x) & 0x0700) >> 8)
+
+unsigned long vr41xx_vtclock = 0;
+
+static inline u16 read_clkspeed(void)
+{
+	switch (mips_cpu.cputype) {
+	case CPU_VR4111:
+	case CPU_VR4121: return readw(VR4111_CLKSPEEDREG);
+	case CPU_VR4122: return readw(VR4122_CLKSPEEDREG);
+	case CPU_VR4131: return readw(VR4131_CLKSPEEDREG);
+	default:
+		printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n");
+		break;
+	}
+
+	return 0;
+}
+
+static inline unsigned long calculate_pclock(u16 clkspeed)
+{
+	unsigned long pclock = 0;
+
+	switch (mips_cpu.cputype) {
+	case CPU_VR4111:
+	case CPU_VR4121:
+		pclock = 18432000 * 64;
+		break;
+	case CPU_VR4122:
+		pclock = 18432000 * 98;
+		break;
+	case CPU_VR4131:
+		pclock = 18432000 * 108;
+		break;
+	default:
+		printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n");
+		break;
+	}
+
+	pclock /= CLKSP(clkspeed);
+	printk(KERN_INFO "PClock: %ldHz\n", pclock);
+
+	return pclock;
+}
+
+static inline unsigned long calculate_vtclock(u16 clkspeed, unsigned long pclock)
+{
+	switch (mips_cpu.cputype) {
+	case CPU_VR4111:
+		/* The NEC VR4111 doesn't have the VTClock. */
+		break;
+	case CPU_VR4121:
+		vr41xx_vtclock = pclock;
+		/* DIVVT == 9 Divide by 1.5 . VTClock = (PClock * 6) / 9 */
+		if (DIVVT(clkspeed) == 9)
+			vr41xx_vtclock = pclock * 6;
+		/* DIVVT == 10 Divide by 2.5 . VTClock = (PClock * 4) / 10 */
+		else if (DIVVT(clkspeed) == 10)
+			vr41xx_vtclock = pclock * 4;
+		vr41xx_vtclock /= DIVVT(clkspeed);
+		printk(KERN_INFO "VTClock: %ldHz\n", vr41xx_vtclock);
+		break;
+	case CPU_VR4122:
+		if(VTDIVMODE(clkspeed) == 7)
+			vr41xx_vtclock = pclock / 1;
+		else if(VTDIVMODE(clkspeed) == 1)
+			vr41xx_vtclock = pclock / 2;
+		else
+			vr41xx_vtclock = pclock / VTDIVMODE(clkspeed);
+		printk(KERN_INFO "VTClock: %ldHz\n", vr41xx_vtclock);
+		break;
+	case CPU_VR4131:
+		vr41xx_vtclock = pclock / VTDIVMODE(clkspeed);
+		printk(KERN_INFO "VTClock: %ldHz\n", vr41xx_vtclock);
+		break;
+	default:
+		printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n");
+		break;
+	}
+
+	return vr41xx_vtclock;
+}
+
+static inline unsigned long calculate_tclock(u16 clkspeed, unsigned long pclock,
+                                             unsigned long vtclock)
+{
+	unsigned long tclock = 0;
+
+	switch (mips_cpu.cputype) {
+	case CPU_VR4111:
+		if (!(clkspeed & DIV2B))
+        		tclock = pclock / 2;
+		else if (!(clkspeed & DIV3B))
+        		tclock = pclock / 3;
+		else if (!(clkspeed & DIV4B))
+        		tclock = pclock / 4;
+		break;
+	case CPU_VR4121:
+		tclock = pclock / DIVT(clkspeed);
+		break;
+	case CPU_VR4122:
+	case CPU_VR4131:
+		tclock = vtclock / TDIVMODE(clkspeed);
+		break;
+	default:
+		printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n");
+		break;
+	}
+
+	printk(KERN_INFO "TClock: %ldHz\n", tclock);
+
+	return tclock;
+}
+
+static inline unsigned long calculate_mips_counter_frequency(unsigned long tclock)
+{
+	/*
+	 * VR4131 Revision 2.0 and 2.1 use a value of (tclock / 2).
+	 */
+	if ((mips_cpu.processor_id == PRID_VR4131_REV2_0) ||
+	    (mips_cpu.processor_id == PRID_VR4131_REV2_1))
+		tclock /= 2;
+	else
+		tclock /= 4;
+
+	return tclock;
+}
+
+void __init vr41xx_bcu_init(void)
+{
+	unsigned long pclock, vtclock, tclock;
+	u16 clkspeed;
+
+	clkspeed = read_clkspeed();
+
+	pclock = calculate_pclock(clkspeed);
+	vtclock = calculate_vtclock(clkspeed, pclock);
+	tclock = calculate_tclock(clkspeed, pclock, vtclock);
+
+	mips_counter_frequency = calculate_mips_counter_frequency(tclock);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/common/cmu.c linux-2.4.20/arch/mips/vr41xx/common/cmu.c
--- linux-2.4.19/arch/mips/vr41xx/common/cmu.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/common/cmu.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,84 @@
+/*
+ * FILE NAME
+ *	arch/mips/vr41xx/common/cmu.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Clock Mask Unit routines for the NEC VR4100 series.
+ *
+ * Author: Yoichi Yuasa
+ *         yyuasa@mvista.com or source@mvista.com
+ *
+ * Copyright 2001,2002 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.
+ */
+/*
+ * Changes:
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - Added support for NEC VR4111 and VR4121.
+ *
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - New creation, NEC VR4122 and VR4131 are supported.
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <asm/cpu.h>
+#include <asm/io.h>
+
+#define VR4111_CMUCLKMSK	KSEG1ADDR(0x0b000060)
+#define VR4122_CMUCLKMSK	KSEG1ADDR(0x0f000060)
+
+static u32 vr41xx_cmu_base;
+static u16 cmuclkmsk;
+
+#define write_cmu(mask)	writew((mask), vr41xx_cmu_base)
+
+void vr41xx_clock_supply(u16 mask)
+{
+	cmuclkmsk |= mask;
+	write_cmu(cmuclkmsk);
+}
+
+void vr41xx_clock_mask(u16 mask)
+{
+	cmuclkmsk &= ~mask;
+	write_cmu(cmuclkmsk);
+}
+
+void __init vr41xx_cmu_init(u16 mask)
+{
+	switch (mips_cpu.cputype) {
+        case CPU_VR4111:
+        case CPU_VR4121:
+                vr41xx_cmu_base = VR4111_CMUCLKMSK;
+                break;
+        case CPU_VR4122:
+        case CPU_VR4131:
+                vr41xx_cmu_base = VR4122_CMUCLKMSK;
+                break;
+	default:
+		panic("Unexpected CPU of NEC VR4100 series");
+		break;
+        }
+
+	cmuclkmsk = mask;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/common/giu.c linux-2.4.20/arch/mips/vr41xx/common/giu.c
--- linux-2.4.19/arch/mips/vr41xx/common/giu.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/common/giu.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,270 @@
+/*
+ * FILE NAME
+ *	arch/mips/vr41xx/common/giu.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	General-purpose I/O Unit Interrupt routines for NEC VR4100 series.
+ *
+ * Author: Yoichi Yuasa
+ *         yyuasa@mvista.com or source@mvista.com
+ *
+ * Copyright 2002 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.
+ */
+/*
+ * Changes:
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - New creation, NEC VR4111, VR4121, VR4122 and VR4131 are supported.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <asm/addrspace.h>
+#include <asm/cpu.h>
+#include <asm/io.h>
+#include <asm/vr41xx/vr41xx.h>
+
+#define VR4111_GIUIOSELL	KSEG1ADDR(0x0b000100)
+#define VR4122_GIUIOSELL	KSEG1ADDR(0x0f000140)
+
+#define GIUIOSELL	0x00
+#define GIUIOSELH	0x02
+#define GIUINTSTATL	0x08
+#define GIUINTSTATH	0x0a
+#define GIUINTENL	0x0c
+#define GIUINTENH	0x0e
+#define GIUINTTYPL	0x10
+#define GIUINTTYPH	0x12
+#define GIUINTALSELL	0x14
+#define GIUINTALSELH	0x16
+#define GIUINTHTSELL	0x18
+#define GIUINTHTSELH	0x1a
+
+u32 vr41xx_giu_base = 0;
+
+#define read_giuint(offset)		readw(vr41xx_giu_base + (offset))
+#define write_giuint(val, offset)	writew((val), vr41xx_giu_base + (offset))
+
+static inline u16 set_giuint(u16 offset, u16 set)
+{
+	u16 res;
+
+	res = read_giuint(offset);
+	res |= set;
+	write_giuint(res, offset);
+
+	return res;
+}
+
+static inline u16 clear_giuint(u16 offset, u16 clear)
+{
+	u16 res;
+
+	res = read_giuint(offset);
+	res &= ~clear;
+	write_giuint(res, offset);
+
+	return res;
+}
+
+void vr41xx_enable_giuint(u8 pin)
+{
+	if (pin < 16)
+		set_giuint(GIUINTENL, (u16)1 << pin);
+	else
+		set_giuint(GIUINTENH, (u16)1 << (pin - 16));
+}
+
+void vr41xx_disable_giuint(u8 pin)
+{
+	if (pin < 16)
+		clear_giuint(GIUINTENL, (u16)1 << pin);
+	else
+		clear_giuint(GIUINTENH, (u16)1 << (pin - 16));
+}
+
+void vr41xx_clear_giuint(u8 pin)
+{
+	if (pin < 16)
+		write_giuint(GIUINTSTATL, (u16)1 << pin);
+	else
+		write_giuint(GIUINTSTATH, (u16)1 << (pin - 16));
+}
+
+void vr41xx_set_irq_trigger(u8 pin, u8 trigger, u8 hold)
+{
+	u16 mask;
+
+	if (pin < 16) {
+		mask = (u16)1 << pin;
+		if (trigger == TRIGGER_EDGE) {
+        		set_giuint(GIUINTTYPL, mask);
+			if (hold == SIGNAL_HOLD)
+				set_giuint(GIUINTHTSELL, mask);
+			else
+				clear_giuint(GIUINTHTSELL, mask);
+		} else {
+			clear_giuint(GIUINTTYPL, mask);
+			clear_giuint(GIUINTHTSELL, mask);
+		}
+	} else {
+		mask = (u16)1 << (pin - 16);
+		if (trigger == TRIGGER_EDGE) {
+			set_giuint(GIUINTTYPH, mask);
+			if (hold == SIGNAL_HOLD)
+				set_giuint(GIUINTHTSELH, mask);
+			else
+				clear_giuint(GIUINTHTSELH, mask);
+		} else {
+			clear_giuint(GIUINTTYPH, mask);
+			clear_giuint(GIUINTHTSELH, mask);
+		}
+	}
+
+	vr41xx_clear_giuint(pin);
+}
+
+void vr41xx_set_irq_level(u8 pin, u8 level)
+{
+	u16 mask;
+
+	if (pin < 16) {
+		mask = (u16)1 << pin;
+		if (level == LEVEL_HIGH)
+			set_giuint(GIUINTALSELL, mask);
+		else
+			clear_giuint(GIUINTALSELL, mask);
+	} else {
+		mask = (u16)1 << (pin - 16);
+		if (level == LEVEL_HIGH)
+			set_giuint(GIUINTALSELH, mask);
+		else
+			clear_giuint(GIUINTALSELH, mask);
+	}
+
+	vr41xx_clear_giuint(pin);
+}
+
+#define GIUINT_CASCADE_IRQ	16
+#define GIUINT_NR_IRQS		32
+
+enum {
+	GIUINT_NO_CASCADE,
+	GIUINT_CASCADE
+};
+
+struct vr41xx_giuint_cascade {
+	unsigned int flag;
+	int (*get_irq_number)(int irq);
+};
+
+static struct vr41xx_giuint_cascade giuint_cascade[GIUINT_NR_IRQS];
+static struct irqaction giu_cascade = {no_action, 0, 0, "cascade", NULL, NULL};
+
+static int no_irq_number(int irq)
+{
+	return -EINVAL;
+}
+
+int vr41xx_cascade_irq(unsigned int irq, int (*get_irq_number)(int irq))
+{
+	unsigned int pin;
+	int retval;
+
+	if (irq < GIU_IRQ(0) || irq > GIU_IRQ(31))
+		return -EINVAL;
+
+	if(!get_irq_number)
+		return -EINVAL;
+
+	pin = irq - GIU_IRQ(0);
+	giuint_cascade[pin].flag = GIUINT_CASCADE;
+	giuint_cascade[pin].get_irq_number = get_irq_number;
+
+	retval = setup_irq(irq, &giu_cascade);
+	if (retval) {
+		giuint_cascade[pin].flag = GIUINT_NO_CASCADE;
+		giuint_cascade[pin].get_irq_number = no_irq_number;
+	}
+
+	return retval;
+}
+
+extern unsigned int do_IRQ(int irq, struct pt_regs *regs);
+
+unsigned int giuint_do_IRQ(int pin, struct pt_regs *regs)
+{
+	struct vr41xx_giuint_cascade *cascade;
+	unsigned int retval = 0;
+	int giuint_irq, cascade_irq;
+
+	disable_irq(GIUINT_CASCADE_IRQ);
+	cascade = &giuint_cascade[pin];
+	giuint_irq = pin + GIU_IRQ(0);
+	if (cascade->flag == GIUINT_CASCADE) {
+		cascade_irq = cascade->get_irq_number(giuint_irq);
+		disable_irq(giuint_irq);
+		if (cascade_irq > 0)
+			retval = do_IRQ(cascade_irq, regs);
+		enable_irq(giuint_irq);
+	} else
+		retval = do_IRQ(giuint_irq, regs);
+	enable_irq(GIUINT_CASCADE_IRQ);
+
+	return retval;
+}
+
+void (*board_irq_init)(void) = NULL;
+
+void __init vr41xx_giuint_init(void)
+{
+	int i;
+
+	switch (mips_cpu.cputype) {
+	case CPU_VR4111:
+	case CPU_VR4121:
+		vr41xx_giu_base = VR4111_GIUIOSELL;
+		break;
+	case CPU_VR4122:
+	case CPU_VR4131:
+		vr41xx_giu_base = VR4122_GIUIOSELL;
+		break;
+	default:
+		panic("GIU: Unexpected CPU of NEC VR4100 series");
+		break;
+	}
+
+	for (i = 0; i < GIUINT_NR_IRQS; i++) {
+                vr41xx_disable_giuint(i);
+		giuint_cascade[i].flag = GIUINT_NO_CASCADE;
+		giuint_cascade[i].get_irq_number = no_irq_number;
+	}
+
+	if (setup_irq(GIUINT_CASCADE_IRQ, &giu_cascade))
+		printk("GIUINT: Can not cascade IRQ %d.\n", GIUINT_CASCADE_IRQ);
+
+	if (board_irq_init)
+		board_irq_init();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/common/icu.c linux-2.4.20/arch/mips/vr41xx/common/icu.c
--- linux-2.4.19/arch/mips/vr41xx/common/icu.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/common/icu.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,422 @@
+/*
+ * FILE NAME
+ *	arch/mips/vr41xx/vr4122/common/icu.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Interrupt Control Unit routines for the NEC VR4122 and VR4131.
+ *
+ * Author: Yoichi Yuasa
+ *         yyuasa@mvista.com or source@mvista.com
+ *
+ * Copyright 2001,2002 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.
+ */
+/*
+ * Changes:
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - Added support for NEC VR4111 and VR4121.
+ *
+ *  Paul Mundt <lethal@chaoticdreams.org>
+ *  - kgdb support.
+ *
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - New creation, NEC VR4122 and VR4131 are supported.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/types.h>
+
+#include <asm/addrspace.h>
+#include <asm/cpu.h>
+#include <asm/gdb-stub.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <asm/vr41xx/vr41xx.h>
+
+#define MIPS_CPU_IRQ_BASE	0
+#define SYSINT1_IRQ_BASE	8
+#define SYSINT1_IRQ_LAST	23
+#define SYSINT2_IRQ_BASE	24
+#define SYSINT2_IRQ_LAST	39
+#define GIUINT_IRQ_BASE		GIU_IRQ(0)
+#define GIUINT_IRQ_LAST		GIU_IRQ(31)
+
+#define ICU_CASCADE_IRQ		(MIPS_CPU_IRQ_BASE + 2)
+
+extern asmlinkage void vr41xx_handle_interrupt(void);
+
+extern void __init init_generic_irq(void);
+extern void mips_cpu_irq_init(u32 irq_base);
+extern unsigned int do_IRQ(int irq, struct pt_regs *regs);
+
+extern void vr41xx_giuint_init(void);
+extern unsigned int giuint_do_IRQ(int pin, struct pt_regs *regs);
+
+static u32 vr41xx_icu1_base = 0;
+static u32 vr41xx_icu2_base = 0;
+
+#define VR4111_SYSINT1REG	KSEG1ADDR(0x0b000080)
+#define VR4111_SYSINT2REG	KSEG1ADDR(0x0b000200)
+
+#define VR4122_SYSINT1REG	KSEG1ADDR(0x0f000080)
+#define VR4122_SYSINT2REG	KSEG1ADDR(0x0f0000a0)
+
+#define SYSINT1REG	0x00
+#define GIUINTLREG	0x08
+#define MSYSINT1REG	0x0c
+#define MGIUINTLREG	0x14
+#define NMIREG		0x18
+#define SOFTREG		0x1a
+
+#define SYSINT2REG	0x00
+#define GIUINTHREG	0x02
+#define MSYSINT2REG	0x06
+#define MGIUINTHREG	0x08
+
+#define read_icu1(offset)	readw(vr41xx_icu1_base + (offset))
+#define write_icu1(val, offset)	writew((val), vr41xx_icu1_base + (offset))
+
+#define read_icu2(offset)	readw(vr41xx_icu2_base + (offset))
+#define write_icu2(val, offset)	writew((val), vr41xx_icu2_base + (offset))
+
+static inline u16 set_icu1(u16 offset, u16 set)
+{
+	u16 res;
+
+	res = read_icu1(offset);
+	res |= set;
+	write_icu1(res, offset);
+
+	return res;
+}
+
+static inline u16 clear_icu1(u16 offset, u16 clear)
+{
+	u16 res;
+
+	res = read_icu1(offset);
+	res &= ~clear;
+	write_icu1(res, offset);
+
+	return res;
+}
+
+static inline u16 set_icu2(u16 offset, u16 set)
+{
+	u16 res;
+
+	res = read_icu2(offset);
+	res |= set;
+	write_icu2(res, offset);
+
+	return res;
+}
+
+static inline u16 clear_icu2(u16 offset, u16 clear)
+{
+	u16 res;
+
+	res = read_icu2(offset);
+	res &= ~clear;
+	write_icu2(res, offset);
+
+	return res;
+}
+
+/*=======================================================================*/
+
+static void enable_sysint1_irq(unsigned int irq)
+{
+	set_icu1(MSYSINT1REG, (u16)1 << (irq - SYSINT1_IRQ_BASE));
+}
+
+static void disable_sysint1_irq(unsigned int irq)
+{
+	clear_icu1(MSYSINT1REG, (u16)1 << (irq - SYSINT1_IRQ_BASE));
+}
+
+static unsigned int startup_sysint1_irq(unsigned int irq)
+{
+	set_icu1(MSYSINT1REG, (u16)1 << (irq - SYSINT1_IRQ_BASE));
+
+	return 0; /* never anything pending */
+}
+
+#define shutdown_sysint1_irq	disable_sysint1_irq
+#define ack_sysint1_irq		disable_sysint1_irq
+
+static void end_sysint1_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		set_icu1(MSYSINT1REG, (u16)1 << (irq - SYSINT1_IRQ_BASE));
+}
+
+static struct hw_interrupt_type sysint1_irq_type = {
+	"SYSINT1",
+	startup_sysint1_irq,
+	shutdown_sysint1_irq,
+	enable_sysint1_irq,
+	disable_sysint1_irq,
+	ack_sysint1_irq,
+	end_sysint1_irq,
+	NULL
+};
+
+/*=======================================================================*/
+
+static void enable_sysint2_irq(unsigned int irq)
+{
+	set_icu2(MSYSINT2REG, (u16)1 << (irq - SYSINT2_IRQ_BASE));
+}
+
+static void disable_sysint2_irq(unsigned int irq)
+{
+	clear_icu2(MSYSINT2REG, (u16)1 << (irq - SYSINT2_IRQ_BASE));
+}
+
+static unsigned int startup_sysint2_irq(unsigned int irq)
+{
+	set_icu2(MSYSINT2REG, (u16)1 << (irq - SYSINT2_IRQ_BASE));
+
+	return 0; /* never anything pending */
+}
+
+#define shutdown_sysint2_irq	disable_sysint2_irq
+#define ack_sysint2_irq		disable_sysint2_irq
+
+static void end_sysint2_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		set_icu2(MSYSINT2REG, (u16)1 << (irq - SYSINT2_IRQ_BASE));
+}
+
+static struct hw_interrupt_type sysint2_irq_type = {
+	"SYSINT2",
+	startup_sysint2_irq,
+	shutdown_sysint2_irq,
+	enable_sysint2_irq,
+	disable_sysint2_irq,
+	ack_sysint2_irq,
+	end_sysint2_irq,
+	NULL
+};
+
+/*=======================================================================*/
+
+extern void vr41xx_enable_giuint(u8 pin);
+extern void vr41xx_disable_giuint(u8 pin);
+extern void vr41xx_clear_giuint(u8 pin);
+
+static void enable_giuint_irq(unsigned int irq)
+{
+	u8 pin;
+
+	pin = irq - GIUINT_IRQ_BASE;
+	if (pin < 16)
+		set_icu1(MGIUINTLREG, (u16)1 << pin);
+	else
+		set_icu2(MGIUINTHREG, (u16)1 << (pin - 16));
+
+	vr41xx_enable_giuint(pin);
+}
+
+static void disable_giuint_irq(unsigned int irq)
+{
+	u8 pin;
+
+	pin = irq - GIUINT_IRQ_BASE;
+	vr41xx_disable_giuint(pin);
+
+	if (pin < 16)
+		clear_icu1(MGIUINTLREG, (u16)1 << pin);
+	else
+		clear_icu2(MGIUINTHREG, (u16)1 << (pin - 16));
+}
+
+static unsigned int startup_giuint_irq(unsigned int irq)
+{
+	vr41xx_clear_giuint(irq - GIUINT_IRQ_BASE);
+
+	enable_giuint_irq(irq);
+
+	return 0; /* never anything pending */
+}
+
+#define shutdown_giuint_irq	disable_giuint_irq
+
+static void ack_giuint_irq(unsigned int irq)
+{
+	disable_giuint_irq(irq);
+
+	vr41xx_clear_giuint(irq - GIUINT_IRQ_BASE);
+}
+
+static void end_giuint_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		enable_giuint_irq(irq);
+}
+
+static struct hw_interrupt_type giuint_irq_type = {
+	"GIUINT",
+	startup_giuint_irq,
+	shutdown_giuint_irq,
+	enable_giuint_irq,
+	disable_giuint_irq,
+	ack_giuint_irq,
+	end_giuint_irq,
+	NULL
+};
+
+/*=======================================================================*/
+
+static struct irqaction icu_cascade = {no_action, 0, 0, "cascade", NULL, NULL};
+
+static void __init vr41xx_icu_init(void)
+{
+	int i;
+
+	switch (mips_cpu.cputype) {
+	case CPU_VR4111:
+	case CPU_VR4121:
+		vr41xx_icu1_base = VR4111_SYSINT1REG;
+		vr41xx_icu2_base = VR4111_SYSINT2REG;
+		break;
+	case CPU_VR4122:
+	case CPU_VR4131:
+		vr41xx_icu1_base = VR4122_SYSINT1REG;
+		vr41xx_icu2_base = VR4122_SYSINT2REG;
+		break;
+	default:
+		panic("Unexpected CPU of NEC VR4100 series");
+		break;
+	}
+
+	write_icu1(0, MSYSINT1REG);
+	write_icu1(0, MGIUINTLREG);
+
+	write_icu2(0, MSYSINT2REG);
+	write_icu2(0, MGIUINTHREG);
+
+	for (i = SYSINT1_IRQ_BASE; i <= GIUINT_IRQ_LAST; i++) {
+		if (i >= SYSINT1_IRQ_BASE && i <= SYSINT1_IRQ_LAST)
+			irq_desc[i].handler = &sysint1_irq_type;
+		else if (i >= SYSINT2_IRQ_BASE && i <= SYSINT2_IRQ_LAST)
+			irq_desc[i].handler = &sysint2_irq_type;
+		else if (i >= GIUINT_IRQ_BASE && i <= GIUINT_IRQ_LAST)
+			irq_desc[i].handler = &giuint_irq_type;
+	}
+
+	setup_irq(ICU_CASCADE_IRQ, &icu_cascade);
+}
+
+void __init init_IRQ(void)
+{
+	memset(irq_desc, 0, sizeof(irq_desc));
+
+	init_generic_irq();
+	mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
+	vr41xx_icu_init();
+
+	vr41xx_giuint_init();
+
+	set_except_vector(0, vr41xx_handle_interrupt);
+
+#ifdef CONFIG_REMOTE_DEBUG
+	printk("Setting debug traps - please connect the remote debugger.\n");
+	set_debug_traps();
+	breakpoint();
+#endif
+}
+
+/*=======================================================================*/
+
+static inline void giuint_irqdispatch(u16 pendl, u16 pendh, struct pt_regs *regs)
+{
+	int i;
+
+	if (pendl) {
+		for (i = 0; i < 16; i++) {
+			if (pendl & (0x0001 << i)) {
+				giuint_do_IRQ(i, regs);
+				return;
+			}
+		}
+	}
+	else if (pendh) {
+		for (i = 0; i < 16; i++) {
+			if (pendh & (0x0001 << i)) {
+				giuint_do_IRQ(i + 16, regs);
+				return;
+			}
+		}
+	}
+}
+
+asmlinkage void icu_irqdispatch(struct pt_regs *regs)
+{
+	u16 pend1, pend2, pendl, pendh;
+	u16 mask1, mask2, maskl, maskh;
+	int i;
+
+	pend1 = read_icu1(SYSINT1REG);
+	mask1 = read_icu1(MSYSINT1REG);
+
+	pend2 = read_icu2(SYSINT2REG);
+	mask2 = read_icu2(MSYSINT2REG);
+
+	pendl = read_icu1(GIUINTLREG);
+	maskl = read_icu1(MGIUINTLREG);
+
+	pendh = read_icu2(GIUINTHREG);
+	maskh = read_icu2(MGIUINTHREG);
+
+	pend1 &= mask1;
+	pend2 &= mask2;
+	pendl &= maskl;
+	pendh &= maskh;
+
+	if (pend1) {
+		if ((pend1 & 0x01ff) == 0x0100) {
+			giuint_irqdispatch(pendl, pendh, regs);
+		}
+		else {
+			for (i = 0; i < 16; i++) {
+				if (pend1 & (0x0001 << i)) {
+					do_IRQ(SYSINT1_IRQ_BASE + i, regs);
+					break;
+				}
+			}
+		}
+		return;
+	}
+	else if (pend2) {
+		for (i = 0; i < 16; i++) {
+			if (pend2 & (0x0001 << i)) {
+				do_IRQ(SYSINT2_IRQ_BASE + i, regs);
+				break;
+			}
+		}
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/common/int-handler.S linux-2.4.20/arch/mips/vr41xx/common/int-handler.S
--- linux-2.4.19/arch/mips/vr41xx/common/int-handler.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/common/int-handler.S	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,114 @@
+/*
+ * FILE NAME
+ *	arch/mips/vr41xx/common/int-handler.S
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Interrupt dispatcher for the NEC VR4100 series.
+ *
+ * Author: Yoichi Yuasa
+ *         yyuasa@mvista.com or source@mvista.com
+ *
+ * Copyright 2001 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.
+ */
+/*
+ * Changes:
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - New creation, NEC VR4100 series are supported.
+ */
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/stackframe.h>
+
+		.text
+		.set	noreorder
+
+		.align	5
+		NESTED(vr41xx_handle_interrupt, PT_SIZE, ra)
+		.set	noat
+		SAVE_ALL
+		CLI
+		.set	at
+		.set	noreorder
+
+		/*
+		 * Get the pending interrupts
+		 */
+		mfc0	t0, CP0_CAUSE
+		mfc0	t1, CP0_STATUS
+		andi	t0, 0xff00
+		and	t0, t0, t1
+
+		andi	t1, t0, CAUSEF_IP7	# timer interrupt
+		beqz	t1, 1f
+		li	a0, 7
+		jal	ll_timer_interrupt
+		move	a1, sp
+		j	ret_from_irq
+
+1:
+		andi	t1, t0, 0x7800		# check for IP3-6
+		beqz	t1, 2f
+
+		andi	t1, t0, CAUSEF_IP3	# check for IP3
+		bnez	t1, handle_it
+		li	a0, 3
+
+		andi	t1, t0, CAUSEF_IP4	# check for IP4
+		bnez	t1, handle_it
+		li	a0, 4
+
+		andi	t1, t0, CAUSEF_IP5	# check for IP5
+		bnez	t1, handle_it
+		li	a0, 5
+
+		andi	t1, t0, CAUSEF_IP6	# check for IP6
+		bnez	t1, handle_it
+		li	a0, 6
+
+2:
+		andi	t1, t0, CAUSEF_IP2	# check for IP2
+		beqz	t1, 3f
+		move	a0, sp
+		jal	icu_irqdispatch
+		nop
+		j	ret_from_irq
+		nop
+
+3:
+		andi	t1, t0, CAUSEF_IP0	# check for IP0
+		bnez	t1, handle_it
+		li	a0, 0
+
+		andi	t1, t0, CAUSEF_IP1	# check for IP1
+		bnez	t1, handle_it
+		li	a0, 1
+
+		j	spurious_interrupt
+		nop
+
+handle_it:
+		jal	do_IRQ
+		move	a1, sp
+		j	ret_from_irq
+		END(vr41xx_handle_interrupt)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/common/pciu.c linux-2.4.20/arch/mips/vr41xx/common/pciu.c
--- linux-2.4.19/arch/mips/vr41xx/common/pciu.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/common/pciu.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,280 @@
+/*
+ * FILE NAME
+ *	arch/mips/vr41xx/common/pciu.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	PCI Control Unit routines for the NEC VR4100 series.
+ *
+ * Author: Yoichi Yuasa
+ *         yyuasa@mvista.com or source@mvista.com
+ *
+ * Copyright 2001,2002 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.
+ */
+/*
+ * Changes:
+ *  Paul Mundt <lethal@chaoticdreams.org>
+ *  - Fix deadlock-causing PCIU access race for VR4131.
+ *
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - New creation, NEC VR4122 and VR4131 are supported.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#include <asm/cpu.h>
+#include <asm/io.h>
+#include <asm/pci_channel.h>
+#include <asm/vr41xx/vr41xx.h>
+
+#include "pciu.h"
+
+extern unsigned long vr41xx_vtclock;
+
+static inline int vr41xx_pci_config_access(struct pci_dev *dev, int where)
+{
+	unsigned char bus = dev->bus->number;
+	unsigned int dev_fn = dev->devfn;
+
+	if (bus == 0) {
+		/*
+		 * Type 0 configuration
+		 */
+		if (PCI_SLOT(dev_fn) < 11 || PCI_SLOT(dev_fn) > 31 || where > 255)
+			return -1;
+
+		writel((1UL << PCI_SLOT(dev_fn))|
+		       (PCI_FUNC(dev_fn) << 8)	|
+		       (where & 0xfc),
+		       PCICONFAREG);
+	}
+	else {
+		/*
+		 * Type 1 configuration
+		 */
+		if (bus > 255 || PCI_SLOT(dev_fn) > 31 || where > 255)
+			return -1;
+
+		writel((bus << 16)	|
+		       (dev_fn << 8)	|
+		       (where & 0xfc)	|
+		       1UL,
+		       PCICONFAREG);
+	}
+
+	return 0;
+}
+
+static int vr41xx_pci_read_config_byte(struct pci_dev *dev, int where, u8 *val)
+{
+	u32 data;
+
+	*val = 0xff;
+	if (vr41xx_pci_config_access(dev, where) < 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	data = readl(PCICONFDREG);
+	*val = (u8)(data >> ((where & 3) << 3));
+
+	return PCIBIOS_SUCCESSFUL;
+
+}
+
+static int vr41xx_pci_read_config_word(struct pci_dev *dev, int where, u16 *val)
+{
+	u32 data;
+
+	*val = 0xffff;
+	if (where & 1)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	if (vr41xx_pci_config_access(dev, where) < 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	data = readl(PCICONFDREG);
+	*val = (u16)(data >> ((where & 2) << 3));
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int vr41xx_pci_read_config_dword(struct pci_dev *dev, int where, u32 *val)
+{
+	*val = 0xffffffff;
+	if (where & 3)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	if (vr41xx_pci_config_access(dev, where) < 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*val = readl(PCICONFDREG);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int vr41xx_pci_write_config_byte(struct pci_dev *dev, int where, u8 val)
+{
+	u32 data;
+	int shift;
+
+	if (vr41xx_pci_config_access(dev, where) < 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	data = readl(PCICONFDREG);
+	shift = (where & 3) << 3;
+	data &= ~(0xff << shift);
+	data |= (((u32)val) << shift);
+
+	writel(data, PCICONFDREG);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int vr41xx_pci_write_config_word(struct pci_dev *dev, int where, u16 val)
+{
+	u32 data;
+	int shift;
+
+	if (where & 1)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	if (vr41xx_pci_config_access(dev, where) < 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	data = readl(PCICONFDREG);
+	shift = (where & 2) << 3;
+	data &= ~(0xffff << shift);
+	data |= (((u32)val) << shift);
+	writel(data, PCICONFDREG);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int vr41xx_pci_write_config_dword(struct pci_dev *dev, int where, u32 val)
+{
+	if (where & 3)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	if (vr41xx_pci_config_access(dev, where) < 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	writel(val, PCICONFDREG);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops vr41xx_pci_ops = {
+	vr41xx_pci_read_config_byte,
+	vr41xx_pci_read_config_word,
+	vr41xx_pci_read_config_dword,
+	vr41xx_pci_write_config_byte,
+	vr41xx_pci_write_config_word,
+	vr41xx_pci_write_config_dword
+};
+
+void __init vr41xx_pciu_init(struct vr41xx_pci_address_map *map)
+{
+	struct vr41xx_pci_address_space *s;
+	u32 config;
+	int n;
+
+	if (!map)
+		return;
+
+	/* Disable PCI interrupt */
+	writew(0, MPCIINTREG);
+
+	/* Supply VTClock to PCIU */
+	vr41xx_clock_supply(PCIU_CLOCK);
+
+	/*
+	 * Sleep for 1us after setting MSKPPCIU bit in CMUCLKMSK
+	 * before doing any PCIU access to avoid deadlock on VR4131.
+	 */
+	udelay(1);
+
+	/* Select PCI clock */
+	if (vr41xx_vtclock < MAX_PCI_CLOCK)
+		writel(EQUAL_VTCLOCK, PCICLKSELREG);
+	else if ((vr41xx_vtclock / 2) < MAX_PCI_CLOCK)
+		writel(HALF_VTCLOCK, PCICLKSELREG);
+	else if ((vr41xx_vtclock / 4) < MAX_PCI_CLOCK)
+		writel(QUARTER_VTCLOCK, PCICLKSELREG);
+	else
+		printk(KERN_INFO "Warning: PCI Clock is over 33MHz.\n");
+
+	/* Supply PCI clock by PCI bus */
+	vr41xx_clock_supply(PCI_CLOCK);
+
+	/*
+	 * Set PCI memory & I/O space address conversion registers
+	 * for master transaction.
+	 */
+	if (map->mem1 != NULL) {
+		s = map->mem1;
+		config = (s->internal_base & 0xff000000) |
+		         ((s->address_mask & 0x7f000000) >> 11) | (1UL << 12) |
+		         ((s->pci_base & 0xff000000) >> 24);
+		writel(config, PCIMMAW1REG);
+	}
+	if (map->mem2 != NULL) {
+		s = map->mem2;
+		config = (s->internal_base & 0xff000000) |
+		         ((s->address_mask & 0x7f000000) >> 11) | (1UL << 12) |
+		         ((s->pci_base & 0xff000000) >> 24);
+		writel(config, PCIMMAW2REG);
+	}
+	if (map->io != NULL) {
+		s = map->io;
+		config = (s->internal_base & 0xff000000) |
+		         ((s->address_mask & 0x7f000000) >> 11) | (1UL << 12) |
+		         ((s->pci_base & 0xff000000) >> 24);
+		writel(config, PCIMIOAWREG);
+	}
+
+	/* Set target memory windows */
+	writel(0x00081000, PCITAW1REG);
+	writel(0UL, PCITAW2REG);
+	pciu_write_config_dword(PCI_BASE_ADDRESS_0, 0UL);
+	pciu_write_config_dword(PCI_BASE_ADDRESS_1, 0UL);
+
+	/* Clear bus error */
+	n = readl(BUSERRADREG);
+
+	if (mips_cpu.cputype == CPU_VR4122) {
+		writel(0UL, PCITRDYVREG);
+		pciu_write_config_dword(PCI_CACHE_LINE_SIZE, 0x0000f804);
+	} else {
+		writel(100UL, PCITRDYVREG);
+		pciu_write_config_dword(PCI_CACHE_LINE_SIZE, 0x00008004);
+	}
+
+	writel(CONFIG_DONE, PCIENREG);
+	pciu_write_config_dword(PCI_COMMAND,
+	                        PCI_COMMAND_IO |
+	                        PCI_COMMAND_MEMORY |
+	                        PCI_COMMAND_MASTER |
+	                        PCI_COMMAND_PARITY |
+	                        PCI_COMMAND_SERR);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/common/pciu.h linux-2.4.20/arch/mips/vr41xx/common/pciu.h
--- linux-2.4.19/arch/mips/vr41xx/common/pciu.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/common/pciu.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,167 @@
+/*
+ * FILE NAME
+ *	arch/mips/vr41xx/common/pciu.h
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Include file for PCI Control Unit of the NEC VR4100 series.
+ *
+ * Author: Yoichi Yuasa
+ *         yyuasa@mvista.com or source@mvista.com
+ *
+ * Copyright 2002 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.
+ */
+/*
+ * Changes:
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - New creation, NEC VR4122 and VR4131 are supported.
+ */
+#ifndef __VR41XX_PCIU_H
+#define __VR41XX_PCIU_H
+
+#include <linux/config.h>
+#include <asm/addrspace.h>
+
+#define BIT(x)	(1 << (x))
+
+#define PCIMMAW1REG			KSEG1ADDR(0x0f000c00)
+#define PCIMMAW2REG			KSEG1ADDR(0x0f000c04)
+#define PCITAW1REG			KSEG1ADDR(0x0f000c08)
+#define PCITAW2REG			KSEG1ADDR(0x0f000c0c)
+#define PCIMIOAWREG			KSEG1ADDR(0x0f000c10)
+#define INTERNAL_BUS_BASE_ADDRESS	0xff000000
+#define ADDRESS_MASK			0x000fe000
+#define PCI_ACCESS_ENABLE		BIT(12)
+#define PCI_ADDRESS_SETTING		0x000000ff
+
+#define PCICONFDREG			KSEG1ADDR(0x0f000c14)
+#define PCICONFAREG			KSEG1ADDR(0x0f000c18)
+#define PCIMAILREG			KSEG1ADDR(0x0f000c1c)
+
+#define BUSERRADREG			KSEG1ADDR(0x0f000c24)
+#define ERROR_ADDRESS			0xfffffffc
+
+#define INTCNTSTAREG			KSEG1ADDR(0x0f000c28)
+#define MABTCLR				BIT(31)
+#define TRDYCLR				BIT(30)
+#define PARCLR				BIT(29)
+#define MBCLR				BIT(28)
+#define SERRCLR				BIT(27)
+
+#define PCIEXACCREG			KSEG1ADDR(0x0f000c2c)
+#define UNLOCK				BIT(1)
+#define EAREQ				BIT(0)
+
+#define PCIRECONTREG			KSEG1ADDR(0x0f000c30)
+#define RTRYCNT				0x000000ff
+
+#define PCIENREG			KSEG1ADDR(0x0f000c34)
+#define CONFIG_DONE			BIT(2)
+
+#define PCICLKSELREG			KSEG1ADDR(0x0f000c38)
+#define EQUAL_VTCLOCK			0x00000002
+#define HALF_VTCLOCK			0x00000000
+#define QUARTER_VTCLOCK			0x00000001
+
+#define PCITRDYVREG			KSEG1ADDR(0x0f000c3c)
+
+#define PCICLKRUNREG			KSEG1ADDR(0x0f000c60)
+
+#define PCIU_CONFIGREGS_BASE		KSEG1ADDR(0x0f000d00)
+#define VENDORIDREG			KSEG1ADDR(0x0f000d00)
+#define DEVICEIDREG			KSEG1ADDR(0x0f000d00)
+#define COMMANDREG			KSEG1ADDR(0x0f000d04)
+#define STATUSREG			KSEG1ADDR(0x0f000d04)
+#define REVIDREG			KSEG1ADDR(0x0f000d08)
+#define CLASSREG			KSEG1ADDR(0x0f000d08)
+#define CACHELSREG			KSEG1ADDR(0x0f000d0c)
+#define LATTIMEREG			KSEG1ADDR(0x0f000d0c)
+#define MAILBAREG			KSEG1ADDR(0x0f000d10)
+#define PCIMBA1REG			KSEG1ADDR(0x0f000d14)
+#define PCIMBA2REG			KSEG1ADDR(0x0f000d18)
+#define INTLINEREG			KSEG1ADDR(0x0f000d3c)
+#define INTPINREG			KSEG1ADDR(0x0f000d3c)
+#define RETVALREG			KSEG1ADDR(0x0f000d40)
+#define PCIAPCNTREG			KSEG1ADDR(0x0f000d40)
+
+#define MPCIINTREG			KSEG1ADDR(0x0f0000b2)
+
+#define MAX_PCI_CLOCK			33333333
+
+#define PCIU_CLOCK			0x0080
+#define PCI_CLOCK			0x2000
+
+static inline int pciu_read_config_byte(int where, u8 *val)
+{
+	u32 data;
+
+	data = readl(PCIU_CONFIGREGS_BASE + where);
+	*val = (u8)(data >> ((where & 3) << 3));
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static inline int pciu_read_config_word(int where, u16 *val)
+{
+	u32 data;
+
+	if (where & 1)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	data = readl(PCIU_CONFIGREGS_BASE + where);
+	*val = (u16)(data >> ((where & 2) << 3));
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static inline int pciu_read_config_dword(int where, u32 *val)
+{
+	if (where & 3)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	*val = readl(PCIU_CONFIGREGS_BASE + where);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static inline int pciu_write_config_byte(int where, u8 val)
+{
+	writel(val, PCIU_CONFIGREGS_BASE + where);
+
+	return 0;
+}
+
+static inline int pciu_write_config_word(int where, u16 val)
+{
+	writel(val, PCIU_CONFIGREGS_BASE + where);
+
+	return 0;
+}
+
+static inline int pciu_write_config_dword(int where, u32 val)
+{
+	writel(val, PCIU_CONFIGREGS_BASE + where);
+
+	return 0;
+}
+
+#endif /* __VR41XX_PCIU_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/common/reset.c linux-2.4.20/arch/mips/vr41xx/common/reset.c
--- linux-2.4.19/arch/mips/vr41xx/common/reset.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/common/reset.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 1997, 2001 Ralf Baechle
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/reboot.h>
+#include <asm/system.h>
+
+void vr41xx_restart(char *command)
+{
+	change_cp0_status((ST0_BEV | ST0_ERL), (ST0_BEV | ST0_ERL));
+	change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
+	flush_cache_all();
+	write_32bit_cp0_register(CP0_WIRED, 0);
+	__asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
+}
+
+void vr41xx_halt(void)
+{
+	printk(KERN_NOTICE "\n** You can safely turn off the power\n");
+	while (1);
+}
+
+void vr41xx_power_off(void)
+{
+	vr41xx_halt();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/common/serial.c linux-2.4.20/arch/mips/vr41xx/common/serial.c
--- linux-2.4.19/arch/mips/vr41xx/common/serial.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/common/serial.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,178 @@
+/*
+ * FILE NAME
+ *	arch/mips/vr41xx/common/serial.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Serial Interface Unit routines for NEC VR4100 series.
+ *
+ * Author: Yoichi Yuasa
+ *         yyuasa@mvista.com or source@mvista.com
+ *
+ * Copyright 2002 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.
+ */
+/*
+ * Changes:
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - Added support for NEC VR4111 and VR4121.
+ *
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - New creation, NEC VR4122 and VR4131 are supported.
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/serial.h>
+
+#include <asm/addrspace.h>
+#include <asm/cpu.h>
+#include <asm/io.h>
+#include <asm/vr41xx/vr41xx.h>
+
+/* VR4111 and VR4121 SIU Registers */
+#define VR4111_SIURB		KSEG1ADDR(0x0c000000)
+#define VR4111_SIUIRSEL		KSEG1ADDR(0x0c000008)
+
+/* VR4122 and VR4131 SIU Registers */
+#define VR4122_SIURB		KSEG1ADDR(0x0f000800)
+#define VR4122_SIUIRSEL		KSEG1ADDR(0x0f000808)
+
+ #define USE_RS232C		0x00
+ #define USE_IRDA		0x01
+ #define SIU_USES_IRDA		0x00
+ #define FIR_USES_IRDA		0x02
+ #define IRDA_MODULE_SHARP	0x00
+ #define IRDA_MODULE_TEMIC	0x04
+ #define IRDA_MODULE_HP		0x08
+ #define TMICTX			0x10
+ #define TMICMODE		0x20
+
+#define SIU_BASE_BAUD		1152000
+#define SIU_CLOCK		0x0102
+#define SIU_IRQ			17
+
+/* VR4122 and VR4131 DSIU Registers */
+#define DSIURB			KSEG1ADDR(0x0f000820)
+
+#define MDSIUINTREG		KSEG1ADDR(0x0f000096)
+ #define INTDSIU		0x0800
+
+#define DSIU_BASE_BAUD		1152000
+#define DSIU_CLOCK		0x0802
+#define DSIU_IRQ		29
+
+int vr41xx_serial_ports = 0;
+
+void vr41xx_siu_ifselect(int interface, int module)
+{
+	u16 val = USE_RS232C;	/* Select RS-232C */
+
+	/* Select IrDA */
+	if (interface == SIU_IRDA) {
+		switch (module) {
+		case IRDA_SHARP:
+			val = IRDA_MODULE_SHARP;
+			break;
+		case IRDA_TEMIC:
+			val = IRDA_MODULE_TEMIC;
+			break;
+		case IRDA_HP:
+			val = IRDA_MODULE_HP;
+			break;
+		}
+		val |= USE_IRDA | SIU_USES_IRDA;
+	}
+
+	switch (mips_cpu.cputype) {
+	case CPU_VR4111:
+	case CPU_VR4121:
+		writew(val, VR4111_SIUIRSEL);
+		break;
+	case CPU_VR4122:
+	case CPU_VR4131:
+		writew(val, VR4122_SIUIRSEL);
+		break;
+	default:
+		printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n");
+		break;
+	}
+}
+
+void __init vr41xx_siu_init(int interface, int module)
+{
+	struct serial_struct s;
+
+	vr41xx_siu_ifselect(interface, module);
+
+	memset(&s, 0, sizeof(s));
+
+	s.line = vr41xx_serial_ports;
+	s.baud_base = SIU_BASE_BAUD;
+	s.irq = SIU_IRQ;
+	s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+	switch (mips_cpu.cputype) {
+	case CPU_VR4111:
+	case CPU_VR4121:
+		s.iomem_base = (unsigned char *)VR4111_SIURB;
+		break;
+	case CPU_VR4122:
+	case CPU_VR4131:
+		s.iomem_base = (unsigned char *)VR4122_SIURB;
+		break;
+	default:
+		panic("Unexpected CPU of NEC VR4100 series");
+		break;
+	}
+	s.iomem_reg_shift = 0;
+	s.io_type = SERIAL_IO_MEM;
+	if (early_serial_setup(&s) != 0)
+		printk(KERN_ERR "SIU setup failed!\n");
+
+	vr41xx_clock_supply(SIU_CLOCK);
+
+	vr41xx_serial_ports++;
+}
+
+void __init vr41xx_dsiu_init(void)
+{
+	struct serial_struct s;
+
+	if (mips_cpu.cputype != CPU_VR4122 && mips_cpu.cputype != CPU_VR4131)
+		return;
+
+	memset(&s, 0, sizeof(s));
+
+	s.line = vr41xx_serial_ports;
+	s.baud_base = DSIU_BASE_BAUD;
+	s.irq = DSIU_IRQ;
+	s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+	s.iomem_base = (unsigned char *)DSIURB;
+	s.iomem_reg_shift = 0;
+	s.io_type = SERIAL_IO_MEM;
+	if (early_serial_setup(&s) != 0)
+		printk(KERN_ERR "DSIU setup failed!\n");
+
+	vr41xx_clock_supply(DSIU_CLOCK);
+
+	writew(INTDSIU, MDSIUINTREG);
+
+	vr41xx_serial_ports++;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/common/time.c linux-2.4.20/arch/mips/vr41xx/common/time.c
--- linux-2.4.19/arch/mips/vr41xx/common/time.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/common/time.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,94 @@
+/*
+ * FILE NAME
+ *	arch/mips/vr41xx/common/time.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Timer routines for the NEC VR4100 series.
+ *
+ * Author: Yoichi Yuasa
+ *         yyuasa@mvista.com or source@mvista.com
+ *
+ * Copyright 2001,2002 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.
+ */
+/*
+ * Changes:
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - Added support for NEC VR4100 series RTC Unit.
+ *
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - New creation, NEC VR4100 series are supported.
+ */
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/types.h>
+
+#include <asm/cpu.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <asm/param.h>
+#include <asm/time.h>
+
+#define MIPS_COUNTER_TIMER_IRQ	7
+
+#define VR4111_ETIMELREG	KSEG1ADDR(0x0b0000c0)
+#define VR4122_ETIMELREG	KSEG1ADDR(0x0f000100)
+
+u32 vr41xx_rtc_base = 0;
+
+#ifdef CONFIG_VR41XX_RTC
+extern unsigned long vr41xx_rtc_get_time(void);
+extern int vr41xx_rtc_set_time(unsigned long sec);
+#endif
+
+void vr41xx_time_init(void)
+{
+	switch (mips_cpu.cputype) {
+	case CPU_VR4111:
+	case CPU_VR4121:
+		vr41xx_rtc_base = VR4111_ETIMELREG;
+		break;
+	case CPU_VR4122:
+	case CPU_VR4131:
+                vr41xx_rtc_base = VR4122_ETIMELREG;
+                break;
+        default:
+                panic("Unexpected CPU of NEC VR4100 series");
+                break;
+        }
+
+#ifdef CONFIG_VR41XX_RTC
+        rtc_get_time = vr41xx_rtc_get_time;
+        rtc_set_time = vr41xx_rtc_set_time;
+#endif
+}
+
+void vr41xx_timer_setup(struct irqaction *irq)
+{
+	u32 count;
+
+	setup_irq(MIPS_COUNTER_TIMER_IRQ, irq);
+
+	count = read_32bit_cp0_register(CP0_COUNT);
+	write_32bit_cp0_register (CP0_COMPARE, count + (mips_counter_frequency / HZ));
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/nec-eagle/Makefile linux-2.4.20/arch/mips/vr41xx/nec-eagle/Makefile
--- linux-2.4.19/arch/mips/vr41xx/nec-eagle/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/nec-eagle/Makefile	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,25 @@
+#
+# Makefile for the NEC Eagle/Hawk specific parts of the kernel
+#
+# Author: Yoichi Yuasa
+#         yyuasa@mvista.com or source@mvista.com
+#
+# Copyright 2001,2002 MontaVista Software Inc.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+USE_STANDARD_AS_RULE := true
+
+O_TARGET := eagle.o
+
+all: eagle.o
+
+obj-y	:= init.o irq.o setup.o
+
+obj-$(CONFIG_IDE)	+= ide-eagle.o
+obj-$(CONFIG_PCI)	+= pci_fixup.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/nec-eagle/ide-eagle.c linux-2.4.20/arch/mips/vr41xx/nec-eagle/ide-eagle.c
--- linux-2.4.19/arch/mips/vr41xx/nec-eagle/ide-eagle.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/nec-eagle/ide-eagle.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,96 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * IDE routines for typical pc-like standard configurations
+ * for the NEC Eagle/Hawk board.
+ *
+ * Copyright (C) 1998, 1999, 2001 by Ralf Baechle
+ */
+/*
+ * Changes:
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  Fri,  5 Apr 2002
+ *  - Added support for NEC Hawk.
+ *
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  Fri,  1 Mar 2002
+ *  - Added support for NEC Eagle.
+ */
+#include <linux/sched.h>
+#include <linux/ide.h>
+#include <linux/ioport.h>
+#include <linux/hdreg.h>
+#include <asm/ptrace.h>
+#include <asm/hdreg.h>
+
+static int eagle_ide_default_irq(ide_ioreg_t base)
+{
+	return 0;
+}
+
+static ide_ioreg_t eagle_ide_default_io_base(int index)
+{
+	return 0;
+}
+
+static void eagle_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port,
+                                      ide_ioreg_t ctrl_port, int *irq)
+{
+	ide_ioreg_t reg = data_port;
+	int i;
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw->io_ports[i] = reg;
+		reg += 1;
+	}
+	if (ctrl_port) {
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+	} else {
+		hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
+	}
+	if (irq != NULL)
+		*irq = 0;
+	hw->io_ports[IDE_IRQ_OFFSET] = 0;
+}
+
+static int eagle_ide_request_irq(unsigned int irq,
+                                 void (*handler)(int,void *, struct pt_regs *),
+                                 unsigned long flags, const char *device,
+                                 void *dev_id)
+{
+	return request_irq(irq, handler, SA_SHIRQ, device, dev_id);
+}
+
+static void eagle_ide_free_irq(unsigned int irq, void *dev_id)
+{
+	free_irq(irq, dev_id);
+}
+
+static int eagle_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+	return check_region(from, extent);
+}
+
+static void eagle_ide_request_region(ide_ioreg_t from, unsigned int extent,
+                                     const char *name)
+{
+	request_region(from, extent, name);
+}
+
+static void eagle_ide_release_region(ide_ioreg_t from, unsigned int extent)
+{
+	release_region(from, extent);
+}
+
+struct ide_ops eagle_ide_ops = {
+	&eagle_ide_default_irq,
+	&eagle_ide_default_io_base,
+	&eagle_ide_init_hwif_ports,
+	&eagle_ide_request_irq,
+	&eagle_ide_free_irq,
+	&eagle_ide_check_region,
+	&eagle_ide_request_region,
+	&eagle_ide_release_region
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/nec-eagle/init.c linux-2.4.20/arch/mips/vr41xx/nec-eagle/init.c
--- linux-2.4.19/arch/mips/vr41xx/nec-eagle/init.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/nec-eagle/init.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,78 @@
+/*
+ * FILE NAME
+ *	arch/mips/vr41xx/nec-eagle/init.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Initialisation code for the NEC Eagle/Hawk board.
+ *
+ * Author: Yoichi Yuasa
+ *         yyuasa@mvista.com or source@mvista.com
+ *
+ * Copyright 2001,2002 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.
+ */
+/*
+ * Changes:
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - Added support for NEC Hawk.
+ *
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - New creation, NEC Eagle is supported.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+
+char arcs_cmdline[CL_SIZE];
+
+const char *get_system_type(void)
+{
+	return "NEC Eagle/Hawk";
+}
+
+void __init bus_error_init(void)
+{
+}
+
+void __init prom_init(int argc, char **argv, unsigned long magic, int *prom_vec)
+{
+	int i;
+
+	/*
+	 * collect args and prepare cmd_line
+	 */
+	for (i = 1; i < argc; i++) {
+		strcat(arcs_cmdline, argv[i]);
+		if (i < (argc - 1))
+			strcat(arcs_cmdline, " ");
+	}
+
+	mips_machgroup = MACH_GROUP_NEC_VR41XX;
+	mips_machtype = MACH_NEC_EAGLE;
+}
+
+void __init prom_free_prom_memory (void)
+{
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/nec-eagle/irq.c linux-2.4.20/arch/mips/vr41xx/nec-eagle/irq.c
--- linux-2.4.19/arch/mips/vr41xx/nec-eagle/irq.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/nec-eagle/irq.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,186 @@
+/*
+ * FILE NAME
+ *	arch/mips/vr41xx/nec-eagle/irq.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Interrupt routines for the NEC Eagle/Hawk board.
+ *
+ * Author: Yoichi Yuasa
+ *         yyuasa@mvista.com or source@mvista.com
+ *
+ * Copyright 2002 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.
+ */
+/*
+ * Changes:
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - Added support for NEC Hawk.
+ *
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - New creation, NEC Eagle is supported.
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/vr41xx/eagle.h>
+
+static void enable_pciint_irq(unsigned int irq)
+{
+	u8 val;
+
+	val = readb(NEC_EAGLE_PCIINTMSKREG);
+	val |= (u8)1 << (irq - PCIINT_IRQ_BASE);
+	writeb(val, NEC_EAGLE_PCIINTMSKREG);
+}
+
+static void disable_pciint_irq(unsigned int irq)
+{
+	u8 val;
+
+	val = readb(NEC_EAGLE_PCIINTMSKREG);
+	val &= ~((u8)1 << (irq - PCIINT_IRQ_BASE));
+	writeb(val, NEC_EAGLE_PCIINTMSKREG);
+}
+
+static unsigned int startup_pciint_irq(unsigned int irq)
+{
+	enable_pciint_irq(irq);
+	return 0; /* never anything pending */
+}
+
+#define shutdown_pciint_irq	disable_pciint_irq
+#define ack_pciint_irq		disable_pciint_irq
+
+static void end_pciint_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		enable_pciint_irq(irq);
+}
+
+static struct hw_interrupt_type pciint_irq_type = {
+	"PCIINT",
+	startup_pciint_irq,
+	shutdown_pciint_irq,
+       	enable_pciint_irq,
+	disable_pciint_irq,
+	ack_pciint_irq,
+	end_pciint_irq,
+	NULL
+};
+
+static void enable_sdbint_irq(unsigned int irq)
+{
+	u8 val;
+
+	val = readb(NEC_EAGLE_SDBINTMSK);
+	val |= (u8)1 << (irq - SDBINT_IRQ_BASE);
+	writeb(val, NEC_EAGLE_SDBINTMSK);
+}
+
+static void disable_sdbint_irq(unsigned int irq)
+{
+	u8 val;
+
+	val = readb(NEC_EAGLE_SDBINTMSK);
+	val &= ~((u8)1 << (irq - SDBINT_IRQ_BASE));
+	writeb(val, NEC_EAGLE_SDBINTMSK);
+}
+
+static unsigned int startup_sdbint_irq(unsigned int irq)
+{
+	enable_sdbint_irq(irq);
+	return 0; /* never anything pending */
+}
+
+#define shutdown_sdbint_irq	disable_sdbint_irq
+#define ack_sdbint_irq		disable_sdbint_irq
+
+static void end_sdbint_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		enable_sdbint_irq(irq);
+}
+
+static struct hw_interrupt_type sdbint_irq_type = {
+	"SDBINT",
+	startup_sdbint_irq,
+	shutdown_sdbint_irq,
+       	enable_sdbint_irq,
+	disable_sdbint_irq,
+	ack_sdbint_irq,
+	end_sdbint_irq,
+	NULL
+};
+
+static int eagle_get_irq_number(int irq)
+{
+	u8 sdbint, pciint;
+	int i;
+
+	sdbint = readb(NEC_EAGLE_SDBINT);
+	sdbint &= (NEC_EAGLE_SDBINT_DEG | NEC_EAGLE_SDBINT_ENUM |
+	           NEC_EAGLE_SDBINT_SIO1INT | NEC_EAGLE_SDBINT_SIO2INT |
+	           NEC_EAGLE_SDBINT_PARINT);
+	pciint = readb(NEC_EAGLE_PCIINTREG);
+	pciint &= (NEC_EAGLE_PCIINT_CP_INTA | NEC_EAGLE_PCIINT_CP_INTB |
+	           NEC_EAGLE_PCIINT_CP_INTC | NEC_EAGLE_PCIINT_CP_INTD |
+	           NEC_EAGLE_PCIINT_LANINT);
+
+	for (i = 1; i < 6; i++)
+		if (sdbint & (0x01 << i))
+			return SDBINT_IRQ_BASE + i;
+
+	for (i = 0; i < 5; i++)
+		if (pciint & (0x01 << i))
+			return PCIINT_IRQ_BASE + i;
+
+	return -EINVAL;
+}
+
+void __init eagle_irq_init(void)
+{
+	int i;
+
+	writeb(0, NEC_EAGLE_SDBINTMSK);
+	writeb(0, NEC_EAGLE_PCIINTMSKREG);
+
+	vr41xx_set_irq_trigger(VRC4173_PIN, TRIGGER_LEVEL, SIGNAL_THROUGH);
+	vr41xx_set_irq_level(VRC4173_PIN, LEVEL_LOW);
+
+	vr41xx_set_irq_trigger(PCISLOT_PIN, TRIGGER_LEVEL, SIGNAL_THROUGH);
+	vr41xx_set_irq_level(PCISLOT_PIN, LEVEL_HIGH);
+
+	vr41xx_set_irq_trigger(FPGA_PIN, TRIGGER_LEVEL, SIGNAL_THROUGH);
+	vr41xx_set_irq_level(FPGA_PIN, LEVEL_HIGH);
+
+	vr41xx_set_irq_trigger(DCD_PIN, TRIGGER_EDGE, SIGNAL_HOLD);
+	vr41xx_set_irq_level(DCD_PIN, LEVEL_LOW);
+
+	for (i = SDBINT_IRQ_BASE; i <= SDBINT_IRQ_LAST; i++)
+		irq_desc[i].handler = &sdbint_irq_type;
+
+	for (i = PCIINT_IRQ_BASE; i <= PCIINT_IRQ_LAST; i++)
+		irq_desc[i].handler = &pciint_irq_type;
+
+	vr41xx_cascade_irq(FPGA_CASCADE_IRQ, eagle_get_irq_number);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/nec-eagle/pci_fixup.c linux-2.4.20/arch/mips/vr41xx/nec-eagle/pci_fixup.c
--- linux-2.4.19/arch/mips/vr41xx/nec-eagle/pci_fixup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/nec-eagle/pci_fixup.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,166 @@
+/*
+ * FILE NAME
+ *	arch/mips/vr41xx/nec-eagle/pci_fixup.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	The NEC Eagle/Hawk Board specific PCI fixups.
+ *
+ * Author: Yoichi Yuasa
+ *         yyuasa@mvista.com or source@mvista.com
+ *
+ * Copyright 2001,2002 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.
+ */
+/*
+ * Changes:
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - Moved mips_pci_channels[] to arch/mips/vr41xx/vr4122/eagle/setup.c.
+ *  - Added support for NEC Hawk.
+ *
+ *  Paul Mundt <lethal@chaoticdreams.org>
+ *  - Fix empty break statements, remove useless CONFIG_PCI.
+ *
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - New creation, NEC Eagle is supported.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/vr41xx/eagle.h>
+#ifdef CONFIG_VRC4173
+#include <asm/vr41xx/vrc4173.h>
+#endif
+
+void __init pcibios_fixup_resources(struct pci_dev *dev)
+{
+}
+
+void __init pcibios_fixup(void)
+{
+}
+
+void __init pcibios_fixup_irqs(void)
+{
+	struct pci_dev *dev;
+	u8 slot, func, pin;
+
+	pci_for_each_dev(dev) {
+		slot = PCI_SLOT(dev->devfn);
+		func = PCI_FUNC(dev->devfn);
+		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+		dev->irq = 0;
+
+		switch (slot) {
+		case 8:
+			switch (pin) {
+			case 1:
+				dev->irq = CP_INTA_IRQ;
+				break;
+			case 2:
+				dev->irq = CP_INTB_IRQ;
+				break;
+			case 3:
+				dev->irq = CP_INTC_IRQ;
+				break;
+			case 4:
+				dev->irq = CP_INTD_IRQ;
+				break;
+			}
+			break;
+		case 9:
+			switch (pin) {
+			case 1:
+				dev->irq = CP_INTD_IRQ;
+				break;
+			case 2:
+				dev->irq = CP_INTA_IRQ;
+				break;
+			case 3:
+				dev->irq = CP_INTB_IRQ;
+				break;
+			case 4:
+				dev->irq = CP_INTC_IRQ;
+				break;
+			}
+			break;
+		case 10:
+			switch (pin) {
+			case 1:
+				dev->irq = CP_INTC_IRQ;
+				break;
+			case 2:
+				dev->irq = CP_INTD_IRQ;
+				break;
+			case 3:
+				dev->irq = CP_INTA_IRQ;
+				break;
+			case 4:
+				dev->irq = CP_INTB_IRQ;
+				break;
+			}
+			break;
+#ifdef CONFIG_VRC4173
+		case 12:
+			dev->irq = VRC4173_CARDU1_IRQ;
+			break;
+		case 13:
+			dev->irq = VRC4173_CARDU2_IRQ;
+			break;
+		case 24:
+			dev->irq = VRC4173_CARDU1_IRQ;
+			break;
+		case 25:
+			dev->irq = VRC4173_CARDU2_IRQ;
+			break;
+#endif
+		case 28:
+			dev->irq = LANINTA_IRQ;
+			break;
+		case 29:
+			dev->irq = PCISLOT_IRQ;
+			break;
+#ifdef CONFIG_VRC4173
+		case 30:
+			switch (func) {
+			case 0:
+				dev->irq = VRC4173_IRQ;
+				break;
+			case 1:
+				dev->irq = VRC4173_AC97U_IRQ;
+				break;
+			case 2:
+				dev->irq = VRC4173_USBU_IRQ;
+				break;
+			}
+			break;
+#endif
+		}
+
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+	}
+}
+
+unsigned int pcibios_assign_all_busses(void)
+{
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/nec-eagle/setup.c linux-2.4.20/arch/mips/vr41xx/nec-eagle/setup.c
--- linux-2.4.19/arch/mips/vr41xx/nec-eagle/setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/nec-eagle/setup.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,156 @@
+/*
+ * FILE NAME
+ *	arch/mips/vr41xx/nec-eagle/setup.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Setup for the NEC Eagle/Hawk board.
+ *
+ * Author: Yoichi Yuasa
+ *         yyuasa@mvista.com or source@mvista.com
+ *
+ * Copyright 2001,2002 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.
+ */
+/*
+ * Changes:
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - Moved mips_pci_channels[] from arch/mips/vr41xx/vr4122/eagle/setup.c.
+ *  - Added support for NEC Hawk.
+ *
+ *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  - New creation, NEC Eagle is supported.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/ide.h>
+#include <linux/ioport.h>
+
+#include <asm/pci_channel.h>
+#include <asm/reboot.h>
+#include <asm/time.h>
+#include <asm/vr41xx/eagle.h>
+
+#ifdef CONFIG_BLK_DEV_INITRD
+extern unsigned long initrd_start, initrd_end;
+extern void * __rd_start, * __rd_end;
+#endif
+
+#ifdef CONFIG_BLK_DEV_IDE
+extern struct ide_ops eagle_ide_ops;
+#endif
+
+extern void eagle_irq_init(void);
+
+#ifdef CONFIG_PCI
+static struct resource vr41xx_pci_io_resource = {
+	"PCI I/O space",
+	VR41XX_PCI_IO_START,
+	VR41XX_PCI_IO_END,
+	IORESOURCE_IO
+};
+
+static struct resource vr41xx_pci_mem_resource = {
+	"PCI memory space",
+	VR41XX_PCI_MEM_START,
+	VR41XX_PCI_MEM_END,
+	IORESOURCE_MEM
+};
+
+extern struct pci_ops vr41xx_pci_ops;
+
+struct pci_channel mips_pci_channels[] = {
+	{&vr41xx_pci_ops, &vr41xx_pci_io_resource, &vr41xx_pci_mem_resource, 0, 256},
+	{NULL, NULL, NULL, 0, 0}
+};
+
+struct vr41xx_pci_address_space vr41xx_pci_mem1 = {
+	VR41XX_PCI_MEM1_BASE,
+	VR41XX_PCI_MEM1_MASK,
+	IO_MEM1_RESOURCE_START
+};
+
+struct vr41xx_pci_address_space vr41xx_pci_mem2 = {
+	VR41XX_PCI_MEM2_BASE,
+	VR41XX_PCI_MEM2_MASK,
+	IO_MEM2_RESOURCE_START
+};
+
+struct vr41xx_pci_address_space vr41xx_pci_io = {
+	VR41XX_PCI_IO_BASE,
+	VR41XX_PCI_IO_MASK,
+	IO_PORT_RESOURCE_START
+};
+
+static struct vr41xx_pci_address_map pci_address_map = {
+	&vr41xx_pci_mem1,
+	&vr41xx_pci_mem2,
+	&vr41xx_pci_io
+};
+#endif
+
+void __init nec_eagle_setup(void)
+{
+	set_io_port_base(IO_PORT_BASE);
+	ioport_resource.start = IO_PORT_RESOURCE_START;
+	ioport_resource.end = IO_PORT_RESOURCE_END;
+	iomem_resource.start = IO_MEM1_RESOURCE_START;
+	iomem_resource.end = IO_MEM2_RESOURCE_END;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+	initrd_start = (unsigned long)&__rd_start;
+	initrd_end = (unsigned long)&__rd_end;
+#endif
+
+	_machine_restart = vr41xx_restart;
+	_machine_halt = vr41xx_halt;
+	_machine_power_off = vr41xx_power_off;
+
+	board_time_init = vr41xx_time_init;
+	board_timer_setup = vr41xx_timer_setup;
+
+	board_irq_init = eagle_irq_init;
+
+#ifdef CONFIG_FB
+	conswitchp = &dummy_con;
+#endif
+
+#ifdef CONFIG_BLK_DEV_IDE
+	ide_ops = &eagle_ide_ops;
+#endif
+
+	vr41xx_bcu_init();
+
+	vr41xx_cmu_init(0);
+
+	vr41xx_dsiu_init();
+	vr41xx_siu_init(SIU_RS232C, 0);
+
+#ifdef CONFIG_PCI
+	vr41xx_pciu_init(&pci_address_map);
+#endif
+
+#ifdef CONFIG_VRC4173
+	vrc4173_init();
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/zao-capcella/Makefile linux-2.4.20/arch/mips/vr41xx/zao-capcella/Makefile
--- linux-2.4.19/arch/mips/vr41xx/zao-capcella/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/zao-capcella/Makefile	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,20 @@
+#
+# Makefile for the ZAO Networks Capcella  specific parts of the kernel
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+USE_STANDARD_AS_RULE := true
+
+O_TARGET := capcella.o
+
+all: capcella.o
+
+obj-y	:= init.o setup.o
+
+obj-$(CONFIG_IDE)	+= ide-capcella.o
+obj-$(CONFIG_PCI)	+= pci_fixup.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/zao-capcella/ide-capcella.c linux-2.4.20/arch/mips/vr41xx/zao-capcella/ide-capcella.c
--- linux-2.4.19/arch/mips/vr41xx/zao-capcella/ide-capcella.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/zao-capcella/ide-capcella.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,99 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * IDE routines for typical pc-like standard configurations
+ * for the ZAO Networks Capcella.
+ *
+ * Copyright (C) 1998, 1999, 2001 by Ralf Baechle
+ */
+/*
+ * Changes:
+ *  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>  Sun, 24 Feb 2002
+ *  - Added ZAO Networks Capcella support.
+ */
+#include <linux/sched.h>
+#include <linux/ide.h>
+#include <linux/ioport.h>
+#include <linux/hdreg.h>
+#include <asm/ptrace.h>
+#include <asm/hdreg.h>
+
+static int capcella_ide_default_irq(ide_ioreg_t base)
+{
+	switch (base) {
+	case 0x8300: return 42;
+	}
+
+	return 0;
+}
+
+static ide_ioreg_t capcella_ide_default_io_base(int index)
+{
+	switch (index) {
+	case 0: return 0x8300;
+	}
+
+	return 0;
+}
+
+static void capcella_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port,
+                                         ide_ioreg_t ctrl_port, int *irq)
+{
+	ide_ioreg_t reg = data_port;
+	int i;
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw->io_ports[i] = reg;
+		reg += 1;
+	}
+	if (ctrl_port) {
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+	} else {
+		hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
+	}
+	if (irq != NULL)
+		*irq = 0;
+	hw->io_ports[IDE_IRQ_OFFSET] = 0;
+}
+
+static int capcella_ide_request_irq(unsigned int irq,
+                                    void (*handler)(int,void *, struct pt_regs *),
+                                    unsigned long flags, const char *device,
+                                    void *dev_id)
+{
+	return request_irq(irq, handler, flags, device, dev_id);
+}
+
+static void capcella_ide_free_irq(unsigned int irq, void *dev_id)
+{
+	free_irq(irq, dev_id);
+}
+
+static int capcella_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+	return check_region(from, extent);
+}
+
+static void capcella_ide_request_region(ide_ioreg_t from, unsigned int extent,
+                                        const char *name)
+{
+	request_region(from, extent, name);
+}
+
+static void capcella_ide_release_region(ide_ioreg_t from, unsigned int extent)
+{
+	release_region(from, extent);
+}
+
+struct ide_ops capcella_ide_ops = {
+	&capcella_ide_default_irq,
+	&capcella_ide_default_io_base,
+	&capcella_ide_init_hwif_ports,
+	&capcella_ide_request_irq,
+	&capcella_ide_free_irq,
+	&capcella_ide_check_region,
+	&capcella_ide_request_region,
+	&capcella_ide_release_region
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/zao-capcella/init.c linux-2.4.20/arch/mips/vr41xx/zao-capcella/init.c
--- linux-2.4.19/arch/mips/vr41xx/zao-capcella/init.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/zao-capcella/init.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,68 @@
+/*
+ * FILE NAME
+ *	arch/mips/vr41xx/zao-capcella/init.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Initialisation code for the ZAO Networks Capcella.
+ *
+ * Copyright 2002 Yoichi Yuasa
+ *                yuasa@hh.iij4u.or.jp
+ *
+ *  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.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
+#include <asm/mipsregs.h>
+#include <asm/vr41xx/vr41xx.h>
+
+char arcs_cmdline[CL_SIZE];
+
+const char *get_system_type(void)
+{
+	return "ZAO Networks Capcella";
+}
+
+void __init bus_error_init(void)
+{
+}
+
+void __init prom_init(int argc, char **argv, unsigned long magic, int *prom_vec)
+{
+	u32 config;
+	int i;
+
+	/*
+	 * collect args and prepare cmd_line
+	 */
+	for (i = 1; i < argc; i++) {
+		strcat(arcs_cmdline, argv[i]);
+		if (i < (argc - 1))
+			strcat(arcs_cmdline, " ");
+	}
+
+	mips_machgroup = MACH_GROUP_NEC_VR41XX;
+	mips_machtype = MACH_ZAO_CAPCELLA;
+
+	switch (mips_cpu.processor_id) {
+	case PRID_VR4131_REV1_2:
+		config = read_32bit_cp0_register(CP0_CONFIG);
+		config &= ~0x00000030UL;
+		config |= 0x00410000UL;
+		write_32bit_cp0_register(CP0_CONFIG, config);
+		break;
+	default:
+		break;
+	}
+}
+
+void __init prom_free_prom_memory (void)
+{
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/zao-capcella/pci_fixup.c linux-2.4.20/arch/mips/vr41xx/zao-capcella/pci_fixup.c
--- linux-2.4.19/arch/mips/vr41xx/zao-capcella/pci_fixup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/zao-capcella/pci_fixup.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,73 @@
+/*
+ * FILE NAME
+ *	arch/mips/vr41xx/zao-capcella/pci_fixup.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	The ZAO Networks Capcella specific PCI fixups.
+ *
+ * Copyright 2002 Yoichi Yuasa
+ *                yuasa@hh.iij4u.or.jp
+ *
+ *  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.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/vr41xx/capcella.h>
+
+void __init pcibios_fixup_resources(struct pci_dev *dev)
+{
+}
+
+void __init pcibios_fixup(void)
+{
+}
+
+void __init pcibios_fixup_irqs(void)
+{
+	struct pci_dev *dev;
+	u8 slot, func, pin;
+
+	pci_for_each_dev(dev) {
+		slot = PCI_SLOT(dev->devfn);
+		func = PCI_FUNC(dev->devfn);
+		dev->irq = 0;
+
+		switch (slot) {
+		case 11:
+			dev->irq = RTL8139_1_IRQ;
+			break;
+		case 12:
+			dev->irq = RTL8139_2_IRQ;
+			break;
+		case 14:
+			pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+			switch (pin) {
+			case 1:
+				dev->irq = PC104PLUS_INTA_IRQ;
+				break;
+			case 2:
+				dev->irq = PC104PLUS_INTB_IRQ;
+				break;
+			case 3:
+				dev->irq = PC104PLUS_INTC_IRQ;
+				break;
+			case 4:
+				dev->irq = PC104PLUS_INTD_IRQ;
+				break;
+			}
+			break;
+		}
+
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+	}
+}
+
+unsigned int pcibios_assign_all_busses(void)
+{
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips/vr41xx/zao-capcella/setup.c linux-2.4.20/arch/mips/vr41xx/zao-capcella/setup.c
--- linux-2.4.19/arch/mips/vr41xx/zao-capcella/setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips/vr41xx/zao-capcella/setup.c	2002-10-29 11:18:38.000000000 +0000
@@ -0,0 +1,121 @@
+/*
+ * FILE NAME
+ *	arch/mips/vr41xx/zao-capcella/setup.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Setup for the ZAO Networks Capcella.
+ *
+ * Copyright 2002 Yoichi Yuasa
+ *                yuasa@hh.iij4u.or.jp
+ *
+ *  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.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/ide.h>
+#include <linux/ioport.h>
+
+#include <asm/pci_channel.h>
+#include <asm/reboot.h>
+#include <asm/time.h>
+#include <asm/vr41xx/capcella.h>
+
+#ifdef CONFIG_BLK_DEV_INITRD
+extern unsigned long initrd_start, initrd_end;
+extern void * __rd_start, * __rd_end;
+#endif
+
+#ifdef CONFIG_BLK_DEV_IDE
+extern struct ide_ops capcella_ide_ops;
+#endif
+
+#ifdef CONFIG_PCI
+static struct resource vr41xx_pci_io_resource = {
+	"PCI I/O space",
+	VR41XX_PCI_IO_START,
+	VR41XX_PCI_IO_END,
+	IORESOURCE_IO
+};
+
+static struct resource vr41xx_pci_mem_resource = {
+	"PCI memory space",
+	VR41XX_PCI_MEM_START,
+	VR41XX_PCI_MEM_END,
+	IORESOURCE_MEM
+};
+
+extern struct pci_ops vr41xx_pci_ops;
+
+struct pci_channel mips_pci_channels[] = {
+	{&vr41xx_pci_ops, &vr41xx_pci_io_resource, &vr41xx_pci_mem_resource, 0, 256},
+	{NULL, NULL, NULL, 0, 0}
+};
+
+struct vr41xx_pci_address_space vr41xx_pci_mem1 = {
+	VR41XX_PCI_MEM1_BASE,
+	VR41XX_PCI_MEM1_MASK,
+	IO_MEM1_RESOURCE_START
+};
+
+struct vr41xx_pci_address_space vr41xx_pci_mem2 = {
+	VR41XX_PCI_MEM2_BASE,
+	VR41XX_PCI_MEM2_MASK,
+	IO_MEM2_RESOURCE_START
+};
+
+struct vr41xx_pci_address_space vr41xx_pci_io = {
+	VR41XX_PCI_IO_BASE,
+	VR41XX_PCI_IO_MASK,
+	IO_PORT_RESOURCE_START
+};
+
+static struct vr41xx_pci_address_map pci_address_map = {
+	&vr41xx_pci_mem1,
+	&vr41xx_pci_mem2,
+	&vr41xx_pci_io
+};
+#endif
+
+void __init zao_capcella_setup(void)
+{
+	set_io_port_base(IO_PORT_BASE);
+	ioport_resource.start = IO_PORT_RESOURCE_START;
+	ioport_resource.end = IO_PORT_RESOURCE_END;
+	iomem_resource.start = IO_MEM1_RESOURCE_START;
+	iomem_resource.end = IO_MEM2_RESOURCE_END;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+	initrd_start = (unsigned long)&__rd_start;
+	initrd_end = (unsigned long)&__rd_end;
+#endif
+
+	_machine_restart = vr41xx_restart;
+	_machine_halt = vr41xx_halt;
+	_machine_power_off = vr41xx_power_off;
+
+	board_time_init = vr41xx_time_init;
+	board_timer_setup = vr41xx_timer_setup;
+
+#ifdef CONFIG_FB
+	conswitchp = &dummy_con;
+#endif
+
+#ifdef CONFIG_BLK_DEV_IDE
+	ide_ops = &capcella_ide_ops;
+#endif
+
+	vr41xx_bcu_init();
+
+	vr41xx_cmu_init(0x0102);
+
+	vr41xx_siu_init(SIU_RS232C, 0);
+
+#ifdef CONFIG_PCI
+	vr41xx_pciu_init(&pci_address_map);
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/Makefile linux-2.4.20/arch/mips64/Makefile
--- linux-2.4.19/arch/mips64/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/Makefile	2002-10-29 11:18:35.000000000 +0000
@@ -25,7 +25,7 @@
 endif
 
 #
-# The ELF GCC uses -G0 -mabicalls -fpic as default.  We don't need PIC
+# The ELF GCC uses -G 0 -mabicalls -fpic as default.  We don't need PIC
 # code in the kernel since it only slows down the whole thing.  For the
 # old GCC these options are just the defaults.  At some point we might
 # make use of global pointer optimizations.
@@ -67,10 +67,10 @@
 ifdef CONFIG_CPU_SB1
 GCCFLAGS	+= -mcpu=r8000 -mips4
 endif
-
-AFLAGS		+= $(GCCFLAGS)
-CFLAGS		+= $(GCCFLAGS)
-
+ifdef CONFIG_CPU_MIPS64
+#CFLAGS		+= -mips64	# Should be used then we get a MIPS64 compiler
+CFLAGS		+= -mcpu=r8000 -mips4
+endif
 
 #
 # We unconditionally build the math emulator
@@ -104,12 +104,22 @@
 endif
 
 #
+# MIPS SEAD board
+#
+ifdef CONFIG_MIPS_SEAD
+LIBS		+= arch/mips/mips-boards/sead/sead.o \
+		   arch/mips/mips-boards/generic/mipsboards.o
+SUBDIRS		+= arch/mips/mips-boards/generic arch/mips/mips-boards/sead
+LOADADDR	:= 0x80100000
+endif
+
+#
 # SGI IP22 (Indy/Indigo2)
 #
 ifdef CONFIG_SGI_IP22
 CORE_FILES	+= arch/mips/sgi-ip22/ip22-kern.o
-LIBS		+= arch/mips64/arc/arclib.a 
-SUBDIRS		+= arch/mips/sgi-ip22 arch/mips64/arc
+LIBS		+= arch/mips/arc/arclib.a
+SUBDIRS		+= arch/mips/sgi-ip22 arch/mips/arc
 #
 # Set LOADADDR to >= 0x88069000 if you want to leave space for symmon,
 # 0x88004000 for production kernels.  Note that the value must be
@@ -122,9 +132,9 @@
 # SGI-IP27 (Origin200/2000)
 #
 ifdef CONFIG_SGI_IP27
-CORE_FILES	+= arch/mips64/sgi-ip27/ip27.o
-LIBS		+= arch/mips64/arc/arclib.a
-SUBDIRS		+= arch/mips64/sgi-ip27 arch/mips64/arc
+CORE_FILES	+= arch/mips/sgi-ip27/ip27.o
+LIBS		+= arch/mips/arc/arclib.a
+SUBDIRS		+= arch/mips/sgi-ip27 arch/mips/arc
 #
 # Set LOADADDR to >= 0xc000000000300000 if you want to leave space for
 # symmon, 0xc00000000001c000 for production kernels.  Note that the value
@@ -142,9 +152,9 @@
 # SGI-IP32 (O2)
 #
 ifdef CONFIG_SGI_IP32
-CORE_FILES	+= arch/mips64/sgi-ip32/ip32-kern.a
-LIBS		+= arch/mips64/arc/arclib.a
-SUBDIRS		+= arch/mips64/sgi-ip32 arch/mips64/arc
+CORE_FILES	+= arch/mips/sgi-ip32/ip32-kern.a
+LIBS		+= arch/mips/arc/arclib.a
+SUBDIRS		+= arch/mips/sgi-ip32 arch/mips/arc
 #
 # Set LOADADDR to >= 0x????????? if you want to leave space for symmon,
 # 0x80002000 for production kernels.  Note that the value must be
@@ -174,6 +184,14 @@
 endif
 
 #
+# Sibyte CFE firmware
+#
+ifdef CONFIG_SIBYTE_CFE
+LIBS		+= arch/mips/sibyte/cfe/cfe.a
+SUBDIRS		+= arch/mips/sibyte/cfe
+endif
+
+#
 # SB1 Cache Error handler
 #
 ifdef CONFIG_SB1_CACHE_ERROR
@@ -188,8 +206,7 @@
 # convert to ECOFF using elf2ecoff.
 #
 ifdef CONFIG_BOOT_ELF32
-CFLAGS += -Wa,-32
-AFLAGS += -Wa,-32
+GCCFLAGS += -Wa,-32
 LINKFLAGS += -T arch/mips64/ld.script.elf32
 endif
 #
@@ -197,19 +214,23 @@
 # ELF files from 32-bit files by conversion.
 #
 ifdef CONFIG_BOOT_ELF64
-CFLAGS += -Wa,-32
-AFLAGS += -Wa,-32
+GCCFLAGS += -Wa,-32
 LINKFLAGS += -T arch/mips64/ld.script.elf32
 #AS += -64
 #LD += -m elf64bmip
 #LINKFLAGS += -T arch/mips64/ld.script.elf64
 endif
 
+
+AFLAGS		+= $(GCCFLAGS)
+CFLAGS		+= $(GCCFLAGS)
+
+
 LINKFLAGS += -Ttext $(LOADADDR)
 
 HEAD := arch/mips64/kernel/head.o arch/mips64/kernel/init_task.o
 
-SUBDIRS := $(addprefix arch/mips64/, tools) $(SUBDIRS) $(addprefix arch/mips64/, kernel mm lib)
+SUBDIRS := $(addprefix arch/mips/, tools) $(SUBDIRS) $(addprefix arch/mips64/, kernel mm lib)
 CORE_FILES := arch/mips64/kernel/kernel.o arch/mips64/mm/mm.o $(CORE_FILES)
 LIBS := arch/mips64/lib/lib.a $(LIBS)
 
@@ -243,12 +264,12 @@
 
 archclean:
 	@$(MAKEBOOT) clean
-	$(MAKE) -C arch/$(ARCH)/tools clean
+	$(MAKE) -C arch/mips/tools clean
 	rm -f vmlinux.64 arch/$(ARCH)/ld.script.elf32
 
 archmrproper:
 	@$(MAKEBOOT) mrproper
-	$(MAKE) -C arch/$(ARCH)/tools mrproper
+	$(MAKE) -C arch/mips/tools mrproper
 
 archdep:
 	if [ ! -f $(TOPDIR)/include/asm-$(ARCH)/offset.h ]; then \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/arc/Makefile linux-2.4.20/arch/mips64/arc/Makefile
--- linux-2.4.19/arch/mips64/arc/Makefile	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.20/arch/mips64/arc/Makefile	1970-01-01 00:00:00.000000000 +0000
@@ -1,12 +0,0 @@
-#
-# Makefile for the ARC prom monitor library routines under Linux.
-#
-
-L_TARGET = arclib.a
-obj-y	:= console.o init.o identify.o tree.o env.o cmdline.o misc.o time.o \
-	   file.o
-
-obj-$(CONFIG_ARC_MEMORY) += memory.o
-obj-$(CONFIG_ARC_CONSOLE) += arc_con.o
-
-include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/arc/arc_con.c linux-2.4.20/arch/mips64/arc/arc_con.c
--- linux-2.4.19/arch/mips64/arc/arc_con.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/arc/arc_con.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,62 +0,0 @@
-/*
- * Wrap-around code for a console using the
- * ARC io-routines.
- *
- * Copyright (c) 1998 Harald Koerfgen 
- * Copyright (c) 2001 Ralf Baechle
- */
-#include <linux/tty.h>
-#include <linux/major.h>
-#include <linux/ptrace.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/fs.h>
-
-#include <asm/sgialib.h>
-
-extern void prom_printf (char *, ...);
-
-void prom_putchar(char c)
-{
-	ULONG cnt;
-	CHAR it = c;
-
-	ArcWrite(1, &it, 1, &cnt);
-}
-
-static void prom_console_write(struct console *co, const char *s,
-			       unsigned count)
-{
-	unsigned i;
-
-	/*
-	 *    Now, do each character
-	 */
-	for (i = 0; i < count; i++) {
-		if (*s == 10)
-			prom_printf("%c", 13);
-		prom_printf("%c", *s++);
-	}
-}
-
-static kdev_t prom_console_device(struct console *c)
-{
-	return MKDEV(TTY_MAJOR, 64 + c->index);
-}
-
-static struct console arc_cons = {
-    name:	"ttyS",
-    write:	prom_console_write,
-    device:	prom_console_device,
-    flags:	CON_PRINTBUFFER,
-    index:	-1,
-};
-
-/*
- *    Register console.
- */
-
-void __init arc_console_init(void)
-{
-	register_console(&arc_cons);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/arc/cmdline.c linux-2.4.20/arch/mips64/arc/cmdline.c
--- linux-2.4.19/arch/mips64/arc/cmdline.c	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.20/arch/mips64/arc/cmdline.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,111 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * cmdline.c: Kernel command line creation using ARCS argc/argv.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-
-#include <asm/sgialib.h>
-#include <asm/bootinfo.h>
-
-/* #define DEBUG_CMDLINE */
-
-char arcs_cmdline[CL_SIZE];
-
-char * __init prom_getcmdline(void)
-{
-	return &(arcs_cmdline[0]);
-}
-
-static char *ignored[] = {
-	"ConsoleIn=",
-	"ConsoleOut=",
-	"SystemPartition=",
-	"OSLoader=",
-	"OSLoadPartition=",
-	"OSLoadFilename=",
-	"OSLoadOptions="
-};
-#define NENTS(foo) ((sizeof((foo)) / (sizeof((foo[0])))))
-
-static char *used_arc[][2] = {
-	{ "OSLoadPartition=", "root=" },
-	{ "OSLoadOptions=", "" }
-};
-
-static char * __init move_firmware_args(char* cp)
-{
-	char *s;
-	int actr, i;
-
-	actr = 1; /* Always ignore argv[0] */
-
-	while (actr < prom_argc) {
-		for(i = 0; i < NENTS(used_arc); i++) {
-			int len = strlen(used_arc[i][0]);
-
-			if (!strncmp(prom_argv(actr), used_arc[i][0], len)) {
-			/* Ok, we want it. First append the replacement... */
-				strcat(cp, used_arc[i][1]);
-				cp += strlen(used_arc[i][1]);
-				/* ... and now the argument */
-				s = strstr(prom_argv(actr), "=");
-				if (s) {
-					s++;
-					strcpy(cp, s);
-					cp += strlen(s);
-				}
-				*cp++ = ' ';
-				break;
-			}
-		}
-		actr++;
-	}
-
-	return cp;
-}
-
-
-void __init prom_init_cmdline(void)
-{
-	char *cp;
-	int actr, i;
-
-	actr = 1; /* Always ignore argv[0] */
-
-	cp = &(arcs_cmdline[0]);
-	/* 
-	 * Move ARC variables to the beginning to make sure they can be
-	 * overridden by later arguments.
-	 */
-	cp = move_firmware_args(cp);
-
-	while (actr < prom_argc) {
-		for (i = 0; i < NENTS(ignored); i++) {
-			int len = strlen(ignored[i]);
-
-			if (!strncmp(prom_argv(actr), ignored[i], len))
-				goto pic_cont;
-		}
-		/* Ok, we want it. */
-		strcpy(cp, prom_argv(actr));
-		cp += strlen(prom_argv(actr));
-		*cp++ = ' ';
-
-	pic_cont:
-		actr++;
-	}
-	if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
-		--cp;
-	*cp = '\0';
-
-#ifdef DEBUG_CMDLINE
-	prom_printf("prom_init_cmdline: %s\n", &(arcs_cmdline[0]));
-#endif
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/arc/console.c linux-2.4.20/arch/mips64/arc/console.c
--- linux-2.4.19/arch/mips64/arc/console.c	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.20/arch/mips64/arc/console.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,33 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1996 David S. Miller (dm@sgi.com)
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/sgialib.h>
-
-static char ppbuf[1024];
-
-void prom_printf(char *fmt, ...)
-{
-	va_list args;
-	char ch, *bptr;
-	int i;
-
-	va_start(args, fmt);
-	i = vsprintf(ppbuf, fmt, args);
-
-	bptr = ppbuf;
-
-	while((ch = *(bptr++)) != 0) {
-		if(ch == '\n')
-			prom_putchar('\r');
-
-		prom_putchar(ch);
-	}
-	va_end(args);
-	return;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/arc/env.c linux-2.4.20/arch/mips64/arc/env.c
--- linux-2.4.19/arch/mips64/arc/env.c	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/arch/mips64/arc/env.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,27 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * env.c: ARCS environment variable routines.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-
-#include <asm/arc/types.h>
-#include <asm/sgialib.h>
-
-PCHAR __init
-ArcGetEnvironmentVariable(CHAR *name)
-{
-	return (CHAR *) ARC_CALL1(get_evar, name);
-}
-
-LONG __init
-ArcSetEnvironmentVariable(PCHAR name, PCHAR value)
-{
-	return ARC_CALL2(set_evar, name, value);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/arc/file.c linux-2.4.20/arch/mips64/arc/file.c
--- linux-2.4.19/arch/mips64/arc/file.c	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/arch/mips64/arc/file.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,75 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * ARC firmware interface.
- *
- * Copyright (C) 1994, 1995, 1996, 1999 Ralf Baechle
- * Copyright (C) 1999 Silicon Graphics, Inc.
- */
-#include <linux/init.h>
-
-#include <asm/arc/types.h>
-#include <asm/sgialib.h>
-
-LONG __init
-ArcGetDirectoryEntry(ULONG FileID, struct linux_vdirent *Buffer,
-                     ULONG N, ULONG *Count)
-{
-	return ARC_CALL4(get_vdirent, FileID, Buffer, N, Count);
-}
-
-LONG __init
-ArcOpen(CHAR *Path, enum linux_omode OpenMode, ULONG *FileID)
-{
-	return ARC_CALL3(open, Path, OpenMode, FileID);
-}
-
-LONG __init
-ArcClose(ULONG FileID)
-{
-	return ARC_CALL1(close, FileID);
-}
-
-LONG __init
-ArcRead(ULONG FileID, VOID *Buffer, ULONG N, ULONG *Count)
-{
-	return ARC_CALL4(read, FileID, Buffer, N, Count);
-}
-
-LONG __init
-ArcGetReadStatus(ULONG FileID)
-{
-	return ARC_CALL1(get_rstatus, FileID);
-}
-
-LONG __init
-ArcWrite(ULONG FileID, PVOID Buffer, ULONG N, PULONG Count)
-{
-	return ARC_CALL4(write, FileID, Buffer, N, Count);
-}
-
-LONG __init
-ArcSeek(ULONG FileID, struct linux_bigint *Position, enum linux_seekmode SeekMode)
-{
-	return ARC_CALL3(seek, FileID, Position, SeekMode);
-}
-
-LONG __init
-ArcMount(char *name, enum linux_mountops op)
-{
-	return ARC_CALL2(mount, name, op);
-}
-
-LONG __init
-ArcGetFileInformation(ULONG FileID, struct linux_finfo *Information)
-{
-	return ARC_CALL2(get_finfo, FileID, Information);
-}
-
-LONG __init ArcSetFileInformation(ULONG FileID, ULONG AttributeFlags,
-                                  ULONG AttributeMask)
-{
-	return ARC_CALL3(set_finfo, FileID, AttributeFlags, AttributeMask);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/arc/identify.c linux-2.4.20/arch/mips64/arc/identify.c
--- linux-2.4.19/arch/mips64/arc/identify.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/arc/identify.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,117 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * identify.c: identify machine by looking up system identifier
- *
- * Copyright (C) 1998 Thomas Bogendoerfer
- * 
- * This code is based on arch/mips/sgi/kernel/system.c, which is
- * 
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- */
-#include <linux/init.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/string.h>
-
-#include <asm/sgialib.h>
-#include <asm/bootinfo.h>
-
-struct smatch {
-	char *arcname;
-	char *liname;
-	int group;
-	int type;
-	int flags;
-};
-
-static struct smatch mach_table[] = {
-	{	"SGI-IP22",
-		"SGI Indy",
-		MACH_GROUP_SGI,
-		MACH_SGI_INDY,
-		PROM_FLAG_ARCS
-	}, {	"SGI-IP27",
-		"SGI Origin",
-		MACH_GROUP_SGI,
-		MACH_SGI_IP27,
-		PROM_FLAG_ARCS
-	}, {	"SGI-IP28",
-		"SGI IP28",
-		MACH_GROUP_SGI,
-		MACH_SGI_IP28,
-		PROM_FLAG_ARCS
-	}, {	"SGI-IP32",
-		"SGI IP32",
-		MACH_GROUP_SGI,
-		MACH_SGI_IP32,
-		PROM_FLAG_ARCS
-	}, {	"Microsoft-Jazz",
-		"Jazz MIPS_Magnum_4000",
-		MACH_GROUP_JAZZ,
-		MACH_MIPS_MAGNUM_4000,
-		0
-	}, {	"PICA-61",
-		"Jazz Acer_PICA_61",
-		MACH_GROUP_JAZZ,
-		MACH_ACER_PICA_61,
-		0
-	}, {	"RM200PCI",
-		"SNI RM200_PCI",
-		MACH_GROUP_SNI_RM,
-		MACH_SNI_RM200_PCI,
-		0
-	}
-};
-
-int prom_flags;
-
-static struct smatch * __init string_to_mach(const char *s)
-{
-	int i;
-    
-	for (i = 0; i < (sizeof (mach_table) / sizeof (mach_table[0])); i++) {
-		if(!strcmp(s, mach_table[i].arcname))
-			return &mach_table[i];
-	}
-	panic("Yeee, could not determine architecture type <%s>", s);
-
-	return NULL;
-}
-
-char *system_type;
-
-const char *get_system_type(void)
-{
-	return system_type;
-}
-
-void __init prom_identify_arch(void)
-{
-	pcomponent *p;
-	struct smatch *mach;
-	const char *iname;
-
-	/* The root component tells us what machine architecture we
-	   have here.  */
-	p = ArcGetChild(PROM_NULL_COMPONENT);
-	if (p == NULL) {
-#ifdef CONFIG_SGI_IP27
-		/* IP27 PROM bisbehaves, seems to not implement ARC
-		   GetChild().  So we just assume it's an IP27.  */
-		iname = "SGI-IP27";
-#endif
-	} else
-		iname = (char *) (long) p->iname;
-
-	printk(KERN_INFO "ARCH: %s\n", iname);
-	mach = string_to_mach(iname);
-	system_type = mach->liname;
-
-	mips_machgroup = mach->group;
-	mips_machtype = mach->type;
-	prom_flags = mach->flags;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/arc/init.c linux-2.4.20/arch/mips64/arc/init.c
--- linux-2.4.19/arch/mips64/arc/init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/arc/init.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,49 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * PROM library initialisation code.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <asm/sgialib.h>
-
-#undef DEBUG_PROM_INIT
-
-/* Master romvec interface. */
-struct linux_romvec *romvec;
-int prom_argc;
-LONG *_prom_argv, *_prom_envp;
-
-int __init prom_init(int argc, char **argv, char **envp)
-{
-	PSYSTEM_PARAMETER_BLOCK pb = PROMBLOCK;
-	romvec = ROMVECTOR;
-	prom_argc = argc;
-	_prom_argv = (LONG *) argv;
-	_prom_envp = (LONG *) envp;
-
-	if(pb->magic != 0x53435241) {
-		prom_printf("Aieee, bad prom vector magic %08lx\n",
-			    pb->magic);
-		while(1)
-			;
-	}
-
-	prom_init_cmdline();
-	prom_identify_arch();
-	printk(KERN_INFO "PROMLIB: ARC firmware Version %d Revision %d\n",
-	       pb->ver, pb->rev);
-	prom_meminit();
-
-#ifdef DEBUG_PROM_INIT
-	prom_printf("Press a key to reboot\n");
-	prom_getchar();
-	ArcEnterInteractiveMode();
-#endif
-	return 0;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/arc/memory.c linux-2.4.20/arch/mips64/arc/memory.c
--- linux-2.4.19/arch/mips64/arc/memory.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/arc/memory.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,159 +0,0 @@
-/*
- * memory.c: PROM library functions for acquiring/using memory descriptors
- *           given to us from the ARCS firmware.
- *
- * Copyright (C) 1996 by David S. Miller
- * Copyright (C) 1999, 2000, 2001 by Ralf Baechle
- * Copyright (C) 1999, 2000 by Silicon Graphics, Inc.
- *
- * PROM library functions for acquiring/using memory descriptors given to us
- * from the ARCS firmware.  This is only used when CONFIG_ARC_MEMORY is set
- * because on some machines like SGI IP27 the ARC memory configuration data
- * completly bogus and alternate easier to use mechanisms are available.
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <linux/swap.h>
-
-#include <asm/sgialib.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/bootinfo.h>
-
-#undef DEBUG
-
-struct linux_mdesc* __init ArcGetMemoryDescriptor(struct linux_mdesc *Current)
-{
-	return (struct linux_mdesc *) ARC_CALL1(get_mdesc, Current);
-}
-
-#ifdef DEBUG /* convenient for debugging */
-static char *arcs_mtypes[8] = {
-	"Exception Block",
-	"ARCS Romvec Page",
-	"Free/Contig RAM",
-	"Generic Free RAM",
-	"Bad Memory",
-	"Standalone Program Pages",
-	"ARCS Temp Storage Area",
-	"ARCS Permanent Storage Area"
-};
-
-static char *arc_mtypes[8] = {
-	"Exception Block",
-	"SystemParameterBlock",
-	"FreeMemory",
-	"Bad Memory",
-	"LoadedProgram",
-	"FirmwareTemporary",
-	"FirmwarePermanent",
-	"FreeContiguous"
-};
-#define mtypes(a) (prom_flags & PROM_FLAG_ARCS) ? arcs_mtypes[a.arcs] \
-						: arc_mtypes[a.arc]
-#endif
-
-static inline int memtype_classify_arcs (union linux_memtypes type)
-{
-	switch (type.arcs) {
-	case arcs_fcontig:
-	case arcs_free:
-		return BOOT_MEM_RAM;
-	case arcs_atmp:
-		return BOOT_MEM_ROM_DATA;
-	case arcs_eblock:
-	case arcs_rvpage:
-	case arcs_bmem:
-	case arcs_prog:
-	case arcs_aperm:
-		return BOOT_MEM_RESERVED;
-	default:
-		BUG();
-	}
-	while(1);				/* Nuke warning.  */
-}
-
-static inline int memtype_classify_arc (union linux_memtypes type)
-{
-	switch (type.arc) {
-	case arc_free:
-	case arc_fcontig:
-		return BOOT_MEM_RAM;
-	case arc_atmp:
-		return BOOT_MEM_ROM_DATA;
-	case arc_eblock:
-	case arc_rvpage:
-	case arc_bmem:
-	case arc_prog:
-	case arc_aperm:
-		return BOOT_MEM_RESERVED;
-	default:
-		BUG();
-	}
-	while(1);				/* Nuke warning.  */
-}
-
-static int __init prom_memtype_classify (union linux_memtypes type)
-{
-	if (prom_flags & PROM_FLAG_ARCS)	/* SGI is ``different'' ... */
-		return memtype_classify_arcs(type);
-
-	return memtype_classify_arc(type);
-}
-
-void __init prom_meminit(void)
-{
-	struct linux_mdesc *p;
-
-#ifdef DEBUG
-	int i = 0;
-
-	prom_printf("ARCS MEMORY DESCRIPTOR dump:\n");
-	p = ArcGetMemoryDescriptor(PROM_NULL_MDESC);
-	while(p) {
-		prom_printf("[%d,%p]: base<%08lx> pages<%08lx> type<%s>\n",
-			    i, p, p->base, p->pages, mtypes(p->type));
-		p = ArcGetMemoryDescriptor(p);
-		i++;
-	}
-#endif
-
-	p = PROM_NULL_MDESC;
-	while ((p = ArcGetMemoryDescriptor(p))) {
-		unsigned long base, size;
-		long type;
-
-		base = p->base << PAGE_SHIFT;
-		size = p->pages << PAGE_SHIFT;
-		type = prom_memtype_classify(p->type);
-
-		add_memory_region(base, size, type);
-	}
-}
-
-void __init prom_free_prom_memory (void)
-{
-	unsigned long freed = 0;
-	unsigned long addr;
-	int i;
-
-	for (i = 0; i < boot_mem_map.nr_map; i++) {
-		if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
-			continue;
-
-		addr = boot_mem_map.map[i].addr;
-		while (addr < boot_mem_map.map[i].addr
-			      + boot_mem_map.map[i].size) {
-			ClearPageReserved(virt_to_page(__va(addr)));
-			set_page_count(virt_to_page(__va(addr)), 1);
-			free_page((unsigned long)__va(addr));
-			addr += PAGE_SIZE;
-			freed += PAGE_SIZE;
-		}
-	}
-	printk(KERN_INFO "Freeing prom memory: %ldkb freed\n", freed >> 10);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/arc/misc.c linux-2.4.20/arch/mips64/arc/misc.c
--- linux-2.4.19/arch/mips64/arc/misc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/arc/misc.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,103 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Miscellaneous ARCS PROM routines.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org)
- * Copyright (C) 1999 Silicon Graphics, Inc.
- */
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <asm/bcache.h>
-
-#include <asm/arc/types.h>
-#include <asm/sgialib.h>
-#include <asm/bootinfo.h>
-#include <asm/system.h>
-
-extern void *sgiwd93_host;
-extern void reset_wd33c93(void *instance);
-
-VOID
-ArcHalt(VOID)
-{
-	bc_disable();
-	cli();
-#if CONFIG_SCSI_SGIWD93
-	reset_wd33c93(sgiwd93_host);
-#endif
-	ARC_CALL0(halt);
-never:	goto never;
-}
-
-VOID
-ArcPowerDown(VOID)
-{
-	bc_disable();
-	cli();
-#if CONFIG_SCSI_SGIWD93
-	reset_wd33c93(sgiwd93_host);
-#endif
-	ARC_CALL0(pdown);
-never:	goto never;
-}
-
-/* XXX is this a soft reset basically? XXX */
-VOID
-ArcRestart(VOID)
-{
-	bc_disable();
-	cli();
-#if CONFIG_SCSI_SGIWD93
-	reset_wd33c93(sgiwd93_host);
-#endif
-	ARC_CALL0(restart);
-never:	goto never;
-}
-
-VOID
-ArcReboot(VOID)
-{
-	bc_disable();
-	cli();
-#if CONFIG_SCSI_SGIWD93
-	reset_wd33c93(sgiwd93_host);
-#endif
-	ARC_CALL0(reboot);
-never:	goto never;
-}
-
-VOID
-ArcEnterInteractiveMode(VOID)
-{
-	bc_disable();
-	cli();
-#if CONFIG_SCSI_SGIWD93
-	reset_wd33c93(sgiwd93_host);
-#endif
-	ARC_CALL0(imode);
-never:	goto never;
-}
-
-LONG
-ArcSaveConfiguration(VOID)
-{
-	return ARC_CALL0(cfg_save);
-}
-
-struct linux_sysid *
-ArcGetSystemId(VOID)
-{
-	return (struct linux_sysid *) ARC_CALL0(get_sysid);
-}
-
-VOID __init
-ArcFlushAllCaches(VOID)
-{
-	ARC_CALL0(cache_flush);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/arc/salone.c linux-2.4.20/arch/mips64/arc/salone.c
--- linux-2.4.19/arch/mips64/arc/salone.c	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/arch/mips64/arc/salone.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,27 +0,0 @@
-/*
- * Routines to load into memory and execute stand-along program images using
- * ARCS PROM firmware.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- */
-#include <linux/init.h>
-#include <asm/sgialib.h>
-
-LONG __init
-ArcLoad(CHAR *Path, ULONG TopAddr, ULONG *ExecAddr, ULONG *LowAddr)
-{
-	return ARC_CALL4(load, Path, TopAddr, ExecAddr, LowAddr);
-}
-
-LONG __init
-ArcInvoke(ULONG ExecAddr, ULONG StackAddr, ULONG Argc, CHAR *Argv[],
-          CHAR *Envp[])
-{
-	return ARC_CALL5(invoke, ExecAddr, StackAddr, Argc, Argv, Envp);
-}
-
-LONG __init
-ArcExecute(CHAR *Path, LONG Argc, CHAR *Argv[], CHAR *Envp[])
-{
-	return ARC_CALL4(exec, Path, Argc, Argv, Envp);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/arc/time.c linux-2.4.20/arch/mips64/arc/time.c
--- linux-2.4.19/arch/mips64/arc/time.c	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/arch/mips64/arc/time.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,25 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Extracting time information from ARCS prom.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- */
-#include <linux/init.h>
-
-#include <asm/arc/types.h>
-#include <asm/sgialib.h>
-
-struct linux_tinfo * __init
-ArcGetTime(VOID)
-{
-	return (struct linux_tinfo *) ARC_CALL0(get_tinfo);
-}
-
-ULONG __init
-ArcGetRelativeTime(VOID)
-{
-	return ARC_CALL0(get_rtime);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/arc/tree.c linux-2.4.20/arch/mips64/arc/tree.c
--- linux-2.4.19/arch/mips64/arc/tree.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/arc/tree.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,129 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * PROM component device tree code.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org)
- * Copyright (C) 1999 Silicon Graphics, Inc.
- */
-#include <linux/init.h>
-
-#include <asm/arc/types.h>
-#include <asm/sgialib.h>
-#include <asm/sgiarcs.h>
-
-#undef DEBUG_PROM_TREE
-
-pcomponent * __init
-ArcGetPeer(pcomponent *Current)
-{
-	if (Current == PROM_NULL_COMPONENT)
-		return PROM_NULL_COMPONENT;
-
-	return (pcomponent *) ARC_CALL1(next_component, Current);
-}
-
-pcomponent * __init
-ArcGetChild(pcomponent *Current)
-{
-	return (pcomponent *) ARC_CALL1(child_component, Current);
-}
-
-pcomponent * __init
-ArcGetParent(pcomponent *Current)
-{
-	if (Current == PROM_NULL_COMPONENT)
-		return PROM_NULL_COMPONENT;
-
-	return (pcomponent *) ARC_CALL1(parent_component, Current);
-}
-
-LONG __init
-ArcGetConfigurationData(VOID *Buffer, pcomponent *Current)
-{
-	return ARC_CALL2(component_data, Buffer, Current);
-}
-
-pcomponent * __init
-ArcAddChild(pcomponent *Current, pcomponent *Template, VOID *ConfigurationData)
-{
-	return (pcomponent *)
-	       ARC_CALL3(child_add, Current, Template, ConfigurationData);
-}
-
-LONG __init
-ArcDeleteComponent(pcomponent *ComponentToDelete)
-{
-	return ARC_CALL1(comp_del, ComponentToDelete);
-}
-
-pcomponent * __init
-ArcGetComponent(CHAR *Path)
-{
-	return (pcomponent *)ARC_CALL1(component_by_path, Path);
-}
-
-#ifdef DEBUG_PROM_TREE
-
-static char *classes[] = {
-	"system", "processor", "cache", "adapter", "controller", "peripheral",
-	"memory"
-};
-
-static char *types[] = {
-	"arc", "cpu", "fpu", "picache", "pdcache", "sicache", "sdcache",
-	"sccache", "memdev", "eisa adapter", "tc adapter", "scsi adapter",
-	"dti adapter", "multi-func adapter", "disk controller",
-	"tp controller", "cdrom controller", "worm controller",
-	"serial controller", "net controller", "display controller",
-	"parallel controller", "pointer controller", "keyboard controller",
-	"audio controller", "misc controller", "disk peripheral",
-	"floppy peripheral", "tp peripheral", "modem peripheral",
-	"monitor peripheral", "printer peripheral", "pointer peripheral",
-	"keyboard peripheral", "terminal peripheral", "line peripheral",
-	"net peripheral", "misc peripheral", "anonymous"
-};
-
-static char *iflags[] = {
-	"bogus", "read only", "removable", "console in", "console out",
-	"input", "output"
-};
-
-static void __init
-dump_component(pcomponent *p)
-{
-	prom_printf("[%p]:class<%s>type<%s>flags<%s>ver<%d>rev<%d>",
-		    p, classes[p->class], types[p->type],
-		    iflags[p->iflags], p->vers, p->rev);
-	prom_printf("key<%08lx>\n\tamask<%08lx>cdsize<%d>ilen<%d>iname<%s>\n",
-		    p->key, p->amask, (int)p->cdsize, (int)p->ilen, p->iname);
-}
-
-static void __init
-traverse(pcomponent *p, int op)
-{
-	dump_component(p);
-	if(ArcGetChild(p))
-		traverse(ArcGetChild(p), 1);
-	if(ArcGetPeer(p) && op)
-		traverse(ArcGetPeer(p), 1);
-}
-
-void __init
-prom_testtree(void)
-{
-	pcomponent *p;
-
-	p = ArcGetChild(PROM_NULL_COMPONENT);
-	dump_component(p);
-	p = ArcGetChild(p);
-	while(p) {
-		dump_component(p);
-		p = ArcGetPeer(p);
-	}
-}
-
-#endif /* DEBUG_PROM_TREE  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/config.in linux-2.4.20/arch/mips64/config.in
--- linux-2.4.19/arch/mips64/config.in	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/config.in	2002-10-29 11:18:33.000000000 +0000
@@ -3,336 +3,7 @@
 # see Documentation/kbuild/config-language.txt.
 #
 define_bool CONFIG_MIPS y
+define_bool CONFIG_MIPS32 n
 define_bool CONFIG_MIPS64 y
 
-mainmenu_name "Linux/MIPS64 Kernel Configuration"
-
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
-
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
-   bool '  Kernel module loader' CONFIG_KMOD
-fi
-endmenu
-
-mainmenu_option next_comment
-comment 'Machine selection'
-dep_bool 'Support for MIPS Atlas board (EXPERIMENTAL)' CONFIG_MIPS_ATLAS $CONFIG_EXPERIMENTAL
-dep_bool 'Support for MIPS Malta board (EXPERIMENTAL)' CONFIG_MIPS_MALTA $CONFIG_EXPERIMENTAL
-dep_bool 'Support for SGI-IP22 (Indy/Indigo2) (EXPERIMENTAL)' CONFIG_SGI_IP22 $CONFIG_EXPERIMENTAL
-bool 'Support for SGI-IP27 (Origin200/2000)' CONFIG_SGI_IP27
-if [ "$CONFIG_SGI_IP27" = "y" ]; then
-   bool '  IP27 N-Mode' CONFIG_SGI_SN0_N_MODE
-   bool '  Discontiguous Memory Support' CONFIG_DISCONTIGMEM
-   bool '  NUMA support' CONFIG_NUMA
-   bool '  Mapped kernel support' CONFIG_MAPPED_KERNEL
-   bool '  Kernel text replication support' CONFIG_REPLICATE_KTEXT
-   bool '  Exception handler replication support' CONFIG_REPLICATE_EXHANDLERS
-   bool '  Multi-Processing support' CONFIG_SMP
-   #bool '  IP27 XXL' CONFIG_SGI_SN0_XXL
-fi
-dep_bool 'Support for SGI-IP32 (O2) (EXPERIMENTAL)' CONFIG_SGI_IP32 $CONFIG_EXPERIMENTAL
-bool 'Support for SiByte SB1250 SOC' CONFIG_SIBYTE_SB1250
-if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then
-   bool '  Support for SB1250 onchip PCI controller' CONFIG_PCI
-   bool '  Support for SB1250 profiling - SB1/SCD perf counters' CONFIG_SIBYTE_SB1250_PROF
-   bool '  Support for BCM1250 profiling using trace buffer' CONFIG_BCM1250_TBPROF
-   bool '  Remote debugging (kgdb over UART 1)' CONFIG_REMOTE_DEBUG
-   bool '  Support for SiByte SWARM board' CONFIG_SIBYTE_SWARM
-   if [ "$CONFIG_SIBYTE_SWARM" = "y" ]; then
-      bool '    Running under simulation' CONFIG_SIMULATION
-      bool '    Configure for L3proc Demo' CONFIG_L3DEMO
-      int '    Maximum memory chunks' CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS 16
-      bool '    Multi-Processing support' CONFIG_SMP
-   fi
-fi
-
-define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
-define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
-
-#
-# Select some configuration options automatically based on user selections.
-#
-
-if [ "$CONFIG_MIPS_ATLAS" = "y" ]; then
-   define_bool CONFIG_BOOT_ELF32 y
-   define_int CONFIG_L1_CACHE_SHIFT 5
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_SWAP_IO_SPACE y
-fi
-if [ "$CONFIG_MIPS_MALTA" = "y" ]; then
-   define_bool CONFIG_BOOT_ELF32 y
-   define_bool CONFIG_I8259 y
-   define_int CONFIG_L1_CACHE_SHIFT 5
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_SWAP_IO_SPACE y
-fi
-if [ "$CONFIG_SGI_IP22" = "y" ]; then
-   define_bool CONFIG_ARC32 y
-   define_bool CONFIG_ARC_CONSOLE y
-   define_bool CONFIG_ARC_MEMORY y
-   define_bool CONFIG_BOARD_SCACHE y
-   define_bool CONFIG_IRQ_CPU y
-   define_bool CONFIG_PC_KEYB y
-   define_bool CONFIG_BOOT_ELF32 y
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_SGI y
-   define_int CONFIG_L1_CACHE_SHIFT 5
-fi
-if [ "$CONFIG_SGI_IP27" = "y" ]; then
-   define_bool CONFIG_BOOT_ELF64 y
-   define_bool CONFIG_ARC64 y
-   define_bool CONFIG_MAPPED_PCI_IO y
-   define_bool CONFIG_PCI y
-   define_bool CONFIG_QL_ISP_A64 y
-   define_int CONFIG_L1_CACHE_SHIFT 7
-fi
-if [ "$CONFIG_SGI_IP32" = "y" ]; then
-   define_bool CONFIG_BOOT_ELF32 y
-   define_bool CONFIG_ARC32 y
-   define_bool CONFIG_PC_KEYB y
-   define_bool CONFIG_PCI y
-   #define_bool CONFIG_BOARD_SCACHE y
-   define_bool CONFIG_MAPPED_PCI_IO n
-   define_bool CONFIG_NONCOHERENT_IO y
-   define_bool CONFIG_ARC_MEMORY y
-   define_int CONFIG_L1_CACHE_SHIFT 5
-fi
-if [ "$CONFIG_SIBYTE_SWARM" = "y" ]; then
-   define_bool CONFIG_BOOT_ELF32 y
-   define_bool CONFIG_SWAP_IO_SPACE y
-   define_bool CONFIG_CFE y
-   define_bool CONFIG_SIBYTE_SB1250 y
-   define_int CONFIG_L1_CACHE_SHIFT 5
-fi
-endmenu
-
-mainmenu_option next_comment
-comment 'CPU selection'
-
-choice 'CPU type' \
-	"R4300	CONFIG_CPU_R4300 \
-	 R4x00	CONFIG_CPU_R4X00 \
-	 R5000	CONFIG_CPU_R5000 \
-	 R52x0	CONFIG_CPU_NEVADA \
-	 R8000	CONFIG_CPU_R8000 \
-	 R10000	CONFIG_CPU_R10000 \
-	 SB1	CONFIG_CPU_SB1" R4x00
-endmenu
-
-if [ "$CONFIG_CPU_SB1" = "y" ]; then
-   bool '  Workarounds for pass 1 sb1 bugs' CONFIG_SB1_PASS_1_WORKAROUNDS
-   bool '  Support for SB1 Cache Error handler' CONFIG_SB1_CACHE_ERROR
-   define_bool CONFIG_VTAG_ICACHE y
-fi
-
-define_bool CONFIG_CPU_HAS_LLSC y
-define_bool CONFIG_CPU_HAS_LLDSCD y
-
-mainmenu_option next_comment
-comment 'General setup'
-
-if [ "$CONFIG_CPU_R10000" = "y" ]; then
-   bool 'Support for large 64-bit configurations' CONFIG_MIPS_INSANE_LARGE
-fi
-bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
-
-if [ "$CONFIG_ARC32" = "y" ]; then
-   bool 'ARC console support' CONFIG_ARC_CONSOLE
-fi
-
-bool 'Networking support' CONFIG_NET
-
-if [ "$CONFIG_PCI" != "y" ]; then
-   define_bool CONFIG_PCI n
-fi
-
-source drivers/pci/Config.in
-
-if [ "$CONFIG_ISA" != "y" ]; then
-   define_bool CONFIG_ISA n
-   define_bool CONFIG_EISA n
-else
-   define_bool CONFIG_EISA y
-fi
-
-define_bool CONFIG_MCA n
-define_bool CONFIG_SBUS n
-
-bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
-
-if [ "$CONFIG_HOTPLUG" = "y" ] ; then
-   source drivers/pcmcia/Config.in
-   source drivers/hotplug/Config.in
-else
-   define_bool CONFIG_PCMCIA n
-   define_bool CONFIG_HOTPLUG_PCI n
-fi
-
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
-define_bool CONFIG_KCORE_ELF y
-define_bool CONFIG_KCORE_AOUT n
-tristate 'Kernel support for 64-bit ELF binaries' CONFIG_BINFMT_ELF
-bool 'Kernel support for Linux/MIPS 32-bit binary compatibility' CONFIG_MIPS32_COMPAT
-define_bool CONFIG_BINFMT_ELF32 $CONFIG_MIPS32_COMPAT
-tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-endmenu
-
-source drivers/mtd/Config.in
-
-source drivers/parport/Config.in
-
-source drivers/pnp/Config.in
-
-source drivers/block/Config.in
-
-source drivers/md/Config.in
-
-if [ "$CONFIG_NET" = "y" ]; then
-   source net/Config.in
-fi
-
-source drivers/telephony/Config.in
-
-if [ "$CONFIG_ISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
-
-   mainmenu_option next_comment
-   comment 'ATA/IDE/MFM/RLL support'
-
-   tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
-
-   if [ "$CONFIG_IDE" != "n" ]; then
-      source drivers/ide/Config.in
-   else
-      define_bool CONFIG_BLK_DEV_IDE_MODES n
-      define_bool CONFIG_BLK_DEV_HD n
-   fi
-   endmenu
-fi
-
-mainmenu_option next_comment
-comment 'SCSI support'
-
-tristate 'SCSI support' CONFIG_SCSI
-
-if [ "$CONFIG_SCSI" != "n" ]; then
-   source drivers/scsi/Config.in
-fi
-endmenu
-
-if [ "$CONFIG_PCI" = "y" ]; then
-   source drivers/message/i2o/Config.in
-fi
-
-if [ "$CONFIG_NET" = "y" ]; then
-   mainmenu_option next_comment
-   comment 'Network device support'
-
-   bool 'Network device support' CONFIG_NETDEVICES
-   if [ "$CONFIG_NETDEVICES" = "y" ]; then
-      source drivers/net/Config.in
-      if [ "$CONFIG_ATM" = "y" ]; then
-	 source drivers/atm/Config.in
-      fi
-   fi
-   endmenu
-fi
-
-source net/ax25/Config.in
-
-source net/irda/Config.in
-
-if [ "$CONFIG_NET" != "n" ]; then
-   mainmenu_option next_comment
-   comment 'ISDN subsystem'
-
-   tristate 'ISDN support' CONFIG_ISDN
-   if [ "$CONFIG_ISDN" != "n" ]; then
-      source drivers/isdn/Config.in
-   fi
-   endmenu
-fi
-
-if [ "$CONFIG_ISA" = "y" ]; then
-   mainmenu_option next_comment
-   comment 'Old CD-ROM drivers (not SCSI, not IDE)'
-
-   bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
-   if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
-      source drivers/cdrom/Config.in
-   fi
-   endmenu
-fi
-
-source drivers/char/Config.in
-
-#source drivers/misc/Config.in
-
-source drivers/media/Config.in
-
-if [ "$CONFIG_SGI_IP22" = "y" ]; then
-   mainmenu_option next_comment
-   comment 'SGI Character devices'
-   if [ "$CONFIG_VT" = "y" ]; then
-      tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE
-      if [ "$CONFIG_SGI_NEWPORT_CONSOLE" = "y" ]; then
-         define_bool CONFIG_FONT_8x16 y
-      fi
-      define_bool CONFIG_DUMMY_CONSOLE y
-   fi
-   endmenu
-fi
-
-source fs/Config.in
-
-if [ "$CONFIG_VT" = "y" ]; then
-   mainmenu_option next_comment
-   comment 'Console drivers'
-   bool 'VGA text console' CONFIG_VGA_CONSOLE
-   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'MDA text console (dual-headed) (EXPERIMENTAL)' CONFIG_MDA_CONSOLE
-      source drivers/video/Config.in
-   fi
-   endmenu
-fi
-
-mainmenu_option next_comment
-comment 'Sound'
-
-tristate 'Sound card support' CONFIG_SOUND
-if [ "$CONFIG_SOUND" != "n" ]; then
-   source drivers/sound/Config.in
-fi
-endmenu
-
-if [ "$CONFIG_SGI_IP22" = "y" ]; then
-   source drivers/sgi/Config.in
-fi
-
-source drivers/usb/Config.in
-
-source net/bluetooth/Config.in
-
-source drivers/input/Config.in
-
-mainmenu_option next_comment
-comment 'Kernel hacking'
-
-#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
-bool 'Are you using a crosscompiler' CONFIG_CROSSCOMPILE
-bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
-bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
-if [ "$CONFIG_SMP" != "y" ]; then
-   bool 'Run uncached' CONFIG_MIPS_UNCACHED
-fi
-endmenu
+source arch/mips/config-shared.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/defconfig linux-2.4.20/arch/mips64/defconfig
--- linux-2.4.19/arch/mips64/defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/defconfig	2002-10-29 11:18:34.000000000 +0000
@@ -2,6 +2,7 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_MIPS=y
+# CONFIG_MIPS32 is not set
 CONFIG_MIPS64=y
 
 #
@@ -17,8 +18,32 @@
 #
 # Machine selection
 #
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_ALGOR_P4032 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_MIPS_ITE8172 is not set
 # CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
 CONFIG_SGI_IP27=y
 # CONFIG_SGI_SN0_N_MODE is not set
@@ -29,38 +54,58 @@
 # CONFIG_REPLICATE_EXHANDLERS is not set
 CONFIG_SMP=y
 # CONFIG_SGI_IP32 is not set
-# CONFIG_SIBYTE_SB1250 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BOOT_ELF64=y
 CONFIG_ARC64=y
-CONFIG_MAPPED_PCI_IO=y
 CONFIG_PCI=y
 CONFIG_QL_ISP_A64=y
 CONFIG_L1_CACHE_SHIFT=7
+# CONFIG_MIPS_AU1000 is not set
 
 #
 # CPU selection
 #
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
 # CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
 # CONFIG_CPU_R8000 is not set
 CONFIG_CPU_R10000=y
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+# CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_LLDSCD=y
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
 #
-# CONFIG_MIPS_INSANE_LARGE is not set
 # CONFIG_CPU_LITTLE_ENDIAN is not set
+# CONFIG_BINFMT_IRIX is not set
+# CONFIG_FORWARD_KEYBOARD is not set
+# CONFIG_MIPS_INSANE_LARGE is not set
 CONFIG_NET=y
 CONFIG_PCI_NAMES=y
 # CONFIG_ISA is not set
 # CONFIG_EISA is not set
+# CONFIG_TC is not set
 # CONFIG_MCA is not set
 # CONFIG_SBUS is not set
 # CONFIG_HOTPLUG is not set
@@ -71,10 +116,12 @@
 CONFIG_SYSCTL=y
 CONFIG_KCORE_ELF=y
 # CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_MIPS32_COMPAT=y
 CONFIG_BINFMT_ELF32=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -107,6 +154,7 @@
 # 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)
@@ -298,6 +346,7 @@
 #
 # 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
@@ -341,6 +390,15 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -394,11 +452,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -411,6 +464,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -428,6 +483,9 @@
 # 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
@@ -458,6 +516,7 @@
 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
@@ -472,7 +531,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -492,10 +550,16 @@
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Sound
 #
 # CONFIG_SOUND is not set
@@ -511,17 +575,16 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
 # CONFIG_REMOTE_DEBUG is not set
+# CONFIG_GDB_CONSOLE is not set
+# CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/defconfig-atlas linux-2.4.20/arch/mips64/defconfig-atlas
--- linux-2.4.19/arch/mips64/defconfig-atlas	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/defconfig-atlas	2002-10-29 11:18:33.000000000 +0000
@@ -2,6 +2,7 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_MIPS=y
+# CONFIG_MIPS32 is not set
 CONFIG_MIPS64=y
 
 #
@@ -17,41 +18,89 @@
 #
 # Machine selection
 #
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_ALGOR_P4032 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_MIPS_ITE8172 is not set
 CONFIG_MIPS_ATLAS=y
+# CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
 # CONFIG_SGI_IP27 is not set
 # CONFIG_SGI_IP32 is not set
-# CONFIG_SIBYTE_SB1250 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BOOT_ELF32=y
 CONFIG_L1_CACHE_SHIFT=5
+CONFIG_NEW_IRQ=y
+CONFIG_NEW_TIME_C=y
 CONFIG_NONCOHERENT_IO=y
 CONFIG_PCI=y
 CONFIG_SWAP_IO_SPACE=y
+# CONFIG_MIPS_AU1000 is not set
 
 #
 # CPU selection
 #
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
 CONFIG_CPU_R5000=y
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
 # CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
+CONFIG_BOARD_SCACHE=y
+# CONFIG_64BIT_PHYS_ADDR is not set
+# CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_LLDSCD=y
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
 #
 # CONFIG_CPU_LITTLE_ENDIAN is not set
+# CONFIG_BINFMT_IRIX is not set
+# CONFIG_FORWARD_KEYBOARD is not set
 CONFIG_NET=y
 CONFIG_PCI_NAMES=y
 # CONFIG_ISA is not set
 # CONFIG_EISA is not set
+# CONFIG_TC is not set
 # CONFIG_MCA is not set
 # CONFIG_SBUS is not set
 # CONFIG_HOTPLUG is not set
@@ -59,13 +108,15 @@
 # CONFIG_HOTPLUG_PCI is not set
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
 CONFIG_KCORE_ELF=y
 # CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_MIPS32_COMPAT=y
 CONFIG_BINFMT_ELF32=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -99,6 +150,7 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -115,8 +167,9 @@
 #
 # Networking options
 #
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK_DEV=y
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
@@ -302,6 +355,7 @@
 #
 # 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
@@ -348,6 +402,15 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -401,11 +464,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -418,6 +476,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -435,6 +495,9 @@
 # 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
@@ -465,6 +528,7 @@
 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_SMB_FS is not set
@@ -478,7 +542,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -489,6 +552,11 @@
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Sound
 #
 # CONFIG_SOUND is not set
@@ -504,18 +572,17 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
 # CONFIG_REMOTE_DEBUG is not set
+# CONFIG_GDB_CONSOLE is not set
+# CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/defconfig-ip22 linux-2.4.20/arch/mips64/defconfig-ip22
--- linux-2.4.19/arch/mips64/defconfig-ip22	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/defconfig-ip22	2002-10-29 11:18:32.000000000 +0000
@@ -2,6 +2,7 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_MIPS=y
+# CONFIG_MIPS32 is not set
 CONFIG_MIPS64=y
 
 #
@@ -19,47 +20,98 @@
 #
 # Machine selection
 #
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_ALGOR_P4032 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_MIPS_ITE8172 is not set
 # CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
 CONFIG_SGI_IP22=y
 # CONFIG_SGI_IP27 is not set
 # CONFIG_SGI_IP32 is not set
-# CONFIG_SIBYTE_SB1250 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_ARC32=y
 CONFIG_ARC_CONSOLE=y
 CONFIG_ARC_MEMORY=y
 CONFIG_BOARD_SCACHE=y
-CONFIG_IRQ_CPU=y
-CONFIG_PC_KEYB=y
 CONFIG_BOOT_ELF32=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_IRQ_CPU=y
+CONFIG_L1_CACHE_SHIFT=5
+CONFIG_NONCOHERENT_IO=y
+CONFIG_NEW_IRQ=y
+CONFIG_NEW_TIME_C=y
 CONFIG_NONCOHERENT_IO=y
+CONFIG_PC_KEYB=y
 CONFIG_SGI=y
-CONFIG_L1_CACHE_SHIFT=5
+# CONFIG_MIPS_AU1000 is not set
 
 #
 # CPU selection
 #
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
 CONFIG_CPU_R5000=y
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
 # CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
+CONFIG_BOARD_SCACHE=y
+# CONFIG_64BIT_PHYS_ADDR is not set
+# CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_LLDSCD=y
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
 #
 # CONFIG_CPU_LITTLE_ENDIAN is not set
+# CONFIG_BINFMT_IRIX is not set
+# CONFIG_FORWARD_KEYBOARD is not set
 CONFIG_ARC_CONSOLE=y
+# CONFIG_IP22_EISA is not set
 CONFIG_NET=y
 # CONFIG_PCI is not set
 # CONFIG_ISA is not set
 # CONFIG_EISA is not set
+# CONFIG_TC is not set
 # CONFIG_MCA is not set
 # CONFIG_SBUS is not set
 # CONFIG_HOTPLUG is not set
@@ -70,10 +122,12 @@
 CONFIG_SYSCTL=y
 CONFIG_KCORE_ELF=y
 # CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_MIPS32_COMPAT=y
 CONFIG_BINFMT_ELF32=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -106,6 +160,7 @@
 # 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)
@@ -185,6 +240,13 @@
 # CONFIG_PHONE_IXJ_PCMCIA is not set
 
 #
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
 # SCSI support
 #
 CONFIG_SCSI=y
@@ -287,6 +349,7 @@
 #
 # 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
@@ -333,6 +396,15 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -381,7 +453,6 @@
 # CONFIG_EUROTECH_WDT is not set
 # CONFIG_IB700_WDT is not set
 # CONFIG_WAFER_WDT is not set
-CONFIG_INDYDOG=y
 # CONFIG_I810_TCO is not set
 # CONFIG_MIXCOMWD is not set
 # CONFIG_60XX_WDT is not set
@@ -392,6 +463,7 @@
 # CONFIG_WDTPCI is not set
 # CONFIG_MACHZ_WDT is not set
 CONFIG_INDYDOG=y
+# CONFIG_AMD7XX_TCO is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -406,11 +478,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # SGI Character devices
 #
 CONFIG_SGI_NEWPORT_CONSOLE=y
@@ -430,6 +497,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -447,6 +516,9 @@
 CONFIG_ISO9660_FS=y
 # 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
@@ -477,6 +549,7 @@
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
@@ -490,7 +563,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -510,10 +582,16 @@
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Console drivers
 #
 # CONFIG_VGA_CONSOLE is not set
@@ -548,18 +626,15 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
-# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/defconfig-ip27 linux-2.4.20/arch/mips64/defconfig-ip27
--- linux-2.4.19/arch/mips64/defconfig-ip27	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/defconfig-ip27	2002-10-29 11:18:40.000000000 +0000
@@ -2,6 +2,7 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_MIPS=y
+# CONFIG_MIPS32 is not set
 CONFIG_MIPS64=y
 
 #
@@ -17,8 +18,32 @@
 #
 # Machine selection
 #
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_ALGOR_P4032 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_MIPS_ITE8172 is not set
 # CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
 CONFIG_SGI_IP27=y
 # CONFIG_SGI_SN0_N_MODE is not set
@@ -29,38 +54,58 @@
 # CONFIG_REPLICATE_EXHANDLERS is not set
 CONFIG_SMP=y
 # CONFIG_SGI_IP32 is not set
-# CONFIG_SIBYTE_SB1250 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BOOT_ELF64=y
 CONFIG_ARC64=y
-CONFIG_MAPPED_PCI_IO=y
 CONFIG_PCI=y
 CONFIG_QL_ISP_A64=y
 CONFIG_L1_CACHE_SHIFT=7
+# CONFIG_MIPS_AU1000 is not set
 
 #
 # CPU selection
 #
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
 # CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
 # CONFIG_CPU_R8000 is not set
 CONFIG_CPU_R10000=y
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+# CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_LLDSCD=y
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
 #
-# CONFIG_MIPS_INSANE_LARGE is not set
 # CONFIG_CPU_LITTLE_ENDIAN is not set
+# CONFIG_BINFMT_IRIX is not set
+# CONFIG_FORWARD_KEYBOARD is not set
+# CONFIG_MIPS_INSANE_LARGE is not set
 CONFIG_NET=y
 CONFIG_PCI_NAMES=y
 # CONFIG_ISA is not set
 # CONFIG_EISA is not set
+# CONFIG_TC is not set
 # CONFIG_MCA is not set
 # CONFIG_SBUS is not set
 # CONFIG_HOTPLUG is not set
@@ -71,10 +116,12 @@
 CONFIG_SYSCTL=y
 CONFIG_KCORE_ELF=y
 # CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_MIPS32_COMPAT=y
 CONFIG_BINFMT_ELF32=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -107,6 +154,7 @@
 # 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)
@@ -298,6 +346,7 @@
 #
 # 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
@@ -341,6 +390,15 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -394,11 +452,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -411,6 +464,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -428,6 +483,9 @@
 # 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
@@ -458,6 +516,7 @@
 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
@@ -472,7 +531,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -492,10 +550,16 @@
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Sound
 #
 # CONFIG_SOUND is not set
@@ -511,17 +575,16 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
 # CONFIG_REMOTE_DEBUG is not set
+# CONFIG_GDB_CONSOLE is not set
+# CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/defconfig-ip32 linux-2.4.20/arch/mips64/defconfig-ip32
--- linux-2.4.19/arch/mips64/defconfig-ip32	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/defconfig-ip32	2002-10-29 11:18:50.000000000 +0000
@@ -2,6 +2,7 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_MIPS=y
+# CONFIG_MIPS32 is not set
 CONFIG_MIPS64=y
 
 #
@@ -17,45 +18,90 @@
 #
 # Machine selection
 #
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_ALGOR_P4032 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_MIPS_ITE8172 is not set
 # CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
 # CONFIG_SGI_IP27 is not set
 CONFIG_SGI_IP32=y
-# CONFIG_SIBYTE_SB1250 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_BOOT_ELF32=y
+CONFIG_ARC_MEMORY=y
 CONFIG_ARC32=y
+CONFIG_BOOT_ELF32=y
+CONFIG_L1_CACHE_SHIFT=5
+CONFIG_NONCOHERENT_IO=y
 CONFIG_PC_KEYB=y
 CONFIG_PCI=y
-# CONFIG_MAPPED_PCI_IO is not set
-CONFIG_NONCOHERENT_IO=y
-CONFIG_ARC_MEMORY=y
-CONFIG_L1_CACHE_SHIFT=5
+# CONFIG_MIPS_AU1000 is not set
 
 #
 # CPU selection
 #
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
 CONFIG_CPU_R5000=y
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
 # CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
+CONFIG_BOARD_SCACHE=y
+# CONFIG_64BIT_PHYS_ADDR is not set
+# CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_LLDSCD=y
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
 #
 # CONFIG_CPU_LITTLE_ENDIAN is not set
+# CONFIG_BINFMT_IRIX is not set
+# CONFIG_FORWARD_KEYBOARD is not set
 CONFIG_ARC_CONSOLE=y
 CONFIG_NET=y
 CONFIG_PCI_NAMES=y
 # CONFIG_ISA is not set
 # CONFIG_EISA is not set
+# CONFIG_TC is not set
 # CONFIG_MCA is not set
 # CONFIG_SBUS is not set
 # CONFIG_HOTPLUG is not set
@@ -66,10 +112,12 @@
 CONFIG_SYSCTL=y
 CONFIG_KCORE_ELF=y
 # CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_MIPS32_COMPAT=y
 CONFIG_BINFMT_ELF32=y
 CONFIG_BINFMT_MISC=y
+# CONFIG_PM is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -102,6 +150,7 @@
 # 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)
@@ -312,6 +361,7 @@
 #
 # 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
@@ -358,6 +408,15 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -415,11 +474,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -432,6 +486,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -449,6 +505,9 @@
 # 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
@@ -479,6 +538,7 @@
 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
@@ -493,7 +553,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -509,10 +568,16 @@
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Sound
 #
 # CONFIG_SOUND is not set
@@ -528,18 +593,17 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
 # CONFIG_REMOTE_DEBUG is not set
+# CONFIG_GDB_CONSOLE is not set
+# CONFIG_DEBUG is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_MIPS_UNCACHED=y
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/defconfig-malta linux-2.4.20/arch/mips64/defconfig-malta
--- linux-2.4.19/arch/mips64/defconfig-malta	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/defconfig-malta	2002-10-29 11:18:39.000000000 +0000
@@ -2,6 +2,7 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_MIPS=y
+# CONFIG_MIPS32 is not set
 CONFIG_MIPS64=y
 
 #
@@ -17,33 +18,79 @@
 #
 # Machine selection
 #
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_ALGOR_P4032 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_MIPS_ITE8172 is not set
 # CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
 CONFIG_MIPS_MALTA=y
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
 # CONFIG_SGI_IP27 is not set
 # CONFIG_SGI_IP32 is not set
-# CONFIG_SIBYTE_SB1250 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BOOT_ELF32=y
+CONFIG_HAVE_STD_PC_SERIAL_PORT=y
 CONFIG_I8259=y
 CONFIG_L1_CACHE_SHIFT=5
+CONFIG_NEW_IRQ=y
+CONFIG_NEW_TIME_C=y
 CONFIG_NONCOHERENT_IO=y
-CONFIG_PCI=y
 CONFIG_SWAP_IO_SPACE=y
+CONFIG_PC_KEYB=y
+CONFIG_PCI=y
+# CONFIG_MIPS_AU1000 is not set
 
 #
 # CPU selection
 #
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 CONFIG_CPU_R4X00=y
+# CONFIG_CPU_TX49XX is not set
 # CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
 # CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+# CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_LLDSCD=y
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
@@ -53,6 +100,7 @@
 CONFIG_PCI_NAMES=y
 # CONFIG_ISA is not set
 # CONFIG_EISA is not set
+# CONFIG_TC is not set
 # CONFIG_MCA is not set
 # CONFIG_SBUS is not set
 # CONFIG_HOTPLUG is not set
@@ -60,13 +108,15 @@
 # CONFIG_HOTPLUG_PCI is not set
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
 CONFIG_KCORE_ELF=y
 # CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_MIPS32_COMPAT=y
 CONFIG_BINFMT_ELF32=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -100,6 +150,7 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -303,6 +354,7 @@
 #
 # 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
@@ -349,6 +401,15 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -402,11 +463,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -419,6 +475,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -436,6 +494,9 @@
 # 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
@@ -466,6 +527,7 @@
 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_SMB_FS is not set
@@ -479,7 +541,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -490,6 +551,11 @@
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Sound
 #
 # CONFIG_SOUND is not set
@@ -505,18 +571,17 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
 # CONFIG_REMOTE_DEBUG is not set
+# CONFIG_GDB_CONSOLE is not set
+# CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/defconfig-sb1250-swarm linux-2.4.20/arch/mips64/defconfig-sb1250-swarm
--- linux-2.4.19/arch/mips64/defconfig-sb1250-swarm	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/defconfig-sb1250-swarm	2002-10-29 11:18:33.000000000 +0000
@@ -2,82 +2,138 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_MIPS=y
+# CONFIG_MIPS32 is not set
 CONFIG_MIPS64=y
 
 #
 # Code maturity level options
 #
-# CONFIG_EXPERIMENTAL is not set
+CONFIG_EXPERIMENTAL=y
 
 #
 # Loadable module support
 #
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
 
 #
 # Machine selection
 #
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_ALGOR_P4032 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_MIPS_ITE8172 is not set
 # CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
 # CONFIG_SGI_IP22 is not set
 # CONFIG_SGI_IP27 is not set
 # CONFIG_SGI_IP32 is not set
+CONFIG_SIBYTE_SB1xxx_SOC=y
 CONFIG_SIBYTE_SB1250=y
-# CONFIG_PCI is not set
+# CONFIG_SIMULATION is not set
+CONFIG_SIBYTE_CFE=y
+# CONFIG_SIBYTE_CFE_CONSOLE is not set
 # CONFIG_SIBYTE_SB1250_PROF is not set
 # CONFIG_BCM1250_TBPROF is not set
-# CONFIG_REMOTE_DEBUG is not set
-CONFIG_SIBYTE_SWARM=y
-# CONFIG_SIMULATION is not set
-# CONFIG_L3DEMO is not set
-CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS=16
 CONFIG_SMP=y
+# CONFIG_PCI is not set
+CONFIG_SIBYTE_SWARM=y
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_BOOT_ELF32=y
+CONFIG_NEW_IRQ=y
+CONFIG_NEW_TIME_C=y
+CONFIG_DUMMY_KEYB=y
 CONFIG_SWAP_IO_SPACE=y
-CONFIG_CFE=y
-CONFIG_SIBYTE_SB1250=y
-CONFIG_L1_CACHE_SHIFT=5
+CONFIG_BOOT_ELF32=y
+# CONFIG_MIPS_AU1000 is not set
 
 #
 # CPU selection
 #
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
 # CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
 # CONFIG_CPU_NEVADA is not set
 # CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
 CONFIG_CPU_SB1=y
+CONFIG_CPU_SB1_PASS_1=y
+# CONFIG_CPU_SB1_PASS_2 is not set
+# CONFIG_CPU_SB1_PASS_2_2 is not set
 CONFIG_SB1_PASS_1_WORKAROUNDS=y
+CONFIG_CPU_HAS_PREFETCH=y
 CONFIG_SB1_CACHE_ERROR=y
+CONFIG_SB1_CERR_IGNORE_RECOVERABLE=y
+# CONFIG_SB1_CERR_SPIN is not set
 CONFIG_VTAG_ICACHE=y
+# CONFIG_64BIT_PHYS_ADDR is not set
+# CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_LLDSCD=y
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
 
 #
 # General setup
 #
 # CONFIG_CPU_LITTLE_ENDIAN is not set
+# CONFIG_BINFMT_IRIX is not set
+# CONFIG_FORWARD_KEYBOARD is not set
 CONFIG_NET=y
 # CONFIG_PCI is not set
 # CONFIG_ISA is not set
 # CONFIG_EISA is not set
+# CONFIG_TC is not set
 # CONFIG_MCA is not set
 # CONFIG_SBUS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_PCMCIA is not set
 # CONFIG_HOTPLUG_PCI is not set
-# CONFIG_SYSVIPC is not set
+CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
 CONFIG_KCORE_ELF=y
 # CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
-CONFIG_MIPS32_COMPAT=y
-CONFIG_BINFMT_ELF32=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_BINFMT_ELF32 is not set
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -110,6 +166,7 @@
 # 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)
@@ -134,14 +191,15 @@
 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=y
-# CONFIG_IP_PNP_RARP is not set
+# CONFIG_IP_PNP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
 
 #
@@ -156,6 +214,14 @@
 # CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
@@ -175,6 +241,13 @@
 # CONFIG_PHONE_IXJ_PCMCIA is not set
 
 #
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
 # SCSI support
 #
 # CONFIG_SCSI is not set
@@ -192,13 +265,13 @@
 # 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_NET_SB1250_MAC=y
-CONFIG_NET_SB1250_MAC=y
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
@@ -216,6 +289,7 @@
 #
 # 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
@@ -223,6 +297,7 @@
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
@@ -237,6 +312,8 @@
 #
 # CONFIG_TR is not set
 # CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
 
 #
 # Wan interfaces
@@ -259,6 +336,15 @@
 # CONFIG_ISDN is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -273,7 +359,9 @@
 # CONFIG_ESPSERIAL is not set
 # CONFIG_MOXA_INTELLIO is not set
 # CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
 # CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
 # CONFIG_N_HDLC is not set
 # CONFIG_RISCOM8 is not set
 # CONFIG_SPECIALIX is not set
@@ -282,14 +370,14 @@
 # CONFIG_STALDRV is not set
 # CONFIG_SERIAL_TX3912 is not set
 # CONFIG_SERIAL_TX3912_CONSOLE is not set
-# CONFIG_AU1000_UART is not set
 # CONFIG_TXX927_SERIAL is not set
 CONFIG_SIBYTE_SB1250_DUART=y
 CONFIG_SIBYTE_SB1250_DUART_CONSOLE=y
 CONFIG_SERIAL_CONSOLE=y
 CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE=1024
 # CONFIG_SIBYTE_SB1250_DUART_NO_PORT_1 is not set
-# CONFIG_UNIX98_PTYS is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
 
 #
 # I2C support
@@ -334,11 +422,6 @@
 # CONFIG_DRM is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -351,9 +434,11 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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_EXT3_FS=y
+CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
@@ -363,11 +448,14 @@
 # CONFIG_JFFS_FS is not set
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
-# CONFIG_TMPFS 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
@@ -377,11 +465,11 @@
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS 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_EXT2_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UDF_FS is not set
 # CONFIG_UDF_RW is not set
@@ -395,9 +483,10 @@
 # CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
+# 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=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -412,30 +501,21 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
 #
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
+# CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-CONFIG_SGI_PARTITION=y
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # Sound
 #
 # CONFIG_SOUND is not set
@@ -451,17 +531,14 @@
 # CONFIG_BLUEZ is not set
 
 #
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
-# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/defconfig-sead linux-2.4.20/arch/mips64/defconfig-sead
--- linux-2.4.19/arch/mips64/defconfig-sead	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips64/defconfig-sead	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,361 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MIPS=y
+# CONFIG_MIPS32 is not set
+CONFIG_MIPS64=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Machine selection
+#
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_ALGOR_P4032 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MIPS_MALTA is not set
+CONFIG_MIPS_SEAD=y
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_L1_CACHE_SHIFT=5
+CONFIG_NEW_IRQ=y
+CONFIG_NEW_TIME_C=y
+CONFIG_NONCOHERENT_IO=y
+# CONFIG_PCI is not set
+# CONFIG_MIPS_AU1000 is not set
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+CONFIG_CPU_R4X00=y
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_SB1 is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_LLDSCD=y
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
+
+#
+# General setup
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_NET is not set
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_TC is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_MIPS32_COMPAT=y
+CONFIG_BINFMT_ELF32=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=18432
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_STATS is not set
+
+#
+# MIPS initrd options
+#
+# CONFIG_EMBEDDED_RAMDISK 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
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+# CONFIG_PHONE_IXJ_PCMCIA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG 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
+# CONFIG_DRM is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_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 is not set
+# 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_NCPFS_NLS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Kernel hacking
+#
+CONFIG_CROSSCOMPILE=y
+# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_GDB_CONSOLE is not set
+# CONFIG_DEBUG is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/Makefile linux-2.4.20/arch/mips64/kernel/Makefile
--- linux-2.4.19/arch/mips64/kernel/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/Makefile	2002-10-29 11:18:37.000000000 +0000
@@ -12,11 +12,12 @@
 
 O_TARGET := kernel.o
 
-export-objs = irq.o mips64_ksyms.o pci-dma.o setup.o smp.o
+export-objs	= irq.o mips64_ksyms.o pci-dma.o setup.o smp.o
 
-obj-y	:= branch.o entry.o irq.o proc.o process.o ptrace.o r4k_cache.o \
-	   r4k_fpu.o r4k_genex.o r4k_switch.o reset.o scall_64.o semaphore.o \
-	   setup.o signal.o syscall.o time.o traps.o unaligned.o
+obj-y		:= branch.o cpu-probe.o entry.o irq.o proc.o process.o \
+		   ptrace.o r4k_cache.o r4k_fpu.o r4k_genex.o r4k_switch.o \
+		   reset.o scall_64.o semaphore.o setup.o signal.o syscall.o \
+		   time.o traps.o unaligned.o
 
 obj-$(CONFIG_I8259)		+= i8259.o
 obj-$(CONFIG_IRQ_CPU)		+= irq_cpu.o
@@ -30,6 +31,6 @@
 obj-y				+= pci-dma.o
 endif
 
-CFLAGS_r4k_genex.o := -P
+AFLAGS_r4k_genex.o := -P
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/binfmt_elf32.c linux-2.4.20/arch/mips64/kernel/binfmt_elf32.c
--- linux-2.4.19/arch/mips64/kernel/binfmt_elf32.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/binfmt_elf32.c	2002-10-29 11:18:35.000000000 +0000
@@ -27,8 +27,26 @@
 typedef double elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
-#define elf_check_arch(x)	\
-	((x)->e_machine == EM_MIPS)
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(hdr)						\
+({									\
+	int __res = 1;							\
+	struct elfhdr *__h = (hdr);					\
+									\
+	if (__h->e_machine != EM_MIPS)					\
+		__res = 0;						\
+	if (__h->e_ident[EI_CLASS] != ELFCLASS32)			\
+		__res = 0;						\
+	if ((__h->e_flags & EF_MIPS_ABI2) != 0)				\
+		__res = 0;						\
+	if (((__h->e_flags & EF_MIPS_ABI) != 0) &&			\
+	    ((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32))		\
+		__res = 0;						\
+									\
+	__res;								\
+})
 
 #define TASK32_SIZE		0x80000000UL
 #undef ELF_ET_DYN_BASE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/cpu-probe.c linux-2.4.20/arch/mips64/kernel/cpu-probe.c
--- linux-2.4.19/arch/mips64/kernel/cpu-probe.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/cpu-probe.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,489 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <asm/bugs.h>
+#include <asm/cpu.h>
+#include <asm/mipsregs.h>
+
+/*
+ * Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
+ * the implementation of the "wait" feature differs between CPU families. This
+ * points to the function that implements CPU specific wait.
+ * The wait instruction stops the pipeline and reduces the power consumption of
+ * the CPU very much.
+ */
+void (*cpu_wait)(void) = NULL;
+
+static void r3081_wait(void)
+{
+	unsigned long cfg = read_32bit_cp0_register(CP0_CONF);
+	write_32bit_cp0_register(CP0_CONF, cfg|CONF_HALT);
+}
+
+static void r39xx_wait(void)
+{
+	unsigned long cfg = read_32bit_cp0_register(CP0_CONF);
+	write_32bit_cp0_register(CP0_CONF, cfg|TX39_CONF_HALT);
+}
+
+static void r4k_wait(void)
+{
+	__asm__(".set\tmips3\n\t"
+		"wait\n\t"
+		".set\tmips0");
+}
+
+void au1k_wait(void)
+{
+#ifdef CONFIG_PM
+	/* using the wait instruction makes CP0 counter unusable */
+	__asm__(".set\tmips3\n\t"
+		"wait\n\t"
+		"nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" ".set\tmips0");
+#else
+	__asm__("nop\n\t" "nop\n\t");
+#endif
+}
+
+static inline void check_wait(void)
+{
+	printk("Checking for 'wait' instruction... ");
+	switch(mips_cpu.cputype) {
+	case CPU_R3081:
+	case CPU_R3081E:
+		cpu_wait = r3081_wait;
+		printk(" available.\n");
+		break;
+	case CPU_TX3927:
+	case CPU_TX39XX:
+		cpu_wait = r39xx_wait;
+		printk(" available.\n");
+		break;
+	case CPU_R4200:
+/*	case CPU_R4300: */
+	case CPU_R4600:
+	case CPU_R4640:
+	case CPU_R4650:
+	case CPU_R4700:
+	case CPU_R5000:
+	case CPU_NEVADA:
+	case CPU_RM7000:
+	case CPU_TX49XX:
+	case CPU_4KC:
+	case CPU_4KEC:
+	case CPU_4KSC:
+	case CPU_5KC:
+/*	case CPU_20KC:*/
+		cpu_wait = r4k_wait;
+		printk(" available.\n");
+		break;
+	case CPU_AU1000:
+	case CPU_AU1100:
+	case CPU_AU1500:
+		cpu_wait = au1k_wait;
+		printk(" available.\n");
+		break;
+	default:
+		printk(" unavailable.\n");
+		break;
+	}
+}
+
+void __init check_bugs(void)
+{
+	check_wait();
+}
+
+/*
+ * Probe whether cpu has config register by trying to play with
+ * alternate cache bit and see whether it matters.
+ * It's used by cpu_probe to distinguish between R3000A and R3081.
+ */
+static inline int cpu_has_confreg(void)
+{
+#ifdef CONFIG_CPU_R3000
+	extern unsigned long r3k_cache_size(unsigned long);
+	unsigned long size1, size2;
+	unsigned long cfg = read_32bit_cp0_register(CP0_CONF);
+
+	size1 = r3k_cache_size(ST0_ISC);
+	write_32bit_cp0_register(CP0_CONF, cfg^CONF_AC);
+	size2 = r3k_cache_size(ST0_ISC);
+	write_32bit_cp0_register(CP0_CONF, cfg);
+	return size1 != size2;
+#else
+	return 0;
+#endif
+}
+
+/*
+ * Get the FPU Implementation/Revision.
+ */
+static inline unsigned long cpu_get_fpu_id(void)
+{
+	unsigned long tmp, fpu_id;
+
+	tmp = read_32bit_cp0_register(CP0_STATUS);
+	__enable_fpu();
+	fpu_id = read_32bit_cp1_register(CP1_REVISION);
+	write_32bit_cp0_register(CP0_STATUS, tmp);
+	return fpu_id;
+}
+
+/*
+ * Check the CPU has an FPU the official way.
+ */
+static inline int cpu_has_fpu(void)
+{
+	return ((cpu_get_fpu_id() & 0xff00) != FPIR_IMP_NONE);
+}
+
+/* declaration of the global struct */
+struct mips_cpu mips_cpu = {
+    processor_id:	PRID_IMP_UNKNOWN,
+    fpu_id:		FPIR_IMP_NONE,
+    cputype:		CPU_UNKNOWN
+};
+
+/* Shortcut for assembler access to mips_cpu.options */
+int *cpuoptions = &mips_cpu.options;
+
+#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4KTLB \
+		| MIPS_CPU_COUNTER | MIPS_CPU_CACHE_CDEX)
+
+__init void cpu_probe(void)
+{
+#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
+	unsigned long config0 = read_32bit_cp0_register(CP0_CONFIG);
+	unsigned long config1;
+
+        if (config0 & (1 << 31)) {
+		/* MIPS32 or MIPS64 compliant CPU. Read Config 1 register. */
+		mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+			MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | MIPS_CPU_DIVEC;
+		config1 = read_mips32_cp0_config1();
+		if (config1 & (1 << 3))
+			mips_cpu.options |= MIPS_CPU_WATCH;
+		if (config1 & (1 << 2))
+			mips_cpu.options |= MIPS_CPU_MIPS16;
+		if (config1 & (1 << 1))
+			mips_cpu.options |= MIPS_CPU_EJTAG;
+		if (config1 & 1) {
+			mips_cpu.options |= MIPS_CPU_FPU;
+#if defined(CONFIG_CPU_MIPS64)
+			mips_cpu.options |= MIPS_CPU_32FPR;
+#endif
+		}
+		mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT;
+	}
+#endif
+	mips_cpu.processor_id = read_32bit_cp0_register(CP0_PRID);
+	switch (mips_cpu.processor_id & 0xff0000) {
+	case PRID_COMP_LEGACY:
+		switch (mips_cpu.processor_id & 0xff00) {
+		case PRID_IMP_R2000:
+			mips_cpu.cputype = CPU_R2000;
+			mips_cpu.isa_level = MIPS_CPU_ISA_I;
+			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_NOFPUEX;
+			if (cpu_has_fpu())
+				mips_cpu.options |= MIPS_CPU_FPU;
+			mips_cpu.tlbsize = 64;
+			break;
+		case PRID_IMP_R3000:
+			if ((mips_cpu.processor_id & 0xff) == PRID_REV_R3000A)
+				if (cpu_has_confreg())
+					mips_cpu.cputype = CPU_R3081E;
+				else
+					mips_cpu.cputype = CPU_R3000A;
+			else
+				mips_cpu.cputype = CPU_R3000;
+			mips_cpu.isa_level = MIPS_CPU_ISA_I;
+			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_NOFPUEX;
+			if (cpu_has_fpu())
+				mips_cpu.options |= MIPS_CPU_FPU;
+			mips_cpu.tlbsize = 64;
+			break;
+		case PRID_IMP_R4000:
+			if ((mips_cpu.processor_id & 0xff) == PRID_REV_R4400)
+				mips_cpu.cputype = CPU_R4400SC;
+			else
+				mips_cpu.cputype = CPU_R4000SC;
+			mips_cpu.isa_level = MIPS_CPU_ISA_III;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+			                   MIPS_CPU_32FPR | MIPS_CPU_WATCH |
+			                   MIPS_CPU_VCE;
+			mips_cpu.tlbsize = 48;
+			break;
+                case PRID_IMP_VR41XX:
+			switch (mips_cpu.processor_id & 0xf0) {
+#ifndef CONFIG_VR4181
+			case PRID_REV_VR4111:
+				mips_cpu.cputype = CPU_VR4111;
+				break;
+#else
+			case PRID_REV_VR4181:
+				mips_cpu.cputype = CPU_VR4181;
+				break;
+#endif
+			case PRID_REV_VR4121:
+				mips_cpu.cputype = CPU_VR4121;
+				break;
+			case PRID_REV_VR4122:
+				if ((mips_cpu.processor_id & 0xf) < 0x3)
+					mips_cpu.cputype = CPU_VR4122;
+				else
+					mips_cpu.cputype = CPU_VR4181A;
+				break;
+			case PRID_REV_VR4131:
+				mips_cpu.cputype = CPU_VR4131;
+				mips_cpu.icache.ways = 2;
+				mips_cpu.dcache.ways = 2;
+				break;
+			default:
+				printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n");
+				mips_cpu.cputype = CPU_VR41XX;
+				break;
+			}
+                        mips_cpu.isa_level = MIPS_CPU_ISA_III;
+                        mips_cpu.options = R4K_OPTS;
+                        mips_cpu.tlbsize = 32;
+                        break;
+		case PRID_IMP_R4300:
+			mips_cpu.cputype = CPU_R4300;
+			mips_cpu.isa_level = MIPS_CPU_ISA_III;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+					   MIPS_CPU_32FPR;
+			mips_cpu.tlbsize = 32;
+			break;
+		case PRID_IMP_R4600:
+			mips_cpu.cputype = CPU_R4600;
+			mips_cpu.isa_level = MIPS_CPU_ISA_III;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
+			mips_cpu.tlbsize = 48;
+			break;
+		#if 0
+ 		case PRID_IMP_R4650:
+			/*
+			 * This processor doesn't have an MMU, so it's not
+			 * "real easy" to run Linux on it. It is left purely
+			 * for documentation.  Commented out because it shares
+			 * it's c0_prid id number with the TX3900.
+			 */
+	 		mips_cpu.cputype = CPU_R4650;
+		 	mips_cpu.isa_level = MIPS_CPU_ISA_III;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
+		        mips_cpu.tlbsize = 48;
+			break;
+		#endif
+		case PRID_IMP_TX39:
+			mips_cpu.isa_level = MIPS_CPU_ISA_I;
+			mips_cpu.options = MIPS_CPU_TLB;
+
+			if ((mips_cpu.processor_id & 0xf0) ==
+			    (PRID_REV_TX3927 & 0xf0)) {
+				mips_cpu.cputype = CPU_TX3927;
+				mips_cpu.tlbsize = 64;
+				mips_cpu.icache.ways = 2;
+				mips_cpu.dcache.ways = 2;
+			} else {
+				switch (mips_cpu.processor_id & 0xff) {
+				case PRID_REV_TX3912:
+					mips_cpu.cputype = CPU_TX3912;
+					mips_cpu.tlbsize = 32;
+					break;
+				case PRID_REV_TX3922:
+					mips_cpu.cputype = CPU_TX3922;
+					mips_cpu.tlbsize = 64;
+					break;
+				default:
+					mips_cpu.cputype = CPU_UNKNOWN;
+					break;
+				}
+			}
+			break;
+		case PRID_IMP_R4700:
+			mips_cpu.cputype = CPU_R4700;
+			mips_cpu.isa_level = MIPS_CPU_ISA_III;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+			                   MIPS_CPU_32FPR;
+			mips_cpu.tlbsize = 48;
+			break;
+		case PRID_IMP_TX49:
+			mips_cpu.cputype = CPU_TX49XX;
+			mips_cpu.isa_level = MIPS_CPU_ISA_III;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+			                   MIPS_CPU_32FPR;
+			mips_cpu.tlbsize = 48;
+			mips_cpu.icache.ways = 4;
+			mips_cpu.dcache.ways = 4;
+			break;
+		case PRID_IMP_R5000:
+			mips_cpu.cputype = CPU_R5000;
+			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+			                   MIPS_CPU_32FPR;
+			mips_cpu.tlbsize = 48;
+			break;
+		case PRID_IMP_R5432:
+			mips_cpu.cputype = CPU_R5432;
+			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+			                   MIPS_CPU_32FPR | MIPS_CPU_WATCH;
+			mips_cpu.tlbsize = 48;
+			break;
+		case PRID_IMP_R5500:
+			mips_cpu.cputype = CPU_R5500;
+			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+			                   MIPS_CPU_32FPR | MIPS_CPU_WATCH;
+			mips_cpu.tlbsize = 48;
+			break;
+		case PRID_IMP_NEVADA:
+			mips_cpu.cputype = CPU_NEVADA;
+			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+			                   MIPS_CPU_32FPR | MIPS_CPU_DIVEC;
+			mips_cpu.tlbsize = 48;
+			mips_cpu.icache.ways = 2;
+			mips_cpu.dcache.ways = 2;
+			break;
+		case PRID_IMP_R6000:
+			mips_cpu.cputype = CPU_R6000;
+			mips_cpu.isa_level = MIPS_CPU_ISA_II;
+			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU;
+			mips_cpu.tlbsize = 32;
+			break;
+		case PRID_IMP_R6000A:
+			mips_cpu.cputype = CPU_R6000A;
+			mips_cpu.isa_level = MIPS_CPU_ISA_II;
+			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU;
+			mips_cpu.tlbsize = 32;
+			break;
+		case PRID_IMP_RM7000:
+			mips_cpu.cputype = CPU_RM7000;
+			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
+			                   MIPS_CPU_32FPR;
+			/*
+			 * Undocumented RM7000:  Bit 29 in the info register of
+			 * the RM7000 v2.0 indicates if the TLB has 48 or 64
+			 * entries.
+			 *
+			 * 29      1 =>    64 entry JTLB
+			 *         0 =>    48 entry JTLB
+			 */
+			mips_cpu.tlbsize = (get_info() & (1 << 29)) ? 64 : 48;
+			break;
+		case PRID_IMP_R8000:
+			mips_cpu.cputype = CPU_R8000;
+			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+				           MIPS_CPU_FPU | MIPS_CPU_32FPR;
+			mips_cpu.tlbsize = 384;      /* has weird TLB: 3-way x 128 */
+			break;
+		case PRID_IMP_R10000:
+			mips_cpu.cputype = CPU_R10000;
+			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+				           MIPS_CPU_FPU | MIPS_CPU_32FPR |
+				           MIPS_CPU_COUNTER | MIPS_CPU_WATCH;
+			mips_cpu.tlbsize = 64;
+			break;
+		case PRID_IMP_R12000:
+			mips_cpu.cputype = CPU_R12000;
+			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+				           MIPS_CPU_FPU | MIPS_CPU_32FPR |
+				           MIPS_CPU_COUNTER | MIPS_CPU_WATCH;
+			mips_cpu.tlbsize = 64;
+			break;
+		default:
+			mips_cpu.cputype = CPU_UNKNOWN;
+			break;
+		}
+		break;
+#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
+	case PRID_COMP_MIPS:
+		switch (mips_cpu.processor_id & 0xff00) {
+		case PRID_IMP_4KC:
+			mips_cpu.cputype = CPU_4KC;
+			mips_cpu.isa_level = MIPS_CPU_ISA_M32;
+			break;
+		case PRID_IMP_4KEC:
+			mips_cpu.cputype = CPU_4KEC;
+			mips_cpu.isa_level = MIPS_CPU_ISA_M32;
+			break;
+		case PRID_IMP_4KSC:
+			mips_cpu.cputype = CPU_4KSC;
+			mips_cpu.isa_level = MIPS_CPU_ISA_M32;
+			break;
+		case PRID_IMP_5KC:
+			mips_cpu.cputype = CPU_5KC;
+			mips_cpu.isa_level = MIPS_CPU_ISA_M64;
+			break;
+		case PRID_IMP_20KC:
+			mips_cpu.cputype = CPU_20KC;
+			mips_cpu.isa_level = MIPS_CPU_ISA_M64;
+			break;
+		default:
+			mips_cpu.cputype = CPU_UNKNOWN;
+			break;
+		}
+		break;
+	case PRID_COMP_ALCHEMY:
+		switch (mips_cpu.processor_id & 0xff00) {
+		case PRID_IMP_AU1_REV1:
+		case PRID_IMP_AU1_REV2:
+			switch ((mips_cpu.processor_id >> 24) & 0xff) {
+			case 0:
+ 				mips_cpu.cputype = CPU_AU1000;
+				break;
+			case 1:
+				mips_cpu.cputype = CPU_AU1500;
+				break;
+			case 2:
+				mips_cpu.cputype = CPU_AU1100;
+				break;
+			default:
+				panic("Unknown Au Core!");
+				break;
+			}
+			mips_cpu.isa_level = MIPS_CPU_ISA_M32;
+ 			break;
+		default:
+			mips_cpu.cputype = CPU_UNKNOWN;
+			break;
+		}
+		break;
+#endif /* CONFIG_CPU_MIPS32 */
+	case PRID_COMP_SIBYTE:
+		switch (mips_cpu.processor_id & 0xff00) {
+		case PRID_IMP_SB1:
+			mips_cpu.cputype = CPU_SB1;
+			mips_cpu.isa_level = MIPS_CPU_ISA_M64;
+			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+			                   MIPS_CPU_COUNTER | MIPS_CPU_DIVEC |
+			                   MIPS_CPU_MCHECK;
+#ifndef CONFIG_SB1_PASS_1_WORKAROUNDS
+			/* FPU in pass1 is known to have issues. */
+			mips_cpu.options |= MIPS_CPU_FPU;
+#endif
+			break;
+		default:
+			mips_cpu.cputype = CPU_UNKNOWN;
+			break;
+		}
+		break;
+	default:
+		mips_cpu.cputype = CPU_UNKNOWN;
+	}
+	if (mips_cpu.options & MIPS_CPU_FPU)
+		mips_cpu.fpu_id = cpu_get_fpu_id();
+}
+
+__init void cpu_report(void)
+{
+	printk("CPU revision is: %08x\n", mips_cpu.processor_id);
+	if (mips_cpu.options & MIPS_CPU_FPU)
+		printk("FPU revision is: %08x\n", mips_cpu.fpu_id);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/entry.S linux-2.4.20/arch/mips64/kernel/entry.S
--- linux-2.4.19/arch/mips64/kernel/entry.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/entry.S	2002-10-29 11:18:33.000000000 +0000
@@ -12,11 +12,9 @@
 #include <asm/asm.h>
 #include <asm/regdef.h>
 #include <asm/mipsregs.h>
+#include <asm/offset.h>
 #include <asm/stackframe.h>
 
-/* This duplicates the definition from <linux/sched.h> */
-#define PT_TRACESYS	0x00000002		/* tracing system calls */
-
 #define KU_USER 0x10
 
 		.text
@@ -24,8 +22,8 @@
 FEXPORT(ret_from_fork)
 		move	a0, v0			# prev
 		jal	schedule_tail
-		lw	t0, TASK_PTRACE($28)	# syscall tracing enabled?
-		andi	t0, PT_TRACESYS
+		ld	t0, TASK_PTRACE($28)	# syscall tracing enabled?
+		andi	t0, _PT_TRACESYS
 		bnez	t0, tracesys_exit
 		j	ret_from_sys_call
 
@@ -40,13 +38,14 @@
 		bnez	t0, ret_from_sys_call
 		j	restore_all
 
-reschedule:	jal	schedule 
+reschedule:	jal	schedule
 
 FEXPORT(ret_from_sys_call)
 		mfc0	t0, CP0_STATUS	# need_resched and signals atomic test
 		ori	t0, t0, 1
 		xori	t0, t0, 1
 		mtc0	t0, CP0_STATUS
+		SSNOP; SSNOP; SSNOP
 
 		ld	v0, TASK_NEED_RESCHED($28)
 		lw	v1, TASK_SIGPENDING($28)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/head.S linux-2.4.20/arch/mips64/kernel/head.S
--- linux-2.4.19/arch/mips64/kernel/head.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/head.S	2002-10-29 11:18:36.000000000 +0000
@@ -26,7 +26,7 @@
 #if defined(CONFIG_ARC64) || defined(CONFIG_MAPPED_KERNEL)
 	/* We get launched at a XKPHYS address but the kernel is linked to
 	   run at a KSEG0 address, so jump there.  */
-	la	t0, \@f
+	PTR_LA	t0, \@f
 	jr	t0
 \@:
 #endif
@@ -105,10 +105,23 @@
 
 	CLI					# disable interrupts
 
-	la	$28, init_task_union		# init current pointer
+	PTR_LA	$28, init_task_union		# init current pointer
 	daddiu	sp, $28, KERNEL_STACK_SIZE-32
 	set_saved_sp	sp, t0
 
+	/* The firmware/bootloader passes argc/argp/envp
+	 * to us as arguments.  But clear bss first because
+	 * the romvec and other important info is stored there
+	 * by prom_init().
+	 */
+	PTR_LA	t0, _edata
+	sd	zero, (t0)
+	PTR_LA	t1, (_end - 8)
+1:
+	daddiu	t0, 8
+	sd	zero, (t0)
+	bne	t0, t1, 1b
+
 	dsubu	sp, 4*SZREG			# init stack pointer
 
 	j	init_arch
@@ -117,7 +130,7 @@
 #ifdef CONFIG_SMP
 /*
  * SMP slave cpus entry point.  Board specific code for bootstrap calls this
- * function after setting up the stack and gp registers. 
+ * function after setting up the stack and gp registers.
  */
 NESTED(smp_bootstrap, 16, sp)
 #ifdef CONFIG_SGI_IP27
@@ -171,7 +184,7 @@
 	page	swapper_pg_dir, 1
 	page	invalid_pte_table, 0
 	page	invalid_pmd_table, 1
-	page	kptbl, KPTBL_PAGE_ORDER
+	page	kptbl, _PGD_ORDER
 	.globl	ekptbl
 	page	kpmdtbl, 0
 ekptbl:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/i8259.c linux-2.4.20/arch/mips64/kernel/i8259.c
--- linux-2.4.19/arch/mips64/kernel/i8259.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/i8259.c	2002-10-29 11:18:35.000000000 +0000
@@ -42,7 +42,7 @@
 void mask_and_ack_8259A(unsigned int);
 
 static unsigned int startup_8259A_irq(unsigned int irq)
-{ 
+{
 	enable_8259A_irq(irq);
 
 	return 0; /* never anything pending */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/ioctl32.c linux-2.4.20/arch/mips64/kernel/ioctl32.c
--- linux-2.4.19/arch/mips64/kernel/ioctl32.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/ioctl32.c	2002-10-29 11:18:40.000000000 +0000
@@ -10,12 +10,18 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
 #include <linux/sched.h>
+#include <linux/if.h>
 #include <linux/mm.h>
 #include <linux/mtio.h>
 #include <linux/init.h>
 #include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#include <linux/if_pppox.h>
+#include <linux/cdrom.h>
+#include <linux/loop.h>
 #include <linux/vt.h>
 #include <linux/kd.h>
 #include <linux/netdevice.h>
@@ -27,6 +33,7 @@
 #include <linux/auto_fs.h>
 #include <linux/ext2_fs.h>
 #include <linux/raid/md_u.h>
+
 #include <scsi/scsi.h>
 #undef __KERNEL__		/* This file was born to be ugly ...  */
 #include <scsi/scsi_ioctl.h>
@@ -34,6 +41,8 @@
 #include <asm/types.h>
 #include <asm/uaccess.h>
 
+#include <linux/rtc.h>
+
 long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 
 static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg)
@@ -41,7 +50,7 @@
 	mm_segment_t old_fs = get_fs();
 	int err;
 	unsigned long val;
-	
+
 	set_fs (KERNEL_DS);
 	err = sys_ioctl(fd, cmd, (unsigned long)&val);
 	set_fs (old_fs);
@@ -197,7 +206,7 @@
 
 	old_fs = get_fs();
 	set_fs (KERNEL_DS);
-	err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc);	
+	err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc);
 	set_fs (old_fs);
 	if (err)
 		goto out;
@@ -224,28 +233,26 @@
 	return err;
 }
 
-static inline int dev_ifsioc(unsigned int fd, unsigned int cmd,
-			     unsigned long arg)
+static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	struct ifreq32 *uifr = (struct ifreq32 *)arg;
 	struct ifreq ifr;
 	mm_segment_t old_fs;
 	int err;
 	
 	switch (cmd) {
 	case SIOCSIFMAP:
-		err = copy_from_user(&ifr, uifr, sizeof(ifr.ifr_name));
-		err |= __get_user(ifr.ifr_map.mem_start, &(uifr->ifr_ifru.ifru_map.mem_start));
-		err |= __get_user(ifr.ifr_map.mem_end, &(uifr->ifr_ifru.ifru_map.mem_end));
-		err |= __get_user(ifr.ifr_map.base_addr, &(uifr->ifr_ifru.ifru_map.base_addr));
-		err |= __get_user(ifr.ifr_map.irq, &(uifr->ifr_ifru.ifru_map.irq));
-		err |= __get_user(ifr.ifr_map.dma, &(uifr->ifr_ifru.ifru_map.dma));
-		err |= __get_user(ifr.ifr_map.port, &(uifr->ifr_ifru.ifru_map.port));
+		err = copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(ifr.ifr_name));
+		err |= __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start));
+		err |= __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end));
+		err |= __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr));
+		err |= __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq));
+		err |= __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma));
+		err |= __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port));
 		if (err)
 			return -EFAULT;
 		break;
 	default:
-		if (copy_from_user(&ifr, uifr, sizeof(struct ifreq32)))
+		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
 			return -EFAULT;
 		break;
 	}
@@ -266,17 +273,17 @@
 		case SIOCGIFDSTADDR:
 		case SIOCGIFNETMASK:
 		case SIOCGIFTXQLEN:
-			if (copy_to_user(uifr, &ifr, sizeof(struct ifreq32)))
+			if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32)))
 				return -EFAULT;
 			break;
 		case SIOCGIFMAP:
-			err = copy_to_user(uifr, &ifr, sizeof(ifr.ifr_name));
-			err |= __put_user(ifr.ifr_map.mem_start, &(uifr->ifr_ifru.ifru_map.mem_start));
-			err |= __put_user(ifr.ifr_map.mem_end, &(uifr->ifr_ifru.ifru_map.mem_end));
-			err |= __put_user(ifr.ifr_map.base_addr, &(uifr->ifr_ifru.ifru_map.base_addr));
-			err |= __put_user(ifr.ifr_map.irq, &(uifr->ifr_ifru.ifru_map.irq));
-			err |= __put_user(ifr.ifr_map.dma, &(uifr->ifr_ifru.ifru_map.dma));
-			err |= __put_user(ifr.ifr_map.port, &(uifr->ifr_ifru.ifru_map.port));
+			err = copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(ifr.ifr_name));
+			err |= __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start));
+			err |= __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end));
+			err |= __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr));
+			err |= __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq));
+			err |= __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma));
+			err |= __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port));
 			if (err)
 				err = -EFAULT;
 			break;
@@ -313,7 +320,7 @@
 	u32 rtdev;
 	int ret;
 	mm_segment_t old_fs = get_fs();
-	
+
 	ret = copy_from_user (&r.rt_dst, &(ur->rt_dst), 3 * sizeof(struct sockaddr));
 	ret |= __get_user (r.rt_flags, &(ur->rt_flags));
 	ret |= __get_user (r.rt_metric, &(ur->rt_metric));
@@ -411,7 +418,7 @@
 	struct blkpg_partition p;
 	int err;
 	mm_segment_t old_fs = get_fs();
-	
+
 	err = get_user(a.op, &arg->op);
 	err |= __get_user(a.flags, &arg->flags);
 	err |= __get_user(a.datalen, &arg->datalen);
@@ -430,7 +437,7 @@
 		set_fs (old_fs);
 	default:
 		return -EINVAL;
-	}                                        
+	}
 	return err;
 }
 
@@ -699,7 +706,95 @@
 	IOCTL32_DEFAULT(SIOCDRARP),
 	IOCTL32_DEFAULT(SIOCADDDLCI),
 	IOCTL32_DEFAULT(SIOCDELDLCI),
+	/* SG stuff */
+	IOCTL32_DEFAULT(SG_SET_TIMEOUT),
+	IOCTL32_DEFAULT(SG_GET_TIMEOUT),
+	IOCTL32_DEFAULT(SG_EMULATED_HOST),
+	IOCTL32_DEFAULT(SG_SET_TRANSFORM),
+	IOCTL32_DEFAULT(SG_GET_TRANSFORM),
+	IOCTL32_DEFAULT(SG_SET_RESERVED_SIZE),
+	IOCTL32_DEFAULT(SG_GET_RESERVED_SIZE),
+	IOCTL32_DEFAULT(SG_GET_SCSI_ID),
+	IOCTL32_DEFAULT(SG_SET_FORCE_LOW_DMA),
+	IOCTL32_DEFAULT(SG_GET_LOW_DMA),
+	IOCTL32_DEFAULT(SG_SET_FORCE_PACK_ID),
+	IOCTL32_DEFAULT(SG_GET_PACK_ID),
+	IOCTL32_DEFAULT(SG_GET_NUM_WAITING),
+	IOCTL32_DEFAULT(SG_SET_DEBUG),
+	IOCTL32_DEFAULT(SG_GET_SG_TABLESIZE),
+	IOCTL32_DEFAULT(SG_GET_COMMAND_Q),
+	IOCTL32_DEFAULT(SG_SET_COMMAND_Q),
+	IOCTL32_DEFAULT(SG_GET_VERSION_NUM),
+	IOCTL32_DEFAULT(SG_NEXT_CMD_LEN),
+	IOCTL32_DEFAULT(SG_SCSI_RESET),
+	IOCTL32_DEFAULT(SG_IO),
+	IOCTL32_DEFAULT(SG_GET_REQUEST_TABLE),
+	IOCTL32_DEFAULT(SG_SET_KEEP_ORPHAN),
+	IOCTL32_DEFAULT(SG_GET_KEEP_ORPHAN),
+	/* PPP stuff */
+	IOCTL32_DEFAULT(PPPIOCGFLAGS),
+	IOCTL32_DEFAULT(PPPIOCSFLAGS),
+	IOCTL32_DEFAULT(PPPIOCGASYNCMAP),
+	IOCTL32_DEFAULT(PPPIOCSASYNCMAP),
+	IOCTL32_DEFAULT(PPPIOCGUNIT),
+	IOCTL32_DEFAULT(PPPIOCGRASYNCMAP),
+	IOCTL32_DEFAULT(PPPIOCSRASYNCMAP),
+	IOCTL32_DEFAULT(PPPIOCGMRU),
+	IOCTL32_DEFAULT(PPPIOCSMRU),
+	IOCTL32_DEFAULT(PPPIOCSMAXCID),
+	IOCTL32_DEFAULT(PPPIOCGXASYNCMAP),
+	IOCTL32_DEFAULT(PPPIOCSXASYNCMAP),
+	IOCTL32_DEFAULT(PPPIOCXFERUNIT),
+	IOCTL32_DEFAULT(PPPIOCGNPMODE),
+	IOCTL32_DEFAULT(PPPIOCSNPMODE),
+	IOCTL32_DEFAULT(PPPIOCGDEBUG),
+	IOCTL32_DEFAULT(PPPIOCSDEBUG),
+	IOCTL32_DEFAULT(PPPIOCNEWUNIT),
+	IOCTL32_DEFAULT(PPPIOCATTACH),
+	IOCTL32_DEFAULT(PPPIOCGCHAN),
+	/* PPPOX */
+	IOCTL32_DEFAULT(PPPOEIOCSFWD),
+	IOCTL32_DEFAULT(PPPOEIOCDFWD),
+	/* CDROM stuff */
+	IOCTL32_DEFAULT(CDROMPAUSE),
+	IOCTL32_DEFAULT(CDROMRESUME),
+	IOCTL32_DEFAULT(CDROMPLAYMSF),
+	IOCTL32_DEFAULT(CDROMPLAYTRKIND),
+	IOCTL32_DEFAULT(CDROMREADTOCHDR),
+	IOCTL32_DEFAULT(CDROMREADTOCENTRY),
+	IOCTL32_DEFAULT(CDROMSTOP),
+	IOCTL32_DEFAULT(CDROMSTART),
+	IOCTL32_DEFAULT(CDROMEJECT),
+	IOCTL32_DEFAULT(CDROMVOLCTRL),
+	IOCTL32_DEFAULT(CDROMSUBCHNL),
+	IOCTL32_DEFAULT(CDROMEJECT_SW),
+	IOCTL32_DEFAULT(CDROMMULTISESSION),
+	IOCTL32_DEFAULT(CDROM_GET_MCN),
+	IOCTL32_DEFAULT(CDROMRESET),
+	IOCTL32_DEFAULT(CDROMVOLREAD),
+	IOCTL32_DEFAULT(CDROMSEEK),
+	IOCTL32_DEFAULT(CDROMPLAYBLK),
+	IOCTL32_DEFAULT(CDROMCLOSETRAY),
+	IOCTL32_DEFAULT(CDROM_SET_OPTIONS),
+	IOCTL32_DEFAULT(CDROM_CLEAR_OPTIONS),
+	IOCTL32_DEFAULT(CDROM_SELECT_SPEED),
+	IOCTL32_DEFAULT(CDROM_SELECT_DISC),
+	IOCTL32_DEFAULT(CDROM_MEDIA_CHANGED),
+	IOCTL32_DEFAULT(CDROM_DRIVE_STATUS),
+	IOCTL32_DEFAULT(CDROM_DISC_STATUS),
+	IOCTL32_DEFAULT(CDROM_CHANGER_NSLOTS),
+	IOCTL32_DEFAULT(CDROM_LOCKDOOR),
+	IOCTL32_DEFAULT(CDROM_DEBUG),
+	IOCTL32_DEFAULT(CDROM_GET_CAPABILITY),
+	/* DVD ioctls */
+	IOCTL32_DEFAULT(DVD_READ_STRUCT),
+	IOCTL32_DEFAULT(DVD_WRITE_STRUCT),
+	IOCTL32_DEFAULT(DVD_AUTH),
+	/* Big L */
+	IOCTL32_DEFAULT(LOOP_SET_FD),
+	IOCTL32_DEFAULT(LOOP_CLR_FD),
 
+	/* And these ioctls need translation */
 	IOCTL32_HANDLER(SIOCGIFNAME, dev_ifname32),
 	IOCTL32_HANDLER(SIOCGIFCONF, dev_ifconf),
 	IOCTL32_HANDLER(SIOCGIFFLAGS, dev_ifsioc),
@@ -727,6 +822,9 @@
 	IOCTL32_HANDLER(SIOCSIFNETMASK, dev_ifsioc),
 	IOCTL32_HANDLER(SIOCSIFPFLAGS, dev_ifsioc),
 	IOCTL32_HANDLER(SIOCGIFPFLAGS, dev_ifsioc),
+	IOCTL32_HANDLER(SIOCGPPPSTATS, dev_ifsioc),
+	IOCTL32_HANDLER(SIOCGPPPCSTATS, dev_ifsioc),
+	IOCTL32_HANDLER(SIOCGPPPVER, dev_ifsioc),
 	IOCTL32_HANDLER(SIOCGIFTXQLEN, dev_ifsioc),
 	IOCTL32_HANDLER(SIOCSIFTXQLEN, dev_ifsioc),
 	IOCTL32_HANDLER(SIOCADDRT, routing_ioctl),
@@ -834,7 +932,25 @@
 	IOCTL32_DEFAULT(AUTOFS_IOC_CATATONIC),
 	IOCTL32_DEFAULT(AUTOFS_IOC_PROTOVER),
 	IOCTL32_HANDLER(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout),
-	IOCTL32_DEFAULT(AUTOFS_IOC_EXPIRE)
+	IOCTL32_DEFAULT(AUTOFS_IOC_EXPIRE),
+
+	/* Little p (/dev/rtc, /dev/envctrl, etc.) */
+	IOCTL32_DEFAULT(_IOR('p', 20, int[7])), /* RTCGET */
+	IOCTL32_DEFAULT(_IOW('p', 21, int[7])), /* RTCSET */
+	IOCTL32_DEFAULT(RTC_AIE_ON),
+	IOCTL32_DEFAULT(RTC_AIE_OFF),
+	IOCTL32_DEFAULT(RTC_UIE_ON),
+	IOCTL32_DEFAULT(RTC_UIE_OFF),
+	IOCTL32_DEFAULT(RTC_PIE_ON),
+	IOCTL32_DEFAULT(RTC_PIE_OFF),
+	IOCTL32_DEFAULT(RTC_WIE_ON),
+	IOCTL32_DEFAULT(RTC_WIE_OFF),
+	IOCTL32_DEFAULT(RTC_ALM_SET),
+	IOCTL32_DEFAULT(RTC_ALM_READ),
+	IOCTL32_DEFAULT(RTC_RD_TIME),
+	IOCTL32_DEFAULT(RTC_SET_TIME),
+	IOCTL32_DEFAULT(RTC_WKALM_SET),
+	IOCTL32_DEFAULT(RTC_WKALM_RD)
 };
 
 #define NR_IOCTL32_HANDLERS	(sizeof(ioctl32_handler_table) /	\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/irq.c linux-2.4.20/arch/mips64/kernel/irq.c
--- linux-2.4.19/arch/mips64/kernel/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/irq.c	2002-10-29 11:18:30.000000000 +0000
@@ -31,6 +31,8 @@
 irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
 	{ [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}};
 
+static void register_irq_proc (unsigned int irq);
+
 /*
  * Special irq handlers.
  */
@@ -48,7 +50,7 @@
 {
 	/*
 	 * 'what should we do if we get a hw irq event on an illegal vector'.
-	 * each architecture has to answer this themselves, it doesnt deserve
+	 * each architecture has to answer this themselves, it doesn't deserve
 	 * a generic callback i think.
 	 */
 	printk("unexpected interrupt %d\n", irq);
@@ -87,7 +89,7 @@
 
 	for (i = 0 ; i < NR_IRQS ; i++) {
 		action = irq_desc[i].action;
-		if (!action) 
+		if (!action)
 			continue;
 		p += sprintf(p, "%3d: ",i);
 #ifndef CONFIG_SMP
@@ -198,12 +200,12 @@
 }
 
 /*
- * A global "cli()" while in an interrupt context turns into just a local 
- * cli(). Interrupts should use spinlocks for the (very unlikely) case that 
+ * A global "cli()" while in an interrupt context turns into just a local
+ * cli(). Interrupts should use spinlocks for the (very unlikely) case that
  * they ever want to protect against each other.
- * 
- * If we already have local interrupts disabled, this will not turn a local 
- * disable into a global one (problems with spinlocks: this makes 
+ *
+ * If we already have local interrupts disabled, this will not turn a local
+ * disable into a global one (problems with spinlocks: this makes
  * save_flags+cli+sti usable inside a spinlock).
  */
 
@@ -317,9 +319,9 @@
  * Generic enable/disable code: this just calls
  * down into the PIC-specific version for the actual
  * hardware disable after having gotten the irq
- * controller lock. 
+ * controller lock.
  */
- 
+
 /**
  *	disable_irq_nosync - disable an irq without waiting
  *	@irq: Interrupt to disable
@@ -330,7 +332,7 @@
  *
  *	This function may be called from IRQ context.
  */
- 
+
 void inline disable_irq_nosync(unsigned int irq)
 {
 	irq_desc_t *desc = irq_desc + irq;
@@ -356,7 +358,7 @@
  *
  *	This function may be called - with care - from IRQ context.
  */
- 
+
 void disable_irq(unsigned int irq)
 {
 	disable_irq_nosync(irq);
@@ -377,7 +379,7 @@
  *
  *	This function may be called from IRQ context.
  */
- 
+
 void enable_irq(unsigned int irq)
 {
 	irq_desc_t *desc = irq_desc + irq;
@@ -412,7 +414,7 @@
  */
 asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs)
 {
-	/* 
+	/*
 	 * We ack quickly, we don't want the irq controller
 	 * thinking we're snobs just because some other CPU has
 	 * disabled global interrupts (we have already done the
@@ -472,7 +474,7 @@
 		spin_unlock(&desc->lock);
 		handle_IRQ_event(irq, regs, action);
 		spin_lock(&desc->lock);
-		
+
 		if (!(desc->status & IRQ_PENDING))
 			break;
 		desc->status &= ~IRQ_PENDING;
@@ -502,7 +504,7 @@
  *	This call allocates interrupt resources and enables the
  *	interrupt line and IRQ handling. From the point this
  *	call is made your handler function may be invoked. Since
- *	your handler function must clear any interrupt the board 
+ *	your handler function must clear any interrupt the board
  *	raises, you must take care both to initialise your hardware
  *	and to set up the interrupt handler in the right order.
  *
@@ -522,10 +524,10 @@
  *	SA_SAMPLE_RANDOM	The interrupt can be used for entropy
  *
  */
- 
-int request_irq(unsigned int irq, 
+
+int request_irq(unsigned int irq,
 		void (*handler)(int, void *, struct pt_regs *),
-		unsigned long irqflags, 
+		unsigned long irqflags,
 		const char * devname,
 		void *dev_id)
 {
@@ -580,12 +582,12 @@
  *	does not return until any executing interrupts for this IRQ
  *	have completed.
  *
- *	This function may be called from interrupt context. 
+ *	This function may be called from interrupt context.
  *
  *	Bugs: Attempting to free an irq in a handler for the same irq hangs
  *	      the machine.
  */
- 
+
 void free_irq(unsigned int irq, void *dev_id)
 {
 	irq_desc_t *desc;
@@ -646,7 +648,7 @@
  *	and a mask of potential interrupt lines is returned.
  *
  */
- 
+
 unsigned long probe_irq_on(void)
 {
 	unsigned int i;
@@ -655,15 +657,15 @@
 	unsigned long delay;
 
 	down(&probe_sem);
-	/* 
+	/*
 	 * something may have generated an irq long ago and we want to
-	 * flush such a longstanding irq before considering it as spurious. 
+	 * flush such a longstanding irq before considering it as spurious.
 	 */
 	for (i = NR_IRQS-1; i > 0; i--)  {
 		desc = irq_desc + i;
 
 		spin_lock_irq(&desc->lock);
-		if (!irq_desc[i].action) 
+		if (!irq_desc[i].action)
 			irq_desc[i].handler->startup(i);
 		spin_unlock_irq(&desc->lock);
 	}
@@ -725,7 +727,7 @@
  * Return a mask of triggered interrupts (this
  * can handle only legacy ISA interrupts).
  */
- 
+
 /**
  *	probe_irq_mask - scan a bitmap of interrupt lines
  *	@val:	mask of interrupts to consider
@@ -787,7 +789,7 @@
  *	nothing prevents two IRQ probe callers from overlapping. The
  *	results of this are non-optimal.
  */
- 
+
 int probe_irq_off(unsigned long val)
 {
 	int i, irq_found, nr_irqs;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/irq_cpu.c linux-2.4.20/arch/mips64/kernel/irq_cpu.c
--- linux-2.4.19/arch/mips64/kernel/irq_cpu.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/irq_cpu.c	2002-10-29 11:18:48.000000000 +0000
@@ -2,6 +2,8 @@
  * Copyright 2001 MontaVista Software Inc.
  * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
  *
+ * Copyright (C) 2001 Ralf Baechle
+ *
  * This file define the irq handler for MIPS CPU interrupts.
  *
  * This program is free software; you can redistribute  it and/or modify it
@@ -13,8 +15,11 @@
 /*
  * Almost all MIPS CPUs define 8 interrupt sources.  They are typically
  * level triggered (i.e., cannot be cleared from CPU; must be cleared from
- * device).  The first two are software interrupts.  The last one is 
- * usually cpu timer interrupt if coutner register is present.
+ * device).  The first two are software interrupts which we don't really
+ * use or support.  The last one is usually cpu timer interrupt if a counter
+ * register is present.
+ *
+ * Don't even think about using this on SMP.  You have been warned.
  *
  * This file exports one global function:
  *	mips_cpu_irq_init(u32 irq_base);
@@ -24,18 +29,37 @@
 #include <linux/kernel.h>
 
 #include <asm/mipsregs.h>
+#include <asm/system.h>
+
+static int mips_cpu_irq_base;
+
+static inline void unmask_mips_irq(unsigned int irq)
+{
+	clear_cp0_cause(0x100 << (irq - mips_cpu_irq_base));
+	set_cp0_status(0x100 << (irq - mips_cpu_irq_base));
+}
 
-static int mips_cpu_irq_base = -1;
+static inline void mask_mips_irq(unsigned int irq)
+{
+	clear_cp0_status(0x100 << (irq - mips_cpu_irq_base));
+}
 
-static void mips_cpu_irq_enable(unsigned int irq)
+static inline void mips_cpu_irq_enable(unsigned int irq)
 {
-	clear_cp0_cause( 1 << (irq - mips_cpu_irq_base + 8));
-	set_cp0_status(1 << (irq - mips_cpu_irq_base + 8));
+	unsigned long flags;
+
+	local_irq_save(flags);
+	unmask_mips_irq(irq);
+	local_irq_restore(flags);
 }
 
 static void mips_cpu_irq_disable(unsigned int irq)
 {
-	clear_cp0_status(1 << (irq - mips_cpu_irq_base + 8));
+	unsigned long flags;
+
+	local_irq_save(flags);
+	mask_mips_irq(irq);
+	local_irq_restore(flags);
 }
 
 static unsigned int mips_cpu_irq_startup(unsigned int irq)
@@ -47,21 +71,22 @@
 
 #define	mips_cpu_irq_shutdown	mips_cpu_irq_disable
 
+/*
+ * While we ack the interrupt interrupts are disabled and thus we don't need
+ * to deal with concurrency issues.  Same for mips_cpu_irq_end.
+ */
 static void mips_cpu_irq_ack(unsigned int irq)
 {
-	/* although we attemp to clear the IP bit in cause reigster, I think
-	 * usually it is cleared by device (irq source)
-	 */
+	/* Only necessary for soft interrupts */
 	clear_cp0_cause(1 << (irq - mips_cpu_irq_base + 8));
 
-	/* disable this interrupt - so that we safe proceed to the handler */
-	mips_cpu_irq_disable(irq);
+	mask_mips_irq(irq);
 }
 
 static void mips_cpu_irq_end(unsigned int irq)
 {
-	if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
-		mips_cpu_irq_enable(irq);
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		unmask_mips_irq(irq);
 }
 
 static hw_irq_controller mips_cpu_irq_controller = {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/linux32.c linux-2.4.20/arch/mips64/kernel/linux32.c
--- linux-2.4.19/arch/mips64/kernel/linux32.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/linux32.c	2002-10-29 11:18:32.000000000 +0000
@@ -1,10 +1,11 @@
-/* 
+/*
  * Conversion between 32-bit and 64-bit native system calls.
  *
  * Copyright (C) 2000 Silicon Graphics, Inc.
  * Written by Ulf Carlsson (ulfc@engr.sgi.com)
  * sys32_execve from ia64/ia32 code, Feb 2000, Kanoj Sarcar (kanoj@sgi.com)
  */
+#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/file.h>
@@ -12,6 +13,7 @@
 #include <linux/highuid.h>
 #include <linux/dirent.h>
 #include <linux/resource.h>
+#include <linux/filter.h>
 #include <linux/highmem.h>
 #include <linux/time.h>
 #include <linux/poll.h>
@@ -21,6 +23,7 @@
 #include <linux/shm.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
+#include <linux/icmpv6.h>
 #include <linux/sysctl.h>
 #include <linux/utime.h>
 #include <linux/utsname.h>
@@ -34,8 +37,16 @@
 #include <asm/mman.h>
 #include <asm/ipc.h>
 
-
+/* Use this to get at 32-bit user passed pointers. */
+/* A() macro should be used for places where you e.g.
+   have some internal variable u32 and just want to get
+   rid of a compiler warning. AA() has to be used in
+   places where you want to convert a function argument
+   to 32bit pointer or when you e.g. access pt_regs
+   structure and want to consider 32bit registers only.
+ */
 #define A(__x) ((unsigned long)(__x))
+#define AA(__x) ((unsigned long)((int)__x))
 
 #ifdef __MIPSEB__
 #define merge_64(r1,r2)	((((r1) & 0xffffffffUL) << 32) + ((r2) & 0xffffffffUL))
@@ -202,7 +213,7 @@
 	mm_segment_t old_fs;
 	int ret;
 	char *filenam;
-	
+
 	if (!times)
 		return sys_utime(filename, NULL);
 	if (get_user (t.actime, &times->actime) ||
@@ -212,7 +223,7 @@
 	ret = PTR_ERR(filenam);
 	if (!IS_ERR(filenam)) {
 		old_fs = get_fs();
-		set_fs (KERNEL_DS); 
+		set_fs (KERNEL_DS);
 		ret = sys_utime(filenam, &t);
 		set_fs (old_fs);
 		putname (filenam);
@@ -251,7 +262,7 @@
  * memory to free pages in kernel mem. These are in a format ready
  * to be put directly into the top of new user memory.
  */
-int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm) 
+int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
 {
 	while (argc-- > 0) {
 		u32 str;
@@ -259,13 +270,13 @@
 		unsigned long pos;
 
 		if (get_user(str, argv+argc) || !str ||
-		     !(len = strnlen_user((char *)A(str), bprm->p))) 
+		     !(len = strnlen_user((char *)A(str), bprm->p)))
 			return -EFAULT;
-		if (bprm->p < len) 
-			return -E2BIG; 
+		if (bprm->p < len)
+			return -E2BIG;
 
 		bprm->p -= len;
-		/* XXX: add architecture specific overflow check here. */ 
+		/* XXX: add architecture specific overflow check here. */
 
 		pos = bprm->p;
 		while (len > 0) {
@@ -302,7 +313,7 @@
 			kunmap(page);
 
 			if (err)
-				return -EFAULT; 
+				return -EFAULT;
 
 			pos += bytes_to_copy;
 			str += bytes_to_copy;
@@ -324,7 +335,7 @@
 	int i;
 
 	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
-	memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); 
+	memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
 
 	dentry = open_namei(filename, 0, 0);
 	retval = PTR_ERR(dentry);
@@ -347,21 +358,21 @@
 	}
 
 	retval = prepare_binprm(&bprm);
-	if (retval < 0) 
-		goto out; 
+	if (retval < 0)
+		goto out;
 
 	retval = copy_strings_kernel(1, &bprm.filename, &bprm);
-	if (retval < 0) 
-		goto out; 
+	if (retval < 0)
+		goto out;
 
 	bprm.exec = bprm.p;
 	retval = copy_strings32(bprm.envc, envp, &bprm);
-	if (retval < 0) 
-		goto out; 
+	if (retval < 0)
+		goto out;
 
 	retval = copy_strings32(bprm.argc, argv, &bprm);
-	if (retval < 0) 
-		goto out; 
+	if (retval < 0)
+		goto out;
 
 	retval = search_binary_handler(&bprm,regs);
 	if (retval >= 0)
@@ -373,8 +384,8 @@
 	if (bprm.dentry)
 		dput(bprm.dentry);
 
-	/* Assumes that free_page() can take a NULL argument. */ 
-	/* I hope this is ok for all architectures */ 
+	/* Assumes that free_page() can take a NULL argument. */
+	/* I hope this is ok for all architectures */
 	for (i = 0 ; i < MAX_ARG_PAGES ; i++)
 		if (bprm.page[i])
 			__free_page(bprm.page[i]);
@@ -403,12 +414,14 @@
 	return error;
 }
 #else
-static int
-nargs(unsigned int arg, char **ap)
+static int nargs(unsigned int arg, char **ap)
 {
 	char *ptr;
 	int n, ret;
 
+	if (!arg)
+		return 0;
+
 	n = 0;
 	do {
 		/* egcs is stupid */
@@ -422,10 +435,11 @@
 		arg += sizeof(unsigned int);
 		n++;
 	} while (ptr);
-	return(n - 1);
+
+	return n - 1;
 }
 
-asmlinkage int 
+asmlinkage int
 sys32_execve(abi64_no_regargs, struct pt_regs regs)
 {
 	extern asmlinkage int sys_execve(abi64_no_regargs, struct pt_regs regs);
@@ -560,8 +574,8 @@
         int    ru_nswap;
         int    ru_inblock;
         int    ru_oublock;
-        int    ru_msgsnd; 
-        int    ru_msgrcv; 
+        int    ru_msgsnd;
+        int    ru_msgrcv;
         int    ru_nsignals;
         int    ru_nvcsw;
         int    ru_nivcsw;
@@ -571,7 +585,7 @@
 put_rusage (struct rusage32 *ru, struct rusage *r)
 {
 	int err;
-	
+
 	err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec);
 	err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec);
 	err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec);
@@ -604,8 +618,8 @@
 		int ret;
 		unsigned int status;
 		mm_segment_t old_fs = get_fs();
-	
-		set_fs(KERNEL_DS);	
+
+		set_fs(KERNEL_DS);
 		ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
 		set_fs(old_fs);
 		if (put_rusage (ru, &r)) return -EFAULT;
@@ -637,7 +651,7 @@
 	struct rlimit r;
 	int ret;
 	mm_segment_t old_fs = get_fs ();
-	
+
 	set_fs (KERNEL_DS);
 	ret = sys_old_getrlimit(resource, &r);
 	set_fs (old_fs);
@@ -657,7 +671,7 @@
 	int ret;
 	mm_segment_t old_fs = get_fs ();
 
-	if (resource >= RLIM_NLIMITS) return -EINVAL;	
+	if (resource >= RLIM_NLIMITS) return -EINVAL;
 	if (get_user (r.rlim_cur, &rlim->rlim_cur) ||
 	    __get_user (r.rlim_max, &rlim->rlim_max))
 		return -EFAULT;
@@ -689,7 +703,7 @@
 put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
 {
 	int err;
-	
+
 	err = put_user (kbuf->f_type, &ubuf->f_type);
 	err |= __put_user (kbuf->f_bsize, &ubuf->f_bsize);
 	err |= __put_user (kbuf->f_blocks, &ubuf->f_blocks);
@@ -711,7 +725,7 @@
 	int ret;
 	struct statfs s;
 	mm_segment_t old_fs = get_fs();
-	
+
 	set_fs (KERNEL_DS);
 	ret = sys_statfs((const char *)path, &s);
 	set_fs (old_fs);
@@ -728,7 +742,7 @@
 	int ret;
 	struct statfs s;
 	mm_segment_t old_fs = get_fs();
-	
+
 	set_fs (KERNEL_DS);
 	ret = sys_fstatfs(fd, &s);
 	set_fs (old_fs);
@@ -746,7 +760,7 @@
 	struct rusage r;
 	int ret;
 	mm_segment_t old_fs = get_fs();
-		
+
 	set_fs (KERNEL_DS);
 	ret = sys_getrusage(who, &r);
 	set_fs (old_fs);
@@ -831,7 +845,7 @@
 	return 0;
 
 }
-asmlinkage unsigned long 
+asmlinkage unsigned long
 sys32_alarm(unsigned int seconds)
 {
 	struct itimerval it_new, it_old;
@@ -980,7 +994,7 @@
 	/* VERIFY_WRITE actually means a read, as we write to user space */
 	fn = file->f_op->read;
 	if (type == VERIFY_READ)
-		fn = (IO_fn_t) file->f_op->write;		
+		fn = (IO_fn_t) file->f_op->write;
 	ivp = iov;
 	while (count > 0) {
 		void * base;
@@ -1222,7 +1236,7 @@
 	/*
 	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
 	 * since we used fdset we need to allocate memory in units of
-	 * long-words. 
+	 * long-words.
 	 */
 	ret = -ENOMEM;
 	size = FDS_BYTES(n);
@@ -1293,7 +1307,7 @@
 	struct timespec t;
 	int ret;
 	mm_segment_t old_fs = get_fs ();
-	
+
 	set_fs (KERNEL_DS);
 	ret = sys_sched_rr_get_interval(pid, &t);
 	set_fs (old_fs);
@@ -1305,7 +1319,7 @@
 
 
 extern asmlinkage int sys_nanosleep(struct timespec *rqtp,
-				    struct timespec *rmtp); 
+				    struct timespec *rmtp);
 
 asmlinkage int
 sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp)
@@ -1317,7 +1331,7 @@
 	if (get_user (t.tv_sec, &rqtp->tv_sec) ||
 	    __get_user (t.tv_nsec, &rqtp->tv_nsec))
 		return -EFAULT;
-	
+
 	set_fs (KERNEL_DS);
 	ret = sys_nanosleep(&t, rmtp ? &t : NULL);
 	set_fs (old_fs);
@@ -1361,75 +1375,119 @@
 extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
 				     char *optval, int optlen);
 
-asmlinkage int sys32_setsockopt(int fd, int level, int optname,
+static int do_set_attach_filter(int fd, int level, int optname,
 				char *optval, int optlen)
 {
-	if (optname == SO_ATTACH_FILTER) {
-		struct sock_fprog32 {
-			__u16 len;
-			__u32 filter;
-		} *fprog32 = (struct sock_fprog32 *)optval;
-		struct sock_fprog kfprog;
-		struct sock_filter *kfilter;
-		unsigned int fsize;
-		mm_segment_t old_fs;
-		__u32 uptr;
-		int ret;
+	struct sock_fprog32 {
+		__u16 len;
+		__u32 filter;
+	} *fprog32 = (struct sock_fprog32 *)optval;
+	struct sock_fprog kfprog;
+	struct sock_filter *kfilter;
+	unsigned int fsize;
+	mm_segment_t old_fs;
+	__u32 uptr;
+	int ret;
 
-		if (get_user(kfprog.len, &fprog32->len) ||
-		    __get_user(uptr, &fprog32->filter))
-			return -EFAULT;
-		kfprog.filter = (struct sock_filter *)A(uptr);
-		fsize = kfprog.len * sizeof(struct sock_filter);
-		kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL);
-		if (kfilter == NULL)
-			return -ENOMEM;
-		if (copy_from_user(kfilter, kfprog.filter, fsize)) {
-			kfree(kfilter);
-			return -EFAULT;
-		}
-		kfprog.filter = kfilter;
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		ret = sys_setsockopt(fd, level, optname,
-				     (char *)&kfprog, sizeof(kfprog));
-		set_fs(old_fs);
+	if (get_user(kfprog.len, &fprog32->len) ||
+	    __get_user(uptr, &fprog32->filter))
+		return -EFAULT;
+
+	kfprog.filter = (struct sock_filter *)A(uptr);
+	fsize = kfprog.len * sizeof(struct sock_filter);
+
+	kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL);
+	if (kfilter == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(kfilter, kfprog.filter, fsize)) {
 		kfree(kfilter);
-		return ret;
+		return -EFAULT;
 	}
-	return sys_setsockopt(fd, level, optname, optval, optlen);
+
+	kfprog.filter = kfilter;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_setsockopt(fd, level, optname,
+			     (char *)&kfprog, sizeof(kfprog));
+	set_fs(old_fs);
+
+	kfree(kfilter);
+
+	return ret;
 }
 
-struct flock32 {
-	short l_type;
-	short l_whence;
-	__kernel_off_t32 l_start;
-	__kernel_off_t32 l_len;
-	__kernel_pid_t32 l_pid;
-	short __unused;
-};
+static int do_set_icmpv6_filter(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	struct icmp6_filter kfilter;
+	mm_segment_t old_fs;
+	int ret, i;
+
+	if (copy_from_user(&kfilter, optval, sizeof(kfilter)))
+		return -EFAULT;
+
+
+	for (i = 0; i < 8; i += 2) {
+		u32 tmp = kfilter.data[i];
+
+		kfilter.data[i] = kfilter.data[i + 1];
+		kfilter.data[i + 1] = tmp;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_setsockopt(fd, level, optname,
+			     (char *) &kfilter, sizeof(kfilter));
+	set_fs(old_fs);
+
+	return ret;
+}
+
+asmlinkage int sys32_setsockopt(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	if (optname == SO_ATTACH_FILTER)
+		return do_set_attach_filter(fd, level, optname,
+					    optval, optlen);
+	if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER)
+		return do_set_icmpv6_filter(fd, level, optname,
+					    optval, optlen);
+
+	return sys_setsockopt(fd, level, optname, optval, optlen);
+}
 
 static inline int get_flock(struct flock *kfl, struct flock32 *ufl)
 {
 	int err;
-	
-	err = get_user(kfl->l_type, &ufl->l_type);
+
+	if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)))
+		return -EFAULT;
+
+	err = __get_user(kfl->l_type, &ufl->l_type);
 	err |= __get_user(kfl->l_whence, &ufl->l_whence);
 	err |= __get_user(kfl->l_start, &ufl->l_start);
 	err |= __get_user(kfl->l_len, &ufl->l_len);
 	err |= __get_user(kfl->l_pid, &ufl->l_pid);
+
 	return err;
 }
 
 static inline int put_flock(struct flock *kfl, struct flock32 *ufl)
 {
 	int err;
-	
+
+	if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)))
+		return -EFAULT;
+
 	err = __put_user(kfl->l_type, &ufl->l_type);
 	err |= __put_user(kfl->l_whence, &ufl->l_whence);
 	err |= __put_user(kfl->l_start, &ufl->l_start);
 	err |= __put_user(kfl->l_len, &ufl->l_len);
+	err |= __put_user(0, &ufl->l_sysid);
 	err |= __put_user(kfl->l_pid, &ufl->l_pid);
+
 	return err;
 }
 
@@ -1447,7 +1505,7 @@
 			struct flock f;
 			mm_segment_t old_fs;
 			long ret;
-			
+
 			if (get_flock(&f, (struct flock32 *)arg))
 				return -EFAULT;
 			old_fs = get_fs(); set_fs (KERNEL_DS);
@@ -1490,6 +1548,19 @@
         unsigned short  seq;
 };
 
+struct ipc64_perm32 {
+	key_t key;
+	__kernel_uid_t32 uid;
+	__kernel_gid_t32 gid;
+	__kernel_uid_t32 cuid;
+	__kernel_gid_t32 cgid;
+	__kernel_mode_t32 mode; 
+	unsigned short seq;
+	unsigned short __pad1;
+	unsigned int __unused1;
+	unsigned int __unused2;
+};
+
 struct semid_ds32 {
         struct ipc_perm32 sem_perm;               /* permissions .. see ipc.h */
         __kernel_time_t32 sem_otime;              /* last semop time */
@@ -1512,24 +1583,44 @@
         u32 wwait;
         u32 rwait;
         unsigned short msg_cbytes;
-        unsigned short msg_qnum;  
+        unsigned short msg_qnum;
         unsigned short msg_qbytes;
         __kernel_ipc_pid_t32 msg_lspid;
         __kernel_ipc_pid_t32 msg_lrpid;
 };
 
+struct msqid64_ds32 {
+	struct ipc64_perm32 msg_perm;
+	__kernel_time_t32 msg_stime;
+	unsigned int __unused1;
+	__kernel_time_t32 msg_rtime;
+	unsigned int __unused2;
+	__kernel_time_t32 msg_ctime;
+	unsigned int __unused3;
+	unsigned int msg_cbytes;
+	unsigned int msg_qnum;
+	unsigned int msg_qbytes;
+	__kernel_pid_t32 msg_lspid;
+	__kernel_pid_t32 msg_lrpid;
+	unsigned int __unused4;
+	unsigned int __unused5;
+};
+
 struct shmid_ds32 {
         struct ipc_perm32       shm_perm;
         int                     shm_segsz;
         __kernel_time_t32       shm_atime;
         __kernel_time_t32       shm_dtime;
         __kernel_time_t32       shm_ctime;
-        __kernel_ipc_pid_t32    shm_cpid; 
-        __kernel_ipc_pid_t32    shm_lpid; 
+        __kernel_ipc_pid_t32    shm_cpid;
+        __kernel_ipc_pid_t32    shm_lpid;
         unsigned short          shm_nattch;
 };
 
-#define IPCOP_MASK(__x)	(1UL << (__x))
+struct ipc_kludge32 {
+	u32 msgp;
+	s32 msgtyp;
+};
 
 static int
 do_sys32_semctl(int first, int second, int third, void *uptr)
@@ -1596,21 +1687,23 @@
 	return err;
 }
 
-static int
 do_sys32_msgsnd (int first, int second, int third, void *uptr)
 {
-	struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf)
-				    + 4, GFP_USER);
 	struct msgbuf32 *up = (struct msgbuf32 *)uptr;
+	struct msgbuf *p;
 	mm_segment_t old_fs;
 	int err;
 
+	if (second < 0)
+		return -EINVAL;
+	p = kmalloc (second + sizeof (struct msgbuf)
+				    + 4, GFP_USER);
 	if (!p)
 		return -ENOMEM;
 	err = get_user (p->mtype, &up->mtype);
 	if (err)
 		goto out;
-	err = __copy_from_user (p->mtext, &up->mtext, second);
+	err |= __copy_from_user (p->mtext, &up->mtext, second);
 	if (err)
 		goto out;
 	old_fs = get_fs ();
@@ -1619,6 +1712,7 @@
 	set_fs (old_fs);
 out:
 	kfree (p);
+
 	return err;
 }
 
@@ -1632,18 +1726,21 @@
 	int err;
 
 	if (!version) {
-		struct ipc_kludge *uipck = (struct ipc_kludge *)uptr;
-		struct ipc_kludge ipck;
+		struct ipc_kludge32 *uipck = (struct ipc_kludge32 *)uptr;
+		struct ipc_kludge32 ipck;
 
 		err = -EINVAL;
 		if (!uptr)
 			goto out;
 		err = -EFAULT;
-		if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge)))
+		if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge32)))
 			goto out;
-		uptr = (void *)A(ipck.msgp);
+		uptr = (void *)AA(ipck.msgp);
 		msgtyp = ipck.msgtyp;
 	}
+
+	if (second < 0)
+		return -EINVAL;
 	err = -ENOMEM;
 	p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER);
 	if (!p)
@@ -1668,13 +1765,12 @@
 do_sys32_msgctl (int first, int second, void *uptr)
 {
 	int err = -EINVAL, err2;
-	struct msqid_ds m;
-	struct msqid64_ds m64;
-	struct msqid_ds32 *up = (struct msqid_ds32 *)uptr;
+	struct msqid64_ds m;
+	struct msqid_ds32 *up32 = (struct msqid_ds32 *)uptr;
+	struct msqid64_ds32 *up64 = (struct msqid64_ds32 *)uptr;
 	mm_segment_t old_fs;
 
-	switch (second) {
-
+	switch (second & ~IPC_64) {
 	case IPC_INFO:
 	case IPC_RMID:
 	case MSG_INFO:
@@ -1682,15 +1778,30 @@
 		break;
 
 	case IPC_SET:
-		err = get_user (m.msg_perm.uid, &up->msg_perm.uid);
-		err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid);
-		err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode);
-		err |= __get_user (m.msg_qbytes, &up->msg_qbytes);
+		if (second & IPC_64) {
+			if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) {
+				err = -EFAULT;
+				break;
+			}
+			err = __get_user(m.msg_perm.uid, &up64->msg_perm.uid);
+			err |= __get_user(m.msg_perm.gid, &up64->msg_perm.gid);
+			err |= __get_user(m.msg_perm.mode, &up64->msg_perm.mode);
+			err |= __get_user(m.msg_qbytes, &up64->msg_qbytes);
+		} else {
+			if (!access_ok(VERIFY_READ, up32, sizeof(*up32))) {
+				err = -EFAULT;
+				break;
+			}
+			err = __get_user(m.msg_perm.uid, &up32->msg_perm.uid);
+			err |= __get_user(m.msg_perm.gid, &up32->msg_perm.gid);
+			err |= __get_user(m.msg_perm.mode, &up32->msg_perm.mode);
+			err |= __get_user(m.msg_qbytes, &up32->msg_qbytes);
+		}
 		if (err)
 			break;
 		old_fs = get_fs ();
 		set_fs (KERNEL_DS);
-		err = sys_msgctl (first, second, &m);
+		err = sys_msgctl (first, second, (struct msqid_ds *)&m);
 		set_fs (old_fs);
 		break;
 
@@ -1698,27 +1809,54 @@
 	case MSG_STAT:
 		old_fs = get_fs ();
 		set_fs (KERNEL_DS);
-		err = sys_msgctl (first, second, (void *) &m64);
+		err = sys_msgctl (first, second, (struct msqid_ds *)&m);
 		set_fs (old_fs);
-		err2 = put_user (m64.msg_perm.key, &up->msg_perm.key);
-		err2 |= __put_user(m64.msg_perm.uid, &up->msg_perm.uid);
-		err2 |= __put_user(m64.msg_perm.gid, &up->msg_perm.gid);
-		err2 |= __put_user(m64.msg_perm.cuid, &up->msg_perm.cuid);
-		err2 |= __put_user(m64.msg_perm.cgid, &up->msg_perm.cgid);
-		err2 |= __put_user(m64.msg_perm.mode, &up->msg_perm.mode);
-		err2 |= __put_user(m64.msg_perm.seq, &up->msg_perm.seq);
-		err2 |= __put_user(m64.msg_stime, &up->msg_stime);
-		err2 |= __put_user(m64.msg_rtime, &up->msg_rtime);
-		err2 |= __put_user(m64.msg_ctime, &up->msg_ctime);
-		err2 |= __put_user(m64.msg_cbytes, &up->msg_cbytes);
-		err2 |= __put_user(m64.msg_qnum, &up->msg_qnum);
-		err2 |= __put_user(m64.msg_qbytes, &up->msg_qbytes);
-		err2 |= __put_user(m64.msg_lspid, &up->msg_lspid);
-		err2 |= __put_user(m64.msg_lrpid, &up->msg_lrpid);
-		if (err2)
-			err = -EFAULT;
+		if (second & IPC_64) {
+			if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(m.msg_perm.key, &up64->msg_perm.key);
+			err2 |= __put_user(m.msg_perm.uid, &up64->msg_perm.uid);
+			err2 |= __put_user(m.msg_perm.gid, &up64->msg_perm.gid);
+			err2 |= __put_user(m.msg_perm.cuid, &up64->msg_perm.cuid);
+			err2 |= __put_user(m.msg_perm.cgid, &up64->msg_perm.cgid);
+			err2 |= __put_user(m.msg_perm.mode, &up64->msg_perm.mode);
+			err2 |= __put_user(m.msg_perm.seq, &up64->msg_perm.seq);
+			err2 |= __put_user(m.msg_stime, &up64->msg_stime);
+			err2 |= __put_user(m.msg_rtime, &up64->msg_rtime);
+			err2 |= __put_user(m.msg_ctime, &up64->msg_ctime);
+			err2 |= __put_user(m.msg_cbytes, &up64->msg_cbytes);
+			err2 |= __put_user(m.msg_qnum, &up64->msg_qnum);
+			err2 |= __put_user(m.msg_qbytes, &up64->msg_qbytes);
+			err2 |= __put_user(m.msg_lspid, &up64->msg_lspid);
+			err2 |= __put_user(m.msg_lrpid, &up64->msg_lrpid);
+			if (err2)
+				err = -EFAULT;
+		} else {
+			if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(m.msg_perm.key, &up32->msg_perm.key);
+			err2 |= __put_user(m.msg_perm.uid, &up32->msg_perm.uid);
+			err2 |= __put_user(m.msg_perm.gid, &up32->msg_perm.gid);
+			err2 |= __put_user(m.msg_perm.cuid, &up32->msg_perm.cuid);
+			err2 |= __put_user(m.msg_perm.cgid, &up32->msg_perm.cgid);
+			err2 |= __put_user(m.msg_perm.mode, &up32->msg_perm.mode);
+			err2 |= __put_user(m.msg_perm.seq, &up32->msg_perm.seq);
+			err2 |= __put_user(m.msg_stime, &up32->msg_stime);
+			err2 |= __put_user(m.msg_rtime, &up32->msg_rtime);
+			err2 |= __put_user(m.msg_ctime, &up32->msg_ctime);
+			err2 |= __put_user(m.msg_cbytes, &up32->msg_cbytes);
+			err2 |= __put_user(m.msg_qnum, &up32->msg_qnum);
+			err2 |= __put_user(m.msg_qbytes, &up32->msg_qbytes);
+			err2 |= __put_user(m.msg_lspid, &up32->msg_lspid);
+			err2 |= __put_user(m.msg_lrpid, &up32->msg_lrpid);
+			if (err2)
+				err = -EFAULT;
+		}
 		break;
-
 	}
 
 	return err;
@@ -1841,7 +1979,7 @@
 
 	case SEMOP:
 		/* struct sembuf is the same on 32 and 64bit :)) */
-		err = sys_semop (first, (struct sembuf *)A(ptr),
+		err = sys_semop (first, (struct sembuf *)AA(ptr),
 				 second);
 		break;
 	case SEMGET:
@@ -1849,36 +1987,36 @@
 		break;
 	case SEMCTL:
 		err = do_sys32_semctl (first, second, third,
-				       (void *)A(ptr));
+				       (void *)AA(ptr));
 		break;
 
 	case MSGSND:
 		err = do_sys32_msgsnd (first, second, third,
-				       (void *)A(ptr));
+				       (void *)AA(ptr));
 		break;
 	case MSGRCV:
 		err = do_sys32_msgrcv (first, second, fifth, third,
-				       version, (void *)A(ptr));
+				       version, (void *)AA(ptr));
 		break;
 	case MSGGET:
 		err = sys_msgget ((key_t) first, second);
 		break;
 	case MSGCTL:
-		err = do_sys32_msgctl (first, second, (void *)A(ptr));
+		err = do_sys32_msgctl (first, second, (void *)AA(ptr));
 		break;
 
 	case SHMAT:
 		err = do_sys32_shmat (first, second, third,
-				      version, (void *)A(ptr));
+				      version, (void *)AA(ptr));
 		break;
-	case SHMDT: 
+	case SHMDT:
 		err = sys_shmdt ((char *)A(ptr));
 		break;
 	case SHMGET:
 		err = sys_shmget (first, second, third);
 		break;
 	case SHMCTL:
-		err = do_sys32_shmctl (first, second, (void *)A(ptr));
+		err = do_sys32_shmctl (first, second, (void *)AA(ptr));
 		break;
 	default:
 		err = -EINVAL;
@@ -1911,7 +2049,7 @@
 	ret = -EFAULT;
 
 	memset(&kargs, 0, sizeof (kargs));
-	
+
 	err = get_user(kargs32.name, &uargs32->name);
 	err |= __get_user(kargs32.nlen, &uargs32->nlen);
 	err |= __get_user(kargs32.oldval, &uargs32->oldval);
@@ -1973,7 +2111,7 @@
 		kfree(kargs.oldval);
 	if (kargs.newval)
 		kfree(kargs.newval);
-	return ret; 
+	return ret;
 }
 
 asmlinkage long sys32_newuname(struct new_utsname * name)
@@ -2081,7 +2219,7 @@
 /*
  *  Declare the 32-bit version of the msghdr
  */
- 
+
 struct msghdr32 {
 	unsigned int    msg_name;	/* Socket name			*/
 	int		msg_namelen;	/* Length of name		*/
@@ -2129,7 +2267,7 @@
 {
 	int size, err, ct;
 	struct iovec32 *iov32;
-	
+
 	if(m->msg_namelen)
 	{
 		if(mode==VERIFY_READ)
@@ -2138,7 +2276,7 @@
 			if(err<0)
 				goto out;
 		}
-		
+
 		m->msg_name = address;
 	} else
 		m->msg_name = NULL;
@@ -2167,7 +2305,7 @@
 }
 
 /* XXX This really belongs in some header file... -DaveM */
-#define MAX_SOCK_ADDR	128		/* 108 for Unix domain - 
+#define MAX_SOCK_ADDR	128		/* 108 for Unix domain -
 					   16 for IP, 16 for IPX,
 					   24 for IPv6,
 					   about 80 for AX.25 */
@@ -2187,13 +2325,13 @@
 	unsigned char *ctl_buf = ctl;
 	struct msghdr msg_sys;
 	int err, ctl_len, iov_size, total_len;
-	
+
 	err = -EFAULT;
 	if (shape_msg(&msg_sys, msg))
-		goto out; 
+		goto out;
 
 	sock = sockfd_lookup(fd, &err);
-	if (!sock) 
+	if (!sock)
 		goto out;
 
 	/* do not move before msg_sys is valid */
@@ -2212,7 +2350,7 @@
 
 	/* This will also move the address data into kernel space */
 	err = verify_iovec32(&msg_sys, iov, address, VERIFY_READ);
-	if (err < 0) 
+	if (err < 0)
 		goto out_freeiov;
 	total_len = err;
 
@@ -2220,14 +2358,14 @@
 
 	if (msg_sys.msg_controllen > INT_MAX)
 		goto out_freeiov;
-	ctl_len = msg_sys.msg_controllen; 
-	if (ctl_len) 
+	ctl_len = msg_sys.msg_controllen;
+	if (ctl_len)
 	{
 		if (ctl_len > sizeof(ctl))
 		{
 			err = -ENOBUFS;
 			ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL);
-			if (ctl_buf == NULL) 
+			if (ctl_buf == NULL)
 				goto out_freeiov;
 		}
 		err = -EFAULT;
@@ -2242,14 +2380,14 @@
 	err = sock_sendmsg(sock, &msg_sys, total_len);
 
 out_freectl:
-	if (ctl_buf != ctl)    
+	if (ctl_buf != ctl)
 		sock_kfree_s(sock->sk, ctl_buf, ctl_len);
 out_freeiov:
 	if (iov != iovstack)
 		sock_kfree_s(sock->sk, iov, iov_size);
 out_put:
 	sockfd_put(sock);
-out:       
+out:
 	return err;
 }
 
@@ -2273,7 +2411,7 @@
 	/* user mode address pointers */
 	struct sockaddr *uaddr;
 	int *uaddr_len;
-	
+
 	err=-EFAULT;
 	if (shape_msg(&msg_sys, msg))
 		goto out;
@@ -2285,7 +2423,7 @@
 	err = -EINVAL;
 	if (msg_sys.msg_iovlen > UIO_MAXIOV)
 		goto out_put;
-	
+
 	/* Check whether to allocate the iovec area*/
 	err = -ENOMEM;
 	iov_size = msg_sys.msg_iovlen * sizeof(struct iovec);
@@ -2299,7 +2437,7 @@
 	 *	Save the user-mode address (verify_iovec will change the
 	 *	kernel msghdr to use the kernel address space)
 	 */
-	 
+
 	uaddr = msg_sys.msg_name;
 	uaddr_len = &msg->msg_namelen;
 	err = verify_iovec32(&msg_sys, iov, addr, VERIFY_WRITE);
@@ -2309,7 +2447,7 @@
 
 	cmsg_ptr = (unsigned long)msg_sys.msg_control;
 	msg_sys.msg_flags = 0;
-	
+
 	if (sock->file->f_flags & O_NONBLOCK)
 		flags |= MSG_DONTWAIT;
 	err = sock_recvmsg(sock, &msg_sys, total_len, flags);
@@ -2325,7 +2463,7 @@
 	err = __put_user(msg_sys.msg_flags, &msg->msg_flags);
 	if (err)
 		goto out_freeiov;
-	err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, 
+	err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr,
 							 &msg->msg_controllen);
 	if (err)
 		goto out_freeiov;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/mips64_ksyms.c linux-2.4.20/arch/mips64/kernel/mips64_ksyms.c
--- linux-2.4.19/arch/mips64/kernel/mips64_ksyms.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/mips64_ksyms.c	2002-10-29 11:18:38.000000000 +0000
@@ -39,7 +39,10 @@
 extern long __strnlen_user_asm(const char *s);
 
 EXPORT_SYMBOL(mips_machtype);
+
+#ifdef CONFIG_EISA
 EXPORT_SYMBOL(EISA_bus);
+#endif
 
 /*
  * String functions
@@ -90,21 +93,11 @@
 EXPORT_SYMBOL(invalid_pte_table);
 
 /*
- * Base address of ports for Intel style I/O.
- */
-#if defined (CONFIG_PCI) || defined (CONFIG_ISA)
-EXPORT_SYMBOL(mips_io_port_base);
-#endif
-
-/*
  * Kernel hacking ...
  */
 #include <asm/branch.h>
 #include <linux/sched.h>
 
-int register_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31));
-int unregister_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31));
-
 #ifdef CONFIG_VT
 EXPORT_SYMBOL(screen_info);
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/pci-dma.c linux-2.4.20/arch/mips64/kernel/pci-dma.c
--- linux-2.4.19/arch/mips64/kernel/pci-dma.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/pci-dma.c	2002-10-29 11:18:40.000000000 +0000
@@ -4,17 +4,17 @@
  * for more details.
  *
  * Copyright (C) 2000  Ani Joshi <ajoshi@unixbox.com>
- * Copyright (C) 2000  Ralf Baechle <ralf@gnu.org>
+ * Copyright (C) 2000, 2001  Ralf Baechle <ralf@gnu.org>
  * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
  */
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/string.h>
 #include <linux/pci.h>
 
 #include <asm/io.h>
-#include <asm/addrspace.h>
 
 void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
 			   dma_addr_t * dma_handle)
@@ -22,24 +22,34 @@
 	void *ret;
 	int gfp = GFP_ATOMIC;
 
-	if (hwdev != NULL && hwdev->dma_mask != 0xffffffff)
+#ifdef CONFIG_ISA
+	if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
 		gfp |= GFP_DMA;
+#endif
 	ret = (void *) __get_free_pages(gfp, get_order(size));
 
 	if (ret != NULL) {
 		memset(ret, 0, size);
+		*dma_handle = bus_to_baddr(hwdev->bus->number, __pa(ret));
 #ifdef CONFIG_NONCOHERENT_IO
 		dma_cache_wback_inv((unsigned long) ret, size);
-		ret = KSEG1ADDR(ret);
+		ret = UNCAC_ADDR(ret);
 #endif
-		*dma_handle = __pa(ret);
-		return ret;
 	}
-	return NULL;
+
+	return ret;
 }
 
 void pci_free_consistent(struct pci_dev *hwdev, size_t size,
 			 void *vaddr, dma_addr_t dma_handle)
 {
-	free_pages((unsigned long) KSEG0ADDR(vaddr), get_order(size));
+	unsigned long addr = (unsigned long) vaddr;
+
+#ifdef CONFIG_NONCOHERENT_IO
+	addr = CAC_ADDR(addr);
+#endif
+	free_pages(addr, get_order(size));
 }
+
+EXPORT_SYMBOL(pci_alloc_consistent);
+EXPORT_SYMBOL(pci_free_consistent);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/proc.c linux-2.4.20/arch/mips64/kernel/proc.c
--- linux-2.4.19/arch/mips64/kernel/proc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/proc.c	2002-10-29 11:18:50.000000000 +0000
@@ -67,7 +67,13 @@
 	[CPU_R5500]	"R5500",
 	[CPU_TX49XX]	"TX49xx",
 	[CPU_TX39XX]	"TX39xx",
-	[CPU_20KC]	"MIPS 20Kc"
+	[CPU_20KC]	"MIPS 20Kc",
+	[CPU_VR4111]	"NEC VR4111",
+	[CPU_VR4121]	"NEC VR4121",
+	[CPU_VR4122]	"NEC VR4122",
+	[CPU_VR4131]	"NEC VR4131",
+	[CPU_VR4181]	"NEC VR4181",
+	[CPU_VR4181A]	"NEC VR4181A"
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/process.c linux-2.4.20/arch/mips64/kernel/process.c
--- linux-2.4.19/arch/mips64/kernel/process.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/process.c	2002-10-29 11:18:35.000000000 +0000
@@ -29,6 +29,7 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/elf.h>
+#include <asm/cpu.h>
 
 ATTRIB_NORET void cpu_idle(void)
 {
@@ -53,8 +54,10 @@
 {
 	/* Forget lazy fpu state */
 	if (IS_FPU_OWNER()) {
-		__enable_fpu();
-		__asm__ __volatile__("cfc1\t$0,$31");
+		if (mips_cpu.options & MIPS_CPU_FPU) {
+			__enable_fpu();
+			__asm__ __volatile__("cfc1\t$0,$31");
+		}
 		CLEAR_FPU_OWNER();
 	}
 }
@@ -63,8 +66,10 @@
 {
 	/* Forget lazy fpu state */
 	if (IS_FPU_OWNER()) {
-		__enable_fpu();
-		__asm__ __volatile__("cfc1\t$0,$31");
+		if (mips_cpu.options & MIPS_CPU_FPU) {
+			__enable_fpu();
+			__asm__ __volatile__("cfc1\t$0,$31");
+		}
 		CLEAR_FPU_OWNER();
 	}
 }
@@ -79,7 +84,8 @@
 	childksp = (unsigned long)p + KERNEL_STACK_SIZE - 32;
 
 	if (IS_FPU_OWNER()) {
-		save_fp(p);
+		if (mips_cpu.options & MIPS_CPU_FPU)
+			save_fp(p);
 	}
 	/* set up new TSS. */
 	childregs = (struct pt_regs *) childksp - 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/ptrace.c linux-2.4.20/arch/mips64/kernel/ptrace.c
--- linux-2.4.19/arch/mips64/kernel/ptrace.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/ptrace.c	2002-10-29 11:18:35.000000000 +0000
@@ -84,7 +84,7 @@
 
 	switch (request) {
 	/* when I and D space are separate, these will need to be fixed. */
-	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+	case PTRACE_PEEKTEXT: /* read word at location addr. */
 	case PTRACE_PEEKDATA: {
 		unsigned int tmp;
 		int copied;
@@ -203,7 +203,7 @@
 			fregs = (unsigned long long *)&child->thread.fpu.hard.fp_regs[0];
 			if (child->used_math) {
 #ifndef CONFIG_SMP
-				if (last_task_used_math == child) 
+				if (last_task_used_math == child)
 					if (mips_cpu.options & MIPS_CPU_FPU) {
 						__enable_fpu();
 						save_fp(child);
@@ -245,7 +245,7 @@
 			regs->lo = data;
 			break;
 		case FPC_CSR:
-			if (mips_cpu.options & MIPS_CPU_FPU) 
+			if (mips_cpu.options & MIPS_CPU_FPU)
 				child->thread.fpu.hard.control = data;
 			else
 				child->thread.fpu.soft.sr = data;
@@ -273,8 +273,8 @@
 	}
 
 /*
- * make the child exit.  Best I can do is send it a sigkill. 
- * perhaps it should be put in the status that it wants to 
+ * make the child exit.  Best I can do is send it a sigkill.
+ * perhaps it should be put in the status that it wants to
  * exit.
  */
 	case PTRACE_KILL: {
@@ -355,7 +355,7 @@
 
 	switch (request) {
 	/* when I and D space are separate, these will need to be fixed. */
-	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+	case PTRACE_PEEKTEXT: /* read word at location addr. */
 	case PTRACE_PEEKDATA: {
 		unsigned long tmp;
 		int copied;
@@ -546,8 +546,8 @@
 	}
 
 /*
- * make the child exit.  Best I can do is send it a sigkill. 
- * perhaps it should be put in the status that it wants to 
+ * make the child exit.  Best I can do is send it a sigkill.
+ * perhaps it should be put in the status that it wants to
  * exit.
  */
 	case PTRACE_KILL: {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/r4k_fpu.S linux-2.4.20/arch/mips64/kernel/r4k_fpu.S
--- linux-2.4.19/arch/mips64/kernel/r4k_fpu.S	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/r4k_fpu.S	2002-10-29 11:18:31.000000000 +0000
@@ -31,7 +31,7 @@
 
 	.set	noreorder
 	/* Save floating point context */
-LEAF(save_fp_context)
+LEAF(_save_fp_context)
 	mfc0	t1, CP0_STATUS
 	sll	t2, t1,5
 
@@ -79,7 +79,7 @@
 
 	jr	ra
 	 li	v0, 0					# success
-	END(save_fp_context)
+	END(_save_fp_context)
 
 /*
  * Restore FPU state:
@@ -90,7 +90,7 @@
  * frame on the current content of c0_status, not on the content of the
  * stack frame which might have been changed by the user.
  */
-LEAF(restore_fp_context)
+LEAF(_restore_fp_context)
 	mfc0	t1, CP0_STATUS
 	sll	t0, t1,5
 	bgez	t0, 1f
@@ -139,7 +139,7 @@
 	ctc1	t0, fcr31
 	jr	ra
 	 li	v0, 0					# success
-	END(restore_fp_context)
+	END(_restore_fp_context)
 
 	.type	fault@function
 	.ent	fault
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/r4k_genex.S linux-2.4.20/arch/mips64/kernel/r4k_genex.S
--- linux-2.4.19/arch/mips64/kernel/r4k_genex.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/r4k_genex.S	2002-10-29 11:18:32.000000000 +0000
@@ -40,6 +40,9 @@
  */
 	NESTED(except_vec3_r4000, 0, sp)
 	.set	noat
+#if defined(R5432_CP0_INTERRUPT_WAR)
+	mfc0    k0, CP0_INDEX
+#endif
 	mfc0	k1, CP0_CAUSE
 	andi	k1, k1, 0x7c
 	li	k0, 31<<2
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/r4k_switch.S linux-2.4.20/arch/mips64/kernel/r4k_switch.S
--- linux-2.4.19/arch/mips64/kernel/r4k_switch.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/r4k_switch.S	2002-10-29 11:18:31.000000000 +0000
@@ -10,7 +10,6 @@
  */
 #include <asm/asm.h>
 #include <asm/cachectl.h>
-#include <asm/current.h>
 #include <asm/fpregdef.h>
 #include <asm/mipsregs.h>
 #include <asm/offset.h>
@@ -69,6 +68,7 @@
 	li	t3, ST0_CU1
 	or	t0, t3
 	mtc0	t0, CP0_STATUS
+	FPU_ENABLE_HAZARD
 
 	beqz	a0, 2f				# Save floating point state
 	 nor	t3, zero, t3
@@ -88,11 +88,11 @@
 
 	sll	t0, t0, 5			# load new fp state
 	bgez	t0, 1f
-	 ldc1	$f0, (THREAD_FPU + 0x00)($28)
-	fpu_restore_16odd $28
+	 ldc1	$f0, (THREAD_FPU + 0x00)(a1)
+	fpu_restore_16odd a1
 1:
 	.set	reorder
-	fpu_restore_16even $28, t0		# clobbers t0
+	fpu_restore_16even a1, t0		# clobbers t0
 3:
 	jr	ra
 	END(lazy_fpu_switch)
@@ -119,15 +119,15 @@
 LEAF(restore_fp)
 	mfc0	t0, CP0_STATUS
 	sll	t1, t0, 5
-	bgez	t0, 1f				# 16 register mode?
+	bgez	t1, 1f				# 16 register mode?
 	 nop
 
-	fpu_restore_16odd $28
+	fpu_restore_16odd a0
 1:
-	.set	reorder
-	fpu_restore_16even $28, t0		# clobbers t0
+	fpu_restore_16even a0, t0		# clobbers t0
 
 	jr	ra
+	 ldc1	$f0, (THREAD_FPU + 0x00)(a0)
 	END(restore_fp)
 
 /*
@@ -145,6 +145,7 @@
 	li	t1, ST0_CU1
 	or	t0, t1
 	mtc0	t0, CP0_STATUS
+	FPU_ENABLE_HAZARD
 	sll	t0, t0, 5
 
 	li	t1, FPU_DEFAULT
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/scall_64.S linux-2.4.20/arch/mips64/kernel/scall_64.S
--- linux-2.4.19/arch/mips64/kernel/scall_64.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/scall_64.S	2002-10-29 11:18:33.000000000 +0000
@@ -15,12 +15,7 @@
 #include <asm/regdef.h>
 #include <asm/stackframe.h>
 #include <asm/unistd.h>
-
-/* This duplicates the definition from <linux/sched.h> */
-#define PT_TRACESYS	0x00000002	/* tracing system calls */
-
-/* This duplicates the definition from <asm/signal.h> */
-#define SIGILL		4		/* Illegal instruction (ANSI).  */
+#include <asm/offset.h>
 
 #ifndef CONFIG_MIPS32_COMPAT
 #define handle_sys64 handle_sys
@@ -49,7 +44,7 @@
 	sd	a3, PT_R26(sp)		# save a3 for syscall restarting
 
 	ld	t0, TASK_PTRACE($28)	# syscall tracing enabled?
-	andi	t0, PT_TRACESYS
+	andi	t0, _PT_TRACESYS
 	bnez	t0, trace_a_syscall
 
 	jalr	t2			# Do The Real Thing (TM)
@@ -65,9 +60,10 @@
 
 ret_from_sys_call:
 	mfc0	t0, CP0_STATUS
-	xori	t0, t0, 1
 	ori	t0, t0, 1
+	xori	t0, t0, 1
 	mtc0	t0, CP0_STATUS
+	SSNOP; SSNOP; SSNOP
 
 	ld	t2, TASK_NEED_RESCHED($28)
 	bnez	t2, reschedule
@@ -132,6 +128,7 @@
 	j	ret_from_sys_call
 	END(handle_sys64)
 
+	.align	3
 sys_call_table:
 	PTR	sys_syscall				/* 5000 */
 	PTR	sys_exit
@@ -350,20 +347,20 @@
 	PTR	sys_ni_syscall
 	PTR	sys_gettid				/* 5215 */
 	PTR	sys_readahead
-	PTR	sys_ni_syscall			/* reserved for setxattr */
-	PTR	sys_ni_syscall			/* reserved for lsetxattr */
-	PTR	sys_ni_syscall			/* reserved for fsetxattr */
-	PTR	sys_ni_syscall			/* 5220 res. for getxattr */
-	PTR	sys_ni_syscall			/* reserved for lgetxattr */
-	PTR	sys_ni_syscall			/* reserved for fgetxattr */
-	PTR	sys_ni_syscall			/* reserved for listxattr */
-	PTR	sys_ni_syscall			/* reserved for llistxattr */
-	PTR	sys_ni_syscall			/* 5225 res. for flistxattr */
-	PTR	sys_ni_syscall			/* reserved for removexattr */
-	PTR	sys_ni_syscall			/* reserved for lremovexattr */
-	PTR	sys_ni_syscall			/* reserved for fremovexattr */
+	PTR	sys_setxattr
+	PTR	sys_lsetxattr
+	PTR	sys_fsetxattr
+	PTR	sys_getxattr				/* 5220 */
+	PTR	sys_lgetxattr
+	PTR	sys_fgetxattr
+	PTR	sys_listxattr
+	PTR	sys_llistxattr
+	PTR	sys_flistxattr				/* 5225 */
+	PTR	sys_removexattr
+	PTR	sys_lremovexattr
+	PTR	sys_fremovexattr
 	PTR	sys_tkill, 2
-	PTR	sys_ni_syscall, 0		/* res. for sendfile64 */
+	PTR	sys_ni_syscall, 0		/* 5230 res. for sendfile64 */
 	PTR	sys_ni_syscall, 0		/* res. for futex */
 	PTR	sys_ni_syscall, 0		/* res. for sched_setaffinity */
-	PTR	sys_ni_syscall, 0		/* 4240 res. for sched_getaffinity */
+	PTR	sys_ni_syscall, 0		/* res. for sched_getaffinity */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/scall_o32.S linux-2.4.20/arch/mips64/kernel/scall_o32.S
--- linux-2.4.19/arch/mips64/kernel/scall_o32.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/scall_o32.S	2002-10-29 11:18:34.000000000 +0000
@@ -16,17 +16,12 @@
 #include <linux/errno.h>
 #include <asm/current.h>
 #include <asm/mipsregs.h>
+#include <asm/offset.h>
 #include <asm/regdef.h>
 #include <asm/stackframe.h>
 #include <asm/unistd.h>
 #include <asm/sysmips.h>
 
-/* This duplicates the definition from <linux/sched.h> */
-#define PT_TRACESYS	0x00000002	/* tracing system calls */
-
-/* This duplicates the definition from <asm/signal.h> */
-#define SIGILL		4		/* Illegal instruction (ANSI).  */
-
 /* Highest syscall used of any syscall flavour */
 #define MAX_SYSCALL_NO	__NR_Linux32 + __NR_Linux32_syscalls
 
@@ -61,7 +56,7 @@
 
 stack_done:
 		ld	t0, TASK_PTRACE($28)	# syscall tracing enabled?
-		andi	t0, PT_TRACESYS
+		andi	t0, _PT_TRACESYS
 		bnez	t0, trace_a_syscall
 
 		jalr	t2			# Do The Real Thing (TM)
@@ -80,6 +75,7 @@
 		ori	t0, t0, 1
 		xori	t0, t0, 1
 		mtc0	t0, CP0_STATUS
+		SSNOP; SSNOP; SSNOP
 
 		ld	t2, TASK_NEED_RESCHED($28)
 		bnez	t2, o32_reschedule
@@ -156,16 +152,20 @@
 	bltz	t0, bad_stack		# -> sp is bad
 
 	ld	t0, PT_R29(sp)		# get old user stack pointer
-	la	t1, 3f			# copy 1 to 2 arguments
+	PTR_LA	t1, 3f			# copy 1 to 2 arguments
 	sll	t3, t3, 2
 	subu	t1, t3
 	jr	t1
 
 	/* Ok, copy the args from the luser stack to the kernel stack */
+	.set	push
+	.set	noreorder
+	.set	nomacro
 1:	lw	a5, 20(t0)		# argument #6 from usp
 2:	lw	a4, 16(t0)		# argument #5 from usp
+3:	.set	pop
 
-3:	j	stack_done		# go back
+	j	stack_done		# go back
 
 	.section __ex_table,"a"
 	PTR	1b, bad_stack
@@ -222,7 +222,7 @@
 
 	/* Success, so skip usual error handling garbage.  */
 	ld	t0, TASK_PTRACE($28)	# syscall tracing enabled?
-	andi	t0, PT_TRACESYS
+	andi	t0, _PT_TRACESYS
 	bnez	t0, 1f
 	b	o32_ret_from_sys_call
 
@@ -245,8 +245,74 @@
 	j	sys_sysmips
 	END(sys32_sysmips)
 
+	LEAF(sys32_syscall)
+	ld	t0, PT_R29(sp)		# user sp
+
+	sltu	v0, a0, __NR_Linux + __NR_Linux_syscalls + 1
+	beqz	v0, enosys
+
+	dsll	v0, a0, 3
+	dla	v1, sys32_syscall
+	ld	t2, (sys_call_table - (__NR_Linux32 * 8))(v0)	# function pointer
+	lbu	t3, (sys_narg_table - __NR_Linux32)(a0)	# number of arguments
+
+	li	v0, -EINVAL
+	beq	t2, v1, out		# do not recurse
+
+	beqz	t2, enosys		# null function pointer?
+
+	andi	v0, t0, 0x3		# unaligned stack pointer?
+	bnez	v0, sigsegv
+
+	daddiu	v0, t0, 16		# v0 = usp + 16
+	daddu	t1, v0, 12		# 3 32-bit arguments
+	ld	v1, THREAD_CURDS($28)
+	or	v0, v0, t1
+	and	v1, v1, v0
+	bltz	v1, efault
+
+	move	a0, a1			# shift argument registers
+	move	a1, a2
+	move	a2, a3
+
+1:	lw	a3, 16(t0)
+2:	lw	t3, 20(t0)
+3:	lw	t1, 24(t0)
+
+	.section __ex_table,"a"
+	PTR	1b, efault
+	PTR	2b, efault
+	PTR	3b, efault
+	.previous
+
+	sw	t3, 16(sp)		# put into new stackframe
+	sw	t1, 20(sp)
+
+	bnez	t1, 1f			# zero arguments?
+	daddu	a0, sp, 32		# then pass sp in a0
+1:
+
+	sw	t3, 16(sp)
+	sw	v1, 20(sp)
+	jr	t2
+	/* Unreached */
+
+enosys:	li	v0, -ENOSYS
+	b	out
+
+sigsegv:
+	li	a0, _SIGSEGV
+	move	a1, $28
+	jal	force_sig
+	/* Fall through */
+
+efault:	li	v0, -EFAULT
+
+out:	jr	ra
+	END(sys32_syscall)
+
 	.macro	syscalltable
-	sys	sys_syscall	0			/* 4000 */
+	sys	sys32_syscall	0			/* 4000 */
 	sys	sys_exit	1
 	sys	sys_fork	0
 	sys	sys_read	3
@@ -453,7 +519,7 @@
 	sys	sys_capget	2
 	sys	sys_capset	2			/* 4205 */
 	sys	sys32_sigaltstack	0
-	sys	sys_sendfile	3
+	sys	sys_sendfile	4
 	sys	sys_ni_syscall	0
 	sys	sys_ni_syscall	0
 	sys	sys_mmap2	6			/* 4210 */
@@ -470,18 +536,18 @@
 	sys	sys_ni_syscall	0
 	sys	sys_gettid	0
 	sys	sys32_readahead	5
-	sys	sys_ni_syscall	0		/* reserved for setxattr */
-	sys	sys_ni_syscall	0		/* 4225 res. for lsetxattr */
-	sys	sys_ni_syscall	0		/* reserved for fsetxattr */
-	sys	sys_ni_syscall	0		/* reserved for getxattr */
-	sys	sys_ni_syscall	0		/* reserved for lgetxattr */
-	sys	sys_ni_syscall	0		/* reserved for fgetxattr */
-	sys	sys_ni_syscall	0		/* 4230 res. for listxattr */
-	sys	sys_ni_syscall	0		/* reserved for llistxattr */
-	sys	sys_ni_syscall	0		/* reserved for flistxattr */
-	sys	sys_ni_syscall	0		/* reserved for removexattr */
-	sys	sys_ni_syscall	0		/* reserved for lremovexattr */
-	sys	sys_ni_syscall	0		/* 4235 res. for fremovexattr */
+	sys	sys_setxattr	5
+	sys	sys_lsetxattr	5		/* 4225 */
+	sys	sys_fsetxattr	5
+	sys	sys_getxattr	4
+	sys	sys_lgetxattr	4
+	sys	sys_fgetxattr	4
+	sys	sys_listxattr	3		/* 4230 */
+	sys	sys_llistxattr	3
+	sys	sys_flistxattr	3
+	sys	sys_removexattr	2
+	sys	sys_lremovexattr 2
+	sys	sys_fremovexattr 2		/* 4235 */
 	sys	sys_tkill, 2
 	sys	sys_ni_syscall, 0		/* res. for sendfile64 */
 	sys	sys_ni_syscall, 0		/* res. for futex */
@@ -494,6 +560,7 @@
 	PTR	\function
 	.endm
 
+	.align	3
 sys_call_table:
 	syscalltable
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/setup.c linux-2.4.20/arch/mips64/kernel/setup.c
--- linux-2.4.19/arch/mips64/kernel/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/setup.c	2002-10-29 11:18:31.000000000 +0000
@@ -43,15 +43,6 @@
 struct cpuinfo_mips cpu_data[1];
 #endif
 
-/*
- * Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
- * the implementation of the "wait" feature differs between CPU families. This
- * points to the function that implements CPU specific wait. 
- * The wait instruction stops the pipeline and reduces the power consumption of
- * the CPU very much.
- */
-void (*cpu_wait)(void) = NULL;
-
 #ifdef CONFIG_VT
 struct screen_info screen_info;
 #endif
@@ -66,7 +57,9 @@
 /*
  * Set if box has EISA slots.
  */
+#ifdef CONFIG_EISA
 int EISA_bus = 0;
+#endif
 
 #ifdef CONFIG_BLK_DEV_FD
 extern struct fd_ops no_fd_ops;
@@ -113,387 +106,19 @@
 extern void ip27_setup(void);
 extern void ip32_setup(void);
 
+/*
+ * isa_slot_offset is the address where E(ISA) busaddress 0 is is mapped
+ * for the processor.
+ */
+unsigned long isa_slot_offset;
+EXPORT_SYMBOL(isa_slot_offset);
+
 extern void sgi_sysinit(void);
 extern void SetUpBootInfo(void);
 extern void load_mmu(void);
 extern ATTRIB_NORET asmlinkage void start_kernel(void);
 extern void prom_init(int, char **, char **, int *);
 
-static inline void check_wait(void)
-{
-	printk("Checking for 'wait' instruction... ");
-	switch(mips_cpu.cputype) {
-	case CPU_R3081:
-	case CPU_R3081E:
-		cpu_wait = r3081_wait;
-		printk(" available.\n");
-		break;
-	case CPU_TX3927:
-	case CPU_TX39XX:
-		cpu_wait = r39xx_wait;
-		printk(" available.\n");
-		break;
-	case CPU_R4200: 
-/*	case CPU_R4300: */
-	case CPU_R4600: 
-	case CPU_R4640: 
-	case CPU_R4650: 
-	case CPU_R4700: 
-	case CPU_R5000: 
-	case CPU_NEVADA:
-	case CPU_RM7000:
-	case CPU_TX49XX:
-	case CPU_4KC:
-	case CPU_4KEC:
-	case CPU_4KSC:
-	case CPU_5KC:
-/*	case CPU_20KC:*/
-		cpu_wait = r4k_wait;
-		printk(" available.\n");
-		break;
-	default:
-		printk(" unavailable.\n");
-		break;
-	}
-}
-
-void __init check_bugs(void)
-{
-	check_wait();
-}
-
-/*
- * Probe whether cpu has config register by trying to play with
- * alternate cache bit and see whether it matters.
- * It's used by cpu_probe to distinguish between R3000A and R3081.
- */
-static inline int cpu_has_confreg(void)
-{
-#ifdef CONFIG_CPU_R3000
-	extern unsigned long r3k_cache_size(unsigned long);
-	unsigned long size1, size2;
-	unsigned long cfg = read_32bit_cp0_register(CP0_CONF);
-
-	size1 = r3k_cache_size(ST0_ISC);
-	write_32bit_cp0_register(CP0_CONF, cfg^CONF_AC);
-	size2 = r3k_cache_size(ST0_ISC);
-	write_32bit_cp0_register(CP0_CONF, cfg);
-	return size1 != size2;
-#else
-	return 0;
-#endif
-}
-
-/*
- * Get the FPU Implementation/Revision.
- */
-static inline unsigned long cpu_get_fpu_id(void)
-{
-	unsigned long tmp, fpu_id;
-
-	tmp = read_32bit_cp0_register(CP0_STATUS);
-	__enable_fpu();
-	fpu_id = read_32bit_cp1_register(CP1_REVISION);
-	write_32bit_cp0_register(CP0_STATUS, tmp);
-	return fpu_id;
-}
-
-/* declaration of the global struct */
-struct mips_cpu mips_cpu = {
-    processor_id:	PRID_IMP_UNKNOWN,
-    fpu_id:		FPIR_IMP_NONE,
-    cputype:		CPU_UNKNOWN
-};
-
-#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4KTLB \
-                | MIPS_CPU_COUNTER | MIPS_CPU_CACHE_CDEX)
-
-static inline void cpu_probe(void)
-{
-#ifdef CONFIG_CPU_MIPS32
-	unsigned long config0 = read_32bit_cp0_register(CP0_CONFIG);
-	unsigned long config1;
-
-        if (config0 & (1 << 31)) {
-		/* MIPS32 compliant CPU. Read Config 1 register. */
-		mips_cpu.isa_level = MIPS_CPU_ISA_M32;
-		mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | 
-			MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | MIPS_CPU_DIVEC;
-		config1 = read_mips32_cp0_config1();
-		if (config1 & (1 << 3))
-			mips_cpu.options |= MIPS_CPU_WATCH;
-		if (config1 & (1 << 2))
-			mips_cpu.options |= MIPS_CPU_MIPS16;
-		if (config1 & (1 << 1))
-			mips_cpu.options |= MIPS_CPU_EJTAG;
-		if (config1 & 1)
-			mips_cpu.options |= MIPS_CPU_FPU;
-		mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT;
-	}
-#endif
-	mips_cpu.processor_id = read_32bit_cp0_register(CP0_PRID);
-	switch (mips_cpu.processor_id & 0xff0000) {
-	case PRID_COMP_LEGACY:
-		switch (mips_cpu.processor_id & 0xff00) {
-		case PRID_IMP_R2000:
-			mips_cpu.cputype = CPU_R2000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_I;
-			mips_cpu.options = MIPS_CPU_TLB;
-			mips_cpu.tlbsize = 64;
-			break;
-		case PRID_IMP_R3000:
-			if ((mips_cpu.processor_id & 0xff) == PRID_REV_R3000A)
-				if (cpu_has_confreg())
-					mips_cpu.cputype = CPU_R3081E;
-				else
-					mips_cpu.cputype = CPU_R3000A;
-			else
-				mips_cpu.cputype = CPU_R3000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_I;
-			mips_cpu.options = MIPS_CPU_TLB;
-			mips_cpu.tlbsize = 64;
-			break;
-		case PRID_IMP_R4000:
-			if ((mips_cpu.processor_id & 0xff) == PRID_REV_R4400)
-				mips_cpu.cputype = CPU_R4400SC;
-			else
-				mips_cpu.cputype = CPU_R4000SC;
-			mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR | MIPS_CPU_WATCH |
-			                   MIPS_CPU_VCE;
-			mips_cpu.tlbsize = 48;
-			break;
-                case PRID_IMP_VR41XX:
-                        mips_cpu.cputype = CPU_VR41XX;
-                        mips_cpu.isa_level = MIPS_CPU_ISA_III;
-                        mips_cpu.options = R4K_OPTS;
-                        mips_cpu.tlbsize = 32;
-                        break;
-		case PRID_IMP_R4300:
-			mips_cpu.cputype = CPU_R4300;
-			mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR;
-			mips_cpu.tlbsize = 32;
-			break;
-		case PRID_IMP_R4600:
-			mips_cpu.cputype = CPU_R4600;
-			mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
-			mips_cpu.tlbsize = 48;
-			break;
-		#if 0
- 		case PRID_IMP_R4650:
-			/*
-			 * This processor doesn't have an MMU, so it's not
-			 * "real easy" to run Linux on it. It is left purely
-			 * for documentation.  Commented out because it shares
-			 * it's c0_prid id number with the TX3900.
-			 */
-	 		mips_cpu.cputype = CPU_R4650;
-		 	mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
-		        mips_cpu.tlbsize = 48;
-			break;
-		#endif
-		case PRID_IMP_TX39:
-			mips_cpu.isa_level = MIPS_CPU_ISA_I;
-			mips_cpu.options = MIPS_CPU_TLB;
-
-			if ((mips_cpu.processor_id & 0xf0) ==
-			    (PRID_REV_TX3927 & 0xf0)) {
-				mips_cpu.cputype = CPU_TX3927;
-				mips_cpu.tlbsize = 64;
-				mips_cpu.icache.ways = 2;
-				mips_cpu.dcache.ways = 2;
-			} else {
-				switch (mips_cpu.processor_id & 0xff) {
-				case PRID_REV_TX3912:
-					mips_cpu.cputype = CPU_TX3912;
-					mips_cpu.tlbsize = 32;
-					break;
-				case PRID_REV_TX3922:
-					mips_cpu.cputype = CPU_TX3922;
-					mips_cpu.tlbsize = 64;
-					break;
-				default:
-					mips_cpu.cputype = CPU_UNKNOWN;
-					break;
-				}
-			}
-			break;
-		case PRID_IMP_R4700:
-			mips_cpu.cputype = CPU_R4700;
-			mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR;
-			mips_cpu.tlbsize = 48;
-			break;
-		case PRID_IMP_TX49:
-			mips_cpu.cputype = CPU_TX49XX;
-			mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR;
-			mips_cpu.tlbsize = 48;
-			mips_cpu.icache.ways = 4;
-			mips_cpu.dcache.ways = 4;
-			break;
-		case PRID_IMP_R5000:
-			mips_cpu.cputype = CPU_R5000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV; 
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR;
-			mips_cpu.tlbsize = 48;
-			break;
-		case PRID_IMP_R5432:
-			mips_cpu.cputype = CPU_R5432;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV; 
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR | MIPS_CPU_WATCH;
-			mips_cpu.tlbsize = 48;
-			break;
-		case PRID_IMP_R5500:
-			mips_cpu.cputype = CPU_R5500;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV; 
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR | MIPS_CPU_WATCH;
-			mips_cpu.tlbsize = 48;
-			break;
-		case PRID_IMP_NEVADA:
-			mips_cpu.cputype = CPU_NEVADA;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV; 
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR | MIPS_CPU_DIVEC;
-			mips_cpu.tlbsize = 48;
-			mips_cpu.icache.ways = 2;
-			mips_cpu.dcache.ways = 2;
-			break;
-		case PRID_IMP_R6000:
-			mips_cpu.cputype = CPU_R6000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_II;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU;
-			mips_cpu.tlbsize = 32;
-			break;
-		case PRID_IMP_R6000A:
-			mips_cpu.cputype = CPU_R6000A;
-			mips_cpu.isa_level = MIPS_CPU_ISA_II;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU;
-			mips_cpu.tlbsize = 32;
-			break;
-		case PRID_IMP_RM7000:
-			mips_cpu.cputype = CPU_RM7000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR;
-			/*
-			 * Undocumented RM7000:  Bit 29 in the info register of
-			 * the RM7000 v2.0 indicates if the TLB has 48 or 64
-			 * entries.
-			 *
-			 * 29      1 =>    64 entry JTLB
-			 *         0 =>    48 entry JTLB
-			 */
-			mips_cpu.tlbsize = (get_info() & (1 << 29)) ? 64 : 48;
-			break;
-		case PRID_IMP_R8000:
-			mips_cpu.cputype = CPU_R8000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
-				           MIPS_CPU_FPU | MIPS_CPU_32FPR;
-			mips_cpu.tlbsize = 384;      /* has wierd TLB: 3-way x 128 */
-			break;
-		case PRID_IMP_R10000:
-			mips_cpu.cputype = CPU_R10000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | 
-				           MIPS_CPU_FPU | MIPS_CPU_32FPR | 
-				           MIPS_CPU_COUNTER | MIPS_CPU_WATCH;
-			mips_cpu.tlbsize = 64;
-			break;
-		case PRID_IMP_R12000:
-			mips_cpu.cputype = CPU_R12000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | 
-				           MIPS_CPU_FPU | MIPS_CPU_32FPR | 
-				           MIPS_CPU_COUNTER | MIPS_CPU_WATCH;
-			mips_cpu.tlbsize = 64;
-			break;
-		default:
-			mips_cpu.cputype = CPU_UNKNOWN;
-			break;
-		}
-		break;
-#ifdef CONFIG_CPU_MIPS32
-	case PRID_COMP_MIPS:
-		switch (mips_cpu.processor_id & 0xff00) {
-		case PRID_IMP_4KC:
-			mips_cpu.cputype = CPU_4KC;
-			break;
-		case PRID_IMP_4KEC:
-			mips_cpu.cputype = CPU_4KEC;
-			break;
-		case PRID_IMP_4KSC:
-			mips_cpu.cputype = CPU_4KSC;
-			break;
-		case PRID_IMP_5KC:
-			mips_cpu.cputype = CPU_5KC;
-			mips_cpu.isa_level = MIPS_CPU_ISA_M64;
-			break;
-		case PRID_IMP_20KC:
-			mips_cpu.cputype = CPU_20KC;
-			mips_cpu.isa_level = MIPS_CPU_ISA_M64;
-		default:
-			mips_cpu.cputype = CPU_UNKNOWN;
-			break;
-		}		
-		break;
-	case PRID_COMP_ALCHEMY:
-		switch (mips_cpu.processor_id & 0xff00) {
-		case PRID_IMP_AU1_REV1:
-		case PRID_IMP_AU1_REV2:
-			if (mips_cpu.processor_id & 0xff000000)
-				mips_cpu.cputype = CPU_AU1500;
-			else
-				mips_cpu.cputype = CPU_AU1000;
-			break;
-		default:
-			mips_cpu.cputype = CPU_UNKNOWN;
-			break;
-		}
-		break;
-#endif /* CONFIG_CPU_MIPS32 */
-	case PRID_COMP_SIBYTE:
-		switch (mips_cpu.processor_id & 0xff00) {
-		case PRID_IMP_SB1:
-			mips_cpu.cputype = CPU_SB1;
-			mips_cpu.isa_level = MIPS_CPU_ISA_M64;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
-			                   MIPS_CPU_COUNTER | MIPS_CPU_DIVEC |
-			                   MIPS_CPU_MCHECK;
-#ifndef CONFIG_SB1_PASS_1_WORKAROUNDS
-			/* FPU in pass1 is known to have issues. */
-			mips_cpu.options |= MIPS_CPU_FPU;
-#endif
-			break;
-		default:
-			mips_cpu.cputype = CPU_UNKNOWN;
-			break;
-		}
-		break;
-	default:
-		mips_cpu.cputype = CPU_UNKNOWN;
-	}
-	if (mips_cpu.options & MIPS_CPU_FPU)
-		mips_cpu.fpu_id = cpu_get_fpu_id();
-}
-
-static inline void cpu_report(void)
-{
-	printk("CPU revision is: %08x\n", mips_cpu.processor_id);
-	if (mips_cpu.options & MIPS_CPU_FPU)
-		printk("FPU revision is: %08x\n", mips_cpu.fpu_id);
-}
-
 asmlinkage void __init init_arch(int argc, char **argv, char **envp,
 	int *prom_vec)
 {
@@ -547,7 +172,7 @@
 	int i;
 
 	for (i = 0; i < boot_mem_map.nr_map; i++) {
-		printk(" memory: %08Lx @ %08Lx ",
+		printk(" memory: %016Lx @ %016Lx ",
 			(unsigned long long) boot_mem_map.map[i].size,
 			(unsigned long long) boot_mem_map.map[i].addr);
 		switch (boot_mem_map.map[i].type) {
@@ -745,6 +370,9 @@
 #ifdef CONFIG_SIBYTE_SWARM
 	swarm_setup();
 #endif
+#ifdef CONFIG_MIPS_MALTA
+	malta_setup();
+#endif
 
 	strncpy(command_line, arcs_cmdline, CL_SIZE);
 	memcpy(saved_command_line, command_line, CL_SIZE);
@@ -759,25 +387,6 @@
 	paging_init();
 }
 
-void r3081_wait(void) 
-{
-	unsigned long cfg = read_32bit_cp0_register(CP0_CONF);
-	write_32bit_cp0_register(CP0_CONF, cfg|CONF_HALT);
-}
-
-void r39xx_wait(void)
-{
-	unsigned long cfg = read_32bit_cp0_register(CP0_CONF);
-	write_32bit_cp0_register(CP0_CONF, cfg|TX39_CONF_HALT);
-}
-
-void r4k_wait(void)
-{
-	__asm__(".set\tmips3\n\t"
-		"wait\n\t"
-		".set\tmips0");
-}
-
 int __init fpu_disable(char *s)
 {
 	mips_cpu.options &= ~MIPS_CPU_FPU;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/signal.c linux-2.4.20/arch/mips64/kernel/signal.c
--- linux-2.4.19/arch/mips64/kernel/signal.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/signal.c	2002-10-29 11:18:35.000000000 +0000
@@ -32,8 +32,8 @@
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
 extern asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
-extern asmlinkage int save_fp_context(struct sigcontext *sc);
-extern asmlinkage int restore_fp_context(struct sigcontext *sc);
+extern asmlinkage int (*save_fp_context)(struct sigcontext *sc);
+extern asmlinkage int (*restore_fp_context)(struct sigcontext *sc);
 
 extern asmlinkage void syscall_trace(void);
 
@@ -72,35 +72,6 @@
 	}
 }
 
-static inline int store_fp_context(struct sigcontext *sc)
-{
-	unsigned int fcr0;
-	int err = 0;
-
-	err |= __copy_to_user(&sc->sc_fpregs[0], 
-		&current->thread.fpu.hard.fp_regs[0], NUM_FPU_REGS * 
-						sizeof(unsigned long));
-	err |= __copy_to_user(&sc->sc_fpc_csr, &current->thread.fpu.hard.control,
-						sizeof(unsigned int));
-	__asm__ __volatile__("cfc1 %0, $0\n\t" : "=r" (fcr0));
-	err |= __copy_to_user(&sc->sc_fpc_eir, &fcr0, sizeof(unsigned int));
-
-	return err;
-}
-
-static inline int refill_fp_context(struct sigcontext *sc)
-{
-	int err = 0;
-
-	if (verify_area(VERIFY_READ, sc, sizeof(*sc)))
-		return -EFAULT;
-	err |= __copy_from_user(&current->thread.fpu.hard.fp_regs[0], 
-			&sc->sc_fpregs[0], NUM_FPU_REGS * sizeof(unsigned long));
-	err |= __copy_from_user(&current->thread.fpu.hard.control, &sc->sc_fpc_csr,
-							sizeof(unsigned int));
-	return err;
-}
-
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
@@ -165,7 +136,7 @@
 	}
 }
 
-asmlinkage int 
+asmlinkage int
 sys_sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
 {
 	struct k_sigaction new_ka, old_ka;
@@ -214,6 +185,54 @@
 	return do_sigaltstack(uss, uoss, usp);
 }
 
+static inline int restore_thread_fp_context(struct sigcontext *sc)
+{
+     u64 *pfreg = &current->thread.fpu.soft.regs[0];
+     int err = 0;
+
+     /*
+      * Copy all 32 64-bit values.
+      */
+
+#define restore_fpr(i)                          \
+     do { err |= __get_user(pfreg[i], &sc->sc_fpregs[i]); } while(0)
+
+     restore_fpr( 0); restore_fpr( 1); restore_fpr( 2); restore_fpr( 3);
+     restore_fpr( 4); restore_fpr( 5); restore_fpr( 6); restore_fpr( 7);
+     restore_fpr( 8); restore_fpr( 9); restore_fpr(10); restore_fpr(11);
+     restore_fpr(12); restore_fpr(13); restore_fpr(14); restore_fpr(15);
+     restore_fpr(16); restore_fpr(17); restore_fpr(18); restore_fpr(19);
+     restore_fpr(20); restore_fpr(21); restore_fpr(22); restore_fpr(23);
+     restore_fpr(24); restore_fpr(25); restore_fpr(26); restore_fpr(27);
+     restore_fpr(28); restore_fpr(29); restore_fpr(30); restore_fpr(31);
+
+     err |= __get_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr);
+
+     return err;
+}
+
+static inline int save_thread_fp_context(struct sigcontext *sc)
+{
+     u64 *pfreg = &current->thread.fpu.soft.regs[0];
+     int err = 0;
+
+#define save_fpr(i)                                     \
+     do { err |= __put_user(pfreg[i], &sc->sc_fpregs[i]); } while(0)
+
+     save_fpr( 0); save_fpr( 1); save_fpr( 2); save_fpr( 3);
+     save_fpr( 4); save_fpr( 5); save_fpr( 6); save_fpr( 7);
+     save_fpr( 8); save_fpr( 9); save_fpr(10); save_fpr(11);
+     save_fpr(12); save_fpr(13); save_fpr(14); save_fpr(15);
+     save_fpr(16); save_fpr(17); save_fpr(18); save_fpr(19);
+     save_fpr(20); save_fpr(21); save_fpr(22); save_fpr(23);
+     save_fpr(24); save_fpr(25); save_fpr(26); save_fpr(27);
+     save_fpr(28); save_fpr(29); save_fpr(30); save_fpr(31);
+
+     err |= __put_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr);
+
+     return err;
+}
+
 asmlinkage int
 restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
 {
@@ -241,15 +260,24 @@
 #undef restore_gp_reg
 
 	err |= __get_user(owned_fp, &sc->sc_ownedfp);
+	err |= __get_user(current->used_math, &sc->sc_used_math);
+
 	if (owned_fp) {
-		if (IS_FPU_OWNER()) {
-			CLEAR_FPU_OWNER();
-			regs->cp0_status &= ~ST0_CU1;
-		}
-		current->used_math = 1;
-		err |= refill_fp_context(sc);
+		err |= restore_fp_context(sc);
+		goto out;
+	}
+
+	if (IS_FPU_OWNER()) {
+		/* Signal handler acquired FPU - give it back */
+		CLEAR_FPU_OWNER();
+		regs->cp0_status &= ~ST0_CU1;
+	}
+	if (current->used_math) {
+		/* Undo possible contamination of thread state */
+		err |= restore_thread_fp_context(sc);
 	}
 
+out:
 	return err;
 }
 
@@ -347,9 +375,11 @@
 static int inline setup_sigcontext(struct pt_regs *regs,
 				   struct sigcontext *sc)
 {
+	int owned_fp;
 	int err = 0;
 
 	err |= __put_user(regs->cp0_epc, &sc->sc_pc);
+	err |= __put_user(regs->cp0_status, &sc->sc_status);
 
 #define save_gp_reg(i) do {						\
 	err |= __put_user(regs->regs[i], &sc->sc_regs[i]);		\
@@ -370,20 +400,27 @@
 	err |= __put_user(regs->cp0_cause, &sc->sc_cause);
 	err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr);
 
-	if (current->used_math) {	/* fp is active.  */
-		if (IS_FPU_OWNER()) {
-			lazy_fpu_switch(current, 0);
-			CLEAR_FPU_OWNER();
-			regs->cp0_status &= ~ST0_CU1;
-		}
-		err |= __put_user(1, &sc->sc_ownedfp);
-		err |= store_fp_context(sc);
-		current->used_math = 0;
-	} else {
-		err |= __put_user(0, &sc->sc_ownedfp);
+	owned_fp = IS_FPU_OWNER();
+	err |= __put_user(owned_fp, &sc->sc_ownedfp);
+	err |= __put_user(current->used_math, &sc->sc_used_math);
+
+	if (!current->used_math)
+		goto out;
+
+	/* There exists FP thread state that may be trashed by signal */
+	if (owned_fp) {
+		/* fp is active.  Save context from FPU */
+		err |= save_fp_context(sc);
+		goto out;
 	}
-	err |= __put_user(regs->cp0_status, &sc->sc_status);
 
+	/*
+	 * Someone else has FPU.
+	 * Copy Thread context into signal context
+	 */
+	err |= save_thread_fp_context(sc);
+
+out:
 	return err;
 }
 
@@ -398,6 +435,13 @@
 	/* Default to using normal stack */
 	sp = regs->regs[29];
 
+	/*
+ 	 * FPU emulator may have it's own trampoline active just
+ 	 * above the user stack, 16-bytes before the next lowest
+ 	 * 16 byte boundary.  Try to avoid trashing it.
+ 	 */
+ 	sp -= 32;
+
 	/* This is the X/Open sanctioned signal stack switching.  */
 	if ((ka->sa.sa_flags & SA_ONSTACK) && ! on_sig_stack(sp))
 		sp = current->sas_ss_sp + current->sas_ss_size;
@@ -456,8 +500,9 @@
 	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
 
 #if DEBUG_SIG
-	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%p ra=0x%p\n",
-	       current->comm, current->pid, frame, regs->cp0_epc, frame->code);
+	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
+	       current->comm, current->pid,
+	       frame, regs->cp0_epc, frame->sf_code);
 #endif
         return;
 
@@ -532,8 +577,9 @@
 	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
 
 #if DEBUG_SIG
-	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%p ra=0x%p\n",
-	       current->comm, current->pid, frame, regs->cp0_epc, frame->code);
+	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
+	       current->comm, current->pid,
+	       frame, regs->cp0_epc, frame->rs_code);
 #endif
 	return;
 
@@ -661,7 +707,7 @@
 				continue;
 
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/signal32.c linux-2.4.20/arch/mips64/kernel/signal32.c
--- linux-2.4.19/arch/mips64/kernel/signal32.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/signal32.c	2002-10-29 11:18:48.000000000 +0000
@@ -31,8 +31,8 @@
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
 extern asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs);
-extern asmlinkage int save_fp_context(struct sigcontext *sc);
-extern asmlinkage int restore_fp_context(struct sigcontext *sc);
+extern asmlinkage int (*save_fp_context)(struct sigcontext *sc);
+extern asmlinkage int (*restore_fp_context)(struct sigcontext *sc);
 
 extern asmlinkage void syscall_trace(void);
 
@@ -63,38 +63,6 @@
 	int ss_flags;
 } stack32_t;
 
-
-static inline int store_fp_context(struct sigcontext *sc)
-{
-	unsigned int fcr0;
-	int err = 0;
-
-	err |= __copy_to_user(&sc->sc_fpregs[0],
-			      &current->thread.fpu.hard.fp_regs[0],
-			      NUM_FPU_REGS * sizeof(unsigned long));
-	err |= __copy_to_user(&sc->sc_fpc_csr,
-			      &current->thread.fpu.hard.control,
-			      sizeof(unsigned int));
-	__asm__ __volatile__("cfc1 %0, $0\n\t" : "=r" (fcr0));
-	err |= __copy_to_user(&sc->sc_fpc_eir, &fcr0, sizeof(unsigned int));
-
-	return err;
-}
-
-static inline int refill_fp_context(struct sigcontext *sc)
-{
-	int err = 0;
-
-	if (verify_area(VERIFY_READ, sc, sizeof(*sc)))
-		return -EFAULT;
-	err |= __copy_from_user(&current->thread.fpu.hard.fp_regs[0],
-				&sc->sc_fpregs[0],
-				NUM_FPU_REGS * sizeof(unsigned long));
-	err |= __copy_from_user(&current->thread.fpu.hard.control,
-				&sc->sc_fpc_csr, sizeof(unsigned int));
-	return err;
-}
-
 extern void __put_sigset_unknown_nsig(void);
 extern void __get_sigset_unknown_nsig(void);
 
@@ -289,6 +257,54 @@
 	return ret;
 }
 
+static inline int restore_thread_fp_context(struct sigcontext *sc)
+{
+	u64 *pfreg = &current->thread.fpu.soft.regs[0];
+	int err = 0;
+
+	/*
+	 * Copy all 32 64-bit values.
+	 */
+
+#define restore_fpr(i) 						\
+	do { err |= __get_user(pfreg[i], &sc->sc_fpregs[i]); } while(0)
+
+	restore_fpr( 0); restore_fpr( 1); restore_fpr( 2); restore_fpr( 3);
+	restore_fpr( 4); restore_fpr( 5); restore_fpr( 6); restore_fpr( 7);
+	restore_fpr( 8); restore_fpr( 9); restore_fpr(10); restore_fpr(11);
+	restore_fpr(12); restore_fpr(13); restore_fpr(14); restore_fpr(15);
+	restore_fpr(16); restore_fpr(17); restore_fpr(18); restore_fpr(19);
+	restore_fpr(20); restore_fpr(21); restore_fpr(22); restore_fpr(23);
+	restore_fpr(24); restore_fpr(25); restore_fpr(26); restore_fpr(27);
+	restore_fpr(28); restore_fpr(29); restore_fpr(30); restore_fpr(31);
+
+	err |= __get_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr);
+
+	return err;
+}
+
+static inline int save_thread_fp_context(struct sigcontext *sc)
+{
+	u64 *pfreg = &current->thread.fpu.soft.regs[0];
+	int err = 0;
+
+#define save_fpr(i) 							\
+	do { err |= __put_user(pfreg[i], &sc->sc_fpregs[i]); } while(0)
+
+	save_fpr( 0); save_fpr( 1); save_fpr( 2); save_fpr( 3);
+	save_fpr( 4); save_fpr( 5); save_fpr( 6); save_fpr( 7);
+	save_fpr( 8); save_fpr( 9); save_fpr(10); save_fpr(11);
+	save_fpr(12); save_fpr(13); save_fpr(14); save_fpr(15);
+	save_fpr(16); save_fpr(17); save_fpr(18); save_fpr(19);
+	save_fpr(20); save_fpr(21); save_fpr(22); save_fpr(23);
+	save_fpr(24); save_fpr(25); save_fpr(26); save_fpr(27);
+	save_fpr(28); save_fpr(29); save_fpr(30); save_fpr(31);
+
+	err |= __put_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr);
+
+	return err;
+}
+
 static asmlinkage int restore_sigcontext(struct pt_regs *regs,
 					 struct sigcontext *sc)
 {
@@ -316,15 +332,24 @@
 #undef restore_gp_reg
 
 	err |= __get_user(owned_fp, &sc->sc_ownedfp);
+	err |= __get_user(current->used_math, &sc->sc_used_math);
+
 	if (owned_fp) {
-		if (IS_FPU_OWNER()) {
-			CLEAR_FPU_OWNER();
-			regs->cp0_status &= ~ST0_CU1;
-		}
-		current->used_math = 1;
-		err |= refill_fp_context(sc);
+		err |= restore_fp_context(sc);
+		goto out;
+	}
+
+	if (IS_FPU_OWNER()) {
+		/* Signal handler acquired FPU - give it back */
+		CLEAR_FPU_OWNER();
+		regs->cp0_status &= ~ST0_CU1;
+	}
+	if (current->used_math) {
+		/* Undo possible contamination of thread state */
+		err |= restore_thread_fp_context(sc);
 	}
 
+out:
 	return err;
 }
 
@@ -335,13 +360,55 @@
 	sigset_t sf_mask;
 };
 
-struct rt_sigframe {
+struct rt_sigframe32 {
 	u32 rs_ass[4];			/* argument save space for o32 */
 	u32 rs_code[2];			/* signal trampoline */
-	struct siginfo rs_info;
+	struct siginfo32 rs_info;
 	struct ucontext rs_uc;
 };
 
+static int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from)
+{
+	int err;
+
+	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32)))
+		return -EFAULT;
+
+	/* If you change siginfo_t structure, please be sure
+	   this code is fixed accordingly.
+	   It should never copy any pad contained in the structure
+	   to avoid security leaks, but must copy the generic
+	   3 ints plus the relevant union member.
+	   This routine must convert siginfo from 64bit to 32bit as well
+	   at the same time.  */
+	err = __put_user(from->si_signo, &to->si_signo);
+	err |= __put_user(from->si_errno, &to->si_errno);
+	err |= __put_user((short)from->si_code, &to->si_code);
+	if (from->si_code < 0)
+		err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
+	else {
+		switch (from->si_code >> 16) {
+		case __SI_CHLD >> 16:
+			err |= __put_user(from->si_utime, &to->si_utime);
+			err |= __put_user(from->si_stime, &to->si_stime);
+			err |= __put_user(from->si_status, &to->si_status);
+		default:
+			err |= __put_user(from->si_pid, &to->si_pid);
+			err |= __put_user(from->si_uid, &to->si_uid);
+			break;
+		case __SI_FAULT >> 16:
+			err |= __put_user((long)from->si_addr, &to->si_addr);
+			break;
+		case __SI_POLL >> 16:
+			err |= __put_user(from->si_band, &to->si_band);
+			err |= __put_user(from->si_fd, &to->si_fd);
+			break;
+		/* case __SI_RT: This is not generated by the kernel as of now.  */
+		}
+	}
+	return err;
+}
+
 asmlinkage void sys32_sigreturn(abi64_no_regargs, struct pt_regs regs)
 {
 	struct sigframe *frame;
@@ -369,7 +436,7 @@
 		syscall_trace();
 	__asm__ __volatile__(
 		"move\t$29, %0\n\t"
-		"j\to32_ret_from_sys_call"
+		"j\tret_from_sys_call"
 		:/* no outputs */
 		:"r" (&regs));
 	/* Unreached */
@@ -380,11 +447,11 @@
 
 asmlinkage void sys32_rt_sigreturn(abi64_no_regargs, struct pt_regs regs)
 {
-	struct rt_sigframe *frame;
+	struct rt_sigframe32 *frame;
 	sigset_t set;
 	stack_t st;
 
-	frame = (struct rt_sigframe *) regs.regs[29];
+	frame = (struct rt_sigframe32 *) regs.regs[29];
 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
@@ -410,7 +477,7 @@
 	 */
 	__asm__ __volatile__(
 		"move\t$29, %0\n\t"
-		"j\to32_ret_from_sys_call"
+		"j\tret_from_sys_call"
 		:/* no outputs */
 		:"r" (&regs));
 	/* Unreached */
@@ -422,9 +489,11 @@
 static int inline setup_sigcontext(struct pt_regs *regs,
 				   struct sigcontext *sc)
 {
+	int owned_fp;
 	int err = 0;
 
 	err |= __put_user(regs->cp0_epc, &sc->sc_pc);
+	err |= __put_user(regs->cp0_status, &sc->sc_status);
 
 #define save_gp_reg(i) {						\
 	err |= __put_user(regs->regs[i], &sc->sc_regs[i]);		\
@@ -445,20 +514,27 @@
 	err |= __put_user(regs->cp0_cause, &sc->sc_cause);
 	err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr);
 
-	if (current->used_math) {	/* fp is active.  */
-		if (IS_FPU_OWNER()) {
-			lazy_fpu_switch(current, 0);
-			CLEAR_FPU_OWNER();
-			regs->cp0_status &= ~ST0_CU1;
-		}
-		err |= __put_user(1, &sc->sc_ownedfp);
-		err |= store_fp_context(sc);
-		current->used_math = 0;
-	} else {
-		err |= __put_user(0, &sc->sc_ownedfp);
+	owned_fp = IS_FPU_OWNER();
+	err |= __put_user(owned_fp, &sc->sc_ownedfp);
+	err |= __put_user(current->used_math, &sc->sc_used_math);
+
+	if (!current->used_math)
+		goto out;
+
+	/* There exists FP thread state that may be trashed by signal */
+	if (owned_fp) {
+		/* fp is active.  Save context from FPU */
+		err |= save_fp_context(sc);
+		goto out;
 	}
-	err |= __put_user(regs->cp0_status, &sc->sc_status);
 
+	/*
+	 * Someone else has FPU.
+	 * Copy Thread context into signal context
+	 */
+	err |= save_thread_fp_context(sc);
+
+out:
 	return err;
 }
 
@@ -473,6 +549,13 @@
 	/* Default to using normal stack */
 	sp = regs->regs[29];
 
+	/*
+ 	 * FPU emulator may have it's own trampoline active just
+ 	 * above the user stack, 16-bytes before the next lowest
+ 	 * 16 byte boundary.  Try to avoid trashing it.
+ 	 */
+ 	sp -= 32;
+
 	/* This is the X/Open sanctioned signal stack switching.  */
 	if ((ka->sa.sa_flags & SA_ONSTACK) && ! on_sig_stack(sp))
 		sp = current->sas_ss_sp + current->sas_ss_size;
@@ -547,7 +630,7 @@
 				  struct pt_regs *regs, int signr,
 				  sigset_t *set, siginfo_t *info)
 {
-	struct rt_sigframe *frame;
+	struct rt_sigframe32 *frame;
 	int err = 0;
 
 	frame = get_sigframe(ka, regs, sizeof(*frame));
@@ -572,8 +655,8 @@
 		flush_cache_sigtramp((unsigned long) frame->rs_code);
 	}
 
-	/* Create siginfo.  */
-	err |= __copy_to_user(&frame->rs_info, info, sizeof(*info));
+	/* Convert (siginfo_t -> siginfo_t32) and copy to user. */
+	err |= copy_siginfo_to_user32(&frame->rs_info, info);
 
 	/* Create the ucontext.  */
 	err |= __put_user(0, &frame->rs_uc.uc_flags);
@@ -598,7 +681,7 @@
 	 *   a2 = pointer to ucontext
 	 *
 	 * $25 and c0_epc point to the signal handler, $29 points to
-	 * the struct rt_sigframe.
+	 * the struct rt_sigframe32.
 	 */
 	regs->regs[ 4] = signr;
 	regs->regs[ 5] = (unsigned long) &frame->rs_info;
@@ -784,7 +867,7 @@
 extern asmlinkage int sys_sigprocmask(int how, old_sigset_t *set,
 						old_sigset_t *oset);
 
-asmlinkage int sys32_sigprocmask(int how, old_sigset_t32 *set, 
+asmlinkage int sys32_sigprocmask(int how, old_sigset_t32 *set,
 				 old_sigset_t32 *oset)
 {
 	old_sigset_t s;
@@ -878,7 +961,7 @@
 
 	if (set && get_sigset(&new_set, set))
 		return -EFAULT;
-	
+
 	set_fs (KERNEL_DS);
 	ret = sys_rt_sigprocmask(how, set ? &new_set : NULL,
 				 oset ? &old_set : NULL, sigsetsize);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/smp.c linux-2.4.20/arch/mips64/kernel/smp.c
--- linux-2.4.19/arch/mips64/kernel/smp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/smp.c	2002-10-29 11:18:34.000000000 +0000
@@ -1,13 +1,25 @@
 /*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
+ * 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.
  *
  * Copyright (C) 2000, 2001 Kanoj Sarcar
  * Copyright (C) 2000, 2001 Ralf Baechle
  * Copyright (C) 2000, 2001 Silicon Graphics, Inc.
+ * Copyright (C) 2000, 2001 Broadcom Corporation
  */
 #include <linux/config.h>
+#include <linux/cache.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -17,7 +29,6 @@
 #include <linux/time.h>
 #include <linux/timex.h>
 #include <linux/sched.h>
-#include <linux/cache.h>
 
 #include <asm/atomic.h>
 #include <asm/cpu.h>
@@ -26,14 +37,13 @@
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 #include <asm/mmu_context.h>
-#include <asm/irq.h>
+#include <asm/smp.h>
 
 /* The 'big kernel lock' */
 spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 int smp_threads_ready;	/* Not used */
 atomic_t smp_commenced = ATOMIC_INIT(0);
 struct cpuinfo_mips cpu_data[NR_CPUS];
-void (*volatile smp_cpu0_finalize)(void);
 
 // static atomic_t cpus_booted = ATOMIC_INIT(0);
 atomic_t cpus_booted = ATOMIC_INIT(0);
@@ -44,8 +54,36 @@
 int __cpu_logical_map[NR_CPUS];
 cycles_t cacheflush_time;
 
-// static void smp_tune_scheduling (void)
-void smp_tune_scheduling (void)
+/* These are defined by the board-specific code. */
+
+/*
+ * Cause the function described by call_data to be executed on the passed
+ * cpu.  When the function has finished, increment the finished field of
+ * call_data.
+ */
+void core_send_ipi(int cpu, unsigned int action);
+
+/*
+ * Clear all undefined state in the cpu, set up sp and gp to the passed
+ * values, and kick the cpu into smp_bootstrap();
+ */
+void prom_boot_secondary(int cpu, unsigned long sp, unsigned long gp);
+
+/*
+ *  After we've done initial boot, this function is called to allow the
+ *  board code to clean up state, if needed
+ */
+void prom_init_secondary(void);
+
+/*
+ * Do whatever setup needs to be done for SMP at the board level.  Return
+ * the number of cpus in the system, including this one
+ */
+int prom_setup_smp(void);
+
+void prom_smp_finish(void);
+
+static void smp_tune_scheduling(void)
 {
 }
 
@@ -100,12 +138,6 @@
 	core_send_ipi(cpu, SMP_RESCHEDULE_YOURSELF);
 }
 
-/* Not really SMP stuff ... */
-int setup_profiling_timer(unsigned int multiplier)
-{
-	return 0;
-}
-
 static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
 
 struct call_data_struct *call_data;
@@ -121,8 +153,7 @@
  * Does not return until remote CPUs are nearly ready to execute <func>
  * or are or have executed.
  */
-
-int smp_call_function (void (*func) (void *info), void *info, int retry, 
+int smp_call_function (void (*func) (void *info), void *info, int retry,
 								int wait)
 {
 	struct call_data_struct data;
@@ -188,21 +219,32 @@
 
 static void stop_this_cpu(void *dummy)
 {
-	int cpu = smp_processor_id();
-	if (cpu)
-		for (;;);		/* XXX Use halt like i386 */
-
-	/* XXXKW this isn't quite there yet */
-	while (!smp_cpu0_finalize) ;
-	smp_cpu0_finalize();
+	/*
+	 * Remove this CPU:
+	 */
+	clear_bit(smp_processor_id(), &cpu_online_map);
+	/* May need to service _machine_restart IPI */
+	__sti();
+	/* XXXKW wait if available? */
+	for (;;);
 }
 
 void smp_send_stop(void)
 {
 	smp_call_function(stop_this_cpu, NULL, 1, 0);
+	/*
+	 * Fix me: this prevents future IPIs, for example that would
+	 * cause a restart to happen on CPU0.
+	 */
 	smp_num_cpus = 1;
 }
 
+/* Not really SMP stuff ... */
+int setup_profiling_timer(unsigned int multiplier)
+{
+	return 0;
+}
+
 static void flush_tlb_all_ipi(void *info)
 {
 	local_flush_tlb_all();
@@ -220,11 +262,11 @@
 }
 
 /*
- * The following tlb flush calls are invoked when old translations are 
+ * The following tlb flush calls are invoked when old translations are
  * being torn down, or pte attributes are changing. For single threaded
  * address spaces, a new context is obtained on the current cpu, and tlb
  * context on other cpus are invalidated to force a new context allocation
- * at switch_mm time, should the mm ever be used on other cpus. For 
+ * at switch_mm time, should the mm ever be used on other cpus. For
  * multithreaded address spaces, intercpu interrupts have to be sent.
  * Another case where intercpu interrupts are required is when the target
  * mm might be active on another cpu (eg debuggers doing the flushes on
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/softfp.S linux-2.4.20/arch/mips64/kernel/softfp.S
--- linux-2.4.19/arch/mips64/kernel/softfp.S	2000-07-10 05:18:16.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/softfp.S	1970-01-01 00:00:00.000000000 +0000
@@ -1,666 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1998, 1999, 2000 by Ralf Baechle
- * Copyright (C) 1999, 2000 by Silicon Graphics, Inc.
- *
- * For now it's just a crude hack good enough to run certain fp programs like
- * Mozilla.
- * XXX: Handle MIPS II/III/IV/V enhancements, exceptions, ...
- */
-#include <asm/regdef.h>
-#include <asm/asm.h>
-
-#ifndef __KERNEL__
-#define printk printf
-#endif
-
-#define LOCK_KERNEL
-#define UNLOCK_KERNEL
-
-/*
- * This duplicates definitions from <linux/kernel.h>.
- */
-#define KERN_EMERG      "<0>"   /* system is unusable                   */
-#define KERN_ALERT      "<1>"   /* action must be taken immediately     */
-#define KERN_CRIT       "<2>"   /* critical conditions                  */
-#define KERN_ERR        "<3>"   /* error conditions                     */
-#define KERN_WARNING    "<4>"   /* warning conditions                   */
-#define KERN_NOTICE     "<5>"   /* normal but significant condition     */
-#define KERN_INFO       "<6>"   /* informational                        */
-#define KERN_DEBUG      "<7>"   /* debug-level messages                 */
-
-/*
- * This duplicates definitions from <asm/signal.h>
- */
-#define SIGILL           4      /* Illegal instruction (ANSI).  */
-
-/*
- * Definitions about the instruction format
- */
-#define fd_shift	6
-#define fr_shift	21
-#define fs_shift	11
-#define ft_shift	16
-
-/*
- * NaNs as use by the MIPS architecture
- */
-#define S_QNaN		0x7fbfffff
-#define D_QNaN		0x7ff7ffffffffffff
-#define W_QNaN		0x7fffffff
-#define L_QNaN		0x7fffffffffffffff
-
-/*
- * Checking for NaNs
- */
-#define S_is_QNaN(reg,res)						\
-	sll	res, reg, S_F_size - S_F_bits
-#define D_is_QNaN(reg1,reg2,res)					\
-	sll	res, reg1, (D_F_size - 32) - (D_F_bits - 32);		\
-	or	res, reg2
-
-/*
- * Checking for Denorms
- */
-#define S_is_Denorm(reg,res)						\
-	li	res, 1 << (S_F_bits - 1);				\
-	and	reg, res
-
-/*
- * Some constants that define the properties of single precission numbers.
- */
-#define S_M_prec	24
-#define S_E_max		127
-#define S_E_min		-126
-#define S_E_bias	127
-#define S_E_bits	8
-#define S_F_bits	23
-#define S_F_size	32
-
-/* Set temp0, if exponent of reg is S_E_max + 1.  */
-#define S_is_E_max(reg,temp0,temp1)					\
-	li	temp0, (S_E_max + 1 + S_E_bias) << S_F_bits;		\
-	and	temp1, temp0, reg;					\
-	seq	temp0, temp1			/* temp0 != 0 if NaN */
-
-/* Clear temp0, if exponent of reg is S_E_min - 1.  */
-#define S_is_E_min(reg,temp0)						\
-	li	temp0, (S_E_min - 1 + S_E_bias) << S_F_bits;		\
-	and	temp0, reg	/* temp0 == 0 if denorm or zero */
-
-/* Set temp0 if reg is a NaN assuming S_is_E_max is true  */
-#define S_get_F(reg,temp0)						\
-	li	temp0, (1 << S_F_bits) - 1;				\
-	and	temp0, reg			/* temp0 != 0 if NaN */
-
-/* Set res if fraction of reg is != 0.  */
-#define S_is_Inf(reg,res)						\
-	li	res, (1 << S_F_bits) - 1;				\
-	and	res, reg			/* temp0 == 0 if Inf */
-
-
-/*
- * Some constants that define the properties of double precission numbers.
- */
-#define D_M_prec	53
-#define D_E_max		1023
-#define D_E_min		-1022
-#define D_E_bias	1023
-#define D_E_bits	8
-#define D_F_bits	52
-#define D_F_size	64
-
-/* Set temp0, if exponent of reg1/reg2 is D_E_max.  */
-#define D_is_E_max(reg1,reg2,temp0,temp1)				\
-	li	temp0, (D_E_max + 1 + D_E_bias) << (D_F_bits - 32);	\
-	and	temp1, temp0, reg1;					\
-	seq	temp0, temp1			/* temp0 != 0 if NaN */
-
-/* Clear temp0, if exponent of reg is D_E_min.  */
-#define D_is_E_min(reg1,reg2,res)					\
-	li	res, (D_E_min + 1 + D_E_bias) << (D_F_bits - 32);	\
-	and	res, reg1	/* temp0 == 0 if NaN or zero */
-
-/* Set res if reg is a NaN assuming S_is_E_max is true  */
-#define D_get_F(reg1,reg2,res)						\
-	li	res, (1 << (D_F_bits - 32)) - 1;			\
-	and	res, reg1			/* temp0 != 0 if NaN */
-
-/* Set temp0 if reg1/reg2 is a NaN  */
-#define D_is_NAN(reg1,reg2,temp0,temp1)					\
-	li	temp0, (1 << (D_F_bits - 32) - 1;			\
-	and	temp0, reg1;						\
-	or	temp0, reg2;						\
-	sne	temp0, zero, temp0		/* temp0 != 0 if NaN */
-
-/* Set res if fraction of reg1/reg2 is != 0.  */
-#define D_is_Inf(reg1,reg2,res)						\
-	li	res, (1 << (D_F_bits - 32)) - 1;			\
-	and	res, reg1;						\
-	or	res, reg2			/* temp0 == 0 if Inf */
-
-/* Complain about yet unhandled instruction.  */
-#define BITCH(insn)							\
-insn:	LOCK_KERNEL;							\
-	la	a1, 8f;							\
-	TEXT(#insn);							\
-	la	a0, nosim;						\
-	jal	printk;							\
-	UNLOCK_KERNEL;							\
-	j	done
-
-	.data
-nosim: .asciz	KERN_DEBUG "Don't know how to simulate %s instruction\n"
-	.previous
-
-/*
- * When we come here, we've saved some of the integer registers and
- * reenabled interrupts.
- */
-LEAF(simfp)
-	.set	noreorder
-	.cpload	$25
-	.set	reorder
-
-	dsubu	sp, 16
-	.cprestore 20
-	sd	ra, 0(sp)
-
-	/* For now we assume that we get the opcode to simulate passed in as
-	   an argument.  */
-	move	ta0, a0
-
-	/*
-	 * First table lookup using insn[5:0]
-	 */
-	la	ta1, lowtab
-	andi	ta2, ta0, 0x3f
-	sll	ta2, ta2, 3
-	daddu	ta1, ta2
-	ld	ta1, (ta1)
-	jr	ta1
-	END(simfp)
-
-/*
- * We only decode the lower 3 of the 5 bit in the fmt field.  That way we
- * can keep the jump table significantly shorter.
- */
-#define FMT_switch(insn,opc,temp0,temp1)				\
-insn:	srl	temp0, opc, 18;						\
-	andi	temp0, 0x1c;						\
-	la	temp1, insn##.tab;					\
-	daddu	temp0, temp1;						\
-	ld	temp0, (temp0);						\
-	jr	temp0;							\
-									\
-	.data;								\
-insn##.tab:								\
-	.dword	insn##.s, insn##.d, unimp, unimp;			\
-	.dword	insn##.w, insn##.l, unimp, unimp;			\
-	.previous
-
-	BITCH(add)
-	BITCH(sub)
-	BITCH(mul)
-	BITCH(div)
-	BITCH(sqrt)
-	BITCH(abs)
-	BITCH(mov)
-	BITCH(neg)
-	BITCH(round.l)
-	BITCH(trunc.l)
-	BITCH(ceil.l)
-	BITCH(floor.l)
-	BITCH(round.w)
-	BITCH(trunc.w)
-	BITCH(ceil.w)
-	BITCH(floor.w)
-	BITCH(cvt.s)
-	BITCH(cvt.d)
-
-/* ------------------------------------------------------------------------ */
-
-FMT_switch(cvt.w,ta0,ta1,ta2)
-
-/* Convert a single fp to a fixed point integer.  */
-cvt.w.s:
-	srl	ta1, ta0, fs_shift	# Get source register
-	andi	ta1, 31
-	jal	s_get_fpreg
-
-	S_is_E_max(ta1,ta2,ta3)
-	beqz	ta2, 3f
-	/* Might be a NaN or Inf.  */
-	S_get_F(ta1,ta2)
-	beqz	ta2, 2f
-
-	/* It's a NaN.  IEEE says undefined.  */
-	/* Is it a QNaN?  Then the result is a QNaN as well.  */
-	S_is_QNaN(ta1,ta2)
-	bltz	ta2, 1f
-
-	/* XXX Ok, it's a SNaN.  Signal invalid exception, if enabled.
-	   For now we don't signal and supply a QNaN for result.  */
-
-1:	li	ta2, W_QNaN
-	srl	ta1, ta0, fd_shift	# Put result register
-	andi	ta1, 31
-	jal	s_put_fpreg
-	j	done
-2:
-
-	S_is_Inf(ta1,ta2)
-	bnez	ta2, 2f
-
-	/* It's +/- Inf.  Set register to +/- max. integer.  */
-	/* XXX Send invalid operation exception instead, if enabled.  */
-	srl	ta1, ta1, 31		# Extract sign bit
-	li	ta2, 0x7fffffff
-	addu	ta2, ta1
-
-	srl	ta1, ta0, fd_shift	# Put result register
-	andi	ta1, 31
-	jal	s_put_fpreg
-	j	done
-2:
-3:	
-
-	/* But then it might be a denorm or zero?  */
-	S_is_E_min(ta1,ta2)
-	bnez	ta2, 2f
-
-	/* Ok, it's a denorm or zero.  */
-	S_get_F(ta1,ta2)
-	beqz	ta2, 1f
-
-	/* It's a denorm.  */
-	/* XXX Should be signaling inexact exception, if enabled.  */
-	/* Fall through.  */
-1:
-	/* Yes, it is a denorm or zero.  Supply a zero as result.  */
-	move	ta2, zero
-	srl	ta1, ta0, fd_shift	# Put result register
-	andi	ta1, 31
-	jal	s_put_fpreg
-	j	done
-2:
-
-	/* XXX Ok, it's a normal number.  We don't handle that case yet.
-	   If we have fp hardware this case is unreached.  Add this for
-	   full fp simulation.  */
-
-	/* Done, return.  */
-	ld	ra, 0(sp)
-	daddu	sp, 16
-	jr	ra
-
-/* Convert a double fp to a fixed point integer.  */
-cvt.w.d:
-	srl	ta1, ta0, fs_shift	# Get source register
-	andi	ta1, 31
-	jal	d_get_fpreg
-
-	D_is_E_max(ta1,ta2,ta3,t0)
-	beqz	ta3, 3f
-
-	/* Might be a NaN or Inf.  */
-	D_get_F(ta1,ta2,ta3)
-	or	ta3, ta2
-	beqz	ta3, 2f
-
-	/* It's a NaN.  IEEE says undefined.  */
-	/* Is it a QNaN?  Then the result is a QNaN as well.  */
-	D_is_QNaN(ta1,ta2,ta3)
-	bltz	ta3, 1f
-
-	/* XXX Ok, it's a SNaN.  Signal invalid exception, if enabled.
-	   For now we don't signal and supply a QNaN for result.  */
-
-1:	li	ta2, W_QNaN
-	srl	ta1, ta0, fd_shift	# Put result register
-	andi	ta1, 31
-	jal	s_put_fpreg
-	j	done
-2:
-
-	D_is_Inf(ta1,ta2,ta3)
-	bnez	ta3, 2f
-
-	/* It's +/- Inf.  Set register to +/- max. integer.  */
-	/* XXX Send invalid operation exception instead, if enabled.  */
-	srl	ta1, ta1, 31		# Extract sign bit
-	li	ta2, 0x7fffffff
-	addu	ta2, ta1
-
-	srl	ta1, ta0, fd_shift	# Put result register
-	andi	ta1, 31
-	jal	s_put_fpreg
-	j	done
-2:
-3:	
-
-	/* But then it might be a denorm or zero?  */
-	D_is_E_min(ta1,ta2,ta3)
-	bnez	ta3, 2f
-
-	/* Ok, it's a denorm or zero.  */
-	D_get_F(ta1,ta2,ta3)
-	or	ta3, ta2
-	beqz	ta3, 1f
-
-	/* It's a denorm.  */
-	/* XXX Should be signaling inexact exception, if enabled.  */
-	/* Fall through.  */
-1:
-	/* Yes, it is a denorm or zero.  Supply a zero as result.  */
-	move	ta2, zero
-	srl	ta1, ta0, fd_shift	# Put result register
-	andi	ta1, 31
-	jal	s_put_fpreg
-	j	done
-2:
-
-	/* XXX Ok, it's a normal number.  We don't handle that case yet.
-	   If we have fp hardware this case is only reached if the value
-	   of the source register exceeds the range which is representable
-	   in a single precission register.  For now we kludge by returning
-	   +/- maxint and don't signal overflow. */
-
-	srl	ta1, ta1, 31		# Extract sign bit
-	li	ta2, 0x7fffffff
-	addu	ta2, ta1
-
-	srl	ta1, ta0, fd_shift	# Put result register
-	andi	ta1, 31
-	jal	s_put_fpreg
-
-	/* Done, return.  */
-	ld	ra, 0(sp)
-	daddu	sp, 16
-	jr	ra
-
-cvt.w.w = unimp				# undefined result
-cvt.w.l = unimp				# undefined result
-
-/* MIPS III extension, no need to handle for 32bit OS.  */
-cvt.l = unimp
-
-/* ------------------------------------------------------------------------ */
-
-	BITCH(c.f)
-	BITCH(c.un)
-	BITCH(c.eq)
-	BITCH(c.ueq)
-	BITCH(c.olt)
-	BITCH(c.ult)
-	BITCH(c.ole)
-	BITCH(c.ule)
-	BITCH(c.sf)
-	BITCH(c.ngle)
-	BITCH(c.seq)
-	BITCH(c.ngl)
-	BITCH(c.lt)
-	BITCH(c.nge)
-	BITCH(c.le)
-	BITCH(c.ngt)
-
-/* Get the single precission register which's number is in ta1.  */
-s_get_fpreg:
-	.set	noat
-	sll	ta1, 3
-	la	AT, 1f
-	daddu	AT, ta1
-	jr	AT
-	.set	at
-
-1:	mfc1	ta1, $0
-	jr	ra
-	mfc1	ta1, $1
-	jr	ra
-	mfc1	ta1, $2
-	jr	ra
-	mfc1	ta1, $3
-	jr	ra
-	mfc1	ta1, $4
-	jr	ra
-	mfc1	ta1, $5
-	jr	ra
-	mfc1	ta1, $6
-	jr	ra
-	mfc1	ta1, $7
-	jr	ra
-	mfc1	ta1, $8
-	jr	ra
-	mfc1	ta1, $9
-	jr	ra
-	mfc1	ta1, $10
-	jr	ra
-	mfc1	ta1, $11
-	jr	ra
-	mfc1	ta1, $12
-	jr	ra
-	mfc1	ta1, $13
-	jr	ra
-	mfc1	ta1, $14
-	jr	ra
-	mfc1	ta1, $15
-	jr	ra
-	mfc1	ta1, $16
-	jr	ra
-	mfc1	ta1, $17
-	jr	ra
-	mfc1	ta1, $18
-	jr	ra
-	mfc1	ta1, $19
-	jr	ra
-	mfc1	ta1, $20
-	jr	ra
-	mfc1	ta1, $21
-	jr	ra
-	mfc1	ta1, $22
-	jr	ra
-	mfc1	ta1, $23
-	jr	ra
-	mfc1	ta1, $24
-	jr	ra
-	mfc1	ta1, $25
-	jr	ra
-	mfc1	ta1, $26
-	jr	ra
-	mfc1	ta1, $27
-	jr	ra
-	mfc1	ta1, $28
-	jr	ra
-	mfc1	ta1, $29
-	jr	ra
-	mfc1	ta1, $30
-	jr	ra
-	mfc1	ta1, $31
-	jr	ra
-
-/*
- * Put the value in ta2 into the single precission register which's number
- * is in ta1.
- */
-s_put_fpreg:
-	.set	noat
-	sll	ta1, 3
-	la	AT, 1f
-	daddu	AT, ta1
-	jr	AT
-	.set	at
-	
-1:	mtc1	ta2, $0
-	jr	ra
-	mtc1	ta2, $1
-	jr	ra
-	mtc1	ta2, $2
-	jr	ra
-	mtc1	ta2, $3
-	jr	ra
-	mtc1	ta2, $4
-	jr	ra
-	mtc1	ta2, $5
-	jr	ra
-	mtc1	ta2, $6
-	jr	ra
-	mtc1	ta2, $7
-	jr	ra
-	mtc1	ta2, $8
-	jr	ra
-	mtc1	ta2, $9
-	jr	ra
-	mtc1	ta2, $10
-	jr	ra
-	mtc1	ta2, $11
-	jr	ra
-	mtc1	ta2, $12
-	jr	ra
-	mtc1	ta2, $13
-	jr	ra
-	mtc1	ta2, $14
-	jr	ra
-	mtc1	ta2, $15
-	jr	ra
-	mtc1	ta2, $16
-	jr	ra
-	mtc1	ta2, $17
-	jr	ra
-	mtc1	ta2, $18
-	jr	ra
-	mtc1	ta2, $19
-	jr	ra
-	mtc1	ta2, $20
-	jr	ra
-	mtc1	ta2, $21
-	jr	ra
-	mtc1	ta2, $22
-	jr	ra
-	mtc1	ta2, $23
-	jr	ra
-	mtc1	ta2, $24
-	jr	ra
-	mtc1	ta2, $25
-	jr	ra
-	mtc1	ta2, $26
-	jr	ra
-	mtc1	ta2, $27
-	jr	ra
-	mtc1	ta2, $28
-	jr	ra
-	mtc1	ta2, $29
-	jr	ra
-	mtc1	ta2, $30
-	jr	ra
-	mtc1	ta2, $31
-	jr	ra
-
-/* Get the double precission register which's number is in ta1 into ta1/ta2.  */
-d_get_fpreg:
-	.set	noat
-	sll	AT, ta1, 1
-	sll	ta1, 2
-	daddu	ta1, AT
-	la	AT, 1f
-	daddu	AT, ta1
-	jr	AT
-	.set	at
-
-1:	mfc1	ta1, $0
-	mfc1	ta2, $1
-	jr	ra
-	mfc1	ta1, $2
-	mfc1	ta2, $3
-	jr	ra
-	mfc1	ta1, $4
-	mfc1	ta2, $5
-	jr	ra
-	mfc1	ta1, $6
-	mfc1	ta2, $7
-	jr	ra
-	mfc1	ta1, $8
-	mfc1	ta2, $9
-	jr	ra
-	mfc1	ta1, $10
-	mfc1	ta2, $11
-	jr	ra
-	mfc1	ta1, $12
-	mfc1	ta2, $13
-	jr	ra
-	mfc1	ta1, $14
-	mfc1	ta2, $15
-	jr	ra
-	mfc1	ta1, $16
-	mfc1	ta2, $17
-	jr	ra
-	mfc1	ta1, $18
-	mfc1	ta2, $19
-	jr	ra
-	mfc1	ta1, $20
-	mfc1	ta2, $21
-	jr	ra
-	mfc1	ta1, $22
-	mfc1	ta2, $23
-	jr	ra
-	mfc1	ta1, $24
-	mfc1	ta2, $25
-	jr	ra
-	mfc1	ta1, $26
-	mfc1	ta2, $27
-	jr	ra
-	mfc1	ta1, $28
-	mfc1	ta2, $29
-	jr	ra
-	mfc1	ta1, $30
-	mfc1	ta2, $31
-	jr	ra
-
-/*
- * Send an invalid operation exception.
- */
-invalid:
-	ld	ra, 0(sp)
-	daddu	sp, 16
-	jr	ra
-
-/*
- * Done, just skip over the current instruction
- */
-done:
-	ld	ra, 0(sp)
-	daddu	sp, 16
-	jr	ra
-
-unimp:
-	/* We've run into an yet unknown instruction.  This happens either
-	   on new, yet unsupported CPU types or when the faulting instruction
-	   is being executed for cache but has been overwritten in memory.  */
-	LOCK_KERNEL
-	move	a1, ta0
-	PRINT(KERN_DEBUG "FP support: unknown fp op %08lx, ")
-	PRINT("please mail to ralf@gnu.org.\n")
-	UNLOCK_KERNEL
-
-	li	a0, SIGILL			# Die, sucker ...
-	move	a1, $28
-	jal	force_sig
-
-	ld	ra, 0(sp)
-	daddu	sp, 16
-	jr	ra
-
-/*
- * Jump table for the lowest 6 bits of a cp1 instruction.
- */
-	.data
-lowtab:	.dword	add,   sub,   mul,   div,   sqrt,  abs,   mov,   neg
-	.dword	round.l,trunc.l,ceil.l,floor.l,round.w,trunc.w,ceil.w,floor.w
-	.dword	unimp, unimp, unimp, unimp, unimp, unimp, unimp, unimp
-	.dword	unimp, unimp, unimp, unimp, unimp, unimp, unimp, unimp
-	.dword	cvt.s, cvt.d, unimp, unimp, cvt.w, cvt.l, unimp, unimp
-	.dword	unimp, unimp, unimp, unimp, unimp, unimp, unimp, unimp
-	.dword	c.f,   c.un,  c.eq,  c.ueq, c.olt, c.ult, c.ole, c.ule
-	.dword	c.sf,  c.ngle,c.seq, c.ngl, c.lt,  c.nge, c.le, c.ngt
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/syscall.c linux-2.4.20/arch/mips64/kernel/syscall.c
--- linux-2.4.19/arch/mips64/kernel/syscall.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/syscall.c	2002-10-29 11:18:49.000000000 +0000
@@ -261,7 +261,7 @@
 	}
 
 	case MSGSND:
-		return sys_msgsnd (first, (struct msgbuf *) ptr, 
+		return sys_msgsnd (first, (struct msgbuf *) ptr,
 				   second, third);
 	case MSGRCV:
 		switch (version) {
@@ -269,9 +269,9 @@
 			struct ipc_kludge tmp;
 			if (!ptr)
 				return -EINVAL;
-			
+
 			if (copy_from_user(&tmp,
-					   (struct ipc_kludge *) ptr, 
+					   (struct ipc_kludge *) ptr,
 					   sizeof (tmp)))
 				return -EFAULT;
 			return sys_msgrcv (first, tmp.msgp, second,
@@ -301,7 +301,7 @@
 				return -EINVAL;
 			return sys_shmat (first, (char *) ptr, second, (ulong *) third);
 		}
-	case SHMDT: 
+	case SHMDT:
 		return sys_shmdt ((char *)ptr);
 	case SHMGET:
 		return sys_shmget (first, second, third);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/time.c linux-2.4.20/arch/mips64/kernel/time.c
--- linux-2.4.19/arch/mips64/kernel/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/time.c	2002-10-29 11:18:39.000000000 +0000
@@ -2,8 +2,8 @@
  * Copyright 2001 MontaVista Software Inc.
  * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
  *
- * Common time service routines for MIPS machines. See 
- * Documents/MIPS/README.txt. 
+ * Common time service routines for MIPS machines. See
+ * Documents/MIPS/README.txt.
  *
  * 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
@@ -289,9 +289,9 @@
 
 /*
  * local_timer_interrupt() does profiling and process accounting
- * on a per-CPU basis.  
+ * on a per-CPU basis.
  *
- * In UP mode, it is invoked from the (global) timer_interrupt.  
+ * In UP mode, it is invoked from the (global) timer_interrupt.
  *
  * In SMP mode, it might invoked by per-CPU timer interrupt, or
  * a broadcasted inter-processor interrupt which itself is triggered
@@ -368,7 +368,7 @@
 		if (rtc_set_time(xtime.tv_sec) == 0) {
 			last_rtc_update = xtime.tv_sec;
 		} else {
-			last_rtc_update = xtime.tv_sec - 600; 
+			last_rtc_update = xtime.tv_sec - 600;
 			/* do it again in 60 s */
 		}
 	}
@@ -384,9 +384,9 @@
 	}
 
 #if !defined(CONFIG_SMP)
-	/* 
+	/*
 	 * In UP mode, we call local_timer_interrupt() to do profiling
-	 * and process accouting.  
+	 * and process accouting.
 	 *
 	 * In SMP mode, local_timer_interrupt() is invoked by appropriate
 	 * low-level local timer interrupt handler.
@@ -396,7 +396,7 @@
 #else	/* CONFIG_SMP */
 
 	if (emulate_local_timer_interrupt) {
-		/* 
+		/*
 		 * this is the place where we send out inter-process
 		 * interrupts and let each CPU do its own profiling
 		 * and process accouting.
@@ -418,7 +418,7 @@
 
 	/* we keep interrupt disabled all the time */
 	timer_interrupt(irq, NULL, regs);
-	
+
 	irq_exit(cpu, irq);
 
 	if (softirq_pending(cpu))
@@ -434,7 +434,7 @@
 
 	/* we keep interrupt disabled all the time */
 	local_timer_interrupt(irq, NULL, regs);
-	
+
 	irq_exit(cpu, irq);
 
 	if (softirq_pending(cpu))
@@ -444,19 +444,19 @@
 /*
  * time_init() - it does the following things.
  *
- * 1) board_time_init() - 
- * 	a) (optional) set up RTC routines, 
+ * 1) board_time_init() -
+ * 	a) (optional) set up RTC routines,
  *      b) (optional) calibrate and set the mips_counter_frequency
  *	    (only needed if you intended to use fixed_rate_gettimeoffset
  *	     or use cpu counter as timer interrupt source)
  * 2) setup xtime based on rtc_get_time().
  * 3) choose a appropriate gettimeoffset routine.
  * 4) calculate a couple of cached variables for later usage
- * 5) board_timer_setup() - 
+ * 5) board_timer_setup() -
  *	a) (optional) over-write any choices made above by time_init().
  *	b) machine specific code should setup the timer irqaction.
  *	c) enable the timer interrupt
- */ 
+ */
 
 void (*board_time_init)(void) = NULL;
 void (*board_timer_setup)(struct irqaction *irq) = NULL;
@@ -496,10 +496,12 @@
 		/* we need to calibrate the counter but we *do* have
 		 * 64-bit division. */
 		do_gettimeoffset = calibrate_div64_gettimeoffset;
-	}	
+	}
 
 	/* caclulate cache parameters */
 	if (mips_counter_frequency) {
+		u32 count;
+
 		cycles_per_jiffy = mips_counter_frequency / HZ;
 
 		/* sll32_usecs_per_cycle = 10^6 * 2^32 / mips_counter_freq */
@@ -507,16 +509,24 @@
 		sll32_usecs_per_cycle = mips_counter_frequency / 100000;
 		sll32_usecs_per_cycle = 0xffffffff / sll32_usecs_per_cycle;
 		sll32_usecs_per_cycle *= 10;
+
+		/*
+		 * For those using cpu counter as timer,  this sets up the
+		 * first interrupt
+		 */
+		count = read_32bit_cp0_register(CP0_COUNT);
+		write_32bit_cp0_register (CP0_COMPARE,
+					  count + cycles_per_jiffy);
 	}
 
-	/* 
+	/*
 	 * Call board specific timer interrupt setup.
 	 *
-	 * this pointer must be setup in machine setup routine. 
+	 * this pointer must be setup in machine setup routine.
 	 *
 	 * Even if the machine choose to use low-level timer interrupt,
 	 * it still needs to setup the timer_irqaction.
-	 * In that case, it might be better to set timer_irqaction.handler 
+	 * In that case, it might be better to set timer_irqaction.handler
 	 * to be NULL function so that we are sure the high-level code
 	 * is not invoked accidentally.
 	 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/traps.c linux-2.4.20/arch/mips64/kernel/traps.c
--- linux-2.4.19/arch/mips64/kernel/traps.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/traps.c	2002-10-29 11:18:49.000000000 +0000
@@ -31,6 +31,7 @@
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/cachectl.h>
+#include <asm/types.h>
 
 extern asmlinkage void __xtlb_mod(void);
 extern asmlinkage void __xtlb_tlbl(void);
@@ -50,7 +51,9 @@
 extern asmlinkage void handle_mcheck(void);
 extern asmlinkage void handle_reserved(void);
 
-extern int fpu_emulator_cop1Handler(struct pt_regs *);
+extern int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp,
+	struct mips_fpu_soft_struct *ctx);
+
 void fpu_emulator_init_fpu(void);
 
 char watch_available = 0;
@@ -66,61 +69,94 @@
  */
 #define MODULE_RANGE (8*1024*1024)
 
+#define OPCODE 0xfc000000
+
+/*
+ * If the address is either in the .text section of the
+ * kernel, or in the vmalloc'ed module regions, it *may*
+ * be the address of a calling routine
+ */
+
+#ifdef CONFIG_MODULES
+
+extern struct module *module_list;
+extern struct module kernel_module;
+
+static inline int kernel_text_address(long addr)
+{
+	extern char _stext, _etext;
+	int retval = 0;
+	struct module *mod;
+
+	if (addr >= (long) &_stext && addr <= (long) &_etext)
+		return 1;
+
+	for (mod = module_list; mod != &kernel_module; mod = mod->next) {
+		/* mod_bound tests for addr being inside the vmalloc'ed
+		 * module area. Of course it'd be better to test only
+		 * for the .text subset... */
+		if (mod_bound(addr, 0, mod)) {
+			retval = 1;
+			break;
+		}
+	}
+
+	return retval;
+}
+
+#else
+
+static inline int kernel_text_address(long addr)
+{
+	extern char _stext, _etext;
+
+	return (addr >= (long) &_stext && addr <= (long) &_etext);
+}
+
+#endif
+
 /*
  * This routine abuses get_user()/put_user() to reference pointers
  * with at least a bit of error checking ...
  */
-void show_stack(unsigned long *sp)
+void show_stack(long *sp)
 {
 	int i;
-	unsigned long *stack;
-
-	stack = sp;
-	i = 0;
+	long stackdata;
 
 	printk("Stack:");
-	while ((unsigned long) stack & (PAGE_SIZE - 1)) {
-		unsigned long stackdata;
-
-		if (__get_user(stackdata, stack++)) {
-			printk(" (Bad stack address)");
+	i = 0;
+	while ((long) sp & (PAGE_SIZE - 1)) {
+		if (i && ((i % 4) == 0))
+			printk("\n      ");
+		if (i > 40) {
+			printk(" ...");
 			break;
 		}
 
-		printk(" %016lx", stackdata);
-
-		if (++i > 40) {
-			printk(" ...");
+		if (__get_user(stackdata, sp++)) {
+			printk(" (Bad stack address)");
 			break;
 		}
 
-		if (i % 4 == 0)
-			printk("\n      ");
+		printk(" %016lx", stackdata);
+		i++;
 	}
+	printk("\n");
 }
 
-void show_trace(unsigned long *sp)
+void show_trace(long *sp)
 {
 	int i;
-	unsigned long *stack;
-	unsigned long kernel_start, kernel_end;
-	unsigned long module_start, module_end;
-	extern char _stext, _etext;
+	long addr;
 
-	stack = sp;
+	printk("Call Trace:");
 	i = 0;
+	while ((long) sp & (PAGE_SIZE - 1)) {
 
-	kernel_start = (unsigned long) &_stext;
-	kernel_end = (unsigned long) &_etext;
-	module_start = VMALLOC_START;
-	module_end = module_start + MODULE_RANGE;
-
-	printk("\nCall Trace:");
-
-	while ((unsigned long) stack & (PAGE_SIZE - 1)) {
-		unsigned long addr;
-
-		if (__get_user(addr, stack++)) {
+		if (__get_user(addr, sp++)) {
+			if (i && ((i % 3) == 0))
+				printk("\n           ");
 			printk(" (Bad stack address)\n");
 			break;
 		}
@@ -134,25 +170,24 @@
 		 * out the call path that was taken.
 		 */
 
-		if ((addr >= kernel_start && addr < kernel_end) ||
-		    (addr >= module_start && addr < module_end)) { 
-
-			/* Since our kernel is still at KSEG0,
-			 * truncate the address so that ksymoops
-			 * understands it.
-			 */
-			printk(" [<%08x>]", (unsigned int) addr);
-			if (++i > 40) {
+		if (kernel_text_address(addr)) {
+			if (i && ((i % 3) == 0))
+				printk("\n           ");
+			if (i > 40) {
 				printk(" ...");
 				break;
 			}
+
+			printk(" [<%016lx>]", addr);
+			i++;
 		}
 	}
+	printk("\n");
 }
 
 void show_trace_task(struct task_struct *tsk)
 {
-	show_trace((unsigned long *)tsk->thread.reg29);
+	show_trace((long *)tsk->thread.reg29);
 }
 
 
@@ -216,31 +251,38 @@
 	printk("Cause   : %08x\n", (unsigned int) regs->cp0_cause);
 }
 
-static spinlock_t die_lock;
-
-void die(const char * str, struct pt_regs * regs)
+void show_registers(struct pt_regs *regs)
 {
-	if (user_mode(regs))	/* Just return if in user mode.  */
-		return;
-
-	console_verbose();
-	spin_lock_irq(&die_lock);
-	printk("%s\n", str);
 	show_regs(regs);
-	printk("Process %s (pid: %d, stackpage=%08lx)\n",
+	printk("Process %s (pid: %d, stackpage=%016lx)\n",
 		current->comm, current->pid, (unsigned long) current);
-	show_stack((unsigned long *) regs->regs[29]);
-	show_trace((unsigned long *) regs->regs[29]);
+	show_stack((long *) regs->regs[29]);
+	show_trace((long *) regs->regs[29]);
 	show_code((unsigned int *) regs->cp0_epc);
 	printk("\n");
+}
+
+static spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
+
+void __die(const char * str, struct pt_regs * regs, const char * file,
+	   const char * func, unsigned long line)
+{
+	console_verbose();
+	spin_lock_irq(&die_lock);
+	printk("%s", str);
+	if (file && func)
+		printk(" in %s:%s, line %ld", file, func, line);
+	printk(":\n");
+	show_registers(regs);
 	spin_unlock_irq(&die_lock);
 	do_exit(SIGSEGV);
 }
 
-void die_if_kernel(const char * str, struct pt_regs * regs)
+void __die_if_kernel(const char * str, struct pt_regs * regs,
+		     const char * file, const char * func, unsigned long line)
 {
 	if (!user_mode(regs))
-		die(str, regs);
+		__die(str, regs, file, func, line);
 }
 
 extern const struct exception_table_entry __start___dbe_table[];
@@ -353,11 +395,18 @@
 	force_sig(SIGBUS, current);
 }
 
-void do_ov(struct pt_regs *regs)
+asmlinkage void do_ov(struct pt_regs *regs)
 {
+	siginfo_t info;
+
 	if (compute_return_epc(regs))
 		return;
-	force_sig(SIGFPE, current);
+
+	info.si_code = FPE_INTOVF;
+	info.si_signo = SIGFPE;
+	info.si_errno = 0;
+	info.si_addr = (void *)regs->cp0_epc;
+	force_sig_info(SIGFPE, &info, current);
 }
 
 /*
@@ -381,10 +430,11 @@
 		save_fp(current);
 
 		/* Run the emulator */
-		sig = fpu_emulator_cop1Handler(regs);
+		sig = fpu_emulator_cop1Handler (0, regs,
+			&current->thread.fpu.soft);
 
-		/* 
-		 * We can't allow the emulated instruction to leave any of 
+		/*
+		 * We can't allow the emulated instruction to leave any of
 		 * the cause bit set in $fcr31.
 		 */
 		current->thread.fpu.soft.sr &= ~FPU_CSR_ALL_X;
@@ -395,8 +445,8 @@
 		/* If something went wrong, signal */
 		if (sig)
 		{
-			/* 
-			 * Return EPC is not calculated in the FPU emulator, 
+			/*
+			 * Return EPC is not calculated in the FPU emulator,
 			 * if a signal is being send. So we calculate it here.
 			 */
 			compute_return_epc(regs);
@@ -411,16 +461,26 @@
 	force_sig(SIGFPE, current);
 }
 
-void do_bp(struct pt_regs *regs)
+static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode)
+{
+	unsigned long *epc;
+
+	epc = (unsigned long *) regs->cp0_epc +
+	      ((regs->cp0_cause & CAUSEF_BD) != 0);
+	if (!get_user(opcode, epc))
+		return 0;
+
+	force_sig(SIGSEGV, current);
+	return 1;
+}
+
+asmlinkage void do_bp(struct pt_regs *regs)
 {
 	unsigned int opcode, bcode;
-	unsigned int *epc;
 	siginfo_t info;
 
-	epc = (unsigned int *) regs->cp0_epc +
-	      ((regs->cp0_cause & CAUSEF_BD) != 0);
-	if (get_user(opcode, epc))
-		goto sigsegv;
+	if (get_insn_opcode(regs, &opcode))
+		return;
 
 	/*
 	 * There is the ancient bug in the MIPS assemblers that the break
@@ -450,37 +510,30 @@
 	default:
 		force_sig(SIGTRAP, current);
 	}
-
-	force_sig(SIGTRAP, current);
-	return;
-
-sigsegv:
-	force_sig(SIGSEGV, current);
 }
 
-void do_tr(struct pt_regs *regs)
+asmlinkage void do_tr(struct pt_regs *regs)
 {
-	unsigned int opcode, bcode;
-	unsigned int *epc;
+	unsigned int opcode, tcode = 0;
 	siginfo_t info;
 
-	epc = (unsigned int *) regs->cp0_epc +
-	      ((regs->cp0_cause & CAUSEF_BD) != 0);
-	if (get_user(opcode, epc))
-		goto sigsegv;
+	if (get_insn_opcode(regs, &opcode))
+		return;
 
-	bcode = ((opcode >> 6) & ((1 << 20) - 1));
+        /* Immediate versions don't provide a code.  */
+	if (!(opcode & OPCODE))
+		tcode = ((opcode >> 6) & ((1 << 20) - 1));
 
 	/*
-	 * (A short test says that IRIX 5.3 sends SIGTRAP for all break
-	 * insns, even for break codes that indicate arithmetic failures.
-	 * Wiered ...)
+	 * (A short test says that IRIX 5.3 sends SIGTRAP for all trap
+	 * insns, even for trap codes that indicate arithmetic failures.
+	 * Weird ...)
 	 * But should we continue the brokenness???  --macro
 	 */
-	switch (bcode) {
+	switch (tcode) {
 	case 6:
 	case 7:
-		if (bcode == 7)
+		if (tcode == 7)
 			info.si_code = FPE_INTDIV;
 		else
 			info.si_code = FPE_INTOVF;
@@ -492,23 +545,22 @@
 	default:
 		force_sig(SIGTRAP, current);
 	}
-	return;
-
-sigsegv:
-	force_sig(SIGSEGV, current);
 }
 
-void do_ri(struct pt_regs *regs)
+asmlinkage void do_ri(struct pt_regs *regs)
 {
+	die_if_kernel("Reserved instruction in kernel code", regs);
+
 	if (compute_return_epc(regs))
 		return;
 
 	force_sig(SIGILL, current);
 }
 
-void do_cpu(struct pt_regs *regs)
+asmlinkage void do_cpu(struct pt_regs *regs)
 {
-	u32 cpid;
+	unsigned int cpid;
+	void fpu_emulator_init_fpu(void);
 	int sig;
 
 	cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
@@ -544,15 +596,17 @@
 	return;
 
 fp_emul:
-	if (!current->used_math) {
-		fpu_emulator_init_fpu();
-		current->used_math = 1;
+	if (last_task_used_math != current) {
+		if (!current->used_math) {
+			fpu_emulator_init_fpu();
+			current->used_math = 1;
+		}
 	}
-	sig = fpu_emulator_cop1Handler(regs);
-	if (sig)
-	{
-		/* 
-		 * Return EPC is not calculated in the FPU emulator, if 
+	sig = fpu_emulator_cop1Handler(0, regs, &current->thread.fpu.soft);
+	last_task_used_math = current;
+	if (sig) {
+		/*
+		 * Return EPC is not calculated in the FPU emulator, if
 		 * a signal is being send. So we calculate it here.
 		 */
 		compute_return_epc(regs);
@@ -565,12 +619,15 @@
 	force_sig(SIGILL, current);
 }
 
-void do_watch(struct pt_regs *regs)
+asmlinkage void do_watch(struct pt_regs *regs)
 {
+	extern void dump_tlb_all(void);
+
 	/*
 	 * We use the watch exception where available to detect stack
 	 * overflows.
 	 */
+	dump_tlb_all();
 	show_regs(regs);
 	panic("Caught WATCH exception - probably caused by stack overflow.");
 }
@@ -578,11 +635,17 @@
 asmlinkage void do_mcheck(struct pt_regs *regs)
 {
 	show_regs(regs);
-	panic("Caught Machine Check exception - probably caused by multiple "
-	      "matching entries in the TLB.");
+	dump_tlb_all();
+	/*
+	 * Some chips may have other causes of machine check (e.g. SB1
+	 * graduation timer)
+	 */
+	panic("Caught Machine Check exception - %scaused by multiple "
+	      "matching entries in the TLB.",
+	      (regs->cp0_status & ST0_TS) ? "" : "not ");
 }
 
-void do_reserved(struct pt_regs *regs)
+asmlinkage void do_reserved(struct pt_regs *regs)
 {
 	/*
 	 * Game over - no way to handle this if it ever occurs.  Most probably
@@ -618,18 +681,28 @@
  * to interrupt handlers in the address range from
  * KSEG0 <= x < KSEG0 + 256mb on the Nevada.  Oh well ...
  */
-void set_except_vector(int n, void *addr)
+void *set_except_vector(int n, void *addr)
 {
 	unsigned long handler = (unsigned long) addr;
-	exception_handlers[n] = handler;
+	unsigned long old_handler = exception_handlers[n];
 
+	exception_handlers[n] = handler;
 	if (n == 0 && mips_cpu.options & MIPS_CPU_DIVEC) {
 		*(volatile u32 *)(KSEG0+0x200) = 0x08000000 |
 		                                 (0x03ffffff & (handler >> 2));
 		flush_icache_range(KSEG0+0x200, KSEG0 + 0x204);
 	}
+	return (void *)old_handler;
 }
 
+asmlinkage int (*save_fp_context)(struct sigcontext *sc);
+asmlinkage int (*restore_fp_context)(struct sigcontext *sc);
+extern asmlinkage int _save_fp_context(struct sigcontext *sc);
+extern asmlinkage int _restore_fp_context(struct sigcontext *sc);
+
+extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc);
+extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc);
+
 void __init per_cpu_trap_init(void)
 {
 	unsigned int cpu = smp_processor_id();
@@ -653,6 +726,7 @@
 void __init trap_init(void)
 {
 	extern char except_vec0;
+	extern char except_vec1_r4k;
 	extern char except_vec1_r10k;
 	extern char except_vec2_generic;
 	extern char except_vec3_generic, except_vec3_r4000;
@@ -724,10 +798,17 @@
 	case CPU_R4600:
 	case CPU_R5000:
 	case CPU_NEVADA:
+	case CPU_5KC:
+	case CPU_20KC:
+	case CPU_RM7000:
 		/* Debug TLB refill handler.  */
 		memcpy((void *)KSEG0, &except_vec0, 0x80);
-		memcpy((void *)KSEG0 + 0x080, &except_vec1_r10k, 0x80);
-
+		if ((mips_cpu.options & MIPS_CPU_4KEX)
+		    && (mips_cpu.options & MIPS_CPU_4KTLB)) {
+			memcpy((void *)KSEG0 + 0x080, &except_vec1_r4k, 0x80);
+		} else {
+			memcpy((void *)KSEG0 + 0x080, &except_vec1_r10k, 0x80);
+		}
 		if (mips_cpu.options & MIPS_CPU_VCE) {
 			memcpy((void *)(KSEG0 + 0x180), &except_vec3_r4000,
 			       0x80);
@@ -764,6 +845,14 @@
 	}
 	flush_icache_range(KSEG0, KSEG0 + 0x200);
 
+	if (mips_cpu.options & MIPS_CPU_FPU) {
+	        save_fp_context = _save_fp_context;
+		restore_fp_context = _restore_fp_context;
+	} else {
+		save_fp_context = fpu_emulator_save_context;
+		restore_fp_context = fpu_emulator_restore_context;
+	}
+
 	if (mips_cpu.isa_level == MIPS_CPU_ISA_IV)
 		set_cp0_status(ST0_XX);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/kernel/unaligned.c linux-2.4.20/arch/mips64/kernel/unaligned.c
--- linux-2.4.19/arch/mips64/kernel/unaligned.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/kernel/unaligned.c	2002-10-29 11:18:35.000000000 +0000
@@ -41,7 +41,7 @@
  *
  * #include <stdio.h>
  * #include <asm/sysmips.h>
- * 
+ *
  * struct foo {
  *         unsigned char bar[8];
  * };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/ld.script.elf32.S linux-2.4.20/arch/mips64/ld.script.elf32.S
--- linux-2.4.19/arch/mips64/ld.script.elf32.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/ld.script.elf32.S	2002-10-29 11:18:40.000000000 +0000
@@ -102,7 +102,7 @@
   }
 
   /* Sections to be discarded */
-  /DISCARD/ : 
+  /DISCARD/ :
   {
         *(.text.exit)
         *(.data.exit)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/ld.script.elf64 linux-2.4.20/arch/mips64/ld.script.elf64
--- linux-2.4.19/arch/mips64/ld.script.elf64	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/ld.script.elf64	2002-10-29 11:18:35.000000000 +0000
@@ -8,7 +8,7 @@
   /* This is the value for an Origin kernel, taken from an IRIX kernel.  */
   /* . = 0xc00000000001c000; */
 
-  /* Set the vaddr for the text segment to a value 
+  /* Set the vaddr for the text segment to a value
         >= 0xa800 0000 0001 9000 if no symmon is going to configured
         >= 0xa800 0000 0030 0000 otherwise  */
 
@@ -111,7 +111,7 @@
   }
 
   /* Sections to be discarded */
-  /DISCARD/ : 
+  /DISCARD/ :
   {
         *(.text.exit)
         *(.data.exit)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/lib/csum_partial_copy.c linux-2.4.20/arch/mips64/lib/csum_partial_copy.c
--- linux-2.4.19/arch/mips64/lib/csum_partial_copy.c	2001-09-09 17:43:01.000000000 +0000
+++ linux-2.4.20/arch/mips64/lib/csum_partial_copy.c	2002-10-29 11:18:49.000000000 +0000
@@ -16,7 +16,7 @@
 /*
  * copy while checksumming, otherwise like csum_partial
  */
-unsigned int csum_partial_copy(const char *src, char *dst, 
+unsigned int csum_partial_copy(const char *src, char *dst,
                                int len, unsigned int sum)
 {
 	/*
@@ -44,6 +44,6 @@
 		memset(dst + len - missing, 0, missing);
 		*err_ptr = -EFAULT;
 	}
-		
+
 	return csum_partial(dst, len, sum);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/lib/floppy-std.c linux-2.4.20/arch/mips64/lib/floppy-std.c
--- linux-2.4.19/arch/mips64/lib/floppy-std.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/lib/floppy-std.c	2002-10-29 11:18:48.000000000 +0000
@@ -111,8 +111,8 @@
 }
 
 static void std_fd_dma_mem_free(unsigned long addr, unsigned long size)
-{       
-	free_pages(addr, get_order(size));	
+{
+	free_pages(addr, get_order(size));
 }
 
 static unsigned long std_fd_drive_type(unsigned long n)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/lib/ide-no.c linux-2.4.20/arch/mips64/lib/ide-no.c
--- linux-2.4.19/arch/mips64/lib/ide-no.c	2001-09-09 17:43:01.000000000 +0000
+++ linux-2.4.20/arch/mips64/lib/ide-no.c	2002-10-29 11:18:31.000000000 +0000
@@ -35,7 +35,7 @@
                               void *dev_id)
 {
 	panic("no_no_ide_request_irq called - shouldn't happen");
-}			
+}
 
 static void no_ide_free_irq(unsigned int irq, void *dev_id)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/lib/ide-std.c linux-2.4.20/arch/mips64/lib/ide-std.c
--- linux-2.4.19/arch/mips64/lib/ide-std.c	2001-09-09 17:43:01.000000000 +0000
+++ linux-2.4.20/arch/mips64/lib/ide-std.c	2002-10-29 11:18:31.000000000 +0000
@@ -68,7 +68,7 @@
                                 void *dev_id)
 {
 	return request_irq(irq, handler, flags, device, dev_id);
-}			
+}
 
 static void std_ide_free_irq(unsigned int irq, void *dev_id)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/lib/memcpy.S linux-2.4.20/arch/mips64/lib/memcpy.S
--- linux-2.4.19/arch/mips64/lib/memcpy.S	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/arch/mips64/lib/memcpy.S	2002-10-29 11:18:32.000000000 +0000
@@ -501,7 +501,7 @@
 r_word_align:
 	beqz	t8, r_dword_align
 	 sltiu	t8, a2, 56
-	
+
 	lh	ta0, -2(a1)
 	dsubu	a2, a2, 0x2
 	sh	ta0, -2(a0)
@@ -762,8 +762,18 @@
 	dsubu	a2, AT, ta0			# a2 bytes to go
 	daddu	a0, ta0				# compute start address in a1
 	dsubu	a0, a1
-	j	__bzero
-	 move	a1, zero
+	/*
+	 * Clear len bytes starting at dst.  Can't call __bzero because it
+	 * might modify len.  An inefficient loop for these rare times...
+	 */
+	beqz	a2, 2f
+	 dsubu	a1, a2, 1
+1:	sb	zero, 0(a0)
+	daddu	a0, a0, 1
+	bnez	a1, 1b
+	 dsubu	a1, a1, 1
+2:	jr	ra
+	 nop
 
 s_fixup:
 	jr	ra
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/lib/memset.S linux-2.4.20/arch/mips64/lib/memset.S
--- linux-2.4.19/arch/mips64/lib/memset.S	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.20/arch/mips64/lib/memset.S	2002-10-29 11:18:33.000000000 +0000
@@ -52,7 +52,6 @@
 1:
 
 FEXPORT(__bzero)
-	.type	__bzero, @function
 	sltiu	t0, a2, 8			/* very small region? */
 	bnez	t0, small_memset
 	 andi	t0, a0, 7			/* aligned? */
@@ -82,7 +81,7 @@
 	.set	noreorder
 
 memset_partial:
-	la	t1, 2f				/* where to start */
+	PTR_LA	t1, 2f				/* where to start */
 	.set	noat
 	dsrl	AT, t0, 1
 	dsubu	t1, AT
@@ -90,8 +89,12 @@
 	jr	t1
 	 daddu	a0, t0				/* dest ptr */
 
+	.set	push
+	.set	noreorder
+	.set	nomacro
 	F_FILL64(a0, -64, a1, partial_fixup)	/* ... but first do dwds ... */
-2:	andi	a2, 7				/* 0 <= n <= 7 to go */
+2:	.set	pop
+	andi	a2, 7				/* 0 <= n <= 7 to go */
 
 	beqz	a2, 1f
 	 daddu	a0, a2				/* What's left */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/lib/strlen_user.S linux-2.4.20/arch/mips64/lib/strlen_user.S
--- linux-2.4.19/arch/mips64/lib/strlen_user.S	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/arch/mips64/lib/strlen_user.S	2002-10-29 11:18:36.000000000 +0000
@@ -36,9 +36,5 @@
 	jr	ra
 	END(__strlen_user_asm)
 
-	.section	__ex_table,"a"
-	PTR		1b, fault
-	.previous
-
 fault:	move	v0, zero
 	jr	ra
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/lib/strnlen_user.S linux-2.4.20/arch/mips64/lib/strnlen_user.S
--- linux-2.4.19/arch/mips64/lib/strnlen_user.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/lib/strnlen_user.S	2002-10-29 11:18:36.000000000 +0000
@@ -24,7 +24,7 @@
  */
 LEAF(__strnlen_user_asm)
 	ld	v0, THREAD_CURDS($28)	# pointer ok?
-	and	v0, ta0
+	and	v0, a0
 	bltz	v0, fault
 
 FEXPORT(__strnlen_user_nocheck_asm)
@@ -38,9 +38,5 @@
 	jr	ra
 	END(__strnlen_user_asm)
 
-	.section	__ex_table,"a"
-	PTR		1b, fault
-	.previous
-
 fault:	move	v0, zero
 	jr	ra
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/Makefile linux-2.4.20/arch/mips64/math-emu/Makefile
--- linux-2.4.19/arch/mips64/math-emu/Makefile	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/Makefile	1970-01-01 00:00:00.000000000 +0000
@@ -1,24 +0,0 @@
-#
-# Makefile for the Linux/MIPS kernel FPU emulation.
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-.S.o:
-	$(CC) $(CFLAGS) -c $< -o $*.o
-
-EXTRA_ASFLAGS = -mips2 -mcpu=r4000
-
-O_TARGET:= fpu_emulator.o
-
-obj-y	:= cp1emu.o ieee754m.o ieee754d.o ieee754dp.o ieee754sp.o ieee754.o \
-	   ieee754xcpt.o dp_frexp.o dp_modf.o dp_div.o dp_mul.o dp_sub.o \
-	   dp_add.o dp_fsp.o dp_cmp.o dp_logb.o dp_scalb.o dp_simple.o \
-	   dp_tint.o dp_fint.o dp_tlong.o dp_flong.o sp_frexp.o sp_modf.o \
-	   sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_logb.o \
-	   sp_scalb.o sp_simple.o sp_tint.o sp_fint.o sp_tlong.o sp_flong.o \
-	   dp_sqrt.o sp_sqrt.o kernel_linkage.o
-
-include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/cp1emu.c linux-2.4.20/arch/mips64/math-emu/cp1emu.c
--- linux-2.4.19/arch/mips64/math-emu/cp1emu.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/cp1emu.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1812 +0,0 @@
-/*
- * MIPS floating point support
- *
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator
- * 
- * A complete emulator for MIPS coprocessor 1 instructions.  This is
- * required for #float(switch) or #float(trap), where it catches all
- * COP1 instructions via the "CoProcessor Unusable" exception.  
- *
- * More surprisingly it is also required for #float(ieee), to help out
- * the hardware fpu at the boundaries of the IEEE-754 representation
- * (denormalised values, infinities, underflow, etc).  It is made
- * quite nasty because emulation of some non-COP1 instructions is
- * required, e.g. in branch delay slots.
- * 
- * Notes: 
- *  1) the IEEE754 library (-le) performs the actual arithmetic;
- *  2) if you know that you won't have an fpu, then you'll get much 
- *     better performance by compiling with -msoft-float!
- *
- *  Nov 7, 2000
- *  Massive changes to integrate with Linux kernel.
- *
- *  Replace use of kernel data area with use of user stack 
- *  for execution of instructions in branch delay slots.
- *
- *  Replace use of static kernel variables with thread_struct elements.
- *
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 2000  MIPS Technologies, Inc.  All rights reserved.
- */
-#include <linux/config.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-
-#include <asm/asm.h>
-#include <asm/branch.h>
-#include <asm/bootinfo.h>
-#include <asm/byteorder.h>
-#include <asm/cpu.h>
-#include <asm/inst.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-#include <asm/mipsregs.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-
-#include <asm/fpu_emulator.h>
-
-#include "ieee754.h"
-
-/* Strap kernel emulator for full MIPS IV emulation */
-
-#ifdef __mips
-#undef __mips
-#endif
-#define __mips 4
-
-typedef void *vaddr_t;
-
-/* Function which emulates the instruction in a branch delay slot. */
-
-static int mips_dsemul(struct pt_regs *, mips_instruction, vaddr_t);
-
-/* Function which emulates a floating point instruction. */
-
-static int fpu_emu(struct pt_regs *, struct mips_fpu_soft_struct *,
-	 mips_instruction);
-
-#if __mips >= 4 && __mips != 32
-static int fpux_emu(struct pt_regs *,
-		    struct mips_fpu_soft_struct *, mips_instruction);
-#endif
-
-/* Further private data for which no space exists in mips_fpu_soft_struct */
-
-struct mips_fpu_emulator_private fpuemuprivate;
-
-/* Control registers */
-
-#define FPCREG_RID	0	/* $0  = revision id */
-#define FPCREG_CSR	31	/* $31 = csr */
-
-/* Convert Mips rounding mode (0..3) to IEEE library modes. */
-static const unsigned char ieee_rm[4] = {
-	IEEE754_RN, IEEE754_RZ, IEEE754_RU, IEEE754_RD
-};
-
-#if __mips >= 4
-/* convert condition code register number to csr bit */
-static const unsigned int fpucondbit[8] = {
-	FPU_CSR_COND0,
-	FPU_CSR_COND1,
-	FPU_CSR_COND2,
-	FPU_CSR_COND3,
-	FPU_CSR_COND4,
-	FPU_CSR_COND5,
-	FPU_CSR_COND6,
-	FPU_CSR_COND7
-};
-#endif
-
-
-
-/* 
- * Redundant with logic already in kernel/branch.c,
- * embedded in compute_return_epc.  At some point,
- * a single subroutine should be used across both
- * modules.
- */
-static int isBranchInstr(mips_instruction * i)
-{
-	switch (MIPSInst_OPCODE(*i)) {
-	case spec_op:
-		switch (MIPSInst_FUNC(*i)) {
-		case jalr_op:
-		case jr_op:
-			return 1;
-		}
-		break;
-
-	case bcond_op:
-		switch (MIPSInst_RT(*i)) {
-		case bltz_op:
-		case bgez_op:
-		case bltzl_op:
-		case bgezl_op:
-		case bltzal_op:
-		case bgezal_op:
-		case bltzall_op:
-		case bgezall_op:
-			return 1;
-		}
-		break;
-
-	case j_op:
-	case jal_op:
-	case jalx_op:
-	case beq_op:
-	case bne_op:
-	case blez_op:
-	case bgtz_op:
-	case beql_op:
-	case bnel_op:
-	case blezl_op:
-	case bgtzl_op:
-		return 1;
-
-	case cop0_op:
-	case cop1_op:
-	case cop2_op:
-	case cop1x_op:
-		if (MIPSInst_RS(*i) == bc_op)
-			return 1;
-		break;
-	}
-
-	return 0;
-}
-
-#define REG_TO_VA (vaddr_t)
-#define VA_TO_REG (unsigned long)
-
-static unsigned long
-mips_get_word(struct pt_regs *xcp, void *va, int *perr)
-{
-	unsigned long temp;
-
-	if (!user_mode(xcp)) {
-		*perr = 0;
-		return (*(unsigned long *) va);
-	} else {
-		/* Use kernel get_user() macro */
-		*perr = (int) get_user(temp, (unsigned long *) va);
-		return temp;
-	}
-}
-
-static unsigned long long
-mips_get_dword(struct pt_regs *xcp, void *va, int *perr)
-{
-	unsigned long long temp;
-
-	if (!user_mode(xcp)) {
-		*perr = 0;
-		return (*(unsigned long long *) va);
-	} else {
-		/* Use kernel get_user() macro */
-		*perr = (int) get_user(temp, (unsigned long long *) va);
-		return temp;
-	}
-}
-
-static int mips_put_word(struct pt_regs *xcp, void *va, unsigned long val)
-{
-	if (!user_mode(xcp)) {
-		*(unsigned long *) va = val;
-		return 0;
-	} else {
-		/* Use kernel get_user() macro */
-		return (int) put_user(val, (unsigned long *) va);
-	}
-}
-
-static int mips_put_dword(struct pt_regs *xcp, void *va, long long val)
-{
-	if (!user_mode(xcp)) {
-		*(unsigned long long *) va = val;
-		return 0;
-	} else {
-		/* Use kernel get_user() macro */
-		return (int) put_user(val, (unsigned long long *) va);
-	}
-}
-
-
-/*
- * In the Linux kernel, we support selection of FPR format on the
- * basis of the Status.FR bit.  This does imply that, if a full 32
- * FPRs are desired, there needs to be a flip-flop that can be written
- * to one at that bit position.  In any case, normal MIPS ABI uses
- * only the even FPRs (Status.FR = 0).
- */
-
-#define CP0_STATUS_FR_SUPPORT
-
-/*
- * Emulate the single floating point instruction pointed at by EPC.
- * Two instructions if the instruction is in a branch delay slot.
- */
-
-static int
-cop1Emulate(int xcptno, struct pt_regs *xcp,
-	    struct mips_fpu_soft_struct *ctx)
-{
-	mips_instruction ir;
-	vaddr_t emulpc;
-	vaddr_t contpc;
-	unsigned int cond;
-	int err = 0;
-
-
-	ir = mips_get_word(xcp, REG_TO_VA xcp->cp0_epc, &err);
-	if (err) {
-		fpuemuprivate.stats.errors++;
-		return SIGBUS;
-	}
-
-	/* XXX NEC Vr54xx bug workaround */
-	if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir))
-		xcp->cp0_cause &= ~CAUSEF_BD;
-
-	if (xcp->cp0_cause & CAUSEF_BD) {
-		/*
-		 * The instruction to be emulated is in a branch delay slot
-		 * which means that we have to  emulate the branch instruction
-		 * BEFORE we do the cop1 instruction. 
-		 *
-		 * This branch could be a COP1 branch, but in that case we
-		 * would have had a trap for that instruction, and would not
-		 * come through this route.
-		 *
-		 * Linux MIPS branch emulator operates on context, updating the
-		 * cp0_epc.
-		 */
-		emulpc = REG_TO_VA(xcp->cp0_epc + 4);	/* Snapshot emulation target */
-
-		if (__compute_return_epc(xcp)) {
-#ifdef CP1DBG
-			printk("failed to emulate branch at %p\n",
-				    REG_TO_VA(xcp->cp0_epc));
-#endif
-			return SIGILL;;
-		}
-		ir = mips_get_word(xcp, emulpc, &err);
-		if (err) {
-			fpuemuprivate.stats.errors++;
-			return SIGBUS;
-		}
-		contpc = REG_TO_VA xcp->cp0_epc;
-	} else {
-		emulpc = REG_TO_VA xcp->cp0_epc;
-		contpc = REG_TO_VA xcp->cp0_epc + 4;
-	}
-
-      emul:
-	fpuemuprivate.stats.emulated++;
-	switch (MIPSInst_OPCODE(ir)) {
-#ifdef CP0_STATUS_FR_SUPPORT
-		/* R4000+ 64-bit fpu registers */
-#ifndef SINGLE_ONLY_FPU
-	case ldc1_op:
-		{
-			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
-			    + MIPSInst_SIMM(ir);
-			int ft = MIPSInst_RT(ir);
-			if (!(xcp->cp0_status & ST0_FR))
-				ft &= ~1;
-			ctx->regs[ft] = mips_get_dword(xcp, va, &err);
-			fpuemuprivate.stats.loads++;
-			if (err) {
-				fpuemuprivate.stats.errors++;
-				return SIGBUS;
-			}
-		}
-		break;
-
-	case sdc1_op:
-		{
-			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
-			    + MIPSInst_SIMM(ir);
-			int ft = MIPSInst_RT(ir);
-			if (!(xcp->cp0_status & ST0_FR))
-				ft &= ~1;
-			fpuemuprivate.stats.stores++;
-			if (mips_put_dword(xcp, va, ctx->regs[ft])) {
-				fpuemuprivate.stats.errors++;
-				return SIGBUS;
-			}
-		}
-		break;
-#endif
-
-	case lwc1_op:
-		{
-			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
-			    + MIPSInst_SIMM(ir);
-			fpureg_t val;
-			int ft = MIPSInst_RT(ir);
-			fpuemuprivate.stats.loads++;
-			val = mips_get_word(xcp, va, &err);
-			if (err) {
-				fpuemuprivate.stats.errors++;
-				return SIGBUS;
-			}
-			if (xcp->cp0_status & ST0_FR) {
-				/* load whole register */
-				ctx->regs[ft] = val;
-			} else if (ft & 1) {
-				/* load to m.s. 32 bits */
-#ifdef SINGLE_ONLY_FPU
-				/* illegal register in single-float mode */
-				return SIGILL;
-#else
-				ctx->regs[(ft & ~1)] &= 0xffffffff;
-				ctx->regs[(ft & ~1)] |= val << 32;
-#endif
-			} else {
-				/* load to l.s. 32 bits */
-				ctx->regs[ft] &= ~0xffffffffLL;
-				ctx->regs[ft] |= val;
-			}
-		}
-		break;
-
-	case swc1_op:
-		{
-			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
-			    + MIPSInst_SIMM(ir);
-			unsigned int val;
-			int ft = MIPSInst_RT(ir);
-			fpuemuprivate.stats.stores++;
-			if (xcp->cp0_status & ST0_FR) {
-				/* store whole register */
-				val = ctx->regs[ft];
-			} else if (ft & 1) {
-#ifdef SINGLE_ONLY_FPU
-				/* illegal register in single-float mode */
-				return SIGILL;
-#else
-				/* store from m.s. 32 bits */
-				val = ctx->regs[(ft & ~1)] >> 32;
-#endif
-			} else {
-				/* store from l.s. 32 bits */
-				val = ctx->regs[ft];
-			}
-			if (mips_put_word(xcp, va, val)) {
-				fpuemuprivate.stats.errors++;
-				return SIGBUS;
-			}
-		}
-		break;
-#else				/* old 32-bit fpu registers */
-	case lwc1_op:
-		{
-			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
-			    + MIPSInst_SIMM(ir);
-			ctx->regs[MIPSInst_RT(ir)] =
-			    mips_get_word(xcp, va, &err);
-			fpuemuprivate.stats.loads++;
-			if (err) {
-				fpuemuprivate.stats.errors++;
-				return SIGBUS;
-			}
-		}
-		break;
-
-	case swc1_op:
-		{
-			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
-			    + MIPSInst_SIMM(ir);
-			fpuemuprivate.stats.stores++;
-			if (mips_put_word
-			    (xcp, va, ctx->regs[MIPSInst_RT(ir)])) {
-				fpuemuprivate.stats.errors++;
-				return SIGBUS;
-			}
-		}
-		break;
-	case ldc1_op:
-		{
-			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
-			    + MIPSInst_SIMM(ir);
-			unsigned int rt = MIPSInst_RT(ir) & ~1;
-			int errs = 0;
-			fpuemuprivate.stats.loads++;
-#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
-			ctx->regs[rt + 1] =
-			    mips_get_word(xcp, va + 0, &err);
-			errs += err;
-			ctx->regs[rt + 0] =
-			    mips_get_word(xcp, va + 4, &err);
-			errs += err;
-#else
-			ctx->regs[rt + 0] =
-			    mips_get_word(xcp, va + 0, &err);
-			errs += err;
-			ctx->regs[rt + 1] =
-			    mips_get_word(xcp, va + 4, &err);
-			errs += err;
-#endif
-			if (err)
-				return SIGBUS;
-		}
-		break;
-
-	case sdc1_op:
-		{
-			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
-			    + MIPSInst_SIMM(ir);
-			unsigned int rt = MIPSInst_RT(ir) & ~1;
-			fpuemuprivate.stats.stores++;
-#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
-			if (mips_put_word(xcp, va + 0, ctx->regs[rt + 1]))
-				return SIGBUS;
-			if (mips_put_word(xcp, va + 4, ctx->regs[rt + 0]))
-				return SIGBUS;
-#else
-			if (mips_put_word(xcp, va + 0, ctx->regs[rt + 0]))
-				return SIGBUS;
-			if (mips_put_word(xcp, va + 4, ctx->regs[rt + 1]))
-				return SIGBUS;
-#endif
-		}
-		break;
-#endif
-
-	case cop1_op:
-		switch (MIPSInst_RS(ir)) {
-
-#ifdef CP0_STATUS_FR_SUPPORT
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
-		case dmfc_op:
-			/* copregister fs -> gpr[rt] */
-			if (MIPSInst_RT(ir) != 0) {
-				int fs = MIPSInst_RD(ir);
-				if (!(xcp->cp0_status & ST0_FR))
-					fs &= ~1;
-				xcp->regs[MIPSInst_RT(ir)] = ctx->regs[fs];
-			}
-			break;
-
-		case dmtc_op:
-			/* copregister fs <- rt */
-			{
-				fpureg_t value;
-				int fs = MIPSInst_RD(ir);
-				if (!(xcp->cp0_status & ST0_FR))
-					fs &= ~1;
-				value =
-				    (MIPSInst_RT(ir) ==
-				     0) ? 0 : xcp->regs[MIPSInst_RT(ir)];
-				ctx->regs[fs] = value;
-			}
-			break;
-#endif
-
-		case mfc_op:
-			/* copregister rd -> gpr[rt] */
-			if (MIPSInst_RT(ir) != 0) {
-				/* default value from l.s. 32 bits */
-				int value = ctx->regs[MIPSInst_RD(ir)];
-				if (MIPSInst_RD(ir) & 1) {
-#ifdef SINGLE_ONLY_FPU
-					/* illegal register in single-float mode */
-					return SIGILL;
-#else
-					if (!(xcp->cp0_status & ST0_FR)) {
-						/* move from m.s. 32 bits */
-						value =
-						    ctx->
-						    regs[MIPSInst_RD(ir) &
-							 ~1] >> 32;
-					}
-#endif
-				}
-				xcp->regs[MIPSInst_RT(ir)] = value;
-			}
-			break;
-
-		case mtc_op:
-			/* copregister rd <- rt */
-			{
-				fpureg_t value;
-				if (MIPSInst_RT(ir) == 0)
-					value = 0;
-				else
-					value =
-					    (unsigned int) xcp->
-					    regs[MIPSInst_RT(ir)];
-				if (MIPSInst_RD(ir) & 1) {
-#ifdef SINGLE_ONLY_FPU
-					/* illegal register in single-float mode */
-					return SIGILL;
-#else
-					if (!(xcp->cp0_status & ST0_FR)) {
-						/* move to m.s. 32 bits */
-						ctx->
-						    regs[
-							 (MIPSInst_RD(ir) &
-							  ~1)] &=
-						    0xffffffff;
-						ctx->
-						    regs[
-							 (MIPSInst_RD(ir) &
-							  ~1)] |=
-						    value << 32;
-						break;
-					}
-#endif
-				}
-				/* move to l.s. 32 bits */
-				ctx->regs[MIPSInst_RD(ir)] &=
-				    ~0xffffffffLL;
-				ctx->regs[MIPSInst_RD(ir)] |= value;
-			}
-			break;
-#else
-
-		case mfc_op:
-			/* copregister rd -> gpr[rt] */
-			if (MIPSInst_RT(ir) != 0) {
-				unsigned value =
-				    ctx->regs[MIPSInst_RD(ir)];
-				xcp->regs[MIPSInst_RT(ir)] = value;
-			}
-			break;
-
-		case mtc_op:
-			/* copregister rd <- rt */
-			{
-				unsigned value;
-				value =
-				    (MIPSInst_RT(ir) ==
-				     0) ? 0 : xcp->regs[MIPSInst_RT(ir)];
-				ctx->regs[MIPSInst_RD(ir)] = value;
-			}
-			break;
-#endif
-
-		case cfc_op:
-			/* cop control register rd -> gpr[rt] */
-			{
-				unsigned value;
-
-				if (MIPSInst_RD(ir) == FPCREG_CSR) {
-					value = ctx->sr;
-#ifdef CSRTRACE
-					printk
-					    ("%p gpr[%d]<-csr=%08x\n",
-					     REG_TO_VA(xcp->cp0_epc),
-					     MIPSInst_RT(ir), value);
-#endif
-				} else if (MIPSInst_RD(ir) == FPCREG_RID)
-					value = 0;
-				else
-					value = 0;
-				if (MIPSInst_RT(ir))
-					xcp->regs[MIPSInst_RT(ir)] = value;
-			}
-			break;
-
-		case ctc_op:
-			/* copregister rd <- rt */
-			{
-				unsigned value;
-
-				if (MIPSInst_RT(ir) == 0)
-					value = 0;
-				else
-					value = xcp->regs[MIPSInst_RT(ir)];
-
-				/* we only have one writable control reg
-				 */
-				if (MIPSInst_RD(ir) == FPCREG_CSR) {
-#ifdef CSRTRACE
-					printk
-					    ("%p gpr[%d]->csr=%08x\n",
-					     REG_TO_VA(xcp->cp0_epc),
-					     MIPSInst_RT(ir), value);
-#endif
-					ctx->sr = value;
-					/* copy new rounding mode to ieee library state! */
-					ieee754_csr.rm =
-					    ieee_rm[value & 0x3];
-				}
-			}
-			break;
-
-		case bc_op:
-			if (xcp->cp0_cause & CAUSEF_BD) {
-				return SIGILL;
-			}
-			{
-				int likely = 0;
-
-#if __mips >= 4
-				cond =
-				    ctx->
-				    sr & fpucondbit[MIPSInst_RT(ir) >> 2];
-#else
-				cond = ctx->sr & FPU_CSR_COND;
-#endif
-				switch (MIPSInst_RT(ir) & 3) {
-				case bcfl_op:
-					likely = 1;
-				case bcf_op:
-					cond = !cond;
-					break;
-				case bctl_op:
-					likely = 1;
-				case bct_op:
-					break;
-				default:
-					/* thats an illegal instruction */
-					return SIGILL;
-				}
-
-				xcp->cp0_cause |= CAUSEF_BD;
-				if (cond) {
-					/* branch taken: emulate dslot instruction */
-					xcp->cp0_epc += 4;
-					contpc =
-					    REG_TO_VA xcp->cp0_epc +
-					    (MIPSInst_SIMM(ir) << 2);
-
-					ir =
-					    mips_get_word(xcp,
-							  REG_TO_VA(xcp->
-								    cp0_epc),
-							  &err);
-					if (err) {
-						fpuemuprivate.stats.
-						    errors++;
-						return SIGBUS;
-					}
-
-					switch (MIPSInst_OPCODE(ir)) {
-					case lwc1_op:
-					case swc1_op:
-#if (__mips >= 2 || __mips64) && !defined(SINGLE_ONLY_FPU)
-					case ldc1_op:
-					case sdc1_op:
-#endif
-					case cop1_op:
-#if __mips >= 4 && __mips != 32
-					case cop1x_op:
-#endif
-						/* its one of ours */
-						goto emul;
-#if __mips >= 4
-					case spec_op:
-						if (MIPSInst_FUNC(ir) ==
-						    movc_op) goto emul;
-						break;
-#endif
-					}
-
-					/* single step the non-cp1 instruction in the dslot */
-					return mips_dsemul(xcp, ir, contpc);
-				} else {
-					/* branch not taken */
-					if (likely)
-						/* branch likely nullifies dslot if not taken */
-						xcp->cp0_epc += 4;
-					/* else continue & execute dslot as normal insn */
-				}
-			}
-			break;
-
-		default:
-			if (!(MIPSInst_RS(ir) & 0x10)) {
-				return SIGILL;
-			}
-			/* a real fpu computation instruction */
-			{
-				int sig;
-				if ((sig = fpu_emu(xcp, ctx, ir)))
-					return sig;
-			}
-		}
-		break;
-
-#if __mips >= 4 && __mips != 32
-	case cop1x_op:
-		{
-			int sig;
-			if ((sig = fpux_emu(xcp, ctx, ir)))
-				return sig;
-		}
-		break;
-#endif
-
-#if __mips >= 4
-	case spec_op:
-		if (MIPSInst_FUNC(ir) != movc_op)
-			return SIGILL;
-		cond = fpucondbit[MIPSInst_RT(ir) >> 2];
-		if (((ctx->sr & cond) != 0) !=
-		    ((MIPSInst_RT(ir) & 1) != 0)) return 0;
-		xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)];
-		break;
-#endif
-
-	default:
-		return SIGILL;
-	}
-
-	/* we did it !! */
-	xcp->cp0_epc = VA_TO_REG(contpc);
-	xcp->cp0_cause &= ~CAUSEF_BD;
-	return 0;
-}
-
-/*
- * Emulate the arbritrary instruction ir at xcp->cp0_epc.  Required when
- * we have to emulate the instruction in a COP1 branch delay slot.  Do
- * not change cp0_epc due to the instruction
- *
- * According to the spec:
- * 1) it shouldnt be a branch :-)
- * 2) it can be a COP instruction :-(
- * 3) if we are tring to run a protected memory space we must take
- *    special care on memory access instructions :-(
- */
-
-/*
- * "Trampoline" return routine to catch exception following
- *  execution of delay-slot instruction execution.
- */
-
-int do_dsemulret(struct pt_regs *xcp)
-{
-#ifdef DSEMUL_TRACE
-	printk("desemulret\n");
-#endif
-	/* Set EPC to return to post-branch instruction */
-	xcp->cp0_epc = current->thread.dsemul_epc;
-	/*
-	 * Clear the state that got us here.
-	 */
-	current->thread.dsemul_aerpc = (unsigned long) 0;
-
-	return 0;
-}
-
-
-#define AdELOAD 0x8c000001	/* lw $0,1($0) */
-
-static int
-mips_dsemul(struct pt_regs *xcp, mips_instruction ir, vaddr_t cpc)
-{
-	mips_instruction *dsemul_insns;
-	mips_instruction forcetrap;
-	extern asmlinkage void handle_dsemulret(void);
-
-	if (ir == 0) {		/* a nop is easy */
-		xcp->cp0_epc = VA_TO_REG(cpc);
-		return 0;
-	}
-#ifdef DSEMUL_TRACE
-	printk("desemul %p %p\n", REG_TO_VA(xcp->cp0_epc), cpc);
-#endif
-
-	/* 
-	 * The strategy is to push the instruction onto the user stack 
-	 * and put a trap after it which we can catch and jump to 
-	 * the required address any alternative apart from full 
-	 * instruction emulation!!.
-	 */
-	dsemul_insns = (mips_instruction *) (xcp->regs[29] & ~3);
-	dsemul_insns -= 3;	/* Two instructions, plus one for luck ;-) */
-	/* Verify that the stack pointer is not competely insane */
-	if (verify_area
-	    (VERIFY_WRITE, dsemul_insns, sizeof(mips_instruction) * 2))
-		return SIGBUS;
-
-	if (mips_put_word(xcp, &dsemul_insns[0], ir)) {
-		fpuemuprivate.stats.errors++;
-		return (SIGBUS);
-	}
-
-	/* 
-	 * Algorithmics used a system call instruction, and
-	 * borrowed that vector.  MIPS/Linux version is a bit
-	 * more heavyweight in the interests of portability and
-	 * multiprocessor support.  We flag the thread for special
-	 * handling in the unaligned access handler and force an
-	 * address error excpetion.
-	 */
-
-	/* If one is *really* paranoid, one tests for a bad stack pointer */
-	if ((xcp->regs[29] & 0x3) == 0x3)
-		forcetrap = AdELOAD - 1;
-	else
-		forcetrap = AdELOAD;
-
-	if (mips_put_word(xcp, &dsemul_insns[1], forcetrap)) {
-		fpuemuprivate.stats.errors++;
-		return (SIGBUS);
-	}
-
-	/* Set thread state to catch and handle the exception */
-	current->thread.dsemul_epc = (unsigned long) cpc;
-	current->thread.dsemul_aerpc = (unsigned long) &dsemul_insns[1];
-	xcp->cp0_epc = VA_TO_REG & dsemul_insns[0];
-	flush_cache_sigtramp((unsigned long) dsemul_insns);
-
-	return SIGILL;		/* force out of emulation loop */
-}
-
-/* 
- * Conversion table from MIPS compare ops 48-63
- * cond = ieee754dp_cmp(x,y,IEEE754_UN);
- */
-static const unsigned char cmptab[8] = {
-	0,					/* cmp_0 (sig) cmp_sf */
-	IEEE754_CUN,				/* cmp_un (sig) cmp_ngle */
-	IEEE754_CEQ,				/* cmp_eq (sig) cmp_seq */
-	IEEE754_CEQ | IEEE754_CUN,		/* cmp_ueq (sig) cmp_ngl  */
-	IEEE754_CLT,				/* cmp_olt (sig) cmp_lt */
-	IEEE754_CLT | IEEE754_CUN,		/* cmp_ult (sig) cmp_nge */
-	IEEE754_CLT | IEEE754_CEQ,		/* cmp_ole (sig) cmp_le */
-	IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */
-};
-
-#define SIFROMREG(si,x)	((si) = ctx->regs[x])
-#define SITOREG(si,x)	(ctx->regs[x] = (int)(si))
-
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
-#define DIFROMREG(di,x)	((di) = ctx->regs[x])
-#define DITOREG(di,x)	(ctx->regs[x] = (di))
-#endif
-
-#define SPFROMREG(sp,x)	((sp).bits = ctx->regs[x])
-#define SPTOREG(sp,x)	(ctx->regs[x] = (sp).bits)
-
-#ifdef CP0_STATUS_FR_SUPPORT
-#define DPFROMREG(dp,x)	((dp).bits = \
-			ctx->regs[(xcp->cp0_status & ST0_FR) ? x : (x & ~1)])
-#define DPTOREG(dp,x)	(ctx->regs[(xcp->cp0_status & ST0_FR) ? x : (x & ~1)]\
-			= (dp).bits)
-#else
-/* Beware: MIPS COP1 doubles are always little_word endian in registers */
-#define DPFROMREG(dp,x)	\
-  ((dp).bits = ((unsigned long long)ctx->regs[(x)+1] << 32) | ctx->regs[x])
-#define DPTOREG(dp,x) \
-  (ctx->regs[x] = (dp).bits, ctx->regs[(x)+1] = (dp).bits >> 32)
-#endif
-
-#if __mips >= 4 && __mips != 32
-
-/*
- * Additional MIPS4 instructions
- */
-
-static ieee754dp fpemu_dp_recip(ieee754dp d)
-{
-	return ieee754dp_div(ieee754dp_one(0), d);
-}
-
-static ieee754dp fpemu_dp_rsqrt(ieee754dp d)
-{
-	return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d));
-}
-
-static ieee754sp fpemu_sp_recip(ieee754sp s)
-{
-	return ieee754sp_div(ieee754sp_one(0), s);
-}
-
-static ieee754sp fpemu_sp_rsqrt(ieee754sp s)
-{
-	return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s));
-}
-
-
-static ieee754dp fpemu_dp_madd(ieee754dp r, ieee754dp s, ieee754dp t)
-{
-	return ieee754dp_add(ieee754dp_mul(s, t), r);
-}
-
-static ieee754dp fpemu_dp_msub(ieee754dp r, ieee754dp s, ieee754dp t)
-{
-	return ieee754dp_sub(ieee754dp_mul(s, t), r);
-}
-
-static ieee754dp fpemu_dp_nmadd(ieee754dp r, ieee754dp s, ieee754dp t)
-{
-	return ieee754dp_neg(ieee754dp_add(ieee754dp_mul(s, t), r));
-}
-
-static ieee754dp fpemu_dp_nmsub(ieee754dp r, ieee754dp s, ieee754dp t)
-{
-	return ieee754dp_neg(ieee754dp_sub(ieee754dp_mul(s, t), r));
-}
-
-
-static ieee754sp fpemu_sp_madd(ieee754sp r, ieee754sp s, ieee754sp t)
-{
-	return ieee754sp_add(ieee754sp_mul(s, t), r);
-}
-
-static ieee754sp fpemu_sp_msub(ieee754sp r, ieee754sp s, ieee754sp t)
-{
-	return ieee754sp_sub(ieee754sp_mul(s, t), r);
-}
-
-static ieee754sp fpemu_sp_nmadd(ieee754sp r, ieee754sp s, ieee754sp t)
-{
-	return ieee754sp_neg(ieee754sp_add(ieee754sp_mul(s, t), r));
-}
-
-static ieee754sp fpemu_sp_nmsub(ieee754sp r, ieee754sp s, ieee754sp t)
-{
-	return ieee754sp_neg(ieee754sp_sub(ieee754sp_mul(s, t), r));
-}
-
-static int
-fpux_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
-	 mips_instruction ir)
-{
-	unsigned rcsr = 0;	/* resulting csr */
-
-	fpuemuprivate.stats.cp1xops++;
-
-	switch (MIPSInst_FMA_FFMT(ir)) {
-	case s_fmt:		/* 0 */
-		{
-			ieee754sp(*handler) (ieee754sp, ieee754sp,
-					     ieee754sp);
-			ieee754sp fd, fr, fs, ft;
-
-			switch (MIPSInst_FUNC(ir)) {
-			case lwxc1_op:
-				{
-					void *va =
-					    REG_TO_VA(xcp->
-						      regs[MIPSInst_FR(ir)]
-						      +
-						      xcp->
-						      regs[MIPSInst_FT
-							   (ir)]);
-					fpureg_t val;
-					int err = 0;
-					val = mips_get_word(xcp, va, &err);
-					if (err) {
-						fpuemuprivate.stats.
-						    errors++;
-						return SIGBUS;
-					}
-					if (xcp->cp0_status & ST0_FR) {
-						/* load whole register */
-						ctx->
-						    regs[MIPSInst_FD(ir)] =
-						    val;
-					} else if (MIPSInst_FD(ir) & 1) {
-						/* load to m.s. 32 bits */
-#if defined(SINGLE_ONLY_FPU)
-						/* illegal register in single-float mode */
-						return SIGILL;
-#else
-						ctx->
-						    regs[
-							 (MIPSInst_FD(ir) &
-							  ~1)] &=
-						    0xffffffff;
-						ctx->
-						    regs[
-							 (MIPSInst_FD(ir) &
-							  ~1)] |=
-						    val << 32;
-#endif
-					} else {
-						/* load to l.s. 32 bits */
-						ctx->
-						    regs[MIPSInst_FD(ir)]
-						    &= ~0xffffffffLL;
-						ctx->
-						    regs[MIPSInst_FD(ir)]
-						    |= val;
-					}
-				}
-				break;
-
-			case swxc1_op:
-				{
-					void *va =
-					    REG_TO_VA(xcp->
-						      regs[MIPSInst_FR(ir)]
-						      +
-						      xcp->
-						      regs[MIPSInst_FT
-							   (ir)]);
-					unsigned int val;
-					if (xcp->cp0_status & ST0_FR) {
-						/* store whole register */
-						val =
-						    ctx->
-						    regs[MIPSInst_FS(ir)];
-					} else if (MIPSInst_FS(ir) & 1) {
-#if defined(SINGLE_ONLY_FPU)
-						/* illegal register in single-float mode */
-						return SIGILL;
-#else
-						/* store from m.s. 32 bits */
-						val =
-						    ctx->
-						    regs[
-							 (MIPSInst_FS(ir) &
-							  ~1)] >> 32;
-#endif
-					} else {
-						/* store from l.s. 32 bits */
-						val =
-						    ctx->
-						    regs[MIPSInst_FS(ir)];
-					}
-					if (mips_put_word(xcp, va, val)) {
-						fpuemuprivate.stats.
-						    errors++;
-						return SIGBUS;
-					}
-				}
-				break;
-
-			case madd_s_op:
-				handler = fpemu_sp_madd;
-				goto scoptop;
-			case msub_s_op:
-				handler = fpemu_sp_msub;
-				goto scoptop;
-			case nmadd_s_op:
-				handler = fpemu_sp_nmadd;
-				goto scoptop;
-			case nmsub_s_op:
-				handler = fpemu_sp_nmsub;
-				goto scoptop;
-
-			      scoptop:
-				SPFROMREG(fr, MIPSInst_FR(ir));
-				SPFROMREG(fs, MIPSInst_FS(ir));
-				SPFROMREG(ft, MIPSInst_FT(ir));
-				fd = (*handler) (fr, fs, ft);
-				SPTOREG(fd, MIPSInst_FD(ir));
-
-			      copcsr:
-				if (ieee754_cxtest(IEEE754_INEXACT))
-					rcsr |=
-					    FPU_CSR_INE_X | FPU_CSR_INE_S;
-				if (ieee754_cxtest(IEEE754_UNDERFLOW))
-					rcsr |=
-					    FPU_CSR_UDF_X | FPU_CSR_UDF_S;
-				if (ieee754_cxtest(IEEE754_OVERFLOW))
-					rcsr |=
-					    FPU_CSR_OVF_X | FPU_CSR_OVF_S;
-				if (ieee754_cxtest
-				    (IEEE754_INVALID_OPERATION)) rcsr |=
-					    FPU_CSR_INV_X | FPU_CSR_INV_S;
-
-				ctx->sr =
-				    (ctx->sr & ~FPU_CSR_ALL_X) | rcsr;
-				if ((ctx->sr >> 5) & ctx->
-				    sr & FPU_CSR_ALL_E) {
-		/*printk ("SIGFPE: fpu csr = %08x\n",ctx->sr); */
-					return SIGFPE;
-				}
-
-				break;
-
-			default:
-				return SIGILL;
-			}
-		}
-		break;
-
-#if !defined(SINGLE_ONLY_FPU)
-	case d_fmt:		/* 1 */
-		{
-			ieee754dp(*handler) (ieee754dp, ieee754dp,
-					     ieee754dp);
-			ieee754dp fd, fr, fs, ft;
-
-			switch (MIPSInst_FUNC(ir)) {
-			case ldxc1_op:
-				{
-					void *va =
-					    REG_TO_VA(xcp->
-						      regs[MIPSInst_FR(ir)]
-						      +
-						      xcp->
-						      regs[MIPSInst_FT
-							   (ir)]);
-					int err = 0;
-					ctx->regs[MIPSInst_FD(ir)] =
-					    mips_get_dword(xcp, va, &err);
-					if (err) {
-						fpuemuprivate.stats.
-						    errors++;
-						return SIGBUS;
-					}
-				}
-				break;
-
-			case sdxc1_op:
-				{
-					void *va =
-					    REG_TO_VA(xcp->
-						      regs[MIPSInst_FR(ir)]
-						      +
-						      xcp->
-						      regs[MIPSInst_FT
-							   (ir)]);
-					if (mips_put_dword
-					    (xcp, va,
-					     ctx->regs[MIPSInst_FS(ir)])) {
-						fpuemuprivate.stats.
-						    errors++;
-						return SIGBUS;
-					}
-				}
-				break;
-
-			case madd_d_op:
-				handler = fpemu_dp_madd;
-				goto dcoptop;
-			case msub_d_op:
-				handler = fpemu_dp_msub;
-				goto dcoptop;
-			case nmadd_d_op:
-				handler = fpemu_dp_nmadd;
-				goto dcoptop;
-			case nmsub_d_op:
-				handler = fpemu_dp_nmsub;
-				goto dcoptop;
-
-			      dcoptop:
-				DPFROMREG(fr, MIPSInst_FR(ir));
-				DPFROMREG(fs, MIPSInst_FS(ir));
-				DPFROMREG(ft, MIPSInst_FT(ir));
-				fd = (*handler) (fr, fs, ft);
-				DPTOREG(fd, MIPSInst_FD(ir));
-				goto copcsr;
-
-			default:
-				return SIGILL;
-			}
-		}
-		break;
-#endif
-
-	case 0x7:		/* 7 */
-		{
-			if (MIPSInst_FUNC(ir) != pfetch_op) {
-				return SIGILL;
-			}
-			/* ignore prefx operation */
-		}
-		break;
-
-	default:
-		return SIGILL;
-	}
-
-	return 0;
-}
-#endif
-
-
-
-/*
- * Emulate a single COP1 arithmetic instruction.
- */
-static int
-fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
-	mips_instruction ir)
-{
-	int rfmt;		/* resulting format */
-	unsigned rcsr = 0;	/* resulting csr */
-	unsigned cond;
-	union {
-		ieee754dp d;
-		ieee754sp s;
-		int w;
-#if __mips64
-		long long l;
-#endif
-	} rv;			/* resulting value */
-
-	fpuemuprivate.stats.cp1ops++;
-	switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) {
-
-	case s_fmt:{		/* 0 */
-		ieee754sp(*handler) ();
-
-		switch (MIPSInst_FUNC(ir)) {
-			/* binary ops */
-		case fadd_op:
-			handler = ieee754sp_add;
-			goto scopbop;
-		case fsub_op:
-			handler = ieee754sp_sub;
-			goto scopbop;
-		case fmul_op:
-			handler = ieee754sp_mul;
-			goto scopbop;
-		case fdiv_op:
-			handler = ieee754sp_div;
-			goto scopbop;
-
-			/* unary  ops */
-#if __mips >= 2 || __mips64
-		case fsqrt_op:
-			handler = ieee754sp_sqrt;
-			goto scopuop;
-#endif
-#if __mips >= 4 && __mips != 32
-		case frsqrt_op:
-			handler = fpemu_sp_rsqrt;
-			goto scopuop;
-		case frecip_op:
-			handler = fpemu_sp_recip;
-			goto scopuop;
-#endif
-#if __mips >= 4
-		case fmovc_op:
-			cond = fpucondbit[MIPSInst_FT(ir) >> 2];
-			if (((ctx->sr & cond) != 0) !=
-			    ((MIPSInst_FT(ir) & 1) != 0))
-				return 0;
-			SPFROMREG(rv.s, MIPSInst_FS(ir));
-			break;
-		case fmovz_op:
-			if (xcp->regs[MIPSInst_FT(ir)] != 0)
-				return 0;
-			SPFROMREG(rv.s, MIPSInst_FS(ir));
-			break;
-		case fmovn_op:
-			if (xcp->regs[MIPSInst_FT(ir)] == 0)
-				return 0;
-			SPFROMREG(rv.s, MIPSInst_FS(ir));
-			break;
-#endif
-		case fabs_op:
-			handler = ieee754sp_abs;
-			goto scopuop;
-		case fneg_op:
-			handler = ieee754sp_neg;
-			goto scopuop;
-		case fmov_op:
-			/* an easy one */
-			SPFROMREG(rv.s, MIPSInst_FS(ir));
-			break;
-			/* binary op on handler */
-scopbop:
-			{
-				ieee754sp fs, ft;
-
-				SPFROMREG(fs, MIPSInst_FS(ir));
-				SPFROMREG(ft, MIPSInst_FT(ir));
-
-				rv.s = (*handler) (fs, ft);
-				goto copcsr;
-			}
-scopuop:
-			{
-				ieee754sp fs;
-
-				SPFROMREG(fs, MIPSInst_FS(ir));
-				rv.s = (*handler) (fs);
-				goto copcsr;
-			}
-copcsr:
-			if (ieee754_cxtest(IEEE754_INEXACT))
-				rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
-			if (ieee754_cxtest(IEEE754_UNDERFLOW))
-				rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
-			if (ieee754_cxtest(IEEE754_OVERFLOW))
-				rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
-			if (ieee754_cxtest(IEEE754_ZERO_DIVIDE))
-				rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S;
-			if (ieee754_cxtest
-				(IEEE754_INVALID_OPERATION)) rcsr |=
-					    FPU_CSR_INV_X | FPU_CSR_INV_S;
-				break;
-
-				/* unary conv ops */
-		case fcvts_op:
-			return SIGILL;	/* not defined */
-		case fcvtd_op:
-#if defined(SINGLE_ONLY_FPU)
-			return SIGILL;	/* not defined */
-#else
-			{
-				ieee754sp fs;
-
-				SPFROMREG(fs, MIPSInst_FS(ir));
-				rv.d = ieee754dp_fsp(fs);
-				rfmt = d_fmt;
-				goto copcsr;
-			}
-#endif
-		case fcvtw_op:
-			{
-				ieee754sp fs;
-
-				SPFROMREG(fs, MIPSInst_FS(ir));
-				rv.w = ieee754sp_tint(fs);
-				rfmt = w_fmt;
-				goto copcsr;
-			}
-
-#if __mips >= 2 || __mips64
-		case fround_op:
-		case ftrunc_op:
-		case fceil_op:
-		case ffloor_op:
-			{
-				unsigned int oldrm = ieee754_csr.rm;
-				ieee754sp fs;
-
-				SPFROMREG(fs, MIPSInst_FS(ir));
-				ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
-				rv.w = ieee754sp_tint(fs);
-				ieee754_csr.rm = oldrm;
-				rfmt = w_fmt;
-				goto copcsr;
-			}
-#endif			/* __mips >= 2 */
-
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
-		case fcvtl_op:
-			{
-				ieee754sp fs;
-
-				SPFROMREG(fs, MIPSInst_FS(ir));
-				rv.l = ieee754sp_tlong(fs);
-				rfmt = l_fmt;
-				goto copcsr;
-			}
-
-		case froundl_op:
-		case ftruncl_op:
-		case fceill_op:
-		case ffloorl_op:
-			{
-				unsigned int oldrm = ieee754_csr.rm;
-				ieee754sp fs;
-
-				SPFROMREG(fs, MIPSInst_FS(ir));
-				ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
-				rv.l = ieee754sp_tlong(fs);
-				ieee754_csr.rm = oldrm;
-				rfmt = l_fmt;
-				goto copcsr;
-			}
-#endif /* __mips64 && !fpu(single) */
-
-		default:
-			if (MIPSInst_FUNC(ir) >= fcmp_op) {
-				unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
-				ieee754sp fs, ft;
-
-				SPFROMREG(fs, MIPSInst_FS(ir));
-				SPFROMREG(ft, MIPSInst_FT(ir));
-				rv.w = ieee754sp_cmp(fs, ft, cmptab[cmpop & 0x7]);
-				rfmt = -1;
-				if ((cmpop & 0x8) && ieee754_cxtest(IEEE754_INVALID_OPERATION))
-					rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
-				} else {
-					return SIGILL;
-				}
-				break;
-			}
-			break;
-		}
-
-#if !defined(SINGLE_ONLY_FPU)
-	case d_fmt: {
-		ieee754dp(*handler) ();
-
-		switch (MIPSInst_FUNC(ir)) {
-			/* binary ops */
-		case fadd_op:
-			handler = ieee754dp_add;
-			goto dcopbop;
-		case fsub_op:
-			handler = ieee754dp_sub;
-			goto dcopbop;
-		case fmul_op:
-			handler = ieee754dp_mul;
-			goto dcopbop;
-		case fdiv_op:
-			handler = ieee754dp_div;
-			goto dcopbop;
-
-			/* unary  ops */
-#if __mips >= 2 || __mips64
-		case fsqrt_op:
-			handler = ieee754dp_sqrt;
-			goto dcopuop;
-#endif
-#if __mips >= 4 && __mips != 32
-		case frsqrt_op:
-			handler = fpemu_dp_rsqrt;
-			goto dcopuop;
-		case frecip_op:
-			handler = fpemu_dp_recip;
-			goto dcopuop;
-#endif
-#if __mips >= 4
-		case fmovc_op:
-			cond = fpucondbit[MIPSInst_FT(ir) >> 2];
-			if (((ctx->sr & cond) != 0) != ((MIPSInst_FT(ir) & 1) != 0))
-				return 0;
-			DPFROMREG(rv.d, MIPSInst_FS(ir));
-			break;
-		case fmovz_op:
-			if (xcp->regs[MIPSInst_FT(ir)] != 0)
-				return 0;
-			DPFROMREG(rv.d, MIPSInst_FS(ir));
-			break;
-		case fmovn_op:
-			if (xcp->regs[MIPSInst_FT(ir)] == 0)
-				return 0;
-			DPFROMREG(rv.d, MIPSInst_FS(ir));
-			break;
-#endif
-		case fabs_op:
-			handler = ieee754dp_abs;
-			goto dcopuop;
-		case fneg_op:
-			handler = ieee754dp_neg;
-			goto dcopuop;
-		case fmov_op:
-			/* an easy one */
-			DPFROMREG(rv.d, MIPSInst_FS(ir));
-			break;
-
-			/* binary op on handler */
-dcopbop:
-			{
-				ieee754dp fs, ft;
-
-				DPFROMREG(fs, MIPSInst_FS(ir));
-				DPFROMREG(ft, MIPSInst_FT(ir));
-
-				rv.d = (*handler) (fs, ft);
-				goto copcsr;
-			}
-dcopuop:
-			{
-				ieee754dp fs;
-
-				DPFROMREG(fs, MIPSInst_FS(ir));
-				rv.d = (*handler) (fs);
-				goto copcsr;
-			}
-
-		/* unary conv ops */
-		case fcvts_op:
-			{
-				ieee754dp fs;
-
-				DPFROMREG(fs, MIPSInst_FS(ir));
-				rv.s = ieee754sp_fdp(fs);
-				rfmt = s_fmt;
-				goto copcsr;
-			}
-		case fcvtd_op:
-			return SIGILL;	/* not defined */
-		case fcvtw_op:
-			{
-				ieee754dp fs;
-
-				DPFROMREG(fs, MIPSInst_FS(ir));
-				rv.w = ieee754dp_tint(fs);	/* wrong */
-				rfmt = w_fmt;
-				goto copcsr;
-			}
-
-#if __mips >= 2 || __mips64
-		case fround_op:
-		case ftrunc_op:
-		case fceil_op:
-		case ffloor_op:
-			{
-				unsigned int oldrm = ieee754_csr.rm;
-				ieee754dp fs;
-
-				DPFROMREG(fs, MIPSInst_FS(ir));
-				ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
-				rv.w = ieee754dp_tint(fs);
-				ieee754_csr.rm = oldrm;
-				rfmt = w_fmt;
-				goto copcsr;
-			}
-#endif
-
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
-		case fcvtl_op:
-			{
-				ieee754dp fs;
-
-				DPFROMREG(fs, MIPSInst_FS(ir));
-				rv.l = ieee754dp_tlong(fs);
-				rfmt = l_fmt;
-				goto copcsr;
-			}
-
-		case froundl_op:
-		case ftruncl_op:
-		case fceill_op:
-		case ffloorl_op:
-			{
-				unsigned int oldrm = ieee754_csr.rm;
-				ieee754dp fs;
-
-				DPFROMREG(fs, MIPSInst_FS(ir));
-				ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
-				rv.l = ieee754dp_tlong(fs);
-				ieee754_csr.rm = oldrm;
-				rfmt = l_fmt;
-				goto copcsr;
-			}
-#endif /* __mips >= 3 && !fpu(single) */
-
-		default:
-			if (MIPSInst_FUNC(ir) >= fcmp_op) {
-				unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
-				ieee754dp fs, ft;
-
-				DPFROMREG(fs, MIPSInst_FS(ir));
-				DPFROMREG(ft, MIPSInst_FT(ir));
-				rv.w = ieee754dp_cmp(fs, ft, cmptab[cmpop & 0x7]);
-				rfmt = -1;
-				if ((cmpop & 0x8) && ieee754_cxtest (IEEE754_INVALID_OPERATION))
-					rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
-			} else {
-				return SIGILL;
-			}
-			break;
-		}
-		break;
-	}
-#endif				/* !defined(SINGLE_ONLY_FPU) */
-
-	case w_fmt: {
-		switch (MIPSInst_FUNC(ir)) {
-		case fcvts_op:
-			/* convert word to single precision real */
-			rv.s = ieee754sp_fint(ctx-> regs[MIPSInst_FS(ir)]);
-			rfmt = s_fmt;
-			goto copcsr;
-#if !defined(SINGLE_ONLY_FPU)
-		case fcvtd_op:
-			/* convert word to double precision real */
-			rv.d = ieee754dp_fint(ctx-> regs[MIPSInst_FS(ir)]);
-			rfmt = d_fmt;
-			goto copcsr;
-#endif
-		default:
-			return SIGILL;
-		}
-		break;
-	}
-
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
-	case l_fmt: {
-		switch (MIPSInst_FUNC(ir)) {
-		case fcvts_op:
-			/* convert long to single precision real */
-			rv.s = ieee754sp_flong(ctx-> regs[MIPSInst_FS(ir)]);
-			rfmt = s_fmt;
-			goto copcsr;
-		case fcvtd_op:
-			/* convert long to double precision real */
-			rv.d = ieee754dp_flong(ctx-> regs[MIPSInst_FS(ir)]);
-			rfmt = d_fmt;
-			goto copcsr;
-		default:
-			return SIGILL;
-		}
-		break;
-	}
-#endif
-
-	default:
-		return SIGILL;
-	}
-
-	/*
-	 * Update the fpu CSR register for this operation.
-	 * If an exception is required, generate a tidy SIGFPE exception,
-	 * without updating the result register.
-	 * Note: cause exception bits do not accumulate, they are rewritten
-	 * for each op; only the flag/sticky bits accumulate.
-	 */
-	ctx->sr = (ctx->sr & ~FPU_CSR_ALL_X) | rcsr;
-	if ((ctx->sr >> 5) & ctx->sr & FPU_CSR_ALL_E) {
-		/*printk ("SIGFPE: fpu csr = %08x\n",ctx->sr); */
-		return SIGFPE;
-	}
-
-	/* 
-	 * Now we can safely write the result back to the register file.
-	 */
-	switch (rfmt) {
-	case -1: {
-#if __mips >= 4
-		cond = fpucondbit[MIPSInst_FD(ir) >> 2];
-#else
-		cond = FPU_CSR_COND;
-#endif
-		if (rv.w)
-			ctx->sr |= cond;
-		else
-			ctx->sr &= ~cond;
-		break;
-	}
-#if !defined(SINGLE_ONLY_FPU)
-	case d_fmt:
-		DPTOREG(rv.d, MIPSInst_FD(ir));
-		break;
-#endif
-	case s_fmt:
-		SPTOREG(rv.s, MIPSInst_FD(ir));
-		break;
-	case w_fmt:
-		SITOREG(rv.w, MIPSInst_FD(ir));
-		break;
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
-	case l_fmt:
-		DITOREG(rv.l, MIPSInst_FD(ir));
-		break;
-#endif
-	default:
-		return SIGILL;
-	}
-
-	return 0;
-}
-
-
-/*
- * Emulate the floating point instruction at EPC, and continue
- * to run until we hit a non-fp instruction, or a backward
- * branch.  This cuts down dramatically on the per instruction 
- * exception overhead.
- */
-int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp)
-{
-	struct mips_fpu_soft_struct *ctx = &current->thread.fpu.soft;
-	unsigned long oldepc, prevepc;
-	unsigned int insn;
-	int sig = 0;
-	int err = 0;
-
-	oldepc = xcp->cp0_epc;
-	do {
-		if (current->need_resched)
-			schedule();
-
-		prevepc = xcp->cp0_epc;
-		insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err);
-		if (err) {
-			fpuemuprivate.stats.errors++;
-			return SIGBUS;
-		}
-		if (insn != 0)
-			sig = cop1Emulate(xcptno, xcp, ctx);
-		else
-			xcp->cp0_epc += 4;	/* skip nops */
-
-		if (mips_cpu.options & MIPS_CPU_FPU)
-			break;
-	} while (xcp->cp0_epc > prevepc && sig == 0);
-
-	/* SIGILL indicates a non-fpu instruction */
-	if (sig == SIGILL && xcp->cp0_epc != oldepc)
-		/* but if epc has advanced, then ignore it */
-		sig = 0;
-
-	return sig;
-}
-
-
-#ifdef NOTDEF
-/*
- * Patch up the hardware fpu state when an f.p. exception occurs.  
- */
-static int cop1Patcher(int xcptno, struct pt_regs *xcp)
-{
-	struct mips_fpu_soft_struct *ctx = &current->thread.fpu.soft;
-	unsigned sr;
-	int sig;
-
-	/* reenable Cp1, else fpe_save() will get nested exception */
-	sr = mips_bissr(ST0_CU1);
-
-	/* get fpu registers and status, then clear pending exceptions */
-	fpe_save(ctx);
-	fpe_setsr(ctx->sr &= ~FPU_CSR_ALL_X);
-
-	/* get current rounding mode for IEEE library, and emulate insn */
-	ieee754_csr.rm = ieee_rm[ctx->sr & 0x3];
-	sig = cop1Emulate(xcptno, xcp, ctx);
-
-	/* don't return with f.p. exceptions pending */
-	ctx->sr &= ~FPU_CSR_ALL_X;
-	fpe_restore(ctx);
-
-	mips_setsr(sr);
-	return sig;
-}
-
-void _cop1_init(int emulate)
-{
-	extern int _nofpu;
-
-	if (emulate) {
-		/* 
-		 * Install cop1 emulator to handle "coprocessor unusable" exception
-		 */
-		xcption(XCPTCPU, cop1Handler);
-		fpuemuactive = 1;	/* tell dbg.c that we are in charge */
-		_nofpu = 0;	/* tell setjmp() it "has" an fpu */
-	} else {
-		/* 
-		 * Install cop1 emulator for floating point exceptions only,
-		 * i.e. denormalised results, underflow, overflow etc, which
-		 * must be emulated in s/w.
-		 */
-#if 1
-		/* r4000 or above use dedicate exception */
-		xcption(XCPTFPE, cop1Patcher);
-#else
-		/* r3000 et al use interrupt */
-		extern int _sbd_getfpuintr(void);
-		int intno = _sbd_getfpuintr();
-		intrupt(intno, cop1Patcher, 0);
-		mips_bissr(SR_IM0 << intno);
-#endif
-
-#if (#cpu(r4640) || #cpu(r4650)) && !defined(SINGLE_ONLY_FPU)
-		/* For R4640/R4650 compiled *without* the -msingle-float flag,
-		   then we share responsibility: the h/w handles the single
-		   precision operations, and the trap emulator handles the
-		   double precision. We set fpuemuactive so that dbg.c first
-		   fetches the s/w state before saving the h/w state. */
-		fpuemuactive = 1;
-		{
-			int i;
-			/* initialise the unused d.p high order words to be NaN */
-			for (i = 0; i < 32; i++)
-				current->thread.fpu.soft.regs[i] =
-				    0x7ff80bad00000000LL;
-		}
-#endif				/* (r4640 || r4650) && !fpu(single) */
-	}
-}
-#endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/dp_add.c linux-2.4.20/arch/mips64/math-emu/dp_add.c
--- linux-2.4.19/arch/mips64/math-emu/dp_add.c	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/dp_add.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,186 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- *
- */
-
-
-#include "ieee754dp.h"
-
-ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y)
-{
-	COMPXDP;
-	COMPYDP;
-
-	EXPLODEXDP;
-	EXPLODEYDP;
-
-	CLEARCX;
-
-	switch (CLPAIR(xc, yc)) {
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
-		return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "add", x,
-					 y);
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
-		return ieee754dp_nanxcpt(y, "add", x, y);
-
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-		return ieee754dp_nanxcpt(x, "add", x, y);
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
-		return ieee754dp_bestnan(x, y);
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
-		return y;
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
-		return x;
-
-
-		/* Inifity handeling 
-		 */
-
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
-		if (xs == ys)
-			return x;
-		SETCX(IEEE754_INVALID_OPERATION);
-		return ieee754dp_xcpt(ieee754dp_indef(), "add", x, y);
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
-		return y;
-
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
-		return x;
-
-		/* Zero handeling 
-		 */
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-		if (xs == ys)
-			return x;
-		else
-			return ieee754dp_zero(ieee754_csr.rm ==
-					      IEEE754_RD);
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
-		return x;
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
-		return y;
-
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
-		DPDNORMX;
-
-		/* FALL THROUGH */
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
-		DPDNORMY;
-		break;
-
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
-		DPDNORMX;
-		break;
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
-		break;
-	}
-	assert(xm & DP_HIDDEN_BIT);
-	assert(ym & DP_HIDDEN_BIT);
-
-	/* provide guard,round and stick bit space */
-	xm <<= 3;
-	ym <<= 3;
-
-	if (xe > ye) {
-		/* have to shift y fraction right to align
-		 */
-		int s = xe - ye;
-		ym = XDPSRS(ym, s);
-		ye += s;
-	} else if (ye > xe) {
-		/* have to shift x fraction right to align
-		 */
-		int s = ye - xe;
-		xm = XDPSRS(xm, s);
-		xe += s;
-	}
-	assert(xe == ye);
-	assert(xe <= DP_EMAX);
-
-	if (xs == ys) {
-		/* generate 28 bit result of adding two 27 bit numbers
-		 * leaving result in xm,xs,xe
-		 */
-		xm = xm + ym;
-		xe = xe;
-		xs = xs;
-
-		if (xm >> (DP_MBITS + 1 + 3)) {	/* carry out */
-			xm = XDPSRS1(xm);
-			xe++;
-		}
-	} else {
-		if (xm >= ym) {
-			xm = xm - ym;
-			xe = xe;
-			xs = xs;
-		} else {
-			xm = ym - xm;
-			xe = xe;
-			xs = ys;
-		}
-		if (xm == 0)
-			return ieee754dp_zero(ieee754_csr.rm ==
-					      IEEE754_RD);
-
-		/* normalize to rounding precision */
-		while ((xm >> (DP_MBITS + 3)) == 0) {
-			xm <<= 1;
-			xe--;
-		}
-
-	}
-	DPNORMRET2(xs, xe, xm, "add", x, y);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/dp_cmp.c linux-2.4.20/arch/mips64/math-emu/dp_cmp.c
--- linux-2.4.19/arch/mips64/math-emu/dp_cmp.c	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/dp_cmp.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,58 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754dp.h"
-
-int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp)
-{
-	CLEARCX;
-
-	if (ieee754dp_isnan(x) || ieee754dp_isnan(y)) {
-		if (cmp & IEEE754_CUN)
-			return 1;
-		if (cmp & (IEEE754_CLT | IEEE754_CGT)) {
-			if (SETCX(IEEE754_INVALID_OPERATION))
-				return ieee754si_xcpt(0, "fcmpf", x);
-		}
-		return 0;
-	} else {
-		long long int vx = x.bits;
-		long long int vy = y.bits;
-
-		if (vx < 0)
-			vx = -vx ^ DP_SIGN_BIT;
-		if (vy < 0)
-			vy = -vy ^ DP_SIGN_BIT;
-
-		if (vx < vy)
-			return (cmp & IEEE754_CLT) != 0;
-		else if (vx == vy)
-			return (cmp & IEEE754_CEQ) != 0;
-		else
-			return (cmp & IEEE754_CGT) != 0;
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/dp_div.c linux-2.4.20/arch/mips64/math-emu/dp_div.c
--- linux-2.4.19/arch/mips64/math-emu/dp_div.c	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/dp_div.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,160 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754dp.h"
-
-ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y)
-{
-	COMPXDP;
-	COMPYDP;
-
-	CLEARCX;
-
-	EXPLODEXDP;
-	EXPLODEYDP;
-
-	switch (CLPAIR(xc, yc)) {
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
-		return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "div", x,
-					 y);
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
-		return ieee754dp_nanxcpt(y, "div", x, y);
-
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-		return ieee754dp_nanxcpt(x, "div", x, y);
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
-		return ieee754dp_bestnan(x, y);
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
-		return y;
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
-		return x;
-
-
-		/* Infinity handeling 
-		 */
-
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
-		SETCX(IEEE754_INVALID_OPERATION);
-		return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y);
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
-		return ieee754dp_zero(xs ^ ys);
-
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
-		return ieee754dp_inf(xs ^ ys);
-
-		/* Zero handeling 
-		 */
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-		SETCX(IEEE754_INVALID_OPERATION);
-		return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y);
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
-		SETCX(IEEE754_ZERO_DIVIDE);
-		return ieee754dp_xcpt(ieee754dp_inf(xs ^ ys), "div", x, y);
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
-		return ieee754dp_zero(xs == ys ? 0 : 1);
-
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
-		DPDNORMX;
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
-		DPDNORMY;
-		break;
-
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
-		DPDNORMX;
-		break;
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
-		break;
-	}
-	assert(xm & DP_HIDDEN_BIT);
-	assert(ym & DP_HIDDEN_BIT);
-
-	/* provide rounding space */
-	xm <<= 3;
-	ym <<= 3;
-
-	{
-		/* now the dirty work */
-
-		unsigned long long rm = 0;
-		int re = xe - ye;
-		unsigned long long bm;
-
-		for (bm = DP_MBIT(DP_MBITS + 2); bm; bm >>= 1) {
-			if (xm >= ym) {
-				xm -= ym;
-				rm |= bm;
-				if (xm == 0)
-					break;
-			}
-			xm <<= 1;
-		}
-		rm <<= 1;
-		if (xm)
-			rm |= 1;	/* have remainder, set sticky */
-
-		assert(rm);
-
-		/* normalise rm to rounding precision ?
-		 */
-		while ((rm >> (DP_MBITS + 3)) == 0) {
-			rm <<= 1;
-			re--;
-		}
-
-		DPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y);
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/dp_fint.c linux-2.4.20/arch/mips64/math-emu/dp_fint.c
--- linux-2.4.19/arch/mips64/math-emu/dp_fint.c	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/dp_fint.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,78 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754dp.h"
-
-ieee754dp ieee754dp_fint(int x)
-{
-	COMPXDP;
-
-	CLEARCX;
-
-	if (x == 0)
-		return ieee754dp_zero(0);
-	if (x == 1 || x == -1)
-		return ieee754dp_one(x < 0);
-	if (x == 10 || x == -10)
-		return ieee754dp_ten(x < 0);
-
-	xs = (x < 0);
-	if (xs) {
-		if (x == (1 << 31))
-			xm = ((unsigned) 1 << 31);	/* max neg can't be safely negated */
-		else
-			xm = -x;
-	} else {
-		xm = x;
-	}
-
-#if 1
-	/* normalize - result can never be inexact or overflow */
-	xe = DP_MBITS;
-	while ((xm >> DP_MBITS) == 0) {
-		xm <<= 1;
-		xe--;
-	}
-	return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
-#else
-	/* normalize */
-	xe = DP_MBITS + 3;
-	while ((xm >> (DP_MBITS + 3)) == 0) {
-		xm <<= 1;
-		xe--;
-	}
-	DPNORMRET1(xs, xe, xm, "fint", x);
-#endif
-}
-
-ieee754dp ieee754dp_funs(unsigned int u)
-{
-	if ((int) u < 0)
-		return ieee754dp_add(ieee754dp_1e31(),
-				     ieee754dp_fint(u & ~(1 << 31)));
-	return ieee754dp_fint(u);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/dp_flong.c linux-2.4.20/arch/mips64/math-emu/dp_flong.c
--- linux-2.4.19/arch/mips64/math-emu/dp_flong.c	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/dp_flong.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,76 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754dp.h"
-
-ieee754dp ieee754dp_flong(long long x)
-{
-	COMPXDP;
-
-	CLEARCX;
-
-	if (x == 0)
-		return ieee754dp_zero(0);
-	if (x == 1 || x == -1)
-		return ieee754dp_one(x < 0);
-	if (x == 10 || x == -10)
-		return ieee754dp_ten(x < 0);
-
-	xs = (x < 0);
-	if (xs) {
-		if (x == (1ULL << 63))
-			xm = (1ULL << 63);	/* max neg can't be safely negated */
-		else
-			xm = -x;
-	} else {
-		xm = x;
-	}
-
-	/* normalize */
-	xe = DP_MBITS + 3;
-	if (xm >> (DP_MBITS + 1 + 3)) {
-		/* shunt out overflow bits */
-		while (xm >> (DP_MBITS + 1 + 3)) {
-			XDPSRSX1();
-		}
-	} else {
-		/* normalize in grs extended double precision */
-		while ((xm >> (DP_MBITS + 3)) == 0) {
-			xm <<= 1;
-			xe--;
-		}
-	}
-	DPNORMRET1(xs, xe, xm, "dp_flong", x);
-}
-
-ieee754dp ieee754dp_fulong(unsigned long long u)
-{
-	if ((long long) u < 0)
-		return ieee754dp_add(ieee754dp_1e63(),
-				     ieee754dp_flong(u & ~(1ULL << 63)));
-	return ieee754dp_flong(u);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/dp_frexp.c linux-2.4.20/arch/mips64/math-emu/dp_frexp.c
--- linux-2.4.19/arch/mips64/math-emu/dp_frexp.c	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/dp_frexp.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,53 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754dp.h"
-
-/* close to ieeep754dp_logb 
-*/
-ieee754dp ieee754dp_frexp(ieee754dp x, int *eptr)
-{
-	COMPXDP;
-	CLEARCX;
-	EXPLODEXDP;
-
-	switch (xc) {
-	case IEEE754_CLASS_SNAN:
-	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_INF:
-	case IEEE754_CLASS_ZERO:
-		*eptr = 0;
-		return x;
-	case IEEE754_CLASS_DNORM:
-		DPDNORMX;
-		break;
-	case IEEE754_CLASS_NORM:
-		break;
-	}
-	*eptr = xe + 1;
-	return builddp(xs, -1 + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/dp_fsp.c linux-2.4.20/arch/mips64/math-emu/dp_fsp.c
--- linux-2.4.19/arch/mips64/math-emu/dp_fsp.c	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/dp_fsp.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,70 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754dp.h"
-
-ieee754dp ieee754dp_fsp(ieee754sp x)
-{
-	COMPXSP;
-
-	CLEARCX;
-
-	EXPLODEXSP;
-
-	switch (xc) {
-	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_SNAN:
-		return ieee754dp_nanxcpt(builddp(xs,
-						 DP_EMAX + 1 + DP_EBIAS,
-						 ((unsigned long long) xm
-						  << (DP_MBITS -
-						      SP_MBITS))), "fsp",
-					 x);
-	case IEEE754_CLASS_INF:
-		return ieee754dp_inf(xs);
-	case IEEE754_CLASS_ZERO:
-		return ieee754dp_zero(xs);
-	case IEEE754_CLASS_DNORM:
-		/* normalize */
-		while ((xm >> SP_MBITS) == 0) {
-			xm <<= 1;
-			xe--;
-		}
-		break;
-	case IEEE754_CLASS_NORM:
-		break;
-	}
-
-	/* CANT possibly overflow,underflow, or need rounding
-	 */
-
-	/* drop the hidden bit */
-	xm &= ~SP_HIDDEN_BIT;
-
-	return builddp(xs, xe + DP_EBIAS,
-		       (unsigned long long) xm << (DP_MBITS - SP_MBITS));
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/dp_logb.c linux-2.4.20/arch/mips64/math-emu/dp_logb.c
--- linux-2.4.19/arch/mips64/math-emu/dp_logb.c	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/dp_logb.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,54 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754dp.h"
-
-ieee754dp ieee754dp_logb(ieee754dp x)
-{
-	COMPXDP;
-
-	CLEARCX;
-
-	EXPLODEXDP;
-
-	switch (xc) {
-	case IEEE754_CLASS_SNAN:
-		return ieee754dp_nanxcpt(x, "logb", x);
-	case IEEE754_CLASS_QNAN:
-		return x;
-	case IEEE754_CLASS_INF:
-		return ieee754dp_inf(0);
-	case IEEE754_CLASS_ZERO:
-		return ieee754dp_inf(1);
-	case IEEE754_CLASS_DNORM:
-		DPDNORMX;
-		break;
-	case IEEE754_CLASS_NORM:
-		break;
-	}
-	return ieee754dp_fint(xe);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/dp_modf.c linux-2.4.20/arch/mips64/math-emu/dp_modf.c
--- linux-2.4.19/arch/mips64/math-emu/dp_modf.c	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/dp_modf.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,80 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754dp.h"
-
-/* modf function is always exact for a finite number
-*/
-ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip)
-{
-	COMPXDP;
-
-	CLEARCX;
-
-	EXPLODEXDP;
-
-	switch (xc) {
-	case IEEE754_CLASS_SNAN:
-	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_INF:
-	case IEEE754_CLASS_ZERO:
-		*ip = x;
-		return x;
-	case IEEE754_CLASS_DNORM:
-		/* far to small */
-		*ip = ieee754dp_zero(xs);
-		return x;
-	case IEEE754_CLASS_NORM:
-		break;
-	}
-	if (xe < 0) {
-		*ip = ieee754dp_zero(xs);
-		return x;
-	}
-	if (xe >= DP_MBITS) {
-		*ip = x;
-		return ieee754dp_zero(xs);
-	}
-	/* generate ipart mantissa by clearing bottom bits 
-	 */
-	*ip = builddp(xs, xe + DP_EBIAS,
-		      ((xm >> (DP_MBITS - xe)) << (DP_MBITS - xe)) &
-		      ~DP_HIDDEN_BIT);
-
-	/* generate fpart mantissa by clearing top bits
-	 * and normalizing (must be able to normalize)
-	 */
-	xm = (xm << (64 - (DP_MBITS - xe))) >> (64 - (DP_MBITS - xe));
-	if (xm == 0)
-		return ieee754dp_zero(xs);
-
-	while ((xm >> DP_MBITS) == 0) {
-		xm <<= 1;
-		xe--;
-	}
-	return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/dp_mul.c linux-2.4.20/arch/mips64/math-emu/dp_mul.c
--- linux-2.4.19/arch/mips64/math-emu/dp_mul.c	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/dp_mul.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,180 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754dp.h"
-
-ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y)
-{
-	COMPXDP;
-	COMPYDP;
-
-	CLEARCX;
-
-	EXPLODEXDP;
-	EXPLODEYDP;
-
-	switch (CLPAIR(xc, yc)) {
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
-		return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "mul", x,
-					 y);
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
-		return ieee754dp_nanxcpt(y, "mul", x, y);
-
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-		return ieee754dp_nanxcpt(x, "mul", x, y);
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
-		return ieee754dp_bestnan(x, y);
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
-		return y;
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
-		return x;
-
-
-		/* Infinity handeling */
-
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
-		SETCX(IEEE754_INVALID_OPERATION);
-		return ieee754dp_xcpt(ieee754dp_indef(), "mul", x, y);
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
-		return ieee754dp_inf(xs ^ ys);
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
-		return ieee754dp_zero(xs ^ ys);
-
-
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
-		DPDNORMX;
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
-		DPDNORMY;
-		break;
-
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
-		DPDNORMX;
-		break;
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
-		break;
-	}
-	/* rm = xm * ym, re = xe+ye basicly */
-	assert(xm & DP_HIDDEN_BIT);
-	assert(ym & DP_HIDDEN_BIT);
-	{
-		int re = xe + ye;
-		int rs = xs ^ ys;
-		unsigned long long rm;
-
-		/* shunt to top of word */
-		xm <<= 64 - (DP_MBITS + 1);
-		ym <<= 64 - (DP_MBITS + 1);
-
-		/* multiply 32bits xm,ym to give high 32bits rm with stickness
-		 */
-
-		/* 32 * 32 => 64 */
-#define DPXMULT(x,y)	((unsigned long long)(x) * (unsigned long long)y)
-
-		{
-			unsigned lxm = xm;
-			unsigned hxm = xm >> 32;
-			unsigned lym = ym;
-			unsigned hym = ym >> 32;
-			unsigned long long lrm;
-			unsigned long long hrm;
-
-			lrm = DPXMULT(lxm, lym);
-			hrm = DPXMULT(hxm, hym);
-
-			{
-				unsigned long long t = DPXMULT(lxm, hym);
-				{
-					unsigned long long at =
-					    lrm + (t << 32);
-					hrm += at < lrm;
-					lrm = at;
-				}
-				hrm = hrm + (t >> 32);
-			}
-
-			{
-				unsigned long long t = DPXMULT(hxm, lym);
-				{
-					unsigned long long at =
-					    lrm + (t << 32);
-					hrm += at < lrm;
-					lrm = at;
-				}
-				hrm = hrm + (t >> 32);
-			}
-			rm = hrm | (lrm != 0);
-		}
-
-		/*
-		 * sticky shift down to normal rounding precision
-		 */
-		if ((signed long long) rm < 0) {
-			rm =
-			    (rm >> (64 - (DP_MBITS + 1 + 3))) |
-			    ((rm << (DP_MBITS + 1 + 3)) != 0);
-			re++;
-		} else {
-			rm =
-			    (rm >> (64 - (DP_MBITS + 1 + 3 + 1))) |
-			    ((rm << (DP_MBITS + 1 + 3 + 1)) != 0);
-		}
-		assert(rm & (DP_HIDDEN_BIT << 3));
-		DPNORMRET2(rs, re, rm, "mul", x, y);
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/dp_scalb.c linux-2.4.20/arch/mips64/math-emu/dp_scalb.c
--- linux-2.4.19/arch/mips64/math-emu/dp_scalb.c	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/dp_scalb.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,58 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754dp.h"
-
-ieee754dp ieee754dp_scalb(ieee754dp x, int n)
-{
-	COMPXDP;
-
-	CLEARCX;
-
-	EXPLODEXDP;
-
-	switch (xc) {
-	case IEEE754_CLASS_SNAN:
-		return ieee754dp_nanxcpt(x, "scalb", x, n);
-	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_INF:
-	case IEEE754_CLASS_ZERO:
-		return x;
-	case IEEE754_CLASS_DNORM:
-		DPDNORMX;
-		break;
-	case IEEE754_CLASS_NORM:
-		break;
-	}
-	DPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n);
-}
-
-
-ieee754dp ieee754dp_ldexp(ieee754dp x, int n)
-{
-	return ieee754dp_scalb(x, n);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/dp_simple.c linux-2.4.20/arch/mips64/math-emu/dp_simple.c
--- linux-2.4.19/arch/mips64/math-emu/dp_simple.c	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/dp_simple.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,66 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754dp.h"
-
-int ieee754dp_finite(ieee754dp x)
-{
-	return DPBEXP(x) != DP_EMAX + 1 + DP_EBIAS;
-}
-
-ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y)
-{
-	CLEARCX;
-	DPSIGN(x) = DPSIGN(y);
-	return x;
-}
-
-
-ieee754dp ieee754dp_neg(ieee754dp x)
-{
-	CLEARCX;
-
-	if (ieee754dp_isnan(x))	/* but not infinity */
-		return ieee754dp_nanxcpt(x, "neg", x);
-
-	/* quick fix up */
-	DPSIGN(x) ^= 1;
-	return x;
-}
-
-
-ieee754dp ieee754dp_abs(ieee754dp x)
-{
-	CLEARCX;
-
-	if (ieee754dp_isnan(x))	/* but not infinity */
-		return ieee754dp_nanxcpt(x, "abs", x);
-
-	/* quick fix up */
-	DPSIGN(x) = 0;
-	return x;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/dp_sqrt.c linux-2.4.20/arch/mips64/math-emu/dp_sqrt.c
--- linux-2.4.19/arch/mips64/math-emu/dp_sqrt.c	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/dp_sqrt.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,167 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision square root
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754dp.h"
-
-static const struct ieee754dp_konst knan = {
-#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__)
-	0, 0, DP_EBIAS + DP_EMAX + 1, 0
-#else
-	0, DP_EBIAS + DP_EMAX + 1, 0, 0
-#endif
-};
-
-#define nan	((ieee754dp)knan)
-
-static const unsigned table[] = {
-	0, 1204, 3062, 5746, 9193, 13348, 18162, 23592,
-	29598, 36145, 43202, 50740, 58733, 67158, 75992,
-	85215, 83599, 71378, 60428, 50647, 41945, 34246,
-	27478, 21581, 16499, 12183, 8588, 5674, 3403,
-	1742, 661, 130
-};
-
-ieee754dp ieee754dp_sqrt(ieee754dp x)
-{
-	struct ieee754_csr oldcsr;
-	ieee754dp y, z, t;
-	unsigned scalx, yh;
-	COMPXDP;
-
-	EXPLODEXDP;
-
-	/* x == INF or NAN? */
-	switch (xc) {
-	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_SNAN:
-		/* sqrt(Nan) = Nan */
-		return ieee754dp_nanxcpt(x, "sqrt");
-	case IEEE754_CLASS_ZERO:
-		/* sqrt(0) = 0 */
-		return x;
-	case IEEE754_CLASS_INF:
-		if (xs)
-			/* sqrt(-Inf) = Nan */
-			return ieee754dp_nanxcpt(nan, "sqrt");
-		/* sqrt(+Inf) = Inf */
-		return x;
-	case IEEE754_CLASS_DNORM:
-		DPDNORMX;
-		/* fall through */
-	case IEEE754_CLASS_NORM:
-		if (xs)
-			/* sqrt(-x) = Nan */
-			return ieee754dp_nanxcpt(nan, "sqrt");
-		break;
-	}
-
-	/* save old csr; switch off INX enable & flag; set RN rounding */
-	oldcsr = ieee754_csr;
-	ieee754_csr.mx &= ~IEEE754_INEXACT;
-	ieee754_csr.sx &= ~IEEE754_INEXACT;
-	ieee754_csr.rm = IEEE754_RN;
-
-	/* adjust exponent to prevent overflow */
-	scalx = 0;
-	if (xe > 512) {		/* x > 2**-512? */
-		xe -= 512;	/* x = x / 2**512 */
-		scalx += 256;
-	} else if (xe < -512) {	/* x < 2**-512? */
-		xe += 512;	/* x = x * 2**512 */
-		scalx -= 256;
-	}
-
-	y = x = builddp(0, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
-
-	/* magic initial approximation to almost 8 sig. bits */
-	yh = y.bits >> 32;
-	yh = (yh >> 1) + 0x1ff80000;
-	yh = yh - table[(yh >> 15) & 31];
-	y.bits = ((unsigned long long) yh << 32) | (y.bits & 0xffffffff);
-
-	/* Heron's rule once with correction to improve to ~18 sig. bits */
-	/* t=x/y; y=y+t; py[n0]=py[n0]-0x00100006; py[n1]=0; */
-	t = ieee754dp_div(x, y);
-	y = ieee754dp_add(y, t);
-	y.bits -= 0x0010000600000000LL;
-	y.bits &= 0xffffffff00000000LL;
-
-	/* triple to almost 56 sig. bits: y ~= sqrt(x) to within 1 ulp */
-	/* t=y*y; z=t;  pt[n0]+=0x00100000; t+=z; z=(x-z)*y; */
-	z = t = ieee754dp_mul(y, y);
-	t.parts.bexp += 0x001;
-	t = ieee754dp_add(t, z);
-	z = ieee754dp_mul(ieee754dp_sub(x, z), y);
-
-	/* t=z/(t+x) ;  pt[n0]+=0x00100000; y+=t; */
-	t = ieee754dp_div(z, ieee754dp_add(t, x));
-	t.parts.bexp += 0x001;
-	y = ieee754dp_add(y, t);
-
-	/* twiddle last bit to force y correctly rounded */
-
-	/* set RZ, clear INEX flag */
-	ieee754_csr.rm = IEEE754_RZ;
-	ieee754_csr.sx &= ~IEEE754_INEXACT;
-
-	/* t=x/y; ...chopped quotient, possibly inexact */
-	t = ieee754dp_div(x, y);
-
-	if (ieee754_csr.sx & IEEE754_INEXACT || t.bits != y.bits) {
-
-		if (!(ieee754_csr.sx & IEEE754_INEXACT))
-			/* t = t-ulp */
-			t.bits -= 1;
-
-		/* add inexact to result status */
-		oldcsr.cx |= IEEE754_INEXACT;
-		oldcsr.sx |= IEEE754_INEXACT;
-
-		switch (oldcsr.rm) {
-		case IEEE754_RP:
-			y.bits += 1;
-			/* drop through */
-		case IEEE754_RN:
-			t.bits += 1;
-			break;
-		}
-
-		/* y=y+t; ...chopped sum */
-		y = ieee754dp_add(y, t);
-
-		/* adjust scalx for correctly rounded sqrt(x) */
-		scalx -= 1;
-	}
-
-	/* py[n0]=py[n0]+scalx; ...scale back y */
-	y.parts.bexp += scalx;
-
-	/* restore rounding mode, possibly set inexact */
-	ieee754_csr = oldcsr;
-
-	return y;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/dp_sub.c linux-2.4.20/arch/mips64/math-emu/dp_sub.c
--- linux-2.4.19/arch/mips64/math-emu/dp_sub.c	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/dp_sub.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,194 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754dp.h"
-
-ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y)
-{
-	COMPXDP;
-	COMPYDP;
-
-	CLEARCX;
-
-	EXPLODEXDP;
-	EXPLODEYDP;
-
-	switch (CLPAIR(xc, yc)) {
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
-		return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "sub", x,
-					 y);
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
-		return ieee754dp_nanxcpt(y, "sub", x, y);
-
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-		return ieee754dp_nanxcpt(x, "sub", x, y);
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
-		return ieee754dp_bestnan(x, y);
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
-		return y;
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
-		return x;
-
-
-		/* Inifity handeling 
-		 */
-
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
-		if (xs != ys)
-			return x;
-		SETCX(IEEE754_INVALID_OPERATION);
-		return ieee754dp_xcpt(ieee754dp_indef(), "sub", x, y);
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
-		return ieee754dp_inf(ys ^ 1);
-
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
-		return x;
-
-		/* Zero handeling 
-		 */
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-		if (xs != ys)
-			return x;
-		else
-			return ieee754dp_zero(ieee754_csr.rm ==
-					      IEEE754_RD);
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
-		return x;
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
-		/* quick fix up */
-		DPSIGN(y) ^= 1;
-		return y;
-
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
-		DPDNORMX;
-		/* FAAL THOROUGH */
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
-		/* normalize ym,ye */
-		DPDNORMY;
-		break;
-
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
-		/* normalize xm,xe */
-		DPDNORMX;
-		break;
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
-		break;
-	}
-	/* flip sign of y and handle as add */
-	ys ^= 1;
-
-	assert(xm & DP_HIDDEN_BIT);
-	assert(ym & DP_HIDDEN_BIT);
-
-
-	/* provide guard,round and stick bit dpace */
-	xm <<= 3;
-	ym <<= 3;
-
-	if (xe > ye) {
-		/* have to shift y fraction right to align
-		 */
-		int s = xe - ye;
-		ym = XDPSRS(ym, s);
-		ye += s;
-	} else if (ye > xe) {
-		/* have to shift x fraction right to align
-		 */
-		int s = ye - xe;
-		xm = XDPSRS(xm, s);
-		xe += s;
-	}
-	assert(xe == ye);
-	assert(xe <= DP_EMAX);
-
-	if (xs == ys) {
-		/* generate 28 bit result of adding two 27 bit numbers
-		 */
-		xm = xm + ym;
-		xe = xe;
-		xs = xs;
-
-		if (xm >> (DP_MBITS + 1 + 3)) {	/* carry out */
-			xm = XDPSRS1(xm);	/* shift preserving sticky */
-			xe++;
-		}
-	} else {
-		if (xm >= ym) {
-			xm = xm - ym;
-			xe = xe;
-			xs = xs;
-		} else {
-			xm = ym - xm;
-			xe = xe;
-			xs = ys;
-		}
-		if (xm == 0) {
-			if (ieee754_csr.rm == IEEE754_RD)
-				return ieee754dp_zero(1);	/* round negative inf. => sign = -1 */
-			else
-				return ieee754dp_zero(0);	/* other round modes   => sign = 1 */
-		}
-
-		/* normalize to rounding precision 
-		 */
-		while ((xm >> (DP_MBITS + 3)) == 0) {
-			xm <<= 1;
-			xe--;
-		}
-	}
-	DPNORMRET2(xs, xe, xm, "sub", x, y);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/dp_tint.c linux-2.4.20/arch/mips64/math-emu/dp_tint.c
--- linux-2.4.19/arch/mips64/math-emu/dp_tint.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/dp_tint.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,88 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include <linux/kernel.h>
-#include "ieee754dp.h"
-
-int ieee754dp_tint(ieee754dp x)
-{
-	COMPXDP;
-
-	CLEARCX;
-
-	EXPLODEXDP;
-
-	switch (xc) {
-	case IEEE754_CLASS_SNAN:
-	case IEEE754_CLASS_QNAN:
-		SETCX(IEEE754_INVALID_OPERATION);
-		return ieee754si_xcpt(ieee754si_indef(), "fixdp", x);
-	case IEEE754_CLASS_INF:
-		SETCX(IEEE754_OVERFLOW);
-		return ieee754si_xcpt(ieee754si_indef(), "fixdp", x);
-	case IEEE754_CLASS_ZERO:
-		return 0;
-	case IEEE754_CLASS_DNORM:	/* much to small */
-		SETCX(IEEE754_UNDERFLOW);
-		return ieee754si_xcpt(0, "fixdp", x);
-	case IEEE754_CLASS_NORM:
-		break;
-	}
-	if (xe >= 31) {
-		SETCX(IEEE754_OVERFLOW);
-		return ieee754si_xcpt(ieee754si_indef(), "fix", x);
-	}
-	if (xe < 0) {
-		SETCX(IEEE754_UNDERFLOW);
-		return ieee754si_xcpt(0, "fix", x);
-	}
-	/* oh gawd */
-	if (xe > DP_MBITS) {
-		xm <<= xe - DP_MBITS;
-	} else if (xe < DP_MBITS) {
-		/* XXX no rounding 
-		 */
-		xm >>= DP_MBITS - xe;
-	}
-	if (xs)
-		return -xm;
-	else
-		return xm;
-}
-
-
-unsigned int ieee754dp_tuns(ieee754dp x)
-{
-	ieee754dp hb = ieee754dp_1e31();
-
-	/* what if x < 0 ?? */
-	if (ieee754dp_lt(x, hb))
-		return (unsigned) ieee754dp_tint(x);
-
-	return (unsigned) ieee754dp_tint(ieee754dp_sub(x, hb)) |
-	    ((unsigned) 1 << 31);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/dp_tlong.c linux-2.4.20/arch/mips64/math-emu/dp_tlong.c
--- linux-2.4.19/arch/mips64/math-emu/dp_tlong.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/dp_tlong.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,141 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754dp.h"
-
-long long ieee754dp_tlong(ieee754dp x)
-{
-	COMPXDP;
-
-	CLEARCX;
-
-	EXPLODEXDP;
-
-	switch (xc) {
-	case IEEE754_CLASS_SNAN:
-	case IEEE754_CLASS_QNAN:
-		SETCX(IEEE754_INVALID_OPERATION);
-		return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x);
-	case IEEE754_CLASS_INF:
-		SETCX(IEEE754_OVERFLOW);
-		return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x);
-	case IEEE754_CLASS_ZERO:
-		return 0;
-	case IEEE754_CLASS_DNORM:	/* much too small */
-		SETCX(IEEE754_UNDERFLOW);
-		return ieee754di_xcpt(0, "dp_tlong", x);
-	case IEEE754_CLASS_NORM:
-		break;
-	}
-	if (xe >= 63) {
-		SETCX(IEEE754_OVERFLOW);
-		return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x);
-	}
-	if (xe < 0) {
-		if (ieee754_csr.rm == IEEE754_RU) {
-			if (xs) {	/* Negative  */
-				return 0x0000000000000000LL;
-			} else {	/* Positive */
-				return 0x0000000000000001LL;
-			}
-		} else if (ieee754_csr.rm == IEEE754_RD) {
-			if (xs) {	/* Negative , return -1 */
-				return 0xffffffffffffffffLL;
-			} else {	/* Positive */
-				return 0x0000000000000000LL;
-			}
-		} else {
-			SETCX(IEEE754_UNDERFLOW);
-			return ieee754di_xcpt(0, "dp_tlong", x);
-		}
-	}
-	/* oh gawd */
-	if (xe > DP_MBITS) {
-		xm <<= xe - DP_MBITS;
-	} else if (xe < DP_MBITS) {
-		unsigned long long residue;
-		unsigned long long mask = 0;
-		int i;
-		int round;
-		int sticky;
-		int odd;
-
-		/* compute mask */
-		for (i = 0; i < DP_MBITS - xe; i++) {
-			mask = mask << 1;
-			mask = mask | 0x1;
-		}
-		residue = (xm & mask) << (64 - (DP_MBITS - xe));
-		round =
-		    ((0x8000000000000000LL & residue) !=
-		     0x0000000000000000LL);
-		sticky =
-		    ((0x7fffffffffffffffLL & residue) !=
-		     0x0000000000000000LL);
-
-		xm >>= DP_MBITS - xe;
-
-		odd = ((xm & 0x1) != 0x0000000000000000LL);
-
-		/* Do the rounding */
-		if (!round && sticky) {
-			if ((ieee754_csr.rm == IEEE754_RU && !xs)
-			    || (ieee754_csr.rm == IEEE754_RD && xs)) {
-				xm++;
-			}
-		} else if (round && !sticky) {
-			if ((ieee754_csr.rm == IEEE754_RU && !xs)
-			    || (ieee754_csr.rm == IEEE754_RD && xs)
-			    || (ieee754_csr.rm == IEEE754_RN && odd)) {
-				xm++;
-			}
-		} else if (round && sticky) {
-			if ((ieee754_csr.rm == IEEE754_RU && !xs)
-			    || (ieee754_csr.rm == IEEE754_RD && xs)
-			    || (ieee754_csr.rm == IEEE754_RN)) {
-				xm++;
-			}
-		}
-	}
-	if (xs)
-		return -xm;
-	else
-		return xm;
-}
-
-
-unsigned long long ieee754dp_tulong(ieee754dp x)
-{
-	ieee754dp hb = ieee754dp_1e63();
-
-	/* what if x < 0 ?? */
-	if (ieee754dp_lt(x, hb))
-		return (unsigned long long) ieee754dp_tlong(x);
-
-	return (unsigned long long) ieee754dp_tlong(ieee754dp_sub(x, hb)) |
-	    (1ULL << 63);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/ieee754.c linux-2.4.20/arch/mips64/math-emu/ieee754.c
--- linux-2.4.19/arch/mips64/math-emu/ieee754.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/ieee754.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,138 +0,0 @@
-/* ieee754 floating point arithmetic
- * single and double precision
- *
- * BUGS
- * not much dp done
- * doesnt generate IEEE754_INEXACT
- *
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754int.h"
-
-#define DP_EBIAS	1023
-#define DP_EMIN		(-1022)
-#define DP_EMAX		1023
-
-#define SP_EBIAS	127
-#define SP_EMIN		(-126)
-#define SP_EMAX		127
-
-/* indexed by class */
-const char *const ieee754_cname[] = {
-	"Normal",
-	"Zero",
-	"Denormal",
-	"Infinity",
-	"QNaN",
-	"SNaN",
-};
-
-/* the control status register 
-*/
-struct ieee754_csr ieee754_csr;
-
-/* special constants
-*/
-
-
-#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__)
-#define SPSTR(s,b,m) {m,b,s}
-#define DPSTR(s,b,mh,ml) {ml,mh,b,s}
-#endif
-
-#ifdef __MIPSEB__
-#define SPSTR(s,b,m) {s,b,m}
-#define DPSTR(s,b,mh,ml) {s,b,mh,ml}
-#endif
-
-const struct ieee754dp_konst __ieee754dp_spcvals[] = {
-	DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 0),	/* + zero   */
-	DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 0),	/* - zero   */
-	DPSTR(0, DP_EBIAS, 0, 0),	/* + 1.0   */
-	DPSTR(1, DP_EBIAS, 0, 0),	/* - 1.0   */
-	DPSTR(0, 3 + DP_EBIAS, 0x40000, 0),	/* + 10.0   */
-	DPSTR(1, 3 + DP_EBIAS, 0x40000, 0),	/* - 10.0   */
-	DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0, 0),	/* + infinity */
-	DPSTR(1, DP_EMAX + 1 + DP_EBIAS, 0, 0),	/* - infinity */
-	DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0x40000, 0),	/* + indef quiet Nan */
-	DPSTR(0, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF),	/* + max */
-	DPSTR(1, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF),	/* - max */
-	DPSTR(0, DP_EMIN + DP_EBIAS, 0, 0),	/* + min normal */
-	DPSTR(1, DP_EMIN + DP_EBIAS, 0, 0),	/* - min normal */
-	DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 1),	/* + min denormal */
-	DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 1),	/* - min denormal */
-	DPSTR(0, 31 + DP_EBIAS, 0, 0),	/* + 1.0e31 */
-	DPSTR(0, 63 + DP_EBIAS, 0, 0),	/* + 1.0e63 */
-};
-
-const struct ieee754sp_konst __ieee754sp_spcvals[] = {
-	SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 0),	/* + zero   */
-	SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 0),	/* - zero   */
-	SPSTR(0, SP_EBIAS, 0),	/* + 1.0   */
-	SPSTR(1, SP_EBIAS, 0),	/* - 1.0   */
-	SPSTR(0, 3 + SP_EBIAS, 0x200000),	/* + 10.0   */
-	SPSTR(1, 3 + SP_EBIAS, 0x200000),	/* - 10.0   */
-	SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0),	/* + infinity */
-	SPSTR(1, SP_EMAX + 1 + SP_EBIAS, 0),	/* - infinity */
-	SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0x200000),	/* + indef quiet Nan  */
-	SPSTR(0, SP_EMAX + SP_EBIAS, 0x7FFFFF),	/* + max normal */
-	SPSTR(1, SP_EMAX + SP_EBIAS, 0x7FFFFF),	/* - max normal */
-	SPSTR(0, SP_EMIN + SP_EBIAS, 0),	/* + min normal */
-	SPSTR(1, SP_EMIN + SP_EBIAS, 0),	/* - min normal */
-	SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 1),	/* + min denormal */
-	SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 1),	/* - min denormal */
-	SPSTR(0, 31 + SP_EBIAS, 0),	/* + 1.0e31 */
-	SPSTR(0, 63 + SP_EBIAS, 0),	/* + 1.0e63 */
-};
-
-
-int ieee754si_xcpt(int r, const char *op, ...)
-{
-	struct ieee754xctx ax;
-
-	if (!TSTX())
-		return r;
-	ax.op = op;
-	ax.rt = IEEE754_RT_SI;
-	ax.rv.si = r;
-	va_start(ax.ap, op);
-	ieee754_xcpt(&ax);
-	return ax.rv.si;
-}
-
-long long ieee754di_xcpt(long long r, const char *op, ...)
-{
-	struct ieee754xctx ax;
-
-	if (!TSTX())
-		return r;
-	ax.op = op;
-	ax.rt = IEEE754_RT_DI;
-	ax.rv.di = r;
-	va_start(ax.ap, op);
-	ieee754_xcpt(&ax);
-	return ax.rv.di;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/ieee754.h linux-2.4.20/arch/mips64/math-emu/ieee754.h
--- linux-2.4.19/arch/mips64/math-emu/ieee754.h	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/ieee754.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,490 +0,0 @@
-/* single and double precision fp ops
- * missing extended precision.
-*/
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-/**************************************************************************
- *  Nov 7, 2000
- *  Modification to allow integration with Linux kernel 
- *
- *  Kevin D. Kissell, kevink@mips.com and Carsten Langgard, carstenl@mips.com
- *  Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
- *************************************************************************/
-
-#ifdef __KERNEL__
-/* Going from Algorithmics to Linux native environment, add this */
-#include <linux/types.h>
-
-/* 
- * Not very pretty, but the Linux kernel's normal va_list definition 
- * does not allow it to be used as a structure element, as it is here.
- */
-#ifndef _STDARG_H
-#include <stdarg.h>
-#endif
-
-#else
-
-/* Note that __KERNEL__ is taken to mean Linux kernel */
-
-#if #system(OpenBSD)
-#include <machine/types.h>
-#endif
-#include <machine/endian.h>
-
-#endif				/* __KERNEL__ */
-
-#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__)
-struct ieee754dp_konst {
-	unsigned mantlo:32;
-	unsigned manthi:20;
-	unsigned bexp:11;
-	unsigned sign:1;
-};
-struct ieee754sp_konst {
-	unsigned mant:23;
-	unsigned bexp:8;
-	unsigned sign:1;
-};
-
-typedef union _ieee754dp {
-	struct ieee754dp_konst oparts;
-	struct {
-		unsigned long long mant:52;
-		unsigned int bexp:11;
-		unsigned int sign:1;
-	} parts;
-	unsigned long long bits;
-	double d;
-} ieee754dp;
-
-typedef union _ieee754sp {
-	struct ieee754sp_konst parts;
-	float f;
-	unsigned long bits;
-} ieee754sp;
-#endif
-
-#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
-struct ieee754dp_konst {
-	unsigned sign:1;
-	unsigned bexp:11;
-	unsigned manthi:20;
-	unsigned mantlo:32;
-};
-typedef union _ieee754dp {
-	struct ieee754dp_konst oparts;
-	struct {
-		unsigned int sign:1;
-		unsigned int bexp:11;
-		unsigned long long mant:52;
-	} parts;
-	double d;
-	unsigned long long bits;
-} ieee754dp;
-
-struct ieee754sp_konst {
-	unsigned sign:1;
-	unsigned bexp:8;
-	unsigned mant:23;
-};
-
-typedef union _ieee754sp {
-	struct ieee754sp_konst parts;
-	float f;
-	unsigned long bits;
-} ieee754sp;
-#endif
-
-/*
- * single precision (often aka float)
-*/
-int ieee754sp_finite(ieee754sp x);
-int ieee754sp_class(ieee754sp x);
-
-ieee754sp ieee754sp_abs(ieee754sp x);
-ieee754sp ieee754sp_neg(ieee754sp x);
-ieee754sp ieee754sp_scalb(ieee754sp x, int);
-ieee754sp ieee754sp_logb(ieee754sp x);
-
-/* x with sign of y */
-ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y);
-
-ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y);
-ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y);
-ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y);
-ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y);
-
-ieee754sp ieee754sp_fint(int x);
-ieee754sp ieee754sp_funs(unsigned x);
-ieee754sp ieee754sp_flong(long long x);
-ieee754sp ieee754sp_fulong(unsigned long long x);
-ieee754sp ieee754sp_fdp(ieee754dp x);
-
-int ieee754sp_tint(ieee754sp x);
-unsigned int ieee754sp_tuns(ieee754sp x);
-long long ieee754sp_tlong(ieee754sp x);
-unsigned long long ieee754sp_tulong(ieee754sp x);
-
-int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cop);
-/*
- * basic sp math
- */
-ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip);
-ieee754sp ieee754sp_frexp(ieee754sp x, int *exp);
-ieee754sp ieee754sp_ldexp(ieee754sp x, int exp);
-
-ieee754sp ieee754sp_ceil(ieee754sp x);
-ieee754sp ieee754sp_floor(ieee754sp x);
-ieee754sp ieee754sp_trunc(ieee754sp x);
-
-ieee754sp ieee754sp_sqrt(ieee754sp x);
-
-/*
- * double precision (often aka double)
-*/
-int ieee754dp_finite(ieee754dp x);
-int ieee754dp_class(ieee754dp x);
-
-/* x with sign of y */
-ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y);
-
-ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y);
-ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y);
-ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y);
-ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y);
-
-ieee754dp ieee754dp_abs(ieee754dp x);
-ieee754dp ieee754dp_neg(ieee754dp x);
-ieee754dp ieee754dp_scalb(ieee754dp x, int);
-
-/* return exponent as integer in floating point format 
- */
-ieee754dp ieee754dp_logb(ieee754dp x);
-
-ieee754dp ieee754dp_fint(int x);
-ieee754dp ieee754dp_funs(unsigned x);
-ieee754dp ieee754dp_flong(long long x);
-ieee754dp ieee754dp_fulong(unsigned long long x);
-ieee754dp ieee754dp_fsp(ieee754sp x);
-
-ieee754dp ieee754dp_ceil(ieee754dp x);
-ieee754dp ieee754dp_floor(ieee754dp x);
-ieee754dp ieee754dp_trunc(ieee754dp x);
-
-int ieee754dp_tint(ieee754dp x);
-unsigned int ieee754dp_tuns(ieee754dp x);
-long long ieee754dp_tlong(ieee754dp x);
-unsigned long long ieee754dp_tulong(ieee754dp x);
-
-int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cop);
-/*
- * basic sp math
- */
-ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip);
-ieee754dp ieee754dp_frexp(ieee754dp x, int *exp);
-ieee754dp ieee754dp_ldexp(ieee754dp x, int exp);
-
-ieee754dp ieee754dp_ceil(ieee754dp x);
-ieee754dp ieee754dp_floor(ieee754dp x);
-ieee754dp ieee754dp_trunc(ieee754dp x);
-
-ieee754dp ieee754dp_sqrt(ieee754dp x);
-
-
-
-/* 5 types of floating point number 
-*/
-#define IEEE754_CLASS_NORM	0x00
-#define IEEE754_CLASS_ZERO	0x01
-#define IEEE754_CLASS_DNORM	0x02
-#define IEEE754_CLASS_INF	0x03
-#define IEEE754_CLASS_SNAN	0x04
-#define IEEE754_CLASS_QNAN	0x05
-extern const char *const ieee754_cname[];
-
-/* exception numbers */
-#define IEEE754_INEXACT			0x01
-#define IEEE754_UNDERFLOW		0x02
-#define IEEE754_OVERFLOW		0x04
-#define IEEE754_ZERO_DIVIDE		0x08
-#define IEEE754_INVALID_OPERATION	0x10
-
-/* cmp operators
-*/
-#define IEEE754_CLT	0x01
-#define IEEE754_CEQ	0x02
-#define IEEE754_CGT	0x04
-#define IEEE754_CUN	0x08
-
-/* rounding mode 
-*/
-#define IEEE754_RN	0	/* round to nearest */
-#define IEEE754_RZ	1	/* round toward zero  */
-#define IEEE754_RD	2	/* round toward -Infinity */
-#define IEEE754_RU	3	/* round toward +Infinity */
-
-/* other naming */
-#define IEEE754_RM	IEEE754_RD
-#define IEEE754_RP	IEEE754_RU
-
-/* "normal" comparisons
-*/
-static __inline int ieee754sp_eq(ieee754sp x, ieee754sp y)
-{
-	return ieee754sp_cmp(x, y, IEEE754_CEQ);
-}
-
-static __inline int ieee754sp_ne(ieee754sp x, ieee754sp y)
-{
-	return ieee754sp_cmp(x, y,
-			     IEEE754_CLT | IEEE754_CGT | IEEE754_CUN);
-}
-
-static __inline int ieee754sp_lt(ieee754sp x, ieee754sp y)
-{
-	return ieee754sp_cmp(x, y, IEEE754_CLT);
-}
-
-static __inline int ieee754sp_le(ieee754sp x, ieee754sp y)
-{
-	return ieee754sp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ);
-}
-
-static __inline int ieee754sp_gt(ieee754sp x, ieee754sp y)
-{
-	return ieee754sp_cmp(x, y, IEEE754_CGT);
-}
-
-
-static __inline int ieee754sp_ge(ieee754sp x, ieee754sp y)
-{
-	return ieee754sp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ);
-}
-
-static __inline int ieee754dp_eq(ieee754dp x, ieee754dp y)
-{
-	return ieee754dp_cmp(x, y, IEEE754_CEQ);
-}
-
-static __inline int ieee754dp_ne(ieee754dp x, ieee754dp y)
-{
-	return ieee754dp_cmp(x, y,
-			     IEEE754_CLT | IEEE754_CGT | IEEE754_CUN);
-}
-
-static __inline int ieee754dp_lt(ieee754dp x, ieee754dp y)
-{
-	return ieee754dp_cmp(x, y, IEEE754_CLT);
-}
-
-static __inline int ieee754dp_le(ieee754dp x, ieee754dp y)
-{
-	return ieee754dp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ);
-}
-
-static __inline int ieee754dp_gt(ieee754dp x, ieee754dp y)
-{
-	return ieee754dp_cmp(x, y, IEEE754_CGT);
-}
-
-static __inline int ieee754dp_ge(ieee754dp x, ieee754dp y)
-{
-	return ieee754dp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ);
-}
-
-
-/* like strtod
-*/
-ieee754dp ieee754dp_fstr(const char *s, char **endp);
-char *ieee754dp_tstr(ieee754dp x, int prec, int fmt, int af);
-
-
-/* the control status register 
-*/
-struct ieee754_csr {
-	unsigned pad:13;
-	unsigned noq:1;		/* set 1 for no quiet NaN's */
-	unsigned nod:1;		/* set 1 for no denormalised numbers */
-	unsigned cx:5;		/* exceptions this operation */
-	unsigned mx:5;		/* exception enable  mask */
-	unsigned sx:5;		/* exceptions total */
-	unsigned rm:2;		/* current rounding mode */
-};
-extern struct ieee754_csr ieee754_csr;
-
-static __inline unsigned ieee754_getrm(void)
-{
-	return (ieee754_csr.rm);
-}
-static __inline unsigned ieee754_setrm(unsigned rm)
-{
-	return (ieee754_csr.rm = rm);
-}
-
-/*
- * get current exceptions
- */
-static __inline unsigned ieee754_getcx(void)
-{
-	return (ieee754_csr.cx);
-}
-
-/* test for current exception condition 
- */
-static __inline int ieee754_cxtest(unsigned n)
-{
-	return (ieee754_csr.cx & n);
-}
-
-/*
- * get sticky exceptions
- */
-static __inline unsigned ieee754_getsx(void)
-{
-	return (ieee754_csr.sx);
-}
-
-/* clear sticky conditions
-*/
-static __inline unsigned ieee754_clrsx(void)
-{
-	return (ieee754_csr.sx = 0);
-}
-
-/* test for sticky exception condition 
- */
-static __inline int ieee754_sxtest(unsigned n)
-{
-	return (ieee754_csr.sx & n);
-}
-
-/* debugging */
-ieee754sp ieee754sp_dump(char *s, ieee754sp x);
-ieee754dp ieee754dp_dump(char *s, ieee754dp x);
-
-#define IEEE754_SPCVAL_PZERO	0
-#define IEEE754_SPCVAL_NZERO	1
-#define IEEE754_SPCVAL_PONE	2
-#define IEEE754_SPCVAL_NONE	3
-#define IEEE754_SPCVAL_PTEN	4
-#define IEEE754_SPCVAL_NTEN	5
-#define IEEE754_SPCVAL_PINFINITY	6
-#define IEEE754_SPCVAL_NINFINITY	7
-#define IEEE754_SPCVAL_INDEF	8
-#define IEEE754_SPCVAL_PMAX	9	/* +max norm */
-#define IEEE754_SPCVAL_NMAX	10	/* -max norm */
-#define IEEE754_SPCVAL_PMIN	11	/* +min norm */
-#define IEEE754_SPCVAL_NMIN	12	/* +min norm */
-#define IEEE754_SPCVAL_PMIND	13	/* +min denorm */
-#define IEEE754_SPCVAL_NMIND	14	/* +min denorm */
-#define IEEE754_SPCVAL_P1E31	15	/* + 1.0e31 */
-#define IEEE754_SPCVAL_P1E63	16	/* + 1.0e63 */
-
-extern const struct ieee754dp_konst __ieee754dp_spcvals[];
-extern const struct ieee754sp_konst __ieee754sp_spcvals[];
-#define ieee754dp_spcvals ((const ieee754dp *)__ieee754dp_spcvals)
-#define ieee754sp_spcvals ((const ieee754sp *)__ieee754sp_spcvals)
-
-/* return infinity with given sign
-*/
-#define ieee754dp_inf(sn)	\
-  (ieee754dp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)])
-#define ieee754dp_zero(sn) \
-  (ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
-#define ieee754dp_one(sn) \
-  (ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
-#define ieee754dp_ten(sn) \
-  (ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
-#define ieee754dp_indef() \
-  (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF])
-#define ieee754dp_max(sn) \
-  (ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
-#define ieee754dp_min(sn) \
-  (ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
-#define ieee754dp_mind(sn) \
-  (ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
-#define ieee754dp_1e31() \
-  (ieee754dp_spcvals[IEEE754_SPCVAL_P1E31])
-#define ieee754dp_1e63() \
-  (ieee754dp_spcvals[IEEE754_SPCVAL_P1E63])
-
-#define ieee754sp_inf(sn) \
-  (ieee754sp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)])
-#define ieee754sp_zero(sn) \
-  (ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
-#define ieee754sp_one(sn) \
-  (ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
-#define ieee754sp_ten(sn) \
-  (ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
-#define ieee754sp_indef() \
-  (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF])
-#define ieee754sp_max(sn) \
-  (ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
-#define ieee754sp_min(sn) \
-  (ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
-#define ieee754sp_mind(sn) \
-  (ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
-#define ieee754sp_1e31() \
-  (ieee754sp_spcvals[IEEE754_SPCVAL_P1E31])
-#define ieee754sp_1e63() \
-  (ieee754sp_spcvals[IEEE754_SPCVAL_P1E63])
-
-/* indefinite integer value 
-*/
-#define ieee754si_indef()	INT_MIN
-#ifdef LONG_LONG_MIN
-#define ieee754di_indef()	LONG_LONG_MIN
-#else
-#define ieee754di_indef()	(-9223372036854775807LL-1)
-#endif
-
-/* IEEE exception context, passed to handler */
-struct ieee754xctx {
-	const char *op;		/* operation name */
-	int rt;			/* result type */
-	union {
-		ieee754sp sp;	/* single precision */
-		ieee754dp dp;	/* double precision */
-#ifdef IEEE854_XP
-		ieee754xp xp;	/* extended precision */
-#endif
-		int si;		/* standard signed integer (32bits) */
-		long long di;	/* extended signed integer (64bits) */
-	} rv;			/* default result format implied by op */
-	va_list ap;
-};
-
-/* result types for xctx.rt */
-#define IEEE754_RT_SP	0
-#define IEEE754_RT_DP	1
-#define IEEE754_RT_XP	2
-#define IEEE754_RT_SI	3
-#define IEEE754_RT_DI	4
-
-extern void ieee754_xcpt(struct ieee754xctx *xcp);
-
-/* compat */
-#define ieee754dp_fix(x)	ieee754dp_tint(x)
-#define ieee754sp_fix(x)	ieee754sp_tint(x)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/ieee754d.c linux-2.4.20/arch/mips64/math-emu/ieee754d.c
--- linux-2.4.19/arch/mips64/math-emu/ieee754d.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/ieee754d.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,142 +0,0 @@
-/* some debug functions
-*/
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-/**************************************************************************
- *  Nov 7, 2000
- *  Modified to build and operate in Linux kernel environment. 
- *
- *  Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
- *  Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
- *************************************************************************/
-
-#include "ieee754.h"
-
-#define DP_EBIAS	1023
-#define DP_EMIN		(-1022)
-#define DP_EMAX		1023
-#define DP_FBITS	52
-
-#define SP_EBIAS	127
-#define SP_EMIN		(-126)
-#define SP_EMAX		127
-#define SP_FBITS	23
-
-#define DP_MBIT(x)	((unsigned long long)1 << (x))
-#define DP_HIDDEN_BIT	DP_MBIT(DP_FBITS)
-#define DP_SIGN_BIT	DP_MBIT(63)
-
-
-#define SP_MBIT(x)	((unsigned long)1 << (x))
-#define SP_HIDDEN_BIT	SP_MBIT(SP_FBITS)
-#define SP_SIGN_BIT	SP_MBIT(31)
-
-
-#define SPSIGN(sp)	(sp.parts.sign)
-#define SPBEXP(sp)	(sp.parts.bexp)
-#define SPMANT(sp)	(sp.parts.mant)
-
-#define DPSIGN(dp)	(dp.parts.sign)
-#define DPBEXP(dp)	(dp.parts.bexp)
-#define DPMANT(dp)	(dp.parts.mant)
-
-ieee754dp ieee754dp_dump(char *m, ieee754dp x)
-{
-	int i;
-
-	printk("%s", m);
-	printk("<%08x,%08x>\n", (unsigned) (x.bits >> 32),
-	       (unsigned) x.bits);
-	printk("\t=");
-	switch (ieee754dp_class(x)) {
-	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_SNAN:
-		printk("Nan %c", DPSIGN(x) ? '-' : '+');
-		for (i = DP_FBITS - 1; i >= 0; i--)
-			printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0');
-		break;
-	case IEEE754_CLASS_INF:
-		printk("%cInfinity", DPSIGN(x) ? '-' : '+');
-		break;
-	case IEEE754_CLASS_ZERO:
-		printk("%cZero", DPSIGN(x) ? '-' : '+');
-		break;
-	case IEEE754_CLASS_DNORM:
-		printk("%c0.", DPSIGN(x) ? '-' : '+');
-		for (i = DP_FBITS - 1; i >= 0; i--)
-			printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0');
-		printk("e%d", DPBEXP(x) - DP_EBIAS);
-		break;
-	case IEEE754_CLASS_NORM:
-		printk("%c1.", DPSIGN(x) ? '-' : '+');
-		for (i = DP_FBITS - 1; i >= 0; i--)
-			printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0');
-		printk("e%d", DPBEXP(x) - DP_EBIAS);
-		break;
-	default:
-		printk("Illegal/Unknown IEEE754 value class");
-	}
-	printk("\n");
-	return x;
-}
-
-ieee754sp ieee754sp_dump(char *m, ieee754sp x)
-{
-	int i;
-
-	printk("%s=", m);
-	printk("<%08x>\n", (unsigned) x.bits);
-	printk("\t=");
-	switch (ieee754sp_class(x)) {
-	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_SNAN:
-		printk("Nan %c", SPSIGN(x) ? '-' : '+');
-		for (i = SP_FBITS - 1; i >= 0; i--)
-			printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0');
-		break;
-	case IEEE754_CLASS_INF:
-		printk("%cInfinity", SPSIGN(x) ? '-' : '+');
-		break;
-	case IEEE754_CLASS_ZERO:
-		printk("%cZero", SPSIGN(x) ? '-' : '+');
-		break;
-	case IEEE754_CLASS_DNORM:
-		printk("%c0.", SPSIGN(x) ? '-' : '+');
-		for (i = SP_FBITS - 1; i >= 0; i--)
-			printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0');
-		printk("e%d", SPBEXP(x) - SP_EBIAS);
-		break;
-	case IEEE754_CLASS_NORM:
-		printk("%c1.", SPSIGN(x) ? '-' : '+');
-		for (i = SP_FBITS - 1; i >= 0; i--)
-			printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0');
-		printk("e%d", SPBEXP(x) - SP_EBIAS);
-		break;
-	default:
-		printk("Illegal/Unknown IEEE754 value class");
-	}
-	printk("\n");
-	return x;
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/ieee754dp.c linux-2.4.20/arch/mips64/math-emu/ieee754dp.c
--- linux-2.4.19/arch/mips64/math-emu/ieee754dp.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/ieee754dp.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,197 +0,0 @@
-/* IEEE754 floating point arithmetic
- * double precision: common utilities
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754dp.h"
-
-int ieee754dp_class(ieee754dp x)
-{
-	COMPXDP;
-	EXPLODEXDP;
-	return xc;
-}
-
-int ieee754dp_isnan(ieee754dp x)
-{
-	return ieee754dp_class(x) >= IEEE754_CLASS_SNAN;
-}
-
-int ieee754dp_issnan(ieee754dp x)
-{
-	assert(ieee754dp_isnan(x));
-	if (ieee754_csr.noq)
-		return 1;
-	return !(DPMANT(x) & DP_MBIT(DP_MBITS - 1));
-}
-
-
-ieee754dp ieee754dp_xcpt(ieee754dp r, const char *op, ...)
-{
-	struct ieee754xctx ax;
-	if (!TSTX())
-		return r;
-
-	ax.op = op;
-	ax.rt = IEEE754_RT_DP;
-	ax.rv.dp = r;
-	va_start(ax.ap, op);
-	ieee754_xcpt(&ax);
-	return ax.rv.dp;
-}
-
-ieee754dp ieee754dp_nanxcpt(ieee754dp r, const char *op, ...)
-{
-	struct ieee754xctx ax;
-
-	assert(ieee754dp_isnan(r));
-
-	if (!ieee754dp_issnan(r))	/* QNAN does not cause invalid op !! */
-		return r;
-
-	if (!SETCX(IEEE754_INVALID_OPERATION)) {
-		/* not enabled convert to a quiet NaN */
-		if (ieee754_csr.noq)
-			return r;
-		DPMANT(r) |= DP_MBIT(DP_MBITS - 1);
-		return r;
-	}
-
-	ax.op = op;
-	ax.rt = 0;
-	ax.rv.dp = r;
-	va_start(ax.ap, op);
-	ieee754_xcpt(&ax);
-	return ax.rv.dp;
-}
-
-ieee754dp ieee754dp_bestnan(ieee754dp x, ieee754dp y)
-{
-	assert(ieee754dp_isnan(x));
-	assert(ieee754dp_isnan(y));
-
-	if (DPMANT(x) > DPMANT(y))
-		return x;
-	else
-		return y;
-}
-
-
-/* generate a normal/denormal number with over,under handeling
- * sn is sign
- * xe is an unbiased exponent
- * xm is 3bit extended precision value.
- */
-ieee754dp ieee754dp_format(int sn, int xe, unsigned long long xm)
-{
-	assert(xm);		/* we dont gen exact zeros (probably should) */
-
-	assert((xm >> (DP_MBITS + 1 + 3)) == 0);	/* no execess */
-	assert(xm & (DP_HIDDEN_BIT << 3));
-
-	if (xe < DP_EMIN) {
-		/* strip lower bits */
-		int es = DP_EMIN - xe;
-
-		if (ieee754_csr.nod) {
-			SETCX(IEEE754_UNDERFLOW);
-			return ieee754dp_zero(sn);
-		}
-
-		/* sticky right shift es bits 
-		 */
-		xm = XDPSRS(xm, es);
-		xe += es;
-
-		assert((xm & (DP_HIDDEN_BIT << 3)) == 0);
-		assert(xe == DP_EMIN);
-	}
-	if (xm & (DP_MBIT(3) - 1)) {
-		SETCX(IEEE754_INEXACT);
-		/* inexact must round of 3 bits 
-		 */
-		switch (ieee754_csr.rm) {
-		case IEEE754_RZ:
-			break;
-		case IEEE754_RN:
-			xm += 0x3 + ((xm >> 3) & 1);
-			/* xm += (xm&0x8)?0x4:0x3 */
-			break;
-		case IEEE754_RU:	/* toward +Infinity */
-			if (!sn)	/* ?? */
-				xm += 0x8;
-			break;
-		case IEEE754_RD:	/* toward -Infinity */
-			if (sn)	/* ?? */
-				xm += 0x8;
-			break;
-		}
-		/* adjust exponent for rounding add overflowing 
-		 */
-		if (xm >> (DP_MBITS + 3 + 1)) {	/* add causes mantissa overflow */
-			xm >>= 1;
-			xe++;
-		}
-	}
-	/* strip grs bits */
-	xm >>= 3;
-
-	assert((xm >> (DP_MBITS + 1)) == 0);	/* no execess */
-	assert(xe >= DP_EMIN);
-
-	if (xe > DP_EMAX) {
-		SETCX(IEEE754_OVERFLOW);
-		/* -O can be table indexed by (rm,sn) */
-		switch (ieee754_csr.rm) {
-		case IEEE754_RN:
-			return ieee754dp_inf(sn);
-		case IEEE754_RZ:
-			return ieee754dp_max(sn);
-		case IEEE754_RU:	/* toward +Infinity */
-			if (sn == 0)
-				return ieee754dp_inf(0);
-			else
-				return ieee754dp_max(1);
-		case IEEE754_RD:	/* toward -Infinity */
-			if (sn == 0)
-				return ieee754dp_max(0);
-			else
-				return ieee754dp_inf(1);
-		}
-	}
-	/* gen norm/denorm/zero */
-
-	if ((xm & DP_HIDDEN_BIT) == 0) {
-		/* we underflow (tiny/zero) */
-		assert(xe == DP_EMIN);
-		SETCX(IEEE754_UNDERFLOW);
-		return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm);
-	} else {
-		assert((xm >> (DP_MBITS + 1)) == 0);	/* no execess */
-		assert(xm & DP_HIDDEN_BIT);
-
-		return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/ieee754dp.h linux-2.4.20/arch/mips64/math-emu/ieee754dp.h
--- linux-2.4.19/arch/mips64/math-emu/ieee754dp.h	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/ieee754dp.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,83 +0,0 @@
-/* 
- * IEEE754 floating point
- * double precision internal header file
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754int.h"
-
-#define assert(expr) ((void)0)
-
-/* 3bit extended double precision sticky right shift */
-#define XDPSRS(v,rs)	\
-  ((rs > (DP_MBITS+3))?1:((v) >> (rs)) | ((v) << (64-(rs)) != 0))
-
-#define XDPSRSX1() \
-  (xe++, (xm = (xm >> 1) | (xm & 1)))
-
-#define XDPSRS1(v)	\
-  (((v) >> 1) | ((v) & 1))
-
-/* convert denormal to normalized with extended exponent */
-#define DPDNORMx(m,e) \
-  while( (m >> DP_MBITS) == 0) { m <<= 1; e--; }
-#define DPDNORMX	DPDNORMx(xm,xe)
-#define DPDNORMY	DPDNORMx(ym,ye)
-
-static __inline ieee754dp builddp(int s, int bx, unsigned long long m)
-{
-	ieee754dp r;
-
-	assert((s) == 0 || (s) == 1);
-	assert((bx) >= DP_EMIN - 1 + DP_EBIAS
-	       && (bx) <= DP_EMAX + 1 + DP_EBIAS);
-	assert(((m) >> DP_MBITS) == 0);
-
-	r.parts.sign = s;
-	r.parts.bexp = bx;
-	r.parts.mant = m;
-	return r;
-}
-
-extern int ieee754dp_isnan(ieee754dp);
-extern int ieee754dp_issnan(ieee754dp);
-extern int ieee754si_xcpt(int, const char *, ...);
-extern long long ieee754di_xcpt(long long, const char *, ...);
-extern ieee754dp ieee754dp_xcpt(ieee754dp, const char *, ...);
-extern ieee754dp ieee754dp_nanxcpt(ieee754dp, const char *, ...);
-extern ieee754dp ieee754dp_bestnan(ieee754dp, ieee754dp);
-extern ieee754dp ieee754dp_format(int, int, unsigned long long);
-
-
-#define DPNORMRET2(s,e,m,name,a0,a1) \
-{ \
-    ieee754dp V = ieee754dp_format(s,e,m); \
-    if(TSTX()) \
-      return ieee754dp_xcpt(V,name,a0,a1); \
-    else \
-      return V; \
-}
-
-#define DPNORMRET1(s,e,m,name,a0)  DPNORMRET2(s,e,m,name,a0,a0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/ieee754int.h linux-2.4.20/arch/mips64/math-emu/ieee754int.h
--- linux-2.4.19/arch/mips64/math-emu/ieee754int.h	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/ieee754int.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,135 +0,0 @@
-/* 
- * IEEE754 floating point
- * common internal header file
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754.h"
-
-#define DP_EBIAS	1023
-#define DP_EMIN		(-1022)
-#define DP_EMAX		1023
-#define DP_MBITS	52
-
-#define SP_EBIAS	127
-#define SP_EMIN		(-126)
-#define SP_EMAX		127
-#define SP_MBITS	23
-
-#define DP_MBIT(x)	((unsigned long long)1 << (x))
-#define DP_HIDDEN_BIT	DP_MBIT(DP_MBITS)
-#define DP_SIGN_BIT	DP_MBIT(63)
-
-#define SP_MBIT(x)	((unsigned long)1 << (x))
-#define SP_HIDDEN_BIT	SP_MBIT(SP_MBITS)
-#define SP_SIGN_BIT	SP_MBIT(31)
-
-
-#define SPSIGN(sp)	(sp.parts.sign)
-#define SPBEXP(sp)	(sp.parts.bexp)
-#define SPMANT(sp)	(sp.parts.mant)
-
-#define DPSIGN(dp)	(dp.parts.sign)
-#define DPBEXP(dp)	(dp.parts.bexp)
-#define DPMANT(dp)	(dp.parts.mant)
-
-#define CLPAIR(x,y)	((x)*6+(y))
-
-#define CLEARCX	\
-  (ieee754_csr.cx = 0)
-
-#define SETCX(x) \
-  (ieee754_csr.cx |= (x),ieee754_csr.sx |= (x),ieee754_csr.mx & (x))
-
-#define TSTX()	\
-	(ieee754_csr.cx & ieee754_csr.mx)
-
-
-#define COMPXSP \
-  unsigned xm; int xe; int xs; int xc
-
-#define COMPYSP \
-  unsigned ym; int ye; int ys; int yc
-
-#define EXPLODESP(v,vc,vs,ve,vm) \
-{\
-    vs = SPSIGN(v);\
-    ve = SPBEXP(v);\
-    vm = SPMANT(v);\
-    if(ve == SP_EMAX+1+SP_EBIAS){\
-	if(vm == 0)\
-	  vc = IEEE754_CLASS_INF;\
-	else if(vm & SP_MBIT(SP_MBITS-1)) \
-	  vc = IEEE754_CLASS_QNAN;\
-	else \
-	  vc = IEEE754_CLASS_SNAN;\
-    } else if(ve == SP_EMIN-1+SP_EBIAS) {\
-	if(vm) {\
-	    ve = SP_EMIN;\
-	    vc = IEEE754_CLASS_DNORM;\
-	} else\
-	  vc = IEEE754_CLASS_ZERO;\
-    } else {\
-	ve -= SP_EBIAS;\
-	vm |= SP_HIDDEN_BIT;\
-	vc = IEEE754_CLASS_NORM;\
-    }\
-}
-#define EXPLODEXSP EXPLODESP(x,xc,xs,xe,xm)
-#define EXPLODEYSP EXPLODESP(y,yc,ys,ye,ym)
-
-
-#define COMPXDP \
-unsigned long long xm; int xe; int xs; int xc
-
-#define COMPYDP \
-unsigned long long ym; int ye; int ys; int yc
-
-#define EXPLODEDP(v,vc,vs,ve,vm) \
-{\
-    vm = DPMANT(v);\
-    vs = DPSIGN(v);\
-    ve = DPBEXP(v);\
-    if(ve == DP_EMAX+1+DP_EBIAS){\
-	if(vm == 0)\
-	  vc = IEEE754_CLASS_INF;\
-	else if(vm & DP_MBIT(DP_MBITS-1)) \
-	  vc = IEEE754_CLASS_QNAN;\
-	else \
-	  vc = IEEE754_CLASS_SNAN;\
-    } else if(ve == DP_EMIN-1+DP_EBIAS) {\
-	if(vm) {\
-	    ve = DP_EMIN;\
-	    vc = IEEE754_CLASS_DNORM;\
-	} else\
-	  vc = IEEE754_CLASS_ZERO;\
-    } else {\
-	ve -= DP_EBIAS;\
-	vm |= DP_HIDDEN_BIT;\
-	vc = IEEE754_CLASS_NORM;\
-    }\
-}
-#define EXPLODEXDP EXPLODEDP(x,xc,xs,xe,xm)
-#define EXPLODEYDP EXPLODEDP(y,yc,ys,ye,ym)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/ieee754m.c linux-2.4.20/arch/mips64/math-emu/ieee754m.c
--- linux-2.4.19/arch/mips64/math-emu/ieee754m.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/ieee754m.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,56 +0,0 @@
-/*
- * floor, trunc, ceil
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754.h"
-
-ieee754dp ieee754dp_floor(ieee754dp x)
-{
-	ieee754dp i;
-
-	if (ieee754dp_lt(ieee754dp_modf(x, &i), ieee754dp_zero(0)))
-		return ieee754dp_sub(i, ieee754dp_one(0));
-	else
-		return i;
-}
-
-ieee754dp ieee754dp_ceil(ieee754dp x)
-{
-	ieee754dp i;
-
-	if (ieee754dp_gt(ieee754dp_modf(x, &i), ieee754dp_zero(0)))
-		return ieee754dp_add(i, ieee754dp_one(0));
-	else
-		return i;
-}
-
-ieee754dp ieee754dp_trunc(ieee754dp x)
-{
-	ieee754dp i;
-
-	(void) ieee754dp_modf(x, &i);
-	return i;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/ieee754sp.c linux-2.4.20/arch/mips64/math-emu/ieee754sp.c
--- linux-2.4.19/arch/mips64/math-emu/ieee754sp.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/ieee754sp.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,197 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754sp.h"
-
-int ieee754sp_class(ieee754sp x)
-{
-	COMPXSP;
-	EXPLODEXSP;
-	return xc;
-}
-
-int ieee754sp_isnan(ieee754sp x)
-{
-	return ieee754sp_class(x) >= IEEE754_CLASS_SNAN;
-}
-
-int ieee754sp_issnan(ieee754sp x)
-{
-	assert(ieee754sp_isnan(x));
-	if (ieee754_csr.noq)
-		return 1;
-	return !(SPMANT(x) & SP_MBIT(SP_MBITS - 1));
-}
-
-
-ieee754sp ieee754sp_xcpt(ieee754sp r, const char *op, ...)
-{
-	struct ieee754xctx ax;
-
-	if (!TSTX())
-		return r;
-
-	ax.op = op;
-	ax.rt = IEEE754_RT_SP;
-	ax.rv.sp = r;
-	va_start(ax.ap, op);
-	ieee754_xcpt(&ax);
-	return ax.rv.sp;
-}
-
-ieee754sp ieee754sp_nanxcpt(ieee754sp r, const char *op, ...)
-{
-	struct ieee754xctx ax;
-
-	assert(ieee754sp_isnan(r));
-
-	if (!ieee754sp_issnan(r))	/* QNAN does not cause invalid op !! */
-		return r;
-
-	if (!SETCX(IEEE754_INVALID_OPERATION)) {
-		/* not enabled convert to a quiet NaN */
-		if (ieee754_csr.noq)
-			return r;
-		SPMANT(r) |= SP_MBIT(SP_MBITS - 1);
-		return r;
-	}
-
-	ax.op = op;
-	ax.rt = 0;
-	ax.rv.sp = r;
-	va_start(ax.ap, op);
-	ieee754_xcpt(&ax);
-	return ax.rv.sp;
-}
-
-ieee754sp ieee754sp_bestnan(ieee754sp x, ieee754sp y)
-{
-	assert(ieee754sp_isnan(x));
-	assert(ieee754sp_isnan(y));
-
-	if (SPMANT(x) > SPMANT(y))
-		return x;
-	else
-		return y;
-}
-
-
-/* generate a normal/denormal number with over,under handeling
- * sn is sign
- * xe is an unbiased exponent
- * xm is 3bit extended precision value.
- */
-ieee754sp ieee754sp_format(int sn, int xe, unsigned xm)
-{
-	assert(xm);		/* we dont gen exact zeros (probably should) */
-
-	assert((xm >> (SP_MBITS + 1 + 3)) == 0);	/* no execess */
-	assert(xm & (SP_HIDDEN_BIT << 3));
-
-	if (xe < SP_EMIN) {
-		/* strip lower bits */
-		int es = SP_EMIN - xe;
-
-		if (ieee754_csr.nod) {
-			SETCX(IEEE754_UNDERFLOW);
-			return ieee754sp_zero(sn);
-		}
-
-		/* sticky right shift es bits 
-		 */
-		SPXSRSXn(es);
-
-		assert((xm & (SP_HIDDEN_BIT << 3)) == 0);
-		assert(xe == SP_EMIN);
-	}
-	if (xm & (SP_MBIT(3) - 1)) {
-		SETCX(IEEE754_INEXACT);
-		/* inexact must round of 3 bits 
-		 */
-		switch (ieee754_csr.rm) {
-		case IEEE754_RZ:
-			break;
-		case IEEE754_RN:
-			xm += 0x3 + ((xm >> 3) & 1);
-			/* xm += (xm&0x8)?0x4:0x3 */
-			break;
-		case IEEE754_RU:	/* toward +Infinity */
-			if (!sn)	/* ?? */
-				xm += 0x8;
-			break;
-		case IEEE754_RD:	/* toward -Infinity */
-			if (sn)	/* ?? */
-				xm += 0x8;
-			break;
-		}
-		/* adjust exponent for rounding add overflowing 
-		 */
-		if (xm >> (SP_MBITS + 1 + 3)) {	/* add causes mantissa overflow */
-			xm >>= 1;
-			xe++;
-		}
-	}
-	/* strip grs bits */
-	xm >>= 3;
-
-	assert((xm >> (SP_MBITS + 1)) == 0);	/* no execess */
-	assert(xe >= SP_EMIN);
-
-	if (xe > SP_EMAX) {
-		SETCX(IEEE754_OVERFLOW);
-		/* -O can be table indexed by (rm,sn) */
-		switch (ieee754_csr.rm) {
-		case IEEE754_RN:
-			return ieee754sp_inf(sn);
-		case IEEE754_RZ:
-			return ieee754sp_max(sn);
-		case IEEE754_RU:	/* toward +Infinity */
-			if (sn == 0)
-				return ieee754sp_inf(0);
-			else
-				return ieee754sp_max(1);
-		case IEEE754_RD:	/* toward -Infinity */
-			if (sn == 0)
-				return ieee754sp_max(0);
-			else
-				return ieee754sp_inf(1);
-		}
-	}
-	/* gen norm/denorm/zero */
-
-	if ((xm & SP_HIDDEN_BIT) == 0) {
-		/* we underflow (tiny/zero) */
-		assert(xe == SP_EMIN);
-		SETCX(IEEE754_UNDERFLOW);
-		return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm);
-	} else {
-		assert((xm >> (SP_MBITS + 1)) == 0);	/* no execess */
-		assert(xm & SP_HIDDEN_BIT);
-
-		return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/ieee754sp.h linux-2.4.20/arch/mips64/math-emu/ieee754sp.h
--- linux-2.4.19/arch/mips64/math-emu/ieee754sp.h	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/ieee754sp.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,89 +0,0 @@
-/* 
- * IEEE754 floating point
- * double precision internal header file
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754int.h"
-
-#define assert(expr) ((void)0)
-
-/* 3bit extended single precision sticky right shift */
-#define SPXSRSXn(rs) \
-  (xe += rs, \
-   xm = (rs > (SP_MBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0))
-
-#define SPXSRSX1() \
-  (xe++, (xm = (xm >> 1) | (xm & 1)))
-
-#define SPXSRSYn(rs) \
-   (ye+=rs, \
-    ym = (rs > (SP_MBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0))
-
-#define SPXSRSY1() \
-   (ye++, (ym = (ym >> 1) | (ym & 1)))
-
-/* convert denormal to normalized with extended exponent */
-#define SPDNORMx(m,e) \
-  while( (m >> SP_MBITS) == 0) { m <<= 1; e--; }
-#define SPDNORMX	SPDNORMx(xm,xe)
-#define SPDNORMY	SPDNORMx(ym,ye)
-
-static __inline ieee754sp buildsp(int s, int bx, unsigned m)
-{
-	ieee754sp r;
-
-	assert((s) == 0 || (s) == 1);
-	assert((bx) >= SP_EMIN - 1 + SP_EBIAS
-	       && (bx) <= SP_EMAX + 1 + SP_EBIAS);
-	assert(((m) >> SP_MBITS) == 0);
-
-	r.parts.sign = s;
-	r.parts.bexp = bx;
-	r.parts.mant = m;
-
-	return r;
-}
-
-extern int ieee754sp_isnan(ieee754sp);
-extern int ieee754sp_issnan(ieee754sp);
-extern int ieee754si_xcpt(int, const char *, ...);
-extern long long ieee754di_xcpt(long long, const char *, ...);
-extern ieee754sp ieee754sp_xcpt(ieee754sp, const char *, ...);
-extern ieee754sp ieee754sp_nanxcpt(ieee754sp, const char *, ...);
-extern ieee754sp ieee754sp_bestnan(ieee754sp, ieee754sp);
-extern ieee754sp ieee754sp_format(int, int, unsigned);
-
-
-#define SPNORMRET2(s,e,m,name,a0,a1) \
-{ \
-    ieee754sp V = ieee754sp_format(s,e,m); \
-    if(TSTX()) \
-      return ieee754sp_xcpt(V,name,a0,a1); \
-    else \
-      return V; \
-}
-
-#define SPNORMRET1(s,e,m,name,a0)  SPNORMRET2(s,e,m,name,a0,a0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/ieee754xcpt.c linux-2.4.20/arch/mips64/math-emu/ieee754xcpt.c
--- linux-2.4.19/arch/mips64/math-emu/ieee754xcpt.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/ieee754xcpt.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,48 +0,0 @@
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-/**************************************************************************
- *  Nov 7, 2000
- *  Added preprocessor hacks to map to Linux kernel diagnostics. 
- *
- *  Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
- *  Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
- *************************************************************************/
-
-#include "ieee754.h"
-
-/*
- * Very naff exception handler (you can plug in your own and
- * override this).
- */
-
-static const char *const rtnames[] = {
-	"sp", "dp", "xp", "si", "di"
-};
-
-void ieee754_xcpt(struct ieee754xctx *xcp)
-{
-	printk("floating point exception in \"%s\", type=%s\n",
-		xcp->op, rtnames[xcp->rt]);
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/kernel_linkage.c linux-2.4.20/arch/mips64/math-emu/kernel_linkage.c
--- linux-2.4.19/arch/mips64/math-emu/kernel_linkage.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/kernel_linkage.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,95 +0,0 @@
-/**************************************************************************
- *
- *  arch/mips/math_emu/kernel_linkage.c
- *
- *  Kevin D. Kissell, kevink@mips and Carsten Langgaard, carstenl@mips.com
- *  Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- *************************************************************************/
-/*
- * Routines corresponding to Linux kernel FP context
- * manipulation primitives for the Algorithmics MIPS
- * FPU Emulator
- */
-
-#include <linux/sched.h>
-#include <asm/processor.h>
-#include <asm/signal.h>
-#include <asm/uaccess.h>
-
-#include <asm/fpu_emulator.h>
-
-extern struct mips_fpu_emulator_private fpuemuprivate;
-
-#define SIGNALLING_NAN 0x7ff800007ff80000LL
-
-void fpu_emulator_init_fpu(void)
-{
-	static int first = 1;
-	int i;
- 
-	if (first) {
-		first = 0;
-		printk("Algorithmics/MIPS FPU Emulator v1.4\n");
-	}
-
-	current->thread.fpu.soft.sr = 0;
-	for (i = 0; i < 32; i++) {
-		current->thread.fpu.soft.regs[i] = SIGNALLING_NAN;
-	}
-}
-
-
-/*
- * Emulator context save/restore to/from a signal context
- * presumed to be on the user stack, and therefore accessed
- * with appropriate macros from uaccess.h
- */
-
-int fpu_emulator_save_context(struct sigcontext *sc)
-{
-	int i;
-	int err = 0;
-
-	for (i = 0; i < 32; i++) {
-		err |=
-		    __put_user(current->thread.fpu.soft.regs[i],
-			       &sc->sc_fpregs[i]);
-	}
-	err |= __put_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr);
-	err |= __put_user(fpuemuprivate.eir, &sc->sc_fpc_eir);
-
-	return err;
-}
-
-int fpu_emulator_restore_context(struct sigcontext *sc)
-{
-	int i;
-	int err = 0;
-
-	for (i = 0; i < 32; i++) {
-		err |=
-		    __get_user(current->thread.fpu.soft.regs[i],
-			       &sc->sc_fpregs[i]);
-	}
-	err |= __get_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr);
-	err |= __get_user(fpuemuprivate.eir, &sc->sc_fpc_eir);
-
-	return err;
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/sp_add.c linux-2.4.20/arch/mips64/math-emu/sp_add.c
--- linux-2.4.19/arch/mips64/math-emu/sp_add.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/sp_add.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,180 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754sp.h"
-
-ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y)
-{
-	COMPXSP;
-	COMPYSP;
-
-	EXPLODEXSP;
-	EXPLODEYSP;
-
-	CLEARCX;
-
-	switch (CLPAIR(xc, yc)) {
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
-		return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "add", x,
-					 y);
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
-		return ieee754sp_nanxcpt(y, "add", x, y);
-
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-		return ieee754sp_nanxcpt(x, "add", x, y);
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
-		return ieee754sp_bestnan(x, y);
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
-		return y;
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
-		return x;
-
-
-		/* Inifity handeling 
-		 */
-
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
-		if (xs == ys)
-			return x;
-		SETCX(IEEE754_INVALID_OPERATION);
-		return ieee754sp_xcpt(ieee754sp_indef(), "add", x, y);
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
-		return y;
-
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
-		return x;
-
-		/* Zero handeling 
-		 */
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-		if (xs == ys)
-			return x;
-		else
-			return ieee754sp_zero(ieee754_csr.rm ==
-					      IEEE754_RD);
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
-		return x;
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
-		return y;
-
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
-		SPDNORMX;
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
-		SPDNORMY;
-		break;
-
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
-		SPDNORMX;
-		break;
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
-		break;
-	}
-	assert(xm & SP_HIDDEN_BIT);
-	assert(ym & SP_HIDDEN_BIT);
-
-	/* provide guard,round and stick bit space */
-	xm <<= 3;
-	ym <<= 3;
-
-	if (xe > ye) {
-		/* have to shift y fraction right to align
-		 */
-		int s = xe - ye;
-		SPXSRSYn(s);
-	} else if (ye > xe) {
-		/* have to shift x fraction right to align
-		 */
-		int s = ye - xe;
-		SPXSRSXn(s);
-	}
-	assert(xe == ye);
-	assert(xe <= SP_EMAX);
-
-	if (xs == ys) {
-		/* generate 28 bit result of adding two 27 bit numbers
-		 * leaving result in xm,xs,xe
-		 */
-		xm = xm + ym;
-		xe = xe;
-		xs = xs;
-
-		if (xm >> (SP_MBITS + 1 + 3)) {	/* carry out */
-			SPXSRSX1();
-		}
-	} else {
-		if (xm >= ym) {
-			xm = xm - ym;
-			xe = xe;
-			xs = xs;
-		} else {
-			xm = ym - xm;
-			xe = xe;
-			xs = ys;
-		}
-		if (xm == 0)
-			return ieee754sp_zero(ieee754_csr.rm ==
-					      IEEE754_RD);
-
-		/* normalize in extended single precision */
-		while ((xm >> (SP_MBITS + 3)) == 0) {
-			xm <<= 1;
-			xe--;
-		}
-
-	}
-	SPNORMRET2(xs, xe, xm, "add", x, y);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/sp_cmp.c linux-2.4.20/arch/mips64/math-emu/sp_cmp.c
--- linux-2.4.19/arch/mips64/math-emu/sp_cmp.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/sp_cmp.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,58 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754sp.h"
-
-int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp)
-{
-	CLEARCX;
-
-	if (ieee754sp_isnan(x) || ieee754sp_isnan(y)) {
-		if (cmp & IEEE754_CUN)
-			return 1;
-		if (cmp & (IEEE754_CLT | IEEE754_CGT)) {
-			if (SETCX(IEEE754_INVALID_OPERATION))
-				return ieee754si_xcpt(0, "fcmpf", x);
-		}
-		return 0;
-	} else {
-		int vx = x.bits;
-		int vy = y.bits;
-
-		if (vx < 0)
-			vx = -vx ^ SP_SIGN_BIT;
-		if (vy < 0)
-			vy = -vy ^ SP_SIGN_BIT;
-
-		if (vx < vy)
-			return (cmp & IEEE754_CLT) != 0;
-		else if (vx == vy)
-			return (cmp & IEEE754_CEQ) != 0;
-		else
-			return (cmp & IEEE754_CGT) != 0;
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/sp_div.c linux-2.4.20/arch/mips64/math-emu/sp_div.c
--- linux-2.4.19/arch/mips64/math-emu/sp_div.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/sp_div.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,160 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754sp.h"
-
-ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y)
-{
-	COMPXSP;
-	COMPYSP;
-
-	CLEARCX;
-
-	EXPLODEXSP;
-	EXPLODEYSP;
-
-	switch (CLPAIR(xc, yc)) {
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
-		return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "div", x,
-					 y);
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
-		return ieee754sp_nanxcpt(y, "div", x, y);
-
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-		return ieee754sp_nanxcpt(x, "div", x, y);
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
-		return ieee754sp_bestnan(x, y);
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
-		return y;
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
-		return x;
-
-
-		/* Infinity handeling 
-		 */
-
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
-		SETCX(IEEE754_INVALID_OPERATION);
-		return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y);
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
-		return ieee754sp_zero(xs ^ ys);
-
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
-		return ieee754sp_inf(xs ^ ys);
-
-		/* Zero handeling 
-		 */
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-		SETCX(IEEE754_INVALID_OPERATION);
-		return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y);
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
-		SETCX(IEEE754_ZERO_DIVIDE);
-		return ieee754sp_xcpt(ieee754sp_inf(xs ^ ys), "div", x, y);
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
-		return ieee754sp_zero(xs == ys ? 0 : 1);
-
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
-		SPDNORMX;
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
-		SPDNORMY;
-		break;
-
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
-		SPDNORMX;
-		break;
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
-		break;
-	}
-	assert(xm & SP_HIDDEN_BIT);
-	assert(ym & SP_HIDDEN_BIT);
-
-	/* provide rounding space */
-	xm <<= 3;
-	ym <<= 3;
-
-	{
-		/* now the dirty work */
-
-		unsigned rm = 0;
-		int re = xe - ye;
-		unsigned bm;
-
-		for (bm = SP_MBIT(SP_MBITS + 2); bm; bm >>= 1) {
-			if (xm >= ym) {
-				xm -= ym;
-				rm |= bm;
-				if (xm == 0)
-					break;
-			}
-			xm <<= 1;
-		}
-		rm <<= 1;
-		if (xm)
-			rm |= 1;	/* have remainder, set sticky */
-
-		assert(rm);
-
-		/* normalise rm to rounding precision ?
-		 */
-		while ((rm >> (SP_MBITS + 3)) == 0) {
-			rm <<= 1;
-			re--;
-		}
-
-		SPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y);
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/sp_fdp.c linux-2.4.20/arch/mips64/math-emu/sp_fdp.c
--- linux-2.4.19/arch/mips64/math-emu/sp_fdp.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/sp_fdp.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,69 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754sp.h"
-
-ieee754sp ieee754sp_fdp(ieee754dp x)
-{
-	COMPXDP;
-
-	CLEARCX;
-
-	EXPLODEXDP;
-
-	switch (xc) {
-	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_SNAN:
-		return ieee754sp_nanxcpt(buildsp(xs,
-						 SP_EMAX + 1 + SP_EBIAS,
-						 (unsigned long)
-						 (xm >>
-						  (DP_MBITS - SP_MBITS))),
-					 "fdp", x);
-	case IEEE754_CLASS_INF:
-		return ieee754sp_inf(xs);
-	case IEEE754_CLASS_ZERO:
-		return ieee754sp_zero(xs);
-	case IEEE754_CLASS_DNORM:
-		/* cant possibly be sp representable */
-		SETCX(IEEE754_UNDERFLOW);
-		return ieee754sp_xcpt(ieee754sp_zero(xs), "fdp", x);
-	case IEEE754_CLASS_NORM:
-		break;
-	}
-
-	{
-		unsigned long rm;
-
-		/* convert from DP_MBITS to SP_MBITS+3 with sticky right shift 
-		 */
-		rm = (xm >> (DP_MBITS - (SP_MBITS + 3))) |
-		    ((xm << (64 - (DP_MBITS - (SP_MBITS + 3)))) != 0);
-
-		SPNORMRET1(xs, xe, rm, "fdp", x);
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/sp_fint.c linux-2.4.20/arch/mips64/math-emu/sp_fint.c
--- linux-2.4.19/arch/mips64/math-emu/sp_fint.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/sp_fint.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,78 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754sp.h"
-
-ieee754sp ieee754sp_fint(int x)
-{
-	COMPXSP;
-
-	CLEARCX;
-
-	if (x == 0)
-		return ieee754sp_zero(0);
-	if (x == 1 || x == -1)
-		return ieee754sp_one(x < 0);
-	if (x == 10 || x == -10)
-		return ieee754sp_ten(x < 0);
-
-	xs = (x < 0);
-	if (xs) {
-		if (x == (1 << 31))
-			xm = ((unsigned) 1 << 31);	/* max neg can't be safely negated */
-		else
-			xm = -x;
-	} else {
-		xm = x;
-	}
-	xe = SP_MBITS + 3;
-
-	if (xm >> (SP_MBITS + 1 + 3)) {
-		/* shunt out overflow bits 
-		 */
-		while (xm >> (SP_MBITS + 1 + 3)) {
-			SPXSRSX1();
-		}
-	} else {
-		/* normalize in grs extended single precision 
-		 */
-		while ((xm >> (SP_MBITS + 3)) == 0) {
-			xm <<= 1;
-			xe--;
-		}
-	}
-	SPNORMRET1(xs, xe, xm, "fint", x);
-}
-
-
-ieee754sp ieee754sp_funs(unsigned int u)
-{
-	if ((int) u < 0)
-		return ieee754sp_add(ieee754sp_1e31(),
-				     ieee754sp_fint(u & ~(1 << 31)));
-	return ieee754sp_fint(u);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/sp_flong.c linux-2.4.20/arch/mips64/math-emu/sp_flong.c
--- linux-2.4.19/arch/mips64/math-emu/sp_flong.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/sp_flong.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,77 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754sp.h"
-
-ieee754sp ieee754sp_flong(long long x)
-{
-	COMPXDP;		/* <--- need 64-bit mantissa temp */
-
-	CLEARCX;
-
-	if (x == 0)
-		return ieee754sp_zero(0);
-	if (x == 1 || x == -1)
-		return ieee754sp_one(x < 0);
-	if (x == 10 || x == -10)
-		return ieee754sp_ten(x < 0);
-
-	xs = (x < 0);
-	if (xs) {
-		if (x == (1ULL << 63))
-			xm = (1ULL << 63);	/* max neg can't be safely negated */
-		else
-			xm = -x;
-	} else {
-		xm = x;
-	}
-	xe = SP_MBITS + 3;
-
-	if (xm >> (SP_MBITS + 1 + 3)) {
-		/* shunt out overflow bits 
-		 */
-		while (xm >> (SP_MBITS + 1 + 3)) {
-			SPXSRSX1();
-		}
-	} else {
-		/* normalize in grs extended single precision */
-		while ((xm >> (SP_MBITS + 3)) == 0) {
-			xm <<= 1;
-			xe--;
-		}
-	}
-	SPNORMRET1(xs, xe, xm, "sp_flong", x);
-}
-
-
-ieee754sp ieee754sp_fulong(unsigned long long u)
-{
-	if ((long long) u < 0)
-		return ieee754sp_add(ieee754sp_1e63(),
-				     ieee754sp_flong(u & ~(1ULL << 63)));
-	return ieee754sp_flong(u);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/sp_frexp.c linux-2.4.20/arch/mips64/math-emu/sp_frexp.c
--- linux-2.4.19/arch/mips64/math-emu/sp_frexp.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/sp_frexp.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,53 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754sp.h"
-
-/* close to ieeep754sp_logb 
-*/
-ieee754sp ieee754sp_frexp(ieee754sp x, int *eptr)
-{
-	COMPXSP;
-	CLEARCX;
-	EXPLODEXSP;
-
-	switch (xc) {
-	case IEEE754_CLASS_SNAN:
-	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_INF:
-	case IEEE754_CLASS_ZERO:
-		*eptr = 0;
-		return x;
-	case IEEE754_CLASS_DNORM:
-		SPDNORMX;
-		break;
-	case IEEE754_CLASS_NORM:
-		break;
-	}
-	*eptr = xe + 1;
-	return buildsp(xs, -1 + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/sp_logb.c linux-2.4.20/arch/mips64/math-emu/sp_logb.c
--- linux-2.4.19/arch/mips64/math-emu/sp_logb.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/sp_logb.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,54 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754sp.h"
-
-ieee754sp ieee754sp_logb(ieee754sp x)
-{
-	COMPXSP;
-
-	CLEARCX;
-
-	EXPLODEXSP;
-
-	switch (xc) {
-	case IEEE754_CLASS_SNAN:
-		return ieee754sp_nanxcpt(x, "logb", x);
-	case IEEE754_CLASS_QNAN:
-		return x;
-	case IEEE754_CLASS_INF:
-		return ieee754sp_inf(0);
-	case IEEE754_CLASS_ZERO:
-		return ieee754sp_inf(1);
-	case IEEE754_CLASS_DNORM:
-		SPDNORMX;
-		break;
-	case IEEE754_CLASS_NORM:
-		break;
-	}
-	return ieee754sp_fint(xe);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/sp_modf.c linux-2.4.20/arch/mips64/math-emu/sp_modf.c
--- linux-2.4.19/arch/mips64/math-emu/sp_modf.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/sp_modf.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,80 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754sp.h"
-
-/* modf function is always exact for a finite number
-*/
-ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip)
-{
-	COMPXSP;
-
-	CLEARCX;
-
-	EXPLODEXSP;
-
-	switch (xc) {
-	case IEEE754_CLASS_SNAN:
-	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_INF:
-	case IEEE754_CLASS_ZERO:
-		*ip = x;
-		return x;
-	case IEEE754_CLASS_DNORM:
-		/* far to small */
-		*ip = ieee754sp_zero(xs);
-		return x;
-	case IEEE754_CLASS_NORM:
-		break;
-	}
-	if (xe < 0) {
-		*ip = ieee754sp_zero(xs);
-		return x;
-	}
-	if (xe >= SP_MBITS) {
-		*ip = x;
-		return ieee754sp_zero(xs);
-	}
-	/* generate ipart mantissa by clearing bottom bits 
-	 */
-	*ip = buildsp(xs, xe + SP_EBIAS,
-		      ((xm >> (SP_MBITS - xe)) << (SP_MBITS - xe)) &
-		      ~SP_HIDDEN_BIT);
-
-	/* generate fpart mantissa by clearing top bits
-	 * and normalizing (must be able to normalize)
-	 */
-	xm = (xm << (32 - (SP_MBITS - xe))) >> (32 - (SP_MBITS - xe));
-	if (xm == 0)
-		return ieee754sp_zero(xs);
-
-	while ((xm >> SP_MBITS) == 0) {
-		xm <<= 1;
-		xe--;
-	}
-	return buildsp(xs, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/sp_mul.c linux-2.4.20/arch/mips64/math-emu/sp_mul.c
--- linux-2.4.19/arch/mips64/math-emu/sp_mul.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/sp_mul.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,174 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754sp.h"
-
-ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y)
-{
-	COMPXSP;
-	COMPYSP;
-
-	CLEARCX;
-
-	EXPLODEXSP;
-	EXPLODEYSP;
-
-	switch (CLPAIR(xc, yc)) {
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
-		return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "mul", x,
-					 y);
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
-		return ieee754sp_nanxcpt(y, "mul", x, y);
-
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-		return ieee754sp_nanxcpt(x, "mul", x, y);
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
-		return ieee754sp_bestnan(x, y);
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
-		return y;
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
-		return x;
-
-
-		/* Infinity handeling */
-
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
-		SETCX(IEEE754_INVALID_OPERATION);
-		return ieee754sp_xcpt(ieee754sp_indef(), "mul", x, y);
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
-		return ieee754sp_inf(xs ^ ys);
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
-		return ieee754sp_zero(xs ^ ys);
-
-
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
-		SPDNORMX;
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
-		SPDNORMY;
-		break;
-
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
-		SPDNORMX;
-		break;
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
-		break;
-	}
-	/* rm = xm * ym, re = xe+ye basicly */
-	assert(xm & SP_HIDDEN_BIT);
-	assert(ym & SP_HIDDEN_BIT);
-
-	{
-		int re = xe + ye;
-		int rs = xs ^ ys;
-		unsigned rm;
-
-		/* shunt to top of word */
-		xm <<= 32 - (SP_MBITS + 1);
-		ym <<= 32 - (SP_MBITS + 1);
-
-		/* multiply 32bits xm,ym to give high 32bits rm with stickness
-		 */
-		{
-			unsigned short lxm = xm & 0xffff;
-			unsigned short hxm = xm >> 16;
-			unsigned short lym = ym & 0xffff;
-			unsigned short hym = ym >> 16;
-			unsigned lrm;
-			unsigned hrm;
-
-			lrm = lxm * lym;	/* 16 * 16 => 32 */
-			hrm = hxm * hym;	/* 16 * 16 => 32 */
-
-			{
-				unsigned t = lxm * hym;	/* 16 * 16 => 32 */
-				{
-					unsigned at = lrm + (t << 16);
-					hrm += at < lrm;
-					lrm = at;
-				}
-				hrm = hrm + (t >> 16);
-			}
-
-			{
-				unsigned t = hxm * lym;	/* 16 * 16 => 32 */
-				{
-					unsigned at = lrm + (t << 16);
-					hrm += at < lrm;
-					lrm = at;
-				}
-				hrm = hrm + (t >> 16);
-			}
-			rm = hrm | (lrm != 0);
-		}
-
-		/*
-		 * sticky shift down to normal rounding precision
-		 */
-		if ((int) rm < 0) {
-			rm = (rm >> (32 - (SP_MBITS + 1 + 3))) |
-			    ((rm << (SP_MBITS + 1 + 3)) != 0);
-			re++;
-		} else {
-			rm = (rm >> (32 - (SP_MBITS + 1 + 3 + 1))) |
-			    ((rm << (SP_MBITS + 1 + 3 + 1)) != 0);
-		}
-		assert(rm & (SP_HIDDEN_BIT << 3));
-
-		SPNORMRET2(rs, re, rm, "mul", x, y);
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/sp_scalb.c linux-2.4.20/arch/mips64/math-emu/sp_scalb.c
--- linux-2.4.19/arch/mips64/math-emu/sp_scalb.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/sp_scalb.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,58 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754sp.h"
-
-ieee754sp ieee754sp_scalb(ieee754sp x, int n)
-{
-	COMPXSP;
-
-	CLEARCX;
-
-	EXPLODEXSP;
-
-	switch (xc) {
-	case IEEE754_CLASS_SNAN:
-		return ieee754sp_nanxcpt(x, "scalb", x, n);
-	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_INF:
-	case IEEE754_CLASS_ZERO:
-		return x;
-	case IEEE754_CLASS_DNORM:
-		SPDNORMX;
-		break;
-	case IEEE754_CLASS_NORM:
-		break;
-	}
-	SPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n);
-}
-
-
-ieee754sp ieee754sp_ldexp(ieee754sp x, int n)
-{
-	return ieee754sp_scalb(x, n);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/sp_simple.c linux-2.4.20/arch/mips64/math-emu/sp_simple.c
--- linux-2.4.19/arch/mips64/math-emu/sp_simple.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/sp_simple.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,66 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754sp.h"
-
-int ieee754sp_finite(ieee754sp x)
-{
-	return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS;
-}
-
-ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y)
-{
-	CLEARCX;
-	SPSIGN(x) = SPSIGN(y);
-	return x;
-}
-
-
-ieee754sp ieee754sp_neg(ieee754sp x)
-{
-	CLEARCX;
-
-	if (ieee754sp_isnan(x))	/* but not infinity */
-		return ieee754sp_nanxcpt(x, "neg", x);
-
-	/* quick fix up */
-	SPSIGN(x) ^= 1;
-	return x;
-}
-
-
-ieee754sp ieee754sp_abs(ieee754sp x)
-{
-	CLEARCX;
-
-	if (ieee754sp_isnan(x))	/* but not infinity */
-		return ieee754sp_nanxcpt(x, "abs", x);
-
-	/* quick fix up */
-	SPSIGN(x) = 0;
-	return x;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/sp_sqrt.c linux-2.4.20/arch/mips64/math-emu/sp_sqrt.c
--- linux-2.4.19/arch/mips64/math-emu/sp_sqrt.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/sp_sqrt.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,115 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision square root
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754sp.h"
-
-static const struct ieee754sp_konst knan = {
-	0, SP_EBIAS + SP_EMAX + 1, 0
-};
-
-#define nan	((ieee754sp)knan)
-
-ieee754sp ieee754sp_sqrt(ieee754sp x)
-{
-	int sign = (int) 0x80000000;
-	int ix, s, q, m, t, i;
-	unsigned int r;
-	COMPXDP;
-
-	/* take care of Inf and NaN */
-
-	EXPLODEXDP;
-
-	/* x == INF or NAN? */
-	switch (xc) {
-	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_SNAN:
-		/* sqrt(Nan) = Nan */
-		return ieee754sp_nanxcpt(x, "sqrt");
-	case IEEE754_CLASS_ZERO:
-		/* sqrt(0) = 0 */
-		return x;
-	case IEEE754_CLASS_INF:
-		if (xs)
-			/* sqrt(-Inf) = Nan */
-			return ieee754sp_nanxcpt(nan, "sqrt");
-		/* sqrt(+Inf) = Inf */
-		return x;
-	case IEEE754_CLASS_DNORM:
-	case IEEE754_CLASS_NORM:
-		if (xs)
-			/* sqrt(-x) = Nan */
-			return ieee754sp_nanxcpt(nan, "sqrt");
-		break;
-	}
-
-	ix = x.bits;
-
-	/* normalize x */
-	m = (ix >> 23);
-	if (m == 0) {		/* subnormal x */
-		for (i = 0; (ix & 0x00800000) == 0; i++)
-			ix <<= 1;
-		m -= i - 1;
-	}
-	m -= 127;		/* unbias exponent */
-	ix = (ix & 0x007fffff) | 0x00800000;
-	if (m & 1)		/* odd m, double x to make it even */
-		ix += ix;
-	m >>= 1;		/* m = [m/2] */
-
-	/* generate sqrt(x) bit by bit */
-	ix += ix;
-	q = s = 0;		/* q = sqrt(x) */
-	r = 0x01000000;		/* r = moving bit from right to left */
-
-	while (r != 0) {
-		t = s + r;
-		if (t <= ix) {
-			s = t + r;
-			ix -= t;
-			q += r;
-		}
-		ix += ix;
-		r >>= 1;
-	}
-
-	if (ix != 0) {
-		switch (ieee754_csr.rm) {
-		case IEEE754_RP:
-			q += 2;
-			break;
-		case IEEE754_RN:
-			q += (q & 1);
-			break;
-		}
-	}
-	ix = (q >> 1) + 0x3f000000;
-	ix += (m << 23);
-	x.bits = ix;
-	return x;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/sp_sub.c linux-2.4.20/arch/mips64/math-emu/sp_sub.c
--- linux-2.4.19/arch/mips64/math-emu/sp_sub.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/sp_sub.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,187 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754sp.h"
-
-ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y)
-{
-	COMPXSP;
-	COMPYSP;
-
-	CLEARCX;
-
-	EXPLODEXSP;
-	EXPLODEYSP;
-
-	switch (CLPAIR(xc, yc)) {
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
-		return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "sub", x,
-					 y);
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
-		return ieee754sp_nanxcpt(y, "sub", x, y);
-
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-		return ieee754sp_nanxcpt(x, "sub", x, y);
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
-		return ieee754sp_bestnan(x, y);
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
-		return y;
-
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
-	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
-		return x;
-
-
-		/* Inifity handeling 
-		 */
-
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
-		if (xs != ys)
-			return x;
-		SETCX(IEEE754_INVALID_OPERATION);
-		return ieee754sp_xcpt(ieee754sp_indef(), "sub", x, y);
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
-		return ieee754sp_inf(ys ^ 1);
-
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
-		return x;
-
-		/* Zero handeling 
-		 */
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-		if (xs != ys)
-			return x;
-		else
-			return ieee754sp_zero(ieee754_csr.rm ==
-					      IEEE754_RD);
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
-		return x;
-
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
-	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
-		/* quick fix up */
-		DPSIGN(y) ^= 1;
-		return y;
-
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
-		SPDNORMX;
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
-		SPDNORMY;
-		break;
-
-	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
-		SPDNORMX;
-		break;
-
-	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
-		break;
-	}
-	/* flip sign of y and handle as add */
-	ys ^= 1;
-
-	assert(xm & SP_HIDDEN_BIT);
-	assert(ym & SP_HIDDEN_BIT);
-
-
-	/* provide guard,round and stick bit space */
-	xm <<= 3;
-	ym <<= 3;
-
-	if (xe > ye) {
-		/* have to shift y fraction right to align
-		 */
-		int s = xe - ye;
-		SPXSRSYn(s);
-	} else if (ye > xe) {
-		/* have to shift x fraction right to align
-		 */
-		int s = ye - xe;
-		SPXSRSXn(s);
-	}
-	assert(xe == ye);
-	assert(xe <= SP_EMAX);
-
-	if (xs == ys) {
-		/* generate 28 bit result of adding two 27 bit numbers
-		 */
-		xm = xm + ym;
-		xe = xe;
-		xs = xs;
-
-		if (xm >> (SP_MBITS + 1 + 3)) {	/* carry out */
-			SPXSRSX1();	/* shift preserving sticky */
-		}
-	} else {
-		if (xm >= ym) {
-			xm = xm - ym;
-			xe = xe;
-			xs = xs;
-		} else {
-			xm = ym - xm;
-			xe = xe;
-			xs = ys;
-		}
-		if (xm == 0)
-			if (ieee754_csr.rm == IEEE754_RD)
-				return ieee754sp_zero(1);	/* round negative inf. => sign = -1 */
-			else
-				return ieee754sp_zero(0);	/* other round modes   => sign = 1 */
-
-		/* normalize to rounding precision 
-		 */
-		while ((xm >> (SP_MBITS + 3)) == 0) {
-			xm <<= 1;
-			xe--;
-		}
-	}
-	SPNORMRET2(xs, xe, xm, "sub", x, y);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/sp_tint.c linux-2.4.20/arch/mips64/math-emu/sp_tint.c
--- linux-2.4.19/arch/mips64/math-emu/sp_tint.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/sp_tint.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,88 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include <linux/kernel.h>
-#include "ieee754sp.h"
-
-int ieee754sp_tint(ieee754sp x)
-{
-	COMPXSP;
-
-	CLEARCX;
-
-	EXPLODEXSP;
-
-	switch (xc) {
-	case IEEE754_CLASS_SNAN:
-	case IEEE754_CLASS_QNAN:
-		SETCX(IEEE754_INVALID_OPERATION);
-		return ieee754si_xcpt(ieee754si_indef(), "fixsp", x);
-	case IEEE754_CLASS_INF:
-		SETCX(IEEE754_OVERFLOW);
-		return ieee754si_xcpt(ieee754si_indef(), "fixsp", x);
-	case IEEE754_CLASS_ZERO:
-		return 0;
-	case IEEE754_CLASS_DNORM:	/* much to small */
-		SETCX(IEEE754_UNDERFLOW);
-		return ieee754si_xcpt(0, "fixsp", x);
-	case IEEE754_CLASS_NORM:
-		break;
-	}
-	if (xe >= 31) {
-		SETCX(IEEE754_OVERFLOW);
-		return ieee754si_xcpt(ieee754si_indef(), "fix", x);
-	}
-	if (xe < 0) {
-		SETCX(IEEE754_UNDERFLOW);
-		return ieee754si_xcpt(0, "fix", x);
-	}
-	/* oh gawd */
-	if (xe > SP_MBITS) {
-		xm <<= xe - SP_MBITS;
-	} else if (xe < SP_MBITS) {
-		/* XXX no rounding 
-		 */
-		xm >>= SP_MBITS - xe;
-	}
-	if (xs)
-		return -xm;
-	else
-		return xm;
-}
-
-
-unsigned int ieee754sp_tuns(ieee754sp x)
-{
-	ieee754sp hb = ieee754sp_1e31();
-
-	/* what if x < 0 ?? */
-	if (ieee754sp_lt(x, hb))
-		return (unsigned) ieee754sp_tint(x);
-
-	return (unsigned) ieee754sp_tint(ieee754sp_sub(x, hb)) |
-	    ((unsigned) 1 << 31);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/math-emu/sp_tlong.c linux-2.4.20/arch/mips64/math-emu/sp_tlong.c
--- linux-2.4.19/arch/mips64/math-emu/sp_tlong.c	2001-07-02 20:56:41.000000000 +0000
+++ linux-2.4.20/arch/mips64/math-emu/sp_tlong.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,87 +0,0 @@
-/* IEEE754 floating point arithmetic
- * single precision
- */
-/*
- * MIPS floating point support
- * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
- * http://www.algor.co.uk
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- */
-
-
-#include "ieee754sp.h"
-
-long long ieee754sp_tlong(ieee754sp x)
-{
-	COMPXDP;		/* <-- need 64-bit mantissa tmp */
-
-	CLEARCX;
-
-	EXPLODEXSP;
-
-	switch (xc) {
-	case IEEE754_CLASS_SNAN:
-	case IEEE754_CLASS_QNAN:
-		SETCX(IEEE754_INVALID_OPERATION);
-		return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x);
-	case IEEE754_CLASS_INF:
-		SETCX(IEEE754_OVERFLOW);
-		return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x);
-	case IEEE754_CLASS_ZERO:
-		return 0;
-	case IEEE754_CLASS_DNORM:	/* much to small */
-		SETCX(IEEE754_UNDERFLOW);
-		return ieee754di_xcpt(0, "sp_tlong", x);
-	case IEEE754_CLASS_NORM:
-		break;
-	}
-	if (xe >= 63) {
-		SETCX(IEEE754_OVERFLOW);
-		return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x);
-	}
-	if (xe < 0) {
-		SETCX(IEEE754_UNDERFLOW);
-		return ieee754di_xcpt(0, "sp_tlong", x);
-	}
-	/* oh gawd */
-	if (xe > SP_MBITS) {
-		xm <<= xe - SP_MBITS;
-	} else if (xe < SP_MBITS) {
-		/* XXX no rounding 
-		 */
-		xm >>= SP_MBITS - xe;
-	}
-	if (xs)
-		return -xm;
-	else
-		return xm;
-}
-
-
-unsigned long long ieee754sp_tulong(ieee754sp x)
-{
-	ieee754sp hb = ieee754sp_1e63();
-
-	/* what if x < 0 ?? */
-	if (ieee754sp_lt(x, hb))
-		return (unsigned long long) ieee754sp_tlong(x);
-
-	return (unsigned long long) ieee754sp_tlong(ieee754sp_sub(x, hb)) |
-	    (1ULL << 63);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/mm/Makefile linux-2.4.20/arch/mips64/mm/Makefile
--- linux-2.4.19/arch/mips64/mm/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/mm/Makefile	2002-10-29 11:18:31.000000000 +0000
@@ -11,11 +11,15 @@
 
 obj-$(CONFIG_CPU_R4300)		+= r4xx0.o tlbex-r4k.o tlb-glue-r4k.o
 obj-$(CONFIG_CPU_R4X00)		+= r4xx0.o tlbex-r4k.o tlb-glue-r4k.o
-obj-$(CONFIG_CPU_R5000)		+= r4xx0.o tlbex-r4k.o tlb-glue-r4k.o
-obj-$(CONFIG_CPU_NEVADA)	+= r4xx0.o tlbex-r4k.o tlb-glue-r4k.o
+obj-$(CONFIG_CPU_R5000)		+= r4xx0.o tlbex-r4k.o tlb-glue-r4k.o \
+				   r5k-sc.o
+obj-$(CONFIG_CPU_NEVADA)	+= r4xx0.o tlbex-r4k.o tlb-glue-r4k.o \
+				   r5k-sc.o
 obj-$(CONFIG_CPU_R10000)	+= andes.o tlbex-r4k.o tlb-glue-r4k.o
 obj-$(CONFIG_CPU_SB1)		+= pg-sb1.o c-sb1.o tlb-sb1.o tlbex-r4k.o \
 				   tlb-glue-r4k.o
+obj-$(CONFIG_CPU_MIPS64)	+= pg-mips64.o c-mips64.o tlb-r4k.o \
+				   tlbex-r4k.o tlb-glue-r4k.o
 
 #
 # Debug TLB exception handler, currently unused
@@ -24,6 +28,6 @@
 
 obj-$(CONFIG_SGI_IP22)		+= umap.o
 
-CFLAGS_tlb-glue-r4k.o := -P
+AFLAGS_tlb-glue-r4k.o := -P
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/mm/andes.c linux-2.4.20/arch/mips64/mm/andes.c
--- linux-2.4.19/arch/mips64/mm/andes.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/mm/andes.c	2002-10-29 11:18:32.000000000 +0000
@@ -328,7 +328,7 @@
 			printk(KERN_EMERG "Unknown L2 line size\n");
 			while(1);
 	}
-    
+
 	_update_mmu_cache = andes_update_mmu_cache;
 
         flush_cache_l1();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/mm/c-mips64.c linux-2.4.20/arch/mips64/mm/c-mips64.c
--- linux-2.4.19/arch/mips64/mm/c-mips64.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips64/mm/c-mips64.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,670 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * MIPS64 CPU variant specific Cache routines.
+ * These routine are not optimized in any way, they are done in a generic way
+ * so they can be used on all MIPS64 compliant CPUs, and also done in an
+ * attempt not to break anything for the R4xx0 style CPUs.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
+#include <asm/bcache.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/mmu_context.h>
+
+/* CP0 hazard avoidance. */
+#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
+				     "nop; nop; nop; nop; nop; nop;\n\t" \
+				     ".set reorder\n\t")
+
+/* Primary cache parameters. */
+int icache_size, dcache_size; /* Size in bytes */
+int ic_lsize, dc_lsize;       /* LineSize in bytes */
+
+/* Secondary cache (if present) parameters. */
+unsigned int scache_size, sc_lsize;	/* Again, in bytes */
+
+#include <asm/cacheops.h>
+#include <asm/mips64_cache.h>
+
+#undef DEBUG_CACHE
+
+/*
+ * Dummy cache handling routines for machines without boardcaches
+ */
+static void no_sc_noop(void) {}
+
+static struct bcache_ops no_sc_ops = {
+	(void *)no_sc_noop, (void *)no_sc_noop,
+	(void *)no_sc_noop, (void *)no_sc_noop
+};
+
+struct bcache_ops *bcops = &no_sc_ops;
+
+
+static inline void mips64_flush_cache_all_sc(void)
+{
+	unsigned long flags;
+
+	__save_and_cli(flags);
+	blast_dcache(); blast_icache(); blast_scache();
+	__restore_flags(flags);
+}
+
+static inline void mips64_flush_cache_all_pc(void)
+{
+	unsigned long flags;
+
+	__save_and_cli(flags);
+	blast_dcache(); blast_icache();
+	__restore_flags(flags);
+}
+
+static void
+mips64_flush_cache_range_sc(struct mm_struct *mm,
+			 unsigned long start,
+			 unsigned long end)
+{
+	struct vm_area_struct *vma;
+	unsigned long flags;
+
+	if(mm->context == 0)
+		return;
+
+	start &= PAGE_MASK;
+#ifdef DEBUG_CACHE
+	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
+#endif
+	vma = find_vma(mm, start);
+	if(vma) {
+		if(mm->context != current->mm->context) {
+			mips64_flush_cache_all_sc();
+		} else {
+			pgd_t *pgd;
+			pmd_t *pmd;
+			pte_t *pte;
+
+			__save_and_cli(flags);
+			while(start < end) {
+				pgd = pgd_offset(mm, start);
+				pmd = pmd_offset(pgd, start);
+				pte = pte_offset(pmd, start);
+
+				if(pte_val(*pte) & _PAGE_VALID)
+					blast_scache_page(start);
+				start += PAGE_SIZE;
+			}
+			__restore_flags(flags);
+		}
+	}
+}
+
+static void mips64_flush_cache_range_pc(struct mm_struct *mm,
+				     unsigned long start,
+				     unsigned long end)
+{
+	if(mm->context != 0) {
+		unsigned long flags;
+
+#ifdef DEBUG_CACHE
+		printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
+#endif
+		__save_and_cli(flags);
+		blast_dcache(); blast_icache();
+		__restore_flags(flags);
+	}
+}
+
+/*
+ * On architectures like the Sparc, we could get rid of lines in
+ * the cache created only by a certain context, but on the MIPS
+ * (and actually certain Sparc's) we cannot.
+ */
+static void mips64_flush_cache_mm_sc(struct mm_struct *mm)
+{
+	if(mm->context != 0) {
+#ifdef DEBUG_CACHE
+		printk("cmm[%d]", (int)mm->context);
+#endif
+		mips64_flush_cache_all_sc();
+	}
+}
+
+static void mips64_flush_cache_mm_pc(struct mm_struct *mm)
+{
+	if(mm->context != 0) {
+#ifdef DEBUG_CACHE
+		printk("cmm[%d]", (int)mm->context);
+#endif
+		mips64_flush_cache_all_pc();
+	}
+}
+
+static void mips64_flush_cache_page_sc(struct vm_area_struct *vma,
+				    unsigned long page)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	unsigned long flags;
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+
+	/*
+	 * If ownes no valid ASID yet, cannot possibly have gotten
+	 * this page into the cache.
+	 */
+	if (mm->context == 0)
+		return;
+
+#ifdef DEBUG_CACHE
+	printk("cpage[%d,%08lx]", (int)mm->context, page);
+#endif
+	__save_and_cli(flags);
+	page &= PAGE_MASK;
+	pgdp = pgd_offset(mm, page);
+	pmdp = pmd_offset(pgdp, page);
+	ptep = pte_offset(pmdp, page);
+
+	/*
+	 * If the page isn't marked valid, the page cannot possibly be
+	 * in the cache.
+	 */
+	if (!(pte_val(*ptep) & _PAGE_VALID))
+		goto out;
+
+	/*
+	 * Doing flushes for another ASID than the current one is
+	 * too difficult since R4k caches do a TLB translation
+	 * for every cache flush operation.  So we do indexed flushes
+	 * in that case, which doesn't overly flush the cache too much.
+	 */
+	if (mm->context != current->active_mm->context) {
+		/*
+		 * Do indexed flush, too much work to get the (possible)
+		 * tlb refills to work correctly.
+		 */
+		page = (KSEG0 + (page & (scache_size - 1)));
+		blast_dcache_page_indexed(page);
+		blast_scache_page_indexed(page);
+	} else
+		blast_scache_page(page);
+out:
+	__restore_flags(flags);
+}
+
+static void mips64_flush_cache_page_pc(struct vm_area_struct *vma,
+				    unsigned long page)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	unsigned long flags;
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+
+	/*
+	 * If ownes no valid ASID yet, cannot possibly have gotten
+	 * this page into the cache.
+	 */
+	if (mm->context == 0)
+		return;
+
+#ifdef DEBUG_CACHE
+	printk("cpage[%d,%08lx]", (int)mm->context, page);
+#endif
+	__save_and_cli(flags);
+	page &= PAGE_MASK;
+	pgdp = pgd_offset(mm, page);
+	pmdp = pmd_offset(pgdp, page);
+	ptep = pte_offset(pmdp, page);
+
+	/*
+	 * If the page isn't marked valid, the page cannot possibly be
+	 * in the cache.
+	 */
+	if (!(pte_val(*ptep) & _PAGE_VALID))
+		goto out;
+
+	/*
+	 * Doing flushes for another ASID than the current one is
+	 * too difficult since Mips64 caches do a TLB translation
+	 * for every cache flush operation.  So we do indexed flushes
+	 * in that case, which doesn't overly flush the cache too much.
+	 */
+	if (mm == current->active_mm) {
+		blast_dcache_page(page);
+	} else {
+		/* Do indexed flush, too much work to get the (possible)
+		 * tlb refills to work correctly.
+		 */
+		page = (KSEG0 + (page & ((unsigned long)dcache_size - 1)));
+		blast_dcache_page_indexed(page);
+	}
+out:
+	__restore_flags(flags);
+}
+
+/* If the addresses passed to these routines are valid, they are
+ * either:
+ *
+ * 1) In KSEG0, so we can do a direct flush of the page.
+ * 2) In KSEG2, and since every process can translate those
+ *    addresses all the time in kernel mode we can do a direct
+ *    flush.
+ * 3) In KSEG1, no flush necessary.
+ */
+static void mips64_flush_page_to_ram_sc(struct page *page)
+{
+	blast_scache_page((unsigned long)page_address(page));
+}
+
+static void mips64_flush_page_to_ram_pc(struct page *page)
+{
+	blast_dcache_page((unsigned long)page_address(page));
+}
+
+static void
+mips64_flush_icache_page_s(struct vm_area_struct *vma, struct page *page)
+{
+	/*
+	 * We did an scache flush therefore PI is already clean.
+	 */
+}
+
+static void
+mips64_flush_icache_range(unsigned long start, unsigned long end)
+{
+	flush_cache_all();
+}
+
+static void
+mips64_flush_icache_page(struct vm_area_struct *vma, struct page *page)
+{
+	unsigned long address;
+
+	if (!(vma->vm_flags & VM_EXEC))
+		return;
+
+	address = KSEG0 + ((unsigned long)page_address(page) & PAGE_MASK & ((unsigned long)icache_size - 1));
+	blast_icache_page_indexed(address);
+}
+
+/*
+ * Writeback and invalidate the primary cache dcache before DMA.
+ */
+static void
+mips64_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size)
+{
+	unsigned long end, a;
+	unsigned int flags;
+
+	if (size >= (unsigned long)dcache_size) {
+		blast_dcache();
+	} else {
+	        __save_and_cli(flags);
+		a = addr & ~(dc_lsize - 1);
+		end = (addr + size) & ~((unsigned long)dc_lsize - 1);
+		while (1) {
+			flush_dcache_line(a); /* Hit_Writeback_Inv_D */
+			if (a == end) break;
+			a += dc_lsize;
+		}
+		__restore_flags(flags);
+	}
+	bc_wback_inv(addr, size);
+}
+
+static void
+mips64_dma_cache_wback_inv_sc(unsigned long addr, unsigned long size)
+{
+	unsigned long end, a;
+
+	if (size >= scache_size) {
+		blast_scache();
+		return;
+	}
+
+	a = addr & ~(sc_lsize - 1);
+	end = (addr + size) & ~(sc_lsize - 1);
+	while (1) {
+		flush_scache_line(a);	/* Hit_Writeback_Inv_SD */
+		if (a == end) break;
+		a += sc_lsize;
+	}
+}
+
+static void
+mips64_dma_cache_inv_pc(unsigned long addr, unsigned long size)
+{
+	unsigned long end, a;
+	unsigned int flags;
+
+	if (size >= (unsigned long)dcache_size) {
+		blast_dcache();
+	} else {
+	        __save_and_cli(flags);
+		a = addr & ~((unsigned long)dc_lsize - 1);
+		end = (addr + size) & ~((unsigned long)dc_lsize - 1);
+		while (1) {
+			invalidate_dcache_line(a); /* Hit_Inv_D */
+			if (a == end) break;
+			a += (unsigned long)dc_lsize;
+		}
+		__restore_flags(flags);
+	}
+
+	bc_inv(addr, size);
+}
+
+static void
+mips64_dma_cache_inv_sc(unsigned long addr, unsigned long size)
+{
+	unsigned long end, a;
+
+	if (size >= scache_size) {
+		blast_scache();
+		return;
+	}
+
+	a = addr & ~(sc_lsize - 1);
+	end = (addr + size) & ~(sc_lsize - 1);
+	while (1) {
+		invalidate_scache_line(a); /* Hit_Writeback_Inv_SD */
+		if (a == end) break;
+		a += sc_lsize;
+	}
+}
+
+static void
+mips64_dma_cache_wback(unsigned long addr, unsigned long size)
+{
+	panic("mips64_dma_cache called - should not happen.\n");
+}
+
+/*
+ * While we're protected against bad userland addresses we don't care
+ * very much about what happens in that case.  Usually a segmentation
+ * fault will dump the process later on anyway ...
+ */
+static void mips64_flush_cache_sigtramp(unsigned long addr)
+{
+	protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
+	protected_flush_icache_line(addr & ~(ic_lsize - 1));
+}
+
+static void
+mips64_flush_icache_all(void)
+{
+	if (mips_cpu.cputype == CPU_20KC) {
+		blast_icache();
+	}
+}
+
+
+/* Detect and size the various caches. */
+static void __init probe_icache(unsigned long config)
+{
+        unsigned long config1;
+	unsigned int lsize;
+
+        if (!(config & (1 << 31))) {
+	        /*
+		 * Not a MIPS64 complainant CPU.
+		 * Config 1 register not supported, we assume R4k style.
+		 */
+	        icache_size = 1 << (12 + ((config >> 9) & 7));
+		ic_lsize = 16 << ((config >> 5) & 1);
+		mips_cpu.icache.linesz = ic_lsize;
+
+		/*
+		 * We cannot infer associativity - assume direct map
+		 * unless probe template indicates otherwise
+		 */
+		if(!mips_cpu.icache.ways) mips_cpu.icache.ways = 1;
+		mips_cpu.icache.sets =
+			(icache_size / ic_lsize) / mips_cpu.icache.ways;
+	} else {
+	       config1 = read_mips32_cp0_config1();
+
+	       if ((lsize = ((config1 >> 19) & 7)))
+		       mips_cpu.icache.linesz = 2 << lsize;
+	       else
+		       mips_cpu.icache.linesz = lsize;
+	       mips_cpu.icache.sets = 64 << ((config1 >> 22) & 7);
+	       mips_cpu.icache.ways = 1 + ((config1 >> 16) & 7);
+
+	       ic_lsize = mips_cpu.icache.linesz;
+	       icache_size = mips_cpu.icache.sets * mips_cpu.icache.ways *
+		             ic_lsize;
+	}
+	printk("Primary instruction cache %dkb, linesize %d bytes (%d ways)\n",
+	       icache_size >> 10, ic_lsize, mips_cpu.icache.ways);
+}
+
+static void __init probe_dcache(unsigned long config)
+{
+        unsigned long config1;
+	unsigned int lsize;
+
+        if (!(config & (1 << 31))) {
+	        /*
+		 * Not a MIPS64 complainant CPU.
+		 * Config 1 register not supported, we assume R4k style.
+		 */
+		dcache_size = 1 << (12 + ((config >> 6) & 7));
+		dc_lsize = 16 << ((config >> 4) & 1);
+		mips_cpu.dcache.linesz = dc_lsize;
+		/*
+		 * We cannot infer associativity - assume direct map
+		 * unless probe template indicates otherwise
+		 */
+		if(!mips_cpu.dcache.ways) mips_cpu.dcache.ways = 1;
+		mips_cpu.dcache.sets =
+			(dcache_size / dc_lsize) / mips_cpu.dcache.ways;
+	} else {
+	        config1 = read_mips32_cp0_config1();
+
+		if ((lsize = ((config1 >> 10) & 7)))
+		        mips_cpu.dcache.linesz = 2 << lsize;
+		else
+		        mips_cpu.dcache.linesz= lsize;
+		mips_cpu.dcache.sets = 64 << ((config1 >> 13) & 7);
+		mips_cpu.dcache.ways = 1 + ((config1 >> 7) & 7);
+
+		dc_lsize = mips_cpu.dcache.linesz;
+		dcache_size =
+			mips_cpu.dcache.sets * mips_cpu.dcache.ways
+			* dc_lsize;
+	}
+	printk("Primary data cache %dkb, linesize %d bytes (%d ways)\n",
+	       dcache_size >> 10, dc_lsize, mips_cpu.dcache.ways);
+}
+
+
+/* If you even _breathe_ on this function, look at the gcc output
+ * and make sure it does not pop things on and off the stack for
+ * the cache sizing loop that executes in KSEG1 space or else
+ * you will crash and burn badly.  You have been warned.
+ */
+static int __init probe_scache(unsigned long config)
+{
+	extern unsigned long stext;
+	unsigned long flags, addr, begin, end, pow2;
+	int tmp;
+
+	if (mips_cpu.scache.flags == MIPS_CACHE_NOT_PRESENT)
+		return 0;
+
+	tmp = ((config >> 17) & 1);
+	if(tmp)
+		return 0;
+	tmp = ((config >> 22) & 3);
+	switch(tmp) {
+	case 0:
+		sc_lsize = 16;
+		break;
+	case 1:
+		sc_lsize = 32;
+		break;
+	case 2:
+		sc_lsize = 64;
+		break;
+	case 3:
+		sc_lsize = 128;
+		break;
+	}
+
+	begin = (unsigned long) &stext;
+	begin &= ~((4 * 1024 * 1024) - 1);
+	end = begin + (4 * 1024 * 1024);
+
+	/* This is such a bitch, you'd think they would make it
+	 * easy to do this.  Away you daemons of stupidity!
+	 */
+	__save_and_cli(flags);
+
+	/* Fill each size-multiple cache line with a valid tag. */
+	pow2 = (64 * 1024);
+	for(addr = begin; addr < end; addr = (begin + pow2)) {
+		unsigned long *p = (unsigned long *) addr;
+		__asm__ __volatile__("nop" : : "r" (*p)); /* whee... */
+		pow2 <<= 1;
+	}
+
+	/* Load first line with zero (therefore invalid) tag. */
+	set_taglo(0);
+	set_taghi(0);
+	__asm__ __volatile__("nop; nop; nop; nop;"); /* avoid the hazard */
+	__asm__ __volatile__("\n\t.set noreorder\n\t"
+			     "cache 8, (%0)\n\t"
+			     ".set reorder\n\t" : : "r" (begin));
+	__asm__ __volatile__("\n\t.set noreorder\n\t"
+			     "cache 9, (%0)\n\t"
+			     ".set reorder\n\t" : : "r" (begin));
+	__asm__ __volatile__("\n\t.set noreorder\n\t"
+			     "cache 11, (%0)\n\t"
+			     ".set reorder\n\t" : : "r" (begin));
+
+	/* Now search for the wrap around point. */
+	pow2 = (128 * 1024);
+	tmp = 0;
+	for(addr = (begin + (128 * 1024)); addr < (end); addr = (begin + pow2)) {
+		__asm__ __volatile__("\n\t.set noreorder\n\t"
+				     "cache 7, (%0)\n\t"
+				     ".set reorder\n\t" : : "r" (addr));
+		__asm__ __volatile__("nop; nop; nop; nop;"); /* hazard... */
+		if(!get_taglo())
+			break;
+		pow2 <<= 1;
+	}
+	__restore_flags(flags);
+	addr -= begin;
+	printk("Secondary cache sized at %dK linesize %d bytes.\n",
+	       (int) (addr >> 10), sc_lsize);
+	scache_size = addr;
+	return 1;
+}
+
+static void __init setup_noscache_funcs(void)
+{
+	_clear_page = (void *)mips64_clear_page_dc;
+	_copy_page = (void *)mips64_copy_page_dc;
+	_flush_cache_all = mips64_flush_cache_all_pc;
+	___flush_cache_all = mips64_flush_cache_all_pc;
+	_flush_cache_mm = mips64_flush_cache_mm_pc;
+	_flush_cache_range = mips64_flush_cache_range_pc;
+	_flush_cache_page = mips64_flush_cache_page_pc;
+	_flush_page_to_ram = mips64_flush_page_to_ram_pc;
+
+	_flush_icache_page = mips64_flush_icache_page;
+
+	_dma_cache_wback_inv = mips64_dma_cache_wback_inv_pc;
+	_dma_cache_wback = mips64_dma_cache_wback;
+	_dma_cache_inv = mips64_dma_cache_inv_pc;
+}
+
+static void __init setup_scache_funcs(void)
+{
+        _flush_cache_all = mips64_flush_cache_all_sc;
+        ___flush_cache_all = mips64_flush_cache_all_sc;
+	_flush_cache_mm = mips64_flush_cache_mm_sc;
+	_flush_cache_range = mips64_flush_cache_range_sc;
+	_flush_cache_page = mips64_flush_cache_page_sc;
+	_flush_page_to_ram = mips64_flush_page_to_ram_sc;
+	_clear_page = (void *)mips64_clear_page_sc;
+	_copy_page = (void *)mips64_copy_page_sc;
+
+	_flush_icache_page = mips64_flush_icache_page_s;
+
+	_dma_cache_wback_inv = mips64_dma_cache_wback_inv_sc;
+	_dma_cache_wback = mips64_dma_cache_wback;
+	_dma_cache_inv = mips64_dma_cache_inv_sc;
+}
+
+typedef int (*probe_func_t)(unsigned long);
+
+static inline void __init setup_scache(unsigned int config)
+{
+	probe_func_t probe_scache_kseg1;
+	int sc_present = 0;
+
+	/* Maybe the cpu knows about a l2 cache? */
+	probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache));
+	sc_present = probe_scache_kseg1(config);
+
+	if (sc_present) {
+	  	mips_cpu.scache.linesz = sc_lsize;
+		/*
+		 * We cannot infer associativity - assume direct map
+		 * unless probe template indicates otherwise
+		 */
+		if(!mips_cpu.scache.ways) mips_cpu.scache.ways = 1;
+		mips_cpu.scache.sets =
+		  (scache_size / sc_lsize) / mips_cpu.scache.ways;
+
+		setup_scache_funcs();
+		return;
+	}
+
+	setup_noscache_funcs();
+}
+
+void __init ld_mmu_mips64(void)
+{
+	unsigned long config = read_32bit_cp0_register(CP0_CONFIG);
+
+	change_cp0_config(CONF_CM_CMASK, CONF_CM_DEFAULT);
+
+	probe_icache(config);
+	probe_dcache(config);
+	setup_scache(config);
+
+	_flush_cache_sigtramp = mips64_flush_cache_sigtramp;
+	_flush_icache_range = mips64_flush_icache_range;	/* Ouch */
+	_flush_icache_all = mips64_flush_icache_all;
+	_flush_cache_l1 = _flush_cache_all;
+	_flush_cache_l2 = _flush_cache_all;
+
+	__flush_cache_all();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/mm/c-sb1.c linux-2.4.20/arch/mips64/mm/c-sb1.c
--- linux-2.4.19/arch/mips64/mm/c-sb1.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/mm/c-sb1.c	2002-10-29 11:18:35.000000000 +0000
@@ -12,11 +12,11 @@
  * 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.
- */ 
+ */
 #include <linux/config.h>
 #include <linux/init.h>
 #include <asm/mmu_context.h>
@@ -46,7 +46,7 @@
  * if we miss in the icache, and have dirty data in the
  * L1 dcache, then we'll go out to memory (or the L2) and
  * get the not-as-recent data.
- * 
+ *
  * So the only time we have to flush the dcache is when
  * we're flushing the icache.  Since the L2 is fully
  * coherent to everything, including I/O, we never have
@@ -63,7 +63,7 @@
 	 * Haven't worried too much about speed here; given that we're flushing
 	 * the icache, the time to invalidate is dwarfed by the time it's going
 	 * to take to refill it.  Register usage:
-	 * 
+	 *
 	 * $1 - moving cache index
 	 * $2 - set count
 	 */
@@ -87,7 +87,7 @@
 		".set noreorder             \n"
 		".set mips2                 \n"
 		"sync                       \n"
-#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS		/* Bug 1384 */			
+#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS		/* Bug 1384 */
 		"sync                       \n"
 #endif
 		".set pop                   \n");
@@ -153,7 +153,7 @@
 		".set noreorder             \n"
 		".set noat                  \n"
 		".set mips4                 \n"
-		"     move   $1, %0         \n" 
+		"     move   $1, %0         \n"
 		"1:                         \n"
 #ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
 		".align 3                   \n"
@@ -192,7 +192,7 @@
 		".set noreorder             \n"
 		".set noat                  \n"
 		".set mips4                 \n"
-		"     move   $1, %0         \n" 
+		"     move   $1, %0         \n"
 		".align 3                   \n"
 		"1:   cache  %3, (0<<13)($1) \n" /* Index-inval this address */
 		"     cache  %3, (1<<13)($1) \n" /* Index-inval this address */
@@ -277,9 +277,9 @@
 static inline void protected_writeback_dcache_line(unsigned long addr)
 {
 #ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
-	/* Have to be sure the TLB entry exists for the cache op, 
+	/* Have to be sure the TLB entry exists for the cache op,
 	   so we have to be sure that nothing happens in between the
-	   lw and the cache op 
+	   lw and the cache op
 	*/
 	unsigned long flags;
 	local_irq_save(flags);
@@ -370,7 +370,7 @@
 	 * Haven't worried too much about speed here; given that we're flushing
 	 * the icache, the time to invalidate is dwarfed by the time it's going
 	 * to take to refill it.  Register usage:
-	 * 
+	 *
 	 * $1 - moving cache index
 	 * $2 - set count
 	 */
@@ -402,23 +402,23 @@
 
 /*
  * This only needs to make sure stores done up to this
- * point are visible to other agents outside the CPU.  Given 
- * the coherent nature of the ZBbus, all that's required here is 
+ * point are visible to other agents outside the CPU.  Given
+ * the coherent nature of the ZBbus, all that's required here is
  * a sync to make sure the data gets out to the caches and is
- * visible to an arbitrary A Phase from an external agent 
- *   
+ * visible to an arbitrary A Phase from an external agent
+ *
  * Actually, I'm not even sure that's necessary; the semantics
  * of this function aren't clear.  If it's supposed to serve as
- * a memory barrier, this is needed.  If it's only meant to 
+ * a memory barrier, this is needed.  If it's only meant to
  * prevent data from being invisible to non-cpu memory accessors
- * for some indefinite period of time (e.g. in a non-coherent 
+ * for some indefinite period of time (e.g. in a non-coherent
  * dcache) then this function would be a complete nop.
  */
 static void sb1_flush_page_to_ram(struct page *page)
 {
 	__asm__ __volatile__(
 		"     sync  \n"  /* Short pipe */
-		:::"memory");	
+		:::"memory");
 }
 
 /*
@@ -432,13 +432,13 @@
  * 6 - 4096
  * 7 - Reserved
  */
-  
+
 static unsigned int decode_cache_sets(unsigned int config_field)
 {
 	if (config_field == 7) {
 		/* JDCXXX - Find a graceful way to abort. */
 		return 0;
-	} 
+	}
 	return (1<<(config_field + 6));
 }
 
@@ -461,7 +461,7 @@
 	} else if (config_field == 7) {
 		/* JDCXXX - Find a graceful way to abort. */
 		return 0;
-	} 
+	}
 	return (1<<(config_field + 1));
 }
 
@@ -518,6 +518,6 @@
 	_flush_cache_sigtramp = sb1_flush_cache_sigtramp;
 	_flush_icache_all = sb1_flush_icache_all;
 
-	change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_COW);
+	change_cp0_config(CONF_CM_CMASK, CONF_CM_DEFAULT);
 	flush_cache_all();
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/mm/extable.c linux-2.4.20/arch/mips64/mm/extable.c
--- linux-2.4.19/arch/mips64/mm/extable.c	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/arch/mips64/mm/extable.c	2002-10-29 11:18:33.000000000 +0000
@@ -40,13 +40,13 @@
 unsigned long search_exception_table(unsigned long addr)
 {
 	unsigned long ret = 0;
-	unsigned long flags;
-	
+
 #ifndef CONFIG_MODULES
 	/* There is only the kernel to search.  */
 	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
 	return ret;
 #else
+	unsigned long flags;
 	/* The kernel is the last "module" -- no need to treat it special.  */
 	struct module *mp;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/mm/fault.c linux-2.4.20/arch/mips64/mm/fault.c
--- linux-2.4.19/arch/mips64/mm/fault.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/mm/fault.c	2002-10-29 11:18:31.000000000 +0000
@@ -126,7 +126,7 @@
 	 * If we're in an interrupt or have no user
 	 * context, we must not take the fault..
 	 */
-	if (in_interrupt() || mm == &init_mm)
+	if (in_interrupt() || !mm)
 		goto no_context;
 
 	down_read(&mm->mmap_sem);
@@ -229,20 +229,18 @@
 	printk(KERN_ALERT "Cpu %d Unable to handle kernel paging request at "
 	       "address %016lx, epc == %016lx, ra == %016lx\n",
 	       smp_processor_id(), address, regs->cp0_epc, regs->regs[31]);
-	die("Oops", regs, write);
+	die("Oops", regs);
 
 /*
  * We ran out of memory, or some other thing happened to us that made
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
-		tsk->policy |= SCHED_YIELD;
-		schedule();
-		down_read(&mm->mmap_sem);
+		yield();
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk(KERN_NOTICE "VM: killing process %s\n", tsk->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/mm/init.c linux-2.4.20/arch/mips64/mm/init.c
--- linux-2.4.19/arch/mips64/mm/init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/mm/init.c	2002-10-29 11:18:33.000000000 +0000
@@ -226,10 +226,10 @@
 
 	free_area_init(zones_size);
 
-	memset((void *)kptbl, 0, PAGE_SIZE << KPTBL_PAGE_ORDER);
+	memset((void *)kptbl, 0, PAGE_SIZE << PGD_ORDER);
 	memset((void *)kpmdtbl, 0, PAGE_SIZE);
 	pgd_set(swapper_pg_dir, kpmdtbl);
-	for (i = 0; i < (1 << KPTBL_PAGE_ORDER); pmd++,i++,pte+=PTRS_PER_PTE)
+	for (i = 0; i < (1 << PGD_ORDER); pmd++,i++,pte+=PTRS_PER_PTE)
 		pmd_val(*pmd) = (unsigned long)pte;
 }
 
@@ -243,17 +243,18 @@
 	int i;
 
 	for (i = 0; i < boot_mem_map.nr_map; i++) {
-	unsigned long addr, end;
+		unsigned long addr, end;
 
-	if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
-		/* not usable memory */
-		continue;
+		if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
+			/* not usable memory */
+			continue;
+
+		addr = PFN_UP(boot_mem_map.map[i].addr);
+		end = PFN_DOWN(boot_mem_map.map[i].addr +
+			       boot_mem_map.map[i].size);
 
-	addr = PFN_UP(boot_mem_map.map[i].addr);
-	end = PFN_DOWN(boot_mem_map.map[i].addr + boot_mem_map.map[i].size);
-
-	if (pagenr >= addr && pagenr < end)
-		return 1;
+		if (pagenr >= addr && pagenr < end)
+			return 1;
 	}
 
 	return 0;
@@ -316,7 +317,7 @@
 	unsigned long addr, page;
 
 	prom_free_prom_memory();
-    
+
 	addr = (unsigned long)(&__init_begin);
 	while (addr < (unsigned long)&__init_end) {
 		page = PAGE_OFFSET | CPHYSADDR(addr);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/mm/loadmmu.c linux-2.4.20/arch/mips64/mm/loadmmu.c
--- linux-2.4.19/arch/mips64/mm/loadmmu.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/mm/loadmmu.c	2002-10-29 11:18:31.000000000 +0000
@@ -54,35 +54,29 @@
 extern void ld_mmu_andes(void);
 extern void ld_mmu_sb1(void);
 extern void sb1_tlb_init(void);
+extern void ld_mmu_mips64(void);
+extern void r4k_tlb_init(void);
 
 void __init load_mmu(void)
 {
-	switch(mips_cpu.cputype) {
+	if (mips_cpu.options & MIPS_CPU_4KTLB) {
 #if defined (CONFIG_CPU_R4300)						\
     || defined (CONFIG_CPU_R4X00)					\
     || defined (CONFIG_CPU_R5000)					\
     || defined (CONFIG_CPU_NEVADA)
-	case CPU_R4000PC:
-	case CPU_R4000SC:
-	case CPU_R4000MC:
-	case CPU_R4200:
-	case CPU_R4300:
-	case CPU_R4400PC:
-	case CPU_R4400SC:
-	case CPU_R4400MC:
-	case CPU_R4600:
-	case CPU_R4640:
-	case CPU_R4650:
-	case CPU_R4700:
-	case CPU_R5000:
-	case CPU_R5000A:
-	case CPU_NEVADA:
 		printk(KERN_INFO "Loading R4000 MMU routines.\n");
 		ld_mmu_r4xx0();
-		break;
 #endif
+#if defined(CONFIG_CPU_MIPS64)
+		printk(KERN_INFO "Loading MIPS64 MMU routines.\n");
+                ld_mmu_mips64();
+		r4k_tlb_init();
+#endif
+
+	} else switch(mips_cpu.cputype) {
 #ifdef CONFIG_CPU_R10000
 	case CPU_R10000:
+	case CPU_R12000:
 		printk(KERN_INFO "Loading R10000 MMU routines.\n");
 		ld_mmu_andes();
 		break;
@@ -95,6 +89,10 @@
 		break;
 #endif
 
+	case CPU_R8000:
+		panic("R8000 is unsupported");
+		break;
+
 	default:
 		/* XXX We need an generic routine in the MIPS port
 		 * XXX to jabber stuff onto the screen on all machines
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/mm/pg-mips64.c linux-2.4.20/arch/mips64/mm/pg-mips64.c
--- linux-2.4.19/arch/mips64/mm/pg-mips64.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips64/mm/pg-mips64.c	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,126 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * MIPS64 CPU variant specific Cache routines.
+ * These routine are not optimized in any way, they are done in a generic way
+ * so they can be used on all MIPS64 compliant CPUs, and also done in an
+ * attempt not to break anything for the R4xx0 style CPUs.
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/bootinfo.h>
+#include <asm/cacheops.h>
+#include <asm/cpu.h>
+
+extern int dc_lsize, ic_lsize, sc_lsize;
+
+/*
+ * Zero an entire page.
+ */
+
+void mips64_clear_page_dc(unsigned long page)
+{
+	unsigned long i;
+
+        if (mips_cpu.options & MIPS_CPU_CACHE_CDEX)
+	{
+	        for (i=page; i<page+PAGE_SIZE; i+=dc_lsize)
+		{
+		        __asm__ __volatile__(
+			        ".set\tnoreorder\n\t"
+				".set\tnoat\n\t"
+				"cache\t%2,(%0)\n\t"
+				".set\tat\n\t"
+				".set\treorder"
+				:"=r" (i)
+				:"0" (i),
+				"I" (Create_Dirty_Excl_D));
+		}
+	}
+	for (i=page; i<page+PAGE_SIZE; i+=sizeof(long))
+	        *(unsigned long *)(i) = 0;
+}
+
+void mips64_clear_page_sc(unsigned long page)
+{
+	unsigned long i;
+
+        if (mips_cpu.options & MIPS_CPU_CACHE_CDEX)
+	{
+	        for (i=page; i<page+PAGE_SIZE; i+=sc_lsize)
+		{
+		        __asm__ __volatile__(
+				".set\tnoreorder\n\t"
+				".set\tnoat\n\t"
+				"cache\t%2,(%0)\n\t"
+				".set\tat\n\t"
+				".set\treorder"
+				:"=r" (i)
+				:"0" (i),
+				"I" (Create_Dirty_Excl_SD));
+		}
+	}
+	for (i=page; i<page+PAGE_SIZE; i+=sizeof(long))
+	        *(unsigned long *)(i) = 0;
+}
+
+void mips64_copy_page_dc(unsigned long to, unsigned long from)
+{
+	unsigned long i;
+
+        if (mips_cpu.options & MIPS_CPU_CACHE_CDEX)
+	{
+	        for (i=to; i<to+PAGE_SIZE; i+=dc_lsize)
+		{
+		        __asm__ __volatile__(
+			        ".set\tnoreorder\n\t"
+				".set\tnoat\n\t"
+				"cache\t%2,(%0)\n\t"
+				".set\tat\n\t"
+				".set\treorder"
+				:"=r" (i)
+				:"0" (i),
+				"I" (Create_Dirty_Excl_D));
+		}
+	}
+	for (i=0; i<PAGE_SIZE; i+=sizeof(long))
+	        *(unsigned long *)(to+i) = *(unsigned long *)(from+i);
+}
+
+void mips64_copy_page_sc(unsigned long to, unsigned long from)
+{
+	unsigned long i;
+
+        if (mips_cpu.options & MIPS_CPU_CACHE_CDEX)
+	{
+	        for (i=to; i<to+PAGE_SIZE; i+=sc_lsize)
+		{
+		        __asm__ __volatile__(
+				".set\tnoreorder\n\t"
+				".set\tnoat\n\t"
+				"cache\t%2,(%0)\n\t"
+				".set\tat\n\t"
+				".set\treorder"
+				:"=r" (i)
+				:"0" (i),
+				"I" (Create_Dirty_Excl_SD));
+		}
+	}
+	for (i=0; i<PAGE_SIZE; i+=sizeof(long))
+	        *(unsigned long *)(to+i) = *(unsigned long *)(from+i);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/mm/pg-sb1.c linux-2.4.20/arch/mips64/mm/pg-sb1.c
--- linux-2.4.19/arch/mips64/mm/pg-sb1.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/mm/pg-sb1.c	2002-10-29 11:18:32.000000000 +0000
@@ -2,7 +2,7 @@
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org)
  * Copyright (C) 2000 Sibyte
- * 
+ *
  * Written by Justin Carlson (carlson@sibyte.com)
  *
  *
@@ -15,11 +15,11 @@
  * 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.
- */ 
+ */
 #include <linux/config.h>
 #include <asm/page.h>
 
@@ -40,7 +40,7 @@
 	 * performance model
 	 *
 	 * We prefetch 4 lines ahead.  We're also "cheating" slightly here...
-	 * since we know we're on an SB1, we force the assembler to take 
+	 * since we know we're on an SB1, we force the assembler to take
 	 * 64-bit operands to speed things up
 	 */
 	__asm__ __volatile__(
@@ -50,9 +50,9 @@
 		".set mips4                 \n"
 		"     daddiu     $1, %0, %2  \n"  /* Calculate the end of the page to clear */
 		"     pref       " SB1_PREF_STORE_STREAMED_HINT ",  0(%0)  \n"  /* Prefetch the first 4 lines */
-		"     pref       " SB1_PREF_STORE_STREAMED_HINT ", 32(%0)  \n"  
-		"     pref       " SB1_PREF_STORE_STREAMED_HINT ", 64(%0)  \n"  
-		"     pref       " SB1_PREF_STORE_STREAMED_HINT ", 96(%0)  \n"  
+		"     pref       " SB1_PREF_STORE_STREAMED_HINT ", 32(%0)  \n"
+		"     pref       " SB1_PREF_STORE_STREAMED_HINT ", 64(%0)  \n"
+		"     pref       " SB1_PREF_STORE_STREAMED_HINT ", 96(%0)  \n"
 		"1:   sd        $0,  0(%0)  \n"  /* Throw out a cacheline of 0's */
 		"     sd        $0,  8(%0)  \n"
 		"     sd        $0, 16(%0)  \n"
@@ -72,7 +72,7 @@
 	/*
 	 * This should be optimized in assembly...can't use ld/sd, though,
 	 * because the top 32 bits could be nuked if we took an interrupt
-	 * during the routine.	And this is not a good place to be cli()'ing 
+	 * during the routine.	And this is not a good place to be cli()'ing
 	 *
 	 * The pref's used here are using "streaming" hints, which cause the
 	 * copied data to be kicked out of the cache sooner.  A page copy often
@@ -88,11 +88,11 @@
 		".set mips4                 \n"
 		"     daddiu     $1, %0, %4  \n"  /* Calculate the end of the page to copy */
 		"     pref       " SB1_PREF_LOAD_STREAMED_HINT  ",  0(%0)  \n"  /* Prefetch the first 3 lines */
-		"     pref       " SB1_PREF_STORE_STREAMED_HINT ",  0(%1)  \n"  
+		"     pref       " SB1_PREF_STORE_STREAMED_HINT ",  0(%1)  \n"
 		"     pref       " SB1_PREF_LOAD_STREAMED_HINT  ",  32(%0) \n"
-		"     pref       " SB1_PREF_STORE_STREAMED_HINT ",  32(%1) \n"  
+		"     pref       " SB1_PREF_STORE_STREAMED_HINT ",  32(%1) \n"
 		"     pref       " SB1_PREF_LOAD_STREAMED_HINT  ",  64(%0) \n"
-		"     pref       " SB1_PREF_STORE_STREAMED_HINT ",  64(%1) \n"  
+		"     pref       " SB1_PREF_STORE_STREAMED_HINT ",  64(%1) \n"
 		"1:   lw        $2,  0(%0)  \n"  /* Block copy a cacheline */
 		"     lw        $3,  4(%0)  \n"
 		"     lw        $4,  8(%0)  \n"
@@ -103,20 +103,20 @@
 		"     lw        $9, 28(%0)  \n"
 		"     pref       " SB1_PREF_LOAD_STREAMED_HINT  ", 96(%0)  \n"  /* Prefetch ahead         */
 		"     pref       " SB1_PREF_STORE_STREAMED_HINT ", 96(%1)  \n"
-		"     sw        $2,  0(%1)  \n"  
+		"     sw        $2,  0(%1)  \n"
 		"     sw        $3,  4(%1)  \n"
 		"     sw        $4,  8(%1)  \n"
 		"     sw        $5, 12(%1)  \n"
 		"     sw        $6, 16(%1)  \n"
 		"     sw        $7, 20(%1)  \n"
 		"     sw        $8, 24(%1)  \n"
-		"     sw        $9, 28(%1)  \n"		
+		"     sw        $9, 28(%1)  \n"
 		"     daddiu     %1, %1, 32  \n"  /* Next cacheline */
 		"     nop                   \n"  /* Force next add to short pipe */
 		"     nop                   \n"  /* Force next add to short pipe */
 		"     bne       $1, %0, 1b  \n"
 		"     daddiu     %0, %0, 32  \n"  /* Next cacheline */
-		".set pop                   \n" 
+		".set pop                   \n"
 		: "=r" (to), "=r" (from)
 		: "0" (from), "1" (to), "I" (PAGE_SIZE-32)
 		: "$2","$3","$4","$5","$6","$7","$8","$9","memory");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/mm/r4xx0.c linux-2.4.20/arch/mips64/mm/r4xx0.c
--- linux-2.4.19/arch/mips64/mm/r4xx0.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/mm/r4xx0.c	2002-10-29 11:18:31.000000000 +0000
@@ -136,10 +136,10 @@
  *      Hit_Invalidate_D and Create_Dirty_Excl_D should only be
  *      executed if there is no other dcache activity. If the dcache is
  *      accessed for another instruction immeidately preceding when these
- *      cache instructions are executing, it is possible that the dcache 
- *      tag match outputs used by these cache instructions will be 
+ *      cache instructions are executing, it is possible that the dcache
+ *      tag match outputs used by these cache instructions will be
  *      incorrect. These cache instructions should be preceded by at least
- *      four instructions that are not any kind of load or store 
+ *      four instructions that are not any kind of load or store
  *      instruction.
  *
  *      This is not allowed:    lw
@@ -1237,7 +1237,7 @@
 	 * for every cache flush operation.  So we do indexed flushes
 	 * in that case, which doesn't overly flush the cache too much.
 	 */
-	if (CPU_CONTEXT(smp_processor_id(), mm) != 
+	if (CPU_CONTEXT(smp_processor_id(), mm) !=
 	    CPU_CONTEXT(smp_processor_id(), current->mm)) {
 		/* Do indexed flush, too much work to get the (possible)
 		 * tlb refills to work correctly.
@@ -1285,7 +1285,7 @@
 	 * for every cache flush operation.  So we do indexed flushes
 	 * in that case, which doesn't overly flush the cache too much.
 	 */
-	if (CPU_CONTEXT(smp_processor_id(), mm) != 
+	if (CPU_CONTEXT(smp_processor_id(), mm) !=
 	    CPU_CONTEXT(smp_processor_id(), current->mm)) {
 		/*
 		 * Do indexed flush, too much work to get the (possible)
@@ -1335,7 +1335,7 @@
 	 * for every cache flush operation.  So we do indexed flushes
 	 * in that case, which doesn't overly flush the cache too much.
 	 */
-	if (CPU_CONTEXT(smp_processor_id(), mm) != 
+	if (CPU_CONTEXT(smp_processor_id(), mm) !=
 	    CPU_CONTEXT(smp_processor_id(), current->mm)) {
 		/*
 		 * Do indexed flush, too much work to get the (possible)
@@ -1385,7 +1385,7 @@
 	 * for every cache flush operation.  So we do indexed flushes
 	 * in that case, which doesn't overly flush the cache too much.
 	 */
-	if (CPU_CONTEXT(smp_processor_id(), mm) != 
+	if (CPU_CONTEXT(smp_processor_id(), mm) !=
 	    CPU_CONTEXT(smp_processor_id(), current->mm)) {
 		/*
 		 * Do indexed flush, too much work to get the (possible)
@@ -1434,7 +1434,7 @@
 	 * for every cache flush operation.  So we do indexed flushes
 	 * in that case, which doesn't overly flush the cache too much.
 	 */
-	if (CPU_CONTEXT(smp_processor_id(), mm) != 
+	if (CPU_CONTEXT(smp_processor_id(), mm) !=
 	    CPU_CONTEXT(smp_processor_id(), current->mm)) {
 		/* Do indexed flush, too much work to get the (possible)
 		 * tlb refills to work correctly.
@@ -1746,11 +1746,6 @@
 	}
 }
 
-static void r4k_dma_cache_wback(unsigned long addr, unsigned long size)
-{
-	panic("r4k_dma_cache called - should not happen.");
-}
-
 /*
  * While we're protected against bad userland addresses we don't care
  * very much about what happens in that case.  Usually a segmentation
@@ -1877,7 +1872,7 @@
 		} else {
 			get_new_mmu_context(mm, smp_processor_id());
 			if(mm == current->mm)
-				set_entryhi(CPU_CONTEXT(smp_processor_id(), 
+				set_entryhi(CPU_CONTEXT(smp_processor_id(),
 								mm) & 0xff);
 		}
 		__restore_flags(flags);
@@ -2152,7 +2147,7 @@
 	}
 	_flush_icache_page = r4k_flush_icache_page_p;
 	_dma_cache_wback_inv = r4k_dma_cache_wback_inv_pc;
-	_dma_cache_wback = r4k_dma_cache_wback;
+	_dma_cache_wback = r4k_dma_cache_wback_inv_pc;
 	_dma_cache_inv = r4k_dma_cache_inv_pc;
 }
 
@@ -2241,11 +2236,12 @@
 	}
 	_flush_icache_page = r4k_flush_icache_page_s;
 	_dma_cache_wback_inv = r4k_dma_cache_wback_inv_sc;
-	_dma_cache_wback = r4k_dma_cache_wback;
+	_dma_cache_wback = r4k_dma_cache_wback_inv_sc;
 	_dma_cache_inv = r4k_dma_cache_inv_sc;
 }
 
 typedef int (*probe_func_t)(unsigned long);
+extern int r5k_sc_init(void);
 
 static inline void __init setup_scache(unsigned int config)
 {
@@ -2256,23 +2252,30 @@
 	probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache));
 	sc_present = probe_scache_kseg1(config);
 
-	if (sc_present) {
-		setup_scache_funcs();
+	if (!sc_present) {
+		setup_noscache_funcs();
 		return;
 	}
 
-	setup_noscache_funcs();
+	switch(mips_cpu.cputype) {
+	case CPU_R5000:
+	case CPU_NEVADA:
+			setup_noscache_funcs();
+#if defined(CONFIG_CPU_R5000) || defined(CONFIG_CPU_NEVADA)
+			r5k_sc_init();
+#endif
+			break;
+	default:
+			setup_scache_funcs();
+	}
+
 }
 
 void __init ld_mmu_r4xx0(void)
 {
 	unsigned long config = read_32bit_cp0_register(CP0_CONFIG);
 
-#ifdef CONFIG_MIPS_UNCACHED
-	change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
-#else
-	change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT);
-#endif /* UNCACHED */
+	change_cp0_config(CONF_CM_CMASK | CONF_CU, CONF_CM_DEFAULT);
 
 	probe_icache(config);
 	probe_dcache(config);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/mm/r5k-sc.c linux-2.4.20/arch/mips64/mm/r5k-sc.c
--- linux-2.4.19/arch/mips64/mm/r5k-sc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips64/mm/r5k-sc.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org),
+ * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com).
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/mipsregs.h>
+#include <asm/bcache.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/mmu_context.h>
+#include <asm/r4kcacheops.h>
+
+/* Secondary cache size in bytes, if present.  */
+static unsigned long scache_size;
+
+#define SC_LINE 32
+#define SC_PAGE (128*SC_LINE)
+
+#define cache_op(base,op)                   \
+__asm__ __volatile__("				\
+		.set noreorder;                 \
+		.set mips3;                     \
+		cache %1, (%0);                 \
+		.set mips0;                     \
+		.set reorder"                   \
+		:                               \
+		: "r" (base),                   \
+		  "i" (op));
+
+static inline void blast_r5000_scache(void)
+{
+	unsigned long start = KSEG0;
+	unsigned long end = KSEG0 + scache_size;
+
+	while(start < end) {
+		cache_op(start, R5K_Page_Invalidate_S);
+		start += SC_PAGE;
+	}
+}
+
+static void r5k_dma_cache_inv_sc(unsigned long addr, unsigned long size)
+{
+	unsigned long end, a;
+
+	if (size >= scache_size) {
+		blast_r5000_scache();
+		return;
+	}
+
+	/* On the R5000 secondary cache we cannot
+	 * invalidate less than a page at a time.
+	 * The secondary cache is physically indexed, write-through.
+	 */
+	a = addr & ~(SC_PAGE - 1);
+	end = (addr + size - 1) & ~(SC_PAGE - 1);
+	while (a <= end) {
+		cache_op(a, R5K_Page_Invalidate_S);
+		a += SC_PAGE;
+	}
+}
+
+static void r5k_sc_enable(void)
+{
+        unsigned long flags;
+
+	__save_and_cli(flags);
+	change_cp0_config(CONF_SE, CONF_SE);
+	blast_r5000_scache();
+	__restore_flags(flags);
+}
+
+static void r5k_sc_disable(void)
+{
+        unsigned long flags;
+
+	__save_and_cli(flags);
+	blast_r5000_scache();
+	change_cp0_config(CONF_SE, 0);
+	__restore_flags(flags);
+}
+
+static inline int __init r5k_sc_probe(void)
+{
+	unsigned long config = read_32bit_cp0_register(CP0_CONFIG);
+
+	if(config & CONF_SC)
+		return(0);
+
+	scache_size = (512*1024) << ((config >> 20)&3);
+
+	printk("R5000 SCACHE size %ldK, linesize 32 bytes.\n",
+			scache_size >> 10);
+
+	return 1;
+}
+
+struct bcache_ops r5k_sc_ops = {
+	r5k_sc_enable,
+	r5k_sc_disable,
+	r5k_dma_cache_inv_sc,
+	r5k_dma_cache_inv_sc
+};
+
+void __init r5k_sc_init(void)
+{
+	if (r5k_sc_probe()) {
+		r5k_sc_enable();
+		bcops = &r5k_sc_ops;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/mm/tlb-r4k.c linux-2.4.20/arch/mips64/mm/tlb-r4k.c
--- linux-2.4.19/arch/mips64/mm/tlb-r4k.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/mips64/mm/tlb-r4k.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,407 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * MIPS64 CPU variant specific MMU routines.
+ * These routine are not optimized in any way, they are done in a generic way
+ * so they can be used on all MIPS64 compliant CPUs, and also done in an
+ * attempt not to break anything for the R4xx0 style CPUs.
+ */
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+#undef DEBUG_TLB
+#undef DEBUG_TLBUPDATE
+
+extern char except_vec1_r4k;
+
+/* CP0 hazard avoidance. */
+#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
+				     "nop; nop; nop; nop; nop; nop;\n\t" \
+				     ".set reorder\n\t")
+
+void local_flush_tlb_all(void)
+{
+	unsigned long flags;
+	unsigned long old_ctx;
+	int entry;
+
+#ifdef DEBUG_TLB
+	printk("[tlball]");
+#endif
+
+	__save_and_cli(flags);
+	/* Save old context and create impossible VPN2 value */
+	old_ctx = (get_entryhi() & 0xff);
+	set_entryhi(KSEG0);
+	set_entrylo0(0);
+	set_entrylo1(0);
+	BARRIER;
+
+	entry = get_wired();
+
+	/* Blast 'em all away. */
+	while(entry < mips_cpu.tlbsize) {
+	        /* Make sure all entries differ. */
+	        set_entryhi(KSEG0+entry*0x2000);
+		set_index(entry);
+		BARRIER;
+		tlb_write_indexed();
+		BARRIER;
+		entry++;
+	}
+	BARRIER;
+	set_entryhi(old_ctx);
+	__restore_flags(flags);
+}
+
+void local_flush_tlb_mm(struct mm_struct *mm)
+{
+	if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
+		unsigned long flags;
+
+#ifdef DEBUG_TLB
+		printk("[tlbmm<%d>]", mm->context);
+#endif
+		__save_and_cli(flags);
+		get_new_mmu_context(mm, smp_processor_id());
+		if (mm == current->active_mm)
+			set_entryhi(CPU_CONTEXT(smp_processor_id(), mm) &
+				    0xff);
+		__restore_flags(flags);
+	}
+}
+
+void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+				unsigned long end)
+{
+	if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
+		unsigned long flags;
+		int size;
+
+#ifdef DEBUG_TLB
+		printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff),
+		       start, end);
+#endif
+		__save_and_cli(flags);
+		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+		size = (size + 1) >> 1;
+		if(size <= mips_cpu.tlbsize/2) {
+			int oldpid = (get_entryhi() & 0xff);
+			int newpid = (CPU_CONTEXT(smp_processor_id(), mm) &
+				      0xff);
+
+			start &= (PAGE_MASK << 1);
+			end += ((PAGE_SIZE << 1) - 1);
+			end &= (PAGE_MASK << 1);
+			while(start < end) {
+				int idx;
+
+				set_entryhi(start | newpid);
+				start += (PAGE_SIZE << 1);
+				BARRIER;
+				tlb_probe();
+				BARRIER;
+				idx = get_index();
+				set_entrylo0(0);
+				set_entrylo1(0);
+				if(idx < 0)
+					continue;
+				/* Make sure all entries differ. */
+				set_entryhi(KSEG0+idx*0x2000);
+				BARRIER;
+				tlb_write_indexed();
+				BARRIER;
+			}
+			set_entryhi(oldpid);
+		} else {
+			get_new_mmu_context(mm, smp_processor_id());
+			if (mm == current->active_mm)
+				set_entryhi(CPU_CONTEXT(smp_processor_id(),
+							mm) & 0xff);
+		}
+		__restore_flags(flags);
+	}
+}
+
+void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+	if (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) != 0) {
+		unsigned long flags;
+		unsigned long oldpid, newpid, idx;
+
+#ifdef DEBUG_TLB
+		printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
+#endif
+		newpid = (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff);
+		page &= (PAGE_MASK << 1);
+		__save_and_cli(flags);
+		oldpid = (get_entryhi() & 0xff);
+		set_entryhi(page | newpid);
+		BARRIER;
+		tlb_probe();
+		BARRIER;
+		idx = get_index();
+		set_entrylo0(0);
+		set_entrylo1(0);
+		if(idx < 0)
+			goto finish;
+		/* Make sure all entries differ. */
+		set_entryhi(KSEG0+idx*0x2000);
+		BARRIER;
+		tlb_write_indexed();
+	finish:
+		BARRIER;
+		set_entryhi(oldpid);
+		__restore_flags(flags);
+	}
+}
+
+/*
+ * Updates the TLB with the new pte(s).
+ */
+void mips64_update_mmu_cache(struct vm_area_struct * vma,
+		      unsigned long address, pte_t pte)
+{
+	unsigned long flags;
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+	int idx, pid;
+
+	/*
+	 * Handle debugger faulting in for debugee.
+	 */
+	if (current->active_mm != vma->vm_mm)
+		return;
+
+	pid = get_entryhi() & 0xff;
+
+#ifdef DEBUG_TLB
+	if((pid != (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff)) ||
+	   (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) == 0)) {
+		printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d
+			tlbpid=%d\n", (int) (CPU_CONTEXT(smp_processor_id(),
+			vma->vm_mm) & 0xff), pid);
+	}
+#endif
+
+	__save_and_cli(flags);
+	address &= (PAGE_MASK << 1);
+	set_entryhi(address | (pid));
+	pgdp = pgd_offset(vma->vm_mm, address);
+	BARRIER;
+	tlb_probe();
+	BARRIER;
+	pmdp = pmd_offset(pgdp, address);
+	idx = get_index();
+	ptep = pte_offset(pmdp, address);
+	BARRIER;
+	set_entrylo0(pte_val(*ptep++) >> 6);
+	set_entrylo1(pte_val(*ptep) >> 6);
+	set_entryhi(address | (pid));
+	BARRIER;
+	if(idx < 0) {
+		tlb_write_random();
+	} else {
+		tlb_write_indexed();
+	}
+	BARRIER;
+	set_entryhi(pid);
+	BARRIER;
+	__restore_flags(flags);
+}
+
+void dump_mm_page(unsigned long addr)
+{
+	pgd_t	*page_dir, *pgd;
+	pmd_t	*pmd;
+	pte_t	*pte, page;
+	unsigned long val;
+
+	page_dir = pgd_offset(current->mm, 0);
+	pgd = pgd_offset(current->mm, addr);
+	pmd = pmd_offset(pgd, addr);
+	pte = pte_offset(pmd, addr);
+	page = *pte;
+	printk("Memory Mapping: VA = %08x, PA = %08x ", addr, (unsigned int) pte_val(page));
+	val = pte_val(page);
+	if (val & _PAGE_PRESENT) printk("present ");
+	if (val & _PAGE_READ) printk("read ");
+	if (val & _PAGE_WRITE) printk("write ");
+	if (val & _PAGE_ACCESSED) printk("accessed ");
+	if (val & _PAGE_MODIFIED) printk("modified ");
+	if (val & _PAGE_R4KBUG) printk("r4kbug ");
+	if (val & _PAGE_GLOBAL) printk("global ");
+	if (val & _PAGE_VALID) printk("valid ");
+	printk("\n");
+}
+
+void show_tlb(void)
+{
+        unsigned int flags;
+        unsigned int old_ctx;
+	unsigned int entry;
+	unsigned int entrylo0, entrylo1, entryhi;
+
+	__save_and_cli(flags);
+
+	/* Save old context */
+	old_ctx = (get_entryhi() & 0xff);
+
+	printk("TLB content:\n");
+	entry = 0;
+	while(entry < mips_cpu.tlbsize) {
+		set_index(entry);
+		BARRIER;
+		tlb_read();
+		BARRIER;
+		entryhi = get_entryhi();
+		entrylo0 = get_entrylo0();
+		entrylo1 = get_entrylo1();
+		printk("%02d: ASID=%02d%s VA=0x%08x ", entry, entryhi & ASID_MASK, (entrylo0 & entrylo1 & 1) ? "(G)" : "   ", entryhi & ~ASID_MASK);
+		printk("PA0=0x%08x C0=%x %s%s%s\n", (entrylo0>>6)<<12, (entrylo0>>3) & 7, (entrylo0 & 4) ? "Dirty " : "", (entrylo0 & 2) ? "Valid " : "Invalid ", (entrylo0 & 1) ? "Global" : "");
+		printk("\t\t\t     PA1=0x%08x C1=%x %s%s%s\n", (entrylo1>>6)<<12, (entrylo1>>3) & 7, (entrylo1 & 4) ? "Dirty " : "", (entrylo1 & 2) ? "Valid " : "Invalid ", (entrylo1 & 1) ? "Global" : "");
+
+		dump_mm_page(entryhi & ~0xff);
+		dump_mm_page((entryhi & ~0xff) | 0x1000);
+		entry++;
+	}
+	BARRIER;
+	set_entryhi(old_ctx);
+
+	__restore_flags(flags);
+}
+
+void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+				      unsigned long entryhi, unsigned long pagemask)
+{
+        unsigned long flags;
+        unsigned long wired;
+        unsigned long old_pagemask;
+        unsigned long old_ctx;
+
+        __save_and_cli(flags);
+        /* Save old context and create impossible VPN2 value */
+        old_ctx = (get_entryhi() & 0xff);
+        old_pagemask = get_pagemask();
+        wired = get_wired();
+        set_wired (wired + 1);
+        set_index (wired);
+        BARRIER;
+        set_pagemask (pagemask);
+        set_entryhi(entryhi);
+        set_entrylo0(entrylo0);
+        set_entrylo1(entrylo1);
+        BARRIER;
+        tlb_write_indexed();
+        BARRIER;
+
+        set_entryhi(old_ctx);
+        BARRIER;
+        set_pagemask (old_pagemask);
+        local_flush_tlb_all();
+        __restore_flags(flags);
+}
+
+/*
+ * Used for loading TLB entries before trap_init() has started, when we
+ * don't actually want to add a wired entry which remains throughout the
+ * lifetime of the system
+ */
+
+static int temp_tlb_entry __initdata;
+
+__init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
+			       unsigned long entryhi, unsigned long pagemask)
+{
+	int ret = 0;
+	unsigned long flags;
+	unsigned long wired;
+	unsigned long old_pagemask;
+	unsigned long old_ctx;
+
+	__save_and_cli(flags);
+	/* Save old context and create impossible VPN2 value */
+	old_ctx = get_entryhi() & 0xff;
+	old_pagemask = get_pagemask();
+	wired = get_wired();
+	if (--temp_tlb_entry < wired) {
+		printk(KERN_WARNING "No TLB space left for add_temporary_entry\n");
+		ret = -ENOSPC;
+		goto out;
+	}
+
+	set_index(temp_tlb_entry);
+	BARRIER;
+	set_pagemask(pagemask);
+	set_entryhi(entryhi);
+	set_entrylo0(entrylo0);
+	set_entrylo1(entrylo1);
+	BARRIER;
+	tlb_write_indexed();
+	BARRIER;
+
+	set_entryhi(old_ctx);
+	BARRIER;
+	set_pagemask(old_pagemask);
+out:
+	__restore_flags(flags);
+	return ret;
+}
+
+static void __init probe_tlb(unsigned long config)
+{
+        unsigned long config1;
+
+        if (!(config & (1 << 31))) {
+	        /*
+		 * Not a MIPS64 complainant CPU.
+		 * Config 1 register not supported, we assume R4k style.
+		 */
+	        mips_cpu.tlbsize = 48;
+	} else {
+	        config1 = read_mips32_cp0_config1();
+		if (!((config >> 7) & 3))
+		        panic("No MMU present");
+		else
+		        mips_cpu.tlbsize = ((config1 >> 25) & 0x3f) + 1;
+	}
+
+	printk("Number of TLB entries %d.\n", mips_cpu.tlbsize);
+}
+
+void __init r4k_tlb_init(void)
+{
+	unsigned long config = read_32bit_cp0_register(CP0_CONFIG);
+
+	probe_tlb(config);
+	_update_mmu_cache = mips64_update_mmu_cache;
+	set_pagemask(PM_4K);
+	write_32bit_cp0_register(CP0_WIRED, 0);
+	temp_tlb_entry = mips_cpu.tlbsize - 1;
+	local_flush_tlb_all();
+
+	memcpy((void *)(KSEG0 + 0x80), &except_vec1_r4k, 0x80);
+	flush_icache_range(KSEG0, KSEG0 + 0x80);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/mm/tlb-sb1.c linux-2.4.20/arch/mips64/mm/tlb-sb1.c
--- linux-2.4.19/arch/mips64/mm/tlb-sb1.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/mm/tlb-sb1.c	2002-10-29 11:18:40.000000000 +0000
@@ -12,11 +12,11 @@
  * 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.
- */ 
+ */
 #include <linux/config.h>
 #include <asm/mmu_context.h>
 #include <asm/bootinfo.h>
@@ -37,13 +37,13 @@
 		"     tlbr             \n"
 		"     dmfc0  $1, $10   \n"
 		"     dsrl32 %0, $1, 0 \n"
-		"     sra    %1, $1, 0 \n"
+		"     sll    %1, $1, 0 \n"
 		"     dmfc0  $1, $2    \n"
 		"     dsrl32 %2, $1, 0 \n"
-		"     sra    %3, $1, 0 \n"
+		"     sll    %3, $1, 0 \n"
 		"     dmfc0  $1, $3    \n"
 		"     dsrl32 %4, $1, 0 \n"
-		"     sra    %5, $1, 0 \n"
+		"     sll    %5, $1, 0 \n"
 		"     mfc0   %6, $5    \n"
 		".set pop              \n"
 		: "=r" (entryhihi),
@@ -62,7 +62,11 @@
 
 void sb1_dump_tlb(void)
 {
+	unsigned long old_ctx;
+	unsigned long flags;
 	int entry;
+	__save_and_cli(flags);
+	old_ctx = get_entryhi();
 	printk("Current TLB registers state:\n"
 	       "      EntryHi       EntryLo0          EntryLo1     PageMask  Index\n"
 	       "--------------------------------------------------------------------\n");
@@ -83,6 +87,8 @@
 		dump_cur_tlb_regs();
 	}
 	printk("\n");
+	set_entryhi(old_ctx);
+	__restore_flags(flags);
 }
 
 void local_flush_tlb_all(void)
@@ -102,12 +108,12 @@
 		tlb_write_indexed();
 	}
 	set_entryhi(old_ctx);
-	__restore_flags(flags);	
+	__restore_flags(flags);
 }
 
 
 /*
- * Use a bogus region of memory (starting at 0) to sanitize the TLB's.  
+ * Use a bogus region of memory (starting at 0) to sanitize the TLB's.
  * Use increments of the maximum page size (16MB), and check for duplicate
  * entries before doing a given write.  Then, when we're safe from collisions
  * with the firmware, go back and give all the entries invalid addresses with
@@ -209,7 +215,7 @@
 		set_entrylo1(0);
 		if(idx < 0)
 			goto finish;
-		/* Make sure all entries differ. */  
+		/* Make sure all entries differ. */
 		set_entryhi(KSEG0+(idx<<(PAGE_SHIFT+1)));
 		tlb_write_indexed();
 	finish:
@@ -299,7 +305,7 @@
 	/*
 	 * We don't know what state the firmware left the TLB's in, so this is
 	 * the ultra-conservative way to flush the TLB's and avoid machine
-	 * check exceptions due to duplicate TLB entries 
+	 * check exceptions due to duplicate TLB entries
 	 */
 	sb1_sanitize_tlb();
 	_update_mmu_cache = sb1_update_mmu_cache;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/mm/tlbex-r4k.S linux-2.4.20/arch/mips64/mm/tlbex-r4k.S
--- linux-2.4.19/arch/mips64/mm/tlbex-r4k.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/mm/tlbex-r4k.S	2002-10-29 11:18:30.000000000 +0000
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2000 Silicon Graphics, Inc.
  * Written by Ulf Carlsson (ulfc@engr.sgi.com)
+ * Copyright (C) 2002  Maciej W. Rozycki
  */
 #include <linux/config.h>
 #include <linux/init.h>
@@ -20,10 +21,9 @@
 
 	/*
 	 * After this macro runs we have a pointer to the pte of the address
-	 * that caused the fault in in PTR.
+	 * that caused the fault in PTR.
 	 */
-
-	.macro	LOAD_PTE2, ptr, tmp
+	.macro	LOAD_PTE2, ptr, tmp, kaddr
 #ifdef CONFIG_SMP
 	dmfc0	\ptr, CP0_CONTEXT
 	dmfc0	\tmp, CP0_BADVADDR
@@ -32,8 +32,8 @@
 	dmfc0	\tmp, CP0_BADVADDR
 	dla	\ptr, pgd_current
 #endif
-	bltz	\tmp, kaddr
-	ld	\ptr, (\ptr)
+	bltz	\tmp, \kaddr
+	 ld	\ptr, (\ptr)
 	dsrl	\tmp, (PGDIR_SHIFT-3)		# get pgd offset in bytes
 	andi	\tmp, ((PTRS_PER_PGD - 1)<<3)
 	daddu	\ptr, \tmp			# add in pgd offset
@@ -48,6 +48,35 @@
 	daddu	\ptr, \tmp
 	.endm
 
+
+	/*
+	 * Ditto for the kernel table.
+	 */
+	.macro	LOAD_KPTE2, ptr, tmp, not_vmalloc
+	/*
+	 * First, determine that the address is in/above vmalloc range.
+	 */
+	dmfc0	\tmp, CP0_BADVADDR
+	dli	\ptr, VMALLOC_START
+
+	/*
+	 * Now find offset into kptbl.
+	 */
+	dsubu	\tmp, \tmp, \ptr
+	dla	\ptr, kptbl
+	dsrl	\tmp, (PAGE_SHIFT+1)		# get vpn2
+	dsll	\tmp, 4				# byte offset of pte
+	daddu	\ptr, \ptr, \tmp
+
+	/*
+	 * Determine that fault address is within vmalloc range.
+	 */
+	dla	\tmp, ekptbl
+	sltu	\tmp, \ptr, \tmp
+	beqz	\tmp, \not_vmalloc		# not vmalloc
+	.endm
+
+
 	/*
 	 * This places the even/odd pte pair in the page table at the pte
 	 * entry pointed to by PTE into ENTRYLO0 and ENTRYLO1.
@@ -59,6 +88,7 @@
 	dmtc0	\pte1, CP0_ENTRYLO1		# load it
 	.endm
 
+
 	.text
 	.set	noreorder
 	.set	mips3
@@ -66,69 +96,93 @@
 	__INIT
 
 	.align	5
-FEXPORT(except_vec0)
+LEAF(except_vec0)
 	.set	noat
 	PANIC("Unused vector called")
 1:	b	1b
 	 nop
+END(except_vec0)
+
 
 	/*
-	 * TLB refill handler for the R10000.
+	 * TLB refill handler for the R4000.
 	 * Attention:  We may only use 32 instructions / 128 bytes.
 	 */
+	.align  5
+LEAF(except_vec1_r4k)
+	.set    noat
+	dla     k0, handle_vec1_r4k
+	jr      k0
+	 nop
+END(except_vec1_r4k)
 
-	.align	5
-LEAF(except_vec1_r10k)
-	.set	noat
-	LOAD_PTE2 k1 k0
+	__FINIT
+
+	.align  5
+LEAF(handle_vec1_r4k)
+	.set    noat
+	LOAD_PTE2 k1 k0 9f
 	ld	k0, 0(k1)			# get even pte
 	ld	k1, 8(k1)			# get odd pte
 	PTE_RELOAD k0 k1
-	nop
-	tlbwr
+	b	1f
+	 tlbwr
+1:	nop
 	eret
-kaddr:
-	dla	k0, handle_vmalloc_address	# MAPPED kernel needs this
-	jr	k0
-	 nop
-	END(except_vec1_r10k)
 
-	__FINIT
+9:						# handle the vmalloc range
+	LOAD_KPTE2 k1 k0 invalid_vmalloc_address
+	ld	k0, 0(k1)			# get even pte
+	ld	k1, 8(k1)			# get odd pte
+	PTE_RELOAD k0 k1
+	b	1f
+	 tlbwr
+1:	nop
+	eret
+END(handle_vec1_r4k)
 
-	.align	5
-LEAF(handle_vmalloc_address)
-	.set	noat
-	/*
-	 * First, determine that the address is in/above vmalloc range.
-	 */
-	dmfc0	k0, CP0_BADVADDR
-	dli	k1, VMALLOC_START
+	__INIT
 
 	/*
-	 * Now find offset into kptbl.
+	 * TLB refill handler for the R10000.
+	 * Attention:  We may only use 32 instructions / 128 bytes.
 	 */
-	dsubu	k0, k0, k1
-	dla	k1, kptbl
-	dsrl	k0, (PAGE_SHIFT+1)		# get vpn2
-	dsll	k0, 4				# byte offset of pte
-	daddu	k1, k1, k0
+	.align	5
+LEAF(except_vec1_r10k)
+	.set    noat
+	dla     k0, handle_vec1_r10k
+	jr      k0
+	 nop
+END(except_vec1_r10k)
 
-	/*
-	 * Determine that fault address is within vmalloc range.
-	 */
-	dla	k0, ekptbl
-	sltu	k0, k1, k0
-	beqz	k0, not_vmalloc
+	__FINIT
 
-	/*
-	 * Load cp0 registers.
-	 */
+	.align	5
+LEAF(handle_vec1_r10k)
+	.set	noat
+	LOAD_PTE2 k1 k0 9f
 	ld	k0, 0(k1)			# get even pte
 	ld	k1, 8(k1)			# get odd pte
+	PTE_RELOAD k0 k1
+	nop
+	tlbwr
+	eret
 
-not_vmalloc:
+9:						# handle the vmalloc range
+	LOAD_KPTE2 k1 k0 invalid_vmalloc_address
+	ld	k0, 0(k1)			# get even pte
+	ld	k1, 8(k1)			# get odd pte
 	PTE_RELOAD k0 k1
 	nop
 	tlbwr
 	eret
-	END(handle_vmalloc_address)
+END(handle_vec1_r10k)
+
+
+	.align	5
+LEAF(invalid_vmalloc_address)
+	.set	noat
+	PANIC("Invalid kernel address")
+1:	b	1b
+	 nop
+END(invalid_vmalloc_address)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/mm/umap.c linux-2.4.20/arch/mips64/mm/umap.c
--- linux-2.4.19/arch/mips64/mm/umap.c	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/arch/mips64/mm/umap.c	2002-10-29 11:18:33.000000000 +0000
@@ -51,7 +51,7 @@
 		address += PAGE_SIZE;
 		pte++;
 	} while (address < end);
-						  
+
 }
 
 static inline void remove_mapping_pmd_range (pgd_t *pgd, unsigned long address,
@@ -79,7 +79,7 @@
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
 	} while (address < end);
-		
+
 }
 
 /*
@@ -137,7 +137,7 @@
 
 /*
  * maps a range of vmalloc()ed memory into the requested pages. the old
- * mappings are removed. 
+ * mappings are removed.
  */
 static inline void vmap_pte_range (pte_t *pte, unsigned long address,
 				   unsigned long size, unsigned long vaddr)
@@ -146,7 +146,7 @@
 	pgd_t *vdir;
 	pmd_t *vpmd;
 	pte_t *vpte;
-	
+
 	address &= ~PMD_MASK;
 	end = address + size;
 	if (end > PMD_SIZE)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/Makefile linux-2.4.20/arch/mips64/sgi-ip27/Makefile
--- linux-2.4.19/arch/mips64/sgi-ip27/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/Makefile	1970-01-01 00:00:00.000000000 +0000
@@ -1,15 +0,0 @@
-#
-# Makefile for the IP27 specific kernel interface routines under Linux.
-#
-
-USE_STANDARD_AS_RULE := true
-
-O_TARGET = ip27.o
-
-export-objs		= ip27-rtc.o
-
-obj-y	:= ip27-berr.o ip27-console.o ip27-irq.o ip27-init.o ip27-irq-glue.o \
-	   ip27-klconfig.o ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-pci.o \
-	   ip27-pci-dma.o ip27-reset.o ip27-setup.o ip27-timer.o
-
-include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/TODO linux-2.4.20/arch/mips64/sgi-ip27/TODO
--- linux-2.4.19/arch/mips64/sgi-ip27/TODO	2000-05-13 15:30:17.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/TODO	1970-01-01 00:00:00.000000000 +0000
@@ -1,23 +0,0 @@
-1. Need to figure out why PCI writes to the IOC3 hang, and if it is okay
-not to write to the IOC3 ever.
-2. Need to figure out RRB allocation in bridge_startup().
-3. Need to figure out why address swaizzling is needed in inw/outw for 
-Qlogic scsi controllers.
-4. Need to integrate ip27-klconfig.c:find_lboard and 
-ip27-init.c:find_lbaord_real. DONE
-5. Is it okay to set calias space on all nodes as 0, instead of 8k as
-in irix?
-6. Investigate why things do not work without the setup_test() call
-being invoked on all nodes in ip27-memory.c.
-7. Too many CLIs in the locore handlers :
-For the low level handlers set up by set_except_vector(), 
-__tlb_refill_debug_tramp, __xtlb_refill_debug_tramp and cacheerror,
-investigate whether the code should do CLI, STI or KMODE. 
-8. Too many do_page_faults invoked - investigate.
-9. start_thread must turn off UX64 ... and define tlb_refill_debug.
-10. Need a bad pmd table, bad pte table. __bad_pmd_table/__bad_pagetable
-does not agree with pgd_bad/pmd_bad.
-11. All intrs (ip27_do_irq handlers) are targetted at cpu A on the node.
-This might need to change later. Only the timer intr is set up to be
-received on both Cpu A and B. (ip27_do_irq()/bridge_startup())
-13. Cache flushing (specially the SMP version) has to be investigated.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/ip27-berr.c linux-2.4.20/arch/mips64/sgi-ip27/ip27-berr.c
--- linux-2.4.19/arch/mips64/sgi-ip27/ip27-berr.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/ip27-berr.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,93 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994, 1995, 1996, 1999, 2000 by Ralf Baechle
- * Copyright (C) 1999, 2000 by Silicon Graphics
- * Copyright (C) 2002  Maciej W. Rozycki
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include <asm/module.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/sn0/hub.h>
-#include <asm/traps.h>
-#include <asm/uaccess.h>
-
-extern void dump_tlb_addr(unsigned long addr);
-extern void dump_tlb_all(void);
-
-static void dump_hub_information(unsigned long errst0, unsigned long errst1)
-{
-	static char *err_type[2][8] = {
-		{ NULL, "Uncached Partial Read PRERR", "DERR", "Read Timeout",
-		  NULL, NULL, NULL, NULL },
-		{ "WERR", "Uncached Partial Write", "PWERR", "Write Timeout",
-		  NULL, NULL, NULL, NULL }
-	};
-	int wrb = errst1 & PI_ERR_ST1_WRBRRB_MASK;
-
-	if (!(errst0 & PI_ERR_ST0_VALID_MASK)) {
-		printk("Hub does not contain valid error information\n");
-		return;
-	}
-
-	
-	printk("Hub has valid error information:\n");
-	if (errst0 & PI_ERR_ST0_OVERRUN_MASK)
-		printk("Overrun is set.  Error stack may contain additional "
-		       "information.\n");
-	printk("Hub error address is %08lx\n",
-	       (errst0 & PI_ERR_ST0_ADDR_MASK) >> (PI_ERR_ST0_ADDR_SHFT - 3));
-	printk("Incoming message command 0x%lx\n",
-	       (errst0 & PI_ERR_ST0_CMD_MASK) >> PI_ERR_ST0_CMD_SHFT);
-	printk("Supplemental field of incoming message is 0x%lx\n",
-	       (errst0 & PI_ERR_ST0_SUPPL_MASK) >> PI_ERR_ST0_SUPPL_SHFT);
-	printk("T5 Rn (for RRB only) is 0x%lx\n",
-	       (errst0 & PI_ERR_ST0_REQNUM_MASK) >> PI_ERR_ST0_REQNUM_SHFT);
-	printk("Error type is %s\n", err_type[wrb]
-	       [(errst0 & PI_ERR_ST0_TYPE_MASK) >> PI_ERR_ST0_TYPE_SHFT]
-		? : "invalid");
-}
-
-int be_ip27_handler(struct pt_regs *regs, int is_fixup)
-{
-	unsigned long errst0, errst1;
-	int data = regs->cp0_cause & 4;
-	int cpu = LOCAL_HUB_L(PI_CPU_NUM);
-
-	if (is_fixup)
-		return MIPS_BE_FIXUP;
-
-	printk("Slice %c got %cbe at 0x%lx\n", 'A' + cpu, data ? 'd' : 'i',
-	       regs->cp0_epc);
-	printk("Hub information:\n");
-	printk("ERR_INT_PEND = 0x%06lx\n", LOCAL_HUB_L(PI_ERR_INT_PEND));
-	errst0 = LOCAL_HUB_L(cpu ? PI_ERR_STATUS0_B : PI_ERR_STATUS0_A);
-	errst1 = LOCAL_HUB_L(cpu ? PI_ERR_STATUS1_B : PI_ERR_STATUS1_A);
-	dump_hub_information(errst0, errst1);
-	show_regs(regs);
-	dump_tlb_all();
-	while(1);
-	force_sig(SIGBUS, current);
-}
-
-void __init bus_error_init(void)
-{
-	/* XXX Initialize all the Hub & Bridge error handling here.  */
-	int cpu = LOCAL_HUB_L(PI_CPU_NUM);
-	int cpuoff = cpu << 8;
-
-	be_board_handler = be_ip27_handler;
-
-	LOCAL_HUB_S(PI_ERR_INT_PEND,
-	            cpu ? PI_ERR_CLEAR_ALL_B : PI_ERR_CLEAR_ALL_A);
-	LOCAL_HUB_S(PI_ERR_INT_MASK_A + cpuoff, 0);
-	LOCAL_HUB_S(PI_ERR_STACK_ADDR_A + cpuoff, 0);
-	LOCAL_HUB_S(PI_ERR_STACK_SIZE, 0);	/* Disable error stack */
-	LOCAL_HUB_S(PI_SYSAD_ERRCHK_EN, PI_SYSAD_CHECK_ALL);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/ip27-console.c linux-2.4.20/arch/mips64/sgi-ip27/ip27-console.c
--- linux-2.4.19/arch/mips64/sgi-ip27/ip27-console.c	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/ip27-console.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,58 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 Ralf Baechle
- */
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/kdev_t.h>
-#include <linux/major.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/sn0/hub.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/ioc3.h>
-#include <asm/sn/sn_private.h>
-
-void prom_putchar(char c)
-{
-	struct ioc3 *ioc3;
-	struct ioc3_uartregs *uart;
-
-	ioc3 = (struct ioc3 *)KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base;
-	uart = &ioc3->sregs.uarta;
-
-	while ((uart->iu_lsr & 0x20) == 0);
-	uart->iu_thr = c;
-}
-
-char __init prom_getchar(void)
-{
-	return 0;
-}
-
-static void
-ip27prom_console_write(struct console *con, const char *s, unsigned n)
-{
-	prom_printf("%s", s);
-}
-
-static kdev_t 
-ip27prom_console_dev(struct console *c)
-{
-	return MKDEV(TTY_MAJOR, 64 + c->index);
-}
-
-static struct console ip27_prom_console = {
-    name:	"prom",
-    write:	ip27prom_console_write,
-    device:	ip27prom_console_dev,
-    flags:	CON_PRINTBUFFER,
-    index:	-1,
-};
-
-__init void ip27_setup_console(void)
-{
-	register_console(&ip27_prom_console);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/ip27-dbe-glue.S linux-2.4.20/arch/mips64/sgi-ip27/ip27-dbe-glue.S
--- linux-2.4.19/arch/mips64/sgi-ip27/ip27-dbe-glue.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/ip27-dbe-glue.S	1970-01-01 00:00:00.000000000 +0000
@@ -1,20 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994 - 1999 by Ralf Baechle
- * Copyright (C) 1999 Silicon Graphics
- *
- * Low level exception handling
- */
-#define __ASSEMBLY__
-#include <linux/init.h>
-#include <asm/asm.h>
-#include <asm/regdef.h>
-#include <asm/fpregdef.h>
-#include <asm/mipsregs.h>
-#include <asm/exception.h>
-
-	BUILD_HANDLER ip27_ibe ip27_ibe cli silent		/* #6  */
-	BUILD_HANDLER ip27_dbe ip27_dbe cli silent		/* #7  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/ip27-init.c linux-2.4.20/arch/mips64/sgi-ip27/ip27-init.c
--- linux-2.4.19/arch/mips64/sgi-ip27/ip27-init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/ip27-init.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,838 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General
- * Public License.  See the file "COPYING" in the main directory of this
- * archive for more details.
- *
- * Copyright (C) 2000 - 2001 by Kanoj Sarcar (kanoj@sgi.com)
- * Copyright (C) 2000 - 2001 by Silicon Graphics, Inc.
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/mmzone.h>	/* for numnodes */
-#include <linux/mm.h>
-#include <asm/cpu.h>
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/sn/types.h>
-#include <asm/sn/sn0/addrs.h>
-#include <asm/sn/sn0/hubni.h>
-#include <asm/sn/sn0/hubio.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/ioc3.h>
-#include <asm/mipsregs.h>
-#include <asm/sn/gda.h>
-#include <asm/sn/intr.h>
-#include <asm/current.h>
-#include <asm/smp.h>
-#include <asm/processor.h>
-#include <asm/mmu_context.h>
-#include <asm/sn/launch.h>
-#include <asm/sn/sn_private.h>
-#include <asm/sn/sn0/ip27.h>
-#include <asm/sn/mapped_kernel.h>
-#include <asm/sn/sn0/addrs.h>
-#include <asm/sn/gda.h>
-
-#define CPU_NONE		(cpuid_t)-1
-
-/*
- * The following should work till 64 nodes, ie 128p SN0s.
- */
-#define CNODEMASK_CLRALL(p)	(p) = 0
-#define CNODEMASK_TSTB(p, bit)	((p) & (1ULL << (bit)))
-#define CNODEMASK_SETB(p, bit)	((p) |= 1ULL << (bit))
-
-cpumask_t	boot_cpumask;
-hubreg_t	region_mask = 0;
-static int	fine_mode = 0;
-int		maxcpus;
-static spinlock_t hub_mask_lock = SPIN_LOCK_UNLOCKED;
-static cnodemask_t hub_init_mask;
-static atomic_t numstarted = ATOMIC_INIT(1);
-static int router_distance;
-nasid_t master_nasid = INVALID_NASID;
-
-cnodeid_t	nasid_to_compact_node[MAX_NASIDS];
-nasid_t		compact_to_nasid_node[MAX_COMPACT_NODES];
-cnodeid_t	cpuid_to_compact_node[MAXCPUS];
-char		node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
-
-hubreg_t get_region(cnodeid_t cnode)
-{
-	if (fine_mode)
-		return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_FINEREG_SHFT;
-	else
-		return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_COARSEREG_SHFT;
-}
-
-static void gen_region_mask(hubreg_t *region_mask, int maxnodes)
-{
-	cnodeid_t cnode;
-
-	(*region_mask) = 0;
-	for (cnode = 0; cnode < maxnodes; cnode++) {
-		(*region_mask) |= 1ULL << get_region(cnode);
-	}
-}
-
-int is_fine_dirmode(void)
-{
-	return (((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK)
-		>> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE);
-}
-
-nasid_t get_actual_nasid(lboard_t *brd)
-{
-	klhub_t *hub;
-
-	if (!brd)
-		return INVALID_NASID;
-
-	/* find out if we are a completely disabled brd. */
-	hub  = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
-	if (!hub)
-		return INVALID_NASID;
-	if (!(hub->hub_info.flags & KLINFO_ENABLE))	/* disabled node brd */
-		return hub->hub_info.physid;
-	else
-		return brd->brd_nasid;
-}
-
-/* Tweak this for maximum number of CPUs to activate */
-static int max_cpus = NR_CPUS;
-
-int do_cpumask(cnodeid_t cnode, nasid_t nasid, cpumask_t *boot_cpumask, 
-							int *highest)
-{
-	static int tot_cpus_found = 0;
-	lboard_t *brd;
-	klcpu_t *acpu;
-	int cpus_found = 0;
-	cpuid_t cpuid;
-
-	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
-
-	do {
-		acpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU);
-		while (acpu) {
-			cpuid = acpu->cpu_info.virtid;
-			/* cnode is not valid for completely disabled brds */
-			if (get_actual_nasid(brd) == brd->brd_nasid)
-				cpuid_to_compact_node[cpuid] = cnode;
-			if (cpuid > *highest)
-				*highest = cpuid;
-			/* Only let it join in if it's marked enabled */
-			if ((acpu->cpu_info.flags & KLINFO_ENABLE) &&
-						(tot_cpus_found != max_cpus)) {
-				CPUMASK_SETB(*boot_cpumask, cpuid);
-				cpus_found++;
-				tot_cpus_found++;
-			}
-			acpu = (klcpu_t *)find_component(brd, (klinfo_t *)acpu, 
-								KLSTRUCT_CPU);
-		}
-		brd = KLCF_NEXT(brd);
-		if (brd)
-			brd = find_lboard(brd,KLTYPE_IP27);
-		else
-			break;
-	} while (brd);
-
-	return cpus_found;
-}
-
-cpuid_t cpu_node_probe(cpumask_t *boot_cpumask, int *numnodes)
-{
-	int i, cpus = 0, highest = 0;
-	gda_t *gdap = GDA;
-	nasid_t nasid;
-
-	/*
-	 * Initialize the arrays to invalid nodeid (-1)
-	 */
-	for (i = 0; i < MAX_COMPACT_NODES; i++)
-		compact_to_nasid_node[i] = INVALID_NASID;
-	for (i = 0; i < MAX_NASIDS; i++)
-		nasid_to_compact_node[i] = INVALID_CNODEID;
-	for (i = 0; i < MAXCPUS; i++)
-		cpuid_to_compact_node[i] = INVALID_CNODEID;
-
-	*numnodes = 0;
-	for (i = 0; i < MAX_COMPACT_NODES; i++) {
-		if ((nasid = gdap->g_nasidtable[i]) == INVALID_NASID) {
-			break;
-		} else {
-			compact_to_nasid_node[i] = nasid;
-			nasid_to_compact_node[nasid] = i;
-			(*numnodes)++;
-			cpus += do_cpumask(i, nasid, boot_cpumask, &highest);
-		}
-	}
-
-	/*
-	 * Cpus are numbered in order of cnodes. Currently, disabled
-	 * cpus are not numbered.
-	 */
-
-	return(highest + 1);
-}
-
-int cpu_enabled(cpuid_t cpu)
-{
-	if (cpu == CPU_NONE)
-		return 0;
-	return (CPUMASK_TSTB(boot_cpumask, cpu) != 0);
-}
-
-void mlreset (void)
-{
-	int i;
-	void init_topology_matrix(void);
-	void dump_topology(void);
-
-
-	master_nasid = get_nasid();
-	fine_mode = is_fine_dirmode();
-
-	/*
-	 * Probe for all CPUs - this creates the cpumask and
-	 * sets up the mapping tables.
-	 */
-	CPUMASK_CLRALL(boot_cpumask);
-	maxcpus = cpu_node_probe(&boot_cpumask, &numnodes);
-	printk("Discovered %d cpus on %d nodes\n", maxcpus, numnodes);
-
-	init_topology_matrix();
-	dump_topology();
-
-	gen_region_mask(&region_mask, numnodes);
-	CNODEMASK_CLRALL(hub_init_mask);
-
-	setup_replication_mask(numnodes);
-
-	/*
-	 * Set all nodes' calias sizes to 8k
-	 */
-	for (i = 0; i < numnodes; i++) {
-		nasid_t nasid;
-
-		nasid = COMPACT_TO_NASID_NODEID(i);
-
-		/*
-		 * Always have node 0 in the region mask, otherwise
-		 * CALIAS accesses get exceptions since the hub
-		 * thinks it is a node 0 address.
-		 */
-		REMOTE_HUB_S(nasid, PI_REGION_PRESENT, (region_mask | 1));
-#ifdef CONFIG_REPLICATE_EXHANDLERS
-		REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_8K);
-#else
-		REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_0);
-#endif
-
-#ifdef LATER
-		/*
-		 * Set up all hubs to have a big window pointing at
-		 * widget 0. Memory mode, widget 0, offset 0
-		 */
-		REMOTE_HUB_S(nasid, IIO_ITTE(SWIN0_BIGWIN),
-			((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) |
-			(0 << IIO_ITTE_WIDGET_SHIFT)));
-#endif
-	}
-}
-
-
-void intr_clear_bits(nasid_t nasid, volatile hubreg_t *pend, int base_level,
-							char *name)
-{
-	volatile hubreg_t bits;
-	int i;
-
-	/* Check pending interrupts */
-	if ((bits = HUB_L(pend)) != 0)
-		for (i = 0; i < N_INTPEND_BITS; i++)
-			if (bits & (1 << i))
-				LOCAL_HUB_CLR_INTR(base_level + i);
-}
-	
-void intr_clear_all(nasid_t nasid)
-{
-	REMOTE_HUB_S(nasid, PI_INT_MASK0_A, 0);
-	REMOTE_HUB_S(nasid, PI_INT_MASK0_B, 0);
-	REMOTE_HUB_S(nasid, PI_INT_MASK1_A, 0);
-	REMOTE_HUB_S(nasid, PI_INT_MASK1_B, 0);
-	intr_clear_bits(nasid, REMOTE_HUB_ADDR(nasid, PI_INT_PEND0),
-		INT_PEND0_BASELVL, "INT_PEND0");
-	intr_clear_bits(nasid, REMOTE_HUB_ADDR(nasid, PI_INT_PEND1),
-		INT_PEND1_BASELVL, "INT_PEND1");
-}
-
-void sn_mp_setup(void)
-{
-	cnodeid_t	cnode;
-#if 0
-	cpuid_t		cpu;
-#endif
-
-	for (cnode = 0; cnode < numnodes; cnode++) {
-#if 0
-		init_platform_nodepda();
-#endif
-		intr_clear_all(COMPACT_TO_NASID_NODEID(cnode));
-	}
-#if 0
-	for (cpu = 0; cpu < maxcpus; cpu++) {
-		init_platform_pda();
-	}
-#endif
-}
-
-void per_hub_init(cnodeid_t cnode)
-{
-	extern void pcibr_setup(cnodeid_t);
-	cnodemask_t	done;
-	nasid_t		nasid;
-
-	nasid = COMPACT_TO_NASID_NODEID(cnode);
-
-	spin_lock(&hub_mask_lock);
-	/* Test our bit. */
-	if (!(done = CNODEMASK_TSTB(hub_init_mask, cnode))) {
-		/* Turn our bit on in the mask. */
-		CNODEMASK_SETB(hub_init_mask, cnode);
-		/*
-	 	 * Do the actual initialization if it hasn't been done yet.
-	 	 * We don't need to hold a lock for this work.
-	 	 */
-		/*
-		 * Set CRB timeout at 5ms, (< PI timeout of 10ms)
-		 */
-		REMOTE_HUB_S(nasid, IIO_ICTP, 0x800);
-		REMOTE_HUB_S(nasid, IIO_ICTO, 0xff);
-		hub_rtc_init(cnode);
-		pcibr_setup(cnode); 
-#ifdef CONFIG_REPLICATE_EXHANDLERS
-		/*
-		 * If this is not a headless node initialization, 
-		 * copy over the caliased exception handlers.
-		 */
-		if (get_compact_nodeid() == cnode) {
-			extern char except_vec0, except_vec1_r10k;
-			extern char except_vec2_generic, except_vec3_generic;
-
-			memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic,
-								0x80);
-			memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic,
-								0x80);
-			memcpy((void *)KSEG0, &except_vec0, 0x80);
-			memcpy((void *)KSEG0 + 0x080, &except_vec1_r10k, 0x80);
-			memcpy((void *)(KSEG0 + 0x100), (void *) KSEG0, 0x80);
-			memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic,
-								0x100);
-			flush_cache_l1();
-			flush_cache_l2();
-		}
-#endif
-	}
-	spin_unlock(&hub_mask_lock);
-}
-
-/*
- * This is similar to hard_smp_processor_id().
- */
-cpuid_t getcpuid(void)
-{
-	klcpu_t *klcpu;
-
-	klcpu = nasid_slice_to_cpuinfo(get_nasid(),LOCAL_HUB_L(PI_CPU_NUM));
-	return klcpu->cpu_info.virtid;
-}
-
-void per_cpu_init(void)
-{
-	extern void install_cpu_nmi_handler(int slice);
-	extern void load_mmu(void);
-	static int is_slave = 0;
-	int cpu = smp_processor_id();
-	cnodeid_t cnode = get_compact_nodeid();
-
-	TLBMISS_HANDLER_SETUP();
-#if 0
-	intr_init();
-#endif
-	clear_cp0_status(ST0_IM);
-	per_hub_init(cnode);
-	cpu_time_init();
-	if (smp_processor_id())	/* master can't do this early, no kmalloc */
-		install_cpuintr(cpu);
-	/* Install our NMI handler if symmon hasn't installed one. */
-	install_cpu_nmi_handler(cputoslice(cpu));
-#if 0
-	install_tlbintr(cpu);
-#endif
-	set_cp0_status(SRB_DEV0 | SRB_DEV1);
-	if (is_slave) {
-		clear_cp0_status(ST0_BEV);
-		if (mips_cpu.isa_level == MIPS_CPU_ISA_IV)
-			set_cp0_status(ST0_XX);
-		set_cp0_status(ST0_KX|ST0_SX|ST0_UX);
-		sti();
-		load_mmu();
-		atomic_inc(&numstarted);
-	} else {
-		is_slave = 1;
-	}
-}
-
-cnodeid_t get_compact_nodeid(void)
-{
-	nasid_t nasid;
-
-	nasid = get_nasid();
-	/*
-	 * Map the physical node id to a virtual node id (virtual node ids
-	 * are contiguous).
-	 */
-	return NASID_TO_COMPACT_NODEID(nasid);
-}
-
-#ifdef CONFIG_SMP
-
-/*
- * Takes as first input the PROM assigned cpu id, and the kernel
- * assigned cpu id as the second.
- */
-static void alloc_cpupda(cpuid_t cpu, int cpunum)
-{
-	cnodeid_t	node;
-	nasid_t		nasid;
-
-	node = get_cpu_cnode(cpu);
-	nasid = COMPACT_TO_NASID_NODEID(node);
-
-	cputonasid(cpunum) = nasid;
-	cputocnode(cpunum) = node;
-	cputoslice(cpunum) = get_cpu_slice(cpu);
-	cpu_data[cpunum].p_cpuid = cpu;
-}
-
-static volatile cpumask_t boot_barrier;
-
-void __init start_secondary(void)
-{
-	CPUMASK_CLRB(boot_barrier, getcpuid());	/* needs atomicity */
-	per_cpu_init();
-	per_cpu_trap_init();
-#if 0
-	ecc_init();
-	bte_lateinit();
-	init_mfhi_war();
-#endif
-	local_flush_tlb_all();
-	flush_cache_l1();
-	flush_cache_l2();
-	start_secondary();
-}
-
-__init void allowboot(void)
-{
-	int		num_cpus = 0;
-	cpuid_t		cpu, mycpuid = getcpuid();
-	cnodeid_t	cnode;
-	extern void	smp_bootstrap(void);
-
-	sn_mp_setup();
-	/* Master has already done per_cpu_init() */
-	install_cpuintr(smp_processor_id());
-#if 0
-	bte_lateinit();
-	ecc_init();
-#endif
-
-	replicate_kernel_text(numnodes);
-	boot_barrier = boot_cpumask;
-	/* Launch slaves. */
-	for (cpu = 0; cpu < maxcpus; cpu++) {
-		if (cpu == mycpuid) {
-			alloc_cpupda(cpu, num_cpus);
-			num_cpus++;
-			/* We're already started, clear our bit */
-			CPUMASK_CLRB(boot_barrier, cpu);
-			continue;
-		}
-
-		/* Skip holes in CPU space */
-		if (CPUMASK_TSTB(boot_cpumask, cpu)) {
-			struct task_struct *p;
-
-			/*
-			 * The following code is purely to make sure
-			 * Linux can schedule processes on this slave.
-			 */
-			kernel_thread(0, NULL, CLONE_PID);
-			p = init_task.prev_task;
-			sprintf(p->comm, "%s%d", "Idle", num_cpus);
-			init_tasks[num_cpus] = p;
-			alloc_cpupda(cpu, num_cpus);
-			del_from_runqueue(p);
-			p->processor = num_cpus;
-			p->cpus_runnable = 1 << num_cpus; /* we schedule the first task manually */
-			unhash_process(p);
-			/* Attach to the address space of init_task. */
-			atomic_inc(&init_mm.mm_count);
-			p->active_mm = &init_mm;
-
-			/*
-		 	 * Launch a slave into smp_bootstrap().
-		 	 * It doesn't take an argument, and we
-			 * set sp to the kernel stack of the newly 
-			 * created idle process, gp to the proc struct
-			 * (so that current-> works).
-		 	 */
-			LAUNCH_SLAVE(cputonasid(num_cpus),cputoslice(num_cpus), 
-				(launch_proc_t)MAPPED_KERN_RW_TO_K0(smp_bootstrap),
-				0, (void *)((unsigned long)p + 
-				KERNEL_STACK_SIZE - 32), (void *)p);
-
-			/*
-			 * Now optimistically set the mapping arrays. We
-			 * need to wait here, verify the cpu booted up, then
-			 * fire up the next cpu.
-			 */
-			__cpu_number_map[cpu] = num_cpus;
-			__cpu_logical_map[num_cpus] = cpu;
-			CPUMASK_SETB(cpu_online_map, cpu);
-			num_cpus++;
-			/*
-			 * Wait this cpu to start up and initialize its hub,
-			 * and discover the io devices it will control.
-			 * 
-			 * XXX: We really want to fire up launch all the CPUs
-			 * at once.  We have to preserve the order of the
-			 * devices on the bridges first though.
-			 */
-			while(atomic_read(&numstarted) != num_cpus);
-		}
-	}
-
-
-#ifdef LATER
-	Wait logic goes here.
-#endif
-	for (cnode = 0; cnode < numnodes; cnode++) {
-#if 0
-		if (cnodetocpu(cnode) == -1) {
-			printk("Initializing headless hub,cnode %d", cnode);
-			per_hub_init(cnode);
-		}
-#endif
-	}
-#if 0
-	cpu_io_setup();
-	init_mfhi_war();
-#endif
-	smp_num_cpus = num_cpus;
-}
-
-void __init smp_boot_cpus(void)
-{
-	extern void allowboot(void);
-
-	init_new_context(current, &init_mm);
-	current->processor = 0;
-	init_idle();
-	smp_tune_scheduling();
-	allowboot();
-}
-
-#else /* CONFIG_SMP */
-void __init start_secondary(void)
-{
-	/* XXX Why do we need this empty definition at all?  */
-}
-#endif /* CONFIG_SMP */
-
-
-#define	rou_rflag	rou_flags
-
-void
-router_recurse(klrou_t *router_a, klrou_t *router_b, int depth)
-{
-	klrou_t *router;
-	lboard_t *brd;
-	int	port;
-
-	if (router_a->rou_rflag == 1)
-		return;
-
-	if (depth >= router_distance)
-		return;
-
-	router_a->rou_rflag = 1;
-
-	for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
-		if (router_a->rou_port[port].port_nasid == INVALID_NASID)
-			continue;
-
-		brd = (lboard_t *)NODE_OFFSET_TO_K0(
-			router_a->rou_port[port].port_nasid,
-			router_a->rou_port[port].port_offset);
-
-		if (brd->brd_type == KLTYPE_ROUTER) {
-			router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
-			if (router == router_b) {
-				if (depth < router_distance)
-					router_distance = depth;
-			}
-			else
-				router_recurse(router, router_b, depth + 1);
-		}
-	}
-
-	router_a->rou_rflag = 0;
-}
-
-int
-node_distance(nasid_t nasid_a, nasid_t nasid_b)
-{
-	nasid_t nasid;
-	cnodeid_t cnode;
-	lboard_t *brd, *dest_brd;
-	int port;
-	klrou_t *router, *router_a = NULL, *router_b = NULL;
-
-	/* Figure out which routers nodes in question are connected to */
-	for (cnode = 0; cnode < numnodes; cnode++) {
-		nasid = COMPACT_TO_NASID_NODEID(cnode);
-
-		if (nasid == -1) continue;
-
-		brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
-					KLTYPE_ROUTER);
-
-		if (!brd)
-			continue;
-
-		do {
-			if (brd->brd_flags & DUPLICATE_BOARD)
-				continue;
-
-			router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
-			router->rou_rflag = 0;
-
-			for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
-				if (router->rou_port[port].port_nasid == INVALID_NASID)
-					continue;
-
-				dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
-					router->rou_port[port].port_nasid,
-					router->rou_port[port].port_offset);
-
-				if (dest_brd->brd_type == KLTYPE_IP27) {
-					if (dest_brd->brd_nasid == nasid_a)
-						router_a = router;
-					if (dest_brd->brd_nasid == nasid_b)
-						router_b = router;
-				}
-			}
-			
-		} while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
-	}
-
-	if (router_a == NULL) {
-		printk("node_distance: router_a NULL\n");
-		return -1;
-	}
-	if (router_b == NULL) {
-		printk("node_distance: router_b NULL\n");
-		return -1;
-	}
-
-	if (nasid_a == nasid_b)
-		return 0;
-
-	if (router_a == router_b)
-		return 1;
-
-	router_distance = 100;
-	router_recurse(router_a, router_b, 2);
-
-	return router_distance;
-}
-
-void
-init_topology_matrix(void)
-{
-	nasid_t nasid, nasid2;
-	cnodeid_t row, col;
-
-	for (row = 0; row < MAX_COMPACT_NODES; row++)
-		for (col = 0; col < MAX_COMPACT_NODES; col++)
-			node_distances[row][col] = -1;
-
-	for (row = 0; row < numnodes; row++) {
-		nasid = COMPACT_TO_NASID_NODEID(row);
-		for (col = 0; col < numnodes; col++) {
-			nasid2 = COMPACT_TO_NASID_NODEID(col);
-			node_distances[row][col] = node_distance(nasid, nasid2);
-		}
-	}
-}
-
-void
-dump_topology(void)
-{
-	nasid_t nasid;
-	cnodeid_t cnode;
-	lboard_t *brd, *dest_brd;
-	int port;
-	int router_num = 0;
-	klrou_t *router;
-	cnodeid_t row, col;
-
-	printk("************** Topology ********************\n");
-
-	printk("    ");
-	for (col = 0; col < numnodes; col++)
-		printk("%02d ", col);
-	printk("\n");
-	for (row = 0; row < numnodes; row++) {
-		printk("%02d  ", row);
-		for (col = 0; col < numnodes; col++)
-			printk("%2d ", node_distances[row][col]);
-		printk("\n");
-	}
-
-	for (cnode = 0; cnode < numnodes; cnode++) {
-		nasid = COMPACT_TO_NASID_NODEID(cnode);
-
-		if (nasid == -1) continue;
-
-		brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
-					KLTYPE_ROUTER);
-
-		if (!brd)
-			continue;
-
-		do {
-			if (brd->brd_flags & DUPLICATE_BOARD)
-				continue;
-			printk("Router %d:", router_num);
-			router_num++;
-
-			router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
-
-			for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
-				if (router->rou_port[port].port_nasid == INVALID_NASID)
-					continue;
-
-				dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
-					router->rou_port[port].port_nasid,
-					router->rou_port[port].port_offset);
-
-				if (dest_brd->brd_type == KLTYPE_IP27)
-					printk(" %d", dest_brd->brd_nasid);
-				if (dest_brd->brd_type == KLTYPE_ROUTER)
-					printk(" r");
-			}
-			printk("\n");
-			
-		} while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
-	}
-}
-
-#if 0
-#define		brd_widgetnum	brd_slot
-#define NODE_OFFSET_TO_KLINFO(n,off)    ((klinfo_t*) TO_NODE_CAC(n,off))
-void
-dump_klcfg(void)
-{
-	cnodeid_t       cnode;
-	int i;
-	nasid_t         nasid;
-	lboard_t        *lbptr;
-	gda_t           *gdap;
-	
-	gdap = (gda_t *)GDA_ADDR(get_nasid());
-	if (gdap->g_magic != GDA_MAGIC) {
-		printk("dumpklcfg_cmd: Invalid GDA MAGIC\n");
-		return;
-	}
-
-	for (cnode = 0; cnode < MAX_COMPACT_NODES; cnode ++) {
-		nasid = gdap->g_nasidtable[cnode];
-
-		if (nasid == INVALID_NASID)
-			continue;
-
-		printk("\nDumpping klconfig Nasid %d:\n", nasid);
-	
-		lbptr = KL_CONFIG_INFO(nasid);
-
-		while (lbptr) {
-			printk("    %s, Nasid %d, Module %d, widget 0x%x, partition %d, NIC 0x%x lboard 0x%lx",
-				"board name here", /* BOARD_NAME(lbptr->brd_type), */
-				lbptr->brd_nasid, lbptr->brd_module, 
-				lbptr->brd_widgetnum,
-				lbptr->brd_partition, 
-				(lbptr->brd_nic), lbptr);
-			if (lbptr->brd_flags & DUPLICATE_BOARD)
-				printk(" -D");
-			printk("\n");
-			for (i = 0; i < lbptr->brd_numcompts; i++) {
-				klinfo_t *kli;
-				kli = NODE_OFFSET_TO_KLINFO(NASID_GET(lbptr), lbptr->brd_compts[i]);                       
-				printk("        type %2d, flags 0x%04x, diagval %3d, physid %4d, virtid %2d: %s\n", 
-					kli->struct_type, 
-					kli->flags,
-					kli->diagval,
-					kli->physid,
-					kli->virtid,
-					"comp. name here");
-					/* COMPONENT_NAME(kli->struct_type)); */
-			}
-			lbptr = KLCF_NEXT(lbptr);
-		}
-	}
-	printk("\n");
-
-	/* Useful to print router maps also */
-
-	for (cnode = 0; cnode < MAX_COMPACT_NODES; cnode ++) {
-		klrou_t *kr;
-		int i;
-
-        	nasid = gdap->g_nasidtable[cnode];
-        	if (nasid == INVALID_NASID)
-            		continue;
-        	lbptr = KL_CONFIG_INFO(nasid);
-
-        	while (lbptr) {
-			
-			lbptr = find_lboard_class(lbptr, KLCLASS_ROUTER);
-			if(!lbptr)
-				break;
-			if (!KL_CONFIG_DUPLICATE_BOARD(lbptr)) {
-				printk("%llx -> \n", lbptr->brd_nic);
-				kr = (klrou_t *)find_first_component(lbptr,
-					KLSTRUCT_ROU);
-				for (i = 1; i <= MAX_ROUTER_PORTS; i++) {
-					printk("[%d, %llx]; ",
-						kr->rou_port[i].port_nasid,
-						kr->rou_port[i].port_offset);
-				}
-				printk("\n");
-			}
-			lbptr = KLCF_NEXT(lbptr);
-        	}
-        	printk("\n");
-    	}
-
-	dump_topology();
-}
-#endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/ip27-irq-glue.S linux-2.4.20/arch/mips64/sgi-ip27/ip27-irq-glue.S
--- linux-2.4.19/arch/mips64/sgi-ip27/ip27-irq-glue.S	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/ip27-irq-glue.S	1970-01-01 00:00:00.000000000 +0000
@@ -1,64 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1999 Ralf Baechle
- * Copyright (C) 1999 Silicon Graphics, Inc.
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
-	.text
-	.set	noat
-	.align	5
-NESTED(ip27_irq, PT_SIZE, sp)
-	SAVE_ALL
-	CLI
-	.set	at
-
-	/* IP27 may signal interrupt which we're not interested in.
-	   Mask them out.  */
-	mfc0	s0, CP0_CAUSE
-	mfc0	t0, CP0_STATUS
-	and	s0, t0
-
-	/* First check for RT interrupt.  */
-	andi	a0, s0, CAUSEF_IP4
-	beqz	a0, 1f
-
-	/* Ok, a timer interrupt. */
-	move	a0, sp
-	jal	rt_timer_interrupt
-
-	j	ret_from_irq
-
-1:	andi	a0, s0, (CAUSEF_IP2 | CAUSEF_IP3)
-	beqz	a0, 1f
-
-	/* ... a device interrupt ...  */
-	move	a0, sp
-	jal	ip27_do_irq
-
-	j	ret_from_irq
-
-1:
-#if 1
-	mfc0	a1, CP0_STATUS
-	srl	a1, a1, 8
-	andi	a1, 0xff
-
-	mfc0	a2, CP0_CAUSE
-	srl	a2, a2, 8
-	andi	a2, 0xff
-
-	move	a3, s0
-	PRINT("Spurious interrupt, c0_status = %02x, c0_cause = %02x, pending %02x.\n")
-	ld	a1, PT_EPC(sp)
-0:	b	0b
-#endif
-
-	j	ret_from_irq
-	END(ip27_irq)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/ip27-irq.c linux-2.4.20/arch/mips64/sgi-ip27/ip27-irq.c
--- linux-2.4.19/arch/mips64/sgi-ip27/ip27-irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/ip27-irq.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,487 +0,0 @@
-/*
- * ip27-irq.c: Highlevel interrupt handling for IP27 architecture.
- *
- * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- * Copyright (C) 1999 - 2001 Kanoj Sarcar
- */
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/smp_lock.h>
-#include <linux/kernel_stat.h>
-#include <linux/delay.h>
-
-#include <asm/bitops.h>
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/mipsregs.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-
-#include <asm/ptrace.h>
-#include <asm/processor.h>
-#include <asm/pci/bridge.h>
-#include <asm/sn/sn0/hub.h>
-#include <asm/sn/sn0/ip27.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/agent.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/intr_public.h>
-
-
-#undef DEBUG_IRQ
-#ifdef DEBUG_IRQ
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-/* These should die */
-unsigned char bus_to_wid[256];	/* widget id for linux pci bus */
-unsigned char bus_to_nid[256];	/* nasid for linux pci bus */
-unsigned char num_bridges;	/* number of bridges in the system */
-
-/*
- * Linux has a controller-independent x86 interrupt architecture.
- * every controller has a 'controller-template', that is used
- * by the main code to do the right thing. Each driver-visible
- * interrupt source is transparently wired to the apropriate
- * controller. Thus drivers need not be aware of the
- * interrupt-controller.
- *
- * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
- * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
- * (IO-APICs assumed to be messaging to Pentium local-APICs)
- *
- * the code is designed to be easily extended with new/different
- * interrupt controllers, without having to do assembly magic.
- */
-
-extern asmlinkage void ip27_irq(void);
-extern void do_IRQ(int irq, struct pt_regs *regs);
-
-extern int irq_to_bus[], irq_to_slot[], bus_to_cpu[];
-int intr_connect_level(int cpu, int bit);
-int intr_disconnect_level(int cpu, int bit);
-
-/*
- * There is a single intpend register per node, and we want to have
- * distinct levels for intercpu intrs for both cpus A and B on a node.
- */
-int node_level_to_irq[MAX_COMPACT_NODES][PERNODE_LEVELS];
-
-/*
- * use these macros to get the encoded nasid and widget id
- * from the irq value
- */
-#define IRQ_TO_BUS(i)			irq_to_bus[(i)]
-#define IRQ_TO_CPU(i)			bus_to_cpu[IRQ_TO_BUS(i)]
-#define NASID_FROM_PCI_IRQ(i)		bus_to_nid[IRQ_TO_BUS(i)]
-#define WID_FROM_PCI_IRQ(i)		bus_to_wid[IRQ_TO_BUS(i)]
-#define	SLOT_FROM_PCI_IRQ(i)		irq_to_slot[i]
-
-static inline int alloc_level(cpuid_t cpunum, int irq)
-{
-	cnodeid_t nodenum = CPUID_TO_COMPACT_NODEID(cpunum);
-	int j = LEAST_LEVEL + 3;	/* resched & crosscall entries taken */
-
-	while (++j < PERNODE_LEVELS) {
-		if (node_level_to_irq[nodenum][j] == -1) {
-			node_level_to_irq[nodenum][j] = irq;
-			return j;
-		}
-	}
-	printk("Cpu %ld flooded with devices\n", cpunum);
-	while(1);
-	return -1;
-}
-
-static inline int find_level(cpuid_t *cpunum, int irq)
-{
-	int j;
-	cnodeid_t nodenum = INVALID_CNODEID;
-
-	while (++nodenum < MAX_COMPACT_NODES) {
-		j = LEAST_LEVEL + 3;	/* resched & crosscall entries taken */
-		while (++j < PERNODE_LEVELS)
-			if (node_level_to_irq[nodenum][j] == irq) {
-				*cpunum = 0;	/* XXX Fixme */
-				return(j);
-			}
-	}
-	printk("Could not identify cpu/level for irq %d\n", irq);
-	while(1);
-	return(-1);
-}
-
-/*
- * Find first bit set
- */
-static int ms1bit(unsigned long x)
-{
-	int b = 0, s;
-
-	s = 16; if (x >> 16 == 0) s = 0; b += s; x >>= s;
-	s =  8; if (x >>  8 == 0) s = 0; b += s; x >>= s;
-	s =  4; if (x >>  4 == 0) s = 0; b += s; x >>= s;
-	s =  2; if (x >>  2 == 0) s = 0; b += s; x >>= s;
-	s =  1; if (x >>  1 == 0) s = 0; b += s;
-
-	return b;
-}
-
-/*
- * This code is unnecessarily complex, because we do SA_INTERRUPT
- * intr enabling. Basically, once we grab the set of intrs we need
- * to service, we must mask _all_ these interrupts; firstly, to make
- * sure the same intr does not intr again, causing recursion that 
- * can lead to stack overflow. Secondly, we can not just mask the
- * one intr we are do_IRQing, because the non-masked intrs in the
- * first set might intr again, causing multiple servicings of the
- * same intr. This effect is mostly seen for intercpu intrs.
- * Kanoj 05.13.00
- */
-void ip27_do_irq(struct pt_regs *regs)
-{
-	int irq, swlevel;
-	hubreg_t pend0, mask0;
-	cpuid_t thiscpu = smp_processor_id();
-	int pi_int_mask0 = ((cputoslice(thiscpu) == 0) ?
-					PI_INT_MASK0_A : PI_INT_MASK0_B);
-
-	/* copied from Irix intpend0() */
-	while (((pend0 = LOCAL_HUB_L(PI_INT_PEND0)) & 
-				(mask0 = LOCAL_HUB_L(pi_int_mask0))) != 0) {
-		pend0 &= mask0;		/* Pick intrs we should look at */
-		if (pend0) {
-			/* Prevent any of the picked intrs from recursing */
-			LOCAL_HUB_S(pi_int_mask0, mask0 & ~(pend0));
-			do {
-				swlevel = ms1bit(pend0);
-				LOCAL_HUB_CLR_INTR(swlevel);
-				/* "map" swlevel to irq */
-				irq = LEVEL_TO_IRQ(thiscpu, swlevel);
-				do_IRQ(irq, regs);
-				/* clear bit in pend0 */
-				pend0 ^= 1ULL << swlevel;
-			} while(pend0);
-			/* Now allow the set of serviced intrs again */
-			LOCAL_HUB_S(pi_int_mask0, mask0);
-			LOCAL_HUB_L(PI_INT_PEND0);
-		}
-	}
-}
-
-
-/* Startup one of the (PCI ...) IRQs routes over a bridge.  */
-static unsigned int startup_bridge_irq(unsigned int irq)
-{
-	bridgereg_t device;
-	bridge_t *bridge;
-	int pin, swlevel;
-	cpuid_t cpu;
-	nasid_t master = NASID_FROM_PCI_IRQ(irq);
-
-	if (irq < BASE_PCI_IRQ)
-		return 0;
-
-        bridge = (bridge_t *) NODE_SWIN_BASE(master, WID_FROM_PCI_IRQ(irq));
-	pin = SLOT_FROM_PCI_IRQ(irq);
-	cpu = IRQ_TO_CPU(irq);
-
-	DBG("bridge_startup(): irq= 0x%x  pin=%d\n", irq, pin);
-	/*
-	 * "map" irq to a swlevel greater than 6 since the first 6 bits
-	 * of INT_PEND0 are taken
-	 */
-	swlevel = alloc_level(cpu, irq);
-	intr_connect_level(cpu, swlevel);
-
-	bridge->b_int_addr[pin].addr = (0x20000 | swlevel | (master << 8));
-	bridge->b_int_enable |= (1 << pin);
-	/* more stuff in int_enable reg */
-	bridge->b_int_enable |= 0x7ffffe00;
-
-	/*
-	 * XXX This only works if b_int_device is initialized to 0!
-	 * We program the bridge to have a 1:1 mapping between devices
-	 * (slots) and intr pins.
-	 */
-	device = bridge->b_int_device;
-	device |= (pin << (pin*3));
-	bridge->b_int_device = device;
-
-        bridge->b_widget.w_tflush;                      /* Flush */
-
-        return 0;       /* Never anything pending.  */
-}
-
-/* Shutdown one of the (PCI ...) IRQs routes over a bridge.  */
-static unsigned int shutdown_bridge_irq(unsigned int irq)
-{
-	bridge_t *bridge;
-	int pin, swlevel;
-	cpuid_t cpu;
-
-	if (irq < BASE_PCI_IRQ)
-		return 0;
-
-	bridge = (bridge_t *) NODE_SWIN_BASE(NASID_FROM_PCI_IRQ(irq), 
-	                                     WID_FROM_PCI_IRQ(irq));
-	DBG("bridge_shutdown: irq 0x%x\n", irq);
-	pin = SLOT_FROM_PCI_IRQ(irq);
-
-	/*
-	 * map irq to a swlevel greater than 6 since the first 6 bits
-	 * of INT_PEND0 are taken
-	 */
-	swlevel = find_level(&cpu, irq);
-	intr_disconnect_level(cpu, swlevel);
-	LEVEL_TO_IRQ(cpu, swlevel) = -1;
-
-	bridge->b_int_enable &= ~(1 << pin);
-	bridge->b_widget.w_tflush;                      /* Flush */
-
-	return 0;       /* Never anything pending.  */
-}
-
-static inline void enable_bridge_irq(unsigned int irq)
-{
-	/* All the braindamage happens magically for us in ip27_do_irq */
-}
-
-static void disable_bridge_irq(unsigned int irq)
-{
-	/* All the braindamage happens magically for us in ip27_do_irq */
-}
-
-static void mask_and_ack_bridge_irq(unsigned int irq)
-{
-	/* All the braindamage happens magically for us in ip27_do_irq */
-}
-
-static void end_bridge_irq (unsigned int irq)
-{
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-		enable_bridge_irq(irq);
-}
-
-static struct hw_interrupt_type bridge_irq_type = {
-	"bridge",
-	startup_bridge_irq,
-	shutdown_bridge_irq,
-	enable_bridge_irq,
-	disable_bridge_irq,
-	mask_and_ack_bridge_irq,
-	end_bridge_irq
-};
-
-void irq_debug(void)
-{
-	bridge_t *bridge = (bridge_t *) 0x9200000008000000;
-
-	printk("bridge->b_int_status = 0x%x\n", bridge->b_int_status);
-	printk("bridge->b_int_enable = 0x%x\n", bridge->b_int_enable);
-	printk("PI_INT_PEND0   = 0x%lx\n", LOCAL_HUB_L(PI_INT_PEND0));
-	printk("PI_INT_MASK0_A = 0x%lx\n", LOCAL_HUB_L(PI_INT_MASK0_A));
-}
-
-void __init init_IRQ(void)
-{
-	int i;
-
-	set_except_vector(0, ip27_irq);
-
-	/*
-	 * Right now the bridge irq is our kitchen sink interrupt type
-	 */
-	for (i = 0; i <= NR_IRQS; i++) {
-		irq_desc[i].status	= IRQ_DISABLED;
-		irq_desc[i].action	= 0;
-		irq_desc[i].depth	= 1;
-		irq_desc[i].handler	= &bridge_irq_type;
-	}
-}
-
-/*
- * Get values that vary depending on which CPU and bit we're operating on.
- */
-static hub_intmasks_t *intr_get_ptrs(cpuid_t cpu, int bit, int *new_bit,
-				hubreg_t **intpend_masks, int *ip)
-{
-	hub_intmasks_t *hub_intmasks;
-
-	hub_intmasks = &cpu_data[cpu].p_intmasks;
-	if (bit < N_INTPEND_BITS) {
-		*intpend_masks = hub_intmasks->intpend0_masks;
-		*ip = 0;
-		*new_bit = bit;
-	} else {
-		*intpend_masks = hub_intmasks->intpend1_masks;
-		*ip = 1;
-		*new_bit = bit - N_INTPEND_BITS;
-	}
-	return hub_intmasks;
-}
-
-int intr_connect_level(int cpu, int bit)
-{
-	int ip;
-	int slice = cputoslice(cpu);
-	volatile hubreg_t *mask_reg;
-	hubreg_t *intpend_masks;
-	nasid_t nasid = COMPACT_TO_NASID_NODEID(cputocnode(cpu));
-
-	(void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks, &ip);
-
-	/* Make sure it's not already pending when we connect it. */
-	REMOTE_HUB_CLR_INTR(nasid, bit + ip * N_INTPEND_BITS);
-
-	intpend_masks[0] |= (1ULL << (u64)bit);
-
-	if (ip == 0) {
-		mask_reg = REMOTE_HUB_ADDR(nasid, PI_INT_MASK0_A + 
-				PI_INT_MASK_OFFSET * slice);
-	} else {
-		mask_reg = REMOTE_HUB_ADDR(nasid, PI_INT_MASK1_A + 
-				PI_INT_MASK_OFFSET * slice);
-	}
-	HUB_S(mask_reg, intpend_masks[0]);
-	return(0);
-}
-
-int intr_disconnect_level(int cpu, int bit)
-{
-	int ip;
-	int slice = cputoslice(cpu);
-	volatile hubreg_t *mask_reg;
-	hubreg_t *intpend_masks;
-	nasid_t nasid = COMPACT_TO_NASID_NODEID(cputocnode(cpu));
-
-	(void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks, &ip);
-	intpend_masks[0] &= ~(1ULL << (u64)bit);
-	if (ip == 0) {
-		mask_reg = REMOTE_HUB_ADDR(nasid, PI_INT_MASK0_A + 
-				PI_INT_MASK_OFFSET * slice);
-	} else {
-		mask_reg = REMOTE_HUB_ADDR(nasid, PI_INT_MASK1_A + 
-				PI_INT_MASK_OFFSET * slice);
-	}
-	HUB_S(mask_reg, intpend_masks[0]);
-	return(0);
-}
-
-
-void handle_resched_intr(int irq, void *dev_id, struct pt_regs *regs)
-{
-	/* Nothing, the return from intr will work for us */
-}
-
-#ifdef CONFIG_SMP
-
-void core_send_ipi(int destid, unsigned int action)
-{
-	int irq;
-
-#if (CPUS_PER_NODE == 2)
-	switch (action) {
-		case SMP_RESCHEDULE_YOURSELF:
-			irq = CPU_RESCHED_A_IRQ;
-			break;
-		case SMP_CALL_FUNCTION:
-			irq = CPU_CALL_A_IRQ;
-			break;
-		default:
-			panic("sendintr");
-	}
-	irq += cputoslice(destid);
-
-	/*
-	 * Convert the compact hub number to the NASID to get the correct
-	 * part of the address space.  Then set the interrupt bit associated
-	 * with the CPU we want to send the interrupt to.
-	 */
-	REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cputocnode(destid)),
-			FAST_IRQ_TO_LEVEL(irq));
-#else
-	<< Bomb!  Must redefine this for more than 2 CPUS. >>
-#endif
-}
-
-#endif
-
-extern void smp_call_function_interrupt(void);
-
-void install_cpuintr(int cpu)
-{
-#ifdef CONFIG_SMP
-#if (CPUS_PER_NODE == 2)
-	static int done = 0;
-
-	/*
-	 * This is a hack till we have a pernode irqlist. Currently,
-	 * just have the master cpu set up the handlers for the per
-	 * cpu irqs.
-	 */
-	if (done == 0) {
-		int j;
-
-		if (request_irq(CPU_RESCHED_A_IRQ, handle_resched_intr, 
-							0, "resched", 0))
-			panic("intercpu intr unconnectible");
-		if (request_irq(CPU_RESCHED_B_IRQ, handle_resched_intr, 
-							0, "resched", 0))
-			panic("intercpu intr unconnectible");
-		if (request_irq(CPU_CALL_A_IRQ, smp_call_function_interrupt,
-							0, "callfunc", 0))
-			panic("intercpu intr unconnectible");
-		if (request_irq(CPU_CALL_B_IRQ, smp_call_function_interrupt,
-							0, "callfunc", 0))
-			panic("intercpu intr unconnectible");
-
-		for (j = 0; j < PERNODE_LEVELS; j++)
-			LEVEL_TO_IRQ(0, j) = -1;
-		LEVEL_TO_IRQ(0, FAST_IRQ_TO_LEVEL(CPU_RESCHED_A_IRQ)) = 
-							CPU_RESCHED_A_IRQ;
-		LEVEL_TO_IRQ(0, FAST_IRQ_TO_LEVEL(CPU_RESCHED_B_IRQ)) = 
-							CPU_RESCHED_B_IRQ;
-		LEVEL_TO_IRQ(0, FAST_IRQ_TO_LEVEL(CPU_CALL_A_IRQ)) = 
-							CPU_CALL_A_IRQ;
-		LEVEL_TO_IRQ(0, FAST_IRQ_TO_LEVEL(CPU_CALL_B_IRQ)) = 
-							CPU_CALL_B_IRQ;
-		for (j = 1; j < MAX_COMPACT_NODES; j++)
-			memcpy(&node_level_to_irq[j][0], 
-			&node_level_to_irq[0][0], 
-			sizeof(node_level_to_irq[0][0])*PERNODE_LEVELS);
-
-		done = 1;
-	}
-
-	intr_connect_level(cpu, FAST_IRQ_TO_LEVEL(CPU_RESCHED_A_IRQ + 
-							cputoslice(cpu)));
-	intr_connect_level(cpu, FAST_IRQ_TO_LEVEL(CPU_CALL_A_IRQ +
-							cputoslice(cpu)));
-#else /* CPUS_PER_NODE */
-#error Must redefine this for more than 2 CPUS.
-#endif /* CPUS_PER_NODE */
-#endif /* CONFIG_SMP */
-}
-
-void install_tlbintr(int cpu)
-{
-#if 0
-	int intr_bit = N_INTPEND_BITS + TLB_INTR_A + cputoslice(cpu);
-
-	intr_connect_level(cpu, intr_bit);
-#endif
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/ip27-klconfig.c linux-2.4.20/arch/mips64/sgi-ip27/ip27-klconfig.c
--- linux-2.4.19/arch/mips64/sgi-ip27/ip27-klconfig.c	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/ip27-klconfig.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/param.h>
-#include <linux/timex.h>
-#include <linux/mm.h>		
-
-#include <asm/sn/klconfig.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/gda.h>
-
-klinfo_t *find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type)
-{
-	int index, j;
-
-	if (kli == (klinfo_t *)NULL) {
-		index = 0;
-	} else {
-		for (j = 0; j < KLCF_NUM_COMPS(brd); j++)
-			if (kli == KLCF_COMP(brd, j))
-				break;
-		index = j;
-		if (index == KLCF_NUM_COMPS(brd)) {
-			printk("find_component: Bad pointer: 0x%p\n", kli);
-			return (klinfo_t *)NULL;
-		}
-		index++;		/* next component */
-	}
-
-	for (; index < KLCF_NUM_COMPS(brd); index++) {
-		kli = KLCF_COMP(brd, index);
-		if (KLCF_COMP_TYPE(kli) == struct_type)
-			return kli;
-	}
-
-	/* Didn't find it. */
-	return (klinfo_t *)NULL;
-}
-
-klinfo_t *find_first_component(lboard_t *brd, unsigned char struct_type)
-{
-	return find_component(brd, (klinfo_t *)NULL, struct_type);
-}
-
-lboard_t * find_lboard(lboard_t *start, unsigned char brd_type)
-{
-	/* Search all boards stored on this node. */
-	while (start) {
-		if (start->brd_type == brd_type)
-			return start;
-		start = KLCF_NEXT(start);
-	}
-	/* Didn't find it. */
-	return (lboard_t *)NULL;
-}
-
-lboard_t * find_lboard_class(lboard_t *start, unsigned char brd_type)
-{
-	/* Search all boards stored on this node. */
-	while (start) {
-		if (KLCLASS(start->brd_type) == KLCLASS(brd_type))
-			return start;
-		start = KLCF_NEXT(start);
-	}
-
-	/* Didn't find it. */
-	return (lboard_t *)NULL;
-}
-
-cnodeid_t get_cpu_cnode(cpuid_t cpu)
-{
-	return CPUID_TO_COMPACT_NODEID(cpu);
-}
-
-klcpu_t * nasid_slice_to_cpuinfo(nasid_t nasid, int slice)
-{
-	lboard_t *brd;
-	klcpu_t *acpu;
-
-	if (!(brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27)))
-		return (klcpu_t *)NULL;
-
-	if (!(acpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU)))
-		return (klcpu_t *)NULL;
-
-	do {
-		if ((acpu->cpu_info.physid) == slice)
-			return acpu;
-	} while ((acpu = (klcpu_t *)find_component(brd, (klinfo_t *)acpu, 
-								KLSTRUCT_CPU)));
-	return (klcpu_t *)NULL;
-}
-
-klcpu_t * sn_get_cpuinfo(cpuid_t cpu)
-{
-	nasid_t nasid;
-	int slice;
-	klcpu_t *acpu;
-	gda_t *gdap = GDA;
-	cnodeid_t cnode;
-
-	if (!(cpu < MAXCPUS)) {
-		printk("sn_get_cpuinfo: illegal cpuid 0x%lx\n", cpu);
-		return NULL;
-	}
-
-	cnode = get_cpu_cnode(cpu);
-	if (cnode == INVALID_CNODEID)
-		return NULL;
-
-	if ((nasid = gdap->g_nasidtable[cnode]) == INVALID_NASID)
-		return NULL;
-
-	for (slice = 0; slice < CPUS_PER_NODE; slice++) {
-		acpu = nasid_slice_to_cpuinfo(nasid, slice);
-		if (acpu && acpu->cpu_info.virtid == cpu)
-			return acpu;
-	}
-	return NULL;
-}
-
-int get_cpu_slice(cpuid_t cpu)
-{
-	klcpu_t *acpu;
-
-	if ((acpu = sn_get_cpuinfo(cpu)) == NULL)
-		return -1;
-	return acpu->cpu_info.physid;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/ip27-klnuma.c linux-2.4.20/arch/mips64/sgi-ip27/ip27-klnuma.c
--- linux-2.4.19/arch/mips64/sgi-ip27/ip27-klnuma.c	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/ip27-klnuma.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,143 +0,0 @@
-/*
- * Ported from IRIX to Linux by Kanoj Sarcar, 06/08/00.
- * Copyright 2000 - 2001 Silicon Graphics, Inc.
- * Copyright 2000 - 2001 Kanoj Sarcar (kanoj@sgi.com)
- */
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/mmzone.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-
-#include <asm/page.h>
-#include <asm/smp.h>
-#include <asm/sn/types.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/gda.h>
-#include <asm/mmzone.h>
-#include <asm/sn/klkernvars.h>
-#include <asm/sn/mapped_kernel.h>
-#include <asm/sn/sn_private.h>
-
-extern char _end;
-static cpumask_t ktext_repmask;
-
-/*
- * XXX - This needs to be much smarter about where it puts copies of the
- * kernel.  For example, we should never put a copy on a headless node,
- * and we should respect the topology of the machine.
- */
-void __init setup_replication_mask(int maxnodes)
-{
-	static int 	numa_kernel_replication_ratio;
-	cnodeid_t	cnode;
-
-	/* Set only the master cnode's bit.  The master cnode is always 0. */
-	CPUMASK_CLRALL(ktext_repmask);
-	CPUMASK_SETB(ktext_repmask, 0);
-
-	numa_kernel_replication_ratio = 0;
-#ifdef CONFIG_REPLICATE_KTEXT
-#ifndef CONFIG_MAPPED_KERNEL
-#error Kernel replication works with mapped kernel support. No calias support.
-#endif
-	numa_kernel_replication_ratio = 1;
-#endif
-
-	for (cnode = 1; cnode < numnodes; cnode++) {
-		/* See if this node should get a copy of the kernel */
-		if (numa_kernel_replication_ratio &&
-		    !(cnode % numa_kernel_replication_ratio)) {
-
-			/* Advertise that we have a copy of the kernel */
-			CPUMASK_SETB(ktext_repmask, cnode);
-		}
-	}
-
-	/* Set up a GDA pointer to the replication mask. */
-	GDA->g_ktext_repmask = &ktext_repmask;
-}
-
-
-static __init void set_ktext_source(nasid_t client_nasid, nasid_t server_nasid)
-{
-	kern_vars_t *kvp;
-	cnodeid_t client_cnode;
-
-	client_cnode = NASID_TO_COMPACT_NODEID(client_nasid);
-	
-	kvp = &(PLAT_NODE_DATA(client_cnode)->kern_vars);
-
-	KERN_VARS_ADDR(client_nasid) = (unsigned long)kvp;
-
-	kvp->kv_magic = KV_MAGIC;
-
-	kvp->kv_ro_nasid = server_nasid;
-	kvp->kv_rw_nasid = master_nasid;
-	kvp->kv_ro_baseaddr = NODE_CAC_BASE(server_nasid);
-	kvp->kv_rw_baseaddr = NODE_CAC_BASE(master_nasid);
-	printk("REPLICATION: ON nasid %d, ktext from nasid %d, kdata from nasid %d\n", client_nasid, server_nasid, master_nasid);
-}
-
-/* XXX - When the BTE works, we should use it instead of this. */
-static __init void copy_kernel(nasid_t dest_nasid)
-{
-	extern char _stext, _etext;
-	unsigned long dest_kern_start, source_start, source_end, kern_size;
-
-	source_start = (unsigned long)&_stext;
-	source_end = (unsigned long)&_etext;
-	kern_size = source_end - source_start;
-
-	dest_kern_start = CHANGE_ADDR_NASID(MAPPED_KERN_RO_TO_K0(source_start),
-					    dest_nasid);
-	memcpy((void *)dest_kern_start, (void *)source_start, kern_size);
-}
-
-void __init replicate_kernel_text(int maxnodes)
-{
-	cnodeid_t cnode;
-	nasid_t client_nasid;
-	nasid_t server_nasid;
-
-	server_nasid = master_nasid;
-
-	/* Record where the master node should get its kernel text */
-	set_ktext_source(master_nasid, master_nasid);
-
-	for (cnode = 1; cnode < maxnodes; cnode++) {
-		client_nasid = COMPACT_TO_NASID_NODEID(cnode);
-
-		/* Check if this node should get a copy of the kernel */
-		if (CPUMASK_TSTB(ktext_repmask, cnode)) {
-			server_nasid = client_nasid;
-			copy_kernel(server_nasid);
-		}
-
-		/* Record where this node should get its kernel text */
-		set_ktext_source(client_nasid, server_nasid);
-	}
-}
-
-/*
- * Return pfn of first free page of memory on a node. PROM may allocate
- * data structures on the first couple of pages of the first slot of each 
- * node. If this is the case, getfirstfree(node) > getslotstart(node, 0).
- */
-pfn_t node_getfirstfree(cnodeid_t cnode)
-{
-	unsigned long loadbase = CKSEG0;
-	nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
-	unsigned long offset;
-
-#ifdef CONFIG_MAPPED_KERNEL
-	loadbase = CKSSEG + 16777216;
-#endif
-	offset = PAGE_ALIGN((unsigned long)(&_end)) - loadbase;
-	if ((cnode == 0) || (CPUMASK_TSTB(ktext_repmask, cnode)))
-		return (TO_NODE(nasid, offset) >> PAGE_SHIFT);
-	else
-		return (KDM_TO_PHYS(PAGE_ALIGN(SYMMON_STK_ADDR(nasid, 0))) >> 
-								PAGE_SHIFT);
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/ip27-memory.c linux-2.4.20/arch/mips64/sgi-ip27/ip27-memory.c
--- linux-2.4.19/arch/mips64/sgi-ip27/ip27-memory.c	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/ip27-memory.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,344 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000 by Ralf Baechle
- * Copyright (C) 2000 by Silicon Graphics, Inc.
- *
- * On SGI IP27 the ARC memory configuration data is completly bogus but
- * alternate easier to use mechanisms are available.
- */
-#include <linux/init.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <linux/swap.h>
-
-#include <asm/page.h>
-#include <asm/bootinfo.h>
-#include <asm/addrspace.h>
-#include <asm/pgtable.h>
-#include <asm/pgalloc.h>
-#include <asm/sn/types.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/arch.h>
-#include <asm/mmzone.h>
-
-/* ip27-klnuma.c   */
-extern pfn_t node_getfirstfree(cnodeid_t cnode);
-
-#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define SLOT_IGNORED	0xffff
-
-short slot_lastfilled_cache[MAX_COMPACT_NODES];
-unsigned short slot_psize_cache[MAX_COMPACT_NODES][MAX_MEM_SLOTS];
-static pfn_t numpages;
-
-plat_pg_data_t *plat_node_data[MAX_COMPACT_NODES];
-bootmem_data_t plat_node_bdata[MAX_COMPACT_NODES];
-
-int numa_debug(void)
-{
-	printk("NUMA debug\n");
-	*(int *)0 = 0;
-	return(0);
-}
-
-/*
- * Return the number of pages of memory provided by the given slot
- * on the specified node.
- */
-pfn_t slot_getsize(cnodeid_t node, int slot)
-{
-	return (pfn_t) slot_psize_cache[node][slot];
-}
-
-/*
- * Return highest slot filled
- */
-int node_getlastslot(cnodeid_t node)
-{
-	return (int) slot_lastfilled_cache[node];
-}
-
-/*
- * Return the pfn of the last free page of memory on a node.
- */
-pfn_t node_getmaxclick(cnodeid_t node)
-{
-	pfn_t	slot_psize;
-	int	slot;
-
-	/*
-	 * Start at the top slot. When we find a slot with memory in it,
-	 * that's the winner.
-	 */
-	for (slot = (node_getnumslots(node) - 1); slot >= 0; slot--) {
-		if ((slot_psize = slot_getsize(node, slot))) {
-			if (slot_psize == SLOT_IGNORED)
-				continue;
-			/* Return the basepfn + the slot size, minus 1. */
-			return slot_getbasepfn(node, slot) + slot_psize - 1;
-		}
-	}
-
-	/*
-	 * If there's no memory on the node, return 0. This is likely
-	 * to cause problems.
-	 */
-	return (pfn_t)0;
-}
-
-static pfn_t slot_psize_compute(cnodeid_t node, int slot)
-{
-	nasid_t nasid;
-	lboard_t *brd;
-	klmembnk_t *banks;
-	unsigned long size;
-
-	nasid = COMPACT_TO_NASID_NODEID(node);
-	/* Find the node board */
-	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
-	if (!brd)
-		return 0;
-
-	/* Get the memory bank structure */
-	banks = (klmembnk_t *)find_first_component(brd, KLSTRUCT_MEMBNK);
-	if (!banks)
-		return 0;
-
-	/* Size in _Megabytes_ */
-	size = (unsigned long)banks->membnk_bnksz[slot/4];
-
-	/* hack for 128 dimm banks */
-	if (size <= 128) {
-		if (slot%4 == 0) {
-			size <<= 20;		/* size in bytes */
-			return(size >> PAGE_SHIFT);
-		} else {
-			return 0;
-		}
-	} else {
-		size /= 4;
-		size <<= 20;
-		return(size >> PAGE_SHIFT);
-	}
-}
-
-pfn_t szmem(pfn_t fpage, pfn_t maxpmem)
-{
-	cnodeid_t node;
-	int slot, numslots;
-	pfn_t num_pages = 0, slot_psize;
-	pfn_t slot0sz = 0, nodebytes;	/* Hack to detect problem configs */
-	int ignore;
-
-	for (node = 0; node < numnodes; node++) {
-		numslots = node_getnumslots(node);
-		ignore = nodebytes = 0;
-		for (slot = 0; slot < numslots; slot++) {
-			slot_psize = slot_psize_compute(node, slot);
-			if (slot == 0) slot0sz = slot_psize;
-			/* 
-			 * We need to refine the hack when we have replicated
-			 * kernel text.
-			 */
-			nodebytes += SLOT_SIZE;
-			if ((nodebytes >> PAGE_SHIFT) * (sizeof(struct page)) >
-						(slot0sz << PAGE_SHIFT))
-				ignore = 1;
-			if (ignore && slot_psize) {
-				printk("Ignoring slot %d onwards on node %d\n",
-								slot, node);
-				slot_psize_cache[node][slot] = SLOT_IGNORED;
-				slot = numslots;
-				continue;
-			}
-			num_pages += slot_psize;
-			slot_psize_cache[node][slot] = 
-					(unsigned short) slot_psize;
-			if (slot_psize)
-				slot_lastfilled_cache[node] = slot;
-		}
-	}
-	if (maxpmem)
-		return((maxpmem > num_pages) ? num_pages : maxpmem);
-	else
-		return num_pages;
-}
-
-/*
- * Currently, the intranode memory hole support assumes that each slot
- * contains at least 32 MBytes of memory. We assume all bootmem data
- * fits on the first slot.
- */
-void __init prom_meminit(void)
-{
-	extern void mlreset(void);
-	cnodeid_t node;
-	pfn_t slot_firstpfn, slot_lastpfn, slot_freepfn;
-	unsigned long bootmap_size;
-	int node_datasz;
-
-	node_datasz = PFN_UP(sizeof(plat_pg_data_t));
-	mlreset();
-	numpages = szmem(0, 0);
-	for (node = (numnodes - 1); node >= 0; node--) {
-		slot_firstpfn = slot_getbasepfn(node, 0);
-		slot_lastpfn = slot_firstpfn + slot_getsize(node, 0);
-		slot_freepfn = node_getfirstfree(node);
-		/* Foll line hack for non discontigmem; remove once discontigmem
-		 * becomes the default. */
-		max_low_pfn = (slot_lastpfn - slot_firstpfn);
-
-		/*
-		 * Allocate the node data structure on the node first.
-		 */
-		plat_node_data[node] = (plat_pg_data_t *)(__va(slot_freepfn \
-							<< PAGE_SHIFT));
-		NODE_DATA(node)->bdata = plat_node_bdata + node;
-		slot_freepfn += node_datasz;
-	  	bootmap_size = init_bootmem_node(NODE_DATA(node), slot_freepfn, 
-						slot_firstpfn, slot_lastpfn);
-		free_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT, 
-				(slot_lastpfn - slot_firstpfn) << PAGE_SHIFT);
-		reserve_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
-		  ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size);
-	}
-	printk("Total memory probed : 0x%lx pages\n", numpages);
-}
-
-int __init page_is_ram(unsigned long pagenr)
-{
-        return 1;
-}
-
-void __init
-prom_free_prom_memory (void)
-{
-	/* We got nothing to free here ...  */
-}
-
-#ifdef CONFIG_DISCONTIGMEM
-
-static pfn_t pagenr = 0;
-
-void __init paging_init(void)
-{
-	pmd_t *pmd = kpmdtbl;
-	pte_t *pte = kptbl;
-
-	cnodeid_t node;
-	unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
-	int i;
-
-	/* Initialize the entire pgd.  */
-	pgd_init((unsigned long)swapper_pg_dir);
-	pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table);
-	memset((void *)invalid_pte_table, 0, sizeof(pte_t) * PTRS_PER_PTE);
-
-	/* This is for vmalloc  */
-	memset((void *)kptbl, 0, PAGE_SIZE << KPTBL_PAGE_ORDER);
-	memset((void *)kpmdtbl, 0, PAGE_SIZE);
-	pgd_set(swapper_pg_dir, kpmdtbl);
-	for (i = 0; i < (1 << KPTBL_PAGE_ORDER); pmd++,i++,pte+=PTRS_PER_PTE)
-		pmd_val(*pmd) = (unsigned long)pte;
-
-	for (node = 0; node < numnodes; node++) {
-		pfn_t start_pfn = slot_getbasepfn(node, 0);
-		pfn_t end_pfn = node_getmaxclick(node);
-
-		zones_size[ZONE_DMA] = end_pfn + 1 - start_pfn;
-		free_area_init_node(node, NODE_DATA(node), 0, zones_size, 
-						start_pfn << PAGE_SHIFT, 0);
-		if ((PLAT_NODE_DATA_STARTNR(node) + 
-					PLAT_NODE_DATA_SIZE(node)) > pagenr)
-			pagenr = PLAT_NODE_DATA_STARTNR(node) +
-					PLAT_NODE_DATA_SIZE(node);
-	}
-}
-
-void __init mem_init(void)
-{
-	extern char _stext, _etext, _fdata, _edata;
-	extern char __init_begin, __init_end;
-	extern unsigned long totalram_pages;
-	extern unsigned long setup_zero_pages(void);
-	cnodeid_t nid;
-	unsigned long tmp;
-	unsigned long codesize, datasize, initsize;
-	int slot, numslots;
-	struct page *pg, *pslot;
-	pfn_t pgnr;
-
-	num_physpages = numpages;	/* memory already sized by szmem */
-	max_mapnr = pagenr;		/* already found during paging_init */
-	high_memory = (void *) __va(max_mapnr << PAGE_SHIFT);
-
-	for (nid = 0; nid < numnodes; nid++) {
-
-		/*
-		 * Hack till free_area_init_core() zeroes free_pages
-		 */
-		for (tmp = 0; tmp < MAX_NR_ZONES; tmp++)
-			PLAT_NODE_DATA(nid)->gendata.node_zones[tmp].free_pages=0;
-		/*
-	 	 * This will free up the bootmem, ie, slot 0 memory.
-	 	 */
-		totalram_pages += free_all_bootmem_node(NODE_DATA(nid));
-
-		/*
-		 * We need to manually do the other slots.
-		 */
-		pg = NODE_DATA(nid)->node_mem_map + slot_getsize(nid, 0);
-		pgnr = PLAT_NODE_DATA_STARTNR(nid) + slot_getsize(nid, 0);
-		numslots = node_getlastslot(nid);
-		for (slot = 1; slot <= numslots; slot++) {
-			pslot = NODE_DATA(nid)->node_mem_map + 
-			   slot_getbasepfn(nid, slot) - slot_getbasepfn(nid, 0);
-
-			/*
-			 * Mark holes in previous slot. May also want to
-			 * free up the pages that hold the memmap entries.
-			 */
-			while (pg < pslot) {
-				pg++; pgnr++;
-			}
-
-			/*
-			 * Free valid memory in current slot.
-			 */
-			pslot += slot_getsize(nid, slot);
-			while (pg < pslot) {
-				if (!page_is_ram(pgnr))
-					continue;
-				ClearPageReserved(pg);
-				atomic_set(&pg->count, 1);
-				__free_page(pg);
-				totalram_pages++;
-				pg++; pgnr++;
-			}
-		}
-	}
-
-	totalram_pages -= setup_zero_pages();	/* This comes from node 0 */
-
-	codesize =  (unsigned long) &_etext - (unsigned long) &_stext;
-	datasize =  (unsigned long) &_edata - (unsigned long) &_fdata;
-	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
-	tmp = (unsigned long) nr_free_pages();
-	printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, "
-		"%ldk data, %ldk init)\n",
-		tmp << (PAGE_SHIFT-10),
-		num_physpages << (PAGE_SHIFT-10),
-		codesize >> 10,
-		(num_physpages - tmp) << (PAGE_SHIFT-10),
-		datasize >> 10,
-		initsize >> 10);
-}
-
-#endif /* CONFIG_DISCONTIGMEM */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/ip27-nmi.c linux-2.4.20/arch/mips64/sgi-ip27/ip27-nmi.c
--- linux-2.4.19/arch/mips64/sgi-ip27/ip27-nmi.c	2000-11-29 05:42:04.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/ip27-nmi.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,168 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/mmzone.h>
-#include <linux/spinlock.h>
-#include <linux/smp.h>
-#include <asm/atomic.h>
-#include <asm/sn/types.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/nmi.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/sn0/hub.h>
-
-#if 0
-#define NODE_NUM_CPUS(n)	CNODE_NUM_CPUS(n)
-#else
-#define NODE_NUM_CPUS(n)	CPUS_PER_NODE
-#endif
-
-#define CNODEID_NONE (cnodeid_t)-1
-#define enter_panic_mode()	spin_lock(&nmi_lock)
-
-typedef unsigned long machreg_t;
-
-spinlock_t nmi_lock = SPIN_LOCK_UNLOCKED;
-
-/*
- * Lets see what else we need to do here. Set up sp, gp?
- */
-void nmi_dump(void)
-{
-	void cont_nmi_dump(void);
-
-	cont_nmi_dump();
-}
-
-void install_cpu_nmi_handler(int slice)
-{
-	nmi_t *nmi_addr;
-
-	nmi_addr = (nmi_t *)NMI_ADDR(get_nasid(), slice);
-	if (nmi_addr->call_addr)
-		return;
-	nmi_addr->magic = NMI_MAGIC;
-	nmi_addr->call_addr = (void *)nmi_dump;
-	nmi_addr->call_addr_c =
-		(void *)(~((unsigned long)(nmi_addr->call_addr)));
-	nmi_addr->call_parm = 0;
-}
-
-/*
- * Copy the cpu registers which have been saved in the IP27prom format
- * into the eframe format for the node under consideration.
- */
-
-void
-nmi_cpu_eframe_save(nasid_t nasid,
-		    int	    slice)
-{
-	int 		i, numberof_nmi_cpu_regs;
-	machreg_t	*prom_format;
-
-	/* Get the total number of registers being saved by the prom */
-	numberof_nmi_cpu_regs = sizeof(struct reg_struct) / sizeof(machreg_t);
-
-	/* Get the pointer to the current cpu's register set. */
-	prom_format = 
-	    (machreg_t *)(TO_UNCAC(TO_NODE(nasid, IP27_NMI_KREGS_OFFSET)) +
-			  slice * IP27_NMI_KREGS_CPU_SIZE);
-
-	printk("NMI nasid %d: slice %d\n", nasid, slice);
-	for (i = 0; i < numberof_nmi_cpu_regs; i++)
-		printk("0x%lx  ", prom_format[i]);
-	printk("\n\n");
-}	
-
-/*
- * Copy the cpu registers which have been saved in the IP27prom format
- * into the eframe format for the node under consideration.
- */
-void
-nmi_node_eframe_save(cnodeid_t  cnode)
-{
-	int		cpu;
-	nasid_t		nasid;
-
-	/* Make sure that we have a valid node */
-	if (cnode == CNODEID_NONE)
-		return;
-
-	nasid = COMPACT_TO_NASID_NODEID(cnode);
-	if (nasid == INVALID_NASID)
-		return;
-
-	/* Save the registers into eframe for each cpu */
-	for(cpu = 0; cpu < NODE_NUM_CPUS(cnode); cpu++) 
-		nmi_cpu_eframe_save(nasid, cpu);
-}
-
-/*
- * Save the nmi cpu registers for all cpus in the system.
- */
-void
-nmi_eframes_save(void)
-{
-	cnodeid_t	cnode;
-
-	for(cnode = 0 ; cnode < numnodes; cnode++) 
-		nmi_node_eframe_save(cnode);
-}
-
-void
-cont_nmi_dump(void)
-{
-#ifndef REAL_NMI_SIGNAL
-	static atomic_t nmied_cpus = ATOMIC_INIT(0);
-
-	atomic_inc(&nmied_cpus);
-#endif
-	/* 
-	 * Use enter_panic_mode to allow only 1 cpu to proceed
-	 */
-	enter_panic_mode();
-
-#ifdef REAL_NMI_SIGNAL
-	/*
-	 * Wait up to 15 seconds for the other cpus to respond to the NMI.
-	 * If a cpu has not responded after 10 sec, send it 1 additional NMI.
-	 * This is for 2 reasons:
-	 *	- sometimes a MMSC fail to NMI all cpus.
-	 *	- on 512p SN0 system, the MMSC will only send NMIs to
-	 *	  half the cpus. Unfortunately, we dont know which cpus may be
-	 *	  NMIed - it depends on how the site chooses to configure.
-	 * 
-	 * Note: it has been measure that it takes the MMSC up to 2.3 secs to
-	 * send NMIs to all cpus on a 256p system.
-	 */
-	for (i=0; i < 1500; i++) {
-		for (node=0; node < numnodes; node++)
-			if (NODEPDA(node)->dump_count == 0)
-				break;
-		if (node == numnodes)
-			break;
-		if (i == 1000) {
-			for (node=0; node < numnodes; node++)
-				if (NODEPDA(node)->dump_count == 0) {
-					cpu = CNODE_TO_CPU_BASE(node);
-					for (n=0; n < CNODE_NUM_CPUS(node); cpu++, n++) {
-						CPUMASK_SETB(nmied_cpus, cpu);
-						/* 
-						 * cputonasid, cputoslice
-						 * needs kernel cpuid
-						 */
-						SEND_NMI((cputonasid(cpu)), (cputoslice(cpu)));
-					}
-				}
-					
-		}
-		udelay(10000);
-	}
-#else
-	while (atomic_read(&nmied_cpus) != smp_num_cpus);
-#endif
-
-	/*
-	 * Save the nmi cpu registers for all cpu in the eframe format.
-	 */
-	nmi_eframes_save();
-	LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/ip27-pci-dma.c linux-2.4.20/arch/mips64/sgi-ip27/ip27-pci-dma.c
--- linux-2.4.19/arch/mips64/sgi-ip27/ip27-pci-dma.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/ip27-pci-dma.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,150 +0,0 @@
-/*
- * Dynamic DMA mapping support.
- *
- * On the Origin there is dynamic DMA address translation for all PCI DMA.
- * However we don't use this facility yet but rely on the 2gb direct
- * mapped DMA window for PCI64.  So consistent alloc/free are merely page
- * allocation/freeing.  The rest of the dynamic DMA mapping interface is
- * implemented in <asm/pci.h>.  So this code will fail with more than
- * 2gb of memory.
- */
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-			   dma_addr_t *dma_handle)
-{
-	void *ret;
-	int gfp = GFP_ATOMIC;
-	int order = get_order(size);
-
-	if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
-		gfp |= GFP_DMA;
-	ret = (void *)__get_free_pages(gfp, order);
-
-	if (ret != NULL) {
-		memset(ret, 0, size);
-		*dma_handle = (bus_to_baddr[hwdev->bus->number] | __pa(ret));
-	}
-
-	return ret;
-}
-
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
-			 void *vaddr, dma_addr_t dma_handle)
-{
-	free_pages((unsigned long)vaddr, get_order(size));
-}
-
-/*
- * Map a single buffer of the indicated size for DMA in streaming mode.
- * The 32-bit bus address to use is returned.
- *
- * Once the device is given the dma address, the device owns this memory
- * until either pci_unmap_single or pci_dma_sync_single is performed.
- */
-dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size,
-                          int direction)
-{
-	if (direction == PCI_DMA_NONE)
-		BUG();
-
-	return (bus_to_baddr[hwdev->bus->number] | __pa(ptr));
-}
-
-/*
- * Unmap a single streaming mode DMA translation.  The dma_addr and size
- * must match what was provided for in a previous pci_map_single call.  All
- * other usages are undefined.
- *
- * After this call, reads by the cpu to the buffer are guarenteed to see
- * whatever the device wrote there.
- */
-void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
-                     size_t size, int direction)
-{
-	if (direction == PCI_DMA_NONE)
-		BUG();
-
-	/* Nothing to do */
-}
-
-/*
- * Map a set of buffers described by scatterlist in streaming
- * mode for DMA.  This is the scather-gather version of the
- * above pci_map_single interface.  Here the scatter gather list
- * elements are each tagged with the appropriate dma address
- * and length.  They are obtained via sg_dma_{address,length}(SG).
- *
- * NOTE: An implementation may be able to use a smaller number of
- *       DMA address/length pairs than there are SG table elements.
- *       (for example via virtual mapping capabilities)
- *       The routine returns the number of addr/length pairs actually
- *       used, at most nents.
- *
- * Device ownership issues as mentioned above for pci_map_single are
- * the same here.
- */
-int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,
-               int direction)
-{
-	int i;
-
-	if (direction == PCI_DMA_NONE)
-		BUG();
-
-	/* Make sure that gcc doesn't leave the empty loop body.  */
-	for (i = 0; i < nents; i++, sg++) {
-		sg->address = (char *)(bus_to_baddr[hwdev->bus->number] | __pa(sg->address));
-	}
-
-	return nents;
-}
-
-/*
- * Unmap a set of streaming mode DMA translations.
- * Again, cpu read rules concerning calls here are the same as for
- * pci_unmap_single() above.
- */
-void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,
-                  int direction)
-{
-	if (direction == PCI_DMA_NONE)
-		BUG();
-
-	/* Nothing to do */
-}
-
-/*
- * Make physical memory consistent for a single
- * streaming mode DMA translation after a transfer.
- *
- * If you perform a pci_map_single() but wish to interrogate the
- * buffer using the cpu, yet do not wish to teardown the PCI dma
- * mapping, you must call this function before doing so.  At the
- * next point you give the PCI dma address back to the card, the
- * device again owns the buffer.
- */
-void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle,
-                         size_t size, int direction)
-{
-	if (direction == PCI_DMA_NONE)
-		BUG();
-}
-
-/*
- * Make physical memory consistent for a set of streaming
- * mode DMA translations after a transfer.
- *
- * The same as pci_dma_sync_single but for a scatter-gather list,
- * same rules and usage.
- */
-void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-                     int nelems, int direction)
-{
-	if (direction == PCI_DMA_NONE)
-		BUG();
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/ip27-pci.c linux-2.4.20/arch/mips64/sgi-ip27/ip27-pci.c
--- linux-2.4.19/arch/mips64/sgi-ip27/ip27-pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/ip27-pci.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,428 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <asm/sn/arch.h>
-#include <asm/pci/bridge.h>
-#include <asm/paccess.h>
-#include <asm/sn/sn0/ip27.h>
-#include <asm/sn/sn0/hub.h>
-
-/*
- * Max #PCI busses we can handle; ie, max #PCI bridges.
- */
-#define MAX_PCI_BUSSES		40
-
-/*
- * Max #PCI devices (like scsi controllers) we handle on a bus.
- */
-#define MAX_DEVICES_PER_PCIBUS	8
-
-/*
- * No locking needed until PCI initialization is done parallely.
- */
-int irqstore[MAX_PCI_BUSSES][MAX_DEVICES_PER_PCIBUS];
-int lastirq = BASE_PCI_IRQ;
-
-/*
- * Translate from irq to software PCI bus number and PCI slot.
- */
-int irq_to_bus[MAX_PCI_BUSSES * MAX_DEVICES_PER_PCIBUS];
-int irq_to_slot[MAX_PCI_BUSSES * MAX_DEVICES_PER_PCIBUS];
-
-/*
- * The Bridge ASIC supports both type 0 and type 1 access.  Type 1 is
- * not really documented, so right now I can't write code which uses it.
- * Therefore we use type 0 accesses for now even though they won't work
- * correcly for PCI-to-PCI bridges.
- */
-#define CF0_READ_PCI_CFG(dev,where,value,bm,mask)			\
-do {									\
-	bridge_t *bridge;                                               \
-	int slot = PCI_SLOT(dev->devfn);				\
-	int fn = PCI_FUNC(dev->devfn);					\
-	volatile u32 *addr;						\
-	u32 cf, __bit;							\
-	unsigned int bus_id = (unsigned) dev->bus->number;              \
-									\
-	bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[bus_id],        \
-                                             bus_to_wid[bus_id]);       \
-                                                                        \
-	if (dev->vendor == PCI_VENDOR_ID_SGI				\
-	    && dev->device == PCI_DEVICE_ID_SGI_IOC3			\
-	    && ((where >= 0x14 && where < 0x40) || (where >= 0x48))) {	\
-		*value = 0;						\
-		return PCIBIOS_SUCCESSFUL;				\
-	}								\
-									\
-	__bit = (((where) & (bm)) << 3);				\
-	addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];	\
-	if (get_dbe(cf, addr))						\
-		return PCIBIOS_DEVICE_NOT_FOUND;			\
-	*value = (cf >> __bit) & (mask);				\
-	return PCIBIOS_SUCCESSFUL;					\
-} while (0)
-
-static int
-pci_conf0_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
-	CF0_READ_PCI_CFG(dev,where,value,3,0xff);
-}
-
-static int
-pci_conf0_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-	CF0_READ_PCI_CFG(dev,where,value,2,0xffff);
-}
-
-static int
-pci_conf0_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-	CF0_READ_PCI_CFG(dev,where,value,0,0xffffffff);
-}
-
-#define CF0_WRITE_PCI_CFG(dev,where,value,bm,mask)			\
-do {									\
-	bridge_t *bridge;                                               \
-	int slot = PCI_SLOT(dev->devfn);				\
-	int fn = PCI_FUNC(dev->devfn);					\
-	volatile u32 *addr;						\
-	u32 cf, __bit;							\
-	unsigned int bus_id = (unsigned) dev->bus->number;              \
-									\
-	bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[bus_id],        \
-                                             bus_to_wid[bus_id]);       \
-                                                                        \
-	if (dev->vendor == PCI_VENDOR_ID_SGI				\
-	    && dev->device == PCI_DEVICE_ID_SGI_IOC3			\
-	    && ((where >= 0x14 && where < 0x40) || (where >= 0x48)))	\
-		return PCIBIOS_SUCCESSFUL;				\
-									\
-	__bit = (((where) & (bm)) << 3);				\
-	addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];	\
-	if (get_dbe(cf, addr))						\
-		return PCIBIOS_DEVICE_NOT_FOUND;			\
-	cf &= (~mask);							\
-	cf |= (value);							\
-	put_dbe(cf, addr);						\
-	return PCIBIOS_SUCCESSFUL;					\
-} while (0)
-
-static int
-pci_conf0_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-	CF0_WRITE_PCI_CFG(dev,where,value,3,0xff);
-}
-
-static int
-pci_conf0_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-	CF0_WRITE_PCI_CFG(dev,where,value,2,0xffff);
-}
-
-static int
-pci_conf0_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-	CF0_WRITE_PCI_CFG(dev,where,value,0,0xffffffff);
-}
-
-
-static struct pci_ops bridge_pci_ops = {
-	pci_conf0_read_config_byte,
-	pci_conf0_read_config_word,
-	pci_conf0_read_config_dword,
-	pci_conf0_write_config_byte,
-	pci_conf0_write_config_word,
-	pci_conf0_write_config_dword
-};
-
-void __init pcibios_init(void)
-{
-	struct pci_ops *ops = &bridge_pci_ops;
-	int	i;
-
-	ioport_resource.end = ~0UL;
-	iomem_resource.end = ~0UL;
-
-	for (i=0; i<num_bridges; i++) {
-		printk("PCI: Probing PCI hardware on host bus %2d.\n", i);
-		pci_scan_bus(i, ops, NULL);
-	}
-}
-
-static inline u8
-bridge_swizzle(u8 pin, u8 slot) 
-{
-	return (((pin-1) + slot) % 4) + 1;
-}
-
-static u8 __init
-pci_swizzle(struct pci_dev *dev, u8 *pinp)
-{
-	u8 pin = *pinp;
-
-	while (dev->bus->self) {	/* Move up the chain of bridges. */
-		pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
-		dev = dev->bus->self;
-	}
-	*pinp = pin;
-
-	return PCI_SLOT(dev->devfn);
-}
-
-/*
- * All observed requests have pin == 1. We could have a global here, that
- * gets incremented and returned every time - unfortunately, pci_map_irq
- * may be called on the same device over and over, and need to return the
- * same value. On O2000, pin can be 0 or 1, and PCI slots can be [0..7]. 
- *
- * A given PCI device, in general, should be able to intr any of the cpus
- * on any one of the hubs connected to its xbow.
- */
-static int __init
-pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
-	if ((dev->bus->number >= MAX_PCI_BUSSES)
-	    || (pin != 1)
-	    || (slot >= MAX_DEVICES_PER_PCIBUS))
-		panic("Increase supported PCI busses %d,%d,%d",
-		      dev->bus->number, slot, pin);
-
-	/*
-	 * Already assigned? Then return previously assigned value ...
-	 */
-	if (irqstore[dev->bus->number][slot])
-		return irqstore[dev->bus->number][slot];
-
-	irq_to_bus[lastirq] = dev->bus->number;
-	irq_to_slot[lastirq] = slot;
-	irqstore[dev->bus->number][slot] = lastirq;
-	lastirq++;
-	return lastirq - 1;
-}
-
-void __init
-pcibios_update_irq(struct pci_dev *dev, int irq)
-{
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-}
-
-void __init
-pcibios_update_resource(struct pci_dev *dev, struct resource *root,
-                        struct resource *res, int resource)
-{
-	unsigned long where, size;
-	u32 reg;
-
-	where = PCI_BASE_ADDRESS_0 + (resource * 4);
-	size = res->end - res->start;
-	pci_read_config_dword(dev, where, &reg);
-	reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
-	pci_write_config_dword(dev, where, reg);
-}
-
-void __init
-pcibios_fixup_bus(struct pci_bus *b)
-{
-	pci_fixup_irqs(pci_swizzle, pci_map_irq);
-}
-
-void __init
-pcibios_fixup_pbus_ranges(struct pci_bus * bus,
-                          struct pbus_set_ranges_data * ranges)
-{
-	ranges->io_start  -= bus->resource[0]->start;
-	ranges->io_end    -= bus->resource[0]->start;
-	ranges->mem_start -= bus->resource[1]->start;
-	ranges->mem_end   -= bus->resource[1]->start;
-}
-
-int __init
-pcibios_enable_device(struct pci_dev *dev)
-{
-	/* Not needed, since we enable all devices at startup.  */
-	return 0;
-}
-
-void __init
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
-{
-}
-
-unsigned __init int pcibios_assign_all_busses(void)
-{
-	return 0;
-}
-
-char * __init
-pcibios_setup(char *str)
-{
-	/* Nothing to do for now.  */
-
-	return str;
-}
-
-/*
- * Device might live on a subordinate PCI bus.  XXX Walk up the chain of buses
- * to find the slot number in sense of the bridge device register.
- * XXX This also means multiple devices might rely on conflicting bridge
- * settings.
- */
-
-static void __init
-pci_disable_swapping(struct pci_dev *dev)
-{
-	unsigned int bus_id = (unsigned) dev->bus->number;
-	bridge_t *bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[bus_id],
-	                                               bus_to_wid[bus_id]);
-	int		slot = PCI_SLOT(dev->devfn);
-
-	/* Turn off byte swapping */
-	bridge->b_device[slot].reg &= ~BRIDGE_DEV_SWAP_DIR;
-	bridge->b_widget.w_tflush;		/* Flush */
-}
-
-static void __init
-pci_enable_swapping(struct pci_dev *dev)
-{
-	unsigned int bus_id = (unsigned) dev->bus->number;
-	bridge_t *bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[bus_id],
-	                                               bus_to_wid[bus_id]);
-	int		slot = PCI_SLOT(dev->devfn);
-
-	/* Turn on byte swapping */
-	bridge->b_device[slot].reg |= BRIDGE_DEV_SWAP_DIR;
-	bridge->b_widget.w_tflush;		/* Flush */
-}
-
-static void __init
-pci_fixup_ioc3(struct pci_dev *d)
-{
-	unsigned long bus_id = (unsigned) d->bus->number;
-
-	printk("PCI: Fixing base addresses for IOC3 device %s\n", d->slot_name);
-
-	d->resource[0].start |= NODE_OFFSET(bus_to_nid[bus_id]);
-	d->resource[0].end   |= NODE_OFFSET(bus_to_nid[bus_id]);
-
-	pci_disable_swapping(d);
-}
-
-static void __init
-pci_fixup_isp1020(struct pci_dev *d)
-{
-	unsigned short command;
-
-	d->resource[0].start |= ((unsigned long)(bus_to_nid[d->bus->number])<<32);
-	printk("PCI: Fixing isp1020 in [bus:slot.fn] %s\n", d->slot_name);
-
-	/*
-	 * Configure device to allow bus mastering, i/o and memory mapping. 
-	 * Older qlogicisp driver expects to have the IO space enable 
-	 * bit set. Things stop working if we program the controllers as not 
-	 * having PCI_COMMAND_MEMORY, so we have to fudge the mem_flags.
-	 */
-
-	pci_set_master(d);
-	pci_read_config_word(d, PCI_COMMAND, &command);
-	command |= PCI_COMMAND_MEMORY;
-	command |= PCI_COMMAND_IO;
-	pci_write_config_word(d, PCI_COMMAND, command);
-	d->resource[1].flags |= 1;
-
-	pci_enable_swapping(d);
-}
-
-static void __init
-pci_fixup_isp2x00(struct pci_dev *d)
-{
-	unsigned int bus_id = (unsigned) d->bus->number;
-	bridge_t *bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[bus_id],
-				     bus_to_wid[bus_id]);
-	bridgereg_t 	devreg;
-	int		i;
-	int		slot = PCI_SLOT(d->devfn);
-	unsigned int	start;
-	unsigned short command;
-
-	printk("PCI: Fixing isp2x00 in [bus:slot.fn] %s\n", d->slot_name);
-
-	/* set the resource struct for this device */
-	start = (u32) (u64)bridge;	/* yes, we want to lose the upper 32 bits here */
-	start |= BRIDGE_DEVIO(slot);
-
-	d->resource[0].start = start;
-	d->resource[0].end = d->resource[0].start + 0xff;
-	d->resource[0].flags = IORESOURCE_IO;
-
-	d->resource[1].start = start;
-	d->resource[1].end = d->resource[0].start + 0xfff;
-	d->resource[1].flags = IORESOURCE_MEM;
-
-	/*
-	 * set the bridge device(x) reg for this device
-	 */
-	devreg = bridge->b_device[slot].reg;
-	/* point device(x) to it appropriate small window */
-	devreg &= ~BRIDGE_DEV_OFF_MASK;
-	devreg |= (start >> 20) & BRIDGE_DEV_OFF_MASK;
-	bridge->b_device[slot].reg = devreg;
-
-	pci_enable_swapping(d);
-
-	/* set card's base addr reg */
-	//pci_conf0_write_config_dword(d, PCI_BASE_ADDRESS_0, 0x500001);
-	//pci_conf0_write_config_dword(d, PCI_BASE_ADDRESS_1, 0x8b00000);
-	//pci_conf0_write_config_dword(d, PCI_ROM_ADDRESS, 0x8b20000);
-
-	/* I got these from booting irix on system...*/
-	pci_conf0_write_config_dword(d, PCI_BASE_ADDRESS_0, 0x200001);
-	//pci_conf0_write_config_dword(d, PCI_BASE_ADDRESS_1, 0xf800000);
-	pci_conf0_write_config_dword(d, PCI_ROM_ADDRESS,   0x10200000);
-
-	pci_conf0_write_config_dword(d, PCI_BASE_ADDRESS_1, start);
-	//pci_conf0_write_config_dword(d, PCI_ROM_ADDRESS, (start | 0x20000));
-
-	/* set cache line size */
-	pci_conf0_write_config_dword(d, PCI_CACHE_LINE_SIZE, 0xf080);
-
-	/* set pci bus timeout */
-	bridge->b_bus_timeout |= BRIDGE_BUS_PCI_RETRY_HLD(0x3);
-	bridge->b_wid_tflush;
-	printk("PCI: bridge bus timeout= 0x%x \n", bridge->b_bus_timeout);
-
-	/* set host error field */
-	bridge->b_int_host_err = 0x44;
-	bridge->b_wid_tflush;
-
-	bridge->b_wid_tflush;   	/* wait until Bridge PIO complete */
-	for (i=0; i<8; i++)
-		printk("PCI: device(%d)= 0x%x\n",i,bridge->b_device[i].reg);
-
-	/* configure device to allow bus mastering, i/o and memory mapping */
-	pci_set_master(d);
-	pci_read_config_word(d, PCI_COMMAND, &command);
-	command |= PCI_COMMAND_MEMORY;
-	command |= PCI_COMMAND_IO;
-	pci_write_config_word(d, PCI_COMMAND, command);
-	/*d->resource[1].flags |= 1;*/
-}
-
-struct pci_fixup pcibios_fixups[] = {
-	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
-	  pci_fixup_ioc3 },
-	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020,
-	  pci_fixup_isp1020 },
-	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100,
-	  pci_fixup_isp2x00 },
-	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200,
-	  pci_fixup_isp2x00 },
-	{ 0 }
-};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/ip27-reset.c linux-2.4.20/arch/mips64/sgi-ip27/ip27-reset.c
--- linux-2.4.19/arch/mips64/sgi-ip27/ip27-reset.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/ip27-reset.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,80 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Reset an IP27.
- *
- * Copyright (C) 1997, 1998, 1999, 2000 by Ralf Baechle
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- */
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/smp.h>
-#include <linux/mmzone.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/reboot.h>
-#include <asm/system.h>
-#include <asm/sgialib.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/gda.h>
-#include <asm/sn/sn0/hub.h>
-
-void machine_restart(char *command) __attribute__((noreturn));
-void machine_halt(void) __attribute__((noreturn));
-void machine_power_off(void) __attribute__((noreturn));
-
-#define noreturn while(1);				/* Silence gcc.  */
-
-/* XXX How to pass the reboot command to the firmware??? */
-static void ip27_machine_restart(char *command)
-{
-#if 0
-	int i;
-#endif
-
-	printk("Reboot started from CPU %d\n", smp_processor_id());
-#ifdef CONFIG_SMP
-	smp_send_stop();
-#endif
-#if 0
-	for (i = 0; i < numnodes; i++)
-		REMOTE_HUB_S(COMPACT_TO_NASID_NODEID(i), PROMOP_REG, 
-							PROMOP_REBOOT);
-#else
-	LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET);
-#endif
-	noreturn;
-}
-
-static void ip27_machine_halt(void)
-{
-	int i;
-
-#ifdef CONFIG_SMP
-	smp_send_stop();
-#endif
-	for (i = 0; i < numnodes; i++)
-		REMOTE_HUB_S(COMPACT_TO_NASID_NODEID(i), PROMOP_REG, 
-							PROMOP_RESTART);
-	LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET);
-	noreturn;
-}
-
-static void ip27_machine_power_off(void)
-{
-	/* To do ...  */
-	noreturn;
-}
-
-void ip27_reboot_setup(void)
-{
-	_machine_restart = ip27_machine_restart;
-	_machine_halt = ip27_machine_halt;
-	_machine_power_off = ip27_machine_power_off;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/ip27-rtc.c linux-2.4.20/arch/mips64/sgi-ip27/ip27-rtc.c
--- linux-2.4.19/arch/mips64/sgi-ip27/ip27-rtc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/ip27-rtc.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,334 +0,0 @@
-/*
- *	Driver for the SGS-Thomson M48T35 Timekeeper RAM chip
- *
- *	Real Time Clock interface for Linux	
- *
- *	TODO: Implement periodic interrupts.
- *
- *	Copyright (C) 2000 Silicon Graphics, Inc.
- *	Written by Ulf Carlsson (ulfc@engr.sgi.com)
- *
- *	Based on code written by Paul Gortmaker.
- *
- *	This driver allows use of the real time clock (built into
- *	nearly all computers) from user space. It exports the /dev/rtc
- *	interface supporting various ioctl() and also the /proc/rtc
- *	pseudo-file for status information.
- *
- *	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.
- *
- */
-
-#define RTC_VERSION		"1.09b"
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/miscdevice.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <linux/rtc.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
-
-#include <asm/m48t35.h>
-#include <asm/sn/ioc3.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/sn0/ip27.h>
-#include <asm/sn/sn0/hub.h>
-
-static int rtc_ioctl(struct inode *inode, struct file *file,
-		     unsigned int cmd, unsigned long arg);
-
-static int rtc_read_proc(char *page, char **start, off_t off,
-                         int count, int *eof, void *data);
-
-static void get_rtc_time(struct rtc_time *rtc_tm);
-
-/*
- *	Bits in rtc_status. (6 bits of room for future expansion)
- */
-
-#define RTC_IS_OPEN		0x01	/* means /dev/rtc is in use	*/
-#define RTC_TIMER_ON		0x02	/* missed irq timer active	*/
-
-static unsigned char rtc_status;	/* bitmapped status byte.	*/
-static spinlock_t rtc_status_lock = SPIN_LOCK_UNLOCKED;
-static unsigned long rtc_freq;	/* Current periodic IRQ rate	*/
-static struct m48t35_rtc *rtc;
-
-/*
- *	If this driver ever becomes modularised, it will be really nice
- *	to make the epoch retain its value across module reload...
- */
-
-static unsigned long epoch = 1970;	/* year corresponding to 0x00	*/
-
-static const unsigned char days_in_mo[] = 
-{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
-static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-		     unsigned long arg)
-{
-
-	struct rtc_time wtime; 
-
-	switch (cmd) {
-	case RTC_RD_TIME:	/* Read the time/date from RTC	*/
-	{
-		get_rtc_time(&wtime);
-		break;
-	}
-	case RTC_SET_TIME:	/* Set the RTC */
-	{
-		struct rtc_time rtc_tm;
-		unsigned char mon, day, hrs, min, sec, leap_yr;
-		unsigned int yrs;
-		unsigned long flags;
-			
-		if (!capable(CAP_SYS_TIME))
-			return -EACCES;
-
-		if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
-				   sizeof(struct rtc_time)))
-			return -EFAULT;
-
-		yrs = rtc_tm.tm_year + 1900;
-		mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
-		day = rtc_tm.tm_mday;
-		hrs = rtc_tm.tm_hour;
-		min = rtc_tm.tm_min;
-		sec = rtc_tm.tm_sec;
-
-		if (yrs < 1970)
-			return -EINVAL;
-
-		leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
-
-		if ((mon > 12) || (day == 0))
-			return -EINVAL;
-
-		if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
-			return -EINVAL;
-			
-		if ((hrs >= 24) || (min >= 60) || (sec >= 60))
-			return -EINVAL;
-
-		if ((yrs -= epoch) > 255)    /* They are unsigned */
-			return -EINVAL;
-
-		save_flags(flags);
-		cli();
-		if (yrs > 169) {
-			restore_flags(flags);
-			return -EINVAL;
-		}
-		if (yrs >= 100)
-			yrs -= 100;
-
-		BIN_TO_BCD(sec);
-		BIN_TO_BCD(min);
-		BIN_TO_BCD(hrs);
-		BIN_TO_BCD(day);
-		BIN_TO_BCD(mon);
-		BIN_TO_BCD(yrs);
-
-		rtc->control &= ~M48T35_RTC_SET;
-		rtc->year = yrs;
-		rtc->month = mon;
-		rtc->date = day;
-		rtc->hour = hrs;
-		rtc->min = min;
-		rtc->sec = sec;
-		rtc->control &= ~M48T35_RTC_SET;
-
-		restore_flags(flags);
-		return 0;
-	}
-	default:
-		return -EINVAL;
-	}
-	return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
-}
-
-/*
- *	We enforce only one user at a time here with the open/close.
- *	Also clear the previous interrupt data on an open, and clean
- *	up things on a close.
- */
-
-static int rtc_open(struct inode *inode, struct file *file)
-{
-	spin_lock(rtc_status_lock);
-
-	if (rtc_status & RTC_IS_OPEN) {
-		spin_unlock(rtc_status_lock);
-		return -EBUSY;
-	}
-
-	rtc_status |= RTC_IS_OPEN;
-	spin_unlock(rtc_status_lock);
-
-	return 0;
-}
-
-static int rtc_release(struct inode *inode, struct file *file)
-{
-	/*
-	 * Turn off all interrupts once the device is no longer
-	 * in use, and clear the data.
-	 */
-
-	spin_lock(rtc_status_lock);
-	rtc_status &= ~RTC_IS_OPEN;
-	spin_unlock(rtc_status_lock);
-
-	return 0;
-}
-
-/*
- *	The various file operations we support.
- */
-
-static struct file_operations rtc_fops = {
-	owner:		THIS_MODULE,
-	ioctl:		rtc_ioctl,
-	open:		rtc_open,
-	release:	rtc_release,
-};
-
-static struct miscdevice rtc_dev=
-{
-	RTC_MINOR,
-	"rtc",
-	&rtc_fops
-};
-
-static int __init rtc_init(void)
-{
-	unsigned long flags;
-	nasid_t nid;
-
-	nid = get_nasid();
-	rtc = (struct m48t35_rtc *)
-	    KL_CONFIG_CH_CONS_INFO(nid)->memory_base + IOC3_BYTEBUS_DEV0;
-
-	printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);
-	if (misc_register(&rtc_dev))
-		return -ENODEV;
-	create_proc_read_entry ("rtc", 0, NULL, rtc_read_proc, NULL);
-
-	save_flags(flags);
-	cli();
-	restore_flags(flags);
-	rtc_freq = 1024;
-	return 0;
-}
-
-static void __exit rtc_exit (void)
-{
-	/* interrupts and timer disabled at this point by rtc_release */
-
-	remove_proc_entry ("rtc", NULL);
-	misc_deregister(&rtc_dev);
-}
-
-module_init(rtc_init);
-module_exit(rtc_exit);
-EXPORT_NO_SYMBOLS;
-
-/*
- *	Info exported via "/proc/rtc".
- */
-
-static int rtc_get_status(char *buf)
-{
-	char *p;
-	struct rtc_time tm;
-
-	/*
-	 * Just emulate the standard /proc/rtc
-	 */
-
-	p = buf;
-
-	get_rtc_time(&tm);
-
-	/*
-	 * There is no way to tell if the luser has the RTC set for local
-	 * time or for Universal Standard Time (GMT). Probably local though.
-	 */
-	p += sprintf(p,
-		     "rtc_time\t: %02d:%02d:%02d\n"
-		     "rtc_date\t: %04d-%02d-%02d\n"
-	 	     "rtc_epoch\t: %04lu\n"
-		     "24hr\t\t: yes\n",
-		     tm.tm_hour, tm.tm_min, tm.tm_sec,
-		     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
-
-	return  p - buf;
-}
-
-static int rtc_read_proc(char *page, char **start, off_t off,
-                                 int count, int *eof, void *data)
-{
-        int len = rtc_get_status(page);
-        if (len <= off+count) *eof = 1;
-        *start = page + off;
-        len -= off;
-        if (len>count) len = count;
-        if (len<0) len = 0;
-        return len;
-}
-
-static void get_rtc_time(struct rtc_time *rtc_tm)
-{
-
-	unsigned long flags;
-
-	/*
-	 * Do we need to wait for the last update to finish?
-	 */
-
-	/*
-	 * Only the values that we read from the RTC are set. We leave
-	 * tm_wday, tm_yday and tm_isdst untouched. Even though the
-	 * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
-	 * by the RTC when initially set to a non-zero value.
-	 */
-	save_flags(flags);
-	cli();
-        rtc->control |= M48T35_RTC_READ;
-	rtc_tm->tm_sec = rtc->sec;
-	rtc_tm->tm_min = rtc->min;
-	rtc_tm->tm_hour = rtc->hour;
-	rtc_tm->tm_mday = rtc->date;
-	rtc_tm->tm_mon = rtc->month;
-	rtc_tm->tm_year = rtc->year;
-	rtc->control &= ~M48T35_RTC_READ;
-	restore_flags(flags);
-
-	BCD_TO_BIN(rtc_tm->tm_sec);
-	BCD_TO_BIN(rtc_tm->tm_min);
-	BCD_TO_BIN(rtc_tm->tm_hour);
-	BCD_TO_BIN(rtc_tm->tm_mday);
-	BCD_TO_BIN(rtc_tm->tm_mon);
-	BCD_TO_BIN(rtc_tm->tm_year);
-
-	/*
-	 * Account for differences between how the RTC uses the values
-	 * and how they are defined in a struct rtc_time;
-	 */
-	if ((rtc_tm->tm_year += (epoch - 1900)) <= 69)
-		rtc_tm->tm_year += 100;
-
-	rtc_tm->tm_mon--;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/ip27-setup.c linux-2.4.20/arch/mips64/sgi-ip27/ip27-setup.c
--- linux-2.4.19/arch/mips64/sgi-ip27/ip27-setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/ip27-setup.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,314 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * SGI IP27 specific setup.
- *
- * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
- * Copyright (C) 1999, 2000 Silcon Graphics, Inc.
- */
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
-
-#include <asm/io.h>
-#include <asm/sn/types.h>
-#include <asm/sn/sn0/addrs.h>
-#include <asm/sn/sn0/hubni.h>
-#include <asm/sn/sn0/hubio.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/ioc3.h>
-#include <asm/time.h>
-#include <asm/mipsregs.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/sn_private.h>
-#include <asm/pci/bridge.h>
-#include <asm/paccess.h>
-#include <asm/sn/sn0/ip27.h>
-
-/* Check against user dumbness.  */
-#ifdef CONFIG_VT
-#error CONFIG_VT not allowed for IP27.
-#endif
-
-#undef DEBUG_SETUP
-#ifdef DEBUG_SETUP
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-/*
- * get_nasid() returns the physical node id number of the caller.
- */
-nasid_t
-get_nasid(void)
-{
-	return (nasid_t)((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_NODEID_MASK)
-	                 >> NSRI_NODEID_SHFT);
-}
-
-/* Extracted from the IOC3 meta driver.  FIXME.  */
-static inline void ioc3_sio_init(void)
-{
-	struct ioc3 *ioc3;
-	nasid_t nid;
-        long loops;
-
-	nid = get_nasid();
-	ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base;
-
-	ioc3->sscr_a = 0;			/* PIO mode for uarta.  */
-	ioc3->sscr_b = 0;			/* PIO mode for uartb.  */
-	ioc3->sio_iec = ~0;
-	ioc3->sio_ies = (SIO_IR_SA_INT | SIO_IR_SB_INT);
-
-	loops=1000000; while(loops--);
-	ioc3->sregs.uarta.iu_fcr = 0;
-	ioc3->sregs.uartb.iu_fcr = 0;
-	loops=1000000; while(loops--);
-}
-
-static inline void ioc3_eth_init(void)
-{
-	struct ioc3 *ioc3;
-	nasid_t nid;
-
-	nid = get_nasid();
-	ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base;
-
-	ioc3->eier = 0;
-}
-
-/* Try to catch kernel missconfigurations and give user an indication what
-   option to select.  */
-static void __init verify_mode(void)
-{
-	int n_mode;
-
-	n_mode = LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_MORENODES_MASK;
-	printk("Machine is in %c mode.\n", n_mode ? 'N' : 'M');
-#ifdef CONFIG_SGI_SN0_N_MODE
-	if (!n_mode)
-		panic("Kernel compiled for M mode.");
-#else
-	if (n_mode)
-		panic("Kernel compiled for N mode.");
-#endif
-}
-
-#define XBOW_WIDGET_PART_NUM    0x0
-#define XXBOW_WIDGET_PART_NUM   0xd000          /* Xbridge */
-#define BASE_XBOW_PORT  	8     /* Lowest external port */
-
-unsigned int bus_to_cpu[256];
-unsigned long bus_to_baddr[256];
-
-void __init pcibr_setup(cnodeid_t nid)
-{
-	int 			i, start, num;
-	unsigned long		masterwid;
-	bridge_t 		*bridge; 
-	volatile u64 		hubreg;
-	nasid_t	 		nasid, masternasid;
-	xwidget_part_num_t	partnum;
-	widgetreg_t 		widget_id;
-	static spinlock_t	pcibr_setup_lock = SPIN_LOCK_UNLOCKED;
-
-	/*
-	 * If the master is doing this for headless node, nothing to do.
-	 * This is because currently we require at least one of the hubs
-	 * (master hub) connected to the xbow to have at least one enabled 
-	 * cpu to receive intrs. Else we need an array bus_to_intrnasid[] 
-	 * that bridge_startup() needs to use to target intrs. All dma is
-	 * routed thru the widget of the master hub. The master hub wid
-	 * is selectable by WIDGET_A below.
-	 */
-	if (nid != get_compact_nodeid())
-		return;
-	/*
-	 * find what's on our local node
-	 */
-	spin_lock(&pcibr_setup_lock);
-	start = num_bridges;		/* Remember where we start from */
-	nasid = COMPACT_TO_NASID_NODEID(nid);
-	hubreg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
-	if (hubreg & IIO_LLP_CSR_IS_UP) {
-		/* link is up */
-		widget_id = *(volatile widgetreg_t *)
-                        (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
-		partnum = XWIDGET_PART_NUM(widget_id);
-		printk("Cpu %d, Nasid 0x%x, pcibr_setup(): found partnum= 0x%x",
-					smp_processor_id(), nasid, partnum);
-		if (partnum == BRIDGE_WIDGET_PART_NUM) {
-			/*
-			 * found direct connected bridge so must be Origin200
-			 */
-			printk("...is bridge\n");
-			num_bridges = 1;
-        		bus_to_wid[0] = 0x8;
-			bus_to_nid[0] = 0;
-			masterwid = 0xa;
-			bus_to_baddr[0] = 0xa100000000000000UL;
-		} else if (partnum == XBOW_WIDGET_PART_NUM) {
-			lboard_t *brd;
-			klxbow_t *xbow_p;
-			/*
-			 * found xbow, so may have multiple bridges
-			 * need to probe xbow
-			 */
-			printk("...is xbow\n");
-
-			if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid),
-                                   KLTYPE_MIDPLANE8)) == NULL)
-				printk("argh\n");
-			else
-				printk("brd = 0x%lx\n", (unsigned long) brd);
-			if ((xbow_p = (klxbow_t *)
-			     find_component(brd, NULL, KLSTRUCT_XBOW)) == NULL)
-				printk("argh\n");
-			else {
-			   /*
-			    * Okay, here's a xbow. Lets arbitrate and find
-			    * out if we should initialize it. Set enabled 
-			    * hub connected at highest or lowest widget as 
-			    * master.
-			    */
-#ifdef WIDGET_A
-			   i = HUB_WIDGET_ID_MAX + 1;
-			   do {
-				i--;
-			   } while ((!XBOW_PORT_TYPE_HUB(xbow_p, i)) ||
-					(!XBOW_PORT_IS_ENABLED(xbow_p, i)));
-#else
-			   i = HUB_WIDGET_ID_MIN - 1;
-			   do {
-				i++;
-			   } while ((!XBOW_PORT_TYPE_HUB(xbow_p, i)) ||
-					(!XBOW_PORT_IS_ENABLED(xbow_p, i)));
-#endif
-			   masterwid = i;
-			   masternasid = XBOW_PORT_NASID(xbow_p, i);
-			   if (nasid == masternasid)
-			   for (i=HUB_WIDGET_ID_MIN; i<=HUB_WIDGET_ID_MAX; i++) {
-				if (!XBOW_PORT_IS_ENABLED(xbow_p, i))
-					continue;
-				if (XBOW_PORT_TYPE_IO(xbow_p, i)) {
-				   widget_id = *(volatile widgetreg_t *)
-                        		   (RAW_NODE_SWIN_BASE(nasid, i) + WIDGET_ID);
-				   partnum = XWIDGET_PART_NUM(widget_id);
-				   if (partnum == BRIDGE_WIDGET_PART_NUM) {
-					printk("widget 0x%x is a bridge\n", i);
-					bus_to_wid[num_bridges] = i;
-					bus_to_nid[num_bridges] = nasid;
-					bus_to_baddr[num_bridges] = ((masterwid << 60) | (1UL << 56));	/* Barrier set */
-					num_bridges++;
-				   }
-				}
-			   }
-			}
-		} else if (partnum == XXBOW_WIDGET_PART_NUM) {
-			/*
-			 * found xbridge, assume ibrick for now 
-			 */
-			printk("...is xbridge\n");
-        		bus_to_wid[0] = 0xb;
-        		bus_to_wid[1] = 0xe;
-        		bus_to_wid[2] = 0xf;
-
-        		bus_to_nid[0] = 0;
-        		bus_to_nid[1] = 0;
-        		bus_to_nid[2] = 0;
-
-			bus_to_baddr[0] = 0xa100000000000000UL;
-			bus_to_baddr[1] = 0xa100000000000000UL;
-			bus_to_baddr[2] = 0xa100000000000000UL;
-			masterwid = 0xa;
-			num_bridges = 3;
-		}
-	}
-	num = num_bridges - start;
-	spin_unlock(&pcibr_setup_lock);
-	/*
-         * set bridge registers
-         */
-	for (i = start; i < (start + num); i++) {
-
-		DBG("pcibr_setup: bus= %d  bus_to_wid[%2d]= %d  bus_to_nid[%2d]= %d\n",
-                        i, i, bus_to_wid[i], i, bus_to_nid[i]);
-
-		bus_to_cpu[i] = smp_processor_id();
-		/*
-		 * point to this bridge
-		 */
-		bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[i],bus_to_wid[i]);
-		/*
-	 	 * Clear all pending interrupts.
-	 	 */
-		bridge->b_int_rst_stat = (BRIDGE_IRR_ALL_CLR);
-		/*
-	 	 * Until otherwise set up, assume all interrupts are from slot 0
-	 	 */
-		bridge->b_int_device = (u32) 0x0;
-		/*
-	 	 * swap pio's to pci mem and io space (big windows)
-	 	 */
-		bridge->b_wid_control |= BRIDGE_CTRL_IO_SWAP;
-		bridge->b_wid_control |= BRIDGE_CTRL_MEM_SWAP;
-
-		/*
-		 * Hmm...  IRIX sets additional bits in the address which 
-		 * are documented as reserved in the bridge docs.
-		 */
-		bridge->b_int_mode = 0x0;		/* Don't clear ints */
-		bridge->b_wid_int_upper = 0x8000 | (masterwid << 16);
-		bridge->b_wid_int_lower = 0x01800090;	/* PI_INT_PEND_MOD off*/
-		bridge->b_dir_map = (masterwid << 20);	/* DMA */
-		bridge->b_int_enable = 0;
-
-		bridge->b_wid_tflush;     /* wait until Bridge PIO complete */
-	}
-}
-
-extern void ip27_setup_console(void);
-extern void ip27_time_init(void);
-
-void __init ip27_setup(void)
-{
-	nasid_t nid;
-	hubreg_t p, e;
-
-	ip27_setup_console();
-
-	num_bridges = 0;
-	/*
-	 * hub_rtc init and cpu clock intr enabled for later calibrate_delay.
-	 */
-	DBG("ip27_setup(): Entered.\n");
-	nid = get_nasid();
-	printk("IP27: Running on node %d.\n", nid);
-
-	p = LOCAL_HUB_L(PI_CPU_PRESENT_A) & 1;
-	e = LOCAL_HUB_L(PI_CPU_ENABLE_A) & 1;
-	printk("Node %d has %s primary CPU%s.\n", nid,
-	       p ? "a" : "no",
-	       e ? ", CPU is running" : "");
-
-	p = LOCAL_HUB_L(PI_CPU_PRESENT_B) & 1;
-	e = LOCAL_HUB_L(PI_CPU_ENABLE_B) & 1;
-	printk("Node %d has %s secondary CPU%s.\n", nid,
-	       p ? "a" : "no",
-	       e ? ", CPU is running" : "");
-
-	verify_mode();
-	ioc3_sio_init();
-	ioc3_eth_init();
-	per_cpu_init();
-
-	mips_io_port_base = IO_BASE;
-	board_time_init = ip27_time_init;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip27/ip27-timer.c linux-2.4.20/arch/mips64/sgi-ip27/ip27-timer.c
--- linux-2.4.19/arch/mips64/sgi-ip27/ip27-timer.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip27/ip27-timer.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,239 +0,0 @@
-/*
- * Copytight (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
- * Copytight (C) 1999, 2000 Silicon Graphics, Inc.
- */
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/param.h>
-#include <linux/timex.h>
-#include <linux/mm.h>		
-
-#include <asm/time.h>
-#include <asm/pgtable.h>
-#include <asm/sgialib.h>
-#include <asm/sn/ioc3.h>
-#include <asm/m48t35.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/sn_private.h>
-#include <asm/sn/sn0/ip27.h>
-#include <asm/sn/sn0/hub.h>
-
-/*
- * This is a hack; we really need to figure these values out dynamically
- * 
- * Since 800 ns works very well with various HUB frequencies, such as
- * 360, 380, 390 and 400 MHZ, we use 800 ns rtc cycle time.
- *
- * Ralf: which clock rate is used to feed the counter?
- */
-#define NSEC_PER_CYCLE		800
-#define NSEC_PER_SEC		1000000000
-#define CYCLES_PER_SEC		(NSEC_PER_SEC/NSEC_PER_CYCLE)
-#define CYCLES_PER_JIFFY	(CYCLES_PER_SEC/HZ)
-
-static unsigned long ct_cur[NR_CPUS];	/* What counter should be at next timer irq */
-static long last_rtc_update;		/* Last time the rtc clock got updated */
-
-extern rwlock_t xtime_lock;
-extern volatile unsigned long wall_jiffies;
-
-
-static int set_rtc_mmss(unsigned long nowtime)
-{
-	int retval = 0;
-	int real_seconds, real_minutes, cmos_minutes;
-	struct m48t35_rtc *rtc;
-	nasid_t nid;
-
-	nid = get_nasid();
-	rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base + 
-							IOC3_BYTEBUS_DEV0);
-
-	rtc->control |= M48T35_RTC_READ;
-	cmos_minutes = rtc->min;
-	BCD_TO_BIN(cmos_minutes);
-	rtc->control &= ~M48T35_RTC_READ;
-
-	/*
-	 * Since we're only adjusting minutes and seconds, don't interfere with
-	 * hour overflow. This avoids messing with unknown time zones but
-	 * requires your RTC not to be off by more than 15 minutes
-	 */
-	real_seconds = nowtime % 60;
-	real_minutes = nowtime / 60;
-	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
-		real_minutes += 30;	/* correct for half hour time zone */
-	real_minutes %= 60;
-
-	if (abs(real_minutes - cmos_minutes) < 30) {
-		BIN_TO_BCD(real_seconds);
-		BIN_TO_BCD(real_minutes);
-		rtc->control |= M48T35_RTC_SET;
-		rtc->sec = real_seconds;
-		rtc->min = real_minutes;
-		rtc->control &= ~M48T35_RTC_SET;
-	} else {
-		printk(KERN_WARNING
-		       "set_rtc_mmss: can't update from %d to %d\n",
-		       cmos_minutes, real_minutes);
-		retval = -1;
-	}
-
-	return retval;
-}
-
-void rt_timer_interrupt(struct pt_regs *regs)
-{
-	int cpu = smp_processor_id();
-	int cpuA = ((cputoslice(cpu)) == 0);
-	int irq = 9;				/* XXX Assign number */
-
-	irq_enter(cpu, irq);
-	write_lock(&xtime_lock);
-
-again:
-	LOCAL_HUB_S(cpuA ? PI_RT_PEND_A : PI_RT_PEND_B, 0);	/* Ack  */
-	ct_cur[cpu] += CYCLES_PER_JIFFY;
-	LOCAL_HUB_S(cpuA ? PI_RT_COMPARE_A : PI_RT_COMPARE_B, ct_cur[cpu]);
-
-	if (LOCAL_HUB_L(PI_RT_COUNT) >= ct_cur[cpu])
-		goto again;
-
-	kstat.irqs[cpu][irq]++;		/* kstat only for bootcpu? */
-
-	if (cpu == 0)
-		do_timer(regs);
-
-#ifdef CONFIG_SMP
-	update_process_times(user_mode(regs));
-#endif /* CONFIG_SMP */
-	
-	/*
-	 * If we have an externally synchronized Linux clock, then update
-	 * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-	 * called as close as possible to when a second starts.
-	 */
-	if ((time_status & STA_UNSYNC) == 0 &&
-	    xtime.tv_sec > last_rtc_update + 660) {
-		if (xtime.tv_usec >= 1000000 - ((unsigned) tick) / 2) {
-			if (set_rtc_mmss(xtime.tv_sec + 1) == 0)
-				last_rtc_update = xtime.tv_sec;
-			else    
-				last_rtc_update = xtime.tv_sec - 600;
-		} else if (xtime.tv_usec <= ((unsigned) tick) / 2) {
-			if (set_rtc_mmss(xtime.tv_sec) == 0)
-				last_rtc_update = xtime.tv_sec;
-			else    
-				last_rtc_update = xtime.tv_sec - 600;
-		}
-        }
-
-	write_unlock(&xtime_lock);
-	irq_exit(cpu, irq);
-
-	if (softirq_pending(cpu))
-		do_softirq();
-}
-
-unsigned long ip27_do_gettimeoffset(void)
-{
-	unsigned long ct_cur1;
-	ct_cur1 = REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT) + CYCLES_PER_JIFFY;
-	return (ct_cur1 - ct_cur[0]) * NSEC_PER_CYCLE / 1000;
-}
-
-/* Includes for ioc3_init().  */
-#include <asm/sn/types.h>
-#include <asm/sn/sn0/addrs.h>
-#include <asm/sn/sn0/hubni.h>
-#include <asm/sn/sn0/hubio.h>
-#include <asm/pci/bridge.h>
-
-static __init unsigned long get_m48t35_time(void)
-{
-        unsigned int year, month, date, hour, min, sec;
-	struct m48t35_rtc *rtc;
-	nasid_t nid;
-
-	nid = get_nasid();
-	rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base + 
-							IOC3_BYTEBUS_DEV0);
-
-	rtc->control |= M48T35_RTC_READ;
-	sec = rtc->sec;
-	min = rtc->min;
-	hour = rtc->hour;
-	date = rtc->date;
-	month = rtc->month;
-	year = rtc->year;
-	rtc->control &= ~M48T35_RTC_READ;
-
-        BCD_TO_BIN(sec);
-        BCD_TO_BIN(min);
-        BCD_TO_BIN(hour);
-        BCD_TO_BIN(date);
-        BCD_TO_BIN(month);
-        BCD_TO_BIN(year);
-
-        year += 1970;
-
-        return mktime(year, month, date, hour, min, sec);
-}
-
-void __init ip27_time_init(void)
-{
-	xtime.tv_sec = get_m48t35_time();
-	xtime.tv_usec = 0;
-
-	do_gettimeoffset = ip27_do_gettimeoffset;
-}
-
-void __init cpu_time_init(void)
-{
-	lboard_t *board;
-	klcpu_t *cpu;
-	int cpuid;
-
-	/* Don't use ARCS.  ARCS is fragile.  Klconfig is simple and sane.  */
-	board = find_lboard(KL_CONFIG_INFO(get_nasid()), KLTYPE_IP27);
-	if (!board)
-		panic("Can't find board info for myself.");
-
-	cpuid = LOCAL_HUB_L(PI_CPU_NUM) ? IP27_CPU0_INDEX : IP27_CPU1_INDEX;
-	cpu = (klcpu_t *) KLCF_COMP(board, cpuid);
-	if (!cpu)
-		panic("No information about myself?");
-
-	printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed);
-
-	set_cp0_status(SRB_TIMOCLK);
-}
-
-void __init hub_rtc_init(cnodeid_t cnode)
-{
-	/*
-	 * We only need to initialize the current node.
-	 * If this is not the current node then it is a cpuless
-	 * node and timeouts will not happen there.
-	 */
-	if (get_compact_nodeid() == cnode) {
-		int cpu = smp_processor_id();
-		LOCAL_HUB_S(PI_RT_EN_A, 1);
-		LOCAL_HUB_S(PI_RT_EN_B, 1);
-		LOCAL_HUB_S(PI_PROF_EN_A, 0);
-		LOCAL_HUB_S(PI_PROF_EN_B, 0);
-		ct_cur[cpu] = CYCLES_PER_JIFFY;
-		LOCAL_HUB_S(PI_RT_COMPARE_A, ct_cur[cpu]);
-		LOCAL_HUB_S(PI_RT_COUNT, 0);
-		LOCAL_HUB_S(PI_RT_PEND_A, 0);
-		LOCAL_HUB_S(PI_RT_COMPARE_B, ct_cur[cpu]);
-		LOCAL_HUB_S(PI_RT_COUNT, 0);
-		LOCAL_HUB_S(PI_RT_PEND_B, 0);
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip32/Makefile linux-2.4.20/arch/mips64/sgi-ip32/Makefile
--- linux-2.4.19/arch/mips64/sgi-ip32/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip32/Makefile	1970-01-01 00:00:00.000000000 +0000
@@ -1,22 +0,0 @@
-#
-# Makefile for the SGI specific kernel interface routines
-# under Linux.
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-USE_STANDARD_AS_RULE := true
-
-O_TARGET := ip32-kern.a
-
-all: ip32-kern.a ip32-irq-glue.o
-
-obj-y	+= ip32-berr.o ip32-rtc.o ip32-setup.o ip32-irq.o ip32-irq-glue.o \
-	   ip32-timer.o crime.o ip32-reset.o
-
-obj-$(CONFIG_PCI)   += ip32-pci.o
-
-include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip32/crime.c linux-2.4.20/arch/mips64/sgi-ip32/crime.c
--- linux-2.4.19/arch/mips64/sgi-ip32/crime.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip32/crime.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,49 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 Keith M Wesolowski
- */
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/ip32/crime.h>
-#include <asm/ptrace.h>
-
-void __init crime_init (void)
-{
-	u64 id = crime_read_64 (CRIME_ID);
-	u64 rev = id & CRIME_ID_REV;
-
-	id = (id & CRIME_ID_IDBITS) >> 4;
-
-	printk ("CRIME id %1lx rev %ld detected at %016lx\n", id, rev,
-		(unsigned long) CRIME_BASE);
-}
-
-/* XXX Like on Sun, these give us various useful information to printk. */
-void crime_memerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
-{
-	u64 memerr = crime_read_64 (CRIME_MEM_ERROR_STAT);
-	u64 addr = crime_read_64 (CRIME_MEM_ERROR_ADDR);
-	memerr &= CRIME_MEM_ERROR_STAT_MASK;
-	
-	printk ("CRIME memory error at physaddr 0x%08lx status %08lx\n",
-		addr << 2, memerr);
-
-	crime_write_64 (CRIME_MEM_ERROR_STAT, 0);
-}
-
-void crime_cpuerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
-{
-	u64 cpuerr = crime_read_64 (CRIME_CPU_ERROR_STAT);
-	u64 addr = crime_read_64 (CRIME_CPU_ERROR_ADDR);
-	cpuerr &= CRIME_CPU_ERROR_MASK;
-	addr <<= 2UL;
-
-	printk ("CRIME CPU interface error detected at %09lx status %08lx\n",
-		addr, cpuerr);
-
-	crime_write_64 (CRIME_CPU_ERROR_STAT, 0);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip32/ip32-berr.c linux-2.4.20/arch/mips64/sgi-ip32/ip32-berr.c
--- linux-2.4.19/arch/mips64/sgi-ip32/ip32-berr.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip32/ip32-berr.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,36 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994, 1995, 1996, 1999, 2000 by Ralf Baechle
- * Copyright (C) 1999, 2000 by Silicon Graphics
- * Copyright (C) 2002  Maciej W. Rozycki
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/traps.h>
-#include <asm/uaccess.h>
-#include <asm/addrspace.h>
-#include <asm/ptrace.h>
-
-int
-be_ip32_handler(struct pt_regs *regs, int is_fixup)
-{
-	int data = regs->cp0_cause & 4;
-
-	if (is_fixup)
-		return MIPS_BE_FIXUP;
-
-	printk("Got %cbe at 0x%lx\n", data ? 'd' : 'i', regs->cp0_epc);
-	show_regs(regs);
-	dump_tlb_all();
-	while(1);
-	force_sig(SIGBUS, current);
-}
-
-void __init
-bus_error_init(void)
-{
-	be_board_handler = be_ip27_handler;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip32/ip32-irq-glue.S linux-2.4.20/arch/mips64/sgi-ip32/ip32-irq-glue.S
--- linux-2.4.19/arch/mips64/sgi-ip32/ip32-irq-glue.S	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip32/ip32-irq-glue.S	1970-01-01 00:00:00.000000000 +0000
@@ -1,87 +0,0 @@
-/*
- * Low level interrupt handler for the SGI O2 aka IP32 aka Moosehead
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000 Harald Koerfgen
- * Copyright (C) 2001 Keith M Wesolowski
- */
-#include <asm/asm.h>
-#include <asm/regdef.h>
-#include <asm/mipsregs.h>
-#include <asm/stackframe.h>
-#include <asm/addrspace.h>
-#include <asm/ip32/ip32_ints.h>
-
-		.text
-		.set    noreorder
-		.set    noat
-		.align  5
-		NESTED(ip32_handle_int, PT_SIZE, ra)
-		.set    noat
-		SAVE_ALL
-		CLI			# TEST: interrupts should be off
-		.set    at
-		.set    noreorder
-
-		mfc0	s0,CP0_CAUSE
-
-		andi	t1, s0, IE_IRQ0
-		bnez	t1, handle_irq0
-		 andi	t1, s0, IE_IRQ1
-		bnez	t1, handle_irq1
-		 andi	t1, s0, IE_IRQ2
-		bnez	t1, handle_irq2
-		 andi	t1, s0, IE_IRQ3
-		bnez	t1, handle_irq3
-		 andi	t1, s0, IE_IRQ4
-		bnez	t1, handle_irq4
-		 andi	t1, s0, IE_IRQ5
-		bnez	t1, handle_irq5
-		 nop
-
-		/* Either someone has triggered the "software interrupts"
-		 * or we lost an interrupt somehow.  Ignore it.
-		 */
-		j	ret_from_irq
-		 nop
-
-handle_irq0:
-		jal	ip32_irq0
-		 move	a0, sp
-		j	ret_from_irq
-		 nop
-
-handle_irq1:
-		jal	ip32_irq1
-		 move	a0, sp
-		j	ret_from_irq
-		 nop
-
-handle_irq2:
-		jal	ip32_irq2
-		 move	a0, sp
-		j	ret_from_irq
-		 nop
-
-handle_irq3:
-		jal	ip32_irq3
-		 move	a0, sp
-		j	ret_from_irq
-		 nop
-
-handle_irq4:
-		jal	ip32_irq4
-		 move	a0, sp
-		j	ret_from_irq
-		 nop
-
-handle_irq5:
-		jal	ip32_irq5
-		move	a0, sp
-		j	ret_from_irq
-		 nop
-
-		END(ip32_handle_int)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip32/ip32-irq.c linux-2.4.20/arch/mips64/sgi-ip32/ip32-irq.c
--- linux-2.4.19/arch/mips64/sgi-ip32/ip32-irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip32/ip32-irq.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,571 +0,0 @@
-/*
- * Code to handle IP32 IRQs
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000 Harald Koerfgen
- * Copyright (C) 2001 Keith M Wesolowski
- */
-#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/bitops.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/random.h>
-#include <linux/sched.h>
-
-#include <asm/bitops.h>
-#include <asm/mipsregs.h>
-#include <asm/system.h>
-#include <asm/ip32/ip32_ints.h>
-#include <asm/ip32/crime.h>
-#include <asm/ip32/mace.h>
-#include <asm/signal.h>
-
-#undef DEBUG_IRQ
-#ifdef DEBUG_IRQ
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-/* O2 irq map
- *
- * IP0 -> software (ignored)
- * IP1 -> software (ignored)
- * IP2 -> (irq0) C crime 1.1 all interrupts; crime 1.5 ???
- * IP3 -> (irq1) X unknown
- * IP4 -> (irq2) X unknown
- * IP5 -> (irq3) X unknown
- * IP6 -> (irq4) X unknown
- * IP7 -> (irq5) 0 CPU count/compare timer (system timer)
- *
- * crime: (C)
- *
- * CRIME_INT_STAT 31:0:
- *
- * 0 -> 1 Video in 1
- * 1 -> 2 Video in 2
- * 2 -> 3 Video out
- * 3 -> 4 Mace ethernet
- * 4 -> S  SuperIO sub-interrupt
- * 5 -> M  Miscellaneous sub-interrupt
- * 6 -> A  Audio sub-interrupt
- * 7 -> 8  PCI bridge errors
- * 8 -> 9  PCI SCSI aic7xxx 0
- * 9 -> 10  PCI SCSI aic7xxx 1
- * 10 -> 11 PCI slot 0
- * 11 -> 12 unused (PCI slot 1)
- * 12 -> 13 unused (PCI slot 2)
- * 13 -> 14 unused (PCI shared 0)
- * 14 -> 15 unused (PCI shared 1)
- * 15 -> 16 unused (PCI shared 2)
- * 16 -> 17 GBE0 (E)
- * 17 -> 18 GBE1 (E)
- * 18 -> 19 GBE2 (E)
- * 19 -> 20 GBE3 (E)
- * 20 -> 21 CPU errors
- * 21 -> 22 Memory errors
- * 22 -> 23 RE empty edge (E)
- * 23 -> 24 RE full edge (E)
- * 24 -> 25 RE idle edge (E)
- * 25 -> 26 RE empty level
- * 26 -> 27 RE full level
- * 27 -> 28 RE idle level
- * 28 -> 29  unused (software 0) (E)
- * 29 -> 30  unused (software 1) (E)
- * 30 -> 31  unused (software 2) - crime 1.5 CPU SysCorError (E)
- * 31 -> 32 VICE
- *
- * S, M, A: Use the MACE ISA interrupt register
- * MACE_ISA_INT_STAT 31:0
- *
- * 0-7 -> 33-40 Audio
- * 8 -> 41 RTC
- * 9 -> 42 Keyboard
- * 10 -> X Keyboard polled
- * 11 -> 44 Mouse
- * 12 -> X Mouse polled
- * 13-15 -> 46-48 Count/compare timers
- * 16-19 -> 49-52 Parallel (16 E)
- * 20-25 -> 53-58 Serial 1 (22 E)
- * 26-31 -> 59-64 Serial 2 (28 E)
- *
- * Note that this means IRQs 5-7, 43, and 45 do not exist.  This is a
- * different IRQ map than IRIX uses, but that's OK as Linux irq handling
- * is quite different anyway.
- */
-
-/* Some initial interrupts to set up */
-extern void crime_memerr_intr (unsigned int irq, void *dev_id,
-			       struct pt_regs *regs);
-extern void crime_cpuerr_intr (unsigned int irq, void *dev_id,
-			       struct pt_regs *regs);
-
-struct irqaction memerr_irq = { crime_memerr_intr, SA_INTERRUPT,
-			       0, "CRIME memory error", NULL,
-			       NULL };
-struct irqaction cpuerr_irq = { crime_cpuerr_intr, SA_INTERRUPT,
-			       0, "CRIME CPU error", NULL,
-			       NULL };
-
-extern void ip32_handle_int (void);
-asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs);
-
-/*
- * For interrupts wired from a single device to the CPU.  Only the clock
- * uses this it seems, which is IRQ 0 and IP7.
- */
-
-static void enable_cpu_irq(unsigned int irq)
-{
-	set_cp0_status(STATUSF_IP7);
-}
-
-static unsigned int startup_cpu_irq(unsigned int irq)
-{
-	enable_cpu_irq(irq);
-	return 0;
-}
-
-static void disable_cpu_irq(unsigned int irq)
-{
-	clear_cp0_status(STATUSF_IP7);
-}
-
-static void end_cpu_irq(unsigned int irq)
-{
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-		enable_cpu_irq (irq);
-}
-
-#define shutdown_cpu_irq disable_cpu_irq
-#define mask_and_ack_cpu_irq disable_cpu_irq
-
-static struct hw_interrupt_type ip32_cpu_interrupt = {
-	"IP32 CPU",
-	startup_cpu_irq,
-	shutdown_cpu_irq,
-	enable_cpu_irq,
-	disable_cpu_irq,
-	mask_and_ack_cpu_irq,
-	end_cpu_irq,
-	NULL
-};
-
-/*
- * This is for pure CRIME interrupts - ie not MACE.  The advantage?
- * We get to split the register in half and do faster lookups.
- */
-
-static void enable_crime_irq(unsigned int irq)
-{
-	u64 crime_mask;
-	unsigned long flags;
-
-	save_and_cli(flags);
-	crime_mask = crime_read_64(CRIME_INT_MASK);
-	crime_mask |= 1 << (irq - 1);
-	crime_write_64(CRIME_INT_MASK, crime_mask);
-	restore_flags(flags);
-}
-
-static unsigned int startup_crime_irq(unsigned int irq)
-{
-	enable_crime_irq(irq);
-	return 0; /* This is probably not right; we could have pending irqs */
-}
-
-static void disable_crime_irq(unsigned int irq)
-{
-	u64 crime_mask;
-	unsigned long flags;
-
-	save_and_cli(flags);
-	crime_mask = crime_read_64(CRIME_INT_MASK);
-	crime_mask &= ~(1 << (irq - 1));
-	crime_write_64(CRIME_INT_MASK, crime_mask);
-	restore_flags(flags);
-}
-
-static void mask_and_ack_crime_irq (unsigned int irq)
-{
-	u64 crime_mask;
-	unsigned long flags;
-
-	/* Edge triggered interrupts must be cleared. */
-	if ((irq <= CRIME_GBE0_IRQ && irq >= CRIME_GBE3_IRQ)
-	    || (irq <= CRIME_RE_EMPTY_E_IRQ && irq >= CRIME_RE_IDLE_E_IRQ)
-	    || (irq <= CRIME_SOFT0_IRQ && irq >= CRIME_SOFT2_IRQ)) {
-		save_and_cli(flags);
-		crime_mask = crime_read_64(CRIME_HARD_INT);
-		crime_mask &= ~(1 << (irq - 1));
-		crime_write_64(CRIME_HARD_INT, crime_mask);
-		restore_flags(flags);
-	}
-	disable_crime_irq(irq);
-}
-
-static void end_crime_irq(unsigned int irq)
-{
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-		enable_crime_irq (irq);
-}
-
-#define shutdown_crime_irq disable_crime_irq
-
-static struct hw_interrupt_type ip32_crime_interrupt = {
-	"IP32 CRIME",
-	startup_crime_irq,
-	shutdown_crime_irq,
-	enable_crime_irq,
-	disable_crime_irq,
-	mask_and_ack_crime_irq,
-	end_crime_irq,
-	NULL
-};
-
-/*
- * This is for MACE PCI interrupts.  We can decrease bus traffic by masking
- * as close to the source as possible.  This also means we can take the
- * next chunk of the CRIME register in one piece.
- */
-
-static void enable_macepci_irq(unsigned int irq)
-{
-	u32 mace_mask;
-	u64 crime_mask;
-	unsigned long flags;
-
-	save_and_cli(flags);
-	mace_mask = mace_read_32(MACEPCI_CONTROL);
-	mace_mask |= MACEPCI_CONTROL_INT(irq - 9);
-	mace_write_32(MACEPCI_CONTROL, mace_mask);
-	/*
-	 * In case the CRIME interrupt isn't enabled, we must enable it;
-	 * however, we never disable interrupts at that level.
-	 */
-	crime_mask = crime_read_64(CRIME_INT_MASK);
-	crime_mask |= 1 << (irq - 1);
-	crime_write_64(CRIME_INT_MASK, crime_mask);
-	restore_flags(flags);
-}
-
-static unsigned int startup_macepci_irq(unsigned int irq)
-{
-	enable_macepci_irq (irq);
-
-	return 0; /* XXX */
-}
-
-static void disable_macepci_irq(unsigned int irq)
-{
-	u32 mace_mask;
-	unsigned long flags;
-
-	save_and_cli(flags);
-	mace_mask = mace_read_32(MACEPCI_CONTROL);
-	mace_mask &= ~MACEPCI_CONTROL_INT(irq - 9);
-	mace_write_32(MACEPCI_CONTROL, mace_mask);
-	restore_flags(flags);
-}
-
-static void end_macepci_irq(unsigned int irq)
-{
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-		enable_macepci_irq (irq);
-}
-
-#define shutdown_macepci_irq disable_macepci_irq
-#define mask_and_ack_macepci_irq disable_macepci_irq
-
-static struct hw_interrupt_type ip32_macepci_interrupt = {
-	"IP32 MACE PCI",
-	startup_macepci_irq,
-	shutdown_macepci_irq,
-	enable_macepci_irq,
-	disable_macepci_irq,
-	mask_and_ack_macepci_irq,
-	end_macepci_irq,
-	NULL
-};
-
-/* This is used for MACE ISA interrupts.  That means bits 4-6 in the
- * CRIME register.
- */
-
-static void enable_maceisa_irq (unsigned int irq)
-{
-	u64 crime_mask;
-	u32 mace_mask;
-	unsigned int crime_int = 0;
-	unsigned long flags;
-
-	DBG ("maceisa enable: %u\n", irq);
-	
-	switch (irq) {
-	case MACEISA_AUDIO_SW_IRQ ... MACEISA_AUDIO3_MERR_IRQ:
-		crime_int = MACE_AUDIO_INT;
-		break;
-	case MACEISA_RTC_IRQ ... MACEISA_TIMER2_IRQ:
-		crime_int = MACE_MISC_INT;
-		break;
-	case MACEISA_PARALLEL_IRQ ... MACEISA_SERIAL2_RDMAOR_IRQ:
-		crime_int = MACE_SUPERIO_INT;
-		break;
-	}
-	DBG ("crime_int %016lx enabled\n", crime_int);
-	save_and_cli(flags);
-	crime_mask = crime_read_64(CRIME_INT_MASK);
-	crime_mask |= crime_int;
-	crime_write_64(CRIME_INT_MASK, crime_mask);
-	mace_mask = mace_read_32(MACEISA_INT_MASK);
-	mace_mask |= 1 << (irq - 33);
-	mace_write_32(MACEISA_INT_MASK, mace_mask);
-	restore_flags(flags);
-}
-
-static unsigned int startup_maceisa_irq (unsigned int irq)
-{
-	enable_maceisa_irq(irq);
-	return 0;
-}
-
-static void disable_maceisa_irq(unsigned int irq)
-{
-	u32 mace_mask;
-	unsigned long flags;
-
-	save_and_cli (flags);
-	mace_mask = mace_read_32(MACEISA_INT_MASK);
-	mace_mask &= ~(1 << (irq - 33));
-	mace_write_32(MACEISA_INT_MASK, mace_mask);
-	restore_flags(flags);
-}
-
-static void mask_and_ack_maceisa_irq(unsigned int irq)
-{
-	u32 mace_mask;
-	unsigned long flags;
-
-	switch (irq) {
-	case MACEISA_PARALLEL_IRQ:
-	case MACEISA_SERIAL1_TDMAPR_IRQ:
-	case MACEISA_SERIAL2_TDMAPR_IRQ:
-		save_and_cli(flags);
-		mace_mask = mace_read_32(MACEISA_INT_STAT);
-		mace_mask &= ~(1 << (irq - 33));
-		mace_write_32(MACEISA_INT_STAT, mace_mask);
-		restore_flags(flags);
-		break;
-	}
-	disable_maceisa_irq(irq);
-}
-
-static void end_maceisa_irq(unsigned irq)
-{
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-		enable_maceisa_irq (irq);
-}
-
-#define shutdown_maceisa_irq disable_maceisa_irq
-
-static struct hw_interrupt_type ip32_maceisa_interrupt = {
-	"IP32 MACE ISA",
-	startup_maceisa_irq,
-	shutdown_maceisa_irq,
-	enable_maceisa_irq,
-	disable_maceisa_irq,
-	mask_and_ack_maceisa_irq,
-	end_maceisa_irq,
-	NULL
-};
-
-/* This is used for regular non-ISA, non-PCI MACE interrupts.  That means
- * bits 0-3 and 7 in the CRIME register.
- */
-
-static void enable_mace_irq(unsigned int irq)
-{
-	u64 crime_mask;
-	unsigned long flags;
-
-	save_and_cli (flags);
-	crime_mask = crime_read_64 (CRIME_INT_MASK);
-	crime_mask |= 1 << (irq - 1);
-	crime_write_64 (CRIME_INT_MASK, crime_mask);
-	restore_flags (flags);
-}
-
-static unsigned int startup_mace_irq(unsigned int irq)
-{
-	enable_mace_irq(irq);
-	return 0;
-}
-
-static void disable_mace_irq(unsigned int irq)
-{
-	u64 crime_mask;
-	unsigned long flags;
-
-	save_and_cli (flags);
-	crime_mask = crime_read_64 (CRIME_INT_MASK);
-	crime_mask &= ~(1 << (irq - 1));
-	crime_write_64 (CRIME_INT_MASK, crime_mask);
-	restore_flags(flags);
-}
-
-static void end_mace_irq(unsigned int irq)
-{
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-		enable_mace_irq (irq);
-}
-
-#define shutdown_mace_irq disable_mace_irq
-#define mask_and_ack_mace_irq disable_mace_irq
-
-static struct hw_interrupt_type ip32_mace_interrupt = {
-	"IP32 MACE",
-	startup_mace_irq,
-	shutdown_mace_irq,
-	enable_mace_irq,
-	disable_mace_irq,
-	mask_and_ack_mace_irq,
-	end_mace_irq,
-	NULL
-};
-
-static void ip32_unknown_interrupt (struct pt_regs *regs)
-{
-	u64 crime;
-	u32 mace;
-	
-	printk ("Unknown interrupt occurred!\n");
-	printk ("cp0_status: %08x\tcp0_cause: %08x\n",
-		read_32bit_cp0_register (CP0_STATUS),
-		read_32bit_cp0_register (CP0_CAUSE));
-	crime = crime_read_64 (CRIME_INT_MASK);
-	printk ("CRIME interrupt mask: %016lx\n", crime);
-	crime = crime_read_64 (CRIME_INT_STAT);
-	printk ("CRIME interrupt status: %016lx\n", crime);
-	crime = crime_read_64 (CRIME_HARD_INT);
-	printk ("CRIME hardware interrupt register: %016lx\n", crime);
-	mace = mace_read_32 (MACEISA_INT_MASK);
-	printk ("MACE ISA interrupt mask: %08x\n", mace);
-	mace = mace_read_32 (MACEISA_INT_STAT);
-	printk ("MACE ISA interrupt status: %08x\n", mace);
-	mace = mace_read_32 (MACEPCI_CONTROL);
-	printk ("MACE PCI control register: %08x\n", mace);
-
-	printk("Register dump:\n");
-	show_regs(regs);
-
-	printk("Please mail this report to linux-mips@oss.sgi.com\n");
-	printk("Spinning...");
-	while(1) ;
-}
-
-/* CRIME 1.1 appears to deliver all interrupts to this one pin. */
-void ip32_irq0(struct pt_regs *regs)
-{
-	u64 crime_int = crime_read_64 (CRIME_INT_STAT);
-	int irq = 0;
-	
-	if (crime_int & CRIME_MACE_INT_MASK) {
-		crime_int &= CRIME_MACE_INT_MASK;
-		irq = ffs (crime_int);
-	} else if (crime_int & CRIME_MACEISA_INT_MASK) {
-		u32 mace_int;
-		mace_int = mace_read_32 (MACEISA_INT_STAT);
-		if (mace_int == 0)
-			irq = 0;
-		else
-			irq = ffs (mace_int) + 32;
-	} else if (crime_int & CRIME_MACEPCI_INT_MASK) {
-		crime_int &= CRIME_MACEPCI_INT_MASK;
-		crime_int >>= 8;
-		irq = ffs (crime_int) + 8;
-	} else if (crime_int & 0xffff0000) {
-		crime_int >>= 16;
-		irq = ffs (crime_int) + 16;
-	}
-	if (irq == 0)
-		ip32_unknown_interrupt(regs);
-	DBG("*irq %u*\n", irq);
-	do_IRQ(irq, regs);
-}
-
-void ip32_irq1(struct pt_regs *regs)
-{
-	ip32_unknown_interrupt (regs);
-}
-
-void ip32_irq2(struct pt_regs *regs)
-{
-	ip32_unknown_interrupt (regs);
-}
-
-void ip32_irq3(struct pt_regs *regs)
-{
-	ip32_unknown_interrupt (regs);
-}
-
-void ip32_irq4(struct pt_regs *regs)
-{
-	ip32_unknown_interrupt (regs);
-}
-
-void ip32_irq5(struct pt_regs *regs)
-{
-	do_IRQ (CLOCK_IRQ, regs);
-}
-
-void __init init_IRQ(void)
-{
-	unsigned int irq;
-	int i;
-
-	/* Install our interrupt handler, then clear and disable all
-	 * CRIME and MACE interrupts.
-	 */
-	crime_write_64(CRIME_INT_MASK, 0);
-	crime_write_64(CRIME_HARD_INT, 0);
-	crime_write_64(CRIME_SOFT_INT, 0);
-	mace_write_32(MACEISA_INT_STAT, 0);
-	mace_write_32(MACEISA_INT_MASK, 0);
-	set_except_vector(0, ip32_handle_int);
-
-	for (i = 0; i < NR_IRQS; i++) {
-		irq_desc[i].status  = IRQ_DISABLED;
-		irq_desc[i].action  = NULL;
-		irq_desc[i].depth   = 1;
-		irq_desc[i].handler = &no_irq_type;
-	}
-
-	for (irq = 0; irq <= IP32_IRQ_MAX; irq++) {
-		hw_irq_controller *controller;
-
-		if (irq == CLOCK_IRQ)
-			controller = &ip32_cpu_interrupt;
-		else if (irq <= MACE_PCI_BRIDGE_IRQ && irq >= MACE_VID_IN1_IRQ)
-			controller = &ip32_mace_interrupt;
-		else if (irq <= MACEPCI_SHARED2_IRQ && irq >= MACEPCI_SCSI0_IRQ)
-			controller = &ip32_macepci_interrupt;
-		else if (irq <= CRIME_VICE_IRQ && irq >= CRIME_GBE0_IRQ)
-			controller = &ip32_crime_interrupt;
-		else
-			controller = &ip32_maceisa_interrupt;
-
-		irq_desc[irq].status = IRQ_DISABLED;
-		irq_desc[irq].action = 0;
-		irq_desc[irq].depth = 0;
-		irq_desc[irq].handler = controller;
-	}
-	setup_irq(CRIME_MEMERR_IRQ, &memerr_irq);
-	setup_irq(CRIME_CPUERR_IRQ, &cpuerr_irq);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip32/ip32-pci.c linux-2.4.20/arch/mips64/sgi-ip32/ip32-pci.c
--- linux-2.4.19/arch/mips64/sgi-ip32/ip32-pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip32/ip32-pci.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,460 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000, 2001 Keith M Wesolowski
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/types.h>
-#include <asm/pci.h>
-#include <asm/ip32/mace.h>
-#include <asm/ip32/crime.h>
-#include <asm/ip32/ip32_ints.h>
-#include <linux/delay.h>
-
-#undef DEBUG_MACE_PCI
-
-/*
- * O2 has up to 5 PCI devices connected into the MACE bridge.  The device
- * map looks like this:
- *
- * 0  aic7xxx 0
- * 1  aic7xxx 1
- * 2  expansion slot
- * 3  N/C
- * 4  N/C
- */
-
-#define chkslot(dev)							\
-do {									\
-	if ((dev)->bus->number > 0 || PCI_SLOT ((dev)->devfn) < 1	\
-	    || PCI_SLOT ((dev)->devfn) > 3)				\
-		return PCIBIOS_DEVICE_NOT_FOUND;			\
-} while (0)
-		
-#define mkaddr(dev, where) \
-((((dev)->devfn & 0xffUL) << 8) | ((where) & 0xfcUL))
-
-void macepci_error (int irq, void *dev, struct pt_regs *regs);
-
-static int macepci_read_config_byte (struct pci_dev *dev, int where,
-				     u8 *val)
-{
-	*val = 0xff;
-	chkslot (dev);
-	mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where));
-	*val = mace_read_8 (MACEPCI_CONFIG_DATA + ((where & 3UL) ^ 3UL));
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int macepci_read_config_word (struct pci_dev *dev, int where,
-				     u16 *val)
-{
-	*val = 0xffff;
-	chkslot (dev);
-	if (where & 1)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
- 	mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where));
-	*val = mace_read_16 (MACEPCI_CONFIG_DATA + ((where & 2UL) ^ 2UL));
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int macepci_read_config_dword (struct pci_dev *dev, int where,
-				      u32 *val)
-{
-	*val = 0xffffffff;
-	chkslot (dev);
-	if (where & 3)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where));
-	*val = mace_read_32 (MACEPCI_CONFIG_DATA);
-	
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int macepci_write_config_byte (struct pci_dev *dev, int where,
-				      u8 val)
-{
-	chkslot (dev);
-	mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where));
-	mace_write_8 (MACEPCI_CONFIG_DATA + ((where & 3UL) ^ 3UL), val);
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int macepci_write_config_word (struct pci_dev *dev, int where,
-				      u16 val)
-{
-	chkslot (dev);
-	if (where & 1)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where));
-	mace_write_16 (MACEPCI_CONFIG_DATA + ((where & 2UL) ^ 2UL), val);
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int macepci_write_config_dword (struct pci_dev *dev, int where,
-                                          u32 val)
-{
-	chkslot (dev);
-	if (where & 3)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where));
-	mace_write_32 (MACEPCI_CONFIG_DATA, val);
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops macepci_ops = {
-	macepci_read_config_byte,
-	macepci_read_config_word,
-	macepci_read_config_dword,
-	macepci_write_config_byte,
-	macepci_write_config_word,
-	macepci_write_config_dword
-};
-
-struct pci_fixup pcibios_fixups[] = { { 0 } };
-
-void __init pcibios_init (void)
-{
-	struct pci_dev *dev;
-	u32 start, size;
-	u16 cmd;
-	u32 base_io = 0x3000; /* The first i/o address to assign after SCSI */
-	u32 base_mem = 0x80100000; /* Likewise */
-	u32 rev = mace_read_32 (MACEPCI_REV);
-	int i;
-
-	printk ("MACE: PCI rev %d detected at %016lx\n", rev,
-		(u64) MACE_BASE + MACE_PCI);
-
-	/* These are *bus* addresses */
-	ioport_resource.start = 0;
-	ioport_resource.end = 0xffffffffUL;
-	iomem_resource.start = 0x80000000UL;
-	iomem_resource.end = 0xffffffffUL;
-
-	/* Clear any outstanding errors and enable interrupts */
-	mace_write_32 (MACEPCI_ERROR_ADDR, 0);
-	mace_write_32 (MACEPCI_ERROR_FLAGS, 0);
-	mace_write_32 (MACEPCI_CONTROL, 0xff008500);
-	crime_write_64 (CRIME_HARD_INT, 0UL);
-	crime_write_64 (CRIME_SOFT_INT, 0UL);
-	crime_write_64 (CRIME_INT_STAT, 0x000000000000ff00UL);
-
-	if (request_irq (MACE_PCI_BRIDGE_IRQ, macepci_error, 0,
-			 "MACE PCI error", NULL))
-		panic("PCI bridge can't get interrupt; can't happen.");
-
-	pci_scan_bus (0, &macepci_ops, NULL);
-
-#ifdef DEBUG_MACE_PCI
-	pci_for_each_dev (dev) {
-		printk ("Device: %d/%d/%d ARCS-assigned bus resource map\n",
-			dev->bus->number, PCI_SLOT (dev->devfn),
-			PCI_FUNC (dev->devfn));
-		for (i=0; i < DEVICE_COUNT_RESOURCE; i++) {
-			if (dev->resource[i].start == 0)
-				continue;
-			printk ("%d: %016lx - %016lx (flags %04lx)\n",
-				i, dev->resource[i].start,
-				dev->resource[i].end, dev->resource[i].flags);
-		}
-	}
-#endif
-	/*
-	 * Assign sane resources to and enable all devices.  The requirement
-	 * for the SCSI controllers is well-known: a 256-byte I/O region
-	 * which we must assign, and a 1-page memory region which is
-	 * assigned by the system firmware.
-	 */
-	pci_for_each_dev (dev) {
-		switch (PCI_SLOT (dev->devfn)) {
-		case 1: /* SCSI bus 0 */
-			dev->resource[0].start = 0x1000UL;
-			dev->resource[0].end = 0x10ffUL;
-			break;
-		case 2: /* SCSI bus 1 */
-			dev->resource[0].start = 0x2000UL;
-			dev->resource[0].end = 0x20ffUL;
-			break;
-		default: /* Slots - I guess we have only 1 */
-			for (i=0; i < 6; i++) {
-				size = dev->resource[i].end
-					- dev->resource[i].start;
-				if (!size
-				    || !(dev->resource[i].flags
-					 & (IORESOURCE_IO|IORESOURCE_MEM))) {
-					dev->resource[i].start
-						= dev->resource[i].end = 0UL;
-					continue;
-				}
-				if (dev->resource[i].flags & IORESOURCE_IO) {
-					dev->resource[i].start = base_io;
-					base_io += PAGE_ALIGN (size);
-				} else {
-					dev->resource[i].start = base_mem;
-					base_mem += 0x100000UL;
-				}
-				dev->resource[i].end =
-					dev->resource[i].start + size;
-			}
-			break;
-		}
-		for (i=0; i < 6; i++) {
-			if (dev->resource[i].start == 0)
-				continue;
-			start = dev->resource[i].start;
-			if (dev->resource[i].flags & IORESOURCE_IO)
-				start |= 1;
-			pci_write_config_dword (dev, 
-				PCI_BASE_ADDRESS_0 + (i << 2), (u32) start);
-		}
-		pci_write_config_byte (dev, PCI_CACHE_LINE_SIZE, 0x20);
-		pci_write_config_byte (dev, PCI_LATENCY_TIMER, 0x30);
-		pci_read_config_word (dev, PCI_COMMAND, &cmd);
-		cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_SPECIAL | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY);
-		pci_write_config_word (dev, PCI_COMMAND, cmd);
-		pci_set_master (dev);
-	}
-        /*
-         * Fixup O2 PCI slot. Bad hack.
-         */
-/*        devtag = pci_make_tag(0, 0, 3, 0);
-
-        slot = macepci_conf_read(0, devtag, PCI_COMMAND_STATUS_REG);
-        slot |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE;
-        macepci_conf_write(0, devtag, PCI_COMMAND_STATUS_REG, slot);
-
-        slot = macepci_conf_read(0, devtag, PCI_MAPREG_START);
-        if (slot == 0xffffffe1)
-                macepci_conf_write(0, devtag, PCI_MAPREG_START, 0x00001000);
-
-        slot = macepci_conf_read(0, devtag, PCI_MAPREG_START + (2 << 2));
-        if ((slot & 0xffff0000) == 0) {
-                slot += 0x00010000;
-                macepci_conf_write(0, devtag, PCI_MAPREG_START + (2 << 2),
-                    0x00000000);
-        }
- */
-#ifdef DEBUG_MACE_PCI
-	printk ("Triggering PCI bridge interrupt...\n");
-	mace_write_32 (MACEPCI_ERROR_FLAGS, MACEPCI_ERROR_INTERRUPT_TEST);
-
-	pci_for_each_dev (dev) {
-		printk ("Device: %d/%d/%d final bus resource map\n",
-			dev->bus->number, PCI_SLOT (dev->devfn),
-			PCI_FUNC (dev->devfn));
-		for (i=0; i < DEVICE_COUNT_RESOURCE; i++) {
-			if (dev->resource[i].start == 0)
-				continue;
-			printk ("%d: %016lx - %016lx (flags %04lx)\n",
-				i, dev->resource[i].start,
-				dev->resource[i].end, dev->resource[i].flags);
-		}
-	}
-#endif
-}
-
-/*
- * Given a PCI slot number (a la PCI_SLOT(...)) and the interrupt pin of
- * the device (1-4 => A-D), tell what irq to use.  Note that we don't
- * in theory have slots 4 and 5, and we never normally use the shared
- * irqs.  I suppose a device without a pin A will thank us for doing it
- * right if there exists such a broken piece of crap.
- */
-static int __init macepci_map_irq (struct pci_dev *dev, u8 slot, u8 pin)
-{
-	chkslot (dev);
-	if (pin == 0)
-		pin = 1;
-	switch (slot) {
-	case 1:
-		return MACEPCI_SCSI0_IRQ;
-	case 2:
-		return MACEPCI_SCSI1_IRQ;
-	case 3:
-		switch (pin) {
-		case 2:
-			return MACEPCI_SHARED0_IRQ;
-		case 3:
-			return MACEPCI_SHARED1_IRQ;
-		case 4:
-			return MACEPCI_SHARED2_IRQ;
-		case 1:
-		default:
-			return MACEPCI_SLOT0_IRQ;
-		}
-	case 4:
-		switch (pin) {
-		case 2:
-			return MACEPCI_SHARED2_IRQ;
-		case 3:
-			return MACEPCI_SHARED0_IRQ;
-		case 4:
-			return MACEPCI_SHARED1_IRQ;
-		case 1:
-		default:
-			return MACEPCI_SLOT1_IRQ;
-		}
-		return MACEPCI_SLOT1_IRQ;
-	case 5:
-		switch (pin) {
-		case 2:
-			return MACEPCI_SHARED1_IRQ;
-		case 3:
-			return MACEPCI_SHARED2_IRQ;
-		case 4:
-			return MACEPCI_SHARED0_IRQ;
-		case 1:
-		default:
-			return MACEPCI_SLOT2_IRQ;
-		}
-	default:
-		return 0;
-	}
-}
-
-/*
- * It's not entirely clear what this does in a system with no bridges.
- * In any case, bridges are not supported by Linux in O2.
- */
-static u8 __init macepci_swizzle (struct pci_dev *dev, u8 *pinp)
-{
-	if (PCI_SLOT (dev->devfn) == 2)
-		*pinp = 2;
-	else
-		*pinp = 1;
-	return PCI_SLOT (dev->devfn);
-}
-
-/* All devices are enabled during initialization. */
-int pcibios_enable_device (struct pci_dev *dev)
-{
-	return PCIBIOS_SUCCESSFUL;
-}
-
-char * __init pcibios_setup (char *str)
-{
-	return str;
-}
-
-void __init pcibios_align_resource (void *data, struct resource *res,
-				    unsigned long size)
-{
-}
-
-void __init pcibios_update_resource (struct pci_dev *dev, struct resource *root,
-				     struct resource *res, int resource)
-{
-}
-
-void __init pcibios_update_irq (struct pci_dev *dev, int irq)
-{
-	pci_write_config_byte (dev, PCI_INTERRUPT_LINE, irq);
-}
-
-void __init pcibios_fixup_bus (struct pci_bus *b)
-{
-	pci_fixup_irqs (macepci_swizzle, macepci_map_irq);
-}
-
-/* XXX anybody know what this is supposed to do? */
-void __init pcibios_fixup_pbus_ranges(struct pci_bus * bus,
-				      struct pbus_set_ranges_data * ranges)
-{
-	ranges->io_start -= bus->resource[0]->start;
-	ranges->io_end -= bus->resource[0]->start;
-	ranges->mem_start -= bus->resource[1]->start;
-	ranges->mem_end -= bus->resource[1]->start;
-}
-
-/*
- * Handle errors from the bridge.  This includes master and target aborts,
- * various command and address errors, and the interrupt test.  This gets
- * registered on the bridge error irq.  It's conceivable that some of these
- * conditions warrant a panic.  Anybody care to say which ones?
- */
-void macepci_error (int irq, void *dev, struct pt_regs *regs) {
-	u32 flags, error_addr;
-	char space;
-
-	flags = mace_read_32 (MACEPCI_ERROR_FLAGS);
-	error_addr = mace_read_32 (MACEPCI_ERROR_ADDR);
-
-	if (flags & MACEPCI_ERROR_MEMORY_ADDR)
-		space = 'M';
-	else if (flags & MACEPCI_ERROR_CONFIG_ADDR)
-		space = 'C';
-	else space = 'X';
-	
-	if (flags & MACEPCI_ERROR_MASTER_ABORT) {
-		printk ("MACEPCI: Master abort at 0x%08x (%c)\n", error_addr,
-			space);
-		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
-			       & ~MACEPCI_ERROR_MASTER_ABORT);
-	}
-	if (flags & MACEPCI_ERROR_TARGET_ABORT) {
-		printk ("MACEPCI: Target abort at 0x%08x (%c)\n", error_addr,
-			space);
-		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
-			       & ~MACEPCI_ERROR_TARGET_ABORT);
-	}
-	if (flags & MACEPCI_ERROR_DATA_PARITY_ERR) {
-		printk ("MACEPCI: Data parity error at 0x%08x (%c)\n",
-			error_addr, space);
-		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
-			       & ~MACEPCI_ERROR_DATA_PARITY_ERR);
-	}
-	if (flags & MACEPCI_ERROR_RETRY_ERR) {
-		printk ("MACEPCI: Retry error at 0x%08x (%c)\n", error_addr,
-			space);
-		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
-			       & ~MACEPCI_ERROR_RETRY_ERR);
-	}
-	if (flags & MACEPCI_ERROR_ILLEGAL_CMD) {
-		printk ("MACEPCI: Illegal command at 0x%08x (%c)\n",
-			error_addr, space);
-		mace_write_32 (MACEPCI_ERROR_FLAGS,
-			       flags & ~MACEPCI_ERROR_ILLEGAL_CMD);
-	}
-	if (flags & MACEPCI_ERROR_SYSTEM_ERR) {
-		printk ("MACEPCI: System error at 0x%08x (%c)\n",
-			error_addr, space);
-		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
-			       & ~MACEPCI_ERROR_SYSTEM_ERR);
-	}
-	if (flags & MACEPCI_ERROR_PARITY_ERR) {
-		printk ("MACEPCI: Parity error at 0x%08x (%c)\n", error_addr,
-			space);
-		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
-			       & ~MACEPCI_ERROR_PARITY_ERR);
-	}
-	if (flags & MACEPCI_ERROR_OVERRUN) {
-		printk ("MACEPCI: Overrun error at 0x%08x (%c)\n",
-			error_addr, space);
-		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
-			       & ~MACEPCI_ERROR_OVERRUN);
-	}
-	if (flags & MACEPCI_ERROR_SIG_TABORT) {
-		printk ("MACEPCI: Signaled target abort (clearing)\n");
-		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
-			       & ~MACEPCI_ERROR_SIG_TABORT);
-	}
-	if (flags & MACEPCI_ERROR_INTERRUPT_TEST) {
-		printk ("MACEPCI: Interrupt test triggered (clearing)\n");
-		mace_write_32 (MACEPCI_ERROR_FLAGS, flags
-			       & ~MACEPCI_ERROR_INTERRUPT_TEST);
-	}
-}
-unsigned __init int pcibios_assign_all_busses(void)
-{
-	return 0;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip32/ip32-reset.c linux-2.4.20/arch/mips64/sgi-ip32/ip32-reset.c
--- linux-2.4.19/arch/mips64/sgi-ip32/ip32-reset.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip32/ip32-reset.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,34 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 Keith M Wesolowski
- * Copyright (C) 2001 Paul Mundt
- */
-#include <linux/init.h>
-
-#include <asm/reboot.h>
-#include <asm/sgialib.h>
-
-static void ip32_machine_restart(char *cmd)
-{
-	ArcReboot();
-}
-
-static inline void ip32_machine_halt(void)
-{
-	ArcEnterInteractiveMode();
-}
-
-static void ip32_machine_power_off(void)
-{
-	ip32_machine_halt();
-}
-
-void __init ip32_reboot_setup(void)
-{
-	_machine_restart = ip32_machine_restart;
-	_machine_halt = ip32_machine_halt;
-	_machine_power_off = ip32_machine_power_off;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip32/ip32-rtc.c linux-2.4.20/arch/mips64/sgi-ip32/ip32-rtc.c
--- linux-2.4.19/arch/mips64/sgi-ip32/ip32-rtc.c	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip32/ip32-rtc.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,32 +0,0 @@
-/*
- * RTC routines for IP32 style attached Dallas chip.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000 Harald Koerfgen
- */
-#include <linux/mc146818rtc.h>
-#include <asm/ip32/mace.h>
-
-static unsigned char ip32_rtc_read_data(unsigned long addr)
-{
-	return (unsigned char) mace_read_8 (MACEISA_RTC_BASE + (addr << 8));
-}
-
-static void ip32_rtc_write_data(unsigned char data, unsigned long addr)
-{
-	mace_write_8 (MACEISA_RTC_BASE + (addr << 8), data);
-}
-
-static int ip32_rtc_bcd_mode(void)
-{
-	return 0;
-}
-
-struct rtc_ops ip32_rtc_ops = {
-	&ip32_rtc_read_data,
-	&ip32_rtc_write_data,
-	&ip32_rtc_bcd_mode
-};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip32/ip32-setup.c linux-2.4.20/arch/mips64/sgi-ip32/ip32-setup.c
--- linux-2.4.19/arch/mips64/sgi-ip32/ip32-setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip32/ip32-setup.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,102 +0,0 @@
-/*
- * IP32 basic setup
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000 Harald Koerfgen
- */
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/mc146818rtc.h>
-#include <linux/param.h>
-#include <linux/init.h>
-
-#include <asm/time.h>
-#include <asm/mipsregs.h>
-#include <asm/bootinfo.h>
-#include <asm/mmu_context.h>
-#include <asm/ip32/crime.h>
-#include <asm/ip32/mace.h>
-#include <asm/ip32/ip32_ints.h>
-#include <asm/sgialib.h>
-
-extern struct rtc_ops ip32_rtc_ops;
-extern u32 cc_interval;
-
-#ifdef CONFIG_SGI_O2MACE_ETH
-
-/*
- * This is taken care of in here 'cause they say using Arc later on is
- * problematic
- */
-extern char o2meth_eaddr[8];
-static inline unsigned char str2hexnum(unsigned char c)
-{
-	if (c >= '0' && c <= '9')
-		return c - '0';
-	if (c >= 'a' && c <= 'f')
-		return c - 'a' + 10;
-	return 0; /* foo */
-}
-
-static inline void str2eaddr(unsigned char *ea, unsigned char *str)
-{
-	int i;
-
-	for (i = 0; i < 6; i++) {
-		unsigned char num;
-
-		if(*str == ':')
-			str++;
-		num = str2hexnum(*str++) << 4;
-		num |= (str2hexnum(*str++));
-		ea[i] = num;
-	}
-}
-#endif
-
-extern void ip32_time_init(void);
-
-void __init ip32_setup(void)
-{
-#ifdef CONFIG_SERIAL_CONSOLE
-	char *ctype;
-#endif
-	TLBMISS_HANDLER_SETUP ();
-
-	mips_io_port_base = UNCACHEDADDR(MACEPCI_HI_IO);;
-
-#ifdef CONFIG_SERIAL_CONSOLE
-	ctype = ArcGetEnvironmentVariable("console");
-	if (*ctype == 'd') {
-		if (ctype[1] == '2')
-			console_setup ("ttyS1");
-		else
-			console_setup ("ttyS0");
-	}
-#endif
-#ifdef CONFIG_SGI_O2MACE_ETH
-	{
-		char *mac=ArcGetEnvironmentVariable("eaddr");
-		str2eaddr(o2meth_eaddr, mac);
-	}
-#endif
-
-#ifdef CONFIG_VT
-	conswitchp = &dummy_con;
-#endif
-
-	rtc_ops = &ip32_rtc_ops;
-	board_time_init = ip32_time_init;
-
-	crime_init ();
-}
-
-int __init page_is_ram (unsigned long pagenr)
-{
-	/* XXX: to do? */
-	return 1;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/sgi-ip32/ip32-timer.c linux-2.4.20/arch/mips64/sgi-ip32/ip32-timer.c
--- linux-2.4.19/arch/mips64/sgi-ip32/ip32-timer.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/sgi-ip32/ip32-timer.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,238 +0,0 @@
-/*
- * IP32 timer calibration
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 Keith M Wesolowski
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/mc146818rtc.h>
-#include <linux/timex.h>
-
-#include <asm/mipsregs.h>
-#include <asm/param.h>
-#include <asm/ip32/crime.h>
-#include <asm/ip32/ip32_ints.h>
-#include <asm/bootinfo.h>
-#include <asm/cpu.h>
-#include <asm/mipsregs.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-extern volatile unsigned long wall_jiffies;
-extern rwlock_t xtime_lock;
-
-u32 cc_interval;
-
-/* Cycle counter value at the previous timer interrupt.. */
-static unsigned int timerhi, timerlo;
-
-/* An arbitrary time; this can be decreased if reliability looks good */
-#define WAIT_MS 10
-#define PER_MHZ (1000000 / 2 / HZ)
-/*
- * Change this if you have some constant time drift
- */
-#define USECS_PER_JIFFY (1000000/HZ)
-
-
-void __init ip32_timer_setup (struct irqaction *irq)
-{
-	u64 crime_time;
-	u32 cc_tick;
-
-	printk("Calibrating system timer... ");
-
-	crime_time = crime_read_64 (CRIME_TIME) & CRIME_TIME_MASK;
-	cc_tick = read_32bit_cp0_register (CP0_COUNT);
-
-	while ((crime_read_64 (CRIME_TIME) & CRIME_TIME_MASK) - crime_time 
-		< WAIT_MS * 1000000 / CRIME_NS_PER_TICK)
-		;
-	cc_tick = read_32bit_cp0_register (CP0_COUNT) - cc_tick;
-	cc_interval = cc_tick / HZ * (1000 / WAIT_MS);
-	/* The round-off seems unnecessary; in testing, the error of the
-	 * above procedure is < 100 ticks, which means it gets filtered
-	 * out by the HZ adjustment. 
-	 */
-	cc_interval = (cc_interval / PER_MHZ) * PER_MHZ;
-
-	printk("%d MHz CPU detected\n", (int) (cc_interval / PER_MHZ));
-
-	setup_irq (CLOCK_IRQ, irq);
-}
-
-struct irqaction irq0  = { NULL, SA_INTERRUPT, 0,
-			   "timer", NULL, NULL};
-
-void cc_timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-	u32 count;
-
-	/*
-	 * The cycle counter is only 32 bit which is good for about
-	 * a minute at current count rates of upto 150MHz or so.
-	 */
-	count = read_32bit_cp0_register(CP0_COUNT);
-	timerhi += (count < timerlo);	/* Wrap around */
-	timerlo = count;
-
-	write_32bit_cp0_register (CP0_COMPARE, 
-				  (u32) (count + cc_interval));
-	kstat.irqs[0][irq]++;
-	do_timer (regs);
-
-	if (!jiffies)
-	{
-		/*
-		 * If jiffies has overflowed in this timer_interrupt we must
-		 * update the timer[hi]/[lo] to make do_fast_gettimeoffset()
-		 * quotient calc still valid. -arca
-		 */
-		timerhi = timerlo = 0;
-	}
-}
-
-/*
- * On MIPS only R4000 and better have a cycle counter.
- *
- * FIXME: Does playing with the RP bit in c0_status interfere with this code?
- */
-static unsigned long do_gettimeoffset(void)
-{
-	u32 count;
-	unsigned long res, tmp;
-
-	/* Last jiffy when do_fast_gettimeoffset() was called. */
-	static unsigned long last_jiffies;
-	u32 quotient;
-
-	/*
-	 * Cached "1/(clocks per usec)*2^32" value.
-	 * It has to be recalculated once each jiffy.
-	 */
-	static u32 cached_quotient;
-
-	tmp = jiffies;
-
-	quotient = cached_quotient;
-
-	if (tmp && last_jiffies != tmp) {
-		last_jiffies = tmp;
-		__asm__(".set\tnoreorder\n\t"
-			".set\tnoat\n\t"
-			".set\tmips3\n\t"
-			"lwu\t%0,%2\n\t"
-			"dsll32\t$1,%1,0\n\t"
-			"or\t$1,$1,%0\n\t"
-			"ddivu\t$0,$1,%3\n\t"
-			"mflo\t$1\n\t"
-			"dsll32\t%0,%4,0\n\t"
-			"nop\n\t"
-			"ddivu\t$0,%0,$1\n\t"
-			"mflo\t%0\n\t"
-			".set\tmips0\n\t"
-			".set\tat\n\t"
-			".set\treorder"
-			:"=&r" (quotient)
-			:"r" (timerhi),
-			 "m" (timerlo),
-			 "r" (tmp),
-			 "r" (USECS_PER_JIFFY)
-			:"$1");
-		cached_quotient = quotient;
-	}
-
-	/* Get last timer tick in absolute kernel time */
-	count = read_32bit_cp0_register(CP0_COUNT);
-
-	/* .. relative to previous jiffy (32 bits is enough) */
-	count -= timerlo;
-
-	__asm__("multu\t%1,%2\n\t"
-		"mfhi\t%0"
-		:"=r" (res)
-		:"r" (count),
-		 "r" (quotient));
-
-	/*
- 	 * Due to possible jiffies inconsistencies, we need to check 
-	 * the result so that we'll get a timer that is monotonic.
-	 */
-	if (res >= USECS_PER_JIFFY)
-		res = USECS_PER_JIFFY-1;
-
-	return res;
-}
-
-void __init ip32_time_init(void)
-{
-	unsigned int epoch = 0, year, mon, day, hour, min, sec;
-	int i;
-
-	/* The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-	/* read RTC exactly on falling edge of update flag */
-	for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
-		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
-			break;
-	for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms */
-		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
-			break;
-	do { /* Isn't this overkill ? UIP above should guarantee consistency */
-		sec = CMOS_READ(RTC_SECONDS);
-		min = CMOS_READ(RTC_MINUTES);
-		hour = CMOS_READ(RTC_HOURS);
-		day = CMOS_READ(RTC_DAY_OF_MONTH);
-		mon = CMOS_READ(RTC_MONTH);
-		year = CMOS_READ(RTC_YEAR);
-	} while (sec != CMOS_READ(RTC_SECONDS));
-	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-		BCD_TO_BIN(sec);
-		BCD_TO_BIN(min);
-		BCD_TO_BIN(hour);
-		BCD_TO_BIN(day);
-		BCD_TO_BIN(mon);
-		BCD_TO_BIN(year);
-	}
-
-	/* Attempt to guess the epoch.  This is the same heuristic as in
-	 * rtc.c so no stupid things will happen to timekeeping.  Who knows,
-	 * maybe Ultrix also uses 1952 as epoch ...
-	 */
-	if (year > 10 && year < 44)
-		epoch = 1980;
-	else if (year < 96)
-		epoch = 1952;
-	year += epoch;
-
-	write_lock_irq (&xtime_lock);
-	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-	xtime.tv_usec = 0;
-	write_unlock_irq (&xtime_lock);
-
-	write_32bit_cp0_register(CP0_COUNT, 0);
-	irq0.handler = cc_timer_interrupt;
-
-	ip32_timer_setup (&irq0);
-
-#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
-	/* Set ourselves up for future interrupts */
-        write_32bit_cp0_register(CP0_COMPARE,
-				 read_32bit_cp0_register(CP0_COUNT)
-				 + cc_interval);
-        change_cp0_status(ST0_IM, ALLINTS);
-	sti ();
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/tools/Makefile linux-2.4.20/arch/mips64/tools/Makefile
--- linux-2.4.19/arch/mips64/tools/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/mips64/tools/Makefile	1970-01-01 00:00:00.000000000 +0000
@@ -1,26 +0,0 @@
-#
-# Makefile for MIPS kernel build tools.
-#
-# Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
-# Copyright (C) 1997, 1999 Ralf Baechle (ralf@gnu.org)
-# Copyright (C) 1999 Silicon Graphics, Inc.
-#
-TARGET	:= $(TOPDIR)/include/asm-$(ARCH)/offset.h
-
-USE_STANDARD_AS_RULE := true
-
-$(TARGET): offset.h
-	cmp -s $^ $@ || (cp $^ $(TARGET).new && mv $(TARGET).new $(TARGET))
-
-offset.h: offset.s
-	sed -n '/^@@@/s///p' $^ >$@
-
-offset.s: offset.c $(TOPDIR)/include/linux/autoconf.h
-
-clean:
-	rm -f offset.[hs] $(TARGET).new
-	
-mrproper: clean
-	rm -f $(TARGET)
-
-include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/mips64/tools/offset.c linux-2.4.20/arch/mips64/tools/offset.c
--- linux-2.4.19/arch/mips64/tools/offset.c	2000-07-28 01:36:54.000000000 +0000
+++ linux-2.4.20/arch/mips64/tools/offset.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,150 +0,0 @@
-/*
- * offset.c: Calculate pt_regs and task_struct offsets.
- *
- * Copyright (C) 1996 David S. Miller
- * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- */
-#include <linux/types.h>
-#include <linux/sched.h>
-
-#include <asm/ptrace.h>
-#include <asm/processor.h>
-
-#define text(t) __asm__("\n@@@" t)
-#define _offset(type, member) (&(((type *)NULL)->member))
-
-#define offset(string, ptr, member) \
-	__asm__("\n@@@" string "%0" : : "i" (_offset(ptr, member)))
-#define size(string, size) \
-	__asm__("\n@@@" string "%0" : : "i" (sizeof(size)))
-#define linefeed text("")
-
-text("/* DO NOT TOUCH, AUTOGENERATED BY OFFSET.C */");
-linefeed;
-text("#ifndef _MIPS_OFFSET_H");
-text("#define _MIPS_OFFSET_H");
-linefeed;
-
-void output_ptreg_defines(void)
-{
-	text("/* MIPS pt_regs offsets. */");
-	offset("#define PT_R0     ", struct pt_regs, regs[0]);
-	offset("#define PT_R1     ", struct pt_regs, regs[1]);
-	offset("#define PT_R2     ", struct pt_regs, regs[2]);
-	offset("#define PT_R3     ", struct pt_regs, regs[3]);
-	offset("#define PT_R4     ", struct pt_regs, regs[4]);
-	offset("#define PT_R5     ", struct pt_regs, regs[5]);
-	offset("#define PT_R6     ", struct pt_regs, regs[6]);
-	offset("#define PT_R7     ", struct pt_regs, regs[7]);
-	offset("#define PT_R8     ", struct pt_regs, regs[8]);
-	offset("#define PT_R9     ", struct pt_regs, regs[9]);
-	offset("#define PT_R10    ", struct pt_regs, regs[10]);
-	offset("#define PT_R11    ", struct pt_regs, regs[11]);
-	offset("#define PT_R12    ", struct pt_regs, regs[12]);
-	offset("#define PT_R13    ", struct pt_regs, regs[13]);
-	offset("#define PT_R14    ", struct pt_regs, regs[14]);
-	offset("#define PT_R15    ", struct pt_regs, regs[15]);
-	offset("#define PT_R16    ", struct pt_regs, regs[16]);
-	offset("#define PT_R17    ", struct pt_regs, regs[17]);
-	offset("#define PT_R18    ", struct pt_regs, regs[18]);
-	offset("#define PT_R19    ", struct pt_regs, regs[19]);
-	offset("#define PT_R20    ", struct pt_regs, regs[20]);
-	offset("#define PT_R21    ", struct pt_regs, regs[21]);
-	offset("#define PT_R22    ", struct pt_regs, regs[22]);
-	offset("#define PT_R23    ", struct pt_regs, regs[23]);
-	offset("#define PT_R24    ", struct pt_regs, regs[24]);
-	offset("#define PT_R25    ", struct pt_regs, regs[25]);
-	offset("#define PT_R26    ", struct pt_regs, regs[26]);
-	offset("#define PT_R27    ", struct pt_regs, regs[27]);
-	offset("#define PT_R28    ", struct pt_regs, regs[28]);
-	offset("#define PT_R29    ", struct pt_regs, regs[29]);
-	offset("#define PT_R30    ", struct pt_regs, regs[30]);
-	offset("#define PT_R31    ", struct pt_regs, regs[31]);
-	offset("#define PT_LO     ", struct pt_regs, lo);
-	offset("#define PT_HI     ", struct pt_regs, hi);
-	offset("#define PT_EPC    ", struct pt_regs, cp0_epc);
-	offset("#define PT_BVADDR ", struct pt_regs, cp0_badvaddr);
-	offset("#define PT_STATUS ", struct pt_regs, cp0_status);
-	offset("#define PT_CAUSE  ", struct pt_regs, cp0_cause);
-	size("#define PT_SIZE   ", struct pt_regs);
-	linefeed;
-}
-
-void output_task_defines(void)
-{
-	text("/* MIPS task_struct offsets. */");
-	offset("#define TASK_STATE         ", struct task_struct, state);
-	offset("#define TASK_FLAGS         ", struct task_struct, flags);
-	offset("#define TASK_SIGPENDING    ", struct task_struct, sigpending);
-	offset("#define TASK_NEED_RESCHED  ", struct task_struct, need_resched);
-	offset("#define TASK_PTRACE        ", struct task_struct, ptrace);
-	offset("#define TASK_COUNTER       ", struct task_struct, counter);
-	offset("#define TASK_NICE          ", struct task_struct, nice);
-	offset("#define TASK_MM            ", struct task_struct, mm);
-	offset("#define TASK_PROCESSOR     ", struct task_struct, processor);
-	size("#define TASK_STRUCT_SIZE   ", struct task_struct);
-	linefeed;
-}
-
-void output_thread_defines(void)
-{
-	text("/* MIPS specific thread_struct offsets. */");
-	offset("#define THREAD_REG16   ", struct task_struct, thread.reg16);
-	offset("#define THREAD_REG17   ", struct task_struct, thread.reg17);
-	offset("#define THREAD_REG18   ", struct task_struct, thread.reg18);
-	offset("#define THREAD_REG19   ", struct task_struct, thread.reg19);
-	offset("#define THREAD_REG20   ", struct task_struct, thread.reg20);
-	offset("#define THREAD_REG21   ", struct task_struct, thread.reg21);
-	offset("#define THREAD_REG22   ", struct task_struct, thread.reg22);
-	offset("#define THREAD_REG23   ", struct task_struct, thread.reg23);
-	offset("#define THREAD_REG29   ", struct task_struct, thread.reg29);
-	offset("#define THREAD_REG30   ", struct task_struct, thread.reg30);
-	offset("#define THREAD_REG31   ", struct task_struct, thread.reg31);
-	offset("#define THREAD_STATUS  ", struct task_struct, \
-	       thread.cp0_status);
-	offset("#define THREAD_FPU     ", struct task_struct, thread.fpu);
-	offset("#define THREAD_BVADDR  ", struct task_struct, \
-	       thread.cp0_badvaddr);
-	offset("#define THREAD_BUADDR  ", struct task_struct, \
-	       thread.cp0_baduaddr);
-	offset("#define THREAD_ECODE   ", struct task_struct, \
-	       thread.error_code);
-	offset("#define THREAD_TRAPNO  ", struct task_struct, thread.trap_no);
-	offset("#define THREAD_MFLAGS  ", struct task_struct, thread.mflags);
-	offset("#define THREAD_CURDS   ", struct task_struct, \
-	       thread.current_ds);
-	offset("#define THREAD_TRAMP   ", struct task_struct, \
-	       thread.irix_trampoline);
-	offset("#define THREAD_OLDCTX  ", struct task_struct, \
-	       thread.irix_oldctx);
-	linefeed;
-}
-
-void output_mm_defines(void)
-{
-	text("/* Linux mm_struct offsets. */");
-	offset("#define MM_USERS      ", struct mm_struct, mm_users);
-	offset("#define MM_PGD        ", struct mm_struct, pgd);
-	offset("#define MM_CONTEXT    ", struct mm_struct, context);
-	linefeed;
-}
-
-void output_sc_defines(void)
-{
-	text("/* Linux sigcontext offsets. */");
-	offset("#define SC_REGS       ", struct sigcontext, sc_regs);
-	offset("#define SC_FPREGS     ", struct sigcontext, sc_fpregs);
-	offset("#define SC_MDHI       ", struct sigcontext, sc_mdhi);
-	offset("#define SC_MDLO       ", struct sigcontext, sc_mdlo);
-	offset("#define SC_PC         ", struct sigcontext, sc_pc);
-	offset("#define SC_STATUS     ", struct sigcontext, sc_status);
-	offset("#define SC_OWNEDFP    ", struct sigcontext, sc_ownedfp);
-	offset("#define SC_FPC_CSR    ", struct sigcontext, sc_fpc_csr);
-	offset("#define SC_FPC_EIR    ", struct sigcontext, sc_fpc_eir);
-	offset("#define SC_CAUSE      ", struct sigcontext, sc_cause);
-	offset("#define SC_BADVADDR   ", struct sigcontext, sc_badvaddr);
-	linefeed;
-}
-
-text("#endif /* !(_MIPS_OFFSET_H) */");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/Makefile linux-2.4.20/arch/parisc/Makefile
--- linux-2.4.19/arch/parisc/Makefile	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/Makefile	2002-10-29 11:18:37.000000000 +0000
@@ -17,12 +17,28 @@
 # Mike Shaver, Helge Deller and Martin K. Petersen
 #
 
+ifdef CONFIG_PARISC64
+LINKFLAGS =-T $(TOPDIR)/arch/parisc/vmlinux64.lds $(LDFLAGS)
+CROSS_COMPILE := hppa64-linux-
+UTS_MACHINE := parisc64
+#CFLAGS += -b hppa64-linux
+
+else
+LINKFLAGS =-T $(TOPDIR)/arch/parisc/vmlinux.lds $(LDFLAGS)
+MACHINE	:= $(subst 64,,$(shell uname -m))
+ifneq (${MACHINE},parisc)
+# cross compilation
+CROSS_COMPILE := hppa-linux-
+endif
+endif
+
+OFFSET_H := $(TOPDIR)/include/asm-parisc/offset.h
 FINAL_LD=$(CROSS_COMPILE)ld --warn-common --warn-section-align 
 
 CPP=$(CC) -E
 OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
 LDFLAGS =
-LINKFLAGS =-T $(TOPDIR)/arch/parisc/vmlinux.lds $(LDFLAGS)
+
 
 CFLAGS_PIPE := -pipe
 CFLAGS_NSR  := -fno-strength-reduce
@@ -32,25 +48,48 @@
 # enable them by default.
 CFLAGS += -mno-space-regs -mfast-indirect-calls
 
-# If we become able to compile for specific platforms, this should be
-# conditional on that.
-CFLAGS += -mschedule=7200
-
 # No fixed-point multiply
 CFLAGS += -mdisable-fpregs
 
-HEAD = arch/parisc/kernel/head.o 
+# Without this, "ld -r" results in .text sections that are too big
+# (> 0x40000) for branches to reach stubs.
+CFLAGS += -ffunction-sections
+
+# select which processor to optimise for
+ifdef CONFIG_PA7100
+CFLAGS += -march=1.1 -mschedule=7100
+endif
+
+ifdef CONFIG_PA7200
+CFLAGS += -march=1.1 -mschedule=7200
+endif
+
+ifdef CONFIG_PA7100LC
+CFLAGS += -march=1.1 -mschedule=7100LC
+endif
+
+ifdef CONFIG_PA8X00
+CFLAGS += -march=2.0 -mschedule=8000
+endif
+
+ASFLAGS := -D__ASSEMBLY__ -traditional
+
+HEAD := arch/parisc/kernel/head.o 
 
 SUBDIRS := $(SUBDIRS) $(addprefix arch/parisc/, tools kernel mm lib hpux)
 CORE_FILES :=  $(addprefix arch/parisc/, kernel/pdc_cons.o kernel/process.o \
 	lib/lib.a mm/mm.o kernel/kernel.o hpux/hpux.o) \
 	$(CORE_FILES) arch/parisc/kernel/init_task.o
+CLEAN_FILES := $(CLEAN_FILES) arch/parisc/tools/offset.[hs] 
+
+ifdef CONFIG_PARISC64
+HEAD := arch/parisc/kernel/head64.o
+endif
+
 LIBS := `$(CC) -print-libgcc-file-name` $(TOPDIR)/arch/parisc/lib/lib.a $(LIBS) 
 
-ifdef CONFIG_MATH_EMULATION
 SUBDIRS := $(SUBDIRS) arch/parisc/math-emu
-DRIVERS := $(DRIVERS) arch/parisc/math-emu/math.a
-endif
+DRIVERS := $(DRIVERS) arch/parisc/math-emu/math.o
 
 ifdef CONFIG_KWDB
 SUBDIRS := $(SUBDIRS) arch/parisc/kdb
@@ -67,7 +106,7 @@
 	$(MAKE) linuxsubdirs SUBDIRS=arch/parisc/mm
 
 palo: vmlinux
-	export TOPDIR=`pwd`; export CONFIG_STI_CONSOLE=$(CONFIG_STI_CONSOLE); \
+	export TOPDIR=`pwd`; \
 	unset STRIP LDFLAGS CPP CPPFLAGS AFLAGS CFLAGS CC LD; cd ../palo && make lifimage
 
 Image: palo
@@ -84,8 +123,14 @@
 
 install: 
 
+archmrproper:
+	rm -f $(OFFSET_H)
+
 archclean:
 
-archmrproper:
+archdep: $(OFFSET_H)
+
+$(OFFSET_H): include/linux/version.h
+	$(MAKE) -C $(TOPDIR)/arch/$(ARCH)/tools all
 
-archdep:
+.PHONY: $(OFFSET_H)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/config.in linux-2.4.20/arch/parisc/config.in
--- linux-2.4.19/arch/parisc/config.in	2001-04-18 00:19:25.000000000 +0000
+++ linux-2.4.20/arch/parisc/config.in	2002-10-29 11:18:51.000000000 +0000
@@ -16,98 +16,106 @@
 endmenu
 
 mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ] ; then
+  bool 'Set version information on all module symbols' CONFIG_MODVERSIONS
+  bool 'Kernel module loader' CONFIG_KMOD
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Processor type'
+choice 'Processor family' \
+	"PA7000/PA7100		CONFIG_PA7100 \
+	 PA7200			CONFIG_PA7200 \
+	 PA7100LC/PA7300LC	CONFIG_PA7100LC \
+	 PA8x00			CONFIG_PA8X00" PA7000
+
+if [ "$CONFIG_PA8X00" = "y" ] ; then
+   define_bool CONFIG_PA20 y
+   bool '64-bit kernel' CONFIG_PARISC64
+   dep_bool '32-bit PDC' CONFIG_PDC_NARROW $CONFIG_PARISC64
+else
+   define_bool CONFIG_PA11 y
+fi
+endmenu
+
+mainmenu_option next_comment
 comment 'General options'
 
-# bool 'Symmetric multi-processing support' CONFIG_SMP
-define_bool CONFIG_SMP n
+bool 'Symmetric multi-processing support' CONFIG_SMP
+bool 'Chassis LCD and LED support' CONFIG_CHASSIS_LCD_LED
 
 bool 'Kernel Debugger support' CONFIG_KWDB
 # define_bool CONFIG_KWDB n
 
-# bool 'GSC/Gecko bus support' CONFIG_GSC y
-define_bool CONFIG_GSC y
-
-bool 'U2/Uturn I/O MMU' CONFIG_IOMMU_CCIO y
-bool 'LASI I/O support' CONFIG_GSC_LASI y
-
-bool 'PCI bus support' CONFIG_PCI y
+bool 'U2/Uturn I/O MMU' CONFIG_IOMMU_CCIO
+bool 'VSC/GSC/HSC bus support' CONFIG_GSC
+dep_bool '  Lasi I/O support' CONFIG_GSC_LASI $CONFIG_GSC
+dep_bool '  Wax I/O support' CONFIG_GSC_WAX $CONFIG_GSC
+
+dep_bool 'EISA support' CONFIG_EISA $CONFIG_GSC
+define_bool CONFIG_ISA $CONFIG_EISA
+bool 'PCI support' CONFIG_PCI
 
 if [ "$CONFIG_PCI" = "y" ]; then
-	bool 'GSCtoPCI/DINO PCI support' CONFIG_GSC_DINO y
-	bool 'LBA/Elroy PCI support' CONFIG_PCI_LBA n
-fi 
+   dep_bool '  GSCtoPCI/Dino PCI support' CONFIG_GSC_DINO $CONFIG_GSC
+   bool '  LBA/Elroy PCI support' CONFIG_PCI_LBA
+   define_bool CONFIG_IOSAPIC $CONFIG_PCI_LBA
+   define_bool CONFIG_IOMMU_SBA $CONFIG_PCI_LBA
 
-if [ "$CONFIG_PCI_LBA" = "y" ]; then
-	define_bool CONFIG_IOSAPIC y
-	define_bool CONFIG_IOMMU_SBA y
-fi
+#   bool '  EPIC PCI support' CONFIG_PCI_EPIC n
+   bool '  SuperIO support' CONFIG_SUPERIO
+fi 
 
-#
-# if [ "$CONFIG_PCI_EPIC" = "y" ]; then...
-#
+source drivers/pci/Config.in
 
 endmenu
 
 mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-  bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
-  bool 'Kernel module loader' CONFIG_KMOD
-fi
-endmenu
-
-mainmenu_option next_comment
 comment 'General setup'
 
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+
 bool 'Networking support' CONFIG_NET
 
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
 bool 'Sysctl support' CONFIG_SYSCTL
-tristate 'Kernel support for SOM binaries' CONFIG_BINFMT_SOM
+define_bool CONFIG_KCORE_ELF y
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for SOM binaries' CONFIG_BINFMT_SOM
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
-fi
+
+# anyone want to get ACPI working on PA/RISC?
+define_bool CONFIG_PM n
 
 endmenu
 
-##source drivers/parport/Config.in
-mainmenu_option next_comment
-comment 'Parallel port support'
+source drivers/parport/Config.in
 
-tristate 'Parallel port support' CONFIG_PARPORT
-if [ "$CONFIG_PARPORT" != "n" ]; then
-   if [ "$CONFIG_PCI" = "y" ]; then
-     dep_tristate '  PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
-     if [ "$CONFIG_PARPORT_PC" != "n" ]; then
-        bool '    Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO
-        if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-           bool '    SuperIO chipset support (EXPERIMENTAL)' CONFIG_PARPORT_PC_SUPERIO
-        fi
-     fi
-   fi
-   if [ "$CONFIG_GSC_LASI" = "y" ]; then
-      dep_tristate '  LASI/ASP builtin parallel-port' CONFIG_PARPORT_GSC $CONFIG_PARPORT
-   else
-      define_tristate CONFIG_PARPORT_GSC n
-   fi
+source drivers/block/Config.in
 
-   # If exactly one hardware type is selected then parport will optimise away
-   # support for loading any others.  Defeat this if the user is keen.
-   bool '  Support foreign hardware' CONFIG_PARPORT_OTHER
+source drivers/md/Config.in
 
-   bool '  IEEE 1284 transfer modes' CONFIG_PARPORT_1284
+if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
 fi
-endmenu
 
+if [ "$CONFIG_SUPERIO" = "y" ]; then
+    mainmenu_option next_comment
+    comment 'ATA/IDE/MFM/RLL support'
 
-source drivers/block/Config.in
+    tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
 
-if [ "$CONFIG_NET" = "y" ]; then
-  source net/Config.in
+    if [ "$CONFIG_IDE" != "n" ]; then
+      source drivers/ide/Config.in
+    else
+      define_bool CONFIG_BLK_DEV_IDE_MODES n
+      define_bool CONFIG_BLK_DEV_HD n
+    fi
+    endmenu
 fi
 
 mainmenu_option next_comment
@@ -116,90 +124,70 @@
 tristate 'SCSI support' CONFIG_SCSI
 
 if [ "$CONFIG_SCSI" != "n" ]; then
-  comment 'SCSI support type (disk, tape, CDrom)'
-
-  dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
-  if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then
-    int  'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40
-  fi
-
-  dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
-  dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
-  if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then
-    bool '  Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
-    int  'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2
-  fi
-  dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
-
-  comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
-  bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
-  bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
-
-  mainmenu_option next_comment
-  comment 'SCSI low-level drivers'
-  if [ "$CONFIG_GSC_LASI" = "y" ]; then
-    dep_tristate 'Lasi SCSI support' CONFIG_SCSI_LASI $CONFIG_SCSI
-    dep_tristate 'Zalon SCSI support' CONFIG_SCSI_ZALON $CONFIG_SCSI
-  fi
-  if [ "$CONFIG_PCI" = "y" ]; then
-    dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI
-  fi
-  if [ "$CONFIG_SCSI_ZALON" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
-    int  '  default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
-    int  '  maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
-    int  '  synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20
-    bool '  enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE
-    bool '  use normal IO' CONFIG_SCSI_NCR53C8XX_IOMAPPED
-  fi
-  endmenu
+   source drivers/scsi/Config.in
 fi
 endmenu
 
 if [ "$CONFIG_NET" = "y" ]; then
-  mainmenu_option next_comment
-  comment 'Network device support'
+   mainmenu_option next_comment
+   comment 'Network device support'
 
-  bool 'Network device support' CONFIG_NETDEVICES
+   bool 'Network device support' CONFIG_NETDEVICES
 
-  if [ "$CONFIG_NETDEVICES" = "y" ]; then
-    if [ "$CONFIG_GSC_LASI" = "y" ]; then
-      tristate 'Lasi ethernet' CONFIG_LASI_82596
-    fi
-    source drivers/net/Config.in
-  fi
-  endmenu
+   if [ "$CONFIG_NETDEVICES" = "y" ]; then
+      source drivers/net/Config.in
+      if [ "$CONFIG_ATM" = "y" ]; then
+         source drivers/atm/Config.in
+      fi
+   fi
+   endmenu
 fi
 
+#
+# input before char - char/joystick depends on it. As does USB.
+#
+source drivers/input/Config.in
 source drivers/char/Config.in
+source drivers/hil/Config.in
+
+source drivers/media/Config.in
 
 source fs/Config.in
 
+if [ "$CONFIG_VT" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Console drivers'
+   source drivers/video/Config.in
+
+   bool 'STI console' CONFIG_STI_CONSOLE
+   if [ "$CONFIG_GSC_PS2" = "y" ]; then
+      define_bool CONFIG_DUMMY_CONSOLE y
+   fi
+   if [ "$CONFIG_STI_CONSOLE" = "y" ]; then
+      define_bool CONFIG_DUMMY_CONSOLE y
+      define_bool CONFIG_FBCON y
+      define_bool CONFIG_FBCON_FONT y
+#      define_bool CONFIG_FBCON_FONTWIDTH8_ONLY n
+      define_bool CONFIG_FONT_8x8 y
+      define_bool CONFIG_FONT_8x16 y
+      define_bool CONFIG_FONT_6x11 y
+      define_bool CONFIG_FONT_SUN12x22 y
+   fi
+   endmenu
+fi
+
 mainmenu_option next_comment
-comment 'Sound Drivers'
+comment 'Sound'
+
 tristate 'Sound card support' CONFIG_SOUND
 if [ "$CONFIG_SOUND" != "n" ]; then
    source drivers/sound/Config.in
 fi
 endmenu
 
-if [ "$CONFIG_VT" = "y" ]; then
-  mainmenu_option next_comment
-  comment 'Console drivers'
-  source drivers/video/Config.in
-
-#  bool 'IODC console' CONFIG_IODC_CONSOLE
-  bool 'STI console' CONFIG_STI_CONSOLE
-  if [ "$CONFIG_IODC_CONSOLE" = "n" ]; then
-    if [ "$CONFIG_GSC_PS2" = "y" ]; then
-      define_bool CONFIG_DUMMY_CONSOLE y
-    fi
-  fi
-  if [ "$CONFIG_STI_CONSOLE" = "y" ]; then
-    define_bool CONFIG_DUMMY_CONSOLE y
-  fi
-  endmenu
+if [ "$CONFIG_SUPERIO" = "y" ]; then
+    source drivers/usb/Config.in
 fi
-# endmenu
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
@@ -208,3 +196,4 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
 
+source lib/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/defconfig linux-2.4.20/arch/parisc/defconfig
--- linux-2.4.19/arch/parisc/defconfig	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/defconfig	2002-10-29 11:18:32.000000000 +0000
@@ -1,8 +1,10 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 CONFIG_PARISC=y
 # CONFIG_UID16 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 
 #
 # Code maturity level options
@@ -10,44 +12,70 @@
 CONFIG_EXPERIMENTAL=y
 
 #
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Processor type
+#
+# CONFIG_PA7100 is not set
+# CONFIG_PA7200 is not set
+# CONFIG_PA7100LC is not set
+# CONFIG_PA8X00 is not set
+# CONFIG_PA11 is not set
+
+#
 # General options
 #
 # CONFIG_SMP is not set
+CONFIG_CHASSIS_LCD_LED=y
 # CONFIG_KWDB is not set
-CONFIG_GSC=y
 CONFIG_IOMMU_CCIO=y
+CONFIG_GSC=y
 CONFIG_GSC_LASI=y
+CONFIG_GSC_WAX=y
+CONFIG_EISA=y
+CONFIG_ISA=y
 CONFIG_PCI=y
 CONFIG_GSC_DINO=y
 CONFIG_PCI_LBA=y
 CONFIG_IOSAPIC=y
 CONFIG_IOMMU_SBA=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
+CONFIG_SUPERIO=y
+CONFIG_PCI_NAMES=y
 
 #
 # General setup
 #
+CONFIG_HOTPLUG=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
-CONFIG_BINFMT_SOM=y
+CONFIG_KCORE_ELF=y
 CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_SOM=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_BINFMT_JAVA is not set
+# CONFIG_PM is not set
 
 #
 # Parallel port support
 #
 CONFIG_PARPORT=y
-# CONFIG_PARPORT_PC is not set
+CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_CML1=y
+# CONFIG_PARPORT_SERIAL is not set
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+# CONFIG_PARPORT_PC_PCMCIA is not set
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
 CONFIG_PARPORT_GSC=y
+# CONFIG_PARPORT_SUNBPP is not set
 # CONFIG_PARPORT_OTHER is not set
 # CONFIG_PARPORT_1284 is not set
 
@@ -60,33 +88,54 @@
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP 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
 
 #
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=y
+CONFIG_MD_RAID0=y
+CONFIG_MD_RAID1=y
+CONFIG_MD_RAID5=y
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
 # Networking options
 #
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK_DEV=y
 # CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
+CONFIG_FILTER=y
 CONFIG_UNIX=y
 CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
 CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
 CONFIG_IP_PNP_BOOTP=y
 # 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 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
 # CONFIG_DECNET is not set
@@ -106,36 +155,181 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_IDEDISK is not set
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+CONFIG_BLK_DEV_ADMA=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+CONFIG_BLK_DEV_NS87415=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
 # SCSI support
 #
 CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
 CONFIG_BLK_DEV_SD=y
 CONFIG_SD_EXTRA_DEVS=40
 CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
 CONFIG_BLK_DEV_SR=y
 # CONFIG_BLK_DEV_SR_VENDOR is not set
 CONFIG_SR_EXTRA_DEVS=2
 CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
 # CONFIG_SCSI_MULTI_LUN is not set
 # CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
 
 #
 # SCSI low-level drivers
 #
-CONFIG_SCSI_LASI=y
-CONFIG_SCSI_ZALON=y
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+CONFIG_SCSI_LASI700=y
+CONFIG_53C700_MEM_MAPPED=y
+CONFIG_53C700_LE_ON_BE=y
+CONFIG_53C700_USE_CONSISTENT=y
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_NCR53C8XX is not set
 CONFIG_SCSI_SYM53C8XX=y
+CONFIG_SCSI_ZALON=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
 CONFIG_SCSI_NCR53C8XX_SYNC=20
 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_SCSI_PCMCIA is not set
 
 #
 # Network device support
 #
 CONFIG_NETDEVICES=y
-CONFIG_LASI_82596=y
 
 #
 # ARCnet devices
@@ -145,12 +339,18 @@
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-# CONFIG_NET_SB1000 is not set
+# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
+CONFIG_LASI_82596=y
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL 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 is not set
@@ -165,23 +365,31 @@
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
-# CONFIG_DE4X5 is not set
 CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
 # CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
 # CONFIG_NE3210 is not set
 # CONFIG_ES3210 is not set
-# CONFIG_RTL8129 is not set
+# CONFIG_8139CP is not set
 # CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_NEW_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
 # CONFIG_NET_POCKET is not set
 
@@ -189,6 +397,9 @@
 # Ethernet (1000 Mbit)
 #
 # CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
@@ -217,12 +428,27 @@
 # CONFIG_WAN is not set
 
 #
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_KEYBDEV=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_GSC_PS2=y
-CONFIG_HIL=y
 CONFIG_SERIAL=y
 CONFIG_SERIAL_CONSOLE=y
 CONFIG_SERIAL_GSC=y
@@ -243,12 +469,45 @@
 # Mice
 #
 # CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+CONFIG_INPUT_SERIO=y
+# CONFIG_INPUT_SERPORT is not set
 
 #
 # Joysticks
 #
-# CONFIG_JOYSTICK is not set
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -271,27 +530,67 @@
 # CONFIG_DRM is not set
 
 #
+# PCMCIA character devices
+#
+# CONFIG_PCMCIA_SERIAL_CS is not set
+
+#
+# HIL support
+#
+CONFIG_HIL=y
+# CONFIG_HIL_KBD_BASIC is not set
+
+#
+#  HIL driver core support
+#
+CONFIG_HP_SDC=y
+# CONFIG_HP_SDC_RTC is not set
+CONFIG_HIL_MLC=y
+CONFIG_HP_SDC_MLC=y
+
+#
+#  HIL device driver
+#
+CONFIG_HIL_KBD=y
+CONFIG_HIL_PTR=y
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # File systems
 #
 # CONFIG_QUOTA is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+# 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 is not set
 CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
@@ -299,13 +598,12 @@
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS 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_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
@@ -315,13 +613,15 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
+CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
-# CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
 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
@@ -330,22 +630,60 @@
 # CONFIG_NCPFS_NFS_NS is not set
 # CONFIG_NCPFS_OS2_NS is not set
 # CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_NLS is not set
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
 
 #
-# Sound Drivers
+# Native Language Support
 #
-# CONFIG_SOUND is not set
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
 
 #
 # Console drivers
@@ -354,8 +692,171 @@
 #
 # Frame-buffer support
 #
-# CONFIG_FB is not set
-# CONFIG_STI_CONSOLE is not set
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_CLGEN is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+CONFIG_FB_STI=y
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB32=y
+CONFIG_FBCON_STI=y
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+# CONFIG_FBCON_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_STI_CONSOLE=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FBCON=y
+CONFIG_FBCON_FONT=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_FONT_6x11=y
+CONFIG_FONT_SUN12x22=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_ICH is not set
+CONFIG_SOUND_HARMONY=y
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Controllers
+#
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+# CONFIG_USB_HID is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_WACOM is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+
+#
+#   Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
 
 #
 # Kernel hacking
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/hpux/Makefile linux-2.4.20/arch/parisc/hpux/Makefile
--- linux-2.4.19/arch/parisc/hpux/Makefile	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/hpux/Makefile	2002-10-29 11:18:35.000000000 +0000
@@ -7,10 +7,7 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-all: hpux.o
 O_TARGET = hpux.o
-O_OBJS = entry_hpux.o gate.o wrappers.o fs.o ioctl.o sys_hpux.o
-
-.o.S:	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o
+obj-y := entry_hpux.o gate.o wrappers.o fs.o ioctl.o sys_hpux.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/hpux/entry_hpux.S linux-2.4.20/arch/parisc/hpux/entry_hpux.S
--- linux-2.4.19/arch/parisc/hpux/entry_hpux.S	2001-10-05 19:22:07.000000000 +0000
+++ linux-2.4.20/arch/parisc/hpux/entry_hpux.S	2002-10-29 11:18:36.000000000 +0000
@@ -1,6 +1,6 @@
-/* -----------------------------------------------------------------------------
+/*
  *
- * Native PARISC/Linux Project (http://www.puffingroup.com/parisc)
+ * Linux/PARISC Project (http://www.parisc-linux.org/)
  *
  * modified by Matthew Wilcox <willy@bofh.ai> 1999-07-26
  */
@@ -10,13 +10,13 @@
 #include <linux/linkage.h>
 #include <asm/unistd.h>
 
-
 	.text
 
 #define ENTRY_NAME(_name_) .word _name_
 
 	.align 4
 	.export hpux_call_table
+	.import hpux_unimplemented_wrapper
 hpux_call_table:
 	ENTRY_NAME(sys_ni_syscall)	/* 0 */
 	ENTRY_NAME(sys_exit)
@@ -36,7 +36,7 @@
 	ENTRY_NAME(sys_chmod)	/* 15 */
 	ENTRY_NAME(sys_chown)
 	ENTRY_NAME(hpux_brk)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_lseek)
 	ENTRY_NAME(sys_getpid)	/* 20 */
 	ENTRY_NAME(hpux_mount)
@@ -46,34 +46,34 @@
 	ENTRY_NAME(sys_stime)	/* 25 */
 	ENTRY_NAME(hpux_ptrace)
 	ENTRY_NAME(sys_alarm)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_pause)
 	ENTRY_NAME(sys_utime)	/* 30 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_access)
 	ENTRY_NAME(hpux_nice)
-	ENTRY_NAME(sys_ni_syscall)	/* 35 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 35 */
 	ENTRY_NAME(sys_sync)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_newstat)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_setpgrp3)
 	ENTRY_NAME(sys_newlstat)	/* 40 */
 	ENTRY_NAME(sys_dup)
 	ENTRY_NAME(hpux_pipe_wrapper)
 	ENTRY_NAME(sys_times)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 45 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 45 */
 	ENTRY_NAME(sys_setgid)
 	ENTRY_NAME(sys_getgid)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 50 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 50 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(hpux_ioctl)
-	ENTRY_NAME(sys_ni_syscall)	/* 55 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 55 */
 	ENTRY_NAME(sys_symlink)
 	ENTRY_NAME(hpux_utssys)
 	ENTRY_NAME(sys_readlink)
@@ -81,218 +81,218 @@
 	ENTRY_NAME(sys_umask)	/* 60 */
 	ENTRY_NAME(sys_chroot)
 	ENTRY_NAME(sys_fcntl)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 65 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 65 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(hpux_sbrk)
-	ENTRY_NAME(sys_ni_syscall)	/* 70 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 70 */
 	ENTRY_NAME(sys_mmap)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 75 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 80 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 75 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 80 */
 	ENTRY_NAME(sys_getpgid)
 	ENTRY_NAME(sys_setpgid)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 85 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(sys_setitimer)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 85 */
+	ENTRY_NAME(sys_getitimer)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_dup2)		/* 90 */
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_newfstat)
 	ENTRY_NAME(sys_select)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 95 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 100 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 105 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 110 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 115 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 95 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 100 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 105 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 110 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 115 */
 	ENTRY_NAME(sys_gettimeofday)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 120 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 120 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_fchown)
 	ENTRY_NAME(sys_fchmod)
-	ENTRY_NAME(sys_ni_syscall)	/* 125 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 125 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_rename)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 130 */
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 130 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(hpux_sysconf)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 135 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 135 */
 	ENTRY_NAME(sys_mkdir)
 	ENTRY_NAME(sys_rmdir)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 140 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 145 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 150 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 155 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 160 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 165 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 170 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 175 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 180 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 185 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 190 */
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 140 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(sys_getrlimit)
+	ENTRY_NAME(sys_setrlimit)      /* 145 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 150 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_lockf)      /* 155 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 160 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 165 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 170 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 175 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 180 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(sys_sigprocmask)      /* 185 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 190 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(hpux_getdomainname)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 195 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 195 */
+	ENTRY_NAME(hpux_statfs)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_waitpid)	/* 200 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 205 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 210 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 215 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 220 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 225 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 230 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 235 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 240 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 245 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 250 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 255 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 260 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 265 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 270 */
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 205 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 210 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 215 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 220 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 225 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 230 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 235 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 240 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 245 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 250 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 255 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 260 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 265 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 270 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_fchdir)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_accept)		/* 275 */
 	ENTRY_NAME(sys_bind)
 	ENTRY_NAME(sys_connect)
@@ -309,227 +309,227 @@
 	ENTRY_NAME(sys_setsockopt)
 	ENTRY_NAME(sys_shutdown)
 	ENTRY_NAME(sys_socket)		/* 290 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 295 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 300 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 305 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 310 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 315 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 320 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 325 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 330 */
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 295 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 300 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 305 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 310 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 315 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 320 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 325 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 330 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_lchown)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 335 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 340 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 345 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 350 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_sysfs)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 335 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 340 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 345 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 350 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_nanosleep)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 355 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 355 */
 	ENTRY_NAME(hpux_getdents)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 360 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 360 */
 	ENTRY_NAME(hpux_fstat64)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 365 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 365 */
 	ENTRY_NAME(hpux_lstat64)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(hpux_stat64)
-	ENTRY_NAME(sys_ni_syscall)	/* 370 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 375 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 380 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 385 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 390 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 395 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 400 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 405 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 410 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 415 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 420 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 425 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 430 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 435 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 440 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 445 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 450 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 455 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 460 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 465 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 470 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 475 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 480 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 485 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 490 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 495 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 500 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 505 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 510 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 370 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 375 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 380 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_setpgrp)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 385 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 390 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 395 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 400 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 405 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 410 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 415 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 420 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 425 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 430 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 435 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 440 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 445 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 450 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 455 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 460 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 465 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 470 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 475 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 480 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 485 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 490 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 495 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 500 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 505 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 510 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 .end
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/hpux/fs.c linux-2.4.20/arch/parisc/hpux/fs.c
--- linux-2.4.19/arch/parisc/hpux/fs.c	2001-08-12 22:07:55.000000000 +0000
+++ linux-2.4.20/arch/parisc/hpux/fs.c	2002-10-29 11:18:34.000000000 +0000
@@ -52,7 +52,8 @@
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
 #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
 
-static int filldir(void * __buf, const char * name, int namlen, loff_t offset, ino_t ino)
+static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
+		ino_t ino, unsigned int d_type)
 {
 	struct hpux_dirent * dirent;
 	struct getdents_callback * buf = (struct getdents_callback *) __buf;
@@ -83,42 +84,21 @@
 int hpux_getdents(unsigned int fd, struct hpux_dirent *dirent, unsigned int count)
 {
 	struct file * file;
-	struct dentry * dentry;
-	struct inode * inode;
 	struct hpux_dirent * lastdirent;
 	struct getdents_callback buf;
 	int error;
 
-	lock_kernel();
 	error = -EBADF;
 	file = fget(fd);
 	if (!file)
 		goto out;
 
-	dentry = file->f_dentry;
-	if (!dentry)
-		goto out_putf;
-
-	inode = dentry->d_inode;
-	if (!inode)
-		goto out_putf;
-
 	buf.current_dir = dirent;
 	buf.previous = NULL;
 	buf.count = count;
 	buf.error = 0;
 
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out_putf;
-
-	/*
-	 * Get the inode's semaphore to prevent changes
-	 * to the directory while we read it.
-	 */
-	down(&inode->i_sem);
-	error = file->f_op->readdir(file, &buf, filldir);
-	up(&inode->i_sem);
+	error = vfs_readdir(file, filldir, &buf);
 	if (error < 0)
 		goto out_putf;
 	error = buf.error;
@@ -131,7 +111,6 @@
 out_putf:
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/hpux/gate.S linux-2.4.20/arch/parisc/hpux/gate.S
--- linux-2.4.19/arch/parisc/hpux/gate.S	2000-12-06 19:46:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/hpux/gate.S	2002-10-29 11:18:33.000000000 +0000
@@ -1,6 +1,6 @@
-/* ------------------------------------------------------------------------------
+/*
  *
- * Linux/PARISC Project (http://www.thepuffingroup.com/parisc)
+ * Linux/PARISC Project (http://www.parisc-linux.org/)
  *
  * System call entry code Copyright (c) Matthew Wilcox 1999 <willy@bofh.ai>
  * Licensed under the GNU GPL.
@@ -8,14 +8,23 @@
  * sorry about the wall, puffin..
  */
 
-#define __ASSEMBLY__
 #include <asm/assembly.h>
 #include <asm/offset.h>
 #include <asm/unistd.h>
 #include <asm/errno.h>
 
+#ifdef __LP64__
+	.level          2.0w
+#else
+	.level		1.1
+#endif
 	.text
 
+#ifdef __LP64__
+#define FRAME_SIZE	128
+#else
+#define FRAME_SIZE	64
+#endif
 	.import hpux_call_table
 	.import hpux_syscall_exit,code
 	.export hpux_gateway_page
@@ -23,35 +32,70 @@
 	.align 4096
 hpux_gateway_page:
 	nop
-	mfsp	%sr7,%r1			;! we must set sr3 to the space
-	mtsp	%r1,%sr3			;! of the user before the gate
 #ifdef __LP64__
 #warning NEEDS WORK for 64-bit
 #endif
-	ldw	-64(%r30), %r28			;! 8th argument
+	ldw     -64(%r30), %r29                 ;! 8th argument
 	ldw	-60(%r30), %r19			;! 7th argument
 	ldw	-56(%r30), %r20			;! 6th argument
 	ldw	-52(%r30), %r21			;! 5th argument
-	gate	.+8, %r0			;! become privileged
-	mtsp	%r0,%sr4			;! get kernel space into sr4
-	mtsp	%r0,%sr5			;! get kernel space into sr5
-	mtsp	%r0,%sr6			;! get kernel space into sr6
-	mtsp	%r0,%sr7			;! get kernel space into sr7
-	mfctl	%cr30,%r1			;! get the kernel task ptr
-	mtctl	%r0,%cr30			;! zero it (flag)
-	STREG	%r30,TASK_PT_GR30(%r1)		;! preserve userspace sp
-	STREG	%r2,TASK_PT_GR2(%r1)		;! preserve rp
-	STREG	%r27,TASK_PT_GR27(%r1)		;! user dp
-	STREG	%r31,TASK_PT_GR31(%r1)		;! preserve syscall return ptr
+	gate	.+8, %r0			/* become privileged */
+	mtsp	%r0,%sr4			/* get kernel space into sr4 */
+	mtsp	%r0,%sr5			/* get kernel space into sr5 */
+	mtsp	%r0,%sr6			/* get kernel space into sr6 */
+	mfsp    %sr7,%r1                        /* save user sr7 */
+	mtsp    %r1,%sr3                        /* and store it in sr3 */
+
+	mtctl   %r30,%cr28
+	mfctl   %cr30,%r1
+	xor     %r1,%r30,%r30                   /* ye olde xor trick */
+	xor     %r1,%r30,%r1
+	xor     %r1,%r30,%r30
+	ldo     TASK_SZ_ALGN+FRAME_SIZE(%r30),%r30  /* set up kernel stack */
+
+	/* N.B.: It is critical that we don't set sr7 to 0 until r30
+	 *       contains a valid kernel stack pointer. It is also
+	 *       critical that we don't start using the kernel stack
+	 *       until after sr7 has been set to 0.
+	 */
+
+	mtsp	%r0,%sr7			/* get kernel space into sr7 */
+	STREG   %r1,TASK_PT_GR30-TASK_SZ_ALGN-FRAME_SIZE(%r30) /* save usp */
+	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1   /* get task ptr in %r1 */
+
+	/* Save some registers for sigcontext and potential task
+	   switch (see entry.S for the details of which ones are
+	   saved/restored).  TASK_PT_PSW is zeroed so we can see whether
+	   a process is on a syscall or not.  For an interrupt the real
+	   PSW value is stored.  This is needed for gdb and sys_ptrace. */
+	STREG	%r0,  TASK_PT_PSW(%r1)
+	STREG	%r2,  TASK_PT_GR2(%r1)		/* preserve rp */
+	STREG   %r19, TASK_PT_GR19(%r1)         /* 7th argument */
+	STREG   %r20, TASK_PT_GR20(%r1)         /* 6th argument */
+	STREG   %r21, TASK_PT_GR21(%r1)         /* 5th argument */
+	STREG   %r22, TASK_PT_GR22(%r1)         /* syscall # */
+	STREG	%r23, TASK_PT_GR23(%r1)		/* 4th argument */
+	STREG	%r24, TASK_PT_GR24(%r1)		/* 3rd argument */
+	STREG	%r25, TASK_PT_GR25(%r1)		/* 2nd argument */
+	STREG	%r26, TASK_PT_GR26(%r1)	 	/* 1st argument */
+	STREG	%r27, TASK_PT_GR27(%r1)		/* user dp */
+	STREG   %r28, TASK_PT_GR28(%r1)         /* return value 0 */
+	STREG   %r28, TASK_PT_ORIG_R28(%r1)     /* return value 0 (saved for signals) */
+	STREG   %r29, TASK_PT_GR29(%r1)         /* 8th argument */
+	STREG	%r31, TASK_PT_GR31(%r1)		/* preserve syscall return ptr */
+	
+	ldo	TASK_PT_FR0(%r1), %r27		/* save fpregs from the kernel */
+	save_fp	%r27				/* or potential task switch  */
 
-	loadgp					;! setup kernel dp
+	mfctl	%cr11, %r27			/* i.e. SAR */
+	STREG	%r27, TASK_PT_SAR(%r1)
 
-	ldo	TASK_SZ_ALGN+64(%r1),%r30	;! set up kernel stack
+	loadgp
 
 	stw	%r21, -52(%r30)			;! 5th argument
 	stw	%r20, -56(%r30)			;! 6th argument
 	stw	%r19, -60(%r30)			;! 7th argument
-	stw	%r28, -64(%r30)			;! 8th argument
+	stw     %r29, -64(%r30)                 ;! 8th argument
 
 	ldil	L%hpux_call_table, %r21
 	ldo	R%hpux_call_table(%r21), %r21
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/hpux/ioctl.c linux-2.4.20/arch/parisc/hpux/ioctl.c
--- linux-2.4.19/arch/parisc/hpux/ioctl.c	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/hpux/ioctl.c	2002-10-29 11:18:34.000000000 +0000
@@ -19,6 +19,7 @@
  *   TIOCSPGRP
  */
 
+#include <linux/sched.h>
 #include <linux/smp_lock.h>
 #include <asm/errno.h>
 #include <asm/ioctl.h>
@@ -54,10 +55,6 @@
 	case 't':
 		result = hpux_ioctl_t(fd, cmd, arg);
 		break;
-	default:
-		/* If my mother ever sees this, I hope she disowns me.
-		 * Take this out after NYLWE. */
-		result = sys_ioctl(fd, cmd, arg);
 	}
 	return result;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/hpux/sys_hpux.c linux-2.4.20/arch/parisc/hpux/sys_hpux.c
--- linux-2.4.19/arch/parisc/hpux/sys_hpux.c	2001-08-09 23:41:36.000000000 +0000
+++ linux-2.4.20/arch/parisc/hpux/sys_hpux.c	2002-10-29 11:18:48.000000000 +0000
@@ -9,6 +9,9 @@
 #include <linux/utsname.h>
 #include <asm/errno.h>
 #include <asm/uaccess.h>
+#include <linux/vmalloc.h>
+#include <asm/pgalloc.h>
+#include <linux/slab.h>
 
 unsigned long sys_brk(unsigned long addr);
  
@@ -41,6 +44,17 @@
 	return sys_waitpid(-1, stat_loc, 0);
 }
 
+int hpux_setpgrp(void)
+{
+	extern int sys_setpgid(int, int);
+	return sys_setpgid(0,0);
+}
+
+int hpux_setpgrp3(void)
+{
+	return hpux_setpgrp();
+}
+
 #define _SC_CPU_VERSION	10001
 #define _SC_OPEN_MAX	4
 #define CPU_PA_RISC1_1	0x210
@@ -129,6 +143,66 @@
 	return err;
 }
 
+/*
+ * Wrapper for hpux statfs call. At the moment, just calls the linux native one
+ * and ignores the extra fields at the end of the hpux statfs struct.
+ *
+ */
+
+typedef int32_t hpux_fsid_t[2];              /* file system ID type */
+typedef uint16_t hpux_site_t;
+
+struct hpux_statfs {
+     int32_t f_type;                    /* type of info, zero for now */
+     int32_t f_bsize;                   /* fundamental file system block size */
+     int32_t f_blocks;                  /* total blocks in file system */
+     int32_t f_bfree;                   /* free block in fs */
+     int32_t f_bavail;                  /* free blocks avail to non-superuser */
+     int32_t f_files;                   /* total file nodes in file system */
+     int32_t f_ffree;                   /* free file nodes in fs */
+     hpux_fsid_t  f_fsid;                    /* file system ID */
+     int32_t f_magic;                   /* file system magic number */
+     int32_t f_featurebits;             /* file system features */
+     int32_t f_spare[4];                /* spare for later */
+     hpux_site_t  f_cnode;                   /* cluster node where mounted */
+     int16_t f_pad;
+};
+
+/* hpux statfs */
+int hpux_statfs(const char *path, struct hpux_statfs *buf)
+{
+	int error;
+	int len;
+	char *kpath;
+
+	len = strlen_user((char *)path); 
+
+	kpath = (char *) kmalloc(len+1, GFP_KERNEL);
+	if ( !kpath ) {
+	printk(KERN_DEBUG "failed to kmalloc kpath\n");
+	return 0;
+	}
+
+	if ( copy_from_user(kpath, (char *)path, len+1) ) {
+	printk(KERN_DEBUG "failed to copy_from_user kpath\n");
+	kfree(kpath);
+	return 0;
+	}
+
+	printk(KERN_DEBUG "hpux_statfs(\"%s\",-)\n", kpath);
+
+	kfree(kpath);
+
+	/* just fake it, beginning of structures match */
+	extern int sys_statfs(const char *, struct statfs *);
+	error = sys_statfs(path, (struct statfs *) buf);
+
+	/* ignoring rest of statfs struct, but it should be zeros. Need to do 
+		something with f_fsid[1], which is the fstype for sysfs */
+
+	return error;
+}
+
 
 /*  This function is called from hpux_utssys(); HP-UX implements
  *  uname() as an option to utssys().
@@ -333,3 +407,541 @@
 	unlock_kernel();
 	return error;
 }
+
+/* lies - says it works, but it really didn't lock anything */
+int hpux_lockf(int fildes, int function, off_t size)
+{
+	return 0;
+}
+
+int hpux_sysfs(int opcode, unsigned long arg1, unsigned long arg2)
+{
+	char *fsname = NULL;
+	int len = 0;
+	int fstype;
+
+/*Unimplemented HP-UX syscall emulation. Syscall #334 (sysfs)
+  Args: 1 80057bf4 0 400179f0 0 0 0 */
+	printk(KERN_DEBUG "in hpux_sysfs\n");
+	printk(KERN_DEBUG "hpux_sysfs called with opcode = %d\n", opcode);
+	printk(KERN_DEBUG "hpux_sysfs called with arg1='%lx'\n", arg1);
+
+	if ( opcode == 1 ) { /* GETFSIND */	
+		len = strlen_user((char *)arg1);
+		printk(KERN_DEBUG "len of arg1 = %d\n", len);
+
+		fsname = (char *) kmalloc(len+1, GFP_KERNEL);
+		if ( !fsname ) {
+			printk(KERN_DEBUG "failed to kmalloc fsname\n");
+			return 0;
+		}
+
+		if ( copy_from_user(fsname, (char *)arg1, len+1) ) {
+			printk(KERN_DEBUG "failed to copy_from_user fsname\n");
+			kfree(fsname);
+			return 0;
+		}
+
+		printk(KERN_DEBUG "that is '%s' as (char *)\n", fsname);
+		if ( !strcmp(fsname, "hfs") ) {
+			fstype = 0;
+		} else {
+			fstype = 0;
+		};
+
+		kfree(fsname);
+
+		printk(KERN_DEBUG "returning fstype=%d\n", fstype);
+		return fstype; /* something other than default */
+	}
+
+
+	return 0;
+}
+
+
+/* Table of syscall names and handle for unimplemented routines */
+static const char *syscall_names[] = {
+	"nosys",                  /* 0 */
+	"exit",                  
+	"fork",                  
+	"read",                  
+	"write",                 
+	"open",                   /* 5 */
+	"close",                 
+	"wait",                  
+	"creat",                 
+	"link",                  
+	"unlink",                 /* 10 */
+	"execv",                 
+	"chdir",                 
+	"time",                  
+	"mknod",                 
+	"chmod",                  /* 15 */
+	"chown",                 
+	"brk",                   
+	"lchmod",                
+	"lseek",                 
+	"getpid",                 /* 20 */
+	"mount",                 
+	"umount",                
+	"setuid",                
+	"getuid",                
+	"stime",                  /* 25 */
+	"ptrace",                
+	"alarm",                 
+	NULL,                    
+	"pause",                 
+	"utime",                  /* 30 */
+	"stty",                  
+	"gtty",                  
+	"access",                
+	"nice",                  
+	"ftime",                  /* 35 */
+	"sync",                  
+	"kill",                  
+	"stat",                  
+	"setpgrp3",              
+	"lstat",                  /* 40 */
+	"dup",                   
+	"pipe",                  
+	"times",                 
+	"profil",                
+	"ki_call",                /* 45 */
+	"setgid",                
+	"getgid",                
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 50 */
+	"acct",                  
+	"set_userthreadid",      
+	NULL,                    
+	"ioctl",                 
+	"reboot",                 /* 55 */
+	"symlink",               
+	"utssys",                
+	"readlink",              
+	"execve",                
+	"umask",                  /* 60 */
+	"chroot",                
+	"fcntl",                 
+	"ulimit",                
+	NULL,                    
+	NULL,                     /* 65 */
+	"vfork",                 
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 70 */
+	"mmap",                  
+	NULL,                    
+	"munmap",                
+	"mprotect",              
+	"madvise",                /* 75 */
+	"vhangup",               
+	"swapoff",               
+	NULL,                    
+	"getgroups",             
+	"setgroups",              /* 80 */
+	"getpgrp2",              
+	"setpgid/setpgrp2",      
+	"setitimer",             
+	"wait3",                 
+	"swapon",                 /* 85 */
+	"getitimer",             
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	"dup2",                   /* 90 */
+	NULL,                    
+	"fstat",                 
+	"select",                
+	NULL,                    
+	"fsync",                  /* 95 */
+	"setpriority",           
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	"getpriority",            /* 100 */
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 105 */
+	NULL,                    
+	NULL,                    
+	"sigvector",             
+	"sigblock",              
+	"sigsetmask",             /* 110 */
+	"sigpause",              
+	"sigstack",              
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 115 */
+	"gettimeofday",          
+	"getrusage",             
+	NULL,                    
+	NULL,                    
+	"readv",                  /* 120 */
+	"writev",                
+	"settimeofday",          
+	"fchown",                
+	"fchmod",                
+	NULL,                     /* 125 */
+	"setresuid",             
+	"setresgid",             
+	"rename",                
+	"truncate",              
+	"ftruncate",              /* 130 */
+	NULL,                    
+	"sysconf",               
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 135 */
+	"mkdir",                 
+	"rmdir",                 
+	NULL,                    
+	"sigcleanup",            
+	"setcore",                /* 140 */
+	NULL,                    
+	"gethostid",             
+	"sethostid",             
+	"getrlimit",             
+	"setrlimit",              /* 145 */
+	NULL,                    
+	NULL,                    
+	"quotactl",              
+	"get_sysinfo",           
+	NULL,                     /* 150 */
+	"privgrp",               
+	"rtprio",                
+	"plock",                 
+	NULL,                    
+	"lockf",                  /* 155 */
+	"semget",                
+	NULL,                    
+	"semop",                 
+	"msgget",                
+	NULL,                     /* 160 */
+	"msgsnd",                
+	"msgrcv",                
+	"shmget",                
+	NULL,                    
+	"shmat",                  /* 165 */
+	"shmdt",                 
+	NULL,                    
+	"csp/nsp_init",          
+	"cluster",               
+	"mkrnod",                 /* 170 */
+	"test",                  
+	"unsp_open",             
+	NULL,                    
+	"getcontext",            
+	"osetcontext",            /* 175 */
+	"bigio",                 
+	"pipenode",              
+	"lsync",                 
+	"getmachineid",          
+	"cnodeid/mysite",         /* 180 */
+	"cnodes/sitels",         
+	"swapclients",           
+	"rmtprocess",            
+	"dskless_stats",         
+	"sigprocmask",            /* 185 */
+	"sigpending",            
+	"sigsuspend",            
+	"sigaction",             
+	NULL,                    
+	"nfssvc",                 /* 190 */
+	"getfh",                 
+	"getdomainname",         
+	"setdomainname",         
+	"async_daemon",          
+	"getdirentries",          /* 195 */
+	"statfs",                
+	"fstatfs",               
+	"vfsmount",              
+	NULL,                    
+	"waitpid",                /* 200 */
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 205 */
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 210 */
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 215 */
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 220 */
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	"sigsetreturn",          
+	"sigsetstatemask",        /* 225 */
+	"bfactl",                
+	"cs",                    
+	"cds",                   
+	NULL,                    
+	"pathconf",               /* 230 */
+	"fpathconf",             
+	NULL,                    
+	NULL,                    
+	"nfs_fcntl",             
+	"ogetacl",                /* 235 */
+	"ofgetacl",              
+	"osetacl",               
+	"ofsetacl",              
+	"pstat",                 
+	"getaudid",               /* 240 */
+	"setaudid",              
+	"getaudproc",            
+	"setaudproc",            
+	"getevent",              
+	"setevent",               /* 245 */
+	"audwrite",              
+	"audswitch",             
+	"audctl",                
+	"ogetaccess",            
+	"fsctl",                  /* 250 */
+	"ulconnect",             
+	"ulcontrol",             
+	"ulcreate",              
+	"uldest",                
+	"ulrecv",                 /* 255 */
+	"ulrecvcn",              
+	"ulsend",                
+	"ulshutdown",            
+	"swapfs",                
+	"fss",                    /* 260 */
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 265 */
+	NULL,                    
+	"tsync",                 
+	"getnumfds",             
+	"poll",                  
+	"getmsg",                 /* 270 */
+	"putmsg",                
+	"fchdir",                
+	"getmount_cnt",          
+	"getmount_entry",        
+	"accept",                 /* 275 */
+	"bind",                  
+	"connect",               
+	"getpeername",           
+	"getsockname",           
+	"getsockopt",             /* 280 */
+	"listen",                
+	"recv",                  
+	"recvfrom",              
+	"recvmsg",               
+	"send",                   /* 285 */
+	"sendmsg",               
+	"sendto",                
+	"setsockopt",            
+	"shutdown",              
+	"socket",                 /* 290 */
+	"socketpair",            
+	"proc_open",             
+	"proc_close",            
+	"proc_send",             
+	"proc_recv",              /* 295 */
+	"proc_sendrecv",         
+	"proc_syscall",          
+	"ipccreate",             
+	"ipcname",               
+	"ipcnamerase",            /* 300 */
+	"ipclookup",             
+	"ipcselect",             
+	"ipcconnect",            
+	"ipcrecvcn",             
+	"ipcsend",                /* 305 */
+	"ipcrecv",               
+	"ipcgetnodename",        
+	"ipcsetnodename",        
+	"ipccontrol",            
+	"ipcshutdown",            /* 310 */
+	"ipcdest",               
+	"semctl",                
+	"msgctl",                
+	"shmctl",                
+	"mpctl",                  /* 315 */
+	"exportfs",              
+	"getpmsg",               
+	"putpmsg",               
+	"strioctl",              
+	"msync",                  /* 320 */
+	"msleep",                
+	"mwakeup",               
+	"msem_init",             
+	"msem_remove",           
+	"adjtime",                /* 325 */
+	"kload",                 
+	"fattach",               
+	"fdetach",               
+	"serialize",             
+	"statvfs",                /* 330 */
+	"fstatvfs",              
+	"lchown",                
+	"getsid",                
+	"sysfs",                 
+	NULL,                     /* 335 */
+	NULL,                    
+	"sched_setparam",        
+	"sched_getparam",        
+	"sched_setscheduler",    
+	"sched_getscheduler",     /* 340 */
+	"sched_yield",           
+	"sched_get_priority_max",
+	"sched_get_priority_min",
+	"sched_rr_get_interval", 
+	"clock_settime",          /* 345 */
+	"clock_gettime",         
+	"clock_getres",          
+	"timer_create",          
+	"timer_delete",          
+	"timer_settime",          /* 350 */
+	"timer_gettime",         
+	"timer_getoverrun",      
+	"nanosleep",             
+	"toolbox",               
+	NULL,                     /* 355 */
+	"getdents",              
+	"getcontext",            
+	"sysinfo",               
+	"fcntl64",               
+	"ftruncate64",            /* 360 */
+	"fstat64",               
+	"getdirentries64",       
+	"getrlimit64",           
+	"lockf64",               
+	"lseek64",                /* 365 */
+	"lstat64",               
+	"mmap64",                
+	"setrlimit64",           
+	"stat64",                
+	"truncate64",             /* 370 */
+	"ulimit64",              
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 375 */
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	"setcontext",             /* 380 */
+	"sigaltstack",           
+	"waitid",                
+	"setpgrp",               
+	"recvmsg2",              
+	"sendmsg2",               /* 385 */
+	"socket2",               
+	"socketpair2",           
+	"setregid",              
+	"lwp_create",            
+	"lwp_terminate",          /* 390 */
+	"lwp_wait",              
+	"lwp_suspend",           
+	"lwp_resume",            
+	"lwp_self",              
+	"lwp_abort_syscall",      /* 395 */
+	"lwp_info",              
+	"lwp_kill",              
+	"ksleep",                
+	"kwakeup",               
+	"ksleep_abort",           /* 400 */
+	"lwp_proc_info",         
+	"lwp_exit",              
+	"lwp_continue",          
+	"getacl",                
+	"fgetacl",                /* 405 */
+	"setacl",                
+	"fsetacl",               
+	"getaccess",             
+	"lwp_mutex_init",        
+	"lwp_mutex_lock_sys",     /* 410 */
+	"lwp_mutex_unlock",      
+	"lwp_cond_init",         
+	"lwp_cond_signal",       
+	"lwp_cond_broadcast",    
+	"lwp_cond_wait_sys",      /* 415 */
+	"lwp_getscheduler",      
+	"lwp_setscheduler",      
+	"lwp_getprivate",        
+	"lwp_setprivate",        
+	"lwp_detach",             /* 420 */
+	"mlock",                 
+	"munlock",               
+	"mlockall",              
+	"munlockall",            
+	"shm_open",               /* 425 */
+	"shm_unlink",            
+	"sigqueue",              
+	"sigwaitinfo",           
+	"sigtimedwait",          
+	"sigwait",                /* 430 */
+	"aio_read",              
+	"aio_write",             
+	"lio_listio",            
+	"aio_error",             
+	"aio_return",             /* 435 */
+	"aio_cancel",            
+	"aio_suspend",           
+	"aio_fsync",             
+	"mq_open",               
+	"mq_unlink",              /* 440 */
+	"mq_send",               
+	"mq_receive",            
+	"mq_notify",             
+	"mq_setattr",            
+	"mq_getattr",             /* 445 */
+	"ksem_open",             
+	"ksem_unlink",           
+	"ksem_close",            
+	"ksem_destroy",          
+	"lw_sem_incr",            /* 450 */
+	"lw_sem_decr",           
+	"lw_sem_read",           
+	"mq_close",              
+};
+static const int syscall_names_max = 453;
+
+int
+hpux_unimplemented(unsigned long arg1,unsigned long arg2,unsigned long arg3,
+		   unsigned long arg4,unsigned long arg5,unsigned long arg6,
+		   unsigned long arg7,unsigned long sc_num)
+{
+	/* NOTE: sc_num trashes arg8 for the few syscalls that actually
+	 * have a valid 8th argument.
+	 */
+	const char *name = NULL;
+	if ( sc_num <= syscall_names_max && sc_num >= 0 ) {
+		name = syscall_names[sc_num];
+	}
+
+	if ( name ) {
+		printk(KERN_DEBUG "Unimplemented HP-UX syscall emulation. Syscall #%lu (%s)\n",
+		sc_num, name);
+	} else {
+		printk(KERN_DEBUG "Unimplemented unknown HP-UX syscall emulation. Syscall #%lu\n",
+		sc_num);
+	}
+	
+	printk(KERN_DEBUG "  Args: %lx %lx %lx %lx %lx %lx %lx\n",
+		arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+
+	return -ENOSYS;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/hpux/wrappers.S linux-2.4.20/arch/parisc/hpux/wrappers.S
--- linux-2.4.19/arch/parisc/hpux/wrappers.S	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/hpux/wrappers.S	2002-10-29 11:18:37.000000000 +0000
@@ -1,5 +1,5 @@
-/*------------------------------------------------------------------------------
- * Native PARISC/Linux Project (http://www.puffingroup.com/parisc)
+/*
+ * Linux/PARISC Project (http://www.parisc-linux.org/)
  *
  * HP-UX System Call Wrapper routines and System Call Return Path
  *
@@ -29,7 +29,6 @@
 	.level		1.1
 	.text
 
-#define __ASSEMBLY__
 #include <asm/assembly.h>
 #include <asm/signal.h>
 
@@ -81,6 +80,7 @@
 
 
 	.export hpux_fork_wrapper
+	.export hpux_child_return
 	.import sys_fork
 
 hpux_fork_wrapper:
@@ -91,12 +91,10 @@
 	stw	%r2,-20(%r30)
 	ldo	64(%r30),%r30
 	stw	%r2,PT_GR19(%r1)	;! save for child
-	stw	%r30,PT_GR20(%r1)	;! save for child
-	ldil	L%child_return,%r3
-	ldo	R%child_return(%r3),%r3
-	stw	%r3,PT_GR21(%r1)	;! save for child
+	stw	%r30,PT_GR21(%r1)	;! save for child
 
-	ldw	TASK_PT_GR30(%r1),%r25
+	ldw     PT_GR30(%r1),%r25
+	mtctl   %r25,%cr29
 	copy	%r1,%r24
 	bl	sys_clone,%r2
 	ldi	SIGCHLD,%r26
@@ -130,7 +128,10 @@
 
 	/* Set the return value for the child */
 
-child_return:
+hpux_child_return:
+	bl	schedule_tail, %r2
+	nop
+
 	ldw TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2
 	b fork_return
 	copy %r0,%r28
@@ -242,3 +243,10 @@
 no_error:
 	b syscall_exit
 	nop
+
+	.export hpux_unimplemented_wrapper
+	.import hpux_unimplemented
+
+hpux_unimplemented_wrapper:
+	b hpux_unimplemented
+	stw %r22,-64(%r30)  /* overwrite arg8 with syscall number */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/Makefile linux-2.4.20/arch/parisc/kernel/Makefile
--- linux-2.4.19/arch/parisc/kernel/Makefile	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/Makefile	2002-10-29 11:18:36.000000000 +0000
@@ -7,26 +7,30 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-all: kernel.o init_task.o pdc_cons.o process.o head.o
-O_TARGET = kernel.o
-O_OBJS = 
+ifdef CONFIG_PARISC64
+all: kernel.o init_task.o pdc_cons.o process.o head64.o unaligned.o perf.o perf_asm.o
+else
+all: kernel.o init_task.o pdc_cons.o process.o head.o unaligned.o
+endif
 
-# Object file lists.
+O_TARGET = kernel.o
 
 obj-y		:=
 obj-m		:=
 obj-n		:=
 obj-		:=
 
-obj-y		+= cache.o setup.o traps.o time.o irq.o \
-		syscall.o entry.o sys_parisc.o pdc.o ptrace.o hardware.o \
-		inventory.o drivers.o semaphore.o pa7300lc.o pci-dma.o \
-		signal.o hpmc.o \
-		real1.o real2.o led.o parisc_ksyms.o
+obj-y           += cache.o pacache.o setup.o traps.o time.o irq.o \
+		pa7300lc.o syscall.o entry.o sys_parisc.o firmware.o \
+		ptrace.o hardware.o inventory.o drivers.o semaphore.o \
+		signal.o hpmc.o real2.o parisc_ksyms.o unaligned.o \
+		processor.o power.o
 
-export-objs	:= parisc_ksyms.o
+export-objs	:= parisc_ksyms.o superio.o keyboard.o
 
 
+obj-$(CONFIG_SMP) += smp.o irq_smp.o
+obj-$(CONFIG_PA11) += pci-dma.o
 obj-$(CONFIG_PCI) += pci.o
 obj-$(CONFIG_VT) += keyboard.o
 obj-$(CONFIG_PCI_LBA) += lba_pci.o
@@ -37,16 +41,11 @@
 # Only use one of them: ccio-rm-dma is for PCX-W systems *only*
 # obj-$(CONFIG_IOMMU_CCIO) += ccio-rm-dma.o
 obj-$(CONFIG_IOMMU_CCIO) += ccio-dma.o
-
-.o.S:	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o
-
-# Translate to Rules.make lists.
-
-O_OBJS          := $(filter-out $(export-objs), $(obj-y))
-OX_OBJS         := $(filter     $(export-objs), $(obj-y))
-M_OBJS          := $(sort $(filter-out $(export-objs), $(obj-m)))
-MX_OBJS         := $(sort $(filter     $(export-objs), $(obj-m)))
-MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
-MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
+obj-$(CONFIG_CHASSIS_LCD_LED) += led.o 
+obj-$(CONFIG_SUPERIO) += superio.o
+obj-$(CONFIG_PARISC64) += binfmt_elf32.o sys_parisc32.o \
+		ioctl32.o signal32.o
+# only supported for PCX-W/U in 64-bit mode at the moment
+obj-$(CONFIG_PARISC64) += perf.o perf_asm.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/binfmt_elf32.c linux-2.4.20/arch/parisc/kernel/binfmt_elf32.c
--- linux-2.4.19/arch/parisc/kernel/binfmt_elf32.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/binfmt_elf32.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,93 @@
+/*
+ * Support for 32-bit Linux/Parisc ELF binaries on 64 bit kernels
+ *
+ * Copyright (C) 2000 John Marvin
+ * Copyright (C) 2000 Hewlett Packard Co.
+ *
+ * Heavily inspired from various other efforts to do the same thing
+ * (ia64,sparc64/mips64)
+ */
+
+/* Make sure include/asm-parisc/elf.h does the right thing */
+
+#define ELF_CLASS	ELFCLASS32
+
+typedef unsigned int elf_greg_t;
+
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/elfcore.h>
+#include "sys32.h"		/* struct timeval32 */
+
+#define elf_prstatus elf_prstatus32
+struct elf_prstatus32
+{
+	struct elf_siginfo pr_info;	/* Info associated with signal */
+	short	pr_cursig;		/* Current signal */
+	unsigned int pr_sigpend;	/* Set of pending signals */
+	unsigned int pr_sighold;	/* Set of held signals */
+	pid_t	pr_pid;
+	pid_t	pr_ppid;
+	pid_t	pr_pgrp;
+	pid_t	pr_sid;
+	struct timeval32 pr_utime;	/* User time */
+	struct timeval32 pr_stime;	/* System time */
+	struct timeval32 pr_cutime;	/* Cumulative user time */
+	struct timeval32 pr_cstime;	/* Cumulative system time */
+	elf_gregset_t pr_reg;	/* GP registers */
+	int pr_fpvalid;		/* True if math co-processor being used.  */
+};
+
+#define elf_prpsinfo elf_prpsinfo32
+struct elf_prpsinfo32
+{
+	char	pr_state;	/* numeric process state */
+	char	pr_sname;	/* char for pr_state */
+	char	pr_zomb;	/* zombie */
+	char	pr_nice;	/* nice val */
+	unsigned int pr_flag;	/* flags */
+	u16	pr_uid;
+	u16	pr_gid;
+	pid_t	pr_pid, pr_ppid, pr_pgrp, pr_sid;
+	/* Lots missing */
+	char	pr_fname[16];	/* filename of executable */
+	char	pr_psargs[ELF_PRARGSZ];	/* initial part of arg list */
+};
+
+#define elf_addr_t	unsigned int
+typedef unsigned int elf_caddr_t;
+#define init_elf_binfmt init_elf32_binfmt
+
+#define ELF_PLATFORM  ("PARISC32\0")
+
+#define ELF_CORE_COPY_REGS(dst, pt)	\
+	memset(dst, 0, sizeof(dst));	/* don't leak any "random" bits */ \
+	{	int i; \
+		for (i = 0; i < 32; i++) dst[i] = (elf_greg_t) pt->gr[i]; \
+		for (i = 0; i < 8; i++) dst[32 + i] = (elf_greg_t) pt->sr[i]; \
+	} \
+	dst[40] = (elf_greg_t) pt->iaoq[0]; dst[41] = (elf_greg_t) pt->iaoq[1]; \
+	dst[42] = (elf_greg_t) pt->iasq[0]; dst[43] = (elf_greg_t) pt->iasq[1]; \
+	dst[44] = (elf_greg_t) pt->sar;   dst[45] = (elf_greg_t) pt->iir; \
+	dst[46] = (elf_greg_t) pt->isr;   dst[47] = (elf_greg_t) pt->ior; \
+	dst[48] = (elf_greg_t) mfctl(22); dst[49] = (elf_greg_t) mfctl(0); \
+	dst[50] = (elf_greg_t) mfctl(24); dst[51] = (elf_greg_t) mfctl(25); \
+	dst[52] = (elf_greg_t) mfctl(26); dst[53] = (elf_greg_t) mfctl(27); \
+	dst[54] = (elf_greg_t) mfctl(28); dst[55] = (elf_greg_t) mfctl(29); \
+	dst[56] = (elf_greg_t) mfctl(30); dst[57] = (elf_greg_t) mfctl(31); \
+	dst[58] = (elf_greg_t) mfctl( 8); dst[59] = (elf_greg_t) mfctl( 9); \
+	dst[60] = (elf_greg_t) mfctl(12); dst[61] = (elf_greg_t) mfctl(13); \
+	dst[62] = (elf_greg_t) mfctl(10); dst[63] = (elf_greg_t) mfctl(15);
+
+/*
+ * We should probably use this macro to set a flag somewhere to indicate
+ * this is a 32 on 64 process. We could use PER_LINUX_32BIT, or we
+ * could set a processor dependent flag in the thread_struct.
+ */
+
+#define SET_PERSONALITY(ex, ibcs2) \
+	current->personality = PER_LINUX_32BIT
+
+#include "../../../fs/binfmt_elf.c"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/cache.c linux-2.4.20/arch/parisc/kernel/cache.c
--- linux-2.4.19/arch/parisc/kernel/cache.c	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/cache.c	2002-10-29 11:18:39.000000000 +0000
@@ -15,202 +15,85 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/seq_file.h>
 
 #include <asm/pdc.h>
 #include <asm/cache.h>
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
+#include <asm/processor.h>
+
+int split_tlb;
+int dcache_stride;
+int icache_stride;
 
 struct pdc_cache_info cache_info;
-#ifndef __LP64__
+#ifndef CONFIG_PA20
 static struct pdc_btlb_info btlb_info;
 #endif
 
-
-void __flush_page_to_ram(unsigned long address)
-{
-	__flush_dcache_range(address, PAGE_SIZE);
-	__flush_icache_range(address, PAGE_SIZE);
-}
-
-
-
-void flush_data_cache(void)
+#ifdef CONFIG_SMP
+void
+flush_data_cache(void)
 {
-	register unsigned long base   = cache_info.dc_base;
-	register unsigned long count  = cache_info.dc_count;
-	register unsigned long loop   = cache_info.dc_loop;
-	register unsigned long stride = cache_info.dc_stride;
-	register unsigned long addr;
-	register long i, j;
-
-	for(i=0,addr=base; i<count; i++,addr+=stride)
-		for(j=0; j<loop; j++)
-			fdce(addr);
-}
-		
-static inline void flush_data_tlb_space(void)
-{
-	unsigned long base   = cache_info.dt_off_base;
-	unsigned long count  = cache_info.dt_off_count;
-	unsigned long stride = cache_info.dt_off_stride;
-	unsigned long loop   = cache_info.dt_loop;
-
-	unsigned long addr;
-	long i,j;
-	
-	for(i=0,addr=base; i<count; i++,addr+=stride)
-		for(j=0; j<loop; j++)
-			pdtlbe(addr);
-}
-
-
-
-void flush_data_tlb(void)
-{
-	unsigned long base   = cache_info.dt_sp_base;
-	unsigned long count  = cache_info.dt_sp_count;
-	unsigned long stride = cache_info.dt_sp_stride;
-	unsigned long space;
-	unsigned long old_sr1;
-	long i;
-	
-	old_sr1 = mfsp(1);
-	
-	for(i=0,space=base; i<count; i++, space+=stride) {
-		mtsp(space,1);
-		flush_data_tlb_space();
-	}
-
-	mtsp(old_sr1, 1);
+	smp_call_function((void (*)(void *))flush_data_cache_local, NULL, 1, 1);
+	flush_data_cache_local();
 }
+#endif
 
-static inline void flush_instruction_tlb_space(void)
+void
+flush_cache_all_local(void)
 {
-	unsigned long base   = cache_info.it_off_base;
-	unsigned long count  = cache_info.it_off_count;
-	unsigned long stride = cache_info.it_off_stride;
-	unsigned long loop   = cache_info.it_loop;
-
-	unsigned long addr;
-	long i,j;
-	
-	for(i=0,addr=base; i<count; i++,addr+=stride)
-		for(j=0; j<loop; j++)
-			pitlbe(addr);
-}
-
-void flush_instruction_tlb(void)
-{
-	unsigned long base   = cache_info.it_sp_base;
-	unsigned long count  = cache_info.it_sp_count;
-	unsigned long stride = cache_info.it_sp_stride;
-	unsigned long space;
-	unsigned long old_sr1;
-	unsigned int i;
-	
-	old_sr1 = mfsp(1);
-	
-	for(i=0,space=base; i<count; i++, space+=stride) {
-		mtsp(space,1);
-		flush_instruction_tlb_space();
-	}
-
-	mtsp(old_sr1, 1);
+	flush_instruction_cache_local();
+	flush_data_cache_local();
 }
 
+/* flushes EVERYTHING (tlb & cache) */
 
-void __flush_tlb_space(unsigned long space)
+void
+flush_all_caches(void)
 {
-	unsigned long old_sr1;
-
-	old_sr1 = mfsp(1);
-	mtsp(space, 1);
-	
-	flush_data_tlb_space();
-	flush_instruction_tlb_space();
-
-	mtsp(old_sr1, 1);
+	flush_cache_all();
+	flush_tlb_all();
 }
 
-
-void flush_instruction_cache(void)
+void
+update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
-	register unsigned long base   = cache_info.ic_base;
-	register unsigned long count  = cache_info.ic_count;
-	register unsigned long loop   = cache_info.ic_loop;
-	register unsigned long stride = cache_info.ic_stride;
-	register unsigned long addr;
-	register long i, j;
-	unsigned long old_sr1;
-	
-	old_sr1 = mfsp(1);
-	mtsp(0,1);
+	struct page *page = pte_page(pte);
 
-	/*
-	 * Note: fice instruction has 3 bit space field, so one must
-	 *       be specified (otherwise you are justing using whatever
-	 *       happens to be in sr0).
-	 */
+	if (VALID_PAGE(page) && page->mapping &&
+	    test_bit(PG_dcache_dirty, &page->flags)) {
 
-	for(i=0,addr=base; i<count; i++,addr+=stride)
-		for(j=0; j<loop; j++)
-			fice(addr);
-
-	mtsp(old_sr1, 1);
-}
-
-/* not yet ... fdc() needs to be implemented in cache.h !
-void flush_datacache_range( unsigned int base, unsigned int end )
-{
-    register long offset,offset_add;
-    offset_add = ( (1<<(cache_info.dc_conf.cc_block-1)) * 
-		    cache_info.dc_conf.cc_line ) << 4;
-    for (offset=base; offset<=end; offset+=offset_add)
-	fdc(space,offset);
-    fdc(space,end);
-}
-*/
-
-/* flushes code and data-cache */
-void flush_all_caches(void)
-{
-	flush_instruction_cache();
-	flush_data_cache();
-
-	flush_instruction_tlb();
-	flush_data_tlb();
-
-	asm volatile("sync");
-	asm volatile("syncdma");
-	asm volatile("sync");
+		flush_kernel_dcache_page(page_address(page));
+		clear_bit(PG_dcache_dirty, &page->flags);
+	}
 }
 
-int get_cache_info(char *buffer)
+void
+show_cache_info(struct seq_file *m)
 {
-	char *p = buffer;
-
-	p += sprintf(p, "I-cache\t\t: %ld KB\n", 
+	seq_printf(m, "I-cache\t\t: %ld KB\n", 
 		cache_info.ic_size/1024 );
-	p += sprintf(p, "D-cache\t\t: %ld KB (%s)%s\n", 
+	seq_printf(m, "D-cache\t\t: %ld KB (%s)%s\n", 
 		cache_info.dc_size/1024,
 		(cache_info.dc_conf.cc_wt ? "WT":"WB"),
 		(cache_info.dc_conf.cc_sh ? " - shared I/D":"")
 	);
 
-	p += sprintf(p, "ITLB entries\t: %ld\n" "DTLB entries\t: %ld%s\n",
+	seq_printf(m, "ITLB entries\t: %ld\n" "DTLB entries\t: %ld%s\n",
 		cache_info.it_size,
 		cache_info.dt_size,
 		cache_info.dt_conf.tc_sh ? " - shared with ITLB":""
 	);
 		
-#ifndef __LP64__
+#ifndef CONFIG_PA20
 	/* BTLB - Block TLB */
 	if (btlb_info.max_size==0) {
-		p += sprintf(p, "BTLB\t\t: not supported\n" );
+		seq_printf(m, "BTLB\t\t: not supported\n" );
 	} else {
-		p += sprintf(p, 
+		seq_printf(m, 
 		"BTLB fixed\t: max. %d pages, pagesize=%d (%dMB)\n"
 		"BTLB fix-entr.\t: %d instruction, %d data (%d combined)\n"
 		"BTLB var-entr.\t: %d instruction, %d data (%d combined)\n",
@@ -225,11 +108,8 @@
 		);
 	}
 #endif
-
-	return p - buffer;
 }
 
-
 void __init 
 cache_init(void)
 {
@@ -237,17 +117,108 @@
 		panic("cache_init: pdc_cache_info failed");
 
 #if 0
-	printk("ic_size %lx dc_size %lx it_size %lx pdc_cache_info %d*long pdc_cache_cf %d\n",
+	printk(KERN_DEBUG "ic_size %lx dc_size %lx it_size %lx pdc_cache_info %d*long pdc_cache_cf %d\n",
 	    cache_info.ic_size,
 	    cache_info.dc_size,
 	    cache_info.it_size,
 	    sizeof (struct pdc_cache_info) / sizeof (long),
 	    sizeof (struct pdc_cache_cf)
 	);
+
+	printk(KERN_DEBUG "dc base %x dc stride %x dc count %x dc loop %d\n",
+	    cache_info.dc_base,
+	    cache_info.dc_stride,
+	    cache_info.dc_count,
+	    cache_info.dc_loop);
+
+	printk(KERN_DEBUG "dc conf: alias %d block %d line %d wt %d sh %d cst %d assoc %d\n",
+	    cache_info.dc_conf.cc_alias,
+	    cache_info.dc_conf.cc_block,
+	    cache_info.dc_conf.cc_line,
+	    cache_info.dc_conf.cc_wt,
+	    cache_info.dc_conf.cc_sh,
+	    cache_info.dc_conf.cc_cst,
+	    cache_info.dc_conf.cc_assoc);
+
+	printk(KERN_DEBUG "ic conf: alias %d block %d line %d wt %d sh %d cst %d assoc %d\n",
+	    cache_info.ic_conf.cc_alias,
+	    cache_info.ic_conf.cc_block,
+	    cache_info.ic_conf.cc_line,
+	    cache_info.ic_conf.cc_wt,
+	    cache_info.ic_conf.cc_sh,
+	    cache_info.ic_conf.cc_cst,
+	    cache_info.ic_conf.cc_assoc);
+
+	printk(KERN_DEBUG "dt conf: sh %d page %d cst %d aid %d pad1 %d \n",
+	    cache_info.dt_conf.tc_sh,
+	    cache_info.dt_conf.tc_page,
+	    cache_info.dt_conf.tc_cst,
+	    cache_info.dt_conf.tc_aid,
+	    cache_info.dt_conf.tc_pad1);
+
+	printk(KERN_DEBUG "it conf: sh %d page %d cst %d aid %d pad1 %d \n",
+	    cache_info.it_conf.tc_sh,
+	    cache_info.it_conf.tc_page,
+	    cache_info.it_conf.tc_cst,
+	    cache_info.it_conf.tc_aid,
+	    cache_info.it_conf.tc_pad1);
 #endif
-#ifndef __LP64__
+
+	split_tlb = 0;
+	if (cache_info.dt_conf.tc_sh == 0 || cache_info.dt_conf.tc_sh == 2) {
+
+	    if (cache_info.dt_conf.tc_sh == 2)
+		printk(KERN_WARNING "Unexpected TLB configuration. "
+			"Will flush I/D separately (could be optimized).\n");
+
+	    split_tlb = 1;
+	}
+
+	dcache_stride = ( (1<<(cache_info.dc_conf.cc_block+3)) *
+			 cache_info.dc_conf.cc_line );
+	icache_stride = ( (1<<(cache_info.ic_conf.cc_block+3)) *
+			 cache_info.ic_conf.cc_line );
+#ifndef CONFIG_PA20
 	if(pdc_btlb_info(&btlb_info)<0) {
 		memset(&btlb_info, 0, sizeof btlb_info);
 	}
 #endif
+
+	if ((boot_cpu_data.pdc.capabilities & PDC_MODEL_NVA_MASK) == PDC_MODEL_NVA_UNSUPPORTED) {
+		printk(KERN_WARNING "Only equivalent aliasing supported\n");
+#ifndef CONFIG_SMP
+		panic("SMP kernel required to avoid non-equivalent aliasing");
+#endif
+	}
+}
+
+void disable_sr_hashing(void)
+{
+    int srhash_type;
+
+    if (boot_cpu_data.cpu_type == pcxl2)
+	return; /* pcxl2 doesn't support space register hashing */
+
+    switch (boot_cpu_data.cpu_type) {
+
+    case pcx:
+	BUG(); /* We shouldn't get here. code in setup.c should prevent it */
+	return;
+
+    case pcxs:
+    case pcxt:
+    case pcxt_:
+	srhash_type = SRHASH_PCXST;
+	break;
+
+    case pcxl:
+	srhash_type = SRHASH_PCXL;
+	break;
+
+    default: /* Currently all PA2.0 machines use the same ins. sequence */
+	srhash_type = SRHASH_PA20;
+	break;
+    }
+
+    disable_sr_hashing_asm(srhash_type);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/ccio-dma.c linux-2.4.20/arch/parisc/kernel/ccio-dma.c
--- linux-2.4.19/arch/parisc/kernel/ccio-dma.c	2001-10-12 22:35:53.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/ccio-dma.c	2002-10-29 11:18:34.000000000 +0000
@@ -38,16 +38,19 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#define PCI_DEBUG
 #include <linux/pci.h>
+#undef PCI_DEBUG
 
 #include <asm/byteorder.h>
 #include <asm/cache.h>		/* for L1_CACHE_BYTES */
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 #include <asm/page.h>
-
+#include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/gsc.h>		/* for gsc_writeN()... */
+#include <asm/hardware.h>       /* for register_module() */
 
 /* 
 ** Choose "ccio" since that's what HP-UX calls it.
@@ -55,12 +58,10 @@
 */
 #define MODULE_NAME "ccio"
 
-/*
-#define DEBUG_CCIO_RES
-#define DEBUG_CCIO_RUN
-#define DEBUG_CCIO_INIT
-#define DUMP_RESMAP
-*/
+#undef DEBUG_CCIO_RES
+#undef DEBUG_CCIO_RUN
+#undef DEBUG_CCIO_INIT
+#undef DEBUG_CCIO_RUN_SG
 
 #include <linux/proc_fs.h>
 #include <asm/runway.h>		/* for proc_runway_root */
@@ -83,68 +84,20 @@
 #define DBG_RES(x...)
 #endif
 
+#ifdef DEBUG_CCIO_RUN_SG
+#define DBG_RUN_SG(x...) printk(x)
+#else
+#define DBG_RUN_SG(x...)
+#endif
+
 #define CCIO_INLINE	/* inline */
-#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr))
+#define WRITE_U32(value, addr) gsc_writel(value, (u32 *)(addr))
+#define READ_U32(addr) gsc_readl((u32 *)(addr))
 
 #define U2_IOA_RUNWAY 0x580
 #define U2_BC_GSC     0x501
 #define UTURN_IOA_RUNWAY 0x581
 #define UTURN_BC_GSC     0x502
-/* We *can't* support JAVA (T600). Venture there at your own risk. */
-
-static void dump_resmap(void);
-
-static int ccio_driver_callback(struct hp_device *, struct pa_iodc_driver *);
-
-static struct pa_iodc_driver ccio_drivers_for[] = {
-
-   {HPHW_IOA, U2_IOA_RUNWAY, 0x0, 0xb, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "U2 I/O MMU", (void *) ccio_driver_callback},
-
-   {HPHW_IOA, UTURN_IOA_RUNWAY, 0x0, 0xb, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "Uturn I/O MMU", (void *) ccio_driver_callback},
-
-/*
-** FIXME: The following claims the GSC bus port, not the IOA.
-**        And there are two busses below a single I/O TLB.
-**
-** These should go away once we have a real PA bus walk.
-** Firmware wants to tell the PA bus walk code about the GSC ports
-** since they are not "architected" PA I/O devices. Ie a PA bus walk
-** wouldn't discover them. But the PA bus walk code could check
-** the "fixed module table" to add such devices to an I/O Tree
-** and proceed with the recursive, depth first bus walk.
-*/
-   {HPHW_BCPORT, U2_BC_GSC, 0x0, 0xc, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "U2 GSC+ BC", (void *) ccio_driver_callback},
-
-   {HPHW_BCPORT, UTURN_BC_GSC, 0x0, 0xc, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "Uturn GSC+ BC", (void *) ccio_driver_callback},
-
-   {0,0,0,0,0,0,
-   0,
-   (char *) NULL, (char *) NULL, (void *) NULL }
-};
-
-
-#define IS_U2(id) ( \
-    (((id)->hw_type == HPHW_IOA) && ((id)->hversion == U2_IOA_RUNWAY)) || \
-    (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == U2_BC_GSC))  \
-)
-
-#define IS_UTURN(id) ( \
-    (((id)->hw_type == HPHW_IOA) && ((id)->hversion == UTURN_IOA_RUNWAY)) || \
-    (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == UTURN_BC_GSC))  \
-)
-
 
 #define IOA_NORMAL_MODE      0x00020080 /* IO_CONTROL to turn on CCIO        */
 #define CMD_TLB_DIRECT_WRITE 35         /* IO_COMMAND for I/O TLB Writes     */
@@ -176,41 +129,46 @@
         volatile uint32_t   io_io_high;             /* Offset 15 */
 };
 
+struct ioc {
+	struct ioa_registers *ioc_hpa;  /* I/O MMU base address */
+	u8  *res_map;	                /* resource map, bit == pdir entry */
+	u64 *pdir_base;	                /* physical base address */
+	u32 res_hint;	                /* next available IOVP - 
+					   circular search */
+	u32 res_size;		    	/* size of resource map in bytes */
+	spinlock_t res_lock;
+
+#ifdef CONFIG_PROC_FS
+#define CCIO_SEARCH_SAMPLE 0x100
+	unsigned long avg_search[CCIO_SEARCH_SAMPLE];
+	unsigned long avg_idx;		  /* current index into avg_search */
+	unsigned long used_pages;
+	unsigned long msingle_calls;
+	unsigned long msingle_pages;
+	unsigned long msg_calls;
+	unsigned long msg_pages;
+	unsigned long usingle_calls;
+	unsigned long usingle_pages;
+	unsigned long usg_calls;
+	unsigned long usg_pages;
 
-struct ccio_device {
-	struct ccio_device    *next;  /* list of LBA's in system */
-	struct hp_device      *iodc;  /* data about dev from firmware */
-	spinlock_t            ccio_lock;
-
-	struct ioa_registers   *ccio_hpa; /* base address */
-	u64   *pdir_base;   /* physical base address */
-	char  *res_map;     /* resource map, bit == pdir entry */
-
-	int   res_hint;	/* next available IOVP - circular search */
-	int   res_size;	/* size of resource map in bytes */
-	int   chainid_shift; /* specify bit location of chain_id */
-	int   flags;         /* state/functionality enabled */
-#ifdef DELAYED_RESOURCE_CNT
-	dma_addr_t res_delay[DELAYED_RESOURCE_CNT];
+	unsigned short cujo20_bug;
 #endif
 
 	/* STUFF We don't need in performance path */
-	int  pdir_size;     /* in bytes, determined by IOV Space size */
-	int  hw_rev;        /* HW revision of chip */
+	u32 pdir_size; 			/* in bytes, determined by IOV Space size */
+	u32 chainid_shift; 		/* specify bit location of chain_id */
+	struct ioc *next;		/* Linked list of discovered iocs */
+	const char *name;		/* device name from firmware */
+	unsigned int hw_path;           /* the hardware path this ioc is associatd with */
+	struct pci_dev *fake_pci_dev;   /* the fake pci_dev for non-pci devs */
+	struct resource mmio_region[2]; /* The "routed" MMIO regions */
 };
 
-
 /* Ratio of Host MEM to IOV Space size */
 static unsigned long ccio_mem_ratio = 4;
-static struct ccio_device *ccio_list = NULL;
-
-static int ccio_proc_info(char *buffer, char **start, off_t offset, int length);
-static unsigned long ccio_used_bytes = 0;
-static unsigned long ccio_used_pages = 0;
-static int ccio_cujo_bug = 0;
-
-static unsigned long ccio_alloc_size = 0;
-static unsigned long ccio_free_size = 0;
+static struct ioc *ioc_list;
+static int ioc_count;
 
 /**************************************************************
 *
@@ -227,55 +185,41 @@
 *   match the I/O TLB replacement policy.
 *
 ***************************************************************/
-#define PAGES_PER_RANGE 1	/* could increase this to 4 or 8 if needed */
 #define IOVP_SIZE PAGE_SIZE
 #define IOVP_SHIFT PAGE_SHIFT
 #define IOVP_MASK PAGE_MASK
 
 /* Convert from IOVP to IOVA and vice versa. */
 #define CCIO_IOVA(iovp,offset) ((iovp) | (offset))
-#define CCIO_IOVP(iova) ((iova) & ~(IOVP_SIZE-1) )
+#define CCIO_IOVP(iova) ((iova) & IOVP_MASK)
 
 #define PDIR_INDEX(iovp)    ((iovp)>>IOVP_SHIFT)
 #define MKIOVP(pdir_idx)    ((long)(pdir_idx) << IOVP_SHIFT)
 #define MKIOVA(iovp,offset) (dma_addr_t)((long)iovp | (long)offset)
-
-/* CUJO20 KLUDGE start */
-#define CUJO_20_BITMASK    0x0ffff000	/* upper nibble is a don't care   */
-#define CUJO_20_STEP       0x10000000	/* inc upper nibble */
-#define CUJO_20_BADPAGE1   0x01003000	/* pages that hpmc on raven U+    */
-#define CUJO_20_BADPAGE2   0x01607000	/* pages that hpmc on firehawk U+ */
-#define CUJO_20_BADHVERS   0x6821	/* low nibble 1 is cujo rev 2.0 */
-#define CUJO_RAVEN_LOC     0xf1000000UL	/* cujo location on raven U+ */
-#define CUJO_FIREHAWK_LOC  0xf1604000UL	/* cujo location on firehawk U+ */
-/* CUJO20 KLUDGE end */
+#define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1))
 
 /*
 ** Don't worry about the 150% average search length on a miss.
 ** If the search wraps around, and passes the res_hint, it will
 ** cause the kernel to panic anyhow.
 */
-
-/* ioa->res_hint = idx + (size >> 3); \ */
-
-#define CCIO_SEARCH_LOOP(ioa, idx, mask, size)  \
-       for(; res_ptr < res_end; ++res_ptr) \
-       { \
-               if(0 == ((*res_ptr) & mask)) { \
-                       *res_ptr |= mask; \
-                       idx = (int)((unsigned long)res_ptr - (unsigned long)ioa->res_map); \
-                       ioa->res_hint = 0;\
+#define CCIO_SEARCH_LOOP(ioc, res_idx, mask_ptr, size)  \
+       for(; res_ptr < res_end; ++res_ptr) { \
+               if(0 == (*res_ptr & *mask_ptr)) { \
+                       *res_ptr |= *mask_ptr; \
+                       res_idx = (int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \
+                       ioc->res_hint = res_idx + (size >> 3); \
                        goto resource_found; \
                } \
        }
 
-#define CCIO_FIND_FREE_MAPPING(ioa, idx, mask, size)  { \
-       u##size *res_ptr = (u##size *)&((ioa)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \
-       u##size *res_end = (u##size *)&(ioa)->res_map[ioa->res_size]; \
-       CCIO_SEARCH_LOOP(ioa, idx, mask, size); \
-       res_ptr = (u##size *)&(ioa)->res_map[0]; \
-       CCIO_SEARCH_LOOP(ioa, idx, mask, size); \
-}
+#define CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, size) \
+       u##size *res_ptr = (u##size *)&((ioc)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \
+       u##size *res_end = (u##size *)&(ioc)->res_map[ioa->res_size]; \
+       u##size *mask_ptr = (u##size *)&mask; \
+       CCIO_SEARCH_LOOP(ioc, res_idx, mask_ptr, size); \
+       res_ptr = (u##size *)&(ioc)->res_map[0]; \
+       CCIO_SEARCH_LOOP(ioa, res_idx, mask_ptr, size);
 
 /*
 ** Find available bit in this ioa's resource map.
@@ -290,123 +234,132 @@
 ** o use different search for "large" (eg > 4 pages) or "very large"
 **   (eg > 16 pages) mappings.
 */
+
+/**
+ * ccio_alloc_range - Allocate pages in the ioc's resource map.
+ * @ioc: The I/O Controller.
+ * @pages_needed: The requested number of pages to be mapped into the
+ * I/O Pdir...
+ *
+ * This function searches the resource map of the ioc to locate a range
+ * of available pages for the requested size.
+ */
 static int
-ccio_alloc_range(struct ccio_device *ioa, size_t size)
+ccio_alloc_range(struct ioc *ioc, unsigned long pages_needed)
 {
 	int res_idx;
-	unsigned long mask, flags;
-	unsigned int pages_needed = size >> PAGE_SHIFT;
-
+	unsigned long mask;
+#ifdef CONFIG_PROC_FS
+	unsigned long cr_start = mfctl(16);
+#endif
+	
 	ASSERT(pages_needed);
-	ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE);
-	ASSERT(pages_needed < (BITS_PER_LONG - IOVP_SHIFT));
+	ASSERT((pages_needed * IOVP_SIZE) <= DMA_CHUNK_SIZE);
+	ASSERT(pages_needed <= BITS_PER_LONG);
 
-	mask = (unsigned long) -1L;
- 	mask >>= BITS_PER_LONG - pages_needed;
-
-	DBG_RES(__FUNCTION__ " size: %d pages_needed %d pages_mask 0x%08lx\n", 
-		size, pages_needed, mask);
-
-	spin_lock_irqsave(&ioa->ccio_lock, flags);
+	mask = ~(~0UL >> pages_needed);
+     
+	DBG_RES("%s() size: %d pages_needed %d mask 0x%08lx\n", 
+		__FUNCTION__, size, pages_needed, mask);
 
 	/*
 	** "seek and ye shall find"...praying never hurts either...
-	** ggg sacrafices another 710 to the computer gods.
+	** ggg sacrifices another 710 to the computer gods.
 	*/
 
 	if(pages_needed <= 8) {
-		CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 8);
+		CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 8);
 	} else if(pages_needed <= 16) {
-		CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 16);
+		CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 16);
 	} else if(pages_needed <= 32) {
-		CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 32);
+		CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 32);
 #ifdef __LP64__
 	} else if(pages_needed <= 64) {
-		CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 64)
+		CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 64);
 #endif
 	} else {
-		panic(__FILE__ ":" __FUNCTION__ "() Too many pages to map.\n");
+		panic(__FILE__ ": %s() Too many pages to map. pages_needed: %ld\n", 
+		      __FUNCTION__, pages_needed);
 	}
 
-#ifdef DUMP_RESMAP
-	dump_resmap();
-#endif
-	panic(__FILE__ ":" __FUNCTION__ "() I/O MMU is out of mapping resources\n");
+	panic(__FILE__ ": %s() I/O MMU is out of mapping resources.\n", 
+	      __FUNCTION__);
 	
 resource_found:
 	
-	DBG_RES(__FUNCTION__ " res_idx %d mask 0x%08lx res_hint: %d\n",
-		res_idx, mask, ioa->res_hint);
+	DBG_RES("%s() res_idx %d mask 0x%08lx res_hint: %d\n",
+		__FUNCTION__, res_idx, mask, ioc->res_hint);
 
-	ccio_used_pages += pages_needed;
-	ccio_used_bytes += ((pages_needed >> 3) ? (pages_needed >> 3) : 1);
-
-	spin_unlock_irqrestore(&ioa->ccio_lock, flags);
+#ifdef CONFIG_PROC_FS
+	{
+		unsigned long cr_end = mfctl(16);
+		unsigned long tmp = cr_end - cr_start;
+		/* check for roll over */
+		cr_start = (cr_end < cr_start) ?  -(tmp) : (tmp);
+	}
+	ioc->avg_search[ioc->avg_idx++] = cr_start;
+	ioc->avg_idx &= CCIO_SEARCH_SAMPLE - 1;
 
-#ifdef DUMP_RESMAP
-	dump_resmap();
+	ioc->used_pages += pages_needed;
 #endif
 
 	/* 
-	** return the bit address (convert from byte to bit).
+	** return the bit address.
 	*/
-	return (res_idx << 3);
+	return res_idx << 3;
 }
 
-
-#define CCIO_FREE_MAPPINGS(ioa, idx, mask, size) \
-        u##size *res_ptr = (u##size *)&((ioa)->res_map[idx + (((size >> 3) - 1) & ~((size >> 3) - 1))]); \
-        ASSERT((*res_ptr & mask) == mask); \
-        *res_ptr &= ~mask;
-
-/*
-** clear bits in the ioa's resource map
-*/
+#define CCIO_FREE_MAPPINGS(ioc, res_idx, mask, size) \
+        u##size *res_ptr = (u##size *)&((ioc)->res_map[res_idx]); \
+	u##size *mask_ptr = (u##size *)&mask; \
+        ASSERT((*res_ptr & *mask_ptr) == *mask_ptr); \
+        *res_ptr &= ~(*mask_ptr);
+
+/**
+ * ccio_free_range - Free pages from the ioc's resource map.
+ * @ioc: The I/O Controller.
+ * @iova: The I/O Virtual Address.
+ * @pages_mapped: The requested number of pages to be freed from the
+ * I/O Pdir.
+ *
+ * This function frees the resouces allocated for the iova.
+ */
 static void
-ccio_free_range(struct ccio_device *ioa, dma_addr_t iova, size_t size)
+ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped)
 {
-	unsigned long mask, flags;
+	unsigned long mask;
 	unsigned long iovp = CCIO_IOVP(iova);
-	unsigned int res_idx = PDIR_INDEX(iovp)>>3;
-	unsigned int pages_mapped = (size >> IOVP_SHIFT) + !!(size & ~IOVP_MASK);
+	unsigned int res_idx = PDIR_INDEX(iovp) >> 3;
 
-	ASSERT(pages_needed);
-	ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE);
-	ASSERT(pages_needed < (BITS_PER_LONG - IOVP_SHIFT));
+	ASSERT(pages_mapped);
+	ASSERT((pages_mapped * IOVP_SIZE) <= DMA_CHUNK_SIZE);
+	ASSERT(pages_mapped <= BITS_PER_LONG);
 
-	mask = (unsigned long) -1L;
- 	mask >>= BITS_PER_LONG - pages_mapped;
+	mask = ~(~0UL >> pages_mapped);
 
-	DBG_RES(__FUNCTION__ " res_idx: %d size: %d pages_mapped %d mask 0x%08lx\n", 
-		res_idx, size, pages_mapped, mask);
+	DBG_RES("%s():  res_idx: %d pages_mapped %d mask 0x%08lx\n", 
+		__FUNCTION__, res_idx, pages_mapped, mask);
 
-	spin_lock_irqsave(&ioa->ccio_lock, flags);
+#ifdef CONFIG_PROC_FS
+	ioc->used_pages -= pages_mapped;
+#endif
 
 	if(pages_mapped <= 8) {
-		CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 8);
+		CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 8);
 	} else if(pages_mapped <= 16) {
-		CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 16);
+		CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 16);
 	} else if(pages_mapped <= 32) {
-		CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 32);
+		CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 32);
 #ifdef __LP64__
 	} else if(pages_mapped <= 64) {
-		CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 64);
+		CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 64);
 #endif
 	} else {
-		panic(__FILE__ ":" __FUNCTION__ "() Too many pages to unmap.\n");
+		panic(__FILE__ ":%s() Too many pages to unmap.\n", 
+		      __FUNCTION__);
 	}
-	
-	ccio_used_pages -= (pages_mapped ? pages_mapped : 1);
-	ccio_used_bytes -= ((pages_mapped >> 3) ? (pages_mapped >> 3) : 1);
-
-	spin_unlock_irqrestore(&ioa->ccio_lock, flags);
-
-#ifdef DUMP_RESMAP
-	dump_resmap();
-#endif
 }
 
-
 /****************************************************************
 **
 **          CCIO dma_ops support routines
@@ -416,7 +369,6 @@
 typedef unsigned long space_t;
 #define KERNEL_SPACE 0
 
-
 /*
 ** DMA "Page Type" and Hints 
 ** o if SAFE_DMA isn't set, mapping is for FAST_DMA. SAFE_DMA should be
@@ -466,32 +418,35 @@
 	[PCI_DMA_NONE]           0,            /* not valid */
 };
 
-/*
-** Initialize an I/O Pdir entry
-**
-** Given a virtual address (vba, arg2) and space id, (sid, arg1),
-** load the I/O PDIR entry pointed to by pdir_ptr (arg0). Each IO Pdir
-** entry consists of 8 bytes as shown below (MSB == bit 0):
-**
-**
-** WORD 0:
-** +------+----------------+-----------------------------------------------+
-** | Phys | Virtual Index  |               Phys                            |
-** | 0:3  |     0:11       |               4:19                            |
-** |4 bits|   12 bits      |              16 bits                          |
-** +------+----------------+-----------------------------------------------+
-** WORD 1:
-** +-----------------------+-----------------------------------------------+
-** |      Phys    |  Rsvd  | Prefetch |Update |Rsvd  |Lock  |Safe  |Valid  |
-** |     20:39    |        | Enable   |Enable |      |Enable|DMA   |       |
-** |    20 bits   | 5 bits | 1 bit    |1 bit  |2 bits|1 bit |1 bit |1 bit  |
-** +-----------------------+-----------------------------------------------+
-**
-** The virtual index field is filled with the results of the LCI
-** (Load Coherence Index) instruction.  The 8 bits used for the virtual
-** index are bits 12:19 of the value returned by LCI.
-*/
-
+/**
+ * ccio_io_pdir_entry - Initialize an I/O Pdir.
+ * @pdir_ptr: A pointer into I/O Pdir.
+ * @sid: The Space Identifier.
+ * @vba: The virtual address.
+ * @hints: The DMA Hint.
+ *
+ * Given a virtual address (vba, arg2) and space id, (sid, arg1),
+ * load the I/O PDIR entry pointed to by pdir_ptr (arg0). Each IO Pdir
+ * entry consists of 8 bytes as shown below (MSB == bit 0):
+ *
+ *
+ * WORD 0:
+ * +------+----------------+-----------------------------------------------+
+ * | Phys | Virtual Index  |               Phys                            |
+ * | 0:3  |     0:11       |               4:19                            |
+ * |4 bits|   12 bits      |              16 bits                          |
+ * +------+----------------+-----------------------------------------------+
+ * WORD 1:
+ * +-----------------------+-----------------------------------------------+
+ * |      Phys    |  Rsvd  | Prefetch |Update |Rsvd  |Lock  |Safe  |Valid  |
+ * |     20:39    |        | Enable   |Enable |      |Enable|DMA   |       |
+ * |    20 bits   | 5 bits | 1 bit    |1 bit  |2 bits|1 bit |1 bit |1 bit  |
+ * +-----------------------+-----------------------------------------------+
+ *
+ * The virtual index field is filled with the results of the LCI
+ * (Load Coherence Index) instruction.  The 8 bits used for the virtual
+ * index are bits 12:19 of the value returned by LCI.
+ */ 
 void CCIO_INLINE
 ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, void * vba, unsigned long hints)
 {
@@ -499,8 +454,7 @@
 	register unsigned long ci; /* coherent index */
 
 	/* We currently only support kernel addresses */
-	ASSERT(sid == 0);
-	ASSERT(((unsigned long) vba & 0xf0000000UL) == 0xc0000000UL);
+	ASSERT(sid == KERNEL_SPACE);
 
 	mtsp(sid,1);
 
@@ -524,7 +478,7 @@
 	** and deposit them
 	*/
 	asm volatile ("extrd,u %1,15,4,%0" : "=r" (ci) : "r" (pa));
-	asm volatile ("extrd,u %1,31,16,%0" : "+r" (ci) : "r" (ci));
+	asm volatile ("extrd,u %1,31,16,%0" : "+r" (pa) : "r" (pa));
 	asm volatile ("depd  %1,35,4,%0" : "+r" (pa) : "r" (ci));
 #else
 	pa = 0;
@@ -556,31 +510,39 @@
 	asm volatile("sync");
 }
 
-
-/*
-** Remove stale entries from the I/O TLB.
-** Need to do this whenever an entry in the PDIR is marked invalid.
-*/
+/**
+ * ccio_clear_io_tlb - Remove stale entries from the I/O TLB.
+ * @ioc: The I/O Controller.
+ * @iovp: The I/O Virtual Page.
+ * @byte_cnt: The requested number of bytes to be freed from the I/O Pdir.
+ *
+ * Purge invalid I/O PDIR entries from the I/O TLB.
+ *
+ * FIXME: Can we change the byte_cnt to pages_mapped?
+ */
 static CCIO_INLINE void
-ccio_clear_io_tlb( struct ccio_device *d, dma_addr_t iovp, size_t byte_cnt)
+ccio_clear_io_tlb(struct ioc *ioc, dma_addr_t iovp, size_t byte_cnt)
 {
-	u32 chain_size = 1 << d->chainid_shift;
+	u32 chain_size = 1 << ioc->chainid_shift;
 
-	iovp &= ~(IOVP_SIZE-1);	/* clear offset bits, just want pagenum */
+	iovp &= IOVP_MASK;	/* clear offset bits, just want pagenum */
 	byte_cnt += chain_size;
 
-        while (byte_cnt > chain_size) {
-		WRITE_U32(CMD_TLB_PURGE | iovp, &d->ccio_hpa->io_command);
-                iovp += chain_size;
+	while(byte_cnt > chain_size) {
+		WRITE_U32(CMD_TLB_PURGE | iovp, &ioc->ioc_hpa->io_command);
+		iovp += chain_size;
 		byte_cnt -= chain_size;
-        }
+      }
 }
 
-
-/***********************************************************
+/**
+ * ccio_mark_invalid - Mark the I/O Pdir entries invalid.
+ * @ioc: The I/O Controller.
+ * @iova: The I/O Virtual Address.
+ * @byte_cnt: The requested number of bytes to be freed from the I/O Pdir.
  *
- * Mark the I/O Pdir entries invalid and blow away the
- * corresponding I/O TLB entries.
+ * Mark the I/O Pdir entries invalid and blow away the corresponding I/O
+ * TLB entries.
  *
  * FIXME: at some threshhold it might be "cheaper" to just blow
  *        away the entire I/O TLB instead of individual entries.
@@ -588,25 +550,25 @@
  * FIXME: Uturn has 256 TLB entries. We don't need to purge every
  *        PDIR entry - just once for each possible TLB entry.
  *        (We do need to maker I/O PDIR entries invalid regardless).
- ***********************************************************/
+ *
+ * FIXME: Can we change byte_cnt to pages_mapped?
+ */ 
 static CCIO_INLINE void
-ccio_mark_invalid(struct ccio_device *d, dma_addr_t iova, size_t byte_cnt)
+ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
 {
-	u32 iovp = (u32) CCIO_IOVP(iova);
+	u32 iovp = (u32)CCIO_IOVP(iova);
 	size_t saved_byte_cnt;
 
 	/* round up to nearest page size */
-	saved_byte_cnt = byte_cnt = (byte_cnt + IOVP_SIZE - 1) & IOVP_MASK;
+	saved_byte_cnt = byte_cnt = ROUNDUP(byte_cnt, IOVP_SIZE);
 
-	while (byte_cnt > 0) {
+	while(byte_cnt > 0) {
 		/* invalidate one page at a time */
 		unsigned int idx = PDIR_INDEX(iovp);
-		char *pdir_ptr = (char *) &(d->pdir_base[idx]);
-
-		ASSERT( idx < (d->pdir_size/sizeof(u64)));
-
-		pdir_ptr[7] = 0;	/* clear only VALID bit */
+		char *pdir_ptr = (char *) &(ioc->pdir_base[idx]);
 
+		ASSERT(idx < (ioc->pdir_size / sizeof(u64)));
+		pdir_ptr[7] = 0;	/* clear only VALID bit */ 
 		/*
 		** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360)
 		**   PCX-U/U+ do. (eg C200/C240)
@@ -622,232 +584,485 @@
 	}
 
 	asm volatile("sync");
-	ccio_clear_io_tlb(d, CCIO_IOVP(iova), saved_byte_cnt);
+	ccio_clear_io_tlb(ioc, CCIO_IOVP(iova), saved_byte_cnt);
 }
 
-
 /****************************************************************
 **
 **          CCIO dma_ops
 **
 *****************************************************************/
 
-void __init ccio_init(void)
-{
-	register_driver(ccio_drivers_for);
-}
-
-
-static int ccio_dma_supported( struct pci_dev *dev, u64 mask)
+/**
+ * ccio_dma_supported - Verify the IOMMU supports the DMA address range.
+ * @dev: The PCI device.
+ * @mask: A bit mask describing the DMA address range of the device.
+ *
+ * This function implements the pci_dma_supported function.
+ */
+static int 
+ccio_dma_supported(struct pci_dev *dev, u64 mask)
 {
-	if (dev == NULL) {
-		printk(MODULE_NAME ": EISA/ISA/et al not supported\n");
+	if(dev == NULL) {
+		printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n");
 		BUG();
-		return(0);
+		return 0;
 	}
 
 	dev->dma_mask = mask;   /* save it */
 
 	/* only support 32-bit devices (ie PCI/GSC) */
-	return((int) (mask >= 0xffffffffUL));
+	return (int)(mask == 0xffffffffUL);
 }
 
-/*
-** Dump a hex representation of the resource map.
-*/
-
-#ifdef DUMP_RESMAP
-static 
-void dump_resmap()
-{
-	struct ccio_device *ioa = ccio_list;
-	unsigned long *res_ptr = (unsigned long *)ioa->res_map;
-	unsigned long i = 0;
-
-	printk("res_map: ");
-	for(; i < (ioa->res_size / sizeof(unsigned long)); ++i, ++res_ptr)
-		printk("%08lx ", *res_ptr);
-
-	printk("\n");
-}
-#endif
-
-/*
-** map_single returns a fully formed IOVA
-*/
-static dma_addr_t ccio_map_single(struct pci_dev *dev, void *addr, size_t size, int direction)
+/**
+ * ccio_map_single - Map an address range into the IOMMU.
+ * @dev: The PCI device.
+ * @addr: The start address of the DMA region.
+ * @size: The length of the DMA region.
+ * @direction: The direction of the DMA transaction (to/from device).
+ *
+ * This function implements the pci_map_single function.
+ */
+static dma_addr_t 
+ccio_map_single(struct pci_dev *dev, void *addr, size_t size, int direction)
 {
-	struct ccio_device *ioa = ccio_list;  /* FIXME : see Multi-IOC below */
+	int idx;
+	struct ioc *ioc;
+	unsigned long flags;
 	dma_addr_t iovp;
 	dma_addr_t offset;
 	u64 *pdir_start;
 	unsigned long hint = hint_lookup[direction];
-	int idx;
+
+	ASSERT(dev);
+	ASSERT(dev->sysdata);
+	ASSERT(HBA_DATA(dev->sysdata)->iommu);
+	ioc = GET_IOC(dev);
 
 	ASSERT(size > 0);
 
 	/* save offset bits */
-	offset = ((dma_addr_t) addr) & ~IOVP_MASK;
+	offset = ((unsigned long) addr) & ~IOVP_MASK;
 
 	/* round up to nearest IOVP_SIZE */
-	size = (size + offset + IOVP_SIZE - 1) & IOVP_MASK;
+	size = ROUNDUP(size + offset, IOVP_SIZE);
+	spin_lock_irqsave(&ioc->res_lock, flags);
+
+#ifdef CONFIG_PROC_FS
+	ioc->msingle_calls++;
+	ioc->msingle_pages += size >> IOVP_SHIFT;
+#endif
 
-	idx = ccio_alloc_range(ioa, size);
-	iovp = (dma_addr_t) MKIOVP(idx);
+	idx = ccio_alloc_range(ioc, (size >> IOVP_SHIFT));
+	iovp = (dma_addr_t)MKIOVP(idx);
 
-	DBG_RUN(__FUNCTION__ " 0x%p -> 0x%lx", addr, (long) iovp | offset);
+	pdir_start = &(ioc->pdir_base[idx]);
 
-	pdir_start = &(ioa->pdir_base[idx]);
+	DBG_RUN("%s() 0x%p -> 0x%lx size: %0x%x\n",
+		__FUNCTION__, addr, (long)iovp | offset, size);
 
 	/* If not cacheline aligned, force SAFE_DMA on the whole mess */
-	if ((size % L1_CACHE_BYTES) || ((unsigned long) addr % L1_CACHE_BYTES))
+	if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES))
 		hint |= HINT_SAFE_DMA;
 
-	/* round up to nearest IOVP_SIZE */
-	size = (size + IOVP_SIZE - 1) & IOVP_MASK;
-
-	while (size > 0) {
-
+	while(size > 0) {
 		ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, addr, hint);
 
 		DBG_RUN(" pdir %p %08x%08x\n",
 			pdir_start,
 			(u32) (((u32 *) pdir_start)[0]),
-			(u32) (((u32 *) pdir_start)[1])
-			);
+			(u32) (((u32 *) pdir_start)[1]));
+		++pdir_start;
 		addr += IOVP_SIZE;
 		size -= IOVP_SIZE;
-		pdir_start++;
 	}
+
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
+
 	/* form complete address */
 	return CCIO_IOVA(iovp, offset);
 }
 
-
-static void ccio_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction)
-{
-#ifdef FIXME
-/* Multi-IOC (ie N-class) :  need to lookup IOC from dev
-** o If we can't know about lba PCI data structs, that eliminates ->sysdata.
-** o walking up pcidev->parent dead ends at elroy too
-** o leaves hashing dev->bus->number into some lookup.
-**   (may only work for N-class)
-*/
-	struct ccio_device *ioa = dev->sysdata
-#else
-	struct ccio_device *ioa = ccio_list;
-#endif
-	dma_addr_t offset;
+/**
+ * ccio_unmap_single - Unmap an address range from the IOMMU.
+ * @dev: The PCI device.
+ * @addr: The start address of the DMA region.
+ * @size: The length of the DMA region.
+ * @direction: The direction of the DMA transaction (to/from device).
+ *
+ * This function implements the pci_unmap_single function.
+ */
+static void 
+ccio_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, 
+		  int direction)
+{
+	struct ioc *ioc;
+	unsigned long flags; 
+	dma_addr_t offset = iova & ~IOVP_MASK;
 	
-	offset = iova & ~IOVP_MASK;
-
-	/* round up to nearest IOVP_SIZE */
-	size = (size + offset + IOVP_SIZE - 1) & IOVP_MASK;
+	ASSERT(dev);
+	ASSERT(dev->sysdata);
+	ASSERT(HBA_DATA(dev->sysdata)->iommu);
+	ioc = GET_IOC(dev);
+
+	DBG_RUN("%s() iovp 0x%lx/%x\n",
+		__FUNCTION__, (long)iova, size);
+
+	iova ^= offset;        /* clear offset bits */
+	size += offset;
+	size = ROUNDUP(size, IOVP_SIZE);
 
-	/* Mask off offset */
-	iova &= IOVP_MASK;
+	spin_lock_irqsave(&ioc->res_lock, flags);
 
-	DBG_RUN(__FUNCTION__ " iovp 0x%lx\n", (long) iova);
-
-#ifdef DELAYED_RESOURCE_CNT
-	if (ioa->saved_cnt < DELAYED_RESOURCE_CNT) {
-		ioa->saved_iova[ioa->saved_cnt] = iova;
-		ioa->saved_size[ioa->saved_cnt] = size;
-		ccio_saved_cnt++;
-	} else {
-		do {
+#ifdef CONFIG_PROC_FS
+	ioc->usingle_calls++;
+	ioc->usingle_pages += size >> IOVP_SHIFT;
 #endif
-			ccio_mark_invalid(ioa, iova, size);
-			ccio_free_range(ioa, iova, size);
 
-#ifdef DELAYED_RESOURCE_CNT
-			d->saved_cnt--;
-			iova = ioa->saved_iova[ioa->saved_cnt];
-			size = ioa->saved_size[ioa->saved_cnt];
-		} while (ioa->saved_cnt)
-	}
-#endif
+	ccio_mark_invalid(ioc, iova, size);
+	ccio_free_range(ioc, iova, (size >> IOVP_SHIFT));
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
 }
 
-
-static void * ccio_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
+/**
+ * ccio_alloc_consistent - Allocate a consistent DMA mapping.
+ * @dev: The PCI device.
+ * @size: The length of the DMA region.
+ * @dma_handle: The DMA address handed back to the device (not the cpu).
+ *
+ * This function implements the pci_alloc_consistent function.
+ */
+static void * 
+ccio_alloc_consistent(struct pci_dev *dev, size_t size, dma_addr_t *dma_handle)
 {
-	void *ret;
-	unsigned long flags;
-	struct ccio_device *ioa = ccio_list;
-
-	DBG_RUN(__FUNCTION__ " size 0x%x\n",  size);
-
+      void *ret;
 #if 0
 /* GRANT Need to establish hierarchy for non-PCI devs as well
 ** and then provide matching gsc_map_xxx() functions for them as well.
 */
-	if (!hwdev) {
+	if(!hwdev) {
 		/* only support PCI */
 		*dma_handle = 0;
 		return 0;
 	}
 #endif
-	spin_lock_irqsave(&ioa->ccio_lock, flags);
-	ccio_alloc_size += get_order(size);
-	spin_unlock_irqrestore(&ioa->ccio_lock, flags);
-
         ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size));
 
 	if (ret) {
 		memset(ret, 0, size);
-		*dma_handle = ccio_map_single(hwdev, ret, size, PCI_DMA_BIDIRECTIONAL);
+		*dma_handle = ccio_map_single(dev, ret, size, PCI_DMA_BIDIRECTIONAL);
 	}
-	DBG_RUN(__FUNCTION__ " ret %p\n",  ret);
 
 	return ret;
 }
 
-
-static void ccio_free_consistent (struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
+/**
+ * ccio_free_consistent - Free a consistent DMA mapping.
+ * @dev: The PCI device.
+ * @size: The length of the DMA region.
+ * @cpu_addr: The cpu address returned from the ccio_alloc_consistent.
+ * @dma_handle: The device address returned from the ccio_alloc_consistent.
+ *
+ * This function implements the pci_free_consistent function.
+ */
+static void 
+ccio_free_consistent(struct pci_dev *dev, size_t size, void *cpu_addr, 
+		     dma_addr_t dma_handle)
 {
-	unsigned long flags;
-	struct ccio_device *ioa = ccio_list;
+	ccio_unmap_single(dev, dma_handle, size, 0);
+	free_pages((unsigned long)cpu_addr, get_order(size));
+}
 
-	spin_lock_irqsave(&ioa->ccio_lock, flags);
-	ccio_free_size += get_order(size);
-	spin_unlock_irqrestore(&ioa->ccio_lock, flags);
+/*
+** Since 0 is a valid pdir_base index value, can't use that
+** to determine if a value is valid or not. Use a flag to indicate
+** the SG list entry contains a valid pdir index.
+*/
+#define PIDE_FLAG 0x80000000UL
 
-	ccio_unmap_single(hwdev, dma_handle, size, 0);
-	free_pages((unsigned long) vaddr, get_order(size));
+/**
+ * ccio_fill_pdir - Insert coalesced scatter/gather chunks into the I/O Pdir.
+ * @ioc: The I/O Controller.
+ * @startsg: The scatter/gather list of coalesced chunks.
+ * @nents: The number of entries in the scatter/gather list.
+ * @hint: The DMA Hint.
+ *
+ * This function inserts the coalesced scatter/gather list chunks into the
+ * I/O Controller's I/O Pdir.
+ */ 
+static CCIO_INLINE int
+ccio_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents, 
+	       unsigned long hint)
+{
+	struct scatterlist *dma_sg = startsg;	/* pointer to current DMA */
+	int n_mappings = 0;
+	u64 *pdirp = 0;
+	unsigned long dma_offset = 0;
+
+	dma_sg--;
+	while (nents-- > 0) {
+		int cnt = sg_dma_len(startsg);
+		sg_dma_len(startsg) = 0;
+
+		DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n", nents,
+			   (unsigned long)sg_dma_address(startsg), cnt,
+			   startsg->address, startsg->length
+		);
+
+		/*
+		** Look for the start of a new DMA stream
+		*/
+		if(sg_dma_address(startsg) & PIDE_FLAG) {
+			u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG;
+			dma_offset = (unsigned long) pide & ~IOVP_MASK;
+			sg_dma_address(startsg) = 0;
+			dma_sg++;
+			sg_dma_address(dma_sg) = pide;
+			pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]);
+			n_mappings++;
+		}
+
+		/*
+		** Look for a VCONTIG chunk
+		*/
+		if (cnt) {
+			unsigned long vaddr = (unsigned long)startsg->address;
+			ASSERT(pdirp);
+
+			/* Since multiple Vcontig blocks could make up
+			** one DMA stream, *add* cnt to dma_len.
+			*/
+			sg_dma_len(dma_sg) += cnt;
+			cnt += dma_offset;
+			dma_offset=0;	/* only want offset on first chunk */
+			cnt = ROUNDUP(cnt, IOVP_SIZE);
+#ifdef CONFIG_PROC_FS
+			ioc->msg_pages += cnt >> IOVP_SHIFT;
+#endif
+			do {
+				ccio_io_pdir_entry(pdirp, KERNEL_SPACE, 
+						   (void *)vaddr, hint);
+				vaddr += IOVP_SIZE;
+				cnt -= IOVP_SIZE;
+				pdirp++;
+			} while (cnt > 0);
+		}
+		startsg++;
+	}
+	return(n_mappings);
 }
 
+/*
+** First pass is to walk the SG list and determine where the breaks are
+** in the DMA stream. Allocates PDIR entries but does not fill them.
+** Returns the number of DMA chunks.
+**
+** Doing the fill seperate from the coalescing/allocation keeps the
+** code simpler. Future enhancement could make one pass through
+** the sglist do both.
+*/
 
-static int ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
+static CCIO_INLINE int
+ccio_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg, int nents)
 {
-	int tmp = nents;
+	struct scatterlist *vcontig_sg;    /* VCONTIG chunk head */
+	unsigned long vcontig_len;         /* len of VCONTIG chunk */
+	unsigned long vcontig_end;
+	struct scatterlist *dma_sg;        /* next DMA stream head */
+	unsigned long dma_offset, dma_len; /* start/len of DMA stream */
+	int n_mappings = 0;
+
+	while (nents > 0) {
+
+		/*
+		** Prepare for first/next DMA stream
+		*/
+		dma_sg = vcontig_sg = startsg;
+		dma_len = vcontig_len = vcontig_end = startsg->length;
+		vcontig_end += (unsigned long) startsg->address;
+		dma_offset = (unsigned long) startsg->address & ~IOVP_MASK;
+
+		/* PARANOID: clear entries */
+		sg_dma_address(startsg) = 0;
+		sg_dma_len(startsg) = 0;
+
+		/*
+		** This loop terminates one iteration "early" since
+		** it's always looking one "ahead".
+		*/
+		while(--nents > 0) {
+			unsigned long startsg_end;
 
-	DBG_RUN(KERN_WARNING __FUNCTION__ " START\n");
+			startsg++;
+			startsg_end = (unsigned long)startsg->address + 
+				startsg->length;
+
+			/* PARANOID: clear entries */
+			sg_dma_address(startsg) = 0;
+			sg_dma_len(startsg) = 0;
+
+			/*
+			** First make sure current dma stream won't
+			** exceed DMA_CHUNK_SIZE if we coalesce the
+			** next entry.
+			*/   
+			if(ROUNDUP(dma_len + dma_offset + startsg->length,
+				   IOVP_SIZE) > DMA_CHUNK_SIZE)
+				break;
+
+			/*
+			** Append the next transaction?
+			*/
+			if(vcontig_end == (unsigned long) startsg->address) {
+				vcontig_len += startsg->length;
+				vcontig_end += startsg->length;
+				dma_len     += startsg->length;
+				continue;
+			}
+
+			/*
+			** Not virtually contigous.
+			** Terminate prev chunk.
+			** Start a new chunk.
+			**
+			** Once we start a new VCONTIG chunk, dma_offset
+			** can't change. And we need the offset from the first
+			** chunk - not the last one. Ergo Successive chunks
+			** must start on page boundaries and dove tail
+			** with it's predecessor.
+			*/
+			sg_dma_len(vcontig_sg) = vcontig_len;
+
+			vcontig_sg = startsg;
+			vcontig_len = startsg->length;
+			break;
+		}
 
-        /* KISS: map each buffer seperately. */
-	while (nents) {
-		sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction);
-		sg_dma_len(sglist) = sglist->length;
-		nents--;
-		sglist++;
+		/*
+		** End of DMA Stream
+		** Terminate last VCONTIG block.
+		** Allocate space for DMA stream.
+		*/
+		sg_dma_len(vcontig_sg) = vcontig_len;
+		dma_len = ROUNDUP(dma_len + dma_offset, IOVP_SIZE);
+		sg_dma_address(dma_sg) =
+			PIDE_FLAG 
+			| (ccio_alloc_range(ioc, (dma_len >> IOVP_SHIFT)) << IOVP_SHIFT)
+			| dma_offset;
+		n_mappings++;
 	}
 
-	DBG_RUN(KERN_WARNING __FUNCTION__ " DONE\n");
-	return tmp;
+	return n_mappings;
 }
 
-
-static void ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
+/**
+ * ccio_map_sg - Map the scatter/gather list into the IOMMU.
+ * @dev: The PCI device.
+ * @sglist: The scatter/gather list to be mapped in the IOMMU.
+ * @nents: The number of entries in the scatter/gather list.
+ * @direction: The direction of the DMA transaction (to/from device).
+ *
+ * This function implements the pci_map_sg function.
+ */
+static int
+ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, 
+	    int direction)
 {
-	DBG_RUN(KERN_WARNING __FUNCTION__ " : unmapping %d entries\n", nents);
-	while (nents) {
-		ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction);
-		nents--;
-		sglist++;
+	struct ioc *ioc;
+	int coalesced, filled = 0;
+	unsigned long flags;
+	unsigned long hint = hint_lookup[direction];
+	
+	ASSERT(dev);
+	ASSERT(dev->sysdata);
+	ASSERT(HBA_DATA(dev->sysdata)->iommu);
+	ioc = GET_IOC(dev);
+	
+	DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents);
+
+	/* Fast path single entry scatterlists. */
+	if(nents == 1) {
+		sg_dma_address(sglist)= ccio_map_single(dev, sglist->address,
+							sglist->length, 
+							direction);
+		sg_dma_len(sglist)= sglist->length;
+		return 1;
 	}
-	return;
+	
+	spin_lock_irqsave(&ioc->res_lock, flags);
+
+#ifdef CONFIG_PROC_FS
+	ioc->msg_calls++;
+#endif
+
+	/*
+	** First coalesce the chunks and allocate I/O pdir space
+	**
+	** If this is one DMA stream, we can properly map using the
+	** correct virtual address associated with each DMA page.
+	** w/o this association, we wouldn't have coherent DMA!
+	** Access to the virtual address is what forces a two pass algorithm.
+	*/
+	coalesced = ccio_coalesce_chunks(ioc, sglist, nents);
+
+	/*
+	** Program the I/O Pdir
+	**
+	** map the virtual addresses to the I/O Pdir
+	** o dma_address will contain the pdir index
+	** o dma_len will contain the number of bytes to map 
+	** o address contains the virtual address.
+	*/
+	filled = ccio_fill_pdir(ioc, sglist, nents, hint);
+
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
+
+	ASSERT(coalesced == filled);
+	DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled);
+
+	return filled;
 }
 
+/**
+ * ccio_unmap_sg - Unmap the scatter/gather list from the IOMMU.
+ * @dev: The PCI device.
+ * @sglist: The scatter/gather list to be unmapped from the IOMMU.
+ * @nents: The number of entries in the scatter/gather list.
+ * @direction: The direction of the DMA transaction (to/from device).
+ *
+ * This function implements the pci_unmap_sg function.
+ */
+static void 
+ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, 
+	      int direction)
+{
+	struct ioc *ioc;
+
+	ASSERT(dev);
+	ASSERT(dev->sysdata);
+	ASSERT(HBA_DATA(dev->sysdata)->iommu);
+	ioc = GET_IOC(dev);
+
+	DBG_RUN_SG("%s() START %d entries,  %p,%x\n",
+		__FUNCTION__, nents, sglist->address, sglist->length);
+
+#ifdef CONFIG_PROC_FS
+	ioc->usg_calls++;
+#endif
+
+	while(sg_dma_len(sglist) && nents--) {
+
+#ifdef CONFIG_PROC_FS
+		ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT;
+#endif
+		ccio_unmap_single(dev, sg_dma_address(sglist),
+				  sg_dma_len(sglist), direction);
+		++sglist;
+	}
+
+	DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__, nents);
+}
 
 static struct pci_dma_ops ccio_ops = {
 	ccio_dma_supported,
@@ -861,6 +1076,201 @@
 	NULL,                   /* dma_sync_sg     : ditto */
 };
 
+#ifdef CONFIG_PROC_FS
+static int proc_append(char *src, int len, char **dst, off_t *offset, int *max)
+{
+	if (len < *offset) {
+		*offset -= len;
+		return 0;
+	}
+	if (*offset > 0) {
+		src += *offset;
+		len -= *offset;
+		*offset = 0;
+	}
+	if (len > *max) {
+		len = *max;
+	}
+	memcpy(*dst, src, len);
+	*dst += len;
+	*max -= len;
+	return (*max == 0);
+}
+
+static int ccio_proc_info(char *buf, char **start, off_t offset, int count,
+			  int *eof, void *data)
+{
+	int max = count;
+	char tmp[80]; /* width of an ANSI-standard terminal */
+	struct ioc *ioc = ioc_list;
+
+	while (ioc != NULL) {
+		unsigned int total_pages = ioc->res_size << 3;
+		unsigned long avg = 0, min, max;
+		int j, len;
+
+		len = sprintf(tmp, "%s\n", ioc->name);
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+		
+		len = sprintf(tmp, "Cujo 2.0 bug    : %s\n",
+			      (ioc->cujo20_bug ? "yes" : "no"));
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+		
+		len = sprintf(tmp, "IO PDIR size    : %d bytes (%d entries)\n",
+			      total_pages * 8, total_pages);
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+		
+		len = sprintf(tmp, "IO PDIR entries : %ld free  %ld used (%d%%)\n",
+			      total_pages - ioc->used_pages, ioc->used_pages,
+			      (int)(ioc->used_pages * 100 / total_pages));
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+		
+		len = sprintf(tmp, "Resource bitmap : %d bytes (%d pages)\n", 
+			ioc->res_size, total_pages);
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+		
+		min = max = ioc->avg_search[0];
+		for(j = 0; j < CCIO_SEARCH_SAMPLE; ++j) {
+			avg += ioc->avg_search[j];
+			if(ioc->avg_search[j] > max) 
+				max = ioc->avg_search[j];
+			if(ioc->avg_search[j] < min) 
+				min = ioc->avg_search[j];
+		}
+		avg /= CCIO_SEARCH_SAMPLE;
+		len = sprintf(tmp, "  Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
+			      min, avg, max);
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+
+		len = sprintf(tmp, "pci_map_single(): %8ld calls  %8ld pages (avg %d/1000)\n",
+			      ioc->msingle_calls, ioc->msingle_pages,
+			      (int)((ioc->msingle_pages * 1000)/ioc->msingle_calls));
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+		
+
+		/* KLUGE - unmap_sg calls unmap_single for each mapped page */
+		min = ioc->usingle_calls - ioc->usg_calls;
+		max = ioc->usingle_pages - ioc->usg_pages;
+		len = sprintf(tmp, "pci_unmap_single: %8ld calls  %8ld pages (avg %d/1000)\n",
+			      min, max, (int)((max * 1000)/min));
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+ 
+		len = sprintf(tmp, "pci_map_sg()    : %8ld calls  %8ld pages (avg %d/1000)\n",
+			      ioc->msg_calls, ioc->msg_pages,
+			      (int)((ioc->msg_pages * 1000)/ioc->msg_calls));
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+		len = sprintf(tmp, "pci_unmap_sg()  : %8ld calls  %8ld pages (avg %d/1000)\n\n\n",
+			      ioc->usg_calls, ioc->usg_pages,
+			      (int)((ioc->usg_pages * 1000)/ioc->usg_calls));
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+
+		ioc = ioc->next;
+	}
+
+	if (count == 0) {
+		*eof = 1;
+	}
+	return (max - count);
+}
+
+static int ccio_resource_map(char *buf, char **start, off_t offset, int len,
+			     int *eof, void *data)
+{
+	struct ioc *ioc = ioc_list;
+
+	buf[0] = '\0';
+	while (ioc != NULL) {
+		u32 *res_ptr = (u32 *)ioc->res_map;
+		int j;
+
+		for (j = 0; j < (ioc->res_size / sizeof(u32)); j++) {
+			if ((j & 7) == 0)
+				strcat(buf,"\n   ");
+			sprintf(buf, "%s %08x", buf, *res_ptr);
+			res_ptr++;
+		}
+		strcat(buf, "\n\n");
+		ioc = ioc->next;
+		break; /* XXX - remove me */
+	}
+
+	return strlen(buf);
+}
+#endif
+
+/**
+ * ccio_find_ioc - Find the ioc in the ioc_list
+ * @hw_path: The hardware path of the ioc.
+ *
+ * This function searches the ioc_list for an ioc that matches
+ * the provide hardware path.
+ */
+static struct ioc * ccio_find_ioc(int hw_path)
+{
+	int i;
+	struct ioc *ioc;
+
+	ioc = ioc_list;
+	for (i = 0; i < ioc_count; i++) {
+		if (ioc->hw_path == hw_path)
+			return ioc;
+
+		ioc = ioc->next;
+	}
+
+	return NULL;
+}
+
+/**
+ * ccio_get_iommu - Find the iommu which controls this device
+ * @dev: The parisc device.
+ *
+ * This function searches through the registerd IOMMU's and returns the
+ * appropriate IOMMU for the device based upon the devices hardware path.
+ */
+void * ccio_get_iommu(const struct parisc_device *dev)
+{
+	dev = find_pa_parent_type(dev, HPHW_IOA);
+	if (!dev)
+		return NULL;
+
+	return ccio_find_ioc(dev->hw_path);
+}
+
+#define CUJO_20_STEP       0x10000000	/* inc upper nibble */
+
+/* Cujo 2.0 has a bug which will silently corrupt data being transferred
+ * to/from certain pages.  To avoid this happening, we mark these pages
+ * as `used', and ensure that nothing will try to allocate from them.
+ */
+void ccio_cujo20_fixup(struct parisc_device *dev, u32 iovp)
+{
+	unsigned int idx;
+	struct ioc *ioc = ccio_get_iommu(dev);
+	u8 *res_ptr;
+
+#ifdef CONFIG_PROC_FS
+	ioc->cujo20_bug = 1;
+#endif
+	res_ptr = ioc->res_map;
+	idx = PDIR_INDEX(iovp) >> 3;
+
+	while (idx < ioc->res_size) {
+ 		res_ptr[idx] |= 0xff;
+		idx += PDIR_INDEX(CUJO_20_STEP) >> 3;
+	}
+}
+
 #if 0
 /* GRANT -  is this needed for U2 or not? */
 
@@ -875,38 +1285,37 @@
 ** I think only Java (K/D/R-class too?) systems don't do this.
 */
 static int
-ccio_get_iotlb_size(struct hp_device *d)
+ccio_get_iotlb_size(struct parisc_device *dev)
 {
-	if(d->spa_shift == 0) {
-		panic(__FUNCTION__ ": Can't determine I/O TLB size.\n");
+	if (dev->spa_shift == 0) {
+		panic("%s() : Can't determine I/O TLB size.\n", __FUNCTION__);
 	}
-	return(1 << d->spa_shift);
+	return (1 << dev->spa_shift);
 }
 #else
 
 /* Uturn supports 256 TLB entries */
 #define CCIO_CHAINID_SHIFT	8
 #define CCIO_CHAINID_MASK	0xff
-
 #endif /* 0 */
 
-
-/*
-** Figure out how big the I/O PDIR should be and alloc it.
-** Also sets variables which depend on pdir size.
-*/
+/**
+ * ccio_ioc_init - Initalize the I/O Controller
+ * @ioc: The I/O Controller.
+ *
+ * Initalize the I/O Controller which includes setting up the
+ * I/O Page Directory, the resource map, and initalizing the
+ * U2/Uturn chip into virtual mode.
+ */
 static void
-ccio_alloc_pdir(struct ccio_device *ioa)
+ccio_ioc_init(struct ioc *ioc)
 {
-	extern unsigned long mem_max;          /* arch.../setup.c */
-
-	u32 iova_space_size = 0;
-	void * pdir_base;
-	int pdir_size, iov_order;
+	int i, iov_order;
+	u32 iova_space_size;
+	unsigned long physmem;
 
 	/*
 	** Determine IOVA Space size from memory size.
-	** Using "mem_max" is a kluge.
 	**
 	** Ideally, PCI drivers would register the maximum number
 	** of DMA they can have outstanding for each device they
@@ -915,15 +1324,18 @@
 	** methods still require some "extra" to support PCI
 	** Hot-Plug/Removal of PCI cards. (aka PCI OLARD).
 	*/
+
 	/* limit IOVA space size to 1MB-1GB */
-	if (mem_max < (ccio_mem_ratio*1024*1024)) {
-		iova_space_size = 1024*1024;
+
+	physmem = num_physpages << PAGE_SHIFT;
+	if(physmem < (ccio_mem_ratio * 1024 * 1024)) {
+		iova_space_size = 1024 * 1024;
 #ifdef __LP64__
-	} else if (mem_max > (ccio_mem_ratio*512*1024*1024)) {
-		iova_space_size = 512*1024*1024;
+	} else if(physmem > (ccio_mem_ratio * 512 * 1024 * 1024)) {
+		iova_space_size = 512 * 1024 * 1024;
 #endif
 	} else {
-		iova_space_size = (u32) (mem_max/ccio_mem_ratio);
+		iova_space_size = (u32)(physmem / ccio_mem_ratio);
 	}
 
 	/*
@@ -933,277 +1345,271 @@
 
 	/* We could use larger page sizes in order to *decrease* the number
 	** of mappings needed.  (ie 8k pages means 1/2 the mappings).
-        **
+	**
 	** Note: Grant Grunder says "Using 8k I/O pages isn't trivial either
 	**   since the pages must also be physically contiguous - typically
 	**   this is the case under linux."
 	*/
 
-	iov_order = get_order(iova_space_size);
+	iov_order = get_order(iova_space_size) >> (IOVP_SHIFT - PAGE_SHIFT);
 	ASSERT(iov_order <= (30 - IOVP_SHIFT));   /* iova_space_size <= 1GB */
 	ASSERT(iov_order >= (20 - IOVP_SHIFT));   /* iova_space_size >= 1MB */
 	iova_space_size = 1 << (iov_order + IOVP_SHIFT);
 
-	ioa->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64);
+	ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64);
 
-	ASSERT(pdir_size < 4*1024*1024);   /* max pdir size < 4MB */
+	ASSERT(ioc->pdir_size < 4 * 1024 * 1024);   /* max pdir size < 4MB */
 
 	/* Verify it's a power of two */
-	ASSERT((1 << get_order(pdir_size)) == (pdir_size >> PAGE_SHIFT));
+	ASSERT((1 << get_order(ioc->pdir_size)) == (ioc->pdir_size >> PAGE_SHIFT));
 
-	DBG_INIT(__FUNCTION__ " hpa 0x%p mem %dMB IOV %dMB (%d bits)\n    PDIR size 0x%0x",
-		ioa->ccio_hpa, (int) (mem_max>>20), iova_space_size>>20,
-		iov_order + PAGE_SHIFT, pdir_size);
-
-	ioa->pdir_base =
-	pdir_base = (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size));
-	if (NULL == pdir_base)
-	{
-		panic(__FILE__ ":" __FUNCTION__ "() could not allocate I/O Page Table\n");
+	DBG_INIT("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits) PDIR size 0x%0x",
+		__FUNCTION__, ioc->ioc_hpa, physmem>>20, iova_space_size>>20,
+		 iov_order + PAGE_SHIFT, ioc->pdir_size);
+
+	ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL, 
+						 get_order(ioc->pdir_size));
+	if(NULL == ioc->pdir_base) {
+		panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__);
 	}
-	memset(pdir_base, 0, pdir_size);
+	memset(ioc->pdir_base, 0, ioc->pdir_size);
 
-	ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base);
+	ASSERT((((unsigned long)ioc->pdir_base) & PAGE_MASK) == (unsigned long)ioc->pdir_base);
+	DBG_INIT(" base %p", ioc->pdir_base);
 
-	DBG_INIT(" base %p", pdir_base);
+	/* resource map size dictated by pdir_size */
+ 	ioc->res_size = (ioc->pdir_size / sizeof(u64)) >> 3;
+	DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, ioc->res_size);
+	
+	ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL, 
+					      get_order(ioc->res_size));
+	if(NULL == ioc->res_map) {
+		panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__);
+	}
+	memset(ioc->res_map, 0, ioc->res_size);
+
+	/* Initialize the res_hint to 16 */
+	ioc->res_hint = 16;
+
+	/* Initialize the spinlock */
+	spin_lock_init(&ioc->res_lock);
 
 	/*
 	** Chainid is the upper most bits of an IOVP used to determine
 	** which TLB entry an IOVP will use.
 	*/
-	ioa->chainid_shift = get_order(iova_space_size)+PAGE_SHIFT-CCIO_CHAINID_SHIFT;
-
-	DBG_INIT(" chainid_shift 0x%x\n", ioa->chainid_shift);
-}
-
-
-static void
-ccio_hw_init(struct ccio_device *ioa)
-{
-	int i;
+	ioc->chainid_shift = get_order(iova_space_size) + PAGE_SHIFT - CCIO_CHAINID_SHIFT;
+	DBG_INIT(" chainid_shift 0x%x\n", ioc->chainid_shift);
 
 	/*
 	** Initialize IOA hardware
 	*/
-	WRITE_U32(CCIO_CHAINID_MASK << ioa->chainid_shift, &ioa->ccio_hpa->io_chain_id_mask);
-	WRITE_U32(virt_to_phys(ioa->pdir_base), &ioa->ccio_hpa->io_pdir_base);
+	WRITE_U32(CCIO_CHAINID_MASK << ioc->chainid_shift, 
+		  &ioc->ioc_hpa->io_chain_id_mask);
 
+	WRITE_U32(virt_to_phys(ioc->pdir_base), 
+		  &ioc->ioc_hpa->io_pdir_base);
 
 	/*
 	** Go to "Virtual Mode"
 	*/
-	WRITE_U32(IOA_NORMAL_MODE, &ioa->ccio_hpa->io_control);
+	WRITE_U32(IOA_NORMAL_MODE, &ioc->ioc_hpa->io_control);
 
 	/*
 	** Initialize all I/O TLB entries to 0 (Valid bit off).
 	*/
-	WRITE_U32(0, &ioa->ccio_hpa->io_tlb_entry_m);
-	WRITE_U32(0, &ioa->ccio_hpa->io_tlb_entry_l);
+	WRITE_U32(0, &ioc->ioc_hpa->io_tlb_entry_m);
+	WRITE_U32(0, &ioc->ioc_hpa->io_tlb_entry_l);
 
-	for (i = 1 << CCIO_CHAINID_SHIFT; i ; i--) {
-		WRITE_U32((CMD_TLB_DIRECT_WRITE | (i << ioa->chainid_shift)),
-					&ioa->ccio_hpa->io_command);
+	for(i = 1 << CCIO_CHAINID_SHIFT; i ; i--) {
+		WRITE_U32((CMD_TLB_DIRECT_WRITE | (i << ioc->chainid_shift)),
+			  &ioc->ioc_hpa->io_command);
 	}
-
 }
 
-
 static void
-ccio_resmap_init(struct ccio_device *ioa)
+ccio_init_resource(struct resource *res, char *name, unsigned long ioaddr)
 {
-	u32 res_size;
-
-	/*
-	** Ok...we do more than just init resource map
-	*/
-	ioa->ccio_lock = SPIN_LOCK_UNLOCKED;
+	int result;
 
-	ioa->res_hint = 16;    /* next available IOVP - circular search */
-
-	/* resource map size dictated by pdir_size */
-	res_size = ioa->pdir_size/sizeof(u64); /* entries */
-	res_size >>= 3;	/* convert bit count to byte count */
-	DBG_INIT(__FUNCTION__ "() res_size 0x%x\n", res_size);
-
-	ioa->res_size = res_size;
-	ioa->res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size));
-	if (NULL == ioa->res_map)
-	{
-		panic(__FILE__ ":" __FUNCTION__ "() could not allocate resource map\n");
+	res->flags = IORESOURCE_MEM;
+	res->start = (unsigned long)(signed) __raw_readl(ioaddr) << 16;
+	res->end = (unsigned long)(signed) (__raw_readl(ioaddr + 4) << 16) - 1;
+	if (res->end + 1 == res->start)
+		return;
+	res->name = name;
+	result = request_resource(&iomem_resource, res);
+	if (result < 0) {
+		printk(KERN_ERR 
+		       "%s: failed to claim CCIO bus address space (%p,%p)\n", 
+		       __FILE__, res->start, res->end);
 	}
-	memset(ioa->res_map, 0, res_size);
 }
 
-/* CUJO20 KLUDGE start */
-static struct {
-		u16 hversion;
-		u8  spa;
-		u8  type;
-		u32     foo[3];	/* 16 bytes total */
-} cujo_iodc __attribute__ ((aligned (64)));
-static unsigned long cujo_result[32] __attribute__ ((aligned (16))) = {0,0,0,0};
+static void __init ccio_init_resources(struct ioc *ioc)
+{
+	struct resource *res = ioc->mmio_region;
+	char *name = kmalloc(14, GFP_KERNEL);
 
-/*
-** CUJO 2.0 incorrectly decodes a memory access for specific
-** pages (every page at specific iotlb locations dependent
-** upon where the cujo is flexed - diff on raven/firehawk.
-** resulting in an hpmc and/or silent data corruption.
-** Workaround is to prevent use of those I/O TLB entries
-** by marking the suspect bitmap range entries as busy.
-*/
-static void
-ccio_cujo20_hack(struct ccio_device *ioa)
+	sprintf(name, "GSC Bus [%d/]", ioc->hw_path);
+
+	ccio_init_resource(res, name, (unsigned long)&ioc->ioc_hpa->io_io_low);
+	ccio_init_resource(res + 1, name,
+			(unsigned long)&ioc->ioc_hpa->io_io_low_hv);
+}
+
+static void expand_ioc_area(struct ioc *ioc, unsigned long size,
+		unsigned long min, unsigned long max, unsigned long align)
 {
-	unsigned long status;
-	unsigned int idx;
-	u8 *res_ptr = ioa->res_map;
-	u32 iovp=0x0;
-	unsigned long mask;
+#ifdef NASTY_HACK_FOR_K_CLASS
+	__raw_writel(0xfffff600, (unsigned long)&(ioc->ioc_hpa->io_io_high));
+	ioc->mmio_region[0].end = 0xf5ffffff;
+#endif
+}
 
-	status = pdc_iodc_read( &cujo_result, (void *) CUJO_RAVEN_LOC, 0, &cujo_iodc, 16);
-	if (status == 0) {
-		if (cujo_iodc.hversion==CUJO_20_BADHVERS)
-			iovp = CUJO_20_BADPAGE1;
+static struct resource *ccio_get_resource(struct ioc* ioc,
+		const struct parisc_device *dev)
+{
+	if (!ioc) {
+		return &iomem_resource;
+	} else if ((ioc->mmio_region->start <= dev->hpa) &&
+			(dev->hpa < ioc->mmio_region->end)) {
+		return ioc->mmio_region;
+	} else if (((ioc->mmio_region + 1)->start <= dev->hpa) &&
+			(dev->hpa < (ioc->mmio_region + 1)->end)) {
+		return ioc->mmio_region + 1;
 	} else {
-		status = pdc_iodc_read( &cujo_result, (void *) CUJO_FIREHAWK_LOC, 0, &cujo_iodc, 16);
-		if (status == 0) {
-			if (cujo_iodc.hversion==CUJO_20_BADHVERS)
-				iovp = CUJO_20_BADPAGE2;
-		} else {
-			/* not a defective system */
-			return;
-		}
+		return NULL;
 	}
+}
 
-	printk(MODULE_NAME ": Cujo 2.0 bug needs a work around\n");
-	ccio_cujo_bug = 1;
+int ccio_allocate_resource(const struct parisc_device *dev,
+		struct resource *res, unsigned long size,
+		unsigned long min, unsigned long max, unsigned long align,
+		void (*alignf)(void *, struct resource *, unsigned long),
+		void *alignf_data)
+{
+	struct ioc *ioc = ccio_get_iommu(dev);
+	struct resource *parent = ccio_get_resource(ioc, dev);
+	if (!parent)
+		return -EBUSY;
 
-	/*
-	** mark bit entries that match "bad page"
-	*/
-	idx = PDIR_INDEX(iovp)>>3;
-	mask = 0xff;
-	
-	while(idx * sizeof(u8) < ioa->res_size) {
-		res_ptr[idx] |= mask;
-		idx += (PDIR_INDEX(CUJO_20_STEP)>>3);
-		ccio_used_pages += 8;
-		ccio_used_bytes += 1;
-	}
+	if (!allocate_resource(parent, res, size, min, max, align, alignf,
+			alignf_data))
+		return 0;
+
+	expand_ioc_area(ioc, size, min, max, align);
+	return allocate_resource(parent, res, size, min, max, align, alignf,
+			alignf_data);
 }
-/* CUJO20 KLUDGE end */
 
-#ifdef CONFIG_PROC_FS
-static int ccio_proc_info(char *buf, char **start, off_t offset, int len)
+int ccio_request_resource(const struct parisc_device *dev,
+		struct resource *res)
 {
-	unsigned long i = 0;
-	struct ccio_device *ioa = ccio_list;
-	unsigned long *res_ptr = (unsigned long *)ioa->res_map;
-	unsigned long total_pages = ioa->res_size << 3;            /* 8 bits per byte */
-
-	sprintf(buf, "%s\nCujo 2.0 bug    : %s\n",
-		parisc_getHWdescription(ioa->iodc->hw_type, ioa->iodc->hversion,
-					ioa->iodc->sversion),
-		(ccio_cujo_bug ? "yes" : "no"));
-
-	sprintf(buf, "%sIO pdir size    : %d bytes (%d entries)\n",
-		buf, ((ioa->res_size << 3) * sizeof(u64)), /* 8 bits per byte */
-		ioa->res_size << 3);                       /* 8 bits per byte */
+	struct ioc *ioc = ccio_get_iommu(dev);
+	struct resource *parent = ccio_get_resource(ioc, dev);
+
+	return request_resource(parent, res);
+}
+/**
+ * ccio_probe - Determine if ccio should claim this device.
+ * @dev: The device which has been found
+ *
+ * Determine if ccio should claim this chip (return 0) or not (return 1).
+ * If so, initialize the chip and tell other partners in crime they
+ * have work to do.
+ */
+static int ccio_probe(struct parisc_device *dev)
+{
+	int i;
+	struct ioc *ioc, **ioc_p = &ioc_list;
 	
-	sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", 
-		buf, ioa->res_size, ioa->res_size << 3);   /* 8 bits per byte */
+	ioc = kmalloc(sizeof(struct ioc), GFP_KERNEL);
+	if (ioc == NULL) {
+		printk(KERN_ERR MODULE_NAME ": memory allocation failure\n");
+		return 1;
+	}
+	memset(ioc, 0, sizeof(struct ioc));
 
-	strcat(buf,  "     	  total:    free:    used:   % used:\n");
-	sprintf(buf, "%sblocks  %8d %8ld %8ld %8ld%%\n", buf, ioa->res_size,
-		ioa->res_size - ccio_used_bytes, ccio_used_bytes,
-		(ccio_used_bytes * 100) / ioa->res_size);
-
-	sprintf(buf, "%spages   %8ld %8ld %8ld %8ld%%\n", buf, total_pages,
-		total_pages - ccio_used_pages, ccio_used_pages,
-		(ccio_used_pages * 100 / total_pages));
+	ioc->name = dev->id.hversion == U2_IOA_RUNWAY ? "U2" : "UTurn";
 
-	sprintf(buf, "%sconsistent       %8ld %8ld\n", buf,
-		ccio_alloc_size, ccio_free_size);
- 
-	strcat(buf, "\nResource bitmap:\n");
+	printk(KERN_INFO "Found %s at 0x%lx\n", ioc->name, dev->hpa);
 
-	for(; i < (ioa->res_size / sizeof(unsigned long)); ++i, ++res_ptr)
-		len += sprintf(buf, "%s%08lx ", buf, *res_ptr);
+	for (i = 0; i < ioc_count; i++) {
+		ioc_p = &(*ioc_p)->next;
+	}
+	*ioc_p = ioc;
 
-	strcat(buf, "\n");
-	return strlen(buf);
+	ioc->hw_path = dev->hw_path;
+	ioc->ioc_hpa = (struct ioa_registers *)dev->hpa;
+	ccio_ioc_init(ioc);
+	ccio_init_resources(ioc);
+	hppa_dma_ops = &ccio_ops;
+
+	if (ioc_count == 0) {
+		/* XXX: Create separate entries for each ioc */
+		create_proc_read_entry(MODULE_NAME, S_IRWXU, proc_runway_root,
+				       ccio_proc_info, NULL);
+		create_proc_read_entry(MODULE_NAME"-bitmap", S_IRWXU,
+				       proc_runway_root, ccio_resource_map, NULL);
+	}
+
+	ioc_count++;
+	return 0;
 }
-#endif
 
-/*
-** Determine if ccio should claim this chip (return 0) or not (return 1).
-** If so, initialize the chip and tell other partners in crime they
-** have work to do.
-*/
-static int
-ccio_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+struct pci_dev * ccio_get_fake(const struct parisc_device *dev)
 {
-	struct ccio_device *ioa;
+	struct ioc *ioc;
 
-	printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa);
+	dev = find_pa_parent_type(dev, HPHW_IOA);
+	if(!dev)
+		return NULL;
 
-	if (ccio_list) {
-		printk(MODULE_NAME ": already initialized one device\n");
-		return(0);
-	}
+	ioc = ccio_find_ioc(dev->hw_path);
+	if(!ioc)
+		return NULL;
 
-	ioa = kmalloc(sizeof(struct ccio_device), GFP_KERNEL);
-	if (NULL == ioa)
-	{
-		printk(MODULE_NAME " - couldn't alloc ccio_device\n");
-		return(1);
-	}
-	memset(ioa, 0, sizeof(struct ccio_device));
+	if(ioc->fake_pci_dev)
+		return ioc->fake_pci_dev;
 
-	/*
-	** ccio list is used mainly as a kluge to support a single instance. 
-	** Eventually, with core dumps, it'll be useful for debugging.
-	*/
-	ccio_list = ioa;
-	ioa->iodc = d;
+	ioc->fake_pci_dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
+	if(ioc->fake_pci_dev == NULL) {
+		printk(KERN_ERR MODULE_NAME ": memory allocation failure\n");
+		return NULL;
+	}
+	memset(ioc->fake_pci_dev, 0, sizeof(struct pci_dev));
 
-#if 1
-/* KLUGE: determine IOA hpa based on GSC port value.
-** Needed until we have a PA bus walk. Can only discover IOA via
-** walking the architected PA MMIO space as described by the I/O ACD.
-** "Legacy" PA Firmware only tells us about unarchitected devices
-** that can't be detected by PA/EISA/PCI bus walks.
-*/
-	switch((long) d->hpa) {
-	case 0xf3fbf000L:       /* C110 IOA0 LBC (aka GSC port) */
-		/* ccio_hpa same as C200 IOA0 */
-	case 0xf203f000L:       /* C180/C200/240/C360 IOA0 LBC (aka GSC port) */
-		ioa->ccio_hpa = (struct ioa_registers *) 0xfff88000L;
-		break;
-	case 0xf103f000L:       /* C180/C200/240/C360 IOA1 LBC (aka GSC port) */
-		ioa->ccio_hpa = (struct ioa_registers *) 0xfff8A000L;
-		break;
-	default:
-		panic("ccio-dma.c doesn't know this GSC port Address!\n");
-		break;
-	};
-#else
-	ioa->ccio_hpa = d->hpa;
-#endif
+	ioc->fake_pci_dev->sysdata = kmalloc(sizeof(struct pci_hba_data), GFP_KERNEL);
+	if(ioc->fake_pci_dev->sysdata == NULL) {
+		printk(KERN_ERR MODULE_NAME ": memory allocation failure\n");
+		return NULL;
+	}
 
-	ccio_alloc_pdir(ioa);
-	ccio_hw_init(ioa);
-	ccio_resmap_init(ioa);
+	HBA_DATA(ioc->fake_pci_dev->sysdata)->iommu = ioc;
+	return ioc->fake_pci_dev;
+}
 
-	/* CUJO20 KLUDGE start */
-	ccio_cujo20_hack(ioa);
-	/* CUJO20 KLUDGE end */
+/* We *can't* support JAVA (T600). Venture there at your own risk. */
+static struct parisc_device_id ccio_tbl[] = {
+	{ HPHW_IOA, HVERSION_REV_ANY_ID, U2_IOA_RUNWAY, 0xb }, /* U2 */
+	{ HPHW_IOA, HVERSION_REV_ANY_ID, UTURN_IOA_RUNWAY, 0xb }, /* UTurn */
+	{ 0, }
+};
 
-	hppa_dma_ops = &ccio_ops;
+static struct parisc_driver ccio_driver = {
+	name:		"U2/Uturn",
+	id_table:	ccio_tbl,
+	probe:		ccio_probe,
+};
 
-	create_proc_info_entry(MODULE_NAME, 0, proc_runway_root, ccio_proc_info);
-	return(0);
+/**
+ * ccio_init - ccio initalization procedure.
+ *
+ * Register this driver.
+ */
+void __init ccio_init(void)
+{
+	register_parisc_driver(&ccio_driver);
 }
 
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/ccio-rm-dma.c linux-2.4.20/arch/parisc/kernel/ccio-rm-dma.c
--- linux-2.4.19/arch/parisc/kernel/ccio-rm-dma.c	2001-10-12 22:35:53.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/ccio-rm-dma.c	2002-10-29 11:18:34.000000000 +0000
@@ -56,26 +56,6 @@
 #define UTURN_IOA_RUNWAY 0x581
 #define UTURN_BC_GSC     0x502
 
-static int ccio_driver_callback(struct hp_device *, struct pa_iodc_driver *);
-
-static struct pa_iodc_driver ccio_drivers_for[] = {
-
-   {HPHW_BCPORT, U2_BC_GSC, 0x0, 0xb, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "U2 I/O MMU", (void *) ccio_driver_callback},
-
-   {HPHW_BCPORT, UTURN_BC_GSC, 0x0, 0xb, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "Uturn I/O MMU", (void *) ccio_driver_callback},
-
-   {0,0,0,0,0,0,
-   0,
-   (char *) NULL, (char *) NULL, (void *) NULL }
-};
-
-
 #define IS_U2(id) ( \
     (((id)->hw_type == HPHW_IOA) && ((id)->hversion == U2_IOA_RUNWAY)) || \
     (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == U2_BC_GSC))  \
@@ -86,17 +66,10 @@
     (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == UTURN_BC_GSC))  \
 )
 
-
-void __init ccio_init(void)
-{
-	register_driver(ccio_drivers_for);
-}
-
-
 static int ccio_dma_supported( struct pci_dev *dev, u64 mask)
 {
 	if (dev == NULL) {
-		printk(MODULE_NAME ": EISA/ISA/et al not supported\n");
+		printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n");
 		BUG();
 		return(0);
 	}
@@ -182,8 +155,6 @@
 	ccio_unmap_sg,
 	NULL,                   /* dma_sync_single : NOP for U2 */
 	NULL,                   /* dma_sync_sg     : ditto */
-
-
 };
 
 
@@ -193,9 +164,11 @@
 ** have work to do.
 */
 static int
-ccio_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+ccio_probe(struct parisc_device *dev)
 {
-	printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa);
+	printk(KERN_INFO "%s found %s at 0x%lx\n", MODULE_NAME,
+			dev->id.hversion == U2_BC_GSC ? "U2" : "UTurn",
+			dev->hpa);
 
 /*
 ** FIXME - should check U2 registers to verify it's really running
@@ -210,3 +183,20 @@
 	hppa_dma_ops = &ccio_ops;
 	return 0;
 }
+
+static struct parisc_device_id ccio_tbl[] = {
+	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, U2_BC_GSC, 0xc },
+	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, UTURN_BC_GSC, 0xc },
+	{ 0, }
+};
+
+static struct parisc_driver ccio_driver = {
+        name:           "U2/Uturn",
+        id_table:       ccio_tbl,
+        probe:          ccio_probe,
+};
+
+void __init ccio_init(void)
+{
+	register_parisc_driver(&ccio_driver);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/drivers.c linux-2.4.20/arch/parisc/kernel/drivers.c
--- linux-2.4.19/arch/parisc/kernel/drivers.c	2000-12-06 19:46:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/drivers.c	2002-10-29 11:18:36.000000000 +0000
@@ -1,134 +1,591 @@
 /*
-
-drivers.c
-
-Copyright (c) 1999 The Puffin Group 
-
-This is a collection of routines intended to register all the devices
-in a system, and register device drivers.
-
-*/
+ * drivers.c
+ *
+ * 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.
+ *
+ * Copyright (c) 1999 The Puffin Group
+ * Copyright (c) 2001 Matthew Wilcox for Hewlett Packard
+ * Copyright (c) 2001 Helge Deller <deller@gmx.de>
+ * 
+ * The file handles registering devices and drivers, then matching them.
+ * It's the closest we get to a dating agency.
+ */
 
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/pdc.h>
+#include <asm/gsc.h>
 
+/* See comments in include/asm-parisc/pci.h */
+struct pci_dma_ops *hppa_dma_ops;
 
-extern struct hp_hardware *parisc_get_reference(
-	unsigned short hw_type, unsigned long hversion, 
-	unsigned long sversion );
+static struct parisc_driver *pa_drivers;
+static struct parisc_device root;
 
+/* This lock protects the pa_drivers list _only_ since all parisc_devices
+ * are registered before smp_init() is called.  If you wish to add devices
+ * after that, this muct be serialised somehow.  I recommend a semaphore
+ * rather than a spinlock since driver ->probe functions are allowed to
+ * sleep (for example when allocating memory).
+ */
+static spinlock_t pa_lock = SPIN_LOCK_UNLOCKED;
 
-/* I'm assuming there'll never be 64 devices.  We should probably make 
-   this more flexible.  */
+#define for_each_padev(dev) \
+	for (dev = root.child; dev != NULL; dev = next_dev(dev))
 
-#define MAX_DEVICES 64
+#define check_dev(dev) \
+	(dev->id.hw_type != HPHW_FAULTY) ? dev : next_dev(dev)
 
-unsigned int num_devices = 0;
+/**
+ * next_dev - enumerates registered devices
+ * @dev: the previous device returned from next_dev
+ *
+ * next_dev does a depth-first search of the tree, returning parents
+ * before children.  Returns NULL when there are no more devices.
+ */
+struct parisc_device *next_dev(struct parisc_device *dev)
+{
+	if (dev->child) {
+		return check_dev(dev->child);
+	} else if (dev->sibling) {
+		return dev->sibling;
+	}
 
-struct hp_device devices[MAX_DEVICES];
+	/* Exhausted tree at this level, time to go up. */
+	do {
+		dev = dev->parent;
+		if (dev && dev->sibling)
+			return dev->sibling;
+	} while (dev != &root);
 
-static unsigned long pdc_result[32] __attribute__ ((aligned (16))) = {0,0,0,0};
-static  u8 iodc_data[32] __attribute__ ((aligned (64)));
+	return NULL;
+}
 
-/*
- *	XXX should we be using a locked array ?
+/**
+ * match_device - Report whether this driver can handle this device
+ * @driver: the PA-RISC driver to try
+ * @dev: the PA-RISC device to try
  */
- 
-int register_driver(struct pa_iodc_driver *driver)
+static int match_device(struct parisc_driver *driver, struct parisc_device *dev)
 {
-	unsigned int i;
-	struct hp_device * device;
+	const struct parisc_device_id *ids;
 
-	for (;driver->check;driver++)  {
+	for (ids = driver->id_table; ids->sversion; ids++) {
+		if ((ids->sversion != SVERSION_ANY_ID) &&
+		    (ids->sversion != dev->id.sversion))
+			continue;
+
+		if ((ids->hw_type != HWTYPE_ANY_ID) &&
+		    (ids->hw_type != dev->id.hw_type))
+			continue;
+
+		if ((ids->hversion != HVERSION_ANY_ID) &&
+		    (ids->hversion != dev->id.hversion))
+			continue;
 
-		for (i=0;i<num_devices;i++) {
-			device = &devices[i];
+		return 1;
+	}
+	return 0;
+}
 
-			if (device->managed) continue;
+static void claim_device(struct parisc_driver *driver, struct parisc_device *dev)
+{
+	dev->driver = driver;
+	request_mem_region(dev->hpa, 0x1000, driver->name);
+}
 
-			if ((driver->check & DRIVER_CHECK_HWTYPE) &&
-			    (driver->hw_type != device->hw_type))
-				continue;
-			if ((driver->check & DRIVER_CHECK_HVERSION) &&
-			    (driver->hversion != device->hversion))
-				continue;
-			if ((driver->check & DRIVER_CHECK_HVERSION_REV) &&
-			    (driver->hversion_rev != device->hversion_rev))
-				continue;
-			if ((driver->check & DRIVER_CHECK_SVERSION) &&
-			    (driver->sversion != device->sversion))
-				continue;
-			if ((driver->check & DRIVER_CHECK_SVERSION_REV) &&
-			    (driver->sversion_rev != device->sversion_rev))
-				continue;
-			if ((driver->check & DRIVER_CHECK_OPT) &&
-			    (driver->opt != device->opt))
-				continue;
-			if ( (*driver->callback)(device,driver) ==0) {
-				device->managed=1;
-			} else {
-				printk("Warning : device (%d, 0x%x, 0x%x, 0x%x, 0x%x) NOT claimed by %s %s\n",
-					device->hw_type,
-					device->hversion, device->hversion_rev,
-					device->sversion, device->sversion_rev,
-					driver->name, driver->version);
-			}
+/**
+ * register_parisc_driver - Register this driver if it can handle a device
+ * @driver: the PA-RISC driver to try
+ */
+int register_parisc_driver(struct parisc_driver *driver)
+{
+	struct parisc_device *device;
+
+	if (driver->next) {
+		printk(KERN_WARNING 
+		       "BUG: Skipping previously registered driver: %s\n",
+		       driver->name);
+		return 1;
+	}
+
+	for_each_padev(device) {
+		if (device->driver)
+			continue;
+		if (!match_device(driver, device))
+			continue;
+
+		if (driver->probe(device) < 0)
+			continue;
+		claim_device(driver, device);
+	}
+
+	/* Note that the list is in reverse order of registration.  This
+	 * may be significant if we ever actually support hotplug and have
+	 * multiple drivers capable of claiming the same chip.
+	 */
+
+	spin_lock(&pa_lock);
+	driver->next = pa_drivers;
+	pa_drivers = driver;
+	spin_unlock(&pa_lock);
+
+	return 0;
+}
+
+/**
+ * count_parisc_driver - count # of devices this driver would match
+ * @driver: the PA-RISC driver to try
+ *
+ * Use by IOMMU support to "guess" the right size IOPdir.
+ * Formula is something like memsize/(num_iommu * entry_size).
+ */
+int count_parisc_driver(struct parisc_driver *driver)
+{
+	struct parisc_device *device;
+	int cnt = 0;
+
+	for_each_padev(device) {
+		if (match_device(driver, device))
+			cnt++;
+	}
+
+	return cnt;
+}
+
+
+
+/**
+ * unregister_parisc_driver - Unregister this driver from the list of drivers
+ * @driver: the PA-RISC driver to unregister
+ */
+int unregister_parisc_driver(struct parisc_driver *driver)
+{
+	struct parisc_device *dev;
+
+	spin_lock(&pa_lock);
+
+	if (pa_drivers == driver) {
+		/* was head of list - update head */
+		pa_drivers = driver->next;
+	} else {
+		struct parisc_driver *prev = pa_drivers;
+
+		while (prev && driver != prev->next) {
+			prev = prev->next;
+		}
+
+		if (!prev) {
+			printk(KERN_WARNING "unregister_parisc_driver: %s wasn't registered\n", driver->name);
+		} else {
+			/* Drop driver from list */
+			prev->next = driver->next;
+			driver->next = NULL;
 		}
+
 	}
+
+	spin_unlock(&pa_lock);
+
+	for_each_padev(dev) {
+		if (dev->driver != driver)
+			continue;
+		dev->driver = NULL;
+		release_mem_region(dev->hpa, 0x1000);
+	}
+
 	return 0;
 }
 
+static struct parisc_device *find_device_by_addr(unsigned long hpa)
+{
+	struct parisc_device *dev;
+	for_each_padev(dev) {
+		if (dev->hpa == hpa)
+			return dev;
+	}
+	return NULL;
+}
 
-struct hp_device * register_module(void *hpa)
+/**
+ * find_pa_parent_type - Find a parent of a specific type
+ * @dev: The device to start searching from
+ * @type: The device type to search for.
+ *
+ * Walks up the device tree looking for a device of the specified type.
+ * If it finds it, it returns it.  If not, it returns NULL.
+ */
+const struct parisc_device *find_pa_parent_type(const struct parisc_device *dev, int type)
 {
+	while (dev != &root) {
+		if (dev->id.hw_type == type)
+			return dev;
+		dev = dev->parent;
+	}
 
-	struct hp_device * d;
+	return NULL;
+}
+
+static void
+get_node_path(struct parisc_device *dev, struct hardware_path *path)
+{
+	int i = 5;
+	memset(&path->bc, -1, 6);
+	while (dev != &root) {
+		path->bc[i--] = dev->hw_path;
+		dev = dev->parent;
+	}
+}
+
+static char *print_hwpath(struct hardware_path *path, char *output)
+{
+	int i;
+	for (i = 0; i < 6; i++) {
+		if (path->bc[i] == -1)
+			continue;
+		output += sprintf(output, "%u/", (unsigned char) path->bc[i]);
+	}
+	output += sprintf(output, "%u", (unsigned char) path->mod);
+	return output;
+}
+
+/**
+ * print_pa_hwpath - Returns hardware path for PA devices
+ * dev: The device to return the path for
+ * output: Pointer to a previously-allocated array to place the path in.
+ *
+ * This function fills in the output array with a human-readable path
+ * to a PA device.  This string is compatible with that used by PDC, and
+ * may be printed on the outside of the box.
+ */
+char *print_pa_hwpath(struct parisc_device *dev, char *output)
+{
+	struct hardware_path path;
+
+	get_node_path(dev->parent, &path);
+	path.mod = dev->hw_path;
+	return print_hwpath(&path, output);
+}
+
+
+#if defined(CONFIG_PCI) || defined(CONFIG_ISA)
+/**
+ * get_pci_node_path - Returns hardware path for PCI devices
+ * dev: The device to return the path for
+ * output: Pointer to a previously-allocated array to place the path in.
+ *
+ * This function fills in the hardware_path structure with the route to
+ * the specified PCI device.  This structure is suitable for passing to
+ * PDC calls.
+ */
+void get_pci_node_path(struct pci_dev *dev, struct hardware_path *path)
+{
+	struct pci_bus *bus;
+	const struct parisc_device *padev;
+	int i = 5;
+
+	memset(&path->bc, -1, 6);
+	path->mod = PCI_FUNC(dev->devfn);
+	path->bc[i--] = PCI_SLOT(dev->devfn);
+	for (bus = dev->bus; bus->parent; bus = bus->parent) {
+		unsigned int devfn = bus->self->devfn;
+		path->bc[i--] = PCI_SLOT(devfn) | (PCI_FUNC(devfn) << 5);
+	}
+
+	padev = HBA_DATA(bus->sysdata)->dev;
+	while (padev != &root) {
+		path->bc[i--] = padev->hw_path;
+		padev = padev->parent;
+	}
+}
+
+/**
+ * print_pci_hwpath - Returns hardware path for PCI devices
+ * dev: The device to return the path for
+ * output: Pointer to a previously-allocated array to place the path in.
+ *
+ * This function fills in the output array with a human-readable path
+ * to a PCI device.  This string is compatible with that used by PDC, and
+ * may be printed on the outside of the box.
+ */
+char *print_pci_hwpath(struct pci_dev *dev, char *output)
+{
+	struct hardware_path path;
+
+	get_pci_node_path(dev, &path);
+	return print_hwpath(&path, output);
+}
+#endif /* defined(CONFIG_PCI) || defined(CONFIG_ISA) */
+
+
+struct parisc_device * create_tree_node(char id, struct parisc_device *parent,
+		struct parisc_device **insert)
+{
+	struct parisc_device *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+	memset(dev, 0, sizeof(*dev));
+	dev->hw_path = id;
+	dev->id.hw_type = HPHW_FAULTY;
+	dev->parent = parent;
+	dev->sibling = *insert;
+	*insert = dev;
+	return dev;
+}
+
+/**
+ * alloc_tree_node - returns a device entry in the iotree
+ * @parent: the parent node in the tree
+ * @id: the element of the module path for this entry
+ *
+ * Checks all the children of @parent for a matching @id.  If none
+ * found, it allocates a new device and returns it.
+ */
+struct parisc_device *
+alloc_tree_node(struct parisc_device *parent, char id)
+{
+	struct parisc_device *prev;
+	if ((!parent->child) || (parent->child->hw_path > id)) {
+		return create_tree_node(id, parent, &parent->child);
+	}
+
+	prev = parent->child;
+	if (prev->hw_path == id)
+		return prev;
+
+	while (prev->sibling && prev->sibling->hw_path < id) {
+		prev = prev->sibling;
+	}
+
+	if ((prev->sibling) && (prev->sibling->hw_path == id))
+		return prev->sibling;
+
+	return create_tree_node(id, parent, &prev->sibling);
+}
+
+static struct parisc_device *find_parisc_device(struct hardware_path *modpath)
+{
+	int i;
+	struct parisc_device *parent = &root;
+	for (i = 0; i < 6; i++) {
+		if (modpath->bc[i] == -1)
+			continue;
+		parent = alloc_tree_node(parent, modpath->bc[i]);
+	}
+	return alloc_tree_node(parent, modpath->mod);
+}
+
+struct parisc_device *
+alloc_pa_dev(unsigned long hpa, struct hardware_path *mod_path)
+{
 	int status;
+	unsigned long bytecnt;
+	u8 iodc_data[32];
+	struct parisc_device *dev;
+	const char *name;
+
+	/* Check to make sure this device has not already been added - Ryan */
+	if (find_device_by_addr(hpa) != NULL)
+		return NULL;
+
+	status = pdc_iodc_read(&bytecnt, hpa, 0, &iodc_data, 32);
+	if (status != PDC_OK)
+		return NULL;
+
+	dev = find_parisc_device(mod_path);
+	if (dev->id.hw_type != HPHW_FAULTY) {
+		char p[64];
+		print_pa_hwpath(dev, p);
+		printk("Two devices have hardware path %s.  Please file a bug with HP.\n"
+			"In the meantime, you could try rearranging your cards.\n", p);
+		return NULL;
+	}
+
+	dev->id.hw_type = iodc_data[3] & 0x1f;
+	dev->id.hversion = (iodc_data[0] << 4) | ((iodc_data[1] & 0xf0) >> 4);
+	dev->id.hversion_rev = iodc_data[1] & 0x0f;
+	dev->id.sversion = ((iodc_data[4] & 0x0f) << 16) |
+			(iodc_data[5] << 8) | iodc_data[6];
+	dev->hpa = hpa;
+	name = parisc_hardware_description(&dev->id);
+	if (name) {
+		strncpy(dev->name, name, sizeof(dev->name)-1);
+	}
+
+	return dev;
+}
 
-	d = &devices[num_devices];
-	status = pdc_iodc_read(&pdc_result,hpa,0,&iodc_data,32 );
-	if (status !=PDC_RET_OK) {
-		/* There is no device here, so we'll skip it */
+/**
+ * register_parisc_device - Locate a driver to manage this device.
+ * @dev: The parisc device.
+ *
+ * Search the driver list for a driver that is willing to manage
+ * this device.
+ */
+int register_parisc_device(struct parisc_device *dev)
+{
+	struct parisc_driver *driver;
+
+	if (!dev)
 		return 0;
+
+	if (dev->driver)
+		return 1;
+	
+	spin_lock(&pa_lock);
+
+	/* Locate a driver which agrees to manage this device.  */
+	for (driver = pa_drivers; driver; driver = driver->next) {
+		if (!match_device(driver,dev))
+			continue;
+		if (driver->probe(dev) == 0)
+			break;
 	}
 
-	d->hw_type = iodc_data[3]&0x1f;
-	d->hversion = (iodc_data[0]<<4)|((iodc_data[1]&0xf0)>>4);
-	d->sversion = 
-		((iodc_data[4]&0x0f)<<16)|(iodc_data[5]<<8)|(iodc_data[6]);
-	d->hversion_rev = iodc_data[1]&0x0f;
-	d->sversion_rev = iodc_data[4]>>4;
-	d->opt = iodc_data[7];
-	d->hpa = hpa;
-	d->managed=0;
-	d->reference = parisc_get_reference(d->hw_type, d->hversion, 
-								d->sversion);
-		
-	num_devices++;	
+	if (driver != NULL) {
+		claim_device(driver, dev);
+	}
+	spin_unlock(&pa_lock);
+	return driver != NULL;
+}
+
+#define BC_PORT_MASK 0x8
+#define BC_LOWER_PORT 0x8
+
+#define BUS_CONVERTER(dev) \
+        ((dev->id.hw_type == HPHW_IOA) || (dev->id.hw_type == HPHW_BCPORT))
+
+#define IS_LOWER_PORT(dev) \
+        ((gsc_readl(&((struct bc_module *)dev->hpa)->io_status) \
+                & BC_PORT_MASK) == BC_LOWER_PORT)
+
+#define READ_IO_IO_LOW(dev) \
+	(dev->id.hw_type == HPHW_IOA ? \
+	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_low) << 16 : \
+	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_low))
 
-	return d;
-}	
+static void walk_native_bus(unsigned long addr, struct parisc_device *parent);
+void walk_lower_bus(struct parisc_device *dev)
+{
+
+	if(!BUS_CONVERTER(dev) || IS_LOWER_PORT(dev))
+		return;
 
-void print_devices(char * buf) {
+	walk_native_bus((unsigned long)(signed int)READ_IO_IO_LOW(dev), dev);
+}
 
+#define MAX_NATIVE_DEVICES 64
+#define NATIVE_DEVICE_OFFSET 0x1000
+
+/**
+ * walk_native_bus -- Probe a bus for devices
+ * @addr: Base address of this bus.
+ * 
+ * A native bus (eg Runway or GSC) may have up to 64 devices on it,
+ * spaced at intervals of 0x1000 bytes.  PDC may not inform us of these
+ * devices, so we have to probe for them.  Unfortunately, we may find
+ * devices which are not physically connected (such as extra serial &
+ * keyboard ports).  This problem is not yet solved.
+ */
+static void walk_native_bus(unsigned long addr, struct parisc_device *parent)
+{
 	int i;
-	struct hp_device *d;
-	printk("Found devices:\n");
-	for (i=0;i<num_devices;i++) {	
-		d = &devices[i];
-		printk(KERN_INFO 
-		"%d. %s (%d) at 0x%p, versions 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", 
-		i+1,
-		(d->reference) ? d->reference->name : "Unknown device",
-		d->hw_type,d->hpa, d->hversion, d->hversion_rev,
-		d->sversion, d->sversion_rev, d->opt);
+	struct hardware_path path;
+
+	get_node_path(parent, &path);
+	for (i = 0; i < MAX_NATIVE_DEVICES; i++) {
+		unsigned long hpa = (addr + i * NATIVE_DEVICE_OFFSET);
+		struct parisc_device *dev;
+
+		/* Was the device already added by Firmware? */
+		dev = find_device_by_addr(hpa);
+		if (!dev) {
+			path.mod = i;
+			dev = alloc_pa_dev(hpa, &path);
+			if (!dev)
+				continue;
+
+			register_parisc_device(dev);
+		}
+		walk_lower_bus(dev);
+	}
+}
+
+#define CENTRAL_BUS_ADDR (unsigned long) 0xfffffffffff80000
+
+/**
+ * walk_central_bus - Find devices attached to the central bus
+ *
+ * PDC doesn't tell us about all devices in the system.  This routine
+ * finds devices connected to the central bus.
+ */
+void walk_central_bus(void)
+{
+	walk_native_bus(CENTRAL_BUS_ADDR, &root);
+}
+
+void fixup_child_irqs(struct parisc_device *parent, int base,
+			int (*choose_irq)(struct parisc_device *))
+{
+	struct parisc_device *dev;
 
+	if (!parent->child)
+		return;
+
+	for (dev = check_dev(parent->child); dev; dev = dev->sibling) {
+		int irq = choose_irq(dev);
+		if (irq > 0) {
+#ifdef __LP64__
+			irq += 32;
+#endif
+			dev->irq = base + irq;
+		}
 	}
-	printk("That's a total of %d devices.\n",num_devices);
 }
 
+static void print_parisc_device(struct parisc_device *dev)
+{
+	char hw_path[64];
+	static int count;
 
+	print_pa_hwpath(dev, hw_path);
+	printk(KERN_INFO "%d. %s (%d) at 0x%lx [%s], versions 0x%x, 0x%x, 0x%x",
+		++count, dev->name, dev->id.hw_type, dev->hpa, hw_path,
+		dev->id.hversion, dev->id.hversion_rev, dev->id.sversion);
+
+	if (dev->num_addrs) {
+		int k;
+		printk(",  additional addresses: ");
+		for (k = 0; k < dev->num_addrs; k++)
+			printk("0x%lx ", dev->addr[k]);
+	}
+	printk("\n");
+}
+
+void print_subdevices(struct parisc_device *parent)
+{
+	struct parisc_device *dev;
+	for (dev = parent->child; dev != parent->sibling; dev = next_dev(dev)) {
+		print_parisc_device(dev);
+	}
+}
+
+/**
+ * print_parisc_devices - Print out a list of devices found in this system
+ */
+void print_parisc_devices(void)
+{
+	struct parisc_device *dev;
+	for_each_padev(dev) {
+		print_parisc_device(dev);
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/entry.S linux-2.4.20/arch/parisc/kernel/entry.S
--- linux-2.4.19/arch/parisc/kernel/entry.S	2000-12-06 19:46:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/entry.S	2002-10-29 11:18:34.000000000 +0000
@@ -1,5 +1,5 @@
-/*------------------------------------------------------------------------------
- * Native PARISC/Linux Project (http://www.puffingroup.com/parisc)
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
  *
  * kernel entry points (interruptions, system call wrappers)
  *  Copyright (C) 1999,2000 Philipp Rumpf 
@@ -25,39 +25,51 @@
 #include <linux/config.h>
 #include <asm/offset.h>
 
-/* the following is the setup i think we should follow:
- * whenever the CPU is interruptible, the following has to be true:
- *  CR30 is the kernel sp or 0 if we currently use the kernel stack
- *  CR31 is the kernel gp */ 
-
 /* we have the following possibilities to act on an interruption:
  *  - handle in assembly and use shadowed registers only
  *  - save registers to kernel stack and handle in assembly or C */
 
-	.text
-
-#ifdef __LP64__
-	.level 2.0w
-#endif
 
-#define __ASSEMBLY__
 #include <asm/assembly.h>	/* for LDREG/STREG defines */
 #include <asm/pgtable.h>
 #include <asm/psw.h>
 #include <asm/signal.h>
+#include <asm/unistd.h>
 
 #ifdef __LP64__
-#define FRAME_SIZE	64
+#define FRAME_SIZE	128
+#define CMPIB           cmpib,*
+#define CMPB            cmpb,*
+
+	.level 2.0w
 #else
 #define FRAME_SIZE	64
+#define CMPIB           cmpib,
+#define CMPB            cmpb,
+
+	.level 2.0
+#endif
+
+	.import         pa_dbit_lock,data
+
+	/* space_to_prot macro creates a prot id from a space id */
+
+#if (SPACEID_SHIFT) == 0
+	.macro  space_to_prot spc prot
+	depd,z  \spc,62,31,\prot
+	.endm
+#else
+	.macro  space_to_prot spc prot
+	extrd,u \spc,(64 - (SPACEID_SHIFT)),32,\prot
+	.endm
 #endif
 
 	/* Switch to virtual mapping, trashing only %r1 */
-	.macro	virt_map rfi_type
-	mtsm	%r0
-	tovirt	%r29
-	tovirt	%r30
+	.macro  virt_map
+	rsm     PSW_SM_Q,%r0
+	tovirt_r1 %r29
 	mfsp	%sr7, %r1
+	or,=    %r0,%r1,%r0 /* Only save sr7 in sr3 if sr7 != 0 */
 	mtsp	%r1, %sr3
 	mtsp	%r0, %sr4
 	mtsp	%r0, %sr5
@@ -65,95 +77,114 @@
 	mtsp	%r0, %sr7
 	ldil	L%KERNEL_PSW, %r1
 	ldo	R%KERNEL_PSW(%r1), %r1
-	LDIL_FIXUP(%r1)
 	mtctl	%r1, %cr22
 	mtctl	%r0, %cr17
 	mtctl	%r0, %cr17
-	ldil	L%.+28, %r1
-	ldo	R%.+24(%r1), %r1
-	LDIL_FIXUP(%r1)
+	ldil	L%4f, %r1
+	ldo	R%4f(%r1), %r1
 	mtctl	%r1, %cr18
 	ldo	4(%r1), %r1
 	mtctl	%r1, %cr18
-	\rfi_type
+	rfir
 	nop
+4:
 	.endm
 
-	.macro	get_stack
-	mfctl	%cr30, %r1 
-	comib,=,n 0, %r1, 0f   /* forward so predicted not taken */
+	/*
+	 * The "get_stack" macros are responsible for determining the
+	 * kernel stack value.
+	 *
+	 * For Faults:
+	 *      If sr7 == 0
+	 *          Already using a kernel stack, so call the
+	 *          get_stack_use_r30 macro to push a pt_regs structure
+	 *          on the stack, and store registers there.
+	 *      else
+	 *          Need to set up a kernel stack, so call the
+	 *          get_stack_use_cr30 macro to set up a pointer
+	 *          to the pt_regs structure contained within the
+	 *          task pointer pointed to by cr30. Set the stack
+	 *          pointer to point to the end of the task structure.
+	 *
+	 * For Interrupts:
+	 *      If sr7 == 0
+	 *          Already using a kernel stack, check to see if r30
+	 *          is already pointing to the per processor interrupt
+	 *          stack. If it is, call the get_stack_use_r30 macro
+	 *          to push a pt_regs structure on the stack, and store
+	 *          registers there. Otherwise, call get_stack_use_cr31
+	 *          to get a pointer to the base of the interrupt stack
+	 *          and push a pt_regs structure on that stack.
+	 *      else
+	 *          Need to set up a kernel stack, so call the
+	 *          get_stack_use_cr30 macro to set up a pointer
+	 *          to the pt_regs structure contained within the
+	 *          task pointer pointed to by cr30. Set the stack
+	 *          pointer to point to the end of the task structure.
+	 *          N.B: We don't use the interrupt stack for the
+	 *          first interrupt from userland, because signals/
+	 *          resched's are processed when returning to userland,
+	 *          and we can sleep in those cases.
+	 *
+	 * Note that we use shadowed registers for temps until
+	 * we can save %r26 and %r29. %r26 is used to preserve
+	 * %r8 (a shadowed register) which temporarily contained
+	 * either the fault type ("code") or the eirr. We need
+	 * to use a non-shadowed register to carry the value over
+	 * the rfir in virt_map. We use %r26 since this value winds
+	 * up being passed as the argument to either do_cpu_irq_mask
+	 * or handle_interruption. %r29 is used to hold a pointer
+	 * the register save area, and once again, it needs to
+	 * be a non-shadowed register so that it survives the rfir.
+	 *
+	 * N.B. TASK_SZ_ALGN and PT_SZ_ALGN include space for a stack frame.
+	 */
+
+	.macro  get_stack_use_cr30
 
 	/* we save the registers in the task struct */
-	ldo	TASK_REGS(%r1), %r29
-	tophys	%r29
-	STREG	%r30, PT_GR30(%r29)
-	STREG	%r1,  PT_CR30(%r29)
+
+	mfctl   %cr30, %r1
+	tophys  %r1,%r9
+	ldo     TASK_REGS(%r9),%r9
+	STREG   %r30, PT_GR30(%r9)
 	ldo	TASK_SZ_ALGN(%r1), %r30
-	b	1f		    /* unconditional so predicted taken */	
-	mtctl	%r0,%cr30
-0:
-	/* we put a struct pt_regs on the stack and save the registers there */
-	copy	%r30,%r29
-	ldo	PT_SZ_ALGN(%r30),%r30
-	tophys	%r29
-	STREG	%r30,PT_GR30(%r29)
-	STREG	%r0,PT_CR30(%r29)
-1:
+	STREG   %r29,PT_GR29(%r9)
+	STREG   %r26,PT_GR26(%r9)
+	copy    %r9,%r29
 	.endm
 
-	.macro	rest_stack regs
-	LDREG	PT_CR30(\regs), %r1
-	comib,=,n 0, %r1, 2f/* forward so predicted not taken */
-
-	/* we restore the registers out of the task struct */
-	mtctl	%r1, %cr30
-	LDREG	PT_GR1(\regs), %r1
-	LDREG	PT_GR30(\regs),%r30
-	b	3f
-	LDREG	PT_GR29(\regs),%r29
-2:
-	/* we take a struct pt_regs off the stack */
-	LDREG	PT_GR1(\regs),  %r1
-	LDREG	PT_GR29(\regs), %r29
-	ldo	-PT_SZ_ALGN(%r30), %r30
-3:
-	.endm
+	.macro  get_stack_use_r30
 
-#ifdef OLD
-	/* fixme interruption handler */
-	.macro	def code
-	/* WARNING!!! THIS IS DEBUG CODE ONLY!!! */
-	b	unimplemented_64bitirq
-	ldi	\code, %r1
-	.align	32
+	/* we put a struct pt_regs on the stack and save the registers there */
+
+	tophys  %r30,%r9
+	STREG   %r30,PT_GR30(%r9)
+	ldo	PT_SZ_ALGN(%r30),%r30
+	STREG   %r29,PT_GR29(%r9)
+	STREG   %r26,PT_GR26(%r9)
+	copy    %r9,%r29
 	.endm
 
-	/* Use def to enable break - KWDB wants em
-	 * (calls traps.c:handle_interruption) */
-	.macro	pass_break code
+	.macro  rest_stack
+	LDREG   PT_GR1(%r29), %r1
+	LDREG   PT_GR30(%r29),%r30
+	LDREG   PT_GR29(%r29),%r29
+	.endm
 
-#else
 	/* default interruption handler
 	 * (calls traps.c:handle_interruption) */
 	.macro	def code
-#endif
-	mtctl	%r29, %cr31
-	mtctl	%r1,  %cr28
-	ldi	\code, %r1
 	b	intr_save
-	mtctl   %r1, %cr29
+	ldi     \code, %r8
 	.align	32
 	.endm
 
 	/* Interrupt interruption handler
-	 * (calls irq.c:do_irq_mask) */
+	 * (calls irq.c:do_cpu_irq_mask) */
 	.macro	extint code
-	mtctl	%r29, %cr31
-	mtctl	%r1,  %cr28
-	mfctl	%cr23, %r1
-	mtctl	%r1, %cr23
 	b	intr_extint
-	mtctl	%r1, %cr29
+	mfsp    %sr7,%r16
 	.align	32
 	.endm	
 
@@ -203,7 +234,6 @@
 	 */
 
 	.macro	itlb_20 code
-
 	mfctl	%pcsq, spc
 #ifdef __LP64__
 	b       itlb_miss_20w
@@ -298,37 +328,27 @@
 	.endm
 	
 #ifndef __LP64__
-	/* nadtlb miss interruption handler (parisc 1.1 - 32 bit)
-	 *
-	 * Note: nadtlb misses will be treated
-	 * as an ordinary dtlb miss for now.
-	 *
-	 */
+	/* nadtlb miss interruption handler (parisc 1.1 - 32 bit) */
 
 	.macro	nadtlb_11 code
 
 	mfctl	%isr,spc
-	b	dtlb_miss_11
+	b       nadtlb_miss_11
 	mfctl	%ior,va
 
 	.align		32
 	.endm
 #endif
 	
-	/* nadtlb miss interruption handler (parisc 2.0)
-	 *
-	 * Note: nadtlb misses will be treated
-	 * as an ordinary dtlb miss for now.
-	 *
-	 */
+	/* nadtlb miss interruption handler (parisc 2.0) */
 
 	.macro	nadtlb_20 code
 
 	mfctl	%isr,spc
 #ifdef __LP64__
-	b       dtlb_miss_20w
+	b       nadtlb_miss_20w
 #else
-	b	dtlb_miss_20
+	b       nadtlb_miss_20
 #endif
 	mfctl	%ior,va
 
@@ -372,13 +392,14 @@
 	 * fault_vector_11 and fault_vector_20 are on the
 	 * same page. This is only necessary as long as we
 	 * write protect the kernel text, which we may stop
-	 * doing once we use large parge translations to cover
+	 * doing once we use large page translations to cover
 	 * the static part of the kernel address space.
 	 */
 
-
 	.export fault_vector_20
 
+	.text
+
 	.align 4096
 
 fault_vector_20:
@@ -402,7 +423,11 @@
 	def		13
 	def		14
 	dtlb_20		15
+#if 0
 	naitlb_20	16
+#else
+	def             16
+#endif
 	nadtlb_20	17
 	def		18
 	def		19
@@ -446,7 +471,11 @@
 	def		13
 	def		14
 	dtlb_11		15
+#if 0
 	naitlb_11	16
+#else
+	def             16
+#endif
 	nadtlb_11	17
 	def		18
 	def		19
@@ -467,9 +496,8 @@
 
 	.import		handle_interruption,code
 	.import		handle_real_interruption,code
-	.import		do_irq_mask,code
+	.import		do_cpu_irq_mask,code
 	.import		parisc_stopkernel,code
-	.import		cpu_irq_region,data
 
 	/*
 	 * r26 = function to be called
@@ -492,7 +520,8 @@
 	ldo	PT_SZ_ALGN(%r30),%r30
 #ifdef __LP64__
 	/* Yo, function pointers in wide mode are little structs... -PB */
-	/* XXX FIXME do we need to honor the fptr's %dp value too? */
+	ldd	24(%r26), %r2
+	STREG	%r2, PT_GR27(%r1)	/* Store childs %dp */
 	ldd	16(%r26), %r26
 #endif
 	STREG	%r26, PT_GR26(%r1)  /* Store function & argument for child */
@@ -500,15 +529,17 @@
 	ldo	CLONE_VM(%r0), %r26   /* Force CLONE_VM since only init_mm */
 	or	%r26, %r24, %r26      /* will have kernel mappings.	 */
 	copy	%r0, %r25
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#endif
 	bl	do_fork, %r2
 	copy	%r1, %r24
 
 	/* Parent Returns here */
 
-	ldo	-PT_SZ_ALGN(%r30), %r30
-	LDREG	-RP_OFFSET(%r30), %r2
+	LDREG	-PT_SZ_ALGN-RP_OFFSET(%r30), %r2
 	bv	%r0(%r2)
-	nop
+	ldo	-PT_SZ_ALGN(%r30), %r30
 
 	/*
 	 * Child Returns here
@@ -520,11 +551,22 @@
 	.export	ret_from_kernel_thread
 ret_from_kernel_thread:
 
+	/* Call schedule_tail first though */
+	bl	schedule_tail, %r2
+	nop
+
 	LDREG	TASK_PT_GR26-TASK_SZ_ALGN(%r30), %r1
 	LDREG	TASK_PT_GR25-TASK_SZ_ALGN(%r30), %r26
+#ifdef __LP64__
+	LDREG	TASK_PT_GR27-TASK_SZ_ALGN(%r30), %r27
+#endif
 	ble	0(%sr7, %r1)
 	copy	%r31, %r2
 
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+	loadgp				/* Thread could have been in a module */
+#endif
 	b	sys_exit
 	ldi	0, %r26
 
@@ -532,23 +574,22 @@
 	.export	__execve, code
 __execve:
 	copy	%r2, %r15
-	copy	%r23, %r17
 	copy	%r30, %r16
 	ldo	PT_SZ_ALGN(%r30), %r30
 	STREG	%r26, PT_GR26(%r16)
 	STREG	%r25, PT_GR25(%r16)
 	STREG	%r24, PT_GR24(%r16)
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#endif
 	bl	sys_execve, %r2
 	copy	%r16, %r26
 
-	comib,<>,n 0,%r28,__execve_failed
-
-	b	intr_return
-	STREG	%r17, PT_CR30(%r16)
+	cmpib,=,n 0,%r28,intr_return    /* forward */
 
-__execve_failed:
 	/* yes, this will trap and die. */
 	copy	%r15, %r2
+	copy	%r16, %r30
 	bv	%r0(%r2)
 	nop
 
@@ -567,16 +608,14 @@
 
 	ldil	L%_switch_to_ret, %r2
 	ldo	R%_switch_to_ret(%r2), %r2
-	LDIL_FIXUP(%r2)
 
 	STREG	%r2, TASK_PT_KPC(%r26)
 	LDREG	TASK_PT_KPC(%r25), %r2
 
 	STREG	%r30, TASK_PT_KSP(%r26)
 	LDREG	TASK_PT_KSP(%r25), %r30
-
 	bv	%r0(%r2)
-	nop
+	mtctl   %r25,%cr30
 
 _switch_to_ret:
 	mtctl	%r0, %cr0		/* Needed for single stepping */
@@ -587,27 +626,30 @@
 	copy	%r26, %r28
 
 	/*
-	 * Common rfi return path for interruptions, kernel execve, and some
-	 * syscalls.  The sys_rt_sigreturn syscall will return via this path
-	 * if the signal was received when the process was running; if the
-	 * process was blocked on a syscall then the normal syscall_exit
-	 * path is used.  All syscalls for traced proceses exit via
-	 * intr_restore.
-	 * Note that the following code uses a "relied upon translation". See
-	 * the parisc ACD for details. The ssm is necessary due to a PCXT bug.
+	 * Common rfi return path for interruptions, kernel execve, and
+	 * sys_rt_sigreturn (sometimes).  The sys_rt_sigreturn syscall will
+	 * return via this path if the signal was received when the process
+	 * was running; if the process was blocked on a syscall then the
+	 * normal syscall_exit path is used.  All syscalls for traced
+	 * proceses exit via intr_restore.
+	 *
+	 * XXX If any syscalls that change a processes space id ever exit
+	 * this way, then we will need to copy %sr3 in to PT_SR[3..7], and
+	 * adjust IASQ[0..1].
+	 *
+	 * Note that the following code uses a "relied upon translation".
+	 * See the parisc ACD for details. The ssm is necessary due to a
+	 * PCXT bug.
 	 */
 
 	.align 4096
 
 	.export	syscall_exit_rfi
 syscall_exit_rfi:
-	copy    %r30,%r16
-	/* FIXME! depi below has hardcoded dependency on kernel stack size */
-	depi    0,31,14,%r16 /* get task pointer */
+	mfctl   %cr30,%r16
 	ldo	TASK_REGS(%r16),%r16
 	/* Force iaoq to userspace, as the user has had access to our current
-	 * context via sigcontext.
-	 * XXX do we need any other protection here?
+	 * context via sigcontext. Also Filter the PSW for the same reason.
 	 */
 	LDREG	PT_IAOQ0(%r16),%r19
 	depi	3,31,2,%r19
@@ -615,57 +657,84 @@
 	LDREG	PT_IAOQ1(%r16),%r19
 	depi	3,31,2,%r19
 	STREG	%r19,PT_IAOQ1(%r16)
-	
+	LDREG   PT_PSW(%r16),%r19
+	ldil    L%USER_PSW_MASK,%r1
+	ldo     R%USER_PSW_MASK(%r1),%r1
+#ifdef __LP64__
+	ldil    L%USER_PSW_HI_MASK,%r20
+	ldo     R%USER_PSW_HI_MASK(%r20),%r20
+	depd    %r20,31,32,%r1
+#endif
+	and     %r19,%r1,%r19 /* Mask out bits that user shouldn't play with */
+	ldil    L%USER_PSW,%r1
+	ldo     R%USER_PSW(%r1),%r1
+	or      %r19,%r1,%r19 /* Make sure default USER_PSW bits are set */
+	STREG   %r19,PT_PSW(%r16)
+
+	/*
+	 * If we aren't being traced, we never saved space registers
+	 * (we don't store them in the sigcontext), so set them
+	 * to "proper" values now (otherwise we'll wind up restoring
+	 * whatever was last stored in the task structure, which might
+	 * be inconsistant if an interrupt occured while on the gateway
+	 * page) Note that we may be "trashing" values the user put in
+	 * them, but we don't support the the user changing them.
+	 */
+
+	STREG   %r0,PT_SR2(%r16)
+	mfsp    %sr3,%r19
+	STREG   %r19,PT_SR0(%r16)
+	STREG   %r19,PT_SR1(%r16)
+	STREG   %r19,PT_SR3(%r16)
+	STREG   %r19,PT_SR4(%r16)
+	STREG   %r19,PT_SR5(%r16)
+	STREG   %r19,PT_SR6(%r16)
+	STREG   %r19,PT_SR7(%r16)
+
 intr_return:
+	ssm     PSW_SM_I, %r0
 
 	/* Check for software interrupts */
 
 	.import irq_stat,data
 
-	ldil    L%irq_stat,%r19
-	ldo     R%irq_stat(%r19),%r19
-	LDIL_FIXUP(%r19)
-
+	ldil	L%irq_stat,%r19
+	ldo	R%irq_stat(%r19),%r19
 #ifdef CONFIG_SMP
-	copy    %r30,%r1
-	/* FIXME! depi below has hardcoded dependency on kernel stack size */
-	depi    0,31,14,%r1 /* get task pointer */
-	ldw     TASK_PROCESSOR(%r1),%r20 /* get cpu # - int */
-#if (IRQSTAT_SZ == 32)
-	dep     %r20,26,27,%r20 /* shift left 5 bits */
-#else
-#error IRQSTAT_SZ changed, fix dep
-#endif /* IRQSTAT_SZ */
-	add     %r19,%r20,%r19
+	mfctl   %cr30,%r1
+	ldw	TASK_PROCESSOR(%r1),%r1 /* get cpu # - int */
+	/* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount
+	** irq_stat[] is defined using ____cacheline_aligned.
+	*/
+#ifdef __LP64__
+	shld	%r1, 6, %r20
+#else
+	shlw	%r1, 5, %r20
+#endif
+	add     %r19,%r20,%r19	/* now have &irq_stat[smp_processor_id()] */
 #endif /* CONFIG_SMP */
 
-	ldw     IRQSTAT_SI_ACTIVE(%r19),%r20	/* hardirq.h: unsigned int */
-	ldw     IRQSTAT_SI_MASK(%r19),%r19	/* hardirq.h: unsigned int */
-	and     %r19,%r20,%r20
-	comib,<>,n 0,%r20,intr_do_softirq /* forward */
+	LDREG   IRQSTAT_SIRQ_PEND(%r19),%r20    /* hardirq.h: unsigned long */
+	cmpib,<>,n 0,%r20,intr_do_softirq /* forward */
 
 intr_check_resched:
 
 	/* check for reschedule */
-	copy    %r30,%r1
-	/* FIXME! depi below has hardcoded dependency on kernel stack size */
-	depi    0,31,14,%r1 /* get task pointer */
+	mfctl   %cr30,%r1
 	LDREG     TASK_NEED_RESCHED(%r1),%r19	/* sched.h: long need_resched */
-	comib,<>,n 0,%r19,intr_do_resched /* forward */
+	CMPIB<>,n 0,%r19,intr_do_resched /* forward */
 
 intr_check_sig:
 	/* As above */
-	copy    %r30,%r1
-	depi    0,31,14,%r1 /* get task pointer */
+	mfctl   %cr30,%r1
 	ldw	TASK_SIGPENDING(%r1),%r19	/* sched.h: int sigpending */
-	comib,<>,n 0,%r19,intr_do_signal /* forward */
+	cmpib,<>,n 0,%r19,intr_do_signal /* forward */
 
 intr_restore:
-	copy	    	%r16, %r29
-	ldo		PT_FR31(%r29), %r29
-	rest_fp		%r29
-	copy    	%r16, %r29
-	rest_general 	%r29
+	copy            %r16,%r29
+	ldo             PT_FR31(%r29),%r1
+	rest_fp         %r1
+	rest_general    %r29
 	ssm		0,%r0
 	nop
 	nop
@@ -674,10 +743,10 @@
 	nop
 	nop
 	nop
-	tophys		%r29
-	mtsm		%r0
+	tophys_r1       %r29
+	rsm             (PSW_SM_Q|PSW_SM_P|PSW_SM_D|PSW_SM_I),%r0
 	rest_specials	%r29
-	rest_stack	%r29
+	rest_stack
 	rfi
 	nop
 	nop
@@ -691,88 +760,163 @@
 	.import do_softirq,code
 intr_do_softirq:
 	bl      do_softirq,%r2
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#else
 	nop
+#endif
 	b       intr_check_resched
 	nop
 
 	.import schedule,code
 intr_do_resched:
 	/* Only do reschedule if we are returning to user space */
-	LDREG     PT_SR7(%r16), %r20
-	comib,= 0,%r20,intr_restore /* backward */
+	LDREG   PT_IASQ0(%r16), %r20
+	CMPIB= 0,%r20,intr_restore /* backward */
+	nop
+	LDREG   PT_IASQ1(%r16), %r20
+	CMPIB= 0,%r20,intr_restore /* backward */
 	nop
 
-	bl      schedule,%r2
-	ssm     PSW_SM_I, %r0
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#endif
+
+	ldil	L%intr_return, %r2
+	b	schedule
+	ldo	R%intr_return(%r2), %r2	/* return to intr_return, not here */
 
-	/* It's OK to leave I bit on */
-	b       intr_return /* start over if we got a resched */
-	nop
 
 	.import do_signal,code
 intr_do_signal:
 	/* Only do signals if we are returning to user space */
-	LDREG   PT_SR7(%r16), %r20
-	comib,= 0,%r20,intr_restore /* backward */
+	LDREG   PT_IASQ0(%r16), %r20
+	CMPIB= 0,%r20,intr_restore /* backward */
+	nop
+	LDREG   PT_IASQ1(%r16), %r20
+	CMPIB= 0,%r20,intr_restore /* backward */
 	nop
 
 	copy	%r0, %r24			/* unsigned long in_syscall */
 	copy	%r16, %r25			/* struct pt_regs *regs */
 	ssm     PSW_SM_I, %r0
+#ifdef __LP64__
+	ldo	-16(%r30),%r29			/* Reference param save area */
+#endif
 	bl	do_signal,%r2
 	copy	%r0, %r26			/* sigset_t *oldset = NULL */
 
 	b	intr_restore
 	nop
 
-	/* CR28 - saved GR1
-	 * CR29 - argument for do_irq_mask */
+	/*
+	 * External interrupts.
+	 */
 
-	/* External interrupts */
 intr_extint:
-	get_stack
+	CMPIB=,n 0,%r16,1f	/* on User or kernel stack? */
+	get_stack_use_cr30
+	b,n 3f
+
+1:
+#if 0  /* Interrupt Stack support not working yet! */
+	mfctl	%cr31,%r1
+	copy	%r30,%r17
+	/* FIXME! depi below has hardcoded idea of interrupt stack size (32k)*/
+#ifdef __LP64__
+	depdi	0,63,15,%r17
+#else
+	depi	0,31,15,%r17
+#endif
+	CMPB=,n	%r1,%r17,2f
+	get_stack_use_cr31
+	b,n 3f
+#endif
+2:
+	get_stack_use_r30
+
+3:
 	save_specials	%r29
-	virt_map	rfi
+	virt_map
 	save_general	%r29
 
-	ldo		PT_FR0(%r29), %r24
-	save_fp		%r24
+	ldo	PT_FR0(%r29), %r24
+	save_fp	%r24
 	
 	loadgp
 
-	copy		%r29, %r24	/* arg2 is pt_regs */
-	copy		%r29, %r16	/* save pt_regs */
-#ifdef CONFIG_KWDB
-	copy		%r29, %r3	/* KWDB - update frame pointer (gr3) */
-#endif
-
-	/* sorry to put this cruft in the interrupt path */
-	ldil		L%cpu_irq_region, %r25
-	ldo		R%cpu_irq_region(%r25), %r25
-	bl		do_irq_mask,%r2
+	copy	%r29, %r26	/* arg0 is pt_regs */
+	copy	%r29, %r16	/* save pt_regs */
+	ldil	L%intr_return, %r2
 #ifdef __LP64__
-	LDIL_FIXUP(%r25)
-#else
-	nop
+	ldo	-16(%r30),%r29	/* Reference param save area */
 #endif
+	b	do_cpu_irq_mask
+	ldo	R%intr_return(%r2), %r2	/* return to intr_return, not here */
+
 
-	b		intr_return
-	nop
 
 	/* Generic interruptions (illegal insn, unaligned, page fault, etc) */
 
 	.export         intr_save, code /* for os_hpmc */
 
 intr_save:
-	get_stack
+	mfsp    %sr7,%r16
+	CMPIB=,n 0,%r16,1f
+	get_stack_use_cr30
+	b	2f
+	copy    %r8,%r26
+
+1:
+	get_stack_use_r30
+	copy    %r8,%r26
+
+2:
 	save_specials	%r29
 
-	mfctl		%cr20, %r1
-	STREG		%r1, PT_ISR(%r29)
-	mfctl		%cr21, %r1
-	STREG		%r1, PT_IOR(%r29)
+	/* If this trap is a itlb miss, skip saving/adjusting isr/ior */
+
+	/*
+	 * FIXME: 1) Use a #define for the hardwired "6" below (and in
+	 *           traps.c.
+	 *        2) Once we start executing code above 4 Gb, we need
+	 *           to adjust iasq/iaoq here in the same way we
+	 *           adjust isr/ior below.
+	 */
+
+	CMPIB=,n        6,%r26,skip_save_ior
+
+	/* save_specials left ipsw value in r8 for us to test */
+
+	mfctl           %cr20, %r16 /* isr */
+	mfctl           %cr21, %r17 /* ior */
+
+#ifdef __LP64__
+	/*
+	 * If the interrupted code was running with W bit off (32 bit),
+	 * clear the b bits (bits 0 & 1) in the ior.
+	 */
+	extrd,u,*<>     %r8,PSW_W_BIT,1,%r0
+	depdi           0,1,2,%r17
+
+	/*
+	 * FIXME: This code has hardwired assumptions about the split
+	 *        between space bits and offset bits. This will change
+	 *        when we allow alternate page sizes.
+	 */
+
+	/* adjust isr/ior. */
+
+	extrd,u         %r16,63,7,%r1    /* get high bits from isr for ior */
+	depd            %r1,31,7,%r17    /* deposit them into ior */
+	depdi           0,63,7,%r16      /* clear them from isr */
+#endif
+	STREG           %r16, PT_ISR(%r29)
+	STREG           %r17, PT_IOR(%r29)
+
 
-	virt_map	rfi
+skip_save_ior:
+	virt_map
 	save_general	%r29
 
 	ldo		PT_FR0(%r29), %r25
@@ -785,11 +929,16 @@
 	copy		%r29, %r3	/* KWDB - update frame pointer (gr3) */
 #endif
 
-	bl		handle_interruption,%r2
-	copy		%r29, %r16	/* save pt_regs */
+#ifdef __LP64__
+	ldo		-16(%r30),%r29	/* Reference param save area */
+#endif
+
+	ldil		L%intr_return, %r2
+	copy		%r25, %r16	/* save pt_regs */
+
+	b		handle_interruption
+	ldo		R%intr_return(%r2), %r2	/* return to intr_return */
 
-	b		intr_return
-	nop
 
 	/*
 	 * Note for all tlb miss handlers:
@@ -821,10 +970,9 @@
 #ifdef __LP64__
 
 dtlb_miss_20w:
-
-	extrd,u         spc,31,7,t1     /* adjust va */
+	extrd,u         spc,63,7,t1     /* adjust va */
 	depd            t1,31,7,va      /* adjust va */
-	depdi           0,31,7,spc      /* adjust space */
+	depdi           0,63,7,spc      /* adjust space */
 	mfctl           %cr25,ptp	/* Assume user space miss */
 	or,*<>          %r0,spc,%r0     /* If it is user space, nullify */
 	mfctl           %cr24,ptp	/* Load kernel pgd instead */
@@ -832,20 +980,20 @@
 
 	mfsp            %sr7,t0		/* Get current space */
 	or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
-	comb,<>,n       t0,spc,dtlb_fault /* forward */
+	cmpb,*<>,n       t0,spc,dtlb_fault /* forward */
 
 	/* First level page table lookup */
 
 	ldd,s           t1(ptp),ptp
 	extrd,u         va,42,9,t0     /* get second-level index */
-	bb,>=,n 	ptp,_PAGE_PRESENT_BIT,dtlb_fault
+	bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
 	depdi           0,63,12,ptp     /* clear prot bits */
 
 	/* Second level page table lookup */
 
 	ldd,s           t0(ptp),ptp
 	extrd,u         va,51,9,t0     /* get third-level index */
-	bb,>=,n 	ptp,_PAGE_PRESENT_BIT,dtlb_fault
+	bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
 	depdi           0,63,12,ptp     /* clear prot bits */
 
 	/* Third level page table lookup */
@@ -853,7 +1001,7 @@
 	shladd           t0,3,ptp,ptp
 	ldi		_PAGE_ACCESSED,t1
 	ldd              0(ptp),pte
-	bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_fault
+	bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
 
 	/* Check whether the "accessed" bit was set, otherwise do so */
 
@@ -861,11 +1009,9 @@
 	and,*<>         t1,pte,%r0      /* test and nullify if already set */
 	std             t0,0(ptp)       /* write back pte */
 
-	copy            spc,prot	/* init prot with faulting space */
-	
-	depd		pte,8,7,prot
-	extrd,u,*=	pte,_PAGE_NO_CACHE_BIT+32,1,r0
-	depdi		1,12,1,prot
+	space_to_prot   spc prot        /* create prot id from space */
+	depd            pte,8,7,prot    /* add in prot bits from pte */
+
 	extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
 	depdi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
 	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
@@ -874,11 +1020,106 @@
 	/* Get rid of prot bits and convert to page addr for idtlbt */
 
 	depdi		0,63,12,pte
-	extrd,u         pte,56,32,pte
-	idtlbt		%r16,%r17
+	extrd,u         pte,56,52,pte
+	idtlbt          pte,prot
 
 	rfir
 	nop
+
+dtlb_check_alias_20w:
+
+	/* Check to see if fault is in the temporary alias region */
+
+	cmpib,*<>,n     0,spc,dtlb_fault /* forward */
+	ldil            L%(TMPALIAS_MAP_START),t0
+	copy            va,t1
+	depdi           0,63,23,t1
+	cmpb,*<>,n      t0,t1,dtlb_fault /* forward */
+	ldi             (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
+	depd,z          prot,8,7,prot
+
+	/*
+	 * OK, it is in the temp alias region, check whether "from" or "to".
+	 * Check "subtle" note in pacache.S re: r23/r26.
+	 */
+
+	extrd,u,*=      va,41,1,r0
+	or,*tr          %r23,%r0,pte    /* If "from" use "from" page */
+	or,*            %r26,%r0,pte    /* else "to", use "to" page  */
+
+	idtlbt          pte,prot
+
+	rfir
+	nop
+
+nadtlb_miss_20w:
+	extrd,u         spc,63,7,t1     /* adjust va */
+	depd            t1,31,7,va      /* adjust va */
+	depdi           0,63,7,spc      /* adjust space */
+	mfctl           %cr25,ptp	/* Assume user space miss */
+	or,*<>          %r0,spc,%r0     /* If it is user space, nullify */
+	mfctl           %cr24,ptp	/* Load kernel pgd instead */
+	extrd,u         va,33,9,t1      /* Get pgd index */
+
+	mfsp            %sr7,t0		/* Get current space */
+	or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
+	cmpb,*<>,n       t0,spc,nadtlb_fault /* forward */
+
+	/* First level page table lookup */
+
+	ldd,s           t1(ptp),ptp
+	extrd,u         va,42,9,t0     /* get second-level index */
+	bb,>=,n         ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
+	depdi           0,63,12,ptp     /* clear prot bits */
+
+	/* Second level page table lookup */
+
+	ldd,s           t0(ptp),ptp
+	extrd,u         va,51,9,t0     /* get third-level index */
+	bb,>=,n         ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
+	depdi           0,63,12,ptp     /* clear prot bits */
+
+	/* Third level page table lookup */
+
+	shladd           t0,3,ptp,ptp
+	ldi		_PAGE_ACCESSED,t1
+	ldd              0(ptp),pte
+	bb,>=,n          pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_20w
+
+	space_to_prot   spc prot        /* create prot id from space */
+	depd            pte,8,7,prot    /* add in prot bits from pte */
+
+	extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
+	depdi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
+	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
+	depdi		0,11,2,prot	/* If Gateway, Set PL2 to 0 */
+
+	/* Get rid of prot bits and convert to page addr for idtlbt */
+
+	depdi		0,63,12,pte
+	extrd,u         pte,56,52,pte
+	idtlbt          pte,prot
+
+	rfir
+	nop
+
+nadtlb_check_flush_20w:
+	bb,>=,n          pte,_PAGE_FLUSH_BIT,nadtlb_emulate
+
+	/* Insert a "flush only" translation */
+
+	depdi,z         7,7,3,prot
+	depdi           1,10,1,prot
+
+	/* Get rid of prot bits and convert to page addr for idtlbt */
+
+	depdi		0,63,12,pte
+	extrd,u         pte,56,52,pte
+	idtlbt          pte,prot
+
+	rfir
+	nop
+
 #else
 
 dtlb_miss_11:
@@ -889,13 +1130,13 @@
 
 	mfsp            %sr7,t0		/* Get current space */
 	or,=            %r0,t0,%r0	/* If kernel, nullify following test */
-	comb,<>,n       t0,spc,dtlb_fault /* forward */
+	cmpb,<>,n       t0,spc,dtlb_fault /* forward */
 
 	/* First level page table lookup */
 
 	ldwx,s		t1(ptp),ptp
 	extru		va,19,10,t0	/* get second-level index */
-	bb,>=,n 	ptp,_PAGE_PRESENT_BIT,dtlb_fault
+	bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_11
 	depi		0,31,12,ptp	/* clear prot bits */
 
 	/* Second level page table lookup */
@@ -903,7 +1144,7 @@
 	sh2addl 	 t0,ptp,ptp
 	ldi		_PAGE_ACCESSED,t1
 	ldw		 0(ptp),pte
-	bb,>=,n 	 pte,_PAGE_PRESENT_BIT,dtlb_fault
+	bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_check_alias_11
 
 	/* Check whether the "accessed" bit was set, otherwise do so */
 
@@ -911,8 +1152,8 @@
 	and,<>		t1,pte,%r0	/* test and nullify if already set */
 	stw		t0,0(ptp)	/* write back pte */
 
-	copy            spc,prot	/* init prot with faulting space */
-	dep		pte,8,7,prot
+	zdep            spc,30,15,prot  /* create prot id from space */
+	dep             pte,8,7,prot    /* add in prot bits from pte */
 
 	extru,=		pte,_PAGE_NO_CACHE_BIT,1,r0
 	depi		1,12,1,prot
@@ -937,9 +1178,34 @@
 	rfir
 	nop
 
-dtlb_miss_20:
-	.level 2.0
+dtlb_check_alias_11:
+
+	/* Check to see if fault is in the temporary alias region */
+
+	cmpib,<>,n      0,spc,dtlb_fault /* forward */
+	ldil            L%(TMPALIAS_MAP_START),t0
+	copy            va,t1
+	depwi           0,31,23,t1
+	cmpb,<>,n       t0,t1,dtlb_fault /* forward */
+	ldi             (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
+	depw,z          prot,8,7,prot
+
+	/*
+	 * OK, it is in the temp alias region, check whether "from" or "to".
+	 * Check "subtle" note in pacache.S re: r23/r26.
+	 */
+
+	extrw,u,=       va,9,1,r0
+	or,tr           %r23,%r0,pte    /* If "from" use "from" page */
+	or              %r26,%r0,pte    /* else "to", use "to" page  */
+
+	idtlba          pte,(va)
+	idtlbp          prot,(va)
 
+	rfir
+	nop
+
+nadtlb_miss_11:
 	mfctl           %cr25,ptp	/* Assume user space miss */
 	or,<>           %r0,spc,%r0	/* If it is user space, nullify */
 	mfctl           %cr24,ptp	/* Load kernel pgd instead */
@@ -947,13 +1213,13 @@
 
 	mfsp            %sr7,t0		/* Get current space */
 	or,=            %r0,t0,%r0	/* If kernel, nullify following test */
-	comb,<>,n       t0,spc,dtlb_fault /* forward */
+	cmpb,<>,n       t0,spc,nadtlb_fault /* forward */
 
 	/* First level page table lookup */
 
 	ldwx,s		t1(ptp),ptp
 	extru		va,19,10,t0	/* get second-level index */
-	bb,>=,n 	ptp,_PAGE_PRESENT_BIT,dtlb_fault
+	bb,>=,n         ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
 	depi		0,31,12,ptp	/* clear prot bits */
 
 	/* Second level page table lookup */
@@ -961,7 +1227,81 @@
 	sh2addl 	 t0,ptp,ptp
 	ldi		_PAGE_ACCESSED,t1
 	ldw		 0(ptp),pte
-	bb,>=,n 	 pte,_PAGE_PRESENT_BIT,dtlb_fault
+	bb,>=,n          pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_11
+
+	zdep            spc,30,15,prot  /* create prot id from space */
+	dep             pte,8,7,prot    /* add in prot bits from pte */
+
+	extru,=		pte,_PAGE_NO_CACHE_BIT,1,r0
+	depi		1,12,1,prot
+	extru,=         pte,_PAGE_USER_BIT,1,r0
+	depi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
+	extru,= 	pte,_PAGE_GATEWAY_BIT,1,r0
+	depi		0,11,2,prot	/* If Gateway, Set PL2 to 0 */
+
+	/* Get rid of prot bits and convert to page addr for idtlba */
+
+	depi		0,31,12,pte
+	extru		pte,24,25,pte
+
+	mfsp		%sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+	mtsp		spc,%sr1
+
+	idtlba		pte,(%sr1,va)
+	idtlbp		prot,(%sr1,va)
+
+	mtsp		t0, %sr1	/* Restore sr1 */
+
+	rfir
+	nop
+
+nadtlb_check_flush_11:
+	bb,>=,n          pte,_PAGE_FLUSH_BIT,nadtlb_emulate
+
+	/* Insert a "flush only" translation */
+
+	zdepi           7,7,3,prot
+	depi            1,10,1,prot
+
+	/* Get rid of prot bits and convert to page addr for idtlba */
+
+	depi		0,31,12,pte
+	extru		pte,24,25,pte
+
+	mfsp		%sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+	mtsp		spc,%sr1
+
+	idtlba		pte,(%sr1,va)
+	idtlbp		prot,(%sr1,va)
+
+	mtsp		t0, %sr1	/* Restore sr1 */
+
+	rfir
+	nop
+
+dtlb_miss_20:
+	mfctl           %cr25,ptp	/* Assume user space miss */
+	or,<>           %r0,spc,%r0	/* If it is user space, nullify */
+	mfctl           %cr24,ptp	/* Load kernel pgd instead */
+	extru		va,9,10,t1	/* Get pgd index */
+
+	mfsp            %sr7,t0		/* Get current space */
+	or,=            %r0,t0,%r0	/* If kernel, nullify following test */
+	cmpb,<>,n       t0,spc,dtlb_fault /* forward */
+
+	/* First level page table lookup */
+
+	ldwx,s		t1(ptp),ptp
+	extru		va,19,10,t0	/* get second-level index */
+	bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20
+	depi		0,31,12,ptp	/* clear prot bits */
+
+	/* Second level page table lookup */
+
+	sh2addl 	 t0,ptp,ptp
+	ldi		_PAGE_ACCESSED,t1
+	ldw		 0(ptp),pte
+	bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20
 
 	/* Check whether the "accessed" bit was set, otherwise do so */
 
@@ -969,11 +1309,9 @@
 	and,<>		t1,pte,%r0	/* test and nullify if already set */
 	stw		t0,0(ptp)	/* write back pte */
 
-	copy            spc,prot	/* init prot with faulting space */
-	
-	depd		pte,8,7,prot
-	extrd,u,*=	pte,_PAGE_NO_CACHE_BIT+32,1,r0
-	depdi		1,12,1,prot
+	space_to_prot   spc prot        /* create prot id from space */
+	depd            pte,8,7,prot    /* add in prot bits from pte */
+
 	extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
 	depdi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
 	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
@@ -981,16 +1319,145 @@
 
 	/* Get rid of prot bits and convert to page addr for idtlbt */
 
-	depdi		0,63,12,pte
-	extrd,u		pte,56,25,pte
-	idtlbt		%r16,%r17
+	extrd,s         pte,35,4,t0
+	depdi		0,63,12,pte	/* clear lower 12 bits */
+        addi,=          1,t0,0 
+        extrd,u,*tr     pte,56,25,pte 
+	extrd,s		pte,56,25,pte	/* bit 31:8 >> 8  */ 
+	idtlbt          pte,prot
+
+	rfir
+	nop
+
+dtlb_check_alias_20:
+
+	/* Check to see if fault is in the temporary alias region */
 
-	.level		1.1
+	cmpib,<>,n      0,spc,dtlb_fault /* forward */
+	ldil            L%(TMPALIAS_MAP_START),t0
+	copy            va,t1
+	depwi           0,31,23,t1
+	cmpb,<>,n       t0,t1,dtlb_fault /* forward */
+	ldi             (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
+	depd,z          prot,8,7,prot
+
+	/*
+	 * OK, it is in the temp alias region, check whether "from" or "to".
+	 * Check "subtle" note in pacache.S re: r23/r26.
+	 */
+
+	extrw,u,=       va,9,1,r0
+	or,tr           %r23,%r0,pte    /* If "from" use "from" page */
+	or              %r26,%r0,pte    /* else "to", use "to" page  */
+
+	idtlbt          pte,prot
+
+	rfir
+	nop
+
+nadtlb_miss_20:
+	mfctl           %cr25,ptp	/* Assume user space miss */
+	or,<>           %r0,spc,%r0	/* If it is user space, nullify */
+	mfctl           %cr24,ptp	/* Load kernel pgd instead */
+	extru		va,9,10,t1	/* Get pgd index */
+
+	mfsp            %sr7,t0		/* Get current space */
+	or,=            %r0,t0,%r0	/* If kernel, nullify following test */
+	cmpb,<>,n       t0,spc,nadtlb_fault /* forward */
+
+	/* First level page table lookup */
+
+	ldwx,s		t1(ptp),ptp
+	extru		va,19,10,t0	/* get second-level index */
+	bb,>=,n         ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
+	depi		0,31,12,ptp	/* clear prot bits */
+
+	/* Second level page table lookup */
+
+	sh2addl 	 t0,ptp,ptp
+	ldi		_PAGE_ACCESSED,t1
+	ldw		 0(ptp),pte
+	bb,>=,n          pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_20
+
+	space_to_prot   spc prot        /* create prot id from space */
+	depd            pte,8,7,prot    /* add in prot bits from pte */
+
+	extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
+	depdi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
+	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
+	depdi		0,11,2,prot	/* If Gateway, Set PL2 to 0 */
+
+	/* Get rid of prot bits and convert to page addr for idtlbt */
+
+        extrd,s         pte,35,4,t0
+        depdi           0,63,12,pte     /* clear lower 12 bits */
+        addi,=          1,t0,0
+        extrd,u,*tr     pte,56,25,pte
+        extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
+        idtlbt          pte,prot
+
+	rfir
+	nop
+
+nadtlb_check_flush_20:
+	bb,>=,n          pte,_PAGE_FLUSH_BIT,nadtlb_emulate
+
+	/* Insert a "flush only" translation */
+
+	depdi,z         7,7,3,prot
+	depdi           1,10,1,prot
+
+	/* Get rid of prot bits and convert to page addr for idtlbt */
+
+	depdi		0,63,12,pte
+	extrd,u         pte,56,32,pte
+	idtlbt          pte,prot
 
 	rfir
 	nop
 #endif
 
+nadtlb_emulate:
+
+	/*
+	 * Non access misses can be caused by fdc,fic,pdc,lpa,probe and
+	 * probei instructions. We don't want to fault for these
+	 * instructions (not only does it not make sense, it can cause
+	 * deadlocks, since some flushes are done with the mmap
+	 * semaphore held). If the translation doesn't exist, we can't
+	 * insert a translation, so have to emulate the side effects
+	 * of the instruction. Since we don't insert a translation
+	 * we can get a lot of faults during a flush loop, so it makes
+	 * sense to try to do it here with minimum overhead. We only
+	 * emulate fdc,fic & pdc instructions whose base and index
+	 * registers are not shadowed. We defer everything else to the
+	 * "slow" path.
+	 */
+
+	mfctl           %cr19,%r9 /* Get iir */
+	ldi             0x280,%r16
+	and             %r9,%r16,%r17
+	cmpb,<>,n       %r16,%r17,nadtlb_fault /* Not fdc,fic,pdc */
+	bb,>=,n         %r9,26,nadtlb_nullify  /* m bit not set, just nullify */
+	b,l             get_register,%r25
+	extrw,u         %r9,15,5,%r8           /* Get index register # */
+	CMPIB=,n        -1,%r1,nadtlb_fault    /* have to use slow path */
+	copy            %r1,%r24
+	b,l             get_register,%r25
+	extrw,u         %r9,10,5,%r8           /* Get base register # */
+	CMPIB=,n        -1,%r1,nadtlb_fault    /* have to use slow path */
+	b,l             set_register,%r25
+	add,l           %r1,%r24,%r1           /* doesn't affect c/b bits */
+
+nadtlb_nullify:
+	mfctl           %cr22,%r8              /* Get ipsw */
+	ldil            L%PSW_N,%r9
+	or              %r8,%r9,%r8            /* Set PSW_N */
+	mtctl           %r8,%cr22
+
+	rfir
+	nop
+
 #ifdef __LP64__
 itlb_miss_20w:
 
@@ -999,9 +1466,9 @@
 	 * on the gateway page which is in the kernel address space.
 	 */
 
-	extrd,u         spc,31,7,t1     /* adjust va */
+	extrd,u         spc,63,7,t1     /* adjust va */
 	depd            t1,31,7,va      /* adjust va */
-	depdi           0,31,7,spc      /* adjust space */
+	depdi           0,63,7,spc      /* adjust space */
 	cmpib,*=        0,spc,itlb_miss_kernel_20w
 	extrd,u         va,33,9,t1      /* Get pgd index */
 
@@ -1039,11 +1506,9 @@
 	and,*<>         t1,pte,%r0      /* test and nullify if already set */
 	std             t0,0(ptp)       /* write back pte */
 
-	copy            spc,prot        /* init prot with faulting space */
-	
-	depd		pte,8,7,prot
-	extrd,u,*=	pte,_PAGE_NO_CACHE_BIT+32,1,r0
-	depdi		1,12,1,prot
+	space_to_prot   spc prot        /* create prot id from space */
+	depd            pte,8,7,prot    /* add in prot bits from pte */
+
 	extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
 	depdi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
 	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
@@ -1053,7 +1518,7 @@
 
 	depdi		0,63,12,pte
 	extrd,u         pte,56,32,pte
-	iitlbt          %r16,%r17
+	iitlbt          pte,prot
 
 	rfir
 	nop
@@ -1070,14 +1535,14 @@
 	 * on the gateway page which is in the kernel address space.
 	 */
 
-	comib,=         0,spc,itlb_miss_kernel_11
+	cmpib,=         0,spc,itlb_miss_kernel_11
 	extru		va,9,10,t1	/* Get pgd index */
 
 	mfctl           %cr25,ptp	/* load user pgd */
 
 	mfsp            %sr7,t0		/* Get current space */
 	or,=            %r0,t0,%r0	/* If kernel, nullify following test */
-	comb,<>,n       t0,spc,itlb_fault /* forward */
+	cmpb,<>,n       t0,spc,itlb_fault /* forward */
 
 	/* First level page table lookup */
 
@@ -1100,8 +1565,8 @@
 	and,<>		t1,pte,%r0	/* test and nullify if already set */
 	stw		t0,0(ptp)	/* write back pte */
 
-	copy            spc,prot        /* init prot with faulting space */
-	dep		pte,8,7,prot
+	zdep            spc,30,15,prot  /* create prot id from space */
+	dep             pte,8,7,prot    /* add in prot bits from pte */
 
 	extru,=		pte,_PAGE_NO_CACHE_BIT,1,r0
 	depi		1,12,1,prot
@@ -1137,14 +1602,14 @@
 	 * on the gateway page which is in the kernel address space.
 	 */
 
-	comib,=         0,spc,itlb_miss_kernel_20
+	cmpib,=         0,spc,itlb_miss_kernel_20
 	extru		va,9,10,t1	/* Get pgd index */
 
 	mfctl           %cr25,ptp	/* load user pgd */
 
 	mfsp            %sr7,t0		/* Get current space */
 	or,=            %r0,t0,%r0	/* If kernel, nullify following test */
-	comb,<>,n       t0,spc,itlb_fault /* forward */
+	cmpb,<>,n       t0,spc,itlb_fault /* forward */
 
 	/* First level page table lookup */
 
@@ -1167,13 +1632,9 @@
 	and,<>		t1,pte,%r0	/* test and nullify if already set */
 	stw		t0,0(ptp)	/* write back pte */
 
-	copy            spc,prot        /* init prot with faulting space */
-	
-	.level 2.0
+	space_to_prot   spc prot        /* create prot id from space */
+	depd            pte,8,7,prot    /* add in prot bits from pte */
 
-	depd		pte,8,7,prot
-	extrd,u,*=	pte,_PAGE_NO_CACHE_BIT+32,1,r0
-	depdi		1,12,1,prot
 	extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
 	depdi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
 	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
@@ -1181,10 +1642,12 @@
 
 	/* Get rid of prot bits and convert to page addr for iitlbt */
 
-	depdi		0,63,12,pte
-	extrd,u		pte,56,25,pte
-	iitlbt          %r16,%r17
-	.level		1.1
+        extrd,s         pte,35,4,t0 
+        depdi           0,63,12,pte     /* clear lower 12 bits */
+        addi,=          1,t0,0
+        extrd,u,*tr     pte,56,25,pte 
+        extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
+	iitlbt          pte,prot
 
 	rfir
 	nop
@@ -1198,11 +1661,10 @@
 #ifdef __LP64__
 
 dbit_trap_20w:
-
-	extrd,u         spc,31,7,t1     /* adjust va */
+	extrd,u         spc,63,7,t1     /* adjust va */
 	depd            t1,31,7,va      /* adjust va */
 	depdi           0,1,2,va        /* adjust va */
-	depdi           0,31,7,spc      /* adjust space */
+	depdi           0,63,7,spc      /* adjust space */
 	mfctl           %cr25,ptp	/* Assume user space miss */
 	or,*<>          %r0,spc,%r0     /* If it is user space, nullify */
 	mfctl           %cr24,ptp	/* Load kernel pgd instead */
@@ -1210,7 +1672,7 @@
 
 	mfsp            %sr7,t0		/* Get current space */
 	or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
-	comb,<>,n       t0,spc,dbit_fault /* forward */
+	cmpb,*<>,n       t0,spc,dbit_fault /* forward */
 
 	/* First level page table lookup */
 
@@ -1229,6 +1691,18 @@
 	/* Third level page table lookup */
 
 	shladd           t0,3,ptp,ptp
+#ifdef CONFIG_SMP
+	CMPIB=,n        0,spc,dbit_nolock_20w
+	ldil            L%PA(pa_dbit_lock),t0
+	ldo             R%PA(pa_dbit_lock)(t0),t0
+
+dbit_spin_20w:
+	ldcw            0(t0),t1
+	cmpib,=         0,t1,dbit_spin_20w
+	nop
+
+dbit_nolock_20w:
+#endif
 	ldi		(_PAGE_ACCESSED|_PAGE_DIRTY),t1
 	ldd              0(ptp),pte
 	bb,>=,n          pte,_PAGE_PRESENT_BIT,dbit_fault
@@ -1238,11 +1712,9 @@
 	or		t1,pte,pte
 	std             pte,0(ptp)      /* write back pte */
 
-	copy            spc,prot	/* init prot with faulting space */
-	
-	depd		pte,8,7,prot
-	extrd,u,*=	pte,_PAGE_NO_CACHE_BIT+32,1,r0
-	depdi		1,12,1,prot
+	space_to_prot   spc prot        /* create prot id from space */
+	depd            pte,8,7,prot    /* add in prot bits from pte */
+
 	extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
 	depdi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
 	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
@@ -1251,8 +1723,15 @@
 	/* Get rid of prot bits and convert to page addr for idtlbt */
 
 	depdi		0,63,12,pte
-	extrd,u         pte,56,32,pte
-	idtlbt		%r16,%r17
+	extrd,u         pte,56,52,pte
+	idtlbt          pte,prot
+#ifdef CONFIG_SMP
+	CMPIB=,n        0,spc,dbit_nounlock_20w
+	ldi             1,t1
+	stw             t1,0(t0)
+
+dbit_nounlock_20w:
+#endif
 
 	rfir
 	nop
@@ -1266,7 +1745,7 @@
 
 	mfsp            %sr7,t0		/* Get current space */
 	or,=            %r0,t0,%r0	/* If kernel, nullify following test */
-	comb,<>,n       t0,spc,dbit_fault /* forward */
+	cmpb,<>,n       t0,spc,dbit_fault /* forward */
 
 	/* First level page table lookup */
 
@@ -1278,6 +1757,18 @@
 	/* Second level page table lookup */
 
 	sh2addl 	 t0,ptp,ptp
+#ifdef CONFIG_SMP
+	CMPIB=,n        0,spc,dbit_nolock_11
+	ldil            L%PA(pa_dbit_lock),t0
+	ldo             R%PA(pa_dbit_lock)(t0),t0
+
+dbit_spin_11:
+	ldcw            0(t0),t1
+	cmpib,=         0,t1,dbit_spin_11
+	nop
+
+dbit_nolock_11:
+#endif
 	ldi		(_PAGE_ACCESSED|_PAGE_DIRTY),t1
 	ldw		 0(ptp),pte
 	bb,>=,n 	 pte,_PAGE_PRESENT_BIT,dbit_fault
@@ -1287,8 +1778,8 @@
 	or		t1,pte,pte
 	stw		pte,0(ptp)	/* write back pte */
 
-	copy            spc,prot        /* init prot with faulting space */
-	dep		pte,8,7,prot
+	zdep            spc,30,15,prot  /* create prot id from space */
+	dep             pte,8,7,prot    /* add in prot bits from pte */
 
 	extru,=		pte,_PAGE_NO_CACHE_BIT,1,r0
 	depi		1,12,1,prot
@@ -1302,13 +1793,20 @@
 	depi		0,31,12,pte
 	extru		pte,24,25,pte
 
-	mfsp		%sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+	mfsp            %sr1,t1  /* Save sr1 so we can use it in tlb inserts */
 	mtsp		spc,%sr1
 
 	idtlba		pte,(%sr1,va)
 	idtlbp		prot,(%sr1,va)
 
-	mtsp		t0, %sr1     /* Restore sr1 */
+	mtsp            t1, %sr1     /* Restore sr1 */
+#ifdef CONFIG_SMP
+	CMPIB=,n        0,spc,dbit_nounlock_11
+	ldi             1,t1
+	stw             t1,0(t0)
+
+dbit_nounlock_11:
+#endif
 
 	rfir
 	nop
@@ -1321,7 +1819,7 @@
 
 	mfsp            %sr7,t0		/* Get current space */
 	or,=            %r0,t0,%r0	/* If kernel, nullify following test */
-	comb,<>,n       t0,spc,dbit_fault /* forward */
+	cmpb,<>,n       t0,spc,dbit_fault /* forward */
 
 	/* First level page table lookup */
 
@@ -1333,6 +1831,18 @@
 	/* Second level page table lookup */
 
 	sh2addl 	 t0,ptp,ptp
+#ifdef CONFIG_SMP
+	CMPIB=,n        0,spc,dbit_nolock_20
+	ldil            L%PA(pa_dbit_lock),t0
+	ldo             R%PA(pa_dbit_lock)(t0),t0
+
+dbit_spin_20:
+	ldcw            0(t0),t1
+	cmpib,=         0,t1,dbit_spin_20
+	nop
+
+dbit_nolock_20:
+#endif
 	ldi		(_PAGE_ACCESSED|_PAGE_DIRTY),t1
 	ldw		 0(ptp),pte
 	bb,>=,n 	 pte,_PAGE_PRESENT_BIT,dbit_fault
@@ -1342,25 +1852,28 @@
 	or		t1,pte,pte
 	stw		pte,0(ptp)	/* write back pte */
 
-	copy            spc,prot        /* init prot with faulting space */
-	
-	.level 2.0
+	space_to_prot   spc prot        /* create prot id from space */
+	depd            pte,8,7,prot    /* add in prot bits from pte */
 
-	depd		pte,8,7,prot
-	extrd,u,*=	pte,_PAGE_NO_CACHE_BIT+32,1,r0
-	depdi		1,12,1,prot
 	extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
 	depdi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
 	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
 	depdi		0,11,2,prot	/* If Gateway, Set PL2 to 0 */
 
-	/* Get rid of prot bits and convert to page addr for idtlbt */
+        extrd,s         pte,35,4,t0 
+        depdi           0,63,12,pte     /* clear lower 12 bits */
+        addi,=          1,t0,0
+        extrd,u,*tr     pte,56,25,pte 
+        extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
+        idtlbt          pte,prot
 
-	depdi		0,63,12,pte
-	extrd,u		pte,56,25,pte
-	idtlbt		%r16,%r17
+#ifdef CONFIG_SMP
+	CMPIB=,n        0,spc,dbit_nounlock_20
+	ldi             1,t1
+	stw             t1,0(t0)
 
-	.level		1.1
+dbit_nounlock_20:
+#endif
 
 	rfir
 	nop
@@ -1369,50 +1882,24 @@
 	.import handle_interruption,code
 
 kernel_bad_space:
-	b		tlb_fault
-	ldi		31,%r1	/* Use an unused code */
+	b               intr_save
+	ldi             31,%r8  /* Use an unused code */
 
 dbit_fault:
-	b		tlb_fault
-	ldi		20,%r1
+	b               intr_save
+	ldi             20,%r8
 
 itlb_fault:
-	b		tlb_fault
-	ldi		6,%r1
-
-dtlb_fault:
-	ldi		15,%r1
+	b               intr_save
+	ldi             6,%r8
 
-	/* Fall Through */
+nadtlb_fault:
+	b               intr_save
+	ldi             17,%r8
 
-tlb_fault:
-	mtctl		%r1,%cr29
-	mtctl		%r29,%cr31
-
-	get_stack
-	save_specials	%r29		/* Note this saves a trashed r1 */
-
-	SAVE_CR		(%cr20, PT_ISR(%r29))
-	SAVE_CR		(%cr21, PT_IOR(%r29))
-
-	virt_map	rfir
-
-	STREG		%r1,PT_GR1(%r29)	/* save good value after rfir */
-
-	save_general	%r29
-
-	ldo	PT_FR0(%r29), %r25
-	save_fp		%r25
-	
-	loadgp
-
-	copy		%r29, %r25
-
-	bl		handle_interruption, %r2
-	copy		%r29, %r16
-
-	b		intr_return
-	nop
+dtlb_fault:
+	b               intr_save
+	ldi             15,%r8
 
 	/* Register saving semantics for system calls:
 
@@ -1475,21 +1962,23 @@
 	.endm
 
 	.export sys_fork_wrapper
+	.export child_return
 sys_fork_wrapper:
 	ldo	TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1	/* get pt regs */
 	reg_save %r1
+	mfctl	%cr27, %r3
+	STREG	%r3, PT_CR27(%r1)
 
 	STREG	%r2,-RP_OFFSET(%r30)
 	ldo	FRAME_SIZE(%r30),%r30
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#endif
 
 	/* These are call-clobbered registers and therefore
 	   also syscall-clobbered (we hope). */
 	STREG	%r2,PT_GR19(%r1)	/* save for child */
-	STREG	%r30,PT_GR20(%r1)
-	ldil	L%child_return, %r3
-	ldo	R%child_return(%r3), %r3
-	LDIL_FIXUP(%r3)
-	STREG	%r3,PT_GR21(%r1)	/* save for child */
+	STREG	%r30,PT_GR21(%r1)
 
 	LDREG	PT_GR30(%r1),%r25
 	copy	%r1,%r24
@@ -1501,14 +1990,21 @@
 	ldo	-FRAME_SIZE(%r30),%r30		/* get the stackframe */
 	ldo	TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1    /* get pt regs */
 
+	LDREG	PT_CR27(%r1), %r3
+	mtctl	%r3, %cr27
 	reg_restore %r1
 
+	/* strace expects syscall # to be preserved in r20 */
+	ldi	__NR_fork,%r20
 	bv %r0(%r2)
-	nop
+	STREG	%r20,PT_GR20(%r1)
 
 	/* Set the return value for the child */
 child_return:
-	LDREG	TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2
+	bl	schedule_tail, %r2
+	nop
+
+	LDREG	TASK_PT_GR19-TASK_SZ_ALGN-FRAME_SIZE-FRAME_SIZE(%r30),%r2
 	b	wrapper_exit
 	copy	%r0,%r28
 
@@ -1517,35 +2013,38 @@
 sys_clone_wrapper:
 	ldo	TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1	/* get pt regs */
 	reg_save %r1
+	mfctl	%cr27, %r3
+	STREG	%r3, PT_CR27(%r1)
 
 	STREG	%r2,-RP_OFFSET(%r30)
 	ldo	FRAME_SIZE(%r30),%r30
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#endif
 
-	STREG	%r30,PT_GR20(%r1)
-	ldil	L%child_return,%r3
-	ldo	R%child_return(%r3),%r3
-	LDIL_FIXUP(%r3)
-
+	STREG	%r2,PT_GR19(%r1)	/* save for child */
+	STREG	%r30,PT_GR21(%r1)
 	bl	sys_clone,%r2
-	STREG	%r3,PT_GR21(%r1)	/* save for child */
+	copy	%r1,%r24
 
 	b	wrapper_exit
 	LDREG	-RP_OFFSET-FRAME_SIZE(%r30),%r2
 
-
 	.export sys_vfork_wrapper
 sys_vfork_wrapper:
 	ldo	TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1	/* get pt regs */
 	reg_save %r1
+	mfctl	%cr27, %r3
+	STREG	%r3, PT_CR27(%r1)
 
 	STREG	%r2,-RP_OFFSET(%r30)
 	ldo	FRAME_SIZE(%r30),%r30
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#endif
 
-	STREG	%r30,PT_GR20(%r1)
-	ldil	L%child_return,%r3
-	ldo	R%child_return(%r3),%r3
-	LDIL_FIXUP(%r3)
-	STREG	%r3,PT_GR21(%r1)	/* save for child */
+	STREG	%r2,PT_GR19(%r1)	/* save for child */
+	STREG	%r30,PT_GR21(%r1)
 
 	bl	sys_vfork,%r2
 	copy	%r1,%r26
@@ -1567,6 +2066,9 @@
 
 	STREG %r2,-RP_OFFSET(%r30)
 	ldo FRAME_SIZE(%r30),%r30
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#endif
 	bl \execve,%r2
 	copy %r1,%arg0
 
@@ -1576,7 +2078,7 @@
 	/* If exec succeeded we need to load the args */
 
 	ldo -1024(%r0),%r1
-	comb,>>= %r28,%r1,error_\execve
+	cmpb,>>= %r28,%r1,error_\execve
 	copy %r2,%r19
 
 error_\execve:
@@ -1603,8 +2105,14 @@
 	ldo	TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30), %r26
 	/* Don't save regs, we are going to restore them from sigcontext. */
 	STREG	%r2, -RP_OFFSET(%r30)
+#ifdef __LP64__
+	ldo	FRAME_SIZE(%r30), %r30
+	bl	sys_rt_sigreturn,%r2
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#else
 	bl	sys_rt_sigreturn,%r2
 	ldo	FRAME_SIZE(%r30), %r30
+#endif
 
 	ldo	-FRAME_SIZE(%r30), %r30
 	LDREG	-RP_OFFSET(%r30), %r2
@@ -1625,22 +2133,50 @@
 	/* Get the user stack pointer */
 	LDREG	-TASK_SZ_ALGN-FRAME_SIZE+TASK_PT_GR30(%r30), %r24
 	STREG	%r2, -RP_OFFSET(%r30)
+#ifdef __LP64__
+	ldo	FRAME_SIZE(%r30), %r30
+	bl	do_sigaltstack,%r2
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#else
 	bl	do_sigaltstack,%r2
 	ldo	FRAME_SIZE(%r30), %r30
+#endif
 
 	ldo	-FRAME_SIZE(%r30), %r30
 	LDREG	-RP_OFFSET(%r30), %r2
 	bv	%r0(%r2)
 	nop
 
+#ifdef __LP64__
+	.export sys32_sigaltstack_wrapper
+sys32_sigaltstack_wrapper:
+	/* Get the user stack pointer */
+	LDREG	-TASK_SZ_ALGN-FRAME_SIZE+TASK_PT_GR30(%r30), %r24
+	STREG	%r2, -RP_OFFSET(%r30)
+	ldo	FRAME_SIZE(%r30), %r30
+	bl	do_sigaltstack32,%r2
+	ldo	-16(%r30),%r29		/* Reference param save area */
+
+	ldo	-FRAME_SIZE(%r30), %r30
+	LDREG	-RP_OFFSET(%r30), %r2
+	bv	%r0(%r2)
+	nop
+#endif
+
 	.export sys_rt_sigsuspend_wrapper
 sys_rt_sigsuspend_wrapper:
 	ldo	TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30), %r24
 	reg_save %r24
 
 	STREG	%r2, -RP_OFFSET(%r30)
+#ifdef __LP64__
+	ldo	FRAME_SIZE(%r30), %r30
+	bl	sys_rt_sigsuspend,%r2
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#else
 	bl	sys_rt_sigsuspend,%r2
 	ldo	FRAME_SIZE(%r30), %r30
+#endif
 
 	ldo	-FRAME_SIZE(%r30), %r30
 	LDREG	-RP_OFFSET(%r30), %r2
@@ -1658,66 +2194,80 @@
 	   values. */
 	/* NOTE: Not all syscalls exit this way.  rt_sigreturn will exit
 	 * via syscall_exit_rfi if the signal was received while the process
-	 * was running.  All traced processes will probably exit via
-	 * syscall_exit_rfi in the future.
+	 * was running.
 	 */
 
 	/* save return value now */
 
 	STREG     %r28,TASK_PT_GR28-TASK_SZ_ALGN-FRAME_SIZE(%r30)
 
+	/* Save other hpux returns if personality is PER_HPUX */
+
+#define PER_HPUX 0xe /* <linux/personality.h> cannot be easily included */
+
+	LDREG     TASK_PERSONALITY-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r19
+	CMPIB<>,n PER_HPUX,%r19,1f
+	STREG     %r22,TASK_PT_GR22-TASK_SZ_ALGN-FRAME_SIZE(%r30)
+	STREG     %r29,TASK_PT_GR29-TASK_SZ_ALGN-FRAME_SIZE(%r30)
+1:
+
+	/* Seems to me that dp could be wrong here, if the syscall involved
+	 * calling a module, and nothing got round to restoring dp on return.
+	 */
+	loadgp
+
 syscall_check_bh:
 
-/* #ifdef NOTNOW */
 	/* Check for software interrupts */
 
 	.import irq_stat,data
 
 	ldil    L%irq_stat,%r19
 	ldo     R%irq_stat(%r19),%r19
-	LDIL_FIXUP(%r19)
 
 #ifdef CONFIG_SMP
 	/* sched.h: int processor */
-	ldw     TASK_PROCESSOR-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r20 /* get cpu # */
-#if (IRQSTAT_SZ == 32)
-	dep     %r20,26,27,%r20 /* shift left 5 bits */
-#else
-#error IRQSTAT_SZ changed, fix dep
-#endif /* IRQSTAT_SZ */
-	add     %r19,%r20,%r19
-#endif /* CONFIG_SMP */
+	/* %r26 is used as scratch register to index into irq_stat[] */
+	ldw     TASK_PROCESSOR-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */
 
-	ldw     IRQSTAT_SI_ACTIVE(%r19),%r20	/* hardirq.h: unsigned int */
-	ldw     IRQSTAT_SI_MASK(%r19),%r19	/* hardirq.h: unsigned int */
-	and     %r19,%r20,%r20
-	comib,<>,n 0,%r20,syscall_do_softirq /* forward */
-/* #endif */
+	/* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */
+#ifdef __LP64__
+	shld	%r26, 6, %r20
+#else
+	shlw	%r26, 5, %r20
+#endif
+	add     %r19,%r20,%r19	/* now have &irq_stat[smp_processor_id()] */
+#endif /* CONFIG_SMP */
 
+	LDREG   IRQSTAT_SIRQ_PEND(%r19),%r20    /* hardirq.h: unsigned long */
+	cmpib,<>,n 0,%r20,syscall_do_softirq /* forward */
 
 syscall_check_resched:
 
 	/* check for reschedule */
 
 	LDREG  TASK_NEED_RESCHED-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r19	/* long */
-	comib,<>,n 0,%r19,syscall_do_resched /* forward */
+	CMPIB<>,n 0,%r19,syscall_do_resched /* forward */
 
 syscall_check_sig:
 	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1         /* get task ptr */
 	/* check for pending signals */
 	ldw     TASK_SIGPENDING(%r1),%r19
-	comib,<>,n 0,%r19,syscall_do_signal  /* forward */
+	cmpib,<>,n 0,%r19,syscall_do_signal  /* forward */
 
 syscall_restore:
-	/* disable interrupts while dicking with the kernel stack, */
-	/* or life can become unpleasant */
-	rsm	PSW_SM_I, %r20
 	LDREG	TASK_PTRACE(%r1), %r19		/* Are we being ptraced? */
 	bb,<,n	%r19,31,syscall_restore_rfi
-	LDREG	TASK_PT_GR20(%r1),%r19
-	mtctl	%r19, %cr27
+
+	ldo	TASK_PT_FR31(%r1),%r19		   /* reload fpregs */
+	rest_fp	%r19
+
+	LDREG	TASK_PT_SAR(%r1),%r19		   /* restore SAR */
+	mtsar	%r19
 
 	LDREG	TASK_PT_GR2(%r1),%r2		   /* restore user rp */
+	LDREG	TASK_PT_GR19(%r1),%r19
+	LDREG   TASK_PT_GR20(%r1),%r20
 	LDREG	TASK_PT_GR21(%r1),%r21
 	LDREG	TASK_PT_GR22(%r1),%r22
 	LDREG	TASK_PT_GR23(%r1),%r23
@@ -1727,43 +2277,31 @@
 	LDREG	TASK_PT_GR27(%r1),%r27	   /* restore user dp */
 	LDREG	TASK_PT_GR28(%r1),%r28	   /* syscall return value */
 	LDREG	TASK_PT_GR29(%r1),%r29
-	LDREG	TASK_PT_GR30(%r1),%r30	   /* restore user sp */
 	LDREG	TASK_PT_GR31(%r1),%r31	   /* restore syscall rp */
-	ldo	TASK_PT_FR31(%r1),%r19		   /* reload fpregs */
-	rest_fp	%r19
-	LDREG	TASK_PT_SAR(%r1),%r19		   /* restore SAR */
-	mtsar	%r19
-	LDREG	TASK_PT_GR19(%r1),%r19
 
-	mtctl	%r1,%cr30			   /* intrhandler okay. */
+	rsm     PSW_SM_I, %r0
+	LDREG   TASK_PT_GR30(%r1),%r30             /* restore user sp */
 	mfsp	%sr3,%r1			   /* Get users space id */
+	mtsp    %r1,%sr7                           /* Restore sr7 */
+	ssm     PSW_SM_I, %r0
 	mtsp	%r1,%sr4			   /* Restore sr4 */
 	mtsp	%r1,%sr5			   /* Restore sr5 */
 	mtsp	%r1,%sr6			   /* Restore sr6 */
 
 	depi	3,31,2,%r31			   /* ensure return to user mode. */
 
-	mtsm	%r20				   /* restore irq state  */
-	mfctl	%cr27,%r20
-	
-	/*
-	 * Due to a dependency in the tlb miss handlers on sr7, it
-	 * is essential that sr7 get set in the delay slot.
-	 */
-
 #ifdef __LP64__
-
-	/* Note the be (and mtsp) is executed in narrow mode. This is OK
-	 * for 32 bit processes, but won't work once we support 64 bit
-	 * processes.
+	/* Since we are returning to a 32 bit user process, we always
+	 * clear the W bit. This means that the be (and mtsp) gets
+	 * executed in narrow mode, but that is OK, since we are
+	 * returning to a 32 bit process. When we support 64 bit processes
+	 * we won't clear the W bit, so the be will run in wide mode.
 	 */
 
-	rsm	PSW_SM_W, %r0
 	be	0(%sr3,%r31)			   /* return to user space */
-	mtsp	%r1,%sr7			   /* Restore sr7 */
+	rsm	PSW_SM_W, %r0
 #else
-	be	0(%sr3,%r31)			   /* return to user space */
-	mtsp	%r1,%sr7			   /* Restore sr7 */
+	be,n    0(%sr3,%r31)                       /* return to user space */
 #endif
 
 	/* We have to return via an RFI, so that PSW T and R bits can be set
@@ -1774,43 +2312,52 @@
 syscall_restore_rfi:
 	ldo	-1(%r0),%r2			   /* Set recovery cntr to -1 */
 	mtctl	%r2,%cr0			   /*   for immediate trap */
-	copy	%r0,%r2				   /* Create a reasonable PSW */
+	LDREG	TASK_PT_PSW(%r1),%r2		   /* Get old PSW */
+	ldi	0x0b,%r20			   /* Create new PSW */
+	depi	-1,13,1,%r20			   /* C, Q, D, and I bits */
+	bb,>=,n	%r19,15,try_tbit		   /* PT_SINGLESTEP */
+	depi	-1,27,1,%r20			   /* R bit */
+try_tbit:
+	bb,>=,n	%r19,14,psw_setup		   /* PT_BLOCKSTEP, see ptrace.c */
+	depi	-1,7,1,%r20			   /* T bit */
+psw_setup:
+	STREG	%r20,TASK_PT_PSW(%r1)
+
+	/* Always store space registers, since sr3 can be changed (e.g. fork) */
+
+	mfsp    %sr3,%r25
+	STREG   %r25,TASK_PT_SR3(%r1)
+	STREG   %r25,TASK_PT_SR4(%r1)
+	STREG   %r25,TASK_PT_SR5(%r1)
+	STREG   %r25,TASK_PT_SR6(%r1)
+	STREG   %r25,TASK_PT_SR7(%r1)
+	STREG   %r25,TASK_PT_IASQ0(%r1)
+	STREG   %r25,TASK_PT_IASQ1(%r1)
+
 	/* XXX W bit??? */
-	depi	-1,13,1,%r2
-	depi	-1,28,1,%r2
-	depi	-1,30,1,%r2
-	depi	-1,31,1,%r2
-	bb,<,n	%r19,15,set_rbit		   /* PT_SINGLESTEP */
-	bb,>=,n	%r19,14,set_nobit		   /* PT_BLOCKSTEP, see ptrace.c */
-set_tbit:
-	depi	-1,7,1,%r2
-	b,n	set_nobit
-set_rbit:
-	depi	-1,27,1,%r2
-set_nobit:
-	STREG	%r2,TASK_PT_PSW(%r1)
-	STREG	%r1,TASK_PT_CR30(%r1)
+	/* Now if old D bit is clear, it means we didn't save all registers
+	 * on syscall entry, so do that now.  This only happens on TRACEME
+	 * calls, or if someone attached to us while we were on a syscall.
+	 * We could make this more efficient by not saving r3-r18, but
+	 * then we wouldn't be able to use the common intr_restore path.
+	 * It is only for traced processes anyway, so performance is not
+	 * an issue.
+	 */
+	bb,<	%r2,30,pt_regs_ok		   /* Branch if D set */
+	ldo	TASK_REGS(%r1),%r25
+	reg_save %r25				   /* Save r3 to r18 */
 	mfsp	%sr0,%r2
 	STREG	%r2,TASK_PT_SR0(%r1)
 	mfsp	%sr1,%r2
 	STREG	%r2,TASK_PT_SR1(%r1)
 	mfsp	%sr2,%r2
 	STREG	%r2,TASK_PT_SR2(%r1)
-	mfsp	%sr3,%r2
-	STREG	%r2,TASK_PT_SR3(%r1)
-	STREG	%r2,TASK_PT_SR4(%r1)
-	STREG	%r2,TASK_PT_SR5(%r1)
-	STREG	%r2,TASK_PT_SR6(%r1)
-	STREG	%r2,TASK_PT_SR7(%r1)
-	STREG	%r2,TASK_PT_IASQ0(%r1)
-	STREG	%r2,TASK_PT_IASQ1(%r1)
+pt_regs_ok:
 	LDREG	TASK_PT_GR31(%r1),%r2
 	depi	3,31,2,%r2			   /* ensure return to user mode. */
 	STREG	%r2,TASK_PT_IAOQ0(%r1)
 	ldo	4(%r2),%r2
 	STREG	%r2,TASK_PT_IAOQ1(%r1)
-	ldo	TASK_REGS(%r1),%r25
-	reg_save %r25				   /* Save r3 to r18 */
 	copy	%r25,%r16
 	b	intr_restore
 	nop
@@ -1825,7 +2372,11 @@
 	.import schedule,code
 syscall_do_resched:
 	bl	schedule,%r2
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#else
 	nop
+#endif
 	b       syscall_check_bh  /* if resched, we start over again */
 	nop
 
@@ -1840,6 +2391,9 @@
 
 	ldi	1, %r24				/* unsigned long in_syscall */
 
+#ifdef __LP64__
+	ldo	-16(%r30),%r29			/* Reference param save area */
+#endif
 	bl	do_signal,%r2
 	copy	%r0, %r26			/* sigset_t *oldset = NULL */
 
@@ -1849,19 +2403,155 @@
 
 	b,n     syscall_restore
 
-#ifdef __LP64__
-unimplemented_64bitirq:
-	ssm PSW_SM_Q+PSW_SM_I, %r0
-	/* indicate that we had an interrupt */
-	ldi	0x77, %r28
-	ldi	0x77, %r29
-	/* save interrupt registers in GRs for diagnosis */
-	mfctl %cr17, %r17
-	mfctl %cr18, %r18
-	mfctl %cr19, %r19
-	mfctl %cr20, %r20
-	mfctl %cr21, %r21
-	mfctl %cr22, %r22
-	b,n .
-	nop
-#endif
+	/*
+	 * get_register is used by the non access tlb miss handlers to
+	 * copy the value of the general register specified in r8 into
+	 * r1. This routine can't be used for shadowed registers, since
+	 * the rfir will restore the original value. So, for the shadowed
+	 * registers we put a -1 into r1 to indicate that the register
+	 * should not be used (the register being copied could also have
+	 * a -1 in it, but that is OK, it just means that we will have
+	 * to use the slow path instead).
+	 */
+
+get_register:
+	blr     %r8,%r0
+	nop
+	bv      %r0(%r25)    /* r0 */
+	copy    %r0,%r1
+	bv      %r0(%r25)    /* r1 - shadowed */
+	ldi     -1,%r1
+	bv      %r0(%r25)    /* r2 */
+	copy    %r2,%r1
+	bv      %r0(%r25)    /* r3 */
+	copy    %r3,%r1
+	bv      %r0(%r25)    /* r4 */
+	copy    %r4,%r1
+	bv      %r0(%r25)    /* r5 */
+	copy    %r5,%r1
+	bv      %r0(%r25)    /* r6 */
+	copy    %r6,%r1
+	bv      %r0(%r25)    /* r7 */
+	copy    %r7,%r1
+	bv      %r0(%r25)    /* r8 - shadowed */
+	ldi     -1,%r1
+	bv      %r0(%r25)    /* r9 - shadowed */
+	ldi     -1,%r1
+	bv      %r0(%r25)    /* r10 */
+	copy    %r10,%r1
+	bv      %r0(%r25)    /* r11 */
+	copy    %r11,%r1
+	bv      %r0(%r25)    /* r12 */
+	copy    %r12,%r1
+	bv      %r0(%r25)    /* r13 */
+	copy    %r13,%r1
+	bv      %r0(%r25)    /* r14 */
+	copy    %r14,%r1
+	bv      %r0(%r25)    /* r15 */
+	copy    %r15,%r1
+	bv      %r0(%r25)    /* r16 - shadowed */
+	ldi     -1,%r1
+	bv      %r0(%r25)    /* r17 - shadowed */
+	ldi     -1,%r1
+	bv      %r0(%r25)    /* r18 */
+	copy    %r18,%r1
+	bv      %r0(%r25)    /* r19 */
+	copy    %r19,%r1
+	bv      %r0(%r25)    /* r20 */
+	copy    %r20,%r1
+	bv      %r0(%r25)    /* r21 */
+	copy    %r21,%r1
+	bv      %r0(%r25)    /* r22 */
+	copy    %r22,%r1
+	bv      %r0(%r25)    /* r23 */
+	copy    %r23,%r1
+	bv      %r0(%r25)    /* r24 - shadowed */
+	ldi     -1,%r1
+	bv      %r0(%r25)    /* r25 - shadowed */
+	ldi     -1,%r1
+	bv      %r0(%r25)    /* r26 */
+	copy    %r26,%r1
+	bv      %r0(%r25)    /* r27 */
+	copy    %r27,%r1
+	bv      %r0(%r25)    /* r28 */
+	copy    %r28,%r1
+	bv      %r0(%r25)    /* r29 */
+	copy    %r29,%r1
+	bv      %r0(%r25)    /* r30 */
+	copy    %r30,%r1
+	bv      %r0(%r25)    /* r31 */
+	copy    %r31,%r1
+
+	/*
+	 * set_register is used by the non access tlb miss handlers to
+	 * copy the value of r1 into the general register specified in
+	 * r8.
+	 */
+
+set_register:
+	blr     %r8,%r0
+	nop
+	bv      %r0(%r25)    /* r0 (silly, but it is a place holder) */
+	copy    %r1,%r0
+	bv      %r0(%r25)    /* r1 */
+	copy    %r1,%r1
+	bv      %r0(%r25)    /* r2 */
+	copy    %r1,%r2
+	bv      %r0(%r25)    /* r3 */
+	copy    %r1,%r3
+	bv      %r0(%r25)    /* r4 */
+	copy    %r1,%r4
+	bv      %r0(%r25)    /* r5 */
+	copy    %r1,%r5
+	bv      %r0(%r25)    /* r6 */
+	copy    %r1,%r6
+	bv      %r0(%r25)    /* r7 */
+	copy    %r1,%r7
+	bv      %r0(%r25)    /* r8 */
+	copy    %r1,%r8
+	bv      %r0(%r25)    /* r9 */
+	copy    %r1,%r9
+	bv      %r0(%r25)    /* r10 */
+	copy    %r1,%r10
+	bv      %r0(%r25)    /* r11 */
+	copy    %r1,%r11
+	bv      %r0(%r25)    /* r12 */
+	copy    %r1,%r12
+	bv      %r0(%r25)    /* r13 */
+	copy    %r1,%r13
+	bv      %r0(%r25)    /* r14 */
+	copy    %r1,%r14
+	bv      %r0(%r25)    /* r15 */
+	copy    %r1,%r15
+	bv      %r0(%r25)    /* r16 */
+	copy    %r1,%r16
+	bv      %r0(%r25)    /* r17 */
+	copy    %r1,%r17
+	bv      %r0(%r25)    /* r18 */
+	copy    %r1,%r18
+	bv      %r0(%r25)    /* r19 */
+	copy    %r1,%r19
+	bv      %r0(%r25)    /* r20 */
+	copy    %r1,%r20
+	bv      %r0(%r25)    /* r21 */
+	copy    %r1,%r21
+	bv      %r0(%r25)    /* r22 */
+	copy    %r1,%r22
+	bv      %r0(%r25)    /* r23 */
+	copy    %r1,%r23
+	bv      %r0(%r25)    /* r24 */
+	copy    %r1,%r24
+	bv      %r0(%r25)    /* r25 */
+	copy    %r1,%r25
+	bv      %r0(%r25)    /* r26 */
+	copy    %r1,%r26
+	bv      %r0(%r25)    /* r27 */
+	copy    %r1,%r27
+	bv      %r0(%r25)    /* r28 */
+	copy    %r1,%r28
+	bv      %r0(%r25)    /* r29 */
+	copy    %r1,%r29
+	bv      %r0(%r25)    /* r30 */
+	copy    %r1,%r30
+	bv      %r0(%r25)    /* r31 */
+	copy    %r1,%r31
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/firmware.c linux-2.4.20/arch/parisc/kernel/firmware.c
--- linux-2.4.19/arch/parisc/kernel/firmware.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/firmware.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,1111 @@
+/* arch/parisc/kernel/pdc.c  - safe pdc access routines
+ *
+ * Copyright 1999 SuSE GmbH Nuernberg (Philipp Rumpf, prumpf@tux.org)
+ * portions Copyright 1999 The Puffin Group, (Alex deVries, David Kennedy)
+ *
+ * only these routines should be used out of the real kernel (i.e. everything
+ * using virtual addresses) for obvious reasons */
+
+/*	I think it would be in everyone's best interest to follow this
+ *	guidelines when writing PDC wrappers:
+ *
+ *	 - the name of the pdc wrapper should match one of the macros
+ *	   used for the first two arguments
+ *	 - don't use caps for random parts of the name
+ *	 - use the static PDC result buffers and "copyout" to structs
+ *	   supplied by the caller to encapsulate alignment restrictions
+ *	 - hold pdc_lock while in PDC or using static result buffers
+ *	 - use __pa() to convert virtual (kernel) pointers to physical
+ *	   ones.
+ *	 - the name of the struct used for pdc return values should equal
+ *	   one of the macros used for the first two arguments to the
+ *	   corresponding PDC call
+ *	 - keep the order of arguments
+ *	 - don't be smart (setting trailing NUL bytes for strings, return
+ *	   something useful even if the call failed) unless you are sure
+ *	   it's not going to affect functionality or performance
+ *
+ *	Example:
+ *	int pdc_cache_info(struct pdc_cache_info *cache_info )
+ *	{
+ *		int retval;
+ *
+ *		spin_lock_irq(&pdc_lock);
+ *		retval = mem_pdc_call(PDC_CACHE,PDC_CACHE_INFO,__pa(cache_info),0);
+ *		convert_to_wide(pdc_result);
+ *		memcpy(cache_info, pdc_result, sizeof(*cache_info));
+ *		spin_unlock_irq(&pdc_lock);
+ *
+ *		return retval;
+ *	}
+ *					prumpf	991016	
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/page.h>
+#include <asm/pdc.h>
+#include <asm/system.h>
+#include <asm/processor.h>	/* for boot_cpu_data */
+
+#include <stdarg.h>
+
+static spinlock_t pdc_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long pdc_result[32] __attribute__ ((aligned (8)));
+static unsigned long pdc_result2[32] __attribute__ ((aligned (8)));
+
+/* on all currently-supported platforms, IODC I/O calls are always
+ * 32-bit calls, and MEM_PDC calls are always the same width as the OS.
+ * This means Cxxx boxes can't run wide kernels right now. -PB
+ *
+ * CONFIG_PDC_NARROW has been added to allow 64-bit kernels to run on
+ * systems with 32-bit MEM_PDC calls. This will allow wide kernels to
+ * run on Cxxx boxes now. -RB
+ *
+ * Note that some PAT boxes may have 64-bit IODC I/O...
+ */
+
+#ifdef __LP64__
+static long real64_call(unsigned long function, ...);
+#endif
+static long real32_call(unsigned long function, ...);
+
+#if defined(__LP64__) && ! defined(CONFIG_PDC_NARROW)
+#define MEM_PDC (unsigned long)(PAGE0->mem_pdc_hi) << 32 | PAGE0->mem_pdc
+#   define mem_pdc_call(args...) real64_call(MEM_PDC, args)
+#else
+#define MEM_PDC (unsigned long)PAGE0->mem_pdc
+#   define mem_pdc_call(args...) real32_call(MEM_PDC, args)
+#endif
+
+
+/**
+ * f_extend - Convert PDC addresses to kernel addresses.
+ * @address: Address returned from PDC.
+ *
+ * This function is used to convert PDC addresses into kernel addresses
+ * when the PDC address size and kernel address size are different.
+ */
+static unsigned long f_extend(unsigned long address)
+{
+#ifdef CONFIG_PDC_NARROW
+	if((address & 0xff000000) == 0xf0000000)
+		return 0xf0f0f0f000000000 | (u32)address;
+
+	if((address & 0xf0000000) == 0xf0000000)
+		return 0xffffffff00000000 | (u32)address;
+#endif
+	return address;
+}
+
+/**
+ * convert_to_wide - Convert the return buffer addresses into kernel addresses.
+ * @address: The return buffer from PDC.
+ *
+ * This function is used to convert the return buffer addresses retrieved from PDC
+ * into kernel addresses when the PDC address size and kernel address size are
+ * different.
+ */
+static void convert_to_wide(unsigned long *addr)
+{
+#ifdef CONFIG_PDC_NARROW
+	int i;
+	unsigned *p = (unsigned int *)addr;
+	for(i = 31; i >= 0; --i)
+		addr[i] = p[i];
+#endif
+}
+
+/**
+ * pdc_emergency_unlock - Unlock the linux pdc lock
+ *
+ * This call unlocks the linux pdc lock in case we need some PDC functions
+ * (like pdc_add_valid) during kernel stack dump.
+ */
+void pdc_emergency_unlock(void)
+{
+        spin_unlock(&pdc_lock);
+}
+
+
+/**
+ * pdc_add_valid - Verify address can be accessed without causing a HPMC.
+ * @address: Address to be verified.
+ *
+ * This PDC call attempts to read from the specified address and verifies
+ * if the address is valid.
+ * 
+ * The return value is PDC_OK (0) in case accessing this address is valid.
+ */
+int pdc_add_valid(unsigned long address)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_ADD_VALID, PDC_ADD_VALID_VERIFY, address);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_chassis_info - Return chassis information.
+ * @result: The return buffer.
+ * @chassis_info: The memory buffer address.
+ * @len: The size of the memory buffer address.
+ *
+ * An HVERSION dependent call for returning the chassis information.
+ */
+int __init pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        memcpy(&pdc_result, chassis_info, sizeof(*chassis_info));
+        memcpy(&pdc_result2, led_info, len);
+        retval = mem_pdc_call(PDC_CHASSIS, PDC_RETURN_CHASSIS_INFO,
+                              __pa(pdc_result), __pa(pdc_result2), len);
+        memcpy(chassis_info, pdc_result, sizeof(*chassis_info));
+        memcpy(led_info, pdc_result2, len);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_coproc_cfg - To identify coprocessors attached to the processor.
+ * @pdc_coproc_info: Return buffer address.
+ *
+ * This PDC call returns the presence and status of all the coprocessors
+ * attached to the processor.
+ */
+int __init pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_COPROC, PDC_COPROC_CFG, __pa(pdc_result));
+        convert_to_wide(pdc_result);
+        pdc_coproc_info->ccr_functional = pdc_result[0];
+        pdc_coproc_info->ccr_present = pdc_result[1];
+        pdc_coproc_info->revision = pdc_result[17];
+        pdc_coproc_info->model = pdc_result[18];
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_iodc_read - Read data from the modules IODC.
+ * @actcnt: The actual number of bytes.
+ * @hpa: The HPA of the module for the iodc read.
+ * @index: The iodc entry point.
+ * @iodc_data: A buffer memory for the iodc options.
+ * @iodc_data_size: Size of the memory buffer.
+ *
+ * This PDC call reads from the IODC of the module specified by the hpa
+ * argument.
+ */
+int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index,
+		  void *iodc_data, unsigned int iodc_data_size)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_IODC, PDC_IODC_READ, __pa(pdc_result), hpa, 
+			      index, __pa(pdc_result2), iodc_data_size);
+	convert_to_wide(pdc_result);
+	*actcnt = pdc_result[0];
+	memcpy(iodc_data, pdc_result2, iodc_data_size);
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
+ * pdc_system_map_find_mods - Locate unarchitected modules.
+ * @pdc_mod_info: Return buffer address.
+ * @mod_path: pointer to dev path structure.
+ * @mod_index: fixed address module index.
+ *
+ * To locate and identify modules which reside at fixed I/O addresses, which
+ * do not self-identify via architected bus walks.
+ */
+int pdc_system_map_find_mods(struct pdc_system_map_mod_info *pdc_mod_info,
+			     struct pdc_module_path *mod_path, long mod_index)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE, __pa(pdc_result), 
+			      __pa(pdc_result2), mod_index);
+	convert_to_wide(pdc_result);
+	memcpy(pdc_mod_info, pdc_result, sizeof(*pdc_mod_info));
+	memcpy(mod_path, pdc_result2, sizeof(*mod_path));
+	spin_unlock_irq(&pdc_lock);
+
+	pdc_mod_info->mod_addr = f_extend(pdc_mod_info->mod_addr);
+	return retval;
+}
+
+/**
+ * pdc_system_map_find_addrs - Retrieve additional address ranges.
+ * @pdc_addr_info: Return buffer address.
+ * @mod_index: Fixed address module index.
+ * @addr_index: Address range index.
+ * 
+ * Retrieve additional information about subsequent address ranges for modules
+ * with multiple address ranges.  
+ */
+int pdc_system_map_find_addrs(struct pdc_system_map_addr_info *pdc_addr_info, 
+			      long mod_index, long addr_index)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_ADDRESS, __pa(pdc_result),
+			      mod_index, addr_index);
+	convert_to_wide(pdc_result);
+	memcpy(pdc_addr_info, pdc_result, sizeof(*pdc_addr_info));
+	spin_unlock_irq(&pdc_lock);
+
+	pdc_addr_info->mod_addr = f_extend(pdc_addr_info->mod_addr);
+	return retval;
+}
+
+/**
+ * pdc_model_info - Return model information about the processor.
+ * @model: The return buffer.
+ *
+ * Returns the version numbers, identifiers, and capabilities from the processor module.
+ */
+int pdc_model_info(struct pdc_model *model) 
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_INFO, __pa(pdc_result), 0);
+	convert_to_wide(pdc_result);
+	memcpy(model, pdc_result, sizeof(*model));
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
+ * pdc_model_sysmodel - Get the system model name.
+ * @name: A char array of at least 81 characters.
+ *
+ * Get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L)
+ */
+int pdc_model_sysmodel(char *name)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_SYSMODEL, __pa(pdc_result),
+                              OS_ID_HPUX, __pa(name));
+        convert_to_wide(pdc_result);
+
+        if (retval == PDC_OK) {
+                name[pdc_result[0]] = '\0'; /* add trailing '\0' */
+        } else {
+                name[0] = 0;
+        }
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_model_versions - Identify the version number of each processor.
+ * @cpu_id: The return buffer.
+ * @id: The id of the processor to check.
+ *
+ * Returns the version number for each processor component.
+ *
+ * This comment was here before, but I do not know what it means :( -RB
+ * id: 0 = cpu revision, 1 = boot-rom-version
+ */
+int pdc_model_versions(unsigned long *versions, int id)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_VERSIONS, __pa(pdc_result), id);
+        convert_to_wide(pdc_result);
+        *versions = pdc_result[0];
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_model_cpuid - Returns the CPU_ID.
+ * @cpu_id: The return buffer.
+ *
+ * Returns the CPU_ID value which uniquely identifies the cpu portion of
+ * the processor module.
+ */
+int pdc_model_cpuid(unsigned long *cpu_id)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        pdc_result[0] = 0; /* preset zero (call may not be implemented!) */
+        retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CPU_ID, __pa(pdc_result), 0);
+        convert_to_wide(pdc_result);
+        *cpu_id = pdc_result[0];
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_model_capabilities - Returns the platform capabilities.
+ * @capabilities: The return buffer.
+ *
+ * Returns information about platform support for 32- and/or 64-bit
+ * OSes, IO-PDIR coherency, and virtual aliasing.
+ */
+int pdc_model_capabilities(unsigned long *capabilities)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        pdc_result[0] = 0; /* preset zero (call may not be implemented!) */
+        retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES, __pa(pdc_result), 0);
+        convert_to_wide(pdc_result);
+        *capabilities = pdc_result[0];
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_cache_info - Return cache and TLB information.
+ * @cache_info: The return buffer.
+ *
+ * Returns information about the processor's cache and TLB.
+ */
+int pdc_cache_info(struct pdc_cache_info *cache_info)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_CACHE, PDC_CACHE_INFO, __pa(pdc_result), 0);
+        convert_to_wide(pdc_result);
+        memcpy(cache_info, pdc_result, sizeof(*cache_info));
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+#ifndef CONFIG_PA20
+/**
+ * pdc_btlb_info - Return block TLB information.
+ * @btlb: The return buffer.
+ *
+ * Returns information about the hardware Block TLB.
+ */
+int pdc_btlb_info(struct pdc_btlb_info *btlb) 
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_BLOCK_TLB, PDC_BTLB_INFO, __pa(pdc_result), 0);
+        memcpy(btlb, pdc_result, sizeof(*btlb));
+        spin_unlock_irq(&pdc_lock);
+
+        if(retval < 0) {
+                btlb->max_size = 0;
+        }
+        return retval;
+}
+
+/**
+ * pdc_mem_map_hpa - Find fixed module information.  
+ * @address: The return buffer
+ * @mod_path: pointer to dev path structure.
+ *
+ * This call was developed for S700 workstations to allow the kernel to find
+ * the I/O devices (Core I/O). In the future (Kittyhawk and beyond) this
+ * call will be replaced (on workstations) by the architected PDC_SYSTEM_MAP
+ * call.
+ *
+ * This call is supported by all existing S700 workstations (up to  Gecko).
+ */
+int pdc_mem_map_hpa(struct pdc_memory_map *address,
+		struct pdc_module_path *mod_path)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        memcpy(pdc_result2, mod_path, sizeof(*mod_path));
+        retval = mem_pdc_call(PDC_MEM_MAP, PDC_MEM_MAP_HPA, __pa(pdc_result),
+				__pa(pdc_result2));
+        memcpy(address, pdc_result, sizeof(*address));
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+#endif	/* !CONFIG_PA20 */
+
+/**
+ * pdc_lan_station_id - Get the LAN address.
+ * @lan_addr: The return buffer.
+ * @hpa: The network device HPA.
+ *
+ * Get the LAN station address when it is not directly available from the LAN hardware.
+ */
+int pdc_lan_station_id(char *lan_addr, unsigned long hpa)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_LAN_STATION_ID, PDC_LAN_STATION_ID_READ,
+			__pa(pdc_result), hpa);
+	if (retval < 0) {
+		/* FIXME: else read MAC from NVRAM */
+		memset(lan_addr, 0, PDC_LAN_STATION_ID_SIZE);
+	} else {
+		memcpy(lan_addr, pdc_result, PDC_LAN_STATION_ID_SIZE);
+	}
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+
+/**
+ * pdc_get_initiator - Get the SCSI Interface Card params (SCSI ID, SDTR, SE or LVD)
+ * @hwpath: fully bc.mod style path to the device.
+ * @scsi_id: what someone told firmware the ID should be.
+ * @period: time in cycles 
+ * @width: 8 or 16-bit wide bus
+ * @mode: 0,1,2 -> SE,HVD,LVD signalling mode
+ *
+ * Get the SCSI operational parameters from PDC.
+ * Needed since HPUX never used BIOS or symbios card NVRAM.
+ * Most ncr/sym cards won't have an entry and just use whatever
+ * capabilities of the card are (eg Ultra, LVD). But there are
+ * several cases where it's useful:
+ *    o set SCSI id for Multi-initiator clusters,
+ *    o cable too long (ie SE scsi 10Mhz won't support 6m length),
+ *    o bus width exported is less than what the interface chip supports.
+ */
+int pdc_get_initiator( struct hardware_path *hwpath, unsigned char *scsi_id,
+	unsigned long *period, char *width, char *mode)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+
+/* BCJ-XXXX series boxes. E.G. "9000/785/C3000" */
+#define IS_SPROCKETS() (strlen(boot_cpu_data.pdc.sys_model_name) == 14 && \
+	strncmp(boot_cpu_data.pdc.sys_model_name, "9000/785", 9) == 0)
+
+	retval = mem_pdc_call(PDC_INITIATOR, PDC_GET_INITIATOR, 
+			      __pa(pdc_result), __pa(hwpath));
+
+
+	if (retval >= PDC_OK) {
+		*scsi_id = (unsigned char) pdc_result[0];
+
+		/* convert Bus speed in Mhz to period (in 1/10 ns) */
+		switch(pdc_result[1]) {
+		/*
+		** case  0:   driver determines rate
+		** case -1:   Settings are uninitialized.
+		*/
+		case  5:  *period = 2000; break;
+		case 10:  *period = 1000; break;
+		case 20:  *period = 500; break;
+		case 40:  *period = 250; break;
+		default: /* Do nothing */ break;
+		}
+
+		/* 
+		** pdc_result[2]	PDC suggested SCSI id
+		** pdc_result[3]	PDC suggested SCSI rate
+		*/
+
+		if (IS_SPROCKETS()) {
+			/*
+			** Revisit: PAT PDC do the same thing?
+			** A500 also exports 50-pin SE SCSI.
+			**	0 == 8-bit
+			**	1 == 16-bit
+			*/
+			*width = (char) pdc_result[4];
+
+			/* ...in case someone needs it in the future.
+			** sym53c8xx.c comments say it can't autodetect
+			** for 825/825A/875 chips.
+			**	0 == SE, 1 == HVD, 2 == LVD
+			*/
+			*mode = (char) pdc_result[5]; 
+		}
+	}
+
+	spin_unlock_irq(&pdc_lock);
+	return retval >= PDC_OK;
+}
+
+
+/**
+ * pdc_pci_irt_size - Get the number of entries in the interrupt routing table.
+ * @num_entries: The return value.
+ * @hpa: The HPA for the device.
+ *
+ * This PDC function returns the number of entries in the specified cell's
+ * interrupt table.
+ * Similar to PDC_PAT stuff - but added for Forte/Allegro boxes
+ */ 
+int pdc_pci_irt_size(unsigned long *num_entries, unsigned long hpa)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SIZE, 
+			      __pa(pdc_result), hpa);
+	convert_to_wide(pdc_result);
+	*num_entries = pdc_result[0];
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/** 
+ * pdc_pci_irt - Get the PCI interrupt routing table.
+ * @num_entries: The number of entries in the table.
+ * @hpa: The Hard Physical Address of the device.
+ * @tbl: 
+ *
+ * Get the PCI interrupt routing table for the device at the given HPA.
+ * Similar to PDC_PAT stuff - but added for Forte/Allegro boxes
+ */
+int pdc_pci_irt(unsigned long num_entries, unsigned long hpa, void *tbl)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	pdc_result[0] = num_entries;
+	retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL, 
+			      __pa(pdc_result), hpa, __pa(tbl));
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+
+/**
+ * pdc_tod_read - Read the Time-Of-Day clock.
+ * @tod: The return buffer:
+ *
+ * Read the Time-Of-Day clock
+ */
+int pdc_tod_read(struct pdc_tod *tod)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_TOD, PDC_TOD_READ, __pa(pdc_result), 0);
+        convert_to_wide(pdc_result);
+        memcpy(tod, pdc_result, sizeof(*tod));
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_tod_set - Set the Time-Of-Day clock.
+ * @sec: The number of seconds since epoch.
+ * @usec: The number of micro seconds.
+ *
+ * Set the Time-Of-Day clock.
+ */ 
+int pdc_tod_set(unsigned long sec, unsigned long usec)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_TOD, PDC_TOD_WRITE, sec, usec);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+#ifdef __LP64__
+int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr,
+		struct pdc_memory_table *tbl, unsigned long entries)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_MEM, PDC_MEM_TABLE, __pa(pdc_result), __pa(pdc_result2), entries);
+	convert_to_wide(pdc_result);
+	memcpy(r_addr, pdc_result, sizeof(*r_addr));
+	memcpy(tbl, pdc_result2, entries * sizeof(*tbl));
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+#endif /* __LP64__ */
+
+/* FIXME: Is this pdc used?  I could not find type reference to ftc_bitmap
+ * so I guessed at unsigned long.  Someone who knows what this does, can fix
+ * it later. :)
+ */
+int pdc_do_firm_test_reset(unsigned long ftc_bitmap)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_FIRM_TEST_RESET,
+                              PDC_FIRM_TEST_MAGIC, ftc_bitmap);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/*
+ * pdc_do_reset - Reset the system.
+ *
+ * Reset the system.
+ */
+int pdc_do_reset()
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_RESET);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/*
+ * pdc_soft_power_info - Enable soft power switch.
+ * @power_reg: address of soft power register
+ *
+ * Return the absolute address of the soft power switch register
+ */
+int __init pdc_soft_power_info(unsigned long *power_reg)
+{
+	int retval;
+
+	*power_reg = (unsigned long) (-1);
+	
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_INFO, __pa(pdc_result), 0);
+	if (retval == PDC_OK) {
+                convert_to_wide(pdc_result);
+                *power_reg = f_extend(pdc_result[0]);
+	}
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/*
+ * pdc_soft_power_button - Control the soft power button behaviour
+ * @sw_control: 0 for hardware control, 1 for software control 
+ *
+ *
+ * This PDC function places the soft power button under software or
+ * hardware control.
+ * Under software control the OS may control to when to allow to shut 
+ * down the system. Under hardware control pressing the power button 
+ * powers off the system immediately.
+ */
+int pdc_soft_power_button(int sw_control)
+{
+	int retval;
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_ENABLE, __pa(pdc_result), sw_control);
+	spin_unlock_irq(&pdc_lock);
+	return retval;
+}
+
+/*
+ * pdc_suspend_usb - Stop USB controller
+ *
+ * If PDC used the usb controller, the usb controller
+ * is still running and will crash the machines during iommu 
+ * setup, because of still running DMA. This PDC call
+ * stops the USB controller
+ */
+void pdc_suspend_usb(void)
+{
+	spin_lock_irq(&pdc_lock);  
+	mem_pdc_call(PDC_IO, PDC_IO_SUSPEND_USB, 0);
+	spin_unlock_irq(&pdc_lock);
+}
+
+/**
+ * pdc_iodc_putc - Console character print using IODC.
+ * @c: the character to output.
+ *
+ * Note that only these special chars are architected for console IODC io:
+ * BEL, BS, CR, and LF. Others are passed through.
+ * Since the HP console requires CR+LF to perform a 'newline', we translate
+ * "\n" to "\r\n".
+ */
+void pdc_iodc_putc(unsigned char c)
+{
+        /* XXX Should we spinlock posx usage */
+        static int posx;        /* for simple TAB-Simulation... */
+        static int __attribute__((aligned(8)))   iodc_retbuf[32];
+        static char __attribute__((aligned(64))) iodc_dbuf[4096];
+        unsigned int n;
+	unsigned int flags;
+
+        switch (c) {
+        case '\n':
+                iodc_dbuf[0] = '\r';
+                iodc_dbuf[1] = '\n';
+                n = 2;
+                posx = 0;
+                break;
+        case '\t':
+                pdc_iodc_putc(' ');
+                while (posx & 7)        /* expand TAB */
+                        pdc_iodc_putc(' ');
+                return;         /* return since IODC can't handle this */
+        case '\b':
+                posx-=2;                /* BS */
+        default:
+                iodc_dbuf[0] = c;
+                n = 1;
+                posx++;
+                break;
+        }
+
+        spin_lock_irqsave(&pdc_lock, flags);
+        real32_call(PAGE0->mem_cons.iodc_io,
+                    (unsigned long)PAGE0->mem_cons.hpa, ENTRY_IO_COUT,
+                    PAGE0->mem_cons.spa, __pa(PAGE0->mem_cons.dp.layers),
+                    __pa(iodc_retbuf), 0, __pa(iodc_dbuf), n, 0);
+        spin_unlock_irqrestore(&pdc_lock, flags);
+}
+
+/**
+ * pdc_iodc_outc - Console character print using IODC (without conversions).
+ * @c: the character to output.
+ *
+ * Write the character directly to the IODC console.
+ */
+void pdc_iodc_outc(unsigned char c)
+{
+	unsigned int n, flags;
+
+	/* fill buffer with one caracter and print it */
+        static int __attribute__((aligned(8)))   iodc_retbuf[32];
+        static char __attribute__((aligned(64))) iodc_dbuf[4096];
+
+	n = 1;
+	iodc_dbuf[0] = c;
+
+	spin_lock_irqsave(&pdc_lock, flags);
+	real32_call(PAGE0->mem_cons.iodc_io,
+		    (unsigned long)PAGE0->mem_cons.hpa, ENTRY_IO_COUT,
+		    PAGE0->mem_cons.spa, __pa(PAGE0->mem_cons.dp.layers),
+		    __pa(iodc_retbuf), 0, __pa(iodc_dbuf), n, 0);
+	spin_unlock_irqrestore(&pdc_lock, flags);
+}
+
+/**
+ * pdc_iodc_getc - Read a character (non-blocking) from the PDC console.
+ *
+ * Read a character (non-blocking) from the PDC console, returns -1 if
+ * key is not present.
+ */
+int pdc_iodc_getc(void)
+{
+	unsigned int flags;
+        static int __attribute__((aligned(8)))   iodc_retbuf[32];
+        static char __attribute__((aligned(64))) iodc_dbuf[4096];
+	int ch;
+	int status;
+
+	/* Bail if no console input device. */
+	if (!PAGE0->mem_kbd.iodc_io)
+		return 0;
+	
+	/* wait for a keyboard (rs232)-input */
+	spin_lock_irqsave(&pdc_lock, flags);
+	real32_call(PAGE0->mem_kbd.iodc_io,
+		    (unsigned long)PAGE0->mem_kbd.hpa, ENTRY_IO_CIN,
+		    PAGE0->mem_kbd.spa, __pa(PAGE0->mem_kbd.dp.layers), 
+		    __pa(iodc_retbuf), 0, __pa(iodc_dbuf), 1, 0);
+
+	ch = *iodc_dbuf;
+	status = *iodc_retbuf;
+	spin_unlock_irqrestore(&pdc_lock, flags);
+
+	if (status == 0)
+	    return -1;
+	
+	return ch;
+}
+
+int pdc_sti_call(unsigned long func, unsigned long flags,
+                 unsigned long inptr, unsigned long outputr,
+                 unsigned long glob_cfg)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);  
+        retval = real32_call(func, flags, inptr, outputr, glob_cfg);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+#ifdef __LP64__
+/**
+ * pdc_pat_cell_get_number - Returns the cell number.
+ * @cell_info: The return buffer.
+ *
+ * This PDC call returns the cell number of the cell from which the call
+ * is made.
+ */
+int pdc_pat_cell_get_number(struct pdc_pat_cell_num *cell_info)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_GET_NUMBER, __pa(pdc_result));
+	memcpy(cell_info, pdc_result, sizeof(*cell_info));
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
+ * pdc_pat_cell_module - Retrieve the cell's module information.
+ * @actcnt: The number of bytes written to mem_addr.
+ * @ploc: The physical location.
+ * @mod: The module index.
+ * @view_type: The view of the address type.
+ * @mem_addr: The return buffer.
+ *
+ * This PDC call returns information about each module attached to the cell
+ * at the specified location.
+ */
+int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long mod,
+			unsigned long view_type, void *mem_addr)
+{
+	int retval;
+	static struct pdc_pat_cell_mod_maddr_block result __attribute__ ((aligned (8)));
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_MODULE, __pa(pdc_result), 
+			      ploc, mod, view_type, __pa(&result));
+	if(!retval) {
+		*actcnt = pdc_result[0];
+		memcpy(mem_addr, &result, *actcnt);
+	}
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
+ * pdc_pat_cpu_get_number - Retrieve the cpu number.
+ * @cpu_info: The return buffer.
+ * @hpa: The Hard Physical Address of the CPU.
+ *
+ * Retrieve the cpu number for the cpu at the specified HPA.
+ */
+int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, void *hpa)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_PAT_CPU, PDC_PAT_CPU_GET_NUMBER,
+			      __pa(&pdc_result), hpa);
+	memcpy(cpu_info, pdc_result, sizeof(*cpu_info));
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
+ * pdc_pat_get_irt_size - Retrieve the number of entries in the cell's interrupt table.
+ * @num_entries: The return value.
+ * @cell_num: The target cell.
+ *
+ * This PDC function returns the number of entries in the specified cell's
+ * interrupt table.
+ */
+int pdc_pat_get_irt_size(unsigned long *num_entries, unsigned long cell_num)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_GET_PCI_ROUTING_TABLE_SIZE,
+			      __pa(pdc_result), cell_num);
+	*num_entries = pdc_result[0];
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
+ * pdc_pat_get_irt - Retrieve the cell's interrupt table.
+ * @r_addr: The return buffer.
+ * @cell_num: The target cell.
+ *
+ * This PDC function returns the actual interrupt table for the specified cell.
+ */
+int pdc_pat_get_irt(void *r_addr, unsigned long cell_num)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_GET_PCI_ROUTING_TABLE,
+			      __pa(r_addr), cell_num);
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
+ * pdc_pat_pd_get_addr_map - Retrieve information about memory address ranges.
+ * @actlen: The return buffer.
+ * @mem_addr: Pointer to the memory buffer.
+ * @count: The number of bytes to read from the buffer.
+ * @offset: The offset with respect to the beginning of the buffer.
+ *
+ */
+int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr, 
+			    unsigned long count, unsigned long offset)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_PAT_PD, PDC_PAT_PD_GET_ADDR_MAP, __pa(pdc_result), 
+			      __pa(pdc_result2), count, offset);
+	*actual_len = pdc_result[0];
+	memcpy(mem_addr, pdc_result2, *actual_len);
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+#endif /* __LP64__ */
+
+
+/***************** 32-bit real-mode calls ***********/
+/* The struct below is used
+ * to overlay real_stack (real2.S), preparing a 32-bit call frame.
+ * real32_call_asm() then uses this stack in narrow real mode
+ */
+
+struct narrow_stack {
+	/* use int, not long which is 64 bits */
+	unsigned int arg13;
+	unsigned int arg12;
+	unsigned int arg11;
+	unsigned int arg10;
+	unsigned int arg9;
+	unsigned int arg8;
+	unsigned int arg7;
+	unsigned int arg6;
+	unsigned int arg5;
+	unsigned int arg4;
+	unsigned int arg3;
+	unsigned int arg2;
+	unsigned int arg1;
+	unsigned int arg0;
+	unsigned int frame_marker[8];
+	unsigned int sp;
+	/* in reality, there's nearly 8k of stack after this */
+};
+
+static long real32_call(unsigned long fn, ...)
+{
+	va_list args;
+	extern struct narrow_stack real_stack;
+	extern unsigned long real32_call_asm(unsigned int *,
+					     unsigned int *, 
+					     unsigned int);
+	
+	va_start(args, fn);
+	real_stack.arg0 = va_arg(args, unsigned int);
+	real_stack.arg1 = va_arg(args, unsigned int);
+	real_stack.arg2 = va_arg(args, unsigned int);
+	real_stack.arg3 = va_arg(args, unsigned int);
+	real_stack.arg4 = va_arg(args, unsigned int);
+	real_stack.arg5 = va_arg(args, unsigned int);
+	real_stack.arg6 = va_arg(args, unsigned int);
+	real_stack.arg7 = va_arg(args, unsigned int);
+	real_stack.arg8 = va_arg(args, unsigned int);
+	real_stack.arg9 = va_arg(args, unsigned int);
+	real_stack.arg10 = va_arg(args, unsigned int);
+	real_stack.arg11 = va_arg(args, unsigned int);
+	real_stack.arg12 = va_arg(args, unsigned int);
+	real_stack.arg13 = va_arg(args, unsigned int);
+	va_end(args);
+	
+	return real32_call_asm(&real_stack.sp, &real_stack.arg0, fn);
+}
+
+#ifdef __LP64__
+/***************** 64-bit real-mode calls ***********/
+
+struct wide_stack {
+	unsigned long arg0;
+	unsigned long arg1;
+	unsigned long arg2;
+	unsigned long arg3;
+	unsigned long arg4;
+	unsigned long arg5;
+	unsigned long arg6;
+	unsigned long arg7;
+	unsigned long arg8;
+	unsigned long arg9;
+	unsigned long arg10;
+	unsigned long arg11;
+	unsigned long arg12;
+	unsigned long arg13;
+	unsigned long frame_marker[2];	/* rp, previous sp */
+	unsigned long sp;
+	/* in reality, there's nearly 8k of stack after this */
+};
+
+static long real64_call(unsigned long fn, ...)
+{
+	va_list args;
+	extern struct wide_stack real_stack;
+	extern unsigned long real64_call_asm(unsigned long *,
+					     unsigned long *, 
+					     unsigned long);
+    
+	va_start(args, fn);
+	real_stack.arg0 = va_arg(args, unsigned long);
+	real_stack.arg1 = va_arg(args, unsigned long);
+	real_stack.arg2 = va_arg(args, unsigned long);
+	real_stack.arg3 = va_arg(args, unsigned long);
+	real_stack.arg4 = va_arg(args, unsigned long);
+	real_stack.arg5 = va_arg(args, unsigned long);
+	real_stack.arg6 = va_arg(args, unsigned long);
+	real_stack.arg7 = va_arg(args, unsigned long);
+	real_stack.arg8 = va_arg(args, unsigned long);
+	real_stack.arg9 = va_arg(args, unsigned long);
+	real_stack.arg10 = va_arg(args, unsigned long);
+	real_stack.arg11 = va_arg(args, unsigned long);
+	real_stack.arg12 = va_arg(args, unsigned long);
+	real_stack.arg13 = va_arg(args, unsigned long);
+	va_end(args);
+	
+	return real64_call_asm(&real_stack.sp, &real_stack.arg0, fn);
+}
+
+#endif /* __LP64__ */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/hardware.c linux-2.4.20/arch/parisc/kernel/hardware.c
--- linux-2.4.19/arch/parisc/kernel/hardware.c	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/hardware.c	2002-10-29 11:18:39.000000000 +0000
@@ -5,7 +5,7 @@
  * 
  *    Based on the document "PA-RISC 1.1 I/O Firmware Architecture 
  *    Reference Specification", March 7, 1999, version 0.96.  This
- *    is available at ?.
+ *    is available at http://parisc-linux.org/documentation/
  *
  *    Copyright 1999 by Alex deVries <adevries@thepuffingroup.com>
  *    and copyright 1999 The Puffin Group Inc.
@@ -30,32 +30,15 @@
 #include <asm/hardware.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
-
-#define HPHW_NUM_TYPES 3431
-
-static char * hw_type_name[16] = {
-	"Processor",
-	"Memory",
-	"B DMA",
-	"Obsolete",
-	"A DMA",
-	"A Direct",
-	"Obsolete",
-	"Bus Converter Port",
-	"HP CIO Adapter",
-	"Console",
-	"Foreign I/O Module",
-	"Bus Adapter",
-	"IOA (?)",
-	"Bus Bridge to Foreign Bus",
-	"HP Clothing: Fabric Component"
-};
+#include <linux/init.h>
 
 /*
- *	XXX	Could this be __init ??
+ *	HP PARISC Hardware Database
+ *	Access to this database is only possible during bootup
+ *	so don't reference this table after starting the init process
  */
  
-static struct hp_hardware hp_hardware_list[] = {
+static struct hp_hardware hp_hardware_list[] __initdata = {
 	{HPHW_NPROC,0x01,0x4,0x0,"Indigo (840, 930)"},
 	{HPHW_NPROC,0x8,0x4,0x01,"Firefox(825,925)"},
 	{HPHW_NPROC,0xA,0x4,0x01,"Top Gun (835,834,935,635)"},
@@ -169,9 +152,10 @@
 	{HPHW_NPROC,0x59A,0x4,0x91,"Unlisted but reserved"},
 	{HPHW_NPROC,0x59A,0x4,0x81,"Unlisted but reserved"},
 	{HPHW_NPROC,0x59B,0x4,0x81,"Raven U 160 (9000/780/C160)"},
+	{HPHW_NPROC,0x59C,0x4,0x81,"Raven U 180 (9000/780/C180)"},
 	{HPHW_NPROC,0x59D,0x4,0x81,"Raven U 200 (9000/780/C200)"},
 	{HPHW_NPROC,0x59E,0x4,0x91,"ThunderHawk T' 120"},
-	{HPHW_NPROC,0x59F,0x4,0x91,"Raven U 180+ (9000/780/\?\?\?\?)"},
+	{HPHW_NPROC,0x59F,0x4,0x91,"Raven U 180+ (9000/780)"},
 	{HPHW_NPROC,0x5A0,0x4,0x81,"UL 1w T120 1MB/1MB (841/D260,D360)"},
 	{HPHW_NPROC,0x5A1,0x4,0x91,"UL 2w T120 1MB/1MB (851/D260,D360)"},
 	{HPHW_NPROC,0x5A2,0x4,0x81,"UL 1w U160 512K/512K (861/D270,D370)"},
@@ -201,7 +185,7 @@
 	{HPHW_NPROC,0x5B8,0x4,0x91,"SPP2250 240 MHz"},
 	{HPHW_NPROC,0x5B9,0x4,0x81,"UL 1w U+/240 (350/550)"},
 	{HPHW_NPROC,0x5BA,0x4,0x91,"UL 2w U+/240 (350/550)"},
-	{HPHW_NPROC,0x5BB,0x4,0x81,"AllegroHigh W "},
+	{HPHW_NPROC,0x5BB,0x4,0x81,"AllegroHigh W"},
 	{HPHW_NPROC,0x5BC,0x4,0x91,"AllegroLow W"},
 	{HPHW_NPROC,0x5BD,0x4,0x91,"Forte W 2-way"},
 	{HPHW_NPROC,0x5BE,0x4,0x91,"Prelude W"},
@@ -212,12 +196,41 @@
 	{HPHW_NPROC,0x5C3,0x4,0x91,"Sonata 360"},
 	{HPHW_NPROC,0x5C4,0x4,0x91,"Rhapsody 440"},
 	{HPHW_NPROC,0x5C5,0x4,0x91,"Rhapsody 360"},
-	{HPHW_NPROC,0x5C6,0x4,0x91,"Raven W 360 (9000/780/\?\?\?\?)"},
+	{HPHW_NPROC,0x5C6,0x4,0x91,"Raven W 360 (9000/780)"},
 	{HPHW_NPROC,0x5C7,0x4,0x91,"Halfdome W 440"},
 	{HPHW_NPROC,0x5C8,0x4,0x81,"Lego 360 processor"},
 	{HPHW_NPROC,0x5C9,0x4,0x91,"Rhapsody DC- 440"},
 	{HPHW_NPROC,0x5CA,0x4,0x91,"Rhapsody DC- 360"},
 	{HPHW_NPROC,0x5CB,0x4,0x91,"Crescendo 440"},
+	{HPHW_NPROC,0x5CC,0x4,0x91,"Prelude W 440"},
+	{HPHW_NPROC,0x5CD,0x4,0x91,"SPP2600"},
+	{HPHW_NPROC,0x5CE,0x4,0x91,"M2600"},
+	{HPHW_NPROC,0x5CF,0x4,0x81,"Allegro W+"},
+	{HPHW_NPROC,0x5D0,0x4,0x81,"Kazoo W+"},
+	{HPHW_NPROC,0x5D1,0x4,0x91,"Forte W+ 2w"},
+	{HPHW_NPROC,0x5D2,0x4,0x91,"Forte W+ 4w"},
+	{HPHW_NPROC,0x5D3,0x4,0x91,"Prelude W+ 540"},
+	{HPHW_NPROC,0x5D4,0x4,0x91,"Duet W+"},
+	{HPHW_NPROC,0x5D5,0x4,0x91,"Crescendo 550"},
+	{HPHW_NPROC,0x5D6,0x4,0x81,"Crescendo DC- 440"},
+	{HPHW_NPROC,0x5D7,0x4,0x91,"Keystone W+"},
+	{HPHW_NPROC,0x5D8,0x4,0x91,"Rhapsody wave 2 W+ DC-"},
+	{HPHW_NPROC,0x5D9,0x4,0x91,"Rhapsody wave 2 W+"},
+	{HPHW_NPROC,0x5DA,0x4,0x91,"Marcato W+ DC-"},
+	{HPHW_NPROC,0x5DB,0x4,0x91,"Marcato W+"},
+	{HPHW_NPROC,0x5DC,0x4,0x91,"Allegro W2"},
+	{HPHW_NPROC,0x5DD,0x4,0x81,"Duet W2"},
+	{HPHW_NPROC,0x5DE,0x4,0x81,"Piccolo W+"},
+	{HPHW_NPROC,0x5DF,0x4,0x81,"Cantata W2"},
+	{HPHW_NPROC,0x5E0,0x4,0x91,"Cantata DC- W2"},
+	{HPHW_NPROC,0x5E1,0x4,0x91,"Crescendo DC- W2"},
+	{HPHW_NPROC,0x5E2,0x4,0x91,"Crescendo 650 W2"},
+	{HPHW_NPROC,0x5E3,0x4,0x91,"Crescendo 750 W2"},
+	{HPHW_NPROC,0x5E4,0x4,0x91,"Keystone/Matterhorn W2 750"},
+	{HPHW_NPROC,0x5E5,0x4,0x91,"PowerBar W+"},
+	{HPHW_NPROC,0x5E6,0x4,0x91,"Keystone/Matterhorn W2 650"},
+	{HPHW_NPROC,0x5E7,0x4,0x91,"Caribe W2 800"},
+	{HPHW_NPROC,0x5E8,0x4,0x91,"Pikes Peak W2"},
 	{HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"},
 	{HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"},
 	{HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"},
@@ -243,7 +256,7 @@
 	{HPHW_NPROC,0x616,0x4,0x81,"Piranha 120"},
 	{HPHW_NPROC,0x617,0x4,0x81,"Jason 50"},
 	{HPHW_NPROC,0x618,0x4,0x81,"Jason 100"},
-	{HPHW_NPROC,0x619,0x4,0x81,"Mirage 80 "},
+	{HPHW_NPROC,0x619,0x4,0x81,"Mirage 80"},
 	{HPHW_NPROC,0x61A,0x4,0x81,"SAIC L-80"},
 	{HPHW_NPROC,0x61B,0x4,0x81,"Rocky1 L-60"},
 	{HPHW_NPROC,0x61C,0x4,0x81,"Anole T (743/T)"},
@@ -311,6 +324,7 @@
 	{HPHW_A_DMA, 0x004, 0x00050, 0x80, "Lanbrusca 802.3 (36967A)"}, 
 	{HPHW_A_DMA, 0x004, 0x00056, 0x80, "HP-PB LoQuix FDDI"}, 
 	{HPHW_A_DMA, 0x004, 0x00057, 0x80, "HP-PB LoQuix FDDI (28670A)"}, 
+	{HPHW_A_DMA, 0x004, 0x0005E, 0x00, "Gecko Add-on Token Ring"}, 
 	{HPHW_A_DMA, 0x012, 0x00089, 0x80, "Barracuda Add-on FW-SCSI"}, 
 	{HPHW_A_DMA, 0x013, 0x00089, 0x80, "Bluefish Add-on FW-SCSI"}, 
 	{HPHW_A_DMA, 0x014, 0x00089, 0x80, "Shrike Add-on FW-SCSI"}, 
@@ -319,6 +333,7 @@
 	{HPHW_A_DMA, 0x01F, 0x00089, 0x80, "SkyHawk 100/120 FW-SCSI"}, 
 	{HPHW_A_DMA, 0x027, 0x00089, 0x80, "Piranha 100 FW-SCSI"}, 
 	{HPHW_A_DMA, 0x032, 0x00089, 0x80, "Raven T' Core FW-SCSI"}, 
+	{HPHW_A_DMA, 0x03b, 0x00089, 0x80, "Raven U/L2 Core FW-SCSI"}, 
 	{HPHW_A_DMA, 0x03d, 0x00089, 0x80, "Merlin 160 Core FW-SCSI"},
 	{HPHW_A_DMA, 0x044, 0x00089, 0x80, "Mohawk Core FW-SCSI"}, 
 	{HPHW_A_DMA, 0x051, 0x00089, 0x80, "Firehawk FW-SCSI"}, 
@@ -440,6 +455,8 @@
 	{HPHW_BA, 0x801, 0x00081, 0x0, "Hitachi Tiny 80 Core BA"}, 
 	{HPHW_BA, 0x004, 0x0008B, 0x0, "Anole Optional PCMCIA BA"}, 
 	{HPHW_BA, 0x004, 0x0008E, 0x0, "GSC ITR Wax BA"}, 
+	{HPHW_BA, 0x00C, 0x0008E, 0x0, "Gecko Optional Wax BA"}, 
+	{HPHW_BA, 0x010, 0x0008E, 0x0, "Pace Wax BA"}, 
 	{HPHW_BA, 0x011, 0x0008E, 0x0, "SuperPace Wax BA"}, 
 	{HPHW_BA, 0x012, 0x0008E, 0x0, "Mirage Jr Wax BA"}, 
 	{HPHW_BA, 0x013, 0x0008E, 0x0, "Mirage Wax BA"}, 
@@ -489,7 +506,7 @@
 	{HPHW_BA, 0x800, 0x00090, 0x0, "Hitachi Tiny 64 Wax EISA BA"}, 
 	{HPHW_BA, 0x801, 0x00090, 0x0, "Hitachi Tiny 80 Wax EISA BA"}, 
 	{HPHW_BA, 0x01A, 0x00093, 0x0, "Anole 64 TIMI BA"}, 
-	{HPHW_BA, 0x01B, 0x00093, 0x0, "Anole 64 TIMI BA"}, 
+	{HPHW_BA, 0x01B, 0x00093, 0x0, "Anole 100 TIMI BA"}, 
 	{HPHW_BA, 0x034, 0x00093, 0x0, "Anole T TIMI BA"}, 
 	{HPHW_BA, 0x04A, 0x00093, 0x0, "Anole L2 132 TIMI BA"}, 
 	{HPHW_BA, 0x04C, 0x00093, 0x0, "Anole L2 165 TIMI BA"}, 
@@ -551,6 +568,7 @@
 	{HPHW_CONSOLE, 0x01A, 0x0001F, 0x00, "Jason/Anole 64 Null Console"}, 
 	{HPHW_CONSOLE, 0x01B, 0x0001F, 0x00, "Jason/Anole 100 Null Console"}, 
 	{HPHW_FABRIC, 0x004, 0x000AA, 0x80, "Halfdome DNA Central Agent"}, 
+	{HPHW_FABRIC, 0x007, 0x000AA, 0x80, "Caribe DNA Central Agent"}, 
 	{HPHW_FABRIC, 0x004, 0x000AB, 0x00, "Halfdome TOGO Fabric Crossbar"}, 
 	{HPHW_FABRIC, 0x004, 0x000AC, 0x00, "Halfdome Sakura Fabric Router"}, 
 	{HPHW_FIO, 0x025, 0x0002E, 0x80, "Armyknife Optional X.25"}, 
@@ -588,14 +606,14 @@
 	{HPHW_FIO, 0x00D, 0x00072, 0x0, "Strider-33 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x00E, 0x00072, 0x0, "Trailways-50 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x00F, 0x00072, 0x0, "Trailways-33 Core LAN (802.3)"}, 
-	{HPHW_FIO, 0x010, 0x00072, 0x0, "Pace Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x011, 0x00072, 0x0, "Sidewinder Core Lan (802.3)"}, 
+	{HPHW_FIO, 0x010, 0x00072, 0x0, "Pace Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x011, 0x00072, 0x0, "Sidewinder Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x019, 0x00072, 0x0, "Scorpio Sr. Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x020, 0x00072, 0x0, "Scorpio 100 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x021, 0x00072, 0x0, "Spectra 50 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x022, 0x00072, 0x0, "Spectra 75 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x023, 0x00072, 0x0, "Spectra 100 Core LAN (802.3)"}, 
-	{HPHW_FIO, 0x024, 0x00072, 0x0, "Fast Pace Core Lan (802.3)"}, 
+	{HPHW_FIO, 0x024, 0x00072, 0x0, "Fast Pace Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x026, 0x00072, 0x0, "CoralII Jaguar Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x004, 0x00073, 0x0, "Cobra Core HIL"}, 
 	{HPHW_FIO, 0x005, 0x00073, 0x0, "Coral Core HIL"}, 
@@ -694,8 +712,8 @@
 	{HPHW_FIO, 0x04D, 0x00074, 0x0, "Anole L2 165 Core Centronics"}, 
 	{HPHW_FIO, 0x050, 0x00074, 0x0, "Merlin Jr 132 Core Centronics"}, 
 	{HPHW_FIO, 0x051, 0x00074, 0x0, "Firehawk Core Centronics"}, 
-	{HPHW_FIO, 0x056, 0x00074, 0x0, "Raven+ wSE FWSCSI Core Centronics"}, 
-	{HPHW_FIO, 0x057, 0x00074, 0x0, "Raven+ wDiff FWSCSI Core Centronics"}, 
+	{HPHW_FIO, 0x056, 0x00074, 0x0, "Raven+ w SE FWSCSI Core Centronics"}, 
+	{HPHW_FIO, 0x057, 0x00074, 0x0, "Raven+ w Diff FWSCSI Core Centronics"}, 
 	{HPHW_FIO, 0x058, 0x00074, 0x0, "FireHawk 200 Core Centronics"}, 
 	{HPHW_FIO, 0x05C, 0x00074, 0x0, "SummitHawk 230 Core Centronics"}, 
 	{HPHW_FIO, 0x800, 0x00074, 0x0, "Hitachi Tiny 64 Core Centronics"}, 
@@ -861,66 +879,66 @@
 	{HPHW_FIO, 0x02E, 0x00083, 0x0, "UL 350 Core PC Floppy"}, 
 	{HPHW_FIO, 0x02F, 0x00083, 0x0, "UL 550 Core PC Floppy"}, 
 	{HPHW_FIO, 0x032, 0x00083, 0x0, "Raven T' Core PC Floppy"}, 
-	{HPHW_FIO, 0x034, 0x00083, 0x0, "SAIC L-80 Core PC Floopy"}, 
-	{HPHW_FIO, 0x035, 0x00083, 0x0, "PCX-L2 712/132 Core Floopy"}, 
-	{HPHW_FIO, 0x036, 0x00083, 0x0, "PCX-L2 712/160 Core Floopy"}, 
-	{HPHW_FIO, 0x03B, 0x00083, 0x0, "Raven U/L2 Core PC Floopy"}, 
-	{HPHW_FIO, 0x03C, 0x00083, 0x0, "Merlin 132 Core PC Floopy"}, 
-	{HPHW_FIO, 0x03D, 0x00083, 0x0, "Merlin 160 Core PC Floopy"}, 
-	{HPHW_FIO, 0x03E, 0x00083, 0x0, "Merlin+ 132 Core PC Floopy"}, 
-	{HPHW_FIO, 0x03F, 0x00083, 0x0, "Merlin+ 180 Core PC Floopy"}, 
-	{HPHW_FIO, 0x045, 0x00083, 0x0, "Rocky1 Core PC Floopy"}, 
-	{HPHW_FIO, 0x046, 0x00083, 0x0, "Rocky2 120 Core PC Floopy"}, 
-	{HPHW_FIO, 0x047, 0x00083, 0x0, "Rocky2 150 Core PC Floopy"}, 
-	{HPHW_FIO, 0x04E, 0x00083, 0x0, "Kiji L2 132 Core PC Floopy"}, 
-	{HPHW_FIO, 0x050, 0x00083, 0x0, "Merlin Jr 132 Core PC Floopy"}, 
-	{HPHW_FIO, 0x056, 0x00083, 0x0, "Raven+ w SE FWSCSI Core PC Floopy"}, 
-	{HPHW_FIO, 0x057, 0x00083, 0x0, "Raven+ w Diff FWSCSI Core PC Floopy"}, 
-	{HPHW_FIO, 0x800, 0x00083, 0x0, "Hitachi Tiny 64 Core PC Floopy"}, 
-	{HPHW_FIO, 0x801, 0x00083, 0x0, "Hitachi Tiny 80 Core PC Floopy"}, 
-	{HPHW_FIO, 0x015, 0x00084, 0x0, "KittyHawk GSY Core PC Keyboard"}, 
-	{HPHW_FIO, 0x016, 0x00084, 0x0, "Gecko Core PC Keyboard"}, 
-	{HPHW_FIO, 0x018, 0x00084, 0x0, "Gecko Optional PC Keyboard"}, 
-	{HPHW_FIO, 0x01A, 0x00084, 0x0, "Anole 64 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x01B, 0x00084, 0x0, "Anole 100 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x01C, 0x00084, 0x0, "Gecko 80 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x01D, 0x00084, 0x0, "Gecko 100 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x01F, 0x00084, 0x0, "SkyHawk 100/120 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x027, 0x00084, 0x0, "Piranha 100 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x028, 0x00084, 0x0, "Mirage Jr Core PC Keyboard"}, 
-	{HPHW_FIO, 0x029, 0x00084, 0x0, "Mirage Core PC Keyboard"}, 
-	{HPHW_FIO, 0x02A, 0x00084, 0x0, "Electra Core PC Keyboard"}, 
-	{HPHW_FIO, 0x02B, 0x00084, 0x0, "Mirage 80 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x02C, 0x00084, 0x0, "Mirage 100+ Core PC Keyboard"}, 
-	{HPHW_FIO, 0x02E, 0x00084, 0x0, "UL 350 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x02F, 0x00084, 0x0, "UL 550 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x032, 0x00084, 0x0, "Raven T' Core PC Keyboard"}, 
-	{HPHW_FIO, 0x033, 0x00084, 0x0, "Anole T Core PC Keyboard"}, 
-	{HPHW_FIO, 0x034, 0x00084, 0x0, "SAIC L-80 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x035, 0x00084, 0x0, "PCX-L2 712/132 Core Keyboard"}, 
-	{HPHW_FIO, 0x036, 0x00084, 0x0, "PCX-L2 712/160 Core Keyboard"}, 
-	{HPHW_FIO, 0x03B, 0x00084, 0x0, "Raven U/L2 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x03C, 0x00084, 0x0, "Merlin 132 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x03D, 0x00084, 0x0, "Merlin 160 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x03E, 0x00084, 0x0, "Merlin+ 132 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x03F, 0x00084, 0x0, "Merlin+ 180 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x044, 0x00084, 0x0, "Mohawk Core PC Keyboard"}, 
-	{HPHW_FIO, 0x045, 0x00084, 0x0, "Rocky1 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x046, 0x00084, 0x0, "Rocky2 120 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x047, 0x00084, 0x0, "Rocky2 150 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x048, 0x00084, 0x0, "Rocky2 120 Dino PC Keyboard"}, 
-	{HPHW_FIO, 0x049, 0x00084, 0x0, "Rocky2 150 Dino PC Keyboard"}, 
-	{HPHW_FIO, 0x04B, 0x00084, 0x0, "Anole L2 132 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x04D, 0x00084, 0x0, "Anole L2 165 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x04E, 0x00084, 0x0, "Kiji L2 132 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x050, 0x00084, 0x0, "Merlin Jr 132 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x051, 0x00084, 0x0, "Firehawk Core PC Keyboard"}, 
-	{HPHW_FIO, 0x056, 0x00084, 0x0, "Raven+ w SE FWSCSI Core PC Keyboard"}, 
-	{HPHW_FIO, 0x057, 0x00084, 0x0, "Raven+ w Diff FWSCSI Core PC Keyboard"}, 
-	{HPHW_FIO, 0x058, 0x00084, 0x0, "FireHawk 200 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x05C, 0x00084, 0x0, "SummitHawk 230 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x800, 0x00084, 0x0, "Hitachi Tiny 64 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x801, 0x00084, 0x0, "Hitachi Tiny 80 Core PC Keyboard"}, 
+	{HPHW_FIO, 0x034, 0x00083, 0x0, "SAIC L-80 Core PC Floppy"}, 
+	{HPHW_FIO, 0x035, 0x00083, 0x0, "PCX-L2 712/132 Core Floppy"}, 
+	{HPHW_FIO, 0x036, 0x00083, 0x0, "PCX-L2 712/160 Core Floppy"}, 
+	{HPHW_FIO, 0x03B, 0x00083, 0x0, "Raven U/L2 Core PC Floppy"}, 
+	{HPHW_FIO, 0x03C, 0x00083, 0x0, "Merlin 132 Core PC Floppy"}, 
+	{HPHW_FIO, 0x03D, 0x00083, 0x0, "Merlin 160 Core PC Floppy"}, 
+	{HPHW_FIO, 0x03E, 0x00083, 0x0, "Merlin+ 132 Core PC Floppy"}, 
+	{HPHW_FIO, 0x03F, 0x00083, 0x0, "Merlin+ 180 Core PC Floppy"}, 
+	{HPHW_FIO, 0x045, 0x00083, 0x0, "Rocky1 Core PC Floppy"}, 
+	{HPHW_FIO, 0x046, 0x00083, 0x0, "Rocky2 120 Core PC Floppy"}, 
+	{HPHW_FIO, 0x047, 0x00083, 0x0, "Rocky2 150 Core PC Floppy"}, 
+	{HPHW_FIO, 0x04E, 0x00083, 0x0, "Kiji L2 132 Core PC Floppy"}, 
+	{HPHW_FIO, 0x050, 0x00083, 0x0, "Merlin Jr 132 Core PC Floppy"}, 
+	{HPHW_FIO, 0x056, 0x00083, 0x0, "Raven+ w SE FWSCSI Core PC Floppy"}, 
+	{HPHW_FIO, 0x057, 0x00083, 0x0, "Raven+ w Diff FWSCSI Core PC Floppy"}, 
+	{HPHW_FIO, 0x800, 0x00083, 0x0, "Hitachi Tiny 64 Core PC Floppy"}, 
+	{HPHW_FIO, 0x801, 0x00083, 0x0, "Hitachi Tiny 80 Core PC Floppy"},
+	{HPHW_FIO, 0x015, 0x00084, 0x0, "KittyHawk GSY Core PS/2 Port"}, 
+	{HPHW_FIO, 0x016, 0x00084, 0x0, "Gecko Core PS/2 Port"}, 
+	{HPHW_FIO, 0x018, 0x00084, 0x0, "Gecko Optional PS/2 Port"}, 
+	{HPHW_FIO, 0x01A, 0x00084, 0x0, "Anole 64 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x01B, 0x00084, 0x0, "Anole 100 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x01C, 0x00084, 0x0, "Gecko 80 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x01D, 0x00084, 0x0, "Gecko 100 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x01F, 0x00084, 0x0, "SkyHawk 100/120 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x027, 0x00084, 0x0, "Piranha 100 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x028, 0x00084, 0x0, "Mirage Jr Core PS/2 Port"}, 
+	{HPHW_FIO, 0x029, 0x00084, 0x0, "Mirage Core PS/2 Port"}, 
+	{HPHW_FIO, 0x02A, 0x00084, 0x0, "Electra Core PS/2 Port"}, 
+	{HPHW_FIO, 0x02B, 0x00084, 0x0, "Mirage 80 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x02C, 0x00084, 0x0, "Mirage 100+ Core PS/2 Port"}, 
+	{HPHW_FIO, 0x02E, 0x00084, 0x0, "UL 350 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x02F, 0x00084, 0x0, "UL 550 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x032, 0x00084, 0x0, "Raven T' Core PS/2 Port"}, 
+	{HPHW_FIO, 0x033, 0x00084, 0x0, "Anole T Core PS/2 Port"}, 
+	{HPHW_FIO, 0x034, 0x00084, 0x0, "SAIC L-80 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x035, 0x00084, 0x0, "PCX-L2 712/132 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x036, 0x00084, 0x0, "PCX-L2 712/160 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x03B, 0x00084, 0x0, "Raven U/L2 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x03C, 0x00084, 0x0, "Merlin 132 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x03D, 0x00084, 0x0, "Merlin 160 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x03E, 0x00084, 0x0, "Merlin+ 132 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x03F, 0x00084, 0x0, "Merlin+ 180 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x044, 0x00084, 0x0, "Mohawk Core PS/2 Port"}, 
+	{HPHW_FIO, 0x045, 0x00084, 0x0, "Rocky1 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x046, 0x00084, 0x0, "Rocky2 120 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x047, 0x00084, 0x0, "Rocky2 150 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x048, 0x00084, 0x0, "Rocky2 120 Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x049, 0x00084, 0x0, "Rocky2 150 Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x04B, 0x00084, 0x0, "Anole L2 132 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x04D, 0x00084, 0x0, "Anole L2 165 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x04E, 0x00084, 0x0, "Kiji L2 132 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x050, 0x00084, 0x0, "Merlin Jr 132 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x051, 0x00084, 0x0, "Firehawk Core PS/2 Port"}, 
+	{HPHW_FIO, 0x056, 0x00084, 0x0, "Raven+ w SE FWSCSI Core PS/2 Port"}, 
+	{HPHW_FIO, 0x057, 0x00084, 0x0, "Raven+ w Diff FWSCSI Core PS/2 Port"}, 
+	{HPHW_FIO, 0x058, 0x00084, 0x0, "FireHawk 200 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x05C, 0x00084, 0x0, "SummitHawk 230 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x800, 0x00084, 0x0, "Hitachi Tiny 64 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x801, 0x00084, 0x0, "Hitachi Tiny 80 Core PS/2 Port"}, 
 	{HPHW_FIO, 0x004, 0x00085, 0x0, "Solo GSC Optional Graphics"}, 
 	{HPHW_FIO, 0x005, 0x00085, 0x0, "Duet GSC Optional Graphics"}, 
 	{HPHW_FIO, 0x008, 0x00085, 0x0, "Anole Artist Optional Graphics"}, 
@@ -969,18 +987,17 @@
 	{HPHW_FIO, 0x034, 0x00088, 0x0, "Anole T VME Networking"}, 
 	{HPHW_FIO, 0x04A, 0x00088, 0x0, "Anole L2 132 VME Networking"}, 
 	{HPHW_FIO, 0x04C, 0x00088, 0x0, "Anole L2 165 VME Networking"}, 
-	{HPHW_FIO, 0x03B, 0x00089, 0x0, "Raven U/L2 Core FW-SCSI"}, 
-	{HPHW_FIO, 0x011, 0x0008A, 0x0, "WB-96 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x012, 0x0008A, 0x0, "Orville Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x013, 0x0008A, 0x0, "Wilbur Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x014, 0x0008A, 0x0, "WB-80 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x015, 0x0008A, 0x0, "KittyHawk GSY Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x016, 0x0008A, 0x0, "Gecko Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x018, 0x0008A, 0x0, "Gecko Optional Lan (802.3)"}, 
-	{HPHW_FIO, 0x01A, 0x0008A, 0x0, "Anole 64 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x01B, 0x0008A, 0x0, "Anole 100 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x01C, 0x0008A, 0x0, "Gecko 80 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x01D, 0x0008A, 0x0, "Gecko 100 Core Lan (802.3)"}, 
+	{HPHW_FIO, 0x011, 0x0008A, 0x0, "WB-96 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x012, 0x0008A, 0x0, "Orville Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x013, 0x0008A, 0x0, "Wilbur Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x014, 0x0008A, 0x0, "WB-80 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x015, 0x0008A, 0x0, "KittyHawk GSY Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x016, 0x0008A, 0x0, "Gecko Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x018, 0x0008A, 0x0, "Gecko Optional LAN (802.3)"}, 
+	{HPHW_FIO, 0x01A, 0x0008A, 0x0, "Anole 64 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x01B, 0x0008A, 0x0, "Anole 100 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x01C, 0x0008A, 0x0, "Gecko 80 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x01D, 0x0008A, 0x0, "Gecko 100 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x01F, 0x0008A, 0x0, "SkyHawk 100/120 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x027, 0x0008A, 0x0, "Piranha 100 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x028, 0x0008A, 0x0, "Mirage Jr Core LAN (802.3)"}, 
@@ -991,24 +1008,24 @@
 	{HPHW_FIO, 0x02E, 0x0008A, 0x0, "UL 350 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x02F, 0x0008A, 0x0, "UL 350 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x032, 0x0008A, 0x0, "Raven T' Core LAN (802.3)"}, 
-	{HPHW_FIO, 0x033, 0x0008A, 0x0, "Anole T Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x034, 0x0008A, 0x0, "SAIC L-80 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x035, 0x0008A, 0x0, "PCX-L2 712/132 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x036, 0x0008A, 0x0, "PCX-L2 712/160 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x03B, 0x0008A, 0x0, "Raven U/L2 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x03C, 0x0008A, 0x0, "Merlin 132 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x03D, 0x0008A, 0x0, "Merlin 160 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x044, 0x0008A, 0x0, "Mohawk Core Lan (802.3)"}, 
+	{HPHW_FIO, 0x033, 0x0008A, 0x0, "Anole T Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x034, 0x0008A, 0x0, "SAIC L-80 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x035, 0x0008A, 0x0, "PCX-L2 712/132 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x036, 0x0008A, 0x0, "PCX-L2 712/160 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x03B, 0x0008A, 0x0, "Raven U/L2 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x03C, 0x0008A, 0x0, "Merlin 132 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x03D, 0x0008A, 0x0, "Merlin 160 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x044, 0x0008A, 0x0, "Mohawk Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x045, 0x0008A, 0x0, "Rocky1 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x046, 0x0008A, 0x0, "Rocky2 120 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x047, 0x0008A, 0x0, "Rocky2 150 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x04B, 0x0008A, 0x0, "Anole L2 132 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x04D, 0x0008A, 0x0, "Anole L2 165 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x04E, 0x0008A, 0x0, "Kiji L2 132 Core LAN (802.3)"}, 
-	{HPHW_FIO, 0x050, 0x0008A, 0x0, "Merlin Jr 132 Core Lan (802.3)"}, 
+	{HPHW_FIO, 0x050, 0x0008A, 0x0, "Merlin Jr 132 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x058, 0x0008A, 0x0, "FireHawk 200 Core LAN (802.3)"}, 
-	{HPHW_FIO, 0x800, 0x0008A, 0x0, "Hitachi Tiny 64 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x801, 0x0008A, 0x0, "Hitachi Tiny 80 Core Lan (802.3)"}, 
+	{HPHW_FIO, 0x800, 0x0008A, 0x0, "Hitachi Tiny 64 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x801, 0x0008A, 0x0, "Hitachi Tiny 80 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x004, 0x0008C, 0x0, "SkyHawk 100/120 Wax RS-232"}, 
 	{HPHW_FIO, 0x005, 0x0008C, 0x0, "SAIC L-80 Wax RS-232"}, 
 	{HPHW_FIO, 0x006, 0x0008C, 0x0, "Raven U/L2 Dino RS-232"}, 
@@ -1099,14 +1116,15 @@
 	{HPHW_FIO, 0x005, 0x0008F, 0x0, "Rocky1 Boot Rom"}, 
 	{HPHW_FIO, 0x006, 0x0008F, 0x0, "Rocky2 120 Boot Rom"}, 
 	{HPHW_FIO, 0x007, 0x0008F, 0x0, "Rocky2 150 Boot Rom"}, 
-	{HPHW_FIO, 0x006, 0x00096, 0x0, "Raven U/L2 Dino PS2 Keyboard"}, 
-	{HPHW_FIO, 0x007, 0x00096, 0x0, "Dino PS2 Keyboard"}, 
-	{HPHW_FIO, 0x008, 0x00096, 0x0, "Merlin 132 Dino PS2 Keyboard"}, 
-	{HPHW_FIO, 0x009, 0x00096, 0x0, "Merlin 160 Dino PS2 Keyboard"}, 
-	{HPHW_FIO, 0x00A, 0x00096, 0x0, "Merlin Jr 132 Dino PS2 Keyboard"}, 
-	{HPHW_FIO, 0x019, 0x00096, 0x0, "Merlin+ 180 Dino PS2 Keyboard"}, 
-	{HPHW_FIO, 0x022, 0x00096, 0x0, "Merlin+ 132 Dino PS2 Keyboard"}, 
-	{HPHW_FIO, 0x004, 0x00097, 0x0, "Cascade EISA 100VG lan"}, 
+	{HPHW_FIO, 0x01B, 0x0008F, 0x0, "Anole 100 Boot Rom"}, 
+	{HPHW_FIO, 0x006, 0x00096, 0x0, "Raven U/L2 Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x007, 0x00096, 0x0, "Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x008, 0x00096, 0x0, "Merlin 132 Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x009, 0x00096, 0x0, "Merlin 160 Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x00A, 0x00096, 0x0, "Merlin Jr 132 Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x019, 0x00096, 0x0, "Merlin+ 180 Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x022, 0x00096, 0x0, "Merlin+ 132 Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x004, 0x00097, 0x0, "Cascade EISA 100VG LAN"}, 
 	{HPHW_FIO, 0x023, 0x00099, 0x0, "Rocky1 Wax HPIB"}, 
 	{HPHW_FIO, 0x048, 0x00099, 0x0, "Rocky2 120 Clark/Dino HPIB"}, 
 	{HPHW_FIO, 0x049, 0x00099, 0x0, "Rocky2 150 Clark/Dino HPIB"}, 
@@ -1114,14 +1132,14 @@
 	{HPHW_FIO, 0x004, 0x000A2, 0x0, "Forte Core PCI 10/100BT LAN"}, 
 	{HPHW_FIO, 0x005, 0x000A2, 0x0, "AllegroLow PCI 10/100BT LAN"}, 
 	{HPHW_FIO, 0x006, 0x000A2, 0x0, "AllegroHIgh Core PCI 10/100BT LAN"}, 
-	{HPHW_FIO, 0x007, 0x000A2, 0x0, "PCI Plug-in Lan"}, 
-	{HPHW_FIO, 0x00A, 0x000A2, 0x0, "Lego 360 Core PCI 10/100BT Lan"}, 
-	{HPHW_FIO, 0x03E, 0x000A2, 0x0, "Merlin+ 132 Core PCI Lan"}, 
-	{HPHW_FIO, 0x03F, 0x000A2, 0x0, "Merlin+ 180 Core PCI Lan"}, 
-	{HPHW_FIO, 0x056, 0x000A2, 0x0, "Raven+ w SE FWSCSI Core PCI Lan"}, 
-	{HPHW_FIO, 0x057, 0x000A2, 0x0, "Raven+ w Diff FWSCSI Core PCI Lan"}, 
-	{HPHW_FIO, 0x05E, 0x000A2, 0x0, "Staccato 132 PCI Lan"}, 
-	{HPHW_FIO, 0x05F, 0x000A2, 0x0, "Staccato 180 PCI Lan"}, 
+	{HPHW_FIO, 0x007, 0x000A2, 0x0, "PCI Plug-in LAN"}, 
+	{HPHW_FIO, 0x00A, 0x000A2, 0x0, "Lego 360 Core PCI 10/100BT LAN"}, 
+	{HPHW_FIO, 0x03E, 0x000A2, 0x0, "Merlin+ 132 Core PCI LAN"}, 
+	{HPHW_FIO, 0x03F, 0x000A2, 0x0, "Merlin+ 180 Core PCI LAN"}, 
+	{HPHW_FIO, 0x056, 0x000A2, 0x0, "Raven+ w SE FWSCSI Core PCI LAN"}, 
+	{HPHW_FIO, 0x057, 0x000A2, 0x0, "Raven+ w Diff FWSCSI Core PCI LAN"}, 
+	{HPHW_FIO, 0x05E, 0x000A2, 0x0, "Staccato 132 PCI LAN"}, 
+	{HPHW_FIO, 0x05F, 0x000A2, 0x0, "Staccato 180 PCI LAN"}, 
 	{HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI LVD Ultra2 SCSI"}, 
 	{HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI SE UltraSCSI"}, 
 	{HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI IDE/ATAPI CD-ROM"}, 
@@ -1157,160 +1175,19 @@
 	{HPHW_IOA, 0x185, 0x0000B, 0x00, "Java BC Summit Port"}, 
 	{HPHW_IOA, 0x1FF, 0x0000B, 0x00, "Hitachi Ghostview Summit Port"}, 
 	{HPHW_IOA, 0x580, 0x0000B, 0x10, "U2-IOA BC Runway Port"}, 
-	{HPHW_IOA, 0x581, 0x0000B, 0x10, "Uturn-IOA BC Runway Port"}, 
-	{HPHW_IOA, 0x582, 0x0000B, 0x10, "Astro BC Runway Port"}, 
-	{HPHW_IOA, 0x700, 0x0000B, 0x00, "NEC-IOS BC System Bus Port"}, 
+	{HPHW_IOA, 0x581, 0x0000B, 0x10, "Uturn-IOA BC Runway Port"},
+	{HPHW_IOA, 0x582, 0x0000B, 0x10, "Astro BC Runway Port"},
+	{HPHW_IOA, 0x700, 0x0000B, 0x00, "NEC-IOS BC System Bus Port"},
 	{HPHW_MEMORY, 0x002, 0x00008, 0x00, "MID_BUS"}, 
-	{HPHW_MEMORY, 0x00C, 0x00008, 0x08, "Kahlua 8MB"}, 
-	{HPHW_MEMORY, 0x00D, 0x00008, 0x08, "Kahlua 4MB"}, 
-	{HPHW_MEMORY, 0x00E, 0x00008, 0x08, "Tequila 16MB"}, 
-	{HPHW_MEMORY, 0x00F, 0x00008, 0x08, "Tequila 32MB"}, 
-	{HPHW_MEMORY, 0x040, 0x00008, 0x00, "Hitachi"}, 
-	{HPHW_MEMORY, 0x004, 0x00009, 0x00, "Cheetah"}, 
-	{HPHW_MEMORY, 0x005, 0x00009, 0x00, "Emerald"}, 
-	{HPHW_MEMORY, 0x008, 0x00009, 0x00, "Indigo 3MB/5MB"}, 
-	{HPHW_MEMORY, 0x00C, 0x00009, 0x00, "Indigo 8MB"}, 
-	{HPHW_MEMORY, 0x00D, 0x00009, 0x00, "Paradise 4MB"}, 
-	{HPHW_MEMORY, 0x00E, 0x00009, 0x00, "Burgundy Onboard"}, 
-	{HPHW_MEMORY, 0x012, 0x00009, 0x00, "Indigo 12MB/20MB"}, 
-	{HPHW_MEMORY, 0x013, 0x00009, 0x00, "Cobra"}, 
-	{HPHW_MEMORY, 0x014, 0x00009, 0x00, "Nova"}, 
-	{HPHW_MEMORY, 0x015, 0x00009, 0x00, "Coral"}, 
-	{HPHW_MEMORY, 0x016, 0x00009, 0x00, "Bushmaster"}, 
-	{HPHW_MEMORY, 0x017, 0x00009, 0x00, "Scorpio"}, 
-	{HPHW_MEMORY, 0x018, 0x00009, 0x00, "Flounder"}, 
-	{HPHW_MEMORY, 0x019, 0x00009, 0x00, "Hardball"}, 
-	{HPHW_MEMORY, 0x01A, 0x00009, 0x00, "CoralII 99"}, 
-	{HPHW_MEMORY, 0x01B, 0x00009, 0x00, "Scorpio Jr."}, 
-	{HPHW_MEMORY, 0x01C, 0x00009, 0x00, "Strider-50 (715T)"}, 
-	{HPHW_MEMORY, 0x01D, 0x00009, 0x00, "Strider-33 (707T)"}, 
-	{HPHW_MEMORY, 0x01E, 0x00009, 0x00, "Trailways-50 (715S)"}, 
-	{HPHW_MEMORY, 0x01F, 0x00009, 0x00, "Trailways-33 (707S)"}, 
-	{HPHW_MEMORY, 0x020, 0x00009, 0x00, "Pace"}, 
-	{HPHW_MEMORY, 0x021, 0x00009, 0x00, "Sidewinder"}, 
-	{HPHW_MEMORY, 0x022, 0x00009, 0x00, "Orville"}, 
-	{HPHW_MEMORY, 0x023, 0x00009, 0x00, "Wilbur"}, 
-	{HPHW_MEMORY, 0x026, 0x00009, 0x00, "Gecko"}, 
-	{HPHW_MEMORY, 0x027, 0x00009, 0x00, "Scorpio Sr."}, 
-	{HPHW_MEMORY, 0x028, 0x00009, 0x00, "Scorpio 100"}, 
-	{HPHW_MEMORY, 0x029, 0x00009, 0x00, "Spectra 50"}, 
-	{HPHW_MEMORY, 0x02A, 0x00009, 0x00, "CoralII 132"}, 
-	{HPHW_MEMORY, 0x02F, 0x00009, 0x00, "KittyHawk DC2-"}, 
-	{HPHW_MEMORY, 0x030, 0x00009, 0x00, "Spectra 75"}, 
-	{HPHW_MEMORY, 0x031, 0x00009, 0x00, "Spectra 100"}, 
-	{HPHW_MEMORY, 0x032, 0x00009, 0x00, "KittyHawk DC3"}, 
-	{HPHW_MEMORY, 0x033, 0x00009, 0x00, "Fast Pace"}, 
-	{HPHW_MEMORY, 0x034, 0x00009, 0x00, "Snake Eagle"}, 
-	{HPHW_MEMORY, 0x035, 0x00009, 0x00, "Anole 64"}, 
-	{HPHW_MEMORY, 0x036, 0x00009, 0x00, "Anole 100"}, 
-	{HPHW_MEMORY, 0x037, 0x00009, 0x00, "Snake Cheetah"}, 
-	{HPHW_MEMORY, 0x038, 0x00009, 0x00, "Gecko 80"}, 
-	{HPHW_MEMORY, 0x039, 0x00009, 0x00, "Gecko 100"}, 
-	{HPHW_MEMORY, 0x03A, 0x00009, 0x00, "Gecko 120"}, 
-	{HPHW_MEMORY, 0x03B, 0x00009, 0x00, "Gila 80"}, 
-	{HPHW_MEMORY, 0x03C, 0x00009, 0x00, "Gila 100"}, 
-	{HPHW_MEMORY, 0x03D, 0x00009, 0x00, "Gila 120"}, 
-	{HPHW_MEMORY, 0x03E, 0x00009, 0x00, "Scorpio-L 80"}, 
-	{HPHW_MEMORY, 0x03F, 0x00009, 0x00, "Scorpio-L 100"}, 
-	{HPHW_MEMORY, 0x040, 0x00009, 0x00, "Scorpio-L 120"}, 
-	{HPHW_MEMORY, 0x041, 0x00009, 0x00, "Spectra-L 80"}, 
-	{HPHW_MEMORY, 0x042, 0x00009, 0x00, "Spectra-L 100"}, 
-	{HPHW_MEMORY, 0x043, 0x00009, 0x00, "Spectra-L 120"}, 
-	{HPHW_MEMORY, 0x044, 0x00009, 0x00, "Piranha 100"}, 
-	{HPHW_MEMORY, 0x045, 0x00009, 0x00, "Piranha 120"}, 
-	{HPHW_MEMORY, 0x046, 0x00009, 0x00, "Jason 50"}, 
-	{HPHW_MEMORY, 0x047, 0x00009, 0x00, "Jason 100"}, 
-	{HPHW_MEMORY, 0x049, 0x00009, 0x00, "SkyHawk 100/120"}, 
-	{HPHW_MEMORY, 0x04A, 0x00009, 0x00, "Mirage Jr"}, 
-	{HPHW_MEMORY, 0x04B, 0x00009, 0x00, "Mirage 100"}, 
-	{HPHW_MEMORY, 0x04C, 0x00009, 0x00, "Mirage 100+"}, 
-	{HPHW_MEMORY, 0x04D, 0x00009, 0x00, "Electra 100"}, 
-	{HPHW_MEMORY, 0x04E, 0x00009, 0x00, "Electra 120"}, 
-	{HPHW_MEMORY, 0x04F, 0x00009, 0x00, "Mirage 80"}, 
-	{HPHW_MEMORY, 0x050, 0x00009, 0x00, "UL Proc 1 way T'100"}, 
-	{HPHW_MEMORY, 0x051, 0x00009, 0x00, "UL Proc 1 way T'120"}, 
-	{HPHW_MEMORY, 0x052, 0x00009, 0x00, "UL Proc 2 way T'100"}, 
-	{HPHW_MEMORY, 0x053, 0x00009, 0x00, "KittyHawk DC3-"}, 
-	{HPHW_MEMORY, 0x054, 0x00009, 0x00, "UL Proc 2 way T'120"}, 
-	{HPHW_MEMORY, 0x055, 0x00009, 0x00, "Raven 120 mem"}, 
-	{HPHW_MEMORY, 0x056, 0x00009, 0x00, "UL Proc L 75"}, 
-	{HPHW_MEMORY, 0x057, 0x00009, 0x00, "UL Proc L 100"}, 
-	{HPHW_MEMORY, 0x058, 0x00009, 0x00, "Anole T"}, 
-	{HPHW_MEMORY, 0x059, 0x00009, 0x00, "SAIC L-80"}, 
-	{HPHW_MEMORY, 0x05A, 0x00009, 0x00, "Merlin+ L2 180"}, 
-	{HPHW_MEMORY, 0x05B, 0x00009, 0x00, "Raven U 200 2-way"}, 
-	{HPHW_MEMORY, 0x05C, 0x00009, 0x00, "Raven U 180+"}, 
-	{HPHW_MEMORY, 0x05D, 0x00009, 0x00, "Raven U 200"}, 
-	{HPHW_MEMORY, 0x05E, 0x00009, 0x00, "Rocky2 150 Memory"}, 
-	{HPHW_MEMORY, 0x08A, 0x00009, 0x00, "Staccato L2 132 Memory"}, 
-	{HPHW_MEMORY, 0x08B, 0x00009, 0x00, "Staccato L2 180 Memory"}, 
-	{HPHW_MEMORY, 0x05F, 0x00009, 0x00, "SPP2000 Memory"}, 
-	{HPHW_MEMORY, 0x060, 0x00009, 0x00, "Merlin L2 132"}, 
-	{HPHW_MEMORY, 0x061, 0x00009, 0x00, "Merlin+ L2 132"}, 
 	{HPHW_MEMORY, 0x063, 0x00009, 0x00, "712/132 L2 Upgrade"}, 
 	{HPHW_MEMORY, 0x064, 0x00009, 0x00, "712/160 L2 Upgrade"}, 
 	{HPHW_MEMORY, 0x065, 0x00009, 0x00, "715/132 L2 Upgrade"}, 
-	{HPHW_MEMORY, 0x066, 0x00009, 0x00, "715/160 L2 Upgrade"}, 
-	{HPHW_MEMORY, 0x067, 0x00009, 0x00, "Merlin 160/ThunderHawk Memory"}, 
-	{HPHW_MEMORY, 0x068, 0x00009, 0x00, "LightningHawk Memory"}, 
-	{HPHW_MEMORY, 0x069, 0x00009, 0x00, "Rocky1 Memory"}, 
-	{HPHW_MEMORY, 0x06A, 0x00009, 0x00, "Raven L2 132"}, 
-	{HPHW_MEMORY, 0x06B, 0x00009, 0x00, "Raven L2 160"}, 
-	{HPHW_MEMORY, 0x06C, 0x00009, 0x00, "Raven L2 187"}, 
-	{HPHW_MEMORY, 0x06D, 0x00009, 0x00, "Raven L2 200"}, 
-	{HPHW_MEMORY, 0x06E, 0x00009, 0x00, "Raven U 230"}, 
-	{HPHW_MEMORY, 0x06F, 0x00009, 0x00, "Raven U 240"}, 
-	{HPHW_MEMORY, 0x070, 0x00009, 0x00, "Rocky2 120 Memory"}, 
-	{HPHW_MEMORY, 0x071, 0x00009, 0x00, "Raven U 160"}, 
-	{HPHW_MEMORY, 0x072, 0x00009, 0x00, "Raven U 180"}, 
-	{HPHW_MEMORY, 0x072, 0x00009, 0x00, "UL Proc 1 way T'120 1MB/1MB"}, 
-	{HPHW_MEMORY, 0x073, 0x00009, 0x00, "UL Proc 2 way T'120 1MB/1MB"}, 
-	{HPHW_MEMORY, 0x074, 0x00009, 0x00, "Anole L2 132 memory"}, 
-	{HPHW_MEMORY, 0x075, 0x00009, 0x00, "Anole L2 165 memory"}, 
-	{HPHW_MEMORY, 0x076, 0x00009, 0x00, "UL 1 way U160 512K/512K memory"}, 
-	{HPHW_MEMORY, 0x077, 0x00009, 0x00, "UL 2 way U160 512K/512K memory"}, 
-	{HPHW_MEMORY, 0x078, 0x00009, 0x00, "Kiji L2 132 memory"}, 
-	{HPHW_MEMORY, 0x079, 0x00009, 0x00, "UL 1 way U160 1M/1M memory"}, 
-	{HPHW_MEMORY, 0x07A, 0x00009, 0x00, "UL 2 way U160 1M/1M memory"}, 
-	{HPHW_MEMORY, 0x07B, 0x00009, 0x00, "UL 1 way U180 1M/1M memory"}, 
-	{HPHW_MEMORY, 0x07C, 0x00009, 0x00, "UL 2 way U180 1M/1M memory"}, 
-	{HPHW_MEMORY, 0x07D, 0x00009, 0x00, "UL 1 way U240 U+ 2M/2M memory"}, 
-	{HPHW_MEMORY, 0x07E, 0x00009, 0x00, "UL 2 way U240 U+ 2M/2M memory"}, 
-	{HPHW_MEMORY, 0x07F, 0x00009, 0x00, "UL L2 132 memory"}, 
-	{HPHW_MEMORY, 0x080, 0x00009, 0x00, "UL L2 160 memory"}, 
-	{HPHW_MEMORY, 0x081, 0x00009, 0x00, "Merlin Jr 132 memory"}, 
-	{HPHW_MEMORY, 0x082, 0x00009, 0x00, "FireHawk 200 Memory"}, 
-	{HPHW_MEMORY, 0x083, 0x00009, 0x00, "SummitHawk Memory"}, 
-	{HPHW_MEMORY, 0x084, 0x00009, 0x00, "Jade Upgrade Memory"}, 
-	{HPHW_MEMORY, 0x085, 0x00009, 0x00, "SPP2500 Memory"}, 
-	{HPHW_MEMORY, 0x086, 0x00009, 0x00, "AllegroHigh Memory"}, 
-	{HPHW_MEMORY, 0x087, 0x00009, 0x00, "AllegroLow Memory"}, 
-	{HPHW_MEMORY, 0x088, 0x00009, 0x00, "Forte 2w Memory"}, 
-	{HPHW_MEMORY, 0x089, 0x00009, 0x00, "Forte 4w Memory"}, 
-	{HPHW_MEMORY, 0x08A, 0x00009, 0x00, "Staccato L2 132 Memory"}, 
-	{HPHW_MEMORY, 0x08B, 0x00009, 0x00, "Staccato L2 180 Memory"}, 
-	{HPHW_MEMORY, 0x090, 0x00009, 0x00, "Prelude SMC Memory"}, 
-	{HPHW_MEMORY, 0x091, 0x00009, 0x00, "Lego 360 Memory"}, 
-	{HPHW_MEMORY, 0x7FF, 0x00009, 0x00, "NEC Aska memory"}, 
-	{HPHW_MEMORY, 0x800, 0x00009, 0x00, "Hitachi Tiny 64"}, 
-	{HPHW_MEMORY, 0x801, 0x00009, 0x00, "Hitachi Tiny 80"}, 
-	{HPHW_MEMORY, 0x8FF, 0x00009, 0x00, "Hitachi X memory"}, 
-	{HPHW_MEMORY, 0x091, 0x00009, 0x00, "M2250 Memory"}, 
-	{HPHW_MEMORY, 0x092, 0x00009, 0x00, "M2500 Memory"}, 
-	{HPHW_MEMORY, 0x093, 0x00009, 0x00, "Sonata 440 Memory"}, 
-	{HPHW_MEMORY, 0x094, 0x00009, 0x00, "Sonata 360 Memory"}, 
-	{HPHW_MEMORY, 0x095, 0x00009, 0x00, "Rhapsody 440 Memory"}, 
-	{HPHW_MEMORY, 0x096, 0x00009, 0x00, "Rhapsody 360 Memory"}, 
-	{HPHW_MEMORY, 0x097, 0x00009, 0x00, "Raven W 360 Memory"}, 
-	{HPHW_MEMORY, 0x098, 0x00009, 0x00, "Halfdome W 440 Memory"}, 
-	{HPHW_MEMORY, 0x099, 0x00009, 0x00, "Rhapsody DC- 440 Memory"}, 
-	{HPHW_MEMORY, 0x09A, 0x00009, 0x00, "Rhapsody DC- 360 Memory"}, 
-	{HPHW_MEMORY, 0x09B, 0x00009, 0x00, "Crescendo Memory"}, 
+	{HPHW_MEMORY, 0x066, 0x00009, 0x00, "715/160 L2 Upgrade"},
 	{HPHW_OTHER, 0x004, 0x00030, 0x00, "Master"}, 
 	{HPHW_OTHER, 0x004, 0x00034, 0x00, "Slave"}, 
 	{HPHW_OTHER, 0x004, 0x00038, 0x00, "EDU"}, 
 	{HPHW_OTHER, 0x004, 0x00049, 0x00, "LGB Control"}, 
-        {0, }			/* leave the last entry empty ! */
+	{HPHW_FAULTY, 0, }  /* Special Marker for last entry */
 };
 
 
@@ -1318,7 +1195,7 @@
 	unsigned short model;
 	unsigned short mask;
 	enum cpu_type cpu;
-} hp_cpu_type_mask_list[] = {
+} hp_cpu_type_mask_list[] __initdata = {
 
 	{ 0x0000, 0x0ff0, pcx    },  /* 0x0000 - 0x000f */
 	{ 0x0048, 0x0ff0, pcxl   },  /* 0x0040 - 0x004f */
@@ -1350,8 +1227,10 @@
 	{ 0x0592, 0x0fff, pcxt_  },  /* 0x0592 - 0x0592 */
 	{ 0x0593, 0x0fff, pcxu   },  /* 0x0593 - 0x0593 */
 	{ 0x0594, 0x0ffc, pcxu   },  /* 0x0594 - 0x0597 */
-	{ 0x0598, 0x0ffc, pcxu   },  /* 0x0598 - 0x059b */
-	{ 0x059c, 0x0ffe, pcxu_  },  /* 0x059c - 0x059d */
+	{ 0x0598, 0x0ffe, pcxu_  },  /* 0x0598 - 0x0599 */
+	{ 0x059a, 0x0ffe, pcxu   },  /* 0x059a - 0x059b */
+	{ 0x059c, 0x0fff, pcxu   },  /* 0x059c - 0x059c */
+	{ 0x059d, 0x0fff, pcxu_  },  /* 0x059d - 0x059d */
 	{ 0x059e, 0x0fff, pcxt_  },  /* 0x059e - 0x059e */
 	{ 0x059f, 0x0fff, pcxu   },  /* 0x059f - 0x059f */
 	{ 0x05a0, 0x0ffe, pcxt_  },  /* 0x05a0 - 0x05a1 */
@@ -1370,7 +1249,27 @@
 	{ 0x05ba, 0x0fff, pcxu_  },  /* 0x05ba - 0x05ba */
 	{ 0x05bb, 0x0fff, pcxw   },  /* 0x05bb - 0x05bb */
 	{ 0x05bc, 0x0ffc, pcxw   },  /* 0x05bc - 0x05bf */
-	{ 0x05c0, 0x0fc0, pcxw   },  /* 0x05c0 - 0x05ff */
+	{ 0x05c0, 0x0ffc, pcxw 	 },  /* 0x05c0 - 0x05c3 */
+	{ 0x05c4, 0x0ffe, pcxw 	 },  /* 0x05c4 - 0x05c5 */
+	{ 0x05c6, 0x0fff, pcxw 	 },  /* 0x05c6 - 0x05c6 */
+	{ 0x05c7, 0x0fff, pcxw_  },  /* 0x05c7 - 0x05c7 */
+	{ 0x05c8, 0x0ffc, pcxw 	 },  /* 0x05c8 - 0x05cb */
+	{ 0x05cc, 0x0ffe, pcxw 	 },  /* 0x05cc - 0x05cd */
+	{ 0x05ce, 0x0ffe, pcxw_  },  /* 0x05ce - 0x05cf */
+	{ 0x05d0, 0x0ffc, pcxw_  },  /* 0x05d0 - 0x05d3 */
+	{ 0x05d4, 0x0ffe, pcxw_  },  /* 0x05d4 - 0x05d5 */
+	{ 0x05d6, 0x0fff, pcxw 	 },  /* 0x05d6 - 0x05d6 */
+	{ 0x05d7, 0x0fff, pcxw_  },  /* 0x05d7 - 0x05d7 */
+	{ 0x05d8, 0x0ffc, pcxw_  },  /* 0x05d8 - 0x05db */
+	{ 0x05dc, 0x0ffe, pcxw2  },  /* 0x05dc - 0x05dd */
+	{ 0x05de, 0x0fff, pcxw_  },  /* 0x05de - 0x05de */
+	{ 0x05df, 0x0fff, pcxw2  },  /* 0x05df - 0x05df */
+	{ 0x05e0, 0x0ffc, pcxw2  },  /* 0x05e0 - 0x05e3 */
+	{ 0x05e4, 0x0fff, pcxw2  },  /* 0x05e4 - 0x05e4 */
+	{ 0x05e5, 0x0fff, pcxw_  },  /* 0x05e5 - 0x05e5 */
+	{ 0x05e6, 0x0ffe, pcxw2  },  /* 0x05e6 - 0x05e7 */
+	{ 0x05e8, 0x0ff8, pcxw2  },  /* 0x05e8 - 0x05ef */
+	{ 0x05f0, 0x0ff0, pcxw2  },  /* 0x05f0 - 0x05ff */
 	{ 0x0600, 0x0ff0, pcxl   },  /* 0x0600 - 0x060f */
 	{ 0x0610, 0x0ff0, pcxl   },  /* 0x0610 - 0x061f */
 	{ 0x0000, 0x0000, pcx    }	/* terminate table */
@@ -1386,36 +1285,51 @@
 	[pcxu]	{ "PA8000 (PCX-U)",	"2.0" },
 	[pcxu_]	{ "PA8200 (PCX-U+)",	"2.0" },
 	[pcxw]	{ "PA8500 (PCX-W)",	"2.0" },
-	[pcxw_]	{ "PA8600 (PCX-W+)",	"2.0" }
+	[pcxw_]	{ "PA8600 (PCX-W+)",	"2.0" },
+	[pcxw2]	{ "PA8700 (PCX-W2)",	"2.0" }
 };
 
-char *parisc_getHWtype(unsigned short hw_type)
-{
-	if (hw_type <= HPHW_CIO) {
-		return hw_type_name[hw_type];
-	} else {
-		return "Unknown Type";
-	}
-}
-
-char *parisc_getHWdescription(unsigned short hw_type, unsigned long hversion,
-		unsigned long sversion)
+const char * __init
+parisc_hardware_description(struct parisc_device_id *id)
 {
 	struct hp_hardware *listptr;
 	
-	for (listptr = hp_hardware_list; listptr->name; listptr++) {
-		if ((listptr->hw_type==hw_type) &&
-				(listptr->hversion==hversion) &&
-				(listptr->sversion==sversion)){
+	for (listptr = hp_hardware_list; listptr->hw_type != HPHW_FAULTY; listptr++) {
+		if ((listptr->hw_type == id->hw_type) &&
+				(listptr->hversion == id->hversion) &&
+				(listptr->sversion == id->sversion)){
 			return listptr->name;
 		}
 	}
+
+	/*
+	 * ok, the above hardware table isn't complete, and we haven't found
+	 * our device in this table. So let's now try to find a generic name
+	 * to describe the given hardware...
+	 */
+	switch (id->hw_type) {
+		case HPHW_NPROC:
+			return "Unknown machine";
+
+		case HPHW_A_DIRECT:
+			switch (id->sversion) {
+				case 0x0D: return "MUX port";
+				case 0x0E: return "RS-232 port";
+			}
+			break;
+			
+		case HPHW_MEMORY:
+			return "Memory";
+			
+	}
+	
 	return "unknown device";
 }
 
 
 /* Interpret hversion (ret[0]) from PDC_MODEL(4)/PDC_MODEL_INFO(0) */
-enum cpu_type parisc_get_cpu_type(unsigned long hversion)
+enum cpu_type __init
+parisc_get_cpu_type(unsigned long hversion)
 {
 	struct hp_cpu_type_mask *ptr;
 	unsigned short model = ((unsigned short) (hversion)) >> 4;
@@ -1424,23 +1338,8 @@
 		if (ptr->model == (model & ptr->mask))
 			return ptr->cpu;
 	}
-	panic("parisc_get_cpu_type() could not identify CPU type\n");
+	panic("could not identify CPU type\n");
 
 	return pcx;	/* not reached: */
 }
 
-
-struct hp_hardware *parisc_get_reference(unsigned short hw_type,
-		unsigned long hversion, unsigned long sversion)
-{
-	struct hp_hardware *listptr = hp_hardware_list;
-
-	for (listptr = hp_hardware_list; listptr->name; listptr++) {
-		if ((listptr->hw_type == hw_type) &&
-				(listptr->hversion == hversion) &&
-				(listptr->sversion == sversion)) {
-			return listptr;
-		}
-	}
-	return NULL;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/head.S linux-2.4.20/arch/parisc/kernel/head.S
--- linux-2.4.19/arch/parisc/kernel/head.S	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/head.S	2002-10-29 11:18:49.000000000 +0000
@@ -8,17 +8,14 @@
  * Copyright 1999 SuSE GmbH (Philipp Rumpf)
  * Copyright 1999 Philipp Rumpf (prumpf@tux.org)
  *
- * Initial Version 04-23-1999 by Helge Deller (helge.deller@ruhr-uni-bochum.de)
+ * Initial Version 04-23-1999 by Helge Deller <deller@gmx.de>
  */
 
+#include <linux/autoconf.h>	/* for CONFIG_SMP */
 
 #include <asm/offset.h>
 #include <asm/psw.h>
 
-#define __ASSEMBLY__
-/*********
-#include <asm/pdc.h>
-*********/
 #include <asm/assembly.h>
 #include <asm/pgtable.h>
 
@@ -36,6 +33,15 @@
 	.export __setup_end
 __setup_end:
 
+	.data
+
+	.export boot_args
+boot_args:
+	.word 0 /* arg0 */
+	.word 0 /* arg1 */
+	.word 0 /* arg2 */
+	.word 0 /* arg3 */
+
 	.text
 	.align	4	
 	.import init_task_union,data
@@ -52,43 +58,129 @@
 	.callinfo
 
 	/* Make sure sr4-sr7 are set to zero for the kernel address space */
-
-	mtsp		%r0,%sr4
-	mtsp		%r0,%sr5
-	mtsp		%r0,%sr6
-	mtsp		%r0,%sr7
+	mtsp	%r0,%sr4
+	mtsp	%r0,%sr5
+	mtsp	%r0,%sr6
+	mtsp	%r0,%sr7
+
+	/* Clear BSS (shouldn't the boot loader do this?) */
+
+	.import _edata,data
+	.import _end,data
+
+	ldil            L%PA(_edata),%r3
+	ldo             R%PA(_edata)(%r3),%r3
+	ldil            L%PA(_end),%r4
+	ldo             R%PA(_end)(%r4),%r4
+$bss_loop:
+	cmpb,<<,n       %r3,%r4,$bss_loop
+	stb,ma          %r0,1(%r3)
+
+	/* Save away the arguments the boot loader passed in (32 bit args) */
+
+	ldil            L%PA(boot_args),%r1
+	ldo             R%PA(boot_args)(%r1),%r1
+	stw,ma          %arg0,4(%r1)
+	stw,ma          %arg1,4(%r1)
+	stw,ma          %arg2,4(%r1)
+	stw,ma          %arg3,4(%r1)
 
 	/* Initialize startup VM. Just map first 8 MB of memory */
-
 	ldil		L%PA(pg0),%r1
 	ldo		R%PA(pg0)(%r1),%r1
 	ldo		_PAGE_TABLE(%r1),%r3
+
 	ldil		L%PA(swapper_pg_dir),%r4
 	ldo		R%PA(swapper_pg_dir)(%r4),%r4
 	mtctl		%r4,%cr24	/* Initialize kernel root pointer */
 	mtctl		%r4,%cr25	/* Initialize user root pointer */
-	stw		%r3,0xc00(%r4)	/* Hardwired 0xc0000000 kernel vaddr start */
+
+#if (__PAGE_OFFSET != 0x10000000UL)
+Error! Code below (the next two stw's) needs to be changed
+#endif
+
+	stw             %r3,0x100(%r4)  /* Hardwired 0x1... kernel Vaddr start*/
 	ldo		0x1000(%r3),%r3
-	stw		%r3,0xc04(%r4)
-	ldo		_PAGE_KERNEL(%r0),%r3 /* Hardwired 0x0 phys addr start */
+	stw             %r3,0x104(%r4)
+	ldo		_PAGE_KERNEL(%r0),%r3 /* Hardwired 0 phys addr start */
 $pgt_fill_loop:
 	stwm		%r3,4(%r1)
 	ldo		0x1000(%r3),%r3
 	bb,>=		%r3,8,$pgt_fill_loop
 	nop
 
+
+	/* Load the return address...er...crash 'n burn */
+	copy		%r0,%r2
+
+	/* And the RFI Target address too */
+	ldil            L%start_kernel,%r11
+	ldo             R%start_kernel(%r11),%r11
+
+	/* And the initial task pointer */
+
+	ldil            L%init_task_union,%r6
+	ldo             R%init_task_union(%r6),%r6
+	mtctl           %r6,%cr30
+
+	/* And the stack pointer too */
+
+	ldo             TASK_SZ_ALGN(%r6),%sp
+
+	/* And the interrupt stack */
+
+	ldil            L%interrupt_stack,%r6
+	ldo             R%interrupt_stack(%r6),%r6
+	mtctl           %r6,%cr31
+
+#ifdef CONFIG_SMP
+	/* Set the smp rendevous address into page zero.
+	** It would be safer to do this in init_smp_config() but
+	** it's just way easier to deal with here because
+	** of 64-bit function ptrs and the address is local to this file.
+	*/
+	ldil		L%PA(smp_slave_stext),%r10
+	ldo		R%PA(smp_slave_stext)(%r10),%r10
+	stw		%r10,0x10(%r0)	/* MEM_RENDEZ */
+	stw		%r0,0x28(%r0)	/* MEM_RENDEZ_HI - assume addr < 4GB */
+
+	/* FALLTHROUGH */
+	.procend
+
+	/*
+	** Code Common to both Monarch and Slave processors.
+	** Entry:
+	**    %r11 must contain RFI target address.
+	**    %r25/%r26 args to pass to target function
+	**    %r2  in case rfi target decides it didn't like something
+	**
+	** Caller must init: SR4-7, %sp, %r10, %cr24/25, 
+	*/
+common_stext:
+	.proc
+	.callinfo
+#else
+	/* Clear PDC entry point - we won't use it */
+	stw		%r0,0x10(%r0)	/* MEM_RENDEZ */
+	stw		%r0,0x28(%r0)	/* MEM_RENDEZ_HI */
+#endif
+
+	/* PARANOID: clear user scratch/user space SR's */
+	mtsp	%r0,%sr0
+	mtsp	%r0,%sr1
+	mtsp	%r0,%sr2
+	mtsp	%r0,%sr3
+
+	/* Initialize Protection Registers */
+	mtctl	%r0,%cr8
+	mtctl	%r0,%cr9
+	mtctl	%r0,%cr12
+	mtctl	%r0,%cr13
+
 	/* Initialize the global data pointer */
 	ldil		L%$global$,%dp
 	ldo		R%$global$(%dp),%dp
-	
-	/* And the stack pointer, physical too */
-	ldil		L%init_task_union+TASK_SZ_ALGN,%sp
-	ldo		R%init_task_union+TASK_SZ_ALGN(%sp),%sp
-
-	/* we need this to take interruptions directly after the rfi below */
-	/* (which we need for PA2.0 boxes) */
-	mtctl		%r0, %cr30
-	
+
 	/*
 	 * Set up our interrupt table.  HPMCs might not work after this! 
 	 *
@@ -96,7 +188,6 @@
 	 * following short sequence of instructions can determine this
 	 * (without being illegal on a PA1.1 machine).
 	 */
-	
 	ldi		32,%r10
 	mtctl		%r10,%cr11
 	.level 2.0
@@ -114,30 +205,30 @@
 $install_iva:
 	mtctl		%r10,%cr14
 
-	/* Disable (most) interruptions */
-	mtsm		%r0			
-	
+	/* Disable Q bit so we can load the iia queue */
+	rsm            PSW_SM_Q,%r0
+
 	/* kernel PSW:
-	 *  - no interruptions except for HPMC and TOC (which are handled by PDC)
+	 *  - no interruptions except HPMC and TOC (which are handled by PDC)
 	 *  - Q bit set (IODC / PDC interruptions)
 	 *  - big-endian
 	 *  - virtually mapped
 	 */
-
 	ldil		L%KERNEL_PSW,%r10
 	ldo		R%KERNEL_PSW(%r10),%r10
 	mtctl		%r10,%ipsw
-	
-	/* Set the space pointers for the post-RFI world */
-	mtctl		%r0,%cr17		/* Clear two-level IIA Space Queue */
-	mtctl		%r0,%cr17		/*    effectively setting kernel space. */
-
-	/* And the return address(es) too */
-	ldil		L%start_parisc,%r10
-	ldo		R%start_parisc(%r10),%r10
-	mtctl		%r10,%cr18
-	ldo		4(%r10),%r10
-	mtctl		%r10,%cr18
+
+	/* Set the space pointers for the post-RFI world
+	** Clear the two-level IIA Space Queue, effectively setting
+	** Kernel space.
+	*/
+	mtctl		%r0,%cr17
+	mtctl		%r0,%cr17
+
+	/* Load RFI target into PC queue */
+	mtctl		%r11,%cr18
+	ldo		4(%r11),%r11
+	mtctl		%r11,%cr18
 
 	/* Jump to hyperspace */
 	rfi
@@ -145,6 +236,71 @@
 
 	.procend
 
+#ifdef CONFIG_SMP
+
+	.import smp_init_current_idle_task,data
+	.import	smp_callin,code
+
+smp_callin_rtn:
+        .proc
+	.callinfo
+	break	1,1		/*  Break if returned from start_secondary */
+	nop
+	nop
+        .procend
+
+/***************************************************************************
+*
+* smp_slave_stext is executed by all non-monarch Processors when the Monarch
+* pokes the slave CPUs in smp.c:smp_boot_cpus().
+*
+* Once here, registers values are initialized in order to branch to virtual
+* mode. Once all available/eligible CPUs are in virtual mode, all are
+* released and start out by executing their own idle task.
+*****************************************************************************/
+
+
+smp_slave_stext:
+        .proc
+	.callinfo
+
+	/*
+	** Initialize Space registers
+	*/
+	mtsp	   %r0,%sr4
+	mtsp	   %r0,%sr5
+	mtsp	   %r0,%sr6
+	mtsp	   %r0,%sr7
+
+	/*  Initialize the SP - monarch sets up smp_init_current_idle_task */
+	ldil		L%PA(smp_init_current_idle_task),%sp
+	ldo		R%PA(smp_init_current_idle_task)(%sp),%sp
+	ldw		0(%sp),%sp	/* load task address */
+	mtctl           %sp,%cr30       /* store in cr30 */
+	addil		L%TASK_SZ_ALGN,%sp	/* stack is above task */
+	ldo		R%TASK_SZ_ALGN(%r1),%sp
+
+	/* point CPU to kernel page tables */
+	ldil		L%PA(swapper_pg_dir),%r4
+	ldo		R%PA(swapper_pg_dir)(%r4),%r4
+	mtctl		%r4,%cr24	/* Initialize kernel root pointer */
+	mtctl		%r4,%cr25	/* Initialize user root pointer */
+
+	/* Load RFI *return* address in case smp_callin bails */
+	ldil		L%smp_callin_rtn,%r2
+	ldo		R%smp_callin_rtn(%r2),%r2
+
+	/* Load RFI target address.  */
+	ldil		L%smp_callin,%r11
+	ldo		R%smp_callin(%r11),%r11
+	
+	/* ok...common code can handle the rest */
+	b		common_stext
+	nop
+
+	.procend
+#endif /* CONFIG_SMP */
+
 	.data
 
 	.align	4
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/head64.S linux-2.4.20/arch/parisc/kernel/head64.S
--- linux-2.4.19/arch/parisc/kernel/head64.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/head64.S	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,333 @@
+/*
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999 by Helge Deller
+ * Copyright 1999 SuSE GmbH (Philipp Rumpf)
+ * Copyright 1999 Philipp Rumpf (prumpf@tux.org)
+ * Copyright 2000 Hewlett Packard (Paul Bame, bame@puffin.external.hp.com)
+ * Copyright (C) 2001 Grant Grundler (Hewlett Packard)
+ *
+ * Initial Version 04-23-1999 by Helge Deller <deller@gmx.de>
+ */
+
+
+#include <linux/autoconf.h>	/* for CONFIG_SMP */
+
+#include <asm/offset.h>
+#include <asm/psw.h>
+
+#include <asm/assembly.h>
+#include <asm/pgtable.h>
+#include <asm/pdc.h>		/* for PDC_PSW defines */
+
+
+	.level 2.0
+
+	.section	.initcall.init
+	.align		4
+	.export __initcall_start
+__initcall_start:
+	.export __initcall_end
+__initcall_end:
+	.export __setup_start
+__setup_start:
+	.export __setup_end
+__setup_end:
+
+	.data
+
+	.export boot_args
+boot_args:
+	.word 0 /* arg0 */
+	.word 0 /* arg1 */
+	.word 0 /* arg2 */
+	.word 0 /* arg3 */
+
+	.text
+	.align	4	
+
+	.export stext
+	.export _stext,data		/* Kernel want it this way! */
+_stext:
+stext:
+	.proc
+	.callinfo
+
+	/* Make sure sr4-sr7 are set to zero for the kernel address space */
+	mtsp	%r0,%sr4
+	mtsp	%r0,%sr5
+	mtsp	%r0,%sr6
+	mtsp	%r0,%sr7
+
+	/* Clear BSS (shouldn't the boot loader do this?) */
+
+	.import _edata,data
+	.import _end,data
+
+	ldil            L%PA(_edata),%r3
+	ldo             R%PA(_edata)(%r3),%r3
+	ldil            L%PA(_end),%r4
+	ldo             R%PA(_end)(%r4),%r4
+$bss_loop:
+	cmpb,<<,n       %r3,%r4,$bss_loop
+	stb,ma          %r0,1(%r3)
+
+	/* Save away the arguments the boot loader passed in (32 bit args) */
+
+	ldil            L%PA(boot_args),%r1
+	ldo             R%PA(boot_args)(%r1),%r1
+	stw,ma          %arg0,4(%r1)
+	stw,ma          %arg1,4(%r1)
+	stw,ma          %arg2,4(%r1)
+	stw,ma          %arg3,4(%r1)
+
+	/* Initialize startup VM. Just map first 8 MB of memory */
+
+	ldil		L%PA(pg0),%r1
+	ldo		R%PA(pg0)(%r1),%r1
+
+	ldil		L%PA(pmd0),%r5
+	ldo		R%PA(pmd0)(%r5),%r5
+	ldo		_PAGE_TABLE(%r5),%r3
+
+	ldil		L%PA(swapper_pg_dir),%r4
+	ldo		R%PA(swapper_pg_dir)(%r4),%r4
+
+	mtctl		%r4,%cr24	/* Initialize kernel root pointer */
+	mtctl		%r4,%cr25	/* Initialize user root pointer */
+
+#if (__PAGE_OFFSET != 0x10000000UL)
+Error! Code below (the next five std's) needs to be changed
+#endif
+
+	std             %r3,0x00(%r4)   /* Hardwired 0x1... kernel Vaddr start*/
+
+	ldo		_PAGE_TABLE(%r1),%r3
+	std             %r3,0x400(%r5)  /* Hardwired 0x1... kernel Vaddr start*/
+	ldo		0x1000(%r3),%r3
+	std             %r3,0x408(%r5)
+	ldo		0x1000(%r3),%r3
+	std             %r3,0x410(%r5)
+	ldo		0x1000(%r3),%r3
+	std             %r3,0x418(%r5)
+
+	ldo		_PAGE_KERNEL(%r0),%r3 /* Hardwired 0 phys addr start */
+$pgt_fill_loop:
+	std,ma		%r3,8(%r1)
+	ldo		0x1000(%r3),%r3
+	bb,>=		%r3,8,$pgt_fill_loop
+	nop
+
+	/* And the RFI Target address too */
+	load32          start_kernel, %r11
+
+	/* And the stack pointer too */
+	load32		PA(init_task_union+TASK_SZ_ALGN),%sp
+
+	/* And the initial task pointer */
+
+	load32          init_task_union,%r6
+	mtctl           %r6,%cr30
+
+	/* And the interrupt stack */
+
+	load32          interrupt_stack,%r6
+	mtctl           %r6,%cr31
+
+	/* Act like PDC just called us - that's how slave CPUs enter */
+#define MEM_PDC_LO 0x388
+#define MEM_PDC_HI 0x35C
+	ldw		MEM_PDC_LO(%r0),%r3
+	ldw		MEM_PDC_HI(%r0),%r6
+	depd		%r6, 31, 32, %r3	/* move to upper word */
+
+#ifdef CONFIG_SMP
+	/* Set the smp rendevous address into page zero.
+	** It would be safer to do this in init_smp_config() but
+	** it's just way easier to deal with here because
+	** of 64-bit function ptrs and the address is local to this file.
+	*/
+	ldil		L%PA(smp_slave_stext),%r10
+	ldo		R%PA(smp_slave_stext)(%r10),%r10
+	stw		%r10,0x10(%r0)	/* MEM_RENDEZ */
+	stw		%r0,0x28(%r0)	/* MEM_RENDEZ_HI - assume addr < 4GB */
+
+	/* FALLTHROUGH */
+	.procend
+
+	/*
+	** Code Common to both Monarch and Slave processors.
+	** Entry:
+	**    %r3	PDCE_PROC address
+	**    %r11	RFI target address.
+	**
+	** Caller must init: SR4-7, %sp, %r10, %cr24/25, 
+	*/
+common_stext:
+	.proc
+	.callinfo
+#else /* CONFIG_SMP */
+	/* Clear PDC's CPU handoff address - we won't use it */
+	stw		%r0,0x10(%r0)	/* MEM_RENDEZ */
+	stw		%r0,0x28(%r0)	/* MEM_RENDEZ_HI */
+#endif /* CONFIG_SMP */
+
+	/* Save the rfi target address */
+	std		%r11,  TASK_PT_GR11-TASK_SZ_ALGN(%sp)
+
+#ifndef CONFIG_PDC_NARROW
+	/* Switch to wide mode; Superdome doesn't support narrow PDC
+	** calls.
+	*/
+1:	mfia		%rp		/* clear upper part of pcoq */
+	ldo		2f-1b(%rp),%rp
+	depdi		0,31,32,%rp
+	bv		(%rp)
+	ssm		PSW_SM_W,%r0
+2:
+#endif /* CONFIG_PDC_NARROW */
+
+	/* Set Wide mode as the "Default" (eg for traps)
+	** First trap occurs *right* after (or part of) rfi for slave CPUs.
+	** Someday, palo might not do this for the Monarch either.
+	*/
+
+	ldo		PDC_PSW(%r0),%arg0		/* 21 */
+	ldo		PDC_PSW_SET_DEFAULTS(%r0),%arg1	/* 2 */
+	ldo		PDC_PSW_WIDE_BIT(%r0),%arg2	/* 2 */
+
+	load32		PA(stext_pdc_ret), %rp
+
+	bv		(%r3)
+	copy		%r0,%arg3
+
+stext_pdc_ret:
+	/* restore rfi target address*/
+	ldd		TASK_PT_GR11-TASK_SZ_ALGN(%sp), %r11
+
+	/* PARANOID: clear user scratch/user space SR's */
+	mtsp	%r0,%sr0
+	mtsp	%r0,%sr1
+	mtsp	%r0,%sr2
+	mtsp	%r0,%sr3
+
+	/* Initialize Protection Registers */
+	mtctl	%r0,%cr8
+	mtctl	%r0,%cr9
+	mtctl	%r0,%cr12
+	mtctl	%r0,%cr13
+
+	/* Prepare to RFI! Man all the cannons! */
+	tovirt_r1       %sp
+
+	/* Initialize the global data pointer */
+	load32		__gp,%dp
+
+	/* Set up our interrupt table.  HPMCs might not work after this! */
+	ldil		L%PA(fault_vector_20),%r10
+	ldo		R%PA(fault_vector_20)(%r10),%r10
+	mtctl		%r10,%cr14
+
+	b		aligned_rfi
+	nop
+
+	/* the magic spell */
+	.align          256
+aligned_rfi:
+	ssm		0,0
+	nop		/* 1 */
+	nop		/* 2 */
+	nop		/* 3 */
+	nop		/* 4 */
+	nop		/* 5 */
+	nop		/* 6 */
+	nop		/* 7 */
+	nop		/* 8 */
+
+	/* turn off troublesome PSW bits */
+	rsm		PSW_Q+PSW_I+PSW_D+PSW_P+PSW_R, %r0
+
+	/* kernel PSW:
+	 *  - no interruptions except HPMC and TOC (which are handled by PDC)
+	 *  - Q bit set (IODC / PDC interruptions)
+	 *  - big-endian
+	 *  - virtually mapped
+	 */
+	load32		KERNEL_PSW,%r10
+	mtctl		%r10,%ipsw
+
+	/* Set the space pointers for the post-RFI world
+	** Clear the two-level IIA Space Queue, effectively setting
+	** Kernel space.
+	*/
+	mtctl		%r0,%cr17
+	mtctl		%r0,%cr17
+
+	/* Load RFI target into PC queue */
+	mtctl		%r11,%cr18
+	ldo		4(%r11),%r11
+	mtctl		%r11,%cr18
+
+	/* Jump to hyperspace */
+	rfi
+	nop
+
+	.procend
+
+
+#ifdef CONFIG_SMP
+
+	.import smp_init_current_idle_task,data
+	.import	smp_callin,code
+
+/***************************************************************************
+*
+* smp_slave_stext is executed by all non-monarch Processors when the Monarch
+* pokes the slave CPUs in smp.c:smp_boot_cpus().
+*
+* Once here, registers values are initialized in order to branch to virtual
+* mode. Once all available/eligible CPUs are in virtual mode, all are
+* released and start out by executing their own idle task.
+*****************************************************************************/
+
+
+smp_slave_stext:
+        .proc
+	.callinfo
+
+	/*
+	** Initialize Space registers
+	*/
+	mtsp	   %r0,%sr4
+	mtsp	   %r0,%sr5
+	mtsp	   %r0,%sr6
+	mtsp	   %r0,%sr7
+
+	/*  Initialize the SP - monarch sets up smp_init_current_idle_task */
+	load32		PA(smp_init_current_idle_task),%sp
+	ldd		0(%sp),%sp	/* load task address */
+	mtctl           %sp,%cr30       /* store in cr30 */
+	ldo             TASK_SZ_ALGN(%sp),%sp
+	tophys_r1       %sp
+
+	/* point CPU to kernel page tables */
+	load32		PA(swapper_pg_dir),%r4
+	mtctl		%r4,%cr24	/* Initialize kernel root pointer */
+	mtctl		%r4,%cr25	/* Initialize user root pointer */
+
+	/* Setup PDCE_PROC entry */
+	copy		%arg0,%r3
+
+	/* Load RFI target address.  */
+	load32		smp_callin, %r11
+	
+	/* ok...common code can handle the rest */
+	b		common_stext
+	nop
+
+	.procend
+#endif /* CONFIG_SMP */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/hpmc.S linux-2.4.20/arch/parisc/kernel/hpmc.S
--- linux-2.4.19/arch/parisc/kernel/hpmc.S	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/hpmc.S	2002-10-29 11:18:36.000000000 +0000
@@ -43,7 +43,6 @@
 	.level		1.1
 	.data
 
-#define __ASSEMBLY__
 #include <asm/assembly.h>
 #include <asm/pdc.h>
 
@@ -262,12 +261,10 @@
 	mtsp	%r0, %sr6
 	mtsp	%r0, %sr7
 
-	tovirt  %r30        /* make sp virtual */
+	tovirt_r1 %r30      /* make sp virtual */
 
 	rsm 8,%r0           /* Clear Q bit */
-	ldi     1,%r1
-	mtctl   %r1,%cr29   /* Set trap code to "1" for HPMC */
-	mtctl   %r0,%cr30   /* Force interruptions to use hpmc stack */
+	ldi     1,%r8       /* Set trap code to "1" for HPMC */
 	ldil    L%PA(intr_save), %r1
 	ldo     R%PA(intr_save)(%r1), %r1
 	be      0(%sr7,%r1)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/init_task.c linux-2.4.20/arch/parisc/kernel/init_task.c
--- linux-2.4.19/arch/parisc/kernel/init_task.c	2001-09-17 22:29:09.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/init_task.c	2002-10-29 11:18:31.000000000 +0000
@@ -18,10 +18,11 @@
  * way process stacks are handled. This is done by having a special
  * "init_task" linker map entry..
  */
+unsigned char interrupt_stack[ISTACK_SIZE] __attribute__ ((section("init_istack"), aligned(4096)));
 union task_union init_task_union 
 	__attribute__((section("init_task"), aligned(4096))) = { INIT_TASK(init_task_union.task) };
 
-unsigned long swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((aligned(4096))) = { 0, };
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((aligned(4096))) = { {0}, };
 #ifdef __LP64__
 unsigned long pmd0[PTRS_PER_PMD] __attribute__ ((aligned(4096))) = { 0, };
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/inventory.c linux-2.4.20/arch/parisc/kernel/inventory.c
--- linux-2.4.19/arch/parisc/kernel/inventory.c	2000-12-06 19:46:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/inventory.c	2002-10-29 11:18:32.000000000 +0000
@@ -1,40 +1,157 @@
-
-/* Copyright (c) 1999 The Puffin Group */
-/* Written by David Kennedy and Alex deVries */
+/*
+ * inventory.c
+ *
+ * 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.
+ *
+ * Copyright (c) 1999 The Puffin Group (David Kennedy and Alex deVries)
+ * Copyright (c) 2001 Matthew Wilcox for Hewlett-Packard
+ *
+ * These are the routines to discover what hardware exists in this box.
+ * This task is complicated by there being 3 different ways of
+ * performing an inventory, depending largely on the age of the box.
+ * The recommended way to do this is to check to see whether the machine
+ * is a `Snake' first, then try System Map, then try PAT.  We try System
+ * Map before checking for a Snake -- this probably doesn't cause any
+ * problems, but...
+ */
 
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/pdc.h>
+#include <asm/processor.h>
+#include <asm/page.h>
 
 /*
 ** Debug options
-**    DEBUG_PAT	Dump details which PDC PAT provides about ranges/devices.
+** DEBUG_PAT Dump details which PDC PAT provides about ranges/devices.
 */
 #undef DEBUG_PAT
 
-extern char *parisc_getHWtype(unsigned short hw_type);
+int pdc_type = PDC_TYPE_ILLEGAL;
+
+void __init setup_pdc(void)
+{
+	long status;
+	unsigned int bus_id;
+	struct pdc_system_map_mod_info module_result;
+	struct pdc_module_path module_path;
+	struct pdc_model model;
+#ifdef __LP64__
+	struct pdc_pat_cell_num cell_info;
+#endif
 
-extern struct hp_device * register_module(void *hpa);
-extern void print_devices(char * buf);
+	/* Determine the pdc "type" used on this machine */
 
+	printk(KERN_INFO "Determining PDC firmware type: ");
 
-int pdc_hpa_processor(void *address);
+	status = pdc_system_map_find_mods(&module_result, &module_path, 0);
+	if (status == PDC_OK) {
+		pdc_type = PDC_TYPE_SYSTEM_MAP;
+		printk("System Map.\n");
+		return;
+	}
 
-#ifndef __LP64__ 
-static	u8 iodc_data[32] __attribute__ ((aligned (64)));
-static	struct pdc_model model __attribute__ ((aligned (8)));
+	/*
+	 * If the machine doesn't support PDC_SYSTEM_MAP then either it
+	 * is a pdc pat box, or it is an older box. All 64 bit capable
+	 * machines are either pdc pat boxes or they support PDC_SYSTEM_MAP.
+	 */
+
+	/*
+	 * TODO: We should test for 64 bit capability and give a
+	 * clearer message.
+	 */
+
+#ifdef __LP64__
+	status = pdc_pat_cell_get_number(&cell_info);
+	if (status == PDC_OK) {
+		pdc_type = PDC_TYPE_PAT;
+		printk("64 bit PAT.\n");
+		return;
+	}
 #endif
-static	unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0};
-static	struct pdc_hpa processor_hpa __attribute__ ((aligned (8)));
-static	struct pdc_system_map module_result __attribute__ ((aligned (8)));
-static	struct pdc_module_path module_path __attribute__ ((aligned (8)));
+
+	/* Check the CPU's bus ID.  There's probably a better test.  */
+
+	status = pdc_model_info(&model);
+
+	bus_id = (model.hversion >> (4 + 7)) & 0x1f;
+
+	switch (bus_id) {
+	case 0x4:		/* 720, 730, 750, 735, 755 */
+	case 0x6:		/* 705, 710 */
+	case 0x7:		/* 715, 725 */
+	case 0x8:		/* 745, 747, 742 */
+	case 0xA:		/* 712 and similiar */
+	case 0xC:		/* 715/64, at least */
+
+		pdc_type = PDC_TYPE_SNAKE;
+		printk("Snake.\n");
+		return;
+
+	default:		/* Everything else */
+
+		printk("Unsupported.\n");
+		panic("If this is a 64-bit machine, please try a 64-bit kernel.\n");
+	}
+}
+
+#define PDC_PAGE_ADJ_SHIFT (PAGE_SHIFT - 12) /* pdc pages are always 4k */
+
+static void __init
+set_pmem_entry(physmem_range_t *pmem_ptr, unsigned long start,
+	       unsigned long pages4k)
+{
+	/* Rather than aligning and potentially throwing away
+	 * memory, we'll assume that any ranges are already
+	 * nicely aligned with any reasonable page size, and
+	 * panic if they are not (it's more likely that the
+	 * pdc info is bad in this case).
+	 */
+
+	if (   ((start & (PAGE_SIZE - 1)) != 0)
+	    || ((pages4k & ((1UL << PDC_PAGE_ADJ_SHIFT) - 1)) != 0) ) {
+
+		panic("Memory range doesn't align with page size!\n");
+	}
+
+	pmem_ptr->start_pfn = (start >> PAGE_SHIFT);
+	pmem_ptr->pages = (pages4k >> PDC_PAGE_ADJ_SHIFT);
+}
+
+static void __init pagezero_memconfig(void)
+{
+	unsigned long npages;
+
+	/* Use the 32 bit information from page zero to create a single
+	 * entry in the pmem_ranges[] table.
+	 *
+	 * We currently don't support machines with contiguous memory
+	 * >= 4 Gb, who report that memory using 64 bit only fields
+	 * on page zero. It's not worth doing until it can be tested,
+	 * and it is not clear we can support those machines for other
+	 * reasons.
+	 *
+	 * If that support is done in the future, this is where it
+	 * should be done.
+	 */
+
+	npages = (PAGE_ALIGN(PAGE0->imm_max_mem) >> PAGE_SHIFT);
+	set_pmem_entry(pmem_ranges,0UL,npages);
+	npmem_ranges = 1;
+}
 
 #ifdef __LP64__
-#include <asm/pdcpat.h>
 
-int pdc_pat = 0;
+/* All of the PDC PAT specific code is 64-bit only */
 
 /*
 **  The module object is filled via PDC_PAT_CELL[Return Cell Module].
@@ -47,30 +164,37 @@
 **
 */
 
-static int
-pat_query_module( ulong pcell_loc, ulong mod_index)
+static int __init 
+pat_query_module(ulong pcell_loc, ulong mod_index)
 {
-	extern int num_devices;
-	extern struct hp_device devices[];
-
 	pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;
-        struct hp_device * dev = &devices[num_devices];
-	uint64_t temp;             /* 64-bit scratch value */
-	long status;               /* PDC return value status */
+	pdc_pat_cell_mod_maddr_block_t io_pdc_cell;
+	unsigned long bytecnt;
+	unsigned long temp;	/* 64-bit scratch value */
+	long status;		/* PDC return value status */
+	struct parisc_device *dev;
 
 	/* return cell module (PA or Processor view) */
-	status = pdc_pat_cell_module(& pdc_result, pcell_loc, mod_index,
-		PA_VIEW, & pa_pdc_cell);
+	status = pdc_pat_cell_module(&bytecnt, pcell_loc, mod_index,
+				     PA_VIEW, &pa_pdc_cell);
 
-	if (status != PDC_RET_OK) {
+	if (status != PDC_OK) {
 		/* no more cell modules or error */
 		return status;
 	}
 
+	temp = pa_pdc_cell.cba;
+	dev = alloc_pa_dev(PAT_GET_CBA(temp), &pa_pdc_cell.mod_path);
+	if (!dev) {
+		return PDC_NE_MOD;
+	}
+
+	/* alloc_pa_dev sets dev->hpa */
+
 	/*
-	** save parameters in the hp_device
+	** save parameters in the parisc_device
 	** (The idea being the device driver will call pdc_pat_cell_module()
-	** and store the results in it's own data structure.)
+	** and store the results in its own data structure.)
 	*/
 	dev->pcell_loc = pcell_loc;
 	dev->mod_index = mod_index;
@@ -79,319 +203,410 @@
 	/* REVISIT: who is the consumer of this? not sure yet... */
 	dev->mod_info = pa_pdc_cell.mod_info;	/* pass to PAT_GET_ENTITY() */
 	dev->pmod_loc = pa_pdc_cell.mod_location;
-	dev->mod_path = pa_pdc_cell.mod_path;
 
-	temp = pa_pdc_cell.cba;
-	register_module((void *) PAT_GET_CBA(temp));	/* fills in dev->hpa */
+	register_parisc_device(dev);	/* advertise device */
 
 #ifdef DEBUG_PAT
 	/* dump what we see so far... */
 	switch (PAT_GET_ENTITY(dev->mod_info)) {
-		ulong i;
+		unsigned long i;
 
 	case PAT_ENTITY_PROC:
-		printk ("PAT_ENTITY_PROC: id_eid 0x%lx\n", pa_pdc_cell.mod[0]);
+		printk(KERN_DEBUG "PAT_ENTITY_PROC: id_eid 0x%lx\n",
+			pa_pdc_cell.mod[0]);
 		break;
 
 	case PAT_ENTITY_MEM:
-		printk ("PAT_ENTITY_MEM: amount 0x%lx min_gni_base 0x%lx min_gni_len 0x%lx\n",
-			pa_pdc_cell.mod[0],
-			pa_pdc_cell.mod[1],
+		printk(KERN_DEBUG 
+			"PAT_ENTITY_MEM: amount 0x%lx min_gni_base 0x%lx min_gni_len 0x%lx\n",
+			pa_pdc_cell.mod[0], pa_pdc_cell.mod[1], 
 			pa_pdc_cell.mod[2]);
 		break;
 	case PAT_ENTITY_CA:
-		printk ("PAT_ENTITY_CA: %ld\n",pcell_loc);
+		printk(KERN_DEBUG "PAT_ENTITY_CA: %ld\n", pcell_loc);
 		break;
 
 	case PAT_ENTITY_PBC:
-		printk ("PAT_ENTITY_PBC: ");
+		printk(KERN_DEBUG "PAT_ENTITY_PBC: ");
 		goto print_ranges;
 
 	case PAT_ENTITY_SBA:
-		printk ("PAT_ENTITY_SBA: ");
+		printk(KERN_DEBUG "PAT_ENTITY_SBA: ");
 		goto print_ranges;
 
 	case PAT_ENTITY_LBA:
-		printk ("PAT_ENTITY_LBA: ");
+		printk(KERN_DEBUG "PAT_ENTITY_LBA: ");
 
-print_ranges:
-		printk ("ranges %ld\n", pa_pdc_cell.mod[1]);
+ print_ranges:
+		pdc_pat_cell_module(&bytecnt, pcell_loc, mod_index,
+				    IO_VIEW, &io_pdc_cell);
+		printk(KERN_DEBUG "ranges %ld\n", pa_pdc_cell.mod[1]);
 		for (i = 0; i < pa_pdc_cell.mod[1]; i++) {
-			printk ("	%ld: 0x%016lx 0x%016lx 0x%016lx\n", i,
-				pa_pdc_cell.mod[2+i*3],	/* type */
-				pa_pdc_cell.mod[3+i*3],	/* start */
-				pa_pdc_cell.mod[4+i*3]);	/* finish (ie end) */
+			printk(KERN_DEBUG 
+				"  PA_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n", 
+				i, pa_pdc_cell.mod[2 + i * 3],	/* type */
+				pa_pdc_cell.mod[3 + i * 3],	/* start */
+				pa_pdc_cell.mod[4 + i * 3]);	/* finish (ie end) */
+			printk(KERN_DEBUG 
+				"  IO_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n", 
+				i, io_pdc_cell.mod[2 + i * 3],	/* type */
+				io_pdc_cell.mod[3 + i * 3],	/* start */
+				io_pdc_cell.mod[4 + i * 3]);	/* finish (ie end) */
 		}
-		printk("\n");
+		printk(KERN_DEBUG "\n");
 		break;
 	}
 #endif /* DEBUG_PAT */
-	return PDC_RET_OK;
+	return PDC_OK;
 }
 
 
-static int do_pat_inventory(void)
-{
-	ulong mod_index=0;
-	int status;
-	ulong cell_num;
-	ulong pcell_loc;
+/* pat pdc can return information about a variety of different
+ * types of memory (e.g. firmware,i/o, etc) but we only care about
+ * the usable physical ram right now. Since the firmware specific
+ * information is allocated on the stack, we'll be generous, in
+ * case there is a lot of other information we don't care about.
+ */
 
-	pdc_pat = (pdc_pat_cell_get_number(&pdc_result) == PDC_OK);
-	if (!pdc_pat)
-	{
-		return 0;
-	}
-
-	cell_num = pdc_result[0];	/* Cell number call was made */
-
-	/* As of PDC PAT ARS 2.5, ret[1] is NOT architected! */
-	pcell_loc = pdc_result[1];	/* Physical location of the cell */
-
-#ifdef DEBUG_PAT
-	printk("CELL_GET_NUMBER: 0x%lx 0x%lx\n", cell_num, pcell_loc);
-#endif
-
-        status = pdc_pat_cell_num_to_loc(&pdc_result, cell_num);
-        if (status == PDC_BAD_OPTION)
-	{
-		/* Prelude (and it's successors: Lclass, A400/500) only
-		** implement PDC_PAT_CELL sub-options 0 and 2.
-		** "Home cook'n is best anyhow!"
-		*/
-	} else if (PDC_OK == status) {
-		/* so far only Halfdome supports this */
-		pcell_loc = pdc_result[0];
-	} else {
-		panic("WTF? CELL_GET_NUMBER give me invalid cell number?");
-	}
-
-	while (PDC_RET_OK == pat_query_module(pcell_loc, mod_index))
-	{
-		mod_index++;
-	}
-
-	return mod_index;
-}
-#endif /* __LP64__ */
+#define PAT_MAX_RANGES (4 * MAX_PHYSMEM_RANGES)
 
-static int do_newer_workstation_inventory(void)
+static void __init pat_memconfig(void)
 {
+	unsigned long actual_len;
+	struct pdc_pat_pd_addr_map_entry mem_table[PAT_MAX_RANGES+1];
+	struct pdc_pat_pd_addr_map_entry *mtbl_ptr;
+	physmem_range_t *pmem_ptr;
 	long status;
-	int i, num = 0;
+	int entries;
+	unsigned long length;
+	int i;
+
+	length = (PAT_MAX_RANGES + 1) * sizeof(struct pdc_pat_pd_addr_map_entry);
+
+	status = pdc_pat_pd_get_addr_map(&actual_len, mem_table, length, 0L);
+
+	if ((status != PDC_OK)
+	    || ((actual_len % sizeof(struct pdc_pat_pd_addr_map_entry)) != 0)) {
+
+		/* The above pdc call shouldn't fail, but, just in
+		 * case, just use the PAGE0 info.
+		 */
+
+		printk("\n\n\n");
+		printk(KERN_WARNING "WARNING! Could not get full memory configuration. "
+			"All memory may not be used!\n\n\n");
+		pagezero_memconfig();
+		return;
+	}
 
-	/* So the idea here is to simply try one SYSTEM_MAP call.  If 
-	   that one works, great, otherwise do it another way */
+	entries = actual_len / sizeof(struct pdc_pat_pd_addr_map_entry);
 
-	status = pdc_system_map_find_mods(&module_result,&module_path,0);
+	if (entries > PAT_MAX_RANGES) {
+		printk(KERN_WARNING "This Machine has more memory ranges than we support!\n");
+		printk(KERN_WARNING "Some memory may not be used!\n");
+	}
 
-	if (status == PDC_RET_OK) {
-		/* This is for newer non-PDC-PAT boxes */
+	/* Copy information into the firmware independent pmem_ranges
+	 * array, skipping types we don't care about. Notice we said
+	 * "may" above. We'll use all the entries that were returned.
+	 */
+
+	npmem_ranges = 0;
+	mtbl_ptr = mem_table;
+	pmem_ptr = pmem_ranges; /* Global firmware independent table */
+	for (i = 0; i < entries; i++,mtbl_ptr++) {
+		if (   (mtbl_ptr->entry_type != PAT_MEMORY_DESCRIPTOR)
+		    || (mtbl_ptr->memory_type != PAT_MEMTYPE_MEMORY)
+		    || (mtbl_ptr->pages == 0)
+		    || (   (mtbl_ptr->memory_usage != PAT_MEMUSE_GENERAL)
+			&& (mtbl_ptr->memory_usage != PAT_MEMUSE_GI)
+			&& (mtbl_ptr->memory_usage != PAT_MEMUSE_GNI) ) ) {
 
-		printk("a newer box...\n");
-		for(i=0, status=PDC_RET_OK; status != PDC_RET_NE_PROC && 
-			status != PDC_RET_NE_MOD ;i++) {
+			continue;
+		}
 
-			status = pdc_system_map_find_mods(&module_result,&module_path,i);
-			if (status == PDC_RET_OK) {
-				num++;
-				register_module(module_result.mod_addr);
-			}
+		if (npmem_ranges == MAX_PHYSMEM_RANGES) {
+			printk(KERN_WARNING "This Machine has more memory ranges than we support!\n");
+			printk(KERN_WARNING "Some memory will not be used!\n");
+			break;
 		}
-	}
 
-	return (num > 0);
+		set_pmem_entry(pmem_ptr++,mtbl_ptr->paddr,mtbl_ptr->pages);
+		npmem_ranges++;
+	}
 }
 
-#ifndef __LP64__
-static	struct  pdc_memory_map r_addr __attribute__ ((aligned (8)));
-
-static int really_do_oldhw_inventory(void)
+static int __init pat_inventory(void)
 {
-	int i, mod, num = 0;
 	int status;
-	unsigned int hw_type;
-	unsigned int func;
+	ulong mod_index = 0;
+	struct pdc_pat_cell_num cell_info;
 
-	/* This is undocumented at the time of writing, but basically 
-	   we're setting up mod_path so that bc[0..4]=0xff, and step
-	   through mod to get the "Path Structure for GSC Modules".  If
-	   it works, use the returned HPA and determine the hardware type.  */
+	/*
+	** Note:  Prelude (and it's successors: Lclass, A400/500) only
+	**        implement PDC_PAT_CELL sub-options 0 and 2.
+	*/
+	status = pdc_pat_cell_get_number(&cell_info);
+	if (status != PDC_OK) {
+		return 0;
+	}
 
-	for (i=0;i<6;i++) module_path.bc[i]=0xff;
+#ifdef DEBUG_PAT
+	printk(KERN_DEBUG "CELL_GET_NUMBER: 0x%lx 0x%lx\n", cell_info.cell_num, 
+	       cell_info.cell_loc);
+#endif
 
-	for (mod=0;mod<16;mod++) {
-		char *stype = NULL;
+	while (PDC_OK == pat_query_module(cell_info.cell_loc, mod_index)) {
+		mod_index++;
+	}
 
-		module_path.mod=mod;
-		status = pdc_mem_map_hpa(&r_addr, &module_path);
-		if (status!=PDC_RET_OK) continue;
-	
-		status = pdc_iodc_read(&pdc_result,(void *) r_addr.hpa,
-			0, &iodc_data,32 );
-		if (status!=PDC_RET_OK) continue;
-		hw_type = iodc_data[3]&0x1f;
+	return mod_index;
+}
 
-		switch (hw_type)
-		{
-		case HPHW_NPROC:	/* 0 */
-			stype="Processor"; break;
+/* We only look for extended memory ranges on a 64 bit capable box */
+static void __init sprockets_memconfig(void)
+{
+	struct pdc_memory_table_raddr r_addr;
+	struct pdc_memory_table mem_table[MAX_PHYSMEM_RANGES];
+	struct pdc_memory_table *mtbl_ptr;
+	physmem_range_t *pmem_ptr;
+	long status;
+	int entries;
+	int i;
 
-		case HPHW_MEMORY:	/* 1 */
-			stype="Memory"; break;
+	status = pdc_mem_mem_table(&r_addr,mem_table,
+				(unsigned long)MAX_PHYSMEM_RANGES);
 
-		case HPHW_B_DMA:	/* 2 */
-			stype="Type B DMA"; break;
+	if (status != PDC_OK) {
 
-		case HPHW_A_DMA:	/* 4 */
-			stype="Type A DMA"; break;
+		/* The above pdc call only works on boxes with sprockets
+		 * firmware (newer B,C,J class). Other non PAT PDC machines
+		 * do support more than 3.75 Gb of memory, but we don't
+		 * support them yet.
+		 */
 
-		case HPHW_A_DIRECT:	/* 5 */
-			stype="Type A Direct"; break;
+		pagezero_memconfig();
+		return;
+	}
+
+	if (r_addr.entries_total > MAX_PHYSMEM_RANGES) {
+		printk(KERN_WARNING "This Machine has more memory ranges than we support!\n");
+		printk(KERN_WARNING "Some memory will not be used!\n");
+	}
 
-		case HPHW_BCPORT:	/* 7 */
-			stype="Bus Converter Port"; break;
+	entries = (int)r_addr.entries_returned;
 
-		case HPHW_CONSOLE:	/* 9 */
-			stype="Console"; break;
+	npmem_ranges = 0;
+	mtbl_ptr = mem_table;
+	pmem_ptr = pmem_ranges; /* Global firmware independent table */
+	for (i = 0; i < entries; i++,mtbl_ptr++) {
+		set_pmem_entry(pmem_ptr++,mtbl_ptr->paddr,mtbl_ptr->pages);
+		npmem_ranges++;
+	}
+}
 
-		case HPHW_FIO:		/* 10 - Graphics */
-			stype="Foreign I/O (Graphics)"; break;
+#else   /* !__LP64__ */
 
-		case HPHW_BA:		/* 11 - Bus Adapter */
-			stype="Bus Adapter"; break;
+#define pat_inventory() do { } while (0)
+#define pat_memconfig() do { } while (0)
+#define sprockets_memconfig() pagezero_memconfig()
 
-		case HPHW_IOA:		/* 12 */
-			stype="I/O Adapter"; break;
+#endif	/* !__LP64__ */
 
-		case HPHW_BRIDGE:	/* 13 */
-			stype="Bridge"; break;
 
-		case HPHW_FABRIC:	/* 14 */
-			stype="Fabric"; break;
+#ifndef CONFIG_PA20
 
-		case HPHW_FAULTY:	/* 31 */
-			stype="Faulty HW"; break;
+/* Code to support Snake machines (7[2350], 7[235]5, 715/Scorpio) */
 
-		case HPHW_OTHER:	/* 42 */
-		default:	
-			printk("Don't know this hw_type: %d\n", hw_type);
-			break;
-		}
+static struct parisc_device * __init
+legacy_create_device(struct pdc_memory_map *r_addr,
+		struct pdc_module_path *module_path)
+{
+	struct parisc_device *dev;
+	int status = pdc_mem_map_hpa(r_addr, module_path);
+	if (status != PDC_OK)
+		return NULL;
+
+	dev = alloc_pa_dev(r_addr->hpa, &module_path->path);
+	if (dev == NULL)
+		return NULL;
 
-		// This is kluged. But don't want to replicate code for
-		// most of the above cases.
-		if (stype) {
-#ifdef DBG_PDC_QUERY
-			// parisc/kernel/drivers.c
-			extern int num_devices; 
-			extern struct hp_device devices[];
-			struct hp_hardware *h;
-#endif
+	register_parisc_device(dev);
+	return dev;
+}
 
-			status = pdc_mem_map_hpa(&r_addr, &module_path);
-			if (status==PDC_RET_OK && register_module((void *) r_addr.hpa) != NULL)
-					num++;
-
-
-		    if (hw_type == HPHW_BA) {
-			/* Now, we're checking for devices for each
-			   module.  I seem to think that the
-			   modules in question are Lasi (2), 2nd Lasi (6)
-			   Wax (5).  To do this, set bc[5]=0, and set
-			   bc[4] to the module, and step through the
-			   functions. */
-
-			for (i=0;i<4;i++) module_path.bc[i]=0xff;
-			module_path.bc[4]=mod;
-			for (func=0;func<16;func++) {
-				module_path.mod = func;
-				module_path.bc[5]=0;
-				status = pdc_mem_map_hpa(&r_addr, &module_path);
-				if (status!=PDC_RET_OK) continue;
-				if (register_module((void *) r_addr.hpa) != NULL) 
-					num++;
-			}
+/**
+ * snake_inventory
+ *
+ * Before PDC_SYSTEM_MAP was invented, the PDC_MEM_MAP call was used.
+ * To use it, we initialise the mod_path.bc to 0xff and try all values of
+ * mod to get the HPA for the top-level devices.  Bus adapters may have
+ * sub-devices which are discovered by setting bc[5] to 0 and bc[4] to the
+ * module, then trying all possible functions.
+ */
+static void __init snake_inventory(void)
+{
+	int mod;
+	for (mod = 0; mod < 16; mod++) {
+		struct parisc_device *dev;
+		struct pdc_module_path module_path;
+		struct pdc_memory_map r_addr;
+		unsigned int func;
+
+		memset(module_path.path.bc, 0xff, 6);
+		module_path.path.mod = mod;
+		dev = legacy_create_device(&r_addr, &module_path);
+		if ((!dev) || (dev->id.hw_type != HPHW_BA))
+			continue;
+
+		memset(module_path.path.bc, 0xff, 4);
+		module_path.path.bc[4] = mod;
+
+		for (func = 0; func < 16; func++) {
+			module_path.path.bc[5] = 0;
+			module_path.path.mod = func;
+			legacy_create_device(&r_addr, &module_path);
 		}
-		// reset module_path.bc[]
-		for (i=0;i<6;i++) module_path.bc[i]=0xff;
+	}
+}
 
+#else /* CONFIG_PA20 */
+#define snake_inventory() do { } while (0)
+#endif  /* CONFIG_PA20 */
+
+/* Common 32/64 bit based code goes here */
+
+/**
+ * add_system_map_addresses - Add additional addresses to the parisc device.
+ * @dev: The parisc device.
+ * @num_addrs: Then number of addresses to add;
+ * @module_instance: The system_map module instance.
+ *
+ * This function adds any additional addresses reported by the system_map
+ * firmware to the parisc device.
+ */
+static void __init
+add_system_map_addresses(struct parisc_device *dev, int num_addrs, 
+			 int module_instance)
+{
+	int i;
+	long status;
+	struct pdc_system_map_addr_info addr_result;
 
-#ifdef DBG_PDC_QUERY
-//
-// Let print_devices() dump everything which is registered.
-//
-			h = devices[num_devices-1].reference;
+	dev->addr = kmalloc(num_addrs * sizeof(unsigned long), GFP_KERNEL);
+	if(!dev->addr) {
+		printk(KERN_ERR "%s %s(): memory allocation failure\n",
+		       __FILE__, __FUNCTION__);
+		return;
+	}
 
-			if (h) stype = h->name;
-			printk("Found %s at %d\n", stype, module_path.mod);
-#endif
+	for(i = 1; i <= num_addrs; ++i) {
+		status = pdc_system_map_find_addrs(&addr_result, 
+						   module_instance, i);
+		if(PDC_OK == status) {
+			dev->addr[dev->num_addrs] = (unsigned long)addr_result.mod_addr;
+			dev->num_addrs++;
+		} else {
+			printk(KERN_WARNING 
+			       "Bad PDC_FIND_ADDRESS status return (%ld) for index %d\n",
+			       status, i);
 		}
 	}
-	return num;
 }
 
-static int
-do_old_inventory(void)
+/**
+ * do_system_map_inventory - Retrieve firmware devices via SYSTEM_MAP.
+ *
+ * This function attempts to retrieve and register all the devices firmware
+ * knows about via the SYSTEM_MAP PDC call.
+ */
+static void __init system_map_inventory(void)
 {
-        unsigned int bus_id;
-	long status;
-	int ok = 0;
-
-	printk(" an older box...\n");
+	int i;
+	long status = PDC_OK;
+    
+	/*
+	 * first stop the usb controller, otherwise the machine
+	 * might crash during iommu setup
+	 */
+	pdc_suspend_usb();
+
+	for (i = 0; status != PDC_BAD_PROC && status != PDC_NE_MOD; i++) {
+		struct parisc_device *dev;
+		struct pdc_system_map_mod_info module_result;
+		struct pdc_module_path module_path;
+
+		status = pdc_system_map_find_mods(&module_result,
+				&module_path, i);
+		if (status != PDC_OK)
+			continue;
+		
+		dev = alloc_pa_dev(module_result.mod_addr, &module_path.path);
+		if (!dev)
+			continue;
+		
+		register_parisc_device(dev);
+
+		/* if available, get the additional addresses for a module */
+		if (!module_result.add_addrs)
+			continue;
 
-	/* Here, we're going to check the model, and decide
-	   if we should even bother trying. */
+		add_system_map_addresses(dev, module_result.add_addrs, i);
+	}
 
-	status = pdc_model_info(&model);
+	walk_central_bus();
+	return;
+}
 
-	bus_id = (model.hversion >> (4+7) ) &0x1f;
+void __init do_memory_inventory(void)
+{
+	switch (pdc_type) {
 
-	/* Here, we're checking the HVERSION of the CPU.
-	   We're only checking the 0th CPU, since it'll
-	   be the same on an SMP box. */
+	case PDC_TYPE_PAT:
+		pat_memconfig();
+		break;
 
-	switch (bus_id) {
-		case 0x4: 	/* 720, 730, 750, 735, 755 */
-		case 0x6: 	/* 705, 710 */
-		case 0x7: 	/* 715, 725 */
-		case 0x8: 	/* 745, 747, 742 */
-		case 0xA: 	/* 712 and similiar */
-		case 0xC: 	/* 715/64, at least */
-
-		/* Do inventory using MEM_MAP */
-		really_do_oldhw_inventory();
-		ok = 1;
+	case PDC_TYPE_SYSTEM_MAP:
+		sprockets_memconfig();
 		break;
-	default: 	/* Everything else */
-		printk("This is a very very old machine, with a bus_id of 0x%x.\n",bus_id);
-		panic("This will probably never run Linux.\n");
+
+	case PDC_TYPE_SNAKE:
+		pagezero_memconfig();
+		return;
+
+	default:
+		panic("Unknown PDC type!\n");
 	}
 
-	return ok;
+	if (npmem_ranges == 0 || pmem_ranges[0].start_pfn != 0) {
+		printk(KERN_WARNING "Bad memory configuration returned!\n");
+		printk(KERN_WARNING "Some memory may not be used!\n");
+		pagezero_memconfig();
+	}
 }
 
-#endif /* !__LP64__ */
+void __init do_device_inventory(void)
+{
+	printk(KERN_INFO "Searching for devices...\n");
 
-void do_inventory(void){
-	if((pdc_hpa_processor(&processor_hpa))<0){
-		printk(KERN_INFO "Couldn't get the HPA of the processor.\n" );
-	}
+	switch (pdc_type) {
+
+	case PDC_TYPE_PAT:
+		pat_inventory();
+		break;
 
-	printk("Searching for devices in PDC firmware... ");
-	printk("processor hpa 0x%lx\n", processor_hpa.hpa);
+	case PDC_TYPE_SYSTEM_MAP:
+		system_map_inventory();
+		break;
 
-	if (!(
-		do_newer_workstation_inventory()
-#ifdef __LP64__
-		|| do_pat_inventory()
-#else /* __LP64__ */
-		|| do_old_inventory()
-#endif /* __LP64__ */
-	    ))
-	{
-	    panic("I can't get the hardware inventory on this machine");
+	case PDC_TYPE_SNAKE:
+		snake_inventory();
+		break;
+
+	default:
+		panic("Unknown PDC type!\n");
 	}
-	print_devices(NULL);
-}
 
+	printk(KERN_INFO "Found devices:\n");
+	print_parisc_devices();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/ioctl32.c linux-2.4.20/arch/parisc/kernel/ioctl32.c
--- linux-2.4.19/arch/parisc/kernel/ioctl32.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/ioctl32.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,3758 @@
+/* $Id: ioctl32.c,v 1.12 2002/07/08 20:52:15 grundler Exp $
+ * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
+ *
+ * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
+ * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
+ *
+ * These routines maintain argument size conversion between 32bit and 64bit
+ * ioctls.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include "sys32.h"
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/ioctl.h>
+#include <linux/if.h>
+#include <linux/slab.h>
+#include <linux/hdreg.h>
+#include <linux/raid/md.h>
+#include <linux/kd.h>
+#include <linux/route.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/vt.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/fd.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#include <linux/if_pppox.h>
+#include <linux/mtio.h>
+#include <linux/cdrom.h>
+#include <linux/loop.h>
+#include <linux/auto_fs.h>
+#include <linux/devfs_fs.h>
+#include <linux/tty.h>
+#include <linux/vt_kern.h>
+#include <linux/fb.h>
+#include <linux/ext2_fs.h>
+#include <linux/videodev.h>
+#include <linux/netdevice.h>
+#include <linux/raw.h>
+#include <linux/smb_fs.h>
+#include <linux/blkpg.h>
+#include <linux/blk.h>
+#include <linux/elevator.h>
+#include <linux/rtc.h>
+#include <linux/serial.h>
+#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
+/* Ugh. This header really is not clean */
+/* #define min min
+#define max max */
+#include <linux/lvm.h>
+#endif /* LVM */
+
+#include <scsi/scsi.h>
+/* Ugly hack. */
+#undef __KERNEL__
+#include <scsi/scsi_ioctl.h>
+#define __KERNEL__
+#include <scsi/sg.h>
+
+#include <asm/types.h>
+#include <asm/uaccess.h>
+#include <asm/perf.h>
+#include <linux/ethtool.h>
+#include <linux/soundcard.h>
+
+#include <linux/atm.h>
+#include <linux/atmarp.h>
+#include <linux/atmclip.h>
+#include <linux/atmdev.h>
+#include <linux/atmioc.h>
+#include <linux/atmlec.h>
+#include <linux/atmmpc.h>
+#include <linux/atmsvc.h>
+#include <linux/atm_tcp.h>
+#include <linux/sonet.h>
+#include <linux/atm_suni.h>
+
+#include <asm/module.h>	/* get #define module_map() */
+
+/* Use this to get at 32-bit user passed pointers. 
+   See sys_sparc32.c for description about these. */
+#define A(__x) ((unsigned long)(__x))
+
+/* Aiee. Someone does not find a difference between int and long */
+#define EXT2_IOC32_GETFLAGS               _IOR('f', 1, int)
+#define EXT2_IOC32_SETFLAGS               _IOW('f', 2, int)
+#define EXT2_IOC32_GETVERSION             _IOR('v', 1, int)
+#define EXT2_IOC32_SETVERSION             _IOW('v', 2, int)
+
+extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+
+static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	int err;
+	unsigned long val;
+	
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&val);
+	set_fs (old_fs);
+	if (!err && put_user(val, (u32 *)arg))
+		return -EFAULT;
+	return err;
+}
+ 
+static int rw_long(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	int err;
+	unsigned long val;
+	
+	if(get_user(val, (u32 *)arg))
+		return -EFAULT;
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&val);
+	set_fs (old_fs);
+	if (!err && put_user(val, (u32 *)arg))
+		return -EFAULT;
+	return err;
+}
+
+static int siocprivate(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	int err = sys_ioctl(fd, cmd, arg);
+	if ((unsigned) err > -4095)
+		printk(KERN_WARNING 
+			"ioctl(%d, 0x%x, %p) -- SIOCDEVPRIVATE-based ioctls aren't really\n"
+			"supported, though some will work by accident.\n",
+		    fd, cmd, (void *)arg);
+	return err;
+}
+
+static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	/* These are just misnamed, they actually get/put from/to user an int */
+	switch (cmd) {
+	case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break;
+	case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break;
+	case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break;
+	case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break;
+	}
+	return sys_ioctl(fd, cmd, arg);
+}
+ 
+static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct timeval32 *up = (struct timeval32 *)arg;
+	struct timeval ktv;
+	mm_segment_t old_fs = get_fs();
+	int err;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&ktv);
+	set_fs(old_fs);
+	if(!err) {
+		err = put_user(ktv.tv_sec, &up->tv_sec);
+		err |= __put_user(ktv.tv_usec, &up->tv_usec);
+	}
+	return err;
+}
+
+struct ifmap32 {
+	u32 mem_start;
+	u32 mem_end;
+	unsigned short base_addr;
+	unsigned char irq;
+	unsigned char dma;
+	unsigned char port;
+};
+
+struct ifreq32 {
+#define IFHWADDRLEN     6
+#define IFNAMSIZ        16
+        union {
+                char    ifrn_name[IFNAMSIZ];            /* if name, e.g. "en0" */
+        } ifr_ifrn;
+        union {
+                struct  sockaddr ifru_addr;
+                struct  sockaddr ifru_dstaddr;
+                struct  sockaddr ifru_broadaddr;
+                struct  sockaddr ifru_netmask;
+                struct  sockaddr ifru_hwaddr;
+                short   ifru_flags;
+                int     ifru_ivalue;
+                int     ifru_mtu;
+                struct  ifmap32 ifru_map;
+                char    ifru_slave[IFNAMSIZ];   /* Just fits the size */
+		char	ifru_newname[IFNAMSIZ];
+                __kernel_caddr_t32 ifru_data;
+        } ifr_ifru;
+};
+
+struct ifconf32 {
+        int     ifc_len;                        /* size of buffer       */
+        __kernel_caddr_t32  ifcbuf;
+};
+
+static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct net_device *dev;
+	struct ifreq32 ifr32;
+	int err;
+
+	if (copy_from_user(&ifr32, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+		return -EFAULT;
+
+	dev = dev_get_by_index(ifr32.ifr_ifindex);
+	if (!dev)
+		return -ENODEV;
+
+	strcpy(ifr32.ifr_name, dev->name);
+
+	err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32));
+	return (err ? -EFAULT : 0);
+}
+
+static inline int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifconf32 ifc32;
+	struct ifconf ifc;
+	struct ifreq32 *ifr32;
+	struct ifreq *ifr;
+	mm_segment_t old_fs;
+	unsigned int i, j;
+	int err;
+
+	if (copy_from_user(&ifc32, (struct ifconf32 *)arg, sizeof(struct ifconf32)))
+		return -EFAULT;
+
+	if(ifc32.ifcbuf == 0) {
+		ifc32.ifc_len = 0;
+		ifc.ifc_len = 0;
+		ifc.ifc_buf = NULL;
+	} else {
+		ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) *
+			sizeof (struct ifreq);
+		ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL);
+		if (!ifc.ifc_buf)
+			return -ENOMEM;
+	}
+	ifr = ifc.ifc_req;
+	ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf);
+	for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) {
+		if (copy_from_user(ifr++, ifr32++, sizeof (struct ifreq32))) {
+			kfree (ifc.ifc_buf);
+			return -EFAULT;
+		}
+	}
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc);	
+	set_fs (old_fs);
+	if (!err) {
+		ifr = ifc.ifc_req;
+		ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf);
+		for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len;
+		     i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) {
+			if (copy_to_user(ifr32++, ifr++, sizeof (struct ifreq32))) {
+				err = -EFAULT;
+				break;
+			}
+		}
+		if (!err) {
+			if (i <= ifc32.ifc_len)
+				ifc32.ifc_len = i;
+			else
+				ifc32.ifc_len = i - sizeof (struct ifreq32);
+			if (copy_to_user((struct ifconf32 *)arg, &ifc32, sizeof(struct ifconf32)))
+				err = -EFAULT;
+		}
+	}
+	if(ifc.ifc_buf != NULL)
+		kfree (ifc.ifc_buf);
+	return err;
+}
+
+static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifreq ifr;
+	mm_segment_t old_fs;
+	int err;
+	
+	switch (cmd) {
+	case SIOCSIFMAP:
+		err = copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(ifr.ifr_name));
+		err |= __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start));
+		err |= __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end));
+		err |= __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr));
+		err |= __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq));
+		err |= __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma));
+		err |= __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port));
+		if (err)
+			return -EFAULT;
+		break;
+	case SIOCGPPPSTATS:
+	case SIOCGPPPCSTATS:
+	case SIOCGPPPVER:
+	case SIOCETHTOOL:
+		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+			return -EFAULT;
+		ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+		if (!ifr.ifr_data)
+			return -EAGAIN;
+		if(cmd == SIOCETHTOOL) {
+			u32 data;
+
+			__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+			if(copy_from_user(ifr.ifr_data,
+					  (char *)A(data),
+					  sizeof(struct ethtool_cmd))) {
+				free_page((unsigned long)ifr.ifr_data);
+				return -EFAULT;
+			}
+		}
+		break;
+	default:
+		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+			return -EFAULT;
+		break;
+	}
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
+	set_fs (old_fs);
+	if (!err) {
+		switch (cmd) {
+		case SIOCGIFFLAGS:
+		case SIOCGIFMETRIC:
+		case SIOCGIFMTU:
+		case SIOCGIFMEM:
+		case SIOCGIFHWADDR:
+		case SIOCGIFINDEX:
+		case SIOCGIFADDR:
+		case SIOCGIFBRDADDR:
+		case SIOCGIFDSTADDR:
+		case SIOCGIFNETMASK:
+		case SIOCGIFTXQLEN:
+			if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32)))
+				return -EFAULT;
+			break;
+		case SIOCGPPPSTATS:
+		case SIOCGPPPCSTATS:
+		case SIOCGPPPVER:
+		case SIOCETHTOOL:
+		{
+			u32 data;
+			int len;
+
+			__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+			if(cmd == SIOCETHTOOL)
+				len = sizeof(struct ethtool_cmd);
+			if(cmd == SIOCGPPPVER)
+				len = strlen((char *)ifr.ifr_data) + 1;
+			else if(cmd == SIOCGPPPCSTATS)
+				len = sizeof(struct ppp_comp_stats);
+			else
+				len = sizeof(struct ppp_stats);
+
+			len = copy_to_user((char *)A(data), ifr.ifr_data, len);
+			free_page((unsigned long)ifr.ifr_data);
+			if(len)
+				return -EFAULT;
+			break;
+		}
+		case SIOCGIFMAP:
+			err = copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(ifr.ifr_name));
+			err |= __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start));
+			err |= __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end));
+			err |= __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr));
+			err |= __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq));
+			err |= __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma));
+			err |= __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port));
+			if (err)
+				err = -EFAULT;
+			break;
+		}
+	}
+	return err;
+}
+
+struct rtentry32 {
+        u32   		rt_pad1;
+        struct sockaddr rt_dst;         /* target address               */
+        struct sockaddr rt_gateway;     /* gateway addr (RTF_GATEWAY)   */
+        struct sockaddr rt_genmask;     /* target network mask (IP)     */
+        unsigned short  rt_flags;
+        short           rt_pad2;
+        u32   		rt_pad3;
+        unsigned char   rt_tos;
+        unsigned char   rt_class;
+        short           rt_pad4;
+        short           rt_metric;      /* +1 for binary compatibility! */
+        /* char * */ u32 rt_dev;        /* forcing the device at add    */
+        u32   		rt_mtu;         /* per route MTU/Window         */
+        u32   		rt_window;      /* Window clamping              */
+        unsigned short  rt_irtt;        /* Initial RTT                  */
+
+};
+
+static inline int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct rtentry r;
+	char devname[16];
+	u32 rtdev;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	
+	ret = copy_from_user (&r.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr));
+	ret |= __get_user (r.rt_flags, &(((struct rtentry32 *)arg)->rt_flags));
+	ret |= __get_user (r.rt_metric, &(((struct rtentry32 *)arg)->rt_metric));
+	ret |= __get_user (r.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu));
+	ret |= __get_user (r.rt_window, &(((struct rtentry32 *)arg)->rt_window));
+	ret |= __get_user (r.rt_irtt, &(((struct rtentry32 *)arg)->rt_irtt));
+	ret |= __get_user (rtdev, &(((struct rtentry32 *)arg)->rt_dev));
+	if (rtdev) {
+		ret |= copy_from_user (devname, (char *)A(rtdev), 15);
+		r.rt_dev = devname; devname[15] = 0;
+	} else
+		r.rt_dev = 0;
+	if (ret)
+		return -EFAULT;
+	set_fs (KERNEL_DS);
+	ret = sys_ioctl (fd, cmd, (long)&r);
+	set_fs (old_fs);
+	return ret;
+}
+
+struct hd_geometry32 {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned short cylinders;
+	u32 start;
+};
+                        
+static inline int hdio_getgeo(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct hd_geometry geo;
+	int err;
+	
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo);
+	set_fs (old_fs);
+	if (!err) {
+		err = copy_to_user ((struct hd_geometry32 *)arg, &geo, 4);
+		err |= __put_user (geo.start, &(((struct hd_geometry32 *)arg)->start));
+	}
+	return err ? -EFAULT : 0;
+}
+
+
+#if 0
+/* looks like SPARC only - eg sbus video */
+struct  fbcmap32 {
+	int             index;          /* first element (0 origin) */
+	int             count;
+	u32		red;
+	u32		green;
+	u32		blue;
+};
+
+
+static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct fbcmap f;
+	int ret;
+	char red[256], green[256], blue[256];
+	u32 r, g, b;
+	mm_segment_t old_fs = get_fs();
+	
+	ret = get_user(f.index, &(((struct fbcmap32 *)arg)->index));
+	ret |= __get_user(f.count, &(((struct fbcmap32 *)arg)->count));
+	ret |= __get_user(r, &(((struct fbcmap32 *)arg)->red));
+	ret |= __get_user(g, &(((struct fbcmap32 *)arg)->green));
+	ret |= __get_user(b, &(((struct fbcmap32 *)arg)->blue));
+	if (ret)
+		return -EFAULT;
+	if ((f.index < 0) || (f.index > 255)) return -EINVAL;
+	if (f.index + f.count > 256)
+		f.count = 256 - f.index;
+	if (cmd == FBIOPUTCMAP32) {
+		ret = copy_from_user (red, (char *)A(r), f.count);
+		ret |= copy_from_user (green, (char *)A(g), f.count);
+		ret |= copy_from_user (blue, (char *)A(b), f.count);
+		if (ret)
+			return -EFAULT;
+	}
+	f.red = red; f.green = green; f.blue = blue;
+	set_fs (KERNEL_DS);
+	ret = sys_ioctl (fd, (cmd == FBIOPUTCMAP32) ? FBIOPUTCMAP_SPARC : FBIOGETCMAP_SPARC, (long)&f);
+	set_fs (old_fs);
+	if (!ret && cmd == FBIOGETCMAP32) {
+		ret = copy_to_user ((char *)A(r), red, f.count);
+		ret |= copy_to_user ((char *)A(g), green, f.count);
+		ret |= copy_to_user ((char *)A(b), blue, f.count);
+	}
+	return ret ? -EFAULT : 0;
+}
+
+struct fbcursor32 {
+	short set;		/* what to set, choose from the list above */
+	short enable;		/* cursor on/off */
+	struct fbcurpos pos;	/* cursor position */
+	struct fbcurpos hot;	/* cursor hot spot */
+	struct fbcmap32 cmap;	/* color map info */
+	struct fbcurpos size;	/* cursor bit map size */
+	u32	image;		/* cursor image bits */
+	u32	mask;		/* cursor mask bits */
+};
+	
+static inline int fbiogscursor(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct fbcursor f;
+	int ret;
+	char red[2], green[2], blue[2];
+	char image[128], mask[128];
+	u32 r, g, b;
+	u32 m, i;
+	mm_segment_t old_fs = get_fs();
+	
+	ret = copy_from_user (&f, (struct fbcursor32 *)arg, 2 * sizeof (short) + 2 * sizeof(struct fbcurpos));
+	ret |= __get_user(f.size.fbx, &(((struct fbcursor32 *)arg)->size.fbx));
+	ret |= __get_user(f.size.fby, &(((struct fbcursor32 *)arg)->size.fby));
+	ret |= __get_user(f.cmap.index, &(((struct fbcursor32 *)arg)->cmap.index));
+	ret |= __get_user(f.cmap.count, &(((struct fbcursor32 *)arg)->cmap.count));
+	ret |= __get_user(r, &(((struct fbcursor32 *)arg)->cmap.red));
+	ret |= __get_user(g, &(((struct fbcursor32 *)arg)->cmap.green));
+	ret |= __get_user(b, &(((struct fbcursor32 *)arg)->cmap.blue));
+	ret |= __get_user(m, &(((struct fbcursor32 *)arg)->mask));
+	ret |= __get_user(i, &(((struct fbcursor32 *)arg)->image));
+	if (ret)
+		return -EFAULT;
+	if (f.set & FB_CUR_SETCMAP) {
+		if ((uint) f.size.fby > 32)
+			return -EINVAL;
+		ret = copy_from_user (mask, (char *)A(m), f.size.fby * 4);
+		ret |= copy_from_user (image, (char *)A(i), f.size.fby * 4);
+		if (ret)
+			return -EFAULT;
+		f.image = image; f.mask = mask;
+	}
+	if (f.set & FB_CUR_SETCMAP) {
+		ret = copy_from_user (red, (char *)A(r), 2);
+		ret |= copy_from_user (green, (char *)A(g), 2);
+		ret |= copy_from_user (blue, (char *)A(b), 2);
+		if (ret)
+			return -EFAULT;
+		f.cmap.red = red; f.cmap.green = green; f.cmap.blue = blue;
+	}
+	set_fs (KERNEL_DS);
+	ret = sys_ioctl (fd, FBIOSCURSOR, (long)&f);
+	set_fs (old_fs);
+	return ret;
+}
+#endif /* 0 */
+
+struct fb_fix_screeninfo32 {
+	char			id[16];
+        __kernel_caddr_t32	smem_start;
+	__u32			smem_len;
+	__u32			type;
+	__u32			type_aux;
+	__u32			visual;
+	__u16			xpanstep;
+	__u16			ypanstep;
+	__u16			ywrapstep;
+	__u32			line_length;
+        __kernel_caddr_t32	mmio_start;
+	__u32			mmio_len;
+	__u32			accel;
+	__u16			reserved[3];
+};
+
+struct fb_cmap32 {
+	__u32			start;
+	__u32			len;
+	__kernel_caddr_t32	red;
+	__kernel_caddr_t32	green;
+	__kernel_caddr_t32	blue;
+	__kernel_caddr_t32	transp;
+};
+
+static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	u32 red = 0, green = 0, blue = 0, transp = 0;
+	struct fb_fix_screeninfo fix;
+	struct fb_cmap cmap;
+	void *karg;
+	int err = 0;
+
+	memset(&cmap, 0, sizeof(cmap));
+	switch (cmd) {
+	case FBIOGET_FSCREENINFO:
+		karg = &fix;
+		break;
+	case FBIOGETCMAP:
+	case FBIOPUTCMAP:
+		karg = &cmap;
+		err = __get_user(cmap.start, &((struct fb_cmap32 *)arg)->start);
+		err |= __get_user(cmap.len, &((struct fb_cmap32 *)arg)->len);
+		err |= __get_user(red, &((struct fb_cmap32 *)arg)->red);
+		err |= __get_user(green, &((struct fb_cmap32 *)arg)->green);
+		err |= __get_user(blue, &((struct fb_cmap32 *)arg)->blue);
+		err |= __get_user(transp, &((struct fb_cmap32 *)arg)->transp);
+		if (err) {
+			err = -EFAULT;
+			goto out;
+		}
+		err = -ENOMEM;
+		cmap.red = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
+		if (!cmap.red)
+			goto out;
+		cmap.green = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
+		if (!cmap.green)
+			goto out;
+		cmap.blue = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
+		if (!cmap.blue)
+			goto out;
+		if (transp) {
+			cmap.transp = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
+			if (!cmap.transp)
+				goto out;
+		}
+			
+		if (cmd == FBIOGETCMAP)
+			break;
+
+		err = __copy_from_user(cmap.red, (char *)A(red), cmap.len * sizeof(__u16));
+		err |= __copy_from_user(cmap.green, (char *)A(green), cmap.len * sizeof(__u16));
+		err |= __copy_from_user(cmap.blue, (char *)A(blue), cmap.len * sizeof(__u16));
+		if (cmap.transp) err |= __copy_from_user(cmap.transp, (char *)A(transp), cmap.len * sizeof(__u16));
+		if (err) {
+			err = -EFAULT;
+			goto out;
+		}
+		break;
+	default:
+		do {
+			static int count = 0;
+			if (++count <= 20)
+				printk(KERN_WARNING
+					"%s: Unknown fb ioctl cmd fd(%d) "
+					"cmd(%08x) arg(%08lx)\n",
+					__FUNCTION__, fd, cmd, arg);
+		} while(0);
+		return -ENOSYS;
+	}
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)karg);
+	set_fs(old_fs);
+	if (err)
+		goto out;
+	switch (cmd) {
+		struct fb_fix_screeninfo32 fix32;
+	case FBIOGET_FSCREENINFO:
+		memset(&fix32, 0, sizeof(fix32));
+		memcpy(fix32.id, fix.id, sizeof(fix32.id));
+		fix32.smem_start = (__u32)(unsigned long)fix.smem_start;
+		fix32.smem_len	= fix.smem_len;
+		fix32.type	= fix.type;
+		fix32.type_aux	= fix.type_aux;
+		fix32.visual	= fix.visual;
+		fix32.xpanstep	= fix.xpanstep;
+		fix32.ypanstep	= fix.ypanstep;
+		fix32.ywrapstep = fix.ywrapstep;
+		fix32.line_length = fix.line_length;
+		fix32.mmio_start = (__u32)(unsigned long)fix.mmio_start;
+		fix32.mmio_len	= fix.mmio_len;
+		fix32.accel	= fix.accel;
+		memcpy(fix32.reserved, fix.reserved, sizeof(fix32.reserved));
+		err = __copy_to_user((void *) arg, (const void *) &fix32, sizeof(fix32));
+
+printk("fix  : %lx %x  %x %x %x  %x %x %x %x  %lx %x %x\n",
+	fix.smem_start, fix.smem_len,
+	fix.type, fix.type_aux, fix.visual,
+	fix.xpanstep, fix.ypanstep, fix.ywrapstep, fix.line_length,
+	fix.mmio_start, fix.mmio_len, fix.accel);
+printk("fix32: %x %x  %x %x %x  %x %x %x %x  %x %x %x\n",
+	fix32.smem_start, fix32.smem_len,
+	fix32.type, fix32.type_aux, fix32.visual,
+	fix32.xpanstep, fix32.ypanstep, fix32.ywrapstep, fix32.line_length,
+	fix32.mmio_start, fix32.mmio_len, fix32.accel);
+
+		break;
+	case FBIOGETCMAP:
+		err = __copy_to_user((char *)A(red), cmap.red, cmap.len * sizeof(__u16));
+		err |= __copy_to_user((char *)A(green), cmap.blue, cmap.len * sizeof(__u16));
+		err |= __copy_to_user((char *)A(blue), cmap.blue, cmap.len * sizeof(__u16));
+		if (cmap.transp)
+			err |= __copy_to_user((char *)A(transp), cmap.transp, cmap.len * sizeof(__u16));
+		break;
+	case FBIOPUTCMAP:
+		break;
+	}
+	if (err)
+		err = -EFAULT;
+
+out:	if (cmap.red) kfree(cmap.red);
+	if (cmap.green) kfree(cmap.green);
+	if (cmap.blue) kfree(cmap.blue);
+	if (cmap.transp) kfree(cmap.transp);
+	return err;
+}
+
+static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	unsigned long kval;
+	unsigned int *uvp;
+	int error;
+
+	set_fs(KERNEL_DS);
+	error = sys_ioctl(fd, cmd, (long)&kval);
+	set_fs(old_fs);
+
+	if(error == 0) {
+		uvp = (unsigned int *)arg;
+		if(put_user(kval, uvp))
+			error = -EFAULT;
+	}
+	return error;
+}
+
+struct floppy_struct32 {
+	unsigned int	size;
+	unsigned int	sect;
+	unsigned int	head;
+	unsigned int	track;
+	unsigned int	stretch;
+	unsigned char	gap;
+	unsigned char	rate;
+	unsigned char	spec1;
+	unsigned char	fmt_gap;
+	const __kernel_caddr_t32 name;
+};
+
+struct floppy_drive_params32 {
+	char		cmos;
+	u32		max_dtr;
+	u32		hlt;
+	u32		hut;
+	u32		srt;
+	u32		spinup;
+	u32		spindown;
+	unsigned char	spindown_offset;
+	unsigned char	select_delay;
+	unsigned char	rps;
+	unsigned char	tracks;
+	u32		timeout;
+	unsigned char	interleave_sect;
+	struct floppy_max_errors max_errors;
+	char		flags;
+	char		read_track;
+	short		autodetect[8];
+	int		checkfreq;
+	int		native_format;
+};
+
+struct floppy_drive_struct32 {
+	signed char	flags;
+	u32		spinup_date;
+	u32		select_date;
+	u32		first_read_date;
+	short		probed_format;
+	short		track;
+	short		maxblock;
+	short		maxtrack;
+	int		generation;
+	int		keep_data;
+	int		fd_ref;
+	int		fd_device;
+	int		last_checked;
+	__kernel_caddr_t32 dmabuf;
+	int		bufblocks;
+};
+
+struct floppy_fdc_state32 {
+	int		spec1;
+	int		spec2;
+	int		dtr;
+	unsigned char	version;
+	unsigned char	dor;
+	u32		address;
+	unsigned int	rawcmd:2;
+	unsigned int	reset:1;
+	unsigned int	need_configure:1;
+	unsigned int	perp_mode:2;
+	unsigned int	has_fifo:1;
+	unsigned int	driver_version;
+	unsigned char	track[4];
+};
+
+struct floppy_write_errors32 {
+	unsigned int	write_errors;
+	u32		first_error_sector;
+	int		first_error_generation;
+	u32		last_error_sector;
+	int		last_error_generation;
+	unsigned int	badness;
+};
+
+#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32)
+#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32)
+#define FDGETPRM32 _IOR(2, 0x04, struct floppy_struct32)
+#define FDSETDRVPRM32 _IOW(2, 0x90, struct floppy_drive_params32)
+#define FDGETDRVPRM32 _IOR(2, 0x11, struct floppy_drive_params32)
+#define FDGETDRVSTAT32 _IOR(2, 0x12, struct floppy_drive_struct32)
+#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct floppy_drive_struct32)
+#define FDGETFDCSTAT32 _IOR(2, 0x15, struct floppy_fdc_state32)
+#define FDWERRORGET32  _IOR(2, 0x17, struct floppy_write_errors32)
+
+static struct {
+	unsigned int	cmd32;
+	unsigned int	cmd;
+} fd_ioctl_trans_table[] = {
+	{ FDSETPRM32, FDSETPRM },
+	{ FDDEFPRM32, FDDEFPRM },
+	{ FDGETPRM32, FDGETPRM },
+	{ FDSETDRVPRM32, FDSETDRVPRM },
+	{ FDGETDRVPRM32, FDGETDRVPRM },
+	{ FDGETDRVSTAT32, FDGETDRVSTAT },
+	{ FDPOLLDRVSTAT32, FDPOLLDRVSTAT },
+	{ FDGETFDCSTAT32, FDGETFDCSTAT },
+	{ FDWERRORGET32, FDWERRORGET }
+};
+
+#define NR_FD_IOCTL_TRANS (sizeof(fd_ioctl_trans_table)/sizeof(fd_ioctl_trans_table[0]))
+
+static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	void *karg = NULL;
+	unsigned int kcmd = 0;
+	int i, err;
+
+	for (i = 0; i < NR_FD_IOCTL_TRANS; i++)
+		if (cmd == fd_ioctl_trans_table[i].cmd32) {
+			kcmd = fd_ioctl_trans_table[i].cmd;
+			break;
+		}
+	if (!kcmd)
+		return -EINVAL;
+
+	switch (cmd) {
+		case FDSETPRM32:
+		case FDDEFPRM32:
+		case FDGETPRM32:
+		{
+			struct floppy_struct *f;
+
+			f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL);
+			if (!karg)
+				return -ENOMEM;
+			if (cmd == FDGETPRM32)
+				break;
+			err = __get_user(f->size, &((struct floppy_struct32 *)arg)->size);
+			err |= __get_user(f->sect, &((struct floppy_struct32 *)arg)->sect);
+			err |= __get_user(f->head, &((struct floppy_struct32 *)arg)->head);
+			err |= __get_user(f->track, &((struct floppy_struct32 *)arg)->track);
+			err |= __get_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch);
+			err |= __get_user(f->gap, &((struct floppy_struct32 *)arg)->gap);
+			err |= __get_user(f->rate, &((struct floppy_struct32 *)arg)->rate);
+			err |= __get_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1);
+			err |= __get_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap);
+			err |= __get_user((u64)f->name, &((struct floppy_struct32 *)arg)->name);
+			if (err) {
+				err = -EFAULT;
+				goto out;
+			}
+			break;
+		}
+		case FDSETDRVPRM32:
+		case FDGETDRVPRM32:
+		{
+			struct floppy_drive_params *f;
+
+			f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL);
+			if (!karg)
+				return -ENOMEM;
+			if (cmd == FDGETDRVPRM32)
+				break;
+			err = __get_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos);
+			err |= __get_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr);
+			err |= __get_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt);
+			err |= __get_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut);
+			err |= __get_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt);
+			err |= __get_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup);
+			err |= __get_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown);
+			err |= __get_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset);
+			err |= __get_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay);
+			err |= __get_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps);
+			err |= __get_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks);
+			err |= __get_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout);
+			err |= __get_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect);
+			err |= __copy_from_user(&f->max_errors, &((struct floppy_drive_params32 *)arg)->max_errors, sizeof(f->max_errors));
+			err |= __get_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags);
+			err |= __get_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track);
+			err |= __copy_from_user(f->autodetect, ((struct floppy_drive_params32 *)arg)->autodetect, sizeof(f->autodetect));
+			err |= __get_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq);
+			err |= __get_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format);
+			if (err) {
+				err = -EFAULT;
+				goto out;
+			}
+			break;
+		}
+		case FDGETDRVSTAT32:
+		case FDPOLLDRVSTAT32:
+			karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL);
+			if (!karg)
+				return -ENOMEM;
+			break;
+		case FDGETFDCSTAT32:
+			karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL);
+			if (!karg)
+				return -ENOMEM;
+			break;
+		case FDWERRORGET32:
+			karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL);
+			if (!karg)
+				return -ENOMEM;
+			break;
+		default:
+			return -EINVAL;
+	}
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, kcmd, (unsigned long)karg);
+	set_fs (old_fs);
+	if (err)
+		goto out;
+	switch (cmd) {
+		case FDGETPRM32:
+		{
+			struct floppy_struct *f = karg;
+
+			err = __put_user(f->size, &((struct floppy_struct32 *)arg)->size);
+			err |= __put_user(f->sect, &((struct floppy_struct32 *)arg)->sect);
+			err |= __put_user(f->head, &((struct floppy_struct32 *)arg)->head);
+			err |= __put_user(f->track, &((struct floppy_struct32 *)arg)->track);
+			err |= __put_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch);
+			err |= __put_user(f->gap, &((struct floppy_struct32 *)arg)->gap);
+			err |= __put_user(f->rate, &((struct floppy_struct32 *)arg)->rate);
+			err |= __put_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1);
+			err |= __put_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap);
+			err |= __put_user((u64)f->name, &((struct floppy_struct32 *)arg)->name);
+			break;
+		}
+		case FDGETDRVPRM32:
+		{
+			struct floppy_drive_params *f = karg;
+
+			err = __put_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos);
+			err |= __put_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr);
+			err |= __put_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt);
+			err |= __put_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut);
+			err |= __put_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt);
+			err |= __put_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup);
+			err |= __put_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown);
+			err |= __put_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset);
+			err |= __put_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay);
+			err |= __put_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps);
+			err |= __put_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks);
+			err |= __put_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout);
+			err |= __put_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect);
+			err |= __copy_to_user(&((struct floppy_drive_params32 *)arg)->max_errors, &f->max_errors, sizeof(f->max_errors));
+			err |= __put_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags);
+			err |= __put_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track);
+			err |= __copy_to_user(((struct floppy_drive_params32 *)arg)->autodetect, f->autodetect, sizeof(f->autodetect));
+			err |= __put_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq);
+			err |= __put_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format);
+			break;
+		}
+		case FDGETDRVSTAT32:
+		case FDPOLLDRVSTAT32:
+		{
+			struct floppy_drive_struct *f = karg;
+
+			err = __put_user(f->flags, &((struct floppy_drive_struct32 *)arg)->flags);
+			err |= __put_user(f->spinup_date, &((struct floppy_drive_struct32 *)arg)->spinup_date);
+			err |= __put_user(f->select_date, &((struct floppy_drive_struct32 *)arg)->select_date);
+			err |= __put_user(f->first_read_date, &((struct floppy_drive_struct32 *)arg)->first_read_date);
+			err |= __put_user(f->probed_format, &((struct floppy_drive_struct32 *)arg)->probed_format);
+			err |= __put_user(f->track, &((struct floppy_drive_struct32 *)arg)->track);
+			err |= __put_user(f->maxblock, &((struct floppy_drive_struct32 *)arg)->maxblock);
+			err |= __put_user(f->maxtrack, &((struct floppy_drive_struct32 *)arg)->maxtrack);
+			err |= __put_user(f->generation, &((struct floppy_drive_struct32 *)arg)->generation);
+			err |= __put_user(f->keep_data, &((struct floppy_drive_struct32 *)arg)->keep_data);
+			err |= __put_user(f->fd_ref, &((struct floppy_drive_struct32 *)arg)->fd_ref);
+			err |= __put_user(f->fd_device, &((struct floppy_drive_struct32 *)arg)->fd_device);
+			err |= __put_user(f->last_checked, &((struct floppy_drive_struct32 *)arg)->last_checked);
+			err |= __put_user((u64)f->dmabuf, &((struct floppy_drive_struct32 *)arg)->dmabuf);
+			err |= __put_user((u64)f->bufblocks, &((struct floppy_drive_struct32 *)arg)->bufblocks);
+			break;
+		}
+		case FDGETFDCSTAT32:
+		{
+			struct floppy_fdc_state *f = karg;
+
+			err = __put_user(f->spec1, &((struct floppy_fdc_state32 *)arg)->spec1);
+			err |= __put_user(f->spec2, &((struct floppy_fdc_state32 *)arg)->spec2);
+			err |= __put_user(f->dtr, &((struct floppy_fdc_state32 *)arg)->dtr);
+			err |= __put_user(f->version, &((struct floppy_fdc_state32 *)arg)->version);
+			err |= __put_user(f->dor, &((struct floppy_fdc_state32 *)arg)->dor);
+			err |= __put_user(f->address, &((struct floppy_fdc_state32 *)arg)->address);
+			err |= __copy_to_user((char *)&((struct floppy_fdc_state32 *)arg)->address
+			    		   + sizeof(((struct floppy_fdc_state32 *)arg)->address),
+					   (char *)&f->address + sizeof(f->address), sizeof(int));
+			err |= __put_user(f->driver_version, &((struct floppy_fdc_state32 *)arg)->driver_version);
+			err |= __copy_to_user(((struct floppy_fdc_state32 *)arg)->track, f->track, sizeof(f->track));
+			break;
+		}
+		case FDWERRORGET32:
+		{
+			struct floppy_write_errors *f = karg;
+
+			err = __put_user(f->write_errors, &((struct floppy_write_errors32 *)arg)->write_errors);
+			err |= __put_user(f->first_error_sector, &((struct floppy_write_errors32 *)arg)->first_error_sector);
+			err |= __put_user(f->first_error_generation, &((struct floppy_write_errors32 *)arg)->first_error_generation);
+			err |= __put_user(f->last_error_sector, &((struct floppy_write_errors32 *)arg)->last_error_sector);
+			err |= __put_user(f->last_error_generation, &((struct floppy_write_errors32 *)arg)->last_error_generation);
+			err |= __put_user(f->badness, &((struct floppy_write_errors32 *)arg)->badness);
+			break;
+		}
+		default:
+			break;
+	}
+	if (err)
+		err = -EFAULT;
+
+out:	if (karg) kfree(karg);
+	return err;
+}
+
+struct ppp_option_data32 {
+	__kernel_caddr_t32	ptr;
+	__u32			length;
+	int			transmit;
+};
+#define PPPIOCSCOMPRESS32	_IOW('t', 77, struct ppp_option_data32)
+
+struct ppp_idle32 {
+	__kernel_time_t32 xmit_idle;
+	__kernel_time_t32 recv_idle;
+};
+#define PPPIOCGIDLE32		_IOR('t', 63, struct ppp_idle32)
+
+static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct ppp_option_data32 data32;
+	struct ppp_option_data data;
+	struct ppp_idle32 idle32;
+	struct ppp_idle idle;
+	unsigned int kcmd;
+	void *karg;
+	int err = 0;
+
+	switch (cmd) {
+	case PPPIOCGIDLE32:
+		kcmd = PPPIOCGIDLE;
+		karg = &idle;
+		break;
+	case PPPIOCSCOMPRESS32:
+		if (copy_from_user(&data32, (struct ppp_option_data32 *)arg, sizeof(struct ppp_option_data32)))
+			return -EFAULT;
+		data.ptr = kmalloc (data32.length, GFP_KERNEL);
+		if (!data.ptr)
+			return -ENOMEM;
+		if (copy_from_user(data.ptr, (__u8 *)A(data32.ptr), data32.length)) {
+			kfree(data.ptr);
+			return -EFAULT;
+		}
+		data.length = data32.length;
+		data.transmit = data32.transmit;
+		kcmd = PPPIOCSCOMPRESS;
+		karg = &data;
+		break;
+	default:
+		do {
+			static int count = 0;
+			if (++count <= 20)
+				printk(KERN_WARNING
+					"ppp_ioctl: Unknown cmd fd(%d) "
+					"cmd(%08x) arg(%08x)\n",
+					(int)fd, (unsigned int)cmd, (unsigned int)arg);
+		} while(0);
+		return -EINVAL;
+	}
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, kcmd, (unsigned long)karg);
+	set_fs (old_fs);
+	switch (cmd) {
+	case PPPIOCGIDLE32:
+		if (err)
+			return err;
+		idle32.xmit_idle = idle.xmit_idle;
+		idle32.recv_idle = idle.recv_idle;
+		if (copy_to_user((struct ppp_idle32 *)arg, &idle32, sizeof(struct ppp_idle32)))
+			return -EFAULT;
+		break;
+	case PPPIOCSCOMPRESS32:
+		kfree(data.ptr);
+		break;
+	default:
+		break;
+	}
+	return err;
+}
+
+
+struct mtget32 {
+	__u32	mt_type;
+	__u32	mt_resid;
+	__u32	mt_dsreg;
+	__u32	mt_gstat;
+	__u32	mt_erreg;
+	__kernel_daddr_t32	mt_fileno;
+	__kernel_daddr_t32	mt_blkno;
+};
+#define MTIOCGET32	_IOR('m', 2, struct mtget32)
+
+struct mtpos32 {
+	__u32	mt_blkno;
+};
+#define MTIOCPOS32	_IOR('m', 3, struct mtpos32)
+
+struct mtconfiginfo32 {
+	__u32	mt_type;
+	__u32	ifc_type;
+	__u16	irqnr;
+	__u16	dmanr;
+	__u16	port;
+	__u32	debug;
+	__u32	have_dens:1;
+	__u32	have_bsf:1;
+	__u32	have_fsr:1;
+	__u32	have_bsr:1;
+	__u32	have_eod:1;
+	__u32	have_seek:1;
+	__u32	have_tell:1;
+	__u32	have_ras1:1;
+	__u32	have_ras2:1;
+	__u32	have_ras3:1;
+	__u32	have_qfa:1;
+	__u32	pad1:5;
+	char	reserved[10];
+};
+#define	MTIOCGETCONFIG32	_IOR('m', 4, struct mtconfiginfo32)
+#define	MTIOCSETCONFIG32	_IOW('m', 5, struct mtconfiginfo32)
+
+static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct mtconfiginfo info;
+	struct mtget get;
+	struct mtpos pos;
+	unsigned long kcmd;
+	void *karg;
+	int err = 0;
+
+	switch(cmd) {
+	case MTIOCPOS32:
+		kcmd = MTIOCPOS;
+		karg = &pos;
+		break;
+	case MTIOCGET32:
+		kcmd = MTIOCGET;
+		karg = &get;
+		break;
+	case MTIOCGETCONFIG32:
+		kcmd = MTIOCGETCONFIG;
+		karg = &info;
+		break;
+	case MTIOCSETCONFIG32:
+		kcmd = MTIOCSETCONFIG;
+		karg = &info;
+		err = __get_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type);
+		err |= __get_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type);
+		err |= __get_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr);
+		err |= __get_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr);
+		err |= __get_user(info.port, &((struct mtconfiginfo32 *)arg)->port);
+		err |= __get_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug);
+		err |= __copy_from_user((char *)&info.debug + sizeof(info.debug),
+				     (char *)&((struct mtconfiginfo32 *)arg)->debug
+				     + sizeof(((struct mtconfiginfo32 *)arg)->debug), sizeof(__u32));
+		if (err)
+			return -EFAULT;
+		break;
+	default:
+		do {
+			static int count = 0;
+			if (++count <= 20)
+				printk(KERN_WARNING
+					"mt_ioctl: Unknown cmd fd(%d) "
+					"cmd(%08x) arg(%08x)\n",
+					(int)fd, (unsigned int)cmd, (unsigned int)arg);
+		} while(0);
+		return -EINVAL;
+	}
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, kcmd, (unsigned long)karg);
+	set_fs (old_fs);
+	if (err)
+		return err;
+	switch (cmd) {
+	case MTIOCPOS32:
+		err = __put_user(pos.mt_blkno, &((struct mtpos32 *)arg)->mt_blkno);
+		break;
+	case MTIOCGET32:
+		err = __put_user(get.mt_type, &((struct mtget32 *)arg)->mt_type);
+		err |= __put_user(get.mt_resid, &((struct mtget32 *)arg)->mt_resid);
+		err |= __put_user(get.mt_dsreg, &((struct mtget32 *)arg)->mt_dsreg);
+		err |= __put_user(get.mt_gstat, &((struct mtget32 *)arg)->mt_gstat);
+		err |= __put_user(get.mt_erreg, &((struct mtget32 *)arg)->mt_erreg);
+		err |= __put_user(get.mt_fileno, &((struct mtget32 *)arg)->mt_fileno);
+		err |= __put_user(get.mt_blkno, &((struct mtget32 *)arg)->mt_blkno);
+		break;
+	case MTIOCGETCONFIG32:
+		err = __put_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type);
+		err |= __put_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type);
+		err |= __put_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr);
+		err |= __put_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr);
+		err |= __put_user(info.port, &((struct mtconfiginfo32 *)arg)->port);
+		err |= __put_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug);
+		err |= __copy_to_user((char *)&((struct mtconfiginfo32 *)arg)->debug
+			    		   + sizeof(((struct mtconfiginfo32 *)arg)->debug),
+					   (char *)&info.debug + sizeof(info.debug), sizeof(__u32));
+		break;
+	case MTIOCSETCONFIG32:
+		break;
+	}
+	return err ? -EFAULT: 0;
+}
+
+struct cdrom_read32 {
+	int			cdread_lba;
+	__kernel_caddr_t32	cdread_bufaddr;
+	int			cdread_buflen;
+};
+
+struct cdrom_read_audio32 {
+	union cdrom_addr	addr;
+	u_char			addr_format;
+	int			nframes;
+	__kernel_caddr_t32	buf;
+};
+
+struct cdrom_generic_command32 {
+	unsigned char		cmd[CDROM_PACKET_SIZE];
+	__kernel_caddr_t32	buffer;
+	unsigned int		buflen;
+	int			stat;
+	__kernel_caddr_t32	sense;
+	__kernel_caddr_t32	reserved[3];
+};
+
+static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct cdrom_read cdread;
+	struct cdrom_read_audio cdreadaudio;
+	struct cdrom_generic_command cgc;
+	__kernel_caddr_t32 addr;
+	char *data = 0;
+	void *karg;
+	int err = 0;
+
+	switch(cmd) {
+	case CDROMREADMODE2:
+	case CDROMREADMODE1:
+	case CDROMREADRAW:
+	case CDROMREADCOOKED:
+		karg = &cdread;
+		err = __get_user(cdread.cdread_lba, &((struct cdrom_read32 *)arg)->cdread_lba);
+		err |= __get_user(addr, &((struct cdrom_read32 *)arg)->cdread_bufaddr);
+		err |= __get_user(cdread.cdread_buflen, &((struct cdrom_read32 *)arg)->cdread_buflen);
+		if (err)
+			return -EFAULT;
+		data = kmalloc(cdread.cdread_buflen, GFP_KERNEL);
+		if (!data)
+			return -ENOMEM;
+		cdread.cdread_bufaddr = data;
+		break;
+	case CDROMREADAUDIO:
+		karg = &cdreadaudio;
+		err = copy_from_user(&cdreadaudio.addr, &((struct cdrom_read_audio32 *)arg)->addr, sizeof(cdreadaudio.addr));
+		err |= __get_user(cdreadaudio.addr_format, &((struct cdrom_read_audio32 *)arg)->addr_format);
+		err |= __get_user(cdreadaudio.nframes, &((struct cdrom_read_audio32 *)arg)->nframes); 
+		err |= __get_user(addr, &((struct cdrom_read_audio32 *)arg)->buf);
+		if (err)
+			return -EFAULT;
+		data = kmalloc(cdreadaudio.nframes * 2352, GFP_KERNEL);
+		if (!data)
+			return -ENOMEM;
+		cdreadaudio.buf = data;
+		break;
+	case CDROM_SEND_PACKET:
+		karg = &cgc;
+		err = copy_from_user(cgc.cmd, &((struct cdrom_generic_command32 *)arg)->cmd, sizeof(cgc.cmd));
+		err |= __get_user(addr, &((struct cdrom_generic_command32 *)arg)->buffer);
+		err |= __get_user(cgc.buflen, &((struct cdrom_generic_command32 *)arg)->buflen);
+		if (err)
+			return -EFAULT;
+		if ((data = kmalloc(cgc.buflen, GFP_KERNEL)) == NULL)
+			return -ENOMEM;
+		cgc.buffer = data;
+		break;
+	default:
+		do {
+			static int count = 0;
+			if (++count <= 20)
+				printk(KERN_WARNING
+					"cdrom_ioctl: Unknown cmd fd(%d) "
+					"cmd(%08x) arg(%08x)\n",
+					(int)fd, (unsigned int)cmd, (unsigned int)arg);
+		} while(0);
+		return -EINVAL;
+	}
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)karg);
+	set_fs (old_fs);
+	if (err)
+		goto out;
+	switch (cmd) {
+	case CDROMREADMODE2:
+	case CDROMREADMODE1:
+	case CDROMREADRAW:
+	case CDROMREADCOOKED:
+		err = copy_to_user((char *)A(addr), data, cdread.cdread_buflen);
+		break;
+	case CDROMREADAUDIO:
+		err = copy_to_user((char *)A(addr), data, cdreadaudio.nframes * 2352);
+		break;
+	case CDROM_SEND_PACKET:
+		err = copy_to_user((char *)A(addr), data, cgc.buflen);
+		break;
+	default:
+		break;
+	}
+out:	if (data)
+		kfree(data);
+	return err ? -EFAULT : 0;
+}
+
+struct loop_info32 {
+	int			lo_number;      /* ioctl r/o */
+	__kernel_dev_t32	lo_device;      /* ioctl r/o */
+	unsigned int		lo_inode;       /* ioctl r/o */
+	__kernel_dev_t32	lo_rdevice;     /* ioctl r/o */
+	int			lo_offset;
+	int			lo_encrypt_type;
+	int			lo_encrypt_key_size;    /* ioctl w/o */
+	int			lo_flags;       /* ioctl r/o */
+	char			lo_name[LO_NAME_SIZE];
+	unsigned char		lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+	unsigned int		lo_init[2];
+	char			reserved[4];
+};
+
+static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct loop_info l;
+	int err = -EINVAL;
+
+	switch(cmd) {
+	case LOOP_SET_STATUS:
+		err = get_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number);
+		err |= __get_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device);
+		err |= __get_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode);
+		err |= __get_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice);
+		err |= __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)arg)->lo_offset,
+					   8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
+		if (err) {
+			err = -EFAULT;
+		} else {
+			set_fs (KERNEL_DS);
+			err = sys_ioctl (fd, cmd, (unsigned long)&l);
+			set_fs (old_fs);
+		}
+		break;
+	case LOOP_GET_STATUS:
+		set_fs (KERNEL_DS);
+		err = sys_ioctl (fd, cmd, (unsigned long)&l);
+		set_fs (old_fs);
+		if (!err) {
+			err = put_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number);
+			err |= __put_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device);
+			err |= __put_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode);
+			err |= __put_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice);
+			err |= __copy_to_user((char *)&((struct loop_info32 *)arg)->lo_offset,
+					   (char *)&l.lo_offset, (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
+			if (err)
+				err = -EFAULT;
+		}
+		break;
+	default: {
+		static int count = 0;
+		if (++count <= 20)
+			printk(KERN_WARNING
+				"%s: Unknown loop ioctl cmd, fd(%d) "
+				"cmd(%08x) arg(%08lx)\n",
+				__FUNCTION__, fd, cmd, arg);
+	}
+	}
+	return err;
+}
+
+#ifdef CONFIG_VT
+extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg);
+
+static int vt_check(struct file *file)
+{
+	struct tty_struct *tty;
+	struct inode *inode = file->f_dentry->d_inode;
+	
+	if (file->f_op->ioctl != tty_ioctl)
+		return -EINVAL;
+	                
+	tty = (struct tty_struct *)file->private_data;
+	if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))
+		return -EINVAL;
+	                                                
+	if (tty->driver.ioctl != vt_ioctl)
+		return -EINVAL;
+	
+	/*
+	 * To have permissions to do most of the vt ioctls, we either have
+	 * to be the owner of the tty, or super-user.
+	 */
+	if (current->tty == tty || suser())
+		return 1;
+	return 0;                                                    
+}
+
+struct consolefontdesc32 {
+	unsigned short charcount;       /* characters in font (256 or 512) */
+	unsigned short charheight;      /* scan lines per character (1-32) */
+	u32 chardata;			/* font data in expanded form */
+};
+
+static int do_fontx_ioctl(unsigned int fd, int cmd, struct consolefontdesc32 *user_cfd, struct file *file)
+{
+	struct consolefontdesc cfdarg;
+	struct console_font_op op;
+	int i, perm;
+
+	perm = vt_check(file);
+	if (perm < 0) return perm;
+	
+	if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc32)))
+		return -EFAULT;
+	
+	cfdarg.chardata = (unsigned char *)A(((struct consolefontdesc32 *)&cfdarg)->chardata);
+ 	
+	switch (cmd) {
+	case PIO_FONTX:
+		if (!perm)
+			return -EPERM;
+		op.op = KD_FONT_OP_SET;
+		op.flags = 0;
+		op.width = 8;
+		op.height = cfdarg.charheight;
+		op.charcount = cfdarg.charcount;
+		op.data = cfdarg.chardata;
+		return con_font_op(fg_console, &op);
+	case GIO_FONTX:
+		if (!cfdarg.chardata)
+			return 0;
+		op.op = KD_FONT_OP_GET;
+		op.flags = 0;
+		op.width = 8;
+		op.height = cfdarg.charheight;
+		op.charcount = cfdarg.charcount;
+		op.data = cfdarg.chardata;
+		i = con_font_op(fg_console, &op);
+		if (i)
+			return i;
+		cfdarg.charheight = op.height;
+		cfdarg.charcount = op.charcount;
+		((struct consolefontdesc32 *)&cfdarg)->chardata	= (unsigned long)cfdarg.chardata;
+		if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc32)))
+			return -EFAULT;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+struct console_font_op32 {
+	unsigned int op;        /* operation code KD_FONT_OP_* */
+	unsigned int flags;     /* KD_FONT_FLAG_* */
+	unsigned int width, height;     /* font size */
+	unsigned int charcount;
+	u32 data;    /* font data with height fixed to 32 */
+};
+                                        
+static int do_kdfontop_ioctl(unsigned int fd, unsigned int cmd, struct console_font_op32 *fontop, struct file *file)
+{
+	struct console_font_op op;
+	int perm = vt_check(file), i;
+	struct vt_struct *vt;
+	
+	if (perm < 0) return perm;
+	
+	if (copy_from_user(&op, (void *) fontop, sizeof(struct console_font_op32)))
+		return -EFAULT;
+	if (!perm && op.op != KD_FONT_OP_GET)
+		return -EPERM;
+	op.data = (unsigned char *)A(((struct console_font_op32 *)&op)->data);
+	op.flags |= KD_FONT_FLAG_OLD;
+	vt = (struct vt_struct *)((struct tty_struct *)file->private_data)->driver_data;
+	i = con_font_op(vt->vc_num, &op);
+	if (i) return i;
+	((struct console_font_op32 *)&op)->data = (unsigned long)op.data;
+	if (copy_to_user((void *) fontop, &op, sizeof(struct console_font_op32)))
+		return -EFAULT;
+	return 0;
+}
+
+struct unimapdesc32 {
+	unsigned short entry_ct;
+	u32 entries;
+};
+
+static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file)
+{
+	struct unimapdesc32 tmp;
+	int perm = vt_check(file);
+	
+	if (perm < 0) return perm;
+	if (copy_from_user(&tmp, user_ud, sizeof tmp))
+		return -EFAULT;
+	switch (cmd) {
+	case PIO_UNIMAP:
+		if (!perm) return -EPERM;
+		return con_set_unimap(fg_console, tmp.entry_ct, (struct unipair *)A(tmp.entries));
+	case GIO_UNIMAP:
+		return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), (struct unipair *)A(tmp.entries));
+	}
+	return 0;
+}
+#endif
+
+#if 0
+static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	__kernel_uid_t kuid;
+	int err;
+
+	cmd = SMB_IOC_GETMOUNTUID;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&kuid);
+	set_fs(old_fs);
+
+	if (err >= 0)
+		err = put_user(kuid, (__kernel_uid_t32 *)arg);
+
+	return err;
+}
+#endif
+
+struct atmif_sioc32 {
+        int                number;
+        int                length;
+        __kernel_caddr_t32 arg;
+};
+
+struct atm_iobuf32 {
+	int                length;
+	__kernel_caddr_t32 buffer;
+};
+
+#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct atmif_sioc32)
+#define ATM_GETNAMES32    _IOW('a', ATMIOC_ITF+3, struct atm_iobuf32)
+#define ATM_GETTYPE32     _IOW('a', ATMIOC_ITF+4, struct atmif_sioc32)
+#define ATM_GETESI32	  _IOW('a', ATMIOC_ITF+5, struct atmif_sioc32)
+#define ATM_GETADDR32	  _IOW('a', ATMIOC_ITF+6, struct atmif_sioc32)
+#define ATM_RSTADDR32	  _IOW('a', ATMIOC_ITF+7, struct atmif_sioc32)
+#define ATM_ADDADDR32	  _IOW('a', ATMIOC_ITF+8, struct atmif_sioc32)
+#define ATM_DELADDR32	  _IOW('a', ATMIOC_ITF+9, struct atmif_sioc32)
+#define ATM_GETCIRANGE32  _IOW('a', ATMIOC_ITF+10, struct atmif_sioc32)
+#define ATM_SETCIRANGE32  _IOW('a', ATMIOC_ITF+11, struct atmif_sioc32)
+#define ATM_SETESI32      _IOW('a', ATMIOC_ITF+12, struct atmif_sioc32)
+#define ATM_SETESIF32     _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32)
+#define ATM_GETSTAT32     _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32)
+#define ATM_GETSTATZ32    _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32)
+#define ATM_GETLOOP32	  _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32)
+#define ATM_SETLOOP32	  _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32)
+#define ATM_QUERYLOOP32	  _IOW('a', ATMIOC_SARCOM+4, struct atmif_sioc32)
+
+static struct {
+        unsigned int cmd32;
+        unsigned int cmd;
+} atm_ioctl_map[] = {
+        { ATM_GETLINKRATE32, ATM_GETLINKRATE },
+	{ ATM_GETNAMES32,    ATM_GETNAMES },
+        { ATM_GETTYPE32,     ATM_GETTYPE },
+        { ATM_GETESI32,      ATM_GETESI },
+        { ATM_GETADDR32,     ATM_GETADDR },
+        { ATM_RSTADDR32,     ATM_RSTADDR },
+        { ATM_ADDADDR32,     ATM_ADDADDR },
+        { ATM_DELADDR32,     ATM_DELADDR },
+        { ATM_GETCIRANGE32,  ATM_GETCIRANGE },
+	{ ATM_SETCIRANGE32,  ATM_SETCIRANGE },
+	{ ATM_SETESI32,      ATM_SETESI },
+	{ ATM_SETESIF32,     ATM_SETESIF },
+	{ ATM_GETSTAT32,     ATM_GETSTAT },
+	{ ATM_GETSTATZ32,    ATM_GETSTATZ },
+	{ ATM_GETLOOP32,     ATM_GETLOOP },
+	{ ATM_SETLOOP32,     ATM_SETLOOP },
+	{ ATM_QUERYLOOP32,   ATM_QUERYLOOP }
+};
+
+#define NR_ATM_IOCTL (sizeof(atm_ioctl_map)/sizeof(atm_ioctl_map[0]))
+
+
+static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct atm_iobuf32 iobuf32;
+	struct atm_iobuf   iobuf = { 0, NULL };
+	mm_segment_t old_fs;
+	int err;
+
+	err = copy_from_user(&iobuf32, (struct atm_iobuf32*)arg,
+	    sizeof(struct atm_iobuf32));
+	if (err)
+		return -EFAULT;
+
+	iobuf.length = iobuf32.length;
+
+	if (iobuf32.buffer == (__kernel_caddr_t32) NULL || iobuf32.length == 0) {
+		iobuf.buffer = (void*)(unsigned long)iobuf32.buffer;
+	} else {
+		iobuf.buffer = kmalloc(iobuf.length, GFP_KERNEL);
+		if (iobuf.buffer == NULL) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		err = copy_from_user(iobuf.buffer, A(iobuf32.buffer), iobuf.length);
+		if (err) {
+			err = -EFAULT;
+			goto out;
+		}
+	}
+
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&iobuf);      
+	set_fs (old_fs);
+        if(err)
+		goto out;
+
+        if(iobuf.buffer && iobuf.length > 0) {
+		err = copy_to_user(A(iobuf32.buffer), iobuf.buffer, iobuf.length);
+		if (err) {
+			err = -EFAULT;
+			goto out;
+		}
+	}
+	err = __put_user(iobuf.length, &(((struct atm_iobuf32*)arg)->length));
+
+ out:
+        if(iobuf32.buffer && iobuf32.length > 0)
+		kfree(iobuf.buffer);
+
+	return err;
+}
+
+
+static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+        struct atmif_sioc32 sioc32;
+        struct atmif_sioc   sioc = { 0, 0, NULL };
+        mm_segment_t old_fs;
+        int err;
+        
+        err = copy_from_user(&sioc32, (struct atmif_sioc32*)arg,
+			     sizeof(struct atmif_sioc32));
+        if (err)
+                return -EFAULT;
+
+        sioc.number = sioc32.number;
+        sioc.length = sioc32.length;
+        
+	if (sioc32.arg == (__kernel_caddr_t32) NULL || sioc32.length == 0) {
+		sioc.arg = (void*)(unsigned long)sioc32.arg;
+        } else {
+                sioc.arg = kmalloc(sioc.length, GFP_KERNEL);
+                if (sioc.arg == NULL) {
+                        err = -ENOMEM;
+			goto out;
+		}
+                
+                err = copy_from_user(sioc.arg, A(sioc32.arg), sioc32.length);
+                if (err) {
+                        err = -EFAULT;
+                        goto out;
+                }
+        }
+        
+        old_fs = get_fs(); set_fs (KERNEL_DS);
+        err = sys_ioctl (fd, cmd, (unsigned long)&sioc);	
+        set_fs (old_fs);
+        if(err) {
+                goto out;
+	}
+        
+        if(sioc.arg && sioc.length > 0) {
+                err = copy_to_user(A(sioc32.arg), sioc.arg, sioc.length);
+                if (err) {
+                        err = -EFAULT;
+                        goto out;
+                }
+        }
+        err = __put_user(sioc.length, &(((struct atmif_sioc32*)arg)->length));
+        
+ out:
+        if(sioc32.arg && sioc32.length > 0)
+		kfree(sioc.arg);
+        
+	return err;
+}
+
+
+static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg)
+{
+        int i;
+        unsigned int cmd = 0;
+        
+	switch (cmd32) {
+	case SONET_GETSTAT:
+	case SONET_GETSTATZ:
+	case SONET_GETDIAG:
+	case SONET_SETDIAG:
+	case SONET_CLRDIAG:
+	case SONET_SETFRAMING:
+	case SONET_GETFRAMING:
+	case SONET_GETFRSENSE:
+		return do_atmif_sioc(fd, cmd32, arg);
+	}
+
+		for (i = 0; i < NR_ATM_IOCTL; i++) {
+			if (cmd32 == atm_ioctl_map[i].cmd32) {
+				cmd = atm_ioctl_map[i].cmd;
+				break;
+			}
+		}
+	        if (i == NR_ATM_IOCTL) {
+	        return -EINVAL;
+	        }
+        
+        switch (cmd) {
+	case ATM_GETNAMES:
+		return do_atm_iobuf(fd, cmd, arg);
+	    
+	case ATM_GETLINKRATE:
+        case ATM_GETTYPE:
+        case ATM_GETESI:
+        case ATM_GETADDR:
+        case ATM_RSTADDR:
+        case ATM_ADDADDR:
+        case ATM_DELADDR:
+        case ATM_GETCIRANGE:
+	case ATM_SETCIRANGE:
+	case ATM_SETESI:
+	case ATM_SETESIF:
+	case ATM_GETSTAT:
+	case ATM_GETSTATZ:
+	case ATM_GETLOOP:
+	case ATM_SETLOOP:
+	case ATM_QUERYLOOP:
+                return do_atmif_sioc(fd, cmd, arg);
+        }
+
+        return -EINVAL;
+}
+
+#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
+/* Ugh, LVM. Pitty it was not cleaned up before accepted :((. */
+typedef struct {
+	uint8_t vg_name[NAME_LEN];
+	uint32_t vg_number;
+	uint32_t vg_access;
+	uint32_t vg_status;
+	uint32_t lv_max;
+	uint32_t lv_cur;
+	uint32_t lv_open;
+	uint32_t pv_max;
+	uint32_t pv_cur;
+	uint32_t pv_act;
+	uint32_t dummy;
+	uint32_t vgda;
+	uint32_t pe_size;
+	uint32_t pe_total;
+	uint32_t pe_allocated;
+	uint32_t pvg_total;
+	u32 proc;
+	u32 pv[ABS_MAX_PV + 1];
+	u32 lv[ABS_MAX_LV + 1];
+    	uint8_t vg_uuid[UUID_LEN+1];	/* volume group UUID */
+	uint8_t dummy1[200];
+} vg32_t;
+
+typedef struct {
+	uint8_t id[2];
+	uint16_t version;
+	lvm_disk_data_t pv_on_disk;
+	lvm_disk_data_t vg_on_disk;
+	lvm_disk_data_t pv_namelist_on_disk;
+	lvm_disk_data_t lv_on_disk;
+	lvm_disk_data_t pe_on_disk;
+	uint8_t pv_name[NAME_LEN];
+	uint8_t vg_name[NAME_LEN];
+	uint8_t system_id[NAME_LEN];
+	kdev_t pv_dev;
+	uint32_t pv_number;
+	uint32_t pv_status;
+	uint32_t pv_allocatable;
+	uint32_t pv_size;
+	uint32_t lv_cur;
+	uint32_t pe_size;
+	uint32_t pe_total;
+	uint32_t pe_allocated;
+	uint32_t pe_stale;
+	u32 pe;
+	u32 inode;
+	uint8_t pv_uuid[UUID_LEN+1];
+} pv32_t;
+
+typedef struct {
+	char lv_name[NAME_LEN];
+	u32 lv;
+} lv_req32_t;
+
+typedef struct {
+	u32 lv_index;
+	u32 lv;
+	/* Transfer size because user space and kernel space differ */
+	uint16_t size;
+} lv_status_byindex_req32_t;
+
+typedef struct {
+	__kernel_dev_t32 dev;
+	u32   lv;
+} lv_status_bydev_req32_t;
+
+typedef struct {
+	uint8_t lv_name[NAME_LEN];
+	kdev_t old_dev;
+	kdev_t new_dev;
+	u32 old_pe;
+	u32 new_pe;
+} le_remap_req32_t;
+
+typedef struct {
+	char pv_name[NAME_LEN];
+	u32 pv;
+} pv_status_req32_t;
+
+typedef struct {
+	uint8_t lv_name[NAME_LEN];
+	uint8_t vg_name[NAME_LEN];
+	uint32_t lv_access;
+	uint32_t lv_status;
+	uint32_t lv_open;
+	kdev_t lv_dev;
+	uint32_t lv_number;
+	uint32_t lv_mirror_copies;
+	uint32_t lv_recovery;
+	uint32_t lv_schedule;
+	uint32_t lv_size;
+	u32 lv_current_pe;
+	uint32_t lv_current_le;
+	uint32_t lv_allocated_le;
+	uint32_t lv_stripes;
+	uint32_t lv_stripesize;
+	uint32_t lv_badblock;
+	uint32_t lv_allocation;
+	uint32_t lv_io_timeout;
+	uint32_t lv_read_ahead;
+	/* delta to version 1 starts here */
+	u32 lv_snapshot_org;
+	u32 lv_snapshot_prev;
+	u32 lv_snapshot_next;
+	u32 lv_block_exception;
+	uint32_t lv_remap_ptr;
+	uint32_t lv_remap_end;
+	uint32_t lv_chunk_size;
+	uint32_t lv_snapshot_minor;
+	char dummy[200];
+} lv32_t;
+
+typedef struct {
+	u32 hash[2];
+	u32 rsector_org;
+	kdev_t rdev_org;
+	u32 rsector_new;
+	kdev_t rdev_new;
+} lv_block_exception32_t;
+
+static void put_lv_t(lv_t *l)
+{
+	if (l->lv_current_pe) vfree(l->lv_current_pe);
+	if (l->lv_block_exception) vfree(l->lv_block_exception);
+	kfree(l);
+}
+
+static lv_t *get_lv_t(u32 p, int *errp)
+{
+	int err, i;
+	u32 ptr1, ptr2;
+	size_t size;
+	lv_block_exception32_t *lbe32;
+	lv_block_exception_t *lbe;
+	lv32_t *ul = (lv32_t *)A(p);
+	lv_t *l = (lv_t *) kmalloc(sizeof(lv_t), GFP_KERNEL);
+
+	if (!l) {
+		*errp = -ENOMEM;
+		return NULL;
+	}
+	memset(l, 0, sizeof(lv_t));
+	err = copy_from_user(l, ul, (long)&((lv32_t *)0)->lv_current_pe);
+	err |= __copy_from_user(&l->lv_current_le, &ul->lv_current_le,
+				((long)&ul->lv_snapshot_org) - ((long)&ul->lv_current_le));
+	err |= __copy_from_user(&l->lv_remap_ptr, &ul->lv_remap_ptr,
+				((long)&ul->dummy[0]) - ((long)&ul->lv_remap_ptr));
+	err |= __get_user(ptr1, &ul->lv_current_pe);
+	err |= __get_user(ptr2, &ul->lv_block_exception);
+	if (err) {
+		kfree(l);
+		*errp = -EFAULT;
+		return NULL;
+	}
+	if (ptr1) {
+		size = l->lv_allocated_le * sizeof(pe_t);
+		l->lv_current_pe = vmalloc(size);
+		if (l->lv_current_pe)
+			err = copy_from_user(l->lv_current_pe, (void *)A(ptr1), size);
+	}
+	if (!err && ptr2) {
+		size = l->lv_remap_end * sizeof(lv_block_exception_t);
+		l->lv_block_exception = lbe = vmalloc(size);
+		if (l->lv_block_exception) {
+			lbe32 = (lv_block_exception32_t *)A(ptr2);
+			memset(lbe, 0, size);
+			for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
+				err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
+				err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
+				err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
+				err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
+			}
+		}
+	}
+	if (err || (ptr1 && !l->lv_current_pe) || (ptr2 && !l->lv_block_exception)) {
+		if (!err)
+			*errp = -ENOMEM;
+		else
+			*errp = -EFAULT;
+		put_lv_t(l);
+		return NULL;
+	}
+	return l;
+}
+
+static int copy_lv_t(u32 ptr, lv_t *l)
+{
+	int err;
+	lv32_t *ul = (lv32_t *)A(ptr);
+	u32 ptr1;
+	size_t size;
+
+	err = get_user(ptr1, &ul->lv_current_pe);
+	if (err)
+		return -EFAULT;
+	err = copy_to_user(ul, l, (long)&((lv32_t *)0)->lv_current_pe);
+	err |= __copy_to_user(&ul->lv_current_le, &l->lv_current_le,
+				((long)&ul->lv_snapshot_org) - ((long)&ul->lv_current_le));
+	err |= __copy_to_user(&ul->lv_remap_ptr, &l->lv_remap_ptr,
+				((long)&ul->dummy[0]) - ((long)&ul->lv_remap_ptr));
+	size = l->lv_allocated_le * sizeof(pe_t);
+	if (ptr1)
+		err |= __copy_to_user((void *)A(ptr1), l->lv_current_pe, size);
+	return err ? -EFAULT : 0;
+}
+
+static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	vg_t *v = NULL;
+	union {
+		lv_req_t lv_req;
+		le_remap_req_t le_remap;
+		lv_status_byindex_req_t lv_byindex;
+	        lv_status_bydev_req_t lv_bydev;
+		pv_status_req_t pv_status;
+	} u;
+	pv_t p;
+	int err;
+	u32 ptr = 0;
+	int i;
+	mm_segment_t old_fs;
+	void *karg = &u;
+
+	switch (cmd) {
+	case VG_STATUS:
+		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
+		if (!v)
+			return -ENOMEM;
+		karg = v;
+		break;
+
+	case VG_CREATE_OLD:
+	case VG_CREATE:
+		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
+		if (!v)
+			return -ENOMEM;
+		if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc)) {
+			kfree(v);
+			return -EFAULT;
+		}
+		/* 'proc' field is unused, just NULL it out. */
+		v->proc = NULL;
+		if (copy_from_user(v->vg_uuid, ((vg32_t *)arg)->vg_uuid, UUID_LEN+1)) {
+			kfree(v);
+			return -EFAULT;
+		}
+		    
+		karg = v;
+		memset(v->pv, 0, sizeof(v->pv) + sizeof(v->lv));
+		if (v->pv_max > ABS_MAX_PV || v->lv_max > ABS_MAX_LV)
+			return -EPERM;
+		for (i = 0; i < v->pv_max; i++) {
+			err = __get_user(ptr, &((vg32_t *)arg)->pv[i]);
+			if (err)
+				break;
+			if (ptr) {
+				v->pv[i] = kmalloc(sizeof(pv_t), GFP_KERNEL);
+				if (!v->pv[i]) {
+					err = -ENOMEM;
+					break;
+				}
+				err = copy_from_user(v->pv[i], (void *)A(ptr),
+						     sizeof(pv32_t) - 8 - UUID_LEN+1);
+				if (err) {
+					err = -EFAULT;
+					break;
+				}
+				err = copy_from_user(v->pv[i]->pv_uuid,
+						     ((pv32_t *)A(ptr))->pv_uuid,
+						     UUID_LEN+1);
+				if (err) {
+				        err = -EFAULT;
+					break;
+				}
+
+				v->pv[i]->pe = NULL;
+				v->pv[i]->bd = NULL;
+			}
+		}
+		if (!err) {
+			for (i = 0; i < v->lv_max; i++) {
+				err = __get_user(ptr, &((vg32_t *)arg)->lv[i]);
+				if (err)
+					break;
+				if (ptr) {
+					v->lv[i] = get_lv_t(ptr, &err);
+					if (err)
+						break;
+				}
+			}
+		}
+		break;
+
+	case LV_CREATE:
+	case LV_EXTEND:
+	case LV_REDUCE:
+	case LV_REMOVE:
+	case LV_RENAME:
+	case LV_STATUS_BYNAME:
+	        err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name));
+		if (err)
+			return -EFAULT;
+		if (cmd != LV_REMOVE) {
+			err = __get_user(ptr, &((lv_req32_t *)arg)->lv);
+			if (err)
+				return err;
+			u.lv_req.lv = get_lv_t(ptr, &err);
+		} else
+			u.lv_req.lv = NULL;
+		break;
+
+	case LV_STATUS_BYINDEX:
+		err = get_user(u.lv_byindex.lv_index,
+			       &((lv_status_byindex_req32_t *)arg)->lv_index);
+		err |= __get_user(ptr, &((lv_status_byindex_req32_t *)arg)->lv);
+		if (err)
+			return err;
+		u.lv_byindex.lv = get_lv_t(ptr, &err);
+		break;
+
+	case LV_STATUS_BYDEV:
+	        err = get_user(u.lv_bydev.dev, &((lv_status_bydev_req32_t *)arg)->dev);
+		err |= __get_user(ptr, &((lv_status_bydev_req32_t *)arg)->lv);
+		if (err)
+			return err;
+		u.lv_bydev.lv = get_lv_t(ptr, &err);
+		break;
+
+	case VG_EXTEND:
+		err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8 - UUID_LEN+1);
+		if (err)
+			return -EFAULT;
+		err = copy_from_user(p.pv_uuid, ((pv32_t *)arg)->pv_uuid, UUID_LEN+1);
+		if (err)
+			return -EFAULT;
+		p.pe = NULL;
+		p.bd = NULL;
+		karg = &p;
+		break;
+
+	case PV_CHANGE:
+	case PV_STATUS:
+		err = copy_from_user(&u.pv_status, arg, sizeof(u.lv_req.lv_name));
+		if (err)
+			return -EFAULT;
+		err = __get_user(ptr, &((pv_status_req32_t *)arg)->pv);
+		if (err)
+			return err;
+		u.pv_status.pv = &p;
+		if (cmd == PV_CHANGE) {
+			err = copy_from_user(&p, (void *)A(ptr),
+					     sizeof(pv32_t) - 8 - UUID_LEN+1);
+			if (err)
+				return -EFAULT;
+			p.pe = NULL;
+			p.bd = NULL;
+		}
+		break;
+	};
+
+        old_fs = get_fs(); set_fs (KERNEL_DS);
+        err = sys_ioctl (fd, cmd, (unsigned long)karg);
+        set_fs (old_fs);
+
+	switch (cmd) {
+	case VG_STATUS:
+		if (!err) {
+			if (copy_to_user((void *)arg, v, (long)&((vg32_t *)0)->proc) ||
+			    clear_user(&((vg32_t *)arg)->proc, sizeof(vg32_t) - (long)&((vg32_t *)0)->proc))
+				err = -EFAULT;
+		}
+		if (copy_to_user(((vg32_t *)arg)->vg_uuid, v->vg_uuid, UUID_LEN+1)) {
+		        err = -EFAULT;
+		}
+		kfree(v);
+		break;
+
+	case VG_CREATE_OLD:
+	case VG_CREATE:
+		for (i = 0; i < v->pv_max; i++) {
+			if (v->pv[i])
+				kfree(v->pv[i]);
+		}
+		for (i = 0; i < v->lv_max; i++) {
+			if (v->lv[i])
+				put_lv_t(v->lv[i]);
+		}
+		kfree(v);
+		break;
+
+	case LV_STATUS_BYNAME:
+		if (!err && u.lv_req.lv)
+			err = copy_lv_t(ptr, u.lv_req.lv);
+		/* Fall through */
+
+        case LV_CREATE:
+	case LV_EXTEND:
+	case LV_REDUCE:
+		if (u.lv_req.lv)
+			put_lv_t(u.lv_req.lv);
+		break;
+
+	case LV_STATUS_BYINDEX:
+		if (u.lv_byindex.lv) {
+			if (!err)
+				err = copy_lv_t(ptr, u.lv_byindex.lv);
+			put_lv_t(u.lv_byindex.lv);
+		}
+		break;
+
+	case LV_STATUS_BYDEV:
+	        if (u.lv_bydev.lv) {
+			if (!err)
+				err = copy_lv_t(ptr, u.lv_bydev.lv);
+			put_lv_t(u.lv_byindex.lv);
+	        }
+	        break;
+
+	case PV_STATUS:
+		if (!err) {
+			err = copy_to_user((void *)A(ptr), &p, sizeof(pv32_t) - 8 - UUID_LEN+1);
+			if (err)
+				return -EFAULT;
+			err = copy_to_user(((pv_t *)A(ptr))->pv_uuid, p.pv_uuid, UUID_LEN + 1);
+			if (err)
+				return -EFAULT;
+		}
+		break;
+	};
+
+	return err;
+}
+#endif
+
+#ifdef CONFIG_GENRTC
+#endif
+
+#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+/* This really belongs in include/linux/drm.h -DaveM */
+#include "../../../drivers/char/drm/drm.h"
+
+typedef struct drm32_version {
+	int    version_major;	  /* Major version			    */
+	int    version_minor;	  /* Minor version			    */
+	int    version_patchlevel;/* Patch level			    */
+	int    name_len;	  /* Length of name buffer		    */
+	u32    name;		  /* Name of driver			    */
+	int    date_len;	  /* Length of date buffer		    */
+	u32    date;		  /* User-space buffer to hold date	    */
+	int    desc_len;	  /* Length of desc buffer		    */
+	u32    desc;		  /* User-space buffer to hold desc	    */
+} drm32_version_t;
+#define DRM32_IOCTL_VERSION    DRM_IOWR(0x00, drm32_version_t)
+
+static int drm32_version(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_version_t *uversion = (drm32_version_t *)arg;
+	char *name_ptr, *date_ptr, *desc_ptr;
+	u32 tmp1, tmp2, tmp3;
+	drm_version_t kversion;
+	mm_segment_t old_fs;
+	int ret;
+
+	memset(&kversion, 0, sizeof(kversion));
+	if (get_user(kversion.name_len, &uversion->name_len) ||
+	    get_user(kversion.date_len, &uversion->date_len) ||
+	    get_user(kversion.desc_len, &uversion->desc_len) ||
+	    get_user(tmp1, &uversion->name) ||
+	    get_user(tmp2, &uversion->date) ||
+	    get_user(tmp3, &uversion->desc))
+		return -EFAULT;
+
+	name_ptr = (char *) A(tmp1);
+	date_ptr = (char *) A(tmp2);
+	desc_ptr = (char *) A(tmp3);
+
+	ret = -ENOMEM;
+	if (kversion.name_len && name_ptr) {
+		kversion.name = kmalloc(kversion.name_len, GFP_KERNEL);
+		if (!kversion.name)
+			goto out;
+	}
+	if (kversion.date_len && date_ptr) {
+		kversion.date = kmalloc(kversion.date_len, GFP_KERNEL);
+		if (!kversion.date)
+			goto out;
+	}
+	if (kversion.desc_len && desc_ptr) {
+		kversion.desc = kmalloc(kversion.desc_len, GFP_KERNEL);
+		if (!kversion.desc)
+			goto out;
+	}
+
+        old_fs = get_fs();
+	set_fs(KERNEL_DS);
+        ret = sys_ioctl (fd, DRM_IOCTL_VERSION, (unsigned long)&kversion);
+        set_fs(old_fs);
+
+	if (!ret) {
+		if ((kversion.name &&
+		     copy_to_user(name_ptr, kversion.name, kversion.name_len)) ||
+		    (kversion.date &&
+		     copy_to_user(date_ptr, kversion.date, kversion.date_len)) ||
+		    (kversion.desc &&
+		     copy_to_user(desc_ptr, kversion.desc, kversion.desc_len)))
+			ret = -EFAULT;
+		if (put_user(kversion.version_major, &uversion->version_major) ||
+		    put_user(kversion.version_minor, &uversion->version_minor) ||
+		    put_user(kversion.version_patchlevel, &uversion->version_patchlevel) ||
+		    put_user(kversion.name_len, &uversion->name_len) ||
+		    put_user(kversion.date_len, &uversion->date_len) ||
+		    put_user(kversion.desc_len, &uversion->desc_len))
+			ret = -EFAULT;
+	}
+
+out:
+	if (kversion.name)
+		kfree(kversion.name);
+	if (kversion.date)
+		kfree(kversion.date);
+	if (kversion.desc)
+		kfree(kversion.desc);
+	return ret;
+}
+
+typedef struct drm32_unique {
+	int	unique_len;	  /* Length of unique			    */
+	u32	unique;		  /* Unique name for driver instantiation   */
+} drm32_unique_t;
+#define DRM32_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm32_unique_t)
+#define DRM32_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm32_unique_t)
+
+static int drm32_getsetunique(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_unique_t *uarg = (drm32_unique_t *)arg;
+	drm_unique_t karg;
+	mm_segment_t old_fs;
+	char *uptr;
+	u32 tmp;
+	int ret;
+
+	if (get_user(karg.unique_len, &uarg->unique_len))
+		return -EFAULT;
+	karg.unique = NULL;
+
+	if (get_user(tmp, &uarg->unique))
+		return -EFAULT;
+
+	uptr = (char *) A(tmp);
+
+	if (uptr) {
+		karg.unique = kmalloc(karg.unique_len, GFP_KERNEL);
+		if (!karg.unique)
+			return -ENOMEM;
+		if (cmd == DRM32_IOCTL_SET_UNIQUE &&
+		    copy_from_user(karg.unique, uptr, karg.unique_len)) {
+			kfree(karg.unique);
+			return -EFAULT;
+		}
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	if (cmd == DRM32_IOCTL_GET_UNIQUE)
+		ret = sys_ioctl (fd, DRM_IOCTL_GET_UNIQUE, (unsigned long)&karg);
+	else
+		ret = sys_ioctl (fd, DRM_IOCTL_SET_UNIQUE, (unsigned long)&karg);
+        set_fs(old_fs);
+
+	if (!ret) {
+		if (cmd == DRM32_IOCTL_GET_UNIQUE &&
+		    uptr != NULL &&
+		    copy_to_user(uptr, karg.unique, karg.unique_len))
+			ret = -EFAULT;
+		if (put_user(karg.unique_len, &uarg->unique_len))
+			ret = -EFAULT;
+	}
+
+	if (karg.unique != NULL)
+		kfree(karg.unique);
+
+	return ret;
+}
+
+typedef struct drm32_map {
+	u32		offset;	 /* Requested physical address (0 for SAREA)*/
+	u32		size;	 /* Requested physical size (bytes)	    */
+	drm_map_type_t	type;	 /* Type of memory to map		    */
+	drm_map_flags_t flags;	 /* Flags				    */
+	u32		handle;  /* User-space: "Handle" to pass to mmap    */
+				 /* Kernel-space: kernel-virtual address    */
+	int		mtrr;	 /* MTRR slot used			    */
+				 /* Private data			    */
+} drm32_map_t;
+#define DRM32_IOCTL_ADD_MAP    DRM_IOWR(0x15, drm32_map_t)
+
+static int drm32_addmap(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_map_t *uarg = (drm32_map_t *) arg;
+	drm_map_t karg;
+	mm_segment_t old_fs;
+	u32 tmp;
+	int ret;
+
+	ret  = get_user(karg.offset, &uarg->offset);
+	ret |= get_user(karg.size, &uarg->size);
+	ret |= get_user(karg.type, &uarg->type);
+	ret |= get_user(karg.flags, &uarg->flags);
+	ret |= get_user(tmp, &uarg->handle);
+	ret |= get_user(karg.mtrr, &uarg->mtrr);
+	if (ret)
+		return -EFAULT;
+
+	karg.handle = (void *) A(tmp);
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_ADD_MAP, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		ret  = put_user(karg.offset, &uarg->offset);
+		ret |= put_user(karg.size, &uarg->size);
+		ret |= put_user(karg.type, &uarg->type);
+		ret |= put_user(karg.flags, &uarg->flags);
+		tmp = (u32) (long)karg.handle;
+		ret |= put_user(tmp, &uarg->handle);
+		ret |= put_user(karg.mtrr, &uarg->mtrr);
+		if (ret)
+			ret = -EFAULT;
+	}
+
+	return ret;
+}
+
+typedef struct drm32_buf_info {
+	int	       count;	/* Entries in list			     */
+	u32	       list;    /* (drm_buf_desc_t *) */ 
+} drm32_buf_info_t;
+#define DRM32_IOCTL_INFO_BUFS  DRM_IOWR(0x18, drm32_buf_info_t)
+
+static int drm32_info_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_buf_info_t *uarg = (drm32_buf_info_t *)arg;
+	drm_buf_desc_t *ulist;
+	drm_buf_info_t karg;
+	mm_segment_t old_fs;
+	int orig_count, ret;
+	u32 tmp;
+
+	if (get_user(karg.count, &uarg->count) ||
+	    get_user(tmp, &uarg->list))
+		return -EFAULT;
+
+	ulist = (drm_buf_desc_t *) A(tmp);
+
+	orig_count = karg.count;
+
+	karg.list = kmalloc(karg.count * sizeof(drm_buf_desc_t), GFP_KERNEL);
+	if (!karg.list)
+		return -EFAULT;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_INFO_BUFS, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		if (karg.count <= orig_count &&
+		    (copy_to_user(ulist, karg.list,
+				  karg.count * sizeof(drm_buf_desc_t))))
+			ret = -EFAULT;
+		if (put_user(karg.count, &uarg->count))
+			ret = -EFAULT;
+	}
+
+	kfree(karg.list);
+
+	return ret;
+}
+
+typedef struct drm32_buf_free {
+	int	       count;
+	u32	       list;	/* (int *) */
+} drm32_buf_free_t;
+#define DRM32_IOCTL_FREE_BUFS  DRM_IOW( 0x1a, drm32_buf_free_t)
+
+static int drm32_free_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_buf_free_t *uarg = (drm32_buf_free_t *)arg;
+	drm_buf_free_t karg;
+	mm_segment_t old_fs;
+	int *ulist;
+	int ret;
+	u32 tmp;
+
+	if (get_user(karg.count, &uarg->count) ||
+	    get_user(tmp, &uarg->list))
+		return -EFAULT;
+
+	ulist = (int *) A(tmp);
+
+	karg.list = kmalloc(karg.count * sizeof(int), GFP_KERNEL);
+	if (!karg.list)
+		return -ENOMEM;
+
+	ret = -EFAULT;
+	if (copy_from_user(karg.list, ulist, (karg.count * sizeof(int))))
+		goto out;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_FREE_BUFS, (unsigned long) &karg);
+	set_fs(old_fs);
+
+out:
+	kfree(karg.list);
+
+	return ret;
+}
+
+typedef struct drm32_buf_pub {
+	int		  idx;	       /* Index into master buflist	     */
+	int		  total;       /* Buffer size			     */
+	int		  used;	       /* Amount of buffer in use (for DMA)  */
+	u32		  address;     /* Address of buffer (void *)	     */
+} drm32_buf_pub_t;
+
+typedef struct drm32_buf_map {
+	int	      count;	/* Length of buflist			    */
+	u32	      virtual;	/* Mmaped area in user-virtual (void *)	    */
+	u32 	      list;	/* Buffer information (drm_buf_pub_t *)	    */
+} drm32_buf_map_t;
+#define DRM32_IOCTL_MAP_BUFS   DRM_IOWR(0x19, drm32_buf_map_t)
+
+static int drm32_map_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_buf_map_t *uarg = (drm32_buf_map_t *)arg;
+	drm32_buf_pub_t *ulist;
+	drm_buf_map_t karg;
+	mm_segment_t old_fs;
+	int orig_count, ret, i;
+	u32 tmp1, tmp2;
+
+	if (get_user(karg.count, &uarg->count) ||
+	    get_user(tmp1, &uarg->virtual) ||
+	    get_user(tmp2, &uarg->list))
+		return -EFAULT;
+
+	karg.virtual = (void *) A(tmp1);
+	ulist = (drm32_buf_pub_t *) A(tmp2);
+
+	orig_count = karg.count;
+
+	karg.list = kmalloc(karg.count * sizeof(drm_buf_pub_t), GFP_KERNEL);
+	if (!karg.list)
+		return -ENOMEM;
+
+	ret = -EFAULT;
+	for (i = 0; i < karg.count; i++) {
+		if (get_user(karg.list[i].idx, &ulist[i].idx) ||
+		    get_user(karg.list[i].total, &ulist[i].total) ||
+		    get_user(karg.list[i].used, &ulist[i].used) ||
+		    get_user(tmp1, &ulist[i].address))
+			goto out;
+
+		karg.list[i].address = (void *) A(tmp1);
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_MAP_BUFS, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		for (i = 0; i < orig_count; i++) {
+			tmp1 = (u32) (long) karg.list[i].address;
+			if (put_user(karg.list[i].idx, &ulist[i].idx) ||
+			    put_user(karg.list[i].total, &ulist[i].total) ||
+			    put_user(karg.list[i].used, &ulist[i].used) ||
+			    put_user(tmp1, &ulist[i].address)) {
+				ret = -EFAULT;
+				goto out;
+			}
+		}
+		if (put_user(karg.count, &uarg->count))
+			ret = -EFAULT;
+	}
+
+out:
+	kfree(karg.list);
+	return ret;
+}
+
+typedef struct drm32_dma {
+				/* Indices here refer to the offset into
+				   buflist in drm_buf_get_t.  */
+	int		context;	  /* Context handle		    */
+	int		send_count;	  /* Number of buffers to send	    */
+	u32		send_indices;	  /* List of handles to buffers (int *) */
+	u32		send_sizes;	  /* Lengths of data to send (int *) */
+	drm_dma_flags_t flags;		  /* Flags			    */
+	int		request_count;	  /* Number of buffers requested    */
+	int		request_size;	  /* Desired size for buffers	    */
+	u32		request_indices;  /* Buffer information (int *)	    */
+	u32		request_sizes;    /* (int *) */
+	int		granted_count;	  /* Number of buffers granted	    */
+} drm32_dma_t;
+#define DRM32_IOCTL_DMA	     DRM_IOWR(0x29, drm32_dma_t)
+
+/* RED PEN	The DRM layer blindly dereferences the send/request
+ * 		indice/size arrays even though they are userland
+ * 		pointers.  -DaveM
+ */
+static int drm32_dma(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_dma_t *uarg = (drm32_dma_t *) arg;
+	int *u_si, *u_ss, *u_ri, *u_rs;
+	drm_dma_t karg;
+	mm_segment_t old_fs;
+	int ret;
+	u32 tmp1, tmp2, tmp3, tmp4;
+
+	karg.send_indices = karg.send_sizes = NULL;
+	karg.request_indices = karg.request_sizes = NULL;
+
+	if (get_user(karg.context, &uarg->context) ||
+	    get_user(karg.send_count, &uarg->send_count) ||
+	    get_user(tmp1, &uarg->send_indices) ||
+	    get_user(tmp2, &uarg->send_sizes) ||
+	    get_user(karg.flags, &uarg->flags) ||
+	    get_user(karg.request_count, &uarg->request_count) ||
+	    get_user(karg.request_size, &uarg->request_size) ||
+	    get_user(tmp3, &uarg->request_indices) ||
+	    get_user(tmp4, &uarg->request_sizes) ||
+	    get_user(karg.granted_count, &uarg->granted_count))
+		return -EFAULT;
+
+	u_si = (int *) A(tmp1);
+	u_ss = (int *) A(tmp2);
+	u_ri = (int *) A(tmp3);
+	u_rs = (int *) A(tmp4);
+
+	if (karg.send_count) {
+		karg.send_indices = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
+		karg.send_sizes = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
+
+		ret = -ENOMEM;
+		if (!karg.send_indices || !karg.send_sizes)
+			goto out;
+
+		ret = -EFAULT;
+		if (copy_from_user(karg.send_indices, u_si,
+				   (karg.send_count * sizeof(int))) ||
+		    copy_from_user(karg.send_sizes, u_ss,
+				   (karg.send_count * sizeof(int))))
+			goto out;
+	}
+
+	if (karg.request_count) {
+		karg.request_indices = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
+		karg.request_sizes = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
+
+		ret = -ENOMEM;
+		if (!karg.request_indices || !karg.request_sizes)
+			goto out;
+
+		ret = -EFAULT;
+		if (copy_from_user(karg.request_indices, u_ri,
+				   (karg.request_count * sizeof(int))) ||
+		    copy_from_user(karg.request_sizes, u_rs,
+				   (karg.request_count * sizeof(int))))
+			goto out;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_DMA, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		if (put_user(karg.context, &uarg->context) ||
+		    put_user(karg.send_count, &uarg->send_count) ||
+		    put_user(karg.flags, &uarg->flags) ||
+		    put_user(karg.request_count, &uarg->request_count) ||
+		    put_user(karg.request_size, &uarg->request_size) ||
+		    put_user(karg.granted_count, &uarg->granted_count))
+			ret = -EFAULT;
+
+		if (karg.send_count) {
+			if (copy_to_user(u_si, karg.send_indices,
+					 (karg.send_count * sizeof(int))) ||
+			    copy_to_user(u_ss, karg.send_sizes,
+					 (karg.send_count * sizeof(int))))
+				ret = -EFAULT;
+		}
+		if (karg.request_count) {
+			if (copy_to_user(u_ri, karg.request_indices,
+					 (karg.request_count * sizeof(int))) ||
+			    copy_to_user(u_rs, karg.request_sizes,
+					 (karg.request_count * sizeof(int))))
+				ret = -EFAULT;
+		}
+	}
+
+out:
+	if (karg.send_indices)
+		kfree(karg.send_indices);
+	if (karg.send_sizes)
+		kfree(karg.send_sizes);
+	if (karg.request_indices)
+		kfree(karg.request_indices);
+	if (karg.request_sizes)
+		kfree(karg.request_sizes);
+
+	return ret;
+}
+
+typedef struct drm32_ctx_res {
+	int		count;
+	u32		contexts; /* (drm_ctx_t *) */
+} drm32_ctx_res_t;
+#define DRM32_IOCTL_RES_CTX    DRM_IOWR(0x26, drm32_ctx_res_t)
+
+static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_ctx_res_t *uarg = (drm32_ctx_res_t *) arg;
+	drm_ctx_t *ulist;
+	drm_ctx_res_t karg;
+	mm_segment_t old_fs;
+	int orig_count, ret;
+	u32 tmp;
+
+	karg.contexts = NULL;
+	if (get_user(karg.count, &uarg->count) ||
+	    get_user(tmp, &uarg->contexts))
+		return -EFAULT;
+
+	ulist = (drm_ctx_t *) A(tmp);
+
+	orig_count = karg.count;
+	if (karg.count && ulist) {
+		karg.contexts = kmalloc((karg.count * sizeof(drm_ctx_t)), GFP_KERNEL);
+		if (!karg.contexts)
+			return -ENOMEM;
+		if (copy_from_user(karg.contexts, ulist,
+				   (karg.count * sizeof(drm_ctx_t)))) {
+			kfree(karg.contexts);
+			return -EFAULT;
+		}
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_RES_CTX, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		if (orig_count) {
+			if (copy_to_user(ulist, karg.contexts,
+					 (orig_count * sizeof(drm_ctx_t))))
+				ret = -EFAULT;
+		}
+		if (put_user(karg.count, &uarg->count))
+			ret = -EFAULT;
+	}
+
+	if (karg.contexts)
+		kfree(karg.contexts);
+
+	return ret;
+}
+
+#endif
+
+static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return -EINVAL;
+}
+
+static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	/* The mkswap binary hard codes it to Intel value :-((( */
+	return w_long(fd, BLKGETSIZE, arg);
+}
+
+struct blkpg_ioctl_arg32 {
+	int op;
+	int flags;
+	int datalen;
+	u32 data;
+};
+                                
+static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg)
+{
+	struct blkpg_ioctl_arg a;
+	struct blkpg_partition p;
+	int err;
+	mm_segment_t old_fs = get_fs();
+	
+	err = get_user(a.op, &arg->op);
+	err |= __get_user(a.flags, &arg->flags);
+	err |= __get_user(a.datalen, &arg->datalen);
+	err |= __get_user((long)a.data, &arg->data);
+	if (err) return err;
+	switch (a.op) {
+	case BLKPG_ADD_PARTITION:
+	case BLKPG_DEL_PARTITION:
+		if (a.datalen < sizeof(struct blkpg_partition))
+			return -EINVAL;
+                if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
+			return -EFAULT;
+		a.data = &p;
+		set_fs (KERNEL_DS);
+		err = sys_ioctl(fd, cmd, (unsigned long)&a);
+		set_fs (old_fs);
+	default:
+		return -EINVAL;
+	}                                        
+	return err;
+}
+
+static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
+}
+
+
+struct serial_struct32 {
+	int	type;
+	int	line;
+	unsigned int	port;
+	int	irq;
+	int	flags;
+	int	xmit_fifo_size;
+	int	custom_divisor;
+	int	baud_base;
+	unsigned short	close_delay;
+	char	io_type;
+	char	reserved_char[1];
+	int	hub6;
+	unsigned short	closing_wait; /* time to wait before closing */
+	unsigned short	closing_wait2; /* no longer used... */
+	unsigned int	iomem_base;	/* char * really */
+	unsigned short	iomem_reg_shift;
+	unsigned int	port_high;
+	int	reserved[1];
+};
+
+static int do_tiocgserial(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct serial_struct ss;
+	int ret;
+	struct serial_struct32 * uptr = (struct serial_struct32 *)arg;
+	mm_segment_t old_fs = get_fs();
+
+	set_fs (KERNEL_DS);
+	ret = sys_ioctl(fd, cmd, (unsigned long) &ss);
+	set_fs(old_fs);
+
+	if (!ret) {
+		/* structs match up to iomem_base */
+		ret = copy_to_user(uptr, &ss, sizeof(struct serial_struct32));
+		ret |= put_user(ss.iomem_base, &uptr->iomem_base);
+		ret |= put_user(ss.iomem_reg_shift, &uptr->iomem_reg_shift);
+		ret |= put_user(ss.port_high, &uptr->port_high);
+		if (ret)
+			ret = -EFAULT;
+	}
+	return ret;
+}
+
+
+struct ioctl_trans {
+	unsigned long handler;
+	unsigned int cmd;
+	unsigned int next;
+};
+#define HANDLE_IOCTL(cmd, handler) asm volatile(".dword %1\n.word %0, 0" : : "i" (cmd), "i" (handler));
+
+#define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL(cmd, sys_ioctl) 
+
+
+#define IOCTL_TABLE_START void ioctl32_foo(void) { asm volatile(".data\nioctl_translations:");
+#define IOCTL_TABLE_END asm volatile("\nioctl_translations_end:\n\t.previous"); }
+
+IOCTL_TABLE_START
+/* List here exlicitly which ioctl's are known to have
+ * compatable types passed or none at all...
+ */
+/* Big T */
+COMPATIBLE_IOCTL(TCGETA)
+COMPATIBLE_IOCTL(TCSETA)
+COMPATIBLE_IOCTL(TCSETAW)
+COMPATIBLE_IOCTL(TCSETAF)
+COMPATIBLE_IOCTL(TCSBRK)
+COMPATIBLE_IOCTL(TCXONC)
+COMPATIBLE_IOCTL(TCFLSH)
+COMPATIBLE_IOCTL(TCGETS)
+COMPATIBLE_IOCTL(TCSETS)
+COMPATIBLE_IOCTL(TCSETSW)
+COMPATIBLE_IOCTL(TCSETSF)
+COMPATIBLE_IOCTL(TIOCLINUX)
+/* Little t */
+COMPATIBLE_IOCTL(TIOCGETD)
+COMPATIBLE_IOCTL(TIOCSETD)
+COMPATIBLE_IOCTL(TIOCEXCL)
+COMPATIBLE_IOCTL(TIOCNXCL)
+COMPATIBLE_IOCTL(TIOCCONS)
+COMPATIBLE_IOCTL(TIOCGSOFTCAR)
+COMPATIBLE_IOCTL(TIOCSSOFTCAR)
+COMPATIBLE_IOCTL(TIOCSWINSZ)
+COMPATIBLE_IOCTL(TIOCGWINSZ)
+COMPATIBLE_IOCTL(TIOCMGET)
+COMPATIBLE_IOCTL(TIOCMBIC)
+COMPATIBLE_IOCTL(TIOCMBIS)
+COMPATIBLE_IOCTL(TIOCMSET)
+COMPATIBLE_IOCTL(TIOCPKT)
+COMPATIBLE_IOCTL(TIOCNOTTY)
+COMPATIBLE_IOCTL(TIOCSTI)
+COMPATIBLE_IOCTL(TIOCOUTQ)
+COMPATIBLE_IOCTL(TIOCSPGRP)
+COMPATIBLE_IOCTL(TIOCGPGRP)
+COMPATIBLE_IOCTL(TIOCSCTTY)
+COMPATIBLE_IOCTL(TIOCGPTN)
+COMPATIBLE_IOCTL(TIOCSPTLCK)
+COMPATIBLE_IOCTL(TIOCSSERIAL)
+COMPATIBLE_IOCTL(TIOCSERGETLSR)
+/* Big F */
+#if 0
+COMPATIBLE_IOCTL(FBIOGTYPE)
+COMPATIBLE_IOCTL(FBIOSATTR)
+COMPATIBLE_IOCTL(FBIOGATTR)
+COMPATIBLE_IOCTL(FBIOSVIDEO)
+COMPATIBLE_IOCTL(FBIOGVIDEO)
+COMPATIBLE_IOCTL(FBIOGCURSOR32)  /* This is not implemented yet. Later it should be converted... */
+COMPATIBLE_IOCTL(FBIOSCURPOS)
+COMPATIBLE_IOCTL(FBIOGCURPOS)
+COMPATIBLE_IOCTL(FBIOGCURMAX)
+#endif
+COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO)
+COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO)
+
+COMPATIBLE_IOCTL(FBIOPAN_DISPLAY)
+COMPATIBLE_IOCTL(FBIOGET_FCURSORINFO)
+COMPATIBLE_IOCTL(FBIOGET_VCURSORINFO)
+COMPATIBLE_IOCTL(FBIOPUT_VCURSORINFO)
+COMPATIBLE_IOCTL(FBIOGET_CURSORSTATE)
+COMPATIBLE_IOCTL(FBIOPUT_CURSORSTATE)
+COMPATIBLE_IOCTL(FBIOGET_CON2FBMAP)
+COMPATIBLE_IOCTL(FBIOPUT_CON2FBMAP)
+/* Little f */
+COMPATIBLE_IOCTL(FIOCLEX)
+COMPATIBLE_IOCTL(FIONCLEX)
+COMPATIBLE_IOCTL(FIOASYNC)
+COMPATIBLE_IOCTL(FIONBIO)
+COMPATIBLE_IOCTL(FIONREAD)  /* This is also TIOCINQ */
+/* 0x00 */
+COMPATIBLE_IOCTL(FIBMAP)
+COMPATIBLE_IOCTL(FIGETBSZ)
+/* 0x03 -- HD/IDE ioctl's used by hdparm and friends.
+ *         Some need translations, these do not.
+ */
+COMPATIBLE_IOCTL(HDIO_GET_IDENTITY)
+COMPATIBLE_IOCTL(HDIO_SET_DMA)
+COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS)
+COMPATIBLE_IOCTL(HDIO_SET_UNMASKINTR)
+COMPATIBLE_IOCTL(HDIO_SET_NOWERR)
+COMPATIBLE_IOCTL(HDIO_SET_32BIT)
+COMPATIBLE_IOCTL(HDIO_SET_MULTCOUNT)
+COMPATIBLE_IOCTL(HDIO_DRIVE_CMD)
+COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE)
+COMPATIBLE_IOCTL(HDIO_SCAN_HWIF)
+COMPATIBLE_IOCTL(HDIO_SET_NICE)
+/* 0x02 -- Floppy ioctls */
+COMPATIBLE_IOCTL(FDMSGON)
+COMPATIBLE_IOCTL(FDMSGOFF)
+COMPATIBLE_IOCTL(FDSETEMSGTRESH)
+COMPATIBLE_IOCTL(FDFLUSH)
+COMPATIBLE_IOCTL(FDWERRORCLR)
+COMPATIBLE_IOCTL(FDSETMAXERRS)
+COMPATIBLE_IOCTL(FDGETMAXERRS)
+COMPATIBLE_IOCTL(FDGETDRVTYP)
+COMPATIBLE_IOCTL(FDEJECT)
+COMPATIBLE_IOCTL(FDCLRPRM)
+COMPATIBLE_IOCTL(FDFMTBEG)
+COMPATIBLE_IOCTL(FDFMTEND)
+COMPATIBLE_IOCTL(FDRESET)
+COMPATIBLE_IOCTL(FDTWADDLE)
+COMPATIBLE_IOCTL(FDFMTTRK)
+COMPATIBLE_IOCTL(FDRAWCMD)
+/* 0x12 */
+COMPATIBLE_IOCTL(BLKROSET)
+COMPATIBLE_IOCTL(BLKROGET)
+COMPATIBLE_IOCTL(BLKRRPART)
+COMPATIBLE_IOCTL(BLKFLSBUF)
+COMPATIBLE_IOCTL(BLKRASET)
+COMPATIBLE_IOCTL(BLKFRASET)
+COMPATIBLE_IOCTL(BLKSECTSET)
+COMPATIBLE_IOCTL(BLKSSZGET)
+
+/* RAID */
+COMPATIBLE_IOCTL(RAID_VERSION)
+COMPATIBLE_IOCTL(GET_ARRAY_INFO)
+COMPATIBLE_IOCTL(GET_DISK_INFO)
+COMPATIBLE_IOCTL(PRINT_RAID_DEBUG)
+COMPATIBLE_IOCTL(CLEAR_ARRAY)
+COMPATIBLE_IOCTL(ADD_NEW_DISK)
+COMPATIBLE_IOCTL(HOT_REMOVE_DISK)
+COMPATIBLE_IOCTL(SET_ARRAY_INFO)
+COMPATIBLE_IOCTL(SET_DISK_INFO)
+COMPATIBLE_IOCTL(WRITE_RAID_INFO)
+COMPATIBLE_IOCTL(UNPROTECT_ARRAY)
+COMPATIBLE_IOCTL(PROTECT_ARRAY)
+COMPATIBLE_IOCTL(HOT_ADD_DISK)
+COMPATIBLE_IOCTL(SET_DISK_FAULTY)
+COMPATIBLE_IOCTL(RUN_ARRAY)
+COMPATIBLE_IOCTL(START_ARRAY)
+COMPATIBLE_IOCTL(STOP_ARRAY)
+COMPATIBLE_IOCTL(STOP_ARRAY_RO)
+COMPATIBLE_IOCTL(RESTART_ARRAY_RW)
+
+/* Big K */
+COMPATIBLE_IOCTL(PIO_FONT)
+COMPATIBLE_IOCTL(GIO_FONT)
+COMPATIBLE_IOCTL(KDSIGACCEPT)
+COMPATIBLE_IOCTL(KDGETKEYCODE)
+COMPATIBLE_IOCTL(KDSETKEYCODE)
+COMPATIBLE_IOCTL(KIOCSOUND)
+COMPATIBLE_IOCTL(KDMKTONE)
+COMPATIBLE_IOCTL(KDGKBTYPE)
+COMPATIBLE_IOCTL(KDSETMODE)
+COMPATIBLE_IOCTL(KDGETMODE)
+COMPATIBLE_IOCTL(KDSKBMODE)
+COMPATIBLE_IOCTL(KDGKBMODE)
+COMPATIBLE_IOCTL(KDSKBMETA)
+COMPATIBLE_IOCTL(KDGKBMETA)
+COMPATIBLE_IOCTL(KDGKBENT)
+COMPATIBLE_IOCTL(KDSKBENT)
+COMPATIBLE_IOCTL(KDGKBSENT)
+COMPATIBLE_IOCTL(KDSKBSENT)
+COMPATIBLE_IOCTL(KDGKBDIACR)
+COMPATIBLE_IOCTL(KDSKBDIACR)
+COMPATIBLE_IOCTL(KDGKBLED)
+COMPATIBLE_IOCTL(KDSKBLED)
+COMPATIBLE_IOCTL(KDGETLED)
+COMPATIBLE_IOCTL(KDSETLED)
+COMPATIBLE_IOCTL(GIO_SCRNMAP)
+COMPATIBLE_IOCTL(PIO_SCRNMAP)
+COMPATIBLE_IOCTL(GIO_UNISCRNMAP)
+COMPATIBLE_IOCTL(PIO_UNISCRNMAP)
+COMPATIBLE_IOCTL(PIO_FONTRESET)
+COMPATIBLE_IOCTL(PIO_UNIMAPCLR)
+/* Little k */
+#if 0
+COMPATIBLE_IOCTL(KIOCTYPE)
+COMPATIBLE_IOCTL(KIOCLAYOUT)
+COMPATIBLE_IOCTL(KIOCGTRANS)
+COMPATIBLE_IOCTL(KIOCTRANS)
+COMPATIBLE_IOCTL(KIOCCMD)
+COMPATIBLE_IOCTL(KIOCSDIRECT)
+COMPATIBLE_IOCTL(KIOCSLED)
+COMPATIBLE_IOCTL(KIOCGLED)
+COMPATIBLE_IOCTL(KIOCSRATE)
+COMPATIBLE_IOCTL(KIOCGRATE)
+#endif
+/* Big S */
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
+COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
+COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
+COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
+COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_ENABLE)
+COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE)
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
+COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
+/* Big V */
+COMPATIBLE_IOCTL(VT_SETMODE)
+COMPATIBLE_IOCTL(VT_GETMODE)
+COMPATIBLE_IOCTL(VT_GETSTATE)
+COMPATIBLE_IOCTL(VT_OPENQRY)
+COMPATIBLE_IOCTL(VT_ACTIVATE)
+COMPATIBLE_IOCTL(VT_WAITACTIVE)
+COMPATIBLE_IOCTL(VT_RELDISP)
+COMPATIBLE_IOCTL(VT_DISALLOCATE)
+COMPATIBLE_IOCTL(VT_RESIZE)
+COMPATIBLE_IOCTL(VT_RESIZEX)
+COMPATIBLE_IOCTL(VT_LOCKSWITCH)
+COMPATIBLE_IOCTL(VT_UNLOCKSWITCH)
+/* Little v, the video4linux ioctls */
+COMPATIBLE_IOCTL(VIDIOCGCAP)
+COMPATIBLE_IOCTL(VIDIOCGCHAN)
+COMPATIBLE_IOCTL(VIDIOCSCHAN)
+COMPATIBLE_IOCTL(VIDIOCGPICT)
+COMPATIBLE_IOCTL(VIDIOCSPICT)
+COMPATIBLE_IOCTL(VIDIOCCAPTURE)
+COMPATIBLE_IOCTL(VIDIOCKEY)
+COMPATIBLE_IOCTL(VIDIOCGAUDIO)
+COMPATIBLE_IOCTL(VIDIOCSAUDIO)
+COMPATIBLE_IOCTL(VIDIOCSYNC)
+COMPATIBLE_IOCTL(VIDIOCMCAPTURE)
+COMPATIBLE_IOCTL(VIDIOCGMBUF)
+COMPATIBLE_IOCTL(VIDIOCGUNIT)
+COMPATIBLE_IOCTL(VIDIOCGCAPTURE)
+COMPATIBLE_IOCTL(VIDIOCSCAPTURE)
+/* BTTV specific... */
+COMPATIBLE_IOCTL(_IOW('v',  BASE_VIDIOCPRIVATE+0, char [256]))
+COMPATIBLE_IOCTL(_IOR('v',  BASE_VIDIOCPRIVATE+1, char [256]))
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int))
+COMPATIBLE_IOCTL(_IOW('v' , BASE_VIDIOCPRIVATE+3, char [16])) /* struct bttv_pll_info */
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+4, int))
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+5, int))
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+6, int))
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+7, int))
+/* Little m */
+COMPATIBLE_IOCTL(MTIOCTOP)
+/* Socket level stuff */
+COMPATIBLE_IOCTL(FIOSETOWN)
+COMPATIBLE_IOCTL(SIOCSPGRP)
+COMPATIBLE_IOCTL(FIOGETOWN)
+COMPATIBLE_IOCTL(SIOCGPGRP)
+COMPATIBLE_IOCTL(SIOCATMARK)
+COMPATIBLE_IOCTL(SIOCSIFLINK)
+COMPATIBLE_IOCTL(SIOCSIFENCAP)
+COMPATIBLE_IOCTL(SIOCGIFENCAP)
+COMPATIBLE_IOCTL(SIOCSIFBR)
+COMPATIBLE_IOCTL(SIOCGIFBR)
+COMPATIBLE_IOCTL(SIOCSARP)
+COMPATIBLE_IOCTL(SIOCGARP)
+COMPATIBLE_IOCTL(SIOCDARP)
+COMPATIBLE_IOCTL(SIOCSRARP)
+COMPATIBLE_IOCTL(SIOCGRARP)
+COMPATIBLE_IOCTL(SIOCDRARP)
+COMPATIBLE_IOCTL(SIOCADDDLCI)
+COMPATIBLE_IOCTL(SIOCDELDLCI)
+/* SG stuff */
+COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
+COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
+COMPATIBLE_IOCTL(SG_EMULATED_HOST)
+COMPATIBLE_IOCTL(SG_SET_TRANSFORM)
+COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
+COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
+COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
+COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
+COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
+COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
+COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
+COMPATIBLE_IOCTL(SG_GET_PACK_ID)
+COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
+COMPATIBLE_IOCTL(SG_SET_DEBUG)
+COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
+COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
+COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
+COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
+COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
+COMPATIBLE_IOCTL(SG_SCSI_RESET)
+COMPATIBLE_IOCTL(SG_IO)
+COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
+COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
+COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
+/* PPP stuff */
+COMPATIBLE_IOCTL(PPPIOCGFLAGS)
+COMPATIBLE_IOCTL(PPPIOCSFLAGS)
+COMPATIBLE_IOCTL(PPPIOCGASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCSASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCGUNIT)
+COMPATIBLE_IOCTL(PPPIOCGRASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCSRASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCGMRU)
+COMPATIBLE_IOCTL(PPPIOCSMRU)
+COMPATIBLE_IOCTL(PPPIOCSMAXCID)
+COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCXFERUNIT)
+COMPATIBLE_IOCTL(PPPIOCGNPMODE)
+COMPATIBLE_IOCTL(PPPIOCSNPMODE)
+COMPATIBLE_IOCTL(PPPIOCGDEBUG)
+COMPATIBLE_IOCTL(PPPIOCSDEBUG)
+COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
+COMPATIBLE_IOCTL(PPPIOCATTACH)
+COMPATIBLE_IOCTL(PPPIOCDETACH)
+COMPATIBLE_IOCTL(PPPIOCSMRRU)
+COMPATIBLE_IOCTL(PPPIOCCONNECT)
+COMPATIBLE_IOCTL(PPPIOCDISCONN)
+COMPATIBLE_IOCTL(PPPIOCATTCHAN)
+/* PPPOX */
+COMPATIBLE_IOCTL(PPPOEIOCSFWD);
+COMPATIBLE_IOCTL(PPPOEIOCDFWD);
+/* CDROM stuff */
+COMPATIBLE_IOCTL(CDROMPAUSE)
+COMPATIBLE_IOCTL(CDROMRESUME)
+COMPATIBLE_IOCTL(CDROMPLAYMSF)
+COMPATIBLE_IOCTL(CDROMPLAYTRKIND)
+COMPATIBLE_IOCTL(CDROMREADTOCHDR)
+COMPATIBLE_IOCTL(CDROMREADTOCENTRY)
+COMPATIBLE_IOCTL(CDROMSTOP)
+COMPATIBLE_IOCTL(CDROMSTART)
+COMPATIBLE_IOCTL(CDROMEJECT)
+COMPATIBLE_IOCTL(CDROMVOLCTRL)
+COMPATIBLE_IOCTL(CDROMSUBCHNL)
+COMPATIBLE_IOCTL(CDROMEJECT_SW)
+COMPATIBLE_IOCTL(CDROMMULTISESSION)
+COMPATIBLE_IOCTL(CDROM_GET_MCN)
+COMPATIBLE_IOCTL(CDROMRESET)
+COMPATIBLE_IOCTL(CDROMVOLREAD)
+COMPATIBLE_IOCTL(CDROMSEEK)
+COMPATIBLE_IOCTL(CDROMPLAYBLK)
+COMPATIBLE_IOCTL(CDROMCLOSETRAY)
+COMPATIBLE_IOCTL(CDROM_SET_OPTIONS)
+COMPATIBLE_IOCTL(CDROM_CLEAR_OPTIONS)
+COMPATIBLE_IOCTL(CDROM_SELECT_SPEED)
+COMPATIBLE_IOCTL(CDROM_SELECT_DISC)
+COMPATIBLE_IOCTL(CDROM_MEDIA_CHANGED)
+COMPATIBLE_IOCTL(CDROM_DRIVE_STATUS)
+COMPATIBLE_IOCTL(CDROM_DISC_STATUS)
+COMPATIBLE_IOCTL(CDROM_CHANGER_NSLOTS)
+COMPATIBLE_IOCTL(CDROM_LOCKDOOR)
+COMPATIBLE_IOCTL(CDROM_DEBUG)
+COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY)
+/* Big L */
+COMPATIBLE_IOCTL(LOOP_SET_FD)
+COMPATIBLE_IOCTL(LOOP_CLR_FD)
+/* Big Q for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_INFO)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_CTRLRATE)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETOUTCOUNT)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETINCOUNT)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_PERCMODE)
+COMPATIBLE_IOCTL(SNDCTL_FM_LOAD_INSTR)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_TESTMIDI)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_RESETSAMPLES)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_NRSYNTHS)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_NRMIDIS)
+COMPATIBLE_IOCTL(SNDCTL_MIDI_INFO)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_THRESHOLD)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_MEMAVL)
+COMPATIBLE_IOCTL(SNDCTL_FM_4OP_ENABLE)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_PANIC)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_OUTOFBAND)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETTIME)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_ID)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_CONTROL)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_REMOVESAMPLE)
+/* Big T for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_TMR_TIMEBASE)
+COMPATIBLE_IOCTL(SNDCTL_TMR_START)
+COMPATIBLE_IOCTL(SNDCTL_TMR_STOP)
+COMPATIBLE_IOCTL(SNDCTL_TMR_CONTINUE)
+COMPATIBLE_IOCTL(SNDCTL_TMR_TEMPO)
+COMPATIBLE_IOCTL(SNDCTL_TMR_SOURCE)
+COMPATIBLE_IOCTL(SNDCTL_TMR_METRONOME)
+COMPATIBLE_IOCTL(SNDCTL_TMR_SELECT)
+/* Little m for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_MIDI_PRETIME)
+COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUMODE)
+COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUCMD)
+/* Big P for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_DSP_RESET)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SYNC)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SPEED)
+COMPATIBLE_IOCTL(SNDCTL_DSP_STEREO)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETBLKSIZE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_CHANNELS)
+COMPATIBLE_IOCTL(SOUND_PCM_WRITE_FILTER)
+COMPATIBLE_IOCTL(SNDCTL_DSP_POST)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SUBDIVIDE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETFRAGMENT)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETFMTS)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETFMT)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETOSPACE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETISPACE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_NONBLOCK)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETCAPS)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETTRIGGER)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETTRIGGER)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETIPTR)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETOPTR)
+/* SNDCTL_DSP_MAPINBUF,  XXX needs translation */
+/* SNDCTL_DSP_MAPOUTBUF,  XXX needs translation */
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETSYNCRO)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETDUPLEX)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETODELAY)
+COMPATIBLE_IOCTL(SNDCTL_DSP_PROFILE)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_RATE)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_CHANNELS)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_BITS)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_FILTER)
+/* Big C for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_COPR_RESET)
+COMPATIBLE_IOCTL(SNDCTL_COPR_LOAD)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RDATA)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RCODE)
+COMPATIBLE_IOCTL(SNDCTL_COPR_WDATA)
+COMPATIBLE_IOCTL(SNDCTL_COPR_WCODE)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RUN)
+COMPATIBLE_IOCTL(SNDCTL_COPR_HALT)
+COMPATIBLE_IOCTL(SNDCTL_COPR_SENDMSG)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RCVMSG)
+/* Big M for sound/OSS */
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_VOLUME)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_BASS)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_TREBLE)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_SYNTH)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_PCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_SPEAKER)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_MIC)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_CD)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_IMIX)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_ALTPCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECLEV)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_IGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_OGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE1)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE2)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE3)
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL1))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL2))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL3))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEIN))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEOUT))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_VIDEO))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_RADIO))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_MONITOR))
+COMPATIBLE_IOCTL(SOUND_MIXER_MUTE)
+/* SOUND_MIXER_READ_ENHANCE,  same value as READ_MUTE */
+/* SOUND_MIXER_READ_LOUD,  same value as READ_MUTE */
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECSRC)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_DEVMASK)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECMASK)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_STEREODEVS)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_CAPS)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_VOLUME)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_BASS)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_TREBLE)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SYNTH)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_PCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SPEAKER)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MIC)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_CD)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IMIX)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_ALTPCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECLEV)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_OGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE1)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE2)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE3)
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL1))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL2))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL3))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEIN))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEOUT))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_VIDEO))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_RADIO))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_MONITOR))
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MUTE)
+/* SOUND_MIXER_WRITE_ENHANCE,  same value as WRITE_MUTE */
+/* SOUND_MIXER_WRITE_LOUD,  same value as WRITE_MUTE */
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECSRC)
+COMPATIBLE_IOCTL(SOUND_MIXER_INFO)
+COMPATIBLE_IOCTL(SOUND_OLD_MIXER_INFO)
+COMPATIBLE_IOCTL(SOUND_MIXER_ACCESS)
+COMPATIBLE_IOCTL(SOUND_MIXER_AGC)
+COMPATIBLE_IOCTL(SOUND_MIXER_3DSE)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE1)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE2)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE3)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE4)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE5)
+COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS)
+COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS)
+COMPATIBLE_IOCTL(OSS_GETVERSION)
+/* AUTOFS */
+COMPATIBLE_IOCTL(AUTOFS_IOC_READY)
+COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL)
+COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
+/* DEVFS */
+COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV)
+COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK)
+COMPATIBLE_IOCTL(DEVFSDIOC_RELEASE_EVENT_QUEUE)
+COMPATIBLE_IOCTL(DEVFSDIOC_SET_DEBUG_MASK)
+/* Raw devices */
+COMPATIBLE_IOCTL(RAW_SETBIND)
+COMPATIBLE_IOCTL(RAW_GETBIND)
+/* SMB ioctls which do not need any translations */
+COMPATIBLE_IOCTL(SMB_IOC_NEWCONN)
+/* Little a */
+COMPATIBLE_IOCTL(ATMSIGD_CTRL)
+COMPATIBLE_IOCTL(ATMARPD_CTRL)
+COMPATIBLE_IOCTL(ATMLEC_CTRL)
+COMPATIBLE_IOCTL(ATMLEC_MCAST)
+COMPATIBLE_IOCTL(ATMLEC_DATA)
+COMPATIBLE_IOCTL(ATM_SETSC)
+COMPATIBLE_IOCTL(SIOCSIFATMTCP)
+COMPATIBLE_IOCTL(SIOCMKCLIP)
+COMPATIBLE_IOCTL(ATMARP_MKIP)
+COMPATIBLE_IOCTL(ATMARP_SETENTRY)
+COMPATIBLE_IOCTL(ATMARP_ENCAP)
+COMPATIBLE_IOCTL(ATMTCP_CREATE)
+COMPATIBLE_IOCTL(ATMTCP_REMOVE)
+COMPATIBLE_IOCTL(ATMMPC_CTRL)
+COMPATIBLE_IOCTL(ATMMPC_DATA)
+#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
+/* 0xfe - lvm */
+COMPATIBLE_IOCTL(VG_SET_EXTENDABLE)
+COMPATIBLE_IOCTL(VG_STATUS_GET_COUNT)
+COMPATIBLE_IOCTL(VG_STATUS_GET_NAMELIST)
+COMPATIBLE_IOCTL(VG_REMOVE)
+COMPATIBLE_IOCTL(VG_RENAME)
+COMPATIBLE_IOCTL(VG_REDUCE)
+COMPATIBLE_IOCTL(PE_LOCK_UNLOCK)
+COMPATIBLE_IOCTL(PV_FLUSH)
+COMPATIBLE_IOCTL(LVM_LOCK_LVM)
+COMPATIBLE_IOCTL(LVM_GET_IOP_VERSION)
+#ifdef LVM_TOTAL_RESET
+COMPATIBLE_IOCTL(LVM_RESET)
+#endif
+COMPATIBLE_IOCTL(LV_SET_ACCESS)
+COMPATIBLE_IOCTL(LV_SET_STATUS)
+COMPATIBLE_IOCTL(LV_SET_ALLOCATION)
+COMPATIBLE_IOCTL(LE_REMAP)
+COMPATIBLE_IOCTL(LV_BMAP)
+COMPATIBLE_IOCTL(LV_SNAPSHOT_USE_RATE)
+#endif /* LVM */
+#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC)
+COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID)
+COMPATIBLE_IOCTL(DRM_IOCTL_AUTH_MAGIC)
+COMPATIBLE_IOCTL(DRM_IOCTL_BLOCK)
+COMPATIBLE_IOCTL(DRM_IOCTL_UNBLOCK)
+COMPATIBLE_IOCTL(DRM_IOCTL_CONTROL)
+COMPATIBLE_IOCTL(DRM_IOCTL_ADD_BUFS)
+COMPATIBLE_IOCTL(DRM_IOCTL_MARK_BUFS)
+COMPATIBLE_IOCTL(DRM_IOCTL_ADD_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_RM_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_MOD_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_GET_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_SWITCH_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_NEW_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_ADD_DRAW)
+COMPATIBLE_IOCTL(DRM_IOCTL_RM_DRAW)
+COMPATIBLE_IOCTL(DRM_IOCTL_LOCK)
+COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK)
+COMPATIBLE_IOCTL(DRM_IOCTL_FINISH)
+#endif /* DRM */
+/* elevator */
+COMPATIBLE_IOCTL(BLKELVGET)
+COMPATIBLE_IOCTL(BLKELVSET)
+/* And these ioctls need translation */
+HANDLE_IOCTL(TIOCGSERIAL, do_tiocgserial)
+HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32)
+HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf)
+HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFMETRIC, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFMETRIC, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFMTU, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFMTU, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFMEM, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFMEM, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFHWADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFHWADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCADDMULTI, dev_ifsioc)
+HANDLE_IOCTL(SIOCDELMULTI, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFINDEX, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFMAP, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFBRDADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFBRDADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFDSTADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFDSTADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFNETMASK, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGPPPSTATS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGPPPCSTATS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGPPPVER, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc)
+HANDLE_IOCTL(SIOCADDRT, routing_ioctl)
+HANDLE_IOCTL(SIOCDELRT, routing_ioctl)
+/* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
+HANDLE_IOCTL(SIOCRTMSG, ret_einval)
+HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp)
+HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo)
+HANDLE_IOCTL(BLKRAGET, w_long)
+HANDLE_IOCTL(BLKGETSIZE, w_long)
+HANDLE_IOCTL(0x1260, broken_blkgetsize)
+HANDLE_IOCTL(BLKFRAGET, w_long)
+HANDLE_IOCTL(BLKSECTGET, w_long)
+HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans)
+
+HANDLE_IOCTL(FBIOGET_FSCREENINFO, fb_ioctl_trans)
+HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans)
+HANDLE_IOCTL(FBIOPUTCMAP, fb_ioctl_trans)
+
+HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_MULTCOUNT, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_NOWERR, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_NICE, hdio_ioctl_trans)
+HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans)
+HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans)
+HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans)
+HANDLE_IOCTL(FDSETDRVPRM32, fd_ioctl_trans)
+HANDLE_IOCTL(FDGETDRVPRM32, fd_ioctl_trans)
+HANDLE_IOCTL(FDGETDRVSTAT32, fd_ioctl_trans)
+HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans)
+HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans)
+HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans)
+HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans)
+HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans)
+HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans)
+HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans)
+HANDLE_IOCTL(MTIOCGETCONFIG32, mt_ioctl_trans)
+HANDLE_IOCTL(MTIOCSETCONFIG32, mt_ioctl_trans)
+HANDLE_IOCTL(CDROMREADMODE2, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADMODE1, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADRAW, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADCOOKED, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADALL, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans)
+HANDLE_IOCTL(LOOP_SET_STATUS, loop_status)
+HANDLE_IOCTL(LOOP_GET_STATUS, loop_status)
+#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
+HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout)
+#ifdef CONFIG_VT
+HANDLE_IOCTL(PIO_FONTX, do_fontx_ioctl)
+HANDLE_IOCTL(GIO_FONTX, do_fontx_ioctl)
+HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl)
+HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl)
+HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl)
+#endif
+HANDLE_IOCTL(EXT2_IOC32_GETFLAGS, do_ext2_ioctl)
+HANDLE_IOCTL(EXT2_IOC32_SETFLAGS, do_ext2_ioctl)
+HANDLE_IOCTL(EXT2_IOC32_GETVERSION, do_ext2_ioctl)
+HANDLE_IOCTL(EXT2_IOC32_SETVERSION, do_ext2_ioctl)
+#if 0
+/* One SMB ioctl needs translations. */
+#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, __kernel_uid_t32)
+HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid)
+#endif
+HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETESI32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETADDR32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_RSTADDR32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_ADDADDR32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_DELADDR32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETCIRANGE32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_SETCIRANGE32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_QUERYLOOP32, do_atm_ioctl)
+HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl)
+HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl)
+HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl)
+HANDLE_IOCTL(SONET_SETDIAG, do_atm_ioctl)
+HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl)
+HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl)
+HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl)
+HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl)
+#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
+HANDLE_IOCTL(VG_STATUS, do_lvm_ioctl)
+HANDLE_IOCTL(VG_CREATE_OLD, do_lvm_ioctl)
+HANDLE_IOCTL(VG_CREATE, do_lvm_ioctl)
+HANDLE_IOCTL(VG_EXTEND, do_lvm_ioctl)
+HANDLE_IOCTL(LV_CREATE, do_lvm_ioctl)
+HANDLE_IOCTL(LV_REMOVE, do_lvm_ioctl)
+HANDLE_IOCTL(LV_EXTEND, do_lvm_ioctl)
+HANDLE_IOCTL(LV_REDUCE, do_lvm_ioctl)
+HANDLE_IOCTL(LV_RENAME, do_lvm_ioctl)
+HANDLE_IOCTL(LV_STATUS_BYNAME, do_lvm_ioctl)
+HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl)
+HANDLE_IOCTL(LV_STATUS_BYDEV, do_lvm_ioctl)
+HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl)
+HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl)
+#endif /* LVM */
+#if defined(CONFIG_GENRTC)
+COMPATIBLE_IOCTL(RTC_AIE_ON)
+COMPATIBLE_IOCTL(RTC_AIE_OFF)
+COMPATIBLE_IOCTL(RTC_UIE_ON)
+COMPATIBLE_IOCTL(RTC_UIE_OFF)
+COMPATIBLE_IOCTL(RTC_PIE_ON)
+COMPATIBLE_IOCTL(RTC_PIE_OFF)
+COMPATIBLE_IOCTL(RTC_WIE_ON)
+COMPATIBLE_IOCTL(RTC_WIE_OFF)
+COMPATIBLE_IOCTL(RTC_ALM_SET)   /* struct rtc_time only has ints */
+COMPATIBLE_IOCTL(RTC_ALM_READ)  /* struct rtc_time only has ints */
+COMPATIBLE_IOCTL(RTC_RD_TIME)   /* struct rtc_time only has ints */
+COMPATIBLE_IOCTL(RTC_SET_TIME)  /* struct rtc_time only has ints */
+HANDLE_IOCTL(RTC_IRQP_READ, w_long)
+COMPATIBLE_IOCTL(RTC_IRQP_SET)
+HANDLE_IOCTL(RTC_EPOCH_READ, w_long)
+COMPATIBLE_IOCTL(RTC_EPOCH_SET)
+#endif
+#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version);
+HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique);
+HANDLE_IOCTL(DRM32_IOCTL_SET_UNIQUE, drm32_getsetunique);
+HANDLE_IOCTL(DRM32_IOCTL_ADD_MAP, drm32_addmap);
+HANDLE_IOCTL(DRM32_IOCTL_INFO_BUFS, drm32_info_bufs);
+HANDLE_IOCTL(DRM32_IOCTL_FREE_BUFS, drm32_free_bufs);
+HANDLE_IOCTL(DRM32_IOCTL_MAP_BUFS, drm32_map_bufs);
+HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma);
+HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx);
+#endif /* DRM */
+COMPATIBLE_IOCTL(PA_PERF_ON)
+COMPATIBLE_IOCTL(PA_PERF_OFF)
+COMPATIBLE_IOCTL(PA_PERF_VERSION)
+IOCTL_TABLE_END
+
+unsigned int ioctl32_hash_table[1024];
+
+extern inline unsigned long ioctl32_hash(unsigned long cmd)
+{
+	return ((cmd >> 6) ^ (cmd >> 4) ^ cmd) & 0x3ff;
+}
+
+static void ioctl32_insert_translation(struct ioctl_trans *trans)
+{
+	unsigned long hash;
+	struct ioctl_trans *t;
+
+	hash = ioctl32_hash (trans->cmd);
+	if (!ioctl32_hash_table[hash])
+		ioctl32_hash_table[hash] = (u32)(long)trans;
+	else {
+		t = (struct ioctl_trans *)(long)ioctl32_hash_table[hash];
+		while (t->next)
+			t = (struct ioctl_trans *)(long)t->next;
+		trans->next = 0;
+		t->next = (u32)(long)trans;
+	}
+}
+
+static int __init init_sys32_ioctl(void)
+{
+	int i;
+	extern struct ioctl_trans ioctl_translations[], ioctl_translations_end[];
+
+	for (i = 0; &ioctl_translations[i] < &ioctl_translations_end[0]; i++)
+		ioctl32_insert_translation(&ioctl_translations[i]);
+	return 0;
+}
+
+__initcall(init_sys32_ioctl);
+
+static struct ioctl_trans *additional_ioctls;
+
+/* Always call these with kernel lock held! */
+
+int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *))
+{
+	int i;
+
+panic("register_ioctl32_conversion() is B0RKEN! Called by %p\n", __builtin_return_address(0));
+
+	if (!additional_ioctls) {
+		additional_ioctls = module_map(PAGE_SIZE);
+		if (!additional_ioctls)
+			return -ENOMEM;
+		memset(additional_ioctls, 0, PAGE_SIZE);
+	}
+	for (i = 0; i < PAGE_SIZE/sizeof(struct ioctl_trans); i++)
+		if (!additional_ioctls[i].cmd)
+			break;
+	if (i == PAGE_SIZE/sizeof(struct ioctl_trans))
+		return -ENOMEM;
+	additional_ioctls[i].cmd = cmd;
+	if (!handler)
+		additional_ioctls[i].handler = (u32)(long)sys_ioctl;
+	else
+		additional_ioctls[i].handler = (u32)(long)handler;
+	ioctl32_insert_translation(&additional_ioctls[i]);
+	return 0;
+}
+
+int unregister_ioctl32_conversion(unsigned int cmd)
+{
+	unsigned long hash = ioctl32_hash(cmd);
+	struct ioctl_trans *t, *t1;
+
+	t = (struct ioctl_trans *)(long)ioctl32_hash_table[hash];
+	if (!t) return -EINVAL;
+	if (t->cmd == cmd && t >= additional_ioctls &&
+	    (unsigned long)t < ((unsigned long)additional_ioctls) + PAGE_SIZE) {
+		ioctl32_hash_table[hash] = t->next;
+		t->cmd = 0;
+		return 0;
+	} else while (t->next) {
+		t1 = (struct ioctl_trans *)(long)t->next;
+		if (t1->cmd == cmd && t1 >= additional_ioctls &&
+		    (unsigned long)t1 < ((unsigned long)additional_ioctls) + PAGE_SIZE) {
+			t1->cmd = 0;
+			t->next = t1->next;
+			return 0;
+		}
+		t = t1;
+	}
+	return -EINVAL;
+}
+
+asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct file * filp;
+	int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
+	unsigned long pafnptr[4];
+	extern char __gp;
+	struct ioctl_trans *t;
+	int error = -EBADF;
+
+	filp = fget(fd);
+	if(!filp)
+		goto out2;
+
+	if (!filp->f_op || !filp->f_op->ioctl) {
+		error = sys_ioctl (fd, cmd, arg);
+		goto out;
+	}
+
+	/* intercept private networking ioctl() calls here since it is
+	 * an onerous task to figure out which ones of the HANDLE_IOCTL
+	 * list map to these values.
+	 */
+	if (cmd >= SIOCDEVPRIVATE && cmd <= SIOCDEVPRIVATE + 0xf) {
+		error = siocprivate(fd, cmd, arg);
+		goto out;
+	}
+
+	t = (struct ioctl_trans *)(long)ioctl32_hash_table [ioctl32_hash (cmd)];
+
+	while (t && t->cmd != cmd)
+		t = (struct ioctl_trans *)(long)t->next;
+	if (t) {
+		handler = (void *) pafnptr;
+		pafnptr[0] = pafnptr[1] = 0UL;
+		pafnptr[2] = (unsigned long) t->handler;
+		pafnptr[3] = A(&__gp);
+		error = handler(fd, cmd, arg, filp);
+	} else {
+		static int count = 0;
+		if (++count <= 20)
+			printk(KERN_WARNING
+				"sys32_ioctl: Unknown cmd fd(%d) "
+				"cmd(%08x) arg(%08x)\n",
+				(int)fd, (unsigned int)cmd, (unsigned int)arg);
+		error = -EINVAL;
+	}
+out:
+	fput(filp);
+out2:
+	return error;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/iosapic.c linux-2.4.20/arch/parisc/kernel/iosapic.c
--- linux-2.4.19/arch/parisc/kernel/iosapic.c	2001-02-09 19:29:44.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/iosapic.c	2002-10-29 11:18:34.000000000 +0000
@@ -169,11 +169,13 @@
 
 #include <asm/byteorder.h>	/* get in-line asm for swab */
 #include <asm/pdc.h>
-#include <asm/pdcpat.h>
 #include <asm/page.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/gsc.h>		/* gsc_read/write functions */
+#ifdef CONFIG_SUPERIO
+#include <asm/superio.h>
+#endif
 
 #include <asm/iosapic.h>
 #include "./iosapic_private.h"
@@ -181,7 +183,6 @@
 #define MODULE_NAME "iosapic"
 
 /* "local" compile flags */
-#undef IOSAPIC_CALLBACK
 #undef PCI_BRIDGE_FUNCS
 #undef DEBUG_IOSAPIC
 #undef DEBUG_IOSAPIC_IRT
@@ -282,28 +283,6 @@
 
 #define	IOSAPIC_EOI(eoi_addr, eoi_data) gsc_writel(eoi_data, eoi_addr)
 
-#if IOSAPIC_CALLBACK
-/*
-** Shouldn't use callback since SAPIC doesn't have an officially assigned
-** H or S version numbers. Slight long term risk the number chosen would
-** collide with something else.
-** But benefit is cleaner lba/sapic interface.
-** Might be worth it but for just use direct calls for now.
-**
-** Entry below is copied from lba driver.
-** Only thing different is hw_type.
-*/
-static struct pa_iodc_driver iosapic_driver_for[] = {
-	{HPHW_OTHER, 0x782, 0, 0x0000A, 0, 0x00,
-	DRIVER_CHECK_HWTYPE + DRIVER_CHECK_HVERSION + DRIVER_CHECK_SVERSION,
-	"I/O Sapic", "",(void *) iosapic_callback},     
-	{0,0,0,0,0,0,
-	0,
-	(char *) NULL,(char *) NULL,(void *) NULL}                     
-};
-#endif /* IOSAPIO_CALLBACK */
-
-
 static struct iosapic_info *iosapic_list;
 static spinlock_t iosapic_lock;
 static int iosapic_count;
@@ -350,25 +329,22 @@
 static int __init /* return number of entries as success/fail flag */
 iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt)
 {
-	struct pdc_pat_io_num pdc_io_num; /* PAT PDC return block */
 	long status;              /* PDC return value status */
-	struct irt_entry *table = NULL;  /* start of interrupt routing tbl */
+	struct irt_entry *table;  /* start of interrupt routing tbl */
 	unsigned long num_entries = 0UL;
 
 	ASSERT(NULL != irt);
-	/* FIXME ASSERT(((&pdc_io_num) & (0x3f)) == 0);  enforce 32-byte alignment */
 
-	/* Try PAT_PDC to get interrupt routing table size */
-	DBG(KERN_DEBUG "calling get_irt_size\n");
-	status = pdc_pat_get_irt_size( &pdc_io_num, cell_num);
-	DBG(KERN_DEBUG "get_irt_size: %ld\n", status);
+	if (is_pdc_pat()) {
 
-	switch(status) {
+		/* Use pat pdc routine to get interrupt routing table size */
+		DBG("calling get_irt_size (cell %ld)\n", cell_num);
+		status = pdc_pat_get_irt_size(&num_entries, cell_num);
+		DBG("get_irt_size: %ld\n", status);
 
-	case PDC_RET_OK:	/* PAT box. Proceed to get the IRT */
+		ASSERT(status == PDC_OK);
 
 		/* save the number of entries in the table */
-		num_entries = pdc_io_num.num;
 		ASSERT(0UL != num_entries);
 
 		/*
@@ -384,30 +360,27 @@
 		}
 
 		/* get PCI INT routing table */
-		status = pdc_pat_get_irt( (void *) table, cell_num);
-		DBG(KERN_DEBUG "pdc_pat_get_irt: %ld\n", status);
-		ASSERT(status == PDC_RET_OK);
-		break;
-
-	case PDC_RET_NE_PROC: /* Not a PAT platform. Try PDC_PCI extensions */
+		status = pdc_pat_get_irt(table, cell_num);
+		DBG("pdc_pat_get_irt: %ld\n", status);
+		ASSERT(status == PDC_OK);
+	} else {
 		/*
-		** C3000/J5000 (and similar) platforms with "legacy" PDC
-		** will return exactly one IRT.
+		** C3000/J5000 (and similar) platforms with Sprockets PDC
+		** will return exactly one IRT for all iosapics.
 		** So if we have one, don't need to get it again.
 		*/
 		if (NULL != irt_cell)
-			break;
+			return 0;
 
-		status = pdc_pci_irt_size( (void *)&pdc_io_num,
-				/* elroy HPA (really a NOP) */ 0);
-		DBG(KERN_WARNING "pdc_pci_irt_size: %ld\n", status);
+		/* Should be using the Elroy's HPA, but it's ignored anyway */
+		status = pdc_pci_irt_size(&num_entries, 0);
+		DBG("pdc_pci_irt_size: %ld\n", status);
 
-		if (PDC_RET_OK != status) {
+		if (PDC_OK != status) {
 			/* Not a "legacy" system with I/O SAPIC either */
 			return 0;
 		}
 
-		num_entries = pdc_io_num.num;
 		ASSERT(0UL != num_entries);
 
 		table = IOSAPIC_KALLOC(struct irt_entry, num_entries);
@@ -416,36 +389,27 @@
 			return 0;
 		}
 
-		status = pdc_pci_irt( (void *) &pdc_io_num,
-				(void *) NULL, /* Elroy HPA - not used */
-				(void *) table);
-
-		ASSERT(PDC_RET_OK == status);
-		break;
-
-	default:
-		printk(KERN_WARNING MODULE_NAME ": PDC_PAT_IO call failed with %ld\n", status);
-		break;
+		/* HPA ignored by this call too. */
+		status = pdc_pci_irt(num_entries, 0, table);
+		ASSERT(PDC_OK == status);
 	}
 
 	/* return interrupt table address */
 	*irt = table;
 
-
 #ifdef DEBUG_IOSAPIC_IRT
-	{
+{
 	struct irt_entry *p = table;
 	int i;
 
-	printk(MODULE_NAME " Interrupt Routing Table (cell %ld)\n", cell_num);
-	printk(MODULE_NAME " start = 0x%p num_entries %ld entry_size %d\n",
+	printk(KERN_DEBUG MODULE_NAME " Interrupt Routing Table (cell %ld)\n", cell_num);
+	printk(KERN_DEBUG MODULE_NAME " start = 0x%p num_entries %ld entry_size %d\n",
 		table,
 		num_entries,
 		(int) sizeof(struct irt_entry));
 
-	for (i = 0 ; i < num_entries ; i++, p++)
-	{
-		printk(MODULE_NAME " %02x %02x %02x %02x %02x %02x %02x %02x %08x%08x\n",
+	for (i = 0 ; i < num_entries ; i++, p++) {
+		printk(KERN_DEBUG MODULE_NAME " %02x %02x %02x %02x %02x %02x %02x %02x %08x%08x\n",
 		p->entry_type, p->entry_length, p->interrupt_type,
 		p->polarity_trigger, p->src_bus_irq_devno, p->src_bus_id,
 		p->src_seg_id, p->dest_iosapic_intin,
@@ -453,7 +417,7 @@
 		((u32 *) p)[3]
 		);
 	}
-	}
+}
 #endif /* DEBUG_IOSAPIC_IRT */
 
 	return num_entries;
@@ -464,6 +428,8 @@
 void __init
 iosapic_init(void)
 {
+	unsigned long cell = 0;
+
 	/* init global data */
 	iosapic_lock = SPIN_LOCK_UNLOCKED;
         iosapic_list = (struct iosapic_info *) NULL;
@@ -471,22 +437,24 @@
 
 	DBG("iosapic_init()\n");
 
+#ifdef __LP64__
+	if (is_pdc_pat()) {
+		int status;
+		struct pdc_pat_cell_num cell_info;
+
+		status = pdc_pat_cell_get_number(&cell_info);
+		if (status == PDC_OK) {
+			cell = cell_info.cell_num;
+		}
+	}
+#endif
+
 	/*
 	**  get IRT for this cell.
 	*/
-	irt_num_entry =  iosapic_load_irt(0L, &irt_cell);
+	irt_num_entry =  iosapic_load_irt(cell, &irt_cell);
 	if (0 == irt_num_entry)
 		irt_cell = NULL;	/* old PDC w/o iosapic */
-
-#ifdef IOSAPIC_CALLBACK
-	/*
-	** When new I/O SAPICs are discovered, this callback
-	** will get invoked. Implies lba driver will register
-	** I/O Sapic as a device it "discovered" with faked
-	** IODC data.
-	*/
-	register_driver(iosapic_driver_for);
-#endif /* IOSAPIC_CALLBACK */
 }
 
 
@@ -546,7 +514,7 @@
 		return i;
 	}
 
-	printk(KERN_WARNING MODULE_NAME ": 0x%p : no IRT entry for slot %d, pin %d\n",
+	printk(KERN_WARNING MODULE_NAME ": 0x%lx : no IRT entry for slot %d, pin %d\n",
 			isi->isi_hpa, slot, intr_pin);
 	return NULL;
 }
@@ -571,21 +539,18 @@
 {
 	u8 intr_pin, intr_slot;
 
-	(void) pci_read_config_byte(pcidev, PCI_INTERRUPT_PIN, &intr_pin);
+	pci_read_config_byte(pcidev, PCI_INTERRUPT_PIN, &intr_pin);
 
-	DBG_IRT("iosapic_xlate_pin() SLOT %d pin %d\n", PCI_SLOT(pcidev->devfn), intr_pin);
+	DBG_IRT("iosapic_xlate_pin() SLOT %d pin %d\n",
+		PCI_SLOT(pcidev->devfn), intr_pin);
 
-	if (0 == intr_pin)
-	{
-		/*
-		** The device does NOT support/use IRQ lines.
-		*/
+	if (0 == intr_pin) {
+		/* The device does NOT support/use IRQ lines.  */
 		return NULL;
 	}
 
 	/* Check if pcidev behind a PPB */
-	if (NULL != pcidev->bus->self)
-	{
+	if (NULL != pcidev->bus->self) {
 		/* Convert pcidev INTR_PIN into something we
 		** can lookup in the IRT.
 		*/
@@ -600,7 +565,7 @@
 		** or by some ambitous soul who wants to watch TV.
 		*/
 		if (pci_bridge_funcs->xlate_intr_line) {
-			intr_pin = (*pci_bridge_funcs->xlate_intr_line)(pcidev);
+			intr_pin = pci_bridge_funcs->xlate_intr_line(pcidev);
 		}
 #else	/* PCI_BRIDGE_FUNCS */
 		struct pci_bus *p = pcidev->bus;
@@ -646,8 +611,8 @@
 	extern void do_irq(struct irqaction *a, int i, struct pt_regs *p);
 	int irq_num = vi->vi_ios->isi_region->data.irqbase + vi->vi_irqline;
 
-	DBG("iosapic_interrupt(): irq %d line %d eoi %p\n", irq, vi->vi_irqline,
-				vi->vi_eoi_addr);
+	DBG("iosapic_interrupt(): irq %d line %d eoi %p\n",
+		irq, vi->vi_irqline, vi->vi_eoi_addr);
 
 /* FIXME: Need to mask/unmask? processor IRQ is already masked... */
 	do_irq(&vi->vi_ios->isi_region->action[vi->vi_irqline], irq_num, regs);
@@ -668,12 +633,39 @@
 	struct vector_info *vi;
 	int isi_line;	/* line used by device */
 	int tmp;
+	int return_irq;
+#ifdef CONFIG_SUPERIO
+	int superio_irq = -1;
+#endif
 
 	if (NULL == isi) {
-		printk(KERN_WARNING MODULE_NAME ": 0x%p hpa not registered\n", isi->isi_hpa);
+		printk(KERN_WARNING MODULE_NAME ": hpa not registered for %s\n",
+			pcidev->name);
 		return(-1);
 	}
 
+#ifdef CONFIG_SUPERIO
+	if (is_superio_device(pcidev)) {
+		superio_irq = superio_fixup_irq(pcidev);
+		if (superio_irq == -1)
+		    return(-1);
+
+		if (PCI_FUNC(pcidev->devfn) != SUPERIO_USB_FN) {
+
+			/*
+			 * SuperIO USB controller has an irt entry.
+			 * Only let the USB controller hookup the rest
+			 * of the interrupt routing when it comes through.
+			 * Note that interrupts for all three functions
+			 * actually come through the PIC's on function 1!
+			 */
+
+			pcidev->irq = superio_irq;
+			return superio_irq;
+		}
+	}
+#endif /* CONFIG_SUPERIO */
+
 	/* lookup IRT entry for isi/slot/pin set */
 	irte = iosapic_xlate_pin(isi, pcidev);
 	if (NULL == irte) {
@@ -714,22 +706,31 @@
 	vi->vi_txn_data = txn_alloc_data(vi->vi_txn_irq, 8);
         ASSERT(vi->vi_txn_data < 256);  /* matches 8 above */
 
-	tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0, "iosapic", vi);
+	tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0,
+						vi->vi_name, vi);
 	ASSERT(tmp == 0);
 
-	vi->vi_eoi_addr = ((void *) isi->isi_hpa) + IOSAPIC_REG_EOI;
+	vi->vi_eoi_addr = (u32 *) (isi->isi_hpa + IOSAPIC_REG_EOI);
 	vi->vi_eoi_data = cpu_to_le32(vi->vi_irqline);
 
 	ASSERT(NULL != isi->isi_region);
-	/*
-	** pcidev->irq still needs to be virtualized.
-	*/
-	pcidev->irq = isi->isi_region->data.irqbase + isi_line;
+	/* pcidev->irq still needs to be virtualized.  */
+
+	return_irq = isi->isi_region->data.irqbase + isi_line;
 
-	DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n", PCI_SLOT(pcidev->devfn),
-	PCI_FUNC(pcidev->devfn), pcidev->vendor, pcidev->device, isi_line, pcidev->irq);
+#ifdef CONFIG_SUPERIO
+	if (superio_irq != -1) {
+		superio_inform_irq(return_irq);
+		return_irq = superio_irq;
+	}
+#endif
+	pcidev->irq = return_irq;
+
+	DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n",
+		PCI_SLOT(pcidev->devfn),
+	PCI_FUNC(pcidev->devfn), pcidev->vendor, pcidev->device, isi_line, return_irq);
 
-	return(pcidev->irq);
+	return return_irq;
 }
 
 
@@ -755,7 +756,7 @@
 	struct iosapic_info *isp = vi->vi_ios;
 
 	ASSERT(NULL != isp);
-	ASSERT(NULL != isp->isi_hpa);
+	ASSERT(0 != isp->isi_hpa);
 	DBG_IRT("iosapic_wr_irt_entry(): irq %d hpa %p WINDOW %p  0x%x 0x%x\n",
 		vi->vi_irqline,
 		isp->isi_hpa, isp->isi_hpa+IOSAPIC_REG_WINDOW,
@@ -807,16 +808,13 @@
 	** Extracting id_eid isn't a real clean way of getting it.
 	** But the encoding is the same for both PA and IA64 platforms.
 	*/
-#ifdef __LP64__
-	if (pdc_pat) {
+	if (is_pdc_pat()) {
 		/*
 		** PAT PDC just hands it to us "right".
 		** vi_txn_addr comes from cpu_data[x].txn_addr.
 		*/
 		*dp1 = (u32) (vi->vi_txn_addr);
-	} else
-#endif
-	{
+	} else {
 		/* 
 		** eg if base_addr == 0xfffa0000),
 		**    we want to get 0xa0ff0000.
@@ -886,7 +884,6 @@
 
 	/* data is initialized by fixup_irq */
 	ASSERT(0 < vi->vi_txn_irq);
-	ASSERT(0UL != vi->vi_txn_addr);
 	ASSERT(0UL != vi->vi_txn_data);
 
 	iosapic_set_irt_data(vi, &d0, &d1);
@@ -895,10 +892,10 @@
 
 #ifdef DEBUG_IOSAPIC_IRT
 {
-u32 *t = (u32 *) ((ulong) vi->vi_eoi_addr & ~0xffUL);
-printk("iosapic_enable_irq(): regs %p", vi->vi_eoi_addr);
-while (t < vi->vi_eoi_addr) printk(" %x", READ_U32(t++));
-printk("\n");
+	u32 *t = (u32 *) ((ulong) vi->vi_eoi_addr & ~0xffUL);
+	printk("iosapic_enable_irq(): regs %p", vi->vi_eoi_addr);
+	while (t < vi->vi_eoi_addr) printk(" %x", READ_U32(t++));
+	printk("\n");
 }
 
 printk("iosapic_enable_irq(): sel ");
@@ -943,10 +940,10 @@
 
 
 static struct irq_region_ops iosapic_irq_ops = {
-	iosapic_disable_irq,
-	iosapic_enable_irq,
-	iosapic_mask_irq,
-	iosapic_unmask_irq
+	disable_irq:	iosapic_disable_irq,
+	enable_irq:	iosapic_enable_irq,
+	mask_irq:	iosapic_mask_irq,
+	unmask_irq:	iosapic_unmask_irq
 };
 
 
@@ -967,15 +964,9 @@
 }
 
 
-#ifndef IOSAPIC_CALLBACK
-/*
-** iosapic_register() is the alternative to iosapic_driver_for().
-** (Only one or the other should be implemented.)
-*/
-
 /*
 ** iosapic_register() is called by "drivers" with an integrated I/O SAPIC.
-** Caller must be certain they have an I/O SAPIC and know it's MMIO address.
+** Caller must be certain they have an I/O SAPIC and know its MMIO address.
 **
 **	o allocate iosapic_info and add it to the list
 **	o read iosapic version and squirrel that away
@@ -984,7 +975,7 @@
 **	o allocate isi_region (registers region handlers)
 */
 void *
-iosapic_register(void *hpa)
+iosapic_register(unsigned long hpa)
 {
 	struct iosapic_info *isi = NULL;
 	struct irt_entry *irte = irt_cell;
@@ -1021,7 +1012,7 @@
 
 	memset(isi, 0, sizeof(struct iosapic_info));
 
-	isi->isi_hpa         = (unsigned char *) hpa;
+	isi->isi_hpa         = hpa;
 	isi->isi_version     = iosapic_rd_version(isi);
 	isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1;
 
@@ -1034,6 +1025,7 @@
 	}
 
 	memset(vip, 0, sizeof(struct vector_info) * isi->isi_num_vectors);
+	sprintf(isi->isi_name, "IO-SAPIC%02d", iosapic_count++);
 
 	/*
 	** Initialize vector array
@@ -1041,17 +1033,16 @@
 	for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) {
 		vip->vi_irqline = (unsigned char) cnt;
 		vip->vi_ios = isi;
+		sprintf(vip->vi_name, "%s-L%d", isi->isi_name, cnt);
 	}
 
 	isi->isi_region = alloc_irq_region(isi->isi_num_vectors,
-				&iosapic_irq_ops, IRQ_REG_DIS|IRQ_REG_MASK,
-				"I/O Sapic", (void *) isi->isi_vector);
+				&iosapic_irq_ops, isi->isi_name,
+				(void *) isi->isi_vector);
 
 	ASSERT(NULL != isi->isi_region);
 	return ((void *) isi);
 }
-#endif /* !IOSAPIC_CALLBACK */
-
 
 
 #ifdef DEBUG_IOSAPIC
@@ -1092,8 +1083,8 @@
 {
 	ASSERT(NULL != isi);
 	printk(KERN_DEBUG MODULE_NAME ": io_sapic_info at %p\n", isi);
-	printk(KERN_DEBUG "\t\tisi_hpa: %p\n", isi->isi_hpa);
-	printk(KERN_DEBUG "\t\tisi_satus:     %x\n", isi->isi_status);
+	printk(KERN_DEBUG "\t\tisi_hpa:       %lx\n", isi->isi_hpa);
+	printk(KERN_DEBUG "\t\tisi_status:     %x\n", isi->isi_status);
 	printk(KERN_DEBUG "\t\tisi_version:   %x\n", isi->isi_version);
 	printk(KERN_DEBUG "\t\tisi_vector:    %p\n", isi->isi_vector);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/iosapic_private.h linux-2.4.20/arch/parisc/kernel/iosapic_private.h
--- linux-2.4.19/arch/parisc/kernel/iosapic_private.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/iosapic_private.h	2002-10-29 11:18:36.000000000 +0000
@@ -111,22 +111,25 @@
 	struct irt_entry *vi_irte;      /* IRT entry */
 	u32	*vi_eoi_addr;	/* precalculate EOI reg address */
 	u32	vi_eoi_data;	/* IA64: ?       PA: swapped txn_data */
-	u8	vi_status;	/* status/flags */
-	u8	vi_irqline;	/* INTINn(IRQ) */
 	int	vi_txn_irq;	/* virtual IRQ number for processor */
 	ulong	vi_txn_addr;    /* IA64: id_eid  PA: partial HPA */
 	ulong	vi_txn_data;    /* IA64: vector  PA: EIR bit */
+	u8	vi_status;	/* status/flags */
+	u8	vi_irqline;	/* INTINn(IRQ) */
+	char	vi_name[32];    /* user visible identity */
 };
 
 
 struct iosapic_info {
 	struct iosapic_info  *isi_next;      /* list of I/O SAPIC          */
-	volatile void        *isi_hpa;       /* physical base address      */
+	unsigned long	     isi_hpa;	     /* physical base address */
 	struct irq_region    *isi_region;    /* each I/O SAPIC is one region */
 	struct vector_info   *isi_vector;    /* IRdT (IRQ line) array  */
 	int                  isi_num_vectors; /* size of IRdT array */
 	int                  isi_status;     /* status/flags               */
 	unsigned int         isi_version;    /* DEBUG: data fr version reg */
+	/* round up to next cacheline */
+	char                 isi_name[20]; /* identify region for users */
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/irq.c linux-2.4.20/arch/parisc/kernel/irq.c
--- linux-2.4.19/arch/parisc/kernel/irq.c	2001-02-09 19:29:44.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/irq.c	2002-10-29 11:18:38.000000000 +0000
@@ -1,13 +1,10 @@
-/* $Id: irq.c,v 1.8 2000/02/08 02:01:17 grundler Exp $
- *
+/* 
  * Code to handle x86 style IRQs plus some generic interrupt stuff.
  *
- * This is not in any way SMP-clean.
- *
  * Copyright (C) 1992 Linus Torvalds
  * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle
- * Copyright (C) 1999 SuSE GmbH (Author: Philipp Rumpf, prumpf@tux.org)
- * Copyright (C) 2000 Hewlett Packard Corp (Co-Author: Grant Grundler, grundler@cup.hp.com)
+ * Copyright (C) 1999 SuSE GmbH (Philipp Rumpf, prumpf@tux.org)
+ * Copyright (C) 1999-2000 Grant Grundler
  *
  *    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
@@ -23,138 +20,178 @@
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-#include <linux/config.h>
 #include <linux/bitops.h>
 #include <asm/bitops.h>
+#include <linux/config.h>
 #include <asm/pdc.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/kernel_stat.h>
 #include <linux/signal.h>
-#include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/ioport.h>
 #include <linux/timex.h>
 #include <linux/slab.h>
 #include <linux/random.h>
+#include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
 #include <linux/irq.h>
+#include <linux/spinlock.h>
 
 #include <asm/cache.h>
 
 #undef DEBUG_IRQ
+#undef PARISC_IRQ_CR16_COUNTS
 
 extern void timer_interrupt(int, void *, struct pt_regs *);
 extern void ipi_interrupt(int, void *, struct pt_regs *);
 
 #ifdef DEBUG_IRQ
-#define DBG_IRQ(x...)   printk(x)
+#define DBG_IRQ(irq, x)	if ((irq) != TIMER_IRQ) printk x
 #else /* DEBUG_IRQ */
-#define DBG_IRQ(x...)
+#define DBG_IRQ(irq, x)	do { } while (0)
 #endif /* DEBUG_IRQ */
 
-#define EIEM_MASK(irq) (1L<<(MAX_CPU_IRQ-IRQ_OFFSET(irq)))
-#define CLEAR_EIEM_BIT(irq) set_eiem(get_eiem() & ~EIEM_MASK(irq))
-#define SET_EIEM_BIT(irq) set_eiem(get_eiem() | EIEM_MASK(irq))
+#define EIEM_MASK(irq)       (1UL<<(MAX_CPU_IRQ-IRQ_OFFSET(irq)))
+
+/* Bits in EIEM correlate with cpu_irq_action[].
+** Numbered *Big Endian*! (ie bit 0 is MSB)
+*/
+static unsigned long cpu_eiem = 0;
+
+static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED;  /* protect IRQ regions */
 
-static void disable_cpu_irq(void *unused, int irq)
+#ifdef CONFIG_SMP
+static void cpu_set_eiem(void *info)
 {
-	CLEAR_EIEM_BIT(irq);
+	set_eiem((unsigned long) info);
+}
+#endif
+
+static inline void disable_cpu_irq(void *unused, int irq)
+{
+	unsigned long eirr_bit = EIEM_MASK(irq);
+
+	cpu_eiem &= ~eirr_bit;
+	set_eiem(cpu_eiem);
+        smp_call_function(cpu_set_eiem, (void *) cpu_eiem, 1, 1);
 }
 
 static void enable_cpu_irq(void *unused, int irq)
 {
-	unsigned long mask = EIEM_MASK(irq);
+	unsigned long eirr_bit = EIEM_MASK(irq);
 
-	mtctl(mask, 23);
-	SET_EIEM_BIT(irq);
+	mtctl(eirr_bit, 23);	/* clear EIRR bit before unmasking */
+	cpu_eiem |= eirr_bit;
+        smp_call_function(cpu_set_eiem, (void *) cpu_eiem, 1, 1);
+	set_eiem(cpu_eiem);
+}
+
+/* mask and disable are the same at the CPU level
+** Difference is enable clears pending interrupts
+*/
+#define mask_cpu_irq	disable_cpu_irq
+
+static inline void unmask_cpu_irq(void *unused, int irq)
+{
+	unsigned long eirr_bit = EIEM_MASK(irq);
+	cpu_eiem |= eirr_bit;
+	/* NOTE: sending an IPI will cause do_cpu_irq_mask() to
+	** handle *any* unmasked pending interrupts.
+	** ie We don't need to check for pending interrupts here.
+	*/
+        smp_call_function(cpu_set_eiem, (void *) cpu_eiem, 1, 1);
+	set_eiem(cpu_eiem);
 }
 
-static struct irqaction cpu_irq_actions[IRQ_PER_REGION] = {
-	[IRQ_OFFSET(TIMER_IRQ)] { timer_interrupt, 0, 0, "timer", NULL, NULL },
-	[IRQ_OFFSET(IPI_IRQ)]	{ ipi_interrupt, 0, 0, "IPI", NULL, NULL },
+/*
+ * XXX cpu_irq_actions[] will become 2 dimensional for per CPU EIR support.
+ * correspond changes needed in:
+ * 	processor_probe()	initialize additional action arrays
+ * 	request_irq()		handle CPU IRQ region specially
+ * 	do_cpu_irq_mask()	index into the matching irq_action array.
+ */
+struct irqaction cpu_irq_actions[IRQ_PER_REGION] = {
+	[IRQ_OFFSET(TIMER_IRQ)] { handler: timer_interrupt, name: "timer", },
+#ifdef CONFIG_SMP
+	[IRQ_OFFSET(IPI_IRQ)]	{ handler: ipi_interrupt,   name: "IPI", },
+#endif
 };
 
-struct irq_region cpu_irq_region = {
-	{ disable_cpu_irq, enable_cpu_irq, NULL, NULL },
-	{ &cpu_data[0], "PA-PIC", IRQ_REG_MASK|IRQ_REG_DIS, IRQ_FROM_REGION(CPU_IRQ_REGION)},
-	cpu_irq_actions
+struct irq_region_ops cpu_irq_ops = {
+	disable_cpu_irq, enable_cpu_irq, unmask_cpu_irq, unmask_cpu_irq
 };
 
-struct irq_region *irq_region[NR_IRQ_REGS] = {
-	[ 0 ] NULL,		/* abuse will data page fault (aka code 15) */
-	[ CPU_IRQ_REGION ] &cpu_irq_region,
+struct irq_region cpu0_irq_region = {
+	ops:	{ disable_cpu_irq, enable_cpu_irq, unmask_cpu_irq, unmask_cpu_irq },
+	data:	{ dev: &cpu_data[0],
+		  name: "PARISC-CPU",
+		  irqbase: IRQ_FROM_REGION(CPU_IRQ_REGION), },
+	action:	cpu_irq_actions,
 };
 
+struct irq_region *irq_region[NR_IRQ_REGS] = {
+	[ 0 ]              NULL, /* reserved for EISA, else causes data page fault (aka code 15) */
+	[ CPU_IRQ_REGION ] &cpu0_irq_region,
+};
 
 
-/* we special-case the real IRQs here, which feels right given the relatively
- * high cost of indirect calls.  If anyone is bored enough to benchmark this
- * and find out whether I am right, feel free to.   prumpf */
+/*
+** Generic interfaces that device drivers can use:
+**    mask_irq()	block IRQ
+**    unmask_irq()	re-enable IRQ and trigger if IRQ is pending
+**    disable_irq()	block IRQ
+**    enable_irq()	clear pending and re-enable IRQ
+*/
 
-static inline void mask_irq(int irq)
+void mask_irq(int irq)
 {
 	struct irq_region *region;
-	
-#ifdef DEBUG_IRQ
-	if (irq != TIMER_IRQ)
-#endif
-	DBG_IRQ("mask_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
 
-	if(IRQ_REGION(irq) != CPU_IRQ_REGION) {
-		region = irq_region[IRQ_REGION(irq)];
-		if(region->data.flags & IRQ_REG_MASK)
-			region->ops.mask_irq(region->data.dev, IRQ_OFFSET(irq));
-	} else {
-		CLEAR_EIEM_BIT(irq);
-	}
+	DBG_IRQ(irq, ("mask_irq(%d) %d+%d eiem 0x%lx\n", irq,
+				IRQ_REGION(irq), IRQ_OFFSET(irq), cpu_eiem));
+	irq = irq_cannonicalize(irq);
+	region = irq_region[IRQ_REGION(irq)];
+	if (region->ops.mask_irq)
+		region->ops.mask_irq(region->data.dev, IRQ_OFFSET(irq));
 }
 
-static inline void unmask_irq(int irq)
+void unmask_irq(int irq)
 {
 	struct irq_region *region;
 
-#ifdef DEBUG_IRQ
-	if (irq != TIMER_IRQ)
-#endif
-	DBG_IRQ("unmask_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
-
-	if(IRQ_REGION(irq) != CPU_IRQ_REGION) {
-		region = irq_region[IRQ_REGION(irq)];
-		if(region->data.flags & IRQ_REG_MASK)
-			region->ops.unmask_irq(region->data.dev, IRQ_OFFSET(irq));
-	} else {
-		SET_EIEM_BIT(irq);
-	}
+	DBG_IRQ(irq, ("unmask_irq(%d) %d+%d eiem 0x%lx\n", irq,
+				IRQ_REGION(irq), IRQ_OFFSET(irq), cpu_eiem));
+	irq = irq_cannonicalize(irq);
+	region = irq_region[IRQ_REGION(irq)];
+	if (region->ops.unmask_irq)
+		region->ops.unmask_irq(region->data.dev, IRQ_OFFSET(irq));
 }
 
 void disable_irq(int irq)
 {
 	struct irq_region *region;
 
-#ifdef DEBUG_IRQ
-	if (irq != TIMER_IRQ)
-#endif
-	DBG_IRQ("disable_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
+	DBG_IRQ(irq, ("disable_irq(%d) %d+%d eiem 0x%lx\n", irq,
+				IRQ_REGION(irq), IRQ_OFFSET(irq), cpu_eiem));
+	irq = irq_cannonicalize(irq);
 	region = irq_region[IRQ_REGION(irq)];
-
-	if(region->data.flags & IRQ_REG_DIS)
+	if (region->ops.disable_irq)
 		region->ops.disable_irq(region->data.dev, IRQ_OFFSET(irq));
 	else
 		BUG();
 }
 
-void enable_irq(int irq) 
+void enable_irq(int irq)
 {
 	struct irq_region *region;
 
-#ifdef DEBUG_IRQ
-	if (irq != TIMER_IRQ)
-#endif
-	DBG_IRQ("enable_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
+	DBG_IRQ(irq, ("enable_irq(%d) %d+%d eiem 0x%lx\n", irq,
+				IRQ_REGION(irq), IRQ_OFFSET(irq), cpu_eiem));
+	irq = irq_cannonicalize(irq);
 	region = irq_region[IRQ_REGION(irq)];
 
-	if(region->data.flags & IRQ_REG_DIS)
+	if (region->ops.enable_irq)
 		region->ops.enable_irq(region->data.dev, IRQ_OFFSET(irq));
 	else
 		BUG();
@@ -164,62 +201,92 @@
 {
 #ifdef CONFIG_PROC_FS
 	char *p = buf;
-	int i, j;
-	int regnr, irq_no;
-	struct irq_region *region;
-	struct irqaction *action, *mainaction;
+	unsigned int regnr;
+
+	p += sprintf(p, "     ");
+#ifdef CONFIG_SMP
+	for (regnr = 0; regnr < smp_num_cpus; regnr++)
+#endif
+		p += sprintf(p, "     CPU%02d ", regnr);
 
-	p += sprintf(p, "           ");
-	for (j=0; j<smp_num_cpus; j++)
-		p += sprintf(p, "CPU%d       ",j);
+
+#ifdef PARISC_IRQ_CR16_COUNTS
+	p += sprintf(p, "[min/avg/max] (CPU cycle counts)");
+#endif
 	*p++ = '\n';
 
+	/* We don't need *irqsave lock variants since this is
+	** only allowed to change while in the base context.
+	*/
+	spin_lock(&irq_lock);
 	for (regnr = 0; regnr < NR_IRQ_REGS; regnr++) {
-	    region = irq_region[regnr];
-	    if (!region || !region->action)
+	    unsigned int i;
+	    struct irq_region *region = irq_region[regnr];
+#ifdef CONFIG_SMP
+	    unsigned int j;
+#endif
+
+            if (!region || !region->action)
 		continue;
-	    
-	    mainaction = region->action;
 
 	    for (i = 0; i <= MAX_CPU_IRQ; i++) {
-		action = mainaction++;
-		if (!action || !action->name)
-		    continue;
-		
-		irq_no = IRQ_FROM_REGION(regnr) + i;
-		
+		struct irqaction *action = &region->action[i];
+		unsigned int irq_no = IRQ_FROM_REGION(regnr) + i;
+
+		if (!action->handler)
+			continue;
+
 		p += sprintf(p, "%3d: ", irq_no);
 #ifndef CONFIG_SMP
 		p += sprintf(p, "%10u ", kstat_irqs(irq_no));
 #else
 		for (j = 0; j < smp_num_cpus; j++)
-		    p += sprintf(p, "%10u ",
-			    kstat.irqs[cpu_logical_map(j)][irq_no]);
+			p += sprintf(p, "%10u ",
+				kstat.irqs[j][regnr][i]);
 #endif
-		p += sprintf(p, " %14s", 
+		p += sprintf(p, " %14s",
 			    region->data.name ? region->data.name : "N/A");
+
+#ifndef PARISC_IRQ_CR16_COUNTS
 		p += sprintf(p, "  %s", action->name);
 
-		for (action=action->next; action; action = action->next)
-		    p += sprintf(p, ", %s", action->name);
-		*p++ = '\n';
-	    }	    	     
-	}  
+		while ((action = action->next))
+			p += sprintf(p, ", %s", action->name);
+#else
+		for ( ;action; action = action->next) {
+			unsigned int i, avg, min, max;
 
-	p += sprintf(p, "\n");
-#if CONFIG_SMP
-	p += sprintf(p, "LOC: ");
-	for (j = 0; j < smp_num_cpus; j++)
-		p += sprintf(p, "%10u ",
-			apic_timer_irqs[cpu_logical_map(j)]);
-	p += sprintf(p, "\n");
+			min = max = action->cr16_hist[0];
+
+			for (avg = i = 0; i < PARISC_CR16_HIST_SIZE; i++) {
+				int hist = action->cr16_hist[i];
+
+				if (hist) {
+					avg += hist;
+				} else
+					break;
+
+				if (hist > max) max = hist;
+				if (hist < min) min = hist;
+			}
+
+			avg /= i;
+			p += sprintf(p, " %s[%d/%d/%d]", action->name,
+					min,avg,max);
+		}
 #endif
 
+		*p++ = '\n';
+	    }
+	}
+	spin_unlock(&irq_lock);
+
+	p += sprintf(p, "\n");
 	return p - buf;
 
 #else	/* CONFIG_PROC_FS */
 
-	return 0;	
+	return 0;
 
 #endif	/* CONFIG_PROC_FS */
 }
@@ -240,8 +307,8 @@
 	int irq;
 
 	/* never return irq 0 cause that's the interval timer */
-	for(irq=1; irq<=MAX_CPU_IRQ; irq++) {
-		if(cpu_irq_region.action[irq].handler == NULL) {
+	for (irq = 1; irq <= MAX_CPU_IRQ; irq++) {
+		if (cpu_irq_actions[irq].handler == NULL) {
 			return (IRQ_FROM_REGION(CPU_IRQ_REGION) + irq);
 		}
 	}
@@ -254,9 +321,7 @@
 txn_claim_irq(int irq)
 {
 	if (irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)].handler ==NULL)
-	{
 		return irq;
-	}
 
 	/* unlikely, but be prepared */
 	return -1;
@@ -265,14 +330,18 @@
 unsigned long
 txn_alloc_addr(int virt_irq)
 {
-	struct cpuinfo_parisc *dev = (struct cpuinfo_parisc *) (irq_region[IRQ_REGION(virt_irq)]->data.dev);
+	static int next_cpu = -1;
 
-	if (0==dev) {
-		printk(KERN_ERR "txn_alloc_addr(0x%x): CPU IRQ region? dev %p\n",
-			virt_irq,dev);
-		return(0UL);
-	}
-	return (dev->txn_addr);
+	next_cpu++; /* assign to "next" CPU we want this bugger on */
+
+	/* validate entry */
+	while ((next_cpu < NR_CPUS) && !cpu_data[next_cpu].txn_addr)
+		next_cpu++;
+
+	if (next_cpu >= NR_CPUS) 
+		next_cpu = 0;	/* nothing else, assign monarch */
+
+	return cpu_data[next_cpu].txn_addr;
 }
 
 
@@ -283,7 +352,7 @@
 ** V-class (EPIC):          6 bits
 ** N/L-class/A500:          8 bits (iosapic)
 ** PCI 2.2 MSI:             16 bits (I think)
-** Existing PCI devices:    32-bits (NCR c720/ATM/GigE/HyperFabric)
+** Existing PCI devices:    32-bits (all Symbios SCSI/ATM/HyperFabric)
 **
 ** On the service provider side:
 ** o PA 1.1 (and PA2.0 narrow mode)     5-bits (width of EIR register)
@@ -308,117 +377,202 @@
 		panic("Sorry -- didn't allocate valid IRQ for this device\n");
 	}
 
-	return(IRQ_OFFSET(virt_irq));
+	return (IRQ_OFFSET(virt_irq));
 }
 
-
-/* FIXME: SMP, flags, bottom halves, rest */
 void do_irq(struct irqaction *action, int irq, struct pt_regs * regs)
 {
 	int cpu = smp_processor_id();
 
 	irq_enter(cpu, irq);
+	++kstat.irqs[cpu][IRQ_REGION(irq)][IRQ_OFFSET(irq)];
 
-#ifdef DEBUG_IRQ
-	if (irq != TIMER_IRQ)
+	DBG_IRQ(irq, ("do_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq)));
+
+	for (; action; action = action->next) {
+#ifdef PARISC_IRQ_CR16_COUNTS
+		unsigned long cr_start = mfctl(16);
 #endif
-	DBG_IRQ("do_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
-	if (action->handler == NULL)
-		printk(KERN_ERR "No handler for interrupt %d !\n", irq);
 
-	for(; action && action->handler; action = action->next) {
+		if (action->handler == NULL) {
+			if (IRQ_REGION(irq) == EISA_IRQ_REGION && irq_region[EISA_IRQ_REGION]) {
+				/* were we called due to autodetecting (E)ISA irqs ? */
+				unsigned int *status;
+				status = &irq_region[EISA_IRQ_REGION]->data.status[IRQ_OFFSET(irq)];
+				if (*status & IRQ_AUTODETECT) {
+					*status &= ~IRQ_WAITING;
+					continue; 
+				}
+			}
+			printk(KERN_ERR "IRQ:  CPU:%d No handler for IRQ %d !\n", cpu, irq);
+			continue;
+		}
+
 		action->handler(irq, action->dev_id, regs);
+
+#ifdef PARISC_IRQ_CR16_COUNTS
+		{
+			unsigned long cr_end = mfctl(16);
+			unsigned long tmp = cr_end - cr_start;
+			/* check for roll over */
+			cr_start = (cr_end < cr_start) ?  -(tmp) : (tmp);
+		}
+		action->cr16_hist[action->cr16_idx++] = (int) cr_start;
+		action->cr16_idx &= PARISC_CR16_HIST_SIZE - 1;
+#endif
 	}
-	
+
 	irq_exit(cpu, irq);
+}
+
+
+/* ONLY called from entry.S:intr_extint() */
+void do_cpu_irq_mask(struct pt_regs *regs)
+{
+	unsigned long eirr_val;
+	unsigned int i=3;	/* limit time in interrupt context */
+
+	/*
+	 * PSW_I or EIEM bits cannot be enabled until after the
+	 * interrupts are processed.
+	 * timer_interrupt() assumes it won't get interrupted when it
+	 * holds the xtime_lock...an unmasked interrupt source could
+	 * interrupt and deadlock by trying to grab xtime_lock too.
+	 * Keeping PSW_I and EIEM disabled avoids this.
+	 */
+	set_eiem(0UL);	/* disable all extr interrupt for now */
+
+	/* 1) only process IRQs that are enabled/unmasked (cpu_eiem)
+	 * 2) We loop here on EIRR contents in order to avoid
+	 *    nested interrupts or having to take another interupt
+	 *    when we could have just handled it right away.
+	 * 3) Limit the number of times we loop to make sure other
+	 *    processing can occur.
+	 */
+	while ((eirr_val = (mfctl(23) & cpu_eiem)) && --i) {
+		unsigned long bit = (1UL<<MAX_CPU_IRQ);
+		unsigned int irq;
+
+		mtctl(eirr_val, 23); /* reset bits we are going to process */
 
-	/* don't need to care about unmasking and stuff */
-	do_softirq();
+#ifdef DEBUG_IRQ
+		if (eirr_val != (1UL << MAX_CPU_IRQ))
+			printk(KERN_DEBUG "do_cpu_irq_mask  %x\n", eirr_val);
+#endif
+
+		for (irq = 0; eirr_val && bit; bit>>=1, irq++)
+		{
+			if (!(bit&eirr_val))
+				continue;
+
+			/* clear bit in mask - can exit loop sooner */
+			eirr_val &= ~bit;
+
+			do_irq(&cpu_irq_actions[irq], TIMER_IRQ+irq, regs);
+		}
+	}
+	set_eiem(cpu_eiem);
 }
 
+
+/* Called from second level IRQ regions: eg dino or iosapic. */
 void do_irq_mask(unsigned long mask, struct irq_region *region, struct pt_regs *regs)
 {
 	unsigned long bit;
-	int irq;
-	int cpu = smp_processor_id();
+	unsigned int irq;
 
 #ifdef DEBUG_IRQ
-	if (mask != (1L << MAX_CPU_IRQ))
-	    printk("do_irq_mask %08lx %p %p\n", mask, region, regs);
+	if (mask != (1L<<MAX_CPU_IRQ))
+	    printk(KERN_DEBUG "do_irq_mask %08lx %p %p\n", mask, region, regs);
 #endif
 
-	for(bit=(1L<<MAX_CPU_IRQ), irq = 0; mask && bit; bit>>=1, irq++) {
-		int irq_num;
-		if(!(bit&mask))
+	for (bit = (1L<<MAX_CPU_IRQ), irq = 0; mask && bit; bit>>=1, irq++) {
+		unsigned int irq_num;
+		if (!(bit&mask))
 			continue;
 
+		mask &= ~bit;	/* clear bit in mask - can exit loop sooner */
 		irq_num = region->data.irqbase + irq;
 
-		++kstat.irqs[cpu][IRQ_FROM_REGION(CPU_IRQ_REGION) | irq];
-		if (IRQ_REGION(irq_num) != CPU_IRQ_REGION)
-		    ++kstat.irqs[cpu][irq_num];
-
 		mask_irq(irq_num);
 		do_irq(&region->action[irq], irq_num, regs);
 		unmask_irq(irq_num);
 	}
 }
 
-static inline int alloc_irqregion(void)
+
+static inline int find_free_region(void)
 {
 	int irqreg;
 
-	for(irqreg=1; irqreg<=(NR_IRQ_REGS); irqreg++) {
-		if(irq_region[irqreg] == NULL)
+	for (irqreg=1; irqreg <= (NR_IRQ_REGS); irqreg++) {
+		if (irq_region[irqreg] == NULL)
 			return irqreg;
 	}
 
 	return 0;
 }
 
-struct irq_region *alloc_irq_region(
-	int count, struct irq_region_ops *ops, unsigned long flags,
-	const char *name, void *dev)
+
+/*****
+ * alloc_irq_region - allocate/init a new IRQ region
+ * @count: number of IRQs in this region.
+ * @ops: function table with request/release/mask/unmask/etc.. entries.
+ * @name: name of region owner for /proc/interrupts output.
+ * @dev: private data to associate with the new IRQ region.
+ *
+ * Every IRQ must become a MMIO write to the CPU's EIRR in
+ * order to get CPU service. The IRQ region represents the
+ * number of unique events the region handler can (or must)
+ * identify. For PARISC CPU, that's the width of the EIR Register.
+ * IRQ regions virtualize IRQs (eg EISA or PCI host bus controllers)
+ * for line based devices.
+ */
+struct irq_region *alloc_irq_region( int count, struct irq_region_ops *ops,
+					const char *name, void *dev)
 {
 	struct irq_region *region;
 	int index;
 
-	index = alloc_irqregion();
+	index = find_free_region();
+	if (index == 0) {
+		printk(KERN_ERR "Maximum number of irq regions exceeded. Increase NR_IRQ_REGS!\n");
+		return NULL;
+	}
 
-	if((IRQ_REGION(count-1)))
+	if ((IRQ_REGION(count-1)))
 		return NULL;
-	
+
 	if (count < IRQ_PER_REGION) {
-	    DBG_IRQ("alloc_irq_region() using minimum of %d irq lines for %s (%d)\n", 
-			IRQ_PER_REGION, name, count);
+	    DBG_IRQ(0, ("alloc_irq_region() using minimum of %d irq lines for %s (%d)\n",
+			IRQ_PER_REGION, name, count));
 	    count = IRQ_PER_REGION;
 	}
 
-	if(flags & IRQ_REG_MASK)
-		if(!(ops->mask_irq && ops->unmask_irq))
-			return NULL;
-			
-	if(flags & IRQ_REG_DIS)
-		if(!(ops->disable_irq && ops->enable_irq))
+	/* if either mask *or* unmask is set, both have to be set. */
+	if((ops->mask_irq || ops->unmask_irq) &&
+		!(ops->mask_irq && ops->unmask_irq))
 			return NULL;
 
-	if((irq_region[index]))
-		return NULL;
+	/* ditto for enable/disable */
+	if( (ops->disable_irq || ops->enable_irq) &&
+		!(ops->disable_irq && ops->enable_irq) )
+			return NULL;
 
-	region = kmalloc(sizeof *region, GFP_ATOMIC);
-	if(!region)
+	region = kmalloc(sizeof(*region), GFP_ATOMIC);
+	if (!region)
 		return NULL;
+	memset(region, 0, sizeof(*region));
 
-	region->action = kmalloc(sizeof *region->action * count, GFP_ATOMIC);
-	if(!region->action) {
+	region->action = kmalloc(count * sizeof(*region->action), GFP_ATOMIC);
+	if (!region->action) {
 		kfree(region);
 		return NULL;
 	}
-	memset(region->action, 0, sizeof *region->action * count);
+	memset(region->action, 0, count * sizeof(*region->action));
 
 	region->ops = *ops;
 	region->data.irqbase = IRQ_FROM_REGION(index);
-	region->data.flags = flags;
 	region->data.name = name;
 	region->data.dev = dev;
 
@@ -426,14 +580,12 @@
 
 	return irq_region[index];
 }
-	
 
-	
 /* FIXME: SMP, flags, bottom halves, rest */
 
-int request_irq(unsigned int irq, 
+int request_irq(unsigned int irq,
 		void (*handler)(int, void *, struct pt_regs *),
-		unsigned long irqflags, 
+		unsigned long irqflags,
 		const char * devname,
 		void *dev_id)
 {
@@ -442,13 +594,19 @@
 #if 0
 	printk(KERN_INFO "request_irq(%d, %p, 0x%lx, %s, %p)\n",irq, handler, irqflags, devname, dev_id);
 #endif
-	if(!handler) {
+
+	irq = irq_cannonicalize(irq);
+	/* request_irq()/free_irq() may not be called from interrupt context. */
+	if (in_interrupt())
+		BUG();
+
+	if (!handler) {
 		printk(KERN_ERR "request_irq(%d,...): Augh! No handler for irq!\n",
 			irq);
 		return -EINVAL;
 	}
 
-	if ((IRQ_REGION(irq) == 0) || irq_region[IRQ_REGION(irq)] == NULL) {
+	if (irq_region[IRQ_REGION(irq)] == NULL) {
 		/*
 		** Bug catcher for drivers which use "char" or u8 for
 		** the IRQ number. They lose the region number which
@@ -459,19 +617,24 @@
 		return -EINVAL;
 	}
 
-	action = &irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)];
+	spin_lock(&irq_lock);
+	action = &(irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)]);
 
-	if(action->handler) {
-		while(action->next)
+	/* First one is preallocated. */
+	if (action->handler) {
+		/* But it's in use...find the tail and allocate a new one */
+		while (action->next)
 			action = action->next;
 
-		action->next = kmalloc(sizeof *action, GFP_ATOMIC);
+		action->next = kmalloc(sizeof(*action), GFP_ATOMIC);
+		memset(action->next, 0, sizeof(*action));
 
 		action = action->next;
-	}			
+	}
 
-	if(!action) {
-		printk(KERN_ERR "request_irq():Augh! No action!\n") ;
+	if (!action) {
+		spin_unlock(&irq_lock);
+		printk(KERN_ERR "request_irq(): Augh! No action!\n") ;
 		return -ENOMEM;
 	}
 
@@ -481,6 +644,7 @@
 	action->name = devname;
 	action->next = NULL;
 	action->dev_id = dev_id;
+	spin_unlock(&irq_lock);
 
 	enable_irq(irq);
 	return 0;
@@ -490,14 +654,22 @@
 {
 	struct irqaction *action, **p;
 
+	/* See comments in request_irq() about interrupt context */
+	irq = irq_cannonicalize(irq);
+	
+	if (in_interrupt()) BUG();
+
+	spin_lock(&irq_lock);
 	action = &irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)];
 
-	if(action->dev_id == dev_id) {
-		if(action->next == NULL)
+	if (action->dev_id == dev_id) {
+		if (action->next == NULL) {
 			action->handler = NULL;
-		else
-			memcpy(action, action->next, sizeof *action);
+		} else {
+			memcpy(action, action->next, sizeof(*action));
+		}
 
+		spin_unlock(&irq_lock);
 		return;
 	}
 
@@ -512,27 +684,175 @@
 		*p = action->next;
 		kfree(action);
 
+		spin_unlock(&irq_lock);
 		return;
 	}
 
+	spin_unlock(&irq_lock);
 	printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
 }
 
-unsigned long probe_irq_on (void)
+
+/*
+ * IRQ autodetection code..
+ *
+ * This depends on the fact that any interrupt that
+ * comes in on to an unassigned handler will get stuck
+ * with "IRQ_WAITING" cleared and the interrupt
+ * disabled.
+ */
+
+static DECLARE_MUTEX(probe_sem);
+
+/**
+ *	probe_irq_on	- begin an interrupt autodetect
+ *
+ *	Commence probing for an interrupt. The interrupts are scanned
+ *	and a mask of potential interrupt lines is returned.
+ *
+ */
+
+/* TODO: spin_lock_irq(desc->lock -> irq_lock) */
+
+unsigned long probe_irq_on(void)
 {
-	return 0;
+	unsigned int i;
+	unsigned long val;
+	unsigned long delay;
+	struct irq_region *region;
+
+	/* support for irq autoprobing is limited to EISA (irq region 0) */
+	region = irq_region[EISA_IRQ_REGION];
+	if (!EISA_bus || !region)
+		return 0;
+
+	down(&probe_sem);
+
+	/*
+	 * enable any unassigned irqs
+	 * (we must startup again here because if a longstanding irq
+	 * happened in the previous stage, it may have masked itself)
+	 */
+	for (i = EISA_MAX_IRQS-1; i > 0; i--) {
+		struct irqaction *action;
+		
+		spin_lock_irq(&irq_lock);
+		action = region->action + i;
+		if (!action->handler) {
+			region->data.status[i] |= IRQ_AUTODETECT | IRQ_WAITING;
+			region->ops.enable_irq(region->data.dev,i);
+		}
+		spin_unlock_irq(&irq_lock);
+	}
+
+	/*
+	 * Wait for spurious interrupts to trigger
+	 */
+	for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
+		/* about 100ms delay */ synchronize_irq();
+
+	/*
+	 * Now filter out any obviously spurious interrupts
+	 */
+	val = 0;
+	for (i = 0; i < EISA_MAX_IRQS; i++) {
+		unsigned int status;
+
+		spin_lock_irq(&irq_lock);
+		status = region->data.status[i];
+
+		if (status & IRQ_AUTODETECT) {
+			/* It triggered already - consider it spurious. */
+			if (!(status & IRQ_WAITING)) {
+				region->data.status[i] = status & ~IRQ_AUTODETECT;
+				region->ops.disable_irq(region->data.dev,i);
+			} else
+				if (i < BITS_PER_LONG)
+					val |= (1 << i);
+		}
+		spin_unlock_irq(&irq_lock);
+	}
+
+	return val;
 }
 
-int probe_irq_off (unsigned long irqs)
+/*
+ * Return the one interrupt that triggered (this can
+ * handle any interrupt source).
+ */
+
+/**
+ *	probe_irq_off	- end an interrupt autodetect
+ *	@val: mask of potential interrupts (unused)
+ *
+ *	Scans the unused interrupt lines and returns the line which
+ *	appears to have triggered the interrupt. If no interrupt was
+ *	found then zero is returned. If more than one interrupt is
+ *	found then minus the first candidate is returned to indicate
+ *	their is doubt.
+ *
+ *	The interrupt probe logic state is returned to its previous
+ *	value.
+ *
+ *	BUGS: When used in a module (which arguably shouldnt happen)
+ *	nothing prevents two IRQ probe callers from overlapping. The
+ *	results of this are non-optimal.
+ */
+ 
+int probe_irq_off(unsigned long val)
 {
-	return 0;
+        struct irq_region *region;
+	int i, irq_found, nr_irqs;
+
+        /* support for irq autoprobing is limited to EISA (irq region 0) */
+        region = irq_region[EISA_IRQ_REGION];
+        if (!EISA_bus || !region)
+		return 0;
+
+	nr_irqs = 0;
+	irq_found = 0;
+	for (i = 0; i < EISA_MAX_IRQS; i++) {
+		unsigned int status;
+		
+		spin_lock_irq(&irq_lock);
+		status = region->data.status[i];
+
+                if (status & IRQ_AUTODETECT) {
+			if (!(status & IRQ_WAITING)) {
+				if (!nr_irqs)
+					irq_found = i;
+				nr_irqs++;
+			}
+			region->ops.disable_irq(region->data.dev,i);
+			region->data.status[i] = status & ~IRQ_AUTODETECT;
+		}
+		spin_unlock_irq(&irq_lock);
+	}
+	up(&probe_sem);
+
+	if (nr_irqs > 1)
+		irq_found = -irq_found;
+	return irq_found;
 }
 
 
 void __init init_IRQ(void)
 {
+	local_irq_disable();	/* PARANOID - should already be disabled */
+	mtctl(-1L, 23);		/* EIRR : clear all pending external intr */
+#ifdef CONFIG_SMP
+	if (!cpu_eiem)
+		cpu_eiem = EIEM_MASK(IPI_IRQ) | EIEM_MASK(TIMER_IRQ);
+#else
+	cpu_eiem = EIEM_MASK(TIMER_IRQ);
+#endif
+        set_eiem(cpu_eiem);	/* EIEM : enable all external intr */
+
 }
 
-void init_irq_proc(void)
+#ifdef CONFIG_PROC_FS
+/* called from kernel/sysctl.c:sysctl_init() */
+void __init init_irq_proc(void)
 {
 }
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/irq_smp.c linux-2.4.20/arch/parisc/kernel/irq_smp.c
--- linux-2.4.19/arch/parisc/kernel/irq_smp.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/irq_smp.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,232 @@
+/*
+ *  linux/arch/parisc/kernel/irq_smp.c
+ *  (90% stolen from alpha port, 9% from ia64, rest is mine -ggg)
+ *  
+ *  Copyright (C) 2001 Hewlett-Packard Co
+ *  Copyright (C) 2001 Grant Grundler <grundler@puffin.external.hp.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/random.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+
+int global_irq_holder = NO_PROC_ID;	/* Who has global_irq_lock. */
+spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; /* protects IRQ's. */
+
+
+/* Global IRQ locking depth. */
+static void *previous_irqholder = NULL;
+
+#define MAXCOUNT 100000000
+
+
+static void
+show(char * str, void *where)
+{
+	int cpu = smp_processor_id();
+
+	printk("\n%s, CPU %d: %p\n", str, cpu, where);
+	printk("irq:  %d [%d %d]\n",
+		irqs_running(),
+		local_irq_count(0),
+		local_irq_count(1));
+
+	printk("bh:   %d [%d %d]\n",
+		spin_is_locked(&global_bh_lock) ? 1 : 0,
+		local_bh_count(0),
+		local_bh_count(1));
+}
+
+static inline void
+wait_on_irq(int cpu, void *where)
+{
+	int count = MAXCOUNT;
+
+	for (;;) {
+
+		/*
+		 * Wait until all interrupts are gone. Wait
+		 * for bottom half handlers unless we're
+		 * already executing in one..
+		 */
+		if (!irqs_running()) {
+			if (local_bh_count(cpu)
+			    || !spin_is_locked(&global_bh_lock))
+				break;
+		}
+
+		/* Duh, we have to loop. Release the lock to avoid deadlocks */
+		spin_unlock(&global_irq_lock);
+
+		for (;;) {
+			if (!--count) {
+				show("wait_on_irq", where);
+				count = MAXCOUNT;
+			}
+			__sti();
+			udelay(1); /* make sure to run pending irqs */
+			__cli();
+
+			if (irqs_running())
+				continue;
+			if (spin_is_locked(&global_irq_lock))
+				continue;
+			if (!local_bh_count(cpu)
+			    && spin_is_locked(&global_bh_lock))
+				continue;
+			if (spin_trylock(&global_irq_lock))
+				break;
+		}
+	}
+}
+
+static inline void
+get_irqlock(int cpu, void* where)
+{
+	if (!spin_trylock(&global_irq_lock)) {
+		/* Do we already hold the lock?  */
+		if (cpu == global_irq_holder)
+			return;
+		/* Uhhuh.. Somebody else got it.  Wait.  */
+		spin_lock(&global_irq_lock);
+	}
+
+	/*
+	 * Ok, we got the lock bit.
+	 * But that's actually just the easy part.. Now
+	 * we need to make sure that nobody else is running
+	 * in an interrupt context. 
+	 */
+	wait_on_irq(cpu, where);
+
+	/*
+	 * Finally.
+	 */
+#if DEBUG_SPINLOCK
+	global_irq_lock.task = current;
+	global_irq_lock.previous = where;
+#endif
+	global_irq_holder = cpu;
+	previous_irqholder = where;
+}
+
+
+/*
+** A global "cli()" while in an interrupt context
+** turns into just a local cli(). Interrupts
+** should use spinlocks for the (very unlikely)
+** case that they ever want to protect against
+** each other.
+** 
+** If we already have local interrupts disabled,
+** this will not turn a local disable into a
+** global one (problems with spinlocks: this makes
+** save_flags+cli+sti usable inside a spinlock).
+*/
+void
+__global_cli(void)
+{
+	unsigned int flags;
+	__save_flags(flags);
+	if (flags & PSW_I) {
+		int cpu = smp_processor_id();
+		__cli(); 
+		if (!local_irq_count(cpu)) {
+			void *where = __builtin_return_address(0);
+			get_irqlock(cpu, where);
+		}
+	}
+}
+
+void
+__global_sti(void)
+{
+	int cpu = smp_processor_id();
+
+	if (!local_irq_count(cpu))
+		release_irqlock(cpu);
+	__sti();
+}
+
+/*
+ * SMP flags value to restore to:
+ * 0 - global cli
+ * 1 - global sti
+ * 2 - local cli
+ * 3 - local sti
+ */
+unsigned long
+__global_save_flags(void)
+{
+	int retval;
+	int local_enabled;
+	unsigned long flags;
+	int cpu = smp_processor_id();
+
+	__save_flags(flags);
+	local_enabled = (flags & PSW_I) != 0;
+	/* default to local */
+	retval = 2 + local_enabled;
+
+	/* Check for global flags if we're not in an interrupt.  */
+	if (!local_irq_count(cpu)) {
+		if (local_enabled)
+			retval = 1;
+		if (global_irq_holder == cpu)
+			retval = 0;
+	}
+	return retval;
+}
+
+void
+__global_restore_flags(unsigned long flags)
+{
+	switch (flags) {
+	case 0:
+		__global_cli();
+		break;
+	case 1:
+		__global_sti();
+		break;
+	case 2:
+		__cli();
+		break;
+	case 3:
+		__sti();
+		break;
+	default:
+		printk(KERN_ERR "global_restore_flags: %08lx (%p)\n",
+			flags, __builtin_return_address(0));
+	}
+}
+
+/*
+ * From its use, I infer that synchronize_irq() stalls a thread until
+ * the effects of a command to an external device are known to have
+ * taken hold.  Typically, the command is to stop sending interrupts.
+ * The strategy here is wait until there is at most one processor
+ * (this one) in an irq.  The memory barrier serializes the write to
+ * the device and the subsequent accesses of global_irq_count.
+ * --jmartin
+ */
+#define DEBUG_SYNCHRONIZE_IRQ 0
+
+void
+synchronize_irq(void)
+{
+	/* Jay's version.  */
+	if (irqs_running()) {
+		cli();
+		sti();
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/keyboard.c linux-2.4.20/arch/parisc/kernel/keyboard.c
--- linux-2.4.19/arch/parisc/kernel/keyboard.c	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/keyboard.c	2002-10-29 11:18:34.000000000 +0000
@@ -1,4 +1,12 @@
 /*
+ *  WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *  ---------------------------------------------------------------
+ *  This source file will be removed as soon as we have converted
+ *  hp_psaux.c and hp_keyb.c to the input layer !
+ *  
+ */
+
+/*
  *  linux/arch/parisc/kernel/keyboard.c
  *
  *  Alex deVries <adevries@thepuffingroup.com>
@@ -7,8 +15,10 @@
  *  Copyright 2000 Philipp Rumpf
  */
 
+#include <linux/errno.h>
 #include <linux/keyboard.h>
 #include <asm/keyboard.h>
+#include <linux/module.h>
 
 static int def_setkeycode(unsigned int x, unsigned int y)
 {
@@ -43,20 +53,29 @@
 
 static char def_sysrq_xlate[NR_KEYS];
 
-static struct kbd_ops def_kbd_ops = {
-	setkeycode:	def_setkeycode,
-	getkeycode:	def_getkeycode,
-	translate:	def_translate,
-	unexpected_up:	def_unexpected_up,
-	leds:		def_leds,
-	init_hw:	def_init_hw,
-
-	sysrq_key:	0xff,
+#define DEFAULT_KEYB_OPS \
+	setkeycode:	def_setkeycode,	\
+	getkeycode:	def_getkeycode, \
+	translate:	def_translate, \
+	unexpected_up:	def_unexpected_up, \
+	leds:		def_leds, \
+	init_hw:	def_init_hw, \
+	sysrq_key:	0xff, \
 	sysrq_xlate:	def_sysrq_xlate,
+
+static struct kbd_ops def_kbd_ops = {
+	DEFAULT_KEYB_OPS
 };
 
 struct kbd_ops *kbd_ops = &def_kbd_ops;
 
+void unregister_kbd_ops(void)
+{
+	struct kbd_ops new_kbd_ops = { DEFAULT_KEYB_OPS };
+	register_kbd_ops(&new_kbd_ops);
+}
+EXPORT_SYMBOL(unregister_kbd_ops);
+
 void register_kbd_ops(struct kbd_ops *ops)
 {
 	if(ops->setkeycode)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/lba_pci.c linux-2.4.20/arch/parisc/kernel/lba_pci.c
--- linux-2.4.19/arch/parisc/kernel/lba_pci.c	2001-02-09 19:29:44.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/lba_pci.c	2002-10-29 11:18:49.000000000 +0000
@@ -34,6 +34,7 @@
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>		/* for __init and __devinit */
+/* #define PCI_DEBUG	enable ASSERT */
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
@@ -42,15 +43,13 @@
 #include <asm/byteorder.h>
 #include <asm/irq.h>		/* for struct irq_region support */
 #include <asm/pdc.h>
-#include <asm/pdcpat.h>
 #include <asm/page.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 
-#include <asm/hardware.h>	/* for register_driver() stuff */
+#include <asm/hardware.h>	/* for register_parisc_driver() stuff */
 #include <asm/iosapic.h>	/* for iosapic_register() */
-#include <asm/gsc.h>		/* gsc_read/write stuff */
-
+#include <asm/io.h>		/* read/write stuff */
 
 #ifndef TRUE
 #define TRUE (1 == 1)
@@ -62,6 +61,9 @@
 #undef DEBUG_LBA_CFG	/* debug Config Space Access (ie PCI Bus walk) */
 #undef DEBUG_LBA_PAT	/* debug PCI Resource Mgt code - PDC PAT only */
 
+#undef FBB_SUPPORT	/* Fast Back-Back xfers - NOT READY YET */
+
+
 #ifdef DEBUG_LBA
 #define DBG(x...)	printk(x)
 #else
@@ -102,22 +104,6 @@
 
 #define MODULE_NAME "lba"
 
-static int lba_driver_callback(struct hp_device *, struct pa_iodc_driver *);
-
-
-static struct pa_iodc_driver lba_drivers_for[]= {
-
-   {HPHW_BRIDGE, 0x782, 0x0, 0xa, 0,0,
-		DRIVER_CHECK_HVERSION + 
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "tbd", (void *) lba_driver_callback},
-
-   {0,0,0,0,0,0,
-   0,
-   (char *) NULL, (char *) NULL, (void *) NULL}
-};
-
-
 #define LBA_FUNC_ID	0x0000	/* function id */
 #define LBA_FCLASS	0x0008	/* function class, bist, header, rev... */
 #define LBA_CAPABLE	0x0030	/* capabilities register */
@@ -137,6 +123,9 @@
 #define LBA_MOD_ID	0x0100	/* Module ID. PDC_PAT_CELL reports 4 */
 
 #define LBA_STAT_CTL	0x0108	/* Status & Control */
+#define   LBA_BUS_RESET		0x01	/*  Deassert PCI Bus Reset Signal */
+#define   CLEAR_ERRLOG		0x10	/*  "Clear Error Log" cmd */
+#define   CLEAR_ERRLOG_ENABLE	0x20	/*  "Clear Error Log" Enable */
 #define   HF_ENABLE	0x40	/*    enable HF mode (default is -1 mode) */
 
 #define LBA_LMMIO_BASE	0x0200	/* < 4GB I/O address range */
@@ -162,15 +151,18 @@
 
 #define LBA_DMA_CTL	0x0278	/* firmware sets this */
 
-/* RESET: ignore DMA stuff until we can measure performance */
-#define LBA_IBASE	0x0300	/* DMA support */
+#define LBA_IBASE	0x0300	/* SBA DMA support */
 #define LBA_IMASK	0x0308
+
+/* FIXME: ignore DMA Hint stuff until we can measure performance */
 #define LBA_HINT_CFG	0x0310
 #define LBA_HINT_BASE	0x0380	/* 14 registers at every 8 bytes. */
 
 /* ERROR regs are needed for config cycle kluges */
 #define LBA_ERROR_CONFIG 0x0680
+#define     LBA_SMART_MODE 0x20
 #define LBA_ERROR_STATUS 0x0688
+#define LBA_ROPE_CTL     0x06A0
 
 #define LBA_IOSAPIC_BASE	0x800 /* Offset of IRQ logic */
 
@@ -232,19 +224,20 @@
  * BE WARNED: register writes are posted.
  *  (ie follow writes which must reach HW with a read)
  */
-#define READ_U8(addr)  gsc_readb(addr)
-#define READ_U16(addr) gsc_readw((u16 *) (addr))
-#define READ_U32(addr) gsc_readl((u32 *) (addr))
-#define WRITE_U8(value, addr) gsc_writeb(value, addr)
-#define WRITE_U16(value, addr) gsc_writew(value, (u16 *) (addr))
-#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr))
-
-#define READ_REG8(addr)  gsc_readb(addr)
-#define READ_REG16(addr) le16_to_cpu(gsc_readw((u16 *) (addr)))
-#define READ_REG32(addr) le32_to_cpu(gsc_readl((u32 *) (addr)))
-#define WRITE_REG8(value, addr) gsc_writeb(value, addr)
-#define WRITE_REG16(value, addr) gsc_writew(cpu_to_le16(value), (u16 *) (addr))
-#define WRITE_REG32(value, addr) gsc_writel(cpu_to_le32(value), (u32 *) (addr))
+#define READ_U8(addr)  __raw_readb(addr)
+#define READ_U16(addr) __raw_readw(addr)
+#define READ_U32(addr) __raw_readl(addr)
+#define WRITE_U8(value, addr)  __raw_writeb(value, addr)
+#define WRITE_U16(value, addr) __raw_writew(value, addr)
+#define WRITE_U32(value, addr) __raw_writel(value, addr)
+
+#define READ_REG8(addr)  readb(addr)
+#define READ_REG16(addr) readw(addr)
+#define READ_REG32(addr) readl(addr)
+#define READ_REG64(addr) readq(addr)
+#define WRITE_REG8(value, addr)  writeb(value, addr)
+#define WRITE_REG16(value, addr) writew(value, addr)
+#define WRITE_REG32(value, addr) writel(value, addr)
 
 
 #define LBA_CFG_TOK(bus,dfn) ((u32) ((bus)<<16 | (dfn)<<8))
@@ -253,25 +246,12 @@
 #define LBA_CFG_FUNC(tok) ((u8) ((tok)>>8 ) & 0x7)
 
 
-#ifdef DEBUG_LBA
-/* Extract LBA (Rope) number from HPA */
-#define LBA_NUM(x)    ((((uintptr_t) x) >> 13) & 0xf)
-#endif /* DEBUG_LBA */
-
-#ifdef __LP64__
-/* PDC_PAT */
-static  unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0};
-#endif
-
 /*
-** One time initialization to let the world know the LBA was found.
-** This is the only routine which is NOT static.
-** Must be called exactly once before pci_init().
+** Extract LBA (Rope) number from HPA
+** REVISIT: 16 ropes for Stretch/Ike?
 */
-void __init lba_init(void)
-{
-	register_driver(lba_drivers_for);
-}
+#define ROPES_PER_SBA	8
+#define LBA_NUM(x)    ((((unsigned long) x) >> 13) & (ROPES_PER_SBA-1))
 
 
 static void
@@ -282,9 +262,9 @@
 	if (NULL == r)
 		return;
 
-	printk("(%p)", r->parent);
+	printk(KERN_DEBUG "(%p)", r->parent);
 	for (i = d; i ; --i) printk(" ");
-	printk("%p [%lx,%lx]/%x\n", r, r->start, r->end, (int) r->flags);
+	printk(KERN_DEBUG "%p [%lx,%lx]/%x\n", r, r->start, r->end, (int) r->flags);
 	lba_dump_res(r->child, d+2);
 	lba_dump_res(r->sibling, d);
 }
@@ -369,7 +349,7 @@
      * Set the smart mode bit so that master aborts don't cause		\
      * LBA to go into PCI fatal mode (required).			\
      */									\
-    WRITE_REG32(error_config | 0x20, d->hba.base_addr + LBA_ERROR_CONFIG);	\
+    WRITE_REG32(error_config | LBA_SMART_MODE, d->hba.base_addr + LBA_ERROR_CONFIG);	\
 }
 
 
@@ -414,9 +394,9 @@
  *
  *		Actually, there is still a race in which
  *		we could be clearing a fatal error.  We will
- *		live with this during our real mode bus walk
+ *		live with this during our initial bus walk
  *		until rev 4.0 (no driver activity during
- *		real mode bus walk).  The real mode bus walk
+ *		initial bus walk).  The initial bus walk
  *		has race conditions concerning the use of
  *		smart mode as well.
  */
@@ -430,7 +410,7 @@
      * Set clear enable (CE) bit. Unset by HW when new			\
      * errors are logged -- LBA HW ERS section 14.3.3).		\
      */									\
-    WRITE_REG32(status_control | 0x20, base + LBA_STAT_CTL);	\
+    WRITE_REG32(status_control | CLEAR_ERRLOG_ENABLE, base + LBA_STAT_CTL); \
     error_status = READ_REG32(base + LBA_ERROR_STATUS);		\
     if ((error_status & 0x1f) != 0) {					\
 	/*								\
@@ -442,7 +422,7 @@
 	     * Clear error status (if fatal bit not set) by setting	\
 	     * clear error log bit (CL).				\
 	     */								\
-	    WRITE_REG32(status_control | 0x10, base + LBA_STAT_CTL);	\
+	    WRITE_REG32(status_control | CLEAR_ERRLOG, base + LBA_STAT_CTL); \
 	}								\
     }									\
 }
@@ -483,7 +463,7 @@
 
 
 static unsigned int
-lba_rd_cfg( struct lba_device *d, u32 tok, u8 reg, u32 size)
+lba_rd_cfg(struct lba_device *d, u32 tok, u8 reg, u32 size)
 {
 	u32 data = ~0;
 	int error = 0;
@@ -525,7 +505,6 @@
 }
 
 
-
 #define LBA_CFG_RD(size, mask) \
 static int lba_cfg_read##size (struct pci_dev *dev, int pos, u##size *data) \
 { \
@@ -533,17 +512,18 @@
 	u32 local_bus = (dev->bus->parent == NULL) ? 0 : dev->bus->secondary; \
 	u32 tok = LBA_CFG_TOK(local_bus,dev->devfn); \
  \
-	if ((!LBA_TR4PLUS(d)) && (!LBA_SKIP_PROBE(d))) { \
+/* FIXME: B2K/C3600 workaround is always use old method... */ \
+	/* if (!LBA_TR4PLUS(d) && !LBA_SKIP_PROBE(d)) */ { \
 		/* original - Generate config cycle on broken elroy \
 		  with risk we will miss PCI bus errors. */ \
 		*data = (u##size) lba_rd_cfg(d, tok, pos, sizeof(u##size)); \
-		DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, *data); \
+		DBG_CFG("%s(%s+%2x) -> 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, *data); \
 		return(*data == (u##size) -1); \
 	} \
  \
 	if (LBA_SKIP_PROBE(d) && (!lba_device_present(dev->bus->secondary, dev->devfn, d))) \
 	{ \
-		DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> -1 (b)\n", __FUNCTION__, dev->slot_name, pos, *data); \
+		DBG_CFG("%s(%s+%2x) -> -1 (b)\n", __FUNCTION__, dev->slot_name, pos); \
 		/* either don't want to look or know device isn't present. */ \
 		*data = (u##size) -1; \
 		return(0); \
@@ -555,7 +535,7 @@
 	*/ \
 	LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); \
 	*data = READ_REG##size(d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & mask));\
-	DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, *data);\
+	DBG_CFG("%s(%s+%2x) -> 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, *data);\
 	return(*data == (u##size) -1); \
 }
 
@@ -618,19 +598,19 @@
  	ASSERT((tok & 0xff) == 0); \
 	ASSERT(pos < 0x100); \
  \
-	if ((!LBA_TR4PLUS(d)) && (!LBA_SKIP_PROBE(d))) { \
+	if (!LBA_TR4PLUS(d) && !LBA_SKIP_PROBE(d)) { \
 		/* Original Workaround */ \
 		lba_wr_cfg(d, tok, pos, (u32) data, sizeof(u##size)); \
-		DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, data); \
+		DBG_CFG("%s(%s+%2x) = 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, data); \
 		return 0; \
 	} \
  \
 	if (LBA_SKIP_PROBE(d) && (!lba_device_present(dev->bus->secondary, dev->devfn, d))) { \
-		DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (b)\n", __FUNCTION__, dev->slot_name, pos, data); \
+		DBG_CFG("%s(%s+%2x) = 0x%x (b)\n", __FUNCTION__, dev->slot_name, pos, data); \
 		return 1; /* New Workaround */ \
 	} \
  \
-	DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, data); \
+	DBG_CFG("%s(%s+%2x) = 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, data); \
 	/* Basic Algorithm */ \
 	LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); \
 	WRITE_REG##size(data, d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & mask)); \
@@ -644,9 +624,12 @@
 LBA_CFG_WR(32, 0) 
 
 static struct pci_ops lba_cfg_ops = {
-        lba_cfg_read8, lba_cfg_read16, lba_cfg_read32,
-	lba_cfg_write8, lba_cfg_write16, lba_cfg_write32
-
+	read_byte:	lba_cfg_read8,
+	read_word:	lba_cfg_read16,
+	read_dword:	lba_cfg_read32,
+	write_byte:	lba_cfg_write8,
+	write_word:	lba_cfg_write16,
+	write_dword:	lba_cfg_write32
 };
 
 
@@ -654,7 +637,7 @@
 static void
 lba_bios_init(void)
 {
-	DBG(KERN_DEBUG MODULE_NAME ": lba_bios_init\n");
+	DBG(MODULE_NAME ": lba_bios_init\n");
 }
 
 
@@ -712,15 +695,15 @@
 lba_fixup_bus(struct pci_bus *bus)
 {
 	struct list_head *ln;
-        struct pci_dev *dev;
+#ifdef FBB_SUPPORT
 	u16 fbb_enable = PCI_STATUS_FAST_BACK;
 	u16 status;
-	struct lba_device *ldev = LBA_DEV(bus->sysdata);
-#ifdef __LP64__
-	int i;
 #endif
+	struct lba_device *ldev = LBA_DEV(bus->sysdata);
+	int lba_portbase = HBA_PORT_BASE(ldev->hba.hba_num);
+
 	DBG("lba_fixup_bus(0x%p) bus %d sysdata 0x%p\n",
-				bus, bus->secondary, bus->sysdata);
+		bus, bus->secondary, bus->sysdata);
 
 	/*
 	** Properly Setup MMIO resources for this bus.
@@ -731,63 +714,119 @@
 
 		DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n",
 			ldev->hba.io_space.name,
-			ldev->hba.io_space.start,
-			ldev->hba.io_space.end,
+			ldev->hba.io_space.start, ldev->hba.io_space.end,
 			(int) ldev->hba.io_space.flags);
 		DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n",
-			ldev->hba.mem_space.name,
-			ldev->hba.mem_space.start,
-			ldev->hba.mem_space.end,
-			(int) ldev->hba.mem_space.flags);
+			ldev->hba.lmmio_space.name,
+			ldev->hba.lmmio_space.start, ldev->hba.lmmio_space.end,
+			(int) ldev->hba.lmmio_space.flags);
 
 		err = request_resource(&ioport_resource, &(ldev->hba.io_space));
 		if (err < 0) {
 			BUG();
 			lba_dump_res(&ioport_resource, 2);
 		}
-		err = request_resource(&iomem_resource, &(ldev->hba.mem_space));
+		err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space));
 		if (err < 0) {
 			BUG();
 			lba_dump_res(&iomem_resource, 2);
 		}
 
 		bus->resource[0] = &(ldev->hba.io_space);
-		bus->resource[1] = &(ldev->hba.mem_space);
+		bus->resource[1] = &(ldev->hba.lmmio_space);
+	} else {
+		/* KLUGE ALERT!
+		** PCI-PCI Bridge resource munging.
+		** This hack should go away in the near future.
+		** It's based on the Alpha port.
+		*/
+		int i;
+		u16 cmd;
+
+		for (i = 0; i < 4; i++) {
+			bus->resource[i] =
+				&bus->self->resource[PCI_BRIDGE_RESOURCES+i];
+			bus->resource[i]->name = bus->name;
+		}
+#if 0
+		bus->resource[0]->flags |= pci_bridge_check_io(bus->self);
+#else
+		bus->resource[0]->flags |= IORESOURCE_IO;
+#endif
+		bus->resource[1]->flags |= IORESOURCE_MEM;
+		bus->resource[2]->flags = 0;	/* Don't support prefetchable */
+		bus->resource[3]->flags = 0;	/* not used */
+
+		/* 
+		** If the PPB is enabled (ie already configured) then
+		** just read those values.
+		*/
+		(void) lba_cfg_read16(bus->self, PCI_COMMAND, &cmd);
+		if (cmd & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)) {
+			pci_read_bridge_bases(bus);
+		} else {
+			/* Not configured.
+			** For now, propogate HBA limits to the bus;
+			**	PCI will adjust them later.
+			*/
+			bus->resource[0]->end = ldev->hba.io_space.end;
+			bus->resource[1]->end = ldev->hba.lmmio_space.end;
+		}
+
+		/* Turn off downstream PF memory address range by default */
+		bus->resource[2]->start = 1024*1024;
+		bus->resource[2]->end = bus->resource[2]->start - 1;
 	}
 
-	list_for_each(ln, &bus->devices) {
 
-		dev = pci_dev_b(ln);
+	list_for_each(ln, &bus->devices) {
+		int i;
+		struct pci_dev *dev = pci_dev_b(ln);
 
-#ifdef __LP64__
-		/*
-		** 0-5 are the "standard PCI regions"
-		** (see comments near PCI_NUM_RESOURCES in include/linux/pci.h)
-		*/
-		for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
-			struct resource *res = &(dev->resource[i]);
+		DBG("lba_fixup_bus() %s\n", dev->name);
 
-			if (res->flags & IORESOURCE_MEM) {
-				/* "Globalize" PCI address */
-				res->start |= ldev->lmmio_base;
-				res->end   |= ldev->lmmio_base;
+		/* Virtualize Device/Bridge Resources. */
+		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+			struct resource *res = &dev->resource[i];
+
+			/* If resource not allocated - skip it */
+			if (!res->start)
+				continue;
+
+			if (res->flags & IORESOURCE_IO) {
+				DBG("lba_fixup_bus() I/O Ports [%lx/%lx] -> ",
+					res->start, res->end);
+				res->start |= lba_portbase;
+				res->end   |= lba_portbase;
+				DBG("[%lx/%lx]\n", res->start, res->end);
+			} else if (res->flags & IORESOURCE_MEM) {
+				/*
+				** Convert PCI (IO_VIEW) addresses to
+				** processor (PA_VIEW) addresses
+				 */
+				DBG("lba_fixup_bus() MMIO [%lx/%lx] -> ",
+					res->start, res->end);
+				res->start = PCI_HOST_ADDR(HBA_DATA(ldev), res->start);
+				res->end   = PCI_HOST_ADDR(HBA_DATA(ldev), res->end);
+				DBG("[%lx/%lx]\n", res->start, res->end);
 			}
 		}
-#endif
 
+#ifdef FBB_SUPPORT
 		/*
 		** If one device does not support FBB transfers,
 		** No one on the bus can be allowed to use them.
 		*/
 		(void) lba_cfg_read16(dev, PCI_STATUS, &status);
 		fbb_enable &= status;
+#endif
 
 #ifdef __LP64__
-		if (pdc_pat) {
+		if (is_pdc_pat()) {
 			/* Claim resources for PDC's devices */
 			lba_claim_dev_resources(dev);
 		}
-#endif	/* __LP64__ */
+#endif
 
                 /*
 		** P2PB's have no IRQs. ignore them.
@@ -796,12 +835,12 @@
 			continue;
 
 		/* Adjust INTERRUPT_LINE for this dev */
-		iosapic_fixup_irq(LBA_DEV(bus->sysdata)->iosapic_obj, dev);
+		iosapic_fixup_irq(ldev->iosapic_obj, dev);
 	}
 
-#if 0
+#ifdef FBB_SUPPORT
 /* FIXME/REVISIT - finish figuring out to set FBB on both
-** pbus_set_ranges() clobbers PCI_BRIDGE_CONTROL.
+** pci_setup_bridge() clobbers PCI_BRIDGE_CONTROL.
 ** Can't fixup here anyway....garr...
 */
 	if (fbb_enable) {
@@ -828,8 +867,8 @@
 
 
 struct pci_bios_ops lba_bios_ops = {
-	lba_bios_init,
-	lba_fixup_bus  /* void lba_fixup_bus(struct pci_bus *bus) */
+	init:		lba_bios_init,
+	fixup_bus:	lba_fixup_bus,
 };
 
 
@@ -853,8 +892,6 @@
 static u##size lba_astro_in##size (struct pci_hba_data *d, u16 addr) \
 { \
 	u##size t; \
-	ASSERT(bus != NULL); \
-	DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x) ->", __FUNCTION__, bus, addr); \
 	t = READ_REG##size(LBA_ASTRO_PORT_BASE + addr); \
 	DBG_PORT(" 0x%x\n", t); \
 	return (t); \
@@ -895,8 +932,8 @@
 #define LBA_PORT_OUT(size, mask) \
 static void lba_astro_out##size (struct pci_hba_data *d, u16 addr, u##size val) \
 { \
-	ASSERT(bus != NULL); \
-	DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, d, addr, val); \
+	ASSERT(d != NULL); \
+	DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, d, addr, val); \
 	WRITE_REG##size(val, LBA_ASTRO_PORT_BASE + addr); \
 	if (LBA_DEV(d)->hw_rev < 3) \
 		lba_t32 = READ_U32(d->base_addr + LBA_FUNC_ID); \
@@ -908,13 +945,16 @@
 
 
 static struct pci_port_ops lba_astro_port_ops = {
-	lba_astro_in8, lba_astro_in16, lba_astro_in32,
-	lba_astro_out8, lba_astro_out16, lba_astro_out32
+	inb:	lba_astro_in8,
+	inw:	lba_astro_in16,
+	inl:	lba_astro_in32,
+	outb:	lba_astro_out8,
+	outw:	lba_astro_out16,
+	outl:	lba_astro_out32
 };
 
 
 #ifdef __LP64__
-
 #define PIOP_TO_GMMIO(lba, addr) \
 	((lba)->iop_base + (((addr)&0xFFFC)<<10) + ((addr)&3))
 
@@ -936,7 +976,7 @@
 { \
 	u##size t; \
 	ASSERT(bus != NULL); \
-	DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x) ->", __FUNCTION__, l, addr); \
+	DBG_PORT("%s(0x%p, 0x%x) ->", __FUNCTION__, l, addr); \
 	t = READ_REG##size(PIOP_TO_GMMIO(LBA_DEV(l), addr)); \
 	DBG_PORT(" 0x%x\n", t); \
 	return (t); \
@@ -953,7 +993,7 @@
 { \
 	void *where = (void *) PIOP_TO_GMMIO(LBA_DEV(l), addr); \
 	ASSERT(bus != NULL); \
-	DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \
+	DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \
 	WRITE_REG##size(val, where); \
 	/* flush the I/O down to the elroy at least */ \
 	lba_t32 = READ_U32(l->base_addr + LBA_FUNC_ID); \
@@ -965,8 +1005,12 @@
 
 
 static struct pci_port_ops lba_pat_port_ops = {
-	lba_pat_in8, lba_pat_in16, lba_pat_in32,
-	lba_pat_out8, lba_pat_out16, lba_pat_out32
+	inb:	lba_pat_in8,
+	inw:	lba_pat_in16,
+	inl:	lba_pat_in32,
+	outb:	lba_pat_out8,
+	outw:	lba_pat_out16,
+	outl:	lba_pat_out32
 };
 
 
@@ -978,30 +1022,27 @@
 ** We don't have a struct pci_bus assigned to us yet.
 */
 static void
-lba_pat_resources( struct hp_device *d, struct lba_device *lba_dev)
+lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
 {
+	unsigned long bytecnt;
 	pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;	/* PA_VIEW */
-#ifdef DONT_NEED_THIS_FOR_ASTRO
 	pdc_pat_cell_mod_maddr_block_t io_pdc_cell;	/* IO_VIEW */
 	long io_count;
-#endif
 	long status;	/* PDC return status */
 	long pa_count;
 	int i;
 
 	/* return cell module (IO view) */
-	status = pdc_pat_cell_module(& pdc_result, d->pcell_loc, d->mod_index,
+	status = pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index,
 				PA_VIEW, & pa_pdc_cell);
 	pa_count = pa_pdc_cell.mod[1];
 
-#ifdef DONT_NEED_THIS_FOR_ASTRO
-	status |= pdc_pat_cell_module(& pdc_result, d->pcell_loc, d->mod_index,
-				IO_VIEW, & io_pdc_cell);
+	status |= pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index,
+				IO_VIEW, &io_pdc_cell);
 	io_count = io_pdc_cell.mod[1];
-#endif
 
 	/* We've already done this once for device discovery...*/
-	if (status != PDC_RET_OK) {
+	if (status != PDC_OK) {
 		panic("pdc_pat_cell_module() call failed for LBA!\n");
 	}
 
@@ -1017,10 +1058,11 @@
 			unsigned long type;
 			unsigned long start;
 			unsigned long end;	/* aka finish */
-		} *p;
+		} *p, *io;
 		struct resource *r;
 
 		p = (void *) &(pa_pdc_cell.mod[2+i*3]);
+		io = (void *) &(io_pdc_cell.mod[2+i*3]);
 
 		/* Convert the PAT range data to PCI "struct resource" */
 		switch(p->type & 0xff) {
@@ -1030,9 +1072,9 @@
 			break;
 		case PAT_LMMIO:
 			/* used to fix up pre-initialized MEM BARs */
-			lba_dev->lmmio_base = p->start;
+			lba_dev->hba.lmmio_space_offset = p->start - io->start;
 
-			r = &(lba_dev->hba.mem_space);
+			r = &(lba_dev->hba.lmmio_space);
 			r->name   = "LBA LMMIO";
 			r->start  = p->start;
 			r->end    = p->end;
@@ -1060,8 +1102,8 @@
 
 			r = &(lba_dev->hba.io_space);
 			r->name   = "LBA I/O Port";
-			r->start = lba_dev->hba.hba_num << 16;
-			r->end   = r->start + 0xffffUL;
+			r->start  = HBA_PORT_BASE(lba_dev->hba.hba_num);
+			r->end    = r->start + HBA_PORT_SPACE_SIZE - 1;
 			r->flags  = IORESOURCE_IO;
 			r->parent = r->sibling = r->child = NULL;
 			break;
@@ -1077,17 +1119,22 @@
 
 
 static void
-lba_legacy_resources( struct hp_device *d, struct lba_device *lba_dev)
+lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
 {
-	int lba_num;
 	struct resource *r;
+	unsigned long rsize;
+	int lba_num;
+
 #ifdef __LP64__
 	/*
-	** Used to sign extend instead BAR values are only 32-bit.
-	** 64-bit BARs have the upper 32-bit's zero'd by firmware.
-	** "Sprockets" PDC initializes for 32-bit OS.
+	** Sign extend all BAR values on "legacy" platforms.
+	** "Sprockets" PDC (Forte/Allegro) initializes everything
+	** for "legacy" 32-bit OS (HPUX 10.20).
+	** Upper 32-bits of 64-bit BAR will be zero too.
 	*/
-	lba_dev->lmmio_base = 0xffffffff00000000UL;
+	lba_dev->hba.lmmio_space_offset = 0xffffffff00000000UL;
+#else
+	lba_dev->hba.lmmio_space_offset = 0UL;
 #endif
 
 	/*
@@ -1097,7 +1144,7 @@
 	** PCI bus walk *should* end up with the same result.
 	** FIXME: But we don't have sanity checks in PCI or LBA.
 	*/
-	lba_num = READ_REG32(d->hpa + LBA_FW_SCRATCH);
+	lba_num = READ_REG32(pa_dev->hpa + LBA_FW_SCRATCH);
 	r = &(lba_dev->hba.bus_num);
 	r->name = "LBA PCI Busses";
 	r->start = lba_num & 0xff;
@@ -1106,19 +1153,67 @@
 	/* Set up local PCI Bus resources - we don't really need
 	** them for Legacy boxes but it's nice to see in /proc.
 	*/
-	r = &(lba_dev->hba.mem_space);
+	r = &(lba_dev->hba.lmmio_space);
 	r->name  = "LBA PCI LMMIO";
 	r->flags = IORESOURCE_MEM;
-	r->start = READ_REG32(d->hpa + LBA_LMMIO_BASE);
-	r->end   = r->start + ~ (READ_REG32(d->hpa + LBA_LMMIO_MASK));
+	/* Ignore "Range Enable" bit in the BASE register */
+	r->start = PCI_HOST_ADDR(HBA_DATA(lba_dev),
+		((long) READ_REG32(pa_dev->hpa + LBA_LMMIO_BASE)) & ~1UL);
+	rsize =  ~READ_REG32(pa_dev->hpa + LBA_LMMIO_MASK) + 1;
+
+	/*
+	** Each rope only gets part of the distributed range.
+	** Adjust "window" for this rope
+	*/
+	rsize /= ROPES_PER_SBA;
+	r->start += rsize * LBA_NUM(pa_dev->hpa);
+	r->end = r->start + rsize - 1 ;
+
+	/*
+	** XXX FIXME - ignore LBA_ELMMIO_BASE for now
+	** "Directed" ranges are used when the "distributed range" isn't
+	** sufficient for all devices below a given LBA.  Typically devices
+	** like graphics cards or X25 may need a directed range when the
+	** bus has multiple slots (ie multiple devices) or the device
+	** needs more than the typical 4 or 8MB a distributed range offers.
+	**
+	** The main reason for ignoring it now frigging complications.
+	** Directed ranges may overlap (and have precedence) over
+	** distributed ranges. Ie a distributed range assigned to a unused
+	** rope may be used by a directed range on a different rope.
+	** Support for graphics devices may require fixing this
+	** since they may be assigned a directed range which overlaps
+	** an existing (but unused portion of) distributed range.
+	*/
+	r = &(lba_dev->hba.elmmio_space);
+	r->name  = "extra LBA PCI LMMIO";
+	r->flags = IORESOURCE_MEM;
+	r->start = READ_REG32(pa_dev->hpa + LBA_ELMMIO_BASE);
+	r->end   = 0;
+
+	/* check Range Enable bit */
+	if (r->start & 1) {
+		/* First baby step to getting Direct Ranges listed in /proc.
+		** AFAIK, only Sprockets PDC will setup a directed Range.
+		*/
+
+		r->start &= ~1;
+		r->end    = r->start;
+		r->end   += ~READ_REG32(pa_dev->hpa + LBA_ELMMIO_MASK);
+		printk(KERN_DEBUG "WARNING: Ignoring enabled ELMMIO BASE 0x%0lx  SIZE 0x%lx\n",
+			r->start,
+			r->end + 1);
+
+	}
 
 	r = &(lba_dev->hba.io_space);
 	r->name  = "LBA PCI I/O Ports";
 	r->flags = IORESOURCE_IO;
-	r->start = READ_REG32(d->hpa + LBA_IOS_BASE);
-	r->end   = r->start + (READ_REG32(d->hpa + LBA_IOS_MASK) ^ 0xffff);
+	r->start = READ_REG32(pa_dev->hpa + LBA_IOS_BASE) & ~1L;
+	r->end   = r->start + (READ_REG32(pa_dev->hpa + LBA_IOS_MASK) ^ (HBA_PORT_SPACE_SIZE - 1));
 
-	lba_num = lba_dev->hba.hba_num << 16;
+	/* Virtualize the I/O Port space ranges */
+	lba_num = HBA_PORT_BASE(lba_dev->hba.hba_num);
 	r->start |= lba_num;
 	r->end   |= lba_num;
 }
@@ -1136,29 +1231,92 @@
 **
 **************************************************************************/
 
-static void
+static int __init
 lba_hw_init(struct lba_device *d)
 {
 	u32 stat;
+	u32 bus_reset;	/* PDC_PAT_BUG */
+
+#if 0
+	printk(KERN_DEBUG "LBA %lx  STAT_CTL %Lx  ERROR_CFG %Lx  STATUS %Lx DMA_CTL %Lx\n",
+		d->hba.base_addr,
+		READ_REG64(d->hba.base_addr + LBA_STAT_CTL),
+		READ_REG64(d->hba.base_addr + LBA_ERROR_CONFIG),
+		READ_REG64(d->hba.base_addr + LBA_ERROR_STATUS),
+		READ_REG64(d->hba.base_addr + LBA_DMA_CTL) );
+	printk(KERN_DEBUG "	ARB mask %Lx  pri %Lx  mode %Lx  mtlt %Lx\n",
+		READ_REG64(d->hba.base_addr + LBA_ARB_MASK),
+		READ_REG64(d->hba.base_addr + LBA_ARB_PRI),
+		READ_REG64(d->hba.base_addr + LBA_ARB_MODE),
+		READ_REG64(d->hba.base_addr + LBA_ARB_MTLT) );
+	printk(KERN_DEBUG "	HINT cfg 0x%Lx\n",
+		READ_REG64(d->hba.base_addr + LBA_HINT_CFG));
+	printk(KERN_DEBUG "	HINT reg ");
+	{ int i;
+	for (i=LBA_HINT_BASE; i< (14*8 + LBA_HINT_BASE); i+=8)
+		printk(" %Lx", READ_REG64(d->hba.base_addr + i));
+	}
+	printk("\n");
+#endif	/* DEBUG_LBA_PAT */
+
+#ifdef __LP64__
+#warning FIXME add support for PDC_PAT_IO "Get slot status" - OLAR support
+#endif
+
+	/* PDC_PAT_BUG: exhibited in rev 40.48  on L2000 */
+	bus_reset = READ_REG32(d->hba.base_addr + LBA_STAT_CTL + 4) & 1;
+	if (bus_reset) {
+		printk(KERN_DEBUG "NOTICE: PCI bus reset still asserted! (clearing)\n");
+	}
+
+	stat = READ_REG32(d->hba.base_addr + LBA_ERROR_CONFIG);
+	if (stat & LBA_SMART_MODE) {
+		printk(KERN_DEBUG "NOTICE: LBA in SMART mode! (cleared)\n");
+		stat &= ~LBA_SMART_MODE;
+		WRITE_REG32(stat, d->hba.base_addr + LBA_ERROR_CONFIG);
+	}
 
 	/* Set HF mode as the default (vs. -1 mode). */
         stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL);
 	WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL);
 
 	/*
+	** Writing a zero to STAT_CTL.rf (bit 0) will clear reset signal
+	** if it's not already set. If we just cleared the PCI Bus Reset
+	** signal, wait a bit for the PCI devices to recover and setup.
+	*/
+	if (bus_reset)
+		mdelay(pci_post_reset_delay);
+
+	if (0 == READ_REG32(d->hba.base_addr + LBA_ARB_MASK)) {
+		/*
+		** PDC_PAT_BUG: PDC rev 40.48 on L2000.
+		** B2000/C3600/J6000 also have this problem?
+		** 
+		** Elroys with hot pluggable slots don't get configured
+		** correctly if the slot is empty.  ARB_MASK is set to 0
+		** and we can't master transactions on the bus if it's
+		** not at least one. 0x3 enables elroy and first slot.
+		*/
+		printk(KERN_DEBUG "NOTICE: Enabling PCI Arbitration\n");
+		WRITE_REG32(0x3, d->hba.base_addr + LBA_ARB_MASK);
+	}
+
+	/*
 	** FIXME: Hint registers are programmed with default hint
 	** values by firmware. Hints should be sane even if we
 	** can't reprogram them the way drivers want.
 	*/
+	return 0;
 }
 
 
 
-static void
+static void __init
 lba_common_init(struct lba_device *lba_dev)
 {
 	pci_bios = &lba_bios_ops;
-	pcibios_register_hba((struct pci_hba_data *)lba_dev);
+	pcibios_register_hba(HBA_DATA(lba_dev));
 	lba_dev->lba_lock = SPIN_LOCK_UNLOCKED;	
 
 	/*
@@ -1176,32 +1334,31 @@
 ** If so, initialize the chip and tell other partners in crime they
 ** have work to do.
 */
-static __init int
-lba_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+static int __init
+lba_driver_callback(struct parisc_device *dev)
 {
 	struct lba_device *lba_dev;
 	struct pci_bus *lba_bus;
 	u32 func_class;
 	void *tmp_obj;
-
-	/* from drivers/pci/setup-bus.c */
-	extern void __init pbus_set_ranges(struct pci_bus *, struct pbus_set_ranges_data *);
+	char *version;
 
 	/* Read HW Rev First */
-	func_class = READ_REG32(d->hpa + LBA_FCLASS);
+	func_class = READ_REG32(dev->hpa + LBA_FCLASS);
 	func_class &= 0xf;
 
 	switch (func_class) {
-	case 0:	dri->version = "TR1.0"; break;
-	case 1:	dri->version = "TR2.0"; break;
-	case 2:	dri->version = "TR2.1"; break;
-	case 3:	dri->version = "TR2.2"; break;
-	case 4:	dri->version = "TR3.0"; break;
-	case 5:	dri->version = "TR4.0"; break;
-	default: dri->version = "TR4+";
+	case 0:	version = "TR1.0"; break;
+	case 1:	version = "TR2.0"; break;
+	case 2:	version = "TR2.1"; break;
+	case 3:	version = "TR2.2"; break;
+	case 4:	version = "TR3.0"; break;
+	case 5:	version = "TR4.0"; break;
+	default: version = "TR4+";
 	}
 
-	printk("%s version %s (0x%x) found at 0x%p\n", dri->name, dri->version, func_class & 0xf, d->hpa);
+	printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n",
+		MODULE_NAME, version, func_class & 0xf, dev->hpa);
 
 	/* Just in case we find some prototypes... */
 	if (func_class < 2) {
@@ -1212,22 +1369,16 @@
 	/*
 	** Tell I/O SAPIC driver we have a IRQ handler/region.
 	*/
-	tmp_obj = iosapic_register(d->hpa+LBA_IOSAPIC_BASE);
-	if (NULL == tmp_obj) {
-		/* iosapic may have failed. But more likely the
-		** slot isn't occupied and thus has no IRT entries.
-		** iosapic_register looks for this iosapic in the IRT
-		** before bothering to allocating data structures
-		** we don't need.
-		*/
-		DBG(KERN_WARNING MODULE_NAME ": iosapic_register says not used\n");
-		return (1);
-	}
+	tmp_obj = iosapic_register(dev->hpa + LBA_IOSAPIC_BASE);
 
+	/* NOTE: PCI devices (e.g. 103c:1005 graphics card) which don't
+	**	have an IRT entry will get NULL back from iosapic code.
+	*/
+	
 	lba_dev = kmalloc(sizeof(struct lba_device), GFP_KERNEL);
 	if (NULL == lba_dev)
 	{
-		printk("lba_init_chip - couldn't alloc lba_device\n");
+		printk(KERN_ERR "lba_init_chip - couldn't alloc lba_device\n");
 		return(1);
 	}
 
@@ -1242,48 +1393,45 @@
 	*/
 	lba_dev->hw_rev = func_class;
 
-	lba_dev->hba.base_addr = d->hpa;  /* faster access */
+	lba_dev->hba.base_addr = dev->hpa;  /* faster access */
+	lba_dev->hba.dev = dev;
 	lba_dev->iosapic_obj = tmp_obj;  /* save interrupt handle */
+	lba_dev->hba.iommu = sba_get_iommu(dev);  /* get iommu data */
 
 	/* ------------ Second : initialize common stuff ---------- */
 	lba_common_init(lba_dev);
-	lba_hw_init(lba_dev);
+
+	if (lba_hw_init(lba_dev))
+		return(1);
 
 	/* ---------- Third : setup I/O Port and MMIO resources  --------- */
-#ifdef __LP64__
 
-	if (pdc_pat) {
+#ifdef __LP64__
+	if (is_pdc_pat()) {
 		/* PDC PAT firmware uses PIOP region of GMMIO space. */
 		pci_port = &lba_pat_port_ops;
 
 		/* Go ask PDC PAT what resources this LBA has */
-		lba_pat_resources(d, lba_dev);
-
-	} else {
+		lba_pat_resources(dev, lba_dev);
+	} else
 #endif
+	{
 		/* Sprockets PDC uses NPIOP region */
 		pci_port = &lba_astro_port_ops;
 
 		/* Poke the chip a bit for /proc output */
-		lba_legacy_resources(d, lba_dev);
-#ifdef __LP64__
+		lba_legacy_resources(dev, lba_dev);
 	}
-#endif
 
 	/* 
 	** Tell PCI support another PCI bus was found.
 	** Walks PCI bus for us too.
 	*/
 	lba_bus = lba_dev->hba.hba_bus =
-		pci_scan_bus( lba_dev->hba.bus_num.start, &lba_cfg_ops, (void *) lba_dev);
+		pci_scan_bus(lba_dev->hba.bus_num.start, &lba_cfg_ops, (void *) lba_dev);
 
 #ifdef __LP64__
-	if (pdc_pat) {
-
-		/* determine window sizes needed by PCI-PCI bridges */
-		DBG_PAT("LBA pcibios_size_bridge()\n");
-		pcibios_size_bridge(lba_bus, NULL);
-
+	if (is_pdc_pat()) {
 		/* assign resources to un-initialized devices */
 		DBG_PAT("LBA pcibios_assign_unassigned_resources()\n");
 		pcibios_assign_unassigned_resources(lba_bus);
@@ -1292,14 +1440,10 @@
 		DBG_PAT("\nLBA PIOP resource tree\n");
 		lba_dump_res(&lba_dev->hba.io_space, 2);
 		DBG_PAT("\nLBA LMMIO resource tree\n");
-		lba_dump_res(&lba_dev->hba.mem_space, 2);
+		lba_dump_res(&lba_dev->hba.lmmio_space, 2);
 #endif
-
-		/* program *all* PCI-PCI bridge range registers */
-		DBG_PAT("LBA pbus_set_ranges()\n");
-		pbus_set_ranges(lba_bus, NULL);
 	}
-#endif /* __LP64__ */
+#endif
 
 	/*
 	** Once PCI register ops has walked the bus, access to config
@@ -1314,33 +1458,43 @@
 	return 0;
 }
 
+static struct parisc_device_id lba_tbl[] = {
+	{ HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x782, 0xa },
+	{ 0, }
+};
+
+static struct parisc_driver lba_driver = {
+	name:		MODULE_NAME,
+	id_table:	lba_tbl,
+	probe:		lba_driver_callback
+};
+
+/*
+** One time initialization to let the world know the LBA was found.
+** Must be called exactly once before pci_init().
+*/
+void __init lba_init(void)
+{
+	register_parisc_driver(&lba_driver);
+}
 
 /*
 ** Initialize the IBASE/IMASK registers for LBA (Elroy).
-** Only called from sba_iommu.c initialization sequence.
+** Only called from sba_iommu.c in order to route ranges (MMIO vs DMA).
+** sba_iommu is responsible for locking (none needed at init time).
 */
-void lba_init_iregs(void *sba_hpa, u32 ibase, u32 imask)
+void
+lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask)
 {
-	extern struct pci_hba_data *hba_list;	/* arch/parisc/kernel/pci.c */
-	struct pci_hba_data *lba;
+	unsigned long base_addr = lba->hpa;
 
 	imask <<= 2;	/* adjust for hints - 2 more bits */
 
 	ASSERT((ibase & 0x003fffff) == 0);
 	ASSERT((imask & 0x003fffff) == 0);
 	
-	/* FIXME: sba_hpa is intended to search some table to
-	**      determine which LBA's belong to the caller's SBA.
-	** IS_ASTRO: just assume only one SBA for now.
-	*/
-	ASSERT(NULL != hba_list);
-	DBG(KERN_DEBUG "%s() ibase 0x%x imask 0x%x\n", __FUNCTION__, ibase, imask);
-
-	for (lba = hba_list; NULL != lba; lba = lba->next) {
-		DBG(KERN_DEBUG "%s() base_addr %p\n", __FUNCTION__, lba->base_addr);
-		WRITE_REG32( imask, lba->base_addr + LBA_IMASK);
-		WRITE_REG32( ibase, lba->base_addr + LBA_IBASE);
-	}
-	DBG(KERN_DEBUG "%s() done\n", __FUNCTION__);
+	DBG("%s() ibase 0x%x imask 0x%x\n", __FUNCTION__, ibase, imask);
+	WRITE_REG32( imask, base_addr + LBA_IMASK);
+	WRITE_REG32( ibase, base_addr + LBA_IBASE);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/led.c linux-2.4.20/arch/parisc/kernel/led.c
--- linux-2.4.19/arch/parisc/kernel/led.c	2000-12-06 19:46:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/led.c	2002-10-29 11:18:36.000000000 +0000
@@ -3,34 +3,64 @@
  *
  *      (c) Copyright 2000 Red Hat Software
  *      (c) Copyright 2000 Helge Deller <hdeller@redhat.com>
+ *      (c) Copyright 2001-2002 Helge Deller <deller@gmx.de>
+ *      (c) Copyright 2001 Randolph Chung <tausq@debian.org>
  *
  *      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.
  *
+ * TODO:
+ *	- speed-up calculations with inlined assembler
+ *	- interface to write to second row of LCD from /proc
  */
 
 #include <linux/config.h>
+#include <linux/module.h>
+#include <linux/stddef.h>	/* for offsetof() */
 #include <linux/init.h>
-#include <linux/kernel_stat.h>
 #include <linux/types.h>
-#include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/bitops.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/reboot.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
 #include <asm/io.h>
 #include <asm/gsc.h>
 #include <asm/processor.h>
 #include <asm/hardware.h>
 #include <asm/param.h>		/* HZ */
 #include <asm/led.h>
+#include <asm/pdc.h>
+#include <asm/uaccess.h>
 
+/* The control of the LEDs and LCDs on PARISC-machines have to be done 
+   completely in software. The necessary calculations are done in a tasklet
+   which is scheduled at every timer interrupt and since the calculations 
+   may consume relatively much CPU-time some of the calculations can be 
+   turned off with the following variables (controlled via procfs) */
+
+static int led_type = -1;
+static int led_heartbeat = 1;
+static int led_diskio = 1;
+static int led_lanrxtx = 1;
+static char lcd_text[32];
 
-/* define to disable all LED functions */
-#undef  DISABLE_LEDS
+#if 0
+#define DPRINTK(x)	printk x
+#else
+#define DPRINTK(x)
+#endif
 
 
-#define CPU_HVERSION ((boot_cpu_data.hversion >> 4) & 0x0FFF)
+#define CALC_ADD(val, comp, add) \
+ (val<=(comp/8) ? add/16 : val<=(comp/4) ? add/8 : val<=(comp/2) ? add/4 : add)
 
 
 struct lcd_block {
@@ -40,8 +70,10 @@
 };
 
 /* Structure returned by PDC_RETURN_CHASSIS_INFO */
+/* NOTE: we use unsigned long:16 two times, since the following member 
+   lcd_cmd_reg_addr needs to be 64bit aligned on 64bit PA2.0-machines */
 struct pdc_chassis_lcd_info_ret_block {
-	unsigned long model:16;		/* DISPLAY_MODEL_XXXX (see below)  */
+	unsigned long model:16;		/* DISPLAY_MODEL_XXXX */
 	unsigned long lcd_width:16;	/* width of the LCD in chars (DISPLAY_MODEL_LCD only) */
 	char *lcd_cmd_reg_addr;		/* ptr to LCD cmd-register & data ptr for LED */
 	char *lcd_data_reg_addr;	/* ptr to LCD data-register (LCD only) */
@@ -56,33 +88,23 @@
 	char _pad;
 };
 
-/* values for pdc_chassis_lcd_info_ret_block.model: */
-#define DISPLAY_MODEL_LCD  0	/* KittyHawk LED or LCD */
-#define DISPLAY_MODEL_NONE 1	/* no LED or LCD */
-#define DISPLAY_MODEL_LASI 2	/* LASI style 8 bit LED */
-#define DISPLAY_MODEL_OLD_ASP 0x7F /* faked: ASP style 8 x 1 bit LED (only very old ASP versions) */
-
 
 /* LCD_CMD and LCD_DATA for KittyHawk machines */
-#ifdef __LP64__
-#define KITTYHAWK_LCD_CMD 0xfffffffff0190000L
-#else
-#define KITTYHAWK_LCD_CMD 0xf0190000
-#endif
-#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD + 1)
+#define KITTYHAWK_LCD_CMD  (0xfffffffff0190000UL) /* 64bit-ready */
+#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD+1)
 
-
-/* lcd_info is pre-initialized to the values needed to program KittyHawk LCD's */
+/* lcd_info is pre-initialized to the values needed to program KittyHawk LCD's 
+ * HP seems to have used Sharp/Hitachi HD44780 LCDs most of the time. */
 static struct pdc_chassis_lcd_info_ret_block
 lcd_info __attribute__((aligned(8))) =
 {
-      model:DISPLAY_MODEL_LCD,
-      lcd_width:16,
-      lcd_cmd_reg_addr:(char *) KITTYHAWK_LCD_CMD,
+      model:		DISPLAY_MODEL_LCD,
+      lcd_width:	16,
+      lcd_cmd_reg_addr:	(char *) KITTYHAWK_LCD_CMD,
       lcd_data_reg_addr:(char *) KITTYHAWK_LCD_DATA,
-      min_cmd_delay:40,
-      reset_cmd1:0x80,
-      reset_cmd2:0xc0,
+      min_cmd_delay:	40,
+      reset_cmd1:	0x80,
+      reset_cmd2:	0xc0,
 };
 
 
@@ -92,7 +114,143 @@
 #define LED_DATA_REG	lcd_info.lcd_cmd_reg_addr	/* LASI & ASP only */
 
 
+/* ptr to LCD/LED-specific function */
+static void (*led_func_ptr) (unsigned char);
+
+#define LED_HASLCD 1
+#define LED_NOLCD  0
+#ifdef CONFIG_PROC_FS
+static int led_proc_read(char *page, char **start, off_t off, int count, 
+	int *eof, void *data)
+{
+	char *out = page;
+	int len;
+
+	switch ((long)data)
+	{
+	case LED_NOLCD:
+		out += sprintf(out, "Heartbeat: %d\n", led_heartbeat);
+		out += sprintf(out, "Disk IO: %d\n", led_diskio);
+		out += sprintf(out, "LAN Rx/Tx: %d\n", led_lanrxtx);
+		break;
+	case LED_HASLCD:
+		out += sprintf(out, "%s\n", lcd_text);
+		break;
+	default:
+		*eof = 1;
+		return 0;
+	}
+
+	len = out - page - off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0) return 0;
+	} else {
+		len = count;
+	}
+	*start = page + off;
+	return len;
+}
+
+static int led_proc_write(struct file *file, const char *buf, 
+	unsigned long count, void *data)
+{
+	char *cur, lbuf[count];
+	int d;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	memset(lbuf, 0, count);
+
+	copy_from_user(lbuf, buf, count);
+	cur = lbuf;
+
+	/* skip initial spaces */
+	while (*cur && isspace(*cur))
+	{
+		cur++;
+	}
+
+	switch ((long)data)
+	{
+	case LED_NOLCD:
+		d = *cur++ - '0';
+		if (d != 0 && d != 1) goto parse_error;
+		led_heartbeat = d;
+
+		if (*cur++ != ' ') goto parse_error;
+
+		d = *cur++ - '0';
+		if (d != 0 && d != 1) goto parse_error;
+		led_diskio = d;
+
+		if (*cur++ != ' ') goto parse_error;
+
+		d = *cur++ - '0';
+		if (d != 0 && d != 1) goto parse_error;
+		led_lanrxtx = d;
+
+		break;
+	case LED_HASLCD:
+		if (*cur == 0) 
+		{
+			/* reset to default */
+			lcd_print("Linux " UTS_RELEASE);
+		}
+		else
+		{
+			/* chop off trailing \n.. if the user gives multiple
+			 * \n then it's all their fault.. */
+			if (*cur && cur[strlen(cur)-1] == '\n')
+				cur[strlen(cur)-1] = 0;
+			lcd_print(cur);
+		}
+		break;
+	default:
+		return 0;
+	}
+	
+	return count;
+
+parse_error:
+	if ((long)data == LED_NOLCD)
+		printk(KERN_CRIT "Parse error: expect \"n n n\" (n == 0 or 1) for heartbeat,\ndisk io and lan tx/rx indicators\n");
+	return -EINVAL;
+}
+
+static int __init led_create_procfs(void)
+{
+	struct proc_dir_entry *proc_pdc_root = NULL;
+	struct proc_dir_entry *ent;
+
+	if (led_type == -1) return -1;
+
+	proc_pdc_root = proc_mkdir("pdc", 0);
+	if (!proc_pdc_root) return -1;
+	proc_pdc_root->owner = THIS_MODULE;
+	ent = create_proc_entry("led", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root);
+	if (!ent) return -1;
+	ent->nlink = 1;
+	ent->data = (void *)LED_NOLCD; /* LED */
+	ent->read_proc = led_proc_read;
+	ent->write_proc = led_proc_write;
+	ent->owner = THIS_MODULE;
+
+	if (led_type == LED_HASLCD)
+	{
+		ent = create_proc_entry("lcd", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root);
+		if (!ent) return -1;
+		ent->nlink = 1;
+		ent->data = (void *)LED_HASLCD; /* LCD */
+		ent->read_proc = led_proc_read;
+		ent->write_proc = led_proc_write;
+		ent->owner = THIS_MODULE;
+	}
 
+	return 0;
+}
+#endif
 
 /*
    ** 
@@ -132,24 +290,20 @@
    ** 
    ** led_LCD_driver()
    ** 
-   ** The logic of the LCD driver is, that we write at every interrupt
+   ** The logic of the LCD driver is, that we write at every scheduled call
    ** only to one of LCD_CMD_REG _or_ LCD_DATA_REG - registers.
-   ** That way we don't need to let this interrupt routine busywait
-   ** the "min_cmd_delay", since idlewaiting in an interrupt-routine is
-   ** allways a BAD IDEA !
+   ** That way we don't need to let this tasklet busywait for min_cmd_delay
+   ** milliseconds.
    **
    ** TODO: check the value of "min_cmd_delay" against the value of HZ.
    **   
  */
-
 static void led_LCD_driver(unsigned char leds)
 {
 	static int last_index;	/* 0:heartbeat, 1:disk, 2:lan_in, 3:lan_out */
 	static int last_was_cmd;/* 0: CMD was written last, 1: DATA was last */
 	struct lcd_block *block_ptr;
 	int value;
-	
- 	// leds = ~leds;	/* needed ? */ 
 
 	switch (last_index) {
 	    case 0:	block_ptr = &lcd_info.heartbeat;
@@ -165,7 +319,6 @@
 			value = leds & LED_LAN_TX;
 			break;
 	    default:	/* should never happen: */
-			BUG();
 			return;
 	}
 
@@ -178,179 +331,293 @@
 	}    
 	
 	/* now update the vars for the next interrupt iteration */ 
-	if (++last_was_cmd == 2) {
+	if (++last_was_cmd == 2) { /* switch between cmd & data */
 	    last_was_cmd = 0;
-	    if (++last_index == 4)
-		last_index = 0;
+	    if (++last_index == 4) 
+		last_index = 0;	 /* switch back to heartbeat index */
 	}
 }
 
 
+/*
+   ** 
+   ** led_get_net_stats()
+   ** 
+   ** calculate the TX- & RX-troughput on the network interfaces in
+   ** the system for usage in the LED code
+   **
+   ** (analog to dev_get_info() from net/core/dev.c)
+   **   
+ */
+static unsigned long led_net_rx_counter, led_net_tx_counter;
+
+static void led_get_net_stats(int addvalue)
+{
+	static unsigned long rx_total_last, tx_total_last;
+	unsigned long rx_total, tx_total;
+	struct net_device *dev;
+	struct net_device_stats *stats;
+
+	rx_total = tx_total = 0;
+	
+	/* we are running as a tasklet, so locking dev_base 
+	 * for reading should be OK */
+	read_lock(&dev_base_lock);
+	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	    if (dev->get_stats) { 
+	        stats = dev->get_stats(dev);
+		rx_total += stats->rx_packets;
+		tx_total += stats->tx_packets;
+	    }
+	}
+	read_unlock(&dev_base_lock);
 
-static char currentleds;	/* stores current value of the LEDs */
+	rx_total -= rx_total_last;
+	tx_total -= tx_total_last;
+	
+	if (rx_total)
+	    led_net_rx_counter += CALC_ADD(rx_total, tx_total, addvalue);
+
+	if (tx_total)
+	    led_net_tx_counter += CALC_ADD(tx_total, rx_total, addvalue);
+        
+	rx_total_last += rx_total;
+        tx_total_last += tx_total;
+}
 
-static void (*led_func_ptr) (unsigned char); /* ptr to LCD/LED-specific function */
 
 /*
-   ** led_interrupt_func()
    ** 
-   ** is called at every timer interrupt from time.c,
+   ** led_get_diskio_stats()
+   ** 
+   ** calculate the disk-io througput in the system
+   ** (analog to linux/fs/proc/proc_misc.c)
+   **   
+ */
+static unsigned long led_diskio_counter;
+
+static void led_get_diskio_stats(int addvalue)
+{	
+	static unsigned int diskio_total_last, diskio_max;
+	int major, disk, total;
+	
+	total = 0;
+	for (major = 0; major < DK_MAX_MAJOR; major++) {
+	    for (disk = 0; disk < DK_MAX_DISK; disk++)
+		total += kstat.dk_drive[major][disk];
+	}
+	total -= diskio_total_last;
+	
+	if (total) {
+	    if (total >= diskio_max) {
+		led_diskio_counter += addvalue;
+	        diskio_max = total; /* new maximum value found */ 
+	    } else
+		led_diskio_counter += CALC_ADD(total, diskio_max, addvalue);
+	}
+	
+	diskio_total_last += total; 
+}
+
+
+
+/*
+   ** led_tasklet_func()
+   ** 
+   ** is scheduled at every timer interrupt from time.c and
    ** updates the chassis LCD/LED 
+
+    TODO:
+    - display load average (older machines like 715/64 have 4 "free" LED's for that)
+    - optimizations
  */
 
-#define HEARTBEAT_LEN	(HZ/16)
+static unsigned char currentleds;	/* stores current value of the LEDs */
+
+#define HEARTBEAT_LEN (HZ*6/100)
+#define HEARTBEAT_2ND_RANGE_START (HZ*22/100)
+#define HEARTBEAT_2ND_RANGE_END   (HEARTBEAT_2ND_RANGE_START + HEARTBEAT_LEN)
 
-void led_interrupt_func(void)
+static void led_tasklet_func(unsigned long unused)
 {
-#ifndef DISABLE_LEDS
-	static int count;
-	static int lastleds = -1;
-	static int nr;
+	static unsigned int count, count_HZ;
+	static unsigned char lastleds;
 
-	/* exit, if not initialized */
+	/* exit if not initialized */
 	if (!led_func_ptr)
 	    return;
-	
-	/* increment the local counter */
-	if (count == (HZ-1))
-	    count = 0;
-	else
-	    count++;
 
-	/* calculate the Heartbeat */
-	if ((count % (HZ/2)) < HEARTBEAT_LEN) 
-	    currentleds |= LED_HEARTBEAT;
-	else
-	    currentleds &= ~LED_HEARTBEAT;
+	/* increment the local counters */
+	++count;
+	if (++count_HZ == HZ)
+	    count_HZ = 0;
+
+	if (led_heartbeat)
+	{
+		/* flash heartbeat-LED like a real heart (2 x short then a long delay) */
+		if (count_HZ<HEARTBEAT_LEN || 
+		    (count_HZ>=HEARTBEAT_2ND_RANGE_START && count_HZ<HEARTBEAT_2ND_RANGE_END)) 
+		    currentleds |= LED_HEARTBEAT;
+		else
+		    currentleds &= ~LED_HEARTBEAT;
+	}
+
+	/* gather network and diskio statistics and flash LEDs respectively */
+
+	if (led_lanrxtx)
+	{
+		if ((count & 31) == 0)
+			led_get_net_stats(30);
+
+		if (led_net_rx_counter) {
+			led_net_rx_counter--;
+			currentleds |= LED_LAN_RCV;
+		}
+		else    
+			currentleds &= ~LED_LAN_RCV;
+
+		if (led_net_tx_counter) {
+			led_net_tx_counter--;
+			currentleds |= LED_LAN_TX;
+		}
+		else    
+			currentleds &= ~LED_LAN_TX;
+	}
 
-	/* roll LEDs 0..2 */
-	if (count == 0) {
-	    if (nr++ >= 2) 
-		nr = 0;
-	    currentleds &= ~7;
-	    currentleds |= (1 << nr);
+	if (led_diskio)
+	{
+		/* avoid to calculate diskio-stats at same irq as netio-stats ! */
+		if ((count & 31) == 15) 
+			led_get_diskio_stats(30);
+
+		if (led_diskio_counter) {
+			led_diskio_counter--;
+			currentleds |= LED_DISK_IO;
+		}
+		else    
+			currentleds &= ~LED_DISK_IO;
 	}
 
-	/* now update the LEDs */
+	/* update the LCD/LEDs */
 	if (currentleds != lastleds) {
 	    led_func_ptr(currentleds);
 	    lastleds = currentleds;
 	}
-#endif
 }
 
+/* main led tasklet struct (scheduled from time.c) */
+DECLARE_TASKLET_DISABLED(led_tasklet, led_tasklet_func, 0);
+
+
+/*
+   ** led_halt()
+   ** 
+   ** called by the reboot notifier chain at shutdown and stops all
+   ** LED/LCD activities.
+   ** 
+ */
+
+static int led_halt(struct notifier_block *, unsigned long, void *);
+
+static struct notifier_block led_notifier = {
+	notifier_call: led_halt,
+};
+
+static int led_halt(struct notifier_block *nb, unsigned long event, void *buf) 
+{
+	char *txt;
+	
+	switch (event) {
+	case SYS_RESTART:	txt = "SYSTEM RESTART";
+				break;
+	case SYS_HALT:		txt = "SYSTEM HALT";
+				break;
+	case SYS_POWER_OFF:	txt = "SYSTEM POWER OFF";
+				break;
+	default:		return NOTIFY_DONE;
+	}
+	
+	/* completely stop the LED/LCD tasklet */
+	tasklet_disable(&led_tasklet);
+
+	if (lcd_info.model == DISPLAY_MODEL_LCD)
+		lcd_print(txt);
+	else
+		if (led_func_ptr)
+			led_func_ptr(0xff); /* turn all LEDs ON */
+	
+	unregister_reboot_notifier(&led_notifier);
+	return NOTIFY_OK;
+}
 
 /*
    ** register_led_driver()
    ** 
-   ** All information in lcd_info needs to be set up prior
-   ** calling this function. 
+   ** registers an external LED or LCD for usage by this driver.
+   ** currently only LCD-, LASI- and ASP-style LCD/LED's are supported.
+   ** 
  */
 
-static void __init register_led_driver(void)
+int __init register_led_driver(int model, char *cmd_reg, char *data_reg)
 {
-#ifndef DISABLE_LEDS
+	static int initialized;
+	
+	if (initialized || !data_reg)
+	    return 1;
+	
+	lcd_info.model = model;		/* store the values */
+	LCD_CMD_REG = (cmd_reg == LED_CMD_REG_NONE) ? NULL : cmd_reg;
+
 	switch (lcd_info.model) {
 	case DISPLAY_MODEL_LCD:
-		printk(KERN_INFO "LCD display at (%p,%p)\n",
-		  LCD_CMD_REG , LCD_DATA_REG);
+		LCD_DATA_REG = data_reg;
+		printk(KERN_INFO "LCD display at %p,%p registered\n", 
+			LCD_CMD_REG , LCD_DATA_REG);
 		led_func_ptr = led_LCD_driver;
+		lcd_print( "Linux " UTS_RELEASE );
+		led_type = LED_HASLCD;
 		break;
 
 	case DISPLAY_MODEL_LASI:
-		printk(KERN_INFO "LED display at %p\n",
-		       LED_DATA_REG);
+		LED_DATA_REG = data_reg;
 		led_func_ptr = led_LASI_driver;
+		printk(KERN_INFO "LED display at %p registered\n", LED_DATA_REG);
+		led_type = LED_NOLCD;
 		break;
 
 	case DISPLAY_MODEL_OLD_ASP:
-		printk(KERN_INFO "LED (ASP-style) display at %p\n",
-		       LED_DATA_REG);
+		LED_DATA_REG = data_reg;
 		led_func_ptr = led_ASP_driver;
+		printk(KERN_INFO "LED (ASP-style) display at %p registered\n", 
+		    LED_DATA_REG);
+		led_type = LED_NOLCD;
 		break;
 
 	default:
 		printk(KERN_ERR "%s: Wrong LCD/LED model %d !\n",
 		       __FUNCTION__, lcd_info.model);
-		return;
+		return 1;
 	}
-#endif
-}
-
-/*
- * XXX - could this move to lasi.c ??
- */
-
-/*
-   ** lasi_led_init()
-   ** 
-   ** lasi_led_init() is called from lasi.c with the base hpa  
-   ** of the lasi controller chip. 
-   ** Since Mirage and Electra machines use a different LED
-   ** address register, we need to check for these machines 
-   ** explicitly.
- */
-
-#ifdef CONFIG_GSC_LASI
-void __init lasi_led_init(unsigned long lasi_hpa)
-{
-	if (lcd_info.model != DISPLAY_MODEL_NONE ||
-	    lasi_hpa == 0)
-		return;
-
-	printk("%s: CPU_HVERSION %x\n", __FUNCTION__, CPU_HVERSION);
-
-	/* Mirage and Electra machines need special offsets */
-	switch (CPU_HVERSION) {
-	case 0x60A:		/* Mirage Jr (715/64) */
-	case 0x60B:		/* Mirage 100 */
-	case 0x60C:		/* Mirage 100+ */
-	case 0x60D:		/* Electra 100 */
-	case 0x60E:		/* Electra 120 */
-		LED_DATA_REG = (char *) (lasi_hpa - 0x00020000);
-		break;
-	default:
-		LED_DATA_REG = (char *) (lasi_hpa + 0x0000C000);
-		break;
-	}			/* switch() */
-
-	lcd_info.model = DISPLAY_MODEL_LASI;
-	register_led_driver();
-}
-#endif
-
-
-/*
-   ** asp_led_init()
-   ** 
-   ** asp_led_init() is called from asp.c with the ptr 
-   ** to the LED display.
- */
-
-#ifdef CONFIG_GSC_LASI
-void __init asp_led_init(unsigned long led_ptr)
-{
-	if (lcd_info.model != DISPLAY_MODEL_NONE ||
-	    led_ptr == 0)
-		return;
-
-	lcd_info.model = DISPLAY_MODEL_OLD_ASP;
-	LED_DATA_REG = (char *) led_ptr;
+	
+	/* mark the LCD/LED driver now as initialized and 
+	 * register to the reboot notifier chain */
+	initialized++;
+	register_reboot_notifier(&led_notifier);
 
-	register_led_driver();
+	/* start the led tasklet for the first time */
+	tasklet_enable(&led_tasklet);
+	
+	return 0;
 }
 
-#endif
-
-
-
 /*
    ** register_led_regions()
    ** 
-   ** Simple function, which registers the LCD/LED regions for /procfs.
+   ** register_led_regions() registers the LCD/LED regions for /procfs.
    ** At bootup - where the initialisation of the LCD/LED normally happens - 
    ** not all internal structures of request_region() are properly set up,
-   ** so that we delay the registration until busdevice.c is executed.
+   ** so that we delay the led-registration until after busdevices_init() 
+   ** has been executed.
    **
  */
 
@@ -358,17 +625,57 @@
 {
 	switch (lcd_info.model) {
 	case DISPLAY_MODEL_LCD:
-		request_region((unsigned long)LCD_CMD_REG,  1, "lcd_cmd");
-		request_region((unsigned long)LCD_DATA_REG, 1, "lcd_data");
+		request_mem_region((unsigned long)LCD_CMD_REG,  1, "lcd_cmd");
+		request_mem_region((unsigned long)LCD_DATA_REG, 1, "lcd_data");
 		break;
 	case DISPLAY_MODEL_LASI:
 	case DISPLAY_MODEL_OLD_ASP:
-		request_region((unsigned long)LED_DATA_REG, 1, "led_data");
+		request_mem_region((unsigned long)LED_DATA_REG, 1, "led_data");
 		break;
 	}
 }
 
 
+/*
+   ** 
+   ** lcd_print()
+   ** 
+   ** Displays the given string on the LCD-Display of newer machines.
+   ** lcd_print() disables the timer-based led tasklet during its 
+   ** execution and enables it afterwards again.
+   **
+ */
+int lcd_print( char *str )
+{
+	int i;
+
+	if (!led_func_ptr || lcd_info.model != DISPLAY_MODEL_LCD)
+	    return 0;
+	
+	/* temporarily disable the led tasklet */
+	tasklet_disable(&led_tasklet);
+
+	/* copy display string to buffer for procfs */
+	strncpy(lcd_text, str, sizeof(lcd_text)-1);
+	
+	/* Set LCD Cursor to 1st character */
+	gsc_writeb(lcd_info.reset_cmd1, LCD_CMD_REG);
+	udelay(lcd_info.min_cmd_delay);
+
+	/* Print the string */
+	for (i=0; i < lcd_info.lcd_width; i++) {
+	    if (str && *str)
+		gsc_writeb(*str++, LCD_DATA_REG);
+	    else
+		gsc_writeb(' ', LCD_DATA_REG);
+	    udelay(lcd_info.min_cmd_delay);
+	}
+	
+	/* re-enable the led tasklet */
+	tasklet_enable(&led_tasklet);
+
+	return lcd_info.lcd_width;
+}
 
 /*
    ** led_init()
@@ -384,10 +691,8 @@
 
 int __init led_init(void)
 {
-#ifndef DISABLE_LEDS
-	long pdc_result[32];
-
-	printk("%s: CPU_HVERSION %x\n", __FUNCTION__, CPU_HVERSION);
+	struct pdc_chassis_info chassis_info;
+	int ret;
 
 	/* Work around the buggy PDC of KittyHawk-machines */
 	switch (CPU_HVERSION) {
@@ -396,56 +701,74 @@
 	case 0x582:		/* KittyHawk DC3 100 (K400) */
 	case 0x583:		/* KittyHawk DC3 120 (K410) */
 	case 0x58B:		/* KittyHawk DC2 100 (K200) */
-		printk("%s: KittyHawk-Machine found !!\n", __FUNCTION__);
+		printk(KERN_INFO "%s: KittyHawk-Machine (hversion 0x%x) found, "
+				"LED detection skipped.\n", __FILE__, CPU_HVERSION);
 		goto found;	/* use the preinitialized values of lcd_info */
-
-	default:
-		break;
 	}
 
-	/* initialize pdc_result, so we can check the return values of pdc_chassis_info() */
-	pdc_result[0] = pdc_result[1] = 0;
-
-	if (pdc_chassis_info(&pdc_result, &lcd_info, sizeof(lcd_info)) == PDC_OK) {
-		printk("%s: chassis info: model %d, ret0=%d, ret1=%d\n",
-		 __FUNCTION__, lcd_info.model, pdc_result[0], pdc_result[1]);
+	/* initialize the struct, so that we can check for valid return values */
+	lcd_info.model = DISPLAY_MODEL_NONE;
+	chassis_info.actcnt = chassis_info.maxcnt = 0;
 
+	if ((ret = pdc_chassis_info(&chassis_info, &lcd_info, sizeof(lcd_info))) == PDC_OK) {
+		DPRINTK((KERN_INFO "%s: chassis info: model=%d (%s), "
+			 "lcd_width=%d, cmd_delay=%u,\n"
+			 "%s: sizecnt=%d, actcnt=%ld, maxcnt=%ld\n",
+		         __FILE__, lcd_info.model,
+			 (lcd_info.model==DISPLAY_MODEL_LCD) ? "LCD" :
+			  (lcd_info.model==DISPLAY_MODEL_LASI) ? "LED" : "unknown",
+			 lcd_info.lcd_width, lcd_info.min_cmd_delay,
+			 __FILE__, sizeof(lcd_info), 
+			 chassis_info.actcnt, chassis_info.maxcnt));
+		DPRINTK((KERN_INFO "%s: cmd=%p, data=%p, reset1=%x, reset2=%x, act_enable=%d\n",
+			__FILE__, lcd_info.lcd_cmd_reg_addr, 
+			lcd_info.lcd_data_reg_addr, lcd_info.reset_cmd1,  
+			lcd_info.reset_cmd2, lcd_info.act_enable ));
+	
 		/* check the results. Some machines have a buggy PDC */
-		if (pdc_result[0] <= 0 || pdc_result[0] != pdc_result[1])
+		if (chassis_info.actcnt <= 0 || chassis_info.actcnt != chassis_info.maxcnt)
 			goto not_found;
 
 		switch (lcd_info.model) {
-		case DISPLAY_MODEL_LCD:	/* LCD display */
-			if (pdc_result[0] != sizeof(struct pdc_chassis_lcd_info_ret_block)
-			    && pdc_result[0] != sizeof(struct pdc_chassis_lcd_info_ret_block) - 1)
-				 goto not_found;
-			printk("%s: min_cmd_delay = %d uS\n",
-		             __FUNCTION__, lcd_info.min_cmd_delay);
+		case DISPLAY_MODEL_LCD:		/* LCD display */
+			if (chassis_info.actcnt < 
+				offsetof(struct pdc_chassis_lcd_info_ret_block, _pad)-1)
+				goto not_found;
+			if (!lcd_info.act_enable) {
+				DPRINTK((KERN_INFO "PDC prohibited usage of the LCD.\n"));
+				goto not_found;
+			}
 			break;
 
 		case DISPLAY_MODEL_NONE:	/* no LED or LCD available */
+			printk(KERN_INFO "PDC reported no LCD or LED.\n");
 			goto not_found;
 
 		case DISPLAY_MODEL_LASI:	/* Lasi style 8 bit LED display */
-			if (pdc_result[0] != 8 && pdc_result[0] != 32)
+			if (chassis_info.actcnt != 8 && chassis_info.actcnt != 32)
 				goto not_found;
 			break;
 
 		default:
-			printk(KERN_WARNING "Unknown LCD/LED model %d\n",
+			printk(KERN_WARNING "PDC reported unknown LCD/LED model %d\n",
 			       lcd_info.model);
 			goto not_found;
-		}		/* switch() */
+		} /* switch() */
 
 found:
 		/* register the LCD/LED driver */
-		register_led_driver();
+		register_led_driver(lcd_info.model, LCD_CMD_REG, LCD_DATA_REG);
 		return 0;
 
-	}			/* if() */
+	} else { /* if() */
+		DPRINTK((KERN_INFO "pdc_chassis_info call failed with retval = %d\n", ret));
+	}
 
 not_found:
 	lcd_info.model = DISPLAY_MODEL_NONE;
 	return 1;
-#endif
 }
+
+#ifdef CONFIG_PROC_FS
+module_init(led_create_procfs)
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/pa7300lc.c linux-2.4.20/arch/parisc/kernel/pa7300lc.c
--- linux-2.4.19/arch/parisc/kernel/pa7300lc.c	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/pa7300lc.c	2002-10-29 11:18:40.000000000 +0000
@@ -4,11 +4,12 @@
  *
  *   Copyright (C) 2000 Philipp Rumpf */
 
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/kernel.h>
 #include <asm/gsc.h>
 #include <asm/ptrace.h>
 #include <asm/machdep.h>
-#include <linux/smp.h>
-#include <linux/kernel.h>
 
 /* CPU register indices */
 
@@ -19,12 +20,6 @@
 #define DIOERR		0xf0ec
 #define HIDMAMEM	0xf0f4
 
-/* read CPU Diagnose register index */
-static u32 diag_read(int index)
-{
-	return 0;
-}
-
 /* this returns the HPA of the CPU it was called on */
 static u32 cpu_hpa(void)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/pacache.S linux-2.4.20/arch/parisc/kernel/pacache.S
--- linux-2.4.19/arch/parisc/kernel/pacache.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/pacache.S	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,908 @@
+/*
+ *  Parisc tlb and cache flushing support
+ *  Copyright (C) 2000 Hewlett-Packard (John Marvin)
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * NOTE: fdc,fic, and pdc instructions that use base register modification
+ *       should only use index and base registers that are not shadowed,
+ *       so that the fast path emulation in the non access miss handler
+ *       can be used.
+ */
+
+#ifdef __LP64__
+#define ADDIB   addib,*
+#define CMPB    cmpb,*
+#define ANDCM   andcm,*
+
+	.level 2.0w
+#else
+#define ADDIB   addib,
+#define CMPB    cmpb,
+#define ANDCM   andcm
+
+	.level 2.0
+#endif
+
+#include <asm/assembly.h>
+#include <asm/psw.h>
+#include <asm/pgtable.h>
+#include <asm/cache.h>
+
+	.text
+	.align 128
+
+	.export flush_tlb_all_local,code
+
+flush_tlb_all_local:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	/*
+	 * The pitlbe and pdtlbe instructions should only be used to
+	 * flush the entire tlb. Also, there needs to be no intervening
+	 * tlb operations, e.g. tlb misses, so the operation needs
+	 * to happen in real mode with all interruptions disabled.
+	 */
+
+	/*
+	 * Once again, we do the rfi dance ... some day we need examine
+	 * all of our uses of this type of code and see what can be
+	 * consolidated.
+	 */
+
+	rsm     PSW_SM_I,%r19      /* relied upon translation! */
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	
+	rsm     PSW_SM_Q,%r0       /* Turn off Q bit to load iia queue */
+	ldil    L%REAL_MODE_PSW, %r1
+	ldo     R%REAL_MODE_PSW(%r1), %r1
+	mtctl	%r1, %cr22
+	mtctl	%r0, %cr17
+	mtctl	%r0, %cr17
+	ldil    L%PA(1f),%r1
+	ldo     R%PA(1f)(%r1),%r1
+	mtctl	%r1, %cr18
+	ldo	4(%r1), %r1
+	mtctl	%r1, %cr18
+	rfi
+	nop
+
+1:      ldil            L%PA(cache_info),%r1
+	ldo             R%PA(cache_info)(%r1),%r1
+
+	/* Flush Instruction Tlb */
+
+	LDREG           ITLB_SID_BASE(%r1),%r20
+	LDREG           ITLB_SID_STRIDE(%r1),%r21
+	LDREG           ITLB_SID_COUNT(%r1),%r22
+	LDREG           ITLB_OFF_BASE(%r1),%arg0
+	LDREG           ITLB_OFF_STRIDE(%r1),%arg1
+	LDREG           ITLB_OFF_COUNT(%r1),%arg2
+	LDREG           ITLB_LOOP(%r1),%arg3
+
+	ADDIB=          -1,%arg3,fitoneloop     /* Preadjust and test */
+	movb,<,n        %arg3,%r31,fitdone      /* If loop < 0, skip */
+	copy            %arg0,%r28              /* Init base addr */
+
+fitmanyloop:                                    /* Loop if LOOP >= 2 */
+	mtsp            %r20,%sr1
+	add             %r21,%r20,%r20          /* increment space */
+	copy            %arg2,%r29              /* Init middle loop count */
+
+fitmanymiddle:                                  /* Loop if LOOP >= 2 */
+	ADDIB>          -1,%r31,fitmanymiddle   /* Adjusted inner loop decr */
+	pitlbe          0(%sr1,%r28)
+	pitlbe,m        %arg1(%sr1,%r28)        /* Last pitlbe and addr adjust */
+	ADDIB>          -1,%r29,fitmanymiddle   /* Middle loop decr */
+	copy            %arg3,%r31              /* Re-init inner loop count */
+
+	movb,tr         %arg0,%r28,fitmanyloop  /* Re-init base addr */
+	ADDIB<=,n       -1,%r22,fitdone         /* Outer loop count decr */
+
+fitoneloop:                                     /* Loop if LOOP = 1 */
+	mtsp            %r20,%sr1
+	copy            %arg0,%r28              /* init base addr */
+	copy            %arg2,%r29              /* init middle loop count */
+
+fitonemiddle:                                   /* Loop if LOOP = 1 */
+	ADDIB>          -1,%r29,fitonemiddle    /* Middle loop count decr */
+	pitlbe,m        %arg1(%sr1,%r28)        /* pitlbe for one loop */
+
+	ADDIB>          -1,%r22,fitoneloop      /* Outer loop count decr */
+	add             %r21,%r20,%r20          /* increment space */
+
+fitdone:
+
+	/* Flush Data Tlb */
+
+	LDREG           DTLB_SID_BASE(%r1),%r20
+	LDREG           DTLB_SID_STRIDE(%r1),%r21
+	LDREG           DTLB_SID_COUNT(%r1),%r22
+	LDREG           DTLB_OFF_BASE(%r1),%arg0
+	LDREG           DTLB_OFF_STRIDE(%r1),%arg1
+	LDREG           DTLB_OFF_COUNT(%r1),%arg2
+	LDREG           DTLB_LOOP(%r1),%arg3
+
+	ADDIB=          -1,%arg3,fdtoneloop     /* Preadjust and test */
+	movb,<,n        %arg3,%r31,fdtdone      /* If loop < 0, skip */
+	copy            %arg0,%r28              /* Init base addr */
+
+fdtmanyloop:                                    /* Loop if LOOP >= 2 */
+	mtsp            %r20,%sr1
+	add             %r21,%r20,%r20          /* increment space */
+	copy            %arg2,%r29              /* Init middle loop count */
+
+fdtmanymiddle:                                  /* Loop if LOOP >= 2 */
+	ADDIB>          -1,%r31,fdtmanymiddle   /* Adjusted inner loop decr */
+	pdtlbe          0(%sr1,%r28)
+	pdtlbe,m        %arg1(%sr1,%r28)        /* Last pdtlbe and addr adjust */
+	ADDIB>          -1,%r29,fdtmanymiddle   /* Middle loop decr */
+	copy            %arg3,%r31              /* Re-init inner loop count */
+
+	movb,tr         %arg0,%r28,fdtmanyloop  /* Re-init base addr */
+	ADDIB<=,n       -1,%r22,fdtdone         /* Outer loop count decr */
+
+fdtoneloop:                                     /* Loop if LOOP = 1 */
+	mtsp            %r20,%sr1
+	copy            %arg0,%r28              /* init base addr */
+	copy            %arg2,%r29              /* init middle loop count */
+
+fdtonemiddle:                                   /* Loop if LOOP = 1 */
+	ADDIB>          -1,%r29,fdtonemiddle    /* Middle loop count decr */
+	pdtlbe,m        %arg1(%sr1,%r28)        /* pdtlbe for one loop */
+
+	ADDIB>          -1,%r22,fdtoneloop      /* Outer loop count decr */
+	add             %r21,%r20,%r20          /* increment space */
+
+fdtdone:
+
+	/* Switch back to virtual mode */
+
+	rsm     PSW_SM_Q,%r0       /* clear Q bit to load iia queue */
+	ldil	L%KERNEL_PSW, %r1
+	ldo	R%KERNEL_PSW(%r1), %r1
+	or      %r1,%r19,%r1    /* Set I bit if set on entry */
+	mtctl	%r1, %cr22
+	mtctl	%r0, %cr17
+	mtctl	%r0, %cr17
+	ldil    L%(2f), %r1
+	ldo     R%(2f)(%r1), %r1
+	mtctl	%r1, %cr18
+	ldo	4(%r1), %r1
+	mtctl	%r1, %cr18
+	rfi
+	nop
+
+2:      bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export flush_instruction_cache_local,code
+	.import cache_info,data
+
+flush_instruction_cache_local:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	mtsp            %r0,%sr1
+	ldil            L%cache_info,%r1
+	ldo             R%cache_info(%r1),%r1
+
+	/* Flush Instruction Cache */
+
+	LDREG           ICACHE_BASE(%r1),%arg0
+	LDREG           ICACHE_STRIDE(%r1),%arg1
+	LDREG           ICACHE_COUNT(%r1),%arg2
+	LDREG           ICACHE_LOOP(%r1),%arg3
+	ADDIB=          -1,%arg3,fioneloop      /* Preadjust and test */
+	movb,<,n        %arg3,%r31,fisync       /* If loop < 0, do sync */
+
+fimanyloop:                                     /* Loop if LOOP >= 2 */
+	ADDIB>          -1,%r31,fimanyloop      /* Adjusted inner loop decr */
+	fice            0(%sr1,%arg0)
+	fice,m          %arg1(%sr1,%arg0)       /* Last fice and addr adjust */
+	movb,tr         %arg3,%r31,fimanyloop   /* Re-init inner loop count */
+	ADDIB<=,n       -1,%arg2,fisync         /* Outer loop decr */
+
+fioneloop:                                      /* Loop if LOOP = 1 */
+	ADDIB>          -1,%arg2,fioneloop      /* Outer loop count decr */
+	fice,m          %arg1(%sr1,%arg0)       /* Fice for one loop */
+
+fisync:
+	sync
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export flush_data_cache_local,code
+	.import cache_info,data
+
+flush_data_cache_local:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	mtsp            %r0,%sr1
+	ldil            L%cache_info,%r1
+	ldo             R%cache_info(%r1),%r1
+
+	/* Flush Data Cache */
+
+	LDREG           DCACHE_BASE(%r1),%arg0
+	LDREG           DCACHE_STRIDE(%r1),%arg1
+	LDREG           DCACHE_COUNT(%r1),%arg2
+	LDREG           DCACHE_LOOP(%r1),%arg3
+	rsm             PSW_SM_I,%r22
+	ADDIB=          -1,%arg3,fdoneloop      /* Preadjust and test */
+	movb,<,n        %arg3,%r31,fdsync       /* If loop < 0, do sync */
+
+fdmanyloop:                                     /* Loop if LOOP >= 2 */
+	ADDIB>          -1,%r31,fdmanyloop      /* Adjusted inner loop decr */
+	fdce            0(%sr1,%arg0)
+	fdce,m          %arg1(%sr1,%arg0)       /* Last fdce and addr adjust */
+	movb,tr         %arg3,%r31,fdmanyloop   /* Re-init inner loop count */
+	ADDIB<=,n       -1,%arg2,fdsync         /* Outer loop decr */
+
+fdoneloop:                                      /* Loop if LOOP = 1 */
+	ADDIB>          -1,%arg2,fdoneloop      /* Outer loop count decr */
+	fdce,m          %arg1(%sr1,%arg0)       /* Fdce for one loop */
+
+fdsync:
+	syncdma
+	sync
+	mtsm    %r22
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export copy_user_page_asm,code
+
+copy_user_page_asm:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldi 64,%r1
+
+	/*
+	 * This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw
+	 * bundles (very restricted rules for bundling). It probably
+	 * does OK on PCXU and better, but we could do better with
+	 * ldd/std instructions. Note that until (if) we start saving
+	 * the full 64 bit register values on interrupt, we can't
+	 * use ldd/std on a 32 bit kernel.
+	 */
+
+
+1:
+	ldw 0(%r25),%r19
+	ldw 4(%r25),%r20
+	ldw 8(%r25),%r21
+	ldw 12(%r25),%r22
+	stw %r19,0(%r26)
+	stw %r20,4(%r26)
+	stw %r21,8(%r26)
+	stw %r22,12(%r26)
+	ldw 16(%r25),%r19
+	ldw 20(%r25),%r20
+	ldw 24(%r25),%r21
+	ldw 28(%r25),%r22
+	stw %r19,16(%r26)
+	stw %r20,20(%r26)
+	stw %r21,24(%r26)
+	stw %r22,28(%r26)
+	ldw 32(%r25),%r19
+	ldw 36(%r25),%r20
+	ldw 40(%r25),%r21
+	ldw 44(%r25),%r22
+	stw %r19,32(%r26)
+	stw %r20,36(%r26)
+	stw %r21,40(%r26)
+	stw %r22,44(%r26)
+	ldw 48(%r25),%r19
+	ldw 52(%r25),%r20
+	ldw 56(%r25),%r21
+	ldw 60(%r25),%r22
+	stw %r19,48(%r26)
+	stw %r20,52(%r26)
+	stw %r21,56(%r26)
+	stw %r22,60(%r26)
+	ldo 64(%r26),%r26
+	ADDIB>  -1,%r1,1b
+	ldo 64(%r25),%r25
+
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+#if (TMPALIAS_MAP_START >= 0x80000000UL)
+Warning TMPALIAS_MAP_START changed. If > 2 Gb, code in pacache.S is bogus
+#endif
+
+/*
+ * NOTE: Code in clear_user_page has a hard coded dependency on the
+ *       maximum alias boundary being 4 Mb. We've been assured by the
+ *       parisc chip designers that there will not ever be a parisc
+ *       chip with a larger alias boundary (Never say never :-) ).
+ *
+ *       Subtle: the dtlb miss handlers support the temp alias region by
+ *       "knowing" that if a dtlb miss happens within the temp alias
+ *       region it must have occurred while in clear_user_page. Since
+ *       this routine makes use of processor local translations, we
+ *       don't want to insert them into the kernel page table. Instead,
+ *       we load up some general registers (they need to be registers
+ *       which aren't shadowed) with the physical page numbers (preshifted
+ *       for tlb insertion) needed to insert the translations. When we
+ *       miss on the translation, the dtlb miss handler inserts the
+ *       translation into the tlb using these values:
+ *
+ *          %r26 physical page (shifted for tlb insert) of "to" translation
+ *          %r23 physical page (shifted for tlb insert) of "from" translation
+ */
+
+#if 0
+
+	/*
+	 * We can't do this since copy_user_page is used to bring in
+	 * file data that might have instructions. Since the data would
+	 * then need to be flushed out so the i-fetch can see it, it
+	 * makes more sense to just copy through the kernel translation
+	 * and flush it.
+	 *
+	 * I'm still keeping this around because it may be possible to
+	 * use it if more information is passed into copy_user_page().
+	 * Have to do some measurements to see if it is worthwhile to
+	 * lobby for such a change.
+	 */
+
+	.export copy_user_page_asm,code
+
+copy_user_page_asm:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil    L%(__PAGE_OFFSET),%r1
+	sub     %r26,%r1,%r26
+	sub     %r25,%r1,%r23  /* move physical addr into non shadowed reg */
+
+	ldil    L%(TMPALIAS_MAP_START),%r28
+#ifdef __LP64__
+	extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */
+	extrd,u %r23,56,32,%r23 /* convert phys addr to tlb insert format */
+	depd    %r24,63,22,%r28 /* Form aliased virtual address 'to' */
+	depdi   0,63,12,%r28    /* Clear any offset bits */
+	copy    %r28,%r29
+	depdi   1,41,1,%r29     /* Form aliased virtual address 'from' */
+#else
+	extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */
+	extrw,u %r23,24,25,%r23 /* convert phys addr to tlb insert format */
+	depw    %r24,31,22,%r28 /* Form aliased virtual address 'to' */
+	depwi   0,31,12,%r28    /* Clear any offset bits */
+	copy    %r28,%r29
+	depwi   1,9,1,%r29      /* Form aliased virtual address 'from' */
+#endif
+
+	/* Purge any old translations */
+
+	pdtlb   0(%r28)
+	pdtlb   0(%r29)
+
+	ldi 64,%r1
+
+	/*
+	 * This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw
+	 * bundles (very restricted rules for bundling). It probably
+	 * does OK on PCXU and better, but we could do better with
+	 * ldd/std instructions. Note that until (if) we start saving
+	 * the full 64 bit register values on interrupt, we can't
+	 * use ldd/std on a 32 bit kernel.
+	 */
+
+
+1:
+	ldw 0(%r29),%r19
+	ldw 4(%r29),%r20
+	ldw 8(%r29),%r21
+	ldw 12(%r29),%r22
+	stw %r19,0(%r28)
+	stw %r20,4(%r28)
+	stw %r21,8(%r28)
+	stw %r22,12(%r28)
+	ldw 16(%r29),%r19
+	ldw 20(%r29),%r20
+	ldw 24(%r29),%r21
+	ldw 28(%r29),%r22
+	stw %r19,16(%r28)
+	stw %r20,20(%r28)
+	stw %r21,24(%r28)
+	stw %r22,28(%r28)
+	ldw 32(%r29),%r19
+	ldw 36(%r29),%r20
+	ldw 40(%r29),%r21
+	ldw 44(%r29),%r22
+	stw %r19,32(%r28)
+	stw %r20,36(%r28)
+	stw %r21,40(%r28)
+	stw %r22,44(%r28)
+	ldw 48(%r29),%r19
+	ldw 52(%r29),%r20
+	ldw 56(%r29),%r21
+	ldw 60(%r29),%r22
+	stw %r19,48(%r28)
+	stw %r20,52(%r28)
+	stw %r21,56(%r28)
+	stw %r22,60(%r28)
+	ldo 64(%r28),%r28
+	ADDIB>  -1,%r1,1b
+	ldo 64(%r29),%r29
+
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+#endif
+
+	.export clear_user_page_asm,code
+
+clear_user_page_asm:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	tophys_r1 %r26
+
+	ldil    L%(TMPALIAS_MAP_START),%r28
+#ifdef __LP64__
+	extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */
+	depd    %r25,63,22,%r28 /* Form aliased virtual address 'to' */
+	depdi   0,63,12,%r28    /* Clear any offset bits */
+#else
+	extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */
+	depw    %r25,31,22,%r28 /* Form aliased virtual address 'to' */
+	depwi   0,31,12,%r28    /* Clear any offset bits */
+#endif
+
+	/* Purge any old translation */
+
+	pdtlb   0(%r28)
+
+	ldi 64,%r1
+
+1:
+	stw %r0,0(%r28)
+	stw %r0,4(%r28)
+	stw %r0,8(%r28)
+	stw %r0,12(%r28)
+	stw %r0,16(%r28)
+	stw %r0,20(%r28)
+	stw %r0,24(%r28)
+	stw %r0,28(%r28)
+	stw %r0,32(%r28)
+	stw %r0,36(%r28)
+	stw %r0,40(%r28)
+	stw %r0,44(%r28)
+	stw %r0,48(%r28)
+	stw %r0,52(%r28)
+	stw %r0,56(%r28)
+	stw %r0,60(%r28)
+	ADDIB>  -1,%r1,1b
+	ldo 64(%r28),%r28
+
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export flush_kernel_dcache_page
+
+flush_kernel_dcache_page:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil    L%dcache_stride,%r1
+	ldw     R%dcache_stride(%r1),%r23
+
+#ifdef __LP64__
+	depdi,z 1,63-PAGE_SHIFT,1,%r25
+#else
+	depwi,z 1,31-PAGE_SHIFT,1,%r25
+#endif
+	add     %r26,%r25,%r25
+	sub     %r25,%r23,%r25
+
+
+1:      fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	CMPB<<  %r26,%r25,1b
+	fdc,m   %r23(%r26)
+
+	sync
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export purge_kernel_dcache_page
+
+purge_kernel_dcache_page:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil    L%dcache_stride,%r1
+	ldw     R%dcache_stride(%r1),%r23
+
+#ifdef __LP64__
+	depdi,z 1,63-PAGE_SHIFT,1,%r25
+#else
+	depwi,z 1,31-PAGE_SHIFT,1,%r25
+#endif
+	add      %r26,%r25,%r25
+	sub      %r25,%r23,%r25
+
+1:      pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	CMPB<<  %r26,%r25,1b
+	pdc,m   %r23(%r26)
+
+	sync
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+#if 0
+	/* Currently not used, but it still is a possible alternate
+	 * solution.
+	 */
+
+	.export flush_alias_page
+
+flush_alias_page:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	tophys_r1 %r26
+
+	ldil    L%(TMPALIAS_MAP_START),%r28
+#ifdef __LP64__
+	extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */
+	depd    %r25,63,22,%r28 /* Form aliased virtual address 'to' */
+	depdi   0,63,12,%r28    /* Clear any offset bits */
+#else
+	extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */
+	depw    %r25,31,22,%r28 /* Form aliased virtual address 'to' */
+	depwi   0,31,12,%r28    /* Clear any offset bits */
+#endif
+
+	/* Purge any old translation */
+
+	pdtlb   0(%r28)
+
+	ldil    L%dcache_stride,%r1
+	ldw     R%dcache_stride(%r1),%r23
+
+#ifdef __LP64__
+	depdi,z 1,63-PAGE_SHIFT,1,%r29
+#else
+	depwi,z 1,31-PAGE_SHIFT,1,%r29
+#endif
+	add      %r28,%r29,%r29
+	sub      %r29,%r23,%r29
+
+1:      fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	CMPB<<  %r28,%r29,1b
+	fdc,m   %r23(%r28)
+
+	sync
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+#endif
+
+	.export flush_user_dcache_range_asm
+
+flush_user_dcache_range_asm:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil    L%dcache_stride,%r1
+	ldw     R%dcache_stride(%r1),%r23
+	ldo     -1(%r23),%r21
+	ANDCM   %r26,%r21,%r26
+
+1:      CMPB<<,n %r26,%r25,1b
+	fdc,m   %r23(%sr3,%r26)
+
+	sync
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export flush_kernel_dcache_range_asm
+
+flush_kernel_dcache_range_asm:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil    L%dcache_stride,%r1
+	ldw     R%dcache_stride(%r1),%r23
+	ldo     -1(%r23),%r21
+	ANDCM   %r26,%r21,%r26
+
+1:      CMPB<<,n %r26,%r25,1b
+	fdc,m   %r23(%r26)
+
+	sync
+	syncdma
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export flush_user_icache_range_asm
+
+flush_user_icache_range_asm:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil    L%icache_stride,%r1
+	ldw     R%icache_stride(%r1),%r23
+	ldo     -1(%r23),%r21
+	ANDCM   %r26,%r21,%r26
+
+1:      CMPB<<,n %r26,%r25,1b
+	fic,m   %r23(%sr3,%r26)
+
+	sync
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export flush_kernel_icache_page
+
+flush_kernel_icache_page:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil    L%icache_stride,%r1
+	ldw     R%icache_stride(%r1),%r23
+
+#ifdef __LP64__
+	depdi,z 1,63-PAGE_SHIFT,1,%r25
+#else
+	depwi,z 1,31-PAGE_SHIFT,1,%r25
+#endif
+	add     %r26,%r25,%r25
+	sub     %r25,%r23,%r25
+
+
+1:      fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	CMPB<<  %r26,%r25,1b
+	fic,m   %r23(%r26)
+
+	sync
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export flush_kernel_icache_range_asm
+
+flush_kernel_icache_range_asm:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil    L%icache_stride,%r1
+	ldw     R%icache_stride(%r1),%r23
+	ldo     -1(%r23),%r21
+	ANDCM   %r26,%r21,%r26
+
+1:      CMPB<<,n %r26,%r25,1b
+	fic,m   %r23(%r26)
+
+	sync
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.align 128
+
+	.export disable_sr_hashing_asm,code
+
+disable_sr_hashing_asm:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	/* Switch to real mode */
+
+	ssm     0,%r0           /* relied upon translation! */
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	
+	rsm     (PSW_SM_Q|PSW_SM_I),%r0 /* disable Q&I to load the iia queue */
+	ldil    L%REAL_MODE_PSW, %r1
+	ldo     R%REAL_MODE_PSW(%r1), %r1
+	mtctl	%r1, %cr22
+	mtctl	%r0, %cr17
+	mtctl	%r0, %cr17
+	ldil    L%PA(1f),%r1
+	ldo     R%PA(1f)(%r1),%r1
+	mtctl	%r1, %cr18
+	ldo	4(%r1), %r1
+	mtctl	%r1, %cr18
+	rfi
+	nop
+
+1:      cmpib,=,n SRHASH_PCXST,%r26,srdis_pcxs
+	cmpib,=,n SRHASH_PCXL,%r26,srdis_pcxl
+	cmpib,=,n SRHASH_PA20,%r26,srdis_pa20
+	b,n       srdis_done
+
+srdis_pcxs:
+
+	/* Disable Space Register Hashing for PCXS,PCXT,PCXT' */
+
+	.word           0x141c1a00  /* mfdiag %dr0,%r28 */
+	.word           0x141c1a00  /* must issue twice */
+	depwi           0,18,1,%r28 /* Clear DHE (dcache hash enable) */
+	depwi           0,20,1,%r28 /* Clear IHE (icache hash enable) */
+	.word           0x141c1600  /* mtdiag %r28,%dr0 */
+	.word           0x141c1600  /* must issue twice */
+	b,n             srdis_done
+
+srdis_pcxl:
+
+	/* Disable Space Register Hashing for PCXL */
+
+	.word           0x141c0600  /* mfdiag %dr0,%r28 */
+	depwi           0,28,2,%r28 /* Clear DHASH_EN & IHASH_EN */
+	.word           0x141c0240  /* mtdiag %r28,%dr0 */
+	b,n             srdis_done
+
+srdis_pa20:
+
+	/* Disable Space Register Hashing for PCXU,PCXU+,PCXW,PCXW+ */
+
+	.word           0x144008bc  /* mfdiag %dr2,%r28 */
+	depdi           0,54,1,%r28 /* clear DIAG_SPHASH_ENAB (bit 54) */
+	.word           0x145c1840  /* mtdiag %r28,%dr2 */
+
+srdis_done:
+
+	/* Switch back to virtual mode */
+
+	rsm     PSW_SM_Q,%r0           /* clear Q bit to load iia queue */
+	ldil	L%KERNEL_PSW, %r1
+	ldo	R%KERNEL_PSW(%r1), %r1
+	mtctl	%r1, %cr22
+	mtctl	%r0, %cr17
+	mtctl	%r0, %cr17
+	ldil    L%(2f), %r1
+	ldo     R%(2f)(%r1), %r1
+	mtctl	%r1, %cr18
+	ldo	4(%r1), %r1
+	mtctl	%r1, %cr18
+	rfi
+	nop
+
+2:      bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.end
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/parisc_ksyms.c linux-2.4.20/arch/parisc/kernel/parisc_ksyms.c
--- linux-2.4.19/arch/parisc/kernel/parisc_ksyms.c	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/parisc_ksyms.c	2002-10-29 11:18:51.000000000 +0000
@@ -14,17 +14,29 @@
 EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(strcat);
 EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strcmp);
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strncat);
 EXPORT_SYMBOL(strncmp);
 EXPORT_SYMBOL(strncpy);
 EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(strstr);
 
+#include <asm/hardware.h>	/* struct parisc_device for asm/pci.h */
 #include <linux/pci.h>
 EXPORT_SYMBOL(hppa_dma_ops);
+#if defined(CONFIG_PCI) || defined(CONFIG_ISA)
+EXPORT_SYMBOL(get_pci_node_path);
+#endif
+
+#ifdef CONFIG_IOMMU_CCIO
+EXPORT_SYMBOL(ccio_get_fake);
+#endif
 
+#include <linux/sched.h>
 #include <asm/irq.h>
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
@@ -32,6 +44,13 @@
 #include <asm/processor.h>
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(boot_cpu_data);
+EXPORT_SYMBOL(map_hpux_gateway_page);
+#ifdef CONFIG_EISA
+EXPORT_SYMBOL(EISA_bus);
+#endif
+
+#include <linux/pm.h>
+EXPORT_SYMBOL(pm_power_off);
 
 #ifdef CONFIG_SMP
 EXPORT_SYMBOL(synchronize_irq);
@@ -39,35 +58,100 @@
 #include <asm/smplock.h>
 EXPORT_SYMBOL(kernel_flag);
 
+/* from asm/system.h */
 #include <asm/system.h>
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
 
+#include <linux/smp.h>
+EXPORT_SYMBOL(smp_num_cpus);
+#endif /* CONFIG_SMP */
+
+#include <asm/atomic.h>
+EXPORT_SYMBOL(__xchg8);
+EXPORT_SYMBOL(__xchg32);
+EXPORT_SYMBOL(__cmpxchg_u32);
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(__atomic_hash);
+#endif
+#ifdef __LP64__
+EXPORT_SYMBOL(__xchg64);
+EXPORT_SYMBOL(__cmpxchg_u64);
 #endif
 
 #include <asm/uaccess.h>
 EXPORT_SYMBOL(lcopy_to_user);
 EXPORT_SYMBOL(lcopy_from_user);
+EXPORT_SYMBOL(lstrnlen_user);
+EXPORT_SYMBOL(lclear_user);
 
+#ifndef __LP64__
 /* Needed so insmod can set dp value */
-
-extern int data_start;
-
-EXPORT_SYMBOL_NOVERS(data_start);
+extern int $global$;
+EXPORT_SYMBOL_NOVERS($global$);
+#endif
 
 #include <asm/gsc.h>
-EXPORT_SYMBOL(_gsc_writeb);
-EXPORT_SYMBOL(_gsc_writew);
-EXPORT_SYMBOL(_gsc_writel);
-EXPORT_SYMBOL(_gsc_readb);
-EXPORT_SYMBOL(_gsc_readw);
-EXPORT_SYMBOL(_gsc_readl);
-EXPORT_SYMBOL(busdevice_alloc_irq);
-EXPORT_SYMBOL(register_driver);
-EXPORT_SYMBOL(gsc_alloc_irq);
+EXPORT_SYMBOL(register_parisc_driver);
+EXPORT_SYMBOL(unregister_parisc_driver);
 EXPORT_SYMBOL(pdc_iodc_read);
+#ifdef CONFIG_GSC
+EXPORT_SYMBOL(gsc_alloc_irq);
+#endif
+
+#include <asm/io.h>
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(iounmap);
+EXPORT_SYMBOL(memcpy_toio);
+EXPORT_SYMBOL(memcpy_fromio);
+EXPORT_SYMBOL(memset_io);
+
+#if defined(CONFIG_PCI) || defined(CONFIG_ISA)
+EXPORT_SYMBOL(inb);
+EXPORT_SYMBOL(inw);
+EXPORT_SYMBOL(inl);
+EXPORT_SYMBOL(outb);
+EXPORT_SYMBOL(outw);
+EXPORT_SYMBOL(outl);
+
+EXPORT_SYMBOL(insb);
+EXPORT_SYMBOL(insw);
+EXPORT_SYMBOL(insl);
+EXPORT_SYMBOL(outsb);
+EXPORT_SYMBOL(outsw);
+EXPORT_SYMBOL(outsl);
+#endif
+
+#include <asm/cache.h>
+EXPORT_SYMBOL(flush_kernel_dcache_range_asm);
+EXPORT_SYMBOL(flush_kernel_dcache_page);
+EXPORT_SYMBOL(flush_all_caches);
+
+#include <asm/unistd.h>
+extern long sys_open(const char *, int, int);
+extern off_t sys_lseek(int, off_t, int);
+extern int sys_read(int, char *, int);
+extern int sys_write(int, const char *, int);
+EXPORT_SYMBOL(sys_open);
+EXPORT_SYMBOL(sys_lseek);
+EXPORT_SYMBOL(sys_read);
+EXPORT_SYMBOL(sys_write);
+
+#include <asm/semaphore.h>
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__down);
+
+#include <linux/in6.h>
+#include <asm/checksum.h>
+EXPORT_SYMBOL(csum_partial_copy);
+
+#include <asm/pdc.h>
+EXPORT_SYMBOL(pdc_add_valid);
+EXPORT_SYMBOL(pdc_lan_station_id);
+EXPORT_SYMBOL(pdc_get_initiator);
 
 extern void $$divI(void);
 extern void $$divU(void);
@@ -99,7 +183,9 @@
 EXPORT_SYMBOL_NOVERS($$remI);
 EXPORT_SYMBOL_NOVERS($$remU);
 EXPORT_SYMBOL_NOVERS($$mulI);
+#ifndef __LP64__
 EXPORT_SYMBOL_NOVERS($$mulU);
+#endif
 EXPORT_SYMBOL_NOVERS($$divU_3);
 EXPORT_SYMBOL_NOVERS($$divU_5);
 EXPORT_SYMBOL_NOVERS($$divU_6);
@@ -120,15 +206,25 @@
 EXPORT_SYMBOL_NOVERS($$divI_15);
 
 extern void __ashrdi3(void);
+extern void __ashldi3(void);
+extern void __lshrdi3(void);
+extern void __muldi3(void);
 
 EXPORT_SYMBOL_NOVERS(__ashrdi3);
+EXPORT_SYMBOL_NOVERS(__ashldi3);
+EXPORT_SYMBOL_NOVERS(__lshrdi3);
+EXPORT_SYMBOL_NOVERS(__muldi3);
 
 #ifdef __LP64__
 extern void __divdi3(void);
 extern void __udivdi3(void);
+extern void __umoddi3(void);
+extern void __moddi3(void);
 
 EXPORT_SYMBOL_NOVERS(__divdi3);
 EXPORT_SYMBOL_NOVERS(__udivdi3);
+EXPORT_SYMBOL_NOVERS(__umoddi3);
+EXPORT_SYMBOL_NOVERS(__moddi3);
 #endif
 
 #ifndef __LP64__
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/pci-dma.c linux-2.4.20/arch/parisc/kernel/pci-dma.c
--- linux-2.4.19/arch/parisc/kernel/pci-dma.c	2001-10-12 22:35:53.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/pci-dma.c	2002-10-29 11:18:50.000000000 +0000
@@ -1,5 +1,7 @@
 /*
-** Dynamic DMA mapping support.
+** PARISC 1.1 Dynamic DMA mapping support.
+** This implementation is for PA-RISC platforms that do not support
+** I/O TLBs (aka DMA address translation hardware).
 ** See Documentation/DMA-mapping.txt for interface definitions.
 **
 **      (c) Copyright 1999,2000 Hewlett-Packard Company
@@ -7,15 +9,10 @@
 **	(c) Copyright 2000 Philipp Rumpf <prumpf@tux.org>
 **      (c) Copyright 2000 John Marvin
 **
-** This implementation is for PA-RISC platforms that do not support
-** I/O TLBs (aka DMA address translation hardware).
-**
 ** "leveraged" from 2.3.47: arch/ia64/kernel/pci-dma.c.
 ** (I assume it's from David Mosberger-Tang but there was no Copyright)
 **
 ** AFAIK, all PA7100LC and PA7300LC platforms can use this code.
-** All PA2.0 machines but V-class can alias xxx_alloc_consistent()
-** to use regular cacheable memory.
 **
 ** - ggg
 */
@@ -117,7 +114,7 @@
 	if (end > PGDIR_SIZE)
 		end = PGDIR_SIZE;
 	do {
-		pte_t * pte = pte_alloc_kernel(pmd, vaddr);
+		pte_t * pte = pte_alloc(NULL, pmd, vaddr);
 		if (!pte)
 			return -ENOMEM;
 		if (map_pte_uncached(pte, orig_vaddr, end - vaddr, paddr_ptr))
@@ -139,7 +136,7 @@
 	do {
 		pmd_t *pmd;
 		
-		pmd = pmd_alloc_kernel(dir, vaddr);
+		pmd = pmd_alloc(NULL, dir, vaddr);
 		if (!pmd)
 			return -ENOMEM;
 		if (map_pmd_uncached(pmd, vaddr, end - vaddr, &paddr))
@@ -510,7 +507,6 @@
 	pa11_dma_sync_sg			/* dma_sync_sg */
 };
 
-struct pci_dma_ops *hppa_dma_ops;
 
 static int pcxl_proc_info(char *buf, char **start, off_t offset, int len)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/pci.c linux-2.4.20/arch/parisc/kernel/pci.c
--- linux-2.4.19/arch/parisc/kernel/pci.c	2000-12-06 19:46:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/pci.c	2002-10-29 11:18:31.000000000 +0000
@@ -6,25 +6,32 @@
  *
  * Copyright (C) 1997, 1998 Ralf Baechle
  * Copyright (C) 1999 SuSE GmbH
- * Copyright (C) 1999 Hewlett-Packard Company
- * Copyright (C) 1999, 2000 Grant Grundler
+ * Copyright (C) 1999-2001 Hewlett-Packard Company
+ * Copyright (C) 1999-2001 Grant Grundler
  */
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/init.h>		/* for __init and __devinit */
 #include <linux/pci.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>	/* for memcpy() */
+#include <linux/slab.h>
 
+#include <asm/io.h>
 #include <asm/system.h>
+#include <asm/cache.h>		/* for L1_CACHE_BYTES */
 
-#ifdef CONFIG_PCI
+#define DEBUG_RESOURCES 0
+#define DEBUG_CONFIG 0
+
+#if DEBUG_CONFIG
+# define DBGC(x...)     printk(KERN_DEBUG x)
+#else
+# define DBGC(x...)
+#endif
 
-#undef DEBUG_RESOURCES
 
-#ifdef DEBUG_RESOURCES
-#define DBG_RES(x...)	printk(x)
+#if DEBUG_RESOURCES
+#define DBG_RES(x...)	printk(KERN_DEBUG x)
 #else
 #define DBG_RES(x...)
 #endif
@@ -42,14 +49,13 @@
 struct pci_port_ops *pci_port;
 struct pci_bios_ops *pci_bios;
 
-struct pci_hba_data *hba_list = NULL;
-int hba_count = 0;
+int pci_hba_count = 0;
 
 /*
 ** parisc_pci_hba used by pci_port->in/out() ops to lookup bus data.
 */
 #define PCI_HBA_MAX 32
-static struct pci_hba_data *parisc_pci_hba[PCI_HBA_MAX];
+struct pci_hba_data *parisc_pci_hba[PCI_HBA_MAX];
 
 
 /********************************************************************
@@ -58,24 +64,31 @@
 **
 *********************************************************************/
 
-#define PCI_PORT_HBA(a) ((a)>>16)
-#define PCI_PORT_ADDR(a) ((a) & 0xffffUL)
+/* EISA port numbers and PCI port numbers share the same interface.  Some
+ * machines have both EISA and PCI adapters installed.  Rather than turn
+ * pci_port into an array, we reserve bus 0 for EISA and call the EISA
+ * routines if the access is to a port on bus 0.  We don't want to fix
+ * EISA and ISA drivers which assume port space is <= 0xffff.
+ */
 
-/* KLUGE : inb needs to be defined differently for PCI devices than
-** for other bus interfaces. Doing this at runtime sucks but is the
-** only way one driver binary can support devices on different bus types.
-**
-*/
+#ifdef CONFIG_EISA
+#define EISA_IN(size) if (EISA_bus && (b == 0)) return eisa_in##size(addr)
+#define EISA_OUT(size) if (EISA_bus && (b == 0)) return eisa_out##size(d, addr)
+#else
+#define EISA_IN(size)
+#define EISA_OUT(size)
+#endif
 
 #define PCI_PORT_IN(type, size) \
 u##size in##type (int addr) \
 { \
 	int b = PCI_PORT_HBA(addr); \
 	u##size d = (u##size) -1; \
+	EISA_IN(size); \
 	ASSERT(pci_port); /* make sure services are defined */ \
 	ASSERT(parisc_pci_hba[b]); /* make sure ioaddr are "fixed up" */ \
 	if (parisc_pci_hba[b] == NULL) { \
-		printk(KERN_WARNING "\nPCI Host Bus Adapter %d not registered. in" #size "(0x%x) returning -1\n", b, addr); \
+		printk(KERN_WARNING "\nPCI or EISA Host Bus Adapter %d not registered. in" #size "(0x%x) returning -1\n", b, addr); \
 	} else { \
 		d = pci_port->in##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr)); \
 	} \
@@ -91,6 +104,7 @@
 void out##type (u##size d, int addr) \
 { \
 	int b = PCI_PORT_HBA(addr); \
+	EISA_OUT(size); \
 	ASSERT(pci_port); \
 	pci_port->out##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr), d); \
 }
@@ -106,15 +120,13 @@
  */
 void pcibios_init(void)
 {
-	ASSERT(pci_bios != NULL);
+	if (!pci_bios)
+		return;
 
-	if (pci_bios)
-	{
-		if (pci_bios->init) {
-			(*pci_bios->init)();
-		} else {
-			printk(KERN_WARNING "pci_bios != NULL but init() is!\n");
-		}
+	if (pci_bios->init) {
+		pci_bios->init();
+	} else {
+		printk(KERN_WARNING "pci_bios != NULL but init() is!\n");
 	}
 }
 
@@ -124,17 +136,10 @@
 {
 	ASSERT(pci_bios != NULL);
 
-        /* If this is a bridge, get the current bases */
-	if (bus->self) {
-		pci_read_bridge_bases(bus);
-	}
-
-	if (pci_bios) {
-		if (pci_bios->fixup_bus) {
-			(*pci_bios->fixup_bus)(bus);
-		} else {
-			printk(KERN_WARNING "pci_bios != NULL but fixup_bus() is!\n");
-		}
+	if (pci_bios->fixup_bus) {
+		pci_bios->fixup_bus(bus);
+	} else {
+		printk(KERN_WARNING "pci_bios != NULL but fixup_bus() is!\n");
 	}
 }
 
@@ -144,14 +149,6 @@
 	return str;
 }
 
-#endif /* defined(CONFIG_PCI) */
-
-
-
-/* -------------------------------------------------------------------
-** linux-2.4: NEW STUFF 
-** --------------------
-*/
 
 /*
 ** Used in drivers/pci/quirks.c
@@ -201,19 +198,11 @@
 ** ------------------------------------
 ** PAT PDC systems need this routine. PA legacy PDC does not.
 **
-** Used by alpha/arm: 
-** alpha/kernel/pci.c:common_init_pci()
-** (or arm/kernel/pci.c:pcibios_init())
-**    drivers/pci/setup.c:pci_assign_unassigned_resources()
-**        drivers/pci/setup.c:pdev_assign_unassigned_resources()
-**            arch/<foo>/kernel/pci.c:pcibios_update_resource()
-**
-** When BAR's are configured by linux, this routine
-** will update configuration space with the "normalized"
-** address. "root" indicates where the range starts and res
-** is some portion of that range.
+** When BAR's are configured by linux, this routine will update
+** configuration space with the "normalized" address. "root" indicates
+** where the range starts and res is some portion of that range.
 **
-** For all PA-RISC systems except V-class, root->start would be zero.
+** VCLASS: For all PA-RISC systems except V-class, root->start would be zero.
 **
 ** PAT PDC can tell us which MMIO ranges are available or already in use.
 ** I/O port space and such are not memory mapped anyway for PA-Risc.
@@ -234,7 +223,7 @@
 		barnum, res->start, res->end, (int) res->flags);
 
 	if (barnum >= PCI_BRIDGE_RESOURCES) {
-		/* handled in pbus_set_ranges_data() */
+		/* handled in PCI-PCI bridge specific support */
 		return;
 	}
 
@@ -248,8 +237,7 @@
 	if (res->flags & IORESOURCE_IO) {
 		barval = PCI_PORT_ADDR(res->start);
 	} else if (res->flags & IORESOURCE_MEM) {
-		/* This should work for VCLASS too */
-		barval = res->start & 0xffffffffUL;
+		barval = PCI_BUS_ADDR(HBA_DATA(dev->bus->sysdata), res->start);
 	} else {
 		panic("pcibios_update_resource() WTF? flags not IO or MEM");
 	}
@@ -267,7 +255,7 @@
 	    == (PCI_BASE_ADDRESS_SPACE_MEMORY
 		| PCI_BASE_ADDRESS_MEM_TYPE_64)) {
 		pci_write_config_dword(dev, where+4, 0);
-		printk(KERN_WARNING "PCI: dev %s type 64-bit\n", dev->name);
+		DBGC("PCIBIOS: dev %s type 64-bit\n", dev->name);
 	}
 }
 
@@ -290,25 +278,78 @@
 pcibios_set_master(struct pci_dev *dev)
 {
 	u8 lat;
+
+	/* If someone already mucked with this, don't touch it. */
 	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
 	if (lat >= 16) return;
 
 	/*
 	** HP generally has fewer devices on the bus than other architectures.
+	** upper byte is PCI_LATENCY_TIMER.
 	*/
-	printk("PCIBIOS: Setting latency timer of %s to 128\n", dev->slot_name);
-	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
+        pci_write_config_word(dev, PCI_CACHE_LINE_SIZE,
+				(0x80 << 8) | (L1_CACHE_BYTES / sizeof(u32)));
+}
+
+
+void __init
+pcibios_init_bus(struct pci_bus *bus)
+{
+	struct pci_dev *dev = bus->self;
+
+	/* We deal only with pci controllers and pci-pci bridges. */
+	if (dev && (dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+		return;
+	
+	if (dev) {
+		/* PCI-PCI bridge - set the cache line and default latency
+		   (32) for primary and secondary buses. */
+		pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 32);
+
+		/* Read bridge control */
+		pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bus->bridge_ctl);
+	}
+
+	/* Set FBB bit for now. Disable ISA IO forwarding. Enable PERR/SERR */
+	bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK | 
+			   PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
 }
 
 
 /*
-** called by drivers/pci/setup-res.c:pbus_set_ranges().
+** KLUGE: Link the child and parent resources - generic PCI didn't
+*/
+static void
+pcibios_link_hba_resources( struct resource *hba_res, struct resource *r)
+{
+	if (!r->parent) {
+		r->parent = hba_res;
+
+		/* reverse link is harder *sigh*  */
+		if (r->parent->child) {
+			if (r->parent->sibling) {
+				struct resource *next = r->parent->sibling;
+				while (next->sibling)
+					 next = next->sibling;
+				next->sibling = r;
+			} else {
+				r->parent->sibling = r;
+			}
+		} else
+			r->parent->child = r;
+	}
+}
+
+/*
+** called by drivers/pci/setup-res.c:pci_setup_bridge().
 */
 void pcibios_fixup_pbus_ranges(
 	struct pci_bus *bus,
 	struct pbus_set_ranges_data *ranges
 	)
 {
+	struct pci_hba_data *hba = HBA_DATA(bus->sysdata);
+
 	/*
 	** I/O space may see busnumbers here. Something
 	** in the form of 0xbbxxxx where bb is the bus num
@@ -319,9 +360,20 @@
 	ranges->io_start = PCI_PORT_ADDR(ranges->io_start);
 	ranges->io_end   = PCI_PORT_ADDR(ranges->io_end);
 
+	/* Convert MMIO addr to PCI addr (undo global virtualization) */
+	ranges->mem_start = PCI_BUS_ADDR(hba, ranges->mem_start);
+	ranges->mem_end   = PCI_BUS_ADDR(hba, ranges->mem_end);
+
 	DBG_RES("pcibios_fixup_pbus_ranges(%02x, [%lx,%lx %lx,%lx])\n", bus->number,
 		ranges->io_start, ranges->io_end,
 		ranges->mem_start, ranges->mem_end);
+
+	/* KLUGE ALERT
+	** if this resource isn't linked to a "parent", then it seems
+	** to be a child of the HBA - lets link it in.
+	*/
+	pcibios_link_hba_resources(&hba->io_space, bus->resource[0]);
+	pcibios_link_hba_resources(&hba->lmmio_space, bus->resource[1]);
 }
 
 #define MAX(val1, val2)   ((val1) > (val2) ? (val1) : (val2))
@@ -337,13 +389,15 @@
 ** than res->start.
 */
 void __devinit
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res,
+		       unsigned long size, unsigned long alignment)
 {
 	unsigned long mask, align;
 
-	DBG_RES("pcibios_align_resource(%s, (%p) [%lx,%lx]/%x, 0x%lx)\n",
+	DBG_RES("pcibios_align_resource(%s, (%p) [%lx,%lx]/%x, 0x%lx, 0x%lx)\n",
 		((struct pci_dev *) data)->slot_name,
-		res->parent, res->start, res->end, (int) res->flags, size);
+		res->parent, res->start, res->end,
+		(int) res->flags, size, alignment);
 
 	/* has resource already been aligned/assigned? */
 	if (res->parent)
@@ -360,107 +414,15 @@
 	/*
 	** WARNING : caller is expected to update "end" field.
 	** We can't since it might really represent the *size*.
-	** The difference is "end = start + size" vs "end += size".
+	** The difference is "end = start + size" vs "end += start".
 	*/
 }
 
 
-#define ROUND_UP(x, a)		(((x) + (a) - 1) & ~((a) - 1))
-
-void __devinit
-pcibios_size_bridge(struct pci_bus *bus, struct pbus_set_ranges_data *outer)
-{
-	struct pbus_set_ranges_data inner;
-	struct pci_dev *dev;
-	struct pci_dev *bridge = bus->self;
-	struct list_head *ln;
-
-	/* set reasonable default "window" for pcibios_align_resource */
-	inner.io_start  = inner.io_end  = 0;
-	inner.mem_start = inner.mem_end = 0;
-
-	/* Collect information about how our direct children are layed out. */
-	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
-		int i;
-		dev = pci_dev_b(ln);
-
-		/* Skip bridges here - we'll catch them below */
-		if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
-			continue;
-
-		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-			struct resource res;
-			unsigned long size;
-
-			if (dev->resource[i].flags == 0)
-				continue;
-
-			memcpy(&res, &dev->resource[i], sizeof(res));
-			size = res.end - res.start + 1;
-
-			if (res.flags & IORESOURCE_IO) {
-				res.start = inner.io_end;
-				pcibios_align_resource(dev, &res, size);
-				inner.io_end += res.start + size;
-			} else if (res.flags & IORESOURCE_MEM) {
-				res.start = inner.mem_end;
-				pcibios_align_resource(dev, &res, size);
-				inner.mem_end = res.start + size;
-			}
-
-		DBG_RES("    %s  inner size %lx/%x IO %lx MEM %lx\n",
-			dev->slot_name,
-			size, res.flags, inner.io_end, inner.mem_end);
-		}
-	}
-
-	/* And for all of the subordinate busses. */
-	for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
-		pcibios_size_bridge(pci_bus_b(ln), &inner);
-
-	/* turn the ending locations into sizes (subtract start) */
-	inner.io_end -= inner.io_start - 1;
-	inner.mem_end -= inner.mem_start - 1;
-
-	/* Align the sizes up by bridge rules */
-	inner.io_end = ROUND_UP(inner.io_end, 4*1024) - 1;
-	inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024) - 1;
-
-	/* PPB - PCI bridge Device will normaller also have "outer" != NULL. */
-	if (bridge) {
-		/* Adjust the bus' allocation requirements */
-		/* PPB's pci device Bridge resources */
-
-		bus->resource[0] = &bridge->resource[PCI_BRIDGE_RESOURCES];
-		bus->resource[1] = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
-		
-		bus->resource[0]->start = bus->resource[1]->start  = 0;
-		bus->resource[0]->parent= bus->resource[1]->parent = NULL;
-
-		bus->resource[0]->end    = inner.io_end;
-		bus->resource[0]->flags  = IORESOURCE_IO;
-
-		bus->resource[1]->end    = inner.mem_end;
-		bus->resource[1]->flags  = IORESOURCE_MEM;
-	}
-
-	/* adjust parent's resource requirements */
-	if (outer) {
-		outer->io_end = ROUND_UP(outer->io_end, 4*1024);
-		outer->io_end += inner.io_end;
-
-		outer->mem_end = ROUND_UP(outer->mem_end, 1*1024*1024);
-		outer->mem_end += inner.mem_end;
-	}
-}
-
-#undef ROUND_UP
-
-
 int __devinit
 pcibios_enable_device(struct pci_dev *dev)
 {
-	u16 cmd, old_cmd;
+	u16 cmd;
 	int idx;
 
 	/*
@@ -468,12 +430,13 @@
 	** enable all the same bits. We just make sure they are here.
 	*/
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	old_cmd = cmd;
 
 	/*
 	** See if any resources have been allocated
+	** While "regular" PCI devices only use 0-5, Bridges use a few
+	** beyond that for window registers.
 	*/
-        for (idx=0; idx<6; idx++) {
+        for (idx=0; idx<DEVICE_COUNT_RESOURCE; idx++) {
 		struct resource *r = &dev->resource[idx];
 		if (r->flags & IORESOURCE_IO)
 			cmd |= PCI_COMMAND_IO;
@@ -482,7 +445,7 @@
 	}
 
 	/*
-	** System error and Parity Error reporting are enabled by default.
+	** Enable System error and Parity Error reporting by default.
 	** Devices that do NOT want those behaviors should clear them
 	** (eg PCI graphics, possibly networking).
 	** Interfaces like SCSI certainly should not. We want the
@@ -491,30 +454,48 @@
 	*/
 	cmd |= (PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
 
-	if (cmd != old_cmd) {
-		printk("PCIBIOS: Enabling device %s (%04x -> %04x)\n",
-			dev->slot_name, old_cmd, cmd);
-		pci_write_config_word(dev, PCI_COMMAND, cmd);
-	}
+	/* If bridge/bus controller has FBB enabled, child must too. */
+	if (dev->bus->bridge_ctl & PCI_BRIDGE_CTL_FAST_BACK)
+		cmd |= PCI_COMMAND_FAST_BACK;
 
+	DBGC("PCIBIOS: Enabling device %s cmd 0x%04x\n", dev->slot_name, cmd);
+	pci_write_config_word(dev, PCI_COMMAND, cmd);
 	return 0;
 }
 
-
-void __devinit
-pcibios_assign_unassigned_resources(struct pci_bus *bus)
+void __init
+pcibios_setup_host_bridge(struct pci_bus *bus)
 {
-	struct list_head *ln;
+	ASSERT(pci_bios != NULL);
 
-        for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next)
+#if 0
+	if (pci_bios)
 	{
-		pdev_assign_unassigned_resources(pci_dev_b(ln));
+		if (pci_bios->setup_host_bridge) {
+			(*pci_bios->setup_host_bridge)(bus);
+		}
 	}
+#endif
+}
 
-        /* And for all of the sub-busses.  */
-	for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
-		pcibios_assign_unassigned_resources(pci_bus_b(ln));
 
+/*
+** Mostly copied from drivers/pci/setup-bus.c:pci_assign_unassigned_resources()
+*/
+void __devinit
+pcibios_assign_unassigned_resources(struct pci_bus *bus)
+{
+	/* from drivers/pci/setup-bus.c */
+	extern void pbus_assign_resources(struct pci_bus *bus, struct pbus_set_ranges_data *ranges);
+
+	struct pbus_set_ranges_data ranges;
+
+	ranges.io_end = ranges.io_start
+				= bus->resource[0]->start + PCIBIOS_MIN_IO;
+	ranges.mem_end = ranges.mem_start
+				= bus->resource[1]->start + PCIBIOS_MIN_MEM;
+	ranges.found_vga = 0;
+	pbus_assign_resources(bus, &ranges);
 }
 
 /*
@@ -522,14 +503,9 @@
 */
 void pcibios_register_hba(struct pci_hba_data *hba)
 {
-	hba->next = hba_list;
-	hba_list = hba;
-
-	ASSERT(hba_count < PCI_HBA_MAX);
+	ASSERT(pci_hba_count < PCI_HBA_MAX);
 
-	/*
-	** pci_port->in/out() uses parisc_pci_hba to lookup parameter.
-	*/
-	parisc_pci_hba[hba_count] = hba;
-	hba->hba_num = hba_count++;
+	/* pci_port->in/out() uses parisc_pci_hba to lookup parameter. */
+	parisc_pci_hba[pci_hba_count] = hba;
+	hba->hba_num = pci_hba_count++;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/pdc.c linux-2.4.20/arch/parisc/kernel/pdc.c
--- linux-2.4.19/arch/parisc/kernel/pdc.c	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/pdc.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,217 +0,0 @@
-/* arch/parisc/kernel/pdc.c  - safe pdc access routines
- *
- * Copyright 1999 SuSE GmbH Nuernberg (Philipp Rumpf, prumpf@tux.org)
- * portions Copyright 1999 The Puffin Group, (Alex deVries, David Kennedy)
- *
- * only these routines should be used out of the real kernel (i.e. everything
- * using virtual addresses) for obvious reasons */
-
-/*	I think it would be in everyone's best interest to follow this
- *	guidelines when writing PDC wrappers:
- *
- *	 - the name of the pdc wrapper should match one of the macros
- *	   used for the first two arguments
- *	 - don't use caps for random parts of the name
- *	 - use ASSERT_ALIGN to ensure the aligment of the arguments is
- *	   correct
- *	 - use __pa() to convert virtual (kernel) pointers to physical
- *	   ones.
- *	 - the name of the struct used for pdc return values should equal
- *	   one of the macros used for the first two arguments to the
- *	   corresponding PDC call
- *	 - keep the order of arguments
- *	 - don't be smart (setting trailing NUL bytes for strings, return
- *	   something useful even if the call failed) unless you are sure
- *	   it's not going to affect functionality or performance
- *
- *	Example:
- *	int pdc_cache_info(struct pdc_cache_info *cache_info )
- *	{
- *		ASSERT_ALIGN(cache_info, 8);
- *	
- *		return mem_pdc_call(PDC_CACHE,PDC_CACHE_INFO,__pa(cache_info),0);
- *	}
- *					prumpf	991016	
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-
-#include <asm/page.h>
-#include <asm/pdc.h>
-#include <asm/real.h>
-#include <asm/system.h>
-
-
-#define ASSERT_ALIGN(ptr, align)					\
-	do { if(((unsigned long)(ptr)) & (align-1)) {			\
-		printk("PDC: %s:%d  %s() called with "	\
-			"unaligned argument from %p", __FILE__, __LINE__, \
-			__FUNCTION__, __builtin_return_address(0));	\
-									\
-		return -1;						\
-	} } while(0)
-	
-/* verify address can be accessed without an HPMC */
-int pdc_add_valid(void *address)
-{
-	ASSERT_ALIGN(address, 4);
-
-	return mem_pdc_call(PDC_ADD_VALID, PDC_ADD_VALID_VERIFY, (unsigned long)address);
-}
-
-#if 0
-int pdc_chassis_warn(struct pdc_chassis_warn *address)
-{
-	ASSERT_ALIGN(address, 4);
-
-	return mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_WARN, __pa(address), 0);
-}
-#endif
-
-int pdc_chassis_disp(unsigned long disp)
-{
-	return mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_DISP, disp);
-}
-
-int pdc_chassis_info(void *pdc_result, void *chassis_info, unsigned long len)
-{
-	ASSERT_ALIGN(pdc_result, 4);
-	ASSERT_ALIGN(chassis_info, 4);
-	return mem_pdc_call(PDC_CHASSIS,PDC_RETURN_CHASSIS_INFO, 
-	        __pa(pdc_result), __pa(chassis_info), len);
-}
-
-int pdc_hpa_processor(void *address)
-{
-	/* We're using 0 for the last parameter just to make sure.
-	   It's actually HVERSION dependant.  And remember, life is
-	   hard without a backspace. */
-	ASSERT_ALIGN(address, 4);
-
-	return mem_pdc_call(PDC_HPA, PDC_HPA_PROCESSOR, __pa(address),0);
-}
-
-#if 0
-int pdc_hpa_modules(void *address)
-{
-	return mem_pdc_call(PDC_HPA, PDC_HPA_MODULES, address);
-}
-#endif
-
-int pdc_iodc_read(void *address, void * hpa, unsigned int index,
-	void * iodc_data, unsigned int iodc_data_size)
-{
-	ASSERT_ALIGN(address, 4);
-	ASSERT_ALIGN(iodc_data, 8);
-	return mem_pdc_call(PDC_IODC, PDC_IODC_READ, 
-		__pa(address), hpa, index, __pa(iodc_data), iodc_data_size);
-}
-
-
-int pdc_system_map_find_mods(void *pdc_mod_info, 
-	void *mod_path, int index)
-{
-	return mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE,
-		__pa(pdc_mod_info), __pa(mod_path), (long)index);
-}
-
-
-int pdc_model_info(struct pdc_model *model) {
-	ASSERT_ALIGN(model, 8);
-	return mem_pdc_call(PDC_MODEL,PDC_MODEL_INFO,__pa(model),0);
-}
-
-/* get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L) */ 
-int pdc_model_sysmodel(char * name)
-{
-	struct pdc_model_sysmodel sys_model;
-	int retval;
-	
-	ASSERT_ALIGN(&sys_model, 8);
-	ASSERT_ALIGN(name, 4);
-
-	sys_model.mod_len = 0;
-	retval = mem_pdc_call(PDC_MODEL,PDC_MODEL_SYSMODEL,__pa(&sys_model),
-		    OS_ID_HPUX,__pa(name));
-	
-	if (retval == PDC_RET_OK) 
-	    name[sys_model.mod_len] = '\0'; /* add trailing '\0' */
-	else
-	    name[0] = 0;
-	
-	return retval;
-}
-
-/* id: 0 = cpu revision, 1 = boot-rom-version */
-int pdc_model_versions(struct pdc_model_cpuid *cpu_id, int id) {
-	return mem_pdc_call(PDC_MODEL,PDC_MODEL_VERSIONS,__pa(cpu_id),id);
-}
-
-int pdc_model_cpuid(struct pdc_model_cpuid *cpu_id) {
-	cpu_id->cpuid = 0; /* preset zero (call maybe not implemented!) */
-	return mem_pdc_call(PDC_MODEL,6,__pa(cpu_id),0);  /* 6="return CPU ID" */
-}
-
-int pdc_cache_info(struct pdc_cache_info *cache_info) {
-	ASSERT_ALIGN(cache_info, 8);
-
-	return mem_pdc_call(PDC_CACHE,PDC_CACHE_INFO,__pa(cache_info),0);
-}
-
-#ifndef __LP64__
-int pdc_btlb_info( struct pdc_btlb_info *btlb ) {
-	int status;
-	status = mem_pdc_call(PDC_BLOCK_TLB,PDC_BTLB_INFO,__pa(btlb),0);
-	if (status<0) btlb->max_size = 0;
-	return status;
-}
-
-int pdc_mem_map_hpa(void *r_addr, void *mod_path) {
-	return mem_pdc_call(PDC_MEM_MAP,PDC_MEM_MAP_HPA,
-		__pa(r_addr),__pa(mod_path));
-}
-
-int pdc_lan_station_id(char *lan_addr, void *net_hpa) {
-	struct pdc_lan_station_id id;
-	unsigned char *addr;
-	
-	if (mem_pdc_call(PDC_LAN_STATION_ID, PDC_LAN_STATION_ID_READ,
-			__pa(&id), net_hpa) < 0)
-		addr = 0;	/* FIXME: else read MAC from NVRAM */
-	    else
-		addr = id.addr;
-	if (addr)
-		memmove( lan_addr, addr, PDC_LAN_STATION_ID_SIZE);
-	    else
-		memset( lan_addr, 0, PDC_LAN_STATION_ID_SIZE);
-	return (addr != 0);
-}
-#endif
-
-
-/* Similar to PDC_PAT stuff in pdcpat.c - but added for Forte/Allegro boxes */
-int pdc_pci_irt_size(void *r_addr, void *hpa)
-{
-	return mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SIZE,
-		__pa(r_addr), hpa);
-
-}
-
-int pdc_pci_irt(void *r_addr, void *hpa, void *tbl)
-{
-	return mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL,
-		__pa(r_addr), hpa, __pa(tbl));
-}
-
-/* access the TOD clock */
-int pdc_tod_read(struct pdc_tod *tod)
-{
-	ASSERT_ALIGN(tod, 8);
-	return mem_pdc_call(PDC_TOD, PDC_TOD_READ, __pa(tod), 0);
-}
-
-int pdc_tod_set(unsigned long sec, unsigned long usec)
-{
-	return mem_pdc_call(PDC_TOD, PDC_TOD_WRITE, sec, usec);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/pdc_cons.c linux-2.4.20/arch/parisc/kernel/pdc_cons.c
--- linux-2.4.19/arch/parisc/kernel/pdc_cons.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/pdc_cons.c	2002-10-29 11:18:35.000000000 +0000
@@ -1,100 +1,49 @@
+/*
+ *  linux/arch/parisc/kernel/pdc_console.c
+ *
+ *  The PDC console is a simple console, which can be used for debugging 
+ *  boot related problems on HP PA-RISC machines.
+ *
+ *  This code uses the ROM (=PDC) based functions to read and write characters
+ *  from and to PDC's boot path.
+ *  Since all character read from that path must be polled, this code never
+ *  can or will be a fully functional linux console.
+ */
+
+/* Define EARLY_BOOTUP_DEBUG to debug kernel related boot problems. 
+ * On production kernels EARLY_BOOTUP_DEBUG should be undefined. */
+#undef EARLY_BOOTUP_DEBUG
+
+
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/console.h>
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <asm/page.h>
 #include <asm/types.h>
 #include <asm/system.h>
-#include <asm/pdc.h>	/* for iodc_call() proto and friends */
-#include <asm/real.h>
+#include <asm/pdc.h>		/* for iodc_call() proto and friends */
 
-static int __attribute__((aligned(8)))   iodc_retbuf[32];
-static char __attribute__((aligned(64))) iodc_dbuf[4096];
-
-/*
- * pdc_putc:
- * Console character print using IODC.
- *
- * Note that only these special chars are architected for console IODC io:
- * BEL, BS, CR, and LF. Others are passed through.
- * Since the HP console requires CR+LF to perform a 'newline', we translate
- * "\n" to "\r\n".
- */
-
-static int posx;	/* for simple TAB-Simulation... */
-
-/* XXX Should we spinlock posx usage */
-
-void pdc_putc(unsigned char c)
-{
-	unsigned int n;
-	unsigned long flags;
-
-	switch (c) {
-	case '\n':
-		iodc_dbuf[0] = '\r'; 
-		iodc_dbuf[1] = '\n';
-               	n = 2;
-               	posx = 0;
-		break;
-	case '\t':
-		pdc_putc(' ');
-		while (posx & 7) 	/* expand TAB */
-			pdc_putc(' ');
-		return;		/* return since IODC can't handle this */
-	case '\b':
-		posx-=2;		/* BS */
-	default:
-		iodc_dbuf[0] = c;
-		n = 1;
-		posx++;
-		break;
-	}
-	{
-		real32_call(PAGE0->mem_cons.iodc_io,
-			(unsigned long)PAGE0->mem_cons.hpa, ENTRY_IO_COUT,
-			PAGE0->mem_cons.spa, __pa(PAGE0->mem_cons.dp.layers),
-			__pa(iodc_retbuf), 0, __pa(iodc_dbuf), n, 0);
-	}
-}
 
 static void pdc_console_write(struct console *co, const char *s, unsigned count)
 {
 	while(count--)
-		pdc_putc(*s++);
+		pdc_iodc_putc(*s++);
 }
 
-int pdc_console_wait_key(struct console *co)
+void pdc_outc(unsigned char c)
 {
-	int ch = 'X';
-	int status;
-
-	/* Bail if no console input device. */
-	if (!PAGE0->mem_kbd.iodc_io)
-		return 0;
-	
-	/* wait for a keyboard (rs232)-input */
-	do {
-		unsigned long flags;
-
-		save_flags(flags);
-		cli();
-		status = real32_call(PAGE0->mem_kbd.iodc_io,
-			(unsigned long)PAGE0->mem_kbd.hpa, ENTRY_IO_CIN,
-			PAGE0->mem_kbd.spa, __pa(PAGE0->mem_kbd.dp.layers),
-			__pa(iodc_retbuf), 0, __pa(iodc_dbuf), 1, 0);
-		restore_flags(flags);
-		ch = *iodc_dbuf;	/* save the character directly to ch */
-	} while (*iodc_retbuf == 0);	/* wait for a key */
-	return ch;
+	pdc_iodc_outc(c);
 }
 
-int pdc_getc(void)
+
+int pdc_console_poll_key(struct console *co)
 {
-	return pdc_console_wait_key(NULL);
+	return pdc_iodc_getc();
 }
 
 static int pdc_console_setup(struct console *co, char *options)
@@ -102,17 +51,34 @@
 	return 0;
 }
 
+#ifdef CONFIG_PDC_CONSOLE
+static kdev_t pdc_console_device (struct console *c)
+{
+        return MKDEV(PDCCONS_MAJOR, 0);
+}
+#endif
+
+#ifdef CONFIG_PDC_CONSOLE
+#define PDC_CONSOLE_DEVICE pdc_console_device
+#else
+#define PDC_CONSOLE_DEVICE NULL
+#endif
+
 static struct console pdc_cons = {
 	name:		"ttyB",
 	write:		pdc_console_write,
+ 	device:		PDC_CONSOLE_DEVICE,
 	setup:		pdc_console_setup,
-	flags:		CON_PRINTBUFFER|CON_ENABLED,  // |CON_CONSDEV,
+	flags:		CON_BOOT|CON_PRINTBUFFER|CON_ENABLED,
 	index:		-1,
 };
 
 static int pdc_console_initialized;
 
-void pdc_console_init(void)
+extern unsigned long con_start;	/* kernel/printk.c */
+extern unsigned long log_end;	/* kernel/printk.c */
+  
+static void pdc_console_init_force(void)
 {
 	if (pdc_console_initialized)
 		return;
@@ -122,23 +88,32 @@
 	if (PAGE0->mem_cons.cl_class == CL_DUPLEX)
 		memcpy(&PAGE0->mem_kbd, &PAGE0->mem_cons, sizeof(PAGE0->mem_cons));
 
-	pdc_console_write(0, "PDC Console Initialized\n", 24);
 	/* register the pdc console */
 	register_console(&pdc_cons);
 }
 
+void pdc_console_init(void)
+{
+#if defined(EARLY_BOOTUP_DEBUG) || defined(CONFIG_PDC_CONSOLE)
+	pdc_console_init_force();
+#endif
+#ifdef EARLY_BOOTUP_DEBUG
+	printk(KERN_INFO "Initialized PDC Console for debugging.\n");
+#endif
+}
+
 
 /* Unregister the pdc console with the printk console layer */
 void pdc_console_die(void)
 {
-	printk("Switching from PDC console\n");
 	if (!pdc_console_initialized)
 		return;
 	--pdc_console_initialized;
-	
-#ifdef CONFIG_VT_CONSOLE
-	schedule_console_callback();
-#endif
+
+	printk(KERN_INFO "Switching from PDC console\n");
+
+	/* Don't repeat what we've already printed */
+	con_start = log_end;
 
 	unregister_console(&pdc_cons);
 }
@@ -155,17 +130,17 @@
 void pdc_console_restart(void)
 {
 	struct console *console;
-	extern int log_size;
 
 	if (pdc_console_initialized)
 		return;
 
-	while ((console = console_drivers) != (struct console *)0)
+	while ((console = console_drivers) != NULL)
 		unregister_console(console_drivers);
 
-	log_size = 0;
-	pdc_console_init();
-	printk("Switched to PDC console\n");
-	return;
+	/* Don't repeat what we've already printed */
+	con_start = log_end;
+	
+	/* force registering the pdc console */
+	pdc_console_init_force();
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/perf.c linux-2.4.20/arch/parisc/kernel/perf.c
--- linux-2.4.19/arch/parisc/kernel/perf.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/perf.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,838 @@
+/*
+ *  Parisc performance counters
+ *  Copyright (C) 2001 Randolph Chung <tausq@debian.org>
+ *
+ *  This code is derived, with permission, from HP/UX sources.
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *  Edited comment from original sources:
+ *
+ *  This driver programs the PCX-U/PCX-W performance counters
+ *  on the PA-RISC 2.0 chips.  The driver keeps all images now
+ *  internally to the kernel to hopefully eliminate the possiblity
+ *  of a bad image halting the CPU.  Also, there are different
+ *  images for the PCX-W and later chips vs the PCX-U chips.
+ *
+ *  Only 1 process is allowed to access the driver at any time,
+ *  so the only protection that is needed is at open and close.
+ *  A variable "perf_enabled" is used to hold the state of the
+ *  driver.  The spinlock "perf_lock" is used to protect the
+ *  modification of the state during open/close operations so
+ *  multiple processes don't get into the driver simultaneously.
+ *
+ *  This driver accesses the processor directly vs going through
+ *  the PDC INTRIGUE calls.  This is done to eliminate bugs introduced
+ *  in various PDC revisions.  The code is much more maintainable
+ *  and reliable this way vs having to debug on every version of PDC
+ *  on every box. 
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+
+#include <asm/gsc.h>
+#include <asm/uaccess.h>
+#include <asm/perf.h>
+#include <asm/processor.h>
+
+#include "perf_images.h"
+
+#define MAX_RDR_WORDS	24
+#define PERF_VERSION	2	/* derived from hpux's PI v2 interface */
+
+/* definition of RDR regs */
+struct rdr_tbl_ent {
+	uint16_t	width;
+	uint8_t		num_words;
+	uint8_t		write_control;
+};
+
+static int perf_processor_interface = UNKNOWN_INTF;
+static int perf_enabled = 0;
+static spinlock_t perf_lock;
+struct parisc_device *cpu_device = NULL;
+
+/* RDRs to write for PCX-W */
+static int perf_rdrs_W[] = 
+	{ 0, 1, 4, 5, 6, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, -1 };
+
+/* RDRs to write for PCX-U */
+static int perf_rdrs_U[] =
+	{ 0, 1, 4, 5, 6, 7, 16, 17, 18, 20, 21, 22, 23, 24, 25, -1 };
+
+/* RDR register descriptions for PCX-W */
+static struct rdr_tbl_ent perf_rdr_tbl_W[] = {
+	{ 19,	1,	8 },   /* RDR 0 */
+	{ 16,	1,	16 },  /* RDR 1 */
+	{ 72,	2,	0 },   /* RDR 2 */
+	{ 81,	2,	0 },   /* RDR 3 */
+	{ 328,	6,	0 },   /* RDR 4 */
+	{ 160,	3,	0 },   /* RDR 5 */
+	{ 336,	6,	0 },   /* RDR 6 */
+	{ 164,	3,	0 },   /* RDR 7 */
+	{ 0,	0,	0 },   /* RDR 8 */
+	{ 35,	1,	0 },   /* RDR 9 */
+	{ 6,	1,	0 },   /* RDR 10 */
+	{ 18,	1,	0 },   /* RDR 11 */
+	{ 13,	1,	0 },   /* RDR 12 */
+	{ 8,	1,	0 },   /* RDR 13 */
+	{ 8,	1,	0 },   /* RDR 14 */
+	{ 8,	1,	0 },   /* RDR 15 */
+	{ 1530,	24,	0 },   /* RDR 16 */
+	{ 16,	1,	0 },   /* RDR 17 */
+	{ 4,	1,	0 },   /* RDR 18 */
+	{ 0,	0,	0 },   /* RDR 19 */
+	{ 152,	3,	24 },  /* RDR 20 */
+	{ 152,	3,	24 },  /* RDR 21 */
+	{ 233,	4,	48 },  /* RDR 22 */
+	{ 233,	4,	48 },  /* RDR 23 */
+	{ 71,	2,	0 },   /* RDR 24 */
+	{ 71,	2,	0 },   /* RDR 25 */
+	{ 11,	1,	0 },   /* RDR 26 */
+	{ 18,	1,	0 },   /* RDR 27 */
+	{ 128,	2,	0 },   /* RDR 28 */
+	{ 0,	0,	0 },   /* RDR 29 */
+	{ 16,	1,	0 },   /* RDR 30 */
+	{ 16,	1,	0 },   /* RDR 31 */
+};
+
+/* RDR register descriptions for PCX-U */
+static struct rdr_tbl_ent perf_rdr_tbl_U[] = {
+	{ 19,	1,	8 },              /* RDR 0 */
+	{ 32,	1,	16 },             /* RDR 1 */
+	{ 20,	1,	0 },              /* RDR 2 */
+	{ 0,	0,	0 },              /* RDR 3 */
+	{ 344,	6,	0 },              /* RDR 4 */
+	{ 176,	3,	0 },              /* RDR 5 */
+	{ 336,	6,	0 },              /* RDR 6 */
+	{ 0,	0,	0 },              /* RDR 7 */
+	{ 0,	0,	0 },              /* RDR 8 */
+	{ 0,	0,	0 },              /* RDR 9 */
+	{ 28,	1,	0 },              /* RDR 10 */
+	{ 33,	1,	0 },              /* RDR 11 */
+	{ 0,	0,	0 },              /* RDR 12 */
+	{ 230,	4,	0 },              /* RDR 13 */
+	{ 32,	1,	0 },              /* RDR 14 */
+	{ 128,	2,	0 },              /* RDR 15 */
+	{ 1494,	24,	0 },              /* RDR 16 */
+	{ 18,	1,	0 },              /* RDR 17 */
+	{ 4,	1,	0 },              /* RDR 18 */
+	{ 0,	0,	0 },              /* RDR 19 */
+	{ 158,	3,	24 },             /* RDR 20 */
+	{ 158,	3,	24 },             /* RDR 21 */
+	{ 194,	4,	48 },             /* RDR 22 */
+	{ 194,	4,	48 },             /* RDR 23 */
+	{ 71,	2,	0 },              /* RDR 24 */
+	{ 71,	2,	0 },              /* RDR 25 */
+	{ 28,	1,	0 },              /* RDR 26 */
+	{ 33,	1,	0 },              /* RDR 27 */
+	{ 88,	2,	0 },              /* RDR 28 */
+	{ 32,	1,	0 },              /* RDR 29 */
+	{ 24,	1,	0 },              /* RDR 30 */
+	{ 16,	1,	0 },              /* RDR 31 */
+};
+
+/*
+ * A non-zero write_control in the above tables is a byte offset into
+ * this array.
+ */
+static uint64_t perf_bitmasks[] = {
+	0x0000000000000000,     /* first dbl word must be zero */
+	0xfdffe00000000000,     /* RDR0 bitmask */
+	0x003f000000000000,     /* RDR1 bitmask */
+	0x00ffffffffffffff,     /* RDR20-RDR21 bitmask (152 bits) */
+	0xffffffffffffffff,
+	0xfffffffc00000000,
+	0xffffffffffffffff,     /* RDR22-RDR23 bitmask (233 bits) */
+	0xffffffffffffffff,
+	0xfffffffffffffffc,
+	0xff00000000000000
+};
+
+/*
+ * Write control bitmasks for Pa-8700 processor given
+ * somethings have changed slightly.
+ */
+static uint64_t perf_bitmasks_piranha[] = {
+	0x0000000000000000,     /* first dbl word must be zero */
+	0xfdffe00000000000,     /* RDR0 bitmask */
+	0x003f000000000000,     /* RDR1 bitmask */
+	0x00ffffffffffffff,     /* RDR20-RDR21 bitmask (158 bits) */
+	0xffffffffffffffff,
+	0xfffffffc00000000,
+	0xffffffffffffffff,     /* RDR22-RDR23 bitmask (210 bits) */
+	0xffffffffffffffff,
+	0xffffffffffffffff,
+	0xfffc000000000000
+};
+
+static uint64_t *bitmask_array;   /* array of bitmasks to use */
+
+/******************************************************************************
+ * Function Prototypes
+ *****************************************************************************/
+static int perf_config(uint32_t *image_ptr);
+static int perf_release(struct inode *inode, struct file *file);
+static int perf_open(struct inode *inode, struct file *file);
+static ssize_t perf_read(struct file *file, char *buf, size_t cnt, loff_t *ppos);
+static ssize_t perf_write(struct file *file, const char *buf, size_t count, 
+	loff_t *ppos);
+static int perf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg);
+static void perf_start_counters(void);
+static int perf_stop_counters(uint32_t *raddr);
+static struct rdr_tbl_ent * perf_rdr_get_entry(uint32_t rdr_num);
+static int perf_rdr_read_ubuf(uint32_t	rdr_num, uint64_t *buffer);
+static int perf_rdr_clear(uint32_t rdr_num);
+static int perf_write_image(uint64_t *memaddr);
+static void perf_rdr_write(uint32_t rdr_num, uint64_t *buffer);
+
+/* External Assembly Routines */
+extern uint64_t perf_rdr_shift_in_W (uint32_t rdr_num, uint16_t width);
+extern uint64_t perf_rdr_shift_in_U (uint32_t rdr_num, uint16_t width);
+extern void perf_rdr_shift_out_W (uint32_t rdr_num, uint64_t buffer);
+extern void perf_rdr_shift_out_U (uint32_t rdr_num, uint64_t buffer);
+extern void perf_intrigue_enable_perf_counters (void);
+extern void perf_intrigue_disable_perf_counters (void);
+
+/******************************************************************************
+ * Function Definitions
+ *****************************************************************************/
+
+
+/*
+ * configure:
+ *
+ * Configure the cpu with a given data image.  First turn off the counters, 
+ * then download the image, then turn the counters back on.
+ */
+static int perf_config(uint32_t *image_ptr)
+{
+	long error;
+	uint32_t raddr[4];
+
+	/* Stop the counters*/
+	error = perf_stop_counters(raddr);
+	if (error != 0) {
+		printk("perf_config: perf_stop_counters = %ld\n", error);
+		return -EINVAL; 
+	}
+
+printk("Preparing to write image\n");
+	/* Write the image to the chip */
+	error = perf_write_image((uint64_t *)image_ptr);
+	if (error != 0) {
+		printk("perf_config: DOWNLOAD = %ld\n", error);
+		return -EINVAL; 
+	}
+
+printk("Preparing to start counters\n");
+
+	/* Start the counters */
+	perf_start_counters();
+
+	return sizeof(uint32_t);
+}
+
+/*
+ * Open the device and initialize all of it's memory.  The device is only 
+ * opened once, but can be "queried" by multiple processes that know its
+ * file descriptor.
+ */
+static int perf_open(struct inode *inode, struct file *file)
+{
+	spin_lock(&perf_lock);
+	if (perf_enabled) {
+		spin_unlock(&perf_lock);
+		return -EBUSY;
+	}
+	perf_enabled = 1;
+ 	spin_unlock(&perf_lock);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+/*
+ * Close the device.
+ */
+static int perf_release(struct inode *inode, struct file *file)
+{
+	spin_lock(&perf_lock);
+	perf_enabled = 0;
+	spin_unlock(&perf_lock);
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+/*
+ * Read does nothing for this driver
+ */
+static ssize_t perf_read(struct file *file, char *buf, size_t cnt, loff_t *ppos)
+{
+	return 0;
+}
+
+/*
+ * write:
+ *
+ * This routine downloads the image to the chip.  It must be
+ * called on the processor that the download should happen
+ * on.
+ */
+static ssize_t perf_write(struct file *file, const char *buf, size_t count, 
+	loff_t *ppos)
+{
+	int err;
+	size_t image_size;
+	uint32_t image_type;
+	uint32_t interface_type;
+	uint32_t test;
+
+	if (perf_processor_interface == ONYX_INTF) 
+		image_size = PCXU_IMAGE_SIZE;
+	else if (perf_processor_interface == CUDA_INTF) 
+		image_size = PCXW_IMAGE_SIZE;
+	else 
+		return -EFAULT;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (count != sizeof(uint32_t))
+		return -EIO;
+
+	if ((err = copy_from_user(&image_type, buf, sizeof(uint32_t))) != 0) 
+		return err;
+
+	/* Get the interface type and test type */
+   	interface_type = (image_type >> 16) & 0xffff;
+	test           = (image_type & 0xffff);
+
+	/* Make sure everything makes sense */
+
+	/* First check the machine type is correct for
+	   the requested image */
+        if (((perf_processor_interface == CUDA_INTF) &&
+		       (interface_type != CUDA_INTF)) ||
+	    ((perf_processor_interface == ONYX_INTF) &&
+	               (interface_type != ONYX_INTF))) 
+		return -EINVAL;
+
+	/* Next check to make sure the requested image
+	   is valid */
+	if (((interface_type == CUDA_INTF) && 
+		       (test >= MAX_CUDA_IMAGES)) ||
+	    ((interface_type == ONYX_INTF) && 
+		       (test >= MAX_ONYX_IMAGES))) 
+		return -EINVAL;
+
+	/* Copy the image into the processor */
+	if (interface_type == CUDA_INTF) 
+		return perf_config(cuda_images[test]);
+	else
+		return perf_config(onyx_images[test]);
+
+	return count;
+}
+
+/*
+ * Patch the images that need to know the IVA addresses.
+ */
+static void perf_patch_images(void)
+{
+#if 0 /* FIXME!! */
+/* 
+ * NOTE:  this routine is VERY specific to the current TLB image.
+ * If the image is changed, this routine might also need to be changed.
+ */
+	extern void $i_itlb_miss_2_0();
+	extern void $i_dtlb_miss_2_0();
+	extern void PA2_0_iva();
+
+	/* 
+	 * We can only use the lower 32-bits, the upper 32-bits should be 0
+	 * anyway given this is in the kernel 
+	 */
+	uint32_t itlb_addr  = (uint32_t)&($i_itlb_miss_2_0);
+	uint32_t dtlb_addr  = (uint32_t)&($i_dtlb_miss_2_0);
+	uint32_t IVAaddress = (uint32_t)&PA2_0_iva;
+
+	if (perf_processor_interface == ONYX_INTF) {
+		/* clear last 2 bytes */
+		onyx_images[TLBMISS][15] &= 0xffffff00;  
+		/* set 2 bytes */
+		onyx_images[TLBMISS][15] |= (0x000000ff&((dtlb_addr) >> 24));
+		onyx_images[TLBMISS][16] = (dtlb_addr << 8)&0xffffff00;
+		onyx_images[TLBMISS][17] = itlb_addr;
+
+		/* clear last 2 bytes */
+		onyx_images[TLBHANDMISS][15] &= 0xffffff00;  
+		/* set 2 bytes */
+		onyx_images[TLBHANDMISS][15] |= (0x000000ff&((dtlb_addr) >> 24));
+		onyx_images[TLBHANDMISS][16] = (dtlb_addr << 8)&0xffffff00;
+		onyx_images[TLBHANDMISS][17] = itlb_addr;
+
+		/* clear last 2 bytes */
+		onyx_images[BIG_CPI][15] &= 0xffffff00;  
+		/* set 2 bytes */
+		onyx_images[BIG_CPI][15] |= (0x000000ff&((dtlb_addr) >> 24));
+		onyx_images[BIG_CPI][16] = (dtlb_addr << 8)&0xffffff00;
+		onyx_images[BIG_CPI][17] = itlb_addr;
+
+	    onyx_images[PANIC][15] &= 0xffffff00;  /* clear last 2 bytes */
+	 	onyx_images[PANIC][15] |= (0x000000ff&((IVAaddress) >> 24)); /* set 2 bytes */
+		onyx_images[PANIC][16] = (IVAaddress << 8)&0xffffff00;
+
+
+	} else if (perf_processor_interface == CUDA_INTF) {
+		/* Cuda interface */
+		cuda_images[TLBMISS][16] =  
+			(cuda_images[TLBMISS][16]&0xffff0000) |
+			((dtlb_addr >> 8)&0x0000ffff);
+		cuda_images[TLBMISS][17] = 
+			((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff);
+		cuda_images[TLBMISS][18] = (itlb_addr << 16)&0xffff0000;
+
+		cuda_images[TLBHANDMISS][16] = 
+			(cuda_images[TLBHANDMISS][16]&0xffff0000) |
+			((dtlb_addr >> 8)&0x0000ffff);
+		cuda_images[TLBHANDMISS][17] = 
+			((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff);
+		cuda_images[TLBHANDMISS][18] = (itlb_addr << 16)&0xffff0000;
+
+		cuda_images[BIG_CPI][16] = 
+			(cuda_images[BIG_CPI][16]&0xffff0000) |
+			((dtlb_addr >> 8)&0x0000ffff);
+		cuda_images[BIG_CPI][17] = 
+			((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff);
+		cuda_images[BIG_CPI][18] = (itlb_addr << 16)&0xffff0000;
+	} else {
+		/* Unknown type */
+	}
+#endif
+}
+
+
+/*
+ * ioctl routine
+ * All routines effect the processor that they are executed on.  Thus you 
+ * must be running on the processor that you wish to change.
+ */
+
+static int perf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	long error_start;
+	uint32_t raddr[4];	
+
+	switch (cmd) {
+
+	    case PA_PERF_ON:
+			/* Start the counters */
+			perf_start_counters();
+			return 0;
+
+	    case PA_PERF_OFF:
+			error_start = perf_stop_counters(raddr);
+			if (error_start != 0) {
+				printk(KERN_ERR "perf_off: perf_stop_counters = %ld\n", error_start);
+				return -EFAULT;	
+			}
+
+			/* copy out the Counters */
+			if (copy_to_user((void *)arg, raddr, 
+					sizeof (raddr)) != 0) {
+				return -EFAULT;
+			}
+			return 0;
+
+	    case PA_PERF_VERSION:
+  	  		/* Return the version # */
+			return put_user(PERF_VERSION, (int *)arg);
+
+	    default:
+  	 		break;
+	}
+	return -ENOTTY;
+}
+
+static struct file_operations perf_fops = {
+	llseek: no_llseek,
+	read: perf_read,
+	write: perf_write,
+	ioctl: perf_ioctl,
+	open: perf_open,
+	release: perf_release
+};
+	
+static struct miscdevice perf_dev = {
+	MISC_DYNAMIC_MINOR,
+	PA_PERF_DEV,
+	&perf_fops
+};
+
+/*
+ * Initialize the module
+ */
+static int __init perf_init(void)
+{
+	/* Determine correct processor interface to use */
+	bitmask_array = perf_bitmasks;
+
+	if (boot_cpu_data.cpu_type == pcxu ||
+	    boot_cpu_data.cpu_type == pcxu_) {
+		perf_processor_interface = ONYX_INTF;
+	} else if (boot_cpu_data.cpu_type == pcxw ||
+		 boot_cpu_data.cpu_type == pcxw_ ||
+		 boot_cpu_data.cpu_type == pcxw2) {
+		perf_processor_interface = CUDA_INTF;
+		if (boot_cpu_data.cpu_type == pcxw2) 
+			bitmask_array = perf_bitmasks_piranha;
+	} else {
+		perf_processor_interface = UNKNOWN_INTF;
+		printk("Performance monitoring counters not supported on this processor\n");
+		return -ENODEV;
+	}
+
+	/* Patch the images to match the system */
+    	perf_patch_images();
+
+	spin_lock_init(&perf_lock);
+	misc_register(&perf_dev);
+
+	/* TODO: this only lets us access the first cpu.. what to do for SMP? */
+	cpu_device = cpu_data[0].dev;
+	printk("Performance monitoring counters enabled for %s\n",
+		cpu_data[0].dev->name);
+
+	return 0;
+}
+
+/*
+ * perf_start_counters(void)
+ *
+ * Start the counters.
+ */
+static void perf_start_counters(void)
+{
+	/* Enable performance monitor counters */
+	perf_intrigue_enable_perf_counters();
+}
+
+/*
+ * perf_stop_counters
+ *
+ * Stop the performance counters and save counts
+ * in a per_processor array.
+ */
+static int perf_stop_counters(uint32_t *raddr)
+{
+	uint64_t userbuf[MAX_RDR_WORDS];
+
+	/* Disable performance counters */
+	perf_intrigue_disable_perf_counters();
+
+	if (perf_processor_interface == ONYX_INTF) {
+		uint64_t tmp64;
+		/*
+		 * Read the counters
+		 */
+		if (!perf_rdr_read_ubuf(16, userbuf))
+			return -13;
+
+		/* Counter0 is bits 1398 thru 1429 */
+		tmp64 =  (userbuf[21] << 22) & 0x00000000ffc00000;
+		tmp64 |= (userbuf[22] >> 42) & 0x00000000003fffff;
+		/* OR sticky0 (bit 1430) to counter0 bit 32 */
+		tmp64 |= (userbuf[22] >> 10) & 0x0000000080000000;
+		raddr[0] = (uint32_t)tmp64;
+
+		/* Counter1 is bits 1431 thru 1462 */
+		tmp64 =  (userbuf[22] >> 9) & 0x00000000ffffffff;
+		/* OR sticky1 (bit 1463) to counter1 bit 32 */
+		tmp64 |= (userbuf[22] << 23) & 0x0000000080000000;
+		raddr[1] = (uint32_t)tmp64;
+
+		/* Counter2 is bits 1464 thru 1495 */
+		tmp64 =  (userbuf[22] << 24) & 0x00000000ff000000;
+		tmp64 |= (userbuf[23] >> 40) & 0x0000000000ffffff;
+		/* OR sticky2 (bit 1496) to counter2 bit 32 */
+		tmp64 |= (userbuf[23] >> 8) & 0x0000000080000000;
+		raddr[2] = (uint32_t)tmp64;
+		
+		/* Counter3 is bits 1497 thru 1528 */
+		tmp64 =  (userbuf[23] >> 7) & 0x00000000ffffffff;
+		/* OR sticky3 (bit 1529) to counter3 bit 32 */
+		tmp64 |= (userbuf[23] << 25) & 0x0000000080000000;
+		raddr[3] = (uint32_t)tmp64;
+
+		/*
+		 * Zero out the counters
+		 */
+
+		/*
+		 * The counters and sticky-bits comprise the last 132 bits
+		 * (1398 - 1529) of RDR16 on a U chip.  We'll zero these
+		 * out the easy way: zero out last 10 bits of dword 21,
+		 * all of dword 22 and 58 bits (plus 6 don't care bits) of
+		 * dword 23.
+		 */
+		userbuf[21] &= 0xfffffffffffffc00;	/* 0 to last 10 bits */
+		userbuf[22] = 0;
+		userbuf[23] = 0;
+
+		/* 
+		 * Write back the zero'ed bytes + the image given
+		 * the read was destructive.
+		 */
+		perf_rdr_write(16, userbuf);
+	} else {
+
+		/*
+		 * Read RDR-15 which contains the counters and sticky bits 
+		 */
+		if (!perf_rdr_read_ubuf(15, userbuf)) {
+			return -13;
+		}
+
+		/* 
+		 * Clear out the counters
+		 */
+		perf_rdr_clear(15);
+
+		/*
+		 * Copy the counters 
+		 */
+		raddr[0] = (uint32_t)((userbuf[0] >> 32) & 0x00000000ffffffffUL);
+		raddr[1] = (uint32_t)(userbuf[0] & 0x00000000ffffffffUL);
+		raddr[2] = (uint32_t)((userbuf[1] >> 32) & 0x00000000ffffffffUL);
+		raddr[3] = (uint32_t)(userbuf[1] & 0x00000000ffffffffUL);
+	}
+ 
+	return 0;
+}
+
+/*
+ * perf_rdr_get_entry
+ *
+ * Retrieve a pointer to the description of what this
+ * RDR contains.
+ */
+static struct rdr_tbl_ent * perf_rdr_get_entry(uint32_t rdr_num)
+{
+	if (perf_processor_interface == ONYX_INTF) {
+		return &perf_rdr_tbl_U[rdr_num];
+	} else {
+		return &perf_rdr_tbl_W[rdr_num];
+	}
+}
+
+/*
+ * perf_rdr_read_ubuf
+ *
+ * Read the RDR value into the buffer specified.
+ */
+static int perf_rdr_read_ubuf(uint32_t	rdr_num, uint64_t *buffer)
+{
+	uint64_t	data, data_mask = 0;
+	uint32_t	width, xbits, i;
+	struct rdr_tbl_ent *tentry;
+
+	tentry = perf_rdr_get_entry(rdr_num);
+	if ((width = tentry->width) == 0)
+		return 0;
+
+	/* Clear out buffer */
+	i = tentry->num_words;
+	while (i--) {
+		buffer[i] = 0;
+	}	
+
+	/* Check for bits an even number of 64 */
+	if ((xbits = width & 0x03f) != 0) {
+		data_mask = 1;
+		data_mask <<= (64 - xbits);
+		data_mask--;
+	}
+
+	/* Grab all of the data */
+	i = tentry->num_words;
+	while (i--) {
+
+		if (perf_processor_interface == ONYX_INTF) {
+			data = perf_rdr_shift_in_U(rdr_num, width);
+		} else {
+			data = perf_rdr_shift_in_W(rdr_num, width);
+		}
+		if (xbits) {
+			buffer[i] |= (data << (64 - xbits));
+			if (i) {
+				buffer[i-1] |= ((data >> xbits) & data_mask);
+			}
+		} else {
+			buffer[i] = data;
+		}
+	}
+
+	return 1;
+}
+
+/*
+ * perf_rdr_clear
+ *
+ * Zero out the given RDR register
+ */
+static int perf_rdr_clear(uint32_t	rdr_num)
+{
+	struct rdr_tbl_ent *tentry;
+	int32_t		i;
+
+	tentry = perf_rdr_get_entry(rdr_num);
+
+	if (tentry->width == 0) {
+		return -1;
+	}
+
+	i = tentry->num_words;
+	while (i--) {
+		if (perf_processor_interface == ONYX_INTF) {
+			perf_rdr_shift_out_U(rdr_num, 0UL);
+		} else {
+			perf_rdr_shift_out_W(rdr_num, 0UL);
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+ * perf_write_image
+ *
+ * Write the given image out to the processor
+ */
+static int perf_write_image(uint64_t *memaddr)
+{
+	uint64_t buffer[MAX_RDR_WORDS];
+	uint64_t *bptr;
+	uint32_t dwords;
+	uint32_t *intrigue_rdr;
+	uint64_t *intrigue_bitmask, tmp64, proc_hpa, *ptr64;
+	struct rdr_tbl_ent *tentry;
+	int i;
+
+	/* Clear out counters */
+	if (perf_processor_interface == ONYX_INTF) {
+
+		perf_rdr_clear(16);
+
+		/* Toggle performance monitor */
+		perf_intrigue_enable_perf_counters();
+		perf_intrigue_disable_perf_counters();
+
+		intrigue_rdr = perf_rdrs_U;
+	} else {
+		perf_rdr_clear(15);
+		intrigue_rdr = perf_rdrs_W;
+	}
+
+	/* Write all RDRs */
+	while (*intrigue_rdr != -1) {
+		tentry = perf_rdr_get_entry(*intrigue_rdr);
+		perf_rdr_read_ubuf(*intrigue_rdr, buffer);
+		bptr   = &buffer[0];
+		dwords = tentry->num_words;
+		if (tentry->write_control) {
+			intrigue_bitmask = &bitmask_array[tentry->write_control >> 3];
+			while (dwords--) {
+				tmp64 = *intrigue_bitmask & *memaddr++;
+				tmp64 |= (~(*intrigue_bitmask++)) & *bptr;
+				*bptr++ = tmp64;
+			}
+		} else {
+			while (dwords--) {
+				*bptr++ = *memaddr++;
+			}
+		}
+
+		perf_rdr_write(*intrigue_rdr, buffer);
+		intrigue_rdr++;
+	}
+
+	/*
+	 * Now copy out the Runway stuff which is not in RDRs
+	 */
+
+	if (cpu_device == NULL)
+	{
+		printk(KERN_ERR "write_image: cpu_device not yet initialized!\n");
+		return -1;
+	}
+
+	proc_hpa = cpu_device->hpa;
+
+	/* Merge intrigue bits into Runway STATUS 0 */
+	ptr64 = (uint64_t *)(proc_hpa + 0x10); /* Runway STATUS 0 */
+	tmp64 = __raw_readq((u64 *)ptr64) & 0xffecffffffffffff;
+	__raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000), (u64 *)ptr64);
+	
+	/* Write RUNWAY DEBUG registers */
+	ptr64 = (uint64_t *)(proc_hpa + 0x40); /* Runway DEBUG 0 */
+	for (i = 0; i < 8; i++) {
+		__raw_writeq(*memaddr++, (u64 *)ptr64);
+		ptr64++;
+	}
+
+	return 0; 
+}
+
+/*
+ * perf_rdr_write
+ *
+ * Write the given RDR register with the contents
+ * of the given buffer.
+ */
+static void perf_rdr_write(uint32_t rdr_num, uint64_t *buffer)
+{
+	struct rdr_tbl_ent *tentry;
+	int32_t		i;
+
+printk("perf_rdr_write\n");
+	tentry = perf_rdr_get_entry(rdr_num);
+	if (tentry->width == 0) { return; }
+
+	i = tentry->num_words;
+	while (i--) {
+		if (perf_processor_interface == ONYX_INTF) {
+			perf_rdr_shift_out_U(rdr_num, buffer[i]);
+		} else {
+			perf_rdr_shift_out_W(rdr_num, buffer[i]);
+		}	
+	}
+printk("perf_rdr_write done\n");
+}
+
+module_init(perf_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/perf_asm.S linux-2.4.20/arch/parisc/kernel/perf_asm.S
--- linux-2.4.19/arch/parisc/kernel/perf_asm.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/perf_asm.S	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,1679 @@
+; 
+;   Purpose:
+;	This file has the overall purpose of suppyling low-level
+;   assembly to program the intrigue portion of the cpu.
+; 
+
+#include <linux/config.h>
+#include <asm/assembly.h>
+
+#ifdef __LP64__
+	.level		2.0w
+#endif /* __LP64__ */
+
+#define MTDIAG_1(gr)    .word 0x14201840 + gr*0x10000
+#define MTDIAG_2(gr)    .word 0x14401840 + gr*0x10000
+#define MFDIAG_1(gr)    .word 0x142008A0 + gr
+#define MFDIAG_2(gr)    .word 0x144008A0 + gr
+#define STDIAG(dr)      .word 0x14000AA0 + dr*0x200000
+#define SFDIAG(dr)      .word 0x14000BA0 + dr*0x200000
+#define DR2_SLOW_RET    53
+
+
+;
+; Enable the performance counters
+;
+; The coprocessor only needs to be enabled when
+; starting/stopping the coprocessor with the pmenb/pmdis.
+;
+	.text
+	.align 32
+
+	.export perf_intrigue_enable_perf_counters,code
+perf_intrigue_enable_perf_counters:
+	.proc
+	.callinfo  frame=0,NO_CALLS
+	.entry
+	
+	ldi     0x20,%r25                ; load up perfmon bit
+	mfctl   ccr,%r26                 ; get coprocessor register
+	or      %r25,%r26,%r26             ; set bit
+	mtctl   %r26,ccr                 ; turn on performance coprocessor
+	pmenb                           ; enable performance monitor
+	ssm     0,0                     ; dummy op to ensure completion
+	sync                            ; follow ERS
+	andcm   %r26,%r25,%r26             ; clear bit now 
+	mtctl   %r26,ccr                 ; turn off performance coprocessor
+	nop                             ; NOPs as specified in ERS
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	bve    (%r2)
+	nop
+	.exit
+	.procend
+
+	.export perf_intrigue_disable_perf_counters,code
+perf_intrigue_disable_perf_counters:
+	.proc
+	.callinfo  frame=0,NO_CALLS
+	.entry
+	ldi     0x20,%r25                ; load up perfmon bit
+	mfctl   ccr,%r26                 ; get coprocessor register
+	or      %r25,%r26,%r26             ; set bit
+	mtctl   %r26,ccr                 ; turn on performance coprocessor
+	pmdis                           ; disable performance monitor
+	ssm     0,0                     ; dummy op to ensure completion
+	andcm   %r26,%r25,%r26             ; clear bit now 
+	bve    (%r2)
+	mtctl   %r26,ccr                 ; turn off performance coprocessor
+	.exit
+	.procend
+
+;************************************************************************
+;*																		*
+;* Name: perf_rdr_shift_in_W												*
+;*																		*
+;* Description:															*
+;*	This routine shifts data in from the RDR in arg0 and returns		*
+;*	the result in ret0.  If the RDR is <= 64 bits in length, it			*
+;*	is shifted shifted backup immediately.  This is to compensate		*
+;*	for RDR10 which has bits that preclude PDC stack operations			*
+;*	when they are in the wrong state.									*
+;*																		*
+;* Arguments:															*
+;*	arg0 : rdr to be read												*
+;*	arg1 : bit length of rdr											*
+;*																		*
+;* Returns:																*
+;*	ret0 = next 64 bits of rdr data from staging register				*
+;*																		*
+;* Register usage:														*
+;*	arg0 : rdr to be read												*
+;*	arg1 : bit length of rdr											*
+;*	%r24  - original DR2 value											*
+;*	%r1   - scratch														*
+;*  %r29  - scratch														*
+;*																		*
+;* Returns:																*
+;*	ret0 = RDR data (right justified)									*
+;*																		*
+;************************************************************************
+
+	.export perf_rdr_shift_in_W,code
+perf_rdr_shift_in_W:
+	.proc
+	.callinfo frame=0,NO_CALLS
+	.entry
+;
+; read(shift in) the RDR.
+;
+
+; NOTE: The PCX-W ERS states that DR2_SLOW_RET must be set before any
+; shifting is done, from or to, remote diagnose registers.
+;
+
+	depdi,z		1,DR2_SLOW_RET,1,%r29
+	MFDIAG_2	(24)
+	or		    %r24,%r29,%r29
+	MTDIAG_2	(29)			; set DR2_SLOW_RET
+
+	nop
+	nop
+	nop
+	nop	
+
+;
+; Cacheline start (32-byte cacheline)
+;
+	nop
+	nop
+	nop
+	extrd,u		arg1,63,6,%r1    ; setup shift amount based on bits to move 
+
+	mtsar		%r1
+	shladd		arg0,2,%r0,%r1	; %r1 = 4 * RDR number
+	blr  		%r1,%r0		    ; branch to 8-instruction sequence
+	nop
+
+;
+; Cacheline start (32-byte cacheline)
+;
+
+	;
+	; RDR 0 sequence
+	;
+	SFDIAG		(0)		
+	ssm		    0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)					; mtdiag %dr1, %r1 
+	STDIAG		(0)
+	ssm		    0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 1 sequence
+	;
+	sync			
+	ssm		    0,0
+	SFDIAG		(1)
+	ssm		    0,0
+	MFDIAG_1	(28)
+	ssm		    0,0
+	b,n         perf_rdr_shift_in_W_leave
+	nop
+	
+	;
+	; RDR 2 read sequence
+	;
+	SFDIAG		(2)		
+	ssm		    0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(2)
+	ssm		    0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 3 read sequence
+	;
+	b,n         perf_rdr_shift_in_W_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	;
+	; RDR 4 read sequence
+	;
+	sync				
+	ssm			0,0
+	SFDIAG		(4)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	; 
+	; RDR 5 read sequence
+	;
+	sync	
+	ssm			0,0
+	SFDIAG		(5)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 6 read sequence
+	;
+	sync	
+	ssm			0,0
+	SFDIAG		(6)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 7 read sequence
+	;
+	b,n         perf_rdr_shift_in_W_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	;
+	; RDR 8 read sequence
+	;
+	b,n         perf_rdr_shift_in_W_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	;
+	; RDR 9 read sequence
+	;
+	b,n         perf_rdr_shift_in_W_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	;
+	; RDR 10 read sequence
+	;
+	SFDIAG		(10)
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(10)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 11 read sequence
+	;
+	SFDIAG		(11)
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(11)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 12 read sequence
+	;
+	b,n         perf_rdr_shift_in_W_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	;
+	; RDR 13 read sequence
+	;
+	sync
+	ssm			0,0
+	SFDIAG		(13)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 14 read sequence
+	;
+	SFDIAG		(14)	
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(14)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 15 read sequence
+	;
+	sync				; RDR 15 read sequence
+	ssm			0,0
+	SFDIAG		(15)
+	ssm			0,0
+	MFDIAG_1	(28)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	nop
+	
+	;
+	; RDR 16 read sequence
+	;
+	sync				; RDR 16 read sequence
+	ssm			0,0
+	SFDIAG		(16)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 17 read sequence
+	;
+	SFDIAG		(17)	
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(17)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 18 read sequence
+	;
+	SFDIAG		(18)	
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(18)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+;
+; RDR 19 read sequence
+;
+	b,n         perf_rdr_shift_in_W_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	;
+	; RDR 20 read sequence
+	;
+	sync
+	ssm			0,0
+	SFDIAG		(20)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 21 read sequence
+	;
+	sync
+	ssm			0,0
+	SFDIAG		(21)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 22 read sequence
+	;
+	sync
+	ssm			0,0
+	SFDIAG		(22)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 23 read sequence
+	;
+	sync		
+	ssm			0,0
+	SFDIAG		(23)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 24 read sequence
+	;
+	sync	
+	ssm			0,0
+	SFDIAG		(24)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 25 read sequence
+	;
+	sync
+	ssm			0,0
+	SFDIAG		(25)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 26 read sequence
+	;
+	SFDIAG		(26)		
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(26)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 27 read sequence
+	;
+	SFDIAG		(27)
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(27)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 28 read sequence
+	;
+	sync				
+	ssm			0,0
+	SFDIAG		(28)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 29 read sequence
+	;
+	sync		
+	ssm			0,0
+	SFDIAG		(29)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 30 read sequence
+	;
+	SFDIAG		(30)
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(30)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 31 read sequence
+	;
+	sync		
+	ssm			0,0
+	SFDIAG		(31)
+	ssm			0,0
+	MFDIAG_1	(28)
+	nop
+	ssm			0,0
+	nop
+
+	;
+	; Fallthrough
+	;
+
+perf_rdr_shift_in_W_leave:
+	bve		    (%r2)
+	.exit
+	MTDIAG_2	(24)			; restore DR2
+	.procend
+
+
+;************************************************************************
+;*																		*
+;* Name: perf_rdr_shift_out_W												*
+;*																		*
+;* Description:															*
+;*	This routine moves data to the RDR's.  The double-word that			*
+;*	arg1 points to is loaded and moved into the staging register.		*
+;*	Then the STDIAG instruction for the RDR # in arg0 is called			*
+;*	to move the data to the RDR.										*
+;*																		*
+;* Arguments:															*
+;*	arg0 = rdr number													*
+;*	arg1 = 64-bit value to write										*
+;*	%r24 - DR2 | DR2_SLOW_RET											*
+;*	%r23 - original DR2 value											*
+;*																		*
+;* Returns:																*
+;*	None																*
+;*																		*
+;* Register usage:														*
+;*																		*
+;************************************************************************
+
+	.export perf_rdr_shift_out_W,code
+perf_rdr_shift_out_W:
+	.proc
+	.callinfo frame=0,NO_CALLS
+	.entry
+;
+; NOTE: The PCX-W ERS states that DR2_SLOW_RET must be set before any
+; shifting is done, from or to, the remote diagnose registers.
+;
+
+	depdi,z		1,DR2_SLOW_RET,1,%r24
+	MFDIAG_2	(23)
+	or		     %r24,%r23,%r24
+	MTDIAG_2	(24)			; set DR2_SLOW_RET
+
+	MTDIAG_1	(25)			; data to the staging register
+	shladd		arg0,2,%r0,%r1	; %r1 = 4 * RDR number
+	blr		    %r1,%r0		    ; branch to 8-instruction sequence
+	nop
+
+	;
+	; RDR 0 write sequence
+	;
+	sync				; RDR 0 write sequence
+	ssm			0,0
+	STDIAG		(0)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm			0,0
+	nop
+
+	;
+	; RDR 1 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(1)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 2 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(2)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 3 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(3)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 4 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(4)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 5 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(5)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 6 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(6)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 7 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(7)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 8 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(8)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 9 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(9)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 10 write sequence
+	;
+	sync	
+	ssm		0,0
+	STDIAG		(10)
+	STDIAG		(26)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	ssm		0,0
+	nop
+
+	;
+	; RDR 11 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(11)
+	STDIAG		(27)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	ssm		0,0
+	nop
+
+	;
+	; RDR 12 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(12)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 13 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(13)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 14 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(14)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 15 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(15)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 16 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(16)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 17 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(17)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 18 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(18)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 19 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(19)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 20 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(20)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 21 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(21)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 22 write sequence
+	;
+	sync	
+	ssm		0,0
+	STDIAG		(22)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 23 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(23)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 24 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(24)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 25 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(25)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 26 write sequence
+	;
+	sync	
+	ssm		0,0
+	STDIAG		(10)
+	STDIAG		(26)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	ssm		0,0
+	nop
+
+	;
+	; RDR 27 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(11)
+	STDIAG		(27)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	ssm		0,0
+	nop
+
+	;
+	; RDR 28 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(28)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 29 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(29)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 30 write sequence
+	;
+	sync	
+	ssm		0,0
+	STDIAG		(30)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 31 write sequence
+	;
+	sync				
+	ssm		0,0
+	STDIAG		(31)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+perf_rdr_shift_out_W_leave:
+	bve		(%r2)
+	.exit
+	MTDIAG_2	(23)			; restore DR2
+	.procend
+
+
+;**************************** CHRIS ***********************************
+
+;************************************************************************
+;*																		*
+;* Name: rdr_shift_in_U													*
+;*																		*
+;* Description:															*
+;*	This routine shifts data in from the RDR in arg0 and returns		*
+;*	the result in ret0.  If the RDR is <= 64 bits in length, it			*
+;*	is shifted shifted backup immediately.  This is to compensate		*
+;*	for RDR10 which has bits that preclude PDC stack operations			*
+;*	when they are in the wrong state.									*
+;*																		*
+;* Arguments:															*
+;*	arg0 : rdr to be read												*
+;*	arg1 : bit length of rdr											*
+;*																		*
+;* Returns:																*
+;*	ret0 = next 64 bits of rdr data from staging register				*
+;*																		*
+;* Register usage:														*
+;*	arg0 : rdr to be read						                        *
+;*	arg1 : bit length of rdr					                        *
+;*	%r24 - original DR2 value											*
+;*	%r23 - DR2 | DR2_SLOW_RET											*
+;*	%r1  - scratch														*
+;*																		*
+;************************************************************************
+
+	.export perf_rdr_shift_in_U,code
+perf_rdr_shift_in_U:
+	.proc
+	.callinfo frame=0,NO_CALLS
+	.entry
+
+; read(shift in) the RDR.
+;
+; NOTE: The PCX-U ERS states that DR2_SLOW_RET must be set before any
+; shifting is done, from or to, remote diagnose registers.
+
+	depdi,z		1,DR2_SLOW_RET,1,%r29
+	MFDIAG_2	(24)
+	or			%r24,%r29,%r29
+	MTDIAG_2	(29)			; set DR2_SLOW_RET
+
+	nop
+	nop
+	nop
+	nop
+
+;
+; Start of next 32-byte cacheline
+;
+	nop
+	nop
+	nop
+	extrd,u		arg1,63,6,%r1
+
+	mtsar		%r1
+	shladd		arg0,2,%r0,%r1	; %r1 = 4 * RDR number
+	blr 		%r1,%r0		; branch to 8-instruction sequence
+	nop
+
+;
+; Start of next 32-byte cacheline
+;
+	SFDIAG		(0)		; RDR 0 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(0)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	SFDIAG		(1)		; RDR 1 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(1)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	sync				; RDR 2 read sequence
+	ssm			0,0
+	SFDIAG		(4)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 3 read sequence
+	ssm			0,0
+	SFDIAG		(3)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+
+	sync				; RDR 4 read sequence
+	ssm			0,0
+	SFDIAG		(4)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 5 read sequence
+	ssm			0,0
+	SFDIAG		(5)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 6 read sequence
+	ssm			0,0
+	SFDIAG		(6)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 7 read sequence
+	ssm			0,0
+	SFDIAG		(7)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+
+	b,n         perf_rdr_shift_in_U_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	SFDIAG		(9)		; RDR 9 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(9)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+
+	SFDIAG		(10)		; RDR 10 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(10)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	SFDIAG		(11)		; RDR 11 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(11)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	SFDIAG		(12)		; RDR 12 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(12)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+
+	SFDIAG		(13)		; RDR 13 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(13)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	SFDIAG		(14)		; RDR 14 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(14)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	SFDIAG		(15)		; RDR 15 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(15)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	sync				; RDR 16 read sequence
+	ssm			0,0
+	SFDIAG		(16)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	SFDIAG		(17)		; RDR 17 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(17)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	SFDIAG		(18)		; RDR 18 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(18)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	b,n         perf_rdr_shift_in_U_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	sync				; RDR 20 read sequence
+	ssm			0,0
+	SFDIAG		(20)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 21 read sequence
+	ssm			0,0
+	SFDIAG		(21)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 22 read sequence
+	ssm			0,0
+	SFDIAG		(22)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 23 read sequence
+	ssm			0,0
+	SFDIAG		(23)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 24 read sequence
+	ssm			0,0
+	SFDIAG		(24)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 25 read sequence
+	ssm			0,0
+	SFDIAG		(25)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	SFDIAG		(26)		; RDR 26 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(26)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	SFDIAG		(27)		; RDR 27 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(27)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	sync				; RDR 28 read sequence
+	ssm			0,0
+	SFDIAG		(28)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	b,n         perf_rdr_shift_in_U_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	
+	SFDIAG		(30)		; RDR 30 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(30)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	SFDIAG		(31)		; RDR 31 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(31)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	nop
+
+perf_rdr_shift_in_U_leave:
+	bve		    (%r2)
+	.exit
+	MTDIAG_2	(24)			; restore DR2
+	.procend
+
+;************************************************************************
+;*																		*
+;* Name: rdr_shift_out_U												*
+;*																		*
+;* Description:															*
+;*	This routine moves data to the RDR's.  The double-word that			*
+;*	arg1 points to is loaded and moved into the staging register.		*
+;*	Then the STDIAG instruction for the RDR # in arg0 is called			*
+;*	to move the data to the RDR.										*
+;*																		*
+;* Arguments:															*
+;*	arg0 = rdr target													*
+;*	arg1 = buffer pointer												*
+;*																		*
+;* Returns:																*
+;*	None																*
+;*																		*
+;* Register usage:														*
+;*	arg0 = rdr target													*
+;*	arg1 = buffer pointer												*
+;*	%r24 - DR2 | DR2_SLOW_RET											*
+;*	%r23 - original DR2 value											*
+;*																		*
+;************************************************************************
+
+	.export perf_rdr_shift_out_U,code
+perf_rdr_shift_out_U:
+	.proc
+	.callinfo frame=0,NO_CALLS
+	.entry
+
+;
+; NOTE: The PCX-U ERS states that DR2_SLOW_RET must be set before any
+; shifting is done, from or to, the remote diagnose registers.
+;
+
+	depdi,z		1,DR2_SLOW_RET,1,%r24
+	MFDIAG_2	(23)
+	or		%r24,%r23,%r24
+	MTDIAG_2	(24)			; set DR2_SLOW_RET
+
+	MTDIAG_1	(25)			; data to the staging register
+	shladd		 arg0,2,%r0,%r1	; %r1 = 4 * RDR number
+	blr		    %r1,%r0		    ; branch to 8-instruction sequence
+	nop
+
+;
+; 32-byte cachline aligned
+;
+
+	sync				; RDR 0 write sequence
+	ssm			0,0
+	STDIAG		(0)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 1 write sequence
+	ssm			0,0
+	STDIAG		(1)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 2 write sequence
+	ssm			0,0
+	STDIAG		(2)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 3 write sequence
+	ssm			0,0
+	STDIAG		(3)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 4 write sequence
+	ssm			0,0
+	STDIAG		(4)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 5 write sequence
+	ssm			0,0
+	STDIAG		(5)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 6 write sequence
+	ssm			0,0
+	STDIAG		(6)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 7 write sequence
+	ssm			0,0
+	STDIAG		(7)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 8 write sequence
+	ssm			0,0
+	STDIAG		(8)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 9 write sequence
+	ssm			0,0
+	STDIAG		(9)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 10 write sequence
+	ssm			0,0
+	STDIAG		(10)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 11 write sequence
+	ssm			0,0
+	STDIAG		(11)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 12 write sequence
+	ssm			0,0
+	STDIAG		(12)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 13 write sequence
+	ssm			0,0
+	STDIAG		(13)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 14 write sequence
+	ssm			0,0
+	STDIAG		(14)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 15 write sequence
+	ssm			0,0
+	STDIAG		(15)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 16 write sequence
+	ssm			0,0
+	STDIAG		(16)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 17 write sequence
+	ssm			0,0
+	STDIAG		(17)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 18 write sequence
+	ssm			0,0
+	STDIAG		(18)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 19 write sequence
+	ssm			0,0
+	STDIAG		(19)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 20 write sequence
+	ssm			0,0
+	STDIAG		(20)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 21 write sequence
+	ssm			0,0
+	STDIAG		(21)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 22 write sequence
+	ssm			0,0
+	STDIAG		(22)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 23 write sequence
+	ssm			0,0
+	STDIAG		(23)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 24 write sequence
+	ssm			0,0
+	STDIAG		(24)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 25 write sequence
+	ssm			0,0
+	STDIAG		(25)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 26 write sequence
+	ssm			0,0
+	STDIAG		(26)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 27 write sequence
+	ssm			0,0
+	STDIAG		(27)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 28 write sequence
+	ssm			0,0
+	STDIAG		(28)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 29 write sequence
+	ssm			0,0
+	STDIAG		(29)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 30 write sequence
+	ssm			0,0
+	STDIAG		(30)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 31 write sequence
+	ssm			0,0
+	STDIAG		(31)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+perf_rdr_shift_out_U_leave:
+	bve		(%r2)
+	.exit
+	MTDIAG_2	(23)			; restore DR2
+	.procend
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/perf_images.h linux-2.4.20/arch/parisc/kernel/perf_images.h
--- linux-2.4.19/arch/parisc/kernel/perf_images.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/perf_images.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,3122 @@
+#ifndef PERF_IMAGES_H
+#define PERF_IMAGES_H
+
+/* Magic numbers taken without modification from HPUX stuff */
+
+/*
+ * Imagine for use with the Onyx cpu interface
+ */
+
+#define PCXU_IMAGE_SIZE 584
+
+static uint32_t onyx_images[][PCXU_IMAGE_SIZE/sizeof(uint32_t)] = {
+/*
+ * CPI:
+ *
+ * Counts the following:
+ *
+ * ctr0 : total cycles
+ * ctr1 : total cycles where nothing retired
+ * ctr2 : total instructions retired, including nullified
+ * ctr3 : total instructions retired, less nullified instructions
+ */
+         {
+         0x4c00c000, 0x00000000, 0x00060000, 0x00000000,
+         0xe0e0e0e0, 0x004e0004, 0x07ffffff, 0xffc01380,
+         0x0101ffff, 0xfffff104, 0xe000c07f, 0xfffffffc,
+         0x01380010, 0x1fffffff, 0xff000000, 0x00000000,
+         0x00000fff, 0xff00000f, 0xffff0000, 0x0fffff00,
+         0x000fffff, 0x00000000, 0x00000000, 0x00ffffff,
+         0xfffff000, 0x0000000f, 0xffffffff, 0xff000000,
+         0x0000ffff, 0xfffffff0, 0x00000000, 0x0fffffff,
+         0xffff0000, 0x00000000, 0x6fffffff, 0xffffffff,
+         0xfff55fff, 0xffffffff, 0xffffffff, 0xf0000000,
+         0xf0000030, 0x00003c00, 0x067f080c, 0x02019fc0,
+         0x02804067, 0xf0009030, 0x19fc002c, 0x40067f08,
+         0x0c12019f, 0xc0028440, 0x67f00091, 0x3019fc00,
+         0x2fc007ff, 0xf800f001, 0xfffe003c, 0x007fff80,
+         0x0f001fff, 0xe003c007, 0xfff800f0, 0x01fffe00,
+         0x3c007fff, 0x800f001f, 0xffe003c0, 0x07fff800,
+         0xf001fffe, 0x003c007f, 0xff800f00, 0x1fffe003,
+         0xc007fff8, 0x00f001ff, 0xfe003c00, 0x7fff800f,
+         0x001fffe0, 0x03c007ff, 0xf800f001, 0xfffe003c,
+         0x007fff80, 0x0f001fff, 0xe003c007, 0xfff800f0,
+         0x01fffe00, 0x3c007fff, 0x800f001f, 0xffe00000,
+         0x00000000, 0x00000000, 0x00000000, 0x00000000,
+         0x6fff0000, 0x00000000, 0x60000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+         0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff},
+
+/* Bus utilization image (bus_util)
+ *
+ * ctr0 : counts address valid cycles
+ * ctr1 : counts data valid cycles
+ * ctr2 : counts overflow from counter 0
+ * ctr3 : counts overflow from counter 1
+ */
+         {
+         0x0c01e000, 0x00000000, 0x00060000, 0x00000000,
+         0xefefefef, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xff000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffff0000, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xf0000000,
+         0x0000000c, 0x00003c00, 0x07930000, 0x0041e4c0,
+         0x01002079, 0x3000800c, 0x1e4c0030, 0x00279300,
+         0x010049e4, 0xc0014022, 0x79300090, 0x0c9e4c00,
+         0x34004793, 0x00020051, 0xe4c00180, 0x24793000,
+         0xa00d1e4c, 0x00380067, 0x93000300, 0x59e4c001,
+         0xc0267930, 0x00b00d9e, 0x4c003fff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xfffffc00,
+         0x00000000, 0x00000000, 0x00000000, 0x00000000,
+         0xffff0000, 0x00000000, 0xf0000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+         0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0x00100000, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff },
+
+/*
+ * TLB counts (same as tlbStats image):
+ *
+ * Counts the following:
+ *
+ * ctr0: DTLB misses
+ * ctr1: ITLB misses
+ * ctr2: total cycles in the miss handlers
+ * ctr3: total cycles
+ */
+
+         {
+         0x0c00c000, 0x00000000, 0x00060000, 0x00000000,
+         0xe7e7e0e0, 0x004e0004, 0x07ffffff, 0xffc01380,
+         0x0101ffff, 0xfffff104, 0xe000c06a, 0xafffc85c,
+         0x01380010, 0x1fffffff, 0xff000000, 0x00000000,
+         0x01b9e000, 0x0001b8c0, 0x00000000, 0x0fffff00,
+         0x000fffff, 0x00000000, 0x00000000, 0x00400000,
+         0x00001000, 0x00000004, 0x00000000, 0x01000000,
+         0x0000ffff, 0xfffffff0, 0x00000000, 0x0fffffff,
+         0xffff0000, 0x00000000, 0x6fffffff, 0xffffffff,
+         0xfff55ff5, 0xffffffff, 0xffffffff, 0xf0000000,
+         0xf0000000, 0x00003c00, 0x01ff0001, 0x08007fc2,
+         0x02c1001f, 0xf0807100, 0x1bfc200c, 0x4806ff00,
+         0x03f001ff, 0xfe003c00, 0x7fff800f, 0x001fffe0,
+         0x03c007ff, 0xf800f001, 0xfffe003c, 0x007fff80,
+         0x0f001fff, 0xe003c007, 0xfff800f0, 0x01fffe00,
+         0x3c007fff, 0x800f001f, 0xffe003c0, 0x07fff800,
+         0xf001fffe, 0x003c007f, 0xff800f00, 0x1fffe003,
+         0xc007fff8, 0x00f001ff, 0xfe003c00, 0x7fff800f,
+         0x001fffe0, 0x03c007ff, 0xf800f001, 0xfffe003c,
+         0x007fff80, 0x0f001fff, 0xe003c007, 0xfff800f0,
+         0x01fffe00, 0x3c007fff, 0x800f001f, 0xffe00000,
+         0x00000000, 0x00000000, 0x00000000, 0x00000000,
+         0x6fff0000, 0x00000000, 0x60000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+         0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff },
+
+/* tlbHandMiss
+ *
+ * ctr0: counts TLB misses 
+ * ctr1: counts dmisses inside tlb miss handlers 
+ * ctr2: counts cycles in the tlb miss handlers 
+ * ctr3: counts overflows of ctr2 
+ */
+{
+0x1c00c000,00000000,0x00060000,00000000,
+0xe7e7e0e0,0x004e0004,0x07ffffff,0xffc01380,
+0x0101ffff,0xfffff104,0xe000c06a,0xafffc85c,
+0x01380010,0x1fffffff,0xff000000,00000000,
+0x01b9e000,0x0001b8c0,00000000,0x0fffff00,
+0x000fffff,00000000,00000000,0x00400000,
+0x00001000,0x00000004,00000000,0x01000000,
+0x0000ffff,0xfffffff0,00000000,0x0fffffff,
+0xffff0000,00000000,0x6fffffff,0xffffffff,
+0xfff55ff5,0xffffffff,0xffffffff,0xf0000000,
+0xf0000000,0x00003c00,0x01fd0000,0x08007f42,
+0x0281001f,0xd080a100,0x19f42008,0x44067d08,
+0x0612019f,0x400084c0,0x67d00060,0x0047f400,
+0x042011fd,0x080b0404,0x7f4202c4,0x0167d080,
+0x311059f4,0x201c4816,0x7d000313,0x059f4001,
+0xfc007fff,0x800f001f,0xffe003c0,0x07fff800,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x6fff0000,00000000,0x60000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+/* branch_taken image (ptkn image)
+ *
+ * ctr0: overflow for ctr1
+ * ctr1: predicted taken branches, actually taken
+ * ctr2: all predicted taken branches (nullfied or not)
+ * ctr3: overflow for ctr2
+ */
+
+        {
+        0xcc01e000, 0x00000000, 0x00060000, 0x00000000,
+        0xa08080a0, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xff000000, 0x00000000,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffff0000, 0x00000000, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xf0000000,
+        0xf0000000, 0x00003c00, 0x04f90000, 0x02013e40,
+        0x0081004f, 0x90004060, 0x13e40018, 0x0024f900,
+        0x0802093e, 0x40028102, 0x4f9000c0, 0x6093e400,
+        0x380014f9, 0x00010205, 0x3e4000c1, 0x014f9000,
+        0x506053e4, 0x001c0034, 0xf9000902, 0x0d3e4002,
+        0xc1034f90, 0x00d060d3, 0xe4003fff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xfffffc00,
+        0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0xffff0000, 0x00000000, 0xf0000000, 0x00000000,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+        0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+        0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+        0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+        0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+        0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+        0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+        0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff },
+
+/* branch_nottaken (pntkn image)
+ *
+ * ctr0: overflow for ctr1
+ * ctr1: counts branches predicted not-taken, but actually taken
+ * ctr2: counts all predictable branches predicted not-taken
+ * ctr3: overflow for ctr2
+ */
+{
+0xcc01e000,00000000,0x00060000,00000000,
+0xc0c0c0e0,0xffb1fffb,0xfff7ffff,0xffffffff,
+0xffffffff,0xfffffffb,0x1fffbfff,0x7fffffff,
+0xfcc7ffff,0xffdffffa,0x5f000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+
+/* imiss image
+ *
+ * ctr0 : counts imiss aligned on 0
+ * ctr1 : counts imiss aligned on 4
+ * ctr2 : counts imiss aligned on 8
+ * ctr3 : counts imiss aligned on C
+ */
+         {
+         0x0c00c000, 0x00000000, 0x00010000, 0x00000000,
+         0xe7ebedee, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xff000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffff0000, 0x00000000, 0x6fffffff, 0xffffffff,
+         0xfff55fff, 0xffffffff, 0xffffffff, 0xf0000000,
+         0xf0000000, 0x00003c00, 0x007f0000, 0x01001fc0,
+         0x00408007, 0xf0002030, 0x01fc000c, 0x10007f00,
+         0x0405001f, 0xc0014180, 0x07f00060, 0x7001fc00,
+         0x1c20007f, 0x00080900, 0x1fc00242, 0x8007f000,
+         0xa0b001fc, 0x002c3000, 0x7f000c0d, 0x001fc003,
+         0x438007f0, 0x00e0f001, 0xfc003fff, 0xfffff800,
+         0xfffffffe, 0x003fffff, 0xff800fff, 0xffffe003,
+         0xfffffff8, 0x00ffffff, 0xfe003fff, 0xffff800f,
+         0xffffffe0, 0x03ffffff, 0xf800ffff, 0xfffe003f,
+         0xffffff80, 0x0fffffff, 0xe003ffff, 0xfff800ff,
+         0xfffffe00, 0x3fffffff, 0x800fffff, 0xffe00000,
+         0x00000000, 0x00000000, 0x00000000, 0x00000000,
+         0x6fff0000, 0x00000000, 0x60000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+         0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff},
+
+/* dmiss image
+ * 
+ * ctr0 : counts cycles
+ * ctr1 : counts cycles where something retired
+ * ctr2 : counts dmisses
+ * ctr3 : (same as ctr2)
+ */
+         {
+         0x3c00c000, 0x00000000, 0x00060000, 0x00000000,
+         0xe0e0e0e0, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xff000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffff0000, 0x00000000, 0x6fffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xf0000000,
+         0xf0000000, 0x00003c04, 0x007f0009, 0x02001fc0,
+         0x0280c007, 0xf000b040, 0x01fc0030, 0x14007f00,
+         0x0d06001f, 0xc00381c0, 0x07f000f0, 0x8001fc00,
+         0x2024007f, 0x00090a00, 0x1fc00282, 0xc007f000,
+         0xb0c001fc, 0x00303400, 0x7f000d0e, 0x001fc003,
+         0x83c007f0, 0x00f00001, 0xfc0023ff, 0xfffff800,
+         0xfffffffe, 0x003fffff, 0xff800fff, 0xffffe003,
+         0xfffffff8, 0x00ffffff, 0xfe003fff, 0xffff800f,
+         0xffffffe0, 0x03ffffff, 0xf800ffff, 0xfffe003f,
+         0xffffff80, 0x0fffffff, 0xe003ffff, 0xfff800ff,
+         0xfffffe00, 0x3fffffff, 0x800fffff, 0xffe00000,
+         0x00000000, 0x00000000, 0x00000000, 0x00000000,
+         0x6fff0000, 0x00000000, 0x60000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+         0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff },
+
+/* dcmiss 
+ *
+ * ctr0: counts store instructions retired 
+ * ctr1: counts load instructions retired
+ * ctr2: counts dmisses 
+ * ctr3: counts READ_SHARED_OR_PRIV and READ_PRIVATE transactions on Runway 
+ */
+{
+0x2c90c000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x6fffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf00000e8,0x00003c02,0x00bf0001,0x02002fc0,
+0x0080a00b,0xf0003040,0x02fc0010,0x1200bf00,
+0x0506002f,0xc00181a0,0x0bf00070,0x8002fc00,
+0x202200bf,0x00090a00,0x2fc00282,0xa00bf000,
+0xb0c002fc,0x00303200,0xbf000d0e,0x002fc003,
+0x83a00bf0,0x00ffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0x6fff0000,00000000,0x60000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0x55555555,0xd5555555,
+0x55555555,0x75555555,0x5e1ffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0xf8000000,00000000,
+00000000,00000000,0xf4000000,00000000,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+00000000,00000000,0x00ffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* big_cpi
+ *
+ * ctr0: counts total cycles 
+ * ctr1: counts overflows of ctr0 (for greater than 32-bit values) 
+ * ctr2: counts overflows of ctr3 (for greater than 32-bit values) 
+ * ctr3: counts unnullified instructions retired 
+ */
+{
+0x0c00c000,00000000,0x00060000,00000000,
+0xe7e7e0e0,0x004e0004,0x07ffffff,0xffc01380,
+0x0101ffff,0xfffff104,0xe000c06a,0xafffc85c,
+0x01380010,0x1fffffff,0xff000000,00000000,
+0x01b9e000,0x0001b8c0,00000000,0x0fffff00,
+0x000fffff,00000000,00000000,0x00400000,
+0x00001000,0x00000004,00000000,0x01000000,
+0x0000ffff,0xfffffff0,00000000,0x0fffffff,
+0xffff0000,00000000,0x6fffffff,0xffffffff,
+0xfff55ff5,0xffffffff,0xffffffff,0xf0000000,
+0xf0000010,0x00003c00,0x01760008,0x00025d80,
+0x02800417,0x6000c001,0x25d80038,0x04017600,
+0x0901025d,0x8002c044,0x176000d0,0x1125d800,
+0x3c2001f6,0x08080400,0x7d820203,0x001f6080,
+0x804027d8,0x20282009,0xf6080a0c,0x027d8202,
+0x81041f60,0x80c08107,0xd8203030,0x41f6080c,
+0x04127d82,0x0382049f,0x6080e0c1,0x27d82038,
+0x4006f608,0x081011bd,0x82030400,0xef6080a1,
+0x013bd820,0x384806f6,0x00081211,0xbd800304,
+0x80ef6000,0xa1213bd8,0x003bc007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x6fff0000,00000000,0x60000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* big_ls
+ *
+ * ctr0:counts the total number of cycles for which local_stall_A1 is asserted. 
+ * ctr1: is the overflow for counter 0. 
+ * ctr2: counts IFLUSH_AV 
+ * ctr3: is the overflow for counter 2. 
+ */
+{
+0x0c000000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x0fffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x00029408,0x02f50002,0x0800bd40,
+0x0202802f,0x5000a000,0x4bd40004,0x0812f500,
+0x030804bd,0x40024281,0x2f5000b0,0x010bd400,
+0x100842f5,0x00060810,0xbd400302,0x842f5000,
+0xe0014bd4,0x00140852,0xf5000708,0x14bd4003,
+0x42852f50,0x00ff001f,0xffe003c0,0x07fff800,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x0df70000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* br_abort
+ *
+ * ctr0: counts BRAD_STALLH 
+ * ctr1: counts ONE_QUAD 
+ * ctr2: counts BR0_ABRT 
+ * ctr3: counts BR1_ABRT
+ */
+{
+0x0c002000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x1fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x1a250000,00000000,0x10000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+/* isnt
+ *
+ * ctr0: counts the total number of cycles for which iside_notrans is asserted 
+ * ctr1: counts the number of times iside_notrans is asserted for 1-4 cycles 
+ * ctr2: counts the number of times iside_notrans is asserted for 5-7 cycles 
+ * ctr3: counts the number of times iside_notrans is asserted for > 7 cycles 
+ */
+{
+0x0c018000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xcfffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x00021c20,0x03ff0808,0x1800ffc4,
+0x0204003f,0xf0004280,0x0ffc6020,0x8003ff00,
+0x043800ff,0xc8020c00,0x3ff00044,0x800ffca0,
+0x210003ff,0x00045800,0xffcc0214,0x003ff000,
+0x26800ffc,0xe0218003,0xff000278,0x00ffd002,
+0x1c003ff0,0x0028800f,0xfd002200,0x03ff0001,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0xcdff0000,00000000,0xc0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+/* quadrant
+ *
+ * ctr0: Total number of instructions in quadrant 0 
+ * ctr1: Total number of instructions in quadrant 1 
+ * ctr2: Total number of instructions in quadrant 2 
+ * ctr3: Total number of instructions in quadrant 3 
+ * Works only with 32-bit
+ */
+
+   {
+   0x0c01e000,   0x00000000,   0x00060000,   0x00000000,
+   0xe0e0e0e0,   0x004e0004,   0x07ffffff,   0xffc01380,
+   0x0101ffff,   0xfffff004,   0xe000407f,   0xfffffffc,
+   0x01380010,   0x1fffffff,   0xff000000,   0x00000000,
+   0x00000fff,   0xff00000f,   0xffff0000,   0x0fffff00,
+   0x000fffff,   0x00000000,   0x00000000,   0x00ffffff,
+   0xffcff000,   0x0000040f,   0xfffffffc,   0xff000000,
+   0x0080ffff,   0xffffcff0,   0x0000000c,   0x0fffffff,
+   0xfcff0000,   0x00000000,   0xffffffff,   0xffffffff,
+   0xfff55ff5,   0x5fffffff,   0xffffffff,   0xf0000000,
+   0xf00000f0,   0x00003c00,   0x007f0000,   0x01001fc0,
+   0x00408007,   0xf0002030,   0x01fc000c,   0x10007f00,
+   0x0405001f,   0xc0014180,   0x07f00060,   0x7001fc00,
+   0x1c20007f,   0x00080900,   0x1fc00242,   0x8007f000,
+   0xa0b001fc,   0x002c3000,   0x7f000c0d,   0x001fc003,
+   0x438007f0,   0x00e0f001,   0xfc003fff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffffc00,
+   0x00000000,   0x00000000,   0x00000000,   0x00000000,
+   0xffff0000,   0x00000000,   0xf0000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xfffffc00,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xfffffc00,   0x00000000,
+   0xffffffff,   0xffffffff,   0xf3ffffff,   0xffffffff,
+   0xfdffffff,   0xffffffff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xf3ffffff,   0xffffffff,
+   0xfdffffff,   0xffffffff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xfffff9ff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xfffff9ff,   0xfe000000,   0x00000000,
+   0x00030000,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff},
+
+/* rw_pdfet (READ_PRIV transactions)
+ *
+ * ctr0: counts address valid cycles 
+ * ctr1: counts *all* data valid cycles 
+ * ctr2: is the overflow from counter 0 
+ * ctr3: is the overflow from counter 1 
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x0000000c,0x00003c00,0x07930000,0x0041e4c0,
+0x01002079,0x3000800c,0x1e4c0030,0x00279300,
+0x010049e4,0xc0014022,0x79300090,0x0c9e4c00,
+0x34004793,0x00020051,0xe4c00180,0x24793000,
+0xa00d1e4c,0x00380067,0x93000300,0x59e4c001,
+0xc0267930,0x00b00d9e,0x4c003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0xf8000000,00000000,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff},
+
+/* rw_wdfet (WRITEBACKS)
+ *
+ * ctr0: counts address valid cycles 
+ * ctr1: counts *all* data valid cycles 
+ * ctr2: is the overflow from counter 0 
+ * ctr3: is the overflow from counter 1
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x0000000c,0x00003c00,0x07930000,0x0041e4c0,
+0x01002079,0x3000800c,0x1e4c0030,0x00279300,
+0x010049e4,0xc0014022,0x79300090,0x0c9e4c00,
+0x34004793,0x00020051,0xe4c00180,0x24793000,
+0xa00d1e4c,0x00380067,0x93000300,0x59e4c001,
+0xc0267930,0x00b00d9e,0x4c003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0x98000000,00000000,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff},
+
+/* shlib_cpi
+ *
+ * ctr0: Total number of instructions in quad 0 
+ * ctr1: Total number of CPU clock cycles in quad 0 
+ * ctr2: total instructions without nullified   
+ * ctr3: total number of CPU clock cycles 
+ */
+   {
+   0x0c01e000,   0x00000000,   0x00060000,   0x00000000,
+   0xe0e0e0e0,   0x004e0004,   0x07ffffff,   0xffc01380,
+   0x0101ffff,   0xfffff004,   0xe000407f,   0xfffffffc,
+   0x01380010,   0x1fffffff,   0xff000000,   0x00000000,
+   0x00000fff,   0xff00000f,   0xffffffff,   0xffffffff,
+   0xffffffff,   0x00000000,   0x00000000,   0x00ffffff,
+   0xffcff000,   0x0000000f,   0xfffffffc,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0xffffffff,   0xffffffff,
+   0xfff77ff5,   0x7fffffff,   0xffffffff,   0xf0000000,
+   0xf00000a0,   0x00003c00,   0x01ff0005,   0x08007fc0,
+   0x03c1001f,   0xf08030c0,   0x07fc203c,   0x4001ff08,
+   0x0118007f,   0xc003c500,   0x1ff08031,   0xc007fc00,
+   0x3fffffff,   0xf800ffff,   0xfffe003f,   0xffffff80,
+   0x0fffffff,   0xe003ffff,   0xfff800ff,   0xfffffe00,
+   0x3fffffff,   0x800fffff,   0xffe003ff,   0xfffff800,
+   0xfffffffe,   0x003fffff,   0xff800fff,   0xffffe003,
+   0xfffffff8,   0x00ffffff,   0xfe003fff,   0xffff800f,
+   0xffffffe0,   0x03ffffff,   0xf800ffff,   0xfffe003f,
+   0xffffff80,   0x0fffffff,   0xe003ffff,   0xfff800ff,
+   0xfffffe00,   0x3fffffff,   0x800fffff,   0xffe00000,
+   0x00000000,   0x00000000,   0x00000000,   0x00000000,
+   0xffff0000,   0x00000000,   0xf0000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xfffffc00,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xfffffc00,   0x00000000,
+   0xffffffff,   0xffffffff,   0xf3ffffff,   0xffffffff,
+   0xfdffffff,   0xffffffff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xf3ffffff,   0xffffffff,
+   0xfdffffff,   0xffffffff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xfffff9ff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xfffff9ff,   0xfe000000,   0x00000000,
+   0x00030000,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff},
+
+
+/* addr_inv_abort_alu
+ *
+ * ctr0: counts ABORT_ALU0L 
+ * ctr1: counts ABORT_ALU1L 
+ * ctr2: counts ADDR0_INVALID 
+ * ctr3: counts ADDR1_INVALID 
+ */
+
+{
+0x0c00c000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x6fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000d,0x01001fc0,
+0x03008007,0xf000f030,0x01fc0038,0x10007f00,
+0x0905001f,0xc0020180,0x07f000b0,0x7001fc00,
+0x2820007f,0x00050900,0x1fc00102,0x8007f000,
+0x70b001fc,0x00183000,0x7f00010d,0x001fc000,
+0x038007f0,0x0030f001,0xfc000bff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x65380000,00000000,0x60000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+
+
+/* brad_stall
+ *
+ * ctr0: counts the total number of cycles for which brad_stall is asserted 
+ * ctr1: counts the number of times brad_stall is asserted for 1-4 cycles 
+ * ctr2: counts the number of times brad_stall is asserted for 5-7 cycles 
+ * ctr3: counts the number of times brad_stall is asserted for > 7 cycles 
+ */
+{
+0x0c002000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x1fffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x00021c20,0x03ff0808,0x1800ffc4,
+0x0204003f,0xf0004280,0x0ffc6020,0x8003ff00,
+0x043800ff,0xc8020c00,0x3ff00044,0x800ffca0,
+0x210003ff,0x00045800,0xffcc0214,0x003ff000,
+0x26800ffc,0xe0218003,0xff000278,0x00ffd002,
+0x1c003ff0,0x0028800f,0xfd002200,0x03ff0001,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x1bff0000,00000000,0x10000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+/* cntl_in_pipel
+ *
+ * ctr0: counts the total number of cycles for which cntl_in_pipel is asserted 
+ * ctr1: counts the number of times cntl_in_pipel is asserted for 1-4 cycles 
+ * ctr2: counts the number of times cntl_in_pipel is asserted for 5-7 cycles 
+ * ctr3: counts the number of times cntl_in_pipel is asserted for > 7 cycles 
+ */
+{
+0x0c006000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x3fffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x00021c00,0x03ff0808,0x1000ffc4,
+0x0206003f,0xf0004200,0x0ffc6020,0xa003ff00,
+0x043000ff,0xc8020e00,0x3ff00044,0x000ffca0,
+0x212003ff,0x00045000,0xffcc0216,0x003ff000,
+0x26000ffc,0xe021a003,0xff000270,0x00ffd002,
+0x1e003ff0,0x0028000f,0xfd002220,0x03ff0001,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x3fff0000,00000000,0x30000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+
+/* dsnt_xfh
+ *
+ * ctr0: counts dside_notrans 
+ * ctr1: counts xfhang 
+ * ctr2: is the overflow for ctr0 
+ * ctr3: is the overflow for ctr1 
+ */
+{
+0x0c018000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xcfffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x00030000,0x01f30000,0x00087cc0,
+0x0040041f,0x30002001,0x87cc000c,0x1001f300,
+0x0404087c,0xc0014104,0x1f300060,0x4187cc00,
+0x1c2001f3,0x00080808,0x7cc00242,0x041f3000,
+0xa08187cc,0x002c3001,0xf3000c0c,0x087cc003,
+0x43041f30,0x00e0c187,0xcc003fc0,0x07fff800,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0xcb3f0000,00000000,0xc0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff }, 
+
+/* fet_sig1
+ *
+ * ctr0: counts ICORE_AV 
+ * ctr1: counts ITRANS_STALL 
+ * ctr2: counts SEL_PCQH 
+ * ctr3: counts OUT_OF_CONTEXT 
+ */
+{
+0x0c000000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x0fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x07c10000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+/* fet_sig2
+ *
+ * ctr0: counts ICORE_AV  
+ * ctr1: counts IRTN_AV 
+ * ctr2: counts ADDRESS_INC 
+ * ctr3: counts ADDRESS_DEC 
+ */
+{
+0x0c000000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x0fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x06930000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* g7_1
+ *
+ * ctr0: counts HIT_RETRY0 
+ * ctr1: counts HIT_RETRY1 
+ * ctr2: counts GO_TAG_E 
+ * ctr3: counts GO_TAG_O 
+ */
+{
+0x0c00e000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x7fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x71c10000,00000000,0x70000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* g7_2
+ *
+ * ctr0: counts HIT_DM0 
+ * ctr1: counts HIT_DM1 
+ * ctr2: counts GO_STORE_E 
+ * ctr3: counts GO_STORE_O 
+ */
+{
+0x0c00e000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x7fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x72930000,00000000,0x70000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* g7_3
+ *
+ * ctr0: counts HIT_DV0 
+ * ctr1: counts HIT_DV1 
+ * ctr2: counts STBYPT_E (load bypasses from store queue) 
+ * ctr3: counts STBYPT_O
+ */
+{
+0x0c00e000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x7fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f0002,0x01001fc0,
+0x00c08007,0xf0000030,0x01fc0004,0x10007f00,
+0x0605001f,0xc001c180,0x07f00040,0x7001fc00,
+0x1420007f,0x000a0900,0x1fc002c2,0x8007f000,
+0x80b001fc,0x00243000,0x7f000e0d,0x001fc003,
+0xc38007f0,0x00c0f001,0xfc0037ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x77250000,00000000,0x70000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* g7_4
+ *
+ * ctr0: counts HIT_DIRTY0 
+ * ctr1: counts HIT_DIRTY1 
+ * ctr2: counts CA_BYP_E (quick launch) 
+ * ctr3: counts CA_BYP_O 
+ */
+{
+0x0c00e000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x7fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x7bb70000,00000000,0x70000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+
+/* mpb_labort
+ *
+ * ctr0: counts L_ABORT_ALU0L
+ * ctr1: counts L_ABORT_ALU1L 
+ * ctr2: counts MPB0H 
+ * ctr3: counts MPB1H 
+ */
+{
+0x0c00c000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x6fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x605c0000,00000000,0x60000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* panic
+ *
+ * ctr0: is the overflow for counter 1 
+ * ctr1: counts traps and RFI's 
+ * ctr2: counts panic traps 
+ * ctr3: is the overflow for counter 2
+ */
+{
+0x0c002000,00000000,0x00060000,00000000,
+0xe7efe0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffffc,
+0x41380030,0x1aabfff2,0x17000000,00000000,
+0x01b80000,0x3effffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,00000000,0x00400000,
+0x00001fff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x1fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+0xb0000000,0x00012c04,0x05790804,0x14013e44,
+0x0008004f,0x90000040,0x15e46000,0xc0047920,
+0x004a003e,0x40011080,0x0f900024,0x4003e460,
+0x00c80479,0x00023301,0x1e400100,0x4157d080,
+0x514053f4,0x40048014,0xfd000104,0x055f4600,
+0x4c0147d2,0x0014a043,0xf4001508,0x10fd0003,
+0x44043f46,0x004c8147,0xd0003330,0x51f40014,
+0x04257908,0x0c14093e,0x44020802,0x4f900080,
+0x4095e460,0x20c02479,0x20084a08,0x3e400310,
+0x820f9000,0xa44083e4,0x6020c824,0x79000a33,
+0x091e4003,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x10400000,00000000,0x10000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* rare_inst
+ *
+ * ctr0: counts sync and syncdma instructions 
+ * ctr1: counts pxtlbx,x instructions 
+ * ctr2: counts ixtlbt instructions 
+ * ctr3: counts cycles 
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0x004e000c,0x000843fc,0x85c09380,
+0x0121ebfd,0xff217124,0xe0004000,0x943fc85f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xe00000e0,0x00003c00,0x007f0001,0x01001fc0,
+0x00408007,0xf0003030,0x01fc000c,0x10007f00,
+0x0505001f,0xc0014180,0x07f00070,0x7001fc00,
+0x1c20007f,0x00090900,0x1fc00242,0x8007f000,
+0xb0b001fc,0x002c3000,0x7f000d0d,0x001fc003,
+0x438007f0,0x00f0f001,0xfc003fff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* rw_dfet (for D-cache misses and writebacks)
+ *
+ * ctr0: counts address valid cycles 
+ * ctr1: counts *all* data valid cycles 
+ * ctr2: is the overflow from counter 0 
+ * ctr3: is the overflow from counter 1 
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x0000000c,0x00003c00,0x07930000,0x0041e4c0,
+0x01002079,0x3000800c,0x1e4c0030,0x00279300,
+0x010049e4,0xc0014022,0x79300090,0x0c9e4c00,
+0x34004793,0x00020051,0xe4c00180,0x24793000,
+0xa00d1e4c,0x00380067,0x93000300,0x59e4c001,
+0xc0267930,0x00b00d9e,0x4c003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0xf0000000,00000000,
+00000000,00000000,0x98000000,00000000,
+0xffffffff,0xffffffff,0x0fffffff,0xffffffff,
+00000000,00000000,0x00ffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* rw_ifet (I-cache misses -- actually dumb READ transactions)
+ *
+ * ctr0: counts address valid cycles 
+ * ctr1: counts *all* data valid cycles 
+ * ctr2: is the overflow from counter 0 
+ * ctr3: is the overflow from counter 1 
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x0000000c,0x00003c00,0x07930000,0x0041e4c0,
+0x01002079,0x3000800c,0x1e4c0030,0x00279300,
+0x010049e4,0xc0014022,0x79300090,0x0c9e4c00,
+0x34004793,0x00020051,0xe4c00180,0x24793000,
+0xa00d1e4c,0x00380067,0x93000300,0x59e4c001,
+0xc0267930,0x00b00d9e,0x4c003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0xd0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+0xffffffff,0xffffffff,00000000,00000000,
+0xffffffff,0xffffffff },
+
+
+/* rw_sdfet (READ_SHARED_OR_PRIVATE transactions)
+ *
+ * ctr0: counts address valid cycles
+ * ctr1: counts *all* data valid cycles 
+ * ctr2: is the overflow from counter 0 
+ * ctr3: is the overflow from counter 1 
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x0000000c,0x00003c00,0x07930000,0x0041e4c0,
+0x01002079,0x3000800c,0x1e4c0030,0x00279300,
+0x010049e4,0xc0014022,0x79300090,0x0c9e4c00,
+0x34004793,0x00020051,0xe4c00180,0x24793000,
+0xa00d1e4c,0x00380067,0x93000300,0x59e4c001,
+0xc0267930,0x00b00d9e,0x4c003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0xf4000000,00000000,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff },
+
+
+/* spec_ifet
+ *
+ * ICORE_AV fires for every request which the Instruction Fetch Unit sends
+ * to the Runway Interface Block.  Hence, this counts all I-misses, speculative
+ * or not, but does *not* include I-cache prefetches, which are generated by
+ * RIB.
+ * IRTN_AV fires twice for every I-cache miss returning from RIB to the IFU.
+ * It will not fire if a second I-cache miss is issued from the IFU to RIB
+ * before the first returns.  Therefore, if the IRTN_AV count is much less
+ * than 2x the ICORE_AV count, many speculative I-cache misses are occuring
+ * which are "discovered" to be incorrect fairly quickly.
+ * The ratio of I-cache miss transactions on Runway to the ICORE_AV count is
+ * a measure of the effectiveness of instruction prefetching.  This ratio
+ * should be between 1 and 2.  If it is close to 1, most prefetches are
+ * eventually called for by the IFU; if it is close to 2, almost no prefetches
+ * are useful and they are wasted bus traffic.
+ *
+ * ctr0: counts ICORE_AV 
+ * ctr1: counts IRTN_AV 
+ * ctr2: counts all non-coherent READ transactions on Runway. (TTYPE D0) 
+ *	This should be just I-cache miss and I-prefetch transactions.
+ * ctr3: counts total processor cycles 
+ */
+{
+0x0c000000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x0fffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x00000008,0x00030c00,0x01bf0001,0x00806fc0,
+0x00c1001b,0xf0005048,0x06fc001c,0x2001bf00,
+0x0908806f,0xc002c300,0x1bf000d0,0xc806fc00,
+0x3fffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0x06bf0000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00110000,00000000,0xd0ffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+0xffffffff,0xffffffff,00000000,00000000,
+0xffffffff,0xffffffff },
+
+/* st_cond0
+ *
+ * ctr0: is the overflow for ctr1
+ * ctr1: counts major ops 0C and 0E (fp ops, not fmac or fmpyadd) 
+ * ctr2: counts B,L (including long and push) and GATE (including nullified),
+ *	 predicted not-taken
+ * ctr3: is the overflow for ctr2 
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0e0c0e0,0xffffffff,0xffffffff,0xffc13380,
+0x0101ffff,0xffa1f057,0xe000407f,0xdfffc87f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_cond1
+ *
+ * ctr0: is the overflow for ctr1 
+ * ctr1: counts major ops 1x (most of the load/stores) 
+ * ctr2: counts CMPB (dw) predicted not-taken 
+ * ctr3: is the overflow for ctr2 
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0e0c0e0,0xffffffff,0xffffffff,0xffc01b80,
+0x0101ffff,0xffb7f03d,0xe000407f,0xffffc8ff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_cond2
+ *
+ * ctr0: is the overflow for ctr1 
+ * ctr1: counts major op 03 
+ * ctr2: counts CMPIB (dw) predicted not taken. 
+ * ctr3: is the overflow for ctr2 
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0e0c0e0,0xffffffff,0xffffffff,0xffc09780,
+0x0101ffff,0xff21f077,0xe000407f,0xffffc87f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_cond3
+ *
+ * ctr0: is the overflow for ctr1 
+ * ctr1: counts major ops 06 & 26 
+ * ctr2: counts BB, BVB, MOVB, MOVIB (incl. nullified) predicted not-taken 
+ * ctr3: is the overflow for ctr2 
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0e0c0e0,0xffffffff,0xffffffff,0xffc03780,
+0x0101ffff,0xff29f016,0xe000407f,0xffffe97f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_cond4
+ *
+ * ctr0: is the overflow for ctr1 
+ * ctr1: counts major op 2E 
+ * ctr2: counts CMPB, CMPIB, ADDB, ADDIB (incl. nullified) predicted not-taken 
+ * ctr3: is the overflow for ctr2 
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0e0c0e0,0xffffffff,0xffffffff,0xffc17780,
+0x0101ffff,0xff21f014,0xe000407f,0xffffe9ff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_unpred0
+ *
+ * ctr0: is the overflow for ctr1 
+ * ctr1: counts BE and BE,L 
+ * ctr2: counts BE and BE,L including nullified 
+ * ctr3: is the overflow for ctr2 
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0c0c0e0,0xffffffff,0xffffffff,0xffdf5bbf,
+0xffffffff,0xff25f7d6,0xefffffff,0xffffc97f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_unpred1
+ *
+ * ctr0: is the overflow for ctr1 
+ * ctr1: counts BLR, BV, BVE, BVE,L 
+ * ctr2: counts BLR, BV, BVE, BVE,L including nullified 
+ * ctr3: is the overflow for ctr2 
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0c0c0e0,0xffffffff,0xffffffff,0xffc15f80,
+0x0501ff7f,0xff21f057,0xe001407f,0xdfffc87f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* unpred
+ *
+ * ctr0: counts non-nullified unpredictable branches 
+ * ctr1: is the overflow for ctr0 
+ * ctr2: counts all unpredictable branches (nullified or not) 
+ * ctr3: is the overflow for ctr2 
+ */
+{
+0xcc01e000,00000000,0x00060000,00000000,
+0x20202020,0xff31ffff,0xfff7fffe,0x97ffcc7f,
+0xfffffdff,0xffa5fff3,0x1fffffff,0x7fffe97f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf00000a0,0x00003c00,0x02f50000,0x0004bd40,
+0x0040802f,0x50002020,0x4bd4000c,0x0042f500,
+0x040014bd,0x40014084,0x2f500060,0x214bd400,
+0x1c2002f5,0x00080804,0xbd400242,0x802f5000,
+0xa0a04bd4,0x002c2042,0xf5000c08,0x14bd4003,
+0x42842f50,0x00e0a14b,0xd4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+   
+
+/* go_store
+ *
+ * ctr0: Overflow for counter 2 
+ * ctr1: Overflow for counter 3 
+ * ctr2: count of GO_STORE_E signal 
+ * ctr3: count of GO_STORE_O signal 
+ */
+
+   {
+   0x0c00e000,   0x00000000,   0x00060000,   0x00000000,
+   0xe0e0e0e0,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffa5ffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xff000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x7fffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xf0000000,
+   0x00000000,   0x0000c000,   0x067c0000,   0x01019f00,
+   0x00408067,   0xc0002030,   0x19f0000c,   0x000e7c00,
+   0x0401039f,   0x00014080,   0xe7c00060,   0x3039f000,
+   0x1c00167c,   0x00080105,   0x9f000240,   0x8167c000,
+   0xa03059f0,   0x002c001e,   0x7c000c01,   0x079f0003,
+   0x4081e7c0,   0x00e03079,   0xf0003fc0,   0x07fff800,
+   0xf001fffe,   0x003c007f,   0xff800f00,   0x1fffe003,
+   0xc007fff8,   0x00f001ff,   0xfe003c00,   0x7fff800f,
+   0x001fffe0,   0x03c007ff,   0xf800f001,   0xfffe003c,
+   0x007fff80,   0x0f001fff,   0xe003c007,   0xfff800f0,
+   0x01fffe00,   0x3c007fff,   0x800f001f,   0xffe00000,
+   0x00000000,   0x00000000,   0x00000000,   0x00000000,
+   0x70130000,   0x00000000,   0x70000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xfffffc00,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xfffffc00,   0x00000000,
+   0xffffaaaa,   0xffffffff,   0xf3ffffff,   0xffffffff,
+   0xfdffffff,   0xffffffff,   0xfe000000,   0x00000000,
+   0xffffaaaa,   0xffffffff,   0xf3ffffff,   0xffffffff,
+   0xfdffffff,   0xffffffff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xfffff9ff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xfffff9ff,   0xfe000000,   0x00000000,
+   0x00030000,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff
+   },
+
+
+/* shlib_call
+ *
+ * ctr0: SharedLib call Depth1 
+ * ctr1: SharedLib call Depth2 
+ * ctr2: SharedLib call Depth3 
+ * ctr3: SharedLib call Depth>3 
+ */
+   {
+   0x0c01e000,   0x00000000,   0x00060000,   0x00000000,
+   0xe0e0e0e0,   0xc76fa005,   0x07dd7e9c,   0x87115b80,
+   0x01100200,   0x07200004,   0xe000407f,   0xfffffffc,
+   0x01380010,   0x1fffffff,   0xff000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xf0000000,
+   0xf0000000,   0x00003c20,   0x01ff0808,   0x04007fc0,
+   0x0003001f,   0xf0000180,   0x07fc4010,   0x5001ff00,
+   0x001c007f,   0xc2000a00,   0x1ff18022,   0x4007fc20,
+   0x00b001ff,   0x10003800,   0x7fc8004d,   0x001ff100,
+   0x03c007fc,   0x60012001,   0xff280144,   0x007fc600,
+   0x13001ff2,   0x00058007,   0xfcc00550,   0x01ff2000,
+   0x5c007fca,   0x001a001f,   0xf3801640,   0x07fca001,
+   0xb001ff30,   0x0078007f,   0xd0005d00,   0x1ff30007,
+   0xc007fce0,   0x022001ff,   0x48018400,   0x7fce0023,
+   0x001ff400,   0x098007fd,   0x20065001,   0xff40009c,
+   0x007fd200,   0x3fffffff,   0x800fffff,   0xffe00000,
+   0x00000000,   0x00000000,   0x00000000,   0x00000000,
+   0xffff0000,   0x00000000,   0xf0000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xfffffc00,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xfffffc00,   0x00000000,
+   0xffffffff,   0xffffffff,   0xf3ffffff,   0xffffffff,
+   0xfdffffff,   0xffffffff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xf3ffffff,   0xffffffff,
+   0xfdffffff,   0xffffffff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xfffff9ff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xfffff9ff,   0xfe000000,   0x00000000,
+   0x00030000,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff
+   }
+};
+#define PCXW_IMAGE_SIZE 576
+
+static uint32_t cuda_images[][PCXW_IMAGE_SIZE/sizeof(uint32_t)] = {
+/*
+ * CPI:     FROM CPI.IDF (Image 0)
+ *
+ * Counts the following:
+ *
+ * ctr0 : total cycles
+ * ctr1 : total cycles where nothing retired
+ * ctr2 : total instructions retired, including nullified
+ * ctr3 : total instructions retired, less nullified instructions
+ */
+   {
+   0x4c00c000,   0x00000000,   0x00060000,   0x00000000, 
+   0xe0e0e0e0,   0x00001fff,   0xfc00007f,   0xfff00001, 
+   0xffffc000,   0x07ffff00,   0x07ffffff,   0x6007ffff, 
+   0xff0007ff,   0xffff0007,   0xffffff00,   0x00000000, 
+   0x60f00000,   0x0fffff00,   0x000fffff,   0x00000fff, 
+   0xff00000f,   0xffff0000,   0x00000000,   0x00ffffff, 
+   0xfffff000,   0x0000000f,   0xffffffff,   0xff000000, 
+   0x0000ffff,   0xfffffff0,   0x00000000,   0x0fffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0x00270000,   0x00000055, 
+   0x0200000e,   0x4d300000,   0x00000000,   0x0ff00002, 
+   0x70000000,   0x00000020,   0x0000e400,   0x00000ff0, 
+   0x00000000,   0x00000000,   0x00000055,   0xffffff00, 
+   0x00000000,   0x0000ff00,   0x00000000,   0x0f000000, 
+   0x0000055f,   0xfffff000,   0x00000000,   0x000ff000, 
+   0x00000000,   0x00000000,   0x000055ff,   0xffff0000, 
+   0x00000000,   0x00ff0000,   0x00000000,   0xf0000000, 
+   0x000055ff,   0xffff0000,   0x00000000,   0x00ff0000, 
+   0x00000000,   0x00000000,   0x00055fff,   0xfff00000, 
+   0x00000000,   0x0ff00000,   0x00000030,   0x00000000, 
+   0x00157fff,   0xffc00000,   0x034c0000,   0x00000000, 
+   0x03fc0000,   0x00000000,   0x6fff0000,   0x00000000, 
+   0x60000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff7fbfc,   0x00000000,   0xffffafff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffafff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* Bus utilization image   FROM BUS_UTIL.IDF (Image 1)
+ *
+ * ctr0 : counts address valid cycles
+ * ctr1 : counts data valid cycles
+ * ctr2 : counts overflow from counter 0
+ * ctr3 : counts overflow from counter 1
+ */
+         {
+	 0x0c01e000, 0x00000000, 0x00060000, 0x00000000,
+	 0xefefefef, 0xffffffff, 0xffffffff, 0xffffffff,
+	 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	 0xffffffff, 0xffffffff, 0xffffff00, 0x00000000,
+	 0xf0ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+	 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+	 0x00000000, 0x00000000, 0x00001b00, 0xaa000000,
+	 0x00000001, 0x30700000, 0x00055aaf, 0xf0000000,
+	 0x01b00000, 0x00000000, 0x00001037, 0x00000000,
+	 0x55aaff00, 0x00c00000, 0x1b55aa00, 0x00000000,
+	 0x0001fff0, 0xcfffff00, 0x00000000, 0x0f0fffff,
+	 0xffffffff, 0xffffffff, 0x30ffff0c, 0xfffff000,
+	 0x00000000, 0x00ffffff, 0xffffffff, 0xfffffff3,
+	 0x0ffff0cf, 0xffff0000, 0x00000000, 0x00ffffff,
+	 0xffffffff, 0xfffffff3, 0x0ffff0cf, 0xffff0000,
+	 0x00000000, 0x0fffffff, 0xffffffff, 0xffffff30,
+	 0xfff70000, 0x000055aa, 0xff000000, 0x000006d5,
+	 0x40000000, 0x00000000, 0x731c0000, 0x000156ab,
+	 0xfc000000, 0x00000000, 0xffff0000, 0x00000000,
+	 0xf0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+	 0xffffffff, 0xffcfffff, 0xfff7fbfc, 0x00000000,
+	 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+	 0xfff7fbfc, 0x00000000, 0xffffffff, 0xffffff3f,
+	 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+	 0x00000000, 0x00000000, 0xffffffff, 0xffffff3f,
+	 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+	 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+	 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+	 0xfe000000, 0x00000000, 0x00100000, 0x00000000,
+	 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+   },
+
+/*
+ * TLB counts:    FROM TLBSTATS.IDF (Image 2)
+ *
+ * Counts the following:
+ *
+ * ctr0: DTLB misses
+ * ctr1: ITLB misses
+ * ctr2: total cycles in the miss handlers
+ * ctr3: total cycles
+ */
+
+   {
+   0x0c00c000,   0x00000000,   0x00060000,   0x00000000, 
+   0xe7e7e0e0,   0x00001fff,   0xfc00007f,   0xfff00001, 
+   0xfff00000,   0x07ffff00,   0x07ffffff,   0x6007ffff, 
+   0xa00007ff,   0xffff0007,   0xffffff00,   0x00000000, 
+   0x603001c1,   0xe0000001,   0xc0c00000,   0x00000fff, 
+   0xff00000f,   0xffff0000,   0x00000000,   0x00400000, 
+   0x00001000,   0x00000004,   0x00000000,   0x01000000, 
+   0x0000ffff,   0xfffffff0,   0x00000000,   0x0fffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0x00800000,   0x00153f7f, 
+   0x55000000,   0xaf800000,   0xc0000000,   0x0403f240, 
+   0x00000000,   0x00001010,   0x00004700,   0x00000ff0, 
+   0x00000000,   0x00000000,   0x00000055,   0xffffff00, 
+   0x00000000,   0x0000ff00,   0x00000000,   0x0f000000, 
+   0x0000055f,   0xfffff000,   0x00000000,   0x000ff000, 
+   0x00000000,   0x00000000,   0x000055ff,   0xffff0000, 
+   0x00000000,   0x00ff0000,   0x00000000,   0xf0000000, 
+   0x000055ff,   0xffff0000,   0x00000000,   0x00ff0000, 
+   0x00000000,   0x00000000,   0x00055fff,   0xfff00000, 
+   0x00000000,   0x0ff00000,   0x00000000,   0x00000000, 
+   0x00157fff,   0xffc00000,   0x00000000,   0x3fc00000, 
+   0x00040000,   0x00000000,   0x6fff0000,   0x00000000, 
+   0x60000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff7fbfc,   0x00000000,   0xffffafff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffafff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* tlbhandler  FROM tlbHandMiss.idf (Image 3)
+ *
+ * ctr0: TLB misses
+ * ctr1: dmisses inside the TLB miss handler
+ * ctr2: cycles in the TLB miss handler
+ * ctr3: overflow of ctr2
+ */
+   {
+   0x1c00c000,   0x00000000,   0x00060000,   0x00000000, 
+   0xe7e7e0e0,   0x00001fff,   0xfc00007f,   0xfff00001, 
+   0xfff00000,   0x07ffff00,   0x07ffffff,   0x6007ffff, 
+   0xa00007ff,   0xffff0007,   0xffffff00,   0x00000000, 
+   0x603001c1,   0xe0000001,   0xc0c00000,   0x00000fff, 
+   0xff00000f,   0xffff0000,   0x00000000,   0x00400000, 
+   0x00001000,   0x00000004,   0x00000000,   0x01000000, 
+   0x0000ffff,   0xfffffff0,   0x00000000,   0x0fffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0x006c0000,   0x01000054, 
+   0x02000002,   0xc3200000,   0xc00aa000,   0x0c03f240, 
+   0x00000000,   0x00001010,   0x000044f4,   0x00000c00, 
+   0xaa0000f0,   0x0f0000b0,   0x00005005,   0x0f5f0000, 
+   0x0001f000,   0x0000ff00,   0x00000000,   0x0f000000, 
+   0x0000055f,   0xfffff000,   0x00000000,   0x000ff000, 
+   0x00000000,   0x00000000,   0x000055ff,   0xffff0000, 
+   0x00000000,   0x00ff0000,   0x00000000,   0xf0000000, 
+   0x000055ff,   0xffff0000,   0x00000000,   0x00ff0000, 
+   0x00000000,   0x00000000,   0x00055fff,   0xfff00000, 
+   0x00000000,   0x0ff00a00,   0x000f0000,   0x24004000, 
+   0x15400001,   0x40c00003,   0x3da00000,   0x0002a800, 
+   0x00ff0000,   0x00000000,   0x6fff0000,   0x00000000, 
+   0x60000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff7fbfc,   0x00000000,   0xffffafff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffafff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* branch_taken image  FROM PTKN.IDF (Image 4)
+ *
+ * ctr0: mispredicted branches
+ * ctr1: predicted taken branches, actually taken
+ * ctr2: predicted taken branches (includes nullfied)
+ * ctr3: all branches
+ */
+
+   {
+   0xcc01e000,   0x00000000,   0x00000000,   0x00000000, 
+   0xa08080a0,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xfffffeff,   0xfffeffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000, 
+   0xf4ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0xd22d0000,   0x00000000, 
+   0x0000000b,   0x46000000,   0x00000000,   0x0ffff900, 
+   0x90000000,   0x00000000,   0x0000907e,   0x00000000, 
+   0x000000ff,   0xff00bfdf,   0x03030303,   0x03030000, 
+   0x000dbfff,   0xffffff00,   0x00000000,   0x0f0fffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000, 
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000, 
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff, 
+   0xffff5555,   0x55500000,   0x003f3ff0,   0x2766c000, 
+   0x00000000,   0x00000002,   0x67840000,   0x00000000, 
+   0x03fffc00,   0x00000000,   0xffff0000,   0x00000000, 
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff7fbfc,   0x00000000,   0xffffffff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* branch_nottaken  FROM PNTKN.IDF (Image 5)
+ *
+ * ctr0: mispredicted branches
+ * ctr1: branches predicted not-taken, but actually taken
+ * ctr2: branches predicted not-taken (includes nullified)
+ * ctr3: all branches
+ */
+   {
+   0xcc01e000,   0x00000000,   0x00000000,   0x00000000, 
+   0xe0c0c0e0,   0xffffffff,   0xffffffff,   0xffefffff, 
+   0xffffbfff,   0xfffffeff,   0xfffeffff,   0xfffffeff, 
+   0xfffffffe,   0xffffffff,   0xffffff00,   0x00000000, 
+   0xf4ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0xd22d0000,   0x00000000, 
+   0x0000000b,   0x46000000,   0x00000000,   0x0ffff900, 
+   0x90000000,   0x00000000,   0x0000907e,   0x00000000, 
+   0x000000ff,   0xff00bfdf,   0x03030303,   0x03030000, 
+   0x000dbfff,   0xffffff00,   0x00000000,   0x0f0fffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000, 
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000, 
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff, 
+   0xffff5555,   0x55500000,   0x003f3ff0,   0x2766c000, 
+   0x00000000,   0x00000002,   0x67840000,   0x00000000, 
+   0x03fffc00,   0x00000000,   0xffff0000,   0x00000000, 
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff7fbfc,   0x00000000,   0xffffffff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+   
+/* IMISS image (Image 6)
+ *
+ * ctr0 : icache misses for retired instructions
+ * ctr1 : total cycles
+ * ctr2 : dcache misses for retired instructions
+ * ctr3 : number of retired instructions
+ */
+   {
+   0x2801e000,   0x00000000,   0x00010000,   0x00000000, 
+   0x00001000,   0xffffffff,   0xffffffff,   0xfff00fff, 
+   0xfffa3fff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000, 
+   0xf0ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0xf2fdf0f0,   0xf0f0f0f0, 
+   0xffffffff,   0xf6c00000,   0x00000000,   0x0ff55800, 
+   0x90000000,   0x00000000,   0x0000b0ff,   0xfffffff0, 
+   0x00000003,   0x0100bfff,   0x3f3f3f3f,   0x3f3f5555, 
+   0x555fffff,   0xffffff00,   0x00000000,   0x000fffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000, 
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000, 
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xfff00000,   0x000301b0,   0x2fefcfcf, 
+   0xcfcfcfcf,   0xd5555557,   0xf7b40000,   0x00000000, 
+   0x03c14000,   0x00000000,   0xffff0000,   0x00000000, 
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff6fb7c,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff6fb7c,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00130000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* DMISS image (Image 7)
+ *
+ * ctr0 : icache misses for retired instructions
+ * ctr1 : total cycles
+ * ctr2 : dcache misses for retired instructions
+ * ctr3 : number of retired instructions
+ */
+   {
+   0x2801e000,   0x00000000,   0x00010000,   0x00000000, 
+   0x00001000,   0xffffffff,   0xffffffff,   0xfff00fff, 
+   0xfffa3fff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000, 
+   0xf0ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0xf2fdf0f0,   0xf0f0f0f0, 
+   0xffffffff,   0xf6c00000,   0x00000000,   0x0ff55800, 
+   0x90000000,   0x00000000,   0x0000b0ff,   0xfffffff0, 
+   0x00000003,   0x0100bfff,   0x3f3f3f3f,   0x3f3f5555, 
+   0x555fffff,   0xffffff00,   0x00000000,   0x000fffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000, 
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000, 
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xfff00000,   0x000301b0,   0x2fefcfcf, 
+   0xcfcfcfcf,   0xd5555557,   0xf7b40000,   0x00000000, 
+   0x03c14000,   0x00000000,   0xffff0000,   0x00000000, 
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff6fb7c,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff6fb7c,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00130000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* dmiss_access image    FROM DMISS_RATIO.IDF  (Image 8)
+ * 
+ * ctr0 : all loads and stores that retire (even lines)
+ * ctr1 : all loads and stores that retire (odd lines)
+ * ctr2 : dcache misses of retired loads/stores
+ * ctr3 : all READ_PRIV and READ_SHAR_OR_PRIV on Runway
+ *        (Speculative and Non-Speculative)
+ */
+   {
+   0x2d81e000,   0x00000000,   0x00000000,   0x00000000, 
+   0x10101010,   0x00ffffff,   0xa003ffff,   0xfe800fff, 
+   0xfffa003f,   0xffffe8ff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000, 
+   0xf0ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0xd2280a00,   0x00000000, 
+   0x0000000b,   0x46000000,   0x00000005,   0x555ff900, 
+   0x80200000,   0x00000000,   0x0000907e,   0x00000000, 
+   0x00005555,   0xff80bf8b,   0xab030303,   0x03030000, 
+   0x000dbfff,   0xffffff00,   0x00000000,   0x000fffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000, 
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000, 
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff, 
+   0xffff5555,   0x55500000,   0x15153fe0,   0x27628880, 
+   0x00000000,   0x00000002,   0x67840000,   0x00000001, 
+   0x5557fc00,   0x00000000,   0xffff0000,   0x00000000, 
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff6fb7c,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff6fb7c,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00110000,   0x00000000, 
+   0xf4ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xf8ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0x00ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0x00ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+
+/* big_cpi image  (Image 9)
+ * 
+ * ctr0 : Total number of CPU clock cycles. 
+ * ctr1 : Unused 
+ * ctr2 : Unused
+ * ctr3 : Total number of Non-Nullified instructions retired. 
+ */
+   {
+   0x0c00c000,   0x00000000,   0x00060000,   0x00000000,
+   0xe7e7e0e0,   0x00001fff,   0xfc00007f,   0xfff00001,
+   0xfff00000,   0x07ffff00,   0x07ffffff,   0x6007ffff,
+   0xa00007ff,   0xffff0007,   0xffffff00,   0x00000000,
+   0x603001c1,   0xe0000001,   0xc0c00000,   0x00000fff,
+   0xff00000f,   0xffff0000,   0x00000000,   0x00400000,
+   0x00001000,   0x00000004,   0x00000000,   0x01000000,
+   0x0000ffff,   0xfffffff0,   0x00000000,   0x0fffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0x00550005,   0x00220000,
+   0x0000000c,   0x71f00000,   0x00f00aa0,   0x0aaff000,
+   0x00005002,   0x20000000,   0x0000c413,   0x00000c0f,
+   0x00aa0000,   0xff00b600,   0x000500a0,   0x00000300,
+   0x000cc3f0,   0x0000c0f0,   0x0aa0000f,   0xff000000,
+   0x011000a0,   0x05503000,   0x00d03700,   0x00000f00,
+   0xaa005500,   0x00000000,   0x000055ff,   0xffff0000,
+   0x00000000,   0x00ff0000,   0x00000000,   0xf000aa00,
+   0x11000a00,   0x55000000,   0x0d037000,   0x00c0f00a,
+   0xa0055000,   0x0db00005,   0x5002a000,   0x00300000,
+   0xf40f0000,   0x0c0f00aa,   0x0000ff10,   0x27400000,
+   0x00008000,   0x00c00003,   0x037c0000,   0x003c02a8,
+   0x02abfc00,   0x00000000,   0x6fff0000,   0x00000000,
+   0x60000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff7fbfc,   0x00000000,   0xffffafff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffafff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* big_ls image  (Image 10)
+ * 
+ * ctr0 : Total number of CPU clock cycles during which local_stall_A1 is asserted 
+ * ctr1 : Overflow of Counter 0 
+ * ctr2 : Total number of IFLUSH_AV 
+ * ctr3 : Overflow of Counter 2 
+ */
+   {
+   0x0c000000,   0x00000000,   0x00060000,   0x00000000,
+   0xefefefef,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000,
+   0x00ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0x28880001,   0x54000000,
+   0x00000004,   0xb6200000,   0x000aaaa0,   0x05555288,
+   0x80000010,   0x00000000,   0x0000486e,   0x00000000,
+   0xaaaa0055,   0x55002888,   0x00545401,   0x03030000,
+   0x0007b000,   0x0000ff00,   0x00000000,   0x05000000,
+   0x0000055f,   0xfffff000,   0x00000000,   0x000ff000,
+   0x00000000,   0x00000000,   0x000055ff,   0xffff0000,
+   0x00000000,   0x00ff0000,   0x00000000,   0x00000000,
+   0x000055ff,   0xffff0000,   0x00000000,   0x00ff0000,
+   0x00000000,   0xa0000000,   0x00055fff,   0xfff00000,
+   0x00aa0000,   0x05502a2a,   0x00151500,   0x0a220015,
+   0x40400000,   0x00000001,   0xe2980000,   0x0002aaa8,
+   0x01555400,   0x00000000,   0x0df70000,   0x00000000,
+   0x00000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff7fbfc,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* br_abort image  (Image 12)
+ * 
+ * ctr0 : Total number of BRAD_STALLH
+ * ctr1 : Total number of ONE_QUAD
+ * ctr2 : Total number of BR0_ABRT
+ * ctr3 : Total number of BR1_ABRT
+ */
+
+   {
+   0x0c002000,   0x00000000,   0x00060000,   0x00000000,
+   0xe0e0e0e0,   0xffffffff,   0xffffffff,   0xff0fffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000,
+   0x1077ffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0x551b0000,   0x00000000,
+   0x0000000c,   0xd4f00000,   0x00000000,   0x0ffff001,
+   0xb0000000,   0x00000000,   0x0000fd4c,   0x00000000,
+   0x000000ff,   0xff00ff1b,   0x00000000,   0x00000000,
+   0x0000d000,   0x0000ff00,   0x00000000,   0x0e0fffff,
+   0xffffffff,   0xfffff000,   0x00000000,   0x000ff000,
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffff0000,
+   0x00000000,   0x00ff0000,   0x00000000,   0x00ffffff,
+   0xffffffff,   0xffff0000,   0x00000000,   0x00ff0000,
+   0x00000000,   0xffffffff,   0xffffffff,   0xfff00000,
+   0x00400000,   0x00000000,   0x00ffff00,   0x2a86c000,
+   0x00000000,   0x00000000,   0xf50c0000,   0x00000000,
+   0x03fffc00,   0x00000000,   0x1a250000,   0x00000000,
+   0x10000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff7fbfc,   0x00000000,   0xffffafff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffafff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+
+/* isnt image  (Image 13)
+ * 
+ * ctr0 : Total number of cycles for which iside_notrans is asserted. 
+ * ctr1 : Total number of times iside_notrans is asserted for 1-4 cycles. 
+ * ctr2 : Total number of times iside_notrans is asserted for 5-7 cycles. 
+ * ctr3 : Total number of times iside_notrans is asserted for > 7 cycles. 
+ */
+
+   {
+   0x0c018000,   0x00000000,   0x00060000,   0x00000000,
+   0xefefefef,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000,
+   0xc0ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0x22000000,   0x000001bc,
+   0x10000006,   0x00900000,   0x50000000,   0x00055a20,
+   0x00000000,   0x00016060,   0x0000c021,   0x00000540,
+   0x00000000,   0x55002200,   0x00000000,   0x56bc4000,
+   0x00048000,   0x0000ff00,   0x00000000,   0x17000000,
+   0x0000055f,   0xfffff000,   0x00000000,   0x000ff000,
+   0x00000000,   0x00000000,   0x000055ff,   0xffff0000,
+   0x00000000,   0x00ff0000,   0x00000000,   0x00000000,
+   0x000055ff,   0xffff0000,   0x00000000,   0x00ff0000,
+   0x00000000,   0x80000000,   0x00015bf3,   0xf5500000,
+   0x02210000,   0x00100000,   0x00005500,   0x08800000,
+   0x00001545,   0x85000001,   0x80240000,   0x11000000,
+   0x00015400,   0x00000000,   0xcdff0000,   0x00000000,
+   0xc0000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff7fbfc,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* quadrant image  (image 14)
+ * 
+ * ctr0 : Total number of instructions in quadrant 0. 
+ * ctr1 : Total number of instructions in quadrant 1. 
+ * ctr2 : Total number of instructions in quadrant 2. 
+ * ctr3 : Total number of instructions in quadrant 3. 
+ *
+ * Only works for 32-bit applications.
+ */
+
+   {
+   0x0c01e000,   0x00000000,   0x00060000,   0x00000000,
+   0xe0e0e0e0,   0x00001fff,   0xfc00007f,   0xfff00001,
+   0xffffc000,   0x07ffff00,   0x07ffffff,   0x0007ffff,
+   0xff0007ff,   0xffff0007,   0xffffff00,   0x00000000,
+   0xf0000000,   0x0fffff00,   0x000fffff,   0x00000fff,
+   0xff00000f,   0xffff0000,   0x00000000,   0x00ffffff,
+   0xffcff000,   0x0000040f,   0xfffffffc,   0xff000000,
+   0x0080ffff,   0xffffcff0,   0x0000000c,   0x0fffffff,
+   0xfcff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0x551b0000,   0x00000000,
+   0x00000003,   0x17000000,   0x00000000,   0x0ffff001,
+   0xb0000000,   0x00000000,   0x00000173,   0x00000000,
+   0x000000ff,   0xff00ff1b,   0x00000000,   0x00000000,
+   0x000f1ff0,   0xcfffff00,   0x00000000,   0x0f0fffff,
+   0xffffffff,   0xffffffff,   0x30ffff0c,   0xfffff000,
+   0x00000000,   0x00ffffff,   0xffffffff,   0xfffffff3,
+   0x0ffff0cf,   0xffff0000,   0x00000000,   0xf0ffffff,
+   0xffffffff,   0xfffffff3,   0x0ffff0cf,   0xffff0000,
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffff30,
+   0xff7f0000,   0x00000000,   0x00fffff0,   0x2a86c000,
+   0x00000000,   0x00000003,   0x05f00000,   0x00000000,
+   0x03fffc00,   0x00000000,   0xffff0000,   0x00000000,
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff7fbfc,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* rw_pdfet image (Image 15)
+ * 
+ * ctr0 : Total of all READ_PRIV address valid cycles. 
+ * ctr1 : Total of all READ_PRIV data valid cycles. 
+ * ctr2 : Overflow of Counter 0. 
+ * ctr3 : Overflow of Counter 1. 
+ */
+
+   {
+   0x0c01e000,   0x00000000,   0x00060000,   0x00000000,
+   0xefefefef,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000,
+   0xf0ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0x00001b00,   0xaa000000,
+   0x00000001,   0x30700000,   0x00055aaf,   0xf0000000,
+   0x01b00000,   0x00000000,   0x00001037,   0x00000000,
+   0x55aaff00,   0x00c00000,   0x1b55aa00,   0x00000000,
+   0x0001fff0,   0xcfffff00,   0x00000000,   0x0f0fffff,
+   0xffffffff,   0xffffffff,   0x30ffff0c,   0xfffff000,
+   0x00000000,   0x00ffffff,   0xffffffff,   0xfffffff3,
+   0x0ffff0cf,   0xffff0000,   0x00000000,   0x00ffffff,
+   0xffffffff,   0xfffffff3,   0x0ffff0cf,   0xffff0000,
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffff30,
+   0xfff70000,   0x000055aa,   0xff000000,   0x000006d5,
+   0x40000000,   0x00000000,   0x731c0000,   0x000156ab,
+   0xfc000000,   0x00000000,   0xffff0000,   0x00000000,
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff7fbfc,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00100000,   0x00000000,
+   0xf8000000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffffff,
+   0x00ffffff,   0xffffffff,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffffff,
+   },
+
+
+/* rw_wdfet image  (Image 16)
+ * 
+ * ctr0 : Counts total number of writeback transactions. 
+ * ctr1 : Total number of data valid Runway cycles. 
+ * ctr2 : Overflow of Counter 0. 
+ * ctr3 : Overflow of Counter 1. 
+ */
+
+   {
+   0x0c01e000,   0x00000000,   0x00060000,   0x00000000,
+   0xefefefef,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000,
+   0xf0ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0x00001b00,   0xaa000000,
+   0x00000001,   0x30700000,   0x00055aaf,   0xf0000000,
+   0x01b00000,   0x00000000,   0x00001037,   0x00000000,
+   0x55aaff00,   0x00c00000,   0x1b55aa00,   0x00000000,
+   0x0001fff0,   0xcfffff00,   0x00000000,   0x0f0fffff,
+   0xffffffff,   0xffffffff,   0x30ffff0c,   0xfffff000,
+   0x00000000,   0x00ffffff,   0xffffffff,   0xfffffff3,
+   0x0ffff0cf,   0xffff0000,   0x00000000,   0x00ffffff,
+   0xffffffff,   0xfffffff3,   0x0ffff0cf,   0xffff0000,
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffff30,
+   0xfff70000,   0x000055aa,   0xff000000,   0x000006d5,
+   0x40000000,   0x00000000,   0x731c0000,   0x000156ab,
+   0xfc000000,   0x00000000,   0xffff0000,   0x00000000,
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff7fbfc,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00100000,   0x00000000,
+   0x98000000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffffff,
+   0x00ffffff,   0xffffffff,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffffff,
+   },
+
+/* shlib_cpi image  (Image 17)
+ * 
+ * ctr0 : Total number of instructions in quadrant 0. 
+ * ctr1 : Total number of CPU clock cycles in quadrant 0. 
+ * ctr2 : Total number of Non-Nullified instructions retired. 
+ * ctr3 : Total number of CPU clock cycles. 
+ *
+ * Only works for 32-bit shared libraries.
+ */
+
+   {
+   0x0c01e000,   0x00000000,   0x00060000,   0x00000000,
+   0xe0e0e0e0,   0x00001fff,   0xfc00007f,   0xfff00001,
+   0xffffc000,   0x07ffff00,   0x07ffffff,   0x0007ffff,
+   0xff0007ff,   0xffff0007,   0xffffff00,   0x00000000,
+   0xf0150000,   0x0fffff00,   0x000fffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0x00000000,   0x00ffffff,
+   0xffcff000,   0x0000000f,   0xfffffffc,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0x27000000,   0x00000055,
+   0x02000005,   0x7f500000,   0xc0000000,   0x000ff270,
+   0x00000000,   0x00000000,   0x00007700,   0x00000ff0,
+   0x00000000,   0x0000ffff,   0xffffffff,   0xffffff00,
+   0x00000000,   0x0000ff00,   0x00000000,   0x0f0fffff,
+   0xffffffff,   0xfffff000,   0x00000000,   0x000ff000,
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffff0000,
+   0x00000000,   0x00ff0000,   0x00000000,   0xf0ffffff,
+   0xffffffff,   0xffff0000,   0x00000000,   0x00ff0000,
+   0x00000000,   0x0fffffff,   0xffffffff,   0xfff00000,
+   0x00000000,   0x0ff00000,   0x000000a0,   0x3fffffff,
+   0xffffffff,   0xffc00000,   0x03d40000,   0x20000000,
+   0x0003fc00,   0x00000000,   0xffff0000,   0x00000000,
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff7fbfc,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* flop image  (Image 18)
+ * 
+ * ctr0 : Total number of floating point instructions (opcode = 0xc). 
+ * ctr1 : Total number of floating point instructions (opcode = 0xe, 0x6, 0x2e, 0x26). 
+ * ctr2 : Unused
+ * ctr3 : Unused 
+ */
+
+   {
+   0x0001e000,   0x00000000,   0x00000000,   0x00000000,
+   0x00001010,   0x33ffffff,   0x006fffff,   0xfc5fffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000,
+   0xf0ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0xd22d0000,   0x00000000,
+   0x0000000b,   0x46000000,   0x00000000,   0x0ffff900,
+   0x90000000,   0x00000000,   0x0000907e,   0x00000000,
+   0x000000ff,   0xff00bfdf,   0x03030303,   0x03030000,
+   0x000dbfff,   0xffffff00,   0x00000000,   0x000fffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000,
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000,
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff,
+   0xffff5555,   0x55500000,   0x003f3ff0,   0x2766c000,
+   0x00000000,   0x00000002,   0x67840000,   0x00000000,
+   0x03fffc00,   0x00000000,   0xffff0000,   0x00000000,
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff6fb7c,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff6fb7c,   0x00000000,   0xffff0fff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffff0fff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00130000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* cachemiss image    FROM I_D_MISSES.IDF  (Image 19)
+ *
+ * ctr0 : icache misses for retired instructions
+ * ctr1 : total cycles
+ * ctr2 : dcache misses for retired instructions
+ * ctr3 : number of retired instructions
+ */
+   {
+   0x2801e000,   0x00000000,   0x00010000,   0x00000000, 
+   0x00001000,   0xffffffff,   0xffffffff,   0xfff00fff, 
+   0xfffa3fff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000, 
+   0xf0ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0xf2fdf0f0,   0xf0f0f0f0, 
+   0xffffffff,   0xf6c00000,   0x00000000,   0x0ff55800, 
+   0x90000000,   0x00000000,   0x0000b0ff,   0xfffffff0, 
+   0x00000003,   0x0100bfff,   0x3f3f3f3f,   0x3f3f5555, 
+   0x555fffff,   0xffffff00,   0x00000000,   0x000fffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000, 
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000, 
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xfff00000,   0x000301b0,   0x2fefcfcf, 
+   0xcfcfcfcf,   0xd5555557,   0xf7b40000,   0x00000000, 
+   0x03c14000,   0x00000000,   0xffff0000,   0x00000000, 
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff6fb7c,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff6fb7c,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00130000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* branch   FROM br_report3.idf 
+ *
+ * ctr0 : Total number of mispredicted branches. 
+ * ctr1 : Some Non-Nullified unpredictable branches. 
+ * ctr2 : Total number of branches (Nullified + Non-Nullified)
+ *        (Unpredicted+ Predicted Taken +Predicted Not Taken). 
+ *	  Total of All Branches.
+ * ctr3 : Remaining Non-Nullified unpredictable branches.
+ */
+   {
+   0x4001e000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0xffffffff,   0xff9fffff,   0xfe0fffff, 
+   0xffffbaff,   0xfdffc0ff,   0xfffdffff,   0xfffffeff, 
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000, 
+   0xf4ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0xd22d0000,   0x00000000, 
+   0x0000000b,   0x46000000,   0x00000000,   0x0ffff900, 
+   0x90000000,   0x00000000,   0x0000907e,   0x00000000, 
+   0x000000ff,   0xff00bfdf,   0x03030303,   0x03030000, 
+   0x000dbfff,   0xffffff00,   0x00000000,   0x000fffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000, 
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000, 
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff, 
+   0xffff5555,   0x55500000,   0x003f3ff0,   0x2766c000, 
+   0x00000000,   0x00000002,   0x67840000,   0x00000000, 
+   0x03fffc00,   0x00000000,   0xffff0000,   0x00000000, 
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff6fb7c,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff6fb7c,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00130000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* crstack  FROM crs_report.idf
+ *
+ * ctr0: correctly predicted branches by the pop_latch
+ * ctr1: some procedure returns
+ * ctr2: all branches, (includes nullified)
+ * ctr3: remaining procedure returns
+ */
+   {
+   0x4001e000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0xffffffff,   0xffa10300,   0x000fffff, 
+   0xffffbaf8,   0x3000007f,   0xffffffff,   0xfffffeff, 
+   0xff7fffff,   0xffffffff,   0xffffff00,   0x00000000, 
+   0xf2ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0xd22d0000,   0x00000000, 
+   0x0000000b,   0x46000000,   0x00000000,   0x0ffff900, 
+   0x90000000,   0x00000000,   0x0000907e,   0x00000000, 
+   0x000000ff,   0xff00bfdf,   0x03030303,   0x03030000, 
+   0x000dbfff,   0xffffff00,   0x00000000,   0x000fffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000, 
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000, 
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff, 
+   0xffff5555,   0x55500000,   0x003f3ff0,   0x2766c000, 
+   0x00000000,   0x00000002,   0x67840000,   0x00000000, 
+   0x03fffc00,   0x00000000,   0xffff0000,   0x00000000, 
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff6fb7c,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff6fb7c,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00130000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* icache_report image 
+ * 
+ * ctr0 : Icache misses actually used by the core. 
+ * ctr1 : ICORE_AV (Icache misses the core THINKS it needs, including fetching down speculative paths). 
+ * ctr2 : READs on Runway (Icache misses that made it out to Runway, including
+ *	  prefetches).
+ * ctr3 : Prefetch returns (1x and 2x). 
+ */
+   {
+   0x00000000,   0x00000000,   0x00010000,   0x00000000,
+   0x00000000,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000,
+   0x00ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0xd2002d00,   0x00000000,
+   0x0000000b,   0x46000000,   0x0000000f,   0xf00ff900,
+   0x00900000,   0x00000000,   0x0000907e,   0x00000000,
+   0x0000ff00,   0xff83bf03,   0xdf030303,   0x03030000,
+   0x000dbfff,   0xffffff00,   0x00000000,   0x000fffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000,
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0x00000000,   0x80ffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000,
+   0x00000000,   0x4fffffff,   0xffffffff,   0xffffffff,
+   0xffff5555,   0x55500000,   0x3f003f80,   0x274026c0,
+   0x00000000,   0x00000002,   0x67840000,   0x00000003,
+   0xfc03fc00,   0x00000000,   0x0eff0000,   0x00000000,
+   0x00000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff6fb7c,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff6fb7c,   0x00000000,   0xffff0fff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffff0fff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00130000,   0x00000000,
+   0xd0ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0x00ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   
+   }
+
+};
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/power.c linux-2.4.20/arch/parisc/kernel/power.c
--- linux-2.4.19/arch/parisc/kernel/power.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/power.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,377 @@
+/*
+ * linux/arch/parisc/kernel/power.c
+ * HP PARISC soft power switch support driver
+ *
+ * Copyright (c) 2001-2002 Helge Deller <deller@gmx.de>
+ * All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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
+ *
+ *
+ * 
+ *  HINT:
+ *  Support of the soft power switch button may be enabled or disabled at
+ *  runtime through the "/proc/sys/kernel/power" procfs entry.
+ */ 
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+
+#include <asm/gsc.h>
+#include <asm/pdc.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/led.h>
+#include <asm/led.h>
+#include <asm/uaccess.h>
+
+
+#ifdef DEBUG
+# define DPRINTK(x) printk x
+#else
+# define DPRINTK(x) do { } while (0)
+#endif
+
+
+/* filename in /proc which can be used to enable/disable the power switch */
+#define SYSCTL_FILENAME		"sys/kernel/power"
+
+
+#define DIAG_CODE(code)		(0x14000000 + ((code)<<5))
+
+/* this will go to processor.h or any other place... */
+/* taken from PCXL ERS page 82 */
+#define MFCPU_X(rDiagReg, t_ch, t_th, code) \
+	(DIAG_CODE(code) + ((rDiagReg)<<21) + ((t_ch)<<16) + ((t_th)<<0) )
+	
+#define MTCPU(dr, gr)		MFCPU_X(dr, gr,  0, 0x12)       /* move value of gr to dr[dr] */
+#define MFCPU_C(dr, gr)		MFCPU_X(dr, gr,  0, 0x30)	/* for dr0 and dr8 only ! */
+#define MFCPU_T(dr, gr)		MFCPU_X(dr,  0, gr, 0xa0)	/* all dr except dr0 and dr8 */
+	
+#define __getDIAG(dr) ( { 			\
+        register unsigned long __res asm("r28");\
+	 __asm__ __volatile__ (			\
+		".word %1\n nop\n" : "=&r" (__res) : "i" (MFCPU_T(dr,28)) \
+	);					\
+	__res;					\
+} )
+
+
+static void deferred_poweroff(void *dummy)
+{
+	extern int cad_pid;	/* from kernel/sys.c */
+	if (kill_proc(cad_pid, SIGINT, 1)) {
+		/* just in case killing init process failed */
+		machine_power_off();
+	}
+}
+
+/*
+ * This function gets called from interrupt context.
+ * As it's called within an interrupt, it wouldn't sync if we don't
+ * use schedule_task().
+ */
+
+static void poweroff(void)
+{
+	static int powering_off;
+	static struct tq_struct poweroff_tq = {
+		routine: deferred_poweroff,
+	};
+
+	if (powering_off)
+		return;
+
+	powering_off++;
+	schedule_task(&poweroff_tq);
+}
+
+
+/* local time-counter for shutdown */
+static int shutdown_timer;
+
+/* check, give feedback and start shutdown after one second */
+static void process_shutdown(void)
+{
+	if (shutdown_timer == 0)
+		DPRINTK((KERN_INFO "Shutdown requested...\n"));
+
+	shutdown_timer++;
+	
+	/* wait until the button was pressed for 1 second */
+	if (shutdown_timer == HZ) {
+		static char msg[] = "Shutting down...";
+		DPRINTK((KERN_INFO "%s\n", msg));
+#ifdef CONFIG_CHASSIS_LCD_LED
+		lcd_print(msg);
+#endif
+		poweroff();
+	}
+}
+
+
+/* main power switch tasklet struct (scheduled from time.c) */
+DECLARE_TASKLET_DISABLED(power_tasklet, NULL, 0);
+
+/* soft power switch enabled/disabled */
+#ifdef CONFIG_PROC_FS
+static int pwrsw_enabled = 1;
+#else
+#define pwrsw_enabled (1)
+#endif
+
+/*
+ * On gecko style machines (e.g. 712/xx and 715/xx) 
+ * the power switch status is stored in Bit 0 ("the highest bit")
+ * of CPU diagnose register 25.
+ * 
+ */
+static void gecko_tasklet_func(unsigned long unused)
+{
+	if (!pwrsw_enabled)
+		return;
+
+	if (__getDIAG(25) & 0x80000000) {
+		/* power switch button not pressed or released again */
+		/* Warning: Some machines do never reset this DIAG flag! */
+		shutdown_timer = 0;
+	} else {
+		process_shutdown();
+	}
+}
+
+
+
+/*
+ * Check the power switch status which is read from the
+ * real I/O location at soft_power_reg.
+ * Bit 31 ("the lowest bit) is the status of the power switch.
+ */
+
+static void polling_tasklet_func(unsigned long soft_power_reg)
+{
+        unsigned long current_status;
+	
+	if (!pwrsw_enabled)
+		return;
+
+	current_status = gsc_readl(soft_power_reg);
+	if (current_status & 0x1) {
+		/* power switch button not pressed */
+		shutdown_timer = 0;
+	} else {
+		process_shutdown();
+	}
+}
+
+
+/*
+ * powerfail interruption handler (irq IRQ_FROM_REGION(CPU_IRQ_REGION)+2) 
+ */
+#if 0
+static void powerfail_interrupt(int code, void *x, struct pt_regs *regs)
+{
+	printk(KERN_CRIT "POWERFAIL INTERRUPTION !\n");
+	poweroff();
+}
+#endif
+
+
+
+
+/* 
+ * /proc filesystem support 
+ */
+
+#ifdef CONFIG_SYSCTL
+static int power_proc_read(char *page, char **start, off_t off, int count, 
+	int *eof, void *data)
+{
+	char *out = page;
+	int len;
+
+	out += sprintf(out, "Software power switch support: ");
+	out += sprintf(out, pwrsw_enabled ? "enabled (1)" : "disabled (0)" );
+	out += sprintf(out, "\n");
+
+	len = out - page - off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0) return 0;
+	} else {
+		len = count;
+	}
+	*start = page + off;
+	return len;
+}
+
+static int power_proc_write(struct file *file, const char *buf, 
+	unsigned long count, void *data)
+{
+	char *cur, lbuf[count];
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	memset(lbuf, 0, count);
+
+	copy_from_user(lbuf, buf, count);
+	cur = lbuf;
+
+	/* skip initial spaces */
+	while (*cur && isspace(*cur))
+		cur++;
+
+	switch (*cur) {
+	case '0':	pwrsw_enabled = 0;
+			break;
+	case '1':	pwrsw_enabled = 1;
+			break;
+	default:	printk(KERN_CRIT "/proc/" SYSCTL_FILENAME 
+					": Parse error: only '0' or '1' allowed!\n");
+			return -EINVAL;
+	} /* switch() */
+
+	return count;
+}
+
+static struct proc_dir_entry *ent;
+
+static void __init power_create_procfs(void)
+{
+	if (!power_tasklet.func)
+		return;
+	
+	ent = create_proc_entry(SYSCTL_FILENAME, S_IFREG|S_IRUGO|S_IWUSR, 0);
+	if (!ent) return;
+	
+	ent->nlink = 1;
+	ent->read_proc = power_proc_read;
+	ent->write_proc = power_proc_write;
+	ent->owner = THIS_MODULE;
+}
+
+static void __exit power_remove_procfs(void)
+{
+	remove_proc_entry(SYSCTL_FILENAME, NULL);
+}
+
+#else
+#define power_create_procfs()	do { } while (0)
+#define power_remove_procfs()	do { } while (0)
+#endif	/* CONFIG_SYSCTL */
+
+
+
+/* parisc_panic_event() is called by the panic handler.
+ * As soon as a panic occurs, our tasklets above will not be
+ * executed any longer. This function then re-enables the 
+ * soft-power switch and allows the user to switch off the system
+ */
+static int parisc_panic_event(struct notifier_block *this,
+		unsigned long event, void *ptr)
+{
+	/* re-enable the soft-power switch */
+	pdc_soft_power_button(0);
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block parisc_panic_block = {
+	notifier_call: parisc_panic_event,
+	priority: INT_MAX,
+};
+
+
+static int __init power_init(void)
+{
+	unsigned long ret;
+	unsigned long soft_power_reg = 0;
+
+#if 0
+	request_irq( IRQ_FROM_REGION(CPU_IRQ_REGION)+2, &powerfail_interrupt,
+		0, "powerfail", NULL);
+#endif
+
+	/* enable the soft power switch if possible */
+	ret = pdc_soft_power_info(&soft_power_reg);
+	if (ret == PDC_OK)
+		ret = pdc_soft_power_button(1);
+	if (ret != PDC_OK)
+		soft_power_reg = -1UL;
+	
+	switch (soft_power_reg) {
+	case 0:		printk(KERN_INFO "Gecko-style soft power switch enabled.\n");
+			power_tasklet.func = gecko_tasklet_func;
+			break;
+			
+	case -1UL:	printk(KERN_INFO "Soft power switch support not available.\n");
+			return -ENODEV;
+	
+	default:	printk(KERN_INFO "Soft power switch enabled, polling @ 0x%08lx.\n",
+				soft_power_reg);
+			power_tasklet.data = soft_power_reg;
+			power_tasklet.func = polling_tasklet_func;
+	}
+
+	/* Register a call for panic conditions. */
+	notifier_chain_register(&panic_notifier_list, &parisc_panic_block);
+
+	power_create_procfs();
+	tasklet_enable(&power_tasklet);
+
+	return 0;
+}
+
+static void __exit power_exit(void)
+{
+	if (!power_tasklet.func)
+		return;
+
+	tasklet_disable(&power_tasklet);
+	notifier_chain_unregister(&panic_notifier_list, &parisc_panic_block);
+	power_remove_procfs();
+	power_tasklet.func = NULL;
+	pdc_soft_power_button(0);
+}
+
+module_init(power_init);
+module_exit(power_exit);
+
+
+MODULE_AUTHOR("Helge Deller");
+MODULE_DESCRIPTION("Soft power switch driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+
+EXPORT_NO_SYMBOLS;
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/process.c linux-2.4.20/arch/parisc/kernel/process.c
--- linux-2.4.19/arch/parisc/kernel/process.c	2001-02-09 19:29:44.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/process.c	2002-10-29 11:18:51.000000000 +0000
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/version.h>
 #include <linux/elf.h>
+#include <linux/personality.h>
 
 #include <asm/machdep.h>
 #include <asm/offset.h>
@@ -36,19 +37,12 @@
 #include <asm/gsc.h>
 #include <asm/processor.h>
 
-spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED;
+int hlt_counter;
 
-#ifdef __LP64__
-/* The 64-bit code should work equally well in 32-bit land but I didn't
- * want to take the time to confirm that.  -PB
- */
-extern unsigned int ret_from_kernel_thread;
-#else
-asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread");
-#endif
-
-
-int hlt_counter=0;
+/*
+ * Power off function, if any
+ */ 
+void (*pm_power_off)(void);
 
 void disable_hlt(void)
 {
@@ -81,35 +75,86 @@
 	}
 }
 
-void __init reboot_setup(char *str, int *ints)
-{
-}
 
-struct notifier_block *mach_notifier;
+#ifdef __LP64__
+#define COMMAND_GLOBAL  0xfffffffffffe0030UL
+#else
+#define COMMAND_GLOBAL  0xfffe0030
+#endif
+
+#define CMD_RESET       5       /* reset any module */
 
-void machine_restart(char *ptr)
+/*
+** The Wright Brothers and Gecko systems have a H/W problem
+** (Lasi...'nuf said) may cause a broadcast reset to lockup
+** the system. An HVERSION dependent PDC call was developed
+** to perform a "safe", platform specific broadcast reset instead
+** of kludging up all the code.
+**
+** Older machines which do not implement PDC_BROADCAST_RESET will
+** return (with an error) and the regular broadcast reset can be
+** issued. Obviously, if the PDC does implement PDC_BROADCAST_RESET
+** the PDC call will not return (the system will be reset).
+*/
+void machine_restart(char *cmd)
 {
-	notifier_call_chain(&mach_notifier, MACH_RESTART, ptr);
+#ifdef FASTBOOT_SELFTEST_SUPPORT
+	/*
+	 ** If user has modified the Firmware Selftest Bitmap,
+	 ** run the tests specified in the bitmap after the
+	 ** system is rebooted w/PDC_DO_RESET.
+	 **
+	 ** ftc_bitmap = 0x1AUL "Skip destructive memory tests"
+	 **
+	 ** Using "directed resets" at each processor with the MEM_TOC
+	 ** vector cleared will also avoid running destructive
+	 ** memory self tests. (Not implemented yet)
+	 */
+	if (ftc_bitmap) {
+		pdc_do_firm_test_reset(ftc_bitmap);
+	}
+#endif
+
+	/* "Normal" system reset */
+	pdc_do_reset();
+
+	/* Nope...box should reset with just CMD_RESET now */
+	gsc_writel(CMD_RESET, COMMAND_GLOBAL);
+
+	/* Wait for RESET to lay us to rest. */
+	while (1) ;
+
 }
 
 void machine_halt(void)
 {
-	notifier_call_chain(&mach_notifier, MACH_HALT, NULL);
+	/*
+	** The LED/ChassisCodes are updated by the led_halt()
+	** function, called by the reboot notifier chain.
+	*/
 }
 
-void machine_power_on(void)
-{
-	notifier_call_chain(&mach_notifier, MACH_POWER_ON, NULL);
-}
 
+/*
+ * This routine is called from sys_reboot to actually turn off the
+ * machine 
+ */
 void machine_power_off(void)
 {
-	notifier_call_chain(&mach_notifier, MACH_POWER_OFF, NULL);
-}
+	/* If there is a registered power off handler, call it. */
+	if(pm_power_off)
+		pm_power_off();
+
+	/* Put the soft power button back under hardware control.
+	 * If the user had already pressed the power button, the
+	 * following call will immediately power off. */
+	pdc_soft_power_button(0);
 
+	/* It seems we have no way to power the system off via
+	 * software. The user has to press the button himself. */
 
-void machine_heartbeat(void)
-{
+	printk(KERN_EMERG "System shut down completed.\n"
+	       KERN_EMERG "Please power this system off now.");
 }
 
 
@@ -138,6 +183,9 @@
 
 void flush_thread(void)
 {
+	/* Only needs to handle fpu stuff or perf monitors.
+	** REVISIT: several arches implement a "lazy fpu state".
+	*/
 	set_fs(USER_DS);
 }
 
@@ -148,6 +196,7 @@
 /*
  * Fill in the FPU structure for a core dump.
  */
+
 int dump_fpu (struct pt_regs * regs, elf_fpregset_t *r)
 {
 	memcpy(r, regs->fr, sizeof *r);
@@ -176,7 +225,13 @@
 	    struct task_struct * p, struct pt_regs * pregs)
 {
 	struct pt_regs * cregs = &(p->thread.regs);
-	long ksp;
+	
+	/* We have to use void * instead of a function pointer, because
+	 * function pointers aren't a pointer to the function on 64-bit.
+	 * Make them const so the compiler knows they live in .text */
+	extern void * const ret_from_kernel_thread;
+	extern void * const child_return;
+	extern void * const hpux_child_return;
 
 	*cregs = *pregs;
 
@@ -193,34 +248,37 @@
 	 * in zero for usp.
 	 */
 	if (usp == 0) {
-		/* Kernel Thread */
-		ksp = (((unsigned long)(p)) + TASK_SZ_ALGN);
-		cregs->ksp = ksp;	    /* always return to kernel */
-#ifdef __LP64__
+		/* kernel thread */
+		cregs->ksp = (((unsigned long)(p)) + TASK_SZ_ALGN);
+		/* Must exit via ret_from_kernel_thread in order
+		 * to call schedule_tail()
+		 */
 		cregs->kpc = (unsigned long) &ret_from_kernel_thread;
-#else
-		cregs->kpc = (unsigned long) ret_from_kernel_thread;
-#endif
-
 		/*
 		 * Copy function and argument to be called from
 		 * ret_from_kernel_thread.
 		 */
+#ifdef __LP64__
+		cregs->gr[27] = pregs->gr[27];
+#endif
 		cregs->gr[26] = pregs->gr[26];
 		cregs->gr[25] = pregs->gr[25];
-
 	} else {
-		/* User Thread:
-		 *
-		 * Use same stack depth as parent when in wrapper
-		 *
+		/* user thread */
+		/*
 		 * Note that the fork wrappers are responsible
-		 * for setting gr[20] and gr[21].
+		 * for setting gr[21].
 		 */
 
+		/* Use same stack depth as parent */
 		cregs->ksp = ((unsigned long)(p))
-			+ (pregs->gr[20] & (INIT_TASK_SIZE - 1));
-		cregs->kpc = pregs->gr[21];
+			+ (pregs->gr[21] & (INIT_TASK_SIZE - 1));
+		cregs->gr[30] = usp;
+		if (p->personality == PER_HPUX) {
+			cregs->kpc = (unsigned long) &hpux_child_return;
+		} else {
+			cregs->kpc = (unsigned long) &child_return;
+		}
 	}
 
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/processor.c linux-2.4.20/arch/parisc/kernel/processor.c
--- linux-2.4.19/arch/parisc/kernel/processor.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/processor.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,374 @@
+/*    $Id: processor.c,v 1.13 2002/07/04 19:33:01 grundler Exp $
+ *
+ *    Initial setup-routines for HP 9000 based hardware.
+ *
+ *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *    Modifications for PA-RISC (C) 1999 Helge Deller <deller@gmx.de>
+ *    Modifications copyright 1999 SuSE GmbH (Philipp Rumpf)
+ *    Modifications copyright 2000 Martin K. Petersen <mkp@mkp.net>
+ *    Modifications copyright 2000 Philipp Rumpf <prumpf@tux.org>
+ *    Modifications copyright 2001 Ryan Bradetich <rbradetich@uswest.net>
+ *
+ *    Initial PA-RISC Version: 04-23-1999 by Helge Deller
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#define PCI_DEBUG
+#include <linux/pci.h>
+#undef PCI_DEBUG
+
+#include <asm/cache.h>
+#include <asm/hardware.h>	/* for register_parisc_driver() stuff */
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/pdc.h>
+#include <asm/irq.h>		/* for struct irq_region */
+
+struct system_cpuinfo_parisc boot_cpu_data;
+struct cpuinfo_parisc cpu_data[NR_CPUS];
+
+/*
+**  	PARISC CPU driver - claim "device" and initialize CPU data structures.
+**
+** Consolidate per CPU initialization into (mostly) one module.
+** Monarch CPU will initialize boot_cpu_data which shouldn't
+** change once the system has booted.
+**
+** The callback *should* do per-instance initialization of
+** everything including the monarch. "Per CPU" init code in
+** setup.c:start_parisc() has migrated here and start_parisc()
+** will call register_parisc_driver(&cpu_driver) before calling do_inventory().
+**
+** The goal of consolidating CPU initialization into one place is
+** to make sure all CPU's get initialized the same way.
+** The code path not shared is how PDC hands control of the CPU to the OS.
+** The initialization of OS data structures is the same (done below).
+*/
+
+/**
+ * processor_probe - Determine if processor driver should claim this device.
+ * @dev: The device which has been found.
+ *
+ * Determine if processor driver should claim this chip (return 0) or not 
+ * (return 1).  If so, initialize the chip and tell other partners in crime 
+ * they have work to do.
+ */
+static int __init processor_probe(struct parisc_device *dev)
+{
+	unsigned long txn_addr;
+	unsigned long cpuid;
+	struct cpuinfo_parisc *p;
+
+#ifndef CONFIG_SMP
+	if (boot_cpu_data.cpu_count > 0) {
+		printk(KERN_INFO "CONFIG_SMP=n  ignoring additional CPUs\n");
+		return 1;
+	}
+#endif
+
+	/* logical CPU ID and update global counter
+	 * May get overwritten by PAT code.
+	 */
+	cpuid = boot_cpu_data.cpu_count;
+	txn_addr = dev->hpa;	/* for legacy PDC */
+
+#ifdef __LP64__
+	if (is_pdc_pat()) {
+		ulong status;
+		unsigned long bytecnt;
+	        pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;
+#undef USE_PAT_CPUID
+#ifdef USE_PAT_CPUID
+		struct pdc_pat_cpu_num cpu_info;
+#endif
+
+		status = pdc_pat_cell_module(&bytecnt, dev->pcell_loc,
+			dev->mod_index, PA_VIEW, &pa_pdc_cell);
+
+		ASSERT(PDC_OK == status);
+
+		/* verify it's the same as what do_pat_inventory() found */
+		ASSERT(dev->mod_info == pa_pdc_cell.mod_info);
+		ASSERT(dev->pmod_loc == pa_pdc_cell.mod_location);
+
+		txn_addr = pa_pdc_cell.mod[0];   /* id_eid for IO sapic */
+
+#ifdef USE_PAT_CPUID
+/* We need contiguous numbers for cpuid. Firmware's notion
+ * of cpuid is for physical CPUs and we just don't care yet.
+ * We'll care when we need to query PAT PDC about a CPU *after*
+ * boot time (ie shutdown a CPU from an OS perspective).
+ */
+		/* get the cpu number */
+		status = pdc_pat_cpu_get_number(&cpu_info, dev->hpa);
+
+		ASSERT(PDC_OK == status);
+
+		if (cpu_info.cpu_num >= NR_CPUS) {
+			printk(KERN_WARNING "IGNORING CPU at 0x%x,"
+				" cpu_slot_id > NR_CPUS"
+				" (%ld > %d)\n",
+				dev->hpa, cpu_info.cpu_num, NR_CPUS);
+			/* Ignore CPU since it will only crash */
+			boot_cpu_data.cpu_count--;
+			return 1;
+		} else {
+			cpuid = cpu_info.cpu_num;
+		}
+#endif
+	}
+#endif
+
+	p = &cpu_data[cpuid];
+	boot_cpu_data.cpu_count++;
+
+	/* initialize counters */
+	memset(p, 0, sizeof(struct cpuinfo_parisc));
+
+	p->dev = dev;		/* Save IODC data in case we need it */
+	p->hpa = dev->hpa;	/* save CPU hpa */
+	p->cpuid = cpuid;	/* save CPU id */
+	p->txn_addr = txn_addr;	/* save CPU IRQ address */
+#ifdef CONFIG_SMP
+	p->lock = SPIN_LOCK_UNLOCKED;
+
+	/*
+	** FIXME: review if any other initialization is clobbered
+	**	for boot_cpu by the above memset().
+	*/
+
+	/* stolen from init_percpu_prof() */
+	cpu_data[cpuid].prof_counter = 1;
+	cpu_data[cpuid].prof_multiplier = 1;
+#endif
+
+	/*
+	** CONFIG_SMP: init_smp_config() will attempt to get CPU's into
+	** OS control. RENDEZVOUS is the default state - see mem_set above.
+	**	p->state = STATE_RENDEZVOUS;
+	*/
+
+	/*
+	** itimer and ipi IRQ handlers are statically initialized in
+	** arch/parisc/kernel/irq.c. ie Don't need to register them.
+	*/
+	p->region = irq_region[IRQ_FROM_REGION(CPU_IRQ_REGION)];
+
+	return 0;
+}
+
+/**
+ * collect_boot_cpu_data - Fill the boot_cpu_data structure.
+ *
+ * This function collects and stores the generic processor information
+ * in the boot_cpu_data structure.
+ */
+void __init collect_boot_cpu_data(void)
+{
+	memset(&boot_cpu_data, 0, sizeof(boot_cpu_data));
+
+	boot_cpu_data.cpu_hz = 100 * PAGE0->mem_10msec; /* Hz of this PARISC */
+
+	/* get CPU-Model Information... */
+#define p ((unsigned long *)&boot_cpu_data.pdc.model)
+	if (pdc_model_info(&boot_cpu_data.pdc.model) == PDC_OK)
+		printk(KERN_INFO 
+			"model %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+			p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]);
+#undef p
+
+	if (pdc_model_versions(&boot_cpu_data.pdc.versions, 0) == PDC_OK)
+		printk(KERN_INFO "vers  %08lx\n", 
+			boot_cpu_data.pdc.versions);
+
+	if (pdc_model_cpuid(&boot_cpu_data.pdc.cpuid) == PDC_OK)
+		printk(KERN_INFO "CPUID vers %ld rev %ld (0x%08lx)\n",
+			(boot_cpu_data.pdc.cpuid >> 5) & 127,
+			boot_cpu_data.pdc.cpuid & 31,
+			boot_cpu_data.pdc.cpuid);
+
+	if (pdc_model_capabilities(&boot_cpu_data.pdc.capabilities) == PDC_OK)
+		printk(KERN_INFO "capabilities 0x%lx\n",
+			boot_cpu_data.pdc.capabilities);
+
+	if (pdc_model_sysmodel(boot_cpu_data.pdc.sys_model_name) == PDC_OK)
+		printk(KERN_INFO "model %s\n",
+			boot_cpu_data.pdc.sys_model_name);
+
+	boot_cpu_data.hversion =  boot_cpu_data.pdc.model.hversion;
+	boot_cpu_data.sversion =  boot_cpu_data.pdc.model.sversion;
+
+	boot_cpu_data.cpu_type =
+			parisc_get_cpu_type(boot_cpu_data.hversion);
+
+	boot_cpu_data.cpu_name = cpu_name_version[boot_cpu_data.cpu_type][0];
+	boot_cpu_data.family_name = cpu_name_version[boot_cpu_data.cpu_type][1];
+}
+
+
+/**
+ * init_cpu_profiler - enable/setup per cpu profiling hooks.
+ * @cpunum: The processor instance.
+ *
+ * FIXME: doesn't do much yet...
+ */
+static inline void __init
+init_percpu_prof(int cpunum)
+{
+	cpu_data[cpunum].prof_counter = 1;
+	cpu_data[cpunum].prof_multiplier = 1;
+}
+
+
+/**
+ * init_per_cpu - Handle individual processor initializations.
+ * @cpunum: logical processor number.
+ *
+ * This function handles initialization for *every* CPU
+ * in the system:
+ *
+ * o Set "default" CPU width for trap handlers
+ *
+ * o Enable FP coprocessor
+ *   REVISIT: this could be done in the "code 22" trap handler.
+ *	(frowands idea - that way we know which processes need FP
+ *	registers saved on the interrupt stack.)
+ *   NEWS FLASH: wide kernels need FP coprocessor enabled to handle
+ *	formatted printing of %lx for example (double divides I think)
+ *
+ * o Enable CPU profiling hooks.
+ */
+int __init init_per_cpu(int cpunum)
+{
+	int ret;
+	struct pdc_coproc_cfg coproc_cfg;
+
+	ret = pdc_coproc_cfg(&coproc_cfg);
+
+	if(ret >= 0 && coproc_cfg.ccr_functional) {
+		mtctl(coproc_cfg.ccr_functional, 10);  /* 10 == Coprocessor Control Reg */
+
+		/* FWIW, FP rev/model is a more accurate way to determine
+		** CPU type. CPU rev/model has some ambiguous cases.
+		*/
+		cpu_data[cpunum].fp_rev = coproc_cfg.revision;
+		cpu_data[cpunum].fp_model = coproc_cfg.model;
+
+		printk(KERN_INFO  "FP[%d] enabled: Rev %ld Model %ld\n",
+			cpunum, coproc_cfg.revision, coproc_cfg.model);
+
+		/*
+		** store status register to stack (hopefully aligned)
+		** and clear the T-bit.
+		*/
+		asm volatile ("fstd    %fr0,8(%sp)");
+
+	} else {
+		printk(KERN_WARNING  "WARNING: No FP CoProcessor?!"
+			" (coproc_cfg.ccr_functional == 0x%lx, expected 0xc0)\n"
+#ifdef __LP64__
+			"Halting Machine - FP required\n"
+#endif
+			, coproc_cfg.ccr_functional);
+#ifdef __LP64__
+		mdelay(100);	/* previous chars get pushed to console */
+		panic("FP CoProc not reported");
+#endif
+	}
+
+	/* FUTURE: Enable Performance Monitor : ccr bit 0x20 */
+	init_percpu_prof(cpunum);
+
+	return ret;
+}
+
+/*
+ * Display cpu info for all cpu's.
+ */
+int
+show_cpuinfo (struct seq_file *m, void *v)
+{
+	int	n;
+
+	for(n=0; n<boot_cpu_data.cpu_count; n++) {
+#ifdef CONFIG_SMP
+		if (0 == cpu_data[n].hpa)
+			continue;
+#ifdef ENTRY_SYS_CPUS
+#error iCOD support wants to show CPU state here
+#endif
+#endif
+		seq_printf(m, "processor\t: %d\n"
+				"cpu family\t: PA-RISC %s\n",
+				 n, boot_cpu_data.family_name);
+
+		seq_printf(m, "cpu\t\t: %s\n",  boot_cpu_data.cpu_name );
+
+		/* cpu MHz */
+		seq_printf(m, "cpu MHz\t\t: %d.%06d\n",
+				 boot_cpu_data.cpu_hz / 1000000,
+				 boot_cpu_data.cpu_hz % 1000000  );
+
+		seq_printf(m, "model\t\t: %s\n"
+				"model name\t: %s\n",
+				 boot_cpu_data.pdc.sys_model_name,
+				 cpu_data[n].dev ? 
+				 cpu_data[n].dev->name : "Unknown" );
+
+		seq_printf(m, "hversion\t: 0x%08x\n"
+			        "sversion\t: 0x%08x\n",
+				 boot_cpu_data.hversion,
+				 boot_cpu_data.sversion );
+
+		/* print cachesize info */
+		show_cache_info(m);
+
+		seq_printf(m, "bogomips\t: %lu.%02lu\n",
+			     loops_per_jiffy / (500000 / HZ),
+			     (loops_per_jiffy / (5000 / HZ)) % 100);
+
+		seq_printf(m, "software id\t: %ld\n\n",
+				boot_cpu_data.pdc.model.sw_id);
+	}
+	return 0;
+}
+
+static struct parisc_device_id processor_tbl[] = {
+	{ HPHW_NPROC, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, SVERSION_ANY_ID },
+	{ 0, }
+};
+
+static struct parisc_driver cpu_driver = {
+	name:		"CPU",
+	id_table:	processor_tbl,
+	probe:		processor_probe
+};
+
+/**
+ * processor_init - Processor initalization procedure.
+ *
+ * Register this driver.
+ */
+void __init processor_init(void)
+{
+	register_parisc_driver(&cpu_driver);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/ptrace.c linux-2.4.20/arch/parisc/kernel/ptrace.c
--- linux-2.4.19/arch/parisc/kernel/ptrace.c	2001-09-18 23:56:19.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/ptrace.c	2002-10-29 11:18:33.000000000 +0000
@@ -14,6 +14,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/personality.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -31,6 +32,47 @@
 #define PT_SINGLESTEP	0x10000
 #define PT_BLOCKSTEP	0x20000
 
+/* PSW bits we allow the debugger to modify */
+#define USER_PSW_BITS	(PSW_N | PSW_V | PSW_CB)
+
+#undef DEBUG_PTRACE
+
+#ifdef DEBUG_PTRACE
+#define DBG(x)	printk x
+#else
+#define DBG(x)
+#endif
+
+#ifdef __LP64__
+
+#define CHILD_IS_32BIT	(child->personality == PER_LINUX_32BIT)
+
+/* This function is needed to translate 32 bit pt_regs offsets in to
+ * 64 bit pt_regs offsets.  For example, a 32 bit gdb under a 64 bit kernel
+ * will request offset 12 if it wants gr3, but the lower 32 bits of
+ * the 64 bit kernels view of gr3 will be at offset 28 (3*8 + 4).
+ * This code relies on a 32 bit pt_regs being comprised of 32 bit values
+ * except for the fp registers which (a) are 64 bits, and (b) follow
+ * the gr registers at the start of pt_regs.  The 32 bit pt_regs should
+ * be half the size of the 64 bit pt_regs, plus 32*4 to allow for fr[]
+ * being 64 bit in both cases.
+ */
+
+static long translate_usr_offset(long offset)
+{
+	if (offset < 0)
+		return -1;
+	else if (offset <= 32*4)	/* gr[0..31] */
+		return offset * 2 + 4;
+	else if (offset <= 32*4+32*8)	/* gr[0..31] + fr[0..31] */
+		return offset + 32*4;
+	else if (offset < sizeof(struct pt_regs)/2 + 32*4)
+		return offset * 2 + 4 - 32*8;
+	else
+		return -1;
+}
+#endif
+
 /*
  * Called by kernel/ptrace.c when detaching..
  *
@@ -49,6 +91,9 @@
 {
 	struct task_struct *child;
 	long ret;
+#ifdef DEBUG_PTRACE
+	long oaddr=addr, odata=data;
+#endif
 
 	lock_kernel();
 	ret = -EPERM;
@@ -91,14 +136,33 @@
 	switch (request) {
 	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 	case PTRACE_PEEKDATA: {
-		unsigned long tmp;
 		int copied;
 
-		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
-		ret = -EIO;
-		if (copied != sizeof(tmp))
-			goto out_tsk;
-		ret = put_user(tmp,(unsigned long *) data);
+#ifdef __LP64__
+		if (CHILD_IS_32BIT) {
+			unsigned int tmp;
+
+			addr &= 0xffffffffL;
+			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+			ret = -EIO;
+			if (copied != sizeof(tmp))
+				goto out_tsk;
+			ret = put_user(tmp,(unsigned int *) data);
+			DBG(("sys_ptrace(PEEK%s, %d, %lx, %lx) returning %ld, data %x\n",
+				request == PTRACE_PEEKTEXT ? "TEXT" : "DATA",
+				pid, oaddr, odata, ret, tmp));
+		}
+		else
+#endif
+		{
+			unsigned long tmp;
+
+			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+			ret = -EIO;
+			if (copied != sizeof(tmp))
+				goto out_tsk;
+			ret = put_user(tmp,(unsigned long *) data);
+		}
 		goto out_tsk;
 	}
 
@@ -106,22 +170,53 @@
 	case PTRACE_POKETEXT: /* write the word at location addr. */
 	case PTRACE_POKEDATA:
 		ret = 0;
-		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
-			goto out_tsk;
+#ifdef __LP64__
+		if (CHILD_IS_32BIT) {
+			unsigned int tmp = (unsigned int)data;
+			DBG(("sys_ptrace(POKE%s, %d, %lx, %lx)\n",
+				request == PTRACE_POKETEXT ? "TEXT" : "DATA",
+				pid, oaddr, odata));
+			addr &= 0xffffffffL;
+			if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1) == sizeof(tmp))
+				goto out_tsk;
+		}
+		else
+#endif
+		{
+			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+				goto out_tsk;
+		}
 		ret = -EIO;
 		goto out_tsk;
 
-	/* Read the word at location addr in the USER area.  This will need
-	   to change when the kernel no longer saves all regs on a syscall. */
+	/* Read the word at location addr in the USER area.  For ptraced
+	   processes, the kernel saves all regs on a syscall. */
 	case PTRACE_PEEKUSR: {
-		unsigned long tmp;
-
 		ret = -EIO;
-		if ((addr & 3) || (unsigned long) addr >= sizeof(struct pt_regs))
-			goto out_tsk;
-
-		tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
-		ret = put_user(tmp, (unsigned long *) data);
+#ifdef __LP64__
+		if (CHILD_IS_32BIT) {
+			unsigned int tmp;
+
+			if (addr & (sizeof(int)-1))
+				goto out_tsk;
+			if ((addr = translate_usr_offset(addr)) < 0)
+				goto out_tsk;
+
+			tmp = *(unsigned int *) ((char *) task_regs(child) + addr);
+			ret = put_user(tmp, (unsigned int *) data);
+			DBG(("sys_ptrace(PEEKUSR, %d, %lx, %lx) returning %ld, addr %lx, data %x\n",
+				pid, oaddr, odata, ret, addr, tmp));
+		}
+		else
+#endif
+		{
+			unsigned long tmp;
+
+			if ((addr & (sizeof(long)-1)) || (unsigned long) addr >= sizeof(struct pt_regs))
+				goto out_tsk;
+			tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
+			ret = put_user(tmp, (unsigned long *) data);
+		}
 		goto out_tsk;
 	}
 
@@ -133,25 +228,73 @@
 	   exit. */
 	case PTRACE_POKEUSR:
 		ret = -EIO;
-		if ((addr & 3) || (unsigned long) addr >= sizeof(struct pt_regs))
-			goto out_tsk;
-		/* XXX This test probably needs adjusting.  We probably want to
-		 * allow writes to some bits of PSW, and may want to block writes
-		 * to (some) space registers.  Some register values written here
-		 * may be ignored in entry.S:syscall_restore_rfi; e.g. iaoq is
-		 * written with r31/r31+4, and not with the values in pt_regs.
+		/* Some register values written here may be ignored in
+		 * entry.S:syscall_restore_rfi; e.g. iaoq is written with
+		 * r31/r31+4, and not with the values in pt_regs.
+		 */
+		 /* PT_PSW=0, so this is valid for 32 bit processes under 64
+		 * bit kernels.
 		 */
-		/* Allow writing of gr1-gr31, fr*, sr*, iasq*, iaoq*, sar */
-		if (addr == PT_PSW || (addr > PT_IAOQ1 && addr != PT_SAR))
+		if (addr == PT_PSW) {
+			/* PT_PSW=0, so this is valid for 32 bit processes
+			 * under 64 bit kernels.
+			 *
+			 * Allow writing to Nullify, Divide-step-correction,
+			 * and carry/borrow bits.
+			 * BEWARE, if you set N, and then single step, it wont
+			 * stop on the nullified instruction.
+			 */
+			DBG(("sys_ptrace(POKEUSR, %d, %lx, %lx)\n",
+				pid, oaddr, odata));
+			data &= USER_PSW_BITS;
+			task_regs(child)->gr[0] &= ~USER_PSW_BITS;
+			task_regs(child)->gr[0] |= data;
+			ret = 0;
 			goto out_tsk;
-
-		*(unsigned long *) ((char *) task_regs(child) + addr) = data;
-		ret = 0;
-		goto out_tsk;
+		}
+#ifdef __LP64__
+		if (CHILD_IS_32BIT) {
+			if (addr & (sizeof(int)-1))
+				goto out_tsk;
+			if ((addr = translate_usr_offset(addr)) < 0)
+				goto out_tsk;
+			DBG(("sys_ptrace(POKEUSR, %d, %lx, %lx) addr %lx\n",
+				pid, oaddr, odata, addr));
+			if (addr >= PT_FR0 && addr <= PT_FR31) {
+				/* Special case, fp regs are 64 bits anyway */
+				*(unsigned int *) ((char *) task_regs(child) + addr) = data;
+				ret = 0;
+			}
+			else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) ||
+					addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4 ||
+					addr == PT_SAR+4) {
+				/* Zero the top 32 bits */
+				*(unsigned int *) ((char *) task_regs(child) + addr - 4) = 0;
+				*(unsigned int *) ((char *) task_regs(child) + addr) = data;
+				ret = 0;
+			}
+			goto out_tsk;
+		}
+		else
+#endif
+		{
+			if ((addr & (sizeof(long)-1)) || (unsigned long) addr >= sizeof(struct pt_regs))
+				goto out_tsk;
+			if ((addr >= PT_GR1 && addr <= PT_GR31) ||
+					addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
+					(addr >= PT_FR0 && addr <= PT_FR31) ||
+					addr == PT_SAR) {
+				*(unsigned long *) ((char *) task_regs(child) + addr) = data;
+				ret = 0;
+			}
+			goto out_tsk;
+		}
 
 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 	case PTRACE_CONT:
 		ret = -EIO;
+		DBG(("sys_ptrace(%s)\n",
+			request == PTRACE_SYSCALL ? "SYSCALL" : "CONT"));
 		if ((unsigned long) data > _NSIG)
 			goto out_tsk;
 		child->ptrace &= ~(PT_SINGLESTEP|PT_BLOCKSTEP);
@@ -168,12 +311,14 @@
 		 * sigkill.  perhaps it should be put in the status
 		 * that it wants to exit.
 		 */
+		DBG(("sys_ptrace(KILL)\n"));
 		if (child->state == TASK_ZOMBIE)	/* already dead */
 			goto out_tsk;
 		child->exit_code = SIGKILL;
 		goto out_wake_notrap;
 
 	case PTRACE_SINGLEBLOCK:
+		DBG(("sys_ptrace(SINGLEBLOCK)\n"));
 		ret = -EIO;
 		if ((unsigned long) data > _NSIG)
 			goto out_tsk;
@@ -189,6 +334,7 @@
 		goto out_wake;
 
 	case PTRACE_SINGLESTEP:
+		DBG(("sys_ptrace(SINGLESTEP)\n"));
 		ret = -EIO;
 		if ((unsigned long) data > _NSIG)
 			goto out_tsk;
@@ -208,10 +354,7 @@
 			pa_psw(child)->y = 0;
 			pa_psw(child)->z = 0;
 			pa_psw(child)->b = 0;
-			pa_psw(child)->r = 0;
-			pa_psw(child)->t = 0;
-			pa_psw(child)->h = 0;
-			pa_psw(child)->l = 0;
+			ptrace_disable(child);
 			/* Don't wake up the child, but let the
 			   parent know something happened. */
 			si.si_code = TRAP_TRACE;
@@ -249,11 +392,7 @@
 	}
 
 out_wake_notrap:
-	/* make sure the trap bits are not set */
-	pa_psw(child)->r = 0;
-	pa_psw(child)->t = 0;
-	pa_psw(child)->h = 0;
-	pa_psw(child)->l = 0;
+	ptrace_disable(child);
 out_wake:
 	wake_up_process(child);
 	ret = 0;
@@ -261,6 +400,8 @@
 	free_task_struct(child);
 out:
 	unlock_kernel();
+	DBG(("sys_ptrace(%ld, %d, %lx, %lx) returning %ld\n",
+		request, pid, oaddr, odata, ret));
 	return ret;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/real1.c linux-2.4.20/arch/parisc/kernel/real1.c
--- linux-2.4.19/arch/parisc/kernel/real1.c	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/real1.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,154 +0,0 @@
-/*
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com)
- *
- * most of these calls might reasonably be moved to ../kernel -PB
- *
- * The basic principle is to construct a stack frame in C then call
- * some assembly which adopts that stack, does some rfi magic, may
- * switch wide/narrow mode, and calls the routine described by the
- * 'fn' parameter WHICH IS NOT A FUNCTION POINTER!!!!!!!!!!!!!!!!
- */
-#include <linux/spinlock.h>
-#include <asm/system.h>
-#include <stdarg.h>
-#include <asm/pgtable.h>		/* for __pa() */
-#include <asm/pdc.h>
-
-static spinlock_t pdc_lock = SPIN_LOCK_UNLOCKED;
-
-/***************** 32-bit real-mode calls ***********/
-/* The struct below is used
- * to overlay real_stack (real2.S), preparing a 32-bit call frame.
- * real32_call_asm() then uses this stack in narrow real mode
- */
-
-struct narrow_stack {
-    /* use int, not long which is 64 bits */
-    unsigned int arg13;
-    unsigned int arg12;
-    unsigned int arg11;
-    unsigned int arg10;
-    unsigned int arg9;
-    unsigned int arg8;
-    unsigned int arg7;
-    unsigned int arg6;
-    unsigned int arg5;
-    unsigned int arg4;
-    unsigned int arg3;
-    unsigned int arg2;
-    unsigned int arg1;
-    unsigned int arg0;
-    unsigned int frame_marker[8];
-    unsigned int sp;
-    /* in reality, there's nearly 8k of stack after this */
-};
-
-long
-real32_call(unsigned long fn, ...)
-{
-    unsigned long r;
-    va_list args;
-    unsigned long flags;
-    extern struct narrow_stack real_stack;
-    extern unsigned long real32_call_asm(unsigned int *,
-				unsigned int *, unsigned int);
-    
-    va_start(args, fn);
-    real_stack.arg0 = va_arg(args, unsigned int);
-    real_stack.arg1 = va_arg(args, unsigned int);
-    real_stack.arg2 = va_arg(args, unsigned int);
-    real_stack.arg3 = va_arg(args, unsigned int);
-    real_stack.arg4 = va_arg(args, unsigned int);
-    real_stack.arg5 = va_arg(args, unsigned int);
-    real_stack.arg6 = va_arg(args, unsigned int);
-    real_stack.arg7 = va_arg(args, unsigned int);
-    real_stack.arg8 = va_arg(args, unsigned int);
-    real_stack.arg9 = va_arg(args, unsigned int);
-    real_stack.arg10 = va_arg(args, unsigned int);
-    real_stack.arg11 = va_arg(args, unsigned int);
-    real_stack.arg12 = va_arg(args, unsigned int);
-    real_stack.arg13 = va_arg(args, unsigned int);
-    va_end(args);
-
-    if (fn == 0) {
-	    /* mem_pdc call */
-	    fn = PAGE0->mem_pdc;
-    }
-
-    spin_lock_irqsave(&pdc_lock, flags);
-    r = real32_call_asm(&real_stack.sp, &real_stack.arg0, fn);
-    spin_unlock_irqrestore(&pdc_lock, flags);
-
-    return r;
-}
-
-#ifdef __LP64__
-/***************** 64-bit real-mode calls ***********/
-
-struct wide_stack {
-    unsigned long arg0;
-    unsigned long arg1;
-    unsigned long arg2;
-    unsigned long arg3;
-    unsigned long arg4;
-    unsigned long arg5;
-    unsigned long arg6;
-    unsigned long arg7;
-    unsigned long arg8;
-    unsigned long arg9;
-    unsigned long arg10;
-    unsigned long arg11;
-    unsigned long arg12;
-    unsigned long arg13;
-    unsigned long frame_marker[2];	/* rp, previous sp */
-    unsigned long sp;
-    /* in reality, there's nearly 8k of stack after this */
-};
-
-long
-real64_call(unsigned long fn, ...)
-{
-    unsigned long r;
-    va_list args;
-    unsigned long flags;
-    extern struct wide_stack real_stack;
-    extern unsigned long real64_call_asm(unsigned long *,
-				unsigned long *, unsigned long);
-    
-    va_start(args, fn);
-    real_stack.arg0 = va_arg(args, unsigned long);
-    real_stack.arg1 = va_arg(args, unsigned long);
-    real_stack.arg2 = va_arg(args, unsigned long);
-    real_stack.arg3 = va_arg(args, unsigned long);
-    real_stack.arg4 = va_arg(args, unsigned long);
-    real_stack.arg5 = va_arg(args, unsigned long);
-    real_stack.arg6 = va_arg(args, unsigned long);
-    real_stack.arg7 = va_arg(args, unsigned long);
-    real_stack.arg8 = va_arg(args, unsigned long);
-    real_stack.arg9 = va_arg(args, unsigned long);
-    real_stack.arg10 = va_arg(args, unsigned long);
-    real_stack.arg11 = va_arg(args, unsigned long);
-    real_stack.arg12 = va_arg(args, unsigned long);
-    real_stack.arg13 = va_arg(args, unsigned long);
-    va_end(args);
-
-    if (fn == 0) {
-	    /* mem_pdc call */
-	    fn = PAGE0->mem_pdc_hi;
-	    fn <<= 32;
-	    fn |= PAGE0->mem_pdc;
-    }
-
-    spin_lock_irqsave(&pdc_lock, flags);
-    r = real64_call_asm(&real_stack.sp, &real_stack.arg0, fn);
-    spin_unlock_irqrestore(&pdc_lock, flags);
-
-    return r;
-}
-
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/real2.S linux-2.4.20/arch/parisc/kernel/real2.S
--- linux-2.4.19/arch/parisc/kernel/real2.S	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/real2.S	2002-10-29 11:18:48.000000000 +0000
@@ -7,7 +7,6 @@
  * Copyright (C) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com)
  *
  */
-#define __ASSEMBLY__
 #include <asm/assembly.h>
 #include <asm/psw.h>
 
@@ -31,8 +30,11 @@
 
 /************************ 32-bit real-mode calls ***********************/
 /* This can be called in both narrow and wide kernels */
+
 	.text
+
 	.export real32_call_asm
+
 	/* unsigned long real32_call_asm(unsigned int *sp,
 	 *		unsigned int *arg0p,
 	 *		unsigned int iodc_fn)
@@ -40,6 +42,7 @@
 	 *	arg0p points to where saved arg values may be found
 	 *	iodc_fn is the IODC function to call
 	 */
+
 real32_call_asm:
 	STREG	%rp, -RP_OFFSET(%sp)	/* save RP */
 #ifdef __LP64__
@@ -61,7 +64,7 @@
 	ldw	-12(%arg1), %arg3
 	ldw	-4(%arg1), %arg1	/* obviously must do this one last! */
 
-	tophys	%sp
+	tophys_r1  %sp
 
 	b,l	rfi_virt2real,%r2
 	nop
@@ -88,7 +91,7 @@
 	b,l	rfi_real2virt,%r2
 	nop
 
-	tovirt	%sp
+	tovirt_r1 %sp
 	LDREG	-REG_SZ(%sp), %sp	/* restore SP */
 #ifdef __LP64__
 	LDREG	-1*REG_SZ(%sp), %r27
@@ -150,14 +153,14 @@
 	nop
 	nop
 	
-	mtsm		0		/* disable interruptions */
+	rsm             (PSW_SM_Q|PSW_SM_I),%r0  /* disable Q & I bits to load iia queue */
 	mtctl		0, %cr17	/* space 0 */
 	mtctl		0, %cr17
 	load32		PA(rfi_v2r_1), %r1
 	mtctl		%r1, %cr18
 	ldo		4(%r1), %r1
 	mtctl		%r1, %cr18
-	load32		PDC_PSW, %r1
+	load32          REAL_MODE_PSW, %r1
 	mtctl		%r1, %cr22
 	rfi
 	
@@ -170,7 +173,7 @@
 	nop
 	nop
 rfi_v2r_1:
-	tophys	%r2
+	tophys_r1 %r2
 	bv	0(%r2)
 	nop
 
@@ -187,7 +190,7 @@
 	nop
 	nop
 	
-	mtsm		0		/* disable interruptions */
+	rsm             PSW_SM_Q,%r0    /* disable Q bit to load iia queue */
 	mtctl		0, %cr17	/* space 0 */
 	mtctl		0, %cr17
 	load32		(rfi_r2v_1), %r1
@@ -207,7 +210,7 @@
 	nop
 	nop
 rfi_r2v_1:
-	tovirt	%r2
+	tovirt_r1 %r2
 	bv	0(%r2)
 	nop
 
@@ -246,7 +249,7 @@
 	ldd	7*REG_SZ(%arg1), %r19
 	ldd	1*REG_SZ(%arg1), %arg1		/* do this one last! */
 
-	tophys	%sp
+	tophys_r1 %sp
 
 	b,l	rfi_virt2real,%r2
 	nop
@@ -265,10 +268,18 @@
 	b,l	rfi_real2virt,%r2
 	nop
 
-	tovirt	%sp
+	tovirt_r1 %sp
 	ldd	-8(%sp), %sp		/* restore SP */
 	ldd	-0x10(%sp), %rp		/* restore RP */
 	bv	0(%rp)
 	nop
 
 #endif
+	.export pc_in_user_space
+	.text
+	/* Doesn't belong here but I couldn't find a nicer spot. */
+	/* Should never get called, only used by profile stuff in time.c */
+pc_in_user_space:
+	bv,n	0(%rp)
+	nop
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/sba_iommu.c linux-2.4.20/arch/parisc/kernel/sba_iommu.c
--- linux-2.4.19/arch/parisc/kernel/sba_iommu.c	2001-10-12 22:35:53.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/sba_iommu.c	2002-10-29 11:18:34.000000000 +0000
@@ -15,7 +15,6 @@
 ** This module initializes the IOC (I/O Controller) found on B1000/C3000/
 ** J5000/J7000/N-class/L-class machines and their successors.
 **
-** FIXME: Multi-IOC support missing - depends on hp_device data
 ** FIXME: add DMA hint support programming in both sba and lba modules.
 */
 
@@ -28,7 +27,7 @@
 
 #include <linux/mm.h>
 #include <linux/string.h>
-#define PCI_DEBUG		/* for ASSERT */
+#undef PCI_DEBUG		/* for ASSERT */
 #include <linux/pci.h>
 #undef PCI_DEBUG
 
@@ -36,19 +35,19 @@
 #include <asm/io.h>
 #include <asm/dma.h>		/* for DMA_CHUNK_SIZE */
 
-#include <asm/hardware.h>	/* for register_driver() stuff */
+#include <asm/hardware.h>	/* for register_parisc_driver() stuff */
 #include <asm/gsc.h>		/* FIXME: for gsc_read/gsc_write */
 
 #include <linux/proc_fs.h>
 #include <asm/runway.h>		/* for proc_runway_root */
-
+#include <asm/pdc.h>		/* for PDC_MODEL_* */
 
 #define MODULE_NAME "SBA"
 
 /*
 ** The number of debug flags is a clue - this code is fragile.
 ** Don't even think about messing with it unless you have
-** plenty of 710's to sacrafice to the computer gods. :^)
+** plenty of 710's to sacrifice to the computer gods. :^)
 */
 #undef DEBUG_SBA_INIT
 #undef DEBUG_SBA_RUN
@@ -56,12 +55,9 @@
 #undef DEBUG_SBA_RESOURCE
 #undef ASSERT_PDIR_SANITY
 #undef DEBUG_LARGE_SG_ENTRIES
+#undef DEBUG_DMB_TRAP
 
-#if 1
-#define SBA_INLINE
-#else
 #define SBA_INLINE	__inline__
-#endif
 
 #ifdef DEBUG_SBA_INIT
 #define DBG_INIT(x...)	printk(x)
@@ -95,73 +91,43 @@
 ** allocated and free'd/purged at a time might make this
 ** less interesting).
 */
-#if 0
 #define DELAYED_RESOURCE_CNT	16
-#else
-#undef DELAYED_RESOURCE_CNT
-#endif
 
 #define DEFAULT_DMA_HINT_REG	0
 
-#define ASTRO_RUNWAY_PORT    0x582
-#define ASTRO_ROPES_PORT     0x780
-
-#define IKE_MERCED_PORT      0x803
-#define IKE_ROPES_PORT       0x781
-
-int sba_driver_callback(struct hp_device *, struct pa_iodc_driver *);
+#define ASTRO_RUNWAY_PORT	0x582
+#define ASTRO_ROPES_PORT	0x780
 
-static struct pa_iodc_driver sba_drivers_for[] = {
+#define IKE_MERCED_PORT		0x803
+#define IKE_ROPES_PORT		0x781
 
-/* FIXME: why is SVERSION checked? */
-
-   {HPHW_IOA, ASTRO_RUNWAY_PORT, 0x0, 0xb, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "I/O MMU", (void *) sba_driver_callback},
-
-   {HPHW_BCPORT, ASTRO_ROPES_PORT, 0x0, 0xb, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "I/O MMU", (void *) sba_driver_callback},
-
-#if 0
-/* FIXME : N-class! Use a different "callback"? */
-   {HPHW_BCPORT, IKE_MERCED_PORT, 0x0, 0xb, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "I/O MMU", (void *) sba_driver_callback},
-
-   {HPHW_BCPORT, IKE_ROPES_PORT, 0x0, 0xb, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "I/O MMU", (void *) sba_driver_callback},
-#endif
-
-   {0,0,0,0,0,0,
-   0,
-   (char *) NULL, (char *) NULL, (void *) NULL }
-};
+#define REO_MERCED_PORT		0x804
+#define REO_ROPES_PORT		0x782
 
+#define REOG_MERCED_PORT	0x805
+#define REOG_ROPES_PORT		0x783
 
 #define SBA_FUNC_ID	0x0000	/* function id */
 #define SBA_FCLASS	0x0008	/* function class, bist, header, rev... */
 
-#define IS_ASTRO(id) ( \
-    (((id)->hw_type == HPHW_IOA) && ((id)->hversion == ASTRO_RUNWAY_PORT)) || \
-    (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == ASTRO_ROPES_PORT))  \
-)
+#define IS_ASTRO(id) \
+(((id)->hversion == ASTRO_RUNWAY_PORT) || ((id)->hversion == ASTRO_ROPES_PORT))
+
+#define IS_IKE(id) \
+(((id)->hversion == IKE_MERCED_PORT) || ((id)->hversion == IKE_ROPES_PORT))
 
-#define CONFIG_FUNC_SIZE 4096   /* SBA configuration function reg set */
+#define SBA_FUNC_SIZE 4096   /* SBA configuration function reg set */
 
 #define ASTRO_IOC_OFFSET 0x20000
 /* Ike's IOC's occupy functions 2 and 3 (not 0 and 1) */
-#define IKE_IOC_OFFSET(p) ((p+2)*CONFIG_FUNC_SIZE)
+#define IKE_IOC_OFFSET(p) ((p+2)*SBA_FUNC_SIZE)
 
 #define IOC_CTRL          0x8	/* IOC_CTRL offset */
-#define IOC_CTRL_TE       (0x1 << 0) /* TOC Enable */
-#define IOC_CTRL_RM       (0x1 << 8) /* Real Mode */
-#define IOC_CTRL_NC       (0x1 << 9) /* Non Coherent Mode */
+#define IOC_CTRL_TC       (1 << 0) /* TOC Enable */
+#define IOC_CTRL_CE       (1 << 1) /* Coalesce Enable */
+#define IOC_CTRL_DE       (1 << 2) /* Dillon Enable */
+#define IOC_CTRL_RM       (1 << 8) /* Real Mode */
+#define IOC_CTRL_NC       (1 << 9) /* Non Coherent Mode */
 
 #define MAX_IOC		2	/* per Ike. Astro only has 1 */
 
@@ -233,18 +199,22 @@
 
 
 struct ioc {
-	char    *ioc_hpa;	/* I/O MMU base address */
+	unsigned long	ioc_hpa;	/* I/O MMU base address */
 	char	*res_map;	/* resource map, bit == pdir entry */
 	u64	*pdir_base;	/* physical base address */
 
-	unsigned long	*res_hint;	/* next available IOVP - circular search */
+	unsigned long	*res_hint;	/* next avail IOVP - circular search */
+	spinlock_t	res_lock;
+	unsigned long	hint_mask_pdir;	/* bits used for DMA hints */
 	unsigned int	res_bitshift;	/* from the LEFT! */
 	unsigned int	res_size;	/* size of resource map in bytes */
 	unsigned int	hint_shift_pdir;
-	spinlock_t	res_lock;
-	unsigned long	hint_mask_pdir;		/* bits used for DMA hints */
-#ifdef DELAYED_RESOURCE_CNT
-	dma_addr_t res_delay[DELAYED_RESOURCE_CNT];
+#if DELAYED_RESOURCE_CNT > 0
+	int saved_cnt;
+	struct sba_dma_pair {
+		dma_addr_t	iova;
+		size_t		size;
+	} saved[DELAYED_RESOURCE_CNT];
 #endif
 
 #ifdef CONFIG_PROC_FS
@@ -269,23 +239,32 @@
 };
 
 struct sba_device {
-	struct sba_device	*next;	/* list of LBA's in system */
-	struct hp_device	*iodc;	/* data about dev from firmware */
-	char			*sba_hpa; /* base address */
+	struct sba_device	*next;	/* list of SBA's in system */
+	struct parisc_device	*dev;	/* dev found in bus walk */
+	struct parisc_device_id	*iodc;	/* data about dev from firmware */
+	const char 		*name;
+	unsigned long		sba_hpa; /* base address */
 	spinlock_t		sba_lock;
-	unsigned int			flags;  /* state/functionality enabled */
-	unsigned int			hw_rev;  /* HW revision of chip */
+	unsigned int		flags;  /* state/functionality enabled */
+	unsigned int		hw_rev;  /* HW revision of chip */
 
-	unsigned int			num_ioc;  /* number of on-board IOC's */
+	unsigned int		num_ioc;  /* number of on-board IOC's */
 	struct ioc		ioc[MAX_IOC];
 };
 
 
 static struct sba_device *sba_list;
-static int sba_count;
+
+static unsigned long ioc_needs_fdc = 0;
 
 /* Ratio of Host MEM to IOV Space size */
-static unsigned long sba_mem_ratio = 4;
+static unsigned long sba_mem_ratio = 8;
+
+/* global count of IOMMUs in the system */
+static unsigned int global_ioc_cnt = 0;
+
+/* PA8700 (Piranha 2.2) bug workaround */
+static unsigned long piranha_bad_128k = 0;
 
 /* Looks nice and keeps the compiler happy */
 #define SBA_DEV(d) ((struct sba_device *) (d))
@@ -299,73 +278,75 @@
 **
 ** BE WARNED: register writes are posted.
 **  (ie follow writes which must reach HW with a read)
+**
+** Superdome (in particular, REO) allows only 64-bit CSR accesses.
 */
-#define READ_U8(addr)  gsc_readb(addr)
-#define READ_U16(addr) gsc_readw((u16 *) (addr))
-#define READ_U32(addr) gsc_readl((u32 *) (addr))
-#define WRITE_U8(value, addr) gsc_writeb(value, addr)
-#define WRITE_U16(value, addr) gsc_writew(value, (u16 *) (addr))
-#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr))
-
-#define READ_REG8(addr)  gsc_readb(addr)
-#define READ_REG16(addr) le16_to_cpu(gsc_readw((u16 *) (addr)))
-#define READ_REG32(addr) le32_to_cpu(gsc_readl((u32 *) (addr)))
-#define READ_REG64(addr) le64_to_cpu(gsc_readq((u64 *) (addr)))
-#define WRITE_REG8(value, addr) gsc_writeb(value, addr)
-#define WRITE_REG16(value, addr) gsc_writew(cpu_to_le16(value), (u16 *) (addr))
-#define WRITE_REG32(value, addr) gsc_writel(cpu_to_le32(value), (u32 *) (addr))
-#define WRITE_REG64(value, addr) gsc_writeq(cpu_to_le64(value), (u64 *) (addr))
+#define READ_REG32(addr)	 le32_to_cpu(__raw_readl(addr))
+#define READ_REG64(addr)	 le64_to_cpu(__raw_readq(addr))
+#define WRITE_REG32(val, addr) __raw_writel(cpu_to_le32(val), addr)
+#define WRITE_REG64(val, addr) __raw_writeq(cpu_to_le64(val), addr)
+
+#ifdef __LP64__
+#define READ_REG(addr)		READ_REG64(addr)
+#define WRITE_REG(value, addr)	WRITE_REG64(value, addr)
+#else
+#define READ_REG(addr)		READ_REG32(addr)
+#define WRITE_REG(value, addr)	WRITE_REG32(value, addr)
+#endif
 
 #ifdef DEBUG_SBA_INIT
 
+/* NOTE: When __LP64__ isn't defined, READ_REG64() is two 32-bit reads */
+
+/**
+ * sba_dump_ranges - debugging only - print ranges assigned to this IOA
+ * @hpa: base address of the sba
+ *
+ * Print the MMIO and IO Port address ranges forwarded by an Astro/Ike/RIO
+ * IO Adapter (aka Bus Converter).
+ */
 static void
-sba_dump_ranges(char *hpa)
+sba_dump_ranges(unsigned long hpa)
 {
-	printk("SBA at 0x%p\n", hpa);
-	printk("IOS_DIST_BASE   : %08x %08x\n",
-			READ_REG32(hpa+IOS_DIST_BASE+4),
-			READ_REG32(hpa+IOS_DIST_BASE));
-	printk("IOS_DIST_MASK   : %08x %08x\n",
-			READ_REG32(hpa+IOS_DIST_MASK+4),
-			READ_REG32(hpa+IOS_DIST_MASK));
-	printk("IOS_DIST_ROUTE  : %08x %08x\n",
-			READ_REG32(hpa+IOS_DIST_ROUTE+4),
-			READ_REG32(hpa+IOS_DIST_ROUTE));
-	printk("\n");
-	printk("IOS_DIRECT_BASE : %08x %08x\n",
-			READ_REG32(hpa+IOS_DIRECT_BASE+4),
-			READ_REG32(hpa+IOS_DIRECT_BASE));
-	printk("IOS_DIRECT_MASK : %08x %08x\n",
-			READ_REG32(hpa+IOS_DIRECT_MASK+4),
-			READ_REG32(hpa+IOS_DIRECT_MASK));
-	printk("IOS_DIRECT_ROUTE: %08x %08x\n",
-			READ_REG32(hpa+IOS_DIRECT_ROUTE+4),
-			READ_REG32(hpa+IOS_DIRECT_ROUTE));
+	DBG_INIT("SBA at 0x%lx\n", hpa);
+	DBG_INIT("IOS_DIST_BASE   : %Lx\n", READ_REG64(hpa+IOS_DIST_BASE));
+	DBG_INIT("IOS_DIST_MASK   : %Lx\n", READ_REG64(hpa+IOS_DIST_MASK));
+	DBG_INIT("IOS_DIST_ROUTE  : %Lx\n", READ_REG64(hpa+IOS_DIST_ROUTE));
+	DBG_INIT("\n");
+	DBG_INIT("IOS_DIRECT_BASE : %Lx\n", READ_REG64(hpa+IOS_DIRECT_BASE));
+	DBG_INIT("IOS_DIRECT_MASK : %Lx\n", READ_REG64(hpa+IOS_DIRECT_MASK));
+	DBG_INIT("IOS_DIRECT_ROUTE: %Lx\n", READ_REG64(hpa+IOS_DIRECT_ROUTE));
 }
 
+/**
+ * sba_dump_tlb - debugging only - print IOMMU operating parameters
+ * @hpa: base address of the IOMMU
+ *
+ * Print the size/location of the IO MMU PDIR.
+ */
 static void
-sba_dump_tlb(char *hpa)
+sba_dump_tlb(unsigned long hpa)
 {
-	printk("IO TLB at 0x%p\n", hpa);
-	printk("IOC_IBASE   : %08x %08x\n",
-			READ_REG32(hpa+IOC_IBASE+4),
-			READ_REG32(hpa+IOC_IBASE));
-	printk("IOC_IMASK   : %08x %08x\n",
-			READ_REG32(hpa+IOC_IMASK+4),
-			READ_REG32(hpa+IOC_IMASK));
-	printk("IOC_TCNFG   : %08x %08x\n",
-			READ_REG32(hpa+IOC_TCNFG+4),
-			READ_REG32(hpa+IOC_TCNFG));
-	printk("IOC_PDIR_BASE: %08x %08x\n",
-			READ_REG32(hpa+IOC_PDIR_BASE+4),
-			READ_REG32(hpa+IOC_PDIR_BASE));
-	printk("\n");
+	DBG_INIT("IO TLB at 0x%lx\n", hpa);
+	DBG_INIT("IOC_IBASE    : %Lx\n", READ_REG64(hpa+IOC_IBASE));
+	DBG_INIT("IOC_IMASK    : %Lx\n", READ_REG64(hpa+IOC_IMASK));
+	DBG_INIT("IOC_TCNFG    : %Lx\n", READ_REG64(hpa+IOC_TCNFG));
+	DBG_INIT("IOC_PDIR_BASE: %Lx\n", READ_REG64(hpa+IOC_PDIR_BASE));
+	DBG_INIT("\n");
 }
 #endif
 
 
 #ifdef ASSERT_PDIR_SANITY
 
+/**
+ * sba_dump_pdir_entry - debugging only - print one IOMMU PDIR entry
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @msg: text to print ont the output line.
+ * @pide: pdir index.
+ *
+ * Print one entry of the IO MMU PDIR in human readable form.
+ */
 static void
 sba_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide)
 {
@@ -374,24 +355,30 @@
 	unsigned long *rptr = (unsigned long *) &(ioc->res_map[(pide >>3) & ~(sizeof(unsigned long) - 1)]);
 	uint rcnt;
 
-	printk("SBA: %s rp %p bit %d rval 0x%lx\n",
+	printk(KERN_DEBUG "SBA: %s rp %p bit %d rval 0x%lx\n",
 		 msg,
 		 rptr, pide & (BITS_PER_LONG - 1), *rptr);
 
 	rcnt = 0;
 	while (rcnt < BITS_PER_LONG) {
-		printk("%s %2d %p %016Lx\n",
+		printk(KERN_DEBUG "%s %2d %p %016Lx\n",
 			(rcnt == (pide & (BITS_PER_LONG - 1)))
 				? "    -->" : "       ",
 			rcnt, ptr, *ptr );
 		rcnt++;
 		ptr++;
 	}
-	printk(msg);
+	printk(KERN_DEBUG "%s", msg);
 }
 
 
-/* Verify the resource map and pdir state is consistent */
+/**
+ * sba_check_pdir - debugging only - consistency checker
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @msg: text to print ont the output line.
+ *
+ * Verify the resource map and pdir state is consistent
+ */
 static int
 sba_check_pdir(struct ioc *ioc, char *msg)
 {
@@ -428,15 +415,23 @@
 }
 
 
+/**
+ * sba_dump_sg - debugging only - print Scatter-Gather list
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg: head of the SG list
+ * @nents: number of entries in SG list
+ *
+ * print the SG list so we can verify it's correct by hand.
+ */
 static void
 sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents)
 {
 	while (nents-- > 0) {
-		printk(" %d : %08lx/%05x %p/%05x\n",
+		printk(KERN_DEBUG " %d : %08lx/%05x %p/%05x\n",
 				nents,
 				(unsigned long) sg_dma_address(startsg),
 				sg_dma_len(startsg),
-				startsg->address, startsg->length);
+				sg_virt_addr(startsg), startsg->length);
 		startsg++;
 	}
 }
@@ -445,25 +440,6 @@
 
 
 
-/*
-** One time initialization to let the world know the LBA was found.
-** This is the only routine which is NOT static.
-** Must be called exactly once before pci_init().
-*/
-void __init
-sba_init(void)
-{
-	sba_list = (struct sba_device *) NULL;
-	sba_count = 0;
-
-#ifdef DEBUG_SBA_INIT
-	sba_dump_ranges((char *) 0xFED00000L);
-#endif
-
-	register_driver(sba_drivers_for);
-}
-
-
 
 /**************************************************************
 *
@@ -489,13 +465,15 @@
 #define RESMAP_IDX_MASK   (sizeof(unsigned long) - 1)
 
 
-/*
-** Perf optimizations:
-** o search for log2(size) bits at a time.
-**
-** Search should use register width as "stride" to search the res_map. 
-*/
-
+/**
+ * sba_search_bitmap - find free space in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @bits_wanted: number of entries we need.
+ *
+ * Find consecutive free bits in resource bitmap.
+ * Each bit represents one entry in the IO Pdir.
+ * Cool perf optimization: search for log2(size) bits at a time.
+ */
 static SBA_INLINE unsigned long
 sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted)
 {
@@ -512,7 +490,6 @@
 				*res_ptr = RESMAP_MASK(bits_wanted);
 				pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
 				pide <<= 3;	/* convert to bit address */
-				ASSERT(0 != pide);
 				break;
 			}
 		}
@@ -536,7 +513,7 @@
 		}
 		mask = RESMAP_MASK(bits_wanted) >> bitshiftcnt;
 
-		DBG_RES("sba_search_bitmap() o %ld %p", o, res_ptr);
+		DBG_RES("%s() o %ld %p", __FUNCTION__, o, res_ptr);
 		while(res_ptr < res_end)
 		{ 
 			DBG_RES("    %p %lx %lx\n", res_ptr, mask, *res_ptr);
@@ -546,7 +523,6 @@
 				pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
 				pide <<= 3;	/* convert to bit address */
 				pide += bitshiftcnt;
-				ASSERT(0 != pide);
 				break;
 			}
 			mask >>= o;
@@ -562,11 +538,24 @@
 	}
 
 	/* wrapped ? */
-	ioc->res_hint = (res_end == res_ptr) ? (unsigned long *) ioc->res_map : res_ptr;
+	if (res_end <= res_ptr) {
+		ioc->res_hint = (unsigned long *) ioc->res_map;
+		ioc->res_bitshift = 0;
+	} else {
+		ioc->res_hint = res_ptr;
+	}
 	return (pide);
 }
 
 
+/**
+ * sba_alloc_range - find free bits and mark them in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @size: number of bytes to create a mapping for
+ *
+ * Given a size, find consecutive unmarked and then mark those bits in the
+ * resource bit map.
+ */
 static int
 sba_alloc_range(struct ioc *ioc, size_t size)
 {
@@ -577,8 +566,8 @@
 	unsigned long pide;
 
 	ASSERT(pages_needed);
-	ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE);
-	ASSERT(pages_needed < BITS_PER_LONG);
+	ASSERT((pages_needed * IOVP_SIZE) <= DMA_CHUNK_SIZE);
+	ASSERT(pages_needed <= BITS_PER_LONG);
 	ASSERT(0 == (size & ~IOVP_MASK));
 
 	/*
@@ -590,7 +579,7 @@
 	if (pide >= (ioc->res_size << 3)) {
 		pide = sba_search_bitmap(ioc, pages_needed);
 		if (pide >= (ioc->res_size << 3))
-			panic(__FILE__ ": I/O MMU @ %p is out of mapping resources\n", ioc->ioc_hpa);
+			panic(__FILE__ ": I/O MMU @ %lx is out of mapping resources\n", ioc->ioc_hpa);
 	}
 
 #ifdef ASSERT_PDIR_SANITY
@@ -600,8 +589,8 @@
 	}
 #endif
 
-	DBG_RES("sba_alloc_range(%x) %d -> %lx hint %x/%x\n",
-		size, pages_needed, pide,
+	DBG_RES("%s(%x) %d -> %lx hint %x/%x\n",
+		__FUNCTION__, size, pages_needed, pide,
 		(uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map),
 		ioc->res_bitshift );
 
@@ -622,9 +611,14 @@
 }
 
 
-/*
-** clear bits in the ioc's resource map
-*/
+/**
+ * sba_free_range - unmark bits in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @iova: IO virtual address which was previously allocated.
+ * @size: number of bytes to create a mapping for
+ *
+ * clear bits in the ioc's resource map
+ */
 static SBA_INLINE void
 sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size)
 {
@@ -638,8 +632,8 @@
 	/* 3-bits "bit" address plus 2 (or 3) bits for "byte" == bit in word */
 	unsigned long m = RESMAP_MASK(bits_not_wanted) >> (pide & (BITS_PER_LONG - 1));
 
-	DBG_RES("sba_free_range( ,%x,%x) %x/%lx %x %p %lx\n",
-		(uint) iova, size,
+	DBG_RES("%s( ,%x,%x) %x/%lx %x %p %lx\n",
+		__FUNCTION__, (uint) iova, size,
 		bits_not_wanted, m, pide, res_ptr, *res_ptr);
 
 #ifdef CONFIG_PROC_FS
@@ -648,8 +642,8 @@
 
 	ASSERT(m != 0);
 	ASSERT(bits_not_wanted);
-	ASSERT((bits_not_wanted * IOVP_SIZE) < DMA_CHUNK_SIZE);
-	ASSERT(bits_not_wanted < BITS_PER_LONG);
+	ASSERT((bits_not_wanted * IOVP_SIZE) <= DMA_CHUNK_SIZE);
+	ASSERT(bits_not_wanted <= BITS_PER_LONG);
 	ASSERT((*res_ptr & m) == m); /* verify same bits are set */
 	*res_ptr &= ~m;
 }
@@ -667,31 +661,37 @@
 typedef unsigned long space_t;
 #define KERNEL_SPACE 0
 
-/*
-* SBA Mapping Routine
-*
-* Given a virtual address (vba, arg2) and space id, (sid, arg1)
-* sba_io_pdir_entry() loads the I/O PDIR entry pointed to by
-* pdir_ptr (arg0). Each IO Pdir entry consists of 8 bytes as
-* shown below (MSB == bit 0):
-*
-*  0                    19                                 51   55       63
-* +-+---------------------+----------------------------------+----+--------+
-* |V|        U            |            PPN[43:12]            | U  |   VI   |
-* +-+---------------------+----------------------------------+----+--------+
-*
-*  V  == Valid Bit
-*  U  == Unused
-* PPN == Physical Page Number
-* VI  == Virtual Index (aka Coherent Index)
-*
-* The physical address fields are filled with the results of the LPA
-* instruction.  The virtual index field is filled with the results of
-* of the LCI (Load Coherence Index) instruction.  The 8 bits used for
-* the virtual index are bits 12:19 of the value returned by LCI.
-*
-* We need to pre-swap the bytes since PCX-W is Big Endian.
-*/
+/**
+ * sba_io_pdir_entry - fill in one IO PDIR entry
+ * @pdir_ptr:  pointer to IO PDIR entry
+ * @sid: process Space ID
+ * @vba: Virtual CPU address of buffer to map
+ *
+ * SBA Mapping Routine
+ *
+ * Given a virtual address (vba, arg2) and space id, (sid, arg1)
+ * sba_io_pdir_entry() loads the I/O PDIR entry pointed to by
+ * pdir_ptr (arg0). Each IO Pdir entry consists of 8 bytes as
+ * shown below (MSB == bit 0):
+ *
+ *  0                    19                                 51   55       63
+ * +-+---------------------+----------------------------------+----+--------+
+ * |V|        U            |            PPN[43:12]            | U  |   VI   |
+ * +-+---------------------+----------------------------------+----+--------+
+ *
+ *  V  == Valid Bit
+ *  U  == Unused
+ * PPN == Physical Page Number
+ * VI  == Virtual Index (aka Coherent Index)
+ *
+ * The physical address fields are filled with the results of the LPA
+ * instruction.  The virtual index field is filled with the results of
+ * of the LCI (Load Coherence Index) instruction.  The 8 bits used for
+ * the virtual index are bits 12:19 of the value returned by LCI.
+ *
+ * We need to pre-swap the bytes since PCX-W is Big Endian.
+ */
+
 
 void SBA_INLINE
 sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba)
@@ -699,9 +699,11 @@
 	u64 pa; /* physical address */
 	register unsigned ci; /* coherent index */
 
-	/* We currently only support kernel addresses */
-	ASSERT(sid == 0);
-	ASSERT(((unsigned long) vba & 0xc0000000UL) == 0xc0000000UL);
+	/* We currently only support kernel addresses.
+	 * fdc instr below will need to reload sr1 with KERNEL_SPACE
+	 * once we try to support direct DMA to user space.
+	 */
+	ASSERT(sid == KERNEL_SPACE);
 
 	pa = virt_to_phys(vba);
 	pa &= ~4095ULL;			/* clear out offset bits */
@@ -712,25 +714,41 @@
 
 	pa |= 0x8000000000000000ULL;	/* set "valid" bit */
 	*pdir_ptr = cpu_to_le64(pa);	/* swap and store into I/O Pdir */
+
+	/*
+	 * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit set
+	 * (bit #61, big endian), we have to flush and sync every time
+	 * IO-PDIR is changed in Ike/Astro.
+	 */
+	if (ioc_needs_fdc) {
+		asm volatile("fdc 0(%%sr1,%0)\n\tsync" : : "r" (pdir_ptr));
+	}
 }
 
 
-/***********************************************************
- * The Ike PCOM (Purge Command Register) is to purge
- * stale entries in the IO TLB when unmapping entries.
+/**
+ * sba_mark_invalid - invalidate one or more IO PDIR entries
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @iova:  IO Virtual Address mapped earlier
+ * @byte_cnt:  number of bytes this mapping covers.
+ *
+ * Marking the IO PDIR entry(ies) as Invalid and invalidate
+ * corresponding IO TLB entry. The Ike PCOM (Purge Command Register)
+ * is to purge stale entries in the IO TLB when unmapping entries.
  *
  * The PCOM register supports purging of multiple pages, with a minium
  * of 1 page and a maximum of 2GB. Hardware requires the address be
  * aligned to the size of the range being purged. The size of the range
- * must be a power of 2.
- ***********************************************************/
+ * must be a power of 2. The "Cool perf optimization" in the
+ * allocation routine helps keep that true.
+ */
 static SBA_INLINE void
 sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
 {
 	u32 iovp = (u32) SBA_IOVP(ioc,iova);
 
 	/* Even though this is a big-endian machine, the entries
-	** in the iopdir are swapped. That's why we clear the byte
+	** in the iopdir are little endian. That's why we clear the byte
 	** at +7 instead of at +0.
 	*/
 	int off = PDIR_INDEX(iovp)*sizeof(u64)+7;
@@ -775,32 +793,45 @@
 		} while (byte_cnt > 0);
 	}
 
-	WRITE_REG32(iovp, ioc->ioc_hpa+IOC_PCOM);
+	WRITE_REG(iovp, ioc->ioc_hpa+IOC_PCOM);
 }
 
+/**
+ * sba_dma_supported - PCI driver can query DMA support
+ * @dev: instance of PCI owned by the driver that's asking
+ * @mask:  number of address bits this PCI device can handle
+ *
+ * See Documentation/DMA-mapping.txt
+ */
 static int
 sba_dma_supported( struct pci_dev *dev, u64 mask)
 {
 	if (dev == NULL) {
-		printk(MODULE_NAME ": EISA/ISA/et al not supported\n");
+		printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n");
 		BUG();
 		return(0);
 	}
 
 	dev->dma_mask = mask;	/* save it */
 
-	/* only support PCI devices */
-	return((int) (mask >= 0xffffffff));
+	/* only support 32-bit PCI devices - no DAC support (yet) */
+	return((int) (mask == 0xffffffff));
 }
 
 
-/*
-** map_single returns a fully formed IOVA
-*/
+/**
+ * sba_map_single - map one buffer and return IOVA for DMA
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @addr:  driver buffer to map.
+ * @size:  number of bytes to map in driver buffer.
+ * @direction:  R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
 static dma_addr_t
 sba_map_single(struct pci_dev *dev, void *addr, size_t size, int direction)
 {
-	struct ioc *ioc = &sba_list->ioc[0];  /* FIXME : see Multi-IOC below */
+	struct ioc *ioc;
 	unsigned long flags; 
 	dma_addr_t iovp;
 	dma_addr_t offset;
@@ -808,9 +839,14 @@
 	int pide;
 
 	ASSERT(size > 0);
+	ASSERT(size <= DMA_CHUNK_SIZE);
+
+	ASSERT(dev->sysdata);
+	ioc = GET_IOC(dev);
+	ASSERT(ioc);
 
 	/* save offset bits */
-	offset = ((dma_addr_t) addr) & ~IOVP_MASK;
+	offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK;
 
 	/* round up to nearest IOVP_SIZE */
 	size = (size + offset + ~IOVP_MASK) & IOVP_MASK;
@@ -827,7 +863,8 @@
 	pide = sba_alloc_range(ioc, size);
 	iovp = (dma_addr_t) pide << IOVP_SHIFT;
 
-	DBG_RUN("sba_map_single() 0x%p -> 0x%lx", addr, (long) iovp | offset);
+	DBG_RUN("%s() 0x%p -> 0x%lx",
+		__FUNCTION__, addr, (long) iovp | offset);
 
 	pdir_start = &(ioc->pdir_base[pide]);
 
@@ -860,72 +897,85 @@
 }
 
 
+/**
+ * sba_unmap_single - unmap one IOVA and free resources
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @iova:  IOVA of driver buffer previously mapped.
+ * @size:  number of bytes mapped in driver buffer.
+ * @direction:  R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
 static void
 sba_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction)
 {
-#ifdef FIXME
-/* Multi-IOC (ie N-class) :  need to lookup IOC from dev
-** o If we can't know about lba PCI data structs, that eliminates ->sysdata.
-** o walking up pcidev->parent dead ends at elroy too
-** o leaves hashing dev->bus->number into some lookup.
-**   (may only work for N-class)
-** o use (struct pci_hba) and put fields in there for DMA.
-**   (ioc and per device dma_hint.)
-**
-** Last one seems the clearest and most promising.
-** sba_dma_supported() fill in those fields when the driver queries
-** the system for support.
-*/
-	struct ioc *ioc = (struct ioc *) ((struct pci_hba *) (dev->sysdata))->dma_data;
-#else
-	struct ioc *ioc = &sba_list->ioc[0];
+	struct ioc *ioc;
+#if DELAYED_RESOURCE_CNT > 0
+	struct sba_dma_pair *d;
 #endif
-	
 	unsigned long flags; 
 	dma_addr_t offset;
+
+	ASSERT(dev->sysdata);
+	ioc = GET_IOC(dev);
+	ASSERT(ioc);
+
 	offset = iova & ~IOVP_MASK;
 
-	DBG_RUN("%s() iovp 0x%lx/%x\n", __FUNCTION__, (long) iova, size);
+	DBG_RUN("%s() iovp 0x%lx/%x\n",
+		__FUNCTION__, (long) iova, size);
 
 	iova ^= offset;        /* clear offset bits */
 	size += offset;
 	size = ROUNDUP(size, IOVP_SIZE);
 
-	ASSERT(0 != iova);
-
 	spin_lock_irqsave(&ioc->res_lock, flags);
+
 #ifdef CONFIG_PROC_FS
 	ioc->usingle_calls++;
 	ioc->usingle_pages += size >> IOVP_SHIFT;
 #endif
-#ifdef DELAYED_RESOURCE_CNT
-	if (ioc->saved_cnt < DELAYED_RESOURCE_CNT) {
-		ioc->saved_iova[ioc->saved_cnt] = iova;
-		ioc->saved_size[ioc->saved_cnt] = size;
-		ioc_saved_cnt++;
-	} else {
-		do {
-#endif
-			sba_mark_invalid(ioc, iova, size);
-			sba_free_range(ioc, iova, size);
 
-#ifdef DELAYED_RESOURCE_CNT
-			ioc->saved_cnt--;
-			iova = ioc->saved_iova[ioc->saved_cnt];
-			size = ioc->saved_size[ioc->saved_cnt];
-		} while (ioc->saved_cnt)
-
-		/* flush purges */
-		(void) (volatile) READ_REG32(ioc->ioc_hpa+IOC_PCOM);
+#if DELAYED_RESOURCE_CNT > 0
+	d = &(ioc->saved[ioc->saved_cnt]);
+	d->iova = iova;
+	d->size = size;
+	if (++(ioc->saved_cnt) >= DELAYED_RESOURCE_CNT) {
+		int cnt = ioc->saved_cnt;
+		while (cnt--) {
+			sba_mark_invalid(ioc, d->iova, d->size);
+			sba_free_range(ioc, d->iova, d->size);
+			d--;
+		}
+		ioc->saved_cnt = 0;
+		READ_REG(ioc->ioc_hpa+IOC_PCOM);	/* flush purges */
 	}
-#else
-	/* flush purges */
-	READ_REG32(ioc->ioc_hpa+IOC_PCOM);
-#endif
+#else /* DELAYED_RESOURCE_CNT == 0 */
+	sba_mark_invalid(ioc, iova, size);
+	sba_free_range(ioc, iova, size);
+	READ_REG(ioc->ioc_hpa+IOC_PCOM);	/* flush purges */
+#endif /* DELAYED_RESOURCE_CNT == 0 */
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
+
+	/* XXX REVISIT for 2.5 Linux - need syncdma for zero-copy support.
+	** For Astro based systems this isn't a big deal WRT performance.
+	** As long as 2.4 kernels copyin/copyout data from/to userspace,
+	** we don't need the syncdma. The issue here is I/O MMU cachelines
+	** are *not* coherent in all cases.  May be hwrev dependent.
+	** Need to investigate more.
+	asm volatile("syncdma");	
+	*/
 }
 
 
+/**
+ * sba_alloc_consistent - allocate/map shared mem for DMA
+ * @hwdev: instance of PCI owned by the driver that's asking.
+ * @size:  number of bytes mapped in driver buffer.
+ * @dma_handle:  IOVA of new buffer.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
 static void *
 sba_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
 {
@@ -948,6 +998,15 @@
 }
 
 
+/**
+ * sba_free_consistent - free/unmap shared mem for DMA
+ * @hwdev: instance of PCI owned by the driver that's asking.
+ * @size:  number of bytes mapped in driver buffer.
+ * @vaddr:  virtual address IOVA of "consistent" buffer.
+ * @dma_handler:  IO virtual address of "consistent" buffer.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
 static void
 sba_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
 {
@@ -955,27 +1014,6 @@
 	free_pages((unsigned long) vaddr, get_order(size));
 }
 
-/*
-** Two address ranges are "virtually contiguous" iff:
-** 1) end of prev == start of next, or...	 append case
-** 3) end of next == start of prev		 prepend case
-**
-** and they are DMA contiguous *iff*:
-** 2) end of prev and start of next are both on a page boundry
-**
-** (shift left is a quick trick to mask off upper bits)
-*/
-#define DMA_CONTIG(__X, __Y) \
-	(((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL)
-
-/*
-** Assumption is two transactions are mutually exclusive.
-** ie both go to different parts of memory.
-** If both are true, then both transaction are on the same page.
-*/
-#define DMA_SAME_PAGE(s1,e1,s2,e2) \
-	( ((((s1) ^ (s2)) >> PAGE_SHIFT) == 0) \
-		&& ((((e1) ^ (e2)) >> PAGE_SHIFT) == 0) )
 
 /*
 ** Since 0 is a valid pdir_base index value, can't use that
@@ -988,6 +1026,17 @@
 int dump_run_sg = 0;
 #endif
 
+
+/**
+ * sba_fill_pdir - write allocated SG entries into IO PDIR
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg:  list of IOVA/size pairs
+ * @nents: number of entries in startsg list
+ *
+ * Take preprocessed SG list and write corresponding entries
+ * in the IO PDIR.
+ */
+
 static SBA_INLINE int
 sba_fill_pdir(
 	struct ioc *ioc,
@@ -1006,16 +1055,16 @@
 
 #ifdef DEBUG_LARGE_SG_ENTRIES
 		if (dump_run_sg)
-			printk(" %d : %08lx/%05x %p/%05x\n",
+			printk(KERN_DEBUG " %2d : %08lx/%05x %p/%05x\n",
 				nents,
 				(unsigned long) sg_dma_address(startsg), cnt,
-				startsg->address, startsg->length
+				sg_virt_address(startsg), startsg->length
 		);
 #else
 		DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n",
 				nents,
 				(unsigned long) sg_dma_address(startsg), cnt,
-				startsg->address, startsg->length
+				sg_virt_addr(startsg), startsg->length
 		);
 #endif
 		/*
@@ -1024,11 +1073,10 @@
 		if (sg_dma_address(startsg) & PIDE_FLAG) {
 			u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG;
 			dma_offset = (unsigned long) pide & ~IOVP_MASK;
-			pide >>= IOVP_SHIFT;
-			pdirp = &(ioc->pdir_base[pide]);
 			sg_dma_address(startsg) = 0;
-			++dma_sg;
-			sg_dma_address(dma_sg) = (pide << IOVP_SHIFT) + dma_offset;
+			dma_sg++;
+			sg_dma_address(dma_sg) = pide;
+			pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]);
 			n_mappings++;
 		}
 
@@ -1036,9 +1084,12 @@
 		** Look for a VCONTIG chunk
 		*/
 		if (cnt) {
-			unsigned long vaddr = (unsigned long) startsg->address;
+			unsigned long vaddr = (unsigned long) sg_virt_addr(startsg);
 			ASSERT(pdirp);
 
+			/* Since multiple Vcontig blocks could make up
+			** one DMA stream, *add* cnt to dma_len.
+			*/
 			sg_dma_len(dma_sg) += cnt;
 			cnt += dma_offset;
 			dma_offset=0;	/* only want offset on first chunk */
@@ -1062,133 +1113,142 @@
 }
 
 
-
 /*
-** First pass is to walk the SG list and determine where the breaks are
-** in the DMA stream. Allocates PDIR entries but does not fill them.
-** Returns the number of DMA chunks.
+** Two address ranges are DMA contiguous *iff* "end of prev" and
+** "start of next" are both on a page boundry.
 **
-** Doing the fill seperate from the coalescing/allocation keeps the
-** code simpler. Future enhancement could make one pass through
-** the sglist do both.
+** (shift left is a quick trick to mask off upper bits)
 */
+#define DMA_CONTIG(__X, __Y) \
+	(((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL)
+
+
+/**
+ * sba_coalesce_chunks - preprocess the SG list
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg:  list of IOVA/size pairs
+ * @nents: number of entries in startsg list
+ *
+ * First pass is to walk the SG list and determine where the breaks are
+ * in the DMA stream. Allocates PDIR entries but does not fill them.
+ * Returns the number of DMA chunks.
+ *
+ * Doing the fill seperate from the coalescing/allocation keeps the
+ * code simpler. Future enhancement could make one pass through
+ * the sglist do both.
+ */
 static SBA_INLINE int
 sba_coalesce_chunks( struct ioc *ioc,
 	struct scatterlist *startsg,
 	int nents)
 {
+	struct scatterlist *vcontig_sg;    /* VCONTIG chunk head */
+	unsigned long vcontig_len;         /* len of VCONTIG chunk */
+	unsigned long vcontig_end;
+	struct scatterlist *dma_sg;        /* next DMA stream head */
+	unsigned long dma_offset, dma_len; /* start/len of DMA stream */
 	int n_mappings = 0;
 
 	while (nents > 0) {
-		struct scatterlist *dma_sg;  /* next DMA stream head */
-		unsigned long dma_offset, dma_len;   /* start/len of DMA stream */
-		struct scatterlist *chunksg; /* virtually contig chunk head */
-		unsigned long chunk_addr, chunk_len; /* start/len of VCONTIG chunk */
+		unsigned long vaddr = (unsigned long) sg_virt_addr(startsg); 
 
 		/*
 		** Prepare for first/next DMA stream
 		*/
-		dma_sg = chunksg = startsg;
-		dma_len = chunk_len  = startsg->length;
-		chunk_addr = (unsigned long) startsg->address;
-		dma_offset = 0UL;
+		dma_sg = vcontig_sg = startsg;
+		dma_len = vcontig_len = vcontig_end = startsg->length;
+		vcontig_end +=  vaddr;
+		dma_offset = vaddr & ~IOVP_MASK;
+
+		/* PARANOID: clear entries */
+		sg_dma_address(startsg) = 0;
+		sg_dma_len(startsg) = 0;
 
 		/*
 		** This loop terminates one iteration "early" since
 		** it's always looking one "ahead".
 		*/
 		while (--nents > 0) {
-			/* ptr to coalesce prev and next */
-			struct scatterlist *prev_sg = startsg;
-			unsigned long prev_end = (unsigned long) prev_sg->address + prev_sg->length;
-			unsigned long current_end;
+			unsigned long vaddr;	/* tmp */
+
+			startsg++;
 
 			/* PARANOID: clear entries */
 			sg_dma_address(startsg) = 0;
 			sg_dma_len(startsg) = 0;
 
-			/* Now start looking ahead */
-			startsg++;
-			current_end  = (unsigned long) startsg->address + startsg->length;
+			/* catch brokenness in SCSI layer */
+			ASSERT(startsg->length <= DMA_CHUNK_SIZE);
 
 			/*
-			** First look for virtually contiguous blocks.
-			** PARISC needs this since it's cache is virtually
-			** indexed and we need the associated virtual
-			** address for each I/O address we map.
-			**
-			** 1) can we *prepend* the next transaction?
+			** First make sure current dma stream won't
+			** exceed DMA_CHUNK_SIZE if we coalesce the
+			** next entry.
 			*/
-			if (current_end == (unsigned long) prev_sg->address)
-			{
-				/* prepend : get new offset */
-				chunksg = startsg;
-				chunk_addr = (unsigned long) prev_sg->address;
-				chunk_len += startsg->length;
-				dma_len   += startsg->length;
-				continue;
-			}
+			if (((dma_len + dma_offset + startsg->length + ~IOVP_MASK) & IOVP_MASK) > DMA_CHUNK_SIZE)
+				break;
 
 			/*
-			** 2) or append the next transaction?
+			** Then look for virtually contiguous blocks.
+			** PARISC needs to associate a virtual address
+			** with each IO address mapped. The CPU cache is
+			** virtually tagged and the IOMMU uses part
+			** of the virtual address to participate in
+			** CPU cache coherency.
+			**
+			** append the next transaction?
 			*/
-			if  (prev_end == (unsigned long) startsg->address)
+			vaddr = (unsigned long) sg_virt_addr(startsg);
+			if  (vcontig_end == vaddr)
 			{
-				chunk_len += startsg->length;
-				dma_len   += startsg->length;
+				vcontig_len += startsg->length;
+				vcontig_end += startsg->length;
+				dma_len     += startsg->length;
 				continue;
 			}
 
 #ifdef DEBUG_LARGE_SG_ENTRIES
-			dump_run_sg = (chunk_len > IOVP_SIZE);
+			dump_run_sg = (vcontig_len > IOVP_SIZE);
 #endif
+
 			/*
 			** Not virtually contigous.
 			** Terminate prev chunk.
 			** Start a new chunk.
 			**
-			** Once we start a new VCONTIG chunk, the offset
+			** Once we start a new VCONTIG chunk, dma_offset
 			** can't change. And we need the offset from the first
 			** chunk - not the last one. Ergo Successive chunks
 			** must start on page boundaries and dove tail
 			** with it's predecessor.
 			*/
-			sg_dma_len(prev_sg) = chunk_len;
+			sg_dma_len(vcontig_sg) = vcontig_len;
 
-			chunk_len = startsg->length;
-			dma_offset |= (chunk_addr & ~IOVP_MASK);
-			ASSERT((0 == (chunk_addr & ~IOVP_MASK)) ||
-				(dma_offset == (chunk_addr & ~IOVP_MASK)));
+			vcontig_sg = startsg;
+			vcontig_len = startsg->length;
 
-#if 0
 			/*
-			** 4) do the chunks end/start on page boundaries?
-			**  Easier than 3 since no offsets are involved.
+			** 3) do the entries end/start on page boundaries?
+			**    Don't update vcontig_end until we've checked.
 			*/
-			if (DMA_CONTIG(prev_end, startsg->address))
+			if (DMA_CONTIG(vcontig_end, vaddr))
 			{
-				/*
-				** Yes.
-				** Reset chunk ptr.
-				*/
-				chunksg = startsg;
-				chunk_addr = (unsigned long) startsg->address;
-
+				vcontig_end = vcontig_len + vaddr;
+				dma_len += vcontig_len;
 				continue;
-			} else
-#endif
-			{
+			} else {
 				break;
 			}
 		}
 
 		/*
 		** End of DMA Stream
-		** Terminate chunk.
+		** Terminate last VCONTIG block.
 		** Allocate space for DMA stream.
 		*/
-		sg_dma_len(startsg) = chunk_len;
+		sg_dma_len(vcontig_sg) = vcontig_len;
 		dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK;
+		ASSERT(dma_len <= DMA_CHUNK_SIZE);
 		sg_dma_address(dma_sg) =
 			PIDE_FLAG 
 			| (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT)
@@ -1200,24 +1260,34 @@
 }
 
 
-/*
-** And this algorithm still generally only ends up coalescing entries
-** that happens to be on the same page due to how sglists are assembled.
-*/
+/**
+ * sba_map_sg - map Scatter/Gather list
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @sglist:  array of buffer/length pairs
+ * @nents:  number of entries in list
+ * @direction:  R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
 static int
 sba_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
 {
-	struct ioc *ioc = &sba_list->ioc[0];  /* FIXME : see Multi-IOC below */
+	struct ioc *ioc;
 	int coalesced, filled = 0;
 	unsigned long flags;
 
 	DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents);
 
+	ASSERT(dev->sysdata);
+	ioc = GET_IOC(dev);
+	ASSERT(ioc);
+
 	/* Fast path single entry scatterlists. */
 	if (nents == 1) {
-		sg_dma_address(sglist)= sba_map_single(dev, sglist->address,
+		sg_dma_address(sglist) = sba_map_single(dev,
+						sg_virt_addr(sglist),
 						sglist->length, direction);
-		sg_dma_len(sglist)= sglist->length;
+		sg_dma_len(sglist)     = sglist->length;
 		return 1;
 	}
 
@@ -1272,16 +1342,29 @@
 }
 
 
+/**
+ * sba_unmap_sg - unmap Scatter/Gather list
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @sglist:  array of buffer/length pairs
+ * @nents:  number of entries in list
+ * @direction:  R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
 static void 
 sba_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
 {
-	struct ioc *ioc = &sba_list->ioc[0];  /* FIXME : see Multi-IOC below */
+	struct ioc *ioc;
 #ifdef ASSERT_PDIR_SANITY
 	unsigned long flags;
 #endif
 
 	DBG_RUN_SG("%s() START %d entries,  %p,%x\n",
-		__FUNCTION__, nents, sglist->address, sglist->length);
+		__FUNCTION__, nents, sg_virt_addr(sglist), sglist->length);
+
+	ASSERT(dev->sysdata);
+	ioc = GET_IOC(dev);
+	ASSERT(ioc);
 
 #ifdef CONFIG_PROC_FS
 	ioc->usg_calls++;
@@ -1295,10 +1378,11 @@
 
 	while (sg_dma_len(sglist) && nents--) {
 
+		sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction);
 #ifdef CONFIG_PROC_FS
-	ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT;
+		ioc->usg_pages += ((sg_dma_address(sglist) & ~IOVP_MASK) + sg_dma_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;
+		ioc->usingle_calls--;	/* kluge since call is unmap_sg() */
 #endif
-		sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction);
 		++sglist;
 	}
 
@@ -1359,21 +1443,117 @@
 *   Initialization and claim
 *
 ***************************************************************/
+#define PIRANHA_ADDR_MASK	0x00160000UL /* bit 17,18,20 */
+#define PIRANHA_ADDR_VAL	0x00060000UL /* bit 17,18 on */
+static void *
+sba_alloc_pdir(unsigned int pdir_size)
+{
+        unsigned long pdir_base;
+	unsigned long pdir_order = get_order(pdir_size);
+
+	pdir_base = __get_free_pages(GFP_KERNEL, pdir_order);
+	if (NULL == (void *) pdir_base)
+		panic("sba_ioc_init() could not allocate I/O Page Table\n");
+
+	/* If this is not PA8700 (PCX-W2)
+	**	OR newer than ver 2.2
+	**	OR in a system that doesn't need VINDEX bits from SBA,
+	**
+	** then we aren't exposed to the HW bug.
+	*/
+	if ( ((boot_cpu_data.pdc.cpuid >> 5) & 0x7f) != 0x13
+			|| (boot_cpu_data.pdc.versions > 0x202)
+			|| (boot_cpu_data.pdc.capabilities & 0x08L) )
+		return (void *) pdir_base;
+
+	/*
+	 * PA8700 (PCX-W2, aka piranha) silent data corruption fix
+	 *
+	 * An interaction between PA8700 CPU (Ver 2.2 or older) and
+	 * Ike/Astro can cause silent data corruption. This is only
+	 * a problem if the I/O PDIR is located in memory such that
+	 * (little-endian)  bits 17 and 18 are on and bit 20 is off.
+	 *
+	 * Since the max IO Pdir size is 2MB, by cleverly allocating the
+	 * right physical address, we can either avoid (IOPDIR <= 1MB)
+	 * or minimize (2MB IO Pdir) the problem if we restrict the
+	 * IO Pdir to a maximum size of 2MB-128K (1902K).
+	 *
+	 * Because we always allocate 2^N sized IO pdirs, either of the
+	 * "bad" regions will be the last 128K if at all. That's easy
+	 * to test for.
+	 * 
+	 */
+	if (pdir_order <= (19-12)) {
+		if (((virt_to_phys(pdir_base)+pdir_size-1) & PIRANHA_ADDR_MASK) == PIRANHA_ADDR_VAL) {
+			/* allocate a new one on 512k alignment */
+			unsigned long new_pdir = __get_free_pages(GFP_KERNEL, (19-12));
+			/* release original */
+			free_pages(pdir_base, pdir_order);
+
+			pdir_base = new_pdir;
+
+			/* release excess */
+			while (pdir_order < (19-12)) {
+				new_pdir += pdir_size;
+				free_pages(new_pdir, pdir_order);
+				pdir_order +=1;
+				pdir_size <<=1;
+			}
+		}
+	} else {
+		/*
+		** 1MB or 2MB Pdir
+		** Needs to be aligned on an "odd" 1MB boundary.
+		*/
+		unsigned long new_pdir = __get_free_pages(GFP_KERNEL, pdir_order+1); /* 2 or 4MB */
+
+		/* release original */
+		free_pages( pdir_base, pdir_order);
+
+		/* release first 1MB */
+		free_pages(new_pdir, 20-12);
+
+		pdir_base = new_pdir + 1024*1024;
+
+		if (pdir_order > (20-12)) {
+			/*
+			** 2MB Pdir.
+			**
+			** Flag tells init_bitmap() to mark bad 128k as used
+			** and to reduce the size by 128k.
+			*/
+			piranha_bad_128k = 1;
+
+			new_pdir += 3*1024*1024;
+			/* release last 1MB */
+			free_pages(new_pdir, 20-12);
+
+			/* release unusable 128KB */
+			free_pages(new_pdir - 128*1024 , 17-12);
+
+			pdir_size -= 128*1024;
+		}
+	}
+
+	memset((void *) pdir_base, 0, pdir_size);
+	return (void *) pdir_base;
+}
 
 
 static void
-sba_ioc_init(struct ioc *ioc)
+sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
 {
-	extern unsigned long mem_max;          /* arch.../setup.c */
-	extern void lba_init_iregs(void *, u32, u32);   /* arch.../lba_pci.c */
+	/* lba_set_iregs() is in arch/parisc/kernel/lba_pci.c */
+	extern void lba_set_iregs(struct parisc_device *, u32, u32);
 
 	u32 iova_space_size, iova_space_mask;
-	void * pdir_base;
 	int pdir_size, iov_order;
+	unsigned long physmem;
+	struct parisc_device *lba;
 
 	/*
 	** Determine IOVA Space size from memory size.
-	** Using "mem_max" is a kluge.
 	**
 	** Ideally, PCI drivers would register the maximum number
 	** of DMA they can have outstanding for each device they
@@ -1385,20 +1565,24 @@
 	** While we have 32-bits "IOVA" space, top two 2 bits are used
 	** for DMA hints - ergo only 30 bits max.
 	*/
+
+	physmem = num_physpages << PAGE_SHIFT;
+	iova_space_size = (u32) (physmem/(sba_mem_ratio*global_ioc_cnt));
+
 	/* limit IOVA space size to 1MB-1GB */
-	if (mem_max < (sba_mem_ratio*1024*1024)) {
+	if (iova_space_size < 1024*1024) {
 		iova_space_size = 1024*1024;
+	}
 #ifdef __LP64__
-	} else if (mem_max > (sba_mem_ratio*512*1024*1024)) {
+	else if (iova_space_size > 512*1024*1024) {
 		iova_space_size = 512*1024*1024;
-#endif
-	} else {
-		iova_space_size = (u32) (mem_max/sba_mem_ratio);
 	}
+#endif
 
 	/*
 	** iova space must be log2() in size.
 	** thus, pdir/res_map will also be log2().
+	** PIRANHA BUG: Exception is when IO Pdir is 2MB (gets reduced)
 	*/
 	iov_order = get_order(iova_space_size >> (IOVP_SHIFT-PAGE_SHIFT));
 	ASSERT(iov_order <= (30 - IOVP_SHIFT));   /* iova_space_size <= 1GB */
@@ -1407,35 +1591,27 @@
 
 	ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64);
 
-	ASSERT(pdir_size < 4*1024*1024);   /* max pdir size < 4MB */
+	ASSERT(pdir_size < 4*1024*1024);   /* max pdir size == 2MB */
 
 	/* Verify it's a power of two */
 	ASSERT((1 << get_order(pdir_size)) == (pdir_size >> PAGE_SHIFT));
 
-	DBG_INIT("%s() hpa 0x%p mem %dMBIOV %dMB (%d bits) PDIR size 0x%0x",
-		__FUNCTION__, ioc->ioc_hpa, (int) (mem_max>>20),
+	DBG_INIT("%s() hpa 0x%lx mem %dMB IOV %dMB (%d bits) PDIR size 0x%0x\n",
+		__FUNCTION__, ioc->ioc_hpa, (int) (physmem>>20),
 		iova_space_size>>20, iov_order + PAGE_SHIFT, pdir_size);
 
 	/* FIXME : DMA HINTs not used */
 	ioc->hint_shift_pdir = iov_order + PAGE_SHIFT;
 	ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT));
 
-	ioc->pdir_base =
-	pdir_base = (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size));
-	if (NULL == pdir_base)
-	{
-		panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__);
-	}
-	memset(pdir_base, 0, pdir_size);
+	ioc->pdir_base = sba_alloc_pdir(pdir_size);
 
-	DBG_INIT("sba_ioc_init() pdir %p size %x hint_shift_pdir %x hint_mask_pdir %lx\n",
-		pdir_base, pdir_size,
+	DBG_INIT("%s() pdir %p size %x hint_shift_pdir %x hint_mask_pdir %lx\n",
+		__FUNCTION__, ioc->pdir_base, pdir_size,
 		ioc->hint_shift_pdir, ioc->hint_mask_pdir);
 
-	ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base);
-	WRITE_REG64(virt_to_phys(pdir_base), (u64 *)(ioc->ioc_hpa+IOC_PDIR_BASE));
-
-	DBG_INIT(" base %p\n", pdir_base);
+	ASSERT((((unsigned long) ioc->pdir_base) & PAGE_MASK) == (unsigned long) ioc->pdir_base);
+	WRITE_REG64(virt_to_phys(ioc->pdir_base), ioc->ioc_hpa + IOC_PDIR_BASE);
 
 	/* build IMASK for IOC and Elroy */
 	iova_space_mask =  0xffffffff;
@@ -1448,8 +1624,8 @@
 	ioc->ibase = IOC_IOVA_SPACE_BASE | 1;	/* bit 0 == enable bit */
 	ioc->imask = iova_space_mask;	/* save it */
 
-	DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n", __FUNCTION__,
-		ioc->ibase, ioc->imask);
+	DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n",
+		__FUNCTION__, ioc->ibase, ioc->imask);
 
 	/*
 	** FIXME: Hint registers are programmed with default hint
@@ -1460,22 +1636,26 @@
 	/*
 	** setup Elroy IBASE/IMASK registers as well.
 	*/
-	lba_init_iregs(ioc->ioc_hpa, ioc->ibase, ioc->imask);
+	for (lba = sba->child; lba; lba = lba->sibling) {
+		int rope_num = (lba->hpa >> 13) & 0xf;
+		if (rope_num >> 3 == ioc_num)
+			lba_set_iregs(lba, ioc->ibase, ioc->imask);
+	}
 
 	/*
 	** Program the IOC's ibase and enable IOVA translation
 	*/
-	WRITE_REG32(ioc->ibase, ioc->ioc_hpa+IOC_IBASE);
-	WRITE_REG32(ioc->imask, ioc->ioc_hpa+IOC_IMASK);
+	WRITE_REG(ioc->ibase, ioc->ioc_hpa+IOC_IBASE);
+	WRITE_REG(ioc->imask, ioc->ioc_hpa+IOC_IMASK);
 
 	/* Set I/O PDIR Page size to 4K */
-	WRITE_REG32(0, ioc->ioc_hpa+IOC_TCNFG);
+	WRITE_REG(0, ioc->ioc_hpa+IOC_TCNFG);
 
 	/*
 	** Clear I/O TLB of any possible entries.
-	** (Yes. This is a it paranoid...but so what)
+	** (Yes. This is a bit paranoid...but so what)
 	*/
-	WRITE_REG32(0 | 31, ioc->ioc_hpa+IOC_PCOM);
+	WRITE_REG(0 | 31, ioc->ioc_hpa+IOC_PCOM);
 
 	DBG_INIT("%s() DONE\n", __FUNCTION__);
 }
@@ -1498,23 +1678,24 @@
 { 
 	int i;
 	int num_ioc;
-	u32 ioc_ctl;
+	u64 ioc_ctl;
+
+	ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL);
+	DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->",
+		__FUNCTION__, sba_dev->sba_hpa, ioc_ctl);
+	ioc_ctl &= ~(IOC_CTRL_RM | IOC_CTRL_NC | IOC_CTRL_CE);
+	ioc_ctl |= IOC_CTRL_TC;	/* Astro: firmware enables this */
 
-	ioc_ctl = READ_REG32(sba_dev->sba_hpa+IOC_CTRL);
-	DBG_INIT("%s() hpa 0x%p ioc_ctl 0x%x ->", __FUNCTION__, sba_dev->sba_hpa, ioc_ctl );
-	ioc_ctl &= ~(IOC_CTRL_RM | IOC_CTRL_NC);
-	ASSERT(ioc_ctl & IOC_CTRL_TE);	/* astro: firmware enables this */
-
-	WRITE_REG32(ioc_ctl, sba_dev->sba_hpa+IOC_CTRL);
-
-#ifdef SBA_DEBUG_INIT
-	ioc_ctl = READ_REG32(sba_dev->sba_hpa+IOC_CTRL);
-	DBG_INIT(" 0x%x\n", ioc_ctl );
+	WRITE_REG(ioc_ctl, sba_dev->sba_hpa+IOC_CTRL);
+
+#ifdef DEBUG_SBA_INIT
+	ioc_ctl = READ_REG64(sba_dev->sba_hpa+IOC_CTRL);
+	DBG_INIT(" 0x%Lx\n", ioc_ctl);
 #endif
 
 	if (IS_ASTRO(sba_dev->iodc)) {
 		/* PAT_PDC (L-class) also reports the same goofy base */
-		sba_dev->ioc[0].ioc_hpa = (char *) ASTRO_IOC_OFFSET;
+		sba_dev->ioc[0].ioc_hpa = ASTRO_IOC_OFFSET;
 		num_ioc = 1;
 	} else {
 		sba_dev->ioc[0].ioc_hpa = sba_dev->ioc[1].ioc_hpa = 0;
@@ -1522,26 +1703,25 @@
 	}
 
 	sba_dev->num_ioc = num_ioc;
-	for( i = 0; i < num_ioc; i++)
-	{
-		(unsigned long) sba_dev->ioc[i].ioc_hpa += (unsigned long) sba_dev->sba_hpa + IKE_IOC_OFFSET(i);
+	for (i = 0; i < num_ioc; i++) {
+		sba_dev->ioc[i].ioc_hpa += sba_dev->sba_hpa + IKE_IOC_OFFSET(i);
 
 		/*
 		** Make sure the box crashes if we get any errors on a rope.
 		*/
-		WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE0_CTL);
-		WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE1_CTL);
-		WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE2_CTL);
-		WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE3_CTL);
-		WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE4_CTL);
-		WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE5_CTL);
-		WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE6_CTL);
-		WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);
+		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE0_CTL);
+		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE1_CTL);
+		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE2_CTL);
+		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE3_CTL);
+		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE4_CTL);
+		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE5_CTL);
+		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE6_CTL);
+		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);
 
 		/* flush out the writes */
-		READ_REG32(sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);
+		READ_REG(sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);
 
-		sba_ioc_init(&(sba_dev->ioc[i]));
+		sba_ioc_init(sba_dev->dev, &(sba_dev->ioc[i]), i);
 	}
 }
 
@@ -1555,11 +1735,10 @@
 	*/
 	sba_dev->next = sba_list;
 	sba_list = sba_dev;
-	sba_count++;
 
 	for(i=0; i< sba_dev->num_ioc; i++) {
 		int res_size;
-#ifdef CONFIG_DMB_TRAP
+#ifdef DEBUG_DMB_TRAP
 		extern void iterate_pages(unsigned long , unsigned long ,
 					  void (*)(pte_t * , unsigned long),
 					  unsigned long );
@@ -1567,13 +1746,20 @@
 #endif
 		/* resource map size dictated by pdir_size */
 		res_size = sba_dev->ioc[i].pdir_size/sizeof(u64); /* entries */
+
+		/* Second part of PIRANHA BUG */
+		if (piranha_bad_128k) {
+			res_size -= (128*1024)/sizeof(u64);
+		}
+
 		res_size >>= 3;  /* convert bit count to byte count */
-		DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, res_size);
+		DBG_INIT("%s() res_size 0x%x\n",
+			__FUNCTION__, res_size);
 
 		sba_dev->ioc[i].res_size = res_size;
 		sba_dev->ioc[i].res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size));
 
-#ifdef CONFIG_DMB_TRAP
+#ifdef DEBUG_DMB_TRAP
 		iterate_pages( sba_dev->ioc[i].res_map, res_size,
 				set_data_memory_break, 0);
 #endif
@@ -1594,39 +1780,66 @@
 		sba_dev->ioc[i].pdir_base[0] = 0xeeffc0addbba0080ULL;
 #endif
 
-#ifdef CONFIG_DMB_TRAP
+		/* Third (and last) part of PIRANHA BUG */
+		if (piranha_bad_128k) {
+			/* region from +1408K to +1536 is un-usable. */
+
+			int idx_start = (1408*1024/sizeof(u64)) >> 3;
+			int idx_end   = (1536*1024/sizeof(u64)) >> 3;
+			long *p_start = (long *) &(sba_dev->ioc[i].res_map[idx_start]);
+			long *p_end   = (long *) &(sba_dev->ioc[i].res_map[idx_end]);
+
+			/* mark that part of the io pdir busy */
+			while (p_start < p_end)
+				*p_start++ = -1;
+				
+		}
+
+#ifdef DEBUG_DMB_TRAP
 		iterate_pages( sba_dev->ioc[i].res_map, res_size,
 				set_data_memory_break, 0);
 		iterate_pages( sba_dev->ioc[i].pdir_base, sba_dev->ioc[i].pdir_size,
 				set_data_memory_break, 0);
 #endif
 
-		DBG_INIT("sba_common_init() %d res_map %x %p\n",
-					i, res_size, sba_dev->ioc[i].res_map);
+		DBG_INIT("%s() %d res_map %x %p\n",
+			__FUNCTION__, i, res_size, sba_dev->ioc[i].res_map);
 	}
 
 	sba_dev->sba_lock = SPIN_LOCK_UNLOCKED;
+	ioc_needs_fdc = boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC;
+
+#ifdef DEBUG_SBA_INIT
+	/*
+	 * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit set
+	 * (bit #61, big endian), we have to flush and sync every time
+	 * IO-PDIR is changed in Ike/Astro.
+	 */
+	if (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC) {
+		printk(KERN_INFO MODULE_NAME " FDC/SYNC required.\n");
+	} else {
+		printk(KERN_INFO MODULE_NAME " IOC has cache coherent PDIR.\n");
+	}
+#endif
 }
 
 #ifdef CONFIG_PROC_FS
 static int sba_proc_info(char *buf, char **start, off_t offset, int len)
 {
 	struct sba_device *sba_dev = sba_list;
-/* FIXME: Multi-IOC support broken! */
-	struct ioc *ioc = &sba_dev->ioc[0];
+	struct ioc *ioc = &sba_dev->ioc[0];	/* FIXME: Multi-IOC support! */
 	int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */
 	unsigned long i = 0, avg = 0, min, max;
 
 	sprintf(buf, "%s rev %d.%d\n",
-		parisc_getHWdescription(sba_dev->iodc->hw_type,
-			sba_dev->iodc->hversion, sba_dev->iodc->sversion),
+		sba_dev->name,
 		(sba_dev->hw_rev & 0x7) + 1,
 		(sba_dev->hw_rev & 0x18) >> 3
 		);
 	sprintf(buf, "%sIO PDIR size    : %d bytes (%d entries)\n",
 		buf,
-		((ioc->res_size << 3) * sizeof(u64)), /* 8 bits per byte */
-		total_pages);                  /* 8 bits per byte */
+		(int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */
+		total_pages);
 
 	sprintf(buf, "%sIO PDIR entries : %ld free  %ld used (%d%%)\n", buf,
 		total_pages - ioc->used_pages, ioc->used_pages,
@@ -1645,46 +1858,72 @@
 	sprintf(buf, "%s  Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
 		buf, min, avg, max);
 
-	sprintf(buf, "%spci_map_single(): %8ld calls  %8ld pages (avg %d/1000)\n",
+	sprintf(buf, "%spci_map_single(): %12ld calls  %12ld pages (avg %d/1000)\n",
 		buf, ioc->msingle_calls, ioc->msingle_pages,
 		(int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls));
 
 	/* KLUGE - unmap_sg calls unmap_single for each mapped page */
-	min = ioc->usingle_calls - ioc->usg_calls;
+	min = ioc->usingle_calls;
 	max = ioc->usingle_pages - ioc->usg_pages;
-	sprintf(buf, "%spci_unmap_single: %8ld calls  %8ld pages (avg %d/1000)\n",
+	sprintf(buf, "%spci_unmap_single: %12ld calls  %12ld pages (avg %d/1000)\n",
 		buf, min, max,
 		(int) ((max * 1000)/min));
 
-	sprintf(buf, "%spci_map_sg()    : %8ld calls  %8ld pages (avg %d/1000)\n",
+	sprintf(buf, "%spci_map_sg()    : %12ld calls  %12ld pages (avg %d/1000)\n",
 		buf, ioc->msg_calls, ioc->msg_pages,
 		(int) ((ioc->msg_pages * 1000)/ioc->msg_calls));
 
-	sprintf(buf, "%spci_unmap_sg()  : %8ld calls  %8ld pages (avg %d/1000)\n",
+	sprintf(buf, "%spci_unmap_sg()  : %12ld calls  %12ld pages (avg %d/1000)\n",
 		buf, ioc->usg_calls, ioc->usg_pages,
 		(int) ((ioc->usg_pages * 1000)/ioc->usg_calls));
 
 	return strlen(buf);
 }
 
+#if 0
+/* XXX too much output - exceeds 4k limit and needs to be re-written */
 static int
 sba_resource_map(char *buf, char **start, off_t offset, int len)
 {
 	struct sba_device *sba_dev = sba_list;
-	struct ioc *ioc = &sba_dev->ioc[0];
-	unsigned long *res_ptr = (unsigned long *)ioc->res_map;
+	struct ioc *ioc = &sba_dev->ioc[0];	/* FIXME: Mutli-IOC suppoer! */
+	unsigned int *res_ptr = (unsigned int *)ioc->res_map;
 	int i;
 
-	for(i = 0; i < (ioc->res_size / sizeof(unsigned long)); ++i, ++res_ptr) {
+	buf[0] = '\0';
+	for(i = 0; i < (ioc->res_size / sizeof(unsigned int)); ++i, ++res_ptr) {
 		if ((i & 7) == 0)
 		    strcat(buf,"\n   ");
-		sprintf(buf, "%s %08lx", buf, *res_ptr);
+		sprintf(buf, "%s %08x", buf, *res_ptr);
 	}
 	strcat(buf, "\n");
 
 	return strlen(buf);
 }
-#endif
+#endif /* 0 */
+#endif /* CONFIG_PROC_FS */
+
+static struct parisc_device_id sba_tbl[] = {
+	{ HPHW_IOA, HVERSION_REV_ANY_ID, ASTRO_RUNWAY_PORT, 0xb },
+	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, IKE_MERCED_PORT, 0xc },
+	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, REO_MERCED_PORT, 0xc },
+	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, REOG_MERCED_PORT, 0xc },
+/* These two entries commented out because we don't find them in a
+ * buswalk yet.  If/when we do, they would cause us to think we had
+ * many more SBAs then we really do.
+ *	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, ASTRO_ROPES_PORT, 0xc },
+ *	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, IKE_ROPES_PORT, 0xc },
+ */
+	{ 0, }
+};
+
+int sba_driver_callback(struct parisc_device *);
+
+static struct parisc_driver sba_driver = {
+	name:		MODULE_NAME,
+	id_table:	sba_tbl,
+	probe:		sba_driver_callback,
+};
 
 /*
 ** Determine if lba should claim this chip (return 0) or not (return 1).
@@ -1692,47 +1931,75 @@
 ** have work to do.
 */
 int
-sba_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+sba_driver_callback(struct parisc_device *dev)
 {
 	struct sba_device *sba_dev;
 	u32 func_class;
 	int i;
+	char *version;
 
-	if (IS_ASTRO(d)) {
+#ifdef DEBUG_SBA_INIT
+	sba_dump_ranges(dev->hpa);
+#endif
+
+	/* Read HW Rev First */
+	func_class = READ_REG(dev->hpa + SBA_FCLASS);
+
+	if (IS_ASTRO(&dev->id)) {
+		unsigned long fclass;
 		static char astro_rev[]="Astro ?.?";
 
-		/* Read HW Rev First */
-		func_class = READ_REG32(d->hpa);
+		/* Astro is broken...Read HW Rev First */
+		fclass = READ_REG(dev->hpa);
 
-		astro_rev[6] = '1' + (char) (func_class & 0x7);
-		astro_rev[8] = '0' + (char) ((func_class & 0x18) >> 3);
-		dri->version = astro_rev;
-	} else {
-		static char ike_rev[]="Ike rev ?";
+		astro_rev[6] = '1' + (char) (fclass & 0x7);
+		astro_rev[8] = '0' + (char) ((fclass & 0x18) >> 3);
+		version = astro_rev;
 
-		/* Read HW Rev First */
-		func_class = READ_REG32(d->hpa + SBA_FCLASS);
+	} else if (IS_IKE(&dev->id)) {
+		static char ike_rev[]="Ike rev ?";
 
 		ike_rev[8] = '0' + (char) (func_class & 0xff);
-		dri->version = ike_rev;
+		version = ike_rev;
+	} else {
+		static char reo_rev[]="REO rev ?";
+
+		reo_rev[8] = '0' + (char) (func_class & 0xff);
+		version = reo_rev;
+	}
+
+	if (!global_ioc_cnt) {
+		global_ioc_cnt = count_parisc_driver(&sba_driver);
+
+		/* Only Astro has one IOC per SBA */
+		if (!IS_ASTRO(&dev->id))
+			global_ioc_cnt *= 2;
 	}
 
-	printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa);
+	printk(KERN_INFO "%s found %s at 0x%lx\n",
+		MODULE_NAME, version, dev->hpa);
+
+#ifdef DEBUG_SBA_INIT
+	sba_dump_tlb(dev->hpa);
+#endif
 
 	sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL);
-	if (NULL == sba_dev)
-	{
-		printk(MODULE_NAME " - couldn't alloc sba_device\n");
+	if (NULL == sba_dev) {
+		printk(KERN_ERR MODULE_NAME " - couldn't alloc sba_device\n");
 		return(1);
 	}
+
+	dev->sysdata = (void *) sba_dev;
 	memset(sba_dev, 0, sizeof(struct sba_device));
+
 	for(i=0; i<MAX_IOC; i++)
 		spin_lock_init(&(sba_dev->ioc[i].res_lock));
 
-
+	sba_dev->dev = dev;
 	sba_dev->hw_rev = func_class;
-	sba_dev->iodc = d;
-	sba_dev->sba_hpa = d->hpa;  /* faster access */
+	sba_dev->iodc = &dev->id;
+	sba_dev->name = dev->name;
+	sba_dev->sba_hpa = dev->hpa;  /* faster access */
 
 	sba_get_pat_resources(sba_dev);
 	sba_hw_init(sba_dev);
@@ -1741,12 +2008,46 @@
 	hppa_dma_ops = &sba_ops;
 
 #ifdef CONFIG_PROC_FS
-	if (IS_ASTRO(d)) {
+	if (IS_ASTRO(&dev->id)) {
 		create_proc_info_entry("Astro", 0, proc_runway_root, sba_proc_info);
-	} else {
+	} else if (IS_IKE(&dev->id)) {
 		create_proc_info_entry("Ike", 0, proc_runway_root, sba_proc_info);
+	} else {
+		create_proc_info_entry("Reo", 0, proc_runway_root, sba_proc_info);
 	}
+#if 0
 	create_proc_info_entry("bitmap", 0, proc_runway_root, sba_resource_map);
 #endif
+#endif
 	return 0;
 }
+
+/*
+** One time initialization to let the world know the SBA was found.
+** This is the only routine which is NOT static.
+** Must be called exactly once before pci_init().
+*/
+void __init sba_init(void)
+{
+	register_parisc_driver(&sba_driver);
+}
+
+
+/**
+ * sba_get_iommu - Assign the iommu pointer for the pci bus controller.
+ * @dev: The parisc device.
+ *
+ * This function searches through the registerd IOMMU's and returns the
+ * appropriate IOMMU data for the given parisc PCI controller.
+ */
+void * sba_get_iommu(struct parisc_device *pci_hba)
+{
+	struct sba_device *sba = (struct sba_device *) pci_hba->parent->sysdata;
+	char t = pci_hba->parent->id.hw_type;
+	int iocnum = (pci_hba->hw_path >> 3);	/* rope # */
+
+	if ((t!=HPHW_IOA) && (t!=HPHW_BCPORT))
+		BUG();
+
+	return &(sba->ioc[iocnum]);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/semaphore.c linux-2.4.20/arch/parisc/kernel/semaphore.c
--- linux-2.4.19/arch/parisc/kernel/semaphore.c	2001-04-18 00:19:25.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/semaphore.c	2002-10-29 11:18:49.000000000 +0000
@@ -1,131 +1,100 @@
 /*
- * Just taken from alpha implementation.
- * This can't work well, perhaps.
- */
-/*
- *  Generic semaphore code. Buyer beware. Do your own
- * specific changes in <asm/semaphore-helper.h>
+ * Semaphore implementation Copyright (c) 2001 Matthew Wilcox, Hewlett-Packard
  */
 
 #include <linux/sched.h>
-#include <asm/semaphore-helper.h>
+#include <linux/spinlock.h>
 
 /*
- * Semaphores are implemented using a two-way counter:
- * The "count" variable is decremented for each process
- * that tries to sleep, while the "waking" variable is
- * incremented when the "up()" code goes to wake up waiting
- * processes.
- *
- * Notably, the inline "up()" and "down()" functions can
- * efficiently test if they need to do any extra work (up
- * needs to do something only if count was negative before
- * the increment operation.
- *
- * waking_non_zero() (from asm/semaphore.h) must execute
- * atomically.
- *
- * When __up() is called, the count was negative before
- * incrementing it, and we need to wake up somebody.
- *
- * This routine adds one to the count of processes that need to
- * wake up and exit.  ALL waiting processes actually wake up but
- * only the one that gets to the "waking" field first will gate
- * through and acquire the semaphore.  The others will go back
- * to sleep.
- *
- * Note that these functions are only called when there is
- * contention on the lock, and as such all this is the
- * "non-critical" part of the whole semaphore business. The
- * critical part is the inline stuff in <asm/semaphore.h>
- * where we want to avoid any extra jumps and calls.
+ * Semaphores are complex as we wish to avoid using two variables.
+ * `count' has multiple roles, depending on its value.  If it is positive
+ * or zero, there are no waiters.  The functions here will never be
+ * called; see <asm/semaphore.h>
+ *
+ * When count is -1 it indicates there is at least one task waiting
+ * for the semaphore.
+ *
+ * When count is less than that, there are '- count - 1' wakeups
+ * pending.  ie if it has value -3, there are 2 wakeups pending.
+ *
+ * Note that these functions are only called when there is contention
+ * on the lock, and as such all this is the "non-critical" part of the
+ * whole semaphore business. The critical part is the inline stuff in
+ * <asm/semaphore.h> where we want to avoid any extra jumps and calls.
  */
 void __up(struct semaphore *sem)
 {
-	wake_one_more(sem);
+	sem->count--;
 	wake_up(&sem->wait);
 }
 
-/*
- * Perform the "down" function.  Return zero for semaphore acquired,
- * return negative for signalled out of the function.
- *
- * If called from __down, the return is ignored and the wait loop is
- * not interruptible.  This means that a task waiting on a semaphore
- * using "down()" cannot be killed until someone does an "up()" on
- * the semaphore.
- *
- * If called from __down_interruptible, the return value gets checked
- * upon return.  If the return value is negative then the task continues
- * with the negative value in the return register (it can be tested by
- * the caller).
- *
- * Either form may be used in conjunction with "up()".
- *
- */
-
+#define wakers(count) (-1 - count)
 
-#define DOWN_HEAD(task_state)						\
+#define DOWN_HEAD							\
+	int ret = 0;							\
+	DECLARE_WAITQUEUE(wait, current);				\
 									\
+	/* Note that someone is waiting */				\
+	if (sem->count == 0)						\
+		sem->count = -1;					\
 									\
-	current->state = (task_state);					\
-	add_wait_queue(&sem->wait, &wait);				\
-									\
-	/*								\
-	 * Ok, we're set up.  sem->count is known to be less than zero	\
-	 * so we must wait.						\
-	 *								\
-	 * We can let go the lock for purposes of waiting.		\
-	 * We re-acquire it after awaking so as to protect		\
-	 * all semaphore operations.					\
-	 *								\
-	 * If "up()" is called before we call waking_non_zero() then	\
-	 * we will catch it right away.  If it is called later then	\
-	 * we will have to go through a wakeup cycle to catch it.	\
-	 *								\
-	 * Multiple waiters contend for the semaphore lock to see	\
-	 * who gets to gate through and who has to wait some more.	\
-	 */								\
-	for (;;) {
-
-#define DOWN_TAIL(task_state)			\
-		current->state = (task_state);	\
-	}					\
-	current->state = TASK_RUNNING;		\
-	remove_wait_queue(&sem->wait, &wait);
+	/* protected by the sentry still -- use unlocked version */	\
+	wait.flags = WQ_FLAG_EXCLUSIVE;					\
+	__add_wait_queue_tail(&sem->wait, &wait);			\
+ lost_race:								\
+	spin_unlock_irq(&sem->sentry);					\
+
+#define DOWN_TAIL							\
+	spin_lock_irq(&sem->sentry);					\
+	if (wakers(sem->count) == 0 && ret == 0)			\
+		goto lost_race;	/* Someone stole our wakeup */		\
+	__remove_wait_queue(&sem->wait, &wait);				\
+	current->state = TASK_RUNNING;					\
+	if (!waitqueue_active(&sem->wait) && (sem->count < 0))		\
+		sem->count = wakers(sem->count);
+
+#define UPDATE_COUNT							\
+	sem->count += (sem->count < 0) ? 1 : - 1;
+	
 
 void __down(struct semaphore * sem)
 {
-	DECLARE_WAITQUEUE(wait, current);
+	DOWN_HEAD
+
+	for(;;) {
+		set_task_state(current, TASK_UNINTERRUPTIBLE);
+		/* we can _read_ this without the sentry */
+		if (sem->count != -1)
+			break;
+ 		schedule();
+ 	}
 
-	DOWN_HEAD(TASK_UNINTERRUPTIBLE)
-	if (waking_non_zero(sem))
-		break;
-	schedule();
-	DOWN_TAIL(TASK_UNINTERRUPTIBLE)
+	DOWN_TAIL
+	UPDATE_COUNT
 }
 
 int __down_interruptible(struct semaphore * sem)
 {
-	DECLARE_WAITQUEUE(wait, current);
-	int ret = 0;
+	DOWN_HEAD
 
-	DOWN_HEAD(TASK_INTERRUPTIBLE)
+	for(;;) {
+		set_task_state(current, TASK_INTERRUPTIBLE);
+		/* we can _read_ this without the sentry */
+		if (sem->count != -1)
+			break;
+
+		if (signal_pending(current)) {
+			ret = -EINTR;
+			break;
+		}
+		schedule();
+	}
 
-	ret = waking_non_zero_interruptible(sem, current);
-	if (ret)
-	{
-		if (ret == 1)
-			/* ret != 0 only if we get interrupted -arca */
-			ret = 0;
-		break;
+	DOWN_TAIL
+
+	if (!ret) {
+		UPDATE_COUNT
 	}
-	schedule();
-	DOWN_TAIL(TASK_INTERRUPTIBLE)
-	return ret;
-}
 
-int __down_trylock(struct semaphore * sem)
-{
-	return waking_non_zero_trylock(sem);
+	return ret;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/setup.c linux-2.4.20/arch/parisc/kernel/setup.c
--- linux-2.4.19/arch/parisc/kernel/setup.c	2001-02-09 19:29:44.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/setup.c	2002-10-29 11:18:50.000000000 +0000
@@ -1,12 +1,13 @@
 /*    $Id: setup.c,v 1.8 2000/02/02 04:42:38 prumpf Exp $
  *
  *    Initial setup-routines for HP 9000 based hardware.
- * 
+ *
  *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *    Modifications for PA-RISC (C) 1999 Helge Deller <helge.deller@ruhr-uni-bochum.de>
+ *    Modifications for PA-RISC (C) 1999 Helge Deller <deller@gmx.de>
  *    Modifications copyright 1999 SuSE GmbH (Philipp Rumpf)
  *    Modifications copyright 2000 Martin K. Petersen <mkp@mkp.net>
  *    Modifications copyright 2000 Philipp Rumpf <prumpf@tux.org>
+ *    Modifications copyright 2001 Ryan Bradetich <rbradetich@uswest.net>
  *
  *    Initial PA-RISC Version: 04-23-1999 by Helge Deller
  *
@@ -19,596 +20,308 @@
  *    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., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  */
 
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/ptrace.h>
-#include <linux/sched.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/user.h>
-#include <linux/tty.h>
 #include <linux/config.h>
-#include <linux/fs.h>
-#include <linux/kdev_t.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/blk.h>
+#include <linux/kernel.h>
+#include <linux/blk.h>          /* for initrd_start and initrd_end */
 #include <linux/init.h>
-#include <linux/interrupt.h>
 #include <linux/console.h>
-#include <linux/bootmem.h>
-#include <linux/delay.h>
+#include <linux/seq_file.h>
+#define PCI_DEBUG
 #include <linux/pci.h>
-#include <linux/threads.h>
+#undef PCI_DEBUG
+#include <linux/proc_fs.h>
 
-#include <asm/cache.h>
-#include <asm/hardware.h>	/* for register_driver() stuff */
 #include <asm/processor.h>
-#include <asm/page.h>
 #include <asm/pdc.h>
 #include <asm/led.h>
-#include <asm/real.h>
-#include <asm/system.h>
 #include <asm/machdep.h>	/* for pa7300lc_init() proto */
 
-#include <asm/irq.h>		/* for struct irq_region */
-#include <asm/pdcpat.h>		/* for PA_VIEW PDC_PAT_CPU_GET_NUMBER etc */
-
-#include <linux/proc_fs.h>
-
 #define COMMAND_LINE_SIZE 1024
 char	saved_command_line[COMMAND_LINE_SIZE];
+char	command_line[COMMAND_LINE_SIZE];
 
-/*
-** KLUGE ALERT!
-**
-** We *really* should be using a combination of request_resource()
-** and request_region()! But request_region() requires kmalloc since
-** returns a new struct resource. And kmalloc just isn't available
-** until after mem_init() is called from start_kernel().
-**
-** FIXME: assume contiguous memory initially.
-**     Additional chunks of memory might be added to sysram_resource.sibling.
-*/
-static struct resource sysrom_resource  = {
-	name: "System ROM", start: 0x0f0000000UL, end: 0x0f00fffffUL,
-	flags: IORESOURCE_BUSY | IORESOURCE_MEM,
-	parent: &iomem_resource, sibling: NULL, child: NULL };
-
-static struct resource pdcdata_resource;
-
-static struct resource sysram_resource  = {
-	name: "System RAM", start: 0UL, end: ~0UL /* bogus */,
-	flags: IORESOURCE_MEM,
-	parent: &iomem_resource, sibling: &sysrom_resource, child: &pdcdata_resource};
-
-extern char _text;	/* start of kernel code, defined by linker */
-extern int  data_start; 
-extern char _edata;	/* end of data, begin BSS, defined by linker */
-extern char _end;	/* end of BSS, defined by linker */
-
-static struct resource data_resource    = {
-	name: "kernel Data", start: virt_to_phys(&data_start), end: virt_to_phys(&_end)-1,
-	flags: IORESOURCE_BUSY | IORESOURCE_MEM,
-	parent: &sysram_resource, sibling: NULL, child: NULL};
-
-static struct resource code_resource = {
-	name: "Kernel Code", start: virt_to_phys(&_text), end: virt_to_phys(&data_start)-1,
-	flags: IORESOURCE_BUSY | IORESOURCE_MEM,
-	parent: &sysram_resource, sibling: &data_resource, child: NULL};
-
-static struct resource pdcdata_resource = {
-	name: "PDC data (Page Zero)", start: 0, end: 0x9ff,
-	flags: IORESOURCE_BUSY | IORESOURCE_MEM,
-	parent: &sysram_resource, sibling: &code_resource, child: NULL};
-
-
+/* Intended for ccio/sba/cpu statistics under /proc/bus/{runway|gsc} */
+struct proc_dir_entry * proc_runway_root = NULL;
+struct proc_dir_entry * proc_gsc_root = NULL;
 
+#ifdef CONFIG_EISA
+int EISA_bus;	/* This has to go somewhere in architecture specific code. */
+#endif
 
-struct system_cpuinfo_parisc boot_cpu_data;
-struct cpuinfo_parisc cpu_data[NR_CPUS];
-
-extern void do_inventory(void);
-extern void cache_init(void);
-extern struct hp_device * register_module(void *hpa);
-
-static int cpu_driver_callback(struct hp_device *, struct pa_iodc_driver *);
-
-static struct pa_iodc_driver cpu_drivers_for[] = {
-	{HPHW_NPROC, 0x0, 0x0, 0x0, 0, 0,
-		DRIVER_CHECK_HWTYPE,
-		"CPU", "PARISC", (void *) cpu_driver_callback},
-	{0,0,0,0,0,0,
-		0,
-		(char *) NULL, (char *) NULL, (void *) NULL }
-};
+void __init setup_cmdline(char **cmdline_p)
+{
+	extern unsigned int boot_args[];
 
-static long fallback_cpu_hpa[] = { 0xfffa0000L, 0xfffbe000L, 0x0 };
+	/* Collect stuff passed in from the boot loader */
 
+	/* boot_args[0] is free-mem start, boot_args[1] is ptr to command line */
+	if (boot_args[0] < 64) {
+		/* called from hpux boot loader */
+		saved_command_line[0] = '\0';
+	} else {
+		strcpy(saved_command_line, (char *)__va(boot_args[1]));
 
-/*
-**  	PARISC CPU driver - claim "device" and initialize CPU data structures.
-**
-** Consolidate per CPU initialization into (mostly) one module.
-** Monarch CPU will initialize boot_cpu_data which shouldn't
-** change once the system has booted.
-**
-** The callback *should* do per-instance initialization of
-** everything including the monarch. Some of the code that's
-** in setup.c:start_parisc() should migrate here and start_parisc()
-** should "register_driver(cpu_driver_for)" before calling
-** do_inventory().
-**
-** The goal of consolidating CPU initialization into one place is
-** to make sure all CPU's get initialized the same way.
-** It would be nice if the even the manarch through the exact same code path.
-** (up to rendevous at least).
-*/
-#undef ASSERT
-#define ASSERT(expr) \
-	if(!(expr)) { \
-		printk( "\n" __FILE__ ":%d: Assertion " #expr " failed!\n",__LINE__); \
-		panic(#expr); \
+#ifdef CONFIG_BLK_DEV_INITRD
+		if (boot_args[2] != 0) /* did palo pass us a ramdisk? */
+		{
+		    initrd_start = (unsigned long)__va(boot_args[2]);
+		    initrd_end = (unsigned long)__va(boot_args[3]);
+		}
+#endif
 	}
 
-static int
-cpu_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+	strcpy(command_line, saved_command_line);
+	*cmdline_p = command_line;
+}
+
+#ifdef CONFIG_PA11
+void __init dma_ops_init(void)
 {
-#ifdef __LP64__
-	extern int pdc_pat;	/* arch/parisc/kernel/inventory.c */
-	static unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0};
-#endif
-	struct cpuinfo_parisc *p;
+	switch (boot_cpu_data.cpu_type) {
+	case pcx:
+		/*
+		 * We've got way too many dependencies on 1.1 semantics
+		 * to support 1.0 boxes at this point.
+		 */
+		panic(	"PA-RISC Linux currently only supports machines that conform to\n"
+			"the PA-RISC 1.1 or 2.0 architecture specification.\n");
 
-#ifndef CONFIG_SMP
-	if (boot_cpu_data.cpu_count > 0) {
-		printk(KERN_INFO "CONFIG_SMP disabled - not claiming addional CPUs\n");
-		return(1);
+	case pcxs:
+	case pcxt:
+		hppa_dma_ops = &pcx_dma_ops;
+		break;
+	case pcxl2:
+		pa7300lc_init();
+	case pcxl: /* falls through */
+		hppa_dma_ops = &pcxl_dma_ops;
+		break;
+	default:
+		break;
 	}
+}
 #endif
 
-	p = &cpu_data[boot_cpu_data.cpu_count];
-	boot_cpu_data.cpu_count++;
-
-/* TODO: Enable FP regs - done early in start_parisc() now */
-
-	/* initialize counters */
-	memset(p, 0, sizeof(struct cpuinfo_parisc));
+extern int init_per_cpu(int cpuid);
+extern void collect_boot_cpu_data(void);
 
-	p->hpa = (unsigned long) d->hpa; /* save CPU hpa */
+void __init setup_arch(char **cmdline_p)
+{
+	init_per_cpu(smp_processor_id());	/* Set Modes & Enable FP */
 
 #ifdef __LP64__
-	if (pdc_pat) {
-		ulong status;
-	        pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;
-
-		status = pdc_pat_cell_module(& pdc_result, d->pcell_loc,
-			d->mod_index, PA_VIEW, & pa_pdc_cell);
-
-		ASSERT(PDC_RET_OK == status);
-
-		/* verify it's the same as what do_pat_inventory() found */
-		ASSERT(d->mod_info == pa_pdc_cell.mod_info);
-		ASSERT(d->pmod_loc == pa_pdc_cell.mod_location);
-		ASSERT(d->mod_path == pa_pdc_cell.mod_path);
-
-		p->txn_addr = pa_pdc_cell.mod[0];   /* id_eid for IO sapic */
-
-		/* get the cpu number */
-		status = mem_pdc_call( PDC_PAT_CPU, PDC_PAT_CPU_GET_NUMBER,
-				__pa(& pdc_result), d->hpa);
+	printk(KERN_INFO "The 64-bit Kernel has started...\n");
+#else
+	printk(KERN_INFO "The 32-bit Kernel has started...\n");
+#endif
 
-		ASSERT(PDC_RET_OK == status);
+	pdc_console_init();
 
-		p->cpuid = pdc_result[0];
+#ifdef CONFIG_PDC_NARROW
+	printk(KERN_INFO "Kernel is using PDC in 32-bit mode.\n");
+#endif
+	setup_pdc();
+	setup_cmdline(cmdline_p);
+	collect_boot_cpu_data();
+	do_memory_inventory();  /* probe for physical memory */
+	cache_init();
+	paging_init();
 
-	} else
+#ifdef CONFIG_CHASSIS_LCD_LED
+	/* initialize the LCD/LED after boot_cpu_data is available ! */
+        led_init();				/* LCD/LED initialization */
 #endif
-	{
-		p->txn_addr = (unsigned long) d->hpa;	/* for normal parisc */
 
-		/* logical CPU ID and update global counter */
-		p->cpuid = boot_cpu_data.cpu_count - 1;
-	}
+#ifdef CONFIG_PA11
+	dma_ops_init();
+#endif
 
-	/*
-	** itimer and ipi IRQ handlers are statically initialized in
-	** arch/parisc/kernel/irq.c
-	*/
-	p->region = irq_region[IRQ_FROM_REGION(CPU_IRQ_REGION)];
+#ifdef CONFIG_VT
+# if defined(CONFIG_STI_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
+        conswitchp = &dummy_con;        /* we use take_over_console() later ! */
+# endif
+#endif
 
-	return(0);
 }
 
+/*
+ * Display cpu info for all cpu's.
+ * for parisc this is in processor.c
+ */
+extern int show_cpuinfo (struct seq_file *m, void *v);
 
-void __xchg_called_with_bad_pointer(void)
+static void *
+c_start (struct seq_file *m, loff_t *pos)
 {
-    printk(KERN_EMERG "xchg() called with bad pointer !\n");
+    	/* Looks like the caller will call repeatedly until we return
+	 * 0, signaling EOF perhaps.  This could be used to sequence
+	 * through CPUs for example.  Since we print all cpu info in our
+	 * show_cpuinfo() disregarding 'pos' (which I assume is 'v' above)
+	 * we only allow for one "position".  */
+	return ((long)*pos < 1) ? (void *)1 : NULL;
 }
 
-
-/* Some versions of IODC don't list the CPU, and since we don't walk
- * the bus yet, we have to probe for processors at well known hpa
- * addresses.  
- */
-
-void __init register_fallback_cpu (void)
+static void *
+c_next (struct seq_file *m, void *v, loff_t *pos)
 {
-	struct hp_device *d = NULL;
-	int i = 0;
-	
-#ifdef CONFIG_SMP
-#error "Revisit CPU fallback addresses for SMP (Assuming bus walk hasn't been implemented)"
-#endif
-	printk ("No CPUs reported by firmware - probing...\n");
-	
-	while (fallback_cpu_hpa[i]) {
-		
-		d = register_module ((void *) fallback_cpu_hpa[i]);
-		
-		if (d > 0) {
-			printk ("Found CPU at %lx\n", fallback_cpu_hpa[i]);
-			cpu_driver_callback (d, 0);
-			return;
-		}
-		
-		i++;
-	}
-	
-	panic ("No CPUs found.  System halted.\n");
-	return;
+	++*pos;
+	return c_start(m, pos);
 }
 
-
-/*
- * Get CPU information and store it in the boot_cpu_data structure.  */
-void __init collect_boot_cpu_data(void)
+static void
+c_stop (struct seq_file *m, void *v)
 {
-	memset(&boot_cpu_data,0,sizeof(boot_cpu_data));
-
-	boot_cpu_data.cpu_hz = 100 * PAGE0->mem_10msec; /* Hz of this PARISC */
-
-	/* get CPU-Model Information... */
-#define p ((unsigned long *)&boot_cpu_data.pdc.model)
-	if(pdc_model_info(&boot_cpu_data.pdc.model)==0)
-		printk("model	%08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-			p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]);
-#undef p
-
-	if(pdc_model_versions(&boot_cpu_data.pdc.versions, 0)==0)
-		printk("vers	%08lx\n", boot_cpu_data.pdc.versions.cpuid);
-
-	if(pdc_model_cpuid(&boot_cpu_data.pdc.cpuid)==0)
-		printk("cpuid	%08lx\n", boot_cpu_data.pdc.cpuid.cpuid);
-	
-	printk("CPUID	vers %ld rev %ld\n",
-		(boot_cpu_data.pdc.cpuid.cpuid >> 5) & 127,
-		boot_cpu_data.pdc.cpuid.cpuid & 31);
-
-	if (pdc_model_sysmodel(boot_cpu_data.pdc.sys_model_name)==0)
-		printk("model	%s\n",boot_cpu_data.pdc.sys_model_name);
-
-	boot_cpu_data.model_name = parisc_getHWdescription(HPHW_NPROC,
-		boot_cpu_data.pdc.model.hversion>>4,
-		boot_cpu_data.pdc.model.sversion>>8);
-	
-	boot_cpu_data.hversion =  boot_cpu_data.pdc.model.hversion;
-	boot_cpu_data.sversion =  boot_cpu_data.pdc.model.sversion;
-
-	boot_cpu_data.cpu_type =
-			parisc_get_cpu_type(boot_cpu_data.pdc.model.hversion);
-
-	boot_cpu_data.cpu_name = cpu_name_version[boot_cpu_data.cpu_type][0];
-	boot_cpu_data.family_name = cpu_name_version[boot_cpu_data.cpu_type][1];
 }
 
+struct seq_operations cpuinfo_op = {
+	start:	c_start,
+	next:	c_next,
+	stop:	c_stop,
+	show:	show_cpuinfo
+};
 
-#ifdef __LP64__
-#define COMMAND_GLOBAL  0xfffffffffffe0030UL
-#else
-#define COMMAND_GLOBAL  0xfffe0030
-#endif
-
-#define CMD_RESET       5       /* reset any module */
-
-/*
-** The Wright Brothers and Gecko systems have a H/W problem
-** (Lasi...'nuf said) may cause a broadcast reset to lockup
-** the system. An HVERSION dependent PDC call was developed
-** to perform a "safe", platform specific broadcast reset instead
-** of kludging up all the code.
-**
-** Older machines which do not implement PDC_BROADCAST_RESET will
-** return (with an error) and the regular broadcast reset can be
-** issued. Obviously, if the PDC does implement PDC_BROADCAST_RESET
-** the PDC call will not return (the system will be reset).
-*/
-static int
-reset_parisc(struct notifier_block *self, unsigned long command, void *ptr)
+static void parisc_proc_mkdir(void)
 {
-	printk("%s: %s(cmd=%lu)\n", __FILE__, __FUNCTION__, command);
-
-	switch(command) {
-	case MACH_RESTART:
-#ifdef FASTBOOT_SELFTEST_SUPPORT
-		/*
-		** If user has modified the Firmware Selftest Bitmap,
-		** run the tests specified in the bitmap after the
-		** system is rebooted w/PDC_DO_RESET.
-		**
-		** ftc_bitmap = 0x1AUL "Skip destructive memory tests"
-		**
-		** Using "directed resets" at each processor with the MEM_TOC
-		** vector cleared will also avoid running destructive
-		** memory self tests. (Not implemented yet)
-		*/
-		if (ftc_bitmap) {
-			mem_pdc_call( PDC_BROADCAST_RESET,
-				PDC_DO_FIRM_TEST_RESET, PDC_FIRM_TEST_MAGIC,
-				ftc_bitmap);
+	/*
+	** Can't call proc_mkdir() until after proc_root_init() has been
+	** called by start_kernel(). In other words, this code can't
+	** live in arch/.../setup.c because start_parisc() calls
+	** start_kernel().
+	*/
+	switch (boot_cpu_data.cpu_type) {
+	case pcxl:
+	case pcxl2:
+		if (NULL == proc_gsc_root)
+		{
+			proc_gsc_root = proc_mkdir("bus/gsc", 0);
 		}
-#endif
-
-		/* "Normal" system reset */
-		(void) mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_RESET,
-			0L, 0L, 0L);
-
-		/* Nope...box should reset with just CMD_RESET now */
-		gsc_writel(CMD_RESET, COMMAND_GLOBAL);
-
-		/* Wait for RESET to lay us to rest. */
-		while (1) ;
-
 		break;
+        case pcxt_:
+        case pcxu:
+        case pcxu_:
+        case pcxw:
+        case pcxw_:
+        case pcxw2:
+                if (NULL == proc_runway_root)
+                {
+                        proc_runway_root = proc_mkdir("bus/runway", 0);
+                }
+                break;
 	}
-	return NOTIFY_DONE;
 }
 
-static struct notifier_block parisc_block = { reset_parisc, NULL, 0 };
+static struct resource central_bus = {
+	name:	"Central Bus",
+	start:	(unsigned long)0xfffffffffff80000,
+	end:    (unsigned long)0xfffffffffffaffff,
+	flags:	IORESOURCE_MEM,
+};
 
+static struct resource local_broadcast = {
+	name:	"Local Broadcast",
+	start:	(unsigned long)0xfffffffffffb0000,
+	end:	(unsigned long)0xfffffffffffdffff,
+	flags:	IORESOURCE_MEM,
+};
 
-/*  start_parisc() will be called from head.S to setup our new memory_start 
-    and actually start our kernel !
-    Memory-Layout is:
-	- Kernel-Image (code+data+BSS)
-	- Stack (stack-size see below!, stack-setup-code is in head.S)
-	- memory_start at end of stack..
-*/
-
-unsigned long mem_start, mem_max;
-unsigned long start_pfn, max_pfn;
-extern asmlinkage void __init start_kernel(void);
-
-#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
-#define PFN_PHYS(x)	((x) << PAGE_SHIFT)
+static struct resource global_broadcast = {
+	name:	"Global Broadcast",
+	start:	(unsigned long)0xfffffffffffe0000,
+	end:	(unsigned long)0xffffffffffffffff,
+	flags:	IORESOURCE_MEM,
+};
 
-void __init start_parisc(unsigned arg0, unsigned arg1,
-			 unsigned arg2, unsigned arg3)
+int __init parisc_init_resources(void)
 {
-	register unsigned long ccr;
-	unsigned long memory_start;
-
-	/* Clear BSS */
+	int result;
 
-	{
-		char *p = &_edata, *q = &_end;
-
-		while (p < q) {
-			*p++ = 0;
-		}
+	result = request_resource(&iomem_resource, &central_bus);
+	if (result < 0) {
+		printk(KERN_ERR 
+		       "%s: failed to claim %s address space!\n", 
+		       __FILE__, central_bus.name);
+		return result;
 	}
 
-
-	pdc_console_init();
-
-#ifdef __LP64__
-	printk("The 64-bit Kernel has started...\n");
-#else
-	printk("The 32-bit Kernel has started...\n");
-#endif
-
-	/*
-	** Enable FP coprocessor
-	**
-	** REVISIT: ccr should be set by PDC_COPROC results to support PA1.0.
-	** Hardcoding works for PA1.1 processors.
-	**
-	** REVISIT: this could be done in the "code 22" trap handler.
-	** (frowands idea - that way we know which processes need FP
-	** registers saved on the interrupt stack.)
-	**
-	** NEWS FLASH: wide kernels need FP coprocessor enabled to handle
-	** formatted printing of %lx for example (double divides I think)
-	*/
-	ccr = 0xc0;
-	mtctl(ccr, 10);
-	printk("Enabled FP coprocessor\n");
-
-#ifdef __LP64__
-	printk( "If this is the LAST MESSAGE YOU SEE, you're probably using\n"
-		"32-bit millicode by mistake.\n");
-#endif
-
-	memory_start = (unsigned long) &_end;
-	memory_start = (memory_start + PAGE_SIZE) & PAGE_MASK;
-	printk("Free memory starts at: 0x%lx\n", memory_start);
-
-	/* Collect stuff passed in from the boot loader */
-	printk(KERN_WARNING  "%s(0x%x,0x%x,0x%x,0x%x)\n", 
-		    __FUNCTION__, arg0, arg1, arg2, arg3);
-
-	/* arg0 is free-mem start, arg1 is ptr to command line */
-	if (arg0 < 64) {
-		/* called from hpux boot loader */
-		saved_command_line[0] = '\0';
-	} else {
-		strcpy(saved_command_line, (char *)__va(arg1));
-		printk("PALO command line: '%s'\nPALO initrd %x-%x\n",
-		    saved_command_line, arg2, arg3);
-
-#ifdef CONFIG_BLK_DEV_INITRD
-		if (arg2 != 0) /* did palo pass us a ramdisk? */
-		{
-		    initrd_start = (unsigned long)__va(arg2);
-		    initrd_end = (unsigned long)__va(arg3);
-		}
-#endif
+	result = request_resource(&iomem_resource, &local_broadcast);
+	if (result < 0) {
+		printk(KERN_ERR 
+		       "%s: failed to claim %saddress space!\n", 
+		       __FILE__, local_broadcast.name);
+		return result;
 	}
 
-	mem_start = __pa(memory_start);
-#define MAX_MEM (512*1024*1024)
-	mem_max = (PAGE0->imm_max_mem > MAX_MEM ? MAX_MEM : PAGE0->imm_max_mem);
-
-	collect_boot_cpu_data();
+	result = request_resource(&iomem_resource, &global_broadcast);
+	if (result < 0) {
+		printk(KERN_ERR 
+		       "%s: failed to claim %s address space!\n", 
+		       __FILE__, global_broadcast.name);
+		return result;
+	}
 
-	/* initialize the LCD/LED after boot_cpu_data is available ! */
-        led_init();				/* LCD/LED initialization */
+	return 0;
+}
 
-	do_inventory();				/* probe for hardware */
-        register_driver(cpu_drivers_for);	/* claim all the CPUs */
+extern void gsc_init(void);
+extern void processor_init(void);
+extern void ccio_init(void);
+extern void dino_init(void);
+extern void iosapic_init(void);
+extern void lba_init(void);
+extern void sba_init(void);
+extern void eisa_init(void);
 
-	if (boot_cpu_data.cpu_count == 0)
-	    register_fallback_cpu();
+void __init parisc_init(void)
+{
+	parisc_proc_mkdir();
+	parisc_init_resources();
+	do_device_inventory();                  /* probe for hardware */
 
-	printk("CPU(s): %d x %s at %d.%06d MHz\n", 
+	processor_init();
+	printk(KERN_INFO "CPU(s): %d x %s at %d.%06d MHz\n",
 			boot_cpu_data.cpu_count,
 			boot_cpu_data.cpu_name,
-			boot_cpu_data.cpu_hz / 1000000, 
+			boot_cpu_data.cpu_hz / 1000000,
 			boot_cpu_data.cpu_hz % 1000000	);
 
-	switch (boot_cpu_data.cpu_type) {
-	case pcx:
-	case pcxs:
-	case pcxt:
-		hppa_dma_ops = &pcx_dma_ops;
-		break;
-	case pcxl2:
-		pa7300lc_init();
-	case pcxl: /* falls through */
-		hppa_dma_ops = &pcxl_dma_ops;
-		break;
-	default:
-		break;
-	}
-
-#if 1
-	/* KLUGE! this really belongs in kernel/resource.c! */
-	iomem_resource.end = ~0UL;
-#endif
-	sysram_resource.end = mem_max - 1;
-	notifier_chain_register(&mach_notifier, &parisc_block);
-	start_kernel(); 	/* now back to arch-generic code... */
-}
-
-void __init setup_arch(char **cmdline_p)
-{
-	unsigned long bootmap_size;
-	unsigned long start_pfn;
-	unsigned long mem_free;
-
-	*cmdline_p = saved_command_line;
-
-	/* initialize bootmem */
-
-	start_pfn = PFN_UP(mem_start);
-	max_pfn = PFN_DOWN(mem_max);
-
-	bootmap_size = init_bootmem(start_pfn, max_pfn);
-
-	mem_start += bootmap_size;
-	mem_free = mem_max - mem_start;
-
-	/* free_bootmem handles rounding nicely */
-	printk("free_bootmem(0x%lx, 0x%lx)\n", (unsigned long)mem_start,
-			(unsigned long)mem_free);
-	free_bootmem(mem_start, mem_free);
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	printk("initrd: %08x-%08x\n", (int) initrd_start, (int) initrd_end);
-
-	if (initrd_end != 0) {
-		initrd_below_start_ok = 1;
-		reserve_bootmem(__pa(initrd_start), initrd_end - initrd_start);
-	}
+	/* These are in a non-obvious order, will fix when we have an iotree */
+#if defined(CONFIG_IOSAPIC)
+	iosapic_init();
 #endif
-
-	cache_init();
-
-	paging_init();
-
-	if((unsigned long)&init_task_union&(INIT_TASK_SIZE - 1)) {
-		printk("init_task_union not aligned.  Please recompile the kernel after changing the first line in arch/parisc/kernel/init_task.c from \n\"#define PAD 0\" to\n\"#define PAD 1\" or vice versa\n");
-		for(;;);
-	}
-
-
-#ifdef CONFIG_SERIAL_CONSOLE
-	/* nothing */
-#elif CONFIG_VT
-#if   defined(CONFIG_STI_CONSOLE)
-	conswitchp = &dummy_con;	/* we use take_over_console() later ! */
-#elif defined(CONFIG_IODC_CONSOLE)
-	conswitchp = &prom_con;		/* it's currently really "prom_con" */
-#elif defined(CONFIG_DUMMY_CONSOLE)
-	conswitchp = &dummy_con;
+#if defined(CONFIG_IOMMU_SBA)
+	sba_init();
 #endif
+#if defined(CONFIG_PCI_LBA)
+	lba_init();
 #endif
 
-}
-
-#ifdef CONFIG_PROC_FS
-/*
- *	Get CPU information for use by procfs.
- */
-
-int get_cpuinfo(char *buffer)
-{
-	char		  *p = buffer;
-	int		  n;
+	/* CCIO before any potential subdevices */
+#if defined(CONFIG_IOMMU_CCIO)
+	ccio_init();
+#endif
 
-	for(n=0; n<boot_cpu_data.cpu_count; n++) {
-#ifdef CONFIG_SMP
-		if (!(cpu_online_map & (1<<n)))
-			continue;
-#endif
-		p += sprintf(p, "processor\t: %d\n"
-				"cpu family\t: PA-RISC %s\n",
-				n, boot_cpu_data.family_name);
-
-		p += sprintf(p, "cpu\t\t: %s\n",  boot_cpu_data.cpu_name );
-	
-		/* cpu MHz */
-		p += sprintf(p, "cpu MHz\t\t: %d.%06d\n",
-				 boot_cpu_data.cpu_hz / 1000000, 
-				 boot_cpu_data.cpu_hz % 1000000  );
-
-		p += sprintf(p, "model\t\t: %s\n"
-				"model name\t: %s\n",
-				boot_cpu_data.pdc.sys_model_name,
-				boot_cpu_data.model_name);
-
-		p += sprintf(p, "hversion\t: 0x%08x\n"
-			        "sversion\t: 0x%08x\n",
-				boot_cpu_data.hversion,
-				boot_cpu_data.sversion );
-
-		p += get_cache_info(p);
-		/* print cachesize info ? */
-		p += sprintf(p, "bogomips\t: %lu.%02lu\n",
-			     (loops_per_sec+2500)/500000,
-			     ((loops_per_sec+2500)/5000) % 100);
-	}
-	return p - buffer;
-}
+	/*
+	 * Need to register Asp & Wax before the EISA adapters for the IRQ
+	 * regions.  EISA must come before PCI to be sure it gets IRQ region
+	 * 0.
+	 */
+#if defined(CONFIG_GSC_LASI) || defined(CONFIG_GSC_WAX)
+	gsc_init();
+#endif
+#ifdef CONFIG_EISA
+	eisa_init();
+#endif
+#if defined(CONFIG_GSC_DINO)
+	dino_init();
 #endif
 
+#ifdef CONFIG_CHASSIS_LCD_LED
+	register_led_regions();	/* register LED port info in procfs */
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/signal.c linux-2.4.20/arch/parisc/kernel/signal.c
--- linux-2.4.19/arch/parisc/kernel/signal.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/signal.c	2002-10-29 11:18:50.000000000 +0000
@@ -26,20 +26,24 @@
 #include <linux/unistd.h>
 #include <linux/stddef.h>
 #include <asm/ucontext.h>
+#include <asm/rt_sigframe.h>
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 
 #define DEBUG_SIG 0
 
+#if DEBUG_SIG
+#define DBG(x)	printk x
+#else
+#define DBG(x)
+#endif
+
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-extern long sys_wait4 (int, int *, int, struct rusage *);
 int do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall);
 
 int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
 {
-	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
-		return -EFAULT;
 	if (from->si_code < 0)
 		return __copy_to_user(to, from, sizeof(siginfo_t));
 	else {
@@ -128,30 +132,15 @@
  * Do a signal return - restore sigcontext.
  */
 
-struct rt_sigframe {
-	unsigned int tramp[4];
-	struct siginfo info;
-	struct ucontext uc;
-};
-
 /* Trampoline for calling rt_sigreturn() */
 #define INSN_LDI_R25_0	 0x34190000 /* ldi  0,%r25 (in_syscall=0) */
 #define INSN_LDI_R25_1	 0x34190002 /* ldi  1,%r25 (in_syscall=1) */
 #define INSN_LDI_R20	 0x3414015a /* ldi  __NR_rt_sigreturn,%r20 */
 #define INSN_BLE_SR2_R0  0xe4008200 /* be,l 0x100(%sr2,%r0),%sr0,%r31 */
-#define INSN_NOP	 0x80000240 /* nop */
+#define INSN_NOP	 0x08000240 /* nop */
 /* For debugging */
 #define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */
 
-/*
- * The 32-bit ABI wants at least 48 bytes for a function call frame:
- * 16 bytes for arg0-arg3, and 32 bytes for magic (the only part of
- * which Linux/parisc uses is sp-20 for the saved return pointer...)
- * Then, the stack pointer must be rounded to a cache line (64 bytes).
- */
-#define PARISC_RT_SIGFRAME_SIZE					\
-	(((sizeof(struct rt_sigframe) + 48) + 63) & -64)
-
 static long
 restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs)
 {
@@ -162,10 +151,7 @@
 	err |= __copy_from_user(regs->iaoq, sc->sc_iaoq, sizeof(regs->iaoq));
 	err |= __copy_from_user(regs->iasq, sc->sc_iasq, sizeof(regs->iasq));
 	err |= __get_user(regs->sar, &sc->sc_sar);
-
-#if DEBUG_SIG
-	printk("restore_sigcontext: r28 is %ld\n", regs->gr[28]);
-#endif
+	DBG(("restore_sigcontext: r28 is %ld\n", regs->gr[28]));
 	return err;
 }
 
@@ -180,13 +166,8 @@
 	/* Unwind the user stack to get the rt_sigframe structure. */
 	frame = (struct rt_sigframe *)
 		(usp - PARISC_RT_SIGFRAME_SIZE);
-#if DEBUG_SIG
-	printk("in sys_rt_sigreturn, frame is %p\n", frame);
-#endif
+	DBG(("in sys_rt_sigreturn, frame is %p\n", frame));
 
-	/* Verify that it's a good sigcontext before using it */
-	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
-		goto give_sigsegv;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto give_sigsegv;
 
@@ -200,10 +181,7 @@
 	if (restore_sigcontext(&frame->uc.uc_mcontext, regs))
 		goto give_sigsegv;
 
-#if DEBUG_SIG
-	printk("usp: %#08lx stack %p",
-	       usp, &frame->uc.uc_stack);
-#endif
+	DBG(("usp: %#08lx stack %p", usp, &frame->uc.uc_stack));
 
 	/* I don't know why everyone else assumes they can call this
            with a pointer to a stack_t on the kernel stack.  That
@@ -218,16 +196,14 @@
 	if (in_syscall)
 		regs->gr[31] = regs->iaoq[0];
 #if DEBUG_SIG
-	printk("returning to %#lx\n", regs->iaoq[0]);
-	printk("in sys_rt_sigreturn:\n");
+	DBG(("returning to %#lx\n", regs->iaoq[0]));
+	DBG(("in sys_rt_sigreturn:\n"));
 	show_regs(regs);
 #endif
 	return;
 
 give_sigsegv:
-#if DEBUG_SIG
-	printk("fuckup in sys_rt_sigreturn, sending SIGSEGV\n");
-#endif
+	DBG(("sys_rt_sigreturn sending SIGSEGV\n"));
 	si.si_signo = SIGSEGV;
 	si.si_errno = 0;
 	si.si_code = SI_KERNEL;
@@ -246,7 +222,7 @@
 get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
 {
 	if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
-		sp = current->sas_ss_sp + current->sas_ss_size;
+		sp = current->sas_ss_sp; /* Stacks grow up! */
 
 	return (void *) sp; /* Stacks grow up.  Fun. */
 }
@@ -265,24 +241,22 @@
 		/* regs->iaoq is undefined in the syscall return path */
 		err |= __put_user(regs->gr[31], &sc->sc_iaoq[0]);
 		err |= __put_user(regs->gr[31]+4, &sc->sc_iaoq[1]);
-#if DEBUG_SIG
-		printk("setup_sigcontext: iaoq %#lx/%#lx\n", regs->gr[31], regs->gr[31]);
-#endif
+		err |= __put_user(regs->sr[3], &sc->sc_iasq[0]);
+		err |= __put_user(regs->sr[3], &sc->sc_iasq[1]);
+		DBG(("setup_sigcontext: iaoq %#lx/%#lx\n",
+			regs->gr[31], regs->gr[31]));
 	} else {
 		err |= __copy_to_user(sc->sc_iaoq, regs->iaoq, sizeof(regs->iaoq));
 		err |= __copy_to_user(sc->sc_iasq, regs->iasq, sizeof(regs->iasq));
-#if DEBUG_SIG
-		printk("setup_sigcontext: iaoq %#lx/%#lx\n", regs->iaoq[0], regs->iaoq[1]);
-#endif
+		DBG(("setup_sigcontext: iaoq %#lx/%#lx\n", 
+			regs->iaoq[0], regs->iaoq[1]));
 	}
 
 	err |= __put_user(flags, &sc->sc_flags);
 	err |= __copy_to_user(sc->sc_gr, regs->gr, sizeof(regs->gr));
 	err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr));
 	err |= __put_user(regs->sar, &sc->sc_sar);
-#if DEBUG_SIG
-	printk("setup_sigcontext: r28 is %ld\n", regs->gr[28]);
-#endif
+	DBG(("setup_sigcontext: r28 is %ld\n", regs->gr[28]));
 
 	return err;
 }
@@ -297,22 +271,9 @@
 	int err = 0;
 
 	usp = regs->gr[30];
-	/* access_ok is broken, so do a simplistic "are we stomping on
-           kernel space" assertion. */
-	if (usp > PAGE_OFFSET) {
-		printk("setup_rt_frame: called on kernel space (usp=%#lx),  NOW YOU MUST DIE!!!\n",
-		       usp);
-		show_regs(regs);
-		while(1);
-	}
-		
 	frame = get_sigframe(ka, usp, sizeof(*frame));
-	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto give_sigsegv;
 
-#if DEBUG_SIG
-	printk("setup_rt_frame 1: frame %p info %p\n", frame, info);
-#endif
+	DBG(("setup_rt_frame 1: frame %p info %p\n", frame, info));
 
 	err |= __copy_to_user(&frame->info, info, sizeof(siginfo_t));
 	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
@@ -337,8 +298,8 @@
 	{
 		int sid;
 		asm ("mfsp %%sr3,%0" : "=r" (sid));
-		printk("flushing 64 bytes at space %#x offset %p\n",
-		       sid, frame->tramp);
+		DBG(("flushing 64 bytes at space %#x offset %p\n",
+		       sid, frame->tramp));
 	}
 #endif
 
@@ -387,6 +348,7 @@
 	if (in_syscall)
 		regs->gr[31] = (HACK) haddr;
 	else {
+		regs->gr[0] = USER_PSW;
 		regs->iaoq[0] = (HACK) haddr | 3;
 		regs->iaoq[1] = regs->iaoq[0] + 4;
 	}
@@ -395,26 +357,20 @@
 	regs->gr[26] = sig;               /* signal number */
 	regs->gr[25] = (HACK) &frame->info; /* siginfo pointer */
 	regs->gr[24] = (HACK) &frame->uc;   /* ucontext pointer */
-#if DEBUG_SIG
-	printk("making sigreturn frame: %#lx + %#lx = %#lx\n",
+	DBG(("making sigreturn frame: %#lx + %#x = %#lx\n",
 	       regs->gr[30], PARISC_RT_SIGFRAME_SIZE,
-	       regs->gr[30] + PARISC_RT_SIGFRAME_SIZE);
-#endif
+	       regs->gr[30] + PARISC_RT_SIGFRAME_SIZE));
 	/* Raise the user stack pointer to make a proper call frame. */
 	regs->gr[30] = ((HACK) frame + PARISC_RT_SIGFRAME_SIZE);
 
-#if DEBUG_SIG
-	printk("SIG deliver (%s:%d): frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n",
+	DBG(("SIG deliver (%s:%d): frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n",
 	       current->comm, current->pid, frame, regs->gr[30],
-	       regs->iaoq[0], regs->iaoq[1], rp);
-#endif
+	       regs->iaoq[0], regs->iaoq[1], rp));
 
 	return 1;
 
 give_sigsegv:
-#if DEBUG_SIG
-	printk("fuckup in setup_rt_frame, sending SIGSEGV\n");
-#endif
+	DBG(("setup_rt_frame sending SIGSEGV\n"));
 	if (sig == SIGSEGV)
 		ka->sa.sa_handler = SIG_DFL;
 	si.si_signo = SIGSEGV;
@@ -436,10 +392,9 @@
 	      siginfo_t *info, sigset_t *oldset,
 	      struct pt_regs *regs, int in_syscall)
 {
-#if DEBUG_SIG
-	printk("handle_signal(sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p)\n",
-	       sig, ka, info, oldset, regs);
-#endif
+	DBG(("handle_signal(sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p)\n",
+	       sig, ka, info, oldset, regs));
+	
 	/* Set up the stack frame */
 	if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))
 		return 0;
@@ -468,16 +423,16 @@
  * registers).  As noted below, the syscall number gets restored for
  * us due to the magic of delayed branching.
  */
+
 asmlinkage int
 do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall)
 {
 	siginfo_t info;
 	struct k_sigaction *ka;
 
-#if DEBUG_SIG
-	printk("do_signal(oldset=0x%p, regs=0x%p, sr7 %#lx, pending %d, in_syscall=%d\n",
-	       oldset, regs, regs->sr[7], current->sigpending, in_syscall);
-#endif
+	DBG(("do_signal(oldset=0x%p, regs=0x%p, sr7 %#lx, pending %d, in_syscall=%d\n",
+	       oldset, regs, regs->sr[7], current->sigpending, in_syscall));
+
 	/* Everyone else checks to see if they are in kernel mode at
 	   this point and exits if that's the case.  I'm not sure why
 	   we would be called in that case, but for some reason we
@@ -486,9 +441,8 @@
 	if (!oldset)
 		oldset = &current->blocked;
 
-#if DEBUG_SIG
-	printk("do_signal: oldset %08lx:%08lx\n", oldset->sig[0], oldset->sig[1]);
-#endif
+	DBG(("do_signal: oldset %08lx:%08lx\n", 
+		oldset->sig[0], oldset->sig[1]));
 
 	for (;;) {
 		unsigned long signr;
@@ -496,10 +450,7 @@
 		spin_lock_irq(&current->sigmask_lock);
 		signr = dequeue_signal(&current->blocked, &info);
 		spin_unlock_irq(&current->sigmask_lock);
-#if DEBUG_SIG
-		printk("do_signal: signr=%ld, pid=%d\n", signr, current->pid);
-#endif
-
+		DBG(("do_signal: signr=%ld, pid=%d\n", signr, current->pid));
 		if (!signr)
 			break;
 
@@ -536,10 +487,9 @@
 		}
 
 		ka = &current->sig->action[signr-1];
-#if DEBUG_SIG
-		printk("sa_handler is %lx\n", ka->sa.sa_handler);
-#endif
-		if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_IGN) {
+		DBG(("sa_handler is %x\n", 
+			(unsigned int) ka->sa.sa_handler));
+		if (ka->sa.sa_handler == SIG_IGN) {
 			if (signr != SIGCHLD)
 				continue;
 			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
@@ -547,7 +497,7 @@
 			continue;
 		}
 
-		if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_DFL) {
+		if (ka->sa.sa_handler == SIG_DFL) {
 			int exit_code = signr;
 
 			/* Init gets no signals it doesn't want.  */
@@ -591,17 +541,13 @@
 			/* Check the return code */
 			switch (regs->gr[28]) {
 			case -ERESTARTNOHAND:
-#if DEBUG_SIG
-				printk("ERESTARTNOHAND: returning -EINTR\n");
-#endif
+				DBG(("ERESTARTNOHAND: returning -EINTR\n"));
 				regs->gr[28] = -EINTR;
 				break;
 
 			case -ERESTARTSYS:
 				if (!(ka->sa.sa_flags & SA_RESTART)) {
-#if DEBUG_SIG
-					printk("ERESTARTSYS: putting -EINTR\n");
-#endif
+					DBG(("ERESTARTSYS: putting -EINTR\n"));
 					regs->gr[28] = -EINTR;
 					break;
 				}
@@ -620,9 +566,9 @@
 		   delivery failed, we need to continue to iterate in
 		   this loop so we can deliver the SIGSEGV... */
 		if (handle_signal(signr, ka, &info, oldset, regs, in_syscall)) {
-#if DEBUG_SIG
-			printk("Exiting do_signal (success), regs->gr[28] = %ld\n", regs->gr[28]);
-#endif
+			DBG((KERN_DEBUG
+				"Exiting do_signal (success), regs->gr[28] = %ld\n",
+				regs->gr[28]));
 			return 1;
 		}
 	}
@@ -642,8 +588,9 @@
 			regs->gr[28] = regs->orig_r28;
 		}
 	}
-#if DEBUG_SIG
-	printk("Exiting do_signal (not delivered), regs->gr[28] = %ld\n", regs->gr[28]);
-#endif
+	
+	DBG(("Exiting do_signal (not delivered), regs->gr[28] = %ld\n", 
+		regs->gr[28]));
+
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/signal32.c linux-2.4.20/arch/parisc/kernel/signal32.c
--- linux-2.4.19/arch/parisc/kernel/signal32.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/signal32.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,213 @@
+/* mostly borrowed from kernel/signal.c */
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/unistd.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+
+#include <asm/uaccess.h>
+#include "sys32.h"
+
+struct k_sigaction32 {
+	struct sigaction32 sa;
+};
+
+typedef unsigned int old_sigset_t32;
+
+static int
+put_old_sigset32(old_sigset_t32 *up, old_sigset_t *set)
+{
+	old_sigset_t32 set32 = *set;
+	return put_user(set32, up);
+}
+
+static int
+get_old_segset32(old_sigset_t32 *up, old_sigset_t *set)
+{
+	old_sigset_t32 set32;
+	int r;
+
+	if ((r = get_user(set32, up)) == 0)
+		*set = set32;
+
+	return r;
+}
+
+long
+sys32_sigpending(old_sigset_t32 *set)
+{
+	extern long sys_sigpending(old_sigset_t *set);
+	old_sigset_t pending;
+	int ret;
+
+	KERNEL_SYSCALL(ret, sys_sigpending, &pending);
+
+	/* can't put_user an old_sigset_t -- it is too big */
+	if (put_old_sigset32(set, &pending))
+		return -EFAULT;
+
+	return ret;
+}
+
+int sys32_sigprocmask(int how, old_sigset_t32 *set, 
+				 old_sigset_t32 *oset)
+{
+	extern int sys_sigprocmask(int how, old_sigset_t *set, 
+				 old_sigset_t *oset);
+	old_sigset_t s;
+	int ret;
+
+	if (set && get_old_segset32 (set, &s))
+		return -EFAULT;
+	KERNEL_SYSCALL(ret, sys_sigprocmask, how, set ? &s : NULL, oset ? &s : NULL);
+	if (!ret && oset && put_old_sigset32(oset, &s))
+		return -EFAULT;
+	return ret;
+}
+
+static inline void
+sigset_32to64(sigset_t *s64, sigset_t32 *s32)
+{
+	s64->sig[0] = s32->sig[0] | ((unsigned long)s32->sig[1] << 32);
+}
+
+static inline void
+sigset_64to32(sigset_t32 *s32, sigset_t *s64)
+{
+	s32->sig[0] = s64->sig[0] & 0xffffffffUL;
+	s32->sig[1] = (s64->sig[0] >> 32) & 0xffffffffUL;
+}
+
+static int
+put_sigset32(sigset_t32 *up, sigset_t *set, size_t sz)
+{
+	sigset_t32 s;
+
+	if (sz != sizeof *set) panic("put_sigset32()");
+	sigset_64to32(&s, set);
+
+	return copy_to_user(up, &s, sizeof s);
+}
+
+static int
+get_sigset32(sigset_t32 *up, sigset_t *set, size_t sz)
+{
+	sigset_t32 s;
+	int r;
+
+	if (sz != sizeof *set) panic("put_sigset32()");
+
+	if ((r = copy_from_user(&s, up, sz)) == 0) {
+		sigset_32to64(set, &s);
+	}
+
+	return r;
+}
+
+int sys32_rt_sigprocmask(int how, sigset_t32 *set, sigset_t32 *oset,
+				    unsigned int sigsetsize)
+{
+	extern long sys_rt_sigprocmask(int how,
+				    sigset_t *set, sigset_t *oset,
+				   size_t sigsetsize);
+	sigset_t old_set, new_set;
+	int ret;
+
+	if (set && get_sigset32(set, &new_set, sigsetsize))
+		return -EFAULT;
+	
+	KERNEL_SYSCALL(ret, sys_rt_sigprocmask, how, set ? &new_set : NULL,
+				 oset ? &old_set : NULL, sigsetsize);
+
+	if (!ret && oset && put_sigset32(oset, &old_set, sigsetsize))
+		return -EFAULT;
+
+	return ret;
+}
+
+
+int sys32_rt_sigpending(sigset_t32 *uset, unsigned int sigsetsize)
+{
+	int ret;
+	sigset_t set;
+	extern long sys_rt_sigpending(sigset_t *set, size_t sigsetsize);
+
+	KERNEL_SYSCALL(ret, sys_rt_sigpending, &set, sigsetsize);
+
+	if (!ret && put_sigset32(uset, &set, sigsetsize))
+		return -EFAULT;
+
+	return ret;
+}
+
+long
+sys32_rt_sigaction(int sig, const struct sigaction32 *act, struct sigaction32 *oact,
+                 size_t sigsetsize)
+{
+	struct k_sigaction32 new_sa32, old_sa32;
+	struct k_sigaction new_sa, old_sa;
+	int ret = -EINVAL;
+
+	if (act) {
+		if (copy_from_user(&new_sa32.sa, act, sizeof new_sa32.sa))
+			return -EFAULT;
+		new_sa.sa.sa_handler = (__sighandler_t)(unsigned long)new_sa32.sa.sa_handler;
+		new_sa.sa.sa_flags = new_sa32.sa.sa_flags;
+		sigset_32to64(&new_sa.sa.sa_mask, &new_sa32.sa.sa_mask);
+	}
+
+	ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
+
+	if (!ret && oact) {
+		sigset_64to32(&old_sa32.sa.sa_mask, &old_sa.sa.sa_mask);
+		old_sa32.sa.sa_flags = old_sa.sa.sa_flags;
+		old_sa32.sa.sa_handler = (__sighandler_t32)(unsigned long)old_sa.sa.sa_handler;
+		if (copy_to_user(oact, &old_sa32.sa, sizeof old_sa32.sa))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+typedef struct {
+	unsigned int ss_sp;
+	int ss_flags;
+	__kernel_size_t32 ss_size;
+} stack_t32;
+
+int 
+do_sigaltstack32 (const stack_t32 *uss32, stack_t32 *uoss32, unsigned long sp)
+{
+	stack_t32 ss32, oss32;
+	stack_t ss, oss;
+	stack_t *ssp = NULL, *ossp = NULL;
+	int ret;
+
+	if (uss32) {
+		if (copy_from_user(&ss32, uss32, sizeof ss32))
+			return -EFAULT;
+
+		ss.ss_sp = (void *)ss32.ss_sp;
+		ss.ss_flags = ss32.ss_flags;
+		ss.ss_size = ss32.ss_size;
+
+		ssp = &ss;
+	}
+
+	if (uoss32)
+		ossp = &oss;
+
+	KERNEL_SYSCALL(ret, do_sigaltstack, ssp, ossp, sp);
+
+	if (!ret && uoss32) {
+		oss32.ss_sp = (unsigned int)(unsigned long)oss.ss_sp;
+		oss32.ss_flags = oss.ss_flags;
+		oss32.ss_size = oss.ss_size;
+		if (copy_to_user(uoss32, &oss32, sizeof *uoss32))
+			return -EFAULT;
+	}
+
+	return ret;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/smp.c linux-2.4.20/arch/parisc/kernel/smp.c
--- linux-2.4.19/arch/parisc/kernel/smp.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/smp.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,794 @@
+/*
+** SMP Support
+**
+** Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+** Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+** Copyright (C) 2001 Grant Grundler <grundler@parisc-linux.org>
+** 
+** Lots of stuff stolen from arch/alpha/kernel/smp.c
+** ...and then parisc stole from arch/ia64/kernel/smp.c. Thanks David! :^)
+**
+** Thanks to John Curry and Ullas Ponnadi. I learned alot from their work.
+** -grant (1/12/2001)
+**
+**	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.
+*/
+#define __KERNEL_SYSCALLS__
+#undef ENTRY_SYS_CPUS	/* syscall support for iCOD-like functionality */
+
+#include <linux/autoconf.h>
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/kernel_stat.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/current.h>
+#include <asm/delay.h>
+#include <asm/pgalloc.h>	/* for flush_tlb_all() proto/macro */
+
+#include <asm/io.h>
+#include <asm/irq.h>		/* for CPU_IRQ_REGION and friends */
+#include <asm/mmu_context.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+
+#define kDEBUG 0
+
+spinlock_t pa_dbit_lock = SPIN_LOCK_UNLOCKED;
+
+spinlock_t smp_lock = SPIN_LOCK_UNLOCKED;
+
+volatile struct task_struct *smp_init_current_idle_task;
+spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+
+static volatile int smp_commenced = 0;   /* Set when the idlers are all forked */
+static volatile int cpu_now_booting = 0;      /* track which CPU is booting */
+volatile unsigned long cpu_online_map = 0;   /* Bitmap of online CPUs */
+#define IS_LOGGED_IN(cpunum) (test_bit(cpunum, (atomic_t *)&cpu_online_map))
+
+int smp_num_cpus = 1;
+int smp_threads_ready = 0;
+static int max_cpus = -1;			     /* Command line */
+struct smp_call_struct {
+	void (*func) (void *info);
+	void *info;
+	long wait;
+	atomic_t unstarted_count;
+	atomic_t unfinished_count;
+};
+static volatile struct smp_call_struct *smp_call_function_data;
+
+enum ipi_message_type {
+	IPI_NOP=0,
+	IPI_RESCHEDULE=1,
+	IPI_CALL_FUNC,
+	IPI_CPU_START,
+	IPI_CPU_STOP,
+	IPI_CPU_TEST
+};
+
+
+/********** SMP inter processor interrupt and communication routines */
+
+#undef PER_CPU_IRQ_REGION
+#ifdef PER_CPU_IRQ_REGION
+/* XXX REVISIT Ignore for now.
+**    *May* need this "hook" to register IPI handler
+**    once we have perCPU ExtIntr switch tables.
+*/
+static void
+ipi_init(int cpuid)
+{
+
+	/* If CPU is present ... */
+#ifdef ENTRY_SYS_CPUS
+	/* *and* running (not stopped) ... */
+#error iCOD support wants state checked here.
+#endif
+
+#error verify IRQ_OFFSET(IPI_IRQ) is ipi_interrupt() in new IRQ region
+
+	if(IS_LOGGED_IN(cpuid) )
+	{
+		switch_to_idle_task(current);
+	}
+
+	return;
+}
+#endif
+
+
+/*
+** Yoink this CPU from the runnable list... 
+**
+*/
+static void
+halt_processor(void) 
+{
+#ifdef ENTRY_SYS_CPUS
+#error halt_processor() needs rework
+/*
+** o migrate I/O interrupts off this CPU.
+** o leave IPI enabled - __cli() will disable IPI.
+** o leave CPU in online map - just change the state
+*/
+	cpu_data[this_cpu].state = STATE_STOPPED;
+	mark_bh(IPI_BH);
+#else
+	/* REVISIT : redirect I/O Interrupts to another CPU? */
+	/* REVISIT : does PM *know* this CPU isn't available? */
+	clear_bit(smp_processor_id(), (void *)&cpu_online_map);
+	__cli();
+	for (;;)
+		;
+#endif
+}
+
+
+void
+ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs) 
+{
+	int this_cpu = smp_processor_id();
+	struct cpuinfo_parisc *p = &cpu_data[this_cpu];
+	unsigned long ops;
+	unsigned long flags;
+
+	/* Count this now; we may make a call that never returns. */
+	p->ipi_count++;
+
+	mb();	/* Order interrupt and bit testing. */
+
+	for (;;) {
+		spin_lock_irqsave(&(p->lock),flags);
+		ops = p->pending_ipi;
+		p->pending_ipi = 0;
+		spin_unlock_irqrestore(&(p->lock),flags);
+
+		mb(); /* Order bit clearing and data access. */
+
+		if (!ops)
+		    break;
+
+		while (ops) {
+			unsigned long which = ffz(~ops);
+
+			switch (which) {
+			case IPI_RESCHEDULE:
+#if (kDEBUG>=100)
+				printk(KERN_DEBUG "CPU%d IPI_RESCHEDULE\n",this_cpu);
+#endif /* kDEBUG */
+				ops &= ~(1 << IPI_RESCHEDULE);
+				/*
+				 * Reschedule callback.  Everything to be
+				 * done is done by the interrupt return path.
+				 */
+				break;
+
+			case IPI_CALL_FUNC:
+#if (kDEBUG>=100)
+				printk(KERN_DEBUG "CPU%d IPI_CALL_FUNC\n",this_cpu);
+#endif /* kDEBUG */
+				ops &= ~(1 << IPI_CALL_FUNC);
+				{
+					volatile struct smp_call_struct *data;
+					void (*func)(void *info);
+					void *info;
+					int wait;
+
+					data = smp_call_function_data;
+					func = data->func;
+					info = data->info;
+					wait = data->wait;
+
+					mb();
+					atomic_dec ((atomic_t *)&data->unstarted_count);
+
+					/* At this point, *data can't
+					 * be relied upon.
+					 */
+
+					(*func)(info);
+
+					/* Notify the sending CPU that the
+					 * task is done.
+					 */
+					mb();
+					if (wait)
+						atomic_dec ((atomic_t *)&data->unfinished_count);
+				}
+				break;
+
+			case IPI_CPU_START:
+#if (kDEBUG>=100)
+				printk(KERN_DEBUG "CPU%d IPI_CPU_START\n",this_cpu);
+#endif /* kDEBUG */
+				ops &= ~(1 << IPI_CPU_START);
+#ifdef ENTRY_SYS_CPUS
+				p->state = STATE_RUNNING;
+#endif
+				break;
+
+			case IPI_CPU_STOP:
+#if (kDEBUG>=100)
+				printk(KERN_DEBUG "CPU%d IPI_CPU_STOP\n",this_cpu);
+#endif /* kDEBUG */
+				ops &= ~(1 << IPI_CPU_STOP);
+#ifdef ENTRY_SYS_CPUS
+#else
+				halt_processor();
+#endif
+				break;
+
+			case IPI_CPU_TEST:
+#if (kDEBUG>=100)
+				printk(KERN_DEBUG "CPU%d is alive!\n",this_cpu);
+#endif /* kDEBUG */
+				ops &= ~(1 << IPI_CPU_TEST);
+				break;
+
+			default:
+				printk(KERN_CRIT "Unknown IPI num on CPU%d: %lu\n",
+					this_cpu, which);
+				ops &= ~(1 << which);
+				return;
+			} /* Switch */
+		} /* while (ops) */
+	}
+	return;
+}
+
+
+static inline void
+ipi_send(int cpu, enum ipi_message_type op)
+{
+	struct cpuinfo_parisc *p = &cpu_data[cpu];
+	unsigned long flags;
+
+	spin_lock_irqsave(&(p->lock),flags);
+	p->pending_ipi |= 1 << op;
+	__raw_writel(IRQ_OFFSET(IPI_IRQ), cpu_data[cpu].hpa);
+	spin_unlock_irqrestore(&(p->lock),flags);
+}
+
+
+static inline void
+send_IPI_single(int dest_cpu, enum ipi_message_type op)
+{
+	if (dest_cpu == NO_PROC_ID) {
+		BUG();
+		return;
+	}
+
+	ipi_send(dest_cpu, op);
+}
+
+static inline void
+send_IPI_allbutself(enum ipi_message_type op)
+{
+	int i;
+	
+	for (i = 0; i < smp_num_cpus; i++) {
+		if (i != smp_processor_id())
+			send_IPI_single(i, op);
+	}
+}
+
+inline void 
+smp_send_stop(void)	{ send_IPI_allbutself(IPI_CPU_STOP); }
+
+static inline void
+smp_send_start(void)	{ send_IPI_allbutself(IPI_CPU_START); }
+
+void 
+smp_send_reschedule(int cpu) { send_IPI_single(cpu, IPI_RESCHEDULE); }
+
+
+/**
+ * Run a function on all other CPUs.
+ *  <func>	The function to run. This must be fast and non-blocking.
+ *  <info>	An arbitrary pointer to pass to the function.
+ *  <retry>	If true, keep retrying until ready.
+ *  <wait>	If true, wait until function has completed on other CPUs.
+ *  [RETURNS]   0 on success, else a negative status code.
+ *
+ * Does not return until remote CPUs are nearly ready to execute <func>
+ * or have executed.
+ */
+
+int
+smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
+{
+	struct smp_call_struct data;
+	long timeout;
+	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+	
+	data.func = func;
+	data.info = info;
+	data.wait = wait;
+	atomic_set(&data.unstarted_count, smp_num_cpus - 1);
+	atomic_set(&data.unfinished_count, smp_num_cpus - 1);
+
+	if (retry) {
+		spin_lock (&lock);
+		while (smp_call_function_data != 0)
+			barrier();
+	}
+	else {
+		spin_lock (&lock);
+		if (smp_call_function_data) {
+			spin_unlock (&lock);
+			return -EBUSY;
+		}
+	}
+
+	smp_call_function_data = &data;
+	spin_unlock (&lock);
+	
+	/*  Send a message to all other CPUs and wait for them to respond  */
+	send_IPI_allbutself(IPI_CALL_FUNC);
+
+	/*  Wait for response  */
+	timeout = jiffies + HZ;
+	while ( (atomic_read (&data.unstarted_count) > 0) &&
+		time_before (jiffies, timeout) )
+		barrier ();
+
+	/* We either got one or timed out. Release the lock */
+
+	mb();
+	smp_call_function_data = NULL;
+	if (atomic_read (&data.unstarted_count) > 0) {
+		printk(KERN_CRIT "SMP CALL FUNCTION TIMED OUT! (cpu=%d)\n",
+		      smp_processor_id());
+		return -ETIMEDOUT;
+	}
+
+	while (wait && atomic_read (&data.unfinished_count) > 0)
+			barrier ();
+
+	return 0;
+}
+
+
+
+/*
+ *	Setup routine for controlling SMP activation
+ *
+ *	Command-line option of "nosmp" or "maxcpus=0" will disable SMP
+ *	activation entirely (the MPS table probe still happens, though).
+ *
+ *	Command-line option of "maxcpus=<NUM>", where <NUM> is an integer
+ *	greater than 0, limits the maximum number of CPUs activated in
+ *	SMP mode to <NUM>.
+ */
+
+static int __init nosmp(char *str)
+{
+	max_cpus = 0;
+	return 1;
+}
+
+__setup("nosmp", nosmp);
+
+static int __init maxcpus(char *str)
+{
+	get_option(&str, &max_cpus);
+	return 1;
+}
+
+__setup("maxcpus=", maxcpus);
+
+/*
+ * Flush all other CPU's tlb and then mine.  Do this with smp_call_function()
+ * as we want to ensure all TLB's flushed before proceeding.
+ */
+
+extern void flush_tlb_all_local(void);
+
+void
+smp_flush_tlb_all(void)
+{
+	smp_call_function((void (*)(void *))flush_tlb_all_local, NULL, 1, 1);
+	flush_tlb_all_local();
+}
+
+
+void 
+smp_do_timer(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+	struct cpuinfo_parisc *data = &cpu_data[cpu];
+
+        if (!--data->prof_counter) {
+		data->prof_counter = data->prof_multiplier;
+		update_process_times(user_mode(regs));
+	}
+}
+
+/*
+ * Called by secondaries to update state and initialize CPU registers.
+ */
+static void __init
+smp_cpu_init(int cpunum)
+{
+	extern int init_per_cpu(int);  /* arch/parisc/kernel/setup.c */
+	extern void init_IRQ(void);    /* arch/parisc/kernel/irq.c */
+
+	/* Set modes and Enable floating point coprocessor */
+	(void) init_per_cpu(cpunum);
+
+	disable_sr_hashing();
+
+	mb();
+
+	/* Well, support 2.4 linux scheme as well. */
+	if (test_and_set_bit(cpunum, (unsigned long *) (&cpu_online_map)))
+	{
+		extern void machine_halt(void); /* arch/parisc.../process.c */
+
+		printk(KERN_CRIT "CPU#%d already initialized!\n", cpunum);
+		machine_halt();
+	}  
+
+	/* Initialise the idle task for this CPU */
+	atomic_inc(&init_mm.mm_count);
+	current->active_mm = &init_mm;
+	if(current->mm)
+		BUG();
+	enter_lazy_tlb(&init_mm, current, cpunum);
+
+	init_IRQ();   /* make sure no IRQ's are enabled or pending */
+}
+
+
+/*
+ * Slaves start using C here. Indirectly called from smp_slave_stext.
+ * Do what start_kernel() and main() do for boot strap processor (aka monarch)
+ */
+void __init smp_callin(void)
+{
+	extern void cpu_idle(void);	/* arch/parisc/kernel/process.c */
+	int slave_id = cpu_now_booting;
+#if 0
+	void *istack;
+#endif
+
+	smp_cpu_init(slave_id);
+
+#if 0	/* NOT WORKING YET - see entry.S */
+	istack = (void *)__get_free_pages(GFP_KERNEL,ISTACK_ORDER);
+	if (istack == NULL) {
+	    printk(KERN_CRIT "Failed to allocate interrupt stack for cpu %d\n",slave_id);
+	    BUG();
+	}
+	mtctl(istack,31);
+#endif
+
+	flush_cache_all_local(); /* start with known state */
+	flush_tlb_all_local();
+
+	local_irq_enable();  /* Interrupts have been off until now */
+
+	/* Slaves wait here until Big Poppa daddy say "jump" */
+	mb();	/* PARANOID */
+	while (!smp_commenced) ;
+	mb();	/* PARANOID */
+
+	cpu_idle();      /* Wait for timer to schedule some work */
+
+	/* NOTREACHED */
+	panic("smp_callin() AAAAaaaaahhhh....\n");
+}
+
+/*
+ * Create the idle task for a new Slave CPU.  DO NOT use kernel_thread()
+ * because that could end up calling schedule(). If it did, the new idle
+ * task could get scheduled before we had a chance to remove it from the
+ * run-queue...
+ */
+static int fork_by_hand(void)
+{
+	struct pt_regs regs;  
+
+	/*
+	 * don't care about the regs settings since
+	 * we'll never reschedule the forked task.
+	 */
+	return do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0);
+}
+
+
+/*
+ * Bring one cpu online.
+ */
+static int smp_boot_one_cpu(int cpuid, int cpunum)
+{
+	struct task_struct *idle;
+	long timeout;
+
+	/* 
+	 * Create an idle task for this CPU.  Note the address wed* give 
+	 * to kernel_thread is irrelevant -- it's going to start
+	 * where OS_BOOT_RENDEVZ vector in SAL says to start.  But
+	 * this gets all the other task-y sort of data structures set
+	 * up like we wish.   We need to pull the just created idle task 
+	 * off the run queue and stuff it into the init_tasks[] array.  
+	 * Sheesh . . .
+	 */
+
+	if (fork_by_hand() < 0) 
+		panic("SMP: fork failed for CPU:%d", cpuid);
+	
+	idle = init_task.prev_task;
+	if (!idle)
+		panic("SMP: No idle process for CPU:%d", cpuid);
+
+	task_set_cpu(idle, cpunum);	/* manually schedule idle task */
+	del_from_runqueue(idle);
+	unhash_process(idle);
+	init_tasks[cpunum] = idle;
+
+	/* Let _start know what logical CPU we're booting
+	** (offset into init_tasks[],cpu_data[])
+	*/
+	cpu_now_booting = cpunum;
+
+	/* 
+	** boot strap code needs to know the task address since
+	** it also contains the process stack.
+	*/
+	smp_init_current_idle_task = idle ;
+	mb();
+
+	/*
+	** This gets PDC to release the CPU from a very tight loop.
+	** See MEM_RENDEZ comments in head.S.
+	*/
+	__raw_writel(IRQ_OFFSET(TIMER_IRQ), cpu_data[cpunum].hpa);
+	mb();
+
+	/* 
+	 * OK, wait a bit for that CPU to finish staggering about. 
+	 * Slave will set a bit when it reaches smp_cpu_init() and then
+	 * wait for smp_commenced to be 1.
+	 * Once we see the bit change, we can move on.
+	 */
+	for (timeout = 0; timeout < 10000; timeout++) {
+		if(IS_LOGGED_IN(cpunum)) {
+			/* Which implies Slave has started up */
+			cpu_now_booting = 0;
+			smp_init_current_idle_task = NULL;
+			goto alive ;
+		}
+		udelay(100);
+		barrier();
+	}
+
+	init_tasks[cpunum] = NULL;
+	free_task_struct(idle);
+
+	printk(KERN_CRIT "SMP: CPU:%d is stuck.\n", cpuid);
+	return -1;
+
+alive:
+	/* Remember the Slave data */
+#if (kDEBUG>=100)
+	printk(KERN_DEBUG "SMP: CPU:%d (num %d) came alive after %ld _us\n",
+		cpuid,  cpunum, timeout * 100);
+#endif /* kDEBUG */
+#ifdef ENTRY_SYS_CPUS
+	cpu_data[cpunum].state = STATE_RUNNING;
+#endif
+	return 0;
+}
+
+
+
+
+/*
+** inventory.c:do_inventory() has already 'discovered' the additional CPU's.
+** We are ready to wrest them from PDC's control now.
+** Called by smp_init bring all the secondaries online and hold them.  
+**
+** o Setup of the IPI irq handler is done in irq.c.
+** o MEM_RENDEZ is initialzed in head.S:stext()
+**
+*/
+void __init smp_boot_cpus(void)
+{
+	int i, cpu_count = 1;
+	unsigned long bogosum = loops_per_jiffy; /* Count Monarch */
+
+	/* REVISIT - assumes first CPU reported by PAT PDC is BSP */
+	int bootstrap_processor=cpu_data[0].cpuid;	/* CPU ID of BSP */
+
+	/* Setup BSP mappings */
+	printk(KERN_DEBUG "SMP: bootstrap CPU ID is %d\n",bootstrap_processor);
+	init_task.processor = bootstrap_processor; 
+	current->processor = bootstrap_processor;
+	cpu_online_map = 1 << bootstrap_processor; /* Mark Boostrap processor as present */
+	current->active_mm = &init_mm;
+
+#ifdef ENTRY_SYS_CPUS
+	cpu_data[0].state = STATE_RUNNING;
+#endif
+
+	/* Nothing to do when told not to.  */
+	if (max_cpus == 0) {
+		printk(KERN_INFO "SMP mode deactivated.\n");
+		return;
+	}
+
+	if (max_cpus != -1) 
+		printk(KERN_INFO "Limiting CPUs to %d\n", max_cpus);
+
+	/* We found more than one CPU.... */
+	if (boot_cpu_data.cpu_count > 1) {
+
+		for (i = 0; i < NR_CPUS; i++) {
+			if (cpu_data[i].cpuid == NO_PROC_ID || 
+			    cpu_data[i].cpuid == bootstrap_processor)
+				continue;
+
+			if (smp_boot_one_cpu(cpu_data[i].cpuid, cpu_count) < 0)
+				continue;
+
+			bogosum += loops_per_jiffy;
+			cpu_count++; /* Count good CPUs only... */
+
+			/* Bail when we've started as many CPUS as told to */
+			if (cpu_count == max_cpus)
+				break;
+		}
+	}
+	if (cpu_count == 1) {
+		printk(KERN_INFO "SMP: Bootstrap processor only.\n");
+	}
+
+	printk(KERN_INFO "SMP: Total %d of %d processors activated "
+	       "(%lu.%02lu BogoMIPS noticed).\n",
+	       cpu_count, boot_cpu_data.cpu_count, (bogosum + 25) / 5000,
+	       ((bogosum + 25) / 50) % 100);
+
+	smp_num_cpus = cpu_count;
+#ifdef PER_CPU_IRQ_REGION
+	ipi_init();
+#endif
+	return;
+}
+
+/* 
+ * Called from main.c by Monarch Processor.
+ * After this, any CPU can schedule any task.
+ */
+void smp_commence(void)
+{
+	smp_commenced = 1;
+	mb();
+	return;
+}
+
+#ifdef ENTRY_SYS_CPUS
+/* Code goes along with:
+**    entry.s:        ENTRY_NAME(sys_cpus)   / * 215, for cpu stat * /
+*/
+int sys_cpus(int argc, char **argv)
+{
+	int i,j=0;
+	extern int current_pid(int cpu);
+
+	if( argc > 2 ) {
+		printk("sys_cpus:Only one argument supported\n");
+		return (-1);
+	}
+	if ( argc == 1 ){
+	
+#ifdef DUMP_MORE_STATE
+		for(i=0; i<NR_CPUS; i++) {
+			int cpus_per_line = 4;
+			if(IS_LOGGED_IN(i)) {
+				if (j++ % cpus_per_line)
+					printk(" %3d",i);
+				else
+					printk("\n %3d",i);
+			}
+		}
+		printk("\n"); 
+#else
+	    	printk("\n 0\n"); 
+#endif
+	} else if((argc==2) && !(strcmp(argv[1],"-l"))) {
+		printk("\nCPUSTATE  TASK CPUNUM CPUID HARDCPU(HPA)\n");
+#ifdef DUMP_MORE_STATE
+		for(i=0;i<NR_CPUS;i++) {
+			if (!IS_LOGGED_IN(i))
+				continue;
+			if (cpu_data[i].cpuid != NO_PROC_ID) {
+				switch(cpu_data[i].state) {
+					case STATE_RENDEZVOUS:
+						printk("RENDEZVS ");
+						break;
+					case STATE_RUNNING:
+						printk((current_pid(i)!=0) ? "RUNNING  " : "IDLING   ");
+						break;
+					case STATE_STOPPED:
+						printk("STOPPED  ");
+						break;
+					case STATE_HALTED:
+						printk("HALTED   ");
+						break;
+					default:
+						printk("%08x?", cpu_data[i].state);
+						break;
+				}
+				if(IS_LOGGED_IN(i)) {
+					printk(" %4d",current_pid(i));
+				}	
+				printk(" %6d",cpu_number_map(i));
+				printk(" %5d",i);
+				printk(" 0x%lx\n",cpu_data[i].hpa);
+			}	
+		}
+#else
+		printk("\n%s  %4d      0     0 --------",
+			(current->pid)?"RUNNING ": "IDLING  ",current->pid); 
+#endif
+	} else if ((argc==2) && !(strcmp(argv[1],"-s"))) { 
+#ifdef DUMP_MORE_STATE
+     		printk("\nCPUSTATE   CPUID\n");
+		for (i=0;i<NR_CPUS;i++) {
+			if (!IS_LOGGED_IN(i))
+				continue;
+			if (cpu_data[i].cpuid != NO_PROC_ID) {
+				switch(cpu_data[i].state) {
+					case STATE_RENDEZVOUS:
+						printk("RENDEZVS");break;
+					case STATE_RUNNING:
+						printk((current_pid(i)!=0) ? "RUNNING " : "IDLING");
+						break;
+					case STATE_STOPPED:
+						printk("STOPPED ");break;
+					case STATE_HALTED:
+						printk("HALTED  ");break;
+					default:
+				}
+				printk("  %5d\n",i);
+			}	
+		}
+#else
+		printk("\n%s    CPU0",(current->pid==0)?"RUNNING ":"IDLING  "); 
+#endif
+	} else {
+		printk("sys_cpus:Unknown request\n");
+		return (-1);
+	}
+	return 0;
+}
+#endif /* ENTRY_SYS_CPUS */
+
+#ifdef CONFIG_PROC_FS
+int __init
+setup_profiling_timer(unsigned int multiplier)
+{
+	return -EINVAL;
+}
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/superio.c linux-2.4.20/arch/parisc/kernel/superio.c
--- linux-2.4.19/arch/parisc/kernel/superio.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/superio.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,543 @@
+/*      National Semiconductor NS87560UBD Super I/O controller used in
+ *      HP [BCJ]x000 workstations.
+ *
+ *      This chip is a horrid piece of engineering, and National
+ *      denies any knowledge of its existence. Thus no datasheet is
+ *      available off www.national.com. 
+ *
+ *	(C) Copyright 2000 Linuxcare, Inc.
+ * 	(C) Copyright 2000 Linuxcare Canada, Inc.
+ *	(C) Copyright 2000 Martin K. Petersen <mkp@linuxcare.com>
+ * 	(C) Copyright 2000 Alex deVries <alex@linuxcare.com>
+ *      (C) Copyright 2001 John Marvin <jsm@fc.hp.com>
+ *
+ *	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.  
+ *
+ *	The initial version of this is by Martin Peterson.  Alex deVries
+ *	has spent a bit of time trying to coax it into working.
+ *
+ *      Major changes to get basic interrupt infrastructure working to
+ *      hopefully be able to support all SuperIO devices. Currently
+ *      works with serial. -- John Marvin <jsm@fc.hp.com>
+ */
+
+
+/* NOTES:
+ * 
+ * Function 0 is an IDE controller. It is identical to a PC87415 IDE
+ * controller (and identifies itself as such).
+ *
+ * Function 1 is a "Legacy I/O" controller. Under this function is a
+ * whole mess of legacy I/O peripherals. Of course, HP hasn't enabled
+ * all the functionality in hardware, but the following is available:
+ *
+ *      Two 16550A compatible serial controllers
+ *      An IEEE 1284 compatible parallel port
+ *      A floppy disk controller
+ *
+ * Function 2 is a USB controller.
+ *
+ * We must be incredibly careful during initialization.  Since all
+ * interrupts are routed through function 1 (which is not allowed by
+ * the PCI spec), we need to program the PICs on the legacy I/O port
+ * *before* we attempt to set up IDE and USB.  @#$!&
+ *
+ * According to HP, devices are only enabled by firmware if they have
+ * a physical device connected.
+ *
+ * Configuration register bits:
+ *     0x5A: FDC, SP1, IDE1, SP2, IDE2, PAR, Reserved, P92
+ *     0x5B: RTC, 8259, 8254, DMA1, DMA2, KBC, P61, APM
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/serial.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/parport.h>
+#include <linux/parport_pc.h>
+#include <linux/serial_reg.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/gsc.h>
+#include <asm/irq.h>
+#include <asm/superio.h>
+
+static struct superio_device sio_dev = {
+	iosapic_irq: -1
+};
+
+
+#undef DEBUG_INIT
+
+void
+superio_inform_irq(int irq)
+{
+    if (sio_dev.iosapic_irq != -1) {
+	printk(KERN_ERR "SuperIO: superio_inform_irq called twice! (more than one SuperIO?)\n");
+	BUG();
+	return;
+    }
+
+    sio_dev.iosapic_irq = irq;
+}
+
+static void
+superio_interrupt(int irq, void *devp, struct pt_regs *regs)
+{
+	struct superio_device *sio = (struct superio_device *)devp;
+	u8 results;
+	u8 local_irq;
+
+	/* Poll the 8259 to see if there's an interrupt. */
+	outb (OCW3_POLL,IC_PIC1+0);
+
+	results = inb(IC_PIC1+0);
+
+	if ((results & 0x80) == 0) {
+#ifndef CONFIG_SMP
+		/* HACK: need to investigate why this happens if SMP enabled */
+		BUG(); /* This shouldn't happen */
+#endif
+		return;
+	}
+
+	/* Check to see which device is interrupting */
+
+	local_irq = results & 0x0f;
+
+	if (local_irq == 2 || local_irq > 7) {
+		printk(KERN_ERR "SuperIO: slave interrupted!\n");
+		BUG();
+		return;
+	}
+
+	if (local_irq == 7) {
+
+		/* Could be spurious. Check in service bits */
+
+		outb(OCW3_ISR,IC_PIC1+0);
+		results = inb(IC_PIC1+0);
+		if ((results & 0x80) == 0) { /* if ISR7 not set: spurious */
+			printk(KERN_WARNING "SuperIO: spurious interrupt!\n");
+			return;
+		}
+	}
+
+	/* Call the appropriate device's interrupt */
+
+	do_irq(&sio->irq_region->action[local_irq],
+		sio->irq_region->data.irqbase + local_irq,
+		regs);
+
+	/* set EOI */
+
+	outb((OCW2_SEOI|local_irq),IC_PIC1 + 0);
+	return;
+}
+
+/* Initialize Super I/O device */
+
+static void __devinit
+superio_init(struct superio_device *sio)
+{
+	struct pci_dev *pdev = sio->lio_pdev;
+	u16 word;
+	u8  i;
+
+	if (!pdev || sio->iosapic_irq == -1) {
+		printk(KERN_ERR "All SuperIO functions not found!\n");
+		BUG();
+		return;
+	}
+
+	printk (KERN_INFO "SuperIO: Found NS87560 Legacy I/O device at %s (IRQ %i) \n",
+		pdev->slot_name,sio->iosapic_irq);
+
+	/* Find our I/O devices */
+	pci_read_config_word (pdev, SIO_SP1BAR, &sio->sp1_base);
+	sio->sp1_base &= ~1;
+	printk (KERN_INFO "SuperIO: Serial port 1 at 0x%x\n", sio->sp1_base);
+
+	pci_read_config_word (pdev, SIO_SP2BAR, &sio->sp2_base);
+	sio->sp2_base &= ~1;
+	printk (KERN_INFO "SuperIO: Serial port 2 at 0x%x\n", sio->sp2_base);
+
+	pci_read_config_word (pdev, SIO_PPBAR, &sio->pp_base);
+	sio->pp_base &= ~1;
+	printk (KERN_INFO "SuperIO: Parallel port at 0x%x\n", sio->pp_base);
+
+	pci_read_config_word (pdev, SIO_FDCBAR, &sio->fdc_base);
+	sio->fdc_base &= ~1;
+	printk (KERN_INFO "SuperIO: Floppy controller at 0x%x\n", sio->fdc_base);
+	pci_read_config_word (pdev, SIO_ACPIBAR, &sio->acpi_base);
+	sio->acpi_base &= ~1;
+	printk (KERN_INFO "SuperIO: ACPI at 0x%x\n", sio->acpi_base);
+
+	request_region (IC_PIC1, 0x1f, "pic1");
+	request_region (IC_PIC2, 0x1f, "pic2");
+	request_region (sio->acpi_base, 0x1f, "acpi");
+
+	/* Enable the legacy I/O function */
+        pci_read_config_word (pdev, PCI_COMMAND, &word);
+	word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO;
+	pci_write_config_word (pdev, PCI_COMMAND, word);
+	pci_set_master (pdev);
+
+	/* Next project is programming the onboard interrupt
+	 * controllers.  PDC hasn't done this for us, since it's using
+	 * polled I/O.
+	 */
+
+	/* Set PIC interrupts to edge triggered */
+	pci_write_config_byte (pdev, TRIGGER_1, 0x0);
+	pci_write_config_byte (pdev, TRIGGER_2, 0x0);
+
+	/* Disable all interrupt routing */
+	for (i = IR_LOW ; i < IR_HIGH ; i++)
+		pci_write_config_byte (pdev, i, 0x0);
+
+	/* PIC1 Initialization Command Word register programming */
+	outb (0x11,IC_PIC1+0);	/* ICW1: ICW4 write req | ICW1 */
+	outb (0x00,IC_PIC1+1);	/* ICW2: N/A */
+	outb (0x04,IC_PIC1+1);	/* ICW3: Cascade */
+	outb (0x01,IC_PIC1+1);	/* ICW4: x86 mode */
+
+	/* PIC1 Program Operational Control Words */
+	outb (0xff,IC_PIC1+1);	/* OCW1: Mask all interrupts */
+	outb (0xc2,IC_PIC1+0);  /* OCW2: priority (3-7,0-2) */
+
+	/* PIC2 Initialization Command Word register programming */
+	outb (0x11,IC_PIC2+0);	/* ICW1: ICW4 write req | ICW1 */
+	outb (0x00,IC_PIC2+1);	/* ICW2: N/A */
+	outb (0x02,IC_PIC2+1);	/* ICW3: Slave ID code */
+	outb (0x01,IC_PIC2+1);	/* ICW4: x86 mode */
+		
+	/* Program Operational Control Words */
+	outb (0xff,IC_PIC1+1);	/* OCW1: Mask all interrupts */
+	outb (0x68,IC_PIC1+0);	/* OCW3: OCW3 select | ESMM | SMM */
+
+	/* Write master mask reg */
+
+	outb (0xff,IC_PIC1+1);
+
+	/* Set up interrupt routing */
+
+	pci_write_config_byte (pdev, IR_USB, 0x10); /* USB on IRQ1 */
+	pci_write_config_byte (pdev, IR_SER, 0x43); /* SP1 on IRQ3, SP2 on IRQ4 */
+	pci_write_config_byte (pdev, IR_PFD, 0x65); /* PAR on IRQ5, FDC on IRQ6 */
+	pci_write_config_byte (pdev, IR_IDE, 0x07); /* IDE1 on IRQ7 */
+	
+	/* Set USB and IDE to level triggered interrupts, rest to edge */
+	pci_write_config_byte (pdev, TRIGGER_1, 0x82); /* IRQ 1 and 7 */
+
+	/* Setup USB power regulation */
+	outb(1, sio->acpi_base + USB_REG_CR);
+	if (inb(sio->acpi_base + USB_REG_CR) & 1)
+		printk(KERN_INFO "SuperIO: USB regulator enabled\n");
+	else
+		printk(KERN_ERR "USB regulator not initialized!\n");
+
+	pci_enable_device(pdev);
+
+	if (request_irq(sio->iosapic_irq,superio_interrupt,SA_INTERRUPT,
+			"SuperIO",(void *)sio)) {
+
+		printk(KERN_ERR "SuperIO: could not get irq\n");
+		BUG();
+		return;
+	}
+
+	sio->iosapic_irq_enabled = 1;
+	
+}
+
+static void
+superio_disable_irq(void *dev, int local_irq)
+{
+	u8 r8;
+
+	if ((local_irq < 1) || (local_irq == 2) || (local_irq > 7)) {
+	    printk(KERN_ERR "SuperIO: Illegal irq number.\n");
+	    BUG();
+	    return;
+	}
+
+	/* Mask interrupt */
+
+	r8 = inb(IC_PIC1+1);
+	r8 |= (1 << local_irq);
+	outb (r8,IC_PIC1+1);
+}
+
+static void
+superio_enable_irq(void *dev, int local_irq)
+{
+	struct superio_device *sio = (struct superio_device *)dev;
+	u8 r8;
+
+	if ((local_irq < 1) || (local_irq == 2) || (local_irq > 7)) {
+	    printk(KERN_ERR "SuperIO: Illegal irq number.\n");
+	    BUG();
+	    return;
+	}
+
+	/*
+	 * It's possible that we haven't initialized the legacy IO
+	 * function yet. If not, do it now.
+	 */
+
+	if (!sio->iosapic_irq_enabled)
+		superio_init(sio);
+
+	/* Unmask interrupt */
+
+	r8 = inb(IC_PIC1+1);
+	r8 &= ~(1 << local_irq);
+	outb (r8,IC_PIC1+1);
+}
+
+static void
+superio_mask_irq(void *dev, int local_irq)
+{
+	BUG();
+}
+
+static void
+superio_unmask_irq(void *dev, int local_irq)
+{
+	BUG();
+}
+
+static struct irq_region_ops superio_irq_ops = {
+	disable_irq:	superio_disable_irq,
+	enable_irq:	superio_enable_irq,
+	mask_irq:	superio_mask_irq,
+	unmask_irq:	superio_unmask_irq
+};
+
+#ifdef DEBUG_INIT
+static unsigned short expected_device[3] = {
+	PCI_DEVICE_ID_NS_87415,
+	PCI_DEVICE_ID_NS_87560_LIO,
+	PCI_DEVICE_ID_NS_87560_USB
+};
+#endif
+
+int superio_fixup_irq(struct pci_dev *pcidev)
+{
+	int local_irq;
+
+#ifdef DEBUG_INIT
+	int fn;
+	fn = PCI_FUNC(pcidev->devfn);
+
+	/* Verify the function number matches the expected device id. */
+	if (expected_device[fn] != pcidev->device) {
+		BUG();
+		return -1;
+	}
+	printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %p\n",
+		pcidev->slot_name,
+		pcidev->vendor, pcidev->device,
+		__builtin_return_address(0));
+#endif
+
+	if (!sio_dev.irq_region) {
+		/* Allocate an irq region for SuperIO devices */
+		sio_dev.irq_region = alloc_irq_region(SUPERIO_NIRQS,
+						&superio_irq_ops,
+						"SuperIO", (void *) &sio_dev);
+		if (!sio_dev.irq_region) {
+			printk(KERN_WARNING "SuperIO: alloc_irq_region failed\n");
+			return -1;
+		}
+	}
+
+	/*
+	 * We don't allocate a SuperIO irq for the legacy IO function,
+	 * since it is a "bridge". Instead, we will allocate irq's for
+	 * each legacy device as they are initialized.
+	 */
+
+	switch(pcidev->device) {
+	case PCI_DEVICE_ID_NS_87415:		/* Function 0 */
+		local_irq = IDE_IRQ;
+		break;
+	case PCI_DEVICE_ID_NS_87560_LIO:	/* Function 1 */
+		sio_dev.lio_pdev = pcidev; /* save for later initialization */
+		return -1;
+	case PCI_DEVICE_ID_NS_87560_USB:	/* Function 2 */
+		local_irq = USB_IRQ;
+		break;
+	default:
+		local_irq = -1;
+		BUG();
+		break;
+	}
+
+	return(sio_dev.irq_region->data.irqbase + local_irq);
+}
+
+void __devinit
+superio_serial_init(void)
+{
+#ifdef CONFIG_SERIAL
+	struct serial_struct *serial;
+	int retval;
+	
+	if (!sio_dev.irq_region)
+		return; /* superio not present */
+
+	if (!sio_dev.iosapic_irq_enabled)
+		superio_init(&sio_dev);
+
+	serial = kmalloc(2 * sizeof (struct serial_struct), GFP_KERNEL);
+
+	if (!serial) {
+		printk(KERN_WARNING "SuperIO: Could not get memory for serial struct.\n");
+		return;
+	}
+
+	memset(serial, 0, 2 * sizeof (struct serial_struct));
+
+	serial->type = PORT_16550A;
+	serial->line = 0;
+	serial->port = sio_dev.sp1_base;
+	serial->port_high = 0;
+	serial->irq = sio_dev.irq_region->data.irqbase + SP1_IRQ;
+	serial->io_type = SERIAL_IO_PORT;
+	serial->flags = 0;
+	serial->xmit_fifo_size = 16;
+	serial->custom_divisor = 0;
+	serial->baud_base = 115200;
+
+	retval = register_serial(serial);
+	if (retval < 0) {
+		printk(KERN_WARNING "SuperIO: Register Serial #0 failed.\n");
+		kfree (serial);
+		return;
+	}
+
+	serial++;
+
+	serial->type = PORT_16550A;
+	serial->line = 1;
+	serial->port = sio_dev.sp2_base;
+	serial->port_high = 0;
+	serial->irq = sio_dev.irq_region->data.irqbase + SP2_IRQ;
+	serial->io_type = SERIAL_IO_PORT;
+	serial->flags = 0;
+	serial->xmit_fifo_size = 16;
+	serial->custom_divisor = 0;
+	serial->baud_base = 115200;
+
+	retval = register_serial(serial);
+	if (retval < 0)
+		printk(KERN_WARNING "SuperIO: Register Serial #1 failed.\n");
+#endif /* CONFIG_SERIAL */
+}
+
+EXPORT_SYMBOL(superio_serial_init);
+
+
+#ifdef CONFIG_PARPORT_PC
+void __devinit
+superio_parport_init(void)
+{
+	if (!sio_dev.irq_region)
+		return; /* superio not present */
+
+	if (!sio_dev.iosapic_irq_enabled)
+		superio_init(&sio_dev);
+
+	if (!parport_pc_probe_port(sio_dev.pp_base, 
+		0 /*base_hi*/,
+		sio_dev.irq_region->data.irqbase + PAR_IRQ, 
+		PARPORT_DMA_NONE /* dma */,
+		NULL /*struct pci_dev* */))
+
+		printk(KERN_WARNING "SuperIO: Probing parallel port failed.\n");
+}
+
+EXPORT_SYMBOL(superio_parport_init);
+#endif	/* CONFIG_PARPORT_PC */
+
+
+int
+superio_get_ide_irq(void)
+{
+	if (sio_dev.irq_region)
+		return sio_dev.irq_region->data.irqbase + IDE_IRQ;
+	else
+		return 0;
+}
+
+EXPORT_SYMBOL(superio_get_ide_irq);
+
+static int __devinit superio_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+#ifdef DEBUG_INIT
+	printk("superio_probe(%s) ven 0x%x dev 0x%x sv 0x%x sd 0x%x class 0x%x\n",
+		dev->slot_name,
+		dev->vendor, dev->device,
+		dev->subsystem_vendor, dev->subsystem_device,
+		dev->class);
+/*
+** superio_probe(00:0e.0) ven 0x100b dev 0x2 sv 0x0 sd 0x0 class 0x1018a
+** superio_probe(00:0e.1) ven 0x100b dev 0xe sv 0x0 sd 0x0 class 0x68000
+** superio_probe(00:0e.2) ven 0x100b dev 0x12 sv 0x0 sd 0x0 class 0xc0310
+*/
+#endif
+
+	/* superio_fixup_irq(dev); */
+
+	if (dev->device == PCI_DEVICE_ID_NS_87560_LIO) {
+#ifdef CONFIG_PARPORT_PC
+		superio_parport_init();
+#endif
+		/* Don't call superio_serial_init() - see rs_init() */
+		/* REVISIT : superio_fdc_init() ? */
+		return 0;
+	}
+	else
+	{
+		/* don't claim this device; let whatever either driver
+		 * do it 
+		 */ 
+		return -1;
+	}
+}
+
+static struct pci_device_id superio_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NS, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, }
+};
+
+static struct pci_driver superio_driver = {
+	name:		"SuperIO",
+	id_table:	superio_tbl,
+	probe:		superio_probe,
+};
+
+static int __init superio_modinit(void)
+{
+	return pci_module_init(&superio_driver);
+}
+
+static void __exit superio_exit(void)
+{
+	pci_unregister_driver(&superio_driver);
+}
+
+module_init(superio_modinit);
+module_exit(superio_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/sys32.h linux-2.4.20/arch/parisc/kernel/sys32.h
--- linux-2.4.19/arch/parisc/kernel/sys32.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/sys32.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,33 @@
+#ifndef _PARISC64_KERNEL_SYS32_H
+#define _PARISC64_KERNEL_SYS32_H
+
+/* Call a kernel syscall which will use kernel space instead of user
+ * space for its copy_to/from_user.
+ */
+#define KERNEL_SYSCALL(ret, syscall, args...) \
+{ \
+    mm_segment_t old_fs = get_fs(); \
+    set_fs(KERNEL_DS); \
+    ret = syscall(args); \
+    set_fs (old_fs); \
+}
+
+struct timeval32 {
+	int tv_sec;
+	int tv_usec;
+};
+
+typedef __u32 __sighandler_t32;
+
+#include <linux/signal.h>
+typedef struct {
+	unsigned int sig[_NSIG_WORDS * 2];
+} sigset_t32;
+
+struct sigaction32 {
+	__sighandler_t32 sa_handler;
+	unsigned int sa_flags;
+	sigset_t32 sa_mask;		/* mask last for extensibility */
+};
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/sys_parisc.c linux-2.4.20/arch/parisc/kernel/sys_parisc.c
--- linux-2.4.19/arch/parisc/kernel/sys_parisc.c	2001-03-19 20:35:11.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/sys_parisc.c	2002-10-29 11:18:49.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * linux/arch/parisc/kernel/sys_parisc.c
  *
- * this implements the missing syscalls.
+ * this implements syscalls which are handled per-arch.
  */
 
 #include <asm/uaccess.h>
@@ -10,26 +10,15 @@
 #include <linux/linkage.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
+#include <linux/shm.h>
 #include <linux/smp_lock.h>
 
-/* for some reason, "old_readdir" is the only syscall which does not begin
- * with "sys_", which breaks the ENTRY_* macros in syscall.S so I "fixed"
- * it here.
- */
-
-int sys_old_readdir(unsigned int fd, void *dirent, unsigned int count)
-{
-    return old_readdir(fd, dirent, count);
-}
-
 int sys_pipe(int *fildes)
 {
 	int fd[2];
 	int error;
 
-	lock_kernel();
 	error = do_pipe(fd);
-	unlock_kernel();
 	if (!error) {
 		if (copy_to_user(fildes, fd, 2*sizeof(int)))
 			error = -EFAULT;
@@ -44,40 +33,117 @@
 	return -ERESTARTNOHAND;
 }
 
-int sys_mmap(unsigned long addr, unsigned long len,
-		unsigned long prot, unsigned long flags, unsigned long fd,
-		unsigned long offset)
+static unsigned long get_unshared_area(unsigned long addr, unsigned long len)
 {
-	struct file * file = NULL;
-	int error;
+	struct vm_area_struct *vma;
 
-	down_write(&current->mm->mmap_sem);
-	lock_kernel();
+	if (!addr)
+		addr = TASK_UNMAPPED_BASE;
+	addr = PAGE_ALIGN(addr);
+
+	for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
+		/* At this point:  (!vma || addr < vma->vm_end). */
+		if (TASK_SIZE - len < addr)
+			return -ENOMEM;
+		if (!vma || addr + len <= vma->vm_start)
+			return addr;
+		addr = vma->vm_end;
+	}
+}
+
+#define DCACHE_ALIGN(addr) (((addr) + (SHMLBA - 1)) &~ (SHMLBA - 1))
+
+static unsigned long get_shared_area(struct inode *inode, unsigned long addr,
+		unsigned long len, unsigned long pgoff)
+{
+	struct vm_area_struct *vma, *first_vma;
+	int offset;
+
+	first_vma = inode->i_mapping->i_mmap_shared;
+	offset = (first_vma->vm_start + ((pgoff - first_vma->vm_pgoff) << PAGE_SHIFT)) & (SHMLBA - 1);
+
+	if (!addr)
+		addr = TASK_UNMAPPED_BASE;
+	addr = DCACHE_ALIGN(addr - offset) + offset;
+
+	for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
+		/* At this point:  (!vma || addr < vma->vm_end). */
+		if (TASK_SIZE - len < addr)
+			return -ENOMEM;
+		if (!vma || addr + len <= vma->vm_start)
+			return addr;
+		addr = DCACHE_ALIGN(vma->vm_end - offset) + offset;
+		if (addr < vma->vm_end) /* handle wraparound */
+			return -ENOMEM;
+	}
+}
+
+unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
+		unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+	struct inode *inode = NULL;
+
+	if (len > TASK_SIZE)
+		return -ENOMEM;
+
+	if (filp) {
+		inode = filp->f_dentry->d_inode;
+	}
+
+	if (inode && (flags & MAP_SHARED) && (inode->i_mapping->i_mmap_shared)) {
+		addr = get_shared_area(inode, addr, len, pgoff);
+	} else {
+		addr = get_unshared_area(addr, len);
+	}
+	return addr;
+}
+
+static unsigned long do_mmap2(unsigned long addr, unsigned long len,
+	unsigned long prot, unsigned long flags, unsigned long fd,
+	unsigned long pgoff)
+{
+	struct file * file = NULL;
+	unsigned long error = -EBADF;
 	if (!(flags & MAP_ANONYMOUS)) {
-		error = -EBADF;
 		file = fget(fd);
 		if (!file)
 			goto out;
 	}
+
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-	error = do_mmap(file, addr, len, prot, flags, offset);
+
+	down_write(&current->mm->mmap_sem);
+	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+	up_write(&current->mm->mmap_sem);
+
 	if (file != NULL)
 		fput(file);
 out:
-	unlock_kernel();
-	up_write(&current->mm->mmap_sem);
 	return error;
 }
 
-int sys_ioperm(unsigned long from, unsigned long num, int on)
+asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len,
+	unsigned long prot, unsigned long flags, unsigned long fd,
+	unsigned long pgoff)
 {
-	return -ENOSYS;
+	/* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE
+	   we have. */
+	return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12));
 }
 
-long sys_shmat_wrapper(int shmid, void *shmaddr, int shmflag)
+asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
+		unsigned long prot, unsigned long flags, unsigned long fd,
+		unsigned long offset)
+{
+	if (!(offset & ~PAGE_MASK)) {
+		return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+	} else {
+		return -EINVAL;
+	}
+}
+
+long sys_shmat_wrapper(int shmid, char *shmaddr, int shmflag)
 {
-	extern int sys_shmat(int shmid, char *shmaddr, int shmflg,
-			     unsigned long * raddr);
 	unsigned long raddr;
 	int r;
 
@@ -86,3 +152,107 @@
 		return r;
 	return raddr;
 }
+
+
+/*
+ * FIXME, please remove this crap as soon as possible
+ *
+ * This is here to fix up broken glibc structures, 
+ * which are already fixed in newer glibcs
+ */
+#include <linux/msg.h>
+#include <linux/sem.h>
+#include <linux/shm.h>
+#include "sys32.h"
+
+struct broken_ipc_perm
+{
+    key_t key;			/* Key.  */
+    uid_t uid;			/* Owner's user ID.  */
+    gid_t gid;			/* Owner's group ID.  */
+    uid_t cuid;			/* Creator's user ID.  */
+    gid_t cgid;			/* Creator's group ID.  */
+    unsigned short int mode;		/* Read/write permission.  */
+    unsigned short int __pad1;
+    unsigned short int seq;		/* Sequence number.  */
+    unsigned short int __pad2;
+    unsigned long int __unused1;
+    unsigned long int __unused2;
+};
+		    
+struct broken_shmid64_ds {
+	struct broken_ipc_perm	shm_perm;	/* operation perms */
+	size_t			shm_segsz;	/* size of segment (bytes) */
+#ifndef __LP64__
+	unsigned int		__pad1;
+#endif
+	__kernel_time_t		shm_atime;	/* last attach time */
+#ifndef __LP64__
+	unsigned int		__pad2;
+#endif
+	__kernel_time_t		shm_dtime;	/* last detach time */
+#ifndef __LP64__
+	unsigned int		__pad3;
+#endif
+	__kernel_time_t		shm_ctime;	/* last change time */
+	__kernel_pid_t		shm_cpid;	/* pid of creator */
+	__kernel_pid_t		shm_lpid;	/* pid of last operator */
+	unsigned int		shm_nattch;	/* no. of current attaches */
+	unsigned int		__unused1;
+	unsigned int		__unused2;
+};
+
+static void convert_broken_perm (struct broken_ipc_perm *out, struct ipc64_perm *in)
+{
+	out->key  = in->key;
+	out->uid  = in->uid;
+	out->gid  = in->gid;
+	out->cuid = in->cuid;
+	out->cgid = in->cgid;
+	out->mode = in->mode;
+	out->seq  = in->seq;
+}
+
+static int copyout_broken_shmid64(struct broken_shmid64_ds *buf, struct shmid64_ds *sbuf)
+{
+	struct broken_shmid64_ds tbuf;
+	
+	memset(&tbuf, 0, sizeof tbuf);
+	convert_broken_perm (&tbuf.shm_perm, &sbuf->shm_perm);
+	tbuf.shm_segsz = sbuf->shm_segsz;
+	tbuf.shm_atime = sbuf->shm_atime;
+	tbuf.shm_dtime = sbuf->shm_dtime;
+	tbuf.shm_ctime = sbuf->shm_ctime;
+	tbuf.shm_cpid = sbuf->shm_cpid;
+	tbuf.shm_lpid = sbuf->shm_lpid;
+	tbuf.shm_nattch = sbuf->shm_nattch;
+	return copy_to_user(buf, &tbuf, sizeof tbuf);
+}
+
+int sys_msgctl_broken(int msqid, int cmd, struct msqid_ds *buf)
+{
+	return sys_msgctl (msqid, cmd & ~IPC_64, buf);
+}
+
+int sys_semctl_broken(int semid, int semnum, int cmd, union semun arg)
+{
+	return sys_semctl (semid, semnum, cmd & ~IPC_64, arg);
+}
+
+int sys_shmctl_broken(int shmid, int cmd, struct shmid64_ds *buf)
+{
+	struct shmid64_ds sbuf;
+	int err;
+
+	if (cmd & IPC_64) {
+		cmd &= ~IPC_64;
+		if (cmd == IPC_STAT || cmd == SHM_STAT) {
+			KERNEL_SYSCALL(err, sys_shmctl, shmid, cmd, (struct shmid_ds *)&sbuf);
+			if (err == 0)
+				err = copyout_broken_shmid64((struct broken_shmid64_ds *)buf, &sbuf);
+			return err;
+		}
+	}
+	return sys_shmctl (shmid, cmd, (struct shmid_ds *)buf);
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/sys_parisc32.c linux-2.4.20/arch/parisc/kernel/sys_parisc32.c
--- linux-2.4.19/arch/parisc/kernel/sys_parisc32.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/sys_parisc32.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,3117 @@
+/*
+ * sys_parisc32.c: Conversion between 32bit and 64bit native syscalls.
+ *
+ * Copyright (C) 2000-2001 Hewlett Packard Company
+ * Copyright (C) 2000 John Marvin
+ * Copyright (C) 2001 Matthew Wilcox
+ *
+ * These routines maintain argument size conversion between 32bit and 64bit
+ * environment. Based heavily on sys_ia32.c and sys_sparc32.c.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h> 
+#include <linux/mm.h> 
+#include <linux/file.h> 
+#include <linux/signal.h>
+#include <linux/utime.h>
+#include <linux/resource.h>
+#include <linux/times.h>
+#include <linux/utsname.h>
+#include <linux/timex.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/slab.h>
+#include <linux/uio.h>
+#include <linux/nfs_fs.h>
+#include <linux/smb_fs.h>
+#include <linux/smb_mount.h>
+#include <linux/ncp_fs.h>
+#include <linux/quota.h>
+#include <linux/module.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/cache.h>
+#include <linux/nfsd/xdr.h>
+#include <linux/nfsd/syscall.h>
+#include <linux/poll.h>
+#include <linux/personality.h>
+#include <linux/stat.h>
+#include <linux/filter.h>			/* for setsockopt() */
+#include <linux/icmpv6.h>			/* for setsockopt() */
+#include <linux/netfilter_ipv4/ip_queue.h>	/* for setsockopt() */
+#include <linux/netfilter_ipv4/ip_tables.h>	/* for setsockopt() */
+#include <linux/netfilter_ipv6/ip6_tables.h>	/* for setsockopt() */
+#include <linux/highmem.h>
+#include <linux/highuid.h>
+#include <linux/mman.h>
+
+#include <asm/types.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+#include "sys32.h"
+
+#define A(__x) ((unsigned long)(__x))
+
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x)	printk x
+#else
+#define DBG(x)
+#endif
+
+
+/*
+ * count32() counts the number of arguments/envelopes. It is basically
+ *           a copy of count() from fs/exec.c, except that it works
+ *           with 32 bit argv and envp pointers.
+ */
+
+static int count32(u32 *argv, int max)
+{
+	int i = 0;
+
+	if (argv != NULL) {
+		for (;;) {
+			u32 p;
+			int error;
+
+			error = get_user(p,argv);
+			if (error)
+				return error;
+			if (!p)
+				break;
+			argv++;
+			if(++i > max)
+				return -E2BIG;
+		}
+	}
+	return i;
+}
+
+
+/*
+ * copy_strings32() is basically a copy of copy_strings() from fs/exec.c
+ *                  except that it works with 32 bit argv and envp pointers.
+ */
+
+
+static int copy_strings32(int argc, u32 *argv, struct linux_binprm *bprm)
+{
+	while (argc-- > 0) {
+		u32 str;
+		int len;
+		unsigned long pos;
+
+		if (get_user(str, argv + argc) ||
+		    !str ||
+		    !(len = strnlen_user((char *)A(str), bprm->p)))
+			return -EFAULT;
+
+		if (bprm->p < len) 
+			return -E2BIG; 
+
+		bprm->p -= len;
+
+		pos = bprm->p;
+		while (len > 0) {
+			char *kaddr;
+			int i, new, err;
+			struct page *page;
+			int offset, bytes_to_copy;
+
+			offset = pos % PAGE_SIZE;
+			i = pos/PAGE_SIZE;
+			page = bprm->page[i];
+			new = 0;
+			if (!page) {
+				page = alloc_page(GFP_HIGHUSER);
+				bprm->page[i] = page;
+				if (!page)
+					return -ENOMEM;
+				new = 1;
+			}
+			kaddr = (char *)kmap(page);
+
+			if (new && offset)
+				memset(kaddr, 0, offset);
+			bytes_to_copy = PAGE_SIZE - offset;
+			if (bytes_to_copy > len) {
+				bytes_to_copy = len;
+				if (new)
+					memset(kaddr+offset+len, 0, PAGE_SIZE-offset-len);
+			}
+			err = copy_from_user(kaddr + offset, (char *)A(str), bytes_to_copy);
+			flush_dcache_page(page);
+			flush_page_to_ram(page);
+			kunmap(page);
+
+			if (err)
+				return -EFAULT; 
+
+			pos += bytes_to_copy;
+			str += bytes_to_copy;
+			len -= bytes_to_copy;
+		}
+	}
+	return 0;
+}
+
+/*
+ * do_execve32() is mostly a copy of do_execve(), with the exception
+ * that it processes 32 bit argv and envp pointers.
+ */
+
+static inline int 
+do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
+{
+	struct linux_binprm bprm;
+	struct file *file;
+	int retval;
+	int i;
+
+	file = open_exec(filename);
+
+	retval = PTR_ERR(file);
+	if (IS_ERR(file))
+		return retval;
+
+	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+	memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
+
+	DBG(("do_execve32(%s, %p, %p, %p)\n", filename, argv, envp, regs));
+
+	bprm.file = file;
+	bprm.filename = filename;
+	bprm.sh_bang = 0;
+	bprm.loader = 0;
+	bprm.exec = 0;
+	if ((bprm.argc = count32(argv, bprm.p / sizeof(u32))) < 0) {
+		allow_write_access(file);
+		fput(file);
+		return bprm.argc;
+	}
+	if ((bprm.envc = count32(envp, bprm.p / sizeof(u32))) < 0) {
+		allow_write_access(file);
+		fput(file);
+		return bprm.envc;
+	}
+
+	retval = prepare_binprm(&bprm);
+	if (retval < 0)
+		goto out;
+	
+	retval = copy_strings_kernel(1, &bprm.filename, &bprm);
+	if (retval < 0)
+		goto out;
+
+	bprm.exec = bprm.p;
+	retval = copy_strings32(bprm.envc, envp, &bprm);
+	if (retval < 0)
+		goto out;
+
+	retval = copy_strings32(bprm.argc, argv, &bprm);
+	if (retval < 0)
+		goto out;
+
+	retval = search_binary_handler(&bprm,regs);
+	if (retval >= 0)
+		/* execve success */
+		return retval;
+
+out:
+	/* Something went wrong, return the inode and free the argument pages*/
+	allow_write_access(bprm.file);
+	if (bprm.file)
+		fput(bprm.file);
+
+	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+		struct page * page = bprm.page[i];
+		if (page)
+			__free_page(page);
+	}
+
+	return retval;
+}
+
+/*
+ * sys32_execve() executes a new program.
+ */
+
+asmlinkage int sys32_execve(struct pt_regs *regs)
+{
+	int error;
+	char *filename;
+
+	DBG(("sys32_execve(%p) r26 = 0x%lx\n", regs, regs->gr[26]));
+	filename = getname((char *) regs->gr[26]);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		goto out;
+	error = do_execve32(filename, (u32 *) regs->gr[25],
+		(u32 *) regs->gr[24], regs);
+	if (error == 0)
+		current->ptrace &= ~PT_DTRACE;
+	putname(filename);
+out:
+
+	return error;
+}
+
+asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23,
+	int r22, int r21, int r20)
+{
+    printk(KERN_ERR "%s(%d): Unimplemented 32 on 64 syscall #%d!\n", 
+    	current->comm, current->pid, r20);
+    return -ENOSYS;
+}
+
+/* 32-bit user apps use struct statfs which uses 'long's */
+struct statfs32 {
+	__s32 f_type;
+	__s32 f_bsize;
+	__s32 f_blocks;
+	__s32 f_bfree;
+	__s32 f_bavail;
+	__s32 f_files;
+	__s32 f_ffree;
+	__kernel_fsid_t f_fsid;
+	__s32 f_namelen;
+	__s32 f_spare[6];
+};
+
+/* convert statfs struct to statfs32 struct and copy result to user */
+static unsigned long statfs32_to_user(struct statfs32 *ust32, struct statfs *st)
+{
+    struct statfs32 st32;
+#undef CP
+#define CP(a) st32.a = st->a
+    CP(f_type);
+    CP(f_bsize);
+    CP(f_blocks);
+    CP(f_bfree);
+    CP(f_bavail);
+    CP(f_files);
+    CP(f_ffree);
+    CP(f_fsid);
+    CP(f_namelen);
+    return copy_to_user(ust32, &st32, sizeof st32);
+}
+
+/* The following statfs calls are copies of code from linux/fs/open.c and
+ * should be checked against those from time to time */
+asmlinkage long sys32_statfs(const char * path, struct statfs32 * buf)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk(path, &nd);
+	if (!error) {
+		struct statfs tmp;
+		error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
+		if (!error && statfs32_to_user(buf, &tmp))
+			error = -EFAULT;
+		path_release(&nd);
+	}
+	return error;
+}
+
+asmlinkage long sys32_fstatfs(unsigned int fd, struct statfs32 * buf)
+{
+	struct file * file;
+	struct statfs tmp;
+	int error;
+
+	error = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto out;
+	error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
+	if (!error && statfs32_to_user(buf, &tmp))
+		error = -EFAULT;
+	fput(file);
+out:
+	return error;
+}
+
+/* These may not work without my local types changes, but I wanted the
+ * code available in case it's useful to others. -PB
+ */
+
+/* from utime.h */
+struct utimbuf32 {
+	__kernel_time_t32 actime;
+	__kernel_time_t32 modtime;
+};
+
+asmlinkage long sys32_utime(char *filename, struct utimbuf32 *times)
+{
+    struct utimbuf32 times32;
+    struct utimbuf times64;
+    extern long sys_utime(char *filename, struct utimbuf *times);
+    char *fname;
+    long ret;
+
+    if (!times)
+    	return sys_utime(filename, NULL);
+
+    /* get the 32-bit struct from user space */
+    if (copy_from_user(&times32, times, sizeof times32))
+    	return -EFAULT;
+
+    /* convert it into the 64-bit one */
+    times64.actime = times32.actime;
+    times64.modtime = times32.modtime;
+
+    /* grab the file name */
+    fname = getname(filename);
+
+    KERNEL_SYSCALL(ret, sys_utime, fname, &times64);
+
+    /* free the file name */
+    putname(fname);
+
+    return ret;
+}
+
+struct tms32 {
+	__kernel_clock_t32 tms_utime;
+	__kernel_clock_t32 tms_stime;
+	__kernel_clock_t32 tms_cutime;
+	__kernel_clock_t32 tms_cstime;
+};
+                                
+asmlinkage long sys32_times(struct tms32 *tbuf)
+{
+	struct tms t;
+	long ret;
+	extern asmlinkage long sys_times(struct tms * tbuf);
+int err;
+	
+	KERNEL_SYSCALL(ret, sys_times, tbuf ? &t : NULL);
+	if (tbuf) {
+		err = put_user (t.tms_utime, &tbuf->tms_utime);
+		err |= __put_user (t.tms_stime, &tbuf->tms_stime);
+		err |= __put_user (t.tms_cutime, &tbuf->tms_cutime);
+		err |= __put_user (t.tms_cstime, &tbuf->tms_cstime);
+		if (err)
+			ret = -EFAULT;
+	}
+	return ret;
+}
+
+struct flock32 {
+	short l_type;
+	short l_whence;
+	__kernel_off_t32 l_start;
+	__kernel_off_t32 l_len;
+	__kernel_pid_t32 l_pid;
+};
+
+
+static inline int get_flock(struct flock *kfl, struct flock32 *ufl)
+{
+	int err;
+	
+	err = get_user(kfl->l_type, &ufl->l_type);
+	err |= __get_user(kfl->l_whence, &ufl->l_whence);
+	err |= __get_user(kfl->l_start, &ufl->l_start);
+	err |= __get_user(kfl->l_len, &ufl->l_len);
+	err |= __get_user(kfl->l_pid, &ufl->l_pid);
+	return err;
+}
+
+static inline int put_flock(struct flock *kfl, struct flock32 *ufl)
+{
+	int err;
+	
+	err = __put_user(kfl->l_type, &ufl->l_type);
+	err |= __put_user(kfl->l_whence, &ufl->l_whence);
+	err |= __put_user(kfl->l_start, &ufl->l_start);
+	err |= __put_user(kfl->l_len, &ufl->l_len);
+	err |= __put_user(kfl->l_pid, &ufl->l_pid);
+	return err;
+}
+
+extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
+
+asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+	case F_GETLK:
+	case F_SETLK:
+	case F_SETLKW:
+		{
+			struct flock f;
+			long ret;
+			
+			if(get_flock(&f, (struct flock32 *)arg))
+				return -EFAULT;
+			KERNEL_SYSCALL(ret, sys_fcntl, fd, cmd, (unsigned long)&f);
+			if (ret) return ret;
+			if (f.l_start >= 0x7fffffffUL ||
+			    f.l_len >= 0x7fffffffUL ||
+			    f.l_start + f.l_len >= 0x7fffffffUL)
+				return -EOVERFLOW;
+			if(put_flock(&f, (struct flock32 *)arg))
+				return -EFAULT;
+			return 0;
+		}
+	default:
+		return sys_fcntl(fd, cmd, (unsigned long)arg);
+	}
+}
+
+#ifdef CONFIG_SYSCTL
+
+struct __sysctl_args32 {
+	u32 name;
+	int nlen;
+	u32 oldval;
+	u32 oldlenp;
+	u32 newval;
+	u32 newlen;
+	u32 __unused[4];
+};
+
+asmlinkage long sys32_sysctl(struct __sysctl_args32 *args)
+{
+	struct __sysctl_args32 tmp;
+	int error;
+	unsigned int oldlen32;
+	size_t oldlen, *oldlenp = NULL;
+	unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7;
+	extern int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
+	       void *newval, size_t newlen);
+
+	DBG(("sysctl32(%p)\n", args));
+
+	if (copy_from_user(&tmp, args, sizeof(tmp)))
+		return -EFAULT;
+
+	if (tmp.oldval && tmp.oldlenp) {
+		/* Duh, this is ugly and might not work if sysctl_args
+		   is in read-only memory, but do_sysctl does indirectly
+		   a lot of uaccess in both directions and we'd have to
+		   basically copy the whole sysctl.c here, and
+		   glibc's __sysctl uses rw memory for the structure
+		   anyway.  */
+		/* a possibly better hack than this, which will avoid the
+		 * problem if the struct is read only, is to push the
+		 * 'oldlen' value out to the user's stack instead. -PB
+		 */
+		if (get_user(oldlen32, (u32 *)(u64)tmp.oldlenp))
+			return -EFAULT;
+		oldlen = oldlen32;
+		if (put_user(oldlen, (size_t *)addr))
+			return -EFAULT;
+		oldlenp = (size_t *)addr;
+	}
+
+	lock_kernel();
+	error = do_sysctl((int *)(u64)tmp.name, tmp.nlen, (void *)(u64)tmp.oldval,
+			  oldlenp, (void *)(u64)tmp.newval, tmp.newlen);
+	unlock_kernel();
+	if (oldlenp) {
+		if (!error) {
+			if (get_user(oldlen, (size_t *)addr)) {
+				error = -EFAULT;
+			} else {
+				oldlen32 = oldlen;
+				if (put_user(oldlen32, (u32 *)(u64)tmp.oldlenp))
+					error = -EFAULT;
+			}
+		}
+		if (copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)))
+			error = -EFAULT;
+	}
+	return error;
+}
+
+#else /* CONFIG_SYSCTL */
+
+asmlinkage long sys32_sysctl(struct __sysctl_args *args)
+{
+	return -ENOSYS;
+}
+#endif /* CONFIG_SYSCTL */
+
+struct timespec32 {
+	s32    tv_sec;
+	s32    tv_nsec;
+};
+                
+static int
+put_timespec32(struct timespec32 *u, struct timespec *t)
+{
+	struct timespec32 t32;
+	t32.tv_sec = t->tv_sec;
+	t32.tv_nsec = t->tv_nsec;
+	return copy_to_user(u, &t32, sizeof t32);
+}
+
+asmlinkage int sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp)
+{
+	struct timespec t;
+	struct timespec32 t32;
+	int ret;
+	extern asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp);
+	
+	if (copy_from_user(&t32, rqtp, sizeof t32))
+		return -EFAULT;
+	t.tv_sec = t32.tv_sec;
+	t.tv_nsec = t32.tv_nsec;
+
+	DBG(("sys32_nanosleep({%d, %d})\n", t32.tv_sec, t32.tv_nsec));
+
+	KERNEL_SYSCALL(ret, sys_nanosleep, &t, rmtp ? &t : NULL);
+	if (rmtp && ret == -EINTR) {
+		if (put_timespec32(rmtp, &t))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+asmlinkage long sys32_sched_rr_get_interval(pid_t pid,
+	struct timespec32 *interval)
+{
+	struct timespec t;
+	int ret;
+	extern asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval);
+	
+	KERNEL_SYSCALL(ret, sys_sched_rr_get_interval, pid, &t);
+	if (put_timespec32(interval, &t))
+		return -EFAULT;
+	return ret;
+}
+
+typedef __kernel_time_t32 time_t32;
+
+static int
+put_timeval32(struct timeval32 *u, struct timeval *t)
+{
+	struct timeval32 t32;
+	t32.tv_sec = t->tv_sec;
+	t32.tv_usec = t->tv_usec;
+	return copy_to_user(u, &t32, sizeof t32);
+}
+
+static int
+get_timeval32(struct timeval32 *u, struct timeval *t)
+{
+	int err;
+	struct timeval32 t32;
+
+	if ((err = copy_from_user(&t32, u, sizeof t32)) == 0)
+	{
+	    t->tv_sec = t32.tv_sec;
+	    t->tv_usec = t32.tv_usec;
+	}
+	return err;
+}
+
+asmlinkage long sys32_time(time_t32 *tloc)
+{
+    time_t now = CURRENT_TIME;
+    time_t32 now32 = now;
+
+    if (tloc)
+    	if (put_user(now32, tloc))
+		now32 = -EFAULT;
+
+    return now32;
+}
+
+asmlinkage int
+sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz)
+{
+    extern void do_gettimeofday(struct timeval *tv);
+
+    if (tv) {
+	    struct timeval ktv;
+	    do_gettimeofday(&ktv);
+	    if (put_timeval32(tv, &ktv))
+		    return -EFAULT;
+    }
+    if (tz) {
+	    extern struct timezone sys_tz;
+	    if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
+		    return -EFAULT;
+    }
+    return 0;
+}
+
+asmlinkage int
+sys32_settimeofday(struct timeval32 *tv, struct timezone *tz)
+{
+    struct timeval ktv;
+    struct timezone ktz;
+    extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
+
+    if (tv) {
+	    if (get_timeval32(tv, &ktv))
+		    return -EFAULT;
+    }
+    if (tz) {
+	    if (copy_from_user(&ktz, tz, sizeof(ktz)))
+		    return -EFAULT;
+    }
+
+    return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL);
+}
+
+struct	itimerval32 {
+	struct	timeval32 it_interval;	/* timer interval */
+	struct	timeval32 it_value;	/* current value */
+};
+
+asmlinkage long sys32_getitimer(int which, struct itimerval32 *ov32)
+{
+	int error = -EFAULT;
+	struct itimerval get_buffer;
+	extern int do_getitimer(int which, struct itimerval *value);
+
+	if (ov32) {
+		error = do_getitimer(which, &get_buffer);
+		if (!error) {
+			struct itimerval32 gb32;
+			gb32.it_interval.tv_sec = get_buffer.it_interval.tv_sec;
+			gb32.it_interval.tv_usec = get_buffer.it_interval.tv_usec;
+			gb32.it_value.tv_sec = get_buffer.it_value.tv_sec;
+			gb32.it_value.tv_usec = get_buffer.it_value.tv_usec;
+			if (copy_to_user(ov32, &gb32, sizeof(gb32)))
+				error = -EFAULT; 
+		}
+	}
+	return error;
+}
+
+asmlinkage long sys32_setitimer(int which, struct itimerval32 *v32,
+			      struct itimerval32 *ov32)
+{
+	struct itimerval set_buffer, get_buffer;
+	struct itimerval32 sb32, gb32;
+	extern int do_setitimer(int which, struct itimerval *value, struct itimerval *ov32);
+	int error;
+
+	if (v32) {
+		if(copy_from_user(&sb32, v32, sizeof(sb32)))
+			return -EFAULT;
+
+		set_buffer.it_interval.tv_sec = sb32.it_interval.tv_sec;
+		set_buffer.it_interval.tv_usec = sb32.it_interval.tv_usec;
+		set_buffer.it_value.tv_sec = sb32.it_value.tv_sec;
+		set_buffer.it_value.tv_usec = sb32.it_value.tv_usec;
+	} else
+		memset((char *) &set_buffer, 0, sizeof(set_buffer));
+
+	error = do_setitimer(which, &set_buffer, ov32 ? &get_buffer : 0);
+	if (error || !ov32)
+		return error;
+
+	gb32.it_interval.tv_sec = get_buffer.it_interval.tv_sec;
+	gb32.it_interval.tv_usec = get_buffer.it_interval.tv_usec;
+	gb32.it_value.tv_sec = get_buffer.it_value.tv_sec;
+	gb32.it_value.tv_usec = get_buffer.it_value.tv_usec;
+	if (copy_to_user(ov32, &gb32, sizeof(gb32)))
+		return -EFAULT; 
+	return 0;
+}
+
+struct rusage32 {
+        struct timeval32 ru_utime;
+        struct timeval32 ru_stime;
+        int    ru_maxrss;
+        int    ru_ixrss;
+        int    ru_idrss;
+        int    ru_isrss;
+        int    ru_minflt;
+        int    ru_majflt;
+        int    ru_nswap;
+        int    ru_inblock;
+        int    ru_oublock;
+        int    ru_msgsnd; 
+        int    ru_msgrcv; 
+        int    ru_nsignals;
+        int    ru_nvcsw;
+        int    ru_nivcsw;
+};
+
+static int
+put_rusage32(struct rusage32 *ru32p, struct rusage *r)
+{
+	struct rusage32 r32;
+#undef CP
+#define CP(t) r32.t = r->t;
+	CP(ru_utime.tv_sec); CP(ru_utime.tv_usec);
+	CP(ru_stime.tv_sec); CP(ru_stime.tv_usec);
+	CP(ru_maxrss);
+	CP(ru_ixrss);
+	CP(ru_idrss);
+	CP(ru_isrss);
+	CP(ru_minflt);
+	CP(ru_majflt);
+	CP(ru_nswap);
+	CP(ru_inblock);
+	CP(ru_oublock);
+	CP(ru_msgsnd);
+	CP(ru_msgrcv);
+	CP(ru_nsignals);
+	CP(ru_nvcsw);
+	CP(ru_nivcsw);
+	return copy_to_user(ru32p, &r32, sizeof r32);
+}
+
+asmlinkage int
+sys32_getrusage(int who, struct rusage32 *ru)
+{
+	struct rusage r;
+	int ret;
+	extern asmlinkage int sys_getrusage(int who, struct rusage *ru);
+		
+	KERNEL_SYSCALL(ret, sys_getrusage, who, &r);
+	if (put_rusage32(ru, &r)) return -EFAULT;
+	return ret;
+}
+
+asmlinkage int
+sys32_wait4(__kernel_pid_t32 pid, unsigned int * stat_addr, int options,
+	    struct rusage32 * ru)
+{
+	if (!ru)
+		return sys_wait4(pid, stat_addr, options, NULL);
+	else {
+		struct rusage r;
+		int ret;
+		unsigned int status;
+	
+		KERNEL_SYSCALL(ret, sys_wait4, pid, stat_addr ? &status : NULL, options, &r);
+		if (put_rusage32(ru, &r)) return -EFAULT;
+		if (stat_addr && put_user(status, stat_addr))
+			return -EFAULT;
+		return ret;
+	}
+}
+
+struct stat32 {
+	__kernel_dev_t32		st_dev;		/* dev_t is 32 bits on parisc */
+	__kernel_ino_t32		st_ino;		/* 32 bits */
+	__kernel_mode_t32	st_mode;	/* 16 bits */
+	__kernel_nlink_t32		st_nlink;	/* 16 bits */
+	unsigned short	st_reserved1;	/* old st_uid */
+	unsigned short	st_reserved2;	/* old st_gid */
+	__kernel_dev_t32		st_rdev;
+	__kernel_off_t32		st_size;
+	__kernel_time_t32	st_atime;
+	unsigned int	st_spare1;
+	__kernel_time_t32	st_mtime;
+	unsigned int	st_spare2;
+	__kernel_time_t32	st_ctime;
+	unsigned int	st_spare3;
+	int		st_blksize;
+	int		st_blocks;
+	unsigned int	__unused1;	/* ACL stuff */
+	__kernel_dev_t32		__unused2;	/* network */
+	__kernel_ino_t32		__unused3;	/* network */
+	unsigned int	__unused4;	/* cnodes */
+	unsigned short	__unused5;	/* netsite */
+	short		st_fstype;
+	__kernel_dev_t32		st_realdev;
+	unsigned short	st_basemode;
+	unsigned short	st_spareshort;
+	__kernel_uid_t32		st_uid;
+	__kernel_gid_t32		st_gid;
+	unsigned int	st_spare4[3];
+};
+
+/*
+ * Revalidate the inode. This is required for proper NFS attribute caching.
+ */
+static __inline__ int
+do_revalidate(struct dentry *dentry)
+{
+	struct inode * inode = dentry->d_inode;
+	if (inode->i_op && inode->i_op->revalidate)
+		return inode->i_op->revalidate(dentry);
+	return 0;
+}
+
+
+static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf)
+{
+	struct stat32 tmp;
+	unsigned int blocks, indirect;
+
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.st_dev = kdev_t_to_nr(inode->i_dev);
+	tmp.st_ino = inode->i_ino;
+	tmp.st_mode = inode->i_mode;
+	tmp.st_nlink = inode->i_nlink;
+	SET_STAT_UID(tmp, inode->i_uid);
+	SET_STAT_GID(tmp, inode->i_gid);
+	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
+#if BITS_PER_LONG == 32
+	if (inode->i_size > 0x7fffffff)
+		return -EOVERFLOW;
+#endif	
+	tmp.st_size = inode->i_size;
+	tmp.st_atime = inode->i_atime;
+	tmp.st_mtime = inode->i_mtime;
+	tmp.st_ctime = inode->i_ctime;
+/*
+ * st_blocks and st_blksize are approximated with a simple algorithm if
+ * they aren't supported directly by the filesystem. The minix and msdos
+ * filesystems don't keep track of blocks, so they would either have to
+ * be counted explicitly (by delving into the file itself), or by using
+ * this simple algorithm to get a reasonable (although not 100% accurate)
+ * value.
+ */
+
+/*
+ * Use minix fs values for the number of direct and indirect blocks.  The
+ * count is now exact for the minix fs except that it counts zero blocks.
+ * Everything is in units of BLOCK_SIZE until the assignment to
+ * tmp.st_blksize.
+ */
+#define D_B   7
+#define I_B   (BLOCK_SIZE / sizeof(unsigned short))
+
+	if (!inode->i_blksize) {
+		blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
+		if (blocks > D_B) {
+			indirect = (blocks - D_B + I_B - 1) / I_B;
+			blocks += indirect;
+			if (indirect > 1) {
+				indirect = (indirect - 1 + I_B - 1) / I_B;
+				blocks += indirect;
+				if (indirect > 1)
+					blocks++;
+			}
+		}
+		tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
+		tmp.st_blksize = BLOCK_SIZE;
+	} else {
+		tmp.st_blocks = inode->i_blocks;
+		tmp.st_blksize = inode->i_blksize;
+	}
+	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+}
+
+asmlinkage long sys32_newstat(char * filename, struct stat32 *statbuf)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk(filename, &nd);
+	if (!error) {
+		error = do_revalidate(nd.dentry);
+		if (!error)
+			error = cp_new_stat32(nd.dentry->d_inode, statbuf);
+		path_release(&nd);
+	}
+	return error;
+}
+
+asmlinkage long sys32_newlstat(char * filename, struct stat32 *statbuf)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk_link(filename, &nd);
+	if (!error) {
+		error = do_revalidate(nd.dentry);
+		if (!error)
+			error = cp_new_stat32(nd.dentry->d_inode, statbuf);
+		path_release(&nd);
+	}
+	return error;
+}
+
+asmlinkage long sys32_newfstat(unsigned int fd, struct stat32 *statbuf)
+{
+	struct file * f;
+	int err = -EBADF;
+
+	f = fget(fd);
+	if (f) {
+		struct dentry * dentry = f->f_dentry;
+
+		err = do_revalidate(dentry);
+		if (!err)
+			err = cp_new_stat32(dentry->d_inode, statbuf);
+		fput(f);
+	}
+	return err;
+}
+
+struct linux32_dirent {
+	u32	d_ino;
+	__kernel_off_t32	d_off;
+	u16	d_reclen;
+	char	d_name[1];
+};
+
+struct old_linux32_dirent {
+	u32	d_ino;
+	u32	d_offset;
+	u16	d_namlen;
+	char	d_name[1];
+};
+
+struct getdents32_callback {
+	struct linux32_dirent * current_dir;
+	struct linux32_dirent * previous;
+	int count;
+	int error;
+};
+
+struct readdir32_callback {
+	struct old_linux32_dirent * dirent;
+	int count;
+};
+
+#define ROUND_UP(x,a)	((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1)))
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+static int
+filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
+	   unsigned int d_type)
+{
+	struct linux32_dirent * dirent;
+	struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
+	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4);
+
+	buf->error = -EINVAL;	/* only used if we fail.. */
+	if (reclen > buf->count)
+		return -EINVAL;
+	dirent = buf->previous;
+	if (dirent)
+		put_user(offset, &dirent->d_off);
+	dirent = buf->current_dir;
+	buf->previous = dirent;
+	put_user(ino, &dirent->d_ino);
+	put_user(reclen, &dirent->d_reclen);
+	copy_to_user(dirent->d_name, name, namlen);
+	put_user(0, dirent->d_name + namlen);
+	((char *) dirent) += reclen;
+	buf->current_dir = dirent;
+	buf->count -= reclen;
+	return 0;
+}
+
+asmlinkage long
+sys32_getdents (unsigned int fd, void * dirent, unsigned int count)
+{
+	struct file * file;
+	struct linux32_dirent * lastdirent;
+	struct getdents32_callback buf;
+	int error;
+
+	error = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto out;
+
+	buf.current_dir = (struct linux32_dirent *) dirent;
+	buf.previous = NULL;
+	buf.count = count;
+	buf.error = 0;
+
+	error = vfs_readdir(file, filldir32, &buf);
+	if (error < 0)
+		goto out_putf;
+	error = buf.error;
+	lastdirent = buf.previous;
+	if (lastdirent) {
+		put_user(file->f_pos, &lastdirent->d_off);
+		error = count - buf.count;
+	}
+
+out_putf:
+	fput(file);
+out:
+	return error;
+}
+
+static int
+fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t ino,
+	      unsigned int d_type)
+{
+	struct readdir32_callback * buf = (struct readdir32_callback *) __buf;
+	struct old_linux32_dirent * dirent;
+
+	if (buf->count)
+		return -EINVAL;
+	buf->count++;
+	dirent = buf->dirent;
+	put_user(ino, &dirent->d_ino);
+	put_user(offset, &dirent->d_offset);
+	put_user(namlen, &dirent->d_namlen);
+	copy_to_user(dirent->d_name, name, namlen);
+	put_user(0, dirent->d_name + namlen);
+	return 0;
+}
+
+asmlinkage long
+sys32_readdir (unsigned int fd, void * dirent, unsigned int count)
+{
+	int error;
+	struct file * file;
+	struct readdir32_callback buf;
+
+	error = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto out;
+
+	buf.count = 0;
+	buf.dirent = dirent;
+
+	error = vfs_readdir(file, fillonedir32, &buf);
+	if (error >= 0)
+		error = buf.count;
+	fput(file);
+out:
+	return error;
+}
+
+struct rlimit32 {
+	__u32	rlim_cur;
+	__u32	rlim_max;
+};
+
+#define RLIM32_INFINITY 0xffffffff
+
+asmlinkage long sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim)
+{
+	struct rlimit32 rlim32;
+	struct rlimit *rlimip;
+
+	if (resource >= RLIM_NLIMITS)
+		return -EINVAL;
+	rlimip = current->rlim + resource;
+	if (rlimip->rlim_cur >= RLIM32_INFINITY) {
+		rlim32.rlim_cur = RLIM32_INFINITY;
+	} else {
+		rlim32.rlim_cur = rlimip->rlim_cur;
+	}
+	if (rlimip->rlim_max >= RLIM32_INFINITY) {
+		rlim32.rlim_max = RLIM32_INFINITY;
+	} else {
+		rlim32.rlim_max = rlimip->rlim_max;
+	}
+	return copy_to_user(rlim, &rlim32, sizeof (struct rlimit32));
+}
+
+asmlinkage long sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim)
+{
+	struct rlimit32 rlim32;
+	struct rlimit new_rlim, *old_rlim;
+
+	if (resource >= RLIM_NLIMITS)
+		return -EINVAL;
+	if (copy_from_user(&rlim32, rlim, sizeof(rlim)))
+		return -EFAULT;
+	if (rlim32.rlim_cur == RLIM32_INFINITY) {
+		new_rlim.rlim_cur = RLIM_INFINITY;
+	} else {
+		new_rlim.rlim_cur = rlim32.rlim_cur;
+	}
+	if (rlim32.rlim_max == RLIM32_INFINITY) {
+		new_rlim.rlim_max = RLIM_INFINITY;
+	} else {
+		new_rlim.rlim_max = rlim32.rlim_max;
+	}
+
+	old_rlim = current->rlim + resource;
+	if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
+	     (new_rlim.rlim_max > old_rlim->rlim_max)) &&
+	    !capable(CAP_SYS_RESOURCE))
+		return -EPERM;
+	if (resource == RLIMIT_NOFILE) {
+		if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN)
+			return -EPERM;
+	}
+	if (resource == RLIMIT_STACK) {
+		if (new_rlim.rlim_max > 1024 * 1024 * 1024) {
+			new_rlim.rlim_max = 1024 * 1024 * 1024;
+		}
+		new_rlim.rlim_max = PAGE_ALIGN(new_rlim.rlim_max);
+	}
+	
+	*old_rlim = new_rlim;
+	return 0;
+}
+
+static int copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
+{
+	int i;
+	unsigned long page;
+	struct vm_area_struct *vma;
+
+	*kernel = 0;
+	if(!user)
+		return 0;
+	vma = find_vma(current->mm, (unsigned long)user);
+	if(!vma || (unsigned long)user < vma->vm_start)
+		return -EFAULT;
+	if(!(vma->vm_flags & VM_READ))
+		return -EFAULT;
+	i = vma->vm_end - (unsigned long) user;
+	if(PAGE_SIZE <= (unsigned long) i)
+		i = PAGE_SIZE - 1;
+	if(!(page = __get_free_page(GFP_KERNEL)))
+		return -ENOMEM;
+	if(copy_from_user((void *) page, user, i)) {
+		free_page(page);
+		return -EFAULT;
+	}
+	*kernel = page;
+	return 0;
+}
+
+#define SMBFS_NAME	"smbfs"
+#define NCPFS_NAME	"ncpfs"
+
+asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data)
+{
+	unsigned long type_page = 0;
+	unsigned long data_page = 0;
+	unsigned long dev_page = 0;
+	unsigned long dir_page = 0;
+	int err, is_smb, is_ncp;
+
+	is_smb = is_ncp = 0;
+
+	err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
+	if (err)
+		goto out;
+
+	if (!type_page) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	is_smb = !strcmp((char *)type_page, SMBFS_NAME);
+	is_ncp = !strcmp((char *)type_page, NCPFS_NAME);
+
+	err = copy_mount_stuff_to_kernel((const void *)(unsigned long)data, &data_page);
+	if (err)
+		goto type_out;
+
+	err = copy_mount_stuff_to_kernel(dev_name, &dev_page);
+	if (err)
+		goto data_out;
+
+	err = copy_mount_stuff_to_kernel(dir_name, &dir_page);
+	if (err)
+		goto dev_out;
+
+	if (!is_smb && !is_ncp) {
+		lock_kernel();
+		err = do_mount((char*)dev_page, (char*)dir_page,
+				(char*)type_page, new_flags, (char*)data_page);
+		unlock_kernel();
+	} else {
+		if (is_ncp)
+			panic("NCP mounts not yet supported 32/64 parisc");
+			/* do_ncp_super_data_conv((void *)data_page); */
+		else {
+			panic("SMB mounts not yet supported 32/64 parisc");
+			/* do_smb_super_data_conv((void *)data_page); */
+		}
+
+		lock_kernel();
+		err = do_mount((char*)dev_page, (char*)dir_page,
+				(char*)type_page, new_flags, (char*)data_page);
+		unlock_kernel();
+	}
+	free_page(dir_page);
+
+dev_out:
+	free_page(dev_page);
+
+data_out:
+	free_page(data_page);
+
+type_out:
+	free_page(type_page);
+
+out:
+	return err;
+}
+
+
+#ifdef CONFIG_MODULES
+
+struct module_info32 {
+	u32 addr;
+	u32 size;
+	u32 flags;
+	s32 usecount;
+};
+
+/* Query various bits about modules.  */
+
+static inline long
+get_mod_name(const char *user_name, char **buf)
+{
+	unsigned long page;
+	long retval;
+
+	if ((unsigned long)user_name >= TASK_SIZE
+	    && !segment_eq(get_fs (), KERNEL_DS))
+		return -EFAULT;
+
+	page = __get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE);
+	if (retval > 0) {
+		if (retval < PAGE_SIZE) {
+			*buf = (char *)page;
+			return retval;
+		}
+		retval = -ENAMETOOLONG;
+	} else if (!retval)
+		retval = -EINVAL;
+
+	free_page(page);
+	return retval;
+}
+
+static inline void
+put_mod_name(char *buf)
+{
+	free_page((unsigned long)buf);
+}
+
+static __inline__ struct module *find_module(const char *name)
+{
+	struct module *mod;
+
+	for (mod = module_list; mod ; mod = mod->next) {
+		if (mod->flags & MOD_DELETED)
+			continue;
+		if (!strcmp(mod->name, name))
+			break;
+	}
+
+	return mod;
+}
+
+static int
+qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+	struct module *mod;
+	size_t nmod, space, len;
+
+	nmod = space = 0;
+
+	for (mod = module_list; mod->next != NULL; mod = mod->next, ++nmod) {
+		len = strlen(mod->name)+1;
+		if (len > bufsize)
+			goto calc_space_needed;
+		if (copy_to_user(buf, mod->name, len))
+			return -EFAULT;
+		buf += len;
+		bufsize -= len;
+		space += len;
+	}
+
+	if (put_user(nmod, ret))
+		return -EFAULT;
+	else
+		return 0;
+
+calc_space_needed:
+	space += len;
+	while ((mod = mod->next)->next != NULL)
+		space += strlen(mod->name)+1;
+
+	if (put_user(space, ret))
+		return -EFAULT;
+	else
+		return -ENOSPC;
+}
+
+static int
+qm_deps(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+	size_t i, space, len;
+
+	if (mod->next == NULL)
+		return -EINVAL;
+	if (!MOD_CAN_QUERY(mod))
+		return put_user(0, ret);
+
+	space = 0;
+	for (i = 0; i < mod->ndeps; ++i) {
+		const char *dep_name = mod->deps[i].dep->name;
+
+		len = strlen(dep_name)+1;
+		if (len > bufsize)
+			goto calc_space_needed;
+		if (copy_to_user(buf, dep_name, len))
+			return -EFAULT;
+		buf += len;
+		bufsize -= len;
+		space += len;
+	}
+
+	return put_user(i, ret);
+
+calc_space_needed:
+	space += len;
+	while (++i < mod->ndeps)
+		space += strlen(mod->deps[i].dep->name)+1;
+
+	if (put_user(space, ret))
+		return -EFAULT;
+	else
+		return -ENOSPC;
+}
+
+static int
+qm_refs(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+	size_t nrefs, space, len;
+	struct module_ref *ref;
+
+	if (mod->next == NULL)
+		return -EINVAL;
+	if (!MOD_CAN_QUERY(mod))
+		if (put_user(0, ret))
+			return -EFAULT;
+		else
+			return 0;
+
+	space = 0;
+	for (nrefs = 0, ref = mod->refs; ref ; ++nrefs, ref = ref->next_ref) {
+		const char *ref_name = ref->ref->name;
+
+		len = strlen(ref_name)+1;
+		if (len > bufsize)
+			goto calc_space_needed;
+		if (copy_to_user(buf, ref_name, len))
+			return -EFAULT;
+		buf += len;
+		bufsize -= len;
+		space += len;
+	}
+
+	if (put_user(nrefs, ret))
+		return -EFAULT;
+	else
+		return 0;
+
+calc_space_needed:
+	space += len;
+	while ((ref = ref->next_ref) != NULL)
+		space += strlen(ref->ref->name)+1;
+
+	if (put_user(space, ret))
+		return -EFAULT;
+	else
+		return -ENOSPC;
+}
+
+static inline int
+qm_symbols(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+	size_t i, space, len;
+	struct module_symbol *s;
+	char *strings;
+	unsigned *vals;
+
+	if (!MOD_CAN_QUERY(mod))
+		if (put_user(0, ret))
+			return -EFAULT;
+		else
+			return 0;
+
+	space = mod->nsyms * 2*sizeof(u32);
+
+	i = len = 0;
+	s = mod->syms;
+
+	if (space > bufsize)
+		goto calc_space_needed;
+
+	if (!access_ok(VERIFY_WRITE, buf, space))
+		return -EFAULT;
+
+	bufsize -= space;
+	vals = (unsigned *)buf;
+	strings = buf+space;
+
+	for (; i < mod->nsyms ; ++i, ++s, vals += 2) {
+		len = strlen(s->name)+1;
+		if (len > bufsize)
+			goto calc_space_needed;
+
+		if (copy_to_user(strings, s->name, len)
+		    || __put_user(s->value, vals+0)
+		    || __put_user(space, vals+1))
+			return -EFAULT;
+
+		strings += len;
+		bufsize -= len;
+		space += len;
+	}
+
+	if (put_user(i, ret))
+		return -EFAULT;
+	else
+		return 0;
+
+calc_space_needed:
+	for (; i < mod->nsyms; ++i, ++s)
+		space += strlen(s->name)+1;
+
+	if (put_user(space, ret))
+		return -EFAULT;
+	else
+		return -ENOSPC;
+}
+
+static inline int
+qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+	int error = 0;
+
+	if (mod->next == NULL)
+		return -EINVAL;
+
+	if (sizeof(struct module_info32) <= bufsize) {
+		struct module_info32 info;
+		info.addr = (unsigned long)mod;
+		info.size = mod->size;
+		info.flags = mod->flags;
+		info.usecount =
+			((mod_member_present(mod, can_unload)
+			  && mod->can_unload)
+			 ? -1 : atomic_read(&mod->uc.usecount));
+
+		if (copy_to_user(buf, &info, sizeof(struct module_info32)))
+			return -EFAULT;
+	} else
+		error = -ENOSPC;
+
+	if (put_user(sizeof(struct module_info32), ret))
+		return -EFAULT;
+
+	return error;
+}
+
+asmlinkage int sys32_query_module(char *name_user, int which, char *buf, __kernel_size_t32 bufsize, __kernel_size_t32 *ret)
+{
+	struct module *mod;
+	int err;
+
+	lock_kernel();
+	if (name_user == 0) {
+		/* This finds "kernel_module" which is not exported. */
+		for(mod = module_list; mod->next != NULL; mod = mod->next)
+			;
+	} else {
+		long namelen;
+		char *name;
+
+		if ((namelen = get_mod_name(name_user, &name)) < 0) {
+			err = namelen;
+			goto out;
+		}
+		err = -ENOENT;
+		if (namelen == 0) {
+			/* This finds "kernel_module" which is not exported. */
+			for(mod = module_list; mod->next != NULL; mod = mod->next)
+				;
+		} else if ((mod = find_module(name)) == NULL) {
+			put_mod_name(name);
+			goto out;
+		}
+		put_mod_name(name);
+	}
+
+	switch (which)
+	{
+	case 0:
+		err = 0;
+		break;
+	case QM_MODULES:
+		err = qm_modules(buf, bufsize, ret);
+		break;
+	case QM_DEPS:
+		err = qm_deps(mod, buf, bufsize, ret);
+		break;
+	case QM_REFS:
+		err = qm_refs(mod, buf, bufsize, ret);
+		break;
+	case QM_SYMBOLS:
+		err = qm_symbols(mod, buf, bufsize, ret);
+		break;
+	case QM_INFO:
+		err = qm_info(mod, buf, bufsize, ret);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+out:
+	unlock_kernel();
+	return err;
+}
+
+struct kernel_sym32 {
+	u32 value;
+	char name[60];
+};
+		 
+extern asmlinkage int sys_get_kernel_syms(struct kernel_sym *table);
+
+asmlinkage int sys32_get_kernel_syms(struct kernel_sym32 *table)
+{
+	int len, i;
+	struct kernel_sym *tbl;
+	mm_segment_t old_fs;
+	
+	len = sys_get_kernel_syms(NULL);
+	if (!table) return len;
+	tbl = kmalloc (len * sizeof (struct kernel_sym), GFP_KERNEL);
+	if (!tbl) return -ENOMEM;
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	sys_get_kernel_syms(tbl);
+	set_fs (old_fs);
+	for (i = 0; i < len; i++, table++) {
+		if (put_user (tbl[i].value, &table->value) ||
+		    copy_to_user (table->name, tbl[i].name, 60))
+			break;
+	}
+	kfree (tbl);
+	return i;
+}
+
+#else /* CONFIG_MODULES */
+
+asmlinkage int
+sys32_query_module(const char *name_user, int which, char *buf, size_t bufsize,
+		 size_t *ret)
+{
+	/* Let the program know about the new interface.  Not that
+	   it'll do them much good.  */
+	if (which == 0)
+		return 0;
+
+	return -ENOSYS;
+}
+
+asmlinkage int
+sys32_get_kernel_syms(struct kernel_sym *table)
+{
+	return -ENOSYS;
+}
+
+#endif  /* CONFIG_MODULES */
+
+/* readv/writev stolen from mips64 */
+struct iovec32 { unsigned int iov_base; int iov_len; };
+
+typedef ssize_t (*IO_fn_t)(struct file *, char *, size_t, loff_t *);
+
+static long
+do_readv_writev32(int type, struct file *file, const struct iovec32 *vector,
+		  u32 count)
+{
+	unsigned long tot_len;
+	struct iovec iovstack[UIO_FASTIOV];
+	struct iovec *iov=iovstack, *ivp;
+	struct inode *inode;
+	long retval, i;
+	IO_fn_t fn;
+
+	/* First get the "struct iovec" from user memory and
+	 * verify all the pointers
+	 */
+	if (!count)
+		return 0;
+	if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count))
+		return -EFAULT;
+	if (count > UIO_MAXIOV)
+		return -EINVAL;
+	if (count > UIO_FASTIOV) {
+		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
+		if (!iov)
+			return -ENOMEM;
+	}
+
+	tot_len = 0;
+	i = count;
+	ivp = iov;
+	while (i > 0) {
+		u32 len;
+		u32 buf;
+
+		__get_user(len, &vector->iov_len);
+		__get_user(buf, &vector->iov_base);
+		tot_len += len;
+		ivp->iov_base = (void *)A(buf);
+		ivp->iov_len = (__kernel_size_t) len;
+		vector++;
+		ivp++;
+		i--;
+	}
+
+	inode = file->f_dentry->d_inode;
+	/* VERIFY_WRITE actually means a read, as we write to user space */
+	retval = locks_verify_area((type == VERIFY_WRITE
+				    ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
+				   inode, file, file->f_pos, tot_len);
+	if (retval) {
+		if (iov != iovstack)
+			kfree(iov);
+		return retval;
+	}
+
+	/* Then do the actual IO.  Note that sockets need to be handled
+	 * specially as they have atomicity guarantees and can handle
+	 * iovec's natively
+	 */
+	if (inode->i_sock) {
+		int err;
+		err = sock_readv_writev(type, inode, file, iov, count, tot_len);
+		if (iov != iovstack)
+			kfree(iov);
+		return err;
+	}
+
+	if (!file->f_op) {
+		if (iov != iovstack)
+			kfree(iov);
+		return -EINVAL;
+	}
+	/* VERIFY_WRITE actually means a read, as we write to user space */
+	fn = file->f_op->read;
+	if (type == VERIFY_READ)
+		fn = (IO_fn_t) file->f_op->write;		
+	ivp = iov;
+	while (count > 0) {
+		void * base;
+		int len, nr;
+
+		base = ivp->iov_base;
+		len = ivp->iov_len;
+		ivp++;
+		count--;
+		nr = fn(file, base, len, &file->f_pos);
+		if (nr < 0) {
+			if (retval)
+				break;
+			retval = nr;
+			break;
+		}
+		retval += nr;
+		if (nr != len)
+			break;
+	}
+	if (iov != iovstack)
+		kfree(iov);
+
+	return retval;
+}
+
+asmlinkage long
+sys32_readv(int fd, struct iovec32 *vector, u32 count)
+{
+	struct file *file;
+	ssize_t ret;
+
+	ret = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto bad_file;
+	if (file->f_op && (file->f_mode & FMODE_READ) &&
+	    (file->f_op->readv || file->f_op->read))
+		ret = do_readv_writev32(VERIFY_WRITE, file, vector, count);
+
+	fput(file);
+
+bad_file:
+	return ret;
+}
+
+asmlinkage long
+sys32_writev(int fd, struct iovec32 *vector, u32 count)
+{
+	struct file *file;
+	ssize_t ret;
+
+	ret = -EBADF;
+	file = fget(fd);
+	if(!file)
+		goto bad_file;
+	if (file->f_op && (file->f_mode & FMODE_WRITE) &&
+	    (file->f_op->writev || file->f_op->write))
+	        ret = do_readv_writev32(VERIFY_READ, file, vector, count);
+	fput(file);
+
+bad_file:
+	return ret;
+}
+
+/********** Borrowed from sparc64 -- hardly reviewed, not tested *****/
+#include <net/scm.h>
+/* XXX This really belongs in some header file... -DaveM */
+#define MAX_SOCK_ADDR	128		/* 108 for Unix domain - 
+					   16 for IP, 16 for IPX,
+					   24 for IPv6,
+					   about 80 for AX.25 */
+
+extern struct socket *sockfd_lookup(int fd, int *err);
+
+/* XXX This as well... */
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+	fput(sock->file);
+}
+
+struct msghdr32 {
+        u32               msg_name;
+        int               msg_namelen;
+        u32               msg_iov;
+        __kernel_size_t32 msg_iovlen;
+        u32               msg_control;
+        __kernel_size_t32 msg_controllen;
+        unsigned          msg_flags;
+};
+
+struct cmsghdr32 {
+        __kernel_size_t32 cmsg_len;
+        int               cmsg_level;
+        int               cmsg_type;
+};
+
+/* Bleech... */
+#define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen))
+#define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) cmsg32_nxthdr((mhdr), (cmsg), (cmsglen))
+
+#define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) )
+
+#define CMSG32_DATA(cmsg)	((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32))))
+#define CMSG32_SPACE(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len))
+#define CMSG32_LEN(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len))
+
+#define __CMSG32_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr32) ? \
+				    (struct cmsghdr32 *)(ctl) : \
+				    (struct cmsghdr32 *)NULL)
+#define CMSG32_FIRSTHDR(msg)	__CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+
+__inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size,
+					      struct cmsghdr32 *__cmsg, int __cmsg_len)
+{
+	struct cmsghdr32 * __ptr;
+
+	__ptr = (struct cmsghdr32 *)(((unsigned char *) __cmsg) +
+				     CMSG32_ALIGN(__cmsg_len));
+	if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
+		return NULL;
+
+	return __ptr;
+}
+
+__inline__ struct cmsghdr32 *cmsg32_nxthdr (struct msghdr *__msg,
+					    struct cmsghdr32 *__cmsg,
+					    int __cmsg_len)
+{
+	return __cmsg32_nxthdr(__msg->msg_control, __msg->msg_controllen,
+			       __cmsg, __cmsg_len);
+}
+
+static inline int iov_from_user32_to_kern(struct iovec *kiov,
+					  struct iovec32 *uiov32,
+					  int niov)
+{
+	int tot_len = 0;
+
+	while(niov > 0) {
+		u32 len, buf;
+
+		if(get_user(len, &uiov32->iov_len) ||
+		   get_user(buf, &uiov32->iov_base)) {
+			tot_len = -EFAULT;
+			break;
+		}
+		tot_len += len;
+		kiov->iov_base = (void *)A(buf);
+		kiov->iov_len = (__kernel_size_t) len;
+		uiov32++;
+		kiov++;
+		niov--;
+	}
+	return tot_len;
+}
+
+static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg,
+					     struct msghdr32 *umsg)
+{
+	u32 tmp1, tmp2, tmp3;
+	int err;
+
+	err = get_user(tmp1, &umsg->msg_name);
+	err |= __get_user(tmp2, &umsg->msg_iov);
+	err |= __get_user(tmp3, &umsg->msg_control);
+	if (err)
+		return -EFAULT;
+
+	kmsg->msg_name = (void *)A(tmp1);
+	kmsg->msg_iov = (struct iovec *)A(tmp2);
+	kmsg->msg_control = (void *)A(tmp3);
+
+	err = get_user(kmsg->msg_namelen, &umsg->msg_namelen);
+	err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen);
+	err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen);
+	err |= get_user(kmsg->msg_flags, &umsg->msg_flags);
+	
+	return err;
+}
+
+/* I've named the args so it is easy to tell whose space the pointers are in. */
+static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov,
+			  char *kern_address, int mode)
+{
+	int tot_len;
+
+	if(kern_msg->msg_namelen) {
+		if(mode==VERIFY_READ) {
+			int err = move_addr_to_kernel(kern_msg->msg_name,
+						      kern_msg->msg_namelen,
+						      kern_address);
+			if(err < 0)
+				return err;
+		}
+		kern_msg->msg_name = kern_address;
+	} else
+		kern_msg->msg_name = NULL;
+
+	if(kern_msg->msg_iovlen > UIO_FASTIOV) {
+		kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec),
+				   GFP_KERNEL);
+		if(!kern_iov)
+			return -ENOMEM;
+	}
+
+	tot_len = iov_from_user32_to_kern(kern_iov,
+					  (struct iovec32 *)kern_msg->msg_iov,
+					  kern_msg->msg_iovlen);
+	if(tot_len >= 0)
+		kern_msg->msg_iov = kern_iov;
+	else if(kern_msg->msg_iovlen > UIO_FASTIOV)
+		kfree(kern_iov);
+
+	return tot_len;
+}
+
+/* There is a lot of hair here because the alignment rules (and
+ * thus placement) of cmsg headers and length are different for
+ * 32-bit apps.  -DaveM
+ */
+static int cmsghdr_from_user32_to_kern(struct msghdr *kmsg,
+				       unsigned char *stackbuf, int stackbuf_size)
+{
+	struct cmsghdr32 *ucmsg;
+	struct cmsghdr *kcmsg, *kcmsg_base;
+	__kernel_size_t32 ucmlen;
+	__kernel_size_t kcmlen, tmp;
+
+	kcmlen = 0;
+	kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
+	ucmsg = CMSG32_FIRSTHDR(kmsg);
+	while(ucmsg != NULL) {
+		if(get_user(ucmlen, &ucmsg->cmsg_len))
+			return -EFAULT;
+
+		/* Catch bogons. */
+		if(CMSG32_ALIGN(ucmlen) <
+		   CMSG32_ALIGN(sizeof(struct cmsghdr32)))
+			return -EINVAL;
+		if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
+				   + ucmlen) > kmsg->msg_controllen)
+			return -EINVAL;
+
+		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
+		       CMSG_ALIGN(sizeof(struct cmsghdr)));
+		kcmlen += tmp;
+		ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
+	}
+	if(kcmlen == 0)
+		return -EINVAL;
+
+	/* The kcmlen holds the 64-bit version of the control length.
+	 * It may not be modified as we do not stick it into the kmsg
+	 * until we have successfully copied over all of the data
+	 * from the user.
+	 */
+	if(kcmlen > stackbuf_size)
+		kcmsg_base = kcmsg = kmalloc(kcmlen, GFP_KERNEL);
+	if(kcmsg == NULL)
+		return -ENOBUFS;
+
+	/* Now copy them over neatly. */
+	memset(kcmsg, 0, kcmlen);
+	ucmsg = CMSG32_FIRSTHDR(kmsg);
+	while(ucmsg != NULL) {
+		__get_user(ucmlen, &ucmsg->cmsg_len);
+		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
+		       CMSG_ALIGN(sizeof(struct cmsghdr)));
+		kcmsg->cmsg_len = tmp;
+		__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level);
+		__get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type);
+
+		/* Copy over the data. */
+		if(copy_from_user(CMSG_DATA(kcmsg),
+				  CMSG32_DATA(ucmsg),
+				  (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
+			goto out_free_efault;
+
+		/* Advance. */
+		kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));
+		ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
+	}
+
+	/* Ok, looks like we made it.  Hook it up and return success. */
+	kmsg->msg_control = kcmsg_base;
+	kmsg->msg_controllen = kcmlen;
+	return 0;
+
+out_free_efault:
+	if(kcmsg_base != (struct cmsghdr *)stackbuf)
+		kfree(kcmsg_base);
+	return -EFAULT;
+}
+
+static void put_cmsg32(struct msghdr *kmsg, int level, int type,
+		       int len, void *data)
+{
+	struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;
+	struct cmsghdr32 cmhdr;
+	int cmlen = CMSG32_LEN(len);
+
+	if(cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {
+		kmsg->msg_flags |= MSG_CTRUNC;
+		return;
+	}
+
+	if(kmsg->msg_controllen < cmlen) {
+		kmsg->msg_flags |= MSG_CTRUNC;
+		cmlen = kmsg->msg_controllen;
+	}
+	cmhdr.cmsg_level = level;
+	cmhdr.cmsg_type = type;
+	cmhdr.cmsg_len = cmlen;
+
+	if(copy_to_user(cm, &cmhdr, sizeof cmhdr))
+		return;
+	if(copy_to_user(CMSG32_DATA(cm), data, cmlen - sizeof(struct cmsghdr32)))
+		return;
+	cmlen = CMSG32_SPACE(len);
+	kmsg->msg_control += cmlen;
+	kmsg->msg_controllen -= cmlen;
+}
+
+static void scm_detach_fds32(struct msghdr *kmsg, struct scm_cookie *scm)
+{
+	struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;
+	int fdmax = (kmsg->msg_controllen - sizeof(struct cmsghdr32)) / sizeof(int);
+	int fdnum = scm->fp->count;
+	struct file **fp = scm->fp->fp;
+	int *cmfptr;
+	int err = 0, i;
+
+	if (fdnum < fdmax)
+		fdmax = fdnum;
+
+	for (i = 0, cmfptr = (int *) CMSG32_DATA(cm); i < fdmax; i++, cmfptr++) {
+		int new_fd;
+		err = get_unused_fd();
+		if (err < 0)
+			break;
+		new_fd = err;
+		err = put_user(new_fd, cmfptr);
+		if (err) {
+			put_unused_fd(new_fd);
+			break;
+		}
+		/* Bump the usage count and install the file. */
+		get_file(fp[i]);
+		fd_install(new_fd, fp[i]);
+	}
+
+	if (i > 0) {
+		int cmlen = CMSG32_LEN(i * sizeof(int));
+		if (!err)
+			err = put_user(SOL_SOCKET, &cm->cmsg_level);
+		if (!err)
+			err = put_user(SCM_RIGHTS, &cm->cmsg_type);
+		if (!err)
+			err = put_user(cmlen, &cm->cmsg_len);
+		if (!err) {
+			cmlen = CMSG32_SPACE(i * sizeof(int));
+			kmsg->msg_control += cmlen;
+			kmsg->msg_controllen -= cmlen;
+		}
+	}
+	if (i < fdnum)
+		kmsg->msg_flags |= MSG_CTRUNC;
+
+	/*
+	 * All of the files that fit in the message have had their
+	 * usage counts incremented, so we just free the list.
+	 */
+	__scm_destroy(scm);
+}
+
+/* In these cases we (currently) can just copy to data over verbatim
+ * because all CMSGs created by the kernel have well defined types which
+ * have the same layout in both the 32-bit and 64-bit API.  One must add
+ * some special cased conversions here if we start sending control messages
+ * with incompatible types.
+ *
+ * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after
+ * we do our work.  The remaining cases are:
+ *
+ * SOL_IP	IP_PKTINFO	struct in_pktinfo	32-bit clean
+ *		IP_TTL		int			32-bit clean
+ *		IP_TOS		__u8			32-bit clean
+ *		IP_RECVOPTS	variable length		32-bit clean
+ *		IP_RETOPTS	variable length		32-bit clean
+ *		(these last two are clean because the types are defined
+ *		 by the IPv4 protocol)
+ *		IP_RECVERR	struct sock_extended_err +
+ *				struct sockaddr_in	32-bit clean
+ * SOL_IPV6	IPV6_RECVERR	struct sock_extended_err +
+ *				struct sockaddr_in6	32-bit clean
+ *		IPV6_PKTINFO	struct in6_pktinfo	32-bit clean
+ *		IPV6_HOPLIMIT	int			32-bit clean
+ *		IPV6_FLOWINFO	u32			32-bit clean
+ *		IPV6_HOPOPTS	ipv6 hop exthdr		32-bit clean
+ *		IPV6_DSTOPTS	ipv6 dst exthdr(s)	32-bit clean
+ *		IPV6_RTHDR	ipv6 routing exthdr	32-bit clean
+ *		IPV6_AUTHHDR	ipv6 auth exthdr	32-bit clean
+ */
+static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
+{
+	unsigned char *workbuf, *wp;
+	unsigned long bufsz, space_avail;
+	struct cmsghdr *ucmsg;
+
+	bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr;
+	space_avail = kmsg->msg_controllen + bufsz;
+	wp = workbuf = kmalloc(bufsz, GFP_KERNEL);
+	if(workbuf == NULL)
+		goto fail;
+
+	/* To make this more sane we assume the kernel sends back properly
+	 * formatted control messages.  Because of how the kernel will truncate
+	 * the cmsg_len for MSG_TRUNC cases, we need not check that case either.
+	 */
+	ucmsg = (struct cmsghdr *) orig_cmsg_uptr;
+	while(((unsigned long)ucmsg) <=
+	      (((unsigned long)kmsg->msg_control) - sizeof(struct cmsghdr))) {
+		struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp;
+		int clen64, clen32;
+
+		/* UCMSG is the 64-bit format CMSG entry in user-space.
+		 * KCMSG32 is within the kernel space temporary buffer
+		 * we use to convert into a 32-bit style CMSG.
+		 */
+		__get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len);
+		__get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level);
+		__get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
+
+		clen64 = kcmsg32->cmsg_len;
+		copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
+			       clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
+		clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
+			  CMSG32_ALIGN(sizeof(struct cmsghdr32)));
+		kcmsg32->cmsg_len = clen32;
+
+		ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64));
+		wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32));
+	}
+
+	/* Copy back fixed up data, and adjust pointers. */
+	bufsz = (wp - workbuf);
+	copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz);
+
+	kmsg->msg_control = (struct cmsghdr *)
+		(((char *)orig_cmsg_uptr) + bufsz);
+	kmsg->msg_controllen = space_avail - bufsz;
+
+	kfree(workbuf);
+	return;
+
+fail:
+	/* If we leave the 64-bit format CMSG chunks in there,
+	 * the application could get confused and crash.  So to
+	 * ensure greater recovery, we report no CMSGs.
+	 */
+	kmsg->msg_controllen += bufsz;
+	kmsg->msg_control = (void *) orig_cmsg_uptr;
+}
+
+asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
+{
+	struct socket *sock;
+	char address[MAX_SOCK_ADDR];
+	struct iovec iov[UIO_FASTIOV];
+	unsigned char ctl[sizeof(struct cmsghdr) + 20];
+	unsigned char *ctl_buf = ctl;
+	struct msghdr kern_msg;
+	int err, total_len;
+
+	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
+		return -EFAULT;
+	if(kern_msg.msg_iovlen > UIO_MAXIOV)
+		return -EINVAL;
+	err = verify_iovec32(&kern_msg, iov, address, VERIFY_READ);
+	if (err < 0)
+		goto out;
+	total_len = err;
+
+	if(kern_msg.msg_controllen) {
+		err = cmsghdr_from_user32_to_kern(&kern_msg, ctl, sizeof(ctl));
+		if(err)
+			goto out_freeiov;
+		ctl_buf = kern_msg.msg_control;
+	}
+	kern_msg.msg_flags = user_flags;
+
+	sock = sockfd_lookup(fd, &err);
+	if (sock != NULL) {
+		if (sock->file->f_flags & O_NONBLOCK)
+			kern_msg.msg_flags |= MSG_DONTWAIT;
+		err = sock_sendmsg(sock, &kern_msg, total_len);
+		sockfd_put(sock);
+	}
+
+	/* N.B. Use kfree here, as kern_msg.msg_controllen might change? */
+	if(ctl_buf != ctl)
+		kfree(ctl_buf);
+out_freeiov:
+	if(kern_msg.msg_iov != iov)
+		kfree(kern_msg.msg_iov);
+out:
+	return err;
+}
+
+asmlinkage int sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags)
+{
+	struct iovec iovstack[UIO_FASTIOV];
+	struct msghdr kern_msg;
+	char addr[MAX_SOCK_ADDR];
+	struct socket *sock;
+	struct iovec *iov = iovstack;
+	struct sockaddr *uaddr;
+	int *uaddr_len;
+	unsigned long cmsg_ptr;
+	int err, total_len, len = 0;
+
+	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
+		return -EFAULT;
+	if(kern_msg.msg_iovlen > UIO_MAXIOV)
+		return -EINVAL;
+
+	uaddr = kern_msg.msg_name;
+	uaddr_len = &user_msg->msg_namelen;
+	err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE);
+	if (err < 0)
+		goto out;
+	total_len = err;
+
+	cmsg_ptr = (unsigned long) kern_msg.msg_control;
+	kern_msg.msg_flags = 0;
+
+	sock = sockfd_lookup(fd, &err);
+	if (sock != NULL) {
+		struct scm_cookie scm;
+
+		if (sock->file->f_flags & O_NONBLOCK)
+			user_flags |= MSG_DONTWAIT;
+		memset(&scm, 0, sizeof(scm));
+		err = sock->ops->recvmsg(sock, &kern_msg, total_len,
+					 user_flags, &scm);
+		if(err >= 0) {
+			len = err;
+			if(!kern_msg.msg_control) {
+				if(sock->passcred || scm.fp)
+					kern_msg.msg_flags |= MSG_CTRUNC;
+				if(scm.fp)
+					__scm_destroy(&scm);
+			} else {
+				/* If recvmsg processing itself placed some
+				 * control messages into user space, it's is
+				 * using 64-bit CMSG processing, so we need
+				 * to fix it up before we tack on more stuff.
+				 */
+				if((unsigned long) kern_msg.msg_control != cmsg_ptr)
+					cmsg32_recvmsg_fixup(&kern_msg, cmsg_ptr);
+
+				/* Wheee... */
+				if(sock->passcred)
+					put_cmsg32(&kern_msg,
+						   SOL_SOCKET, SCM_CREDENTIALS,
+						   sizeof(scm.creds), &scm.creds);
+				if(scm.fp != NULL)
+					scm_detach_fds32(&kern_msg, &scm);
+			}
+		}
+		sockfd_put(sock);
+	}
+
+	if(uaddr != NULL && err >= 0)
+		err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
+	if(cmsg_ptr != 0 && err >= 0) {
+		unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control);
+		__kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr - cmsg_ptr);
+		err |= __put_user(uclen, &user_msg->msg_controllen);
+	}
+	if(err >= 0)
+		err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags);
+	if(kern_msg.msg_iov != iov)
+		kfree(kern_msg.msg_iov);
+out:
+	if(err < 0)
+		return err;
+	return len;
+}
+
+
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
+				     char *optval, int optlen);
+
+static int do_set_attach_filter(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	struct sock_fprog32 {
+		__u16 len;
+		__u32 filter;
+	} *fprog32 = (struct sock_fprog32 *)optval;
+	struct sock_fprog kfprog;
+	struct sock_filter *kfilter;
+	unsigned int fsize;
+	mm_segment_t old_fs;
+	__u32 uptr;
+	int ret;
+
+	if (get_user(kfprog.len, &fprog32->len) ||
+	    __get_user(uptr, &fprog32->filter))
+		return -EFAULT;
+
+	kfprog.filter = (struct sock_filter *)A(uptr);
+	fsize = kfprog.len * sizeof(struct sock_filter);
+
+	kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL);
+	if (kfilter == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(kfilter, kfprog.filter, fsize)) {
+		kfree(kfilter);
+		return -EFAULT;
+	}
+
+	kfprog.filter = kfilter;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_setsockopt(fd, level, optname,
+			     (char *)&kfprog, sizeof(kfprog));
+	set_fs(old_fs);
+
+	kfree(kfilter);
+
+	return ret;
+}
+
+static int do_set_icmpv6_filter(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	struct icmp6_filter kfilter;
+	mm_segment_t old_fs;
+	int ret, i;
+
+	if (copy_from_user(&kfilter, optval, sizeof(kfilter)))
+		return -EFAULT;
+
+
+	for (i = 0; i < 8; i += 2) {
+		u32 tmp = kfilter.data[i];
+
+		kfilter.data[i] = kfilter.data[i + 1];
+		kfilter.data[i + 1] = tmp;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_setsockopt(fd, level, optname,
+			     (char *) &kfilter, sizeof(kfilter));
+	set_fs(old_fs);
+
+	return ret;
+}
+
+
+static int do_ipv4_set_replace(int fd, int level, int optname,
+				char *optval, int optlen)
+#if 1
+/* Fields happen to be padded such that this works.
+** Don't need to change iptables.h:struct ipt_replace
+*/
+{
+	struct ipt_replace *repl = (struct ipt_replace *) optval;
+	unsigned long ptr64;
+	unsigned int ptr32;
+	int ret;
+
+	if (copy_from_user(&ptr32, &repl->counters, sizeof(ptr32)))
+		return -EFAULT;
+	ptr64 = (unsigned long) ptr32;
+	if (copy_to_user(&repl->counters, &ptr64, sizeof(ptr64)))
+		return -EFAULT;
+
+	ret = sys_setsockopt(fd, level, optname, (char *) optval, optlen);
+
+	/* Restore 32-bit ptr */
+	if (copy_to_user(&repl->counters, &ptr32, sizeof(ptr32)))
+		return -EFAULT;
+
+	return ret;
+}
+#else
+/* This version tries to "do it right". ie allocate kernel buffers for
+** everything and copy data in/out. Way too complicated.
+** NOT TESTED for correctness!
+*/
+{
+	struct ipt_replace  *kern_repl;
+	struct ipt_counters *kern_counters;
+	unsigned int user_counters;
+	mm_segment_t old_fs;
+	int ret = 0;
+
+	kern_repl = (struct ipt_replace *) kmalloc(optlen+8, GFP_KERNEL);
+	if (!kern_repl)
+		return -ENOMEM;
+
+	if (copy_from_user(kern_repl, optval, optlen)) {
+		ret = -EFAULT;
+		goto err02;
+	}
+
+	/* 32-bit ptr is in the MSB's */
+	user_counters = (unsigned int) (((unsigned long) kern_repl->counters) >> 32);
+	/*
+	** We are going to set_fs() to kernel space - and thus need
+	** "relocate" the counters buffer to the kernel space.
+	*/
+	kern_counters = (struct ipt_counters *) kmalloc(kern_repl->num_counters * sizeof(struct ipt_counters), GFP_KERNEL);
+	if (!user_counters) {
+		ret = -ENOMEM;
+		goto err02;
+	}
+
+	if (copy_from_user(kern_counters, (char *) user_counters, optlen)) {
+		ret = -EFAULT;
+		goto err01;
+	}
+
+	/* We can update the kernel ptr now that we have the data. */
+	kern_repl->counters = kern_counters;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	ret = sys_setsockopt(fd, level, optname, (char *) optval, optlen);
+
+	set_fs(old_fs);
+
+	/* Copy counters back out to user space */
+	if (copy_to_user((char *) user_counters, kern_counters,
+			kern_repl->num_counters * sizeof(struct ipt_counters)))
+	{
+		ret = -EFAULT;
+		goto err01;
+	}
+
+	/* restore counters so userspace can consume it */
+	kern_repl->counters = NULL;
+	(unsigned int) kern_repl->counters = user_counters;
+
+	/* Copy repl back out to user space */
+	if (copy_to_user(optval, kern_repl, optlen))
+	{
+		ret = -EFAULT;
+	}
+
+err01:
+	kfree(kern_counters);
+err02:
+	kfree(kern_repl);
+	return ret;
+}
+#endif
+
+
+asmlinkage int sys32_setsockopt(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	if (optname == SO_ATTACH_FILTER)
+		return do_set_attach_filter(fd, level, optname, optval, optlen);
+
+	if (level == SOL_ICMPV6   && optname == ICMPV6_FILTER)
+		return do_set_icmpv6_filter(fd, level, optname, optval, optlen);
+
+	/*
+	** Beware:    IPT_SO_SET_REPLACE == IP6T_SO_SET_REPLACE
+	*/
+	if (level == IPPROTO_IP   && optname == IPT_SO_SET_REPLACE)
+		return do_ipv4_set_replace(fd, level, optname, optval, optlen);
+
+	if (level == IPPROTO_IPV6 && optname == IP6T_SO_SET_REPLACE)
+#if 0
+		/* FIXME: I don't (yet) use IPV6. -ggg */
+		return do_ipv6_set_replace(fd, level, optname, optval, optlen);
+#else
+	{
+		BUG();
+		return -ENXIO;
+	}
+#endif
+
+	return sys_setsockopt(fd, level, optname, optval, optlen);
+}
+
+
+/*** copied from mips64 ***/
+/*
+ * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
+ * 64-bit unsigned longs.
+ */
+
+static inline int
+get_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
+{
+	n = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
+	if (ufdset) {
+		unsigned long odd;
+
+		if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32)))
+			return -EFAULT;
+
+		odd = n & 1UL;
+		n &= ~1UL;
+		while (n) {
+			unsigned long h, l;
+			__get_user(l, ufdset);
+			__get_user(h, ufdset+1);
+			ufdset += 2;
+			*fdset++ = h << 32 | l;
+			n -= 2;
+		}
+		if (odd)
+			__get_user(*fdset, ufdset);
+	} else {
+		/* Tricky, must clear full unsigned long in the
+		 * kernel fdset at the end, this makes sure that
+		 * actually happens.
+		 */
+		memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32));
+	}
+	return 0;
+}
+
+static inline void
+set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
+{
+	unsigned long odd;
+	n = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
+
+	if (!ufdset)
+		return;
+
+	odd = n & 1UL;
+	n &= ~1UL;
+	while (n) {
+		unsigned long h, l;
+		l = *fdset++;
+		h = l >> 32;
+		__put_user(l, ufdset);
+		__put_user(h, ufdset+1);
+		ufdset += 2;
+		n -= 2;
+	}
+	if (odd)
+		__put_user(*fdset, ufdset);
+}
+
+/*** This is a virtual copy of sys_select from fs/select.c and probably
+ *** should be compared to it from time to time
+ ***/
+static inline void *select_bits_alloc(int size)
+{
+	return kmalloc(6 * size, GFP_KERNEL);
+}
+
+static inline void select_bits_free(void *bits, int size)
+{
+	kfree(bits);
+}
+
+/*
+ * We can actually return ERESTARTSYS instead of EINTR, but I'd
+ * like to be certain this leads to no problems. So I return
+ * EINTR just for safety.
+ *
+ * Update: ERESTARTSYS breaks at least the xview clock binary, so
+ * I'm trying ERESTARTNOHAND which restart only when you want to.
+ */
+#define MAX_SELECT_SECONDS \
+	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
+#define DIVIDE_ROUND_UP(x,y) (((x)+(y)-1)/(y))
+
+asmlinkage long
+sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, struct timeval32 *tvp)
+{
+	fd_set_bits fds;
+	char *bits;
+	long timeout;
+	int ret, size, err;
+
+	timeout = MAX_SCHEDULE_TIMEOUT;
+	if (tvp) {
+		struct timeval32 tv32;
+		time_t sec, usec;
+
+		if ((ret = copy_from_user(&tv32, tvp, sizeof tv32)))
+			goto out_nofds;
+
+		sec = tv32.tv_sec;
+		usec = tv32.tv_usec;
+
+		ret = -EINVAL;
+		if (sec < 0 || usec < 0)
+			goto out_nofds;
+
+		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
+			timeout = DIVIDE_ROUND_UP(usec, 1000000/HZ);
+			timeout += sec * (unsigned long) HZ;
+		}
+	}
+
+	ret = -EINVAL;
+	if (n < 0)
+		goto out_nofds;
+
+	if (n > current->files->max_fdset)
+		n = current->files->max_fdset;
+
+	/*
+	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
+	 * since we used fdset we need to allocate memory in units of
+	 * long-words. 
+	 */
+	ret = -ENOMEM;
+	size = FDS_BYTES(n);
+	bits = select_bits_alloc(size);
+	if (!bits)
+		goto out_nofds;
+	fds.in      = (unsigned long *)  bits;
+	fds.out     = (unsigned long *) (bits +   size);
+	fds.ex      = (unsigned long *) (bits + 2*size);
+	fds.res_in  = (unsigned long *) (bits + 3*size);
+	fds.res_out = (unsigned long *) (bits + 4*size);
+	fds.res_ex  = (unsigned long *) (bits + 5*size);
+
+	if ((ret = get_fd_set32(n, inp, fds.in)) ||
+	    (ret = get_fd_set32(n, outp, fds.out)) ||
+	    (ret = get_fd_set32(n, exp, fds.ex)))
+		goto out;
+	zero_fd_set(n, fds.res_in);
+	zero_fd_set(n, fds.res_out);
+	zero_fd_set(n, fds.res_ex);
+
+	ret = do_select(n, &fds, &timeout);
+
+	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
+		time_t sec = 0, usec = 0;
+		if (timeout) {
+			sec = timeout / HZ;
+			usec = timeout % HZ;
+			usec *= (1000000/HZ);
+		}
+		err = put_user(sec, &tvp->tv_sec);
+		err |= __put_user(usec, &tvp->tv_usec);
+		if (err)
+			ret = -EFAULT;
+	}
+
+	if (ret < 0)
+		goto out;
+	if (!ret) {
+		ret = -ERESTARTNOHAND;
+		if (signal_pending(current))
+			goto out;
+		ret = 0;
+	}
+
+	set_fd_set32(n, inp, fds.res_in);
+	set_fd_set32(n, outp, fds.res_out);
+	set_fd_set32(n, exp, fds.res_ex);
+
+out:
+	select_bits_free(bits, size);
+out_nofds:
+	return ret;
+}
+
+struct msgbuf32 {
+    int mtype;
+    char mtext[1];
+};
+
+asmlinkage long sys32_msgsnd(int msqid,
+				struct msgbuf32 *umsgp32,
+				size_t msgsz, int msgflg)
+{
+	struct msgbuf *mb;
+	struct msgbuf32 mb32;
+	int err;
+
+	if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+	err = get_user(mb32.mtype, &umsgp32->mtype);
+	mb->mtype = mb32.mtype;
+	err |= copy_from_user(mb->mtext, &umsgp32->mtext, msgsz);
+
+	if (err)
+		err = -EFAULT;
+	else
+		KERNEL_SYSCALL(err, sys_msgsnd, msqid, mb, msgsz, msgflg);
+
+	kfree(mb);
+	return err;
+}
+
+asmlinkage long sys32_msgrcv(int msqid,
+				struct msgbuf32 *umsgp32,
+				size_t msgsz, long msgtyp, int msgflg)
+{
+	struct msgbuf *mb;
+	struct msgbuf32 mb32;
+	int err, len;
+
+	if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+	KERNEL_SYSCALL(err, sys_msgrcv, msqid, mb, msgsz, msgtyp, msgflg);
+
+	if (err >= 0) {
+		len = err;
+		mb32.mtype = mb->mtype;
+		err = put_user(mb32.mtype, &umsgp32->mtype);
+		err |= copy_to_user(&umsgp32->mtext, mb->mtext, len);
+		if (err)
+			err = -EFAULT;
+		else
+			err = len;
+	}
+
+	kfree(mb);
+	return err;
+}
+
+/* LFS */
+
+extern asmlinkage long sys_truncate(const char *, loff_t);
+extern asmlinkage long sys_ftruncate(unsigned int, loff_t);
+extern asmlinkage long sys_fcntl(unsigned int, unsigned int, unsigned long);
+extern asmlinkage ssize_t sys_pread(unsigned int, char *, size_t, loff_t);
+extern asmlinkage ssize_t sys_pwrite(unsigned int, char *, size_t, loff_t);
+
+asmlinkage long sys32_truncate64(const char * path, unsigned int high, unsigned int low)
+{
+	return sys_truncate(path, (loff_t)high << 32 | low);
+}
+
+asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned int high, unsigned int low)
+{
+	return sys_ftruncate(fd, (loff_t)high << 32 | low);
+}
+
+asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+		case F_GETLK64:
+			cmd = F_GETLK;
+			break;
+		case F_SETLK64:
+			cmd = F_SETLK;
+			break;
+		case F_SETLKW64:
+			cmd = F_SETLKW;
+			break;
+		default:
+			break;
+	}
+	return sys_fcntl(fd, cmd, arg);
+}
+
+asmlinkage int sys32_pread(int fd, void *buf, size_t count, unsigned int high, unsigned int low)
+{
+	return sys_pread(fd, buf, count, (loff_t)high << 32 | low);
+}
+
+asmlinkage int sys32_pwrite(int fd, void *buf, size_t count, unsigned int high, unsigned int low)
+{
+       return sys_pwrite(fd, buf, count, (loff_t)high << 32 | low);
+}
+
+/* EXPORT/UNEXPORT */
+struct nfsctl_export32 {
+	char			ex_client[NFSCLNT_IDMAX+1];
+	char			ex_path[NFS_MAXPATHLEN+1];
+	__kernel_dev_t		ex_dev;
+	__kernel_ino_t32	ex_ino;
+	int			ex_flags;
+	__kernel_uid_t		ex_anon_uid;
+	__kernel_gid_t		ex_anon_gid;
+};
+
+/* GETFH */
+struct nfsctl_fhparm32 {
+	struct sockaddr		gf_addr;
+	__kernel_dev_t		gf_dev;
+	__kernel_ino_t32	gf_ino;
+	int			gf_version;
+};
+
+/* UGIDUPDATE */
+struct nfsctl_uidmap32 {
+	__kernel_caddr_t32	ug_ident;
+	__kernel_uid_t		ug_uidbase;
+	int			ug_uidlen;
+	__kernel_caddr_t32	ug_udimap;
+	__kernel_gid_t		ug_gidbase;
+	int			ug_gidlen;
+	__kernel_caddr_t32	ug_gdimap;
+};
+
+struct nfsctl_arg32 {
+	int			ca_version;	/* safeguard */
+	/* wide kernel places this union on 8-byte boundary, narrow on 4 */
+	union {
+		struct nfsctl_svc	u_svc;
+		struct nfsctl_client	u_client;
+		struct nfsctl_export32	u_export;
+		struct nfsctl_uidmap32	u_umap;
+		struct nfsctl_fhparm32	u_getfh;
+		struct nfsctl_fdparm	u_getfd;
+		struct nfsctl_fsparm	u_getfs;
+	} u;
+};
+
+asmlinkage int sys32_nfsservctl(int cmd, void *argp, void *resp)
+{
+	int ret, tmp;
+	struct nfsctl_arg32 n32;
+	struct nfsctl_arg n;
+
+	ret = copy_from_user(&n, argp, sizeof n.ca_version);
+	if (ret != 0)
+		return ret;
+
+	/* adjust argp to point at the union inside the user's n32 struct */
+	tmp = (unsigned long)&n32.u - (unsigned long)&n32;
+	argp = (void *)((unsigned long)argp + tmp);
+	switch(cmd) {
+	case NFSCTL_SVC:
+		ret = copy_from_user(&n.u, argp, sizeof n.u.u_svc);
+		break;
+
+	case NFSCTL_ADDCLIENT:
+	case NFSCTL_DELCLIENT:
+		ret = copy_from_user(&n.u, argp, sizeof n.u.u_client);
+		break;
+
+	case NFSCTL_GETFD:
+		ret = copy_from_user(&n.u, argp, sizeof n.u.u_getfd);
+		break;
+
+	case NFSCTL_GETFS:
+		ret = copy_from_user(&n.u, argp, sizeof n.u.u_getfs);
+		break;
+
+	case NFSCTL_GETFH:		/* nfsctl_fhparm */
+		ret = copy_from_user(&n32.u, argp, sizeof n32.u.u_getfh);
+#undef CP
+#define CP(x)	n.u.u_getfh.gf_##x = n32.u.u_getfh.gf_##x
+		CP(addr);
+		CP(dev);
+		CP(ino);
+		CP(version);
+		break;
+
+	case NFSCTL_UGIDUPDATE:		/* nfsctl_uidmap */
+		ret = copy_from_user(&n32.u, argp, sizeof n32.u.u_umap);
+#undef CP
+#define CP(x)	n.u.u_umap.ug_##x = n32.u.u_umap.ug_##x
+		n.u.u_umap.ug_ident = (char *)(u_long)n32.u.u_umap.ug_ident;
+		CP(uidbase);
+		CP(uidlen);
+		n.u.u_umap.ug_udimap = (__kernel_uid_t *)(u_long)n32.u.u_umap.ug_udimap;
+		CP(gidbase);
+		CP(gidlen);
+		n.u.u_umap.ug_gdimap = (__kernel_gid_t *)(u_long)n32.u.u_umap.ug_gdimap;
+		break;
+
+	case NFSCTL_UNEXPORT:		/* nfsctl_export */
+	case NFSCTL_EXPORT:		/* nfsctl_export */
+		ret = copy_from_user(&n32.u, argp, sizeof n32.u.u_export);
+#undef CP
+#define CP(x)	n.u.u_export.ex_##x = n32.u.u_export.ex_##x
+		memcpy(n.u.u_export.ex_client, n32.u.u_export.ex_client, sizeof n32.u.u_export.ex_client);
+		memcpy(n.u.u_export.ex_path, n32.u.u_export.ex_path, sizeof n32.u.u_export.ex_path);
+		CP(dev);
+		CP(ino);
+		CP(flags);
+		CP(anon_uid);
+		CP(anon_gid);
+		break;
+
+	default:
+		BUG(); /* new cmd values to be translated... */
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret == 0) {
+		unsigned char rbuf[NFS_FHSIZE + sizeof (struct knfsd_fh)];
+		KERNEL_SYSCALL(ret, sys_nfsservctl, cmd, &n, &rbuf);
+		if (cmd == NFSCTL_GETFH || cmd == NFSCTL_GETFD) {
+			ret = copy_to_user(resp, rbuf, NFS_FHSIZE);
+		} else if (cmd == NFSCTL_GETFS) {
+			ret = copy_to_user(resp, rbuf, sizeof (struct knfsd_fh));
+		}
+	}
+
+	return ret;
+}
+
+#include <linux/quota.h>
+
+struct dqblk32 {
+    __u32 dqb_bhardlimit;
+    __u32 dqb_bsoftlimit;
+    __u32 dqb_curblocks;
+    __u32 dqb_ihardlimit;
+    __u32 dqb_isoftlimit;
+    __u32 dqb_curinodes;
+    __kernel_time_t32 dqb_btime;
+    __kernel_time_t32 dqb_itime;
+};
+                                
+
+asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr)
+{
+	extern int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
+	int cmds = cmd >> SUBCMDSHIFT;
+	int err;
+	struct dqblk d;
+	char *spec;
+	
+	switch (cmds) {
+	case Q_GETQUOTA:
+		break;
+	case Q_SETQUOTA:
+	case Q_SETUSE:
+	case Q_SETQLIM:
+		if (copy_from_user (&d, (struct dqblk32 *)addr,
+				    sizeof (struct dqblk32)))
+			return -EFAULT;
+		d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
+		d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
+		break;
+	default:
+		return sys_quotactl(cmd, special,
+				    id, (caddr_t)addr);
+	}
+	spec = getname (special);
+	err = PTR_ERR(spec);
+	if (IS_ERR(spec)) return err;
+	KERNEL_SYSCALL(err, sys_quotactl, cmd, (const char *)spec, id, (caddr_t)&d);
+	putname (spec);
+	if (cmds == Q_GETQUOTA) {
+		__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
+		((struct dqblk32 *)&d)->dqb_itime = i;
+		((struct dqblk32 *)&d)->dqb_btime = b;
+		if (copy_to_user ((struct dqblk32 *)addr, &d,
+				  sizeof (struct dqblk32)))
+			return -EFAULT;
+	}
+	return err;
+}
+
+struct timex32 {
+	unsigned int modes;	/* mode selector */
+	int offset;		/* time offset (usec) */
+	int freq;		/* frequency offset (scaled ppm) */
+	int maxerror;		/* maximum error (usec) */
+	int esterror;		/* estimated error (usec) */
+	int status;		/* clock command/status */
+	int constant;		/* pll time constant */
+	int precision;		/* clock precision (usec) (read only) */
+	int tolerance;		/* clock frequency tolerance (ppm)
+				 * (read only)
+				 */
+	struct timeval32 time;	/* (read only) */
+	int tick;		/* (modified) usecs between clock ticks */
+
+	int ppsfreq;           /* pps frequency (scaled ppm) (ro) */
+	int jitter;            /* pps jitter (us) (ro) */
+	int shift;              /* interval duration (s) (shift) (ro) */
+	int stabil;            /* pps stability (scaled ppm) (ro) */
+	int jitcnt;            /* jitter limit exceeded (ro) */
+	int calcnt;            /* calibration intervals (ro) */
+	int errcnt;            /* calibration errors (ro) */
+	int stbcnt;            /* stability limit exceeded (ro) */
+
+	int  :32; int  :32; int  :32; int  :32;
+	int  :32; int  :32; int  :32; int  :32;
+	int  :32; int  :32; int  :32; int  :32;
+};
+
+asmlinkage long sys32_adjtimex(struct timex32 *txc_p32)
+{
+	struct timex txc;
+	struct timex32 t32;
+	int ret;
+	extern int do_adjtimex(struct timex *txc);
+
+	if(copy_from_user(&t32, txc_p32, sizeof(struct timex32)))
+		return -EFAULT;
+#undef CP
+#define CP(x) txc.x = t32.x
+	CP(modes); CP(offset); CP(freq); CP(maxerror); CP(esterror);
+	CP(status); CP(constant); CP(precision); CP(tolerance);
+	CP(time.tv_sec); CP(time.tv_usec); CP(tick); CP(ppsfreq); CP(jitter);
+	CP(shift); CP(stabil); CP(jitcnt); CP(calcnt); CP(errcnt);
+	CP(stbcnt);
+	ret = do_adjtimex(&txc);
+#define CP(x) t32.x = txc.x
+	CP(modes); CP(offset); CP(freq); CP(maxerror); CP(esterror);
+	CP(status); CP(constant); CP(precision); CP(tolerance);
+	CP(time.tv_sec); CP(time.tv_usec); CP(tick); CP(ppsfreq); CP(jitter);
+	CP(shift); CP(stabil); CP(jitcnt); CP(calcnt); CP(errcnt);
+	CP(stbcnt);
+	return copy_to_user(txc_p32, &t32, sizeof(struct timex32)) ? -EFAULT : ret;
+}
+
+
+struct sysinfo32 {
+	s32 uptime;
+	u32 loads[3];
+	u32 totalram;
+	u32 freeram;
+	u32 sharedram;
+	u32 bufferram;
+	u32 totalswap;
+	u32 freeswap;
+	unsigned short procs;
+	u32 totalhigh;
+	u32 freehigh;
+	u32 mem_unit;
+	char _f[12];
+};
+
+/* We used to call sys_sysinfo and translate the result.  But sys_sysinfo
+ * undoes the good work done elsewhere, and rather than undoing the
+ * damage, I decided to just duplicate the code from sys_sysinfo here.
+ */
+
+asmlinkage int sys32_sysinfo(struct sysinfo32 *info)
+{
+	struct sysinfo val;
+	int err;
+
+	/* We don't need a memset here because we copy the
+	 * struct to userspace once element at a time.
+	 */
+
+	cli();
+	val.uptime = jiffies / HZ;
+
+	val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);
+	val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
+	val.loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT);
+
+	val.procs = nr_threads-1;
+	sti();
+
+	si_meminfo(&val);
+	si_swapinfo(&val);
+	
+	err = put_user (val.uptime, &info->uptime);
+	err |= __put_user (val.loads[0], &info->loads[0]);
+	err |= __put_user (val.loads[1], &info->loads[1]);
+	err |= __put_user (val.loads[2], &info->loads[2]);
+	err |= __put_user (val.totalram, &info->totalram);
+	err |= __put_user (val.freeram, &info->freeram);
+	err |= __put_user (val.sharedram, &info->sharedram);
+	err |= __put_user (val.bufferram, &info->bufferram);
+	err |= __put_user (val.totalswap, &info->totalswap);
+	err |= __put_user (val.freeswap, &info->freeswap);
+	err |= __put_user (val.procs, &info->procs);
+	err |= __put_user (val.totalhigh, &info->totalhigh);
+	err |= __put_user (val.freehigh, &info->freehigh);
+	err |= __put_user (val.mem_unit, &info->mem_unit);
+	return err ? -EFAULT : 0;
+}
+
+
+/* lseek() needs a wrapper because 'offset' can be negative, but the top
+ * half of the argument has been zeroed by syscall.S.
+ */
+
+extern asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin);
+
+asmlinkage int sys32_lseek(unsigned int fd, int offset, unsigned int origin)
+{
+	return sys_lseek(fd, offset, origin);
+}
+
+asmlinkage long sys32_semctl_broken(int semid, int semnum, int cmd, union semun arg)
+{
+        union semun u;
+	
+	cmd &= ~IPC_64; /* should be removed together with the _broken suffix */
+
+        if (cmd == SETVAL) {
+                /* Ugh.  arg is a union of int,ptr,ptr,ptr, so is 8 bytes.
+                 * The int should be in the first 4, but our argument
+                 * frobbing has left it in the last 4.
+                 */
+                u.val = *((int *)&arg + 1);
+                return sys_semctl (semid, semnum, cmd, u);
+	}
+	return sys_semctl (semid, semnum, cmd, arg);
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/syscall.S linux-2.4.20/arch/parisc/kernel/syscall.S
--- linux-2.4.19/arch/parisc/kernel/syscall.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/syscall.S	2002-10-29 11:18:51.000000000 +0000
@@ -1,5 +1,5 @@
 /* 
- * Linux/PARISC Project (http://www.thepuffingroup.com/parisc)
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
  * 
  * System call entry code Copyright (c) Matthew Wilcox 1999 <willy@bofh.ai>
  * Licensed under the GNU GPL.
@@ -12,7 +12,6 @@
 #include <asm/errno.h>
 #include <asm/psw.h>
 
-#define __ASSEMBLY__
 #include <asm/assembly.h>
 #include <asm/processor.h>
 #include <linux/version.h>
@@ -23,7 +22,13 @@
 	.level		1.1
 #endif
 	.text
-	
+
+#ifdef __LP64__
+#define FRAME_SIZE	128
+#else
+#define FRAME_SIZE	64
+#endif
+
 	.import syscall_exit,code
 	.import syscall_exit_rfi,code
 	.export linux_gateway_page
@@ -39,17 +44,30 @@
 	.align 4096
 linux_gateway_page:
 
+	.rept 56
 	break   0,0
+	.endr
 
+set_thread_pointer:
+	gate	.+8, %r0		/* increase privilege */
+	depi	3, 31, 2, %r31		/* Ensure we return into user mode. */
+	be	0(%sr7,%r31)		/* return to user space */
+	mtctl	%r26, %cr27		/* move arg0 to the control register */
+
+	.rept 4
+	break   0,0
+	.endr
+
+/* This address must remain fixed, or user binaries go splat. */
 	.align 256
 linux_gateway_entry:
-	mfsp	%sr7,%r1			/* we must set sr3 to the space */
-	mtsp	%r1,%sr3			/* of the user before the gate */
 	gate	.+8, %r0			/* become privileged */
 	mtsp	%r0,%sr4			/* get kernel space into sr4 */
 	mtsp	%r0,%sr5			/* get kernel space into sr5 */
 	mtsp	%r0,%sr6			/* get kernel space into sr6 */
-	mtsp	%r0,%sr7			/* get kernel space into sr7 */
+	mfsp    %sr7,%r1                        /* save user sr7 */
+	mtsp    %r1,%sr3                        /* and store it in sr3 */
+
 #ifdef __LP64__
 	/* for now we can *always* set the W bit on entry to the syscall
 	 * since we don't support wide userland processes.  We could
@@ -58,15 +76,38 @@
 	 * whether to do narrow or wide syscalls. -PB
 	 */
 	ssm	PSW_SM_W, %r0
+	/* The top halves of argument registers must be cleared on syscall
+	 * entry.
+	 */
+	depdi	0, 31, 32, %r26
+	depdi	0, 31, 32, %r25
+	depdi	0, 31, 32, %r24
+	depdi	0, 31, 32, %r23
+	depdi	0, 31, 32, %r22
+	depdi	0, 31, 32, %r21
 #endif
-	mtctl	%r28,%cr27
-	rsm	PSW_I, %r28			/* no ints for a bit  */
-	mfctl	%cr30,%r1			/* get the kernel task ptr */
-	mtctl	%r0,%cr30			/* zero it (flag) */
+	mfctl   %cr30,%r1
+	xor     %r1,%r30,%r30                   /* ye olde xor trick */
+	xor     %r1,%r30,%r1
+	xor     %r1,%r30,%r30
+	ldo     TASK_SZ_ALGN+FRAME_SIZE(%r30),%r30  /* set up kernel stack */
+
+	/* N.B.: It is critical that we don't set sr7 to 0 until r30
+	 *       contains a valid kernel stack pointer. It is also
+	 *       critical that we don't start using the kernel stack
+	 *       until after sr7 has been set to 0.
+	 */
+
+	mtsp	%r0,%sr7			/* get kernel space into sr7 */
+	STREG   %r1,TASK_PT_GR30-TASK_SZ_ALGN-FRAME_SIZE(%r30) /* save usp */
+	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1   /* get task ptr in %r1 */
 
 	/* Save some registers for sigcontext and potential task
 	   switch (see entry.S for the details of which ones are
-	   saved/restored) */
+	   saved/restored).  TASK_PT_PSW is zeroed so we can see whether
+	   a process is on a syscall or not.  For an interrupt the real
+	   PSW value is stored.  This is needed for gdb and sys_ptrace. */
+	STREG	%r0,  TASK_PT_PSW(%r1)
 	STREG	%r2,  TASK_PT_GR2(%r1)		/* preserve rp */
 	STREG	%r19, TASK_PT_GR19(%r1)
 	STREG	%r20, TASK_PT_GR20(%r1)
@@ -77,11 +118,9 @@
 	STREG	%r25, TASK_PT_GR25(%r1)		/* 2nd argument */
 	STREG	%r26, TASK_PT_GR26(%r1)	 	/* 1st argument */
 	STREG	%r27, TASK_PT_GR27(%r1)		/* user dp */
-	mfctl	%cr27,%r19
-	STREG	%r19, TASK_PT_GR28(%r1)		/* return value 0 */
-	STREG	%r19, TASK_PT_ORIG_R28(%r1)	/* return value 0 (saved for signals) */
+	STREG   %r28, TASK_PT_GR28(%r1)         /* return value 0 */
+	STREG   %r28, TASK_PT_ORIG_R28(%r1)     /* return value 0 (saved for signals) */
 	STREG	%r29, TASK_PT_GR29(%r1)		/* return value 1 */
-	STREG	%r30, TASK_PT_GR30(%r1)		/* preserve userspace sp */
 	STREG	%r31, TASK_PT_GR31(%r1)		/* preserve syscall return ptr */
 	
 	ldo	TASK_PT_FR0(%r1), %r27		/* save fpregs from the kernel */
@@ -92,10 +131,10 @@
 
 	loadgp
 
-	ldo	TASK_SZ_ALGN+64(%r1),%r30	/* set up kernel stack */
-
-#ifndef __LP64__
-	/* no need to save these on stack because in wide mode the first 8
+#ifdef __LP64__
+	ldo	-16(%r30),%r29			/* Reference param save area */
+#else
+	/* no need to save these on stack in wide mode because the first 8
 	 * args are passed in registers */
 	stw     %r22, -52(%r30)                 /* 5th argument */
 	stw     %r21, -56(%r30)                 /* 6th argument */
@@ -103,7 +142,6 @@
 
 	/* for some unknown reason, task_struct.ptrace is an unsigned long so use LDREG */
 	LDREG	TASK_PTRACE(%r1), %r19		/* Are we being ptraced? */
-	mtsm	%r28				/* irqs back  */
 
 	bb,<,n	%r19, 31, .Ltracesys		/* must match PT_PTRACE bit */
 	
@@ -112,7 +150,6 @@
 
 	ldil	L%sys_call_table, %r1
 	ldo     R%sys_call_table(%r1), %r19
-	LDIL_FIXUP(%r19)
 	
 	comiclr,>>=	__NR_Linux_syscalls, %r20, %r0
 	b,n	.Lsyscall_nosys
@@ -131,13 +168,11 @@
 	comb,=	%r2,%r20,.Lrt_sigreturn
 .Lin_syscall:
 	ldil	L%syscall_exit,%r2
-	LDIL_FIXUP(%r2)
 	be      0(%sr7,%r19)
 	ldo	R%syscall_exit(%r2),%r2
 .Lrt_sigreturn:
 	comib,<> 0,%r25,.Lin_syscall
 	ldil	L%syscall_exit_rfi,%r2
-	LDIL_FIXUP(%r2)
 	be      0(%sr7,%r19)
 	ldo	R%syscall_exit_rfi(%r2),%r2
 
@@ -149,7 +184,6 @@
 .Lsyscall_nosys:
 syscall_nosys:
 	ldil	L%syscall_exit,%r1
-	LDIL_FIXUP(%r1)
 	be	R%syscall_exit(%sr7,%r1)
 	ldo	-ENOSYS(%r0),%r28		   /* set errno */
 
@@ -159,12 +193,17 @@
 .Ltracesys:
 tracesys:
 	/* Need to save more registers so the debugger can see where we
-	 * are.
+	 * are.  This saves only the lower 8 bits of PSW, so that the C
+	 * bit is still clear on syscalls, and the D bit is set if this
+	 * full register save path has been executed.  We check the D
+	 * bit on syscall_return_rfi to determine which registers to
+	 * restore.  An interrupt results in a full PSW saved with the
+	 * C bit set, a non-straced syscall entry results in C and D clear
+	 * in the saved PSW.
 	 */
-	ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
-	ssm	0,%r2				/* Lower 8 bits only!! */
-	STREG	%r2,TASK_PT_PSW(%r1)
-	STREG	%r1,TASK_PT_CR30(%r1)
+	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
+	ssm	0,%r2
+	STREG	%r2,TASK_PT_PSW(%r1)		/* Lower 8 bits only!! */
 	mfsp	%sr0,%r2
 	STREG	%r2,TASK_PT_SR0(%r1)
 	mfsp	%sr1,%r2
@@ -204,18 +243,15 @@
 	/* Finished saving things for the debugger */
 
 	ldil	L%syscall_trace,%r1
-	LDIL_FIXUP(%r1)
 	ldil	L%tracesys_next,%r2
-	LDIL_FIXUP(%r2)
 	be	R%syscall_trace(%sr7,%r1)
 	ldo	R%tracesys_next(%r2),%r2
 	
 tracesys_next:	
 	ldil	L%sys_call_table,%r1
-	LDIL_FIXUP(%r1)
 	ldo     R%sys_call_table(%r1), %r19
 
-	ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
 	LDREG   TASK_PT_GR20(%r1), %r20
 	LDREG   TASK_PT_GR26(%r1), %r26		/* Restore the users args */
 	LDREG   TASK_PT_GR25(%r1), %r25
@@ -224,6 +260,7 @@
 #ifdef __LP64__
 	LDREG   TASK_PT_GR22(%r1), %r22
 	LDREG   TASK_PT_GR21(%r1), %r21
+	ldo	-16(%r30),%r29			/* Reference param save area */
 #endif
 
 	comiclr,>>=	__NR_Linux_syscalls, %r20, %r0
@@ -243,7 +280,6 @@
 	comb,=	%r2,%r20,.Ltrace_rt_sigreturn
 .Ltrace_in_syscall:
 	ldil	L%tracesys_exit,%r2
-	LDIL_FIXUP(%r2)
 	be      0(%sr7,%r19)
 	ldo	R%tracesys_exit(%r2),%r2
 
@@ -251,30 +287,33 @@
 	makes a direct call to syscall_trace. */
 	
 tracesys_exit:
-	ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
+#ifdef __LP64__
+	ldo	-16(%r30),%r29			/* Reference param save area */
+#endif
 	bl	syscall_trace, %r2
 	STREG   %r28,TASK_PT_GR28(%r1)          /* save return value now */
-	ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
 	LDREG   TASK_PT_GR28(%r1), %r28		/* Restore return val. */
 
 	ldil	L%syscall_exit,%r1
-	LDIL_FIXUP(%r1)
 	be,n	R%syscall_exit(%sr7,%r1)
 
 .Ltrace_rt_sigreturn:
 	comib,<> 0,%r25,.Ltrace_in_syscall
 	ldil	L%tracesys_sigexit,%r2
-	LDIL_FIXUP(%r2)
 	be      0(%sr7,%r19)
 	ldo	R%tracesys_sigexit(%r2),%r2
 
 tracesys_sigexit:
-	ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
+#ifdef __LP64__
+	ldo	-16(%r30),%r29			/* Reference param save area */
+#endif
 	bl	syscall_trace, %r2
 	nop
 
 	ldil	L%syscall_exit_rfi,%r1
-	LDIL_FIXUP(%r1)
 	be,n	R%syscall_exit_rfi(%sr7,%r1)
 
 #ifdef __LP64__
@@ -282,13 +321,13 @@
  * narrow palinux.  Use ENTRY_DIFF for those where a 32-bit specific
  * implementation is required on wide palinux.
  */
-#define ENTRY_SAME(_name_) .dword sys_##_name_
-#define ENTRY_DIFF(_name_) .dword sys32_##_name_
-#define ENTRY_UHOH(_name_) .dword sys32_unimplemented
+#define ENTRY_SAME(_name_) .dword sys_/**/_name_
+#define ENTRY_DIFF(_name_) .dword sys32_/**/_name_
+#define ENTRY_UHOH(_name_) .dword sys32_/**/unimplemented
 #else
-#define ENTRY_SAME(_name_) .word sys_##_name_
-#define ENTRY_DIFF(_name_) .word sys_##_name_
-#define ENTRY_UHOH(_name_) .word sys_##_name_
+#define ENTRY_SAME(_name_) .word sys_/**/_name_
+#define ENTRY_DIFF(_name_) .word sys_/**/_name_
+#define ENTRY_UHOH(_name_) .word sys_/**/_name_
 #endif
 
 	.align 8
@@ -316,7 +355,7 @@
 	ENTRY_SAME(socket)
 	/* struct stat is MAYBE identical wide and narrow ?? */
 	ENTRY_DIFF(newstat)
-	ENTRY_SAME(lseek)
+	ENTRY_DIFF(lseek)
 	ENTRY_SAME(getpid)		/* 20 */
 	/* the 'void * data' parameter may need re-packing in wide */
 	ENTRY_DIFF(mount)
@@ -391,8 +430,8 @@
 	ENTRY_DIFF(getrlimit)
 	ENTRY_DIFF(getrusage)
 	/* struct timeval and timezone are maybe?? consistent wide and narrow */
-	ENTRY_SAME(gettimeofday)
-	ENTRY_SAME(settimeofday)
+	ENTRY_DIFF(gettimeofday)
+	ENTRY_DIFF(settimeofday)
 	ENTRY_SAME(getgroups)	/* 80 */
 	ENTRY_SAME(setgroups)
 	/* struct socketaddr... */
@@ -402,12 +441,12 @@
 	ENTRY_DIFF(newlstat)
 	ENTRY_SAME(readlink)	/* 85 */
 	/* suspect we'll need some work for narrow shlibs on wide kernel */
+	/* NOTE this doesn't get used when I boot 32-bit userspace */
+	/* containing working shlib apps -- can this be nuked? */
 	ENTRY_UHOH(uselib)
 	ENTRY_SAME(swapon)
 	ENTRY_SAME(reboot)
-	/* argh! struct dirent contains a long */
-	ENTRY_UHOH(old_readdir)
-	/* I'm not certain about off_t... */
+	ENTRY_SAME(mmap2)
 	ENTRY_SAME(mmap)		/* 90 */
 	ENTRY_SAME(munmap)
 	ENTRY_SAME(truncate)
@@ -419,28 +458,27 @@
 	ENTRY_SAME(recv)
 	ENTRY_DIFF(statfs)
 	ENTRY_DIFF(fstatfs)		/* 100 */
-	ENTRY_SAME(ni_syscall)
+	ENTRY_SAME(stat64)
 	/* don't think hppa glibc even provides an entry pt for this
 	 * so disable for now */
 	ENTRY_UHOH(socketcall)
 	ENTRY_SAME(syslog)
 	/* even though manpage says struct timeval contains longs, ours has
 	 * time_t and suseconds_t -- both of which are safe wide/narrow */
-	ENTRY_SAME(setitimer)
-	ENTRY_SAME(getitimer)	/* 105 */
+	ENTRY_DIFF(setitimer)
+	ENTRY_DIFF(getitimer)	/* 105 */
 	ENTRY_SAME(capget)
 	ENTRY_SAME(capset)
-	ENTRY_SAME(pread)
-	ENTRY_SAME(pwrite)
+	ENTRY_DIFF(pread)
+	ENTRY_DIFF(pwrite)
 	ENTRY_SAME(getcwd)		/* 110 */
 	ENTRY_SAME(vhangup)
-	ENTRY_SAME(ni_syscall)
+	ENTRY_SAME(fstat64)
 	ENTRY_SAME(vfork_wrapper)
 	/* struct rusage contains longs... */
 	ENTRY_DIFF(wait4)
 	ENTRY_SAME(swapoff)		/* 115 */
-	/* struct sysinfo contains longs */
-	ENTRY_SAME(sysinfo)
+	ENTRY_DIFF(sysinfo)
 	ENTRY_SAME(shutdown)
 	ENTRY_SAME(fsync)
 	ENTRY_SAME(madvise)
@@ -450,7 +488,7 @@
 	/* struct sockaddr... */
 	ENTRY_SAME(recvfrom)
 	/* struct timex contains longs */
-	ENTRY_UHOH(adjtimex)
+	ENTRY_DIFF(adjtimex)
 	ENTRY_SAME(mprotect)	/* 125 */
 	/* old_sigset_t forced to 32 bits.  Beware glibc sigset_t */
 	ENTRY_DIFF(sigprocmask)
@@ -461,12 +499,11 @@
 	ENTRY_SAME(delete_module)
 	/* struct kernel_sym contains a long. Linus never heard of size_t? */
 	ENTRY_DIFF(get_kernel_syms)	/* 130 */
-	ENTRY_SAME(quotactl)
+	/* time_t inside struct dqblk */
+	ENTRY_DIFF(quotactl)
 	ENTRY_SAME(getpgid)
 	ENTRY_SAME(fchdir)
-	/* bdflush(func, addr) where func has least-significant-bit set means
-	 * addr is a pointer to long :-( */
-	ENTRY_UHOH(bdflush)
+	ENTRY_SAME(bdflush)
 	ENTRY_SAME(sysfs)		/* 135 */
 	ENTRY_SAME(personality)
 	ENTRY_SAME(ni_syscall)	/* for afs_syscall */
@@ -479,12 +516,12 @@
 	ENTRY_DIFF(getdents)
 	/* it is POSSIBLE that select will be OK because even though fd_set
 	 * contains longs, the macros and sizes are clever. */
-	ENTRY_SAME(select)
+	ENTRY_DIFF(select)
 	ENTRY_SAME(flock)
 	ENTRY_SAME(msync)
 	/* struct iovec contains pointers */
-	ENTRY_UHOH(readv)		/* 145 */
-	ENTRY_UHOH(writev)
+	ENTRY_DIFF(readv)		/* 145 */
+	ENTRY_DIFF(writev)
 	ENTRY_SAME(getsid)
 	ENTRY_SAME(fdatasync)
 	/* struct __sysctl_args is a mess */
@@ -509,13 +546,12 @@
 	ENTRY_SAME(mremap)
 	ENTRY_SAME(setresuid)
 	ENTRY_SAME(getresuid)	/* 165 */
-	/* might work, but in general signals need a thorough review */
-	ENTRY_UHOH(sigaltstack_wrapper)
+	ENTRY_DIFF(sigaltstack_wrapper)
 	/* struct passed back to user can contain long symbol values */
 	ENTRY_DIFF(query_module)
 	ENTRY_SAME(poll)
 	/* structs contain pointers and an in_addr... */
-	ENTRY_UHOH(nfsservctl)
+	ENTRY_DIFF(nfsservctl)
 	ENTRY_SAME(setresgid)	/* 170 */
 	ENTRY_SAME(getresgid)
 	ENTRY_SAME(prctl)
@@ -525,35 +561,43 @@
 	ENTRY_DIFF(rt_sigprocmask)	/* 175 */
 	ENTRY_DIFF(rt_sigpending)
 	ENTRY_UHOH(rt_sigtimedwait)
-	ENTRY_UHOH(rt_sigqueueinfo)
+	/* even though the struct siginfo_t is different, it appears like
+	 * all the paths use values which should be same wide and narrow.
+	 * Also the struct is padded to 128 bytes which means we don't have
+	 * to worry about faulting trying to copy in a larger 64-bit
+	 * struct from a 32-bit user-space app.
+	 */
+	ENTRY_SAME(rt_sigqueueinfo)
 	ENTRY_SAME(rt_sigsuspend_wrapper) /* not really SAME -- see the code */
 	ENTRY_SAME(chown)		/* 180 */
-	/* *sockopt() might work... */
-	ENTRY_SAME(setsockopt)
+	/* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */
+	ENTRY_DIFF(setsockopt)
 	ENTRY_SAME(getsockopt)
-	/* struct msghdr contains pointers... */
-	ENTRY_UHOH(sendmsg)
-	ENTRY_UHOH(recvmsg)
+	ENTRY_DIFF(sendmsg)
+	ENTRY_DIFF(recvmsg)
 	ENTRY_SAME(semop)		/* 185 */
 	ENTRY_SAME(semget)
-	/* needs a more careful review */
-	ENTRY_UHOH(semctl)
-	/* struct msgbuf contains a long */
-	ENTRY_UHOH(msgsnd)
-	ENTRY_UHOH(msgrcv)
+	ENTRY_DIFF(semctl_broken)
+	ENTRY_DIFF(msgsnd)
+	ENTRY_DIFF(msgrcv)
 	ENTRY_SAME(msgget)		/* 190 */
-	/* struct msqid_ds contains pointers */
-	ENTRY_UHOH(msgctl)
+	ENTRY_SAME(msgctl_broken)
 	ENTRY_SAME(shmat_wrapper)
 	ENTRY_SAME(shmdt)
 	ENTRY_SAME(shmget)
-	/***************/
-	/* struct shmid_ds contains pointers */
-	ENTRY_UHOH(shmctl)		/* 195 */
+	ENTRY_SAME(shmctl_broken)		/* 195 */
 	ENTRY_SAME(ni_syscall)		/* streams1 */
 	ENTRY_SAME(ni_syscall)		/* streams2 */
+	ENTRY_SAME(lstat64)
+	ENTRY_DIFF(truncate64)
+	ENTRY_DIFF(ftruncate64)	/* 200 */
+	ENTRY_SAME(getdents64)
+	ENTRY_DIFF(fcntl64)
+	ENTRY_SAME(ni_syscall)		/* attrctl */
+	ENTRY_SAME(ni_syscall)		/* acl_get */
+	ENTRY_SAME(ni_syscall)		/* acl_set */
 	ENTRY_SAME(gettid)
-	ENTRY_SAME(tkill)
+	ENTRY_SAME(readahead)          
 
 .end
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/time.c linux-2.4.20/arch/parisc/kernel/time.c
--- linux-2.4.19/arch/parisc/kernel/time.c	2000-12-06 19:46:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/time.c	2002-10-29 11:18:39.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/arm/kernel/time.c
+ *  linux/arch/parisc/kernel/time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
  *  Modifications for ARM (C) 1994, 1995, 1996,1997 Russell King
@@ -10,6 +10,7 @@
  * 1998-12-20  Updated NTP code according to technical memorandum Jan '96
  *             "A Kernel Model for Precision Timekeeping" by Dave Mills
  */
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -30,69 +31,208 @@
 
 #include <linux/timex.h>
 
+/* xtime and wall_jiffies keep wall-clock time */
+extern unsigned long wall_jiffies;
 extern rwlock_t xtime_lock;
 
-static int timer_value;
-static int timer_delta;
-static struct pdc_tod tod_data __attribute__((aligned(8)));
+static long clocktick;	/* timer cycles per tick */
+static long halftick;
 
-void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#ifdef CONFIG_SMP
+extern void smp_do_timer(struct pt_regs *regs);
+#endif
+
+static inline void
+parisc_do_profile(unsigned long pc)
 {
-	int old;
-	int lost = 0;
-	int cr16;
-	
-	old = timer_value;
+	extern char _stext;
 
-	cr16 = mfctl(16);
-	while((timer_value - cr16) < (timer_delta / 2)) {
-		timer_value += timer_delta;
-		lost++;
-	}
+	if (!prof_buffer)
+		return;
 
-	mtctl(timer_value ,16);
+	pc -= (unsigned long) &_stext;
+	pc >>= prof_shift;
+	/*
+	 * Don't ignore out-of-bounds PC values silently,
+	 * put them into the last histogram slot, so if
+	 * present, they will show up as a sharp peak.
+	 */
+	if (pc > prof_len - 1)
+		pc = prof_len - 1;
+	atomic_inc((atomic_t *)&prof_buffer[pc]);
+}
+
+void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	long now = mfctl(16);
+	long next_tick;
+	int nticks;
+	int cpu = smp_processor_id();
+
+	/* initialize next_tick to time at last clocktick */
+
+	next_tick = cpu_data[cpu].it_value;
+
+	/* since time passes between the interrupt and the mfctl()
+	 * above, it is never true that last_tick + clocktick == now.  If we
+	 * never miss a clocktick, we could set next_tick = last_tick + clocktick
+	 * but maybe we'll miss ticks, hence the loop.
+	 *
+	 * Variables are *signed*.
+	 */
+
+	nticks = 0;
+	while((next_tick - now) < halftick) {
+		next_tick += clocktick;
+		nticks++;
+	}
+	mtctl(next_tick, 16);
+	cpu_data[cpu].it_value = next_tick;
 
-	do_timer(regs);
+	while (nticks--) {
+#ifdef CONFIG_SMP
+		smp_do_timer(regs);
+#endif
+		if (cpu == 0) {
+			extern int pc_in_user_space;
+			write_lock(&xtime_lock);
+#ifndef CONFIG_SMP
+			if (!user_mode(regs))
+				parisc_do_profile(regs->iaoq[0]);
+			else
+				parisc_do_profile(&pc_in_user_space);
+#endif
+			do_timer(regs);
+			write_unlock(&xtime_lock);
+		}
+	}
     
-	led_interrupt_func();
+#ifdef CONFIG_CHASSIS_LCD_LED
+	/* Only schedule the led tasklet on cpu 0, and only if it
+	 * is enabled.
+	 */
+	if (cpu == 0 && !atomic_read(&led_tasklet.count))
+		tasklet_schedule(&led_tasklet);
+#endif
+
+	/* check soft power switch status */
+	if (cpu == 0 && !atomic_read(&power_tasklet.count))
+		tasklet_schedule(&power_tasklet);
 }
 
-void do_gettimeofday(struct timeval *tv)
+/*** converted from ia64 ***/
+/*
+ * Return the number of micro-seconds that elapsed since the last
+ * update to wall time (aka xtime aka wall_jiffies).  The xtime_lock
+ * must be at least read-locked when calling this routine.
+ */
+static inline unsigned long
+gettimeoffset (void)
 {
-	unsigned long flags;
-	
+#ifndef CONFIG_SMP
+	/*
+	 * FIXME: This won't work on smp because jiffies are updated by cpu 0.
+	 *    Once parisc-linux learns the cr16 difference between processors,
+	 *    this could be made to work.
+	 */
+	long last_tick;
+	long elapsed_cycles;
+
+	/* it_value is the intended time of the next tick */
+	last_tick = cpu_data[smp_processor_id()].it_value;
+
+	/* Subtract one tick and account for possible difference between
+	 * when we expected the tick and when it actually arrived.
+	 * (aka wall vs real)
+	 */
+	last_tick -= clocktick * (jiffies - wall_jiffies + 1);
+	elapsed_cycles = mfctl(16) - last_tick;
+
+	/* the precision of this math could be improved */
+	return elapsed_cycles / (PAGE0->mem_10msec / 10000);
+#else
+	return 0;
+#endif
+}
+
+void
+do_gettimeofday (struct timeval *tv)
+{
+	unsigned long flags, usec, sec;
+
 	read_lock_irqsave(&xtime_lock, flags);
-	tv->tv_sec = xtime.tv_sec;
-	tv->tv_usec = xtime.tv_usec;
+	{
+		usec = gettimeoffset();
+	
+		sec = xtime.tv_sec;
+		usec += xtime.tv_usec;
+	}
 	read_unlock_irqrestore(&xtime_lock, flags);
 
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		++sec;
+	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
 }
 
-void do_settimeofday(struct timeval *tv)
+void
+do_settimeofday (struct timeval *tv)
 {
 	write_lock_irq(&xtime_lock);
-	xtime.tv_sec = tv->tv_sec;
-	xtime.tv_usec = tv->tv_usec;
+	{
+		/*
+		 * This is revolting. We need to set "xtime"
+		 * correctly. However, the value in this location is
+		 * the value at the most recent update of wall time.
+		 * Discover what correction gettimeofday would have
+		 * done, and then undo it!
+		 */
+		tv->tv_usec -= gettimeoffset();
+		tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
+
+		while (tv->tv_usec < 0) {
+			tv->tv_usec += 1000000;
+			tv->tv_sec--;
+		}
+
+		xtime = *tv;
+		time_adjust = 0;		/* stop active adjtime() */
+		time_status |= STA_UNSYNC;
+		time_maxerror = NTP_PHASE_LIMIT;
+		time_esterror = NTP_PHASE_LIMIT;
+	}
 	write_unlock_irq(&xtime_lock);
 }
 
+
 void __init time_init(void)
 {
-	timer_delta = (100 * PAGE0->mem_10msec) / HZ;
+	unsigned long next_tick;
+	static struct pdc_tod tod_data;
+
+	clocktick = (100 * PAGE0->mem_10msec) / HZ;
+	halftick = clocktick / 2;
 
-	/* make the first timer interrupt go off in one second */
-	timer_value = mfctl(16) + (HZ * timer_delta);
-	mtctl(timer_value, 16);
+	/* Setup clock interrupt timing */
 
+	next_tick = mfctl(16);
+	next_tick += clocktick;
+	cpu_data[smp_processor_id()].it_value = next_tick;
+
+	/* kick off Itimer (CR16) */
+	mtctl(next_tick, 16);
 
 	if(pdc_tod_read(&tod_data) == 0) {
+		write_lock_irq(&xtime_lock);
 		xtime.tv_sec = tod_data.tod_sec;
 		xtime.tv_usec = tod_data.tod_usec;
+		write_unlock_irq(&xtime_lock);
 	} else {
 		printk(KERN_ERR "Error reading tod clock\n");
 	        xtime.tv_sec = 0;
 		xtime.tv_usec = 0;
 	}
-
 }
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/traps.c linux-2.4.20/arch/parisc/kernel/traps.c
--- linux-2.4.19/arch/parisc/kernel/traps.c	2002-02-25 19:37:53.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/traps.c	2002-10-29 11:18:48.000000000 +0000
@@ -23,15 +23,20 @@
 #include <linux/spinlock.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/console.h>
+
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/unaligned.h>
 #include <asm/atomic.h>
-
 #include <asm/smp.h>
 #include <asm/pdc.h>
 
+#include "../math-emu/math-emu.h"	/* for handle_fpe() */
+
 #ifdef CONFIG_KWDB
 #include <kdb/break.h>		/* for BI2_KGDB_GDB */
 #include <kdb/kgdb_types.h>	/* for __() */
@@ -40,150 +45,205 @@
 #include <kdb/trap.h>		/* for I_BRK_INST */
 #endif /* CONFIG_KWDB */
 
+#define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */
+			  /*  dumped to the console via printk)          */
 
-static inline void console_verbose(void)
-{
-	console_loglevel = 15;
-}
-
-
-void page_exception(void);
-
-/*
- * These constants are for searching for possible module text
- * segments.  VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
- * a guess of how much space is likely to be vmalloced.
- */
-#define VMALLOC_OFFSET (8*1024*1024)
-#define MODULE_RANGE (8*1024*1024)
-
-int kstack_depth_to_print = 24;
-
-static void printbinary(unsigned long x, int nbits)
+static int printbinary(char *buf, unsigned long x, int nbits)
 {
 	unsigned long mask = 1UL << (nbits - 1);
 	while (mask != 0) {
-		printk(mask & x ? "1" : "0");
+		*buf++ = (mask & x ? '1' : '0');
 		mask >>= 1;
 	}
+	*buf = '\0';
+
+	return nbits;
 }
 
-void show_regs(struct pt_regs *regs)
-{
-	int i;
 #ifdef __LP64__
-#define RFMT " %016lx"
+#define RFMT "%016lx"
 #else
-#define RFMT " %08lx"
+#define RFMT "%08lx"
 #endif
 
-	printk("\n"); /* don't want to have that pretty register dump messed up */
-
-	printk("     YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\nPSW: ");
-	printbinary(regs->gr[0], 32);
-	printk("    %s\n", print_tainted());
+void show_regs(struct pt_regs *regs)
+{
+	int i;
+	char buf[128], *p;
+	char *level;
+	unsigned long cr30;
+	unsigned long cr31;
+
+	level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT;
+
+	printk("%s\n", level); /* don't want to have that pretty register dump messed up */
+
+	printk("%s     YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\n", level);
+	printbinary(buf, regs->gr[0], 32);
+	printk("%sPSW: %s %s\n", level, buf, print_tainted());
 
 	for (i = 0; i < 32; i += 4) {
 		int j;
-		printk("r%d-%d\t", i, i + 3);
+		p = buf;
+		p += sprintf(p, "%sr%02d-%02d ", level, i, i + 3);
 		for (j = 0; j < 4; j++) {
-			printk(RFMT, i + j == 0 ? 0 : regs->gr[i + j]);
+			p += sprintf(p, " " RFMT, (i+j) == 0 ? 0 : regs->gr[i + j]);
 		}
-		printk("\n");
+		printk("%s\n", buf);
 	}
 
 	for (i = 0; i < 8; i += 4) {
 		int j;
-		printk("sr%d-%d\t", i, i + 4);
+		p = buf;
+		p += sprintf(p, "%ssr%d-%d  ", level, i, i + 3);
 		for (j = 0; j < 4; j++) {
-			printk(RFMT, regs->sr[i + j]);
+			p += sprintf(p, " " RFMT, regs->sr[i + j]);
 		}
-		printk("\n");
+		printk("%s\n", buf);
 	}
 
-#if REDICULOUSLY_VERBOSE
-	for (i = 0; i < 32; i++) {
-		printk("FR%2d : %016lx  ", i, regs->fr[i]);
-		if ((i & 1) == 1)
-			printk("\n");
-	}
+#if RIDICULOUSLY_VERBOSE
+	for (i = 0; i < 32; i += 2)
+		printk("%sFR%02d : %016lx  FR%2d : %016lx", level, i,
+				regs->fr[i], i+1, regs->fr[i+1]);
 #endif
 
-	printk("\nIASQ:" RFMT RFMT " IAOQ:" RFMT RFMT "\n",
-	       regs->iasq[0], regs->iasq[1], regs->iaoq[0], regs->iaoq[1]);
-	printk(" IIR: %08lx    ISR:" RFMT "  IOR:" RFMT "\nORIG_R28:" RFMT
-	       "\n", regs->iir, regs->isr, regs->ior, regs->orig_r28);
+	cr30 = mfctl(30);
+	cr31 = mfctl(31);
+	printk("%s\n", level);
+	printk("%sIASQ: " RFMT " " RFMT " IAOQ: " RFMT " " RFMT "\n",
+	       level, regs->iasq[0], regs->iasq[1], regs->iaoq[0], regs->iaoq[1]);
+	printk("%s IIR: %08lx    ISR: " RFMT "  IOR: " RFMT "\n",
+	       level, regs->iir, regs->isr, regs->ior);
+	printk("%s CPU: %8d   CR30: " RFMT " CR31: " RFMT "\n",
+	       level, ((struct task_struct *)cr30)->processor, cr30, cr31);
+	printk("%s ORIG_R28: " RFMT "\n", level, regs->orig_r28);
 }
 
-void
-die_if_kernel (char *str, struct pt_regs *regs, long err)
+
+static void dump_stack(unsigned long from, unsigned long to, int istackflag)
+{
+	unsigned int *fromptr;
+	unsigned int *toptr;
+
+	fromptr = (unsigned int *)from;
+	toptr = (unsigned int *)to;
+
+	printk("\n");
+	printk(KERN_CRIT "Dumping %sStack from 0x%p to 0x%p:\n",
+			istackflag ? "Interrupt " : "",
+			fromptr, toptr);
+
+	while (fromptr < toptr) {
+		printk(KERN_CRIT "%04lx %08x %08x %08x %08x %08x %08x %08x %08x\n",
+		    ((unsigned long)fromptr) & 0xffff,
+		    fromptr[0], fromptr[1], fromptr[2], fromptr[3],
+		    fromptr[4], fromptr[5], fromptr[6], fromptr[7]);
+		fromptr += 8;
+	}
+}
+
+
+void show_stack(struct pt_regs *regs)
 {
-	if (user_mode(regs)) {
 #if 1
+	/* If regs->sr[7] == 0, we are on a kernel stack */
+	if (regs->sr[7] == 0) {
+
+		unsigned long sp = regs->gr[30];
+		unsigned long cr30;
+		unsigned long cr31;
+		unsigned long stack_start;
+		struct pt_regs *int_regs;
+
+		cr30 = mfctl(30);
+		cr31 = mfctl(31);
+		stack_start = sp & ~(ISTACK_SIZE - 1);
+		if (stack_start == cr31) {
+		    /*
+		     * We are on the interrupt stack, get the stack
+		     * pointer from the first pt_regs structure on
+		     * the interrupt stack, so we can dump the task
+		     * stack first.
+		     */
+
+		    int_regs = (struct pt_regs *)cr31;
+		    sp = int_regs->gr[30];
+		    stack_start = sp & ~(INIT_TASK_SIZE - 1);
+		    if (stack_start != cr30) {
+			printk(KERN_CRIT "WARNING! Interrupt-Stack pointer and cr30 do not correspond!\n");
+			printk(KERN_CRIT "Dumping virtual address stack instead\n");
+			dump_stack((unsigned long)__va(stack_start), (unsigned long)__va(sp), 0);
+		    } else {
+			dump_stack(stack_start, sp, 0);
+		    };
+
+		    printk("\n\n" KERN_DEBUG "Registers at Interrupt:\n");
+		    show_regs(int_regs);
+
+		    /* Now dump the interrupt stack */
+
+		    sp = regs->gr[30];
+		    stack_start = sp & ~(ISTACK_SIZE - 1);
+		    dump_stack(stack_start,sp,1);
+		}
+		else
+		{
+		    /* Stack Dump! */
+		    printk(KERN_CRIT "WARNING! Stack pointer and cr30 do not correspond!\n");
+		    printk(KERN_CRIT "Dumping virtual address stack instead\n");
+		    dump_stack((unsigned long)__va(stack_start), (unsigned long)__va(sp), 0);
+		}
+	}
+#endif
+}
+
+
+void die_if_kernel(char *str, struct pt_regs *regs, long err)
+{
+	if (user_mode(regs)) {
+#ifdef PRINT_USER_FAULTS
 		if (err == 0)
 			return; /* STFU */
 
 		/* XXX for debugging only */
-		printk ("!!die_if_kernel: %s(%d): %s %ld\n",
+		printk(KERN_DEBUG "%s (pid %d): %s (code %ld)\n",
 			current->comm, current->pid, str, err);
 		show_regs(regs);
 #endif
 		return;
 	}
+	
+	/* unlock the pdc lock if necessary */
+	pdc_emergency_unlock();
 
-	printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err);
-
+	/* maybe the kernel hasn't booted very far yet and hasn't been able 
+	 * to initialize the serial or STI console. In that case we should 
+	 * re-enable the pdc console, so that the user will be able to 
+	 * identify the problem. */
+	if (!console_drivers)
+		pdc_console_restart();
+	
+	printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n",
+		current->comm, current->pid, str, err);
 	show_regs(regs);
 
 	/* Wot's wrong wif bein' racy? */
 	if (current->thread.flags & PARISC_KERNEL_DEATH) {
-		printk("die_if_kernel recursion detected.\n");
+		printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__);
 		sti();
 		while (1);
 	}
+
 	current->thread.flags |= PARISC_KERNEL_DEATH;
 	do_exit(SIGSEGV);
 }
 
-asmlinkage void cache_flush_denied(struct pt_regs * regs, long error_code)
-{
-}
-
-asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
-{
-}
-
-#ifndef CONFIG_MATH_EMULATION
-
-asmlinkage void math_emulate(long arg)
-{
-}
-
-#endif /* CONFIG_MATH_EMULATION */
-
 int syscall_ipi(int (*syscall) (struct pt_regs *), struct pt_regs *regs)
 {
 	return syscall(regs);
 }
 
-struct {
-	int retval;
-
-	int (*func) (void *, struct pt_regs *);
-	void * data;
-} ipi_action[NR_CPUS];
-
-void ipi_interrupt(int irq, void *unused, struct pt_regs *regs)
-{
-	int cpu = smp_processor_id();
-
-	if(!ipi_action[cpu].func)
-		BUG();
-
-	ipi_action[cpu].retval =
-		ipi_action[cpu].func(ipi_action[cpu].data, regs);
-}
-
 /* gdb uses break 4,8 */
 #define GDB_BREAK_INSN 0x10004
 void handle_gdb_break(struct pt_regs *regs, int wot)
@@ -204,15 +264,16 @@
 	struct save_state ssp;
 #endif /* CONFIG_KWDB */   
 
-	flush_all_caches();
 	switch(iir) {
 	case 0x00:
-		/* show registers, halt */
-		cli();
-		printk("break 0,0: pid=%d command='%s'\n",
+#ifdef PRINT_USER_FAULTS
+		printk(KERN_DEBUG "break 0,0: pid=%d command='%s'\n",
 		       current->pid, current->comm);
+#endif
 		die_if_kernel("Breakpoint", regs, 0);
+#ifdef PRINT_USER_FAULTS
 		show_regs(regs);
+#endif
 		si.si_code = TRAP_BRKPT;
 		si.si_addr = (void *) (regs->iaoq[0] & ~3);
 		si.si_signo = SIGTRAP;
@@ -225,7 +286,6 @@
 		break;
 
 #ifdef CONFIG_KWDB
-
 	case KGDB_BREAK_INSN:
 		mtctl(0, 15);
 		pt_regs_to_ssp(regs, &ssp);
@@ -243,14 +303,14 @@
 		regs->iaoq[0] = regs->iaoq[1];
 		regs->iaoq[1] += 4;
 		break;
-
 #endif /* CONFIG_KWDB */
 
 	default:
-		set_eiem(0);
-		printk("break %#08x: pid=%d command='%s'\n",
+#ifdef PRINT_USER_FAULTS
+		printk(KERN_DEBUG "break %#08x: pid=%d command='%s'\n",
 		       iir, current->pid, current->comm);
 		show_regs(regs);
+#endif
 		si.si_signo = SIGTRAP;
 		si.si_code = TRAP_BRKPT;
 		si.si_addr = (void *) (regs->iaoq[0] & ~3);
@@ -259,252 +319,151 @@
 	}
 }
 
-/* Format of the floating-point exception registers. */
-struct exc_reg {
-	unsigned int exception : 6;
-	unsigned int ei : 26;
-};
-
-/* Macros for grabbing bits of the instruction format from the 'ei'
-   field above. */
-/* Major opcode 0c and 0e */
-#define FP0CE_UID(i) (((i) >> 6) & 3)
-#define FP0CE_CLASS(i) (((i) >> 9) & 3)
-#define FP0CE_SUBOP(i) (((i) >> 13) & 7)
-#define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */
-#define FP0C_FORMAT(i) (((i) >> 11) & 3)
-#define FP0E_FORMAT(i) (((i) >> 11) & 1)
-
-/* Major opcode 0c, uid 2 (performance monitoring) */
-#define FPPM_SUBOP(i) (((i) >> 9) & 0x1f)
-
-/* Major opcode 2e (fused operations).   */
-#define FP2E_SUBOP(i)  (((i) >> 5) & 1)
-#define FP2E_FORMAT(i) (((i) >> 11) & 1)
-
-/* Major opcode 26 (FMPYSUB) */
-/* Major opcode 06 (FMPYADD) */
-#define FPx6_FORMAT(i) ((i) & 0x1f)
-
-/* Flags and enable bits of the status word. */
-#define FPSW_FLAGS(w) ((w) >> 27)
-#define FPSW_ENABLE(w) ((w) & 0x1f)
-#define FPSW_V (1<<4)
-#define FPSW_Z (1<<3)
-#define FPSW_O (1<<2)
-#define FPSW_U (1<<1)
-#define FPSW_I (1<<0)
-
-/* Emulate a floating point instruction if necessary and possible
-   (this will be moved elsewhere eventually).  Return zero if
-   successful or if emulation was not required, -1 if the instruction
-   is actually illegal or unimplemented.  The status word passed as
-   the first parameter will be modified to signal exceptions, if
-   any. */
-
-/* FIXME!!!  This is really incomplete and, at the moment, most
-   illegal FP instructions will simply act as no-ops.  Obviously that
-   is *not* what we want.  Also we don't even try to handle exception
-   types other than the 'unimplemented' ones. */
-int
-fp_emul_insn(u32 *sw, struct exc_reg exc, struct pt_regs *regs)
-{
-	switch (exc.exception) {
-	case 0x3:  /* Unimplemented, opcode 06 */
-		break;
-	case 0x9:  /* Unimplemented, opcode 0c */
-		/* We do not support quadword operations, end of
-                   story.  There's no support for them in GCC. */
-		if (FP0C_FORMAT(exc.ei) == 3)
-			return -1; /* SIGILL */
-		/* Fall through. */
-	case 0xa:  /* Unimplemented, opcode 0e */
-		if (FP0CE_CLASS(exc.ei) == 1) {
-			/* FCNV instructions of various sorts. */
-		} else {
-			if (FP0CE_CLASS(exc.ei == 0)
-			    && FP0CE_SUBOP(exc.ei == 5)) {
-				/* FRND instructions should be
-                                   emulated, at some point, I
-                                   guess. */
-				return -1; /* SIGILL */
-			}
-		}
-		break;
-	case 0x23: /* Unimplemented, opcode 26 */
-		break;
-	case 0x2b: /* Unimplemented, opcode 2e */
-		break;
-	case 0x1:  /* Unimplemented, opcode 0e/0c */
-		/* FIXME: How the hell are we supposed to tell which
-                   opcode it is? */
-		break;
-	default:
-		return -1; /* Punt */
-	}
 
+int handle_toc(void)
+{
+	printk(KERN_CRIT "TOC call.\n");
 	return 0;
 }
 
-/* Handle a floating point exception.  Return zero if the faulting
-   instruction can be completed successfully. */
-int
-handle_fpe(struct pt_regs *regs)
+static void default_trap(int code, struct pt_regs *regs)
 {
-	struct siginfo si;
-	union {
-		struct fpsw {
-			/* flag bits */
-			unsigned int fv : 1;
-			unsigned int fz : 1;
-			unsigned int fo : 1;
-			unsigned int fu : 1;
-			unsigned int fi : 1;
-
-			unsigned int c : 1;
-			unsigned int pad1 : 4;
-			unsigned int cq : 11;
-			unsigned int rm : 2;
-			unsigned int pad2 : 2;
-			unsigned int t : 1;
-			unsigned int d : 1;
-
-			/* enable bits */
-			unsigned int ev : 1;
-			unsigned int ez : 1;
-			unsigned int eo : 1;
-			unsigned int eu : 1;
-			unsigned int ei : 1;
-		} status;
-		u32 word;
-	} sw;
-	struct exc_reg excepts[7];
-	unsigned int code = 0;
-	unsigned int throw;
-
-	/* Status word = FR0L. */
-	memcpy(&sw, regs->fr, sizeof(sw));
-	/* Exception words = FR0R-FR3R. */
-	memcpy(excepts, ((char *) regs->fr) + 4, sizeof(excepts));
-
-	/* This is all CPU dependent.  Since there is no public
-           documentation on the PA2.0 processors we will just assume
-           everything is like the 7100/7100LC/7300LC for now.
-
-	   Specifically: All exceptions are marked as "unimplemented"
-	   in the exception word, and the only exception word used is
-	   excepts[1]. */
-
-	/* Try to emulate the instruction.  Also determine if it is
-           really an illegal instruction in the process.
-
-	   FIXME: fp_emul_insn() only checks for the "unimplemented"
-	   exceptions at the moment.  So this may break horribly on
-	   PA2.0, where we may want to also check to see if we should
-	   just send SIGFPE (or maybe not, let's see the documentation
-	   first...) */
-	if (fp_emul_insn(&sw.word, excepts[1], regs) == -1)
-		goto send_sigill;
-
-	/* Take the intersection of the flag bits in the FPSW and the
-           enable bits in the FPSW. */
-	throw = FPSW_FLAGS(sw.word) & FPSW_ENABLE(sw.word);
-
-	/* Concoct an appropriate si_code.  Of course we don't know
-           what to do if multiple exceptions were enabled and multiple
-           flags were set.  Maybe that's why HP/UX doesn't implement
-           feenableexcept(). */
-
-	if (throw == 0)
-		goto success; /* Duh. */
-	else if (throw & FPSW_V)
-		code = FPE_FLTINV;
-	else if (throw & FPSW_Z)
-		code = FPE_FLTDIV;
-	else if (throw & FPSW_O)
-		code = FPE_FLTOVF;
-	else if (throw & FPSW_U)
-		code = FPE_FLTUND;
-	else if (throw & FPSW_I)
-		code = FPE_FLTRES;
-
-#if 1 /* Debugging... */
-	printk("Unemulated floating point exception, pid=%d (%s)\n",
-	       current->pid, current->comm);
+	printk(KERN_ERR "Trap %d on CPU %d\n", code, smp_processor_id());
 	show_regs(regs);
-	{
-		int i;
-		printk("FP Status: %08x\n", sw.word);
-		printk("FP Exceptions:\n");
-		for (i = 0; i < 7; i++) {
-			printk("\tExcept%d: exception %03x insn %06x\n",
-			       i, excepts[i].exception, excepts[i].ei);
-		}
-	}
-#endif
+}
 
-	/* FIXME: Should we clear the flag bits, T bit, and exception
-           registers here? */
+void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap;
 
-	si.si_signo = SIGFPE;
-	si.si_errno = 0;
-	si.si_code = code;
-	si.si_addr = (void *) regs->iaoq[0];
-	force_sig_info(SIGFPE, &si, current);
-	return -1;
 
- send_sigill:
-	si.si_signo = SIGILL;
-	si.si_errno = 0;
-	si.si_code = ILL_COPROC;
-	si.si_addr = (void *) regs->iaoq[0];
-	force_sig_info(SIGILL, &si, current);
-	return -1;
-
- success:
-	/* We absolutely have to clear the T bit and exception
-           registers to allow the process to recover.  Otherwise every
-           subsequent floating point instruction will trap. */
-	sw.status.t = 0;
-	memset(excepts, 0, sizeof(excepts));
-
-	memcpy(regs->fr, &sw, sizeof(sw));
-	memcpy(((char *) regs->fr) + 4,excepts , sizeof(excepts));
-	return 0;
+#ifdef CONFIG_KWDB
+int debug_call (void)
+{
+    printk (KERN_DEBUG "Debug call.\n");
+    return 0;
 }
 
-int handle_toc(void)
+int debug_call_leaf (void)
 {
-	return 0;
+    return 0;
 }
+#endif /* CONFIG_KWDB */
+
 
-void default_trap(int code, struct pt_regs *regs)
+void transfer_pim_to_trap_frame(struct pt_regs *regs)
 {
-	printk("Trap %d on CPU %d\n", code, smp_processor_id());
+    register int i;
+    extern unsigned int hpmc_pim_data[];
+    struct pdc_hpmc_pim_11 *pim_narrow;
+    struct pdc_hpmc_pim_20 *pim_wide;
 
-	show_regs(regs);
-}
+    if (boot_cpu_data.cpu_type >= pcxu) {
 
-void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap;
+	pim_wide = (struct pdc_hpmc_pim_20 *)hpmc_pim_data;
 
+	/*
+	 * Note: The following code will probably generate a
+	 * bunch of truncation error warnings from the compiler.
+	 * Could be handled with an ifdef, but perhaps there
+	 * is a better way.
+	 */
 
-#ifdef CONFIG_KWDB
-int
-debug_call (void) {
-    printk ("Debug call.\n");
-    return 0;
-}
+	regs->gr[0] = pim_wide->cr[22];
 
-int
-debug_call_leaf (void) {
-    return 0;
+	for (i = 1; i < 32; i++)
+	    regs->gr[i] = pim_wide->gr[i];
+
+	for (i = 0; i < 32; i++)
+	    regs->fr[i] = pim_wide->fr[i];
+
+	for (i = 0; i < 8; i++)
+	    regs->sr[i] = pim_wide->sr[i];
+
+	regs->iasq[0] = pim_wide->cr[17];
+	regs->iasq[1] = pim_wide->iasq_back;
+	regs->iaoq[0] = pim_wide->cr[18];
+	regs->iaoq[1] = pim_wide->iaoq_back;
+
+	regs->sar  = pim_wide->cr[11];
+	regs->iir  = pim_wide->cr[19];
+	regs->isr  = pim_wide->cr[20];
+	regs->ior  = pim_wide->cr[21];
+    }
+    else {
+	pim_narrow = (struct pdc_hpmc_pim_11 *)hpmc_pim_data;
+
+	regs->gr[0] = pim_narrow->cr[22];
+
+	for (i = 1; i < 32; i++)
+	    regs->gr[i] = pim_narrow->gr[i];
+
+	for (i = 0; i < 32; i++)
+	    regs->fr[i] = pim_narrow->fr[i];
+
+	for (i = 0; i < 8; i++)
+	    regs->sr[i] = pim_narrow->sr[i];
+
+	regs->iasq[0] = pim_narrow->cr[17];
+	regs->iasq[1] = pim_narrow->iasq_back;
+	regs->iaoq[0] = pim_narrow->cr[18];
+	regs->iaoq[1] = pim_narrow->iaoq_back;
+
+	regs->sar  = pim_narrow->cr[11];
+	regs->iir  = pim_narrow->cr[19];
+	regs->isr  = pim_narrow->cr[20];
+	regs->ior  = pim_narrow->cr[21];
+    }
+
+    /*
+     * The following fields only have meaning if we came through
+     * another path. So just zero them here.
+     */
+
+    regs->ksp = 0;
+    regs->kpc = 0;
+    regs->orig_r28 = 0;
 }
-#endif /* CONFIG_KWDB */
 
-extern void do_page_fault(struct pt_regs *, int, unsigned long);
-extern void parisc_terminate(char *, struct pt_regs *, int, unsigned long);
-extern void transfer_pim_to_trap_frame(struct pt_regs *);
-extern void pdc_console_restart(void);
+
+/*
+ * This routine handles page faults.  It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ */
+void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long offset)
+{
+	static spinlock_t terminate_lock = SPIN_LOCK_UNLOCKED;
+
+	set_eiem(0);
+	__cli();
+	spin_lock(&terminate_lock);
+
+	/* unlock the pdc lock if necessary */
+	pdc_emergency_unlock();
+
+	/* restart pdc console if necessary */
+	if (!console_drivers)
+		pdc_console_restart();
+
+	if (code == 1)
+	    transfer_pim_to_trap_frame(regs);
+
+	show_stack(regs);
+
+	printk("\n");
+	printk(KERN_CRIT "%s: Code=%d regs=%p (Addr=" RFMT ")\n",
+			msg, code, regs, offset);
+	show_regs(regs);
+
+	spin_unlock(&terminate_lock);
+
+	/* put soft power button back under hardware control;
+	 * if the user had pressed it once at any time, the 
+	 * system will shut down immediately right here. */
+	pdc_soft_power_button(0);
+	
+	for(;;)
+	    ;
+}
 
 void handle_interruption(int code, struct pt_regs *regs)
 {
@@ -520,75 +479,127 @@
 	else
 	    sti();
 
-#ifdef __LP64__
-
-	/*
-	 * FIXME:
-	 * For 32 bit processes we don't want the b bits (bits 0 & 1)
-	 * in the ior. This is more appropriately handled in the tlb
-	 * miss handlers. Changes need to be made to support addresses
-	 * >32 bits for 64 bit processes.
-	 */
-
-	regs->ior &= 0x3FFFFFFFFFFFFFFFUL;
-#endif
-
 #if 0
-	printk("interrupted with code %d, regs %p\n", code, regs);
-	show_regs(regs);
+	printk(KERN_CRIT "Interruption # %d\n", code);
 #endif
 
 	switch(code) {
+
 	case  1:
-		parisc_terminate("High Priority Machine Check (HPMC)",regs,code,0);
+		/* High-priority machine check (HPMC) */
+		parisc_terminate("High Priority Machine Check (HPMC)",
+				regs, code, 0);
 		/* NOT REACHED */
-	case  3: /* Recovery counter trap */
+		
+	case  2:
+		/* Power failure interrupt */
+		printk(KERN_CRIT "Power failure interrupt !\n");
+		return;
+
+	case  3:
+		/* Recovery counter trap */
 		regs->gr[0] &= ~PSW_R;
 		if (regs->iasq[0])
 			handle_gdb_break(regs, TRAP_TRACE);
-		/* else this must be the start of a syscall - just let it
-		 * run.
-		 */
+		/* else this must be the start of a syscall - just let it run */
 		return;
 
 	case  5:
+		/* Low-priority machine check */
 		flush_all_caches();
 		cpu_lpmc(5, regs);
 		return;
 
 	case  6:
+		/* Instruction TLB miss fault/Instruction page fault */
 		fault_address = regs->iaoq[0];
 		fault_space   = regs->iasq[0];
 		break;
 
-	case  9: /* Break Instruction */
+	case  8:
+		/* Illegal instruction trap */
+		die_if_kernel("Illegal instruction", regs, code);
+		si.si_code = ILL_ILLOPC;
+		goto give_sigill;
+
+	case  9:
+		/* Break instruction trap */
 		handle_break(regs->iir,regs);
 		return;
+	
+	case 10:
+		/* Privileged operation trap */
+		die_if_kernel("Privileged operation", regs, code);
+		si.si_code = ILL_PRVOPC;
+		goto give_sigill;
+	
+	case 11:
+		/* Privileged register trap */
+		if ((regs->iir & 0xffdfffe0) == 0x034008a0) {
+
+			/* This is a MFCTL cr26/cr27 to gr instruction.
+			 * PCXS traps on this, so we need to emulate it.
+			 */
+
+			if (regs->iir & 0x00200000)
+				regs->gr[regs->iir & 0x1f] = mfctl(27);
+			else
+				regs->gr[regs->iir & 0x1f] = mfctl(26);
+
+			regs->iaoq[0] = regs->iaoq[1];
+			regs->iaoq[1] += 4;
+			regs->iasq[0] = regs->iasq[1];
+			return;
+		}
+
+		die_if_kernel("Privileged register usage", regs, code);
+		si.si_code = ILL_PRVREG;
+	give_sigill:
+		si.si_signo = SIGILL;
+		si.si_errno = 0;
+		si.si_addr = (void *) regs->iaoq[0];
+		force_sig_info(SIGILL, &si, current);
+		return;
 
 	case 14:
 		/* Assist Exception Trap, i.e. floating point exception. */
 		die_if_kernel("Floating point exception", regs, 0); /* quiet */
 		handle_fpe(regs);
 		return;
-	case 15:
-	case 16:  /* Non-Access TLB miss faulting address is in IOR */
+
 	case 17:
-	case 26:
+		/* Non-access data TLB miss fault/Non-access data page fault */
+		/* TODO: Still need to add slow path emulation code here */
 		fault_address = regs->ior;
-		fault_space   = regs->isr;
+		parisc_terminate("Non access data tlb fault!",regs,code,fault_address);
 
-		if (code == 26 && fault_space == 0)
-		    parisc_terminate("Data access rights fault in kernel",regs,code,fault_address);
+	case 18:
+		/* PCXS only -- later cpu's split this into types 26,27 & 28 */
+		/* Check for unaligned access */
+		if (check_unaligned(regs)) {
+			handle_unaligned(regs);
+			return;
+		}
+		/* Fall Through */
+
+	case 15: /* Data TLB miss fault/Data page fault */
+	case 26: /* PCXL: Data memory access rights trap */
+		fault_address = regs->ior;
+		fault_space   = regs->isr;
 		break;
 
 	case 19:
+		/* Data memory break trap */
 		regs->gr[0] |= PSW_X; /* So we can single-step over the trap */
 		/* fall thru */
 	case 21:
+		/* Page reference trap */
 		handle_gdb_break(regs, TRAP_HWBKPT);
 		return;
 
-	case 25: /* Taken branch trap */
+	case 25:
+		/* Taken branch trap */
+#ifndef CONFIG_KWDB
 		regs->gr[0] &= ~PSW_T;
 		if (regs->iasq[0])
 			handle_gdb_break(regs, TRAP_BRANCH);
@@ -596,9 +607,8 @@
 		 * run.
 		 */
 		return;
-
-#if 0 /* def CONFIG_KWDB */
-	case I_TAKEN_BR:	/* 25 */
+#else
+		/* Kernel debugger: */
 		mtctl(0, 15);
 		pt_regs_to_ssp(regs, &ssp);
 		kgdb_trap(I_TAKEN_BR, &ssp, 1);
@@ -606,39 +616,64 @@
 		break;
 #endif /* CONFIG_KWDB */
 
-	case  8:
-		die_if_kernel("Illegal instruction", regs, code);
-		si.si_code = ILL_ILLOPC;
-		goto give_sigill;
+	case  7:  
+		/* Instruction access rights */
+		/* PCXL: Instruction memory protection trap */
+
+		/*
+		 * This could be caused by either: 1) a process attempting
+		 * to execute within a vma that does not have execute
+		 * permission, or 2) an access rights violation caused by a
+		 * flush only translation set up by ptep_get_and_clear().
+		 * So we check the vma permissions to differentiate the two.
+		 * If the vma indicates we have execute permission, then
+		 * the cause is the latter one. In this case, we need to
+		 * call do_page_fault() to fix the problem.
+		 */
 
-	case 10:
-		die_if_kernel("Priviledged operation - shouldn't happen!", regs, code);
-		si.si_code = ILL_PRVOPC;
-		goto give_sigill;
-	case 11:
-		die_if_kernel("Priviledged register - shouldn't happen!", regs, code);
-		si.si_code = ILL_PRVREG;
-	give_sigill:
-		si.si_signo = SIGILL;
+		if (user_mode(regs)) {
+			struct vm_area_struct *vma;
+
+			down_read(&current->mm->mmap_sem);
+			vma = find_vma(current->mm,regs->iaoq[0]);
+			if (vma && (regs->iaoq[0] >= vma->vm_start)
+				&& (vma->vm_flags & VM_EXEC)) {
+
+				fault_address = regs->iaoq[0];
+				fault_space = regs->iasq[0];
+
+				up_read(&current->mm->mmap_sem);
+				break; /* call do_page_fault() */
+			}
+			up_read(&current->mm->mmap_sem);
+		}
+		/* Fall Through */
+
+	case 27: 
+		/* Data memory protection ID trap */
+		die_if_kernel("Protection id trap", regs, code);
+		si.si_code = SEGV_MAPERR;
+		si.si_signo = SIGSEGV;
 		si.si_errno = 0;
-		si.si_addr = (void *) regs->iaoq[0];
-		force_sig_info(SIGILL, &si, current);
+		if (code == 7)
+		    si.si_addr = (void *) regs->iaoq[0];
+		else
+		    si.si_addr = (void *) regs->ior;
+		force_sig_info(SIGSEGV, &si, current);
 		return;
 
-	case 28:  /* Unaligned just causes SIGBUS for now */
-		die_if_kernel("Unaligned data reference", regs, code);
-		si.si_code = BUS_ADRALN;
-		si.si_signo = SIGBUS;
-		si.si_errno = 0;
-		si.si_addr = (void *) regs->ior;
-		force_sig_info(SIGBUS, &si, current);
+	case 28: 
+		/* Unaligned data reference trap */
+		handle_unaligned(regs);
 		return;
 
 	default:
 		if (user_mode(regs)) {
-			printk("\nhandle_interruption() pid=%d command='%s'\n",
+#ifdef PRINT_USER_FAULTS
+			printk(KERN_DEBUG "\nhandle_interruption() pid=%d command='%s'\n",
 			    current->pid, current->comm);
 			show_regs(regs);
+#endif
 			/* SIGBUS, for lack of a better one. */
 			si.si_signo = SIGBUS;
 			si.si_code = BUS_OBJERR;
@@ -647,18 +682,20 @@
 			force_sig_info(SIGBUS, &si, current);
 			return;
 		}
-		parisc_terminate("Unexpected Interruption!",regs,code,0);
+		parisc_terminate("Unexpected interruption", regs, code, 0);
 		/* NOT REACHED */
 	}
 
 	if (user_mode(regs)) {
 	    if (fault_space != regs->sr[7]) {
+#ifdef PRINT_USER_FAULTS
 		if (fault_space == 0)
-			printk("User Fault on Kernel Space ");
-		else /* this case should never happen, but whatever... */
-			printk("User Fault (long pointer) ");
+			printk(KERN_DEBUG "User Fault on Kernel Space ");
+		else
+			printk(KERN_DEBUG "User Fault (long pointer) ");
 		printk("pid=%d command='%s'\n", current->pid, current->comm);
 		show_regs(regs);
+#endif
 		si.si_signo = SIGSEGV;
 		si.si_errno = 0;
 		si.si_code = SEGV_MAPERR;
@@ -674,7 +711,7 @@
 	     */
 
 	    if (fault_space == 0)
-		    parisc_terminate("Kernel Fault",regs,code,fault_address);
+		    parisc_terminate("Kernel Fault", regs, code, fault_address);
 	}
 
 #ifdef CONFIG_KWDB
@@ -682,149 +719,15 @@
 #endif /* CONFIG_KWDB */
 
 	do_page_fault(regs, code, fault_address);
-
-	/*
-	 * This should not be necessary.
-	 * However, we do not currently
-	 * implement flush_page_to_ram.
-	 *
-	 * The problem is that if we just
-	 * brought in some code through the
-	 * D-cache, the I-cache may not see
-	 * it since it hasn't been flushed
-	 * to ram.
-	 */
-
-/* 	flush_all_caches(); */
-
-#if 0
-	printk("returning %p\n", regs);
-/*	show_regs(regs); */
-#endif
-
-	return;
-
-}
-
-void show_stack(unsigned long sp)
-{
-#if 1
-	if ((sp & 0xc0000000UL) == 0xc0000000UL) {
-
-	    __u32 *stackptr;
-	    __u32 *dumpptr;
-
-	    /* Stack Dump! */
-
-	    stackptr = (__u32 *)sp;
-	    dumpptr  = (__u32 *)(sp & ~(INIT_TASK_SIZE - 1));
-	    printk("\nDumping Stack from %p to %p:\n",dumpptr,stackptr);
-	    while (dumpptr < stackptr) {
-		printk("%04x %08x %08x %08x %08x %08x %08x %08x %08x\n",
-		    ((__u32)dumpptr) & 0xffff,
-		    dumpptr[0], dumpptr[1], dumpptr[2], dumpptr[3],
-		    dumpptr[4], dumpptr[5], dumpptr[6], dumpptr[7]);
-		dumpptr += 8;
-	    }
-	}
-#endif
 }
 
 
-void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long offset)
+void show_trace_task(struct task_struct *tsk)
 {
-	set_eiem(0);
-	cli();
-
-	if (code == 1)
-	    transfer_pim_to_trap_frame(regs);
-
-#if 1
-	show_stack(regs->gr[30]);
-#endif
-
-	printk("\n%s: Code=%d regs=%p (Addr=%08lx)\n",msg,code,regs,offset);
-	show_regs(regs);
-
-	for(;;)
-	    ;
+    	BUG();
 }
 
-void transfer_pim_to_trap_frame(struct pt_regs *regs)
-{
-    register int i;
-    extern unsigned int hpmc_pim_data[];
-    struct pdc_hpmc_pim_11 *pim_narrow;
-    struct pdc_hpmc_pim_20 *pim_wide;
-
-    if (boot_cpu_data.cpu_type >= pcxu) {
 
-	pim_wide = (struct pdc_hpmc_pim_20 *)hpmc_pim_data;
-
-	/*
-	 * Note: The following code will probably generate a
-	 * bunch of truncation error warnings from the compiler.
-	 * Could be handled with an ifdef, but perhaps there
-	 * is a better way.
-	 */
-
-	regs->gr[0] = pim_wide->cr[22];
-
-	for (i = 1; i < 32; i++)
-	    regs->gr[i] = pim_wide->gr[i];
-
-	for (i = 0; i < 32; i++)
-	    regs->fr[i] = pim_wide->fr[i];
-
-	for (i = 0; i < 8; i++)
-	    regs->sr[i] = pim_wide->sr[i];
-
-	regs->iasq[0] = pim_wide->cr[17];
-	regs->iasq[1] = pim_wide->iasq_back;
-	regs->iaoq[0] = pim_wide->cr[18];
-	regs->iaoq[1] = pim_wide->iaoq_back;
-
-	regs->cr30 = pim_wide->cr[30];
-	regs->sar  = pim_wide->cr[11];
-	regs->iir  = pim_wide->cr[19];
-	regs->isr  = pim_wide->cr[20];
-	regs->ior  = pim_wide->cr[21];
-    }
-    else {
-	pim_narrow = (struct pdc_hpmc_pim_11 *)hpmc_pim_data;
-
-	regs->gr[0] = pim_narrow->cr[22];
-
-	for (i = 1; i < 32; i++)
-	    regs->gr[i] = pim_narrow->gr[i];
-
-	for (i = 0; i < 32; i++)
-	    regs->fr[i] = pim_narrow->fr[i];
-
-	for (i = 0; i < 8; i++)
-	    regs->sr[i] = pim_narrow->sr[i];
-
-	regs->iasq[0] = pim_narrow->cr[17];
-	regs->iasq[1] = pim_narrow->iasq_back;
-	regs->iaoq[0] = pim_narrow->cr[18];
-	regs->iaoq[1] = pim_narrow->iaoq_back;
-
-	regs->cr30 = pim_narrow->cr[30];
-	regs->sar  = pim_narrow->cr[11];
-	regs->iir  = pim_narrow->cr[19];
-	regs->isr  = pim_narrow->cr[20];
-	regs->ior  = pim_narrow->cr[21];
-    }
-
-    /*
-     * The following fields only have meaning if we came through
-     * another path. So just zero them here.
-     */
-
-    regs->ksp = 0;
-    regs->kpc = 0;
-    regs->orig_r28 = 0;
-}
 
 int __init check_ivt(void *iva)
 {
@@ -836,7 +739,7 @@
 	extern void os_hpmc(void);
 	extern void os_hpmc_end(void);
 
-	if(strcmp((char *)iva, "cows can fly"))
+	if (strcmp((char *)iva, "cows can fly"))
 		return -1;
 
 	ivap = (u32 *)iva;
@@ -851,10 +754,10 @@
 
 	hpmcp = (u32 *)os_hpmc;
 
-	for(i=0; i<length/4; i++)
+	for (i=0; i<length/4; i++)
 	    check += *hpmcp++;
 
-	for(i=0; i<8; i++)
+	for (i=0; i<8; i++)
 	    check += ivap[i];
 
 	ivap[5] = -check;
@@ -869,11 +772,8 @@
 
 void __init trap_init(void)
 {
-	volatile long eiem;
 	void *iva;
 
-	printk("trap_init\n");
-	
 	if (boot_cpu_data.cpu_type >= pcxu)
 		iva = (void *) &fault_vector_20;
 	else
@@ -883,12 +783,6 @@
 		iva = (void *) &fault_vector_11;
 #endif
 
-	if(check_ivt(iva))
+	if (check_ivt(iva))
 		panic("IVT invalid");
-
-	mtctl(0, 30);
-	mtctl(90000000, 16);
-	set_eiem(-1L);
-	mtctl(-1L, 23);
-	asm volatile ("rsm 0,%0" : "=r" (eiem));
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/kernel/unaligned.c linux-2.4.20/arch/parisc/kernel/unaligned.c
--- linux-2.4.19/arch/parisc/kernel/unaligned.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/kernel/unaligned.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,434 @@
+/*    $Id: unaligned.c,v 1.9 2001/10/04 03:31:08 tausq Exp $
+ *
+ *    Unaligned memory access handler
+ *
+ *    Copyright (C) 2001 Randolph Chung <tausq@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+
+#include <asm/smp.h>
+#include <asm/pdc.h>
+
+/* #define DEBUG_UNALIGNED 1 */
+
+#ifdef DEBUG_UNALIGNED
+#define DPRINTF(fmt, args...) do { printk(KERN_DEBUG "%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__ ); printk(KERN_DEBUG fmt, ##args ); } while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
+
+#ifdef __LP64__
+#define RFMT "%016lx"
+#else
+#define RFMT "%08lx"
+#endif
+
+/* 1111 1100 0000 0000 0001 0011 1100 0000 */
+#define OPCODE1(a,b,c)	((a)<<26|(b)<<12|(c)<<6) 
+#define OPCODE2(a,b)	((a)<<26|(b)<<1)
+#define OPCODE3(a,b)	((a)<<26|(b)<<2)
+#define OPCODE4(a)	((a)<<26)
+#define OPCODE1_MASK	OPCODE1(0x3f,1,0xf)
+#define OPCODE2_MASK 	OPCODE2(0x3f,1)
+#define OPCODE3_MASK	OPCODE3(0x3f,1)
+#define OPCODE4_MASK    OPCODE4(0x3f)
+
+/* skip LDB (index) */
+#define OPCODE_LDH_I	OPCODE1(0x03,0,0x1)
+#define OPCODE_LDW_I	OPCODE1(0x03,0,0x2)
+#define OPCODE_LDD_I	OPCODE1(0x03,0,0x3)
+#define OPCODE_LDDA_I	OPCODE1(0x03,0,0x4)
+/* skip LDCD (index) */
+#define OPCODE_LDWA_I	OPCODE1(0x03,0,0x6)
+/* skip LDCW (index) */
+/* skip LDB (short) */
+#define OPCODE_LDH_S	OPCODE1(0x03,1,0x1)
+#define OPCODE_LDW_S	OPCODE1(0x03,1,0x2)
+#define OPCODE_LDD_S	OPCODE1(0x03,1,0x3)
+#define OPCODE_LDDA_S	OPCODE1(0x03,1,0x4)
+/* skip LDCD (short) */
+#define OPCODE_LDWA_S	OPCODE1(0x03,1,0x6)
+/* skip LDCW (short) */
+/* skip STB */
+#define OPCODE_STH	OPCODE1(0x03,1,0x9)
+#define OPCODE_STW	OPCODE1(0x03,1,0xa)
+#define OPCODE_STD	OPCODE1(0x03,1,0xb)
+/* skip STBY */
+/* skip STDBY */
+#define OPCODE_STWA	OPCODE1(0x03,1,0xe)
+#define OPCODE_STDA	OPCODE1(0x03,1,0xf)
+
+#define OPCODE_LDD_L	OPCODE2(0x14,0)
+#define OPCODE_FLDD_L	OPCODE2(0x14,1)
+#define OPCODE_STD_L	OPCODE2(0x1c,0)
+#define OPCODE_FSTD_L	OPCODE2(0x1c,1)
+
+#define OPCODE_LDW_M	OPCODE3(0x17,1)
+#define OPCODE_FLDW_L	OPCODE3(0x17,0)
+#define OPCODE_FSTW_L	OPCODE3(0x1f,0)
+#define OPCODE_STW_M	OPCODE3(0x1f,1)
+
+#define OPCODE_LDH_L    OPCODE4(0x11)
+#define OPCODE_LDW_L    OPCODE4(0x12)
+#define OPCODE_LDW_L2   OPCODE4(0x13)
+#define OPCODE_STH_L    OPCODE4(0x19)
+#define OPCODE_STW_L    OPCODE4(0x1A)
+#define OPCODE_STW_L2   OPCODE4(0x1B)
+
+
+
+void die_if_kernel (char *str, struct pt_regs *regs, long err);
+
+static int emulate_load(struct pt_regs *regs, int len, int toreg)
+{
+	unsigned long saddr = regs->ior;
+	unsigned long val = 0;
+	int ret = 0;
+
+	if (regs->isr != regs->sr[7])
+	{
+		printk(KERN_CRIT "isr verification failed (isr: " RFMT ", sr7: " RFMT "\n",
+			regs->isr, regs->sr[7]);
+		return 1;
+	}
+
+	DPRINTF("load " RFMT ":" RFMT " to r%d for %d bytes\n", 
+		regs->isr, regs->ior, toreg, len);
+
+	__asm__ __volatile__  (
+"       mfsp %%sr1, %%r20\n"
+"       mtsp %6, %%sr1\n"
+"	copy %%r0, %0\n"
+"0:	ldbs,ma	1(%%sr1,%4), %%r19\n"
+"	addi -1, %5, %5\n"
+"	cmpib,>= 0, %5, 2f\n"
+"	or %%r19, %0, %0\n"
+"	b 0b\n"
+	
+#ifdef __LP64__
+	"depd,z %0, 55, 56, %0\n"
+#else
+	"depw,z %0, 23, 24, %0\n"
+#endif
+	
+"1:	ldi	10, %1\n"
+"2:     mtsp %%r20, %%sr1\n"
+"	.section __ex_table,\"a\"\n"
+#ifdef __LP64__
+	".dword 0b, (1b-0b)\n"
+#else
+	".word 0b, (1b-0b)\n"
+#endif
+	".previous\n" 
+	: "=r" (val), "=r" (ret)
+	: "0" (val), "1" (ret), "r" (saddr), "r" (len), "r" (regs->isr)
+	: "r19", "r20" );
+
+	DPRINTF("val = 0x" RFMT "\n", val);
+
+	regs->gr[toreg] = val;
+
+	return ret;
+}
+
+static int emulate_store(struct pt_regs *regs, int len, int frreg)
+{
+	int ret = 0;
+#ifdef __LP64__
+	unsigned long val = regs->gr[frreg] << (64 - (len << 3));
+#else
+	unsigned long val = regs->gr[frreg] << (32 - (len << 3));
+#endif
+
+	if (regs->isr != regs->sr[7])
+	{
+		printk(KERN_CRIT "isr verification failed (isr: " RFMT ", sr7: " RFMT "\n",
+			regs->isr, regs->sr[7]);
+		return 1;
+	}
+
+	DPRINTF("store r%d (0x" RFMT ") to " RFMT ":" RFMT " for %d bytes\n", frreg, 
+		regs->gr[frreg], regs->isr, regs->ior, len);
+
+
+	__asm__ __volatile__ (
+"       mfsp %%sr1, %%r20\n"		/* save sr1 */
+"       mtsp %5, %%sr1\n"
+#ifdef __LP64__
+"0:	extrd,u %2, 7, 8, %%r19\n"
+#else
+"0:	extrw,u %2, 7, 8, %%r19\n"
+#endif
+"1:	stb,ma %%r19, 1(%%sr1, %3)\n"
+"	addi -1, %4, %4\n"
+"	cmpib,>= 0, %4, 3f\n"
+	
+#ifdef __LP64__
+	"depd,z %2, 55, 56, %2\n"
+#else
+	"depw,z %2, 23, 24, %2\n"
+#endif
+
+"	b 0b\n"
+"	nop\n"
+
+"2:	ldi 11, %0\n"
+"3:     mtsp %%r20, %%sr1\n"
+"	.section __ex_table,\"a\"\n"
+#ifdef __LP64__
+	".dword 1b, (2b-1b)\n"
+#else
+	".word 1b, (2b-1b)\n"
+#endif
+	".previous\n" 
+	: "=r" (ret)
+	: "0" (ret), "r" (val), "r" (regs->ior), "r" (len), "r" (regs->isr)
+	: "r19", "r20" );
+
+	return ret;
+}
+
+
+void handle_unaligned(struct pt_regs *regs)
+{
+	unsigned long unaligned_count = 0;
+	unsigned long last_time = 0;
+	int ret = -1;
+	struct siginfo si;
+
+	/* if the unaligned access is inside the kernel:
+	 *   if the access is caused by a syscall, then we fault the calling
+	 *     user process
+	 *   otherwise we halt the kernel
+	 */
+	if (!user_mode(regs))
+	{
+		const struct exception_table_entry *fix;
+
+		/* see if the offending code have its own
+		 * exception handler 
+		 */ 
+
+		fix = search_exception_table(regs->iaoq[0]);
+		if (fix)
+		{
+			/* lower bits of fix->skip are flags
+			 * upper bits are the handler addr
+			 */
+			if (fix->skip & 1)
+				regs->gr[8] = -EFAULT;
+			if (fix->skip & 2)
+				regs->gr[9] = 0;
+
+			regs->iaoq[0] += ((fix->skip) & ~3);
+			regs->iaoq[1] = regs->iaoq[0] + 4;
+			regs->gr[0] &= ~PSW_B;
+
+			return;
+		}
+	}
+
+	/* log a message with pacing */
+	if (user_mode(regs))
+	{
+		if (unaligned_count > 5 && jiffies - last_time > 5*HZ)
+		{
+			unaligned_count = 0;
+			last_time = jiffies;
+		}
+		if (++unaligned_count < 5)
+		{
+			char buf[256];
+			sprintf(buf, "%s(%d): unaligned access to 0x" RFMT " at ip=0x" RFMT "\n",
+				current->comm, current->pid, regs->ior, regs->iaoq[0]);
+			printk(KERN_WARNING "%s", buf);
+#ifdef DEBUG_UNALIGNED
+			show_regs(regs);
+#endif		
+		}
+	}
+
+	/* TODO: make this cleaner... */
+	switch (regs->iir & OPCODE1_MASK)
+	{
+	case OPCODE_LDH_I:
+	case OPCODE_LDH_S:
+		ret = emulate_load(regs, 2, regs->iir & 0x1f);
+		break;
+
+	case OPCODE_LDW_I:
+	case OPCODE_LDWA_I:
+	case OPCODE_LDW_S:
+	case OPCODE_LDWA_S:
+		ret = emulate_load(regs, 4, regs->iir&0x1f);
+		break;
+
+	case OPCODE_LDD_I:
+	case OPCODE_LDDA_I:
+	case OPCODE_LDD_S:
+	case OPCODE_LDDA_S:
+		ret = emulate_load(regs, 8, regs->iir&0x1f);
+		break;
+
+	case OPCODE_STH:
+		ret = emulate_store(regs, 2, (regs->iir>>16)&0x1f);
+		break;
+
+	case OPCODE_STW:
+	case OPCODE_STWA:
+		ret = emulate_store(regs, 4, (regs->iir>>16)&0x1f);
+		break;
+
+	case OPCODE_STD:
+	case OPCODE_STDA:
+		ret = emulate_store(regs, 8, (regs->iir>>16)&0x1f);
+		break;
+	}
+	switch (regs->iir & OPCODE2_MASK)
+	{
+	case OPCODE_LDD_L:
+	case OPCODE_FLDD_L:
+		ret = emulate_load(regs, 8, (regs->iir>>16)&0x1f);
+		break;
+
+	case OPCODE_STD_L:
+	case OPCODE_FSTD_L:
+		ret = emulate_store(regs, 8, (regs->iir>>16)&0x1f);
+		break;
+	}
+	switch (regs->iir & OPCODE3_MASK)
+	{
+	case OPCODE_LDW_M:
+	case OPCODE_FLDW_L:
+		ret = emulate_load(regs, 4, (regs->iir>>16)&0x1f);
+		break;
+
+	case OPCODE_FSTW_L:
+	case OPCODE_STW_M:
+		ret = emulate_store(regs, 4, (regs->iir>>16)&0x1f);
+		break;
+	}
+	switch (regs->iir & OPCODE4_MASK)
+	{
+	case OPCODE_LDH_L:
+		ret = emulate_load(regs, 2, (regs->iir>>16)&0x1f);
+		break;
+	case OPCODE_LDW_L:
+	case OPCODE_LDW_L2:
+		ret = emulate_load(regs, 4, (regs->iir>>16)&0x1f);
+		break;
+	case OPCODE_STH_L:
+		ret = emulate_store(regs, 2, (regs->iir>>16)&0x1f);
+		break;
+	case OPCODE_STW_L:
+	case OPCODE_STW_L2:
+		ret = emulate_store(regs, 4, (regs->iir>>16)&0x1f);
+		break;
+	}
+
+	if (ret < 0)
+		printk(KERN_CRIT "Not-handled unaligned insn 0x%08lx\n", regs->iir);
+
+	DPRINTF("ret = %d\n", ret);
+
+	if (ret)
+	{
+		printk(KERN_CRIT "Unaligned handler failed, ret = %d\n", ret);
+		die_if_kernel("Unaligned data reference", regs, 28);
+
+		/* couldn't handle it ... */
+		si.si_signo = SIGBUS;
+		si.si_errno = 0;
+		si.si_code = BUS_ADRALN;
+		si.si_addr = (void *)regs->ior;
+		force_sig_info(SIGBUS, &si, current);
+		
+		return;
+	}
+
+	/* else we handled it, advance the PC.... */
+	regs->iaoq[0] = regs->iaoq[1];
+	regs->iaoq[1] = regs->iaoq[0] + 4;
+}
+
+/*
+ * NB: check_unaligned() is only used for PCXS processors right
+ * now, so we only check for PA1.1 encodings at this point.
+ */
+
+int
+check_unaligned(struct pt_regs *regs)
+{
+	unsigned long align_mask;
+
+	/* Get alignment mask */
+
+	align_mask = 0UL;
+	switch (regs->iir & OPCODE1_MASK) {
+
+	case OPCODE_LDH_I:
+	case OPCODE_LDH_S:
+	case OPCODE_STH:
+		align_mask = 1UL;
+		break;
+
+	case OPCODE_LDW_I:
+	case OPCODE_LDWA_I:
+	case OPCODE_LDW_S:
+	case OPCODE_LDWA_S:
+	case OPCODE_STW:
+	case OPCODE_STWA:
+		align_mask = 3UL;
+		break;
+
+	default:
+		switch (regs->iir & OPCODE4_MASK) {
+		case OPCODE_LDH_L:
+		case OPCODE_STH_L:
+			align_mask = 1UL;
+			break;
+		case OPCODE_LDW_L:
+		case OPCODE_LDW_L2:
+		case OPCODE_STW_L:
+		case OPCODE_STW_L2:
+			align_mask = 3UL;
+			break;
+		}
+		break;
+	}
+
+	return (int)(regs->ior & align_mask);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/lib/Makefile linux-2.4.20/arch/parisc/lib/Makefile
--- linux-2.4.19/arch/parisc/lib/Makefile	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/lib/Makefile	2002-10-29 11:18:48.000000000 +0000
@@ -4,10 +4,6 @@
 
 
 L_TARGET = lib.a
-L_OBJS	= lusercopy.o bitops.o checksum.o
-
-
-.S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+obj-y	:= lusercopy.o bitops.o checksum.o io.o memset.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/lib/bitops.c linux-2.4.20/arch/parisc/lib/bitops.c
--- linux-2.4.19/arch/parisc/lib/bitops.c	2000-12-06 19:46:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/lib/bitops.c	2002-10-29 11:18:33.000000000 +0000
@@ -1,7 +1,10 @@
-/* atomic.c: atomic operations which got too long to be inlined all over
- * the place.
+/*
+ * bitops.c: atomic operations which got too long to be inlined all over
+ *      the place.
  * 
- * Copyright 1999 Philipp Rumpf (prumpf@tux.org */
+ * Copyright 1999 Philipp Rumpf (prumpf@tux.org)
+ * Copyright 2000 Grant Grundler (grundler@cup.hp.com)
+ */
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -17,44 +20,67 @@
 
 spinlock_t __atomic_lock = SPIN_LOCK_UNLOCKED;
 
-#ifndef __LP64__
-unsigned long __xchg(unsigned long x, unsigned long *ptr, int size)
+#ifdef __LP64__
+unsigned long __xchg64(unsigned long x, unsigned long *ptr)
 {
 	unsigned long temp, flags;
 
-	if (size != sizeof x) {
-		printk("__xchg called with bad pointer\n");
-	}
-	spin_lock_irqsave(&__atomic_lock, flags);
+	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags);
 	temp = *ptr;
 	*ptr = x;
-	spin_unlock_irqrestore(&__atomic_lock, flags);
+	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags);
 	return temp;
 }
-#else
-unsigned long __xchg(unsigned long x, unsigned long *ptr, int size)
+#endif
+
+unsigned long __xchg32(int x, int *ptr)
 {
-	unsigned long temp, flags;
-	unsigned int *ptr32;
+	unsigned long flags;
+	unsigned long temp;
+
+	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags);
+	(long) temp = (long) *ptr;	/* XXX - sign extension wanted? */
+	*ptr = x;
+	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags);
+	return temp;
+}
+
+
+unsigned long __xchg8(char x, char *ptr)
+{
+	unsigned long flags;
+	unsigned long temp;
 
-	if (size == 8) {
-try_long:
-		spin_lock_irqsave(&__atomic_lock, flags);
-		temp = *ptr;
-		*ptr = x;
-		spin_unlock_irqrestore(&__atomic_lock, flags);
-		return temp;
-	}
-	if (size == 4) {
-		ptr32 = (unsigned int *)ptr;
-		spin_lock_irqsave(&__atomic_lock, flags);
-		temp = (unsigned long)*ptr32;
-		*ptr32 = (unsigned int)x;
-		spin_unlock_irqrestore(&__atomic_lock, flags);
-		return temp;
-	}
+	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags);
+	(long) temp = (long) *ptr;	/* XXX - sign extension wanted? */
+	*ptr = x;
+	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags);
+	return temp;
+}
+
+
+#ifdef __LP64__
+unsigned long __cmpxchg_u64(volatile unsigned long *ptr, unsigned long old, unsigned long new)
+{
+	unsigned long flags;
+	unsigned long prev;
 
-	printk("__xchg called with bad pointer\n");
-	goto try_long;
+	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags);
+	if ((prev = *ptr) == old)
+		*ptr = new;
+	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags);
+	return prev;
 }
 #endif
+
+unsigned long __cmpxchg_u32(volatile unsigned int *ptr, unsigned int old, unsigned int new)
+{
+	unsigned long flags;
+	unsigned int prev;
+
+	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags);
+	if ((prev = *ptr) == old)
+		*ptr = new;
+	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags);
+	return (unsigned long)prev;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/lib/io.c linux-2.4.20/arch/parisc/lib/io.c
--- linux-2.4.19/arch/parisc/lib/io.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/lib/io.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,459 @@
+/*
+ * arch/parisc/lib/io.c
+ *
+ * Copyright (c) Matthew Wilcox 2001 for Hewlett-Packard
+ * Copyright (c) Randolph Chung 2001 <tausq@debian.org>
+ *
+ * IO accessing functions which shouldn't be inlined because they're too big
+ */
+
+#include <linux/kernel.h>
+#include <asm/io.h>
+
+/* Copies a block of memory to a device in an efficient manner.
+ * Assumes the device can cope with 32-bit transfers.  If it can't,
+ * don't use this function.
+ */
+void memcpy_toio(unsigned long dest, const void *src, int count)
+{
+	if ((dest & 3) != ((unsigned long)src & 3))
+		goto bytecopy;
+	while (dest & 3) {
+		writeb(*(char *)src, dest++);
+		((char *)src)++;
+		count--;
+	}
+	while (count > 3) {
+		__raw_writel(*(u32 *)src, dest);
+		(unsigned long) src += 4;
+		dest += 4;
+		count -= 4;
+	}
+ bytecopy:
+	while (count--) {
+		writeb(*(char *)src, dest++);
+		((char *)src)++;
+	}
+}
+
+/*
+** Copies a block of memory from a device in an efficient manner.
+** Assumes the device can cope with 32-bit transfers.  If it can't,
+** don't use this function.
+**
+** CR16 counts on C3000 reading 256 bytes from Symbios 896 RAM:
+**	27341/64    = 427 cyc per int
+**	61311/128   = 478 cyc per short
+**	122637/256  = 479 cyc per byte
+** Ergo bus latencies dominant (not transfer size).
+**      Minimize total number of transfers at cost of CPU cycles.
+**	TODO: only look at src alignment and adjust the stores to dest.
+*/
+void memcpy_fromio(void *dest, unsigned long src, int count)
+{
+	/* first compare alignment of src/dst */ 
+	if ( (((unsigned long)dest ^ src) & 1) || (count < 2) )
+		goto bytecopy;
+
+	if ( (((unsigned long)dest ^ src) & 2) || (count < 4) )
+		goto shortcopy;
+
+	/* Then check for misaligned start address */
+	if (src & 1) {
+		*(u8 *)dest = readb(src);
+		((u8 *)src)++;
+		((u8 *)dest)++;
+		count--;
+		if (count < 2) goto bytecopy;
+	}
+
+	if (src & 2) {
+		*(u16 *)dest = __raw_readw(src);
+		((u16 *)src)++;
+		((u16 *)dest)++;
+		count-=2;
+	}
+
+	while (count > 3) {
+		*(u32 *)dest = __raw_readl(src);
+		dest += 4;
+		src += 4;
+		count -= 4;
+	}
+
+ shortcopy:
+	while (count > 1) {
+		*(u16 *)dest = __raw_readw(src);
+		((u16 *)src)++;
+		((u16 *)dest)++;
+		count-=2;
+	}
+
+ bytecopy:
+	while (count--) {
+		*(char *)dest = readb(src);
+		((char *)src)++;
+		((char *)dest)++;
+	}
+}
+
+/* Sets a block of memory on a device to a given value.
+ * Assumes the device can cope with 32-bit transfers.  If it can't,
+ * don't use this function.
+ */
+void memset_io(unsigned long dest, char fill, int count)
+{
+	u32 fill32 = (fill << 24) | (fill << 16) | (fill << 8) | fill;
+	while (dest & 3) {
+		writeb(fill, dest++);
+		count--;
+	}
+	while (count > 3) {
+		__raw_writel(fill32, dest);
+		dest += 4;
+		count -= 4;
+	}
+	while (count--) {
+		writeb(fill, dest++);
+	}
+}
+
+/*
+ * Read COUNT 8-bit bytes from port PORT into memory starting at
+ * SRC.
+ */
+void insb (unsigned long port, void *dst, unsigned long count)
+{
+	while (((unsigned long)dst) & 0x3) {
+		if (!count)
+			return;
+		count--;
+		*(unsigned char *) dst = inb(port);
+		((unsigned char *) dst)++;
+	}
+
+	while (count >= 4) {
+		unsigned int w;
+		count -= 4;
+		w = inb(port) << 24;
+		w |= inb(port) << 16;
+		w |= inb(port) << 8;
+		w |= inb(port);
+		*(unsigned int *) dst = w;
+		((unsigned int *) dst)++;
+	}
+
+	while (count) {
+		--count;
+		*(unsigned char *) dst = inb(port);
+		((unsigned char *) dst)++;
+	}
+}
+
+
+/*
+ * Read COUNT 16-bit words from port PORT into memory starting at
+ * SRC.  SRC must be at least short aligned.  This is used by the
+ * IDE driver to read disk sectors.  Performance is important, but
+ * the interfaces seems to be slow: just using the inlined version
+ * of the inw() breaks things.
+ */
+void insw (unsigned long port, void *dst, unsigned long count)
+{
+	unsigned int l = 0, l2;
+	
+	if (!count)
+		return;
+	
+	switch (((unsigned long) dst) & 0x3)
+	{
+	 case 0x00:			/* Buffer 32-bit aligned */
+		while (count>=2) {
+			
+			count -= 2;
+			l = cpu_to_le16(inw(port)) << 16;
+			l |= cpu_to_le16(inw(port));
+			*(unsigned int *) dst = l;
+			((unsigned int *) dst)++;
+		}
+		if (count) {
+			*(unsigned short *) dst = cpu_to_le16(inw(port));
+		}
+		break;
+	
+	 case 0x02:			/* Buffer 16-bit aligned */
+		*(unsigned short *) dst = cpu_to_le16(inw(port));
+		((unsigned short *) dst)++;
+		count--;
+		while (count>=2) {
+			
+			count -= 2;
+			l = cpu_to_le16(inw(port)) << 16;
+			l |= cpu_to_le16(inw(port));
+			*(unsigned int *) dst = l;
+			((unsigned int *) dst)++;
+		}
+		if (count) {
+			*(unsigned short *) dst = cpu_to_le16(inw(port));
+		}
+		break;
+		
+	 case 0x01:			/* Buffer 8-bit aligned */
+	 case 0x03:
+		/* I don't bother with 32bit transfers
+		 * in this case, 16bit will have to do -- DE */
+		--count;
+		
+		l = cpu_to_le16(inw(port));
+		*(unsigned char *) dst = l >> 8;
+		((unsigned char *) dst)++;
+		while (count--)
+		{
+			l2 = cpu_to_le16(inw(port));
+			*(unsigned short *) dst = (l & 0xff) << 8 | (l2 >> 8);
+			((unsigned short *) dst)++;
+			l = l2;
+		}
+		*(unsigned char *) dst = l & 0xff;
+		break;
+	}
+}
+
+
+
+/*
+ * Read COUNT 32-bit words from port PORT into memory starting at
+ * SRC. Now works with any alignment in SRC. Performance is important,
+ * but the interfaces seems to be slow: just using the inlined version
+ * of the inl() breaks things.
+ */
+void insl (unsigned long port, void *dst, unsigned long count)
+{
+	unsigned int l = 0, l2;
+	
+	if (!count)
+		return;
+	
+	switch (((unsigned long) dst) & 0x3)
+	{
+	 case 0x00:			/* Buffer 32-bit aligned */
+		while (count--)
+		{
+			*(unsigned int *) dst = cpu_to_le32(inl(port));
+			((unsigned int *) dst)++;
+		}
+		break;
+	
+	 case 0x02:			/* Buffer 16-bit aligned */
+		--count;
+		
+		l = cpu_to_le32(inl(port));
+		*(unsigned short *) dst = l >> 16;
+		((unsigned short *) dst)++;
+		
+		while (count--)
+		{
+			l2 = cpu_to_le32(inl(port));
+			*(unsigned int *) dst = (l & 0xffff) << 16 | (l2 >> 16);
+			((unsigned int *) dst)++;
+			l = l2;
+		}
+		*(unsigned short *) dst = l & 0xffff;
+		break;
+	 case 0x01:			/* Buffer 8-bit aligned */
+		--count;
+		
+		l = cpu_to_le32(inl(port));
+		*(unsigned char *) dst = l >> 24;
+		((unsigned char *) dst)++;
+		*(unsigned short *) dst = (l >> 8) & 0xffff;
+		((unsigned short *) dst)++;
+		while (count--)
+		{
+			l2 = cpu_to_le32(inl(port));
+			*(unsigned int *) dst = (l & 0xff) << 24 | (l2 >> 8);
+			((unsigned int *) dst)++;
+			l = l2;
+		}
+		*(unsigned char *) dst = l & 0xff;
+		break;
+	 case 0x03:			/* Buffer 8-bit aligned */
+		--count;
+		
+		l = cpu_to_le32(inl(port));
+		*(unsigned char *) dst = l >> 24;
+		((unsigned char *) dst)++;
+		while (count--)
+		{
+			l2 = cpu_to_le32(inl(port));
+			*(unsigned int *) dst = (l & 0xffffff) << 8 | l2 >> 24;
+			((unsigned int *) dst)++;
+			l = l2;
+		}
+		*(unsigned short *) dst = (l >> 8) & 0xffff;
+		((unsigned short *) dst)++;
+		*(unsigned char *) dst = l & 0xff;
+		break;
+	}
+}
+
+
+/*
+ * Like insb but in the opposite direction.
+ * Don't worry as much about doing aligned memory transfers:
+ * doing byte reads the "slow" way isn't nearly as slow as
+ * doing byte writes the slow way (no r-m-w cycle).
+ */
+void outsb(unsigned long port, const void * src, unsigned long count)
+{
+	while (count) {
+		count--;
+		outb(*(char *)src, port);
+		((char *) src)++;
+	}
+}
+
+/*
+ * Like insw but in the opposite direction.  This is used by the IDE
+ * driver to write disk sectors.  Performance is important, but the
+ * interfaces seems to be slow: just using the inlined version of the
+ * outw() breaks things.
+ */
+void outsw (unsigned long port, const void *src, unsigned long count)
+{
+	unsigned int l = 0, l2;
+	
+	if (!count)
+		return;
+	
+	switch (((unsigned long) src) & 0x3)
+	{
+	 case 0x00:			/* Buffer 32-bit aligned */
+		while (count>=2) {
+			count -= 2;
+			l = *(unsigned int *) src;
+			((unsigned int *) src)++;
+			outw(le16_to_cpu(l >> 16), port);
+			outw(le16_to_cpu(l & 0xffff), port);
+		}
+		if (count) {
+			outw(le16_to_cpu(*(unsigned short*)src), port);
+		}
+		break;
+	
+	 case 0x02:			/* Buffer 16-bit aligned */
+		
+		outw(le16_to_cpu(*(unsigned short*)src), port);
+		((unsigned short *) src)++;
+		count--;
+		
+		while (count>=2) {
+			count -= 2;
+			l = *(unsigned int *) src;
+			((unsigned int *) src)++;
+			outw(le16_to_cpu(l >> 16), port);
+			outw(le16_to_cpu(l & 0xffff), port);
+		}
+		if (count) {
+			outw(le16_to_cpu(*(unsigned short*)src), port);
+		}
+		break;
+		
+	 case 0x01:			/* Buffer 8-bit aligned */	
+		/* I don't bother with 32bit transfers
+		 * in this case, 16bit will have to do -- DE */
+		
+		l  = *(unsigned char *) src << 8;
+		((unsigned char *) src)++;
+		count--;
+		while (count)
+		{
+			count--;
+			l2 = *(unsigned short *) src;
+			((unsigned short *) src)++;
+			outw(le16_to_cpu(l | l2 >> 8), port);
+		        l = l2 << 8;
+		}
+		l2 = *(unsigned char *) src;
+		outw (le16_to_cpu(l | l2>>8), port);
+		break;
+	
+	}
+}
+
+
+/*
+ * Like insl but in the opposite direction.  This is used by the IDE
+ * driver to write disk sectors.  Works with any alignment in SRC.
+ *  Performance is important, but the interfaces seems to be slow:
+ * just using the inlined version of the outl() breaks things.
+ */
+void outsl (unsigned long port, const void *src, unsigned long count)
+{
+	unsigned int l = 0, l2;
+	
+	if (!count)
+		return;
+	
+	switch (((unsigned long) src) & 0x3)
+	{
+	 case 0x00:			/* Buffer 32-bit aligned */
+		while (count--)
+		{
+			outl(le32_to_cpu(*(unsigned int *) src), port);
+			((unsigned int *) src)++;
+		}
+		break;
+	
+	 case 0x02:			/* Buffer 16-bit aligned */
+		--count;
+		
+		l = *(unsigned short *) src;
+		((unsigned short *) src)++;
+		
+		while (count--)
+		{
+			l2 = *(unsigned int *) src;
+			((unsigned int *) src)++;
+			outl (le32_to_cpu(l << 16 | l2 >> 16), port);
+			l = l2;
+		}
+		l2 = *(unsigned short *) src;
+		outl (le32_to_cpu(l << 16 | l2), port);
+		break;
+	 case 0x01:			/* Buffer 8-bit aligned */
+		--count;
+		
+		l  = *(unsigned char *) src << 24;
+		((unsigned char *) src)++;
+		l |= *(unsigned short *) src << 8;
+		((unsigned short *) src)++;
+		while (count--)
+		{
+			l2 = *(unsigned int *) src;
+			((unsigned int *) src)++;
+			outl (le32_to_cpu(l | l2 >> 24), port);
+			l = l2 << 8;
+		}
+		l2 = *(unsigned char *) src;
+		      outl (le32_to_cpu(l | l2), port);
+		break;
+	 case 0x03:			/* Buffer 8-bit aligned */
+		--count;
+		
+		l  = *(unsigned char *) src << 24;
+		((unsigned char *) src)++;
+		while (count--)
+		{
+			l2 = *(unsigned int *) src;
+			((unsigned int *) src)++;
+			outl (le32_to_cpu(l | l2 >> 8), port);
+			l = l2 << 24;
+		}
+		l2  = *(unsigned short *) src << 16;
+		((unsigned short *) src)++;
+		l2 |= *(unsigned char *) src;
+		outl (le32_to_cpu(l | l2), port);
+		break;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/lib/lusercopy.S linux-2.4.20/arch/parisc/lib/lusercopy.S
--- linux-2.4.19/arch/parisc/lib/lusercopy.S	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/lib/lusercopy.S	2002-10-29 11:18:32.000000000 +0000
@@ -1,5 +1,5 @@
-/*------------------------------------------------------------------------------
- * Native PARISC/Linux Project (http://www.puffingroup.com/parisc)
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
  *
  * Assembly Language User Access Routines
  *  Copyright (C) 2000 Hewlett-Packard (John Marvin)
@@ -30,7 +30,6 @@
  */
 
 
-	.level		1.1
 	.text
 	
 #include <asm/assembly.h>
@@ -42,11 +41,8 @@
 	 * on the flag stored in the task structure.
 	 */
 
-	/* FIXME! depi below has hardcoded idea of kernel stack size */
-
 	.macro  get_sr
-	copy        %r30,%r1        ;! Get task structure
-	depi        0,31,14,%r1     ;! into r1
+	mfctl       %cr30,%r1
 	ldw         TASK_SEGMENT(%r1),%r22
 	mfsp        %sr3,%r1
 	or,<>       %r22,%r0,%r0
@@ -82,7 +78,11 @@
 	ldo         1(%r24),%r24
 
 	.section __ex_table,"a"
+#ifdef __LP64__
+	.dword      1b,(2b-1b)
+#else
 	.word       1b,(2b-1b)
+#endif
 	.previous
 
 	.procend
@@ -123,7 +123,11 @@
 	nop
 
 	.section __ex_table,"a"
+#ifdef __LP64__
+	.dword      1b,(2b-1b)
+#else
 	.word       1b,(2b-1b)
+#endif
 	.previous
 
 	.procend
@@ -133,7 +137,7 @@
 	 *
 	 * Returns -EFAULT if exception before terminator,
 	 *         N if the entire buffer filled,
-	 *         otherwise strlen + 1 (i.e. includes zero byte)
+	 *         otherwise strlen (i.e. excludes zero byte)
 	 */
 
 	.export lstrncpy_from_user,code
@@ -142,7 +146,7 @@
 	.callinfo NO_CALLS
 	.entry
 	comib,=     0,%r24,$lsfu_done
-	copy        %r26,%r23
+	copy        %r24,%r23
 	get_sr
 1:      ldbs,ma     1(%sr1,%r25),%r1
 $lsfu_loop:
@@ -151,7 +155,7 @@
 	addib,<>,n  -1,%r24,$lsfu_loop
 2:      ldbs,ma     1(%sr1,%r25),%r1
 $lsfu_done:
-	sub         %r26,%r23,%r28
+	sub         %r23,%r24,%r28
 $lsfu_exit:
 	bv          %r0(%r2)
 	nop
@@ -161,8 +165,13 @@
 	ldi         -EFAULT,%r28
 
 	.section __ex_table,"a"
+#ifdef __LP64__
+	.dword      1b,(3b-1b)
+	.dword      2b,(3b-2b)
+#else
 	.word       1b,(3b-1b)
-	.word       2b,(2b-1b)
+	.word       2b,(3b-2b)
+#endif
 	.previous
 
 	.procend
@@ -194,7 +203,11 @@
 	ldo        1(%r25),%r25
 
 	.section __ex_table,"a"
+#ifdef __LP64__
+	.dword      1b,(2b-1b)
+#else
 	.word       1b,(2b-1b)
+#endif
 	.previous
 
 	.procend
@@ -233,8 +246,13 @@
 	copy        %r24,%r26    /* reset r26 so 0 is returned on fault */
 
 	.section __ex_table,"a"
+#ifdef __LP64__
+	.dword      1b,(3b-1b)
+	.dword      2b,(3b-2b)
+#else
 	.word       1b,(3b-1b)
-	.word       2b,(2b-1b)
+	.word       2b,(3b-2b)
+#endif
 	.previous
 
 	.procend
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/lib/memset.c linux-2.4.20/arch/parisc/lib/memset.c
--- linux-2.4.19/arch/parisc/lib/memset.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/lib/memset.c	2002-10-29 11:18:51.000000000 +0000
@@ -0,0 +1,91 @@
+/* Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Slight modifications for pa-risc linux - Paul Bame <bame@debian.org> */
+
+#include <linux/types.h>
+#include <asm/string.h>
+
+#define OPSIZ (BITS_PER_LONG/8)
+typedef unsigned long op_t;
+
+void *
+memset (void *dstpp, int sc, size_t len)
+{
+  unsigned int c = sc;
+  long int dstp = (long int) dstpp;
+
+  if (len >= 8)
+    {
+      size_t xlen;
+      op_t cccc;
+
+      cccc = (unsigned char) c;
+      cccc |= cccc << 8;
+      cccc |= cccc << 16;
+      if (OPSIZ > 4)
+	/* Do the shift in two steps to avoid warning if long has 32 bits.  */
+	cccc |= (cccc << 16) << 16;
+
+      /* There are at least some bytes to set.
+	 No need to test for LEN == 0 in this alignment loop.  */
+      while (dstp % OPSIZ != 0)
+	{
+	  ((unsigned char *) dstp)[0] = c;
+	  dstp += 1;
+	  len -= 1;
+	}
+
+      /* Write 8 `op_t' per iteration until less than 8 `op_t' remain.  */
+      xlen = len / (OPSIZ * 8);
+      while (xlen > 0)
+	{
+	  ((op_t *) dstp)[0] = cccc;
+	  ((op_t *) dstp)[1] = cccc;
+	  ((op_t *) dstp)[2] = cccc;
+	  ((op_t *) dstp)[3] = cccc;
+	  ((op_t *) dstp)[4] = cccc;
+	  ((op_t *) dstp)[5] = cccc;
+	  ((op_t *) dstp)[6] = cccc;
+	  ((op_t *) dstp)[7] = cccc;
+	  dstp += 8 * OPSIZ;
+	  xlen -= 1;
+	}
+      len %= OPSIZ * 8;
+
+      /* Write 1 `op_t' per iteration until less than OPSIZ bytes remain.  */
+      xlen = len / OPSIZ;
+      while (xlen > 0)
+	{
+	  ((op_t *) dstp)[0] = cccc;
+	  dstp += OPSIZ;
+	  xlen -= 1;
+	}
+      len %= OPSIZ;
+    }
+
+  /* Write the last few bytes.  */
+  while (len > 0)
+    {
+      ((unsigned char *) dstp)[0] = c;
+      dstp += 1;
+      len -= 1;
+    }
+
+  return dstpp;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/Makefile linux-2.4.20/arch/parisc/math-emu/Makefile
--- linux-2.4.19/arch/parisc/math-emu/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/Makefile	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,22 @@
+#
+# Makefile for the linux/parisc floating point code
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := math.o
+obj-y	 := frnd.o driver.o decode_exc.o fpudispatch.o denormal.o \
+		dfmpy.o sfmpy.o sfsqrt.o dfsqrt.o dfadd.o fmpyfadd.o \
+		sfadd.o dfsub.o sfsub.o fcnvfxt.o fcnvff.o fcnvxf.o \
+		fcnvfx.o fcnvuf.o fcnvfu.o fcnvfut.o dfdiv.o sfdiv.o \
+		dfrem.o sfrem.o dfcmp.o sfcmp.o
+
+# Math emulation code beyond the FRND is required for 712/80i and
+# other very old or stripped-down PA-RISC CPUs -- not currently supported
+
+obj-$CONFIG_MATH_EMULATION	+= unimplemented-math-emulation.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/README linux-2.4.20/arch/parisc/math-emu/README
--- linux-2.4.19/arch/parisc/math-emu/README	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/README	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,11 @@
+All files except driver.c are snapshots from the HP-UX kernel.  They've
+been modified as little as possible.  Even though they don't fit the
+Linux coding style, please leave them in their funny format just in case
+someone in the future, with access to HP-UX source code, is generous
+enough to update our copies with later changes from HP-UX -- it'll
+make their 'diff' job easier if our code is relatively unmodified.
+
+Required Disclaimer: Hewlett-Packard makes no implied or expressed
+warranties about this code nor any promises to maintain or test it
+in any way.  This copy of this snapshot is no longer the property
+of Hewlett-Packard.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/cnv_float.h linux-2.4.20/arch/parisc/math-emu/cnv_float.h
--- linux-2.4.19/arch/parisc/math-emu/cnv_float.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/cnv_float.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,377 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef __NO_PA_HDRS
+    PA header file -- do not include this header file for non-PA builds.
+#endif
+
+/*
+ * Some more constants
+ */
+#define SGL_FX_MAX_EXP 30
+#define DBL_FX_MAX_EXP 62
+#define QUAD_FX_MAX_EXP 126
+
+#define Dintp1(object) (object)
+#define Dintp2(object) (object)
+
+#define Duintp1(object) (object)
+#define Duintp2(object) (object)
+
+#define Qintp0(object) (object)
+#define Qintp1(object) (object)
+#define Qintp2(object) (object)
+#define Qintp3(object) (object)
+
+
+/*
+ * These macros will be used specifically by the convert instructions.
+ *
+ *
+ * Single format macros
+ */
+
+#define Sgl_to_dbl_exponent(src_exponent,dest)			\
+    Deposit_dexponent(dest,src_exponent+(DBL_BIAS-SGL_BIAS))
+
+#define Sgl_to_dbl_mantissa(src_mantissa,destA,destB)	\
+    Deposit_dmantissap1(destA,src_mantissa>>3);		\
+    Dmantissap2(destB) = src_mantissa << 29
+
+#define Sgl_isinexact_to_fix(sgl_value,exponent)	\
+    ((exponent < (SGL_P - 1)) ?				\
+     (Sall(sgl_value) << (SGL_EXP_LENGTH + 1 + exponent)) : FALSE)
+
+#define Int_isinexact_to_sgl(int_value)	(int_value << 33 - SGL_EXP_LENGTH)
+
+#define Sgl_roundnearest_from_int(int_value,sgl_value)			\
+    if (int_value & 1<<(SGL_EXP_LENGTH - 2))   /* round bit */		\
+    	if ((int_value << 34 - SGL_EXP_LENGTH) || Slow(sgl_value))	\
+		Sall(sgl_value)++
+
+#define Dint_isinexact_to_sgl(dint_valueA,dint_valueB)		\
+    ((Dintp1(dint_valueA) << 33 - SGL_EXP_LENGTH) || Dintp2(dint_valueB))
+
+#define Sgl_roundnearest_from_dint(dint_valueA,dint_valueB,sgl_value)	\
+    if (Dintp1(dint_valueA) & 1<<(SGL_EXP_LENGTH - 2)) 			\
+    	if ((Dintp1(dint_valueA) << 34 - SGL_EXP_LENGTH) ||		\
+    	Dintp2(dint_valueB) || Slow(sgl_value)) Sall(sgl_value)++
+
+#define Dint_isinexact_to_dbl(dint_value) 	\
+    (Dintp2(dint_value) << 33 - DBL_EXP_LENGTH)
+
+#define Dbl_roundnearest_from_dint(dint_opndB,dbl_opndA,dbl_opndB) 	\
+    if (Dintp2(dint_opndB) & 1<<(DBL_EXP_LENGTH - 2))			\
+       if ((Dintp2(dint_opndB) << 34 - DBL_EXP_LENGTH) || Dlowp2(dbl_opndB))  \
+          if ((++Dallp2(dbl_opndB))==0) Dallp1(dbl_opndA)++
+
+#define Sgl_isone_roundbit(sgl_value,exponent)			\
+    ((Sall(sgl_value) << (SGL_EXP_LENGTH + 1 + exponent)) >> 31)
+
+#define Sgl_isone_stickybit(sgl_value,exponent)		\
+    (exponent < (SGL_P - 2) ?				\
+     Sall(sgl_value) << (SGL_EXP_LENGTH + 2 + exponent) : FALSE)
+
+
+/* 
+ * Double format macros
+ */
+
+#define Dbl_to_sgl_exponent(src_exponent,dest)			\
+    dest = src_exponent + (SGL_BIAS - DBL_BIAS)
+
+#define Dbl_to_sgl_mantissa(srcA,srcB,dest,inexact,guard,sticky,odd)	\
+    Shiftdouble(Dmantissap1(srcA),Dmantissap2(srcB),29,dest); 	\
+    guard = Dbit3p2(srcB);					\
+    sticky = Dallp2(srcB)<<4;					\
+    inexact = guard | sticky;					\
+    odd = Dbit2p2(srcB)
+
+#define Dbl_to_sgl_denormalized(srcA,srcB,exp,dest,inexact,guard,sticky,odd,tiny) \
+    Deposit_dexponent(srcA,1);						\
+    tiny = TRUE;							\
+    if (exp >= -2) {							\
+	if (exp == 0) {							\
+	    inexact = Dallp2(srcB) << 3;				\
+	    guard = inexact >> 31;					\
+	    sticky = inexact << 1;					\
+	    Shiftdouble(Dmantissap1(srcA),Dmantissap2(srcB),29,dest);	\
+	    odd = dest << 31;						\
+	    if (inexact) {						\
+		switch(Rounding_mode()) {				\
+		    case ROUNDPLUS:					\
+			if (Dbl_iszero_sign(srcA)) {			\
+			    dest++;					\
+			    if (Sgl_isone_hidden(dest))	\
+				tiny = FALSE;				\
+			    dest--;					\
+			}						\
+			break;						\
+		    case ROUNDMINUS:					\
+			if (Dbl_isone_sign(srcA)) {			\
+			    dest++;					\
+			    if (Sgl_isone_hidden(dest))	\
+				tiny = FALSE;				\
+			    dest--;					\
+			}						\
+			break;						\
+		    case ROUNDNEAREST:					\
+			if (guard && (sticky || odd)) {			\
+			    dest++;					\
+			    if (Sgl_isone_hidden(dest))	\
+				tiny = FALSE;				\
+			    dest--;					\
+			}						\
+			break;						\
+		}							\
+	    }								\
+		/* shift right by one to get correct result */		\
+		guard = odd;						\
+		sticky = inexact;					\
+		inexact |= guard;					\
+		dest >>= 1;						\
+    		Deposit_dsign(srcA,0);					\
+    	        Shiftdouble(Dallp1(srcA),Dallp2(srcB),30,dest);		\
+	        odd = dest << 31;					\
+	}								\
+	else {								\
+    	    inexact = Dallp2(srcB) << (2 + exp);			\
+    	    guard = inexact >> 31;					\
+    	    sticky = inexact << 1; 					\
+    	    Deposit_dsign(srcA,0);					\
+    	    if (exp == -2) dest = Dallp1(srcA);				\
+    	    else Variable_shift_double(Dallp1(srcA),Dallp2(srcB),30-exp,dest); \
+    	    odd = dest << 31;						\
+	}								\
+    }									\
+    else {								\
+    	Deposit_dsign(srcA,0);						\
+    	if (exp > (1 - SGL_P)) {					\
+    	    dest = Dallp1(srcA) >> (- 2 - exp);				\
+    	    inexact = Dallp1(srcA) << (34 + exp);			\
+    	    guard = inexact >> 31;					\
+    	    sticky = (inexact << 1) | Dallp2(srcB);			\
+    	    inexact |= Dallp2(srcB); 					\
+    	    odd = dest << 31;						\
+    	}								\
+    	else {								\
+    	    dest = 0;							\
+    	    inexact = Dallp1(srcA) | Dallp2(srcB);			\
+    	    if (exp == (1 - SGL_P)) {					\
+    	    	guard = Dhidden(srcA);					\
+    	    	sticky = Dmantissap1(srcA) | Dallp2(srcB); 		\
+    	    }								\
+    	    else {							\
+    	    	guard = 0;						\
+    	    	sticky = inexact;					\
+    	    }								\
+    	    odd = 0;							\
+    	}								\
+    }									\
+    exp = 0
+
+#define Dbl_isinexact_to_fix(dbl_valueA,dbl_valueB,exponent)		\
+    (exponent < (DBL_P-33) ? 						\
+     Dallp2(dbl_valueB) || Dallp1(dbl_valueA) << (DBL_EXP_LENGTH+1+exponent) : \
+     (exponent < (DBL_P-1) ? Dallp2(dbl_valueB) << (exponent + (33-DBL_P)) :   \
+      FALSE))
+
+#define Dbl_isoverflow_to_int(exponent,dbl_valueA,dbl_valueB)		\
+    ((exponent > SGL_FX_MAX_EXP + 1) || Dsign(dbl_valueA)==0 ||		\
+     Dmantissap1(dbl_valueA)!=0 || (Dallp2(dbl_valueB)>>21)!=0 ) 
+
+#define Dbl_isone_roundbit(dbl_valueA,dbl_valueB,exponent)              \
+    ((exponent < (DBL_P - 33) ?						\
+      Dallp1(dbl_valueA) >> ((30 - DBL_EXP_LENGTH) - exponent) :	\
+      Dallp2(dbl_valueB) >> ((DBL_P - 2) - exponent)) & 1)
+
+#define Dbl_isone_stickybit(dbl_valueA,dbl_valueB,exponent)		\
+    (exponent < (DBL_P-34) ? 						\
+     (Dallp2(dbl_valueB) || Dallp1(dbl_valueA)<<(DBL_EXP_LENGTH+2+exponent)) : \
+     (exponent<(DBL_P-2) ? (Dallp2(dbl_valueB) << (exponent + (34-DBL_P))) : \
+      FALSE))
+
+
+/* Int macros */
+
+#define Int_from_sgl_mantissa(sgl_value,exponent)	\
+    Sall(sgl_value) = 				\
+    	(unsigned)(Sall(sgl_value) << SGL_EXP_LENGTH)>>(31 - exponent)
+
+#define Int_from_dbl_mantissa(dbl_valueA,dbl_valueB,exponent)	\
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),22,Dallp1(dbl_valueA)); \
+    if (exponent < 31) Dallp1(dbl_valueA) >>= 30 - exponent;	\
+    else Dallp1(dbl_valueA) <<= 1
+
+#define Int_negate(int_value) int_value = -int_value
+
+
+/* Dint macros */
+
+#define Dint_from_sgl_mantissa(sgl_value,exponent,dresultA,dresultB)	\
+    {Sall(sgl_value) <<= SGL_EXP_LENGTH;  /*  left-justify  */		\
+    if (exponent <= 31) {						\
+    	Dintp1(dresultA) = 0;						\
+    	Dintp2(dresultB) = (unsigned)Sall(sgl_value) >> (31 - exponent); \
+    }									\
+    else {								\
+    	Dintp1(dresultA) = Sall(sgl_value) >> (63 - exponent);		\
+    	Dintp2(dresultB) = Sall(sgl_value) << (exponent - 31);		\
+    }}
+
+
+#define Dint_from_dbl_mantissa(dbl_valueA,dbl_valueB,exponent,destA,destB) \
+    {if (exponent < 32) {						\
+    	Dintp1(destA) = 0;						\
+    	if (exponent <= 20)						\
+    	    Dintp2(destB) = Dallp1(dbl_valueA) >> 20-exponent;		\
+    	else Variable_shift_double(Dallp1(dbl_valueA),Dallp2(dbl_valueB), \
+	     52-exponent,Dintp2(destB));					\
+    }									\
+    else {								\
+    	if (exponent <= 52) {						\
+    	    Dintp1(destA) = Dallp1(dbl_valueA) >> 52-exponent;		\
+	    if (exponent == 52) Dintp2(destB) = Dallp2(dbl_valueB);	\
+	    else Variable_shift_double(Dallp1(dbl_valueA),Dallp2(dbl_valueB), \
+	    52-exponent,Dintp2(destB));					\
+        }								\
+    	else {								\
+    	    Variable_shift_double(Dallp1(dbl_valueA),Dallp2(dbl_valueB), \
+	    84-exponent,Dintp1(destA));					\
+    	    Dintp2(destB) = Dallp2(dbl_valueB) << exponent-52;		\
+    	}								\
+    }}
+
+#define Dint_setzero(dresultA,dresultB) 	\
+    Dintp1(dresultA) = 0; 	\
+    Dintp2(dresultB) = 0
+
+#define Dint_setone_sign(dresultA,dresultB)		\
+    Dintp1(dresultA) = ~Dintp1(dresultA);		\
+    if ((Dintp2(dresultB) = -Dintp2(dresultB)) == 0) Dintp1(dresultA)++
+
+#define Dint_set_minint(dresultA,dresultB)		\
+    Dintp1(dresultA) = (unsigned int)1<<31;		\
+    Dintp2(dresultB) = 0
+
+#define Dint_isone_lowp2(dresultB)  (Dintp2(dresultB) & 01)
+
+#define Dint_increment(dresultA,dresultB) 		\
+    if ((++Dintp2(dresultB))==0) Dintp1(dresultA)++
+
+#define Dint_decrement(dresultA,dresultB) 		\
+    if ((Dintp2(dresultB)--)==0) Dintp1(dresultA)--
+
+#define Dint_negate(dresultA,dresultB)			\
+    Dintp1(dresultA) = ~Dintp1(dresultA);		\
+    if ((Dintp2(dresultB) = -Dintp2(dresultB))==0) Dintp1(dresultA)++
+
+#define Dint_copyfromptr(src,destA,destB) \
+     Dintp1(destA) = src->wd0;		\
+     Dintp2(destB) = src->wd1
+#define Dint_copytoptr(srcA,srcB,dest)	\
+    dest->wd0 = Dintp1(srcA);		\
+    dest->wd1 = Dintp2(srcB)
+
+
+/* other macros  */
+
+#define Find_ms_one_bit(value, position)	\
+    {						\
+	int var;				\
+	for (var=8; var >=1; var >>= 1) {	\
+	    if (value >> 32 - position)		\
+		position -= var;		\
+		else position += var;		\
+	}					\
+	if ((value >> 32 - position) == 0)	\
+	    position--;				\
+	else position -= 2;			\
+    }
+
+
+/*
+ * Unsigned int macros
+ */
+#define Duint_copyfromptr(src,destA,destB) \
+    Dint_copyfromptr(src,destA,destB)
+#define Duint_copytoptr(srcA,srcB,dest)	\
+    Dint_copytoptr(srcA,srcB,dest)
+
+#define Suint_isinexact_to_sgl(int_value) \
+    (int_value << 32 - SGL_EXP_LENGTH)
+
+#define Sgl_roundnearest_from_suint(suint_value,sgl_value)		\
+    if (suint_value & 1<<(SGL_EXP_LENGTH - 1))   /* round bit */	\
+    	if ((suint_value << 33 - SGL_EXP_LENGTH) || Slow(sgl_value))	\
+		Sall(sgl_value)++
+
+#define Duint_isinexact_to_sgl(duint_valueA,duint_valueB)	\
+    ((Duintp1(duint_valueA) << 32 - SGL_EXP_LENGTH) || Duintp2(duint_valueB))
+
+#define Sgl_roundnearest_from_duint(duint_valueA,duint_valueB,sgl_value) \
+    if (Duintp1(duint_valueA) & 1<<(SGL_EXP_LENGTH - 1))		\
+    	if ((Duintp1(duint_valueA) << 33 - SGL_EXP_LENGTH) ||		\
+    	Duintp2(duint_valueB) || Slow(sgl_value)) Sall(sgl_value)++
+
+#define Duint_isinexact_to_dbl(duint_value) 	\
+    (Duintp2(duint_value) << 32 - DBL_EXP_LENGTH)
+
+#define Dbl_roundnearest_from_duint(duint_opndB,dbl_opndA,dbl_opndB) 	\
+    if (Duintp2(duint_opndB) & 1<<(DBL_EXP_LENGTH - 1))			\
+       if ((Duintp2(duint_opndB) << 33 - DBL_EXP_LENGTH) || Dlowp2(dbl_opndB)) \
+          if ((++Dallp2(dbl_opndB))==0) Dallp1(dbl_opndA)++
+
+#define Suint_from_sgl_mantissa(src,exponent,result)	\
+    Sall(result) = (unsigned)(Sall(src) << SGL_EXP_LENGTH)>>(31 - exponent)
+
+#define Sgl_isinexact_to_unsigned(sgl_value,exponent)	\
+    Sgl_isinexact_to_fix(sgl_value,exponent)
+
+#define Duint_from_sgl_mantissa(sgl_value,exponent,dresultA,dresultB)	\
+  {Sall(sgl_value) <<= SGL_EXP_LENGTH;  /*  left-justify  */		\
+    if (exponent <= 31) {						\
+    	Dintp1(dresultA) = 0;						\
+    	Dintp2(dresultB) = (unsigned)Sall(sgl_value) >> (31 - exponent); \
+    }									\
+    else {								\
+    	Dintp1(dresultA) = Sall(sgl_value) >> (63 - exponent);		\
+    	Dintp2(dresultB) = Sall(sgl_value) << (exponent - 31);		\
+    }									\
+    Sall(sgl_value) >>= SGL_EXP_LENGTH;  /* return to original */	\
+  }
+
+#define Duint_setzero(dresultA,dresultB) 	\
+    Dint_setzero(dresultA,dresultB)
+
+#define Duint_increment(dresultA,dresultB) Dint_increment(dresultA,dresultB) 
+
+#define Duint_isone_lowp2(dresultB)  Dint_isone_lowp2(dresultB)
+
+#define Suint_from_dbl_mantissa(srcA,srcB,exponent,dest) \
+    Shiftdouble(Dallp1(srcA),Dallp2(srcB),21,dest); \
+    dest = (unsigned)dest >> 31 - exponent
+
+#define Dbl_isinexact_to_unsigned(dbl_valueA,dbl_valueB,exponent) \
+    Dbl_isinexact_to_fix(dbl_valueA,dbl_valueB,exponent)
+
+#define Duint_from_dbl_mantissa(dbl_valueA,dbl_valueB,exponent,destA,destB) \
+    Dint_from_dbl_mantissa(dbl_valueA,dbl_valueB,exponent,destA,destB) 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/dbl_float.h linux-2.4.20/arch/parisc/math-emu/dbl_float.h
--- linux-2.4.19/arch/parisc/math-emu/dbl_float.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/dbl_float.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,847 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifdef __NO_PA_HDRS
+    PA header file -- do not include this header file for non-PA builds.
+#endif
+
+/* 32-bit word grabing functions */
+#define Dbl_firstword(value) Dallp1(value)
+#define Dbl_secondword(value) Dallp2(value)
+#define Dbl_thirdword(value) dummy_location
+#define Dbl_fourthword(value) dummy_location
+
+#define Dbl_sign(object) Dsign(object)
+#define Dbl_exponent(object) Dexponent(object)
+#define Dbl_signexponent(object) Dsignexponent(object)
+#define Dbl_mantissap1(object) Dmantissap1(object)
+#define Dbl_mantissap2(object) Dmantissap2(object)
+#define Dbl_exponentmantissap1(object) Dexponentmantissap1(object)
+#define Dbl_allp1(object) Dallp1(object)
+#define Dbl_allp2(object) Dallp2(object)
+
+/* dbl_and_signs ands the sign bits of each argument and puts the result
+ * into the first argument. dbl_or_signs ors those same sign bits */
+#define Dbl_and_signs( src1dst, src2)		\
+    Dallp1(src1dst) = (Dallp1(src2)|~((unsigned int)1<<31)) & Dallp1(src1dst)
+#define Dbl_or_signs( src1dst, src2)		\
+    Dallp1(src1dst) = (Dallp1(src2)&((unsigned int)1<<31)) | Dallp1(src1dst)
+
+/* The hidden bit is always the low bit of the exponent */
+#define Dbl_clear_exponent_set_hidden(srcdst) Deposit_dexponent(srcdst,1)
+#define Dbl_clear_signexponent_set_hidden(srcdst) \
+    Deposit_dsignexponent(srcdst,1)
+#define Dbl_clear_sign(srcdst) Dallp1(srcdst) &= ~((unsigned int)1<<31)
+#define Dbl_clear_signexponent(srcdst) \
+    Dallp1(srcdst) &= Dmantissap1((unsigned int)-1)
+
+/* Exponent field for doubles has already been cleared and may be
+ * included in the shift.  Here we need to generate two double width
+ * variable shifts.  The insignificant bits can be ignored.
+ *      MTSAR f(varamount)
+ *      VSHD	srcdst.high,srcdst.low => srcdst.low
+ *	VSHD	0,srcdst.high => srcdst.high 
+ * This is very difficult to model with C expressions since the shift amount
+ * could exceed 32.  */
+/* varamount must be less than 64 */
+#define Dbl_rightshift(srcdstA, srcdstB, varamount)			\
+    {if((varamount) >= 32) {						\
+        Dallp2(srcdstB) = Dallp1(srcdstA) >> (varamount-32);		\
+        Dallp1(srcdstA)=0;						\
+    }									\
+    else if(varamount > 0) {						\
+	Variable_shift_double(Dallp1(srcdstA), Dallp2(srcdstB), 	\
+	  (varamount), Dallp2(srcdstB));				\
+	Dallp1(srcdstA) >>= varamount;					\
+    } }
+/* varamount must be less than 64 */
+#define Dbl_rightshift_exponentmantissa(srcdstA, srcdstB, varamount)	\
+    {if((varamount) >= 32) {						\
+        Dallp2(srcdstB) = Dexponentmantissap1(srcdstA) >> (varamount-32); \
+	Dallp1(srcdstA) &= ((unsigned int)1<<31);  /* clear expmant field */ \
+    }									\
+    else if(varamount > 0) {						\
+	Variable_shift_double(Dexponentmantissap1(srcdstA), Dallp2(srcdstB), \
+	(varamount), Dallp2(srcdstB));					\
+	Deposit_dexponentmantissap1(srcdstA,				\
+	    (Dexponentmantissap1(srcdstA)>>varamount));			\
+    } }
+/* varamount must be less than 64 */
+#define Dbl_leftshift(srcdstA, srcdstB, varamount)			\
+    {if((varamount) >= 32) {						\
+	Dallp1(srcdstA) = Dallp2(srcdstB) << (varamount-32);		\
+	Dallp2(srcdstB)=0;						\
+    }									\
+    else {								\
+	if ((varamount) > 0) {						\
+	    Dallp1(srcdstA) = (Dallp1(srcdstA) << (varamount)) |	\
+		(Dallp2(srcdstB) >> (32-(varamount)));			\
+	    Dallp2(srcdstB) <<= varamount;				\
+	}								\
+    } }
+#define Dbl_leftshiftby1_withextent(lefta,leftb,right,resulta,resultb)	\
+    Shiftdouble(Dallp1(lefta), Dallp2(leftb), 31, Dallp1(resulta));	\
+    Shiftdouble(Dallp2(leftb), Extall(right), 31, Dallp2(resultb)) 
+    
+#define Dbl_rightshiftby1_withextent(leftb,right,dst)		\
+    Extall(dst) = (Dallp2(leftb) << 31) | ((unsigned int)Extall(right) >> 1) | \
+		  Extlow(right)
+
+#define Dbl_arithrightshiftby1(srcdstA,srcdstB)			\
+    Shiftdouble(Dallp1(srcdstA),Dallp2(srcdstB),1,Dallp2(srcdstB));\
+    Dallp1(srcdstA) = (int)Dallp1(srcdstA) >> 1
+   
+/* Sign extend the sign bit with an integer destination */
+#define Dbl_signextendedsign(value)  Dsignedsign(value)
+
+#define Dbl_isone_hidden(dbl_value) (Is_dhidden(dbl_value)!=0)
+/* Singles and doubles may include the sign and exponent fields.  The
+ * hidden bit and the hidden overflow must be included. */
+#define Dbl_increment(dbl_valueA,dbl_valueB) \
+    if( (Dallp2(dbl_valueB) += 1) == 0 )  Dallp1(dbl_valueA) += 1
+#define Dbl_increment_mantissa(dbl_valueA,dbl_valueB) \
+    if( (Dmantissap2(dbl_valueB) += 1) == 0 )  \
+    Deposit_dmantissap1(dbl_valueA,dbl_valueA+1)
+#define Dbl_decrement(dbl_valueA,dbl_valueB) \
+    if( Dallp2(dbl_valueB) == 0 )  Dallp1(dbl_valueA) -= 1; \
+    Dallp2(dbl_valueB) -= 1
+
+#define Dbl_isone_sign(dbl_value) (Is_dsign(dbl_value)!=0)
+#define Dbl_isone_hiddenoverflow(dbl_value) (Is_dhiddenoverflow(dbl_value)!=0)
+#define Dbl_isone_lowmantissap1(dbl_valueA) (Is_dlowp1(dbl_valueA)!=0)
+#define Dbl_isone_lowmantissap2(dbl_valueB) (Is_dlowp2(dbl_valueB)!=0)
+#define Dbl_isone_signaling(dbl_value) (Is_dsignaling(dbl_value)!=0)
+#define Dbl_is_signalingnan(dbl_value) (Dsignalingnan(dbl_value)==0xfff)
+#define Dbl_isnotzero(dbl_valueA,dbl_valueB) \
+    (Dallp1(dbl_valueA) || Dallp2(dbl_valueB))
+#define Dbl_isnotzero_hiddenhigh7mantissa(dbl_value) \
+    (Dhiddenhigh7mantissa(dbl_value)!=0)
+#define Dbl_isnotzero_exponent(dbl_value) (Dexponent(dbl_value)!=0)
+#define Dbl_isnotzero_mantissa(dbl_valueA,dbl_valueB) \
+    (Dmantissap1(dbl_valueA) || Dmantissap2(dbl_valueB))
+#define Dbl_isnotzero_mantissap1(dbl_valueA) (Dmantissap1(dbl_valueA)!=0)
+#define Dbl_isnotzero_mantissap2(dbl_valueB) (Dmantissap2(dbl_valueB)!=0)
+#define Dbl_isnotzero_exponentmantissa(dbl_valueA,dbl_valueB) \
+    (Dexponentmantissap1(dbl_valueA) || Dmantissap2(dbl_valueB))
+#define Dbl_isnotzero_low4p2(dbl_value) (Dlow4p2(dbl_value)!=0)
+#define Dbl_iszero(dbl_valueA,dbl_valueB) (Dallp1(dbl_valueA)==0 && \
+    Dallp2(dbl_valueB)==0)
+#define Dbl_iszero_allp1(dbl_value) (Dallp1(dbl_value)==0)
+#define Dbl_iszero_allp2(dbl_value) (Dallp2(dbl_value)==0)
+#define Dbl_iszero_hidden(dbl_value) (Is_dhidden(dbl_value)==0)
+#define Dbl_iszero_hiddenoverflow(dbl_value) (Is_dhiddenoverflow(dbl_value)==0)
+#define Dbl_iszero_hiddenhigh3mantissa(dbl_value) \
+    (Dhiddenhigh3mantissa(dbl_value)==0)
+#define Dbl_iszero_hiddenhigh7mantissa(dbl_value) \
+    (Dhiddenhigh7mantissa(dbl_value)==0)
+#define Dbl_iszero_sign(dbl_value) (Is_dsign(dbl_value)==0)
+#define Dbl_iszero_exponent(dbl_value) (Dexponent(dbl_value)==0)
+#define Dbl_iszero_mantissa(dbl_valueA,dbl_valueB) \
+    (Dmantissap1(dbl_valueA)==0 && Dmantissap2(dbl_valueB)==0)
+#define Dbl_iszero_exponentmantissa(dbl_valueA,dbl_valueB) \
+    (Dexponentmantissap1(dbl_valueA)==0 && Dmantissap2(dbl_valueB)==0)
+#define Dbl_isinfinity_exponent(dbl_value)		\
+    (Dexponent(dbl_value)==DBL_INFINITY_EXPONENT)
+#define Dbl_isnotinfinity_exponent(dbl_value)		\
+    (Dexponent(dbl_value)!=DBL_INFINITY_EXPONENT)
+#define Dbl_isinfinity(dbl_valueA,dbl_valueB)			\
+    (Dexponent(dbl_valueA)==DBL_INFINITY_EXPONENT &&	\
+    Dmantissap1(dbl_valueA)==0 && Dmantissap2(dbl_valueB)==0)
+#define Dbl_isnan(dbl_valueA,dbl_valueB)		\
+    (Dexponent(dbl_valueA)==DBL_INFINITY_EXPONENT &&	\
+    (Dmantissap1(dbl_valueA)!=0 || Dmantissap2(dbl_valueB)!=0))
+#define Dbl_isnotnan(dbl_valueA,dbl_valueB)		\
+    (Dexponent(dbl_valueA)!=DBL_INFINITY_EXPONENT ||	\
+    (Dmantissap1(dbl_valueA)==0 && Dmantissap2(dbl_valueB)==0))
+
+#define Dbl_islessthan(dbl_op1a,dbl_op1b,dbl_op2a,dbl_op2b)	\
+    (Dallp1(dbl_op1a) < Dallp1(dbl_op2a) ||			\
+     (Dallp1(dbl_op1a) == Dallp1(dbl_op2a) &&			\
+      Dallp2(dbl_op1b) < Dallp2(dbl_op2b)))
+#define Dbl_isgreaterthan(dbl_op1a,dbl_op1b,dbl_op2a,dbl_op2b)	\
+    (Dallp1(dbl_op1a) > Dallp1(dbl_op2a) ||			\
+     (Dallp1(dbl_op1a) == Dallp1(dbl_op2a) &&			\
+      Dallp2(dbl_op1b) > Dallp2(dbl_op2b)))
+#define Dbl_isnotlessthan(dbl_op1a,dbl_op1b,dbl_op2a,dbl_op2b)	\
+    (Dallp1(dbl_op1a) > Dallp1(dbl_op2a) ||			\
+     (Dallp1(dbl_op1a) == Dallp1(dbl_op2a) &&			\
+      Dallp2(dbl_op1b) >= Dallp2(dbl_op2b)))
+#define Dbl_isnotgreaterthan(dbl_op1a,dbl_op1b,dbl_op2a,dbl_op2b) \
+    (Dallp1(dbl_op1a) < Dallp1(dbl_op2a) ||			\
+     (Dallp1(dbl_op1a) == Dallp1(dbl_op2a) &&			\
+      Dallp2(dbl_op1b) <= Dallp2(dbl_op2b)))
+#define Dbl_isequal(dbl_op1a,dbl_op1b,dbl_op2a,dbl_op2b)	\
+     ((Dallp1(dbl_op1a) == Dallp1(dbl_op2a)) &&			\
+      (Dallp2(dbl_op1b) == Dallp2(dbl_op2b)))
+
+#define Dbl_leftshiftby8(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),24,Dallp1(dbl_valueA)); \
+    Dallp2(dbl_valueB) <<= 8
+#define Dbl_leftshiftby7(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),25,Dallp1(dbl_valueA)); \
+    Dallp2(dbl_valueB) <<= 7
+#define Dbl_leftshiftby4(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),28,Dallp1(dbl_valueA)); \
+    Dallp2(dbl_valueB) <<= 4
+#define Dbl_leftshiftby3(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),29,Dallp1(dbl_valueA)); \
+    Dallp2(dbl_valueB) <<= 3
+#define Dbl_leftshiftby2(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),30,Dallp1(dbl_valueA)); \
+    Dallp2(dbl_valueB) <<= 2
+#define Dbl_leftshiftby1(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),31,Dallp1(dbl_valueA)); \
+    Dallp2(dbl_valueB) <<= 1
+
+#define Dbl_rightshiftby8(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),8,Dallp2(dbl_valueB)); \
+    Dallp1(dbl_valueA) >>= 8
+#define Dbl_rightshiftby4(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),4,Dallp2(dbl_valueB)); \
+    Dallp1(dbl_valueA) >>= 4
+#define Dbl_rightshiftby2(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),2,Dallp2(dbl_valueB)); \
+    Dallp1(dbl_valueA) >>= 2
+#define Dbl_rightshiftby1(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),1,Dallp2(dbl_valueB)); \
+    Dallp1(dbl_valueA) >>= 1
+    
+/* This magnitude comparison uses the signless first words and
+ * the regular part2 words.  The comparison is graphically:
+ *
+ *       1st greater?  -------------
+ *                                 |
+ *       1st less?-----------------+---------
+ *                                 |        |
+ *       2nd greater or equal----->|        |
+ *                               False     True
+ */
+#define Dbl_ismagnitudeless(leftB,rightB,signlessleft,signlessright)	\
+      ((signlessleft <= signlessright) &&				\
+       ( (signlessleft < signlessright) || (Dallp2(leftB)<Dallp2(rightB)) ))
+    
+#define Dbl_copytoint_exponentmantissap1(src,dest) \
+    dest = Dexponentmantissap1(src)
+
+/* A quiet NaN has the high mantissa bit clear and at least on other (in this
+ * case the adjacent bit) bit set. */
+#define Dbl_set_quiet(dbl_value) Deposit_dhigh2mantissa(dbl_value,1)
+#define Dbl_set_exponent(dbl_value, exp) Deposit_dexponent(dbl_value,exp)
+
+#define Dbl_set_mantissa(desta,destb,valuea,valueb)	\
+    Deposit_dmantissap1(desta,valuea);			\
+    Dmantissap2(destb) = Dmantissap2(valueb)
+#define Dbl_set_mantissap1(desta,valuea)		\
+    Deposit_dmantissap1(desta,valuea)
+#define Dbl_set_mantissap2(destb,valueb)		\
+    Dmantissap2(destb) = Dmantissap2(valueb)
+
+#define Dbl_set_exponentmantissa(desta,destb,valuea,valueb)	\
+    Deposit_dexponentmantissap1(desta,valuea);			\
+    Dmantissap2(destb) = Dmantissap2(valueb)
+#define Dbl_set_exponentmantissap1(dest,value)			\
+    Deposit_dexponentmantissap1(dest,value)
+
+#define Dbl_copyfromptr(src,desta,destb) \
+    Dallp1(desta) = src->wd0;		\
+    Dallp2(destb) = src->wd1 
+#define Dbl_copytoptr(srca,srcb,dest)	\
+    dest->wd0 = Dallp1(srca);		\
+    dest->wd1 = Dallp2(srcb)
+
+/*  An infinity is represented with the max exponent and a zero mantissa */
+#define Dbl_setinfinity_exponent(dbl_value) \
+    Deposit_dexponent(dbl_value,DBL_INFINITY_EXPONENT)
+#define Dbl_setinfinity_exponentmantissa(dbl_valueA,dbl_valueB)	\
+    Deposit_dexponentmantissap1(dbl_valueA, 			\
+    (DBL_INFINITY_EXPONENT << (32-(1+DBL_EXP_LENGTH))));	\
+    Dmantissap2(dbl_valueB) = 0
+#define Dbl_setinfinitypositive(dbl_valueA,dbl_valueB)		\
+    Dallp1(dbl_valueA) 						\
+        = (DBL_INFINITY_EXPONENT << (32-(1+DBL_EXP_LENGTH)));	\
+    Dmantissap2(dbl_valueB) = 0
+#define Dbl_setinfinitynegative(dbl_valueA,dbl_valueB)		\
+    Dallp1(dbl_valueA) = ((unsigned int)1<<31) |		\
+         (DBL_INFINITY_EXPONENT << (32-(1+DBL_EXP_LENGTH)));	\
+    Dmantissap2(dbl_valueB) = 0
+#define Dbl_setinfinity(dbl_valueA,dbl_valueB,sign)		\
+    Dallp1(dbl_valueA) = ((unsigned int)sign << 31) | 		\
+	(DBL_INFINITY_EXPONENT << (32-(1+DBL_EXP_LENGTH)));	\
+    Dmantissap2(dbl_valueB) = 0
+
+#define Dbl_sethigh4bits(dbl_value, extsign) Deposit_dhigh4p1(dbl_value,extsign)
+#define Dbl_set_sign(dbl_value,sign) Deposit_dsign(dbl_value,sign)
+#define Dbl_invert_sign(dbl_value) Deposit_dsign(dbl_value,~Dsign(dbl_value))
+#define Dbl_setone_sign(dbl_value) Deposit_dsign(dbl_value,1)
+#define Dbl_setone_lowmantissap2(dbl_value) Deposit_dlowp2(dbl_value,1)
+#define Dbl_setzero_sign(dbl_value) Dallp1(dbl_value) &= 0x7fffffff
+#define Dbl_setzero_exponent(dbl_value) 		\
+    Dallp1(dbl_value) &= 0x800fffff
+#define Dbl_setzero_mantissa(dbl_valueA,dbl_valueB)	\
+    Dallp1(dbl_valueA) &= 0xfff00000; 			\
+    Dallp2(dbl_valueB) = 0
+#define Dbl_setzero_mantissap1(dbl_value) Dallp1(dbl_value) &= 0xfff00000
+#define Dbl_setzero_mantissap2(dbl_value) Dallp2(dbl_value) = 0
+#define Dbl_setzero_exponentmantissa(dbl_valueA,dbl_valueB)	\
+    Dallp1(dbl_valueA) &= 0x80000000;		\
+    Dallp2(dbl_valueB) = 0
+#define Dbl_setzero_exponentmantissap1(dbl_valueA)	\
+    Dallp1(dbl_valueA) &= 0x80000000
+#define Dbl_setzero(dbl_valueA,dbl_valueB) \
+    Dallp1(dbl_valueA) = 0; Dallp2(dbl_valueB) = 0
+#define Dbl_setzerop1(dbl_value) Dallp1(dbl_value) = 0
+#define Dbl_setzerop2(dbl_value) Dallp2(dbl_value) = 0
+#define Dbl_setnegativezero(dbl_value) \
+    Dallp1(dbl_value) = (unsigned int)1 << 31; Dallp2(dbl_value) = 0
+#define Dbl_setnegativezerop1(dbl_value) Dallp1(dbl_value) = (unsigned int)1<<31
+
+/* Use the following macro for both overflow & underflow conditions */
+#define ovfl -
+#define unfl +
+#define Dbl_setwrapped_exponent(dbl_value,exponent,op) \
+    Deposit_dexponent(dbl_value,(exponent op DBL_WRAP))
+
+#define Dbl_setlargestpositive(dbl_valueA,dbl_valueB) 			\
+    Dallp1(dbl_valueA) = ((DBL_EMAX+DBL_BIAS) << (32-(1+DBL_EXP_LENGTH))) \
+			| ((1<<(32-(1+DBL_EXP_LENGTH))) - 1 );		\
+    Dallp2(dbl_valueB) = 0xFFFFFFFF
+#define Dbl_setlargestnegative(dbl_valueA,dbl_valueB) 			\
+    Dallp1(dbl_valueA) = ((DBL_EMAX+DBL_BIAS) << (32-(1+DBL_EXP_LENGTH))) \
+			| ((1<<(32-(1+DBL_EXP_LENGTH))) - 1 )		\
+			| ((unsigned int)1<<31);			\
+    Dallp2(dbl_valueB) = 0xFFFFFFFF
+#define Dbl_setlargest_exponentmantissa(dbl_valueA,dbl_valueB)		\
+    Deposit_dexponentmantissap1(dbl_valueA,				\
+	(((DBL_EMAX+DBL_BIAS) << (32-(1+DBL_EXP_LENGTH)))		\
+			| ((1<<(32-(1+DBL_EXP_LENGTH))) - 1 )));	\
+    Dallp2(dbl_valueB) = 0xFFFFFFFF
+
+#define Dbl_setnegativeinfinity(dbl_valueA,dbl_valueB) 			\
+    Dallp1(dbl_valueA) = ((1<<DBL_EXP_LENGTH) | DBL_INFINITY_EXPONENT) 	\
+			 << (32-(1+DBL_EXP_LENGTH)) ; 			\
+    Dallp2(dbl_valueB) = 0
+#define Dbl_setlargest(dbl_valueA,dbl_valueB,sign)			\
+    Dallp1(dbl_valueA) = ((unsigned int)sign << 31) |			\
+         ((DBL_EMAX+DBL_BIAS) << (32-(1+DBL_EXP_LENGTH))) |	 	\
+	 ((1 << (32-(1+DBL_EXP_LENGTH))) - 1 );				\
+    Dallp2(dbl_valueB) = 0xFFFFFFFF
+    
+
+/* The high bit is always zero so arithmetic or logical shifts will work. */
+#define Dbl_right_align(srcdstA,srcdstB,shift,extent)			\
+    if( shift >= 32 ) 							\
+	{								\
+	/* Big shift requires examining the portion shift off 		\
+	the end to properly set inexact.  */				\
+	if(shift < 64)							\
+	    {								\
+	    if(shift > 32)						\
+		{							\
+	        Variable_shift_double(Dallp1(srcdstA),Dallp2(srcdstB),	\
+		 shift-32, Extall(extent));				\
+	        if(Dallp2(srcdstB) << 64 - (shift)) Ext_setone_low(extent); \
+	        }							\
+	    else Extall(extent) = Dallp2(srcdstB);			\
+	    Dallp2(srcdstB) = Dallp1(srcdstA) >> (shift - 32);		\
+	    }								\
+	else								\
+	    {								\
+	    Extall(extent) = Dallp1(srcdstA);				\
+	    if(Dallp2(srcdstB)) Ext_setone_low(extent);			\
+	    Dallp2(srcdstB) = 0;					\
+	    }								\
+	Dallp1(srcdstA) = 0;						\
+	}								\
+    else								\
+	{								\
+	/* Small alignment is simpler.  Extension is easily set. */	\
+	if (shift > 0)							\
+	    {								\
+	    Extall(extent) = Dallp2(srcdstB) << 32 - (shift);		\
+	    Variable_shift_double(Dallp1(srcdstA),Dallp2(srcdstB),shift, \
+	     Dallp2(srcdstB));						\
+	    Dallp1(srcdstA) >>= shift;					\
+	    }								\
+	else Extall(extent) = 0;					\
+	}
+
+/* 
+ * Here we need to shift the result right to correct for an overshift
+ * (due to the exponent becoming negative) during normalization.
+ */
+#define Dbl_fix_overshift(srcdstA,srcdstB,shift,extent)			\
+	    Extall(extent) = Dallp2(srcdstB) << 32 - (shift);		\
+	    Dallp2(srcdstB) = (Dallp1(srcdstA) << 32 - (shift)) |	\
+		(Dallp2(srcdstB) >> (shift));				\
+	    Dallp1(srcdstA) = Dallp1(srcdstA) >> shift
+
+#define Dbl_hiddenhigh3mantissa(dbl_value) Dhiddenhigh3mantissa(dbl_value)
+#define Dbl_hidden(dbl_value) Dhidden(dbl_value)
+#define Dbl_lowmantissap2(dbl_value) Dlowp2(dbl_value)
+
+/* The left argument is never smaller than the right argument */
+#define Dbl_subtract(lefta,leftb,righta,rightb,resulta,resultb)			\
+    if( Dallp2(rightb) > Dallp2(leftb) ) Dallp1(lefta)--;	\
+    Dallp2(resultb) = Dallp2(leftb) - Dallp2(rightb);		\
+    Dallp1(resulta) = Dallp1(lefta) - Dallp1(righta)
+
+/* Subtract right augmented with extension from left augmented with zeros and
+ * store into result and extension. */
+#define Dbl_subtract_withextension(lefta,leftb,righta,rightb,extent,resulta,resultb)	\
+    Dbl_subtract(lefta,leftb,righta,rightb,resulta,resultb);		\
+    if( (Extall(extent) = 0-Extall(extent)) )				\
+        {								\
+        if((Dallp2(resultb)--) == 0) Dallp1(resulta)--;			\
+        }
+
+#define Dbl_addition(lefta,leftb,righta,rightb,resulta,resultb)		\
+    /* If the sum of the low words is less than either source, then	\
+     * an overflow into the next word occurred. */			\
+    Dallp1(resulta) = Dallp1(lefta) + Dallp1(righta);			\
+    if((Dallp2(resultb) = Dallp2(leftb) + Dallp2(rightb)) < Dallp2(rightb)) \
+	Dallp1(resulta)++
+
+#define Dbl_xortointp1(left,right,result)			\
+    result = Dallp1(left) XOR Dallp1(right)
+
+#define Dbl_xorfromintp1(left,right,result)			\
+    Dallp1(result) = left XOR Dallp1(right)
+
+#define Dbl_swap_lower(left,right)				\
+    Dallp2(left)  = Dallp2(left) XOR Dallp2(right);		\
+    Dallp2(right) = Dallp2(left) XOR Dallp2(right);		\
+    Dallp2(left)  = Dallp2(left) XOR Dallp2(right)
+
+/* Need to Initialize */
+#define Dbl_makequietnan(desta,destb)					\
+    Dallp1(desta) = ((DBL_EMAX+DBL_BIAS)+1)<< (32-(1+DBL_EXP_LENGTH))	\
+                 | (1<<(32-(1+DBL_EXP_LENGTH+2)));			\
+    Dallp2(destb) = 0
+#define Dbl_makesignalingnan(desta,destb)				\
+    Dallp1(desta) = ((DBL_EMAX+DBL_BIAS)+1)<< (32-(1+DBL_EXP_LENGTH))	\
+                 | (1<<(32-(1+DBL_EXP_LENGTH+1)));			\
+    Dallp2(destb) = 0
+
+#define Dbl_normalize(dbl_opndA,dbl_opndB,exponent)			\
+	while(Dbl_iszero_hiddenhigh7mantissa(dbl_opndA)) {		\
+		Dbl_leftshiftby8(dbl_opndA,dbl_opndB);			\
+		exponent -= 8;						\
+	}								\
+	if(Dbl_iszero_hiddenhigh3mantissa(dbl_opndA)) {			\
+		Dbl_leftshiftby4(dbl_opndA,dbl_opndB);			\
+		exponent -= 4;						\
+	}								\
+	while(Dbl_iszero_hidden(dbl_opndA)) {				\
+		Dbl_leftshiftby1(dbl_opndA,dbl_opndB);			\
+		exponent -= 1;						\
+	}
+
+#define Twoword_add(src1dstA,src1dstB,src2A,src2B)		\
+	/* 							\
+	 * want this macro to generate:				\
+	 *	ADD	src1dstB,src2B,src1dstB;		\
+	 *	ADDC	src1dstA,src2A,src1dstA;		\
+	 */							\
+	if ((src1dstB) + (src2B) < (src1dstB)) Dallp1(src1dstA)++; \
+	Dallp1(src1dstA) += (src2A);				\
+	Dallp2(src1dstB) += (src2B)
+
+#define Twoword_subtract(src1dstA,src1dstB,src2A,src2B)		\
+	/* 							\
+	 * want this macro to generate:				\
+	 *	SUB	src1dstB,src2B,src1dstB;		\
+	 *	SUBB	src1dstA,src2A,src1dstA;		\
+	 */							\
+	if ((src1dstB) < (src2B)) Dallp1(src1dstA)--;		\
+	Dallp1(src1dstA) -= (src2A);				\
+	Dallp2(src1dstB) -= (src2B)
+
+#define Dbl_setoverflow(resultA,resultB)				\
+	/* set result to infinity or largest number */			\
+	switch (Rounding_mode()) {					\
+		case ROUNDPLUS:						\
+			if (Dbl_isone_sign(resultA)) {			\
+				Dbl_setlargestnegative(resultA,resultB); \
+			}						\
+			else {						\
+				Dbl_setinfinitypositive(resultA,resultB); \
+			}						\
+			break;						\
+		case ROUNDMINUS:					\
+			if (Dbl_iszero_sign(resultA)) {			\
+				Dbl_setlargestpositive(resultA,resultB); \
+			}						\
+			else {						\
+				Dbl_setinfinitynegative(resultA,resultB); \
+			}						\
+			break;						\
+		case ROUNDNEAREST:					\
+			Dbl_setinfinity_exponentmantissa(resultA,resultB); \
+			break;						\
+		case ROUNDZERO:						\
+			Dbl_setlargest_exponentmantissa(resultA,resultB); \
+	}
+
+#define Dbl_denormalize(opndp1,opndp2,exponent,guard,sticky,inexact)	\
+    Dbl_clear_signexponent_set_hidden(opndp1);				\
+    if (exponent >= (1-DBL_P)) {					\
+	if (exponent >= -31) {						\
+	    guard = (Dallp2(opndp2) >> -exponent) & 1;			\
+	    if (exponent < 0) sticky |= Dallp2(opndp2) << (32+exponent); \
+	    if (exponent > -31) {					\
+		Variable_shift_double(opndp1,opndp2,1-exponent,opndp2);	\
+		Dallp1(opndp1) >>= 1-exponent;				\
+	    }								\
+	    else {							\
+		Dallp2(opndp2) = Dallp1(opndp1);			\
+		Dbl_setzerop1(opndp1);					\
+	    }								\
+	}								\
+	else {								\
+	    guard = (Dallp1(opndp1) >> -32-exponent) & 1;		\
+	    if (exponent == -32) sticky |= Dallp2(opndp2);		\
+	    else sticky |= (Dallp2(opndp2) | Dallp1(opndp1) << 64+exponent); \
+	    Dallp2(opndp2) = Dallp1(opndp1) >> -31-exponent;		\
+	    Dbl_setzerop1(opndp1);					\
+	}								\
+	inexact = guard | sticky;					\
+    }									\
+    else {								\
+	guard = 0;							\
+	sticky |= (Dallp1(opndp1) | Dallp2(opndp2));			\
+	Dbl_setzero(opndp1,opndp2);					\
+	inexact = sticky;						\
+    }
+
+/* 
+ * The fused multiply add instructions requires a double extended format,
+ * with 106 bits of mantissa.
+ */
+#define DBLEXT_THRESHOLD 106
+
+#define Dblext_setzero(valA,valB,valC,valD)	\
+    Dextallp1(valA) = 0; Dextallp2(valB) = 0;	\
+    Dextallp3(valC) = 0; Dextallp4(valD) = 0
+
+
+#define Dblext_isnotzero_mantissap3(valC) (Dextallp3(valC)!=0)
+#define Dblext_isnotzero_mantissap4(valD) (Dextallp3(valD)!=0)
+#define Dblext_isone_lowp2(val) (Dextlowp2(val)!=0)
+#define Dblext_isone_highp3(val) (Dexthighp3(val)!=0)
+#define Dblext_isnotzero_low31p3(val) (Dextlow31p3(val)!=0)
+#define Dblext_iszero(valA,valB,valC,valD) (Dextallp1(valA)==0 && \
+    Dextallp2(valB)==0 && Dextallp3(valC)==0 && Dextallp4(valD)==0)
+
+#define Dblext_copy(srca,srcb,srcc,srcd,desta,destb,destc,destd) \
+    Dextallp1(desta) = Dextallp4(srca);	\
+    Dextallp2(destb) = Dextallp4(srcb);	\
+    Dextallp3(destc) = Dextallp4(srcc);	\
+    Dextallp4(destd) = Dextallp4(srcd)
+
+#define Dblext_swap_lower(leftp2,leftp3,leftp4,rightp2,rightp3,rightp4)  \
+    Dextallp2(leftp2)  = Dextallp2(leftp2) XOR Dextallp2(rightp2);  \
+    Dextallp2(rightp2) = Dextallp2(leftp2) XOR Dextallp2(rightp2);  \
+    Dextallp2(leftp2)  = Dextallp2(leftp2) XOR Dextallp2(rightp2);  \
+    Dextallp3(leftp3)  = Dextallp3(leftp3) XOR Dextallp3(rightp3);  \
+    Dextallp3(rightp3) = Dextallp3(leftp3) XOR Dextallp3(rightp3);  \
+    Dextallp3(leftp3)  = Dextallp3(leftp3) XOR Dextallp3(rightp3);  \
+    Dextallp4(leftp4)  = Dextallp4(leftp4) XOR Dextallp4(rightp4);  \
+    Dextallp4(rightp4) = Dextallp4(leftp4) XOR Dextallp4(rightp4);  \
+    Dextallp4(leftp4)  = Dextallp4(leftp4) XOR Dextallp4(rightp4)
+
+#define Dblext_setone_lowmantissap4(dbl_value) Deposit_dextlowp4(dbl_value,1)
+
+/* The high bit is always zero so arithmetic or logical shifts will work. */
+#define Dblext_right_align(srcdstA,srcdstB,srcdstC,srcdstD,shift) \
+  {int shiftamt, sticky;						\
+    shiftamt = shift % 32;						\
+    sticky = 0;								\
+    switch (shift/32) {							\
+     case 0: if (shiftamt > 0) {					\
+	        sticky = Dextallp4(srcdstD) << 32 - (shiftamt); 	\
+                Variable_shift_double(Dextallp3(srcdstC),		\
+		 Dextallp4(srcdstD),shiftamt,Dextallp4(srcdstD));	\
+                Variable_shift_double(Dextallp2(srcdstB),		\
+		 Dextallp3(srcdstC),shiftamt,Dextallp3(srcdstC));	\
+                Variable_shift_double(Dextallp1(srcdstA),		\
+		 Dextallp2(srcdstB),shiftamt,Dextallp2(srcdstB));	\
+	        Dextallp1(srcdstA) >>= shiftamt;			\
+	     }								\
+	     break;							\
+     case 1: if (shiftamt > 0) {					\
+                sticky = (Dextallp3(srcdstC) << 31 - shiftamt) |	\
+			 Dextallp4(srcdstD);				\
+                Variable_shift_double(Dextallp2(srcdstB),		\
+		 Dextallp3(srcdstC),shiftamt,Dextallp4(srcdstD));	\
+                Variable_shift_double(Dextallp1(srcdstA),		\
+		 Dextallp2(srcdstB),shiftamt,Dextallp3(srcdstC));	\
+	     }								\
+	     else {							\
+		sticky = Dextallp4(srcdstD);				\
+		Dextallp4(srcdstD) = Dextallp3(srcdstC);		\
+		Dextallp3(srcdstC) = Dextallp2(srcdstB);		\
+	     }								\
+	     Dextallp2(srcdstB) = Dextallp1(srcdstA) >> shiftamt;	\
+	     Dextallp1(srcdstA) = 0;					\
+	     break;							\
+     case 2: if (shiftamt > 0) {					\
+                sticky = (Dextallp2(srcdstB) << 31 - shiftamt) |	\
+			 Dextallp3(srcdstC) | Dextallp4(srcdstD);	\
+                Variable_shift_double(Dextallp1(srcdstA),		\
+		 Dextallp2(srcdstB),shiftamt,Dextallp4(srcdstD));	\
+	     }								\
+	     else {							\
+		sticky = Dextallp3(srcdstC) | Dextallp4(srcdstD);	\
+		Dextallp4(srcdstD) = Dextallp2(srcdstB);		\
+	     }								\
+	     Dextallp3(srcdstC) = Dextallp1(srcdstA) >> shiftamt;	\
+	     Dextallp1(srcdstA) = Dextallp2(srcdstB) = 0;		\
+	     break;							\
+     case 3: if (shiftamt > 0) {					\
+                sticky = (Dextallp1(srcdstA) << 31 - shiftamt) |	\
+			 Dextallp2(srcdstB) | Dextallp3(srcdstC) |	\
+			 Dextallp4(srcdstD);				\
+	     }								\
+	     else {							\
+		sticky = Dextallp2(srcdstB) | Dextallp3(srcdstC) |	\
+		    Dextallp4(srcdstD);					\
+	     }								\
+	     Dextallp4(srcdstD) = Dextallp1(srcdstA) >> shiftamt;	\
+	     Dextallp1(srcdstA) = Dextallp2(srcdstB) = 0;		\
+	     Dextallp3(srcdstC) = 0;					\
+	     break;							\
+    }									\
+    if (sticky) Dblext_setone_lowmantissap4(srcdstD);			\
+  }
+
+/* The left argument is never smaller than the right argument */
+#define Dblext_subtract(lefta,leftb,leftc,leftd,righta,rightb,rightc,rightd,resulta,resultb,resultc,resultd) \
+    if( Dextallp4(rightd) > Dextallp4(leftd) ) 			\
+	if( (Dextallp3(leftc)--) == 0)				\
+	    if( (Dextallp2(leftb)--) == 0) Dextallp1(lefta)--;	\
+    Dextallp4(resultd) = Dextallp4(leftd) - Dextallp4(rightd);	\
+    if( Dextallp3(rightc) > Dextallp3(leftc) ) 			\
+        if( (Dextallp2(leftb)--) == 0) Dextallp1(lefta)--;	\
+    Dextallp3(resultc) = Dextallp3(leftc) - Dextallp3(rightc);	\
+    if( Dextallp2(rightb) > Dextallp2(leftb) ) Dextallp1(lefta)--; \
+    Dextallp2(resultb) = Dextallp2(leftb) - Dextallp2(rightb);	\
+    Dextallp1(resulta) = Dextallp1(lefta) - Dextallp1(righta)
+
+#define Dblext_addition(lefta,leftb,leftc,leftd,righta,rightb,rightc,rightd,resulta,resultb,resultc,resultd) \
+    /* If the sum of the low words is less than either source, then \
+     * an overflow into the next word occurred. */ \
+    if ((Dextallp4(resultd) = Dextallp4(leftd)+Dextallp4(rightd)) < \
+	Dextallp4(rightd)) \
+	if((Dextallp3(resultc) = Dextallp3(leftc)+Dextallp3(rightc)+1) <= \
+	    Dextallp3(rightc)) \
+	    if((Dextallp2(resultb) = Dextallp2(leftb)+Dextallp2(rightb)+1) \
+	        <= Dextallp2(rightb))  \
+		    Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta)+1; \
+	    else Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta); \
+	else \
+	    if ((Dextallp2(resultb) = Dextallp2(leftb)+Dextallp2(rightb)) < \
+	        Dextallp2(rightb)) \
+		    Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta)+1; \
+	    else Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta); \
+    else \
+	if ((Dextallp3(resultc) = Dextallp3(leftc)+Dextallp3(rightc)) < \
+	    Dextallp3(rightc))  \
+	    if ((Dextallp2(resultb) = Dextallp2(leftb)+Dextallp2(rightb)+1) \
+	        <= Dextallp2(rightb)) \
+		    Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta)+1; \
+	    else Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta); \
+	else \
+	    if ((Dextallp2(resultb) = Dextallp2(leftb)+Dextallp2(rightb)) < \
+	        Dextallp2(rightb)) \
+		    Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta)+1; \
+	    else Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta)
+
+
+#define Dblext_arithrightshiftby1(srcdstA,srcdstB,srcdstC,srcdstD)	\
+    Shiftdouble(Dextallp3(srcdstC),Dextallp4(srcdstD),1,Dextallp4(srcdstD)); \
+    Shiftdouble(Dextallp2(srcdstB),Dextallp3(srcdstC),1,Dextallp3(srcdstC)); \
+    Shiftdouble(Dextallp1(srcdstA),Dextallp2(srcdstB),1,Dextallp2(srcdstB)); \
+    Dextallp1(srcdstA) = (int)Dextallp1(srcdstA) >> 1
+   
+#define Dblext_leftshiftby8(valA,valB,valC,valD) \
+    Shiftdouble(Dextallp1(valA),Dextallp2(valB),24,Dextallp1(valA)); \
+    Shiftdouble(Dextallp2(valB),Dextallp3(valC),24,Dextallp2(valB)); \
+    Shiftdouble(Dextallp3(valC),Dextallp4(valD),24,Dextallp3(valC)); \
+    Dextallp4(valD) <<= 8
+#define Dblext_leftshiftby4(valA,valB,valC,valD) \
+    Shiftdouble(Dextallp1(valA),Dextallp2(valB),28,Dextallp1(valA)); \
+    Shiftdouble(Dextallp2(valB),Dextallp3(valC),28,Dextallp2(valB)); \
+    Shiftdouble(Dextallp3(valC),Dextallp4(valD),28,Dextallp3(valC)); \
+    Dextallp4(valD) <<= 4
+#define Dblext_leftshiftby3(valA,valB,valC,valD) \
+    Shiftdouble(Dextallp1(valA),Dextallp2(valB),29,Dextallp1(valA)); \
+    Shiftdouble(Dextallp2(valB),Dextallp3(valC),29,Dextallp2(valB)); \
+    Shiftdouble(Dextallp3(valC),Dextallp4(valD),29,Dextallp3(valC)); \
+    Dextallp4(valD) <<= 3
+#define Dblext_leftshiftby2(valA,valB,valC,valD) \
+    Shiftdouble(Dextallp1(valA),Dextallp2(valB),30,Dextallp1(valA)); \
+    Shiftdouble(Dextallp2(valB),Dextallp3(valC),30,Dextallp2(valB)); \
+    Shiftdouble(Dextallp3(valC),Dextallp4(valD),30,Dextallp3(valC)); \
+    Dextallp4(valD) <<= 2
+#define Dblext_leftshiftby1(valA,valB,valC,valD) \
+    Shiftdouble(Dextallp1(valA),Dextallp2(valB),31,Dextallp1(valA)); \
+    Shiftdouble(Dextallp2(valB),Dextallp3(valC),31,Dextallp2(valB)); \
+    Shiftdouble(Dextallp3(valC),Dextallp4(valD),31,Dextallp3(valC)); \
+    Dextallp4(valD) <<= 1
+
+#define Dblext_rightshiftby4(valueA,valueB,valueC,valueD) \
+    Shiftdouble(Dextallp3(valueC),Dextallp4(valueD),4,Dextallp4(valueD)); \
+    Shiftdouble(Dextallp2(valueB),Dextallp3(valueC),4,Dextallp3(valueC)); \
+    Shiftdouble(Dextallp1(valueA),Dextallp2(valueB),4,Dextallp2(valueB)); \
+    Dextallp1(valueA) >>= 4
+#define Dblext_rightshiftby1(valueA,valueB,valueC,valueD) \
+    Shiftdouble(Dextallp3(valueC),Dextallp4(valueD),1,Dextallp4(valueD)); \
+    Shiftdouble(Dextallp2(valueB),Dextallp3(valueC),1,Dextallp3(valueC)); \
+    Shiftdouble(Dextallp1(valueA),Dextallp2(valueB),1,Dextallp2(valueB)); \
+    Dextallp1(valueA) >>= 1
+
+#define Dblext_xortointp1(left,right,result) Dbl_xortointp1(left,right,result)
+
+#define Dblext_xorfromintp1(left,right,result) \
+	Dbl_xorfromintp1(left,right,result)
+
+#define Dblext_copytoint_exponentmantissap1(src,dest) \
+	Dbl_copytoint_exponentmantissap1(src,dest)
+
+#define Dblext_ismagnitudeless(leftB,rightB,signlessleft,signlessright) \
+	Dbl_ismagnitudeless(leftB,rightB,signlessleft,signlessright)
+
+#define Dbl_copyto_dblext(src1,src2,dest1,dest2,dest3,dest4) \
+	Dextallp1(dest1) = Dallp1(src1); Dextallp2(dest2) = Dallp2(src2); \
+	Dextallp3(dest3) = 0; Dextallp4(dest4) = 0
+
+#define Dblext_set_sign(dbl_value,sign)  Dbl_set_sign(dbl_value,sign)  
+#define Dblext_clear_signexponent_set_hidden(srcdst) \
+	Dbl_clear_signexponent_set_hidden(srcdst) 
+#define Dblext_clear_signexponent(srcdst) Dbl_clear_signexponent(srcdst) 
+#define Dblext_clear_sign(srcdst) Dbl_clear_sign(srcdst) 
+#define Dblext_isone_hidden(dbl_value) Dbl_isone_hidden(dbl_value) 
+
+/*
+ * The Fourword_add() macro assumes that integers are 4 bytes in size.
+ * It will break if this is not the case.
+ */
+
+#define Fourword_add(src1dstA,src1dstB,src1dstC,src1dstD,src2A,src2B,src2C,src2D) \
+	/* 								\
+	 * want this macro to generate:					\
+	 *	ADD	src1dstD,src2D,src1dstD;			\
+	 *	ADDC	src1dstC,src2C,src1dstC;			\
+	 *	ADDC	src1dstB,src2B,src1dstB;			\
+	 *	ADDC	src1dstA,src2A,src1dstA;			\
+	 */								\
+	if ((unsigned int)(src1dstD += (src2D)) < (unsigned int)(src2D)) { \
+	   if ((unsigned int)(src1dstC += (src2C) + 1) <=		\
+	       (unsigned int)(src2C)) {					\
+	     if ((unsigned int)(src1dstB += (src2B) + 1) <=		\
+		 (unsigned int)(src2B)) src1dstA++;			\
+	   }								\
+	   else if ((unsigned int)(src1dstB += (src2B)) < 		\
+		    (unsigned int)(src2B)) src1dstA++;			\
+	}								\
+	else {								\
+	   if ((unsigned int)(src1dstC += (src2C)) <			\
+	       (unsigned int)(src2C)) {					\
+	      if ((unsigned int)(src1dstB += (src2B) + 1) <=		\
+		  (unsigned int)(src2B)) src1dstA++;			\
+	   }								\
+	   else if ((unsigned int)(src1dstB += (src2B)) <		\
+		    (unsigned int)(src2B)) src1dstA++;			\
+	}								\
+	src1dstA += (src2A)
+
+#define Dblext_denormalize(opndp1,opndp2,opndp3,opndp4,exponent,is_tiny) \
+  {int shiftamt, sticky;						\
+    is_tiny = TRUE;							\
+    if (exponent == 0 && (Dextallp3(opndp3) || Dextallp4(opndp4))) {	\
+	switch (Rounding_mode()) {					\
+	case ROUNDPLUS:							\
+		if (Dbl_iszero_sign(opndp1)) {				\
+			Dbl_increment(opndp1,opndp2);			\
+			if (Dbl_isone_hiddenoverflow(opndp1))		\
+				is_tiny = FALSE;			\
+			Dbl_decrement(opndp1,opndp2);			\
+		}							\
+		break;							\
+	case ROUNDMINUS:						\
+		if (Dbl_isone_sign(opndp1)) {				\
+			Dbl_increment(opndp1,opndp2);			\
+			if (Dbl_isone_hiddenoverflow(opndp1))		\
+				is_tiny = FALSE;			\
+			Dbl_decrement(opndp1,opndp2);			\
+		}							\
+		break;							\
+	case ROUNDNEAREST:						\
+		if (Dblext_isone_highp3(opndp3) &&			\
+		    (Dblext_isone_lowp2(opndp2) || 			\
+		     Dblext_isnotzero_low31p3(opndp3)))	{		\
+			Dbl_increment(opndp1,opndp2);			\
+			if (Dbl_isone_hiddenoverflow(opndp1))		\
+				is_tiny = FALSE;			\
+			Dbl_decrement(opndp1,opndp2);			\
+		}							\
+		break;							\
+	}								\
+    }									\
+    Dblext_clear_signexponent_set_hidden(opndp1);			\
+    if (exponent >= (1-QUAD_P)) {					\
+	shiftamt = (1-exponent) % 32;					\
+	switch((1-exponent)/32) {					\
+	  case 0: sticky = Dextallp4(opndp4) << 32-(shiftamt);		\
+		  Variableshiftdouble(opndp3,opndp4,shiftamt,opndp4);	\
+		  Variableshiftdouble(opndp2,opndp3,shiftamt,opndp3);	\
+		  Variableshiftdouble(opndp1,opndp2,shiftamt,opndp2);	\
+		  Dextallp1(opndp1) >>= shiftamt;			\
+		  break;						\
+	  case 1: sticky = (Dextallp3(opndp3) << 32-(shiftamt)) | 	\
+			   Dextallp4(opndp4);				\
+		  Variableshiftdouble(opndp2,opndp3,shiftamt,opndp4);	\
+		  Variableshiftdouble(opndp1,opndp2,shiftamt,opndp3);	\
+		  Dextallp2(opndp2) = Dextallp1(opndp1) >> shiftamt;	\
+		  Dextallp1(opndp1) = 0;				\
+		  break;						\
+	  case 2: sticky = (Dextallp2(opndp2) << 32-(shiftamt)) |	\
+			    Dextallp3(opndp3) | Dextallp4(opndp4);	\
+		  Variableshiftdouble(opndp1,opndp2,shiftamt,opndp4);	\
+		  Dextallp3(opndp3) = Dextallp1(opndp1) >> shiftamt;	\
+		  Dextallp1(opndp1) = Dextallp2(opndp2) = 0;		\
+		  break;						\
+	  case 3: sticky = (Dextallp1(opndp1) << 32-(shiftamt)) |	\
+		  	Dextallp2(opndp2) | Dextallp3(opndp3) | 	\
+			Dextallp4(opndp4);				\
+		  Dextallp4(opndp4) = Dextallp1(opndp1) >> shiftamt;	\
+		  Dextallp1(opndp1) = Dextallp2(opndp2) = 0;		\
+		  Dextallp3(opndp3) = 0;				\
+		  break;						\
+	}								\
+    }									\
+    else {								\
+	sticky = Dextallp1(opndp1) | Dextallp2(opndp2) |		\
+		 Dextallp3(opndp3) | Dextallp4(opndp4);			\
+	Dblext_setzero(opndp1,opndp2,opndp3,opndp4);			\
+    }									\
+    if (sticky) Dblext_setone_lowmantissap4(opndp4);			\
+    exponent = 0;							\
+  }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/decode_exc.c linux-2.4.20/arch/parisc/math-emu/decode_exc.c
--- linux-2.4.19/arch/parisc/math-emu/decode_exc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/decode_exc.c	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,368 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/fp/decode_exc.c		$ Revision: $
+ *
+ *  Purpose:
+ *	<<please update with a synopsis of the functionality provided by this file>>
+ *
+ *  External Interfaces:
+ *	<<the following list was autogenerated, please review>>
+ *	decode_fpu(Fpu_register, trap_counts)
+ *
+ *  Internal Interfaces:
+ *	<<please update>>
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+/* #include "types.h" */
+#include <asm/signal.h>
+#include <asm/siginfo.h>
+/* #include <machine/sys/mdep_private.h> */
+
+#undef Fpustatus_register
+#define Fpustatus_register Fpu_register[0]
+
+/* General definitions */
+#define DOESTRAP 1
+#define NOTRAP 0
+#define SIGNALCODE(signal, code) ((signal) << 24 | (code));
+#define copropbit	1<<31-2	/* bit position 2 */
+#define opclass		9	/* bits 21 & 22 */
+#define fmt		11	/* bits 19 & 20 */
+#define df		13	/* bits 17 & 18 */
+#define twobits		3	/* mask low-order 2 bits */
+#define fivebits	31	/* mask low-order 5 bits */
+#define MAX_EXCP_REG	7	/* number of excpeption registers to check */
+
+/* Exception register definitions */
+#define Excp_type(index) Exceptiontype(Fpu_register[index])
+#define Excp_instr(index) Instructionfield(Fpu_register[index])
+#define Clear_excp_register(index) Allexception(Fpu_register[index]) = 0
+#define Excp_format() \
+    (current_ir >> ((current_ir>>opclass & twobits)==1 ? df : fmt) & twobits)
+
+/* Miscellaneous definitions */
+#define Fpu_sgl(index) Fpu_register[index*2]
+
+#define Fpu_dblp1(index) Fpu_register[index*2]
+#define Fpu_dblp2(index) Fpu_register[(index*2)+1]
+
+#define Fpu_quadp1(index) Fpu_register[index*2]
+#define Fpu_quadp2(index) Fpu_register[(index*2)+1]
+#define Fpu_quadp3(index) Fpu_register[(index*2)+2]
+#define Fpu_quadp4(index) Fpu_register[(index*2)+3]
+
+/* Single precision floating-point definitions */
+#ifndef Sgl_decrement
+# define Sgl_decrement(sgl_value) Sall(sgl_value)--
+#endif
+
+/* Double precision floating-point definitions */
+#ifndef Dbl_decrement
+# define Dbl_decrement(dbl_valuep1,dbl_valuep2) \
+    if ((Dallp2(dbl_valuep2)--) == 0) Dallp1(dbl_valuep1)-- 
+#endif
+
+
+#define update_trap_counts(Fpu_register, aflags, bflags, trap_counts) {	\
+	aflags=(Fpu_register[0])>>27;	/* assumes zero fill. 32 bit */	\
+	Fpu_register[0] |= bflags;					\
+}
+
+u_int
+decode_fpu(unsigned int Fpu_register[], unsigned int trap_counts[])
+{
+    unsigned int current_ir, excp;
+    int target, exception_index = 1;
+    boolean inexact;
+    unsigned int aflags;
+    unsigned int bflags;
+    unsigned int excptype;
+
+
+    /* Keep stats on how many floating point exceptions (based on type)
+     * that happen.  Want to keep this overhead low, but still provide
+     * some information to the customer.  All exits from this routine
+     * need to restore Fpu_register[0]
+    */
+
+    bflags=(Fpu_register[0] & 0xf8000000);
+    Fpu_register[0] &= 0x07ffffff;
+
+    /* exception_index is used to index the exception register queue.  It
+     *   always points at the last register that contains a valid exception.  A
+     *   zero value implies no exceptions (also the initialized value).  Setting
+     *   the T-bit resets the exception_index to zero.
+     */
+
+    /*
+     * Check for reserved-op exception.  A reserved-op exception does not 
+     * set any exception registers nor does it set the T-bit.  If the T-bit
+     * is not set then a reserved-op exception occurred.
+     *
+     * At some point, we may want to report reserved op exceptions as
+     * illegal instructions.
+     */
+    
+    if (!Is_tbit_set()) {
+	update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+	return SIGNALCODE(SIGILL, ILL_COPROC);
+    }
+
+    /* 
+     * Is a coprocessor op. 
+     *
+     * Now we need to determine what type of exception occurred.
+     */
+    for (exception_index=1; exception_index<=MAX_EXCP_REG; exception_index++) {
+	current_ir = Excp_instr(exception_index);
+	  /*
+	   * On PA89: there are 5 different unimplemented exception
+	   * codes: 0x1, 0x9, 0xb, 0x3, and 0x23.  PA-RISC 2.0 adds
+	   * another, 0x2b.  Only these have the low order bit set.
+	   */
+	excptype = Excp_type(exception_index);
+	if (excptype & UNIMPLEMENTEDEXCEPTION) {
+		/*
+		 * Clear T-bit and exception register so that
+		 * we can tell if a trap really occurs while 
+		 * emulating the instruction.
+		 */
+		Clear_tbit();
+		Clear_excp_register(exception_index);
+		/*
+		 * Now emulate this instruction.  If a trap occurs,
+		 * fpudispatch will return a non-zero number 
+		 */
+		excp = fpudispatch(current_ir,excptype,0,Fpu_register);
+		/* accumulate the status flags, don't lose them as in hpux */
+		if (excp) {
+			/*
+			 * We now need to make sure that the T-bit and the
+			 * exception register contain the correct values
+			 * before continuing.
+			 */
+			/*
+			 * Set t-bit since it might still be needed for a
+			 * subsequent real trap (I don't understand fully -PB)
+			 */
+			Set_tbit();
+			/* some of the following code uses
+			 * Excp_type(exception_index) so fix that up */
+			Set_exceptiontype_and_instr_field(excp,current_ir,
+			 Fpu_register[exception_index]);
+			if (excp == UNIMPLEMENTEDEXCEPTION) {
+				/*
+			 	 * it is really unimplemented, so restore the
+			 	 * TIMEX extended unimplemented exception code
+			 	 */
+				excp = excptype;
+				update_trap_counts(Fpu_register, aflags, bflags, 
+					   trap_counts);
+				return SIGNALCODE(SIGILL, ILL_COPROC);
+			}
+			/* some of the following code uses excptype, so
+			 * fix that up too */
+			excptype = excp;
+		}
+		/* handle exceptions other than the real UNIMPLIMENTED the
+		 * same way as if the hardware had caused them */
+		if (excp == NOEXCEPTION)
+			/* For now use 'break', should technically be 'continue' */
+			break;
+	}
+
+	  /*
+	   * In PA89, the underflow exception has been extended to encode
+	   * additional information.  The exception looks like pp01x0,
+	   * where x is 1 if inexact and pp represent the inexact bit (I)
+	   * and the round away bit (RA)
+	   */
+	if (excptype & UNDERFLOWEXCEPTION) {
+		/* check for underflow trap enabled */
+		if (Is_underflowtrap_enabled()) {
+			update_trap_counts(Fpu_register, aflags, bflags, 
+					   trap_counts);
+			return SIGNALCODE(SIGFPE, FPE_FLTUND);
+		} else {
+		    /*
+		     * Isn't a real trap; we need to 
+		     * return the default value.
+		     */
+		    target = current_ir & fivebits;
+#ifndef lint
+		    if (Ibit(Fpu_register[exception_index])) inexact = TRUE;
+		    else inexact = FALSE;
+#endif
+		    switch (Excp_format()) {
+		      case SGL:
+		        /*
+		         * If ra (round-away) is set, will 
+		         * want to undo the rounding done
+		         * by the hardware.
+		         */
+		        if (Rabit(Fpu_register[exception_index])) 
+				Sgl_decrement(Fpu_sgl(target));
+
+			/* now denormalize */
+			sgl_denormalize(&Fpu_sgl(target),&inexact,Rounding_mode());
+		    	break;
+		      case DBL:
+		    	/*
+		    	 * If ra (round-away) is set, will 
+		    	 * want to undo the rounding done
+		    	 * by the hardware.
+		    	 */
+		    	if (Rabit(Fpu_register[exception_index])) 
+				Dbl_decrement(Fpu_dblp1(target),Fpu_dblp2(target));
+
+			/* now denormalize */
+			dbl_denormalize(&Fpu_dblp1(target),&Fpu_dblp2(target),
+			  &inexact,Rounding_mode());
+		    	break;
+		    }
+		    if (inexact) Set_underflowflag();
+		    /* 
+		     * Underflow can generate an inexact
+		     * exception.  If inexact trap is enabled,
+		     * want to do an inexact trap, otherwise 
+		     * set inexact flag.
+		     */
+		    if (inexact && Is_inexacttrap_enabled()) {
+		    	/*
+		    	 * Set exception field of exception register
+		    	 * to inexact, parm field to zero.
+			 * Underflow bit should be cleared.
+		    	 */
+		    	Set_exceptiontype(Fpu_register[exception_index],
+			 INEXACTEXCEPTION);
+			Set_parmfield(Fpu_register[exception_index],0);
+			update_trap_counts(Fpu_register, aflags, bflags, 
+					   trap_counts);
+			return SIGNALCODE(SIGFPE, FPE_FLTRES);
+		    }
+		    else {
+		    	/*
+		    	 * Exception register needs to be cleared.  
+			 * Inexact flag needs to be set if inexact.
+		    	 */
+		    	Clear_excp_register(exception_index);
+		    	if (inexact) Set_inexactflag();
+		    }
+		}
+		continue;
+	}
+	switch(Excp_type(exception_index)) {
+	  case OVERFLOWEXCEPTION:
+	  case OVERFLOWEXCEPTION | INEXACTEXCEPTION:
+		/* check for overflow trap enabled */
+			update_trap_counts(Fpu_register, aflags, bflags, 
+					   trap_counts);
+		if (Is_overflowtrap_enabled()) {
+			update_trap_counts(Fpu_register, aflags, bflags, 
+					   trap_counts);
+			return SIGNALCODE(SIGFPE, FPE_FLTOVF);
+		} else {
+			/*
+			 * Isn't a real trap; we need to 
+			 * return the default value.
+			 */
+			target = current_ir & fivebits;
+			switch (Excp_format()) {
+			  case SGL: 
+				Sgl_setoverflow(Fpu_sgl(target));
+				break;
+			  case DBL:
+				Dbl_setoverflow(Fpu_dblp1(target),Fpu_dblp2(target));
+				break;
+			}
+			Set_overflowflag();
+			/* 
+			 * Overflow always generates an inexact
+			 * exception.  If inexact trap is enabled,
+			 * want to do an inexact trap, otherwise 
+			 * set inexact flag.
+			 */
+			if (Is_inexacttrap_enabled()) {
+				/*
+				 * Set exception field of exception
+				 * register to inexact.  Overflow
+				 * bit should be cleared.
+				 */
+				Set_exceptiontype(Fpu_register[exception_index],
+				 INEXACTEXCEPTION);
+				update_trap_counts(Fpu_register, aflags, bflags,
+					   trap_counts);
+				return SIGNALCODE(SIGFPE, FPE_FLTRES);
+			}
+			else {
+				/*
+				 * Exception register needs to be cleared.  
+				 * Inexact flag needs to be set.
+				 */
+				Clear_excp_register(exception_index);
+				Set_inexactflag();
+			}
+		}
+		break;
+	  case INVALIDEXCEPTION:
+		update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+		return SIGNALCODE(SIGFPE, FPE_FLTINV);
+	  case DIVISIONBYZEROEXCEPTION:
+		update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+	  	return SIGNALCODE(SIGFPE, FPE_FLTDIV);
+	  case INEXACTEXCEPTION:
+		update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+		return SIGNALCODE(SIGFPE, FPE_FLTRES);
+	  default:
+		update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+		printk(__FILE__ "(%d) Unknown FPU exception 0x%x\n",
+			__LINE__, Excp_type(exception_index));
+		return SIGNALCODE(SIGILL, ILL_COPROC);
+	  case NOEXCEPTION:	/* no exception */
+		/*
+		 * Clear exception register in case 
+		 * other fields are non-zero.
+		 */
+		Clear_excp_register(exception_index);
+		break;
+	}
+    }
+    /*
+     * No real exceptions occurred.
+     */
+    Clear_tbit();
+    update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+    return(NOTRAP);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/denormal.c linux-2.4.20/arch/parisc/math-emu/denormal.c
--- linux-2.4.19/arch/parisc/math-emu/denormal.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/denormal.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,135 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/fp/denormal.c		$ Revision: $
+ *
+ *  Purpose:
+ *	<<please update with a synopsis of the functionality provided by this file>>
+ *
+ *  External Interfaces:
+ *	<<the following list was autogenerated, please review>>
+ *	dbl_denormalize(dbl_opndp1,dbl_opndp2,inexactflag,rmode)
+ *	sgl_denormalize(sgl_opnd,inexactflag,rmode)
+ *
+ *  Internal Interfaces:
+ *	<<please update>>
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "hppa.h"
+#include "types.h"
+/* #include <machine/sys/mdep_private.h> */
+
+#undef Fpustatus_register
+#define Fpustatus_register Fpu_register[0]
+
+void
+sgl_denormalize(unsigned int *sgl_opnd, boolean *inexactflag, int rmode)
+{
+	unsigned int opnd;
+	int sign, exponent;
+	boolean guardbit = FALSE, stickybit, inexact;
+
+	opnd = *sgl_opnd;
+	stickybit = *inexactflag;
+        exponent = Sgl_exponent(opnd) - SGL_WRAP;
+        sign = Sgl_sign(opnd);
+	Sgl_denormalize(opnd,exponent,guardbit,stickybit,inexact);
+	if (inexact) {
+	    switch (rmode) {
+	      case ROUNDPLUS:
+		if (sign == 0) {
+			Sgl_increment(opnd);
+		}
+		break;
+	      case ROUNDMINUS:
+		if (sign != 0) {
+			Sgl_increment(opnd);
+		}
+		break;
+	      case ROUNDNEAREST:
+		if (guardbit && (stickybit || 
+		       Sgl_isone_lowmantissa(opnd))) {
+			   Sgl_increment(opnd);
+		}
+		break;
+	    }
+	}
+	Sgl_set_sign(opnd,sign);
+	*sgl_opnd = opnd;
+	*inexactflag = inexact;
+	return;
+}
+
+void
+dbl_denormalize(unsigned int *dbl_opndp1,
+	unsigned int * dbl_opndp2,
+	boolean *inexactflag,
+	int rmode)
+{
+	unsigned int opndp1, opndp2;
+	int sign, exponent;
+	boolean guardbit = FALSE, stickybit, inexact;
+
+	opndp1 = *dbl_opndp1;
+	opndp2 = *dbl_opndp2;
+	stickybit = *inexactflag;
+	exponent = Dbl_exponent(opndp1) - DBL_WRAP;
+	sign = Dbl_sign(opndp1);
+	Dbl_denormalize(opndp1,opndp2,exponent,guardbit,stickybit,inexact);
+	if (inexact) {
+	    switch (rmode) {
+	      case ROUNDPLUS:
+		if (sign == 0) {
+			Dbl_increment(opndp1,opndp2);
+		}
+		break;
+	      case ROUNDMINUS:
+		if (sign != 0) {
+			Dbl_increment(opndp1,opndp2);
+		}
+		break;
+	      case ROUNDNEAREST:
+		if (guardbit && (stickybit || 
+		       Dbl_isone_lowmantissap2(opndp2))) {
+			   Dbl_increment(opndp1,opndp2);
+		}
+		break;
+	    }
+	}
+	Dbl_set_sign(opndp1,sign);
+	*dbl_opndp1 = opndp1;
+	*dbl_opndp2 = opndp2;
+	*inexactflag = inexact;
+	return;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/dfadd.c linux-2.4.20/arch/parisc/math-emu/dfadd.c
--- linux-2.4.19/arch/parisc/math-emu/dfadd.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/dfadd.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,524 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/dfadd.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Double_add: add two double precision values.
+ *
+ *  External Interfaces:
+ *	dbl_fadd(leftptr, rightptr, dstptr, status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ * Double_add: add two double precision values.
+ */
+dbl_fadd(
+    dbl_floating_point *leftptr,
+    dbl_floating_point *rightptr,
+    dbl_floating_point *dstptr,
+    unsigned int *status)
+{
+    register unsigned int signless_upper_left, signless_upper_right, save;
+    register unsigned int leftp1, leftp2, rightp1, rightp2, extent;
+    register unsigned int resultp1 = 0, resultp2 = 0;
+    
+    register int result_exponent, right_exponent, diff_exponent;
+    register int sign_save, jumpsize;
+    register boolean inexact = FALSE;
+    register boolean underflowtrap;
+        
+    /* Create local copies of the numbers */
+    Dbl_copyfromptr(leftptr,leftp1,leftp2);
+    Dbl_copyfromptr(rightptr,rightp1,rightp2);
+
+    /* A zero "save" helps discover equal operands (for later),  *
+     * and is used in swapping operands (if needed).             */
+    Dbl_xortointp1(leftp1,rightp1,/*to*/save);
+
+    /*
+     * check first operand for NaN's or infinity
+     */
+    if ((result_exponent = Dbl_exponent(leftp1)) == DBL_INFINITY_EXPONENT)
+	{
+	if (Dbl_iszero_mantissa(leftp1,leftp2)) 
+	    {
+	    if (Dbl_isnotnan(rightp1,rightp2)) 
+		{
+		if (Dbl_isinfinity(rightp1,rightp2) && save!=0) 
+		    {
+		    /* 
+		     * invalid since operands are opposite signed infinity's
+		     */
+		    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                    Set_invalidflag();
+                    Dbl_makequietnan(resultp1,resultp2);
+		    Dbl_copytoptr(resultp1,resultp2,dstptr);
+		    return(NOEXCEPTION);
+		    }
+		/*
+	 	 * return infinity
+	 	 */
+		Dbl_copytoptr(leftp1,leftp2,dstptr);
+		return(NOEXCEPTION);
+		}
+	    }
+	else 
+	    {
+            /*
+             * is NaN; signaling or quiet?
+             */
+            if (Dbl_isone_signaling(leftp1)) 
+		{
+               	/* trap if INVALIDTRAP enabled */
+		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+        	/* make NaN quiet */
+        	Set_invalidflag();
+        	Dbl_set_quiet(leftp1);
+        	}
+	    /* 
+	     * is second operand a signaling NaN? 
+	     */
+	    else if (Dbl_is_signalingnan(rightp1)) 
+		{
+        	/* trap if INVALIDTRAP enabled */
+               	if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+		/* make NaN quiet */
+		Set_invalidflag();
+		Dbl_set_quiet(rightp1);
+		Dbl_copytoptr(rightp1,rightp2,dstptr);
+		return(NOEXCEPTION);
+		}
+	    /*
+ 	     * return quiet NaN
+ 	     */
+	    Dbl_copytoptr(leftp1,leftp2,dstptr);
+ 	    return(NOEXCEPTION);
+	    }
+	} /* End left NaN or Infinity processing */
+    /*
+     * check second operand for NaN's or infinity
+     */
+    if (Dbl_isinfinity_exponent(rightp1)) 
+	{
+	if (Dbl_iszero_mantissa(rightp1,rightp2)) 
+	    {
+	    /* return infinity */
+	    Dbl_copytoptr(rightp1,rightp2,dstptr);
+	    return(NOEXCEPTION);
+	    }
+        /*
+         * is NaN; signaling or quiet?
+         */
+        if (Dbl_isone_signaling(rightp1)) 
+	    {
+            /* trap if INVALIDTRAP enabled */
+	    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+	    /* make NaN quiet */
+	    Set_invalidflag();
+	    Dbl_set_quiet(rightp1);
+	    }
+	/*
+	 * return quiet NaN
+ 	 */
+	Dbl_copytoptr(rightp1,rightp2,dstptr);
+	return(NOEXCEPTION);
+    	} /* End right NaN or Infinity processing */
+
+    /* Invariant: Must be dealing with finite numbers */
+
+    /* Compare operands by removing the sign */
+    Dbl_copytoint_exponentmantissap1(leftp1,signless_upper_left);
+    Dbl_copytoint_exponentmantissap1(rightp1,signless_upper_right);
+
+    /* sign difference selects add or sub operation. */
+    if(Dbl_ismagnitudeless(leftp2,rightp2,signless_upper_left,signless_upper_right))
+	{
+	/* Set the left operand to the larger one by XOR swap *
+	 *  First finish the first word using "save"          */
+	Dbl_xorfromintp1(save,rightp1,/*to*/rightp1);
+	Dbl_xorfromintp1(save,leftp1,/*to*/leftp1);
+     	Dbl_swap_lower(leftp2,rightp2);
+	result_exponent = Dbl_exponent(leftp1);
+	}
+    /* Invariant:  left is not smaller than right. */ 
+
+    if((right_exponent = Dbl_exponent(rightp1)) == 0)
+        {
+	/* Denormalized operands.  First look for zeroes */
+	if(Dbl_iszero_mantissa(rightp1,rightp2)) 
+	    {
+	    /* right is zero */
+	    if(Dbl_iszero_exponentmantissa(leftp1,leftp2))
+		{
+		/* Both operands are zeros */
+		if(Is_rounding_mode(ROUNDMINUS))
+		    {
+		    Dbl_or_signs(leftp1,/*with*/rightp1);
+		    }
+		else
+		    {
+		    Dbl_and_signs(leftp1,/*with*/rightp1);
+		    }
+		}
+	    else 
+		{
+		/* Left is not a zero and must be the result.  Trapped
+		 * underflows are signaled if left is denormalized.  Result
+		 * is always exact. */
+		if( (result_exponent == 0) && Is_underflowtrap_enabled() )
+		    {
+		    /* need to normalize results mantissa */
+	    	    sign_save = Dbl_signextendedsign(leftp1);
+		    Dbl_leftshiftby1(leftp1,leftp2);
+		    Dbl_normalize(leftp1,leftp2,result_exponent);
+		    Dbl_set_sign(leftp1,/*using*/sign_save);
+                    Dbl_setwrapped_exponent(leftp1,result_exponent,unfl);
+		    Dbl_copytoptr(leftp1,leftp2,dstptr);
+		    /* inexact = FALSE */
+		    return(UNDERFLOWEXCEPTION);
+		    }
+		}
+	    Dbl_copytoptr(leftp1,leftp2,dstptr);
+	    return(NOEXCEPTION);
+	    }
+
+	/* Neither are zeroes */
+	Dbl_clear_sign(rightp1);	/* Exponent is already cleared */
+	if(result_exponent == 0 )
+	    {
+	    /* Both operands are denormalized.  The result must be exact
+	     * and is simply calculated.  A sum could become normalized and a
+	     * difference could cancel to a true zero. */
+	    if( (/*signed*/int) save < 0 )
+		{
+		Dbl_subtract(leftp1,leftp2,/*minus*/rightp1,rightp2,
+		/*into*/resultp1,resultp2);
+		if(Dbl_iszero_mantissa(resultp1,resultp2))
+		    {
+		    if(Is_rounding_mode(ROUNDMINUS))
+			{
+			Dbl_setone_sign(resultp1);
+			}
+		    else
+			{
+			Dbl_setzero_sign(resultp1);
+			}
+		    Dbl_copytoptr(resultp1,resultp2,dstptr);
+		    return(NOEXCEPTION);
+		    }
+		}
+	    else
+		{
+		Dbl_addition(leftp1,leftp2,rightp1,rightp2,
+		/*into*/resultp1,resultp2);
+		if(Dbl_isone_hidden(resultp1))
+		    {
+		    Dbl_copytoptr(resultp1,resultp2,dstptr);
+		    return(NOEXCEPTION);
+		    }
+		}
+	    if(Is_underflowtrap_enabled())
+		{
+		/* need to normalize result */
+	    	sign_save = Dbl_signextendedsign(resultp1);
+		Dbl_leftshiftby1(resultp1,resultp2);
+		Dbl_normalize(resultp1,resultp2,result_exponent);
+		Dbl_set_sign(resultp1,/*using*/sign_save);
+                Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+	        Dbl_copytoptr(resultp1,resultp2,dstptr);
+		/* inexact = FALSE */
+	        return(UNDERFLOWEXCEPTION);
+		}
+	    Dbl_copytoptr(resultp1,resultp2,dstptr);
+	    return(NOEXCEPTION);
+	    }
+	right_exponent = 1;	/* Set exponent to reflect different bias
+				 * with denomalized numbers. */
+	}
+    else
+	{
+	Dbl_clear_signexponent_set_hidden(rightp1);
+	}
+    Dbl_clear_exponent_set_hidden(leftp1);
+    diff_exponent = result_exponent - right_exponent;
+
+    /* 
+     * Special case alignment of operands that would force alignment 
+     * beyond the extent of the extension.  A further optimization
+     * could special case this but only reduces the path length for this
+     * infrequent case.
+     */
+    if(diff_exponent > DBL_THRESHOLD)
+	{
+	diff_exponent = DBL_THRESHOLD;
+	}
+    
+    /* Align right operand by shifting to right */
+    Dbl_right_align(/*operand*/rightp1,rightp2,/*shifted by*/diff_exponent,
+    /*and lower to*/extent);
+
+    /* Treat sum and difference of the operands separately. */
+    if( (/*signed*/int) save < 0 )
+	{
+	/*
+	 * Difference of the two operands.  Their can be no overflow.  A
+	 * borrow can occur out of the hidden bit and force a post
+	 * normalization phase.
+	 */
+	Dbl_subtract_withextension(leftp1,leftp2,/*minus*/rightp1,rightp2,
+	/*with*/extent,/*into*/resultp1,resultp2);
+	if(Dbl_iszero_hidden(resultp1))
+	    {
+	    /* Handle normalization */
+	    /* A straight foward algorithm would now shift the result
+	     * and extension left until the hidden bit becomes one.  Not
+	     * all of the extension bits need participate in the shift.
+	     * Only the two most significant bits (round and guard) are
+	     * needed.  If only a single shift is needed then the guard
+	     * bit becomes a significant low order bit and the extension
+	     * must participate in the rounding.  If more than a single 
+	     * shift is needed, then all bits to the right of the guard 
+	     * bit are zeros, and the guard bit may or may not be zero. */
+	    sign_save = Dbl_signextendedsign(resultp1);
+            Dbl_leftshiftby1_withextent(resultp1,resultp2,extent,resultp1,resultp2);
+
+            /* Need to check for a zero result.  The sign and exponent
+	     * fields have already been zeroed.  The more efficient test
+	     * of the full object can be used.
+	     */
+    	    if(Dbl_iszero(resultp1,resultp2))
+		/* Must have been "x-x" or "x+(-x)". */
+		{
+		if(Is_rounding_mode(ROUNDMINUS)) Dbl_setone_sign(resultp1);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+		}
+	    result_exponent--;
+	    /* Look to see if normalization is finished. */
+	    if(Dbl_isone_hidden(resultp1))
+		{
+		if(result_exponent==0)
+		    {
+		    /* Denormalized, exponent should be zero.  Left operand *
+		     * was normalized, so extent (guard, round) was zero    */
+		    goto underflow;
+		    }
+		else
+		    {
+		    /* No further normalization is needed. */
+		    Dbl_set_sign(resultp1,/*using*/sign_save);
+	    	    Ext_leftshiftby1(extent);
+		    goto round;
+		    }
+		}
+
+	    /* Check for denormalized, exponent should be zero.  Left    *
+	     * operand was normalized, so extent (guard, round) was zero */
+	    if(!(underflowtrap = Is_underflowtrap_enabled()) &&
+	       result_exponent==0) goto underflow;
+
+	    /* Shift extension to complete one bit of normalization and
+	     * update exponent. */
+	    Ext_leftshiftby1(extent);
+
+	    /* Discover first one bit to determine shift amount.  Use a
+	     * modified binary search.  We have already shifted the result
+	     * one position right and still not found a one so the remainder
+	     * of the extension must be zero and simplifies rounding. */
+	    /* Scan bytes */
+	    while(Dbl_iszero_hiddenhigh7mantissa(resultp1))
+		{
+		Dbl_leftshiftby8(resultp1,resultp2);
+		if((result_exponent -= 8) <= 0  && !underflowtrap)
+		    goto underflow;
+		}
+	    /* Now narrow it down to the nibble */
+	    if(Dbl_iszero_hiddenhigh3mantissa(resultp1))
+		{
+		/* The lower nibble contains the normalizing one */
+		Dbl_leftshiftby4(resultp1,resultp2);
+		if((result_exponent -= 4) <= 0 && !underflowtrap)
+		    goto underflow;
+		}
+	    /* Select case were first bit is set (already normalized)
+	     * otherwise select the proper shift. */
+	    if((jumpsize = Dbl_hiddenhigh3mantissa(resultp1)) > 7)
+		{
+		/* Already normalized */
+		if(result_exponent <= 0) goto underflow;
+		Dbl_set_sign(resultp1,/*using*/sign_save);
+		Dbl_set_exponent(resultp1,/*using*/result_exponent);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+		}
+	    Dbl_sethigh4bits(resultp1,/*using*/sign_save);
+	    switch(jumpsize) 
+		{
+		case 1:
+		    {
+		    Dbl_leftshiftby3(resultp1,resultp2);
+		    result_exponent -= 3;
+		    break;
+		    }
+		case 2:
+		case 3:
+		    {
+		    Dbl_leftshiftby2(resultp1,resultp2);
+		    result_exponent -= 2;
+		    break;
+		    }
+		case 4:
+		case 5:
+		case 6:
+		case 7:
+		    {
+		    Dbl_leftshiftby1(resultp1,resultp2);
+		    result_exponent -= 1;
+		    break;
+		    }
+		}
+	    if(result_exponent > 0) 
+		{
+		Dbl_set_exponent(resultp1,/*using*/result_exponent);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION); 	/* Sign bit is already set */
+		}
+	    /* Fixup potential underflows */
+	  underflow:
+	    if(Is_underflowtrap_enabled())
+		{
+		Dbl_set_sign(resultp1,sign_save);
+                Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		/* inexact = FALSE */
+		return(UNDERFLOWEXCEPTION);
+		}
+	    /* 
+	     * Since we cannot get an inexact denormalized result,
+	     * we can now return.
+	     */
+	    Dbl_fix_overshift(resultp1,resultp2,(1-result_exponent),extent);
+	    Dbl_clear_signexponent(resultp1);
+	    Dbl_set_sign(resultp1,sign_save);
+	    Dbl_copytoptr(resultp1,resultp2,dstptr);
+	    return(NOEXCEPTION);
+	    } /* end if(hidden...)... */
+	/* Fall through and round */
+	} /* end if(save < 0)... */
+    else 
+	{
+	/* Add magnitudes */
+	Dbl_addition(leftp1,leftp2,rightp1,rightp2,/*to*/resultp1,resultp2);
+	if(Dbl_isone_hiddenoverflow(resultp1))
+	    {
+	    /* Prenormalization required. */
+	    Dbl_rightshiftby1_withextent(resultp2,extent,extent);
+	    Dbl_arithrightshiftby1(resultp1,resultp2);
+	    result_exponent++;
+	    } /* end if hiddenoverflow... */
+	} /* end else ...add magnitudes... */
+    
+    /* Round the result.  If the extension is all zeros,then the result is
+     * exact.  Otherwise round in the correct direction.  No underflow is
+     * possible. If a postnormalization is necessary, then the mantissa is
+     * all zeros so no shift is needed. */
+  round:
+    if(Ext_isnotzero(extent))
+	{
+	inexact = TRUE;
+	switch(Rounding_mode())
+	    {
+	    case ROUNDNEAREST: /* The default. */
+	    if(Ext_isone_sign(extent))
+		{
+		/* at least 1/2 ulp */
+		if(Ext_isnotzero_lower(extent)  ||
+		  Dbl_isone_lowmantissap2(resultp2))
+		    {
+		    /* either exactly half way and odd or more than 1/2ulp */
+		    Dbl_increment(resultp1,resultp2);
+		    }
+		}
+	    break;
+
+	    case ROUNDPLUS:
+	    if(Dbl_iszero_sign(resultp1))
+		{
+		/* Round up positive results */
+		Dbl_increment(resultp1,resultp2);
+		}
+	    break;
+	    
+	    case ROUNDMINUS:
+	    if(Dbl_isone_sign(resultp1))
+		{
+		/* Round down negative results */
+		Dbl_increment(resultp1,resultp2);
+		}
+	    
+	    case ROUNDZERO:;
+	    /* truncate is simple */
+	    } /* end switch... */
+	if(Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
+	}
+    if(result_exponent == DBL_INFINITY_EXPONENT)
+        {
+        /* Overflow */
+        if(Is_overflowtrap_enabled())
+	    {
+	    Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+	    Dbl_copytoptr(resultp1,resultp2,dstptr);
+	    if (inexact)
+		if (Is_inexacttrap_enabled())
+			return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+		else Set_inexactflag();
+	    return(OVERFLOWEXCEPTION);
+	    }
+        else
+	    {
+	    inexact = TRUE;
+	    Set_overflowflag();
+	    Dbl_setoverflow(resultp1,resultp2);
+	    }
+	}
+    else Dbl_set_exponent(resultp1,result_exponent);
+    Dbl_copytoptr(resultp1,resultp2,dstptr);
+    if(inexact) 
+	if(Is_inexacttrap_enabled())
+	    return(INEXACTEXCEPTION);
+	else Set_inexactflag();
+    return(NOEXCEPTION);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/dfcmp.c linux-2.4.20/arch/parisc/math-emu/dfcmp.c
--- linux-2.4.19/arch/parisc/math-emu/dfcmp.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/dfcmp.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,181 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/dfcmp.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	dbl_cmp: compare two values
+ *
+ *  External Interfaces:
+ *	dbl_fcmp(leftptr, rightptr, cond, status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+
+#include "float.h"
+#include "dbl_float.h"
+    
+/*
+ * dbl_cmp: compare two values
+ */
+int
+dbl_fcmp (dbl_floating_point * leftptr, dbl_floating_point * rightptr,
+	  unsigned int cond, unsigned int *status)
+                                           
+                       /* The predicate to be tested */
+                         
+    {
+    register unsigned int leftp1, leftp2, rightp1, rightp2;
+    register int xorresult;
+        
+    /* Create local copies of the numbers */
+    Dbl_copyfromptr(leftptr,leftp1,leftp2);
+    Dbl_copyfromptr(rightptr,rightp1,rightp2);
+    /*
+     * Test for NaN
+     */
+    if(    (Dbl_exponent(leftp1) == DBL_INFINITY_EXPONENT)
+        || (Dbl_exponent(rightp1) == DBL_INFINITY_EXPONENT) )
+	{
+	/* Check if a NaN is involved.  Signal an invalid exception when 
+	 * comparing a signaling NaN or when comparing quiet NaNs and the
+	 * low bit of the condition is set */
+        if( ((Dbl_exponent(leftp1) == DBL_INFINITY_EXPONENT)
+	    && Dbl_isnotzero_mantissa(leftp1,leftp2) 
+	    && (Exception(cond) || Dbl_isone_signaling(leftp1)))
+	   ||
+	    ((Dbl_exponent(rightp1) == DBL_INFINITY_EXPONENT)
+	    && Dbl_isnotzero_mantissa(rightp1,rightp2) 
+	    && (Exception(cond) || Dbl_isone_signaling(rightp1))) )
+	    {
+	    if( Is_invalidtrap_enabled() ) {
+	    	Set_status_cbit(Unordered(cond));
+		return(INVALIDEXCEPTION);
+	    }
+	    else Set_invalidflag();
+	    Set_status_cbit(Unordered(cond));
+	    return(NOEXCEPTION);
+	    }
+	/* All the exceptional conditions are handled, now special case
+	   NaN compares */
+        else if( ((Dbl_exponent(leftp1) == DBL_INFINITY_EXPONENT)
+	    && Dbl_isnotzero_mantissa(leftp1,leftp2))
+	   ||
+	    ((Dbl_exponent(rightp1) == DBL_INFINITY_EXPONENT)
+	    && Dbl_isnotzero_mantissa(rightp1,rightp2)) )
+	    {
+	    /* NaNs always compare unordered. */
+	    Set_status_cbit(Unordered(cond));
+	    return(NOEXCEPTION);
+	    }
+	/* infinities will drop down to the normal compare mechanisms */
+	}
+    /* First compare for unequal signs => less or greater or
+     * special equal case */
+    Dbl_xortointp1(leftp1,rightp1,xorresult);
+    if( xorresult < 0 )
+        {
+        /* left negative => less, left positive => greater.
+         * equal is possible if both operands are zeros. */
+        if( Dbl_iszero_exponentmantissa(leftp1,leftp2) 
+	  && Dbl_iszero_exponentmantissa(rightp1,rightp2) )
+            {
+	    Set_status_cbit(Equal(cond));
+	    }
+	else if( Dbl_isone_sign(leftp1) )
+	    {
+	    Set_status_cbit(Lessthan(cond));
+	    }
+	else
+	    {
+	    Set_status_cbit(Greaterthan(cond));
+	    }
+        }
+    /* Signs are the same.  Treat negative numbers separately
+     * from the positives because of the reversed sense.  */
+    else if(Dbl_isequal(leftp1,leftp2,rightp1,rightp2))
+        {
+        Set_status_cbit(Equal(cond));
+        }
+    else if( Dbl_iszero_sign(leftp1) )
+        {
+        /* Positive compare */
+	if( Dbl_allp1(leftp1) < Dbl_allp1(rightp1) )
+	    {
+	    Set_status_cbit(Lessthan(cond));
+	    }
+	else if( Dbl_allp1(leftp1) > Dbl_allp1(rightp1) )
+	    {
+	    Set_status_cbit(Greaterthan(cond));
+	    }
+	else
+	    {
+	    /* Equal first parts.  Now we must use unsigned compares to
+	     * resolve the two possibilities. */
+	    if( Dbl_allp2(leftp2) < Dbl_allp2(rightp2) )
+		{
+		Set_status_cbit(Lessthan(cond));
+		}
+	    else 
+		{
+		Set_status_cbit(Greaterthan(cond));
+		}
+	    }
+	}
+    else
+        {
+        /* Negative compare.  Signed or unsigned compares
+         * both work the same.  That distinction is only
+         * important when the sign bits differ. */
+	if( Dbl_allp1(leftp1) > Dbl_allp1(rightp1) )
+	    {
+	    Set_status_cbit(Lessthan(cond));
+	    }
+	else if( Dbl_allp1(leftp1) < Dbl_allp1(rightp1) )
+	    {
+	    Set_status_cbit(Greaterthan(cond));
+	    }
+	else
+	    {
+	    /* Equal first parts.  Now we must use unsigned compares to
+	     * resolve the two possibilities. */
+	    if( Dbl_allp2(leftp2) > Dbl_allp2(rightp2) )
+		{
+		Set_status_cbit(Lessthan(cond));
+		}
+	    else 
+		{
+		Set_status_cbit(Greaterthan(cond));
+		}
+	    }
+        }
+	return(NOEXCEPTION);
+    }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/dfdiv.c linux-2.4.20/arch/parisc/math-emu/dfdiv.c
--- linux-2.4.19/arch/parisc/math-emu/dfdiv.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/dfdiv.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,400 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/dfdiv.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Double Precision Floating-point Divide
+ *
+ *  External Interfaces:
+ *	dbl_fdiv(srcptr1,srcptr2,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ *  Double Precision Floating-point Divide
+ */
+
+int
+dbl_fdiv (dbl_floating_point * srcptr1, dbl_floating_point * srcptr2,
+	  dbl_floating_point * dstptr, unsigned int *status)
+{
+	register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2;
+	register unsigned int opnd3p1, opnd3p2, resultp1, resultp2;
+	register int dest_exponent, count;
+	register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
+	boolean is_tiny;
+
+	Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2);
+	Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2);
+	/* 
+	 * set sign bit of result 
+	 */
+	if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1)) 
+		Dbl_setnegativezerop1(resultp1);  
+	else Dbl_setzerop1(resultp1);
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd1p1)) {
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			if (Dbl_isnotnan(opnd2p1,opnd2p2)) {
+				if (Dbl_isinfinity(opnd2p1,opnd2p2)) {
+					/* 
+					 * invalid since both operands 
+					 * are infinity 
+					 */
+					if (Is_invalidtrap_enabled())
+                                		return(INVALIDEXCEPTION);
+                                	Set_invalidflag();
+                                	Dbl_makequietnan(resultp1,resultp2);
+					Dbl_copytoptr(resultp1,resultp2,dstptr);
+					return(NOEXCEPTION);
+				}
+				/*
+			 	 * return infinity
+			 	 */
+				Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+                	/*
+                 	 * is NaN; signaling or quiet?
+                 	 */
+                	if (Dbl_isone_signaling(opnd1p1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled())
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Dbl_set_quiet(opnd1p1);
+                	}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd2p1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled())
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Dbl_set_quiet(opnd2p1);
+				Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+                		return(NOEXCEPTION);
+			}
+                	/*
+                 	 * return quiet NaN
+                 	 */
+			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+                	return(NOEXCEPTION);
+		}
+	}
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd2p1)) {
+		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+			/*
+			 * return zero
+			 */
+			Dbl_setzero_exponentmantissa(resultp1,resultp2);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+                /*
+                 * is NaN; signaling or quiet?
+                 */
+                if (Dbl_isone_signaling(opnd2p1)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Dbl_set_quiet(opnd2p1);
+                }
+                /*
+                 * return quiet NaN
+                 */
+		Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+                return(NOEXCEPTION);
+	}
+        /*
+         * check for division by zero
+         */
+        if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
+                if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
+                        /* invalid since both operands are zero */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        Set_invalidflag();
+                        Dbl_makequietnan(resultp1,resultp2);
+                        Dbl_copytoptr(resultp1,resultp2,dstptr);
+                        return(NOEXCEPTION);
+                }
+                if (Is_divisionbyzerotrap_enabled())
+                       	return(DIVISIONBYZEROEXCEPTION);
+                Set_divisionbyzeroflag();
+                Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+                Dbl_copytoptr(resultp1,resultp2,dstptr);
+                return(NOEXCEPTION);
+        }
+	/*
+	 * Generate exponent 
+	 */
+	dest_exponent = Dbl_exponent(opnd1p1) - Dbl_exponent(opnd2p1) + DBL_BIAS;
+
+	/*
+	 * Generate mantissa
+	 */
+	if (Dbl_isnotzero_exponent(opnd1p1)) {
+		/* set hidden bit */
+		Dbl_clear_signexponent_set_hidden(opnd1p1);
+	}
+	else {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			Dbl_setzero_exponentmantissa(resultp1,resultp2);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+                /* is denormalized, want to normalize */
+                Dbl_clear_signexponent(opnd1p1);
+                Dbl_leftshiftby1(opnd1p1,opnd1p2);
+		Dbl_normalize(opnd1p1,opnd1p2,dest_exponent);
+	}
+	/* opnd2 needs to have hidden bit set with msb in hidden bit */
+	if (Dbl_isnotzero_exponent(opnd2p1)) {
+		Dbl_clear_signexponent_set_hidden(opnd2p1);
+	}
+	else {
+                /* is denormalized; want to normalize */
+                Dbl_clear_signexponent(opnd2p1);
+                Dbl_leftshiftby1(opnd2p1,opnd2p2);
+                while (Dbl_iszero_hiddenhigh7mantissa(opnd2p1)) {
+                        dest_exponent+=8;
+                        Dbl_leftshiftby8(opnd2p1,opnd2p2);
+                }
+                if (Dbl_iszero_hiddenhigh3mantissa(opnd2p1)) {
+                        dest_exponent+=4;
+                        Dbl_leftshiftby4(opnd2p1,opnd2p2);
+                }
+                while (Dbl_iszero_hidden(opnd2p1)) {
+                        dest_exponent++;
+                        Dbl_leftshiftby1(opnd2p1,opnd2p2);
+                }
+	}
+
+	/* Divide the source mantissas */
+
+	/* 
+	 * A non-restoring divide algorithm is used.
+	 */
+	Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
+	Dbl_setzero(opnd3p1,opnd3p2);
+	for (count=1; count <= DBL_P && (opnd1p1 || opnd1p2); count++) {
+		Dbl_leftshiftby1(opnd1p1,opnd1p2);
+		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+		if (Dbl_iszero_sign(opnd1p1)) {
+			Dbl_setone_lowmantissap2(opnd3p2);
+			Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
+		}
+		else {
+			Twoword_add(opnd1p1, opnd1p2, opnd2p1, opnd2p2);
+		}
+	}
+	if (count <= DBL_P) {
+		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+		Dbl_setone_lowmantissap2(opnd3p2);
+		Dbl_leftshift(opnd3p1,opnd3p2,(DBL_P-count));
+		if (Dbl_iszero_hidden(opnd3p1)) {
+			Dbl_leftshiftby1(opnd3p1,opnd3p2);
+			dest_exponent--;
+		}
+	}
+	else {
+		if (Dbl_iszero_hidden(opnd3p1)) {
+			/* need to get one more bit of result */
+			Dbl_leftshiftby1(opnd1p1,opnd1p2);
+			Dbl_leftshiftby1(opnd3p1,opnd3p2);
+			if (Dbl_iszero_sign(opnd1p1)) {
+				Dbl_setone_lowmantissap2(opnd3p2);
+				Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
+			}
+			else {
+				Twoword_add(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
+			}
+			dest_exponent--;
+		}
+		if (Dbl_iszero_sign(opnd1p1)) guardbit = TRUE;
+		stickybit = Dbl_allp1(opnd1p1) || Dbl_allp2(opnd1p2);
+	}
+	inexact = guardbit | stickybit;
+
+	/* 
+	 * round result 
+	 */
+	if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) {
+		Dbl_clear_signexponent(opnd3p1);
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Dbl_iszero_sign(resultp1)) 
+					Dbl_increment(opnd3p1,opnd3p2);
+				break;
+			case ROUNDMINUS: 
+				if (Dbl_isone_sign(resultp1)) 
+					Dbl_increment(opnd3p1,opnd3p2);
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Dbl_isone_lowmantissap2(opnd3p2))) {
+			      		Dbl_increment(opnd3p1,opnd3p2);
+				}
+		}
+		if (Dbl_isone_hidden(opnd3p1)) dest_exponent++;
+	}
+	Dbl_set_mantissa(resultp1,resultp2,opnd3p1,opnd3p2);
+
+        /* 
+         * Test for overflow
+         */
+	if (dest_exponent >= DBL_INFINITY_EXPONENT) {
+                /* trap if OVERFLOWTRAP enabled */
+                if (Is_overflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Dbl_setwrapped_exponent(resultp1,dest_exponent,ovfl);
+                        Dbl_copytoptr(resultp1,resultp2,dstptr);
+                        if (inexact) 
+                            if (Is_inexacttrap_enabled())
+                                return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+                            else Set_inexactflag();
+                        return(OVERFLOWEXCEPTION);
+                }
+		Set_overflowflag();
+                /* set result to infinity or largest number */
+		Dbl_setoverflow(resultp1,resultp2);
+		inexact = TRUE;
+	}
+        /* 
+         * Test for underflow
+         */
+	else if (dest_exponent <= 0) {
+                /* trap if UNDERFLOWTRAP enabled */
+                if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl);
+                        Dbl_copytoptr(resultp1,resultp2,dstptr);
+                        if (inexact) 
+                            if (Is_inexacttrap_enabled())
+                                return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
+                            else Set_inexactflag();
+                        return(UNDERFLOWEXCEPTION);
+                }
+
+		/* Determine if should set underflow flag */
+		is_tiny = TRUE;
+		if (dest_exponent == 0 && inexact) {
+			switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Dbl_iszero_sign(resultp1)) {
+					Dbl_increment(opnd3p1,opnd3p2);
+					if (Dbl_isone_hiddenoverflow(opnd3p1))
+                			    is_tiny = FALSE;
+					Dbl_decrement(opnd3p1,opnd3p2);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Dbl_isone_sign(resultp1)) {
+					Dbl_increment(opnd3p1,opnd3p2);
+					if (Dbl_isone_hiddenoverflow(opnd3p1))
+                			    is_tiny = FALSE;
+					Dbl_decrement(opnd3p1,opnd3p2);
+				}
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Dbl_isone_lowmantissap2(opnd3p2))) {
+				      	Dbl_increment(opnd3p1,opnd3p2);
+					if (Dbl_isone_hiddenoverflow(opnd3p1))
+                			    is_tiny = FALSE;
+					Dbl_decrement(opnd3p1,opnd3p2);
+				}
+				break;
+			}
+		}
+
+                /*
+                 * denormalize result or set to signed zero
+                 */
+		stickybit = inexact;
+		Dbl_denormalize(opnd3p1,opnd3p2,dest_exponent,guardbit,
+		 stickybit,inexact);
+
+		/* return rounded number */ 
+		if (inexact) {
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				if (Dbl_iszero_sign(resultp1)) {
+					Dbl_increment(opnd3p1,opnd3p2);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Dbl_isone_sign(resultp1)) {
+					Dbl_increment(opnd3p1,opnd3p2);
+				}
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Dbl_isone_lowmantissap2(opnd3p2))) {
+			      		Dbl_increment(opnd3p1,opnd3p2);
+				}
+				break;
+			}
+                	if (is_tiny) Set_underflowflag();
+                }
+		Dbl_set_exponentmantissa(resultp1,resultp2,opnd3p1,opnd3p2);
+	}
+	else Dbl_set_exponent(resultp1,dest_exponent);
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+
+	/* check for inexact */
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/dfmpy.c linux-2.4.20/arch/parisc/math-emu/dfmpy.c
--- linux-2.4.19/arch/parisc/math-emu/dfmpy.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/dfmpy.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,394 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/dfmpy.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Double Precision Floating-point Multiply
+ *
+ *  External Interfaces:
+ *	dbl_fmpy(srcptr1,srcptr2,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ *  Double Precision Floating-point Multiply
+ */
+
+int
+dbl_fmpy(
+	    dbl_floating_point *srcptr1,
+	    dbl_floating_point *srcptr2,
+	    dbl_floating_point *dstptr,
+	    unsigned int *status)
+{
+	register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2;
+	register unsigned int opnd3p1, opnd3p2, resultp1, resultp2;
+	register int dest_exponent, count;
+	register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
+	boolean is_tiny;
+
+	Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2);
+	Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2);
+
+	/* 
+	 * set sign bit of result 
+	 */
+	if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1)) 
+		Dbl_setnegativezerop1(resultp1); 
+	else Dbl_setzerop1(resultp1);
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd1p1)) {
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			if (Dbl_isnotnan(opnd2p1,opnd2p2)) {
+				if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
+					/* 
+					 * invalid since operands are infinity 
+					 * and zero 
+					 */
+					if (Is_invalidtrap_enabled())
+                                		return(INVALIDEXCEPTION);
+                                	Set_invalidflag();
+                                	Dbl_makequietnan(resultp1,resultp2);
+					Dbl_copytoptr(resultp1,resultp2,dstptr);
+					return(NOEXCEPTION);
+				}
+				/*
+			 	 * return infinity
+			 	 */
+				Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+                	/*
+                 	 * is NaN; signaling or quiet?
+                 	 */
+                	if (Dbl_isone_signaling(opnd1p1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled()) 
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Dbl_set_quiet(opnd1p1);
+                	}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd2p1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled())
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Dbl_set_quiet(opnd2p1);
+				Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+                		return(NOEXCEPTION);
+			}
+                	/*
+                 	 * return quiet NaN
+                 	 */
+			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+                	return(NOEXCEPTION);
+		}
+	}
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd2p1)) {
+		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+			if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
+				/* invalid since operands are zero & infinity */
+				if (Is_invalidtrap_enabled())
+                                	return(INVALIDEXCEPTION);
+                                Set_invalidflag();
+                                Dbl_makequietnan(opnd2p1,opnd2p2);
+				Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+				return(NOEXCEPTION);
+			}
+			/*
+			 * return infinity
+			 */
+			Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+                /*
+                 * is NaN; signaling or quiet?
+                 */
+                if (Dbl_isone_signaling(opnd2p1)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Dbl_set_quiet(opnd2p1);
+                }
+                /*
+                 * return quiet NaN
+                 */
+		Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+                return(NOEXCEPTION);
+	}
+	/*
+	 * Generate exponent 
+	 */
+	dest_exponent = Dbl_exponent(opnd1p1) + Dbl_exponent(opnd2p1) -DBL_BIAS;
+
+	/*
+	 * Generate mantissa
+	 */
+	if (Dbl_isnotzero_exponent(opnd1p1)) {
+		/* set hidden bit */
+		Dbl_clear_signexponent_set_hidden(opnd1p1);
+	}
+	else {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			Dbl_setzero_exponentmantissa(resultp1,resultp2);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+                /* is denormalized, adjust exponent */
+                Dbl_clear_signexponent(opnd1p1);
+                Dbl_leftshiftby1(opnd1p1,opnd1p2);
+		Dbl_normalize(opnd1p1,opnd1p2,dest_exponent);
+	}
+	/* opnd2 needs to have hidden bit set with msb in hidden bit */
+	if (Dbl_isnotzero_exponent(opnd2p1)) {
+		Dbl_clear_signexponent_set_hidden(opnd2p1);
+	}
+	else {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+			Dbl_setzero_exponentmantissa(resultp1,resultp2);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+                /* is denormalized; want to normalize */
+                Dbl_clear_signexponent(opnd2p1);
+                Dbl_leftshiftby1(opnd2p1,opnd2p2);
+		Dbl_normalize(opnd2p1,opnd2p2,dest_exponent);
+	}
+
+	/* Multiply two source mantissas together */
+
+	/* make room for guard bits */
+	Dbl_leftshiftby7(opnd2p1,opnd2p2);
+	Dbl_setzero(opnd3p1,opnd3p2);
+        /* 
+         * Four bits at a time are inspected in each loop, and a 
+         * simple shift and add multiply algorithm is used. 
+         */ 
+	for (count=1;count<=DBL_P;count+=4) {
+		stickybit |= Dlow4p2(opnd3p2);
+		Dbl_rightshiftby4(opnd3p1,opnd3p2);
+		if (Dbit28p2(opnd1p2)) {
+	 		/* Twoword_add should be an ADDC followed by an ADD. */
+                        Twoword_add(opnd3p1, opnd3p2, opnd2p1<<3 | opnd2p2>>29, 
+				    opnd2p2<<3);
+		}
+		if (Dbit29p2(opnd1p2)) {
+                        Twoword_add(opnd3p1, opnd3p2, opnd2p1<<2 | opnd2p2>>30, 
+				    opnd2p2<<2);
+		}
+		if (Dbit30p2(opnd1p2)) {
+                        Twoword_add(opnd3p1, opnd3p2, opnd2p1<<1 | opnd2p2>>31,
+				    opnd2p2<<1);
+		}
+		if (Dbit31p2(opnd1p2)) {
+                        Twoword_add(opnd3p1, opnd3p2, opnd2p1, opnd2p2);
+		}
+		Dbl_rightshiftby4(opnd1p1,opnd1p2);
+	}
+	if (Dbit3p1(opnd3p1)==0) {
+		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+	}
+	else {
+		/* result mantissa >= 2. */
+		dest_exponent++;
+	}
+	/* check for denormalized result */
+	while (Dbit3p1(opnd3p1)==0) {
+		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+		dest_exponent--;
+	}
+	/*
+	 * check for guard, sticky and inexact bits 
+	 */
+	stickybit |= Dallp2(opnd3p2) << 25;
+	guardbit = (Dallp2(opnd3p2) << 24) >> 31;
+	inexact = guardbit | stickybit;
+
+	/* align result mantissa */
+	Dbl_rightshiftby8(opnd3p1,opnd3p2);
+
+	/* 
+	 * round result 
+	 */
+	if (inexact && (dest_exponent>0 || Is_underflowtrap_enabled())) {
+		Dbl_clear_signexponent(opnd3p1);
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Dbl_iszero_sign(resultp1)) 
+					Dbl_increment(opnd3p1,opnd3p2);
+				break;
+			case ROUNDMINUS: 
+				if (Dbl_isone_sign(resultp1)) 
+					Dbl_increment(opnd3p1,opnd3p2);
+				break;
+			case ROUNDNEAREST:
+				if (guardbit) {
+			   	if (stickybit || Dbl_isone_lowmantissap2(opnd3p2))
+			      	Dbl_increment(opnd3p1,opnd3p2);
+				}
+		}
+		if (Dbl_isone_hidden(opnd3p1)) dest_exponent++;
+	}
+	Dbl_set_mantissa(resultp1,resultp2,opnd3p1,opnd3p2);
+
+        /* 
+         * Test for overflow
+         */
+	if (dest_exponent >= DBL_INFINITY_EXPONENT) {
+                /* trap if OVERFLOWTRAP enabled */
+                if (Is_overflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+			Dbl_setwrapped_exponent(resultp1,dest_exponent,ovfl);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			if (inexact) 
+			    if (Is_inexacttrap_enabled())
+				return (OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+			    else Set_inexactflag();
+			return (OVERFLOWEXCEPTION);
+                }
+		inexact = TRUE;
+		Set_overflowflag();
+                /* set result to infinity or largest number */
+		Dbl_setoverflow(resultp1,resultp2);
+	}
+        /* 
+         * Test for underflow
+         */
+	else if (dest_exponent <= 0) {
+                /* trap if UNDERFLOWTRAP enabled */
+                if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+			Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			if (inexact) 
+			    if (Is_inexacttrap_enabled())
+				return (UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
+			    else Set_inexactflag();
+			return (UNDERFLOWEXCEPTION);
+                }
+
+		/* Determine if should set underflow flag */
+		is_tiny = TRUE;
+		if (dest_exponent == 0 && inexact) {
+			switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Dbl_iszero_sign(resultp1)) {
+					Dbl_increment(opnd3p1,opnd3p2);
+					if (Dbl_isone_hiddenoverflow(opnd3p1))
+                			    is_tiny = FALSE;
+					Dbl_decrement(opnd3p1,opnd3p2);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Dbl_isone_sign(resultp1)) {
+					Dbl_increment(opnd3p1,opnd3p2);
+					if (Dbl_isone_hiddenoverflow(opnd3p1))
+                			    is_tiny = FALSE;
+					Dbl_decrement(opnd3p1,opnd3p2);
+				}
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Dbl_isone_lowmantissap2(opnd3p2))) {
+				      	Dbl_increment(opnd3p1,opnd3p2);
+					if (Dbl_isone_hiddenoverflow(opnd3p1))
+                			    is_tiny = FALSE;
+					Dbl_decrement(opnd3p1,opnd3p2);
+				}
+				break;
+			}
+		}
+
+		/*
+		 * denormalize result or set to signed zero
+		 */
+		stickybit = inexact;
+		Dbl_denormalize(opnd3p1,opnd3p2,dest_exponent,guardbit,
+		 stickybit,inexact);
+
+		/* return zero or smallest number */
+		if (inexact) {
+			switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Dbl_iszero_sign(resultp1)) {
+					Dbl_increment(opnd3p1,opnd3p2);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Dbl_isone_sign(resultp1)) {
+					Dbl_increment(opnd3p1,opnd3p2);
+				}
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Dbl_isone_lowmantissap2(opnd3p2))) {
+			      		Dbl_increment(opnd3p1,opnd3p2);
+				}
+				break;
+			}
+                	if (is_tiny) Set_underflowflag();
+		}
+		Dbl_set_exponentmantissa(resultp1,resultp2,opnd3p1,opnd3p2);
+	}
+	else Dbl_set_exponent(resultp1,dest_exponent);
+	/* check for inexact */
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/dfrem.c linux-2.4.20/arch/parisc/math-emu/dfrem.c
--- linux-2.4.19/arch/parisc/math-emu/dfrem.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/dfrem.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,297 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/dfrem.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Double Precision Floating-point Remainder
+ *
+ *  External Interfaces:
+ *	dbl_frem(srcptr1,srcptr2,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ *  Double Precision Floating-point Remainder
+ */
+
+int
+dbl_frem (dbl_floating_point * srcptr1, dbl_floating_point * srcptr2,
+	  dbl_floating_point * dstptr, unsigned int *status)
+{
+	register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2;
+	register unsigned int resultp1, resultp2;
+	register int opnd1_exponent, opnd2_exponent, dest_exponent, stepcount;
+	register boolean roundup = FALSE;
+
+	Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2);
+	Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2);
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if ((opnd1_exponent = Dbl_exponent(opnd1p1)) == DBL_INFINITY_EXPONENT) {
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			if (Dbl_isnotnan(opnd2p1,opnd2p2)) {
+				/* invalid since first operand is infinity */
+				if (Is_invalidtrap_enabled()) 
+                                	return(INVALIDEXCEPTION);
+                                Set_invalidflag();
+                                Dbl_makequietnan(resultp1,resultp2);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+                	/*
+                 	 * is NaN; signaling or quiet?
+                 	 */
+                	if (Dbl_isone_signaling(opnd1p1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled()) 
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Dbl_set_quiet(opnd1p1);
+                	}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd2p1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled()) 
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Dbl_set_quiet(opnd2p1);
+				Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+                		return(NOEXCEPTION);
+			}
+                	/*
+                 	 * return quiet NaN
+                 	 */
+			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+                	return(NOEXCEPTION);
+		}
+	} 
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if ((opnd2_exponent = Dbl_exponent(opnd2p1)) == DBL_INFINITY_EXPONENT) {
+		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+			/*
+			 * return first operand
+			 */
+			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+			return(NOEXCEPTION);
+		}
+                /*
+                 * is NaN; signaling or quiet?
+                 */
+                if (Dbl_isone_signaling(opnd2p1)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Dbl_set_quiet(opnd2p1);
+                }
+                /*
+                 * return quiet NaN
+                 */
+		Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+                return(NOEXCEPTION);
+	}
+	/*
+	 * check second operand for zero
+	 */
+	if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
+		/* invalid since second operand is zero */
+		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                Set_invalidflag();
+                Dbl_makequietnan(resultp1,resultp2);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+
+	/* 
+	 * get sign of result
+	 */
+	resultp1 = opnd1p1;  
+
+	/* 
+	 * check for denormalized operands
+	 */
+	if (opnd1_exponent == 0) {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* normalize, then continue */
+		opnd1_exponent = 1;
+		Dbl_normalize(opnd1p1,opnd1p2,opnd1_exponent);
+	}
+	else {
+		Dbl_clear_signexponent_set_hidden(opnd1p1);
+	}
+	if (opnd2_exponent == 0) {
+		/* normalize, then continue */
+		opnd2_exponent = 1;
+		Dbl_normalize(opnd2p1,opnd2p2,opnd2_exponent);
+	}
+	else {
+		Dbl_clear_signexponent_set_hidden(opnd2p1);
+	}
+
+	/* find result exponent and divide step loop count */
+	dest_exponent = opnd2_exponent - 1;
+	stepcount = opnd1_exponent - opnd2_exponent;
+
+	/*
+	 * check for opnd1/opnd2 < 1
+	 */
+	if (stepcount < 0) {
+		/*
+		 * check for opnd1/opnd2 > 1/2
+		 *
+		 * In this case n will round to 1, so 
+		 *    r = opnd1 - opnd2 
+		 */
+		if (stepcount == -1 && 
+		    Dbl_isgreaterthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
+			/* set sign */
+			Dbl_allp1(resultp1) = ~Dbl_allp1(resultp1);
+			/* align opnd2 with opnd1 */
+			Dbl_leftshiftby1(opnd2p1,opnd2p2); 
+			Dbl_subtract(opnd2p1,opnd2p2,opnd1p1,opnd1p2,
+			 opnd2p1,opnd2p2);
+			/* now normalize */
+                	while (Dbl_iszero_hidden(opnd2p1)) {
+                        	Dbl_leftshiftby1(opnd2p1,opnd2p2);
+                        	dest_exponent--;
+			}
+			Dbl_set_exponentmantissa(resultp1,resultp2,opnd2p1,opnd2p2);
+			goto testforunderflow;
+		}
+		/*
+		 * opnd1/opnd2 <= 1/2
+		 *
+		 * In this case n will round to zero, so 
+		 *    r = opnd1
+		 */
+		Dbl_set_exponentmantissa(resultp1,resultp2,opnd1p1,opnd1p2);
+		dest_exponent = opnd1_exponent;
+		goto testforunderflow;
+	}
+
+	/*
+	 * Generate result
+	 *
+	 * Do iterative subtract until remainder is less than operand 2.
+	 */
+	while (stepcount-- > 0 && (Dbl_allp1(opnd1p1) || Dbl_allp2(opnd1p2))) {
+		if (Dbl_isnotlessthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
+			Dbl_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2,opnd1p1,opnd1p2);
+		}
+		Dbl_leftshiftby1(opnd1p1,opnd1p2);
+	}
+	/*
+	 * Do last subtract, then determine which way to round if remainder 
+	 * is exactly 1/2 of opnd2 
+	 */
+	if (Dbl_isnotlessthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
+		Dbl_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2,opnd1p1,opnd1p2);
+		roundup = TRUE;
+	}
+	if (stepcount > 0 || Dbl_iszero(opnd1p1,opnd1p2)) {
+		/* division is exact, remainder is zero */
+		Dbl_setzero_exponentmantissa(resultp1,resultp2);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+
+	/* 
+	 * Check for cases where opnd1/opnd2 < n 
+	 *
+	 * In this case the result's sign will be opposite that of
+	 * opnd1.  The mantissa also needs some correction.
+	 */
+	Dbl_leftshiftby1(opnd1p1,opnd1p2);
+	if (Dbl_isgreaterthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
+		Dbl_invert_sign(resultp1);
+		Dbl_leftshiftby1(opnd2p1,opnd2p2);
+		Dbl_subtract(opnd2p1,opnd2p2,opnd1p1,opnd1p2,opnd1p1,opnd1p2);
+	}
+	/* check for remainder being exactly 1/2 of opnd2 */
+	else if (Dbl_isequal(opnd1p1,opnd1p2,opnd2p1,opnd2p2) && roundup) { 
+		Dbl_invert_sign(resultp1);
+	}
+
+	/* normalize result's mantissa */
+        while (Dbl_iszero_hidden(opnd1p1)) {
+                dest_exponent--;
+                Dbl_leftshiftby1(opnd1p1,opnd1p2);
+        }
+	Dbl_set_exponentmantissa(resultp1,resultp2,opnd1p1,opnd1p2);
+
+        /* 
+         * Test for underflow
+         */
+    testforunderflow:
+	if (dest_exponent <= 0) {
+                /* trap if UNDERFLOWTRAP enabled */
+                if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl);
+			/* frem is always exact */
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(UNDERFLOWEXCEPTION);
+                }
+                /*
+                 * denormalize result or set to signed zero
+                 */
+                if (dest_exponent >= (1 - DBL_P)) {
+			Dbl_rightshift_exponentmantissa(resultp1,resultp2,
+			 1-dest_exponent);
+                }
+                else {
+			Dbl_setzero_exponentmantissa(resultp1,resultp2);
+		}
+	}
+	else Dbl_set_exponent(resultp1,dest_exponent);
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	return(NOEXCEPTION);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/dfsqrt.c linux-2.4.20/arch/parisc/math-emu/dfsqrt.c
--- linux-2.4.19/arch/parisc/math-emu/dfsqrt.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/dfsqrt.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,195 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/dfsqrt.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Double Floating-point Square Root
+ *
+ *  External Interfaces:
+ *	dbl_fsqrt(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ *  Double Floating-point Square Root
+ */
+
+/*ARGSUSED*/
+unsigned int
+dbl_fsqrt(
+	    dbl_floating_point *srcptr,
+	    unsigned int *nullptr,
+	    dbl_floating_point *dstptr,
+	    unsigned int *status)
+{
+	register unsigned int srcp1, srcp2, resultp1, resultp2;
+	register unsigned int newbitp1, newbitp2, sump1, sump2;
+	register int src_exponent;
+	register boolean guardbit = FALSE, even_exponent;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+        /*
+         * check source operand for NaN or infinity
+         */
+        if ((src_exponent = Dbl_exponent(srcp1)) == DBL_INFINITY_EXPONENT) {
+                /*
+                 * is signaling NaN?
+                 */
+                if (Dbl_isone_signaling(srcp1)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Dbl_set_quiet(srcp1);
+                }
+                /*
+                 * Return quiet NaN or positive infinity.
+		 *  Fall thru to negative test if negative infinity.
+                 */
+		if (Dbl_iszero_sign(srcp1) || 
+		    Dbl_isnotzero_mantissa(srcp1,srcp2)) {
+                	Dbl_copytoptr(srcp1,srcp2,dstptr);
+                	return(NOEXCEPTION);
+		}
+        }
+
+        /*
+         * check for zero source operand
+         */
+	if (Dbl_iszero_exponentmantissa(srcp1,srcp2)) {
+		Dbl_copytoptr(srcp1,srcp2,dstptr);
+		return(NOEXCEPTION);
+	}
+
+        /*
+         * check for negative source operand 
+         */
+	if (Dbl_isone_sign(srcp1)) {
+		/* trap if INVALIDTRAP enabled */
+		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+		/* make NaN quiet */
+		Set_invalidflag();
+		Dbl_makequietnan(srcp1,srcp2);
+		Dbl_copytoptr(srcp1,srcp2,dstptr);
+		return(NOEXCEPTION);
+	}
+
+	/*
+	 * Generate result
+	 */
+	if (src_exponent > 0) {
+		even_exponent = Dbl_hidden(srcp1);
+		Dbl_clear_signexponent_set_hidden(srcp1);
+	}
+	else {
+		/* normalize operand */
+		Dbl_clear_signexponent(srcp1);
+		src_exponent++;
+		Dbl_normalize(srcp1,srcp2,src_exponent);
+		even_exponent = src_exponent & 1;
+	}
+	if (even_exponent) {
+		/* exponent is even */
+		/* Add comment here.  Explain why odd exponent needs correction */
+		Dbl_leftshiftby1(srcp1,srcp2);
+	}
+	/*
+	 * Add comment here.  Explain following algorithm.
+	 * 
+	 * Trust me, it works.
+	 *
+	 */
+	Dbl_setzero(resultp1,resultp2);
+	Dbl_allp1(newbitp1) = 1 << (DBL_P - 32);
+	Dbl_setzero_mantissap2(newbitp2);
+	while (Dbl_isnotzero(newbitp1,newbitp2) && Dbl_isnotzero(srcp1,srcp2)) {
+		Dbl_addition(resultp1,resultp2,newbitp1,newbitp2,sump1,sump2);
+		if(Dbl_isnotgreaterthan(sump1,sump2,srcp1,srcp2)) {
+			Dbl_leftshiftby1(newbitp1,newbitp2);
+			/* update result */
+			Dbl_addition(resultp1,resultp2,newbitp1,newbitp2,
+			 resultp1,resultp2);  
+			Dbl_subtract(srcp1,srcp2,sump1,sump2,srcp1,srcp2);
+			Dbl_rightshiftby2(newbitp1,newbitp2);
+		}
+		else {
+			Dbl_rightshiftby1(newbitp1,newbitp2);
+		}
+		Dbl_leftshiftby1(srcp1,srcp2);
+	}
+	/* correct exponent for pre-shift */
+	if (even_exponent) {
+		Dbl_rightshiftby1(resultp1,resultp2);
+	}
+
+	/* check for inexact */
+	if (Dbl_isnotzero(srcp1,srcp2)) {
+		if (!even_exponent && Dbl_islessthan(resultp1,resultp2,srcp1,srcp2)) {
+			Dbl_increment(resultp1,resultp2);
+		}
+		guardbit = Dbl_lowmantissap2(resultp2);
+		Dbl_rightshiftby1(resultp1,resultp2);
+
+		/*  now round result  */
+		switch (Rounding_mode()) {
+		case ROUNDPLUS:
+		     Dbl_increment(resultp1,resultp2);
+		     break;
+		case ROUNDNEAREST:
+		     /* stickybit is always true, so guardbit 
+		      * is enough to determine rounding */
+		     if (guardbit) {
+			    Dbl_increment(resultp1,resultp2);
+		     }
+		     break;
+		}
+		/* increment result exponent by 1 if mantissa overflowed */
+		if (Dbl_isone_hiddenoverflow(resultp1)) src_exponent+=2;
+
+		if (Is_inexacttrap_enabled()) {
+			Dbl_set_exponent(resultp1,
+			 ((src_exponent-DBL_BIAS)>>1)+DBL_BIAS);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(INEXACTEXCEPTION);
+		}
+		else Set_inexactflag();
+	}
+	else {
+		Dbl_rightshiftby1(resultp1,resultp2);
+	}
+	Dbl_set_exponent(resultp1,((src_exponent-DBL_BIAS)>>1)+DBL_BIAS);
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	return(NOEXCEPTION);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/dfsub.c linux-2.4.20/arch/parisc/math-emu/dfsub.c
--- linux-2.4.19/arch/parisc/math-emu/dfsub.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/dfsub.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,526 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/dfsub.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Double_subtract: subtract two double precision values.
+ *
+ *  External Interfaces:
+ *	dbl_fsub(leftptr, rightptr, dstptr, status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ * Double_subtract: subtract two double precision values.
+ */
+int
+dbl_fsub(
+	    dbl_floating_point *leftptr,
+	    dbl_floating_point *rightptr,
+	    dbl_floating_point *dstptr,
+	    unsigned int *status)
+    {
+    register unsigned int signless_upper_left, signless_upper_right, save;
+    register unsigned int leftp1, leftp2, rightp1, rightp2, extent;
+    register unsigned int resultp1 = 0, resultp2 = 0;
+    
+    register int result_exponent, right_exponent, diff_exponent;
+    register int sign_save, jumpsize;
+    register boolean inexact = FALSE, underflowtrap;
+        
+    /* Create local copies of the numbers */
+    Dbl_copyfromptr(leftptr,leftp1,leftp2);
+    Dbl_copyfromptr(rightptr,rightp1,rightp2);
+
+    /* A zero "save" helps discover equal operands (for later),  *
+     * and is used in swapping operands (if needed).             */
+    Dbl_xortointp1(leftp1,rightp1,/*to*/save);
+
+    /*
+     * check first operand for NaN's or infinity
+     */
+    if ((result_exponent = Dbl_exponent(leftp1)) == DBL_INFINITY_EXPONENT)
+	{
+	if (Dbl_iszero_mantissa(leftp1,leftp2)) 
+	    {
+	    if (Dbl_isnotnan(rightp1,rightp2)) 
+		{
+		if (Dbl_isinfinity(rightp1,rightp2) && save==0) 
+		    {
+		    /* 
+		     * invalid since operands are same signed infinity's
+		     */
+		    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                    Set_invalidflag();
+                    Dbl_makequietnan(resultp1,resultp2);
+		    Dbl_copytoptr(resultp1,resultp2,dstptr);
+		    return(NOEXCEPTION);
+		    }
+		/*
+	 	 * return infinity
+	 	 */
+		Dbl_copytoptr(leftp1,leftp2,dstptr);
+		return(NOEXCEPTION);
+		}
+	    }
+	else 
+	    {
+            /*
+             * is NaN; signaling or quiet?
+             */
+            if (Dbl_isone_signaling(leftp1)) 
+		{
+               	/* trap if INVALIDTRAP enabled */
+		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+        	/* make NaN quiet */
+        	Set_invalidflag();
+        	Dbl_set_quiet(leftp1);
+        	}
+	    /* 
+	     * is second operand a signaling NaN? 
+	     */
+	    else if (Dbl_is_signalingnan(rightp1)) 
+		{
+        	/* trap if INVALIDTRAP enabled */
+               	if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+		/* make NaN quiet */
+		Set_invalidflag();
+		Dbl_set_quiet(rightp1);
+		Dbl_copytoptr(rightp1,rightp2,dstptr);
+		return(NOEXCEPTION);
+		}
+	    /*
+ 	     * return quiet NaN
+ 	     */
+	    Dbl_copytoptr(leftp1,leftp2,dstptr);
+ 	    return(NOEXCEPTION);
+	    }
+	} /* End left NaN or Infinity processing */
+    /*
+     * check second operand for NaN's or infinity
+     */
+    if (Dbl_isinfinity_exponent(rightp1)) 
+	{
+	if (Dbl_iszero_mantissa(rightp1,rightp2)) 
+	    {
+	    /* return infinity */
+	    Dbl_invert_sign(rightp1);
+	    Dbl_copytoptr(rightp1,rightp2,dstptr);
+	    return(NOEXCEPTION);
+	    }
+        /*
+         * is NaN; signaling or quiet?
+         */
+        if (Dbl_isone_signaling(rightp1)) 
+	    {
+            /* trap if INVALIDTRAP enabled */
+	    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+	    /* make NaN quiet */
+	    Set_invalidflag();
+	    Dbl_set_quiet(rightp1);
+	    }
+	/*
+	 * return quiet NaN
+ 	 */
+	Dbl_copytoptr(rightp1,rightp2,dstptr);
+	return(NOEXCEPTION);
+    	} /* End right NaN or Infinity processing */
+
+    /* Invariant: Must be dealing with finite numbers */
+
+    /* Compare operands by removing the sign */
+    Dbl_copytoint_exponentmantissap1(leftp1,signless_upper_left);
+    Dbl_copytoint_exponentmantissap1(rightp1,signless_upper_right);
+
+    /* sign difference selects add or sub operation. */
+    if(Dbl_ismagnitudeless(leftp2,rightp2,signless_upper_left,signless_upper_right))
+	{
+	/* Set the left operand to the larger one by XOR swap *
+	 *  First finish the first word using "save"          */
+	Dbl_xorfromintp1(save,rightp1,/*to*/rightp1);
+	Dbl_xorfromintp1(save,leftp1,/*to*/leftp1);
+     	Dbl_swap_lower(leftp2,rightp2);
+	result_exponent = Dbl_exponent(leftp1);
+	Dbl_invert_sign(leftp1);
+	}
+    /* Invariant:  left is not smaller than right. */ 
+
+    if((right_exponent = Dbl_exponent(rightp1)) == 0)
+        {
+	/* Denormalized operands.  First look for zeroes */
+	if(Dbl_iszero_mantissa(rightp1,rightp2)) 
+	    {
+	    /* right is zero */
+	    if(Dbl_iszero_exponentmantissa(leftp1,leftp2))
+		{
+		/* Both operands are zeros */
+		Dbl_invert_sign(rightp1);
+		if(Is_rounding_mode(ROUNDMINUS))
+		    {
+		    Dbl_or_signs(leftp1,/*with*/rightp1);
+		    }
+		else
+		    {
+		    Dbl_and_signs(leftp1,/*with*/rightp1);
+		    }
+		}
+	    else 
+		{
+		/* Left is not a zero and must be the result.  Trapped
+		 * underflows are signaled if left is denormalized.  Result
+		 * is always exact. */
+		if( (result_exponent == 0) && Is_underflowtrap_enabled() )
+		    {
+		    /* need to normalize results mantissa */
+	    	    sign_save = Dbl_signextendedsign(leftp1);
+		    Dbl_leftshiftby1(leftp1,leftp2);
+		    Dbl_normalize(leftp1,leftp2,result_exponent);
+		    Dbl_set_sign(leftp1,/*using*/sign_save);
+                    Dbl_setwrapped_exponent(leftp1,result_exponent,unfl);
+		    Dbl_copytoptr(leftp1,leftp2,dstptr);
+		    /* inexact = FALSE */
+		    return(UNDERFLOWEXCEPTION);
+		    }
+		}
+	    Dbl_copytoptr(leftp1,leftp2,dstptr);
+	    return(NOEXCEPTION);
+	    }
+
+	/* Neither are zeroes */
+	Dbl_clear_sign(rightp1);	/* Exponent is already cleared */
+	if(result_exponent == 0 )
+	    {
+	    /* Both operands are denormalized.  The result must be exact
+	     * and is simply calculated.  A sum could become normalized and a
+	     * difference could cancel to a true zero. */
+	    if( (/*signed*/int) save >= 0 )
+		{
+		Dbl_subtract(leftp1,leftp2,/*minus*/rightp1,rightp2,
+		 /*into*/resultp1,resultp2);
+		if(Dbl_iszero_mantissa(resultp1,resultp2))
+		    {
+		    if(Is_rounding_mode(ROUNDMINUS))
+			{
+			Dbl_setone_sign(resultp1);
+			}
+		    else
+			{
+			Dbl_setzero_sign(resultp1);
+			}
+		    Dbl_copytoptr(resultp1,resultp2,dstptr);
+		    return(NOEXCEPTION);
+		    }
+		}
+	    else
+		{
+		Dbl_addition(leftp1,leftp2,rightp1,rightp2,
+		 /*into*/resultp1,resultp2);
+		if(Dbl_isone_hidden(resultp1))
+		    {
+		    Dbl_copytoptr(resultp1,resultp2,dstptr);
+		    return(NOEXCEPTION);
+		    }
+		}
+	    if(Is_underflowtrap_enabled())
+		{
+		/* need to normalize result */
+	    	sign_save = Dbl_signextendedsign(resultp1);
+		Dbl_leftshiftby1(resultp1,resultp2);
+		Dbl_normalize(resultp1,resultp2,result_exponent);
+		Dbl_set_sign(resultp1,/*using*/sign_save);
+                Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		/* inexact = FALSE */
+		return(UNDERFLOWEXCEPTION);
+		}
+	    Dbl_copytoptr(resultp1,resultp2,dstptr);
+	    return(NOEXCEPTION);
+	    }
+	right_exponent = 1;	/* Set exponent to reflect different bias
+				 * with denomalized numbers. */
+	}
+    else
+	{
+	Dbl_clear_signexponent_set_hidden(rightp1);
+	}
+    Dbl_clear_exponent_set_hidden(leftp1);
+    diff_exponent = result_exponent - right_exponent;
+
+    /* 
+     * Special case alignment of operands that would force alignment 
+     * beyond the extent of the extension.  A further optimization
+     * could special case this but only reduces the path length for this
+     * infrequent case.
+     */
+    if(diff_exponent > DBL_THRESHOLD)
+	{
+	diff_exponent = DBL_THRESHOLD;
+	}
+    
+    /* Align right operand by shifting to right */
+    Dbl_right_align(/*operand*/rightp1,rightp2,/*shifted by*/diff_exponent,
+     /*and lower to*/extent);
+
+    /* Treat sum and difference of the operands separately. */
+    if( (/*signed*/int) save >= 0 )
+	{
+	/*
+	 * Difference of the two operands.  Their can be no overflow.  A
+	 * borrow can occur out of the hidden bit and force a post
+	 * normalization phase.
+	 */
+	Dbl_subtract_withextension(leftp1,leftp2,/*minus*/rightp1,rightp2,
+	 /*with*/extent,/*into*/resultp1,resultp2);
+	if(Dbl_iszero_hidden(resultp1))
+	    {
+	    /* Handle normalization */
+	    /* A straight foward algorithm would now shift the result
+	     * and extension left until the hidden bit becomes one.  Not
+	     * all of the extension bits need participate in the shift.
+	     * Only the two most significant bits (round and guard) are
+	     * needed.  If only a single shift is needed then the guard
+	     * bit becomes a significant low order bit and the extension
+	     * must participate in the rounding.  If more than a single 
+	     * shift is needed, then all bits to the right of the guard 
+	     * bit are zeros, and the guard bit may or may not be zero. */
+	    sign_save = Dbl_signextendedsign(resultp1);
+            Dbl_leftshiftby1_withextent(resultp1,resultp2,extent,resultp1,resultp2);
+
+            /* Need to check for a zero result.  The sign and exponent
+	     * fields have already been zeroed.  The more efficient test
+	     * of the full object can be used.
+	     */
+    	    if(Dbl_iszero(resultp1,resultp2))
+		/* Must have been "x-x" or "x+(-x)". */
+		{
+		if(Is_rounding_mode(ROUNDMINUS)) Dbl_setone_sign(resultp1);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+		}
+	    result_exponent--;
+	    /* Look to see if normalization is finished. */
+	    if(Dbl_isone_hidden(resultp1))
+		{
+		if(result_exponent==0)
+		    {
+		    /* Denormalized, exponent should be zero.  Left operand *
+		     * was normalized, so extent (guard, round) was zero    */
+		    goto underflow;
+		    }
+		else
+		    {
+		    /* No further normalization is needed. */
+		    Dbl_set_sign(resultp1,/*using*/sign_save);
+	    	    Ext_leftshiftby1(extent);
+		    goto round;
+		    }
+		}
+
+	    /* Check for denormalized, exponent should be zero.  Left    *
+	     * operand was normalized, so extent (guard, round) was zero */
+	    if(!(underflowtrap = Is_underflowtrap_enabled()) &&
+	       result_exponent==0) goto underflow;
+
+	    /* Shift extension to complete one bit of normalization and
+	     * update exponent. */
+	    Ext_leftshiftby1(extent);
+
+	    /* Discover first one bit to determine shift amount.  Use a
+	     * modified binary search.  We have already shifted the result
+	     * one position right and still not found a one so the remainder
+	     * of the extension must be zero and simplifies rounding. */
+	    /* Scan bytes */
+	    while(Dbl_iszero_hiddenhigh7mantissa(resultp1))
+		{
+		Dbl_leftshiftby8(resultp1,resultp2);
+		if((result_exponent -= 8) <= 0  && !underflowtrap)
+		    goto underflow;
+		}
+	    /* Now narrow it down to the nibble */
+	    if(Dbl_iszero_hiddenhigh3mantissa(resultp1))
+		{
+		/* The lower nibble contains the normalizing one */
+		Dbl_leftshiftby4(resultp1,resultp2);
+		if((result_exponent -= 4) <= 0 && !underflowtrap)
+		    goto underflow;
+		}
+	    /* Select case were first bit is set (already normalized)
+	     * otherwise select the proper shift. */
+	    if((jumpsize = Dbl_hiddenhigh3mantissa(resultp1)) > 7)
+		{
+		/* Already normalized */
+		if(result_exponent <= 0) goto underflow;
+		Dbl_set_sign(resultp1,/*using*/sign_save);
+		Dbl_set_exponent(resultp1,/*using*/result_exponent);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+		}
+	    Dbl_sethigh4bits(resultp1,/*using*/sign_save);
+	    switch(jumpsize) 
+		{
+		case 1:
+		    {
+		    Dbl_leftshiftby3(resultp1,resultp2);
+		    result_exponent -= 3;
+		    break;
+		    }
+		case 2:
+		case 3:
+		    {
+		    Dbl_leftshiftby2(resultp1,resultp2);
+		    result_exponent -= 2;
+		    break;
+		    }
+		case 4:
+		case 5:
+		case 6:
+		case 7:
+		    {
+		    Dbl_leftshiftby1(resultp1,resultp2);
+		    result_exponent -= 1;
+		    break;
+		    }
+		}
+	    if(result_exponent > 0) 
+		{
+		Dbl_set_exponent(resultp1,/*using*/result_exponent);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);		/* Sign bit is already set */
+		}
+	    /* Fixup potential underflows */
+	  underflow:
+	    if(Is_underflowtrap_enabled())
+		{
+		Dbl_set_sign(resultp1,sign_save);
+                Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		/* inexact = FALSE */
+		return(UNDERFLOWEXCEPTION);
+		}
+	    /* 
+	     * Since we cannot get an inexact denormalized result,
+	     * we can now return.
+	     */
+	    Dbl_fix_overshift(resultp1,resultp2,(1-result_exponent),extent);
+	    Dbl_clear_signexponent(resultp1);
+	    Dbl_set_sign(resultp1,sign_save);
+	    Dbl_copytoptr(resultp1,resultp2,dstptr);
+	    return(NOEXCEPTION);
+	    } /* end if(hidden...)... */
+	/* Fall through and round */
+	} /* end if(save >= 0)... */
+    else 
+	{
+	/* Subtract magnitudes */
+	Dbl_addition(leftp1,leftp2,rightp1,rightp2,/*to*/resultp1,resultp2);
+	if(Dbl_isone_hiddenoverflow(resultp1))
+	    {
+	    /* Prenormalization required. */
+	    Dbl_rightshiftby1_withextent(resultp2,extent,extent);
+	    Dbl_arithrightshiftby1(resultp1,resultp2);
+	    result_exponent++;
+	    } /* end if hiddenoverflow... */
+	} /* end else ...subtract magnitudes... */
+    
+    /* Round the result.  If the extension is all zeros,then the result is
+     * exact.  Otherwise round in the correct direction.  No underflow is
+     * possible. If a postnormalization is necessary, then the mantissa is
+     * all zeros so no shift is needed. */
+  round:
+    if(Ext_isnotzero(extent))
+	{
+	inexact = TRUE;
+	switch(Rounding_mode())
+	    {
+	    case ROUNDNEAREST: /* The default. */
+	    if(Ext_isone_sign(extent))
+		{
+		/* at least 1/2 ulp */
+		if(Ext_isnotzero_lower(extent)  ||
+		  Dbl_isone_lowmantissap2(resultp2))
+		    {
+		    /* either exactly half way and odd or more than 1/2ulp */
+		    Dbl_increment(resultp1,resultp2);
+		    }
+		}
+	    break;
+
+	    case ROUNDPLUS:
+	    if(Dbl_iszero_sign(resultp1))
+		{
+		/* Round up positive results */
+		Dbl_increment(resultp1,resultp2);
+		}
+	    break;
+	    
+	    case ROUNDMINUS:
+	    if(Dbl_isone_sign(resultp1))
+		{
+		/* Round down negative results */
+		Dbl_increment(resultp1,resultp2);
+		}
+	    
+	    case ROUNDZERO:;
+	    /* truncate is simple */
+	    } /* end switch... */
+	if(Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
+	}
+    if(result_exponent == DBL_INFINITY_EXPONENT)
+        {
+        /* Overflow */
+        if(Is_overflowtrap_enabled())
+	    {
+	    Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+	    Dbl_copytoptr(resultp1,resultp2,dstptr);
+	    if (inexact)
+	    if (Is_inexacttrap_enabled())
+		return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+		else Set_inexactflag();
+	    return(OVERFLOWEXCEPTION);
+	    }
+        else
+	    {
+	    inexact = TRUE;
+	    Set_overflowflag();
+	    Dbl_setoverflow(resultp1,resultp2);
+	    }
+	}
+    else Dbl_set_exponent(resultp1,result_exponent);
+    Dbl_copytoptr(resultp1,resultp2,dstptr);
+    if(inexact) 
+	if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+	else Set_inexactflag();
+    return(NOEXCEPTION);
+    }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/driver.c linux-2.4.20/arch/parisc/math-emu/driver.c
--- linux-2.4.19/arch/parisc/math-emu/driver.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/driver.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,125 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ *  linux/arch/math-emu/driver.c.c
+ *
+ *	decodes and dispatches unimplemented FPU instructions
+ *
+ *  Copyright (C) 1999, 2000  Philipp Rumpf <prumpf@tux.org>
+ *  Copyright (C) 2001	      Hewlett-Packard <bame@debian.org>
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include "float.h"
+#include "math-emu.h"
+
+
+#define fptpos 31
+#define fpr1pos 10
+#define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1))
+
+#define FPUDEBUG 0
+
+/* Format of the floating-point exception registers. */
+struct exc_reg {
+	unsigned int exception : 6;
+	unsigned int ei : 26;
+};
+
+/* Macros for grabbing bits of the instruction format from the 'ei'
+   field above. */
+/* Major opcode 0c and 0e */
+#define FP0CE_UID(i) (((i) >> 6) & 3)
+#define FP0CE_CLASS(i) (((i) >> 9) & 3)
+#define FP0CE_SUBOP(i) (((i) >> 13) & 7)
+#define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */
+#define FP0C_FORMAT(i) (((i) >> 11) & 3)
+#define FP0E_FORMAT(i) (((i) >> 11) & 1)
+
+/* Major opcode 0c, uid 2 (performance monitoring) */
+#define FPPM_SUBOP(i) (((i) >> 9) & 0x1f)
+
+/* Major opcode 2e (fused operations).   */
+#define FP2E_SUBOP(i)  (((i) >> 5) & 1)
+#define FP2E_FORMAT(i) (((i) >> 11) & 1)
+
+/* Major opcode 26 (FMPYSUB) */
+/* Major opcode 06 (FMPYADD) */
+#define FPx6_FORMAT(i) ((i) & 0x1f)
+
+/* Flags and enable bits of the status word. */
+#define FPSW_FLAGS(w) ((w) >> 27)
+#define FPSW_ENABLE(w) ((w) & 0x1f)
+#define FPSW_V (1<<4)
+#define FPSW_Z (1<<3)
+#define FPSW_O (1<<2)
+#define FPSW_U (1<<1)
+#define FPSW_I (1<<0)
+
+/* Handle a floating point exception.  Return zero if the faulting
+   instruction can be completed successfully. */
+int
+handle_fpe(struct pt_regs *regs)
+{
+	extern void printbinary(unsigned long x, int nbits);
+	struct siginfo si;
+	unsigned int orig_sw, sw;
+	int signalcode;
+	/* need an intermediate copy of float regs because FPU emulation
+	 * code expects an artificial last entry which contains zero
+	 */
+	__u64 frcopy[33];
+
+	memcpy(frcopy, regs->fr, sizeof regs->fr);
+	frcopy[32] = 0;
+
+	memcpy(&orig_sw, frcopy, sizeof(orig_sw));
+
+	if (FPUDEBUG) {
+		printk(KERN_DEBUG "FP VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI ->\n   ");
+		printbinary(orig_sw, 32);
+		printk(KERN_DEBUG "\n");
+	}
+
+	signalcode = decode_fpu(frcopy, 0x666);
+
+	/* Status word = FR0L. */
+	memcpy(&sw, frcopy, sizeof(sw));
+	if (FPUDEBUG) {
+		printk(KERN_DEBUG "VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI decode_fpu returns %d|0x%x\n",
+			signalcode >> 24, signalcode & 0xffffff);
+		printbinary(sw, 32);
+		printk(KERN_DEBUG "\n");
+	}
+
+	memcpy(regs->fr, frcopy, sizeof regs->fr);
+	if (signalcode != 0) {
+	    si.si_signo = signalcode >> 24;
+	    si.si_errno = 0;
+	    si.si_code = signalcode & 0xffffff;
+	    si.si_addr = (void *) regs->iaoq[0];
+	    force_sig_info(si.si_signo, &si, current);
+	    return -1;
+	}
+
+	return signalcode ? -1 : 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/fcnvff.c linux-2.4.20/arch/parisc/math-emu/fcnvff.c
--- linux-2.4.19/arch/parisc/math-emu/fcnvff.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/fcnvff.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,309 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/fcnvff.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single Floating-point to Double Floating-point
+ *	Double Floating-point to Single Floating-point
+ *
+ *  External Interfaces:
+ *	dbl_to_sgl_fcnvff(srcptr,nullptr,dstptr,status)
+ *	sgl_to_dbl_fcnvff(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/*
+ *  Single Floating-point to Double Floating-point 
+ */
+/*ARGSUSED*/
+int
+sgl_to_dbl_fcnvff(
+	    sgl_floating_point *srcptr,
+	    unsigned int *nullptr,
+	    dbl_floating_point *dstptr,
+	    unsigned int *status)
+{
+	register unsigned int src, resultp1, resultp2;
+	register int src_exponent;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src);
+	Dbl_allp1(resultp1) = Sgl_all(src);  /* set sign of result */
+	/* 
+ 	 * Test for NaN or infinity
+ 	 */
+	if (src_exponent == SGL_INFINITY_EXPONENT) {
+		/*
+		 * determine if NaN or infinity
+		 */
+		if (Sgl_iszero_mantissa(src)) {
+			/*
+			 * is infinity; want to return double infinity
+			 */
+			Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+		else {
+			/* 
+			 * is NaN; signaling or quiet?
+			 */
+			if (Sgl_isone_signaling(src)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(INVALIDEXCEPTION);
+				/* make NaN quiet */
+				else {
+					Set_invalidflag();
+					Sgl_set_quiet(src);
+				}
+			}
+			/* 
+			 * NaN is quiet, return as double NaN 
+			 */
+			Dbl_setinfinity_exponent(resultp1);
+			Sgl_to_dbl_mantissa(src,resultp1,resultp2);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+	/* 
+ 	 * Test for zero or denormalized
+ 	 */
+	if (src_exponent == 0) {
+		/*
+		 * determine if zero or denormalized
+		 */
+		if (Sgl_isnotzero_mantissa(src)) {
+			/*
+			 * is denormalized; want to normalize
+			 */
+			Sgl_clear_signexponent(src);
+			Sgl_leftshiftby1(src);
+			Sgl_normalize(src,src_exponent);
+			Sgl_to_dbl_exponent(src_exponent,resultp1);
+			Sgl_to_dbl_mantissa(src,resultp1,resultp2);
+		}
+		else {
+			Dbl_setzero_exponentmantissa(resultp1,resultp2);
+		}
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+	/*
+	 * No special cases, just complete the conversion
+	 */
+	Sgl_to_dbl_exponent(src_exponent, resultp1);
+	Sgl_to_dbl_mantissa(Sgl_mantissa(src), resultp1,resultp2);
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Single Floating-point 
+ */
+/*ARGSUSED*/
+int
+dbl_to_sgl_fcnvff(
+		    dbl_floating_point *srcptr,
+		    unsigned int *nullptr,
+		    sgl_floating_point *dstptr,
+		    unsigned int *status)
+{
+        register unsigned int srcp1, srcp2, result;
+        register int src_exponent, dest_exponent, dest_mantissa;
+        register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
+	register boolean lsb_odd = FALSE;
+	boolean is_tiny;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+        src_exponent = Dbl_exponent(srcp1);
+	Sgl_all(result) = Dbl_allp1(srcp1);  /* set sign of result */
+        /* 
+         * Test for NaN or infinity
+         */
+        if (src_exponent == DBL_INFINITY_EXPONENT) {
+                /*
+                 * determine if NaN or infinity
+                 */
+                if (Dbl_iszero_mantissa(srcp1,srcp2)) {
+                        /*
+                         * is infinity; want to return single infinity
+                         */
+                        Sgl_setinfinity_exponentmantissa(result);
+                        *dstptr = result;
+                        return(NOEXCEPTION);
+                }
+                /* 
+                 * is NaN; signaling or quiet?
+                 */
+                if (Dbl_isone_signaling(srcp1)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        else {
+				Set_invalidflag();
+                        	/* make NaN quiet */
+                        	Dbl_set_quiet(srcp1);
+			}
+                }
+                /* 
+                 * NaN is quiet, return as single NaN 
+                 */
+                Sgl_setinfinity_exponent(result);
+		Sgl_set_mantissa(result,Dallp1(srcp1)<<3 | Dallp2(srcp2)>>29);
+		if (Sgl_iszero_mantissa(result)) Sgl_set_quiet(result);
+                *dstptr = result;
+                return(NOEXCEPTION);
+        }
+        /*
+         * Generate result
+         */
+        Dbl_to_sgl_exponent(src_exponent,dest_exponent);
+	if (dest_exponent > 0) {
+        	Dbl_to_sgl_mantissa(srcp1,srcp2,dest_mantissa,inexact,guardbit, 
+		stickybit,lsb_odd);
+	}
+	else {
+		if (Dbl_iszero_exponentmantissa(srcp1,srcp2)){
+			Sgl_setzero_exponentmantissa(result);
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+                if (Is_underflowtrap_enabled()) {
+			Dbl_to_sgl_mantissa(srcp1,srcp2,dest_mantissa,inexact,
+			guardbit,stickybit,lsb_odd);
+                }
+		else {
+			/* compute result, determine inexact info,
+			 * and set Underflowflag if appropriate
+			 */
+			Dbl_to_sgl_denormalized(srcp1,srcp2,dest_exponent,
+			dest_mantissa,inexact,guardbit,stickybit,lsb_odd,
+			is_tiny);
+		}
+	}
+        /* 
+         * Now round result if not exact
+         */
+        if (inexact) {
+                switch (Rounding_mode()) {
+                        case ROUNDPLUS: 
+                                if (Sgl_iszero_sign(result)) dest_mantissa++;
+                                break;
+                        case ROUNDMINUS: 
+                                if (Sgl_isone_sign(result)) dest_mantissa++;
+                                break;
+                        case ROUNDNEAREST:
+                                if (guardbit) {
+                                   if (stickybit || lsb_odd) dest_mantissa++;
+                                   }
+                }
+        }
+        Sgl_set_exponentmantissa(result,dest_mantissa);
+
+        /*
+         * check for mantissa overflow after rounding
+         */
+        if ((dest_exponent>0 || Is_underflowtrap_enabled()) && 
+	    Sgl_isone_hidden(result)) dest_exponent++;
+
+        /* 
+         * Test for overflow
+         */
+        if (dest_exponent >= SGL_INFINITY_EXPONENT) {
+                /* trap if OVERFLOWTRAP enabled */
+                if (Is_overflowtrap_enabled()) {
+                        /* 
+                         * Check for gross overflow
+                         */
+                        if (dest_exponent >= SGL_INFINITY_EXPONENT+SGL_WRAP) 
+                        	return(UNIMPLEMENTEDEXCEPTION);
+                        
+                        /*
+                         * Adjust bias of result
+                         */
+			Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
+			*dstptr = result;
+			if (inexact) 
+			    if (Is_inexacttrap_enabled())
+				return(OVERFLOWEXCEPTION|INEXACTEXCEPTION);
+			    else Set_inexactflag();
+                        return(OVERFLOWEXCEPTION);
+                }
+                Set_overflowflag();
+		inexact = TRUE;
+		/* set result to infinity or largest number */
+		Sgl_setoverflow(result);
+        }
+        /* 
+         * Test for underflow
+         */
+        else if (dest_exponent <= 0) {
+                /* trap if UNDERFLOWTRAP enabled */
+                if (Is_underflowtrap_enabled()) {
+                        /* 
+                         * Check for gross underflow
+                         */
+                        if (dest_exponent <= -(SGL_WRAP))
+                        	return(UNIMPLEMENTEDEXCEPTION);
+                        /*
+                         * Adjust bias of result
+                         */
+			Sgl_setwrapped_exponent(result,dest_exponent,unfl);
+			*dstptr = result;
+			if (inexact) 
+			    if (Is_inexacttrap_enabled())
+				return(UNDERFLOWEXCEPTION|INEXACTEXCEPTION);
+			    else Set_inexactflag();
+                        return(UNDERFLOWEXCEPTION);
+                }
+                 /* 
+                  * result is denormalized or signed zero
+                  */
+               if (inexact && is_tiny) Set_underflowflag();
+
+        }
+	else Sgl_set_exponent(result,dest_exponent);
+	*dstptr = result;
+        /* 
+         * Trap if inexact trap is enabled
+         */
+        if (inexact)
+        	if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+        	else Set_inexactflag();
+        return(NOEXCEPTION);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/fcnvfu.c linux-2.4.20/arch/parisc/math-emu/fcnvfu.c
--- linux-2.4.19/arch/parisc/math-emu/fcnvfu.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/fcnvfu.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,536 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/fcnvfu.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Floating-point to Unsigned Fixed-point Converts
+ *
+ *  External Interfaces:
+ *	dbl_to_dbl_fcnvfu(srcptr,nullptr,dstptr,status)
+ *	dbl_to_sgl_fcnvfu(srcptr,nullptr,dstptr,status)
+ *	sgl_to_dbl_fcnvfu(srcptr,nullptr,dstptr,status)
+ *	sgl_to_sgl_fcnvfu(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/************************************************************************
+ *  Floating-point to Unsigned Fixed-point Converts			*
+ ************************************************************************/
+
+/*
+ *  Single Floating-point to Single Unsigned Fixed 
+ */
+/*ARGSUSED*/
+int
+sgl_to_sgl_fcnvfu(
+			sgl_floating_point *srcptr,
+			unsigned int *nullptr,
+			unsigned int *dstptr,
+			unsigned int *status)
+{
+	register unsigned int src, result;
+	register int src_exponent;
+	register boolean inexact = FALSE;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > SGL_FX_MAX_EXP + 1) {
+		if (Sgl_isone_sign(src)) {
+			result = 0;
+		} else {
+			result = 0xffffffff;
+		}
+		if (Is_invalidtrap_enabled()) {
+			return(INVALIDEXCEPTION);
+		}
+		Set_invalidflag();
+		*dstptr = result;
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		/* 
+		 * Check sign.
+		 * If negative, trap unimplemented.
+		 */
+		if (Sgl_isone_sign(src)) {
+			result = 0;
+			if (Is_invalidtrap_enabled()) {
+				return(INVALIDEXCEPTION);
+			}
+			Set_invalidflag();
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+		Sgl_clear_signexponent_set_hidden(src);
+		Suint_from_sgl_mantissa(src,src_exponent,result);
+
+		/* check for inexact */
+		if (Sgl_isinexact_to_unsigned(src,src_exponent)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				result++;
+				break;
+			case ROUNDMINUS: /* never negative */
+				break;
+			case ROUNDNEAREST:
+				if (Sgl_isone_roundbit(src,src_exponent) &&
+				    (Sgl_isone_stickybit(src,src_exponent) ||
+				     (result & 1))) {
+			     		result++;
+				}
+				break;
+			}
+		}
+	} else {
+		result = 0;
+
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				if (Sgl_iszero_sign(src)) {
+					result++;
+				}
+				break;
+			case ROUNDMINUS:
+				if (Sgl_isone_sign(src)) {
+					result = 0;
+					if (Is_invalidtrap_enabled()) {
+						return(INVALIDEXCEPTION);
+					}
+					Set_invalidflag();
+					inexact = FALSE;
+				}
+				break;
+			case ROUNDNEAREST:
+				if (src_exponent == -1 &&
+				    Sgl_isnotzero_mantissa(src)) {
+					if (Sgl_isone_sign(src)) {
+						result = 0;
+						if (Is_invalidtrap_enabled()) {
+							return(INVALIDEXCEPTION);
+						}
+						Set_invalidflag();
+						inexact = FALSE;
+					}
+			      		else result++;
+				}
+				break;
+			}
+		}
+	}
+	*dstptr = result;
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Single Floating-point to Double Unsigned Fixed 
+ */
+/*ARGSUSED*/
+int
+sgl_to_dbl_fcnvfu(
+		    sgl_floating_point *srcptr,
+		    unsigned int *nullptr,
+		    dbl_unsigned *dstptr,
+		    unsigned int *status)
+{
+	register int src_exponent;
+	register unsigned int src, resultp1, resultp2;
+	register boolean inexact = FALSE;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > DBL_FX_MAX_EXP + 1) {
+		if (Sgl_isone_sign(src)) {
+			resultp1 = resultp2 = 0;
+		} else {
+			resultp1 = resultp2 = 0xffffffff;
+		}
+		if (Is_invalidtrap_enabled()) {
+			return(INVALIDEXCEPTION);
+		}
+		Set_invalidflag();
+    		Duint_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		/* 
+		 * Check sign.
+		 * If negative, trap unimplemented.
+		 */
+		if (Sgl_isone_sign(src)) {
+			resultp1 = resultp2 = 0;
+			if (Is_invalidtrap_enabled()) {
+				return(INVALIDEXCEPTION);
+			}
+			Set_invalidflag();
+    			Duint_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+		Sgl_clear_signexponent_set_hidden(src);
+		Duint_from_sgl_mantissa(src,src_exponent,resultp1,resultp2);
+
+		/* check for inexact */
+		if (Sgl_isinexact_to_unsigned(src,src_exponent)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				Duint_increment(resultp1,resultp2);
+				break;
+			case ROUNDMINUS: /* never negative */
+				break;
+			case ROUNDNEAREST:
+				if (Sgl_isone_roundbit(src,src_exponent) &&
+				    (Sgl_isone_stickybit(src,src_exponent) || 
+				     Duint_isone_lowp2(resultp2))) {
+					Duint_increment(resultp1,resultp2);
+				}
+				break;
+			}
+		}
+	} else {
+		Duint_setzero(resultp1,resultp2);
+
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				if (Sgl_iszero_sign(src)) {
+					Duint_increment(resultp1,resultp2);
+				}
+				break;
+			case ROUNDMINUS:
+				if (Sgl_isone_sign(src)) {
+					resultp1 = resultp2 = 0;
+					if (Is_invalidtrap_enabled()) {
+						return(INVALIDEXCEPTION);
+					}
+					Set_invalidflag();
+					inexact = FALSE;
+				}
+				break;
+			case ROUNDNEAREST:
+				if (src_exponent == -1 &&
+				    Sgl_isnotzero_mantissa(src)) {
+					if (Sgl_isone_sign(src)) {
+						resultp1 = 0;
+						resultp2 = 0;
+						if (Is_invalidtrap_enabled()) {
+							return(INVALIDEXCEPTION);
+						}
+						Set_invalidflag();
+						inexact = FALSE;
+					}
+					else Duint_increment(resultp1,resultp2);
+				}
+			}
+		}
+	}
+	Duint_copytoptr(resultp1,resultp2,dstptr);
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Single Unsigned Fixed 
+ */
+/*ARGSUSED*/
+int
+dbl_to_sgl_fcnvfu (dbl_floating_point * srcptr, unsigned int *nullptr,
+		   unsigned int *dstptr, unsigned int *status)
+{
+	register unsigned int srcp1, srcp2, result;
+	register int src_exponent;
+	register boolean inexact = FALSE;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > SGL_FX_MAX_EXP + 1) {
+		if (Dbl_isone_sign(srcp1)) {
+			result = 0;
+		} else {
+			result = 0xffffffff;
+		}
+		if (Is_invalidtrap_enabled()) {
+			return(INVALIDEXCEPTION);
+		}
+		Set_invalidflag();
+		*dstptr = result;
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		/* 
+		 * Check sign.
+		 * If negative, trap unimplemented.
+		 */
+		if (Dbl_isone_sign(srcp1)) {
+			result = 0;
+			if (Is_invalidtrap_enabled()) {
+				return(INVALIDEXCEPTION);
+			}
+			Set_invalidflag();
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+		Dbl_clear_signexponent_set_hidden(srcp1);
+		Suint_from_dbl_mantissa(srcp1,srcp2,src_exponent,result);
+
+		/* check for inexact */
+		if (Dbl_isinexact_to_unsigned(srcp1,srcp2,src_exponent)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+			     result++;
+			     break;
+			case ROUNDMINUS: /* never negative */
+			     break;
+			case ROUNDNEAREST:
+			     if(Dbl_isone_roundbit(srcp1,srcp2,src_exponent) &&
+				(Dbl_isone_stickybit(srcp1,srcp2,src_exponent)||
+				 result&1))
+				   result++;
+			     break;
+			}
+			/* check for overflow */
+			if (result == 0) {
+				result = 0xffffffff;
+				if (Is_invalidtrap_enabled()) {
+					return(INVALIDEXCEPTION);
+				}
+				Set_invalidflag();
+				*dstptr = result;
+				return(NOEXCEPTION);
+			}
+		}
+	} else {
+		result = 0;
+
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				if (Dbl_iszero_sign(srcp1)) result++;
+				break;
+			case ROUNDMINUS:
+				if (Dbl_isone_sign(srcp1)) {
+					result = 0;
+					if (Is_invalidtrap_enabled()) {
+						return(INVALIDEXCEPTION);
+					}
+					Set_invalidflag();
+					inexact = FALSE;
+				}
+				break;
+			case ROUNDNEAREST:
+				if (src_exponent == -1 &&
+				    Dbl_isnotzero_mantissa(srcp1,srcp2))
+					if (Dbl_isone_sign(srcp1)) {
+						result = 0;
+						if (Is_invalidtrap_enabled()) {
+							return(INVALIDEXCEPTION);
+						}
+						Set_invalidflag();
+						inexact = FALSE;
+					}
+					else result++;
+			}
+		}
+	}
+	*dstptr = result;
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Double Unsigned Fixed 
+ */
+/*ARGSUSED*/
+int
+dbl_to_dbl_fcnvfu (dbl_floating_point * srcptr, unsigned int *nullptr,
+		   dbl_unsigned * dstptr, unsigned int *status)
+{
+	register int src_exponent;
+	register unsigned int srcp1, srcp2, resultp1, resultp2;
+	register boolean inexact = FALSE;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > DBL_FX_MAX_EXP + 1) {
+		if (Dbl_isone_sign(srcp1)) {
+			resultp1 = resultp2 = 0;
+		} else {
+			resultp1 = resultp2 = 0xffffffff;
+		}
+		if (Is_invalidtrap_enabled()) {
+			return(INVALIDEXCEPTION);
+		}
+		Set_invalidflag();
+    		Duint_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+ 
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		/* 
+		 * Check sign.
+		 * If negative, trap unimplemented.
+		 */
+		if (Dbl_isone_sign(srcp1)) {
+			resultp1 = resultp2 = 0;
+			if (Is_invalidtrap_enabled()) {
+				return(INVALIDEXCEPTION);
+			}
+			Set_invalidflag();
+    			Duint_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+		Dbl_clear_signexponent_set_hidden(srcp1);
+		Duint_from_dbl_mantissa(srcp1,srcp2,src_exponent,resultp1,
+		  resultp2);
+
+		/* check for inexact */
+		if (Dbl_isinexact_to_unsigned(srcp1,srcp2,src_exponent)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				Duint_increment(resultp1,resultp2);
+				break;
+			case ROUNDMINUS: /* never negative */
+				break;
+			case ROUNDNEAREST:
+				if(Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
+				  if(Dbl_isone_stickybit(srcp1,srcp2,src_exponent) || 
+				     Duint_isone_lowp2(resultp2))
+					Duint_increment(resultp1,resultp2);
+			} 
+		}
+	} else {
+		Duint_setzero(resultp1,resultp2);
+
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				if (Dbl_iszero_sign(srcp1)) {
+					Duint_increment(resultp1,resultp2);
+				}
+				break;
+			case ROUNDMINUS:
+				if (Dbl_isone_sign(srcp1)) {
+					resultp1 = resultp2 = 0;
+					if (Is_invalidtrap_enabled()) {
+						return(INVALIDEXCEPTION);
+					}
+					Set_invalidflag();
+					inexact = FALSE;
+				}
+				break;
+			case ROUNDNEAREST:
+				if (src_exponent == -1 &&
+				    Dbl_isnotzero_mantissa(srcp1,srcp2))
+					if (Dbl_iszero_sign(srcp1)) {
+						Duint_increment(resultp1,resultp2);
+					} else {
+						resultp1 = 0;
+						resultp2 = 0;
+						if (Is_invalidtrap_enabled()) {
+							return(INVALIDEXCEPTION);
+						}
+						Set_invalidflag();
+						inexact = FALSE;
+					}
+			}
+		}
+	}
+	Duint_copytoptr(resultp1,resultp2,dstptr);
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/fcnvfut.c linux-2.4.20/arch/parisc/math-emu/fcnvfut.c
--- linux-2.4.19/arch/parisc/math-emu/fcnvfut.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/fcnvfut.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,332 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/fcnvfut.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Floating-point to Unsigned Fixed-point Converts with Truncation
+ *
+ *  External Interfaces:
+ *	dbl_to_dbl_fcnvfut(srcptr,nullptr,dstptr,status)
+ *	dbl_to_sgl_fcnvfut(srcptr,nullptr,dstptr,status)
+ *	sgl_to_dbl_fcnvfut(srcptr,nullptr,dstptr,status)
+ *	sgl_to_sgl_fcnvfut(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/************************************************************************
+ *  Floating-point to Unsigned Fixed-point Converts with Truncation	*
+ ************************************************************************/
+
+/*
+ *  Convert single floating-point to single fixed-point format
+ *  with truncated result
+ */
+/*ARGSUSED*/
+int
+sgl_to_sgl_fcnvfut (sgl_floating_point * srcptr, unsigned int *nullptr,
+		    unsigned int *dstptr, unsigned int *status)
+{
+	register unsigned int src, result;
+	register int src_exponent;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > SGL_FX_MAX_EXP + 1) {
+		if (Sgl_isone_sign(src)) {
+			result = 0;
+		} else {
+			result = 0xffffffff;
+		}
+		if (Is_invalidtrap_enabled()) {
+			return(INVALIDEXCEPTION);
+		}
+		Set_invalidflag();
+		*dstptr = result;
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		/* 
+		 * Check sign.
+		 * If negative, trap unimplemented.
+		 */
+		if (Sgl_isone_sign(src)) {
+			result = 0;
+			if (Is_invalidtrap_enabled()) {
+				return(INVALIDEXCEPTION);
+			}
+			Set_invalidflag();
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+		Sgl_clear_signexponent_set_hidden(src);
+		Suint_from_sgl_mantissa(src,src_exponent,result);
+		*dstptr = result;
+
+		/* check for inexact */
+		if (Sgl_isinexact_to_unsigned(src,src_exponent)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	else {
+		*dstptr = 0;
+
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Single Floating-point to Double Unsigned Fixed 
+ */
+/*ARGSUSED*/
+int
+sgl_to_dbl_fcnvfut (sgl_floating_point * srcptr, unsigned int *nullptr,
+		    dbl_unsigned * dstptr, unsigned int *status)
+{
+	register int src_exponent;
+	register unsigned int src, resultp1, resultp2;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > DBL_FX_MAX_EXP + 1) {
+		if (Sgl_isone_sign(src)) {
+			resultp1 = resultp2 = 0;
+		} else {
+			resultp1 = resultp2 = 0xffffffff;
+		}
+		if (Is_invalidtrap_enabled()) {
+			return(INVALIDEXCEPTION);
+		}
+		Set_invalidflag();
+    		Duint_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		/* 
+		 * Check sign.
+		 * If negative, trap unimplemented.
+		 */
+		if (Sgl_isone_sign(src)) {
+			resultp1 = resultp2 = 0;
+			if (Is_invalidtrap_enabled()) {
+				return(INVALIDEXCEPTION);
+			}
+			Set_invalidflag();
+    			Duint_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+		Sgl_clear_signexponent_set_hidden(src);
+		Duint_from_sgl_mantissa(src,src_exponent,resultp1,resultp2);
+		Duint_copytoptr(resultp1,resultp2,dstptr);
+
+		/* check for inexact */
+		if (Sgl_isinexact_to_unsigned(src,src_exponent)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	else {
+		Duint_setzero(resultp1,resultp2);
+		Duint_copytoptr(resultp1,resultp2,dstptr);
+
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Single Unsigned Fixed 
+ */
+/*ARGSUSED*/
+int
+dbl_to_sgl_fcnvfut (dbl_floating_point * srcptr, unsigned int *nullptr,
+		    unsigned int *dstptr, unsigned int *status)
+{
+	register unsigned int srcp1, srcp2, result;
+	register int src_exponent;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > SGL_FX_MAX_EXP + 1) {
+		if (Dbl_isone_sign(srcp1)) {
+			result = 0;
+		} else {
+			result = 0xffffffff;
+		}
+		if (Is_invalidtrap_enabled()) {
+			return(INVALIDEXCEPTION);
+		}
+		Set_invalidflag();
+		*dstptr = result;
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		/* 
+		 * Check sign.
+		 * If negative, trap unimplemented.
+		 */
+		if (Dbl_isone_sign(srcp1)) {
+			result = 0;
+			if (Is_invalidtrap_enabled()) {
+				return(INVALIDEXCEPTION);
+			}
+			Set_invalidflag();
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+		Dbl_clear_signexponent_set_hidden(srcp1);
+		Suint_from_dbl_mantissa(srcp1,srcp2,src_exponent,result);
+		*dstptr = result;
+
+		/* check for inexact */
+		if (Dbl_isinexact_to_unsigned(srcp1,srcp2,src_exponent)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	else {
+		*dstptr = 0;
+
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Double Unsigned Fixed 
+ */
+/*ARGSUSED*/
+int
+dbl_to_dbl_fcnvfut (dbl_floating_point * srcptr, unsigned int *nullptr,
+		    dbl_unsigned * dstptr, unsigned int *status)
+{
+	register int src_exponent;
+	register unsigned int srcp1, srcp2, resultp1, resultp2;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > DBL_FX_MAX_EXP + 1) {
+		if (Dbl_isone_sign(srcp1)) {
+			resultp1 = resultp2 = 0;
+		} else {
+			resultp1 = resultp2 = 0xffffffff;
+		}
+		if (Is_invalidtrap_enabled()) {
+			return(INVALIDEXCEPTION);
+		}
+		Set_invalidflag();
+    		Duint_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		/* 
+		 * Check sign.
+		 * If negative, trap unimplemented.
+		 */
+		if (Dbl_isone_sign(srcp1)) {
+			resultp1 = resultp2 = 0;
+			if (Is_invalidtrap_enabled()) {
+				return(INVALIDEXCEPTION);
+			}
+			Set_invalidflag();
+    			Duint_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+		Dbl_clear_signexponent_set_hidden(srcp1);
+		Duint_from_dbl_mantissa(srcp1,srcp2,src_exponent,
+		  resultp1,resultp2);
+		Duint_copytoptr(resultp1,resultp2,dstptr);
+
+		/* check for inexact */
+		if (Dbl_isinexact_to_unsigned(srcp1,srcp2,src_exponent)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	else {
+		Duint_setzero(resultp1,resultp2);
+		Duint_copytoptr(resultp1,resultp2,dstptr);
+
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	return(NOEXCEPTION);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/fcnvfx.c linux-2.4.20/arch/parisc/math-emu/fcnvfx.c
--- linux-2.4.19/arch/parisc/math-emu/fcnvfx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/fcnvfx.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,501 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/fcnvfx.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single Floating-point to Single Fixed-point
+ *	Single Floating-point to Double Fixed-point 
+ *	Double Floating-point to Single Fixed-point 
+ *	Double Floating-point to Double Fixed-point 
+ *
+ *  External Interfaces:
+ *	dbl_to_dbl_fcnvfx(srcptr,nullptr,dstptr,status)
+ *	dbl_to_sgl_fcnvfx(srcptr,nullptr,dstptr,status)
+ *	sgl_to_dbl_fcnvfx(srcptr,nullptr,dstptr,status)
+ *	sgl_to_sgl_fcnvfx(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/*
+ *  Single Floating-point to Single Fixed-point 
+ */
+/*ARGSUSED*/
+int
+sgl_to_sgl_fcnvfx(
+		    sgl_floating_point *srcptr,
+		    sgl_floating_point *nullptr,
+		    int *dstptr,
+		    sgl_floating_point *status)
+{
+	register unsigned int src, temp;
+	register int src_exponent, result;
+	register boolean inexact = FALSE;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > SGL_FX_MAX_EXP) {
+		/* check for MININT */
+		if ((src_exponent > SGL_FX_MAX_EXP + 1) || 
+		Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
+                        if (Sgl_iszero_sign(src)) result = 0x7fffffff;
+                        else result = 0x80000000; 
+
+	                if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                        }
+                        Set_invalidflag();
+			*dstptr = result;
+			return(NOEXCEPTION);
+       		}
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		temp = src;
+		Sgl_clear_signexponent_set_hidden(temp);
+		Int_from_sgl_mantissa(temp,src_exponent);
+		if (Sgl_isone_sign(src))  result = -Sgl_all(temp);
+		else result = Sgl_all(temp);
+
+		/* check for inexact */
+		if (Sgl_isinexact_to_fix(src,src_exponent)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+			     if (Sgl_iszero_sign(src)) result++;
+			     break;
+			case ROUNDMINUS:
+			     if (Sgl_isone_sign(src)) result--;
+			     break;
+			case ROUNDNEAREST:
+			     if (Sgl_isone_roundbit(src,src_exponent)) {
+			        if (Sgl_isone_stickybit(src,src_exponent) 
+				|| (Sgl_isone_lowmantissa(temp)))
+			           if (Sgl_iszero_sign(src)) result++;
+			           else result--;
+			     }
+			} 
+		}
+	}
+	else {
+		result = 0;
+
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+			     if (Sgl_iszero_sign(src)) result++;
+			     break;
+			case ROUNDMINUS:
+			     if (Sgl_isone_sign(src)) result--;
+			     break;
+			case ROUNDNEAREST:
+			     if (src_exponent == -1)
+			        if (Sgl_isnotzero_mantissa(src))
+			           if (Sgl_iszero_sign(src)) result++;
+			           else result--;
+			} 
+		}
+	}
+	*dstptr = result;
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Single Floating-point to Double Fixed-point 
+ */
+/*ARGSUSED*/
+int
+sgl_to_dbl_fcnvfx(
+		sgl_floating_point *srcptr,
+		unsigned int *nullptr,
+		dbl_integer *dstptr,
+		unsigned int *status)
+{
+	register int src_exponent, resultp1;
+	register unsigned int src, temp, resultp2;
+	register boolean inexact = FALSE;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > DBL_FX_MAX_EXP) {
+		/* check for MININT */
+		if ((src_exponent > DBL_FX_MAX_EXP + 1) || 
+		Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
+                        if (Sgl_iszero_sign(src)) {
+                              resultp1 = 0x7fffffff;
+			      resultp2 = 0xffffffff;
+			}
+                        else {
+			    resultp1 = 0x80000000; 
+			    resultp2 = 0;
+			}
+	                if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                        }
+                        Set_invalidflag();
+    		        Dint_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+		Dint_set_minint(resultp1,resultp2);
+		Dint_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		temp = src;
+		Sgl_clear_signexponent_set_hidden(temp);
+		Dint_from_sgl_mantissa(temp,src_exponent,resultp1,resultp2);
+		if (Sgl_isone_sign(src)) {
+			Dint_setone_sign(resultp1,resultp2);
+		}
+
+		/* check for inexact */
+		if (Sgl_isinexact_to_fix(src,src_exponent)) {
+			inexact = TRUE;
+                        /*  round result  */
+                        switch (Rounding_mode()) {
+                        case ROUNDPLUS:
+                             if (Sgl_iszero_sign(src)) {
+				Dint_increment(resultp1,resultp2);
+			     }
+                             break;
+                        case ROUNDMINUS:
+                             if (Sgl_isone_sign(src)) {
+				Dint_decrement(resultp1,resultp2);
+			     }
+                             break;
+                        case ROUNDNEAREST:
+                             if (Sgl_isone_roundbit(src,src_exponent))
+                                if (Sgl_isone_stickybit(src,src_exponent) || 
+				(Dint_isone_lowp2(resultp2)))
+				   if (Sgl_iszero_sign(src)) {
+				      Dint_increment(resultp1,resultp2);
+				   }
+                                   else {
+				      Dint_decrement(resultp1,resultp2);
+				   }
+                        }
+                }
+        }
+	else {
+		Dint_setzero(resultp1,resultp2);
+
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			inexact = TRUE;
+                        /*  round result  */
+                        switch (Rounding_mode()) {
+                        case ROUNDPLUS:
+                             if (Sgl_iszero_sign(src)) {
+				Dint_increment(resultp1,resultp2);
+			     }
+                             break;
+                        case ROUNDMINUS:
+                             if (Sgl_isone_sign(src)) {
+				Dint_decrement(resultp1,resultp2);
+			     }
+                             break;
+                        case ROUNDNEAREST:
+                             if (src_exponent == -1)
+                                if (Sgl_isnotzero_mantissa(src))
+                                   if (Sgl_iszero_sign(src)) {
+				      Dint_increment(resultp1,resultp2);
+				   }
+                                   else {
+				      Dint_decrement(resultp1,resultp2);
+				   }
+			}
+		}
+	}
+	Dint_copytoptr(resultp1,resultp2,dstptr);
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Single Fixed-point 
+ */
+/*ARGSUSED*/
+int
+dbl_to_sgl_fcnvfx(
+		    dbl_floating_point *srcptr,
+		    unsigned int *nullptr,
+		    int *dstptr,
+		    unsigned int *status)
+{
+	register unsigned int srcp1,srcp2, tempp1,tempp2;
+	register int src_exponent, result;
+	register boolean inexact = FALSE;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > SGL_FX_MAX_EXP) {
+		/* check for MININT */
+		if (Dbl_isoverflow_to_int(src_exponent,srcp1,srcp2)) {
+                        if (Dbl_iszero_sign(srcp1)) result = 0x7fffffff;
+                        else result = 0x80000000; 
+
+	                if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                        }
+                        Set_invalidflag();
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		tempp1 = srcp1;
+		tempp2 = srcp2;
+		Dbl_clear_signexponent_set_hidden(tempp1);
+		Int_from_dbl_mantissa(tempp1,tempp2,src_exponent);
+		if (Dbl_isone_sign(srcp1) && (src_exponent <= SGL_FX_MAX_EXP))
+			result = -Dbl_allp1(tempp1);
+		else result = Dbl_allp1(tempp1);
+
+		/* check for inexact */
+		if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
+                        inexact = TRUE;
+                        /*  round result  */
+                        switch (Rounding_mode()) {
+                        case ROUNDPLUS:
+                             if (Dbl_iszero_sign(srcp1)) result++;
+                             break;
+                        case ROUNDMINUS:
+                             if (Dbl_isone_sign(srcp1)) result--;
+                             break;
+                        case ROUNDNEAREST:
+                             if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
+                                if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent) || 
+				(Dbl_isone_lowmantissap1(tempp1)))
+                                   if (Dbl_iszero_sign(srcp1)) result++;
+                                   else result--;
+                        } 
+			/* check for overflow */
+			if ((Dbl_iszero_sign(srcp1) && result < 0) ||
+			    (Dbl_isone_sign(srcp1) && result > 0)) {
+			        
+                          if (Dbl_iszero_sign(srcp1)) result = 0x7fffffff;
+                          else result = 0x80000000; 
+
+	                  if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                          }
+                          Set_invalidflag();
+			  *dstptr = result;
+			  return(NOEXCEPTION);
+			}
+                }
+	}
+	else {
+		result = 0;
+
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+                        inexact = TRUE;
+                        /*  round result  */
+                        switch (Rounding_mode()) {
+                        case ROUNDPLUS:
+                             if (Dbl_iszero_sign(srcp1)) result++;
+                             break;
+                        case ROUNDMINUS:
+                             if (Dbl_isone_sign(srcp1)) result--;
+                             break;
+                        case ROUNDNEAREST:
+                             if (src_exponent == -1)
+                                if (Dbl_isnotzero_mantissa(srcp1,srcp2))
+                                   if (Dbl_iszero_sign(srcp1)) result++;
+                                   else result--;
+			}
+                }
+	}
+	*dstptr = result;
+        if (inexact) {
+                if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+        }
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Double Fixed-point 
+ */
+/*ARGSUSED*/
+int
+dbl_to_dbl_fcnvfx(
+		    dbl_floating_point *srcptr,
+		    unsigned int *nullptr,
+		    dbl_integer *dstptr,
+		    unsigned int *status)
+{
+	register int src_exponent, resultp1;
+	register unsigned int srcp1, srcp2, tempp1, tempp2, resultp2;
+	register boolean inexact = FALSE;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > DBL_FX_MAX_EXP) {
+		/* check for MININT */
+		if ((src_exponent > DBL_FX_MAX_EXP + 1) || 
+		Dbl_isnotzero_mantissa(srcp1,srcp2) || Dbl_iszero_sign(srcp1)) {
+                        if (Dbl_iszero_sign(srcp1)) {
+                              resultp1 = 0x7fffffff;
+			      resultp2 = 0xffffffff;
+			}
+                        else {
+			    resultp1 = 0x80000000; 
+			    resultp2 = 0;
+			}
+	                if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                        }
+                        Set_invalidflag();
+    		        Dint_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+ 
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		tempp1 = srcp1;
+		tempp2 = srcp2;
+		Dbl_clear_signexponent_set_hidden(tempp1);
+		Dint_from_dbl_mantissa(tempp1,tempp2,src_exponent,resultp1,
+		resultp2);
+		if (Dbl_isone_sign(srcp1)) {
+			Dint_setone_sign(resultp1,resultp2);
+		}
+
+		/* check for inexact */
+		if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
+                        inexact = TRUE;
+                        /*  round result  */
+                        switch (Rounding_mode()) {
+                        case ROUNDPLUS:
+                             if (Dbl_iszero_sign(srcp1)) {
+				Dint_increment(resultp1,resultp2);
+			     }
+                             break;
+                        case ROUNDMINUS:
+                             if (Dbl_isone_sign(srcp1)) {
+				Dint_decrement(resultp1,resultp2);
+			     }
+                             break;
+                        case ROUNDNEAREST:
+                             if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
+                                if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent) || 
+				(Dint_isone_lowp2(resultp2)))
+                                   if (Dbl_iszero_sign(srcp1)) {
+				      Dint_increment(resultp1,resultp2);
+				   }
+                                   else {
+				      Dint_decrement(resultp1,resultp2);
+				   }
+                        } 
+                }
+	}
+	else {
+		Dint_setzero(resultp1,resultp2);
+
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+                        inexact = TRUE;
+                        /*  round result  */
+                        switch (Rounding_mode()) {
+                        case ROUNDPLUS:
+                             if (Dbl_iszero_sign(srcp1)) {
+				Dint_increment(resultp1,resultp2);
+			     }
+                             break;
+                        case ROUNDMINUS:
+                             if (Dbl_isone_sign(srcp1)) {
+				Dint_decrement(resultp1,resultp2);
+			     }
+                             break;
+                        case ROUNDNEAREST:
+                             if (src_exponent == -1)
+                                if (Dbl_isnotzero_mantissa(srcp1,srcp2))
+                                   if (Dbl_iszero_sign(srcp1)) {
+				      Dint_increment(resultp1,resultp2);
+				   }
+                                   else {
+				      Dint_decrement(resultp1,resultp2);
+				   }
+			}
+                }
+	}
+	Dint_copytoptr(resultp1,resultp2,dstptr);
+        if (inexact) {
+                if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+        	else Set_inexactflag();
+        }
+	return(NOEXCEPTION);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/fcnvfxt.c linux-2.4.20/arch/parisc/math-emu/fcnvfxt.c
--- linux-2.4.19/arch/parisc/math-emu/fcnvfxt.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/fcnvfxt.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,328 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/fcnvfxt.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single Floating-point to Single Fixed-point /w truncated result
+ *	Single Floating-point to Double Fixed-point /w truncated result
+ *	Double Floating-point to Single Fixed-point /w truncated result
+ *	Double Floating-point to Double Fixed-point /w truncated result
+ *
+ *  External Interfaces:
+ *	dbl_to_dbl_fcnvfxt(srcptr,nullptr,dstptr,status)
+ *	dbl_to_sgl_fcnvfxt(srcptr,nullptr,dstptr,status)
+ *	sgl_to_dbl_fcnvfxt(srcptr,nullptr,dstptr,status)
+ *	sgl_to_sgl_fcnvfxt(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/*
+ *  Convert single floating-point to single fixed-point format
+ *  with truncated result
+ */
+/*ARGSUSED*/
+int
+sgl_to_sgl_fcnvfxt(
+		    sgl_floating_point *srcptr,
+		    unsigned int *nullptr,
+		    int *dstptr,
+		    unsigned int *status)
+{
+	register unsigned int src, temp;
+	register int src_exponent, result;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > SGL_FX_MAX_EXP) {
+		/* check for MININT */
+		if ((src_exponent > SGL_FX_MAX_EXP + 1) || 
+		Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
+                        if (Sgl_iszero_sign(src)) result = 0x7fffffff;
+                        else result = 0x80000000; 
+
+	                if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                        }
+                        Set_invalidflag();
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		temp = src;
+		Sgl_clear_signexponent_set_hidden(temp);
+		Int_from_sgl_mantissa(temp,src_exponent);
+		if (Sgl_isone_sign(src))  result = -Sgl_all(temp);
+		else result = Sgl_all(temp);
+		*dstptr = result;
+
+		/* check for inexact */
+		if (Sgl_isinexact_to_fix(src,src_exponent)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	else {
+		*dstptr = 0;
+
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Single Floating-point to Double Fixed-point 
+ */
+/*ARGSUSED*/
+int
+sgl_to_dbl_fcnvfxt(
+		    sgl_floating_point *srcptr,
+		    unsigned int *nullptr,
+		    dbl_integer *dstptr,
+		    unsigned int *status)
+{
+	register int src_exponent, resultp1;
+	register unsigned int src, temp, resultp2;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > DBL_FX_MAX_EXP) {
+		/* check for MININT */
+		if ((src_exponent > DBL_FX_MAX_EXP + 1) || 
+		Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
+                        if (Sgl_iszero_sign(src)) {
+                              resultp1 = 0x7fffffff;
+			      resultp2 = 0xffffffff;
+			}
+                        else {
+			    resultp1 = 0x80000000; 
+			    resultp2 = 0;
+			}
+	                if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                        }
+                        Set_invalidflag();
+    		        Dint_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+		Dint_set_minint(resultp1,resultp2);
+		Dint_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		temp = src;
+		Sgl_clear_signexponent_set_hidden(temp);
+		Dint_from_sgl_mantissa(temp,src_exponent,resultp1,resultp2);
+		if (Sgl_isone_sign(src)) {
+			Dint_setone_sign(resultp1,resultp2);
+		}
+		Dint_copytoptr(resultp1,resultp2,dstptr);
+
+		/* check for inexact */
+		if (Sgl_isinexact_to_fix(src,src_exponent)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	else {
+		Dint_setzero(resultp1,resultp2);
+		Dint_copytoptr(resultp1,resultp2,dstptr);
+
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Single Fixed-point 
+ */
+/*ARGSUSED*/
+int
+dbl_to_sgl_fcnvfxt(
+			dbl_floating_point *srcptr,
+			unsigned int *nullptr,
+			int *dstptr,
+			unsigned int *status)
+{
+	register unsigned int srcp1, srcp2, tempp1, tempp2;
+	register int src_exponent, result;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > SGL_FX_MAX_EXP) {
+		/* check for MININT */
+		if (Dbl_isoverflow_to_int(src_exponent,srcp1,srcp2)) {
+                        if (Dbl_iszero_sign(srcp1)) result = 0x7fffffff;
+                        else result = 0x80000000; 
+
+	                if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                        }
+                        Set_invalidflag();
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		tempp1 = srcp1;
+		tempp2 = srcp2;
+		Dbl_clear_signexponent_set_hidden(tempp1);
+		Int_from_dbl_mantissa(tempp1,tempp2,src_exponent);
+		if (Dbl_isone_sign(srcp1) && (src_exponent <= SGL_FX_MAX_EXP))
+			result = -Dbl_allp1(tempp1);
+		else result = Dbl_allp1(tempp1);
+		*dstptr = result;
+
+		/* check for inexact */
+		if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	else {
+		*dstptr = 0;
+
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Double Fixed-point 
+ */
+/*ARGSUSED*/
+int
+dbl_to_dbl_fcnvfxt(
+			dbl_floating_point *srcptr,
+			unsigned int *nullptr,
+			dbl_integer *dstptr,
+			unsigned int *status)
+{
+	register int src_exponent, resultp1;
+	register unsigned int srcp1, srcp2, tempp1, tempp2, resultp2;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > DBL_FX_MAX_EXP) {
+		/* check for MININT */
+		if ((src_exponent > DBL_FX_MAX_EXP + 1) || 
+		Dbl_isnotzero_mantissa(srcp1,srcp2) || Dbl_iszero_sign(srcp1)) {
+                        if (Dbl_iszero_sign(srcp1)) {
+                              resultp1 = 0x7fffffff;
+			      resultp2 = 0xffffffff;
+			}
+                        else {
+			    resultp1 = 0x80000000; 
+			    resultp2 = 0;
+			}
+	                if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                        }
+                        Set_invalidflag();
+    		        Dint_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		tempp1 = srcp1;
+		tempp2 = srcp2;
+		Dbl_clear_signexponent_set_hidden(tempp1);
+		Dint_from_dbl_mantissa(tempp1,tempp2,src_exponent,
+		resultp1,resultp2);
+		if (Dbl_isone_sign(srcp1)) {
+			Dint_setone_sign(resultp1,resultp2);
+		}
+		Dint_copytoptr(resultp1,resultp2,dstptr);
+
+		/* check for inexact */
+		if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	else {
+		Dint_setzero(resultp1,resultp2);
+		Dint_copytoptr(resultp1,resultp2,dstptr);
+
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	return(NOEXCEPTION);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/fcnvuf.c linux-2.4.20/arch/parisc/math-emu/fcnvuf.c
--- linux-2.4.19/arch/parisc/math-emu/fcnvuf.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/fcnvuf.c	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,318 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/fcnvuf.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Fixed point to Floating-point Converts
+ *
+ *  External Interfaces:
+ *	dbl_to_dbl_fcnvuf(srcptr,nullptr,dstptr,status)
+ *	dbl_to_sgl_fcnvuf(srcptr,nullptr,dstptr,status)
+ *	sgl_to_dbl_fcnvuf(srcptr,nullptr,dstptr,status)
+ *	sgl_to_sgl_fcnvuf(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/************************************************************************
+ *  Fixed point to Floating-point Converts				*
+ ************************************************************************/
+
+/*
+ *  Convert Single Unsigned Fixed to Single Floating-point format
+ */
+
+int
+sgl_to_sgl_fcnvuf(
+			unsigned int *srcptr,
+			unsigned int *nullptr,
+			sgl_floating_point *dstptr,
+			unsigned int *status)
+{
+	register unsigned int src, result = 0;
+	register int dst_exponent;
+
+	src = *srcptr;
+
+	/* Check for zero */ 
+	if (src == 0) { 
+	       	Sgl_setzero(result); 
+		*dstptr = result;
+	       	return(NOEXCEPTION); 
+	} 
+	/*
+	 * Generate exponent and normalized mantissa
+	 */
+	dst_exponent = 16;    /* initialize for normalization */
+	/*
+	 * Check word for most significant bit set.  Returns
+	 * a value in dst_exponent indicating the bit position,
+	 * between -1 and 30.
+	 */
+	Find_ms_one_bit(src,dst_exponent);
+	/*  left justify source, with msb at bit position 0  */
+	src <<= dst_exponent+1;
+	Sgl_set_mantissa(result, src >> SGL_EXP_LENGTH);
+	Sgl_set_exponent(result, 30+SGL_BIAS - dst_exponent);
+
+	/* check for inexact */
+	if (Suint_isinexact_to_sgl(src)) {
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				Sgl_increment(result);
+				break;
+			case ROUNDMINUS: /* never negative */
+				break;
+			case ROUNDNEAREST:
+				Sgl_roundnearest_from_suint(src,result);
+				break;
+		}
+		if (Is_inexacttrap_enabled()) {
+			*dstptr = result;
+			return(INEXACTEXCEPTION);
+		}
+		else Set_inexactflag();
+	}
+	*dstptr = result;
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Single Unsigned Fixed to Double Floating-point 
+ */
+
+int
+sgl_to_dbl_fcnvuf(
+			unsigned int *srcptr,
+			unsigned int *nullptr,
+			dbl_floating_point *dstptr,
+			unsigned int *status)
+{
+	register int dst_exponent;
+	register unsigned int src, resultp1 = 0, resultp2 = 0;
+
+	src = *srcptr;
+
+	/* Check for zero */
+	if (src == 0) {
+	       	Dbl_setzero(resultp1,resultp2);
+	       	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	       	return(NOEXCEPTION);
+	}
+	/*
+	 * Generate exponent and normalized mantissa
+	 */
+	dst_exponent = 16;    /* initialize for normalization */
+	/*
+	 * Check word for most significant bit set.  Returns
+	 * a value in dst_exponent indicating the bit position,
+	 * between -1 and 30.
+	 */
+	Find_ms_one_bit(src,dst_exponent);
+	/*  left justify source, with msb at bit position 0  */
+	src <<= dst_exponent+1;
+	Dbl_set_mantissap1(resultp1, src >> DBL_EXP_LENGTH);
+	Dbl_set_mantissap2(resultp2, src << (32-DBL_EXP_LENGTH));
+	Dbl_set_exponent(resultp1, (30+DBL_BIAS) - dst_exponent);
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Unsigned Fixed to Single Floating-point 
+ */
+
+int
+dbl_to_sgl_fcnvuf(
+			dbl_unsigned *srcptr,
+			unsigned int *nullptr,
+			sgl_floating_point *dstptr,
+			unsigned int *status)
+{
+	int dst_exponent;
+	unsigned int srcp1, srcp2, result = 0;
+
+	Duint_copyfromptr(srcptr,srcp1,srcp2);
+
+	/* Check for zero */
+	if (srcp1 == 0 && srcp2 == 0) {
+	       	Sgl_setzero(result);
+	       	*dstptr = result;
+	       	return(NOEXCEPTION);
+	}
+	/*
+	 * Generate exponent and normalized mantissa
+	 */
+	dst_exponent = 16;    /* initialize for normalization */
+	if (srcp1 == 0) {
+		/*
+		 * Check word for most significant bit set.  Returns
+		 * a value in dst_exponent indicating the bit position,
+		 * between -1 and 30.
+		 */
+		Find_ms_one_bit(srcp2,dst_exponent);
+		/*  left justify source, with msb at bit position 0  */
+		srcp1 = srcp2 << dst_exponent+1;    
+		srcp2 = 0;
+		/*
+		 *  since msb set is in second word, need to 
+		 *  adjust bit position count
+		 */
+		dst_exponent += 32;
+	}
+	else {
+		/*
+		 * Check word for most significant bit set.  Returns
+		 * a value in dst_exponent indicating the bit position,
+		 * between -1 and 30.
+		 *
+		 */
+		Find_ms_one_bit(srcp1,dst_exponent);
+		/*  left justify source, with msb at bit position 0  */
+		if (dst_exponent >= 0) {
+			Variable_shift_double(srcp1,srcp2,(31-dst_exponent),
+			 srcp1); 
+			srcp2 <<= dst_exponent+1;
+		}
+	}
+	Sgl_set_mantissa(result, srcp1 >> SGL_EXP_LENGTH);
+	Sgl_set_exponent(result, (62+SGL_BIAS) - dst_exponent);
+
+	/* check for inexact */
+	if (Duint_isinexact_to_sgl(srcp1,srcp2)) {
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				Sgl_increment(result);
+				break;
+			case ROUNDMINUS: /* never negative */
+				break;
+			case ROUNDNEAREST:
+				Sgl_roundnearest_from_duint(srcp1,srcp2,result);
+				break;
+		}
+		if (Is_inexacttrap_enabled()) {
+			*dstptr = result;
+			return(INEXACTEXCEPTION);
+		}
+		else Set_inexactflag();
+	}
+	*dstptr = result;
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Unsigned Fixed to Double Floating-point 
+ */
+
+int
+dbl_to_dbl_fcnvuf(
+		    dbl_unsigned *srcptr,
+		    unsigned int *nullptr,
+		    dbl_floating_point *dstptr,
+		    unsigned int *status)
+{
+	register int dst_exponent;
+	register unsigned int srcp1, srcp2, resultp1 = 0, resultp2 = 0;
+
+	Duint_copyfromptr(srcptr,srcp1,srcp2);
+
+	/* Check for zero */
+	if (srcp1 == 0 && srcp2 ==0) {
+	       	Dbl_setzero(resultp1,resultp2);
+	       	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	       	return(NOEXCEPTION);
+	}
+	/*
+	 * Generate exponent and normalized mantissa
+	 */
+	dst_exponent = 16;    /* initialize for normalization */
+	if (srcp1 == 0) {
+		/*
+		 * Check word for most significant bit set.  Returns
+		 * a value in dst_exponent indicating the bit position,
+		 * between -1 and 30.
+		 */
+		Find_ms_one_bit(srcp2,dst_exponent);
+		/*  left justify source, with msb at bit position 0  */
+		srcp1 = srcp2 << dst_exponent+1;
+		srcp2 = 0;
+		/*
+		 *  since msb set is in second word, need to 
+		 *  adjust bit position count
+		 */
+		dst_exponent += 32;
+	}
+	else {
+		/*
+		 * Check word for most significant bit set.  Returns
+		 * a value in dst_exponent indicating the bit position,
+		 * between -1 and 30.
+		 */
+		Find_ms_one_bit(srcp1,dst_exponent);
+		/*  left justify source, with msb at bit position 0  */
+		if (dst_exponent >= 0) {
+			Variable_shift_double(srcp1,srcp2,(31-dst_exponent),
+			 srcp1); 
+			srcp2 <<= dst_exponent+1;
+		}
+	}
+	Dbl_set_mantissap1(resultp1, srcp1 >> DBL_EXP_LENGTH);
+	Shiftdouble(srcp1,srcp2,DBL_EXP_LENGTH,resultp2);
+	Dbl_set_exponent(resultp1, (62+DBL_BIAS) - dst_exponent);
+
+	/* check for inexact */
+	if (Duint_isinexact_to_dbl(srcp2)) {
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				Dbl_increment(resultp1,resultp2);
+				break;
+			case ROUNDMINUS: /* never negative */
+				break;
+			case ROUNDNEAREST:
+				Dbl_roundnearest_from_duint(srcp2,resultp1,
+				resultp2);
+				break;
+		}
+		if (Is_inexacttrap_enabled()) {
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(INEXACTEXCEPTION);
+		}
+		else Set_inexactflag();
+	}
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	return(NOEXCEPTION);
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/fcnvxf.c linux-2.4.20/arch/parisc/math-emu/fcnvxf.c
--- linux-2.4.19/arch/parisc/math-emu/fcnvxf.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/fcnvxf.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,386 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/fcnvxf.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single Fixed-point to Single Floating-point
+ *	Single Fixed-point to Double Floating-point 
+ *	Double Fixed-point to Single Floating-point 
+ *	Double Fixed-point to Double Floating-point 
+ *
+ *  External Interfaces:
+ *	dbl_to_dbl_fcnvxf(srcptr,nullptr,dstptr,status)
+ *	dbl_to_sgl_fcnvxf(srcptr,nullptr,dstptr,status)
+ *	sgl_to_dbl_fcnvxf(srcptr,nullptr,dstptr,status)
+ *	sgl_to_sgl_fcnvxf(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/*
+ *  Convert single fixed-point to single floating-point format
+ */
+
+int
+sgl_to_sgl_fcnvxf(
+		    int *srcptr,
+		    unsigned int *nullptr,
+		    sgl_floating_point *dstptr,
+		    unsigned int *status)
+{
+	register int src, dst_exponent;
+	register unsigned int result = 0;
+
+	src = *srcptr;
+	/* 
+	 * set sign bit of result and get magnitude of source 
+	 */
+	if (src < 0) {
+		Sgl_setone_sign(result);  
+		Int_negate(src);
+	}
+	else {
+		Sgl_setzero_sign(result);
+        	/* Check for zero */ 
+        	if (src == 0) { 
+                	Sgl_setzero(result); 
+			*dstptr = result;
+                	return(NOEXCEPTION); 
+        	} 
+	}
+	/*
+	 * Generate exponent and normalized mantissa
+	 */
+	dst_exponent = 16;    /* initialize for normalization */
+	/*
+	 * Check word for most significant bit set.  Returns
+	 * a value in dst_exponent indicating the bit position,
+	 * between -1 and 30.
+	 */
+	Find_ms_one_bit(src,dst_exponent);
+	/*  left justify source, with msb at bit position 1  */
+	if (dst_exponent >= 0) src <<= dst_exponent;
+	else src = 1 << 30;
+	Sgl_set_mantissa(result, src >> (SGL_EXP_LENGTH-1));
+	Sgl_set_exponent(result, 30+SGL_BIAS - dst_exponent);
+
+	/* check for inexact */
+	if (Int_isinexact_to_sgl(src)) {
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Sgl_iszero_sign(result)) 
+					Sgl_increment(result);
+				break;
+			case ROUNDMINUS: 
+				if (Sgl_isone_sign(result)) 
+					Sgl_increment(result);
+				break;
+			case ROUNDNEAREST:
+				Sgl_roundnearest_from_int(src,result);
+		}
+		if (Is_inexacttrap_enabled()) {
+			*dstptr = result;
+			return(INEXACTEXCEPTION);
+		}
+		else Set_inexactflag();
+	}
+	*dstptr = result;
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Single Fixed-point to Double Floating-point 
+ */
+
+int
+sgl_to_dbl_fcnvxf(
+		    int *srcptr,
+		    unsigned int *nullptr,
+		    dbl_floating_point *dstptr,
+		    unsigned int *status)
+{
+	register int src, dst_exponent;
+	register unsigned int resultp1 = 0, resultp2 = 0;
+
+	src = *srcptr;
+	/* 
+	 * set sign bit of result and get magnitude of source 
+	 */
+	if (src < 0) {
+		Dbl_setone_sign(resultp1);  
+		Int_negate(src);
+	}
+	else {
+		Dbl_setzero_sign(resultp1);
+        	/* Check for zero */
+        	if (src == 0) {
+                	Dbl_setzero(resultp1,resultp2);
+                	Dbl_copytoptr(resultp1,resultp2,dstptr);
+                	return(NOEXCEPTION);
+        	}
+	}
+	/*
+	 * Generate exponent and normalized mantissa
+	 */
+	dst_exponent = 16;    /* initialize for normalization */
+	/*
+	 * Check word for most significant bit set.  Returns
+	 * a value in dst_exponent indicating the bit position,
+	 * between -1 and 30.
+	 */
+	Find_ms_one_bit(src,dst_exponent);
+	/*  left justify source, with msb at bit position 1  */
+	if (dst_exponent >= 0) src <<= dst_exponent;
+	else src = 1 << 30;
+	Dbl_set_mantissap1(resultp1, src >> DBL_EXP_LENGTH - 1);
+	Dbl_set_mantissap2(resultp2, src << (33-DBL_EXP_LENGTH));
+	Dbl_set_exponent(resultp1, (30+DBL_BIAS) - dst_exponent);
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Fixed-point to Single Floating-point 
+ */
+
+int
+dbl_to_sgl_fcnvxf(
+			dbl_integer *srcptr,
+			unsigned int *nullptr,
+			sgl_floating_point *dstptr,
+			unsigned int *status)
+{
+	int dst_exponent, srcp1;
+	unsigned int result = 0, srcp2;
+
+	Dint_copyfromptr(srcptr,srcp1,srcp2);
+	/* 
+	 * set sign bit of result and get magnitude of source 
+	 */
+	if (srcp1 < 0) {
+		Sgl_setone_sign(result);  
+		Dint_negate(srcp1,srcp2);
+	}
+	else {
+		Sgl_setzero_sign(result);
+        	/* Check for zero */
+        	if (srcp1 == 0 && srcp2 == 0) {
+                	Sgl_setzero(result);
+                	*dstptr = result;
+                	return(NOEXCEPTION);
+		}
+        }
+	/*
+	 * Generate exponent and normalized mantissa
+	 */
+	dst_exponent = 16;    /* initialize for normalization */
+	if (srcp1 == 0) {
+		/*
+		 * Check word for most significant bit set.  Returns
+		 * a value in dst_exponent indicating the bit position,
+		 * between -1 and 30.
+		 */
+		Find_ms_one_bit(srcp2,dst_exponent);
+		/*  left justify source, with msb at bit position 1  */
+		if (dst_exponent >= 0) {
+			srcp1 = srcp2 << dst_exponent;    
+			srcp2 = 0;
+		}
+		else {
+			srcp1 = srcp2 >> 1;
+			srcp2 <<= 31; 
+		}
+		/*
+		 *  since msb set is in second word, need to 
+		 *  adjust bit position count
+		 */
+		dst_exponent += 32;
+	}
+	else {
+		/*
+		 * Check word for most significant bit set.  Returns
+		 * a value in dst_exponent indicating the bit position,
+		 * between -1 and 30.
+		 *
+		 */
+		Find_ms_one_bit(srcp1,dst_exponent);
+		/*  left justify source, with msb at bit position 1  */
+		if (dst_exponent > 0) {
+			Variable_shift_double(srcp1,srcp2,(32-dst_exponent),
+			 srcp1); 
+			srcp2 <<= dst_exponent;
+		}
+		/*
+		 * If dst_exponent = 0, we don't need to shift anything.
+		 * If dst_exponent = -1, src = - 2**63 so we won't need to 
+		 * shift srcp2.
+		 */
+		else srcp1 >>= -(dst_exponent);
+	}
+	Sgl_set_mantissa(result, srcp1 >> SGL_EXP_LENGTH - 1);
+	Sgl_set_exponent(result, (62+SGL_BIAS) - dst_exponent);
+
+	/* check for inexact */
+	if (Dint_isinexact_to_sgl(srcp1,srcp2)) {
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Sgl_iszero_sign(result)) 
+					Sgl_increment(result);
+				break;
+			case ROUNDMINUS: 
+				if (Sgl_isone_sign(result)) 
+					Sgl_increment(result);
+				break;
+			case ROUNDNEAREST:
+				Sgl_roundnearest_from_dint(srcp1,srcp2,result);
+		}
+		if (Is_inexacttrap_enabled()) {
+			*dstptr = result;
+			return(INEXACTEXCEPTION);
+		}
+		else Set_inexactflag();
+	}
+	*dstptr = result;
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Fixed-point to Double Floating-point 
+ */
+
+int
+dbl_to_dbl_fcnvxf(
+		    dbl_integer *srcptr,
+		    unsigned int *nullptr,
+		    dbl_floating_point *dstptr,
+		    unsigned int *status)
+{
+	register int srcp1, dst_exponent;
+	register unsigned int srcp2, resultp1 = 0, resultp2 = 0;
+
+	Dint_copyfromptr(srcptr,srcp1,srcp2);
+	/* 
+	 * set sign bit of result and get magnitude of source 
+	 */
+	if (srcp1 < 0) {
+		Dbl_setone_sign(resultp1);
+		Dint_negate(srcp1,srcp2);
+	}
+	else {
+		Dbl_setzero_sign(resultp1);
+        	/* Check for zero */
+        	if (srcp1 == 0 && srcp2 ==0) {
+                	Dbl_setzero(resultp1,resultp2);
+                	Dbl_copytoptr(resultp1,resultp2,dstptr);
+                	return(NOEXCEPTION);
+		}
+        }
+	/*
+	 * Generate exponent and normalized mantissa
+	 */
+	dst_exponent = 16;    /* initialize for normalization */
+	if (srcp1 == 0) {
+		/*
+		 * Check word for most significant bit set.  Returns
+		 * a value in dst_exponent indicating the bit position,
+		 * between -1 and 30.
+		 */
+		Find_ms_one_bit(srcp2,dst_exponent);
+		/*  left justify source, with msb at bit position 1  */
+		if (dst_exponent >= 0) {
+			srcp1 = srcp2 << dst_exponent;    
+			srcp2 = 0;
+		}
+		else {
+			srcp1 = srcp2 >> 1;
+			srcp2 <<= 31;
+		}
+		/*
+		 *  since msb set is in second word, need to 
+		 *  adjust bit position count
+		 */
+		dst_exponent += 32;
+	}
+	else {
+		/*
+		 * Check word for most significant bit set.  Returns
+		 * a value in dst_exponent indicating the bit position,
+		 * between -1 and 30.
+		 */
+		Find_ms_one_bit(srcp1,dst_exponent);
+		/*  left justify source, with msb at bit position 1  */
+		if (dst_exponent > 0) {
+			Variable_shift_double(srcp1,srcp2,(32-dst_exponent),
+			 srcp1); 
+			srcp2 <<= dst_exponent;
+		}
+		/*
+		 * If dst_exponent = 0, we don't need to shift anything.
+		 * If dst_exponent = -1, src = - 2**63 so we won't need to 
+		 * shift srcp2.
+		 */
+		else srcp1 >>= -(dst_exponent);
+	}
+	Dbl_set_mantissap1(resultp1, srcp1 >> (DBL_EXP_LENGTH-1));
+	Shiftdouble(srcp1,srcp2,DBL_EXP_LENGTH-1,resultp2);
+	Dbl_set_exponent(resultp1, (62+DBL_BIAS) - dst_exponent);
+
+	/* check for inexact */
+	if (Dint_isinexact_to_dbl(srcp2)) {
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Dbl_iszero_sign(resultp1)) {
+					Dbl_increment(resultp1,resultp2);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Dbl_isone_sign(resultp1)) {
+					Dbl_increment(resultp1,resultp2);
+				}
+				break;
+			case ROUNDNEAREST:
+				Dbl_roundnearest_from_dint(srcp2,resultp1,
+				resultp2);
+		}
+		if (Is_inexacttrap_enabled()) {
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(INEXACTEXCEPTION);
+		}
+		else Set_inexactflag();
+	}
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	return(NOEXCEPTION);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/float.h linux-2.4.20/arch/parisc/math-emu/float.h
--- linux-2.4.19/arch/parisc/math-emu/float.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/float.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,582 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ * 
+ *  File: 
+ *      @(#)	pa/spmath/float.h		$Revision: 1.2 $
+ * 
+ *  Purpose:
+ *      <<please update with a synopis of the functionality provided by this file>>
+ * 
+ *  BE header:  no
+ *
+ *  Shipped:  yes
+ *	/usr/conf/pa/spmath/float.h
+ *
+ * END_DESC  
+*/
+
+#ifdef __NO_PA_HDRS
+    PA header file -- do not include this header file for non-PA builds.
+#endif
+
+#include "fpbits.h"
+#include "hppa.h"
+/*
+ * Want to pick up the FPU capability flags, not the PDC structures.
+ * 'LOCORE' isn't really true in this case, but we don't want the C structures
+ * so it suits our purposes
+ */
+#define LOCORE
+#include "fpu.h"
+
+/*
+ * Declare the basic structures for the 3 different
+ * floating-point precisions.
+ *        
+ * Single number  
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s|       exp     |               mantissa                      |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define	Sall(object) (object)
+#define	Ssign(object) Bitfield_extract( 0,  1,object)
+#define	Ssignedsign(object) Bitfield_signed_extract( 0,  1,object)
+#define	Sexponent(object) Bitfield_extract( 1,  8,object)
+#define	Smantissa(object) Bitfield_mask( 9, 23,object)
+#define	Ssignaling(object) Bitfield_extract( 9,  1,object)
+#define	Ssignalingnan(object) Bitfield_extract( 1,  9,object)
+#define	Shigh2mantissa(object) Bitfield_extract( 9,  2,object)
+#define	Sexponentmantissa(object) Bitfield_mask( 1, 31,object)
+#define	Ssignexponent(object) Bitfield_extract( 0,  9,object)
+#define	Shidden(object) Bitfield_extract( 8,  1,object)
+#define	Shiddenoverflow(object) Bitfield_extract( 7,  1,object)
+#define	Shiddenhigh7mantissa(object) Bitfield_extract( 8,  8,object)
+#define	Shiddenhigh3mantissa(object) Bitfield_extract( 8,  4,object)
+#define	Slow(object) Bitfield_mask( 31,  1,object)
+#define	Slow4(object) Bitfield_mask( 28,  4,object)
+#define	Slow31(object) Bitfield_mask( 1, 31,object)
+#define	Shigh31(object) Bitfield_extract( 0, 31,object)
+#define	Ssignedhigh31(object) Bitfield_signed_extract( 0, 31,object)
+#define	Shigh4(object) Bitfield_extract( 0,  4,object)
+#define	Sbit24(object) Bitfield_extract( 24,  1,object)
+#define	Sbit28(object) Bitfield_extract( 28,  1,object)
+#define	Sbit29(object) Bitfield_extract( 29,  1,object)
+#define	Sbit30(object) Bitfield_extract( 30,  1,object)
+#define	Sbit31(object) Bitfield_mask( 31,  1,object)
+
+#define Deposit_ssign(object,value) Bitfield_deposit(value,0,1,object)
+#define Deposit_sexponent(object,value) Bitfield_deposit(value,1,8,object)
+#define Deposit_smantissa(object,value) Bitfield_deposit(value,9,23,object)
+#define Deposit_shigh2mantissa(object,value) Bitfield_deposit(value,9,2,object)
+#define Deposit_sexponentmantissa(object,value) \
+    Bitfield_deposit(value,1,31,object)
+#define Deposit_ssignexponent(object,value) Bitfield_deposit(value,0,9,object)
+#define Deposit_slow(object,value) Bitfield_deposit(value,31,1,object)
+#define Deposit_shigh4(object,value) Bitfield_deposit(value,0,4,object)
+
+#define	Is_ssign(object) Bitfield_mask( 0,  1,object)
+#define	Is_ssignaling(object) Bitfield_mask( 9,  1,object)
+#define	Is_shidden(object) Bitfield_mask( 8,  1,object)
+#define	Is_shiddenoverflow(object) Bitfield_mask( 7,  1,object)
+#define	Is_slow(object) Bitfield_mask( 31,  1,object)
+#define	Is_sbit24(object) Bitfield_mask( 24,  1,object)
+#define	Is_sbit28(object) Bitfield_mask( 28,  1,object)
+#define	Is_sbit29(object) Bitfield_mask( 29,  1,object)
+#define	Is_sbit30(object) Bitfield_mask( 30,  1,object)
+#define	Is_sbit31(object) Bitfield_mask( 31,  1,object)
+
+/* 
+ * Double number.
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s|       exponent      |          mantissa part 1              |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                    mantissa part 2                            |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define Dallp1(object) (object)
+#define Dsign(object) Bitfield_extract( 0,  1,object)
+#define Dsignedsign(object) Bitfield_signed_extract( 0,  1,object)
+#define Dexponent(object) Bitfield_extract( 1,  11,object)
+#define Dmantissap1(object) Bitfield_mask( 12, 20,object)
+#define Dsignaling(object) Bitfield_extract( 12,  1,object)
+#define Dsignalingnan(object) Bitfield_extract( 1,  12,object)
+#define Dhigh2mantissa(object) Bitfield_extract( 12,  2,object)
+#define Dexponentmantissap1(object) Bitfield_mask( 1, 31,object)
+#define Dsignexponent(object) Bitfield_extract( 0, 12,object)
+#define Dhidden(object) Bitfield_extract( 11,  1,object)
+#define Dhiddenoverflow(object) Bitfield_extract( 10,  1,object)
+#define Dhiddenhigh7mantissa(object) Bitfield_extract( 11,  8,object)
+#define Dhiddenhigh3mantissa(object) Bitfield_extract( 11,  4,object)
+#define Dlowp1(object) Bitfield_mask( 31,  1,object)
+#define Dlow31p1(object) Bitfield_mask( 1, 31,object)
+#define Dhighp1(object) Bitfield_extract( 0,  1,object)
+#define Dhigh4p1(object) Bitfield_extract( 0,  4,object)
+#define Dhigh31p1(object) Bitfield_extract( 0, 31,object)
+#define Dsignedhigh31p1(object) Bitfield_signed_extract( 0, 31,object)
+#define Dbit3p1(object) Bitfield_extract( 3,  1,object)
+
+#define Deposit_dsign(object,value) Bitfield_deposit(value,0,1,object)
+#define Deposit_dexponent(object,value) Bitfield_deposit(value,1,11,object)
+#define Deposit_dmantissap1(object,value) Bitfield_deposit(value,12,20,object)
+#define Deposit_dhigh2mantissa(object,value) Bitfield_deposit(value,12,2,object)
+#define Deposit_dexponentmantissap1(object,value) \
+    Bitfield_deposit(value,1,31,object)
+#define Deposit_dsignexponent(object,value) Bitfield_deposit(value,0,12,object)
+#define Deposit_dlowp1(object,value) Bitfield_deposit(value,31,1,object)
+#define Deposit_dhigh4p1(object,value) Bitfield_deposit(value,0,4,object)
+
+#define Is_dsign(object) Bitfield_mask( 0,  1,object)
+#define Is_dsignaling(object) Bitfield_mask( 12,  1,object)
+#define Is_dhidden(object) Bitfield_mask( 11,  1,object)
+#define Is_dhiddenoverflow(object) Bitfield_mask( 10,  1,object)
+#define Is_dlowp1(object) Bitfield_mask( 31,  1,object)
+#define Is_dhighp1(object) Bitfield_mask( 0,  1,object)
+#define Is_dbit3p1(object) Bitfield_mask( 3,  1,object)
+
+#define Dallp2(object) (object)
+#define Dmantissap2(object) (object)
+#define Dlowp2(object) Bitfield_mask( 31,  1,object)
+#define Dlow4p2(object) Bitfield_mask( 28,  4,object)
+#define Dlow31p2(object) Bitfield_mask( 1, 31,object)
+#define Dhighp2(object) Bitfield_extract( 0,  1,object)
+#define Dhigh31p2(object) Bitfield_extract( 0, 31,object)
+#define Dbit2p2(object) Bitfield_extract( 2,  1,object)
+#define Dbit3p2(object) Bitfield_extract( 3,  1,object)
+#define Dbit21p2(object) Bitfield_extract( 21,  1,object)
+#define Dbit28p2(object) Bitfield_extract( 28,  1,object)
+#define Dbit29p2(object) Bitfield_extract( 29,  1,object)
+#define Dbit30p2(object) Bitfield_extract( 30,  1,object)
+#define Dbit31p2(object) Bitfield_mask( 31,  1,object)
+
+#define Deposit_dlowp2(object,value) Bitfield_deposit(value,31,1,object)
+
+#define Is_dlowp2(object) Bitfield_mask( 31,  1,object)
+#define Is_dhighp2(object) Bitfield_mask( 0,  1,object)
+#define Is_dbit2p2(object) Bitfield_mask( 2,  1,object)
+#define Is_dbit3p2(object) Bitfield_mask( 3,  1,object)
+#define Is_dbit21p2(object) Bitfield_mask( 21,  1,object)
+#define Is_dbit28p2(object) Bitfield_mask( 28,  1,object)
+#define Is_dbit29p2(object) Bitfield_mask( 29,  1,object)
+#define Is_dbit30p2(object) Bitfield_mask( 30,  1,object)
+#define Is_dbit31p2(object) Bitfield_mask( 31,  1,object)
+
+/* 
+ * Quad number.
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s|          exponent           |      mantissa part 1          |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                    mantissa part 2                            |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                    mantissa part 3                            |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                    mantissa part 4                            |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+typedef struct
+    {
+    union
+	{
+	struct { unsigned qallp1; } u_qallp1;
+/* Not needed for now...
+	Bitfield_extract( 0,  1,u_qsign,qsign)
+	Bitfield_signed_extract( 0,  1,u_qsignedsign,qsignedsign)
+	Bitfield_extract( 1, 15,u_qexponent,qexponent)
+	Bitfield_extract(16, 16,u_qmantissap1,qmantissap1)
+	Bitfield_extract(16,  1,u_qsignaling,qsignaling)
+	Bitfield_extract(1,  16,u_qsignalingnan,qsignalingnan)
+	Bitfield_extract(16,  2,u_qhigh2mantissa,qhigh2mantissa)
+	Bitfield_extract( 1, 31,u_qexponentmantissap1,qexponentmantissap1)
+	Bitfield_extract( 0, 16,u_qsignexponent,qsignexponent)
+	Bitfield_extract(15,  1,u_qhidden,qhidden)
+	Bitfield_extract(14,  1,u_qhiddenoverflow,qhiddenoverflow)
+	Bitfield_extract(15,  8,u_qhiddenhigh7mantissa,qhiddenhigh7mantissa)
+	Bitfield_extract(15,  4,u_qhiddenhigh3mantissa,qhiddenhigh3mantissa)
+	Bitfield_extract(31,  1,u_qlowp1,qlowp1)
+	Bitfield_extract( 1, 31,u_qlow31p1,qlow31p1)
+	Bitfield_extract( 0,  1,u_qhighp1,qhighp1)
+	Bitfield_extract( 0,  4,u_qhigh4p1,qhigh4p1)
+	Bitfield_extract( 0, 31,u_qhigh31p1,qhigh31p1)
+  */
+	} quad_u1;
+    union
+	{
+	struct { unsigned qallp2; } u_qallp2;
+  /* Not needed for now...
+	Bitfield_extract(31,  1,u_qlowp2,qlowp2)
+	Bitfield_extract( 1, 31,u_qlow31p2,qlow31p2)
+	Bitfield_extract( 0,  1,u_qhighp2,qhighp2)
+	Bitfield_extract( 0, 31,u_qhigh31p2,qhigh31p2)
+   */
+	} quad_u2;
+    union
+	{
+	struct { unsigned qallp3; } u_qallp3;
+  /* Not needed for now...
+	Bitfield_extract(31,  1,u_qlowp3,qlowp3)
+	Bitfield_extract( 1, 31,u_qlow31p3,qlow31p3)
+	Bitfield_extract( 0,  1,u_qhighp3,qhighp3)
+	Bitfield_extract( 0, 31,u_qhigh31p3,qhigh31p3)
+   */ 
+	} quad_u3;
+    union
+	{
+	struct { unsigned qallp4; } u_qallp4;
+    /* Not need for now...
+	Bitfield_extract(31,  1,u_qlowp4,qlowp4)
+	Bitfield_extract( 1, 31,u_qlow31p4,qlow31p4)
+	Bitfield_extract( 0,  1,u_qhighp4,qhighp4)
+	Bitfield_extract( 0, 31,u_qhigh31p4,qhigh31p4)
+     */
+	} quad_u4;
+    } quad_floating_point;
+
+/* Extension - An additional structure to hold the guard, round and
+ *             sticky bits during computations.
+ */
+#define Extall(object) (object)
+#define Extsign(object) Bitfield_extract( 0,  1,object)
+#define Exthigh31(object) Bitfield_extract( 0, 31,object)
+#define Extlow31(object) Bitfield_extract( 1, 31,object)
+#define Extlow(object) Bitfield_extract( 31,  1,object)
+
+/*
+ * Single extended - The upper word is just like single precision,
+ *                 but one additional word of mantissa is needed.
+ */
+#define Sextallp1(object) (object)
+#define Sextallp2(object) (object)
+#define Sextlowp1(object) Bitfield_extract( 31,  1,object)
+#define Sexthighp2(object) Bitfield_extract( 0,  1,object)
+#define Sextlow31p2(object) Bitfield_extract( 1, 31,object)
+#define Sexthiddenoverflow(object) Bitfield_extract( 4,  1,object)
+#define Is_sexthiddenoverflow(object) Bitfield_mask( 4,  1,object)
+
+/*
+ * Double extended - The upper two words are just like double precision,
+ *		     but two additional words of mantissa are needed.
+ */
+#define Dextallp1(object) (object)
+#define Dextallp2(object) (object)
+#define Dextallp3(object) (object)
+#define Dextallp4(object) (object)
+#define Dextlowp2(object) Bitfield_extract( 31,  1,object)
+#define Dexthighp3(object) Bitfield_extract( 0,  1,object)
+#define Dextlow31p3(object) Bitfield_extract( 1, 31,object)
+#define Dexthiddenoverflow(object) Bitfield_extract( 10,  1,object)
+#define Is_dexthiddenoverflow(object) Bitfield_mask( 10,  1,object)
+#define Deposit_dextlowp4(object,value) Bitfield_deposit(value,31,1,object)
+
+/*
+ * Declare the basic structures for the 3 different
+ * fixed-point precisions.
+ *        
+ * Single number  
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s|                    integer                                  |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+typedef int sgl_integer;
+
+/* 
+ * Double number.
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s|                     high integer                            |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                       low integer                             |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+struct dint {
+        int  wd0;
+        unsigned int wd1;
+};
+
+struct dblwd {
+        unsigned int wd0;
+        unsigned int wd1;
+};
+
+/* 
+ * Quad number.
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s|                  integer part1                              |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                    integer part 2                             |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                    integer part 3                             |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                    integer part 4                             |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+
+struct quadwd {
+        int  wd0;
+        unsigned int wd1;
+        unsigned int wd2;
+        unsigned int wd3;
+};
+
+typedef struct quadwd quad_integer;
+
+
+/* useful typedefs */
+typedef unsigned int sgl_floating_point;
+typedef struct dblwd dbl_floating_point;
+typedef struct dint dbl_integer;
+typedef struct dblwd dbl_unsigned;
+
+/* 
+ * Define the different precisions' parameters.
+ */
+#define SGL_BITLENGTH 32
+#define SGL_EMAX 127
+#define SGL_EMIN (-126)
+#define SGL_BIAS 127
+#define SGL_WRAP 192
+#define SGL_INFINITY_EXPONENT (SGL_EMAX+SGL_BIAS+1)
+#define SGL_THRESHOLD 32
+#define SGL_EXP_LENGTH 8
+#define SGL_P 24
+
+#define DBL_BITLENGTH 64
+#define DBL_EMAX 1023
+#define DBL_EMIN (-1022)
+#define DBL_BIAS 1023
+#define DBL_WRAP 1536
+#define DBL_INFINITY_EXPONENT (DBL_EMAX+DBL_BIAS+1)
+#define DBL_THRESHOLD 64
+#define DBL_EXP_LENGTH 11
+#define DBL_P 53
+
+#define QUAD_BITLENGTH 128
+#define QUAD_EMAX 16383
+#define QUAD_EMIN (-16382)
+#define QUAD_BIAS 16383
+#define QUAD_WRAP 24576
+#define QUAD_INFINITY_EXPONENT (QUAD_EMAX+QUAD_BIAS+1)
+#define QUAD_P 113
+
+/* Boolean Values etc. */
+#define FALSE 0
+#define TRUE (!FALSE)
+#define NOT !
+#define XOR ^
+
+/* other constants */
+#undef NULL
+#define NULL 0
+#define NIL 0
+#define SGL 0
+#define DBL 1
+#define BADFMT 2
+#define QUAD 3
+
+
+/* Types */
+typedef int boolean;
+typedef int FORMAT;
+typedef int VOID;
+
+
+/* Declare status register equivalent to FPUs architecture.
+ *
+ *  0 1 2 3 4 5 6 7 8 910 1 2 3 4 5 6 7 8 920 1 2 3 4 5 6 7 8 930 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |V|Z|O|U|I|C|  rsv  |  model    | version |RM |rsv|T|r|V|Z|O|U|I|
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define Cbit(object) Bitfield_extract( 5, 1,object)
+#define Tbit(object) Bitfield_extract( 25, 1,object)
+#define Roundingmode(object) Bitfield_extract( 21, 2,object)
+#define Invalidtrap(object) Bitfield_extract( 27, 1,object)
+#define Divisionbyzerotrap(object) Bitfield_extract( 28, 1,object)
+#define Overflowtrap(object) Bitfield_extract( 29, 1,object)
+#define Underflowtrap(object) Bitfield_extract( 30, 1,object)
+#define Inexacttrap(object) Bitfield_extract( 31, 1,object)
+#define Invalidflag(object) Bitfield_extract( 0, 1,object)
+#define Divisionbyzeroflag(object) Bitfield_extract( 1, 1,object)
+#define Overflowflag(object) Bitfield_extract( 2, 1,object)
+#define Underflowflag(object) Bitfield_extract( 3, 1,object)
+#define Inexactflag(object) Bitfield_extract( 4, 1,object)
+#define Allflags(object) Bitfield_extract( 0, 5,object)
+
+/* Definitions relevant to the status register */
+
+/* Rounding Modes */
+#define ROUNDNEAREST 0
+#define ROUNDZERO    1
+#define ROUNDPLUS    2
+#define ROUNDMINUS   3
+
+/* Exceptions */
+#define NOEXCEPTION		0x0
+#define INVALIDEXCEPTION	0x20
+#define DIVISIONBYZEROEXCEPTION	0x10
+#define OVERFLOWEXCEPTION	0x08
+#define UNDERFLOWEXCEPTION	0x04
+#define INEXACTEXCEPTION	0x02
+#define UNIMPLEMENTEDEXCEPTION	0x01
+
+/* New exceptions for the 2E Opcode */
+#define OPC_2E_INVALIDEXCEPTION     0x30
+#define OPC_2E_OVERFLOWEXCEPTION    0x18
+#define OPC_2E_UNDERFLOWEXCEPTION   0x0c
+#define OPC_2E_INEXACTEXCEPTION     0x12
+
+/* Declare exception registers equivalent to FPUs architecture 
+ *
+ *  0 1 2 3 4 5 6 7 8 910 1 2 3 4 5 6 7 8 920 1 2 3 4 5 6 7 8 930 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |excepttype |  r1     | r2/ext  |  operation  |parm |n| t/cond  |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define Allexception(object) (object)
+#define Exceptiontype(object) Bitfield_extract( 0, 6,object)
+#define Instructionfield(object) Bitfield_mask( 6,26,object)
+#define Parmfield(object) Bitfield_extract( 23, 3,object)
+#define Rabit(object) Bitfield_extract( 24, 1,object)
+#define Ibit(object) Bitfield_extract( 25, 1,object)
+
+#define Set_exceptiontype(object,value) Bitfield_deposit(value, 0, 6,object)
+#define Set_parmfield(object,value) Bitfield_deposit(value, 23, 3,object)
+#define Set_exceptiontype_and_instr_field(exception,instruction,object) \
+    object = exception << 26 | instruction
+
+/* Declare the condition field
+ *
+ *  0 1 2 3 4 5 6 7 8 910 1 2 3 4 5 6 7 8 920 1 2 3 4 5 6 7 8 930 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                                                     |G|L|E|U|X|
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define Allexception(object) (object)
+#define Greaterthanbit(object) Bitfield_extract( 27, 1,object)
+#define Lessthanbit(object) Bitfield_extract( 28, 1,object)
+#define Equalbit(object) Bitfield_extract( 29, 1,object)
+#define Unorderedbit(object) Bitfield_extract( 30, 1,object)
+#define Exceptionbit(object) Bitfield_extract( 31, 1,object)
+
+/* An alias name for the status register */
+#define Fpustatus_register (*status)
+
+/**************************************************
+ * Status register referencing and manipulation.  *
+ **************************************************/
+
+/* Rounding mode */
+#define Rounding_mode()  Roundingmode(Fpustatus_register)
+#define Is_rounding_mode(rmode) \
+    (Roundingmode(Fpustatus_register) == rmode)
+#define Set_rounding_mode(value) \
+    Bitfield_deposit(value,21,2,Fpustatus_register)
+
+/* Boolean testing of the trap enable bits */
+#define Is_invalidtrap_enabled() Invalidtrap(Fpustatus_register)
+#define Is_divisionbyzerotrap_enabled() Divisionbyzerotrap(Fpustatus_register)
+#define Is_overflowtrap_enabled() Overflowtrap(Fpustatus_register)
+#define Is_underflowtrap_enabled() Underflowtrap(Fpustatus_register)
+#define Is_inexacttrap_enabled() Inexacttrap(Fpustatus_register)
+
+/* Set the indicated flags in the status register */
+#define Set_invalidflag() Bitfield_deposit(1,0,1,Fpustatus_register)
+#define Set_divisionbyzeroflag() Bitfield_deposit(1,1,1,Fpustatus_register)
+#define Set_overflowflag() Bitfield_deposit(1,2,1,Fpustatus_register)
+#define Set_underflowflag() Bitfield_deposit(1,3,1,Fpustatus_register)
+#define Set_inexactflag() Bitfield_deposit(1,4,1,Fpustatus_register)
+
+#define Clear_all_flags() Bitfield_deposit(0,0,5,Fpustatus_register)
+
+/* Manipulate the trap and condition code bits (tbit and cbit) */
+#define Set_tbit() Bitfield_deposit(1,25,1,Fpustatus_register)
+#define Clear_tbit() Bitfield_deposit(0,25,1,Fpustatus_register)
+#define Is_tbit_set() Tbit(Fpustatus_register)
+#define Is_cbit_set() Cbit(Fpustatus_register)
+
+#define Set_status_cbit(value)  \
+        Bitfield_deposit(value,5,1,Fpustatus_register)
+
+/*******************************
+ * Condition field referencing *
+ *******************************/
+#define Unordered(cond) Unorderedbit(cond)
+#define Equal(cond) Equalbit(cond)
+#define Lessthan(cond) Lessthanbit(cond)
+#define Greaterthan(cond) Greaterthanbit(cond)
+#define Exception(cond) Exceptionbit(cond)
+
+
+/* Defines for the extension */
+#define Ext_isone_sign(extent) (Extsign(extent))
+#define Ext_isnotzero(extent) \
+    (Extall(extent))
+#define Ext_isnotzero_lower(extent) \
+    (Extlow31(extent))
+#define Ext_leftshiftby1(extent) \
+    Extall(extent) <<= 1
+#define Ext_negate(extent) \
+    (int )Extall(extent) = 0 - (int )Extall(extent)
+#define Ext_setone_low(extent) Bitfield_deposit(1,31,1,extent)
+#define Ext_setzero(extent) Extall(extent) = 0
+
+typedef int operation;
+
+/* error messages */
+
+#define		NONE		0
+#define		UNDEFFPINST	1
+
+/* Function definitions: opcode, opclass */
+#define FTEST	(1<<2) | 0
+#define FCPY	(2<<2) | 0
+#define FABS	(3<<2) | 0
+#define FSQRT   (4<<2) | 0
+#define FRND    (5<<2) | 0
+
+#define FCNVFF	(0<<2) | 1
+#define FCNVXF	(1<<2) | 1
+#define FCNVFX	(2<<2) | 1
+#define FCNVFXT	(3<<2) | 1
+
+#define FCMP    (0<<2) | 2
+
+#define FADD	(0<<2) | 3
+#define FSUB	(1<<2) | 3
+#define FMPY	(2<<2) | 3
+#define FDIV	(3<<2) | 3
+#define FREM	(4<<2) | 3
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/fmpyfadd.c linux-2.4.20/arch/parisc/math-emu/fmpyfadd.c
--- linux-2.4.19/arch/parisc/math-emu/fmpyfadd.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/fmpyfadd.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,2655 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/fmpyfadd.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Double Floating-point Multiply Fused Add
+ *	Double Floating-point Multiply Negate Fused Add
+ *	Single Floating-point Multiply Fused Add
+ *	Single Floating-point Multiply Negate Fused Add
+ *
+ *  External Interfaces:
+ *	dbl_fmpyfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+ *	dbl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+ *	sgl_fmpyfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+ *	sgl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+
+
+/*
+ *  Double Floating-point Multiply Fused Add
+ */
+
+int
+dbl_fmpyfadd(
+	    dbl_floating_point *src1ptr,
+	    dbl_floating_point *src2ptr,
+	    dbl_floating_point *src3ptr,
+	    unsigned int *status,
+	    dbl_floating_point *dstptr)
+{
+	unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2, opnd3p1, opnd3p2;
+	register unsigned int tmpresp1, tmpresp2, tmpresp3, tmpresp4;
+	unsigned int rightp1, rightp2, rightp3, rightp4;
+	unsigned int resultp1, resultp2 = 0, resultp3 = 0, resultp4 = 0;
+	register int mpy_exponent, add_exponent, count;
+	boolean inexact = FALSE, is_tiny = FALSE;
+
+	unsigned int signlessleft1, signlessright1, save;
+	register int result_exponent, diff_exponent;
+	int sign_save, jumpsize;
+	
+	Dbl_copyfromptr(src1ptr,opnd1p1,opnd1p2);
+	Dbl_copyfromptr(src2ptr,opnd2p1,opnd2p2);
+	Dbl_copyfromptr(src3ptr,opnd3p1,opnd3p2);
+
+	/* 
+	 * set sign bit of result of multiply
+	 */
+	if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1)) 
+		Dbl_setnegativezerop1(resultp1); 
+	else Dbl_setzerop1(resultp1);
+
+	/*
+	 * Generate multiply exponent 
+	 */
+	mpy_exponent = Dbl_exponent(opnd1p1) + Dbl_exponent(opnd2p1) - DBL_BIAS;
+
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd1p1)) {
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			if (Dbl_isnotnan(opnd2p1,opnd2p2) &&
+			    Dbl_isnotnan(opnd3p1,opnd3p2)) {
+				if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
+					/* 
+					 * invalid since operands are infinity 
+					 * and zero 
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Dbl_makequietnan(resultp1,resultp2);
+					Dbl_copytoptr(resultp1,resultp2,dstptr);
+					return(NOEXCEPTION);
+				}
+				/*
+				 * Check third operand for infinity with a
+				 *  sign opposite of the multiply result
+				 */
+				if (Dbl_isinfinity(opnd3p1,opnd3p2) &&
+				    (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) {
+					/* 
+					 * invalid since attempting a magnitude
+					 * subtraction of infinities
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Dbl_makequietnan(resultp1,resultp2);
+					Dbl_copytoptr(resultp1,resultp2,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+			 	 * return infinity
+			 	 */
+				Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+			/*
+		 	 * is NaN; signaling or quiet?
+		 	 */
+			if (Dbl_isone_signaling(opnd1p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled()) 
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd1p1);
+			}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd2p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd2p1);
+				Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+				return(NOEXCEPTION);
+			}
+			/* 
+			 * is third operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd3p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd3p1);
+				Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+				return(NOEXCEPTION);
+			}
+			/*
+		 	 * return quiet NaN
+		 	 */
+			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd2p1)) {
+		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+			if (Dbl_isnotnan(opnd3p1,opnd3p2)) {
+				if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
+					/* 
+					 * invalid since multiply operands are
+					 * zero & infinity
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Dbl_makequietnan(opnd2p1,opnd2p2);
+					Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+				 * Check third operand for infinity with a
+				 *  sign opposite of the multiply result
+				 */
+				if (Dbl_isinfinity(opnd3p1,opnd3p2) &&
+				    (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) {
+					/* 
+					 * invalid since attempting a magnitude
+					 * subtraction of infinities
+					 */
+					if (Is_invalidtrap_enabled())
+				       		return(OPC_2E_INVALIDEXCEPTION);
+				       	Set_invalidflag();
+				       	Dbl_makequietnan(resultp1,resultp2);
+					Dbl_copytoptr(resultp1,resultp2,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+				 * return infinity
+				 */
+				Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+			/*
+			 * is NaN; signaling or quiet?
+			 */
+			if (Dbl_isone_signaling(opnd2p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd2p1);
+			}
+			/* 
+			 * is third operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd3p1)) {
+			       	/* trap if INVALIDTRAP enabled */
+			       	if (Is_invalidtrap_enabled())
+				   		return(OPC_2E_INVALIDEXCEPTION);
+			       	/* make NaN quiet */
+			       	Set_invalidflag();
+			       	Dbl_set_quiet(opnd3p1);
+				Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+		       		return(NOEXCEPTION);
+			}
+			/*
+			 * return quiet NaN
+			 */
+			Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+
+	/*
+	 * check third operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd3p1)) {
+		if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) {
+			/* return infinity */
+			Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+			return(NOEXCEPTION);
+		} else {
+			/*
+			 * is NaN; signaling or quiet?
+			 */
+			if (Dbl_isone_signaling(opnd3p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd3p1);
+			}
+			/*
+			 * return quiet NaN
+ 			 */
+			Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+			return(NOEXCEPTION);
+		}
+    	}
+
+	/*
+	 * Generate multiply mantissa
+	 */
+	if (Dbl_isnotzero_exponent(opnd1p1)) {
+		/* set hidden bit */
+		Dbl_clear_signexponent_set_hidden(opnd1p1);
+	}
+	else {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			/*
+			 * Perform the add opnd3 with zero here.
+			 */
+			if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) {
+				if (Is_rounding_mode(ROUNDMINUS)) {
+					Dbl_or_signs(opnd3p1,resultp1);
+				} else {
+					Dbl_and_signs(opnd3p1,resultp1);
+				}
+			}
+			/*
+			 * Now let's check for trapped underflow case.
+			 */
+			else if (Dbl_iszero_exponent(opnd3p1) &&
+			         Is_underflowtrap_enabled()) {
+                    		/* need to normalize results mantissa */
+                    		sign_save = Dbl_signextendedsign(opnd3p1);
+				result_exponent = 0;
+                    		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+                    		Dbl_normalize(opnd3p1,opnd3p2,result_exponent);
+                    		Dbl_set_sign(opnd3p1,/*using*/sign_save);
+                    		Dbl_setwrapped_exponent(opnd3p1,result_exponent,
+							unfl);
+                    		Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+                    		/* inexact = FALSE */
+                    		return(OPC_2E_UNDERFLOWEXCEPTION);
+			}
+			Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* is denormalized, adjust exponent */
+		Dbl_clear_signexponent(opnd1p1);
+		Dbl_leftshiftby1(opnd1p1,opnd1p2);
+		Dbl_normalize(opnd1p1,opnd1p2,mpy_exponent);
+	}
+	/* opnd2 needs to have hidden bit set with msb in hidden bit */
+	if (Dbl_isnotzero_exponent(opnd2p1)) {
+		Dbl_clear_signexponent_set_hidden(opnd2p1);
+	}
+	else {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+			/*
+			 * Perform the add opnd3 with zero here.
+			 */
+			if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) {
+				if (Is_rounding_mode(ROUNDMINUS)) {
+					Dbl_or_signs(opnd3p1,resultp1);
+				} else {
+					Dbl_and_signs(opnd3p1,resultp1);
+				}
+			}
+			/*
+			 * Now let's check for trapped underflow case.
+			 */
+			else if (Dbl_iszero_exponent(opnd3p1) &&
+			    Is_underflowtrap_enabled()) {
+                    		/* need to normalize results mantissa */
+                    		sign_save = Dbl_signextendedsign(opnd3p1);
+				result_exponent = 0;
+                    		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+                    		Dbl_normalize(opnd3p1,opnd3p2,result_exponent);
+                    		Dbl_set_sign(opnd3p1,/*using*/sign_save);
+                    		Dbl_setwrapped_exponent(opnd3p1,result_exponent,
+							unfl);
+                    		Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+                    		/* inexact = FALSE */
+				return(OPC_2E_UNDERFLOWEXCEPTION);
+			}
+			Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* is denormalized; want to normalize */
+		Dbl_clear_signexponent(opnd2p1);
+		Dbl_leftshiftby1(opnd2p1,opnd2p2);
+		Dbl_normalize(opnd2p1,opnd2p2,mpy_exponent);
+	}
+
+	/* Multiply the first two source mantissas together */
+
+	/* 
+	 * The intermediate result will be kept in tmpres,
+	 * which needs enough room for 106 bits of mantissa,
+	 * so lets call it a Double extended.
+	 */
+	Dblext_setzero(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+
+	/* 
+	 * Four bits at a time are inspected in each loop, and a 
+	 * simple shift and add multiply algorithm is used. 
+	 */ 
+	for (count = DBL_P-1; count >= 0; count -= 4) {
+		Dblext_rightshiftby4(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+		if (Dbit28p2(opnd1p2)) {
+	 		/* Fourword_add should be an ADD followed by 3 ADDC's */
+			Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4, 
+			 opnd2p1<<3 | opnd2p2>>29, opnd2p2<<3, 0, 0);
+		}
+		if (Dbit29p2(opnd1p2)) {
+			Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+			 opnd2p1<<2 | opnd2p2>>30, opnd2p2<<2, 0, 0);
+		}
+		if (Dbit30p2(opnd1p2)) {
+			Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+			 opnd2p1<<1 | opnd2p2>>31, opnd2p2<<1, 0, 0);
+		}
+		if (Dbit31p2(opnd1p2)) {
+			Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+			 opnd2p1, opnd2p2, 0, 0);
+		}
+		Dbl_rightshiftby4(opnd1p1,opnd1p2);
+	}
+	if (Is_dexthiddenoverflow(tmpresp1)) {
+		/* result mantissa >= 2 (mantissa overflow) */
+		mpy_exponent++;
+		Dblext_rightshiftby1(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+	}
+
+	/*
+	 * Restore the sign of the mpy result which was saved in resultp1.
+	 * The exponent will continue to be kept in mpy_exponent.
+	 */
+	Dblext_set_sign(tmpresp1,Dbl_sign(resultp1));
+
+	/* 
+	 * No rounding is required, since the result of the multiply
+	 * is exact in the extended format.
+	 */
+
+	/*
+	 * Now we are ready to perform the add portion of the operation.
+	 *
+	 * The exponents need to be kept as integers for now, since the
+	 * multiply result might not fit into the exponent field.  We
+	 * can't overflow or underflow because of this yet, since the
+	 * add could bring the final result back into range.
+	 */
+	add_exponent = Dbl_exponent(opnd3p1);
+
+	/*
+	 * Check for denormalized or zero add operand.
+	 */
+	if (add_exponent == 0) {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) {
+			/* right is zero */
+			/* Left can't be zero and must be result.
+			 *
+			 * The final result is now in tmpres and mpy_exponent,
+			 * and needs to be rounded and squeezed back into
+			 * double precision format from double extended.
+			 */
+			result_exponent = mpy_exponent;
+			Dblext_copy(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+				resultp1,resultp2,resultp3,resultp4);
+			sign_save = Dbl_signextendedsign(resultp1);/*save sign*/
+			goto round;
+		}
+
+		/* 
+		 * Neither are zeroes.  
+		 * Adjust exponent and normalize add operand.
+		 */
+		sign_save = Dbl_signextendedsign(opnd3p1);	/* save sign */
+		Dbl_clear_signexponent(opnd3p1);
+		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+		Dbl_normalize(opnd3p1,opnd3p2,add_exponent);
+		Dbl_set_sign(opnd3p1,sign_save);	/* restore sign */
+	} else {
+		Dbl_clear_exponent_set_hidden(opnd3p1);
+	}
+	/*
+	 * Copy opnd3 to the double extended variable called right.
+	 */
+	Dbl_copyto_dblext(opnd3p1,opnd3p2,rightp1,rightp2,rightp3,rightp4);
+
+	/*
+	 * A zero "save" helps discover equal operands (for later),
+	 * and is used in swapping operands (if needed).
+	 */
+	Dblext_xortointp1(tmpresp1,rightp1,/*to*/save);
+
+	/*
+	 * Compare magnitude of operands.
+	 */
+	Dblext_copytoint_exponentmantissap1(tmpresp1,signlessleft1);
+	Dblext_copytoint_exponentmantissap1(rightp1,signlessright1);
+	if (mpy_exponent < add_exponent || mpy_exponent == add_exponent &&
+	    Dblext_ismagnitudeless(tmpresp2,rightp2,signlessleft1,signlessright1)){
+		/*
+		 * Set the left operand to the larger one by XOR swap.
+		 * First finish the first word "save".
+		 */
+		Dblext_xorfromintp1(save,rightp1,/*to*/rightp1);
+		Dblext_xorfromintp1(save,tmpresp1,/*to*/tmpresp1);
+		Dblext_swap_lower(tmpresp2,tmpresp3,tmpresp4,
+			rightp2,rightp3,rightp4);
+		/* also setup exponents used in rest of routine */
+		diff_exponent = add_exponent - mpy_exponent;
+		result_exponent = add_exponent;
+	} else {
+		/* also setup exponents used in rest of routine */
+		diff_exponent = mpy_exponent - add_exponent;
+		result_exponent = mpy_exponent;
+	}
+	/* Invariant: left is not smaller than right. */
+
+	/*
+	 * Special case alignment of operands that would force alignment
+	 * beyond the extent of the extension.  A further optimization
+	 * could special case this but only reduces the path length for
+	 * this infrequent case.
+	 */
+	if (diff_exponent > DBLEXT_THRESHOLD) {
+		diff_exponent = DBLEXT_THRESHOLD;
+	}
+
+	/* Align right operand by shifting it to the right */
+	Dblext_clear_sign(rightp1);
+	Dblext_right_align(rightp1,rightp2,rightp3,rightp4,
+		/*shifted by*/diff_exponent);
+	
+	/* Treat sum and difference of the operands separately. */
+	if ((int)save < 0) {
+		/*
+		 * Difference of the two operands.  Overflow can occur if the
+		 * multiply overflowed.  A borrow can occur out of the hidden
+		 * bit and force a post normalization phase.
+		 */
+		Dblext_subtract(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+			rightp1,rightp2,rightp3,rightp4,
+			resultp1,resultp2,resultp3,resultp4);
+		sign_save = Dbl_signextendedsign(resultp1);
+		if (Dbl_iszero_hidden(resultp1)) {
+			/* Handle normalization */
+		/* A straight foward algorithm would now shift the
+		 * result and extension left until the hidden bit
+		 * becomes one.  Not all of the extension bits need
+		 * participate in the shift.  Only the two most 
+		 * significant bits (round and guard) are needed.
+		 * If only a single shift is needed then the guard
+		 * bit becomes a significant low order bit and the
+		 * extension must participate in the rounding.
+		 * If more than a single shift is needed, then all
+		 * bits to the right of the guard bit are zeros, 
+		 * and the guard bit may or may not be zero. */
+			Dblext_leftshiftby1(resultp1,resultp2,resultp3,
+				resultp4);
+
+			/* Need to check for a zero result.  The sign and
+			 * exponent fields have already been zeroed.  The more
+			 * efficient test of the full object can be used.
+			 */
+			 if(Dblext_iszero(resultp1,resultp2,resultp3,resultp4)){
+				/* Must have been "x-x" or "x+(-x)". */
+				if (Is_rounding_mode(ROUNDMINUS))
+					Dbl_setone_sign(resultp1);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+			result_exponent--;
+
+			/* Look to see if normalization is finished. */
+			if (Dbl_isone_hidden(resultp1)) {
+				/* No further normalization is needed */
+				goto round;
+			}
+
+			/* Discover first one bit to determine shift amount.
+			 * Use a modified binary search.  We have already
+			 * shifted the result one position right and still
+			 * not found a one so the remainder of the extension
+			 * must be zero and simplifies rounding. */
+			/* Scan bytes */
+			while (Dbl_iszero_hiddenhigh7mantissa(resultp1)) {
+				Dblext_leftshiftby8(resultp1,resultp2,resultp3,resultp4);
+				result_exponent -= 8;
+			}
+			/* Now narrow it down to the nibble */
+			if (Dbl_iszero_hiddenhigh3mantissa(resultp1)) {
+				/* The lower nibble contains the
+				 * normalizing one */
+				Dblext_leftshiftby4(resultp1,resultp2,resultp3,resultp4);
+				result_exponent -= 4;
+			}
+			/* Select case where first bit is set (already
+			 * normalized) otherwise select the proper shift. */
+			jumpsize = Dbl_hiddenhigh3mantissa(resultp1);
+			if (jumpsize <= 7) switch(jumpsize) {
+			case 1:
+				Dblext_leftshiftby3(resultp1,resultp2,resultp3,
+					resultp4);
+				result_exponent -= 3;
+				break;
+			case 2:
+			case 3:
+				Dblext_leftshiftby2(resultp1,resultp2,resultp3,
+					resultp4);
+				result_exponent -= 2;
+				break;
+			case 4:
+			case 5:
+			case 6:
+			case 7:
+				Dblext_leftshiftby1(resultp1,resultp2,resultp3,
+					resultp4);
+				result_exponent -= 1;
+				break;
+			}
+		} /* end if (hidden...)... */
+	/* Fall through and round */
+	} /* end if (save < 0)... */
+	else {
+		/* Add magnitudes */
+		Dblext_addition(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+			rightp1,rightp2,rightp3,rightp4,
+			/*to*/resultp1,resultp2,resultp3,resultp4);
+		sign_save = Dbl_signextendedsign(resultp1);
+		if (Dbl_isone_hiddenoverflow(resultp1)) {
+	    		/* Prenormalization required. */
+	    		Dblext_arithrightshiftby1(resultp1,resultp2,resultp3,
+				resultp4);
+	    		result_exponent++;
+		} /* end if hiddenoverflow... */
+	} /* end else ...add magnitudes... */
+
+	/* Round the result.  If the extension and lower two words are
+	 * all zeros, then the result is exact.  Otherwise round in the
+	 * correct direction.  Underflow is possible. If a postnormalization
+	 * is necessary, then the mantissa is all zeros so no shift is needed.
+	 */
+  round:
+	if (result_exponent <= 0 && !Is_underflowtrap_enabled()) {
+		Dblext_denormalize(resultp1,resultp2,resultp3,resultp4,
+			result_exponent,is_tiny);
+	}
+	Dbl_set_sign(resultp1,/*using*/sign_save);
+	if (Dblext_isnotzero_mantissap3(resultp3) || 
+	    Dblext_isnotzero_mantissap4(resultp4)) {
+		inexact = TRUE;
+		switch(Rounding_mode()) {
+		case ROUNDNEAREST: /* The default. */
+			if (Dblext_isone_highp3(resultp3)) {
+				/* at least 1/2 ulp */
+				if (Dblext_isnotzero_low31p3(resultp3) ||
+				    Dblext_isnotzero_mantissap4(resultp4) ||
+				    Dblext_isone_lowp2(resultp2)) {
+					/* either exactly half way and odd or
+					 * more than 1/2ulp */
+					Dbl_increment(resultp1,resultp2);
+				}
+			}
+	    		break;
+
+		case ROUNDPLUS:
+	    		if (Dbl_iszero_sign(resultp1)) {
+				/* Round up positive results */
+				Dbl_increment(resultp1,resultp2);
+			}
+			break;
+	    
+		case ROUNDMINUS:
+	    		if (Dbl_isone_sign(resultp1)) {
+				/* Round down negative results */
+				Dbl_increment(resultp1,resultp2);
+			}
+	    
+		case ROUNDZERO:;
+			/* truncate is simple */
+		} /* end switch... */
+		if (Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
+	}
+	if (result_exponent >= DBL_INFINITY_EXPONENT) {
+                /* trap if OVERFLOWTRAP enabled */
+                if (Is_overflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+                        Dbl_copytoptr(resultp1,resultp2,dstptr);
+                        if (inexact)
+                            if (Is_inexacttrap_enabled())
+                                return (OPC_2E_OVERFLOWEXCEPTION |
+					OPC_2E_INEXACTEXCEPTION);
+                            else Set_inexactflag();
+                        return (OPC_2E_OVERFLOWEXCEPTION);
+                }
+                inexact = TRUE;
+                Set_overflowflag();
+                /* set result to infinity or largest number */
+                Dbl_setoverflow(resultp1,resultp2);
+
+	} else if (result_exponent <= 0) {	/* underflow case */
+		if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                	Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+                        if (inexact)
+                            if (Is_inexacttrap_enabled())
+                                return (OPC_2E_UNDERFLOWEXCEPTION |
+					OPC_2E_INEXACTEXCEPTION);
+                            else Set_inexactflag();
+	    		return(OPC_2E_UNDERFLOWEXCEPTION);
+		}
+		else if (inexact && is_tiny) Set_underflowflag();
+	}
+	else Dbl_set_exponent(resultp1,result_exponent);
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	if (inexact) 
+		if (Is_inexacttrap_enabled()) return(OPC_2E_INEXACTEXCEPTION);
+		else Set_inexactflag();
+    	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point Multiply Negate Fused Add
+ */
+
+dbl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+
+dbl_floating_point *src1ptr, *src2ptr, *src3ptr, *dstptr;
+unsigned int *status;
+{
+	unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2, opnd3p1, opnd3p2;
+	register unsigned int tmpresp1, tmpresp2, tmpresp3, tmpresp4;
+	unsigned int rightp1, rightp2, rightp3, rightp4;
+	unsigned int resultp1, resultp2 = 0, resultp3 = 0, resultp4 = 0;
+	register int mpy_exponent, add_exponent, count;
+	boolean inexact = FALSE, is_tiny = FALSE;
+
+	unsigned int signlessleft1, signlessright1, save;
+	register int result_exponent, diff_exponent;
+	int sign_save, jumpsize;
+	
+	Dbl_copyfromptr(src1ptr,opnd1p1,opnd1p2);
+	Dbl_copyfromptr(src2ptr,opnd2p1,opnd2p2);
+	Dbl_copyfromptr(src3ptr,opnd3p1,opnd3p2);
+
+	/* 
+	 * set sign bit of result of multiply
+	 */
+	if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1)) 
+		Dbl_setzerop1(resultp1);
+	else
+		Dbl_setnegativezerop1(resultp1); 
+
+	/*
+	 * Generate multiply exponent 
+	 */
+	mpy_exponent = Dbl_exponent(opnd1p1) + Dbl_exponent(opnd2p1) - DBL_BIAS;
+
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd1p1)) {
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			if (Dbl_isnotnan(opnd2p1,opnd2p2) &&
+			    Dbl_isnotnan(opnd3p1,opnd3p2)) {
+				if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
+					/* 
+					 * invalid since operands are infinity 
+					 * and zero 
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Dbl_makequietnan(resultp1,resultp2);
+					Dbl_copytoptr(resultp1,resultp2,dstptr);
+					return(NOEXCEPTION);
+				}
+				/*
+				 * Check third operand for infinity with a
+				 *  sign opposite of the multiply result
+				 */
+				if (Dbl_isinfinity(opnd3p1,opnd3p2) &&
+				    (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) {
+					/* 
+					 * invalid since attempting a magnitude
+					 * subtraction of infinities
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Dbl_makequietnan(resultp1,resultp2);
+					Dbl_copytoptr(resultp1,resultp2,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+			 	 * return infinity
+			 	 */
+				Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+			/*
+		 	 * is NaN; signaling or quiet?
+		 	 */
+			if (Dbl_isone_signaling(opnd1p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled()) 
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd1p1);
+			}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd2p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd2p1);
+				Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+				return(NOEXCEPTION);
+			}
+			/* 
+			 * is third operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd3p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd3p1);
+				Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+				return(NOEXCEPTION);
+			}
+			/*
+		 	 * return quiet NaN
+		 	 */
+			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd2p1)) {
+		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+			if (Dbl_isnotnan(opnd3p1,opnd3p2)) {
+				if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
+					/* 
+					 * invalid since multiply operands are
+					 * zero & infinity
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Dbl_makequietnan(opnd2p1,opnd2p2);
+					Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+				 * Check third operand for infinity with a
+				 *  sign opposite of the multiply result
+				 */
+				if (Dbl_isinfinity(opnd3p1,opnd3p2) &&
+				    (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) {
+					/* 
+					 * invalid since attempting a magnitude
+					 * subtraction of infinities
+					 */
+					if (Is_invalidtrap_enabled())
+				       		return(OPC_2E_INVALIDEXCEPTION);
+				       	Set_invalidflag();
+				       	Dbl_makequietnan(resultp1,resultp2);
+					Dbl_copytoptr(resultp1,resultp2,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+				 * return infinity
+				 */
+				Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+			/*
+			 * is NaN; signaling or quiet?
+			 */
+			if (Dbl_isone_signaling(opnd2p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd2p1);
+			}
+			/* 
+			 * is third operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd3p1)) {
+			       	/* trap if INVALIDTRAP enabled */
+			       	if (Is_invalidtrap_enabled())
+				   		return(OPC_2E_INVALIDEXCEPTION);
+			       	/* make NaN quiet */
+			       	Set_invalidflag();
+			       	Dbl_set_quiet(opnd3p1);
+				Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+		       		return(NOEXCEPTION);
+			}
+			/*
+			 * return quiet NaN
+			 */
+			Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+
+	/*
+	 * check third operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd3p1)) {
+		if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) {
+			/* return infinity */
+			Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+			return(NOEXCEPTION);
+		} else {
+			/*
+			 * is NaN; signaling or quiet?
+			 */
+			if (Dbl_isone_signaling(opnd3p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd3p1);
+			}
+			/*
+			 * return quiet NaN
+ 			 */
+			Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+			return(NOEXCEPTION);
+		}
+    	}
+
+	/*
+	 * Generate multiply mantissa
+	 */
+	if (Dbl_isnotzero_exponent(opnd1p1)) {
+		/* set hidden bit */
+		Dbl_clear_signexponent_set_hidden(opnd1p1);
+	}
+	else {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			/*
+			 * Perform the add opnd3 with zero here.
+			 */
+			if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) {
+				if (Is_rounding_mode(ROUNDMINUS)) {
+					Dbl_or_signs(opnd3p1,resultp1);
+				} else {
+					Dbl_and_signs(opnd3p1,resultp1);
+				}
+			}
+			/*
+			 * Now let's check for trapped underflow case.
+			 */
+			else if (Dbl_iszero_exponent(opnd3p1) &&
+			         Is_underflowtrap_enabled()) {
+                    		/* need to normalize results mantissa */
+                    		sign_save = Dbl_signextendedsign(opnd3p1);
+				result_exponent = 0;
+                    		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+                    		Dbl_normalize(opnd3p1,opnd3p2,result_exponent);
+                    		Dbl_set_sign(opnd3p1,/*using*/sign_save);
+                    		Dbl_setwrapped_exponent(opnd3p1,result_exponent,
+							unfl);
+                    		Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+                    		/* inexact = FALSE */
+                    		return(OPC_2E_UNDERFLOWEXCEPTION);
+			}
+			Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* is denormalized, adjust exponent */
+		Dbl_clear_signexponent(opnd1p1);
+		Dbl_leftshiftby1(opnd1p1,opnd1p2);
+		Dbl_normalize(opnd1p1,opnd1p2,mpy_exponent);
+	}
+	/* opnd2 needs to have hidden bit set with msb in hidden bit */
+	if (Dbl_isnotzero_exponent(opnd2p1)) {
+		Dbl_clear_signexponent_set_hidden(opnd2p1);
+	}
+	else {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+			/*
+			 * Perform the add opnd3 with zero here.
+			 */
+			if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) {
+				if (Is_rounding_mode(ROUNDMINUS)) {
+					Dbl_or_signs(opnd3p1,resultp1);
+				} else {
+					Dbl_and_signs(opnd3p1,resultp1);
+				}
+			}
+			/*
+			 * Now let's check for trapped underflow case.
+			 */
+			else if (Dbl_iszero_exponent(opnd3p1) &&
+			    Is_underflowtrap_enabled()) {
+                    		/* need to normalize results mantissa */
+                    		sign_save = Dbl_signextendedsign(opnd3p1);
+				result_exponent = 0;
+                    		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+                    		Dbl_normalize(opnd3p1,opnd3p2,result_exponent);
+                    		Dbl_set_sign(opnd3p1,/*using*/sign_save);
+                    		Dbl_setwrapped_exponent(opnd3p1,result_exponent,
+							unfl);
+                    		Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+                    		/* inexact = FALSE */
+                    		return(OPC_2E_UNDERFLOWEXCEPTION);
+			}
+			Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* is denormalized; want to normalize */
+		Dbl_clear_signexponent(opnd2p1);
+		Dbl_leftshiftby1(opnd2p1,opnd2p2);
+		Dbl_normalize(opnd2p1,opnd2p2,mpy_exponent);
+	}
+
+	/* Multiply the first two source mantissas together */
+
+	/* 
+	 * The intermediate result will be kept in tmpres,
+	 * which needs enough room for 106 bits of mantissa,
+	 * so lets call it a Double extended.
+	 */
+	Dblext_setzero(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+
+	/* 
+	 * Four bits at a time are inspected in each loop, and a 
+	 * simple shift and add multiply algorithm is used. 
+	 */ 
+	for (count = DBL_P-1; count >= 0; count -= 4) {
+		Dblext_rightshiftby4(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+		if (Dbit28p2(opnd1p2)) {
+	 		/* Fourword_add should be an ADD followed by 3 ADDC's */
+			Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4, 
+			 opnd2p1<<3 | opnd2p2>>29, opnd2p2<<3, 0, 0);
+		}
+		if (Dbit29p2(opnd1p2)) {
+			Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+			 opnd2p1<<2 | opnd2p2>>30, opnd2p2<<2, 0, 0);
+		}
+		if (Dbit30p2(opnd1p2)) {
+			Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+			 opnd2p1<<1 | opnd2p2>>31, opnd2p2<<1, 0, 0);
+		}
+		if (Dbit31p2(opnd1p2)) {
+			Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+			 opnd2p1, opnd2p2, 0, 0);
+		}
+		Dbl_rightshiftby4(opnd1p1,opnd1p2);
+	}
+	if (Is_dexthiddenoverflow(tmpresp1)) {
+		/* result mantissa >= 2 (mantissa overflow) */
+		mpy_exponent++;
+		Dblext_rightshiftby1(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+	}
+
+	/*
+	 * Restore the sign of the mpy result which was saved in resultp1.
+	 * The exponent will continue to be kept in mpy_exponent.
+	 */
+	Dblext_set_sign(tmpresp1,Dbl_sign(resultp1));
+
+	/* 
+	 * No rounding is required, since the result of the multiply
+	 * is exact in the extended format.
+	 */
+
+	/*
+	 * Now we are ready to perform the add portion of the operation.
+	 *
+	 * The exponents need to be kept as integers for now, since the
+	 * multiply result might not fit into the exponent field.  We
+	 * can't overflow or underflow because of this yet, since the
+	 * add could bring the final result back into range.
+	 */
+	add_exponent = Dbl_exponent(opnd3p1);
+
+	/*
+	 * Check for denormalized or zero add operand.
+	 */
+	if (add_exponent == 0) {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) {
+			/* right is zero */
+			/* Left can't be zero and must be result.
+			 *
+			 * The final result is now in tmpres and mpy_exponent,
+			 * and needs to be rounded and squeezed back into
+			 * double precision format from double extended.
+			 */
+			result_exponent = mpy_exponent;
+			Dblext_copy(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+				resultp1,resultp2,resultp3,resultp4);
+			sign_save = Dbl_signextendedsign(resultp1);/*save sign*/
+			goto round;
+		}
+
+		/* 
+		 * Neither are zeroes.  
+		 * Adjust exponent and normalize add operand.
+		 */
+		sign_save = Dbl_signextendedsign(opnd3p1);	/* save sign */
+		Dbl_clear_signexponent(opnd3p1);
+		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+		Dbl_normalize(opnd3p1,opnd3p2,add_exponent);
+		Dbl_set_sign(opnd3p1,sign_save);	/* restore sign */
+	} else {
+		Dbl_clear_exponent_set_hidden(opnd3p1);
+	}
+	/*
+	 * Copy opnd3 to the double extended variable called right.
+	 */
+	Dbl_copyto_dblext(opnd3p1,opnd3p2,rightp1,rightp2,rightp3,rightp4);
+
+	/*
+	 * A zero "save" helps discover equal operands (for later),
+	 * and is used in swapping operands (if needed).
+	 */
+	Dblext_xortointp1(tmpresp1,rightp1,/*to*/save);
+
+	/*
+	 * Compare magnitude of operands.
+	 */
+	Dblext_copytoint_exponentmantissap1(tmpresp1,signlessleft1);
+	Dblext_copytoint_exponentmantissap1(rightp1,signlessright1);
+	if (mpy_exponent < add_exponent || mpy_exponent == add_exponent &&
+	    Dblext_ismagnitudeless(tmpresp2,rightp2,signlessleft1,signlessright1)){
+		/*
+		 * Set the left operand to the larger one by XOR swap.
+		 * First finish the first word "save".
+		 */
+		Dblext_xorfromintp1(save,rightp1,/*to*/rightp1);
+		Dblext_xorfromintp1(save,tmpresp1,/*to*/tmpresp1);
+		Dblext_swap_lower(tmpresp2,tmpresp3,tmpresp4,
+			rightp2,rightp3,rightp4);
+		/* also setup exponents used in rest of routine */
+		diff_exponent = add_exponent - mpy_exponent;
+		result_exponent = add_exponent;
+	} else {
+		/* also setup exponents used in rest of routine */
+		diff_exponent = mpy_exponent - add_exponent;
+		result_exponent = mpy_exponent;
+	}
+	/* Invariant: left is not smaller than right. */
+
+	/*
+	 * Special case alignment of operands that would force alignment
+	 * beyond the extent of the extension.  A further optimization
+	 * could special case this but only reduces the path length for
+	 * this infrequent case.
+	 */
+	if (diff_exponent > DBLEXT_THRESHOLD) {
+		diff_exponent = DBLEXT_THRESHOLD;
+	}
+
+	/* Align right operand by shifting it to the right */
+	Dblext_clear_sign(rightp1);
+	Dblext_right_align(rightp1,rightp2,rightp3,rightp4,
+		/*shifted by*/diff_exponent);
+	
+	/* Treat sum and difference of the operands separately. */
+	if ((int)save < 0) {
+		/*
+		 * Difference of the two operands.  Overflow can occur if the
+		 * multiply overflowed.  A borrow can occur out of the hidden
+		 * bit and force a post normalization phase.
+		 */
+		Dblext_subtract(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+			rightp1,rightp2,rightp3,rightp4,
+			resultp1,resultp2,resultp3,resultp4);
+		sign_save = Dbl_signextendedsign(resultp1);
+		if (Dbl_iszero_hidden(resultp1)) {
+			/* Handle normalization */
+		/* A straight foward algorithm would now shift the
+		 * result and extension left until the hidden bit
+		 * becomes one.  Not all of the extension bits need
+		 * participate in the shift.  Only the two most 
+		 * significant bits (round and guard) are needed.
+		 * If only a single shift is needed then the guard
+		 * bit becomes a significant low order bit and the
+		 * extension must participate in the rounding.
+		 * If more than a single shift is needed, then all
+		 * bits to the right of the guard bit are zeros, 
+		 * and the guard bit may or may not be zero. */
+			Dblext_leftshiftby1(resultp1,resultp2,resultp3,
+				resultp4);
+
+			/* Need to check for a zero result.  The sign and
+			 * exponent fields have already been zeroed.  The more
+			 * efficient test of the full object can be used.
+			 */
+			 if (Dblext_iszero(resultp1,resultp2,resultp3,resultp4)) {
+				/* Must have been "x-x" or "x+(-x)". */
+				if (Is_rounding_mode(ROUNDMINUS))
+					Dbl_setone_sign(resultp1);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+			result_exponent--;
+
+			/* Look to see if normalization is finished. */
+			if (Dbl_isone_hidden(resultp1)) {
+				/* No further normalization is needed */
+				goto round;
+			}
+
+			/* Discover first one bit to determine shift amount.
+			 * Use a modified binary search.  We have already
+			 * shifted the result one position right and still
+			 * not found a one so the remainder of the extension
+			 * must be zero and simplifies rounding. */
+			/* Scan bytes */
+			while (Dbl_iszero_hiddenhigh7mantissa(resultp1)) {
+				Dblext_leftshiftby8(resultp1,resultp2,resultp3,resultp4);
+				result_exponent -= 8;
+			}
+			/* Now narrow it down to the nibble */
+			if (Dbl_iszero_hiddenhigh3mantissa(resultp1)) {
+				/* The lower nibble contains the
+				 * normalizing one */
+				Dblext_leftshiftby4(resultp1,resultp2,resultp3,resultp4);
+				result_exponent -= 4;
+			}
+			/* Select case where first bit is set (already
+			 * normalized) otherwise select the proper shift. */
+			jumpsize = Dbl_hiddenhigh3mantissa(resultp1);
+			if (jumpsize <= 7) switch(jumpsize) {
+			case 1:
+				Dblext_leftshiftby3(resultp1,resultp2,resultp3,
+					resultp4);
+				result_exponent -= 3;
+				break;
+			case 2:
+			case 3:
+				Dblext_leftshiftby2(resultp1,resultp2,resultp3,
+					resultp4);
+				result_exponent -= 2;
+				break;
+			case 4:
+			case 5:
+			case 6:
+			case 7:
+				Dblext_leftshiftby1(resultp1,resultp2,resultp3,
+					resultp4);
+				result_exponent -= 1;
+				break;
+			}
+		} /* end if (hidden...)... */
+	/* Fall through and round */
+	} /* end if (save < 0)... */
+	else {
+		/* Add magnitudes */
+		Dblext_addition(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+			rightp1,rightp2,rightp3,rightp4,
+			/*to*/resultp1,resultp2,resultp3,resultp4);
+		sign_save = Dbl_signextendedsign(resultp1);
+		if (Dbl_isone_hiddenoverflow(resultp1)) {
+	    		/* Prenormalization required. */
+	    		Dblext_arithrightshiftby1(resultp1,resultp2,resultp3,
+				resultp4);
+	    		result_exponent++;
+		} /* end if hiddenoverflow... */
+	} /* end else ...add magnitudes... */
+
+	/* Round the result.  If the extension and lower two words are
+	 * all zeros, then the result is exact.  Otherwise round in the
+	 * correct direction.  Underflow is possible. If a postnormalization
+	 * is necessary, then the mantissa is all zeros so no shift is needed.
+	 */
+  round:
+	if (result_exponent <= 0 && !Is_underflowtrap_enabled()) {
+		Dblext_denormalize(resultp1,resultp2,resultp3,resultp4,
+			result_exponent,is_tiny);
+	}
+	Dbl_set_sign(resultp1,/*using*/sign_save);
+	if (Dblext_isnotzero_mantissap3(resultp3) || 
+	    Dblext_isnotzero_mantissap4(resultp4)) {
+		inexact = TRUE;
+		switch(Rounding_mode()) {
+		case ROUNDNEAREST: /* The default. */
+			if (Dblext_isone_highp3(resultp3)) {
+				/* at least 1/2 ulp */
+				if (Dblext_isnotzero_low31p3(resultp3) ||
+				    Dblext_isnotzero_mantissap4(resultp4) ||
+				    Dblext_isone_lowp2(resultp2)) {
+					/* either exactly half way and odd or
+					 * more than 1/2ulp */
+					Dbl_increment(resultp1,resultp2);
+				}
+			}
+	    		break;
+
+		case ROUNDPLUS:
+	    		if (Dbl_iszero_sign(resultp1)) {
+				/* Round up positive results */
+				Dbl_increment(resultp1,resultp2);
+			}
+			break;
+	    
+		case ROUNDMINUS:
+	    		if (Dbl_isone_sign(resultp1)) {
+				/* Round down negative results */
+				Dbl_increment(resultp1,resultp2);
+			}
+	    
+		case ROUNDZERO:;
+			/* truncate is simple */
+		} /* end switch... */
+		if (Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
+	}
+	if (result_exponent >= DBL_INFINITY_EXPONENT) {
+		/* Overflow */
+		if (Is_overflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+                        Dbl_copytoptr(resultp1,resultp2,dstptr);
+                        if (inexact)
+                            if (Is_inexacttrap_enabled())
+                                return (OPC_2E_OVERFLOWEXCEPTION |
+					OPC_2E_INEXACTEXCEPTION);
+                            else Set_inexactflag();
+                        return (OPC_2E_OVERFLOWEXCEPTION);
+		}
+		inexact = TRUE;
+		Set_overflowflag();
+		Dbl_setoverflow(resultp1,resultp2);
+	} else if (result_exponent <= 0) {	/* underflow case */
+		if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                	Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+                        if (inexact)
+                            if (Is_inexacttrap_enabled())
+                                return (OPC_2E_UNDERFLOWEXCEPTION |
+					OPC_2E_INEXACTEXCEPTION);
+                            else Set_inexactflag();
+	    		return(OPC_2E_UNDERFLOWEXCEPTION);
+		}
+		else if (inexact && is_tiny) Set_underflowflag();
+	}
+	else Dbl_set_exponent(resultp1,result_exponent);
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	if (inexact) 
+		if (Is_inexacttrap_enabled()) return(OPC_2E_INEXACTEXCEPTION);
+		else Set_inexactflag();
+    	return(NOEXCEPTION);
+}
+
+/*
+ *  Single Floating-point Multiply Fused Add
+ */
+
+sgl_fmpyfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+
+sgl_floating_point *src1ptr, *src2ptr, *src3ptr, *dstptr;
+unsigned int *status;
+{
+	unsigned int opnd1, opnd2, opnd3;
+	register unsigned int tmpresp1, tmpresp2;
+	unsigned int rightp1, rightp2;
+	unsigned int resultp1, resultp2 = 0;
+	register int mpy_exponent, add_exponent, count;
+	boolean inexact = FALSE, is_tiny = FALSE;
+
+	unsigned int signlessleft1, signlessright1, save;
+	register int result_exponent, diff_exponent;
+	int sign_save, jumpsize;
+	
+	Sgl_copyfromptr(src1ptr,opnd1);
+	Sgl_copyfromptr(src2ptr,opnd2);
+	Sgl_copyfromptr(src3ptr,opnd3);
+
+	/* 
+	 * set sign bit of result of multiply
+	 */
+	if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) 
+		Sgl_setnegativezero(resultp1); 
+	else Sgl_setzero(resultp1);
+
+	/*
+	 * Generate multiply exponent 
+	 */
+	mpy_exponent = Sgl_exponent(opnd1) + Sgl_exponent(opnd2) - SGL_BIAS;
+
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd1)) {
+		if (Sgl_iszero_mantissa(opnd1)) {
+			if (Sgl_isnotnan(opnd2) && Sgl_isnotnan(opnd3)) {
+				if (Sgl_iszero_exponentmantissa(opnd2)) {
+					/* 
+					 * invalid since operands are infinity 
+					 * and zero 
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Sgl_makequietnan(resultp1);
+					Sgl_copytoptr(resultp1,dstptr);
+					return(NOEXCEPTION);
+				}
+				/*
+				 * Check third operand for infinity with a
+				 *  sign opposite of the multiply result
+				 */
+				if (Sgl_isinfinity(opnd3) &&
+				    (Sgl_sign(resultp1) ^ Sgl_sign(opnd3))) {
+					/* 
+					 * invalid since attempting a magnitude
+					 * subtraction of infinities
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Sgl_makequietnan(resultp1);
+					Sgl_copytoptr(resultp1,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+			 	 * return infinity
+			 	 */
+				Sgl_setinfinity_exponentmantissa(resultp1);
+				Sgl_copytoptr(resultp1,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+			/*
+		 	 * is NaN; signaling or quiet?
+		 	 */
+			if (Sgl_isone_signaling(opnd1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled()) 
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd1);
+			}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd2)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd2);
+				Sgl_copytoptr(opnd2,dstptr);
+				return(NOEXCEPTION);
+			}
+			/* 
+			 * is third operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd3)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd3);
+				Sgl_copytoptr(opnd3,dstptr);
+				return(NOEXCEPTION);
+			}
+			/*
+		 	 * return quiet NaN
+		 	 */
+			Sgl_copytoptr(opnd1,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd2)) {
+		if (Sgl_iszero_mantissa(opnd2)) {
+			if (Sgl_isnotnan(opnd3)) {
+				if (Sgl_iszero_exponentmantissa(opnd1)) {
+					/* 
+					 * invalid since multiply operands are
+					 * zero & infinity
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Sgl_makequietnan(opnd2);
+					Sgl_copytoptr(opnd2,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+				 * Check third operand for infinity with a
+				 *  sign opposite of the multiply result
+				 */
+				if (Sgl_isinfinity(opnd3) &&
+				    (Sgl_sign(resultp1) ^ Sgl_sign(opnd3))) {
+					/* 
+					 * invalid since attempting a magnitude
+					 * subtraction of infinities
+					 */
+					if (Is_invalidtrap_enabled())
+				       		return(OPC_2E_INVALIDEXCEPTION);
+				       	Set_invalidflag();
+				       	Sgl_makequietnan(resultp1);
+					Sgl_copytoptr(resultp1,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+				 * return infinity
+				 */
+				Sgl_setinfinity_exponentmantissa(resultp1);
+				Sgl_copytoptr(resultp1,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+			/*
+			 * is NaN; signaling or quiet?
+			 */
+			if (Sgl_isone_signaling(opnd2)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd2);
+			}
+			/* 
+			 * is third operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd3)) {
+			       	/* trap if INVALIDTRAP enabled */
+			       	if (Is_invalidtrap_enabled())
+				   		return(OPC_2E_INVALIDEXCEPTION);
+			       	/* make NaN quiet */
+			       	Set_invalidflag();
+			       	Sgl_set_quiet(opnd3);
+				Sgl_copytoptr(opnd3,dstptr);
+		       		return(NOEXCEPTION);
+			}
+			/*
+			 * return quiet NaN
+			 */
+			Sgl_copytoptr(opnd2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+
+	/*
+	 * check third operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd3)) {
+		if (Sgl_iszero_mantissa(opnd3)) {
+			/* return infinity */
+			Sgl_copytoptr(opnd3,dstptr);
+			return(NOEXCEPTION);
+		} else {
+			/*
+			 * is NaN; signaling or quiet?
+			 */
+			if (Sgl_isone_signaling(opnd3)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd3);
+			}
+			/*
+			 * return quiet NaN
+ 			 */
+			Sgl_copytoptr(opnd3,dstptr);
+			return(NOEXCEPTION);
+		}
+    	}
+
+	/*
+	 * Generate multiply mantissa
+	 */
+	if (Sgl_isnotzero_exponent(opnd1)) {
+		/* set hidden bit */
+		Sgl_clear_signexponent_set_hidden(opnd1);
+	}
+	else {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd1)) {
+			/*
+			 * Perform the add opnd3 with zero here.
+			 */
+			if (Sgl_iszero_exponentmantissa(opnd3)) {
+				if (Is_rounding_mode(ROUNDMINUS)) {
+					Sgl_or_signs(opnd3,resultp1);
+				} else {
+					Sgl_and_signs(opnd3,resultp1);
+				}
+			}
+			/*
+			 * Now let's check for trapped underflow case.
+			 */
+			else if (Sgl_iszero_exponent(opnd3) &&
+			         Is_underflowtrap_enabled()) {
+                    		/* need to normalize results mantissa */
+                    		sign_save = Sgl_signextendedsign(opnd3);
+				result_exponent = 0;
+                    		Sgl_leftshiftby1(opnd3);
+                    		Sgl_normalize(opnd3,result_exponent);
+                    		Sgl_set_sign(opnd3,/*using*/sign_save);
+                    		Sgl_setwrapped_exponent(opnd3,result_exponent,
+							unfl);
+                    		Sgl_copytoptr(opnd3,dstptr);
+                    		/* inexact = FALSE */
+                    		return(OPC_2E_UNDERFLOWEXCEPTION);
+			}
+			Sgl_copytoptr(opnd3,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* is denormalized, adjust exponent */
+		Sgl_clear_signexponent(opnd1);
+		Sgl_leftshiftby1(opnd1);
+		Sgl_normalize(opnd1,mpy_exponent);
+	}
+	/* opnd2 needs to have hidden bit set with msb in hidden bit */
+	if (Sgl_isnotzero_exponent(opnd2)) {
+		Sgl_clear_signexponent_set_hidden(opnd2);
+	}
+	else {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd2)) {
+			/*
+			 * Perform the add opnd3 with zero here.
+			 */
+			if (Sgl_iszero_exponentmantissa(opnd3)) {
+				if (Is_rounding_mode(ROUNDMINUS)) {
+					Sgl_or_signs(opnd3,resultp1);
+				} else {
+					Sgl_and_signs(opnd3,resultp1);
+				}
+			}
+			/*
+			 * Now let's check for trapped underflow case.
+			 */
+			else if (Sgl_iszero_exponent(opnd3) &&
+			    Is_underflowtrap_enabled()) {
+                    		/* need to normalize results mantissa */
+                    		sign_save = Sgl_signextendedsign(opnd3);
+				result_exponent = 0;
+                    		Sgl_leftshiftby1(opnd3);
+                    		Sgl_normalize(opnd3,result_exponent);
+                    		Sgl_set_sign(opnd3,/*using*/sign_save);
+                    		Sgl_setwrapped_exponent(opnd3,result_exponent,
+							unfl);
+                    		Sgl_copytoptr(opnd3,dstptr);
+                    		/* inexact = FALSE */
+                    		return(OPC_2E_UNDERFLOWEXCEPTION);
+			}
+			Sgl_copytoptr(opnd3,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* is denormalized; want to normalize */
+		Sgl_clear_signexponent(opnd2);
+		Sgl_leftshiftby1(opnd2);
+		Sgl_normalize(opnd2,mpy_exponent);
+	}
+
+	/* Multiply the first two source mantissas together */
+
+	/* 
+	 * The intermediate result will be kept in tmpres,
+	 * which needs enough room for 106 bits of mantissa,
+	 * so lets call it a Double extended.
+	 */
+	Sglext_setzero(tmpresp1,tmpresp2);
+
+	/* 
+	 * Four bits at a time are inspected in each loop, and a 
+	 * simple shift and add multiply algorithm is used. 
+	 */ 
+	for (count = SGL_P-1; count >= 0; count -= 4) {
+		Sglext_rightshiftby4(tmpresp1,tmpresp2);
+		if (Sbit28(opnd1)) {
+	 		/* Twoword_add should be an ADD followed by 2 ADDC's */
+			Twoword_add(tmpresp1, tmpresp2, opnd2<<3, 0);
+		}
+		if (Sbit29(opnd1)) {
+			Twoword_add(tmpresp1, tmpresp2, opnd2<<2, 0);
+		}
+		if (Sbit30(opnd1)) {
+			Twoword_add(tmpresp1, tmpresp2, opnd2<<1, 0);
+		}
+		if (Sbit31(opnd1)) {
+			Twoword_add(tmpresp1, tmpresp2, opnd2, 0);
+		}
+		Sgl_rightshiftby4(opnd1);
+	}
+	if (Is_sexthiddenoverflow(tmpresp1)) {
+		/* result mantissa >= 2 (mantissa overflow) */
+		mpy_exponent++;
+		Sglext_rightshiftby4(tmpresp1,tmpresp2);
+	} else {
+		Sglext_rightshiftby3(tmpresp1,tmpresp2);
+	}
+
+	/*
+	 * Restore the sign of the mpy result which was saved in resultp1.
+	 * The exponent will continue to be kept in mpy_exponent.
+	 */
+	Sglext_set_sign(tmpresp1,Sgl_sign(resultp1));
+
+	/* 
+	 * No rounding is required, since the result of the multiply
+	 * is exact in the extended format.
+	 */
+
+	/*
+	 * Now we are ready to perform the add portion of the operation.
+	 *
+	 * The exponents need to be kept as integers for now, since the
+	 * multiply result might not fit into the exponent field.  We
+	 * can't overflow or underflow because of this yet, since the
+	 * add could bring the final result back into range.
+	 */
+	add_exponent = Sgl_exponent(opnd3);
+
+	/*
+	 * Check for denormalized or zero add operand.
+	 */
+	if (add_exponent == 0) {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd3)) {
+			/* right is zero */
+			/* Left can't be zero and must be result.
+			 *
+			 * The final result is now in tmpres and mpy_exponent,
+			 * and needs to be rounded and squeezed back into
+			 * double precision format from double extended.
+			 */
+			result_exponent = mpy_exponent;
+			Sglext_copy(tmpresp1,tmpresp2,resultp1,resultp2);
+			sign_save = Sgl_signextendedsign(resultp1);/*save sign*/
+			goto round;
+		}
+
+		/* 
+		 * Neither are zeroes.  
+		 * Adjust exponent and normalize add operand.
+		 */
+		sign_save = Sgl_signextendedsign(opnd3);	/* save sign */
+		Sgl_clear_signexponent(opnd3);
+		Sgl_leftshiftby1(opnd3);
+		Sgl_normalize(opnd3,add_exponent);
+		Sgl_set_sign(opnd3,sign_save);		/* restore sign */
+	} else {
+		Sgl_clear_exponent_set_hidden(opnd3);
+	}
+	/*
+	 * Copy opnd3 to the double extended variable called right.
+	 */
+	Sgl_copyto_sglext(opnd3,rightp1,rightp2);
+
+	/*
+	 * A zero "save" helps discover equal operands (for later),
+	 * and is used in swapping operands (if needed).
+	 */
+	Sglext_xortointp1(tmpresp1,rightp1,/*to*/save);
+
+	/*
+	 * Compare magnitude of operands.
+	 */
+	Sglext_copytoint_exponentmantissa(tmpresp1,signlessleft1);
+	Sglext_copytoint_exponentmantissa(rightp1,signlessright1);
+	if (mpy_exponent < add_exponent || mpy_exponent == add_exponent &&
+	    Sglext_ismagnitudeless(signlessleft1,signlessright1)) {
+		/*
+		 * Set the left operand to the larger one by XOR swap.
+		 * First finish the first word "save".
+		 */
+		Sglext_xorfromintp1(save,rightp1,/*to*/rightp1);
+		Sglext_xorfromintp1(save,tmpresp1,/*to*/tmpresp1);
+		Sglext_swap_lower(tmpresp2,rightp2);
+		/* also setup exponents used in rest of routine */
+		diff_exponent = add_exponent - mpy_exponent;
+		result_exponent = add_exponent;
+	} else {
+		/* also setup exponents used in rest of routine */
+		diff_exponent = mpy_exponent - add_exponent;
+		result_exponent = mpy_exponent;
+	}
+	/* Invariant: left is not smaller than right. */
+
+	/*
+	 * Special case alignment of operands that would force alignment
+	 * beyond the extent of the extension.  A further optimization
+	 * could special case this but only reduces the path length for
+	 * this infrequent case.
+	 */
+	if (diff_exponent > SGLEXT_THRESHOLD) {
+		diff_exponent = SGLEXT_THRESHOLD;
+	}
+
+	/* Align right operand by shifting it to the right */
+	Sglext_clear_sign(rightp1);
+	Sglext_right_align(rightp1,rightp2,/*shifted by*/diff_exponent);
+	
+	/* Treat sum and difference of the operands separately. */
+	if ((int)save < 0) {
+		/*
+		 * Difference of the two operands.  Overflow can occur if the
+		 * multiply overflowed.  A borrow can occur out of the hidden
+		 * bit and force a post normalization phase.
+		 */
+		Sglext_subtract(tmpresp1,tmpresp2, rightp1,rightp2,
+			resultp1,resultp2);
+		sign_save = Sgl_signextendedsign(resultp1);
+		if (Sgl_iszero_hidden(resultp1)) {
+			/* Handle normalization */
+		/* A straight foward algorithm would now shift the
+		 * result and extension left until the hidden bit
+		 * becomes one.  Not all of the extension bits need
+		 * participate in the shift.  Only the two most 
+		 * significant bits (round and guard) are needed.
+		 * If only a single shift is needed then the guard
+		 * bit becomes a significant low order bit and the
+		 * extension must participate in the rounding.
+		 * If more than a single shift is needed, then all
+		 * bits to the right of the guard bit are zeros, 
+		 * and the guard bit may or may not be zero. */
+			Sglext_leftshiftby1(resultp1,resultp2);
+
+			/* Need to check for a zero result.  The sign and
+			 * exponent fields have already been zeroed.  The more
+			 * efficient test of the full object can be used.
+			 */
+			 if (Sglext_iszero(resultp1,resultp2)) {
+				/* Must have been "x-x" or "x+(-x)". */
+				if (Is_rounding_mode(ROUNDMINUS))
+					Sgl_setone_sign(resultp1);
+				Sgl_copytoptr(resultp1,dstptr);
+				return(NOEXCEPTION);
+			}
+			result_exponent--;
+
+			/* Look to see if normalization is finished. */
+			if (Sgl_isone_hidden(resultp1)) {
+				/* No further normalization is needed */
+				goto round;
+			}
+
+			/* Discover first one bit to determine shift amount.
+			 * Use a modified binary search.  We have already
+			 * shifted the result one position right and still
+			 * not found a one so the remainder of the extension
+			 * must be zero and simplifies rounding. */
+			/* Scan bytes */
+			while (Sgl_iszero_hiddenhigh7mantissa(resultp1)) {
+				Sglext_leftshiftby8(resultp1,resultp2);
+				result_exponent -= 8;
+			}
+			/* Now narrow it down to the nibble */
+			if (Sgl_iszero_hiddenhigh3mantissa(resultp1)) {
+				/* The lower nibble contains the
+				 * normalizing one */
+				Sglext_leftshiftby4(resultp1,resultp2);
+				result_exponent -= 4;
+			}
+			/* Select case where first bit is set (already
+			 * normalized) otherwise select the proper shift. */
+			jumpsize = Sgl_hiddenhigh3mantissa(resultp1);
+			if (jumpsize <= 7) switch(jumpsize) {
+			case 1:
+				Sglext_leftshiftby3(resultp1,resultp2);
+				result_exponent -= 3;
+				break;
+			case 2:
+			case 3:
+				Sglext_leftshiftby2(resultp1,resultp2);
+				result_exponent -= 2;
+				break;
+			case 4:
+			case 5:
+			case 6:
+			case 7:
+				Sglext_leftshiftby1(resultp1,resultp2);
+				result_exponent -= 1;
+				break;
+			}
+		} /* end if (hidden...)... */
+	/* Fall through and round */
+	} /* end if (save < 0)... */
+	else {
+		/* Add magnitudes */
+		Sglext_addition(tmpresp1,tmpresp2,
+			rightp1,rightp2, /*to*/resultp1,resultp2);
+		sign_save = Sgl_signextendedsign(resultp1);
+		if (Sgl_isone_hiddenoverflow(resultp1)) {
+	    		/* Prenormalization required. */
+	    		Sglext_arithrightshiftby1(resultp1,resultp2);
+	    		result_exponent++;
+		} /* end if hiddenoverflow... */
+	} /* end else ...add magnitudes... */
+
+	/* Round the result.  If the extension and lower two words are
+	 * all zeros, then the result is exact.  Otherwise round in the
+	 * correct direction.  Underflow is possible. If a postnormalization
+	 * is necessary, then the mantissa is all zeros so no shift is needed.
+	 */
+  round:
+	if (result_exponent <= 0 && !Is_underflowtrap_enabled()) {
+		Sglext_denormalize(resultp1,resultp2,result_exponent,is_tiny);
+	}
+	Sgl_set_sign(resultp1,/*using*/sign_save);
+	if (Sglext_isnotzero_mantissap2(resultp2)) {
+		inexact = TRUE;
+		switch(Rounding_mode()) {
+		case ROUNDNEAREST: /* The default. */
+			if (Sglext_isone_highp2(resultp2)) {
+				/* at least 1/2 ulp */
+				if (Sglext_isnotzero_low31p2(resultp2) ||
+				    Sglext_isone_lowp1(resultp1)) {
+					/* either exactly half way and odd or
+					 * more than 1/2ulp */
+					Sgl_increment(resultp1);
+				}
+			}
+	    		break;
+
+		case ROUNDPLUS:
+	    		if (Sgl_iszero_sign(resultp1)) {
+				/* Round up positive results */
+				Sgl_increment(resultp1);
+			}
+			break;
+	    
+		case ROUNDMINUS:
+	    		if (Sgl_isone_sign(resultp1)) {
+				/* Round down negative results */
+				Sgl_increment(resultp1);
+			}
+	    
+		case ROUNDZERO:;
+			/* truncate is simple */
+		} /* end switch... */
+		if (Sgl_isone_hiddenoverflow(resultp1)) result_exponent++;
+	}
+	if (result_exponent >= SGL_INFINITY_EXPONENT) {
+		/* Overflow */
+		if (Is_overflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Sgl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+                        Sgl_copytoptr(resultp1,dstptr);
+                        if (inexact)
+                            if (Is_inexacttrap_enabled())
+                                return (OPC_2E_OVERFLOWEXCEPTION |
+					OPC_2E_INEXACTEXCEPTION);
+                            else Set_inexactflag();
+                        return (OPC_2E_OVERFLOWEXCEPTION);
+		}
+		inexact = TRUE;
+		Set_overflowflag();
+		Sgl_setoverflow(resultp1);
+	} else if (result_exponent <= 0) {	/* underflow case */
+		if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                	Sgl_setwrapped_exponent(resultp1,result_exponent,unfl);
+			Sgl_copytoptr(resultp1,dstptr);
+                        if (inexact)
+                            if (Is_inexacttrap_enabled())
+                                return (OPC_2E_UNDERFLOWEXCEPTION |
+					OPC_2E_INEXACTEXCEPTION);
+                            else Set_inexactflag();
+	    		return(OPC_2E_UNDERFLOWEXCEPTION);
+		}
+		else if (inexact && is_tiny) Set_underflowflag();
+	}
+	else Sgl_set_exponent(resultp1,result_exponent);
+	Sgl_copytoptr(resultp1,dstptr);
+	if (inexact) 
+		if (Is_inexacttrap_enabled()) return(OPC_2E_INEXACTEXCEPTION);
+		else Set_inexactflag();
+    	return(NOEXCEPTION);
+}
+
+/*
+ *  Single Floating-point Multiply Negate Fused Add
+ */
+
+sgl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+
+sgl_floating_point *src1ptr, *src2ptr, *src3ptr, *dstptr;
+unsigned int *status;
+{
+	unsigned int opnd1, opnd2, opnd3;
+	register unsigned int tmpresp1, tmpresp2;
+	unsigned int rightp1, rightp2;
+	unsigned int resultp1, resultp2 = 0;
+	register int mpy_exponent, add_exponent, count;
+	boolean inexact = FALSE, is_tiny = FALSE;
+
+	unsigned int signlessleft1, signlessright1, save;
+	register int result_exponent, diff_exponent;
+	int sign_save, jumpsize;
+	
+	Sgl_copyfromptr(src1ptr,opnd1);
+	Sgl_copyfromptr(src2ptr,opnd2);
+	Sgl_copyfromptr(src3ptr,opnd3);
+
+	/* 
+	 * set sign bit of result of multiply
+	 */
+	if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) 
+		Sgl_setzero(resultp1);
+	else 
+		Sgl_setnegativezero(resultp1); 
+
+	/*
+	 * Generate multiply exponent 
+	 */
+	mpy_exponent = Sgl_exponent(opnd1) + Sgl_exponent(opnd2) - SGL_BIAS;
+
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd1)) {
+		if (Sgl_iszero_mantissa(opnd1)) {
+			if (Sgl_isnotnan(opnd2) && Sgl_isnotnan(opnd3)) {
+				if (Sgl_iszero_exponentmantissa(opnd2)) {
+					/* 
+					 * invalid since operands are infinity 
+					 * and zero 
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Sgl_makequietnan(resultp1);
+					Sgl_copytoptr(resultp1,dstptr);
+					return(NOEXCEPTION);
+				}
+				/*
+				 * Check third operand for infinity with a
+				 *  sign opposite of the multiply result
+				 */
+				if (Sgl_isinfinity(opnd3) &&
+				    (Sgl_sign(resultp1) ^ Sgl_sign(opnd3))) {
+					/* 
+					 * invalid since attempting a magnitude
+					 * subtraction of infinities
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Sgl_makequietnan(resultp1);
+					Sgl_copytoptr(resultp1,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+			 	 * return infinity
+			 	 */
+				Sgl_setinfinity_exponentmantissa(resultp1);
+				Sgl_copytoptr(resultp1,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+			/*
+		 	 * is NaN; signaling or quiet?
+		 	 */
+			if (Sgl_isone_signaling(opnd1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled()) 
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd1);
+			}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd2)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd2);
+				Sgl_copytoptr(opnd2,dstptr);
+				return(NOEXCEPTION);
+			}
+			/* 
+			 * is third operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd3)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd3);
+				Sgl_copytoptr(opnd3,dstptr);
+				return(NOEXCEPTION);
+			}
+			/*
+		 	 * return quiet NaN
+		 	 */
+			Sgl_copytoptr(opnd1,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd2)) {
+		if (Sgl_iszero_mantissa(opnd2)) {
+			if (Sgl_isnotnan(opnd3)) {
+				if (Sgl_iszero_exponentmantissa(opnd1)) {
+					/* 
+					 * invalid since multiply operands are
+					 * zero & infinity
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Sgl_makequietnan(opnd2);
+					Sgl_copytoptr(opnd2,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+				 * Check third operand for infinity with a
+				 *  sign opposite of the multiply result
+				 */
+				if (Sgl_isinfinity(opnd3) &&
+				    (Sgl_sign(resultp1) ^ Sgl_sign(opnd3))) {
+					/* 
+					 * invalid since attempting a magnitude
+					 * subtraction of infinities
+					 */
+					if (Is_invalidtrap_enabled())
+				       		return(OPC_2E_INVALIDEXCEPTION);
+				       	Set_invalidflag();
+				       	Sgl_makequietnan(resultp1);
+					Sgl_copytoptr(resultp1,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+				 * return infinity
+				 */
+				Sgl_setinfinity_exponentmantissa(resultp1);
+				Sgl_copytoptr(resultp1,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+			/*
+			 * is NaN; signaling or quiet?
+			 */
+			if (Sgl_isone_signaling(opnd2)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd2);
+			}
+			/* 
+			 * is third operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd3)) {
+			       	/* trap if INVALIDTRAP enabled */
+			       	if (Is_invalidtrap_enabled())
+				   		return(OPC_2E_INVALIDEXCEPTION);
+			       	/* make NaN quiet */
+			       	Set_invalidflag();
+			       	Sgl_set_quiet(opnd3);
+				Sgl_copytoptr(opnd3,dstptr);
+		       		return(NOEXCEPTION);
+			}
+			/*
+			 * return quiet NaN
+			 */
+			Sgl_copytoptr(opnd2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+
+	/*
+	 * check third operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd3)) {
+		if (Sgl_iszero_mantissa(opnd3)) {
+			/* return infinity */
+			Sgl_copytoptr(opnd3,dstptr);
+			return(NOEXCEPTION);
+		} else {
+			/*
+			 * is NaN; signaling or quiet?
+			 */
+			if (Sgl_isone_signaling(opnd3)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd3);
+			}
+			/*
+			 * return quiet NaN
+ 			 */
+			Sgl_copytoptr(opnd3,dstptr);
+			return(NOEXCEPTION);
+		}
+    	}
+
+	/*
+	 * Generate multiply mantissa
+	 */
+	if (Sgl_isnotzero_exponent(opnd1)) {
+		/* set hidden bit */
+		Sgl_clear_signexponent_set_hidden(opnd1);
+	}
+	else {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd1)) {
+			/*
+			 * Perform the add opnd3 with zero here.
+			 */
+			if (Sgl_iszero_exponentmantissa(opnd3)) {
+				if (Is_rounding_mode(ROUNDMINUS)) {
+					Sgl_or_signs(opnd3,resultp1);
+				} else {
+					Sgl_and_signs(opnd3,resultp1);
+				}
+			}
+			/*
+			 * Now let's check for trapped underflow case.
+			 */
+			else if (Sgl_iszero_exponent(opnd3) &&
+			         Is_underflowtrap_enabled()) {
+                    		/* need to normalize results mantissa */
+                    		sign_save = Sgl_signextendedsign(opnd3);
+				result_exponent = 0;
+                    		Sgl_leftshiftby1(opnd3);
+                    		Sgl_normalize(opnd3,result_exponent);
+                    		Sgl_set_sign(opnd3,/*using*/sign_save);
+                    		Sgl_setwrapped_exponent(opnd3,result_exponent,
+							unfl);
+                    		Sgl_copytoptr(opnd3,dstptr);
+                    		/* inexact = FALSE */
+                    		return(OPC_2E_UNDERFLOWEXCEPTION);
+			}
+			Sgl_copytoptr(opnd3,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* is denormalized, adjust exponent */
+		Sgl_clear_signexponent(opnd1);
+		Sgl_leftshiftby1(opnd1);
+		Sgl_normalize(opnd1,mpy_exponent);
+	}
+	/* opnd2 needs to have hidden bit set with msb in hidden bit */
+	if (Sgl_isnotzero_exponent(opnd2)) {
+		Sgl_clear_signexponent_set_hidden(opnd2);
+	}
+	else {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd2)) {
+			/*
+			 * Perform the add opnd3 with zero here.
+			 */
+			if (Sgl_iszero_exponentmantissa(opnd3)) {
+				if (Is_rounding_mode(ROUNDMINUS)) {
+					Sgl_or_signs(opnd3,resultp1);
+				} else {
+					Sgl_and_signs(opnd3,resultp1);
+				}
+			}
+			/*
+			 * Now let's check for trapped underflow case.
+			 */
+			else if (Sgl_iszero_exponent(opnd3) &&
+			    Is_underflowtrap_enabled()) {
+                    		/* need to normalize results mantissa */
+                    		sign_save = Sgl_signextendedsign(opnd3);
+				result_exponent = 0;
+                    		Sgl_leftshiftby1(opnd3);
+                    		Sgl_normalize(opnd3,result_exponent);
+                    		Sgl_set_sign(opnd3,/*using*/sign_save);
+                    		Sgl_setwrapped_exponent(opnd3,result_exponent,
+							unfl);
+                    		Sgl_copytoptr(opnd3,dstptr);
+                    		/* inexact = FALSE */
+                    		return(OPC_2E_UNDERFLOWEXCEPTION);
+			}
+			Sgl_copytoptr(opnd3,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* is denormalized; want to normalize */
+		Sgl_clear_signexponent(opnd2);
+		Sgl_leftshiftby1(opnd2);
+		Sgl_normalize(opnd2,mpy_exponent);
+	}
+
+	/* Multiply the first two source mantissas together */
+
+	/* 
+	 * The intermediate result will be kept in tmpres,
+	 * which needs enough room for 106 bits of mantissa,
+	 * so lets call it a Double extended.
+	 */
+	Sglext_setzero(tmpresp1,tmpresp2);
+
+	/* 
+	 * Four bits at a time are inspected in each loop, and a 
+	 * simple shift and add multiply algorithm is used. 
+	 */ 
+	for (count = SGL_P-1; count >= 0; count -= 4) {
+		Sglext_rightshiftby4(tmpresp1,tmpresp2);
+		if (Sbit28(opnd1)) {
+	 		/* Twoword_add should be an ADD followed by 2 ADDC's */
+			Twoword_add(tmpresp1, tmpresp2, opnd2<<3, 0);
+		}
+		if (Sbit29(opnd1)) {
+			Twoword_add(tmpresp1, tmpresp2, opnd2<<2, 0);
+		}
+		if (Sbit30(opnd1)) {
+			Twoword_add(tmpresp1, tmpresp2, opnd2<<1, 0);
+		}
+		if (Sbit31(opnd1)) {
+			Twoword_add(tmpresp1, tmpresp2, opnd2, 0);
+		}
+		Sgl_rightshiftby4(opnd1);
+	}
+	if (Is_sexthiddenoverflow(tmpresp1)) {
+		/* result mantissa >= 2 (mantissa overflow) */
+		mpy_exponent++;
+		Sglext_rightshiftby4(tmpresp1,tmpresp2);
+	} else {
+		Sglext_rightshiftby3(tmpresp1,tmpresp2);
+	}
+
+	/*
+	 * Restore the sign of the mpy result which was saved in resultp1.
+	 * The exponent will continue to be kept in mpy_exponent.
+	 */
+	Sglext_set_sign(tmpresp1,Sgl_sign(resultp1));
+
+	/* 
+	 * No rounding is required, since the result of the multiply
+	 * is exact in the extended format.
+	 */
+
+	/*
+	 * Now we are ready to perform the add portion of the operation.
+	 *
+	 * The exponents need to be kept as integers for now, since the
+	 * multiply result might not fit into the exponent field.  We
+	 * can't overflow or underflow because of this yet, since the
+	 * add could bring the final result back into range.
+	 */
+	add_exponent = Sgl_exponent(opnd3);
+
+	/*
+	 * Check for denormalized or zero add operand.
+	 */
+	if (add_exponent == 0) {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd3)) {
+			/* right is zero */
+			/* Left can't be zero and must be result.
+			 *
+			 * The final result is now in tmpres and mpy_exponent,
+			 * and needs to be rounded and squeezed back into
+			 * double precision format from double extended.
+			 */
+			result_exponent = mpy_exponent;
+			Sglext_copy(tmpresp1,tmpresp2,resultp1,resultp2);
+			sign_save = Sgl_signextendedsign(resultp1);/*save sign*/
+			goto round;
+		}
+
+		/* 
+		 * Neither are zeroes.  
+		 * Adjust exponent and normalize add operand.
+		 */
+		sign_save = Sgl_signextendedsign(opnd3);	/* save sign */
+		Sgl_clear_signexponent(opnd3);
+		Sgl_leftshiftby1(opnd3);
+		Sgl_normalize(opnd3,add_exponent);
+		Sgl_set_sign(opnd3,sign_save);		/* restore sign */
+	} else {
+		Sgl_clear_exponent_set_hidden(opnd3);
+	}
+	/*
+	 * Copy opnd3 to the double extended variable called right.
+	 */
+	Sgl_copyto_sglext(opnd3,rightp1,rightp2);
+
+	/*
+	 * A zero "save" helps discover equal operands (for later),
+	 * and is used in swapping operands (if needed).
+	 */
+	Sglext_xortointp1(tmpresp1,rightp1,/*to*/save);
+
+	/*
+	 * Compare magnitude of operands.
+	 */
+	Sglext_copytoint_exponentmantissa(tmpresp1,signlessleft1);
+	Sglext_copytoint_exponentmantissa(rightp1,signlessright1);
+	if (mpy_exponent < add_exponent || mpy_exponent == add_exponent &&
+	    Sglext_ismagnitudeless(signlessleft1,signlessright1)) {
+		/*
+		 * Set the left operand to the larger one by XOR swap.
+		 * First finish the first word "save".
+		 */
+		Sglext_xorfromintp1(save,rightp1,/*to*/rightp1);
+		Sglext_xorfromintp1(save,tmpresp1,/*to*/tmpresp1);
+		Sglext_swap_lower(tmpresp2,rightp2);
+		/* also setup exponents used in rest of routine */
+		diff_exponent = add_exponent - mpy_exponent;
+		result_exponent = add_exponent;
+	} else {
+		/* also setup exponents used in rest of routine */
+		diff_exponent = mpy_exponent - add_exponent;
+		result_exponent = mpy_exponent;
+	}
+	/* Invariant: left is not smaller than right. */
+
+	/*
+	 * Special case alignment of operands that would force alignment
+	 * beyond the extent of the extension.  A further optimization
+	 * could special case this but only reduces the path length for
+	 * this infrequent case.
+	 */
+	if (diff_exponent > SGLEXT_THRESHOLD) {
+		diff_exponent = SGLEXT_THRESHOLD;
+	}
+
+	/* Align right operand by shifting it to the right */
+	Sglext_clear_sign(rightp1);
+	Sglext_right_align(rightp1,rightp2,/*shifted by*/diff_exponent);
+	
+	/* Treat sum and difference of the operands separately. */
+	if ((int)save < 0) {
+		/*
+		 * Difference of the two operands.  Overflow can occur if the
+		 * multiply overflowed.  A borrow can occur out of the hidden
+		 * bit and force a post normalization phase.
+		 */
+		Sglext_subtract(tmpresp1,tmpresp2, rightp1,rightp2,
+			resultp1,resultp2);
+		sign_save = Sgl_signextendedsign(resultp1);
+		if (Sgl_iszero_hidden(resultp1)) {
+			/* Handle normalization */
+		/* A straight foward algorithm would now shift the
+		 * result and extension left until the hidden bit
+		 * becomes one.  Not all of the extension bits need
+		 * participate in the shift.  Only the two most 
+		 * significant bits (round and guard) are needed.
+		 * If only a single shift is needed then the guard
+		 * bit becomes a significant low order bit and the
+		 * extension must participate in the rounding.
+		 * If more than a single shift is needed, then all
+		 * bits to the right of the guard bit are zeros, 
+		 * and the guard bit may or may not be zero. */
+			Sglext_leftshiftby1(resultp1,resultp2);
+
+			/* Need to check for a zero result.  The sign and
+			 * exponent fields have already been zeroed.  The more
+			 * efficient test of the full object can be used.
+			 */
+			 if (Sglext_iszero(resultp1,resultp2)) {
+				/* Must have been "x-x" or "x+(-x)". */
+				if (Is_rounding_mode(ROUNDMINUS))
+					Sgl_setone_sign(resultp1);
+				Sgl_copytoptr(resultp1,dstptr);
+				return(NOEXCEPTION);
+			}
+			result_exponent--;
+
+			/* Look to see if normalization is finished. */
+			if (Sgl_isone_hidden(resultp1)) {
+				/* No further normalization is needed */
+				goto round;
+			}
+
+			/* Discover first one bit to determine shift amount.
+			 * Use a modified binary search.  We have already
+			 * shifted the result one position right and still
+			 * not found a one so the remainder of the extension
+			 * must be zero and simplifies rounding. */
+			/* Scan bytes */
+			while (Sgl_iszero_hiddenhigh7mantissa(resultp1)) {
+				Sglext_leftshiftby8(resultp1,resultp2);
+				result_exponent -= 8;
+			}
+			/* Now narrow it down to the nibble */
+			if (Sgl_iszero_hiddenhigh3mantissa(resultp1)) {
+				/* The lower nibble contains the
+				 * normalizing one */
+				Sglext_leftshiftby4(resultp1,resultp2);
+				result_exponent -= 4;
+			}
+			/* Select case where first bit is set (already
+			 * normalized) otherwise select the proper shift. */
+			jumpsize = Sgl_hiddenhigh3mantissa(resultp1);
+			if (jumpsize <= 7) switch(jumpsize) {
+			case 1:
+				Sglext_leftshiftby3(resultp1,resultp2);
+				result_exponent -= 3;
+				break;
+			case 2:
+			case 3:
+				Sglext_leftshiftby2(resultp1,resultp2);
+				result_exponent -= 2;
+				break;
+			case 4:
+			case 5:
+			case 6:
+			case 7:
+				Sglext_leftshiftby1(resultp1,resultp2);
+				result_exponent -= 1;
+				break;
+			}
+		} /* end if (hidden...)... */
+	/* Fall through and round */
+	} /* end if (save < 0)... */
+	else {
+		/* Add magnitudes */
+		Sglext_addition(tmpresp1,tmpresp2,
+			rightp1,rightp2, /*to*/resultp1,resultp2);
+		sign_save = Sgl_signextendedsign(resultp1);
+		if (Sgl_isone_hiddenoverflow(resultp1)) {
+	    		/* Prenormalization required. */
+	    		Sglext_arithrightshiftby1(resultp1,resultp2);
+	    		result_exponent++;
+		} /* end if hiddenoverflow... */
+	} /* end else ...add magnitudes... */
+
+	/* Round the result.  If the extension and lower two words are
+	 * all zeros, then the result is exact.  Otherwise round in the
+	 * correct direction.  Underflow is possible. If a postnormalization
+	 * is necessary, then the mantissa is all zeros so no shift is needed.
+	 */
+  round:
+	if (result_exponent <= 0 && !Is_underflowtrap_enabled()) {
+		Sglext_denormalize(resultp1,resultp2,result_exponent,is_tiny);
+	}
+	Sgl_set_sign(resultp1,/*using*/sign_save);
+	if (Sglext_isnotzero_mantissap2(resultp2)) {
+		inexact = TRUE;
+		switch(Rounding_mode()) {
+		case ROUNDNEAREST: /* The default. */
+			if (Sglext_isone_highp2(resultp2)) {
+				/* at least 1/2 ulp */
+				if (Sglext_isnotzero_low31p2(resultp2) ||
+				    Sglext_isone_lowp1(resultp1)) {
+					/* either exactly half way and odd or
+					 * more than 1/2ulp */
+					Sgl_increment(resultp1);
+				}
+			}
+	    		break;
+
+		case ROUNDPLUS:
+	    		if (Sgl_iszero_sign(resultp1)) {
+				/* Round up positive results */
+				Sgl_increment(resultp1);
+			}
+			break;
+	    
+		case ROUNDMINUS:
+	    		if (Sgl_isone_sign(resultp1)) {
+				/* Round down negative results */
+				Sgl_increment(resultp1);
+			}
+	    
+		case ROUNDZERO:;
+			/* truncate is simple */
+		} /* end switch... */
+		if (Sgl_isone_hiddenoverflow(resultp1)) result_exponent++;
+	}
+	if (result_exponent >= SGL_INFINITY_EXPONENT) {
+		/* Overflow */
+		if (Is_overflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Sgl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+                        Sgl_copytoptr(resultp1,dstptr);
+                        if (inexact)
+                            if (Is_inexacttrap_enabled())
+                                return (OPC_2E_OVERFLOWEXCEPTION |
+					OPC_2E_INEXACTEXCEPTION);
+                            else Set_inexactflag();
+                        return (OPC_2E_OVERFLOWEXCEPTION);
+		}
+		inexact = TRUE;
+		Set_overflowflag();
+		Sgl_setoverflow(resultp1);
+	} else if (result_exponent <= 0) {	/* underflow case */
+		if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                	Sgl_setwrapped_exponent(resultp1,result_exponent,unfl);
+			Sgl_copytoptr(resultp1,dstptr);
+                        if (inexact)
+                            if (Is_inexacttrap_enabled())
+                                return (OPC_2E_UNDERFLOWEXCEPTION |
+					OPC_2E_INEXACTEXCEPTION);
+                            else Set_inexactflag();
+	    		return(OPC_2E_UNDERFLOWEXCEPTION);
+		}
+		else if (inexact && is_tiny) Set_underflowflag();
+	}
+	else Sgl_set_exponent(resultp1,result_exponent);
+	Sgl_copytoptr(resultp1,dstptr);
+	if (inexact) 
+		if (Is_inexacttrap_enabled()) return(OPC_2E_INEXACTEXCEPTION);
+		else Set_inexactflag();
+    	return(NOEXCEPTION);
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/fpbits.h linux-2.4.20/arch/parisc/math-emu/fpbits.h
--- linux-2.4.19/arch/parisc/math-emu/fpbits.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/fpbits.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,65 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef __NO_PA_HDRS
+    PA header file -- do not include this header file for non-PA builds.
+#endif
+
+
+/*
+ *  These macros are designed to be portable to all machines that have
+ *  a wordsize greater than or equal to 32 bits that support the portable
+ *  C compiler and the standard C preprocessor.  Wordsize (default 32)
+ *  and bitfield assignment (default left-to-right,  unlike VAX, PDP-11)
+ *  should be predefined using the constants HOSTWDSZ and BITFRL and
+ *  the C compiler "-D" flag (e.g., -DHOSTWDSZ=36 -DBITFLR for the DEC-20).
+ *  Note that the macro arguments assume that the integer being referenced
+ *  is a 32-bit integer (right-justified on the 20) and that bit 0 is the
+ *  most significant bit.
+ */
+
+#ifndef HOSTWDSZ
+#define	HOSTWDSZ	32
+#endif
+
+
+/*###########################  Macros  ######################################*/
+
+/*-------------------------------------------------------------------------
+ * NewDeclareBitField_Reference - Declare a structure similar to the simulator
+ * function "DeclBitfR" except its use is restricted to occur within a larger
+ * enclosing structure or union definition.  This declaration is an unnamed
+ * structure with the argument, name, as the member name and the argument,
+ * uname, as the element name. 
+ *----------------------------------------------------------------------- */
+#define Bitfield_extract(start, length, object) 	\
+    ((object) >> (HOSTWDSZ - (start) - (length)) & 	\
+    ((unsigned)-1 >> (HOSTWDSZ - (length))))
+
+#define Bitfield_signed_extract(start, length, object) \
+    ((int)((object) << start) >> (HOSTWDSZ - (length)))
+
+#define Bitfield_mask(start, len, object)		\
+    ((object) & (((unsigned)-1 >> (HOSTWDSZ-len)) << (HOSTWDSZ-start-len)))
+
+#define Bitfield_deposit(value,start,len,object)  object = \
+    ((object) & ~(((unsigned)-1 >> (HOSTWDSZ-len)) << (HOSTWDSZ-start-len))) | \
+    (((value) & ((unsigned)-1 >> (HOSTWDSZ-len))) << (HOSTWDSZ-start-len))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/fpu.h linux-2.4.20/arch/parisc/math-emu/fpu.h
--- linux-2.4.19/arch/parisc/math-emu/fpu.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/fpu.h	2002-10-29 11:18:47.000000000 +0000
@@ -0,0 +1,76 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ * 
+ *  File: 
+ *      @(#)	pa/fp/fpu.h		$Revision: 1.2 $
+ * 
+ *  Purpose:
+ *      <<please update with a synopis of the functionality provided by this file>>
+ * 
+ * 
+ * END_DESC  
+*/
+
+#ifdef __NO_PA_HDRS
+    PA header file -- do not include this header file for non-PA builds.
+#endif
+
+
+#ifndef _MACHINE_FPU_INCLUDED /* allows multiple inclusion */
+#define _MACHINE_FPU_INCLUDED
+
+#if 0
+#ifndef _SYS_STDSYMS_INCLUDED
+#    include <sys/stdsyms.h>
+#endif   /* _SYS_STDSYMS_INCLUDED  */
+#include  <machine/pdc/pdc_rqsts.h>
+#endif
+
+#define PA83_FPU_FLAG    0x00000001
+#define PA89_FPU_FLAG    0x00000002
+#define PA2_0_FPU_FLAG   0x00000010
+
+#define TIMEX_EXTEN_FLAG 0x00000004
+
+#define ROLEX_EXTEN_FLAG 0x00000008
+#define COPR_FP 	0x00000080	/* Floating point -- Coprocessor 0 */
+#define SFU_MPY_DIVIDE	0x00008000	/* Multiply/Divide __ SFU 0 */
+
+
+#define EM_FPU_TYPE_OFFSET 272
+
+/* version of EMULATION software for COPR,0,0 instruction */
+#define EMULATION_VERSION 4
+
+/*
+ * The only was to differeniate between TIMEX and ROLEX (or PCX-S and PCX-T)
+ * is thorough the potential type field from the PDC_MODEL call.  The 
+ * following flags are used at assist this differeniation.
+ */
+
+#define ROLEX_POTENTIAL_KEY_FLAGS	PDC_MODEL_CPU_KEY_WORD_TO_IO
+#define TIMEX_POTENTIAL_KEY_FLAGS	(PDC_MODEL_CPU_KEY_QUAD_STORE | \
+					 PDC_MODEL_CPU_KEY_RECIP_SQRT)
+
+
+#endif /* ! _MACHINE_FPU_INCLUDED */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/fpudispatch.c linux-2.4.20/arch/parisc/math-emu/fpudispatch.c
--- linux-2.4.19/arch/parisc/math-emu/fpudispatch.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/fpudispatch.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,1425 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/fp/fpudispatch.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	<<please update with a synopsis of the functionality provided by this file>>
+ *
+ *  External Interfaces:
+ *	<<the following list was autogenerated, please review>>
+ *	emfpudispatch(ir, dummy1, dummy2, fpregs)
+ *	fpudispatch(ir, excp_code, holder, fpregs)
+ *
+ *  Internal Interfaces:
+ *	<<the following list was autogenerated, please review>>
+ *	static u_int decode_06(u_int, u_int *)
+ *	static u_int decode_0c(u_int, u_int, u_int, u_int *)
+ *	static u_int decode_0e(u_int, u_int, u_int, u_int *)
+ *	static u_int decode_26(u_int, u_int *)
+ *	static u_int decode_2e(u_int, u_int *)
+ *	static void update_status_cbit(u_int *, u_int, u_int, u_int)
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+#define FPUDEBUG 0
+
+#include "float.h"
+#include "types.h"
+/* #include <sys/debug.h> */
+/* #include <machine/sys/mdep_private.h> */
+
+#define COPR_INST 0x30000000
+
+/*
+ * definition of extru macro.  If pos and len are constants, the compiler
+ * will generate an extru instruction when optimized
+ */
+#define extru(r,pos,len)	(((r) >> (31-(pos))) & (( 1 << (len)) - 1))
+/* definitions of bit field locations in the instruction */
+#define fpmajorpos 5
+#define fpr1pos	10
+#define fpr2pos 15
+#define fptpos	31
+#define fpsubpos 18
+#define fpclass1subpos 16
+#define fpclasspos 22
+#define fpfmtpos 20
+#define fpdfpos 18
+#define fpnulpos 26
+/*
+ * the following are the extra bits for the 0E major op
+ */
+#define fpxr1pos 24
+#define fpxr2pos 19
+#define fpxtpos 25
+#define fpxpos 23
+#define fp0efmtpos 20
+/*
+ * the following are for the multi-ops
+ */
+#define fprm1pos 10
+#define fprm2pos 15
+#define fptmpos 31
+#define fprapos 25
+#define fptapos 20
+#define fpmultifmt 26
+/*
+ * the following are for the fused FP instructions
+ */
+     /* fprm1pos 10 */
+     /* fprm2pos 15 */
+#define fpraupos 18
+#define fpxrm2pos 19
+     /* fpfmtpos 20 */
+#define fpralpos 23
+#define fpxrm1pos 24
+     /* fpxtpos 25 */
+#define fpfusedsubop 26
+     /* fptpos	31 */
+
+/*
+ * offset to constant zero in the FP emulation registers
+ */
+#define fpzeroreg (32*sizeof(double)/sizeof(u_int))
+
+/*
+ * extract the major opcode from the instruction
+ */
+#define get_major(op) extru(op,fpmajorpos,6)
+/*
+ * extract the two bit class field from the FP instruction. The class is at bit
+ * positions 21-22
+ */
+#define get_class(op) extru(op,fpclasspos,2)
+/*
+ * extract the 3 bit subop field.  For all but class 1 instructions, it is
+ * located at bit positions 16-18
+ */
+#define get_subop(op) extru(op,fpsubpos,3)
+/*
+ * extract the 2 or 3 bit subop field from class 1 instructions.  It is located
+ * at bit positions 15-16 (PA1.1) or 14-16 (PA2.0)
+ */
+#define get_subop1_PA1_1(op) extru(op,fpclass1subpos,2)	/* PA89 (1.1) fmt */
+#define get_subop1_PA2_0(op) extru(op,fpclass1subpos,3)	/* PA 2.0 fmt */
+
+/* definitions of unimplemented exceptions */
+#define MAJOR_0C_EXCP	0x09
+#define MAJOR_0E_EXCP	0x0b
+#define MAJOR_06_EXCP	0x03
+#define MAJOR_26_EXCP	0x23
+#define MAJOR_2E_EXCP	0x2b
+#define PA83_UNIMP_EXCP	0x01
+
+/*
+ * Special Defines for TIMEX specific code
+ */
+
+#define FPU_TYPE_FLAG_POS (EM_FPU_TYPE_OFFSET>>2)
+#define TIMEX_ROLEX_FPU_MASK (TIMEX_EXTEN_FLAG|ROLEX_EXTEN_FLAG)
+
+/*
+ * Static function definitions
+ */
+#define _PROTOTYPES
+#if defined(_PROTOTYPES) || defined(_lint)
+static u_int decode_0c(u_int, u_int, u_int, u_int *);
+static u_int decode_0e(u_int, u_int, u_int, u_int *);
+static u_int decode_06(u_int, u_int *);
+static u_int decode_26(u_int, u_int *);
+static u_int decode_2e(u_int, u_int *);
+static void update_status_cbit(u_int *, u_int, u_int, u_int);
+#else /* !_PROTOTYPES&&!_lint */
+static u_int decode_0c();
+static u_int decode_0e();
+static u_int decode_06();
+static u_int decode_26();
+static u_int decode_2e();
+static void update_status_cbit();
+#endif /* _PROTOTYPES&&!_lint */
+
+#define VASSERT(x)
+
+/*
+ * this routine will decode the excepting floating point instruction and
+ * call the approiate emulation routine.
+ * It is called by decode_fpu with the following parameters:
+ * fpudispatch(current_ir, unimplemented_code, 0, &Fpu_register)
+ * where current_ir is the instruction to be emulated,
+ * unimplemented_code is the exception_code that the hardware generated
+ * and &Fpu_register is the address of emulated FP reg 0.
+ */
+u_int
+fpudispatch(u_int ir, u_int excp_code, u_int holder, u_int fpregs[])
+{
+	u_int class, subop;
+	u_int fpu_type_flags;
+
+	/* All FP emulation code assumes that ints are 4-bytes in length */
+	VASSERT(sizeof(int) == 4);
+
+	fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];  /* get fpu type flags */
+
+	class = get_class(ir);
+	if (class == 1) {
+		if  (fpu_type_flags & PA2_0_FPU_FLAG)
+			subop = get_subop1_PA2_0(ir);
+		else
+			subop = get_subop1_PA1_1(ir);
+	}
+	else
+		subop = get_subop(ir);
+
+	if (FPUDEBUG) printk("class %d subop %d\n", class, subop);
+
+	switch (excp_code) {
+		case MAJOR_0C_EXCP:
+		case PA83_UNIMP_EXCP:
+			return(decode_0c(ir,class,subop,fpregs));
+		case MAJOR_0E_EXCP:
+			return(decode_0e(ir,class,subop,fpregs));
+		case MAJOR_06_EXCP:
+			return(decode_06(ir,fpregs));
+		case MAJOR_26_EXCP:
+			return(decode_26(ir,fpregs));
+		case MAJOR_2E_EXCP:
+			return(decode_2e(ir,fpregs));
+		default:
+			/* "crashme Night Gallery painting nr 2. (asm_crash.s).
+			 * This was fixed for multi-user kernels, but
+			 * workstation kernels had a panic here.  This allowed
+			 * any arbitrary user to panic the kernel by executing
+			 * setting the FP exception registers to strange values
+			 * and generating an emulation trap.  The emulation and
+			 * exception code must never be able to panic the
+			 * kernel.
+			 */
+			return(UNIMPLEMENTEDEXCEPTION);
+	}
+}
+
+/*
+ * this routine is called by $emulation_trap to emulate a coprocessor
+ * instruction if one doesn't exist
+ */
+u_int
+emfpudispatch(u_int ir, u_int dummy1, u_int dummy2, u_int fpregs[])
+{
+	u_int class, subop, major;
+	u_int fpu_type_flags;
+
+	/* All FP emulation code assumes that ints are 4-bytes in length */
+	VASSERT(sizeof(int) == 4);
+
+	fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];  /* get fpu type flags */
+
+	major = get_major(ir);
+	class = get_class(ir);
+	if (class == 1) {
+		if  (fpu_type_flags & PA2_0_FPU_FLAG)
+			subop = get_subop1_PA2_0(ir);
+		else
+			subop = get_subop1_PA1_1(ir);
+	}
+	else
+		subop = get_subop(ir);
+	switch (major) {
+		case 0x0C:
+			return(decode_0c(ir,class,subop,fpregs));
+		case 0x0E:
+			return(decode_0e(ir,class,subop,fpregs));
+		case 0x06:
+			return(decode_06(ir,fpregs));
+		case 0x26:
+			return(decode_26(ir,fpregs));
+		case 0x2E:
+			return(decode_2e(ir,fpregs));
+		default:
+			return(PA83_UNIMP_EXCP);
+	}
+}
+	
+
+static u_int
+decode_0c(u_int ir, u_int class, u_int subop, u_int fpregs[])
+{
+	u_int r1,r2,t;		/* operand register offsets */ 
+	u_int fmt;		/* also sf for class 1 conversions */
+	u_int  df;		/* for class 1 conversions */
+	u_int *status;
+	u_int retval, local_status;
+	u_int fpu_type_flags;
+
+	if (ir == COPR_INST) {
+		fpregs[0] = EMULATION_VERSION << 11;
+		return(NOEXCEPTION);
+	}
+	status = &fpregs[0];	/* fp status register */
+	local_status = fpregs[0]; /* and local copy */
+	r1 = extru(ir,fpr1pos,5) * sizeof(double)/sizeof(u_int);
+	if (r1 == 0)		/* map fr0 source to constant zero */
+		r1 = fpzeroreg;
+	t = extru(ir,fptpos,5) * sizeof(double)/sizeof(u_int);
+	if (t == 0 && class != 2)	/* don't allow fr0 as a dest */
+		return(MAJOR_0C_EXCP);
+	fmt = extru(ir,fpfmtpos,2);	/* get fmt completer */
+
+	switch (class) {
+	    case 0:
+		switch (subop) {
+			case 0:	/* COPR 0,0 emulated above*/
+			case 1:
+				return(MAJOR_0C_EXCP);
+			case 2:	/* FCPY */
+				switch (fmt) {
+				    case 2: /* illegal */
+					return(MAJOR_0C_EXCP);
+				    case 3: /* quad */
+					t &= ~3;  /* force to even reg #s */
+					r1 &= ~3;
+					fpregs[t+3] = fpregs[r1+3];
+					fpregs[t+2] = fpregs[r1+2];
+				    case 1: /* double */
+					fpregs[t+1] = fpregs[r1+1];
+				    case 0: /* single */
+					fpregs[t] = fpregs[r1];
+					return(NOEXCEPTION);
+				}
+			case 3: /* FABS */
+				switch (fmt) {
+				    case 2: /* illegal */
+					return(MAJOR_0C_EXCP);
+				    case 3: /* quad */
+					t &= ~3;  /* force to even reg #s */
+					r1 &= ~3;
+					fpregs[t+3] = fpregs[r1+3];
+					fpregs[t+2] = fpregs[r1+2];
+				    case 1: /* double */
+					fpregs[t+1] = fpregs[r1+1];
+				    case 0: /* single */
+					/* copy and clear sign bit */
+					fpregs[t] = fpregs[r1] & 0x7fffffff;
+					return(NOEXCEPTION);
+				}
+			case 6: /* FNEG */
+				switch (fmt) {
+				    case 2: /* illegal */
+					return(MAJOR_0C_EXCP);
+				    case 3: /* quad */
+					t &= ~3;  /* force to even reg #s */
+					r1 &= ~3;
+					fpregs[t+3] = fpregs[r1+3];
+					fpregs[t+2] = fpregs[r1+2];
+				    case 1: /* double */
+					fpregs[t+1] = fpregs[r1+1];
+				    case 0: /* single */
+					/* copy and invert sign bit */
+					fpregs[t] = fpregs[r1] ^ 0x80000000;
+					return(NOEXCEPTION);
+				}
+			case 7: /* FNEGABS */
+				switch (fmt) {
+				    case 2: /* illegal */
+					return(MAJOR_0C_EXCP);
+				    case 3: /* quad */
+					t &= ~3;  /* force to even reg #s */
+					r1 &= ~3;
+					fpregs[t+3] = fpregs[r1+3];
+					fpregs[t+2] = fpregs[r1+2];
+				    case 1: /* double */
+					fpregs[t+1] = fpregs[r1+1];
+				    case 0: /* single */
+					/* copy and set sign bit */
+					fpregs[t] = fpregs[r1] | 0x80000000;
+					return(NOEXCEPTION);
+				}
+			case 4: /* FSQRT */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fsqrt(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_fsqrt(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2:
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+			case 5: /* FRND */
+				switch (fmt) {
+				    case 0:
+					return(sgl_frnd(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_frnd(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2:
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+		} /* end of switch (subop) */
+
+	case 1: /* class 1 */
+		df = extru(ir,fpdfpos,2); /* get dest format */
+		if ((df & 2) || (fmt & 2)) {
+			/*
+			 * fmt's 2 and 3 are illegal of not implemented
+			 * quad conversions
+			 */
+			return(MAJOR_0C_EXCP);
+		}
+		/*
+		 * encode source and dest formats into 2 bits.
+		 * high bit is source, low bit is dest.
+		 * bit = 1 --> double precision
+		 */
+		fmt = (fmt << 1) | df;
+		switch (subop) {
+			case 0: /* FCNVFF */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(MAJOR_0C_EXCP);
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvff(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvff(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(MAJOR_0C_EXCP);
+				}
+			case 1: /* FCNVXF */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvxf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvxf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvxf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvxf(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 2: /* FCNVFX */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvfx(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvfx(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvfx(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvfx(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 3: /* FCNVFXT */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvfxt(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvfxt(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvfxt(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvfxt(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 5: /* FCNVUF (PA2.0 only) */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvuf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvuf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvuf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvuf(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 6: /* FCNVFU (PA2.0 only) */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvfu(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvfu(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvfu(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvfu(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 7: /* FCNVFUT (PA2.0 only) */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvfut(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvfut(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvfut(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvfut(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 4: /* undefined */
+				return(MAJOR_0C_EXCP);
+		} /* end of switch subop */
+
+	case 2: /* class 2 */
+		fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];
+		r2 = extru(ir, fpr2pos, 5) * sizeof(double)/sizeof(u_int);
+		if (r2 == 0)
+			r2 = fpzeroreg;
+		if  (fpu_type_flags & PA2_0_FPU_FLAG) {
+			/* FTEST if nullify bit set, otherwise FCMP */
+			if (extru(ir, fpnulpos, 1)) {  /* FTEST */
+				switch (fmt) {
+				    case 0:
+					/*
+					 * arg0 is not used
+					 * second param is the t field used for
+					 * ftest,acc and ftest,rej
+					 * third param is the subop (y-field)
+					 */
+					BUG();
+					/* Unsupported
+					 * return(ftest(0L,extru(ir,fptpos,5),
+					 *	 &fpregs[0],subop));
+					 */
+				    case 1:
+				    case 2:
+				    case 3:
+					return(MAJOR_0C_EXCP);
+				}
+			} else {  /* FCMP */
+				switch (fmt) {
+				    case 0:
+					retval = sgl_fcmp(&fpregs[r1],
+						&fpregs[r2],extru(ir,fptpos,5),
+						&local_status);
+					update_status_cbit(status,local_status,
+						fpu_type_flags, subop);
+					return(retval);
+				    case 1:
+					retval = dbl_fcmp(&fpregs[r1],
+						&fpregs[r2],extru(ir,fptpos,5),
+						&local_status);
+					update_status_cbit(status,local_status,
+						fpu_type_flags, subop);
+					return(retval);
+				    case 2: /* illegal */
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+			}
+		}  /* end of if for PA2.0 */
+		else {	/* PA1.0 & PA1.1 */
+		    switch (subop) {
+			case 2:
+			case 3:
+			case 4:
+			case 5:
+			case 6:
+			case 7:
+				return(MAJOR_0C_EXCP);
+			case 0: /* FCMP */
+				switch (fmt) {
+				    case 0:
+					retval = sgl_fcmp(&fpregs[r1],
+						&fpregs[r2],extru(ir,fptpos,5),
+						&local_status);
+					update_status_cbit(status,local_status,
+						fpu_type_flags, subop);
+					return(retval);
+				    case 1:
+					retval = dbl_fcmp(&fpregs[r1],
+						&fpregs[r2],extru(ir,fptpos,5),
+						&local_status);
+					update_status_cbit(status,local_status,
+						fpu_type_flags, subop);
+					return(retval);
+				    case 2: /* illegal */
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+			case 1: /* FTEST */
+				switch (fmt) {
+				    case 0:
+					/*
+					 * arg0 is not used
+					 * second param is the t field used for
+					 * ftest,acc and ftest,rej
+					 * third param is the subop (y-field)
+					 */
+					BUG();
+					/* unsupported
+					 * return(ftest(0L,extru(ir,fptpos,5),
+					 *     &fpregs[0],subop));
+					 */
+				    case 1:
+				    case 2:
+				    case 3:
+					return(MAJOR_0C_EXCP);
+				}
+		    } /* end of switch subop */
+		} /* end of else for PA1.0 & PA1.1 */
+	case 3: /* class 3 */
+		r2 = extru(ir,fpr2pos,5) * sizeof(double)/sizeof(u_int);
+		if (r2 == 0)
+			r2 = fpzeroreg;
+		switch (subop) {
+			case 5:
+			case 6:
+			case 7:
+				return(MAJOR_0C_EXCP);
+			
+			case 0: /* FADD */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fadd(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_fadd(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 2: /* illegal */
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+			case 1: /* FSUB */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fsub(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_fsub(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 2: /* illegal */
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+			case 2: /* FMPY */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fmpy(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_fmpy(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 2: /* illegal */
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+			case 3: /* FDIV */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fdiv(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_fdiv(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 2: /* illegal */
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+			case 4: /* FREM */
+				switch (fmt) {
+				    case 0:
+					return(sgl_frem(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_frem(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 2: /* illegal */
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+		} /* end of class 3 switch */
+	} /* end of switch(class) */
+
+	/* If we get here, something is really wrong! */
+	return(MAJOR_0C_EXCP);
+}
+
+static u_int
+decode_0e(ir,class,subop,fpregs)
+u_int ir,class,subop;
+u_int fpregs[];
+{
+	u_int r1,r2,t;		/* operand register offsets */
+	u_int fmt;		/* also sf for class 1 conversions */
+	u_int df;		/* dest format for class 1 conversions */
+	u_int *status;
+	u_int retval, local_status;
+	u_int fpu_type_flags;
+
+	status = &fpregs[0];
+	local_status = fpregs[0];
+	r1 = ((extru(ir,fpr1pos,5)<<1)|(extru(ir,fpxr1pos,1)));
+	if (r1 == 0)
+		r1 = fpzeroreg;
+	t = ((extru(ir,fptpos,5)<<1)|(extru(ir,fpxtpos,1)));
+	if (t == 0 && class != 2)
+		return(MAJOR_0E_EXCP);
+	if (class < 2)		/* class 0 or 1 has 2 bit fmt */
+		fmt = extru(ir,fpfmtpos,2);
+	else 			/* class 2 and 3 have 1 bit fmt */
+		fmt = extru(ir,fp0efmtpos,1);
+	/*
+	 * An undefined combination, double precision accessing the
+	 * right half of a FPR, can get us into trouble.  
+	 * Let's just force proper alignment on it.
+	 */
+	if (fmt == DBL) {
+		r1 &= ~1;
+		if (class != 1)
+			t &= ~1;
+	}
+
+	switch (class) {
+	    case 0:
+		switch (subop) {
+			case 0: /* unimplemented */
+			case 1:
+				return(MAJOR_0E_EXCP);
+			case 2: /* FCPY */
+				switch (fmt) {
+				    case 2:
+				    case 3:
+					return(MAJOR_0E_EXCP);
+				    case 1: /* double */
+					fpregs[t+1] = fpregs[r1+1];
+				    case 0: /* single */
+					fpregs[t] = fpregs[r1];
+					return(NOEXCEPTION);
+				}
+			case 3: /* FABS */
+				switch (fmt) {
+				    case 2:
+				    case 3:
+					return(MAJOR_0E_EXCP);
+				    case 1: /* double */
+					fpregs[t+1] = fpregs[r1+1];
+				    case 0: /* single */
+					fpregs[t] = fpregs[r1] & 0x7fffffff;
+					return(NOEXCEPTION);
+				}
+			case 6: /* FNEG */
+				switch (fmt) {
+				    case 2:
+				    case 3:
+					return(MAJOR_0E_EXCP);
+				    case 1: /* double */
+					fpregs[t+1] = fpregs[r1+1];
+				    case 0: /* single */
+					fpregs[t] = fpregs[r1] ^ 0x80000000;
+					return(NOEXCEPTION);
+				}
+			case 7: /* FNEGABS */
+				switch (fmt) {
+				    case 2:
+				    case 3:
+					return(MAJOR_0E_EXCP);
+				    case 1: /* double */
+					fpregs[t+1] = fpregs[r1+1];
+				    case 0: /* single */
+					fpregs[t] = fpregs[r1] | 0x80000000;
+					return(NOEXCEPTION);
+				}
+			case 4: /* FSQRT */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fsqrt(&fpregs[r1],0,
+						&fpregs[t], status));
+				    case 1:
+					return(dbl_fsqrt(&fpregs[r1],0,
+						&fpregs[t], status));
+				    case 2:
+				    case 3:
+					return(MAJOR_0E_EXCP);
+				}
+			case 5: /* FRMD */
+				switch (fmt) {
+				    case 0:
+					return(sgl_frnd(&fpregs[r1],0,
+						&fpregs[t], status));
+				    case 1:
+					return(dbl_frnd(&fpregs[r1],0,
+						&fpregs[t], status));
+				    case 2:
+				    case 3:
+					return(MAJOR_0E_EXCP);
+				}
+		} /* end of switch (subop */
+	
+	case 1: /* class 1 */
+		df = extru(ir,fpdfpos,2); /* get dest format */
+		/*
+		 * Fix Crashme problem (writing to 31R in double precision)
+		 * here too.
+		 */
+		if (df == DBL) {
+			t &= ~1;
+		}
+		if ((df & 2) || (fmt & 2))
+			return(MAJOR_0E_EXCP);
+		
+		fmt = (fmt << 1) | df;
+		switch (subop) {
+			case 0: /* FCNVFF */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(MAJOR_0E_EXCP);
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvff(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvff(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(MAJOR_0E_EXCP);
+				}
+			case 1: /* FCNVXF */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvxf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvxf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvxf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvxf(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 2: /* FCNVFX */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvfx(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvfx(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvfx(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvfx(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 3: /* FCNVFXT */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvfxt(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvfxt(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvfxt(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvfxt(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 5: /* FCNVUF (PA2.0 only) */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvuf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvuf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvuf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvuf(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 6: /* FCNVFU (PA2.0 only) */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvfu(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvfu(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvfu(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvfu(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 7: /* FCNVFUT (PA2.0 only) */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvfut(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvfut(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvfut(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvfut(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 4: /* undefined */
+				return(MAJOR_0C_EXCP);
+		} /* end of switch subop */
+	case 2: /* class 2 */
+		/*
+		 * Be careful out there.
+		 * Crashme can generate cases where FR31R is specified
+		 * as the source or target of a double precision operation.
+		 * Since we just pass the address of the floating-point
+		 * register to the emulation routines, this can cause
+		 * corruption of fpzeroreg.
+		 */
+		if (fmt == DBL)
+			r2 = (extru(ir,fpr2pos,5)<<1);
+		else
+			r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1)));
+		fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];
+		if (r2 == 0)
+			r2 = fpzeroreg;
+		if  (fpu_type_flags & PA2_0_FPU_FLAG) {
+			/* FTEST if nullify bit set, otherwise FCMP */
+			if (extru(ir, fpnulpos, 1)) {  /* FTEST */
+				/* not legal */
+				return(MAJOR_0E_EXCP);
+			} else {  /* FCMP */
+			switch (fmt) {
+				    /*
+				     * fmt is only 1 bit long
+				     */
+				    case 0:
+					retval = sgl_fcmp(&fpregs[r1],
+						&fpregs[r2],extru(ir,fptpos,5),
+						&local_status);
+					update_status_cbit(status,local_status,
+						fpu_type_flags, subop);
+					return(retval);
+				    case 1:
+					retval = dbl_fcmp(&fpregs[r1],
+						&fpregs[r2],extru(ir,fptpos,5),
+						&local_status);
+					update_status_cbit(status,local_status,
+						fpu_type_flags, subop);
+					return(retval);
+				}
+			}
+		}  /* end of if for PA2.0 */
+		else {  /* PA1.0 & PA1.1 */
+		    switch (subop) {
+			case 1:
+			case 2:
+			case 3:
+			case 4:
+			case 5:
+			case 6:
+			case 7:
+				return(MAJOR_0E_EXCP);
+			case 0: /* FCMP */
+				switch (fmt) {
+				    /*
+				     * fmt is only 1 bit long
+				     */
+				    case 0:
+					retval = sgl_fcmp(&fpregs[r1],
+						&fpregs[r2],extru(ir,fptpos,5),
+						&local_status);
+					update_status_cbit(status,local_status,
+						fpu_type_flags, subop);
+					return(retval);
+				    case 1:
+					retval = dbl_fcmp(&fpregs[r1],
+						&fpregs[r2],extru(ir,fptpos,5),
+						&local_status);
+					update_status_cbit(status,local_status,
+						fpu_type_flags, subop);
+					return(retval);
+				}
+		    } /* end of switch subop */
+		} /* end of else for PA1.0 & PA1.1 */
+	case 3: /* class 3 */
+		/*
+		 * Be careful out there.
+		 * Crashme can generate cases where FR31R is specified
+		 * as the source or target of a double precision operation.
+		 * Since we just pass the address of the floating-point
+		 * register to the emulation routines, this can cause
+		 * corruption of fpzeroreg.
+		 */
+		if (fmt == DBL)
+			r2 = (extru(ir,fpr2pos,5)<<1);
+		else
+			r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1)));
+		if (r2 == 0)
+			r2 = fpzeroreg;
+		switch (subop) {
+			case 5:
+			case 6:
+			case 7:
+				return(MAJOR_0E_EXCP);
+			
+			/*
+			 * Note that fmt is only 1 bit for class 3 */
+			case 0: /* FADD */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fadd(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_fadd(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				}
+			case 1: /* FSUB */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fsub(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_fsub(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				}
+			case 2: /* FMPY or XMPYU */
+				/*
+				 * check for integer multiply (x bit set)
+				 */
+				if (extru(ir,fpxpos,1)) {
+				    /*
+				     * emulate XMPYU
+				     */
+				    switch (fmt) {
+					case 0:
+					    /*
+					     * bad instruction if t specifies
+					     * the right half of a register
+					     */
+					    if (t & 1)
+						return(MAJOR_0E_EXCP);
+					    BUG();
+					    /* unsupported
+					     * impyu(&fpregs[r1],&fpregs[r2],
+						 * &fpregs[t]);
+					     */
+					    return(NOEXCEPTION);
+					case 1:
+						return(MAJOR_0E_EXCP);
+				    }
+				}
+				else { /* FMPY */
+				    switch (fmt) {
+				        case 0:
+					    return(sgl_fmpy(&fpregs[r1],
+					       &fpregs[r2],&fpregs[t],status));
+				        case 1:
+					    return(dbl_fmpy(&fpregs[r1],
+					       &fpregs[r2],&fpregs[t],status));
+				    }
+				}
+			case 3: /* FDIV */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fdiv(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_fdiv(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				}
+			case 4: /* FREM */
+				switch (fmt) {
+				    case 0:
+					return(sgl_frem(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_frem(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				}
+		} /* end of class 3 switch */
+	} /* end of switch(class) */
+
+	/* If we get here, something is really wrong! */
+	return(MAJOR_0E_EXCP);
+}
+
+
+/*
+ * routine to decode the 06 (FMPYADD and FMPYCFXT) instruction
+ */
+static u_int
+decode_06(ir,fpregs)
+u_int ir;
+u_int fpregs[];
+{
+	u_int rm1, rm2, tm, ra, ta; /* operands */
+	u_int fmt;
+	u_int error = 0;
+	u_int status;
+	u_int fpu_type_flags;
+	union {
+		double dbl;
+		float flt;
+		struct { u_int i1; u_int i2; } ints;
+	} mtmp, atmp;
+
+
+	status = fpregs[0];		/* use a local copy of status reg */
+	fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];  /* get fpu type flags */
+	fmt = extru(ir, fpmultifmt, 1);	/* get sgl/dbl flag */
+	if (fmt == 0) { /* DBL */
+		rm1 = extru(ir, fprm1pos, 5) * sizeof(double)/sizeof(u_int);
+		if (rm1 == 0)
+			rm1 = fpzeroreg;
+		rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(u_int);
+		if (rm2 == 0)
+			rm2 = fpzeroreg;
+		tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(u_int);
+		if (tm == 0)
+			return(MAJOR_06_EXCP);
+		ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(u_int);
+		ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(u_int);
+		if (ta == 0)
+			return(MAJOR_06_EXCP);
+
+		if  (fpu_type_flags & TIMEX_ROLEX_FPU_MASK)  {
+
+			if (ra == 0) {
+			 	/* special case FMPYCFXT, see sgl case below */
+				if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],
+					&mtmp.ints.i1,&status))
+					error = 1;
+				if (dbl_to_sgl_fcnvfxt(&fpregs[ta],
+					&atmp.ints.i1,&atmp.ints.i1,&status))
+					error = 1;
+				}
+			else {
+
+			if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,
+					&status))
+				error = 1;
+			if (dbl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,
+					&status))
+				error = 1;
+				}
+			}
+
+		else
+
+			{
+			if (ra == 0)
+				ra = fpzeroreg;
+
+			if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,
+					&status))
+				error = 1;
+			if (dbl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,
+					&status))
+				error = 1;
+
+			}
+
+		if (error)
+			return(MAJOR_06_EXCP);
+		else {
+			/* copy results */
+			fpregs[tm] = mtmp.ints.i1;
+			fpregs[tm+1] = mtmp.ints.i2;
+			fpregs[ta] = atmp.ints.i1;
+			fpregs[ta+1] = atmp.ints.i2;
+			fpregs[0] = status;
+			return(NOEXCEPTION);
+		}
+	}
+	else { /* SGL */
+		/*
+		 * calculate offsets for single precision numbers
+		 * See table 6-14 in PA-89 architecture for mapping
+		 */
+		rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1;	/* get offset */
+		rm1 |= extru(ir,fprm1pos-4,1);	/* add right word offset */
+
+		rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1;	/* get offset */
+		rm2 |= extru(ir,fprm2pos-4,1);	/* add right word offset */
+
+		tm = (extru(ir,fptmpos,4) | 0x10 ) << 1;	/* get offset */
+		tm |= extru(ir,fptmpos-4,1);	/* add right word offset */
+
+		ra = (extru(ir,fprapos,4) | 0x10 ) << 1;	/* get offset */
+		ra |= extru(ir,fprapos-4,1);	/* add right word offset */
+
+		ta = (extru(ir,fptapos,4) | 0x10 ) << 1;	/* get offset */
+		ta |= extru(ir,fptapos-4,1);	/* add right word offset */
+		
+		if (ra == 0x20 &&(fpu_type_flags & TIMEX_ROLEX_FPU_MASK)) {
+			/* special case FMPYCFXT (really 0)
+			  * This instruction is only present on the Timex and
+			  * Rolex fpu's in so if it is the special case and
+			  * one of these fpu's we run the FMPYCFXT instruction
+			  */
+			if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,
+					&status))
+				error = 1;
+			if (sgl_to_sgl_fcnvfxt(&fpregs[ta],&atmp.ints.i1,
+				&atmp.ints.i1,&status))
+				error = 1;
+		}
+		else {
+			if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,
+					&status))
+				error = 1;
+			if (sgl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,
+					&status))
+				error = 1;
+		}
+		if (error)
+			return(MAJOR_06_EXCP);
+		else {
+			/* copy results */
+			fpregs[tm] = mtmp.ints.i1;
+			fpregs[ta] = atmp.ints.i1;
+			fpregs[0] = status;
+			return(NOEXCEPTION);
+		}
+	}
+}
+
+/*
+ * routine to decode the 26 (FMPYSUB) instruction
+ */
+static u_int
+decode_26(ir,fpregs)
+u_int ir;
+u_int fpregs[];
+{
+	u_int rm1, rm2, tm, ra, ta; /* operands */
+	u_int fmt;
+	u_int error = 0;
+	u_int status;
+	union {
+		double dbl;
+		float flt;
+		struct { u_int i1; u_int i2; } ints;
+	} mtmp, atmp;
+
+
+	status = fpregs[0];
+	fmt = extru(ir, fpmultifmt, 1);	/* get sgl/dbl flag */
+	if (fmt == 0) { /* DBL */
+		rm1 = extru(ir, fprm1pos, 5) * sizeof(double)/sizeof(u_int);
+		if (rm1 == 0)
+			rm1 = fpzeroreg;
+		rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(u_int);
+		if (rm2 == 0)
+			rm2 = fpzeroreg;
+		tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(u_int);
+		if (tm == 0)
+			return(MAJOR_26_EXCP);
+		ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(u_int);
+		if (ra == 0)
+			return(MAJOR_26_EXCP);
+		ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(u_int);
+		if (ta == 0)
+			return(MAJOR_26_EXCP);
+		
+		if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,&status))
+			error = 1;
+		if (dbl_fsub(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,&status))
+			error = 1;
+		if (error)
+			return(MAJOR_26_EXCP);
+		else {
+			/* copy results */
+			fpregs[tm] = mtmp.ints.i1;
+			fpregs[tm+1] = mtmp.ints.i2;
+			fpregs[ta] = atmp.ints.i1;
+			fpregs[ta+1] = atmp.ints.i2;
+			fpregs[0] = status;
+			return(NOEXCEPTION);
+		}
+	}
+	else { /* SGL */
+		/*
+		 * calculate offsets for single precision numbers
+		 * See table 6-14 in PA-89 architecture for mapping
+		 */
+		rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1;	/* get offset */
+		rm1 |= extru(ir,fprm1pos-4,1);	/* add right word offset */
+
+		rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1;	/* get offset */
+		rm2 |= extru(ir,fprm2pos-4,1);	/* add right word offset */
+
+		tm = (extru(ir,fptmpos,4) | 0x10 ) << 1;	/* get offset */
+		tm |= extru(ir,fptmpos-4,1);	/* add right word offset */
+
+		ra = (extru(ir,fprapos,4) | 0x10 ) << 1;	/* get offset */
+		ra |= extru(ir,fprapos-4,1);	/* add right word offset */
+
+		ta = (extru(ir,fptapos,4) | 0x10 ) << 1;	/* get offset */
+		ta |= extru(ir,fptapos-4,1);	/* add right word offset */
+		
+		if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,&status))
+			error = 1;
+		if (sgl_fsub(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,&status))
+			error = 1;
+		if (error)
+			return(MAJOR_26_EXCP);
+		else {
+			/* copy results */
+			fpregs[tm] = mtmp.ints.i1;
+			fpregs[ta] = atmp.ints.i1;
+			fpregs[0] = status;
+			return(NOEXCEPTION);
+		}
+	}
+
+}
+
+/*
+ * routine to decode the 2E (FMPYFADD,FMPYNFADD) instructions
+ */
+static u_int
+decode_2e(ir,fpregs)
+u_int ir;
+u_int fpregs[];
+{
+	u_int rm1, rm2, ra, t; /* operands */
+	u_int fmt;
+
+	fmt = extru(ir,fpfmtpos,1);	/* get fmt completer */
+	if (fmt == DBL) { /* DBL */
+		rm1 = extru(ir,fprm1pos,5) * sizeof(double)/sizeof(u_int);
+		if (rm1 == 0)
+			rm1 = fpzeroreg;
+		rm2 = extru(ir,fprm2pos,5) * sizeof(double)/sizeof(u_int);
+		if (rm2 == 0)
+			rm2 = fpzeroreg;
+		ra = ((extru(ir,fpraupos,3)<<2)|(extru(ir,fpralpos,3)>>1)) *
+		     sizeof(double)/sizeof(u_int);
+		if (ra == 0)
+			ra = fpzeroreg;
+		t = extru(ir,fptpos,5) * sizeof(double)/sizeof(u_int);
+		if (t == 0)
+			return(MAJOR_2E_EXCP);
+
+		if (extru(ir,fpfusedsubop,1)) { /* fmpyfadd or fmpynfadd? */
+			return(dbl_fmpynfadd(&fpregs[rm1], &fpregs[rm2],
+					&fpregs[ra], &fpregs[0], &fpregs[t]));
+		} else {
+			return(dbl_fmpyfadd(&fpregs[rm1], &fpregs[rm2],
+					&fpregs[ra], &fpregs[0], &fpregs[t]));
+		}
+	} /* end DBL */
+	else { /* SGL */
+		rm1 = (extru(ir,fprm1pos,5)<<1)|(extru(ir,fpxrm1pos,1));
+		if (rm1 == 0)
+			rm1 = fpzeroreg;
+		rm2 = (extru(ir,fprm2pos,5)<<1)|(extru(ir,fpxrm2pos,1));
+		if (rm2 == 0)
+			rm2 = fpzeroreg;
+		ra = (extru(ir,fpraupos,3)<<3)|extru(ir,fpralpos,3);
+		if (ra == 0)
+			ra = fpzeroreg;
+		t = ((extru(ir,fptpos,5)<<1)|(extru(ir,fpxtpos,1)));
+		if (t == 0)
+			return(MAJOR_2E_EXCP);
+
+		if (extru(ir,fpfusedsubop,1)) { /* fmpyfadd or fmpynfadd? */
+			return(sgl_fmpynfadd(&fpregs[rm1], &fpregs[rm2],
+					&fpregs[ra], &fpregs[0], &fpregs[t]));
+		} else {
+			return(sgl_fmpyfadd(&fpregs[rm1], &fpregs[rm2],
+					&fpregs[ra], &fpregs[0], &fpregs[t]));
+		}
+	} /* end SGL */
+}
+
+/*
+ * update_status_cbit
+ *
+ *	This routine returns the correct FP status register value in
+ *	*status, based on the C-bit & V-bit returned by the FCMP
+ *	emulation routine in new_status.  The architecture type
+ *	(PA83, PA89 or PA2.0) is available in fpu_type.  The y_field
+ *	and the architecture type are used to determine what flavor
+ *	of FCMP is being emulated.
+ */
+static void
+update_status_cbit(status, new_status, fpu_type, y_field)
+u_int *status, new_status;
+u_int fpu_type;
+u_int y_field;
+{
+	/*
+	 * For PA89 FPU's which implement the Compare Queue and
+	 * for PA2.0 FPU's, update the Compare Queue if the y-field = 0,
+	 * otherwise update the specified bit in the Compare Array.
+	 * Note that the y-field will always be 0 for non-PA2.0 FPU's.
+	 */
+	if ((fpu_type & TIMEX_EXTEN_FLAG) || 
+	    (fpu_type & ROLEX_EXTEN_FLAG) ||
+	    (fpu_type & PA2_0_FPU_FLAG)) {
+		if (y_field == 0) {
+			*status = ((*status & 0x04000000) >> 5) | /* old Cbit */
+				  ((*status & 0x003ff000) >> 1) | /* old CQ   */
+				  (new_status & 0xffc007ff); /* all other bits*/
+		} else {
+			*status = (*status & 0x04000000) |     /* old Cbit */
+				  ((new_status & 0x04000000) >> (y_field+4)) |
+				  (new_status & ~0x04000000 &  /* other bits */
+				   ~(0x04000000 >> (y_field+4)));
+		}
+	}
+	/* if PA83, just update the C-bit */
+	else {
+		*status = new_status;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/frnd.c linux-2.4.20/arch/parisc/math-emu/frnd.c
--- linux-2.4.19/arch/parisc/math-emu/frnd.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/frnd.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,252 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  Purpose:
+ *	Single Floating-point Round to Integer
+ *	Double Floating-point Round to Integer
+ *	Quad Floating-point Round to Integer (returns unimplemented)
+ *
+ *  External Interfaces:
+ *	dbl_frnd(srcptr,nullptr,dstptr,status)
+ *	sgl_frnd(srcptr,nullptr,dstptr,status)
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/*
+ *  Single Floating-point Round to Integer
+ */
+
+/*ARGSUSED*/
+int
+sgl_frnd(sgl_floating_point *srcptr,
+	unsigned int *nullptr,
+	sgl_floating_point *dstptr,
+	unsigned int *status)
+{
+	register unsigned int src, result;
+	register int src_exponent;
+	register boolean inexact = FALSE;
+
+	src = *srcptr;
+        /*
+         * check source operand for NaN or infinity
+         */
+        if ((src_exponent = Sgl_exponent(src)) == SGL_INFINITY_EXPONENT) {
+                /*
+                 * is signaling NaN?
+                 */
+                if (Sgl_isone_signaling(src)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Sgl_set_quiet(src);
+                }
+                /*
+                 * return quiet NaN or infinity
+                 */
+                *dstptr = src;
+                return(NOEXCEPTION);
+        }
+	/* 
+	 * Need to round?
+	 */
+	if ((src_exponent -= SGL_BIAS) >= SGL_P - 1) {
+		*dstptr = src;
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		Sgl_clear_exponent_set_hidden(src);
+		result = src;
+		Sgl_rightshift(result,(SGL_P-1) - (src_exponent));
+		/* check for inexact */
+		if (Sgl_isinexact_to_fix(src,src_exponent)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+			     if (Sgl_iszero_sign(src)) Sgl_increment(result);
+			     break;
+			case ROUNDMINUS:
+			     if (Sgl_isone_sign(src)) Sgl_increment(result);
+			     break;
+			case ROUNDNEAREST:
+			     if (Sgl_isone_roundbit(src,src_exponent))
+			        if (Sgl_isone_stickybit(src,src_exponent) 
+				|| (Sgl_isone_lowmantissa(result))) 
+					Sgl_increment(result);
+			} 
+		}
+		Sgl_leftshift(result,(SGL_P-1) - (src_exponent));
+		if (Sgl_isone_hiddenoverflow(result)) 
+			Sgl_set_exponent(result,src_exponent + (SGL_BIAS+1));
+		else Sgl_set_exponent(result,src_exponent + SGL_BIAS);
+	}
+	else {
+		result = src;  		/* set sign */
+		Sgl_setzero_exponentmantissa(result);
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+			     if (Sgl_iszero_sign(src)) 
+				Sgl_set_exponent(result,SGL_BIAS);
+			     break;
+			case ROUNDMINUS:
+			     if (Sgl_isone_sign(src)) 
+				Sgl_set_exponent(result,SGL_BIAS);
+			     break;
+			case ROUNDNEAREST:
+			     if (src_exponent == -1)
+			        if (Sgl_isnotzero_mantissa(src))
+				   Sgl_set_exponent(result,SGL_BIAS);
+			} 
+		}
+	}
+	*dstptr = result;
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+} 
+
+/*
+ *  Double Floating-point Round to Integer
+ */
+
+/*ARGSUSED*/
+int
+dbl_frnd(
+	dbl_floating_point *srcptr,
+	unsigned int *nullptr,
+	dbl_floating_point *dstptr,
+	unsigned int *status)
+{
+	register unsigned int srcp1, srcp2, resultp1, resultp2;
+	register int src_exponent;
+	register boolean inexact = FALSE;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+        /*
+         * check source operand for NaN or infinity
+         */
+        if ((src_exponent = Dbl_exponent(srcp1)) == DBL_INFINITY_EXPONENT) {
+                /*
+                 * is signaling NaN?
+                 */
+                if (Dbl_isone_signaling(srcp1)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Dbl_set_quiet(srcp1);
+                }
+                /*
+                 * return quiet NaN or infinity
+                 */
+                Dbl_copytoptr(srcp1,srcp2,dstptr);
+                return(NOEXCEPTION);
+        }
+	/* 
+	 * Need to round?
+	 */
+	if ((src_exponent -= DBL_BIAS) >= DBL_P - 1) {
+		Dbl_copytoptr(srcp1,srcp2,dstptr);
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		Dbl_clear_exponent_set_hidden(srcp1);
+		resultp1 = srcp1;
+		resultp2 = srcp2;
+		Dbl_rightshift(resultp1,resultp2,(DBL_P-1) - (src_exponent));
+		/* check for inexact */
+		if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+			     if (Dbl_iszero_sign(srcp1)) 
+				Dbl_increment(resultp1,resultp2);
+			     break;
+			case ROUNDMINUS:
+			     if (Dbl_isone_sign(srcp1)) 
+				Dbl_increment(resultp1,resultp2);
+			     break;
+			case ROUNDNEAREST:
+			     if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
+			      if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent) 
+				  || (Dbl_isone_lowmantissap2(resultp2))) 
+					Dbl_increment(resultp1,resultp2);
+			} 
+		}
+		Dbl_leftshift(resultp1,resultp2,(DBL_P-1) - (src_exponent));
+		if (Dbl_isone_hiddenoverflow(resultp1))
+			Dbl_set_exponent(resultp1,src_exponent + (DBL_BIAS+1));
+		else Dbl_set_exponent(resultp1,src_exponent + DBL_BIAS);
+	}
+	else {
+		resultp1 = srcp1;  /* set sign */
+		Dbl_setzero_exponentmantissa(resultp1,resultp2);
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+			     if (Dbl_iszero_sign(srcp1)) 
+				Dbl_set_exponent(resultp1,DBL_BIAS);
+			     break;
+			case ROUNDMINUS:
+			     if (Dbl_isone_sign(srcp1)) 
+				Dbl_set_exponent(resultp1,DBL_BIAS);
+			     break;
+			case ROUNDNEAREST:
+			     if (src_exponent == -1)
+			        if (Dbl_isnotzero_mantissa(srcp1,srcp2))
+				   Dbl_set_exponent(resultp1,DBL_BIAS);
+			} 
+		}
+	}
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/hppa.h linux-2.4.20/arch/parisc/math-emu/hppa.h
--- linux-2.4.19/arch/parisc/math-emu/hppa.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/hppa.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,42 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef __NO_PA_HDRS
+    PA header file -- do not include this header file for non-PA builds.
+#endif
+
+
+/* amount is assumed to be a constant between 0 and 32 (non-inclusive) */
+#define Shiftdouble(left,right,amount,dest)			\
+    /* int left, right, amount, dest; */			\
+    dest = ((left) << (32-(amount))) | ((unsigned int)(right) >> (amount))
+
+/* amount must be less than 32 */
+#define Variableshiftdouble(left,right,amount,dest)		\
+    /* unsigned int left, right;  int amount, dest; */		\
+    if (amount == 0) dest = right;				\
+    else dest = ((((unsigned) left)&0x7fffffff) << (32-(amount))) |	\
+          ((unsigned) right >> (amount))
+
+/* amount must be between 0 and 32 (non-inclusive) */
+#define Variable_shift_double(left,right,amount,dest)		\
+    /* unsigned int left, right;  int amount, dest; */		\
+    dest = (left << (32-(amount))) | ((unsigned) right >> (amount))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/math-emu.h linux-2.4.20/arch/parisc/math-emu/math-emu.h
--- linux-2.4.19/arch/parisc/math-emu/math-emu.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/math-emu.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,27 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _PARISC_MATH_EMU_H
+#define _PARISC_MATH_EMU_H
+
+#include <asm/ptrace.h>
+extern int handle_fpe(struct pt_regs *regs);
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/sfadd.c linux-2.4.20/arch/parisc/math-emu/sfadd.c
--- linux-2.4.19/arch/parisc/math-emu/sfadd.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/sfadd.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,518 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/sfadd.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single_add: add two single precision values.
+ *
+ *  External Interfaces:
+ *	sgl_fadd(leftptr, rightptr, dstptr, status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ * Single_add: add two single precision values.
+ */
+int
+sgl_fadd(
+    sgl_floating_point *leftptr,
+    sgl_floating_point *rightptr,
+    sgl_floating_point *dstptr,
+    unsigned int *status)
+    {
+    register unsigned int left, right, result, extent;
+    register unsigned int signless_upper_left, signless_upper_right, save;
+    
+    
+    register int result_exponent, right_exponent, diff_exponent;
+    register int sign_save, jumpsize;
+    register boolean inexact = FALSE;
+    register boolean underflowtrap;
+        
+    /* Create local copies of the numbers */
+    left = *leftptr;
+    right = *rightptr;
+
+    /* A zero "save" helps discover equal operands (for later),  *
+     * and is used in swapping operands (if needed).             */
+    Sgl_xortointp1(left,right,/*to*/save);
+
+    /*
+     * check first operand for NaN's or infinity
+     */
+    if ((result_exponent = Sgl_exponent(left)) == SGL_INFINITY_EXPONENT)
+	{
+	if (Sgl_iszero_mantissa(left)) 
+	    {
+	    if (Sgl_isnotnan(right)) 
+		{
+		if (Sgl_isinfinity(right) && save!=0) 
+		    {
+		    /* 
+		     * invalid since operands are opposite signed infinity's
+		     */
+		    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                    Set_invalidflag();
+                    Sgl_makequietnan(result);
+		    *dstptr = result;
+		    return(NOEXCEPTION);
+		    }
+		/*
+	 	 * return infinity
+	 	 */
+		*dstptr = left;
+		return(NOEXCEPTION);
+		}
+	    }
+	else 
+	    {
+            /*
+             * is NaN; signaling or quiet?
+             */
+            if (Sgl_isone_signaling(left)) 
+		{
+               	/* trap if INVALIDTRAP enabled */
+		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+        	/* make NaN quiet */
+        	Set_invalidflag();
+        	Sgl_set_quiet(left);
+        	}
+	    /* 
+	     * is second operand a signaling NaN? 
+	     */
+	    else if (Sgl_is_signalingnan(right)) 
+		{
+        	/* trap if INVALIDTRAP enabled */
+               	if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+		/* make NaN quiet */
+		Set_invalidflag();
+		Sgl_set_quiet(right);
+		*dstptr = right;
+		return(NOEXCEPTION);
+		}
+	    /*
+ 	     * return quiet NaN
+ 	     */
+ 	    *dstptr = left;
+ 	    return(NOEXCEPTION);
+	    }
+	} /* End left NaN or Infinity processing */
+    /*
+     * check second operand for NaN's or infinity
+     */
+    if (Sgl_isinfinity_exponent(right)) 
+	{
+	if (Sgl_iszero_mantissa(right)) 
+	    {
+	    /* return infinity */
+	    *dstptr = right;
+	    return(NOEXCEPTION);
+	    }
+        /*
+         * is NaN; signaling or quiet?
+         */
+        if (Sgl_isone_signaling(right)) 
+	    {
+            /* trap if INVALIDTRAP enabled */
+	    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+	    /* make NaN quiet */
+	    Set_invalidflag();
+	    Sgl_set_quiet(right);
+	    }
+	/*
+	 * return quiet NaN
+ 	 */
+	*dstptr = right;
+	return(NOEXCEPTION);
+    	} /* End right NaN or Infinity processing */
+
+    /* Invariant: Must be dealing with finite numbers */
+
+    /* Compare operands by removing the sign */
+    Sgl_copytoint_exponentmantissa(left,signless_upper_left);
+    Sgl_copytoint_exponentmantissa(right,signless_upper_right);
+
+    /* sign difference selects add or sub operation. */
+    if(Sgl_ismagnitudeless(signless_upper_left,signless_upper_right))
+	{
+	/* Set the left operand to the larger one by XOR swap *
+	 *  First finish the first word using "save"          */
+	Sgl_xorfromintp1(save,right,/*to*/right);
+	Sgl_xorfromintp1(save,left,/*to*/left);
+	result_exponent = Sgl_exponent(left);
+	}
+    /* Invariant:  left is not smaller than right. */ 
+
+    if((right_exponent = Sgl_exponent(right)) == 0)
+        {
+	/* Denormalized operands.  First look for zeroes */
+	if(Sgl_iszero_mantissa(right)) 
+	    {
+	    /* right is zero */
+	    if(Sgl_iszero_exponentmantissa(left))
+		{
+		/* Both operands are zeros */
+		if(Is_rounding_mode(ROUNDMINUS))
+		    {
+		    Sgl_or_signs(left,/*with*/right);
+		    }
+		else
+		    {
+		    Sgl_and_signs(left,/*with*/right);
+		    }
+		}
+	    else 
+		{
+		/* Left is not a zero and must be the result.  Trapped
+		 * underflows are signaled if left is denormalized.  Result
+		 * is always exact. */
+		if( (result_exponent == 0) && Is_underflowtrap_enabled() )
+		    {
+		    /* need to normalize results mantissa */
+	    	    sign_save = Sgl_signextendedsign(left);
+		    Sgl_leftshiftby1(left);
+		    Sgl_normalize(left,result_exponent);
+		    Sgl_set_sign(left,/*using*/sign_save);
+		    Sgl_setwrapped_exponent(left,result_exponent,unfl);
+		    *dstptr = left;
+		    return(UNDERFLOWEXCEPTION);
+		    }
+		}
+	    *dstptr = left;
+	    return(NOEXCEPTION);
+	    }
+
+	/* Neither are zeroes */
+	Sgl_clear_sign(right);	/* Exponent is already cleared */
+	if(result_exponent == 0 )
+	    {
+	    /* Both operands are denormalized.  The result must be exact
+	     * and is simply calculated.  A sum could become normalized and a
+	     * difference could cancel to a true zero. */
+	    if( (/*signed*/int) save < 0 )
+		{
+		Sgl_subtract(left,/*minus*/right,/*into*/result);
+		if(Sgl_iszero_mantissa(result))
+		    {
+		    if(Is_rounding_mode(ROUNDMINUS))
+			{
+			Sgl_setone_sign(result);
+			}
+		    else
+			{
+			Sgl_setzero_sign(result);
+			}
+		    *dstptr = result;
+		    return(NOEXCEPTION);
+		    }
+		}
+	    else
+		{
+		Sgl_addition(left,right,/*into*/result);
+		if(Sgl_isone_hidden(result))
+		    {
+		    *dstptr = result;
+		    return(NOEXCEPTION);
+		    }
+		}
+	    if(Is_underflowtrap_enabled())
+		{
+		/* need to normalize result */
+	    	sign_save = Sgl_signextendedsign(result);
+		Sgl_leftshiftby1(result);
+		Sgl_normalize(result,result_exponent);
+		Sgl_set_sign(result,/*using*/sign_save);
+                Sgl_setwrapped_exponent(result,result_exponent,unfl);
+		*dstptr = result;
+		return(UNDERFLOWEXCEPTION);
+		}
+	    *dstptr = result;
+	    return(NOEXCEPTION);
+	    }
+	right_exponent = 1;	/* Set exponent to reflect different bias
+				 * with denomalized numbers. */
+	}
+    else
+	{
+	Sgl_clear_signexponent_set_hidden(right);
+	}
+    Sgl_clear_exponent_set_hidden(left);
+    diff_exponent = result_exponent - right_exponent;
+
+    /* 
+     * Special case alignment of operands that would force alignment 
+     * beyond the extent of the extension.  A further optimization
+     * could special case this but only reduces the path length for this
+     * infrequent case.
+     */
+    if(diff_exponent > SGL_THRESHOLD)
+	{
+	diff_exponent = SGL_THRESHOLD;
+	}
+    
+    /* Align right operand by shifting to right */
+    Sgl_right_align(/*operand*/right,/*shifted by*/diff_exponent,
+     /*and lower to*/extent);
+
+    /* Treat sum and difference of the operands separately. */
+    if( (/*signed*/int) save < 0 )
+	{
+	/*
+	 * Difference of the two operands.  Their can be no overflow.  A
+	 * borrow can occur out of the hidden bit and force a post
+	 * normalization phase.
+	 */
+	Sgl_subtract_withextension(left,/*minus*/right,/*with*/extent,/*into*/result);
+	if(Sgl_iszero_hidden(result))
+	    {
+	    /* Handle normalization */
+	    /* A straight foward algorithm would now shift the result
+	     * and extension left until the hidden bit becomes one.  Not
+	     * all of the extension bits need participate in the shift.
+	     * Only the two most significant bits (round and guard) are
+	     * needed.  If only a single shift is needed then the guard
+	     * bit becomes a significant low order bit and the extension
+	     * must participate in the rounding.  If more than a single 
+	     * shift is needed, then all bits to the right of the guard 
+	     * bit are zeros, and the guard bit may or may not be zero. */
+	    sign_save = Sgl_signextendedsign(result);
+            Sgl_leftshiftby1_withextent(result,extent,result);
+
+            /* Need to check for a zero result.  The sign and exponent
+	     * fields have already been zeroed.  The more efficient test
+	     * of the full object can be used.
+	     */
+    	    if(Sgl_iszero(result))
+		/* Must have been "x-x" or "x+(-x)". */
+		{
+		if(Is_rounding_mode(ROUNDMINUS)) Sgl_setone_sign(result);
+		*dstptr = result;
+		return(NOEXCEPTION);
+		}
+	    result_exponent--;
+	    /* Look to see if normalization is finished. */
+	    if(Sgl_isone_hidden(result))
+		{
+		if(result_exponent==0)
+		    {
+		    /* Denormalized, exponent should be zero.  Left operand *
+ 		     * was normalized, so extent (guard, round) was zero    */
+		    goto underflow;
+		    }
+		else
+		    {
+		    /* No further normalization is needed. */
+		    Sgl_set_sign(result,/*using*/sign_save);
+	    	    Ext_leftshiftby1(extent);
+		    goto round;
+		    }
+		}
+
+	    /* Check for denormalized, exponent should be zero.  Left    * 
+	     * operand was normalized, so extent (guard, round) was zero */
+	    if(!(underflowtrap = Is_underflowtrap_enabled()) &&
+	       result_exponent==0) goto underflow;
+
+	    /* Shift extension to complete one bit of normalization and
+	     * update exponent. */
+	    Ext_leftshiftby1(extent);
+
+	    /* Discover first one bit to determine shift amount.  Use a
+	     * modified binary search.  We have already shifted the result
+	     * one position right and still not found a one so the remainder
+	     * of the extension must be zero and simplifies rounding. */
+	    /* Scan bytes */
+	    while(Sgl_iszero_hiddenhigh7mantissa(result))
+		{
+		Sgl_leftshiftby8(result);
+		if((result_exponent -= 8) <= 0  && !underflowtrap)
+		    goto underflow;
+		}
+	    /* Now narrow it down to the nibble */
+	    if(Sgl_iszero_hiddenhigh3mantissa(result))
+		{
+		/* The lower nibble contains the normalizing one */
+		Sgl_leftshiftby4(result);
+		if((result_exponent -= 4) <= 0 && !underflowtrap)
+		    goto underflow;
+		}
+	    /* Select case were first bit is set (already normalized)
+	     * otherwise select the proper shift. */
+	    if((jumpsize = Sgl_hiddenhigh3mantissa(result)) > 7)
+		{
+		/* Already normalized */
+		if(result_exponent <= 0) goto underflow;
+		Sgl_set_sign(result,/*using*/sign_save);
+		Sgl_set_exponent(result,/*using*/result_exponent);
+		*dstptr = result;
+		return(NOEXCEPTION);
+		}
+	    Sgl_sethigh4bits(result,/*using*/sign_save);
+	    switch(jumpsize) 
+		{
+		case 1:
+		    {
+		    Sgl_leftshiftby3(result);
+		    result_exponent -= 3;
+		    break;
+		    }
+		case 2:
+		case 3:
+		    {
+		    Sgl_leftshiftby2(result);
+		    result_exponent -= 2;
+		    break;
+		    }
+		case 4:
+		case 5:
+		case 6:
+		case 7:
+		    {
+		    Sgl_leftshiftby1(result);
+		    result_exponent -= 1;
+		    break;
+		    }
+		}
+	    if(result_exponent > 0) 
+		{
+		Sgl_set_exponent(result,/*using*/result_exponent);
+		*dstptr = result;
+		return(NOEXCEPTION); /* Sign bit is already set */
+		}
+	    /* Fixup potential underflows */
+	  underflow:
+	    if(Is_underflowtrap_enabled())
+		{
+		Sgl_set_sign(result,sign_save);
+                Sgl_setwrapped_exponent(result,result_exponent,unfl);
+		*dstptr = result;
+		/* inexact = FALSE; */
+		return(UNDERFLOWEXCEPTION);
+		}
+	    /* 
+	     * Since we cannot get an inexact denormalized result,
+	     * we can now return.
+	     */
+	    Sgl_right_align(result,/*by*/(1-result_exponent),extent);
+	    Sgl_clear_signexponent(result);
+	    Sgl_set_sign(result,sign_save);
+	    *dstptr = result;
+	    return(NOEXCEPTION);
+	    } /* end if(hidden...)... */
+	/* Fall through and round */
+	} /* end if(save < 0)... */
+    else 
+	{
+	/* Add magnitudes */
+	Sgl_addition(left,right,/*to*/result);
+	if(Sgl_isone_hiddenoverflow(result))
+	    {
+	    /* Prenormalization required. */
+	    Sgl_rightshiftby1_withextent(result,extent,extent);
+	    Sgl_arithrightshiftby1(result);
+	    result_exponent++;
+	    } /* end if hiddenoverflow... */
+	} /* end else ...add magnitudes... */
+    
+    /* Round the result.  If the extension is all zeros,then the result is
+     * exact.  Otherwise round in the correct direction.  No underflow is
+     * possible. If a postnormalization is necessary, then the mantissa is
+     * all zeros so no shift is needed. */
+  round:
+    if(Ext_isnotzero(extent))
+	{
+	inexact = TRUE;
+	switch(Rounding_mode())
+	    {
+	    case ROUNDNEAREST: /* The default. */
+	    if(Ext_isone_sign(extent))
+		{
+		/* at least 1/2 ulp */
+		if(Ext_isnotzero_lower(extent)  ||
+		  Sgl_isone_lowmantissa(result))
+		    {
+		    /* either exactly half way and odd or more than 1/2ulp */
+		    Sgl_increment(result);
+		    }
+		}
+	    break;
+
+	    case ROUNDPLUS:
+	    if(Sgl_iszero_sign(result))
+		{
+		/* Round up positive results */
+		Sgl_increment(result);
+		}
+	    break;
+	    
+	    case ROUNDMINUS:
+	    if(Sgl_isone_sign(result))
+		{
+		/* Round down negative results */
+		Sgl_increment(result);
+		}
+	    
+	    case ROUNDZERO:;
+	    /* truncate is simple */
+	    } /* end switch... */
+	if(Sgl_isone_hiddenoverflow(result)) result_exponent++;
+	}
+    if(result_exponent == SGL_INFINITY_EXPONENT)
+        {
+        /* Overflow */
+        if(Is_overflowtrap_enabled())
+	    {
+	    Sgl_setwrapped_exponent(result,result_exponent,ovfl);
+	    *dstptr = result;
+	    if (inexact)
+		if (Is_inexacttrap_enabled())
+		    return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+		else Set_inexactflag();
+	    return(OVERFLOWEXCEPTION);
+	    }
+        else
+	    {
+	    Set_overflowflag();
+	    inexact = TRUE;
+	    Sgl_setoverflow(result);
+	    }
+	}
+    else Sgl_set_exponent(result,result_exponent);
+    *dstptr = result;
+    if(inexact) 
+	if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+	else Set_inexactflag();
+    return(NOEXCEPTION);
+    }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/sfcmp.c linux-2.4.20/arch/parisc/math-emu/sfcmp.c
--- linux-2.4.19/arch/parisc/math-emu/sfcmp.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/sfcmp.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,155 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/sfcmp.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	sgl_cmp: compare two values
+ *
+ *  External Interfaces:
+ *	sgl_fcmp(leftptr, rightptr, cond, status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+    
+/*
+ * sgl_cmp: compare two values
+ */
+int
+sgl_fcmp (sgl_floating_point * leftptr, sgl_floating_point * rightptr,
+	  unsigned int cond, unsigned int *status)
+                                           
+                       /* The predicate to be tested */
+                         
+    {
+    register unsigned int left, right;
+    register int xorresult;
+        
+    /* Create local copies of the numbers */
+    left = *leftptr;
+    right = *rightptr;
+
+    /*
+     * Test for NaN
+     */
+    if(    (Sgl_exponent(left) == SGL_INFINITY_EXPONENT)
+        || (Sgl_exponent(right) == SGL_INFINITY_EXPONENT) )
+	{
+	/* Check if a NaN is involved.  Signal an invalid exception when 
+	 * comparing a signaling NaN or when comparing quiet NaNs and the
+	 * low bit of the condition is set */
+        if( (  (Sgl_exponent(left) == SGL_INFINITY_EXPONENT)
+	    && Sgl_isnotzero_mantissa(left) 
+	    && (Exception(cond) || Sgl_isone_signaling(left)))
+	   ||
+	    (  (Sgl_exponent(right) == SGL_INFINITY_EXPONENT)
+	    && Sgl_isnotzero_mantissa(right) 
+	    && (Exception(cond) || Sgl_isone_signaling(right)) ) )
+	    {
+	    if( Is_invalidtrap_enabled() ) {
+	    	Set_status_cbit(Unordered(cond));
+		return(INVALIDEXCEPTION);
+	    }
+	    else Set_invalidflag();
+	    Set_status_cbit(Unordered(cond));
+	    return(NOEXCEPTION);
+	    }
+	/* All the exceptional conditions are handled, now special case
+	   NaN compares */
+        else if( ((Sgl_exponent(left) == SGL_INFINITY_EXPONENT)
+	    && Sgl_isnotzero_mantissa(left))
+	   ||
+	    ((Sgl_exponent(right) == SGL_INFINITY_EXPONENT)
+	    && Sgl_isnotzero_mantissa(right)) )
+	    {
+	    /* NaNs always compare unordered. */
+	    Set_status_cbit(Unordered(cond));
+	    return(NOEXCEPTION);
+	    }
+	/* infinities will drop down to the normal compare mechanisms */
+	}
+    /* First compare for unequal signs => less or greater or
+     * special equal case */
+    Sgl_xortointp1(left,right,xorresult);
+    if( xorresult < 0 )
+        {
+        /* left negative => less, left positive => greater.
+         * equal is possible if both operands are zeros. */
+        if( Sgl_iszero_exponentmantissa(left) 
+	  && Sgl_iszero_exponentmantissa(right) )
+            {
+	    Set_status_cbit(Equal(cond));
+	    }
+	else if( Sgl_isone_sign(left) )
+	    {
+	    Set_status_cbit(Lessthan(cond));
+	    }
+	else
+	    {
+	    Set_status_cbit(Greaterthan(cond));
+	    }
+        }
+    /* Signs are the same.  Treat negative numbers separately
+     * from the positives because of the reversed sense.  */
+    else if( Sgl_all(left) == Sgl_all(right) )
+        {
+        Set_status_cbit(Equal(cond));
+        }
+    else if( Sgl_iszero_sign(left) )
+        {
+        /* Positive compare */
+        if( Sgl_all(left) < Sgl_all(right) )
+	    {
+	    Set_status_cbit(Lessthan(cond));
+	    }
+	else
+	    {
+	    Set_status_cbit(Greaterthan(cond));
+	    }
+	}
+    else
+        {
+        /* Negative compare.  Signed or unsigned compares
+         * both work the same.  That distinction is only
+         * important when the sign bits differ. */
+        if( Sgl_all(left) > Sgl_all(right) )
+	    {
+	    Set_status_cbit(Lessthan(cond));
+	    }
+        else
+	    {
+	    Set_status_cbit(Greaterthan(cond));
+	    }
+        }
+	return(NOEXCEPTION);
+    }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/sfdiv.c linux-2.4.20/arch/parisc/math-emu/sfdiv.c
--- linux-2.4.19/arch/parisc/math-emu/sfdiv.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/sfdiv.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,392 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/sfdiv.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single Precision Floating-point Divide
+ *
+ *  External Interfaces:
+ *	sgl_fdiv(srcptr1,srcptr2,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ *  Single Precision Floating-point Divide
+ */
+
+int
+sgl_fdiv (sgl_floating_point * srcptr1, sgl_floating_point * srcptr2,
+	  sgl_floating_point * dstptr, unsigned int *status)
+{
+	register unsigned int opnd1, opnd2, opnd3, result;
+	register int dest_exponent, count;
+	register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
+	boolean is_tiny;
+
+	opnd1 = *srcptr1;
+	opnd2 = *srcptr2;
+	/* 
+	 * set sign bit of result 
+	 */
+	if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result);  
+	else Sgl_setzero(result);
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd1)) {
+		if (Sgl_iszero_mantissa(opnd1)) {
+			if (Sgl_isnotnan(opnd2)) {
+				if (Sgl_isinfinity(opnd2)) {
+					/* 
+					 * invalid since both operands 
+					 * are infinity 
+					 */
+					if (Is_invalidtrap_enabled()) 
+                                		return(INVALIDEXCEPTION);
+                                	Set_invalidflag();
+                                	Sgl_makequietnan(result);
+					*dstptr = result;
+					return(NOEXCEPTION);
+				}
+				/*
+			 	 * return infinity
+			 	 */
+				Sgl_setinfinity_exponentmantissa(result);
+				*dstptr = result;
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+                	/*
+                 	 * is NaN; signaling or quiet?
+                 	 */
+                	if (Sgl_isone_signaling(opnd1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled()) 
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Sgl_set_quiet(opnd1);
+                	}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd2)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled())
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Sgl_set_quiet(opnd2);
+                		*dstptr = opnd2;
+                		return(NOEXCEPTION);
+			}
+                	/*
+                 	 * return quiet NaN
+                 	 */
+                	*dstptr = opnd1;
+                	return(NOEXCEPTION);
+		}
+	}
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd2)) {
+		if (Sgl_iszero_mantissa(opnd2)) {
+			/*
+			 * return zero
+			 */
+			Sgl_setzero_exponentmantissa(result);
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+                /*
+                 * is NaN; signaling or quiet?
+                 */
+                if (Sgl_isone_signaling(opnd2)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Sgl_set_quiet(opnd2);
+                }
+                /*
+                 * return quiet NaN
+                 */
+                *dstptr = opnd2;
+                return(NOEXCEPTION);
+	}
+	/*
+	 * check for division by zero
+	 */
+	if (Sgl_iszero_exponentmantissa(opnd2)) {
+		if (Sgl_iszero_exponentmantissa(opnd1)) {
+			/* invalid since both operands are zero */
+			if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        Set_invalidflag();
+                        Sgl_makequietnan(result);
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+		if (Is_divisionbyzerotrap_enabled())
+                        return(DIVISIONBYZEROEXCEPTION);
+                Set_divisionbyzeroflag();
+                Sgl_setinfinity_exponentmantissa(result);
+		*dstptr = result;
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate exponent 
+	 */
+	dest_exponent = Sgl_exponent(opnd1) - Sgl_exponent(opnd2) + SGL_BIAS;
+
+	/*
+	 * Generate mantissa
+	 */
+	if (Sgl_isnotzero_exponent(opnd1)) {
+		/* set hidden bit */
+		Sgl_clear_signexponent_set_hidden(opnd1);
+	}
+	else {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd1)) {
+			Sgl_setzero_exponentmantissa(result);
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+                /* is denormalized; want to normalize */
+                Sgl_clear_signexponent(opnd1);
+                Sgl_leftshiftby1(opnd1);
+		Sgl_normalize(opnd1,dest_exponent);
+	}
+	/* opnd2 needs to have hidden bit set with msb in hidden bit */
+	if (Sgl_isnotzero_exponent(opnd2)) {
+		Sgl_clear_signexponent_set_hidden(opnd2);
+	}
+	else {
+                /* is denormalized; want to normalize */
+                Sgl_clear_signexponent(opnd2);
+                Sgl_leftshiftby1(opnd2);
+		while(Sgl_iszero_hiddenhigh7mantissa(opnd2)) {
+			Sgl_leftshiftby8(opnd2);
+			dest_exponent += 8;
+		}
+		if(Sgl_iszero_hiddenhigh3mantissa(opnd2)) {
+			Sgl_leftshiftby4(opnd2);
+			dest_exponent += 4;
+		}
+		while(Sgl_iszero_hidden(opnd2)) {
+			Sgl_leftshiftby1(opnd2);
+			dest_exponent += 1;
+		}
+	}
+
+	/* Divide the source mantissas */
+
+	/*
+	 * A non_restoring divide algorithm is used.
+	 */
+	Sgl_subtract(opnd1,opnd2,opnd1);
+	Sgl_setzero(opnd3);
+	for (count=1;count<=SGL_P && Sgl_all(opnd1);count++) {
+		Sgl_leftshiftby1(opnd1);
+		Sgl_leftshiftby1(opnd3);
+		if (Sgl_iszero_sign(opnd1)) {
+			Sgl_setone_lowmantissa(opnd3);
+			Sgl_subtract(opnd1,opnd2,opnd1);
+		}
+		else Sgl_addition(opnd1,opnd2,opnd1);
+	}
+	if (count <= SGL_P) {
+		Sgl_leftshiftby1(opnd3);
+		Sgl_setone_lowmantissa(opnd3);
+		Sgl_leftshift(opnd3,SGL_P-count);
+		if (Sgl_iszero_hidden(opnd3)) {
+			Sgl_leftshiftby1(opnd3);
+			dest_exponent--;
+		}
+	}
+	else {
+		if (Sgl_iszero_hidden(opnd3)) {
+			/* need to get one more bit of result */
+			Sgl_leftshiftby1(opnd1);
+			Sgl_leftshiftby1(opnd3);
+			if (Sgl_iszero_sign(opnd1)) {
+				Sgl_setone_lowmantissa(opnd3);
+				Sgl_subtract(opnd1,opnd2,opnd1);
+			}
+			else Sgl_addition(opnd1,opnd2,opnd1);
+			dest_exponent--;
+		}
+		if (Sgl_iszero_sign(opnd1)) guardbit = TRUE;
+		stickybit = Sgl_all(opnd1);
+	}
+	inexact = guardbit | stickybit;
+
+	/* 
+	 * round result 
+	 */
+	if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) {
+		Sgl_clear_signexponent(opnd3);
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Sgl_iszero_sign(result)) 
+					Sgl_increment_mantissa(opnd3);
+				break;
+			case ROUNDMINUS: 
+				if (Sgl_isone_sign(result)) 
+					Sgl_increment_mantissa(opnd3);
+				break;
+			case ROUNDNEAREST:
+				if (guardbit) {
+			   	if (stickybit || Sgl_isone_lowmantissa(opnd3))
+			      	    Sgl_increment_mantissa(opnd3);
+				}
+		}
+		if (Sgl_isone_hidden(opnd3)) dest_exponent++;
+	}
+	Sgl_set_mantissa(result,opnd3);
+
+        /* 
+         * Test for overflow
+         */
+	if (dest_exponent >= SGL_INFINITY_EXPONENT) {
+                /* trap if OVERFLOWTRAP enabled */
+                if (Is_overflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
+                        *dstptr = result;
+                        if (inexact) 
+                            if (Is_inexacttrap_enabled())
+                                return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+                            else Set_inexactflag();
+                        return(OVERFLOWEXCEPTION);
+                }
+		Set_overflowflag();
+                /* set result to infinity or largest number */
+		Sgl_setoverflow(result);
+		inexact = TRUE;
+	}
+        /* 
+         * Test for underflow
+         */
+	else if (dest_exponent <= 0) {
+                /* trap if UNDERFLOWTRAP enabled */
+                if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Sgl_setwrapped_exponent(result,dest_exponent,unfl);
+                        *dstptr = result;
+                        if (inexact) 
+                            if (Is_inexacttrap_enabled())
+                                return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
+                            else Set_inexactflag();
+                        return(UNDERFLOWEXCEPTION);
+                }
+
+		/* Determine if should set underflow flag */
+		is_tiny = TRUE;
+		if (dest_exponent == 0 && inexact) {
+			switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Sgl_iszero_sign(result)) {
+					Sgl_increment(opnd3);
+					if (Sgl_isone_hiddenoverflow(opnd3))
+                			    is_tiny = FALSE;
+					Sgl_decrement(opnd3);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Sgl_isone_sign(result)) {
+					Sgl_increment(opnd3);
+					if (Sgl_isone_hiddenoverflow(opnd3))
+                			    is_tiny = FALSE;
+					Sgl_decrement(opnd3);
+				}
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Sgl_isone_lowmantissa(opnd3))) {
+				      	Sgl_increment(opnd3);
+					if (Sgl_isone_hiddenoverflow(opnd3))
+                			    is_tiny = FALSE;
+					Sgl_decrement(opnd3);
+				}
+				break;
+			}
+		}
+
+                /*
+                 * denormalize result or set to signed zero
+                 */
+		stickybit = inexact;
+		Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact);
+
+		/* return rounded number */ 
+		if (inexact) {
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				if (Sgl_iszero_sign(result)) {
+					Sgl_increment(opnd3);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Sgl_isone_sign(result))  {
+					Sgl_increment(opnd3);
+				}
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Sgl_isone_lowmantissa(opnd3))) {
+			      		Sgl_increment(opnd3);
+				}
+				break;
+			}
+                	if (is_tiny) Set_underflowflag();
+                }
+		Sgl_set_exponentmantissa(result,opnd3);
+	}
+	else Sgl_set_exponent(result,dest_exponent);
+	*dstptr = result;
+	/* check for inexact */
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else  Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/sfmpy.c linux-2.4.20/arch/parisc/math-emu/sfmpy.c
--- linux-2.4.19/arch/parisc/math-emu/sfmpy.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/sfmpy.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,380 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/sfmpy.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single Precision Floating-point Multiply
+ *
+ *  External Interfaces:
+ *	sgl_fmpy(srcptr1,srcptr2,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ *  Single Precision Floating-point Multiply
+ */
+
+int
+sgl_fmpy(
+    sgl_floating_point *srcptr1,
+    sgl_floating_point *srcptr2,
+    sgl_floating_point *dstptr,
+    unsigned int *status)
+{
+	register unsigned int opnd1, opnd2, opnd3, result;
+	register int dest_exponent, count;
+	register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
+	boolean is_tiny;
+
+	opnd1 = *srcptr1;
+	opnd2 = *srcptr2;
+	/* 
+	 * set sign bit of result 
+	 */
+	if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result);  
+	else Sgl_setzero(result);
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd1)) {
+		if (Sgl_iszero_mantissa(opnd1)) {
+			if (Sgl_isnotnan(opnd2)) {
+				if (Sgl_iszero_exponentmantissa(opnd2)) {
+					/* 
+					 * invalid since operands are infinity 
+					 * and zero 
+					 */
+					if (Is_invalidtrap_enabled()) 
+                                		return(INVALIDEXCEPTION);
+                                	Set_invalidflag();
+                                	Sgl_makequietnan(result);
+					*dstptr = result;
+					return(NOEXCEPTION);
+				}
+				/*
+			 	 * return infinity
+			 	 */
+				Sgl_setinfinity_exponentmantissa(result);
+				*dstptr = result;
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+                	/*
+                 	 * is NaN; signaling or quiet?
+                 	 */
+                	if (Sgl_isone_signaling(opnd1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled()) 
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Sgl_set_quiet(opnd1);
+                	}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd2)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled()) 
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Sgl_set_quiet(opnd2);
+                		*dstptr = opnd2;
+                		return(NOEXCEPTION);
+			}
+                	/*
+                 	 * return quiet NaN
+                 	 */
+                	*dstptr = opnd1;
+                	return(NOEXCEPTION);
+		}
+	}
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd2)) {
+		if (Sgl_iszero_mantissa(opnd2)) {
+			if (Sgl_iszero_exponentmantissa(opnd1)) {
+				/* invalid since operands are zero & infinity */
+				if (Is_invalidtrap_enabled()) 
+                                	return(INVALIDEXCEPTION);
+                                Set_invalidflag();
+                                Sgl_makequietnan(opnd2);
+				*dstptr = opnd2;
+				return(NOEXCEPTION);
+			}
+			/*
+			 * return infinity
+			 */
+			Sgl_setinfinity_exponentmantissa(result);
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+                /*
+                 * is NaN; signaling or quiet?
+                 */
+                if (Sgl_isone_signaling(opnd2)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Sgl_set_quiet(opnd2);
+                }
+                /*
+                 * return quiet NaN
+                 */
+                *dstptr = opnd2;
+                return(NOEXCEPTION);
+	}
+	/*
+	 * Generate exponent 
+	 */
+	dest_exponent = Sgl_exponent(opnd1) + Sgl_exponent(opnd2) - SGL_BIAS;
+
+	/*
+	 * Generate mantissa
+	 */
+	if (Sgl_isnotzero_exponent(opnd1)) {
+		/* set hidden bit */
+		Sgl_clear_signexponent_set_hidden(opnd1);
+	}
+	else {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd1)) {
+			Sgl_setzero_exponentmantissa(result);
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+                /* is denormalized, adjust exponent */
+                Sgl_clear_signexponent(opnd1);
+		Sgl_leftshiftby1(opnd1);
+		Sgl_normalize(opnd1,dest_exponent);
+	}
+	/* opnd2 needs to have hidden bit set with msb in hidden bit */
+	if (Sgl_isnotzero_exponent(opnd2)) {
+		Sgl_clear_signexponent_set_hidden(opnd2);
+	}
+	else {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd2)) {
+			Sgl_setzero_exponentmantissa(result);
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+                /* is denormalized; want to normalize */
+                Sgl_clear_signexponent(opnd2);
+                Sgl_leftshiftby1(opnd2);
+		Sgl_normalize(opnd2,dest_exponent);
+	}
+
+	/* Multiply two source mantissas together */
+
+	Sgl_leftshiftby4(opnd2);     /* make room for guard bits */
+	Sgl_setzero(opnd3);
+	/*
+	 * Four bits at a time are inspected in each loop, and a
+	 * simple shift and add multiply algorithm is used.
+	 */
+	for (count=1;count<SGL_P;count+=4) {
+		stickybit |= Slow4(opnd3);
+		Sgl_rightshiftby4(opnd3);
+		if (Sbit28(opnd1)) Sall(opnd3) += (Sall(opnd2) << 3);
+		if (Sbit29(opnd1)) Sall(opnd3) += (Sall(opnd2) << 2);
+		if (Sbit30(opnd1)) Sall(opnd3) += (Sall(opnd2) << 1);
+		if (Sbit31(opnd1)) Sall(opnd3) += Sall(opnd2);
+		Sgl_rightshiftby4(opnd1);
+	}
+	/* make sure result is left-justified */
+	if (Sgl_iszero_sign(opnd3)) {
+		Sgl_leftshiftby1(opnd3);
+	}
+	else {
+		/* result mantissa >= 2. */
+		dest_exponent++;
+	}
+	/* check for denormalized result */
+	while (Sgl_iszero_sign(opnd3)) {
+		Sgl_leftshiftby1(opnd3);
+		dest_exponent--;
+	}
+	/*
+	 * check for guard, sticky and inexact bits
+	 */
+	stickybit |= Sgl_all(opnd3) << (SGL_BITLENGTH - SGL_EXP_LENGTH + 1);
+	guardbit = Sbit24(opnd3);
+	inexact = guardbit | stickybit;
+
+	/* re-align mantissa */
+	Sgl_rightshiftby8(opnd3);
+
+	/* 
+	 * round result 
+	 */
+	if (inexact && (dest_exponent>0 || Is_underflowtrap_enabled())) {
+		Sgl_clear_signexponent(opnd3);
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Sgl_iszero_sign(result)) 
+					Sgl_increment(opnd3);
+				break;
+			case ROUNDMINUS: 
+				if (Sgl_isone_sign(result)) 
+					Sgl_increment(opnd3);
+				break;
+			case ROUNDNEAREST:
+				if (guardbit) {
+			   	if (stickybit || Sgl_isone_lowmantissa(opnd3))
+			      	Sgl_increment(opnd3);
+				}
+		}
+		if (Sgl_isone_hidden(opnd3)) dest_exponent++;
+	}
+	Sgl_set_mantissa(result,opnd3);
+
+        /* 
+         * Test for overflow
+         */
+	if (dest_exponent >= SGL_INFINITY_EXPONENT) {
+                /* trap if OVERFLOWTRAP enabled */
+                if (Is_overflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+			Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
+			*dstptr = result;
+			if (inexact) 
+			    if (Is_inexacttrap_enabled())
+				return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+			    else Set_inexactflag();
+			return(OVERFLOWEXCEPTION);
+                }
+		inexact = TRUE;
+		Set_overflowflag();
+                /* set result to infinity or largest number */
+		Sgl_setoverflow(result);
+	}
+        /* 
+         * Test for underflow
+         */
+	else if (dest_exponent <= 0) {
+                /* trap if UNDERFLOWTRAP enabled */
+                if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+			Sgl_setwrapped_exponent(result,dest_exponent,unfl);
+			*dstptr = result;
+			if (inexact) 
+			    if (Is_inexacttrap_enabled())
+				return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
+			    else Set_inexactflag();
+			return(UNDERFLOWEXCEPTION);
+                }
+
+		/* Determine if should set underflow flag */
+		is_tiny = TRUE;
+		if (dest_exponent == 0 && inexact) {
+			switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Sgl_iszero_sign(result)) {
+					Sgl_increment(opnd3);
+					if (Sgl_isone_hiddenoverflow(opnd3))
+                			    is_tiny = FALSE;
+					Sgl_decrement(opnd3);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Sgl_isone_sign(result)) {
+					Sgl_increment(opnd3);
+					if (Sgl_isone_hiddenoverflow(opnd3))
+                			    is_tiny = FALSE;
+					Sgl_decrement(opnd3);
+				}
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Sgl_isone_lowmantissa(opnd3))) {
+				      	Sgl_increment(opnd3);
+					if (Sgl_isone_hiddenoverflow(opnd3))
+                			    is_tiny = FALSE;
+					Sgl_decrement(opnd3);
+				}
+				break;
+			}
+		}
+
+                /*
+                 * denormalize result or set to signed zero
+                 */
+		stickybit = inexact;
+		Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact);
+
+		/* return zero or smallest number */
+		if (inexact) {
+			switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Sgl_iszero_sign(result)) {
+					Sgl_increment(opnd3);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Sgl_isone_sign(result)) {
+					Sgl_increment(opnd3);
+				}
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Sgl_isone_lowmantissa(opnd3))) {
+			      		Sgl_increment(opnd3);
+				}
+				break;
+			}
+                if (is_tiny) Set_underflowflag();
+		}
+		Sgl_set_exponentmantissa(result,opnd3);
+	}
+	else Sgl_set_exponent(result,dest_exponent);
+	*dstptr = result;
+
+	/* check for inexact */
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/sfrem.c linux-2.4.20/arch/parisc/math-emu/sfrem.c
--- linux-2.4.19/arch/parisc/math-emu/sfrem.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/sfrem.c	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,290 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/sfrem.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single Precision Floating-point Remainder
+ *
+ *  External Interfaces:
+ *	sgl_frem(srcptr1,srcptr2,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ *  Single Precision Floating-point Remainder
+ */
+
+int
+sgl_frem (sgl_floating_point * srcptr1, sgl_floating_point * srcptr2,
+	  sgl_floating_point * dstptr, unsigned int *status)
+{
+	register unsigned int opnd1, opnd2, result;
+	register int opnd1_exponent, opnd2_exponent, dest_exponent, stepcount;
+	register boolean roundup = FALSE;
+
+	opnd1 = *srcptr1;
+	opnd2 = *srcptr2;
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if ((opnd1_exponent = Sgl_exponent(opnd1)) == SGL_INFINITY_EXPONENT) {
+		if (Sgl_iszero_mantissa(opnd1)) {
+			if (Sgl_isnotnan(opnd2)) {
+				/* invalid since first operand is infinity */
+				if (Is_invalidtrap_enabled()) 
+                                	return(INVALIDEXCEPTION);
+                                Set_invalidflag();
+                                Sgl_makequietnan(result);
+				*dstptr = result;
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+                	/*
+                 	 * is NaN; signaling or quiet?
+                 	 */
+                	if (Sgl_isone_signaling(opnd1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled()) 
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Sgl_set_quiet(opnd1);
+                	}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd2)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled()) 
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Sgl_set_quiet(opnd2);
+                		*dstptr = opnd2;
+                		return(NOEXCEPTION);
+			}
+                	/*
+                 	 * return quiet NaN
+                 	 */
+                	*dstptr = opnd1;
+                	return(NOEXCEPTION);
+		}
+	} 
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if ((opnd2_exponent = Sgl_exponent(opnd2)) == SGL_INFINITY_EXPONENT) {
+		if (Sgl_iszero_mantissa(opnd2)) {
+			/*
+			 * return first operand
+			 */
+                	*dstptr = opnd1;
+			return(NOEXCEPTION);
+		}
+                /*
+                 * is NaN; signaling or quiet?
+                 */
+                if (Sgl_isone_signaling(opnd2)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Sgl_set_quiet(opnd2);
+                }
+                /*
+                 * return quiet NaN
+                 */
+                *dstptr = opnd2;
+                return(NOEXCEPTION);
+	}
+	/*
+	 * check second operand for zero
+	 */
+	if (Sgl_iszero_exponentmantissa(opnd2)) {
+		/* invalid since second operand is zero */
+		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                Set_invalidflag();
+                Sgl_makequietnan(result);
+		*dstptr = result;
+		return(NOEXCEPTION);
+	}
+
+	/* 
+	 * get sign of result
+	 */
+	result = opnd1;  
+
+	/* 
+	 * check for denormalized operands
+	 */
+	if (opnd1_exponent == 0) {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd1)) {
+			*dstptr = opnd1;
+			return(NOEXCEPTION);
+		}
+		/* normalize, then continue */
+		opnd1_exponent = 1;
+		Sgl_normalize(opnd1,opnd1_exponent);
+	}
+	else {
+		Sgl_clear_signexponent_set_hidden(opnd1);
+	}
+	if (opnd2_exponent == 0) {
+		/* normalize, then continue */
+		opnd2_exponent = 1;
+		Sgl_normalize(opnd2,opnd2_exponent);
+	}
+	else {
+		Sgl_clear_signexponent_set_hidden(opnd2);
+	}
+
+	/* find result exponent and divide step loop count */
+	dest_exponent = opnd2_exponent - 1;
+	stepcount = opnd1_exponent - opnd2_exponent;
+
+	/*
+	 * check for opnd1/opnd2 < 1
+	 */
+	if (stepcount < 0) {
+		/*
+		 * check for opnd1/opnd2 > 1/2
+		 *
+		 * In this case n will round to 1, so 
+		 *    r = opnd1 - opnd2 
+		 */
+		if (stepcount == -1 && Sgl_isgreaterthan(opnd1,opnd2)) {
+			Sgl_all(result) = ~Sgl_all(result);   /* set sign */
+			/* align opnd2 with opnd1 */
+			Sgl_leftshiftby1(opnd2); 
+			Sgl_subtract(opnd2,opnd1,opnd2);
+			/* now normalize */
+                	while (Sgl_iszero_hidden(opnd2)) {
+                        	Sgl_leftshiftby1(opnd2);
+                        	dest_exponent--;
+			}
+			Sgl_set_exponentmantissa(result,opnd2);
+			goto testforunderflow;
+		}
+		/*
+		 * opnd1/opnd2 <= 1/2
+		 *
+		 * In this case n will round to zero, so 
+		 *    r = opnd1
+		 */
+		Sgl_set_exponentmantissa(result,opnd1);
+		dest_exponent = opnd1_exponent;
+		goto testforunderflow;
+	}
+
+	/*
+	 * Generate result
+	 *
+	 * Do iterative subtract until remainder is less than operand 2.
+	 */
+	while (stepcount-- > 0 && Sgl_all(opnd1)) {
+		if (Sgl_isnotlessthan(opnd1,opnd2))
+			Sgl_subtract(opnd1,opnd2,opnd1);
+		Sgl_leftshiftby1(opnd1);
+	}
+	/*
+	 * Do last subtract, then determine which way to round if remainder 
+	 * is exactly 1/2 of opnd2 
+	 */
+	if (Sgl_isnotlessthan(opnd1,opnd2)) {
+		Sgl_subtract(opnd1,opnd2,opnd1);
+		roundup = TRUE;
+	}
+	if (stepcount > 0 || Sgl_iszero(opnd1)) {
+		/* division is exact, remainder is zero */
+		Sgl_setzero_exponentmantissa(result);
+		*dstptr = result;
+		return(NOEXCEPTION);
+	}
+
+	/* 
+	 * Check for cases where opnd1/opnd2 < n 
+	 *
+	 * In this case the result's sign will be opposite that of
+	 * opnd1.  The mantissa also needs some correction.
+	 */
+	Sgl_leftshiftby1(opnd1);
+	if (Sgl_isgreaterthan(opnd1,opnd2)) {
+		Sgl_invert_sign(result);
+		Sgl_subtract((opnd2<<1),opnd1,opnd1);
+	}
+	/* check for remainder being exactly 1/2 of opnd2 */
+	else if (Sgl_isequal(opnd1,opnd2) && roundup) { 
+		Sgl_invert_sign(result);
+	}
+
+	/* normalize result's mantissa */
+        while (Sgl_iszero_hidden(opnd1)) {
+                dest_exponent--;
+                Sgl_leftshiftby1(opnd1);
+        }
+	Sgl_set_exponentmantissa(result,opnd1);
+
+        /* 
+         * Test for underflow
+         */
+    testforunderflow:
+	if (dest_exponent <= 0) {
+                /* trap if UNDERFLOWTRAP enabled */
+                if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Sgl_setwrapped_exponent(result,dest_exponent,unfl);
+			*dstptr = result;
+			/* frem is always exact */
+			return(UNDERFLOWEXCEPTION);
+                }
+                /*
+                 * denormalize result or set to signed zero
+                 */
+                if (dest_exponent >= (1 - SGL_P)) {
+			Sgl_rightshift_exponentmantissa(result,1-dest_exponent);
+                }
+                else {
+			Sgl_setzero_exponentmantissa(result);
+		}
+	}
+	else Sgl_set_exponent(result,dest_exponent);
+	*dstptr = result;
+	return(NOEXCEPTION);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/sfsqrt.c linux-2.4.20/arch/parisc/math-emu/sfsqrt.c
--- linux-2.4.19/arch/parisc/math-emu/sfsqrt.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/sfsqrt.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,187 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/sfsqrt.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single Floating-point Square Root
+ *
+ *  External Interfaces:
+ *	sgl_fsqrt(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ *  Single Floating-point Square Root
+ */
+
+/*ARGSUSED*/
+unsigned int
+sgl_fsqrt(
+    sgl_floating_point *srcptr,
+    unsigned int *nullptr,
+    sgl_floating_point *dstptr,
+    unsigned int *status)
+{
+	register unsigned int src, result;
+	register int src_exponent;
+	register unsigned int newbit, sum;
+	register boolean guardbit = FALSE, even_exponent;
+
+	src = *srcptr;
+        /*
+         * check source operand for NaN or infinity
+         */
+        if ((src_exponent = Sgl_exponent(src)) == SGL_INFINITY_EXPONENT) {
+                /*
+                 * is signaling NaN?
+                 */
+                if (Sgl_isone_signaling(src)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Sgl_set_quiet(src);
+                }
+                /*
+                 * Return quiet NaN or positive infinity.
+		 *  Fall thru to negative test if negative infinity.
+                 */
+		if (Sgl_iszero_sign(src) || Sgl_isnotzero_mantissa(src)) {
+                	*dstptr = src;
+                	return(NOEXCEPTION);
+		}
+        }
+
+        /*
+         * check for zero source operand
+         */
+	if (Sgl_iszero_exponentmantissa(src)) {
+		*dstptr = src;
+		return(NOEXCEPTION);
+	}
+
+        /*
+         * check for negative source operand 
+         */
+	if (Sgl_isone_sign(src)) {
+		/* trap if INVALIDTRAP enabled */
+		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+		/* make NaN quiet */
+		Set_invalidflag();
+		Sgl_makequietnan(src);
+		*dstptr = src;
+		return(NOEXCEPTION);
+	}
+
+	/*
+	 * Generate result
+	 */
+	if (src_exponent > 0) {
+		even_exponent = Sgl_hidden(src);
+		Sgl_clear_signexponent_set_hidden(src);
+	}
+	else {
+		/* normalize operand */
+		Sgl_clear_signexponent(src);
+		src_exponent++;
+		Sgl_normalize(src,src_exponent);
+		even_exponent = src_exponent & 1;
+	}
+	if (even_exponent) {
+		/* exponent is even */
+		/* Add comment here.  Explain why odd exponent needs correction */
+		Sgl_leftshiftby1(src);
+	}
+	/*
+	 * Add comment here.  Explain following algorithm.
+	 * 
+	 * Trust me, it works.
+	 *
+	 */
+	Sgl_setzero(result);
+	newbit = 1 << SGL_P;
+	while (newbit && Sgl_isnotzero(src)) {
+		Sgl_addition(result,newbit,sum);
+		if(sum <= Sgl_all(src)) {
+			/* update result */
+			Sgl_addition(result,(newbit<<1),result);
+			Sgl_subtract(src,sum,src);
+		}
+		Sgl_rightshiftby1(newbit);
+		Sgl_leftshiftby1(src);
+	}
+	/* correct exponent for pre-shift */
+	if (even_exponent) {
+		Sgl_rightshiftby1(result);
+	}
+
+	/* check for inexact */
+	if (Sgl_isnotzero(src)) {
+		if (!even_exponent && Sgl_islessthan(result,src)) 
+			Sgl_increment(result);
+		guardbit = Sgl_lowmantissa(result);
+		Sgl_rightshiftby1(result);
+
+		/*  now round result  */
+		switch (Rounding_mode()) {
+		case ROUNDPLUS:
+		     Sgl_increment(result);
+		     break;
+		case ROUNDNEAREST:
+		     /* stickybit is always true, so guardbit 
+		      * is enough to determine rounding */
+		     if (guardbit) {
+			Sgl_increment(result);
+		     }
+		     break;
+		}
+		/* increment result exponent by 1 if mantissa overflowed */
+		if (Sgl_isone_hiddenoverflow(result)) src_exponent+=2;
+
+		if (Is_inexacttrap_enabled()) {
+			Sgl_set_exponent(result,
+			 ((src_exponent-SGL_BIAS)>>1)+SGL_BIAS);
+			*dstptr = result;
+			return(INEXACTEXCEPTION);
+		}
+		else Set_inexactflag();
+	}
+	else {
+		Sgl_rightshiftby1(result);
+	}
+	Sgl_set_exponent(result,((src_exponent-SGL_BIAS)>>1)+SGL_BIAS);
+	*dstptr = result;
+	return(NOEXCEPTION);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/sfsub.c linux-2.4.20/arch/parisc/math-emu/sfsub.c
--- linux-2.4.19/arch/parisc/math-emu/sfsub.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/sfsub.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,521 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/sfsub.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single_subtract: subtract two single precision values.
+ *
+ *  External Interfaces:
+ *	sgl_fsub(leftptr, rightptr, dstptr, status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ * Single_subtract: subtract two single precision values.
+ */
+int
+sgl_fsub(
+	    sgl_floating_point *leftptr,
+	    sgl_floating_point *rightptr,
+	    sgl_floating_point *dstptr,
+	    unsigned int *status)
+    {
+    register unsigned int left, right, result, extent;
+    register unsigned int signless_upper_left, signless_upper_right, save;
+    
+    register int result_exponent, right_exponent, diff_exponent;
+    register int sign_save, jumpsize;
+    register boolean inexact = FALSE, underflowtrap;
+        
+    /* Create local copies of the numbers */
+    left = *leftptr;
+    right = *rightptr;
+
+    /* A zero "save" helps discover equal operands (for later),  *
+     * and is used in swapping operands (if needed).             */
+    Sgl_xortointp1(left,right,/*to*/save);
+
+    /*
+     * check first operand for NaN's or infinity
+     */
+    if ((result_exponent = Sgl_exponent(left)) == SGL_INFINITY_EXPONENT)
+	{
+	if (Sgl_iszero_mantissa(left)) 
+	    {
+	    if (Sgl_isnotnan(right)) 
+		{
+		if (Sgl_isinfinity(right) && save==0) 
+		    {
+		    /* 
+		     * invalid since operands are same signed infinity's
+		     */
+		    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                    Set_invalidflag();
+                    Sgl_makequietnan(result);
+		    *dstptr = result;
+		    return(NOEXCEPTION);
+		    }
+		/*
+	 	 * return infinity
+	 	 */
+		*dstptr = left;
+		return(NOEXCEPTION);
+		}
+	    }
+	else 
+	    {
+            /*
+             * is NaN; signaling or quiet?
+             */
+            if (Sgl_isone_signaling(left)) 
+		{
+               	/* trap if INVALIDTRAP enabled */
+		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+        	/* make NaN quiet */
+        	Set_invalidflag();
+        	Sgl_set_quiet(left);
+        	}
+	    /* 
+	     * is second operand a signaling NaN? 
+	     */
+	    else if (Sgl_is_signalingnan(right)) 
+		{
+        	/* trap if INVALIDTRAP enabled */
+               	if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+		/* make NaN quiet */
+		Set_invalidflag();
+		Sgl_set_quiet(right);
+		*dstptr = right;
+		return(NOEXCEPTION);
+		}
+	    /*
+ 	     * return quiet NaN
+ 	     */
+ 	    *dstptr = left;
+ 	    return(NOEXCEPTION);
+	    }
+	} /* End left NaN or Infinity processing */
+    /*
+     * check second operand for NaN's or infinity
+     */
+    if (Sgl_isinfinity_exponent(right)) 
+	{
+	if (Sgl_iszero_mantissa(right)) 
+	    {
+	    /* return infinity */
+	    Sgl_invert_sign(right);
+	    *dstptr = right;
+	    return(NOEXCEPTION);
+	    }
+        /*
+         * is NaN; signaling or quiet?
+         */
+        if (Sgl_isone_signaling(right)) 
+	    {
+            /* trap if INVALIDTRAP enabled */
+	    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+	    /* make NaN quiet */
+	    Set_invalidflag();
+	    Sgl_set_quiet(right);
+	    }
+	/*
+	 * return quiet NaN
+ 	 */
+	*dstptr = right;
+	return(NOEXCEPTION);
+    	} /* End right NaN or Infinity processing */
+
+    /* Invariant: Must be dealing with finite numbers */
+
+    /* Compare operands by removing the sign */
+    Sgl_copytoint_exponentmantissa(left,signless_upper_left);
+    Sgl_copytoint_exponentmantissa(right,signless_upper_right);
+
+    /* sign difference selects sub or add operation. */
+    if(Sgl_ismagnitudeless(signless_upper_left,signless_upper_right))
+	{
+	/* Set the left operand to the larger one by XOR swap *
+	 *  First finish the first word using "save"          */
+	Sgl_xorfromintp1(save,right,/*to*/right);
+	Sgl_xorfromintp1(save,left,/*to*/left);
+	result_exponent = Sgl_exponent(left);
+	Sgl_invert_sign(left);
+	}
+    /* Invariant:  left is not smaller than right. */ 
+
+    if((right_exponent = Sgl_exponent(right)) == 0)
+        {
+	/* Denormalized operands.  First look for zeroes */
+	if(Sgl_iszero_mantissa(right)) 
+	    {
+	    /* right is zero */
+	    if(Sgl_iszero_exponentmantissa(left))
+		{
+		/* Both operands are zeros */
+		Sgl_invert_sign(right);
+		if(Is_rounding_mode(ROUNDMINUS))
+		    {
+		    Sgl_or_signs(left,/*with*/right);
+		    }
+		else
+		    {
+		    Sgl_and_signs(left,/*with*/right);
+		    }
+		}
+	    else 
+		{
+		/* Left is not a zero and must be the result.  Trapped
+		 * underflows are signaled if left is denormalized.  Result
+		 * is always exact. */
+		if( (result_exponent == 0) && Is_underflowtrap_enabled() )
+		    {
+		    /* need to normalize results mantissa */
+	    	    sign_save = Sgl_signextendedsign(left);
+		    Sgl_leftshiftby1(left);
+		    Sgl_normalize(left,result_exponent);
+		    Sgl_set_sign(left,/*using*/sign_save);
+                    Sgl_setwrapped_exponent(left,result_exponent,unfl);
+		    *dstptr = left;
+		    /* inexact = FALSE */
+		    return(UNDERFLOWEXCEPTION);
+		    }
+		}
+	    *dstptr = left;
+	    return(NOEXCEPTION);
+	    }
+
+	/* Neither are zeroes */
+	Sgl_clear_sign(right);	/* Exponent is already cleared */
+	if(result_exponent == 0 )
+	    {
+	    /* Both operands are denormalized.  The result must be exact
+	     * and is simply calculated.  A sum could become normalized and a
+	     * difference could cancel to a true zero. */
+	    if( (/*signed*/int) save >= 0 )
+		{
+		Sgl_subtract(left,/*minus*/right,/*into*/result);
+		if(Sgl_iszero_mantissa(result))
+		    {
+		    if(Is_rounding_mode(ROUNDMINUS))
+			{
+			Sgl_setone_sign(result);
+			}
+		    else
+			{
+			Sgl_setzero_sign(result);
+			}
+		    *dstptr = result;
+		    return(NOEXCEPTION);
+		    }
+		}
+	    else
+		{
+		Sgl_addition(left,right,/*into*/result);
+		if(Sgl_isone_hidden(result))
+		    {
+		    *dstptr = result;
+		    return(NOEXCEPTION);
+		    }
+		}
+	    if(Is_underflowtrap_enabled())
+		{
+		/* need to normalize result */
+	    	sign_save = Sgl_signextendedsign(result);
+		Sgl_leftshiftby1(result);
+		Sgl_normalize(result,result_exponent);
+		Sgl_set_sign(result,/*using*/sign_save);
+                Sgl_setwrapped_exponent(result,result_exponent,unfl);
+		*dstptr = result;
+		/* inexact = FALSE */
+		return(UNDERFLOWEXCEPTION);
+		}
+	    *dstptr = result;
+	    return(NOEXCEPTION);
+	    }
+	right_exponent = 1;	/* Set exponent to reflect different bias
+				 * with denomalized numbers. */
+	}
+    else
+	{
+	Sgl_clear_signexponent_set_hidden(right);
+	}
+    Sgl_clear_exponent_set_hidden(left);
+    diff_exponent = result_exponent - right_exponent;
+
+    /* 
+     * Special case alignment of operands that would force alignment 
+     * beyond the extent of the extension.  A further optimization
+     * could special case this but only reduces the path length for this
+     * infrequent case.
+     */
+    if(diff_exponent > SGL_THRESHOLD)
+	{
+	diff_exponent = SGL_THRESHOLD;
+	}
+    
+    /* Align right operand by shifting to right */
+    Sgl_right_align(/*operand*/right,/*shifted by*/diff_exponent,
+      /*and lower to*/extent);
+
+    /* Treat sum and difference of the operands separately. */
+    if( (/*signed*/int) save >= 0 )
+	{
+	/*
+	 * Difference of the two operands.  Their can be no overflow.  A
+	 * borrow can occur out of the hidden bit and force a post
+	 * normalization phase.
+	 */
+	Sgl_subtract_withextension(left,/*minus*/right,/*with*/extent,/*into*/result);
+	if(Sgl_iszero_hidden(result))
+	    {
+	    /* Handle normalization */
+	    /* A straight foward algorithm would now shift the result
+	     * and extension left until the hidden bit becomes one.  Not
+	     * all of the extension bits need participate in the shift.
+	     * Only the two most significant bits (round and guard) are
+	     * needed.  If only a single shift is needed then the guard
+	     * bit becomes a significant low order bit and the extension
+	     * must participate in the rounding.  If more than a single 
+	     * shift is needed, then all bits to the right of the guard 
+	     * bit are zeros, and the guard bit may or may not be zero. */
+	    sign_save = Sgl_signextendedsign(result);
+            Sgl_leftshiftby1_withextent(result,extent,result);
+
+            /* Need to check for a zero result.  The sign and exponent
+	     * fields have already been zeroed.  The more efficient test
+	     * of the full object can be used.
+	     */
+    	    if(Sgl_iszero(result))
+		/* Must have been "x-x" or "x+(-x)". */
+		{
+		if(Is_rounding_mode(ROUNDMINUS)) Sgl_setone_sign(result);
+		*dstptr = result;
+		return(NOEXCEPTION);
+		}
+	    result_exponent--;
+	    /* Look to see if normalization is finished. */
+	    if(Sgl_isone_hidden(result))
+		{
+		if(result_exponent==0)
+		    {
+		    /* Denormalized, exponent should be zero.  Left operand *
+ 		     * was normalized, so extent (guard, round) was zero    */
+		    goto underflow;
+		    }
+		else
+		    {
+		    /* No further normalization is needed. */
+		    Sgl_set_sign(result,/*using*/sign_save);
+	    	    Ext_leftshiftby1(extent);
+		    goto round;
+		    }
+		}
+
+	    /* Check for denormalized, exponent should be zero.  Left    *
+	     * operand was normalized, so extent (guard, round) was zero */
+	    if(!(underflowtrap = Is_underflowtrap_enabled()) &&
+	       result_exponent==0) goto underflow;
+
+	    /* Shift extension to complete one bit of normalization and
+	     * update exponent. */
+	    Ext_leftshiftby1(extent);
+
+	    /* Discover first one bit to determine shift amount.  Use a
+	     * modified binary search.  We have already shifted the result
+	     * one position right and still not found a one so the remainder
+	     * of the extension must be zero and simplifies rounding. */
+	    /* Scan bytes */
+	    while(Sgl_iszero_hiddenhigh7mantissa(result))
+		{
+		Sgl_leftshiftby8(result);
+		if((result_exponent -= 8) <= 0  && !underflowtrap)
+		    goto underflow;
+		}
+	    /* Now narrow it down to the nibble */
+	    if(Sgl_iszero_hiddenhigh3mantissa(result))
+		{
+		/* The lower nibble contains the normalizing one */
+		Sgl_leftshiftby4(result);
+		if((result_exponent -= 4) <= 0 && !underflowtrap)
+		    goto underflow;
+		}
+	    /* Select case were first bit is set (already normalized)
+	     * otherwise select the proper shift. */
+	    if((jumpsize = Sgl_hiddenhigh3mantissa(result)) > 7)
+		{
+		/* Already normalized */
+		if(result_exponent <= 0) goto underflow;
+		Sgl_set_sign(result,/*using*/sign_save);
+		Sgl_set_exponent(result,/*using*/result_exponent);
+		*dstptr = result;
+		return(NOEXCEPTION);
+		}
+	    Sgl_sethigh4bits(result,/*using*/sign_save);
+	    switch(jumpsize) 
+		{
+		case 1:
+		    {
+		    Sgl_leftshiftby3(result);
+		    result_exponent -= 3;
+		    break;
+		    }
+		case 2:
+		case 3:
+		    {
+		    Sgl_leftshiftby2(result);
+		    result_exponent -= 2;
+		    break;
+		    }
+		case 4:
+		case 5:
+		case 6:
+		case 7:
+		    {
+		    Sgl_leftshiftby1(result);
+		    result_exponent -= 1;
+		    break;
+		    }
+		}
+	    if(result_exponent > 0) 
+		{
+		Sgl_set_exponent(result,/*using*/result_exponent);
+		*dstptr = result;	/* Sign bit is already set */
+		return(NOEXCEPTION);
+		}
+	    /* Fixup potential underflows */
+	  underflow:
+	    if(Is_underflowtrap_enabled())
+		{
+		Sgl_set_sign(result,sign_save);
+                Sgl_setwrapped_exponent(result,result_exponent,unfl);
+		*dstptr = result;
+		/* inexact = FALSE */
+		return(UNDERFLOWEXCEPTION);
+		}
+	    /*
+	     * Since we cannot get an inexact denormalized result,
+	     * we can now return.
+	     */
+	    Sgl_right_align(result,/*by*/(1-result_exponent),extent);
+	    Sgl_clear_signexponent(result);
+	    Sgl_set_sign(result,sign_save);
+	    *dstptr = result;
+	    return(NOEXCEPTION);
+	    } /* end if(hidden...)... */
+	/* Fall through and round */
+	} /* end if(save >= 0)... */
+    else 
+	{
+	/* Add magnitudes */
+	Sgl_addition(left,right,/*to*/result);
+	if(Sgl_isone_hiddenoverflow(result))
+	    {
+	    /* Prenormalization required. */
+	    Sgl_rightshiftby1_withextent(result,extent,extent);
+	    Sgl_arithrightshiftby1(result);
+	    result_exponent++;
+	    } /* end if hiddenoverflow... */
+	} /* end else ...sub magnitudes... */
+    
+    /* Round the result.  If the extension is all zeros,then the result is
+     * exact.  Otherwise round in the correct direction.  No underflow is
+     * possible. If a postnormalization is necessary, then the mantissa is
+     * all zeros so no shift is needed. */
+  round:
+    if(Ext_isnotzero(extent))
+	{
+	inexact = TRUE;
+	switch(Rounding_mode())
+	    {
+	    case ROUNDNEAREST: /* The default. */
+	    if(Ext_isone_sign(extent))
+		{
+		/* at least 1/2 ulp */
+		if(Ext_isnotzero_lower(extent)  ||
+		  Sgl_isone_lowmantissa(result))
+		    {
+		    /* either exactly half way and odd or more than 1/2ulp */
+		    Sgl_increment(result);
+		    }
+		}
+	    break;
+
+	    case ROUNDPLUS:
+	    if(Sgl_iszero_sign(result))
+		{
+		/* Round up positive results */
+		Sgl_increment(result);
+		}
+	    break;
+	    
+	    case ROUNDMINUS:
+	    if(Sgl_isone_sign(result))
+		{
+		/* Round down negative results */
+		Sgl_increment(result);
+		}
+	    
+	    case ROUNDZERO:;
+	    /* truncate is simple */
+	    } /* end switch... */
+	if(Sgl_isone_hiddenoverflow(result)) result_exponent++;
+	}
+    if(result_exponent == SGL_INFINITY_EXPONENT)
+        {
+        /* Overflow */
+        if(Is_overflowtrap_enabled())
+	    {
+	    Sgl_setwrapped_exponent(result,result_exponent,ovfl);
+	    *dstptr = result;
+	    if (inexact)
+		if (Is_inexacttrap_enabled())
+		    return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+		else Set_inexactflag();
+	    return(OVERFLOWEXCEPTION);
+	    }
+        else
+	    {
+	    Set_overflowflag();
+	    inexact = TRUE;
+	    Sgl_setoverflow(result);
+	    }
+	}
+    else Sgl_set_exponent(result,result_exponent);
+    *dstptr = result;
+    if(inexact) 
+	if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+	else Set_inexactflag();
+    return(NOEXCEPTION);
+    }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/sgl_float.h linux-2.4.20/arch/parisc/math-emu/sgl_float.h
--- linux-2.4.19/arch/parisc/math-emu/sgl_float.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/sgl_float.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,486 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef __NO_PA_HDRS
+    PA header file -- do not include this header file for non-PA builds.
+#endif
+
+/* 32-bit word grabing functions */
+#define Sgl_firstword(value) Sall(value)
+#define Sgl_secondword(value) dummy_location
+#define Sgl_thirdword(value) dummy_location
+#define Sgl_fourthword(value) dummy_location
+
+#define Sgl_sign(object) Ssign(object)
+#define Sgl_exponent(object) Sexponent(object)
+#define Sgl_signexponent(object) Ssignexponent(object)
+#define Sgl_mantissa(object) Smantissa(object)
+#define Sgl_exponentmantissa(object) Sexponentmantissa(object)
+#define Sgl_all(object) Sall(object)
+
+/* sgl_and_signs ands the sign bits of each argument and puts the result
+ * into the first argument. sgl_or_signs ors those same sign bits */
+#define Sgl_and_signs( src1dst, src2)		\
+    Sall(src1dst) = (Sall(src2)|~((unsigned int)1<<31)) & Sall(src1dst)
+#define Sgl_or_signs( src1dst, src2)		\
+    Sall(src1dst) = (Sall(src2)&((unsigned int)1<<31)) | Sall(src1dst)
+
+/* The hidden bit is always the low bit of the exponent */
+#define Sgl_clear_exponent_set_hidden(srcdst) Deposit_sexponent(srcdst,1)
+#define Sgl_clear_signexponent_set_hidden(srcdst) \
+    Deposit_ssignexponent(srcdst,1)
+#define Sgl_clear_sign(srcdst) Sall(srcdst) &= ~((unsigned int)1<<31)
+#define Sgl_clear_signexponent(srcdst) Sall(srcdst) &= 0x007fffff
+
+/* varamount must be less than 32 for the next three functions */
+#define Sgl_rightshift(srcdst, varamount)	\
+    Sall(srcdst) >>= varamount
+#define Sgl_leftshift(srcdst, varamount)	\
+    Sall(srcdst) <<= varamount
+#define Sgl_rightshift_exponentmantissa(srcdst, varamount) \
+    Sall(srcdst) = \
+	(Sexponentmantissa(srcdst) >> varamount) | \
+	(Sall(srcdst) & ((unsigned int)1<<31))
+
+#define Sgl_leftshiftby1_withextent(left,right,result) \
+    Shiftdouble(Sall(left),Extall(right),31,Sall(result))
+    
+#define Sgl_rightshiftby1_withextent(left,right,dst)		\
+    Shiftdouble(Sall(left),Extall(right),1,Extall(right))
+#define Sgl_arithrightshiftby1(srcdst)	\
+    Sall(srcdst) = (int)Sall(srcdst) >> 1
+    
+/* Sign extend the sign bit with an integer destination */
+#define Sgl_signextendedsign(value) Ssignedsign(value)
+
+#define Sgl_isone_hidden(sgl_value) (Shidden(sgl_value))
+#define Sgl_increment(sgl_value) Sall(sgl_value) += 1
+#define Sgl_increment_mantissa(sgl_value) \
+    Deposit_smantissa(sgl_value,sgl_value+1)
+#define Sgl_decrement(sgl_value) Sall(sgl_value) -= 1
+
+#define Sgl_isone_sign(sgl_value) (Is_ssign(sgl_value)!=0)
+#define Sgl_isone_hiddenoverflow(sgl_value) \
+    (Is_shiddenoverflow(sgl_value)!=0)
+#define Sgl_isone_lowmantissa(sgl_value) (Is_slow(sgl_value)!=0)
+#define Sgl_isone_signaling(sgl_value) (Is_ssignaling(sgl_value)!=0)
+#define Sgl_is_signalingnan(sgl_value) (Ssignalingnan(sgl_value)==0x1ff)
+#define Sgl_isnotzero(sgl_value) (Sall(sgl_value)!=0)
+#define Sgl_isnotzero_hiddenhigh7mantissa(sgl_value) \
+    (Shiddenhigh7mantissa(sgl_value)!=0)
+#define Sgl_isnotzero_low4(sgl_value) (Slow4(sgl_value)!=0)
+#define Sgl_isnotzero_exponent(sgl_value) (Sexponent(sgl_value)!=0)
+#define Sgl_isnotzero_mantissa(sgl_value) (Smantissa(sgl_value)!=0)
+#define Sgl_isnotzero_exponentmantissa(sgl_value) \
+    (Sexponentmantissa(sgl_value)!=0)
+#define Sgl_iszero(sgl_value) (Sall(sgl_value)==0)
+#define Sgl_iszero_signaling(sgl_value) (Is_ssignaling(sgl_value)==0)
+#define Sgl_iszero_hidden(sgl_value) (Is_shidden(sgl_value)==0)
+#define Sgl_iszero_hiddenoverflow(sgl_value) \
+    (Is_shiddenoverflow(sgl_value)==0)
+#define Sgl_iszero_hiddenhigh3mantissa(sgl_value) \
+    (Shiddenhigh3mantissa(sgl_value)==0)
+#define Sgl_iszero_hiddenhigh7mantissa(sgl_value) \
+    (Shiddenhigh7mantissa(sgl_value)==0)
+#define Sgl_iszero_sign(sgl_value) (Is_ssign(sgl_value)==0)
+#define Sgl_iszero_exponent(sgl_value) (Sexponent(sgl_value)==0)
+#define Sgl_iszero_mantissa(sgl_value) (Smantissa(sgl_value)==0)
+#define Sgl_iszero_exponentmantissa(sgl_value) \
+    (Sexponentmantissa(sgl_value)==0)
+#define Sgl_isinfinity_exponent(sgl_value) 		\
+    (Sgl_exponent(sgl_value)==SGL_INFINITY_EXPONENT)
+#define Sgl_isnotinfinity_exponent(sgl_value) 		\
+    (Sgl_exponent(sgl_value)!=SGL_INFINITY_EXPONENT)
+#define Sgl_isinfinity(sgl_value)			\
+    (Sgl_exponent(sgl_value)==SGL_INFINITY_EXPONENT &&	\
+    Sgl_mantissa(sgl_value)==0)
+#define Sgl_isnan(sgl_value)				\
+    (Sgl_exponent(sgl_value)==SGL_INFINITY_EXPONENT &&	\
+    Sgl_mantissa(sgl_value)!=0)
+#define Sgl_isnotnan(sgl_value)				\
+    (Sgl_exponent(sgl_value)!=SGL_INFINITY_EXPONENT ||	\
+    Sgl_mantissa(sgl_value)==0)
+#define Sgl_islessthan(sgl_op1,sgl_op2)			\
+    (Sall(sgl_op1) < Sall(sgl_op2))
+#define Sgl_isgreaterthan(sgl_op1,sgl_op2)		\
+    (Sall(sgl_op1) > Sall(sgl_op2))
+#define Sgl_isnotlessthan(sgl_op1,sgl_op2)		\
+    (Sall(sgl_op1) >= Sall(sgl_op2))
+#define Sgl_isequal(sgl_op1,sgl_op2)			\
+    (Sall(sgl_op1) == Sall(sgl_op2))
+
+#define Sgl_leftshiftby8(sgl_value) \
+    Sall(sgl_value) <<= 8
+#define Sgl_leftshiftby4(sgl_value) \
+    Sall(sgl_value) <<= 4
+#define Sgl_leftshiftby3(sgl_value) \
+    Sall(sgl_value) <<= 3
+#define Sgl_leftshiftby2(sgl_value) \
+    Sall(sgl_value) <<= 2
+#define Sgl_leftshiftby1(sgl_value) \
+    Sall(sgl_value) <<= 1
+#define Sgl_rightshiftby1(sgl_value) \
+    Sall(sgl_value) >>= 1
+#define Sgl_rightshiftby4(sgl_value) \
+    Sall(sgl_value) >>= 4
+#define Sgl_rightshiftby8(sgl_value) \
+    Sall(sgl_value) >>= 8
+    
+#define Sgl_ismagnitudeless(signlessleft,signlessright)			\
+/*  unsigned int signlessleft, signlessright; */			\
+      (signlessleft < signlessright)  
+    
+
+#define Sgl_copytoint_exponentmantissa(source,dest)     \
+    dest = Sexponentmantissa(source)
+
+/* A quiet NaN has the high mantissa bit clear and at least on other (in this
+ * case the adjacent bit) bit set. */
+#define Sgl_set_quiet(sgl_value) Deposit_shigh2mantissa(sgl_value,1)
+#define Sgl_set_exponent(sgl_value,exp) Deposit_sexponent(sgl_value,exp)
+
+#define Sgl_set_mantissa(dest,value) Deposit_smantissa(dest,value)
+#define Sgl_set_exponentmantissa(dest,value) \
+    Deposit_sexponentmantissa(dest,value)
+
+/*  An infinity is represented with the max exponent and a zero mantissa */
+#define Sgl_setinfinity_exponent(sgl_value) \
+    Deposit_sexponent(sgl_value,SGL_INFINITY_EXPONENT)
+#define Sgl_setinfinity_exponentmantissa(sgl_value)	\
+    Deposit_sexponentmantissa(sgl_value, \
+	(SGL_INFINITY_EXPONENT << (32-(1+SGL_EXP_LENGTH))))
+#define Sgl_setinfinitypositive(sgl_value)		\
+    Sall(sgl_value) = (SGL_INFINITY_EXPONENT << (32-(1+SGL_EXP_LENGTH)))
+#define Sgl_setinfinitynegative(sgl_value)		\
+    Sall(sgl_value) = (SGL_INFINITY_EXPONENT << (32-(1+SGL_EXP_LENGTH))) \
+    | ((unsigned int)1<<31)
+#define Sgl_setinfinity(sgl_value,sign)					\
+    Sall(sgl_value) = (SGL_INFINITY_EXPONENT << (32-(1+SGL_EXP_LENGTH))) | \
+     ((unsigned int)sign << 31)
+#define Sgl_sethigh4bits(sgl_value, extsign)  \
+    Deposit_shigh4(sgl_value,extsign)
+#define Sgl_set_sign(sgl_value,sign) Deposit_ssign(sgl_value,sign)
+#define Sgl_invert_sign(sgl_value)  \
+    Deposit_ssign(sgl_value,~Ssign(sgl_value))
+#define Sgl_setone_sign(sgl_value) Deposit_ssign(sgl_value,1)
+#define Sgl_setone_lowmantissa(sgl_value) Deposit_slow(sgl_value,1)
+#define Sgl_setzero_sign(sgl_value)  Sall(sgl_value) &= 0x7fffffff
+#define Sgl_setzero_exponent(sgl_value) Sall(sgl_value) &= 0x807fffff
+#define Sgl_setzero_mantissa(sgl_value) Sall(sgl_value) &= 0xff800000
+#define Sgl_setzero_exponentmantissa(sgl_value)  Sall(sgl_value) &= 0x80000000
+#define Sgl_setzero(sgl_value) Sall(sgl_value) = 0
+#define Sgl_setnegativezero(sgl_value) Sall(sgl_value) = (unsigned int)1 << 31
+
+/* Use following macro for both overflow & underflow conditions */
+#define ovfl -
+#define unfl +
+#define Sgl_setwrapped_exponent(sgl_value,exponent,op) \
+    Deposit_sexponent(sgl_value,(exponent op SGL_WRAP))
+
+#define Sgl_setlargestpositive(sgl_value) 				\
+    Sall(sgl_value) = ((SGL_EMAX+SGL_BIAS) << (32-(1+SGL_EXP_LENGTH)))	\
+                      | ((1<<(32-(1+SGL_EXP_LENGTH))) - 1 )
+#define Sgl_setlargestnegative(sgl_value)				\
+    Sall(sgl_value) = ((SGL_EMAX+SGL_BIAS) << (32-(1+SGL_EXP_LENGTH)))	\
+                      | ((1<<(32-(1+SGL_EXP_LENGTH))) - 1 )		\
+		      | ((unsigned int)1<<31)
+
+#define Sgl_setnegativeinfinity(sgl_value)	\
+    Sall(sgl_value) = 				\
+    ((1<<SGL_EXP_LENGTH) | SGL_INFINITY_EXPONENT) << (32-(1+SGL_EXP_LENGTH))
+#define Sgl_setlargest(sgl_value,sign) 					\
+    Sall(sgl_value) = (unsigned int)sign << 31 |			\
+        (((SGL_EMAX+SGL_BIAS) << (32-(1+SGL_EXP_LENGTH)))		\
+	  | ((1 << (32-(1+SGL_EXP_LENGTH))) - 1 ))
+#define Sgl_setlargest_exponentmantissa(sgl_value)			\
+    Sall(sgl_value) = Sall(sgl_value) & ((unsigned int)1<<31) |		\
+        (((SGL_EMAX+SGL_BIAS) << (32-(1+SGL_EXP_LENGTH)))		\
+	  | ((1 << (32-(1+SGL_EXP_LENGTH))) - 1 ))
+
+/* The high bit is always zero so arithmetic or logical shifts will work. */
+#define Sgl_right_align(srcdst,shift,extent)				\
+    /* sgl_floating_point srcdst; int shift; extension extent */	\
+    if (shift < 32) {							\
+	Extall(extent) = Sall(srcdst) << (32-(shift));			\
+    	Sall(srcdst) >>= shift;						\
+    }									\
+    else {								\
+	Extall(extent) = Sall(srcdst);					\
+	Sall(srcdst) = 0;						\
+    }
+#define Sgl_hiddenhigh3mantissa(sgl_value) Shiddenhigh3mantissa(sgl_value)
+#define Sgl_hidden(sgl_value) Shidden(sgl_value)
+#define Sgl_lowmantissa(sgl_value) Slow(sgl_value)
+
+/* The left argument is never smaller than the right argument */
+#define Sgl_subtract(sgl_left,sgl_right,sgl_result) \
+    Sall(sgl_result) = Sall(sgl_left) - Sall(sgl_right)
+
+/* Subtract right augmented with extension from left augmented with zeros and
+ * store into result and extension. */
+#define Sgl_subtract_withextension(left,right,extent,result)		\
+    /* sgl_floating_point left,right,result; extension extent */	\
+  Sgl_subtract(left,right,result);					\
+  if((Extall(extent) = 0-Extall(extent)))				\
+      Sall(result) = Sall(result)-1
+
+#define Sgl_addition(sgl_left,sgl_right,sgl_result) \
+    Sall(sgl_result) = Sall(sgl_left) + Sall(sgl_right)
+
+#define Sgl_xortointp1(left,right,result)			\
+    result = Sall(left) XOR Sall(right);
+
+#define Sgl_xorfromintp1(left,right,result)			\
+    Sall(result) = left XOR Sall(right)
+
+/* Need to Initialize */
+#define Sgl_makequietnan(dest)						\
+    Sall(dest) = ((SGL_EMAX+SGL_BIAS)+1)<< (32-(1+SGL_EXP_LENGTH))	\
+                 | (1<<(32-(1+SGL_EXP_LENGTH+2)))
+#define Sgl_makesignalingnan(dest)					\
+    Sall(dest) = ((SGL_EMAX+SGL_BIAS)+1)<< (32-(1+SGL_EXP_LENGTH))	\
+                 | (1<<(32-(1+SGL_EXP_LENGTH+1)))
+
+#define Sgl_normalize(sgl_opnd,exponent)			\
+	while(Sgl_iszero_hiddenhigh7mantissa(sgl_opnd)) {	\
+		Sgl_leftshiftby8(sgl_opnd);			\
+		exponent -= 8;					\
+	}							\
+	if(Sgl_iszero_hiddenhigh3mantissa(sgl_opnd)) {		\
+		Sgl_leftshiftby4(sgl_opnd);			\
+		exponent -= 4;					\
+	}							\
+	while(Sgl_iszero_hidden(sgl_opnd)) {			\
+		Sgl_leftshiftby1(sgl_opnd);			\
+		exponent -= 1;					\
+	}
+
+#define Sgl_setoverflow(sgl_opnd)				\
+	/* set result to infinity or largest number */		\
+	switch (Rounding_mode()) {				\
+		case ROUNDPLUS:					\
+			if (Sgl_isone_sign(sgl_opnd)) {		\
+				Sgl_setlargestnegative(sgl_opnd); \
+			}					\
+			else {					\
+				Sgl_setinfinitypositive(sgl_opnd); \
+			}					\
+			break;					\
+		case ROUNDMINUS:				\
+			if (Sgl_iszero_sign(sgl_opnd)) {	\
+				Sgl_setlargestpositive(sgl_opnd); \
+			}					\
+			else {					\
+				Sgl_setinfinitynegative(sgl_opnd); \
+			}					\
+			break;					\
+		case ROUNDNEAREST:				\
+			Sgl_setinfinity_exponentmantissa(sgl_opnd); \
+			break;					\
+		case ROUNDZERO:					\
+			Sgl_setlargest_exponentmantissa(sgl_opnd); \
+	}
+
+#define Sgl_denormalize(opnd,exponent,guard,sticky,inexact)		\
+	Sgl_clear_signexponent_set_hidden(opnd);			\
+	if (exponent >= (1 - SGL_P)) {					\
+		guard = (Sall(opnd) >> -exponent) & 1;			\
+		if (exponent < 0) sticky |= Sall(opnd) << (32+exponent); \
+		inexact = guard | sticky;				\
+		Sall(opnd) >>= (1-exponent);				\
+	}								\
+	else {								\
+		guard = 0;						\
+		sticky |= Sall(opnd);					\
+		inexact = sticky;					\
+		Sgl_setzero(opnd);					\
+	}
+
+/* 
+ * The fused multiply add instructions requires a single extended format,
+ * with 48 bits of mantissa.
+ */
+#define SGLEXT_THRESHOLD 48
+
+#define Sglext_setzero(valA,valB)	\
+    Sextallp1(valA) = 0; Sextallp2(valB) = 0
+
+#define Sglext_isnotzero_mantissap2(valB) (Sextallp2(valB)!=0)
+#define Sglext_isone_lowp1(val) (Sextlowp1(val)!=0)
+#define Sglext_isone_highp2(val) (Sexthighp2(val)!=0)
+#define Sglext_isnotzero_low31p2(val) (Sextlow31p2(val)!=0)
+#define Sglext_iszero(valA,valB) (Sextallp1(valA)==0 && Sextallp2(valB)==0)
+
+#define Sgl_copytoptr(src,destptr) *destptr = src
+#define Sgl_copyfromptr(srcptr,dest) dest = *srcptr
+#define Sglext_copy(srca,srcb,desta,destb) \
+    Sextallp1(desta) = Sextallp1(srca);	\
+    Sextallp2(destb) = Sextallp2(srcb)
+#define Sgl_copyto_sglext(src1,dest1,dest2) \
+	Sextallp1(dest1) = Sall(src1); Sextallp2(dest2) = 0
+
+#define Sglext_swap_lower(leftp2,rightp2)  \
+    Sextallp2(leftp2)  = Sextallp2(leftp2) XOR Sextallp2(rightp2);  \
+    Sextallp2(rightp2) = Sextallp2(leftp2) XOR Sextallp2(rightp2);  \
+    Sextallp2(leftp2)  = Sextallp2(leftp2) XOR Sextallp2(rightp2)
+
+#define Sglext_setone_lowmantissap2(value) Deposit_dlowp2(value,1)
+
+/* The high bit is always zero so arithmetic or logical shifts will work. */
+#define Sglext_right_align(srcdstA,srcdstB,shift) \
+  {int shiftamt, sticky;						\
+    shiftamt = shift % 32;						\
+    sticky = 0;								\
+    switch (shift/32) {							\
+     case 0: if (shiftamt > 0) {					\
+	        sticky = Sextallp2(srcdstB) << 32 - (shiftamt);		\
+                Variable_shift_double(Sextallp1(srcdstA),		\
+		 Sextallp2(srcdstB),shiftamt,Sextallp2(srcdstB));	\
+	        Sextallp1(srcdstA) >>= shiftamt;			\
+	     }								\
+	     break;							\
+     case 1: if (shiftamt > 0) {					\
+	        sticky = (Sextallp1(srcdstA) << 32 - (shiftamt)) |	\
+			 Sextallp2(srcdstB);				\
+	     }								\
+	     else {							\
+		sticky = Sextallp2(srcdstB);				\
+	     }								\
+	     Sextallp2(srcdstB) = Sextallp1(srcdstA) >> shiftamt;	\
+	     Sextallp1(srcdstA) = 0;					\
+	     break;							\
+    }									\
+    if (sticky) Sglext_setone_lowmantissap2(srcdstB);			\
+  }
+
+/* The left argument is never smaller than the right argument */
+#define Sglext_subtract(lefta,leftb,righta,rightb,resulta,resultb) \
+    if( Sextallp2(rightb) > Sextallp2(leftb) ) Sextallp1(lefta)--; \
+    Sextallp2(resultb) = Sextallp2(leftb) - Sextallp2(rightb);	\
+    Sextallp1(resulta) = Sextallp1(lefta) - Sextallp1(righta)
+
+#define Sglext_addition(lefta,leftb,righta,rightb,resulta,resultb) \
+    /* If the sum of the low words is less than either source, then \
+     * an overflow into the next word occurred. */ \
+    if ((Sextallp2(resultb) = Sextallp2(leftb)+Sextallp2(rightb)) < \
+        Sextallp2(rightb)) \
+	    Sextallp1(resulta) = Sextallp1(lefta)+Sextallp1(righta)+1; \
+    else Sextallp1(resulta) = Sextallp1(lefta)+Sextallp1(righta)
+
+
+#define Sglext_arithrightshiftby1(srcdstA,srcdstB)	\
+    Shiftdouble(Sextallp1(srcdstA),Sextallp2(srcdstB),1,Sextallp2(srcdstB)); \
+    Sextallp1(srcdstA) = (int)Sextallp1(srcdstA) >> 1
+   
+#define Sglext_leftshiftby8(valA,valB) \
+    Shiftdouble(Sextallp1(valA),Sextallp2(valB),24,Sextallp1(valA)); \
+    Sextallp2(valB) <<= 8
+#define Sglext_leftshiftby4(valA,valB) \
+    Shiftdouble(Sextallp1(valA),Sextallp2(valB),28,Sextallp1(valA)); \
+    Sextallp2(valB) <<= 4
+#define Sglext_leftshiftby3(valA,valB) \
+    Shiftdouble(Sextallp1(valA),Sextallp2(valB),29,Sextallp1(valA)); \
+    Sextallp2(valB) <<= 3
+#define Sglext_leftshiftby2(valA,valB) \
+    Shiftdouble(Sextallp1(valA),Sextallp2(valB),30,Sextallp1(valA)); \
+    Sextallp2(valB) <<= 2
+#define Sglext_leftshiftby1(valA,valB) \
+    Shiftdouble(Sextallp1(valA),Sextallp2(valB),31,Sextallp1(valA)); \
+    Sextallp2(valB) <<= 1
+
+#define Sglext_rightshiftby4(valueA,valueB) \
+    Shiftdouble(Sextallp1(valueA),Sextallp2(valueB),4,Sextallp2(valueB)); \
+    Sextallp1(valueA) >>= 4
+#define Sglext_rightshiftby3(valueA,valueB) \
+    Shiftdouble(Sextallp1(valueA),Sextallp2(valueB),3,Sextallp2(valueB)); \
+    Sextallp1(valueA) >>= 3
+#define Sglext_rightshiftby1(valueA,valueB) \
+    Shiftdouble(Sextallp1(valueA),Sextallp2(valueB),1,Sextallp2(valueB)); \
+    Sextallp1(valueA) >>= 1
+
+#define Sglext_xortointp1(left,right,result) Sgl_xortointp1(left,right,result)
+#define Sglext_xorfromintp1(left,right,result) \
+	Sgl_xorfromintp1(left,right,result)
+#define Sglext_copytoint_exponentmantissa(src,dest) \
+	Sgl_copytoint_exponentmantissa(src,dest)
+#define Sglext_ismagnitudeless(signlessleft,signlessright) \
+	Sgl_ismagnitudeless(signlessleft,signlessright)
+
+#define Sglext_set_sign(dbl_value,sign)  Sgl_set_sign(dbl_value,sign)  
+#define Sglext_clear_signexponent_set_hidden(srcdst) \
+	Sgl_clear_signexponent_set_hidden(srcdst) 
+#define Sglext_clear_signexponent(srcdst) Sgl_clear_signexponent(srcdst) 
+#define Sglext_clear_sign(srcdst) Sgl_clear_sign(srcdst) 
+#define Sglext_isone_hidden(dbl_value) Sgl_isone_hidden(dbl_value) 
+
+#define Sglext_denormalize(opndp1,opndp2,exponent,is_tiny)		\
+  {int sticky;								\
+    is_tiny = TRUE;							\
+    if (exponent == 0 && Sextallp2(opndp2)) {				\
+	switch (Rounding_mode()) {					\
+	case ROUNDPLUS:							\
+		if (Sgl_iszero_sign(opndp1))				\
+			if (Sgl_isone_hiddenoverflow(opndp1 + 1))	\
+				is_tiny = FALSE;			\
+		break;							\
+	case ROUNDMINUS:						\
+		if (Sgl_isone_sign(opndp1)) {				\
+			if (Sgl_isone_hiddenoverflow(opndp1 + 1))	\
+				is_tiny = FALSE;			\
+		}							\
+		break;							\
+	case ROUNDNEAREST:						\
+		if (Sglext_isone_highp2(opndp2) &&			\
+		    (Sglext_isone_lowp1(opndp1) || 			\
+		     Sglext_isnotzero_low31p2(opndp2)))			\
+			if (Sgl_isone_hiddenoverflow(opndp1 + 1))	\
+				is_tiny = FALSE;			\
+		break;							\
+	}								\
+    }									\
+    Sglext_clear_signexponent_set_hidden(opndp1);			\
+    if (exponent >= (1-DBL_P)) {					\
+	if (exponent >= -31) {						\
+	    if (exponent > -31) {					\
+		sticky = Sextallp2(opndp2) << 31+exponent;		\
+		Variable_shift_double(opndp1,opndp2,1-exponent,opndp2);	\
+		Sextallp1(opndp1) >>= 1-exponent;			\
+	    }								\
+	    else {							\
+		sticky = Sextallp2(opndp2);				\
+		Sextallp2(opndp2) = Sextallp1(opndp1);			\
+		Sextallp1(opndp1) = 0;					\
+	    }								\
+	}								\
+	else {								\
+	    sticky = (Sextallp1(opndp1) << 31+exponent) | 		\
+		     Sextallp2(opndp2);					\
+	    Sextallp2(opndp2) = Sextallp1(opndp1) >> -31-exponent;	\
+	    Sextallp1(opndp1) = 0;					\
+	}								\
+    }									\
+    else {								\
+	sticky = Sextallp1(opndp1) | Sextallp2(opndp2);			\
+	Sglext_setzero(opndp1,opndp2);					\
+    }									\
+    if (sticky) Sglext_setone_lowmantissap2(opndp2);			\
+    exponent = 0;							\
+  }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/math-emu/types.h linux-2.4.20/arch/parisc/math-emu/types.h
--- linux-2.4.19/arch/parisc/math-emu/types.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/math-emu/types.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,25 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#define BUG() do { \
+        printk(KERN_ERR "floating-pt emulation BUG at %s:%d!\n", __FILE__, __LINE__); \
+} while (0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/mm/Makefile linux-2.4.20/arch/parisc/mm/Makefile
--- linux-2.4.19/arch/parisc/mm/Makefile	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/mm/Makefile	2002-10-29 11:18:36.000000000 +0000
@@ -8,6 +8,6 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := mm.o
-O_OBJS	 := init.o fault.o kmap.o extable.o
+obj-y	 := init.o fault.o extable.o ioremap.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/mm/extable.c linux-2.4.20/arch/parisc/mm/extable.c
--- linux-2.4.19/arch/parisc/mm/extable.c	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/mm/extable.c	2002-10-29 11:18:35.000000000 +0000
@@ -46,17 +46,17 @@
 const struct exception_table_entry *
 search_exception_table (unsigned long addr)
 {
-#ifndef CONFIG_MODULE
+#ifndef CONFIG_MODULES
 	/* There is only the kernel to search.  */
 	return search_one_table(__start___ex_table, 
                                 __stop___ex_table - 1, 
                                 addr);
 #else
-	struct exception_table_entry *ret;
 	/* The kernel is the last "module" -- no need to treat it special. */
 	struct module *mp;
 
 	for (mp = module_list; mp ; mp = mp->next) {
+		const struct exception_table_entry *ret;
 		if (!mp->ex_table_start)
 			continue;
 		ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/mm/fault.c linux-2.4.20/arch/parisc/mm/fault.c
--- linux-2.4.19/arch/parisc/mm/fault.c	2001-03-19 20:37:16.000000000 +0000
+++ linux-2.4.20/arch/parisc/mm/fault.c	2002-10-29 11:18:49.000000000 +0000
@@ -17,6 +17,10 @@
 #include <linux/interrupt.h>
 
 #include <asm/uaccess.h>
+#include <asm/traps.h>
+
+#define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */
+			 /*  dumped to the console via printk)          */
 
 
 /* Defines for parisc_acctyp()	*/
@@ -114,59 +118,31 @@
 #undef isGraphicsFlushRead
 #undef BITSSET
 
-/* This is similar to expand_stack(), except that it is for stacks
- * that grow upwards.
- */
-
-static inline int expand_stackup(struct vm_area_struct * vma, unsigned long address)
-{
-	unsigned long grow;
-
-	address += 4 + PAGE_SIZE - 1;
-	address &= PAGE_MASK;
-	grow = (address - vma->vm_end) >> PAGE_SHIFT;
-	if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur ||
-	    ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur)
-		return -ENOMEM;
-	vma->vm_end = address;
-	vma->vm_mm->total_vm += grow;
-	if (vma->vm_flags & VM_LOCKED)
-		vma->vm_mm->locked_vm += grow;
-	return 0;
-}
-
-
-/* This is similar to find_vma(), except that it understands that stacks
- * grow up rather than down.
- * XXX Optimise by making use of cache and avl tree as per find_vma().
- */
 
-struct vm_area_struct * pa_find_vma(struct mm_struct * mm, unsigned long addr)
-{
-	struct vm_area_struct *vma = NULL;
-
-	if (mm) {
-		vma = mm->mmap;
-		if (!vma || addr < vma->vm_start)
-			return NULL;
-		while (vma->vm_next && addr >= vma->vm_next->vm_start)
-			vma = vma->vm_next;
-	}
-	return vma;
-}
-
-
-/*
- * This routine handles page faults.  It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
- */
-extern void parisc_terminate(char *, struct pt_regs *, int, unsigned long);
+#if 0
+/* This is the treewalk to find a vma which is the highest that has
+ * a start < addr.  We're using find_vma_prev instead right now, but
+ * we might want to use this at some point in the future.  Probably
+ * not, but I want it committed to CVS so I don't lose it :-)
+ */
+			while (tree != vm_avl_empty) {
+				if (tree->vm_start > addr) {
+					tree = tree->vm_avl_left;
+				} else {
+					prev = tree;
+					if (prev->vm_next == NULL)
+						break;
+					if (prev->vm_next->vm_start > addr)
+						break;
+					tree = tree->vm_avl_right;
+				}
+			}
+#endif
 
 void do_page_fault(struct pt_regs *regs, unsigned long code,
 			      unsigned long address)
 {
-	struct vm_area_struct * vma;
+	struct vm_area_struct *vma, *prev_vma;
 	struct task_struct *tsk = current;
 	struct mm_struct *mm = tsk->mm;
 	const struct exception_table_entry *fix;
@@ -176,13 +152,9 @@
 		goto no_context;
 
 	down_read(&mm->mmap_sem);
-	vma = pa_find_vma(mm, address);
-	if (!vma)
-		goto bad_area;
-	if (address < vma->vm_end)
-		goto good_area;
-	if (!(vma->vm_flags & VM_GROWSUP) || expand_stackup(vma, address))
-		goto bad_area;
+	vma = find_vma_prev(mm, address, &prev_vma);
+	if (!vma || address < vma->vm_start)
+		goto check_expansion;
 /*
  * Ok, we have a good vm_area for this memory access. We still need to
  * check the access permissions.
@@ -221,6 +193,11 @@
 	up_read(&mm->mmap_sem);
 	return;
 
+check_expansion:
+	vma = prev_vma;
+	if (vma && (expand_stack(vma, address) == 0))
+		goto good_area;
+
 /*
  * Something tried to access memory that isn't in our memory map..
  */
@@ -230,9 +207,16 @@
 	if (user_mode(regs)) {
 		struct siginfo si;
 
-		printk("\ndo_page_fault() pid=%d command='%s'\n",
-		    tsk->pid, tsk->comm);
+#ifdef PRINT_USER_FAULTS
+		printk(KERN_DEBUG "\n");
+		printk(KERN_DEBUG "do_page_fault() pid=%d command='%s' type=%lu address=0x%08lx\n",
+		    tsk->pid, tsk->comm, code, address);
+		if (vma) {
+			printk(KERN_DEBUG "vm_start = 0x%08lx, vm_end = 0x%08lx\n",
+					vma->vm_start, vma->vm_end);
+		}
 		show_regs(regs);
+#endif
 		/* FIXME: actually we need to get the signo and code correct */
 		si.si_signo = SIGSEGV;
 		si.si_errno = 0;
@@ -272,11 +256,11 @@
 		}
 	}
 
-	parisc_terminate("Bad Address (null pointer deref?)",regs,code,address);
+	parisc_terminate("Bad Address (null pointer deref?)", regs, code, address);
 
   out_of_memory:
 	up_read(&mm->mmap_sem);
-	printk("VM: killing process %s\n", current->comm);
+	printk(KERN_CRIT "VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
 	goto no_context;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/mm/init.c linux-2.4.20/arch/parisc/mm/init.c
--- linux-2.4.19/arch/parisc/mm/init.c	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/mm/init.c	2002-10-29 11:18:40.000000000 +0000
@@ -15,15 +15,400 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/pci.h>		/* for hppa_dma_ops and pcxl_dma_ops */
+#include <linux/blk.h>          /* for initrd_start and initrd_end */
 #include <linux/swap.h>
 #include <linux/unistd.h>
 
 #include <asm/pgalloc.h>
+#include <asm/tlb.h>
 
-static unsigned long totalram_pages;
-extern unsigned long max_pfn, mem_max;
+mmu_gather_t mmu_gathers[NR_CPUS];
 
-void free_initmem(void)  {
+extern char _text;	/* start of kernel code, defined by linker */
+extern int  data_start;
+extern char _end;	/* end of BSS, defined by linker */
+extern char __init_begin, __init_end;
+
+#ifdef CONFIG_DISCONTIGMEM
+struct node_map_data node_data[MAX_PHYSMEM_RANGES];
+bootmem_data_t bmem_data[MAX_PHYSMEM_RANGES];
+unsigned char *chunkmap;
+unsigned int maxchunkmap;
+#endif
+
+static struct resource data_resource = {
+	name:	"Kernel data",
+	flags:	IORESOURCE_BUSY | IORESOURCE_MEM,
+};
+
+static struct resource code_resource = {
+	name:	"Kernel code",
+	flags:	IORESOURCE_BUSY | IORESOURCE_MEM,
+};
+
+static struct resource pdcdata_resource = {
+	name:	"PDC data (Page Zero)",
+	start:	0,
+	end:	0x9ff,
+	flags:	IORESOURCE_BUSY | IORESOURCE_MEM,
+};
+
+static struct resource sysram_resources[MAX_PHYSMEM_RANGES];
+
+static unsigned long max_pfn;
+
+/* The following array is initialized from the firmware specific
+ * information retrieved in kernel/inventory.c.
+ */
+
+physmem_range_t pmem_ranges[MAX_PHYSMEM_RANGES];
+int npmem_ranges;
+
+#ifdef __LP64__
+#define MAX_MEM         (~0UL)
+#else /* !__LP64__ */
+#define MAX_MEM         (3584U*1024U*1024U)
+#endif /* !__LP64__ */
+
+static unsigned long mem_limit = MAX_MEM;
+
+static void __init mem_limit_func(void)
+{
+	char *cp, *end;
+	unsigned long limit;
+	extern char saved_command_line[];
+
+	/* We need this before __setup() functions are called */
+
+	limit = MAX_MEM;
+	for (cp = saved_command_line; *cp; ) {
+		if (memcmp(cp, "mem=", 4) == 0) {
+			cp += 4;
+			limit = memparse(cp, &end);
+			if (end != cp)
+				break;
+			cp = end;
+		} else {
+			while (*cp != ' ' && *cp)
+				++cp;
+			while (*cp == ' ')
+				++cp;
+		}
+	}
+
+	if (limit < mem_limit)
+		mem_limit = limit;
+}
+
+#define MAX_GAP (0x40000000UL >> PAGE_SHIFT)
+
+static void __init setup_bootmem(void)
+{
+	unsigned long bootmap_size;
+	unsigned long mem_max;
+	unsigned long bootmap_pages;
+	unsigned long bootmap_start_pfn;
+	unsigned long bootmap_pfn;
+#ifndef CONFIG_DISCONTIGMEM
+	physmem_range_t pmem_holes[MAX_PHYSMEM_RANGES - 1];
+	int npmem_holes;
+#endif
+	int i, sysram_resource_count;
+
+	disable_sr_hashing(); /* Turn off space register hashing */
+
+#ifdef CONFIG_DISCONTIGMEM
+	/*
+	 * The below is still true as of 2.4.2. If this is ever fixed,
+	 * we can remove this warning!
+	 */
+
+	printk(KERN_WARNING "\n\n");
+	printk(KERN_WARNING "CONFIG_DISCONTIGMEM is enabled, which is probably a mistake. This\n");
+	printk(KERN_WARNING "option can lead to heavy swapping, even when there are gigabytes\n");
+	printk(KERN_WARNING "of free memory.\n\n");
+#endif
+
+#ifdef __LP64__
+
+#ifndef CONFIG_DISCONTIGMEM
+	/*
+	 * Sort the ranges. Since the number of ranges is typically
+	 * small, and performance is not an issue here, just do
+	 * a simple insertion sort.
+	 */
+
+	for (i = 1; i < npmem_ranges; i++) {
+		int j;
+
+		for (j = i; j > 0; j--) {
+			unsigned long tmp;
+
+			if (pmem_ranges[j-1].start_pfn <
+			    pmem_ranges[j].start_pfn) {
+
+				break;
+			}
+			tmp = pmem_ranges[j-1].start_pfn;
+			pmem_ranges[j-1].start_pfn = pmem_ranges[j].start_pfn;
+			pmem_ranges[j].start_pfn = tmp;
+			tmp = pmem_ranges[j-1].pages;
+			pmem_ranges[j-1].pages = pmem_ranges[j].pages;
+			pmem_ranges[j].pages = tmp;
+		}
+	}
+
+	/*
+	 * Throw out ranges that are too far apart (controlled by
+	 * MAX_GAP). If CONFIG_DISCONTIGMEM wasn't implemented so
+	 * poorly, we would recommend enabling that option, but,
+	 * until it is fixed, this is the best way to go.
+	 */
+
+	for (i = 1; i < npmem_ranges; i++) {
+		if (pmem_ranges[i].start_pfn -
+			(pmem_ranges[i-1].start_pfn +
+			 pmem_ranges[i-1].pages) > MAX_GAP) {
+			npmem_ranges = i;
+			break;
+		}
+	}
+#endif
+
+	if (npmem_ranges > 1) {
+
+		/* Print the memory ranges */
+
+		printk(KERN_INFO "Memory Ranges:\n");
+
+		for (i = 0; i < npmem_ranges; i++) {
+			unsigned long start;
+			unsigned long size;
+
+			size = (pmem_ranges[i].pages << PAGE_SHIFT);
+			start = (pmem_ranges[i].start_pfn << PAGE_SHIFT);
+			printk(KERN_INFO "%2d) Start 0x%016lx End 0x%016lx Size %6ld Mb\n",
+				i,start, start + (size - 1), size >> 20);
+		}
+	}
+
+#endif /* __LP64__ */
+
+#if 1
+	/* KLUGE! this really belongs in kernel/resource.c! */
+	iomem_resource.end = ~0UL;
+#endif
+
+	sysram_resource_count = npmem_ranges;
+	for (i = 0; i < sysram_resource_count; i++) {
+		struct resource *res = &sysram_resources[i];
+		res->name = "System RAM";
+		res->start = pmem_ranges[i].start_pfn << PAGE_SHIFT;
+		res->end = res->start + (pmem_ranges[i].pages << PAGE_SHIFT)-1;
+		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+		request_resource(&iomem_resource, res);
+	}
+
+	/*
+	 * For 32 bit kernels we limit the amount of memory we can
+	 * support, in order to preserve enough kernel address space
+	 * for other purposes. For 64 bit kernels we don't normally
+	 * limit the memory, but this mechanism can be used to
+	 * artificially limit the amount of memory (and it is written
+	 * to work with multiple memory ranges).
+	 */
+
+	mem_limit_func();       /* check for "mem=" argument */
+
+	mem_max = 0;
+	for (i = 0; i < npmem_ranges; i++) {
+		unsigned long rsize;
+
+		rsize = pmem_ranges[i].pages << PAGE_SHIFT;
+		if ((mem_max + rsize) > mem_limit) {
+			printk(KERN_WARNING "Memory truncated to %ld Mb\n", mem_limit >> 20);
+			if (mem_max == mem_limit)
+				npmem_ranges = i;
+			else {
+				pmem_ranges[i].pages =   (mem_limit >> PAGE_SHIFT)
+						       - (mem_max >> PAGE_SHIFT);
+				npmem_ranges = i + 1;
+				mem_max = mem_limit;
+			}
+			break;
+		}
+		mem_max += rsize;
+	}
+
+	printk(KERN_INFO "Total Memory: %ld Mb\n",mem_max >> 20);
+
+#ifndef CONFIG_DISCONTIGMEM
+
+	/* Merge the ranges, keeping track of the holes */
+
+	{
+		unsigned long end_pfn;
+		unsigned long hole_pages;
+
+		npmem_holes = 0;
+		end_pfn = pmem_ranges[0].start_pfn + pmem_ranges[0].pages;
+		for (i = 1; i < npmem_ranges; i++) {
+
+			hole_pages = pmem_ranges[i].start_pfn - end_pfn;
+			if (hole_pages) {
+				pmem_holes[npmem_holes].start_pfn = end_pfn;
+				pmem_holes[npmem_holes++].pages = hole_pages;
+				end_pfn += hole_pages;
+			}
+			end_pfn += pmem_ranges[i].pages;
+		}
+
+		pmem_ranges[0].pages = end_pfn - pmem_ranges[0].start_pfn;
+		npmem_ranges = 1;
+	}
+#endif
+
+	bootmap_pages = 0;
+	for (i = 0; i < npmem_ranges; i++)
+		bootmap_pages += bootmem_bootmap_pages(pmem_ranges[i].pages);
+
+	bootmap_start_pfn = PAGE_ALIGN(__pa((unsigned long) &_end)) >> PAGE_SHIFT;
+
+#ifdef CONFIG_DISCONTIGMEM
+	for (i = 0; i < npmem_ranges; i++)
+		node_data[i].pg_data.bdata = &bmem_data[i];
+#endif
+	/*
+	 * Initialize and free the full range of memory in each range.
+	 * Note that the only writing these routines do are to the bootmap,
+	 * and we've made sure to locate the bootmap properly so that they
+	 * won't be writing over anything important.
+	 */
+
+	bootmap_pfn = bootmap_start_pfn;
+	max_pfn = 0;
+	for (i = 0; i < npmem_ranges; i++) {
+		unsigned long start_pfn;
+		unsigned long npages;
+
+		start_pfn = pmem_ranges[i].start_pfn;
+		npages = pmem_ranges[i].pages;
+
+		bootmap_size = init_bootmem_node(NODE_DATA(i),
+						bootmap_pfn,
+						start_pfn,
+						(start_pfn + npages) );
+		free_bootmem_node(NODE_DATA(i),
+				  (start_pfn << PAGE_SHIFT),
+				  (npages << PAGE_SHIFT) );
+		bootmap_pfn += (bootmap_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+		if ((start_pfn + npages) > max_pfn)
+			max_pfn = start_pfn + npages;
+	}
+
+	if ((bootmap_pfn - bootmap_start_pfn) != bootmap_pages) {
+		printk(KERN_WARNING "WARNING! bootmap sizing is messed up!\n");
+		BUG();
+	}
+
+	/* reserve PAGE0 pdc memory, kernel text/data/bss & bootmap */
+
+#define PDC_CONSOLE_IO_IODC_SIZE 32768
+
+	reserve_bootmem_node(NODE_DATA(0), 0UL,
+			(unsigned long)(PAGE0->mem_free + PDC_CONSOLE_IO_IODC_SIZE));
+	reserve_bootmem_node(NODE_DATA(0),__pa((unsigned long)&_text),
+			(unsigned long)(&_end - &_text));
+	reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT),
+			((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT));
+
+#ifndef CONFIG_DISCONTIGMEM
+
+	/* reserve the holes */
+
+	for (i = 0; i < npmem_holes; i++) {
+		reserve_bootmem_node(NODE_DATA(0),
+				(pmem_holes[i].start_pfn << PAGE_SHIFT),
+				(pmem_holes[i].pages << PAGE_SHIFT));
+	}
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start) {
+		printk(KERN_INFO "initrd: %08lx-%08lx\n", initrd_start, initrd_end);
+		if (__pa(initrd_start) < mem_max) {
+			unsigned long initrd_reserve;
+
+			if (__pa(initrd_end) > mem_max) {
+				initrd_reserve = mem_max - __pa(initrd_start);
+			} else {
+				initrd_reserve = initrd_end - initrd_start;
+			}
+			initrd_below_start_ok = 1;
+			printk(KERN_INFO "initrd: reserving %08lx-%08lx (mem_max %08lx)\n", __pa(initrd_start), __pa(initrd_start) + initrd_reserve, mem_max);
+
+			reserve_bootmem_node(NODE_DATA(0),__pa(initrd_start), initrd_reserve);
+		}
+	}
+#endif
+
+	data_resource.start =  virt_to_phys(&data_start);
+	data_resource.end = virt_to_phys(&_end)-1;
+	code_resource.start = virt_to_phys(&_text);
+	code_resource.end = virt_to_phys(&data_start)-1;
+
+	/* We don't know which region the kernel will be in, so try
+	 * all of them.
+	 */
+	for (i = 0; i < sysram_resource_count; i++) {
+		struct resource *res = &sysram_resources[i];
+		request_resource(res, &code_resource);
+		request_resource(res, &data_resource);
+	}
+	request_resource(&sysram_resources[0], &pdcdata_resource);
+}
+
+void free_initmem(void)
+{
+	/* FIXME: */
+#if 0
+	printk(KERN_INFO "NOT FREEING INITMEM (%dk)\n",
+			(&__init_end - &__init_begin) >> 10);
+	return;
+#endif
+	unsigned long addr;
+	
+	printk(KERN_INFO "Freeing unused kernel memory: ");
+
+#if 1
+	/* Attempt to catch anyone trying to execute code here
+	 * by filling the page with BRK insns.
+	 * 
+	 * If we disable interrupts for all CPUs, then IPI stops working.
+	 * Kinda breaks the global cache flushing.
+	 */
+	local_irq_disable();
+
+	memset(&__init_begin, 0x00, 
+		(unsigned long)&__init_end - (unsigned long)&__init_begin);
+
+	flush_data_cache();
+	asm volatile("sync" : : );
+	flush_icache_range((unsigned long)&__init_begin, (unsigned long)&__init_end);
+	asm volatile("sync" : : );
+
+	local_irq_enable();
+#endif
+	
+	addr = (unsigned long)(&__init_begin);
+	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+		ClearPageReserved(virt_to_page(addr));
+		set_page_count(virt_to_page(addr), 1);
+		free_page(addr);
+		num_physpages++;
+	}
+
+	printk("%luk freed\n", (unsigned long)(&__init_end - &__init_begin) >> 10);
 }
 
 /*
@@ -37,67 +422,42 @@
  * a hole of 4kB between each vmalloced area for the same reason.
  */
 
+#define MAP_START 0x4000 /* Leave room for gateway page expansion */
 #define VM_MAP_OFFSET  (32*1024)
 #define SET_MAP_OFFSET(x) ((void *)(((unsigned long)(x) + VM_MAP_OFFSET) \
 				     & ~(VM_MAP_OFFSET-1)))
 
 void *vmalloc_start;
+#ifdef CONFIG_PA11
 unsigned long pcxl_dma_start;
+#endif
 
 void __init mem_init(void)
 {
-	max_mapnr = num_physpages = max_low_pfn;
-	high_memory = __va(max_low_pfn * PAGE_SIZE);
+	int i;
+
+	high_memory = __va((max_pfn << PAGE_SHIFT));
+	max_mapnr = (virt_to_page(high_memory - 1) - mem_map) + 1;
+
+	num_physpages = 0;
+	for (i = 0; i < npmem_ranges; i++)
+		num_physpages += free_all_bootmem_node(NODE_DATA(i));
 
-	totalram_pages += free_all_bootmem();
-	printk("Memory: %luk available\n", totalram_pages << (PAGE_SHIFT-10));
+	printk(KERN_INFO "Memory: %luk available\n", num_physpages << (PAGE_SHIFT-10));
 
+#ifdef CONFIG_PA11
 	if (hppa_dma_ops == &pcxl_dma_ops) {
-	    pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(high_memory);
+	    pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(MAP_START);
 	    vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start + PCXL_DMA_MAP_SIZE);
 	}
 	else {
 	    pcxl_dma_start = 0;
-	    vmalloc_start = SET_MAP_OFFSET(high_memory);
-	}
-}
-
-void __bad_pgd(pgd_t *pgd)
-{
-	printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
-	pgd_val(*pgd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
-}
-
-void __bad_pmd(pmd_t *pmd)
-{
-	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-	pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
-}
-
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *pte;
-
-	pte = (pte_t *) __get_free_page(GFP_KERNEL);
-
-	if (pmd_none(*pmd)) {
-		if (pte) {
-			clear_page(pte);
-			pmd_val(*pmd) = _PAGE_TABLE + __pa((unsigned long)pte);
-			return pte + offset;
-		}
-		pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
-		return NULL;
-	}
-
-	free_page((unsigned long)pte);
-
-	if (pmd_bad(*pmd)) {
-		__bad_pmd(pmd);
-		return NULL;
+	    vmalloc_start = SET_MAP_OFFSET(MAP_START);
 	}
+#else
+	vmalloc_start = SET_MAP_OFFSET(MAP_START);
+#endif
 
-	return (pte_t *) pmd_page(*pmd) + offset;
 }
 
 int do_check_pgt_cache(int low, int high)
@@ -105,40 +465,16 @@
 	return 0;
 }
 
-/*
- * BAD_PAGE is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving an inode
- * unused etc..
- *
- * BAD_PAGETABLE is the accompanying page-table: it is initialized
- * to point to BAD_PAGE entries.
- *
- * ZERO_PAGE is a special page that is used for zero-initialized
- * data and COW.
- */
-pte_t * __bad_pagetable(void)
-{
-	return (pte_t *) NULL;
-}
-
 unsigned long *empty_zero_page;
-unsigned long *empty_bad_page;
-
-pte_t __bad_page(void)
-{
-	return *(pte_t *)NULL;
-}
 
 void show_mem(void)
 {
 	int i,free = 0,total = 0,reserved = 0;
 	int shared = 0, cached = 0;
 
-	printk("Mem-info:\n");
+	printk(KERN_INFO "Mem-info:\n");
 	show_free_areas();
-	printk("Free swap:	 %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+	printk(KERN_INFO "Free swap:	 %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
 	i = max_mapnr;
 	while (i-- > 0) {
 		total++;
@@ -151,54 +487,50 @@
 		else
 			shared += atomic_read(&mem_map[i].count) - 1;
 	}
-	printk("%d pages of RAM\n",total);
-	printk("%d reserved pages\n",reserved);
-	printk("%d pages shared\n",shared);
-	printk("%d pages swap cached\n",cached);
+	printk(KERN_INFO "%d pages of RAM\n", total);
+	printk(KERN_INFO "%d reserved pages\n", reserved);
+	printk(KERN_INFO "%d pages shared\n", shared);
+	printk(KERN_INFO "%d pages swap cached\n", cached);
 	show_buffers();
 }
 
-void set_pte_phys (unsigned long vaddr, unsigned long phys)
-{
-}
-
 
-/*
- * pagetable_init() sets up the page tables
- *
- * Note that gateway_init() places the Linux gateway page at page 0.
- * Since gateway pages cannot be dereferenced this has the desirable
- * side effect of trapping those pesky NULL-reference errors in the
- * kernel.
- */
-static void __init pagetable_init(void)
+static void __init map_pages(unsigned long start_vaddr, unsigned long start_paddr, unsigned long size, pgprot_t pgprot)
 {
 	pgd_t *pg_dir;
 	pmd_t *pmd;
 	pte_t *pg_table;
+	unsigned long end_paddr;
+	unsigned long start_pmd;
+	unsigned long start_pte;
 	unsigned long tmp1;
 	unsigned long tmp2;
 	unsigned long address;
 	unsigned long ro_start;
 	unsigned long ro_end;
 	unsigned long fv_addr;
-	extern  const int stext;
-	extern  int data_start;
-	extern  const unsigned long fault_vector_20;
+	unsigned long gw_addr;
+	extern const unsigned long fault_vector_20;
+	extern void * const linux_gateway_page;
 
-	ro_start = __pa((unsigned long)&stext);
+	ro_start = __pa((unsigned long)&_text);
 	ro_end   = __pa((unsigned long)&data_start);
 	fv_addr  = __pa((unsigned long)&fault_vector_20) & PAGE_MASK;
+	gw_addr  = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK;
 
-	printk("pagetable_init\n");
+	end_paddr = start_paddr + size;
 
-	/* Map whole memory from PAGE_OFFSET */
-	pg_dir = (pgd_t *)swapper_pg_dir + USER_PGD_PTRS;
+	pg_dir = pgd_offset_k(start_vaddr);
 
-	address = 0;
-	while (address < mem_max) {
-		/* XXX: BTLB should be done here */
+#if PTRS_PER_PMD == 1
+	start_pmd = 0;
+#else
+	start_pmd = ((start_vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1));
+#endif
+	start_pte = ((start_vaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
 
+	address = start_paddr;
+	while (address < end_paddr) {
 #if PTRS_PER_PMD == 1
 		pmd = (pmd_t *)__pa(pg_dir);
 #else
@@ -209,7 +541,7 @@
 		 */
 
 		if (!pmd) {
-			pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+			pmd = (pmd_t *) alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE);
 			pmd = (pmd_t *) __pa(pmd);
 		}
 
@@ -219,8 +551,8 @@
 
 		/* now change pmd to kernel virtual addresses */
 
-		pmd = (pmd_t *) __va(pmd);
-		for (tmp1 = 0 ; tmp1 < PTRS_PER_PMD ; tmp1++,pmd++) {
+		pmd = (pmd_t *)__va(pmd) + start_pmd;
+		for (tmp1 = start_pmd; tmp1 < PTRS_PER_PMD; tmp1++,pmd++) {
 
 			/*
 			 * pg_table is physical at this point
@@ -229,7 +561,7 @@
 			pg_table = (pte_t *) (PAGE_MASK & pmd_val(*pmd));
 			if (!pg_table) {
 				pg_table = (pte_t *)
-					alloc_bootmem_low_pages(PAGE_SIZE);
+					alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE);
 				pg_table = (pte_t *) __pa(pg_table);
 			}
 
@@ -238,8 +570,8 @@
 
 			/* now change pg_table to kernel virtual addresses */
 
-			pg_table = (pte_t *) __va(pg_table);
-			for (tmp2=0; tmp2 < PTRS_PER_PTE; tmp2++,pg_table++) {
+			pg_table = (pte_t *) __va(pg_table) + start_pte;
+			for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++,pg_table++) {
 				pte_t pte;
 
 #if !defined(CONFIG_KWDB) && !defined(CONFIG_STI_CONSOLE)
@@ -249,53 +581,84 @@
 ** The right thing to do seems like KWDB modify only the pte which
 ** has a break point on it...otherwise we might mask worse bugs.
 */
+				/*
+				 * Map the fault vector writable so we can
+				 * write the HPMC checksum.
+				 */
 				if (address >= ro_start && address < ro_end
-							&& address != fv_addr)
+							&& address != fv_addr
+							&& address != gw_addr)
 				    pte = __mk_pte(address, PAGE_KERNEL_RO);
 				else
 #endif
-				    pte = __mk_pte(address, PAGE_KERNEL);
+				    pte = __mk_pte(address, pgprot);
 
-				if (address >= mem_max)
+				if (address >= end_paddr)
 					pte_val(pte) = 0;
 
 				set_pte(pg_table, pte);
 
 				address += PAGE_SIZE;
 			}
+			start_pte = 0;
 
-			if (address >= mem_max)
+			if (address >= end_paddr)
 			    break;
 		}
+		start_pmd = 0;
 	}
+}
+
+/*
+ * pagetable_init() sets up the page tables
+ *
+ * Note that gateway_init() places the Linux gateway page at page 0.
+ * Since gateway pages cannot be dereferenced this has the desirable
+ * side effect of trapping those pesky NULL-reference errors in the
+ * kernel.
+ */
+static void __init pagetable_init(void)
+{
+	int range;
+
+	printk("pagetable_init\n");
+
+	/* Map each physical memory range to its kernel vaddr */
+
+	for (range = 0; range < npmem_ranges; range++) {
+		unsigned long start_paddr;
+		unsigned long end_paddr;
+		unsigned long size;
+
+		start_paddr = pmem_ranges[range].start_pfn << PAGE_SHIFT;
+		end_paddr = start_paddr + (pmem_ranges[range].pages << PAGE_SHIFT);
+		size = pmem_ranges[range].pages << PAGE_SHIFT;
+
+		map_pages((unsigned long)__va(start_paddr), start_paddr,
+			size, PAGE_KERNEL);
+	}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_end && initrd_end > mem_limit) {
+		printk("initrd: mapping %08lx-%08lx\n", initrd_start, initrd_end);
+		map_pages(initrd_start, __pa(initrd_start),
+			initrd_end - initrd_start, PAGE_KERNEL);
+	}
+#endif
 
 	empty_zero_page = alloc_bootmem_pages(PAGE_SIZE);
 	memset(empty_zero_page, 0, PAGE_SIZE);
 }
 
-unsigned long gateway_pgd_offset;
-unsigned long gateway_pgd_entry;
-
 static void __init gateway_init(void)
 {
-	unsigned long hpux_gateway_page_addr;
 	unsigned long linux_gateway_page_addr;
-	pgd_t *pg_dir;
-	pmd_t *pmd_base;
-	pmd_t *pmd;
-	pte_t *pg_table_base;
-	pte_t *pg_table;
-	/* FIXME: These are 'const' in order to trick the compiler
-           into not treating them as DP-relative data. */
-	extern void * const hpux_gateway_page;
+	/* FIXME: This is 'const' in order to trick the compiler
+	   into not treating it as DP-relative data. */
 	extern void * const linux_gateway_page;
-	pte_t pte;
 
-	hpux_gateway_page_addr = HPUX_GATEWAY_ADDR & PAGE_MASK;
 	linux_gateway_page_addr = LINUX_GATEWAY_ADDR & PAGE_MASK;
 
-	gateway_pgd_offset = hpux_gateway_page_addr >> PGDIR_SHIFT;
-
 	/*
 	 * Setup Linux Gateway page.
 	 *
@@ -303,177 +666,356 @@
 	 * page 0), so it doesn't need to be aliased into user space.
 	 */
 
-	pg_dir = (pgd_t *)swapper_pg_dir;
-
-#if PTRS_PER_PMD == 1
-	pmd_base = (pmd_t *)pg_dir;
-	pmd = pmd_base +
-		((linux_gateway_page_addr) >> PGDIR_SHIFT);
-
-#else
-	pmd_base = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE);
-	pgd_val(*(pg_dir + (linux_gateway_page_addr >> PGDIR_SHIFT))) =
-		_PAGE_TABLE | __pa(pmd_base);
+	map_pages(linux_gateway_page_addr, __pa(&linux_gateway_page),
+		PAGE_SIZE, PAGE_GATEWAY);
+}
 
-	pmd = pmd_base +
-		((linux_gateway_page_addr & (PMD_MASK) & (PGDIR_SIZE - 1)) >>
-								PMD_SHIFT);
-#endif
+void
+map_hpux_gateway_page(struct task_struct *tsk, struct mm_struct *mm)
+{
+	pgd_t *pg_dir;
+	pmd_t *pmd;
+	pte_t *pg_table;
+	unsigned long start_pmd;
+	unsigned long start_pte;
+	unsigned long address;
+	unsigned long hpux_gw_page_addr;
+	/* FIXME: This is 'const' in order to trick the compiler
+	   into not treating it as DP-relative data. */
+	extern void * const hpux_gateway_page;
 
-	pg_table_base = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
+	hpux_gw_page_addr = HPUX_GATEWAY_ADDR & PAGE_MASK;
 
-	pmd_val(*pmd) = _PAGE_TABLE | __pa(pg_table_base);
+	/*
+	 * Setup HP-UX Gateway page.
+	 *
+	 * The HP-UX gateway page resides in the user address space,
+	 * so it needs to be aliased into each process.
+	 */
 
-	pte = __mk_pte(__pa(&linux_gateway_page), PAGE_GATEWAY);
+	pg_dir = pgd_offset(mm,hpux_gw_page_addr);
 
-	pg_table = pg_table_base +
-		((linux_gateway_page_addr & (PAGE_MASK) & (PMD_SIZE - 1)) >>
-								PAGE_SHIFT);
+#if PTRS_PER_PMD == 1
+	start_pmd = 0;
+#else
+	start_pmd = ((hpux_gw_page_addr >> PMD_SHIFT) & (PTRS_PER_PMD - 1));
+#endif
+	start_pte = ((hpux_gw_page_addr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
 
-	set_pte(pg_table,pte);
+	address = __pa(&hpux_gateway_page);
+#if PTRS_PER_PMD == 1
+	pmd = (pmd_t *)__pa(pg_dir);
+#else
+	pmd = (pmd_t *) (PAGE_MASK & pgd_val(*pg_dir));
 
 	/*
-	 * Setup HP-UX gateway page.
-	 * This page will be aliased into each user address space.
+	 * pmd is physical at this point
 	 */
 
-	pg_table_base = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
-
-	pte = __mk_pte(__pa(&hpux_gateway_page), PAGE_GATEWAY);
-	pg_table = pg_table_base +
-		((hpux_gateway_page_addr & (PAGE_MASK) & (PMD_SIZE - 1)) >>
-								PAGE_SHIFT);
-
-	set_pte(pg_table,pte);
-
+	if (!pmd) {
+		pmd = (pmd_t *) get_zeroed_page(GFP_KERNEL);
+		pmd = (pmd_t *) __pa(pmd);
+	}
 
-#if PTRS_PER_PMD == 1
-	pmd_base = (pmd_t *)pg_table_base;
-#else
-	pmd_base = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE);
-	pmd = pmd_base +
-		((hpux_gateway_page_addr & (PMD_MASK) & (PGDIR_SIZE - 1)) >>
-								PMD_SHIFT);
-	pmd_val(*pmd) = _PAGE_TABLE | __pa(pg_table_base);
+	pgd_val(*pg_dir) = _PAGE_TABLE | (unsigned long) pmd;
 #endif
+	/* now change pmd to kernel virtual addresses */
 
-	gateway_pgd_entry = _PAGE_TABLE | __pa(pmd_base);
+	pmd = (pmd_t *)__va(pmd) + start_pmd;
 
 	/*
-	 * We will be aliasing the HP-UX gateway page into all HP-UX
-	 * user spaces at the same address (not counting the space register
-	 * value) that will be equivalently mapped as long as space register
-	 * hashing is disabled. It will be a problem if anyone touches
-	 * the gateway pages at its "kernel" address, since that is
-	 * NOT equivalently mapped. We'll flush the caches at this
-	 * point, just in case some code has touched those addresses
-	 * previous to this, but all bets are off if they get touched
-	 * after this point.
+	 * pg_table is physical at this point
 	 */
 
-	flush_all_caches();
+	pg_table = (pte_t *) (PAGE_MASK & pmd_val(*pmd));
+	if (!pg_table)
+		pg_table = (pte_t *) __pa(get_zeroed_page(GFP_KERNEL));
 
-	return;
+	pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) pg_table;
+
+	/* now change pg_table to kernel virtual addresses */
+
+	pg_table = (pte_t *) __va(pg_table) + start_pte;
+	set_pte(pg_table, __mk_pte(address, PAGE_GATEWAY));
 }
 
+extern void flush_tlb_all_local(void);
+
 void __init paging_init(void)
 {
+	int i;
+
+	setup_bootmem();
 	pagetable_init();
 	gateway_init();
+	flush_cache_all_local(); /* start with known state */
+	flush_tlb_all_local();
 
-	{
-		unsigned long zones_size[MAX_NR_ZONES] = { max_pfn/2, max_pfn/2, };
+	for (i = 0; i < npmem_ranges; i++) {
+		unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0, };
 
-		free_area_init(zones_size);
+		zones_size[ZONE_DMA] = pmem_ranges[i].pages;
+		free_area_init_node(i,NODE_DATA(i),NULL,zones_size,
+				(pmem_ranges[i].start_pfn << PAGE_SHIFT),0);
 	}
+
+#ifdef CONFIG_DISCONTIGMEM
+	/*
+	 * Initialize support for virt_to_page() macro.
+	 *
+	 * Note that MAX_ADDRESS is the largest virtual address that
+	 * we can map. However, since we map all physical memory into
+	 * the kernel address space, it also has an effect on the maximum
+	 * physical address we can map (MAX_ADDRESS - PAGE_OFFSET).
+	 */
+
+	maxchunkmap = MAX_ADDRESS >> CHUNKSHIFT;
+	chunkmap = (unsigned char *)alloc_bootmem(maxchunkmap);
+
+	for (i = 0; i < maxchunkmap; i++)
+	    chunkmap[i] = BADCHUNK;
+
+	for (i = 0; i < npmem_ranges; i++) {
+
+		ADJ_NODE_MEM_MAP(i) = NODE_MEM_MAP(i) - pmem_ranges[i].start_pfn;
+		{
+			unsigned long chunk_paddr;
+			unsigned long end_paddr;
+			int chunknum;
+
+			chunk_paddr = (pmem_ranges[i].start_pfn << PAGE_SHIFT);
+			end_paddr = chunk_paddr + (pmem_ranges[i].pages << PAGE_SHIFT);
+			chunk_paddr &= CHUNKMASK;
+
+			chunknum = (int)CHUNKNUM(chunk_paddr);
+			while (chunk_paddr < end_paddr) {
+				if (chunknum >= maxchunkmap)
+					goto badchunkmap1;
+				if (chunkmap[chunknum] != BADCHUNK)
+					goto badchunkmap2;
+				chunkmap[chunknum] = (unsigned char)i;
+				chunk_paddr += CHUNKSZ;
+				chunknum++;
+			}
+		}
+	}
+
+	return;
+
+badchunkmap1:
+	panic("paging_init: Physical address exceeds maximum address space!\n");
+badchunkmap2:
+	panic("paging_init: Collision in chunk map array. CHUNKSZ needs to be smaller\n");
+#endif
 }
 
-#define NR_SPACE_IDS	8192
+#ifdef CONFIG_PA20
 
-static unsigned long space_id[NR_SPACE_IDS / (8 * sizeof(long))];
-static unsigned long space_id_index;
-static unsigned long free_space_ids = NR_SPACE_IDS;
+/*
+ * Currently, all PA20 chips have 18 bit protection id's, which is the
+ * limiting factor (space ids are 32 bits).
+ */
+
+#define NR_SPACE_IDS 262144
+
+#else
 
 /*
- * XXX: We should probably unfold the set_bit / test_bit / clear_bit
- * locking out of these two functions and have a single spinlock on the
- * space_id data structures.
- *
- * Don't bother. This is all going to be significantly changed in the
- * very near future.
+ * Currently we have a one-to-one relationship between space id's and
+ * protection id's. Older parisc chips (PCXS, PCXT, PCXL, PCXL2) only
+ * support 15 bit protection id's, so that is the limiting factor.
+ * PCXT' has 18 bit protection id's, but only 16 bit spaceids, so it's
+ * probably not worth the effort for a special case here.
  */
 
-#define SPACEID_SHIFT (PAGE_SHIFT + (PT_NLEVELS)*(PAGE_SHIFT - PT_NLEVELS) - 32)
+#define NR_SPACE_IDS 32768
+
+#endif  /* !CONFIG_PA20 */
+
+#define RECYCLE_THRESHOLD (NR_SPACE_IDS / 2)
+#define SID_ARRAY_SIZE  (NR_SPACE_IDS / (8 * sizeof(long)))
+
+static unsigned long space_id[SID_ARRAY_SIZE] = { 1 }; /* disallow space 0 */
+static unsigned long dirty_space_id[SID_ARRAY_SIZE];
+static unsigned long space_id_index;
+static unsigned long free_space_ids = NR_SPACE_IDS - 1;
+static unsigned long dirty_space_ids = 0;
+
+static spinlock_t sid_lock = SPIN_LOCK_UNLOCKED;
 
 unsigned long alloc_sid(void)
 {
 	unsigned long index;
 
-	if (free_space_ids == 0)
-		BUG();
+	spin_lock(&sid_lock);
 
-	free_space_ids--;
+	if (free_space_ids == 0) {
+		if (dirty_space_ids != 0) {
+			spin_unlock(&sid_lock);
+			flush_tlb_all(); /* flush_tlb_all() calls recycle_sids() */
+			spin_lock(&sid_lock);
+		}
+		if (free_space_ids == 0)
+			BUG();
+	}
 
-	do {
-		index = find_next_zero_bit(space_id, NR_SPACE_IDS, space_id_index);
-	} while(test_and_set_bit(index, space_id));
+	free_space_ids--;
 
+	index = find_next_zero_bit(space_id, NR_SPACE_IDS, space_id_index);
+	space_id[index >> SHIFT_PER_LONG] |= (1L << (index & (BITS_PER_LONG - 1)));
 	space_id_index = index;
 
+	spin_unlock(&sid_lock);
+
 	return index << SPACEID_SHIFT;
 }
 
 void free_sid(unsigned long spaceid)
 {
 	unsigned long index = spaceid >> SPACEID_SHIFT;
-	if (index < 0)
-		BUG();
+	unsigned long *dirty_space_offset;
+
+	dirty_space_offset = dirty_space_id + (index >> SHIFT_PER_LONG);
+	index &= (BITS_PER_LONG - 1);
+
+	spin_lock(&sid_lock);
+
+	if (*dirty_space_offset & (1L << index))
+	    BUG(); /* attempt to free space id twice */
+
+	*dirty_space_offset |= (1L << index);
+	dirty_space_ids++;
+
+	spin_unlock(&sid_lock);
+}
+
+
+#ifdef CONFIG_SMP
+static void get_dirty_sids(unsigned long *ndirtyptr,unsigned long *dirty_array)
+{
+	int i;
+
+	/* NOTE: sid_lock must be held upon entry */
+
+	*ndirtyptr = dirty_space_ids;
+	if (dirty_space_ids != 0) {
+	    for (i = 0; i < SID_ARRAY_SIZE; i++) {
+		dirty_array[i] = dirty_space_id[i];
+		dirty_space_id[i] = 0;
+	    }
+	    dirty_space_ids = 0;
+	}
 
-	clear_bit(index, space_id);
+	return;
+}
+
+static void recycle_sids(unsigned long ndirty,unsigned long *dirty_array)
+{
+	int i;
+
+	/* NOTE: sid_lock must be held upon entry */
+
+	if (ndirty != 0) {
+		for (i = 0; i < SID_ARRAY_SIZE; i++) {
+			space_id[i] ^= dirty_array[i];
+		}
+
+		free_space_ids += ndirty;
+		space_id_index = 0;
+	}
+}
+
+#else /* CONFIG_SMP */
+
+static void recycle_sids(void)
+{
+	int i;
+
+	/* NOTE: sid_lock must be held upon entry */
+
+	if (dirty_space_ids != 0) {
+		for (i = 0; i < SID_ARRAY_SIZE; i++) {
+			space_id[i] ^= dirty_space_id[i];
+			dirty_space_id[i] = 0;
+		}
+
+		free_space_ids += dirty_space_ids;
+		dirty_space_ids = 0;
+		space_id_index = 0;
+	}
+}
+#endif
+
+/*
+ * flush_tlb_all() calls recycle_sids(), since whenever the entire tlb is
+ * purged, we can safely reuse the space ids that were released but
+ * not flushed from the tlb.
+ */
+
+#ifdef CONFIG_SMP
 
-	if (space_id_index > index) {
-		space_id_index = index;
+static unsigned long recycle_ndirty;
+static unsigned long recycle_dirty_array[SID_ARRAY_SIZE];
+static unsigned int recycle_inuse = 0;
+
+void flush_tlb_all(void)
+{
+	int do_recycle;
+
+	do_recycle = 0;
+	spin_lock(&sid_lock);
+	if (dirty_space_ids > RECYCLE_THRESHOLD) {
+	    if (recycle_inuse) {
+		BUG();  /* FIXME: Use a semaphore/wait queue here */
+	    }
+	    get_dirty_sids(&recycle_ndirty,recycle_dirty_array);
+	    recycle_inuse++;
+	    do_recycle++;
+	}
+	spin_unlock(&sid_lock);
+	smp_call_function((void (*)(void *))flush_tlb_all_local, NULL, 1, 1);
+	flush_tlb_all_local();
+	if (do_recycle) {
+	    spin_lock(&sid_lock);
+	    recycle_sids(recycle_ndirty,recycle_dirty_array);
+	    recycle_inuse = 0;
+	    spin_unlock(&sid_lock);
 	}
-	free_space_ids++;
 }
+#else
+void flush_tlb_all(void)
+{
+	spin_lock(&sid_lock);
+	flush_tlb_all_local();
+	recycle_sids();
+	spin_unlock(&sid_lock);
+}
+#endif
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
 #if 0
+	if (start < end)
+		printk(KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
 	for (; start < end; start += PAGE_SIZE) {
-		ClearPageReserved(mem_map + MAP_NR(start));
-		set_page_count(mem_map+MAP_NR(start), 1);
+		ClearPageReserved(virt_to_page(start));
+		set_page_count(virt_to_page(start), 1);
 		free_page(start);
-		totalram_pages++;
+		num_physpages++;
 	}
-	printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
 #endif
 }
 #endif
 
 void si_meminfo(struct sysinfo *val)
 {
-	int i;
-
-	i = max_mapnr;
-	val->totalram = totalram_pages;
+	val->totalram = num_physpages;
 	val->sharedram = 0;
 	val->freeram = nr_free_pages();
 	val->bufferram = atomic_read(&buffermem_pages);
-#if 0
-	while (i-- > 0)  {
-		if (PageReserved(mem_map+i))
-			continue;
-		val->totalram++;
-		if (!atomic_read(&mem_map[i].count))
-			continue;
-		val->sharedram += atomic_read(&mem_map[i].count) - 1;
-	}
-	val->totalram <<= PAGE_SHIFT;
-	val->sharedram <<= PAGE_SHIFT;
-#endif
 	val->totalhigh = 0;
 	val->freehigh = 0;
+	val->mem_unit = PAGE_SIZE;
 	return;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/mm/ioremap.c linux-2.4.20/arch/parisc/mm/ioremap.c
--- linux-2.4.19/arch/parisc/mm/ioremap.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/mm/ioremap.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,177 @@
+/*
+ * arch/parisc/mm/ioremap.c
+ *
+ * Re-map IO memory to kernel address space so that we can access it.
+ * This is needed for high PCI addresses that aren't mapped in the
+ * 640k-1MB IO memory area on PC's
+ *
+ * (C) Copyright 1995 1996 Linus Torvalds
+ * (C) Copyright 2001 Helge Deller <deller@gmx.de>
+ */
+
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+
+static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+	unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	if (address >= end)
+		BUG();
+	do {
+		if (!pte_none(*pte)) {
+			printk(KERN_ERR "remap_area_pte: page already exists\n");
+			BUG();
+		}
+		set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | _PAGE_RW | 
+					_PAGE_DIRTY | _PAGE_ACCESSED | flags)));
+		address += PAGE_SIZE;
+		phys_addr += PAGE_SIZE;
+		pte++;
+	} while (address && (address < end));
+}
+
+static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+	unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	phys_addr -= address;
+	if (address >= end)
+		BUG();
+	do {
+		pte_t * pte = pte_alloc(NULL, pmd, address);
+		if (!pte)
+			return -ENOMEM;
+		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address && (address < end));
+	return 0;
+}
+
+#if (USE_HPPA_IOREMAP)
+static int remap_area_pages(unsigned long address, unsigned long phys_addr,
+				 unsigned long size, unsigned long flags)
+{
+	int error;
+	pgd_t * dir;
+	unsigned long end = address + size;
+
+	phys_addr -= address;
+	dir = pgd_offset(&init_mm, address);
+	flush_cache_all();
+	if (address >= end)
+		BUG();
+	spin_lock(&init_mm.page_table_lock);
+	do {
+		pmd_t *pmd;
+		pmd = pmd_alloc(dir, address);
+		error = -ENOMEM;
+		if (!pmd)
+			break;
+		if (remap_area_pmd(pmd, address, end - address,
+					 phys_addr + address, flags))
+			break;
+		error = 0;
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	} while (address && (address < end));
+	spin_unlock(&init_mm.page_table_lock);
+	flush_tlb_all();
+	return error;
+}
+#endif /* USE_HPPA_IOREMAP */
+
+/*
+ * Generic mapping function (not visible outside):
+ */
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ *
+ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
+ * have to convert them into an offset in a page-aligned mapping, but the
+ * caller shouldn't need to know that small detail.
+ */
+void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
+{
+#if !(USE_HPPA_IOREMAP)
+
+	unsigned long end = phys_addr + size - 1;
+	/* Support EISA addresses */
+	if ((phys_addr >= 0x00080000 && end < 0x000fffff)
+			|| (phys_addr >= 0x00500000 && end < 0x03bfffff)) {
+		phys_addr |= 0xfc000000;
+	}
+
+	return (void *)phys_addr;
+
+#else
+	void * addr;
+	struct vm_struct * area;
+	unsigned long offset, last_addr;
+
+	/* Don't allow wraparound or zero size */
+	last_addr = phys_addr + size - 1;
+	if (!size || last_addr < phys_addr)
+		return NULL;
+
+	/*
+	 * Don't allow anybody to remap normal RAM that we're using..
+	 */
+	if (phys_addr < virt_to_phys(high_memory)) {
+		char *t_addr, *t_end;
+		struct page *page;
+
+		t_addr = __va(phys_addr);
+		t_end = t_addr + (size - 1);
+	   
+		for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++)
+			if(!PageReserved(page))
+				return NULL;
+	}
+
+	/*
+	 * Mappings have to be page-aligned
+	 */
+	offset = phys_addr & ~PAGE_MASK;
+	phys_addr &= PAGE_MASK;
+	size = PAGE_ALIGN(last_addr) - phys_addr;
+
+	/*
+	 * Ok, go for it..
+	 */
+	area = get_vm_area(size, VM_IOREMAP);
+	if (!area)
+		return NULL;
+	addr = area->addr;
+	if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
+		vfree(addr);
+		return NULL;
+	}
+	return (void *) (offset + (char *)addr);
+#endif
+}
+
+void iounmap(void *addr)
+{
+#if !(USE_HPPA_IOREMAP)
+	return;
+#else
+	if (addr > high_memory)
+		return vfree((void *) (PAGE_MASK & (unsigned long) addr));
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/mm/kmap.c linux-2.4.20/arch/parisc/mm/kmap.c
--- linux-2.4.19/arch/parisc/mm/kmap.c	2001-02-09 19:29:44.000000000 +0000
+++ linux-2.4.20/arch/parisc/mm/kmap.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,143 +0,0 @@
-/*
-** Stolen mostly from arch/parisc/kernel/pci-dma.c
-*/
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-
-#include <asm/io.h>
-#include <asm/page.h>		/* get_order */
-
-#undef flush_cache_all
-#define flush_cache_all flush_all_caches
-
-typedef void (*pte_iterator_t) (pte_t * pte, unsigned long arg);
-
-#if 0
-/* XXX This routine could be used with iterate_page() to replace
- * unmap_uncached_page() and save a little code space but I didn't
- * do that since I'm not certain whether this is the right path. -PB
- */
-static void unmap_cached_pte(pte_t * pte, unsigned long arg)
-{
-	pte_t page = *pte;
-	pte_clear(pte);
-	if (!pte_none(page)) {
-		if (pte_present(page)) {
-			unsigned long map_nr = pte_pagenr(page);
-			if (map_nr < max_mapnr)
-				__free_page(mem_map + map_nr);
-		} else {
-			printk(KERN_CRIT
-			       "Whee.. Swapped out page in kernel page table\n");
-		}
-	}
-}
-#endif
-
-/* These two routines should probably check a few things... */
-static void set_uncached(pte_t * pte, unsigned long arg)
-{
-	pte_val(*pte) |= _PAGE_NO_CACHE;
-}
-
-static void set_cached(pte_t * pte, unsigned long arg)
-{
-	pte_val(*pte) &= ~_PAGE_NO_CACHE;
-}
-
-static inline void iterate_pte(pmd_t * pmd, unsigned long address,
-			       unsigned long size, pte_iterator_t op,
-			       unsigned long arg)
-{
-	pte_t *pte;
-	unsigned long end;
-
-	if (pmd_none(*pmd))
-		return;
-	if (pmd_bad(*pmd)) {
-		pmd_ERROR(*pmd);
-		pmd_clear(pmd);
-		return;
-	}
-	pte = pte_offset(pmd, address);
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
-	do {
-		op(pte, arg);
-		address += PAGE_SIZE;
-		pte++;
-	} while (address < end);
-}
-
-static inline void iterate_pmd(pgd_t * dir, unsigned long address,
-			       unsigned long size, pte_iterator_t op,
-			       unsigned long arg)
-{
-	pmd_t *pmd;
-	unsigned long end;
-
-	if (pgd_none(*dir))
-		return;
-	if (pgd_bad(*dir)) {
-		pgd_ERROR(*dir);
-		pgd_clear(dir);
-		return;
-	}
-	pmd = pmd_offset(dir, address);
-	address &= ~PGDIR_MASK;
-	end = address + size;
-	if (end > PGDIR_SIZE)
-		end = PGDIR_SIZE;
-	do {
-		iterate_pte(pmd, address, end - address, op, arg);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address < end);
-}
-
-static void iterate_pages(unsigned long address, unsigned long size,
-			  pte_iterator_t op, unsigned long arg)
-{
-	pgd_t *dir;
-	unsigned long end = address + size;
-
-	dir = pgd_offset_k(address);
-	flush_cache_all();
-	do {
-		iterate_pmd(dir, address, end - address, op, arg);
-		address = (address + PGDIR_SIZE) & PGDIR_MASK;
-		dir++;
-	} while (address && (address < end));
-	flush_tlb_all();
-}
-
-void
-kernel_set_cachemode(unsigned long vaddr, unsigned long size, int what)
-{
-	switch (what) {
-	case IOMAP_FULL_CACHING:
-		iterate_pages(vaddr, size, set_cached, 0);
-		flush_tlb_range(&init_mm, vaddr, size);
-		break;
-	case IOMAP_NOCACHE_SER:
-		iterate_pages(vaddr, size, set_uncached, 0);
-		flush_tlb_range(&init_mm, vaddr, size);
-		break;
-	default:
-		printk(KERN_CRIT
-		       "kernel_set_cachemode mode %d not understood\n",
-		       what);
-		break;
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/mm/pa11.c linux-2.4.20/arch/parisc/mm/pa11.c
--- linux-2.4.19/arch/parisc/mm/pa11.c	2001-09-30 19:26:08.000000000 +0000
+++ linux-2.4.20/arch/parisc/mm/pa11.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,171 +0,0 @@
-/* $Id: pa11.c,v 1.1 1999/03/17 01:05:41 pjlahaie Exp $
- *
- * pa11.c: PA 1.1 specific mmu/cache code.
- *
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/sgialib.h>
-#include <asm/mmu_context.h>
-
-extern unsigned long mips_tlb_entries;
-
-/* page functions */
-void pa11_clear_page(unsigned long page)
-{
-}
-
-static void pa11_copy_page(unsigned long to, unsigned long from)
-{
-}
-
-/* Cache operations. */
-static inline void pa11_flush_cache_all(void) { }
-static void pa11_flush_cache_mm(struct mm_struct *mm) { }
-static void pa11_flush_cache_range(struct mm_struct *mm,
-				    unsigned long start,
-				    unsigned long end)
-{
-}
-
-static void pa11_flush_cache_page(struct vm_area_struct *vma,
-				   unsigned long page)
-{
-}
-
-static void pa11_flush_page_to_ram(unsigned long page)
-{
-}
-
-static void pa11_flush_cache_sigtramp(unsigned long page)
-{
-}
-
-/* TLB operations. */
-static inline void pa11_flush_tlb_all(void)
-{
-	unsigned long flags;
-	int entry;
-
-	save_and_cli(flags);
-/* Here we will need to flush all the TLBs */
-	restore_flags(flags);
-}
-
-static void pa11_flush_tlb_mm(struct mm_struct *mm)
-{
-/* This is what the MIPS does..  Is it the right thing for PA-RISC? */
-	if(mm == current->mm)
-		pa11_flush_tlb_all();
-}
-
-static void pa11_flush_tlb_range(struct mm_struct *mm, unsigned long start,
-				  unsigned long end)
-{
-	if(mm == current->mm)
-		pa11_flush_tlb_all();
-}
-
-static void pa11_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
-	if(vma->vm_mm == current->mm)
-		pa11_flush_tlb_all();
-}
-
-static void pa11_load_pgd(unsigned long pg_dir)
-{
-	unsigned long flags;
-    /* We need to do the right thing here */
-}
-
-/*
- * Initialize new page directory with pointers to invalid ptes
- */
-static void pa11_pgd_init(unsigned long page)
-{
-	unsigned long dummy1, dummy2;
-
-}
-
-static void pa11_update_mmu_cache(struct vm_area_struct * vma,
-				   unsigned long address, pte_t pte)
-{
-	pa11_flush_tlb_page(vma, address);
-}
-
-static void pa11_show_regs(struct pt_regs * regs)
-{
-	/*
-	 * Saved main processor registers
-	 */
-	printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       0, (unsigned long) regs->regs[1], (unsigned long) regs->regs[2],
-	       (unsigned long) regs->regs[3], (unsigned long) regs->regs[4],
-	       (unsigned long) regs->regs[5], (unsigned long) regs->regs[6],
-	       (unsigned long) regs->regs[7]);
-	printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       (unsigned long) regs->regs[8], (unsigned long) regs->regs[9],
-	       (unsigned long) regs->regs[10], (unsigned long) regs->regs[11],
-               (unsigned long) regs->regs[12], (unsigned long) regs->regs[13],
-	       (unsigned long) regs->regs[14], (unsigned long) regs->regs[15]);
-	printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       (unsigned long) regs->regs[16], (unsigned long) regs->regs[17],
-	       (unsigned long) regs->regs[18], (unsigned long) regs->regs[19],
-               (unsigned long) regs->regs[20], (unsigned long) regs->regs[21],
-	       (unsigned long) regs->regs[22], (unsigned long) regs->regs[23]);
-	printk("$24: %08lx %08lx                   %08lx %08lx %08lx %08lx\n",
-	       (unsigned long) regs->regs[24], (unsigned long) regs->regs[25],
-	       (unsigned long) regs->regs[28], (unsigned long) regs->regs[29],
-               (unsigned long) regs->regs[30], (unsigned long) regs->regs[31]);
-
-	/*
-	 * Saved cp0 registers
-	 */
-	printk("epc  : %08lx    %s\nStatus: %08x\nCause : %08x\n",
-	       (unsigned long) regs->cp0_epc, print_tainted(),
-	       (unsigned int) regs->cp0_status,
-	       (unsigned int) regs->cp0_cause);
-}
-
-static int pa11_user_mode(struct pt_regs *regs)
-{
-       /* Return user mode stuff?? */
-}
-
-__initfunc(void ld_mmu_pa11(void))
-{
-
-    /* Taken directly from the MIPS arch..  Lots of bad things here */
-	clear_page = pa11_clear_page;
-	copy_page = pa11_copy_page;
-
-	flush_cache_all = pa11_flush_cache_all;
-	flush_cache_mm = pa11_flush_cache_mm;
-	flush_cache_range = pa11_flush_cache_range;
-	flush_cache_page = pa11_flush_cache_page;
-	flush_cache_sigtramp = pa11_flush_cache_sigtramp;
-	flush_page_to_ram = pa11_flush_page_to_ram;
-
-	flush_tlb_all = pa11_flush_tlb_all;
-	flush_tlb_mm = pa11_flush_tlb_mm;
-	flush_tlb_range = pa11_flush_tlb_range;
-	flush_tlb_page = pa11_flush_tlb_page;
-	pa11_asid_setup();
-
-	load_pgd = pa11_load_pgd;
-	pgd_init = pa11_pgd_init;
-	update_mmu_cache = pa11_update_mmu_cache;
-
-	show_regs = pa11_show_regs;
-    
-        add_wired_entry = pa11_add_wired_entry;
-
-	user_mode = pa11_user_mode;
-	flush_tlb_all();
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/mm/pa20.c linux-2.4.20/arch/parisc/mm/pa20.c
--- linux-2.4.19/arch/parisc/mm/pa20.c	2001-09-30 19:26:08.000000000 +0000
+++ linux-2.4.20/arch/parisc/mm/pa20.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,171 +0,0 @@
-/* $Id: pa20.c,v 1.1 1999/03/17 01:05:41 pjlahaie Exp $
- *
- * pa20.c: PA 2.0 specific mmu/cache code.
- *
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/sgialib.h>
-#include <asm/mmu_context.h>
-
-extern unsigned long mips_tlb_entries;
-
-/* page functions */
-void pa20_clear_page(unsigned long page)
-{
-}
-
-static void pa20_copy_page(unsigned long to, unsigned long from)
-{
-}
-
-/* Cache operations. */
-static inline void pa20_flush_cache_all(void) { }
-static void pa20_flush_cache_mm(struct mm_struct *mm) { }
-static void pa20_flush_cache_range(struct mm_struct *mm,
-				    unsigned long start,
-				    unsigned long end)
-{
-}
-
-static void pa20_flush_cache_page(struct vm_area_struct *vma,
-				   unsigned long page)
-{
-}
-
-static void pa20_flush_page_to_ram(unsigned long page)
-{
-}
-
-static void pa20_flush_cache_sigtramp(unsigned long page)
-{
-}
-
-/* TLB operations. */
-static inline void pa20_flush_tlb_all(void)
-{
-	unsigned long flags;
-	int entry;
-
-	save_and_cli(flags);
-/* Here we will need to flush all the TLBs */
-	restore_flags(flags);
-}
-
-static void pa20_flush_tlb_mm(struct mm_struct *mm)
-{
-/* This is what the MIPS does..  Is it the right thing for PA-RISC? */
-	if(mm == current->mm)
-		pa20_flush_tlb_all();
-}
-
-static void pa20_flush_tlb_range(struct mm_struct *mm, unsigned long start,
-				  unsigned long end)
-{
-	if(mm == current->mm)
-		pa20_flush_tlb_all();
-}
-
-static void pa20_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
-	if(vma->vm_mm == current->mm)
-		pa20_flush_tlb_all();
-}
-
-static void pa20_load_pgd(unsigned long pg_dir)
-{
-	unsigned long flags;
-    /* We need to do the right thing here */
-}
-
-/*
- * Initialize new page directory with pointers to invalid ptes
- */
-static void pa20_pgd_init(unsigned long page)
-{
-	unsigned long dummy1, dummy2;
-
-}
-
-static void pa20_update_mmu_cache(struct vm_area_struct * vma,
-				   unsigned long address, pte_t pte)
-{
-	pa20_flush_tlb_page(vma, address);
-}
-
-static void pa20_show_regs(struct pt_regs * regs)
-{
-	/*
-	 * Saved main processor registers
-	 */
-	printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       0, (unsigned long) regs->regs[1], (unsigned long) regs->regs[2],
-	       (unsigned long) regs->regs[3], (unsigned long) regs->regs[4],
-	       (unsigned long) regs->regs[5], (unsigned long) regs->regs[6],
-	       (unsigned long) regs->regs[7]);
-	printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       (unsigned long) regs->regs[8], (unsigned long) regs->regs[9],
-	       (unsigned long) regs->regs[10], (unsigned long) regs->regs[11],
-               (unsigned long) regs->regs[12], (unsigned long) regs->regs[13],
-	       (unsigned long) regs->regs[14], (unsigned long) regs->regs[15]);
-	printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       (unsigned long) regs->regs[16], (unsigned long) regs->regs[17],
-	       (unsigned long) regs->regs[18], (unsigned long) regs->regs[19],
-               (unsigned long) regs->regs[20], (unsigned long) regs->regs[21],
-	       (unsigned long) regs->regs[22], (unsigned long) regs->regs[23]);
-	printk("$24: %08lx %08lx                   %08lx %08lx %08lx %08lx\n",
-	       (unsigned long) regs->regs[24], (unsigned long) regs->regs[25],
-	       (unsigned long) regs->regs[28], (unsigned long) regs->regs[29],
-               (unsigned long) regs->regs[30], (unsigned long) regs->regs[31]);
-
-	/*
-	 * Saved cp0 registers
-	 */
-	printk("epc  : %08lx    %s\nStatus: %08x\nCause : %08x\n",
-	       (unsigned long) regs->cp0_epc, print_tainted(),
-	       (unsigned int) regs->cp0_status,
-	       (unsigned int) regs->cp0_cause);
-}
-
-static int pa20_user_mode(struct pt_regs *regs)
-{
-       /* Return user mode stuff?? */
-}
-
-__initfunc(void ld_mmu_pa20(void))
-{
-
-    /* Taken directly from the MIPS arch..  Lots of bad things here */
-	clear_page = pa20_clear_page;
-	copy_page = pa20_copy_page;
-
-	flush_cache_all = pa20_flush_cache_all;
-	flush_cache_mm = pa20_flush_cache_mm;
-	flush_cache_range = pa20_flush_cache_range;
-	flush_cache_page = pa20_flush_cache_page;
-	flush_cache_sigtramp = pa20_flush_cache_sigtramp;
-	flush_page_to_ram = pa20_flush_page_to_ram;
-
-	flush_tlb_all = pa20_flush_tlb_all;
-	flush_tlb_mm = pa20_flush_tlb_mm;
-	flush_tlb_range = pa20_flush_tlb_range;
-	flush_tlb_page = pa20_flush_tlb_page;
-	pa20_asid_setup();
-
-	load_pgd = pa20_load_pgd;
-	pgd_init = pa20_pgd_init;
-	update_mmu_cache = pa20_update_mmu_cache;
-
-	show_regs = pa20_show_regs;
-    
-        add_wired_entry = pa20_add_wired_entry;
-
-	user_mode = pa20_user_mode;
-	flush_tlb_all();
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/tools/Makefile linux-2.4.20/arch/parisc/tools/Makefile
--- linux-2.4.19/arch/parisc/tools/Makefile	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/tools/Makefile	2002-10-29 11:18:50.000000000 +0000
@@ -22,7 +22,4 @@
 
 offset.s: offset.c
 
-clean:
-	rm -f offset.[hs] $(TARGET).new
-
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/tools/offset.c linux-2.4.20/arch/parisc/tools/offset.c
--- linux-2.4.19/arch/parisc/tools/offset.c	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/arch/parisc/tools/offset.c	2002-10-29 11:18:31.000000000 +0000
@@ -13,6 +13,13 @@
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 #include <asm/hardirq.h>
+#include <asm/pdc.h>
+
+#ifdef __LP64__
+#define FRAME_SIZE	128
+#else
+#define FRAME_SIZE	64
+#endif
 
 #define text(t) __asm__("\n@@@" t)
 #define _offset(type, member) (&(((type *)NULL)->member))
@@ -21,7 +28,7 @@
 	__asm__("\n@@@" string "%0" : : "i" (_offset(ptr, member)))
 #define size(string, size) \
 	__asm__("\n@@@" string "%0" : : "i" (sizeof(size)))
-#define align(x,y) (((x)+(2*(y))-1)-(((x)+(y)-1)%(y)))
+#define align(x,y) (((x)+FRAME_SIZE+(y)-1)-(((x)+(y)-1)%(y)))
 #define size_align(string, size, algn) \
 	__asm__("\n@@@" string "%0" : : "i" \
 		align(sizeof(size),algn))
@@ -32,6 +39,15 @@
 text("#ifndef _PARISC_OFFSET_H");
 text("#define _PARISC_OFFSET_H");
 linefeed;
+#ifdef __LP64__
+text("#ifndef __LP64__");
+text("#error offset.h was generated for 64-bit build; did you do 'make dep'?");
+#else
+text("#ifdef __LP64__");
+text("#error offset.h was generated for 32-bit build; did you do 'make dep'?");
+#endif
+text("#endif");
+linefeed;
 
 void output_task_ptreg_defines(void)
 {
@@ -113,23 +129,14 @@
 	offset("#define TASK_PT_IASQ1   ", struct task_struct, thread.regs.iasq[1]);
 	offset("#define TASK_PT_IAOQ0   ", struct task_struct, thread.regs.iaoq[0]);
 	offset("#define TASK_PT_IAOQ1   ", struct task_struct, thread.regs.iaoq[1]);
-	offset("#define TASK_PT_CR24    ", struct task_struct, thread.regs.cr24);
-	offset("#define TASK_PT_CR25    ", struct task_struct, thread.regs.cr25);
-	offset("#define TASK_PT_CR26    ", struct task_struct, thread.regs.cr26);
 	offset("#define TASK_PT_CR27    ", struct task_struct, thread.regs.cr27);
-	offset("#define TASK_PT_CR30    ", struct task_struct, thread.regs.cr30);
 	offset("#define TASK_PT_ORIG_R28 ", struct task_struct, thread.regs.orig_r28);
 	offset("#define TASK_PT_KSP     ", struct task_struct, thread.regs.ksp);
 	offset("#define TASK_PT_KPC     ", struct task_struct, thread.regs.kpc);
 	offset("#define TASK_PT_SAR     ", struct task_struct, thread.regs.sar);
-	offset("#define TASK_PT_CR11    ", struct task_struct, thread.regs.sar);
 	offset("#define TASK_PT_IIR     ", struct task_struct, thread.regs.iir);
 	offset("#define TASK_PT_ISR     ", struct task_struct, thread.regs.isr);
 	offset("#define TASK_PT_IOR     ", struct task_struct, thread.regs.ior);
-	offset("#define TASK_PT_CR_PID0 ", struct task_struct, thread.regs.cr_pid[0]);
-	offset("#define TASK_PT_CR_PID1 ", struct task_struct, thread.regs.cr_pid[1]);
-	offset("#define TASK_PT_CR_PID2 ", struct task_struct, thread.regs.cr_pid[2]);
-	offset("#define TASK_PT_CR_PID3 ", struct task_struct, thread.regs.cr_pid[3]);
 	size("#define TASK_SZ      ", struct task_struct);
 	size_align("#define TASK_SZ_ALGN  ", struct task_struct, 64);
 	linefeed;
@@ -214,23 +221,14 @@
 	offset("#define PT_IASQ1   ", struct pt_regs, iasq[1]);
 	offset("#define PT_IAOQ0   ", struct pt_regs, iaoq[0]);
 	offset("#define PT_IAOQ1   ", struct pt_regs, iaoq[1]);
-	offset("#define PT_CR24    ", struct pt_regs, cr24);
-	offset("#define PT_CR25    ", struct pt_regs, cr25);
-	offset("#define PT_CR26    ", struct pt_regs, cr26);
 	offset("#define PT_CR27    ", struct pt_regs, cr27);
-	offset("#define PT_CR30    ", struct pt_regs, cr30);
 	offset("#define PT_ORIG_R28 ", struct pt_regs, orig_r28);
 	offset("#define PT_KSP     ", struct pt_regs, ksp);
 	offset("#define PT_KPC     ", struct pt_regs, kpc);
 	offset("#define PT_SAR     ", struct pt_regs, sar);
-	offset("#define PT_CR11    ", struct pt_regs, sar);
 	offset("#define PT_IIR     ", struct pt_regs, iir);
 	offset("#define PT_ISR     ", struct pt_regs, isr);
 	offset("#define PT_IOR     ", struct pt_regs, ior);
-	offset("#define PT_CR_PID0 ", struct pt_regs, cr_pid[0]);
-	offset("#define PT_CR_PID1 ", struct pt_regs, cr_pid[1]);
-	offset("#define PT_CR_PID2 ", struct pt_regs, cr_pid[2]);
-	offset("#define PT_CR_PID3 ", struct pt_regs, cr_pid[3]);
 	size("#define PT_SIZE    ", struct pt_regs);
 	size_align("#define PT_SZ_ALGN  ", struct pt_regs, 64);
 	linefeed;
@@ -249,6 +247,7 @@
 	offset("#define TASK_NICE          ", struct task_struct, nice);
 	offset("#define TASK_MM            ", struct task_struct, mm);
 	offset("#define TASK_PROCESSOR     ", struct task_struct, processor);
+	offset("#define TASK_PERSONALITY   ", struct task_struct, personality);
 	size  ("#define TASK_SZ          ", struct task_struct);
 	size_align("#define TASK_SZ_ALGN       ", struct task_struct, 64);
 	linefeed;
@@ -257,12 +256,39 @@
 void output_irq_stat_defines(void)
 {
 	text("/* PARISC irq_cpustat_t offsets. */");
-	offset("#define IRQSTAT_SI_ACTIVE  ", irq_cpustat_t, __softirq_active);
-	offset("#define IRQSTAT_SI_MASK    ", irq_cpustat_t, __softirq_mask);
+	offset("#define IRQSTAT_SIRQ_PEND  ", irq_cpustat_t, __softirq_pending);
 	size  ("#define IRQSTAT_SZ         ", irq_cpustat_t);
 	linefeed;
 }
 
+void output_cache_info_defines(void)
+{
+	text("/* PARISC pdc_cache_info offsets. */");
+	offset("#define ICACHE_BASE      ", struct pdc_cache_info, ic_base);
+	offset("#define ICACHE_STRIDE    ", struct pdc_cache_info, ic_stride);
+	offset("#define ICACHE_COUNT     ", struct pdc_cache_info, ic_count);
+	offset("#define ICACHE_LOOP      ", struct pdc_cache_info, ic_loop);
+	offset("#define DCACHE_BASE      ", struct pdc_cache_info, dc_base);
+	offset("#define DCACHE_STRIDE    ", struct pdc_cache_info, dc_stride);
+	offset("#define DCACHE_COUNT     ", struct pdc_cache_info, dc_count);
+	offset("#define DCACHE_LOOP      ", struct pdc_cache_info, dc_loop);
+	offset("#define ITLB_SID_BASE    ", struct pdc_cache_info, it_sp_base);
+	offset("#define ITLB_SID_STRIDE  ", struct pdc_cache_info, it_sp_stride);
+	offset("#define ITLB_SID_COUNT   ", struct pdc_cache_info, it_sp_count);
+	offset("#define ITLB_OFF_BASE    ", struct pdc_cache_info, it_off_base);
+	offset("#define ITLB_OFF_STRIDE  ", struct pdc_cache_info, it_off_stride);
+	offset("#define ITLB_OFF_COUNT   ", struct pdc_cache_info, it_off_count);
+	offset("#define ITLB_LOOP        ", struct pdc_cache_info, it_loop);
+	offset("#define DTLB_SID_BASE    ", struct pdc_cache_info, dt_sp_base);
+	offset("#define DTLB_SID_STRIDE  ", struct pdc_cache_info, dt_sp_stride);
+	offset("#define DTLB_SID_COUNT   ", struct pdc_cache_info, dt_sp_count);
+	offset("#define DTLB_OFF_BASE    ", struct pdc_cache_info, dt_off_base);
+	offset("#define DTLB_OFF_STRIDE  ", struct pdc_cache_info, dt_off_stride);
+	offset("#define DTLB_OFF_COUNT   ", struct pdc_cache_info, dt_off_count);
+	offset("#define DTLB_LOOP        ", struct pdc_cache_info, dt_loop);
+	linefeed;
+}
+
 #ifdef PRUMPF_HAD_MORE_TIME
 void output_thread_defines(void)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/vmlinux.lds linux-2.4.20/arch/parisc/vmlinux.lds
--- linux-2.4.19/arch/parisc/vmlinux.lds	2001-07-02 21:40:58.000000000 +0000
+++ linux-2.4.20/arch/parisc/vmlinux.lds	2002-10-29 11:18:34.000000000 +0000
@@ -1,21 +1,14 @@
 /* ld script to make hppa Linux kernel */
-OUTPUT_FORMAT("elf32-hppa")
 OUTPUT_ARCH(hppa)
 ENTRY(_stext)
 SECTIONS
 {
 
-/* right now use 0x10000/0x11000, later when we don't use Console and
- * Boot-Device IODC, we will change this to 0x8000 !!!
- */
-
-  . = 0xc0100000;   
-/*	. = 0x10000;  */
+  . = 0x10100000;
 
   _text = .;			/* Text and read-only data */
   .text BLOCK(16) : {
 	*(.text*)
-	*(.PARISC.unwind)
 	*(.fixup)
 	*(.lock.text)		/* out-of-line lock text */
 	*(.gnu.warning)
@@ -57,12 +50,14 @@
 
 
   init_task BLOCK(16384) : { *(init_task) }  /* The initial task and kernel stack */
+  init_istack BLOCK(32768) : { *(init_istack) }  /* The initial interrupt stack */
 
   _edata = .;			/* End of data section */
 
 
   .bss : { *(.bss) *(COMMON) }		/* BSS */
 
+  .PARISC.unwind : { *(.PARISC.unwind) }
 
   _end = . ;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/parisc/vmlinux64.lds linux-2.4.20/arch/parisc/vmlinux64.lds
--- linux-2.4.19/arch/parisc/vmlinux64.lds	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/parisc/vmlinux64.lds	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,76 @@
+/* ld script to make hppa Linux kernel */
+OUTPUT_ARCH(hppa:hppa2.0w)
+ENTRY(_stext)
+SECTIONS
+{
+
+  . = 0x10100000;
+
+  _text = .;			/* Text and read-only data */
+  .text BLOCK(16) : {
+	*(.text*)
+	*(.PARISC.unwind)
+	*(.fixup)
+	*(.lock.text)		/* out-of-line lock text */
+	*(.gnu.warning)
+	} = 0
+
+  . = ALIGN(16);
+  .rodata : { *(.rodata) }
+  .kstrtab : { *(.kstrtab) }
+
+  _etext = .;			/* End of text section */
+  
+  .data BLOCK(8192) : {			/* Data without special */
+	data_start = .;
+	*(.data)
+	}
+
+  . = ALIGN(16);		/* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___ksymtab = .;	/* Kernel symbol table */
+  __ksymtab : { *(__ksymtab) }
+  __stop___ksymtab = .;
+
+  . = ALIGN(16);		/* Linkage tables */
+  .opd : { *(.opd) } PROVIDE (__gp = .); .plt : { *(.plt) } .dlt : { *(.dlt) }
+
+  . = ALIGN(16384);
+  __init_begin = .;
+  .init.text : { *(.init.text) }
+  .init.data : { *(.init.data) }
+  . = ALIGN(16);
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;
+  .initcall.init : { *(.initcall.init) } 
+  __initcall_end = .;
+  __init_end = .;
+
+
+  init_task BLOCK(16384) : { *(init_task) }  /* The initial task and kernel stack */
+  init_istack BLOCK(32768) : { *(init_task) }  /* The initial interrupt stack */
+
+  _edata = .;			/* End of data section */
+
+
+  .bss : { *(.bss) *(COMMON) }		/* BSS */
+
+
+  _end = . ;
+
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  .note 0 : { *(.note) }	
+	
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/8260_io/Config.in linux-2.4.20/arch/ppc/8260_io/Config.in
--- linux-2.4.19/arch/ppc/8260_io/Config.in	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/8260_io/Config.in	2002-10-29 11:18:32.000000000 +0000
@@ -2,7 +2,7 @@
 # MPC8260 Communication options
 #
 mainmenu_option next_comment
-comment 'MPC8260 Communication Options'
+comment 'MPC8260 CPM Options'
 bool 'Enable SCC Console' CONFIG_SCC_CONSOLE
 if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
   bool 'CPM SCC Ethernet' CONFIG_SCC_ENET
@@ -23,4 +23,7 @@
     bool 'Ethernet on FCC3' CONFIG_FCC3_ENET
   fi
 fi
+
+comment 'Generic MPC8260 Options'
+bool 'Disable data cache' CONFIG_DCACHE_DISABLE
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/8xx_io/fec.c linux-2.4.20/arch/ppc/8xx_io/fec.c
--- linux-2.4.19/arch/ppc/8xx_io/fec.c	2001-10-17 21:37:01.000000000 +0000
+++ linux-2.4.20/arch/ppc/8xx_io/fec.c	2002-10-29 11:18:38.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.fec.c 1.20 10/11/01 11:55:47 trini
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx.
@@ -33,6 +33,8 @@
 #undef	CONFIG_FEC_LXT970
 #define	CONFIG_FEC_LXT971
 #undef	CONFIG_FEC_QS6612
+#undef	CONFIG_FEC_DP83843
+#undef	CONFIG_FEC_DP83846A
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -50,9 +52,8 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
-#ifdef CONFIG_FEC_PACKETHOOK
-#include <linux/pkthook.h>
-#endif
+#include <linux/mii.h>
+#include <linux/ethtool.h>
 
 #include <asm/8xx_immap.h>
 #include <asm/pgtable.h>
@@ -68,7 +69,7 @@
 
 typedef struct {
 	uint mii_data;
-	void (*funct)(uint mii_reg, struct net_device *dev);
+	void (*funct)(uint mii_reg, struct net_device *dev, uint data);
 } phy_cmd_t;
 
 typedef struct {
@@ -179,20 +180,14 @@
 	uint	sequence_done;
 
 	uint	phy_addr;
+
+	struct timer_list phy_timer_list;
+	u16 old_status;
 #endif	/* CONFIG_USE_MDIO */
 
 	int	link;
 	int	old_link;
 	int	full_duplex;
-
-#ifdef CONFIG_FEC_PACKETHOOK
-	unsigned long	ph_lock;
-	fec_ph_func	*ph_rxhandler;
-	fec_ph_func	*ph_txhandler;
-	__u16		ph_proto;
-	volatile __u32	*ph_regaddr;
-	void 		*ph_priv;
-#endif
 };
 
 static int fec_enet_open(struct net_device *dev);
@@ -201,13 +196,8 @@
 static void fec_enet_mii(struct net_device *dev);
 #endif	/* CONFIG_USE_MDIO */
 static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs);
-#ifdef CONFIG_FEC_PACKETHOOK
-static void  fec_enet_tx(struct net_device *dev, __u32 regval);
-static void  fec_enet_rx(struct net_device *dev, __u32 regval);
-#else
 static void  fec_enet_tx(struct net_device *dev);
 static void  fec_enet_rx(struct net_device *dev);
-#endif
 static int fec_enet_close(struct net_device *dev);
 static struct net_device_stats *fec_enet_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
@@ -216,14 +206,25 @@
 static	ushort	my_enet_addr[3];
 
 #ifdef	CONFIG_USE_MDIO
+static int fec_enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr);
+
+static void mdio_callback(uint regval, struct net_device *dev, uint data);
+static int mdio_read(struct net_device *dev, int phy_id, int location);
+
+#if defined(CONFIG_FEC_DP83846A)
+static void mdio_timer_callback(unsigned long data);
+#endif /* CONFIG_FEC_DP83846A */
+
 /* MII processing.  We keep this as simple as possible.  Requests are
  * placed on the list (if there is room).  When the request is finished
  * by the MII, an optional function may be called.
  */
 typedef struct mii_list {
 	uint	mii_regval;
-	void	(*mii_func)(uint val, struct net_device *dev);
+	void	(*mii_func)(uint val, struct net_device *dev, uint data);
 	struct	mii_list *mii_next;
+	uint	mii_data;
 } mii_list_t;
 
 #define		NMII	20
@@ -232,8 +233,14 @@
 mii_list_t	*mii_head;
 mii_list_t	*mii_tail;
 
+typedef struct mdio_read_data {
+	u16 regval;
+	struct task_struct *sleeping_task;
+} mdio_read_data_t;
+
 static int	mii_queue(struct net_device *dev, int request,
-				void (*func)(uint, struct net_device *));
+				void (*func)(uint, struct net_device *, uint), uint data);
+static void mii_queue_relink(uint mii_reg, struct net_device *dev, uint data);
 
 /* Make MII read/write commands for the FEC.
 */
@@ -281,65 +288,6 @@
 #define PHY_STAT_100FDX	0x8000  /* 100 Mbit full duplex selected */
 #endif	/* CONFIG_USE_MDIO */
 
-#ifdef CONFIG_FEC_PACKETHOOK
-int
-fec_register_ph(struct net_device *dev, fec_ph_func *rxfun, fec_ph_func *txfun,
-		__u16 proto, volatile __u32 *regaddr, void *priv)
-{
-	struct fec_enet_private *fep;
-	int retval = 0;
-
-	fep = dev->priv;
-
-	if (test_and_set_bit(0, (void*)&fep->ph_lock) != 0) {
-		/* Someone is messing with the packet hook */
-		return -EAGAIN;
-	}
-	if (fep->ph_rxhandler != NULL || fep->ph_txhandler != NULL) {
-		retval = -EBUSY;
-		goto out;
-	}
-	fep->ph_rxhandler = rxfun;
-	fep->ph_txhandler = txfun;
-	fep->ph_proto = proto;
-	fep->ph_regaddr = regaddr;
-	fep->ph_priv = priv;
-
-	out:
-	fep->ph_lock = 0;
-
-	return retval;
-}
-
-
-int
-fec_unregister_ph(struct net_device *dev)
-{
-	struct fec_enet_private *fep;
-	int retval = 0;
-
-	fep = dev->priv;
-
-	if (test_and_set_bit(0, (void*)&fep->ph_lock) != 0) {
-		/* Someone is messing with the packet hook */
-		return -EAGAIN;
-	}
-
-	fep->ph_rxhandler = fep->ph_txhandler = NULL;
-	fep->ph_proto = 0;
-	fep->ph_regaddr = NULL;
-	fep->ph_priv = NULL;
-
-	fep->ph_lock = 0;
-
-	return retval;
-}
-
-EXPORT_SYMBOL(fec_register_ph);
-EXPORT_SYMBOL(fec_unregister_ph);
-
-#endif /* CONFIG_FEC_PACKETHOOK */
-
 static int
 fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
@@ -477,12 +425,6 @@
 	struct	net_device *dev = dev_id;
 	volatile fec_t	*fecp;
 	uint	int_events;
-#ifdef CONFIG_FEC_PACKETHOOK
-	struct	fec_enet_private *fep = dev->priv;
-	__u32 regval;
-
-	if (fep->ph_regaddr) regval = *fep->ph_regaddr;
-#endif
 	fecp = (volatile fec_t*)dev->base_addr;
 
 	/* Get the interrupt events that caused us to be here.
@@ -496,25 +438,15 @@
 
 		/* Handle receive event in its own function.
 		 */
-		if (int_events & FEC_ENET_RXF) {
-#ifdef CONFIG_FEC_PACKETHOOK
-			fec_enet_rx(dev, regval);
-#else
+		if (int_events & FEC_ENET_RXF)
 			fec_enet_rx(dev);
-#endif
-		}
 
 		/* Transmit OK, or non-fatal error. Update the buffer
 		   descriptors. FEC handles all errors, we just discover
 		   them as part of the transmit process.
 		*/
-		if (int_events & FEC_ENET_TXF) {
-#ifdef CONFIG_FEC_PACKETHOOK
-			fec_enet_tx(dev, regval);
-#else
+		if (int_events & FEC_ENET_TXF)
 			fec_enet_tx(dev);
-#endif
-		}
 
 		if (int_events & FEC_ENET_MII) {
 #ifdef	CONFIG_USE_MDIO
@@ -529,11 +461,7 @@
 
 
 static void
-#ifdef CONFIG_FEC_PACKETHOOK
-fec_enet_tx(struct net_device *dev, __u32 regval)
-#else
 fec_enet_tx(struct net_device *dev)
-#endif
 {
 	struct	fec_enet_private *fep;
 	volatile cbd_t	*bdp;
@@ -562,18 +490,8 @@
 				fep->stats.tx_fifo_errors++;
 			if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */
 				fep->stats.tx_carrier_errors++;
-		} else {
-#ifdef CONFIG_FEC_PACKETHOOK
-			/* Packet hook ... */
-			if (fep->ph_txhandler &&
-			    ((struct ethhdr *)skb->data)->h_proto
-			    == fep->ph_proto) {
-				fep->ph_txhandler((__u8*)skb->data, skb->len,
-						  regval, fep->ph_priv);
-			}
-#endif
+		} else
 			fep->stats.tx_packets++;
-		}
 
 #ifndef final_version
 		if (bdp->cbd_sc & BD_ENET_TX_READY)
@@ -609,11 +527,6 @@
 			if (netif_queue_stopped(dev))
 				netif_wake_queue(dev);
 		}
-#ifdef CONFIG_FEC_PACKETHOOK
-		/* Re-read register. Not exactly guaranteed to be correct,
-		   but... */
-		if (fep->ph_regaddr) regval = *fep->ph_regaddr;
-#endif
 	}
 	fep->dirty_tx = (cbd_t *)bdp;
 	spin_unlock(&fep->lock);
@@ -626,11 +539,7 @@
  * effectively tossing the packet.
  */
 static void
-#ifdef CONFIG_FEC_PACKETHOOK
-fec_enet_rx(struct net_device *dev, __u32 regval)
-#else
 fec_enet_rx(struct net_device *dev)
-#endif
 {
 	struct	fec_enet_private *fep;
 	volatile fec_t	*fecp;
@@ -690,27 +599,6 @@
 	fep->stats.rx_bytes += pkt_len;
 	data = (__u8*)__va(bdp->cbd_bufaddr);
 
-#ifdef CONFIG_FEC_PACKETHOOK
-	/* Packet hook ... */
-	if (fep->ph_rxhandler) {
-		if (((struct ethhdr *)data)->h_proto == fep->ph_proto) {
-			switch (fep->ph_rxhandler(data, pkt_len, regval,
-						  fep->ph_priv)) {
-			case 1:
-				goto rx_processing_done;
-				break;
-			case 0:
-				break;
-			default:
-				fep->stats.rx_errors++;
-				goto rx_processing_done;
-			}
-		}
-	}
-
-	/* If it wasn't filtered - copy it to an sk buffer. */
-#endif
-
 	/* This does 16 byte alignment, exactly what we need.
 	 * The packet length includes FCS, but we don't want to
 	 * include that when passing upstream as it messes up
@@ -754,11 +642,6 @@
 	 */
 	fecp->fec_r_des_active = 0x01000000;
 #endif
-#ifdef CONFIG_FEC_PACKETHOOK
-	/* Re-read register. Not exactly guaranteed to be correct,
-	   but... */
-	if (fep->ph_regaddr) regval = *fep->ph_regaddr;
-#endif
    } /* while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) */
 	fep->cur_rx = (cbd_t *)bdp;
 
@@ -794,7 +677,7 @@
 	}
 
 	if (mip->mii_func != NULL)
-		(*(mip->mii_func))(mii_reg, dev);
+		(*(mip->mii_func))(mii_reg, dev, mip->mii_data);
 
 	mii_head = mip->mii_next;
 	mip->mii_next = mii_free;
@@ -806,7 +689,7 @@
 }
 
 static int
-mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *))
+mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *, uint), uint data)
 {
 	struct fec_enet_private *fep;
 	unsigned long	flags;
@@ -828,6 +711,7 @@
 		mip->mii_regval = regval;
 		mip->mii_func = func;
 		mip->mii_next = NULL;
+		mip->mii_data = data;
 		if (mii_head) {
 			mii_tail->mii_next = mip;
 			mii_tail = mip;
@@ -852,10 +736,10 @@
 		return;
 
 	for(k = 0; (c+k)->mii_data != mk_mii_end; k++)
-		mii_queue(dev, (c+k)->mii_data, (c+k)->funct);
+		mii_queue(dev, (c+k)->mii_data, (c+k)->funct, 0);
 }
 
-static void mii_parse_sr(uint mii_reg, struct net_device *dev)
+static void mii_parse_sr(uint mii_reg, struct net_device *dev, uint data)
 {
 	struct fec_enet_private *fep = dev->priv;
 	volatile uint *s = &(fep->phy_status);
@@ -872,7 +756,7 @@
 	fep->link = (*s & PHY_STAT_LINK) ? 1 : 0;
 }
 
-static void mii_parse_cr(uint mii_reg, struct net_device *dev)
+static void mii_parse_cr(uint mii_reg, struct net_device *dev, uint data)
 {
 	struct fec_enet_private *fep = dev->priv;
 	volatile uint *s = &(fep->phy_status);
@@ -885,7 +769,7 @@
 		*s |= PHY_CONF_LOOP;
 }
 
-static void mii_parse_anar(uint mii_reg, struct net_device *dev)
+static void mii_parse_anar(uint mii_reg, struct net_device *dev, uint data)
 {
 	struct fec_enet_private *fep = dev->priv;
 	volatile uint *s = &(fep->phy_status);
@@ -919,7 +803,7 @@
 #define MII_LXT970_CONFIG    19  /* Configuration Register    */
 #define MII_LXT970_CSR       20  /* Chip Status Register      */
 
-static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev)
+static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev, uint data)
 {
 	struct fec_enet_private *fep = dev->priv;
 	volatile uint *s = &(fep->phy_status);
@@ -1001,7 +885,7 @@
  * weird, so 2.5 MHz ought to be enough for anyone...
  */
 
-static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev)
+static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev, uint data)
 {
 	struct fec_enet_private *fep = dev->priv;
 	volatile uint *s = &(fep->phy_status);
@@ -1079,7 +963,7 @@
 #define MII_QS6612_IMR       30  /* Interrupt Mask Register    */
 #define MII_QS6612_PCR       31  /* 100BaseTx PHY Control Reg. */
 
-static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev)
+static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev, uint data)
 {
 	struct fec_enet_private *fep = dev->priv;
 	volatile uint *s = &(fep->phy_status);
@@ -1141,6 +1025,144 @@
 #endif /* CONFIG_FEC_QS6612 */
 
 
+/* -------------------------------------------------------------------- */
+/* The National Semiconductor DP83843BVJE is used on a Mediatrix board  */
+/* -------------------------------------------------------------------- */
+
+#ifdef CONFIG_FEC_DP83843
+
+/* Register definitions */
+#define MII_DP83843_PHYSTS 0x10  /* PHY Status Register */
+#define MII_DP83843_MIPSCR 0x11  /* Specific Status Register */
+#define MII_DP83843_MIPGSR 0x12  /* Generic Status Register */
+
+static void mii_parse_dp83843_physts(uint mii_reg, struct net_device *dev, uint data)
+{
+	struct fec_enet_private *fep = dev->priv;
+	volatile uint *s = &(fep->phy_status);
+
+	*s &= ~(PHY_STAT_SPMASK);
+
+	if (mii_reg & 0x0002)
+	{
+		if (mii_reg & 0x0004)
+			*s |= PHY_STAT_10FDX;
+		else
+			*s |= PHY_STAT_10HDX;
+	}
+	else
+	{
+		if (mii_reg & 0x0004)
+			*s |= PHY_STAT_100FDX;
+		else
+			*s |= PHY_STAT_100HDX;
+	}
+}
+
+static phy_info_t phy_info_dp83843 = {
+	0x020005c1,
+	"DP83843BVJE",
+
+	(const phy_cmd_t []) {  /* config */  
+		{ mk_mii_write(MII_REG_ANAR, 0x01E1), NULL  }, /* Auto-Negociation Register Control set to    */
+		                                               /* auto-negociate 10/100MBps, Half/Full duplex */
+		{ mk_mii_read(MII_REG_CR),   mii_parse_cr   },
+		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) {  /* startup */
+		{ mk_mii_write(MII_DP83843_MIPSCR, 0x0002), NULL }, /* Enable interrupts */
+		{ mk_mii_write(MII_REG_CR, 0x1200), NULL         }, /* Enable and Restart Auto-Negotiation */
+		{ mk_mii_read(MII_REG_SR), mii_parse_sr	         },
+		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
+		{ mk_mii_read(MII_DP83843_PHYSTS), mii_parse_dp83843_physts },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) { /* ack_int */
+		{ mk_mii_read(MII_DP83843_MIPGSR), NULL },  /* Acknowledge interrupts */
+		{ mk_mii_read(MII_REG_SR), mii_parse_sr },  /* Find out the current status */
+		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
+		{ mk_mii_read(MII_DP83843_PHYSTS), mii_parse_dp83843_physts },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) {  /* shutdown - disable interrupts */
+		{ mk_mii_end, }
+	}
+};
+
+#endif /* CONFIG_FEC_DP83843 */
+
+
+/* ----------------------------------------------------------------- */
+/* The National Semiconductor DP83846A is used on a Mediatrix board  */
+/* ----------------------------------------------------------------- */
+
+#ifdef CONFIG_FEC_DP83846A
+
+/* Register definitions */
+#define MII_DP83846A_PHYSTS 0x10  /* PHY Status Register */
+
+static void mii_parse_dp83846a_physts(uint mii_reg, struct net_device *dev, uint data)
+{
+	struct fec_enet_private *fep = (struct fec_enet_private *)dev->priv;
+	volatile uint *s = &(fep->phy_status);
+	int link_change_mask;
+
+	*s &= ~(PHY_STAT_SPMASK);
+
+	if (mii_reg & 0x0002) {
+		if (mii_reg & 0x0004)
+			*s |= PHY_STAT_10FDX;
+		else
+			*s |= PHY_STAT_10HDX;
+	}
+	else {
+		if (mii_reg & 0x0004)
+			*s |= PHY_STAT_100FDX;
+		else
+			*s |= PHY_STAT_100HDX;
+	}
+
+	link_change_mask = PHY_STAT_LINK | PHY_STAT_10FDX | PHY_STAT_10HDX | PHY_STAT_100FDX | PHY_STAT_100HDX;
+	if(fep->old_status != (link_change_mask & *s))
+	{
+		fep->old_status = (link_change_mask & *s);
+		mii_queue_relink(mii_reg, dev, 0);
+	}
+}
+
+static phy_info_t phy_info_dp83846a = {
+	0x020005c2,
+	"DP83846A",
+
+	(const phy_cmd_t []) {  /* config */  
+		{ mk_mii_write(MII_REG_ANAR, 0x01E1), NULL  }, /* Auto-Negociation Register Control set to    */
+		                                               /* auto-negociate 10/100MBps, Half/Full duplex */
+		{ mk_mii_read(MII_REG_CR),   mii_parse_cr   },
+		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) {  /* startup */
+		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* Enable and Restart Auto-Negotiation */
+		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
+		{ mk_mii_read(MII_REG_CR), mii_parse_cr   },
+		{ mk_mii_read(MII_DP83846A_PHYSTS), mii_parse_dp83846a_physts },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) { /* ack_int */
+		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
+		{ mk_mii_read(MII_REG_CR), mii_parse_cr   },
+		{ mk_mii_read(MII_DP83846A_PHYSTS), mii_parse_dp83846a_physts },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) {  /* shutdown - disable interrupts */
+		{ mk_mii_end, }
+	}
+};
+
+#endif /* CONFIG_FEC_DP83846A */
+
+
 static phy_info_t *phy_info[] = {
 
 #ifdef CONFIG_FEC_LXT970
@@ -1155,6 +1177,14 @@
 	&phy_info_qs6612,
 #endif /* CONFIG_FEC_LXT971 */
 
+#ifdef CONFIG_FEC_DP83843
+	&phy_info_dp83843,
+#endif /* CONFIG_FEC_DP83843 */
+
+#ifdef CONFIG_FEC_DP83846A
+	&phy_info_dp83846a,
+#endif /* CONFIG_FEC_DP83846A */
+
 	NULL
 };
 
@@ -1250,7 +1280,7 @@
 
 }
 
-static void mii_queue_relink(uint mii_reg, struct net_device *dev)
+static void mii_queue_relink(uint mii_reg, struct net_device *dev, uint data)
 {
 	struct fec_enet_private *fep = dev->priv;
 
@@ -1259,7 +1289,7 @@
 	schedule_task(&fep->phy_task);
 }
 
-static void mii_queue_config(uint mii_reg, struct net_device *dev)
+static void mii_queue_config(uint mii_reg, struct net_device *dev, uint data)
 {
 	struct fec_enet_private *fep = dev->priv;
 
@@ -1280,7 +1310,7 @@
 /* Read remainder of PHY ID.
 */
 static void
-mii_discover_phy3(uint mii_reg, struct net_device *dev)
+mii_discover_phy3(uint mii_reg, struct net_device *dev, uint data)
 {
 	struct fec_enet_private *fep;
 	int	i;
@@ -1307,7 +1337,7 @@
  * with a valid ID.  This usually happens quickly.
  */
 static void
-mii_discover_phy(uint mii_reg, struct net_device *dev)
+mii_discover_phy(uint mii_reg, struct net_device *dev, uint data)
 {
 	struct fec_enet_private *fep;
 	uint	phytype;
@@ -1319,12 +1349,12 @@
 		/* Got first part of ID, now get remainder.
 		*/
 		fep->phy_id = phytype << 16;
-		mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), mii_discover_phy3);
+		mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), mii_discover_phy3, 0);
 	} else {
 		fep->phy_addr++;
 		if (fep->phy_addr < 32) {
 			mii_queue(dev, mk_mii_read(MII_REG_PHYIR1),
-							mii_discover_phy);
+							mii_discover_phy, 0);
 		} else {
 			printk("fec: No PHY device found.\n");
 		}
@@ -1387,13 +1417,40 @@
 	fep->link = 0;
 
 	if (fep->phy) {
-		mii_do_cmd(dev, fep->phy->ack_int);
 		mii_do_cmd(dev, fep->phy->config);
 		mii_do_cmd(dev, phy_cmd_config);  /* display configuration */
 		while(!fep->sequence_done)
 			schedule();
 
 		mii_do_cmd(dev, fep->phy->startup);
+
+#if defined(CONFIG_USE_MDIO) && defined(CONFIG_FEC_DP83846A)
+		if(fep->phy == &phy_info_dp83846a)
+		{
+			/* Initializing timers
+			 */
+			init_timer( &fep->phy_timer_list ); 
+
+			/* Starting timer for periodic link status check
+			 * After 100 milli-seconds, mdio_timer_callback function is called.
+			 */
+			fep->phy_timer_list.expires  = jiffies + (100 * HZ / 1000);
+			fep->phy_timer_list.data     = (unsigned long)dev;
+			fep->phy_timer_list.function = mdio_timer_callback;
+			add_timer( &fep->phy_timer_list );
+		}
+
+#if defined(CONFIG_IP_PNP)
+        printk("%s: Waiting for the link to be up...\n", dev->name);
+
+        while(fep->link == 0 || ((((volatile fec_t*)dev->base_addr)->fec_ecntrl & FEC_ECNTRL_ETHER_EN) == 0))
+        {
+            schedule();
+        }
+#endif /* CONFIG_IP_PNP */
+
+#endif /* CONFIG_USE_MDIO && CONFIG_FEC_DP83846A */
+
 		netif_start_queue(dev);
 		return 0;		/* Success */
 	}
@@ -1424,6 +1481,139 @@
 	return &fep->stats;
 }
 
+#ifdef CONFIG_USE_MDIO
+
+#if defined(CONFIG_FEC_DP83846A)
+/* Execute the ack_int command set and schedules next timer call back.  */
+static void mdio_timer_callback(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct fec_enet_private *fep = (struct fec_enet_private *)(dev->priv);
+	mii_do_cmd(dev, fep->phy->ack_int);
+
+	if(fep->link == 0)
+	{
+		fep->phy_timer_list.expires  = jiffies + (100 * HZ / 1000); /* Sleep for 100ms */
+	}
+	else
+	{
+		fep->phy_timer_list.expires  = jiffies + (1 * HZ); /* Sleep for 1 sec. */
+	}
+	add_timer( &fep->phy_timer_list ); 
+}
+#endif /* CONFIG_FEC_DP83846A */
+
+static void mdio_callback(uint regval, struct net_device *dev, uint data)
+{
+	mdio_read_data_t* mrd = (mdio_read_data_t *)data;
+	mrd->regval = 0xFFFF & regval;
+	wake_up_process(mrd->sleeping_task);
+}
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	uint retval;
+	mdio_read_data_t* mrd = (mdio_read_data_t *)kmalloc(sizeof(*mrd), GFP_KERNEL);
+
+	mrd->sleeping_task = current;
+	set_current_state(TASK_INTERRUPTIBLE);
+	mii_queue(dev, mk_mii_read(location), mdio_callback, (unsigned int) mrd);
+	schedule();
+
+	retval = mrd->regval;
+
+	kfree(mrd);
+
+	return retval;
+}
+
+void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+{
+	mii_queue(dev, mk_mii_write(location, value), NULL, 0);
+}
+
+static int fec_enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct fec_enet_private *cep = (struct fec_enet_private *)dev->priv;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
+
+	int phy = cep->phy_addr & 0x1f;
+	int retval;
+
+	if (data == NULL)
+	{
+		retval = -EINVAL;
+	}
+	else
+	{
+		switch(cmd)
+		{						
+		case SIOCETHTOOL:
+			return netdev_ethtool_ioctl(dev, (void*)rq->ifr_data);
+			break;
+
+		case SIOCGMIIPHY:			/* Get address of MII PHY in use. */
+		case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
+			data->phy_id = phy;
+
+		case SIOCGMIIREG:			/* Read MII PHY register.	*/
+		case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
+			data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
+			retval = 0;
+			break;
+
+		case SIOCSMIIREG:			/* Write MII PHY register.	*/
+		case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
+			if (!capable(CAP_NET_ADMIN))
+			{
+				retval = -EPERM;
+			}
+			else
+			{
+				mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
+				retval = 0;
+			}
+			break;
+
+		default:
+			retval = -EOPNOTSUPP;
+			break;
+		}		
+	}
+	return retval;
+}
+
+
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+
+	/* dev_ioctl() in ../../net/core/dev.c has already checked
+	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+
+	if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
+		return -EFAULT;
+
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO:
+		{
+			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+			strcpy (info.driver, dev->name);
+			strcpy (info.version, "0.2");
+			strcpy (info.bus_info, "");
+			if (copy_to_user (useraddr, &info, sizeof (info)))
+				return -EFAULT;
+			return 0;
+		}
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+#endif	/* CONFIG_USE_MDIO */
+
 /* Set or clear the multicast filter for this adaptor.
  * Skeleton taken from sunlance driver.
  * The CPM Ethernet implementation allows Multicast as well as individual
@@ -1624,16 +1814,7 @@
 	bdp--;
 	bdp->cbd_sc |= BD_SC_WRAP;
 
-#ifdef CONFIG_FEC_PACKETHOOK
-	fep->ph_lock = 0;
-	fep->ph_rxhandler = fep->ph_txhandler = NULL;
-	fep->ph_proto = 0;
-	fep->ph_regaddr = NULL;
-	fep->ph_priv = NULL;
-#endif
-
-	/* Install our interrupt handler.
-	*/
+	/* Install our interrupt handler. */
 	if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0)
 		panic("Could not allocate FEC IRQ!");
 
@@ -1672,6 +1853,8 @@
 	dev->set_multicast_list = set_multicast_list;
 
 #ifdef	CONFIG_USE_MDIO
+	dev->do_ioctl = fec_enet_ioctl;
+
 	for (i=0; i<NMII-1; i++)
 		mii_cmds[i].mii_next = &mii_cmds[i+1];
 	mii_free = mii_cmds;
@@ -1722,9 +1905,11 @@
 	 */
 	fep->phy_id_done = 0;
 	fep->phy_addr = 0;
-	mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy);
+	mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy, 0);
 #endif	/* CONFIG_USE_MDIO */
 
+	fep->old_status = 0;
+
 	return 0;
 }
 
@@ -1862,6 +2047,13 @@
 	*/
 	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
 	fecp->fec_r_des_active = 0x01000000;
+
+	/* The tx ring is no longer full. */
+	if(fep->tx_full)
+	{
+		fep->tx_full = 0;
+		netif_wake_queue(dev);
+	}
 }
 
 static void
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/Makefile linux-2.4.20/arch/ppc/Makefile
--- linux-2.4.19/arch/ppc/Makefile	2001-10-11 16:04:57.000000000 +0000
+++ linux-2.4.20/arch/ppc/Makefile	2002-10-29 11:18:32.000000000 +0000
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.Makefile 1.23 09/18/01 11:19:05 paulus
+# BK Id: %F% %I% %G% %U% %#%
 #
 # This file is included by the global makefile so that you can add your own
 # architecture-specific flags and dependencies. Remember to do have actions
@@ -21,16 +21,17 @@
 CHECKS		= checks
 endif
 
-ASFLAGS		=
 LINKFLAGS	= -T arch/ppc/vmlinux.lds -Ttext $(KERNELLOAD) -Bstatic
-CPPFLAGS	:= $(CPPFLAGS) -D__powerpc__
-CFLAGS		:= $(CFLAGS) -D__powerpc__ -fsigned-char \
+CPPFLAGS	:= $(CPPFLAGS) -I$(TOPDIR)/arch/$(ARCH)
+AFLAGS		:= $(AFLAGS) -I$(TOPDIR)/arch/$(ARCH)
+CFLAGS		:= $(CFLAGS) -I$(TOPDIR)/arch/$(ARCH) -fsigned-char \
 		-msoft-float -pipe -ffixed-r2 -Wno-uninitialized \
 		-mmultiple -mstring
+HOSTCFLAGS	+= -I$(TOPDIR)/arch/$(ARCH)
 CPP		= $(CC) -E $(CFLAGS)
 
 ifdef CONFIG_4xx
-CFLAGS := $(CFLAGS) -mcpu=403
+CFLAGS := $(CFLAGS) -Wa,-m405
 endif
 
 ifdef CONFIG_8xx
@@ -41,19 +42,25 @@
 CFLAGS := $(CFLAGS) -Wa,-mppc64bridge
 endif
 
+ifdef CONFIG_MORE_COMPILE_OPTIONS
+# Use sed to remove the quotes.
+  CFLAGS += $(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g')
+endif
+
 ifdef CONFIG_4xx
   HEAD := arch/ppc/kernel/head_4xx.o
 else
   ifdef CONFIG_8xx
     HEAD := arch/ppc/kernel/head_8xx.o
   else
-    HEAD := arch/ppc/kernel/head.o
+    HEAD := arch/ppc/kernel/head.o arch/ppc/kernel/idle_6xx.o
   endif
 endif
 
-ARCH_SUBDIRS = arch/ppc/kernel arch/ppc/mm arch/ppc/lib
+ARCH_SUBDIRS = arch/ppc/kernel arch/ppc/platforms arch/ppc/mm arch/ppc/lib
 SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS)
-CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES)
+CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/platforms/platform.o \
+	arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES)
 
 ifdef CONFIG_MATH_EMULATION
 SUBDIRS += arch/ppc/math-emu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/amiga/amiints.c linux-2.4.20/arch/ppc/amiga/amiints.c
--- linux-2.4.19/arch/ppc/amiga/amiints.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.20/arch/ppc/amiga/amiints.c	2002-10-29 11:18:33.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.amiints.c 1.8 05/21/01 00:48:24 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code
@@ -42,6 +42,8 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/kernel_stat.h>
 #include <linux/init.h>
 
@@ -63,9 +65,6 @@
 extern void cia_init_IRQ(struct ciabase *base);
 extern int cia_get_irq_list(struct ciabase *base, char *buf);
 
-/* irq node variables for amiga interrupt sources */
-static irq_node_t *ami_irq_list[AMI_STD_IRQS];
-
 unsigned short ami_intena_vals[AMI_STD_IRQS] = {
 	IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT,
 	IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_SOFT, IF_PORTS, IF_EXTER
@@ -78,7 +77,7 @@
 
 static void ami_badint(int irq, void *dev_id, struct pt_regs *fp)
 {
-	num_spurious += 1;
+/*	num_spurious += 1;*/
 }
 
 /*
@@ -97,25 +96,12 @@
 {
 	int i;
 
-	/* initialize handlers */
-	for (i = 0; i < AMI_STD_IRQS; i++) {
-		if (ami_servers[i]) {
-			ami_irq_list[i] = NULL;
-		} else {
-			ami_irq_list[i] = new_irq_node();
-			ami_irq_list[i]->handler = ami_badint;
-			ami_irq_list[i]->flags   = 0;
-			ami_irq_list[i]->dev_id  = NULL;
-			ami_irq_list[i]->devname = NULL;
-			ami_irq_list[i]->next    = NULL;
-		}
-	}
 	for (i = 0; i < AMI_IRQS; i++)
 		ami_ablecount[i] = 0;
 
 	/* turn off PCMCIA interrupts */
 	if (AMIGAHW_PRESENT(PCMCIA))
-		pcmcia_disable_irq();
+		gayle.inten = GAYLE_IRQ_IDE;
 
 	/* turn off all interrupts... */
 	custom.intena = 0x7fff;
@@ -138,152 +124,6 @@
 	cia_init_IRQ(&ciab_base);
 }
 
-static inline int amiga_insert_irq(irq_node_t **list, irq_node_t *node)
-{
-	unsigned long flags;
-	irq_node_t *cur;
-
-	if (!node->dev_id)
-		printk("%s: Warning: dev_id of %s is zero\n",
-		       __FUNCTION__, node->devname);
-
-	save_flags(flags);
-	cli();
-
-	cur = *list;
-
-	if (node->flags & SA_INTERRUPT) {
-		if (node->flags & SA_SHIRQ)
-			return -EBUSY;
-		/*
-		 * There should never be more than one
-		 */
-		while (cur && cur->flags & SA_INTERRUPT) {
-			list = &cur->next;
-			cur = cur->next;
-		}
-	} else {
-		while (cur) {
-			list = &cur->next;
-			cur = cur->next;
-		}
-	}
-
-	node->next = cur;
-	*list = node;
-
-	restore_flags(flags);
-	return 0;
-}
-
-static inline void amiga_delete_irq(irq_node_t **list, void *dev_id)
-{
-	unsigned long flags;
-	irq_node_t *node;
-
-	save_flags(flags);
-	cli();
-
-	for (node = *list; node; list = &node->next, node = *list) {
-		if (node->dev_id == dev_id) {
-			*list = node->next;
-			/* Mark it as free. */
-			node->handler = NULL;
-			restore_flags(flags);
-			return;
-		}
-	}
-	restore_flags(flags);
-	printk ("%s: tried to remove invalid irq\n", __FUNCTION__);
-}
-
-/*
- * amiga_request_irq : add an interrupt service routine for a particular
- *                     machine specific interrupt source.
- *                     If the addition was successful, it returns 0.
- */
-
-int amiga_request_irq(unsigned int irq,
-		      void (*handler)(int, void *, struct pt_regs *),
-                      unsigned long flags, const char *devname, void *dev_id)
-{
-	irq_node_t *node;
-	int error = 0;
-
-	if (irq >= AMI_IRQS) {
-		printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__,
-			irq, devname);
-		return -ENXIO;
-	}
-
-	if (irq >= IRQ_AMIGA_AUTO)
-		return sys_request_irq(irq - IRQ_AMIGA_AUTO, handler,
-		                       flags, devname, dev_id);
-
-	if (irq >= IRQ_AMIGA_CIAA)
-		return cia_request_irq(irq, handler, flags, devname, dev_id);
-
-	/*
-	 * IRQ_AMIGA_PORTS & IRQ_AMIGA_EXTER defaults to shared,
-	 * we could add a check here for the SA_SHIRQ flag but all drivers
-	 * should be aware of sharing anyway.
-	 */
-	if (ami_servers[irq]) {
-		if (!(node = new_irq_node()))
-			return -ENOMEM;
-		node->handler = handler;
-		node->flags   = flags;
-		node->dev_id  = dev_id;
-		node->devname = devname;
-		node->next    = NULL;
-		error = amiga_insert_irq(&ami_irq_list[irq], node);
-	} else {
-		ami_irq_list[irq]->handler = handler;
-		ami_irq_list[irq]->flags   = flags;
-		ami_irq_list[irq]->dev_id  = dev_id;
-		ami_irq_list[irq]->devname = devname;
-	}
-
-	/* enable the interrupt */
-	if (irq < IRQ_AMIGA_PORTS && !ami_ablecount[irq])
-		custom.intena = IF_SETCLR | ami_intena_vals[irq];
-
-	return error;
-}
-
-void amiga_free_irq(unsigned int irq, void *dev_id)
-{
-	if (irq >= AMI_IRQS) {
-		printk ("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
-		return;
-	}
-
-	if (irq >= IRQ_AMIGA_AUTO) {
-		sys_free_irq(irq - IRQ_AMIGA_AUTO, dev_id);
-		return;
-	}
-	if (irq >= IRQ_AMIGA_CIAA) {
-		cia_free_irq(irq, dev_id);
-		return;
-	}
-
-	if (ami_servers[irq]) {
-		amiga_delete_irq(&ami_irq_list[irq], dev_id);
-		/* if server list empty, disable the interrupt */
-		if (!ami_irq_list[irq] && irq < IRQ_AMIGA_PORTS)
-			custom.intena = ami_intena_vals[irq];
-	} else {
-		if (ami_irq_list[irq]->dev_id != dev_id)
-			printk("%s: removing probably wrong IRQ %d from %s\n",
-			       __FUNCTION__, irq, ami_irq_list[irq]->devname);
-		ami_irq_list[irq]->handler = ami_badint;
-		ami_irq_list[irq]->flags   = 0;
-		ami_irq_list[irq]->dev_id  = NULL;
-		ami_irq_list[irq]->devname = NULL;
-		custom.intena = ami_intena_vals[irq];
-	}
-}
-
 /*
  * Enable/disable a particular machine specific interrupt source.
  * Note that this may affect other interrupts in case of a shared interrupt.
@@ -350,20 +190,24 @@
 
 inline void amiga_do_irq(int irq, struct pt_regs *fp)
 {
-	kstat.irqs[0][SYS_IRQS + irq]++;
-	ami_irq_list[irq]->handler(irq, ami_irq_list[irq]->dev_id, fp);
+	irq_desc_t *desc = irq_desc + irq;
+	struct irqaction *action = desc->action;
+
+	kstat.irqs[0][irq]++;
+	action->handler(irq, action->dev_id, fp);
 }
 
 void amiga_do_irq_list(int irq, struct pt_regs *fp)
 {
-	irq_node_t *node;
+	irq_desc_t *desc = irq_desc + irq;
+	struct irqaction *action;
 
-	kstat.irqs[0][SYS_IRQS + irq]++;
+	kstat.irqs[0][irq]++;
 
 	custom.intreq = ami_intena_vals[irq];
 
-	for (node = ami_irq_list[irq]; node; node = node->next)
-		node->handler(irq, node->dev_id, fp);
+	for (action = desc->action; action; action = action->next)
+		action->handler(irq, action->dev_id, fp);
 }
 
 /*
@@ -469,9 +313,15 @@
 /* The PPC irq handling links all handlers requested on the same vector
    and executes them in a loop. Having ami_badint at the end of the chain
    is a bad idea. */
-void (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-	NULL, ami_int1, NULL, ami_int3,
-	ami_int4, ami_int5, NULL, ami_int7
+struct irqaction amiga_sys_irqaction[AUTO_IRQS] = {
+	{ handler: ami_badint, name: "spurious int" },
+	{ handler: ami_int1, name: "int1 handler" },
+	{ 0, /* CIAA */ },
+	{ handler: ami_int3, name: "int3 handler" },
+	{ handler: ami_int4, name: "int4 handler" },
+	{ handler: ami_int5, name: "int5 handler" },
+	{ 0, /* CIAB */ },
+	{ handler: ami_int7, name: "int7 handler" },
 };
 #else
 void (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
@@ -479,29 +329,3 @@
 	ami_int4, ami_int5, ami_badint, ami_int7
 };
 #endif
-
-int amiga_get_irq_list(char *buf)
-{
-	int i, len = 0;
-	irq_node_t *node;
-
-	for (i = 0; i < AMI_STD_IRQS; i++) {
-		if (!(node = ami_irq_list[i]))
-			continue;
-		len += sprintf(buf+len, "ami  %2d: %10u ", i,
-		               kstat.irqs[0][SYS_IRQS + i]);
-		do {
-			if (node->flags & SA_INTERRUPT)
-				len += sprintf(buf+len, "F ");
-			else
-				len += sprintf(buf+len, "  ");
-			len += sprintf(buf+len, "%s\n", node->devname);
-			if ((node = node->next))
-				len += sprintf(buf+len, "                    ");
-		} while (node);
-	}
-
-	len += cia_get_irq_list(&ciaa_base, buf+len);
-	len += cia_get_irq_list(&ciab_base, buf+len);
-	return len;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/amiga/cia.c linux-2.4.20/arch/ppc/amiga/cia.c
--- linux-2.4.19/arch/ppc/amiga/cia.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.20/arch/ppc/amiga/cia.c	2002-10-29 11:18:34.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.cia.c 1.7 05/21/01 00:48:24 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  linux/arch/m68k/amiga/cia.c - CIA support
@@ -16,7 +16,8 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/kernel_stat.h>
 #include <linux/init.h>
 
@@ -30,7 +31,6 @@
 	u_short int_mask;
 	int handler_irq, cia_irq, server_irq;
 	char *name;
-	irq_handler_t irq_list[CIA_IRQS];
 } ciaa_base = {
 	&ciaa, 0, 0, IF_PORTS,
 	IRQ_AMIGA_AUTO_2, IRQ_AMIGA_CIAA,
@@ -99,15 +99,13 @@
 }
 
 /*
- *  Enable or disable CIA interrupts, return old interrupt mask,
- *  interrupts will only be enabled if a handler exists
+ *  Enable or disable CIA interrupts, return old interrupt mask.
  */
 
 static unsigned char cia_able_irq_private(struct ciabase *base,
 					  unsigned char mask)
 {
-	u_char old, tmp;
-	int i;
+	u_char old;
 
 	old = base->icr_mask;
 	base->icr_data |= base->cia->icr;
@@ -117,12 +115,7 @@
 	else
 		base->icr_mask &= ~mask;
 	base->icr_mask &= CIA_ICR_ALL;
-	for (i = 0, tmp = 1; i < CIA_IRQS; i++, tmp <<= 1) {
-		if ((tmp & base->icr_mask) && !base->irq_list[i].handler) {
-			base->icr_mask &= ~tmp;
-			base->cia->icr = tmp;
-		}
-	}
+
 	if (base->icr_data & base->icr_mask)
 		custom.intreq = IF_SETCLR | base->int_mask;
 	return old;
@@ -144,94 +137,45 @@
 	return cia_able_irq_private(base, mask);
 }
 
-int cia_request_irq(unsigned int irq,
-                    void (*handler)(int, void *, struct pt_regs *),
-                    unsigned long flags, const char *devname, void *dev_id)
-{
-	u_char mask;
-	struct ciabase *base;
-
-	CIA_SET_BASE_ADJUST_IRQ(base, irq);
-
-	base->irq_list[irq].handler = handler;
-	base->irq_list[irq].flags   = flags;
-	base->irq_list[irq].dev_id  = dev_id;
-	base->irq_list[irq].devname = devname;
-
-	/* enable the interrupt */
-	mask = 1 << irq;
-	cia_set_irq_private(base, mask);
-	cia_able_irq_private(base, CIA_ICR_SETCLR | mask);
-	return 0;
-}
-
-void cia_free_irq(unsigned int irq, void *dev_id)
-{
-	struct ciabase *base;
-
-	CIA_SET_BASE_ADJUST_IRQ(base, irq);
-
-	if (base->irq_list[irq].dev_id != dev_id)
-		printk("%s: removing probably wrong IRQ %i from %s\n",
-		       __FUNCTION__, base->cia_irq + irq,
-		       base->irq_list[irq].devname);
-
-	base->irq_list[irq].handler = NULL;
-	base->irq_list[irq].flags   = 0;
-
-	cia_able_irq_private(base, 1 << irq);
-}
-
 static void cia_handler(int irq, void *dev_id, struct pt_regs *fp)
 {
 	struct ciabase *base = (struct ciabase *)dev_id;
-	int mach_irq, i;
+	irq_desc_t *desc;
+	struct irqaction *action;
+	int i;
 	unsigned char ints;
 
-	mach_irq = base->cia_irq;
-	irq = SYS_IRQS + mach_irq;
+	irq = base->cia_irq;
+	desc = irq_desc + irq;
 	ints = cia_set_irq_private(base, CIA_ICR_ALL);
 	custom.intreq = base->int_mask;
-	for (i = 0; i < CIA_IRQS; i++, irq++, mach_irq++) {
+	for (i = 0; i < CIA_IRQS; i++, irq++) {
 		if (ints & 1) {
 			kstat.irqs[0][irq]++;
-			base->irq_list[i].handler(mach_irq, base->irq_list[i].dev_id, fp);
+			action = desc->action;
+			action->handler(irq, action->dev_id, fp);
 		}
 		ints >>= 1;
+		desc++;
 	}
 	amiga_do_irq_list(base->server_irq, fp);
 }
 
 void __init cia_init_IRQ(struct ciabase *base)
 {
-	int i;
-
-	/* init isr handlers */
-	for (i = 0; i < CIA_IRQS; i++) {
-		base->irq_list[i].handler = NULL;
-		base->irq_list[i].flags   = 0;
-	}
+	extern struct irqaction amiga_sys_irqaction[AUTO_IRQS];
+	struct irqaction *action;
 
 	/* clear any pending interrupt and turn off all interrupts */
 	cia_set_irq_private(base, CIA_ICR_ALL);
 	cia_able_irq_private(base, CIA_ICR_ALL);
 
 	/* install CIA handler */
-	request_irq(base->handler_irq, cia_handler, 0, base->name, base);
+	action = &amiga_sys_irqaction[base->handler_irq-IRQ_AMIGA_AUTO];
+	action->handler = cia_handler;
+	action->dev_id = base;
+	action->name = base->name;
+	setup_irq(base->handler_irq, &amiga_sys_irqaction[base->handler_irq-IRQ_AMIGA_AUTO]);
 
 	custom.intena = IF_SETCLR | base->int_mask;
 }
-
-int cia_get_irq_list(struct ciabase *base, char *buf)
-{
-	int i, j, len = 0;
-
-	j = base->cia_irq;
-	for (i = 0; i < CIA_IRQS; i++) {
-		len += sprintf(buf+len, "cia  %2d: %10d ", j + i,
-			       kstat.irqs[0][SYS_IRQS + j + i]);
-			len += sprintf(buf+len, "  ");
-		len += sprintf(buf+len, "%s\n", base->irq_list[i].devname);
-	}
-	return len;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/amiga/config.c linux-2.4.20/arch/ppc/amiga/config.c
--- linux-2.4.19/arch/ppc/amiga/config.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/amiga/config.c	2002-10-29 11:18:35.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.config.c 1.12 09/18/01 11:19:06 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #define m68k_debug_device debug_device
 
@@ -411,16 +411,16 @@
   mach_keyb_init       = amiga_keyb_init;
   mach_kbdrate         = amiga_kbdrate;
   mach_init_IRQ        = amiga_init_IRQ;
-  mach_default_handler = &amiga_default_handler;
 #ifndef CONFIG_APUS
+  mach_default_handler = &amiga_default_handler;
   mach_request_irq     = amiga_request_irq;
   mach_free_irq        = amiga_free_irq;
   enable_irq           = amiga_enable_irq;
   disable_irq          = amiga_disable_irq;
+  mach_get_irq_list    = amiga_get_irq_list;
 #endif
   mach_get_model       = amiga_get_model;
   mach_get_hardware_list = amiga_get_hardware_list;
-  mach_get_irq_list    = amiga_get_irq_list;
   mach_gettimeoffset   = amiga_gettimeoffset;
   if (AMIGAHW_PRESENT(A3000_CLK)){
     mach_gettod  = a3000_gettod;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/amiga/time.c linux-2.4.20/arch/ppc/amiga/time.c
--- linux-2.4.19/arch/ppc/amiga/time.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.20/arch/ppc/amiga/time.c	2002-10-29 11:18:40.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.time.c 1.5 05/17/01 18:14:20 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #include <linux/config.h> /* CONFIG_HEARTBEAT */
 #include <linux/errno.h>
@@ -56,6 +56,4 @@
                 dist = period / 4;
 	}
 #endif
-	/* should be made smarter */
-	ppc_md.heartbeat_count = 1;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/boot/Makefile linux-2.4.20/arch/ppc/boot/Makefile
--- linux-2.4.19/arch/ppc/boot/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/boot/Makefile	2002-10-29 11:18:32.000000000 +0000
@@ -31,6 +31,7 @@
 subdir-$(CONFIG_ALL_PPC)	:= chrp pmac prep
 tools-$(CONFIG_ALL_PPC)		:= addnote mknote hack-coff mkprep
 tools-$(CONFIG_4xx)		:= mktree
+tools-$(CONFIG_SPRUCE)		:= mktree
 
 # These are dirs we don't want to go into on BOOT_TARGETS.  We have them for
 # the 'depend' stage.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/boot/common/crt0.S linux-2.4.20/arch/ppc/boot/common/crt0.S
--- linux-2.4.19/arch/ppc/boot/common/crt0.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/boot/common/crt0.S	2002-10-29 11:18:49.000000000 +0000
@@ -22,7 +22,7 @@
  */
 
 #include <linux/config.h>
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 
 	.text
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/boot/common/misc-simple.c linux-2.4.20/arch/ppc/boot/common/misc-simple.c
--- linux-2.4.19/arch/ppc/boot/common/misc-simple.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/boot/common/misc-simple.c	2002-10-29 11:18:49.000000000 +0000
@@ -148,9 +148,12 @@
 	memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
 	while ( *cp ) putc(*cp++);
 
-#ifndef CONFIG_GEMINI
-	/* Val Henson has requested that Gemini doesn't wait for the
-	 * user to edit the cmdline or not. */
+#if (defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_VGA_CONSOLE)) \
+	&& !defined(CONFIG_GEMINI)
+	/*
+	 * If they have a console, allow them to edit the command line.
+	 * Otherwise, don't bother wasting the five seconds.
+	 */
 	while (timer++ < 5*1000) {
 		if (tstc()) {
 			while ((ch = getc()) != '\n' && ch != '\r') {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/boot/common/relocate.S linux-2.4.20/arch/ppc/boot/common/relocate.S
--- linux-2.4.19/arch/ppc/boot/common/relocate.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/boot/common/relocate.S	2002-10-29 11:18:49.000000000 +0000
@@ -20,7 +20,7 @@
 #include <linux/config.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 
 #define GETSYM(reg, sym)	\
 	lis	reg, sym@h; ori	reg, reg, sym@l	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/boot/common/util.S linux-2.4.20/arch/ppc/boot/common/util.S
--- linux-2.4.19/arch/ppc/boot/common/util.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/boot/common/util.S	2002-10-29 11:18:33.000000000 +0000
@@ -24,7 +24,7 @@
 
 #include <asm/processor.h>
 #include <asm/cache.h>
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 
 
 	.text
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/boot/ld.script linux-2.4.20/arch/ppc/boot/ld.script
--- linux-2.4.19/arch/ppc/boot/ld.script	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/boot/ld.script	2002-10-29 11:18:40.000000000 +0000
@@ -39,7 +39,7 @@
   PROVIDE (etext = .);
 
   /* Read-write section, merged into data segment: */
-  . = (. + 0x0FFF) & 0xFFFFF000;
+  . = ALIGN(8);
   .data    :
   {
     *(.data)
@@ -70,6 +70,7 @@
   _edata  =  .;
   PROVIDE (edata = .);
 
+  . = ALIGN(8);
   __bss_start = .;
   .bss       :
   {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/boot/prep/head.S linux-2.4.20/arch/ppc/boot/prep/head.S
--- linux-2.4.19/arch/ppc/boot/prep/head.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/boot/prep/head.S	2002-10-29 11:18:33.000000000 +0000
@@ -2,7 +2,7 @@
  * BK Id: SCCS/s.head.S 1.13 01/11/02 10:46:07 trini
  */
 
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/boot/simple/Makefile linux-2.4.20/arch/ppc/boot/simple/Makefile
--- linux-2.4.19/arch/ppc/boot/simple/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/boot/simple/Makefile	2002-10-29 11:18:31.000000000 +0000
@@ -3,11 +3,16 @@
 #
 # Author: Tom Rini <trini@mvista.com>
 #
-# Copyright 2001 MontaVista Software Inc.
+# Copyright 2001-2002 MontaVista Software Inc.
 #
-# Notes: For machine targets which produce more than one image, define
+# Notes:
+# (1) For machine targets which produce more than one image, define
 # ZNETBOOT and ZNETBOOTRD to the image which should be available for
 # 'znetboot' and 'znetboot.initrd`
+# (2) For machine targets which use the mktree program, define END to be
+# the machine name you want in the image, and you can optionally set
+# ENTRYPOINT which the image should be loaded at.  The optimal setting
+# for ENTRYPOINT is the link address.
 #
 # 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
@@ -28,9 +33,24 @@
 ifeq ($(CONFIG_GEMINI),y)
 ZIMAGE				:= zImage-SMON
 ZIMAGEINITRD			:= zImage.initrd-SMON
-HEADHELP			:= direct.o
+EXTRA				:= direct.o
 TFTPIMAGE			:= /tftpboot/zImage.gemini
 endif
+ifeq ($(CONFIG_PAL4),y)
+ZIMAGE				:= zImage-PAL4
+ZIMAGEINITRD			:= zImage.initrd-PAL4
+EXTRA				:= direct.o
+TFTPIMAGE			:= /tftpboot/zImage.pal4
+endif
+ifeq ($(CONFIG_SPRUCE),y)
+ZIMAGE				:= zImage-TREE
+ZIMAGEINITRD			:= zImage.initrd-TREE
+EXTRA				:= direct.o
+ENTRYPOINT			:= 0x00800000
+MISC				:= misc-spruce.o
+END				:= spruce
+TFTPIMAGE			:= /tftpboot/zImage.$(END)
+endif
 ifeq ($(CONFIG_SMP),y)
 TFTPIMAGE			+= .smp
 endif
@@ -46,7 +66,7 @@
 OBJCOPY_ARGS			:= -O elf32-powerpc
 
 # head.o and ../common/relocate.o must be at the start.
-obj-y				:= head.o ../common/relocate.o $(HEADHELP) \
+obj-y				:= head.o ../common/relocate.o $(EXTRA) \
 				$(MISC) ../common/misc-common.o \
 				../common/string.o ../common/util.o
 obj-$(CONFIG_4xx)		+= embed_config.o
@@ -69,10 +89,6 @@
 MKPREP				:= ../utils/mkprep
 MKTREE				:= ../utils/mktree
 
-AFLAGS_head.o			+= -I$(TOPDIR)/arch/$(ARCH)/kernel
-AFLAGS_../common/util.o		+= -I$(TOPDIR)/arch/$(ARCH)/kernel
-AFLAGS_../common/relocate.o	+= -I$(TOPDIR)/arch/$(ARCH)/kernel
-
 zvmlinux: $(obj-y) $(LIBS) ../ld.script ../images/vmlinux.gz ../common/dummy.o
 	$(OBJCOPY) $(OBJCOPY_ARGS) \
 		--add-section=.image=../images/vmlinux.gz \
@@ -120,6 +136,12 @@
 zImage.initrd-EMBEDDED: zvmlinux.initrd
 	mv zvmlinux.initrd ../images/zImage.initrd.embedded
 
+zImage-PAL4: zvmlinux
+	cp zvmlinux ../images/zImage.pal4
+
+zImage.initrd-PAL4: zvmlinux.initrd
+	cp zvmlinux.initrd ../images/zImage.initrd.pal4
+
 zImage-SMON: zvmlinux
 	dd if=zvmlinux of=../images/zImage.gemini skip=64 bs=1k
 
@@ -127,9 +149,9 @@
 	dd if=zvmlinux.initrd of=../images/zImage.initrd.gemini skip=64 bs=1k
 
 zImage-TREE: zvmlinux
-	$(MKTREE) zvmlinux ../images/zImage.treeboot
+	$(MKTREE) zvmlinux ../images/zImage.$(END) $(ENTRYPOINT)
 
 zImage.initrd-TREE: zvmlinux.initrd
-	$(MKTREE) zvmlinux.initrd ../images/zImage.initrd.treeboot
+	$(MKTREE) zvmlinux.initrd ../images/zImage.initrd.$(END) $(ENTRYPOINT)
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/boot/simple/head.S linux-2.4.20/arch/ppc/boot/simple/head.S
--- linux-2.4.19/arch/ppc/boot/simple/head.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/boot/simple/head.S	2002-10-29 11:18:36.000000000 +0000
@@ -18,7 +18,7 @@
 #include <linux/config.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 
 	.text
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/boot/simple/legacy.S linux-2.4.20/arch/ppc/boot/simple/legacy.S
--- linux-2.4.19/arch/ppc/boot/simple/legacy.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/boot/simple/legacy.S	2002-10-29 11:18:34.000000000 +0000
@@ -6,7 +6,7 @@
  * This will go and setup ISA_io to 0x8000000 and return.
  */
 
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 
 	.text
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/boot/simple/misc-embedded.c linux-2.4.20/arch/ppc/boot/simple/misc-embedded.c
--- linux-2.4.19/arch/ppc/boot/simple/misc-embedded.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/boot/simple/misc-embedded.c	2002-10-29 11:18:39.000000000 +0000
@@ -59,7 +59,7 @@
 char compiled_string[] = CONFIG_CMDLINE;
 #endif
 char ramroot_string[] = "root=/dev/ram";
-char netroot_string[] = "root=/dev/nfs rw ip=auto";
+char netroot_string[] = "root=/dev/nfs rw ip=on";
 
 /* Serial port to use. */
 unsigned long com_port;
@@ -172,6 +172,11 @@
 #endif
 	while ( *cp )
 		putc(*cp++);
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_VGA_CONSOLE)
+	/*
+	 * If they have a console, allow them to edit the command line.
+	 * Otherwise, don't bother wasting the five seconds.
+	 */
 	while (timer++ < 5*1000) {
 		if (tstc()) {
 			while ((ch = getc()) != '\n' && ch != '\r') {
@@ -195,6 +200,7 @@
 		}
 		udelay(1000);  /* 1 msec */
 	}
+#endif
 	*cp = 0;
 	puts("\nUncompressing Linux...");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/boot/simple/misc-spruce.c linux-2.4.20/arch/ppc/boot/simple/misc-spruce.c
--- linux-2.4.19/arch/ppc/boot/simple/misc-spruce.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/boot/simple/misc-spruce.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,440 @@
+/*
+ * arch/ppc/boot/spruce/misc.c
+ *
+ * Misc. bootloader code for IBM Spruce reference platform
+ *
+ * Authors: Johnnie Peters <jpeters@mvista.com>
+ *	    Matt Porter <mporter@mvista.com>
+ *
+ * Derived from arch/ppc/boot/prep/misc.c
+ *
+ * Copyright 2000-2001 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.
+ */
+
+#include <linux/types.h>
+#include <linux/elf.h>
+#include <linux/config.h>
+#include <linux/pci.h>
+
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <asm/bootinfo.h>
+
+#include "zlib.h"
+
+/* Define some important locations of the Spruce. */
+#define SPRUCE_PCI_CONFIG_ADDR	0xfec00000
+#define SPRUCE_PCI_CONFIG_DATA	0xfec00004
+#define SPRUCE_ISA_IO_BASE	0xf8000000
+
+unsigned long com_port;
+
+char *avail_ram;
+char *end_avail;
+
+/* The linker tells us where the image is. */
+extern char __image_begin, __image_end;
+extern char __ramdisk_begin, __ramdisk_end;
+extern char _end[];
+
+#ifdef CONFIG_CMDLINE
+#define CMDLINE CONFIG_CMDLINE
+#else
+#define CMDLINE ""
+#endif
+char cmd_preset[] = CMDLINE;
+char cmd_buf[256];
+char *cmd_line = cmd_buf;
+
+unsigned long initrd_size = 0;
+
+char *zimage_start;
+int zimage_size;
+
+extern void udelay(long);
+extern void puts(const char *);
+extern void putc(const char c);
+extern void puthex(unsigned long val);
+extern int getc(void);
+extern int tstc(void);
+extern void gunzip(void *, int, unsigned char *, int *);
+
+extern unsigned long serial_init(int chan, void *ignored);
+
+/* PCI configuration space access routines. */
+unsigned int *pci_config_address = (unsigned int *)SPRUCE_PCI_CONFIG_ADDR;
+unsigned char *pci_config_data   = (unsigned char *)SPRUCE_PCI_CONFIG_DATA;
+
+void cpc700_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned char *val)
+{
+	out_le32(pci_config_address,
+		 (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
+
+	*val= (in_le32((unsigned *)pci_config_data) >> (8 * (offset & 3))) & 0xff;
+}
+
+void cpc700_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned char val)
+{
+	out_le32(pci_config_address,
+		 (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
+
+	out_8(pci_config_data + (offset&3), val);
+}
+
+void cpc700_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned short *val)
+{
+	out_le32(pci_config_address,
+		 (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
+
+	*val= in_le16((unsigned short *)(pci_config_data + (offset&3)));
+}
+
+void cpc700_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned short val)
+{
+	out_le32(pci_config_address,
+		 (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
+
+	out_le16((unsigned short *)(pci_config_data + (offset&3)), val);
+}
+
+void cpc700_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned int *val)
+{
+	out_le32(pci_config_address,
+		 (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
+
+	*val= in_le32((unsigned *)pci_config_data);
+}
+
+void cpc700_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned int val)
+{
+	out_le32(pci_config_address,
+		 (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000));
+
+	out_le32((unsigned *)pci_config_data, val);
+}
+
+unsigned long isa_io_base = SPRUCE_ISA_IO_BASE;
+
+#define PCNET32_WIO_RDP		0x10
+#define PCNET32_WIO_RAP		0x12
+#define PCNET32_WIO_RESET	0x14
+
+#define PCNET32_DWIO_RDP	0x10
+#define PCNET32_DWIO_RAP	0x14
+#define PCNET32_DWIO_RESET	0x18
+
+/* Processor interface config register access */
+#define PIFCFGADDR 0xff500000
+#define PIFCFGDATA 0xff500004
+
+#define PLBMIFOPT 0x18 /* PLB Master Interface Options */
+
+#define MEM_MBEN	0x24
+#define MEM_TYPE	0x28
+#define MEM_B1SA	0x3c
+#define MEM_B1EA	0x5c
+#define MEM_B2SA	0x40
+#define MEM_B2EA	0x60
+
+unsigned long
+decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
+{
+	int timer = 0;
+	char *cp, ch;
+
+	int loop;
+	int csr0;
+	int csr_id;
+	volatile int *mem_addr = (int *)0xff500008;
+	volatile int *mem_data = (int *)0xff50000c;
+	int mem_size = 0;
+	unsigned long mem_mben;
+	unsigned long mem_type;
+	unsigned long mem_start;
+	unsigned long mem_end;
+	volatile int *pif_addr = (int *)0xff500000;
+	volatile int *pif_data = (int *)0xff500004;
+	int pci_devfn;
+	int found_multi = 0;
+	unsigned short vendor;
+	unsigned short device;
+	unsigned short command;
+	unsigned char header_type;
+	unsigned int bar0;
+
+#ifdef CONFIG_SERIAL_CONSOLE
+	/* Initialize the serial console port */
+	com_port = serial_init(0, NULL);
+#endif
+
+	/*
+	 * Gah, these firmware guys need to learn that hardware
+	 * byte swapping is evil! Disable all hardware byte
+	 * swapping so it doesn't hurt anyone.
+	 */
+	*pif_addr = PLBMIFOPT;
+	asm("sync");
+	*pif_data = 0x00000000;
+	asm("sync");
+
+	/* Get the size of memory from the memory controller. */
+	*mem_addr = MEM_MBEN;
+	asm("sync");
+	mem_mben = *mem_data;
+	asm("sync");
+	for(loop = 0; loop < 1000; loop++);
+
+	*mem_addr = MEM_TYPE;
+	asm("sync");
+	mem_type = *mem_data;
+	asm("sync");
+	for(loop = 0; loop < 1000; loop++);
+
+	*mem_addr = MEM_TYPE;
+	/* Confirm bank 1 has DRAM memory */
+	if ((mem_mben & 0x40000000) &&
+				((mem_type & 0x30000000) == 0x10000000)) {
+		*mem_addr = MEM_B1SA;
+		asm("sync");
+		mem_start = *mem_data;
+		asm("sync");
+		for(loop = 0; loop < 1000; loop++);
+
+		*mem_addr = MEM_B1EA;
+		asm("sync");
+		mem_end = *mem_data;
+		asm("sync");
+		for(loop = 0; loop < 1000; loop++);
+
+		mem_size = mem_end - mem_start + 0x100000;
+	}
+
+	/* Confirm bank 2 has DRAM memory */
+	if ((mem_mben & 0x20000000) &&
+				((mem_type & 0xc000000) == 0x4000000)) {
+		*mem_addr = MEM_B2SA;
+		asm("sync");
+		mem_start = *mem_data;
+		asm("sync");
+		for(loop = 0; loop < 1000; loop++);
+
+		*mem_addr = MEM_B2EA;
+		asm("sync");
+		mem_end = *mem_data;
+		asm("sync");
+		for(loop = 0; loop < 1000; loop++);
+
+		mem_size += mem_end - mem_start + 0x100000;
+	}
+
+	/* Search out and turn off the PcNet ethernet boot device. */
+	for (pci_devfn = 1; pci_devfn < 0xff; pci_devfn++) {
+		if (PCI_FUNC(pci_devfn) && !found_multi)
+			continue;
+
+		cpc700_pcibios_read_config_byte(0, pci_devfn,
+				PCI_HEADER_TYPE, &header_type);
+
+		if (!PCI_FUNC(pci_devfn))
+			found_multi = header_type & 0x80;
+
+		cpc700_pcibios_read_config_word(0, pci_devfn, PCI_VENDOR_ID,
+				&vendor);
+
+		if (vendor != 0xffff) {
+			cpc700_pcibios_read_config_word(0, pci_devfn,
+						PCI_DEVICE_ID, &device);
+
+			/* If this PCI device is the Lance PCNet board then turn it off */
+			if ((vendor == PCI_VENDOR_ID_AMD) &&
+					(device == PCI_DEVICE_ID_AMD_LANCE)) {
+
+				/* Turn on I/O Space on the board. */
+				cpc700_pcibios_read_config_word(0, pci_devfn,
+						PCI_COMMAND, &command);
+				command |= 0x1;
+				cpc700_pcibios_write_config_word(0, pci_devfn,
+						PCI_COMMAND, command);
+
+				/* Get the I/O space address */
+				cpc700_pcibios_read_config_dword(0, pci_devfn,
+						PCI_BASE_ADDRESS_0, &bar0);
+				bar0 &= 0xfffffffe;
+
+				/* Reset the PCNet Board */
+				inl (bar0+PCNET32_DWIO_RESET);
+				inw (bar0+PCNET32_WIO_RESET);
+
+				/* First do a work oriented read of csr0.  If the value is
+				 * 4 then this is the correct mode to access the board.
+				 * If not try a double word ortiented read.
+				 */
+				outw(0, bar0 + PCNET32_WIO_RAP);
+				csr0 = inw(bar0 + PCNET32_WIO_RDP);
+
+				if (csr0 == 4) {
+					/* Check the Chip id register */
+					outw(88, bar0 + PCNET32_WIO_RAP);
+					csr_id = inw(bar0 + PCNET32_WIO_RDP);
+
+					if (csr_id) {
+						/* This is the valid mode - set the stop bit */
+						outw(0, bar0 + PCNET32_WIO_RAP);
+						outw(csr0, bar0 + PCNET32_WIO_RDP);
+					}
+				} else {
+					outl(0, bar0 + PCNET32_DWIO_RAP);
+					csr0 = inl(bar0 + PCNET32_DWIO_RDP);
+					if (csr0 == 4) {
+						/* Check the Chip id register */
+						outl(88, bar0 + PCNET32_WIO_RAP);
+						csr_id = inl(bar0 + PCNET32_WIO_RDP);
+
+						if (csr_id) {
+							/* This is the valid mode  - set the stop bit*/
+							outl(0, bar0 + PCNET32_WIO_RAP);
+							outl(csr0, bar0 + PCNET32_WIO_RDP);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	/* assume the chunk below 8M is free */
+	end_avail = (char *)0x00800000;
+
+	/*
+	 * We link ourself to 0x00800000.  When we run, we relocate
+	 * ourselves there.  So we just need __image_begin for the
+	 * start. -- Tom
+	 */
+	zimage_start = (char *)(unsigned long)(&__image_begin);
+	zimage_size = (unsigned long)(&__image_end) -
+			(unsigned long)(&__image_begin);
+
+	initrd_size = (unsigned long)(&__ramdisk_end) -
+		(unsigned long)(&__ramdisk_begin);
+
+	/*
+	 * The zImage and initrd will be between start and _end, so they've
+	 * already been moved once.  We're good to go now. -- Tom
+	 */
+	avail_ram = (char *)PAGE_ALIGN((unsigned long)_end);
+	puts("zimage at:     "); puthex((unsigned long)zimage_start);
+	puts(" "); puthex((unsigned long)(zimage_size+zimage_start));
+	puts("\n");
+
+	if ( initrd_size ) {
+		puts("initrd at:     ");
+		puthex((unsigned long)(&__ramdisk_begin));
+		puts(" "); puthex((unsigned long)(&__ramdisk_end));puts("\n");
+	}
+
+	avail_ram = (char *)0x00400000;
+	end_avail = (char *)0x00800000;
+	puts("avail ram:     "); puthex((unsigned long)avail_ram); puts(" ");
+	puthex((unsigned long)end_avail); puts("\n");
+
+	/* Display standard Linux/PPC boot prompt for kernel args */
+	puts("\nLinux/PPC load: ");
+	cp = cmd_line;
+	memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
+	while ( *cp ) putc(*cp++);
+	while (timer++ < 5*1000) {
+		if (tstc()) {
+			while ((ch = getc()) != '\n' && ch != '\r') {
+				if (ch == '\b') {
+					if (cp != cmd_line) {
+						cp--;
+						puts("\b \b");
+					}
+				} else {
+					*cp++ = ch;
+					putc(ch);
+				}
+			}
+			break;  /* Exit 'timer' loop */
+		}
+		udelay(1000);  /* 1 msec */
+	}
+	*cp = 0;
+	puts("\n");
+
+	puts("Uncompressing Linux...");
+
+	gunzip(0, 0x400000, zimage_start, &zimage_size);
+
+	puts("done.\n");
+
+	{
+		struct bi_record *rec;
+
+		rec = (struct bi_record *)_ALIGN((ulong)zimage_size +
+							(1<<20)-1,(1<<20));
+
+		rec->tag = BI_FIRST;
+        	rec->size = sizeof(struct bi_record);
+        	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+        	rec->tag = BI_BOOTLOADER_ID;
+        	memcpy( (void *)rec->data, "spruceboot", 11);
+        	rec->size = sizeof(struct bi_record) + 10 + 1;
+        	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+        	rec->tag = BI_MEMSIZE;
+        	rec->data[0] = mem_size;
+        	rec->size = sizeof(struct bi_record) + sizeof(unsigned long);
+        	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+        	rec->tag = BI_CMD_LINE;
+        	memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1);
+        	rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1;
+        	rec = (struct bi_record *)((ulong)rec + rec->size);
+
+		if ( initrd_size ) {
+			rec->tag = BI_INITRD;
+			rec->data[0] = (unsigned long)(&__ramdisk_begin);
+			rec->data[1] = initrd_size;
+			rec->size = sizeof(struct bi_record) + 2 *
+				sizeof(unsigned long);
+			rec = (struct bi_record *)((unsigned long)rec +
+					rec->size);
+		}
+
+        	rec->tag = BI_LAST;
+        	rec->size = sizeof(struct bi_record);
+        	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+	}
+
+	puts("Now booting the kernel\n");
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/config.in linux-2.4.20/arch/ppc/config.in
--- linux-2.4.19/arch/ppc/config.in	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/config.in	2002-10-29 11:18:31.000000000 +0000
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.config.in 1.51 03/07/02 13:36:31 trini
+# BK Id: %F% %I% %G% %U% %#%
 #
 # For a description of the syntax of this configuration file,
 # see Documentation/kbuild/config-language.txt.
@@ -42,6 +42,7 @@
 if [ "$CONFIG_POWER3" = "y" -o "$CONFIG_POWER4" = "y" ]; then
   define_bool CONFIG_PPC64BRIDGE y
   define_bool CONFIG_ALL_PPC y
+  define_bool CONFIG_PPC_ISATIMER y
 fi
 
 if [ "$CONFIG_6xx" = "y" -o "$CONFIG_POWER3" = "y" -o \
@@ -97,6 +98,8 @@
   choice 'Machine Type'		\
 	"CHRP/PowerMac/PReP	CONFIG_ALL_PPC		\
   	 Amiga-APUS		CONFIG_APUS		\
+	 IBM-Spruce		CONFIG_SPRUCE		\
+	 SBS-Palomar4		CONFIG_PAL4		\
 	 Synergy-Gemini        	CONFIG_GEMINI"		CHRP/PowerMac/PReP
 fi
 
@@ -116,6 +119,7 @@
     bool '    Interrupt driven TAU driver (DANGEROUS)' CONFIG_TAU_INT
     bool '    Average high and low temp' CONFIG_TAU_AVERAGE
   fi
+  define_bool CONFIG_PPC_ISATIMER y
 fi
 
 if [ "$CONFIG_4xx" = "y" -o "$CONFIG_8xx" = "y" ]; then
@@ -395,10 +399,29 @@
 
 source net/bluetooth/Config.in
 
+source lib/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
-bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
-bool 'Include kgdb kernel debugger' CONFIG_KGDB
-bool 'Include xmon kernel debugger' CONFIG_XMON
+bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
+if [ "$CONFIG_DEBUG_KERNEL" = "y" ]; then
+  bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
+  bool '  Debug high memory support' CONFIG_DEBUG_HIGHMEM
+  bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
+  if [ "$CONFIG_SMP" = "y" ]; then
+    bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
+  fi
+  bool '  Wait queue debugging' CONFIG_DEBUG_WAITQ
+  bool '  Include kgdb kernel debugger' CONFIG_KGDB
+  bool '  Include xmon kernel debugger' CONFIG_XMON
+  bool '  Include BDI-2000 user context switcher' CONFIG_BDI_SWITCH
+  if [ "$CONFIG_KGDB" = "y" -o "$CONFIG_XMON" = "y" \
+	-o "$CONFIG_BDI_SWITCH" = "y" ]; then
+    bool '    Add any additional compile options' CONFIG_MORE_COMPILE_OPTIONS
+    if [ "$CONFIG_MORE_COMPILE_OPTIONS" = "y" ]; then
+      string '    Additional compile arguments' CONFIG_COMPILE_OPTIONS "-g -ggdb"
+    fi
+  fi
+fi
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/IVMS8_defconfig linux-2.4.20/arch/ppc/configs/IVMS8_defconfig
--- linux-2.4.19/arch/ppc/configs/IVMS8_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/IVMS8_defconfig	2002-10-29 11:18:33.000000000 +0000
@@ -100,10 +100,12 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -153,13 +155,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -177,6 +172,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 CONFIG_IDE=y
@@ -193,6 +193,7 @@
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -207,6 +208,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -270,11 +272,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -380,7 +384,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -412,6 +415,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -425,10 +430,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 # 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
@@ -459,6 +467,7 @@
 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_SMB_FS is not set
@@ -472,7 +481,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -488,6 +496,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
@@ -519,116 +528,17 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-
-#
-#   SCSI support is needed for USB Storage
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/SM850_defconfig linux-2.4.20/arch/ppc/configs/SM850_defconfig
--- linux-2.4.19/arch/ppc/configs/SM850_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/SM850_defconfig	2002-10-29 11:18:38.000000000 +0000
@@ -101,10 +101,12 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -154,13 +156,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -178,6 +173,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -228,11 +228,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -338,7 +340,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -370,6 +371,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -383,10 +386,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
@@ -417,6 +423,7 @@
 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_SMB_FS is not set
@@ -430,7 +437,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -446,6 +452,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
@@ -481,116 +488,17 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-
-#
-#   SCSI support is needed for USB Storage
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/SPD823TS_defconfig linux-2.4.20/arch/ppc/configs/SPD823TS_defconfig
--- linux-2.4.19/arch/ppc/configs/SPD823TS_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/SPD823TS_defconfig	2002-10-29 11:18:50.000000000 +0000
@@ -100,10 +100,12 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -153,13 +155,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -177,6 +172,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -227,11 +227,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -337,7 +339,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -369,6 +370,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -382,10 +385,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
@@ -416,6 +422,7 @@
 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_SMB_FS is not set
@@ -429,7 +436,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -445,6 +451,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
@@ -480,116 +487,17 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-
-#
-#   SCSI support is needed for USB Storage
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/TQM823L_defconfig linux-2.4.20/arch/ppc/configs/TQM823L_defconfig
--- linux-2.4.19/arch/ppc/configs/TQM823L_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/TQM823L_defconfig	2002-10-29 11:18:34.000000000 +0000
@@ -101,10 +101,12 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -154,13 +156,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -178,6 +173,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -228,11 +228,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -338,7 +340,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -370,6 +371,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -383,10 +386,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
@@ -417,6 +423,7 @@
 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_SMB_FS is not set
@@ -430,7 +437,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -446,6 +452,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
@@ -481,116 +488,17 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-
-#
-#   SCSI support is needed for USB Storage
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/TQM850L_defconfig linux-2.4.20/arch/ppc/configs/TQM850L_defconfig
--- linux-2.4.19/arch/ppc/configs/TQM850L_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/TQM850L_defconfig	2002-10-29 11:18:48.000000000 +0000
@@ -101,10 +101,12 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -154,13 +156,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -178,6 +173,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -228,11 +228,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -338,7 +340,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -370,6 +371,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -383,10 +386,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
@@ -417,6 +423,7 @@
 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_SMB_FS is not set
@@ -430,7 +437,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -446,6 +452,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
@@ -481,116 +488,17 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-
-#
-#   SCSI support is needed for USB Storage
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/TQM860L_defconfig linux-2.4.20/arch/ppc/configs/TQM860L_defconfig
--- linux-2.4.19/arch/ppc/configs/TQM860L_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/TQM860L_defconfig	2002-10-29 11:18:36.000000000 +0000
@@ -101,10 +101,12 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -154,13 +156,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -178,6 +173,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 CONFIG_IDE=y
@@ -194,6 +194,7 @@
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -208,6 +209,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -271,11 +273,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -381,7 +385,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -413,6 +416,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -426,10 +431,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
@@ -460,6 +468,7 @@
 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_SMB_FS is not set
@@ -473,7 +482,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -493,6 +501,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
@@ -528,116 +537,17 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-
-#
-#   SCSI support is needed for USB Storage
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/apus_defconfig linux-2.4.20/arch/ppc/configs/apus_defconfig
--- linux-2.4.19/arch/ppc/configs/apus_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/apus_defconfig	2002-10-29 11:18:49.000000000 +0000
@@ -32,10 +32,13 @@
 CONFIG_PPC_STD_MMU=y
 # CONFIG_ALL_PPC is not set
 CONFIG_APUS=y
+# CONFIG_SPRUCE is not set
+# CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
 # CONFIG_SMP is not set
 # CONFIG_ALTIVEC is not set
 # CONFIG_TAU is not set
+CONFIG_PPC_ISATIMER=y
 
 #
 # General setup
@@ -119,11 +122,13 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_NBD=m
 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)
@@ -167,14 +172,19 @@
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
 CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
 CONFIG_IP_NF_MATCH_AH_ESP=m
 CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
 CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_UNCLEAN=m
 CONFIG_IP_NF_MATCH_OWNER=m
 CONFIG_IP_NF_FILTER=m
@@ -184,15 +194,20 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
 CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
 CONFIG_IP_NF_TARGET_MARK=m
 CONFIG_IP_NF_TARGET_LOG=m
 CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_COMPAT_IPCHAINS=m
 CONFIG_IP_NF_NAT_NEEDED=y
 # CONFIG_IP_NF_COMPAT_IPFWADM is not set
@@ -211,13 +226,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -235,6 +243,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 CONFIG_IDE=y
@@ -251,6 +264,7 @@
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -265,6 +279,7 @@
 CONFIG_BLK_DEV_IDETAPE=m
 CONFIG_BLK_DEV_IDEFLOPPY=y
 CONFIG_BLK_DEV_IDESCSI=m
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -274,7 +289,6 @@
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
 # CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_GAYLE=y
 CONFIG_BLK_DEV_IDEDOUBLER=y
 CONFIG_BLK_DEV_BUDDHA=y
@@ -425,11 +439,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 CONFIG_PLIP=m
@@ -523,6 +539,7 @@
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
@@ -600,6 +617,7 @@
 # CONFIG_PSMOUSE is not set
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
 
 #
 # Joysticks
@@ -642,7 +660,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -674,6 +691,8 @@
 # CONFIG_ADFS_FS_RW is not set
 CONFIG_AFFS_FS=y
 CONFIG_HFS_FS=y
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
 # CONFIG_BFS_FS is not set
 CONFIG_EXT3_FS=y
 CONFIG_JBD=y
@@ -687,10 +706,13 @@
 # CONFIG_JFFS2_FS is not set
 CONFIG_CRAMFS=y
 CONFIG_TMPFS=y
-CONFIG_RAMFS=m
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 CONFIG_JOLIET=y
 # 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=y
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -721,6 +743,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=m
 CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -736,7 +759,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-CONFIG_ZLIB_FS_INFLATE=y
 
 #
 # Partition Types
@@ -756,6 +778,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 CONFIG_SMB_NLS=y
 CONFIG_NLS=y
 
@@ -807,6 +830,7 @@
 CONFIG_SOUND=y
 CONFIG_DMASOUND_PAULA=m
 CONFIG_DMASOUND=m
+# CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
@@ -818,6 +842,7 @@
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
@@ -864,113 +889,17 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-# CONFIG_USB_HID is not set
-# CONFIG_USB_HIDDEV is not set
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_WACOM is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
 
 #
 # Kernel hacking
 #
-CONFIG_MAGIC_SYSRQ=y
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/briq_defconfig linux-2.4.20/arch/ppc/configs/briq_defconfig
--- linux-2.4.19/arch/ppc/configs/briq_defconfig	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/briq_defconfig	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,797 @@
+#
+# Automatically generated make config: 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
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_6xx=y
+# CONFIG_4xx is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_8260 is not set
+CONFIG_PPC_STD_MMU=y
+CONFIG_ALL_PPC=y
+# CONFIG_APUS is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_PAL4 is not set
+# CONFIG_GEMINI is not set
+# CONFIG_SMP is not set
+CONFIG_ALTIVEC=y
+CONFIG_TAU=y
+# CONFIG_TAU_INT is not set
+# CONFIG_TAU_AVERAGE is not set
+CONFIG_PPC_ISATIMER=y
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+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=m
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+CONFIG_PPC_RTC=y
+CONFIG_PPC601_SYNC_FIX=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_PPC_RTAS=y
+CONFIG_BOOTX_TEXT=y
+# CONFIG_PREP_RESIDUAL is not set
+# CONFIG_PROC_PREPRESIDUAL is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_FD=m
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=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=y
+# CONFIG_NETFILTER_DEBUG 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 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
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+# CONFIG_IP_NF_MATCH_AH_ESP is not set
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_UNCLEAN=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_MIRROR=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_IP_NF_TARGET_TCPMSS=m
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+CONFIG_ATALK=m
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
+# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CMD680 is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_SL82C105=y
+# CONFIG_BLK_DEV_IDE_PMAC is not set
+# CONFIG_BLK_DEV_IDEDMA_PMAC is not set
+# CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_IDE_MODES=y
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_SYM53C8XX is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 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_SUNLANCE is not set
+# CONFIG_HAPPYMEAL 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 is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=y
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_TULIP is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
+# CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_WINBOND_840 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+# 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
+#
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_ADB_CUDA is not set
+# CONFIG_ADB_PMU is not set
+# CONFIG_MAC_FLOPPY is not set
+# CONFIG_MAC_SERIAL is not set
+# CONFIG_ADB is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+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
+CONFIG_BRIQ_PANEL=y
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_KEYWEST=m
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_PROC=m
+
+#
+# Mice
+#
+CONFIG_BUSMOUSE=y
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_LOGIBUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_NVRAM=y
+# 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
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+# 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=y
+# 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
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT 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=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_SUN_PARTITION=y
+# CONFIG_EFI_PARTITION is not set
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Library routines
+#
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_KGDB is not set
+CONFIG_XMON=y
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_MORE_COMPILE_OPTIONS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/bseip_defconfig linux-2.4.20/arch/ppc/configs/bseip_defconfig
--- linux-2.4.19/arch/ppc/configs/bseip_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/bseip_defconfig	2002-10-29 11:18:34.000000000 +0000
@@ -98,11 +98,13 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=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)
@@ -153,13 +155,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -177,6 +172,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -227,11 +227,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -337,7 +339,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -369,6 +370,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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=y
 CONFIG_JBD=y
@@ -382,10 +385,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
@@ -416,6 +422,7 @@
 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_SMB_FS is not set
@@ -429,7 +436,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -445,6 +451,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
@@ -480,116 +487,17 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-
-#
-#   SCSI support is needed for USB Storage
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/common_defconfig linux-2.4.20/arch/ppc/configs/common_defconfig
--- linux-2.4.19/arch/ppc/configs/common_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/common_defconfig	2002-10-29 11:18:35.000000000 +0000
@@ -32,12 +32,15 @@
 CONFIG_PPC_STD_MMU=y
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
 # CONFIG_SMP is not set
 CONFIG_ALTIVEC=y
 CONFIG_TAU=y
 # CONFIG_TAU_INT is not set
 # CONFIG_TAU_AVERAGE is not set
+CONFIG_PPC_ISATIMER=y
 
 #
 # General setup
@@ -99,11 +102,13 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=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)
@@ -148,14 +153,19 @@
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
 CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
 CONFIG_IP_NF_MATCH_AH_ESP=m
 CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
 CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_UNCLEAN=m
 CONFIG_IP_NF_MATCH_OWNER=m
 CONFIG_IP_NF_FILTER=m
@@ -165,6 +175,7 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
@@ -172,6 +183,8 @@
 # CONFIG_IP_NF_TARGET_LOG is not set
 CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_COMPAT_IPCHAINS=m
 CONFIG_IP_NF_NAT_NEEDED=y
 # CONFIG_IP_NF_COMPAT_IPFWADM is not set
@@ -190,13 +203,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -214,6 +220,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 CONFIG_IDE=y
@@ -230,6 +241,7 @@
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -244,6 +256,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 CONFIG_BLK_DEV_IDEFLOPPY=y
 CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -255,12 +268,15 @@
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -268,6 +284,7 @@
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
+# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
@@ -336,6 +353,7 @@
 CONFIG_SCSI_AIC7XXX=m
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
 CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
 # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
 CONFIG_SCSI_AIC7XXX_OLD=m
 # CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT is not set
@@ -381,6 +399,7 @@
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
+CONFIG_SCSI_MESH_RESET_DELAY_MS=4000
 CONFIG_SCSI_MAC53C94=y
 
 #
@@ -434,6 +453,7 @@
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -445,11 +465,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -460,11 +482,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -492,6 +516,7 @@
 CONFIG_HERMES=m
 CONFIG_APPLE_AIRPORT=m
 # CONFIG_PLX_HERMES is not set
+# CONFIG_PCI_HERMES is not set
 CONFIG_NET_WIRELESS=y
 
 #
@@ -563,6 +588,7 @@
 CONFIG_FB_RADEON=y
 CONFIG_FB_ATY128=y
 # CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
 CONFIG_FB_3DFX=y
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
@@ -621,6 +647,7 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_BRIQ_PANEL is not set
 
 #
 # I2C support
@@ -643,6 +670,7 @@
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
 
 #
 # Joysticks
@@ -684,7 +712,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -716,6 +743,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 CONFIG_HFS_FS=m
+# 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
@@ -729,10 +758,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 # 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
@@ -763,6 +795,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
@@ -776,7 +809,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -796,6 +828,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 CONFIG_NLS=y
 
@@ -824,7 +857,7 @@
 # CONFIG_NLS_CODEPAGE_949 is not set
 # CONFIG_NLS_CODEPAGE_874 is not set
 # CONFIG_NLS_ISO8859_8 is not set
-CONFIG_NLS_CODEPAGE_1250=m
+# CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
@@ -847,8 +880,7 @@
 CONFIG_SOUND=m
 CONFIG_DMASOUND_PMAC=m
 CONFIG_DMASOUND=m
-CONFIG_I2C=m
-CONFIG_I2C_KEYWEST=m
+# CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
@@ -860,6 +892,7 @@
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
@@ -885,8 +918,9 @@
 # CONFIG_USB_LONG_TIMEOUT is not set
 
 #
-# USB Controllers
+# USB Host Controller Drivers
 #
+# CONFIG_USB_EHCI_HCD is not set
 # CONFIG_USB_UHCI is not set
 # CONFIG_USB_UHCI_ALT is not set
 CONFIG_USB_OHCI=y
@@ -895,7 +929,9 @@
 # USB Device Class drivers
 #
 # CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
 # CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -904,6 +940,7 @@
 # CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_HP8200e is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
 CONFIG_USB_ACM=m
 CONFIG_USB_PRINTER=m
@@ -912,7 +949,9 @@
 # USB Human Interface Devices (HID)
 #
 CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
 
 #
@@ -936,6 +975,7 @@
 # USB Network adaptors
 #
 # CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_CATC is not set
 # CONFIG_USB_CDCETHER is not set
@@ -950,6 +990,7 @@
 # USB Serial Converter support
 #
 CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_DEBUG is not set
 # CONFIG_USB_SERIAL_GENERIC is not set
 # CONFIG_USB_SERIAL_BELKIN is not set
 # CONFIG_USB_SERIAL_WHITEHEAT is not set
@@ -960,16 +1001,9 @@
 # CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
 # CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
 # CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
@@ -981,6 +1015,10 @@
 # USB Miscellaneous drivers
 #
 # CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
 
 #
 # Bluetooth support
@@ -988,8 +1026,20 @@
 # CONFIG_BLUEZ is not set
 
 #
+# Library routines
+#
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
 # Kernel hacking
 #
+CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_WAITQ is not set
 # CONFIG_KGDB is not set
 CONFIG_XMON=y
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_MORE_COMPILE_OPTIONS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/est8260_defconfig linux-2.4.20/arch/ppc/configs/est8260_defconfig
--- linux-2.4.19/arch/ppc/configs/est8260_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/est8260_defconfig	2002-10-29 11:18:48.000000000 +0000
@@ -81,11 +81,13 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=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)
@@ -136,13 +138,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -160,6 +155,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -210,11 +210,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -321,7 +323,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -353,6 +354,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -366,10 +369,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
@@ -400,6 +406,7 @@
 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_SMB_FS is not set
@@ -413,7 +420,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -429,6 +435,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
@@ -438,7 +445,7 @@
 # CONFIG_SOUND is not set
 
 #
-# MPC8260 Communication Options
+# MPC8260 CPM Options
 #
 # CONFIG_SCC_CONSOLE is not set
 CONFIG_SCC_ENET=y
@@ -446,121 +453,27 @@
 # CONFIG_FEC_ENET is not set
 
 #
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
+# Generic MPC8260 Options
 #
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_DCACHE_DISABLE is not set
 
 #
-#   SCSI support is needed for USB Storage
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
+# USB support
 #
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB is not set
 
 #
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/gemini_defconfig linux-2.4.20/arch/ppc/configs/gemini_defconfig
--- linux-2.4.19/arch/ppc/configs/gemini_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/gemini_defconfig	2002-10-29 11:18:39.000000000 +0000
@@ -32,12 +32,15 @@
 CONFIG_PPC_STD_MMU=y
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_PAL4 is not set
 CONFIG_GEMINI=y
 # CONFIG_SMP is not set
 CONFIG_ALTIVEC=y
 CONFIG_TAU=y
 # CONFIG_TAU_INT is not set
 # CONFIG_TAU_AVERAGE is not set
+CONFIG_PPC_ISATIMER=y
 
 #
 # General setup
@@ -88,11 +91,13 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -132,6 +137,7 @@
 # CONFIG_IP_NF_CONNTRACK is not set
 # CONFIG_IP_NF_QUEUE is not set
 # CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
 # CONFIG_IP_NF_COMPAT_IPCHAINS is not set
 # CONFIG_IP_NF_COMPAT_IPFWADM is not set
 # CONFIG_IPV6 is not set
@@ -149,13 +155,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -173,6 +172,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -301,11 +305,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -414,7 +420,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -446,6 +451,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -459,10 +466,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 # 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
@@ -493,6 +503,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
@@ -506,7 +517,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -526,6 +536,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
@@ -540,112 +551,25 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
+CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_WAITQ is not set
 # CONFIG_KGDB is not set
 CONFIG_XMON=y
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_MORE_COMPILE_OPTIONS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/ibmchrp_defconfig linux-2.4.20/arch/ppc/configs/ibmchrp_defconfig
--- linux-2.4.19/arch/ppc/configs/ibmchrp_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/ibmchrp_defconfig	2002-10-29 11:18:40.000000000 +0000
@@ -32,10 +32,13 @@
 CONFIG_PPC_STD_MMU=y
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
 # CONFIG_SMP is not set
 # CONFIG_ALTIVEC is not set
 # CONFIG_TAU is not set
+CONFIG_PPC_ISATIMER=y
 
 #
 # General setup
@@ -92,11 +95,13 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=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=y
 
 #
 # Multi-device support (RAID and LVM)
@@ -141,14 +146,19 @@
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
 CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
 CONFIG_IP_NF_MATCH_AH_ESP=m
 CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
 CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_UNCLEAN=m
 CONFIG_IP_NF_MATCH_OWNER=m
 CONFIG_IP_NF_FILTER=m
@@ -158,6 +168,7 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
@@ -165,6 +176,8 @@
 # CONFIG_IP_NF_TARGET_LOG is not set
 CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_COMPAT_IPCHAINS=m
 CONFIG_IP_NF_NAT_NEEDED=y
 # CONFIG_IP_NF_COMPAT_IPFWADM is not set
@@ -183,13 +196,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -207,6 +213,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -339,6 +350,7 @@
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -350,11 +362,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -365,11 +379,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -387,6 +403,7 @@
 CONFIG_TR=y
 CONFIG_IBMOL=y
 # CONFIG_IBMLS is not set
+# CONFIG_3C359 is not set
 # CONFIG_TMS380TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_RCPCI is not set
@@ -450,6 +467,7 @@
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
 CONFIG_FB_3DFX=y
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
@@ -502,6 +520,7 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_BRIQ_PANEL is not set
 
 #
 # I2C support
@@ -519,6 +538,7 @@
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
 
 #
 # Joysticks
@@ -560,7 +580,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -592,6 +611,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -605,10 +626,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
+CONFIG_JFS_FS=y
+# 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
@@ -639,6 +663,7 @@
 # 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
@@ -652,7 +677,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -672,6 +696,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 CONFIG_NLS=y
 
@@ -728,113 +753,25 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-# CONFIG_USB_HID is not set
-# CONFIG_USB_HIDDEV is not set
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_WACOM is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
+CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_WAITQ is not set
 # CONFIG_KGDB is not set
 CONFIG_XMON=y
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_MORE_COMPILE_OPTIONS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/mbx_defconfig linux-2.4.20/arch/ppc/configs/mbx_defconfig
--- linux-2.4.19/arch/ppc/configs/mbx_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/mbx_defconfig	2002-10-29 11:18:30.000000000 +0000
@@ -98,10 +98,12 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -150,13 +152,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -174,6 +169,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -224,11 +224,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -333,7 +335,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -365,6 +366,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -378,10 +381,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
@@ -412,6 +418,7 @@
 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_SMB_FS is not set
@@ -425,7 +432,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -441,6 +447,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
@@ -476,116 +483,17 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-
-#
-#   SCSI support is needed for USB Storage
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/oak_defconfig linux-2.4.20/arch/ppc/configs/oak_defconfig
--- linux-2.4.19/arch/ppc/configs/oak_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/oak_defconfig	2002-10-29 11:18:32.000000000 +0000
@@ -82,11 +82,13 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=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)
@@ -136,13 +138,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -160,6 +155,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -210,11 +210,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -320,7 +322,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -352,6 +353,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -365,10 +368,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
@@ -399,6 +405,7 @@
 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_SMB_FS is not set
@@ -412,7 +419,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -433,116 +439,17 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-
-#
-#   SCSI support is needed for USB Storage
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/pal4_defconfig linux-2.4.20/arch/ppc/configs/pal4_defconfig
--- linux-2.4.19/arch/ppc/configs/pal4_defconfig	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/pal4_defconfig	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,567 @@
+#
+# Automatically generated make config: 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
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_6xx=y
+# CONFIG_4xx is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_8260 is not set
+CONFIG_PPC_STD_MMU=y
+# CONFIG_ALL_PPC is not set
+# CONFIG_APUS is not set
+# CONFIG_SPRUCE is not set
+CONFIG_PAL4=y
+# CONFIG_GEMINI is not set
+# CONFIG_SMP is not set
+# CONFIG_ALTIVEC is not set
+# CONFIG_TAU is not set
+CONFIG_PPC_ISATIMER=y
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+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=m
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_PPC_RTC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="ip=on"
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=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=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
+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
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_UNCLEAN=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_MIRROR=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 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_SUNLANCE is not set
+# CONFIG_HAPPYMEAL 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 is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_TULIP is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+CONFIG_EEPRO100=y
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
+# CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_WINBOND_840 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_AIRO is not set
+CONFIG_HERMES=m
+# CONFIG_PLX_HERMES is not set
+# CONFIG_PCI_HERMES is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# 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
+#
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+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=m
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_PROC=m
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG 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
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_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=y
+# 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
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_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
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/pmac_defconfig linux-2.4.20/arch/ppc/configs/pmac_defconfig
--- linux-2.4.19/arch/ppc/configs/pmac_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/pmac_defconfig	2002-10-29 11:18:35.000000000 +0000
@@ -32,12 +32,15 @@
 CONFIG_PPC_STD_MMU=y
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
 # CONFIG_SMP is not set
 CONFIG_ALTIVEC=y
 CONFIG_TAU=y
 # CONFIG_TAU_INT is not set
 # CONFIG_TAU_AVERAGE is not set
+CONFIG_PPC_ISATIMER=y
 
 #
 # General setup
@@ -64,9 +67,9 @@
 #
 CONFIG_PCMCIA=m
 CONFIG_CARDBUS=y
+CONFIG_TCIC=y
 CONFIG_I82092=y
 CONFIG_I82365=y
-CONFIG_TCIC=y
 
 #
 # Parallel port support
@@ -102,11 +105,13 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=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)
@@ -151,14 +156,19 @@
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
 CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
 CONFIG_IP_NF_MATCH_AH_ESP=m
 CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
 CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_UNCLEAN=m
 CONFIG_IP_NF_MATCH_OWNER=m
 CONFIG_IP_NF_FILTER=m
@@ -168,6 +178,7 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
@@ -175,6 +186,8 @@
 # CONFIG_IP_NF_TARGET_LOG is not set
 CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_COMPAT_IPCHAINS=m
 CONFIG_IP_NF_NAT_NEEDED=y
 # CONFIG_IP_NF_COMPAT_IPFWADM is not set
@@ -193,13 +206,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -217,6 +223,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 CONFIG_IDE=y
@@ -233,6 +244,7 @@
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -247,6 +259,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 CONFIG_BLK_DEV_IDEFLOPPY=y
 CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -258,12 +271,15 @@
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -271,6 +287,7 @@
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
+# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
@@ -339,6 +356,7 @@
 CONFIG_SCSI_AIC7XXX=m
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
 CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
 # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
 CONFIG_SCSI_AIC7XXX_OLD=m
 # CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT is not set
@@ -384,6 +402,7 @@
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
+CONFIG_SCSI_MESH_RESET_DELAY_MS=500
 CONFIG_SCSI_MAC53C94=y
 
 #
@@ -399,9 +418,10 @@
 #
 # Device Drivers
 #
-CONFIG_IEEE1394_PCILYNX=m
-# CONFIG_IEEE1394_PCILYNX_LOCALRAM is not set
-# CONFIG_IEEE1394_PCILYNX_PORTS is not set
+
+#
+#   Texas Instruments PCILynx requires I2C bit-banging
+#
 CONFIG_IEEE1394_OHCI1394=m
 
 #
@@ -409,7 +429,11 @@
 #
 CONFIG_IEEE1394_VIDEO1394=m
 CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+CONFIG_IEEE1394_ETH1394=m
+# CONFIG_IEEE1394_DV1394 is not set
 CONFIG_IEEE1394_RAWIO=m
+# CONFIG_IEEE1394_CMP is not set
 # CONFIG_IEEE1394_VERBOSEDEBUG is not set
 
 #
@@ -458,6 +482,7 @@
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -469,11 +494,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -484,11 +511,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -516,6 +545,7 @@
 CONFIG_HERMES=m
 CONFIG_APPLE_AIRPORT=m
 # CONFIG_PLX_HERMES is not set
+CONFIG_PCI_HERMES=m
 
 #
 # Wireless Pcmcia cards support
@@ -656,6 +686,7 @@
 CONFIG_FB_RADEON=y
 CONFIG_FB_ATY128=y
 # CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
 CONFIG_FB_3DFX=y
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
@@ -717,6 +748,7 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_BRIQ_PANEL is not set
 
 #
 # I2C support
@@ -739,6 +771,7 @@
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
 
 #
 # Joysticks
@@ -780,7 +813,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -798,6 +830,7 @@
 # PCMCIA character devices
 #
 # CONFIG_PCMCIA_SERIAL_CS is not set
+# CONFIG_SYNCLINK_CS is not set
 
 #
 # Multimedia devices
@@ -817,6 +850,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 CONFIG_HFS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
 # CONFIG_BFS_FS is not set
 CONFIG_EXT3_FS=y
 CONFIG_JBD=y
@@ -830,10 +865,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 # 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
@@ -864,6 +902,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_SMB_FS=m
@@ -878,7 +917,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -898,6 +936,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 CONFIG_SMB_NLS=y
 CONFIG_NLS=y
 
@@ -949,8 +988,7 @@
 CONFIG_SOUND=m
 CONFIG_DMASOUND_PMAC=m
 CONFIG_DMASOUND=m
-CONFIG_I2C=m
-CONFIG_I2C_KEYWEST=m
+# CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
@@ -962,6 +1000,7 @@
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
@@ -987,8 +1026,9 @@
 # CONFIG_USB_LONG_TIMEOUT is not set
 
 #
-# USB Controllers
+# USB Host Controller Drivers
 #
+# CONFIG_USB_EHCI_HCD is not set
 # CONFIG_USB_UHCI is not set
 # CONFIG_USB_UHCI_ALT is not set
 CONFIG_USB_OHCI=y
@@ -997,7 +1037,9 @@
 # USB Device Class drivers
 #
 # CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
 # CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -1006,6 +1048,7 @@
 # CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_HP8200e is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
 CONFIG_USB_ACM=m
 CONFIG_USB_PRINTER=m
@@ -1014,7 +1057,9 @@
 # USB Human Interface Devices (HID)
 #
 CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
 
 #
@@ -1038,6 +1083,7 @@
 # USB Network adaptors
 #
 # CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_CATC is not set
 # CONFIG_USB_CDCETHER is not set
@@ -1052,6 +1098,7 @@
 # USB Serial Converter support
 #
 CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_DEBUG is not set
 # CONFIG_USB_SERIAL_GENERIC is not set
 # CONFIG_USB_SERIAL_BELKIN is not set
 # CONFIG_USB_SERIAL_WHITEHEAT is not set
@@ -1062,16 +1109,9 @@
 # CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
 # CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
 # CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
@@ -1083,6 +1123,10 @@
 # USB Miscellaneous drivers
 #
 # CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
 
 #
 # Bluetooth support
@@ -1090,8 +1134,20 @@
 # CONFIG_BLUEZ is not set
 
 #
+# Library routines
+#
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
 # Kernel hacking
 #
+CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_WAITQ is not set
 # CONFIG_KGDB is not set
 CONFIG_XMON=y
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_MORE_COMPILE_OPTIONS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/power3_defconfig linux-2.4.20/arch/ppc/configs/power3_defconfig
--- linux-2.4.19/arch/ppc/configs/power3_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/power3_defconfig	2002-10-29 11:18:34.000000000 +0000
@@ -30,6 +30,7 @@
 # CONFIG_8xx is not set
 CONFIG_PPC64BRIDGE=y
 CONFIG_ALL_PPC=y
+CONFIG_PPC_ISATIMER=y
 CONFIG_PPC_STD_MMU=y
 CONFIG_SMP=y
 # CONFIG_IRQ_ALL_CPUS is not set
@@ -100,11 +101,13 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=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=y
 
 #
 # Multi-device support (RAID and LVM)
@@ -152,13 +155,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -176,6 +172,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -310,6 +311,7 @@
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -321,11 +323,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -336,11 +340,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -358,6 +364,7 @@
 CONFIG_TR=y
 CONFIG_IBMOL=y
 # CONFIG_IBMLS is not set
+# CONFIG_3C359 is not set
 # CONFIG_TMS380TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_RCPCI is not set
@@ -423,6 +430,7 @@
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
@@ -478,6 +486,7 @@
 CONFIG_PRINTER=m
 # CONFIG_LP_CONSOLE is not set
 # CONFIG_PPDEV is not set
+# CONFIG_BRIQ_PANEL is not set
 
 #
 # I2C support
@@ -501,6 +510,7 @@
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
 
 #
 # Joysticks
@@ -542,7 +552,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -574,6 +583,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -587,10 +598,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 CONFIG_JOLIET=y
 # CONFIG_ZISOFS is not set
+CONFIG_JFS_FS=y
+# 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
@@ -621,6 +635,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
@@ -634,7 +649,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -691,6 +705,7 @@
 #
 CONFIG_SOUND=y
 # CONFIG_DMASOUND_PMAC is not set
+# CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
@@ -702,6 +717,7 @@
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
@@ -748,113 +764,26 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-# CONFIG_USB_HID is not set
-# CONFIG_USB_HIDDEV is not set
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_WACOM is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
+CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
 # CONFIG_KGDB is not set
 CONFIG_XMON=y
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_MORE_COMPILE_OPTIONS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/rpxcllf_defconfig linux-2.4.20/arch/ppc/configs/rpxcllf_defconfig
--- linux-2.4.19/arch/ppc/configs/rpxcllf_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/rpxcllf_defconfig	2002-10-29 11:18:35.000000000 +0000
@@ -98,11 +98,13 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=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)
@@ -153,13 +155,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -177,6 +172,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -227,11 +227,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -337,7 +339,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -369,6 +370,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -382,10 +385,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
@@ -416,6 +422,7 @@
 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_SMB_FS is not set
@@ -429,7 +436,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -445,6 +451,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
@@ -481,116 +488,17 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-
-#
-#   SCSI support is needed for USB Storage
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/rpxlite_defconfig linux-2.4.20/arch/ppc/configs/rpxlite_defconfig
--- linux-2.4.19/arch/ppc/configs/rpxlite_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/rpxlite_defconfig	2002-10-29 11:18:34.000000000 +0000
@@ -98,11 +98,13 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=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)
@@ -153,13 +155,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -177,6 +172,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -227,11 +227,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -337,7 +339,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -369,6 +370,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -382,10 +385,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
@@ -416,6 +422,7 @@
 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_SMB_FS is not set
@@ -429,7 +436,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -445,6 +451,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
@@ -478,116 +485,17 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-
-#
-#   SCSI support is needed for USB Storage
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/spruce_defconfig linux-2.4.20/arch/ppc/configs/spruce_defconfig
--- linux-2.4.19/arch/ppc/configs/spruce_defconfig	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/spruce_defconfig	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,506 @@
+#
+# Automatically generated make config: 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
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_6xx=y
+# CONFIG_4xx is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_8260 is not set
+CONFIG_PPC_STD_MMU=y
+# CONFIG_ALL_PPC is not set
+# CONFIG_APUS is not set
+CONFIG_SPRUCE=y
+# CONFIG_PAL4 is not set
+# CONFIG_GEMINI is not set
+# CONFIG_SMP is not set
+# CONFIG_ALTIVEC is not set
+# CONFIG_TAU is not set
+CONFIG_PPC_ISATIMER=y
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+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_PCI_NAMES is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+CONFIG_PPC_RTC=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="ip=on"
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# 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 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 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_SUNLANCE is not set
+# CONFIG_HAPPYMEAL 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 is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=y
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_TULIP is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
+# CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_WINBOND_840 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+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 is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG 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
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+# 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=y
+# 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
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 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_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
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/configs/walnut_defconfig linux-2.4.20/arch/ppc/configs/walnut_defconfig
--- linux-2.4.19/arch/ppc/configs/walnut_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/walnut_defconfig	2002-10-29 11:18:35.000000000 +0000
@@ -82,11 +82,13 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=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)
@@ -136,13 +138,6 @@
 # Appletalk devices
 #
 # CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -160,6 +155,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -210,11 +210,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -324,7 +326,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -356,6 +357,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_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
@@ -369,10 +372,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
@@ -403,6 +409,7 @@
 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_SMB_FS is not set
@@ -416,7 +423,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -437,116 +443,17 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-
-#
-#   SCSI support is needed for USB Storage
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/defconfig linux-2.4.20/arch/ppc/defconfig
--- linux-2.4.19/arch/ppc/defconfig	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.20/arch/ppc/defconfig	2002-10-29 11:18:35.000000000 +0000
@@ -32,12 +32,15 @@
 CONFIG_PPC_STD_MMU=y
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
 # CONFIG_SMP is not set
 CONFIG_ALTIVEC=y
 CONFIG_TAU=y
 # CONFIG_TAU_INT is not set
 # CONFIG_TAU_AVERAGE is not set
+CONFIG_PPC_ISATIMER=y
 
 #
 # General setup
@@ -74,6 +77,7 @@
 CONFIG_PPC_RTAS=y
 CONFIG_BOOTX_TEXT=y
 CONFIG_PREP_RESIDUAL=y
+CONFIG_PROC_PREPRESIDUAL=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyS0,9600 console=tty0 root=/dev/sda2"
 
@@ -96,12 +100,15 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=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)
@@ -146,13 +153,19 @@
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
 CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
 CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
 CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_UNCLEAN=m
 CONFIG_IP_NF_MATCH_OWNER=m
 CONFIG_IP_NF_FILTER=m
@@ -162,12 +175,16 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
 # CONFIG_IP_NF_MANGLE is not set
 # CONFIG_IP_NF_TARGET_LOG is not set
+CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_COMPAT_IPCHAINS=m
 CONFIG_IP_NF_NAT_NEEDED=y
 # CONFIG_IP_NF_COMPAT_IPFWADM is not set
@@ -181,6 +198,11 @@
 #
 # CONFIG_IPX is not set
 CONFIG_ATALK=m
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -198,6 +220,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 CONFIG_IDE=y
@@ -214,6 +241,7 @@
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -228,6 +256,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 CONFIG_BLK_DEV_IDEFLOPPY=y
 CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -239,12 +268,15 @@
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -252,6 +284,7 @@
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
+# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
@@ -316,9 +349,11 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
 CONFIG_SCSI_AIC7XXX=m
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
 CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
 # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
 CONFIG_SCSI_AIC7XXX_OLD=m
 # CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT is not set
@@ -364,6 +399,7 @@
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
+CONFIG_SCSI_MESH_RESET_DELAY_MS=4000
 CONFIG_SCSI_MAC53C94=y
 
 #
@@ -380,13 +416,6 @@
 # ARCnet devices
 #
 # CONFIG_ARCNET is not set
-
-#
-# Appletalk devices
-#
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_IPDDP is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
@@ -405,7 +434,6 @@
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -425,6 +453,7 @@
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -436,10 +465,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -450,11 +482,13 @@
 #
 # 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_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -482,6 +516,7 @@
 CONFIG_HERMES=m
 CONFIG_APPLE_AIRPORT=m
 # CONFIG_PLX_HERMES is not set
+# CONFIG_PCI_HERMES is not set
 CONFIG_NET_WIRELESS=y
 
 #
@@ -530,6 +565,7 @@
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_CLGEN is not set
 # CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_OF=y
 CONFIG_FB_CONTROL=y
@@ -552,8 +588,10 @@
 CONFIG_FB_RADEON=y
 CONFIG_FB_ATY128=y
 # CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
 CONFIG_FB_3DFX=y
 # CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -609,6 +647,7 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_BRIQ_PANEL is not set
 
 #
 # I2C support
@@ -631,6 +670,7 @@
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
 
 #
 # Joysticks
@@ -672,7 +712,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -704,6 +743,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 CONFIG_HFS_FS=m
+# 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
@@ -717,10 +758,13 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 # 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
@@ -751,6 +795,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
@@ -764,7 +809,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -784,6 +828,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 CONFIG_NLS=y
 
@@ -812,6 +857,7 @@
 # CONFIG_NLS_CODEPAGE_949 is not set
 # CONFIG_NLS_CODEPAGE_874 is not set
 # CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
@@ -834,8 +880,7 @@
 CONFIG_SOUND=m
 CONFIG_DMASOUND_PMAC=m
 CONFIG_DMASOUND=m
-CONFIG_I2C=m
-CONFIG_I2C_KEYWEST=m
+# CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
@@ -847,6 +892,7 @@
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
@@ -872,8 +918,9 @@
 # CONFIG_USB_LONG_TIMEOUT is not set
 
 #
-# USB Controllers
+# USB Host Controller Drivers
 #
+# CONFIG_USB_EHCI_HCD is not set
 # CONFIG_USB_UHCI is not set
 # CONFIG_USB_UHCI_ALT is not set
 CONFIG_USB_OHCI=y
@@ -882,7 +929,9 @@
 # USB Device Class drivers
 #
 # CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
 # CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -891,6 +940,7 @@
 # CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_HP8200e is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
 CONFIG_USB_ACM=m
 CONFIG_USB_PRINTER=m
@@ -899,7 +949,9 @@
 # USB Human Interface Devices (HID)
 #
 CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
 
 #
@@ -923,6 +975,7 @@
 # USB Network adaptors
 #
 # CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_CATC is not set
 # CONFIG_USB_CDCETHER is not set
@@ -937,6 +990,7 @@
 # USB Serial Converter support
 #
 CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_DEBUG is not set
 # CONFIG_USB_SERIAL_GENERIC is not set
 # CONFIG_USB_SERIAL_BELKIN is not set
 # CONFIG_USB_SERIAL_WHITEHEAT is not set
@@ -944,19 +998,14 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 CONFIG_USB_SERIAL_VISOR=m
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
 # CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
@@ -966,6 +1015,10 @@
 # USB Miscellaneous drivers
 #
 # CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
 
 #
 # Bluetooth support
@@ -973,8 +1026,20 @@
 # CONFIG_BLUEZ is not set
 
 #
+# Library routines
+#
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
 # Kernel hacking
 #
+CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_WAITQ is not set
 # CONFIG_KGDB is not set
 CONFIG_XMON=y
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_MORE_COMPILE_OPTIONS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/Makefile linux-2.4.20/arch/ppc/kernel/Makefile
--- linux-2.4.19/arch/ppc/kernel/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/Makefile	2002-10-29 11:18:49.000000000 +0000
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.Makefile 1.41 04/16/02 20:08:22 paulus
+# BK Id: %F% %I% %G% %U% %#%
 #
 #
 # Makefile for the linux kernel.
@@ -14,9 +14,9 @@
 ifdef CONFIG_PPC64BRIDGE
 EXTRA_AFLAGS		:= -Wa,-mppc64bridge
 endif
-
-# Extra CFLAGS so we don't have to do relative includes
-CFLAGS_pmac_setup.o	+= -I$(TOPDIR)/arch/$(ARCH)/mm -I$(TOPDIR)/drivers/scsi
+ifdef CONFIG_4xx
+EXTRA_AFLAGS		:= -Wa,-m405
+endif
 
 # Code in these files is used before the kernel is moved to its final position
 CFLAGS_prom_init.o	+= -mrelocatable-lib
@@ -24,6 +24,7 @@
 
 # Start off with 'head.o', change as needed.
 HEAD-y				:= head.o
+HEAD-$(CONFIG_6xx)		+= idle_6xx.o
 HEAD-$(CONFIG_4xx)		:= head_4xx.o
 HEAD-$(CONFIG_8xx)		:= head_8xx.o
 
@@ -31,7 +32,7 @@
 
 O_TARGET := kernel.o
 
-export-objs			:= ppc_ksyms.o prep_setup.o time.o
+export-objs			:= ppc_ksyms.o time.o
 
 obj-y				:= entry.o traps.o irq.o idle.o time.o misc.o \
 					process.o signal.o ptrace.o align.o \
@@ -39,17 +40,12 @@
 					cputable.o ppc_htab.o
 obj-$(CONFIG_6xx)		+= l2cr.o
 obj-$(CONFIG_MODULES)		+= ppc_ksyms.o
-obj-$(CONFIG_POWER4)		+= xics.o
-obj-$(CONFIG_PCI)		+= pci.o pci-dma.o
+obj-$(CONFIG_PCI)		+= pci.o 
+obj-$(CONFIG_PCI)		+= pci-dma.o
 obj-$(CONFIG_KGDB)		+= ppc-stub.o
 obj-$(CONFIG_SMP)		+= smp.o
-obj-$(CONFIG_4xx)		+= ppc4xx_pic.o
-obj-$(CONFIG_OAK)		+= oak_setup.o
-obj-$(CONFIG_WALNUT)		+= walnut_setup.o
 obj-$(CONFIG_TAU)		+= temp.o
-ifeq ($(CONFIG_WALNUT),y)
-obj-$(CONFIG_PCI)		+= galaxy_pci.o
-endif
+obj-$(CONFIG_4xx)		+= ppc4xx_pic.o
 obj-$(CONFIG_8xx)		+= m8xx_setup.o ppc8xx_pic.o
 ifeq ($(CONFIG_8xx),y)
 obj-$(CONFIG_PCI)		+= qspan_pci.o
@@ -58,30 +54,14 @@
 endif
 endif
 obj-$(CONFIG_MBX)		+= i8259.o
-obj-$(CONFIG_APUS)		+= apus_setup.o
-ifeq ($(CONFIG_APUS),y)
-obj-$(CONFIG_PCI)		+= apus_pci.o
-endif
-obj-$(CONFIG_ALL_PPC)		+= pmac_pic.o pmac_setup.o pmac_time.o prom.o \
-					prom_init.o pmac_feature.o pmac_pci.o \
-					chrp_setup.o chrp_time.o chrp_pci.o \
-					open_pic.o indirect_pci.o i8259.o \
-					prep_pci.o prep_time.o prep_nvram.o \
-					prep_setup.o
-obj-$(CONFIG_NVRAM)		+= pmac_nvram.o
-obj-$(CONFIG_PMAC_BACKLIGHT)	+= pmac_backlight.o
-obj-$(CONFIG_PMAC_PBOOK)	+= sleep.o
-obj-$(CONFIG_PREP_RESIDUAL)	+= residual.o
-obj-$(CONFIG_PPC_RTAS)		+= error_log.o proc_rtas.o
-obj-$(CONFIG_GEMINI)		+= gemini_prom.o gemini_pci.o gemini_setup.o \
-					open_pic.o
+obj-$(CONFIG_ALL_PPC)		+= prom_init.o prom.o open_pic.o \
+					indirect_pci.o i8259.o prep_nvram.o
+obj-$(CONFIG_GEMINI)		+= open_pic.o
+obj-$(CONFIG_PAL4)		+= indirect_pci.o pci_auto.o todc_time.o
+obj-$(CONFIG_SPRUCE)		+= indirect_pci.o pci_auto.o todc_time.o
 obj-$(CONFIG_8260)		+= m8260_setup.o ppc8260_pic.o
 obj-$(CONFIG_BOOTX_TEXT)	+= btext.o
 
-ifeq ($(CONFIG_SMP),y)
-obj-$(CONFIG_ALL_PPC)		+= pmac_smp.o chrp_smp.o
-endif
-
 include $(TOPDIR)/Rules.make
 
 entry.o: entry.S ppc_defs.h
@@ -90,7 +70,7 @@
 head.o: head.S ppc_defs.h
 head_4xx.o: head_4xx.S ppc_defs.h
 head_8xx.o: head_8xx.S ppc_defs.h
-gemini_prom.o: gemini_prom.S ppc_defs.h
+idle_6xx.o: idle_6xx.S ppc_defs.h
 
 ppc_defs.h: mk_defs.c ppc_defs.head \
 		$(TOPDIR)/include/asm/mmu.h \
@@ -110,4 +90,3 @@
 checks: checks.c
 	$(HOSTCC) -I$(HPATH) $(HOSTCFLAGS) -D__KERNEL__ -fno-builtin -o checks checks.c
 	./checks
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/apus_pci.c linux-2.4.20/arch/ppc/kernel/apus_pci.c
--- linux-2.4.19/arch/ppc/kernel/apus_pci.c	2001-09-08 19:38:41.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/apus_pci.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,187 +0,0 @@
-/*
- * BK Id: SCCS/s.apus_pci.c 1.5 09/08/01 15:47:42 paulus
- */
-/*
- * Copyright (C) Michel Dnzer <michdaen@iiic.ethz.ch>
- *
- * APUS PCI routines.
- *
- * Currently, only B/CVisionPPC cards (Permedia2) are supported.
- *
- * Thanks to Geert Uytterhoeven for the idea:
- * Read values from given config space(s) for the first devices, -1 otherwise
- *
- */
-
-#include <linux/config.h>
-#ifdef CONFIG_AMIGA
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-
-#include <asm/io.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-
-#include "apus_pci.h"
-
-
-/* These definitions are mostly adapted from pm2fb.c */
-
-#undef APUS_PCI_MASTER_DEBUG
-#ifdef APUS_PCI_MASTER_DEBUG
-#define DPRINTK(a,b...)	printk(KERN_DEBUG "apus_pci: %s: " a, __FUNCTION__ , ## b)
-#else
-#define DPRINTK(a,b...)
-#endif 
-
-/*
- * The _DEFINITIVE_ memory mapping/unmapping functions.
- * This is due to the fact that they're changing soooo often...
- */
-#define DEFW()		wmb()
-#define DEFR()		rmb()
-#define DEFRW()		mb()
-
-#define DEVNO(d)	((d)>>3)
-#define FNNO(d)		((d)&7)
-
-
-extern unsigned long powerup_PCI_present;
-
-static struct pci_controller *apus_hose;
-
-
-void *pci_io_base(unsigned int bus)
-{
-	return 0;
-}
-
-
-#define cfg_read(val, addr, type, op)	*val = op((type)(addr))
-#define cfg_write(val, addr, type, op)	op((val), (type *)(addr)); DEFW()
-#define cfg_read_bad	*val = ~0;
-#define cfg_write_bad	;
-#define cfg_read_val(val)	*val
-#define cfg_write_val(val)	val
-
-#define APUS_PCI_OP(rw, size, type, op, mask)					\
-int									\
-apus_pcibios_##rw##_config_##size(struct pci_dev *dev, int offset, type val)	\
-{										\
-	int fnno = FNNO(dev->devfn);						\
-	int devno = DEVNO(dev->devfn);						\
-										\
-	if (dev->bus->number > 0 || devno != 1) {				\
-		cfg_##rw##_bad;							\
-		return PCIBIOS_DEVICE_NOT_FOUND;				\
-	}									\
-	/* base address + function offset + offset ^ endianness conversion */	\
-	cfg_##rw(val, apus_hose->cfg_data + (fnno<<5) + (offset ^ mask),	\
-		 type, op);							\
-										\
-	DPRINTK(#op " b: 0x%x, d: 0x%x, f: 0x%x, o: 0x%x, v: 0x%x\n",		\
-		dev->bus->number, dev->devfn>>3, dev->devfn&7,			\
-		offset, cfg_##rw##_val(val));					\
-	return PCIBIOS_SUCCESSFUL;						\
-}
-
-APUS_PCI_OP(read, byte, u8 *, readb, 3)
-APUS_PCI_OP(read, word, u16 *, readw, 2)
-APUS_PCI_OP(read, dword, u32 *, readl, 0)
-APUS_PCI_OP(write, byte, u8, writeb, 3)
-APUS_PCI_OP(write, word, u16, writew, 2)
-APUS_PCI_OP(write, dword, u32, writel, 0)
-
-
-static struct pci_ops apus_pci_ops = {
-	apus_pcibios_read_config_byte,
-	apus_pcibios_read_config_word,
-	apus_pcibios_read_config_dword,
-	apus_pcibios_write_config_byte,
-	apus_pcibios_write_config_word,
-	apus_pcibios_write_config_dword
-};
-
-static struct resource pci_mem = { "B/CVisionPPC PCI mem", CVPPC_FB_APERTURE_ONE, CVPPC_PCI_CONFIG, IORESOURCE_MEM };
-
-void __init
-apus_pcibios_fixup(void)
-{
-/*	struct pci_dev *dev = pci_find_slot(0, 1<<3);
-	unsigned int reg, val, offset;*/
-
-	/* FIXME: interrupt? */
-	/*dev->interrupt = xxx;*/
-
-        request_resource(&iomem_resource, &pci_mem);
-    	printk("%s: PCI mem resource requested\n", __FUNCTION__);
-}
-
-static void __init apus_pcibios_fixup_bus(struct pci_bus *bus)
-{
-        bus->resource[1] = &pci_mem;
-}
-
-
-/* 
- * This is from pm2fb.c again
- * 
- * Check if PCI (B/CVisionPPC) is available, initialize it and set up
- * the pcibios_* pointers
- */
-
-
-void __init
-apus_setup_pci_ptrs(void)
-{
-	if (!powerup_PCI_present) {
-		DPRINTK("no PCI bridge detected\n");
-		return;
-	}
-	DPRINTK("Phase5 B/CVisionPPC PCI bridge detected.\n");
-
-	apus_hose = pcibios_alloc_controller();
-	if (!apus_hose) {
-		printk("apus_pci: Can't allocate PCI controller structure\n");
-		return;
-	}
-
-	if (!(apus_hose->cfg_data = ioremap(CVPPC_PCI_CONFIG, 256))) {
-		printk("apus_pci: unable to map PCI config region\n");
-		return;
-	}
-
-	if (!(apus_hose->cfg_addr = ioremap(CSPPC_PCI_BRIDGE, 256))) {
-		printk("apus_pci: unable to map PCI bridge\n");
-		return;
-	}
-
-	writel(CSPPCF_BRIDGE_BIG_ENDIAN, apus_hose->cfg_addr + CSPPC_BRIDGE_ENDIAN);
-	DEFW();
-
-	writel(CVPPC_REGS_REGION,  apus_hose->cfg_data+ PCI_BASE_ADDRESS_0);
-	DEFW();
-	writel(CVPPC_FB_APERTURE_ONE, apus_hose->cfg_data + PCI_BASE_ADDRESS_1);
-	DEFW();
-	writel(CVPPC_FB_APERTURE_TWO, apus_hose->cfg_data + PCI_BASE_ADDRESS_2);
-	DEFW();
-	writel(CVPPC_ROM_ADDRESS, apus_hose->cfg_data + PCI_ROM_ADDRESS);
-	DEFW();
-
-	writel(0xef000000 | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-		PCI_COMMAND_MASTER, apus_hose->cfg_data + PCI_COMMAND);
-	DEFW();
-
-	apus_hose->first_busno = 0;
-	apus_hose->last_busno = 0;
-	apus_hose->ops = &apus_pci_ops;
-	ppc_md.pcibios_fixup = apus_pcibios_fixup;
-	ppc_md.pcibios_fixup_bus = apus_pcibios_fixup_bus;
-
-	return;
-}
-
-#endif /* CONFIG_AMIGA */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/apus_pci.h linux-2.4.20/arch/ppc/kernel/apus_pci.h
--- linux-2.4.19/arch/ppc/kernel/apus_pci.h	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/apus_pci.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,40 +0,0 @@
-/*
- * BK Id: SCCS/s.apus_pci.h 1.4 05/17/01 18:14:21 cort
- */
-/*
- * Phase5 CybervisionPPC (TVP4020) definitions for the Permedia2 framebuffer
- * driver.
- *
- * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
- * --------------------------------------------------------------------------
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- */
-
-#ifndef APUS_PCI_H
-#define APUS_PCI_H
-
-
-#include "pci.h"
-
-
-#define CSPPC_PCI_BRIDGE		0xfffe0000
-#define CSPPC_BRIDGE_ENDIAN		0x0000
-#define CSPPC_BRIDGE_INT		0x0010
-
-#define	CVPPC_PCI_CONFIG		0xfffc0000
-#define CVPPC_ROM_ADDRESS		0xe2000001
-#define CVPPC_REGS_REGION		0xef000000
-#define CVPPC_FB_APERTURE_ONE		0xe0000000
-#define CVPPC_FB_APERTURE_TWO		0xe1000000
-#define CVPPC_FB_SIZE			0x00800000
-
-/* CVPPC_BRIDGE_ENDIAN */
-#define CSPPCF_BRIDGE_BIG_ENDIAN	0x02
-
-/* CVPPC_BRIDGE_INT */
-#define CSPPCF_BRIDGE_ACTIVE_INT2	0x01
-
-
-#endif	/* APUS_PCI_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/apus_setup.c linux-2.4.20/arch/ppc/kernel/apus_setup.c
--- linux-2.4.19/arch/ppc/kernel/apus_setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/apus_setup.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1113 +0,0 @@
-/*
- * BK Id: SCCS/s.apus_setup.c 1.24 11/13/01 21:26:07 paulus
- */
-/*
- *  linux/arch/ppc/kernel/apus_setup.c
- *
- *  Copyright (C) 1998, 1999  Jesper Skov
- *
- *  Basically what is needed to replace functionality found in
- *  arch/m68k allowing Amiga drivers to work under APUS.
- *  Bits of code and/or ideas from arch/m68k and arch/ppc files.
- *
- * TODO:
- *  This file needs a *really* good cleanup. Restructure and optimize.
- *  Make sure it can be compiled for non-APUS configs. Begin to move
- *  Amiga specific stuff into mach/amiga.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kd.h>
-#include <linux/init.h>
-#include <linux/hdreg.h>
-#include <linux/blk.h>
-#include <linux/pci.h>
-#include <linux/seq_file.h>
-
-#ifdef CONFIG_APUS
-#include <asm/logging.h>
-#endif
-
-/* Needs INITSERIAL call in head.S! */
-#undef APUS_DEBUG
-
-
-#include <linux/ide.h>
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
-static u_short driveid_types[] = {
-        D_SHORT(10),    /* config - vendor2 */
-        D_TEXT(20),     /* serial_no */
-        D_SHORT(3),     /* buf_type, buf_size - ecc_bytes */
-        D_TEXT(48),     /* fw_rev - model */
-        D_CHAR(2),      /* max_multsect - vendor3 */
-        D_SHORT(1),     /* dword_io */
-        D_CHAR(2),      /* vendor4 - capability */
-        D_SHORT(1),     /* reserved50 */
-        D_CHAR(4),      /* vendor5 - tDMA */
-        D_SHORT(4),     /* field_valid - cur_sectors */
-        D_INT(1),       /* cur_capacity */
-        D_CHAR(2),      /* multsect - multsect_valid */
-        D_INT(1),       /* lba_capacity */
-        D_SHORT(194)    /* dma_1word - reservedyy */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-
-#include <asm/bootinfo.h>
-#include <asm/setup.h>
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#include <asm/amigappc.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/machdep.h>
-
-#include "local_irq.h"
-
-unsigned long m68k_machtype;
-char debug_device[6] = "";
-
-extern void amiga_init_IRQ(void);
-
-void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;
-/* machine dependent keyboard functions */
-int (*mach_keyb_init) (void) __initdata = NULL;
-int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
-void (*mach_kbd_leds) (unsigned int) = NULL;
-/* machine dependent irq functions */
-void (*mach_init_IRQ) (void) __initdata = NULL;
-void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
-void (*mach_get_model) (char *model) = NULL;
-int (*mach_get_hardware_list) (char *buffer) = NULL;
-int (*mach_get_irq_list) (char *) = NULL;
-void (*mach_process_int) (int, struct pt_regs *) = NULL;
-/* machine dependent timer functions */
-unsigned long (*mach_gettimeoffset) (void);
-void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
-int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
-int (*mach_set_clock_mmss) (unsigned long) = NULL;
-void (*mach_reset)( void );
-long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
-#if defined(CONFIG_AMIGA_FLOPPY)
-void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
-#endif
-#ifdef CONFIG_HEARTBEAT
-void (*mach_heartbeat) (int) = NULL;
-extern void apus_heartbeat (void);
-#endif
-
-extern unsigned long amiga_model;
-extern unsigned decrementer_count;/* count value for 1e6/HZ microseconds */
-extern unsigned count_period_num; /* 1 decrementer count equals */
-extern unsigned count_period_den; /* count_period_num / count_period_den us */
-
-int num_memory = 0;
-struct mem_info memory[NUM_MEMINFO];/* memory description */
-/* FIXME: Duplicate memory data to avoid conflicts with m68k shared code. */
-int m68k_realnum_memory = 0;
-struct mem_info m68k_memory[NUM_MEMINFO];/* memory description */
-
-struct mem_info ramdisk;
-
-extern void amiga_floppy_setup(char *, int *);
-extern void config_amiga(void);
-
-static int __60nsram = 0;
-
-/* for cpuinfo */
-static int __bus_speed = 0;
-static int __speed_test_failed = 0;
-
-/********************************************** COMPILE PROTECTION */
-/* Provide some stubs that links to Amiga specific functions. 
- * This allows CONFIG_APUS to be removed from generic PPC files while
- * preventing link errors for other PPC targets.
- */
-unsigned long apus_get_rtc_time(void)
-{
-#ifdef CONFIG_APUS
-	extern unsigned long m68k_get_rtc_time(void);
-	
-	return m68k_get_rtc_time ();
-#else
-	return 0;
-#endif
-}
-
-int apus_set_rtc_time(unsigned long nowtime)
-{
-#ifdef CONFIG_APUS
-	extern int m68k_set_rtc_time(unsigned long nowtime);
-
-	return m68k_set_rtc_time (nowtime);
-#else
-	return 0;
-#endif
-}
-
-
-
-/* Here some functions we don't support, but which the other ports reference */
-int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
-{
-	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
-	return 0; 
-}
-int pckbd_getkeycode(unsigned int scancode) 
-{ 
-	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
-	return 0; 
-}
-int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-		    char raw_mode) 
-{
-	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
-	return 0; 
-}
-char pckbd_unexpected_up(unsigned char keycode)
-{
-	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
-	return 0;
-}
-void pckbd_leds(unsigned char leds)
-{
-	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
-}
-void pckbd_init_hw(void)
-{
-	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
-}
-unsigned char pckbd_sysrq_xlate[128];
-
-struct pci_bus * __init pci_scan_peer_bridge(int bus)
-{
-	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
-	return NULL;
-}
-
-/*********************************************************** SETUP */
-/* From arch/m68k/kernel/setup.c. */
-void __init apus_setup_arch(void)
-{
-#ifdef CONFIG_APUS
-	extern char cmd_line[];
-	int i;
-	char *p, *q;
-
-	/* Let m68k-shared code know it should do the Amiga thing. */
-	m68k_machtype = MACH_AMIGA;
-
-	/* Parse the command line for arch-specific options.
-	 * For the m68k, this is currently only "debug=xxx" to enable printing
-	 * certain kernel messages to some machine-specific device.  */
-	for( p = cmd_line; p && *p; ) {
-	    i = 0;
-	    if (!strncmp( p, "debug=", 6 )) {
-		    strncpy( debug_device, p+6, sizeof(debug_device)-1 );
-		    debug_device[sizeof(debug_device)-1] = 0;
-		    if ((q = strchr( debug_device, ' ' ))) *q = 0;
-		    i = 1;
-	    } else if (!strncmp( p, "60nsram", 7 )) {
-		    APUS_WRITE (APUS_REG_WAITSTATE, 
-				REGWAITSTATE_SETRESET
-				|REGWAITSTATE_PPCR
-				|REGWAITSTATE_PPCW);
-		    __60nsram = 1;
-		    i = 1;
-	    }
-
-	    if (i) {
-		/* option processed, delete it */
-		if ((q = strchr( p, ' ' )))
-		    strcpy( p, q+1 );
-		else
-		    *p = 0;
-	    } else {
-		if ((p = strchr( p, ' ' ))) ++p;
-	    }
-	}
-
-	config_amiga();
-
-#if 0 /* Enable for logging - also include logging.o in Makefile rule */
-	{
-#define LOG_SIZE 4096
-		void* base;
-
-		/* Throw away some memory - the P5 firmare stomps on top
-		 * of CHIP memory during bootup.
-		 */
-		amiga_chip_alloc(0x1000);
-
-		base = amiga_chip_alloc(LOG_SIZE+sizeof(klog_data_t));
-		LOG_INIT(base, base+sizeof(klog_data_t), LOG_SIZE);
-	}
-#endif
-#endif
-}
-
-int
-apus_show_cpuinfo(struct seq_file *m)
-{
-	extern int __map_without_bats;
-	extern unsigned long powerup_PCI_present;
-
-	seq_printf(m, "machine\t\t: Amiga\n");
-	seq_printf(m, "bus speed\t: %d%s", __bus_speed,
-		   (__speed_test_failed) ? " [failed]\n" : "\n");
-	seq_printf(m, "using BATs\t: %s\n",
-		   (__map_without_bats) ? "No" : "Yes");
-	seq_printf(m, "ram speed\t: %dns\n", (__60nsram) ? 60 : 70);
-	seq_printf(m, "PCI bridge\t: %s\n",
-		   (powerup_PCI_present) ? "Yes" : "No");
-	return 0;
-}
-
-static void get_current_tb(unsigned long long *time)
-{
-	__asm __volatile ("1:mftbu 4      \n\t"
-			  "  mftb  5      \n\t"
-			  "  mftbu 6      \n\t"
-			  "  cmpw  4,6    \n\t"
-			  "  bne   1b     \n\t"
-			  "  stw   4,0(%0)\n\t"
-			  "  stw   5,4(%0)\n\t"
-			  : 
-			  : "r" (time)
-			  : "r4", "r5", "r6");
-}
-
-
-void apus_calibrate_decr(void)
-{
-#ifdef CONFIG_APUS
-	unsigned long freq;
-
-	/* This algorithm for determining the bus speed was
-           contributed by Ralph Schmidt. */
-	unsigned long long start, stop;
-	int bus_speed;
-	int speed_test_failed = 0;
-
-	{
-		unsigned long loop = amiga_eclock / 10;
-
-		get_current_tb (&start);
-		while (loop--) {
-			unsigned char tmp;
-
-			tmp = ciaa.pra;
-		}
-		get_current_tb (&stop);
-	}
-
-	bus_speed = (((unsigned long)(stop-start))*10*4) / 1000000;
-	if (AMI_1200 == amiga_model)
-		bus_speed /= 2;
-
-	if ((bus_speed >= 47) && (bus_speed < 53)) {
-		bus_speed = 50;
-		freq = 12500000;
-	} else if ((bus_speed >= 57) && (bus_speed < 63)) {
-		bus_speed = 60;
-		freq = 15000000;
-	} else if ((bus_speed >= 63) && (bus_speed < 69)) {
-		bus_speed = 67;
-		freq = 16666667;
-	} else {
-		printk ("APUS: Unable to determine bus speed (%d). "
-			"Defaulting to 50MHz", bus_speed);
-		bus_speed = 50;
-		freq = 12500000;
-		speed_test_failed = 1;
-	}
-
-	/* Ease diagnostics... */
-	{
-		extern int __map_without_bats;
-		extern unsigned long powerup_PCI_present;
-
-		printk ("APUS: BATs=%d, BUS=%dMHz",
-			(__map_without_bats) ? 0 : 1,
-			bus_speed);
-		if (speed_test_failed)
-			printk ("[FAILED - please report]");
-
-		printk (", RAM=%dns, PCI bridge=%d\n",
-			(__60nsram) ? 60 : 70,
-			(powerup_PCI_present) ? 1 : 0);
-
-		/* print a bit more if asked politely... */
-		if (!(ciaa.pra & 0x40)){
-			extern unsigned int bat_addrs[4][3];
-			int b;
-			for (b = 0; b < 4; ++b) {
-				printk ("APUS: BAT%d ", b);
-				printk ("%08x-%08x -> %08x\n",
-					bat_addrs[b][0],
-					bat_addrs[b][1],
-					bat_addrs[b][2]);
-			}
-		}
-
-	}
-
-        printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
-	       freq/1000000, freq%1000000);
-	tb_ticks_per_jiffy = freq / HZ;
-	tb_to_us = mulhwu_scale_factor(freq, 1000000);
-
-	__bus_speed = bus_speed;
-	__speed_test_failed = speed_test_failed;
-#endif
-}
-
-void arch_gettod(int *year, int *mon, int *day, int *hour,
-		 int *min, int *sec)
-{
-#ifdef CONFIG_APUS
-	if (mach_gettod)
-		mach_gettod(year, mon, day, hour, min, sec);
-	else
-		*year = *mon = *day = *hour = *min = *sec = 0;
-#endif
-}
-
-/* for "kbd-reset" cmdline param */
-__init
-void kbd_reset_setup(char *str, int *ints)
-{
-}
-
-/*********************************************************** FLOPPY */
-#if defined(CONFIG_AMIGA_FLOPPY)
-__init 
-void floppy_setup(char *str, int *ints)
-{
-	if (mach_floppy_setup)
-		mach_floppy_setup (str, ints);
-}
-#endif
-
-/*********************************************************** MEMORY */
-#define KMAP_MAX 32
-unsigned long kmap_chunks[KMAP_MAX*3];
-int kmap_chunk_count = 0;
-
-/* From pgtable.h */
-static __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va)
-{
-	pgd_t *dir = 0;
-	pmd_t *pmd = 0;
-	pte_t *pte = 0;
-
-	va &= PAGE_MASK;
-	
-	dir = pgd_offset( mm, va );
-	if (dir)
-	{
-		pmd = pmd_offset(dir, va & PAGE_MASK);
-		if (pmd && pmd_present(*pmd))
-		{
-			pte = pte_offset(pmd, va);
-		}
-	}
-	return pte;
-}
-
-
-/* Again simulating an m68k/mm/kmap.c function. */
-void kernel_set_cachemode( unsigned long address, unsigned long size,
-			   unsigned int cmode )
-{
-	unsigned long mask, flags;
-
-	switch (cmode)
-	{
-	case IOMAP_FULL_CACHING:
-		mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED);
-		flags = 0;
-		break;
-	case IOMAP_NOCACHE_SER:
-		mask = ~0;
-		flags = (_PAGE_NO_CACHE | _PAGE_GUARDED);
-		break;
-	default:
-		panic ("kernel_set_cachemode() doesn't support mode %d\n", 
-		       cmode);
-		break;
-	}
-	
-	size /= PAGE_SIZE;
-	address &= PAGE_MASK;
-	while (size--)
-	{
-		pte_t *pte;
-
-		pte = my_find_pte(&init_mm, address);
-		if ( !pte )
-		{
-			printk("pte NULL in kernel_set_cachemode()\n");
-			return;
-		}
-
-                pte_val (*pte) &= mask;
-                pte_val (*pte) |= flags;
-                flush_tlb_page(find_vma(&init_mm,address),address);
-
-		address += PAGE_SIZE;
-	}
-}
-
-unsigned long mm_ptov (unsigned long paddr)
-{
-	unsigned long ret;
-	if (paddr < 16*1024*1024)
-		ret = ZTWO_VADDR(paddr);
-	else {
-		int i;
-
-		for (i = 0; i < kmap_chunk_count;){
-			unsigned long phys = kmap_chunks[i++];
-			unsigned long size = kmap_chunks[i++];
-			unsigned long virt = kmap_chunks[i++];
-			if (paddr >= phys
-			    && paddr < (phys + size)){
-				ret = virt + paddr - phys;
-				goto exit;
-			}
-		}
-		
-		ret = (unsigned long) __va(paddr);
-	}
-exit:
-#ifdef DEBUGPV
-	printk ("PTOV(%lx)=%lx\n", paddr, ret);
-#endif
-	return ret;
-}
-
-int mm_end_of_chunk (unsigned long addr, int len)
-{
-	if (memory[0].addr + memory[0].size == addr + len)
-		return 1;
-	return 0;
-}
-
-/*********************************************************** CACHE */
-
-#define L1_CACHE_BYTES 32
-#define MAX_CACHE_SIZE 8192
-void cache_push(__u32 addr, int length)
-{
-	addr = mm_ptov(addr);
-
-	if (MAX_CACHE_SIZE < length)
-		length = MAX_CACHE_SIZE;
-
-	while(length > 0){
-		__asm ("dcbf 0,%0\n\t"
-		       : : "r" (addr));
-		addr += L1_CACHE_BYTES;
-		length -= L1_CACHE_BYTES;
-	}
-	/* Also flush trailing block */
-	__asm ("dcbf 0,%0\n\t"
-	       "sync \n\t"
-	       : : "r" (addr));
-}
-
-void cache_clear(__u32 addr, int length)
-{
-	if (MAX_CACHE_SIZE < length)
-		length = MAX_CACHE_SIZE;
-
-	addr = mm_ptov(addr);
-
-	__asm ("dcbf 0,%0\n\t"
-	       "sync \n\t"
-	       "icbi 0,%0 \n\t"
-	       "isync \n\t"
-	       : : "r" (addr));
-	
-	addr += L1_CACHE_BYTES;
-	length -= L1_CACHE_BYTES;
-
-	while(length > 0){
-		__asm ("dcbf 0,%0\n\t"
-		       "sync \n\t"
-		       "icbi 0,%0 \n\t"
-		       "isync \n\t"
-		       : : "r" (addr));
-		addr += L1_CACHE_BYTES;
-		length -= L1_CACHE_BYTES;
-	}
-
-	__asm ("dcbf 0,%0\n\t"
-	       "sync \n\t"
-	       "icbi 0,%0 \n\t"
-	       "isync \n\t"
-	       : : "r" (addr));
-}
-
-/****************************************************** from setup.c */
-void
-apus_restart(char *cmd)
-{
-	cli();
-
-	APUS_WRITE(APUS_REG_LOCK, 
-		   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2);
-	APUS_WRITE(APUS_REG_LOCK, 
-		   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3);
-	APUS_WRITE(APUS_REG_LOCK, 
-		   REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3);
-	APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET);
-	APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET);
-	for(;;);
-}
-
-void
-apus_power_off(void)
-{
-	for (;;);
-}
-
-void
-apus_halt(void)
-{
-   apus_restart(NULL);
-}
-
-/****************************************************** from setup.c/IDE */
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-
-#if 0	/* no longer used  -- paulus */
-void
-apus_ide_fix_driveid(struct hd_driveid *id)
-{
-   u_char *p = (u_char *)id;
-   int i, j, cnt;
-   u_char t;
-
-   if (!MACH_IS_AMIGA && !MACH_IS_MAC)
-   	return;
-   for (i = 0; i < num_driveid_types; i++) {
-      cnt = driveid_types[i] & T_MASK_COUNT;
-      switch (driveid_types[i] & T_MASK_TYPE) {
-         case T_CHAR:
-            p += cnt;
-            break;
-         case T_SHORT:
-            for (j = 0; j < cnt; j++) {
-               t = p[0];
-               p[0] = p[1];
-               p[1] = t;
-               p += 2;
-            }
-            break;
-         case T_INT:
-            for (j = 0; j < cnt; j++) {
-               t = p[0];
-               p[0] = p[3];
-               p[3] = t;
-               t = p[1];
-               p[1] = p[2];
-               p[2] = t;
-               p += 4;
-            }
-            break;
-         case T_TEXT:
-            for (j = 0; j < cnt; j += 2) {
-               t = p[0];
-               p[0] = p[1];
-               p[1] = t;
-               p += 2;
-            }
-            break;
-      }
-   }
-}
-#endif /* 0 */
-
-__init
-void apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, 
-			       ide_ioreg_t ctrl_port, int *irq)
-{
-        if (data_port || ctrl_port)
-                printk("apus_ide_init_hwif_ports: must not be called\n");
-}
-#endif
-/****************************************************** IRQ stuff */
-
-static unsigned int apus_irq_cannonicalize(unsigned int irq)
-{
-	return irq;
-}
-
-int apus_get_irq_list(char *buf)
-{
-#ifdef CONFIG_APUS
-	extern int amiga_get_irq_list(char *buf);
-	
-	return amiga_get_irq_list (buf);
-#else
-	return 0;
-#endif
-}
-
-/* IPL must be between 0 and 7 */
-static inline void apus_set_IPL(unsigned long ipl)
-{
-	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
-	APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
-	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | ((~ipl) & IPLEMU_IPLMASK));
-	APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
-}
-
-static inline unsigned long apus_get_IPL(void)
-{
-	/* This returns the present IPL emulation level. */
-	unsigned long __f;
-	APUS_READ(APUS_IPL_EMU, __f);
-	return ((~__f) & IPLEMU_IPLMASK);
-}
-
-static inline unsigned long apus_get_prev_IPL(struct pt_regs* regs)
-{
-	/* The value saved in mq is the IPL_EMU value at the time of
-	   interrupt. The lower bits are the current interrupt level,
-	   the upper bits the requested level. Thus, to restore the
-	   IPL level to the post-interrupt state, we will need to use
-	   the lower bits. */
-	unsigned long __f = regs->mq;
-	return ((~__f) & IPLEMU_IPLMASK);
-}
-
-
-#ifdef CONFIG_APUS
-void free_irq(unsigned int irq, void *dev_id)
-{
-	extern void amiga_free_irq(unsigned int irq, void *dev_id);
-
-	amiga_free_irq (irq, dev_id);
-}
-
-int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-	unsigned long irqflags, const char * devname, void *dev_id)
-{
-	extern int  amiga_request_irq(unsigned int irq, 
-				      void (*handler)(int, void *, 
-						      struct pt_regs *),
-				      unsigned long flags, 
-				      const char *devname, 
-				      void *dev_id);
-
-	return amiga_request_irq (irq, handler, irqflags, devname, dev_id);
-}
-
-/* In Linux/m68k the sys_request_irq deals with vectors 0-7. That's what
-   callers expect - but on Linux/APUS we actually use the IRQ_AMIGA_AUTO
-   vectors (24-31), so we put this dummy function in between to adjust
-   the vector argument (rather have cruft here than in the generic irq.c). */
-int sys_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-		    unsigned long irqflags, const char * devname, void *dev_id)
-{
-	extern int request_sysirq(unsigned int irq, 
-				  void (*handler)(int, void *, 
-						  struct pt_regs *),
-				  unsigned long irqflags,
-				  const char * devname, void *dev_id);
-	return request_sysirq(irq+IRQ_AMIGA_AUTO, handler, irqflags, 
-			      devname, dev_id);
-}
-#endif
-
-int apus_get_irq(struct pt_regs* regs)
-{
-#ifdef CONFIG_APUS
-	int level = apus_get_IPL();
-
-#ifdef __INTERRUPT_DEBUG
-	printk("<%d:%d>", level, apus_get_prev_IPL(regs));
-#endif
-
-	if (0 == level)
-		return -8;
-	if (7 == level)
-		return -9;
-
-	return level + IRQ_AMIGA_AUTO;
-#else
-	return 0;
-#endif
-}
-
-void apus_post_irq(struct pt_regs* regs, int level)
-{
-#ifdef __INTERRUPT_DEBUG
-	printk("{%d}", apus_get_prev_IPL(regs));
-#endif
-	/* Restore IPL to the previous value */
-	apus_set_IPL(apus_get_prev_IPL(regs));
-}
-
-/****************************************************** keyboard */
-static int apus_kbd_setkeycode(unsigned int scancode, unsigned int keycode)
-{
-	return -EOPNOTSUPP;
-}
-
-static int apus_kbd_getkeycode(unsigned int scancode)
-{
-	return scancode > 127 ? -EINVAL : scancode;
-}
-
-static int apus_kbd_translate(unsigned char keycode, unsigned char *keycodep,
-			      char raw_mode)
-{
-	*keycodep = keycode;
-	return 1;
-}
-
-static char apus_kbd_unexpected_up(unsigned char keycode)
-{
-	return 0200;
-}
-
-static void apus_kbd_leds(unsigned char leds)
-{
-}
-
-static void apus_kbd_init_hw(void)
-{
-#ifdef CONFIG_APUS
-	extern int amiga_keyb_init(void);
-
-	amiga_keyb_init();
-#endif
-}
-
-
-/****************************************************** debugging */
-
-/* some serial hardware definitions */
-#define SDR_OVRUN   (1<<15)
-#define SDR_RBF     (1<<14)
-#define SDR_TBE     (1<<13)
-#define SDR_TSRE    (1<<12)
-
-#define AC_SETCLR   (1<<15)
-#define AC_UARTBRK  (1<<11)
-
-#define SER_DTR     (1<<7)
-#define SER_RTS     (1<<6)
-#define SER_DCD     (1<<5)
-#define SER_CTS     (1<<4)
-#define SER_DSR     (1<<3)
-
-static __inline__ void ser_RTSon(void)
-{
-    ciab.pra &= ~SER_RTS; /* active low */
-}
-
-int __debug_ser_out( unsigned char c )
-{
-	custom.serdat = c | 0x100;
-	mb();
-	while (!(custom.serdatr & 0x2000))
-		barrier();
-	return 1;
-}
-
-unsigned char __debug_ser_in( void )
-{
-	unsigned char c;
-
-	/* XXX: is that ok?? derived from amiga_ser.c... */
-	while( !(custom.intreqr & IF_RBF) )
-		barrier();
-	c = custom.serdatr;
-	/* clear the interrupt, so that another character can be read */
-	custom.intreq = IF_RBF;
-	return c;
-}
-
-int __debug_serinit( void )
-{	
-	unsigned long flags;
-	
-	save_flags (flags);
-	cli();
-
-	/* turn off Rx and Tx interrupts */
-	custom.intena = IF_RBF | IF_TBE;
-
-	/* clear any pending interrupt */
-	custom.intreq = IF_RBF | IF_TBE;
-
-	restore_flags (flags);
-
-	/*
-	 * set the appropriate directions for the modem control flags,
-	 * and clear RTS and DTR
-	 */
-	ciab.ddra |= (SER_DTR | SER_RTS);   /* outputs */
-	ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR);  /* inputs */
-	
-#ifdef CONFIG_KGDB
-	/* turn Rx interrupts on for GDB */
-	custom.intena = IF_SETCLR | IF_RBF;
-	ser_RTSon();
-#endif
-
-	return 0;
-}
-
-void __debug_print_hex(unsigned long x)
-{
-	int i;
-	char hexchars[] = "0123456789ABCDEF";
-
-	for (i = 0; i < 8; i++) {
-		__debug_ser_out(hexchars[(x >> 28) & 15]);
-		x <<= 4;
-	}
-	__debug_ser_out('\n');
-	__debug_ser_out('\r');
-}
-
-void __debug_print_string(char* s)
-{
-	unsigned char c;
-	while((c = *s++))
-		__debug_ser_out(c);
-	__debug_ser_out('\n');
-	__debug_ser_out('\r');
-}
-
-static void apus_progress(char *s, unsigned short value)
-{
-	__debug_print_string(s);
-}
-
-/****************************************************** init */
-
-/* The number of spurious interrupts */
-volatile unsigned int num_spurious;
-
-#define NUM_IRQ_NODES 100
-static irq_node_t nodes[NUM_IRQ_NODES];
-
-extern void (*amiga_default_handler[AUTO_IRQS])(int, void *, struct pt_regs *);
-
-static const char *default_names[SYS_IRQS] = {
-	"spurious int", "int1 handler", "int2 handler", "int3 handler",
-	"int4 handler", "int5 handler", "int6 handler", "int7 handler"
-};
-
-irq_node_t *new_irq_node(void)
-{
-	irq_node_t *node;
-	short i;
-
-	for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
-		if (!node->handler)
-			return node;
-
-	printk ("new_irq_node: out of nodes\n");
-	return NULL;
-}
-
-extern void amiga_enable_irq(unsigned int irq);
-extern void amiga_disable_irq(unsigned int irq);
-
-struct hw_interrupt_type amiga_irqctrl = {
-	" Amiga  ",
-	NULL,
-	NULL,
-	amiga_enable_irq,
-	amiga_disable_irq,
-	0,
-	0
-};
-
-#define HARDWARE_MAPPED_SIZE (512*1024)
-unsigned long __init apus_find_end_of_memory(void)
-{
-	int shadow = 0;
-	unsigned long total;
-
-	/* The memory size reported by ADOS excludes the 512KB
-	   reserved for PPC exception registers and possibly 512KB
-	   containing a shadow of the ADOS ROM. */
-	{
-		unsigned long size = memory[0].size;
-
-		/* If 2MB aligned, size was probably user
-                   specified. We can't tell anything about shadowing
-                   in this case so skip shadow assignment. */
-		if (0 != (size & 0x1fffff)){
-			/* Align to 512KB to ensure correct handling
-			   of both memfile and system specified
-			   sizes. */
-			size = ((size+0x0007ffff) & 0xfff80000);
-			/* If memory is 1MB aligned, assume
-                           shadowing. */
-			shadow = !(size & 0x80000);
-		}
-
-		/* Add the chunk that ADOS does not see. by aligning
-                   the size to the nearest 2MB limit upwards.  */
-		memory[0].size = ((size+0x001fffff) & 0xffe00000);
-	}
-
-	total = memory[0].size;
-
-	/* Remove the memory chunks that are controlled by special
-           Phase5 hardware. */
-
-	/* Remove the upper 512KB if it contains a shadow of
-	   the ADOS ROM. FIXME: It might be possible to
-	   disable this shadow HW. Check the booter
-	   (ppc_boot.c) */
-	if (shadow)
-		total -= HARDWARE_MAPPED_SIZE;
-
-	/* Remove the upper 512KB where the PPC exception
-	   vectors are mapped. */
-	total -= HARDWARE_MAPPED_SIZE;
-
-	/* Linux/APUS only handles one block of memory -- the one on
-	   the PowerUP board. Other system memory is horrible slow in
-	   comparison. The user can use other memory for swapping
-	   using the z2ram device. */
-	ram_phys_base = memory[0].addr;
-	return total;
-}
-
-static void __init
-apus_map_io(void)
-{
-	/* Map PPC exception vectors. */
-	io_block_mapping(0xfff00000, 0xfff00000, 0x00020000, _PAGE_KERNEL);
-	/* Map chip and ZorroII memory */
-	io_block_mapping(zTwoBase,   0x00000000, 0x01000000, _PAGE_IO);
-}
-
-__init
-void apus_init_IRQ(void)
-{
-	int i;
-
-	for ( i = 0 ; i < NR_IRQS ; i++ )
-		irq_desc[i].handler = &amiga_irqctrl;
-
-	for (i = 0; i < NUM_IRQ_NODES; i++)
-		nodes[i].handler = NULL;
-
-	for (i = 0; i < AUTO_IRQS; i++) {
-		if (amiga_default_handler[i] != NULL)
-			sys_request_irq(i, amiga_default_handler[i],
-					0, default_names[i], NULL);
-	}
-
-	amiga_init_IRQ();
-
-}
-
-__init
-void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-		   unsigned long r6, unsigned long r7)
-{
-	extern int parse_bootinfo(const struct bi_record *);
-	extern char _end[];
-	
-	/* Parse bootinfo. The bootinfo is located right after
-           the kernel bss */
-	parse_bootinfo((const struct bi_record *)&_end);
-#ifdef CONFIG_BLK_DEV_INITRD
-	/* Take care of initrd if we have one. Use data from
-	   bootinfo to avoid the need to initialize PPC
-	   registers when kernel is booted via a PPC reset. */
-	if ( ramdisk.addr ) {
-		initrd_start = (unsigned long) __va(ramdisk.addr);
-		initrd_end = (unsigned long) 
-			__va(ramdisk.size + ramdisk.addr);
-	}
-#endif /* CONFIG_BLK_DEV_INITRD */
-
-	ISA_DMA_THRESHOLD = 0x00ffffff;
-
-	ppc_md.setup_arch     = apus_setup_arch;
-	ppc_md.show_cpuinfo   = apus_show_cpuinfo;
-	ppc_md.irq_cannonicalize = apus_irq_cannonicalize;
-	ppc_md.init_IRQ       = apus_init_IRQ;
-	ppc_md.get_irq        = apus_get_irq;
-	
-#error Should use the ->end() member of irq_desc[x]. -- Cort
-	/*ppc_md.post_irq       = apus_post_irq;*/
-	
-#ifdef CONFIG_HEARTBEAT
-	ppc_md.heartbeat      = apus_heartbeat;
-	ppc_md.heartbeat_count = 1;
-#endif
-#ifdef APUS_DEBUG
-	__debug_serinit();
-	ppc_md.progress       = apus_progress;
-#endif
-	ppc_md.init           = NULL;
-
-	ppc_md.restart        = apus_restart;
-	ppc_md.power_off      = apus_power_off;
-	ppc_md.halt           = apus_halt;
-
-	ppc_md.time_init      = NULL;
-	ppc_md.set_rtc_time   = apus_set_rtc_time;
-	ppc_md.get_rtc_time   = apus_get_rtc_time;
-	ppc_md.calibrate_decr = apus_calibrate_decr;
-
-	ppc_md.find_end_of_memory = apus_find_end_of_memory;
-	ppc_md.setup_io_mappings = apus_map_io;
-
-	ppc_md.nvram_read_val = NULL;
-	ppc_md.nvram_write_val = NULL;
-
-	/* These should not be used for the APUS yet, since it uses
-	   the M68K keyboard now. */
-	ppc_md.kbd_setkeycode    = apus_kbd_setkeycode;
-	ppc_md.kbd_getkeycode    = apus_kbd_getkeycode;
-	ppc_md.kbd_translate     = apus_kbd_translate;
-	ppc_md.kbd_unexpected_up = apus_kbd_unexpected_up;
-	ppc_md.kbd_leds          = apus_kbd_leds;
-	ppc_md.kbd_init_hw       = apus_kbd_init_hw;
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.ide_init_hwif = apus_ide_init_hwif_ports;
-#endif		
-}
-
-
-/*************************************************** coexistence */
-void __init adbdev_init(void)
-{
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/chrp_pci.c linux-2.4.20/arch/ppc/kernel/chrp_pci.c
--- linux-2.4.19/arch/ppc/kernel/chrp_pci.c	2001-09-08 19:38:41.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/chrp_pci.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,330 +0,0 @@
-/*
- * BK Id: SCCS/s.chrp_pci.c 1.22 09/08/01 15:47:42 paulus
- */
-/*
- * CHRP pci routines.
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <linux/bootmem.h>
-
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/hydra.h>
-#include <asm/prom.h>
-#include <asm/gg2.h>
-#include <asm/machdep.h>
-#include <asm/sections.h>
-#include <asm/pci-bridge.h>
-
-#include "open_pic.h"
-#include "pci.h"
-
-/* LongTrail */
-unsigned long gg2_pci_config_base;
-
-#define pci_config_addr(dev, offset) \
-(gg2_pci_config_base | ((dev->bus->number)<<16) | ((dev->devfn)<<8) | (offset))
-
-volatile struct Hydra *Hydra = NULL;
-
-/*
- * The VLSI Golden Gate II has only 512K of PCI configuration space, so we
- * limit the bus number to 3 bits
- */
-
-#define cfg_read(val, addr, type, op)	*val = op((type)(addr))
-#define cfg_write(val, addr, type, op)	op((type *)(addr), (val))
-
-#define cfg_read_bad(val, size)		*val = bad_##size;
-#define cfg_write_bad(val, size)
-
-#define bad_byte	0xff
-#define bad_word	0xffff
-#define bad_dword	0xffffffffU
-
-#define GG2_PCI_OP(rw, size, type, op)					    \
-int __chrp gg2_##rw##_config_##size(struct pci_dev *dev, int off, type val) \
-{									    \
-	if (dev->bus->number > 7) {					    \
-		cfg_##rw##_bad(val, size)				    \
-		return PCIBIOS_DEVICE_NOT_FOUND;			    \
-	}								    \
-	cfg_##rw(val, pci_config_addr(dev, off), type, op);		    \
-	return PCIBIOS_SUCCESSFUL;					    \
-}
-
-GG2_PCI_OP(read, byte, u8 *, in_8)
-GG2_PCI_OP(read, word, u16 *, in_le16)
-GG2_PCI_OP(read, dword, u32 *, in_le32)
-GG2_PCI_OP(write, byte, u8, out_8)
-GG2_PCI_OP(write, word, u16, out_le16)
-GG2_PCI_OP(write, dword, u32, out_le32)
-
-static struct pci_ops gg2_pci_ops =
-{
-	gg2_read_config_byte,
-	gg2_read_config_word,
-	gg2_read_config_dword,
-	gg2_write_config_byte,
-	gg2_write_config_word,
-	gg2_write_config_dword
-};
-
-/*
- * Access functions for PCI config space on IBM "python" host bridges.
- */
-#define PYTHON_CFA(b, d, o)	(0x80 | ((b) << 8) | ((d) << 16) \
-				 | (((o) & ~3) << 24))
-
-#define PYTHON_PCI_OP(rw, size, type, op, mask)			    	     \
-int __chrp								     \
-python_##rw##_config_##size(struct pci_dev *dev, int offset, type val) 	     \
-{									     \
-	struct pci_controller *hose = dev->sysdata;			     \
-									     \
-	out_be32(hose->cfg_addr,					     \
-		 PYTHON_CFA(dev->bus->number, dev->devfn, offset));	     \
-	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);   	     \
-	return PCIBIOS_SUCCESSFUL;					     \
-}
-
-PYTHON_PCI_OP(read, byte, u8 *, in_8, 3)
-PYTHON_PCI_OP(read, word, u16 *, in_le16, 2)
-PYTHON_PCI_OP(read, dword, u32 *, in_le32, 0)
-PYTHON_PCI_OP(write, byte, u8, out_8, 3)
-PYTHON_PCI_OP(write, word, u16, out_le16, 2)
-PYTHON_PCI_OP(write, dword, u32, out_le32, 0)
-
-static struct pci_ops python_pci_ops =
-{
-	python_read_config_byte,
-	python_read_config_word,
-	python_read_config_dword,
-	python_write_config_byte,
-	python_write_config_word,
-	python_write_config_dword
-};
-
-/*
- * Access functions for PCI config space using RTAS calls.
- */
-#define RTAS_PCI_READ_OP(size, type, nbytes)			    	  \
-int __chrp								  \
-rtas_read_config_##size(struct pci_dev *dev, int offset, type val) 	  \
-{									  \
-	unsigned long addr = (offset & 0xff) | ((dev->devfn & 0xff) << 8) \
-		| ((dev->bus->number & 0xff) << 16);			  \
-	unsigned long ret = ~0UL;					  \
-	int rval;							  \
-									  \
-	rval = call_rtas("read-pci-config", 2, 2, &ret, addr, nbytes);	  \
-	*val = ret;							  \
-	return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL;    	  \
-}
-
-#define RTAS_PCI_WRITE_OP(size, type, nbytes)				  \
-int __chrp								  \
-rtas_write_config_##size(struct pci_dev *dev, int offset, type val)	  \
-{									  \
-	unsigned long addr = (offset & 0xff) | ((dev->devfn & 0xff) << 8) \
-		| ((dev->bus->number & 0xff) << 16);			  \
-	int rval;							  \
-									  \
-	rval = call_rtas("write-pci-config", 3, 1, NULL,		  \
-			 addr, nbytes, (ulong)val);			  \
-	return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL;	  \
-}
-
-RTAS_PCI_READ_OP(byte, u8 *, 1)
-RTAS_PCI_READ_OP(word, u16 *, 2)
-RTAS_PCI_READ_OP(dword, u32 *, 4)
-RTAS_PCI_WRITE_OP(byte, u8, 1)
-RTAS_PCI_WRITE_OP(word, u16, 2)
-RTAS_PCI_WRITE_OP(dword, u32, 4)
-
-static struct pci_ops rtas_pci_ops =
-{
-	rtas_read_config_byte,
-	rtas_read_config_word,
-	rtas_read_config_dword,
-	rtas_write_config_byte,
-	rtas_write_config_word,
-	rtas_write_config_dword
-};
-
-    /*
-     *  Temporary fixes for PCI devices. These should be replaced by OF query
-     *  code -- Geert
-     */
-
-static u_char hydra_openpic_initsenses[] __initdata = {
-    1,	/* HYDRA_INT_SIO */
-    0,	/* HYDRA_INT_SCSI_DMA */
-    0,	/* HYDRA_INT_SCCA_TX_DMA */
-    0,	/* HYDRA_INT_SCCA_RX_DMA */
-    0,	/* HYDRA_INT_SCCB_TX_DMA */
-    0,	/* HYDRA_INT_SCCB_RX_DMA */
-    1,	/* HYDRA_INT_SCSI */
-    1,	/* HYDRA_INT_SCCA */
-    1,	/* HYDRA_INT_SCCB */
-    1,	/* HYDRA_INT_VIA */
-    1,	/* HYDRA_INT_ADB */
-    0,	/* HYDRA_INT_ADB_NMI */
-    	/* all others are 1 (= default) */
-};
-
-int __init
-hydra_init(void)
-{
-	struct device_node *np;
-
-	np = find_devices("mac-io");
-	if (np == NULL || np->n_addrs == 0) {
-		printk(KERN_WARNING "Warning: no mac-io found\n");
-		return 0;
-	}
-	Hydra = ioremap(np->addrs[0].address, np->addrs[0].size);
-	printk("Hydra Mac I/O at %x\n", np->addrs[0].address);
-	out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN |
-					   HYDRA_FC_SCSI_CELL_EN |
-					   HYDRA_FC_SCCA_ENABLE |
-					   HYDRA_FC_SCCB_ENABLE |
-					   HYDRA_FC_ARB_BYPASS |
-					   HYDRA_FC_MPIC_ENABLE |
-					   HYDRA_FC_SLOW_SCC_PCLK |
-					   HYDRA_FC_MPIC_IS_MASTER));
-	OpenPIC_Addr = &Hydra->OpenPIC;
-	OpenPIC_InitSenses = hydra_openpic_initsenses;
-	OpenPIC_NumInitSenses = sizeof(hydra_openpic_initsenses);
-	return 1;
-}
-
-void __init
-chrp_pcibios_fixup(void)
-{
-	struct pci_dev *dev;
-	struct device_node *np;
-
-	/* PCI interrupts are controlled by the OpenPIC */
-	pci_for_each_dev(dev) {
-		np = pci_device_to_OF_node(dev);
-		if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0))
-			dev->irq = np->intrs[0].line;
-		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
-	}
-}
-
-void __init
-chrp_find_bridges(void)
-{
-	struct device_node *dev;
-	int *bus_range;
-	int len, index = -1;
-	struct pci_controller *hose;
-	volatile unsigned char *cfg;
-	unsigned int *dma;
-	char *model, *machine;
-	int is_longtrail = 0, is_mot = 0;
-	struct device_node *root = find_path_device("/");
-#ifdef CONFIG_POWER3
-	unsigned int *opprop = (unsigned int *)
-		get_property(root, "platform-open-pic", NULL);
-	int i;
-#endif
-
-	/*
-	 * The PCI host bridge nodes on some machines don't have
-	 * properties to adequately identify them, so we have to
-	 * look at what sort of machine this is as well.
-	 */
-	machine = get_property(root, "model", NULL);
-	if (machine != NULL) {
-		is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0;
-		is_mot = strncmp(machine, "MOT", 3) == 0;
-	}
-	for (dev = root->child; dev != NULL; dev = dev->sibling) {
-		if (dev->type == NULL || strcmp(dev->type, "pci") != 0)
-			continue;
-		++index;
-		/* The GG2 bridge on the LongTrail doesn't have an address */
-		if (dev->n_addrs < 1 && !is_longtrail) {
-			printk(KERN_WARNING "Can't use %s: no address\n",
-			       dev->full_name);
-			continue;
-		}
-		bus_range = (int *) get_property(dev, "bus-range", &len);
-		if (bus_range == NULL || len < 2 * sizeof(int)) {
-			printk(KERN_WARNING "Can't get bus-range for %s\n",
-				dev->full_name);
-			continue;
-		}
-		if (bus_range[1] == bus_range[0])
-			printk(KERN_INFO "PCI bus %d", bus_range[0]);
-		else
-			printk(KERN_INFO "PCI buses %d..%d",
-			       bus_range[0], bus_range[1]);
-		printk(" controlled by %s", dev->type);
-		if (dev->n_addrs > 0)
-			printk(" at %x", dev->addrs[0].address);
-		printk("\n");
-
-		hose = pcibios_alloc_controller();
-		if (!hose) {
-			printk("Can't allocate PCI controller structure for %s\n",
-				dev->full_name);
-			continue;
-		}
-		hose->arch_data = dev;
-		hose->first_busno = bus_range[0];
-		hose->last_busno = bus_range[1];
-
-		model = get_property(dev, "model", NULL);
-		if (model == NULL)
-			model = "<none>";
-		if (device_is_compatible(dev, "IBM,python")) {
-			hose->ops = &python_pci_ops;
-			cfg = ioremap(dev->addrs[0].address + 0xf8000, 0x20);
-			hose->cfg_addr = (volatile unsigned int *) cfg;
-			hose->cfg_data = cfg + 0x10;
-		} else if (is_mot
-			   || strncmp(model, "Motorola, Grackle", 17) == 0) {
-			setup_grackle(hose);
-		} else if (is_longtrail) {
-			hose->ops = &gg2_pci_ops;
-			gg2_pci_config_base = (unsigned long)
-				ioremap(GG2_PCI_CONFIG_BASE, 0x80000);
-		} else {
-			printk("No methods for %s (model %s), using RTAS\n",
-			       dev->full_name, model);
-			hose->ops = &rtas_pci_ops;
-		}
-
-		pci_process_bridge_OF_ranges(hose, dev, index == 0);
-
-#ifdef CONFIG_POWER3
-		if (opprop != NULL) {
-			i = prom_n_addr_cells(root) * (index + 2) - 1;
-			openpic_setup_ISU(index, opprop[i]);
-		}
-#endif /* CONFIG_POWER3 */
-
-		/* check the first bridge for a property that we can
-		   use to set pci_dram_offset */
-		dma = (unsigned int *)
-			get_property(dev, "ibm,dma-ranges", &len);
-		if (index == 0 && dma != NULL && len >= 6 * sizeof(*dma)) {
-			pci_dram_offset = dma[2] - dma[3];
-			printk("pci_dram_offset = %lx\n", pci_dram_offset);
-		}
-	}
-
-	ppc_md.pcibios_fixup = chrp_pcibios_fixup;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/chrp_setup.c linux-2.4.20/arch/ppc/kernel/chrp_setup.c
--- linux-2.4.19/arch/ppc/kernel/chrp_setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/chrp_setup.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,634 +0,0 @@
-/*
- * BK Id: SCCS/s.chrp_setup.c 1.42 04/09/02 21:43:09 paulus
- */
-/*
- *  linux/arch/ppc/kernel/setup.c
- *
- *  Copyright (C) 1995  Linus Torvalds
- *  Adapted from 'alpha' version by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu)
- */
-
-/*
- * bootup setup stuff..
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/major.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/blk.h>
-#include <linux/ioport.h>
-#include <linux/console.h>
-#include <linux/pci.h>
-#include <linux/version.h>
-#include <linux/adb.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/seq_file.h>
-
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/prom.h>
-#include <asm/gg2.h>
-#include <asm/pci-bridge.h>
-#include <asm/dma.h>
-#include <asm/machdep.h>
-#include <asm/irq.h>
-#include <asm/hydra.h>
-#include <asm/keyboard.h>
-#include <asm/sections.h>
-#include <asm/time.h>
-#include <asm/btext.h>
-
-#include "local_irq.h"
-#include "i8259.h"
-#include "open_pic.h"
-#include "xics.h"
-
-unsigned long chrp_get_rtc_time(void);
-int chrp_set_rtc_time(unsigned long nowtime);
-void chrp_calibrate_decr(void);
-long chrp_time_init(void);
-
-void chrp_find_bridges(void);
-void chrp_event_scan(void);
-void rtas_display_progress(char *, unsigned short);
-void rtas_indicator_progress(char *, unsigned short);
-void btext_progress(char *, unsigned short);
-
-extern unsigned long pmac_find_end_of_memory(void);
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
-extern unsigned char pckbd_sysrq_xlate[128];
-extern void select_adb_keyboard(void);
-extern int of_show_percpuinfo(struct seq_file *, int);
-
-extern kdev_t boot_dev;
-
-extern PTE *Hash, *Hash_end;
-extern unsigned long Hash_size, Hash_mask;
-extern int probingmem;
-extern unsigned long loops_per_jiffy;
-static int max_width;
-
-#ifdef CONFIG_SMP
-extern struct smp_ops_t chrp_smp_ops;
-extern struct smp_ops_t xics_smp_ops;
-#endif
-
-static const char *gg2_memtypes[4] = {
-	"FPM", "SDRAM", "EDO", "BEDO"
-};
-static const char *gg2_cachesizes[4] = {
-	"256 KB", "512 KB", "1 MB", "Reserved"
-};
-static const char *gg2_cachetypes[4] = {
-	"Asynchronous", "Reserved", "Flow-Through Synchronous",
-	"Pipelined Synchronous"
-};
-static const char *gg2_cachemodes[4] = {
-	"Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
-};
-
-int __chrp
-chrp_show_cpuinfo(struct seq_file *m)
-{
-	int i, sdramen;
-	unsigned int t;
-	struct device_node *root;
-	const char *model = "";
-
-	root = find_path_device("/");
-	if (root)
-		model = get_property(root, "model", NULL);
-	seq_printf(m, "machine\t\t: CHRP %s\n", model);
-
-	/* longtrail (goldengate) stuff */
-	if (!strncmp(model, "IBM,LongTrail", 13)) {
-		/* VLSI VAS96011/12 `Golden Gate 2' */
-		/* Memory banks */
-		sdramen = (in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+
-						GG2_PCI_DRAM_CTRL))
-			   >>31) & 1;
-		for (i = 0; i < (sdramen ? 4 : 6); i++) {
-			t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+
-						 GG2_PCI_DRAM_BANK0+
-						 i*4));
-			if (!(t & 1))
-				continue;
-			switch ((t>>8) & 0x1f) {
-			case 0x1f:
-				model = "4 MB";
-				break;
-			case 0x1e:
-				model = "8 MB";
-				break;
-			case 0x1c:
-				model = "16 MB";
-				break;
-			case 0x18:
-				model = "32 MB";
-				break;
-			case 0x10:
-				model = "64 MB";
-				break;
-			case 0x00:
-				model = "128 MB";
-				break;
-			default:
-				model = "Reserved";
-				break;
-			}
-			seq_printf(m, "memory bank %d\t: %s %s\n", i, model,
-				   gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]);
-		}
-		/* L2 cache */
-		t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_CC_CTRL));
-		seq_printf(m, "board l2\t: %s %s (%s)\n",
-			   gg2_cachesizes[(t>>7) & 3],
-			   gg2_cachetypes[(t>>2) & 3],
-			   gg2_cachemodes[t & 3]);
-	}
-	return 0;
-}
-
-/*
- *  Fixes for the National Semiconductor PC78308VUL SuperI/O
- *
- *  Some versions of Open Firmware incorrectly initialize the IRQ settings
- *  for keyboard and mouse
- */
-static inline void __init sio_write(u8 val, u8 index)
-{
-	outb(index, 0x15c);
-	outb(val, 0x15d);
-}
-
-static inline u8 __init sio_read(u8 index)
-{
-	outb(index, 0x15c);
-	return inb(0x15d);
-}
-
-static void __init sio_fixup_irq(const char *name, u8 device, u8 level,
-				     u8 type)
-{
-	u8 level0, type0, active;
-
-	/* select logical device */
-	sio_write(device, 0x07);
-	active = sio_read(0x30);
-	level0 = sio_read(0x70);
-	type0 = sio_read(0x71);
-	if (level0 != level || type0 != type || !active) {
-		printk(KERN_WARNING "sio: %s irq level %d, type %d, %sactive: "
-		       "remapping to level %d, type %d, active\n",
-		       name, level0, type0, !active ? "in" : "", level, type);
-		sio_write(0x01, 0x30);
-		sio_write(level, 0x70);
-		sio_write(type, 0x71);
-	}
-}
-
-static void __init sio_init(void)
-{
-	struct device_node *root;
-
-	if ((root = find_path_device("/")) &&
-	    !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) {
-		/* logical device 0 (KBC/Keyboard) */
-		sio_fixup_irq("keyboard", 0, 1, 2);
-		/* select logical device 1 (KBC/Mouse) */
-		sio_fixup_irq("mouse", 1, 12, 2);
-	}
-}
-
-
-void __init
-chrp_setup_arch(void)
-{
-	struct device_node *device;
-
-	/* init to some ~sane value until calibrate_delay() runs */
-	loops_per_jiffy = 50000000/HZ;
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	/* this is fine for chrp */
-	initrd_below_start_ok = 1;
-	
-	if (initrd_start)
-		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
-	else
-#endif
-		ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */
-
-	/* Lookup PCI host bridges */
-	chrp_find_bridges();
-
-#ifndef CONFIG_PPC64BRIDGE
-	/*
-	 *  Temporary fixes for PCI devices.
-	 *  -- Geert
-	 */
-	hydra_init();		/* Mac I/O */
-
-#endif /* CONFIG_PPC64BRIDGE */
-
-	/* Some IBM machines don't have the hydra -- Cort */
-	if (!OpenPIC_Addr) {
-		struct device_node *root;
-		unsigned long *opprop;
-		int n;
-
-		root = find_path_device("/");
-		opprop = (unsigned long *) get_property
-			(root, "platform-open-pic", NULL);
-		n = prom_n_addr_cells(root);
-		if (opprop != 0) {
-			printk("OpenPIC addrs: %lx %lx %lx\n",
-			       opprop[n-1], opprop[2*n-1], opprop[3*n-1]);
-			OpenPIC_Addr = ioremap(opprop[n-1], 0x40000);
-		}
-	}
-
-	/*
-	 *  Fix the Super I/O configuration
-	 */
-	sio_init();
-
-	/*
-	 *  Setup the console operations
-	 */
-#ifdef CONFIG_DUMMY_CONSOLE
-	conswitchp = &dummy_con;
-#endif
-
-	/* Get the event scan rate for the rtas so we know how
-	 * often it expects a heartbeat. -- Cort
-	 */
-	if ( rtas_data ) {
-		struct property *p;
-		device = find_devices("rtas");
-		for ( p = device->properties;
-		      p && strncmp(p->name, "rtas-event-scan-rate", 20);
-		      p = p->next )
-			/* nothing */ ;
-		if ( p && *(unsigned long *)p->value ) {
-			ppc_md.heartbeat = chrp_event_scan;
-			ppc_md.heartbeat_reset = (HZ/(*(unsigned long *)p->value)*30)-1;
-			ppc_md.heartbeat_count = 1;
-			printk("RTAS Event Scan Rate: %lu (%lu jiffies)\n",
-			       *(unsigned long *)p->value, ppc_md.heartbeat_reset );
-		}
-	}
-}
-
-void __chrp
-chrp_event_scan(void)
-{
-	unsigned char log[1024];
-	unsigned long ret = 0;
-	/* XXX: we should loop until the hardware says no more error logs -- Cort */
-	call_rtas( "event-scan", 4, 1, &ret, 0xffffffff, 0,
-		   __pa(log), 1024 );
-	ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
-}
-	
-void __chrp
-chrp_restart(char *cmd)
-{
-	printk("RTAS system-reboot returned %d\n",
-	       call_rtas("system-reboot", 0, 1, NULL));
-	for (;;);
-}
-
-void __chrp
-chrp_power_off(void)
-{
-	/* allow power on only with power button press */
-	printk("RTAS power-off returned %d\n",
-	       call_rtas("power-off", 2, 1, NULL,0xffffffff,0xffffffff));
-	for (;;);
-}
-
-void __chrp
-chrp_halt(void)
-{
-	chrp_power_off();
-}
-
-u_int __chrp
-chrp_irq_cannonicalize(u_int irq)
-{
-	if (irq == 2)
-		return 9;
-	return irq;
-}
-
-void __init chrp_init_IRQ(void)
-{
-	struct device_node *np;
-	int i;
-	unsigned int *addrp;
-	unsigned char* chrp_int_ack_special = 0;
-	unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
-	int nmi_irq = -1;
-#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)	
-	struct device_node *kbd;
-#endif
-
-	if (!(np = find_devices("pci"))
-	    || !(addrp = (unsigned int *)
-		 get_property(np, "8259-interrupt-acknowledge", NULL)))
-		printk("Cannot find pci to get ack address\n");
-	else
-		chrp_int_ack_special = (unsigned char *)
-			ioremap(addrp[prom_n_addr_cells(np)-1], 1);
-	/* hydra still sets OpenPIC_InitSenses to a static set of values */
-	if (OpenPIC_InitSenses == NULL) {
-		prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS);
-		OpenPIC_InitSenses = init_senses;
-		OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS;
-	}
-	openpic_init(1, NUM_8259_INTERRUPTS, chrp_int_ack_special, nmi_irq);
-	for ( i = 0 ; i < NUM_8259_INTERRUPTS  ; i++ )
-		irq_desc[i].handler = &i8259_pic;
-	i8259_init(0);
-#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)
-	/* see if there is a keyboard in the device tree
-	   with a parent of type "adb" */
-	for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next)
-		if (kbd->parent && kbd->parent->type
-		    && strcmp(kbd->parent->type, "adb") == 0)
-			break;
-	if (kbd)
-		request_irq( HYDRA_INT_ADB_NMI, xmon_irq, 0, "XMON break", 0);
-#endif
-}
-
-void __init
-chrp_init2(void)
-{
-#ifdef CONFIG_NVRAM  
-	pmac_nvram_init();
-#endif
-
-	request_region(0x20,0x20,"pic1");
-	request_region(0xa0,0x20,"pic2");
-	request_region(0x00,0x20,"dma1");
-	request_region(0x40,0x20,"timer");
-	request_region(0x80,0x10,"dma page reg");
-	request_region(0xc0,0x20,"dma2");
-
-	if (ppc_md.progress)
-		ppc_md.progress("  Have fun!    ", 0x7777);
-
-#if defined(CONFIG_VT) && (defined(CONFIG_ADB_KEYBOARD) || defined(CONFIG_INPUT))
-	/* see if there is a keyboard in the device tree
-	   with a parent of type "adb" */
-	{
-		struct device_node *kbd;
-
-		for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next) {
-			if (kbd->parent && kbd->parent->type
-			    && strcmp(kbd->parent->type, "adb") == 0) {
-				select_adb_keyboard();
-				break;
-			}
-		}
-	}
-#endif /* CONFIG_VT && (CONFIG_ADB_KEYBOARD || CONFIG_INPUT) */
-}
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-
-static int __chrp
-chrp_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-        return check_region(from, extent);
-}
-
-static void __chrp
-chrp_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-        request_region(from, extent, name);
-}
-
-static void __chrp
-chrp_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-        release_region(from, extent);
-}
-
-static void __chrp
-chrp_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t reg = data_port;
-	int i;
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg;
-		reg += 1;
-	}
-	hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-}
-#endif
-
-/*
- * One of the main thing these mappings are needed for is so that
- * xmon can get to the serial port early on.  We probably should
- * handle the machines with the mpc106 as well as the python (F50)
- * and the GG2 (longtrail).  Actually we should look in the device
- * tree and do the right thing.
- */
-static void __init
-chrp_map_io(void)
-{
-	char *name;
-
-	/*
-	 * The code below tends to get removed, please don't take it out.
-	 * The F50 needs this mapping and it you take it out I'll track you
-	 * down and slap your hands.  If it causes problems please email me.
-	 *  -- Cort <cort@fsmlabs.com>
-	 */
-	name = get_property(find_path_device("/"), "name", NULL);
-	if (name && strncmp(name, "IBM-70", 6) == 0
-	    && strstr(name, "-F50")) {
-		io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
-		io_block_mapping(0x90000000, 0x90000000, 0x10000000, _PAGE_IO);
-		return;
-	} else {
-		io_block_mapping(0xf8000000, 0xf8000000, 0x04000000, _PAGE_IO);
-	}
-}
-
-void __init
-chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
-	  unsigned long r6, unsigned long r7)
-{
-#ifdef CONFIG_BLK_DEV_INITRD
-	/* take care of initrd if we have one */
-	if ( r6 )
-	{
-		initrd_start = r6 + KERNELBASE;
-		initrd_end = r6 + r7 + KERNELBASE;
-	}
-#endif /* CONFIG_BLK_DEV_INITRD */
-
-	ISA_DMA_THRESHOLD = ~0L;
-	DMA_MODE_READ = 0x44;
-	DMA_MODE_WRITE = 0x48;
-	isa_io_base = CHRP_ISA_IO_BASE;		/* default value */
-
-	ppc_md.setup_arch     = chrp_setup_arch;
-	ppc_md.show_percpuinfo = of_show_percpuinfo;
-	ppc_md.show_cpuinfo   = chrp_show_cpuinfo;
-	ppc_md.irq_cannonicalize = chrp_irq_cannonicalize;
-#ifndef CONFIG_POWER4
-	ppc_md.init_IRQ       = chrp_init_IRQ;
-	ppc_md.get_irq        = openpic_get_irq;
-#else
-	ppc_md.init_IRQ	      = xics_init_IRQ;
-	ppc_md.get_irq	      = xics_get_irq;
-#endif /* CONFIG_POWER4 */
-
-	ppc_md.init           = chrp_init2;
-
-	ppc_md.restart        = chrp_restart;
-	ppc_md.power_off      = chrp_power_off;
-	ppc_md.halt           = chrp_halt;
-
-	ppc_md.time_init      = chrp_time_init;
-	ppc_md.set_rtc_time   = chrp_set_rtc_time;
-	ppc_md.get_rtc_time   = chrp_get_rtc_time;
-	ppc_md.calibrate_decr = chrp_calibrate_decr;
-
-	ppc_md.find_end_of_memory = pmac_find_end_of_memory;
-	ppc_md.setup_io_mappings = chrp_map_io;
-
-#ifdef CONFIG_VT
-	/* these are adjusted in chrp_init2 if we have an ADB keyboard */
-	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
-	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
-	ppc_md.kbd_translate     = pckbd_translate;
-	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
-	ppc_md.kbd_leds          = pckbd_leds;
-	ppc_md.kbd_init_hw       = pckbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
-	SYSRQ_KEY = 0x54;
-#endif /* CONFIG_MAGIC_SYSRQ */
-#endif /* CONFIG_VT */
-
-	if (rtas_data) {
-		struct device_node *rtas;
-		unsigned int *p;
-
-		rtas = find_devices("rtas");
-		if (rtas != NULL) {
-			if (get_property(rtas, "display-character", NULL)) {
-				ppc_md.progress = rtas_display_progress;
-				p = (unsigned int *) get_property
-				       (rtas, "ibm,display-line-length", NULL);
-				if (p)
-					max_width = *p;
-			} else if (get_property(rtas, "set-indicator", NULL))
-				ppc_md.progress = rtas_indicator_progress;
-		}
-	}
-#ifdef CONFIG_BOOTX_TEXT
-	if (ppc_md.progress == NULL && boot_text_mapped)
-		ppc_md.progress = btext_progress;
-#endif
-
-#ifdef CONFIG_SMP
-#ifndef CONFIG_POWER4
-	ppc_md.smp_ops = &chrp_smp_ops;
-#else
-	ppc_md.smp_ops = &xics_smp_ops;
-#endif /* CONFIG_POWER4 */
-#endif /* CONFIG_SMP */
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.ide_check_region = chrp_ide_check_region;
-        ppc_ide_md.ide_request_region = chrp_ide_request_region;
-        ppc_ide_md.ide_release_region = chrp_ide_release_region;
-        ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports;
-#endif
-
-	/*
-	 * Print the banner, then scroll down so boot progress
-	 * can be printed.  -- Cort 
-	 */
-	if ( ppc_md.progress ) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0);
-}
-
-void __chrp
-rtas_display_progress(char *s, unsigned short hex)
-{
-	int width;
-	char *os = s;
-
-	if ( call_rtas( "display-character", 1, 1, NULL, '\r' ) )
-		return;
-
-	width = max_width;
-	while ( *os )
-	{
-		if ( (*os == '\n') || (*os == '\r') )
-			width = max_width;
-		else
-			width--;
-		call_rtas( "display-character", 1, 1, NULL, *os++ );
-		/* if we overwrite the screen length */
-		if ( width == 0 )
-			while ( (*os != 0) && (*os != '\n') && (*os != '\r') )
-				os++;
-	}
-
-	/*while ( width-- > 0 )*/
-	call_rtas( "display-character", 1, 1, NULL, ' ' );
-}
-
-void __chrp
-rtas_indicator_progress(char *s, unsigned short hex)
-{
-	call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex);
-}
-
-#ifdef CONFIG_BOOTX_TEXT
-void
-btext_progress(char *s, unsigned short hex)
-{
-	prom_print(s);
-	prom_print("\n");
-}
-#endif /* CONFIG_BOOTX_TEXT */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/chrp_smp.c linux-2.4.20/arch/ppc/kernel/chrp_smp.c
--- linux-2.4.19/arch/ppc/kernel/chrp_smp.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/chrp_smp.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,148 +0,0 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- * Smp support for CHRP machines.
- *
- * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
- * deal of code from the sparc and intel versions.
- *
- * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/delay.h>
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-
-#include <asm/ptrace.h>
-#include <asm/atomic.h>
-#include <asm/irq.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/hardirq.h>
-#include <asm/softirq.h>
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/smp.h>
-#include <asm/residual.h>
-#include <asm/time.h>
-
-#include "open_pic.h"
-
-extern unsigned long smp_chrp_cpu_nr;
-
-static int __init
-smp_chrp_probe(void)
-{
-	if (smp_chrp_cpu_nr > 1)
-		openpic_request_IPIs();
-
-	return smp_chrp_cpu_nr;
-}
-
-static void __init
-smp_chrp_kick_cpu(int nr)
-{
-	*(unsigned long *)KERNELBASE = nr;
-	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
-}
-
-static void __init
-smp_chrp_setup_cpu(int cpu_nr)
-{
-	static atomic_t ready = ATOMIC_INIT(1);
-	static volatile int frozen = 0;
-
-	if (cpu_nr == 0) {
-		/* wait for all the others */
-		while (atomic_read(&ready) < smp_num_cpus)
-			barrier();
-		atomic_set(&ready, 1);
-		/* freeze the timebase */
-		call_rtas("freeze-time-base", 0, 1, NULL);
-		mb();
-		frozen = 1;
-		/* XXX assumes this is not a 601 */
-		set_tb(0, 0);
-		last_jiffy_stamp(0) = 0;
-		while (atomic_read(&ready) < smp_num_cpus)
-			barrier();
-		/* thaw the timebase again */
-		call_rtas("thaw-time-base", 0, 1, NULL);
-		mb();
-		frozen = 0;
-		smp_tb_synchronized = 1;
-	} else {
-		atomic_inc(&ready);
-		while (!frozen)
-			barrier();
-		set_tb(0, 0);
-		last_jiffy_stamp(0) = 0;
-		mb();
-		atomic_inc(&ready);
-		while (frozen)
-			barrier();
-	}
-
-	if (OpenPIC_Addr)
-		do_openpic_setup_cpu();
-}
-
-#ifdef CONFIG_POWER4
-static void __chrp
-smp_xics_message_pass(int target, int msg, unsigned long data, int wait)
-{
-	/* for now, only do reschedule messages
-	   since we only have one IPI */
-	if (msg != PPC_MSG_RESCHEDULE)
-		return;
-	for (i = 0; i < smp_num_cpus; ++i) {
-		if (target == MSG_ALL || target == i
-		    || (target == MSG_ALL_BUT_SELF
-			&& i != smp_processor_id()))
-			xics_cause_IPI(i);
-	}
-}
-
-static int __chrp
-smp_xics_probe(void)
-{
-	return smp_chrp_cpu_nr;
-}
-
-static void __chrp
-smp_xics_setup_cpu(int cpu_nr)
-{
-	if (cpu_nr > 0)
-		xics_setup_cpu();
-}
-#endif /* CONFIG_POWER4 */
-
-/* CHRP with openpic */
-struct smp_ops_t chrp_smp_ops __chrpdata = {
-	smp_openpic_message_pass,
-	smp_chrp_probe,
-	smp_chrp_kick_cpu,
-	smp_chrp_setup_cpu,
-};
-
-#ifdef CONFIG_POWER4
-/* CHRP with new XICS interrupt controller */
-struct smp_ops_t xics_smp_ops __chrpdata = {
-	smp_xics_message_pass,
-	smp_xics_probe,
-	smp_chrp_kick_cpu,
-	smp_xics_setup_cpu,
-};
-#endif /* CONFIG_POWER4 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/chrp_time.c linux-2.4.20/arch/ppc/kernel/chrp_time.c
--- linux-2.4.19/arch/ppc/kernel/chrp_time.c	2001-09-08 19:38:41.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/chrp_time.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,195 +0,0 @@
-/*
- * BK Id: SCCS/s.chrp_time.c 1.10 09/08/01 15:47:42 paulus
- */
-/*
- *  linux/arch/i386/kernel/time.c
- *
- *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *
- * Adapted for PowerPC (PreP) by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
- *  copied and modified from intel version
- *
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-#include <linux/kernel_stat.h>
-#include <linux/mc146818rtc.h>
-#include <linux/init.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/processor.h>
-#include <asm/nvram.h>
-#include <asm/prom.h>
-#include <asm/sections.h>
-#include <asm/time.h>
-
-extern spinlock_t rtc_lock;
-
-static int nvram_as1 = NVRAM_AS1;
-static int nvram_as0 = NVRAM_AS0;
-static int nvram_data = NVRAM_DATA;
-
-long __init chrp_time_init(void)
-{
-	struct device_node *rtcs;
-	int base;
-
-	rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
-	if (rtcs == NULL || rtcs->addrs == NULL)
-		return 0;
-	base = rtcs->addrs[0].address;
-	nvram_as1 = 0;
-	nvram_as0 = base;
-	nvram_data = base + 1;
-	
-	return 0;
-}
-
-int __chrp chrp_cmos_clock_read(int addr)
-{
-	if (nvram_as1 != 0)
-		outb(addr>>8, nvram_as1);
-	outb(addr, nvram_as0);
-	return (inb(nvram_data));
-}
-
-void __chrp chrp_cmos_clock_write(unsigned long val, int addr)
-{
-	if (nvram_as1 != 0)
-		outb(addr>>8, nvram_as1);
-	outb(addr, nvram_as0);
-	outb(val, nvram_data);
-	return;
-}
-
-/*
- * Set the hardware clock. -- Cort
- */
-int __chrp chrp_set_rtc_time(unsigned long nowtime)
-{
-	unsigned char save_control, save_freq_select;
-	struct rtc_time tm;
-
-	spin_lock(&rtc_lock);
-	to_tm(nowtime, &tm);
-
-	save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
-
-	chrp_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
-
-	save_freq_select = chrp_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
-	
-	chrp_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
-        tm.tm_year -= 1900;
-	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-		BIN_TO_BCD(tm.tm_sec);
-		BIN_TO_BCD(tm.tm_min);
-		BIN_TO_BCD(tm.tm_hour);
-		BIN_TO_BCD(tm.tm_mon);
-		BIN_TO_BCD(tm.tm_mday);
-		BIN_TO_BCD(tm.tm_year);
-	}
-	chrp_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
-	chrp_cmos_clock_write(tm.tm_min,RTC_MINUTES);
-	chrp_cmos_clock_write(tm.tm_hour,RTC_HOURS);
-	chrp_cmos_clock_write(tm.tm_mon,RTC_MONTH);
-	chrp_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
-	chrp_cmos_clock_write(tm.tm_year,RTC_YEAR);
-	
-	/* The following flags have to be released exactly in this order,
-	 * otherwise the DS12887 (popular MC146818A clone with integrated
-	 * battery and quartz) will not reset the oscillator and will not
-	 * update precisely 500 ms later. You won't find this mentioned in
-	 * the Dallas Semiconductor data sheets, but who believes data
-	 * sheets anyway ...                           -- Markus Kuhn
-	 */
-	chrp_cmos_clock_write(save_control, RTC_CONTROL);
-	chrp_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
-
-	if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
-		time_state = TIME_OK;
-	spin_unlock(&rtc_lock);
-	return 0;
-}
-
-unsigned long __chrp chrp_get_rtc_time(void)
-{
-	unsigned int year, mon, day, hour, min, sec;
-	int uip, i;
-
-	/* The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-
-	/* Since the UIP flag is set for about 2.2 ms and the clock
-	 * is typically written with a precision of 1 jiffy, trying
-	 * to obtain a precision better than a few milliseconds is 
-	 * an illusion. Only consistency is interesting, this also
-	 * allows to use the routine for /dev/rtc without a potential
-	 * 1 second kernel busy loop triggered by any reader of /dev/rtc. 
-	 */
-
-	for ( i = 0; i<1000000; i++) {
-		uip = chrp_cmos_clock_read(RTC_FREQ_SELECT);
-		sec = chrp_cmos_clock_read(RTC_SECONDS);
-		min = chrp_cmos_clock_read(RTC_MINUTES);
-		hour = chrp_cmos_clock_read(RTC_HOURS);
-		day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH);
-		mon = chrp_cmos_clock_read(RTC_MONTH);
-		year = chrp_cmos_clock_read(RTC_YEAR);
-		uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT);
-		if ((uip & RTC_UIP)==0) break;
-	}
-
-	if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-	  {
-	    BCD_TO_BIN(sec);
-	    BCD_TO_BIN(min);
-	    BCD_TO_BIN(hour);
-	    BCD_TO_BIN(day);
-	    BCD_TO_BIN(mon);
-	    BCD_TO_BIN(year);
-	  }
-	if ((year += 1900) < 1970)
-		year += 100;
-	return mktime(year, mon, day, hour, min, sec);
-}
-
-
-void __init chrp_calibrate_decr(void)
-{
-	struct device_node *cpu;
-	unsigned int freq, *fp;
-
-	if (via_calibrate_decr())
-		return;
-
-	/*
-	 * The cpu node should have a timebase-frequency property
-	 * to tell us the rate at which the decrementer counts.
-	 */
-	freq = 16666000;		/* hardcoded default */
-	cpu = find_type_devices("cpu");
-	if (cpu != 0) {
-		fp = (unsigned int *)
-			get_property(cpu, "timebase-frequency", NULL);
-		if (fp != 0)
-			freq = *fp;
-	}
-	printk("time_init: decrementer frequency = %u.%.6u MHz\n",
- 	       freq/1000000, freq%1000000);
-	tb_ticks_per_jiffy = freq / HZ;
-	tb_to_us = mulhwu_scale_factor(freq, 1000000);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/cputable.c linux-2.4.20/arch/ppc/kernel/cputable.c
--- linux-2.4.19/arch/ppc/kernel/cputable.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/cputable.c	2002-10-29 11:18:48.000000000 +0000
@@ -21,19 +21,20 @@
 
 struct cpu_spec* cur_cpu_spec[NR_CPUS];
 
-extern void __setup_cpu_601(int cpu_nr);
-extern void __setup_cpu_603(int cpu_nr);
-extern void __setup_cpu_604(int cpu_nr);
-extern void __setup_cpu_750(int cpu_nr);
-extern void __setup_cpu_7400(int cpu_nr);
-extern void __setup_cpu_7410(int cpu_nr);
-extern void __setup_cpu_7450(int cpu_nr);
-extern void __setup_cpu_7450_23(int cpu_nr);
-extern void __setup_cpu_7455(int cpu_nr);
-extern void __setup_cpu_power3(int cpu_nr);
-extern void __setup_cpu_power4(int cpu_nr);
-extern void __setup_cpu_8xx(int cpu_nr);
-extern void __setup_cpu_generic(int cpu_nr);
+extern void __setup_cpu_601(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_603(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_604(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_750(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_750cx(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_750fx(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_7400(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_7410(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_7450(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_7455(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_power3(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_power4(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_8xx(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_generic(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 
 #define CLASSIC_PPC (!defined(CONFIG_8xx) && 	 \
 		     !defined(CONFIG_4xx) && !defined(CONFIG_POWER3) &&  \
@@ -141,15 +142,16 @@
 	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP,
 	COMMON_PPC,
 	32, 32,
-	__setup_cpu_750
+	__setup_cpu_750cx
     },
     {	/* 750FX (All revs for now) */
     	0xffff0000, 0x70000000, "750FX",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP,
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP |
+	CPU_FTR_DUAL_PLL_750FX,
 	COMMON_PPC,
 	32, 32,
-	__setup_cpu_750
+	__setup_cpu_750fx
     },
     {	/* 740/750 (L2CR bit need fixup for 740) */
     	0xffff0000, 0x00080000, "740/750",
@@ -189,7 +191,7 @@
     {	/* 7450 2.0 - no doze/nap */
     	0xffffffff, 0x80000200, "7450",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
 	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
@@ -198,8 +200,9 @@
     {	/* 7450 2.1 */
     	0xffffffff, 0x80000201, "7450",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
-	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
+	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR |
+	CPU_FTR_L3_DISABLE_NAP,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
 	__setup_cpu_7450
@@ -207,17 +210,36 @@
     {	/* 7450 2.3 and newer */
     	0xffff0000, 0x80000000, "7450",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
+	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR,
+	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+	32, 32,
+	__setup_cpu_7450
+    },
+    {	/* 7455 rev 1.x */
+    	0xffffff00, 0x80010100, "7455",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
 	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
-	__setup_cpu_7450_23
+	__setup_cpu_7455
+    },
+    {	/* 7455 rev 2.0 */
+    	0xffffffff, 0x80010200, "7455",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
+	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR |
+	CPU_FTR_L3_DISABLE_NAP,
+	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+	32, 32,
+	__setup_cpu_7455
     },
-    {	/* 7455 */
+    {	/* 7455 others */
     	0xffff0000, 0x80010000, "7455",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
-	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
+	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
 	__setup_cpu_7455
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/entry.S linux-2.4.20/arch/ppc/kernel/entry.S
--- linux-2.4.19/arch/ppc/kernel/entry.S	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/entry.S	2002-10-29 11:18:36.000000000 +0000
@@ -22,7 +22,6 @@
  *	
  */
 
-#include "ppc_asm.h"
 #include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sys.h>
@@ -31,6 +30,8 @@
 #include <asm/page.h>
 #include <asm/mmu.h>
 #include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include "ppc_defs.h"
 
 #undef SHOW_SYSCALLS
 #undef SHOW_SYSCALLS_TASK
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/error_log.c linux-2.4.20/arch/ppc/kernel/error_log.c
--- linux-2.4.19/arch/ppc/kernel/error_log.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/error_log.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,186 +0,0 @@
-/*
- * BK Id: SCCS/s.error_log.c 1.6 05/17/01 18:14:21 cort
- */
-/*
- *  arch/ppc/kernel/error_log.c
- *  
- *  Copyright (c) 2000 Tilmann Bitterberg
- *  (tilmann@bitterberg.de)
- *
- *  Error processing of errors found by rtas even-scan routine
- *  which is done with every heartbeat. (chrp_setup.c)
- */
-
-#include <linux/sched.h>
-
-#include <asm/prom.h>
-
-#include "error_log.h"
-
-/* ****************************************************************** */
-/* 
- * EVENT-SCAN
- * The whole stuff below here doesn't take any action when it found
- * an error, it just prints as much information as possible and 
- * then its up to the user to decide what to do.
- *
- * Returns 0 if no errors were found
- * Returns 1 if there may be more errors
- */
-int ppc_rtas_errorlog_scan(void)
-{
-const char *_errlog_severity[] = {
-#ifdef VERBOSE_ERRORS
-	"No Error\n\t\
-Should require no further information",
-	"Event\n\t\
-This is not really an error, it is an event. I use events\n\t\
-to communicate with RTAS back and forth.",
-	"Warning\n\t\
-Indicates a non-state-losing error, either fully recovered\n\t\
-by RTAS or not needing recovery. Ignore it.",
-	"Error sync\n\t\
-May only be fatal to a certain program or thread. Recovery\n\t\
-and continuation is possible, if I only had a handler for\n\t\
-this. Less serious",
-	"Error\n\t\
-Less serious, but still causing a loss of data and state.\n\t\
-I can't tell you exactly what to do, You have to decide\n\t\
-with help from the target and initiator field, what kind\n\t\
-of further actions may take place.",
-	"Fatal\n\t\
-Represent a permanent hardware failure and I believe this\n\t\
-affects my overall performance and behaviour. I would not\n\t\
-attempt to continue normal operation."
-#else
-	"No Error",
-	"Event",
-	"Warning",
-	"Error sync",
-	"Error",
-	"Fatal"
-#endif /* VERBOSE_ERRORS */
-};
-
-#if 0 /* unused?? */
-const char *_errlog_disposition[] = {
-#ifdef VERBOSE_ERRORS
-	"Fully recovered\n\t\
-There was an error, but it is fully recovered by RTAS.",
-	"Limited recovery\n\t\
-RTAS was able to recover the state of the machine, but some\n\t\
-feature of the machine has been disabled or lost (for example\n\t\
-error checking) or performance may suffer.",
-	"Not recovered\n\t\
-Whether RTAS did not try to recover anything or recovery failed:\n\t\
-HOUSTON, WE HAVE A PROBLEM!"
-#else
-	"Fully recovered",
-	"Limited recovery",
-	"Not recovered"
-#endif /* VERBOSE_ERRORS */
-};
-#endif
-
-const char *_errlog_extended[] = {
-#ifdef VERBOSE_ERRORS
-	"Not present\n\t\
-Sad, the RTAS call didn't return an extended error log.",
-	"Present\n\t\
-The extended log is present and hopefully it contains a lot of\n\t\
-useful information, which leads to the solution of the problem."
-#else
-	"Not present",
-	"Present"
-#endif /* VERBOSE_ERRORS */
-};
-
-const char *_errlog_initiator[] = { 
-	"Unknown or not applicable",
-	"CPU",
-	"PCI",
-	"ISA",
-	"Memory",
-	"Power management"
-};
-
-const char *_errlog_target[] = { 
-	"Unknown or not applicable",
-	"CPU",
-	"PCI",
-	"ISA",
-	"Memory",
-	"Power management"
-};
-	rtas_error_log error_log;
-	char logdata[1024];
-	int error;
-#if 0 /* unused?? */
-	int retries = 0; /* if HW error, try 10 times */
-#endif
-
-	error = call_rtas ("event-scan", 4, 1, (unsigned long *)&error_log,
-			INTERNAL_ERROR | EPOW_WARNING,
-			0, __pa(logdata), 1024);
-
-	if (error == 1) /* no errors found */
-		return 0;
-
-	if (error == -1) {
-		printk(KERN_ERR "Unable to get errors. Do you a favor and throw this box away\n");
-		return 0;
-	}
-	if (error_log.version != 1)
-		printk(KERN_WARNING "Unknown version (%d), please implement me\n", 
-				error_log.version);
-
-	switch (error_log.disposition) {
-		case DISP_FULLY_RECOVERED:
-			/* there was an error, but everything is fine now */
-			return 0;
-		case DISP_NOT_RECOVERED:
-			printk("We have a really serious Problem!\n");
-		case DISP_LIMITED_RECOVERY:
-			printk("Error classification\n");
-			printk("Severity  : %s\n", 
-					ppc_rtas_errorlog_check_severity (error_log));
-			printk("Initiator : %s\n", 
-					ppc_rtas_errorlog_check_initiator (error_log));
-			printk("Target    : %s\n", 
-					ppc_rtas_errorlog_check_target (error_log));
-			printk("Type      : %s\n", 
-					ppc_rtas_errorlog_check_type (error_log));
-			printk("Ext. log  : %s\n", 
-					ppc_rtas_errorlog_check_extended (error_log));
-			if (error_log.extended)
-				ppc_rtas_errorlog_disect_extended (logdata);
-			return 1;	
-		default:
-			/* nothing */
-			break;
-	}
-	return 0;
-}
-/* ****************************************************************** */
-const char * ppc_rtas_errorlog_check_type (rtas_error_log error_log)
-{
-	const char *_errlog_type[] = {
-		"unknown type",
-		"too many tries failed",
-		"TCE error",
-		"RTAS device failed",
-		"target timed out",
-		"parity error on data",			/* 5 */
-		"parity error on address",
-		"parity error on external cache",
-		"access to invalid address",
-		"uncorrectable ECC error",
-		"corrected ECC error"			/* 10 */
-	};
-	if (error_log.type == TYPE_EPOW) 
-		return "EPOW"; 
-	if (error_log.type >= TYPE_PMGM_POWER_SW_ON)
-		return "PowerMGM Event (not handled right now)";
-	return _errlog_type[error_log.type];
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/error_log.h linux-2.4.20/arch/ppc/kernel/error_log.h
--- linux-2.4.19/arch/ppc/kernel/error_log.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/error_log.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,98 +0,0 @@
-/*
- * BK Id: SCCS/s.error_log.h 1.5 05/17/01 18:14:21 cort
- */
-#ifndef __ERROR_LOG_H__
-#define __ERROR_LOG_H__
-
-#define VERBOSE_ERRORS		1 /* Maybe I enlarge the kernel too much */
-#undef VERBOSE_ERRORS
-
-/* Event classes */
-/* XXX: Endianess correct? NOW*/
-#define INTERNAL_ERROR		0x80000000 /* set bit 0 */
-#define EPOW_WARNING		0x40000000 /* set bit 1 */
-#define POWERMGM_EVENTS		0x20000000 /* set bit 2 */
-
-/* event-scan returns */
-#define SEVERITY_FATAL		0x5
-#define SEVERITY_ERROR		0x4
-#define SEVERITY_ERROR_SYNC	0x3
-#define SEVERITY_WARNING	0x2
-#define SEVERITY_EVENT		0x1
-#define SEVERITY_NO_ERROR	0x0
-#define DISP_FULLY_RECOVERED	0x0
-#define DISP_LIMITED_RECOVERY	0x1
-#define DISP_NOT_RECOVERED	0x2
-#define PART_PRESENT		0x0
-#define PART_NOT_PRESENT	0x1
-#define INITIATOR_UNKNOWN	0x0
-#define INITIATOR_CPU		0x1
-#define INITIATOR_PCI		0x2
-#define INITIATOR_ISA		0x3
-#define INITIATOR_MEMORY	0x4
-#define INITIATOR_POWERMGM	0x5
-#define TARGET_UNKNOWN		0x0
-#define TARGET_CPU		0x1
-#define TARGET_PCI		0x2
-#define TARGET_ISA		0x3
-#define TARGET_MEMORY		0x4
-#define TARGET_POWERMGM		0x5
-#define TYPE_RETRY		0x01
-#define TYPE_TCE_ERR		0x02
-#define TYPE_INTERN_DEV_FAIL	0x03
-#define TYPE_TIMEOUT		0x04
-#define TYPE_DATA_PARITY	0x05
-#define TYPE_ADDR_PARITY	0x06
-#define TYPE_CACHE_PARITY	0x07
-#define TYPE_ADDR_INVALID	0x08
-#define TYPE_ECC_UNCORR		0x09
-#define TYPE_ECC_CORR		0x0a
-#define TYPE_EPOW		0x40
-/* I don't add PowerMGM events right now, this is a different topic */ 
-#define TYPE_PMGM_POWER_SW_ON	0x60
-#define TYPE_PMGM_POWER_SW_OFF	0x61
-#define TYPE_PMGM_LID_OPEN	0x62
-#define TYPE_PMGM_LID_CLOSE	0x63
-#define TYPE_PMGM_SLEEP_BTN	0x64
-#define TYPE_PMGM_WAKE_BTN	0x65
-#define TYPE_PMGM_BATTERY_WARN	0x66
-#define TYPE_PMGM_BATTERY_CRIT	0x67
-#define TYPE_PMGM_SWITCH_TO_BAT	0x68
-#define TYPE_PMGM_SWITCH_TO_AC	0x69
-#define TYPE_PMGM_KBD_OR_MOUSE	0x6a
-#define TYPE_PMGM_ENCLOS_OPEN	0x6b
-#define TYPE_PMGM_ENCLOS_CLOSED	0x6c
-#define TYPE_PMGM_RING_INDICATE	0x6d
-#define TYPE_PMGM_LAN_ATTENTION	0x6e
-#define TYPE_PMGM_TIME_ALARM	0x6f
-#define TYPE_PMGM_CONFIG_CHANGE	0x70
-#define TYPE_PMGM_SERVICE_PROC	0x71
-
-typedef struct _rtas_error_log {
-	unsigned long version:8;		/* Architectural version */
-	unsigned long severity:3;		/* Severity level of error */
-	unsigned long disposition:2;		/* Degree of recovery */
-	unsigned long extended:1;		/* extended log present? */
-	unsigned long /* reserved */ :2;	/* Reserved for future use */
-	unsigned long initiator:4;		/* Initiator of event */
-	unsigned long target:4;			/* Target of failed operation */
-	unsigned long type:8;			/* General event or error*/
-	unsigned long extended_log_length:32;	/* length in bytes */
-} rtas_error_log;
-
-/* ****************************************************************** */
-#define ppc_rtas_errorlog_check_severity(x) \
-	(_errlog_severity[x.severity])
-#define ppc_rtas_errorlog_check_target(x) \
-	(_errlog_target[x.target])
-#define ppc_rtas_errorlog_check_initiator(x) \
-	(_errlog_initiator[x.initiator])
-#define ppc_rtas_errorlog_check_extended(x) \
-	(_errlog_extended[x.extended])
-#define ppc_rtas_errorlog_disect_extended(x) \
-	do { /* implement me */ } while(0)
-extern const char * ppc_rtas_errorlog_check_type (rtas_error_log error_log);
-extern int ppc_rtas_errorlog_scan(void);
-
-
-#endif /* __ERROR_LOG_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/galaxy_pci.c linux-2.4.20/arch/ppc/kernel/galaxy_pci.c
--- linux-2.4.19/arch/ppc/kernel/galaxy_pci.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/galaxy_pci.c	2002-10-29 11:18:48.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.galaxy_pci.c 1.7 05/17/01 18:14:21 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *
@@ -27,8 +27,7 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
-
-#include "pci.h"
+#include <asm/pci-bridge.h>
 
 
 /* Preprocessor Defines */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/gemini_pci.c linux-2.4.20/arch/ppc/kernel/gemini_pci.c
--- linux-2.4.19/arch/ppc/kernel/gemini_pci.c	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/gemini_pci.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,124 +0,0 @@
-/*
- * BK Id: SCCS/s.gemini_pci.c 1.6 10/11/01 08:51:46 trini
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <asm/machdep.h>
-#include <asm/gemini.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/pci-bridge.h>
-
-#include "pci.h"
-
-#define pci_config_addr(bus,dev,offset) \
-        (0x80000000 | (bus<<16) | (dev<<8) | offset)
-
-
-int
-gemini_pcibios_read_config_byte(struct pci_dev *dev, int offset, u8 *val)
-{
-	unsigned long reg;
-	reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn,
-					   (offset & ~(0x3))));
-	*val = ((reg >> ((offset & 0x3) << 3)) & 0xff);
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int
-gemini_pcibios_read_config_word(struct pci_dev *dev, int offset, u16 *val)
-{
-	unsigned long reg;
-	reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn,
-					   (offset & ~(0x3))));
-	*val = ((reg >> ((offset & 0x3) << 3)) & 0xffff);
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int
-gemini_pcibios_read_config_dword(struct pci_dev *dev, int offset, u32 *val)
-{
-	*val = grackle_read(pci_config_addr(dev->bus->number, dev->devfn,
-					    (offset & ~(0x3))));
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int
-gemini_pcibios_write_config_byte(struct pci_dev *dev, int offset, u8 val)
-{
-	unsigned long reg;
-	int shifts = offset & 0x3;
-	unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn,
-					    (offset & ~(0x3)));
-
-	reg = grackle_read(addr);
-	reg = (reg & ~(0xff << (shifts << 3))) | (val << (shifts << 3));
-	grackle_write(addr, reg );
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int
-gemini_pcibios_write_config_word(struct pci_dev *dev, int offset, u16 val)
-{
-	unsigned long reg;
-	int shifts = offset & 0x3;
-	unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn,
-					    (offset & ~(0x3)));
-
-	reg = grackle_read(addr);
-	reg = (reg & ~(0xffff << (shifts << 3))) | (val << (shifts << 3));
-	grackle_write(addr, reg );
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int
-gemini_pcibios_write_config_dword(struct pci_dev *dev, int offset, u32 val)
-{
-	grackle_write(pci_config_addr(dev->bus->number, dev->devfn,
-				      (offset & ~(0x3))), val);
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops gemini_pci_ops =
-{
-	gemini_pcibios_read_config_byte,
-	gemini_pcibios_read_config_word,
-	gemini_pcibios_read_config_dword,
-	gemini_pcibios_write_config_byte,
-	gemini_pcibios_write_config_word,
-	gemini_pcibios_write_config_dword
-};
-
-void __init gemini_pcibios_fixup(void)
-{
-	int i;
-	struct pci_dev *dev;
-	
-	pci_for_each_dev(dev) {
-		for(i = 0; i < 6; i++) {
-			if (dev->resource[i].flags & IORESOURCE_IO) {
-				dev->resource[i].start |= (0xfe << 24);
-				dev->resource[i].end |= (0xfe << 24);
-			}
-		}
-	}
-}
-
-
-/* The "bootloader" for Synergy boards does none of this for us, so we need to
-   lay it all out ourselves... --Dan */
-void __init gemini_find_bridges(void)
-{
-	struct pci_controller* hose;
-	
-	ppc_md.pcibios_fixup = gemini_pcibios_fixup;
-
-	hose = pcibios_alloc_controller();
-	if (!hose)
-		return;
-	hose->ops = &gemini_pci_ops;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/gemini_prom.S linux-2.4.20/arch/ppc/kernel/gemini_prom.S
--- linux-2.4.19/arch/ppc/kernel/gemini_prom.S	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/gemini_prom.S	1970-01-01 00:00:00.000000000 +0000
@@ -1,99 +0,0 @@
-/*
- * BK Id: SCCS/s.gemini_prom.S 1.5 05/17/01 18:14:21 cort
- */
-/*
- *  arch/ppc/kernel/gemini_prom.S
- *
- *  Not really prom support code (yet), but sort of anti-prom code.  The current
- *  bootloader does a number of things it shouldn't and doesn't do things that it
- *  should.  The stuff in here is mainly a hodge-podge collection of setup code
- *  to get the board up and running.
- *    ---Dan
- */
-
-#include "ppc_asm.tmpl"
-#include "ppc_defs.h"
-#include <linux/config.h>
-#include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/gemini.h>
-
-#define HID0_ABE (1<<3)
-
-/*
- *  On 750's the MMU is on when Linux is booted, so we need to clear out the
- *  bootloader's BAT settings, make sure we're in supervisor state (gotcha!),
- *  and turn off the MMU.
- *
- */
-
-_GLOBAL(gemini_prom_init)
-#ifdef CONFIG_SMP
-	/* Since the MMU's on, get stuff in rom space that we'll need */
-	lis	r4,GEMINI_CPUSTAT@h
-	ori	r4,r4,GEMINI_CPUSTAT@l
-	lbz	r5,0(r4)
-	andi.	r5,r5,3
-	mr	r24,r5		/* cpu # used later on */
-#endif
-	mfmsr	r4
-	li	r3,MSR_PR	/* ensure supervisor! */
-	ori	r3,r3,MSR_IR|MSR_DR
-	andc	r4,r4,r3
-	mtmsr	r4
-	isync
-#if 0
-	/* zero out the bats now that the MMU is off */
-prom_no_mmu:	
-	li	r3,0
-        mtspr   IBAT0U,r3
-        mtspr   IBAT0L,r3
-        mtspr   IBAT1U,r3
-        mtspr   IBAT1L,r3
-        mtspr   IBAT2U,r3
-        mtspr   IBAT2L,r3
-        mtspr   IBAT3U,r3
-        mtspr   IBAT3L,r3
-
-        mtspr   DBAT0U,r3
-        mtspr   DBAT0L,r3
-        mtspr   DBAT1U,r3
-        mtspr   DBAT1L,r3
-        mtspr   DBAT2U,r3
-	mtspr   DBAT2L,r3
-        mtspr   DBAT3U,r3
-        mtspr   DBAT3L,r3
-#endif
-
-	/* the bootloader (as far as I'm currently aware) doesn't mess with page
-	   tables, but since we're already here, might as well zap these, too */
-	li	r4,0
-	mtspr	SDR1,r4
-
-	li	r4,16
-	mtctr	r4
-	li	r3,0
-	li	r4,0
-3:	mtsrin	r3,r4
-	addi	r3,r3,1
-	bdnz	3b
-
-#ifdef CONFIG_SMP
-	/* The 750 book (and Mot/IBM support) says that this will "assist" snooping
-	   when in SMP.  Not sure yet whether this should stay or leave... */
-	mfspr	r4,HID0
-	ori	r4,r4,HID0_ABE
-	mtspr	HID0,r4
-	sync
-#endif /* CONFIG_SMP */
-	blr
-
-/*  apparently, SMon doesn't pay attention to HID0[SRST].  Disable the MMU and
-    branch to 0xfff00100 */
-_GLOBAL(_gemini_reboot)
-	lis	r5,GEMINI_BOOT_INIT@h
-	ori	r5,r5,GEMINI_BOOT_INIT@l
-	li	r6,MSR_IP
-	mtspr	SRR0,r5
-	mtspr	SRR1,r6
-	rfi
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/gemini_setup.c linux-2.4.20/arch/ppc/kernel/gemini_setup.c
--- linux-2.4.19/arch/ppc/kernel/gemini_setup.c	2001-11-16 18:10:08.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/gemini_setup.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,584 +0,0 @@
-/*
- * BK Id: SCCS/s.gemini_setup.c 1.14 10/18/01 11:16:28 trini
- */
-/*
- *  linux/arch/ppc/kernel/setup.c
- *
- *  Copyright (C) 1995 Linus Torvalds
- *  Adapted from 'alpha' version by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu)
- *  Synergy Microsystems board support by Dan Cox (dan@synergymicro.com)
- *
- */
-
-#include <linux/config.h>
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h> 
-#include <linux/reboot.h>
-#include <linux/pci.h>
-#include <linux/time.h>
-#include <linux/kdev_t.h>
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/blk.h>
-#include <linux/console.h>
-#include <linux/seq_file.h>
-
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/m48t35.h>
-#include <asm/gemini.h>
-#include <asm/time.h>
-
-#include "local_irq.h"
-#include "open_pic.h"
-
-void gemini_find_bridges(void);
-static int gemini_get_clock_speed(void);
-extern void gemini_pcibios_fixup(void);
-
-static char *gemini_board_families[] = {
-  "VGM", "VSS", "KGM", "VGR", "VCM", "VCS", "KCM", "VCR"
-};
-static int gemini_board_count = sizeof(gemini_board_families) /
-                                 sizeof(gemini_board_families[0]);
-
-static unsigned int cpu_7xx[16] = {
-	0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
-};
-static unsigned int cpu_6xx[16] = {
-	0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0
-};
-
-/*
- * prom_init is the Gemini version of prom.c:prom_init.  We only need
- * the BSS clearing code, so I copied that out of prom.c.  This is a
- * lot simpler than hacking prom.c so it will build with Gemini. -VAL
- */
-
-#define PTRRELOC(x)	((typeof(x))((unsigned long)(x) + offset))
-
-unsigned long
-prom_init(void)
-{
-	unsigned long offset = reloc_offset();
-	unsigned long phys;
-	extern char __bss_start, _end;
-
-	/* First zero the BSS -- use memset, some arches don't have
-	 * caches on yet */
-	memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start);
-
- 	/* Default */
- 	phys = offset + KERNELBASE;
-
-	gemini_prom_init();
-
-	return phys;
-}
-
-int
-gemini_show_cpuinfo(struct seq_file *m)
-{
-	unsigned char reg, rev;
-	char *family;
-	unsigned int type;
-
-	reg = readb(GEMINI_FEAT);
-	family = gemini_board_families[((reg>>4) & 0xf)];
-	if (((reg>>4) & 0xf) > gemini_board_count)
-		printk(KERN_ERR "cpuinfo(): unable to determine board family\n");
-
-	reg = readb(GEMINI_BREV);
-	type = (reg>>4) & 0xf;
-	rev = reg & 0xf;
-
-	reg = readb(GEMINI_BECO);
-
-	seq_printf(m, "machine\t\t: Gemini %s%d, rev %c, eco %d\n", 
-		   family, type, (rev + 'A'), (reg & 0xf));
-
-	seq_printf(m, "board\t\t: Gemini %s", family);
-	if (type > 9)
-		seq_printf(m, "%c", (type - 10) + 'A');
-	else
-		seq_printf(m, "%d", type);
-
-	seq_printf(m, ", rev %c, eco %d\n", (rev + 'A'), (reg & 0xf));
-
-	seq_printf(m, "clock\t\t: %dMhz\n", gemini_get_clock_speed());
-
-	return 0;
-}
-
-static u_char gemini_openpic_initsenses[] = {
-	1,
-	1,
-	1,
-	1,
-	0,
-	0,
-	1, /* remainder are level-triggered */
-};
-
-#define GEMINI_MPIC_ADDR (0xfcfc0000)
-#define GEMINI_MPIC_PCI_CFG (0x80005800)
-
-void __init gemini_openpic_init(void)
-{
-
-	OpenPIC_Addr = (volatile struct OpenPIC *)
-		grackle_read(GEMINI_MPIC_PCI_CFG + 0x10);
-	OpenPIC_InitSenses = gemini_openpic_initsenses;
-	OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses );
-
-	ioremap( GEMINI_MPIC_ADDR, OPENPIC_SIZE);
-}
-
-
-extern unsigned long loops_per_jiffy;
-extern int root_mountflags;
-extern char cmd_line[];
-
-void
-gemini_heartbeat(void)
-{
-	static unsigned long led = GEMINI_LEDBASE+(4*8);
-	static char direction = 8;
-
-	/* We only want to do this on 1 CPU */
-	if (smp_processor_id())
-		return;
-	*(char *)led = 0;
-	if ( (led + direction) > (GEMINI_LEDBASE+(7*8)) ||
-	     (led + direction) < (GEMINI_LEDBASE+(4*8)) )
-		direction *= -1;
-	led += direction;
-	*(char *)led = 0xff;
-	ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
-}
-
-void __init gemini_setup_arch(void)
-{
-	extern char cmd_line[];
-
-
-	loops_per_jiffy = 50000000/HZ;
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	/* bootable off CDROM */
-	if (initrd_start)
-		ROOT_DEV = MKDEV(SCSI_CDROM_MAJOR, 0);
-	else
-#endif
-		ROOT_DEV = to_kdev_t(0x0801);
-
-	/* nothing but serial consoles... */
-	sprintf(cmd_line, "%s console=ttyS0", cmd_line);
-
-	printk("Boot arguments: %s\n", cmd_line);
-
-	ppc_md.heartbeat = gemini_heartbeat;
-	ppc_md.heartbeat_reset = HZ/8;
-	ppc_md.heartbeat_count = 1;
-	
-	/* Lookup PCI hosts */
-	gemini_find_bridges();
-	/* take special pains to map the MPIC, since it isn't mapped yet */
-	gemini_openpic_init();
-	/* start the L2 */
-	gemini_init_l2();
-}
-
-
-int
-gemini_get_clock_speed(void)
-{
-	unsigned long hid1, pvr;
-	int clock;
-
-	pvr = mfspr(PVR);
-	hid1 = (mfspr(HID1) >> 28) & 0xf;
-	if (PVR_VER(pvr) == 8 ||
-	    PVR_VER(pvr) == 12)
-		hid1 = cpu_7xx[hid1];
-	else
-		hid1 = cpu_6xx[hid1];
-
-	switch((readb(GEMINI_BSTAT) & 0xc) >> 2) {
-
-	case 0:
-	default:
-		clock = (hid1*100)/3;
-		break;
-  
-	case 1:
-		clock = (hid1*125)/3;
-		break;
-  
-	case 2:
-		clock = (hid1*50);
-		break;
-	}
-
-	return clock;
-}
-
-void __init gemini_init_l2(void)
-{
-        unsigned char reg, brev, fam, creg;
-        unsigned long cache;
-        unsigned long pvr;
-
-        reg = readb(GEMINI_L2CFG);
-        brev = readb(GEMINI_BREV);
-        fam = readb(GEMINI_FEAT);
-        pvr = mfspr(PVR);
-
-        switch(PVR_VER(pvr)) {
-
-        case 8:
-                if (reg & 0xc0)
-                        cache = (((reg >> 6) & 0x3) << 28);
-                else
-                        cache = 0x3 << 28;
-
-#ifdef CONFIG_SMP
-                /* Pre-3.0 processor revs had snooping errata.  Leave
-                   their L2's disabled with SMP. -- Dan */
-                if (PVR_CFG(pvr) < 3) {
-                        printk("Pre-3.0 750; L2 left disabled!\n");
-                        return;
-                }
-#endif /* CONFIG_SMP */
-
-                /* Special case: VGM5-B's came before L2 ratios were set on
-                   the board.  Processor speed shouldn't be too high, so
-                   set L2 ratio to 1:1.5.  */
-                if ((brev == 0x51) && ((fam & 0xa0) >> 4) == 0)
-                        reg |= 1;
-
-                /* determine best cache ratio based upon what the board
-                   tells us (which sometimes _may_ not be true) and
-                   the processor speed. */
-                else {
-                        if (gemini_get_clock_speed() > 250)
-                                reg = 2;
-                }
-                break;
-        case 12:
-	{
-		static unsigned long l2_size_val = 0;
-		
-		if (!l2_size_val)
-			l2_size_val = _get_L2CR();
-		cache = l2_size_val;
-                break;
-	}
-        case 4:
-        case 9:
-                creg = readb(GEMINI_CPUSTAT);
-                if (((creg & 0xc) >> 2) != 1)
-                        printk("Dual-604 boards don't support the use of L2\n");
-                else
-                        writeb(1, GEMINI_L2CFG);
-                return;
-        default:
-                printk("Unknown processor; L2 left disabled\n");
-                return;
-        }
-
-        cache |= ((1<<reg) << 25);
-        cache |= (L2CR_L2RAM_MASK|L2CR_L2CTL|L2CR_L2DO);
-        _set_L2CR(0);
-        _set_L2CR(cache | L2CR_L2E);
-
-}
-
-void
-gemini_restart(char *cmd)
-{
-	__cli();
-	/* make a clean restart, not via the MPIC */
-	_gemini_reboot();
-	for(;;);
-}
-
-void
-gemini_power_off(void)
-{
-	for(;;);
-}
-
-void
-gemini_halt(void)
-{
-	gemini_restart(NULL);
-}
-
-void __init gemini_init_IRQ(void)
-{
-	/* gemini has no 8259 */
-	openpic_init(1, 0, 0, -1);
-}
-
-#define gemini_rtc_read(x)       (readb(GEMINI_RTC+(x)))
-#define gemini_rtc_write(val,x)  (writeb((val),(GEMINI_RTC+(x))))
-
-/* ensure that the RTC is up and running */
-long __init gemini_time_init(void)
-{
-	unsigned char reg;
-
-	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
-
-	if ( reg & M48T35_RTC_STOPPED ) {
-		printk(KERN_INFO "M48T35 real-time-clock was stopped. Now starting...\n");
-		gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL);
-		gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL);
-	}
-	return 0;
-}
-
-#undef DEBUG_RTC
-
-unsigned long
-gemini_get_rtc_time(void)
-{
-	unsigned int year, mon, day, hour, min, sec;
-	unsigned char reg;
-
-	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
-	gemini_rtc_write((reg|M48T35_RTC_READ), M48T35_RTC_CONTROL);
-#ifdef DEBUG_RTC
-	printk("get rtc: reg = %x\n", reg);
-#endif
-  
-	do {
-		sec = gemini_rtc_read(M48T35_RTC_SECONDS);
-		min = gemini_rtc_read(M48T35_RTC_MINUTES);
-		hour = gemini_rtc_read(M48T35_RTC_HOURS);
-		day = gemini_rtc_read(M48T35_RTC_DOM);
-		mon = gemini_rtc_read(M48T35_RTC_MONTH);
-		year = gemini_rtc_read(M48T35_RTC_YEAR);
-	} while( sec != gemini_rtc_read(M48T35_RTC_SECONDS));
-#ifdef DEBUG_RTC
-	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", 
-	       sec, min, hour, day, mon, year);
-#endif
-
-	gemini_rtc_write(reg, M48T35_RTC_CONTROL);
-
-	BCD_TO_BIN(sec);
-	BCD_TO_BIN(min);
-	BCD_TO_BIN(hour);
-	BCD_TO_BIN(day);
-	BCD_TO_BIN(mon);
-	BCD_TO_BIN(year);
-
-	if ((year += 1900) < 1970)
-		year += 100;
-#ifdef DEBUG_RTC
-	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", 
-	       sec, min, hour, day, mon, year);
-#endif
-
-	return mktime( year, mon, day, hour, min, sec );
-}
-
-
-int
-gemini_set_rtc_time( unsigned long now )
-{
-	unsigned char reg;
-	struct rtc_time tm;
-
-	to_tm( now, &tm );
-
-	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
-#if DEBUG_RTC
-	printk("set rtc: reg = %x\n", reg);
-#endif
-  
-	gemini_rtc_write((reg|M48T35_RTC_SET), M48T35_RTC_CONTROL);
-#if DEBUG_RTC
-	printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
-	       tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
-#endif
-  
-	tm.tm_year -= 1900;
-	BIN_TO_BCD(tm.tm_sec);
-	BIN_TO_BCD(tm.tm_min);
-	BIN_TO_BCD(tm.tm_hour);
-	BIN_TO_BCD(tm.tm_mon);
-	BIN_TO_BCD(tm.tm_mday);
-	BIN_TO_BCD(tm.tm_year);
-#ifdef DEBUG_RTC
-	printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
-	       tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
-#endif
-
-	gemini_rtc_write(tm.tm_sec, M48T35_RTC_SECONDS);
-	gemini_rtc_write(tm.tm_min, M48T35_RTC_MINUTES);
-	gemini_rtc_write(tm.tm_hour, M48T35_RTC_HOURS);
-	gemini_rtc_write(tm.tm_mday, M48T35_RTC_DOM);
-	gemini_rtc_write(tm.tm_mon, M48T35_RTC_MONTH);
-	gemini_rtc_write(tm.tm_year, M48T35_RTC_YEAR);
-
-	/* done writing */
-	gemini_rtc_write(reg, M48T35_RTC_CONTROL);
-
-	if ((time_state == TIME_ERROR) || (time_state == TIME_BAD))
-		time_state = TIME_OK;
-  
-	return 0;
-}
-
-/*  use the RTC to determine the decrementer count */
-void __init gemini_calibrate_decr(void)
-{
-	int freq, divisor;
-	unsigned char reg;
-
-	/* determine processor bus speed */
-	reg = readb(GEMINI_BSTAT);
-
-	switch(((reg & 0x0c)>>2)&0x3) {
-	case 0:
-	default:
-		freq = 66667;
-		break;
-	case 1:
-		freq = 83000;
-		break;
-	case 2:
-		freq = 100000;
-		break;
-	}
-
-	freq *= 1000;
-	divisor = 4;
-	tb_ticks_per_jiffy = freq / HZ / divisor;
-	tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
-}
-
-unsigned long __init gemini_find_end_of_memory(void)
-{
-	unsigned long total;
-	unsigned char reg;
-
-	reg = readb(GEMINI_MEMCFG);
-	total = ((1<<((reg & 0x7) - 1)) *
-		 (8<<((reg >> 3) & 0x7)));
-	total *= (1024*1024);
-	return total;
-}
-
-static void __init
-gemini_map_io(void)
-{
-	io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
-	io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
-}
-
-#ifdef CONFIG_SMP
-static int
-smp_gemini_probe(void)
-{
-	int i, nr;
-
-        nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2;
-	if (nr == 0)
-		nr = 4;
-
-	if (nr > 1) {
-		openpic_request_IPIs();
-		for (i = 1; i < nr; ++i)
-			smp_hw_index[i] = i;
-	}
-
-	return nr;
-}
-
-static void
-smp_gemini_kick_cpu(int nr)
-{
-	openpic_reset_processor_phys(1 << nr);
-	openpic_reset_processor_phys(0);
-}
-
-static void
-smp_gemini_setup_cpu(int cpu_nr)
-{
-	if (OpenPIC_Addr)
-		do_openpic_setup_cpu();
-	if (cpu_nr > 0)
-		gemini_init_l2();
-}
-
-static struct smp_ops_t gemini_smp_ops = {
-	smp_openpic_message_pass,
-	smp_gemini_probe,
-	smp_gemini_kick_cpu,
-	smp_gemini_setup_cpu,
-};
-#endif /* CONFIG_SMP */
-
-void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-			  unsigned long r6, unsigned long r7)
-{
-	int i;
-
-	for(i = 0; i < GEMINI_LEDS; i++)
-		gemini_led_off(i);
- 
-	ISA_DMA_THRESHOLD = 0;
-	DMA_MODE_READ = 0;
-	DMA_MODE_WRITE = 0;
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	if ( r4 )
-	{
-		initrd_start = r4 + KERNELBASE;
-		initrd_end = r5 + KERNELBASE;
-	}
-#endif
-
-	ppc_md.setup_arch = gemini_setup_arch;
-	ppc_md.show_cpuinfo = gemini_show_cpuinfo;
-	ppc_md.irq_cannonicalize = NULL;
-	ppc_md.init_IRQ = gemini_init_IRQ;
-	ppc_md.get_irq = openpic_get_irq;
-	ppc_md.init = NULL;
-
-	ppc_md.restart = gemini_restart;
-	ppc_md.power_off = gemini_power_off;
-	ppc_md.halt = gemini_halt;
-
-	ppc_md.time_init = gemini_time_init;
-	ppc_md.set_rtc_time = gemini_set_rtc_time;
-	ppc_md.get_rtc_time = gemini_get_rtc_time;
-	ppc_md.calibrate_decr = gemini_calibrate_decr;
-
-	ppc_md.find_end_of_memory = gemini_find_end_of_memory;
-	ppc_md.setup_io_mappings = gemini_map_io;
-
-	/* no keyboard/mouse/video stuff yet.. */
-	ppc_md.kbd_setkeycode = NULL;
-	ppc_md.kbd_getkeycode = NULL;
-	ppc_md.kbd_translate = NULL;
-	ppc_md.kbd_unexpected_up = NULL;
-	ppc_md.kbd_leds = NULL;
-	ppc_md.kbd_init_hw = NULL;
-	ppc_md.ppc_kbd_sysrq_xlate = NULL;
-	ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup;
-
-#ifdef CONFIG_SMP
-	ppc_md.smp_ops = &gemini_smp_ops;
-#endif /* CONFIG_SMP */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/head.S linux-2.4.20/arch/ppc/kernel/head.S
--- linux-2.4.19/arch/ppc/kernel/head.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/head.S	2002-10-29 11:18:31.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.head.S 1.43 06/25/02 17:24:29 benh
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  PowerPC version 
@@ -22,17 +22,19 @@
  *  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.
- *	
+ *
  */
 
 #include <linux/config.h>
-#include "ppc_asm.h"
+#include <linux/threads.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
 #include <asm/pgtable.h>
 #include <asm/cputable.h>
 #include <asm/cache.h>
+#include <asm/ppc_asm.h>
+#include "ppc_defs.h"
 
 #ifdef CONFIG_APUS
 #include <asm/amigappc.h>
@@ -48,9 +50,9 @@
 	ld	RB,(n*32)+24(reg);	\
 	mtspr	DBAT##n##U,RA;		\
 	mtspr	DBAT##n##L,RB;		\
-	
+
 #else /* CONFIG_PPC64BRIDGE */
-	
+
 /* 601 only have IBAT; cr0.eq is set on 601 when using this macro */
 #define LOAD_BAT(n, reg, RA, RB)	\
 	/* see the comment for clear_bats() -- Cort */ \
@@ -66,7 +68,7 @@
 	lwz	RB,(n*16)+12(reg);	\
 	mtspr	DBAT##n##U,RA;		\
 	mtspr	DBAT##n##L,RB;		\
-1:	
+1:
 #endif /* CONFIG_PPC64BRIDGE */	 
 
 	.text
@@ -113,7 +115,7 @@
  * PREP
  * This is jumped to on prep systems right after the kernel is relocated
  * to its proper place in memory by the boot loader.  The expected layout
- * of the regs is:	
+ * of the regs is:
  *   r3: ptr to residual data
  *   r4: initrd_start or if no initrd then 0
  *   r5: initrd_end - unused if r4 is 0
@@ -124,7 +126,7 @@
  * start_here() to do the real work.
  * -- Cort
  */
-	
+
 	.globl	__start
 __start:
 /*
@@ -184,6 +186,17 @@
 	mtsr	12,r5
 #endif /* CONFIG_POWER4 */
 
+	/*
+	 * Call setup_cpu for CPU 0
+	 */
+	bl	reloc_offset
+	li	r24,0			/* cpu# */
+	bl	call_setup_cpu		/* Call setup_cpu for this CPU */
+#ifdef CONFIG_6xx
+	bl	reloc_offset
+	bl	init_idle_6xx
+#endif /* CONFIG_6xx */
+
 #ifndef CONFIG_APUS
 /*
  * We need to run with _start at physical address 0.
@@ -404,16 +417,12 @@
 	EXCEPTION_PROLOG;
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	li	r20,MSR_KERNEL
-#ifndef CONFIG_APUS
 	li	r4,0
 	bl	transfer_to_handler
 	.globl do_IRQ_intercept
 do_IRQ_intercept:
 	.long	do_IRQ;
 	.long	ret_from_intercept
-#else
-	bl	apus_interrupt_entry
-#endif /* CONFIG_APUS */
 
 /* Alignment exception */
 	. = 0x600
@@ -503,7 +512,7 @@
 Trap_0f:
 	EXCEPTION_PROLOG
 	b	trap_0f_cont
-	
+
 /*
  * Handle TLB miss for instruction on 603/603e.
  * Note: we get an alternate set of r0 - r3 to use automatically.
@@ -652,7 +661,7 @@
 	mtcrf	0x80,r3		/* Restore CR0 */
 	mtmsr	r0
 	b	DataAccess
-	
+
 /*
  * Handle TLB miss for DATA Store on 603/603e
  */
@@ -775,6 +784,7 @@
 	SAVE_8GPRS(24, r21)
 	andi.	r23,r23,MSR_PR
 	mfspr	r23,SPRG3		/* if from user, fix up THREAD.regs */
+	addi	r2,r23,-THREAD		/* set r2 to current */
 	beq	2f
 	addi	r24,r1,STACK_FRAME_OVERHEAD
 	stw	r24,PT_REGS(r23)
@@ -784,7 +794,8 @@
 	stw	r22,THREAD_VRSAVE(r23)
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif /* CONFIG_ALTIVEC */
-2:	addi	r2,r23,-THREAD		/* set r2 to current */
+	.globl transfer_to_handler_cont
+transfer_to_handler_cont:
 	tovirt(r2,r2)
 	mflr	r23
 	andi.	r24,r23,0x3f00		/* get vector offset */
@@ -805,6 +816,23 @@
 	mtlr	r23
 	SYNC
 	RFI				/* jump to handler, enable MMU */
+2:
+	/* Out of line case when returning to kernel,
+	 * check return from power_save_6xx
+	 */
+#ifdef CONFIG_6xx
+	
+	mfspr	r24,SPRN_HID0
+	mtcr	r24
+BEGIN_FTR_SECTION
+	bt-	8,power_save_6xx_restore	/* Check DOZE */
+END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE)
+BEGIN_FTR_SECTION
+	bt-	9,power_save_6xx_restore	/* Check NAP */
+END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
+	b	transfer_to_handler_cont
+
+#endif /* CONFIG_6xx */
 
 /*
  * On kernel stack overflow, load up an initial stack pointer
@@ -891,7 +919,7 @@
 	lwz	r21,GPR21(r21)
 	SYNC
 	RFI
-	
+
 /*
  * FP unavailable trap from kernel - print a message, but let
  * the task use FP in the kernel until it returns to user mode.
@@ -1036,7 +1064,7 @@
 #endif /* CONFIG_SMP */
 	blr
 #endif /* CONFIG_ALTIVEC */
-	
+
 /*
  * giveup_fpu(tsk)
  * Disable FP for the task given as the argument,
@@ -1188,62 +1216,6 @@
 	sync				/* additional sync needed on g4 */
 	isync				/* No speculative loading until now */
 	blr
-	
-apus_interrupt_entry:
-	/* This is horrible, but there's no way around it. Enable the
-	 * data cache so the IRQ hardware register can be accessed
-	 * without cache intervention. Then disable interrupts and get
-	 * the current emulated m68k IPL value. 
-	 */
-	
-	mfmsr	20
-	xori	r20,r20,MSR_DR
-	SYNC
-	mtmsr	r20
-	isync
-
-	lis	r4,APUS_IPL_EMU@h
-
-	li	r20,(IPLEMU_SETRESET|IPLEMU_DISABLEINT)
-	stb	r20,APUS_IPL_EMU@l(r4)
-	eieio
-
-	lbz	r3,APUS_IPL_EMU@l(r4)
-
-	li	r2,IPLEMU_IPLMASK
-	rlwinm. r20,r3,32-3,29,31
-	bne	2f
-	mr	r20,r2		/* lvl7! Need to reset state machine. */
-	b	3f
-2:	cmp	0,r20,r2
-	beq	1f
-3:	eieio
-	stb     r2,APUS_IPL_EMU@l(r4)
-	ori	r20,r20,IPLEMU_SETRESET
-	eieio
-	stb     r20,APUS_IPL_EMU@l(r4)
-1:	eieio
-	li	r20,IPLEMU_DISABLEINT
-	stb	r20,APUS_IPL_EMU@l(r4)
-
-	/* At this point we could do some magic to avoid the overhead
-	 * of calling the C interrupt handler in case of a spurious
-	 * interrupt. Could not get a simple hack to work though.
-	 */
-	
-	mfmsr	r20
-	xori	r20,r20,MSR_DR
-	SYNC
-	mtmsr	r20
-	isync
-
-	stw	r3,(_CCR+4)(r21);
-
-	addi	r3,r1,STACK_FRAME_OVERHEAD;
-	li	r20,MSR_KERNEL;
-	bl	transfer_to_handler;
-	.long	do_IRQ;
-	.long	ret_from_except
 
 /***********************************************************************
  *  Please note that on APUS the exception handlers are located at the
@@ -1266,7 +1238,6 @@
         bl      prom_init
         b       __secondary_start
 #endif /* CONFIG_GEMINI */
-	
 	.globl	__secondary_start_psurge
 __secondary_start_psurge:
 	li	r24,1			/* cpu # */
@@ -1302,7 +1273,11 @@
 	mr	r4,r24
 	bl	identify_cpu
 	bl	call_setup_cpu		/* Call setup_cpu for this CPU */
-
+#ifdef CONFIG_6xx
+	lis	r3,-KERNELBASE@h
+	bl	init_idle_6xx
+#endif /* CONFIG_6xx */
+	
 	/* get current */
 	lis	r2,current_set@h
 	ori	r2,r2,current_set@l
@@ -1357,6 +1332,20 @@
 	bl	setup_750_7400_hid0
 	mtlr	r4
 	blr
+_GLOBAL(__setup_cpu_750cx)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_750_7400_hid0
+	bl	setup_750cx
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_750fx)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_750_7400_hid0
+	bl	setup_750fx
+	mtlr	r4
+	blr
 _GLOBAL(__setup_cpu_7400)
 	mflr	r4
 	bl	setup_common_caches
@@ -1374,19 +1363,13 @@
 _GLOBAL(__setup_cpu_7450)
 	mflr	r4
 	bl	setup_common_caches
-	bl	setup_7450_hid0
-	mtlr	r4
-	blr
-_GLOBAL(__setup_cpu_7450_23)
-	mflr	r4
-	bl	setup_common_caches
-	bl	setup_7450_23_hid0
+	bl	setup_745x_specifics
 	mtlr	r4
 	blr
 _GLOBAL(__setup_cpu_7455)
 	mflr	r4
 	bl	setup_common_caches
-	bl	setup_7455_hid0
+	bl	setup_745x_specifics
 	mtlr	r4
 	blr
 _GLOBAL(__setup_cpu_power3)
@@ -1400,7 +1383,11 @@
 setup_common_caches:
 	mfspr	r11,HID0
 	andi.	r0,r11,HID0_DCE
+#ifdef CONFIG_DCACHE_DISABLE
+	ori	r11,r11,HID0_ICE
+#else
 	ori	r11,r11,HID0_ICE|HID0_DCE
+#endif
 	ori	r8,r11,HID0_ICFI
 	bne	1f			/* don't invalidate the D-cache */
 	ori	r8,r8,HID0_DCI		/* unless it wasn't enabled */
@@ -1447,7 +1434,19 @@
 	isync
 	blr
 
-/* 7450
+/* 750cx specific
+ * Looks like we have to disable NAP feature for some PLL settings...
+ * (waiting for confirmation)
+ */
+setup_750cx:
+	blr
+
+/* 750fx specific
+ */
+setup_750fx:
+	blr
+
+/* MPC 745x
  * Enable Store Gathering (SGE), Branch Folding (FOLD)
  * Branch History Table (BHTE), Branch Target ICache (BTIC)
  * Dynamic Power Management (DPM), Speculative (SPD)
@@ -1455,8 +1454,9 @@
  * Timebase has to be running or we wouldn't have made it here,
  * just ensure we don't disable it.
  * Clear Instruction cache throttling (ICTC)
+ * Enable L2 HW prefetch
  */
-setup_7450_hid0:
+setup_745x_specifics:
 	/* We check for the presence of an L3 cache setup by
 	 * the firmware. If any, we disable NAP capability as
 	 * it's known to be bogus on rev 2.1 and earlier
@@ -1464,21 +1464,22 @@
 	mfspr	r11,SPRN_L3CR
 	andis.	r11,r11,L3CR_L3E@h
 	beq	1f
-	li	r7,CPU_FTR_CAN_NAP
 	lwz	r6,CPU_SPEC_FEATURES(r5)
+	andi.	r0,r6,CPU_FTR_L3_DISABLE_NAP
+	beq	1f
+	li	r7,CPU_FTR_CAN_NAP
 	andc	r6,r6,r7
 	stw	r6,CPU_SPEC_FEATURES(r5)
 1:	
-setup_7450_23_hid0:
 	mfspr	r11,HID0
 
 	/* All of the bits we have to set.....
-	*/
+	 */
 	ori	r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_BTIC | HID0_LRSTK
 	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
 
 	/* All of the bits we have to clear....
-	*/
+	 */
 	li	r3,HID0_SPD | HID0_NOPDST | HID0_NOPTI
 	andc	r11,r11,r3		/* clear SPD: enable speculative */
  	li	r3,0
@@ -1488,34 +1489,13 @@
 	mtspr	HID0,r11
 	sync
 	isync
-	blr
-
-/* 7450
- * Enable Store Gathering (SGE), Branch Folding (FOLD)
- * Branch History Table (BHTE), Branch Target ICache (BTIC)
- * Dynamic Power Management (DPM), Speculative (SPD)
- * Ensure our data cache instructions really operate.
- * Timebase has to be running or we wouldn't have made it here,
- * just ensure we don't disable it.
- * Clear Instruction cache throttling (ICTC)
- */
-setup_7455_hid0:
-	mfspr	r11,HID0
-
-	/* All of the bits we have to set.....
-	*/
-	ori	r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_BTIC | HID0_LRSTK
-	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
 
-	/* All of the bits we have to clear....
-	*/
-	li	r3,HID0_SPD | HID0_NOPDST | HID0_NOPTI
-	andc	r11,r11,r3		/* clear SPD: enable speculative */
- 	li	r3,0
-
- 	mtspr	ICTC,r3			/* Instruction Cache Throttling off */
-	isync
-	mtspr	HID0,r11
+	/* Enable L2 HW prefetch
+	 */
+	mfspr	r3,SPRN_MSSCR0
+	ori	r3,r3,3
+	sync
+	mtspr	SPRN_MSSCR0,r3
 	sync
 	isync
 	blr
@@ -1563,11 +1543,6 @@
  * This is where the main kernel code starts.
  */
 start_here:
-	/* Call setup_cpu for CPU 0 */
-	li	r3,0		/* data offset */
-	li	r24,0		/* cpu# */
-	bl	call_setup_cpu
-
 	/* ptr to current */
 	lis	r2,init_task_union@h
 	ori	r2,r2,init_task_union@l
@@ -1626,12 +1601,27 @@
 /* Load up the kernel context */
 2:
 	sync			/* Force all PTE updates to finish */
-	ISYNC_601
+	isync
 	tlbia			/* Clear all TLB entries */
 	sync			/* wait for tlbia/tlbie to finish */
 	TLBSYNC			/* ... on all CPUs */
 
 	bl	load_up_mmu
+
+#ifdef CONFIG_BDI_SWITCH
+	/* Add helper information for the Abatron bdiGDB debugger.
+	 * We do this here because we know the mmu is disabled, and
+	 * will be enabled for real in just a few instructions.
+	 */
+	lis	r5, abatron_pteptrs@h
+	ori	r5, r5, abatron_pteptrs@l
+	stw	r5, 0xf0(r0)	/* This much match your Abatron config */
+	lis	r6, swapper_pg_dir@h
+	ori	r6, r6, swapper_pg_dir@l
+	tophys(r5, r5)
+	stw	r6, 0(r5)
+#endif
+
 /* Now turn on the MMU for real! */
 	li	r4,MSR_KERNEL
 	FIX_SRR1(r4,r5)
@@ -1651,12 +1641,22 @@
 	addis	r3,r3,0x6000	/* Set Ks, Ku bits */
 	li	r0,NUM_USER_SEGMENTS
 	mtctr	r0
+
+#ifdef CONFIG_BDI_SWITCH
+	/* Context switch the PTE pointer for the Abatron BDI2000.
+	 * The PGDIR is passed as second argument.
+	 */
+	lis	r5, KERNELBASE@h
+	lwz	r5, 0xf0(r5)
+	stw	r4, 0x4(r5)
+#endif
+
 	li	r4,0
 BEGIN_FTR_SECTION
 	DSSALL
 	sync
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-3:
+3:	isync
 #ifdef CONFIG_PPC64BRIDGE
 	slbie	r4
 #endif /* CONFIG_PPC64BRIDGE */
@@ -1684,16 +1684,16 @@
 	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
 	cmpwi	r9, 1
 	beq	1f
-	
+
 	mtspr	DBAT0U,r20
-	mtspr	DBAT0L,r20	
+	mtspr	DBAT0L,r20
 	mtspr	DBAT1U,r20
 	mtspr	DBAT1L,r20
 	mtspr	DBAT2U,r20
-	mtspr	DBAT2L,r20	
+	mtspr	DBAT2L,r20
 	mtspr	DBAT3U,r20
 	mtspr	DBAT3L,r20
-1:	
+1:
 	mtspr	IBAT0U,r20
 	mtspr	IBAT0L,r20
 	mtspr	IBAT1U,r20
@@ -1762,7 +1762,7 @@
 #else
 	ori	r11,r11,BL_256M<<2|0x2	/* set up BAT registers for 604 */
 #endif /* CONFIG_APUS */
-	
+
 #ifdef CONFIG_PPC64BRIDGE
 	/* clear out the high 32 bits in the BAT */
 	clrldi	r11,r11,32
@@ -1851,12 +1851,12 @@
 
 	.globl	swapper_pg_dir
 swapper_pg_dir:
-	.space	4096	
+	.space	4096
 
 /*
  * This space gets a copy of optional info passed to us by the bootstrap
  * Used to pass parameters into the kernel like root=/dev/sda1, etc.
- */	
+ */
 	.globl	cmd_line
 cmd_line:
 	.space	512
@@ -1869,3 +1869,11 @@
 	.long 0, 0, 0, 0, 0, 0, 0, 0
 	.long 0, 0, 0, 0, 0, 0, 0, 0
 	.long 0, 0, 0, 0, 0, 0, 0, 0
+
+#ifdef CONFIG_BDI_SWITCH
+/* Room for two PTE pointers, usually the kernel and current user pointers
+ * to their respective root page table.
+ */
+abatron_pteptrs:
+	.space	8
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/head_4xx.S linux-2.4.20/arch/ppc/kernel/head_4xx.S
--- linux-2.4.19/arch/ppc/kernel/head_4xx.S	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/head_4xx.S	2002-10-29 11:18:40.000000000 +0000
@@ -34,7 +34,8 @@
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
 
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
+#include "ppc_defs.h"
 
 
 /* Preprocessor Defines */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/head_8xx.S linux-2.4.20/arch/ppc/kernel/head_8xx.S
--- linux-2.4.19/arch/ppc/kernel/head_8xx.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/head_8xx.S	2002-10-29 11:18:40.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.head_8xx.S 1.25 01/08/02 16:41:27 trini
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  arch/ppc/kernel/except_8xx.S
@@ -21,10 +21,9 @@
  *  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.
- *	
+ *
  */
 
-#include "ppc_asm.h"
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <linux/config.h>
@@ -32,6 +31,8 @@
 #include <asm/cache.h>
 #include <asm/pgtable.h>
 #include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include "ppc_defs.h"
 
 	.text
 	.globl	_stext
@@ -78,7 +79,7 @@
  * and the CCR at memory location 0.....Someday I'll fix this.....
  *	-- Dan
  */
-	
+
 	.globl	__start
 __start:
 	mr	r31,r3			/* save parameters */
@@ -152,22 +153,22 @@
 /*
  * Exception vectors.
  */
+
+#define FINISH_EXCEPTION(func)			\
+	bl	transfer_to_handler;		\
+	.long	func;				\
+	.long	ret_from_except
+
 #define STD_EXCEPTION(n, label, hdlr)		\
 	. = n;					\
 label:						\
 	EXCEPTION_PROLOG;			\
 	addi	r3,r1,STACK_FRAME_OVERHEAD;	\
 	li	r20,MSR_KERNEL;			\
-	bl	transfer_to_handler; 		\
-	.long	hdlr;				\
-	.long	ret_from_except
+	FINISH_EXCEPTION(hdlr)
 
 /* System reset */
-#ifdef CONFIG_SMP /* MVME/MTX start the secondary here */
-	STD_EXCEPTION(0x100, Reset, __secondary_start_psurge)
-#else
 	STD_EXCEPTION(0x100, Reset, UnknownException)
-#endif	
 
 /* Machine check */
 	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
@@ -187,9 +188,7 @@
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	li	r20,MSR_KERNEL
 	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
-	bl	transfer_to_handler
-	.long	do_page_fault
-	.long	ret_from_except
+	FINISH_EXCEPTION(do_page_fault)
 
 /* Instruction access exception.
  * This is "never generated" by the MPC8xx.  We jump to it for other
@@ -203,9 +202,7 @@
 	mr	r5,r23
 	li	r20,MSR_KERNEL
 	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
-	bl	transfer_to_handler
-	.long	do_page_fault
-	.long	ret_from_except
+	FINISH_EXCEPTION(do_page_fault)
 
 /* External interrupt */
 	. = 0x500;
@@ -215,11 +212,10 @@
 	li	r20,MSR_KERNEL
 	li	r4,0
 	bl	transfer_to_handler
-	.globl do_IRQ_intercept
+	.globl	do_IRQ_intercept
 do_IRQ_intercept:
 	.long	do_IRQ;
 	.long	ret_from_intercept
-	
 
 /* Alignment exception */
 	. = 0x600
@@ -232,9 +228,7 @@
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	li	r20,MSR_KERNEL
 	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
-	bl	transfer_to_handler
-	.long	AlignmentException
-	.long	ret_from_except
+	FINISH_EXCEPTION(AlignmentException)
 
 /* Program check exception */
 	. = 0x700
@@ -243,9 +237,7 @@
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	li	r20,MSR_KERNEL
 	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
-	bl	transfer_to_handler
-	.long	ProgramCheckException
-	.long	ret_from_except
+	FINISH_EXCEPTION(ProgramCheckException)
 
 /* No FPU on MPC8xx.  This exception is not supposed to happen.
 */
@@ -257,7 +249,7 @@
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	li	r20,MSR_KERNEL
 	bl	transfer_to_handler
-	.globl timer_interrupt_intercept
+	.globl	timer_interrupt_intercept
 timer_interrupt_intercept:
 	.long	timer_interrupt
 	.long	ret_from_intercept
@@ -272,9 +264,7 @@
 	stw	r3,ORIG_GPR3(r21)
 	li	r20,MSR_KERNEL
 	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
-	bl	transfer_to_handler
-	.long	DoSyscall
-	.long	ret_from_except
+	FINISH_EXCEPTION(DoSyscall)
 
 /* Single step - not used on 601 */
 	STD_EXCEPTION(0xd00, SingleStep, SingleStepException)
@@ -776,14 +766,18 @@
 	sync			/* wait for tlbia/tlbie to finish */
 	TLBSYNC			/* ... on all CPUs */
 
-	/* set up the PTE pointers for the Abatron bdiGDB.
-	*/
+#ifdef CONFIG_BDI_SWITCH
+	/* Add helper information for the Abatron bdiGDB debugger.
+	 * We do this here because we know the mmu is disabled, and
+	 * will be enabled for real in just a few instructions.
+	 */
 	tovirt(r6,r6)
 	lis	r5, abatron_pteptrs@h
 	ori	r5, r5, abatron_pteptrs@l
 	stw	r5, 0xf0(r0)	/* Must match your Abatron config file */
 	tophys(r5,r5)
 	stw	r6, 0(r5)
+#endif
 
 /* Now turn on the MMU for real! */
 	li	r4,MSR_KERNEL
@@ -922,7 +916,7 @@
 	SYNC
 	blr
 #endif
-	
+
 /*
  * We put a few things here that have to be page-aligned.
  * This stuff goes at the beginning of the data segment,
@@ -937,25 +931,26 @@
 
 	.globl	swapper_pg_dir
 swapper_pg_dir:
-	.space	4096	
+	.space	4096
 
 /*
  * This space gets a copy of optional info passed to us by the bootstrap
  * Used to pass parameters into the kernel like root=/dev/sda1, etc.
- */	
+ */
 	.globl	cmd_line
 cmd_line:
 	.space	512
 
+#ifdef CONFIG_BDI_SWITCH
 /* Room for two PTE table poiners, usually the kernel and current user
  * pointer to their respective root page table (pgdir).
  */
 abatron_pteptrs:
 	.space	8
+#endif
 
 #ifdef CONFIG_8xx_CPU6
 	.globl	cpu6_errata_word
 cpu6_errata_word:
 	.space	16
 #endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/i8259.c linux-2.4.20/arch/ppc/kernel/i8259.c
--- linux-2.4.19/arch/ppc/kernel/i8259.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/i8259.c	2002-10-29 11:18:40.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.i8259.c 1.11 12/19/01 09:45:54 trini
+ * BK Id: %F% %I% %G% %U% %#%
  */
 
 #include <linux/stddef.h>
@@ -9,9 +9,9 @@
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <asm/io.h>
-#include "i8259.h"
+#include <asm/i8259.h>
 
-static volatile char *pci_intack; /* RO, gives us the irq vector */
+static volatile unsigned char *pci_intack; /* RO, gives us the irq vector */
 
 unsigned char cached_8259[2] = { 0xff, 0xff };
 #define cached_A1 (cached_8259[0])
@@ -24,13 +24,13 @@
 /* Acknowledge the irq using the PCI host bridge's interrupt acknowledge
  * feature. (Polling is somehow broken on some IBM and Motorola PReP boxes.)
  */
-int i8259_irq(void)
+int i8259_irq(struct pt_regs *regs)
 {
 	int irq;
 
 	spin_lock/*_irqsave*/(&i8259_lock/*, flags*/);
 
-	irq = *pci_intack & 0xff;
+	irq = *pci_intack;
 	if (irq==7) {
 		/*
 		 * This may be a spurious interrupt.
@@ -48,7 +48,7 @@
 }
 
 /* Poke the 8259's directly using poll commands. */
-int i8259_poll(void)
+int i8259_poll(struct pt_regs *regs)
 {
 	int irq;
 
@@ -171,7 +171,7 @@
 	"8259 edge control", 0x4d0, 0x4d1, IORESOURCE_BUSY
 };
 
-void __init i8259_init(long intack_addr)
+void __init i8259_init(unsigned long intack_addr)
 {
 	unsigned long flags;
 
@@ -201,10 +201,11 @@
 	/* reserve our resources */
 	request_irq( i8259_pic_irq_offset + 2, no_action, SA_INTERRUPT,
 				"82c59 secondary cascade", NULL );
+#if 0 /* Do not request these before the host bridge resource have been setup */
 	request_resource(&ioport_resource, &pic1_iores);
 	request_resource(&ioport_resource, &pic2_iores);
 	request_resource(&ioport_resource, &pic_edgectrl_iores);
-
+#endif
 	if (intack_addr)
 		pci_intack = ioremap(intack_addr, 1);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/i8259.h linux-2.4.20/arch/ppc/kernel/i8259.h
--- linux-2.4.19/arch/ppc/kernel/i8259.h	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/i8259.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,16 +0,0 @@
-/*
- * BK Id: SCCS/s.i8259.h 1.8 12/19/01 09:45:54 trini
- */
-
-#ifndef _PPC_KERNEL_i8259_H
-#define _PPC_KERNEL_i8259_H
-
-#include "local_irq.h"
-
-extern struct hw_interrupt_type i8259_pic;
-
-void i8259_init(long);
-int i8259_irq(void);
-int i8259_poll(void);
-
-#endif /* _PPC_KERNEL_i8259_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/idle.c linux-2.4.20/arch/ppc/kernel/idle.c
--- linux-2.4.19/arch/ppc/kernel/idle.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/idle.c	2002-10-29 11:18:31.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.idle.c 1.20 03/19/02 15:04:39 benh
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Idle daemon for PowerPC.  Idle daemon will handle any action
@@ -33,23 +33,19 @@
 #include <asm/cache.h>
 #include <asm/cputable.h>
 
-void zero_paged(void);
-void power_save(void);
+unsigned long zero_paged_on;
+unsigned long powersave_nap;
+unsigned long powersave_lowspeed;
 
-unsigned long zero_paged_on = 0;
-unsigned long powersave_nap = 0;
-
-unsigned long *zero_cache;    /* head linked list of pre-zero'd pages */
-atomic_t zerototal;      /* # pages zero'd over time */
-atomic_t zeropage_hits;  /* # zero'd pages request that we've done */
-atomic_t zero_sz;	      /* # currently pre-zero'd pages */
-atomic_t zeropage_calls; /* # zero'd pages request that've been made */
+#ifdef CONFIG_6xx
+extern void power_save_6xx(void);
+#endif
 
 int idled(void)
 {
 	int do_power_save = 0;
 
-	/* Check if CPU can powersave */
+	/* Check if CPU can powersave (get rid of that soon!) */
 	if (cur_cpu_spec[smp_processor_id()]->cpu_features &
 		(CPU_FTR_CAN_DOZE | CPU_FTR_CAN_NAP))
 		do_power_save = 1;
@@ -73,8 +69,10 @@
 			}
 		}
 #endif
+#ifdef CONFIG_6xx
 		if (do_power_save && !current->need_resched)
-			power_save();
+			power_save_6xx();
+#endif /* CONFIG_6xx */			
 
 		if (current->need_resched) {
 			schedule();
@@ -93,191 +91,3 @@
 	idled();
 	return 0; 
 }
-
-#if 0
-/*
- * Returns a pre-zero'd page from the list otherwise returns
- * NULL.
- */
-unsigned long get_zero_page_fast(void)
-{
-	unsigned long page = 0;
-
-	atomic_inc(&zero_cache_calls);
-	if ( zero_quicklist )
-	{
-		/* atomically remove this page from the list */
-		register unsigned long tmp;
-		asm (	"101:lwarx  %1,0,%3\n"  /* reserve zero_cache */
-			"    lwz    %0,0(%1)\n" /* get next -- new zero_cache */
-			"    stwcx. %0,0,%3\n"  /* update zero_cache */
-			"    bne-   101b\n"     /* if lost reservation try again */
-			: "=&r" (tmp), "=&r" (page), "+m" (zero_cache)
-			: "r" (&zero_quicklist)
-			: "cc" );
-#ifdef CONFIG_SMP
-		/* if another cpu beat us above this can happen -- Cort */
-		if ( page == 0 ) 
-			return 0;
-#endif /* CONFIG_SMP */		
-		/* we can update zerocount after the fact since it is not
-		 * used for anything but control of a loop which doesn't
-		 * matter since it won't affect anything if it zeros one
-		 * less page -- Cort
-		 */
-		atomic_inc((atomic_t *)&zero_cache_hits);
-		atomic_dec((atomic_t *)&zero_cache_sz);
-		
-		/* zero out the pointer to next in the page */
-		*(unsigned long *)page = 0;
-		return page;
-	}
-	return 0;
-}
-
-/*
- * Experimental stuff to zero out pages in the idle task
- * to speed up get_free_pages(). Zero's out pages until
- * we've reached the limit of zero'd pages.  We handle
- * reschedule()'s in here so when we return we know we've
- * zero'd all we need to for now.
- */
-int zero_cache_water[2] = { 25, 96 }; /* high and low water marks for zero cache */
-void zero_paged(void)
-{
-	unsigned long pageptr = 0;	/* current page being zero'd */
-	unsigned long bytecount = 0;  
-        register unsigned long tmp;
-	pte_t *pte;
-
-	if ( atomic_read(&zero_cache_sz) >= zero_cache_water[0] )
-		return;
-	while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && (!current->need_resched) )
-	{
-		/*
-		 * Mark a page as reserved so we can mess with it
-		 * If we're interrupted we keep this page and our place in it
-		 * since we validly hold it and it's reserved for us.
-		 */
-		pageptr = __get_free_pages(GFP_ATOMIC, 0);
-		if ( !pageptr )
-			return;
-		
-		if ( current->need_resched )
-			schedule();
-		
-		/*
-		 * Make the page no cache so we don't blow our cache with 0's
-		 */
-		pte = find_pte(&init_mm, pageptr);
-		if ( !pte )
-		{
-			printk("pte NULL in zero_paged()\n");
-			return;
-		}
-		
-		pte_uncache(*pte);
-		flush_tlb_page(find_vma(&init_mm,pageptr),pageptr);
-		/*
-		 * Important here to not take time away from real processes.
-		 */
-		for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
-		{
-			if ( current->need_resched )
-				schedule();
-			*(unsigned long *)(bytecount + pageptr) = 0;
-		}
-		
-		/*
-		 * If we finished zero-ing out a page add this page to
-		 * the zero_cache atomically -- we can't use
-		 * down/up since we can't sleep in idle.
-		 * Disabling interrupts is also a bad idea since we would
-		 * steal time away from real processes.
-		 * We can also have several zero_paged's running
-		 * on different processors so we can't interfere with them.
-		 * So we update the list atomically without locking it.
-		 * -- Cort
-		 */
-		
-		/* turn cache on for this page */
-		pte_cache(*pte);
-		flush_tlb_page(find_vma(&init_mm,pageptr),pageptr);
-		/* atomically add this page to the list */
-		asm (	"101:lwarx  %0,0,%2\n"  /* reserve zero_cache */
-			"    stw    %0,0(%3)\n" /* update *pageptr */
-#ifdef CONFIG_SMP
-			"    sync\n"            /* let store settle */
-#endif			
-			"    stwcx. %3,0,%2\n"  /* update zero_cache in mem */
-			"    bne-   101b\n"     /* if lost reservation try again */
-			: "=&r" (tmp), "+m" (zero_quicklist)
-			: "r" (&zero_quicklist), "r" (pageptr)
-			: "cc" );
-		/*
-		 * This variable is used in the above loop and nowhere
-		 * else so the worst that could happen is we would
-		 * zero out one more or one less page than we want
-		 * per processor on the machine.  This is because
-		 * we could add our page to the list but not have
-		 * zerocount updated yet when another processor
-		 * reads it.  -- Cort
-		 */
-		atomic_inc((atomic_t *)&zero_cache_sz);
-		atomic_inc((atomic_t *)&zero_cache_total);
-	}
-}
-#endif /* 0 */
-
-#define DSSALL		.long	(0x1f<<26)+(0x10<<21)+(0x336<<1)
-
-void power_save(void)
-{
-	unsigned long hid0;
-	int nap = powersave_nap;
-	
-	/* 7450 has no DOZE mode mode, we return if powersave_nap
-	 * isn't enabled
-	 */
-	if (!(nap || (cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_CAN_DOZE)))
-		return;
-	/*
-	 * Disable interrupts to prevent a lost wakeup
-	 * when going to sleep.  This is necessary even with
-	 * RTLinux since we are not guaranteed an interrupt
-	 * didn't come in and is waiting for a __sti() before
-	 * emulating one.  This way, we really do hard disable.
-	 * 
-	 * We assume that we're sti-ed when we come in here.  We
-	 * are in the idle loop so if we're cli-ed then it's a bug
-	 * anyway.
-	 *  -- Cort
-	 */
-	_nmask_and_or_msr(MSR_EE, 0);
-	if (!current->need_resched)
-	{
-		__asm__ __volatile__("mfspr %0,1008" : "=r" (hid0) :);
-		hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
-		hid0 |= (powersave_nap? HID0_NAP: HID0_DOZE) | HID0_DPM;
-		__asm__ __volatile__("mtspr 1008,%0" : : "r" (hid0));
-		/* Flush pending data streams, consider this instruction
-		 * exist on all altivec capable CPUs
-		 */
-		__asm__ __volatile__(
-			"98:	" stringify(DSSALL) "\n"
-			"	sync\n"
-			"99:\n"
-			".section __ftr_fixup,\"a\"\n"
-			"	.long %0\n"
-			"	.long %1\n"
-			"	.long 98b\n"
-			"	.long 99b\n"
-			".previous" : : "i" (CPU_FTR_ALTIVEC), "i" (CPU_FTR_ALTIVEC));
-		
-		/* set the POW bit in the MSR, and enable interrupts
-		 * so we wake up sometime! */
-		_nmask_and_or_msr(0, MSR_POW | MSR_EE);
-	}
-	_nmask_and_or_msr(0, MSR_EE);
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/idle_6xx.S linux-2.4.20/arch/ppc/kernel/idle_6xx.S
--- linux-2.4.19/arch/ppc/kernel/idle_6xx.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/idle_6xx.S	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,224 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  This file contains the power_save function for 6xx & 7xxx CPUs
+ *  rewritten in assembler
+ *
+ *  Warning ! This code assumes that if your machine has a 750fx
+ *  it will have PLL 1 set to low speed mode (used during NAP/DOZE).
+ *  if this is not the case some additional changes will have to
+ *  be done to check a runtime var (a bit like powersave-nap)
+ *
+ *  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.
+ */
+
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include "ppc_defs.h"
+
+#undef DEBUG
+
+	.text
+
+/*
+ * Init idle, called at early CPU setup time from head.S for each CPU
+ * Make sure no rest of NAP mode remains in HID0, save default
+ * values for some CPU specific registers. Called with r24
+ * containing CPU number and r3 reloc offset
+ */
+ 	.globl	init_idle_6xx
+init_idle_6xx:
+BEGIN_FTR_SECTION
+	mfspr	r4,SPRN_HID0
+	rlwinm	r4,r4,0,10,8	/* Clear NAP */
+	mtspr	SPRN_HID0, r4
+	b	1f
+END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
+	blr
+1:
+	slwi	r5,r24,2
+	add	r5,r5,r3
+BEGIN_FTR_SECTION
+	mfspr	r4,SPRN_MSSCR0
+	addis	r6,r5, nap_save_msscr0@ha
+	stw	r4,nap_save_msscr0@l(r6)
+END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR)
+BEGIN_FTR_SECTION
+	mfspr	r4,SPRN_HID1
+	addis	r6,r5,nap_save_hid1@ha
+	stw	r4,nap_save_hid1@l(r6)
+END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX)
+	blr
+
+/*
+ * Here is the power_save_6xx function. This could eventually be
+ * split into several functions & changing the function pointer
+ * depending on the various features.
+ */
+	.globl	power_save_6xx
+power_save_6xx:
+	/* Check if we can nap or doze, put HID0 mask in r3
+	 */
+	lis	r3, 0
+BEGIN_FTR_SECTION
+	lis	r3,HID0_DOZE@h
+END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE)
+BEGIN_FTR_SECTION
+	/* We must dynamically check for the NAP feature as it
+	 * can be cleared by CPU init after the fixups are done
+	 */
+	lis	r4,cur_cpu_spec@ha
+	lwz	r4,cur_cpu_spec@l(r4)
+	lwz	r4,CPU_SPEC_FEATURES(r4)
+	andi.	r0,r4,CPU_FTR_CAN_NAP
+	beq	1f
+	/* Now check if user or arch enabled NAP mode */
+	lis	r4,powersave_nap@ha
+	lwz	r4,powersave_nap@l(r4)
+	cmpi	0,r4,0
+	beq	1f
+	lis	r3,HID0_NAP@h
+1:	
+END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
+	cmpi	0,r3,0
+	beqlr
+
+	/* Clear MSR:EE */
+	mfmsr	r7
+	rlwinm	r0,r7,0,17,15
+	mtmsr	r0
+
+	/* Check current->need_resched */
+	lwz	r4,NEED_RESCHED(r2)
+	cmpi	0,r4,0
+	beq+	1f
+	mtmsr	r7	/* out of line this ? */
+	blr
+1:	
+	/* Some pre-nap cleanups needed on some CPUs */
+	andis.	r0,r3,HID0_NAP@h
+	beq	2f
+BEGIN_FTR_SECTION
+	/* Disable L2 prefetch on some 745x */
+	mfspr	r4,SPRN_MSSCR0
+	rlwinm	r4,r4,0,0,29
+	sync
+	mtspr	SPRN_MSSCR0,r4
+	sync
+	isync
+END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR)
+#ifdef DEBUG
+	lis	r6,nap_enter_count@ha
+	lwz	r4,nap_enter_count@l(r6)
+	addi	r4,r4,1
+	stw	r4,nap_enter_count@l(r6)
+#endif	
+2:
+BEGIN_FTR_SECTION
+	/* Go to low speed mode on some 750FX */
+	lis	r4,powersave_lowspeed@ha
+	lwz	r4,powersave_lowspeed@l(r4)
+	cmpi	0,r4,0
+	beq	1f
+	mfspr	r4,SPRN_HID1
+	oris	r4,r4,0x0001
+	mtspr	SPRN_HID1,r4
+1:	
+END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX)
+
+	/* Go to NAP or DOZE now */	
+	mfspr	r4,SPRN_HID0
+	lis	r5,(HID0_NAP|HID0_SLEEP)@h
+BEGIN_FTR_SECTION
+	oris	r5,r5,HID0_DOZE@h
+END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE)
+	andc	r4,r4,r5
+	or	r4,r4,r3
+	oris	r4,r4,HID0_DPM@h	/* that should be done once for all ... */
+	mtspr	SPRN_HID0,r4
+BEGIN_FTR_SECTION
+	DSSALL
+	sync
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+	ori	r7,r7,MSR_EE /* Could be ommited (already set) */
+	oris	r7,r7,MSR_POW@h
+	sync
+	isync
+	mtmsr	r7
+	.globl	power_save_6xx_ret
+power_save_6xx_ret:
+	isync
+	sync
+	blr
+	
+/*
+ * Return from NAP/DOZE mode, restore some CPU specific registers,
+ * we are called with DR/IR still off and r2 containing physical
+ * address of current.
+ */
+ 	.globl power_save_6xx_restore
+power_save_6xx_restore:
+	mfspr	r22,SPRN_HID0
+	rlwinm.	r22,r22,0,10,8	/* Clear NAP & copy NAP bit !state to cr1 EQ */
+	cror	4*cr1+eq,4*cr0+eq,4*cr0+eq
+BEGIN_FTR_SECTION
+	rlwinm	r22,r22,0,9,7	/* Clear DOZE */
+END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE)
+	mtspr	SPRN_HID0, r22
+
+#ifdef DEBUG
+	beq	cr1,1f
+	lis	r22,(nap_return_count-KERNELBASE)@ha
+	lwz	r24,nap_return_count@l(r22)
+	addi	r24,r24,1
+	stw	r24,nap_return_count@l(r22)
+1:
+#endif
+	
+	lwz	r24,PROCESSOR(r2)
+	slwi	r24,r24,2
+	/* Todo make sure all these are in the same page
+	 * and load r22 (@ha part + CPU offset) only once
+	 */
+BEGIN_FTR_SECTION
+	beq	cr1,1f
+	addis	r22,r24,(nap_save_msscr0-KERNELBASE)@ha
+	lwz	r22,nap_save_msscr0@l(r22)
+	mtspr	SPRN_MSSCR0, r22
+	sync
+	isync
+1:
+END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR)
+BEGIN_FTR_SECTION
+	addis	r22,r24,(nap_save_hid1-KERNELBASE)@ha
+	lwz	r22,nap_save_hid1@l(r22)
+	mtspr	SPRN_HID1, r22
+END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX)
+	b	transfer_to_handler_cont
+
+	.data
+
+	.globl nap_save_msscr0
+nap_save_msscr0:
+	.space	4*NR_CPUS
+
+	.globl nap_save_hid1
+nap_save_hid1:
+	.space	4*NR_CPUS
+
+#ifdef DEBUG
+	.globl nap_enter_count
+nap_enter_count:
+	.space	4
+	.globl nap_return_count
+nap_return_count:
+	.space	4
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/indirect_pci.c linux-2.4.20/arch/ppc/kernel/indirect_pci.c
--- linux-2.4.19/arch/ppc/kernel/indirect_pci.c	2001-09-08 19:38:41.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/indirect_pci.c	2002-10-29 11:18:33.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.indirect_pci.c 1.10 09/08/01 15:47:42 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Support for indirect PCI bridges.
@@ -24,8 +24,6 @@
 #include <asm/pci-bridge.h>
 #include <asm/machdep.h>
 
-#include "pci.h"
-
 #define cfg_read(val, addr, type, op)	*val = op((type)(addr))
 #define cfg_write(val, addr, type, op)	op((type *)(addr), (val))
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/irq.c linux-2.4.20/arch/ppc/kernel/irq.c
--- linux-2.4.19/arch/ppc/kernel/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/irq.c	2002-10-29 11:18:35.000000000 +0000
@@ -50,20 +50,15 @@
 
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
-#include <asm/hydra.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
-#include <asm/gg2.h>
 #include <asm/cache.h>
 #include <asm/prom.h>
-#include <asm/amigaints.h>
-#include <asm/amigahw.h>
-#include <asm/amigappc.h>
 #include <asm/ptrace.h>
 
-#include "local_irq.h"
+#define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
 
 extern atomic_t ipi_recv;
 extern atomic_t ipi_sent;
@@ -189,9 +184,6 @@
  * now, this is what I need. -- Dan
  */
 #define request_irq	request_8xxirq
-#elif defined(CONFIG_APUS)
-#define request_irq	request_sysirq
-#define free_irq	sys_free_irq
 #endif
 
 void free_irq(unsigned int irq, void* dev_id)
@@ -373,9 +365,6 @@
 
 int get_irq_list(char *buf)
 {
-#ifdef CONFIG_APUS
-	return apus_get_irq_list (buf);
-#else
 	int i, len = 0, j;
 	struct irqaction * action;
 
@@ -423,7 +412,6 @@
 #endif		
 	len += sprintf(buf+len, "BAD: %10u\n", ppc_spurious_interrupts);
 	return len;
-#endif /* CONFIG_APUS */
 }
 
 static inline void
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/l2cr.S linux-2.4.20/arch/ppc/kernel/l2cr.S
--- linux-2.4.19/arch/ppc/kernel/l2cr.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/l2cr.S	2002-10-29 11:18:48.000000000 +0000
@@ -42,7 +42,7 @@
 */
 #include <asm/processor.h>
 #include <asm/cputable.h>
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 
 /* Usage:
 	
@@ -101,6 +101,12 @@
 	blr
 END_FTR_SECTION_IFCLR(CPU_FTR_L2CR)
 
+	/* Stop DST streams */
+BEGIN_FTR_SECTION
+	DSSALL
+	sync
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+
 	/* Turn off interrupts and data relocation. */
 	mfmsr	r7		/* Save MSR in r7 */
 	rlwinm	r4,r7,0,17,15
@@ -136,7 +142,7 @@
 
 	/* TODO: use HW flush assist when available */
 
-	lis	r4,0x0002
+	lis	r4,0x0004
 	mtctr	r4
 	li	r4,0
 1:
@@ -145,7 +151,7 @@
 	bdnz	1b
 	
 	/* Now, flush the first 4MB of memory */
-	lis	r4,0x0002
+	lis	r4,0x0004
 	mtctr	r4
 	li	r4,0
 	sync
@@ -246,6 +252,10 @@
 	blr
 END_FTR_SECTION_IFCLR(CPU_FTR_L3CR)
 
+	/* Stop DST streams */
+	DSSALL
+	sync
+	
 	/* Turn off interrupts and data relocation. */
 	mfmsr	r7		/* Save MSR in r7 */
 	rlwinm	r4,r7,0,17,15
@@ -254,9 +264,6 @@
 	mtmsr	r4
 	isync
 
-	/* Stop DST streams */
-	DSSALL
-	
 	/* Get the current enable bit of the L3CR into r4 */
 	mfspr	r4,SPRN_L3CR
 	
@@ -269,50 +276,26 @@
 	rlwinm.	r4,r4,0,0,0
 	beq	2f
 
-	/* Flush the cache. First, read the first 4MB of memory (physical) to
-	 * put new data in the cache.  (Actually we only need
-	 * the size of the L3 cache plus the size of the L1+L2 cache, but 4MB will
-	 * cover everything just to be safe).
+	/* Flush the cache.
 	 */
 		
 	/* TODO: use HW flush assist */
 
-	lis	r4,0x0002
+	lis	r4,0x0008
 	mtctr	r4
 	li	r4,0
 1:
 	lwzx	r0,r0,r4
-	addi	r4,r4,32		/* Go to start of next cache line */
-	bdnz	1b
-	
-	/* Now, flush the first 4MB of memory */
-	lis	r4,0x0002
-	mtctr	r4
-	li	r4,0
-	sync
-1:
 	dcbf	r0,r4
 	addi	r4,r4,32		/* Go to start of next cache line */
 	bdnz	1b
-
+	
 2:
 	/* Set up the L3CR configuration bits (and switch L3 off) */
 	sync
 	mtspr	SPRN_L3CR,r3
 	sync
 
-	/* Before we perform the global invalidation, we must disable dynamic
-	 * power management via HID0[DPM] to work around a processor bug where
-	 * DPM can possibly interfere with the state machine in the processor
-	 * that invalidates the L3 cache tags. Hrm... This is necessary for L2,
-	 * is it for L3 as well ? --BenH.
-	 */
-	mfspr	r8,HID0			/* Save HID0 in r8 */
-	rlwinm	r4,r8,0,12,10		/* Turn off HID0[DPM] */
-	sync
-	mtspr	HID0,r4			/* Disable DPM */
-	sync
-
 	oris	r3,r3,L3CR_L3RES@h		/* Set reserved bit 5 */
 	mtspr	SPRN_L3CR,r3
 	sync
@@ -321,7 +304,7 @@
 	sync
 
 	/* Wait for stabilize */
-	li	r0,128
+	li	r0,256
 	mtctr	r0
 1:	bdnz	1b
 	
@@ -343,15 +326,10 @@
 	sync
 
 	/* Wait for stabilize */
-	li	r0,128
+	li	r0,256
 	mtctr	r0
 1:	bdnz	1b
 	
-	/* Restore HID0[DPM] to whatever it was before */
-	sync
-	mtspr	1008,r8
-	sync
-
 	/* See if we need to enable the cache */
 	cmplwi	r5,0
 	beq	4f
@@ -361,6 +339,11 @@
 	mtspr	SPRN_L3CR,r3
 	sync
 
+	/* Wait for stabilize */
+	li	r0,256
+	mtctr	r0
+1:	bdnz	1b
+
 	/* Restore MSR (restores EE and DR bits to original state) */
 4:	SYNC
 	mtmsr	r7
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/local_irq.h linux-2.4.20/arch/ppc/kernel/local_irq.h
--- linux-2.4.19/arch/ppc/kernel/local_irq.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/local_irq.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,22 +0,0 @@
-/*
- * BK Id: SCCS/s.local_irq.h 1.7 05/17/01 18:14:21 cort
- */
-
-#ifndef _PPC_KERNEL_LOCAL_IRQ_H
-#define _PPC_KERNEL_LOCAL_IRQ_H
-
-#include <linux/kernel_stat.h>
-#include <linux/interrupt.h>
-#include <linux/cache.h>
-#include <linux/spinlock.h>
-#include <linux/irq.h>
-
-void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
-
-#define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
-
-extern int ppc_spurious_interrupts;
-extern int ppc_second_irq;
-extern struct irqaction *ppc_irq_action[NR_IRQS];
-
-#endif /* _PPC_KERNEL_LOCAL_IRQ_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/m8260_setup.c linux-2.4.20/arch/ppc/kernel/m8260_setup.c
--- linux-2.4.19/arch/ppc/kernel/m8260_setup.c	2001-11-16 18:10:08.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/m8260_setup.c	2002-10-29 11:18:48.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.m8260_setup.c 1.30 11/13/01 21:26:07 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  linux/arch/ppc/kernel/setup.c
@@ -45,8 +45,9 @@
 #include <asm/mpc8260.h>
 #include <asm/immap_8260.h>
 #include <asm/machdep.h>
-
+#include <asm/bootinfo.h>
 #include <asm/time.h>
+
 #include "ppc8260_pic.h"
 
 static int m8260_set_rtc_time(unsigned long time);
@@ -219,6 +220,7 @@
 platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 	      unsigned long r6, unsigned long r7)
 {
+	parse_bootinfo(find_bootinfo());
 
 	if ( r3 )
 		memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/m8xx_setup.c linux-2.4.20/arch/ppc/kernel/m8xx_setup.c
--- linux-2.4.19/arch/ppc/kernel/m8xx_setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/m8xx_setup.c	2002-10-29 11:18:39.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.m8xx_setup.c 1.40 11/13/01 21:26:07 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  *
  *  linux/arch/ppc/kernel/setup.c
  *
@@ -43,8 +43,9 @@
 #include <asm/mpc8xx.h>
 #include <asm/8xx_immap.h>
 #include <asm/machdep.h>
-
+#include <asm/bootinfo.h>
 #include <asm/time.h>
+
 #include "ppc8xx_pic.h"
 
 static int m8xx_set_rtc_time(unsigned long time);
@@ -343,6 +344,8 @@
 platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 		unsigned long r6, unsigned long r7)
 {
+	parse_bootinfo(find_bootinfo());
+
 	if ( r3 )
 		memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
 	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/misc.S linux-2.4.20/arch/ppc/kernel/misc.S
--- linux-2.4.19/arch/ppc/kernel/misc.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/misc.S	2002-10-29 11:18:37.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.misc.S 1.44 06/25/02 17:24:30 benh
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * This file contains miscellaneous low-level functions.
@@ -23,7 +23,9 @@
 #include <asm/page.h>
 #include <asm/cache.h>
 #include <asm/cputable.h>
-#include "ppc_asm.h"
+#include <asm/mmu.h>
+#include <asm/ppc_asm.h>
+#include "ppc_defs.h"
 
 	.text
 
@@ -184,8 +186,10 @@
  * call_setup_cpu - call the setup_cpu function for this cpu
  * r3 = data offset, r24 = cpu number
  *
- * Don't change register layout, the setup function may rely
- * on r5 containing a relocated pointer to the current cpu spec.
+ * Setup function is called with:
+ *   r3 = data offset
+ *   r4 = CPU number
+ *   r5 = ptr to CPU spec (relocated)
  */
 _GLOBAL(call_setup_cpu)
 	addis	r5,r3,cur_cpu_spec@ha
@@ -196,7 +200,7 @@
 	lwz	r6,CPU_SPEC_SETUP(r5)
 	add	r6,r6,r3
 	mtctr	r6
-	mr	r3,r24
+	mr	r4,r24
 	bctr
 
 /* void __save_flags_ptr(unsigned long *flags) */
@@ -1157,6 +1161,30 @@
 	.long sys_mincore
 	.long sys_gettid
 	.long sys_tkill
+	.long sys_setxattr
+	.long sys_lsetxattr	/* 210 */
+	.long sys_fsetxattr
+	.long sys_getxattr
+	.long sys_lgetxattr
+	.long sys_fgetxattr
+	.long sys_listxattr	/* 215 */
+	.long sys_llistxattr
+	.long sys_flistxattr
+	.long sys_removexattr
+	.long sys_lremovexattr
+	.long sys_fremovexattr	/* 220  */
+	.long sys_ni_syscall 	/*	reserved for sys_futex */
+	.long sys_ni_syscall 	/*	reserved for sys_sched_setaffinity */
+	.long sys_ni_syscall 	/*	reserved for sys_sched_getaffinity */
+	.long sys_ni_syscall 	/*	reserved for sys_security */
+	.long sys_ni_syscall 	/* 225	reserved for Tux */
+	.long sys_ni_syscall 	/*	reserved for sys_sendfile64 */
+	.long sys_ni_syscall 	/*	reserved for sys_io_setup */
+	.long sys_ni_syscall 	/*	reserved for sys_io_destroy */
+	.long sys_ni_syscall 	/*	reserved for sys_io_getevents */
+	.long sys_ni_syscall 	/* 230	reserved for sys_io_submit */
+	.long sys_ni_syscall 	/*	reserved for sys_io_cancel */
+
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long sys_ni_syscall
 	.endr
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/oak_setup.c linux-2.4.20/arch/ppc/kernel/oak_setup.c
--- linux-2.4.19/arch/ppc/kernel/oak_setup.c	2001-11-16 18:10:08.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/oak_setup.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,297 +0,0 @@
-/*
- * BK Id: SCCS/s.oak_setup.c 1.12 11/13/01 21:26:07 paulus
- */
-/*
- *
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: oak_setup.c
- *
- *    Description:
- *      Architecture- / platform-specific boot-time initialization code for
- *      the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
- *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
- *      <dan@net4x.com>.
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/threads.h>
-#include <linux/interrupt.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/blk.h>
-#include <linux/seq_file.h>
-
-#include <asm/processor.h>
-#include <asm/board.h>
-#include <asm/machdep.h>
-#include <asm/page.h>
-
-#include "local_irq.h"
-#include "ppc4xx_pic.h"
-#include <asm/time.h>
-#include "oak_setup.h"
-
-
-
-
-
-
-
-/* Function Prototypes */
-
-extern void abort(void);
-
-/* Global Variables */
-
-unsigned char __res[sizeof(bd_t)];
-
-
-/*
- * void __init oak_init()
- *
- * Description:
- *   This routine...
- *
- * Input(s):
- *   r3 - Optional pointer to a board information structure.
- *   r4 - Optional pointer to the physical starting address of the init RAM
- *        disk.
- *   r5 - Optional pointer to the physical ending address of the init RAM
- *        disk.
- *   r6 - Optional pointer to the physical starting address of any kernel
- *        command-line parameters.
- *   r7 - Optional pointer to the physical ending address of any kernel
- *        command-line parameters.
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   N/A
- *
- */
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5, 
-	      unsigned long r6, unsigned long r7)
-{
-	/*
-	 * If we were passed in a board information, copy it into the
-	 * residual data area.
-	 */
-	if (r3) {
-		memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t));
-	}
-
-#if defined(CONFIG_BLK_DEV_INITRD)
-	/*
-	 * If the init RAM disk has been configured in, and there's a valid
-	 * starting address for it, set it up.
-	 */
-	if (r4) {
-		initrd_start = r4 + KERNELBASE;
-		initrd_end = r5 + KERNELBASE;
-	}
-#endif /* CONFIG_BLK_DEV_INITRD */
-
-	/* Copy the kernel command line arguments to a safe place. */
-
-	if (r6) {
- 		*(char *)(r7 + KERNELBASE) = 0;
-		strcpy(cmd_line, (char *)(r6 + KERNELBASE));
-	}
-
-	/* Initialize machine-dependency vectors */
-
-	ppc_md.setup_arch	 	= oak_setup_arch;
-	ppc_md.show_percpuinfo	 	= oak_show_percpuinfo;
-	ppc_md.irq_cannonicalize 	= NULL;
-	ppc_md.init_IRQ		 	= oak_init_IRQ;
-	ppc_md.get_irq		 	= oak_get_irq;
-	ppc_md.init		 	= NULL;
-
-	ppc_md.restart		 	= oak_restart;
-	ppc_md.power_off	 	= oak_power_off;
-	ppc_md.halt		 	= oak_halt;
-
-	ppc_md.time_init	 	= oak_time_init;
-	ppc_md.set_rtc_time	 	= oak_set_rtc_time;
-	ppc_md.get_rtc_time	 	= oak_get_rtc_time;
-	ppc_md.calibrate_decr	 	= oak_calibrate_decr;
-
-	ppc_md.kbd_setkeycode    	= NULL;
-	ppc_md.kbd_getkeycode    	= NULL;
-	ppc_md.kbd_translate     	= NULL;
-	ppc_md.kbd_unexpected_up 	= NULL;
-	ppc_md.kbd_leds          	= NULL;
-	ppc_md.kbd_init_hw       	= NULL;
-	ppc_md.ppc_kbd_sysrq_xlate	= NULL;
-}
-
-/*
- * Document me.
- */
-void __init
-oak_setup_arch(void)
-{
-	/* XXX - Implement me */
-}
-
-/*
- * int oak_show_percpuinfo()
- *
- * Description:
- *   This routine pretty-prints the platform's internal CPU and bus clock
- *   frequencies into the buffer for usage in /proc/cpuinfo.
- *
- * Input(s):
- *  *buffer - Buffer into which CPU and bus clock frequencies are to be
- *            printed.
- *
- * Output(s):
- *  *buffer - Buffer with the CPU and bus clock frequencies.
- *
- * Returns:
- *   The number of bytes copied into 'buffer' if OK, otherwise zero or less
- *   on error.
- */
-int
-oak_show_percpuinfo(struct seq_file *m, int i)
-{
-	bd_t *bp = (bd_t *)__res;
-
-	seq_printf(m, "clock\t\t: %dMHz\n"
-		   "bus clock\t\t: %dMHz\n",
-		   bp->bi_intfreq / 1000000,
-		   bp->bi_busfreq / 1000000);
-
-	return 0;
-}
-
-/*
- * Document me.
- */
-void __init
-oak_init_IRQ(void)
-{
-	int i;
-
-	ppc4xx_pic_init();
-
-	for (i = 0; i < NR_IRQS; i++) {
-		irq_desc[i].handler = ppc4xx_pic;
-	}
-
-	return;
-}
-
-/*
- * Document me.
- */
-int
-oak_get_irq(struct pt_regs *regs)
-{
-	return (ppc4xx_pic_get_irq(regs));
-}
-
-/*
- * Document me.
- */
-void
-oak_restart(char *cmd)
-{
-	abort();
-}
-
-/*
- * Document me.
- */
-void
-oak_power_off(void)
-{
-	oak_restart(NULL);
-}
-
-/*
- * Document me.
- */
-void
-oak_halt(void)
-{
-	oak_restart(NULL);
-}
-
-/*
- * Document me.
- */
-long __init
-oak_time_init(void)
-{
-	/* XXX - Implement me */
-	return 0;
-}
-
-/*
- * Document me.
- */
-int __init
-oak_set_rtc_time(unsigned long time)
-{
-	/* XXX - Implement me */
-
-	return (0);
-}
-
-/*
- * Document me.
- */
-unsigned long __init
-oak_get_rtc_time(void)
-{
-	/* XXX - Implement me */
-
-	return (0);
-}
-
-/*
- * void __init oak_calibrate_decr()
- *
- * Description:
- *   This routine retrieves the internal processor frequency from the board
- *   information structure, sets up the kernel timer decrementer based on
- *   that value, enables the 403 programmable interval timer (PIT) and sets
- *   it up for auto-reload.
- *
- * Input(s):
- *   N/A
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   N/A
- *
- */
-void __init
-oak_calibrate_decr(void)
-{
-	unsigned int freq;
-	bd_t *bip = (bd_t *)__res;
-
-	freq = bip->bi_intfreq;
-
-	decrementer_count = freq / HZ;
-	count_period_num = 1;
-	count_period_den = freq;
-
-	/* Enable the PIT and set auto-reload of its value */
-
-	mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
-
-	/* Clear any pending timer interrupts */
-
-	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/oak_setup.h linux-2.4.20/arch/ppc/kernel/oak_setup.h
--- linux-2.4.19/arch/ppc/kernel/oak_setup.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/oak_setup.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,53 +0,0 @@
-/*
- * BK Id: SCCS/s.oak_setup.h 1.5 05/17/01 18:14:21 cort
- */
-/*
- *
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: oak_setup.h
- *
- *    Description:
- *      Architecture- / platform-specific boot-time initialization code for
- *      the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
- *      code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
- *      <dan@netx4.com>.
- *
- */
-
-#ifndef	__OAK_SETUP_H__
-#define	__OAK_SETUP_H__
-
-#include <asm/ptrace.h>
-#include <asm/board.h>
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern unsigned char	 __res[sizeof(bd_t)];
-
-extern void		 oak_init(unsigned long r3,
-				  unsigned long ird_start,
-				  unsigned long ird_end,
-				  unsigned long cline_start,
-				  unsigned long cline_end);
-extern void		 oak_setup_arch(void);
-extern int		 oak_setup_residual(char *buffer);
-extern void		 oak_init_IRQ(void);
-extern int		 oak_get_irq(struct pt_regs *regs);
-extern void		 oak_restart(char *cmd);
-extern void		 oak_power_off(void);
-extern void		 oak_halt(void);
-extern void		 oak_time_init(void);
-extern int		 oak_set_rtc_time(unsigned long now);
-extern unsigned long	 oak_get_rtc_time(void);
-extern void		 oak_calibrate_decr(void);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __OAK_SETUP_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/open_pic.c linux-2.4.20/arch/ppc/kernel/open_pic.c
--- linux-2.4.19/arch/ppc/kernel/open_pic.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/open_pic.c	2002-10-29 11:18:48.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.open_pic.c 1.33 12/19/01 09:45:54 trini
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
@@ -17,18 +17,16 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/irq.h>
-#include <linux/init.h>
 #include <asm/ptrace.h>
 #include <asm/signal.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/prom.h>
 #include <asm/sections.h>
+#include <asm/open_pic.h>
+#include <asm/i8259.h>
 
-#include "local_irq.h"
-#include "open_pic.h"
 #include "open_pic_defs.h"
-#include "i8259.h"
 
 void* OpenPIC_Addr;
 static volatile struct OpenPIC *OpenPIC = NULL;
@@ -36,18 +34,12 @@
 u_char *OpenPIC_InitSenses __initdata = NULL;
 extern int use_of_interrupt_tree;
 
-void find_ISUs(void);
-
 static u_int NumProcessors;
 static u_int NumSources;
-#ifdef CONFIG_POWER3
-static int NumISUs;
-#endif
 static int open_pic_irq_offset;
+static volatile OpenPIC_Source *ISR[NR_IRQS];
 static volatile unsigned char* chrp_int_ack_special;
 
-OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU];
-
 /* Global Operations */
 static void openpic_disable_8259_pass_through(void);
 static void openpic_set_priority(u_int pri);
@@ -68,7 +60,7 @@
 static void openpic_disable_irq(u_int irq);
 static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
 			    int is_level);
-static void openpic_mapirq(u_int irq, u_int cpumask);
+static void openpic_mapirq(u_int irq, u_int cpumask, u_int keepmask);
 
 /*
  * These functions are not used but the code is kept here
@@ -167,12 +159,6 @@
 #define check_arg_cpu(cpu)	do {} while (0)
 #endif
 
-#ifdef CONFIG_POWER3
-	#define GET_ISU(source)	ISU[(source) >> 4][(source) & 0xf]
-#else
-	#define GET_ISU(source)	ISU[0][(source)]
-#endif
-
 u_int openpic_read(volatile u_int *addr)
 {
 	u_int val;
@@ -261,6 +247,20 @@
 }
 #endif /* CONFIG_SMP */
 
+void __init openpic_set_sources(int first_irq, int num_irqs, void *first_ISR)
+{
+	volatile OpenPIC_Source *src = first_ISR;
+	int i, last_irq;
+
+	last_irq = first_irq + num_irqs;
+	if (last_irq > NumSources)
+		NumSources = last_irq;
+	if (src == 0)
+		src = &((struct OpenPIC *)OpenPIC_Addr)->Source[first_irq];
+	for (i = first_irq; i < last_irq; ++i, ++src)
+		ISR[i] = src;
+}
+
 void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
 			 int programmer_switch_irq)
 {
@@ -274,7 +274,7 @@
 	}
 	OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr;
 
-	if ( ppc_md.progress ) ppc_md.progress("openpic enter",0x122);
+	if (ppc_md.progress) ppc_md.progress("openpic: enter", 0x122);
 
 	t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
 	switch (t & OPENPIC_FEATURE_VERSION_MASK) {
@@ -293,8 +293,11 @@
 	}
 	NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
 			 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
-	NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
-		      OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
+	if (NumSources == 0)
+		openpic_set_sources(0,
+				    ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
+				     OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1,
+				    NULL);
 	printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n",
 	       version, NumProcessors, NumSources, OpenPIC);
 	timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
@@ -309,7 +312,7 @@
 	chrp_int_ack_special = (volatile unsigned char*)chrp_ack;
 
 	/* Initialize timer interrupts */
-	if ( ppc_md.progress ) ppc_md.progress("openpic timer",0x3ba);
+	if ( ppc_md.progress ) ppc_md.progress("openpic: timer",0x3ba);
 	for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
 		/* Disabled, Priority 0 */
 		openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+offset);
@@ -319,7 +322,7 @@
 
 #ifdef CONFIG_SMP
 	/* Initialize IPI interrupts */
-	if ( ppc_md.progress ) ppc_md.progress("openpic ipi",0x3bb);
+	if ( ppc_md.progress ) ppc_md.progress("openpic: ipi",0x3bb);
 	for (i = 0; i < OPENPIC_NUM_IPI; i++) {
 		/* Disabled, Priority 10..13 */
 		openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+offset);
@@ -329,8 +332,6 @@
 	}
 #endif
 
-	find_ISUs();
-
 	/* Initialize external interrupts */
 	if (ppc_md.progress) ppc_md.progress("openpic ext",0x3bc);
 
@@ -339,13 +340,16 @@
 	/* SIOint (8259 cascade) is special */
 	if (offset) {
 		openpic_initirq(0, 8, offset, 1, 1);
-		openpic_mapirq(0, 1<<0);
+		openpic_mapirq(0, 1<<0, 0);
 	}
 
 	/* Init all external sources */
 	for (i = 1; i < NumSources; i++) {
 		int pri, sense;
 
+		if (ISR[i] == 0)
+			continue;
+
 		/* the bootloader may have left it enabled (bad !) */
 		openpic_disable_irq(i+offset);
 
@@ -357,7 +361,7 @@
 		/* Enabled, Priority 8 or 9 */
 		openpic_initirq(i, pri, i+offset, !sense, sense);
 		/* Processor 0 */
-		openpic_mapirq(i, 1<<0);
+		openpic_mapirq(i, 1<<0, 0);
 	}
 
 	/* Init descriptors */
@@ -365,7 +369,7 @@
 		irq_desc[i].handler = &open_pic;
 
 	/* Initialize the spurious interrupt */
-	if (ppc_md.progress) ppc_md.progress("openpic spurious",0x3bd);
+	if (ppc_md.progress) ppc_md.progress("openpic: spurious",0x3bd);
 	openpic_set_spurious(OPENPIC_VEC_SPURIOUS+offset);
 
 	/* Initialize the cascade */
@@ -380,39 +384,6 @@
 	if (ppc_md.progress) ppc_md.progress("openpic exit",0x222);
 }
 
-#ifdef CONFIG_POWER3
-void openpic_setup_ISU(int isu_num, unsigned long addr)
-{
-	if (isu_num >= OPENPIC_MAX_ISU)
-		return;
-	ISU[isu_num] = (OpenPIC_SourcePtr) ioremap(addr, 0x400);
-	if (isu_num >= NumISUs)
-		NumISUs = isu_num + 1;
-}
-#endif
-
-void find_ISUs(void)
-{
-#ifdef CONFIG_POWER3
-        /* Use /interrupt-controller/reg and
-         * /interrupt-controller/interrupt-ranges from OF device tree
-	 * the ISU array is setup in chrp_pci.c in ibm_add_bridges
-	 * as a result
-	 * -- tgall
-         */
-
-	/* basically each ISU is a bus, and this assumes that
-	 * open_pic_isu_count interrupts per bus are possible 
-	 * ISU == Interrupt Source
-	 */
-	NumSources = NumISUs * 0x10;
-
-#else
-	/* for non-distributed OpenPIC implementations it's in the IDU -- Cort */
-	ISU[0] = (OpenPIC_Source *)OpenPIC->Source;
-#endif
-}
-
 static void openpic_reset(void)
 {
 	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
@@ -430,6 +401,7 @@
 }
 #endif /* notused */
 
+/* This can't be __init, it is used in openpic_sleep_restore_intrs */
 static void openpic_disable_8259_pass_through(void)
 {
 	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
@@ -471,7 +443,7 @@
 }
 #endif /* notused */
 
-static void openpic_set_priority(u_int pri)
+static void __init openpic_set_priority(u_int pri)
 {
 	DECL_THIS_CPU;
 
@@ -492,6 +464,7 @@
 }
 #endif /* notused */
 
+/* This can't be __init, it is used in openpic_sleep_restore_intrs */
 static void openpic_set_spurious(u_int vec)
 {
 	check_arg_vec(vec);
@@ -521,7 +494,9 @@
 	openpic_write(&OpenPIC->Global.Processor_Initialization, mask);
 }
 
+#if defined(CONFIG_SMP) || defined(CONFIG_PMAC_PBOOK)
 static spinlock_t openpic_setup_lock = SPIN_LOCK_UNLOCKED;
+#endif
 
 #ifdef CONFIG_SMP
 /*
@@ -603,8 +578,8 @@
  	 * we should make sure we also change the default values of irq_affinity
  	 * in irq.c.
  	 */
- 	for (i = 0; i < NumSources ; i++)
-		openpic_mapirq(i, openpic_read(&GET_ISU(i).Destination) | msk);
+ 	for (i = 0; i < NumSources; i++)
+		openpic_mapirq(i, msk, ~0U);
 #endif /* CONFIG_IRQ_ALL_CPUS */
  	openpic_set_priority(0);
 
@@ -654,26 +629,29 @@
  */
 static void openpic_enable_irq(u_int irq)
 {
+	volatile u_int *vpp;
+
 	check_arg_irq(irq);
-	openpic_clearfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
+	vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority;
+	openpic_clearfield(vpp, OPENPIC_MASK);
 	/* make sure mask gets to controller before we return to user */
 	do {
 		mb(); /* sync is probably useless here */
-	} while(openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
-			OPENPIC_MASK));
+	} while (openpic_readfield(vpp, OPENPIC_MASK));
 }
 
 static void openpic_disable_irq(u_int irq)
 {
+	volatile u_int *vpp;
 	u32 vp;
 	
 	check_arg_irq(irq);
-	openpic_setfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
+	vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority;
+	openpic_setfield(vpp, OPENPIC_MASK);
 	/* make sure mask gets to controller before we return to user */
 	do {
 		mb();  /* sync is probably useless here */
-		vp = openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
-    			OPENPIC_MASK | OPENPIC_ACTIVITY);
+		vp = openpic_readfield(vpp, OPENPIC_MASK | OPENPIC_ACTIVITY);
 	} while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
 }
 
@@ -708,9 +686,10 @@
  *  pol: polarity (1 for positive, 0 for negative)
  *  sense: 1 for level, 0 for edge
  */
-static void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
+static void __init
+openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
 {
-	openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
+	openpic_safe_writefield(&ISR[irq]->Vector_Priority,
 				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
 				OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
 				(pri << OPENPIC_PRIORITY_SHIFT) | vec |
@@ -722,9 +701,13 @@
 /*
  *  Map an interrupt source to one or more CPUs
  */
-static void openpic_mapirq(u_int irq, u_int physmask)
+static void openpic_mapirq(u_int irq, u_int physmask, u_int keepmask)
 {
-	openpic_write(&GET_ISU(irq).Destination, physmask);
+	if (ISR[irq] == 0)
+		return;
+	if (keepmask != 0)
+		physmask |= openpic_read(&ISR[irq]->Destination) & keepmask;
+	openpic_write(&ISR[irq]->Destination, physmask);
 }
 
 #ifdef notused
@@ -735,9 +718,10 @@
  */
 static void openpic_set_sense(u_int irq, int sense)
 {
-	openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
-				OPENPIC_SENSE_LEVEL,
-				(sense ? OPENPIC_SENSE_LEVEL : 0));
+	if (ISR[irq] != 0)
+		openpic_safe_writefield(&ISR[irq]->Vector_Priority,
+					OPENPIC_SENSE_LEVEL,
+					(sense ? OPENPIC_SENSE_LEVEL : 0));
 }
 #endif /* notused */
 
@@ -758,7 +742,7 @@
 
 static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask)
 {
-	openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask));
+	openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask), 0);
 }
 
 #ifdef CONFIG_SMP
@@ -799,7 +783,7 @@
 			irq = *chrp_int_ack_special;
 #ifndef CONFIG_GEMINI
 		else
-			irq = i8259_poll();
+			irq = i8259_poll(regs);
 #endif
 		openpic_eoi();
         }
@@ -856,9 +840,11 @@
 	for (i=0; i<OPENPIC_NUM_IPI; i++)
 		save_ipi_vp[i] = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(i));
 	for (i=0; i<NumSources; i++) {
-		save_irq_src_vp[i] = openpic_read(&OpenPIC->Source[i].Vector_Priority)
+		if (ISR[i] == 0)
+			continue;
+		save_irq_src_vp[i] = openpic_read(&ISR[i]->Vector_Priority)
 			& ~OPENPIC_ACTIVITY;
-		save_irq_src_dest[i] = openpic_read(&OpenPIC->Source[i].Destination);
+		save_irq_src_dest[i] = openpic_read(&ISR[i]->Destination);
 	}
 	spin_unlock_irqrestore(&openpic_setup_lock, flags);
 }
@@ -874,15 +860,19 @@
 	openpic_reset();
 
 	for (i=0; i<OPENPIC_NUM_IPI; i++)
-		openpic_write(&OpenPIC->Global.IPI_Vector_Priority(i), save_ipi_vp[i]);
+		openpic_write(&OpenPIC->Global.IPI_Vector_Priority(i),
+			      save_ipi_vp[i]);
 	for (i=0; i<NumSources; i++) {
-		openpic_write(&OpenPIC->Source[i].Vector_Priority, save_irq_src_vp[i]);
-		openpic_write(&OpenPIC->Source[i].Destination, save_irq_src_dest[i]);
+		if (ISR[i] == 0)
+			continue;
+		openpic_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]);
+		openpic_write(&ISR[i]->Destination, save_irq_src_dest[i]);
 	}
 	openpic_set_spurious(OPENPIC_VEC_SPURIOUS+open_pic_irq_offset);
 	openpic_disable_8259_pass_through();
 	for (i=0; i<NumProcessors; i++)
-		openpic_write(&OpenPIC->Processor[i].Current_Task_Priority, save_cpu_task_pri[i]);
+		openpic_write(&OpenPIC->Processor[i].Current_Task_Priority,
+			      save_cpu_task_pri[i]);
 
 	spin_unlock_irqrestore(&openpic_setup_lock, flags);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/open_pic.h linux-2.4.20/arch/ppc/kernel/open_pic.h
--- linux-2.4.19/arch/ppc/kernel/open_pic.h	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/open_pic.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,68 +0,0 @@
-/*
- * BK Id: SCCS/s.open_pic.h 1.14 10/11/01 12:09:12 trini
- */
-/*
- *  arch/ppc/kernel/open_pic.h -- OpenPIC Interrupt Handling
- *
- *  Copyright (C) 1997 Geert Uytterhoeven
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive
- *  for more details.
- *  
- */
-
-#ifndef _PPC_KERNEL_OPEN_PIC_H
-#define _PPC_KERNEL_OPEN_PIC_H
-
-#include <linux/config.h>
-
-#define OPENPIC_SIZE	0x40000
-
-/*
- *  Non-offset'ed vector numbers
- */
-
-#define OPENPIC_VEC_TIMER	64	/* and up */
-#define OPENPIC_VEC_IPI		72	/* and up */
-#define OPENPIC_VEC_SPURIOUS	127
-
-/* OpenPIC IRQ controller structure */
-extern struct hw_interrupt_type open_pic;
-
-/* OpenPIC IPI controller structure */
-#ifdef CONFIG_SMP
-extern struct hw_interrupt_type open_pic_ipi;
-#endif /* CONFIG_SMP */
-
-extern u_int OpenPIC_NumInitSenses;
-extern u_char *OpenPIC_InitSenses;
-extern void* OpenPIC_Addr;
-
-/* Exported functions */
-extern void openpic_init(int, int, unsigned char *, int);
-extern u_int openpic_irq(void);
-extern void openpic_eoi(void);
-extern void openpic_request_IPIs(void);
-extern void do_openpic_setup_cpu(void);
-extern int openpic_get_irq(struct pt_regs *regs);
-extern void openpic_reset_processor_phys(u_int cpumask);
-extern void openpic_setup_ISU(int isu_num, unsigned long addr);
-extern void openpic_cause_IPI(u_int ipi, u_int cpumask);
-extern void smp_openpic_message_pass(int target, int msg, unsigned long data,
-				     int wait);
-
-extern inline int openpic_to_irq(int irq)
-{
-	/* IRQ 0 usually means 'disabled'.. don't mess with it 
-	 * exceptions to this (sandpoint maybe?) 
-	 * shouldn't use openpic_to_irq 
-	 */
-	if (irq != 0){
-		return irq += NUM_8259_INTERRUPTS;
-	} else {
-		return 0;
-	}
-}
-/*extern int open_pic_irq_offset;*/
-#endif /* _PPC_KERNEL_OPEN_PIC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/pci.c linux-2.4.20/arch/ppc/kernel/pci.c
--- linux-2.4.19/arch/ppc/kernel/pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/pci.c	2002-10-29 11:18:40.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pci.c 1.43 05/08/02 15:01:15 benh
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Common pmac/prep/chrp pci routines. -- Cort
@@ -21,15 +21,11 @@
 #include <asm/prom.h>
 #include <asm/sections.h>
 #include <asm/pci-bridge.h>
-#include <asm/residual.h>
 #include <asm/byteorder.h>
 #include <asm/irq.h>
-#include <asm/gg2.h>
 #include <asm/uaccess.h>
 
-#include "pci.h"
-
-#define DEBUG
+#undef DEBUG
 
 #ifdef DEBUG
 #define DBG(x...) printk(x)
@@ -184,6 +180,10 @@
 #endif
 		}
 	}
+
+	/* Call machine specific resource fixup */
+	if (ppc_md.pcibios_fixup_resources)
+		ppc_md.pcibios_fixup_resources(dev);
 }
 
 #ifdef CONFIG_ALL_PPC
@@ -237,7 +237,8 @@
  * which might have be mirrored at 0x0100-0x03ff..
  */
 void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res, unsigned long size,
+		       unsigned long align)
 {
 	struct pci_dev *dev = data;
 
@@ -795,17 +796,237 @@
 		ranges += np;
 	}
 }
+
+/* We create the "pci-OF-bus-map" property now so it appears in the
+ * /proc device tree
+ */
+void __init
+pci_create_OF_bus_map(void)
+{
+	struct property* of_prop;
+		
+	of_prop = (struct property*) alloc_bootmem(sizeof(struct property) + 256);
+	if (of_prop && find_path_device("/")) {
+		memset(of_prop, -1, sizeof(struct property) + 256);
+		of_prop->name = "pci-OF-bus-map";
+		of_prop->length = 256;
+		of_prop->value = (unsigned char *)&of_prop[1];
+		prom_add_property(find_path_device("/"), of_prop);
+	}
+}
 #endif /* CONFIG_ALL_PPC */
 
+/*
+ * This set of routines checks for PCI<->PCI bridges that have closed
+ * IO resources and have child devices. It tries to re-open an IO
+ * window on them. 
+ * 
+ * This is a _temporary_ fix to workaround a problem with Apple's OF
+ * closing IO windows on P2P bridges when the OF drivers of cards
+ * below this bridge don't claim any IO range (typically ATI or
+ * Adaptec).
+ * 
+ * A more complete fix would be to use drivers/pci/setup-bus.c, which
+ * involves a working pcibios_fixup_pbus_ranges(), some more care about
+ * ordering when creating the host bus resources, and maybe a few more
+ * minor tweaks
+ */
+
+/* Initialize bridges with base/limit values we have collected */
+static void __init
+do_update_p2p_io_resource(struct pci_bus *bus, int enable_vga)
+{
+	struct pci_dev *bridge = bus->self;
+	struct pci_controller* hose = (struct pci_controller *)bridge->sysdata;
+	u32 l;
+	u16 w;
+	struct resource res;
+	
+ 	res = *(bus->resource[0]);
+
+	DBG("Remapping Bus %d, bridge: %s\n", bus->number, bridge->name);
+	res.start -= ((unsigned long) hose->io_base_virt - isa_io_base);
+	res.end -= ((unsigned long) hose->io_base_virt - isa_io_base);
+	DBG("  IO window: %08lx-%08lx\n", res.start, res.end);
+
+	/* Set up the top and bottom of the PCI I/O segment for this bus. */
+	pci_read_config_dword(bridge, PCI_IO_BASE, &l);
+	l &= 0xffff000f;
+	l |= (res.start >> 8) & 0x00f0;
+	l |= res.end & 0xf000;
+	pci_write_config_dword(bridge, PCI_IO_BASE, l);
+
+	if ((l & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
+		l = (res.start >> 16) | (res.end & 0xffff0000);
+		pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, l);
+	}
+
+	pci_read_config_word(bridge, PCI_COMMAND, &w);
+	w |= PCI_COMMAND_IO;
+	pci_write_config_word(bridge, PCI_COMMAND, w);
+
+#if 0 /* Enabling this causes XFree 4.2.0 to hang during PCI probe */
+	if (enable_vga) {
+		pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &w);
+		w |= PCI_BRIDGE_CTL_VGA;
+		pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, w);
+	}
+#endif
+}
+
+/* This function is pretty basic and actually quite broken for the
+ * general case, it's enough for us right now though. It's supposed
+ * to tell us if we need to open an IO range at all or not and what
+ * size.
+ */
+static int __init
+check_for_io_childs(struct pci_bus *bus, struct resource* res, int *found_vga)
+{
+	struct list_head *ln;
+	int	i;
+	int	rc = 0;
+
+#define push_end(res, size) do { unsigned long __sz = (size) ; \
+	res->end = ((res->end + __sz) / (__sz + 1)) * (__sz + 1) + __sz; \
+    } while (0)
+
+	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+		struct pci_dev *dev = pci_dev_b(ln);
+		u16 class = dev->class >> 8;
+
+		if (class == PCI_CLASS_DISPLAY_VGA || class == PCI_CLASS_NOT_DEFINED_VGA)
+			*found_vga = 1;
+		if (class >> 8 == PCI_BASE_CLASS_BRIDGE && dev->subordinate)
+			rc |= check_for_io_childs(dev->subordinate, res, found_vga);
+		if (class == PCI_CLASS_BRIDGE_CARDBUS)
+			push_end(res, 0xfff);
+
+		for (i=0; i<PCI_NUM_RESOURCES; i++) {
+			struct resource *r;
+			unsigned long r_size;
+
+			if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI && i >= PCI_BRIDGE_RESOURCES)
+				continue;
+			r = &dev->resource[i];
+			r_size = r->end - r->start;
+			if (r_size < 0xfff)
+				r_size = 0xfff;
+			if (r->flags & IORESOURCE_IO && (r_size) != 0) {
+				rc = 1;
+				push_end(res, r_size);
+			}
+		}
+	}
+
+	return rc;
+}
+
+/* Here we scan all P2P bridges of a given level that have a closed
+ * IO window. Note that the test for the presence of a VGA card should
+ * be improved to take into account already configured P2P bridges,
+ * currently, we don't see them and might end up configuring 2 bridges
+ * with VGA pass through enabled
+ */
+static void __init
+do_fixup_p2p_level(struct pci_bus *bus)
+{
+	struct list_head *ln;
+	int i;
+	int has_vga = 0;
+	
+	for (ln=bus->children.next; ln != &bus->children; ln=ln->next) {
+		struct pci_bus *b = pci_bus_b(ln);
+		struct pci_dev *d = b->self;
+		struct pci_controller* hose = (struct pci_controller *)d->sysdata;
+		struct resource *res = b->resource[0];
+		unsigned long max;
+		int found_vga = 0;
+
+		res->end = 0;
+		res->start = 0x1000;
+		
+		if (!list_empty(&b->devices) && res && res->flags == 0 && res != bus->resource[0] &&
+		    (d->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
+		    check_for_io_childs(b, res, &found_vga)) {
+			u8 io_base_lo;
+
+			printk(KERN_INFO "Fixing up IO bus %s\n", b->name);
+
+			if (found_vga) {
+				if (has_vga) {
+					printk(KERN_WARNING "Skipping VGA, already active on bus segment\n");
+					found_vga = 0;
+				} else
+					has_vga = 1;
+			}
+			pci_read_config_byte(d, PCI_IO_BASE, &io_base_lo);
+
+			if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32)
+				max = ((unsigned long) hose->io_base_virt - isa_io_base) + 0xffffffff;
+			else
+				max = ((unsigned long) hose->io_base_virt - isa_io_base) + 0xffff;
+			
+			res->flags = IORESOURCE_IO;
+			res->name = b->name;
+			
+			/* Find a resource in the parent where we can allocate */
+			for (i = 0 ; i < 4; i++) {
+				struct resource *r = bus->resource[i];
+				if (!r)
+					continue;
+				if ((r->flags & IORESOURCE_IO) == 0)
+					continue;
+				DBG("Trying to allocate from %08lx, size %08lx from parent res %d: %08lx -> %08lx\n",
+					res->start, res->end, i, r->start, r->end);
+				
+				if (allocate_resource(r, res, res->end + 1, res->start, max, res->end + 1, NULL, NULL) < 0) {
+					DBG("Failed !\n");
+					continue;
+				}
+				do_update_p2p_io_resource(b, found_vga);
+				break;
+			}
+		}
+		do_fixup_p2p_level(b);
+	}
+}
+
+static void
+pcibios_fixup_p2p_bridges(void)
+{
+	struct list_head *ln;
+
+	for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next) {
+		struct pci_bus *b = pci_bus_b(ln);
+		do_fixup_p2p_level(b);
+	}
+}
+
 void __init
 pcibios_init(void)
 {
 	struct pci_controller *hose;
 	struct pci_bus *bus;
-	int next_busno;
+	int next_busno, bus_offset;
 
 	printk(KERN_INFO "PCI: Probing PCI hardware\n");
 
+	/* There is a problem with bus renumbering currently. If
+	 * you have 2 sibling pci<->pci bridges, and during PCI
+	 * probe, the first one gets assigned a new number equal
+	 * to the old number of the second one, you'll end up
+	 * probing that branch with 2 bridges racing on the bus
+	 * numbers.
+	 * I work around this on pmac by adding a large offset
+	 * between host bridges, though a better long term solution
+	 * will have to be found in the generic code. --BenH
+	 */
+#ifdef CONFIG_ALL_PPC
+	if (machine_is_compatible("MacRISC"))
+		bus_offset = 0x10;
+	else
+#endif
+		bus_offset = 1;
 	/* Scan all of the recorded PCI controllers.  */
 	for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
 		if (pci_assign_all_busses)
@@ -814,7 +1035,7 @@
 		bus = pci_scan_bus(hose->first_busno, hose->ops, hose);
 		hose->last_busno = bus->subordinate;
 		if (pci_assign_all_busses || next_busno <= hose->last_busno)
-			next_busno = hose->last_busno+1;
+			next_busno = hose->last_busno + bus_offset;
 	}
 	pci_bus_count = next_busno;
 
@@ -825,6 +1046,10 @@
 	if (pci_assign_all_busses && have_of)
 		pcibios_make_OF_bus_map();
 
+	/* Do machine dependent PCI interrupt routing */
+	if (ppc_md.pci_swizzle && ppc_md.pci_map_irq)
+		pci_fixup_irqs(ppc_md.pci_swizzle, ppc_md.pci_map_irq);
+
 	/* Call machine dependant fixup */
 	if (ppc_md.pcibios_fixup)
 		ppc_md.pcibios_fixup();
@@ -833,6 +1058,7 @@
 	pcibios_allocate_bus_resources(&pci_root_buses);
 	pcibios_allocate_resources(0);
 	pcibios_allocate_resources(1);
+	pcibios_fixup_p2p_bridges();
 	pcibios_assign_resources();
 
 	/* Call machine dependent post-init code */
@@ -840,10 +1066,23 @@
 		ppc_md.pcibios_after_init();
 }
 
-int __init
-pcibios_assign_all_busses(void)
+unsigned char __init
+common_swizzle(struct pci_dev *dev, unsigned char *pinp)
 {
-	return pci_assign_all_busses;
+	struct pci_controller *hose = dev->sysdata;
+
+	if (dev->bus->number != hose->first_busno) {
+		u8 pin = *pinp;
+		do {
+			pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
+			/* Move up the chain of bridges. */
+			dev = dev->bus->self;
+		} while (dev->bus->self);
+		*pinp = pin;
+
+		/* The slot is the idsel of the last bridge. */
+	}
+	return PCI_SLOT(dev->devfn);
 }
 
 void __init
@@ -935,7 +1174,7 @@
 	/* XXX FIXME - update OF device tree node interrupt property */
 }
 
-int pcibios_enable_device(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
@@ -948,6 +1187,9 @@
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for (idx=0; idx<6; idx++) {
+		if(!(mask & (1<<idx)))
+			continue;
+			
 		r = &dev->resource[idx];
 		if (!r->start && r->end) {
 			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
@@ -1238,6 +1480,19 @@
 	return result;
 }
 
+void __init
+pci_init_resource(struct resource *res, unsigned long start, unsigned long end,
+		  int flags, char *name)
+{
+	res->start = start;
+	res->end = end;
+	res->flags = flags;
+	res->name = name;
+	res->parent = NULL;
+	res->sibling = NULL;
+	res->child = NULL;
+}
+
 /*
  * Null PCI config access functions, for the case when we can't
  * find a hose.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/pci_auto.c linux-2.4.20/arch/ppc/kernel/pci_auto.c
--- linux-2.4.19/arch/ppc/kernel/pci_auto.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/pci_auto.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,519 @@
+/*
+ * arch/ppc/kernel/pci_auto.c
+ * 
+ * PCI autoconfiguration library
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2001 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.
+ */
+
+/*
+ * The CardBus support is very preliminary.  Preallocating space is
+ * the way to go but will require some change in card services to
+ * make it useful.  Eventually this will ensure that we can put
+ * multiple CB bridges behind multiple P2P bridges.  For now, at
+ * least it ensures that we place the CB bridge BAR and assigned
+ * initial bus numbers.  I definitely need to do something about
+ * the lack of 16-bit I/O support. -MDP
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/pci-bridge.h>
+
+#define	PCIAUTO_IDE_MODE_MASK		0x05
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* DEBUG */
+
+static int pciauto_upper_iospc;
+static int pciauto_upper_memspc;
+
+void __init pciauto_setup_bars(struct pci_controller *hose,
+		int current_bus,
+		int pci_devfn,
+		int bar_limit)
+{
+	int bar_response, bar_size, bar_value;
+	int bar, addr_mask;
+	int * upper_limit;
+	int found_mem64 = 0;
+
+	DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n",
+		current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) );
+
+	for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) {
+		/* Tickle the BAR and get the response */
+		early_write_config_dword(hose,
+				current_bus,
+				pci_devfn,
+				bar,
+				0xffffffff);
+		early_read_config_dword(hose,
+				current_bus,
+				pci_devfn,
+				bar,
+				&bar_response);
+
+		/* If BAR is not implemented go to the next BAR */
+		if (!bar_response)
+			continue;
+
+		/* Check the BAR type and set our address mask */
+		if (bar_response & PCI_BASE_ADDRESS_SPACE) {
+			addr_mask = PCI_BASE_ADDRESS_IO_MASK;
+			upper_limit = &pciauto_upper_iospc;
+			DBG("PCI Autoconfig: BAR 0x%x, I/O, ", bar);
+		} else {
+			if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+			PCI_BASE_ADDRESS_MEM_TYPE_64)
+				found_mem64 = 1;
+
+			addr_mask = PCI_BASE_ADDRESS_MEM_MASK;		
+			upper_limit = &pciauto_upper_memspc;
+			DBG("PCI Autoconfig: BAR 0x%x, Mem ", bar);
+		}
+
+		/* Calculate requested size */
+		bar_size = ~(bar_response & addr_mask) + 1;
+
+		/* Allocate a base address */
+		bar_value = (*upper_limit - bar_size) & ~(bar_size - 1);
+
+		/* Write it out and update our limit */
+		early_write_config_dword(hose,
+				current_bus,
+				pci_devfn,
+				bar,
+				bar_value);
+
+		*upper_limit = bar_value;
+
+		/*
+		 * If we are a 64-bit decoder then increment to the
+		 * upper 32 bits of the bar and force it to locate
+		 * in the lower 4GB of memory.
+		 */ 
+		if (found_mem64) {
+			bar += 4;
+			early_write_config_dword(hose,
+					current_bus,
+					pci_devfn,
+					bar,
+					0x00000000);
+			found_mem64 = 0;
+		}
+
+		DBG("size=0x%x, address=0x%x\n",
+			bar_size, bar_value);
+	}
+
+}
+
+void __init pciauto_prescan_setup_bridge(struct pci_controller *hose,
+		int current_bus,
+		int pci_devfn,
+		int sub_bus,
+		int *iosave,
+		int *memsave)
+{
+	/* Configure bus number registers */
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PRIMARY_BUS,
+			current_bus);
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SECONDARY_BUS,
+			sub_bus + 1);
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SUBORDINATE_BUS,
+			0xff);
+
+	/* Round memory allocator to 1MB boundary */
+	pciauto_upper_memspc &= ~(0x100000 - 1);
+	*memsave = pciauto_upper_memspc;
+
+	/* Round I/O allocator to 4KB boundary */
+	pciauto_upper_iospc &= ~(0x1000 - 1);
+	*iosave = pciauto_upper_iospc;
+
+	/* Set up memory and I/O filter limits, assume 32-bit I/O space */
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_MEMORY_LIMIT,
+			((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_IO_LIMIT,
+			((pciauto_upper_iospc - 1) & 0x0000f000) >> 8);
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_IO_LIMIT_UPPER16,
+			((pciauto_upper_iospc - 1) & 0xffff0000) >> 16);
+
+	/* Zero upper 32 bits of prefetchable base/limit */
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PREF_BASE_UPPER32,
+			0);
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PREF_LIMIT_UPPER32,
+			0);
+}
+
+void __init pciauto_postscan_setup_bridge(struct pci_controller *hose,
+		int current_bus,
+		int pci_devfn,
+		int sub_bus,
+		int *iosave,
+		int *memsave)
+{
+	int cmdstat;
+
+	/* Configure bus number registers */
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SUBORDINATE_BUS,
+			sub_bus);
+
+	/*
+	 * Round memory allocator to 1MB boundary.
+	 * If no space used, allocate minimum.
+	 */
+	pciauto_upper_memspc &= ~(0x100000 - 1);
+	if (*memsave == pciauto_upper_memspc)
+		pciauto_upper_memspc -= 0x00100000;
+
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_MEMORY_BASE,
+			pciauto_upper_memspc >> 16);
+
+	/* Allocate 1MB for pre-fretch */
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PREF_MEMORY_LIMIT,
+			((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
+
+	pciauto_upper_memspc -= 0x100000;
+
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PREF_MEMORY_BASE,
+			pciauto_upper_memspc >> 16);
+
+	/* Round I/O allocator to 4KB boundary */
+	pciauto_upper_iospc &= ~(0x1000 - 1);
+	if (*iosave == pciauto_upper_iospc)
+		pciauto_upper_iospc -= 0x1000;
+
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_IO_BASE,
+			(pciauto_upper_iospc & 0x0000f000) >> 8);
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_IO_BASE_UPPER16,
+			pciauto_upper_iospc >> 16);
+	
+	/* Enable memory and I/O accesses, enable bus master */
+	early_read_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_COMMAND,
+			&cmdstat);
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_COMMAND,
+			cmdstat |
+			PCI_COMMAND_IO |
+			PCI_COMMAND_MEMORY |
+			PCI_COMMAND_MASTER);
+}
+
+void __init pciauto_prescan_setup_cardbus_bridge(struct pci_controller *hose,
+		int current_bus,
+		int pci_devfn,
+		int sub_bus,
+		int *iosave,
+		int *memsave)
+{
+	/* Configure bus number registers */
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PRIMARY_BUS,
+			current_bus);
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SECONDARY_BUS,
+			sub_bus + 1);
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SUBORDINATE_BUS,
+			0xff);
+
+	/* Round memory allocator to 4KB boundary */
+	pciauto_upper_memspc &= ~(0x1000 - 1);
+	*memsave = pciauto_upper_memspc;
+
+	/* Round I/O allocator to 4 byte boundary */
+	pciauto_upper_iospc &= ~(0x4 - 1);
+	*iosave = pciauto_upper_iospc;
+
+	/* Set up memory and I/O filter limits, assume 32-bit I/O space */
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			0x20,
+			pciauto_upper_memspc - 1);
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			0x30,
+			pciauto_upper_iospc - 1);
+}
+
+void __init pciauto_postscan_setup_cardbus_bridge(struct pci_controller *hose,
+		int current_bus,
+		int pci_devfn,
+		int sub_bus,
+		int *iosave,
+		int *memsave)
+{
+	int cmdstat;
+
+	/*
+	 * Configure subordinate bus number.  The PCI subsystem
+	 * bus scan will renumber buses (reserving three additional
+	 * for this PCI<->CardBus bridge for the case where a CardBus
+	 * adapter contains a P2P or CB2CB bridge.
+	 */
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SUBORDINATE_BUS,
+			sub_bus);
+
+	/*
+	 * Reserve an additional 4MB for mem space and 16KB for
+	 * I/O space.  This should cover any additional space
+	 * requirement of unusual CardBus devices with 
+	 * additional bridges that can consume more address space.
+	 * 
+	 * Although pcmcia-cs currently will reprogram bridge
+	 * windows, the goal is to add an option to leave them
+	 * alone and use the bridge window ranges as the regions
+	 * that are searched for free resources upon hot-insertion
+	 * of a device.  This will allow a PCI<->CardBus bridge
+	 * configured by this routine to happily live behind a
+	 * P2P bridge in a system.
+	 */
+	pciauto_upper_memspc -= 0x00400000;
+	pciauto_upper_iospc -= 0x00004000;
+
+	/* Round memory allocator to 4KB boundary */
+	pciauto_upper_memspc &= ~(0x1000 - 1);
+
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			0x1c,
+			pciauto_upper_memspc);
+
+	/* Round I/O allocator to 4 byte boundary */
+	pciauto_upper_iospc &= ~(0x4 - 1);
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			0x2c,
+			pciauto_upper_iospc);
+	
+	/* Enable memory and I/O accesses, enable bus master */
+	early_read_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_COMMAND,
+			&cmdstat);
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_COMMAND,
+			cmdstat |
+			PCI_COMMAND_IO |
+			PCI_COMMAND_MEMORY |
+			PCI_COMMAND_MASTER);
+}
+
+int __init pciauto_bus_scan(struct pci_controller *hose, int current_bus)
+{
+	int sub_bus, pci_devfn, pci_class, cmdstat, found_multi = 0;
+	unsigned short vid;
+	unsigned char header_type;
+
+	/*
+	 * Fetch our I/O and memory space upper boundaries used
+	 * to allocated base addresses on this hose.
+	 */
+	if (current_bus == hose->first_busno) {
+		pciauto_upper_iospc = hose->io_space.end + 1;
+		pciauto_upper_memspc = hose->mem_space.end + 1;
+	}
+
+	sub_bus = current_bus;
+
+	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
+		/* Skip our host bridge */
+		if ( (current_bus == hose->first_busno) && (pci_devfn == 0) )
+			continue;
+
+		if (PCI_FUNC(pci_devfn) && !found_multi)
+			continue;
+
+		/* If config space read fails from this device, move on */
+		if (early_read_config_byte(hose,
+				current_bus,
+				pci_devfn,
+				PCI_HEADER_TYPE,
+				&header_type))
+			continue;
+
+		if (!PCI_FUNC(pci_devfn))
+			found_multi = header_type & 0x80;
+
+		early_read_config_word(hose,
+				current_bus,
+				pci_devfn,
+				PCI_VENDOR_ID,
+				&vid);
+
+		if (vid != 0xffff) {
+			early_read_config_dword(hose,
+					current_bus,
+					pci_devfn,
+					PCI_CLASS_REVISION, &pci_class);
+			if ( (pci_class >> 16) == PCI_CLASS_BRIDGE_PCI ) {
+				int iosave, memsave;
+
+				DBG("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_SLOT(pci_devfn));
+				/* Allocate PCI I/O and/or memory space */
+				pciauto_setup_bars(hose,
+						current_bus,
+						pci_devfn,
+						PCI_BASE_ADDRESS_1);
+
+				pciauto_prescan_setup_bridge(hose,
+						current_bus,
+						pci_devfn,
+						sub_bus,
+						&iosave,
+						&memsave);
+				sub_bus = pciauto_bus_scan(hose, sub_bus+1);
+				pciauto_postscan_setup_bridge(hose,
+						current_bus,
+						pci_devfn,
+						sub_bus,
+						&iosave,
+						&memsave);
+			} else if ((pci_class >> 16) == PCI_CLASS_BRIDGE_CARDBUS) {
+				int iosave, memsave;
+
+				DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn));
+				/* Place CardBus Socket/ExCA registers */
+				pciauto_setup_bars(hose,
+						current_bus,
+						pci_devfn,
+						PCI_BASE_ADDRESS_0);
+
+				pciauto_prescan_setup_cardbus_bridge(hose,
+						current_bus,
+						pci_devfn,
+						sub_bus,
+						&iosave,
+						&memsave);
+				sub_bus = pciauto_bus_scan(hose, sub_bus+1);
+				pciauto_postscan_setup_cardbus_bridge(hose,
+						current_bus,
+						pci_devfn,
+						sub_bus,
+						&iosave,
+						&memsave);
+			} else {
+				if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) {
+					unsigned char prg_iface;
+
+					early_read_config_byte(hose,
+							current_bus,
+							pci_devfn,
+							PCI_CLASS_PROG,
+							&prg_iface);
+					if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) {
+						DBG("PCI Autoconfig: Skipping legacy mode IDE controller\n");
+						continue;
+					}
+				}
+				/* Allocate PCI I/O and/or memory space */
+				pciauto_setup_bars(hose,
+						current_bus,
+						pci_devfn,
+						PCI_BASE_ADDRESS_5);
+
+				/*
+				 * Enable some standard settings
+				 */
+				early_read_config_dword(hose,
+						current_bus,
+						pci_devfn,
+						PCI_COMMAND,
+						&cmdstat);
+				early_write_config_dword(hose,
+						current_bus,
+						pci_devfn,
+						PCI_COMMAND,
+						cmdstat |
+						PCI_COMMAND_IO |
+						PCI_COMMAND_MEMORY |
+						PCI_COMMAND_MASTER);
+				early_write_config_byte(hose,
+						current_bus,
+						pci_devfn,
+						PCI_LATENCY_TIMER,
+						0x80);
+			}
+		}
+	}
+	return sub_bus;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/pmac_backlight.c linux-2.4.20/arch/ppc/kernel/pmac_backlight.c
--- linux-2.4.19/arch/ppc/kernel/pmac_backlight.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/pmac_backlight.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,150 +0,0 @@
-/*
- * BK Id: SCCS/s.pmac_backlight.c 1.10 12/01/01 20:09:06 benh
- */
-/*
- * Miscellaneous procedures for dealing with the PowerMac hardware.
- * Contains support for the backlight.
- * 
- *   Copyright (C) 2000 Benjamin Herrenschmidt
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/reboot.h>
-#include <linux/nvram.h>
-#include <asm/sections.h>
-#include <asm/ptrace.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/nvram.h>
-#include <asm/backlight.h>
-
-#include <linux/adb.h>
-#include <linux/pmu.h>
-
-static struct backlight_controller *backlighter = NULL;
-static void* backlighter_data = NULL;
-static int backlight_autosave = 0;
-static int backlight_level = BACKLIGHT_MAX;
-static int backlight_enabled = 1;
-
-void __pmac
-register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type)
-{
-	struct device_node* bk_node;
-	char *prop;
-	int valid = 0;
-
-	bk_node = find_devices("backlight");
-	
-#ifdef CONFIG_ADB_PMU
-	/* Special case for the old PowerBook since I can't test on it */
-	backlight_autosave = machine_is_compatible("AAPL,3400/2400")
-		|| machine_is_compatible("AAPL,3500");
-	if ((backlight_autosave
-	     || machine_is_compatible("AAPL,PowerBook1998")
-	     || machine_is_compatible("PowerBook1,1"))
-	    && !strcmp(type, "pmu"))
-		valid = 1;
-#endif
-	if (bk_node) {
-		prop = get_property(bk_node, "backlight-control", NULL);
-		if (prop && !strncmp(prop, type, strlen(type)))
-			valid = 1;
-	}
-	if (!valid)
-		return;
-	backlighter = ctrler;
-	backlighter_data = data;
-	
-	if (bk_node && !backlight_autosave)
-		prop = get_property(bk_node, "bklt", NULL);
-	else
-		prop = NULL;
-	if (prop) {
-		backlight_level = ((*prop)+1) >> 1;
-		if (backlight_level > BACKLIGHT_MAX)
-			backlight_level = BACKLIGHT_MAX;
-	}
-	
-#ifdef CONFIG_ADB_PMU
-	if (backlight_autosave) {
-		struct adb_request req;
-		pmu_request(&req, NULL, 2, 0xd9, 0);
-		while (!req.complete)
-			pmu_poll();
-		backlight_level = req.reply[0] >> 4;
-	}
-#endif
-	if (!backlighter->set_enable(1, backlight_level, data))
-		backlight_enabled = 1;
-
-	printk(KERN_INFO "Registered \"%s\" backlight controller, level: %d/15\n",
-		type, backlight_level);
-}
-
-void __pmac
-unregister_backlight_controller(struct backlight_controller *ctrler, void *data)
-{
-	/* We keep the current backlight level (for now) */
-	if (ctrler == backlighter && data == backlighter_data)
-		backlighter = NULL;
-}
-
-int __pmac
-set_backlight_enable(int enable)
-{
-	int rc;
-	
-	if (!backlighter)
-		return -ENODEV;
-	rc = backlighter->set_enable(enable, backlight_level, backlighter_data);
-	if (!rc)
-		backlight_enabled = enable;
-	return rc;
-}
-
-int __pmac
-get_backlight_enable(void)
-{
-	if (!backlighter)
-		return -ENODEV;
-	return backlight_enabled;
-}
-
-int __pmac
-set_backlight_level(int level)
-{
-	int rc = 0;
-	
-	if (!backlighter)
-		return -ENODEV;
-	if (level < BACKLIGHT_MIN)
-		level = BACKLIGHT_OFF;
-	if (level > BACKLIGHT_MAX)
-		level = BACKLIGHT_MAX;
-	if (backlight_enabled)
-		rc = backlighter->set_level(level, backlighter_data);
-	if (!rc)
-		backlight_level = level;
-	if (!rc && !backlight_autosave) {
-		level <<=1;
-		if (level & 0x10)
-			level |= 0x01;
-		// -- todo: save to property "bklt"
-	}
-	return rc;
-}
-
-int __pmac
-get_backlight_level(void)
-{
-	if (!backlighter)
-		return -ENODEV;
-	return backlight_level;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/pmac_feature.c linux-2.4.20/arch/ppc/kernel/pmac_feature.c
--- linux-2.4.19/arch/ppc/kernel/pmac_feature.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/pmac_feature.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,2139 +0,0 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  arch/ppc/kernel/pmac_feature.c
- *
- *  Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au)
- *                          Ben. Herrenschmidt (benh@kernel.crashing.org)
- *
- *  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.
- *  
- *  TODO: 
- *  
- *   - Replace mdelay with some schedule loop if possible
- *   - Shorten some obfuscated delays on some routines (like modem
- *     power)
- *
- */
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <asm/sections.h>
-#include <asm/errno.h>
-#include <asm/ohare.h>
-#include <asm/heathrow.h>
-#include <asm/keylargo.h>
-#include <asm/uninorth.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/dbdma.h>
-
-#undef DEBUG_FEATURE
-
-#ifdef DEBUG_FEATURE
-#define DBG(fmt,...) printk(KERN_DEBUG fmt)
-#else
-#define DBG(fmt,...)
-#endif
-
-/* Exported from arch/ppc/kernel/idle.c */
-extern unsigned long powersave_nap;
-
-/*
- * We use a single global lock to protect accesses. Each driver has
- * to take care of it's own locking
- */
-static spinlock_t feature_lock  __pmacdata = SPIN_LOCK_UNLOCKED;
-
-#define LOCK(flags)	spin_lock_irqsave(&feature_lock, flags);
-#define UNLOCK(flags)	spin_unlock_irqrestore(&feature_lock, flags);
-
-/*
- * Helper functions regarding the various flavors of mac-io
- */
- 
-#define MAX_MACIO_CHIPS		2
-
-enum {
-	macio_unknown = 0,
-	macio_grand_central,
-	macio_ohare,
-	macio_ohareII,
-	macio_heathrow,
-	macio_gatwick,
-	macio_paddington,
-	macio_keylargo,
-	macio_pangea
-};
-
-static const char* macio_names[] __pmacdata = 
-{
-	"Unknown",
-	"Grand Central",
-	"OHare",
-	"OHareII",
-	"Heathrow",
-	"Gatwick",
-	"Paddington",
-	"Keylargo",
-	"Pangea"
-};
-
-static struct macio_chip
-{
-	struct device_node*	of_node;
-	int			type;
-	int			rev;
-	volatile u32*		base;
-	unsigned long		flags;
-} macio_chips[MAX_MACIO_CHIPS]  __pmacdata;
-
-#define MACIO_FLAG_SCCA_ON	0x00000001
-#define MACIO_FLAG_SCCB_ON	0x00000002
-#define MACIO_FLAG_SCC_LOCKED	0x00000004
-#define MACIO_FLAG_AIRPORT_ON	0x00000010
-#define MACIO_FLAG_FW_SUPPORTED	0x00000020
-
-static struct macio_chip* __pmac
-macio_find(struct device_node* child, int type)
-{
-	while(child) {
-		int	i;
-	
-		for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++)
-			if (child == macio_chips[i].of_node &&
-			    (!type || macio_chips[i].type == type))
-				return &macio_chips[i];
-		child = child->parent;
-	}
-	return NULL;
-}
-
-#define MACIO_FCR32(macio, r)	((macio)->base + ((r) >> 2))
-#define MACIO_FCR8(macio, r)	(((volatile u8*)((macio)->base)) + (r))
-
-#define MACIO_IN32(r)		(in_le32(MACIO_FCR32(macio,r)))
-#define MACIO_OUT32(r,v)	(out_le32(MACIO_FCR32(macio,r), (v)))
-#define MACIO_BIS(r,v)		(MACIO_OUT32((r), MACIO_IN32(r) | (v)))
-#define MACIO_BIC(r,v)		(MACIO_OUT32((r), MACIO_IN32(r) & ~(v)))
-#define MACIO_IN8(r)		(in_8(MACIO_FCR8(macio,r)))
-#define MACIO_OUT8(r,v)		(out_8(MACIO_FCR8(macio,r), (v)))
-
-/*
- * Uninorth reg. access. Note that Uni-N regs are big endian
- */
- 
-#define UN_REG(r)	(uninorth_base + ((r) >> 2))
-#define UN_IN(r)	(in_be32(UN_REG(r)))
-#define UN_OUT(r,v)	(out_be32(UN_REG(r), (v)))
-#define UN_BIS(r,v)	(UN_OUT((r), UN_IN(r) | (v)))
-#define UN_BIC(r,v)	(UN_OUT((r), UN_IN(r) & ~(v)))
-
-static struct device_node* uninorth_node __pmacdata;
-static u32* uninorth_base __pmacdata;
-static u32 uninorth_rev __pmacdata;
-
-
-/*
- * For each motherboard family, we have a table of functions pointers
- * that handle the various features.
- */
-
-typedef int (*feature_call)(struct device_node* node, int param, int value);
-
-struct feature_table_entry {
-	unsigned int	selector;	
-	feature_call	function;
-};
-
-struct pmac_mb_def
-{
-	const char*			model_string;
-	const char*			model_name;
-	int				model_id;
-	struct feature_table_entry* 	features;
-	unsigned long			board_flags;
-};
-static struct pmac_mb_def pmac_mb __pmacdata;
-
-/*
- * Here are the chip specific feature functions
- */
-
-static inline int __pmac
-simple_feature_tweak(struct device_node* node, int type, int reg, u32 mask, int value)
-{
-	struct macio_chip*	macio;
-	unsigned long		flags;
-	
-	macio = macio_find(node, type);
-	if (!macio)
-		return -ENODEV;
-	LOCK(flags);
-	if (value)
-		MACIO_BIS(reg, mask);
-	else
-		MACIO_BIC(reg, mask);
-	(void)MACIO_IN32(reg);
-	UNLOCK(flags);
-
-	return 0;
-}
-
-static int __pmac
-ohare_htw_scc_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	unsigned long		chan_mask;
-	unsigned long		fcr;
-	unsigned long		flags;
-	int			htw, trans;
-	unsigned long		rmask;
-	
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-	if (!strcmp(node->name, "ch-a"))
-		chan_mask = MACIO_FLAG_SCCA_ON;
-	else if (!strcmp(node->name, "ch-b"))
-		chan_mask = MACIO_FLAG_SCCB_ON;
-	else
-		return -ENODEV;
-
-	htw = (macio->type == macio_heathrow || macio->type == macio_paddington
-		|| macio->type == macio_gatwick);
-	/* On these machines, the HRW_SCC_TRANS_EN_N bit mustn't be touched */
-	trans = (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
-	    	 pmac_mb.model_id != PMAC_TYPE_YIKES);
-	if (value) {
-#ifdef CONFIG_ADB_PMU
-		if ((param & 0xfff) == PMAC_SCC_IRDA)
-			pmu_enable_irled(1);
-#endif /* CONFIG_ADB_PMU */		
-		LOCK(flags);
-		fcr = MACIO_IN32(OHARE_FCR);
-		/* Check if scc cell need enabling */
-		if (!(fcr & OH_SCC_ENABLE)) {
-			fcr |= OH_SCC_ENABLE;
-			if (htw) {
-				/* Side effect: this will also power up the
-				 * modem, but it's too messy to figure out on which
-				 * ports this controls the tranceiver and on which
-				 * it controls the modem
-				 */
-				if (trans)
-					fcr &= ~HRW_SCC_TRANS_EN_N;
-				MACIO_OUT32(OHARE_FCR, fcr);
-				fcr |= (rmask = HRW_RESET_SCC);
-				MACIO_OUT32(OHARE_FCR, fcr);
-			} else {
-				fcr |= (rmask = OH_SCC_RESET);
-				MACIO_OUT32(OHARE_FCR, fcr);
-			}
-			UNLOCK(flags);
-			(void)MACIO_IN32(OHARE_FCR);
-			mdelay(15);
-			LOCK(flags);
-			fcr &= ~rmask;
-			MACIO_OUT32(OHARE_FCR, fcr);
-		}
-		if (chan_mask & MACIO_FLAG_SCCA_ON)
-			fcr |= OH_SCCA_IO;
-		if (chan_mask & MACIO_FLAG_SCCB_ON)
-			fcr |= OH_SCCB_IO;
-		MACIO_OUT32(OHARE_FCR, fcr);
-		macio->flags |= chan_mask;
-		UNLOCK(flags);
-		if (param & PMAC_SCC_FLAG_XMON)
-			macio->flags |= MACIO_FLAG_SCC_LOCKED;
-	} else {
-		if (macio->flags & MACIO_FLAG_SCC_LOCKED)
-			return -EPERM;
-		LOCK(flags);
-		fcr = MACIO_IN32(OHARE_FCR);
-		if (chan_mask & MACIO_FLAG_SCCA_ON)
-			fcr &= ~OH_SCCA_IO;
-		if (chan_mask & MACIO_FLAG_SCCB_ON)
-			fcr &= ~OH_SCCB_IO;
-		MACIO_OUT32(OHARE_FCR, fcr);
-		if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) {
-			fcr &= ~OH_SCC_ENABLE;
-			if (htw && trans)
-				fcr |= HRW_SCC_TRANS_EN_N;
-			MACIO_OUT32(OHARE_FCR, fcr);
-		}
-		macio->flags &= ~(chan_mask);
-		UNLOCK(flags);
-		mdelay(10);
-#ifdef CONFIG_ADB_PMU
-		if ((param & 0xfff) == PMAC_SCC_IRDA)
-			pmu_enable_irled(0);
-#endif /* CONFIG_ADB_PMU */		
-	}
-	return 0;
-}
-
-static int __pmac
-ohare_floppy_enable(struct device_node* node, int param, int value)
-{
-	return simple_feature_tweak(node, macio_ohare,
-		OHARE_FCR, OH_FLOPPY_ENABLE, value);
-}
-
-static int __pmac
-ohare_mesh_enable(struct device_node* node, int param, int value)
-{
-	return simple_feature_tweak(node, macio_ohare,
-		OHARE_FCR, OH_MESH_ENABLE, value);
-}
-
-static int __pmac
-ohare_ide_enable(struct device_node* node, int param, int value)
-{
-	switch(param) {
-	    case 0:
-	    	/* For some reason, setting the bit in set_initial_features()
-	    	 * doesn't stick. I'm still investigating... --BenH.
-	    	 */
-	    	if (value)
-	    		simple_feature_tweak(node, macio_ohare,
-				OHARE_FCR, OH_IOBUS_ENABLE, 1);
-		return simple_feature_tweak(node, macio_ohare,
-			OHARE_FCR, OH_IDE0_ENABLE, value);
-	    case 1:
-		return simple_feature_tweak(node, macio_ohare,
-			OHARE_FCR, OH_BAY_IDE_ENABLE, value);
-	    default:
-	    	return -ENODEV;
-	}
-}
-
-static int __pmac
-ohare_ide_reset(struct device_node* node, int param, int value)
-{
-	switch(param) {
-	    case 0:
-		return simple_feature_tweak(node, macio_ohare,
-			OHARE_FCR, OH_IDE0_RESET_N, !value);
-	    case 1:
-		return simple_feature_tweak(node, macio_ohare,
-			OHARE_FCR, OH_IDE1_RESET_N, !value);
-	    default:
-	    	return -ENODEV;
-	}
-}
-
-static int __pmac
-ohare_sleep_state(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio = &macio_chips[0];
-
-	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
-		return -EPERM;
-	if (value == 1) {
-		MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE);
-	} else if (value == 0) {
-		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
-	}
-	
-	return 0;
-}
-
-static int __pmac
-heathrow_modem_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	u8			gpio;
-	unsigned long		flags;
-	
-	macio = macio_find(node, macio_unknown);
-	if (!macio)
-		return -ENODEV;
-	gpio = MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1;
-	if (!value) {
-		LOCK(flags);
-		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
-		UNLOCK(flags);
-		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-		mdelay(250);
-	}
-	if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
-	    pmac_mb.model_id != PMAC_TYPE_YIKES) {
-	    	LOCK(flags);
-	    	if (value)
-	    		MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
-	    	else
-	    		MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
-	    	UNLOCK(flags);
-	    	(void)MACIO_IN32(HEATHROW_FCR);
-		mdelay(250);
-	}
-	if (value) {
-		LOCK(flags);
-		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
-		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
-		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
-		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
-		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
-		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250);
-	}
-	return 0;
-}
-
-static int __pmac
-heathrow_floppy_enable(struct device_node* node, int param, int value)
-{
-	return simple_feature_tweak(node, macio_unknown,
-		HEATHROW_FCR,
-		HRW_SWIM_ENABLE|HRW_BAY_FLOPPY_ENABLE,
-		value);
-}
-
-static int __pmac
-heathrow_mesh_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	unsigned long		flags;
-	
-	macio = macio_find(node, macio_unknown);
-	if (!macio)
-		return -ENODEV;
-	LOCK(flags);
-	/* Set clear mesh cell enable */
-	if (value)
-		MACIO_BIS(HEATHROW_FCR, HRW_MESH_ENABLE);
-	else
-		MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE);
-	(void)MACIO_IN32(HEATHROW_FCR);
-	udelay(10);
-	/* Set/Clear termination power (todo: test ! the bit value
-	 * used by Darwin doesn't seem to match what we used so
-	 * far. If you experience problems, turn #if 1 into #if 0
-	 * and tell me about it --BenH.
-	 */
-#if 1
-	if (value)
-		MACIO_BIC(HEATHROW_MBCR, 0x00000004);
-	else
-		MACIO_BIS(HEATHROW_MBCR, 0x00000004);
-#else
-	if (value)
-		MACIO_BIC(HEATHROW_MBCR, 0x00040000);
-	else
-		MACIO_BIS(HEATHROW_MBCR, 0x00040000);
-#endif		
-	(void)MACIO_IN32(HEATHROW_MBCR);
-	udelay(10);
-	UNLOCK(flags);
-
-	return 0;
-}
-
-static int __pmac
-heathrow_ide_enable(struct device_node* node, int param, int value)
-{
-	switch(param) {
-	    case 0:
-		return simple_feature_tweak(node, macio_unknown,
-			HEATHROW_FCR, HRW_IDE0_ENABLE, value);
-	    case 1:
-		return simple_feature_tweak(node, macio_unknown,
-			HEATHROW_FCR, HRW_BAY_IDE_ENABLE, value);
-	    default:
-	    	return -ENODEV;
-	}
-}
-
-static int __pmac
-heathrow_ide_reset(struct device_node* node, int param, int value)
-{
-	switch(param) {
-	    case 0:
-		return simple_feature_tweak(node, macio_unknown,
-			HEATHROW_FCR, HRW_IDE0_RESET_N, !value);
-	    case 1:
-		return simple_feature_tweak(node, macio_unknown,
-			HEATHROW_FCR, HRW_IDE1_RESET_N, !value);
-	    default:
-	    	return -ENODEV;
-	}
-}
-
-static int __pmac
-heathrow_bmac_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	unsigned long		flags;
-	
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-	if (value) {
-		LOCK(flags);
-		MACIO_BIS(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
-		MACIO_BIS(HEATHROW_FCR, HRW_BMAC_RESET);
-		UNLOCK(flags);
-		(void)MACIO_IN32(HEATHROW_FCR);
-		mdelay(10);
-		LOCK(flags);
-		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_RESET);
-		UNLOCK(flags);
-		(void)MACIO_IN32(HEATHROW_FCR);
-		mdelay(10);
-	} else {
-		LOCK(flags);
-		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
-		UNLOCK(flags);
-	}
-	return 0;
-}
-
-static int __pmac
-heathrow_sound_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	unsigned long		flags;
-
-	/* B&W G3 and Yikes don't support that properly (the
-	 * sound appear to never come back after beeing shut down).
-	 */
-	if (pmac_mb.model_id == PMAC_TYPE_YOSEMITE ||
-	    pmac_mb.model_id == PMAC_TYPE_YIKES)
-		return 0;
-	
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-	if (value) {
-		LOCK(flags);
-		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
-		UNLOCK(flags);
-		(void)MACIO_IN32(HEATHROW_FCR);
-	} else {
-		LOCK(flags);
-		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
-		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-		UNLOCK(flags);
-	}
-	return 0;
-}
-
-static u32 save_fcr[5] __pmacdata;
-static u32 save_mbcr __pmacdata;
-static u32 save_gpio_levels[2] __pmacdata;
-static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT] __pmacdata;
-static u8 save_gpio_normal[KEYLARGO_GPIO_CNT] __pmacdata;
-static u32 save_unin_clock_ctl __pmacdata;
-static struct dbdma_regs save_dbdma[13] __pmacdata;
-static struct dbdma_regs save_alt_dbdma[13] __pmacdata;
-
-static void __pmac
-dbdma_save(struct macio_chip* macio, struct dbdma_regs* save)
-{
-	int i;
-	
-	/* Save state & config of DBDMA channels */
-	for (i=0; i<13; i++) {
-		volatile struct dbdma_regs* chan = (volatile struct dbdma_regs*)
-			(macio->base + ((0x8000+i*0x100)>>2));
-		save[i].cmdptr_hi = in_le32(&chan->cmdptr_hi);
-		save[i].cmdptr = in_le32(&chan->cmdptr);
-		save[i].intr_sel = in_le32(&chan->intr_sel);
-		save[i].br_sel = in_le32(&chan->br_sel);
-		save[i].wait_sel = in_le32(&chan->wait_sel);
-	}
-}
-
-static void __pmac
-dbdma_restore(struct macio_chip* macio, struct dbdma_regs* save)
-{
-	int i;
-	
-	/* Save state & config of DBDMA channels */
-	for (i=0; i<13; i++) {
-		volatile struct dbdma_regs* chan = (volatile struct dbdma_regs*)
-			(macio->base + ((0x8000+i*0x100)>>2));
-		out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16);
-		while (in_le32(&chan->status) & ACTIVE)
-			mb();
-		out_le32(&chan->cmdptr_hi, save[i].cmdptr_hi);
-		out_le32(&chan->cmdptr, save[i].cmdptr);
-		out_le32(&chan->intr_sel, save[i].intr_sel);
-		out_le32(&chan->br_sel, save[i].br_sel);
-		out_le32(&chan->wait_sel, save[i].wait_sel);
-	}
-}
-
-static void __pmac
-heathrow_sleep(struct macio_chip* macio, int secondary)
-{
-	if (secondary) {
-		dbdma_save(macio, save_alt_dbdma);
-		save_fcr[2] = MACIO_IN32(0x38);
-		save_fcr[3] = MACIO_IN32(0x3c);
-	} else {
-		dbdma_save(macio, save_dbdma);
-		save_fcr[0] = MACIO_IN32(0x38);
-		save_fcr[1] = MACIO_IN32(0x3c);
-		save_mbcr = MACIO_IN32(0x34);
-		/* Make sure sound is shut down */
-		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
-		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-		/* This seems to be necessary as well or the fan
-		 * keeps coming up and battery drains fast */
-		MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE);
-		/* Make sure eth is down even if module or sleep
-		 * won't work properly */
-		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET);
-	}
-	/* Make sure modem is shut down */
-	MACIO_OUT8(HRW_GPIO_MODEM_RESET,
-		MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1);
-	MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
-	MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE);
-
-	/* Let things settle */
-	(void)MACIO_IN32(HEATHROW_FCR);
-	mdelay(1);
-}
-
-static void __pmac
-heathrow_wakeup(struct macio_chip* macio, int secondary)
-{
-	if (secondary) {
-		MACIO_OUT32(0x38, save_fcr[2]);
-		(void)MACIO_IN32(0x38);
-		mdelay(1);
-		MACIO_OUT32(0x3c, save_fcr[3]);
-		(void)MACIO_IN32(0x38);
-		mdelay(10);
-		dbdma_restore(macio, save_alt_dbdma);
-	} else {
-		MACIO_OUT32(0x38, save_fcr[0] | HRW_IOBUS_ENABLE);
-		(void)MACIO_IN32(0x38);
-		mdelay(1);
-		MACIO_OUT32(0x3c, save_fcr[1]);
-		(void)MACIO_IN32(0x38);
-		mdelay(1);
-		MACIO_OUT32(0x34, save_mbcr);
-		(void)MACIO_IN32(0x38);
-		mdelay(10);
-		dbdma_restore(macio, save_dbdma);
-	}
-}
-
-static int __pmac
-heathrow_sleep_state(struct device_node* node, int param, int value)
-{
-	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
-		return -EPERM;
-	if (value == 1) {
-		if (macio_chips[1].type == macio_gatwick)
-			heathrow_sleep(&macio_chips[0], 1);
-		heathrow_sleep(&macio_chips[0], 0);
-	} else if (value == 0) {
-		heathrow_wakeup(&macio_chips[0], 0);
-		if (macio_chips[1].type == macio_gatwick)
-			heathrow_wakeup(&macio_chips[0], 1);
-	}
-	return 0;
-}
-
-static int __pmac
-core99_scc_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	unsigned long		flags;
-	unsigned long		chan_mask;
-	u32			fcr;
-	
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-	if (!strcmp(node->name, "ch-a"))
-		chan_mask = MACIO_FLAG_SCCA_ON;
-	else if (!strcmp(node->name, "ch-b"))
-		chan_mask = MACIO_FLAG_SCCB_ON;
-	else
-		return -ENODEV;
-
-	if (value) {
-		int need_reset_scc = 0;
-		int need_reset_irda = 0;
-		
-		LOCK(flags);
-		fcr = MACIO_IN32(KEYLARGO_FCR0);
-		/* Check if scc cell need enabling */
-		if (!(fcr & KL0_SCC_CELL_ENABLE)) {
-			fcr |= KL0_SCC_CELL_ENABLE;
-			need_reset_scc = 1;
-		}
-		if (chan_mask & MACIO_FLAG_SCCA_ON) {
-			fcr |= KL0_SCCA_ENABLE;
-			/* Don't enable line drivers for I2S modem */
-			if ((param & 0xfff) == PMAC_SCC_I2S1)
-				fcr &= ~KL0_SCC_A_INTF_ENABLE;
-			else
-				fcr |= KL0_SCC_A_INTF_ENABLE;
-		}
-		if (chan_mask & MACIO_FLAG_SCCB_ON) {
-			fcr |= KL0_SCCB_ENABLE;
-			/* Perform irda specific inits */
-			if ((param & 0xfff) == PMAC_SCC_IRDA) {
-				fcr &= ~KL0_SCC_B_INTF_ENABLE;
-				fcr |= KL0_IRDA_ENABLE;
-				fcr |= KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE;
-				fcr |= KL0_IRDA_SOURCE1_SEL;
-				fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
-				fcr &= ~(KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
-				need_reset_irda = 1;
-			} else
-				fcr |= KL0_SCC_B_INTF_ENABLE;
-		}
-		MACIO_OUT32(KEYLARGO_FCR0, fcr);
-		macio->flags |= chan_mask;
-		if (need_reset_scc)  {
-			MACIO_BIS(KEYLARGO_FCR0, KL0_SCC_RESET);
-			(void)MACIO_IN32(KEYLARGO_FCR0);
-			UNLOCK(flags);
-			mdelay(15);
-			LOCK(flags);
-			MACIO_BIC(KEYLARGO_FCR0, KL0_SCC_RESET);
-		}
-		if (need_reset_irda)  {
-			MACIO_BIS(KEYLARGO_FCR0, KL0_IRDA_RESET);
-			(void)MACIO_IN32(KEYLARGO_FCR0);
-			UNLOCK(flags);
-			mdelay(15);
-			LOCK(flags);
-			MACIO_BIC(KEYLARGO_FCR0, KL0_IRDA_RESET);
-		}
-		UNLOCK(flags);
-		if (param & PMAC_SCC_FLAG_XMON)
-			macio->flags |= MACIO_FLAG_SCC_LOCKED;
-	} else {
-		if (macio->flags & MACIO_FLAG_SCC_LOCKED)
-			return -EPERM;
-		LOCK(flags);
-		fcr = MACIO_IN32(KEYLARGO_FCR0);
-		if (chan_mask & MACIO_FLAG_SCCA_ON)
-			fcr &= ~KL0_SCCA_ENABLE;
-		if (chan_mask & MACIO_FLAG_SCCB_ON) {
-			fcr &= ~KL0_SCCB_ENABLE;
-			/* Perform irda specific clears */
-			if ((param & 0xfff) == PMAC_SCC_IRDA) {
-				fcr &= ~KL0_IRDA_ENABLE;
-				fcr &= ~(KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE);
-				fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
-				fcr &= ~(KL0_IRDA_SOURCE1_SEL|KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
-			}
-		}
-		MACIO_OUT32(KEYLARGO_FCR0, fcr);
-		if ((fcr & (KL0_SCCA_ENABLE | KL0_SCCB_ENABLE)) == 0) {
-			fcr &= ~KL0_SCC_CELL_ENABLE;
-			MACIO_OUT32(KEYLARGO_FCR0, fcr);
-		}
-		macio->flags &= ~(chan_mask);
-		UNLOCK(flags);
-		mdelay(10);
-	}
-	return 0;
-}
-
-static int __pmac
-core99_modem_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	u8			gpio;
-	unsigned long		flags;
-	
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-	gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
-	gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
-	gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
-	
-	if (!value) {
-		LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-		UNLOCK(flags);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-		mdelay(250);
-	}
-    	LOCK(flags);
-    	if (value) {
-    		MACIO_BIC(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
-	    	UNLOCK(flags);
-	    	(void)MACIO_IN32(KEYLARGO_FCR2);
-		mdelay(250);
-    	} else {
-    		MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
-	    	UNLOCK(flags);
-    	}
-	if (value) {
-		LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250);
-	}
-	return 0;
-}
-
-static int __pmac
-core99_ide_enable(struct device_node* node, int param, int value)
-{
-	switch(param) {
-	    case 0:
-		return simple_feature_tweak(node, macio_unknown,
-			KEYLARGO_FCR1, KL1_EIDE0_ENABLE, value);
-	    case 1:
-		return simple_feature_tweak(node, macio_unknown,
-			KEYLARGO_FCR1, KL1_EIDE1_ENABLE, value);
-	    case 2:
-		return simple_feature_tweak(node, macio_unknown,
-			KEYLARGO_FCR1, KL1_UIDE_ENABLE, value);
-	    default:
-	    	return -ENODEV;
-	}
-}
-
-static int __pmac
-core99_ide_reset(struct device_node* node, int param, int value)
-{
-	switch(param) {
-	    case 0:
-		return simple_feature_tweak(node, macio_unknown,
-			KEYLARGO_FCR1, KL1_EIDE0_RESET_N, !value);
-	    case 1:
-		return simple_feature_tweak(node, macio_unknown,
-			KEYLARGO_FCR1, KL1_EIDE1_RESET_N, !value);
-	    case 2:
-		return simple_feature_tweak(node, macio_unknown,
-			KEYLARGO_FCR1, KL1_UIDE_RESET_N, !value);
-	    default:
-	    	return -ENODEV;
-	}
-}
-
-static int __pmac
-core99_gmac_enable(struct device_node* node, int param, int value)
-{
-	unsigned long flags;
-
-	LOCK(flags);
-	if (value)
-		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
-	else
-		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
-	(void)UN_IN(UNI_N_CLOCK_CNTL);
-	UNLOCK(flags);
-	udelay(20);
-
-	return 0;
-}
-
-static int __pmac
-core99_gmac_phy_reset(struct device_node* node, int param, int value)
-{
-	unsigned long flags;
-	struct macio_chip* macio;
-	
-	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
-		return -ENODEV;
-
-	LOCK(flags);
-	MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE);
-	(void)MACIO_IN8(KL_GPIO_ETH_PHY_RESET);
-	UNLOCK(flags);
-	mdelay(10);
-	LOCK(flags);
-	MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE
-		| KEYLARGO_GPIO_OUTOUT_DATA);
-	UNLOCK(flags);
-	mdelay(10);
-
-	return 0;
-}
-
-static int __pmac
-core99_sound_chip_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	unsigned long		flags;
-	
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-
-	/* Do a better probe code, screamer G4 desktops &
-	 * iMacs can do that too, add a recalibrate  in
-	 * the driver as well
-	 */
-	if (pmac_mb.model_id == PMAC_TYPE_PISMO ||
-	    pmac_mb.model_id == PMAC_TYPE_TITANIUM) {
-		LOCK(flags);
-		if (value)
-	    		MACIO_OUT8(KL_GPIO_SOUND_POWER,
-	    			KEYLARGO_GPIO_OUTPUT_ENABLE |
-	    			KEYLARGO_GPIO_OUTOUT_DATA);
-	    	else
-	    		MACIO_OUT8(KL_GPIO_SOUND_POWER,
-	    			KEYLARGO_GPIO_OUTPUT_ENABLE);
-	    	(void)MACIO_IN8(KL_GPIO_SOUND_POWER);
-	    	UNLOCK(flags);
-	}
-	return 0;
-}
-
-static int __pmac
-core99_airport_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	unsigned long		flags;
-	int			state;
-	
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-	
-	/* Hint: we allow passing of macio itself for the sake of the
-	 * sleep code
-	 */
-	if (node != macio->of_node &&
-	    (!node->parent || node->parent != macio->of_node))
-		return -ENODEV;
-	state = (macio->flags & MACIO_FLAG_AIRPORT_ON) != 0;
-	if (value == state)
-		return 0;
-	if (value) {
-		/* This code is a reproduction of OF enable-cardslot
-		 * and init-wireless methods, slightly hacked until
-		 * I got it working.
-		 */
-		LOCK(flags);
-		MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 5);
-		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
-		UNLOCK(flags);
-		mdelay(10);
-		LOCK(flags);
-		MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 4);
-		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
-		UNLOCK(flags);
-
-		mdelay(10);
-
-		LOCK(flags);
-		MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
-		(void)MACIO_IN32(KEYLARGO_FCR2);
-		udelay(10);
-		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xb, 0);
-		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xb);
-		udelay(10);
-		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xa, 0x28);
-		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xa);
-		udelay(10);
-		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xd, 0x28);
-		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xd);
-		udelay(10);
-		MACIO_OUT8(KEYLARGO_GPIO_0+0xd, 0x28);
-		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xd);
-		udelay(10);
-		MACIO_OUT8(KEYLARGO_GPIO_0+0xe, 0x28);
-		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xe);
-		UNLOCK(flags);
-		udelay(10);
-		MACIO_OUT32(0x1c000, 0);
-		mdelay(1);
-		MACIO_OUT8(0x1a3e0, 0x41);
-		(void)MACIO_IN8(0x1a3e0);
-		udelay(10);
-		LOCK(flags);
-		MACIO_BIS(KEYLARGO_FCR2, KL2_CARDSEL_16);
-		(void)MACIO_IN32(KEYLARGO_FCR2);
-		UNLOCK(flags);
-		mdelay(100);
-
-		macio->flags |= MACIO_FLAG_AIRPORT_ON;
-	} else {
-		LOCK(flags);
-		MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
-		(void)MACIO_IN32(KEYLARGO_FCR2);
-		MACIO_OUT8(KL_GPIO_AIRPORT_0, 0);
-		MACIO_OUT8(KL_GPIO_AIRPORT_1, 0);
-		MACIO_OUT8(KL_GPIO_AIRPORT_2, 0);
-		MACIO_OUT8(KL_GPIO_AIRPORT_3, 0);
-		MACIO_OUT8(KL_GPIO_AIRPORT_4, 0);
-		(void)MACIO_IN8(KL_GPIO_AIRPORT_4);
-		UNLOCK(flags);
-
-		macio->flags &= ~MACIO_FLAG_AIRPORT_ON;
-	}
-	return 0;
-}
-
-#ifdef CONFIG_SMP
-static int __pmac
-core99_reset_cpu(struct device_node* node, int param, int value)
-{
-	const int reset_lines[] = {	KL_GPIO_RESET_CPU0,
-					KL_GPIO_RESET_CPU1,
-					KL_GPIO_RESET_CPU2,
-					KL_GPIO_RESET_CPU3 };
-	int reset_io;
-	unsigned long flags;
-	struct macio_chip* macio;
-	
-	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
-		return -ENODEV;
-	if (param > 3 || param < 0)
-		return -ENODEV;
-
-	reset_io = reset_lines[param];
-	
-	LOCK(flags);
-	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
-	(void)MACIO_IN8(reset_io);
-	udelay(1);
-	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
-	(void)MACIO_IN8(reset_io);
-	UNLOCK(flags);
-
-	return 0;
-}
-#endif /* CONFIG_SMP */
-
-static int __pmac
-core99_usb_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip* macio;
-	unsigned long flags;
-	char* prop;
-	int number;
-	u32 reg;
-	
-	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
-		return -ENODEV;
-	
-	prop = (char *)get_property(node, "AAPL,clock-id", NULL);
-	if (!prop)
-		return -ENODEV;
-	if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0)
-		number = 0;
-	else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0)
-		number = 2;
-	else
-		return -ENODEV;
-
-	/* Sorry for the brute-force locking, but this is only used during
-	 * sleep and the timing seem to be critical
-	 */
-	LOCK(flags);
-	if (value) {
-		/* Turn ON */
-		if (number == 0) {
-			MACIO_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
-			(void)MACIO_IN32(KEYLARGO_FCR0);
-			UNLOCK(flags);
-			mdelay(1);
-			LOCK(flags);
-			MACIO_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
-		} else {
-			MACIO_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
-			UNLOCK(flags);
-			(void)MACIO_IN32(KEYLARGO_FCR0);
-			mdelay(1);
-			LOCK(flags);
-			MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
-		}
-		reg = MACIO_IN32(KEYLARGO_FCR4);
-		reg &=	~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
-			KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number));
-		reg &=	~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
-			KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1));
-		MACIO_OUT32(KEYLARGO_FCR4, reg);
-		(void)MACIO_IN32(KEYLARGO_FCR4);
-		udelay(10);
-	} else {
-		/* Turn OFF */
-		reg = MACIO_IN32(KEYLARGO_FCR4);
-		reg |=	KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
-			KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number);
-		reg |=	KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
-			KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1);
-		MACIO_OUT32(KEYLARGO_FCR4, reg);
-		(void)MACIO_IN32(KEYLARGO_FCR4);
-		udelay(1);
-		if (number == 0) {
-			MACIO_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
-			(void)MACIO_IN32(KEYLARGO_FCR0);
-			udelay(1);
-			MACIO_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
-			(void)MACIO_IN32(KEYLARGO_FCR0);
-		} else {
-			MACIO_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
-			(void)MACIO_IN32(KEYLARGO_FCR0);
-			udelay(1);
-			MACIO_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
-			(void)MACIO_IN32(KEYLARGO_FCR0);
-		}
-		udelay(1);
-	}
-	UNLOCK(flags);
-
-	return 0;
-}
-
-static int __pmac
-core99_firewire_enable(struct device_node* node, int param, int value)
-{
-	unsigned long flags;
-	struct macio_chip* macio;
-
-	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
-		return -ENODEV;
-	if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
-		return -ENODEV;
-	
-	LOCK(flags);
-	if (value) {
-		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
-		(void)UN_IN(UNI_N_CLOCK_CNTL);
-	} else {
-		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
-		(void)UN_IN(UNI_N_CLOCK_CNTL);
-	}
-	UNLOCK(flags);
-	mdelay(1);
-
-	return 0;
-}
-
-static int __pmac
-core99_firewire_cable_power(struct device_node* node, int param, int value)
-{
-	unsigned long flags;
-	struct macio_chip* macio;
-
-	/* Trick: we allow NULL node */
-	if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0)
-	    	return -ENODEV;
-	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
-		return -ENODEV;
-	if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
-		return -ENODEV;
-	
-	LOCK(flags);
-	if (value) {
-		MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 0);
-		MACIO_IN8(KL_GPIO_FW_CABLE_POWER);
-		udelay(10);
-	} else {
-		MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 4);
-		MACIO_IN8(KL_GPIO_FW_CABLE_POWER); udelay(10);
-	}
-	UNLOCK(flags);
-	mdelay(1);
-
-	return 0;
-}
-
-static int __pmac
-core99_read_gpio(struct device_node* node, int param, int value)
-{
-	struct macio_chip* macio = &macio_chips[0];
-	
-	return MACIO_IN8(param);
-}
-
-
-static int __pmac
-core99_write_gpio(struct device_node* node, int param, int value)
-{
-	struct macio_chip* macio = &macio_chips[0];
-
-	MACIO_OUT8(param, (u8)(value & 0xff));
-	return 0;
-}
-
-static void __pmac
-keylargo_shutdown(struct macio_chip* macio, int restart)
-{
-	u32 temp;
-
-	mdelay(1);
-	MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
-	(void)MACIO_IN32(KEYLARGO_FCR0);
-	mdelay(100);
-
-	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
-				KL0_SCC_CELL_ENABLE |
-		      		KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE |
-		      		KL0_IRDA_CLK19_ENABLE);
-
-	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
-	MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
-	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
-
-	MACIO_BIC(KEYLARGO_FCR1,
-		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
-		KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
-		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
-		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
-		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
-		KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N |
-		KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N |
-		KL1_UIDE_ENABLE);
-	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
-
-	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
- 	udelay(10);
- 	MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);
- 	udelay(10);
-	temp = MACIO_IN32(KEYLARGO_FCR3);
-	if (macio->rev >= 2)
-		temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL);
-		
-	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
-		KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12;
-	temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
-		| KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE
-		| KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
-	MACIO_OUT32(KEYLARGO_FCR3, temp);
-	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
-}
-
-static void __pmac
-pangea_shutdown(struct macio_chip* macio, int restart)
-{
-	u32 temp;
-
-	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
-				KL0_SCC_CELL_ENABLE |
-				KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE);
-
-	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
-	MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
-	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
-
-	MACIO_BIC(KEYLARGO_FCR1,
-		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
-		KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
-		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
-		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
-		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
-		KL1_UIDE_ENABLE);
-	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
-
-	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
- 	udelay(10);
-	temp = MACIO_IN32(KEYLARGO_FCR3);
-	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
-		KL3_SHUTDOWN_PLLKW35;
-	temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
-		| KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE
-		| KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
-	MACIO_OUT32(KEYLARGO_FCR3, temp);
-	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
-}
-
-static int __pmac
-core99_sleep(void)
-{
-	struct macio_chip* macio;
-	int i;
-
-	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
-		return -ENODEV;
-	
-	/* We power off the wireless slot in case it was not done
-	 * by the driver. We don't power it on automatically however
-	 */
-	if (macio->flags & MACIO_FLAG_AIRPORT_ON)
-		core99_airport_enable(macio->of_node, 0, 0);
-
-	/* We power off the FW cable. Should be done by the driver... */
-	if (macio->flags & MACIO_FLAG_FW_SUPPORTED) {
-		core99_firewire_enable(NULL, 0, 0);
-		core99_firewire_cable_power(NULL, 0, 0);
-	}
-
-	/* We make sure int. modem is off (in case driver lost it) */
-	core99_modem_enable(macio->of_node, 0, 0);
-	/* We make sure the sound is off as well */
-	core99_sound_chip_enable(macio->of_node, 0, 0);
-	 
-	/*
-	 * Save various bits of KeyLargo
-	 */
-
-	/* Save the state of the various GPIOs */
-	save_gpio_levels[0] = MACIO_IN32(KEYLARGO_GPIO_LEVELS0);
-	save_gpio_levels[1] = MACIO_IN32(KEYLARGO_GPIO_LEVELS1);
-	for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
-		save_gpio_extint[i] = MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+i);
-	for (i=0; i<KEYLARGO_GPIO_CNT; i++)
-		save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i);
-
-	/* Save the FCRs */
-	save_mbcr = MACIO_IN32(KEYLARGO_MBCR);
-	save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0);
-	save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1);
-	save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2);
-	save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3);
-	save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4);
-
-	/* Save state & config of DBDMA channels */
-	dbdma_save(macio, save_dbdma);
-	
-	/*
-	 * Turn off as much as we can
-	 */
-	if (macio->type == macio_pangea)
-		pangea_shutdown(macio, 0);
-	else if (macio->type == macio_keylargo)
-		keylargo_shutdown(macio, 0);
-	
-	/* 
-	 * Put the host bridge to sleep
-	 */
-
-	save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL);
-	UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl &
-		~(UNI_N_CLOCK_CNTL_GMAC|UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/));
-	udelay(100);
-	UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
-	UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP);
-
-	/*
-	 * FIXME: A bit of black magic with OpenPIC (don't ask me why)
-	 */
-	if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
-		MACIO_BIS(0x506e0, 0x00400000);
-		MACIO_BIS(0x506e0, 0x80000000);
-	}
-	return 0;
-}
-
-static int __pmac
-core99_wake_up(void)
-{
-	struct macio_chip* macio;
-	int i;
-
-	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
-		return -ENODEV;
-
-	/*
-	 * Wakeup the host bridge
-	 */
-	UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
-	udelay(10);
-	UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
-	udelay(10);
-	
-	/*
-	 * Restore KeyLargo
-	 */
-	 
-	MACIO_OUT32(KEYLARGO_MBCR, save_mbcr);
-	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
-	MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]);
-	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
-	MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]);
-	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
-	MACIO_OUT32(KEYLARGO_FCR2, save_fcr[2]);
-	(void)MACIO_IN32(KEYLARGO_FCR2); udelay(10);
-	MACIO_OUT32(KEYLARGO_FCR3, save_fcr[3]);
-	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
-	MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]);
-	(void)MACIO_IN32(KEYLARGO_FCR4); udelay(10);
-
-	dbdma_restore(macio, save_dbdma);
-
-	MACIO_OUT32(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]);
-	MACIO_OUT32(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]);
-	for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
-		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+i, save_gpio_extint[i]);
-	for (i=0; i<KEYLARGO_GPIO_CNT; i++)
-		MACIO_OUT8(KEYLARGO_GPIO_0+i, save_gpio_normal[i]);
-
-	/* FIXME more black magic with OpenPIC ... */
-	if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
-		MACIO_BIC(0x506e0, 0x00400000);
-		MACIO_BIC(0x506e0, 0x80000000);
-	}
-
-	UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl);
-	udelay(100);
-
-	return 0;
-}
-
-static int __pmac
-core99_sleep_state(struct device_node* node, int param, int value)
-{
-	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
-		return -EPERM;
-	if (value == 1)
-		return core99_sleep();
-	else if (value == 0)
-		return core99_wake_up();
-	return 0;
-}
-
-static int __pmac
-pangea_modem_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	u8			gpio;
-	unsigned long		flags;
-	
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-	gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
-	gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
-	gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
-	
-	if (!value) {
-		LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-		UNLOCK(flags);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-		mdelay(250);
-	}
-    	LOCK(flags);
-	if (value) {
-		MACIO_OUT8(KL_GPIO_MODEM_POWER,
-			KEYLARGO_GPIO_OUTPUT_ENABLE);
-    		UNLOCK(flags);
-	    	(void)MACIO_IN32(KEYLARGO_FCR2);
-		mdelay(250);
-	} else {
-		MACIO_OUT8(KL_GPIO_MODEM_POWER,
-			KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
-    		UNLOCK(flags);
-	}
-	if (value) {
-		LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250);
-	}
-	return 0;
-}
-
-
-static int __pmac
-generic_get_mb_info(struct device_node* node, int param, int value)
-{
-	switch(param) {
-		case PMAC_MB_INFO_MODEL:
-			return pmac_mb.model_id;
-		case PMAC_MB_INFO_FLAGS:
-			return pmac_mb.board_flags;
-		case PMAC_MB_INFO_NAME:	
-			/* hack hack hack... but should work */
-			*((const char **)value) = pmac_mb.model_name;
-			break;
-	}
-	return 0;
-}
-
-
-/* 
- * Table definitions
- */
- 
-/* Used on any machine
- */
-static struct feature_table_entry any_features[]  __pmacdata = {
-	{ PMAC_FTR_GET_MB_INFO,		generic_get_mb_info },
-	{ 0, NULL }
-};
-
-/* OHare based motherboards. Currently, we only use these on the
- * 2400,3400 and 3500 series powerbooks. Some older desktops seem
- * to have issues with turning on/off those asic cells
- */
-static struct feature_table_entry ohare_features[]  __pmacdata = {
-	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
-	{ PMAC_FTR_SWIM3_ENABLE,	ohare_floppy_enable },
-	{ PMAC_FTR_MESH_ENABLE,		ohare_mesh_enable },
-	{ PMAC_FTR_IDE_ENABLE,		ohare_ide_enable},
-	{ PMAC_FTR_IDE_RESET,		ohare_ide_reset},
-	{ PMAC_FTR_SLEEP_STATE,		ohare_sleep_state },
-	{ 0, NULL }
-};
-
-/* Heathrow desktop machines (Beige G3).
- * Separated as some features couldn't be properly tested
- * and the serial port control bits appear to confuse it.
- */
-static struct feature_table_entry heathrow_desktop_features[]  __pmacdata = {
-	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
-	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
-	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
-	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
-	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
-	{ 0, NULL }
-};
-
-/* Heathrow based laptop, that is the Wallstreet and mainstreet
- * powerbooks.
- */
-static struct feature_table_entry heathrow_laptop_features[]  __pmacdata = {
-	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
-	{ PMAC_FTR_MODEM_ENABLE,	heathrow_modem_enable },
-	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
-	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
-	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
-	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
-	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
-	{ PMAC_FTR_SOUND_CHIP_ENABLE,	heathrow_sound_enable },
-	{ PMAC_FTR_SLEEP_STATE,		heathrow_sleep_state },
-	{ 0, NULL }
-};
-
-/* Paddington based machines
- * The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4.
- */
-static struct feature_table_entry paddington_features[]  __pmacdata = {
-	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
-	{ PMAC_FTR_MODEM_ENABLE,	heathrow_modem_enable },
-	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
-	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
-	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
-	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
-	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
-	{ PMAC_FTR_SOUND_CHIP_ENABLE,	heathrow_sound_enable },
-	{ PMAC_FTR_SLEEP_STATE,		heathrow_sleep_state },
-	{ 0, NULL }
-};
-
-/* Core99 & MacRISC 2 machines (all machines released since the
- * iBook (included), that is all AGP machines, except pangea
- * chipset. The pangea chipset is the "combo" UniNorth/KeyLargo
- * used on iBook2 & iMac "flow power".
- */
-static struct feature_table_entry core99_features[]  __pmacdata = {
-	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
-	{ PMAC_FTR_MODEM_ENABLE,	core99_modem_enable },
-	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
-	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
-	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
-	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
-	{ PMAC_FTR_SOUND_CHIP_ENABLE,	core99_sound_chip_enable },
-	{ PMAC_FTR_AIRPORT_ENABLE,	core99_airport_enable },
-	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
-	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
-	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
-	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
-#ifdef CONFIG_SMP
-	{ PMAC_FTR_RESET_CPU,		core99_reset_cpu },
-#endif /* CONFIG_SMP */
-	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
-	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
-	{ 0, NULL }
-};
-
-/* Pangea features
- */
-static struct feature_table_entry pangea_features[]  __pmacdata = {
-	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
-	{ PMAC_FTR_MODEM_ENABLE,	pangea_modem_enable },
-	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
-	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
-	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
-	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
-	{ PMAC_FTR_SOUND_CHIP_ENABLE,	core99_sound_chip_enable },
-	{ PMAC_FTR_AIRPORT_ENABLE,	core99_airport_enable },
-	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
-	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
-	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
-	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
-	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
-	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
-	{ 0, NULL }
-};
-	
-static struct pmac_mb_def pmac_mb_defs[] __pmacdata = {
-	/* Warning: ordering is important as some models may claim
-	 * beeing compatible with several types
-	 */
-	{	"AAPL,8500",			"PowerMac 8500/8600",
-		PMAC_TYPE_PSURGE,		NULL,
-		0
-	},
-	{	"AAPL,9500",			"PowerMac 9500/9600",
-		PMAC_TYPE_PSURGE,		NULL,
-		0
-	},
-	{	"AAPL,7500",			"PowerMac 7500",
-		PMAC_TYPE_PSURGE,		NULL,
-		0
-	},
-	{	"AAPL,ShinerESB",		"Apple Network Server",
-		PMAC_TYPE_ANS,			NULL,
-		0
-	},
-	{	"AAPL,e407",			"Alchemy",
-		PMAC_TYPE_ALCHEMY,		NULL,
-		0
-	},
-	{	"AAPL,e411",			"Gazelle",
-		PMAC_TYPE_GAZELLE,		NULL,
-		0
-	},
-	{	"AAPL,3400/2400",		"PowerBook 3400",
-		PMAC_TYPE_HOOPER,		ohare_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"AAPL,3500",			"PowerBook 3500",
-		PMAC_TYPE_KANGA,		ohare_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"AAPL,Gossamer",		"PowerMac G3 (Gossamer)",
-		PMAC_TYPE_GOSSAMER,		heathrow_desktop_features,
-		0
-	},
-	{	"AAPL,PowerMac G3",		"PowerMac G3 (Silk)",
-		PMAC_TYPE_SILK,			heathrow_desktop_features,
-		0
-	},
-	{	"AAPL,PowerBook1998",		"PowerBook Wallstreet",
-		PMAC_TYPE_WALLSTREET,		heathrow_laptop_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"AAPL,PowerBook1,1",		"PowerBook 101 (Lombard)",
-		PMAC_TYPE_101_PBOOK,		paddington_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"iMac,1",			"iMac (first generation)",
-		PMAC_TYPE_ORIG_IMAC,		paddington_features,
-		0
-	},
-	{	"PowerMac4,1",			"iMac \"Flower Power\"",
-		PMAC_TYPE_PANGEA_IMAC,		pangea_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"PowerBook4,3",			"iBook 2 with 14\" LCD",
-		PMAC_TYPE_IBOOK2,		pangea_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
-	},
-	{	"PowerBook4,2",			"iBook 2 with 14\" LCD",
-		PMAC_TYPE_IBOOK2,		pangea_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
-	},
-	{	"PowerBook4,1",			"iBook 2",
-		PMAC_TYPE_IBOOK2,		pangea_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
-	},
-	{	"PowerMac4,2",			"Flat panel iMac",
-		PMAC_TYPE_FLAT_PANEL_IMAC,	pangea_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"PowerMac1,1",			"Blue&White G3",
-		PMAC_TYPE_YOSEMITE,		paddington_features,
-		0
-	},
-	{	"PowerMac1,2",			"PowerMac G4 PCI Graphics",
-		PMAC_TYPE_YIKES,		paddington_features,
-		0
-	},
-	{	"PowerBook2,1",			"iBook (first generation)",
-		PMAC_TYPE_ORIG_IBOOK,		core99_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"PowerMac3,1",			"PowerMac G4 AGP Graphics",
-		PMAC_TYPE_SAWTOOTH,		core99_features,
-		0
-	},
-	{	"PowerMac3,2",			"PowerMac G4 AGP Graphics",
-		PMAC_TYPE_SAWTOOTH,		core99_features,
-		0
-	},
-	{	"PowerMac3,3",			"PowerMac G4 AGP Graphics",
-		PMAC_TYPE_SAWTOOTH,		core99_features,
-		0
-	},
-	{	"PowerMac2,1",			"iMac FireWire",
-		PMAC_TYPE_FW_IMAC,		core99_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"PowerMac2,2",			"iMac FireWire",
-		PMAC_TYPE_FW_IMAC,		core99_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"PowerBook2,2",			"iBook FireWire",
-		PMAC_TYPE_FW_IBOOK,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
-	},
-	{	"PowerMac5,1",			"PowerMac G4 Cube",
-		PMAC_TYPE_CUBE,			core99_features,
-	},
-	{	"PowerMac3,4",			"PowerMac G4 Silver",
-		PMAC_TYPE_QUICKSILVER,		core99_features,
-		0
-	},
-	{	"PowerMac3,5",			"PowerMac G4 Silver",
-		PMAC_TYPE_QUICKSILVER,		core99_features,
-		0
-	},
-	{	"PowerBook3,1",			"PowerBook Pismo",
-		PMAC_TYPE_PISMO,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
-	},
-	{	"PowerBook3,2",			"PowerBook Titanium",
-		PMAC_TYPE_TITANIUM,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
-	},
-	{	"PowerBook3,3",			"PowerBook Titanium II",
-		PMAC_TYPE_TITANIUM2,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
-	},
-	{	"PowerBook3,4",			"PowerBook Titanium III",
-		PMAC_TYPE_TITANIUM3,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
-	},
-};
-
-/*
- * The toplevel feature_call callback
- */
-int __pmac
-pmac_do_feature_call(unsigned int selector, ...)
-{
-	struct device_node* node;
-	int param, value, i;
-	feature_call func = NULL;
-	va_list args;
-	
-	if (pmac_mb.features)
-		for (i=0; pmac_mb.features[i].function; i++)
-			if (pmac_mb.features[i].selector == selector) {
-				func = pmac_mb.features[i].function;
-				break;
-			}
-	if (!func)
-		for (i=0; any_features[i].function; i++)
-			if (any_features[i].selector == selector) {
-				func = any_features[i].function;
-				break;
-			}
-	if (!func)
-		return -ENODEV;
-
-	va_start(args, selector);
-	node = (struct device_node*)va_arg(args, void*);
-	param = va_arg(args, int);
-	value = va_arg(args, int);
-	va_end(args);
-
-	return func(node, param, value);
-}
-
-static int __init
-probe_motherboard(void)
-{
-	int i;
-	struct macio_chip* macio = &macio_chips[0];
-
-	/* Lookup known motherboard type in device-tree */
-	for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
-	    if (machine_is_compatible(pmac_mb_defs[i].model_string)) {
-		pmac_mb = pmac_mb_defs[i];
-		goto found;
-	    }
-	}
-
-	/* Fallback to selection depending on mac-io chip type */
-	switch(macio->type) {
-	    case macio_grand_central:
-		pmac_mb.model_id = PMAC_TYPE_PSURGE;
-		pmac_mb.model_name = "Unknown PowerSurge";
-		break;
-	    case macio_ohare:
-		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_OHARE;
-		pmac_mb.model_name = "Unknown OHare-based";
-	    	break;
-	    case macio_heathrow:
-		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_HEATHROW;
-		pmac_mb.model_name = "Unknown Heathrow-based";
-		pmac_mb.features = heathrow_desktop_features;
-		break;
-	    case macio_paddington:
-		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PADDINGTON;
-		pmac_mb.model_name = "Unknown Paddington-based";
-	    	pmac_mb.features = paddington_features;
-		break;
-	    case macio_keylargo:
-		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_CORE99;
-		pmac_mb.model_name = "Unknown Keylargo-based";
-	    	pmac_mb.features = core99_features;
-		break;
-	    case macio_pangea:
-		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA;
-		pmac_mb.model_name = "Unknown Pangea-based";
-	    	pmac_mb.features = pangea_features;
-		break;
-	    default:
-	    	return -ENODEV;
-	}
-found:
-	/* Fixup Hooper vs. Comet */
-	if (pmac_mb.model_id == PMAC_TYPE_HOOPER) {
-		u32* mach_id_ptr = (u32*)ioremap(0xf3000034, 4);
-		if (!mach_id_ptr)
-			return -ENODEV;
-		/* Here, I used to disable the media-bay on comet. It
-		 * appears this is wrong, the floppy connector is actually
-		 * a kind of media-bay and works with the current driver.
-		 */
-		if ((*mach_id_ptr) & 0x20000000UL)
-			pmac_mb.model_id = PMAC_TYPE_COMET;
-		iounmap(mach_id_ptr);
-	}
-
-	/* Set default value of powersave_nap on machines that support it.
-	 * It appears that uninorth rev 3 has a problem with it, we don't
-	 * enable it on those. In theory, the flush-on-lock property is
-	 * supposed to be set when not supported, but I'm not very confident
-	 * that all Apple OF revs did it properly, I do it the paranoid way.
-	 */
-	while (uninorth_base && uninorth_rev > 3) {
-		struct device_node* np = find_path_device("/cpus");
-		u32 pvr = mfspr(PVR);
-		if (!np || !np->child) {
-			printk(KERN_WARNING "Can't find CPU(s) in device tree !\n");
-			break;
-		}
-		np = np->child;
-		/* Nap mode not supported on SMP */
-		if (np->sibling)
-			break;
-		/* Nap mode not supported if flush-on-lock property is present */
-		if (get_property(np, "flush-on-lock", NULL))
-			break;
-		/* Some 7450 may have problem with NAP mode too ... */
-		if (((pvr >> 16) == 0x8000) && ((pvr & 0xffff) < 0x0201))
-			break;
-		powersave_nap = 1;
-		printk(KERN_INFO "Processor NAP mode on idle enabled.\n");
-		break;
-	}
-
-	printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
-	return 0;
-}
-
-/* Initialize the Core99 UniNorth host bridge and memory controller
- */
-static void __init
-probe_uninorth(void)
-{
-	unsigned long actrl;
-	
-	/* Locate core99 Uni-N */
-	uninorth_node = find_devices("uni-n");
-	if (uninorth_node && uninorth_node->n_addrs > 0) {
-		uninorth_base = ioremap(uninorth_node->addrs[0].address, 0x1000);
-		uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
-	} else
-		uninorth_node = NULL;
-		
-	if (!uninorth_node)
-		return;
-	
-	printk(KERN_INFO "Found Uninorth memory controller & host bridge, revision: %d\n",
-			uninorth_rev);
-
-	/* Set the arbitrer QAck delay according to what Apple does
-	 */
-	if (uninorth_rev < 0x10) {
-		actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK;
-		actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 :
-			UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
-		UN_OUT(UNI_N_ARB_CTRL, actrl);
-	}
-}	
-
-static void __init
-probe_one_macio(const char* name, const char* compat, int type)
-{
-	struct device_node*	node;
-	int			i;
-	volatile u32*		base;
-	u32*			revp;
-	
-	node = find_devices(name);
-	if (!node || !node->n_addrs)
-		return;
-	if (compat)
-		do {
-			if (device_is_compatible(node, compat))
-				break;
-			node = node->next;
-		} while (node);
-	if (!node)
-		return;
-	for(i=0; i<MAX_MACIO_CHIPS; i++) {
-		if (!macio_chips[i].of_node)
-			break;
-		if (macio_chips[i].of_node == node)
-			return;
-	}
-	if (i >= MAX_MACIO_CHIPS) {
-		printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");
-		printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
-		return;
-	}
-	base = (volatile u32*)ioremap(node->addrs[0].address, node->addrs[0].size);
-	if (!base) {
-		printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n");
-		return;
-	}
-	if (type == macio_keylargo) {
-		u32* did = (u32 *)get_property(node, "device-id", NULL);
-		if (*did == 0x00000025)
-			type = macio_pangea;
-	}
-	macio_chips[i].of_node	= node;
-	macio_chips[i].type	= type;
-	macio_chips[i].base	= base;
-	macio_chips[i].flags	= MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON;
-	revp = (u32 *)get_property(node, "revision-id", NULL);
-	if (revp)
-		macio_chips[i].rev = *revp;
-	printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n",
-		macio_names[type], macio_chips[i].rev, macio_chips[i].base);
-}
-
-static int __init
-probe_macios(void)
-{
-	/* Warning, ordering is important */
-	probe_one_macio("gc", NULL, macio_grand_central);
-	probe_one_macio("ohare", NULL, macio_ohare);
-	probe_one_macio("pci106b,7", NULL, macio_ohareII);
-	probe_one_macio("mac-io", "keylargo", macio_keylargo);
-	probe_one_macio("mac-io", "paddington", macio_paddington);
-	probe_one_macio("mac-io", "gatwick", macio_gatwick);
-	probe_one_macio("mac-io", "heathrow", macio_heathrow);
-
-	/* Make sure the "main" macio chip appear first */
-	if (macio_chips[0].type == macio_gatwick
-	    && macio_chips[1].type == macio_heathrow) {
-		struct macio_chip temp = macio_chips[0];
-		macio_chips[0] = macio_chips[1];
-		macio_chips[1] = temp;
-	}
-	if (macio_chips[0].type == macio_ohareII
-	    && macio_chips[1].type == macio_ohare) {
-		struct macio_chip temp = macio_chips[0];
-		macio_chips[0] = macio_chips[1];
-		macio_chips[1] = temp;
-	}
-
-	return (macio_chips[0].of_node == NULL) ? -ENODEV : 0;
-}
-
-static void __init
-initial_serial_shutdown(struct device_node* np)
-{
-	int len;
-	struct slot_names_prop {
-		int	count;
-		char	name[1];
-	} *slots;
-	char *conn;
-	int port_type = PMAC_SCC_ASYNC;
-	int modem = 0;
-	
-	slots = (struct slot_names_prop *)get_property(np, "slot-names", &len);
-	conn = get_property(np, "AAPL,connector", &len);
-	if (conn && (strcmp(conn, "infrared") == 0))
-		port_type = PMAC_SCC_IRDA;
-	else if (device_is_compatible(np, "cobalt"))
-		modem = 1;
-	else if (slots && slots->count > 0) {
-		if (strcmp(slots->name, "IrDA") == 0)
-			port_type = PMAC_SCC_IRDA;
-		else if (strcmp(slots->name, "Modem") == 0)
-			modem = 1;
-	}
-	if (modem)
-		pmac_call_feature(PMAC_FTR_MODEM_ENABLE, np, 0, 0);
-	pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, port_type, 0);
-}
-
-static void __init
-set_initial_features(void)
-{
-	struct device_node* np;
-	
-	/* That hack appears to be necessary for some StarMax motherboards
-	 * but I'm not too sure it was audited for side-effects on other
-	 * ohare based machines...
-	 * Since I still have difficulties figuring the right way to
-	 * differenciate them all and since that hack was there for a long
-	 * time, I'll keep it around
-	 */
-	if (macio_chips[0].type == macio_ohare && !find_devices("via-pmu")) {
-		struct macio_chip* macio = &macio_chips[0];
-		MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);
-	} else if (macio_chips[0].type == macio_ohare) {
-		struct macio_chip* macio = &macio_chips[0];
-		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
-	} else if (macio_chips[1].type == macio_ohare) {
-		struct macio_chip* macio = &macio_chips[1];
-		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
-	}
-
-	if (macio_chips[0].type == macio_keylargo ||
-	    macio_chips[0].type == macio_pangea) {
-		/* Enable GMAC for now for PCI probing. It will be disabled
-		 * later on after PCI probe
-		 */
-		np = find_devices("ethernet");
-		while(np) {
-			if (np->parent
-			    && device_is_compatible(np->parent, "uni-north")
-			    && device_is_compatible(np, "gmac"))
-				core99_gmac_enable(np, 0, 1);
-			np = np->next;
-		}
-
-		/* Enable FW before PCI probe. Will be disabled later on
-		 * Note: We should have a batter way to check that we are
-		 * dealing with uninorth internal cell and not a PCI cell
-		 * on the external PCI. The code below works though.
-		 */
-		np = find_devices("firewire");
-		while(np) {
-			if (np->parent
-			    && device_is_compatible(np->parent, "uni-north")
-			    && (device_is_compatible(np, "pci106b,18") || 
-	     		        device_is_compatible(np, "pci106b,30") ||
-	     		        device_is_compatible(np, "pci11c1,5811"))) {
-				macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
-				core99_firewire_enable(np, 0, 1);
-			}
-			np = np->next;
-		}
-		
-		/* Switch airport off */
-		np = find_devices("radio");
-		while(np) {
-			if (np && np->parent == macio_chips[0].of_node) {
-				macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON;
-				core99_airport_enable(np, 0, 0);
-			}
-			np = np->next;
-		}
-	}
-
-	/* On all machines that support sound PM, switch sound off */
-	if (macio_chips[0].of_node)
-		pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE,
-			macio_chips[0].of_node, 0, 0);
-
-	/* While on some desktop G3s, we turn it back on */
-	if (macio_chips[0].of_node && macio_chips[0].type == macio_heathrow
-		&& (pmac_mb.model_id == PMAC_TYPE_GOSSAMER ||
-		    pmac_mb.model_id == PMAC_TYPE_SILK)) {
-		struct macio_chip* macio = &macio_chips[0];
-		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
-	}
-
-
-	/* On all machines, switch modem & serial ports off */
-	np = find_devices("ch-a");
-	while(np) {
-		initial_serial_shutdown(np);
-		np = np->next;
-	}
-	np = find_devices("ch-b");
-	while(np) {
-		initial_serial_shutdown(np);
-		np = np->next;
-	}
-	
-	/* Let hardware settle down */
-	mdelay(10);
-}
-
-void __init
-pmac_feature_init(void)
-{
-	/* Detect the UniNorth memory controller */
-	probe_uninorth();
-
-	/* Probe mac-io controllers */
-	if (probe_macios()) {
-		printk(KERN_WARNING "No mac-io chip found\n");
-		return;
-	}
-
-	/* Probe machine type */
-	if (probe_motherboard())
-		printk(KERN_WARNING "Unknown PowerMac !\n");
-
-	/* Set some initial features (turn off some chips that will
-	 * be later turned on)
-	 */
-	set_initial_features();
-}
-
-void __init
-pmac_feature_late_init(void)
-{
-	struct device_node* np;
-	
-	/* Request some resources late */
-	if (uninorth_node)
-		request_OF_resource(uninorth_node, 0, NULL);
-	np = find_devices("hammerhead");
-	if (np)
-		request_OF_resource(np, 0, NULL);
-	np = find_devices("interrupt-controller");
-	if (np)
-		request_OF_resource(np, 0, NULL);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/pmac_nvram.c linux-2.4.20/arch/ppc/kernel/pmac_nvram.c
--- linux-2.4.19/arch/ppc/kernel/pmac_nvram.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/pmac_nvram.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,402 +0,0 @@
-/*
- * BK Id: SCCS/s.pmac_nvram.c 1.17 12/01/01 20:09:06 benh
- */
-/*
- * Miscellaneous procedures for dealing with the PowerMac hardware.
- */
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/nvram.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/nvram.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-
-#undef DEBUG
-
-#define NVRAM_SIZE		0x2000	/* 8kB of non-volatile RAM */
-
-#define CORE99_SIGNATURE	0x5a
-#define CORE99_ADLER_START	0x14
-
-/* Core99 nvram is a flash */
-#define CORE99_FLASH_STATUS_DONE	0x80
-#define CORE99_FLASH_STATUS_ERR		0x38
-#define CORE99_FLASH_CMD_ERASE_CONFIRM	0xd0
-#define CORE99_FLASH_CMD_ERASE_SETUP	0x20
-#define CORE99_FLASH_CMD_RESET		0xff
-#define CORE99_FLASH_CMD_WRITE_SETUP	0x40
-
-/* CHRP NVRAM header */
-struct chrp_header {
-  u8		signature;
-  u8		cksum;
-  u16		len;
-  char          name[12];
-  u8		data[0];
-};
-
-struct core99_header {
-  struct chrp_header	hdr;
-  u32			adler;
-  u32			generation;
-  u32			reserved[2];
-};
-
-/*
- * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
- */
-static int nvram_naddrs;
-static volatile unsigned char *nvram_addr;
-static volatile unsigned char *nvram_data;
-static int nvram_mult, is_core_99;
-static int core99_bank = 0;
-static int nvram_partitions[3];
-
-/* FIXME: kmalloc fails to allocate the image now that I had to move it
- *        before time_init(). For now, I allocate a static buffer here
- *        but it's a waste of space on all but core99 machines
- */
-#if 0
-static char* nvram_image;
-#else
-static char nvram_image[NVRAM_SIZE] __pmacdata;
-#endif
-
-extern int pmac_newworld;
-
-static u8 __openfirmware
-chrp_checksum(struct chrp_header* hdr)
-{
-	u8 *ptr;
-	u16 sum = hdr->signature;
-	for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
-		sum += *ptr;
-	while (sum > 0xFF)
-		sum = (sum & 0xFF) + (sum>>8);
-	return sum;
-}
-
-static u32 __pmac
-core99_calc_adler(u8 *buffer)
-{
-	int cnt;
-	u32 low, high;
-
-   	buffer += CORE99_ADLER_START;
-	low = 1;
-	high = 0;
-	for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
-		if ((cnt % 5000) == 0) {
-			high  %= 65521UL;
-			high %= 65521UL;
-		}
-		low += buffer[cnt];
-		high += low;
-	}
-	low  %= 65521UL;
-	high %= 65521UL;
-  
-	return (high << 16) | low;
-}
-
-static u32 __pmac
-core99_check(u8* datas)
-{
-	struct core99_header* hdr99 = (struct core99_header*)datas;
-
-	if (hdr99->hdr.signature != CORE99_SIGNATURE) {
-#ifdef DEBUG
-		printk("Invalid signature\n");
-#endif		
-		return 0;
-	}
-	if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
-#ifdef DEBUG
-		printk("Invalid checksum\n");
-#endif
-		return 0;
-	}
-	if (hdr99->adler != core99_calc_adler(datas)) {
-#ifdef DEBUG
-		printk("Invalid adler\n");
-#endif
-		return 0;
-	}
-	return hdr99->generation;
-}
-
-static int __pmac
-core99_erase_bank(int bank)
-{
-	int stat, i;
-	
-	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
-	
-	out_8(base, CORE99_FLASH_CMD_ERASE_SETUP);
-	out_8(base, CORE99_FLASH_CMD_ERASE_CONFIRM);
-	do { stat = in_8(base); }
-	while(!(stat & CORE99_FLASH_STATUS_DONE));
-	out_8(base, CORE99_FLASH_CMD_RESET);
-	if (stat & CORE99_FLASH_STATUS_ERR) {
-		printk("nvram: flash error 0x%02x on erase !\n", stat);
-		return -ENXIO;
-	}
-	for (i=0; i<NVRAM_SIZE; i++)
-		if (base[i] != 0xff) {
-			printk("nvram: flash erase failed !\n");
-			return -ENXIO;
-		}
-	return 0;
-}
-
-static int __pmac
-core99_write_bank(int bank, u8* datas)
-{
-	int i, stat = 0;
-	
-	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
-	
-	for (i=0; i<NVRAM_SIZE; i++) {
-		out_8(base+i, CORE99_FLASH_CMD_WRITE_SETUP);
-		out_8(base+i, datas[i]);
-		do { stat = in_8(base); }
-		while(!(stat & CORE99_FLASH_STATUS_DONE));
-		if (stat & CORE99_FLASH_STATUS_ERR)
-			break;
-	}
-	out_8(base, CORE99_FLASH_CMD_RESET);
-	if (stat & CORE99_FLASH_STATUS_ERR) {
-		printk("nvram: flash error 0x%02x on write !\n", stat);
-		return -ENXIO;
-	}
-	for (i=0; i<NVRAM_SIZE; i++)
-		if (base[i] != datas[i]) {
-			printk("nvram: flash write failed !\n");
-			return -ENXIO;
-		}
-	return 0;	
-}
-
-static void __init
-lookup_partitions(void)
-{
-	u8 buffer[17];
-	int i, offset;
-	struct chrp_header* hdr;
-
-	if (pmac_newworld) {
-		nvram_partitions[pmac_nvram_OF] = -1;
-		nvram_partitions[pmac_nvram_XPRAM] = -1;
-		nvram_partitions[pmac_nvram_NR] = -1;
-		hdr = (struct chrp_header *)buffer;
-	
-		offset = 0;
-		buffer[16] = 0;
-		do {
-			for (i=0;i<16;i++)
-				buffer[i] = nvram_read_byte(offset+i);
-			if (!strcmp(hdr->name, "common"))
-				nvram_partitions[pmac_nvram_OF] = offset + 0x10;
-			if (!strcmp(hdr->name, "APL,MacOS75")) {
-				nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10;
-				nvram_partitions[pmac_nvram_NR] = offset + 0x110;
-			}
-			offset += (hdr->len * 0x10);
-		} while(offset < NVRAM_SIZE);
-	} else {
-		nvram_partitions[pmac_nvram_OF] = 0x1800;
-		nvram_partitions[pmac_nvram_XPRAM] = 0x1300;
-		nvram_partitions[pmac_nvram_NR] = 0x1400;
-	}	
-#ifdef DEBUG
-	printk("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]);
-	printk("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]);
-	printk("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]);
-#endif	
-}
-
-void __init
-pmac_nvram_init(void)
-{
-	struct device_node *dp;
-
-	nvram_naddrs = 0;
-
-	dp = find_devices("nvram");
-	if (dp == NULL) {
-		printk(KERN_ERR "Can't find NVRAM device\n");
-		return;
-	}
-	nvram_naddrs = dp->n_addrs;
-	is_core_99 = device_is_compatible(dp, "nvram,flash");
-	if (is_core_99) {
-		int i;
-		u32 gen_bank0, gen_bank1;
-		
-		if (nvram_naddrs < 1) {
-			printk(KERN_ERR "nvram: no address\n");
-			return;
-		}
-#if 0
-		nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL);
-		if (!nvram_image) {
-			printk(KERN_ERR "nvram: can't allocate image\n");
-			return;
-		}
-#endif
-		nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
-#ifdef DEBUG
-		printk("nvram: Checking bank 0...\n");
-#endif
-		gen_bank0 = core99_check((u8 *)nvram_data);
-		gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
-		core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
-#ifdef DEBUG
-		printk("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
-		printk("nvram: Active bank is: %d\n", core99_bank);
-#endif
-		for (i=0; i<NVRAM_SIZE; i++)
-			nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
-	} else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
-		nvram_data = ioremap(dp->addrs[0].address + isa_mem_base,
-				     dp->addrs[0].size);
-		nvram_mult = 1;
-	} else if (nvram_naddrs == 1) {
-		nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-		nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
-	} else if (nvram_naddrs == 2) {
-		nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-		nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
-	} else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
-		nvram_naddrs = -1;
-	} else {
-		printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
-		       nvram_naddrs);
-	}
-	lookup_partitions();
-}
-
-void __pmac
-pmac_nvram_update(void)
-{
-	struct core99_header* hdr99;
-	
-	if (!is_core_99 || !nvram_data || !nvram_image)
-		return;
-	if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
-		NVRAM_SIZE))
-		return;
-#ifdef DEBUG
-	printk("Updating nvram...\n");
-#endif
-	hdr99 = (struct core99_header*)nvram_image;
-	hdr99->generation++;
-	hdr99->hdr.signature = CORE99_SIGNATURE;
-	hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
-	hdr99->adler = core99_calc_adler(nvram_image);
-	core99_bank = core99_bank ? 0 : 1;
-	if (core99_erase_bank(core99_bank)) {
-		printk("nvram: Error erasing bank %d\n", core99_bank);
-		return;
-	}
-	if (core99_write_bank(core99_bank, nvram_image))
-		printk("nvram: Error writing bank %d\n", core99_bank);
-}
-
-unsigned char __openfirmware
-nvram_read_byte(int addr)
-{
-	switch (nvram_naddrs) {
-#ifdef CONFIG_ADB_PMU
-	case -1: {
-		struct adb_request req;
-
-		if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM,
-				(addr >> 8) & 0xff, addr & 0xff))
-			break;
-		while (!req.complete)
-			pmu_poll();
-		return req.reply[0];
-	}
-#endif
-	case 1:
-		if (is_core_99)
-			return nvram_image[addr];
-		return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
-	case 2:
-		*nvram_addr = addr >> 5;
-		eieio();
-		return nvram_data[(addr & 0x1f) << 4];
-	}
-	return 0;
-}
-
-void __openfirmware
-nvram_write_byte(unsigned char val, int addr)
-{
-	switch (nvram_naddrs) {
-#ifdef CONFIG_ADB_PMU
-	case -1: {
-		struct adb_request req;
-
-		if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM,
-				(addr >> 8) & 0xff, addr & 0xff, val))
-			break;
-		while (!req.complete)
-			pmu_poll();
-		break;
-	}
-#endif
-	case 1:
-		if (is_core_99) {
-			nvram_image[addr] = val;
-			break;
-		}
-		nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
-		break;
-	case 2:
-		*nvram_addr = addr >> 5;
-		eieio();
-		nvram_data[(addr & 0x1f) << 4] = val;
-		break;
-	}
-	eieio();
-}
-
-int __pmac
-pmac_get_partition(int partition)
-{
-	return nvram_partitions[partition];
-}
-
-u8 __pmac
-pmac_xpram_read(int xpaddr)
-{
-	int offset = nvram_partitions[pmac_nvram_XPRAM];
-	
-	if (offset < 0)
-		return 0;
-		
-	return nvram_read_byte(xpaddr + offset);
-}
-
-void __pmac
-pmac_xpram_write(int xpaddr, u8 data)
-{
-	int offset = nvram_partitions[pmac_nvram_XPRAM];
-	
-	if (offset < 0)
-		return;
-		
-	nvram_write_byte(xpaddr + offset, data);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/pmac_pci.c linux-2.4.20/arch/ppc/kernel/pmac_pci.c
--- linux-2.4.19/arch/ppc/kernel/pmac_pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/pmac_pci.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,615 +0,0 @@
-/*
- * BK Id: SCCS/s.pmac_pci.c 1.35 05/06/02 01:37:30 benh
- */
-/*
- * Support for PCI bridges found on Power Macintoshes.
- * At present the "bandit" and "chaos" bridges are supported.
- * Fortunately you access configuration space in the same
- * way with either bridge.
- *
- * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au)
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-
-#include "pci.h"
-
-#undef DEBUG
-
-static void add_bridges(struct device_node *dev);
-
-/* XXX Could be per-controller, but I don't think we risk anything by
- * assuming we won't have both UniNorth and Bandit */
-static int has_uninorth;
-
-/*
- * Magic constants for enabling cache coherency in the bandit/PSX bridge.
- */
-#define BANDIT_DEVID_2	8
-#define BANDIT_REVID	3
-
-#define BANDIT_DEVNUM	11
-#define BANDIT_MAGIC	0x50
-#define BANDIT_COHERENT	0x40
-
-static int __init
-fixup_one_level_bus_range(struct device_node *node, int higher)
-{
-	for (; node != 0;node = node->sibling) {
-		int * bus_range;
-		unsigned int *class_code;			
-		int len;
-
-		/* For PCI<->PCI bridges or CardBus bridges, we go down */
-		class_code = (unsigned int *) get_property(node, "class-code", 0);
-		if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
-			(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
-			continue;
-		bus_range = (int *) get_property(node, "bus-range", &len);
-		if (bus_range != NULL && len > 2 * sizeof(int)) {
-			if (bus_range[1] > higher)
-				higher = bus_range[1];
-		}
-		higher = fixup_one_level_bus_range(node->child, higher);
-	}
-	return higher;
-}
-
-/* This routine fixes the "bus-range" property of all bridges in the
- * system since they tend to have their "last" member wrong on macs
- * 
- * Note that the bus numbers manipulated here are OF bus numbers, they
- * are not Linux bus numbers.
- */
-static void __init
-fixup_bus_range(struct device_node *bridge)
-{
-	int * bus_range;
-	int len;
-	
-	/* Lookup the "bus-range" property for the hose */		
-	bus_range = (int *) get_property(bridge, "bus-range", &len);
-	if (bus_range == NULL || len < 2 * sizeof(int)) {
-		printk(KERN_WARNING "Can't get bus-range for %s\n",
-			       bridge->full_name);
-		return;
-	}
-	bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
-}
-
-/*
- * Apple MacRISC (UniNorth, Bandit, Chaos) PCI controllers.
- * 
- * The "Bandit" version is present in all early PCI PowerMacs,
- * and up to the first ones using Grackle. Some machines may
- * have 2 bandit controllers (2 PCI busses).
- * 
- * "Chaos" is used in some "Bandit"-type machines as a bridge
- * for the separate display bus. It is accessed the same
- * way as bandit, but cannot be probed for devices. It therefore
- * has its own config access functions.
- *
- * The "UniNorth" version is present in all Core99 machines
- * (iBook, G4, new IMacs, and all the recent Apple machines).
- * It contains 3 controllers in one ASIC.
- */
-
-#define MACRISC_CFA0(devfn, off)	\
-	((1 << (unsigned long)PCI_SLOT(dev_fn)) \
-	| (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
-	| (((unsigned long)(off)) & 0xFCUL))
-
-#define MACRISC_CFA1(bus, devfn, off)	\
-	((((unsigned long)(bus)) << 16) \
-	|(((unsigned long)(devfn)) << 8) \
-	|(((unsigned long)(off)) & 0xFCUL) \
-	|1UL)
-	
-static unsigned int __pmac
-macrisc_cfg_access(struct pci_controller* hose, u8 bus, u8 dev_fn, u8 offset)
-{
-	unsigned int caddr;
-	
-	if (bus == hose->first_busno) {
-		if (dev_fn < (11 << 3))
-			return 0;
-		caddr = MACRISC_CFA0(dev_fn, offset);
-	} else
-		caddr = MACRISC_CFA1(bus, dev_fn, offset);
-	
-	/* Uninorth will return garbage if we don't read back the value ! */
-	do {
-		out_le32(hose->cfg_addr, caddr);
-	} while(in_le32(hose->cfg_addr) != caddr);
-
-	offset &= has_uninorth ? 0x07 : 0x03;
-	return (unsigned int)(hose->cfg_data) + (unsigned int)offset;
-}
-
-#define cfg_read(val, addr, type, op, op2)	\
-	*val = op((type)(addr))
-#define cfg_write(val, addr, type, op, op2)	\
-	op((type *)(addr), (val)); (void) op2((type *)(addr))
-
-#define cfg_read_bad(val, size)		*val = bad_##size;
-#define cfg_write_bad(val, size)
-
-#define bad_byte	0xff
-#define bad_word	0xffff
-#define bad_dword	0xffffffffU
-
-#define MACRISC_PCI_OP(rw, size, type, op, op2)				    \
-static int __pmac							    \
-macrisc_##rw##_config_##size(struct pci_dev *dev, int off, type val)	    \
-{									    \
-	struct pci_controller *hose = dev->sysdata;			    \
-	unsigned int addr;						    \
-									    \
-	addr = macrisc_cfg_access(hose, dev->bus->number, dev->devfn, off); \
-	if (!addr) {							    \
-		cfg_##rw##_bad(val, size)				    \
-		return PCIBIOS_DEVICE_NOT_FOUND;			    \
-	}								    \
-	cfg_##rw(val, addr, type, op, op2);				    \
-	return PCIBIOS_SUCCESSFUL;					    \
-}
-
-MACRISC_PCI_OP(read, byte, u8 *, in_8, x)
-MACRISC_PCI_OP(read, word, u16 *, in_le16, x)
-MACRISC_PCI_OP(read, dword, u32 *, in_le32, x)
-MACRISC_PCI_OP(write, byte, u8, out_8, in_8)
-MACRISC_PCI_OP(write, word, u16, out_le16, in_le16)
-MACRISC_PCI_OP(write, dword, u32, out_le32, in_le32)
-
-static struct pci_ops macrisc_pci_ops =
-{
-	macrisc_read_config_byte,
-	macrisc_read_config_word,
-	macrisc_read_config_dword,
-	macrisc_write_config_byte,
-	macrisc_write_config_word,
-	macrisc_write_config_dword
-};
-
-/*
- * Verifiy that a specific (bus, dev_fn) exists on chaos
- */
-static int __pmac
-chaos_validate_dev(struct pci_dev *dev, int offset)
-{
-	if(pci_device_to_OF_node(dev) == 0)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	if((dev->vendor == 0x106b) && (dev->device == 3) && (offset >= 0x10) &&
-	    (offset != 0x14) && (offset != 0x18) && (offset <= 0x24)) {
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-#define CHAOS_PCI_OP(rw, size, type)					\
-static int __pmac							\
-chaos_##rw##_config_##size(struct pci_dev *dev, int off, type val)	\
-{									\
-	int result = chaos_validate_dev(dev, off);			\
-	if(result == PCIBIOS_BAD_REGISTER_NUMBER) {			\
-		cfg_##rw##_bad(val, size)				\
-		return PCIBIOS_BAD_REGISTER_NUMBER;			\
-	}								\
-	if(result == PCIBIOS_SUCCESSFUL)				\
-		return macrisc_##rw##_config_##size(dev, off, val);	\
-	return result;							\
-}
-
-CHAOS_PCI_OP(read, byte, u8 *)
-CHAOS_PCI_OP(read, word, u16 *)
-CHAOS_PCI_OP(read, dword, u32 *)
-CHAOS_PCI_OP(write, byte, u8)
-CHAOS_PCI_OP(write, word, u16)
-CHAOS_PCI_OP(write, dword, u32) 
-
-static struct pci_ops chaos_pci_ops =
-{
-	chaos_read_config_byte,
-	chaos_read_config_word,
-	chaos_read_config_dword,
-	chaos_write_config_byte,
-	chaos_write_config_word,
-	chaos_write_config_dword
-};
-
-
-/*
- * For a bandit bridge, turn on cache coherency if necessary.
- * N.B. we could clean this up using the hose ops directly.
- */
-static void __init
-init_bandit(struct pci_controller *bp)
-{
-	unsigned int vendev, magic;
-	int rev;
-
-	/* read the word at offset 0 in config space for device 11 */
-	out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
-	udelay(2);
-	vendev = in_le32((volatile unsigned int *)bp->cfg_data);
-	if (vendev == (PCI_DEVICE_ID_APPLE_BANDIT << 16) + 
-			PCI_VENDOR_ID_APPLE) {
-		/* read the revision id */
-		out_le32(bp->cfg_addr,
-			 (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
-		udelay(2);
-		rev = in_8(bp->cfg_data);
-		if (rev != BANDIT_REVID)
-			printk(KERN_WARNING
-			       "Unknown revision %d for bandit\n", rev);
-	} else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) {
-		printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
-		return;
-	}
-
-	/* read the word at offset 0x50 */
-	out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
-	udelay(2);
-	magic = in_le32((volatile unsigned int *)bp->cfg_data);
-	if ((magic & BANDIT_COHERENT) != 0)
-		return;
-	magic |= BANDIT_COHERENT;
-	udelay(2);
-	out_le32((volatile unsigned int *)bp->cfg_data, magic);
-	printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n");
-}
-
-
-/*
- * Tweak the PCI-PCI bridge chip on the blue & white G3s.
- */
-static void __init
-init_p2pbridge(void)
-{
-	struct device_node *p2pbridge;
-	struct pci_controller* hose;
-	u8 bus, devfn;
-	u16 val;
-
-	/* XXX it would be better here to identify the specific
-	   PCI-PCI bridge chip we have. */
-	if ((p2pbridge = find_devices("pci-bridge")) == 0
-	    || p2pbridge->parent == NULL
-	    || strcmp(p2pbridge->parent->name, "pci") != 0)
-		return;
-	if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) {
-#ifdef DEBUG
-		printk("Can't find PCI infos for PCI<->PCI bridge\n");
-#endif		
-		return;
-	}
-	/* Warning: At this point, we have not yet renumbered all busses. 
-	 * So we must use OF walking to find out hose
-	 */
-	hose = pci_find_hose_for_OF_device(p2pbridge);
-	if (!hose) {
-#ifdef DEBUG
-		printk("Can't find hose for PCI<->PCI bridge\n");
-#endif		
-		return;
-	}
-	if (early_read_config_word(hose, bus, devfn,
-				   PCI_BRIDGE_CONTROL, &val) < 0) {
-		printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n");
-		return;
-	}
-	val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
-	early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);
-}
-
-void __init
-pmac_find_bridges(void)
-{
-	add_bridges(find_devices("bandit"));
-	add_bridges(find_devices("chaos"));
-	add_bridges(find_devices("pci"));
-	init_p2pbridge();
-}
-
-#define GRACKLE_CFA(b, d, o)	(0x80 | ((b) << 8) | ((d) << 16) \
-				 | (((o) & ~3) << 24))
-
-#define GRACKLE_PICR1_STG		0x00000040
-#define GRACKLE_PICR1_LOOPSNOOP		0x00000010
-
-/* N.B. this is called before bridges is initialized, so we can't
-   use grackle_pcibios_{read,write}_config_dword. */
-static inline void grackle_set_stg(struct pci_controller* bp, int enable)
-{
-	unsigned int val;
-
-	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
-	val = in_le32((volatile unsigned int *)bp->cfg_data);
-	val = enable? (val | GRACKLE_PICR1_STG) :
-		(val & ~GRACKLE_PICR1_STG);
-	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
-	out_le32((volatile unsigned int *)bp->cfg_data, val);
-	(void)in_le32((volatile unsigned int *)bp->cfg_data);
-}
-
-static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable)
-{
-	unsigned int val;
-
-	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
-	val = in_le32((volatile unsigned int *)bp->cfg_data);
-	val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) :
-		(val & ~GRACKLE_PICR1_LOOPSNOOP);
-	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
-	out_le32((volatile unsigned int *)bp->cfg_data, val);
-	(void)in_le32((volatile unsigned int *)bp->cfg_data);
-}
-
-static int __init
-setup_uninorth(struct pci_controller* hose, struct reg_property* addr)
-{
-	pci_assign_all_busses = 1;
-	has_uninorth = 1;
-	hose->ops = &macrisc_pci_ops;
-	hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
-	hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
-	/* We "know" that the bridge at f2000000 has the PCI slots. */
-	return addr->address == 0xf2000000;
-}
-
-static void __init
-setup_bandit(struct pci_controller* hose, struct reg_property* addr)
-{
-	hose->ops = &macrisc_pci_ops;
-	hose->cfg_addr = (volatile unsigned int *)
-		ioremap(addr->address + 0x800000, 0x1000);
-	hose->cfg_data = (volatile unsigned char *)
-		ioremap(addr->address + 0xc00000, 0x1000);
-	init_bandit(hose);
-}
-
-static void __init
-setup_chaos(struct pci_controller* hose, struct reg_property* addr)
-{
-	/* assume a `chaos' bridge */
-	hose->ops = &chaos_pci_ops;
-	hose->cfg_addr = (volatile unsigned int *)
-		ioremap(addr->address + 0x800000, 0x1000);
-	hose->cfg_data = (volatile unsigned char *)
-		ioremap(addr->address + 0xc00000, 0x1000);
-}
-
-void __init
-setup_grackle(struct pci_controller *hose)
-{
-	setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
-	if (machine_is_compatible("AAPL,PowerBook1998"))
-		grackle_set_loop_snoop(hose, 1);
-#if 0	/* Disabled for now, HW problems ??? */
-	grackle_set_stg(hose, 1);
-#endif
-}
-
-/*
- * We assume that if we have a G3 powermac, we have one bridge called
- * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise,
- * if we have one or more bandit or chaos bridges, we don't have a MPC106.
- */
-static void __init
-add_bridges(struct device_node *dev)
-{
-	int len;
-	struct pci_controller *hose;
-	struct reg_property *addr;
-	char* disp_name;
-	int *bus_range;
-	int first = 1, primary;
-	
-	for (; dev != NULL; dev = dev->next) {
-		addr = (struct reg_property *) get_property(dev, "reg", &len);
-		if (addr == NULL || len < sizeof(*addr)) {
-			printk(KERN_WARNING "Can't use %s: no address\n",
-			       dev->full_name);
-			continue;
-		}
-		bus_range = (int *) get_property(dev, "bus-range", &len);
-		if (bus_range == NULL || len < 2 * sizeof(int)) {
-			printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",
-				       dev->full_name);
-		}
-		
-		hose = pcibios_alloc_controller();
-		if (!hose)
-			continue;
-		hose->arch_data = dev;
-		hose->first_busno = bus_range ? bus_range[0] : 0;
-		hose->last_busno = bus_range ? bus_range[1] : 0xff;
-
-		disp_name = NULL;
-		primary = first;
-		if (device_is_compatible(dev, "uni-north")) {
-			primary = setup_uninorth(hose, addr);
-			disp_name = "UniNorth";
-		} else if (strcmp(dev->name, "pci") == 0) {
-			/* XXX assume this is a mpc106 (grackle) */
-			setup_grackle(hose);
-			disp_name = "Grackle (MPC106)";
-		} else if (strcmp(dev->name, "bandit") == 0) {
-			setup_bandit(hose, addr);
-			disp_name = "Bandit";
-		} else if (strcmp(dev->name, "chaos") == 0) {
-			setup_chaos(hose, addr);
-			disp_name = "Chaos";
-			primary = 0;
-		}
-		printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n",
-			disp_name, addr->address, hose->first_busno, hose->last_busno);
-#ifdef DEBUG
-		printk(" ->Hose at 0x%08lx, cfg_addr=0x%08lx,cfg_data=0x%08lx\n",
-			hose, hose->cfg_addr, hose->cfg_data);
-#endif		
-		
-		/* Interpret the "ranges" property */
-		/* This also maps the I/O region and sets isa_io/mem_base */
-		pci_process_bridge_OF_ranges(hose, dev, primary);
-
-		/* Fixup "bus-range" OF property */
-		fixup_bus_range(dev);
-
-		first &= !primary;
-	}
-}
-
-static void __init
-pcibios_fixup_OF_interrupts(void)
-{	
-	struct pci_dev* dev;
-	
-	/*
-	 * Open Firmware often doesn't initialize the
-	 * PCI_INTERRUPT_LINE config register properly, so we
-	 * should find the device node and apply the interrupt
-	 * obtained from the OF device-tree
-	 */
-	pci_for_each_dev(dev) {
-		struct device_node* node = pci_device_to_OF_node(dev);
-		/* this is the node, see if it has interrupts */
-		if (node && node->n_intrs > 0)
-			dev->irq = node->intrs[0].line;
-		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
-	}
-}
-
-void __init
-pmac_pcibios_fixup(void)
-{
-	/* Fixup interrupts according to OF tree */
-	pcibios_fixup_OF_interrupts();
-}
-
-int __pmac
-pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
-{
-	struct device_node* node;
-	int updatecfg = 0;
-	int uninorth_child;
-	
-	node = pci_device_to_OF_node(dev);
-	
-	/* We don't want to enable USB controllers absent from the OF tree
-	 * (iBook second controller)
-	 */
-	if (dev->vendor == PCI_VENDOR_ID_APPLE
-	    && dev->device == PCI_DEVICE_ID_APPLE_KL_USB && !node)
-		return -EINVAL;
-
-	if (!node)
-		return 0;
-		
-	uninorth_child = node->parent &&
-		device_is_compatible(node->parent, "uni-north");
-		
-	/* Firewire & GMAC were disabled after PCI probe, the driver is
-	 * claiming them, we must re-enable them now.
-	 */
-	if (uninorth_child && !strcmp(node->name, "firewire") && 
-	    (device_is_compatible(node, "pci106b,18") || 
-	     device_is_compatible(node, "pci106b,30") ||
-	     device_is_compatible(node, "pci11c1,5811"))) {
-		pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, node, 0, 1);
-		pmac_call_feature(PMAC_FTR_1394_ENABLE, node, 0, 1);
-		updatecfg = 1;
-	}
-	if (uninorth_child && !strcmp(node->name, "ethernet") && 
-	    device_is_compatible(node, "gmac")) {
-		pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1);
-		updatecfg = 1;
-	}
-
-	if (updatecfg) {
-		u16 cmd;
-		
-		/*
-		 * Make sure PCI is correctly configured
-		 *
-		 * We use old pci_bios versions of the function since, by
-		 * default, gmac is not powered up, and so will be absent
-		 * from the kernel initial PCI lookup. 
-		 * 
-		 * Should be replaced by 2.4 new PCI mecanisms and really
-		 * regiser the device.
-		 */
-		pci_read_config_word(dev, PCI_COMMAND, &cmd);
-		cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
-    		pci_write_config_word(dev, PCI_COMMAND, cmd);
-    		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16);
-    		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8);
-	}
-	
-	return 0;
-}
-
-/* We power down some devices after they have been probed. They'll
- * be powered back on later on
- */
-void __init
-pmac_pcibios_after_init(void)
-{
-	struct device_node* nd;
-
-#ifdef CONFIG_BLK_DEV_IDE
-	struct pci_dev *dev;
-
-	/* OF fails to initialize IDE controllers on macs
-	 * (and maybe other machines)
-	 * 
-	 * Ideally, this should be moved to the IDE layer, but we need
-	 * to check specifically with Andre Hedrick how to do it cleanly
-	 * since the common IDE code seem to care about the fact that the
-	 * BIOS may have disabled a controller.
-	 * 
-	 * -- BenH
-	 */
-	pci_for_each_dev(dev) {
-		if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE)
-			pci_enable_device(dev);
-	}
-#endif /* CONFIG_BLK_DEV_IDE */
-
-	nd = find_devices("firewire");
-	while (nd) {
-		if (nd->parent && (device_is_compatible(nd, "pci106b,18") ||
-				   device_is_compatible(nd, "pci106b,30") ||
-				   device_is_compatible(nd, "pci11c1,5811"))
-		    && device_is_compatible(nd->parent, "uni-north")) {
-			pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0);
-			pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0);
-		}
-		nd = nd->next;
-	}
-	nd = find_devices("ethernet");
-	while (nd) {
-		if (nd->parent && device_is_compatible(nd, "gmac")
-		    && device_is_compatible(nd->parent, "uni-north"))
-			pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0);
-		nd = nd->next;
-	}
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/pmac_pic.c linux-2.4.20/arch/ppc/kernel/pmac_pic.c
--- linux-2.4.19/arch/ppc/kernel/pmac_pic.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/pmac_pic.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,528 +0,0 @@
-/*
- * BK Id: SCCS/s.pmac_pic.c 1.24 12/19/01 10:53:01 paulus
- */
-#include <linux/config.h>
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/pci.h>
-
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/time.h>
-
-#include "pmac_pic.h"
-#include "open_pic.h"
-
-struct pmac_irq_hw {
-        unsigned int    event;
-        unsigned int    enable;
-        unsigned int    ack;
-        unsigned int    level;
-};
-
-/* Default addresses */
-static volatile struct pmac_irq_hw *pmac_irq_hw[4] __pmacdata = {
-        (struct pmac_irq_hw *) 0xf3000020,
-        (struct pmac_irq_hw *) 0xf3000010,
-        (struct pmac_irq_hw *) 0xf4000020,
-        (struct pmac_irq_hw *) 0xf4000010,
-};
-
-#define GC_LEVEL_MASK		0x3ff00000
-#define OHARE_LEVEL_MASK	0x1ff00000
-#define HEATHROW_LEVEL_MASK	0x1ff00000
-
-static int max_irqs __pmacdata;
-static int max_real_irqs __pmacdata;
-static u32 level_mask[4] __pmacdata;
-
-static spinlock_t pmac_pic_lock __pmacdata = SPIN_LOCK_UNLOCKED;
-
-
-#define GATWICK_IRQ_POOL_SIZE        10
-static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE] __pmacdata;
-
-/*
- * Mark an irq as "lost".  This is only used on the pmac
- * since it can lose interrupts (see pmac_set_irq_mask).
- * -- Cort
- */
-void __pmac
-__set_lost(unsigned long irq_nr, int nokick)
-{
-	if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
-		atomic_inc(&ppc_n_lost_interrupts);
-		if (!nokick)
-			set_dec(1);
-	}
-}
-
-static void __pmac
-pmac_mask_and_ack_irq(unsigned int irq_nr)
-{
-        unsigned long bit = 1UL << (irq_nr & 0x1f);
-        int i = irq_nr >> 5;
-        unsigned long flags;
-
-        if ((unsigned)irq_nr >= max_irqs)
-                return;
-
-        clear_bit(irq_nr, ppc_cached_irq_mask);
-        if (test_and_clear_bit(irq_nr, ppc_lost_interrupts))
-                atomic_dec(&ppc_n_lost_interrupts);
-	spin_lock_irqsave(&pmac_pic_lock, flags);
-        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
-        out_le32(&pmac_irq_hw[i]->ack, bit);
-        do {
-                /* make sure ack gets to controller before we enable
-                   interrupts */
-                mb();
-        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
-                != (ppc_cached_irq_mask[i] & bit));
-	spin_unlock_irqrestore(&pmac_pic_lock, flags);
-}
-
-static void __pmac pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
-{
-        unsigned long bit = 1UL << (irq_nr & 0x1f);
-        int i = irq_nr >> 5;
-        unsigned long flags;
-
-        if ((unsigned)irq_nr >= max_irqs)
-                return;
-
-	spin_lock_irqsave(&pmac_pic_lock, flags);
-        /* enable unmasked interrupts */
-        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
-
-        do {
-                /* make sure mask gets to controller before we
-                   return to user */
-                mb();
-        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
-                != (ppc_cached_irq_mask[i] & bit));
-
-        /*
-         * Unfortunately, setting the bit in the enable register
-         * when the device interrupt is already on *doesn't* set
-         * the bit in the flag register or request another interrupt.
-         */
-        if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level))
-		__set_lost((ulong)irq_nr, nokicklost);
-	spin_unlock_irqrestore(&pmac_pic_lock, flags);
-}
-
-static void __pmac pmac_mask_irq(unsigned int irq_nr)
-{
-        clear_bit(irq_nr, ppc_cached_irq_mask);
-        pmac_set_irq_mask(irq_nr, 0);
-        mb();
-}
-
-static void __pmac pmac_unmask_irq(unsigned int irq_nr)
-{
-        set_bit(irq_nr, ppc_cached_irq_mask);
-        pmac_set_irq_mask(irq_nr, 0);
-}
-
-static void __pmac pmac_end_irq(unsigned int irq_nr)
-{
-	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
-        	set_bit(irq_nr, ppc_cached_irq_mask);
-	        pmac_set_irq_mask(irq_nr, 1);
-	}
-}
-
-
-struct hw_interrupt_type pmac_pic = {
-        " PMAC-PIC ",
-        NULL,
-        NULL,
-        pmac_unmask_irq,
-        pmac_mask_irq,
-        pmac_mask_and_ack_irq,
-        pmac_end_irq,
-        NULL
-};
-
-struct hw_interrupt_type gatwick_pic = {
-	" GATWICK  ",
-	NULL,
-	NULL,
-	pmac_unmask_irq,
-	pmac_mask_irq,
-	pmac_mask_and_ack_irq,
-	pmac_end_irq,
-	NULL
-};
-
-static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-	int irq, bits;
-	
-	for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) {
-		int i = irq >> 5;
-		bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
-		/* We must read level interrupts from the level register */
-		bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);
-		bits &= ppc_cached_irq_mask[i];
-		if (bits == 0)
-			continue;
-		irq += __ilog2(bits);
-		break;
-	}
-	/* The previous version of this code allowed for this case, we
-	 * don't.  Put this here to check for it.
-	 * -- Cort
-	 */
-	if ( irq_desc[irq].handler != &gatwick_pic )
-		printk("gatwick irq not from gatwick pic\n");
-	else
-		ppc_irq_dispatch_handler( regs, irq );
-}
-
-int
-pmac_get_irq(struct pt_regs *regs)
-{
-	int irq;
-	unsigned long bits = 0;
-
-#ifdef CONFIG_SMP
-	void psurge_smp_message_recv(struct pt_regs *);
-	
-       	/* IPI's are a hack on the powersurge -- Cort */
-       	if ( smp_processor_id() != 0 ) {
-		psurge_smp_message_recv(regs);
-		return -2;	/* ignore, already handled */
-        }
-#endif /* CONFIG_SMP */
-	for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
-		int i = irq >> 5;
-		bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
-		/* We must read level interrupts from the level register */
-		bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);
-		bits &= ppc_cached_irq_mask[i];
-		if (bits == 0)
-			continue;
-		irq += __ilog2(bits);
-		break;
-	}
-
-	return irq;
-}
-
-/* This routine will fix some missing interrupt values in the device tree
- * on the gatwick mac-io controller used by some PowerBooks
- */
-static void __init
-pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
-{
-	struct device_node *node;
-	int count;
-	
-	memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
-	node = gw->child;
-	count = 0;
-	while(node)
-	{
-		/* Fix SCC */
-		if (strcasecmp(node->name, "escc") == 0)
-			if (node->child) {
-				if (node->child->n_intrs < 3) {
-					node->child->intrs = &gatwick_int_pool[count];
-					count += 3;
-				}
-				node->child->n_intrs = 3;				
-				node->child->intrs[0].line = 15+irq_base;
-				node->child->intrs[1].line =  4+irq_base;
-				node->child->intrs[2].line =  5+irq_base;
-				printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
-					node->child->intrs[0].line,
-					node->child->intrs[1].line,
-					node->child->intrs[2].line);
-			}
-		/* Fix media-bay & left SWIM */
-		if (strcasecmp(node->name, "media-bay") == 0) {
-			struct device_node* ya_node;
-
-			if (node->n_intrs == 0)
-				node->intrs = &gatwick_int_pool[count++];
-			node->n_intrs = 1;
-			node->intrs[0].line = 29+irq_base;
-			printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
-					node->intrs[0].line);
-			
-			ya_node = node->child;
-			while(ya_node)
-			{
-				if (strcasecmp(ya_node->name, "floppy") == 0) {
-					if (ya_node->n_intrs < 2) {
-						ya_node->intrs = &gatwick_int_pool[count];
-						count += 2;
-					}
-					ya_node->n_intrs = 2;
-					ya_node->intrs[0].line = 19+irq_base;
-					ya_node->intrs[1].line =  1+irq_base;
-					printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
-						ya_node->intrs[0].line, ya_node->intrs[1].line);
-				} 
-				if (strcasecmp(ya_node->name, "ata4") == 0) {
-					if (ya_node->n_intrs < 2) {
-						ya_node->intrs = &gatwick_int_pool[count];
-						count += 2;
-					}
-					ya_node->n_intrs = 2;
-					ya_node->intrs[0].line = 14+irq_base;
-					ya_node->intrs[1].line =  3+irq_base;
-					printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n",
-						ya_node->intrs[0].line, ya_node->intrs[1].line);
-				} 
-				ya_node = ya_node->sibling;
-			}
-		}
-		node = node->sibling;
-	}
-	if (count > 10) {
-		printk("WARNING !! Gatwick interrupt pool overflow\n");
-		printk("  GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE);
-		printk("              requested = %d\n", count);
-	}
-}
-
-/*
- * The PowerBook 3400/2400/3500 can have a combo ethernet/modem
- * card which includes an ohare chip that acts as a second interrupt
- * controller.  If we find this second ohare, set it up and fix the
- * interrupt value in the device tree for the ethernet chip.
- */
-static int __init enable_second_ohare(void)
-{
-	unsigned char bus, devfn;
-	unsigned short cmd;
-        unsigned long addr;
-	struct device_node *irqctrler = find_devices("pci106b,7");
-	struct device_node *ether;
-
-	if (irqctrler == NULL || irqctrler->n_addrs <= 0)
-		return -1;
-	addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40);
-	pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20);
-	max_irqs = 64;
-	if (pci_device_from_OF_node(irqctrler, &bus, &devfn) == 0) {
-		struct pci_controller* hose = pci_find_hose_for_OF_device(irqctrler);
-		if (!hose)
-		    printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
-		else {
-		    early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
-		    cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
-	  	    cmd &= ~PCI_COMMAND_IO;
-		    early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
-		}
-	}
-
-	/* Fix interrupt for the modem/ethernet combo controller. The number
-	   in the device tree (27) is bogus (correct for the ethernet-only
-	   board but not the combo ethernet/modem board).
-	   The real interrupt is 28 on the second controller -> 28+32 = 60.
-	*/
-	ether = find_devices("pci1011,14");
-	if (ether && ether->n_intrs > 0) {
-		ether->intrs[0].line = 60;
-		printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n",
-		       ether->intrs[0].line);
-	}
-
-	/* Return the interrupt number of the cascade */
-	return irqctrler->intrs[0].line;
-}
-
-void __init
-pmac_pic_init(void)
-{
-        int i;
-        struct device_node *irqctrler;
-        unsigned long addr;
-	int irq_cascade = -1;
-	
-	/* We first try to detect Apple's new Core99 chipset, since mac-io
-	 * is quite different on those machines and contains an IBM MPIC2.
-	 */
-	irqctrler = find_type_devices("open-pic");
-	if (irqctrler != NULL)
-	{
-		printk("PowerMac using OpenPIC irq controller\n");
-		if (irqctrler->n_addrs > 0)
-		{
-			int nmi_irq = -1;
-			unsigned char senses[NR_IRQS];
-#ifdef CONFIG_XMON
-			struct device_node* pswitch;
-
-			pswitch = find_devices("programmer-switch");
-			if (pswitch && pswitch->n_intrs)
-				nmi_irq = pswitch->intrs[0].line;
-#endif /* CONFIG_XMON */
-			prom_get_irq_senses(senses, 0, NR_IRQS);
-			OpenPIC_InitSenses = senses;
-			OpenPIC_NumInitSenses = NR_IRQS;
-			ppc_md.get_irq = openpic_get_irq;
-			OpenPIC_Addr = ioremap(irqctrler->addrs[0].address,
-					       irqctrler->addrs[0].size);
-			openpic_init(1, 0, 0, nmi_irq);
-#ifdef CONFIG_XMON
-			if (nmi_irq >= 0)
-				request_irq(nmi_irq, xmon_irq, 0,
-					    "NMI - XMON", 0);
-#endif	/* CONFIG_XMON */
-			return;
-		}
-		irqctrler = NULL;
-	}
-
-	/* Get the level/edge settings, assume if it's not
-	 * a Grand Central nor an OHare, then it's an Heathrow
-	 * (or Paddington).
-	 */
-	if (find_devices("gc"))
-		level_mask[0] = GC_LEVEL_MASK;
-	else if (find_devices("ohare")) {
-		level_mask[0] = OHARE_LEVEL_MASK;
-		/* We might have a second cascaded ohare */
-		level_mask[1] = OHARE_LEVEL_MASK;
-	} else {
-		level_mask[0] = HEATHROW_LEVEL_MASK;
-		level_mask[1] = 0;
-		/* We might have a second cascaded heathrow */
-		level_mask[2] = HEATHROW_LEVEL_MASK;
-		level_mask[3] = 0;
-	}
-
-	/*
-	 * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
-	 * 1998 G3 Series PowerBooks have 128, 
-	 * other powermacs have 32.
-	 * The combo ethernet/modem card for the Powerstar powerbooks
-	 * (2400/3400/3500, ohare based) has a second ohare chip
-	 * effectively making a total of 64.
-	 */
-	max_irqs = max_real_irqs = 32;
-	irqctrler = find_devices("mac-io");
-	if (irqctrler)
-	{
-		max_real_irqs = 64;
-		if (irqctrler->next)
-			max_irqs = 128;
-		else
-			max_irqs = 64;
-	}
-	for ( i = 0; i < max_real_irqs ; i++ )
-		irq_desc[i].handler = &pmac_pic;
-
-	/* get addresses of first controller */
-	if (irqctrler) {
-		if  (irqctrler->n_addrs > 0) {
-			addr = (unsigned long) 
-				ioremap(irqctrler->addrs[0].address, 0x40);
-			for (i = 0; i < 2; ++i)
-				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-					(addr + (2 - i) * 0x10);
-		}
-		
-		/* get addresses of second controller */
-		irqctrler = irqctrler->next;
-		if (irqctrler && irqctrler->n_addrs > 0) {
-			addr = (unsigned long) 
-				ioremap(irqctrler->addrs[0].address, 0x40);
-			for (i = 2; i < 4; ++i)
-				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-					(addr + (4 - i) * 0x10);
-			irq_cascade = irqctrler->intrs[0].line;
-			if (device_is_compatible(irqctrler, "gatwick"))
-				pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
-		}
-	} else {
-		/* older powermacs have a GC (grand central) or ohare at
-		   f3000000, with interrupt control registers at f3000020. */
-		addr = (unsigned long) ioremap(0xf3000000, 0x40);
-		pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20);
-	}
-
-	/* PowerBooks 3400 and 3500 can have a second controller in a second
-	   ohare chip, on the combo ethernet/modem card */
-	if (machine_is_compatible("AAPL,3400/2400")
-	     || machine_is_compatible("AAPL,3500"))
-		irq_cascade = enable_second_ohare();
-
-	/* disable all interrupts in all controllers */
-	for (i = 0; i * 32 < max_irqs; ++i)
-		out_le32(&pmac_irq_hw[i]->enable, 0);
-	/* mark level interrupts */
-	for (i = 0; i < max_irqs; i++)
-		if (level_mask[i >> 5] & (1UL << (i & 0x1f)))
-			irq_desc[i].status = IRQ_LEVEL;
-	
-	/* get interrupt line of secondary interrupt controller */
-	if (irq_cascade >= 0) {
-		printk(KERN_INFO "irq: secondary controller on irq %d\n",
-			(int)irq_cascade);
-		for ( i = max_real_irqs ; i < max_irqs ; i++ )
-			irq_desc[i].handler = &gatwick_pic;
-		request_irq( irq_cascade, gatwick_action, SA_INTERRUPT,
-			     "cascade", 0 );
-	}
-	printk("System has %d possible interrupts\n", max_irqs);
-	if (max_irqs != max_real_irqs)
-		printk(KERN_DEBUG "%d interrupts on main controller\n",
-			max_real_irqs);
-
-#ifdef CONFIG_XMON
-	request_irq(20, xmon_irq, 0, "NMI - XMON", 0);
-#endif	/* CONFIG_XMON */
-}
-
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * These procedures are used in implementing sleep on the powerbooks.
- * sleep_save_intrs() saves the states of all interrupt enables
- * and disables all interrupts except for the nominated one.
- * sleep_restore_intrs() restores the states of all interrupt enables.
- */
-unsigned int sleep_save_mask[2];
-
-void __pmac
-pmac_sleep_save_intrs(int viaint)
-{
-	sleep_save_mask[0] = ppc_cached_irq_mask[0];
-	sleep_save_mask[1] = ppc_cached_irq_mask[1];
-	ppc_cached_irq_mask[0] = 0;
-	ppc_cached_irq_mask[1] = 0;
-	if (viaint > 0)
-		set_bit(viaint, ppc_cached_irq_mask);
-	out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]);
-	if (max_real_irqs > 32)
-		out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);
-	(void)in_le32(&pmac_irq_hw[0]->event);
-	/* make sure mask gets to controller before we return to caller */
-	mb();
-        (void)in_le32(&pmac_irq_hw[0]->enable);
-}
-
-void __pmac
-pmac_sleep_restore_intrs(void)
-{
-	int i;
-
-	out_le32(&pmac_irq_hw[0]->enable, 0);
-	if (max_real_irqs > 32)
-		out_le32(&pmac_irq_hw[1]->enable, 0);
-	mb();
-	for (i = 0; i < max_real_irqs; ++i)
-		if (test_bit(i, sleep_save_mask))
-			pmac_unmask_irq(i);
-}
-#endif /* CONFIG_PMAC_PBOOK */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/pmac_pic.h linux-2.4.20/arch/ppc/kernel/pmac_pic.h
--- linux-2.4.19/arch/ppc/kernel/pmac_pic.h	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/pmac_pic.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,14 +0,0 @@
-/*
- * BK Id: SCCS/s.pmac_pic.h 1.9 08/19/01 22:23:04 paulus
- */
-#ifndef _PPC_KERNEL_PMAC_PIC_H
-#define _PPC_KERNEL_PMAC_PIC_H
-
-#include "local_irq.h"
-
-extern struct hw_interrupt_type pmac_pic;
-
-void pmac_pic_init(void);
-int pmac_get_irq(struct pt_regs *regs);
-
-#endif /* _PPC_KERNEL_PMAC_PIC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/pmac_setup.c linux-2.4.20/arch/ppc/kernel/pmac_setup.c
--- linux-2.4.19/arch/ppc/kernel/pmac_setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/pmac_setup.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,957 +0,0 @@
-/*
- * BK Id: SCCS/s.pmac_setup.c 1.54 04/16/02 20:08:22 paulus
- */
-/*
- *  linux/arch/ppc/kernel/setup.c
- *
- *  PowerPC version 
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Adapted for Power Macintosh by Paul Mackerras
- *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
- *
- *  Derived from "arch/alpha/kernel/setup.c"
- *    Copyright (C) 1995 Linus Torvalds
- *
- *  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.
- *
- */
-
-/*
- * bootup setup stuff..
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/major.h>
-#include <linux/blk.h>
-#include <linux/vt_kern.h>
-#include <linux/console.h>
-#include <linux/ide.h>
-#include <linux/pci.h>
-#include <linux/adb.h>
-#include <linux/cuda.h>
-#include <linux/pmu.h>
-#include <linux/seq_file.h>
-#include <linux/blkdev.h>
-#include <linux/genhd.h>
-
-#include <asm/processor.h>
-#include <asm/sections.h>
-#include <asm/prom.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/pci-bridge.h>
-#include <asm/ohare.h>
-#include <asm/mediabay.h>
-#include <asm/machdep.h>
-#include <asm/keyboard.h>
-#include <asm/dma.h>
-#include <asm/bootx.h>
-#include <asm/cputable.h>
-#include <asm/btext.h>
-#include <asm/pmac_feature.h>
-#include <asm/time.h>
-
-#include "local_irq.h"
-#include "pmac_pic.h"
-#include "mem_pieces.h"
-#include "scsi.h" /* sd_find_target */
-#include "sd.h"
-
-extern long pmac_time_init(void);
-extern unsigned long pmac_get_rtc_time(void);
-extern int pmac_set_rtc_time(unsigned long nowtime);
-extern void pmac_read_rtc_time(void);
-extern void pmac_calibrate_decr(void);
-extern void pmac_pcibios_fixup(void);
-extern void pmac_find_bridges(void);
-extern int pmac_ide_check_base(ide_ioreg_t base);
-extern ide_ioreg_t pmac_ide_get_base(int index);
-extern void pmac_ide_init_hwif_ports(hw_regs_t *hw,
-	ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq);
-
-extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int mackbd_getkeycode(unsigned int scancode);
-extern int mackbd_translate(unsigned char keycode, unsigned char *keycodep,
-		     char raw_mode);
-extern char mackbd_unexpected_up(unsigned char keycode);
-extern void mackbd_leds(unsigned char leds);
-extern void __init mackbd_init_hw(void);
-extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
-				 char raw_mode);
-extern char mac_hid_kbd_unexpected_up(unsigned char keycode);
-extern void mac_hid_init_hw(void);
-extern unsigned char mac_hid_kbd_sysrq_xlate[];
-extern unsigned char pckbd_sysrq_xlate[];
-extern unsigned char mackbd_sysrq_xlate[];
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern int keyboard_sends_linux_keycodes;
-extern void pmac_nvram_update(void);
-
-extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial);
-extern void pmac_pcibios_after_init(void);
-
-struct device_node *memory_node;
-
-unsigned char drive_info;
-
-int ppc_override_l2cr = 0;
-int ppc_override_l2cr_value;
-int has_l2cache = 0;
-
-static int current_root_goodness = -1;
-
-extern char saved_command_line[];
-
-extern int pmac_newworld;
-
-#define DEFAULT_ROOT_DEVICE 0x0801	/* sda1 - slightly silly choice */
-
-extern void zs_kgdb_hook(int tty_num);
-static void ohare_init(void);
-#ifdef CONFIG_BOOTX_TEXT
-void pmac_progress(char *s, unsigned short hex);
-#endif
-
-sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN;
-
-#ifdef CONFIG_SMP
-extern struct smp_ops_t psurge_smp_ops;
-extern struct smp_ops_t core99_smp_ops;
-#endif /* CONFIG_SMP */
-
-/*
- * Assume here that all clock rates are the same in a
- * smp system.  -- Cort
- */
-int __openfirmware
-of_show_percpuinfo(struct seq_file *m, int i)
-{
-	struct device_node *cpu_node;
-	int *fp, s;
-			
-	cpu_node = find_type_devices("cpu");
-	if (!cpu_node)
-		return 0;
-	for (s = 0; s < i && cpu_node->next; s++)
-		cpu_node = cpu_node->next;
-	fp = (int *) get_property(cpu_node, "clock-frequency", NULL);
-	if (fp)
-		seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000);
-	return 0;
-}
-
-int __pmac
-pmac_show_cpuinfo(struct seq_file *m)
-{
-	struct device_node *np;
-	char *pp;
-	int plen;
-	int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
-		NULL, PMAC_MB_INFO_MODEL, 0);
-	unsigned int mbflags = (unsigned int)pmac_call_feature(PMAC_FTR_GET_MB_INFO,
-		NULL, PMAC_MB_INFO_FLAGS, 0);
-	char* mbname;
-
-	if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, (int)&mbname) != 0)
-		mbname = "Unknown";
-		
-	/* find motherboard type */
-	seq_printf(m, "machine\t\t: ");
-	np = find_devices("device-tree");
-	if (np != NULL) {
-		pp = (char *) get_property(np, "model", NULL);
-		if (pp != NULL)
-			seq_printf(m, "%s\n", pp);
-		else
-			seq_printf(m, "PowerMac\n");
-		pp = (char *) get_property(np, "compatible", &plen);
-		if (pp != NULL) {
-			seq_printf(m, "motherboard\t:");
-			while (plen > 0) {
-				int l = strlen(pp) + 1;
-				seq_printf(m, " %s", pp);
-				plen -= l;
-				pp += l;
-			}
-			seq_printf(m, "\n");
-		}
-	} else
-		seq_printf(m, "PowerMac\n");
-
-	/* print parsed model */
-	seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname);
-	seq_printf(m, "pmac flags\t: %08x\n", mbflags);
-	
-	/* find l2 cache info */
-	np = find_devices("l2-cache");
-	if (np == 0)
-		np = find_type_devices("cache");
-	if (np != 0) {
-		unsigned int *ic = (unsigned int *)
-			get_property(np, "i-cache-size", NULL);
-		unsigned int *dc = (unsigned int *)
-			get_property(np, "d-cache-size", NULL);
-		seq_printf(m, "L2 cache\t:");
-		has_l2cache = 1;
-		if (get_property(np, "cache-unified", NULL) != 0 && dc) {
-			seq_printf(m, " %dK unified", *dc / 1024);
-		} else {
-			if (ic)
-				seq_printf(m, " %dK instruction", *ic / 1024);
-			if (dc)
-				seq_printf(m, "%s %dK data",
-					   (ic? " +": ""), *dc / 1024);
-		}
-		pp = get_property(np, "ram-type", NULL);
-		if (pp)
-			seq_printf(m, " %s", pp);
-		seq_printf(m, "\n");
-	}
-
-	/* find ram info */
-	np = find_devices("memory");
-	if (np != 0) {
-		int n;
-		struct reg_property *reg = (struct reg_property *)
-			get_property(np, "reg", &n);
-		
-		if (reg != 0) {
-			unsigned long total = 0;
-
-			for (n /= sizeof(struct reg_property); n > 0; --n)
-				total += (reg++)->size;
-			seq_printf(m, "memory\t\t: %luMB\n", total >> 20);
-		}
-	}
-
-	/* Checks "l2cr-value" property in the registry */
-	np = find_devices("cpus");		
-	if (np == 0)
-		np = find_type_devices("cpu");		
-	if (np != 0) {
-		unsigned int *l2cr = (unsigned int *)
-			get_property(np, "l2cr-value", NULL);
-		if (l2cr != 0) {
-			seq_printf(m, "l2cr override\t: 0x%x\n", *l2cr);
-		}
-	}
-	
-	/* Indicate newworld/oldworld */
-	seq_printf(m, "pmac-generation\t: %s\n",
-		   pmac_newworld ? "NewWorld" : "OldWorld");
-	
-
-	return 0;
-}
-
-#ifdef CONFIG_VT
-/*
- * Dummy mksound function that does nothing.
- * The real one is in the dmasound driver.
- */
-static void __pmac
-pmac_mksound(unsigned int hz, unsigned int ticks)
-{
-}
-#endif /* CONFIG_VT */
-
-static volatile u32 *sysctrl_regs;
-
-void __init
-pmac_setup_arch(void)
-{
-	struct device_node *cpu;
-	int *fp;
-	unsigned long pvr;
-	
-	pvr = PVR_VER(mfspr(PVR));
-
-	/* Set loops_per_jiffy to a half-way reasonable value,
-	   for use until calibrate_delay gets called. */
-	cpu = find_type_devices("cpu");
-	if (cpu != 0) {
-		fp = (int *) get_property(cpu, "clock-frequency", NULL);
-		if (fp != 0) {
-			if (pvr == 4 || pvr >= 8)
-				/* 604, G3, G4 etc. */
-				loops_per_jiffy = *fp / HZ;
-			else
-				/* 601, 603, etc. */
-				loops_per_jiffy = *fp / (2*HZ);
-		} else
-			loops_per_jiffy = 50000000 / HZ;
-	}
-
-	/* this area has the CPU identification register
-	   and some registers used by smp boards */
-	sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);
-	ohare_init();
-
-	/* Lookup PCI hosts */
-	pmac_find_bridges();
-	
-	/* Checks "l2cr-value" property in the registry */
-	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR) {
-		struct device_node *np = find_devices("cpus");		
-		if (np == 0)
-			np = find_type_devices("cpu");		
-		if (np != 0) {
-			unsigned int *l2cr = (unsigned int *)
-				get_property(np, "l2cr-value", NULL);
-			if (l2cr != 0) {
-				ppc_override_l2cr = 1;
-				ppc_override_l2cr_value = *l2cr;
-				_set_L2CR(0);
-				_set_L2CR(ppc_override_l2cr_value);
-			}
-		}
-	}
-
-	if (ppc_override_l2cr)
-		printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n",
-			ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000)
-				? "enabled" : "disabled");
-	
-#ifdef CONFIG_KGDB
-	zs_kgdb_hook(0);
-#endif
-
-#ifdef CONFIG_ADB_CUDA
-	find_via_cuda();
-#else
-	if (find_devices("via-cuda")) {
-		printk("WARNING ! Your machine is Cuda based but your kernel\n");
-		printk("          wasn't compiled with CONFIG_ADB_CUDA option !\n");
-	}
-#endif	
-#ifdef CONFIG_ADB_PMU
-	find_via_pmu();
-#else
-	if (find_devices("via-pmu")) {
-		printk("WARNING ! Your machine is PMU based but your kernel\n");
-		printk("          wasn't compiled with CONFIG_ADB_PMU option !\n");
-	}
-#endif	
-#ifdef CONFIG_NVRAM
-	pmac_nvram_init();
-#endif
-#ifdef CONFIG_DUMMY_CONSOLE
-	conswitchp = &dummy_con;
-#endif
-#ifdef CONFIG_VT
-	kd_mksound = pmac_mksound;
-#endif
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (initrd_start)
-		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
-	else
-#endif
-		ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
-
-#ifdef CONFIG_SMP
-	/* Check for Core99 */
-	if (find_devices("uni-n"))
-		ppc_md.smp_ops = &core99_smp_ops;
-	else
-		ppc_md.smp_ops = &psurge_smp_ops;
-#endif /* CONFIG_SMP */
-}
-
-static void __init ohare_init(void)
-{
-	/*
-	 * Turn on the L2 cache.
-	 * We assume that we have a PSX memory controller iff
-	 * we have an ohare I/O controller.
-	 */
-	if (find_devices("ohare") != NULL) {
-		if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {
-			if (sysctrl_regs[4] & 0x10)
-				sysctrl_regs[4] |= 0x04000020;
-			else
-				sysctrl_regs[4] |= 0x04000000;
-			if(has_l2cache)
-				printk(KERN_INFO "Level 2 cache enabled\n");
-		}
-	}
-}
-
-extern char *bootpath;
-extern char *bootdevice;
-void *boot_host;
-int boot_target;
-int boot_part;
-extern kdev_t boot_dev;
-
-void __init
-pmac_init2(void)
-{
-#ifdef CONFIG_ADB_PMU
-	via_pmu_start();
-#endif
-#ifdef CONFIG_ADB_CUDA
-	via_cuda_start();
-#endif
-#ifdef CONFIG_PMAC_PBOOK
-	media_bay_init();
-#endif
-	pmac_feature_late_init();
-}
-
-/* That include would have to be in include/linux/ ideally */
-#include "../../../fs/partitions/mac.h"
-
-/* Borrowed from fs/partition/check.c */
-static unsigned char* __init
-read_one_block(struct block_device *bdev, unsigned long n, struct page **v)
-{
-	struct address_space *mapping = bdev->bd_inode->i_mapping;
-	int sect = PAGE_CACHE_SIZE / 512;
-	struct page *page;
-
-	page = read_cache_page(mapping, n/sect,
-			(filler_t *)mapping->a_ops->readpage, NULL);
-	if (!IS_ERR(page)) {
-		wait_on_page(page);
-		if (!Page_Uptodate(page))
-			goto fail;
-		if (PageError(page))
-			goto fail;
-		*v = page;
-		return (unsigned char *)page_address(page) + 512 * (n % sect);
-fail:
-		page_cache_release(page);
-	}
-	*v = NULL;
-	return NULL;
-}
-
-#ifdef CONFIG_SCSI
-void __init
-note_scsi_host(struct device_node *node, void *host)
-{
-	int l;
-	char *p;
-
-	l = strlen(node->full_name);
-	if (bootpath != NULL && bootdevice != NULL
-	    && strncmp(node->full_name, bootdevice, l) == 0
-	    && (bootdevice[l] == '/' || bootdevice[l] == 0)) {
-		boot_host = host;
-		/*
-		 * There's a bug in OF 1.0.5.  (Why am I not surprised.)
-		 * If you pass a path like scsi/sd@1:0 to canon, it returns
-		 * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0
-		 * That is, the scsi target number doesn't get preserved.
-		 * So we pick the target number out of bootpath and use that.
-		 */
-		p = strstr(bootpath, "/sd@");
-		if (p != NULL) {
-			p += 4;
-			boot_target = simple_strtoul(p, NULL, 10);
-			p = strchr(p, ':');
-			if (p != NULL)
-				boot_part = simple_strtoul(p + 1, NULL, 10);
-		}
-	}
-}
-#endif /* CONFIG_SCSI */
-
-#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
-kdev_t __init
-find_ide_boot(void)
-{
-	char *p;
-	int n;
-	kdev_t __init pmac_find_ide_boot(char *bootdevice, int n);
-
-	if (bootdevice == NULL)
-		return 0;
-	p = strrchr(bootdevice, '/');
-	if (p == NULL)
-		return 0;
-	n = p - bootdevice;
-
-	return pmac_find_ide_boot(bootdevice, n);
-}
-#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */
-
-void __init
-find_boot_device(void)
-{
-#if defined(CONFIG_SCSI) && defined(CONFIG_BLK_DEV_SD)
-	if (boot_host != NULL) {
-		boot_dev = sd_find_target(boot_host, boot_target);
-		if (boot_dev != 0)
-			return;
-	}
-#endif
-#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
-	boot_dev = find_ide_boot();
-#endif
-}
-
-static void __init
-check_bootable_part(kdev_t dev, int blk, struct mac_partition *part)
-{
-	int goodness = 0;
-
-	macpart_fix_string(part->processor, 16);
-	macpart_fix_string(part->name, 32);
-	macpart_fix_string(part->type, 32);					
-    
-	if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
-	    && strcasecmp(part->processor, "powerpc") == 0)
-		goodness++;
-
-	if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
-	    || (strnicmp(part->type, "Linux", 5) == 0
-	    && strcasecmp(part->type, "Linux_swap") != 0)) {
-		int i, l;
-
-		goodness++;
-		l = strlen(part->name);
-		if (strcmp(part->name, "/") == 0)
-			goodness++;
-		for (i = 0; i <= l - 4; ++i) {
-			if (strnicmp(part->name + i, "root",
-				     4) == 0) {
-				goodness += 2;
-				break;
-			}
-		}
-		if (strnicmp(part->name, "swap", 4) == 0)
-			goodness--;
-	}
-
-	if (goodness > current_root_goodness) {
-		ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + blk);
-		current_root_goodness = goodness;
-	}
-}
-
-static void __init
-check_bootable_disk(kdev_t dev, struct block_device *bdev)
-{
-	struct mac_partition *part;
-	struct mac_driver_desc *md;
-	struct page* pg;
-	unsigned secsize, blocks_in_map, blk;
-	unsigned char* data;
-	
-	/* Check driver descriptor */
-	md = (struct mac_driver_desc *) read_one_block(bdev, 0, &pg);
-	if (!md)
-		return;
-	if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC)
-		goto fail;
-	secsize = be16_to_cpu(md->block_size);
-	page_cache_release(pg);
-	
-	/* Check if it looks like a mac partition map */
-	data = read_one_block(bdev, secsize/512, &pg);
-	if (!data)
-		goto fail;
-	part = (struct mac_partition *) (data + secsize%512);
-	if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
-		goto fail;
-
-	/* Iterate the partition map */
-	blocks_in_map = be32_to_cpu(part->map_count);
-	for (blk = 1; blk <= blocks_in_map; ++blk) {
-		int pos = blk * secsize;
-		page_cache_release(pg);
-		data = read_one_block(bdev, pos/512, &pg);
-		if (!data)
-			break;
-		part = (struct mac_partition *) (data + pos%512);
-		if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
-			break;
-		check_bootable_part(dev, blk, part);
-	}
-fail:
-	if (pg)	
-		page_cache_release(pg);
-}
-
-static int __init
-walk_bootable(struct gendisk *hd, void *data)
-{
-	int drive;
-	
-	for (drive=0; drive<hd->nr_real; drive++) {
-		kdev_t dev;
-		struct block_device *bdev;
-		int rc;
-
-		dev = MKDEV(hd->major, drive << hd->minor_shift);
-		if (boot_dev && boot_dev != dev)
-			continue;
-		bdev = bdget(kdev_t_to_nr(dev));
-		if (bdev == NULL)
-			continue;
-		rc = blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW);
-		if (rc == 0) {
-			check_bootable_disk(dev, bdev);
-			blkdev_put(bdev, BDEV_RAW);
-		}
-	}
-
-	return 0;
-}
-
-void __init
-pmac_discover_root(void)
-{
-	char* p;
-
-	/* Check if root devices already got selected by other ways */
-	if (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE))
-		return;
-	p = strstr(saved_command_line, "root=");
-	if (p != NULL && (p == saved_command_line || p[-1] == ' '))
-		return;
-
-	/* Find the device used for booting if we can */
-	find_boot_device();
-
-	/* Try to locate a partition */
-	walk_gendisk(walk_bootable, NULL);
-}
-
-void __pmac
-pmac_restart(char *cmd)
-{
-#ifdef CONFIG_ADB_CUDA
-	struct adb_request req;
-#endif /* CONFIG_ADB_CUDA */
-
-#ifdef CONFIG_NVRAM
-	pmac_nvram_update();
-#endif
-	
-	switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
-	case SYS_CTRLER_CUDA:
-		cuda_request(&req, NULL, 2, CUDA_PACKET,
-			     CUDA_RESET_SYSTEM);
-		for (;;)
-			cuda_poll();
-		break;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU		
-	case SYS_CTRLER_PMU:
-		pmu_restart();
-		break;
-#endif /* CONFIG_ADB_PMU */		
-	default: ;
-	}
-}
-
-void __pmac
-pmac_power_off(void)
-{
-#ifdef CONFIG_ADB_CUDA
-	struct adb_request req;
-#endif /* CONFIG_ADB_CUDA */
-
-#ifdef CONFIG_NVRAM
-	pmac_nvram_update();
-#endif
-	
-	switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
-	case SYS_CTRLER_CUDA:
-		cuda_request(&req, NULL, 2, CUDA_PACKET,
-			     CUDA_POWERDOWN);
-		for (;;)
-			cuda_poll();
-		break;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
-	case SYS_CTRLER_PMU:
-		pmu_shutdown();
-		break;
-#endif /* CONFIG_ADB_PMU */
-	default: ;
-	}
-}
-
-void __pmac
-pmac_halt(void)
-{
-   pmac_power_off();
-}
-
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-static int __pmac
-pmac_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return 0;
-#endif
-	return check_region(from, extent);
-}
-
-static void __pmac
-pmac_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return;
-#endif
-	request_region(from, extent, name);
-}
-
-static void __pmac
-pmac_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return;
-#endif
-	release_region(from, extent);
-}
-
-#ifndef CONFIG_BLK_DEV_IDE_PMAC
-/*
- * This is only used if we have a PCI IDE controller, not
- * for the IDE controller in the ohare/paddington/heathrow/keylargo.
- */
-static void __pmac
-pmac_ide_pci_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port,
-		ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t reg = data_port;
-	int i;
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg;
-		reg += 1;
-	}
-	hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-}
-#endif /* CONFIG_BLK_DEV_IDE_PMAC */
-#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
-
-/*
- * Read in a property describing some pieces of memory.
- */
-
-static int __init
-get_mem_prop(char *name, struct mem_pieces *mp)
-{
-	struct reg_property *rp;
-	int i, s;
-	unsigned int *ip;
-	int nac = prom_n_addr_cells(memory_node);
-	int nsc = prom_n_size_cells(memory_node);
-
-	ip = (unsigned int *) get_property(memory_node, name, &s);
-	if (ip == NULL) {
-		printk(KERN_ERR "error: couldn't get %s property on /memory\n",
-		       name);
-		return 0;
-	}
-	s /= (nsc + nac) * 4;
-	rp = mp->regions;
-	for (i = 0; i < s; ++i, ip += nac+nsc) {
-		if (nac >= 2 && ip[nac-2] != 0)
-			continue;
-		rp->address = ip[nac-1];
-		if (nsc >= 2 && ip[nac+nsc-2] != 0)
-			rp->size = ~0U;
-		else
-			rp->size = ip[nac+nsc-1];
-		++rp;
-	}
-	mp->n_regions = rp - mp->regions;
-
-	/* Make sure the pieces are sorted. */
-	mem_pieces_sort(mp);
-	mem_pieces_coalesce(mp);
-	return 1;
-}
-
-/*
- * On systems with Open Firmware, collect information about
- * physical RAM and which pieces are already in use.
- * At this point, we have (at least) the first 8MB mapped with a BAT.
- * Our text, data, bss use something over 1MB, starting at 0.
- * Open Firmware may be using 1MB at the 4MB point.
- */
-unsigned long __init
-pmac_find_end_of_memory(void)
-{
-	unsigned long a, total;
-	struct mem_pieces phys_mem;
-
-	/*
-	 * Find out where physical memory is, and check that it
-	 * starts at 0 and is contiguous.  It seems that RAM is
-	 * always physically contiguous on Power Macintoshes.
-	 *
-	 * Supporting discontiguous physical memory isn't hard,
-	 * it just makes the virtual <-> physical mapping functions
-	 * more complicated (or else you end up wasting space
-	 * in mem_map).
-	 */
-	memory_node = find_devices("memory");
-	if (memory_node == NULL || !get_mem_prop("reg", &phys_mem)
-	    || phys_mem.n_regions == 0)
-		panic("No RAM??");
-	a = phys_mem.regions[0].address;
-	if (a != 0)
-		panic("RAM doesn't start at physical address 0");
-	total = phys_mem.regions[0].size;
-
-	if (phys_mem.n_regions > 1) {
-		printk("RAM starting at 0x%x is not contiguous\n",
-		       phys_mem.regions[1].address);
-		printk("Using RAM from 0 to 0x%lx\n", total-1);
-	}
-
-	return total;
-}
-
-void __init
-select_adb_keyboard(void)
-{
-#ifdef CONFIG_VT
-#ifdef CONFIG_INPUT
-	ppc_md.kbd_init_hw       = mac_hid_init_hw;
-	ppc_md.kbd_translate     = mac_hid_kbd_translate;
-	ppc_md.kbd_unexpected_up = mac_hid_kbd_unexpected_up;
-	ppc_md.kbd_setkeycode    = 0;
-	ppc_md.kbd_getkeycode    = 0;
-	ppc_md.kbd_leds		 = 0;
-#ifdef CONFIG_MAGIC_SYSRQ
-#ifdef CONFIG_MAC_ADBKEYCODES
-	if (!keyboard_sends_linux_keycodes) {
-		ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate;
-		SYSRQ_KEY = 0x69;
-	} else
-#endif /* CONFIG_MAC_ADBKEYCODES */
-	{
-		ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
-		SYSRQ_KEY = 0x54;
-	}
-#endif /* CONFIG_MAGIC_SYSRQ */
-#elif defined(CONFIG_ADB_KEYBOARD)
-	ppc_md.kbd_setkeycode       = mackbd_setkeycode;
-	ppc_md.kbd_getkeycode       = mackbd_getkeycode;
-	ppc_md.kbd_translate        = mackbd_translate;
-	ppc_md.kbd_unexpected_up    = mackbd_unexpected_up;
-	ppc_md.kbd_leds             = mackbd_leds;
-	ppc_md.kbd_init_hw          = mackbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.ppc_kbd_sysrq_xlate  = mackbd_sysrq_xlate;
-	SYSRQ_KEY = 0x69;
-#endif /* CONFIG_MAGIC_SYSRQ */
-#endif /* CONFIG_INPUT_ADBHID/CONFIG_ADB_KEYBOARD */
-#endif /* CONFIG_VT */
-}
-
-void __init
-pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
-	  unsigned long r6, unsigned long r7)
-{
-	/* isa_io_base gets set in pmac_find_bridges */
-	isa_mem_base = PMAC_ISA_MEM_BASE;
-	pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
-	ISA_DMA_THRESHOLD = ~0L;
-	DMA_MODE_READ = 1;
-	DMA_MODE_WRITE = 2;
-
-	ppc_md.setup_arch     = pmac_setup_arch;
-	ppc_md.show_cpuinfo   = pmac_show_cpuinfo;
-	ppc_md.show_percpuinfo = of_show_percpuinfo;
-	ppc_md.irq_cannonicalize = NULL;
-	ppc_md.init_IRQ       = pmac_pic_init;
-	ppc_md.get_irq        = pmac_get_irq; /* Changed later on ... */
-	ppc_md.init           = pmac_init2;
-	
-	ppc_md.pcibios_fixup  = pmac_pcibios_fixup;
-	ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook;
-	ppc_md.pcibios_after_init = pmac_pcibios_after_init;
-
-	ppc_md.discover_root  = pmac_discover_root;
-
-	ppc_md.restart        = pmac_restart;
-	ppc_md.power_off      = pmac_power_off;
-	ppc_md.halt           = pmac_halt;
-
-	ppc_md.time_init      = pmac_time_init;
-	ppc_md.set_rtc_time   = pmac_set_rtc_time;
-	ppc_md.get_rtc_time   = pmac_get_rtc_time;
-	ppc_md.calibrate_decr = pmac_calibrate_decr;
-
-	ppc_md.find_end_of_memory = pmac_find_end_of_memory;
-
-	ppc_md.feature_call   = pmac_do_feature_call;
-
-	select_adb_keyboard();
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.ide_check_region	= pmac_ide_check_region;
-        ppc_ide_md.ide_request_region	= pmac_ide_request_region;
-        ppc_ide_md.ide_release_region	= pmac_ide_release_region;
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-        ppc_ide_md.ide_init_hwif	= pmac_ide_init_hwif_ports;
-        ppc_ide_md.default_io_base	= pmac_ide_get_base;
-#else /* CONFIG_BLK_DEV_IDE_PMAC */
-        ppc_ide_md.ide_init_hwif	= pmac_ide_pci_init_hwif_ports;
-#endif /* CONFIG_BLK_DEV_IDE_PMAC */
-#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
-
-#ifdef CONFIG_BOOTX_TEXT
-	ppc_md.progress = pmac_progress;
-#endif /* CONFIG_BOOTX_TEXT */
-
-	if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0);
-	
-}
-
-#ifdef CONFIG_BOOTX_TEXT
-void __init
-pmac_progress(char *s, unsigned short hex)
-{
-	if (boot_text_mapped) {
-		btext_drawstring(s);
-		btext_drawchar('\n');
-	}
-}
-#endif /* CONFIG_BOOTX_TEXT */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/pmac_smp.c linux-2.4.20/arch/ppc/kernel/pmac_smp.c
--- linux-2.4.19/arch/ppc/kernel/pmac_smp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/pmac_smp.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,622 +0,0 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- * SMP support for power macintosh.
- *
- * We support both the old "powersurge" SMP architecture
- * and the current Core99 (G4 PowerMac) machines.
- *
- * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net)
- * and Ben Herrenschmidt <benh@kernel.crashing.org>.
- *
- * Support for DayStar quad CPU cards
- * Copyright (C) XLR8, Inc. 1994-2000
- *
- *  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.
- */
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/delay.h>
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-
-#include <asm/ptrace.h>
-#include <asm/atomic.h>
-#include <asm/irq.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/hardirq.h>
-#include <asm/softirq.h>
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/smp.h>
-#include <asm/residual.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/time.h>
-#include <asm/gemini.h>
-#include <asm/processor.h>
-
-#include "open_pic.h"
-
-/*
- * Powersurge (old powermac SMP) support.
- */
-
-extern void __secondary_start_psurge(void);
-extern void __secondary_start_psurge2(void);	/* Temporary horrible hack */
-extern void __secondary_start_psurge3(void);	/* Temporary horrible hack */
-
-/* Addresses for powersurge registers */
-#define HAMMERHEAD_BASE		0xf8000000
-#define HHEAD_CONFIG		0x90
-#define HHEAD_SEC_INTR		0xc0
-
-/* register for interrupting the primary processor on the powersurge */
-/* N.B. this is actually the ethernet ROM! */
-#define PSURGE_PRI_INTR		0xf3019000
-
-/* register for storing the start address for the secondary processor */
-/* N.B. this is the PCI config space address register for the 1st bridge */
-#define PSURGE_START		0xf2800000
-
-/* Daystar/XLR8 4-CPU card */
-#define PSURGE_QUAD_REG_ADDR	0xf8800000
-
-#define PSURGE_QUAD_IRQ_SET	0
-#define PSURGE_QUAD_IRQ_CLR	1
-#define PSURGE_QUAD_IRQ_PRIMARY	2
-#define PSURGE_QUAD_CKSTOP_CTL	3
-#define PSURGE_QUAD_PRIMARY_ARB	4
-#define PSURGE_QUAD_BOARD_ID	6
-#define PSURGE_QUAD_WHICH_CPU	7
-#define PSURGE_QUAD_CKSTOP_RDBK	8
-#define PSURGE_QUAD_RESET_CTL	11
-
-#define PSURGE_QUAD_OUT(r, v)	(out_8(quad_base + ((r) << 4) + 4, (v)))
-#define PSURGE_QUAD_IN(r)	(in_8(quad_base + ((r) << 4) + 4) & 0x0f)
-#define PSURGE_QUAD_BIS(r, v)	(PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v)))
-#define PSURGE_QUAD_BIC(r, v)	(PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v)))
-
-/* virtual addresses for the above */
-static volatile u8 *hhead_base;
-static volatile u8 *quad_base;
-static volatile u32 *psurge_pri_intr;
-static volatile u8 *psurge_sec_intr;
-static volatile u32 *psurge_start;
-
-/* what sort of powersurge board we have */
-static int psurge_type;
-
-/* values for psurge_type */
-#define PSURGE_DUAL		0
-#define PSURGE_QUAD_OKEE	1
-#define PSURGE_QUAD_COTTON	2
-#define PSURGE_QUAD_ICEGRASS	3
-
-volatile static long int core99_l2_cache;
-volatile static long int core99_l3_cache;
-
-static void __init
-core99_init_caches(void)
-{
-	int cpu = smp_processor_id();
-
-	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
-		return;
-
-	if (cpu == 0){
-		core99_l2_cache = _get_L2CR();
-		printk("CPU0: L2CR is %lx\n", core99_l2_cache);
-	} else {
-		printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());
-		_set_L2CR(0);
-		_set_L2CR(core99_l2_cache);
-		printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);
-	}
-
-	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR))
-		return;
-
-	if (cpu == 0){
-		core99_l3_cache = _get_L3CR();
-		printk("CPU0: L3CR is %lx\n", core99_l3_cache);
-	} else {
-		printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR());
-		_set_L3CR(0);
-		_set_L3CR(core99_l3_cache);
-		printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache);
-	}
-}
-
-/* Some CPU registers have to be saved from the first CPU and
- * applied to others. Note that we override what is setup by
- * the cputable intentionally.
- */
-
-#define	reg_hid0	0
-#define	reg_hid1	1
-#define	reg_msscr0	2
-#define	reg_msssr0	3
-#define	reg_ictrl	4
-#define	reg_ldstcr	5
-#define	reg_ldstdb	6
-#define	reg_count	7
-
-static unsigned long cpu_regs[reg_count];
-
-static void __pmac
-cpu_setup_grab(void)
-{
-	unsigned int pvers = mfspr(SPRN_PVR)>>16;
-
-	/* Read cache setting of CPU 0 */
-	core99_init_caches();
-
-	/* 7400/7410/7450 */
-	if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) {
-		cpu_regs[reg_hid0] = mfspr(SPRN_HID0);
-		cpu_regs[reg_msscr0] = mfspr(SPRN_MSSCR0);
-		cpu_regs[reg_msssr0] = mfspr(SPRN_MSSSR0);
-	}
-	/* 7450 only */
-	if (pvers == 0x8000) {
-		cpu_regs[reg_hid1] = mfspr(SPRN_HID1);
-		cpu_regs[reg_ictrl] = mfspr(SPRN_ICTRL);
-		cpu_regs[reg_ldstcr] = mfspr(SPRN_LDSTCR);
-		cpu_regs[reg_ldstdb] = mfspr(SPRN_LDSTDB);
-	}
-	flush_dcache_range((unsigned long)cpu_regs, (unsigned long)&cpu_regs[reg_count]);
-}
-
-static void __pmac
-cpu_setup_apply(int cpu_nr)
-{
-	unsigned int pvers = mfspr(SPRN_PVR)>>16;
-
-	/* Apply cache setting from CPU 0 */
-	core99_init_caches();
-
-	/* 7400/7410/7450 */
-	if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) {
-		unsigned long tmp;
-		__asm__ __volatile__ (
-			"lwz	%0,4*"stringify(reg_hid0)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_HID0)", %0\n"
-			"isync;sync\n"
-			"lwz	%0, 4*"stringify(reg_msscr0)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_MSSCR0)", %0\n"
-			"isync;sync\n"
-//			"lwz	%0, "stringify(reg_msssr0)"(%1)\n"
-//			"sync\n"
-//			"mtspr	"stringify(SPRN_MSSSR0)", %0\n"
-//			"isync;sync\n"
-		: "=&r" (tmp) : "r" (cpu_regs));			
-	}
-	/* 7410 only */
-	if (pvers == 0x800c) {
-		unsigned long tmp;
-		__asm__ __volatile__ (
-			"li	%0, 0\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_L2CR2)", %0\n"
-			"isync;sync\n"
-		: "=&r" (tmp));		
-	}
-	/* 7450 only */
-	if (pvers == 0x8000) {
-		unsigned long tmp;
-		__asm__ __volatile__ (
-			"lwz	%0, 4*"stringify(reg_hid1)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_HID1)", %0\n"
-			"isync;sync\n"
-			"lwz	%0, 4*"stringify(reg_ictrl)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_ICTRL)", %0\n"
-			"isync;sync\n"
-			"lwz	%0, 4*"stringify(reg_ldstcr)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_LDSTCR)", %0\n"
-			"isync;sync\n"
-			"lwz	%0, 4*"stringify(reg_ldstdb)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_LDSTDB)", %0\n"
-			"isync;sync\n"
-		: "=&r" (tmp) : "r" (cpu_regs));		
-	}
-}
-
-/*
- * Set and clear IPIs for powersurge.
- */
-static inline void psurge_set_ipi(int cpu)
-{
-	if (cpu == 0)
-		in_be32(psurge_pri_intr);
-	else if (psurge_type == PSURGE_DUAL)
-		out_8(psurge_sec_intr, 0);
-	else
-		PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_SET, 1 << cpu);
-}
-
-static inline void psurge_clr_ipi(int cpu)
-{
-	if (cpu > 0) {
-		if (psurge_type == PSURGE_DUAL)
-			out_8(psurge_sec_intr, ~0);
-		else
-			PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu);
-	}
-}
-
-/*
- * On powersurge (old SMP powermac architecture) we don't have
- * separate IPIs for separate messages like openpic does.  Instead
- * we have a bitmap for each processor, where a 1 bit means that
- * the corresponding message is pending for that processor.
- * Ideally each cpu's entry would be in a different cache line.
- *  -- paulus.
- */
-static unsigned long psurge_smp_message[NR_CPUS];
-
-void __pmac
-psurge_smp_message_recv(struct pt_regs *regs)
-{
-	int cpu = smp_processor_id();
-	int msg;
-
-	/* clear interrupt */
-	psurge_clr_ipi(cpu);
-
-	if (smp_num_cpus < 2)
-		return;
-
-	/* make sure there is a message there */
-	for (msg = 0; msg < 4; msg++)
-		if (test_and_clear_bit(msg, &psurge_smp_message[cpu]))
-			smp_message_recv(msg, regs);
-}
-
-void __pmac
-psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
-{
-	psurge_smp_message_recv(regs);
-}
-
-static void __pmac
-smp_psurge_message_pass(int target, int msg, unsigned long data, int wait)
-{
-	int i;
-
-	if (smp_num_cpus < 2)
-		return;
-
-	for (i = 0; i < smp_num_cpus; i++) {
-		if (target == MSG_ALL
-		    || (target == MSG_ALL_BUT_SELF && i != smp_processor_id())
-		    || target == i) {
-			set_bit(msg, &psurge_smp_message[i]);
-			psurge_set_ipi(i);
-		}
-	}
-}
-
-/*
- * Determine a quad card presence. We read the board ID register, we
- * force the data bus to change to something else, and we read it again.
- * It it's stable, then the register probably exist (ugh !)
- */
-static int __init psurge_quad_probe(void)
-{
-	int type;
-	unsigned int i;
-
-	type = PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID);
-	if (type < PSURGE_QUAD_OKEE || type > PSURGE_QUAD_ICEGRASS
-	    || type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
-		return PSURGE_DUAL;
-
-	/* looks OK, try a slightly more rigorous test */
-	/* bogus is not necessarily cacheline-aligned,
-	   though I don't suppose that really matters.  -- paulus */
-	for (i = 0; i < 100; i++) {
-		volatile u32 bogus[8];
-		bogus[(0+i)%8] = 0x00000000;
-		bogus[(1+i)%8] = 0x55555555;
-		bogus[(2+i)%8] = 0xFFFFFFFF;
-		bogus[(3+i)%8] = 0xAAAAAAAA;
-		bogus[(4+i)%8] = 0x33333333;
-		bogus[(5+i)%8] = 0xCCCCCCCC;
-		bogus[(6+i)%8] = 0xCCCCCCCC;
-		bogus[(7+i)%8] = 0x33333333;
-		wmb();
-		asm volatile("dcbf 0,%0" : : "r" (bogus) : "memory");
-		mb();
-		if (type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
-			return PSURGE_DUAL;
-	}
-	return type;
-}
-
-static void __init psurge_quad_init(void)
-{
-	int procbits;
-
-	if (ppc_md.progress) ppc_md.progress("psurge_quad_init", 0x351);
-	procbits = ~PSURGE_QUAD_IN(PSURGE_QUAD_WHICH_CPU);
-	if (psurge_type == PSURGE_QUAD_ICEGRASS)
-		PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
-	else
-		PSURGE_QUAD_BIC(PSURGE_QUAD_CKSTOP_CTL, procbits);
-	mdelay(33);
-	out_8(psurge_sec_intr, ~0);
-	PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, procbits);
-	PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
-	if (psurge_type != PSURGE_QUAD_ICEGRASS)
-		PSURGE_QUAD_BIS(PSURGE_QUAD_CKSTOP_CTL, procbits);
-	PSURGE_QUAD_BIC(PSURGE_QUAD_PRIMARY_ARB, procbits);
-	mdelay(33);
-	PSURGE_QUAD_BIC(PSURGE_QUAD_RESET_CTL, procbits);
-	mdelay(33);
-	PSURGE_QUAD_BIS(PSURGE_QUAD_PRIMARY_ARB, procbits);
-	mdelay(33);
-}
-
-static int __init smp_psurge_probe(void)
-{
-	int i, ncpus;
-
-	/* We don't do SMP on the PPC601 -- paulus */
-	if (PVR_VER(mfspr(PVR)) == 1)
-		return 1;
-
-	/*
-	 * The powersurge cpu board can be used in the generation
-	 * of powermacs that have a socket for an upgradeable cpu card,
-	 * including the 7500, 8500, 9500, 9600.
-	 * The device tree doesn't tell you if you have 2 cpus because
-	 * OF doesn't know anything about the 2nd processor.
-	 * Instead we look for magic bits in magic registers,
-	 * in the hammerhead memory controller in the case of the
-	 * dual-cpu powersurge board.  -- paulus.
-	 */
-	if (find_devices("hammerhead") == NULL)
-		return 1;
-
-	hhead_base = ioremap(HAMMERHEAD_BASE, 0x800);
-	quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024);
-	psurge_sec_intr = hhead_base + HHEAD_SEC_INTR;
-
-	psurge_type = psurge_quad_probe();
-	if (psurge_type != PSURGE_DUAL) {
-		psurge_quad_init();
-		/* All released cards using this HW design have 4 CPUs */
-		ncpus = 4;
-	} else {
-		iounmap((void *) quad_base);
-		if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {
-			/* not a dual-cpu card */
-			iounmap((void *) hhead_base);
-			return 1;
-		}
-		ncpus = 2;
-	}
-
-	psurge_start = ioremap(PSURGE_START, 4);
-	psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);
-
-	/* this is not actually strictly necessary -- paulus. */
-	for (i = 1; i < ncpus; ++i)
-		smp_hw_index[i] = i;
-
-	if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);
-
-	return ncpus;
-}
-
-static void __init smp_psurge_kick_cpu(int nr)
-{
-	void (*start)(void) = __secondary_start_psurge;
-	unsigned long a;
-
-	/* may need to flush here if secondary bats aren't setup */
-	for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
-		asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
-	asm volatile("sync");
-
-	if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353);
-
-	/* setup entry point of secondary processor */
-	switch (nr) {
-	case 2:
-		start = __secondary_start_psurge2;
-		break;
-	case 3:
-		start = __secondary_start_psurge3;
-		break;
-	}
-
-	out_be32(psurge_start, __pa(start));
-	mb();
-
-	psurge_set_ipi(nr);
-	udelay(10);
-	psurge_clr_ipi(nr);
-
-	if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
-}
-
-/*
- * With the dual-cpu powersurge board, the decrementers and timebases
- * of both cpus are frozen after the secondary cpu is started up,
- * until we give the secondary cpu another interrupt.  This routine
- * uses this to get the timebases synchronized.
- *  -- paulus.
- */
-static void __init psurge_dual_sync_tb(int cpu_nr)
-{
-	static volatile int sec_tb_reset = 0;
-	int t;
-
-	set_dec(tb_ticks_per_jiffy);
-	set_tb(0, 0);
-	last_jiffy_stamp(cpu_nr) = 0;
-
-	if (cpu_nr > 0) {
-		mb();
-		sec_tb_reset = 1;
-		return;
-	}
-
-	/* wait for the secondary to have reset its TB before proceeding */
-	for (t = 10000000; t > 0 && !sec_tb_reset; --t)
-		;
-
-	/* now interrupt the secondary, starting both TBs */
-	psurge_set_ipi(1);
-
-	smp_tb_synchronized = 1;
-}
-
-static void __init
-smp_psurge_setup_cpu(int cpu_nr)
-{
-
-	if (cpu_nr == 0) {
-		if (smp_num_cpus < 2)
-			return;
-		/* reset the entry point so if we get another intr we won't
-		 * try to startup again */
-		out_be32(psurge_start, 0x100);
-		if (request_irq(30, psurge_primary_intr, 0, "primary IPI", 0))
-			printk(KERN_ERR "Couldn't get primary IPI interrupt");
-	}
-
-	if (psurge_type == PSURGE_DUAL)
-		psurge_dual_sync_tb(cpu_nr);
-}
-
-static int __init
-smp_core99_probe(void)
-{
-	struct device_node *cpus;
-	int i, ncpus = 1;
-	extern int powersave_nap;
-
-	if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
-	cpus = find_type_devices("cpu");
-	if (cpus)
-		while ((cpus = cpus->next) != NULL)
-			++ncpus;
-	printk("smp_core99_probe: found %d cpus\n", ncpus);
-	if (ncpus > 1) {
-		openpic_request_IPIs();
-		for (i = 1; i < ncpus; ++i)
-			smp_hw_index[i] = i;
-		powersave_nap = 0;
-		cpu_setup_grab();
-	}
-
-	return ncpus;
-}
-
-static void __init
-smp_core99_kick_cpu(int nr)
-{
-	unsigned long save_vector, new_vector;
-	unsigned long flags;
-
-	volatile unsigned long *vector
-		 = ((volatile unsigned long *)(KERNELBASE+0x100));
-	if (nr < 1 || nr > 3)
-		return;
-	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
-
-	local_irq_save(flags);
-	local_irq_disable();
-	
-	/* Save reset vector */
-	save_vector = *vector;
-	
-	/* Setup fake reset vector that does	  
-	 *   b __secondary_start_psurge - KERNELBASE
-	 */  
-	switch(nr) {
-		case 1:
-			new_vector = (unsigned long)__secondary_start_psurge;
-			break;
-		case 2:
-			new_vector = (unsigned long)__secondary_start_psurge2;
-			break;
-		case 3:
-			new_vector = (unsigned long)__secondary_start_psurge3;
-			break;
-	}
-	*vector = 0x48000002 + new_vector - KERNELBASE;
-	
-	/* flush data cache and inval instruction cache */
-	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
-	
-	/* Put some life in our friend */
-	pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
-	
-	/* FIXME: We wait a bit for the CPU to take the exception, I should
-	 * instead wait for the entry code to set something for me. Well,
-	 * ideally, all that crap will be done in prom.c and the CPU left
-	 * in a RAM-based wait loop like CHRP.
-	 */
-	mdelay(1);
-	
-	/* Restore our exception vector */
-	*vector = save_vector;
-	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
-	
-	local_irq_restore(flags);
-	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
-}
-
-static void __init
-smp_core99_setup_cpu(int cpu_nr)
-{
-	/* Setup some registers */
-	if (cpu_nr != 0)
-		cpu_setup_apply(cpu_nr);
-	
-	/* Setup openpic */
-	do_openpic_setup_cpu();
-
-	/* Setup L2/L3 */
-	if (cpu_nr == 0)
-		if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
-}
-
-/* PowerSurge-style Macs */
-struct smp_ops_t psurge_smp_ops __pmacdata = {
-	smp_psurge_message_pass,
-	smp_psurge_probe,
-	smp_psurge_kick_cpu,
-	smp_psurge_setup_cpu,
-};
-
-/* Core99 Macs (dual G4s) */
-struct smp_ops_t core99_smp_ops __pmacdata = {
-	smp_openpic_message_pass,
-	smp_core99_probe,
-	smp_core99_kick_cpu,
-	smp_core99_setup_cpu,
-};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/pmac_time.c linux-2.4.20/arch/ppc/kernel/pmac_time.c
--- linux-2.4.19/arch/ppc/kernel/pmac_time.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/pmac_time.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,282 +0,0 @@
-/*
- * BK Id: SCCS/s.pmac_time.c 1.19 12/04/01 01:24:51 benh
- */
-/*
- * Support for periodic interrupts (100 per second) and for getting
- * the current time from the RTC on Power Macintoshes.
- *
- * We use the decrementer register for our periodic interrupts.
- *
- * Paul Mackerras	August 1996.
- * Copyright (C) 1996 Paul Mackerras.
- */
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/adb.h>
-#include <linux/cuda.h>
-#include <linux/pmu.h>
-
-#include <asm/sections.h>
-#include <asm/prom.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/machdep.h>
-#include <asm/hardirq.h>
-#include <asm/time.h>
-#include <asm/nvram.h>
-
-extern rwlock_t xtime_lock;
-
-/* Apparently the RTC stores seconds since 1 Jan 1904 */
-#define RTC_OFFSET	2082844800
-
-/*
- * Calibrate the decrementer frequency with the VIA timer 1.
- */
-#define VIA_TIMER_FREQ_6	4700000	/* time 1 frequency * 6 */
-
-/* VIA registers */
-#define RS		0x200		/* skip between registers */
-#define T1CL		(4*RS)		/* Timer 1 ctr/latch (low 8 bits) */
-#define T1CH		(5*RS)		/* Timer 1 counter (high 8 bits) */
-#define T1LL		(6*RS)		/* Timer 1 latch (low 8 bits) */
-#define T1LH		(7*RS)		/* Timer 1 latch (high 8 bits) */
-#define ACR		(11*RS)		/* Auxiliary control register */
-#define IFR		(13*RS)		/* Interrupt flag register */
-
-/* Bits in ACR */
-#define T1MODE		0xc0		/* Timer 1 mode */
-#define T1MODE_CONT	0x40		/*  continuous interrupts */
-
-/* Bits in IFR and IER */
-#define T1_INT		0x40		/* Timer 1 interrupt */
-
-extern struct timezone sys_tz;
-
-long __init
-pmac_time_init(void)
-{
-#ifdef CONFIG_NVRAM
-	s32 delta = 0;
-	int dst;
-	
-	delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
-	delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8;
-	delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb);
-	if (delta & 0x00800000UL)
-		delta |= 0xFF000000UL;
-	dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
-	printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
-		dst ? "on" : "off");
-	return delta;
-#else
-	return 0;
-#endif
-}
-
-unsigned long __pmac
-pmac_get_rtc_time(void)
-{
-#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
-	struct adb_request req;
-	unsigned long now;
-#endif
-
-	/* Get the time from the RTC */
-	switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
-	case SYS_CTRLER_CUDA:
-		if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
-			return 0;
-		while (!req.complete)
-			cuda_poll();
-		if (req.reply_len != 7)
-			printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
-			       req.reply_len);
-		now = (req.reply[3] << 24) + (req.reply[4] << 16)
-			+ (req.reply[5] << 8) + req.reply[6];
-		return now - RTC_OFFSET;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
-	case SYS_CTRLER_PMU:
-		if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
-			return 0;
-		while (!req.complete)
-			pmu_poll();
-		if (req.reply_len != 4)
-			printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
-			       req.reply_len);
-		now = (req.reply[0] << 24) + (req.reply[1] << 16)
-			+ (req.reply[2] << 8) + req.reply[3];
-		return now - RTC_OFFSET;
-#endif /* CONFIG_ADB_PMU */
-	default: ;
-	}
-	return 0;
-}
-
-int __pmac
-pmac_set_rtc_time(unsigned long nowtime)
-{
-#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
-	struct adb_request req;
-#endif
-
-	nowtime += RTC_OFFSET;
-
-	switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
-	case SYS_CTRLER_CUDA:
-		if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
-				 nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
-			return 0;
-		while (!req.complete)
-			cuda_poll();
-		if ((req.reply_len != 3) && (req.reply_len != 7))
-			printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
-			       req.reply_len);
-		return 1;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
-	case SYS_CTRLER_PMU:
-		if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
-				nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
-			return 0;
-		while (!req.complete)
-			pmu_poll();
-		if (req.reply_len != 0)
-			printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
-			       req.reply_len);
-		return 1;
-#endif /* CONFIG_ADB_PMU */
-	default:
-		return 0;
-	}
-}
-
-/*
- * Calibrate the decrementer register using VIA timer 1.
- * This is used both on powermacs and CHRP machines.
- */
-int __init
-via_calibrate_decr(void)
-{
-	struct device_node *vias;
-	volatile unsigned char *via;
-	int count = VIA_TIMER_FREQ_6 / HZ;
-	unsigned int dstart, dend;
-
-	vias = find_devices("via-cuda");
-	if (vias == 0)
-		vias = find_devices("via-pmu");
-	if (vias == 0)
-		vias = find_devices("via");
-	if (vias == 0 || vias->n_addrs == 0)
-		return 0;
-	via = (volatile unsigned char *)
-		ioremap(vias->addrs[0].address, vias->addrs[0].size);
-
-	/* set timer 1 for continuous interrupts */
-	out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
-	/* set the counter to a small value */
-	out_8(&via[T1CH], 2);
-	/* set the latch to `count' */
-	out_8(&via[T1LL], count);
-	out_8(&via[T1LH], count >> 8);
-	/* wait until it hits 0 */
-	while ((in_8(&via[IFR]) & T1_INT) == 0)
-		;
-	dstart = get_dec();
-	/* clear the interrupt & wait until it hits 0 again */
-	in_8(&via[T1CL]);
-	while ((in_8(&via[IFR]) & T1_INT) == 0)
-		;
-	dend = get_dec();
-
-	tb_ticks_per_jiffy = (dstart - dend) / 6;
-	tb_to_us = mulhwu_scale_factor(dstart - dend, 60000);
-
-	printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n",
-	       tb_ticks_per_jiffy, dstart - dend);
-
-	return 1;
-}
-
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * Reset the time after a sleep.
- */
-static int __pmac
-time_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
-	static unsigned long time_diff;
-	unsigned long flags;
-
-	switch (when) {
-	case PBOOK_SLEEP_NOW:
-		read_lock_irqsave(&xtime_lock, flags);
-		time_diff = xtime.tv_sec - pmac_get_rtc_time();
-		read_unlock_irqrestore(&xtime_lock, flags);
-		break;
-	case PBOOK_WAKE:
-		write_lock_irqsave(&xtime_lock, flags);
-		xtime.tv_sec = pmac_get_rtc_time() + time_diff;
-		xtime.tv_usec = 0;
-		last_rtc_update = xtime.tv_sec;
-		write_unlock_irqrestore(&xtime_lock, flags);
-		break;
-	}
-	return PBOOK_SLEEP_OK;
-}
-
-static struct pmu_sleep_notifier time_sleep_notifier __pmacdata = {
-	time_sleep_notify, SLEEP_LEVEL_MISC,
-};
-#endif /* CONFIG_PMAC_PBOOK */
-
-/*
- * Query the OF and get the decr frequency.
- * This was taken from the pmac time_init() when merging the prep/pmac
- * time functions.
- */
-void __init
-pmac_calibrate_decr(void)
-{
-	struct device_node *cpu;
-	unsigned int freq, *fp;
-
-#ifdef CONFIG_PMAC_PBOOK
-	pmu_register_sleep_notifier(&time_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-
-	/* We assume MacRISC2 machines have correct device-tree
-	 * calibration. That's better since the VIA itself seems
-	 * to be slightly off. --BenH
-	 */
-	if (!machine_is_compatible("MacRISC2"))
-		if (via_calibrate_decr())
-			return;
-
-	/*
-	 * The cpu node should have a timebase-frequency property
-	 * to tell us the rate at which the decrementer counts.
-	 */
-	cpu = find_type_devices("cpu");
-	if (cpu == 0)
-		panic("can't find cpu node in time_init");
-	fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL);
-	if (fp == 0)
-		panic("can't get cpu timebase frequency");
-	freq = *fp;
-	printk("time_init: decrementer frequency = %u.%.6u MHz\n",
-	       freq/1000000, freq%1000000);
-	tb_ticks_per_jiffy = freq / HZ;
-	tb_to_us = mulhwu_scale_factor(freq, 1000000);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/ppc4xx_pic.c linux-2.4.20/arch/ppc/kernel/ppc4xx_pic.c
--- linux-2.4.19/arch/ppc/kernel/ppc4xx_pic.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/ppc4xx_pic.c	2002-10-29 11:18:30.000000000 +0000
@@ -33,10 +33,7 @@
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/irq.h>
-
-#include "local_irq.h"
-#include "ppc4xx_pic.h"
-
+#include <asm/ppc4xx_pic.h>
 
 /* Global Variables */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/ppc4xx_pic.h linux-2.4.20/arch/ppc/kernel/ppc4xx_pic.h
--- linux-2.4.19/arch/ppc/kernel/ppc4xx_pic.h	2001-07-02 21:34:57.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/ppc4xx_pic.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,30 +0,0 @@
-/*
- * BK Id: SCCS/s.ppc4xx_pic.h 1.8 06/15/01 13:56:56 paulus
- */
-/*
- *
- *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: ppc4xx_pic.h
- *
- *    Description:
- *      Interrupt controller driver for PowerPC 4xx-based processors.
- */
-
-#ifndef	__PPC4XX_PIC_H__
-#define	__PPC4XX_PIC_H__
-
-#include <linux/config.h>
-#include "local_irq.h"
-
-/* External Global Variables */
-
-extern struct hw_interrupt_type *ppc4xx_pic;
-
-
-/* Function Prototypes */
-
-extern void	 ppc4xx_pic_init(void);
-extern int	 ppc4xx_pic_get_irq(struct pt_regs *regs);
-
-#endif /* __PPC4XX_PIC_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/ppc8260_pic.h linux-2.4.20/arch/ppc/kernel/ppc8260_pic.h
--- linux-2.4.19/arch/ppc/kernel/ppc8260_pic.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/ppc8260_pic.h	2002-10-29 11:18:39.000000000 +0000
@@ -1,11 +1,11 @@
 /*
- * BK Id: SCCS/s.ppc8260_pic.h 1.7 05/17/01 18:14:21 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 
 #ifndef _PPC_KERNEL_PPC8260_H
 #define _PPC_KERNEL_PPC8260_H
 
-#include "local_irq.h"
+#include <linux/irq.h>
 
 extern struct hw_interrupt_type ppc8260_pic;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/ppc8xx_pic.h linux-2.4.20/arch/ppc/kernel/ppc8xx_pic.h
--- linux-2.4.19/arch/ppc/kernel/ppc8xx_pic.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/ppc8xx_pic.h	2002-10-29 11:18:39.000000000 +0000
@@ -1,11 +1,11 @@
 /*
- * BK Id: SCCS/s.ppc8xx_pic.h 1.7 05/17/01 18:14:21 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #ifndef _PPC_KERNEL_PPC8xx_H
 #define _PPC_KERNEL_PPC8xx_H
 
 #include <linux/config.h>
-#include "local_irq.h"
+#include <linux/irq.h>
 
 extern struct hw_interrupt_type ppc8xx_pic;
 
@@ -15,7 +15,7 @@
 int m8xx_get_irq(struct pt_regs *regs);
 
 #ifdef CONFIG_MBX
-#include "i8259.h"
+#include <asm/i8259.h>
 #include <asm/io.h>
 void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs);
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/ppc_asm.h linux-2.4.20/arch/ppc/kernel/ppc_asm.h
--- linux-2.4.19/arch/ppc/kernel/ppc_asm.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/ppc_asm.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,159 +0,0 @@
-/*
- * BK Id: SCCS/s.ppc_asm.h 1.20 03/19/02 15:04:39 benh
- */
-/*
- * arch/ppc/kernel/ppc_asm.h
- *
- * Definitions used by various bits of low-level assembly code on PowerPC.
- *
- * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan.
- *
- *  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.
- */
-
-#include <linux/config.h>
-
-#include "ppc_asm.tmpl"
-#include "ppc_defs.h"
-
-/*
- * Macros for storing registers into and loading registers from
- * exception frames.
- */
-#define SAVE_GPR(n, base)	stw	n,GPR0+4*(n)(base)
-#define SAVE_2GPRS(n, base)	SAVE_GPR(n, base); SAVE_GPR(n+1, base)
-#define SAVE_4GPRS(n, base)	SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
-#define SAVE_8GPRS(n, base)	SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
-#define SAVE_10GPRS(n, base)	SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
-#define REST_GPR(n, base)	lwz	n,GPR0+4*(n)(base)
-#define REST_2GPRS(n, base)	REST_GPR(n, base); REST_GPR(n+1, base)
-#define REST_4GPRS(n, base)	REST_2GPRS(n, base); REST_2GPRS(n+2, base)
-#define REST_8GPRS(n, base)	REST_4GPRS(n, base); REST_4GPRS(n+4, base)
-#define REST_10GPRS(n, base)	REST_8GPRS(n, base); REST_2GPRS(n+8, base)
-
-#define SAVE_FPR(n, base)	stfd	n,THREAD_FPR0+8*(n)(base)
-#define SAVE_2FPRS(n, base)	SAVE_FPR(n, base); SAVE_FPR(n+1, base)
-#define SAVE_4FPRS(n, base)	SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
-#define SAVE_8FPRS(n, base)	SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base)
-#define SAVE_16FPRS(n, base)	SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base)
-#define SAVE_32FPRS(n, base)	SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base)
-#define REST_FPR(n, base)	lfd	n,THREAD_FPR0+8*(n)(base)
-#define REST_2FPRS(n, base)	REST_FPR(n, base); REST_FPR(n+1, base)
-#define REST_4FPRS(n, base)	REST_2FPRS(n, base); REST_2FPRS(n+2, base)
-#define REST_8FPRS(n, base)	REST_4FPRS(n, base); REST_4FPRS(n+4, base)
-#define REST_16FPRS(n, base)	REST_8FPRS(n, base); REST_8FPRS(n+8, base)
-#define REST_32FPRS(n, base)	REST_16FPRS(n, base); REST_16FPRS(n+16, base)
-
-/*
- * Once a version of gas that understands the AltiVec instructions
- * is freely available, we can do this the normal way...  - paulus
- */
-#define LVX(r,a,b)	.long	(31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(103<<1)
-#define STVX(r,a,b)	.long	(31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(231<<1)
-#define MFVSCR(r)	.long	(4<<26)+((r)<<21)+(770<<1)
-#define MTVSCR(r)	.long	(4<<26)+((r)<<11)+(802<<1)
-#define DSSALL		.long	(0x1f<<26)+(0x10<<21)+(0x336<<1)
-
-#define SAVE_VR(n,b,base)	li b,THREAD_VR0+(16*(n)); STVX(n,b,base)
-#define SAVE_2VR(n,b,base)	SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) 
-#define SAVE_4VR(n,b,base)	SAVE_2VR(n,b,base); SAVE_2VR(n+2,b,base) 
-#define SAVE_8VR(n,b,base)	SAVE_4VR(n,b,base); SAVE_4VR(n+4,b,base) 
-#define SAVE_16VR(n,b,base)	SAVE_8VR(n,b,base); SAVE_8VR(n+8,b,base)
-#define SAVE_32VR(n,b,base)	SAVE_16VR(n,b,base); SAVE_16VR(n+16,b,base)
-#define REST_VR(n,b,base)	li b,THREAD_VR0+(16*(n)); LVX(n,b,base)
-#define REST_2VR(n,b,base)	REST_VR(n,b,base); REST_VR(n+1,b,base) 
-#define REST_4VR(n,b,base)	REST_2VR(n,b,base); REST_2VR(n+2,b,base) 
-#define REST_8VR(n,b,base)	REST_4VR(n,b,base); REST_4VR(n+4,b,base) 
-#define REST_16VR(n,b,base)	REST_8VR(n,b,base); REST_8VR(n+8,b,base) 
-#define REST_32VR(n,b,base)	REST_16VR(n,b,base); REST_16VR(n+16,b,base)
-
-#ifdef CONFIG_PPC601_SYNC_FIX
-#define SYNC				\
-BEGIN_FTR_SECTION			\
-	sync;				\
-	isync;				\
-END_FTR_SECTION_IFSET(CPU_FTR_601)
-#define SYNC_601			\
-BEGIN_FTR_SECTION			\
-	sync;				\
-END_FTR_SECTION_IFSET(CPU_FTR_601)
-#define ISYNC_601			\
-BEGIN_FTR_SECTION			\
-	isync;				\
-END_FTR_SECTION_IFSET(CPU_FTR_601)
-#else
-#define	SYNC
-#define SYNC_601
-#define ISYNC_601
-#endif
-
-#ifndef CONFIG_SMP
-#define TLBSYNC
-#else /* CONFIG_SMP */
-/* tlbsync is not implemented on 601 */
-#define TLBSYNC				\
-BEGIN_FTR_SECTION			\
-	tlbsync;			\
-	sync;				\
-END_FTR_SECTION_IFCLR(CPU_FTR_601)
-#endif
-
-/*
- * This instruction is not implemented on the PPC 603 or 601; however, on
- * the 403GCX and 405GP tlbia IS defined and tlbie is not.
- * All of these instructions exist in the 8xx, they have magical powers,
- * and they must be used.
- */
-
-#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
-#define tlbia					\
-	li	r4,1024;			\
-	mtctr	r4;				\
-	lis	r4,KERNELBASE@h;		\
-0:	tlbie	r4;				\
-	addi	r4,r4,0x1000;			\
-	bdnz	0b
-#endif
-
-/*
- * On APUS (Amiga PowerPC cpu upgrade board), we don't know the
- * physical base address of RAM at compile time.
- */
-#define tophys(rd,rs)				\
-0:	addis	rd,rs,-KERNELBASE@h;		\
-	.section ".vtop_fixup","aw";		\
-	.align  1;				\
-	.long   0b;				\
-	.previous
-
-#define tovirt(rd,rs)				\
-0:	addis	rd,rs,KERNELBASE@h;		\
-	.section ".ptov_fixup","aw";		\
-	.align  1;				\
-	.long   0b;				\
-	.previous
-
-/*
- * On 64-bit cpus, we use the rfid instruction instead of rfi, but
- * we then have to make sure we preserve the top 32 bits except for
- * the 64-bit mode bit, which we clear.
- */
-#ifdef CONFIG_PPC64BRIDGE
-#define	FIX_SRR1(ra, rb)	\
-	mr	rb,ra;		\
-	mfmsr	ra;		\
-	clrldi	ra,ra,1;		/* turn off 64-bit mode */ \
-	rldimi	ra,rb,0,32
-#define	RFI		.long	0x4c000024	/* rfid instruction */
-#define MTMSRD(r)	.long	(0x7c000164 + ((r) << 21))	/* mtmsrd */
-#define CLR_TOP32(r)	rlwinm	(r),(r),0,0,31	/* clear top 32 bits */
-
-#else
-#define FIX_SRR1(ra, rb)
-#define	RFI		rfi
-#define MTMSRD(r)	mtmsr	r
-#define CLR_TOP32(r)
-#endif /* CONFIG_PPC64BRIDGE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/ppc_asm.tmpl linux-2.4.20/arch/ppc/kernel/ppc_asm.tmpl
--- linux-2.4.19/arch/ppc/kernel/ppc_asm.tmpl	2000-02-13 18:47:01.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/ppc_asm.tmpl	1970-01-01 00:00:00.000000000 +0000
@@ -1,115 +0,0 @@
-/* Condition Register Bit Fields */
-
-#define	cr0	0
-#define	cr1	1
-#define	cr2	2
-#define	cr3	3
-#define	cr4	4
-#define	cr5	5
-#define	cr6	6
-#define	cr7	7
-
-
-/* General Purpose Registers (GPRs) */
-
-#define	r0	0
-#define	r1	1
-#define	r2	2
-#define	r3	3
-#define	r4	4
-#define	r5	5
-#define	r6	6
-#define	r7	7
-#define	r8	8
-#define	r9	9
-#define	r10	10
-#define	r11	11
-#define	r12	12
-#define	r13	13
-#define	r14	14
-#define	r15	15
-#define	r16	16
-#define	r17	17
-#define	r18	18
-#define	r19	19
-#define	r20	20
-#define	r21	21
-#define	r22	22
-#define	r23	23
-#define	r24	24
-#define	r25	25
-#define	r26	26
-#define	r27	27
-#define	r28	28
-#define	r29	29
-#define	r30	30
-#define	r31	31
-
-
-/* Floating Point Registers (FPRs) */
-
-#define	fr0	0
-#define	fr1	1
-#define	fr2	2
-#define	fr3	3
-#define	fr4	4
-#define	fr5	5
-#define	fr6	6
-#define	fr7	7
-#define	fr8	8
-#define	fr9	9
-#define	fr10	10
-#define	fr11	11
-#define	fr12	12
-#define	fr13	13
-#define	fr14	14
-#define	fr15	15
-#define	fr16	16
-#define	fr17	17
-#define	fr18	18
-#define	fr19	19
-#define	fr20	20
-#define	fr21	21
-#define	fr22	22
-#define	fr23	23
-#define	fr24	24
-#define	fr25	25
-#define	fr26	26
-#define	fr27	27
-#define	fr28	28
-#define	fr29	29
-#define	fr30	30
-#define	fr31	31
-
-#define	vr0	0
-#define	vr1	1
-#define	vr2	2
-#define	vr3	3
-#define	vr4	4
-#define	vr5	5
-#define	vr6	6
-#define	vr7	7
-#define	vr8	8
-#define	vr9	9
-#define	vr10	10
-#define	vr11	11
-#define	vr12	12
-#define	vr13	13
-#define	vr14	14
-#define	vr15	15
-#define	vr16	16
-#define	vr17	17
-#define	vr18	18
-#define	vr19	19
-#define	vr20	20
-#define	vr21	21
-#define	vr22	22
-#define	vr23	23
-#define	vr24	24
-#define	vr25	25
-#define	vr26	26
-#define	vr27	27
-#define	vr28	28
-#define	vr29	29
-#define	vr30	30
-#define	vr31	31
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/ppc_ksyms.c linux-2.4.20/arch/ppc/kernel/ppc_ksyms.c
--- linux-2.4.19/arch/ppc/kernel/ppc_ksyms.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/ppc_ksyms.c	2002-10-29 11:18:50.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.ppc_ksyms.c 1.63 01/20/02 23:53:11 benh
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -17,13 +17,13 @@
 #include <linux/irq.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/ide.h>
 
 #include <asm/page.h>
 #include <asm/semaphore.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <linux/ide.h>
 #include <asm/ide.h>
 #include <asm/atomic.h>
 #include <asm/bitops.h>
@@ -167,8 +167,11 @@
 EXPORT_SYMBOL(iopa);
 EXPORT_SYMBOL(mm_ptov);
 
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) \
+	defined(CONFIG_USB_STORAGE) || defined(CONFIG_USB_STORAGE_MODULE)
 EXPORT_SYMBOL(ppc_ide_md);
 EXPORT_SYMBOL(ppc_generic_ide_fix_driveid);
+#endif
 
 #ifdef CONFIG_PCI
 EXPORT_SYMBOL_NOVERS(isa_io_base);
@@ -205,7 +208,7 @@
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
-#ifdef SPINLOCK_DEBUG
+#if SPINLOCK_DEBUG
 EXPORT_SYMBOL(_spin_lock);
 EXPORT_SYMBOL(_spin_unlock);
 EXPORT_SYMBOL(spin_trylock);
@@ -246,6 +249,7 @@
 EXPORT_SYMBOL(find_type_devices);
 EXPORT_SYMBOL(find_compatible_devices);
 EXPORT_SYMBOL(find_path_device);
+EXPORT_SYMBOL(find_phandle);
 EXPORT_SYMBOL(device_is_compatible);
 EXPORT_SYMBOL(machine_is_compatible);
 EXPORT_SYMBOL(find_all_nodes);
@@ -262,6 +266,10 @@
 EXPORT_SYMBOL(pci_phys_to_bus);
 EXPORT_SYMBOL(pci_bus_to_phys);
 EXPORT_SYMBOL(pmac_newworld);
+EXPORT_SYMBOL(nvram_read_byte);
+EXPORT_SYMBOL(nvram_write_byte);
+EXPORT_SYMBOL(pmac_xpram_read);
+EXPORT_SYMBOL(pmac_xpram_write);
 #endif /* defined(CONFIG_ALL_PPC) */
 #if defined(CONFIG_BOOTX_TEXT)
 EXPORT_SYMBOL(btext_update_display);
@@ -272,12 +280,6 @@
 #ifdef CONFIG_VT
 EXPORT_SYMBOL(kd_mksound);
 #endif
-#ifdef CONFIG_NVRAM
-EXPORT_SYMBOL(nvram_read_byte);
-EXPORT_SYMBOL(nvram_write_byte);
-EXPORT_SYMBOL(pmac_xpram_read);
-EXPORT_SYMBOL(pmac_xpram_write);
-#endif /* CONFIG_NVRAM */
 EXPORT_SYMBOL(to_tm);
 
 EXPORT_SYMBOL_NOVERS(__ashrdi3);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/prep_nvram.c linux-2.4.20/arch/ppc/kernel/prep_nvram.c
--- linux-2.4.19/arch/ppc/kernel/prep_nvram.c	2001-09-08 19:38:42.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/prep_nvram.c	2002-10-29 11:18:40.000000000 +0000
@@ -1,8 +1,8 @@
 /*
- * BK Id: SCCS/s.prep_nvram.c 1.12 09/08/01 15:47:42 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
- *  linux/arch/ppc/kernel/prep_nvram.c
+ *  arch/ppc/platforms/prep_nvram.c
  *
  *  Copyright (C) 1998  Corey Minyard
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/prep_pci.c linux-2.4.20/arch/ppc/kernel/prep_pci.c
--- linux-2.4.19/arch/ppc/kernel/prep_pci.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/prep_pci.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1271 +0,0 @@
-/*
- * BK Id: SCCS/s.prep_pci.c 1.33 12/20/01 15:36:12 trini
- */
-/*
- * PReP pci functions.
- * Originally by Gary Thomas
- * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
- *
- * The motherboard routes/maps will disappear shortly. -- Cort
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/sections.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/ptrace.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/residual.h>
-#include <asm/processor.h>
-#include <asm/irq.h>
-#include <asm/machdep.h>
-
-#include "pci.h"
-#include "open_pic.h"
-
-#define MAX_DEVNR 22
-
-/* Which PCI interrupt line does a given device [slot] use? */
-/* Note: This really should be two dimensional based in slot/pin used */
-static unsigned char *Motherboard_map;
-unsigned char *Motherboard_map_name;
-
-/* How is the 82378 PIRQ mapping setup? */
-static unsigned char *Motherboard_routes;
-
-static void (*Motherboard_non0)(struct pci_dev *);
-
-static void Powerplus_Map_Non0(struct pci_dev *);
-
-/* Used for Motorola to store system config register */
-static unsigned long	*ProcInfo;
-
-/* Tables for known hardware */   
-
-/* Motorola PowerStackII - Utah */
-static char Utah_pci_IRQ_map[23] __prepdata =
-{
-        0,   /* Slot 0  - unused */
-        0,   /* Slot 1  - unused */
-        5,   /* Slot 2  - SCSI - NCR825A  */
-        0,   /* Slot 3  - unused */
-        1,   /* Slot 4  - Ethernet - DEC2114x */
-        0,   /* Slot 5  - unused */
-        3,   /* Slot 6  - PCI Card slot #1 */
-        4,   /* Slot 7  - PCI Card slot #2 */
-        5,   /* Slot 8  - PCI Card slot #3 */
-        5,   /* Slot 9  - PCI Bridge */
-             /* added here in case we ever support PCI bridges */
-             /* Secondary PCI bus cards are at slot-9,6 & slot-9,7 */
-        0,   /* Slot 10 - unused */
-        0,   /* Slot 11 - unused */
-        5,   /* Slot 12 - SCSI - NCR825A */
-        0,   /* Slot 13 - unused */
-        3,   /* Slot 14 - enet */
-        0,   /* Slot 15 - unused */
-        2,   /* Slot 16 - unused */
-        3,   /* Slot 17 - unused */
-        5,   /* Slot 18 - unused */
-        0,   /* Slot 19 - unused */
-        0,   /* Slot 20 - unused */
-        0,   /* Slot 21 - unused */
-        0,   /* Slot 22 - unused */
-};
-
-static char Utah_pci_IRQ_routes[] __prepdata =
-{
-        0,   /* Line 0 - Unused */
-        9,   /* Line 1 */
-	10,  /* Line 2 */
-        11,  /* Line 3 */
-        14,  /* Line 4 */
-        15,  /* Line 5 */
-};
-
-/* Motorola PowerStackII - Omaha */
-/* no integrated SCSI or ethernet */
-static char Omaha_pci_IRQ_map[23] __prepdata =
-{
-        0,   /* Slot 0  - unused */
-        0,   /* Slot 1  - unused */
-        3,   /* Slot 2  - Winbond EIDE */
-        0,   /* Slot 3  - unused */
-        0,   /* Slot 4  - unused */
-        0,   /* Slot 5  - unused */
-        1,   /* Slot 6  - PCI slot 1 */
-        2,   /* Slot 7  - PCI slot 2  */
-        3,   /* Slot 8  - PCI slot 3 */
-        4,   /* Slot 9  - PCI slot 4 */ /* needs indirect access */
-        0,   /* Slot 10 - unused */
-        0,   /* Slot 11 - unused */
-        0,   /* Slot 12 - unused */
-        0,   /* Slot 13 - unused */
-        0,   /* Slot 14 - unused */
-        0,   /* Slot 15 - unused */
-        1,   /* Slot 16  - PCI slot 1 */
-        2,   /* Slot 17  - PCI slot 2  */
-        3,   /* Slot 18  - PCI slot 3 */
-        4,   /* Slot 19  - PCI slot 4 */ /* needs indirect access */
-        0,
-        0,
-        0,
-};
-
-static char Omaha_pci_IRQ_routes[] __prepdata =
-{
-        0,   /* Line 0 - Unused */
-        9,   /* Line 1 */
-        11,  /* Line 2 */
-        14,  /* Line 3 */
-        15   /* Line 4 */
-};
-
-/* Motorola PowerStack */
-static char Blackhawk_pci_IRQ_map[19] __prepdata =
-{
-  	0,	/* Slot 0  - unused */
-  	0,	/* Slot 1  - unused */
-  	0,	/* Slot 2  - unused */
-  	0,	/* Slot 3  - unused */
-  	0,	/* Slot 4  - unused */
-  	0,	/* Slot 5  - unused */
-  	0,	/* Slot 6  - unused */
-  	0,	/* Slot 7  - unused */
-  	0,	/* Slot 8  - unused */
-  	0,	/* Slot 9  - unused */
-  	0,	/* Slot 10 - unused */
-  	0,	/* Slot 11 - unused */
-  	3,	/* Slot 12 - SCSI */
-  	0,	/* Slot 13 - unused */
-  	1,	/* Slot 14 - Ethernet */
-  	0,	/* Slot 15 - unused */
- 	1,	/* Slot P7 */
- 	2,	/* Slot P6 */
- 	3,	/* Slot P5 */
-};
-
-static char Blackhawk_pci_IRQ_routes[] __prepdata =
-{
-   	0,	/* Line 0 - Unused */
-   	9,	/* Line 1 */
-   	11,	/* Line 2 */
-   	15,	/* Line 3 */
-   	15	/* Line 4 */
-};
-   
-/* Motorola Mesquite */
-static char Mesquite_pci_IRQ_map[23] __prepdata =
-{
-	0,	/* Slot 0  - unused */
-	0,	/* Slot 1  - unused */
-	0,	/* Slot 2  - unused */
-	0,	/* Slot 3  - unused */
-	0,	/* Slot 4  - unused */
-	0,	/* Slot 5  - unused */
-	0,	/* Slot 6  - unused */
-	0,	/* Slot 7  - unused */
-	0,	/* Slot 8  - unused */
-	0,	/* Slot 9  - unused */
-	0,	/* Slot 10 - unused */
-	0,	/* Slot 11 - unused */
-	0,	/* Slot 12 - unused */
-	0,	/* Slot 13 - unused */
-	2,	/* Slot 14 - Ethernet */
-	0,	/* Slot 15 - unused */
-	3,	/* Slot 16 - PMC */
-	0,	/* Slot 17 - unused */
-	0,	/* Slot 18 - unused */
-	0,	/* Slot 19 - unused */
-	0,	/* Slot 20 - unused */
-	0,	/* Slot 21 - unused */
-	0,	/* Slot 22 - unused */
-};
-
-/* Motorola Sitka */
-static char Sitka_pci_IRQ_map[21] __prepdata =
-{
-	0,      /* Slot 0  - unused */
-	0,      /* Slot 1  - unused */
-	0,      /* Slot 2  - unused */
-	0,      /* Slot 3  - unused */
-	0,      /* Slot 4  - unused */
-	0,      /* Slot 5  - unused */
-	0,      /* Slot 6  - unused */
-	0,      /* Slot 7  - unused */
-	0,      /* Slot 8  - unused */
-	0,      /* Slot 9  - unused */
-	0,      /* Slot 10 - unused */
-	0,      /* Slot 11 - unused */
-	0,      /* Slot 12 - unused */
-	0,      /* Slot 13 - unused */
-	2,      /* Slot 14 - Ethernet */
-	0,      /* Slot 15 - unused */
-	9,      /* Slot 16 - PMC 1  */
-	12,     /* Slot 17 - PMC 2  */
-	0,      /* Slot 18 - unused */
-	0,      /* Slot 19 - unused */
-	4,      /* Slot 20 - NT P2P bridge */
-};
-
-/* Motorola MTX */
-static char MTX_pci_IRQ_map[23] __prepdata =
-{
-	0,	/* Slot 0  - unused */
-	0,	/* Slot 1  - unused */
-	0,	/* Slot 2  - unused */
-	0,	/* Slot 3  - unused */
-	0,	/* Slot 4  - unused */
-	0,	/* Slot 5  - unused */
-	0,	/* Slot 6  - unused */
-	0,	/* Slot 7  - unused */
-	0,	/* Slot 8  - unused */
-	0,	/* Slot 9  - unused */
-	0,	/* Slot 10 - unused */
-	0,	/* Slot 11 - unused */
-	3,	/* Slot 12 - SCSI */
-	0,	/* Slot 13 - unused */
-	2,	/* Slot 14 - Ethernet */
-	0,	/* Slot 15 - unused */
-	9,      /* Slot 16 - PCI/PMC slot 1 */
-	10,     /* Slot 17 - PCI/PMC slot 2 */
-	11,     /* Slot 18 - PCI slot 3 */
-	0,	/* Slot 19 - unused */
-	0,	/* Slot 20 - unused */
-	0,	/* Slot 21 - unused */
-	0,	/* Slot 22 - unused */
-};
-
-/* Motorola MTX Plus */
-/* Secondary bus interrupt routing is not supported yet */
-static char MTXplus_pci_IRQ_map[23] __prepdata =
-{
-        0,      /* Slot 0  - unused */
-        0,      /* Slot 1  - unused */
-        0,      /* Slot 2  - unused */
-        0,      /* Slot 3  - unused */
-        0,      /* Slot 4  - unused */
-        0,      /* Slot 5  - unused */
-        0,      /* Slot 6  - unused */
-        0,      /* Slot 7  - unused */
-        0,      /* Slot 8  - unused */
-        0,      /* Slot 9  - unused */
-        0,      /* Slot 10 - unused */
-        0,      /* Slot 11 - unused */
-        3,      /* Slot 12 - SCSI */
-        0,      /* Slot 13 - unused */
-        2,      /* Slot 14 - Ethernet 1 */
-        0,      /* Slot 15 - unused */
-        9,      /* Slot 16 - PCI slot 1P */
-        10,     /* Slot 17 - PCI slot 2P */
-        11,     /* Slot 18 - PCI slot 3P */
-        10,     /* Slot 19 - Ethernet 2 */
-        0,      /* Slot 20 - P2P Bridge */
-        0,      /* Slot 21 - unused */
-        0,      /* Slot 22 - unused */
-};
-
-static char Raven_pci_IRQ_routes[] __prepdata =
-{
-   	0,	/* This is a dummy structure */
-};
-   
-/* Motorola MVME16xx */
-static char Genesis_pci_IRQ_map[16] __prepdata =
-{
-  	0,	/* Slot 0  - unused */
-  	0,	/* Slot 1  - unused */
-  	0,	/* Slot 2  - unused */
-  	0,	/* Slot 3  - unused */
-  	0,	/* Slot 4  - unused */
-  	0,	/* Slot 5  - unused */
-  	0,	/* Slot 6  - unused */
-  	0,	/* Slot 7  - unused */
-  	0,	/* Slot 8  - unused */
-  	0,	/* Slot 9  - unused */
-  	0,	/* Slot 10 - unused */
-  	0,	/* Slot 11 - unused */
-  	3,	/* Slot 12 - SCSI */
-  	0,	/* Slot 13 - unused */
-  	1,	/* Slot 14 - Ethernet */
-  	0,	/* Slot 15 - unused */
-};
-
-static char Genesis_pci_IRQ_routes[] __prepdata =
-{
-   	0,	/* Line 0 - Unused */
-   	10,	/* Line 1 */
-   	11,	/* Line 2 */
-   	14,	/* Line 3 */
-   	15	/* Line 4 */
-};
-   
-static char Genesis2_pci_IRQ_map[23] __prepdata =
-{
-	0,	/* Slot 0  - unused */
-	0,	/* Slot 1  - unused */
-	0,	/* Slot 2  - unused */
-	0,	/* Slot 3  - unused */
-	0,	/* Slot 4  - unused */
-	0,	/* Slot 5  - unused */
-	0,	/* Slot 6  - unused */
-	0,	/* Slot 7  - unused */
-	0,	/* Slot 8  - unused */
-	0,	/* Slot 9  - unused */
-	0,	/* Slot 10 - Ethernet */
-	0,	/* Slot 11 - Universe PCI - VME Bridge */
-	3,	/* Slot 12 - unused */
-	0,	/* Slot 13 - unused */
-	2,	/* Slot 14 - SCSI */
-	0,	/* Slot 15 - unused */
-	9,	/* Slot 16 - PMC 1 */
-	12,	/* Slot 17 - pci */
-	11,	/* Slot 18 - pci */
-	10,	/* Slot 19 - pci */
-	0,	/* Slot 20 - pci */
-	0,	/* Slot 21 - unused */
-	0,	/* Slot 22 - unused */
-};
-
-/* Motorola Series-E */
-static char Comet_pci_IRQ_map[23] __prepdata =
-{
-  	0,	/* Slot 0  - unused */
-  	0,	/* Slot 1  - unused */
-  	0,	/* Slot 2  - unused */
-  	0,	/* Slot 3  - unused */
-  	0,	/* Slot 4  - unused */
-  	0,	/* Slot 5  - unused */
-  	0,	/* Slot 6  - unused */
-  	0,	/* Slot 7  - unused */
-  	0,	/* Slot 8  - unused */
-  	0,	/* Slot 9  - unused */
-  	0,	/* Slot 10 - unused */
-  	0,	/* Slot 11 - unused */
-  	3,	/* Slot 12 - SCSI */
-  	0,	/* Slot 13 - unused */
-  	1,	/* Slot 14 - Ethernet */
-  	0,	/* Slot 15 - unused */
-	1,	/* Slot 16 - PCI slot 1 */
-	2,	/* Slot 17 - PCI slot 2 */
-	3,	/* Slot 18 - PCI slot 3 */
-	4,	/* Slot 19 - PCI bridge */
-	0,
-	0,
-	0,
-};
-
-static char Comet_pci_IRQ_routes[] __prepdata =
-{
-   	0,	/* Line 0 - Unused */
-   	10,	/* Line 1 */
-   	11,	/* Line 2 */
-   	14,	/* Line 3 */
-   	15	/* Line 4 */
-};
-
-/* Motorola Series-EX */
-static char Comet2_pci_IRQ_map[23] __prepdata =
-{
-	0,	/* Slot 0  - unused */
-	0,	/* Slot 1  - unused */
-	3,	/* Slot 2  - SCSI - NCR825A */
-	0,	/* Slot 3  - unused */
-	1,	/* Slot 4  - Ethernet - DEC2104X */
-	0,	/* Slot 5  - unused */
-	1,	/* Slot 6  - PCI slot 1 */
-	2,	/* Slot 7  - PCI slot 2 */
-	3,	/* Slot 8  - PCI slot 3 */
-	4,	/* Slot 9  - PCI bridge  */
-	0,	/* Slot 10 - unused */
-	0,	/* Slot 11 - unused */
-	3,	/* Slot 12 - SCSI - NCR825A */
-	0,	/* Slot 13 - unused */
-	1,	/* Slot 14 - Ethernet - DEC2104X */
-	0,	/* Slot 15 - unused */
-	1,	/* Slot 16 - PCI slot 1 */
-	2,	/* Slot 17 - PCI slot 2 */
-	3,	/* Slot 18 - PCI slot 3 */
-	4,	/* Slot 19 - PCI bridge */
-	0,
-	0,
-	0,
-};
-
-static char Comet2_pci_IRQ_routes[] __prepdata =
-{
-	0,	/* Line 0 - Unused */
-	10,	/* Line 1 */
-	11,	/* Line 2 */
-	14,	/* Line 3 */
-	15,	/* Line 4 */
-};
-
-/*
- * ibm 830 (and 850?).
- * This is actually based on the Carolina motherboard
- * -- Cort
- */
-static char ibm8xx_pci_IRQ_map[23] __prepdata = {
-        0, /* Slot 0  - unused */
-        0, /* Slot 1  - unused */
-        0, /* Slot 2  - unused */
-        0, /* Slot 3  - unused */
-        0, /* Slot 4  - unused */
-        0, /* Slot 5  - unused */
-        0, /* Slot 6  - unused */
-        0, /* Slot 7  - unused */
-        0, /* Slot 8  - unused */
-        0, /* Slot 9  - unused */
-        0, /* Slot 10 - unused */
-        0, /* Slot 11 - FireCoral */
-        4, /* Slot 12 - Ethernet  PCIINTD# */
-        2, /* Slot 13 - PCI Slot #2 */
-        2, /* Slot 14 - S3 Video PCIINTD# */
-        0, /* Slot 15 - onboard SCSI (INDI) [1] */
-        3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
-        0, /* Slot 17 - unused */
-        2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
-        0, /* Slot 19 - unused */
-        0, /* Slot 20 - unused */
-        0, /* Slot 21 - unused */
-        2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
-};
-
-static char ibm8xx_pci_IRQ_routes[] __prepdata = {
-        0,      /* Line 0 - unused */
-        15,     /* Line 1 */
-        15,     /* Line 2 */
-        15,     /* Line 3 */
-        15,     /* Line 4 */
-};
-
-/*
- * a 6015 ibm board
- * -- Cort
- */
-static char ibm6015_pci_IRQ_map[23] __prepdata = {
-        0, /* Slot 0  - unused */
-        0, /* Slot 1  - unused */
-        0, /* Slot 2  - unused */
-        0, /* Slot 3  - unused */
-        0, /* Slot 4  - unused */
-        0, /* Slot 5  - unused */
-        0, /* Slot 6  - unused */
-        0, /* Slot 7  - unused */
-        0, /* Slot 8  - unused */
-        0, /* Slot 9  - unused */
-        0, /* Slot 10 - unused */
-        0, /* Slot 11 -  */
-        1, /* Slot 12 - SCSI */
-        2, /* Slot 13 -  */
-        2, /* Slot 14 -  */
-        1, /* Slot 15 -  */
-        1, /* Slot 16 -  */
-        0, /* Slot 17 -  */
-        2, /* Slot 18 -  */
-        0, /* Slot 19 -  */
-        0, /* Slot 20 -  */
-        0, /* Slot 21 -  */
-        2, /* Slot 22 -  */
-};
-
-static char ibm6015_pci_IRQ_routes[] __prepdata = {
-        0,      /* Line 0 - unused */
-        13,     /* Line 1 */
-        15,     /* Line 2 */
-        15,     /* Line 3 */
-        15,     /* Line 4 */
-};
-
-
-/* IBM Nobis and Thinkpad 850 */
-static char Nobis_pci_IRQ_map[23] __prepdata ={
-        0, /* Slot 0  - unused */
-        0, /* Slot 1  - unused */
-        0, /* Slot 2  - unused */
-        0, /* Slot 3  - unused */
-        0, /* Slot 4  - unused */
-        0, /* Slot 5  - unused */
-        0, /* Slot 6  - unused */
-        0, /* Slot 7  - unused */
-        0, /* Slot 8  - unused */
-        0, /* Slot 9  - unused */
-        0, /* Slot 10 - unused */
-        0, /* Slot 11 - unused */
-        3, /* Slot 12 - SCSI */
-        0, /* Slot 13 - unused */
-        0, /* Slot 14 - unused */
-        0, /* Slot 15 - unused */
-};
-
-static char Nobis_pci_IRQ_routes[] __prepdata = {
-        0, /* Line 0 - Unused */
-        13, /* Line 1 */
-        13, /* Line 2 */
-        13, /* Line 3 */
-        13      /* Line 4 */
-};
-
-/*
- * IBM RS/6000 43p/140  -- paulus
- * XXX we should get all this from the residual data
- */
-static char ibm43p_pci_IRQ_map[23] __prepdata = {
-        0, /* Slot 0  - unused */
-        0, /* Slot 1  - unused */
-        0, /* Slot 2  - unused */
-        0, /* Slot 3  - unused */
-        0, /* Slot 4  - unused */
-        0, /* Slot 5  - unused */
-        0, /* Slot 6  - unused */
-        0, /* Slot 7  - unused */
-        0, /* Slot 8  - unused */
-        0, /* Slot 9  - unused */
-        0, /* Slot 10 - unused */
-        0, /* Slot 11 - FireCoral ISA bridge */
-        6, /* Slot 12 - Ethernet  */
-        0, /* Slot 13 - openpic */
-        0, /* Slot 14 - unused */
-        0, /* Slot 15 - unused */
-        7, /* Slot 16 - NCR58C825a onboard scsi */
-        0, /* Slot 17 - unused */
-        2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
-        0, /* Slot 19 - unused */
-        0, /* Slot 20 - unused */
-        0, /* Slot 21 - unused */
-        1, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
-};
-
-static char ibm43p_pci_IRQ_routes[] __prepdata = {
-        0,      /* Line 0 - unused */
-        15,     /* Line 1 */
-        15,     /* Line 2 */
-        15,     /* Line 3 */
-        15,     /* Line 4 */
-};
-
-/* Motorola PowerPlus architecture PCI IRQ tables */
-/* Interrupt line values for INTA-D on primary/secondary MPIC inputs */
-
-struct powerplus_irq_list
-{
-	unsigned char primary[4];       /* INT A-D */
-	unsigned char secondary[4];     /* INT A-D */
-};
-
-/*
- * For standard PowerPlus boards, bus 0 PCI INTs A-D are routed to
- * OpenPIC inputs 9-12.  PCI INTs A-D from the on board P2P bridge
- * are routed to OpenPIC inputs 5-8.  These values are offset by
- * 16 in the table to reflect the Linux kernel interrupt value.
- */
-struct powerplus_irq_list Powerplus_pci_IRQ_list __prepdata =
-{
-	{25, 26, 27, 28},
-	{21, 22, 23, 24}
-};
-
-/*
- * For the MCP750 (system slot board), cPCI INTs A-D are routed to
- * OpenPIC inputs 8-11 and the PMC INTs A-D are routed to OpenPIC
- * input 3.  On a hot swap MCP750, the companion card PCI INTs A-D
- * are routed to OpenPIC inputs 12-15. These values are offset by
- * 16 in the table to reflect the Linux kernel interrupt value.
- */
-struct powerplus_irq_list Mesquite_pci_IRQ_list __prepdata =
-{
-	{24, 25, 26, 27},
-	{28, 29, 30, 31}
-};
-
-/*
- * This table represents the standard PCI swizzle defined in the
- * PCI bus specification.
- */
-static unsigned char prep_pci_intpins[4][4] __prepdata =
-{
-	{ 1, 2, 3, 4},  /* Buses 0, 4, 8, ... */
-	{ 2, 3, 4, 1},  /* Buses 1, 5, 9, ... */
-	{ 3, 4, 1, 2},  /* Buses 2, 6, 10 ... */
-	{ 4, 1, 2, 3},  /* Buses 3, 7, 11 ... */
-};
-
-/* We have to turn on LEVEL mode for changed IRQ's */
-/* All PCI IRQ's need to be level mode, so this should be something
- * other than hard-coded as well... IRQ's are individually mappable
- * to either edge or level.
- */
-
-/*
- * 8259 edge/level control definitions
- */
-#define ISA8259_M_ELCR 0x4d0
-#define ISA8259_S_ELCR 0x4d1
-
-#define ELCRS_INT15_LVL         0x80
-#define ELCRS_INT14_LVL         0x40
-#define ELCRS_INT12_LVL         0x10
-#define ELCRS_INT11_LVL         0x08
-#define ELCRS_INT10_LVL         0x04
-#define ELCRS_INT9_LVL          0x02
-#define ELCRS_INT8_LVL          0x01
-#define ELCRM_INT7_LVL          0x80
-#define ELCRM_INT5_LVL          0x20
-
-#define CFGPTR(dev) (0x80800000 | (1<<(dev>>3)) | ((dev&7)<<8) | offset)
-#define DEVNO(dev)  (dev>>3)                                  
-
-#define cfg_read(val, addr, type, op)	*val = op((type)(addr))
-#define cfg_write(val, addr, type, op)	op((type *)(addr), (val))
-
-#define cfg_read_bad(val, size)		*val = bad_##size;
-#define cfg_write_bad(val, size)
-
-#define bad_byte	0xff
-#define bad_word	0xffff
-#define bad_dword	0xffffffffU
-
-#define PREP_PCI_OP(rw, size, type, op)					\
-static int __prep							\
-prep_##rw##_config_##size(struct pci_dev *dev, int offset, type val)	\
-{									\
-	if ((dev->bus->number != 0) || (DEVNO(dev->devfn) > MAX_DEVNR))	\
-	{                   						\
-		cfg_##rw##_bad(val, size)				\
-		return PCIBIOS_DEVICE_NOT_FOUND;    			\
-	}								\
-	cfg_##rw(val, CFGPTR(dev->devfn), type, op);			\
-	return PCIBIOS_SUCCESSFUL;					\
-}
-
-PREP_PCI_OP(read, byte, u8 *, in_8)
-PREP_PCI_OP(read, word, u16 *, in_le16)
-PREP_PCI_OP(read, dword, u32 *, in_le32)
-PREP_PCI_OP(write, byte, u8, out_8)
-PREP_PCI_OP(write, word, u16, out_le16)
-PREP_PCI_OP(write, dword, u32, out_le32)
-
-static struct pci_ops prep_pci_ops =
-{
-	prep_read_config_byte,
-	prep_read_config_word,
-	prep_read_config_dword,
-	prep_write_config_byte,
-	prep_write_config_word,
-	prep_write_config_dword
-};
-
-#define MOTOROLA_CPUTYPE_REG	0x800
-#define MOTOROLA_BASETYPE_REG	0x803
-#define MPIC_RAVEN_ID		0x48010000
-#define	MPIC_HAWK_ID		0x48030000
-#define	MOT_PROC2_BIT		0x800
-
-static u_char mvme2600_openpic_initsenses[] __initdata = {
-    1,	/* MVME2600_INT_SIO */
-    0,	/* MVME2600_INT_FALCN_ECC_ERR */
-    1,	/* MVME2600_INT_PCI_ETHERNET */
-    1,	/* MVME2600_INT_PCI_SCSI */
-    1,	/* MVME2600_INT_PCI_GRAPHICS */
-    1,	/* MVME2600_INT_PCI_VME0 */
-    1,	/* MVME2600_INT_PCI_VME1 */
-    1,	/* MVME2600_INT_PCI_VME2 */
-    1,	/* MVME2600_INT_PCI_VME3 */
-    1,	/* MVME2600_INT_PCI_INTA */
-    1,	/* MVME2600_INT_PCI_INTB */
-    1,	/* MVME2600_INT_PCI_INTC */
-    1,	/* MVME2600_INT_PCI_INTD */
-    1,	/* MVME2600_INT_LM_SIG0 */
-    1,	/* MVME2600_INT_LM_SIG1 */
-};
-
-#define MOT_RAVEN_PRESENT	0x1
-#define MOT_HAWK_PRESENT	0x2
-
-int mot_entry = -1;
-int prep_keybd_present = 1;
-int MotMPIC;
-int mot_multi;
-
-int __init
-raven_init(void)
-{
-	unsigned int	devid;
-	unsigned int	pci_membase;
-	unsigned char	base_mod;
-
-	/* Check to see if the Raven chip exists. */
-	if ( _prep_type != _PREP_Motorola) {
-		OpenPIC_Addr = NULL;
-		return 0;
-	}
-
-	/* Check to see if this board is a type that might have a Raven. */
-	if ((inb(MOTOROLA_CPUTYPE_REG) & 0xF0) != 0xE0) {
-		OpenPIC_Addr = NULL;
-		return 0;
-	}
-
-	/* Check the first PCI device to see if it is a Raven. */
-	early_read_config_dword(0, 0, 0, PCI_VENDOR_ID, &devid);
-
-	switch (devid & 0xffff0000) {
-	case MPIC_RAVEN_ID:
-		MotMPIC = MOT_RAVEN_PRESENT;
-		break;
-	case MPIC_HAWK_ID:
-		MotMPIC = MOT_HAWK_PRESENT;
-		break;
-	default:
-		OpenPIC_Addr = NULL;
-		return 0;
-	}
-
-
-	/* Read the memory base register. */
-	early_read_config_dword(0, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
-
-	if (pci_membase == 0) {
-		OpenPIC_Addr = NULL;
-		return 0;
-	}
-
-	/* Map the Raven MPIC registers to virtual memory. */
-	OpenPIC_Addr = ioremap(pci_membase+0xC0000000, 0x22000);
-
-	OpenPIC_InitSenses = mvme2600_openpic_initsenses;
-	OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
-
-	ppc_md.get_irq = openpic_get_irq;
-	
-	/* If raven is present on Motorola store the system config register
-	 * for later use.
-	 */
-	ProcInfo = (unsigned long *)ioremap(0xfef80400, 4);
-
-	/* Indicate to system if this is a multiprocessor board */
-	if (!(*ProcInfo & MOT_PROC2_BIT)) {
-		mot_multi = 1;
-	}
-
-	/* This is a hack.  If this is a 2300 or 2400 mot board then there is
-	 * no keyboard controller and we have to indicate that.
-	 */
-	base_mod = inb(MOTOROLA_BASETYPE_REG);
-	if ((MotMPIC == MOT_HAWK_PRESENT) || (base_mod == 0xF9) ||
-	    (base_mod == 0xFA) || (base_mod == 0xE1))
-		prep_keybd_present = 0;
-
-	return 1;
-}
-
-struct mot_info {
-	int		cpu_type;	/* 0x100 mask assumes for Raven and Hawk boards that the level/edge are set */
-					/* 0x200 if this board has a Hawk chip. */
-	int		base_type;
-	int		max_cpu;	/* ored with 0x80 if this board should be checked for multi CPU */
-	const char	*name;
-	unsigned char	*map;
-	unsigned char	*routes;
-	void            (*map_non0_bus)(struct pci_dev *);      /* For boards with more than bus 0 devices. */
-	struct powerplus_irq_list *pci_irq_list; /* List of PCI MPIC inputs */
-	unsigned char   secondary_bridge_devfn; /* devfn of secondary bus transparent bridge */
-} mot_info[] __prepdata = {
-	{0x300, 0x00, 0x00, "MVME 2400",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x010, 0x00, 0x00, "Genesis",				Genesis_pci_IRQ_map,	Genesis_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
-	{0x020, 0x00, 0x00, "Powerstack (Series E)",		Comet_pci_IRQ_map,	Comet_pci_IRQ_routes, NULL, NULL, 0x00},
-	{0x040, 0x00, 0x00, "Blackhawk (Powerstack)",		Blackhawk_pci_IRQ_map,	Blackhawk_pci_IRQ_routes, NULL, NULL, 0x00},
-	{0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)",	Omaha_pci_IRQ_map,	Omaha_pci_IRQ_routes, NULL, NULL, 0x00},
-	{0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)",	Utah_pci_IRQ_map,	Utah_pci_IRQ_routes, NULL, NULL, 0x00},
-	{0x0A0, 0x00, 0x00, "Powerstack (Series EX)",		Comet2_pci_IRQ_map,	Comet2_pci_IRQ_routes, NULL, NULL, 0x00},
-	{0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)",		Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)",		Sitka_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC",	Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xC0},
-	{0x1E0, 0xF6, 0x80, "MTX Plus",				MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
-	{0x1E0, 0xF6, 0x81, "Dual MTX Plus",			MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
-	{0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
-	{0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
-	{0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
-	{0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
-	{0x1E0, 0xF9, 0x00, "MVME 2300",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
-	{0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x000, 0x00, 0x00, "",					NULL,			NULL, NULL, NULL, 0x00}
-};
-
-void __init
-ibm_prep_init(void)
-{
-	u32 addr;
-#ifdef CONFIG_PREP_RESIDUAL
-	PPC_DEVICE *mpic;
-#endif
-
-	if (inb(0x0852) == 0xd5) {
-		/* This is for the 43p-140 */
-		early_read_config_dword(0, 0, PCI_DEVFN(13, 0),
-					PCI_BASE_ADDRESS_0, &addr);
-		if (addr != 0xffffffff
-		    && !(addr & PCI_BASE_ADDRESS_SPACE_IO)
-		    && (addr &= PCI_BASE_ADDRESS_MEM_MASK) != 0) {
-			addr += PREP_ISA_MEM_BASE;
-			OpenPIC_Addr = ioremap(addr, 0x40000);
-			ppc_md.get_irq = openpic_get_irq;
-		}
-	}
-
-#ifdef CONFIG_PREP_RESIDUAL
-	mpic = residual_find_device(-1, NULL, SystemPeripheral,
-				    ProgrammableInterruptController, MPIC, 0);
-	if (mpic != NULL)
-		printk("mpic = %p\n", mpic);
-#endif
-}
-
-static void __init
-ibm43p_pci_map_non0(struct pci_dev *dev)
-{
-	unsigned char intpin;
-	static unsigned char bridge_intrs[4] = { 3, 4, 5, 8 };
-
-	if (dev == NULL)
-		return;
-	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &intpin);
-	if (intpin < 1 || intpin > 4)
-		return;
-	intpin = (PCI_SLOT(dev->devfn) + intpin - 1) & 3;
-	dev->irq = openpic_to_irq(bridge_intrs[intpin]);
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
-}
-
-void __init
-prep_route_pci_interrupts(void)
-{
-	unsigned char *ibc_pirq = (unsigned char *)0x80800860;
-	unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
-	int i;
-	
-	if ( _prep_type == _PREP_Motorola)
-	{
-		unsigned short irq_mode;
-		unsigned char  cpu_type;
-		unsigned char  base_mod;
-		int	       entry;
-
-		cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
-		base_mod = inb(MOTOROLA_BASETYPE_REG);
-
-		for (entry = 0; mot_info[entry].cpu_type != 0; entry++) {
-			if (mot_info[entry].cpu_type & 0x200) {		 	/* Check for Hawk chip */
-				if (!(MotMPIC & MOT_HAWK_PRESENT))
-					continue;
-			} else {						/* Check non hawk boards */
-				if ((mot_info[entry].cpu_type & 0xff) != cpu_type)
-					continue;
-
-				if (mot_info[entry].base_type == 0) {
-					mot_entry = entry;
-					break;
-				}
-
-				if (mot_info[entry].base_type != base_mod)
-					continue;
-			}
-
-			if (!(mot_info[entry].max_cpu & 0x80)) {
-				mot_entry = entry;
-				break;
-			}
-
-			/* processor 1 not present and max processor zero indicated */
-			if ((*ProcInfo & MOT_PROC2_BIT) && !(mot_info[entry].max_cpu & 0x7f)) {
-				mot_entry = entry;
-				break;
-			}
-
-			/* processor 1 present and max processor zero indicated */
-			if (!(*ProcInfo & MOT_PROC2_BIT) && (mot_info[entry].max_cpu & 0x7f)) {
-				mot_entry = entry;
-				break;
-			}
-		}
-
-		if (mot_entry == -1) 	/* No particular cpu type found - assume Blackhawk */
-			mot_entry = 3;
-
-		Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name;
-		Motherboard_map = mot_info[mot_entry].map;
-		Motherboard_routes = mot_info[mot_entry].routes;
-		Motherboard_non0 = mot_info[mot_entry].map_non0_bus;
-
-		if (!(mot_info[entry].cpu_type & 0x100)) {
-			/* AJF adjust level/edge control according to routes */
-			irq_mode = 0;
-			for (i = 1;  i <= 4;  i++)
-				irq_mode |= ( 1 << Motherboard_routes[i] );
-			outb( irq_mode & 0xff, 0x4d0 );
-			outb( (irq_mode >> 8) & 0xff, 0x4d1 );
-		}
-	} else if ( _prep_type == _PREP_IBM ) {
-		unsigned char planar_id = inb(0x0852);
-		unsigned char irq_edge_mask_lo, irq_edge_mask_hi;
-
-		printk("IBM ID: %08x\n", planar_id);
-		switch(planar_id) {
-		case 0xff:
-			Motherboard_map_name = "IBM Thinkpad 850/860";
-			Motherboard_map = Nobis_pci_IRQ_map;
-			Motherboard_routes = Nobis_pci_IRQ_routes;
-			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
-			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
-			break;
-		case 0xfc:
-			Motherboard_map_name = "IBM 6015/7020 (Sandalfoot/Sandalbow)";
-			Motherboard_map = ibm6015_pci_IRQ_map;
-			Motherboard_routes = ibm6015_pci_IRQ_routes;
-			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
-			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
-			break;
-		case 0xd5:
-			Motherboard_map_name = "IBM 43P-140 (Tiger1)";
-			Motherboard_map = ibm43p_pci_IRQ_map;
-			Motherboard_routes = ibm43p_pci_IRQ_routes;
-			Motherboard_non0 = ibm43p_pci_map_non0;
-			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
-			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
-			break;
-		default:
-			printk(KERN_ERR "Unknown IBM motherboard! Defaulting to Carolina.\n");
-		case 0xf0: /* PowerSeries 830/850 */
-		case 0xf1: /* PowerSeries 830/850 */
-		case 0xf2: /* PowerSeries 830/850 */
-		case 0xf4: /* 7248-43P */
-		case 0xf5: /* 7248-43P */
-		case 0xf6: /* 7248-43P */
-		case 0xf7: /* 7248-43P (missing from Carolina Tech Spec) */
-			Motherboard_map_name = "IBM PS830/PS850/7248 (Carolina)";
-			Motherboard_map = ibm8xx_pci_IRQ_map;
-			Motherboard_routes = ibm8xx_pci_IRQ_routes;
-			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
-			irq_edge_mask_hi = 0xA4; /* irq's 10, 13, 15 level-triggered */
-			break;
-		}
-
-		outb(inb(0x04d0)|irq_edge_mask_lo, 0x04d0); /* primary 8259 */
-		outb(inb(0x04d1)|irq_edge_mask_hi, 0x04d1); /* cascaded 8259 */
-	} else {
-		printk("No known machine pci routing!\n");
-		return;
-	}
-	
-	/* Set up mapping from slots */
-	for (i = 1;  i <= 4;  i++)
-		ibc_pirq[i-1] = Motherboard_routes[i];
-	/* Enable PCI interrupts */
-	*ibc_pcicon |= 0x20;
-}
-
-void __init
-prep_pib_init(void)
-{
-	unsigned char   reg;
-	unsigned short  short_reg;
-
-	struct pci_dev *dev = NULL;
-
-	if (( _prep_type == _PREP_Motorola) && (OpenPIC_Addr)) {
-		/*
-		 * Perform specific configuration for the Via Tech or
-		 * or Winbond PCI-ISA-Bridge part.
-		 */
-		if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, 
-					PCI_DEVICE_ID_VIA_82C586_1, dev))) {
-			/*
-			 * PPCBUG does not set the enable bits
-			 * for the IDE device. Force them on here.
-			 */
-			pci_read_config_byte(dev, 0x40, &reg);
-
-			reg |= 0x03; /* IDE: Chip Enable Bits */
-			pci_write_config_byte(dev, 0x40, reg);
-		}
-		if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
-						PCI_DEVICE_ID_VIA_82C586_2,
-						dev)) && (dev->devfn = 0x5a)) {
-			/* Force correct USB interrupt */
-			dev->irq = 11;
-			pci_write_config_byte(dev,
-					PCI_INTERRUPT_LINE,
-					dev->irq);
-		}
-		if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
-					PCI_DEVICE_ID_WINBOND_83C553, dev))) {
-			 /* Clear PCI Interrupt Routing Control Register. */
-			short_reg = 0x0000;
-			pci_write_config_word(dev, 0x44, short_reg);
-			if (OpenPIC_Addr){
-				/* Route IDE interrupts to IRQ 14 */
-				reg = 0xEE;
-				pci_write_config_byte(dev, 0x43, reg);
-			}
-		}
-	}
-
-	if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
-				   PCI_DEVICE_ID_WINBOND_82C105, dev))){
-		if (OpenPIC_Addr){
-			/*
-			 * Disable LEGIRQ mode so PCI INTS are routed
-			 * directly to the 8259 and enable both channels
-			 */
-			pci_write_config_dword(dev, 0x40, 0x10ff0033);
-
-			/* Force correct IDE interrupt */
-			dev->irq = 14;
-			pci_write_config_byte(dev,
-					PCI_INTERRUPT_LINE,
-					dev->irq);
-		} else {
-			/* Enable LEGIRQ for PCI INT -> 8259 IRQ routing */
-			pci_write_config_dword(dev, 0x40, 0x10ff08a1);
-		}
-	}
-}
-
-static void __init
-Powerplus_Map_Non0(struct pci_dev *dev)
-{
-	struct pci_bus  *pbus;          /* Parent bus structure pointer */
-	struct pci_dev  *tdev = dev;    /* Temporary device structure */
-	unsigned int    devnum;         /* Accumulated device number */
-	unsigned char   intline;        /* Linux interrupt value */
-	unsigned char   intpin;         /* PCI interrupt pin */
-
-	/* Check for valid PCI dev pointer */
-	if (dev == NULL) return;
-
-	/* Initialize bridge IDSEL variable */
-	devnum = PCI_SLOT(tdev->devfn);
-
-	/* Read the interrupt pin of the device and adjust for indexing */
-	pcibios_read_config_byte(dev->bus->number, dev->devfn,
-			PCI_INTERRUPT_PIN, &intpin);
-
-	/* If device doesn't request an interrupt, return */
-	if ( (intpin < 1) || (intpin > 4) )
-		return;
-
-	intpin--;
-
-	/*
-	 * Walk up to bus 0, adjusting the interrupt pin for the standard
-	 * PCI bus swizzle.
-	 */
-	do {
-		intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
-		pbus = tdev->bus;        /* up one level */
-		tdev = pbus->self;
-		devnum = PCI_SLOT(tdev->devfn);
-	} while(tdev->bus->number);
-
-	/* Use the primary interrupt inputs by default */
-	intline = mot_info[mot_entry].pci_irq_list->primary[intpin];
-
-	/*
-	 * If the board has secondary interrupt inputs, walk the bus and
-	 * note the devfn of the bridge from bus 0.  If it is the same as
-	 * the devfn of the bus bridge with secondary inputs, use those.
-	 * Otherwise, assume it's a PMC site and get the interrupt line
-	 * value from the interrupt routing table.
-	 */ 
-	if (mot_info[mot_entry].secondary_bridge_devfn) {
-		pbus = dev->bus;
-
-		while (pbus->primary != 0)
-			pbus = pbus->parent;
-
-		if ((pbus->self)->devfn != 0xA0) {
-			if ((pbus->self)->devfn == mot_info[mot_entry].secondary_bridge_devfn)
-				intline = mot_info[mot_entry].pci_irq_list->secondary[intpin];
-			else {
-				if ((char *)(mot_info[mot_entry].map) == (char *)Mesquite_pci_IRQ_map)
-					intline = mot_info[mot_entry].map[((pbus->self)->devfn)/8] + 16;
-				else {
-					int i;
-					for (i=0;i<3;i++)
-						intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
-					intline = mot_info[mot_entry].pci_irq_list->primary[intpin];
-				}
-			}
-		}
-	}
-
-	/* Write calculated interrupt value to header and device list */
-	dev->irq = intline;
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, (u8)dev->irq);
-}
-
-void __init
-prep_pcibios_fixup(void)
-{
-        struct pci_dev *dev;
-        extern unsigned char *Motherboard_map;
-        extern unsigned char *Motherboard_routes;
-        unsigned char i;
-
-	prep_route_pci_interrupts();
-
-	printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
-	if (OpenPIC_Addr) {
-		/* PCI interrupts are controlled by the OpenPIC */
-		pci_for_each_dev(dev) {
-			if (dev->bus->number == 0) {
-                       		dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
-				pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_LINE, dev->irq);
-			} else {
-				if (Motherboard_non0 != NULL)
-					Motherboard_non0(dev);
-			}
-		}
-
-		/* Setup the Winbond or Via PIB */
-		prep_pib_init();
-
-		return;
-	}
-
-	pci_for_each_dev(dev) {
-		/*
-		 * Use our old hard-coded kludge to figure out what
-		 * irq this device uses.  This is necessary on things
-		 * without residual data. -- Cort
-		 */
-		unsigned char d = PCI_SLOT(dev->devfn);
-		dev->irq = Motherboard_routes[Motherboard_map[d]];
-
-		for ( i = 0 ; i <= 5 ; i++ ) {
-			/*
-			 * Relocate PCI I/O resources if necessary so the
-			 * standard 256MB BAT covers them.
-			 */
-			if ( (pci_resource_flags(dev, i) & IORESOURCE_IO) &&
-				      (dev->resource[i].start > 0x10000000))  {
-				printk("Relocating PCI address %lx -> %lx\n",
-						dev->resource[i].start,
-						(dev->resource[i].start & 
-						 0x00FFFFFF)| 0x01000000);
-				dev->resource[i].start =
-					(dev->resource[i].start & 0x00FFFFFF)
-					| 0x01000000;
-		                pci_write_config_dword(dev,
-						PCI_BASE_ADDRESS_0 + (i*0x4),
-						dev->resource[i].start);
-				dev->resource[i].end = 
-					(dev->resource[i].end & 0x00FFFFFF)
-					| 0x01000000;
-		        }
-		}
-#if 0
-		/*
-		 * If we have residual data and if it knows about this
-		 * device ask it what the irq is.
-		 *  -- Cort
-		 */
-		ppcd = residual_find_device_id( ~0L, dev->device,
-		                                -1,-1,-1, 0);
-#endif
-	}
-}
-
-static void __init
-prep_pcibios_after_init(void)
-{
-	struct pci_dev *dev;
-	
-	/* If there is a WD 90C, reset the IO BAR to 0x0 (it started that 
-	 * way, but the PCI layer relocated it because it thought 0x0 was
-	 * invalid for a BAR).
-	 * If you don't do this, the card's VGA base will be <IO BAR>+0xc0000
-	 * instead of 0xc0000. vgacon.c (for example) is completely unaware of
-	 * this little quirk.
-	 */
-	dev = pci_find_device(PCI_VENDOR_ID_WD, PCI_DEVICE_ID_WD_90C, NULL);
-	if (dev) {
-		dev->resource[1].end -= dev->resource[1].start;
-		dev->resource[1].start = 0;
-		/* tell the hardware */
-		pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0x0);
-	}
-}
-
-static void __init
-prep_init_resource(struct resource *res, unsigned long start,
-		   unsigned long end, int flags)
-{
-	res->flags = flags;
-	res->start = start;
-	res->end = end;
-	res->name = "PCI host bridge";
-	res->parent = NULL;
-	res->sibling = NULL;
-	res->child = NULL;
-}
-
-void __init
-prep_find_bridges(void)
-{
-	struct pci_controller* hose;
-
-	hose = pcibios_alloc_controller();
-	if (!hose)
-		return;
-
-	hose->first_busno = 0;
-	hose->last_busno = 0xff;
-	hose->pci_mem_offset = PREP_ISA_MEM_BASE;
-	hose->io_base_phys = PREP_ISA_IO_BASE;
-	hose->io_base_virt = (void *)0x80000000; /* see prep_map_io() */
-	prep_init_resource(&hose->io_resource, 0, 0x0fffffff, IORESOURCE_IO);
-	prep_init_resource(&hose->mem_resources[0], 0xc0000000, 0xfeffffff,
-			   IORESOURCE_MEM);
-	
-	printk("PReP architecture\n");
-	{
-#ifdef CONFIG_PREP_RESIDUAL	  
-		PPC_DEVICE *hostbridge;
-
-		hostbridge = residual_find_device(PROCESSORDEVICE, NULL,
-			BridgeController, PCIBridge, -1, 0);
-		if (hostbridge &&
-			hostbridge->DeviceId.Interface == PCIBridgeIndirect) {
-			PnP_TAG_PACKET * pkt;
-			pkt = PnP_find_large_vendor_packet(
-				res->DevicePnPHeap+hostbridge->AllocatedOffset,
-				3, 0);
-			if(pkt) {
-#define p pkt->L4_Pack.L4_Data.L4_PPCPack
-				setup_indirect_pci(hose, 
-					ld_le32((unsigned *) (p.PPCData)),
-					ld_le32((unsigned *) (p.PPCData+8)));
-			} else
-				setup_indirect_pci(hose, 0x80000cf8, 0x80000cfc);
-		} else
-#endif /* CONFIG_PREP_RESIDUAL */
-			hose->ops = &prep_pci_ops;
-	}
-
-	ppc_md.pcibios_fixup = prep_pcibios_fixup;
-	ppc_md.pcibios_after_init = prep_pcibios_after_init;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/prep_setup.c linux-2.4.20/arch/ppc/kernel/prep_setup.c
--- linux-2.4.19/arch/ppc/kernel/prep_setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/prep_setup.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,906 +0,0 @@
-/*
- * BK Id: SCCS/s.prep_setup.c 1.52 04/05/02 10:17:22 trini
- */
-/*
- *  linux/arch/ppc/kernel/setup.c
- *
- *  Copyright (C) 1995  Linus Torvalds
- *  Adapted from 'alpha' version by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu)
- *
- * Support for PReP (Motorola MTX/MVME)
- * by Troy Benjegerdes (hozer@drgw.net)
- */
-
-/*
- * bootup setup stuff..
- */
-
-#include <linux/config.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/major.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/blk.h>
-#include <linux/ioport.h>
-#include <linux/console.h>
-#include <linux/timex.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/seq_file.h>
-
-#include <asm/sections.h>
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/residual.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/cache.h>
-#include <asm/dma.h>
-#include <asm/machdep.h>
-#include <asm/mk48t59.h>
-#include <asm/prep_nvram.h>
-#include <asm/raven.h>
-#include <asm/keyboard.h>
-#include <asm/vga.h>
-#include <asm/time.h>
-
-#include "local_irq.h"
-#include "i8259.h"
-#include "open_pic.h"
-
-#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
-#include <../drivers/sound/sound_config.h>
-#include <../drivers/sound/dev_table.h>
-#endif
-
-unsigned char ucSystemType;
-unsigned char ucBoardRev;
-unsigned char ucBoardRevMaj, ucBoardRevMin;
-
-extern unsigned long mc146818_get_rtc_time(void);
-extern int mc146818_set_rtc_time(unsigned long nowtime);
-extern unsigned long mk48t59_get_rtc_time(void);
-extern int mk48t59_set_rtc_time(unsigned long nowtime);
-
-extern unsigned char prep_nvram_read_val(int addr);
-extern void prep_nvram_write_val(int addr,
-				 unsigned char val);
-extern unsigned char rs_nvram_read_val(int addr);
-extern void rs_nvram_write_val(int addr,
-				 unsigned char val);
-extern void ibm_prep_init(void);
-
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-		char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
-extern unsigned char pckbd_sysrq_xlate[];
-
-extern void prep_find_bridges(void);
-extern char saved_command_line[];
-
-int _prep_type;
-
-#define cached_21	(((char *)(ppc_cached_irq_mask))[3])
-#define cached_A1	(((char *)(ppc_cached_irq_mask))[2])
-
-/* for the mac fs */
-kdev_t boot_dev;
-/* used in nasty hack for sound - see prep_setup_arch() -- Cort */
-long ppc_cs4232_dma, ppc_cs4232_dma2;
-
-extern PTE *Hash, *Hash_end;
-extern unsigned long Hash_size, Hash_mask;
-extern int probingmem;
-extern unsigned long loops_per_jiffy;
-
-#ifdef CONFIG_SOUND_MODULE
-EXPORT_SYMBOL(ppc_cs4232_dma);
-EXPORT_SYMBOL(ppc_cs4232_dma2);
-#endif
-
-static int __prep
-prep_show_cpuinfo(struct seq_file *m)
-{
-	extern char *Motherboard_map_name;
-	int cachew;
-#ifdef CONFIG_PREP_RESIDUAL
-	int i;
-#endif
-
-	seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name);
-
-	switch ( _prep_type ) {
-	case _PREP_IBM:
-		cachew = inw(0x80c);
-		if (cachew & (1<<6))
-			seq_printf(m, "Upgrade CPU\n");
-		seq_printf(m, "L2\t\t: ");
-		if (cachew & (1<<7)) {
-			seq_printf(m, "not present\n");
-			goto no_l2;
-		}
-		seq_printf(m, "%sKb,", (cachew & (1 << 10))? "512" : "256");
-		seq_printf(m, "%ssync\n", (cachew & (1 << 15))? "" : "a");
-		break;
-	case _PREP_Motorola:
-		cachew = *((unsigned char *)CACHECRBA);
-		seq_printf(m, "L2\t\t: ");
-		switch (cachew & L2CACHE_MASK) {
-		case L2CACHE_512KB:
-			seq_printf(m, "512Kb");
-			break;
-		case L2CACHE_256KB:
-			seq_printf(m, "256Kb");
-			break;
-		case L2CACHE_1MB:
-			seq_printf(m, "1MB");
-			break;
-		case L2CACHE_NONE:
-			seq_printf(m, "none\n");
-			goto no_l2;
-			break;
-		default:
-			seq_printf(m, "%x\n", cachew);
-		}
-		
-		seq_printf(m, ", parity %s",
-			   (cachew & L2CACHE_PARITY)? "enabled" : "disabled");
-
-		seq_printf(m, " SRAM:");
-		
-		switch ( ((cachew & 0xf0) >> 4) & ~(0x3) ) {
-		case 1: seq_printf(m, "synchronous,parity,flow-through\n");
-			break;
-		case 2: seq_printf(m, "asynchronous,no parity\n");
-			break;
-		case 3: seq_printf(m, "asynchronous,parity\n");
-			break;
-		default:seq_printf(m, "synchronous,pipelined,no parity\n");
-			break;
-		}
-		break;
-	default:
-		break;
-	}
-
-no_l2:
-#ifdef CONFIG_PREP_RESIDUAL
-	if (res->ResidualLength != 0) {
-		/* print info about SIMMs */
-		seq_printf(m, "simms\t\t: ");
-		for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) {
-			if (res->Memories[i].SIMMSize != 0)
-				seq_printf(m, "%d:%ldM ", i,
-					(res->Memories[i].SIMMSize > 1024) ? 
-					res->Memories[i].SIMMSize>>20 : 
-					res->Memories[i].SIMMSize);
-		}
-		seq_printf(m, "\n");
-	}
-#endif
-
-	return 0;
-}
-
-static int __prep
-prep_show_percpuinfo(struct seq_file *m, int i)
-{
-	/* PREP's without residual data will give incorrect values here */
-	seq_printf(m, "clock\t\t: ");
-#ifdef CONFIG_PREP_RESIDUAL	
-	if (res->ResidualLength)
-		seq_printf(m, "%ldMHz\n",
-			   (res->VitalProductData.ProcessorHz > 1024) ?
-			   res->VitalProductData.ProcessorHz / 1000000 :
-			   res->VitalProductData.ProcessorHz);
-	else
-#endif /* CONFIG_PREP_RESIDUAL */
-		seq_printf(m, "???\n");
-
-	return 0;
-}
-
-static void __init
-prep_setup_arch(void)
-{
-	unsigned char reg;
-#if 0 /* unused?? */
-	unsigned char ucMothMemType;
-	unsigned char ucEquipPres1;
-#endif
-
-	/* init to some ~sane value until calibrate_delay() runs */
-	loops_per_jiffy = 50000000;
-	
-	/* Lookup PCI host bridges */
-	prep_find_bridges();
-	
-	/* Set up floppy in PS/2 mode */
-	outb(0x09, SIO_CONFIG_RA);
-	reg = inb(SIO_CONFIG_RD);
-	reg = (reg & 0x3F) | 0x40;
-	outb(reg, SIO_CONFIG_RD);
-	outb(reg, SIO_CONFIG_RD);	/* Have to write twice to change! */
-
-	/* we should determine this according to what we find! -- Cort */
-	switch ( _prep_type )
-	{
-	case _PREP_IBM:
-		/* Enable L2.  Assume we don't need to flush -- Cort*/
-		*(unsigned char *)(0x8000081c) |= 3;
-		ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
-		break;
-	case _PREP_Motorola:
-		/* Enable L2.  Assume we don't need to flush -- Cort*/
-		*(unsigned char *)(0x8000081c) |= 3;
-#ifdef CONFIG_BLK_DEV_INITRD
-		if (initrd_start)
-			ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); /* /dev/ram */
-		else
-#endif
-#ifdef CONFIG_ROOT_NFS
-			ROOT_DEV = to_kdev_t(0x00ff); /* /dev/nfs */
-#else
-			ROOT_DEV = to_kdev_t(0x0802); /* /dev/sda2 */
-#endif
-		break;
-	}
-
-	/* Read in NVRAM data */ 
-	init_prep_nvram();
-
-	/* if no bootargs, look in NVRAM */
-	if ( cmd_line[0] == '\0' ) {
-		char *bootargs;
-		 bootargs = prep_nvram_get_var("bootargs");
-		 if (bootargs != NULL) {
-			 strcpy(cmd_line, bootargs);
-			 /* again.. */
-			 strcpy(saved_command_line, cmd_line);
-		}
-	}
-
-#ifdef CONFIG_SOUND_CS4232
-	/*
-	 * setup proper values for the cs4232 driver so we don't have
-	 * to recompile for the motorola or ibm workstations sound systems.
-	 * This is a really nasty hack, but unless we change the driver
-	 * it's the only way to support both addrs from one binary.
-	 * -- Cort
-	 */
-	if ( _machine == _MACH_prep )
-	{
-		extern struct card_info snd_installed_cards[];
-		struct card_info *snd_ptr;
-
-		for ( snd_ptr = snd_installed_cards; 
-			snd_ptr < &snd_installed_cards[num_sound_cards];
-			snd_ptr++ )
-		{
-			if ( snd_ptr->card_type == SNDCARD_CS4232 )
-			{
-				if ( _prep_type == _PREP_Motorola )
-				{
-					snd_ptr->config.io_base = 0x830;
-					snd_ptr->config.irq = 10;
-					snd_ptr->config.dma = ppc_cs4232_dma = 6;
-					snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7;
-				}
-				if ( _prep_type == _PREP_IBM )
-				{
-					snd_ptr->config.io_base = 0x530;
-					snd_ptr->config.irq = 5;
-					snd_ptr->config.dma = ppc_cs4232_dma = 1;
-					/* this is wrong - but leave it for now */
-					snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7;
-				}
-			}
-		}
-	}
-#endif /* CONFIG_SOUND_CS4232 */	
-
-	/*print_residual_device_info();*/
-
-	switch (_prep_type) {
-	case _PREP_Motorola:
-		raven_init();
-		break;
-	case _PREP_IBM:
-		ibm_prep_init();
-		break;
-	}
-
-#ifdef CONFIG_VGA_CONSOLE
-	/* remap the VGA memory */
-	vgacon_remap_base = 0xf0000000;
-	/*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/
-	conswitchp = &vga_con;
-#elif defined(CONFIG_DUMMY_CONSOLE)
-	conswitchp = &dummy_con;
-#endif
-}
-
-/*
- * Determine the decrementer frequency from the residual data
- * This allows for a faster boot as we do not need to calibrate the
- * decrementer against another clock. This is important for embedded systems.
- */
-static int __init
-prep_res_calibrate_decr(void)
-{
-#ifdef CONFIG_PREP_RESIDUAL
-	unsigned long freq, divisor = 4;
-
-	if ( res->VitalProductData.ProcessorBusHz ) {
-		freq = res->VitalProductData.ProcessorBusHz;
-		printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
-				(freq/divisor)/1000000,
-				(freq/divisor)%1000000);
-		tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
-		tb_ticks_per_jiffy = freq / HZ / divisor;
-		return 0;
-	} else
-#endif	
-		return 1;
-}
-
-/*
- * Uses the on-board timer to calibrate the on-chip decrementer register
- * for prep systems.  On the pmac the OF tells us what the frequency is
- * but on prep we have to figure it out.
- * -- Cort
- */
-/* Done with 3 interrupts: the first one primes the cache and the
- * 2 following ones measure the interval. The precision of the method
- * is still doubtful due to the short interval sampled.
- */
-static volatile int calibrate_steps __initdata = 3;
-static unsigned tbstamp __initdata = 0;
-
-static void __init
-prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs *regs)
-{
-	unsigned long t, freq;
-	int step=--calibrate_steps;
-
-	t = get_tbl();
-	if (step > 0) {
-		tbstamp = t;
-	} else {
-		freq = (t - tbstamp)*HZ;
-		printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
-			 freq/1000000, freq%1000000);
-		tb_ticks_per_jiffy = freq / HZ;
-		tb_to_us = mulhwu_scale_factor(freq, 1000000);
-	}
-}
-
-static void __init
-prep_calibrate_decr(void)
-{
-	int res;
-
-	/* Try and get this from the residual data. */
-	res = prep_res_calibrate_decr();
-
-	/* If we didn't get it from the residual data, try this. */
-	if ( res ) {
-		unsigned long flags;
-
-		save_flags(flags);
-
-#define TIMER0_COUNT 0x40
-#define TIMER_CONTROL 0x43
-		/* set timer to periodic mode */
-		outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */
-		/* set the clock to ~100 Hz */
-		outb_p(LATCH & 0xff , TIMER0_COUNT);	/* LSB */
-		outb(LATCH >> 8 , TIMER0_COUNT);	/* MSB */
-
-		if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0)
-			panic("Could not allocate timer IRQ!");
-		__sti();
-		/* wait for calibrate */
-		while ( calibrate_steps )
-			;
-		restore_flags(flags);
-		free_irq( 0, NULL);
-	}
-}
-
-static long __init
-mk48t59_init(void) {
-	unsigned char tmp;
-
-	tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
-	if (tmp & MK48T59_RTC_CB_STOP) {
-		printk("Warning: RTC was stopped, date will be wrong.\n");
-		ppc_md.nvram_write_val(MK48T59_RTC_CONTROLB, 
-					 tmp & ~MK48T59_RTC_CB_STOP);
-		/* Low frequency crystal oscillators may take a very long
-		 * time to startup and stabilize. For now just ignore the
-		 * the issue, but attempting to calibrate the decrementer
-		 * from the RTC just after this wakeup is likely to be very 
-		 * inaccurate. Firmware should not allow to load
-		 * the OS with the clock stopped anyway...
-		 */
-	}
-	/* Ensure that the clock registers are updated */
-	tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
-	tmp &= ~(MK48T59_RTC_CA_READ | MK48T59_RTC_CA_WRITE);
-	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, tmp);
-	return 0;
-}
-
-/* We use the NVRAM RTC to time a second to calibrate the decrementer,
- * the RTC registers have just been set up in the right state by the
- * preceding routine.
- */
-static void __init
-mk48t59_calibrate_decr(void)
-{
-	unsigned long freq;
-	unsigned long t1;
-	unsigned char save_control;
-	long i;
-	unsigned char sec;
- 
-		
-	/* Make sure the time is not stopped. */
-	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
-	
-	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
-			(save_control & (~MK48T59_RTC_CB_STOP)));
-
-	/* Now make sure the read bit is off so the value will change. */
-	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
-	save_control &= ~MK48T59_RTC_CA_READ;
-	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
-
-
-	/* Read the seconds value to see when it changes. */
-	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
-	/* Actually this is bad for precision, we should have a loop in
-	 * which we only read the seconds counter. nvram_read_val writes
-	 * the address bytes on every call and this takes a lot of time.
-	 * Perhaps an nvram_wait_change method returning a time
-	 * stamp with a loop count as parameter would be the  solution.
-	 */
-	for (i = 0 ; i < 1000000 ; i++)	{ /* may take up to 1 second... */
-		t1 = get_tbl();
-		if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
-			break;
-		}
-	}
-
-	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
-	for (i = 0 ; i < 1000000 ; i++)	{ /* Should take up 1 second... */
-		freq = get_tbl()-t1;
-		if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec)
-			break;
-	}
-
-	printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
-		 freq/1000000, freq%1000000);
-	tb_ticks_per_jiffy = freq / HZ;
-	tb_to_us = mulhwu_scale_factor(freq, 1000000);
-}
-
-static void __prep
-prep_restart(char *cmd)
-{
-	unsigned long i = 10000;
-
-	__cli();
-
-	/* set exception prefix high - to the prom */
-	_nmask_and_or_msr(0, MSR_IP);
-
-	/* make sure bit 0 (reset) is a 0 */
-	outb( inb(0x92) & ~1L , 0x92 );
-	/* signal a reset to system control port A - soft reset */
-	outb( inb(0x92) | 1 , 0x92 );
-
-	while ( i != 0 ) i++;
-	panic("restart failed\n");
-}
-
-static void __prep
-prep_halt(void)
-{
-	unsigned long flags;
-	__cli();
-	/* set exception prefix high - to the prom */
-	save_flags( flags );
-	restore_flags( flags|MSR_IP );
-
-	/* make sure bit 0 (reset) is a 0 */
-	outb( inb(0x92) & ~1L , 0x92 );
-	/* signal a reset to system control port A - soft reset */
-	outb( inb(0x92) | 1 , 0x92 );
-
-	while ( 1 ) ;
-	/*
-	 * Not reached
-	 */
-}
-
-/*
- * On IBM PReP's, power management is handled by a Signetics 87c750 behind the
- * Utah component on the ISA bus. To access the 750 you must write a series of
- * nibbles to port 0x82a (decoded by the Utah). This is described somewhat in
- * the IBM Carolina Technical Specification.
- * -Hollis
- */
-static void __prep
-utah_sig87c750_setbit(unsigned int bytenum, unsigned int bitnum, int value)
-{
-	/*
-	 * byte1: 0 0 0 1 0  d  a5 a4
-	 * byte2: 0 0 0 1 a3 a2 a1 a0
-	 *
-	 * d = the bit's value, enabled or disabled
-	 * (a5 a4 a3) = the byte number, minus 20
-	 * (a2 a1 a0) = the bit number
-	 *
-	 * example: set the 5th bit of byte 21 (21.5)
-	 *     a5 a4 a3 = 001 (byte 1)
-	 *     a2 a1 a0 = 101 (bit 5)
-	 *
-	 *     byte1 = 0001 0100 (0x14)
-	 *     byte2 = 0001 1101 (0x1d)
-	 */
-	unsigned char byte1=0x10, byte2=0x10;
-	const unsigned int pm_reg_1=0x82a; /* ISA address */
-
-	/* the 750's '20.0' is accessed as '0.0' through Utah (which adds 20) */
-	bytenum -= 20;
-
-	byte1 |= (!!value) << 2;		/* set d */
-	byte1 |= (bytenum >> 1) & 0x3;	/* set a5, a4 */
-
-	byte2 |= (bytenum & 0x1) << 3;	/* set a3 */
-	byte2 |= bitnum & 0x7;			/* set a2, a1, a0 */
-
-	outb(byte1, pm_reg_1);		/* first nibble */
-	mb();
-	udelay(100);				/* important: let controller recover */
-
-	outb(byte2, pm_reg_1);		/* second nibble */
-	mb();
-	udelay(100);				/* important: let controller recover */
-}
-
-static void __prep
-prep_power_off(void)
-{
-	if ( _prep_type == _PREP_IBM) {
-		/* tested on:
-		 * 		Carolina's: 7248-43P, 6070 (PowerSeries 850)
-		 * should work on:
-		 * 		Carolina: 6050 (PowerSeries 830)
-		 * 		7043-140 (Tiger 1)
-		 */
-		unsigned long flags;
-		__cli();
-		/* set exception prefix high - to the prom */
-		save_flags( flags );
-		restore_flags( flags|MSR_IP );
-
-		utah_sig87c750_setbit(21, 5, 1); /* set bit 21.5, "PMEXEC_OFF" */
-
-		while ( 1 ) ;
-		/* not reached */
-	} else {
-		prep_halt();
-	}
-}
-
-static unsigned int __prep
-prep_irq_cannonicalize(u_int irq)
-{
-	if (irq == 2)
-	{
-		return 9;
-	}
-	else
-	{
-		return irq;
-	}
-}
-
-static int __prep
-prep_get_irq(struct pt_regs *regs)
-{
-	return i8259_irq();
-}		
-
-static void __init
-prep_init_IRQ(void)
-{
-	int i;
-
-	if (OpenPIC_Addr != NULL)
-		openpic_init(1, NUM_8259_INTERRUPTS, 0, -1);
-	for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ )
-		irq_desc[i].handler = &i8259_pic;
-	i8259_init(0xbffffff0); /* PCI interrupt ack address for MPC105 and 106 */
-}
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-static int __prep
-prep_ide_default_irq(ide_ioreg_t base)
-{
-	switch (base) {
-		case 0x1f0: return 13;
-		case 0x170: return 13;
-		case 0x1e8: return 11;
-		case 0x168: return 10;
-		case 0xfff0: return 14;		/* MCP(N)750 ide0 */
-		case 0xffe0: return 15;		/* MCP(N)750 ide1 */
-		default: return 0;
-	}
-}
-
-static ide_ioreg_t __prep
-prep_ide_default_io_base(int index)
-{
-	switch (index) {
-		case 0: return 0x1f0;
-		case 1: return 0x170;
-		case 2: return 0x1e8;
-		case 3: return 0x168;
-		default:
-			return 0;
-	}
-}
-
-static int __prep
-prep_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-	return check_region(from, extent);
-}
-
-static void __prep
-prep_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-	request_region(from, extent, name);
-}
-
-static void __prep
-prep_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-	release_region(from, extent);
-}
-
-static void __init
-prep_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t reg = data_port;
-	int i;
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg;
-		reg += 1;
-	}
-	if (ctrl_port) {
-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-	} else {
-		hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
-	}
-	if (irq != NULL)
-		*irq = 0;
-}
-#endif
-
-#ifdef CONFIG_SMP
-/* PReP (MTX) support */
-static int __init
-smp_prep_probe(void)
-{
-	extern int mot_multi;
-
-	if (mot_multi) {
-		openpic_request_IPIs();
-		smp_hw_index[1] = 1;
-		return 2;
-	}
-
-	return 1;
-}
-
-static void __init
-smp_prep_kick_cpu(int nr)
-{
-	*(unsigned long *)KERNELBASE = nr;
-	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
-	printk("CPU1 reset, waiting\n");
-}
-
-static void __init
-smp_prep_setup_cpu(int cpu_nr)
-{
-	if (OpenPIC_Addr)
-		do_openpic_setup_cpu();
-}
-
-static struct smp_ops_t prep_smp_ops __prepdata = {
-	smp_openpic_message_pass,
-	smp_prep_probe,
-	smp_prep_kick_cpu,
-	smp_prep_setup_cpu,
-};
-#endif /* CONFIG_SMP */
-
-/*
- * This finds the amount of physical ram and does necessary
- * setup for prep.  This is pretty architecture specific so
- * this will likely stay separate from the pmac.
- * -- Cort
- */
-static unsigned long __init
-prep_find_end_of_memory(void)
-{
-	unsigned long total = 0;
-	extern unsigned int boot_mem_size;
-
-#ifdef CONFIG_PREP_RESIDUAL	
-	total = res->TotalMemory;
-#endif	
-
-	if (total == 0 && boot_mem_size != 0)
-		total = boot_mem_size;
-	else if (total == 0) {
-		/*
-		 * I need a way to probe the amount of memory if the residual
-		 * data doesn't contain it. -- Cort
-		 */
-		total = 0x02000000;
-		printk(KERN_INFO "Ramsize from residual data was 0"
-			 " -- defaulting to %ldM\n", total>>20);
-	}
-
-	return (total);
-}
-
-/*
- * Setup the bat mappings we're going to load that cover
- * the io areas.  RAM was mapped by mapin_ram().
- * -- Cort
- */
-static void __init
-prep_map_io(void)
-{
-	io_block_mapping(0x80000000, PREP_ISA_IO_BASE, 0x10000000, _PAGE_IO);
-	io_block_mapping(0xf0000000, PREP_ISA_MEM_BASE, 0x08000000, _PAGE_IO);
-}
-
-static void __init
-prep_init2(void)
-{
-#ifdef CONFIG_NVRAM
-	request_region(PREP_NVRAM_AS0, 0x8, "nvram");
-#endif
-	request_region(0x20,0x20,"pic1");
-	request_region(0xa0,0x20,"pic2");
-	request_region(0x00,0x20,"dma1");
-	request_region(0x40,0x20,"timer");
-	request_region(0x80,0x10,"dma page reg");
-	request_region(0xc0,0x20,"dma2");
-}
-
-void __init
-prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
-		unsigned long r6, unsigned long r7)
-{
-#ifdef CONFIG_PREP_RESIDUAL	
-	/* make a copy of residual data */
-	if ( r3 ) {
-		memcpy((void *)res,(void *)(r3+KERNELBASE),
-			 sizeof(RESIDUAL));
-	}
-#endif
-
-	isa_io_base = PREP_ISA_IO_BASE;
-	isa_mem_base = PREP_ISA_MEM_BASE;
-	pci_dram_offset = PREP_PCI_DRAM_OFFSET;
-	ISA_DMA_THRESHOLD = 0x00ffffff;
-	DMA_MODE_READ = 0x44;
-	DMA_MODE_WRITE = 0x48;
-
-	/* figure out what kind of prep workstation we are */
-#ifdef CONFIG_PREP_RESIDUAL	
-	if ( res->ResidualLength != 0 )
-	{
-		if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
-			_prep_type = _PREP_IBM;
-		else
-			_prep_type = _PREP_Motorola;
-	}
-	else /* assume motorola if no residual (netboot?) */
-#endif
-	{
-		_prep_type = _PREP_Motorola;
-	}
-
-	ppc_md.setup_arch     = prep_setup_arch;
-	ppc_md.show_percpuinfo = prep_show_percpuinfo;
-	ppc_md.show_cpuinfo   = prep_show_cpuinfo;
-	ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
-	ppc_md.init_IRQ       = prep_init_IRQ;
-	/* this gets changed later on if we have an OpenPIC -- Cort */
-	ppc_md.get_irq        = prep_get_irq;
-	ppc_md.init           = prep_init2;
-
-	ppc_md.restart        = prep_restart;
-	ppc_md.power_off      = prep_power_off;
-	ppc_md.halt           = prep_halt;
-
-	ppc_md.nvram_read_val = prep_nvram_read_val;
-	ppc_md.nvram_write_val = prep_nvram_write_val;
-
-	ppc_md.time_init      = NULL;
-	if (_prep_type == _PREP_IBM) {
-		ppc_md.set_rtc_time   = mc146818_set_rtc_time;
-		ppc_md.get_rtc_time   = mc146818_get_rtc_time;
-		ppc_md.calibrate_decr = prep_calibrate_decr;
-	} else {
-		ppc_md.set_rtc_time   = mk48t59_set_rtc_time;
-		ppc_md.get_rtc_time   = mk48t59_get_rtc_time;
-		ppc_md.calibrate_decr = mk48t59_calibrate_decr;
-		ppc_md.time_init      = mk48t59_init;
-	}
-
-	ppc_md.find_end_of_memory = prep_find_end_of_memory;
-	ppc_md.setup_io_mappings = prep_map_io;
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-	ppc_ide_md.default_irq = prep_ide_default_irq;
-	ppc_ide_md.default_io_base = prep_ide_default_io_base;
-	ppc_ide_md.ide_check_region = prep_ide_check_region;
-	ppc_ide_md.ide_request_region = prep_ide_request_region;
-	ppc_ide_md.ide_release_region = prep_ide_release_region;
-	ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
-#endif
-
-#ifdef CONFIG_VT
-	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
-	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
-	ppc_md.kbd_translate     = pckbd_translate;
-	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
-	ppc_md.kbd_leds          = pckbd_leds;
-	ppc_md.kbd_init_hw       = pckbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
-	SYSRQ_KEY = 0x54;
-#endif
-#endif
-
-#ifdef CONFIG_SMP
-	ppc_md.smp_ops		 = &prep_smp_ops;
-#endif /* CONFIG_SMP */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/prep_time.c linux-2.4.20/arch/ppc/kernel/prep_time.c
--- linux-2.4.19/arch/ppc/kernel/prep_time.c	2001-09-08 19:38:42.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/prep_time.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,228 +0,0 @@
-/*
- * BK Id: SCCS/s.prep_time.c 1.10 09/08/01 15:47:42 paulus
- */
-/*
- *  linux/arch/i386/kernel/time.c
- *
- *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *
- * Adapted for PowerPC (PreP) by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
- *  copied and modified from intel version
- *
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-#include <linux/kernel_stat.h>
-#include <linux/init.h>
-
-#include <asm/sections.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/processor.h>
-#include <asm/machdep.h>
-#include <asm/prep_nvram.h>
-#include <asm/mk48t59.h>
-
-#include <asm/time.h>
-
-extern spinlock_t rtc_lock;
-
-/*
- * The motorola uses the m48t18 rtc (includes DS1643) whose registers
- * are at a higher end of nvram (1ff8-1fff) than the ibm mc146818
- * rtc (ds1386) which has regs at addr 0-d).  The intel gets
- * past this because the bios emulates the mc146818.
- *
- * Why in the world did they have to use different clocks?
- *
- * Right now things are hacked to check which machine we're on then
- * use the appropriate macro.  This is very very ugly and I should
- * probably have a function that checks which machine we're on then
- * does things correctly transparently or a function pointer which
- * is setup at boot time to use the correct addresses.
- * -- Cort
- */
-
-/*
- * Set the hardware clock. -- Cort
- */
-__prep
-int mc146818_set_rtc_time(unsigned long nowtime)
-{
-	unsigned char save_control, save_freq_select;
-	struct rtc_time tm;
-
-	spin_lock(&rtc_lock);
-	to_tm(nowtime, &tm);
-
-	/* tell the clock it's being set */
-	save_control = CMOS_READ(RTC_CONTROL);
-	
-	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
-	
-	/* stop and reset prescaler */
-	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
-	
-	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-	
-        tm.tm_year = (tm.tm_year - 1900) % 100;
-	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-		BIN_TO_BCD(tm.tm_sec);
-		BIN_TO_BCD(tm.tm_min);
-		BIN_TO_BCD(tm.tm_hour);
-		BIN_TO_BCD(tm.tm_mon);
-		BIN_TO_BCD(tm.tm_mday);
-		BIN_TO_BCD(tm.tm_year);
-	}
-	CMOS_WRITE(tm.tm_sec,  RTC_SECONDS);
-	CMOS_WRITE(tm.tm_min,  RTC_MINUTES);
-	CMOS_WRITE(tm.tm_hour, RTC_HOURS);
-	CMOS_WRITE(tm.tm_mon,  RTC_MONTH);
-	CMOS_WRITE(tm.tm_mday, RTC_DAY_OF_MONTH);
-	CMOS_WRITE(tm.tm_year, RTC_YEAR);
-	
-	/* The following flags have to be released exactly in this order,
-	 * otherwise the DS12887 (popular MC146818A clone with integrated
-	 * battery and quartz) will not reset the oscillator and will not
-	 * update precisely 500 ms later. You won't find this mentioned in
-	 * the Dallas Semiconductor data sheets, but who believes data
-	 * sheets anyway ...                           -- Markus Kuhn
-	 */
-	CMOS_WRITE(save_control,     RTC_CONTROL);
-	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
-	spin_unlock(&rtc_lock);
-
-	return 0;
-}
-
-__prep
-unsigned long mc146818_get_rtc_time(void)
-{
-	unsigned int year, mon, day, hour, min, sec;
-	int uip, i;
-
-	/* The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-
-	/* Since the UIP flag is set for about 2.2 ms and the clock
-	 * is typically written with a precision of 1 jiffy, trying
-	 * to obtain a precision better than a few milliseconds is 
-	 * an illusion. Only consistency is interesting, this also
-	 * allows to use the routine for /dev/rtc without a potential
-	 * 1 second kernel busy loop triggered by any reader of /dev/rtc. 
-	 */
-
-	for ( i = 0; i<1000000; i++) {
-		uip = CMOS_READ(RTC_FREQ_SELECT);
-		sec = CMOS_READ(RTC_SECONDS);
-		min = CMOS_READ(RTC_MINUTES);
-		hour = CMOS_READ(RTC_HOURS);
-		day = CMOS_READ(RTC_DAY_OF_MONTH);
-		mon = CMOS_READ(RTC_MONTH);
-		year = CMOS_READ(RTC_YEAR);
-		uip |= CMOS_READ(RTC_FREQ_SELECT);
-		if ((uip & RTC_UIP)==0) break;
-	}
-
-	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
-	    || RTC_ALWAYS_BCD)
-	{
-		BCD_TO_BIN(sec);
-		BCD_TO_BIN(min);
-		BCD_TO_BIN(hour);
-		BCD_TO_BIN(day);
-		BCD_TO_BIN(mon);
-		BCD_TO_BIN(year);
-	}
-	if ((year += 1900) < 1970)
-		year += 100;
-	return mktime(year, mon, day, hour, min, sec);
-}
-
-__prep
-int mk48t59_set_rtc_time(unsigned long nowtime)
-{
-	unsigned char save_control;
-	struct rtc_time tm;
-
-	spin_lock(&rtc_lock);
-	to_tm(nowtime, &tm);
-
-	/* tell the clock it's being written */
-	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
-	
-	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
-			     (save_control | MK48T59_RTC_CA_WRITE));
-
-        tm.tm_year = (tm.tm_year - 1900) % 100;
-	BIN_TO_BCD(tm.tm_sec);
-	BIN_TO_BCD(tm.tm_min);
-	BIN_TO_BCD(tm.tm_hour);
-	BIN_TO_BCD(tm.tm_mon);
-	BIN_TO_BCD(tm.tm_mday);
-	BIN_TO_BCD(tm.tm_year);
-
-	ppc_md.nvram_write_val(MK48T59_RTC_SECONDS,      tm.tm_sec);
-	ppc_md.nvram_write_val(MK48T59_RTC_MINUTES,      tm.tm_min);
-	ppc_md.nvram_write_val(MK48T59_RTC_HOURS,        tm.tm_hour);
-	ppc_md.nvram_write_val(MK48T59_RTC_MONTH,        tm.tm_mon);
-	ppc_md.nvram_write_val(MK48T59_RTC_DAY_OF_MONTH, tm.tm_mday);
-	ppc_md.nvram_write_val(MK48T59_RTC_YEAR,         tm.tm_year);
-	
-	/* Turn off the write bit. */
-	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
-	spin_unlock(&rtc_lock);
-
-	return 0;
-}
-
-__prep
-unsigned long mk48t59_get_rtc_time(void)
-{
-	unsigned char save_control;
-	unsigned int year, mon, day, hour, min, sec;
-
-	/* Simple: freeze the clock, read it and allow updates again */
-	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
-	save_control &= ~MK48T59_RTC_CA_READ;
-	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
-
-	/* Set the register to read the value. */
-	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
-			     (save_control | MK48T59_RTC_CA_READ));
-
-	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
-	min = ppc_md.nvram_read_val(MK48T59_RTC_MINUTES);
-	hour = ppc_md.nvram_read_val(MK48T59_RTC_HOURS);
-	day = ppc_md.nvram_read_val(MK48T59_RTC_DAY_OF_MONTH);
-	mon = ppc_md.nvram_read_val(MK48T59_RTC_MONTH);
-	year = ppc_md.nvram_read_val(MK48T59_RTC_YEAR);
-
-	/* Let the time values change again. */
-	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
-
-	BCD_TO_BIN(sec);
-	BCD_TO_BIN(min);
-	BCD_TO_BIN(hour);
-	BCD_TO_BIN(day);
-	BCD_TO_BIN(mon);
-	BCD_TO_BIN(year);
-
-	year = year + 1900;
-	if (year < 1970) {
-		year += 100;
-	}
-
-	return mktime(year, mon, day, hour, min, sec);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/proc_rtas.c linux-2.4.20/arch/ppc/kernel/proc_rtas.c
--- linux-2.4.19/arch/ppc/kernel/proc_rtas.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/proc_rtas.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,787 +0,0 @@
-/*
- * BK Id: SCCS/s.proc_rtas.c 1.5 05/17/01 18:14:22 cort
- */
-/*
- *   arch/ppc/kernel/proc_rtas.c
- *   Copyright (C) 2000 Tilmann Bitterberg
- *   (tilmann@bitterberg.de)
- *
- *   RTAS (Runtime Abstraction Services) stuff
- *   Intention is to provide a clean user interface
- *   to use the RTAS.
- *
- *   TODO:
- *   Split off a header file and maybe move it to a different
- *   location. Write Documentation on what the /proc/rtas/ entries
- *   actually do.
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/ctype.h>
-#include <linux/time.h>
-#include <linux/string.h>
-
-#include <asm/uaccess.h>
-#include <asm/bitops.h>
-#include <asm/processor.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/machdep.h> /* for ppc_md */
-#include <asm/time.h>
-
-/* Token for Sensors */
-#define KEY_SWITCH		0x0001
-#define ENCLOSURE_SWITCH	0x0002
-#define THERMAL_SENSOR		0x0003
-#define LID_STATUS		0x0004
-#define POWER_SOURCE		0x0005
-#define BATTERY_VOLTAGE		0x0006
-#define BATTERY_REMAINING	0x0007
-#define BATTERY_PERCENTAGE	0x0008
-#define EPOW_SENSOR		0x0009
-#define BATTERY_CYCLESTATE	0x000a
-#define BATTERY_CHARGING	0x000b
-
-/* IBM specific sensors */
-#define IBM_SURVEILLANCE	0x2328 /* 9000 */
-#define IBM_FANRPM		0x2329 /* 9001 */
-#define IBM_VOLTAGE		0x232a /* 9002 */
-#define IBM_DRCONNECTOR		0x232b /* 9003 */
-#define IBM_POWERSUPPLY		0x232c /* 9004 */
-#define IBM_INTQUEUE		0x232d /* 9005 */
-
-/* Status return values */
-#define SENSOR_CRITICAL_HIGH	13
-#define SENSOR_WARNING_HIGH	12
-#define SENSOR_NORMAL		11
-#define SENSOR_WARNING_LOW	10
-#define SENSOR_CRITICAL_LOW	 9
-#define SENSOR_SUCCESS		 0
-#define SENSOR_HW_ERROR		-1
-#define SENSOR_BUSY		-2
-#define SENSOR_NOT_EXIST	-3
-#define SENSOR_DR_ENTITY	-9000
-
-/* Location Codes */
-#define LOC_SCSI_DEV_ADDR	'A'
-#define LOC_SCSI_DEV_LOC	'B'
-#define LOC_CPU			'C'
-#define LOC_DISKETTE		'D'
-#define LOC_ETHERNET		'E'
-#define LOC_FAN			'F'
-#define LOC_GRAPHICS		'G'
-/* reserved / not used		'H' */
-#define LOC_IO_ADAPTER		'I'
-/* reserved / not used		'J' */
-#define LOC_KEYBOARD		'K'
-#define LOC_LCD			'L'
-#define LOC_MEMORY		'M'
-#define LOC_NV_MEMORY		'N'
-#define LOC_MOUSE		'O'
-#define LOC_PLANAR		'P'
-#define LOC_OTHER_IO		'Q'
-#define LOC_PARALLEL		'R'
-#define LOC_SERIAL		'S'
-#define LOC_DEAD_RING		'T'
-#define LOC_RACKMOUNTED		'U' /* for _u_nit is rack mounted */
-#define LOC_VOLTAGE		'V'
-#define LOC_SWITCH_ADAPTER	'W'
-#define LOC_OTHER		'X'
-#define LOC_FIRMWARE		'Y'
-#define LOC_SCSI		'Z'
-
-/* Tokens for indicators */
-#define TONE_FREQUENCY		0x0001 /* 0 - 1000 (HZ)*/
-#define TONE_VOLUME		0x0002 /* 0 - 100 (%) */
-#define SYSTEM_POWER_STATE	0x0003 
-#define WARNING_LIGHT		0x0004
-#define DISK_ACTIVITY_LIGHT	0x0005
-#define HEX_DISPLAY_UNIT	0x0006
-#define BATTERY_WARNING_TIME	0x0007
-#define CONDITION_CYCLE_REQUEST	0x0008
-#define SURVEILLANCE_INDICATOR	0x2328 /* 9000 */
-#define DR_ACTION		0x2329 /* 9001 */
-#define DR_INDICATOR		0x232a /* 9002 */
-/* 9003 - 9004: Vendor specific */
-#define GLOBAL_INTERRUPT_QUEUE	0x232d /* 9005 */
-/* 9006 - 9999: Vendor specific */
-
-/* other */
-#define MAX_SENSORS		 17  /* I only know of 17 sensors */    
-#define MAX_LINELENGTH          256
-#define SENSOR_PREFIX		"ibm,sensor-"
-#define cel_to_fahr(x)		((x*9/5)+32)
-
-
-/* Globals */
-static struct proc_dir_entry *proc_rtas;
-static struct rtas_sensors sensors;
-static struct device_node *rtas;
-static unsigned long power_on_time = 0; /* Save the time the user set */
-static char progress_led[MAX_LINELENGTH];
-
-static unsigned long rtas_tone_frequency = 1000;
-static unsigned long rtas_tone_volume = 0;
-
-/* ****************STRUCTS******************************************* */
-struct individual_sensor {
-	unsigned int token;
-	unsigned int quant;
-};
-
-struct rtas_sensors {
-        struct individual_sensor sensor[MAX_SENSORS];
-	unsigned int quant;
-};
-
-/* ****************************************************************** */
-/* Declarations */
-static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off,
-		int count, int *eof, void *data);
-static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, 
-		size_t count, loff_t *ppos);
-static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, 
-		size_t count, loff_t *ppos);
-static ssize_t ppc_rtas_progress_read(struct file * file, char * buf,
-		size_t count, loff_t *ppos);
-static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf,
-		size_t count, loff_t *ppos);
-static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf,
-		size_t count, loff_t *ppos);
-static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf,
-		size_t count, loff_t *ppos);
-
-static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf,
-		size_t count, loff_t *ppos);
-static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf,
-		size_t count, loff_t *ppos);
-static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf,
-		size_t count, loff_t *ppos);
-static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
-		size_t count, loff_t *ppos);
-
-struct file_operations ppc_rtas_poweron_operations = {
-	read:		ppc_rtas_poweron_read,
-	write:		ppc_rtas_poweron_write
-};
-struct file_operations ppc_rtas_progress_operations = {
-	read:		ppc_rtas_progress_read,
-	write:		ppc_rtas_progress_write
-};
-
-struct file_operations ppc_rtas_clock_operations = {
-	read:		ppc_rtas_clock_read,
-	write:		ppc_rtas_clock_write
-};
-
-struct file_operations ppc_rtas_tone_freq_operations = {
-	read:		ppc_rtas_tone_freq_read,
-	write:		ppc_rtas_tone_freq_write
-};
-struct file_operations ppc_rtas_tone_volume_operations = {
-	read:		ppc_rtas_tone_volume_read,
-	write:		ppc_rtas_tone_volume_write
-};
-
-int ppc_rtas_find_all_sensors (void);
-int ppc_rtas_process_sensor(struct individual_sensor s, int state, 
-		int error, char * buf);
-char * ppc_rtas_process_error(int error);
-int get_location_code(struct individual_sensor s, char * buf);
-int check_location_string (char *c, char * buf);
-int check_location (char *c, int idx, char * buf);
-
-/* ****************************************************************** */
-/* MAIN                                                               */
-/* ****************************************************************** */
-void proc_rtas_init(void)
-{
-	struct proc_dir_entry *entry;
-
-	rtas = find_devices("rtas");
-	if ((rtas == 0) || (_machine != _MACH_chrp)) {
-		return;
-	}
-	
-	proc_rtas = proc_mkdir("rtas", 0);
-	if (proc_rtas == 0)
-		return;
-
-	/* /proc/rtas entries */
-
-	entry = create_proc_entry("progress", S_IRUGO|S_IWUSR, proc_rtas);
-	if (entry) entry->proc_fops = &ppc_rtas_progress_operations;
-
-	entry = create_proc_entry("clock", S_IRUGO|S_IWUSR, proc_rtas); 
-	if (entry) entry->proc_fops = &ppc_rtas_clock_operations;
-
-	entry = create_proc_entry("poweron", S_IWUSR|S_IRUGO, proc_rtas); 
-	if (entry) entry->proc_fops = &ppc_rtas_poweron_operations;
-
-	create_proc_read_entry("sensors", S_IRUGO, proc_rtas, 
-			ppc_rtas_sensor_read, NULL);
-	
-	entry = create_proc_entry("frequency", S_IWUSR|S_IRUGO, proc_rtas); 
-	if (entry) entry->proc_fops = &ppc_rtas_tone_freq_operations;
-
-	entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, proc_rtas); 
-	if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations;
-}
-
-/* ****************************************************************** */
-/* POWER-ON-TIME                                                      */
-/* ****************************************************************** */
-static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf,
-		size_t count, loff_t *ppos)
-{
-	struct rtc_time tm;
-	unsigned long nowtime;
-	char *dest;
-	int error;
-
-	nowtime = simple_strtoul(buf, &dest, 10);
-	if (*dest != '\0' && *dest != '\n') {
-		printk("ppc_rtas_poweron_write: Invalid time\n");
-		return count;
-	}
-	power_on_time = nowtime; /* save the time */
-
-	to_tm(nowtime, &tm);
-
-	error = call_rtas("set-time-for-power-on", 7, 1, NULL, 
-			tm.tm_year, tm.tm_mon, tm.tm_mday, 
-			tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */);
-	if (error != 0)
-		printk(KERN_WARNING "error: setting poweron time returned: %s\n", 
-				ppc_rtas_process_error(error));
-	return count;
-}
-/* ****************************************************************** */
-static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf,
-		size_t count, loff_t *ppos)
-{
-	int n;
-	if (power_on_time == 0)
-		n = sprintf(buf, "Power on time not set\n");
-	else
-		n = sprintf(buf, "%lu\n", power_on_time);
-
-	if (*ppos >= strlen(buf))
-		return 0;
-	if (n > strlen(buf) - *ppos)
-		n = strlen(buf) - *ppos;
-	if (n > count)
-		n = count;
-	*ppos += n;
-	return n;
-}
-
-/* ****************************************************************** */
-/* PROGRESS                                                           */
-/* ****************************************************************** */
-static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf,
-		size_t count, loff_t *ppos)
-{
-	unsigned long hex;
-
-	strcpy(progress_led, buf); /* save the string */
-	/* Lets see if the user passed hexdigits */
-	hex = simple_strtoul(buf, NULL, 10);
-	
-	ppc_md.progress ((char *)buf, hex);
-	return count;
-
-	/* clear the line */ /* ppc_md.progress("                   ", 0xffff);*/
-}
-/* ****************************************************************** */
-static ssize_t ppc_rtas_progress_read(struct file * file, char * buf,
-		size_t count, loff_t *ppos)
-{
-	int n = 0;
-	if (progress_led != NULL)
-		n = sprintf (buf, "%s\n", progress_led);
-	if (*ppos >= strlen(buf))
-		return 0;
-	if (n > strlen(buf) - *ppos)
-		n = strlen(buf) - *ppos;
-	if (n > count)
-		n = count;
-	*ppos += n;
-	return n;
-}
-
-/* ****************************************************************** */
-/* CLOCK                                                              */
-/* ****************************************************************** */
-static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, 
-		size_t count, loff_t *ppos)
-{
-	struct rtc_time tm;
-	unsigned long nowtime;
-	char *dest;
-	int error;
-
-	nowtime = simple_strtoul(buf, &dest, 10);
-	if (*dest != '\0' && *dest != '\n') {
-		printk("ppc_rtas_clock_write: Invalid time\n");
-		return count;
-	}
-
-	to_tm(nowtime, &tm);
-	error = call_rtas("set-time-of-day", 7, 1, NULL, 
-			tm.tm_year, tm.tm_mon, tm.tm_mday, 
-			tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
-	if (error != 0)
-		printk(KERN_WARNING "error: setting the clock returned: %s\n", 
-				ppc_rtas_process_error(error));
-	return count;
-}
-/* ****************************************************************** */
-static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, 
-		size_t count, loff_t *ppos)
-{
-	unsigned int year, mon, day, hour, min, sec;
-	unsigned long *ret = kmalloc(4*8, GFP_KERNEL);
-	int n, error;
-
-	error = call_rtas("get-time-of-day", 0, 8, ret);
-	
-	year = ret[0]; mon  = ret[1]; day  = ret[2];
-	hour = ret[3]; min  = ret[4]; sec  = ret[5];
-
-	if (error != 0){
-		printk(KERN_WARNING "error: reading the clock returned: %s\n", 
-				ppc_rtas_process_error(error));
-		n = sprintf (buf, "0");
-	} else { 
-		n = sprintf (buf, "%lu\n", mktime(year, mon, day, hour, min, sec));
-	}
-	kfree(ret);
-
-	if (*ppos >= strlen(buf))
-		return 0;
-	if (n > strlen(buf) - *ppos)
-		n = strlen(buf) - *ppos;
-	if (n > count)
-		n = count;
-	*ppos += n;
-	return n;
-}
-
-/* ****************************************************************** */
-/* SENSOR STUFF                                                       */
-/* ****************************************************************** */
-static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off,
-		int count, int *eof, void *data)
-{
-	int i,j,n;
-	unsigned long ret;
-	int state, error;
-	char buffer[MAX_LINELENGTH*MAX_SENSORS]; /* May not be enough */
-
-	if (count < 0)
-		return -EINVAL;
-
-	n  = sprintf ( buffer  , "RTAS (RunTime Abstraction Services) Sensor Information\n");
-	n += sprintf ( buffer+n, "Sensor\t\tValue\t\tCondition\tLocation\n");
-	n += sprintf ( buffer+n, "********************************************************\n");
-
-	if (ppc_rtas_find_all_sensors() != 0) {
-		n += sprintf ( buffer+n, "\nNo sensors are available\n");
-		goto return_string;
-	}
-
-	for (i=0; i<sensors.quant; i++) {
-		j = sensors.sensor[i].quant;
-		/* A sensor may have multiple instances */
-		while (j >= 0) {
-			error =	call_rtas("get-sensor-state", 2, 2, &ret, 
-				  sensors.sensor[i].token, sensors.sensor[i].quant-j);
-			state = (int) ret;
-			n += ppc_rtas_process_sensor(sensors.sensor[i], state, error, buffer+n );
-			n += sprintf (buffer+n, "\n");
-			j--;
-		} /* while */
-	} /* for */
-
-return_string:
-	if (off >= strlen(buffer)) {
-		*eof = 1;
-		return 0;
-	}
-	if (n > strlen(buffer) - off)
-		n = strlen(buffer) - off;
-	if (n > count)
-		n = count;
-	else
-		*eof = 1;
-	memcpy(buf, buffer + off, n);
-	*start = buf;
-	return n;
-}
-
-/* ****************************************************************** */
-
-int ppc_rtas_find_all_sensors (void)
-{
-	unsigned long *utmp;
-	int len, i, j;
-
-	utmp = (unsigned long *) get_property(rtas, "rtas-sensors", &len);
-	if (utmp == NULL) {
-		printk (KERN_ERR "error: could not get rtas-sensors\n");
-		return 1;
-	}
-
-	sensors.quant = len / 8;      /* int + int */
-
-	for (i=0, j=0; j<sensors.quant; i+=2, j++) {
-		sensors.sensor[j].token = utmp[i];
-		sensors.sensor[j].quant = utmp[i+1];
-	}
-	return 0;
-}
-
-/* ****************************************************************** */
-/*
- * Builds a string of what rtas returned
- */
-char * ppc_rtas_process_error(int error)
-{
-	switch (error) {
-		case SENSOR_CRITICAL_HIGH:
-			return "(critical high)";
-		case SENSOR_WARNING_HIGH:
-			return "(warning high)";
-		case SENSOR_NORMAL:
-			return "(normal)";
-		case SENSOR_WARNING_LOW:
-			return "(warning low)";
-		case SENSOR_CRITICAL_LOW:
-			return "(critical low)";
-		case SENSOR_SUCCESS:
-			return "(read ok)";
-		case SENSOR_HW_ERROR:
-			return "(hardware error)";
-		case SENSOR_BUSY:
-			return "(busy)";
-		case SENSOR_NOT_EXIST:
-			return "(non existant)";
-		case SENSOR_DR_ENTITY:
-			return "(dr entity removed)";
-		default:
-			return "(UNKNOWN)";
-	}
-}
-
-/* ****************************************************************** */
-/*
- * Builds a string out of what the sensor said
- */
-
-int ppc_rtas_process_sensor(struct individual_sensor s, int state, 
-		int error, char * buf) 
-{
-	/* Defined return vales */
-	const char * key_switch[]        = { "Off\t", "Normal\t", "Secure\t", "Mainenance" };
-	const char * enclosure_switch[]  = { "Closed", "Open" };
-	const char * lid_status[]        = { " ", "Open", "Closed" };
-	const char * power_source[]      = { "AC\t", "Battery", "AC & Battery" };
-	const char * battery_remaining[] = { "Very Low", "Low", "Mid", "High" };
-	const char * epow_sensor[]       = { 
-		"EPOW Reset", "Cooling warning", "Power warning",
-		"System shutdown", "System halt", "EPOW main enclosure",
-		"EPOW power off" };
-	const char * battery_cyclestate[]  = { "None", "In progress", "Requested" };
-	const char * battery_charging[]    = { "Charging", "Discharching", "No current flow" };
-	const char * ibm_drconnector[]     = { "Empty", "Present" };
-	const char * ibm_intqueue[]        = { "Disabled", "Enabled" };
-
-	int have_strings = 0;
-	int temperature = 0;
-	int unknown = 0;
-	int n = 0;
-
-	/* What kind of sensor do we have here? */
-	switch (s.token) {
-		case KEY_SWITCH:
-			n += sprintf(buf+n, "Key switch:\t");
-			n += sprintf(buf+n, "%s\t", key_switch[state]);
-			have_strings = 1;
-			break;
-		case ENCLOSURE_SWITCH:
-			n += sprintf(buf+n, "Enclosure switch:\t");
-			n += sprintf(buf+n, "%s\t", enclosure_switch[state]);
-			have_strings = 1;
-			break;
-		case THERMAL_SENSOR:
-			n += sprintf(buf+n, "Temp. (C/F):\t");
-			temperature = 1;
-			break;
-		case LID_STATUS:
-			n += sprintf(buf+n, "Lid status:\t");
-			n += sprintf(buf+n, "%s\t", lid_status[state]);
-			have_strings = 1;
-			break;
-		case POWER_SOURCE:
-			n += sprintf(buf+n, "Power source:\t");
-			n += sprintf(buf+n, "%s\t", power_source[state]);
-			have_strings = 1;
-			break;
-		case BATTERY_VOLTAGE:
-			n += sprintf(buf+n, "Battery voltage:\t");
-			break;
-		case BATTERY_REMAINING:
-			n += sprintf(buf+n, "Battery remaining:\t");
-			n += sprintf(buf+n, "%s\t", battery_remaining[state]);
-			have_strings = 1;
-			break;
-		case BATTERY_PERCENTAGE:
-			n += sprintf(buf+n, "Battery percentage:\t");
-			break;
-		case EPOW_SENSOR:
-			n += sprintf(buf+n, "EPOW Sensor:\t");
-			n += sprintf(buf+n, "%s\t", epow_sensor[state]);
-			have_strings = 1;
-			break;
-		case BATTERY_CYCLESTATE:
-			n += sprintf(buf+n, "Battery cyclestate:\t");
-			n += sprintf(buf+n, "%s\t", battery_cyclestate[state]);
-			have_strings = 1;
-			break;
-		case BATTERY_CHARGING:
-			n += sprintf(buf+n, "Battery Charging:\t");
-			n += sprintf(buf+n, "%s\t", battery_charging[state]);
-			have_strings = 1;
-			break;
-		case IBM_SURVEILLANCE:
-			n += sprintf(buf+n, "Surveillance:\t");
-			break;
-		case IBM_FANRPM:
-			n += sprintf(buf+n, "Fan (rpm):\t");
-			break;
-		case IBM_VOLTAGE:
-			n += sprintf(buf+n, "Voltage (mv):\t");
-			break;
-		case IBM_DRCONNECTOR:
-			n += sprintf(buf+n, "DR connector:\t");
-			n += sprintf(buf+n, "%s\t", ibm_drconnector[state]);
-			have_strings = 1;
-			break;
-		case IBM_POWERSUPPLY:
-			n += sprintf(buf+n, "Powersupply:\t");
-			break;
-		case IBM_INTQUEUE:
-			n += sprintf(buf+n, "Interrupt queue:\t");
-			n += sprintf(buf+n, "%s\t", ibm_intqueue[state]);
-			have_strings = 1;
-			break;
-		default:
-			n += sprintf(buf+n,  "Unkown sensor (type %d), ignoring it\n",
-					s.token);
-			unknown = 1;
-			have_strings = 1;
-			break;
-	}
-	if (have_strings == 0) {
-		if (temperature) {
-			n += sprintf(buf+n, "%4d /%4d\t", state, cel_to_fahr(state));
-		} else
-			n += sprintf(buf+n, "%10d\t", state);
-	}
-	if (unknown == 0) {
-		n += sprintf ( buf+n, "%s\t", ppc_rtas_process_error(error));
-		n += get_location_code(s, buf+n);
-	}
-	return n;
-}
-
-/* ****************************************************************** */
-
-int check_location (char *c, int idx, char * buf)
-{
-	int n = 0;
-
-	switch (*(c+idx)) {
-		case LOC_PLANAR:
-			n += sprintf ( buf, "Planar #%c", *(c+idx+1));
-			break;
-		case LOC_CPU:
-			n += sprintf ( buf, "CPU #%c", *(c+idx+1));
-			break;
-		case LOC_FAN:
-			n += sprintf ( buf, "Fan #%c", *(c+idx+1));
-			break;
-		case LOC_RACKMOUNTED:
-			n += sprintf ( buf, "Rack #%c", *(c+idx+1));
-			break;
-		case LOC_VOLTAGE:
-			n += sprintf ( buf, "Voltage #%c", *(c+idx+1));
-			break;
-		case LOC_LCD:
-			n += sprintf ( buf, "LCD #%c", *(c+idx+1));
-			break;
-		case '.':
-			n += sprintf ( buf, "- %c", *(c+idx+1));
-		default:
-			n += sprintf ( buf, "Unknown location");
-			break;
-	}
-	return n;
-}
-
-
-/* ****************************************************************** */
-/* 
- * Format: 
- * ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ]
- * the '.' may be an abbrevation
- */
-int check_location_string (char *c, char *buf)
-{
-	int n=0,i=0;
-
-	while (c[i]) {
-		if (isalpha(c[i]) || c[i] == '.') {
-			 n += check_location(c, i, buf+n);
-		}
-		else if (c[i] == '/' || c[i] == '-')
-			n += sprintf(buf+n, " at ");
-		i++;
-	}
-	return n;
-}
-
-
-/* ****************************************************************** */
-
-int get_location_code(struct individual_sensor s, char * buffer)
-{
-	char rstr[512], tmp[10], tmp2[10];
-	int n=0, i=0, llen, len;
-	/* char *buf = kmalloc(MAX_LINELENGTH, GFP_KERNEL); */
-	char *ret;
-
-	static int pos = 0; /* remember position where buffer was */
-
-	/* construct the sensor number like 0003 */
-	/* fill with zeros */
-	n = sprintf(tmp, "%d", s.token);
-	len = strlen(tmp);
-	while (strlen(tmp) < 4)
-		n += sprintf (tmp+n, "0");
-	
-	/* invert the string */
-	while (tmp[i]) {
-		if (i<len)
-			tmp2[4-len+i] = tmp[i];
-		else
-			tmp2[3-i] = tmp[i];
-		i++;
-	}
-	tmp2[4] = '\0';
-
-	sprintf (rstr, SENSOR_PREFIX"%s", tmp2);
-
-	ret = (char *) get_property(rtas, rstr, &llen);
-
-	n=0;
-	if (ret[0] == '\0')
-		n += sprintf ( buffer+n, "--- ");/* does not have a location */
-	else {
-		char t[50];
-		ret += pos;
-
-		n += check_location_string(ret, buffer + n);
-		n += sprintf ( buffer+n, " ");
-		/* see how many characters we have printed */
-		sprintf ( t, "%s ", ret);
-
-		pos += strlen(t);
-		if (pos >= llen) pos=0;
-	}
-	return n;
-}
-/* ****************************************************************** */
-/* INDICATORS - Tone Frequency                                        */
-/* ****************************************************************** */
-static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf,
-		size_t count, loff_t *ppos)
-{
-	unsigned long freq;
-	char *dest;
-	int error;
-	freq = simple_strtoul(buf, &dest, 10);
-	if (*dest != '\0' && *dest != '\n') {
-		printk("ppc_rtas_tone_freq_write: Invalid tone freqency\n");
-		return count;
-	}
-	if (freq < 0) freq = 0;
-	rtas_tone_frequency = freq; /* save it for later */
-	error = call_rtas("set-indicator", 3, 1, NULL,
-			TONE_FREQUENCY, 0, freq);
-	if (error != 0)
-		printk(KERN_WARNING "error: setting tone frequency returned: %s\n", 
-				ppc_rtas_process_error(error));
-	return count;
-}
-/* ****************************************************************** */
-static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf,
-		size_t count, loff_t *ppos)
-{
-	int n;
-	n = sprintf(buf, "%lu\n", rtas_tone_frequency);
-
-	if (*ppos >= strlen(buf))
-		return 0;
-	if (n > strlen(buf) - *ppos)
-		n = strlen(buf) - *ppos;
-	if (n > count)
-		n = count;
-	*ppos += n;
-	return n;
-}
-/* ****************************************************************** */
-/* INDICATORS - Tone Volume                                           */
-/* ****************************************************************** */
-static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf,
-		size_t count, loff_t *ppos)
-{
-	unsigned long volume;
-	char *dest;
-	int error;
-	volume = simple_strtoul(buf, &dest, 10);
-	if (*dest != '\0' && *dest != '\n') {
-		printk("ppc_rtas_tone_volume_write: Invalid tone volume\n");
-		return count;
-	}
-	if (volume < 0) volume = 0;
-	if (volume > 100) volume = 100;
-	
-        rtas_tone_volume = volume; /* save it for later */
-	error = call_rtas("set-indicator", 3, 1, NULL,
-			TONE_VOLUME, 0, volume);
-	if (error != 0)
-		printk(KERN_WARNING "error: setting tone volume returned: %s\n", 
-				ppc_rtas_process_error(error));
-	return count;
-}
-/* ****************************************************************** */
-static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
-		size_t count, loff_t *ppos)
-{
-	int n;
-	n = sprintf(buf, "%lu\n", rtas_tone_volume);
-
-	if (*ppos >= strlen(buf))
-		return 0;
-	if (n > strlen(buf) - *ppos)
-		n = strlen(buf) - *ppos;
-	if (n > count)
-		n = count;
-	*ppos += n;
-	return n;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/prom.c linux-2.4.20/arch/ppc/kernel/prom.c
--- linux-2.4.19/arch/ppc/kernel/prom.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/prom.c	2002-10-29 11:18:32.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.prom.c 1.52 04/09/02 21:01:58 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Procedures for interfacing to the Open Firmware PROM on
@@ -26,6 +26,7 @@
 #include <asm/page.h>
 #include <asm/processor.h>
 #include <asm/irq.h>
+#include <asm/open_pic.h>
 #include <asm/system.h>
 #include <asm/btext.h>
 #include <asm/pci-bridge.h>
@@ -72,7 +73,6 @@
 static unsigned long finish_node(struct device_node *, unsigned long,
 				 interpret_func *, int, int);
 static unsigned long finish_node_interrupts(struct device_node *, unsigned long);
-static struct device_node *find_phandle(phandle);
 
 extern void enter_rtas(void *);
 void phys_call_rtas(int, int, int, ...);
@@ -152,7 +152,7 @@
 			   match on /chosen.interrupt_controller */
 			if ((name != NULL
 			     && strcmp(name, "interrupt-controller") == 0)
-			    || (ic != NULL && iclen == 0)) {
+			    || (ic != NULL && iclen == 0 && strcmp(name, "AppleKiwi"))) {
 				if (n == 0)
 					dflt_interrupt_controller = np;
 				++n;
@@ -898,7 +898,7 @@
 /*
  * Find the device_node with a given phandle.
  */
-static struct device_node * __init
+struct device_node * __init
 find_phandle(phandle ph)
 {
 	struct device_node *np;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/ptrace.c linux-2.4.20/arch/ppc/kernel/ptrace.c
--- linux-2.4.19/arch/ppc/kernel/ptrace.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/ptrace.c	2002-10-29 11:18:35.000000000 +0000
@@ -16,8 +16,7 @@
  * and Paul Mackerras (paulus@linuxcare.com.au).
  *
  * This file is subject to the terms and conditions of the GNU General
- * Public License.  See the file README.legal in the main directory of
- * this archive for more details.
+ * Public License.  Please read the COPYING file for all license details.
  */
 
 #include <linux/kernel.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/qspan_pci.c linux-2.4.20/arch/ppc/kernel/qspan_pci.c
--- linux-2.4.19/arch/ppc/kernel/qspan_pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/qspan_pci.c	2002-10-29 11:18:34.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.qspan_pci.c 1.5 05/17/01 18:14:22 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * QSpan pci routines.
@@ -29,8 +29,7 @@
 #include <asm/mpc8xx.h>
 #include <asm/system.h>
 #include <asm/machdep.h>
-
-#include "pci.h"
+#include <asm/pci-bridge.h>
 
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/residual.c linux-2.4.20/arch/ppc/kernel/residual.c
--- linux-2.4.19/arch/ppc/kernel/residual.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/residual.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,913 +0,0 @@
-/*
- * BK Id: SCCS/s.residual.c 1.15 02/05/02 18:08:35 trini
- */
-/*
- * Code to deal with the PReP residual data.
- *
- * Written by: Cort Dougan (cort@cs.nmt.edu)
- * Improved _greatly_ and rewritten by Gabriel Paubert (paubert@iram.es)
- *
- *  This file is based on the following documentation:
- *
- *	IBM Power Personal Systems Architecture
- *	Residual Data
- * 	Document Number: PPS-AR-FW0001
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive
- *  for more details.
- *
- */
-
-#include <linux/string.h>
-#include <asm/residual.h>
-#include <asm/pnp.h>
-#include <asm/byteorder.h>
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/major.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/blk.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#include <asm/sections.h>
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/ide.h>
-
-
-unsigned char __res[sizeof(RESIDUAL)] __prepdata = {0,};
-RESIDUAL *res = (RESIDUAL *)&__res;
-
-char * PnP_BASE_TYPES[] __initdata = {
-  "Reserved",
-  "MassStorageDevice",
-  "NetworkInterfaceController",
-  "DisplayController",
-  "MultimediaController",
-  "MemoryController",
-  "BridgeController",
-  "CommunicationsDevice",
-  "SystemPeripheral",
-  "InputDevice",
-  "ServiceProcessor"
-  };
-
-/* Device Sub Type Codes */
-
-unsigned char * PnP_SUB_TYPES[] __initdata = {
-  "\001\000SCSIController",
-  "\001\001IDEController",
-  "\001\002FloppyController",
-  "\001\003IPIController",
-  "\001\200OtherMassStorageController",
-  "\002\000EthernetController",
-  "\002\001TokenRingController",
-  "\002\002FDDIController",
-  "\002\0x80OtherNetworkController",
-  "\003\000VGAController",
-  "\003\001SVGAController",
-  "\003\002XGAController",
-  "\003\200OtherDisplayController",
-  "\004\000VideoController",
-  "\004\001AudioController",
-  "\004\200OtherMultimediaController",
-  "\005\000RAM",
-  "\005\001FLASH",
-  "\005\200OtherMemoryDevice",
-  "\006\000HostProcessorBridge",
-  "\006\001ISABridge",
-  "\006\002EISABridge",
-  "\006\003MicroChannelBridge",
-  "\006\004PCIBridge",
-  "\006\005PCMCIABridge",
-  "\006\006VMEBridge",
-  "\006\200OtherBridgeDevice",
-  "\007\000RS232Device",
-  "\007\001ATCompatibleParallelPort",
-  "\007\200OtherCommunicationsDevice",
-  "\010\000ProgrammableInterruptController",
-  "\010\001DMAController",
-  "\010\002SystemTimer",
-  "\010\003RealTimeClock",
-  "\010\004L2Cache",
-  "\010\005NVRAM",
-  "\010\006PowerManagement",
-  "\010\007CMOS",
-  "\010\010OperatorPanel",
-  "\010\011ServiceProcessorClass1",
-  "\010\012ServiceProcessorClass2",
-  "\010\013ServiceProcessorClass3",
-  "\010\014GraphicAssist",
-  "\010\017SystemPlanar",
-  "\010\200OtherSystemPeripheral",
-  "\011\000KeyboardController",
-  "\011\001Digitizer",
-  "\011\002MouseController",
-  "\011\003TabletController",
-  "\011\0x80OtherInputController",
-  "\012\000GeneralMemoryController",
-  NULL
-};
-
-/* Device Interface Type Codes */
-
-unsigned char * PnP_INTERFACES[] __initdata = {
-  "\000\000\000General",
-  "\001\000\000GeneralSCSI",
-  "\001\001\000GeneralIDE",
-  "\001\001\001ATACompatible",
-
-  "\001\002\000GeneralFloppy",
-  "\001\002\001Compatible765",
-  "\001\002\002NS398_Floppy",         /* NS Super I/O wired to use index
-                                         register at port 398 and data
-                                         register at port 399               */
-  "\001\002\003NS26E_Floppy",         /* Ports 26E and 26F                  */
-  "\001\002\004NS15C_Floppy",         /* Ports 15C and 15D                  */
-  "\001\002\005NS2E_Floppy",          /* Ports 2E and 2F                    */
-  "\001\002\006CHRP_Floppy",          /* CHRP Floppy in PR*P system         */
-
-  "\001\003\000GeneralIPI",
-  
-  "\002\000\000GeneralEther",
-  "\002\001\000GeneralToken",
-  "\002\002\000GeneralFDDI",
-  
-  "\003\000\000GeneralVGA",
-  "\003\001\000GeneralSVGA",
-  "\003\002\000GeneralXGA",
-  
-  "\004\000\000GeneralVideo",
-  "\004\001\000GeneralAudio",
-  "\004\001\001CS4232Audio",            /* CS 4232 Plug 'n Play Configured    */
-
-  "\005\000\000GeneralRAM",
-  /* This one is obviously wrong ! */
-  "\005\000\000PCIMemoryController",    /* PCI Config Method                  */
-  "\005\000\001RS6KMemoryController",   /* RS6K Config Method                 */
-  "\005\001\000GeneralFLASH",
-  
-  "\006\000\000GeneralHostBridge",
-  "\006\001\000GeneralISABridge",
-  "\006\002\000GeneralEISABridge",
-  "\006\003\000GeneralMCABridge",
-  /* GeneralPCIBridge = 0, */
-  "\006\004\000PCIBridgeDirect",
-  "\006\004\001PCIBridgeIndirect",
-  "\006\004\002PCIBridgeRS6K",
-  "\006\005\000GeneralPCMCIABridge",
-  "\006\006\000GeneralVMEBridge",
-  
-  "\007\000\000GeneralRS232",
-  "\007\000\001COMx",
-  "\007\000\002Compatible16450",
-  "\007\000\003Compatible16550",
-  "\007\000\004NS398SerPort",         /* NS Super I/O wired to use index
-                                         register at port 398 and data
-                                         register at port 399               */
-  "\007\000\005NS26ESerPort",         /* Ports 26E and 26F                  */
-  "\007\000\006NS15CSerPort",         /* Ports 15C and 15D                  */
-  "\007\000\007NS2ESerPort",          /* Ports 2E and 2F                    */
-
-  "\007\001\000GeneralParPort",
-  "\007\001\001LPTx",
-  "\007\001\002NS398ParPort",         /* NS Super I/O wired to use index
-                                         register at port 398 and data
-                                         register at port 399               */
-  "\007\001\003NS26EParPort",         /* Ports 26E and 26F                  */
-  "\007\001\004NS15CParPort",         /* Ports 15C and 15D                  */
-  "\007\001\005NS2EParPort",          /* Ports 2E and 2F                    */
-  
-  "\010\000\000GeneralPIC",
-  "\010\000\001ISA_PIC",
-  "\010\000\002EISA_PIC",
-  "\010\000\003MPIC",
-  "\010\000\004RS6K_PIC",
-
-  "\010\001\000GeneralDMA",
-  "\010\001\001ISA_DMA",
-  "\010\001\002EISA_DMA",
-
-  "\010\002\000GeneralTimer",
-  "\010\002\001ISA_Timer",
-  "\010\002\002EISA_Timer",
-  "\010\003\000GeneralRTC",
-  "\010\003\001ISA_RTC",
-  
-  "\010\004\001StoreThruOnly",
-  "\010\004\002StoreInEnabled",
-  "\010\004\003RS6KL2Cache",
-
-  "\010\005\000IndirectNVRAM",        /* Indirectly addressed               */
-  "\010\005\001DirectNVRAM",          /* Memory Mapped                      */
-  "\010\005\002IndirectNVRAM24",      /* Indirectly addressed - 24 bit      */
-
-  "\010\006\000GeneralPowerManagement",
-  "\010\006\001EPOWPowerManagement",
-  "\010\006\002PowerControl",         // d1378
-  
-  "\010\007\000GeneralCMOS",
-
-  "\010\010\000GeneralOPPanel",
-  "\010\010\001HarddiskLight",
-  "\010\010\002CDROMLight",
-  "\010\010\003PowerLight",
-  "\010\010\004KeyLock",
-  "\010\010\005ANDisplay",            /* AlphaNumeric Display               */
-  "\010\010\006SystemStatusLED",      /* 3 digit 7 segment LED              */
-  "\010\010\007CHRP_SystemStatusLED", /* CHRP LEDs in PR*P system           */
-
-  "\010\011\000GeneralServiceProcessor",
-  "\010\012\000GeneralServiceProcessor",
-  "\010\013\000GeneralServiceProcessor",
-  
-  "\010\014\001TransferData",
-  "\010\014\002IGMC32",
-  "\010\014\003IGMC64",
-  
-  "\010\017\000GeneralSystemPlanar",   /* 10/5/95                            */
-  NULL
-  };
-
-static const unsigned char __init *PnP_SUB_TYPE_STR(unsigned char BaseType, 
-					     unsigned char SubType) {
-	unsigned char ** s=PnP_SUB_TYPES;
-	while (*s && !((*s)[0]==BaseType 
-		       && (*s)[1]==SubType)) s++;
-	if (*s) return *s+2;
-	else return("Unknown !");
-};
-
-static const unsigned char __init *PnP_INTERFACE_STR(unsigned char BaseType, 
-					      unsigned char SubType,
-					      unsigned char Interface) {
-	unsigned char ** s=PnP_INTERFACES;
-	while (*s && !((*s)[0]==BaseType 
-		       && (*s)[1]==SubType 
-		       && (*s)[2]==Interface)) s++;
-	if (*s) return *s+3;
-	else return NULL;
-};
-
-static void __init printsmallvendor(PnP_TAG_PACKET *pkt, int size) {
-	int i, c;
-	char decomp[4];
-#define p pkt->S14_Pack.S14_Data.S14_PPCPack
-	switch(p.Type) {
-	case 1:
-	  /* Decompress first 3 chars */
-	  c = *(unsigned short *)p.PPCData;
-	  decomp[0]='A'-1+((c>>10)&0x1F);
-	  decomp[1]='A'-1+((c>>5)&0x1F);
-	  decomp[2]='A'-1+(c&0x1F);
-	  decomp[3]=0;
-	  printk("    Chip identification: %s%4.4X\n",
-		 decomp, ld_le16((unsigned short *)(p.PPCData+2)));
-	  break;
-	default:
-	  printk("    Small vendor item type 0x%2.2x, data (hex): ",
-		 p.Type);
-	  for(i=0; i<size-2; i++) printk("%2.2x ", p.PPCData[i]);
-	  printk("\n");
-	  break;
-	}
-#undef p
-}
-
-static void __init printsmallpacket(PnP_TAG_PACKET * pkt, int size) {
-	static const unsigned char * intlevel[] = {"high", "low"};
-	static const unsigned char * intsense[] = {"edge", "level"};
-
-	switch (tag_small_item_name(pkt->S1_Pack.Tag)) {
-	case PnPVersion:
-	  printk("    PnPversion 0x%x.%x\n", 
-		 pkt->S1_Pack.Version[0], /* How to interpret version ? */
-		 pkt->S1_Pack.Version[1]);
-	  break;
-//	case Logicaldevice:
-	  break;
-//	case CompatibleDevice:
-	  break;
-	case IRQFormat:
-#define p pkt->S4_Pack
-	  printk("    IRQ Mask 0x%4.4x, %s %s sensitive\n", 
-		 ld_le16((unsigned short *)p.IRQMask),
-		 intlevel[(size>3) ? !(p.IRQInfo&0x05) : 0],
-		 intsense[(size>3) ? !(p.IRQInfo&0x03) : 0]);
-#undef p
-	  break;
-	case DMAFormat:
-#define p pkt->S5_Pack
-	  printk("    DMA channel mask 0x%2.2x, info 0x%2.2x\n",
-		 p.DMAMask, p.DMAInfo);
-#undef p
-	  break;
-	case StartDepFunc:
-	  printk("Start dependent function:\n");
-	  break;
-	case EndDepFunc:
-	  printk("End dependent function\n");
-	  break;
-	case IOPort:
-#define p pkt->S8_Pack
-	  printk("    Variable (%d decoded bits) I/O port\n"
-		 "      from 0x%4.4x to 0x%4.4x, alignment %d, %d ports\n",
-		 p.IOInfo&ISAAddr16bit?16:10,
-		 ld_le16((unsigned short *)p.RangeMin),
- 		 ld_le16((unsigned short *)p.RangeMax),
-		 p.IOAlign, p.IONum); 
-#undef p
-	  break;
-	case FixedIOPort:
-#define p pkt->S9_Pack
-	  printk("    Fixed (10 decoded bits) I/O port from %3.3x to %3.3x\n",
-		 (p.Range[1]<<8)|p.Range[0],
-		 ((p.Range[1]<<8)|p.Range[0])+p.IONum-1);
-#undef p		 
-	  break;
-	case Res1:
-	case Res2:
-	case Res3:
-	  printk("    Undefined packet type %d!\n", 
-		 tag_small_item_name(pkt->S1_Pack.Tag));
-	  break;
-	case SmallVendorItem:
-	  printsmallvendor(pkt,size);
-	  break;
-	default:
-	  printk("    Type 0x2.2x%d, size=%d\n", 
-		 pkt->S1_Pack.Tag, size);    
-	  break;
-	}
-}
-
-static void __init printlargevendor(PnP_TAG_PACKET * pkt, int size) {
-	static const unsigned char * addrtype[] = {"I/O", "Memory", "System"};
-	static const unsigned char * inttype[] = {"8259", "MPIC", "RS6k BUID %d"};
-	static const unsigned char * convtype[] = {"Bus Memory", "Bus I/O", "DMA"};
-	static const unsigned char * transtype[] = {"direct", "mapped", "direct-store segment"};
-	static const unsigned char * L2type[] = {"WriteThru", "CopyBack"};
-	static const unsigned char * L2assoc[] = {"DirectMapped", "2-way set"};
-
-	int i;
-	char tmpstr[30], *t;
-#define p pkt->L4_Pack.L4_Data.L4_PPCPack
-	switch(p.Type) {
-	case 2:
-	  printk("    %d K %s %s L2 cache, %d/%d bytes line/sector size\n",
-		 ld_le32((unsigned int *)p.PPCData),
-		 L2type[p.PPCData[10]-1],
-		 L2assoc[p.PPCData[4]-1],
-		 ld_le16((unsigned short *)p.PPCData+3),
-		 ld_le16((unsigned short *)p.PPCData+4));
-	  break;
-	case 3:
-	  printk("    PCI Bridge parameters\n"
-		 "      ConfigBaseAddress %0x\n"
-		 "      ConfigBaseData %0x\n"
-		 "      Bus number %d\n",
-		 ld_le32((unsigned int *)p.PPCData),
-		 ld_le32((unsigned int *)(p.PPCData+8)),
-		 p.PPCData[16]);
-	  for(i=20; i<size-4; i+=12) {
-	  	int j, first;
-	  	if(p.PPCData[i]) printk("      PCI Slot %d", p.PPCData[i]);
-		else printk ("      Integrated PCI device");
-		for(j=0, first=1, t=tmpstr; j<4; j++) {
-			int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j);
-			if(line!=0xffff){
-			        if(first) first=0; else *t++='/';
-				*t++='A'+j;
-			}
-		}
-		*t='\0';
-		printk(" DevFunc 0x%x interrupt line(s) %s routed to",
-		       p.PPCData[i+1],tmpstr);
-		sprintf(tmpstr,
-			inttype[p.PPCData[i+2]-1],
-			p.PPCData[i+3]);
-		printk(" %s line(s) ",
-		       tmpstr);
-		for(j=0, first=1, t=tmpstr; j<4; j++) {
-			int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j);
-			if(line!=0xffff){
-				if(first) first=0; else *t++='/';
-				t+=sprintf(t,"%d(%c)",
-					   line&0x7fff,
-					   line&0x8000?'E':'L');
-			}
-		}
-		printk("%s\n",tmpstr);
-	  }
-	  break;
-	case 5:
-	  printk("    Bridge address translation, %s decoding:\n"
-		 "      Processor  Bus        Size       Conversion Translation\n"
-		 "      0x%8.8x 0x%8.8x 0x%8.8x %s %s\n",
-		 p.PPCData[0]&1 ? "positive" : "subtractive",
-		 ld_le32((unsigned int *)p.PPCData+1),
-		 ld_le32((unsigned int *)p.PPCData+3),
-		 ld_le32((unsigned int *)p.PPCData+5),
-		 convtype[p.PPCData[2]-1],
-		 transtype[p.PPCData[1]-1]);
-	  break;
-	case 6:
-	  printk("    Bus speed %d Hz, %d slot(s)\n",
-		 ld_le32((unsigned int *)p.PPCData),
-		 p.PPCData[4]);
-	  break;
-	case 7:
-	  printk("    SCSI buses: %d, id(s):", p.PPCData[0]);
-	  for(i=1; i<=p.PPCData[0]; i++) 
-	    printk(" %d%c", p.PPCData[i], i==p.PPCData[0] ? '\n' : ',');
-	  break;
-	case 9:
-	  printk("    %s address (%d bits), at 0x%x size 0x%x bytes\n",
-		 addrtype[p.PPCData[0]-1],
-		 p.PPCData[1],
-		 ld_le32((unsigned int *)(p.PPCData+4)),
-		 ld_le32((unsigned int *)(p.PPCData+12)));
-	  break;
-	case 10:
-	  sprintf(tmpstr,
-		  inttype[p.PPCData[0]-1],
-		  p.PPCData[1]);
-
-	  printk("    ISA interrupts routed to %s\n"
-		 "      lines", 
-		 tmpstr);
-	  for(i=0; i<16; i++) {
-	  	int line=ld_le16((unsigned short *)p.PPCData+i+1);
-		if (line!=0xffff) printk(" %d(IRQ%d)", line, i); 
-	  }
-	  printk("\n");
-	  break;
-	default:
-	  printk("    Large vendor item type 0x%2.2x\n      Data (hex):",
-		 p.Type);
-	  for(i=0; i<size-4; i++) printk(" %2.2x", p.PPCData[i]);
-	  printk("\n");
-#undef p
-	}
-}
-
-static void __init printlargepacket(PnP_TAG_PACKET * pkt, int size) {
-	switch (tag_large_item_name(pkt->S1_Pack.Tag)) {
-	case LargeVendorItem:
-	  printlargevendor(pkt, size);
-	  break;
-	default:
-	  printk("    Type 0x2.2x%d, size=%d\n", 
-		 pkt->S1_Pack.Tag, size);    
-	  break;
-	}
-}
-static void __init printpackets(PnP_TAG_PACKET * pkt, const char * cat) {
-	if (pkt->S1_Pack.Tag== END_TAG) {
-		printk("  No packets describing %s resources.\n", cat);
-		return;
-	}
-	printk(  "  Packets describing %s resources:\n",cat);
-	do {
-		int size;
-		if (tag_type(pkt->S1_Pack.Tag)) {
-		  	size= 3 +
-			  pkt->L1_Pack.Count0 + 
-			  pkt->L1_Pack.Count1*256;
-			printlargepacket(pkt, size);
-		} else {
-			size=tag_small_count(pkt->S1_Pack.Tag)+1;
-			printsmallpacket(pkt, size);
-		}
-		(unsigned char *) pkt+=size;
-	} while (pkt->S1_Pack.Tag != END_TAG);
-}
-
-void __init print_residual_device_info(void)
-{
-	int i;
-	PPC_DEVICE *dev;
-#define did dev->DeviceId
-	
-	/* make sure we have residual data first */
-	if ( res->ResidualLength == 0 )
-		return;
-	
-	printk("Residual: %ld devices\n", res->ActualNumDevices);
-	for ( i = 0;
-	      i < res->ActualNumDevices ;
-	      i++)
-	{
-	  	char decomp[4], sn[20];
-		const char * s;
-		dev = &res->Devices[i];
-		s = PnP_INTERFACE_STR(did.BaseType, did.SubType, 
-				      did.Interface);
-		if(!s) {
-			sprintf(sn, "interface %d", did.Interface);
-			s=sn;
-		}
-		if ( did.BusId & PCIDEVICE ) 
-		  printk("PCI Device, Bus %d, DevFunc 0x%x:",
-			 dev->BusAccess.PCIAccess.BusNumber,
-			 dev->BusAccess.PCIAccess.DevFuncNumber);
-	       	if ( did.BusId & PNPISADEVICE ) printk("PNPISA Device:");
-		if ( did.BusId & ISADEVICE ) 
-		  printk("ISA Device, Slot %d, LogicalDev %d:",
-			 dev->BusAccess.ISAAccess.SlotNumber,
-			 dev->BusAccess.ISAAccess.LogicalDevNumber);
-		if ( did.BusId & EISADEVICE ) printk("EISA Device:");
-		if ( did.BusId & PROCESSORDEVICE ) 
-		  printk("ProcBus Device, Bus %d, BUID %d: ",
-			 dev->BusAccess.ProcBusAccess.BusNumber,
-			 dev->BusAccess.ProcBusAccess.BUID);
-		if ( did.BusId & PCMCIADEVICE ) printk("PCMCIA ");
-		if ( did.BusId & VMEDEVICE ) printk("VME ");
-		if ( did.BusId & MCADEVICE ) printk("MCA ");
-		if ( did.BusId & MXDEVICE ) printk("MX ");
-		/* Decompress first 3 chars */
-		decomp[0]='A'-1+((did.DevId>>26)&0x1F);
-		decomp[1]='A'-1+((did.DevId>>21)&0x1F);
-		decomp[2]='A'-1+((did.DevId>>16)&0x1F);
-		decomp[3]=0;
-		printk(" %s%4.4lX, %s, %s, %s\n", 
-		       decomp, did.DevId&0xffff,
-		       PnP_BASE_TYPES[did.BaseType],
-		       PnP_SUB_TYPE_STR(did.BaseType,did.SubType),
-		       s);
-		if ( dev->AllocatedOffset )
-			printpackets( (union _PnP_TAG_PACKET *)
-				      &res->DevicePnPHeap[dev->AllocatedOffset],
-				      "allocated");
-		if ( dev->PossibleOffset )
-			printpackets( (union _PnP_TAG_PACKET *)
-				      &res->DevicePnPHeap[dev->PossibleOffset],
-				      "possible");
-		if ( dev->CompatibleOffset )
-			printpackets( (union _PnP_TAG_PACKET *)
-				      &res->DevicePnPHeap[dev->CompatibleOffset],
-				      "compatible");
-	}
-}
-
-
-#if 0
-static void __init printVPD(void) {
-#define vpd res->VitalProductData
-	int ps=vpd.PageSize, i, j;
-	static const char* Usage[]={
-	  "FirmwareStack",  "FirmwareHeap",  "FirmwareCode", "BootImage",
-	  "Free", "Unpopulated", "ISAAddr", "PCIConfig",
-	  "IOMemory", "SystemIO", "SystemRegs", "PCIAddr", 
-	  "UnPopSystemRom", "SystemROM", "ResumeBlock", "Other" 
-	};
-	static const unsigned char *FWMan[]={
-	  "IBM", "Motorola", "FirmWorks", "Bull"
-	};
-	static const unsigned char *FWFlags[]={
-	  "Conventional", "OpenFirmware", "Diagnostics", "LowDebug",
-	  "MultiBoot", "LowClient", "Hex41", "FAT", 
-	  "ISO9660", "SCSI_ID_Override", "Tape_Boot", "FW_Boot_Path"
-	};
-	static const unsigned char *ESM[]={
-	  "Port92", "PCIConfigA8", "FF001030", "????????"
-	};
-	static const unsigned char *SIOM[]={
-	  "Port850", "????????", "PCIConfigA8", "????????"
-	};
-
-	printk("Model: %s\n",vpd.PrintableModel);
-	printk("Serial: %s\n", vpd.Serial);
-	printk("FirmwareSupplier: %s\n", FWMan[vpd.FirmwareSupplier]);
-	printk("FirmwareFlags:");
-	for(j=0; j<12; j++) {
-	  	if (vpd.FirmwareSupports & (1<<j)) {
-			printk(" %s%c", FWFlags[j], 
-			       vpd.FirmwareSupports&(-2<<j) ? ',' : '\n');
-		}
-	}
-	printk("NVRamSize: %ld\n", vpd.NvramSize);
-	printk("SIMMslots: %ld\n", vpd.NumSIMMSlots);
-	printk("EndianSwitchMethod: %s\n", 
-	       ESM[vpd.EndianSwitchMethod>2 ? 2 : vpd.EndianSwitchMethod]);
-	printk("SpreadIOMethod: %s\n", 
-	       SIOM[vpd.SpreadIOMethod>3 ? 3 : vpd.SpreadIOMethod]);
-	printk("Processor/Bus frequencies (Hz): %ld/%ld\n",
-	       vpd.ProcessorHz, vpd.ProcessorBusHz);
-	printk("Time Base Divisor: %ld\n", vpd.TimeBaseDivisor);
-	printk("WordWidth, PageSize: %ld, %d\n", vpd.WordWidth, ps);
-	printk("Cache sector size, Lock granularity: %ld, %ld\n",
-	       vpd.CoherenceBlockSize, vpd.GranuleSize);
-	for (i=0; i<res->ActualNumMemSegs; i++) {
-		int mask=res->Segs[i].Usage, first, j;
-		printk("%8.8lx-%8.8lx ", 
-		       res->Segs[i].BasePage*ps,
-		       (res->Segs[i].PageCount+res->Segs[i].BasePage)*ps-1);
-		for(j=15, first=1; j>=0; j--) {
-			if (mask&(1<<j)) {
-				if (first) first=0;
-				else printk(", ");
-				printk("%s", Usage[j]);
-			}
-		}
-		printk("\n");
-	}
-}
-
-/*
- * Spit out some info about residual data
- */
-void print_residual_device_info(void)
-{
-	int i;
-	union _PnP_TAG_PACKET *pkt;
-	PPC_DEVICE *dev;
-#define did dev->DeviceId
-	
-	/* make sure we have residual data first */
-	if ( res->ResidualLength == 0 )
-		return;
-	printk("Residual: %ld devices\n", res->ActualNumDevices);
-	for ( i = 0;
-	      i < res->ActualNumDevices ;
-	      i++)
-	{
-		dev = &res->Devices[i];
-		/*
-		 * pci devices
-		 */
-		if ( did.BusId & PCIDEVICE )
-		{
-			printk("PCI Device:");
-			/* unknown vendor */
-			if ( !strncmp( "Unknown", pci_strvendor(did.DevId>>16), 7) )
-				printk(" id %08lx types %d/%d", did.DevId,
-				       did.BaseType, did.SubType);
-			/* known vendor */
-			else
-				printk(" %s %s",
-				       pci_strvendor(did.DevId>>16),
-				       pci_strdev(did.DevId>>16,
-						  did.DevId&0xffff)
-					);
-			
-			if ( did.BusId & PNPISADEVICE )
-			{
-				printk(" pnp:");
-				/* get pnp info on the device */
-				pkt = (union _PnP_TAG_PACKET *)
-					&res->DevicePnPHeap[dev->AllocatedOffset];
-				for (; pkt->S1_Pack.Tag != DF_END_TAG;
-				     pkt++ )
-				{
-					if ( (pkt->S1_Pack.Tag == S4_Packet) ||
-					     (pkt->S1_Pack.Tag == S4_Packet_flags) )
-						printk(" irq %02x%02x",
-						       pkt->S4_Pack.IRQMask[0],
-						       pkt->S4_Pack.IRQMask[1]);
-				}
-			}
-			printk("\n");
-			continue;
-		}
-		/*
-		 * isa devices
-		 */
-		if ( did.BusId & ISADEVICE )
-		{
-			printk("ISA Device: basetype: %d subtype: %d",
-			       did.BaseType, did.SubType);
-			printk("\n");
-			continue;
-		}		
-		/*
-		 * eisa devices
-		 */
-		if ( did.BusId & EISADEVICE )
-		{
-			printk("EISA Device: basetype: %d subtype: %d",
-			       did.BaseType, did.SubType);
-			printk("\n");
-			continue;
-		}		
-		/*
-		 * proc bus devices
-		 */
-		if ( did.BusId & PROCESSORDEVICE )
-		{
-			printk("ProcBus Device: basetype: %d subtype: %d",
-			       did.BaseType, did.SubType);
-			printk("\n");
-			continue;
-		}
-		/*
-		 * pcmcia devices
-		 */
-		if ( did.BusId & PCMCIADEVICE )
-		{
-			printk("PCMCIA Device: basetype: %d subtype: %d",
-			       did.BaseType, did.SubType);
-			printk("\n");
-			continue;
-		}		
-		printk("Unknown bus access device: busid %lx\n",
-		       did.BusId);
-	}
-}
-#endif	
-
-/* Returns the device index in the residual data, 
-   any of the search items may be set as -1 for wildcard,
-   DevID number field (second halfword) is big endian ! 
-
-   Examples:
-   - search for the Interrupt controller (8259 type), 2 methods:
-     1) i8259 = residual_find_device(~0, 
-                                     NULL, 
-				     SystemPeripheral, 
-				     ProgrammableInterruptController, 
-				     ISA_PIC, 
-				     0);
-     2) i8259 = residual_find_device(~0, "PNP0000", -1, -1, -1, 0) 
-
-   - search for the first two serial devices, whatever their type)
-     iserial1 = residual_find_device(~0,NULL,
-                                     CommunicationsDevice,
-				     RS232Device,
-				     -1, 0)
-     iserial2 = residual_find_device(~0,NULL,
-                                     CommunicationsDevice,
-				     RS232Device,
-				     -1, 1)
-   - but search for typical COM1 and COM2 is not easy due to the
-     fact that the interface may be anything and the name "PNP0500" or 
-     "PNP0501". Quite bad. 
-
-*/
-
-/* devid are easier to uncompress than to compress, so to minimize bloat
-in this rarely used area we unencode and compare */
-
-/* in residual data number is big endian in the device table and
-little endian in the heap, so we use two parameters to avoid writing
-two very similar functions */
-
-static int __init same_DevID(unsigned short vendor,
-	       unsigned short Number,
-	       char * str) 
-{
-	static unsigned const char hexdigit[]="0123456789ABCDEF";
-	if (strlen(str)!=7) return 0;
-	if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0])  &&
-	     ( ((vendor>>5)&0x1f)+'A'-1 == str[1])   &&
-	     ( (vendor&0x1f)+'A'-1 == str[2])        &&
-	     (hexdigit[(Number>>12)&0x0f] == str[3]) &&
-	     (hexdigit[(Number>>8)&0x0f] == str[4])  &&
-	     (hexdigit[(Number>>4)&0x0f] == str[5])  &&
-	     (hexdigit[Number&0x0f] == str[6]) ) return 1;
-	return 0;
-}
-
-PPC_DEVICE __init *residual_find_device(unsigned long BusMask,
-			 unsigned char * DevID,
-			 int BaseType,
-			 int SubType,
-			 int Interface,
-			 int n)
-{
-	int i;
-	if ( !res->ResidualLength ) return NULL;
-	for (i=0; i<res->ActualNumDevices; i++) {
-#define Dev res->Devices[i].DeviceId
-		if ( (Dev.BusId&BusMask)                                  &&
-		     (BaseType==-1 || Dev.BaseType==BaseType)             &&
-		     (SubType==-1 || Dev.SubType==SubType)                &&
-		     (Interface==-1 || Dev.Interface==Interface)          &&
-		     (DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff,
-						Dev.DevId&0xffff, DevID)) &&
-		     !(n--) ) return res->Devices+i;
-#undef Dev
-	}
-	return 0;
-}
-
-PPC_DEVICE __init *residual_find_device_id(unsigned long BusMask,
-			 unsigned short DevID,
-			 int BaseType,
-			 int SubType,
-			 int Interface,
-			 int n)
-{
-	int i;
-	if ( !res->ResidualLength ) return NULL;
-	for (i=0; i<res->ActualNumDevices; i++) {
-#define Dev res->Devices[i].DeviceId
-		if ( (Dev.BusId&BusMask)                                  &&
-		     (BaseType==-1 || Dev.BaseType==BaseType)             &&
-		     (SubType==-1 || Dev.SubType==SubType)                &&
-		     (Interface==-1 || Dev.Interface==Interface)          &&
-		     (DevID==0xffff || (Dev.DevId&0xffff) == DevID)	  &&
-		     !(n--) ) return res->Devices+i;
-#undef Dev
-	}
-	return 0;
-}
-
-PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,
-				unsigned packet_tag,
-				int n)
-{
-	unsigned mask, masked_tag, size;
-	if(!p) return 0;
-	if (tag_type(packet_tag)) mask=0xff; else mask=0xF8;
-	masked_tag = packet_tag&mask;
-	for(; *p != END_TAG; p+=size) {
-		if ((*p & mask) == masked_tag && !(n--)) 
-			return (PnP_TAG_PACKET *) p;
-		if (tag_type(*p))
-			size=ld_le16((unsigned short *)(p+1))+3;
-		else 
-			size=tag_small_count(*p)+1;
-	}
-	return 0; /* not found */
-}
-
-PnP_TAG_PACKET __init *PnP_find_small_vendor_packet(unsigned char *p,
-					     unsigned packet_type,
-					     int n)
-{
-	int next=0;
-	while (p) {
-		p = (unsigned char *) PnP_find_packet(p, 0x70, next);
-		if (p && p[1]==packet_type && !(n--)) 
-			return (PnP_TAG_PACKET *) p;
-		next = 1;
-	};
-	return 0; /* not found */
-}
-
-PnP_TAG_PACKET __init *PnP_find_large_vendor_packet(unsigned char *p,
-					   unsigned packet_type,
-					   int n)
-{
-	int next=0;
-	while (p) {
-		p = (unsigned char *) PnP_find_packet(p, 0x84, next);
-		if (p && p[3]==packet_type && !(n--)) 
-			return (PnP_TAG_PACKET *) p;
-		next = 1;
-	};
-	return 0; /* not found */
-}
-
-#ifdef CONFIG_PROC_PREPRESIDUAL
-static int proc_prep_residual_read(char * buf, char ** start, off_t off,
-		int count, int *eof, void *data)
-{
-	int n;
-
-	n = res->ResidualLength - off;
-	if (n < 0) {
-		*eof = 1;
-		n = 0;
-	}
-	else {
-		if (n > count)
-			n = count;
-		else
-			*eof = 1;
-
-		memcpy(buf, (char *)res + off, n);
-		*start = buf;
-	}
-
-	return n;
-}
-
-void __init
-proc_prep_residual_init(void)
-{
-	if (res->ResidualLength)
-		create_proc_read_entry("residual", S_IRUGO, NULL,
-					proc_prep_residual_read, NULL);
-}
-
-__initcall(proc_prep_residual_init);
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/setup.c linux-2.4.20/arch/ppc/kernel/setup.c
--- linux-2.4.19/arch/ppc/kernel/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/setup.c	2002-10-29 11:18:39.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.setup.c 1.75 04/16/02 20:08:22 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Common prep/pmac/chrp boot and setup code.
@@ -29,17 +29,6 @@
 #include <asm/smp.h>
 #include <asm/elf.h>
 #include <asm/cputable.h>
-#ifdef CONFIG_8xx
-#include <asm/mpc8xx.h>
-#include <asm/8xx_immap.h>
-#endif
-#ifdef CONFIG_8260
-#include <asm/mpc8260.h>
-#include <asm/immap_8260.h>
-#endif
-#ifdef CONFIG_4xx
-#include <asm/ppc4xx.h>
-#endif
 #include <asm/bootx.h>
 #include <asm/btext.h>
 #include <asm/machdep.h>
@@ -68,9 +57,7 @@
 
 /* Used with the BI_MEMSIZE bootinfo parameter to store the memory
    size value reported by the boot loader. */ 
-unsigned int boot_mem_size;
-
-int parse_bootinfo(void);
+unsigned long boot_mem_size;
 
 unsigned long ISA_DMA_THRESHOLD;
 unsigned long DMA_MODE_READ, DMA_MODE_WRITE;
@@ -350,6 +337,8 @@
 	}
 #endif	
 
+	parse_bootinfo(find_bootinfo());
+
 	/* if we didn't get any bootinfo telling us what we are... */
 	if (_machine == 0) {
 		/* prep boot loader tells us if we're prep or not */
@@ -439,7 +428,8 @@
 }
 #endif /* CONFIG_ALL_PPC */
 
-int parse_bootinfo(void)
+#ifndef CONFIG_APUS
+struct bi_record *find_bootinfo(void)
 {
 	struct bi_record *rec;
 	extern char __bss_start[];
@@ -453,15 +443,21 @@
 		 */
 		rec = (struct bi_record *)_ALIGN((ulong)__bss_start+0x10000+(1<<20)-1,(1<<20));
 		if ( rec->tag != BI_FIRST )
-			return -1;
+			return NULL;
 	}
-	for ( ; rec->tag != BI_LAST ;
-	      rec = (struct bi_record *)((ulong)rec + rec->size) )
-	{
+	return rec;
+}
+
+void parse_bootinfo(struct bi_record *rec)
+{
+	if (rec == NULL || rec->tag != BI_FIRST)
+		return;
+	while (rec->tag != BI_LAST) {
 		ulong *data = rec->data;
 		switch (rec->tag) {
 		case BI_CMD_LINE:
-			memcpy(cmd_line, (void *)data, rec->size);
+			memcpy(cmd_line, (void *)data, rec->size - 
+					sizeof(struct bi_record));
 			break;
 		case BI_SYSMAP:
 			sysmap = (char *)((data[0] >= (KERNELBASE)) ? data[0] :
@@ -483,10 +479,10 @@
 			boot_mem_size = data[0];
 			break;
 		}
+		rec = (struct bi_record *)((ulong)rec + rec->size);
 	}
-
-	return 0;
 }
+#endif /* CONFIG_APUS */
 
 /*
  * Find out what kind of machine we're on and save any data we need
@@ -502,8 +498,6 @@
 	strcpy(cmd_line, CONFIG_CMDLINE);
 #endif /* CONFIG_CMDLINE */
 
-	parse_bootinfo();
-
 	platform_init(r3, r4, r5, r6, r7);
 
 	if (ppc_md.progress)
@@ -603,24 +597,6 @@
 	ppc_md.setup_arch();
 	if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
 
-#if defined(CONFIG_PCI) && defined(CONFIG_ALL_PPC)
-	/* We create the "pci-OF-bus-map" property now so it appear in the
-	 * /proc device tree
-	 */
-	if (have_of) {
-		struct property* of_prop;
-		
-		of_prop = (struct property*)alloc_bootmem(sizeof(struct property) + 256);
-		if (of_prop && find_path_device("/")) {
-			memset(of_prop, -1, sizeof(struct property) + 256);
-			of_prop->name = "pci-OF-bus-map";
-			of_prop->length = 256;
-			of_prop->value = (unsigned char *)&of_prop[1];
-			prom_add_property(find_path_device("/"), of_prop);
-		}
-	}
-#endif /* CONFIG_PCI && CONFIG_ALL_PPC */
-
 	paging_init();
 	sort_exception_table();
 
@@ -628,6 +604,8 @@
 	ppc_md.ppc_machine = _machine;
 }
 
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) \
+	|| defined(CONFIG_USB_STORAGE) || defined(CONFIG_USB_STORAGE_MODULE)
 /* Convert the shorts/longs in hd_driveid from little to big endian;
  * chars are endian independant, of course, but strings need to be flipped.
  * (Despite what it says in drivers/block/ide.h, they come up as little
@@ -722,3 +700,4 @@
 		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
 	id->integrity_word  = __le16_to_cpu(id->integrity_word);
 }
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/signal.c linux-2.4.20/arch/ppc/kernel/signal.c
--- linux-2.4.19/arch/ppc/kernel/signal.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/signal.c	2002-10-29 11:18:40.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.signal.c 1.10 11/23/01 16:38:30 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  linux/arch/ppc/kernel/signal.c
@@ -108,7 +108,9 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs->gpr[3] = -EINTR;
+	regs->result = -EINTR;
+	regs->gpr[3] = EINTR;
+	regs->ccr |= 0x10000000;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
@@ -145,7 +147,9 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs->gpr[3] = -EINTR;
+	regs->result = -EINTR;
+	regs->gpr[3] = EINTR;
+	regs->ccr |= 0x10000000;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/sleep.S linux-2.4.20/arch/ppc/kernel/sleep.S
--- linux-2.4.19/arch/ppc/kernel/sleep.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/sleep.S	1970-01-01 00:00:00.000000000 +0000
@@ -1,451 +0,0 @@
-/*
- * BK Id: SCCS/s.sleep.S 1.20 03/19/02 15:04:39 benh
- */
-/*
- * This file contains sleep low-level functions for PowerBook G3.
- *    Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org)
- *    and Paul Mackerras (paulus@samba.org).
- *
- * 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.
- *
- */
-
-#include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/cputable.h>
-#include "ppc_asm.h"
-
-#define MAGIC	0x4c617273	/* 'Lars' */
-
-/*
- * Structure for storing CPU registers on the stack.
- */
-#define SL_SP		0
-#define SL_PC		4
-#define SL_MSR		8
-#define SL_SDR1		0xc
-#define SL_SPRG0	0x10	/* 4 sprg's */
-#define SL_DBAT0	0x20
-#define SL_IBAT0	0x28
-#define SL_DBAT1	0x30
-#define SL_IBAT1	0x38
-#define SL_DBAT2	0x40
-#define SL_IBAT2	0x48
-#define SL_DBAT3	0x50
-#define SL_IBAT3	0x58
-#define SL_TB		0x60
-#define SL_HID0		0x68
-#define SL_HID1		0x6c
-#define SL_MSSCR0	0x70
-#define SL_MSSSR0	0x74
-#define SL_ICTRL	0x78
-#define SL_LDSTCR	0x7c
-#define SL_LDSTDB	0x80
-#define SL_R2		0x84
-#define SL_CR		0x88
-#define SL_R12		0x8c	/* r12 to r31 */
-#define SL_SIZE		(SL_R12 + 80)
-
-	.text
-	.align	5
-
-/* This gets called by via-pmu.c late during the sleep process.
- * The PMU was already send the sleep command and will shut us down
- * soon. We need to save all that is needed and setup the wakeup
- * vector that will be called by the ROM on wakeup
- */
-_GLOBAL(low_sleep_handler)
-	mflr	r0
-	stw	r0,4(r1)
-	stwu	r1,-SL_SIZE(r1)
-	mfcr	r0
-	stw	r0,SL_CR(r1)
-	stw	r2,SL_R2(r1)
-	stmw	r12,SL_R12(r1)
-
-	/* Save MSR & SDR1 */
-	mfmsr	r4
-	stw	r4,SL_MSR(r1)
-	mfsdr1	r4
-	stw	r4,SL_SDR1(r1)
-
-	/* Get a stable timebase and save it */
-1:	mftbu	r4
-	stw	r4,SL_TB(r1)
-	mftb	r5
-	stw	r5,SL_TB+4(r1)
-	mftbu	r3
-	cmpw	r3,r4
-	bne	1b
-	
-	/* Save SPRGs */
-	mfsprg	r4,0
-	stw	r4,SL_SPRG0(r1)
-	mfsprg	r4,1
-	stw	r4,SL_SPRG0+4(r1)
-	mfsprg	r4,2
-	stw	r4,SL_SPRG0+8(r1)
-	mfsprg	r4,3
-	stw	r4,SL_SPRG0+12(r1)
-
-	/* Save BATs */
-	mfdbatu	r4,0
-	stw	r4,SL_DBAT0(r1)
-	mfdbatl	r4,0
-	stw	r4,SL_DBAT0+4(r1)
-	mfdbatu	r4,1
-	stw	r4,SL_DBAT1(r1)
-	mfdbatl	r4,1
-	stw	r4,SL_DBAT1+4(r1)
-	mfdbatu	r4,2
-	stw	r4,SL_DBAT2(r1)
-	mfdbatl	r4,2
-	stw	r4,SL_DBAT2+4(r1)
-	mfdbatu	r4,3
-	stw	r4,SL_DBAT3(r1)
-	mfdbatl	r4,3
-	stw	r4,SL_DBAT3+4(r1)
-	mfibatu	r4,0
-	stw	r4,SL_IBAT0(r1)
-	mfibatl	r4,0
-	stw	r4,SL_IBAT0+4(r1)
-	mfibatu	r4,1
-	stw	r4,SL_IBAT1(r1)
-	mfibatl	r4,1
-	stw	r4,SL_IBAT1+4(r1)
-	mfibatu	r4,2
-	stw	r4,SL_IBAT2(r1)
-	mfibatl	r4,2
-	stw	r4,SL_IBAT2+4(r1)
-	mfibatu	r4,3
-	stw	r4,SL_IBAT3(r1)
-	mfibatl	r4,3
-	stw	r4,SL_IBAT3+4(r1)
-
-	/* Save HID0 */
-	mfspr	r4,HID0
-	stw	r4,SL_HID0(r1)
-
-	/* Save 7400/7410/7450 specific registers */
-	mfspr	r3,PVR
-	srwi	r3,r3,16
-	cmpli	cr0,r3,0x8000
-	cmpli	cr1,r3,0x000c
-	cmpli	cr2,r3,0x800c
-	cror	4*cr1+eq,4*cr1+eq,4*cr2+eq
-	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
-	bne	1f
-	mfspr	r4,SPRN_MSSCR0
-	stw	r4,SL_MSSCR0(r1)
-	mfspr	r4,SPRN_MSSSR0
-	stw	r4,SL_MSSSR0(r1)
-	/* Save 7450 specific registers */
-	beq	cr1,1f
-	mfspr	r4,HID1
-	stw	r4,SL_HID1(r1)
-	mfspr	r4,SPRN_ICTRL
-	stw	r4,SL_ICTRL(r1)
-	mfspr	r4,SPRN_LDSTCR
-	stw	r4,SL_LDSTCR(r1)
-	mfspr	r4,SPRN_LDSTDB
-	stw	r4,SL_LDSTDB(r1)
-1:
-	/* The ROM can wake us up via 2 different vectors:
-	 *  - On wallstreet & lombard, we must write a magic
-	 *    value 'Lars' at address 4 and a pointer to a
-	 *    memory location containing the PC to resume from
-	 *    at address 0.
-	 *  - On Core99, we must store the wakeup vector at
-	 *    address 0x80 and eventually it's parameters
-	 *    at address 0x84. I've have some trouble with those
-	 *    parameters however and I no longer use them.
-	 */
-	lis	r5,grackle_wake_up@ha
-	addi	r5,r5,grackle_wake_up@l
-	tophys(r5,r5)
-	stw	r5,SL_PC(r1)
-	lis	r4,KERNELBASE@h
-	tophys(r5,r1)
-	addi	r5,r5,SL_PC
-	lis	r6,MAGIC@ha
-	addi	r6,r6,MAGIC@l
-	stw	r5,0(r4)
-	stw	r6,4(r4)
-	/* Setup stuffs at 0x80-0x84 for Core99 */
-	lis	r3,core99_wake_up@ha
-	addi	r3,r3,core99_wake_up@l
-	tophys(r3,r3)
-	stw	r3,0x80(r4)
-	stw	r5,0x84(r4)
-	/* Store a pointer to our backup storage into
-	 * a kernel global
-	 */
-	lis r3,sleep_storage@ha
-	addi r3,r3,sleep_storage@l
-	stw r5,0(r3)
-
-	BEGIN_FTR_SECTION
-	DSSALL
-	sync
-	END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-
-/*
- * Flush the L1 data cache by reading the first 128kB of RAM
- * and then flushing the same area with the dcbf instruction.
- * The L2 cache has already been disabled.
- */
-	li	r4,0x1000	/* 128kB / 32B */
-	mtctr	r4
-	lis	r4,KERNELBASE@h
-1:
-	lwz	r0,0(r4)
-	addi	r4,r4,0x0020	/* Go to start of next cache line */
-	bdnz	1b
-	sync
-	
-	li	r4,0x1000	/* 128kB / 32B */
-	mtctr	r4
-	lis	r4,KERNELBASE@h
-1:
-	dcbf	r0,r4
-	addi	r4,r4,0x0020	/* Go to start of next cache line */
-	bdnz	1b
-	sync
-
-/*
- * Set the HID0 and MSR for sleep.
- */
-	mfspr	r2,HID0
-	rlwinm	r2,r2,0,10,7	/* clear doze, nap */
-	oris	r2,r2,HID0_SLEEP@h
-	sync
-	mtspr	HID0,r2
-	sync
-
-/* This loop puts us back to sleep in case we have a spurrious
- * wakeup so that the host bridge properly stays asleep. The
- * CPU will be turned off, either after a known time (about 1
- * second) on wallstreet & lombard, or as soon as the CPU enters
- * SLEEP mode on core99
- */
-	mfmsr	r2
-	oris	r2,r2,MSR_POW@h
-1:	sync
-	mtmsr	r2
-	isync
-	b	1b
-
-/* 
- * Here is the resume code.
- */
-
-
-/*
- * Core99 machines resume here
- * r4 has the physical address of SL_PC(sp) (unused)
- */
-_GLOBAL(core99_wake_up)
-	/* Make sure HID0 no longer contains any sleep bit */
-	mfspr	r3,HID0
-	rlwinm	r3,r3,0,11,7		/* clear SLEEP, NAP, DOZE bits */
-	mtspr	HID0,r3
-	sync
-	isync
-
-	/* Won't that cause problems on CPU that doesn't support it ? */
-	lis	r3, 0
-	mtspr	SPRN_MMCR0, r3
-	
-	/* sanitize MSR */
-	mfmsr	r3
-	ori	r3,r3,MSR_EE|MSR_IP
-	xori	r3,r3,MSR_EE|MSR_IP
-	sync
-	isync
-	mtmsr	r3
-	sync
-	isync
-
-	/* Recover sleep storage */
-	lis	r3,sleep_storage@ha
-	addi	r3,r3,sleep_storage@l
-	tophys(r3,r3)
-	lwz	r1,0(r3)
-
-	/* Pass thru to older resume code ... */
-/* 
- * Here is the resume code for older machines.
- * r1 has the physical address of SL_PC(sp).
- */
-	
-grackle_wake_up:
-	/* Enable and then Flash inval the instruction & data cache */
-	mfspr	r3,HID0
-	ori	r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI
-	sync
-	isync
-	mtspr	HID0,r3
-	xori	r3,r3, HID0_ICFI|HID0_DCI
-	mtspr	HID0,r3
-	sync
-	
-	/* Restore the kernel's segment registers before
-	 * we do any r1 memory access as we are not sure they
-	 * are in a sane state above the first 256Mb region
-	 */
-	li	r0,16		/* load up segment register values */
-	mtctr	r0		/* for context 0 */
-	lis	r3,0x2000	/* Ku = 1, VSID = 0 */
-	li	r4,0
-3:	mtsrin	r3,r4
-	addi	r3,r3,0x111	/* increment VSID */
-	addis	r4,r4,0x1000	/* address of next segment */
-	bdnz	3b
-	
-	/* Restore the remaining bits of the HID0 register. */
-	subi	r1,r1,SL_PC
-	lwz	r3,SL_HID0(r1)
-	sync
-	isync
-	mtspr	HID0,r3
-	sync
-	isync
-
-	/* Restore 7400/7410/7450 specific registers */
-	mfspr	r3,PVR
-	srwi	r3,r3,16
-	cmpli	cr0,r3,0x8000
-	cmpli	cr1,r3,0x000c
-	cmpli	cr2,r3,0x800c
-	cror	4*cr1+eq,4*cr1+eq,4*cr2+eq
-	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
-	bne	1f
-	lwz	r4,SL_MSSCR0(r1)
-	sync
-	mtspr	SPRN_MSSCR0,r4
-	sync
-	isync
-	lwz	r4,SL_MSSSR0(r1)
-	sync
-	mtspr	SPRN_MSSSR0,r4
-	sync
-	isync
-	bne	cr2,1f
-	li	r4,0
-	mtspr	SPRN_L2CR2,r4
-	/* Restore 7450 specific registers */
-	beq	cr1,1f
-	lwz	r4,SL_HID1(r1)
-	sync
-	mtspr	HID1,r4
-	isync
-	sync
-	lwz	r4,SPRN_ICTRL(r1)
-	sync
-	mtspr	SPRN_ICTRL,r4
-	isync
-	sync
-	lwz	r4,SPRN_LDSTCR(r1)
-	sync
-	mtspr	SPRN_LDSTCR,r4
-	isync
-	sync
-	lwz	r4,SL_LDSTDB(r1)
-	sync
-	mtspr	SPRN_LDSTDB,r4
-	isync
-	sync
-1:
-	/* Restore the BATs, and SDR1.  Then we can turn on the MMU. */
-	lwz	r4,SL_SDR1(r1)
-	mtsdr1	r4
-	lwz	r4,SL_SPRG0(r1)
-	mtsprg	0,r4
-	lwz	r4,SL_SPRG0+4(r1)
-	mtsprg	1,r4
-	lwz	r4,SL_SPRG0+8(r1)
-	mtsprg	2,r4
-	lwz	r4,SL_SPRG0+12(r1)
-	mtsprg	3,r4
-
-	lwz	r4,SL_DBAT0(r1)
-	mtdbatu	0,r4
-	lwz	r4,SL_DBAT0+4(r1)
-	mtdbatl	0,r4
-	lwz	r4,SL_DBAT1(r1)
-	mtdbatu	1,r4
-	lwz	r4,SL_DBAT1+4(r1)
-	mtdbatl	1,r4
-	lwz	r4,SL_DBAT2(r1)
-	mtdbatu	2,r4
-	lwz	r4,SL_DBAT2+4(r1)
-	mtdbatl	2,r4
-	lwz	r4,SL_DBAT3(r1)
-	mtdbatu	3,r4
-	lwz	r4,SL_DBAT3+4(r1)
-	mtdbatl	3,r4
-	lwz	r4,SL_IBAT0(r1)
-	mtibatu	0,r4
-	lwz	r4,SL_IBAT0+4(r1)
-	mtibatl	0,r4
-	lwz	r4,SL_IBAT1(r1)
-	mtibatu	1,r4
-	lwz	r4,SL_IBAT1+4(r1)
-	mtibatl	1,r4
-	lwz	r4,SL_IBAT2(r1)
-	mtibatu	2,r4
-	lwz	r4,SL_IBAT2+4(r1)
-	mtibatl	2,r4
-	lwz	r4,SL_IBAT3(r1)
-	mtibatu	3,r4
-	lwz	r4,SL_IBAT3+4(r1)
-	mtibatl	3,r4
-
-	/* Flush all TLBs */
-	lis	r4,0x1000
-1:	addic.	r4,r4,-0x1000
-	tlbie	r4
-	blt	1b
-	sync
-
-	/* restore the MSR and turn on the MMU */
-	lwz	r3,SL_MSR(r1)
-	bl	turn_on_mmu	
-
-	/* get back the stack pointer */
-	tovirt(r1,r1)
-
-	/* Restore TB */
-	li	r3,0
-	mttbl	r3
-	lwz	r3,SL_TB(r1)
-	lwz	r4,SL_TB+4(r1)
-	mttbu	r3
-	mttbl	r4
-
-	/* Restore the callee-saved registers and return */
-	lwz	r0,SL_CR(r1)
-	mtcr	r0
-	lwz	r2,SL_R2(r1)
-	lmw	r12,SL_R12(r1)
-	addi	r1,r1,SL_SIZE
-	lwz	r0,4(r1)
-	mtlr	r0
-	blr
-
-turn_on_mmu:
-	mflr	r4
-	tovirt(r4,r4)
-	mtsrr0	r4
-	mtsrr1	r3
-	sync
-	isync
-	rfi
-
-	.data
-	.globl sleep_storage
-sleep_storage:
-	.long 0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/time.c linux-2.4.20/arch/ppc/kernel/time.c
--- linux-2.4.19/arch/ppc/kernel/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/time.c	2002-10-29 11:18:34.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.time.c 1.29 12/11/01 11:40:45 trini
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Common time routines among all ppc machines.
@@ -157,7 +157,12 @@
 		jiffy_stamp += tb_ticks_per_jiffy;
 		if (!user_mode(regs))
 			ppc_do_profile(instruction_pointer(regs));
-	  	if (smp_processor_id())
+		if (unlikely(!heartbeat_count(cpu)--) 
+				&& heartbeat_reset(cpu)) {
+			ppc_md.heartbeat();
+			heartbeat_count(cpu) = heartbeat_reset(cpu);
+		}
+	  	if (cpu)
 			continue;
 
 		/* We are in an interrupt, no need to save/restore flags */
@@ -192,8 +197,10 @@
 				last_rtc_update += 60;
 		}
 		write_unlock(&xtime_lock);
+		
+
 	}
-	if ( !disarm_decr[smp_processor_id()] )
+	if (!disarm_decr[cpu])
 		set_dec(next_dec);
 	last_jiffy_stamp(cpu) = jiffy_stamp;
 
@@ -201,9 +208,6 @@
 	smp_local_timer_interrupt(regs);
 #endif /* CONFIG_SMP */
 
-	if (ppc_md.heartbeat && !ppc_md.heartbeat_count--)
-		ppc_md.heartbeat();
-
 	hardirq_exit(cpu);
 
 	if (softirq_pending(cpu))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/todc_time.c linux-2.4.20/arch/ppc/kernel/todc_time.c
--- linux-2.4.19/arch/ppc/kernel/todc_time.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/todc_time.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,505 @@
+/*
+ * arch/ppc/kernel/todc_time.c
+ * 
+ * Time of Day Clock support for the M48T35, M48T37, M48T59, and MC146818
+ * Real Time Clocks/Timekeepers.
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001 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.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/time.h>
+#include <asm/todc.h>
+
+/*
+ * Depending on the hardware on your board and your board design, the
+ * RTC/NVRAM may be accessed either directly (like normal memory) or via
+ * address/data registers.  If your board uses the direct method, set
+ * 'nvram_data' to the base address of your nvram and leave 'nvram_as0' and
+ * 'nvram_as1' NULL.  If your board uses address/data regs to access nvram,
+ * set 'nvram_as0' to the address of the lower byte, set 'nvram_as1' to the
+ * address of the upper byte (leave NULL if using mv146818), and set
+ * 'nvram_data' to the address of the 8-bit data register.
+ *
+ * You also need to set 'ppc_md.nvram_read_val' and 'ppc_md.nvram_write_val' to
+ * the proper routines.  There are standard ones defined further down in
+ * this file that you can use.
+ *
+ * There is a built in assumption that the RTC and NVRAM are accessed by the
+ * same mechanism (i.e., ppc_md.nvram_read_val, etc works for both).
+ *
+ * Note: Even though the documentation for the various RTC chips say that it
+ * 	 take up to a second before it starts updating once the 'R' bit is
+ * 	 cleared, they always seem to update even though we bang on it many
+ * 	 times a second.  This is true, except for the Dallas Semi 1746/1747
+ * 	 (possibly others).  Those chips seem to have a real problem whenever
+ * 	 we set the 'R' bit before reading them, they basically stop counting.
+ * 	 					--MAG
+ */
+
+extern spinlock_t	rtc_lock;
+
+/*
+ * 'todc_info' should be initialized in your *_setup.c file to
+ * point to a fully initialized 'todc_info_t' structure.
+ * This structure holds all the register offsets for your particular
+ * TODC/RTC chip.
+ * TODC_ALLOC()/TODC_INIT() will allocate and initialize this table for you.
+ */
+
+#ifdef	RTC_FREQ_SELECT
+#undef	RTC_FREQ_SELECT
+#define	RTC_FREQ_SELECT		control_b	/* Register A */
+#endif
+
+#ifdef	RTC_CONTROL
+#undef	RTC_CONTROL
+#define	RTC_CONTROL		control_a	/* Register B */
+#endif
+
+#ifdef	RTC_INTR_FLAGS
+#undef	RTC_INTR_FLAGS
+#define	RTC_INTR_FLAGS		watchdog	/* Register C */
+#endif
+
+#ifdef	RTC_VALID
+#undef	RTC_VALID
+#define	RTC_VALID		interrupts	/* Register D */
+#endif
+
+/* Access routines when RTC accessed directly (like normal memory) */
+u_char
+todc_direct_read_val(int addr)
+{
+	return readb(todc_info->nvram_data + addr);
+}
+  
+void
+todc_direct_write_val(int addr, unsigned char val)
+{
+	writeb(val, todc_info->nvram_data + addr);
+	return;
+}
+
+/* Access routines for accessing m48txx type chips via addr/data regs */
+u_char
+todc_m48txx_read_val(int addr)
+{
+	outb(addr, todc_info->nvram_as0);
+	outb(addr>>todc_info->as0_bits, todc_info->nvram_as1);
+	return inb(todc_info->nvram_data);
+}
+  
+void
+todc_m48txx_write_val(int addr, unsigned char val)
+{
+	outb(addr, todc_info->nvram_as0);
+	outb(addr>>todc_info->as0_bits, todc_info->nvram_as1);
+   	outb(val, todc_info->nvram_data);
+	return;
+}
+
+/* Access routines for accessing mc146818 type chips via addr/data regs */
+u_char
+todc_mc146818_read_val(int addr)
+{
+	outb(addr, todc_info->nvram_as0);
+	return inb(todc_info->nvram_data);
+}
+  
+void
+todc_mc146818_write_val(int addr, unsigned char val)
+{
+	outb(addr, todc_info->nvram_as0);
+   	outb(val, todc_info->nvram_data);
+	return;
+}
+
+
+/*
+ * Routines to make RTC chips with NVRAM buried behind an addr/data pair
+ * have the NVRAM and clock regs appear at the same level.
+ * The NVRAM will appear to start at addr 0 and the clock regs will appear
+ * to start immediately after the NVRAM (actually, start at offset
+ * todc_info->nvram_size).
+ */
+static inline u_char
+todc_read_val(int addr)
+{
+	u_char	val;
+
+	if (todc_info->sw_flags & TODC_FLAG_2_LEVEL_NVRAM) {
+		if (addr < todc_info->nvram_size) { /* NVRAM */
+			ppc_md.nvram_write_val(todc_info->nvram_addr_reg, addr);
+			val = ppc_md.nvram_read_val(todc_info->nvram_data_reg);
+		}
+		else { /* Clock Reg */
+			addr -= todc_info->nvram_size;
+			val = ppc_md.nvram_read_val(addr);
+		}
+	}
+	else {
+		val = ppc_md.nvram_read_val(addr);
+	}
+
+	return val;
+}
+
+static inline void
+todc_write_val(int addr, u_char val)
+{
+	if (todc_info->sw_flags & TODC_FLAG_2_LEVEL_NVRAM) {
+		if (addr < todc_info->nvram_size) { /* NVRAM */
+			ppc_md.nvram_write_val(todc_info->nvram_addr_reg, addr);
+			ppc_md.nvram_write_val(todc_info->nvram_data_reg, val);
+		}
+		else { /* Clock Reg */
+			addr -= todc_info->nvram_size;
+			ppc_md.nvram_write_val(addr, val);
+		}
+	}
+	else {
+		ppc_md.nvram_write_val(addr, val);
+	}
+}
+
+/*
+ * TODC routines
+ *
+ * There is some ugly stuff in that there are assumptions for the mc146818.
+ *
+ * Assumptions:
+ *	- todc_info->control_a has the offset as mc146818 Register B reg
+ *	- todc_info->control_b has the offset as mc146818 Register A reg
+ *	- m48txx control reg's write enable or 'W' bit is same as
+ *	  mc146818 Register B 'SET' bit (i.e., 0x80)
+ *
+ * These assumptions were made to make the code simpler.
+ */
+long __init
+todc_time_init(void)
+{
+	static u_char	not_initialized = 1;
+
+	/* Make sure clocks are running */
+	if (not_initialized) {
+		u_char	cntl_b;
+
+		cntl_b = todc_read_val(todc_info->control_b);
+
+		if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+			if ((cntl_b & 0x70) != 0x20) {
+				printk(KERN_INFO "TODC %s %s\n",
+					"real-time-clock was stopped.",
+					"Now starting...");
+				cntl_b &= ~0x70;
+				cntl_b |= 0x20;
+			}
+
+			todc_write_val(todc_info->control_b, cntl_b);
+		}
+		else if (todc_info->rtc_type == TODC_TYPE_DS1501) {
+			u_char	month;
+
+			todc_info->enable_read = TODC_DS1501_CNTL_B_TE;
+			todc_info->enable_write = TODC_DS1501_CNTL_B_TE;
+
+			month = todc_read_val(todc_info->month);
+
+			if ((month & 0x80) == 0x80) {
+				printk(KERN_INFO "TODC %s %s\n",
+					"real-time-clock was stopped.",
+					"Now starting...");
+				month &= ~0x80;
+				todc_write_val(todc_info->month, month);
+			}
+
+			cntl_b &= ~TODC_DS1501_CNTL_B_TE;
+			todc_write_val(todc_info->control_b, cntl_b);
+		}
+		else { /* must be a m48txx type */
+			u_char	cntl_a;
+
+			todc_info->enable_read = TODC_MK48TXX_CNTL_A_R;
+			todc_info->enable_write = TODC_MK48TXX_CNTL_A_W;
+
+			cntl_a = todc_read_val(todc_info->control_a);
+
+			/* Check & clear STOP bit in control B register */
+			if (cntl_b & TODC_MK48TXX_DAY_CB) {
+				printk(KERN_INFO "TODC %s %s\n",
+					"real-time-clock was stopped.",
+					"Now starting...");
+
+				cntl_a |= todc_info->enable_write;
+				cntl_b &= ~TODC_MK48TXX_DAY_CB;/* Start Oscil */
+
+				todc_write_val(todc_info->control_a, cntl_a);
+				todc_write_val(todc_info->control_b, cntl_b);
+			}
+
+			/* Make sure READ & WRITE bits are cleared. */
+			cntl_a &= ~(todc_info->enable_write |
+				    todc_info->enable_read);
+			todc_write_val(todc_info->control_a, cntl_a);
+		}
+
+		not_initialized = 0;
+	}
+
+
+	return 0;
+}
+
+/*
+ * There is some ugly stuff in that there are assumptions that for a mc146818,
+ * the todc_info->control_a has the offset of the mc146818 Register B reg and
+ * that the register'ss 'SET' bit is the same as the m48txx's write enable
+ * bit in the control register of the m48txx (i.e., 0x80).
+ *
+ * It was done to make the code look simpler.
+ */
+ulong
+todc_get_rtc_time(void)
+{
+	uint	year, mon, day, hour, min, sec;
+	uint	limit, i;
+	u_char	save_control, uip;
+
+	spin_lock(&rtc_lock);
+	save_control = todc_read_val(todc_info->control_a);
+
+	if (todc_info->rtc_type != TODC_TYPE_MC146818) {
+		limit = 1;
+
+		switch (todc_info->rtc_type) {
+			case TODC_TYPE_DS1557:
+			case TODC_TYPE_DS1743:
+			case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
+			case TODC_TYPE_DS1747:
+				break;
+			default:
+				todc_write_val(todc_info->control_a,
+				       (save_control | todc_info->enable_read));
+		}
+	}
+	else {
+		limit = 100000000;
+	}
+
+	for (i=0; i<limit; i++) {
+		if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+			uip = todc_read_val(todc_info->RTC_FREQ_SELECT);
+		}
+
+		sec = todc_read_val(todc_info->seconds) & 0x7f;
+		min = todc_read_val(todc_info->minutes) & 0x7f;
+		hour = todc_read_val(todc_info->hours) & 0x3f;
+		day = todc_read_val(todc_info->day_of_month) & 0x3f;
+		mon = todc_read_val(todc_info->month) & 0x1f;
+		year = todc_read_val(todc_info->year) & 0xff;
+
+		if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+			uip |= todc_read_val(todc_info->RTC_FREQ_SELECT);
+			if ((uip & RTC_UIP) == 0) break;
+		}
+	}
+
+	if (todc_info->rtc_type != TODC_TYPE_MC146818) {
+		switch (todc_info->rtc_type) {
+			case TODC_TYPE_DS1557:
+			case TODC_TYPE_DS1743:
+			case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
+			case TODC_TYPE_DS1747:
+				break;
+			default:
+				save_control &= ~(todc_info->enable_read);
+				todc_write_val(todc_info->control_a,
+						       save_control);
+		}
+	}
+	spin_unlock(&rtc_lock);
+
+	if ((todc_info->rtc_type != TODC_TYPE_MC146818) ||
+	    ((save_control & RTC_DM_BINARY) == 0) ||
+	    RTC_ALWAYS_BCD) {
+
+		BCD_TO_BIN(sec);
+		BCD_TO_BIN(min);
+		BCD_TO_BIN(hour);
+		BCD_TO_BIN(day);
+		BCD_TO_BIN(mon);
+		BCD_TO_BIN(year);
+	}
+
+	year = year + 1900;
+	if (year < 1970) {
+		year += 100;
+	}
+
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+int
+todc_set_rtc_time(unsigned long nowtime)
+{
+	struct rtc_time	tm;
+	u_char		save_control, save_freq_select;
+
+	spin_lock(&rtc_lock);
+	to_tm(nowtime, &tm);
+
+	save_control = todc_read_val(todc_info->control_a);
+
+	/* Assuming MK48T59_RTC_CA_WRITE & RTC_SET are equal */
+	todc_write_val(todc_info->control_a,
+			       (save_control | todc_info->enable_write));
+	save_control &= ~(todc_info->enable_write); /* in case it was set */
+
+	if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+		save_freq_select = todc_read_val(todc_info->RTC_FREQ_SELECT);
+		todc_write_val(todc_info->RTC_FREQ_SELECT,
+				       save_freq_select | RTC_DIV_RESET2);
+	}
+
+
+        tm.tm_year = (tm.tm_year - 1900) % 100;
+
+	if ((todc_info->rtc_type != TODC_TYPE_MC146818) ||
+	    ((save_control & RTC_DM_BINARY) == 0) ||
+	    RTC_ALWAYS_BCD) {
+
+		BIN_TO_BCD(tm.tm_sec);
+		BIN_TO_BCD(tm.tm_min);
+		BIN_TO_BCD(tm.tm_hour);
+		BIN_TO_BCD(tm.tm_mon);
+		BIN_TO_BCD(tm.tm_mday);
+		BIN_TO_BCD(tm.tm_year);
+	}
+
+	todc_write_val(todc_info->seconds,      tm.tm_sec);
+	todc_write_val(todc_info->minutes,      tm.tm_min);
+	todc_write_val(todc_info->hours,        tm.tm_hour);
+	todc_write_val(todc_info->month,        tm.tm_mon);
+	todc_write_val(todc_info->day_of_month, tm.tm_mday);
+	todc_write_val(todc_info->year,         tm.tm_year);
+	
+	todc_write_val(todc_info->control_a, save_control);
+
+	if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+		todc_write_val(todc_info->RTC_FREQ_SELECT, save_freq_select);
+	}
+	spin_unlock(&rtc_lock);
+
+	return 0;
+}
+
+/*
+ * Manipulates read bit to reliably read seconds at a high rate.
+ */
+static unsigned char __init todc_read_timereg(int addr)
+{
+	unsigned char save_control, val;
+
+	switch (todc_info->rtc_type) {
+		case TODC_TYPE_DS1557:
+		case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
+		case TODC_TYPE_DS1747:
+		case TODC_TYPE_MC146818:
+			break;
+		default:
+			save_control = todc_read_val(todc_info->control_a);
+			todc_write_val(todc_info->control_a,
+				       (save_control | todc_info->enable_read));
+	}
+	val = todc_read_val(addr);
+
+	switch (todc_info->rtc_type) {
+		case TODC_TYPE_DS1557:
+		case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
+		case TODC_TYPE_DS1747:
+		case TODC_TYPE_MC146818:
+			break;
+		default:
+			save_control &= ~(todc_info->enable_read);
+			todc_write_val(todc_info->control_a, save_control);
+	}
+
+	return val;
+} 
+
+/*
+ * This was taken from prep_setup.c
+ * Use the NVRAM RTC to time a second to calibrate the decrementer.
+ */
+void __init
+todc_calibrate_decr(void)
+{
+	ulong	freq;
+	ulong	tbl, tbu;
+        long	i, loop_count;
+        u_char	sec;
+ 
+	todc_time_init();
+
+	/*
+	 * Actually this is bad for precision, we should have a loop in
+	 * which we only read the seconds counter. todc_read_val writes
+	 * the address bytes on every call and this takes a lot of time.
+	 * Perhaps an nvram_wait_change method returning a time
+	 * stamp with a loop count as parameter would be the solution.
+	 */
+	/*
+	 * Need to make sure the tbl doesn't roll over so if tbu increments
+	 * during this test, we need to do it again.
+	 */
+	loop_count = 0;
+
+	sec = todc_read_timereg(todc_info->seconds) & 0x7f;
+
+	do {
+		tbu = get_tbu();
+
+		for (i = 0 ; i < 10000000 ; i++) {/* may take up to 1 second */
+		   tbl = get_tbl();
+
+		   if ((todc_read_timereg(todc_info->seconds) & 0x7f) != sec) {
+		      break;
+		   }
+		}
+
+		sec = todc_read_timereg(todc_info->seconds) & 0x7f;
+
+		for (i = 0 ; i < 10000000 ; i++) { /* Should take 1 second */
+		   freq = get_tbl();
+
+		   if ((todc_read_timereg(todc_info->seconds) & 0x7f) != sec) {
+		      break;
+		   }
+		}
+
+		freq -= tbl;
+	} while ((get_tbu() != tbu) && (++loop_count < 2));
+
+	printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+	       freq/1000000, freq%1000000);
+
+	tb_ticks_per_jiffy = freq / HZ;
+	tb_to_us = mulhwu_scale_factor(freq, 1000000);
+
+	return;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/walnut_setup.c linux-2.4.20/arch/ppc/kernel/walnut_setup.c
--- linux-2.4.19/arch/ppc/kernel/walnut_setup.c	2001-11-16 18:10:08.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/walnut_setup.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,292 +0,0 @@
-/*
- * BK Id: SCCS/s.walnut_setup.c 1.10 11/13/01 21:26:07 paulus
- */
-/*
- *
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: walnut_setup.c
- *
- *    Description:
- *      Architecture- / platform-specific boot-time initialization code for
- *      the IBM PowerPC 403GP "Walnut" evaluation board. Adapted from original
- *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
- *      <dan@net4x.com>.
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/threads.h>
-#include <linux/interrupt.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/blk.h>
-#include <linux/seq_file.h>
-
-#include <asm/processor.h>
-#include <asm/board.h>
-#include <asm/machdep.h>
-#include <asm/page.h>
-
-#include "local_irq.h"
-#include "ppc4xx_pic.h"
-#include <asm/time.h>
-#include "walnut_setup.h"
-
-
-/* Function Prototypes */
-
-extern void abort(void);
-
-/* Global Variables */
-
-unsigned char __res[sizeof(bd_t)];
-
-
-/*
- * void __init walnut_init()
- *
- * Description:
- *   This routine...
- *
- * Input(s):
- *   r3 - Optional pointer to a board information structure.
- *   r4 - Optional pointer to the physical starting address of the init RAM
- *        disk.
- *   r5 - Optional pointer to the physical ending address of the init RAM
- *        disk.
- *   r6 - Optional pointer to the physical starting address of any kernel
- *        command-line parameters.
- *   r7 - Optional pointer to the physical ending address of any kernel
- *        command-line parameters.
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   N/A
- *
- */
-void __init
-walnut_init(unsigned long r3, unsigned long r4, unsigned long r5, 
-	    unsigned long r6, unsigned long r7)
-{
-	/*
-	 * If we were passed in a board information, copy it into the
-	 * residual data area.
-	 */
-	if (r3) {
-		memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t));
-	}
-
-#if defined(CONFIG_BLK_DEV_INITRD)
-	/*
-	 * If the init RAM disk has been configured in, and there's a valid
-	 * starting address for it, set it up.
-	 */
-	if (r4) {
-		initrd_start = r4 + KERNELBASE;
-		initrd_end = r5 + KERNELBASE;
-	}
-#endif /* CONFIG_BLK_DEV_INITRD */
-
-	/* Copy the kernel command line arguments to a safe place. */
-
-	if (r6) {
- 		*(char *)(r7 + KERNELBASE) = 0;
-		strcpy(cmd_line, (char *)(r6 + KERNELBASE));
-	}
-
-	/* Initialize machine-dependency vectors */
-
-	ppc_md.setup_arch	 	= walnut_setup_arch;
-	ppc_md.show_percpuinfo	 	= walnut_show_percpuinfo;
-	ppc_md.irq_cannonicalize 	= NULL;
-	ppc_md.init_IRQ		 	= walnut_init_IRQ;
-	ppc_md.get_irq		 	= walnut_get_irq;
-	ppc_md.init		 	= NULL;
-
-	ppc_md.restart		 	= walnut_restart;
-	ppc_md.power_off	 	= walnut_power_off;
-	ppc_md.halt		 	= walnut_halt;
-
-	ppc_md.time_init	 	= walnut_time_init;
-	ppc_md.set_rtc_time	 	= walnut_set_rtc_time;
-	ppc_md.get_rtc_time	 	= walnut_get_rtc_time;
-	ppc_md.calibrate_decr	 	= walnut_calibrate_decr;
-
-	ppc_md.kbd_setkeycode    	= NULL;
-	ppc_md.kbd_getkeycode    	= NULL;
-	ppc_md.kbd_translate     	= NULL;
-	ppc_md.kbd_unexpected_up 	= NULL;
-	ppc_md.kbd_leds          	= NULL;
-	ppc_md.kbd_init_hw       	= NULL;
-	ppc_md.ppc_kbd_sysrq_xlate	= NULL;
-}
-
-/*
- * Document me.
- */
-void __init
-walnut_setup_arch(void)
-{
-	/* XXX - Implement me */
-}
-
-/*
- * int walnut_show_percpuinfo()
- *
- * Description:
- *   This routine pretty-prints the platform's internal CPU and bus clock
- *   frequencies into the buffer for usage in /proc/cpuinfo.
- *
- * Input(s):
- *  *buffer - Buffer into which CPU and bus clock frequencies are to be
- *            printed.
- *
- * Output(s):
- *  *buffer - Buffer with the CPU and bus clock frequencies.
- *
- * Returns:
- *   The number of bytes copied into 'buffer' if OK, otherwise zero or less
- *   on error.
- */
-int
-walnut_show_percpuinfo(struct seq_file *m)
-{
-	bd_t *bp = (bd_t *)__res;
-
-	seq_printf(m, "clock\t\t: %dMHz\n"
-		   "bus clock\t\t: %dMHz\n",
-		   bp->bi_intfreq / 1000000,
-		   bp->bi_busfreq / 1000000);
-
-	return 0;
-}
-
-/*
- * Document me.
- */
-void __init
-walnut_init_IRQ(void)
-{
-	int i;
-
-	ppc4xx_pic_init();
-
-	for (i = 0; i < NR_IRQS; i++) {
-		irq_desc[i].handler = ppc4xx_pic;
-	}
-
-	return;
-}
-
-/*
- * Document me.
- */
-int
-walnut_get_irq(struct pt_regs *regs)
-{
-	return (ppc4xx_pic_get_irq(regs));
-}
-
-/*
- * Document me.
- */
-void
-walnut_restart(char *cmd)
-{
-	abort();
-}
-
-/*
- * Document me.
- */
-void
-walnut_power_off(void)
-{
-	walnut_restart(NULL);
-}
-
-/*
- * Document me.
- */
-void
-walnut_halt(void)
-{
-	walnut_restart(NULL);
-}
-
-/*
- * Document me.
- */
-long __init
-walnut_time_init(void)
-{
-	/* XXX - Implement me */
-	return 0;
-}
-
-/*
- * Document me.
- */
-int __init
-walnut_set_rtc_time(unsigned long time)
-{
-	/* XXX - Implement me */
-
-	return (0);
-}
-
-/*
- * Document me.
- */
-unsigned long __init
-walnut_get_rtc_time(void)
-{
-	/* XXX - Implement me */
-
-	return (0);
-}
-
-/*
- * void __init walnut_calibrate_decr()
- *
- * Description:
- *   This routine retrieves the internal processor frequency from the board
- *   information structure, sets up the kernel timer decrementer based on
- *   that value, enables the 403 programmable interval timer (PIT) and sets
- *   it up for auto-reload.
- *
- * Input(s):
- *   N/A
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   N/A
- *
- */
-void __init
-walnut_calibrate_decr(void)
-{
-	unsigned int freq;
-	bd_t *bip = (bd_t *)__res;
-
-	freq = bip->bi_intfreq;
-
-	decrementer_count = freq / HZ;
-	count_period_num = 1;
-	count_period_den = freq;
-
-	/* Enable the PIT and set auto-reload of its value */
-
-	mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
-
-	/* Clear any pending timer interrupts */
-
-	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/walnut_setup.h linux-2.4.20/arch/ppc/kernel/walnut_setup.h
--- linux-2.4.19/arch/ppc/kernel/walnut_setup.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/walnut_setup.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,53 +0,0 @@
-/*
- * BK Id: SCCS/s.walnut_setup.h 1.5 05/17/01 18:14:22 cort
- */
-/*
- *
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: walnut_setup.c
- *
- *    Description:
- *      Architecture- / platform-specific boot-time initialization code for
- *      the IBM PowerPC 405GP "Walnut" evaluation board. Adapted from original
- *      code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
- *      <dan@netx4.com>.
- *
- */
-
-#ifndef	__WALNUT_SETUP_H__
-#define	__WALNUT_SETUP_H__
-
-#include <asm/ptrace.h>
-#include <asm/board.h>
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern unsigned char	 __res[sizeof(bd_t)];
-
-extern void		 walnut_init(unsigned long r3,
-				  unsigned long ird_start,
-				  unsigned long ird_end,
-				  unsigned long cline_start,
-				  unsigned long cline_end);
-extern void		 walnut_setup_arch(void);
-extern int		 walnut_setup_residual(char *buffer);
-extern void		 walnut_init_IRQ(void);
-extern int		 walnut_get_irq(struct pt_regs *regs);
-extern void		 walnut_restart(char *cmd);
-extern void		 walnut_power_off(void);
-extern void		 walnut_halt(void);
-extern void		 walnut_time_init(void);
-extern int		 walnut_set_rtc_time(unsigned long now);
-extern unsigned long	 walnut_get_rtc_time(void);
-extern void		 walnut_calibrate_decr(void);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __WALNUT_SETUP_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/xics.c linux-2.4.20/arch/ppc/kernel/xics.c
--- linux-2.4.19/arch/ppc/kernel/xics.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/xics.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,217 +0,0 @@
-/*
- * BK Id: SCCS/s.xics.c 1.8 12/19/01 09:48:40 trini
- */
-/*
- * arch/ppc/kernel/xics.c
- *
- * Copyright 2000 IBM Corporation.
- *
- *  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.
- */
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/threads.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <asm/prom.h>
-#include <asm/io.h>
-#include "i8259.h"
-#include "xics.h"
-
-void xics_enable_irq(u_int irq);
-void xics_disable_irq(u_int irq);
-void xics_mask_and_ack_irq(u_int irq);
-void xics_end_irq(u_int irq);
-
-struct hw_interrupt_type xics_pic = {
-	" XICS     ",
-	NULL,
-	NULL,
-	xics_enable_irq,
-	xics_disable_irq,
-	xics_mask_and_ack_irq,
-	xics_end_irq
-};
-
-struct hw_interrupt_type xics_8259_pic = {
-	" XICS/8259",
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	xics_mask_and_ack_irq,
-	NULL
-};
-
-#define XICS_IPI		2
-#define XICS_IRQ_8259_CASCADE	0x2c
-#define XICS_IRQ_OFFSET		16
-#define XICS_IRQ_SPURIOUS	0
-
-#define DEFAULT_SERVER		0
-#define	DEFAULT_PRIORITY	0
-
-struct xics_ipl {
-	union {
-		u32	word;
-		u8	bytes[4];
-	} xirr_poll;
-	union {
-		u32 word;
-		u8	bytes[4];
-	} xirr;
-	u32	dummy;
-	union {
-		u32	word;
-		u8	bytes[4];
-	} qirr;
-};
-
-struct xics_info {
-	volatile struct xics_ipl *	per_cpu[NR_CPUS];
-};
-
-struct xics_info	xics_info;
-
-#define xirr_info(n_cpu)	(xics_info.per_cpu[n_cpu]->xirr.word)
-#define cppr_info(n_cpu)	(xics_info.per_cpu[n_cpu]->xirr.bytes[0])
-#define poll_info(n_cpu)	(xics_info.per_cpu[n_cpu]->xirr_poll.word)
-#define qirr_info(n_cpu)	(xics_info.per_cpu[n_cpu]->qirr.bytes[0])
-
-void
-xics_enable_irq(
-	u_int	irq
-	)
-{
-	int	status;
-	int	call_status;
-
-	irq -= XICS_IRQ_OFFSET;
-	if (irq == XICS_IPI)
-		return;
-	call_status = call_rtas("ibm,set-xive", 3, 1, (ulong*)&status,
-				irq, DEFAULT_SERVER, DEFAULT_PRIORITY);
-	if( call_status != 0 ) {
-		printk("xics_enable_irq: irq=%x: call_rtas failed; retn=%x, status=%x\n",
-		       irq, call_status, status);
-		return;
-	}
-}
-
-void
-xics_disable_irq(
-	u_int	irq
-	)
-{
-	int	status;
-	int	call_status;
-
-	irq -= XICS_IRQ_OFFSET;
-	call_status = call_rtas("ibm,int-off", 1, 1, (ulong*)&status, irq);
-	if( call_status != 0 ) {
-		printk("xics_disable_irq: irq=%x: call_rtas failed, retn=%x\n",
-		       irq, call_status);
-		return;
-	}
-}
-
-void
-xics_end_irq(
-	u_int	irq
-	)
-{
-	int cpu = smp_processor_id();
-
-	cppr_info(cpu) = 0; /* actually the value overwritten by ack */
-	xirr_info(cpu) = (0xff<<24) | (irq-XICS_IRQ_OFFSET);
-}
-
-void
-xics_mask_and_ack_irq(
-	u_int	irq
-	)
-{
-	int cpu = smp_processor_id();
-
-	if( irq < XICS_IRQ_OFFSET ) {
-		i8259_pic.ack(irq);
-		xirr_info(cpu) = (0xff<<24) | XICS_IRQ_8259_CASCADE;
-	}
-	else {
-		cppr_info(cpu) = 0xff;
-	}
-}
-
-int
-xics_get_irq(struct pt_regs *regs)
-{
-	u_int	cpu = smp_processor_id();
-	u_int	vec;
-	int irq;
-  
-	vec = xirr_info(cpu);
-	/*  (vec >> 24) == old priority */
-	vec &= 0x00ffffff;
-	/* for sanity, this had better be < NR_IRQS - 16 */
-	if( vec == XICS_IRQ_8259_CASCADE )
-		irq = i8259_poll();
-	else if( vec == XICS_IRQ_SPURIOUS )
-		irq = -1;
-	else
-		irq = vec + XICS_IRQ_OFFSET;
-	return irq;
-}
-
-#ifdef CONFIG_SMP
-void xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
-{
-	qirr_info(smp_processor_id()) = 0xff;
-	smp_message_recv(MSG_RESCHEDULE, regs);
-}
-
-void xics_cause_IPI(int cpu)
-{
-	qirr_info(cpu) = 0;
-}
-
-void xics_setup_cpu(void)
-{
-	int cpu = smp_processor_id();
-
-	cppr_info(cpu) = 0xff;
-}
-#endif /* CONFIG_SMP */
-
-void
-xics_init_IRQ( void )
-{
-	int i;
-	extern unsigned long smp_chrp_cpu_nr;
-
-#ifdef CONFIG_SMP
-	for (i = 0; i < smp_chrp_cpu_nr; ++i)
-		xics_info.per_cpu[i] =
-			ioremap(0xfe000000 + smp_hw_index[i] * 0x1000, 0x20);
-#else
-	xics_info.per_cpu[0] = ioremap(0xfe000000, 0x20);
-#endif /* CONFIG_SMP */
-	xics_8259_pic.enable = i8259_pic.enable;
-	xics_8259_pic.disable = i8259_pic.disable;
-	for (i = 0; i < 16; ++i)
-		irq_desc[i].handler = &xics_8259_pic;
-	for (; i < NR_IRQS; ++i)
-		irq_desc[i].handler = &xics_pic;
-
-	cppr_info(0) = 0xff;
-	if (request_irq(XICS_IRQ_8259_CASCADE + XICS_IRQ_OFFSET, no_action,
-			0, "8259 cascade", 0))
-		printk(KERN_ERR "xics_init_IRQ: couldn't get 8259 cascade\n");
-	i8259_init();
-
-#ifdef CONFIG_SMP
-	request_irq(XICS_IPI + XICS_IRQ_OFFSET, xics_ipi_action, 0, "IPI", 0);
-#endif
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/kernel/xics.h linux-2.4.20/arch/ppc/kernel/xics.h
--- linux-2.4.19/arch/ppc/kernel/xics.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/xics.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,26 +0,0 @@
-/*
- * BK Id: SCCS/s.xics.h 1.5 05/17/01 18:14:22 cort
- */
-/*
- * arch/ppc/kernel/xics.h
- *
- * Copyright 2000 IBM Corporation.
- *
- *  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.
- */
-
-#ifndef _PPC_KERNEL_XICS_H
-#define _PPC_KERNEL_XICS_H
-
-#include "local_irq.h"
-
-extern struct hw_interrupt_type xics_pic;
-extern struct hw_interrupt_type xics_8259_pic;
-
-void xics_init_IRQ(void);
-int xics_get_irq(struct pt_regs *);
-
-#endif /* _PPC_KERNEL_XICS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/lib/checksum.S linux-2.4.20/arch/ppc/lib/checksum.S
--- linux-2.4.19/arch/ppc/lib/checksum.S	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.20/arch/ppc/lib/checksum.S	2002-10-29 11:18:35.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.checksum.S 1.8 08/20/01 22:09:34 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * This file contains assembly-language implementations
@@ -18,7 +18,7 @@
 #include <linux/sys.h>
 #include <asm/processor.h>
 #include <asm/errno.h>
-#include "../kernel/ppc_asm.tmpl"
+#include <asm/ppc_asm.h>
 
 	.text
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/lib/locks.c linux-2.4.20/arch/ppc/lib/locks.c
--- linux-2.4.19/arch/ppc/lib/locks.c	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.20/arch/ppc/lib/locks.c	2002-10-29 11:18:34.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.locks.c 1.11 08/19/01 22:27:32 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Locks for smp ppc 
@@ -16,7 +16,7 @@
 #include <asm/system.h>
 #include <asm/io.h>
 
-#ifdef SPINLOCK_DEBUG
+#if SPINLOCK_DEBUG
 
 #undef INIT_STUCK
 #define INIT_STUCK 200000000 /*0xffffffff*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/lib/string.S linux-2.4.20/arch/ppc/lib/string.S
--- linux-2.4.19/arch/ppc/lib/string.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/lib/string.S	2002-10-29 11:18:32.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.string.S 1.11 05/21/02 21:44:32 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * String handling functions for PowerPC.
@@ -11,11 +11,11 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#include "../kernel/ppc_asm.tmpl"
 #include <linux/config.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
 #include <asm/errno.h>
+#include <asm/ppc_asm.h>
 
 #define COPY_16_BYTES		\
 	lwz	r7,4(r4);	\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/mm/fault.c linux-2.4.20/arch/ppc/mm/fault.c
--- linux-2.4.19/arch/ppc/mm/fault.c	2001-10-02 16:12:44.000000000 +0000
+++ linux-2.4.20/arch/ppc/mm/fault.c	2002-10-29 11:18:35.000000000 +0000
@@ -195,13 +195,11 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (current->pid == 1) {
-		current->policy |= SCHED_YIELD;
-		schedule();
-		down_read(&mm->mmap_sem);
+		yield();
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/mm/hashtable.S linux-2.4.20/arch/ppc/mm/hashtable.S
--- linux-2.4.19/arch/ppc/mm/hashtable.S	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.20/arch/ppc/mm/hashtable.S	2002-10-29 11:18:35.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.hashtable.S 1.18 08/15/01 22:43:07 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  arch/ppc/kernel/hashtable.S
@@ -27,11 +27,13 @@
  */
 
 #include <linux/config.h>
-#include "../kernel/ppc_asm.h"
+#include <asm/ppc_asm.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include <kernel/ppc_defs.h>
 
 #ifdef CONFIG_SMP
 	.comm	hash_table_lock,4
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/mm/mmu_decl.h linux-2.4.20/arch/ppc/mm/mmu_decl.h
--- linux-2.4.19/arch/ppc/mm/mmu_decl.h	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.20/arch/ppc/mm/mmu_decl.h	2002-10-29 11:18:48.000000000 +0000
@@ -23,6 +23,8 @@
  *
  */
 
+#include <asm/pgtable.h>
+
 extern void mapin_ram(void);
 extern void bat_mapin_ram(unsigned long bat2, unsigned long bat3);
 extern void adjust_total_lowmem(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/mm/ppc_mmu.c linux-2.4.20/arch/ppc/mm/ppc_mmu.c
--- linux-2.4.19/arch/ppc/mm/ppc_mmu.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc/mm/ppc_mmu.c	2002-10-29 11:18:33.000000000 +0000
@@ -51,7 +51,7 @@
 	u64	word[2];
 #else
 	u32	word[2];
-#endif	
+#endif
 } BATS[4][2];			/* 4 pairs of IBAT, DBAT */
 
 struct batrange {		/* stores address ranges mapped by BATs */
@@ -158,31 +158,13 @@
  */
 void __init MMU_init_hw(void)
 {
-	int Hash_bits, mb, mb2;
-	unsigned int hmask;
+	unsigned int hmask, mb, mb2;
+	unsigned int n_hpteg, lg_n_hpteg;
 
 	extern unsigned int hash_page_patch_A[];
 	extern unsigned int hash_page_patch_B[], hash_page_patch_C[];
 	extern unsigned int flush_hash_patch_A[], flush_hash_patch_B[];
 
-#ifdef CONFIG_PPC64BRIDGE
-	/* The hash table has already been allocated and initialized
-	   in prom.c */
-	Hash_mask = (Hash_size >> 7) - 1;
-	hmask = Hash_mask >> 9;
-	Hash_bits = __ilog2(Hash_size) - 7;
-	mb = 25 - Hash_bits;
-	if (Hash_bits > 16)
-		Hash_bits = 16;
-	mb2 = 25 - Hash_bits;
-
-	/* Remove the hash table from the available memory */
-	if (Hash)
-		reserve_phys_mem(__pa(Hash), Hash_size);
-
-#else /* CONFIG_PPC64BRIDGE */
-	unsigned int h;
-
 	if ((cur_cpu_spec[0]->cpu_features & CPU_FTR_HPTE_TABLE) == 0) {
 		Hash_size = 0;
 		Hash_end = 0;
@@ -192,72 +174,78 @@
 
 	if ( ppc_md.progress ) ppc_md.progress("hash:enter", 0x105);
 
+#ifdef CONFIG_PPC64BRIDGE
+#define LG_HPTEG_SIZE	7		/* 128 bytes per HPTEG */
+#define SDR1_LOW_BITS	(lg_n_hpteg - 11)
+#define MIN_N_HPTEG	2048		/* min 256kB hash table */
+#else
+#define LG_HPTEG_SIZE	6		/* 64 bytes per HPTEG */
+#define SDR1_LOW_BITS	((n_hpteg - 1) >> 10)
+#define MIN_N_HPTEG	1024		/* min 64kB hash table */
+#endif
+
 	/*
-	 * Allow 64k of hash table for every 16MB of memory,
-	 * up to a maximum of 2MB.
+	 * Allow 1 HPTE (1/8 HPTEG) for each page of memory.
+	 * This is less than the recommended amount, but then
+	 * Linux ain't AIX.
 	 */
-	for (h = 64<<10; h < total_memory / 256 && h < (2<<20); h *= 2)
-		;
-	Hash_size = h;
-	Hash_mask = (h >> 6) - 1;
-	hmask = Hash_mask >> 10;
-	Hash_bits = __ilog2(h) - 6;
-	mb = 26 - Hash_bits;
-	if (Hash_bits > 16)
-		Hash_bits = 16;
-	mb2 = 26 - Hash_bits;
+	n_hpteg = total_memory / (PAGE_SIZE * 8);
+	if (n_hpteg < MIN_N_HPTEG)
+		n_hpteg = MIN_N_HPTEG;
+	lg_n_hpteg = __ilog2(n_hpteg);
+	if (n_hpteg & (n_hpteg - 1)) {
+		++lg_n_hpteg;		/* round up if not power of 2 */
+		n_hpteg = 1 << lg_n_hpteg;
+	}
+	Hash_size = n_hpteg << LG_HPTEG_SIZE;
 
+	/*
+	 * Find some memory for the hash table.
+	 */
 	if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322);
-	/* Find some memory for the hash table. */
-	if ( Hash_size ) {
-		Hash = mem_pieces_find(Hash_size, Hash_size);
-		cacheable_memzero(Hash, Hash_size);
-		_SDR1 = __pa(Hash) | (Hash_mask >> 10);
-	} else
-		Hash = 0;
-#endif /* CONFIG_PPC64BRIDGE */
+	Hash = mem_pieces_find(Hash_size, Hash_size);
+	cacheable_memzero(Hash, Hash_size);
+	_SDR1 = __pa(Hash) | SDR1_LOW_BITS;
+	Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
 
 	printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
 	       total_memory >> 20, Hash_size >> 10, Hash);
-	if (Hash_size) {
-		if ( ppc_md.progress ) ppc_md.progress("hash:patch", 0x345);
-		Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
-
-		/*
-		 * Patch up the instructions in hashtable.S:create_hpte
-		 */
-		hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff)
-			| ((unsigned int)(Hash) >> 16);
-		hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0)
-			| (mb << 6);
-		hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0)
-			| (mb2 << 6);
-		hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff)
-			| hmask;
-		hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff)
-			| hmask;
-		/*
-		 * Ensure that the locations we've patched have been written
-		 * out from the data cache and invalidated in the instruction
-		 * cache, on those machines with split caches.
-		 */
-		flush_icache_range((unsigned long) &hash_page_patch_A[0],
-				   (unsigned long) &hash_page_patch_C[1]);
-		/*
-		 * Patch up the instructions in hashtable.S:flush_hash_page
-		 */
-		flush_hash_patch_A[0] = (flush_hash_patch_A[0] & ~0xffff)
-			| ((unsigned int)(Hash) >> 16);
-		flush_hash_patch_A[1] = (flush_hash_patch_A[1] & ~0x7c0)
-			| (mb << 6);
-		flush_hash_patch_A[2] = (flush_hash_patch_A[2] & ~0x7c0)
-			| (mb2 << 6);
-		flush_hash_patch_B[0] = (flush_hash_patch_B[0] & ~0xffff)
-			| hmask;
-		flush_icache_range((unsigned long) &flush_hash_patch_A[0],
-				   (unsigned long) &flush_hash_patch_B[1]);
-	}
-	
+
+	/*
+	 * Patch up the instructions in hashtable.S:create_hpte
+	 */
+	if ( ppc_md.progress ) ppc_md.progress("hash:patch", 0x345);
+	Hash_mask = n_hpteg - 1;
+	hmask = Hash_mask >> (16 - LG_HPTEG_SIZE);
+	mb2 = mb = 32 - LG_HPTEG_SIZE - lg_n_hpteg;
+	if (lg_n_hpteg > 16)
+		mb2 = 16 - LG_HPTEG_SIZE;
+	hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff)
+		| ((unsigned int)(Hash) >> 16);
+	hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0) | (mb << 6);
+	hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0) | (mb2 << 6);
+	hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff) | hmask;
+	hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff) | hmask;
+
+	/*
+	 * Ensure that the locations we've patched have been written
+	 * out from the data cache and invalidated in the instruction
+	 * cache, on those machines with split caches.
+	 */
+	flush_icache_range((unsigned long) &hash_page_patch_A[0],
+			   (unsigned long) &hash_page_patch_C[1]);
+
+	/*
+	 * Patch up the instructions in hashtable.S:flush_hash_page
+	 */
+	flush_hash_patch_A[0] = (flush_hash_patch_A[0] & ~0xffff)
+		| ((unsigned int)(Hash) >> 16);
+	flush_hash_patch_A[1] = (flush_hash_patch_A[1] & ~0x7c0) | (mb << 6);
+	flush_hash_patch_A[2] = (flush_hash_patch_A[2] & ~0x7c0) | (mb2 << 6);
+	flush_hash_patch_B[0] = (flush_hash_patch_B[0] & ~0xffff) | hmask;
+	flush_icache_range((unsigned long) &flush_hash_patch_A[0],
+			   (unsigned long) &flush_hash_patch_B[1]);
+
 	if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/Makefile linux-2.4.20/arch/ppc/platforms/Makefile
--- linux-2.4.19/arch/ppc/platforms/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/Makefile	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,56 @@
+# BK Id: SCCS/s.Makefile 1.57 09/24/01 07:45:31 trini
+#
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+USE_STANDARD_AS_RULE	:= true
+
+ifdef CONFIG_PPC64BRIDGE
+EXTRA_AFLAGS		:= -Wa,-mppc64bridge
+endif
+ifdef CONFIG_40x
+EXTRA_AFLAGS		:= -Wa,-m405
+endif
+
+# Extra CFLAGS so we don't have to do relative includes
+CFLAGS_pmac_setup.o	+= -I$(TOPDIR)/drivers/scsi -I$(TOPDIR)/fs/partitions \
+				-I$(TOPDIR)/arch/$(ARCH)/mm
+CFLAGS_spruce_setup.o	+= -I$(TOPDIR)/arch/ppc/kernel
+CFLAGS_spruce_pci.o	+= -I$(TOPDIR)/arch/ppc/kernel
+CFLAGS_pal4_setup.o	+= -I$(TOPDIR)/arch/ppc/kernel
+CFLAGS_pal4_pci.o	+= -I$(TOPDIR)/arch/ppc/kernel
+
+O_TARGET := platform.o
+
+export-objs			:= prep_setup.o
+
+obj-$(CONFIG_WALNUT)		+= walnut.o
+
+obj-$(CONFIG_APUS)		+= apus_setup.o
+ifeq ($(CONFIG_APUS),y)
+obj-$(CONFIG_PCI)		+= apus_pci.o
+endif
+
+obj-$(CONFIG_ALL_PPC)		+= pmac_pic.o pmac_setup.o pmac_time.o \
+					pmac_feature.o pmac_pci.o chrp_setup.o\
+					chrp_time.o chrp_pci.o prep_pci.o \
+					prep_time.o prep_setup.o pmac_sleep.o \
+					pmac_nvram.o
+obj-$(CONFIG_PMAC_BACKLIGHT)	+= pmac_backlight.o
+obj-$(CONFIG_PPC_RTAS)		+= error_log.o proc_rtas.o
+obj-$(CONFIG_PREP_RESIDUAL)	+= residual.o
+obj-$(CONFIG_GEMINI)		+= gemini_pci.o gemini_setup.o gemini_prom.o
+obj-$(CONFIG_PAL4)		+= pal4_setup.o pal4_pci.o cpc700_pic.o
+obj-$(CONFIG_SPRUCE)		+= spruce_setup.o spruce_pci.o cpc700_pic.o
+
+ifeq ($(CONFIG_SMP),y)
+obj-$(CONFIG_ALL_PPC)		+= pmac_smp.o chrp_smp.o
+endif
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/apus_pci.c linux-2.4.20/arch/ppc/platforms/apus_pci.c
--- linux-2.4.19/arch/ppc/platforms/apus_pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/apus_pci.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,188 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * Copyright (C) Michel Dnzer <michdaen@iiic.ethz.ch>
+ *
+ * APUS PCI routines.
+ *
+ * Currently, only B/CVisionPPC cards (Permedia2) are supported.
+ *
+ * Thanks to Geert Uytterhoeven for the idea:
+ * Read values from given config space(s) for the first devices, -1 otherwise
+ *
+ */
+
+#include <linux/config.h>
+#ifdef CONFIG_AMIGA
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+
+#include "apus_pci.h"
+
+
+/* These definitions are mostly adapted from pm2fb.c */
+
+#undef APUS_PCI_MASTER_DEBUG
+#ifdef APUS_PCI_MASTER_DEBUG
+#define DPRINTK(a,b...)	printk(KERN_DEBUG "apus_pci: %s: " a, __FUNCTION__ , ## b)
+#else
+#define DPRINTK(a,b...)
+#endif 
+
+/*
+ * The _DEFINITIVE_ memory mapping/unmapping functions.
+ * This is due to the fact that they're changing soooo often...
+ */
+#define DEFW()		wmb()
+#define DEFR()		rmb()
+#define DEFRW()		mb()
+
+#define DEVNO(d)	((d)>>3)
+#define FNNO(d)		((d)&7)
+
+
+extern unsigned long powerup_PCI_present;
+
+static struct pci_controller *apus_hose;
+
+
+void *pci_io_base(unsigned int bus)
+{
+	return 0;
+}
+
+
+#define cfg_read(val, addr, type, op)	*val = op((type)(addr))
+#define cfg_write(val, addr, type, op)	op((val), (type *)(addr)); DEFW()
+#define cfg_read_bad	*val = ~0;
+#define cfg_write_bad	;
+#define cfg_read_val(val)	*val
+#define cfg_write_val(val)	val
+
+#define APUS_PCI_OP(rw, size, type, op, mask)					\
+int									\
+apus_pcibios_##rw##_config_##size(struct pci_dev *dev, int offset, type val)	\
+{										\
+	int fnno = FNNO(dev->devfn);						\
+	int devno = DEVNO(dev->devfn);						\
+										\
+	if (dev->bus->number > 0 || devno != 1) {				\
+		cfg_##rw##_bad;							\
+		return PCIBIOS_DEVICE_NOT_FOUND;				\
+	}									\
+	/* base address + function offset + offset ^ endianness conversion */	\
+	cfg_##rw(val, apus_hose->cfg_data + (fnno<<5) + (offset ^ mask),	\
+		 type, op);							\
+										\
+	DPRINTK(#op " b: 0x%x, d: 0x%x, f: 0x%x, o: 0x%x, v: 0x%x\n",		\
+		dev->bus->number, dev->devfn>>3, dev->devfn&7,			\
+		offset, cfg_##rw##_val(val));					\
+	return PCIBIOS_SUCCESSFUL;						\
+}
+
+APUS_PCI_OP(read, byte, u8 *, readb, 3)
+APUS_PCI_OP(read, word, u16 *, readw, 2)
+APUS_PCI_OP(read, dword, u32 *, readl, 0)
+APUS_PCI_OP(write, byte, u8, writeb, 3)
+APUS_PCI_OP(write, word, u16, writew, 2)
+APUS_PCI_OP(write, dword, u32, writel, 0)
+
+
+static struct pci_ops apus_pci_ops = {
+	apus_pcibios_read_config_byte,
+	apus_pcibios_read_config_word,
+	apus_pcibios_read_config_dword,
+	apus_pcibios_write_config_byte,
+	apus_pcibios_write_config_word,
+	apus_pcibios_write_config_dword
+};
+
+static struct resource pci_mem = { "B/CVisionPPC PCI mem", CVPPC_FB_APERTURE_ONE, CVPPC_PCI_CONFIG, IORESOURCE_MEM };
+
+void __init
+apus_pcibios_fixup(void)
+{
+/*	struct pci_dev *dev = pci_find_slot(0, 1<<3);
+	unsigned int reg, val, offset;*/
+
+	/* FIXME: interrupt? */
+	/*dev->interrupt = xxx;*/
+
+        request_resource(&iomem_resource, &pci_mem);
+    	printk("%s: PCI mem resource requested\n", __FUNCTION__);
+}
+
+static void __init apus_pcibios_fixup_bus(struct pci_bus *bus)
+{
+        bus->resource[1] = &pci_mem;
+}
+
+
+/* 
+ * This is from pm2fb.c again
+ * 
+ * Check if PCI (B/CVisionPPC) is available, initialize it and set up
+ * the pcibios_* pointers
+ */
+
+
+void __init
+apus_setup_pci_ptrs(void)
+{
+	if (!powerup_PCI_present) {
+		DPRINTK("no PCI bridge detected\n");
+		return;
+	}
+	DPRINTK("Phase5 B/CVisionPPC PCI bridge detected.\n");
+
+	apus_hose = pcibios_alloc_controller();
+	if (!apus_hose) {
+		printk("apus_pci: Can't allocate PCI controller structure\n");
+		return;
+	}
+
+	if (!(apus_hose->cfg_data = ioremap(CVPPC_PCI_CONFIG, 256))) {
+		printk("apus_pci: unable to map PCI config region\n");
+		return;
+	}
+
+	if (!(apus_hose->cfg_addr = ioremap(CSPPC_PCI_BRIDGE, 256))) {
+		printk("apus_pci: unable to map PCI bridge\n");
+		return;
+	}
+
+	writel(CSPPCF_BRIDGE_BIG_ENDIAN, apus_hose->cfg_addr + CSPPC_BRIDGE_ENDIAN);
+	DEFW();
+
+	writel(CVPPC_REGS_REGION,  apus_hose->cfg_data+ PCI_BASE_ADDRESS_0);
+	DEFW();
+	writel(CVPPC_FB_APERTURE_ONE, apus_hose->cfg_data + PCI_BASE_ADDRESS_1);
+	DEFW();
+	writel(CVPPC_FB_APERTURE_TWO, apus_hose->cfg_data + PCI_BASE_ADDRESS_2);
+	DEFW();
+	writel(CVPPC_ROM_ADDRESS, apus_hose->cfg_data + PCI_ROM_ADDRESS);
+	DEFW();
+
+	writel(0xef000000 | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+		PCI_COMMAND_MASTER, apus_hose->cfg_data + PCI_COMMAND);
+	DEFW();
+
+	apus_hose->first_busno = 0;
+	apus_hose->last_busno = 0;
+	apus_hose->ops = &apus_pci_ops;
+	ppc_md.pcibios_fixup = apus_pcibios_fixup;
+	ppc_md.pcibios_fixup_bus = apus_pcibios_fixup_bus;
+
+	return;
+}
+
+#endif /* CONFIG_AMIGA */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/apus_pci.h linux-2.4.20/arch/ppc/platforms/apus_pci.h
--- linux-2.4.19/arch/ppc/platforms/apus_pci.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/apus_pci.h	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,37 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * Phase5 CybervisionPPC (TVP4020) definitions for the Permedia2 framebuffer
+ * driver.
+ *
+ * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
+ * --------------------------------------------------------------------------
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef APUS_PCI_H
+#define APUS_PCI_H
+
+
+#define CSPPC_PCI_BRIDGE		0xfffe0000
+#define CSPPC_BRIDGE_ENDIAN		0x0000
+#define CSPPC_BRIDGE_INT		0x0010
+
+#define	CVPPC_PCI_CONFIG		0xfffc0000
+#define CVPPC_ROM_ADDRESS		0xe2000001
+#define CVPPC_REGS_REGION		0xef000000
+#define CVPPC_FB_APERTURE_ONE		0xe0000000
+#define CVPPC_FB_APERTURE_TWO		0xe1000000
+#define CVPPC_FB_SIZE			0x00800000
+
+/* CVPPC_BRIDGE_ENDIAN */
+#define CSPPCF_BRIDGE_BIG_ENDIAN	0x02
+
+/* CVPPC_BRIDGE_INT */
+#define CSPPCF_BRIDGE_ACTIVE_INT2	0x01
+
+
+#endif	/* APUS_PCI_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/apus_setup.c linux-2.4.20/arch/ppc/platforms/apus_setup.c
--- linux-2.4.19/arch/ppc/platforms/apus_setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/apus_setup.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,867 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/platforms/apus_setup.c
+ *
+ *  Copyright (C) 1998, 1999  Jesper Skov
+ *
+ *  Basically what is needed to replace functionality found in
+ *  arch/m68k allowing Amiga drivers to work under APUS.
+ *  Bits of code and/or ideas from arch/m68k and arch/ppc files.
+ *
+ * TODO:
+ *  This file needs a *really* good cleanup. Restructure and optimize.
+ *  Make sure it can be compiled for non-APUS configs. Begin to move
+ *  Amiga specific stuff into mach/amiga.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/seq_file.h>
+
+/* Needs INITSERIAL call in head.S! */
+#undef APUS_DEBUG
+
+#include <asm/bootinfo.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/amigappc.h>
+#include <asm/pgtable.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/hardirq.h>
+#include <asm/keyboard.h>
+#include <asm/time.h>
+
+unsigned long m68k_machtype;
+char debug_device[6] = "";
+
+extern void amiga_init_IRQ(void);
+
+extern int amiga_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode);
+extern char amiga_sysrq_xlate[128];
+
+extern void apus_setup_pci_ptrs(void);
+
+void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;
+/* machine dependent keyboard functions */
+int (*mach_keyb_init) (void) __initdata = NULL;
+int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
+void (*mach_kbd_leds) (unsigned int) = NULL;
+/* machine dependent irq functions */
+void (*mach_init_IRQ) (void) __initdata = NULL;
+void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
+void (*mach_get_model) (char *model) = NULL;
+int (*mach_get_hardware_list) (char *buffer) = NULL;
+int (*mach_get_irq_list) (char *) = NULL;
+void (*mach_process_int) (int, struct pt_regs *) = NULL;
+/* machine dependent timer functions */
+unsigned long (*mach_gettimeoffset) (void);
+void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
+int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
+int (*mach_set_clock_mmss) (unsigned long) = NULL;
+void (*mach_reset)( void );
+long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
+#if defined(CONFIG_AMIGA_FLOPPY)
+void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
+#endif
+#ifdef CONFIG_HEARTBEAT
+void (*mach_heartbeat) (int) = NULL;
+extern void apus_heartbeat(void);
+#endif
+
+extern unsigned long amiga_model;
+extern unsigned decrementer_count;/* count value for 1e6/HZ microseconds */
+extern unsigned count_period_num; /* 1 decrementer count equals */
+extern unsigned count_period_den; /* count_period_num / count_period_den us */
+
+int num_memory = 0;
+struct mem_info memory[NUM_MEMINFO];/* memory description */
+/* FIXME: Duplicate memory data to avoid conflicts with m68k shared code. */
+int m68k_realnum_memory = 0;
+struct mem_info m68k_memory[NUM_MEMINFO];/* memory description */
+
+struct mem_info ramdisk;
+
+extern void amiga_floppy_setup(char *, int *);
+extern void config_amiga(void);
+
+static int __60nsram = 0;
+
+/* for cpuinfo */
+static int __bus_speed = 0;
+static int __speed_test_failed = 0;
+
+/********************************************** COMPILE PROTECTION */
+/* Provide some stubs that links to Amiga specific functions.
+ * This allows CONFIG_APUS to be removed from generic PPC files while
+ * preventing link errors for other PPC targets.
+ */
+unsigned long apus_get_rtc_time(void)
+{
+#ifdef CONFIG_APUS
+	extern unsigned long m68k_get_rtc_time(void);
+
+	return m68k_get_rtc_time ();
+#else
+	return 0;
+#endif
+}
+
+int apus_set_rtc_time(unsigned long nowtime)
+{
+#ifdef CONFIG_APUS
+	extern int m68k_set_rtc_time(unsigned long nowtime);
+
+	return m68k_set_rtc_time (nowtime);
+#else
+	return 0;
+#endif
+}
+
+/*********************************************************** SETUP */
+/* From arch/m68k/kernel/setup.c. */
+void __init apus_setup_arch(void)
+{
+#ifdef CONFIG_APUS
+	extern char cmd_line[];
+	int i;
+	char *p, *q;
+
+	/* Let m68k-shared code know it should do the Amiga thing. */
+	m68k_machtype = MACH_AMIGA;
+
+	/* Parse the command line for arch-specific options.
+	 * For the m68k, this is currently only "debug=xxx" to enable printing
+	 * certain kernel messages to some machine-specific device.  */
+	for( p = cmd_line; p && *p; ) {
+	    i = 0;
+	    if (!strncmp( p, "debug=", 6 )) {
+		    strncpy( debug_device, p+6, sizeof(debug_device)-1 );
+		    debug_device[sizeof(debug_device)-1] = 0;
+		    if ((q = strchr( debug_device, ' ' ))) *q = 0;
+		    i = 1;
+	    } else if (!strncmp( p, "60nsram", 7 )) {
+		    APUS_WRITE (APUS_REG_WAITSTATE,
+				REGWAITSTATE_SETRESET
+				|REGWAITSTATE_PPCR
+				|REGWAITSTATE_PPCW);
+		    __60nsram = 1;
+		    i = 1;
+	    }
+
+	    if (i) {
+		/* option processed, delete it */
+		if ((q = strchr( p, ' ' )))
+		    strcpy( p, q+1 );
+		else
+		    *p = 0;
+	    } else {
+		if ((p = strchr( p, ' ' ))) ++p;
+	    }
+	}
+
+	config_amiga();
+
+#if 0 /* Enable for logging - also include logging.o in Makefile rule */
+	{
+#define LOG_SIZE 4096
+		void* base;
+
+		/* Throw away some memory - the P5 firmare stomps on top
+		 * of CHIP memory during bootup.
+		 */
+		amiga_chip_alloc(0x1000);
+
+		base = amiga_chip_alloc(LOG_SIZE+sizeof(klog_data_t));
+		LOG_INIT(base, base+sizeof(klog_data_t), LOG_SIZE);
+	}
+#endif
+#endif
+}
+
+int
+apus_show_cpuinfo(struct seq_file *m)
+{
+	extern int __map_without_bats;
+	extern unsigned long powerup_PCI_present;
+
+	seq_printf(m, "machine\t\t: Amiga\n");
+	seq_printf(m, "bus speed\t: %d%s", __bus_speed,
+		   (__speed_test_failed) ? " [failed]\n" : "\n");
+	seq_printf(m, "using BATs\t: %s\n",
+		   (__map_without_bats) ? "No" : "Yes");
+	seq_printf(m, "ram speed\t: %dns\n", (__60nsram) ? 60 : 70);
+	seq_printf(m, "PCI bridge\t: %s\n",
+		   (powerup_PCI_present) ? "Yes" : "No");
+	return 0;
+}
+
+static void get_current_tb(unsigned long long *time)
+{
+	__asm __volatile ("1:mftbu 4      \n\t"
+			  "  mftb  5      \n\t"
+			  "  mftbu 6      \n\t"
+			  "  cmpw  4,6    \n\t"
+			  "  bne   1b     \n\t"
+			  "  stw   4,0(%0)\n\t"
+			  "  stw   5,4(%0)\n\t"
+			  :
+			  : "r" (time)
+			  : "r4", "r5", "r6");
+}
+
+
+void apus_calibrate_decr(void)
+{
+#ifdef CONFIG_APUS
+	unsigned long freq;
+
+	/* This algorithm for determining the bus speed was
+           contributed by Ralph Schmidt. */
+	unsigned long long start, stop;
+	int bus_speed;
+	int speed_test_failed = 0;
+
+	{
+		unsigned long loop = amiga_eclock / 10;
+
+		get_current_tb (&start);
+		while (loop--) {
+			unsigned char tmp;
+
+			tmp = ciaa.pra;
+		}
+		get_current_tb (&stop);
+	}
+
+	bus_speed = (((unsigned long)(stop-start))*10*4) / 1000000;
+	if (AMI_1200 == amiga_model)
+		bus_speed /= 2;
+
+	if ((bus_speed >= 47) && (bus_speed < 53)) {
+		bus_speed = 50;
+		freq = 12500000;
+	} else if ((bus_speed >= 57) && (bus_speed < 63)) {
+		bus_speed = 60;
+		freq = 15000000;
+	} else if ((bus_speed >= 63) && (bus_speed < 69)) {
+		bus_speed = 67;
+		freq = 16666667;
+	} else {
+		printk ("APUS: Unable to determine bus speed (%d). "
+			"Defaulting to 50MHz", bus_speed);
+		bus_speed = 50;
+		freq = 12500000;
+		speed_test_failed = 1;
+	}
+
+	/* Ease diagnostics... */
+	{
+		extern int __map_without_bats;
+		extern unsigned long powerup_PCI_present;
+
+		printk ("APUS: BATs=%d, BUS=%dMHz",
+			(__map_without_bats) ? 0 : 1,
+			bus_speed);
+		if (speed_test_failed)
+			printk ("[FAILED - please report]");
+
+		printk (", RAM=%dns, PCI bridge=%d\n",
+			(__60nsram) ? 60 : 70,
+			(powerup_PCI_present) ? 1 : 0);
+
+		/* print a bit more if asked politely... */
+		if (!(ciaa.pra & 0x40)){
+			extern unsigned int bat_addrs[4][3];
+			int b;
+			for (b = 0; b < 4; ++b) {
+				printk ("APUS: BAT%d ", b);
+				printk ("%08x-%08x -> %08x\n",
+					bat_addrs[b][0],
+					bat_addrs[b][1],
+					bat_addrs[b][2]);
+			}
+		}
+
+	}
+
+        printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+	       freq/1000000, freq%1000000);
+	tb_ticks_per_jiffy = freq / HZ;
+	tb_to_us = mulhwu_scale_factor(freq, 1000000);
+
+	__bus_speed = bus_speed;
+	__speed_test_failed = speed_test_failed;
+#endif
+}
+
+void arch_gettod(int *year, int *mon, int *day, int *hour,
+		 int *min, int *sec)
+{
+#ifdef CONFIG_APUS
+	if (mach_gettod)
+		mach_gettod(year, mon, day, hour, min, sec);
+	else
+		*year = *mon = *day = *hour = *min = *sec = 0;
+#endif
+}
+
+/* for "kbd-reset" cmdline param */
+__init
+void kbd_reset_setup(char *str, int *ints)
+{
+}
+
+/*********************************************************** FLOPPY */
+#if defined(CONFIG_AMIGA_FLOPPY)
+__init
+void floppy_setup(char *str, int *ints)
+{
+	if (mach_floppy_setup)
+		mach_floppy_setup (str, ints);
+}
+#endif
+
+/*********************************************************** MEMORY */
+#define KMAP_MAX 32
+unsigned long kmap_chunks[KMAP_MAX*3];
+int kmap_chunk_count = 0;
+
+/* From pgtable.h */
+static __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va)
+{
+	pgd_t *dir = 0;
+	pmd_t *pmd = 0;
+	pte_t *pte = 0;
+
+	va &= PAGE_MASK;
+
+	dir = pgd_offset( mm, va );
+	if (dir)
+	{
+		pmd = pmd_offset(dir, va & PAGE_MASK);
+		if (pmd && pmd_present(*pmd))
+		{
+			pte = pte_offset(pmd, va);
+		}
+	}
+	return pte;
+}
+
+
+/* Again simulating an m68k/mm/kmap.c function. */
+void kernel_set_cachemode( unsigned long address, unsigned long size,
+			   unsigned int cmode )
+{
+	unsigned long mask, flags;
+
+	switch (cmode)
+	{
+	case IOMAP_FULL_CACHING:
+		mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED);
+		flags = 0;
+		break;
+	case IOMAP_NOCACHE_SER:
+		mask = ~0;
+		flags = (_PAGE_NO_CACHE | _PAGE_GUARDED);
+		break;
+	default:
+		panic ("kernel_set_cachemode() doesn't support mode %d\n",
+		       cmode);
+		break;
+	}
+
+	size /= PAGE_SIZE;
+	address &= PAGE_MASK;
+	while (size--)
+	{
+		pte_t *pte;
+
+		pte = my_find_pte(&init_mm, address);
+		if ( !pte )
+		{
+			printk("pte NULL in kernel_set_cachemode()\n");
+			return;
+		}
+
+                pte_val (*pte) &= mask;
+                pte_val (*pte) |= flags;
+                flush_tlb_page(find_vma(&init_mm,address),address);
+
+		address += PAGE_SIZE;
+	}
+}
+
+unsigned long mm_ptov (unsigned long paddr)
+{
+	unsigned long ret;
+	if (paddr < 16*1024*1024)
+		ret = ZTWO_VADDR(paddr);
+	else {
+		int i;
+
+		for (i = 0; i < kmap_chunk_count;){
+			unsigned long phys = kmap_chunks[i++];
+			unsigned long size = kmap_chunks[i++];
+			unsigned long virt = kmap_chunks[i++];
+			if (paddr >= phys
+			    && paddr < (phys + size)){
+				ret = virt + paddr - phys;
+				goto exit;
+			}
+		}
+
+		ret = (unsigned long) __va(paddr);
+	}
+exit:
+#ifdef DEBUGPV
+	printk ("PTOV(%lx)=%lx\n", paddr, ret);
+#endif
+	return ret;
+}
+
+int mm_end_of_chunk (unsigned long addr, int len)
+{
+	if (memory[0].addr + memory[0].size == addr + len)
+		return 1;
+	return 0;
+}
+
+/*********************************************************** CACHE */
+
+#define L1_CACHE_BYTES 32
+#define MAX_CACHE_SIZE 8192
+void cache_push(__u32 addr, int length)
+{
+	addr = mm_ptov(addr);
+
+	if (MAX_CACHE_SIZE < length)
+		length = MAX_CACHE_SIZE;
+
+	while(length > 0){
+		__asm ("dcbf 0,%0\n\t"
+		       : : "r" (addr));
+		addr += L1_CACHE_BYTES;
+		length -= L1_CACHE_BYTES;
+	}
+	/* Also flush trailing block */
+	__asm ("dcbf 0,%0\n\t"
+	       "sync \n\t"
+	       : : "r" (addr));
+}
+
+void cache_clear(__u32 addr, int length)
+{
+	if (MAX_CACHE_SIZE < length)
+		length = MAX_CACHE_SIZE;
+
+	addr = mm_ptov(addr);
+
+	__asm ("dcbf 0,%0\n\t"
+	       "sync \n\t"
+	       "icbi 0,%0 \n\t"
+	       "isync \n\t"
+	       : : "r" (addr));
+
+	addr += L1_CACHE_BYTES;
+	length -= L1_CACHE_BYTES;
+
+	while(length > 0){
+		__asm ("dcbf 0,%0\n\t"
+		       "sync \n\t"
+		       "icbi 0,%0 \n\t"
+		       "isync \n\t"
+		       : : "r" (addr));
+		addr += L1_CACHE_BYTES;
+		length -= L1_CACHE_BYTES;
+	}
+
+	__asm ("dcbf 0,%0\n\t"
+	       "sync \n\t"
+	       "icbi 0,%0 \n\t"
+	       "isync \n\t"
+	       : : "r" (addr));
+}
+
+/****************************************************** from setup.c */
+void
+apus_restart(char *cmd)
+{
+	cli();
+
+	APUS_WRITE(APUS_REG_LOCK,
+		   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2);
+	APUS_WRITE(APUS_REG_LOCK,
+		   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3);
+	APUS_WRITE(APUS_REG_LOCK,
+		   REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3);
+	APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET);
+	APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET);
+	for(;;);
+}
+
+void
+apus_power_off(void)
+{
+	for (;;);
+}
+
+void
+apus_halt(void)
+{
+   apus_restart(NULL);
+}
+
+/****************************************************** IRQ stuff */
+
+static unsigned char last_ipl[8];
+
+int apus_get_irq(struct pt_regs* regs)
+{
+	unsigned char ipl_emu, mask;
+	unsigned int level;
+
+	APUS_READ(APUS_IPL_EMU, ipl_emu);
+	level = (ipl_emu >> 3) & IPLEMU_IPLMASK;
+	mask = IPLEMU_SETRESET|IPLEMU_DISABLEINT|level;
+	level ^= 7;
+
+	/* Save previous IPL value */
+	if (last_ipl[level])
+		return -2;
+	last_ipl[level] = ipl_emu;
+
+	/* Set to current IPL value */
+	APUS_WRITE(APUS_IPL_EMU, mask);
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT|level);
+
+
+#ifdef __INTERRUPT_DEBUG
+	printk("<%d:%d>", level, ~ipl_emu & IPLEMU_IPLMASK);
+#endif
+	return level + IRQ_AMIGA_AUTO;
+}
+
+void apus_end_irq(unsigned int irq)
+{
+	unsigned char ipl_emu;
+	unsigned int level = irq - IRQ_AMIGA_AUTO;
+#ifdef __INTERRUPT_DEBUG
+	printk("{%d}", ~last_ipl[level] & IPLEMU_IPLMASK);
+#endif
+	/* Restore IPL to the previous value */
+	ipl_emu = last_ipl[level] & IPLEMU_IPLMASK;
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET|IPLEMU_DISABLEINT|ipl_emu);
+	last_ipl[level] = 0;
+	ipl_emu ^= 7;
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT|ipl_emu);
+}
+
+/****************************************************** keyboard */
+static int apus_kbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+	return -EOPNOTSUPP;
+}
+
+static int apus_kbd_getkeycode(unsigned int scancode)
+{
+	return scancode > 127 ? -EINVAL : scancode;
+}
+
+static char apus_kbd_unexpected_up(unsigned char keycode)
+{
+	return 0200;
+}
+
+static void apus_kbd_init_hw(void)
+{
+#ifdef CONFIG_APUS
+	extern int amiga_keyb_init(void);
+
+	amiga_keyb_init();
+#endif
+}
+
+
+/****************************************************** debugging */
+
+/* some serial hardware definitions */
+#define SDR_OVRUN   (1<<15)
+#define SDR_RBF     (1<<14)
+#define SDR_TBE     (1<<13)
+#define SDR_TSRE    (1<<12)
+
+#define AC_SETCLR   (1<<15)
+#define AC_UARTBRK  (1<<11)
+
+#define SER_DTR     (1<<7)
+#define SER_RTS     (1<<6)
+#define SER_DCD     (1<<5)
+#define SER_CTS     (1<<4)
+#define SER_DSR     (1<<3)
+
+static __inline__ void ser_RTSon(void)
+{
+    ciab.pra &= ~SER_RTS; /* active low */
+}
+
+int __debug_ser_out( unsigned char c )
+{
+	custom.serdat = c | 0x100;
+	mb();
+	while (!(custom.serdatr & 0x2000))
+		barrier();
+	return 1;
+}
+
+unsigned char __debug_ser_in( void )
+{
+	unsigned char c;
+
+	/* XXX: is that ok?? derived from amiga_ser.c... */
+	while( !(custom.intreqr & IF_RBF) )
+		barrier();
+	c = custom.serdatr;
+	/* clear the interrupt, so that another character can be read */
+	custom.intreq = IF_RBF;
+	return c;
+}
+
+int __debug_serinit( void )
+{
+	unsigned long flags;
+
+	save_flags (flags);
+	cli();
+
+	/* turn off Rx and Tx interrupts */
+	custom.intena = IF_RBF | IF_TBE;
+
+	/* clear any pending interrupt */
+	custom.intreq = IF_RBF | IF_TBE;
+
+	restore_flags (flags);
+
+	/*
+	 * set the appropriate directions for the modem control flags,
+	 * and clear RTS and DTR
+	 */
+	ciab.ddra |= (SER_DTR | SER_RTS);   /* outputs */
+	ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR);  /* inputs */
+
+#ifdef CONFIG_KGDB
+	/* turn Rx interrupts on for GDB */
+	custom.intena = IF_SETCLR | IF_RBF;
+	ser_RTSon();
+#endif
+
+	return 0;
+}
+
+void __debug_print_hex(unsigned long x)
+{
+	int i;
+	char hexchars[] = "0123456789ABCDEF";
+
+	for (i = 0; i < 8; i++) {
+		__debug_ser_out(hexchars[(x >> 28) & 15]);
+		x <<= 4;
+	}
+	__debug_ser_out('\n');
+	__debug_ser_out('\r');
+}
+
+void __debug_print_string(char* s)
+{
+	unsigned char c;
+	while((c = *s++))
+		__debug_ser_out(c);
+	__debug_ser_out('\n');
+	__debug_ser_out('\r');
+}
+
+static void apus_progress(char *s, unsigned short value)
+{
+	__debug_print_string(s);
+}
+
+/****************************************************** init */
+
+/* The number of spurious interrupts */
+volatile unsigned int num_spurious;
+
+extern struct irqaction amiga_sys_irqaction[AUTO_IRQS];
+
+
+extern void amiga_enable_irq(unsigned int irq);
+extern void amiga_disable_irq(unsigned int irq);
+
+struct hw_interrupt_type amiga_sys_irqctrl = {
+	typename: "Amiga IPL",
+	end: apus_end_irq,
+};
+
+struct hw_interrupt_type amiga_irqctrl = {
+	typename: "Amiga    ",
+	enable: amiga_enable_irq,
+	disable: amiga_disable_irq,
+};
+
+#define HARDWARE_MAPPED_SIZE (512*1024)
+unsigned long __init apus_find_end_of_memory(void)
+{
+	int shadow = 0;
+	unsigned long total;
+
+	/* The memory size reported by ADOS excludes the 512KB
+	   reserved for PPC exception registers and possibly 512KB
+	   containing a shadow of the ADOS ROM. */
+	{
+		unsigned long size = memory[0].size;
+
+		/* If 2MB aligned, size was probably user
+                   specified. We can't tell anything about shadowing
+                   in this case so skip shadow assignment. */
+		if (0 != (size & 0x1fffff)){
+			/* Align to 512KB to ensure correct handling
+			   of both memfile and system specified
+			   sizes. */
+			size = ((size+0x0007ffff) & 0xfff80000);
+			/* If memory is 1MB aligned, assume
+                           shadowing. */
+			shadow = !(size & 0x80000);
+		}
+
+		/* Add the chunk that ADOS does not see. by aligning
+                   the size to the nearest 2MB limit upwards.  */
+		memory[0].size = ((size+0x001fffff) & 0xffe00000);
+	}
+
+	total = memory[0].size;
+
+	/* Remove the memory chunks that are controlled by special
+           Phase5 hardware. */
+
+	/* Remove the upper 512KB if it contains a shadow of
+	   the ADOS ROM. FIXME: It might be possible to
+	   disable this shadow HW. Check the booter
+	   (ppc_boot.c) */
+	if (shadow)
+		total -= HARDWARE_MAPPED_SIZE;
+
+	/* Remove the upper 512KB where the PPC exception
+	   vectors are mapped. */
+	total -= HARDWARE_MAPPED_SIZE;
+
+	/* Linux/APUS only handles one block of memory -- the one on
+	   the PowerUP board. Other system memory is horrible slow in
+	   comparison. The user can use other memory for swapping
+	   using the z2ram device. */
+	ram_phys_base = memory[0].addr;
+	return total;
+}
+
+static void __init
+apus_map_io(void)
+{
+	/* Map PPC exception vectors. */
+	io_block_mapping(0xfff00000, 0xfff00000, 0x00020000, _PAGE_KERNEL);
+	/* Map chip and ZorroII memory */
+	io_block_mapping(zTwoBase,   0x00000000, 0x01000000, _PAGE_IO);
+}
+
+__init
+void apus_init_IRQ(void)
+{
+	struct irqaction *action;
+	int i;
+
+#ifdef CONFIG_PCI
+        apus_setup_pci_ptrs();
+#endif
+
+	for ( i = 0 ; i < AMI_IRQS; i++ ) {
+		irq_desc[i].status = IRQ_LEVEL;
+		if (i < IRQ_AMIGA_AUTO) {
+			irq_desc[i].handler = &amiga_irqctrl;
+		} else {
+			irq_desc[i].handler = &amiga_sys_irqctrl;
+			action = &amiga_sys_irqaction[i-IRQ_AMIGA_AUTO];
+			if (action->name)
+				setup_irq(i, action);
+		}
+	}
+
+	amiga_init_IRQ();
+
+}
+
+__init
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+		   unsigned long r6, unsigned long r7)
+{
+	extern int parse_bootinfo(const struct bi_record *);
+	extern char _end[];
+
+	/* Parse bootinfo. The bootinfo is located right after
+           the kernel bss */
+	parse_bootinfo((const struct bi_record *)&_end);
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* Take care of initrd if we have one. Use data from
+	   bootinfo to avoid the need to initialize PPC
+	   registers when kernel is booted via a PPC reset. */
+	if ( ramdisk.addr ) {
+		initrd_start = (unsigned long) __va(ramdisk.addr);
+		initrd_end = (unsigned long)
+			__va(ramdisk.size + ramdisk.addr);
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	ISA_DMA_THRESHOLD = 0x00ffffff;
+
+	ppc_md.setup_arch     = apus_setup_arch;
+	ppc_md.show_cpuinfo   = apus_show_cpuinfo;
+	ppc_md.init_IRQ       = apus_init_IRQ;
+	ppc_md.get_irq        = apus_get_irq;
+
+#ifdef CONFIG_HEARTBEAT
+	ppc_md.heartbeat      = apus_heartbeat;
+	heartbeat_reset(0)    = 1;		/* assume UP for now */
+	heartbeat_count(0)    = 1;
+#endif
+#ifdef APUS_DEBUG
+	__debug_serinit();
+	ppc_md.progress       = apus_progress;
+#endif
+	ppc_md.init           = NULL;
+
+	ppc_md.restart        = apus_restart;
+	ppc_md.power_off      = apus_power_off;
+	ppc_md.halt           = apus_halt;
+
+	ppc_md.time_init      = NULL;
+	ppc_md.set_rtc_time   = apus_set_rtc_time;
+	ppc_md.get_rtc_time   = apus_get_rtc_time;
+	ppc_md.calibrate_decr = apus_calibrate_decr;
+
+	ppc_md.find_end_of_memory = apus_find_end_of_memory;
+	ppc_md.setup_io_mappings = apus_map_io;
+
+	/* These should not be used for the APUS yet, since it uses
+	   the M68K keyboard now. */
+	ppc_md.kbd_setkeycode    = apus_kbd_setkeycode;
+	ppc_md.kbd_getkeycode    = apus_kbd_getkeycode;
+	ppc_md.kbd_translate     = amiga_kbd_translate;
+	ppc_md.kbd_unexpected_up = apus_kbd_unexpected_up;
+	ppc_md.kbd_init_hw       = apus_kbd_init_hw;
+#ifdef CONFIG_SYSRQ
+	ppc_md.ppc_kbd_sysrq_xlate = amiga_sysrq_xlate;
+	SYSRQ_KEY                = 0xff;
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/bseip.h linux-2.4.20/arch/ppc/platforms/bseip.h
--- linux-2.4.19/arch/ppc/platforms/bseip.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/bseip.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,42 @@
+/*
+ * BK Id: SCCS/s.bseip.h 1.10 08/17/01 15:23:17 paulus
+ */
+
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Bright Star Engineering ip-Engine board.  Copied from the MBX stuff.
+ *
+ * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
+ */
+#ifndef __MACH_BSEIP_DEFS
+#define __MACH_BSEIP_DEFS
+
+#ifndef __ASSEMBLY__
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+	unsigned int	bi_memstart;	/* Memory start address */
+	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
+	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
+	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
+	unsigned char	bi_enetaddr[6];
+	unsigned int	bi_baudrate;
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
+/* Memory map is configured by the PROM startup.
+ * All we need to get started is the IMMR.
+ */
+#define IMAP_ADDR		((uint)0xff000000)
+#define IMAP_SIZE		((uint)(64 * 1024))
+#define PCMCIA_MEM_ADDR		((uint)0x04000000)
+#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
+#endif	/* !__ASSEMBLY__ */
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS	0
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/chrp_pci.c linux-2.4.20/arch/ppc/platforms/chrp_pci.c
--- linux-2.4.19/arch/ppc/platforms/chrp_pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/chrp_pci.c	2002-10-29 11:18:51.000000000 +0000
@@ -0,0 +1,322 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * CHRP pci routines.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/bootmem.h>
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/hydra.h>
+#include <asm/prom.h>
+#include <asm/gg2.h>
+#include <asm/machdep.h>
+#include <asm/sections.h>
+#include <asm/pci-bridge.h>
+#include <asm/open_pic.h>
+
+/* LongTrail */
+unsigned long gg2_pci_config_base;
+
+#define pci_config_addr(dev, offset) \
+(gg2_pci_config_base | ((dev->bus->number)<<16) | ((dev->devfn)<<8) | (offset))
+
+volatile struct Hydra *Hydra = NULL;
+
+/*
+ * The VLSI Golden Gate II has only 512K of PCI configuration space, so we
+ * limit the bus number to 3 bits
+ */
+
+#define cfg_read(val, addr, type, op)	*val = op((type)(addr))
+#define cfg_write(val, addr, type, op)	op((type *)(addr), (val))
+
+#define cfg_read_bad(val, size)		*val = bad_##size;
+#define cfg_write_bad(val, size)
+
+#define bad_byte	0xff
+#define bad_word	0xffff
+#define bad_dword	0xffffffffU
+
+#define GG2_PCI_OP(rw, size, type, op)					    \
+int __chrp gg2_##rw##_config_##size(struct pci_dev *dev, int off, type val) \
+{									    \
+	if (dev->bus->number > 7) {					    \
+		cfg_##rw##_bad(val, size)				    \
+		return PCIBIOS_DEVICE_NOT_FOUND;			    \
+	}								    \
+	cfg_##rw(val, pci_config_addr(dev, off), type, op);		    \
+	return PCIBIOS_SUCCESSFUL;					    \
+}
+
+GG2_PCI_OP(read, byte, u8 *, in_8)
+GG2_PCI_OP(read, word, u16 *, in_le16)
+GG2_PCI_OP(read, dword, u32 *, in_le32)
+GG2_PCI_OP(write, byte, u8, out_8)
+GG2_PCI_OP(write, word, u16, out_le16)
+GG2_PCI_OP(write, dword, u32, out_le32)
+
+static struct pci_ops gg2_pci_ops =
+{
+	gg2_read_config_byte,
+	gg2_read_config_word,
+	gg2_read_config_dword,
+	gg2_write_config_byte,
+	gg2_write_config_word,
+	gg2_write_config_dword
+};
+
+/*
+ * Access functions for PCI config space on IBM "python" host bridges.
+ */
+#define PYTHON_CFA(b, d, o)	(0x80 | ((b) << 8) | ((d) << 16) \
+				 | (((o) & ~3) << 24))
+
+#define PYTHON_PCI_OP(rw, size, type, op, mask)			    	     \
+int __chrp								     \
+python_##rw##_config_##size(struct pci_dev *dev, int offset, type val) 	     \
+{									     \
+	struct pci_controller *hose = dev->sysdata;			     \
+									     \
+	out_be32(hose->cfg_addr,					     \
+		 PYTHON_CFA(dev->bus->number, dev->devfn, offset));	     \
+	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);   	     \
+	return PCIBIOS_SUCCESSFUL;					     \
+}
+
+PYTHON_PCI_OP(read, byte, u8 *, in_8, 3)
+PYTHON_PCI_OP(read, word, u16 *, in_le16, 2)
+PYTHON_PCI_OP(read, dword, u32 *, in_le32, 0)
+PYTHON_PCI_OP(write, byte, u8, out_8, 3)
+PYTHON_PCI_OP(write, word, u16, out_le16, 2)
+PYTHON_PCI_OP(write, dword, u32, out_le32, 0)
+
+static struct pci_ops python_pci_ops =
+{
+	python_read_config_byte,
+	python_read_config_word,
+	python_read_config_dword,
+	python_write_config_byte,
+	python_write_config_word,
+	python_write_config_dword
+};
+
+/*
+ * Access functions for PCI config space using RTAS calls.
+ */
+#define RTAS_PCI_READ_OP(size, type, nbytes)			    	  \
+int __chrp								  \
+rtas_read_config_##size(struct pci_dev *dev, int offset, type val) 	  \
+{									  \
+	unsigned long addr = (offset & 0xff) | ((dev->devfn & 0xff) << 8) \
+		| ((dev->bus->number & 0xff) << 16);			  \
+	unsigned long ret = ~0UL;					  \
+	int rval;							  \
+									  \
+	rval = call_rtas("read-pci-config", 2, 2, &ret, addr, nbytes);	  \
+	*val = ret;							  \
+	return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL;    	  \
+}
+
+#define RTAS_PCI_WRITE_OP(size, type, nbytes)				  \
+int __chrp								  \
+rtas_write_config_##size(struct pci_dev *dev, int offset, type val)	  \
+{									  \
+	unsigned long addr = (offset & 0xff) | ((dev->devfn & 0xff) << 8) \
+		| ((dev->bus->number & 0xff) << 16);			  \
+	int rval;							  \
+									  \
+	rval = call_rtas("write-pci-config", 3, 1, NULL,		  \
+			 addr, nbytes, (ulong)val);			  \
+	return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL;	  \
+}
+
+RTAS_PCI_READ_OP(byte, u8 *, 1)
+RTAS_PCI_READ_OP(word, u16 *, 2)
+RTAS_PCI_READ_OP(dword, u32 *, 4)
+RTAS_PCI_WRITE_OP(byte, u8, 1)
+RTAS_PCI_WRITE_OP(word, u16, 2)
+RTAS_PCI_WRITE_OP(dword, u32, 4)
+
+static struct pci_ops rtas_pci_ops =
+{
+	rtas_read_config_byte,
+	rtas_read_config_word,
+	rtas_read_config_dword,
+	rtas_write_config_byte,
+	rtas_write_config_word,
+	rtas_write_config_dword
+};
+
+int __init
+hydra_init(void)
+{
+	struct device_node *np;
+
+	np = find_devices("mac-io");
+	if (np == NULL || np->n_addrs == 0)
+		return 0;
+	Hydra = ioremap(np->addrs[0].address, np->addrs[0].size);
+	printk("Hydra Mac I/O at %x\n", np->addrs[0].address);
+	out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN |
+					   HYDRA_FC_SCSI_CELL_EN |
+					   HYDRA_FC_SCCA_ENABLE |
+					   HYDRA_FC_SCCB_ENABLE |
+					   HYDRA_FC_ARB_BYPASS |
+					   HYDRA_FC_MPIC_ENABLE |
+					   HYDRA_FC_SLOW_SCC_PCLK |
+					   HYDRA_FC_MPIC_IS_MASTER));
+	return 1;
+}
+
+void __init
+chrp_pcibios_fixup(void)
+{
+	struct pci_dev *dev;
+	struct device_node *np;
+
+	/* PCI interrupts are controlled by the OpenPIC */
+	pci_for_each_dev(dev) {
+		np = pci_device_to_OF_node(dev);
+		if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0))
+			dev->irq = np->intrs[0].line;
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+	}
+}
+
+#define PRG_CL_RESET_VALID 0x00010000
+
+static void __init
+setup_python(struct pci_controller *hose, struct device_node *dev)
+{
+	u32 *reg, val;
+	volatile unsigned char *cfg;
+
+	hose->ops = &python_pci_ops;
+	cfg = ioremap(dev->addrs[0].address + 0xf8000, 0x20);
+	hose->cfg_addr = (volatile unsigned int *) cfg;
+	hose->cfg_data = cfg + 0x10;
+
+	/* Clear the magic go-slow bit */
+	reg = (u32 *) ioremap(dev->addrs[0].address + 0xf6000, 0x40);
+	val = in_be32(&reg[12]);
+	if (val & PRG_CL_RESET_VALID) {
+		out_be32(&reg[12], val & ~PRG_CL_RESET_VALID);
+		in_be32(&reg[12]);
+	}
+	iounmap(reg);
+}
+
+void __init
+chrp_find_bridges(void)
+{
+	struct device_node *dev;
+	int *bus_range;
+	int len, index = -1;
+	struct pci_controller *hose;
+	unsigned int *dma;
+	char *model, *machine;
+	int is_longtrail = 0, is_mot = 0;
+	struct device_node *root = find_path_device("/");
+
+	/*
+	 * The PCI host bridge nodes on some machines don't have
+	 * properties to adequately identify them, so we have to
+	 * look at what sort of machine this is as well.
+	 */
+	machine = get_property(root, "model", NULL);
+	if (machine != NULL) {
+		is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0;
+		is_mot = strncmp(machine, "MOT", 3) == 0;
+	}
+	for (dev = root->child; dev != NULL; dev = dev->sibling) {
+		if (dev->type == NULL || strcmp(dev->type, "pci") != 0)
+			continue;
+		++index;
+		/* The GG2 bridge on the LongTrail doesn't have an address */
+		if (dev->n_addrs < 1 && !is_longtrail) {
+			printk(KERN_WARNING "Can't use %s: no address\n",
+			       dev->full_name);
+			continue;
+		}
+		bus_range = (int *) get_property(dev, "bus-range", &len);
+		if (bus_range == NULL || len < 2 * sizeof(int)) {
+			printk(KERN_WARNING "Can't get bus-range for %s\n",
+				dev->full_name);
+			continue;
+		}
+		if (bus_range[1] == bus_range[0])
+			printk(KERN_INFO "PCI bus %d", bus_range[0]);
+		else
+			printk(KERN_INFO "PCI buses %d..%d",
+			       bus_range[0], bus_range[1]);
+		printk(" controlled by %s", dev->type);
+		if (dev->n_addrs > 0)
+			printk(" at %x", dev->addrs[0].address);
+		printk("\n");
+
+		hose = pcibios_alloc_controller();
+		if (!hose) {
+			printk("Can't allocate PCI controller structure for %s\n",
+				dev->full_name);
+			continue;
+		}
+		hose->arch_data = dev;
+		hose->first_busno = bus_range[0];
+		hose->last_busno = bus_range[1];
+
+		model = get_property(dev, "model", NULL);
+		if (model == NULL)
+			model = "<none>";
+		if (device_is_compatible(dev, "IBM,python")) {
+			setup_python(hose, dev);
+		} else if (is_mot
+			   || strncmp(model, "Motorola, Grackle", 17) == 0) {
+			setup_grackle(hose);
+		} else if (is_longtrail) {
+			hose->ops = &gg2_pci_ops;
+			gg2_pci_config_base = (unsigned long)
+				ioremap(GG2_PCI_CONFIG_BASE, 0x80000);
+		} else if (!strncmp(model, "IBM,CPC710", 10)) {
+			setup_indirect_pci(hose,
+				dev->addrs[0].address + 0x000f8000,
+				dev->addrs[0].address + 0x000f8010);
+			if (index == 0) {
+				dma = (unsigned int *)
+					get_property(dev, "system-dma-base", &len);
+			 	if (dma && len >= sizeof(*dma)) {
+					dma = (unsigned int *)(((unsigned long)dma) +
+						len - sizeof(*dma));
+					pci_dram_offset = *dma;
+				}
+			}
+		} else {
+			printk("No methods for %s (model %s), using RTAS\n",
+			       dev->full_name, model);
+			hose->ops = &rtas_pci_ops;
+		}
+
+		pci_process_bridge_OF_ranges(hose, dev, index == 0);
+
+		/* check the first bridge for a property that we can
+		   use to set pci_dram_offset */
+		dma = (unsigned int *)
+			get_property(dev, "ibm,dma-ranges", &len);
+		if (index == 0 && dma != NULL && len >= 6 * sizeof(*dma)) {
+			pci_dram_offset = dma[2] - dma[3];
+			printk("pci_dram_offset = %lx\n", pci_dram_offset);
+		}
+	}
+
+	ppc_md.pcibios_fixup = chrp_pcibios_fixup;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/chrp_setup.c linux-2.4.20/arch/ppc/platforms/chrp_setup.c
--- linux-2.4.19/arch/ppc/platforms/chrp_setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/chrp_setup.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,713 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/platforms/setup.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/version.h>
+#include <linux/adb.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/irq.h>
+#include <linux/console.h>
+#include <linux/seq_file.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/prom.h>
+#include <asm/gg2.h>
+#include <asm/pci-bridge.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/hydra.h>
+#include <asm/keyboard.h>
+#include <asm/sections.h>
+#include <asm/time.h>
+#include <asm/btext.h>
+#include <asm/i8259.h>
+#include <asm/open_pic.h>
+
+unsigned long chrp_get_rtc_time(void);
+int chrp_set_rtc_time(unsigned long nowtime);
+void chrp_calibrate_decr(void);
+long chrp_time_init(void);
+
+void chrp_find_bridges(void);
+void chrp_event_scan(void);
+void rtas_display_progress(char *, unsigned short);
+void rtas_indicator_progress(char *, unsigned short);
+void btext_progress(char *, unsigned short);
+
+extern unsigned long pmac_find_end_of_memory(void);
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
+extern void select_adb_keyboard(void);
+extern int of_show_percpuinfo(struct seq_file *, int);
+
+extern kdev_t boot_dev;
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern int probingmem;
+extern unsigned long loops_per_jiffy;
+static int max_width;
+static int is_briq;
+unsigned int* briq_SPOR; /* To be replaced by RTAS when available */
+
+#ifdef CONFIG_SMP
+extern struct smp_ops_t chrp_smp_ops;
+#endif
+
+static const char *gg2_memtypes[4] = {
+	"FPM", "SDRAM", "EDO", "BEDO"
+};
+static const char *gg2_cachesizes[4] = {
+	"256 KB", "512 KB", "1 MB", "Reserved"
+};
+static const char *gg2_cachetypes[4] = {
+	"Asynchronous", "Reserved", "Flow-Through Synchronous",
+	"Pipelined Synchronous"
+};
+static const char *gg2_cachemodes[4] = {
+	"Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
+};
+
+int __chrp
+chrp_show_cpuinfo(struct seq_file *m)
+{
+	int i, sdramen;
+	unsigned int t;
+	struct device_node *root;
+	const char *model = "";
+
+	root = find_path_device("/");
+	if (root)
+		model = get_property(root, "model", NULL);
+	seq_printf(m, "machine\t\t: CHRP %s\n", model);
+
+	/* longtrail (goldengate) stuff */
+	if (!strncmp(model, "IBM,LongTrail", 13)) {
+		/* VLSI VAS96011/12 `Golden Gate 2' */
+		/* Memory banks */
+		sdramen = (in_le32((unsigned *)(gg2_pci_config_base+
+						GG2_PCI_DRAM_CTRL))
+			   >>31) & 1;
+		for (i = 0; i < (sdramen ? 4 : 6); i++) {
+			t = in_le32((unsigned *)(gg2_pci_config_base+
+						 GG2_PCI_DRAM_BANK0+
+						 i*4));
+			if (!(t & 1))
+				continue;
+			switch ((t>>8) & 0x1f) {
+			case 0x1f:
+				model = "4 MB";
+				break;
+			case 0x1e:
+				model = "8 MB";
+				break;
+			case 0x1c:
+				model = "16 MB";
+				break;
+			case 0x18:
+				model = "32 MB";
+				break;
+			case 0x10:
+				model = "64 MB";
+				break;
+			case 0x00:
+				model = "128 MB";
+				break;
+			default:
+				model = "Reserved";
+				break;
+			}
+			seq_printf(m, "memory bank %d\t: %s %s\n", i, model,
+				   gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]);
+		}
+		/* L2 cache */
+		t = in_le32((unsigned *)(gg2_pci_config_base+GG2_PCI_CC_CTRL));
+		seq_printf(m, "board l2\t: %s %s (%s)\n",
+			   gg2_cachesizes[(t>>7) & 3],
+			   gg2_cachetypes[(t>>2) & 3],
+			   gg2_cachemodes[t & 3]);
+	}
+	return 0;
+}
+
+/*
+ *  Fixes for the National Semiconductor PC78308VUL SuperI/O
+ *
+ *  Some versions of Open Firmware incorrectly initialize the IRQ settings
+ *  for keyboard and mouse
+ */
+static inline void __init sio_write(u8 val, u8 index)
+{
+	outb(index, 0x15c);
+	outb(val, 0x15d);
+}
+
+static inline u8 __init sio_read(u8 index)
+{
+	outb(index, 0x15c);
+	return inb(0x15d);
+}
+
+static void __init sio_fixup_irq(const char *name, u8 device, u8 level,
+				     u8 type)
+{
+	u8 level0, type0, active;
+
+	/* select logical device */
+	sio_write(device, 0x07);
+	active = sio_read(0x30);
+	level0 = sio_read(0x70);
+	type0 = sio_read(0x71);
+	if (level0 != level || type0 != type || !active) {
+		printk(KERN_WARNING "sio: %s irq level %d, type %d, %sactive: "
+		       "remapping to level %d, type %d, active\n",
+		       name, level0, type0, !active ? "in" : "", level, type);
+		sio_write(0x01, 0x30);
+		sio_write(level, 0x70);
+		sio_write(type, 0x71);
+	}
+}
+
+static void __init sio_init(void)
+{
+	struct device_node *root;
+
+	if ((root = find_path_device("/")) &&
+	    !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) {
+		/* logical device 0 (KBC/Keyboard) */
+		sio_fixup_irq("keyboard", 0, 1, 2);
+		/* select logical device 1 (KBC/Mouse) */
+		sio_fixup_irq("mouse", 1, 12, 2);
+	}
+}
+
+
+void __init
+chrp_setup_arch(void)
+{
+	struct device_node *device;
+
+	/* init to some ~sane value until calibrate_delay() runs */
+	loops_per_jiffy = 50000000/HZ;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* this is fine for chrp */
+	initrd_below_start_ok = 1;
+	
+	if (initrd_start)
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+	else
+#endif
+		ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */
+
+	/* Lookup PCI host bridges */
+	chrp_find_bridges();
+
+#ifndef CONFIG_PPC64BRIDGE
+	/*
+	 *  Temporary fixes for PCI devices.
+	 *  -- Geert
+	 */
+	hydra_init();		/* Mac I/O */
+
+#endif /* CONFIG_PPC64BRIDGE */
+
+	/*
+	 *  Fix the Super I/O configuration
+	 */
+	sio_init();
+
+	/*
+	 *  Setup the console operations
+	 */
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+
+	/* Get the event scan rate for the rtas so we know how
+	 * often it expects a heartbeat. -- Cort
+	 */
+	if (rtas_data) {
+		struct property *p;
+		unsigned long rate, count;
+		device = find_devices("rtas");
+		for ( p = device->properties;
+		      p && strncmp(p->name, "rtas-event-scan-rate", 20);
+		      p = p->next )
+			/* nothing */ ;
+		if (p && (rate = *(unsigned long *)p->value) > 0) {
+			/*
+			 * The value is the number of times per minute.
+			 * For now assign the full workload here to cpu 0.  
+			 *
+			 * We now split the rate and spread the heartbeats
+			 * when we kick secondary cpus so we can spread
+			 * the calls evenly.   
+			 */
+			ppc_md.heartbeat = chrp_event_scan;
+			
+			count = (60*HZ) / rate;
+			if (!count)        /* XXX insane */
+				count = 1;
+
+			heartbeat_reset(0) = count;
+			heartbeat_count(0) = 1;
+
+			printk("RTAS Event Scan Rate: %lu calls/minute "
+			       "(every %lu jiffies)\n", rate, count );
+		}
+	}
+
+	pci_create_OF_bus_map();
+}
+
+void __chrp
+chrp_event_scan(void)
+{
+	unsigned char log[1024];
+	unsigned long ret = 0;
+	/* XXX: we should loop until the hardware says no more error logs -- Cort */
+	call_rtas( "event-scan", 4, 1, &ret, 0xffffffff, 0,
+		   __pa(log), 1024 );
+}
+	
+void __chrp
+chrp_restart(char *cmd)
+{
+	printk("RTAS system-reboot returned %d\n",
+	       call_rtas("system-reboot", 0, 1, NULL));
+	for (;;);
+}
+
+void __chrp
+chrp_power_off(void)
+{
+	/* allow power on only with power button press */
+	printk("RTAS power-off returned %d\n",
+	       call_rtas("power-off", 2, 1, NULL,0xffffffff,0xffffffff));
+	for (;;);
+}
+
+void __chrp
+chrp_halt(void)
+{
+	chrp_power_off();
+}
+
+u_int __chrp
+chrp_irq_cannonicalize(u_int irq)
+{
+	if (irq == 2)
+		return 9;
+	return irq;
+}
+
+static void __chrp
+briq_restart(char *cmd)
+{
+	cli();
+	if (briq_SPOR)
+		out_be32(briq_SPOR, 0);
+	for(;;) ;
+}
+
+/*
+ * Finds the open-pic node and sets OpenPIC_Addr based on its reg property.
+ * Then checks if it has an interrupt-ranges property.  If it does then
+ * we have a distributed open-pic, so call openpic_set_sources to tell
+ * the openpic code where to find the interrupt source registers.
+ */
+static void __init chrp_find_openpic(void)
+{
+	struct device_node *np;
+	int len, i;
+	unsigned int *iranges;
+	void *isu;
+
+	np = find_type_devices("open-pic");
+	if (np == NULL || np->n_addrs == 0)
+		return;
+	printk(KERN_INFO "OpenPIC at %x (size %x)\n",
+	       np->addrs[0].address, np->addrs[0].size);
+	OpenPIC_Addr = ioremap(np->addrs[0].address, 0x40000);
+	if (OpenPIC_Addr == NULL) {
+		printk(KERN_ERR "Failed to map OpenPIC!\n");
+		return;
+	}
+
+	iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len);
+	if (iranges == NULL || len < 2 * sizeof(unsigned int))
+		return;		/* not distributed */
+
+	/*
+	 * The first pair of cells in interrupt-ranges refers to the
+	 * IDU; subsequent pairs refer to the ISUs.
+	 */
+	len /= 2 * sizeof(unsigned int);
+	if (np->n_addrs < len) {
+		printk(KERN_ERR "Insufficient addresses for distributed"
+		       " OpenPIC (%d < %d)\n", np->n_addrs, len);
+		return;
+	}
+	if (iranges[1] != 0) {
+		printk(KERN_INFO "OpenPIC irqs %d..%d in IDU\n",
+		       iranges[0], iranges[0] + iranges[1] - 1);
+		openpic_set_sources(iranges[0], iranges[1], NULL);
+	}
+	for (i = 1; i < len; ++i) {
+		iranges += 2;
+		printk(KERN_INFO "OpenPIC irqs %d..%d in ISU at %x (%x)\n",
+		       iranges[0], iranges[0] + iranges[1] - 1,
+		       np->addrs[i].address, np->addrs[i].size);
+		isu = ioremap(np->addrs[i].address, np->addrs[i].size);
+		if (isu != NULL)
+			openpic_set_sources(iranges[0], iranges[1], isu);
+		else
+			printk(KERN_ERR "Failed to map OpenPIC ISU at %x!\n",
+			       np->addrs[i].address);
+	}
+}
+
+static void __init
+chrp_init_irq_openpic(unsigned long intack)
+{
+	int i;
+	unsigned char* chrp_int_ack_special = 0;
+	int nmi_irq = -1;
+	unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
+
+	chrp_find_openpic();
+
+	prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS);
+	OpenPIC_InitSenses = init_senses;
+	OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS;
+
+	if (intack)
+		chrp_int_ack_special = (unsigned char *) ioremap(intack, 1);
+	openpic_init(1, NUM_8259_INTERRUPTS, chrp_int_ack_special, nmi_irq);
+	for (i = 0; i < NUM_8259_INTERRUPTS; i++)
+		irq_desc[i].handler = &i8259_pic;
+	i8259_init(0);
+}
+
+static void __init
+chrp_init_irq_8259(unsigned long intack)
+{
+	int i;
+	
+	ppc_md.get_irq = i8259_irq;
+	for (i = 0; i < NUM_8259_INTERRUPTS; i++)
+		irq_desc[i].handler = &i8259_pic;
+	i8259_init(intack);
+}
+
+void __init chrp_init_IRQ(void)
+{
+	struct device_node *np;
+	unsigned long intack = 0;
+	struct device_node *main_irq_ctrler = NULL;
+#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)	
+	struct device_node *kbd;
+#endif
+
+	for (np = find_devices("pci"); np != NULL; np = np->next) {
+		unsigned int *addrp = (unsigned int *)
+			get_property(np, "8259-interrupt-acknowledge", NULL);
+		if (addrp == NULL)
+			continue;
+		intack = addrp[prom_n_addr_cells(np)-1];
+		break;
+	}
+	if (np == NULL)
+		printk("Cannot find pci to get ack address\n");
+
+	/* Look for the node of the toplevel interrupt controller.
+	 * If we don't find it, we assume openpic
+	 */
+	np = find_path_device("/chosen");
+	if (np) {
+		phandle *irq_ctrler_ph =
+			(phandle *)get_property(np, "interrupt-controller", NULL);
+		if (irq_ctrler_ph)
+			main_irq_ctrler = find_phandle(*irq_ctrler_ph);
+	}
+
+	if (main_irq_ctrler && device_is_compatible(main_irq_ctrler, "8259"))
+		chrp_init_irq_8259(intack);
+	else
+		chrp_init_irq_openpic(intack);
+
+#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)
+	/* see if there is a keyboard in the device tree
+	   with a parent of type "adb" */
+	for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next)
+		if (kbd->parent && kbd->parent->type
+		    && strcmp(kbd->parent->type, "adb") == 0)
+			break;
+	if (kbd)
+		request_irq(HYDRA_INT_ADB_NMI, xmon_irq, 0, "XMON break", 0);
+#endif
+}
+
+void __init
+chrp_init2(void)
+{
+ 
+	if (is_briq)
+		briq_SPOR = (unsigned int *)ioremap(0xff0000e8, 4);
+#ifdef CONFIG_NVRAM  
+/* Fix me: currently, a lot of pmac_nvram routines are marked __pmac, and
+ * blindly calling pmac_nvram_init() on chrp cause bad results.
+ * Among others, it cracks on briQ.
+ * Please implement a CHRP specific version. --BenH
+ */
+	if (!is_briq)
+		pmac_nvram_init();
+#endif
+	/* This is to be replaced by RTAS when available */
+
+	request_region(0x20,0x20,"pic1");
+	request_region(0xa0,0x20,"pic2");
+	request_region(0x00,0x20,"dma1");
+	request_region(0x40,0x20,"timer");
+	request_region(0x80,0x10,"dma page reg");
+	request_region(0xc0,0x20,"dma2");
+
+	if (ppc_md.progress)
+		ppc_md.progress("  Have fun!    ", 0x7777);
+
+#if defined(CONFIG_VT) && (defined(CONFIG_ADB_KEYBOARD) || defined(CONFIG_INPUT))
+	/* see if there is a keyboard in the device tree
+	   with a parent of type "adb" */
+	{
+		struct device_node *kbd;
+
+		for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next) {
+			if (kbd->parent && kbd->parent->type
+			    && strcmp(kbd->parent->type, "adb") == 0) {
+				select_adb_keyboard();
+				break;
+			}
+		}
+	}
+#endif /* CONFIG_VT && (CONFIG_ADB_KEYBOARD || CONFIG_INPUT) */
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+
+static int __chrp
+chrp_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+        return check_region(from, extent);
+}
+
+static void __chrp
+chrp_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+        request_region(from, extent, name);
+}
+
+static void __chrp
+chrp_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+        release_region(from, extent);
+}
+
+static void __chrp
+chrp_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+{
+	ide_ioreg_t reg = data_port;
+	int i;
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw->io_ports[i] = reg;
+		reg += 1;
+	}
+	hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+}
+#endif
+
+void __init
+chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	  unsigned long r6, unsigned long r7)
+{
+	struct device_node *root = find_path_device("/");
+	char *machine;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* take care of initrd if we have one */
+	if ( r6 )
+	{
+		initrd_start = r6 + KERNELBASE;
+		initrd_end = r6 + r7 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	ISA_DMA_THRESHOLD = ~0L;
+	DMA_MODE_READ = 0x44;
+	DMA_MODE_WRITE = 0x48;
+	isa_io_base = CHRP_ISA_IO_BASE;		/* default value */
+
+	/* Check if it's a briq */
+	machine = get_property(root, "model", NULL);
+	is_briq = machine && strncmp(machine, "TotalImpact,BRIQ-1", 18) == 0;
+
+	ppc_md.setup_arch     = chrp_setup_arch;
+	ppc_md.show_percpuinfo = of_show_percpuinfo;
+	ppc_md.show_cpuinfo   = chrp_show_cpuinfo;
+	ppc_md.irq_cannonicalize = chrp_irq_cannonicalize;
+	ppc_md.init_IRQ       = chrp_init_IRQ;
+	ppc_md.get_irq        = openpic_get_irq;
+
+	ppc_md.init           = chrp_init2;
+
+	ppc_md.restart        = is_briq ? briq_restart : chrp_restart;
+	ppc_md.power_off      = chrp_power_off;
+	ppc_md.halt           = chrp_halt;
+
+	ppc_md.time_init      = chrp_time_init;
+	ppc_md.set_rtc_time   = chrp_set_rtc_time;
+	ppc_md.get_rtc_time   = chrp_get_rtc_time;
+	ppc_md.calibrate_decr = chrp_calibrate_decr;
+
+	ppc_md.find_end_of_memory = pmac_find_end_of_memory;
+
+#ifdef CONFIG_VT
+	/* these are adjusted in chrp_init2 if we have an ADB keyboard */
+	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
+	ppc_md.kbd_translate     = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+	ppc_md.kbd_leds          = pckbd_leds;
+	ppc_md.kbd_init_hw       = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+	SYSRQ_KEY = 0x54;
+#endif /* CONFIG_MAGIC_SYSRQ */
+#endif /* CONFIG_VT */
+
+	if (rtas_data) {
+		struct device_node *rtas;
+		unsigned int *p;
+
+		rtas = find_devices("rtas");
+		if (rtas != NULL) {
+			if (get_property(rtas, "display-character", NULL)) {
+				ppc_md.progress = rtas_display_progress;
+				p = (unsigned int *) get_property
+				       (rtas, "ibm,display-line-length", NULL);
+				if (p)
+					max_width = *p;
+			} else if (get_property(rtas, "set-indicator", NULL))
+				ppc_md.progress = rtas_indicator_progress;
+		}
+	}
+#ifdef CONFIG_BOOTX_TEXT
+	if (ppc_md.progress == NULL && boot_text_mapped)
+		ppc_md.progress = btext_progress;
+#endif
+
+#ifdef CONFIG_SMP
+	ppc_md.smp_ops = &chrp_smp_ops;
+#endif /* CONFIG_SMP */
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+        ppc_ide_md.ide_check_region = chrp_ide_check_region;
+        ppc_ide_md.ide_request_region = chrp_ide_request_region;
+        ppc_ide_md.ide_release_region = chrp_ide_release_region;
+        ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports;
+#endif
+
+	/*
+	 * Print the banner, then scroll down so boot progress
+	 * can be printed.  -- Cort 
+	 */
+	if ( ppc_md.progress ) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0);
+}
+
+void __chrp
+rtas_display_progress(char *s, unsigned short hex)
+{
+	int width;
+	char *os = s;
+
+	if ( call_rtas( "display-character", 1, 1, NULL, '\r' ) )
+		return;
+
+	width = max_width;
+	while ( *os )
+	{
+		if ( (*os == '\n') || (*os == '\r') )
+			width = max_width;
+		else
+			width--;
+		call_rtas( "display-character", 1, 1, NULL, *os++ );
+		/* if we overwrite the screen length */
+		if ( width == 0 )
+			while ( (*os != 0) && (*os != '\n') && (*os != '\r') )
+				os++;
+	}
+
+	/*while ( width-- > 0 )*/
+	call_rtas( "display-character", 1, 1, NULL, ' ' );
+}
+
+void __chrp
+rtas_indicator_progress(char *s, unsigned short hex)
+{
+	call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex);
+}
+
+#ifdef CONFIG_BOOTX_TEXT
+void
+btext_progress(char *s, unsigned short hex)
+{
+	prom_print(s);
+	prom_print("\n");
+}
+#endif /* CONFIG_BOOTX_TEXT */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/chrp_smp.c linux-2.4.20/arch/ppc/platforms/chrp_smp.c
--- linux-2.4.19/arch/ppc/platforms/chrp_smp.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/chrp_smp.c	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,176 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * Smp support for CHRP machines.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
+ * deal of code from the sparc and intel versions.
+ *
+ * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/residual.h>
+#include <asm/time.h>
+#include <asm/open_pic.h>
+
+extern unsigned long smp_chrp_cpu_nr;
+
+/*
+ * The CHRP RTAS note on multiprocessor systems:
+ * "In a multiprocessor system, each processor should
+ * call event-scan periodically, not always the same
+ * one.  The event-scan function needs to be called a
+ * total of rtas-event-scan-rate times a minute"
+ * 
+ * We must call on each cpu in on a regular basis
+ * so that firmware can watch for cpu unique errors.
+ */
+static void spread_heartbeat(void)
+{
+	unsigned count = heartbeat_count(0);
+	unsigned offset = count;
+	int i;
+
+	if (!count || smp_chrp_cpu_nr < 2)
+		return;
+
+	count *=  smp_chrp_cpu_nr;
+
+	for (i = 0; i < smp_chrp_cpu_nr ; i++)
+	{
+		heartbeat_reset(i) = count;
+		heartbeat_count(i) = i * offset;
+	}
+	printk("RTAS Event Scan now every %u jiffes on each cpu\n", count);
+}
+
+static int __init
+smp_chrp_probe(void)
+{
+	if (smp_chrp_cpu_nr > 1)
+		openpic_request_IPIs();
+
+	return smp_chrp_cpu_nr;
+}
+
+static void __init
+smp_chrp_kick_cpu(int nr)
+{
+	*(unsigned long *)KERNELBASE = nr;
+	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
+}
+
+static void __init
+smp_chrp_setup_cpu(int cpu_nr)
+{
+	static atomic_t ready = ATOMIC_INIT(1);
+	static volatile int frozen = 0;
+
+	if (cpu_nr == 0) {
+		/* wait for all the others */
+		while (atomic_read(&ready) < smp_num_cpus)
+			barrier();
+		atomic_set(&ready, 1);
+		/* freeze the timebase */
+		call_rtas("freeze-time-base", 0, 1, NULL);
+		mb();
+		frozen = 1;
+		/* XXX assumes this is not a 601 */
+		set_tb(0, 0);
+		last_jiffy_stamp(0) = 0;
+		while (atomic_read(&ready) < smp_num_cpus)
+			barrier();
+		/* thaw the timebase again */
+		call_rtas("thaw-time-base", 0, 1, NULL);
+		mb();
+		frozen = 0;
+		smp_tb_synchronized = 1;
+	} else {
+		atomic_inc(&ready);
+		while (!frozen)
+			barrier();
+		set_tb(0, 0);
+		last_jiffy_stamp(0) = 0;
+		mb();
+		atomic_inc(&ready);
+		while (frozen)
+			barrier();
+	}
+
+	if (OpenPIC_Addr)
+		do_openpic_setup_cpu();
+}
+
+#ifdef CONFIG_POWER4
+static void __chrp
+smp_xics_message_pass(int target, int msg, unsigned long data, int wait)
+{
+	/* for now, only do reschedule messages
+	   since we only have one IPI */
+	if (msg != PPC_MSG_RESCHEDULE)
+		return;
+	for (i = 0; i < smp_num_cpus; ++i) {
+		if (target == MSG_ALL || target == i
+		    || (target == MSG_ALL_BUT_SELF
+			&& i != smp_processor_id()))
+			xics_cause_IPI(i);
+	}
+}
+
+static int __chrp
+smp_xics_probe(void)
+{
+	return smp_chrp_cpu_nr;
+}
+
+static void __chrp
+smp_xics_setup_cpu(int cpu_nr)
+{
+	if (cpu_nr > 0)
+		xics_setup_cpu();
+}
+#endif /* CONFIG_POWER4 */
+
+/* CHRP with openpic */
+struct smp_ops_t chrp_smp_ops __chrpdata = {
+	smp_openpic_message_pass,
+	smp_chrp_probe,
+	smp_chrp_kick_cpu,
+	smp_chrp_setup_cpu,
+};
+
+#ifdef CONFIG_POWER4
+/* CHRP with new XICS interrupt controller */
+struct smp_ops_t xics_smp_ops __chrpdata = {
+	smp_xics_message_pass,
+	smp_xics_probe,
+	smp_chrp_kick_cpu,
+	smp_xics_setup_cpu,
+};
+#endif /* CONFIG_POWER4 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/chrp_time.c linux-2.4.20/arch/ppc/platforms/chrp_time.c
--- linux-2.4.19/arch/ppc/platforms/chrp_time.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/chrp_time.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,195 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/platforms/chrp_time.c
+ *
+ *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *
+ * Adapted for PowerPC (PReP) by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu).
+ * Copied and modified from arch/i386/kernel/time.c
+ *
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+#include <linux/init.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/nvram.h>
+#include <asm/prom.h>
+#include <asm/sections.h>
+#include <asm/time.h>
+
+extern spinlock_t rtc_lock;
+
+static int nvram_as1 = NVRAM_AS1;
+static int nvram_as0 = NVRAM_AS0;
+static int nvram_data = NVRAM_DATA;
+
+long __init chrp_time_init(void)
+{
+	struct device_node *rtcs;
+	int base;
+
+	rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
+	if (rtcs == NULL || rtcs->addrs == NULL)
+		return 0;
+	base = rtcs->addrs[0].address;
+	nvram_as1 = 0;
+	nvram_as0 = base;
+	nvram_data = base + 1;
+
+	return 0;
+}
+
+int __chrp chrp_cmos_clock_read(int addr)
+{
+	if (nvram_as1 != 0)
+		outb(addr>>8, nvram_as1);
+	outb(addr, nvram_as0);
+	return (inb(nvram_data));
+}
+
+void __chrp chrp_cmos_clock_write(unsigned long val, int addr)
+{
+	if (nvram_as1 != 0)
+		outb(addr>>8, nvram_as1);
+	outb(addr, nvram_as0);
+	outb(val, nvram_data);
+	return;
+}
+
+/*
+ * Set the hardware clock. -- Cort
+ */
+int __chrp chrp_set_rtc_time(unsigned long nowtime)
+{
+	unsigned char save_control, save_freq_select;
+	struct rtc_time tm;
+
+	spin_lock(&rtc_lock);
+	to_tm(nowtime, &tm);
+
+	save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
+
+	chrp_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
+
+	save_freq_select = chrp_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+
+	chrp_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+        tm.tm_year -= 1900;
+	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BIN_TO_BCD(tm.tm_sec);
+		BIN_TO_BCD(tm.tm_min);
+		BIN_TO_BCD(tm.tm_hour);
+		BIN_TO_BCD(tm.tm_mon);
+		BIN_TO_BCD(tm.tm_mday);
+		BIN_TO_BCD(tm.tm_year);
+	}
+	chrp_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
+	chrp_cmos_clock_write(tm.tm_min,RTC_MINUTES);
+	chrp_cmos_clock_write(tm.tm_hour,RTC_HOURS);
+	chrp_cmos_clock_write(tm.tm_mon,RTC_MONTH);
+	chrp_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
+	chrp_cmos_clock_write(tm.tm_year,RTC_YEAR);
+
+	/* The following flags have to be released exactly in this order,
+	 * otherwise the DS12887 (popular MC146818A clone with integrated
+	 * battery and quartz) will not reset the oscillator and will not
+	 * update precisely 500 ms later. You won't find this mentioned in
+	 * the Dallas Semiconductor data sheets, but who believes data
+	 * sheets anyway ...                           -- Markus Kuhn
+	 */
+	chrp_cmos_clock_write(save_control, RTC_CONTROL);
+	chrp_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
+
+	if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
+		time_state = TIME_OK;
+	spin_unlock(&rtc_lock);
+	return 0;
+}
+
+unsigned long __chrp chrp_get_rtc_time(void)
+{
+	unsigned int year, mon, day, hour, min, sec;
+	int uip, i;
+
+	/* The Linux interpretation of the CMOS clock register contents:
+	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+	 * RTC registers show the second which has precisely just started.
+	 * Let's hope other operating systems interpret the RTC the same way.
+	 */
+
+	/* Since the UIP flag is set for about 2.2 ms and the clock
+	 * is typically written with a precision of 1 jiffy, trying
+	 * to obtain a precision better than a few milliseconds is 
+	 * an illusion. Only consistency is interesting, this also
+	 * allows to use the routine for /dev/rtc without a potential
+	 * 1 second kernel busy loop triggered by any reader of /dev/rtc. 
+	 */
+
+	for ( i = 0; i<1000000; i++) {
+		uip = chrp_cmos_clock_read(RTC_FREQ_SELECT);
+		sec = chrp_cmos_clock_read(RTC_SECONDS);
+		min = chrp_cmos_clock_read(RTC_MINUTES);
+		hour = chrp_cmos_clock_read(RTC_HOURS);
+		day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH);
+		mon = chrp_cmos_clock_read(RTC_MONTH);
+		year = chrp_cmos_clock_read(RTC_YEAR);
+		uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT);
+		if ((uip & RTC_UIP)==0) break;
+	}
+
+	if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+	  {
+	    BCD_TO_BIN(sec);
+	    BCD_TO_BIN(min);
+	    BCD_TO_BIN(hour);
+	    BCD_TO_BIN(day);
+	    BCD_TO_BIN(mon);
+	    BCD_TO_BIN(year);
+	  }
+	if ((year += 1900) < 1970)
+		year += 100;
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+
+void __init chrp_calibrate_decr(void)
+{
+	struct device_node *cpu;
+	unsigned int freq, *fp;
+
+	if (via_calibrate_decr())
+		return;
+
+	/*
+	 * The cpu node should have a timebase-frequency property
+	 * to tell us the rate at which the decrementer counts.
+	 */
+	freq = 16666000;		/* hardcoded default */
+	cpu = find_type_devices("cpu");
+	if (cpu != 0) {
+		fp = (unsigned int *)
+			get_property(cpu, "timebase-frequency", NULL);
+		if (fp != 0)
+			freq = *fp;
+	}
+	printk("time_init: decrementer frequency = %u.%.6u MHz\n",
+ 	       freq/1000000, freq%1000000);
+	tb_ticks_per_jiffy = freq / HZ;
+	tb_to_us = mulhwu_scale_factor(freq, 1000000);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/cpc700.h linux-2.4.20/arch/ppc/platforms/cpc700.h
--- linux-2.4.19/arch/ppc/platforms/cpc700.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/cpc700.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,109 @@
+/*
+ * include/asm-ppc/cpc700.h
+ * 
+ * Header file for IBM CPC700 Host Bridge, et. al.
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2000-2002 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.
+ */
+
+/*
+ * This file contains the defines and macros for the IBM CPC700 host bridge,
+ * memory controller, PIC, UARTs, IIC, and Timers.
+ */
+
+#ifndef	_ASMPPC_CPC700_H
+#define	_ASMPPC_CPC700_H
+
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <linux/init.h>
+
+#define CPC700_OUT_32(a,d)  (*(u_int *)a = d)
+#define CPC700_IN_32(a)     (*(u_int *)a)
+
+/*
+ * PCI Section
+ */
+#define CPC700_PCI_CONFIG_ADDR          0xfec00000
+#define CPC700_PCI_CONFIG_DATA          0xfec00004
+
+#define CPC700_PMM0_LOCAL		0xff400000
+#define CPC700_PMM0_MASK_ATTR		0xff400004
+#define CPC700_PMM0_PCI_LOW		0xff400008
+#define CPC700_PMM0_PCI_HIGH		0xff40000c
+#define CPC700_PMM1_LOCAL		0xff400010
+#define CPC700_PMM1_MASK_ATTR		0xff400014
+#define CPC700_PMM1_PCI_LOW		0xff400018
+#define CPC700_PMM1_PCI_HIGH		0xff40001c
+#define CPC700_PMM2_LOCAL		0xff400020
+#define CPC700_PMM2_MASK_ATTR		0xff400024
+#define CPC700_PMM2_PCI_LOW		0xff400028
+#define CPC700_PMM2_PCI_HIGH		0xff40002c
+#define CPC700_PTM1_MEMSIZE		0xff400030
+#define CPC700_PTM1_LOCAL		0xff400034
+#define CPC700_PTM2_MEMSIZE		0xff400038
+#define CPC700_PTM2_LOCAL		0xff40003c
+
+/*
+ * PIC Section
+ *
+ * IBM calls the CPC700's programmable interrupt controller the Universal
+ * Interrupt Controller or UIC.
+ */
+
+/*
+ * UIC Register Addresses.
+ */
+#define	CPC700_UIC_UICSR		0xff500880	/* Status Reg (Rd/Clr)*/
+#define	CPC700_UIC_UICSRS		0xff500884	/* Status Reg (Set) */
+#define	CPC700_UIC_UICER		0xff500888	/* Enable Reg */
+#define	CPC700_UIC_UICCR		0xff50088c	/* Critical Reg */
+#define	CPC700_UIC_UICPR		0xff500890	/* Polarity Reg */
+#define	CPC700_UIC_UICTR		0xff500894	/* Trigger Reg */
+#define	CPC700_UIC_UICMSR		0xff500898	/* Masked Status Reg */
+#define	CPC700_UIC_UICVR		0xff50089c	/* Vector Reg */
+#define	CPC700_UIC_UICVCR		0xff5008a0	/* Vector Config Reg */
+
+#define	CPC700_UIC_UICER_ENABLE		0x00000001	/* Enable an IRQ */
+
+#define	CPC700_UIC_UICVCR_31_HI		0x00000000	/* IRQ 31 hi priority */
+#define	CPC700_UIC_UICVCR_0_HI		0x00000001	/* IRQ 0 hi priority */
+#define CPC700_UIC_UICVCR_BASE_MASK	0xfffffffc
+#define CPC700_UIC_UICVCR_ORDER_MASK	0x00000001
+
+/* Specify value of a bit for an IRQ. */
+#define	CPC700_UIC_IRQ_BIT(i)		((0x00000001) << (31 - (i)))
+
+/*
+ * UIC Exports...
+ */
+extern struct hw_interrupt_type cpc700_pic;
+extern unsigned int cpc700_irq_assigns[32][2];
+ 
+extern void __init cpc700_init_IRQ(void);
+extern int cpc700_get_irq(struct pt_regs *);
+
+#endif	/* _ASMPPC_CPC700_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/cpc700_pic.c linux-2.4.20/arch/ppc/platforms/cpc700_pic.c
--- linux-2.4.19/arch/ppc/platforms/cpc700_pic.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/cpc700_pic.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,205 @@
+/*
+ * arch/ppc/platforms/cpc700_pic.c
+ * 
+ * Interrupt controller support for IBM Spruce
+ *
+ * Authors: Mark Greer, Matt Porter, and Johnnie Peters
+ *	    mgreer@mvista.com
+ *          mporter@mvista.com
+ *          jpeters@mvista.com
+ *
+ * Copyright 2001-2002 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.
+ */
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+
+#include "cpc700.h"
+
+static void
+cpc700_unmask_irq(unsigned int irq)
+{
+	unsigned int tr_bits;
+
+	/*
+	 * IRQ 31 is largest IRQ supported.
+	 * IRQs 17-19 are reserved.
+	 */
+	if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
+		tr_bits = CPC700_IN_32(CPC700_UIC_UICTR);
+
+		if ((tr_bits & (1 << (31 - irq))) == 0) {
+			/* level trigger interrupt, clear bit in status
+			 * register */
+			CPC700_OUT_32(CPC700_UIC_UICSR, 1 << (31 - irq));
+		}
+
+		/* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
+		ppc_cached_irq_mask[0] |= CPC700_UIC_IRQ_BIT(irq);
+		
+		CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
+	}
+	return;
+}
+
+static void
+cpc700_mask_irq(unsigned int irq)
+{
+	/*
+	 * IRQ 31 is largest IRQ supported.
+	 * IRQs 17-19 are reserved.
+	 */
+	if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
+		/* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
+		ppc_cached_irq_mask[0] &=
+			~CPC700_UIC_IRQ_BIT(irq);
+
+		CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
+	}
+	return;
+}
+
+static void
+cpc700_mask_and_ack_irq(unsigned int irq)
+{
+	u_int	bit;
+
+	/*
+	 * IRQ 31 is largest IRQ supported.
+	 * IRQs 17-19 are reserved.
+	 */
+	if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
+		/* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
+		bit = CPC700_UIC_IRQ_BIT(irq);
+
+		ppc_cached_irq_mask[0] &= ~bit;
+		CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
+		CPC700_OUT_32(CPC700_UIC_UICSR, bit); /* Write 1 clears IRQ */
+	}
+	return;
+}
+
+static struct hw_interrupt_type cpc700_pic = {
+	"CPC700 PIC",
+	NULL,
+	NULL,
+	cpc700_unmask_irq,
+	cpc700_mask_irq,
+	cpc700_mask_and_ack_irq,
+	NULL,
+	NULL
+};
+
+__init static void
+cpc700_pic_init_irq(unsigned int irq)
+{
+	unsigned int tmp;
+
+	/* Set interrupt sense */
+	tmp = CPC700_IN_32(CPC700_UIC_UICTR);
+	if (cpc700_irq_assigns[irq][0] == 0) {
+		tmp &= ~CPC700_UIC_IRQ_BIT(irq);
+	} else {
+		tmp |= CPC700_UIC_IRQ_BIT(irq);
+	}
+	CPC700_OUT_32(CPC700_UIC_UICTR, tmp);
+
+	/* Set interrupt polarity */
+	tmp = CPC700_IN_32(CPC700_UIC_UICPR);
+	if (cpc700_irq_assigns[irq][1]) {
+		tmp |= CPC700_UIC_IRQ_BIT(irq);
+	} else {
+		tmp &= ~CPC700_UIC_IRQ_BIT(irq);
+	}
+	CPC700_OUT_32(CPC700_UIC_UICPR, tmp);
+
+	/* Set interrupt critical */
+	tmp = CPC700_IN_32(CPC700_UIC_UICCR);
+	tmp |= CPC700_UIC_IRQ_BIT(irq);
+	CPC700_OUT_32(CPC700_UIC_UICCR, tmp);
+			
+	return;
+}
+	
+__init void
+cpc700_init_IRQ(void)
+{
+	int i;
+
+	ppc_cached_irq_mask[0] = 0;
+	CPC700_OUT_32(CPC700_UIC_UICER, 0x00000000);    /* Disable all irq's */
+	CPC700_OUT_32(CPC700_UIC_UICSR, 0xffffffff);    /* Clear cur intrs */
+	CPC700_OUT_32(CPC700_UIC_UICCR, 0xffffffff);    /* Gen INT not MCP */
+	CPC700_OUT_32(CPC700_UIC_UICPR, 0x00000000);    /* Active low */
+	CPC700_OUT_32(CPC700_UIC_UICTR, 0x00000000);    /* Level Sensitive */
+	CPC700_OUT_32(CPC700_UIC_UICVR, CPC700_UIC_UICVCR_0_HI);
+						        /* IRQ 0 is highest */
+
+	for (i = 0; i < 17; i++) {
+		irq_desc[i].handler = &cpc700_pic;
+		cpc700_pic_init_irq(i);
+	}
+
+	for (i = 20; i < 32; i++) {
+		irq_desc[i].handler = &cpc700_pic;
+		cpc700_pic_init_irq(i);
+	}
+
+	return;
+}
+
+
+
+/*
+ * Find the highest IRQ that generating an interrupt, if any.
+ */
+int
+cpc700_get_irq(struct pt_regs *regs)
+{
+	int irq = 0;
+	u_int irq_status, irq_test = 1;
+
+	irq_status = CPC700_IN_32(CPC700_UIC_UICMSR);
+
+	do
+	{
+		if (irq_status & irq_test)
+			break;
+		irq++;
+		irq_test <<= 1;
+	} while (irq < NR_IRQS);
+		
+
+	if (irq == NR_IRQS)
+	    irq = 33;
+
+	return (31 - irq);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/error_log.c linux-2.4.20/arch/ppc/platforms/error_log.c
--- linux-2.4.19/arch/ppc/platforms/error_log.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/error_log.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,186 @@
+/*
+ * BK Id: SCCS/s.error_log.c 1.6 05/17/01 18:14:21 cort
+ */
+/*
+ *  arch/ppc/kernel/error_log.c
+ *  
+ *  Copyright (c) 2000 Tilmann Bitterberg
+ *  (tilmann@bitterberg.de)
+ *
+ *  Error processing of errors found by rtas even-scan routine
+ *  which is done with every heartbeat. (chrp_setup.c)
+ */
+
+#include <linux/sched.h>
+
+#include <asm/prom.h>
+
+#include "error_log.h"
+
+/* ****************************************************************** */
+/* 
+ * EVENT-SCAN
+ * The whole stuff below here doesn't take any action when it found
+ * an error, it just prints as much information as possible and 
+ * then its up to the user to decide what to do.
+ *
+ * Returns 0 if no errors were found
+ * Returns 1 if there may be more errors
+ */
+int ppc_rtas_errorlog_scan(void)
+{
+const char *_errlog_severity[] = {
+#ifdef VERBOSE_ERRORS
+	"No Error\n\t\
+Should require no further information",
+	"Event\n\t\
+This is not really an error, it is an event. I use events\n\t\
+to communicate with RTAS back and forth.",
+	"Warning\n\t\
+Indicates a non-state-losing error, either fully recovered\n\t\
+by RTAS or not needing recovery. Ignore it.",
+	"Error sync\n\t\
+May only be fatal to a certain program or thread. Recovery\n\t\
+and continuation is possible, if I only had a handler for\n\t\
+this. Less serious",
+	"Error\n\t\
+Less serious, but still causing a loss of data and state.\n\t\
+I can't tell you exactly what to do, You have to decide\n\t\
+with help from the target and initiator field, what kind\n\t\
+of further actions may take place.",
+	"Fatal\n\t\
+Represent a permanent hardware failure and I believe this\n\t\
+affects my overall performance and behaviour. I would not\n\t\
+attempt to continue normal operation."
+#else
+	"No Error",
+	"Event",
+	"Warning",
+	"Error sync",
+	"Error",
+	"Fatal"
+#endif /* VERBOSE_ERRORS */
+};
+
+#if 0 /* unused?? */
+const char *_errlog_disposition[] = {
+#ifdef VERBOSE_ERRORS
+	"Fully recovered\n\t\
+There was an error, but it is fully recovered by RTAS.",
+	"Limited recovery\n\t\
+RTAS was able to recover the state of the machine, but some\n\t\
+feature of the machine has been disabled or lost (for example\n\t\
+error checking) or performance may suffer.",
+	"Not recovered\n\t\
+Whether RTAS did not try to recover anything or recovery failed:\n\t\
+HOUSTON, WE HAVE A PROBLEM!"
+#else
+	"Fully recovered",
+	"Limited recovery",
+	"Not recovered"
+#endif /* VERBOSE_ERRORS */
+};
+#endif
+
+const char *_errlog_extended[] = {
+#ifdef VERBOSE_ERRORS
+	"Not present\n\t\
+Sad, the RTAS call didn't return an extended error log.",
+	"Present\n\t\
+The extended log is present and hopefully it contains a lot of\n\t\
+useful information, which leads to the solution of the problem."
+#else
+	"Not present",
+	"Present"
+#endif /* VERBOSE_ERRORS */
+};
+
+const char *_errlog_initiator[] = { 
+	"Unknown or not applicable",
+	"CPU",
+	"PCI",
+	"ISA",
+	"Memory",
+	"Power management"
+};
+
+const char *_errlog_target[] = { 
+	"Unknown or not applicable",
+	"CPU",
+	"PCI",
+	"ISA",
+	"Memory",
+	"Power management"
+};
+	rtas_error_log error_log;
+	char logdata[1024];
+	int error;
+#if 0 /* unused?? */
+	int retries = 0; /* if HW error, try 10 times */
+#endif
+
+	error = call_rtas ("event-scan", 4, 1, (unsigned long *)&error_log,
+			INTERNAL_ERROR | EPOW_WARNING,
+			0, __pa(logdata), 1024);
+
+	if (error == 1) /* no errors found */
+		return 0;
+
+	if (error == -1) {
+		printk(KERN_ERR "Unable to get errors. Do you a favor and throw this box away\n");
+		return 0;
+	}
+	if (error_log.version != 1)
+		printk(KERN_WARNING "Unknown version (%d), please implement me\n", 
+				error_log.version);
+
+	switch (error_log.disposition) {
+		case DISP_FULLY_RECOVERED:
+			/* there was an error, but everything is fine now */
+			return 0;
+		case DISP_NOT_RECOVERED:
+			printk("We have a really serious Problem!\n");
+		case DISP_LIMITED_RECOVERY:
+			printk("Error classification\n");
+			printk("Severity  : %s\n", 
+					ppc_rtas_errorlog_check_severity (error_log));
+			printk("Initiator : %s\n", 
+					ppc_rtas_errorlog_check_initiator (error_log));
+			printk("Target    : %s\n", 
+					ppc_rtas_errorlog_check_target (error_log));
+			printk("Type      : %s\n", 
+					ppc_rtas_errorlog_check_type (error_log));
+			printk("Ext. log  : %s\n", 
+					ppc_rtas_errorlog_check_extended (error_log));
+			if (error_log.extended)
+				ppc_rtas_errorlog_disect_extended (logdata);
+			return 1;	
+		default:
+			/* nothing */
+			break;
+	}
+	return 0;
+}
+/* ****************************************************************** */
+const char * ppc_rtas_errorlog_check_type (rtas_error_log error_log)
+{
+	const char *_errlog_type[] = {
+		"unknown type",
+		"too many tries failed",
+		"TCE error",
+		"RTAS device failed",
+		"target timed out",
+		"parity error on data",			/* 5 */
+		"parity error on address",
+		"parity error on external cache",
+		"access to invalid address",
+		"uncorrectable ECC error",
+		"corrected ECC error"			/* 10 */
+	};
+	if (error_log.type == TYPE_EPOW) 
+		return "EPOW"; 
+	if (error_log.type >= TYPE_PMGM_POWER_SW_ON)
+		return "PowerMGM Event (not handled right now)";
+	return _errlog_type[error_log.type];
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/error_log.h linux-2.4.20/arch/ppc/platforms/error_log.h
--- linux-2.4.19/arch/ppc/platforms/error_log.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/error_log.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,98 @@
+/*
+ * BK Id: SCCS/s.error_log.h 1.5 05/17/01 18:14:21 cort
+ */
+#ifndef __ERROR_LOG_H__
+#define __ERROR_LOG_H__
+
+#define VERBOSE_ERRORS		1 /* Maybe I enlarge the kernel too much */
+#undef VERBOSE_ERRORS
+
+/* Event classes */
+/* XXX: Endianess correct? NOW*/
+#define INTERNAL_ERROR		0x80000000 /* set bit 0 */
+#define EPOW_WARNING		0x40000000 /* set bit 1 */
+#define POWERMGM_EVENTS		0x20000000 /* set bit 2 */
+
+/* event-scan returns */
+#define SEVERITY_FATAL		0x5
+#define SEVERITY_ERROR		0x4
+#define SEVERITY_ERROR_SYNC	0x3
+#define SEVERITY_WARNING	0x2
+#define SEVERITY_EVENT		0x1
+#define SEVERITY_NO_ERROR	0x0
+#define DISP_FULLY_RECOVERED	0x0
+#define DISP_LIMITED_RECOVERY	0x1
+#define DISP_NOT_RECOVERED	0x2
+#define PART_PRESENT		0x0
+#define PART_NOT_PRESENT	0x1
+#define INITIATOR_UNKNOWN	0x0
+#define INITIATOR_CPU		0x1
+#define INITIATOR_PCI		0x2
+#define INITIATOR_ISA		0x3
+#define INITIATOR_MEMORY	0x4
+#define INITIATOR_POWERMGM	0x5
+#define TARGET_UNKNOWN		0x0
+#define TARGET_CPU		0x1
+#define TARGET_PCI		0x2
+#define TARGET_ISA		0x3
+#define TARGET_MEMORY		0x4
+#define TARGET_POWERMGM		0x5
+#define TYPE_RETRY		0x01
+#define TYPE_TCE_ERR		0x02
+#define TYPE_INTERN_DEV_FAIL	0x03
+#define TYPE_TIMEOUT		0x04
+#define TYPE_DATA_PARITY	0x05
+#define TYPE_ADDR_PARITY	0x06
+#define TYPE_CACHE_PARITY	0x07
+#define TYPE_ADDR_INVALID	0x08
+#define TYPE_ECC_UNCORR		0x09
+#define TYPE_ECC_CORR		0x0a
+#define TYPE_EPOW		0x40
+/* I don't add PowerMGM events right now, this is a different topic */ 
+#define TYPE_PMGM_POWER_SW_ON	0x60
+#define TYPE_PMGM_POWER_SW_OFF	0x61
+#define TYPE_PMGM_LID_OPEN	0x62
+#define TYPE_PMGM_LID_CLOSE	0x63
+#define TYPE_PMGM_SLEEP_BTN	0x64
+#define TYPE_PMGM_WAKE_BTN	0x65
+#define TYPE_PMGM_BATTERY_WARN	0x66
+#define TYPE_PMGM_BATTERY_CRIT	0x67
+#define TYPE_PMGM_SWITCH_TO_BAT	0x68
+#define TYPE_PMGM_SWITCH_TO_AC	0x69
+#define TYPE_PMGM_KBD_OR_MOUSE	0x6a
+#define TYPE_PMGM_ENCLOS_OPEN	0x6b
+#define TYPE_PMGM_ENCLOS_CLOSED	0x6c
+#define TYPE_PMGM_RING_INDICATE	0x6d
+#define TYPE_PMGM_LAN_ATTENTION	0x6e
+#define TYPE_PMGM_TIME_ALARM	0x6f
+#define TYPE_PMGM_CONFIG_CHANGE	0x70
+#define TYPE_PMGM_SERVICE_PROC	0x71
+
+typedef struct _rtas_error_log {
+	unsigned long version:8;		/* Architectural version */
+	unsigned long severity:3;		/* Severity level of error */
+	unsigned long disposition:2;		/* Degree of recovery */
+	unsigned long extended:1;		/* extended log present? */
+	unsigned long /* reserved */ :2;	/* Reserved for future use */
+	unsigned long initiator:4;		/* Initiator of event */
+	unsigned long target:4;			/* Target of failed operation */
+	unsigned long type:8;			/* General event or error*/
+	unsigned long extended_log_length:32;	/* length in bytes */
+} rtas_error_log;
+
+/* ****************************************************************** */
+#define ppc_rtas_errorlog_check_severity(x) \
+	(_errlog_severity[x.severity])
+#define ppc_rtas_errorlog_check_target(x) \
+	(_errlog_target[x.target])
+#define ppc_rtas_errorlog_check_initiator(x) \
+	(_errlog_initiator[x.initiator])
+#define ppc_rtas_errorlog_check_extended(x) \
+	(_errlog_extended[x.extended])
+#define ppc_rtas_errorlog_disect_extended(x) \
+	do { /* implement me */ } while(0)
+extern const char * ppc_rtas_errorlog_check_type (rtas_error_log error_log);
+extern int ppc_rtas_errorlog_scan(void);
+
+
+#endif /* __ERROR_LOG_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/est8260.h linux-2.4.20/arch/ppc/platforms/est8260.h
--- linux-2.4.19/arch/ppc/platforms/est8260.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/est8260.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,31 @@
+/*
+ * BK Id: SCCS/s.est8260.h 1.5 05/17/01 18:14:24 cort
+ */
+
+/* Board information for the EST8260, which should be generic for
+ * all 8260 boards.  The IMMR is now given to us so the hard define
+ * will soon be removed.  All of the clock values are computed from
+ * the configuration SCMR and the Power-On-Reset word.
+ */
+
+#define IMAP_ADDR	((uint)0xf0000000)
+
+
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+	unsigned int	bi_memstart;	/* Memory start address */
+	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
+	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
+	unsigned int	bi_busfreq;	/* Bus Freq, in MHz */
+	unsigned int	bi_cpmfreq;	/* CPM Freq, in MHz */
+	unsigned int	bi_brgfreq;	/* BRG Freq, in MHz */
+	unsigned int	bi_vco;		/* VCO Out from PLL */
+	unsigned int	bi_baudrate;	/* Default console baud rate */
+	unsigned int	bi_immr;	/* IMMR when called from boot rom */
+	unsigned char	bi_enetaddr[6];
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/fads.h linux-2.4.20/arch/ppc/platforms/fads.h
--- linux-2.4.19/arch/ppc/platforms/fads.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/fads.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,61 @@
+/*
+ * BK Id: SCCS/s.fads.h 1.14 10/26/01 10:14:09 trini
+ */
+
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Motorola 860T FADS board.  Copied from the MBX stuff.
+ *
+ * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
+ */
+#ifdef __KERNEL__
+#ifndef __ASM_FADS_H__
+#define __ASM_FADS_H__
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+/* Memory map is configured by the PROM startup.
+ * I tried to follow the FADS manual, although the startup PROM
+ * dictates this and we simply have to move some of the physical
+ * addresses for Linux.
+ */
+#define BCSR_ADDR		((uint)0xff010000)
+#define BCSR_SIZE		((uint)(64 * 1024))
+#define	BCSR0			((uint)0xff010000)
+#define	BCSR1			((uint)0xff010004)
+#define	BCSR2			((uint)0xff010008)
+#define	BCSR3			((uint)0xff01000c)
+#define	BCSR4			((uint)0xff010010)
+
+#define IMAP_ADDR		((uint)0xff000000)
+#define IMAP_SIZE		((uint)(64 * 1024))
+
+#define PCMCIA_MEM_ADDR		((uint)0xff020000)
+#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
+
+/* Bits of interest in the BCSRs.
+ */
+#define BCSR1_ETHEN		((uint)0x20000000)
+#define BCSR1_RS232EN_1		((uint)0x01000000)
+#define BCSR1_RS232EN_2		((uint)0x00040000)
+#define BCSR4_ETHLOOP		((uint)0x80000000)	/* EEST Loopback */
+#define BCSR4_EEFDX		((uint)0x40000000)	/* EEST FDX enable */
+#define BCSR4_FETH_EN		((uint)0x08000000)	/* PHY enable */
+#define BCSR4_FETHCFG0		((uint)0x04000000)	/* PHY autoneg mode */
+#define BCSR4_FETHCFG1		((uint)0x00400000)	/* PHY autoneg mode */
+#define BCSR4_FETHFDE		((uint)0x02000000)	/* PHY FDX advertise */
+#define BCSR4_FETHRST		((uint)0x00200000)	/* PHY Reset */
+
+/* Interrupt level assignments.
+ */
+#define FEC_INTERRUPT	SIU_LEVEL1	/* FEC interrupt */
+#define PHY_INTERRUPT	SIU_IRQ2	/* PHY link change interrupt */
+
+/* We don't use the 8259.
+ */
+#define NR_8259_INTS	0
+
+#endif /* __ASM_FADS_H__ */
+#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/gemini.h linux-2.4.20/arch/ppc/platforms/gemini.h
--- linux-2.4.19/arch/ppc/platforms/gemini.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/gemini.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,171 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/platforms/gemini.h
+ *
+ *
+ *  Onboard registers and descriptions for Synergy Microsystems' 
+ *  "Gemini" boards.
+ *
+ */
+#ifdef __KERNEL__
+#ifndef __PPC_GEMINI_H
+#define __PPC_GEMINI_H
+
+/*  Registers  */
+
+#define GEMINI_SERIAL_B     (0xffeffb00)
+#define GEMINI_SERIAL_A     (0xffeffb08)
+#define GEMINI_USWITCH      (0xffeffd00)
+#define GEMINI_BREV         (0xffeffe00)
+#define GEMINI_BECO         (0xffeffe08)
+#define GEMINI_FEAT         (0xffeffe10)
+#define GEMINI_BSTAT        (0xffeffe18)
+#define GEMINI_CPUSTAT      (0xffeffe20)
+#define GEMINI_L2CFG        (0xffeffe30)
+#define GEMINI_MEMCFG       (0xffeffe38)
+#define GEMINI_FLROM        (0xffeffe40)
+#define GEMINI_P0PCI        (0xffeffe48)
+#define GEMINI_FLWIN        (0xffeffe50)
+#define GEMINI_P0INTMASK    (0xffeffe60)
+#define GEMINI_P0INTAP      (0xffeffe68)
+#define GEMINI_PCIERR       (0xffeffe70)
+#define GEMINI_LEDBASE      (0xffeffe80)
+#define GEMINI_RTC          (0xffe9fff8)
+#define GEMINI_LEDS         8
+#define GEMINI_SWITCHES     8
+
+
+/* Flash ROM bit definitions */
+#define GEMINI_FLS_WEN      (1<<0)
+#define GEMINI_FLS_JMP      (1<<6)
+#define GEMINI_FLS_BOOT     (1<<7)
+
+/* Memory bit definitions */
+#define GEMINI_MEM_TYPE_MASK 0xc0
+#define GEMINI_MEM_SIZE_MASK 0x38
+#define GEMINI_MEM_BANK_MASK 0x07
+
+/* L2 cache bit definitions */
+#define GEMINI_L2_SIZE_MASK  0xc0
+#define GEMINI_L2_RATIO_MASK 0x03
+
+/* Timebase register bit definitons */
+#define GEMINI_TIMEB0_EN     (1<<0)
+#define GEMINI_TIMEB1_EN     (1<<1)
+#define GEMINI_TIMEB2_EN     (1<<2)
+#define GEMINI_TIMEB3_EN     (1<<3)
+
+/* CPU status bit definitions */
+#define GEMINI_CPU_ID_MASK   0x03
+#define GEMINI_CPU_COUNT_MASK 0x0c
+#define GEMINI_CPU0_HALTED   (1<<4)
+#define GEMINI_CPU1_HALTED   (1<<5)
+#define GEMINI_CPU2_HALTED   (1<<6)
+#define GEMINI_CPU3_HALTED   (1<<7)
+
+/* Board status bit definitions */
+#define GEMINI_BRD_FAIL      (1<<0)   /* FAIL led is lit */
+#define GEMINI_BRD_BUS_MASK  0x0c     /* PowerPC bus speed */
+
+/* Board family/feature bit descriptions */
+#define GEMINI_FEAT_HAS_FLASH (1<<0)
+#define GEMINI_FEAT_HAS_ETH   (1<<1)
+#define GEMINI_FEAT_HAS_SCSI  (1<<2)
+#define GEMINI_FEAT_HAS_P0    (1<<3)
+#define GEMINI_FEAT_FAM_MASK  0xf0
+
+/* Mod/ECO bit definitions */
+#define GEMINI_ECO_LEVEL_MASK 0x0f
+#define GEMINI_MOD_MASK       0xf0
+
+/* Type/revision bit definitions */
+#define GEMINI_REV_MASK       0x0f
+#define GEMINI_TYPE_MASK      0xf0
+
+/* User switch definitions */
+#define GEMINI_SWITCH_VERBOSE    1     /* adds "debug" to boot cmd line */
+#define GEMINI_SWITCH_SINGLE_USER 7    /* boots into "single-user" mode */
+
+#define SGS_RTC_CONTROL  0
+#define SGS_RTC_SECONDS  1
+#define SGS_RTC_MINUTES  2
+#define SGS_RTC_HOURS    3
+#define SGS_RTC_DAY      4
+#define SGS_RTC_DAY_OF_MONTH 5
+#define SGS_RTC_MONTH    6
+#define SGS_RTC_YEAR     7
+
+#define SGS_RTC_SET  0x80
+#define SGS_RTC_IS_STOPPED 0x80
+
+#define GRACKLE_CONFIG_ADDR_ADDR  (0xfec00000)
+#define GRACKLE_CONFIG_DATA_ADDR  (0xfee00000)
+
+#define GEMINI_BOOT_INIT  (0xfff00100)
+
+#ifndef __ASSEMBLY__
+
+static inline void grackle_write( unsigned long addr, unsigned long data )
+{
+  __asm__ __volatile__(
+  " stwbrx %1, 0, %0\n \
+    sync\n \
+    stwbrx %3, 0, %2\n \
+    sync "
+  : /* no output */
+  : "r" (GRACKLE_CONFIG_ADDR_ADDR), "r" (addr),
+    "r" (GRACKLE_CONFIG_DATA_ADDR), "r" (data));
+}
+
+static inline unsigned long grackle_read( unsigned long addr )
+{
+  unsigned long val;
+
+  __asm__ __volatile__(
+  " stwbrx %1, 0, %2\n \
+    sync\n \
+    lwbrx %0, 0, %3\n \
+    sync "
+  : "=r" (val)
+  : "r" (addr), "r" (GRACKLE_CONFIG_ADDR_ADDR),
+    "r" (GRACKLE_CONFIG_DATA_ADDR));
+
+  return val;
+}
+
+static inline void gemini_led_on( int led )
+{
+  if (led >= 0 && led < GEMINI_LEDS)
+    *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 1;
+}
+
+static inline void gemini_led_off(int led)
+{
+  if (led >= 0 && led < GEMINI_LEDS)
+    *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 0;
+}
+
+static inline int gemini_led_val(int led)
+{
+  int val = 0;
+  if (led >= 0 && led < GEMINI_LEDS)
+    val = *(unsigned char *)(GEMINI_LEDBASE + (led<<3));
+  return (val & 0x1);
+}
+
+/* returns processor id from the board */
+static inline int gemini_processor(void)
+{
+  unsigned char cpu = *(unsigned char *)(GEMINI_CPUSTAT);
+  return (int) ((cpu == 0) ? 4 : (cpu & GEMINI_CPU_ID_MASK));
+}
+
+
+extern void _gemini_reboot(void);
+extern void gemini_prom_init(void);
+extern void gemini_init_l2(void);
+#endif /* __ASSEMBLY__ */
+#endif
+#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/gemini_pci.c linux-2.4.20/arch/ppc/platforms/gemini_pci.c
--- linux-2.4.19/arch/ppc/platforms/gemini_pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/gemini_pci.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,122 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/machdep.h>
+#include <platforms/gemini.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/pci-bridge.h>
+
+#define pci_config_addr(bus,dev,offset) \
+        (0x80000000 | (bus<<16) | (dev<<8) | offset)
+
+
+int
+gemini_pcibios_read_config_byte(struct pci_dev *dev, int offset, u8 *val)
+{
+	unsigned long reg;
+	reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn,
+					   (offset & ~(0x3))));
+	*val = ((reg >> ((offset & 0x3) << 3)) & 0xff);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_read_config_word(struct pci_dev *dev, int offset, u16 *val)
+{
+	unsigned long reg;
+	reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn,
+					   (offset & ~(0x3))));
+	*val = ((reg >> ((offset & 0x3) << 3)) & 0xffff);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_read_config_dword(struct pci_dev *dev, int offset, u32 *val)
+{
+	*val = grackle_read(pci_config_addr(dev->bus->number, dev->devfn,
+					    (offset & ~(0x3))));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_write_config_byte(struct pci_dev *dev, int offset, u8 val)
+{
+	unsigned long reg;
+	int shifts = offset & 0x3;
+	unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn,
+					    (offset & ~(0x3)));
+
+	reg = grackle_read(addr);
+	reg = (reg & ~(0xff << (shifts << 3))) | (val << (shifts << 3));
+	grackle_write(addr, reg );
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_write_config_word(struct pci_dev *dev, int offset, u16 val)
+{
+	unsigned long reg;
+	int shifts = offset & 0x3;
+	unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn,
+					    (offset & ~(0x3)));
+
+	reg = grackle_read(addr);
+	reg = (reg & ~(0xffff << (shifts << 3))) | (val << (shifts << 3));
+	grackle_write(addr, reg );
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_write_config_dword(struct pci_dev *dev, int offset, u32 val)
+{
+	grackle_write(pci_config_addr(dev->bus->number, dev->devfn,
+				      (offset & ~(0x3))), val);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops gemini_pci_ops =
+{
+	gemini_pcibios_read_config_byte,
+	gemini_pcibios_read_config_word,
+	gemini_pcibios_read_config_dword,
+	gemini_pcibios_write_config_byte,
+	gemini_pcibios_write_config_word,
+	gemini_pcibios_write_config_dword
+};
+
+void __init gemini_pcibios_fixup(void)
+{
+	int i;
+	struct pci_dev *dev;
+	
+	pci_for_each_dev(dev) {
+		for(i = 0; i < 6; i++) {
+			if (dev->resource[i].flags & IORESOURCE_IO) {
+				dev->resource[i].start |= (0xfe << 24);
+				dev->resource[i].end |= (0xfe << 24);
+			}
+		}
+	}
+}
+
+
+/* The "bootloader" for Synergy boards does none of this for us, so we need to
+   lay it all out ourselves... --Dan */
+void __init gemini_find_bridges(void)
+{
+	struct pci_controller* hose;
+	
+	ppc_md.pcibios_fixup = gemini_pcibios_fixup;
+
+	hose = pcibios_alloc_controller();
+	if (!hose)
+		return;
+	hose->ops = &gemini_pci_ops;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/gemini_prom.S linux-2.4.20/arch/ppc/platforms/gemini_prom.S
--- linux-2.4.19/arch/ppc/platforms/gemini_prom.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/gemini_prom.S	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,98 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/kernel/gemini_prom.S
+ *
+ *  Not really prom support code (yet), but sort of anti-prom code.  The current
+ *  bootloader does a number of things it shouldn't and doesn't do things that it
+ *  should.  The stuff in here is mainly a hodge-podge collection of setup code
+ *  to get the board up and running.
+ *    ---Dan
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <platforms/gemini.h>
+#include <asm/ppc_asm.h>
+
+#define HID0_ABE (1<<3)
+
+/*
+ *  On 750's the MMU is on when Linux is booted, so we need to clear out the
+ *  bootloader's BAT settings, make sure we're in supervisor state (gotcha!),
+ *  and turn off the MMU.
+ *
+ */
+
+_GLOBAL(gemini_prom_init)
+#ifdef CONFIG_SMP
+	/* Since the MMU's on, get stuff in rom space that we'll need */
+	lis	r4,GEMINI_CPUSTAT@h
+	ori	r4,r4,GEMINI_CPUSTAT@l
+	lbz	r5,0(r4)
+	andi.	r5,r5,3
+	mr	r24,r5		/* cpu # used later on */
+#endif
+	mfmsr	r4
+	li	r3,MSR_PR	/* ensure supervisor! */
+	ori	r3,r3,MSR_IR|MSR_DR
+	andc	r4,r4,r3
+	mtmsr	r4
+	isync
+#if 0
+	/* zero out the bats now that the MMU is off */
+prom_no_mmu:	
+	li	r3,0
+        mtspr   IBAT0U,r3
+        mtspr   IBAT0L,r3
+        mtspr   IBAT1U,r3
+        mtspr   IBAT1L,r3
+        mtspr   IBAT2U,r3
+        mtspr   IBAT2L,r3
+        mtspr   IBAT3U,r3
+        mtspr   IBAT3L,r3
+
+        mtspr   DBAT0U,r3
+        mtspr   DBAT0L,r3
+        mtspr   DBAT1U,r3
+        mtspr   DBAT1L,r3
+        mtspr   DBAT2U,r3
+	mtspr   DBAT2L,r3
+        mtspr   DBAT3U,r3
+        mtspr   DBAT3L,r3
+#endif
+
+	/* the bootloader (as far as I'm currently aware) doesn't mess with page
+	   tables, but since we're already here, might as well zap these, too */
+	li	r4,0
+	mtspr	SDR1,r4
+
+	li	r4,16
+	mtctr	r4
+	li	r3,0
+	li	r4,0
+3:	mtsrin	r3,r4
+	addi	r3,r3,1
+	bdnz	3b
+
+#ifdef CONFIG_SMP
+	/* The 750 book (and Mot/IBM support) says that this will "assist" snooping
+	   when in SMP.  Not sure yet whether this should stay or leave... */
+	mfspr	r4,HID0
+	ori	r4,r4,HID0_ABE
+	mtspr	HID0,r4
+	sync
+#endif /* CONFIG_SMP */
+	blr
+
+/*  apparently, SMon doesn't pay attention to HID0[SRST].  Disable the MMU and
+    branch to 0xfff00100 */
+_GLOBAL(_gemini_reboot)
+	lis	r5,GEMINI_BOOT_INIT@h
+	ori	r5,r5,GEMINI_BOOT_INIT@l
+	li	r6,MSR_IP
+	mtspr	SRR0,r5
+	mtspr	SRR1,r6
+	rfi
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/gemini_serial.h linux-2.4.20/arch/ppc/platforms/gemini_serial.h
--- linux-2.4.19/arch/ppc/platforms/gemini_serial.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/gemini_serial.h	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,44 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+#ifdef __KERNEL__
+#ifndef __ASMPPC_GEMINI_SERIAL_H
+#define __ASMPPC_GEMINI_SERIAL_H
+
+#include <linux/config.h>
+#include <platforms/gemini.h>
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define RS_TABLE_SIZE  64
+#else
+#define RS_TABLE_SIZE  4
+#endif
+
+/* Rate for the 24.576 Mhz clock for the onboard serial chip */
+#define BASE_BAUD  (24576000 / 16)
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF)
+#endif
+
+#define STD_SERIAL_PORT_DEFNS \
+        { 0, BASE_BAUD, GEMINI_SERIAL_A, 15, STD_COM_FLAGS }, /* ttyS0 */ \
+        { 0, BASE_BAUD, GEMINI_SERIAL_B, 14, STD_COM_FLAGS }, /* ttyS1 */ \
+
+#ifdef CONFIG_GEMINI_PU32
+#define PU32_SERIAL_PORT_DEFNS \
+        { 0, BASE_BAUD, NULL, 0, STD_COM_FLAGS },
+#else
+#define PU32_SERIAL_PORT_DEFNS
+#endif
+
+#define SERIAL_PORT_DFNS \
+        STD_SERIAL_PORT_DEFNS \
+        PU32_SERIAL_PORT_DEFNS
+
+#endif
+#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/gemini_setup.c linux-2.4.20/arch/ppc/platforms/gemini_setup.c
--- linux-2.4.19/arch/ppc/platforms/gemini_setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/gemini_setup.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,592 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/platforms/setup.c
+ *
+ *  Copyright (C) 1995 Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  Synergy Microsystems board support by Dan Cox (dan@synergymicro.com)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/console.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/m48t35.h>
+#include <platforms/gemini.h>
+#include <asm/time.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/hardirq.h> /* for heartbeat */
+
+void gemini_find_bridges(void);
+static int gemini_get_clock_speed(void);
+extern void gemini_pcibios_fixup(void);
+
+static char *gemini_board_families[] = {
+  "VGM", "VSS", "KGM", "VGR", "VCM", "VCS", "KCM", "VCR"
+};
+static int gemini_board_count = sizeof(gemini_board_families) /
+                                 sizeof(gemini_board_families[0]);
+
+static unsigned int cpu_7xx[16] = {
+	0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
+};
+static unsigned int cpu_6xx[16] = {
+	0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0
+};
+
+/*
+ * prom_init is the Gemini version of prom.c:prom_init.  We only need
+ * the BSS clearing code, so I copied that out of prom.c.  This is a
+ * lot simpler than hacking prom.c so it will build with Gemini. -VAL
+ */
+
+#define PTRRELOC(x)	((typeof(x))((unsigned long)(x) + offset))
+
+unsigned long
+prom_init(void)
+{
+	unsigned long offset = reloc_offset();
+	unsigned long phys;
+	extern char __bss_start, _end;
+
+	/* First zero the BSS -- use memset, some arches don't have
+	 * caches on yet */
+	memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start);
+
+ 	/* Default */
+ 	phys = offset + KERNELBASE;
+
+	gemini_prom_init();
+
+	return phys;
+}
+
+int
+gemini_show_cpuinfo(struct seq_file *m)
+{
+	unsigned char reg, rev;
+	char *family;
+	unsigned int type;
+
+	reg = readb(GEMINI_FEAT);
+	family = gemini_board_families[((reg>>4) & 0xf)];
+	if (((reg>>4) & 0xf) > gemini_board_count)
+		printk(KERN_ERR "cpuinfo(): unable to determine board family\n");
+
+	reg = readb(GEMINI_BREV);
+	type = (reg>>4) & 0xf;
+	rev = reg & 0xf;
+
+	reg = readb(GEMINI_BECO);
+
+	seq_printf(m, "machine\t\t: Gemini %s%d, rev %c, eco %d\n",
+		   family, type, (rev + 'A'), (reg & 0xf));
+
+	seq_printf(m, "board\t\t: Gemini %s", family);
+	if (type > 9)
+		seq_printf(m, "%c", (type - 10) + 'A');
+	else
+		seq_printf(m, "%d", type);
+
+	seq_printf(m, ", rev %c, eco %d\n", (rev + 'A'), (reg & 0xf));
+
+	seq_printf(m, "clock\t\t: %dMhz\n", gemini_get_clock_speed());
+
+	return 0;
+}
+
+static u_char gemini_openpic_initsenses[] = {
+	1,
+	1,
+	1,
+	1,
+	0,
+	0,
+	1, /* remainder are level-triggered */
+};
+
+#define GEMINI_MPIC_ADDR (0xfcfc0000)
+#define GEMINI_MPIC_PCI_CFG (0x80005800)
+
+void __init gemini_openpic_init(void)
+{
+
+	OpenPIC_Addr = (volatile struct OpenPIC *)
+		grackle_read(GEMINI_MPIC_PCI_CFG + 0x10);
+	OpenPIC_InitSenses = gemini_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses );
+
+	ioremap( GEMINI_MPIC_ADDR, OPENPIC_SIZE);
+}
+
+
+extern unsigned long loops_per_jiffy;
+extern int root_mountflags;
+extern char cmd_line[];
+
+void
+gemini_heartbeat(void)
+{
+	static unsigned long led = GEMINI_LEDBASE+(4*8);
+	static char direction = 8;
+
+	/* We only want to do this on 1 CPU */
+	if (smp_processor_id()) {
+		static short ratelimit;
+		if (!ratelimit++)
+			printk(KERN_ERR "%s: unexpected heartbeat on cpu %d\n", 
+					__FUNCTION__, smp_processor_id());
+		return;
+	}
+	*(char *)led = 0;
+	if ( (led + direction) > (GEMINI_LEDBASE+(7*8)) ||
+	     (led + direction) < (GEMINI_LEDBASE+(4*8)) )
+		direction *= -1;
+	led += direction;
+	*(char *)led = 0xff;
+}
+
+void __init gemini_setup_arch(void)
+{
+	extern char cmd_line[];
+
+
+	loops_per_jiffy = 50000000/HZ;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* bootable off CDROM */
+	if (initrd_start)
+		ROOT_DEV = MKDEV(SCSI_CDROM_MAJOR, 0);
+	else
+#endif
+		ROOT_DEV = to_kdev_t(0x0801);
+
+	/* nothing but serial consoles... */
+	sprintf(cmd_line, "%s console=ttyS0", cmd_line);
+
+	printk("Boot arguments: %s\n", cmd_line);
+
+	ppc_md.heartbeat = gemini_heartbeat;
+	/* only run on cpu 0 */
+	heartbeat_reset(0) = HZ/8;
+	heartbeat_count(0) = 1;
+
+	/* Lookup PCI hosts */
+	gemini_find_bridges();
+	/* take special pains to map the MPIC, since it isn't mapped yet */
+	gemini_openpic_init();
+	/* start the L2 */
+	gemini_init_l2();
+}
+
+
+int
+gemini_get_clock_speed(void)
+{
+	unsigned long hid1, pvr;
+	int clock;
+
+	pvr = mfspr(PVR);
+	hid1 = (mfspr(HID1) >> 28) & 0xf;
+	if (PVR_VER(pvr) == 8 ||
+	    PVR_VER(pvr) == 12)
+		hid1 = cpu_7xx[hid1];
+	else
+		hid1 = cpu_6xx[hid1];
+
+	switch((readb(GEMINI_BSTAT) & 0xc) >> 2) {
+
+	case 0:
+	default:
+		clock = (hid1*100)/3;
+		break;
+
+	case 1:
+		clock = (hid1*125)/3;
+		break;
+
+	case 2:
+		clock = (hid1*50);
+		break;
+	}
+
+	return clock;
+}
+
+void __init gemini_init_l2(void)
+{
+        unsigned char reg, brev, fam, creg;
+        unsigned long cache;
+        unsigned long pvr;
+
+        reg = readb(GEMINI_L2CFG);
+        brev = readb(GEMINI_BREV);
+        fam = readb(GEMINI_FEAT);
+        pvr = mfspr(PVR);
+
+        switch(PVR_VER(pvr)) {
+
+        case 8:
+                if (reg & 0xc0)
+                        cache = (((reg >> 6) & 0x3) << 28);
+                else
+                        cache = 0x3 << 28;
+
+#ifdef CONFIG_SMP
+                /* Pre-3.0 processor revs had snooping errata.  Leave
+                   their L2's disabled with SMP. -- Dan */
+                if (PVR_CFG(pvr) < 3) {
+                        printk("Pre-3.0 750; L2 left disabled!\n");
+                        return;
+                }
+#endif /* CONFIG_SMP */
+
+                /* Special case: VGM5-B's came before L2 ratios were set on
+                   the board.  Processor speed shouldn't be too high, so
+                   set L2 ratio to 1:1.5.  */
+                if ((brev == 0x51) && ((fam & 0xa0) >> 4) == 0)
+                        reg |= 1;
+
+                /* determine best cache ratio based upon what the board
+                   tells us (which sometimes _may_ not be true) and
+                   the processor speed. */
+                else {
+                        if (gemini_get_clock_speed() > 250)
+                                reg = 2;
+                }
+                break;
+        case 12:
+	{
+		static unsigned long l2_size_val = 0;
+
+		if (!l2_size_val)
+			l2_size_val = _get_L2CR();
+		cache = l2_size_val;
+                break;
+	}
+        case 4:
+        case 9:
+                creg = readb(GEMINI_CPUSTAT);
+                if (((creg & 0xc) >> 2) != 1)
+                        printk("Dual-604 boards don't support the use of L2\n");
+                else
+                        writeb(1, GEMINI_L2CFG);
+                return;
+        default:
+                printk("Unknown processor; L2 left disabled\n");
+                return;
+        }
+
+        cache |= ((1<<reg) << 25);
+        cache |= (L2CR_L2RAM_MASK|L2CR_L2CTL|L2CR_L2DO);
+        _set_L2CR(0);
+        _set_L2CR(cache | L2CR_L2E);
+
+}
+
+void
+gemini_restart(char *cmd)
+{
+	__cli();
+	/* make a clean restart, not via the MPIC */
+	_gemini_reboot();
+	for(;;);
+}
+
+void
+gemini_power_off(void)
+{
+	for(;;);
+}
+
+void
+gemini_halt(void)
+{
+	gemini_restart(NULL);
+}
+
+void __init gemini_init_IRQ(void)
+{
+	/* gemini has no 8259 */
+	openpic_init(1, 0, 0, -1);
+}
+
+#define gemini_rtc_read(x)       (readb(GEMINI_RTC+(x)))
+#define gemini_rtc_write(val,x)  (writeb((val),(GEMINI_RTC+(x))))
+
+/* ensure that the RTC is up and running */
+long __init gemini_time_init(void)
+{
+	unsigned char reg;
+
+	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
+
+	if ( reg & M48T35_RTC_STOPPED ) {
+		printk(KERN_INFO "M48T35 real-time-clock was stopped. Now starting...\n");
+		gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL);
+		gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL);
+	}
+	return 0;
+}
+
+#undef DEBUG_RTC
+
+unsigned long
+gemini_get_rtc_time(void)
+{
+	unsigned int year, mon, day, hour, min, sec;
+	unsigned char reg;
+
+	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
+	gemini_rtc_write((reg|M48T35_RTC_READ), M48T35_RTC_CONTROL);
+#ifdef DEBUG_RTC
+	printk("get rtc: reg = %x\n", reg);
+#endif
+
+	do {
+		sec = gemini_rtc_read(M48T35_RTC_SECONDS);
+		min = gemini_rtc_read(M48T35_RTC_MINUTES);
+		hour = gemini_rtc_read(M48T35_RTC_HOURS);
+		day = gemini_rtc_read(M48T35_RTC_DOM);
+		mon = gemini_rtc_read(M48T35_RTC_MONTH);
+		year = gemini_rtc_read(M48T35_RTC_YEAR);
+	} while( sec != gemini_rtc_read(M48T35_RTC_SECONDS));
+#ifdef DEBUG_RTC
+	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", 
+	       sec, min, hour, day, mon, year);
+#endif
+
+	gemini_rtc_write(reg, M48T35_RTC_CONTROL);
+
+	BCD_TO_BIN(sec);
+	BCD_TO_BIN(min);
+	BCD_TO_BIN(hour);
+	BCD_TO_BIN(day);
+	BCD_TO_BIN(mon);
+	BCD_TO_BIN(year);
+
+	if ((year += 1900) < 1970)
+		year += 100;
+#ifdef DEBUG_RTC
+	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", 
+	       sec, min, hour, day, mon, year);
+#endif
+
+	return mktime( year, mon, day, hour, min, sec );
+}
+
+
+int
+gemini_set_rtc_time( unsigned long now )
+{
+	unsigned char reg;
+	struct rtc_time tm;
+
+	to_tm( now, &tm );
+
+	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
+#if DEBUG_RTC
+	printk("set rtc: reg = %x\n", reg);
+#endif
+
+	gemini_rtc_write((reg|M48T35_RTC_SET), M48T35_RTC_CONTROL);
+#if DEBUG_RTC
+	printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
+	       tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
+#endif
+
+	tm.tm_year -= 1900;
+	BIN_TO_BCD(tm.tm_sec);
+	BIN_TO_BCD(tm.tm_min);
+	BIN_TO_BCD(tm.tm_hour);
+	BIN_TO_BCD(tm.tm_mon);
+	BIN_TO_BCD(tm.tm_mday);
+	BIN_TO_BCD(tm.tm_year);
+#ifdef DEBUG_RTC
+	printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
+	       tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
+#endif
+
+	gemini_rtc_write(tm.tm_sec, M48T35_RTC_SECONDS);
+	gemini_rtc_write(tm.tm_min, M48T35_RTC_MINUTES);
+	gemini_rtc_write(tm.tm_hour, M48T35_RTC_HOURS);
+	gemini_rtc_write(tm.tm_mday, M48T35_RTC_DOM);
+	gemini_rtc_write(tm.tm_mon, M48T35_RTC_MONTH);
+	gemini_rtc_write(tm.tm_year, M48T35_RTC_YEAR);
+
+	/* done writing */
+	gemini_rtc_write(reg, M48T35_RTC_CONTROL);
+
+	if ((time_state == TIME_ERROR) || (time_state == TIME_BAD))
+		time_state = TIME_OK;
+
+	return 0;
+}
+
+/*  use the RTC to determine the decrementer count */
+void __init gemini_calibrate_decr(void)
+{
+	int freq, divisor;
+	unsigned char reg;
+
+	/* determine processor bus speed */
+	reg = readb(GEMINI_BSTAT);
+
+	switch(((reg & 0x0c)>>2)&0x3) {
+	case 0:
+	default:
+		freq = 66667;
+		break;
+	case 1:
+		freq = 83000;
+		break;
+	case 2:
+		freq = 100000;
+		break;
+	}
+
+	freq *= 1000;
+	divisor = 4;
+	tb_ticks_per_jiffy = freq / HZ / divisor;
+	tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
+}
+
+unsigned long __init gemini_find_end_of_memory(void)
+{
+	unsigned long total;
+	unsigned char reg;
+
+	reg = readb(GEMINI_MEMCFG);
+	total = ((1<<((reg & 0x7) - 1)) *
+		 (8<<((reg >> 3) & 0x7)));
+	total *= (1024*1024);
+	return total;
+}
+
+static void __init
+gemini_map_io(void)
+{
+	io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
+	io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
+}
+
+#ifdef CONFIG_SMP
+static int
+smp_gemini_probe(void)
+{
+	int i, nr;
+
+        nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2;
+	if (nr == 0)
+		nr = 4;
+
+	if (nr > 1) {
+		openpic_request_IPIs();
+		for (i = 1; i < nr; ++i)
+			smp_hw_index[i] = i;
+	}
+
+	return nr;
+}
+
+static void
+smp_gemini_kick_cpu(int nr)
+{
+	openpic_reset_processor_phys(1 << nr);
+	openpic_reset_processor_phys(0);
+}
+
+static void
+smp_gemini_setup_cpu(int cpu_nr)
+{
+	if (OpenPIC_Addr)
+		do_openpic_setup_cpu();
+	if (cpu_nr > 0)
+		gemini_init_l2();
+}
+
+static struct smp_ops_t gemini_smp_ops = {
+	smp_openpic_message_pass,
+	smp_gemini_probe,
+	smp_gemini_kick_cpu,
+	smp_gemini_setup_cpu,
+};
+#endif /* CONFIG_SMP */
+
+void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+			  unsigned long r6, unsigned long r7)
+{
+	int i;
+
+	parse_bootinfo(find_bootinfo());
+
+	for(i = 0; i < GEMINI_LEDS; i++)
+		gemini_led_off(i);
+
+	ISA_DMA_THRESHOLD = 0;
+	DMA_MODE_READ = 0;
+	DMA_MODE_WRITE = 0;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if ( r4 )
+	{
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif
+
+	ppc_md.setup_arch = gemini_setup_arch;
+	ppc_md.show_cpuinfo = gemini_show_cpuinfo;
+	ppc_md.irq_cannonicalize = NULL;
+	ppc_md.init_IRQ = gemini_init_IRQ;
+	ppc_md.get_irq = openpic_get_irq;
+	ppc_md.init = NULL;
+
+	ppc_md.restart = gemini_restart;
+	ppc_md.power_off = gemini_power_off;
+	ppc_md.halt = gemini_halt;
+
+	ppc_md.time_init = gemini_time_init;
+	ppc_md.set_rtc_time = gemini_set_rtc_time;
+	ppc_md.get_rtc_time = gemini_get_rtc_time;
+	ppc_md.calibrate_decr = gemini_calibrate_decr;
+
+	ppc_md.find_end_of_memory = gemini_find_end_of_memory;
+	ppc_md.setup_io_mappings = gemini_map_io;
+
+	/* no keyboard/mouse/video stuff yet.. */
+	ppc_md.kbd_setkeycode = NULL;
+	ppc_md.kbd_getkeycode = NULL;
+	ppc_md.kbd_translate = NULL;
+	ppc_md.kbd_unexpected_up = NULL;
+	ppc_md.kbd_leds = NULL;
+	ppc_md.kbd_init_hw = NULL;
+	ppc_md.ppc_kbd_sysrq_xlate = NULL;
+	ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup;
+
+#ifdef CONFIG_SMP
+	ppc_md.smp_ops = &gemini_smp_ops;
+#endif /* CONFIG_SMP */
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/ivms8.h linux-2.4.20/arch/ppc/platforms/ivms8.h
--- linux-2.4.19/arch/ppc/platforms/ivms8.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/ivms8.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,59 @@
+/*
+ * BK Id: SCCS/s.ivms8.h 1.8 10/26/01 10:14:09 trini
+ */
+/*
+ * Speech Design Integrated Voicemail board specific definitions
+ * - IVMS8  (small,  8 channels)
+ * - IVML24 (large, 24 channels)
+ *
+ * In 2.5 when we force a new bootloader, we can merge these two, and add
+ * in _MACH_'s for them. -- Tom
+ *
+ * Copyright (c) 2000, 2001 Wolfgang Denk (wd@denx.de)
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IVMS8_H__
+#define __ASM_IVMS8_H__
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+#define IVMS_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR */
+#define IVMS_IMAP_SIZE	(64 * 1024)	/* size of mapped area */
+
+#define IMAP_ADDR	IVMS_IMMR_BASE	/* phys. base address of IMMR area */
+#define IMAP_SIZE	IVMS_IMAP_SIZE	/* mapped size of IMMR area */
+
+#define PCMCIA_MEM_ADDR	((uint)0xFE100000)
+#define PCMCIA_MEM_SIZE	((uint)(64 * 1024))
+
+#define FEC_INTERRUPT	 9		/* = SIU_LEVEL4 */
+#define IDE0_INTERRUPT	10		/* = IRQ5 */
+#define CPM_INTERRUPT	11		/* = SIU_LEVEL5 (was: SIU_LEVEL2) */
+#define PHY_INTERRUPT	12		/* = IRQ6 */
+
+/* override the default number of IDE hardware interfaces */
+#define MAX_HWIFS	1
+
+/*
+ * Definitions for IDE0 Interface
+ */
+#define IDE0_BASE_OFFSET		0x0000	/* Offset in PCMCIA memory */
+#define IDE0_DATA_REG_OFFSET		0x0000
+#define IDE0_ERROR_REG_OFFSET		0x0081
+#define IDE0_NSECTOR_REG_OFFSET		0x0082
+#define IDE0_SECTOR_REG_OFFSET		0x0083
+#define IDE0_LCYL_REG_OFFSET		0x0084
+#define IDE0_HCYL_REG_OFFSET		0x0085
+#define IDE0_SELECT_REG_OFFSET		0x0086
+#define IDE0_STATUS_REG_OFFSET		0x0087
+#define IDE0_CONTROL_REG_OFFSET		0x0106
+#define IDE0_IRQ_REG_OFFSET		0x000A	/* not used */
+
+/* We don't use the 8259. */
+#define NR_8259_INTS	0
+
+#endif /* __ASM_IVMS8_H__ */
+#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/mbx.h linux-2.4.20/arch/ppc/platforms/mbx.h
--- linux-2.4.19/arch/ppc/platforms/mbx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/mbx.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,98 @@
+/*
+ * BK Id: SCCS/s.mbx.h 1.11 08/17/01 15:23:17 paulus
+ */
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Motorola MBX boards.  This was originally created for the
+ * MBX860, and probably needs revisions for other boards (like the 821).
+ * When this file gets out of control, we can split it up into more
+ * meaningful pieces.
+ *
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ */
+#ifdef __KERNEL__
+#ifndef __MACH_MBX_DEFS
+#define __MACH_MBX_DEFS
+
+#ifndef __ASSEMBLY__
+/* A Board Information structure that is given to a program when
+ * EPPC-Bug starts it up.
+ */
+typedef struct bd_info {
+	unsigned int	bi_tag;		/* Should be 0x42444944 "BDID" */
+	unsigned int	bi_size;	/* Size of this structure */
+	unsigned int	bi_revision;	/* revision of this structure */
+	unsigned int	bi_bdate;	/* EPPCbug date, i.e. 0x11061997 */
+	unsigned int	bi_memstart;	/* Memory start address */
+	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
+	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
+	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
+	unsigned int	bi_clun;	/* Boot device controller */
+	unsigned int	bi_dlun;	/* Boot device logical dev */
+
+	/* These fields are not part of the board information structure
+	 * provided by the boot rom.  They are filled in by embed_config.c
+	 * so we have the information consistent with other platforms.
+	 */
+	unsigned char	bi_enetaddr[6];
+	unsigned int	bi_baudrate;
+} bd_t;
+
+/* Memory map for the MBX as configured by EPPC-Bug.  We could reprogram
+ * The SIU and PCI bridge, and try to use larger MMU pages, but the
+ * performance gain is not measureable and it certainly complicates the
+ * generic MMU model.
+ *
+ * In a effort to minimize memory usage for embedded applications, any
+ * PCI driver or ISA driver must request or map the region required by
+ * the device.  For convenience (and since we can map up to 4 Mbytes with
+ * a single page table page), the MMU initialization will map the
+ * NVRAM, Status/Control registers, CPM Dual Port RAM, and the PCI
+ * Bridge CSRs 1:1 into the kernel address space.
+ */
+#define PCI_ISA_IO_ADDR		((unsigned)0x80000000)
+#define PCI_ISA_IO_SIZE		((uint)(512 * 1024 * 1024))
+#define PCI_IDE_ADDR		((unsigned)0x81000000)
+#define PCI_ISA_MEM_ADDR	((unsigned)0xc0000000)
+#define PCI_ISA_MEM_SIZE	((uint)(512 * 1024 * 1024))
+#define PCMCIA_MEM_ADDR		((uint)0xe0000000)
+#define PCMCIA_MEM_SIZE		((uint)(64 * 1024 * 1024))
+#define PCMCIA_DMA_ADDR		((uint)0xe4000000)
+#define PCMCIA_DMA_SIZE		((uint)(64 * 1024 * 1024))
+#define PCMCIA_ATTRB_ADDR	((uint)0xe8000000)
+#define PCMCIA_ATTRB_SIZE	((uint)(64 * 1024 * 1024))
+#define PCMCIA_IO_ADDR		((uint)0xec000000)
+#define PCMCIA_IO_SIZE		((uint)(64 * 1024 * 1024))
+#define NVRAM_ADDR		((uint)0xfa000000)
+#define NVRAM_SIZE		((uint)(1 * 1024 * 1024))
+#define MBX_CSR_ADDR		((uint)0xfa100000)
+#define MBX_CSR_SIZE		((uint)(1 * 1024 * 1024))
+#define IMAP_ADDR		((uint)0xfa200000)
+#define IMAP_SIZE		((uint)(64 * 1024))
+#define PCI_CSR_ADDR		((uint)0xfa210000)
+#define PCI_CSR_SIZE		((uint)(64 * 1024))
+
+/* Map additional physical space into well known virtual addresses.  Due
+ * to virtual address mapping, these physical addresses are not accessible
+ * in a 1:1 virtual to physical mapping.
+ */
+#define ISA_IO_VIRT_ADDR	((uint)0xfa220000)
+#define ISA_IO_VIRT_SIZE	((uint)64 * 1024)
+
+/* Interrupt assignments.
+ * These are defined (and fixed) by the MBX hardware implementation.
+ */
+#define POWER_FAIL_INT	SIU_IRQ0	/* Power fail */
+#define TEMP_HILO_INT	SIU_IRQ1	/* Temperature sensor */
+#define QSPAN_INT	SIU_IRQ2	/* PCI Bridge (DMA CTLR?) */
+#define ISA_BRIDGE_INT	SIU_IRQ3	/* All those PC things */
+#define COMM_L_INT	SIU_IRQ6	/* MBX Comm expansion connector pin */
+#define STOP_ABRT_INT	SIU_IRQ7	/* Stop/Abort header pin */
+#endif /* !__ASSEMBLY__ */
+
+/* The MBX uses the 8259.
+*/
+#define NR_8259_INTS	16
+
+#endif
+#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/oak.h linux-2.4.20/arch/ppc/platforms/oak.h
--- linux-2.4.19/arch/ppc/platforms/oak.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/oak.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,65 @@
+/*
+ * BK Id: SCCS/s.oak.h 1.12 10/11/01 13:05:07 trini
+ */
+/*
+ *
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: oak.h
+ *
+ *    Description:
+ *	Macros, definitions, and data structures specific to the IBM PowerPC
+ *      403G{A,B,C,CX} "Oak" evaluation board. Anything specific to the pro-
+ *      cessor itself is defined elsewhere.
+ *
+ */
+
+#ifdef __KERNEL__
+#ifndef	__OAK_H__
+#define	__OAK_H__
+
+#define _IO_BASE	0
+#define _ISA_MEM_BASE	0
+#define PCI_DRAM_OFFSET	0
+
+/* Memory map for the "Oak" evaluation board */
+
+#define	PPC403SPU_IO_BASE      	0x40000000	/* 403 On-chip serial port */
+#define	PPC403SPU_IO_SIZE      	0x00000008
+#define	OAKSERIAL_IO_BASE	0x7E000000	/* NS16550DV serial port */
+#define	OAKSERIAL_IO_SIZE	0x00000008
+#define	OAKNET_IO_BASE		0xF4000000	/* NS83902AV Ethernet */
+#define	OAKNET_IO_SIZE		0x00000040
+#define	OAKPROM_IO_BASE		0xFFFE0000	/* AMD 29F010 Flash ROM */
+#define	OAKPROM_IO_SIZE		0x00020000
+
+
+/* Interrupt assignments fixed by the hardware implementation */
+
+/* This is annoying kbuild-2.4 problem. -- Tom */
+
+#define	PPC403SPU_RX_INT	4	/* AIC_INT4 */
+#define	PPC403SPU_TX_INT	5	/* AIC_INT5 */
+#define	OAKNET_INT		27	/* AIC_INT27 */
+#define	OAKSERIAL_INT		28	/* AIC_INT28 */
+
+#ifndef __ASSEMBLY__
+/*
+ * Data structure defining board information maintained by the boot
+ * ROM on IBM's "Oak" evaluation board. An effort has been made to
+ * keep the field names consistent with the 8xx 'bd_t' board info
+ * structures.
+ */
+
+typedef struct board_info {
+	unsigned char	 bi_s_version[4];	/* Version of this structure */
+	unsigned char	 bi_r_version[30];	/* Version of the IBM ROM */
+	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
+	unsigned char	 bi_enetaddr[6];	/* Ethernet MAC address */
+	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
+	unsigned int	 bi_busfreq;		/* Bus speed, in Hz */
+} bd_t;
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __OAK_H__ */
+#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/oak_setup.c linux-2.4.20/arch/ppc/platforms/oak_setup.c
--- linux-2.4.19/arch/ppc/platforms/oak_setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/oak_setup.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,293 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *
+ *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: oak_setup.c
+ *
+ *    Description:
+ *      Architecture- / platform-specific boot-time initialization code for
+ *      the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
+ *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
+ *      <dan@net4x.com>.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+
+#include <asm/processor.h>
+#include <asm/board.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/bootinfo.h>
+#include <asm/ppc4xx_pic.h>
+#include <asm/time.h>
+
+#include "oak_setup.h"
+
+/* Function Prototypes */
+
+extern void abort(void);
+
+/* Global Variables */
+
+unsigned char __res[sizeof(bd_t)];
+
+
+/*
+ * void __init oak_init()
+ *
+ * Description:
+ *   This routine...
+ *
+ * Input(s):
+ *   r3 - Optional pointer to a board information structure.
+ *   r4 - Optional pointer to the physical starting address of the init RAM
+ *        disk.
+ *   r5 - Optional pointer to the physical ending address of the init RAM
+ *        disk.
+ *   r6 - Optional pointer to the physical starting address of any kernel
+ *        command-line parameters.
+ *   r7 - Optional pointer to the physical ending address of any kernel
+ *        command-line parameters.
+ *
+ * Output(s):
+ *   N/A
+ *
+ * Returns:
+ *   N/A
+ *
+ */
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	parse_bootinfo(find_bootinfo());
+
+	/*
+	 * If we were passed in a board information, copy it into the
+	 * residual data area.
+	 */
+	if (r3) {
+		memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t));
+	}
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+	/*
+	 * If the init RAM disk has been configured in, and there's a valid
+	 * starting address for it, set it up.
+	 */
+	if (r4) {
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	/* Copy the kernel command line arguments to a safe place. */
+
+	if (r6) {
+ 		*(char *)(r7 + KERNELBASE) = 0;
+		strcpy(cmd_line, (char *)(r6 + KERNELBASE));
+	}
+
+	/* Initialize machine-dependency vectors */
+
+	ppc_md.setup_arch	 	= oak_setup_arch;
+	ppc_md.show_percpuinfo	 	= oak_show_percpuinfo;
+	ppc_md.irq_cannonicalize 	= NULL;
+	ppc_md.init_IRQ		 	= oak_init_IRQ;
+	ppc_md.get_irq		 	= oak_get_irq;
+	ppc_md.init		 	= NULL;
+
+	ppc_md.restart		 	= oak_restart;
+	ppc_md.power_off	 	= oak_power_off;
+	ppc_md.halt		 	= oak_halt;
+
+	ppc_md.time_init	 	= oak_time_init;
+	ppc_md.set_rtc_time	 	= oak_set_rtc_time;
+	ppc_md.get_rtc_time	 	= oak_get_rtc_time;
+	ppc_md.calibrate_decr	 	= oak_calibrate_decr;
+
+	ppc_md.kbd_setkeycode    	= NULL;
+	ppc_md.kbd_getkeycode    	= NULL;
+	ppc_md.kbd_translate     	= NULL;
+	ppc_md.kbd_unexpected_up 	= NULL;
+	ppc_md.kbd_leds          	= NULL;
+	ppc_md.kbd_init_hw       	= NULL;
+	ppc_md.ppc_kbd_sysrq_xlate	= NULL;
+}
+
+/*
+ * Document me.
+ */
+void __init
+oak_setup_arch(void)
+{
+	/* XXX - Implement me */
+}
+
+/*
+ * int oak_show_percpuinfo()
+ *
+ * Description:
+ *   This routine pretty-prints the platform's internal CPU and bus clock
+ *   frequencies into the buffer for usage in /proc/cpuinfo.
+ *
+ * Input(s):
+ *  *buffer - Buffer into which CPU and bus clock frequencies are to be
+ *            printed.
+ *
+ * Output(s):
+ *  *buffer - Buffer with the CPU and bus clock frequencies.
+ *
+ * Returns:
+ *   The number of bytes copied into 'buffer' if OK, otherwise zero or less
+ *   on error.
+ */
+int
+oak_show_percpuinfo(struct seq_file *m, int i)
+{
+	bd_t *bp = (bd_t *)__res;
+
+	seq_printf(m, "clock\t\t: %dMHz\n"
+		   "bus clock\t\t: %dMHz\n",
+		   bp->bi_intfreq / 1000000,
+		   bp->bi_busfreq / 1000000);
+
+	return 0;
+}
+
+/*
+ * Document me.
+ */
+void __init
+oak_init_IRQ(void)
+{
+	int i;
+
+	ppc4xx_pic_init();
+
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc[i].handler = ppc4xx_pic;
+	}
+
+	return;
+}
+
+/*
+ * Document me.
+ */
+int
+oak_get_irq(struct pt_regs *regs)
+{
+	return (ppc4xx_pic_get_irq(regs));
+}
+
+/*
+ * Document me.
+ */
+void
+oak_restart(char *cmd)
+{
+	abort();
+}
+
+/*
+ * Document me.
+ */
+void
+oak_power_off(void)
+{
+	oak_restart(NULL);
+}
+
+/*
+ * Document me.
+ */
+void
+oak_halt(void)
+{
+	oak_restart(NULL);
+}
+
+/*
+ * Document me.
+ */
+long __init
+oak_time_init(void)
+{
+	/* XXX - Implement me */
+	return 0;
+}
+
+/*
+ * Document me.
+ */
+int __init
+oak_set_rtc_time(unsigned long time)
+{
+	/* XXX - Implement me */
+
+	return (0);
+}
+
+/*
+ * Document me.
+ */
+unsigned long __init
+oak_get_rtc_time(void)
+{
+	/* XXX - Implement me */
+
+	return (0);
+}
+
+/*
+ * void __init oak_calibrate_decr()
+ *
+ * Description:
+ *   This routine retrieves the internal processor frequency from the board
+ *   information structure, sets up the kernel timer decrementer based on
+ *   that value, enables the 403 programmable interval timer (PIT) and sets
+ *   it up for auto-reload.
+ *
+ * Input(s):
+ *   N/A
+ *
+ * Output(s):
+ *   N/A
+ *
+ * Returns:
+ *   N/A
+ *
+ */
+void __init
+oak_calibrate_decr(void)
+{
+	unsigned int freq;
+	bd_t *bip = (bd_t *)__res;
+
+	freq = bip->bi_intfreq;
+
+	decrementer_count = freq / HZ;
+	count_period_num = 1;
+	count_period_den = freq;
+
+	/* Enable the PIT and set auto-reload of its value */
+
+	mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
+
+	/* Clear any pending timer interrupts */
+
+	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/oak_setup.h linux-2.4.20/arch/ppc/platforms/oak_setup.h
--- linux-2.4.19/arch/ppc/platforms/oak_setup.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/oak_setup.h	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,53 @@
+/*
+ * BK Id: SCCS/s.oak_setup.h 1.5 05/17/01 18:14:21 cort
+ */
+/*
+ *
+ *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: oak_setup.h
+ *
+ *    Description:
+ *      Architecture- / platform-specific boot-time initialization code for
+ *      the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
+ *      code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
+ *      <dan@netx4.com>.
+ *
+ */
+
+#ifndef	__OAK_SETUP_H__
+#define	__OAK_SETUP_H__
+
+#include <asm/ptrace.h>
+#include <asm/board.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned char	 __res[sizeof(bd_t)];
+
+extern void		 oak_init(unsigned long r3,
+				  unsigned long ird_start,
+				  unsigned long ird_end,
+				  unsigned long cline_start,
+				  unsigned long cline_end);
+extern void		 oak_setup_arch(void);
+extern int		 oak_setup_residual(char *buffer);
+extern void		 oak_init_IRQ(void);
+extern int		 oak_get_irq(struct pt_regs *regs);
+extern void		 oak_restart(char *cmd);
+extern void		 oak_power_off(void);
+extern void		 oak_halt(void);
+extern void		 oak_time_init(void);
+extern int		 oak_set_rtc_time(unsigned long now);
+extern unsigned long	 oak_get_rtc_time(void);
+extern void		 oak_calibrate_decr(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __OAK_SETUP_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/pal4.h linux-2.4.20/arch/ppc/platforms/pal4.h
--- linux-2.4.19/arch/ppc/platforms/pal4.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/pal4.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,68 @@
+/*
+ * arch/ppc/platforms/pal4.h
+ * 
+ * Definitions for SBS Palomar IV board
+ *
+ * Author: Dan Cox
+ *
+ * Copyright 2002 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.
+ */
+
+#ifndef __PPC_PLATFORMS_PAL4_H
+#define __PPC_PLATFORMS_PAL4_H
+
+#include <asm/io.h>
+
+#define CPC700_MEM_CFGADDR    0xff500008
+#define CPC700_MEM_CFGDATA    0xff50000c
+
+#define CPC700_MB0SA            0x38
+#define CPC700_MB0EA            0x58
+#define CPC700_MB1SA            0x3c
+#define CPC700_MB1EA            0x5c
+#define CPC700_MB2SA            0x40
+#define CPC700_MB2EA            0x60
+#define CPC700_MB3SA            0x44
+#define CPC700_MB3EA            0x64
+#define CPC700_MB4SA            0x48
+#define CPC700_MB4EA            0x68
+
+extern inline long
+cpc700_read_memreg(int reg)
+{
+	out_be32((volatile unsigned int *) CPC700_MEM_CFGADDR, reg);
+	return in_be32((volatile unsigned int *) CPC700_MEM_CFGDATA);
+}
+
+
+#define PAL4_NVRAM             0xfffc0000
+#define PAL4_NVRAM_SIZE        0x8000
+
+#define PAL4_DRAM              0xfff80000
+#define  PAL4_DRAM_BR_MASK     0xc0
+#define  PAL4_DRAM_BR_SHIFT    6
+#define  PAL4_DRAM_RESET       0x10
+#define  PAL4_DRAM_EREADY      0x40
+
+#define PAL4_MISC              0xfff80004
+#define  PAL4_MISC_FB_MASK     0xc0
+#define  PAL4_MISC_FLASH       0x40  /* StratFlash mapping: 1->0xff80, 0->0xfff0 */
+#define  PAL4_MISC_MISC        0x08
+#define  PAL4_MISC_BITF        0x02
+#define  PAL4_MISC_NVKS        0x01
+
+#define PAL4_L2                0xfff80008
+#define  PAL4_L2_MASK          0x07
+
+#define PAL4_PLDR              0xfff8000c
+
+/* Only two Ethernet devices on the board... */
+#define PAL4_ETH               31
+#define PAL4_INTA              20
+
+#endif /* __PPC_PLATFORMS_PAL4_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/pal4_pci.c linux-2.4.20/arch/ppc/platforms/pal4_pci.c
--- linux-2.4.19/arch/ppc/platforms/pal4_pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/pal4_pci.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,78 @@
+/*
+ * arch/ppc/platforms/pal4_pci.c
+ * 
+ * PCI support for SBS Palomar IV
+ *
+ * Author: Dan Cox 
+ *
+ * Copyright 2002 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/byteorder.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/uaccess.h>
+
+#include "cpc700.h"
+#include "pal4.h"
+
+/* not much to this.... */
+static inline int __init
+pal4_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	if (idsel == 9)
+		return PAL4_ETH;
+	else
+		return PAL4_INTA + (idsel - 3);
+}
+
+void __init
+pal4_find_bridges(void)
+{
+	struct pci_controller *hose;
+
+	hose = pcibios_alloc_controller();
+	if (!hose)
+		return;
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+	hose->pci_mem_offset = 0;
+
+	/* Could snatch these from the CPC700.... */
+	pci_init_resource(&hose->io_resource,
+			  0x0, 
+			  0x03ffffff,
+			  IORESOURCE_IO,
+			  "PCI host bridge");
+
+	pci_init_resource(&hose->mem_resources[0],
+			  0x90000000,
+			  0x9fffffff,
+			  IORESOURCE_MEM,
+			  "PCI host bridge");
+
+	hose->io_space.start = 0x00800000;
+	hose->io_space.end = 0x03ffffff;
+	hose->mem_space.start = 0x90000000;
+	hose->mem_space.end = 0x9fffffff;
+	hose->io_base_virt = (void *) 0xf8000000;
+	
+	setup_indirect_pci(hose, CPC700_PCI_CONFIG_ADDR,
+			   CPC700_PCI_CONFIG_DATA);
+	
+	hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+	ppc_md.pci_swizzle = common_swizzle;
+	ppc_md.pci_map_irq = pal4_map_irq;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/pal4_serial.h linux-2.4.20/arch/ppc/platforms/pal4_serial.h
--- linux-2.4.19/arch/ppc/platforms/pal4_serial.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/pal4_serial.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,41 @@
+/*
+ * arch/ppc/platforms/pal4_serial.h
+ * 
+ * Definitions for SBS PalomarIV serial support 
+ *
+ * Author: Dan Cox
+ *
+ * Copyright 2002 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.
+ */
+
+#ifndef __PPC_PAL4_SERIAL_H
+#define __PPC_PAL4_SERIAL_H
+
+#define CPC700_SERIAL_1       0xff600300
+#define CPC700_SERIAL_2       0xff600400
+
+#define RS_TABLE_SIZE     2
+#define BASE_BAUD         (33333333 / 4 / 16)
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF)
+#endif
+
+#define SERIAL_PORT_DFNS \
+      {0, BASE_BAUD, CPC700_SERIAL_1, 3, STD_COM_FLAGS, \
+       iomem_base: (unsigned char *) CPC700_SERIAL_1, \
+       io_type: SERIAL_IO_MEM},   /* ttyS0 */ \
+      {0, BASE_BAUD, CPC700_SERIAL_2, 4, STD_COM_FLAGS, \
+       iomem_base: (unsigned char *) CPC700_SERIAL_2, \
+       io_type: SERIAL_IO_MEM}
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/pal4_setup.c linux-2.4.20/arch/ppc/platforms/pal4_setup.c
--- linux-2.4.19/arch/ppc/platforms/pal4_setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/pal4_setup.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,199 @@
+/*
+ * arch/ppc/platforms/pal4_setup.c
+ *
+ * Board setup routines for the SBS PalomarIV.
+ *
+ * Author: Dan Cox
+ *
+ * Copyright 2002 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.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/time.h>
+#include <linux/irq.h>
+#include <linux/kdev_t.h>
+#include <linux/blk.h>
+#include <linux/console.h>
+#include <linux/seq_file.h>
+
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+
+#include "cpc700.h"
+#include "pal4.h"
+
+extern void pal4_find_bridges(void);
+
+unsigned int cpc700_irq_assigns[][2] = {
+        {1, 1},    /* IRQ 0: ECC correctable error */
+        {1, 1},    /* IRQ 1: PCI write to memory range */
+        {0, 1},    /* IRQ 2: PCI write to command register */
+        {0, 1},    /* IRQ 3: UART 0 */
+        {0, 1},    /* IRQ 4: UART 1 */
+        {0, 1},    /* IRQ 5: ICC 0 */
+        {0, 1},    /* IRQ 6: ICC 1 */
+        {0, 1},    /* IRQ 7: GPT compare 0 */
+        {0, 1},    /* IRQ 8: GPT compare 1 */
+        {0, 1},    /* IRQ 9: GPT compare 2 */
+        {0, 1},    /* IRQ 10: GPT compare 3 */
+        {0, 1},    /* IRQ 11: GPT compare 4 */
+        {0, 1},    /* IRQ 12: GPT capture 0 */
+        {0, 1},    /* IRQ 13: GPT capture 1 */
+        {0, 1},    /* IRQ 14: GPT capture 2 */
+        {0, 1},    /* IRQ 15: GPT capture 3 */
+        {0, 1},    /* IRQ 16: GPT capture 4 */
+        {0, 0},    /* IRQ 17: reserved */
+        {0, 0},    /* IRQ 18: reserved */
+        {0, 0},    /* IRQ 19: reserved */
+        {0, 0},    /* IRQ 20: reserved */
+        {0, 1},    /* IRQ 21: Ethernet */
+        {0, 0},    /* IRQ 22: reserved */
+        {0, 0},    /* IRQ 23: reserved */
+        {0, 0},    /* IRQ 24: resreved */
+        {0, 0},    /* IRQ 25: reserved */
+        {0, 0},    /* IRQ 26: reserved */
+        {0, 0},    /* IRQ 27: reserved */
+        {0, 0},    /* IRQ 28: reserved */
+        {0, 0},    /* IRQ 29: reserved */
+        {0, 0},    /* IRQ 30: reserved */
+        {0, 0},    /* IRQ 31: reserved */
+};
+
+static int
+pal4_show_cpuinfo(struct seq_file *m)
+{
+        seq_printf(m, "board\t\t: SBS Palomar IV\n");
+
+        return 0;
+}
+
+static void
+pal4_restart(char *cmd)
+{
+        __cli();
+        __asm__ __volatile__("lis  3,0xfff0\n \
+                              ori  3,3,0x100\n \
+                              mtspr 26,3\n \
+                              li   3,0\n \
+                              mtspr 27,3\n \
+                              rfi");
+
+        for(;;);
+}
+
+static void
+pal4_power_off(void)
+{
+	__cli();
+	for(;;);
+}
+
+static void
+pal4_halt(void)
+{
+	pal4_power_off();
+}
+
+static unsigned long __init
+pal4_find_end_of_memory(void)
+{
+	int i;
+	unsigned long len, amt, batu, batl;
+
+        __asm__ __volatile__("lis  %0,0xf000\n \
+                              ori  %1,%0,0x002a\n \
+                              ori  %0,%0,0x1ffe\n \
+                              mtspr 0x21e,%0\n \
+                              mtspr 0x21f,%1\n \
+                              isync\n \
+                              sync" : "=r" (batu), "=r" (batl));
+
+	for(len = 0, i = CPC700_MB1EA; i <= CPC700_MB4EA; i+=4) {
+		amt = cpc700_read_memreg(i);
+		if (amt == 0)
+			break;
+		len = amt;
+	}
+
+	return len;
+}
+
+TODC_ALLOC();
+
+static void __init
+pal4_setup_arch(void)
+{
+	unsigned long l2;
+
+	TODC_INIT(TODC_TYPE_MK48T37, 0, 0, 
+		  ioremap(PAL4_NVRAM, PAL4_NVRAM_SIZE), 8);
+
+	pal4_find_bridges();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+	else
+#endif
+		ROOT_DEV = to_kdev_t(0x00ff);
+
+	/* The L2 gets disabled in the bootloader, but all the proper
+	   bits should be present from the fw, so just re-enable it */
+	l2 = _get_L2CR();
+	if (!(l2 & L2CR_L2E)) {
+		/* presume that it was initially set if the size is
+		   still present. */
+		if (l2 ^ L2CR_L2SIZ_MASK)
+			_set_L2CR(l2 | L2CR_L2E);
+		else
+			printk("L2 not set by firmware; left disabled.\n");
+	}
+}
+
+static void __init
+pal4_map_io(void)
+{
+	io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	parse_bootinfo(find_bootinfo());
+
+	isa_io_base = 0 /*PAL4_ISA_IO_BASE*/;
+	pci_dram_offset = 0 /*PAL4_PCI_SYS_MEM_BASE*/;
+	
+	ppc_md.setup_arch = pal4_setup_arch;
+	ppc_md.show_cpuinfo = pal4_show_cpuinfo;
+	
+	ppc_md.find_end_of_memory = pal4_find_end_of_memory;
+	ppc_md.setup_io_mappings = pal4_map_io;
+
+	ppc_md.init_IRQ = cpc700_init_IRQ;
+	ppc_md.get_irq = cpc700_get_irq;
+
+	ppc_md.restart = pal4_restart;
+	ppc_md.halt = pal4_halt;
+	ppc_md.power_off = pal4_power_off;
+
+	ppc_md.time_init = todc_time_init;
+	ppc_md.set_rtc_time = todc_set_rtc_time;
+	ppc_md.get_rtc_time = todc_get_rtc_time;
+	ppc_md.calibrate_decr = todc_calibrate_decr;
+
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/pmac_backlight.c linux-2.4.20/arch/ppc/platforms/pmac_backlight.c
--- linux-2.4.19/arch/ppc/platforms/pmac_backlight.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/pmac_backlight.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,150 @@
+/*
+ * BK Id: SCCS/s.pmac_backlight.c 1.10 12/01/01 20:09:06 benh
+ */
+/*
+ * Miscellaneous procedures for dealing with the PowerMac hardware.
+ * Contains support for the backlight.
+ * 
+ *   Copyright (C) 2000 Benjamin Herrenschmidt
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/reboot.h>
+#include <linux/nvram.h>
+#include <asm/sections.h>
+#include <asm/ptrace.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/nvram.h>
+#include <asm/backlight.h>
+
+#include <linux/adb.h>
+#include <linux/pmu.h>
+
+static struct backlight_controller *backlighter = NULL;
+static void* backlighter_data = NULL;
+static int backlight_autosave = 0;
+static int backlight_level = BACKLIGHT_MAX;
+static int backlight_enabled = 1;
+
+void __pmac
+register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type)
+{
+	struct device_node* bk_node;
+	char *prop;
+	int valid = 0;
+
+	bk_node = find_devices("backlight");
+	
+#ifdef CONFIG_ADB_PMU
+	/* Special case for the old PowerBook since I can't test on it */
+	backlight_autosave = machine_is_compatible("AAPL,3400/2400")
+		|| machine_is_compatible("AAPL,3500");
+	if ((backlight_autosave
+	     || machine_is_compatible("AAPL,PowerBook1998")
+	     || machine_is_compatible("PowerBook1,1"))
+	    && !strcmp(type, "pmu"))
+		valid = 1;
+#endif
+	if (bk_node) {
+		prop = get_property(bk_node, "backlight-control", NULL);
+		if (prop && !strncmp(prop, type, strlen(type)))
+			valid = 1;
+	}
+	if (!valid)
+		return;
+	backlighter = ctrler;
+	backlighter_data = data;
+	
+	if (bk_node && !backlight_autosave)
+		prop = get_property(bk_node, "bklt", NULL);
+	else
+		prop = NULL;
+	if (prop) {
+		backlight_level = ((*prop)+1) >> 1;
+		if (backlight_level > BACKLIGHT_MAX)
+			backlight_level = BACKLIGHT_MAX;
+	}
+	
+#ifdef CONFIG_ADB_PMU
+	if (backlight_autosave) {
+		struct adb_request req;
+		pmu_request(&req, NULL, 2, 0xd9, 0);
+		while (!req.complete)
+			pmu_poll();
+		backlight_level = req.reply[0] >> 4;
+	}
+#endif
+	if (!backlighter->set_enable(1, backlight_level, data))
+		backlight_enabled = 1;
+
+	printk(KERN_INFO "Registered \"%s\" backlight controller, level: %d/15\n",
+		type, backlight_level);
+}
+
+void __pmac
+unregister_backlight_controller(struct backlight_controller *ctrler, void *data)
+{
+	/* We keep the current backlight level (for now) */
+	if (ctrler == backlighter && data == backlighter_data)
+		backlighter = NULL;
+}
+
+int __pmac
+set_backlight_enable(int enable)
+{
+	int rc;
+	
+	if (!backlighter)
+		return -ENODEV;
+	rc = backlighter->set_enable(enable, backlight_level, backlighter_data);
+	if (!rc)
+		backlight_enabled = enable;
+	return rc;
+}
+
+int __pmac
+get_backlight_enable(void)
+{
+	if (!backlighter)
+		return -ENODEV;
+	return backlight_enabled;
+}
+
+int __pmac
+set_backlight_level(int level)
+{
+	int rc = 0;
+	
+	if (!backlighter)
+		return -ENODEV;
+	if (level < BACKLIGHT_MIN)
+		level = BACKLIGHT_OFF;
+	if (level > BACKLIGHT_MAX)
+		level = BACKLIGHT_MAX;
+	if (backlight_enabled)
+		rc = backlighter->set_level(level, backlighter_data);
+	if (!rc)
+		backlight_level = level;
+	if (!rc && !backlight_autosave) {
+		level <<=1;
+		if (level & 0x10)
+			level |= 0x01;
+		// -- todo: save to property "bklt"
+	}
+	return rc;
+}
+
+int __pmac
+get_backlight_level(void)
+{
+	if (!backlighter)
+		return -ENODEV;
+	return backlight_level;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/pmac_feature.c linux-2.4.20/arch/ppc/platforms/pmac_feature.c
--- linux-2.4.19/arch/ppc/platforms/pmac_feature.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/pmac_feature.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,2263 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/platform/pmac_feature.c
+ *
+ *  Copyright (C) 1996-2002 Paul Mackerras (paulus@cs.anu.edu.au)
+ *                          Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *
+ *  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.
+ *  
+ *  TODO: 
+ *  
+ *   - Replace mdelay with some schedule loop if possible
+ *   - Shorten some obfuscated delays on some routines (like modem
+ *     power)
+ *
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <asm/sections.h>
+#include <asm/errno.h>
+#include <asm/ohare.h>
+#include <asm/heathrow.h>
+#include <asm/keylargo.h>
+#include <asm/uninorth.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/dbdma.h>
+#include <asm/pci-bridge.h>
+
+#undef DEBUG_FEATURE
+
+#ifdef DEBUG_FEATURE
+#define DBG(fmt,...) printk(KERN_DEBUG fmt)
+#else
+#define DBG(fmt,...)
+#endif
+
+/* Exported from arch/ppc/kernel/idle.c */
+extern unsigned long powersave_nap;
+extern unsigned long powersave_lowspeed;
+
+/*
+ * We use a single global lock to protect accesses. Each driver has
+ * to take care of it's own locking
+ */
+static spinlock_t feature_lock  __pmacdata = SPIN_LOCK_UNLOCKED;
+
+#define LOCK(flags)	spin_lock_irqsave(&feature_lock, flags);
+#define UNLOCK(flags)	spin_unlock_irqrestore(&feature_lock, flags);
+
+/*
+ * Helper functions regarding the various flavors of mac-io
+ */
+ 
+#define MAX_MACIO_CHIPS		2
+
+enum {
+	macio_unknown = 0,
+	macio_grand_central,
+	macio_ohare,
+	macio_ohareII,
+	macio_heathrow,
+	macio_gatwick,
+	macio_paddington,
+	macio_keylargo,
+	macio_pangea
+};
+
+static const char* macio_names[] __pmacdata = 
+{
+	"Unknown",
+	"Grand Central",
+	"OHare",
+	"OHareII",
+	"Heathrow",
+	"Gatwick",
+	"Paddington",
+	"Keylargo",
+	"Pangea"
+};
+
+static struct macio_chip
+{
+	struct device_node*	of_node;
+	int			type;
+	int			rev;
+	volatile u32*		base;
+	unsigned long		flags;
+} macio_chips[MAX_MACIO_CHIPS]  __pmacdata;
+
+#define MACIO_FLAG_SCCA_ON	0x00000001
+#define MACIO_FLAG_SCCB_ON	0x00000002
+#define MACIO_FLAG_SCC_LOCKED	0x00000004
+#define MACIO_FLAG_AIRPORT_ON	0x00000010
+#define MACIO_FLAG_FW_SUPPORTED	0x00000020
+
+static struct macio_chip* __pmac
+macio_find(struct device_node* child, int type)
+{
+	while(child) {
+		int	i;
+	
+		for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++)
+			if (child == macio_chips[i].of_node &&
+			    (!type || macio_chips[i].type == type))
+				return &macio_chips[i];
+		child = child->parent;
+	}
+	return NULL;
+}
+
+#define MACIO_FCR32(macio, r)	((macio)->base + ((r) >> 2))
+#define MACIO_FCR8(macio, r)	(((volatile u8*)((macio)->base)) + (r))
+
+#define MACIO_IN32(r)		(in_le32(MACIO_FCR32(macio,r)))
+#define MACIO_OUT32(r,v)	(out_le32(MACIO_FCR32(macio,r), (v)))
+#define MACIO_BIS(r,v)		(MACIO_OUT32((r), MACIO_IN32(r) | (v)))
+#define MACIO_BIC(r,v)		(MACIO_OUT32((r), MACIO_IN32(r) & ~(v)))
+#define MACIO_IN8(r)		(in_8(MACIO_FCR8(macio,r)))
+#define MACIO_OUT8(r,v)		(out_8(MACIO_FCR8(macio,r), (v)))
+
+/*
+ * Uninorth reg. access. Note that Uni-N regs are big endian
+ */
+ 
+#define UN_REG(r)	(uninorth_base + ((r) >> 2))
+#define UN_IN(r)	(in_be32(UN_REG(r)))
+#define UN_OUT(r,v)	(out_be32(UN_REG(r), (v)))
+#define UN_BIS(r,v)	(UN_OUT((r), UN_IN(r) | (v)))
+#define UN_BIC(r,v)	(UN_OUT((r), UN_IN(r) & ~(v)))
+
+static struct device_node* uninorth_node __pmacdata;
+static u32* uninorth_base __pmacdata;
+static u32 uninorth_rev __pmacdata;
+
+
+/*
+ * For each motherboard family, we have a table of functions pointers
+ * that handle the various features.
+ */
+
+typedef int (*feature_call)(struct device_node* node, int param, int value);
+
+struct feature_table_entry {
+	unsigned int	selector;	
+	feature_call	function;
+};
+
+struct pmac_mb_def
+{
+	const char*			model_string;
+	const char*			model_name;
+	int				model_id;
+	struct feature_table_entry* 	features;
+	unsigned long			board_flags;
+};
+static struct pmac_mb_def pmac_mb __pmacdata;
+
+/*
+ * Here are the chip specific feature functions
+ */
+
+static inline int __pmac
+simple_feature_tweak(struct device_node* node, int type, int reg, u32 mask, int value)
+{
+	struct macio_chip*	macio;
+	unsigned long		flags;
+	
+	macio = macio_find(node, type);
+	if (!macio)
+		return -ENODEV;
+	LOCK(flags);
+	if (value)
+		MACIO_BIS(reg, mask);
+	else
+		MACIO_BIC(reg, mask);
+	(void)MACIO_IN32(reg);
+	UNLOCK(flags);
+
+	return 0;
+}
+
+static int __pmac
+ohare_htw_scc_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	unsigned long		chan_mask;
+	unsigned long		fcr;
+	unsigned long		flags;
+	int			htw, trans;
+	unsigned long		rmask;
+	
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+	if (!strcmp(node->name, "ch-a"))
+		chan_mask = MACIO_FLAG_SCCA_ON;
+	else if (!strcmp(node->name, "ch-b"))
+		chan_mask = MACIO_FLAG_SCCB_ON;
+	else
+		return -ENODEV;
+
+	htw = (macio->type == macio_heathrow || macio->type == macio_paddington
+		|| macio->type == macio_gatwick);
+	/* On these machines, the HRW_SCC_TRANS_EN_N bit mustn't be touched */
+	trans = (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
+	    	 pmac_mb.model_id != PMAC_TYPE_YIKES);
+	if (value) {
+#ifdef CONFIG_ADB_PMU
+		if ((param & 0xfff) == PMAC_SCC_IRDA)
+			pmu_enable_irled(1);
+#endif /* CONFIG_ADB_PMU */		
+		LOCK(flags);
+		fcr = MACIO_IN32(OHARE_FCR);
+		/* Check if scc cell need enabling */
+		if (!(fcr & OH_SCC_ENABLE)) {
+			fcr |= OH_SCC_ENABLE;
+			if (htw) {
+				/* Side effect: this will also power up the
+				 * modem, but it's too messy to figure out on which
+				 * ports this controls the tranceiver and on which
+				 * it controls the modem
+				 */
+				if (trans)
+					fcr &= ~HRW_SCC_TRANS_EN_N;
+				MACIO_OUT32(OHARE_FCR, fcr);
+				fcr |= (rmask = HRW_RESET_SCC);
+				MACIO_OUT32(OHARE_FCR, fcr);
+			} else {
+				fcr |= (rmask = OH_SCC_RESET);
+				MACIO_OUT32(OHARE_FCR, fcr);
+			}
+			UNLOCK(flags);
+			(void)MACIO_IN32(OHARE_FCR);
+			mdelay(15);
+			LOCK(flags);
+			fcr &= ~rmask;
+			MACIO_OUT32(OHARE_FCR, fcr);
+		}
+		if (chan_mask & MACIO_FLAG_SCCA_ON)
+			fcr |= OH_SCCA_IO;
+		if (chan_mask & MACIO_FLAG_SCCB_ON)
+			fcr |= OH_SCCB_IO;
+		MACIO_OUT32(OHARE_FCR, fcr);
+		macio->flags |= chan_mask;
+		UNLOCK(flags);
+		if (param & PMAC_SCC_FLAG_XMON)
+			macio->flags |= MACIO_FLAG_SCC_LOCKED;
+	} else {
+		if (macio->flags & MACIO_FLAG_SCC_LOCKED)
+			return -EPERM;
+		LOCK(flags);
+		fcr = MACIO_IN32(OHARE_FCR);
+		if (chan_mask & MACIO_FLAG_SCCA_ON)
+			fcr &= ~OH_SCCA_IO;
+		if (chan_mask & MACIO_FLAG_SCCB_ON)
+			fcr &= ~OH_SCCB_IO;
+		MACIO_OUT32(OHARE_FCR, fcr);
+		if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) {
+			fcr &= ~OH_SCC_ENABLE;
+			if (htw && trans)
+				fcr |= HRW_SCC_TRANS_EN_N;
+			MACIO_OUT32(OHARE_FCR, fcr);
+		}
+		macio->flags &= ~(chan_mask);
+		UNLOCK(flags);
+		mdelay(10);
+#ifdef CONFIG_ADB_PMU
+		if ((param & 0xfff) == PMAC_SCC_IRDA)
+			pmu_enable_irled(0);
+#endif /* CONFIG_ADB_PMU */		
+	}
+	return 0;
+}
+
+static int __pmac
+ohare_floppy_enable(struct device_node* node, int param, int value)
+{
+	return simple_feature_tweak(node, macio_ohare,
+		OHARE_FCR, OH_FLOPPY_ENABLE, value);
+}
+
+static int __pmac
+ohare_mesh_enable(struct device_node* node, int param, int value)
+{
+	return simple_feature_tweak(node, macio_ohare,
+		OHARE_FCR, OH_MESH_ENABLE, value);
+}
+
+static int __pmac
+ohare_ide_enable(struct device_node* node, int param, int value)
+{
+	switch(param) {
+	    case 0:
+	    	/* For some reason, setting the bit in set_initial_features()
+	    	 * doesn't stick. I'm still investigating... --BenH.
+	    	 */
+	    	if (value)
+	    		simple_feature_tweak(node, macio_ohare,
+				OHARE_FCR, OH_IOBUS_ENABLE, 1);
+		return simple_feature_tweak(node, macio_ohare,
+			OHARE_FCR, OH_IDE0_ENABLE, value);
+	    case 1:
+		return simple_feature_tweak(node, macio_ohare,
+			OHARE_FCR, OH_BAY_IDE_ENABLE, value);
+	    default:
+	    	return -ENODEV;
+	}
+}
+
+static int __pmac
+ohare_ide_reset(struct device_node* node, int param, int value)
+{
+	switch(param) {
+	    case 0:
+		return simple_feature_tweak(node, macio_ohare,
+			OHARE_FCR, OH_IDE0_RESET_N, !value);
+	    case 1:
+		return simple_feature_tweak(node, macio_ohare,
+			OHARE_FCR, OH_IDE1_RESET_N, !value);
+	    default:
+	    	return -ENODEV;
+	}
+}
+
+static int __pmac
+ohare_sleep_state(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio = &macio_chips[0];
+
+	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
+		return -EPERM;
+	if (value == 1) {
+		MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE);
+	} else if (value == 0) {
+		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+	}
+	
+	return 0;
+}
+
+static int __pmac
+heathrow_modem_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	u8			gpio;
+	unsigned long		flags;
+	
+	macio = macio_find(node, macio_unknown);
+	if (!macio)
+		return -ENODEV;
+	gpio = MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1;
+	if (!value) {
+		LOCK(flags);
+		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
+		UNLOCK(flags);
+		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
+		mdelay(250);
+	}
+	if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
+	    pmac_mb.model_id != PMAC_TYPE_YIKES) {
+	    	LOCK(flags);
+	    	if (value)
+	    		MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
+	    	else
+	    		MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
+	    	UNLOCK(flags);
+	    	(void)MACIO_IN32(HEATHROW_FCR);
+		mdelay(250);
+	}
+	if (value) {
+		LOCK(flags);
+		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
+		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
+		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
+		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250);
+	}
+	return 0;
+}
+
+static int __pmac
+heathrow_floppy_enable(struct device_node* node, int param, int value)
+{
+	return simple_feature_tweak(node, macio_unknown,
+		HEATHROW_FCR,
+		HRW_SWIM_ENABLE|HRW_BAY_FLOPPY_ENABLE,
+		value);
+}
+
+static int __pmac
+heathrow_mesh_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	unsigned long		flags;
+	
+	macio = macio_find(node, macio_unknown);
+	if (!macio)
+		return -ENODEV;
+	LOCK(flags);
+	/* Set clear mesh cell enable */
+	if (value)
+		MACIO_BIS(HEATHROW_FCR, HRW_MESH_ENABLE);
+	else
+		MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE);
+	(void)MACIO_IN32(HEATHROW_FCR);
+	udelay(10);
+	/* Set/Clear termination power (todo: test ! the bit value
+	 * used by Darwin doesn't seem to match what we used so
+	 * far. If you experience problems, turn #if 1 into #if 0
+	 * and tell me about it --BenH.
+	 */
+#if 1
+	if (value)
+		MACIO_BIC(HEATHROW_MBCR, 0x00000004);
+	else
+		MACIO_BIS(HEATHROW_MBCR, 0x00000004);
+#else
+	if (value)
+		MACIO_BIC(HEATHROW_MBCR, 0x00040000);
+	else
+		MACIO_BIS(HEATHROW_MBCR, 0x00040000);
+#endif		
+	(void)MACIO_IN32(HEATHROW_MBCR);
+	udelay(10);
+	UNLOCK(flags);
+
+	return 0;
+}
+
+static int __pmac
+heathrow_ide_enable(struct device_node* node, int param, int value)
+{
+	switch(param) {
+	    case 0:
+		return simple_feature_tweak(node, macio_unknown,
+			HEATHROW_FCR, HRW_IDE0_ENABLE, value);
+	    case 1:
+		return simple_feature_tweak(node, macio_unknown,
+			HEATHROW_FCR, HRW_BAY_IDE_ENABLE, value);
+	    default:
+	    	return -ENODEV;
+	}
+}
+
+static int __pmac
+heathrow_ide_reset(struct device_node* node, int param, int value)
+{
+	switch(param) {
+	    case 0:
+		return simple_feature_tweak(node, macio_unknown,
+			HEATHROW_FCR, HRW_IDE0_RESET_N, !value);
+	    case 1:
+		return simple_feature_tweak(node, macio_unknown,
+			HEATHROW_FCR, HRW_IDE1_RESET_N, !value);
+	    default:
+	    	return -ENODEV;
+	}
+}
+
+static int __pmac
+heathrow_bmac_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	unsigned long		flags;
+	
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+	if (value) {
+		LOCK(flags);
+		MACIO_BIS(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
+		MACIO_BIS(HEATHROW_FCR, HRW_BMAC_RESET);
+		UNLOCK(flags);
+		(void)MACIO_IN32(HEATHROW_FCR);
+		mdelay(10);
+		LOCK(flags);
+		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_RESET);
+		UNLOCK(flags);
+		(void)MACIO_IN32(HEATHROW_FCR);
+		mdelay(10);
+	} else {
+		LOCK(flags);
+		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
+		UNLOCK(flags);
+	}
+	return 0;
+}
+
+static int __pmac
+heathrow_sound_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	unsigned long		flags;
+
+	/* B&W G3 and Yikes don't support that properly (the
+	 * sound appear to never come back after beeing shut down).
+	 */
+	if (pmac_mb.model_id == PMAC_TYPE_YOSEMITE ||
+	    pmac_mb.model_id == PMAC_TYPE_YIKES)
+		return 0;
+	
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+	if (value) {
+		LOCK(flags);
+		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
+		UNLOCK(flags);
+		(void)MACIO_IN32(HEATHROW_FCR);
+	} else {
+		LOCK(flags);
+		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
+		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+		UNLOCK(flags);
+	}
+	return 0;
+}
+
+static u32 save_fcr[5] __pmacdata;
+static u32 save_mbcr __pmacdata;
+static u32 save_gpio_levels[2] __pmacdata;
+static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT] __pmacdata;
+static u8 save_gpio_normal[KEYLARGO_GPIO_CNT] __pmacdata;
+static u32 save_unin_clock_ctl __pmacdata;
+static struct dbdma_regs save_dbdma[13] __pmacdata;
+static struct dbdma_regs save_alt_dbdma[13] __pmacdata;
+
+static void __pmac
+dbdma_save(struct macio_chip* macio, struct dbdma_regs* save)
+{
+	int i;
+	
+	/* Save state & config of DBDMA channels */
+	for (i=0; i<13; i++) {
+		volatile struct dbdma_regs* chan = (volatile struct dbdma_regs*)
+			(macio->base + ((0x8000+i*0x100)>>2));
+		save[i].cmdptr_hi = in_le32(&chan->cmdptr_hi);
+		save[i].cmdptr = in_le32(&chan->cmdptr);
+		save[i].intr_sel = in_le32(&chan->intr_sel);
+		save[i].br_sel = in_le32(&chan->br_sel);
+		save[i].wait_sel = in_le32(&chan->wait_sel);
+	}
+}
+
+static void __pmac
+dbdma_restore(struct macio_chip* macio, struct dbdma_regs* save)
+{
+	int i;
+	
+	/* Save state & config of DBDMA channels */
+	for (i=0; i<13; i++) {
+		volatile struct dbdma_regs* chan = (volatile struct dbdma_regs*)
+			(macio->base + ((0x8000+i*0x100)>>2));
+		out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16);
+		while (in_le32(&chan->status) & ACTIVE)
+			mb();
+		out_le32(&chan->cmdptr_hi, save[i].cmdptr_hi);
+		out_le32(&chan->cmdptr, save[i].cmdptr);
+		out_le32(&chan->intr_sel, save[i].intr_sel);
+		out_le32(&chan->br_sel, save[i].br_sel);
+		out_le32(&chan->wait_sel, save[i].wait_sel);
+	}
+}
+
+static void __pmac
+heathrow_sleep(struct macio_chip* macio, int secondary)
+{
+	if (secondary) {
+		dbdma_save(macio, save_alt_dbdma);
+		save_fcr[2] = MACIO_IN32(0x38);
+		save_fcr[3] = MACIO_IN32(0x3c);
+	} else {
+		dbdma_save(macio, save_dbdma);
+		save_fcr[0] = MACIO_IN32(0x38);
+		save_fcr[1] = MACIO_IN32(0x3c);
+		save_mbcr = MACIO_IN32(0x34);
+		/* Make sure sound is shut down */
+		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
+		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+		/* This seems to be necessary as well or the fan
+		 * keeps coming up and battery drains fast */
+		MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE);
+		MACIO_BIC(HEATHROW_FCR, HRW_IDE0_RESET_N);
+		/* Make sure eth is down even if module or sleep
+		 * won't work properly */
+		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET);
+	}
+	/* Make sure modem is shut down */
+	MACIO_OUT8(HRW_GPIO_MODEM_RESET,
+		MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1);
+	MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
+	MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE);
+
+	/* Let things settle */
+	(void)MACIO_IN32(HEATHROW_FCR);
+	mdelay(1);
+}
+
+static void __pmac
+heathrow_wakeup(struct macio_chip* macio, int secondary)
+{
+	if (secondary) {
+		MACIO_OUT32(0x38, save_fcr[2]);
+		(void)MACIO_IN32(0x38);
+		mdelay(1);
+		MACIO_OUT32(0x3c, save_fcr[3]);
+		(void)MACIO_IN32(0x38);
+		mdelay(10);
+		dbdma_restore(macio, save_alt_dbdma);
+	} else {
+		MACIO_OUT32(0x38, save_fcr[0] | HRW_IOBUS_ENABLE);
+		(void)MACIO_IN32(0x38);
+		mdelay(1);
+		MACIO_OUT32(0x3c, save_fcr[1]);
+		(void)MACIO_IN32(0x38);
+		mdelay(1);
+		MACIO_OUT32(0x34, save_mbcr);
+		(void)MACIO_IN32(0x38);
+		mdelay(10);
+		dbdma_restore(macio, save_dbdma);
+	}
+}
+
+static int __pmac
+heathrow_sleep_state(struct device_node* node, int param, int value)
+{
+	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
+		return -EPERM;
+	if (value == 1) {
+		if (macio_chips[1].type == macio_gatwick)
+			heathrow_sleep(&macio_chips[0], 1);
+		heathrow_sleep(&macio_chips[0], 0);
+	} else if (value == 0) {
+		heathrow_wakeup(&macio_chips[0], 0);
+		if (macio_chips[1].type == macio_gatwick)
+			heathrow_wakeup(&macio_chips[0], 1);
+	}
+	return 0;
+}
+
+static int __pmac
+core99_scc_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	unsigned long		flags;
+	unsigned long		chan_mask;
+	u32			fcr;
+	
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+	if (!strcmp(node->name, "ch-a"))
+		chan_mask = MACIO_FLAG_SCCA_ON;
+	else if (!strcmp(node->name, "ch-b"))
+		chan_mask = MACIO_FLAG_SCCB_ON;
+	else
+		return -ENODEV;
+
+	if (value) {
+		int need_reset_scc = 0;
+		int need_reset_irda = 0;
+		
+		LOCK(flags);
+		fcr = MACIO_IN32(KEYLARGO_FCR0);
+		/* Check if scc cell need enabling */
+		if (!(fcr & KL0_SCC_CELL_ENABLE)) {
+			fcr |= KL0_SCC_CELL_ENABLE;
+			need_reset_scc = 1;
+		}
+		if (chan_mask & MACIO_FLAG_SCCA_ON) {
+			fcr |= KL0_SCCA_ENABLE;
+			/* Don't enable line drivers for I2S modem */
+			if ((param & 0xfff) == PMAC_SCC_I2S1)
+				fcr &= ~KL0_SCC_A_INTF_ENABLE;
+			else
+				fcr |= KL0_SCC_A_INTF_ENABLE;
+		}
+		if (chan_mask & MACIO_FLAG_SCCB_ON) {
+			fcr |= KL0_SCCB_ENABLE;
+			/* Perform irda specific inits */
+			if ((param & 0xfff) == PMAC_SCC_IRDA) {
+				fcr &= ~KL0_SCC_B_INTF_ENABLE;
+				fcr |= KL0_IRDA_ENABLE;
+				fcr |= KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE;
+				fcr |= KL0_IRDA_SOURCE1_SEL;
+				fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
+				fcr &= ~(KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
+				need_reset_irda = 1;
+			} else
+				fcr |= KL0_SCC_B_INTF_ENABLE;
+		}
+		MACIO_OUT32(KEYLARGO_FCR0, fcr);
+		macio->flags |= chan_mask;
+		if (need_reset_scc)  {
+			MACIO_BIS(KEYLARGO_FCR0, KL0_SCC_RESET);
+			(void)MACIO_IN32(KEYLARGO_FCR0);
+			UNLOCK(flags);
+			mdelay(15);
+			LOCK(flags);
+			MACIO_BIC(KEYLARGO_FCR0, KL0_SCC_RESET);
+		}
+		if (need_reset_irda)  {
+			MACIO_BIS(KEYLARGO_FCR0, KL0_IRDA_RESET);
+			(void)MACIO_IN32(KEYLARGO_FCR0);
+			UNLOCK(flags);
+			mdelay(15);
+			LOCK(flags);
+			MACIO_BIC(KEYLARGO_FCR0, KL0_IRDA_RESET);
+		}
+		UNLOCK(flags);
+		if (param & PMAC_SCC_FLAG_XMON)
+			macio->flags |= MACIO_FLAG_SCC_LOCKED;
+	} else {
+		if (macio->flags & MACIO_FLAG_SCC_LOCKED)
+			return -EPERM;
+		LOCK(flags);
+		fcr = MACIO_IN32(KEYLARGO_FCR0);
+		if (chan_mask & MACIO_FLAG_SCCA_ON)
+			fcr &= ~KL0_SCCA_ENABLE;
+		if (chan_mask & MACIO_FLAG_SCCB_ON) {
+			fcr &= ~KL0_SCCB_ENABLE;
+			/* Perform irda specific clears */
+			if ((param & 0xfff) == PMAC_SCC_IRDA) {
+				fcr &= ~KL0_IRDA_ENABLE;
+				fcr &= ~(KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE);
+				fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
+				fcr &= ~(KL0_IRDA_SOURCE1_SEL|KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
+			}
+		}
+		MACIO_OUT32(KEYLARGO_FCR0, fcr);
+		if ((fcr & (KL0_SCCA_ENABLE | KL0_SCCB_ENABLE)) == 0) {
+			fcr &= ~KL0_SCC_CELL_ENABLE;
+			MACIO_OUT32(KEYLARGO_FCR0, fcr);
+		}
+		macio->flags &= ~(chan_mask);
+		UNLOCK(flags);
+		mdelay(10);
+	}
+	return 0;
+}
+
+static int __pmac
+core99_modem_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	u8			gpio;
+	unsigned long		flags;
+
+	/* Hack for internal USB modem */
+	if (node == NULL) {	
+		if (macio_chips[0].type != macio_keylargo)
+			return -ENODEV;
+		node = macio_chips[0].of_node;
+	}
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+	gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
+	gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
+	gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
+	
+	if (!value) {
+		LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+		UNLOCK(flags);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+		mdelay(250);
+	}
+    	LOCK(flags);
+    	if (value) {
+    		MACIO_BIC(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+	    	UNLOCK(flags);
+	    	(void)MACIO_IN32(KEYLARGO_FCR2);
+		mdelay(250);
+    	} else {
+    		MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+	    	UNLOCK(flags);
+    	}
+	if (value) {
+		LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250);
+	}
+	return 0;
+}
+
+static int __pmac
+core99_ide_enable(struct device_node* node, int param, int value)
+{
+	switch(param) {
+	    case 0:
+		return simple_feature_tweak(node, macio_unknown,
+			KEYLARGO_FCR1, KL1_EIDE0_ENABLE, value);
+	    case 1:
+		return simple_feature_tweak(node, macio_unknown,
+			KEYLARGO_FCR1, KL1_EIDE1_ENABLE, value);
+	    case 2:
+		return simple_feature_tweak(node, macio_unknown,
+			KEYLARGO_FCR1, KL1_UIDE_ENABLE, value);
+	    default:
+	    	return -ENODEV;
+	}
+}
+
+static int __pmac
+core99_ide_reset(struct device_node* node, int param, int value)
+{
+	switch(param) {
+	    case 0:
+		return simple_feature_tweak(node, macio_unknown,
+			KEYLARGO_FCR1, KL1_EIDE0_RESET_N, !value);
+	    case 1:
+		return simple_feature_tweak(node, macio_unknown,
+			KEYLARGO_FCR1, KL1_EIDE1_RESET_N, !value);
+	    case 2:
+		return simple_feature_tweak(node, macio_unknown,
+			KEYLARGO_FCR1, KL1_UIDE_RESET_N, !value);
+	    default:
+	    	return -ENODEV;
+	}
+}
+
+static int __pmac
+core99_gmac_enable(struct device_node* node, int param, int value)
+{
+	unsigned long flags;
+
+	LOCK(flags);
+	if (value)
+		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
+	else
+		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
+	(void)UN_IN(UNI_N_CLOCK_CNTL);
+	UNLOCK(flags);
+	udelay(20);
+
+	return 0;
+}
+
+static int __pmac
+core99_gmac_phy_reset(struct device_node* node, int param, int value)
+{
+	unsigned long flags;
+	struct macio_chip* macio;
+	
+	macio = &macio_chips[0];
+	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+		return -ENODEV;
+
+	LOCK(flags);
+	MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE);
+	(void)MACIO_IN8(KL_GPIO_ETH_PHY_RESET);
+	UNLOCK(flags);
+	mdelay(10);
+	LOCK(flags);
+	MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE
+		| KEYLARGO_GPIO_OUTOUT_DATA);
+	UNLOCK(flags);
+	mdelay(10);
+
+	return 0;
+}
+
+static int __pmac
+core99_sound_chip_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	unsigned long		flags;
+	
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+
+	/* Do a better probe code, screamer G4 desktops &
+	 * iMacs can do that too, add a recalibrate  in
+	 * the driver as well
+	 */
+	if (pmac_mb.model_id == PMAC_TYPE_PISMO ||
+	    pmac_mb.model_id == PMAC_TYPE_TITANIUM) {
+		LOCK(flags);
+		if (value)
+	    		MACIO_OUT8(KL_GPIO_SOUND_POWER,
+	    			KEYLARGO_GPIO_OUTPUT_ENABLE |
+	    			KEYLARGO_GPIO_OUTOUT_DATA);
+	    	else
+	    		MACIO_OUT8(KL_GPIO_SOUND_POWER,
+	    			KEYLARGO_GPIO_OUTPUT_ENABLE);
+	    	(void)MACIO_IN8(KL_GPIO_SOUND_POWER);
+	    	UNLOCK(flags);
+	}
+	return 0;
+}
+
+static int __pmac
+core99_airport_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	unsigned long		flags;
+	int			state;
+	
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+	
+	/* Hint: we allow passing of macio itself for the sake of the
+	 * sleep code
+	 */
+	if (node != macio->of_node &&
+	    (!node->parent || node->parent != macio->of_node))
+		return -ENODEV;
+	state = (macio->flags & MACIO_FLAG_AIRPORT_ON) != 0;
+	if (value == state)
+		return 0;
+	if (value) {
+		/* This code is a reproduction of OF enable-cardslot
+		 * and init-wireless methods, slightly hacked until
+		 * I got it working.
+		 */
+		LOCK(flags);
+		MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 5);
+		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
+		UNLOCK(flags);
+		mdelay(10);
+		LOCK(flags);
+		MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 4);
+		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
+		UNLOCK(flags);
+
+		mdelay(10);
+
+		LOCK(flags);
+		MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
+		(void)MACIO_IN32(KEYLARGO_FCR2);
+		udelay(10);
+		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xb, 0);
+		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xb);
+		udelay(10);
+		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xa, 0x28);
+		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xa);
+		udelay(10);
+		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xd, 0x28);
+		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xd);
+		udelay(10);
+		MACIO_OUT8(KEYLARGO_GPIO_0+0xd, 0x28);
+		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xd);
+		udelay(10);
+		MACIO_OUT8(KEYLARGO_GPIO_0+0xe, 0x28);
+		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xe);
+		UNLOCK(flags);
+		udelay(10);
+		MACIO_OUT32(0x1c000, 0);
+		mdelay(1);
+		MACIO_OUT8(0x1a3e0, 0x41);
+		(void)MACIO_IN8(0x1a3e0);
+		udelay(10);
+		LOCK(flags);
+		MACIO_BIS(KEYLARGO_FCR2, KL2_CARDSEL_16);
+		(void)MACIO_IN32(KEYLARGO_FCR2);
+		UNLOCK(flags);
+		mdelay(100);
+
+		macio->flags |= MACIO_FLAG_AIRPORT_ON;
+	} else {
+		LOCK(flags);
+		MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
+		(void)MACIO_IN32(KEYLARGO_FCR2);
+		MACIO_OUT8(KL_GPIO_AIRPORT_0, 0);
+		MACIO_OUT8(KL_GPIO_AIRPORT_1, 0);
+		MACIO_OUT8(KL_GPIO_AIRPORT_2, 0);
+		MACIO_OUT8(KL_GPIO_AIRPORT_3, 0);
+		MACIO_OUT8(KL_GPIO_AIRPORT_4, 0);
+		(void)MACIO_IN8(KL_GPIO_AIRPORT_4);
+		UNLOCK(flags);
+
+		macio->flags &= ~MACIO_FLAG_AIRPORT_ON;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_SMP
+static int __pmac
+core99_reset_cpu(struct device_node* node, int param, int value)
+{
+	const int reset_lines[] = {	KL_GPIO_RESET_CPU0,
+					KL_GPIO_RESET_CPU1,
+					KL_GPIO_RESET_CPU2,
+					KL_GPIO_RESET_CPU3 };
+	int reset_io;
+	unsigned long flags;
+	struct macio_chip* macio;
+	
+	macio = &macio_chips[0];
+	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+		return -ENODEV;
+	if (param > 3 || param < 0)
+		return -ENODEV;
+
+	reset_io = reset_lines[param];
+	
+	LOCK(flags);
+	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
+	(void)MACIO_IN8(reset_io);
+	udelay(1);
+	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
+	(void)MACIO_IN8(reset_io);
+	UNLOCK(flags);
+
+	return 0;
+}
+
+static int __pmac
+rackmac_reset_cpu(struct device_node* node, int param, int value)
+{
+	int reset_io;
+	unsigned long flags;
+	struct macio_chip* macio;
+	struct device_node* np;
+	
+	macio = &macio_chips[0];
+	if (macio->type != macio_keylargo)
+		return -ENODEV;
+		
+	np = find_path_device("/cpus");
+	if (np == NULL)
+		return -ENODEV;
+	for (np = np->child; np != NULL; np = np->sibling) {
+		u32* num = (u32 *)get_property(np, "reg", NULL);
+		u32* rst = (u32 *)get_property(np, "soft-reset", NULL);
+		if (num == NULL || rst == NULL)
+			continue;
+		if (param == *num) {
+			reset_io = *rst;
+			break;
+		}
+	}
+	if (np == NULL)
+		return -ENODEV;
+	
+	LOCK(flags);
+	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
+	(void)MACIO_IN8(reset_io);
+	udelay(1);
+	MACIO_OUT8(reset_io, 0);
+	(void)MACIO_IN8(reset_io);
+	UNLOCK(flags);
+
+	return 0;
+}
+#endif /* CONFIG_SMP */
+
+static int __pmac
+core99_usb_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip* macio;
+	unsigned long flags;
+	char* prop;
+	int number;
+	u32 reg;
+	
+	macio = &macio_chips[0];
+	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+		return -ENODEV;
+	
+	prop = (char *)get_property(node, "AAPL,clock-id", NULL);
+	if (!prop)
+		return -ENODEV;
+	if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0)
+		number = 0;
+	else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0)
+		number = 2;
+	else
+		return -ENODEV;
+
+	/* Sorry for the brute-force locking, but this is only used during
+	 * sleep and the timing seem to be critical
+	 */
+	LOCK(flags);
+	if (value) {
+		/* Turn ON */
+		if (number == 0) {
+			MACIO_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
+			(void)MACIO_IN32(KEYLARGO_FCR0);
+			UNLOCK(flags);
+			mdelay(1);
+			LOCK(flags);
+			MACIO_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
+		} else {
+			MACIO_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
+			UNLOCK(flags);
+			(void)MACIO_IN32(KEYLARGO_FCR0);
+			mdelay(1);
+			LOCK(flags);
+			MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
+		}
+		reg = MACIO_IN32(KEYLARGO_FCR4);
+		reg &=	~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
+			KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number));
+		reg &=	~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
+			KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1));
+		MACIO_OUT32(KEYLARGO_FCR4, reg);
+		(void)MACIO_IN32(KEYLARGO_FCR4);
+		udelay(10);
+	} else {
+		/* Turn OFF */
+		reg = MACIO_IN32(KEYLARGO_FCR4);
+		reg |=	KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
+			KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number);
+		reg |=	KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
+			KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1);
+		MACIO_OUT32(KEYLARGO_FCR4, reg);
+		(void)MACIO_IN32(KEYLARGO_FCR4);
+		udelay(1);
+		if (number == 0) {
+			MACIO_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
+			(void)MACIO_IN32(KEYLARGO_FCR0);
+			udelay(1);
+			MACIO_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
+			(void)MACIO_IN32(KEYLARGO_FCR0);
+		} else {
+			MACIO_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
+			(void)MACIO_IN32(KEYLARGO_FCR0);
+			udelay(1);
+			MACIO_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
+			(void)MACIO_IN32(KEYLARGO_FCR0);
+		}
+		udelay(1);
+	}
+	UNLOCK(flags);
+
+	return 0;
+}
+
+static int __pmac
+core99_firewire_enable(struct device_node* node, int param, int value)
+{
+	unsigned long flags;
+	struct macio_chip* macio;
+
+	macio = &macio_chips[0];
+	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+		return -ENODEV;
+	if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
+		return -ENODEV;
+	
+	LOCK(flags);
+	if (value) {
+		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
+		(void)UN_IN(UNI_N_CLOCK_CNTL);
+	} else {
+		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
+		(void)UN_IN(UNI_N_CLOCK_CNTL);
+	}
+	UNLOCK(flags);
+	mdelay(1);
+
+	return 0;
+}
+
+static int __pmac
+core99_firewire_cable_power(struct device_node* node, int param, int value)
+{
+	unsigned long flags;
+	struct macio_chip* macio;
+
+	/* Trick: we allow NULL node */
+	if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0)
+	    	return -ENODEV;
+	macio = &macio_chips[0];
+	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+		return -ENODEV;
+	if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
+		return -ENODEV;
+	
+	LOCK(flags);
+	if (value) {
+		MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 0);
+		MACIO_IN8(KL_GPIO_FW_CABLE_POWER);
+		udelay(10);
+	} else {
+		MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 4);
+		MACIO_IN8(KL_GPIO_FW_CABLE_POWER); udelay(10);
+	}
+	UNLOCK(flags);
+	mdelay(1);
+
+	return 0;
+}
+
+static int __pmac
+core99_read_gpio(struct device_node* node, int param, int value)
+{
+	struct macio_chip* macio = &macio_chips[0];
+	
+	return MACIO_IN8(param);
+}
+
+
+static int __pmac
+core99_write_gpio(struct device_node* node, int param, int value)
+{
+	struct macio_chip* macio = &macio_chips[0];
+
+	MACIO_OUT8(param, (u8)(value & 0xff));
+	return 0;
+}
+
+static void __pmac
+keylargo_shutdown(struct macio_chip* macio, int restart)
+{
+	u32 temp;
+
+	mdelay(1);
+	MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
+	(void)MACIO_IN32(KEYLARGO_FCR0);
+	mdelay(100);
+
+	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
+				KL0_SCC_CELL_ENABLE |
+		      		KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE |
+		      		KL0_IRDA_CLK19_ENABLE);
+
+	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
+	MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
+	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
+
+	MACIO_BIC(KEYLARGO_FCR1,
+		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
+		KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
+		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
+		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
+		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
+		KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N |
+		KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N |
+		KL1_UIDE_ENABLE);
+	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
+
+	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+ 	udelay(10);
+ 	MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);
+ 	udelay(10);
+	temp = MACIO_IN32(KEYLARGO_FCR3);
+	if (macio->rev >= 2)
+		temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL);
+		
+	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
+		KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12;
+	temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
+		| KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE
+		| KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
+	MACIO_OUT32(KEYLARGO_FCR3, temp);
+	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
+}
+
+static void __pmac
+pangea_shutdown(struct macio_chip* macio, int restart)
+{
+	u32 temp;
+
+	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
+				KL0_SCC_CELL_ENABLE |
+				KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE);
+
+	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
+	MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
+	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
+
+	MACIO_BIC(KEYLARGO_FCR1,
+		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
+		KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
+		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
+		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
+		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
+		KL1_UIDE_ENABLE);
+	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
+
+	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+ 	udelay(10);
+	temp = MACIO_IN32(KEYLARGO_FCR3);
+	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
+		KL3_SHUTDOWN_PLLKW35;
+	temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
+		| KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE
+		| KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
+	MACIO_OUT32(KEYLARGO_FCR3, temp);
+	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
+}
+
+static int __pmac
+core99_sleep(void)
+{
+	struct macio_chip* macio;
+	int i;
+
+	macio = &macio_chips[0];
+	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+		return -ENODEV;
+	
+	/* We power off the wireless slot in case it was not done
+	 * by the driver. We don't power it on automatically however
+	 */
+	if (macio->flags & MACIO_FLAG_AIRPORT_ON)
+		core99_airport_enable(macio->of_node, 0, 0);
+
+	/* We power off the FW cable. Should be done by the driver... */
+	if (macio->flags & MACIO_FLAG_FW_SUPPORTED) {
+		core99_firewire_enable(NULL, 0, 0);
+		core99_firewire_cable_power(NULL, 0, 0);
+	}
+
+	/* We make sure int. modem is off (in case driver lost it) */
+	core99_modem_enable(macio->of_node, 0, 0);
+	/* We make sure the sound is off as well */
+	core99_sound_chip_enable(macio->of_node, 0, 0);
+	 
+	/*
+	 * Save various bits of KeyLargo
+	 */
+
+	/* Save the state of the various GPIOs */
+	save_gpio_levels[0] = MACIO_IN32(KEYLARGO_GPIO_LEVELS0);
+	save_gpio_levels[1] = MACIO_IN32(KEYLARGO_GPIO_LEVELS1);
+	for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
+		save_gpio_extint[i] = MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+i);
+	for (i=0; i<KEYLARGO_GPIO_CNT; i++)
+		save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i);
+
+	/* Save the FCRs */
+	save_mbcr = MACIO_IN32(KEYLARGO_MBCR);
+	save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0);
+	save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1);
+	save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2);
+	save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3);
+	save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4);
+
+	/* Save state & config of DBDMA channels */
+	dbdma_save(macio, save_dbdma);
+	
+	/*
+	 * Turn off as much as we can
+	 */
+	if (macio->type == macio_pangea)
+		pangea_shutdown(macio, 0);
+	else if (macio->type == macio_keylargo)
+		keylargo_shutdown(macio, 0);
+	
+	/* 
+	 * Put the host bridge to sleep
+	 */
+
+	save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL);
+	UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl &
+		~(UNI_N_CLOCK_CNTL_GMAC|UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/));
+	udelay(100);
+	UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
+	UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP);
+
+	/*
+	 * FIXME: A bit of black magic with OpenPIC (don't ask me why)
+	 */
+	if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
+		MACIO_BIS(0x506e0, 0x00400000);
+		MACIO_BIS(0x506e0, 0x80000000);
+	}
+	return 0;
+}
+
+static int __pmac
+core99_wake_up(void)
+{
+	struct macio_chip* macio;
+	int i;
+
+	macio = &macio_chips[0];
+	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+		return -ENODEV;
+
+	/*
+	 * Wakeup the host bridge
+	 */
+	UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
+	udelay(10);
+	UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
+	udelay(10);
+	
+	/*
+	 * Restore KeyLargo
+	 */
+	 
+	MACIO_OUT32(KEYLARGO_MBCR, save_mbcr);
+	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
+	MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]);
+	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
+	MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]);
+	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
+	MACIO_OUT32(KEYLARGO_FCR2, save_fcr[2]);
+	(void)MACIO_IN32(KEYLARGO_FCR2); udelay(10);
+	MACIO_OUT32(KEYLARGO_FCR3, save_fcr[3]);
+	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
+	MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]);
+	(void)MACIO_IN32(KEYLARGO_FCR4); udelay(10);
+
+	dbdma_restore(macio, save_dbdma);
+
+	MACIO_OUT32(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]);
+	MACIO_OUT32(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]);
+	for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
+		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+i, save_gpio_extint[i]);
+	for (i=0; i<KEYLARGO_GPIO_CNT; i++)
+		MACIO_OUT8(KEYLARGO_GPIO_0+i, save_gpio_normal[i]);
+
+	/* FIXME more black magic with OpenPIC ... */
+	if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
+		MACIO_BIC(0x506e0, 0x00400000);
+		MACIO_BIC(0x506e0, 0x80000000);
+	}
+
+	UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl);
+	udelay(100);
+
+	return 0;
+}
+
+static int __pmac
+core99_sleep_state(struct device_node* node, int param, int value)
+{
+	/* Param == 1 means to enter the "fake sleep" mode that is
+	 * used for CPU speed switch
+	 */
+	if (param == 1) {
+		if (value == 1) {
+			UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
+			UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_IDLE2);
+		} else {
+			UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
+			udelay(10);
+			UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
+			udelay(10);
+		}
+		return 0;
+	}
+	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
+		return -EPERM;
+	if (value == 1)
+		return core99_sleep();
+	else if (value == 0)
+		return core99_wake_up();
+	return 0;
+}
+
+static int __pmac
+pangea_modem_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	u8			gpio;
+	unsigned long		flags;
+	
+	/* Hack for internal USB modem */
+	if (node == NULL) {	
+		if (macio_chips[0].type != macio_pangea)
+			return -ENODEV;
+		node = macio_chips[0].of_node;
+	}
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+	gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
+	gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
+	gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
+	
+	if (!value) {
+		LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+		UNLOCK(flags);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+		mdelay(250);
+	}
+    	LOCK(flags);
+	if (value) {
+		MACIO_OUT8(KL_GPIO_MODEM_POWER,
+			KEYLARGO_GPIO_OUTPUT_ENABLE);
+    		UNLOCK(flags);
+	    	(void)MACIO_IN32(KEYLARGO_FCR2);
+		mdelay(250);
+	} else {
+		MACIO_OUT8(KL_GPIO_MODEM_POWER,
+			KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
+    		UNLOCK(flags);
+	}
+	if (value) {
+		LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250);
+	}
+	return 0;
+}
+
+
+static int __pmac
+generic_get_mb_info(struct device_node* node, int param, int value)
+{
+	switch(param) {
+		case PMAC_MB_INFO_MODEL:
+			return pmac_mb.model_id;
+		case PMAC_MB_INFO_FLAGS:
+			return pmac_mb.board_flags;
+		case PMAC_MB_INFO_NAME:	
+			/* hack hack hack... but should work */
+			*((const char **)value) = pmac_mb.model_name;
+			break;
+	}
+	return 0;
+}
+
+
+/* 
+ * Table definitions
+ */
+ 
+/* Used on any machine
+ */
+static struct feature_table_entry any_features[]  __pmacdata = {
+	{ PMAC_FTR_GET_MB_INFO,		generic_get_mb_info },
+	{ 0, NULL }
+};
+
+/* OHare based motherboards. Currently, we only use these on the
+ * 2400,3400 and 3500 series powerbooks. Some older desktops seem
+ * to have issues with turning on/off those asic cells
+ */
+static struct feature_table_entry ohare_features[]  __pmacdata = {
+	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
+	{ PMAC_FTR_SWIM3_ENABLE,	ohare_floppy_enable },
+	{ PMAC_FTR_MESH_ENABLE,		ohare_mesh_enable },
+	{ PMAC_FTR_IDE_ENABLE,		ohare_ide_enable},
+	{ PMAC_FTR_IDE_RESET,		ohare_ide_reset},
+	{ PMAC_FTR_SLEEP_STATE,		ohare_sleep_state },
+	{ 0, NULL }
+};
+
+/* Heathrow desktop machines (Beige G3).
+ * Separated as some features couldn't be properly tested
+ * and the serial port control bits appear to confuse it.
+ */
+static struct feature_table_entry heathrow_desktop_features[]  __pmacdata = {
+	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
+	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
+	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
+	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
+	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
+	{ 0, NULL }
+};
+
+/* Heathrow based laptop, that is the Wallstreet and mainstreet
+ * powerbooks.
+ */
+static struct feature_table_entry heathrow_laptop_features[]  __pmacdata = {
+	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
+	{ PMAC_FTR_MODEM_ENABLE,	heathrow_modem_enable },
+	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
+	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
+	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
+	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
+	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
+	{ PMAC_FTR_SOUND_CHIP_ENABLE,	heathrow_sound_enable },
+	{ PMAC_FTR_SLEEP_STATE,		heathrow_sleep_state },
+	{ 0, NULL }
+};
+
+/* Paddington based machines
+ * The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4.
+ */
+static struct feature_table_entry paddington_features[]  __pmacdata = {
+	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
+	{ PMAC_FTR_MODEM_ENABLE,	heathrow_modem_enable },
+	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
+	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
+	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
+	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
+	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
+	{ PMAC_FTR_SOUND_CHIP_ENABLE,	heathrow_sound_enable },
+	{ PMAC_FTR_SLEEP_STATE,		heathrow_sleep_state },
+	{ 0, NULL }
+};
+
+/* Core99 & MacRISC 2 machines (all machines released since the
+ * iBook (included), that is all AGP machines, except pangea
+ * chipset. The pangea chipset is the "combo" UniNorth/KeyLargo
+ * used on iBook2 & iMac "flow power".
+ */
+static struct feature_table_entry core99_features[]  __pmacdata = {
+	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
+	{ PMAC_FTR_MODEM_ENABLE,	core99_modem_enable },
+	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
+	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
+	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
+	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
+	{ PMAC_FTR_SOUND_CHIP_ENABLE,	core99_sound_chip_enable },
+	{ PMAC_FTR_AIRPORT_ENABLE,	core99_airport_enable },
+	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
+	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
+	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
+	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
+#ifdef CONFIG_SMP
+	{ PMAC_FTR_RESET_CPU,		core99_reset_cpu },
+#endif /* CONFIG_SMP */
+	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
+	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
+	{ 0, NULL }
+};
+
+/* RackMac
+ */
+static struct feature_table_entry rackmac_features[]  __pmacdata = {
+	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
+	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
+	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
+	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
+	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
+	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
+	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
+	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
+	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
+#ifdef CONFIG_SMP
+	{ PMAC_FTR_RESET_CPU,		rackmac_reset_cpu },
+#endif /* CONFIG_SMP */
+	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
+	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
+	{ 0, NULL }
+};
+
+/* Pangea features
+ */
+static struct feature_table_entry pangea_features[]  __pmacdata = {
+	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
+	{ PMAC_FTR_MODEM_ENABLE,	pangea_modem_enable },
+	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
+	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
+	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
+	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
+	{ PMAC_FTR_SOUND_CHIP_ENABLE,	core99_sound_chip_enable },
+	{ PMAC_FTR_AIRPORT_ENABLE,	core99_airport_enable },
+	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
+	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
+	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
+	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
+	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
+	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
+	{ 0, NULL }
+};
+	
+static struct pmac_mb_def pmac_mb_defs[] __pmacdata = {
+	/* Warning: ordering is important as some models may claim
+	 * beeing compatible with several types
+	 */
+	{	"AAPL,8500",			"PowerMac 8500/8600",
+		PMAC_TYPE_PSURGE,		NULL,
+		0
+	},
+	{	"AAPL,9500",			"PowerMac 9500/9600",
+		PMAC_TYPE_PSURGE,		NULL,
+		0
+	},
+	{	"AAPL,7500",			"PowerMac 7500",
+		PMAC_TYPE_PSURGE,		NULL,
+		0
+	},
+	{	"AAPL,ShinerESB",		"Apple Network Server",
+		PMAC_TYPE_ANS,			NULL,
+		0
+	},
+	{	"AAPL,e407",			"Alchemy",
+		PMAC_TYPE_ALCHEMY,		NULL,
+		0
+	},
+	{	"AAPL,e411",			"Gazelle",
+		PMAC_TYPE_GAZELLE,		NULL,
+		0
+	},
+	{	"AAPL,3400/2400",		"PowerBook 3400",
+		PMAC_TYPE_HOOPER,		ohare_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"AAPL,3500",			"PowerBook 3500",
+		PMAC_TYPE_KANGA,		ohare_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"AAPL,Gossamer",		"PowerMac G3 (Gossamer)",
+		PMAC_TYPE_GOSSAMER,		heathrow_desktop_features,
+		0
+	},
+	{	"AAPL,PowerMac G3",		"PowerMac G3 (Silk)",
+		PMAC_TYPE_SILK,			heathrow_desktop_features,
+		0
+	},
+	{	"AAPL,PowerBook1998",		"PowerBook Wallstreet",
+		PMAC_TYPE_WALLSTREET,		heathrow_laptop_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"PowerBook1,1",			"PowerBook 101 (Lombard)",
+		PMAC_TYPE_101_PBOOK,		paddington_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"iMac,1",			"iMac (first generation)",
+		PMAC_TYPE_ORIG_IMAC,		paddington_features,
+		0
+	},
+	{	"PowerMac4,1",			"iMac \"Flower Power\"",
+		PMAC_TYPE_PANGEA_IMAC,		pangea_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"PowerBook4,3",			"iBook 2 rev. 2",
+		PMAC_TYPE_IBOOK2,		pangea_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
+	{	"PowerBook4,2",			"iBook 2",
+		PMAC_TYPE_IBOOK2,		pangea_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
+	{	"PowerBook4,1",			"iBook 2",
+		PMAC_TYPE_IBOOK2,		pangea_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
+	{	"PowerMac4,4",			"eMac",
+		PMAC_TYPE_EMAC,			core99_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"PowerMac4,2",			"Flat panel iMac",
+		PMAC_TYPE_FLAT_PANEL_IMAC,	pangea_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"PowerMac1,1",			"Blue&White G3",
+		PMAC_TYPE_YOSEMITE,		paddington_features,
+		0
+	},
+	{	"PowerMac1,2",			"PowerMac G4 PCI Graphics",
+		PMAC_TYPE_YIKES,		paddington_features,
+		0
+	},
+	{	"PowerBook2,1",			"iBook (first generation)",
+		PMAC_TYPE_ORIG_IBOOK,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99
+	},
+	{	"PowerMac3,1",			"PowerMac G4 AGP Graphics",
+		PMAC_TYPE_SAWTOOTH,		core99_features,
+		PMAC_MB_OLD_CORE99
+	},
+	{	"PowerMac3,2",			"PowerMac G4 AGP Graphics",
+		PMAC_TYPE_SAWTOOTH,		core99_features,
+		PMAC_MB_OLD_CORE99
+	},
+	{	"PowerMac3,3",			"PowerMac G4 AGP Graphics",
+		PMAC_TYPE_SAWTOOTH,		core99_features,
+		PMAC_MB_OLD_CORE99
+	},
+	{	"PowerMac2,1",			"iMac FireWire",
+		PMAC_TYPE_FW_IMAC,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99
+	},
+	{	"PowerMac2,2",			"iMac FireWire",
+		PMAC_TYPE_FW_IMAC,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99
+	},
+	{	"PowerBook2,2",			"iBook FireWire",
+		PMAC_TYPE_FW_IBOOK,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_OLD_CORE99
+	},
+	{	"PowerMac5,1",			"PowerMac G4 Cube",
+		PMAC_TYPE_CUBE,			core99_features,
+		PMAC_MB_OLD_CORE99
+	},
+	{	"PowerMac3,4",			"PowerMac G4 Silver",
+		PMAC_TYPE_QUICKSILVER,		core99_features,
+		0
+	},
+	{	"PowerMac3,5",			"PowerMac G4 Silver",
+		PMAC_TYPE_QUICKSILVER,		core99_features,
+		0
+	},
+	{	"PowerBook3,1",			"PowerBook Pismo",
+		PMAC_TYPE_PISMO,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_OLD_CORE99
+	},
+	{	"PowerBook3,2",			"PowerBook Titanium",
+		PMAC_TYPE_TITANIUM,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
+	{	"PowerBook3,3",			"PowerBook Titanium II",
+		PMAC_TYPE_TITANIUM2,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
+	{	"PowerBook3,4",			"PowerBook Titanium III",
+		PMAC_TYPE_TITANIUM3,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
+	{	"RackMac1,1",			"XServe",
+		PMAC_TYPE_RACKMAC,		rackmac_features,
+		0,
+	},
+	{	"PowerMac3,6",			"PowerMac G4 Windtunnel",
+		PMAC_TYPE_WINDTUNNEL,		rackmac_features,
+		0,
+	},
+};
+
+/*
+ * The toplevel feature_call callback
+ */
+int __pmac
+pmac_do_feature_call(unsigned int selector, ...)
+{
+	struct device_node* node;
+	int param, value, i;
+	feature_call func = NULL;
+	va_list args;
+	
+	if (pmac_mb.features)
+		for (i=0; pmac_mb.features[i].function; i++)
+			if (pmac_mb.features[i].selector == selector) {
+				func = pmac_mb.features[i].function;
+				break;
+			}
+	if (!func)
+		for (i=0; any_features[i].function; i++)
+			if (any_features[i].selector == selector) {
+				func = any_features[i].function;
+				break;
+			}
+	if (!func)
+		return -ENODEV;
+
+	va_start(args, selector);
+	node = (struct device_node*)va_arg(args, void*);
+	param = va_arg(args, int);
+	value = va_arg(args, int);
+	va_end(args);
+
+	return func(node, param, value);
+}
+
+static int __init
+probe_motherboard(void)
+{
+	int i;
+	struct macio_chip* macio = &macio_chips[0];
+	const char* model = NULL;
+	struct device_node *dt;
+	
+	/* Lookup known motherboard type in device-tree. First try an
+	 * exact match on the "model" property, then try a "compatible"
+	 * match is none is found.
+	 */
+	dt = find_devices("device-tree");
+	if (dt != NULL)
+		model = (const char *) get_property(dt, "model", NULL);
+	for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
+	    if (strcmp(model, pmac_mb_defs[i].model_string) == 0) {
+		pmac_mb = pmac_mb_defs[i];
+		goto found;
+	    }
+	}
+	for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
+	    if (machine_is_compatible(pmac_mb_defs[i].model_string)) {
+		pmac_mb = pmac_mb_defs[i];
+		goto found;
+	    }
+	}
+
+	/* Fallback to selection depending on mac-io chip type */
+	switch(macio->type) {
+	    case macio_grand_central:
+		pmac_mb.model_id = PMAC_TYPE_PSURGE;
+		pmac_mb.model_name = "Unknown PowerSurge";
+		break;
+	    case macio_ohare:
+		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_OHARE;
+		pmac_mb.model_name = "Unknown OHare-based";
+	    	break;
+	    case macio_heathrow:
+		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_HEATHROW;
+		pmac_mb.model_name = "Unknown Heathrow-based";
+		pmac_mb.features = heathrow_desktop_features;
+		break;
+	    case macio_paddington:
+		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PADDINGTON;
+		pmac_mb.model_name = "Unknown Paddington-based";
+	    	pmac_mb.features = paddington_features;
+		break;
+	    case macio_keylargo:
+		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_CORE99;
+		pmac_mb.model_name = "Unknown Keylargo-based";
+	    	pmac_mb.features = core99_features;
+		break;
+	    case macio_pangea:
+		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA;
+		pmac_mb.model_name = "Unknown Pangea-based";
+	    	pmac_mb.features = pangea_features;
+		break;
+	    default:
+	    	return -ENODEV;
+	}
+found:
+	/* Fixup Hooper vs. Comet */
+	if (pmac_mb.model_id == PMAC_TYPE_HOOPER) {
+		u32* mach_id_ptr = (u32*)ioremap(0xf3000034, 4);
+		if (!mach_id_ptr)
+			return -ENODEV;
+		/* Here, I used to disable the media-bay on comet. It
+		 * appears this is wrong, the floppy connector is actually
+		 * a kind of media-bay and works with the current driver.
+		 */
+		if ((*mach_id_ptr) & 0x20000000UL)
+			pmac_mb.model_id = PMAC_TYPE_COMET;
+		iounmap(mach_id_ptr);
+	}
+
+	/* Set default value of powersave_nap on machines that support it.
+	 * It appears that uninorth rev 3 has a problem with it, we don't
+	 * enable it on those. In theory, the flush-on-lock property is
+	 * supposed to be set when not supported, but I'm not very confident
+	 * that all Apple OF revs did it properly, I do it the paranoid way.
+	 */
+	while (uninorth_base && uninorth_rev > 3) {
+		struct device_node* np = find_path_device("/cpus");
+		if (!np || !np->child) {
+			printk(KERN_WARNING "Can't find CPU(s) in device tree !\n");
+			break;
+		}
+		np = np->child;
+		/* Nap mode not supported on SMP */
+		if (np->sibling)
+			break;
+		/* Nap mode not supported if flush-on-lock property is present */
+		if (get_property(np, "flush-on-lock", NULL))
+			break;
+		powersave_nap = 1;
+		printk(KERN_INFO "Processor NAP mode on idle enabled.\n");
+		break;
+	}
+
+	/* On CPUs that support it (750FX), lowspeed by default during
+	 * NAP mode
+	 */
+	powersave_lowspeed = 1;
+	
+	printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
+	return 0;
+}
+
+/* Initialize the Core99 UniNorth host bridge and memory controller
+ */
+static void __init
+probe_uninorth(void)
+{
+	unsigned long actrl;
+	
+	/* Locate core99 Uni-N */
+	uninorth_node = find_devices("uni-n");
+	if (uninorth_node && uninorth_node->n_addrs > 0) {
+		uninorth_base = ioremap(uninorth_node->addrs[0].address, 0x4000);
+		uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
+	} else
+		uninorth_node = NULL;
+		
+	if (!uninorth_node)
+		return;
+	
+	printk(KERN_INFO "Found Uninorth memory controller & host bridge, revision: %d\n",
+			uninorth_rev);
+	printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base);
+
+	/* Set the arbitrer QAck delay according to what Apple does
+	 */
+	if (uninorth_rev < 0x11) {
+		actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK;
+		actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 :
+			UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
+		UN_OUT(UNI_N_ARB_CTRL, actrl);
+	}
+
+	/* Some more magic as done by them in recent MacOS X on UniNorth
+	 * revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI
+	 * memory timeout
+	 */
+	if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || uninorth_rev == 0xc0)
+		UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff);
+}	
+
+static void __init
+probe_one_macio(const char* name, const char* compat, int type)
+{
+	struct device_node*	node;
+	int			i;
+	volatile u32*		base;
+	u32*			revp;
+	
+	node = find_devices(name);
+	if (!node || !node->n_addrs)
+		return;
+	if (compat)
+		do {
+			if (device_is_compatible(node, compat))
+				break;
+			node = node->next;
+		} while (node);
+	if (!node)
+		return;
+	for(i=0; i<MAX_MACIO_CHIPS; i++) {
+		if (!macio_chips[i].of_node)
+			break;
+		if (macio_chips[i].of_node == node)
+			return;
+	}
+	if (i >= MAX_MACIO_CHIPS) {
+		printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");
+		printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
+		return;
+	}
+	base = (volatile u32*)ioremap(node->addrs[0].address, node->addrs[0].size);
+	if (!base) {
+		printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n");
+		return;
+	}
+	if (type == macio_keylargo) {
+		u32* did = (u32 *)get_property(node, "device-id", NULL);
+		if (*did == 0x00000025)
+			type = macio_pangea;
+	}
+	macio_chips[i].of_node	= node;
+	macio_chips[i].type	= type;
+	macio_chips[i].base	= base;
+	macio_chips[i].flags	= MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON;
+	revp = (u32 *)get_property(node, "revision-id", NULL);
+	if (revp)
+		macio_chips[i].rev = *revp;
+	printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n",
+		macio_names[type], macio_chips[i].rev, macio_chips[i].base);
+}
+
+static int __init
+probe_macios(void)
+{
+	/* Warning, ordering is important */
+	probe_one_macio("gc", NULL, macio_grand_central);
+	probe_one_macio("ohare", NULL, macio_ohare);
+	probe_one_macio("pci106b,7", NULL, macio_ohareII);
+	probe_one_macio("mac-io", "keylargo", macio_keylargo);
+	probe_one_macio("mac-io", "paddington", macio_paddington);
+	probe_one_macio("mac-io", "gatwick", macio_gatwick);
+	probe_one_macio("mac-io", "heathrow", macio_heathrow);
+
+	/* Make sure the "main" macio chip appear first */
+	if (macio_chips[0].type == macio_gatwick
+	    && macio_chips[1].type == macio_heathrow) {
+		struct macio_chip temp = macio_chips[0];
+		macio_chips[0] = macio_chips[1];
+		macio_chips[1] = temp;
+	}
+	if (macio_chips[0].type == macio_ohareII
+	    && macio_chips[1].type == macio_ohare) {
+		struct macio_chip temp = macio_chips[0];
+		macio_chips[0] = macio_chips[1];
+		macio_chips[1] = temp;
+	}
+
+	return (macio_chips[0].of_node == NULL) ? -ENODEV : 0;
+}
+
+static void __init
+initial_serial_shutdown(struct device_node* np)
+{
+	int len;
+	struct slot_names_prop {
+		int	count;
+		char	name[1];
+	} *slots;
+	char *conn;
+	int port_type = PMAC_SCC_ASYNC;
+	int modem = 0;
+	
+	slots = (struct slot_names_prop *)get_property(np, "slot-names", &len);
+	conn = get_property(np, "AAPL,connector", &len);
+	if (conn && (strcmp(conn, "infrared") == 0))
+		port_type = PMAC_SCC_IRDA;
+	else if (device_is_compatible(np, "cobalt"))
+		modem = 1;
+	else if (slots && slots->count > 0) {
+		if (strcmp(slots->name, "IrDA") == 0)
+			port_type = PMAC_SCC_IRDA;
+		else if (strcmp(slots->name, "Modem") == 0)
+			modem = 1;
+	}
+	if (modem)
+		pmac_call_feature(PMAC_FTR_MODEM_ENABLE, np, 0, 0);
+	pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, port_type, 0);
+}
+
+static void __init
+set_initial_features(void)
+{
+	struct device_node* np;
+	
+	/* That hack appears to be necessary for some StarMax motherboards
+	 * but I'm not too sure it was audited for side-effects on other
+	 * ohare based machines...
+	 * Since I still have difficulties figuring the right way to
+	 * differenciate them all and since that hack was there for a long
+	 * time, I'll keep it around
+	 */
+	if (macio_chips[0].type == macio_ohare && !find_devices("via-pmu")) {
+		struct macio_chip* macio = &macio_chips[0];
+		MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);
+	} else if (macio_chips[0].type == macio_ohare) {
+		struct macio_chip* macio = &macio_chips[0];
+		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+	} else if (macio_chips[1].type == macio_ohare) {
+		struct macio_chip* macio = &macio_chips[1];
+		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+	}
+
+	if (macio_chips[0].type == macio_keylargo ||
+	    macio_chips[0].type == macio_pangea) {
+		/* Enable GMAC for now for PCI probing. It will be disabled
+		 * later on after PCI probe
+		 */
+		np = find_devices("ethernet");
+		while(np) {
+			if (np->parent
+			    && device_is_compatible(np->parent, "uni-north")
+			    && device_is_compatible(np, "gmac"))
+				core99_gmac_enable(np, 0, 1);
+			np = np->next;
+		}
+
+		/* Enable FW before PCI probe. Will be disabled later on
+		 * Note: We should have a batter way to check that we are
+		 * dealing with uninorth internal cell and not a PCI cell
+		 * on the external PCI. The code below works though.
+		 */
+		np = find_devices("firewire");
+		while(np) {
+			if (np->parent
+			    && device_is_compatible(np->parent, "uni-north")
+			    && (device_is_compatible(np, "pci106b,18") || 
+	     		        device_is_compatible(np, "pci106b,30") ||
+	     		        device_is_compatible(np, "pci11c1,5811"))) {
+				macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
+				core99_firewire_enable(np, 0, 1);
+			}
+			np = np->next;
+		}
+		
+		/* Switch airport off */
+		np = find_devices("radio");
+		while(np) {
+			if (np && np->parent == macio_chips[0].of_node) {
+				macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON;
+				core99_airport_enable(np, 0, 0);
+			}
+			np = np->next;
+		}
+	}
+
+	/* On all machines that support sound PM, switch sound off */
+	if (macio_chips[0].of_node)
+		pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE,
+			macio_chips[0].of_node, 0, 0);
+
+	/* While on some desktop G3s, we turn it back on */
+	if (macio_chips[0].of_node && macio_chips[0].type == macio_heathrow
+		&& (pmac_mb.model_id == PMAC_TYPE_GOSSAMER ||
+		    pmac_mb.model_id == PMAC_TYPE_SILK)) {
+		struct macio_chip* macio = &macio_chips[0];
+		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
+	}
+
+
+	/* On all machines, switch modem & serial ports off */
+	np = find_devices("ch-a");
+	while(np) {
+		initial_serial_shutdown(np);
+		np = np->next;
+	}
+	np = find_devices("ch-b");
+	while(np) {
+		initial_serial_shutdown(np);
+		np = np->next;
+	}
+}
+
+void __init
+pmac_feature_init(void)
+{
+	/* Detect the UniNorth memory controller */
+	probe_uninorth();
+
+	/* Probe mac-io controllers */
+	if (probe_macios()) {
+		printk(KERN_WARNING "No mac-io chip found\n");
+		return;
+	}
+
+	/* Probe machine type */
+	if (probe_motherboard())
+		printk(KERN_WARNING "Unknown PowerMac !\n");
+
+	/* Set some initial features (turn off some chips that will
+	 * be later turned on)
+	 */
+	set_initial_features();
+}
+
+void __init
+pmac_feature_late_init(void)
+{
+	struct device_node* np;
+	
+	/* Request some resources late */
+	if (uninorth_node)
+		request_OF_resource(uninorth_node, 0, NULL);
+	np = find_devices("hammerhead");
+	if (np)
+		request_OF_resource(np, 0, NULL);
+	np = find_devices("interrupt-controller");
+	if (np)
+		request_OF_resource(np, 0, NULL);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/pmac_nvram.c linux-2.4.20/arch/ppc/platforms/pmac_nvram.c
--- linux-2.4.19/arch/ppc/platforms/pmac_nvram.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/pmac_nvram.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,402 @@
+/*
+ * BK Id: SCCS/s.pmac_nvram.c 1.17 12/01/01 20:09:06 benh
+ */
+/*
+ * Miscellaneous procedures for dealing with the PowerMac hardware.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/nvram.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/nvram.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+
+#undef DEBUG
+
+#define NVRAM_SIZE		0x2000	/* 8kB of non-volatile RAM */
+
+#define CORE99_SIGNATURE	0x5a
+#define CORE99_ADLER_START	0x14
+
+/* Core99 nvram is a flash */
+#define CORE99_FLASH_STATUS_DONE	0x80
+#define CORE99_FLASH_STATUS_ERR		0x38
+#define CORE99_FLASH_CMD_ERASE_CONFIRM	0xd0
+#define CORE99_FLASH_CMD_ERASE_SETUP	0x20
+#define CORE99_FLASH_CMD_RESET		0xff
+#define CORE99_FLASH_CMD_WRITE_SETUP	0x40
+
+/* CHRP NVRAM header */
+struct chrp_header {
+  u8		signature;
+  u8		cksum;
+  u16		len;
+  char          name[12];
+  u8		data[0];
+};
+
+struct core99_header {
+  struct chrp_header	hdr;
+  u32			adler;
+  u32			generation;
+  u32			reserved[2];
+};
+
+/*
+ * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
+ */
+static int nvram_naddrs;
+static volatile unsigned char *nvram_addr;
+static volatile unsigned char *nvram_data;
+static int nvram_mult, is_core_99;
+static int core99_bank = 0;
+static int nvram_partitions[3];
+
+/* FIXME: kmalloc fails to allocate the image now that I had to move it
+ *        before time_init(). For now, I allocate a static buffer here
+ *        but it's a waste of space on all but core99 machines
+ */
+#if 0
+static char* nvram_image;
+#else
+static char nvram_image[NVRAM_SIZE] __pmacdata;
+#endif
+
+extern int pmac_newworld;
+
+static u8 __openfirmware
+chrp_checksum(struct chrp_header* hdr)
+{
+	u8 *ptr;
+	u16 sum = hdr->signature;
+	for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
+		sum += *ptr;
+	while (sum > 0xFF)
+		sum = (sum & 0xFF) + (sum>>8);
+	return sum;
+}
+
+static u32 __pmac
+core99_calc_adler(u8 *buffer)
+{
+	int cnt;
+	u32 low, high;
+
+   	buffer += CORE99_ADLER_START;
+	low = 1;
+	high = 0;
+	for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
+		if ((cnt % 5000) == 0) {
+			high  %= 65521UL;
+			high %= 65521UL;
+		}
+		low += buffer[cnt];
+		high += low;
+	}
+	low  %= 65521UL;
+	high %= 65521UL;
+  
+	return (high << 16) | low;
+}
+
+static u32 __pmac
+core99_check(u8* datas)
+{
+	struct core99_header* hdr99 = (struct core99_header*)datas;
+
+	if (hdr99->hdr.signature != CORE99_SIGNATURE) {
+#ifdef DEBUG
+		printk("Invalid signature\n");
+#endif		
+		return 0;
+	}
+	if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
+#ifdef DEBUG
+		printk("Invalid checksum\n");
+#endif
+		return 0;
+	}
+	if (hdr99->adler != core99_calc_adler(datas)) {
+#ifdef DEBUG
+		printk("Invalid adler\n");
+#endif
+		return 0;
+	}
+	return hdr99->generation;
+}
+
+static int __pmac
+core99_erase_bank(int bank)
+{
+	int stat, i;
+	
+	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+	
+	out_8(base, CORE99_FLASH_CMD_ERASE_SETUP);
+	out_8(base, CORE99_FLASH_CMD_ERASE_CONFIRM);
+	do { stat = in_8(base); }
+	while(!(stat & CORE99_FLASH_STATUS_DONE));
+	out_8(base, CORE99_FLASH_CMD_RESET);
+	if (stat & CORE99_FLASH_STATUS_ERR) {
+		printk("nvram: flash error 0x%02x on erase !\n", stat);
+		return -ENXIO;
+	}
+	for (i=0; i<NVRAM_SIZE; i++)
+		if (base[i] != 0xff) {
+			printk("nvram: flash erase failed !\n");
+			return -ENXIO;
+		}
+	return 0;
+}
+
+static int __pmac
+core99_write_bank(int bank, u8* datas)
+{
+	int i, stat = 0;
+	
+	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+	
+	for (i=0; i<NVRAM_SIZE; i++) {
+		out_8(base+i, CORE99_FLASH_CMD_WRITE_SETUP);
+		out_8(base+i, datas[i]);
+		do { stat = in_8(base); }
+		while(!(stat & CORE99_FLASH_STATUS_DONE));
+		if (stat & CORE99_FLASH_STATUS_ERR)
+			break;
+	}
+	out_8(base, CORE99_FLASH_CMD_RESET);
+	if (stat & CORE99_FLASH_STATUS_ERR) {
+		printk("nvram: flash error 0x%02x on write !\n", stat);
+		return -ENXIO;
+	}
+	for (i=0; i<NVRAM_SIZE; i++)
+		if (base[i] != datas[i]) {
+			printk("nvram: flash write failed !\n");
+			return -ENXIO;
+		}
+	return 0;	
+}
+
+static void __init
+lookup_partitions(void)
+{
+	u8 buffer[17];
+	int i, offset;
+	struct chrp_header* hdr;
+
+	if (pmac_newworld) {
+		nvram_partitions[pmac_nvram_OF] = -1;
+		nvram_partitions[pmac_nvram_XPRAM] = -1;
+		nvram_partitions[pmac_nvram_NR] = -1;
+		hdr = (struct chrp_header *)buffer;
+	
+		offset = 0;
+		buffer[16] = 0;
+		do {
+			for (i=0;i<16;i++)
+				buffer[i] = nvram_read_byte(offset+i);
+			if (!strcmp(hdr->name, "common"))
+				nvram_partitions[pmac_nvram_OF] = offset + 0x10;
+			if (!strcmp(hdr->name, "APL,MacOS75")) {
+				nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10;
+				nvram_partitions[pmac_nvram_NR] = offset + 0x110;
+			}
+			offset += (hdr->len * 0x10);
+		} while(offset < NVRAM_SIZE);
+	} else {
+		nvram_partitions[pmac_nvram_OF] = 0x1800;
+		nvram_partitions[pmac_nvram_XPRAM] = 0x1300;
+		nvram_partitions[pmac_nvram_NR] = 0x1400;
+	}	
+#ifdef DEBUG
+	printk("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]);
+	printk("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]);
+	printk("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]);
+#endif	
+}
+
+void __init
+pmac_nvram_init(void)
+{
+	struct device_node *dp;
+
+	nvram_naddrs = 0;
+
+	dp = find_devices("nvram");
+	if (dp == NULL) {
+		printk(KERN_ERR "Can't find NVRAM device\n");
+		return;
+	}
+	nvram_naddrs = dp->n_addrs;
+	is_core_99 = device_is_compatible(dp, "nvram,flash");
+	if (is_core_99) {
+		int i;
+		u32 gen_bank0, gen_bank1;
+		
+		if (nvram_naddrs < 1) {
+			printk(KERN_ERR "nvram: no address\n");
+			return;
+		}
+#if 0
+		nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL);
+		if (!nvram_image) {
+			printk(KERN_ERR "nvram: can't allocate image\n");
+			return;
+		}
+#endif
+		nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
+#ifdef DEBUG
+		printk("nvram: Checking bank 0...\n");
+#endif
+		gen_bank0 = core99_check((u8 *)nvram_data);
+		gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
+		core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
+#ifdef DEBUG
+		printk("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
+		printk("nvram: Active bank is: %d\n", core99_bank);
+#endif
+		for (i=0; i<NVRAM_SIZE; i++)
+			nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
+	} else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
+		nvram_data = ioremap(dp->addrs[0].address + isa_mem_base,
+				     dp->addrs[0].size);
+		nvram_mult = 1;
+	} else if (nvram_naddrs == 1) {
+		nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+		nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
+	} else if (nvram_naddrs == 2) {
+		nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+		nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
+	} else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
+		nvram_naddrs = -1;
+	} else {
+		printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
+		       nvram_naddrs);
+	}
+	lookup_partitions();
+}
+
+void __pmac
+pmac_nvram_update(void)
+{
+	struct core99_header* hdr99;
+	
+	if (!is_core_99 || !nvram_data || !nvram_image)
+		return;
+	if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
+		NVRAM_SIZE))
+		return;
+#ifdef DEBUG
+	printk("Updating nvram...\n");
+#endif
+	hdr99 = (struct core99_header*)nvram_image;
+	hdr99->generation++;
+	hdr99->hdr.signature = CORE99_SIGNATURE;
+	hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
+	hdr99->adler = core99_calc_adler(nvram_image);
+	core99_bank = core99_bank ? 0 : 1;
+	if (core99_erase_bank(core99_bank)) {
+		printk("nvram: Error erasing bank %d\n", core99_bank);
+		return;
+	}
+	if (core99_write_bank(core99_bank, nvram_image))
+		printk("nvram: Error writing bank %d\n", core99_bank);
+}
+
+unsigned char __openfirmware
+nvram_read_byte(int addr)
+{
+	switch (nvram_naddrs) {
+#ifdef CONFIG_ADB_PMU
+	case -1: {
+		struct adb_request req;
+
+		if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM,
+				(addr >> 8) & 0xff, addr & 0xff))
+			break;
+		while (!req.complete)
+			pmu_poll();
+		return req.reply[0];
+	}
+#endif
+	case 1:
+		if (is_core_99)
+			return nvram_image[addr];
+		return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
+	case 2:
+		*nvram_addr = addr >> 5;
+		eieio();
+		return nvram_data[(addr & 0x1f) << 4];
+	}
+	return 0;
+}
+
+void __openfirmware
+nvram_write_byte(unsigned char val, int addr)
+{
+	switch (nvram_naddrs) {
+#ifdef CONFIG_ADB_PMU
+	case -1: {
+		struct adb_request req;
+
+		if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM,
+				(addr >> 8) & 0xff, addr & 0xff, val))
+			break;
+		while (!req.complete)
+			pmu_poll();
+		break;
+	}
+#endif
+	case 1:
+		if (is_core_99) {
+			nvram_image[addr] = val;
+			break;
+		}
+		nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
+		break;
+	case 2:
+		*nvram_addr = addr >> 5;
+		eieio();
+		nvram_data[(addr & 0x1f) << 4] = val;
+		break;
+	}
+	eieio();
+}
+
+int __pmac
+pmac_get_partition(int partition)
+{
+	return nvram_partitions[partition];
+}
+
+u8 __pmac
+pmac_xpram_read(int xpaddr)
+{
+	int offset = nvram_partitions[pmac_nvram_XPRAM];
+	
+	if (offset < 0)
+		return 0;
+		
+	return nvram_read_byte(xpaddr + offset);
+}
+
+void __pmac
+pmac_xpram_write(int xpaddr, u8 data)
+{
+	int offset = nvram_partitions[pmac_nvram_XPRAM];
+	
+	if (offset < 0)
+		return;
+		
+	nvram_write_byte(xpaddr + offset, data);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/pmac_pci.c linux-2.4.20/arch/ppc/platforms/pmac_pci.c
--- linux-2.4.19/arch/ppc/platforms/pmac_pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/pmac_pci.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,613 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * Support for PCI bridges found on Power Macintoshes.
+ * At present the "bandit" and "chaos" bridges are supported.
+ * Fortunately you access configuration space in the same
+ * way with either bridge.
+ *
+ * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+
+#undef DEBUG
+
+static void add_bridges(struct device_node *dev);
+
+/* XXX Could be per-controller, but I don't think we risk anything by
+ * assuming we won't have both UniNorth and Bandit */
+static int has_uninorth;
+
+/*
+ * Magic constants for enabling cache coherency in the bandit/PSX bridge.
+ */
+#define BANDIT_DEVID_2	8
+#define BANDIT_REVID	3
+
+#define BANDIT_DEVNUM	11
+#define BANDIT_MAGIC	0x50
+#define BANDIT_COHERENT	0x40
+
+static int __init
+fixup_one_level_bus_range(struct device_node *node, int higher)
+{
+	for (; node != 0;node = node->sibling) {
+		int * bus_range;
+		unsigned int *class_code;			
+		int len;
+
+		/* For PCI<->PCI bridges or CardBus bridges, we go down */
+		class_code = (unsigned int *) get_property(node, "class-code", 0);
+		if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
+			(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
+			continue;
+		bus_range = (int *) get_property(node, "bus-range", &len);
+		if (bus_range != NULL && len > 2 * sizeof(int)) {
+			if (bus_range[1] > higher)
+				higher = bus_range[1];
+		}
+		higher = fixup_one_level_bus_range(node->child, higher);
+	}
+	return higher;
+}
+
+/* This routine fixes the "bus-range" property of all bridges in the
+ * system since they tend to have their "last" member wrong on macs
+ * 
+ * Note that the bus numbers manipulated here are OF bus numbers, they
+ * are not Linux bus numbers.
+ */
+static void __init
+fixup_bus_range(struct device_node *bridge)
+{
+	int * bus_range;
+	int len;
+	
+	/* Lookup the "bus-range" property for the hose */		
+	bus_range = (int *) get_property(bridge, "bus-range", &len);
+	if (bus_range == NULL || len < 2 * sizeof(int)) {
+		printk(KERN_WARNING "Can't get bus-range for %s\n",
+			       bridge->full_name);
+		return;
+	}
+	bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
+}
+
+/*
+ * Apple MacRISC (UniNorth, Bandit, Chaos) PCI controllers.
+ * 
+ * The "Bandit" version is present in all early PCI PowerMacs,
+ * and up to the first ones using Grackle. Some machines may
+ * have 2 bandit controllers (2 PCI busses).
+ * 
+ * "Chaos" is used in some "Bandit"-type machines as a bridge
+ * for the separate display bus. It is accessed the same
+ * way as bandit, but cannot be probed for devices. It therefore
+ * has its own config access functions.
+ *
+ * The "UniNorth" version is present in all Core99 machines
+ * (iBook, G4, new IMacs, and all the recent Apple machines).
+ * It contains 3 controllers in one ASIC.
+ */
+
+#define MACRISC_CFA0(devfn, off)	\
+	((1 << (unsigned long)PCI_SLOT(dev_fn)) \
+	| (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
+	| (((unsigned long)(off)) & 0xFCUL))
+
+#define MACRISC_CFA1(bus, devfn, off)	\
+	((((unsigned long)(bus)) << 16) \
+	|(((unsigned long)(devfn)) << 8) \
+	|(((unsigned long)(off)) & 0xFCUL) \
+	|1UL)
+	
+static unsigned int __pmac
+macrisc_cfg_access(struct pci_controller* hose, u8 bus, u8 dev_fn, u8 offset)
+{
+	unsigned int caddr;
+	
+	if (bus == hose->first_busno) {
+		if (dev_fn < (11 << 3))
+			return 0;
+		caddr = MACRISC_CFA0(dev_fn, offset);
+	} else
+		caddr = MACRISC_CFA1(bus, dev_fn, offset);
+	
+	/* Uninorth will return garbage if we don't read back the value ! */
+	do {
+		out_le32(hose->cfg_addr, caddr);
+	} while(in_le32(hose->cfg_addr) != caddr);
+
+	offset &= has_uninorth ? 0x07 : 0x03;
+	return (unsigned int)(hose->cfg_data) + (unsigned int)offset;
+}
+
+#define cfg_read(val, addr, type, op, op2)	\
+	*val = op((type)(addr))
+#define cfg_write(val, addr, type, op, op2)	\
+	op((type *)(addr), (val)); (void) op2((type *)(addr))
+
+#define cfg_read_bad(val, size)		*val = bad_##size;
+#define cfg_write_bad(val, size)
+
+#define bad_byte	0xff
+#define bad_word	0xffff
+#define bad_dword	0xffffffffU
+
+#define MACRISC_PCI_OP(rw, size, type, op, op2)				    \
+static int __pmac							    \
+macrisc_##rw##_config_##size(struct pci_dev *dev, int off, type val)	    \
+{									    \
+	struct pci_controller *hose = dev->sysdata;			    \
+	unsigned int addr;						    \
+									    \
+	addr = macrisc_cfg_access(hose, dev->bus->number, dev->devfn, off); \
+	if (!addr) {							    \
+		cfg_##rw##_bad(val, size)				    \
+		return PCIBIOS_DEVICE_NOT_FOUND;			    \
+	}								    \
+	cfg_##rw(val, addr, type, op, op2);				    \
+	return PCIBIOS_SUCCESSFUL;					    \
+}
+
+MACRISC_PCI_OP(read, byte, u8 *, in_8, x)
+MACRISC_PCI_OP(read, word, u16 *, in_le16, x)
+MACRISC_PCI_OP(read, dword, u32 *, in_le32, x)
+MACRISC_PCI_OP(write, byte, u8, out_8, in_8)
+MACRISC_PCI_OP(write, word, u16, out_le16, in_le16)
+MACRISC_PCI_OP(write, dword, u32, out_le32, in_le32)
+
+static struct pci_ops macrisc_pci_ops =
+{
+	macrisc_read_config_byte,
+	macrisc_read_config_word,
+	macrisc_read_config_dword,
+	macrisc_write_config_byte,
+	macrisc_write_config_word,
+	macrisc_write_config_dword
+};
+
+/*
+ * Verifiy that a specific (bus, dev_fn) exists on chaos
+ */
+static int __pmac
+chaos_validate_dev(struct pci_dev *dev, int offset)
+{
+	if(pci_device_to_OF_node(dev) == 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if((dev->vendor == 0x106b) && (dev->device == 3) && (offset >= 0x10) &&
+	    (offset != 0x14) && (offset != 0x18) && (offset <= 0x24)) {
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+#define CHAOS_PCI_OP(rw, size, type)					\
+static int __pmac							\
+chaos_##rw##_config_##size(struct pci_dev *dev, int off, type val)	\
+{									\
+	int result = chaos_validate_dev(dev, off);			\
+	if(result == PCIBIOS_BAD_REGISTER_NUMBER) {			\
+		cfg_##rw##_bad(val, size)				\
+		return PCIBIOS_BAD_REGISTER_NUMBER;			\
+	}								\
+	if(result == PCIBIOS_SUCCESSFUL)				\
+		return macrisc_##rw##_config_##size(dev, off, val);	\
+	return result;							\
+}
+
+CHAOS_PCI_OP(read, byte, u8 *)
+CHAOS_PCI_OP(read, word, u16 *)
+CHAOS_PCI_OP(read, dword, u32 *)
+CHAOS_PCI_OP(write, byte, u8)
+CHAOS_PCI_OP(write, word, u16)
+CHAOS_PCI_OP(write, dword, u32) 
+
+static struct pci_ops chaos_pci_ops =
+{
+	chaos_read_config_byte,
+	chaos_read_config_word,
+	chaos_read_config_dword,
+	chaos_write_config_byte,
+	chaos_write_config_word,
+	chaos_write_config_dword
+};
+
+
+/*
+ * For a bandit bridge, turn on cache coherency if necessary.
+ * N.B. we could clean this up using the hose ops directly.
+ */
+static void __init
+init_bandit(struct pci_controller *bp)
+{
+	unsigned int vendev, magic;
+	int rev;
+
+	/* read the word at offset 0 in config space for device 11 */
+	out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
+	udelay(2);
+	vendev = in_le32((volatile unsigned int *)bp->cfg_data);
+	if (vendev == (PCI_DEVICE_ID_APPLE_BANDIT << 16) + 
+			PCI_VENDOR_ID_APPLE) {
+		/* read the revision id */
+		out_le32(bp->cfg_addr,
+			 (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
+		udelay(2);
+		rev = in_8(bp->cfg_data);
+		if (rev != BANDIT_REVID)
+			printk(KERN_WARNING
+			       "Unknown revision %d for bandit\n", rev);
+	} else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) {
+		printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
+		return;
+	}
+
+	/* read the word at offset 0x50 */
+	out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
+	udelay(2);
+	magic = in_le32((volatile unsigned int *)bp->cfg_data);
+	if ((magic & BANDIT_COHERENT) != 0)
+		return;
+	magic |= BANDIT_COHERENT;
+	udelay(2);
+	out_le32((volatile unsigned int *)bp->cfg_data, magic);
+	printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n");
+}
+
+
+/*
+ * Tweak the PCI-PCI bridge chip on the blue & white G3s.
+ */
+static void __init
+init_p2pbridge(void)
+{
+	struct device_node *p2pbridge;
+	struct pci_controller* hose;
+	u8 bus, devfn;
+	u16 val;
+
+	/* XXX it would be better here to identify the specific
+	   PCI-PCI bridge chip we have. */
+	if ((p2pbridge = find_devices("pci-bridge")) == 0
+	    || p2pbridge->parent == NULL
+	    || strcmp(p2pbridge->parent->name, "pci") != 0)
+		return;
+	if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) {
+#ifdef DEBUG
+		printk("Can't find PCI infos for PCI<->PCI bridge\n");
+#endif		
+		return;
+	}
+	/* Warning: At this point, we have not yet renumbered all busses. 
+	 * So we must use OF walking to find out hose
+	 */
+	hose = pci_find_hose_for_OF_device(p2pbridge);
+	if (!hose) {
+#ifdef DEBUG
+		printk("Can't find hose for PCI<->PCI bridge\n");
+#endif		
+		return;
+	}
+	if (early_read_config_word(hose, bus, devfn,
+				   PCI_BRIDGE_CONTROL, &val) < 0) {
+		printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n");
+		return;
+	}
+	val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
+	early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);
+}
+
+void __init
+pmac_find_bridges(void)
+{
+	add_bridges(find_devices("bandit"));
+	add_bridges(find_devices("chaos"));
+	add_bridges(find_devices("pci"));
+	init_p2pbridge();
+}
+
+#define GRACKLE_CFA(b, d, o)	(0x80 | ((b) << 8) | ((d) << 16) \
+				 | (((o) & ~3) << 24))
+
+#define GRACKLE_PICR1_STG		0x00000040
+#define GRACKLE_PICR1_LOOPSNOOP		0x00000010
+
+/* N.B. this is called before bridges is initialized, so we can't
+   use grackle_pcibios_{read,write}_config_dword. */
+static inline void grackle_set_stg(struct pci_controller* bp, int enable)
+{
+	unsigned int val;
+
+	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+	val = in_le32((volatile unsigned int *)bp->cfg_data);
+	val = enable? (val | GRACKLE_PICR1_STG) :
+		(val & ~GRACKLE_PICR1_STG);
+	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+	out_le32((volatile unsigned int *)bp->cfg_data, val);
+	(void)in_le32((volatile unsigned int *)bp->cfg_data);
+}
+
+static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable)
+{
+	unsigned int val;
+
+	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+	val = in_le32((volatile unsigned int *)bp->cfg_data);
+	val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) :
+		(val & ~GRACKLE_PICR1_LOOPSNOOP);
+	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+	out_le32((volatile unsigned int *)bp->cfg_data, val);
+	(void)in_le32((volatile unsigned int *)bp->cfg_data);
+}
+
+static int __init
+setup_uninorth(struct pci_controller* hose, struct reg_property* addr)
+{
+	pci_assign_all_busses = 1;
+	has_uninorth = 1;
+	hose->ops = &macrisc_pci_ops;
+	hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
+	hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+	/* We "know" that the bridge at f2000000 has the PCI slots. */
+	return addr->address == 0xf2000000;
+}
+
+static void __init
+setup_bandit(struct pci_controller* hose, struct reg_property* addr)
+{
+	hose->ops = &macrisc_pci_ops;
+	hose->cfg_addr = (volatile unsigned int *)
+		ioremap(addr->address + 0x800000, 0x1000);
+	hose->cfg_data = (volatile unsigned char *)
+		ioremap(addr->address + 0xc00000, 0x1000);
+	init_bandit(hose);
+}
+
+static void __init
+setup_chaos(struct pci_controller* hose, struct reg_property* addr)
+{
+	/* assume a `chaos' bridge */
+	hose->ops = &chaos_pci_ops;
+	hose->cfg_addr = (volatile unsigned int *)
+		ioremap(addr->address + 0x800000, 0x1000);
+	hose->cfg_data = (volatile unsigned char *)
+		ioremap(addr->address + 0xc00000, 0x1000);
+}
+
+void __init
+setup_grackle(struct pci_controller *hose)
+{
+	setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
+	if (machine_is_compatible("AAPL,PowerBook1998"))
+		grackle_set_loop_snoop(hose, 1);
+#if 0	/* Disabled for now, HW problems ??? */
+	grackle_set_stg(hose, 1);
+#endif
+}
+
+/*
+ * We assume that if we have a G3 powermac, we have one bridge called
+ * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise,
+ * if we have one or more bandit or chaos bridges, we don't have a MPC106.
+ */
+static void __init
+add_bridges(struct device_node *dev)
+{
+	int len;
+	struct pci_controller *hose;
+	struct reg_property *addr;
+	char* disp_name;
+	int *bus_range;
+	int first = 1, primary;
+	
+	for (; dev != NULL; dev = dev->next) {
+		addr = (struct reg_property *) get_property(dev, "reg", &len);
+		if (addr == NULL || len < sizeof(*addr)) {
+			printk(KERN_WARNING "Can't use %s: no address\n",
+			       dev->full_name);
+			continue;
+		}
+		bus_range = (int *) get_property(dev, "bus-range", &len);
+		if (bus_range == NULL || len < 2 * sizeof(int)) {
+			printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",
+				       dev->full_name);
+		}
+		
+		hose = pcibios_alloc_controller();
+		if (!hose)
+			continue;
+		hose->arch_data = dev;
+		hose->first_busno = bus_range ? bus_range[0] : 0;
+		hose->last_busno = bus_range ? bus_range[1] : 0xff;
+
+		disp_name = NULL;
+		primary = first;
+		if (device_is_compatible(dev, "uni-north")) {
+			primary = setup_uninorth(hose, addr);
+			disp_name = "UniNorth";
+		} else if (strcmp(dev->name, "pci") == 0) {
+			/* XXX assume this is a mpc106 (grackle) */
+			setup_grackle(hose);
+			disp_name = "Grackle (MPC106)";
+		} else if (strcmp(dev->name, "bandit") == 0) {
+			setup_bandit(hose, addr);
+			disp_name = "Bandit";
+		} else if (strcmp(dev->name, "chaos") == 0) {
+			setup_chaos(hose, addr);
+			disp_name = "Chaos";
+			primary = 0;
+		}
+		printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n",
+			disp_name, addr->address, hose->first_busno, hose->last_busno);
+#ifdef DEBUG
+		printk(" ->Hose at 0x%08lx, cfg_addr=0x%08lx,cfg_data=0x%08lx\n",
+			hose, hose->cfg_addr, hose->cfg_data);
+#endif		
+		
+		/* Interpret the "ranges" property */
+		/* This also maps the I/O region and sets isa_io/mem_base */
+		pci_process_bridge_OF_ranges(hose, dev, primary);
+
+		/* Fixup "bus-range" OF property */
+		fixup_bus_range(dev);
+
+		first &= !primary;
+	}
+}
+
+static void __init
+pcibios_fixup_OF_interrupts(void)
+{	
+	struct pci_dev* dev;
+	
+	/*
+	 * Open Firmware often doesn't initialize the
+	 * PCI_INTERRUPT_LINE config register properly, so we
+	 * should find the device node and apply the interrupt
+	 * obtained from the OF device-tree
+	 */
+	pci_for_each_dev(dev) {
+		struct device_node* node = pci_device_to_OF_node(dev);
+		/* this is the node, see if it has interrupts */
+		if (node && node->n_intrs > 0)
+			dev->irq = node->intrs[0].line;
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+	}
+}
+
+void __init
+pmac_pcibios_fixup(void)
+{
+	/* Fixup interrupts according to OF tree */
+	pcibios_fixup_OF_interrupts();
+}
+
+int __pmac
+pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
+{
+	struct device_node* node;
+	int updatecfg = 0;
+	int uninorth_child;
+
+	node = pci_device_to_OF_node(dev);
+
+	/* We don't want to enable USB controllers absent from the OF tree
+	 * (iBook second controller)
+	 */
+	if (dev->vendor == PCI_VENDOR_ID_APPLE
+	    && dev->device == PCI_DEVICE_ID_APPLE_KL_USB && !node)
+		return -EINVAL;
+
+	if (!node)
+		return 0;
+
+	uninorth_child = node->parent &&
+		device_is_compatible(node->parent, "uni-north");
+		
+	/* Firewire & GMAC were disabled after PCI probe, the driver is
+	 * claiming them, we must re-enable them now.
+	 */
+	if (uninorth_child && !strcmp(node->name, "firewire") && 
+	    (device_is_compatible(node, "pci106b,18") || 
+	     device_is_compatible(node, "pci106b,30") ||
+	     device_is_compatible(node, "pci11c1,5811"))) {
+		pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, node, 0, 1);
+		pmac_call_feature(PMAC_FTR_1394_ENABLE, node, 0, 1);
+		updatecfg = 1;
+	}
+	if (uninorth_child && !strcmp(node->name, "ethernet") && 
+	    device_is_compatible(node, "gmac")) {
+		pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1);
+		updatecfg = 1;
+	}
+
+	if (updatecfg) {
+		u16 cmd;
+		
+		/*
+		 * Make sure PCI is correctly configured
+		 *
+		 * We use old pci_bios versions of the function since, by
+		 * default, gmac is not powered up, and so will be absent
+		 * from the kernel initial PCI lookup. 
+		 * 
+		 * Should be replaced by 2.4 new PCI mecanisms and really
+		 * regiser the device.
+		 */
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
+    		pci_write_config_word(dev, PCI_COMMAND, cmd);
+    		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16);
+    		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8);
+	}
+	
+	return 0;
+}
+
+/* We power down some devices after they have been probed. They'll
+ * be powered back on later on
+ */
+void __init
+pmac_pcibios_after_init(void)
+{
+	struct device_node* nd;
+
+#ifdef CONFIG_BLK_DEV_IDE
+	struct pci_dev *dev;
+
+	/* OF fails to initialize IDE controllers on macs
+	 * (and maybe other machines)
+	 * 
+	 * Ideally, this should be moved to the IDE layer, but we need
+	 * to check specifically with Andre Hedrick how to do it cleanly
+	 * since the common IDE code seem to care about the fact that the
+	 * BIOS may have disabled a controller.
+	 * 
+	 * -- BenH
+	 */
+	pci_for_each_dev(dev) {
+		if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE)
+			pci_enable_device(dev);
+	}
+#endif /* CONFIG_BLK_DEV_IDE */
+
+	nd = find_devices("firewire");
+	while (nd) {
+		if (nd->parent && (device_is_compatible(nd, "pci106b,18") ||
+				   device_is_compatible(nd, "pci106b,30") ||
+				   device_is_compatible(nd, "pci11c1,5811"))
+		    && device_is_compatible(nd->parent, "uni-north")) {
+			pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0);
+			pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0);
+		}
+		nd = nd->next;
+	}
+	nd = find_devices("ethernet");
+	while (nd) {
+		if (nd->parent && device_is_compatible(nd, "gmac")
+		    && device_is_compatible(nd->parent, "uni-north"))
+			pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0);
+		nd = nd->next;
+	}
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/pmac_pic.c linux-2.4.20/arch/ppc/platforms/pmac_pic.c
--- linux-2.4.19/arch/ppc/platforms/pmac_pic.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/pmac_pic.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,528 @@
+/*
+ * BK Id: SCCS/s.pmac_pic.c 1.24 12/19/01 10:53:01 paulus
+ */
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/pci.h>
+
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/time.h>
+#include <asm/open_pic.h>
+
+#include "pmac_pic.h"
+
+struct pmac_irq_hw {
+        unsigned int    event;
+        unsigned int    enable;
+        unsigned int    ack;
+        unsigned int    level;
+};
+
+/* Default addresses */
+static volatile struct pmac_irq_hw *pmac_irq_hw[4] __pmacdata = {
+        (struct pmac_irq_hw *) 0xf3000020,
+        (struct pmac_irq_hw *) 0xf3000010,
+        (struct pmac_irq_hw *) 0xf4000020,
+        (struct pmac_irq_hw *) 0xf4000010,
+};
+
+#define GC_LEVEL_MASK		0x3ff00000
+#define OHARE_LEVEL_MASK	0x1ff00000
+#define HEATHROW_LEVEL_MASK	0x1ff00000
+
+static int max_irqs __pmacdata;
+static int max_real_irqs __pmacdata;
+static u32 level_mask[4] __pmacdata;
+
+static spinlock_t pmac_pic_lock __pmacdata = SPIN_LOCK_UNLOCKED;
+
+
+#define GATWICK_IRQ_POOL_SIZE        10
+static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE] __pmacdata;
+
+/*
+ * Mark an irq as "lost".  This is only used on the pmac
+ * since it can lose interrupts (see pmac_set_irq_mask).
+ * -- Cort
+ */
+void __pmac
+__set_lost(unsigned long irq_nr, int nokick)
+{
+	if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
+		atomic_inc(&ppc_n_lost_interrupts);
+		if (!nokick)
+			set_dec(1);
+	}
+}
+
+static void __pmac
+pmac_mask_and_ack_irq(unsigned int irq_nr)
+{
+        unsigned long bit = 1UL << (irq_nr & 0x1f);
+        int i = irq_nr >> 5;
+        unsigned long flags;
+
+        if ((unsigned)irq_nr >= max_irqs)
+                return;
+
+        clear_bit(irq_nr, ppc_cached_irq_mask);
+        if (test_and_clear_bit(irq_nr, ppc_lost_interrupts))
+                atomic_dec(&ppc_n_lost_interrupts);
+	spin_lock_irqsave(&pmac_pic_lock, flags);
+        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
+        out_le32(&pmac_irq_hw[i]->ack, bit);
+        do {
+                /* make sure ack gets to controller before we enable
+                   interrupts */
+                mb();
+        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
+                != (ppc_cached_irq_mask[i] & bit));
+	spin_unlock_irqrestore(&pmac_pic_lock, flags);
+}
+
+static void __pmac pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
+{
+        unsigned long bit = 1UL << (irq_nr & 0x1f);
+        int i = irq_nr >> 5;
+        unsigned long flags;
+
+        if ((unsigned)irq_nr >= max_irqs)
+                return;
+
+	spin_lock_irqsave(&pmac_pic_lock, flags);
+        /* enable unmasked interrupts */
+        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
+
+        do {
+                /* make sure mask gets to controller before we
+                   return to user */
+                mb();
+        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
+                != (ppc_cached_irq_mask[i] & bit));
+
+        /*
+         * Unfortunately, setting the bit in the enable register
+         * when the device interrupt is already on *doesn't* set
+         * the bit in the flag register or request another interrupt.
+         */
+        if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level))
+		__set_lost((ulong)irq_nr, nokicklost);
+	spin_unlock_irqrestore(&pmac_pic_lock, flags);
+}
+
+static void __pmac pmac_mask_irq(unsigned int irq_nr)
+{
+        clear_bit(irq_nr, ppc_cached_irq_mask);
+        pmac_set_irq_mask(irq_nr, 0);
+        mb();
+}
+
+static void __pmac pmac_unmask_irq(unsigned int irq_nr)
+{
+        set_bit(irq_nr, ppc_cached_irq_mask);
+        pmac_set_irq_mask(irq_nr, 0);
+}
+
+static void __pmac pmac_end_irq(unsigned int irq_nr)
+{
+	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+        	set_bit(irq_nr, ppc_cached_irq_mask);
+	        pmac_set_irq_mask(irq_nr, 1);
+	}
+}
+
+
+struct hw_interrupt_type pmac_pic = {
+        " PMAC-PIC ",
+        NULL,
+        NULL,
+        pmac_unmask_irq,
+        pmac_mask_irq,
+        pmac_mask_and_ack_irq,
+        pmac_end_irq,
+        NULL
+};
+
+struct hw_interrupt_type gatwick_pic = {
+	" GATWICK  ",
+	NULL,
+	NULL,
+	pmac_unmask_irq,
+	pmac_mask_irq,
+	pmac_mask_and_ack_irq,
+	pmac_end_irq,
+	NULL
+};
+
+static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	int irq, bits;
+	
+	for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) {
+		int i = irq >> 5;
+		bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
+		/* We must read level interrupts from the level register */
+		bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);
+		bits &= ppc_cached_irq_mask[i];
+		if (bits == 0)
+			continue;
+		irq += __ilog2(bits);
+		break;
+	}
+	/* The previous version of this code allowed for this case, we
+	 * don't.  Put this here to check for it.
+	 * -- Cort
+	 */
+	if ( irq_desc[irq].handler != &gatwick_pic )
+		printk("gatwick irq not from gatwick pic\n");
+	else
+		ppc_irq_dispatch_handler( regs, irq );
+}
+
+int
+pmac_get_irq(struct pt_regs *regs)
+{
+	int irq;
+	unsigned long bits = 0;
+
+#ifdef CONFIG_SMP
+	void psurge_smp_message_recv(struct pt_regs *);
+	
+       	/* IPI's are a hack on the powersurge -- Cort */
+       	if ( smp_processor_id() != 0 ) {
+		psurge_smp_message_recv(regs);
+		return -2;	/* ignore, already handled */
+        }
+#endif /* CONFIG_SMP */
+	for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
+		int i = irq >> 5;
+		bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
+		/* We must read level interrupts from the level register */
+		bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);
+		bits &= ppc_cached_irq_mask[i];
+		if (bits == 0)
+			continue;
+		irq += __ilog2(bits);
+		break;
+	}
+
+	return irq;
+}
+
+/* This routine will fix some missing interrupt values in the device tree
+ * on the gatwick mac-io controller used by some PowerBooks
+ */
+static void __init
+pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
+{
+	struct device_node *node;
+	int count;
+	
+	memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
+	node = gw->child;
+	count = 0;
+	while(node)
+	{
+		/* Fix SCC */
+		if (strcasecmp(node->name, "escc") == 0)
+			if (node->child) {
+				if (node->child->n_intrs < 3) {
+					node->child->intrs = &gatwick_int_pool[count];
+					count += 3;
+				}
+				node->child->n_intrs = 3;				
+				node->child->intrs[0].line = 15+irq_base;
+				node->child->intrs[1].line =  4+irq_base;
+				node->child->intrs[2].line =  5+irq_base;
+				printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
+					node->child->intrs[0].line,
+					node->child->intrs[1].line,
+					node->child->intrs[2].line);
+			}
+		/* Fix media-bay & left SWIM */
+		if (strcasecmp(node->name, "media-bay") == 0) {
+			struct device_node* ya_node;
+
+			if (node->n_intrs == 0)
+				node->intrs = &gatwick_int_pool[count++];
+			node->n_intrs = 1;
+			node->intrs[0].line = 29+irq_base;
+			printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
+					node->intrs[0].line);
+			
+			ya_node = node->child;
+			while(ya_node)
+			{
+				if (strcasecmp(ya_node->name, "floppy") == 0) {
+					if (ya_node->n_intrs < 2) {
+						ya_node->intrs = &gatwick_int_pool[count];
+						count += 2;
+					}
+					ya_node->n_intrs = 2;
+					ya_node->intrs[0].line = 19+irq_base;
+					ya_node->intrs[1].line =  1+irq_base;
+					printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
+						ya_node->intrs[0].line, ya_node->intrs[1].line);
+				} 
+				if (strcasecmp(ya_node->name, "ata4") == 0) {
+					if (ya_node->n_intrs < 2) {
+						ya_node->intrs = &gatwick_int_pool[count];
+						count += 2;
+					}
+					ya_node->n_intrs = 2;
+					ya_node->intrs[0].line = 14+irq_base;
+					ya_node->intrs[1].line =  3+irq_base;
+					printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n",
+						ya_node->intrs[0].line, ya_node->intrs[1].line);
+				} 
+				ya_node = ya_node->sibling;
+			}
+		}
+		node = node->sibling;
+	}
+	if (count > 10) {
+		printk("WARNING !! Gatwick interrupt pool overflow\n");
+		printk("  GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE);
+		printk("              requested = %d\n", count);
+	}
+}
+
+/*
+ * The PowerBook 3400/2400/3500 can have a combo ethernet/modem
+ * card which includes an ohare chip that acts as a second interrupt
+ * controller.  If we find this second ohare, set it up and fix the
+ * interrupt value in the device tree for the ethernet chip.
+ */
+static int __init enable_second_ohare(void)
+{
+	unsigned char bus, devfn;
+	unsigned short cmd;
+        unsigned long addr;
+	struct device_node *irqctrler = find_devices("pci106b,7");
+	struct device_node *ether;
+
+	if (irqctrler == NULL || irqctrler->n_addrs <= 0)
+		return -1;
+	addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40);
+	pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20);
+	max_irqs = 64;
+	if (pci_device_from_OF_node(irqctrler, &bus, &devfn) == 0) {
+		struct pci_controller* hose = pci_find_hose_for_OF_device(irqctrler);
+		if (!hose)
+		    printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
+		else {
+		    early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
+		    cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+	  	    cmd &= ~PCI_COMMAND_IO;
+		    early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
+		}
+	}
+
+	/* Fix interrupt for the modem/ethernet combo controller. The number
+	   in the device tree (27) is bogus (correct for the ethernet-only
+	   board but not the combo ethernet/modem board).
+	   The real interrupt is 28 on the second controller -> 28+32 = 60.
+	*/
+	ether = find_devices("pci1011,14");
+	if (ether && ether->n_intrs > 0) {
+		ether->intrs[0].line = 60;
+		printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n",
+		       ether->intrs[0].line);
+	}
+
+	/* Return the interrupt number of the cascade */
+	return irqctrler->intrs[0].line;
+}
+
+void __init
+pmac_pic_init(void)
+{
+        int i;
+        struct device_node *irqctrler;
+        unsigned long addr;
+	int irq_cascade = -1;
+	
+	/* We first try to detect Apple's new Core99 chipset, since mac-io
+	 * is quite different on those machines and contains an IBM MPIC2.
+	 */
+	irqctrler = find_type_devices("open-pic");
+	if (irqctrler != NULL)
+	{
+		printk("PowerMac using OpenPIC irq controller\n");
+		if (irqctrler->n_addrs > 0)
+		{
+			int nmi_irq = -1;
+			unsigned char senses[NR_IRQS];
+#ifdef CONFIG_XMON
+			struct device_node* pswitch;
+
+			pswitch = find_devices("programmer-switch");
+			if (pswitch && pswitch->n_intrs)
+				nmi_irq = pswitch->intrs[0].line;
+#endif /* CONFIG_XMON */
+			prom_get_irq_senses(senses, 0, NR_IRQS);
+			OpenPIC_InitSenses = senses;
+			OpenPIC_NumInitSenses = NR_IRQS;
+			ppc_md.get_irq = openpic_get_irq;
+			OpenPIC_Addr = ioremap(irqctrler->addrs[0].address,
+					       irqctrler->addrs[0].size);
+			openpic_init(1, 0, 0, nmi_irq);
+#ifdef CONFIG_XMON
+			if (nmi_irq >= 0)
+				request_irq(nmi_irq, xmon_irq, 0,
+					    "NMI - XMON", 0);
+#endif	/* CONFIG_XMON */
+			return;
+		}
+		irqctrler = NULL;
+	}
+
+	/* Get the level/edge settings, assume if it's not
+	 * a Grand Central nor an OHare, then it's an Heathrow
+	 * (or Paddington).
+	 */
+	if (find_devices("gc"))
+		level_mask[0] = GC_LEVEL_MASK;
+	else if (find_devices("ohare")) {
+		level_mask[0] = OHARE_LEVEL_MASK;
+		/* We might have a second cascaded ohare */
+		level_mask[1] = OHARE_LEVEL_MASK;
+	} else {
+		level_mask[0] = HEATHROW_LEVEL_MASK;
+		level_mask[1] = 0;
+		/* We might have a second cascaded heathrow */
+		level_mask[2] = HEATHROW_LEVEL_MASK;
+		level_mask[3] = 0;
+	}
+
+	/*
+	 * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
+	 * 1998 G3 Series PowerBooks have 128, 
+	 * other powermacs have 32.
+	 * The combo ethernet/modem card for the Powerstar powerbooks
+	 * (2400/3400/3500, ohare based) has a second ohare chip
+	 * effectively making a total of 64.
+	 */
+	max_irqs = max_real_irqs = 32;
+	irqctrler = find_devices("mac-io");
+	if (irqctrler)
+	{
+		max_real_irqs = 64;
+		if (irqctrler->next)
+			max_irqs = 128;
+		else
+			max_irqs = 64;
+	}
+	for ( i = 0; i < max_real_irqs ; i++ )
+		irq_desc[i].handler = &pmac_pic;
+
+	/* get addresses of first controller */
+	if (irqctrler) {
+		if  (irqctrler->n_addrs > 0) {
+			addr = (unsigned long) 
+				ioremap(irqctrler->addrs[0].address, 0x40);
+			for (i = 0; i < 2; ++i)
+				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+					(addr + (2 - i) * 0x10);
+		}
+		
+		/* get addresses of second controller */
+		irqctrler = irqctrler->next;
+		if (irqctrler && irqctrler->n_addrs > 0) {
+			addr = (unsigned long) 
+				ioremap(irqctrler->addrs[0].address, 0x40);
+			for (i = 2; i < 4; ++i)
+				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+					(addr + (4 - i) * 0x10);
+			irq_cascade = irqctrler->intrs[0].line;
+			if (device_is_compatible(irqctrler, "gatwick"))
+				pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
+		}
+	} else {
+		/* older powermacs have a GC (grand central) or ohare at
+		   f3000000, with interrupt control registers at f3000020. */
+		addr = (unsigned long) ioremap(0xf3000000, 0x40);
+		pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20);
+	}
+
+	/* PowerBooks 3400 and 3500 can have a second controller in a second
+	   ohare chip, on the combo ethernet/modem card */
+	if (machine_is_compatible("AAPL,3400/2400")
+	     || machine_is_compatible("AAPL,3500"))
+		irq_cascade = enable_second_ohare();
+
+	/* disable all interrupts in all controllers */
+	for (i = 0; i * 32 < max_irqs; ++i)
+		out_le32(&pmac_irq_hw[i]->enable, 0);
+	/* mark level interrupts */
+	for (i = 0; i < max_irqs; i++)
+		if (level_mask[i >> 5] & (1UL << (i & 0x1f)))
+			irq_desc[i].status = IRQ_LEVEL;
+	
+	/* get interrupt line of secondary interrupt controller */
+	if (irq_cascade >= 0) {
+		printk(KERN_INFO "irq: secondary controller on irq %d\n",
+			(int)irq_cascade);
+		for ( i = max_real_irqs ; i < max_irqs ; i++ )
+			irq_desc[i].handler = &gatwick_pic;
+		request_irq( irq_cascade, gatwick_action, SA_INTERRUPT,
+			     "cascade", 0 );
+	}
+	printk("System has %d possible interrupts\n", max_irqs);
+	if (max_irqs != max_real_irqs)
+		printk(KERN_DEBUG "%d interrupts on main controller\n",
+			max_real_irqs);
+
+#ifdef CONFIG_XMON
+	request_irq(20, xmon_irq, 0, "NMI - XMON", 0);
+#endif	/* CONFIG_XMON */
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * These procedures are used in implementing sleep on the powerbooks.
+ * sleep_save_intrs() saves the states of all interrupt enables
+ * and disables all interrupts except for the nominated one.
+ * sleep_restore_intrs() restores the states of all interrupt enables.
+ */
+unsigned int sleep_save_mask[2];
+
+void __pmac
+pmac_sleep_save_intrs(int viaint)
+{
+	sleep_save_mask[0] = ppc_cached_irq_mask[0];
+	sleep_save_mask[1] = ppc_cached_irq_mask[1];
+	ppc_cached_irq_mask[0] = 0;
+	ppc_cached_irq_mask[1] = 0;
+	if (viaint > 0)
+		set_bit(viaint, ppc_cached_irq_mask);
+	out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]);
+	if (max_real_irqs > 32)
+		out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);
+	(void)in_le32(&pmac_irq_hw[0]->event);
+	/* make sure mask gets to controller before we return to caller */
+	mb();
+        (void)in_le32(&pmac_irq_hw[0]->enable);
+}
+
+void __pmac
+pmac_sleep_restore_intrs(void)
+{
+	int i;
+
+	out_le32(&pmac_irq_hw[0]->enable, 0);
+	if (max_real_irqs > 32)
+		out_le32(&pmac_irq_hw[1]->enable, 0);
+	mb();
+	for (i = 0; i < max_real_irqs; ++i)
+		if (test_bit(i, sleep_save_mask))
+			pmac_unmask_irq(i);
+}
+#endif /* CONFIG_PMAC_PBOOK */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/pmac_pic.h linux-2.4.20/arch/ppc/platforms/pmac_pic.h
--- linux-2.4.19/arch/ppc/platforms/pmac_pic.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/pmac_pic.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,14 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+#ifndef __PPC_PLATFORMS_PMAC_PIC_H
+#define __PPC_PLATFORMS_PMAC_PIC_H
+
+#include <linux/irq.h>
+
+extern struct hw_interrupt_type pmac_pic;
+
+void pmac_pic_init(void);
+int pmac_get_irq(struct pt_regs *regs);
+
+#endif /* __PPC_PLATFORMS_PMAC_PIC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/pmac_setup.c linux-2.4.20/arch/ppc/platforms/pmac_setup.c
--- linux-2.4.19/arch/ppc/platforms/pmac_setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/pmac_setup.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,957 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/platforms/setup.c
+ *
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Adapted for Power Macintosh by Paul Mackerras
+ *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ *  Derived from "arch/alpha/kernel/setup.c"
+ *    Copyright (C) 1995 Linus Torvalds
+ *
+ *  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.
+ *
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/blkdev.h>
+#include <linux/genhd.h>
+
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/ohare.h>
+#include <asm/mediabay.h>
+#include <asm/machdep.h>
+#include <asm/keyboard.h>
+#include <asm/dma.h>
+#include <asm/bootx.h>
+#include <asm/cputable.h>
+#include <asm/btext.h>
+#include <asm/pmac_feature.h>
+#include <asm/time.h>
+
+#include "pmac_pic.h"
+#include "mem_pieces.h"
+#include "scsi.h" /* sd_find_target */
+#include "sd.h"
+#include "mac.h"
+
+extern long pmac_time_init(void);
+extern unsigned long pmac_get_rtc_time(void);
+extern int pmac_set_rtc_time(unsigned long nowtime);
+extern void pmac_read_rtc_time(void);
+extern void pmac_calibrate_decr(void);
+extern void pmac_pcibios_fixup(void);
+extern void pmac_find_bridges(void);
+extern int pmac_ide_check_base(ide_ioreg_t base);
+extern ide_ioreg_t pmac_ide_get_base(int index);
+extern void pmac_ide_init_hwif_ports(hw_regs_t *hw,
+	ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq);
+
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_translate(unsigned char keycode, unsigned char *keycodep,
+		     char raw_mode);
+extern char mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void __init mackbd_init_hw(void);
+extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
+				 char raw_mode);
+extern char mac_hid_kbd_unexpected_up(unsigned char keycode);
+extern void mac_hid_init_hw(void);
+extern unsigned char mac_hid_kbd_sysrq_xlate[];
+extern unsigned char pckbd_sysrq_xlate[];
+extern unsigned char mackbd_sysrq_xlate[];
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern int keyboard_sends_linux_keycodes;
+extern void pmac_nvram_update(void);
+
+extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial);
+extern void pmac_pcibios_after_init(void);
+
+struct device_node *memory_node;
+
+unsigned char drive_info;
+
+int ppc_override_l2cr = 0;
+int ppc_override_l2cr_value;
+int has_l2cache = 0;
+
+static int current_root_goodness = -1;
+
+extern char saved_command_line[];
+
+extern int pmac_newworld;
+
+#define DEFAULT_ROOT_DEVICE 0x0801	/* sda1 - slightly silly choice */
+
+extern void zs_kgdb_hook(int tty_num);
+static void ohare_init(void);
+#ifdef CONFIG_BOOTX_TEXT
+void pmac_progress(char *s, unsigned short hex);
+#endif
+
+sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN;
+
+#ifdef CONFIG_SMP
+extern struct smp_ops_t psurge_smp_ops;
+extern struct smp_ops_t core99_smp_ops;
+#endif /* CONFIG_SMP */
+
+/*
+ * Assume here that all clock rates are the same in a
+ * smp system.  -- Cort
+ */
+int __openfirmware
+of_show_percpuinfo(struct seq_file *m, int i)
+{
+	struct device_node *cpu_node;
+	int *fp, s;
+			
+	cpu_node = find_type_devices("cpu");
+	if (!cpu_node)
+		return 0;
+	for (s = 0; s < i && cpu_node->next; s++)
+		cpu_node = cpu_node->next;
+	fp = (int *) get_property(cpu_node, "clock-frequency", NULL);
+	if (fp)
+		seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000);
+	return 0;
+}
+
+int __pmac
+pmac_show_cpuinfo(struct seq_file *m)
+{
+	struct device_node *np;
+	char *pp;
+	int plen;
+	int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
+		NULL, PMAC_MB_INFO_MODEL, 0);
+	unsigned int mbflags = (unsigned int)pmac_call_feature(PMAC_FTR_GET_MB_INFO,
+		NULL, PMAC_MB_INFO_FLAGS, 0);
+	char* mbname;
+
+	if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, (int)&mbname) != 0)
+		mbname = "Unknown";
+		
+	/* find motherboard type */
+	seq_printf(m, "machine\t\t: ");
+	np = find_devices("device-tree");
+	if (np != NULL) {
+		pp = (char *) get_property(np, "model", NULL);
+		if (pp != NULL)
+			seq_printf(m, "%s\n", pp);
+		else
+			seq_printf(m, "PowerMac\n");
+		pp = (char *) get_property(np, "compatible", &plen);
+		if (pp != NULL) {
+			seq_printf(m, "motherboard\t:");
+			while (plen > 0) {
+				int l = strlen(pp) + 1;
+				seq_printf(m, " %s", pp);
+				plen -= l;
+				pp += l;
+			}
+			seq_printf(m, "\n");
+		}
+	} else
+		seq_printf(m, "PowerMac\n");
+
+	/* print parsed model */
+	seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname);
+	seq_printf(m, "pmac flags\t: %08x\n", mbflags);
+
+	/* find l2 cache info */
+	np = find_devices("l2-cache");
+	if (np == 0)
+		np = find_type_devices("cache");
+	if (np != 0) {
+		unsigned int *ic = (unsigned int *)
+			get_property(np, "i-cache-size", NULL);
+		unsigned int *dc = (unsigned int *)
+			get_property(np, "d-cache-size", NULL);
+		seq_printf(m, "L2 cache\t:");
+		has_l2cache = 1;
+		if (get_property(np, "cache-unified", NULL) != 0 && dc) {
+			seq_printf(m, " %dK unified", *dc / 1024);
+		} else {
+			if (ic)
+				seq_printf(m, " %dK instruction", *ic / 1024);
+			if (dc)
+				seq_printf(m, "%s %dK data",
+					   (ic? " +": ""), *dc / 1024);
+		}
+		pp = get_property(np, "ram-type", NULL);
+		if (pp)
+			seq_printf(m, " %s", pp);
+		seq_printf(m, "\n");
+	}
+
+	/* find ram info */
+	np = find_devices("memory");
+	if (np != 0) {
+		int n;
+		struct reg_property *reg = (struct reg_property *)
+			get_property(np, "reg", &n);
+		
+		if (reg != 0) {
+			unsigned long total = 0;
+
+			for (n /= sizeof(struct reg_property); n > 0; --n)
+				total += (reg++)->size;
+			seq_printf(m, "memory\t\t: %luMB\n", total >> 20);
+		}
+	}
+
+	/* Checks "l2cr-value" property in the registry */
+	np = find_devices("cpus");		
+	if (np == 0)
+		np = find_type_devices("cpu");		
+	if (np != 0) {
+		unsigned int *l2cr = (unsigned int *)
+			get_property(np, "l2cr-value", NULL);
+		if (l2cr != 0) {
+			seq_printf(m, "l2cr override\t: 0x%x\n", *l2cr);
+		}
+	}
+	
+	/* Indicate newworld/oldworld */
+	seq_printf(m, "pmac-generation\t: %s\n",
+		   pmac_newworld ? "NewWorld" : "OldWorld");
+	
+
+	return 0;
+}
+
+#ifdef CONFIG_VT
+/*
+ * Dummy mksound function that does nothing.
+ * The real one is in the dmasound driver.
+ */
+static void __pmac
+pmac_mksound(unsigned int hz, unsigned int ticks)
+{
+}
+#endif /* CONFIG_VT */
+
+static volatile u32 *sysctrl_regs;
+
+void __init
+pmac_setup_arch(void)
+{
+	struct device_node *cpu;
+	int *fp;
+	unsigned long pvr;
+	
+	pvr = PVR_VER(mfspr(PVR));
+
+	/* Set loops_per_jiffy to a half-way reasonable value,
+	   for use until calibrate_delay gets called. */
+	cpu = find_type_devices("cpu");
+	if (cpu != 0) {
+		fp = (int *) get_property(cpu, "clock-frequency", NULL);
+		if (fp != 0) {
+			if (pvr == 4 || pvr >= 8)
+				/* 604, G3, G4 etc. */
+				loops_per_jiffy = *fp / HZ;
+			else
+				/* 601, 603, etc. */
+				loops_per_jiffy = *fp / (2*HZ);
+		} else
+			loops_per_jiffy = 50000000 / HZ;
+	}
+
+	/* this area has the CPU identification register
+	   and some registers used by smp boards */
+	sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);
+	ohare_init();
+
+	/* Lookup PCI hosts */
+	pmac_find_bridges();
+	
+	/* Checks "l2cr-value" property in the registry */
+	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR) {
+		struct device_node *np = find_devices("cpus");		
+		if (np == 0)
+			np = find_type_devices("cpu");		
+		if (np != 0) {
+			unsigned int *l2cr = (unsigned int *)
+				get_property(np, "l2cr-value", NULL);
+			if (l2cr != 0) {
+				ppc_override_l2cr = 1;
+				ppc_override_l2cr_value = *l2cr;
+				_set_L2CR(0);
+				_set_L2CR(ppc_override_l2cr_value);
+			}
+		}
+	}
+
+	if (ppc_override_l2cr)
+		printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n",
+			ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000)
+				? "enabled" : "disabled");
+	
+#ifdef CONFIG_KGDB
+	zs_kgdb_hook(0);
+#endif
+
+#ifdef CONFIG_ADB_CUDA
+	find_via_cuda();
+#else
+	if (find_devices("via-cuda")) {
+		printk("WARNING ! Your machine is Cuda based but your kernel\n");
+		printk("          wasn't compiled with CONFIG_ADB_CUDA option !\n");
+	}
+#endif	
+#ifdef CONFIG_ADB_PMU
+	find_via_pmu();
+#else
+	if (find_devices("via-pmu")) {
+		printk("WARNING ! Your machine is PMU based but your kernel\n");
+		printk("          wasn't compiled with CONFIG_ADB_PMU option !\n");
+	}
+#endif	
+#ifdef CONFIG_NVRAM
+	pmac_nvram_init();
+#endif
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+#ifdef CONFIG_VT
+	kd_mksound = pmac_mksound;
+#endif
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+	else
+#endif
+		ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
+
+#ifdef CONFIG_SMP
+	/* Check for Core99 */
+	if (find_devices("uni-n"))
+		ppc_md.smp_ops = &core99_smp_ops;
+	else
+		ppc_md.smp_ops = &psurge_smp_ops;
+#endif /* CONFIG_SMP */
+
+	pci_create_OF_bus_map();
+}
+
+static void __init ohare_init(void)
+{
+	/*
+	 * Turn on the L2 cache.
+	 * We assume that we have a PSX memory controller iff
+	 * we have an ohare I/O controller.
+	 */
+	if (find_devices("ohare") != NULL) {
+		if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {
+			if (sysctrl_regs[4] & 0x10)
+				sysctrl_regs[4] |= 0x04000020;
+			else
+				sysctrl_regs[4] |= 0x04000000;
+			if(has_l2cache)
+				printk(KERN_INFO "Level 2 cache enabled\n");
+		}
+	}
+}
+
+extern char *bootpath;
+extern char *bootdevice;
+void *boot_host;
+int boot_target;
+int boot_part;
+extern kdev_t boot_dev;
+
+void __init
+pmac_init2(void)
+{
+#ifdef CONFIG_ADB_PMU
+	via_pmu_start();
+#endif
+#ifdef CONFIG_ADB_CUDA
+	via_cuda_start();
+#endif
+#ifdef CONFIG_PMAC_PBOOK
+	media_bay_init();
+#endif
+	pmac_feature_late_init();
+}
+
+/* Borrowed from fs/partition/check.c */
+static unsigned char* __init
+read_one_block(struct block_device *bdev, unsigned long n, struct page **v)
+{
+	struct address_space *mapping = bdev->bd_inode->i_mapping;
+	int sect = PAGE_CACHE_SIZE / 512;
+	struct page *page;
+
+	page = read_cache_page(mapping, n/sect,
+			(filler_t *)mapping->a_ops->readpage, NULL);
+	if (!IS_ERR(page)) {
+		wait_on_page(page);
+		if (!Page_Uptodate(page))
+			goto fail;
+		if (PageError(page))
+			goto fail;
+		*v = page;
+		return (unsigned char *)page_address(page) + 512 * (n % sect);
+fail:
+		page_cache_release(page);
+	}
+	*v = NULL;
+	return NULL;
+}
+
+#ifdef CONFIG_SCSI
+void __init
+note_scsi_host(struct device_node *node, void *host)
+{
+	int l;
+	char *p;
+
+	l = strlen(node->full_name);
+	if (bootpath != NULL && bootdevice != NULL
+	    && strncmp(node->full_name, bootdevice, l) == 0
+	    && (bootdevice[l] == '/' || bootdevice[l] == 0)) {
+		boot_host = host;
+		/*
+		 * There's a bug in OF 1.0.5.  (Why am I not surprised.)
+		 * If you pass a path like scsi/sd@1:0 to canon, it returns
+		 * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0
+		 * That is, the scsi target number doesn't get preserved.
+		 * So we pick the target number out of bootpath and use that.
+		 */
+		p = strstr(bootpath, "/sd@");
+		if (p != NULL) {
+			p += 4;
+			boot_target = simple_strtoul(p, NULL, 10);
+			p = strchr(p, ':');
+			if (p != NULL)
+				boot_part = simple_strtoul(p + 1, NULL, 10);
+		}
+	}
+}
+#endif /* CONFIG_SCSI */
+
+#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
+kdev_t __init
+find_ide_boot(void)
+{
+	char *p;
+	int n;
+	kdev_t __init pmac_find_ide_boot(char *bootdevice, int n);
+
+	if (bootdevice == NULL)
+		return 0;
+	p = strrchr(bootdevice, '/');
+	if (p == NULL)
+		return 0;
+	n = p - bootdevice;
+
+	return pmac_find_ide_boot(bootdevice, n);
+}
+#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */
+
+void __init
+find_boot_device(void)
+{
+#if defined(CONFIG_SCSI) && defined(CONFIG_BLK_DEV_SD)
+	if (boot_host != NULL) {
+		boot_dev = sd_find_target(boot_host, boot_target);
+		if (boot_dev != 0)
+			return;
+	}
+#endif
+#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
+	boot_dev = find_ide_boot();
+#endif
+}
+
+static void __init
+check_bootable_part(kdev_t dev, int blk, struct mac_partition *part)
+{
+	int goodness = 0;
+
+	macpart_fix_string(part->processor, 16);
+	macpart_fix_string(part->name, 32);
+	macpart_fix_string(part->type, 32);
+    
+	if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
+	    && strcasecmp(part->processor, "powerpc") == 0)
+		goodness++;
+
+	if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
+	    || (strnicmp(part->type, "Linux", 5) == 0
+	    && strcasecmp(part->type, "Linux_swap") != 0)) {
+		int i, l;
+
+		goodness++;
+		l = strlen(part->name);
+		if (strcmp(part->name, "/") == 0)
+			goodness++;
+		for (i = 0; i <= l - 4; ++i) {
+			if (strnicmp(part->name + i, "root",
+				     4) == 0) {
+				goodness += 2;
+				break;
+			}
+		}
+		if (strnicmp(part->name, "swap", 4) == 0)
+			goodness--;
+	}
+
+	if (goodness > current_root_goodness) {
+		ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + blk);
+		current_root_goodness = goodness;
+	}
+}
+
+static void __init
+check_bootable_disk(kdev_t dev, struct block_device *bdev)
+{
+	struct mac_partition *part;
+	struct mac_driver_desc *md;
+	struct page* pg;
+	unsigned secsize, blocks_in_map, blk;
+	unsigned char* data;
+	
+	/* Check driver descriptor */
+	md = (struct mac_driver_desc *) read_one_block(bdev, 0, &pg);
+	if (!md)
+		return;
+	if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC)
+		goto fail;
+	secsize = be16_to_cpu(md->block_size);
+	page_cache_release(pg);
+	
+	/* Check if it looks like a mac partition map */
+	data = read_one_block(bdev, secsize/512, &pg);
+	if (!data)
+		goto fail;
+	part = (struct mac_partition *) (data + secsize%512);
+	if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
+		goto fail;
+
+	/* Iterate the partition map */
+	blocks_in_map = be32_to_cpu(part->map_count);
+	for (blk = 1; blk <= blocks_in_map; ++blk) {
+		int pos = blk * secsize;
+		page_cache_release(pg);
+		data = read_one_block(bdev, pos/512, &pg);
+		if (!data)
+			break;
+		part = (struct mac_partition *) (data + pos%512);
+		if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
+			break;
+		check_bootable_part(dev, blk, part);
+	}
+fail:
+	if (pg)	
+		page_cache_release(pg);
+}
+
+static int __init
+walk_bootable(struct gendisk *hd, void *data)
+{
+	int drive;
+	
+	for (drive=0; drive<hd->nr_real; drive++) {
+		kdev_t dev;
+		struct block_device *bdev;
+		int rc;
+
+		dev = MKDEV(hd->major, drive << hd->minor_shift);
+		if (boot_dev && boot_dev != dev)
+			continue;
+		bdev = bdget(kdev_t_to_nr(dev));
+		if (bdev == NULL)
+			continue;
+		rc = blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW);
+		if (rc == 0) {
+			check_bootable_disk(dev, bdev);
+			blkdev_put(bdev, BDEV_RAW);
+		}
+	}
+
+	return 0;
+}
+
+void __init
+pmac_discover_root(void)
+{
+	char* p;
+
+	/* Check if root devices already got selected by other ways */
+	if (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE))
+		return;
+	p = strstr(saved_command_line, "root=");
+	if (p != NULL && (p == saved_command_line || p[-1] == ' '))
+		return;
+
+	/* Find the device used for booting if we can */
+	find_boot_device();
+
+	/* Try to locate a partition */
+	walk_gendisk(walk_bootable, NULL);
+}
+
+void __pmac
+pmac_restart(char *cmd)
+{
+#ifdef CONFIG_ADB_CUDA
+	struct adb_request req;
+#endif /* CONFIG_ADB_CUDA */
+
+#ifdef CONFIG_NVRAM
+	pmac_nvram_update();
+#endif
+	
+	switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+	case SYS_CTRLER_CUDA:
+		cuda_request(&req, NULL, 2, CUDA_PACKET,
+			     CUDA_RESET_SYSTEM);
+		for (;;)
+			cuda_poll();
+		break;
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU		
+	case SYS_CTRLER_PMU:
+		pmu_restart();
+		break;
+#endif /* CONFIG_ADB_PMU */		
+	default: ;
+	}
+}
+
+void __pmac
+pmac_power_off(void)
+{
+#ifdef CONFIG_ADB_CUDA
+	struct adb_request req;
+#endif /* CONFIG_ADB_CUDA */
+
+#ifdef CONFIG_NVRAM
+	pmac_nvram_update();
+#endif
+	
+	switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+	case SYS_CTRLER_CUDA:
+		cuda_request(&req, NULL, 2, CUDA_PACKET,
+			     CUDA_POWERDOWN);
+		for (;;)
+			cuda_poll();
+		break;
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU
+	case SYS_CTRLER_PMU:
+		pmu_shutdown();
+		break;
+#endif /* CONFIG_ADB_PMU */
+	default: ;
+	}
+}
+
+void __pmac
+pmac_halt(void)
+{
+   pmac_power_off();
+}
+
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+static int __pmac
+pmac_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+	if (pmac_ide_check_base(from) >= 0)
+		return 0;
+#endif
+	return check_region(from, extent);
+}
+
+static void __pmac
+pmac_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+	if (pmac_ide_check_base(from) >= 0)
+		return;
+#endif
+	request_region(from, extent, name);
+}
+
+static void __pmac
+pmac_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+	if (pmac_ide_check_base(from) >= 0)
+		return;
+#endif
+	release_region(from, extent);
+}
+
+#ifndef CONFIG_BLK_DEV_IDE_PMAC
+/*
+ * This is only used if we have a PCI IDE controller, not
+ * for the IDE controller in the ohare/paddington/heathrow/keylargo.
+ */
+static void __pmac
+pmac_ide_pci_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port,
+		ide_ioreg_t ctrl_port, int *irq)
+{
+	ide_ioreg_t reg = data_port;
+	int i;
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw->io_ports[i] = reg;
+		reg += 1;
+	}
+	hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+}
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
+
+/*
+ * Read in a property describing some pieces of memory.
+ */
+
+static int __init
+get_mem_prop(char *name, struct mem_pieces *mp)
+{
+	struct reg_property *rp;
+	int i, s;
+	unsigned int *ip;
+	int nac = prom_n_addr_cells(memory_node);
+	int nsc = prom_n_size_cells(memory_node);
+
+	ip = (unsigned int *) get_property(memory_node, name, &s);
+	if (ip == NULL) {
+		printk(KERN_ERR "error: couldn't get %s property on /memory\n",
+		       name);
+		return 0;
+	}
+	s /= (nsc + nac) * 4;
+	rp = mp->regions;
+	for (i = 0; i < s; ++i, ip += nac+nsc) {
+		if (nac >= 2 && ip[nac-2] != 0)
+			continue;
+		rp->address = ip[nac-1];
+		if (nsc >= 2 && ip[nac+nsc-2] != 0)
+			rp->size = ~0U;
+		else
+			rp->size = ip[nac+nsc-1];
+		++rp;
+	}
+	mp->n_regions = rp - mp->regions;
+
+	/* Make sure the pieces are sorted. */
+	mem_pieces_sort(mp);
+	mem_pieces_coalesce(mp);
+	return 1;
+}
+
+/*
+ * On systems with Open Firmware, collect information about
+ * physical RAM and which pieces are already in use.
+ * At this point, we have (at least) the first 8MB mapped with a BAT.
+ * Our text, data, bss use something over 1MB, starting at 0.
+ * Open Firmware may be using 1MB at the 4MB point.
+ */
+unsigned long __init
+pmac_find_end_of_memory(void)
+{
+	unsigned long a, total;
+	struct mem_pieces phys_mem;
+
+	/*
+	 * Find out where physical memory is, and check that it
+	 * starts at 0 and is contiguous.  It seems that RAM is
+	 * always physically contiguous on Power Macintoshes.
+	 *
+	 * Supporting discontiguous physical memory isn't hard,
+	 * it just makes the virtual <-> physical mapping functions
+	 * more complicated (or else you end up wasting space
+	 * in mem_map).
+	 */
+	memory_node = find_devices("memory");
+	if (memory_node == NULL || !get_mem_prop("reg", &phys_mem)
+	    || phys_mem.n_regions == 0)
+		panic("No RAM??");
+	a = phys_mem.regions[0].address;
+	if (a != 0)
+		panic("RAM doesn't start at physical address 0");
+	total = phys_mem.regions[0].size;
+
+	if (phys_mem.n_regions > 1) {
+		printk("RAM starting at 0x%x is not contiguous\n",
+		       phys_mem.regions[1].address);
+		printk("Using RAM from 0 to 0x%lx\n", total-1);
+	}
+
+	return total;
+}
+
+void __init
+select_adb_keyboard(void)
+{
+#ifdef CONFIG_VT
+#ifdef CONFIG_INPUT
+	ppc_md.kbd_init_hw       = mac_hid_init_hw;
+	ppc_md.kbd_translate     = mac_hid_kbd_translate;
+	ppc_md.kbd_unexpected_up = mac_hid_kbd_unexpected_up;
+	ppc_md.kbd_setkeycode    = 0;
+	ppc_md.kbd_getkeycode    = 0;
+	ppc_md.kbd_leds		 = 0;
+#ifdef CONFIG_MAGIC_SYSRQ
+#ifdef CONFIG_MAC_ADBKEYCODES
+	if (!keyboard_sends_linux_keycodes) {
+		ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate;
+		SYSRQ_KEY = 0x69;
+	} else
+#endif /* CONFIG_MAC_ADBKEYCODES */
+	{
+		ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
+		SYSRQ_KEY = 0x54;
+	}
+#endif /* CONFIG_MAGIC_SYSRQ */
+#elif defined(CONFIG_ADB_KEYBOARD)
+	ppc_md.kbd_setkeycode       = mackbd_setkeycode;
+	ppc_md.kbd_getkeycode       = mackbd_getkeycode;
+	ppc_md.kbd_translate        = mackbd_translate;
+	ppc_md.kbd_unexpected_up    = mackbd_unexpected_up;
+	ppc_md.kbd_leds             = mackbd_leds;
+	ppc_md.kbd_init_hw          = mackbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.ppc_kbd_sysrq_xlate  = mackbd_sysrq_xlate;
+	SYSRQ_KEY = 0x69;
+#endif /* CONFIG_MAGIC_SYSRQ */
+#endif /* CONFIG_INPUT_ADBHID/CONFIG_ADB_KEYBOARD */
+#endif /* CONFIG_VT */
+}
+
+void __init
+pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	  unsigned long r6, unsigned long r7)
+{
+	/* isa_io_base gets set in pmac_find_bridges */
+	isa_mem_base = PMAC_ISA_MEM_BASE;
+	pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
+	ISA_DMA_THRESHOLD = ~0L;
+	DMA_MODE_READ = 1;
+	DMA_MODE_WRITE = 2;
+
+	ppc_md.setup_arch     = pmac_setup_arch;
+	ppc_md.show_cpuinfo   = pmac_show_cpuinfo;
+	ppc_md.show_percpuinfo = of_show_percpuinfo;
+	ppc_md.irq_cannonicalize = NULL;
+	ppc_md.init_IRQ       = pmac_pic_init;
+	ppc_md.get_irq        = pmac_get_irq; /* Changed later on ... */
+	ppc_md.init           = pmac_init2;
+	
+	ppc_md.pcibios_fixup  = pmac_pcibios_fixup;
+	ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook;
+	ppc_md.pcibios_after_init = pmac_pcibios_after_init;
+
+	ppc_md.discover_root  = pmac_discover_root;
+
+	ppc_md.restart        = pmac_restart;
+	ppc_md.power_off      = pmac_power_off;
+	ppc_md.halt           = pmac_halt;
+
+	ppc_md.time_init      = pmac_time_init;
+	ppc_md.set_rtc_time   = pmac_set_rtc_time;
+	ppc_md.get_rtc_time   = pmac_get_rtc_time;
+	ppc_md.calibrate_decr = pmac_calibrate_decr;
+
+	ppc_md.find_end_of_memory = pmac_find_end_of_memory;
+
+	ppc_md.feature_call   = pmac_do_feature_call;
+
+	select_adb_keyboard();
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+        ppc_ide_md.ide_check_region	= pmac_ide_check_region;
+        ppc_ide_md.ide_request_region	= pmac_ide_request_region;
+        ppc_ide_md.ide_release_region	= pmac_ide_release_region;
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+        ppc_ide_md.ide_init_hwif	= pmac_ide_init_hwif_ports;
+        ppc_ide_md.default_io_base	= pmac_ide_get_base;
+#else /* CONFIG_BLK_DEV_IDE_PMAC */
+        ppc_ide_md.ide_init_hwif	= pmac_ide_pci_init_hwif_ports;
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
+
+#ifdef CONFIG_BOOTX_TEXT
+	ppc_md.progress = pmac_progress;
+#endif /* CONFIG_BOOTX_TEXT */
+
+	if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0);
+	
+}
+
+#ifdef CONFIG_BOOTX_TEXT
+void __init
+pmac_progress(char *s, unsigned short hex)
+{
+	if (boot_text_mapped) {
+		btext_drawstring(s);
+		btext_drawchar('\n');
+	}
+}
+#endif /* CONFIG_BOOTX_TEXT */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/pmac_sleep.S linux-2.4.20/arch/ppc/platforms/pmac_sleep.S
--- linux-2.4.19/arch/ppc/platforms/pmac_sleep.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/pmac_sleep.S	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,485 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * This file contains sleep low-level functions for PowerBook G3.
+ *    Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *    and Paul Mackerras (paulus@samba.org).
+ *
+ * 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.
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include "../kernel/ppc_defs.h" // DAMMIT !
+
+#define MAGIC	0x4c617273	/* 'Lars' */
+
+/*
+ * Structure for storing CPU registers on the stack.
+ */
+#define SL_SP		0
+#define SL_PC		4
+#define SL_MSR		8
+#define SL_SDR1		0xc
+#define SL_SPRG0	0x10	/* 4 sprg's */
+#define SL_DBAT0	0x20
+#define SL_IBAT0	0x28
+#define SL_DBAT1	0x30
+#define SL_IBAT1	0x38
+#define SL_DBAT2	0x40
+#define SL_IBAT2	0x48
+#define SL_DBAT3	0x50
+#define SL_IBAT3	0x58
+#define SL_TB		0x60
+#define SL_HID0		0x68
+#define SL_HID1		0x6c
+#define SL_MSSCR0	0x70
+#define SL_MSSSR0	0x74
+#define SL_ICTRL	0x78
+#define SL_LDSTCR	0x7c
+#define SL_LDSTDB	0x80
+#define SL_R2		0x84
+#define SL_CR		0x88
+#define SL_R12		0x8c	/* r12 to r31 */
+#define SL_SIZE		(SL_R12 + 80)
+
+	.text
+	.align	5
+
+#if defined(CONFIG_PMAC_PBOOK)
+
+/* This gets called by via-pmu.c late during the sleep process.
+ * The PMU was already send the sleep command and will shut us down
+ * soon. We need to save all that is needed and setup the wakeup
+ * vector that will be called by the ROM on wakeup
+ */
+_GLOBAL(low_sleep_handler)
+	mflr	r0
+	stw	r0,4(r1)
+	stwu	r1,-SL_SIZE(r1)
+	mfcr	r0
+	stw	r0,SL_CR(r1)
+	stw	r2,SL_R2(r1)
+	stmw	r12,SL_R12(r1)
+
+	/* Save MSR & SDR1 */
+	mfmsr	r4
+	stw	r4,SL_MSR(r1)
+	mfsdr1	r4
+	stw	r4,SL_SDR1(r1)
+
+	/* Get a stable timebase and save it */
+1:	mftbu	r4
+	stw	r4,SL_TB(r1)
+	mftb	r5
+	stw	r5,SL_TB+4(r1)
+	mftbu	r3
+	cmpw	r3,r4
+	bne	1b
+	
+	/* Save SPRGs */
+	mfsprg	r4,0
+	stw	r4,SL_SPRG0(r1)
+	mfsprg	r4,1
+	stw	r4,SL_SPRG0+4(r1)
+	mfsprg	r4,2
+	stw	r4,SL_SPRG0+8(r1)
+	mfsprg	r4,3
+	stw	r4,SL_SPRG0+12(r1)
+
+	/* Save BATs */
+	mfdbatu	r4,0
+	stw	r4,SL_DBAT0(r1)
+	mfdbatl	r4,0
+	stw	r4,SL_DBAT0+4(r1)
+	mfdbatu	r4,1
+	stw	r4,SL_DBAT1(r1)
+	mfdbatl	r4,1
+	stw	r4,SL_DBAT1+4(r1)
+	mfdbatu	r4,2
+	stw	r4,SL_DBAT2(r1)
+	mfdbatl	r4,2
+	stw	r4,SL_DBAT2+4(r1)
+	mfdbatu	r4,3
+	stw	r4,SL_DBAT3(r1)
+	mfdbatl	r4,3
+	stw	r4,SL_DBAT3+4(r1)
+	mfibatu	r4,0
+	stw	r4,SL_IBAT0(r1)
+	mfibatl	r4,0
+	stw	r4,SL_IBAT0+4(r1)
+	mfibatu	r4,1
+	stw	r4,SL_IBAT1(r1)
+	mfibatl	r4,1
+	stw	r4,SL_IBAT1+4(r1)
+	mfibatu	r4,2
+	stw	r4,SL_IBAT2(r1)
+	mfibatl	r4,2
+	stw	r4,SL_IBAT2+4(r1)
+	mfibatu	r4,3
+	stw	r4,SL_IBAT3(r1)
+	mfibatl	r4,3
+	stw	r4,SL_IBAT3+4(r1)
+
+	/* Save HID0 */
+	mfspr	r4,HID0
+	stw	r4,SL_HID0(r1)
+
+	/* Save 7400/7410/7450 specific registers */
+	mfspr	r3,PVR
+	srwi	r3,r3,16
+	cmpli	cr0,r3,0x8000	/* 7450 */
+	cmpli	cr1,r3,0x000c	/* 7400 */
+	cmpli	cr2,r3,0x800c	/* 7410 */
+	cmpli	cr3,r3,0x8001	/* 7455 */
+	cmpli	cr4,r3,0x7000	/* 750FX */
+	cror	4*cr1+eq,4*cr1+eq,4*cr2+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr3+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
+	bne	1f
+	mfspr	r4,SPRN_MSSCR0
+	stw	r4,SL_MSSCR0(r1)
+	mfspr	r4,SPRN_MSSSR0
+	stw	r4,SL_MSSSR0(r1)
+	/* Save 7450/7455 specific registers */
+	beq	cr1,1f
+	mfspr	r4,HID1
+	stw	r4,SL_HID1(r1)
+	mfspr	r4,SPRN_ICTRL
+	stw	r4,SL_ICTRL(r1)
+	mfspr	r4,SPRN_LDSTCR
+	stw	r4,SL_LDSTCR(r1)
+	mfspr	r4,SPRN_LDSTDB
+	stw	r4,SL_LDSTDB(r1)
+1:	
+	/* Save 750FX specific registers */
+	bne	cr4,1f
+	mfspr	r4,HID1
+	stw	r4,SL_HID1(r1)
+	
+1:
+	/* The ROM can wake us up via 2 different vectors:
+	 *  - On wallstreet & lombard, we must write a magic
+	 *    value 'Lars' at address 4 and a pointer to a
+	 *    memory location containing the PC to resume from
+	 *    at address 0.
+	 *  - On Core99, we must store the wakeup vector at
+	 *    address 0x80 and eventually it's parameters
+	 *    at address 0x84. I've have some trouble with those
+	 *    parameters however and I no longer use them.
+	 */
+	lis	r5,grackle_wake_up@ha
+	addi	r5,r5,grackle_wake_up@l
+	tophys(r5,r5)
+	stw	r5,SL_PC(r1)
+	lis	r4,KERNELBASE@h
+	tophys(r5,r1)
+	addi	r5,r5,SL_PC
+	lis	r6,MAGIC@ha
+	addi	r6,r6,MAGIC@l
+	stw	r5,0(r4)
+	stw	r6,4(r4)
+	/* Setup stuffs at 0x80-0x84 for Core99 */
+	lis	r3,core99_wake_up@ha
+	addi	r3,r3,core99_wake_up@l
+	tophys(r3,r3)
+	stw	r3,0x80(r4)
+	stw	r5,0x84(r4)
+	/* Store a pointer to our backup storage into
+	 * a kernel global
+	 */
+	lis r3,sleep_storage@ha
+	addi r3,r3,sleep_storage@l
+	stw r5,0(r3)
+
+BEGIN_FTR_SECTION
+	DSSALL
+	sync
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+
+/*
+ * Flush the L1 data cache by reading the first 128kB of RAM
+ * and then flushing the same area with the dcbf instruction.
+ * The L2 cache has already been disabled.
+ */
+	li	r4,0x1000	/* 128kB / 32B */
+	mtctr	r4
+	lis	r4,KERNELBASE@h
+1:
+	lwz	r0,0(r4)
+	addi	r4,r4,0x0020	/* Go to start of next cache line */
+	bdnz	1b
+	sync
+	
+	li	r4,0x1000	/* 128kB / 32B */
+	mtctr	r4
+	lis	r4,KERNELBASE@h
+1:
+	dcbf	r0,r4
+	addi	r4,r4,0x0020	/* Go to start of next cache line */
+	bdnz	1b
+	sync
+
+/*
+ * Set the HID0 and MSR for sleep.
+ */
+	mfspr	r2,HID0
+	rlwinm	r2,r2,0,10,7	/* clear doze, nap */
+	oris	r2,r2,HID0_SLEEP@h
+	sync
+	mtspr	HID0,r2
+	sync
+
+/* This loop puts us back to sleep in case we have a spurrious
+ * wakeup so that the host bridge properly stays asleep. The
+ * CPU will be turned off, either after a known time (about 1
+ * second) on wallstreet & lombard, or as soon as the CPU enters
+ * SLEEP mode on core99
+ */
+	mfmsr	r2
+	oris	r2,r2,MSR_POW@h
+1:	sync
+	mtmsr	r2
+	isync
+	b	1b
+
+/* 
+ * Here is the resume code.
+ */
+
+
+/*
+ * Core99 machines resume here
+ * r4 has the physical address of SL_PC(sp) (unused)
+ */
+_GLOBAL(core99_wake_up)
+	/* Make sure HID0 no longer contains any sleep bit */
+	mfspr	r3,HID0
+	rlwinm	r3,r3,0,11,7		/* clear SLEEP, NAP, DOZE bits */
+	mtspr	HID0,r3
+	sync
+	isync
+
+	/* Won't that cause problems on CPU that doesn't support it ? */
+	lis	r3, 0
+	mtspr	SPRN_MMCR0, r3
+	
+	/* sanitize MSR */
+	mfmsr	r3
+	ori	r3,r3,MSR_EE|MSR_IP
+	xori	r3,r3,MSR_EE|MSR_IP
+	sync
+	isync
+	mtmsr	r3
+	sync
+	isync
+
+	/* Recover sleep storage */
+	lis	r3,sleep_storage@ha
+	addi	r3,r3,sleep_storage@l
+	tophys(r3,r3)
+	lwz	r1,0(r3)
+
+	/* Pass thru to older resume code ... */
+/* 
+ * Here is the resume code for older machines.
+ * r1 has the physical address of SL_PC(sp).
+ */
+	
+grackle_wake_up:
+	/* Enable and then Flash inval the instruction & data cache */
+	mfspr	r3,HID0
+	ori	r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI
+	sync
+	isync
+	mtspr	HID0,r3
+	xori	r3,r3, HID0_ICFI|HID0_DCI
+	mtspr	HID0,r3
+	sync
+	
+	/* Restore the kernel's segment registers before
+	 * we do any r1 memory access as we are not sure they
+	 * are in a sane state above the first 256Mb region
+	 */
+	li	r0,16		/* load up segment register values */
+	mtctr	r0		/* for context 0 */
+	lis	r3,0x2000	/* Ku = 1, VSID = 0 */
+	li	r4,0
+3:	mtsrin	r3,r4
+	addi	r3,r3,0x111	/* increment VSID */
+	addis	r4,r4,0x1000	/* address of next segment */
+	bdnz	3b
+	
+	/* Restore the remaining bits of the HID0 register. */
+	subi	r1,r1,SL_PC
+	lwz	r3,SL_HID0(r1)
+	sync
+	isync
+	mtspr	HID0,r3
+	sync
+	isync
+
+	/* Restore 7400/7410/7450 specific registers */
+	mfspr	r3,PVR
+	srwi	r3,r3,16
+	cmpli	cr0,r3,0x8000	/* 7450 */
+	cmpli	cr1,r3,0x000c	/* 7400 */
+	cmpli	cr2,r3,0x800c	/* 7410 */
+	cmpli	cr3,r3,0x8001	/* 7455 */
+	cmpli	cr4,r3,0x7000	/* 750FX */
+	cror	4*cr1+eq,4*cr1+eq,4*cr2+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr3+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
+	bne	1f
+	lwz	r4,SL_MSSCR0(r1)
+	sync
+	mtspr	SPRN_MSSCR0,r4
+	sync
+	isync
+	lwz	r4,SL_MSSSR0(r1)
+	sync
+	mtspr	SPRN_MSSSR0,r4
+	sync
+	isync
+	bne	cr2,1f
+	li	r4,0
+	mtspr	SPRN_L2CR2,r4
+	/* Restore 7450/7455 specific registers */
+	beq	cr1,1f
+	lwz	r4,SL_HID1(r1)
+	sync
+	mtspr	HID1,r4
+	isync
+	sync
+	lwz	r4,SPRN_ICTRL(r1)
+	sync
+	mtspr	SPRN_ICTRL,r4
+	isync
+	sync
+	lwz	r4,SPRN_LDSTCR(r1)
+	sync
+	mtspr	SPRN_LDSTCR,r4
+	isync
+	sync
+	lwz	r4,SL_LDSTDB(r1)
+	sync
+	mtspr	SPRN_LDSTDB,r4
+	isync
+	sync
+1:	
+	/* Restore 750FX specific registers */
+	bne	cr4,1f
+		/* Read PLL config & switch to PLL 0 */
+	lwz	r4,SL_HID1(r1)
+	rlwinm  r5,r4,0,16,14
+	mtspr	SPRN_HID1,r5
+		/* Wait for PLL to stabilize */
+	mftbl	r5
+2:	mftbl	r6
+	sub	r6,r6,r5
+	cmpli	cr0,r6,10000
+	ble	2b
+		/* Setup final PLL */
+	mtspr	SPRN_HID1,r4
+1:
+	/* Restore the BATs, and SDR1.  Then we can turn on the MMU. */
+	lwz	r4,SL_SDR1(r1)
+	mtsdr1	r4
+	lwz	r4,SL_SPRG0(r1)
+	mtsprg	0,r4
+	lwz	r4,SL_SPRG0+4(r1)
+	mtsprg	1,r4
+	lwz	r4,SL_SPRG0+8(r1)
+	mtsprg	2,r4
+	lwz	r4,SL_SPRG0+12(r1)
+	mtsprg	3,r4
+
+	lwz	r4,SL_DBAT0(r1)
+	mtdbatu	0,r4
+	lwz	r4,SL_DBAT0+4(r1)
+	mtdbatl	0,r4
+	lwz	r4,SL_DBAT1(r1)
+	mtdbatu	1,r4
+	lwz	r4,SL_DBAT1+4(r1)
+	mtdbatl	1,r4
+	lwz	r4,SL_DBAT2(r1)
+	mtdbatu	2,r4
+	lwz	r4,SL_DBAT2+4(r1)
+	mtdbatl	2,r4
+	lwz	r4,SL_DBAT3(r1)
+	mtdbatu	3,r4
+	lwz	r4,SL_DBAT3+4(r1)
+	mtdbatl	3,r4
+	lwz	r4,SL_IBAT0(r1)
+	mtibatu	0,r4
+	lwz	r4,SL_IBAT0+4(r1)
+	mtibatl	0,r4
+	lwz	r4,SL_IBAT1(r1)
+	mtibatu	1,r4
+	lwz	r4,SL_IBAT1+4(r1)
+	mtibatl	1,r4
+	lwz	r4,SL_IBAT2(r1)
+	mtibatu	2,r4
+	lwz	r4,SL_IBAT2+4(r1)
+	mtibatl	2,r4
+	lwz	r4,SL_IBAT3(r1)
+	mtibatu	3,r4
+	lwz	r4,SL_IBAT3+4(r1)
+	mtibatl	3,r4
+
+	/* Flush all TLBs */
+	lis	r4,0x1000
+1:	addic.	r4,r4,-0x1000
+	tlbie	r4
+	blt	1b
+	sync
+
+	/* restore the MSR and turn on the MMU */
+	lwz	r3,SL_MSR(r1)
+	bl	turn_on_mmu	
+
+	/* get back the stack pointer */
+	tovirt(r1,r1)
+
+	/* Restore TB */
+	li	r3,0
+	mttbl	r3
+	lwz	r3,SL_TB(r1)
+	lwz	r4,SL_TB+4(r1)
+	mttbu	r3
+	mttbl	r4
+
+	/* Restore the callee-saved registers and return */
+	lwz	r0,SL_CR(r1)
+	mtcr	r0
+	lwz	r2,SL_R2(r1)
+	lmw	r12,SL_R12(r1)
+	addi	r1,r1,SL_SIZE
+	lwz	r0,4(r1)
+	mtlr	r0
+	blr
+
+turn_on_mmu:
+	mflr	r4
+	tovirt(r4,r4)
+	mtsrr0	r4
+	mtsrr1	r3
+	sync
+	isync
+	rfi
+
+#endif /* defined(CONFIG_PMAC_PBOOK) */
+
+	.data
+	.globl sleep_storage
+sleep_storage:
+	.long 0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/pmac_smp.c linux-2.4.20/arch/ppc/platforms/pmac_smp.c
--- linux-2.4.19/arch/ppc/platforms/pmac_smp.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/pmac_smp.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,623 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * SMP support for power macintosh.
+ *
+ * We support both the old "powersurge" SMP architecture
+ * and the current Core99 (G4 PowerMac) machines.
+ *
+ * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net)
+ * and Ben Herrenschmidt <benh@kernel.crashing.org>.
+ *
+ * Support for DayStar quad CPU cards
+ * Copyright (C) XLR8, Inc. 1994-2000
+ *
+ *  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.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/stringify.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/residual.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/time.h>
+#include <asm/open_pic.h>
+#include <asm/processor.h>
+
+/*
+ * Powersurge (old powermac SMP) support.
+ */
+
+extern void __secondary_start_psurge(void);
+extern void __secondary_start_psurge2(void);	/* Temporary horrible hack */
+extern void __secondary_start_psurge3(void);	/* Temporary horrible hack */
+
+/* Addresses for powersurge registers */
+#define HAMMERHEAD_BASE		0xf8000000
+#define HHEAD_CONFIG		0x90
+#define HHEAD_SEC_INTR		0xc0
+
+/* register for interrupting the primary processor on the powersurge */
+/* N.B. this is actually the ethernet ROM! */
+#define PSURGE_PRI_INTR		0xf3019000
+
+/* register for storing the start address for the secondary processor */
+/* N.B. this is the PCI config space address register for the 1st bridge */
+#define PSURGE_START		0xf2800000
+
+/* Daystar/XLR8 4-CPU card */
+#define PSURGE_QUAD_REG_ADDR	0xf8800000
+
+#define PSURGE_QUAD_IRQ_SET	0
+#define PSURGE_QUAD_IRQ_CLR	1
+#define PSURGE_QUAD_IRQ_PRIMARY	2
+#define PSURGE_QUAD_CKSTOP_CTL	3
+#define PSURGE_QUAD_PRIMARY_ARB	4
+#define PSURGE_QUAD_BOARD_ID	6
+#define PSURGE_QUAD_WHICH_CPU	7
+#define PSURGE_QUAD_CKSTOP_RDBK	8
+#define PSURGE_QUAD_RESET_CTL	11
+
+#define PSURGE_QUAD_OUT(r, v)	(out_8(quad_base + ((r) << 4) + 4, (v)))
+#define PSURGE_QUAD_IN(r)	(in_8(quad_base + ((r) << 4) + 4) & 0x0f)
+#define PSURGE_QUAD_BIS(r, v)	(PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v)))
+#define PSURGE_QUAD_BIC(r, v)	(PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v)))
+
+/* virtual addresses for the above */
+static volatile u8 *hhead_base;
+static volatile u8 *quad_base;
+static volatile u32 *psurge_pri_intr;
+static volatile u8 *psurge_sec_intr;
+static volatile u32 *psurge_start;
+
+/* what sort of powersurge board we have */
+static int psurge_type;
+
+/* values for psurge_type */
+#define PSURGE_DUAL		0
+#define PSURGE_QUAD_OKEE	1
+#define PSURGE_QUAD_COTTON	2
+#define PSURGE_QUAD_ICEGRASS	3
+
+volatile static long int core99_l2_cache;
+volatile static long int core99_l3_cache;
+
+static void __init
+core99_init_caches(void)
+{
+	int cpu = smp_processor_id();
+
+	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
+		return;
+
+	if (cpu == 0){
+		core99_l2_cache = _get_L2CR();
+		printk("CPU0: L2CR is %lx\n", core99_l2_cache);
+	} else {
+		printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());
+		_set_L2CR(0);
+		_set_L2CR(core99_l2_cache);
+		printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);
+	}
+
+	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR))
+		return;
+
+	if (cpu == 0){
+		core99_l3_cache = _get_L3CR();
+		printk("CPU0: L3CR is %lx\n", core99_l3_cache);
+	} else {
+		printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR());
+		_set_L3CR(0);
+		_set_L3CR(core99_l3_cache);
+		printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache);
+	}
+}
+
+/* Some CPU registers have to be saved from the first CPU and
+ * applied to others. Note that we override what is setup by
+ * the cputable intentionally.
+ */
+
+#define	reg_hid0	0
+#define	reg_hid1	1
+#define	reg_msscr0	2
+#define	reg_msssr0	3
+#define	reg_ictrl	4
+#define	reg_ldstcr	5
+#define	reg_ldstdb	6
+#define	reg_count	7
+
+#define stringify __stringify
+
+static unsigned long cpu_regs[reg_count];
+
+static void __pmac
+cpu_setup_grab(void)
+{
+	unsigned int pvers = mfspr(SPRN_PVR)>>16;
+
+	/* Read cache setting of CPU 0 */
+	core99_init_caches();
+
+	/* 7400/7410/7450 */
+	if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) {
+		cpu_regs[reg_hid0] = mfspr(SPRN_HID0);
+		cpu_regs[reg_msscr0] = mfspr(SPRN_MSSCR0);
+		cpu_regs[reg_msssr0] = mfspr(SPRN_MSSSR0);
+	}
+	/* 7450 only */
+	if (pvers == 0x8000) {
+		cpu_regs[reg_hid1] = mfspr(SPRN_HID1);
+		cpu_regs[reg_ictrl] = mfspr(SPRN_ICTRL);
+		cpu_regs[reg_ldstcr] = mfspr(SPRN_LDSTCR);
+		cpu_regs[reg_ldstdb] = mfspr(SPRN_LDSTDB);
+	}
+	flush_dcache_range((unsigned long)cpu_regs, (unsigned long)&cpu_regs[reg_count]);
+}
+
+static void __pmac
+cpu_setup_apply(int cpu_nr)
+{
+	unsigned int pvers = mfspr(SPRN_PVR)>>16;
+
+	/* Apply cache setting from CPU 0 */
+	core99_init_caches();
+
+	/* 7400/7410/7450 */
+	if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) {
+		unsigned long tmp;
+		__asm__ __volatile__ (
+			"lwz	%0,4*"stringify(reg_hid0)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_HID0)", %0\n"
+			"isync;sync\n"
+			"lwz	%0, 4*"stringify(reg_msscr0)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_MSSCR0)", %0\n"
+			"isync;sync\n"
+//			"lwz	%0, "stringify(reg_msssr0)"(%1)\n"
+//			"sync\n"
+//			"mtspr	"stringify(SPRN_MSSSR0)", %0\n"
+//			"isync;sync\n"
+		: "=&r" (tmp) : "r" (cpu_regs));			
+	}
+	/* 7410 only */
+	if (pvers == 0x800c) {
+		unsigned long tmp;
+		__asm__ __volatile__ (
+			"li	%0, 0\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_L2CR2)", %0\n"
+			"isync;sync\n"
+		: "=&r" (tmp));		
+	}
+	/* 7450 only */
+	if (pvers == 0x8000) {
+		unsigned long tmp;
+		__asm__ __volatile__ (
+			"lwz	%0, 4*"stringify(reg_hid1)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_HID1)", %0\n"
+			"isync;sync\n"
+			"lwz	%0, 4*"stringify(reg_ictrl)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_ICTRL)", %0\n"
+			"isync;sync\n"
+			"lwz	%0, 4*"stringify(reg_ldstcr)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_LDSTCR)", %0\n"
+			"isync;sync\n"
+			"lwz	%0, 4*"stringify(reg_ldstdb)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_LDSTDB)", %0\n"
+			"isync;sync\n"
+		: "=&r" (tmp) : "r" (cpu_regs));		
+	}
+}
+
+/*
+ * Set and clear IPIs for powersurge.
+ */
+static inline void psurge_set_ipi(int cpu)
+{
+	if (cpu == 0)
+		in_be32(psurge_pri_intr);
+	else if (psurge_type == PSURGE_DUAL)
+		out_8(psurge_sec_intr, 0);
+	else
+		PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_SET, 1 << cpu);
+}
+
+static inline void psurge_clr_ipi(int cpu)
+{
+	if (cpu > 0) {
+		if (psurge_type == PSURGE_DUAL)
+			out_8(psurge_sec_intr, ~0);
+		else
+			PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu);
+	}
+}
+
+/*
+ * On powersurge (old SMP powermac architecture) we don't have
+ * separate IPIs for separate messages like openpic does.  Instead
+ * we have a bitmap for each processor, where a 1 bit means that
+ * the corresponding message is pending for that processor.
+ * Ideally each cpu's entry would be in a different cache line.
+ *  -- paulus.
+ */
+static unsigned long psurge_smp_message[NR_CPUS];
+
+void __pmac
+psurge_smp_message_recv(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+	int msg;
+
+	/* clear interrupt */
+	psurge_clr_ipi(cpu);
+
+	if (smp_num_cpus < 2)
+		return;
+
+	/* make sure there is a message there */
+	for (msg = 0; msg < 4; msg++)
+		if (test_and_clear_bit(msg, &psurge_smp_message[cpu]))
+			smp_message_recv(msg, regs);
+}
+
+void __pmac
+psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
+{
+	psurge_smp_message_recv(regs);
+}
+
+static void __pmac
+smp_psurge_message_pass(int target, int msg, unsigned long data, int wait)
+{
+	int i;
+
+	if (smp_num_cpus < 2)
+		return;
+
+	for (i = 0; i < smp_num_cpus; i++) {
+		if (target == MSG_ALL
+		    || (target == MSG_ALL_BUT_SELF && i != smp_processor_id())
+		    || target == i) {
+			set_bit(msg, &psurge_smp_message[i]);
+			psurge_set_ipi(i);
+		}
+	}
+}
+
+/*
+ * Determine a quad card presence. We read the board ID register, we
+ * force the data bus to change to something else, and we read it again.
+ * It it's stable, then the register probably exist (ugh !)
+ */
+static int __init psurge_quad_probe(void)
+{
+	int type;
+	unsigned int i;
+
+	type = PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID);
+	if (type < PSURGE_QUAD_OKEE || type > PSURGE_QUAD_ICEGRASS
+	    || type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
+		return PSURGE_DUAL;
+
+	/* looks OK, try a slightly more rigorous test */
+	/* bogus is not necessarily cacheline-aligned,
+	   though I don't suppose that really matters.  -- paulus */
+	for (i = 0; i < 100; i++) {
+		volatile u32 bogus[8];
+		bogus[(0+i)%8] = 0x00000000;
+		bogus[(1+i)%8] = 0x55555555;
+		bogus[(2+i)%8] = 0xFFFFFFFF;
+		bogus[(3+i)%8] = 0xAAAAAAAA;
+		bogus[(4+i)%8] = 0x33333333;
+		bogus[(5+i)%8] = 0xCCCCCCCC;
+		bogus[(6+i)%8] = 0xCCCCCCCC;
+		bogus[(7+i)%8] = 0x33333333;
+		wmb();
+		asm volatile("dcbf 0,%0" : : "r" (bogus) : "memory");
+		mb();
+		if (type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
+			return PSURGE_DUAL;
+	}
+	return type;
+}
+
+static void __init psurge_quad_init(void)
+{
+	int procbits;
+
+	if (ppc_md.progress) ppc_md.progress("psurge_quad_init", 0x351);
+	procbits = ~PSURGE_QUAD_IN(PSURGE_QUAD_WHICH_CPU);
+	if (psurge_type == PSURGE_QUAD_ICEGRASS)
+		PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
+	else
+		PSURGE_QUAD_BIC(PSURGE_QUAD_CKSTOP_CTL, procbits);
+	mdelay(33);
+	out_8(psurge_sec_intr, ~0);
+	PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, procbits);
+	PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
+	if (psurge_type != PSURGE_QUAD_ICEGRASS)
+		PSURGE_QUAD_BIS(PSURGE_QUAD_CKSTOP_CTL, procbits);
+	PSURGE_QUAD_BIC(PSURGE_QUAD_PRIMARY_ARB, procbits);
+	mdelay(33);
+	PSURGE_QUAD_BIC(PSURGE_QUAD_RESET_CTL, procbits);
+	mdelay(33);
+	PSURGE_QUAD_BIS(PSURGE_QUAD_PRIMARY_ARB, procbits);
+	mdelay(33);
+}
+
+static int __init smp_psurge_probe(void)
+{
+	int i, ncpus;
+
+	/* We don't do SMP on the PPC601 -- paulus */
+	if (PVR_VER(mfspr(PVR)) == 1)
+		return 1;
+
+	/*
+	 * The powersurge cpu board can be used in the generation
+	 * of powermacs that have a socket for an upgradeable cpu card,
+	 * including the 7500, 8500, 9500, 9600.
+	 * The device tree doesn't tell you if you have 2 cpus because
+	 * OF doesn't know anything about the 2nd processor.
+	 * Instead we look for magic bits in magic registers,
+	 * in the hammerhead memory controller in the case of the
+	 * dual-cpu powersurge board.  -- paulus.
+	 */
+	if (find_devices("hammerhead") == NULL)
+		return 1;
+
+	hhead_base = ioremap(HAMMERHEAD_BASE, 0x800);
+	quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024);
+	psurge_sec_intr = hhead_base + HHEAD_SEC_INTR;
+
+	psurge_type = psurge_quad_probe();
+	if (psurge_type != PSURGE_DUAL) {
+		psurge_quad_init();
+		/* All released cards using this HW design have 4 CPUs */
+		ncpus = 4;
+	} else {
+		iounmap((void *) quad_base);
+		if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {
+			/* not a dual-cpu card */
+			iounmap((void *) hhead_base);
+			return 1;
+		}
+		ncpus = 2;
+	}
+
+	psurge_start = ioremap(PSURGE_START, 4);
+	psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);
+
+	/* this is not actually strictly necessary -- paulus. */
+	for (i = 1; i < ncpus; ++i)
+		smp_hw_index[i] = i;
+
+	if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);
+
+	return ncpus;
+}
+
+static void __init smp_psurge_kick_cpu(int nr)
+{
+	void (*start)(void) = __secondary_start_psurge;
+	unsigned long a;
+
+	/* may need to flush here if secondary bats aren't setup */
+	for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
+		asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
+	asm volatile("sync");
+
+	if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353);
+
+	/* setup entry point of secondary processor */
+	switch (nr) {
+	case 2:
+		start = __secondary_start_psurge2;
+		break;
+	case 3:
+		start = __secondary_start_psurge3;
+		break;
+	}
+
+	out_be32(psurge_start, __pa(start));
+	mb();
+
+	psurge_set_ipi(nr);
+	udelay(10);
+	psurge_clr_ipi(nr);
+
+	if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
+}
+
+/*
+ * With the dual-cpu powersurge board, the decrementers and timebases
+ * of both cpus are frozen after the secondary cpu is started up,
+ * until we give the secondary cpu another interrupt.  This routine
+ * uses this to get the timebases synchronized.
+ *  -- paulus.
+ */
+static void __init psurge_dual_sync_tb(int cpu_nr)
+{
+	static volatile int sec_tb_reset = 0;
+	int t;
+
+	set_dec(tb_ticks_per_jiffy);
+	set_tb(0, 0);
+	last_jiffy_stamp(cpu_nr) = 0;
+
+	if (cpu_nr > 0) {
+		mb();
+		sec_tb_reset = 1;
+		return;
+	}
+
+	/* wait for the secondary to have reset its TB before proceeding */
+	for (t = 10000000; t > 0 && !sec_tb_reset; --t)
+		;
+
+	/* now interrupt the secondary, starting both TBs */
+	psurge_set_ipi(1);
+
+	smp_tb_synchronized = 1;
+}
+
+static void __init
+smp_psurge_setup_cpu(int cpu_nr)
+{
+
+	if (cpu_nr == 0) {
+		if (smp_num_cpus < 2)
+			return;
+		/* reset the entry point so if we get another intr we won't
+		 * try to startup again */
+		out_be32(psurge_start, 0x100);
+		if (request_irq(30, psurge_primary_intr, 0, "primary IPI", 0))
+			printk(KERN_ERR "Couldn't get primary IPI interrupt");
+	}
+
+	if (psurge_type == PSURGE_DUAL)
+		psurge_dual_sync_tb(cpu_nr);
+}
+
+static int __init
+smp_core99_probe(void)
+{
+	struct device_node *cpus;
+	int i, ncpus = 1;
+	extern int powersave_nap;
+
+	if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
+	cpus = find_type_devices("cpu");
+	if (cpus)
+		while ((cpus = cpus->next) != NULL)
+			++ncpus;
+	printk("smp_core99_probe: found %d cpus\n", ncpus);
+	if (ncpus > 1) {
+		openpic_request_IPIs();
+		for (i = 1; i < ncpus; ++i)
+			smp_hw_index[i] = i;
+		powersave_nap = 0;
+		cpu_setup_grab();
+	}
+
+	return ncpus;
+}
+
+static void __init
+smp_core99_kick_cpu(int nr)
+{
+	unsigned long save_vector, new_vector;
+	unsigned long flags;
+
+	volatile unsigned long *vector
+		 = ((volatile unsigned long *)(KERNELBASE+0x100));
+	if (nr < 1 || nr > 3)
+		return;
+	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
+
+	local_irq_save(flags);
+	local_irq_disable();
+	
+	/* Save reset vector */
+	save_vector = *vector;
+	
+	/* Setup fake reset vector that does	  
+	 *   b __secondary_start_psurge - KERNELBASE
+	 */  
+	switch(nr) {
+		case 1:
+			new_vector = (unsigned long)__secondary_start_psurge;
+			break;
+		case 2:
+			new_vector = (unsigned long)__secondary_start_psurge2;
+			break;
+		case 3:
+			new_vector = (unsigned long)__secondary_start_psurge3;
+			break;
+	}
+	*vector = 0x48000002 + new_vector - KERNELBASE;
+	
+	/* flush data cache and inval instruction cache */
+	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+	
+	/* Put some life in our friend */
+	pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
+	
+	/* FIXME: We wait a bit for the CPU to take the exception, I should
+	 * instead wait for the entry code to set something for me. Well,
+	 * ideally, all that crap will be done in prom.c and the CPU left
+	 * in a RAM-based wait loop like CHRP.
+	 */
+	mdelay(1);
+	
+	/* Restore our exception vector */
+	*vector = save_vector;
+	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+	
+	local_irq_restore(flags);
+	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
+}
+
+static void __init
+smp_core99_setup_cpu(int cpu_nr)
+{
+	/* Setup some registers */
+	if (cpu_nr != 0)
+		cpu_setup_apply(cpu_nr);
+	
+	/* Setup openpic */
+	do_openpic_setup_cpu();
+
+	/* Setup L2/L3 */
+	if (cpu_nr == 0)
+		if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
+}
+
+/* PowerSurge-style Macs */
+struct smp_ops_t psurge_smp_ops __pmacdata = {
+	smp_psurge_message_pass,
+	smp_psurge_probe,
+	smp_psurge_kick_cpu,
+	smp_psurge_setup_cpu,
+};
+
+/* Core99 Macs (dual G4s) */
+struct smp_ops_t core99_smp_ops __pmacdata = {
+	smp_openpic_message_pass,
+	smp_core99_probe,
+	smp_core99_kick_cpu,
+	smp_core99_setup_cpu,
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/pmac_time.c linux-2.4.20/arch/ppc/platforms/pmac_time.c
--- linux-2.4.19/arch/ppc/platforms/pmac_time.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/pmac_time.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,284 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * Support for periodic interrupts (100 per second) and for getting
+ * the current time from the RTC on Power Macintoshes.
+ *
+ * We use the decrementer register for our periodic interrupts.
+ *
+ * Paul Mackerras	August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/hardirq.h>
+#include <asm/time.h>
+#include <asm/nvram.h>
+
+extern rwlock_t xtime_lock;
+
+/* Apparently the RTC stores seconds since 1 Jan 1904 */
+#define RTC_OFFSET	2082844800
+
+/*
+ * Calibrate the decrementer frequency with the VIA timer 1.
+ */
+#define VIA_TIMER_FREQ_6	4700000	/* time 1 frequency * 6 */
+
+/* VIA registers */
+#define RS		0x200		/* skip between registers */
+#define T1CL		(4*RS)		/* Timer 1 ctr/latch (low 8 bits) */
+#define T1CH		(5*RS)		/* Timer 1 counter (high 8 bits) */
+#define T1LL		(6*RS)		/* Timer 1 latch (low 8 bits) */
+#define T1LH		(7*RS)		/* Timer 1 latch (high 8 bits) */
+#define ACR		(11*RS)		/* Auxiliary control register */
+#define IFR		(13*RS)		/* Interrupt flag register */
+
+/* Bits in ACR */
+#define T1MODE		0xc0		/* Timer 1 mode */
+#define T1MODE_CONT	0x40		/*  continuous interrupts */
+
+/* Bits in IFR and IER */
+#define T1_INT		0x40		/* Timer 1 interrupt */
+
+extern struct timezone sys_tz;
+
+long __init
+pmac_time_init(void)
+{
+#ifdef CONFIG_NVRAM
+	s32 delta = 0;
+	int dst;
+	
+	delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
+	delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8;
+	delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb);
+	if (delta & 0x00800000UL)
+		delta |= 0xFF000000UL;
+	dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
+	printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
+		dst ? "on" : "off");
+	return delta;
+#else
+	return 0;
+#endif
+}
+
+unsigned long __pmac
+pmac_get_rtc_time(void)
+{
+#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
+	struct adb_request req;
+	unsigned long now;
+#endif
+
+	/* Get the time from the RTC */
+	switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+	case SYS_CTRLER_CUDA:
+		if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
+			return 0;
+		while (!req.complete)
+			cuda_poll();
+		if (req.reply_len != 7)
+			printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+			       req.reply_len);
+		now = (req.reply[3] << 24) + (req.reply[4] << 16)
+			+ (req.reply[5] << 8) + req.reply[6];
+		return now - RTC_OFFSET;
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU
+	case SYS_CTRLER_PMU:
+		if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
+			return 0;
+		while (!req.complete)
+			pmu_poll();
+		if (req.reply_len != 4)
+			printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+			       req.reply_len);
+		now = (req.reply[0] << 24) + (req.reply[1] << 16)
+			+ (req.reply[2] << 8) + req.reply[3];
+		return now - RTC_OFFSET;
+#endif /* CONFIG_ADB_PMU */
+	default: ;
+	}
+	return 0;
+}
+
+int __pmac
+pmac_set_rtc_time(unsigned long nowtime)
+{
+#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
+	struct adb_request req;
+#endif
+
+	nowtime += RTC_OFFSET;
+
+	switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+	case SYS_CTRLER_CUDA:
+		if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
+				 nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
+			return 0;
+		while (!req.complete)
+			cuda_poll();
+		if ((req.reply_len != 3) && (req.reply_len != 7))
+			printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
+			       req.reply_len);
+		return 1;
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU
+	case SYS_CTRLER_PMU:
+		if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
+				nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
+			return 0;
+		while (!req.complete)
+			pmu_poll();
+		if (req.reply_len != 0)
+			printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
+			       req.reply_len);
+		return 1;
+#endif /* CONFIG_ADB_PMU */
+	default:
+		return 0;
+	}
+}
+
+/*
+ * Calibrate the decrementer register using VIA timer 1.
+ * This is used both on powermacs and CHRP machines.
+ */
+int __init
+via_calibrate_decr(void)
+{
+	struct device_node *vias;
+	volatile unsigned char *via;
+	int count = VIA_TIMER_FREQ_6 / HZ;
+	unsigned int dstart, dend;
+
+	vias = find_devices("via-cuda");
+	if (vias == 0)
+		vias = find_devices("via-pmu");
+	if (vias == 0)
+		vias = find_devices("via");
+	if (vias == 0 || vias->n_addrs == 0)
+		return 0;
+	via = (volatile unsigned char *)
+		ioremap(vias->addrs[0].address, vias->addrs[0].size);
+
+	/* set timer 1 for continuous interrupts */
+	out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
+	/* set the counter to a small value */
+	out_8(&via[T1CH], 2);
+	/* set the latch to `count' */
+	out_8(&via[T1LL], count);
+	out_8(&via[T1LH], count >> 8);
+	/* wait until it hits 0 */
+	while ((in_8(&via[IFR]) & T1_INT) == 0)
+		;
+	dstart = get_dec();
+	/* clear the interrupt & wait until it hits 0 again */
+	in_8(&via[T1CL]);
+	while ((in_8(&via[IFR]) & T1_INT) == 0)
+		;
+	dend = get_dec();
+
+	tb_ticks_per_jiffy = (dstart - dend) / 6;
+	tb_to_us = mulhwu_scale_factor(dstart - dend, 60000);
+
+	printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n",
+	       tb_ticks_per_jiffy, dstart - dend);
+
+	iounmap(via);
+	
+	return 1;
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Reset the time after a sleep.
+ */
+static int __pmac
+time_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+	static unsigned long time_diff;
+	unsigned long flags;
+
+	switch (when) {
+	case PBOOK_SLEEP_NOW:
+		read_lock_irqsave(&xtime_lock, flags);
+		time_diff = xtime.tv_sec - pmac_get_rtc_time();
+		read_unlock_irqrestore(&xtime_lock, flags);
+		break;
+	case PBOOK_WAKE:
+		write_lock_irqsave(&xtime_lock, flags);
+		xtime.tv_sec = pmac_get_rtc_time() + time_diff;
+		xtime.tv_usec = 0;
+		last_rtc_update = xtime.tv_sec;
+		write_unlock_irqrestore(&xtime_lock, flags);
+		break;
+	}
+	return PBOOK_SLEEP_OK;
+}
+
+static struct pmu_sleep_notifier time_sleep_notifier __pmacdata = {
+	time_sleep_notify, SLEEP_LEVEL_MISC,
+};
+#endif /* CONFIG_PMAC_PBOOK */
+
+/*
+ * Query the OF and get the decr frequency.
+ * This was taken from the pmac time_init() when merging the prep/pmac
+ * time functions.
+ */
+void __init
+pmac_calibrate_decr(void)
+{
+	struct device_node *cpu;
+	unsigned int freq, *fp;
+
+#ifdef CONFIG_PMAC_PBOOK
+	pmu_register_sleep_notifier(&time_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+
+	/* We assume MacRISC2 machines have correct device-tree
+	 * calibration. That's better since the VIA itself seems
+	 * to be slightly off. --BenH
+	 */
+	if (!machine_is_compatible("MacRISC2"))
+		if (via_calibrate_decr())
+			return;
+
+	/*
+	 * The cpu node should have a timebase-frequency property
+	 * to tell us the rate at which the decrementer counts.
+	 */
+	cpu = find_type_devices("cpu");
+	if (cpu == 0)
+		panic("can't find cpu node in time_init");
+	fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL);
+	if (fp == 0)
+		panic("can't get cpu timebase frequency");
+	freq = *fp;
+	printk("time_init: decrementer frequency = %u.%.6u MHz\n",
+	       freq/1000000, freq%1000000);
+	tb_ticks_per_jiffy = freq / HZ;
+	tb_to_us = mulhwu_scale_factor(freq, 1000000);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/prep_pci.c linux-2.4.20/arch/ppc/platforms/prep_pci.c
--- linux-2.4.19/arch/ppc/platforms/prep_pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/prep_pci.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,1269 @@
+/*
+ * BK Id: SCCS/s.prep_pci.c 1.33 12/20/01 15:36:12 trini
+ */
+/*
+ * PReP pci functions.
+ * Originally by Gary Thomas
+ * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * The motherboard routes/maps will disappear shortly. -- Cort
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/sections.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/ptrace.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/residual.h>
+#include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+#include <asm/open_pic.h>
+
+#define MAX_DEVNR 22
+
+/* Which PCI interrupt line does a given device [slot] use? */
+/* Note: This really should be two dimensional based in slot/pin used */
+static unsigned char *Motherboard_map;
+unsigned char *Motherboard_map_name;
+
+/* How is the 82378 PIRQ mapping setup? */
+static unsigned char *Motherboard_routes;
+
+static void (*Motherboard_non0)(struct pci_dev *);
+
+static void Powerplus_Map_Non0(struct pci_dev *);
+
+/* Used for Motorola to store system config register */
+static unsigned long	*ProcInfo;
+
+/* Tables for known hardware */   
+
+/* Motorola PowerStackII - Utah */
+static char Utah_pci_IRQ_map[23] __prepdata =
+{
+        0,   /* Slot 0  - unused */
+        0,   /* Slot 1  - unused */
+        5,   /* Slot 2  - SCSI - NCR825A  */
+        0,   /* Slot 3  - unused */
+        1,   /* Slot 4  - Ethernet - DEC2114x */
+        0,   /* Slot 5  - unused */
+        3,   /* Slot 6  - PCI Card slot #1 */
+        4,   /* Slot 7  - PCI Card slot #2 */
+        5,   /* Slot 8  - PCI Card slot #3 */
+        5,   /* Slot 9  - PCI Bridge */
+             /* added here in case we ever support PCI bridges */
+             /* Secondary PCI bus cards are at slot-9,6 & slot-9,7 */
+        0,   /* Slot 10 - unused */
+        0,   /* Slot 11 - unused */
+        5,   /* Slot 12 - SCSI - NCR825A */
+        0,   /* Slot 13 - unused */
+        3,   /* Slot 14 - enet */
+        0,   /* Slot 15 - unused */
+        2,   /* Slot 16 - unused */
+        3,   /* Slot 17 - unused */
+        5,   /* Slot 18 - unused */
+        0,   /* Slot 19 - unused */
+        0,   /* Slot 20 - unused */
+        0,   /* Slot 21 - unused */
+        0,   /* Slot 22 - unused */
+};
+
+static char Utah_pci_IRQ_routes[] __prepdata =
+{
+        0,   /* Line 0 - Unused */
+        9,   /* Line 1 */
+	10,  /* Line 2 */
+        11,  /* Line 3 */
+        14,  /* Line 4 */
+        15,  /* Line 5 */
+};
+
+/* Motorola PowerStackII - Omaha */
+/* no integrated SCSI or ethernet */
+static char Omaha_pci_IRQ_map[23] __prepdata =
+{
+        0,   /* Slot 0  - unused */
+        0,   /* Slot 1  - unused */
+        3,   /* Slot 2  - Winbond EIDE */
+        0,   /* Slot 3  - unused */
+        0,   /* Slot 4  - unused */
+        0,   /* Slot 5  - unused */
+        1,   /* Slot 6  - PCI slot 1 */
+        2,   /* Slot 7  - PCI slot 2  */
+        3,   /* Slot 8  - PCI slot 3 */
+        4,   /* Slot 9  - PCI slot 4 */ /* needs indirect access */
+        0,   /* Slot 10 - unused */
+        0,   /* Slot 11 - unused */
+        0,   /* Slot 12 - unused */
+        0,   /* Slot 13 - unused */
+        0,   /* Slot 14 - unused */
+        0,   /* Slot 15 - unused */
+        1,   /* Slot 16  - PCI slot 1 */
+        2,   /* Slot 17  - PCI slot 2  */
+        3,   /* Slot 18  - PCI slot 3 */
+        4,   /* Slot 19  - PCI slot 4 */ /* needs indirect access */
+        0,
+        0,
+        0,
+};
+
+static char Omaha_pci_IRQ_routes[] __prepdata =
+{
+        0,   /* Line 0 - Unused */
+        9,   /* Line 1 */
+        11,  /* Line 2 */
+        14,  /* Line 3 */
+        15   /* Line 4 */
+};
+
+/* Motorola PowerStack */
+static char Blackhawk_pci_IRQ_map[19] __prepdata =
+{
+  	0,	/* Slot 0  - unused */
+  	0,	/* Slot 1  - unused */
+  	0,	/* Slot 2  - unused */
+  	0,	/* Slot 3  - unused */
+  	0,	/* Slot 4  - unused */
+  	0,	/* Slot 5  - unused */
+  	0,	/* Slot 6  - unused */
+  	0,	/* Slot 7  - unused */
+  	0,	/* Slot 8  - unused */
+  	0,	/* Slot 9  - unused */
+  	0,	/* Slot 10 - unused */
+  	0,	/* Slot 11 - unused */
+  	3,	/* Slot 12 - SCSI */
+  	0,	/* Slot 13 - unused */
+  	1,	/* Slot 14 - Ethernet */
+  	0,	/* Slot 15 - unused */
+ 	1,	/* Slot P7 */
+ 	2,	/* Slot P6 */
+ 	3,	/* Slot P5 */
+};
+
+static char Blackhawk_pci_IRQ_routes[] __prepdata =
+{
+   	0,	/* Line 0 - Unused */
+   	9,	/* Line 1 */
+   	11,	/* Line 2 */
+   	15,	/* Line 3 */
+   	15	/* Line 4 */
+};
+   
+/* Motorola Mesquite */
+static char Mesquite_pci_IRQ_map[23] __prepdata =
+{
+	0,	/* Slot 0  - unused */
+	0,	/* Slot 1  - unused */
+	0,	/* Slot 2  - unused */
+	0,	/* Slot 3  - unused */
+	0,	/* Slot 4  - unused */
+	0,	/* Slot 5  - unused */
+	0,	/* Slot 6  - unused */
+	0,	/* Slot 7  - unused */
+	0,	/* Slot 8  - unused */
+	0,	/* Slot 9  - unused */
+	0,	/* Slot 10 - unused */
+	0,	/* Slot 11 - unused */
+	0,	/* Slot 12 - unused */
+	0,	/* Slot 13 - unused */
+	2,	/* Slot 14 - Ethernet */
+	0,	/* Slot 15 - unused */
+	3,	/* Slot 16 - PMC */
+	0,	/* Slot 17 - unused */
+	0,	/* Slot 18 - unused */
+	0,	/* Slot 19 - unused */
+	0,	/* Slot 20 - unused */
+	0,	/* Slot 21 - unused */
+	0,	/* Slot 22 - unused */
+};
+
+/* Motorola Sitka */
+static char Sitka_pci_IRQ_map[21] __prepdata =
+{
+	0,      /* Slot 0  - unused */
+	0,      /* Slot 1  - unused */
+	0,      /* Slot 2  - unused */
+	0,      /* Slot 3  - unused */
+	0,      /* Slot 4  - unused */
+	0,      /* Slot 5  - unused */
+	0,      /* Slot 6  - unused */
+	0,      /* Slot 7  - unused */
+	0,      /* Slot 8  - unused */
+	0,      /* Slot 9  - unused */
+	0,      /* Slot 10 - unused */
+	0,      /* Slot 11 - unused */
+	0,      /* Slot 12 - unused */
+	0,      /* Slot 13 - unused */
+	2,      /* Slot 14 - Ethernet */
+	0,      /* Slot 15 - unused */
+	9,      /* Slot 16 - PMC 1  */
+	12,     /* Slot 17 - PMC 2  */
+	0,      /* Slot 18 - unused */
+	0,      /* Slot 19 - unused */
+	4,      /* Slot 20 - NT P2P bridge */
+};
+
+/* Motorola MTX */
+static char MTX_pci_IRQ_map[23] __prepdata =
+{
+	0,	/* Slot 0  - unused */
+	0,	/* Slot 1  - unused */
+	0,	/* Slot 2  - unused */
+	0,	/* Slot 3  - unused */
+	0,	/* Slot 4  - unused */
+	0,	/* Slot 5  - unused */
+	0,	/* Slot 6  - unused */
+	0,	/* Slot 7  - unused */
+	0,	/* Slot 8  - unused */
+	0,	/* Slot 9  - unused */
+	0,	/* Slot 10 - unused */
+	0,	/* Slot 11 - unused */
+	3,	/* Slot 12 - SCSI */
+	0,	/* Slot 13 - unused */
+	2,	/* Slot 14 - Ethernet */
+	0,	/* Slot 15 - unused */
+	9,      /* Slot 16 - PCI/PMC slot 1 */
+	10,     /* Slot 17 - PCI/PMC slot 2 */
+	11,     /* Slot 18 - PCI slot 3 */
+	0,	/* Slot 19 - unused */
+	0,	/* Slot 20 - unused */
+	0,	/* Slot 21 - unused */
+	0,	/* Slot 22 - unused */
+};
+
+/* Motorola MTX Plus */
+/* Secondary bus interrupt routing is not supported yet */
+static char MTXplus_pci_IRQ_map[23] __prepdata =
+{
+        0,      /* Slot 0  - unused */
+        0,      /* Slot 1  - unused */
+        0,      /* Slot 2  - unused */
+        0,      /* Slot 3  - unused */
+        0,      /* Slot 4  - unused */
+        0,      /* Slot 5  - unused */
+        0,      /* Slot 6  - unused */
+        0,      /* Slot 7  - unused */
+        0,      /* Slot 8  - unused */
+        0,      /* Slot 9  - unused */
+        0,      /* Slot 10 - unused */
+        0,      /* Slot 11 - unused */
+        3,      /* Slot 12 - SCSI */
+        0,      /* Slot 13 - unused */
+        2,      /* Slot 14 - Ethernet 1 */
+        0,      /* Slot 15 - unused */
+        9,      /* Slot 16 - PCI slot 1P */
+        10,     /* Slot 17 - PCI slot 2P */
+        11,     /* Slot 18 - PCI slot 3P */
+        10,     /* Slot 19 - Ethernet 2 */
+        0,      /* Slot 20 - P2P Bridge */
+        0,      /* Slot 21 - unused */
+        0,      /* Slot 22 - unused */
+};
+
+static char Raven_pci_IRQ_routes[] __prepdata =
+{
+   	0,	/* This is a dummy structure */
+};
+   
+/* Motorola MVME16xx */
+static char Genesis_pci_IRQ_map[16] __prepdata =
+{
+  	0,	/* Slot 0  - unused */
+  	0,	/* Slot 1  - unused */
+  	0,	/* Slot 2  - unused */
+  	0,	/* Slot 3  - unused */
+  	0,	/* Slot 4  - unused */
+  	0,	/* Slot 5  - unused */
+  	0,	/* Slot 6  - unused */
+  	0,	/* Slot 7  - unused */
+  	0,	/* Slot 8  - unused */
+  	0,	/* Slot 9  - unused */
+  	0,	/* Slot 10 - unused */
+  	0,	/* Slot 11 - unused */
+  	3,	/* Slot 12 - SCSI */
+  	0,	/* Slot 13 - unused */
+  	1,	/* Slot 14 - Ethernet */
+  	0,	/* Slot 15 - unused */
+};
+
+static char Genesis_pci_IRQ_routes[] __prepdata =
+{
+   	0,	/* Line 0 - Unused */
+   	10,	/* Line 1 */
+   	11,	/* Line 2 */
+   	14,	/* Line 3 */
+   	15	/* Line 4 */
+};
+   
+static char Genesis2_pci_IRQ_map[23] __prepdata =
+{
+	0,	/* Slot 0  - unused */
+	0,	/* Slot 1  - unused */
+	0,	/* Slot 2  - unused */
+	0,	/* Slot 3  - unused */
+	0,	/* Slot 4  - unused */
+	0,	/* Slot 5  - unused */
+	0,	/* Slot 6  - unused */
+	0,	/* Slot 7  - unused */
+	0,	/* Slot 8  - unused */
+	0,	/* Slot 9  - unused */
+	0,	/* Slot 10 - Ethernet */
+	0,	/* Slot 11 - Universe PCI - VME Bridge */
+	3,	/* Slot 12 - unused */
+	0,	/* Slot 13 - unused */
+	2,	/* Slot 14 - SCSI */
+	0,	/* Slot 15 - unused */
+	9,	/* Slot 16 - PMC 1 */
+	12,	/* Slot 17 - pci */
+	11,	/* Slot 18 - pci */
+	10,	/* Slot 19 - pci */
+	0,	/* Slot 20 - pci */
+	0,	/* Slot 21 - unused */
+	0,	/* Slot 22 - unused */
+};
+
+/* Motorola Series-E */
+static char Comet_pci_IRQ_map[23] __prepdata =
+{
+  	0,	/* Slot 0  - unused */
+  	0,	/* Slot 1  - unused */
+  	0,	/* Slot 2  - unused */
+  	0,	/* Slot 3  - unused */
+  	0,	/* Slot 4  - unused */
+  	0,	/* Slot 5  - unused */
+  	0,	/* Slot 6  - unused */
+  	0,	/* Slot 7  - unused */
+  	0,	/* Slot 8  - unused */
+  	0,	/* Slot 9  - unused */
+  	0,	/* Slot 10 - unused */
+  	0,	/* Slot 11 - unused */
+  	3,	/* Slot 12 - SCSI */
+  	0,	/* Slot 13 - unused */
+  	1,	/* Slot 14 - Ethernet */
+  	0,	/* Slot 15 - unused */
+	1,	/* Slot 16 - PCI slot 1 */
+	2,	/* Slot 17 - PCI slot 2 */
+	3,	/* Slot 18 - PCI slot 3 */
+	4,	/* Slot 19 - PCI bridge */
+	0,
+	0,
+	0,
+};
+
+static char Comet_pci_IRQ_routes[] __prepdata =
+{
+   	0,	/* Line 0 - Unused */
+   	10,	/* Line 1 */
+   	11,	/* Line 2 */
+   	14,	/* Line 3 */
+   	15	/* Line 4 */
+};
+
+/* Motorola Series-EX */
+static char Comet2_pci_IRQ_map[23] __prepdata =
+{
+	0,	/* Slot 0  - unused */
+	0,	/* Slot 1  - unused */
+	3,	/* Slot 2  - SCSI - NCR825A */
+	0,	/* Slot 3  - unused */
+	1,	/* Slot 4  - Ethernet - DEC2104X */
+	0,	/* Slot 5  - unused */
+	1,	/* Slot 6  - PCI slot 1 */
+	2,	/* Slot 7  - PCI slot 2 */
+	3,	/* Slot 8  - PCI slot 3 */
+	4,	/* Slot 9  - PCI bridge  */
+	0,	/* Slot 10 - unused */
+	0,	/* Slot 11 - unused */
+	3,	/* Slot 12 - SCSI - NCR825A */
+	0,	/* Slot 13 - unused */
+	1,	/* Slot 14 - Ethernet - DEC2104X */
+	0,	/* Slot 15 - unused */
+	1,	/* Slot 16 - PCI slot 1 */
+	2,	/* Slot 17 - PCI slot 2 */
+	3,	/* Slot 18 - PCI slot 3 */
+	4,	/* Slot 19 - PCI bridge */
+	0,
+	0,
+	0,
+};
+
+static char Comet2_pci_IRQ_routes[] __prepdata =
+{
+	0,	/* Line 0 - Unused */
+	10,	/* Line 1 */
+	11,	/* Line 2 */
+	14,	/* Line 3 */
+	15,	/* Line 4 */
+};
+
+/*
+ * ibm 830 (and 850?).
+ * This is actually based on the Carolina motherboard
+ * -- Cort
+ */
+static char ibm8xx_pci_IRQ_map[23] __prepdata = {
+        0, /* Slot 0  - unused */
+        0, /* Slot 1  - unused */
+        0, /* Slot 2  - unused */
+        0, /* Slot 3  - unused */
+        0, /* Slot 4  - unused */
+        0, /* Slot 5  - unused */
+        0, /* Slot 6  - unused */
+        0, /* Slot 7  - unused */
+        0, /* Slot 8  - unused */
+        0, /* Slot 9  - unused */
+        0, /* Slot 10 - unused */
+        0, /* Slot 11 - FireCoral */
+        4, /* Slot 12 - Ethernet  PCIINTD# */
+        2, /* Slot 13 - PCI Slot #2 */
+        2, /* Slot 14 - S3 Video PCIINTD# */
+        0, /* Slot 15 - onboard SCSI (INDI) [1] */
+        3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
+        0, /* Slot 17 - unused */
+        2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
+        0, /* Slot 19 - unused */
+        0, /* Slot 20 - unused */
+        0, /* Slot 21 - unused */
+        2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
+};
+
+static char ibm8xx_pci_IRQ_routes[] __prepdata = {
+        0,      /* Line 0 - unused */
+        15,     /* Line 1 */
+        15,     /* Line 2 */
+        15,     /* Line 3 */
+        15,     /* Line 4 */
+};
+
+/*
+ * a 6015 ibm board
+ * -- Cort
+ */
+static char ibm6015_pci_IRQ_map[23] __prepdata = {
+        0, /* Slot 0  - unused */
+        0, /* Slot 1  - unused */
+        0, /* Slot 2  - unused */
+        0, /* Slot 3  - unused */
+        0, /* Slot 4  - unused */
+        0, /* Slot 5  - unused */
+        0, /* Slot 6  - unused */
+        0, /* Slot 7  - unused */
+        0, /* Slot 8  - unused */
+        0, /* Slot 9  - unused */
+        0, /* Slot 10 - unused */
+        0, /* Slot 11 -  */
+        1, /* Slot 12 - SCSI */
+        2, /* Slot 13 -  */
+        2, /* Slot 14 -  */
+        1, /* Slot 15 -  */
+        1, /* Slot 16 -  */
+        0, /* Slot 17 -  */
+        2, /* Slot 18 -  */
+        0, /* Slot 19 -  */
+        0, /* Slot 20 -  */
+        0, /* Slot 21 -  */
+        2, /* Slot 22 -  */
+};
+
+static char ibm6015_pci_IRQ_routes[] __prepdata = {
+        0,      /* Line 0 - unused */
+        13,     /* Line 1 */
+        15,     /* Line 2 */
+        15,     /* Line 3 */
+        15,     /* Line 4 */
+};
+
+
+/* IBM Nobis and Thinkpad 850 */
+static char Nobis_pci_IRQ_map[23] __prepdata ={
+        0, /* Slot 0  - unused */
+        0, /* Slot 1  - unused */
+        0, /* Slot 2  - unused */
+        0, /* Slot 3  - unused */
+        0, /* Slot 4  - unused */
+        0, /* Slot 5  - unused */
+        0, /* Slot 6  - unused */
+        0, /* Slot 7  - unused */
+        0, /* Slot 8  - unused */
+        0, /* Slot 9  - unused */
+        0, /* Slot 10 - unused */
+        0, /* Slot 11 - unused */
+        3, /* Slot 12 - SCSI */
+        0, /* Slot 13 - unused */
+        0, /* Slot 14 - unused */
+        0, /* Slot 15 - unused */
+};
+
+static char Nobis_pci_IRQ_routes[] __prepdata = {
+        0, /* Line 0 - Unused */
+        13, /* Line 1 */
+        13, /* Line 2 */
+        13, /* Line 3 */
+        13      /* Line 4 */
+};
+
+/*
+ * IBM RS/6000 43p/140  -- paulus
+ * XXX we should get all this from the residual data
+ */
+static char ibm43p_pci_IRQ_map[23] __prepdata = {
+        0, /* Slot 0  - unused */
+        0, /* Slot 1  - unused */
+        0, /* Slot 2  - unused */
+        0, /* Slot 3  - unused */
+        0, /* Slot 4  - unused */
+        0, /* Slot 5  - unused */
+        0, /* Slot 6  - unused */
+        0, /* Slot 7  - unused */
+        0, /* Slot 8  - unused */
+        0, /* Slot 9  - unused */
+        0, /* Slot 10 - unused */
+        0, /* Slot 11 - FireCoral ISA bridge */
+        6, /* Slot 12 - Ethernet  */
+        0, /* Slot 13 - openpic */
+        0, /* Slot 14 - unused */
+        0, /* Slot 15 - unused */
+        7, /* Slot 16 - NCR58C825a onboard scsi */
+        0, /* Slot 17 - unused */
+        2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
+        0, /* Slot 19 - unused */
+        0, /* Slot 20 - unused */
+        0, /* Slot 21 - unused */
+        1, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
+};
+
+static char ibm43p_pci_IRQ_routes[] __prepdata = {
+        0,      /* Line 0 - unused */
+        15,     /* Line 1 */
+        15,     /* Line 2 */
+        15,     /* Line 3 */
+        15,     /* Line 4 */
+};
+
+/* Motorola PowerPlus architecture PCI IRQ tables */
+/* Interrupt line values for INTA-D on primary/secondary MPIC inputs */
+
+struct powerplus_irq_list
+{
+	unsigned char primary[4];       /* INT A-D */
+	unsigned char secondary[4];     /* INT A-D */
+};
+
+/*
+ * For standard PowerPlus boards, bus 0 PCI INTs A-D are routed to
+ * OpenPIC inputs 9-12.  PCI INTs A-D from the on board P2P bridge
+ * are routed to OpenPIC inputs 5-8.  These values are offset by
+ * 16 in the table to reflect the Linux kernel interrupt value.
+ */
+struct powerplus_irq_list Powerplus_pci_IRQ_list __prepdata =
+{
+	{25, 26, 27, 28},
+	{21, 22, 23, 24}
+};
+
+/*
+ * For the MCP750 (system slot board), cPCI INTs A-D are routed to
+ * OpenPIC inputs 8-11 and the PMC INTs A-D are routed to OpenPIC
+ * input 3.  On a hot swap MCP750, the companion card PCI INTs A-D
+ * are routed to OpenPIC inputs 12-15. These values are offset by
+ * 16 in the table to reflect the Linux kernel interrupt value.
+ */
+struct powerplus_irq_list Mesquite_pci_IRQ_list __prepdata =
+{
+	{24, 25, 26, 27},
+	{28, 29, 30, 31}
+};
+
+/*
+ * This table represents the standard PCI swizzle defined in the
+ * PCI bus specification.
+ */
+static unsigned char prep_pci_intpins[4][4] __prepdata =
+{
+	{ 1, 2, 3, 4},  /* Buses 0, 4, 8, ... */
+	{ 2, 3, 4, 1},  /* Buses 1, 5, 9, ... */
+	{ 3, 4, 1, 2},  /* Buses 2, 6, 10 ... */
+	{ 4, 1, 2, 3},  /* Buses 3, 7, 11 ... */
+};
+
+/* We have to turn on LEVEL mode for changed IRQ's */
+/* All PCI IRQ's need to be level mode, so this should be something
+ * other than hard-coded as well... IRQ's are individually mappable
+ * to either edge or level.
+ */
+
+/*
+ * 8259 edge/level control definitions
+ */
+#define ISA8259_M_ELCR 0x4d0
+#define ISA8259_S_ELCR 0x4d1
+
+#define ELCRS_INT15_LVL         0x80
+#define ELCRS_INT14_LVL         0x40
+#define ELCRS_INT12_LVL         0x10
+#define ELCRS_INT11_LVL         0x08
+#define ELCRS_INT10_LVL         0x04
+#define ELCRS_INT9_LVL          0x02
+#define ELCRS_INT8_LVL          0x01
+#define ELCRM_INT7_LVL          0x80
+#define ELCRM_INT5_LVL          0x20
+
+#define CFGPTR(dev) (0x80800000 | (1<<(dev>>3)) | ((dev&7)<<8) | offset)
+#define DEVNO(dev)  (dev>>3)                                  
+
+#define cfg_read(val, addr, type, op)	*val = op((type)(addr))
+#define cfg_write(val, addr, type, op)	op((type *)(addr), (val))
+
+#define cfg_read_bad(val, size)		*val = bad_##size;
+#define cfg_write_bad(val, size)
+
+#define bad_byte	0xff
+#define bad_word	0xffff
+#define bad_dword	0xffffffffU
+
+#define PREP_PCI_OP(rw, size, type, op)					\
+static int __prep							\
+prep_##rw##_config_##size(struct pci_dev *dev, int offset, type val)	\
+{									\
+	if ((dev->bus->number != 0) || (DEVNO(dev->devfn) > MAX_DEVNR))	\
+	{                   						\
+		cfg_##rw##_bad(val, size)				\
+		return PCIBIOS_DEVICE_NOT_FOUND;    			\
+	}								\
+	cfg_##rw(val, CFGPTR(dev->devfn), type, op);			\
+	return PCIBIOS_SUCCESSFUL;					\
+}
+
+PREP_PCI_OP(read, byte, u8 *, in_8)
+PREP_PCI_OP(read, word, u16 *, in_le16)
+PREP_PCI_OP(read, dword, u32 *, in_le32)
+PREP_PCI_OP(write, byte, u8, out_8)
+PREP_PCI_OP(write, word, u16, out_le16)
+PREP_PCI_OP(write, dword, u32, out_le32)
+
+static struct pci_ops prep_pci_ops =
+{
+	prep_read_config_byte,
+	prep_read_config_word,
+	prep_read_config_dword,
+	prep_write_config_byte,
+	prep_write_config_word,
+	prep_write_config_dword
+};
+
+#define MOTOROLA_CPUTYPE_REG	0x800
+#define MOTOROLA_BASETYPE_REG	0x803
+#define MPIC_RAVEN_ID		0x48010000
+#define	MPIC_HAWK_ID		0x48030000
+#define	MOT_PROC2_BIT		0x800
+
+static u_char mvme2600_openpic_initsenses[] __initdata = {
+    1,	/* MVME2600_INT_SIO */
+    0,	/* MVME2600_INT_FALCN_ECC_ERR */
+    1,	/* MVME2600_INT_PCI_ETHERNET */
+    1,	/* MVME2600_INT_PCI_SCSI */
+    1,	/* MVME2600_INT_PCI_GRAPHICS */
+    1,	/* MVME2600_INT_PCI_VME0 */
+    1,	/* MVME2600_INT_PCI_VME1 */
+    1,	/* MVME2600_INT_PCI_VME2 */
+    1,	/* MVME2600_INT_PCI_VME3 */
+    1,	/* MVME2600_INT_PCI_INTA */
+    1,	/* MVME2600_INT_PCI_INTB */
+    1,	/* MVME2600_INT_PCI_INTC */
+    1,	/* MVME2600_INT_PCI_INTD */
+    1,	/* MVME2600_INT_LM_SIG0 */
+    1,	/* MVME2600_INT_LM_SIG1 */
+};
+
+#define MOT_RAVEN_PRESENT	0x1
+#define MOT_HAWK_PRESENT	0x2
+
+int mot_entry = -1;
+int prep_keybd_present = 1;
+int MotMPIC;
+int mot_multi;
+
+int __init
+raven_init(void)
+{
+	unsigned int	devid;
+	unsigned int	pci_membase;
+	unsigned char	base_mod;
+
+	/* Check to see if the Raven chip exists. */
+	if ( _prep_type != _PREP_Motorola) {
+		OpenPIC_Addr = NULL;
+		return 0;
+	}
+
+	/* Check to see if this board is a type that might have a Raven. */
+	if ((inb(MOTOROLA_CPUTYPE_REG) & 0xF0) != 0xE0) {
+		OpenPIC_Addr = NULL;
+		return 0;
+	}
+
+	/* Check the first PCI device to see if it is a Raven. */
+	early_read_config_dword(0, 0, 0, PCI_VENDOR_ID, &devid);
+
+	switch (devid & 0xffff0000) {
+	case MPIC_RAVEN_ID:
+		MotMPIC = MOT_RAVEN_PRESENT;
+		break;
+	case MPIC_HAWK_ID:
+		MotMPIC = MOT_HAWK_PRESENT;
+		break;
+	default:
+		OpenPIC_Addr = NULL;
+		return 0;
+	}
+
+
+	/* Read the memory base register. */
+	early_read_config_dword(0, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
+
+	if (pci_membase == 0) {
+		OpenPIC_Addr = NULL;
+		return 0;
+	}
+
+	/* Map the Raven MPIC registers to virtual memory. */
+	OpenPIC_Addr = ioremap(pci_membase+0xC0000000, 0x22000);
+
+	OpenPIC_InitSenses = mvme2600_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
+
+	ppc_md.get_irq = openpic_get_irq;
+	
+	/* If raven is present on Motorola store the system config register
+	 * for later use.
+	 */
+	ProcInfo = (unsigned long *)ioremap(0xfef80400, 4);
+
+	/* Indicate to system if this is a multiprocessor board */
+	if (!(*ProcInfo & MOT_PROC2_BIT)) {
+		mot_multi = 1;
+	}
+
+	/* This is a hack.  If this is a 2300 or 2400 mot board then there is
+	 * no keyboard controller and we have to indicate that.
+	 */
+	base_mod = inb(MOTOROLA_BASETYPE_REG);
+	if ((MotMPIC == MOT_HAWK_PRESENT) || (base_mod == 0xF9) ||
+	    (base_mod == 0xFA) || (base_mod == 0xE1))
+		prep_keybd_present = 0;
+
+	return 1;
+}
+
+struct mot_info {
+	int		cpu_type;	/* 0x100 mask assumes for Raven and Hawk boards that the level/edge are set */
+					/* 0x200 if this board has a Hawk chip. */
+	int		base_type;
+	int		max_cpu;	/* ored with 0x80 if this board should be checked for multi CPU */
+	const char	*name;
+	unsigned char	*map;
+	unsigned char	*routes;
+	void            (*map_non0_bus)(struct pci_dev *);      /* For boards with more than bus 0 devices. */
+	struct powerplus_irq_list *pci_irq_list; /* List of PCI MPIC inputs */
+	unsigned char   secondary_bridge_devfn; /* devfn of secondary bus transparent bridge */
+} mot_info[] __prepdata = {
+	{0x300, 0x00, 0x00, "MVME 2400",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x010, 0x00, 0x00, "Genesis",				Genesis_pci_IRQ_map,	Genesis_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x020, 0x00, 0x00, "Powerstack (Series E)",		Comet_pci_IRQ_map,	Comet_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x040, 0x00, 0x00, "Blackhawk (Powerstack)",		Blackhawk_pci_IRQ_map,	Blackhawk_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)",	Omaha_pci_IRQ_map,	Omaha_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)",	Utah_pci_IRQ_map,	Utah_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x0A0, 0x00, 0x00, "Powerstack (Series EX)",		Comet2_pci_IRQ_map,	Comet2_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)",		Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)",		Sitka_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC",	Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xC0},
+	{0x1E0, 0xF6, 0x80, "MTX Plus",				MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
+	{0x1E0, 0xF6, 0x81, "Dual MTX Plus",			MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
+	{0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF9, 0x00, "MVME 2300",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x000, 0x00, 0x00, "",					NULL,			NULL, NULL, NULL, 0x00}
+};
+
+void __init
+ibm_prep_init(void)
+{
+	u32 addr;
+#ifdef CONFIG_PREP_RESIDUAL
+	PPC_DEVICE *mpic;
+#endif
+
+	if (inb(0x0852) == 0xd5) {
+		/* This is for the 43p-140 */
+		early_read_config_dword(0, 0, PCI_DEVFN(13, 0),
+					PCI_BASE_ADDRESS_0, &addr);
+		if (addr != 0xffffffff
+		    && !(addr & PCI_BASE_ADDRESS_SPACE_IO)
+		    && (addr &= PCI_BASE_ADDRESS_MEM_MASK) != 0) {
+			addr += PREP_ISA_MEM_BASE;
+			OpenPIC_Addr = ioremap(addr, 0x40000);
+			ppc_md.get_irq = openpic_get_irq;
+		}
+	}
+
+#ifdef CONFIG_PREP_RESIDUAL
+	mpic = residual_find_device(-1, NULL, SystemPeripheral,
+				    ProgrammableInterruptController, MPIC, 0);
+	if (mpic != NULL)
+		printk("mpic = %p\n", mpic);
+#endif
+}
+
+static void __init
+ibm43p_pci_map_non0(struct pci_dev *dev)
+{
+	unsigned char intpin;
+	static unsigned char bridge_intrs[4] = { 3, 4, 5, 8 };
+
+	if (dev == NULL)
+		return;
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &intpin);
+	if (intpin < 1 || intpin > 4)
+		return;
+	intpin = (PCI_SLOT(dev->devfn) + intpin - 1) & 3;
+	dev->irq = openpic_to_irq(bridge_intrs[intpin]);
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+}
+
+void __init
+prep_route_pci_interrupts(void)
+{
+	unsigned char *ibc_pirq = (unsigned char *)0x80800860;
+	unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
+	int i;
+	
+	if ( _prep_type == _PREP_Motorola)
+	{
+		unsigned short irq_mode;
+		unsigned char  cpu_type;
+		unsigned char  base_mod;
+		int	       entry;
+
+		cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
+		base_mod = inb(MOTOROLA_BASETYPE_REG);
+
+		for (entry = 0; mot_info[entry].cpu_type != 0; entry++) {
+			if (mot_info[entry].cpu_type & 0x200) {		 	/* Check for Hawk chip */
+				if (!(MotMPIC & MOT_HAWK_PRESENT))
+					continue;
+			} else {						/* Check non hawk boards */
+				if ((mot_info[entry].cpu_type & 0xff) != cpu_type)
+					continue;
+
+				if (mot_info[entry].base_type == 0) {
+					mot_entry = entry;
+					break;
+				}
+
+				if (mot_info[entry].base_type != base_mod)
+					continue;
+			}
+
+			if (!(mot_info[entry].max_cpu & 0x80)) {
+				mot_entry = entry;
+				break;
+			}
+
+			/* processor 1 not present and max processor zero indicated */
+			if ((*ProcInfo & MOT_PROC2_BIT) && !(mot_info[entry].max_cpu & 0x7f)) {
+				mot_entry = entry;
+				break;
+			}
+
+			/* processor 1 present and max processor zero indicated */
+			if (!(*ProcInfo & MOT_PROC2_BIT) && (mot_info[entry].max_cpu & 0x7f)) {
+				mot_entry = entry;
+				break;
+			}
+		}
+
+		if (mot_entry == -1) 	/* No particular cpu type found - assume Blackhawk */
+			mot_entry = 3;
+
+		Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name;
+		Motherboard_map = mot_info[mot_entry].map;
+		Motherboard_routes = mot_info[mot_entry].routes;
+		Motherboard_non0 = mot_info[mot_entry].map_non0_bus;
+
+		if (!(mot_info[entry].cpu_type & 0x100)) {
+			/* AJF adjust level/edge control according to routes */
+			irq_mode = 0;
+			for (i = 1;  i <= 4;  i++)
+				irq_mode |= ( 1 << Motherboard_routes[i] );
+			outb( irq_mode & 0xff, 0x4d0 );
+			outb( (irq_mode >> 8) & 0xff, 0x4d1 );
+		}
+	} else if ( _prep_type == _PREP_IBM ) {
+		unsigned char planar_id = inb(0x0852);
+		unsigned char irq_edge_mask_lo, irq_edge_mask_hi;
+
+		printk("IBM ID: %08x\n", planar_id);
+		switch(planar_id) {
+		case 0xff:
+			Motherboard_map_name = "IBM Thinkpad 850/860";
+			Motherboard_map = Nobis_pci_IRQ_map;
+			Motherboard_routes = Nobis_pci_IRQ_routes;
+			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
+			break;
+		case 0xfc:
+			Motherboard_map_name = "IBM 6015/7020 (Sandalfoot/Sandalbow)";
+			Motherboard_map = ibm6015_pci_IRQ_map;
+			Motherboard_routes = ibm6015_pci_IRQ_routes;
+			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
+			break;
+		case 0xd5:
+			Motherboard_map_name = "IBM 43P-140 (Tiger1)";
+			Motherboard_map = ibm43p_pci_IRQ_map;
+			Motherboard_routes = ibm43p_pci_IRQ_routes;
+			Motherboard_non0 = ibm43p_pci_map_non0;
+			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
+			break;
+		default:
+			printk(KERN_ERR "Unknown IBM motherboard! Defaulting to Carolina.\n");
+		case 0xf0: /* PowerSeries 830/850 */
+		case 0xf1: /* PowerSeries 830/850 */
+		case 0xf2: /* PowerSeries 830/850 */
+		case 0xf4: /* 7248-43P */
+		case 0xf5: /* 7248-43P */
+		case 0xf6: /* 7248-43P */
+		case 0xf7: /* 7248-43P (missing from Carolina Tech Spec) */
+			Motherboard_map_name = "IBM PS830/PS850/7248 (Carolina)";
+			Motherboard_map = ibm8xx_pci_IRQ_map;
+			Motherboard_routes = ibm8xx_pci_IRQ_routes;
+			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+			irq_edge_mask_hi = 0xA4; /* irq's 10, 13, 15 level-triggered */
+			break;
+		}
+
+		outb(inb(0x04d0)|irq_edge_mask_lo, 0x04d0); /* primary 8259 */
+		outb(inb(0x04d1)|irq_edge_mask_hi, 0x04d1); /* cascaded 8259 */
+	} else {
+		printk("No known machine pci routing!\n");
+		return;
+	}
+	
+	/* Set up mapping from slots */
+	for (i = 1;  i <= 4;  i++)
+		ibc_pirq[i-1] = Motherboard_routes[i];
+	/* Enable PCI interrupts */
+	*ibc_pcicon |= 0x20;
+}
+
+void __init
+prep_pib_init(void)
+{
+	unsigned char   reg;
+	unsigned short  short_reg;
+
+	struct pci_dev *dev = NULL;
+
+	if (( _prep_type == _PREP_Motorola) && (OpenPIC_Addr)) {
+		/*
+		 * Perform specific configuration for the Via Tech or
+		 * or Winbond PCI-ISA-Bridge part.
+		 */
+		if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, 
+					PCI_DEVICE_ID_VIA_82C586_1, dev))) {
+			/*
+			 * PPCBUG does not set the enable bits
+			 * for the IDE device. Force them on here.
+			 */
+			pci_read_config_byte(dev, 0x40, &reg);
+
+			reg |= 0x03; /* IDE: Chip Enable Bits */
+			pci_write_config_byte(dev, 0x40, reg);
+		}
+		if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
+						PCI_DEVICE_ID_VIA_82C586_2,
+						dev)) && (dev->devfn = 0x5a)) {
+			/* Force correct USB interrupt */
+			dev->irq = 11;
+			pci_write_config_byte(dev,
+					PCI_INTERRUPT_LINE,
+					dev->irq);
+		}
+		if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+					PCI_DEVICE_ID_WINBOND_83C553, dev))) {
+			 /* Clear PCI Interrupt Routing Control Register. */
+			short_reg = 0x0000;
+			pci_write_config_word(dev, 0x44, short_reg);
+			if (OpenPIC_Addr){
+				/* Route IDE interrupts to IRQ 14 */
+				reg = 0xEE;
+				pci_write_config_byte(dev, 0x43, reg);
+			}
+		}
+	}
+
+	if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+				   PCI_DEVICE_ID_WINBOND_82C105, dev))){
+		if (OpenPIC_Addr){
+			/*
+			 * Disable LEGIRQ mode so PCI INTS are routed
+			 * directly to the 8259 and enable both channels
+			 */
+			pci_write_config_dword(dev, 0x40, 0x10ff0033);
+
+			/* Force correct IDE interrupt */
+			dev->irq = 14;
+			pci_write_config_byte(dev,
+					PCI_INTERRUPT_LINE,
+					dev->irq);
+		} else {
+			/* Enable LEGIRQ for PCI INT -> 8259 IRQ routing */
+			pci_write_config_dword(dev, 0x40, 0x10ff08a1);
+		}
+	}
+}
+
+static void __init
+Powerplus_Map_Non0(struct pci_dev *dev)
+{
+	struct pci_bus  *pbus;          /* Parent bus structure pointer */
+	struct pci_dev  *tdev = dev;    /* Temporary device structure */
+	unsigned int    devnum;         /* Accumulated device number */
+	unsigned char   intline;        /* Linux interrupt value */
+	unsigned char   intpin;         /* PCI interrupt pin */
+
+	/* Check for valid PCI dev pointer */
+	if (dev == NULL) return;
+
+	/* Initialize bridge IDSEL variable */
+	devnum = PCI_SLOT(tdev->devfn);
+
+	/* Read the interrupt pin of the device and adjust for indexing */
+	pcibios_read_config_byte(dev->bus->number, dev->devfn,
+			PCI_INTERRUPT_PIN, &intpin);
+
+	/* If device doesn't request an interrupt, return */
+	if ( (intpin < 1) || (intpin > 4) )
+		return;
+
+	intpin--;
+
+	/*
+	 * Walk up to bus 0, adjusting the interrupt pin for the standard
+	 * PCI bus swizzle.
+	 */
+	do {
+		intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
+		pbus = tdev->bus;        /* up one level */
+		tdev = pbus->self;
+		devnum = PCI_SLOT(tdev->devfn);
+	} while(tdev->bus->number);
+
+	/* Use the primary interrupt inputs by default */
+	intline = mot_info[mot_entry].pci_irq_list->primary[intpin];
+
+	/*
+	 * If the board has secondary interrupt inputs, walk the bus and
+	 * note the devfn of the bridge from bus 0.  If it is the same as
+	 * the devfn of the bus bridge with secondary inputs, use those.
+	 * Otherwise, assume it's a PMC site and get the interrupt line
+	 * value from the interrupt routing table.
+	 */ 
+	if (mot_info[mot_entry].secondary_bridge_devfn) {
+		pbus = dev->bus;
+
+		while (pbus->primary != 0)
+			pbus = pbus->parent;
+
+		if ((pbus->self)->devfn != 0xA0) {
+			if ((pbus->self)->devfn == mot_info[mot_entry].secondary_bridge_devfn)
+				intline = mot_info[mot_entry].pci_irq_list->secondary[intpin];
+			else {
+				if ((char *)(mot_info[mot_entry].map) == (char *)Mesquite_pci_IRQ_map)
+					intline = mot_info[mot_entry].map[((pbus->self)->devfn)/8] + 16;
+				else {
+					int i;
+					for (i=0;i<3;i++)
+						intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
+					intline = mot_info[mot_entry].pci_irq_list->primary[intpin];
+				}
+			}
+		}
+	}
+
+	/* Write calculated interrupt value to header and device list */
+	dev->irq = intline;
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, (u8)dev->irq);
+}
+
+void __init
+prep_pcibios_fixup(void)
+{
+        struct pci_dev *dev;
+        extern unsigned char *Motherboard_map;
+        extern unsigned char *Motherboard_routes;
+        unsigned char i;
+
+	prep_route_pci_interrupts();
+
+	printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
+	if (OpenPIC_Addr) {
+		/* PCI interrupts are controlled by the OpenPIC */
+		pci_for_each_dev(dev) {
+			if (dev->bus->number == 0) {
+                       		dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
+				pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_LINE, dev->irq);
+			} else {
+				if (Motherboard_non0 != NULL)
+					Motherboard_non0(dev);
+			}
+		}
+
+		/* Setup the Winbond or Via PIB */
+		prep_pib_init();
+
+		return;
+	}
+
+	pci_for_each_dev(dev) {
+		/*
+		 * Use our old hard-coded kludge to figure out what
+		 * irq this device uses.  This is necessary on things
+		 * without residual data. -- Cort
+		 */
+		unsigned char d = PCI_SLOT(dev->devfn);
+		dev->irq = Motherboard_routes[Motherboard_map[d]];
+
+		for ( i = 0 ; i <= 5 ; i++ ) {
+			/*
+			 * Relocate PCI I/O resources if necessary so the
+			 * standard 256MB BAT covers them.
+			 */
+			if ( (pci_resource_flags(dev, i) & IORESOURCE_IO) &&
+				      (dev->resource[i].start > 0x10000000))  {
+				printk("Relocating PCI address %lx -> %lx\n",
+						dev->resource[i].start,
+						(dev->resource[i].start & 
+						 0x00FFFFFF)| 0x01000000);
+				dev->resource[i].start =
+					(dev->resource[i].start & 0x00FFFFFF)
+					| 0x01000000;
+		                pci_write_config_dword(dev,
+						PCI_BASE_ADDRESS_0 + (i*0x4),
+						dev->resource[i].start);
+				dev->resource[i].end = 
+					(dev->resource[i].end & 0x00FFFFFF)
+					| 0x01000000;
+		        }
+		}
+#if 0
+		/*
+		 * If we have residual data and if it knows about this
+		 * device ask it what the irq is.
+		 *  -- Cort
+		 */
+		ppcd = residual_find_device_id( ~0L, dev->device,
+		                                -1,-1,-1, 0);
+#endif
+	}
+}
+
+static void __init
+prep_pcibios_after_init(void)
+{
+	struct pci_dev *dev;
+	
+	/* If there is a WD 90C, reset the IO BAR to 0x0 (it started that 
+	 * way, but the PCI layer relocated it because it thought 0x0 was
+	 * invalid for a BAR).
+	 * If you don't do this, the card's VGA base will be <IO BAR>+0xc0000
+	 * instead of 0xc0000. vgacon.c (for example) is completely unaware of
+	 * this little quirk.
+	 */
+	dev = pci_find_device(PCI_VENDOR_ID_WD, PCI_DEVICE_ID_WD_90C, NULL);
+	if (dev) {
+		dev->resource[1].end -= dev->resource[1].start;
+		dev->resource[1].start = 0;
+		/* tell the hardware */
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0x0);
+	}
+}
+
+static void __init
+prep_init_resource(struct resource *res, unsigned long start,
+		   unsigned long end, int flags)
+{
+	res->flags = flags;
+	res->start = start;
+	res->end = end;
+	res->name = "PCI host bridge";
+	res->parent = NULL;
+	res->sibling = NULL;
+	res->child = NULL;
+}
+
+void __init
+prep_find_bridges(void)
+{
+	struct pci_controller* hose;
+
+	hose = pcibios_alloc_controller();
+	if (!hose)
+		return;
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+	hose->pci_mem_offset = PREP_ISA_MEM_BASE;
+	hose->io_base_phys = PREP_ISA_IO_BASE;
+	hose->io_base_virt = (void *)0x80000000; /* see prep_map_io() */
+	prep_init_resource(&hose->io_resource, 0, 0x0fffffff, IORESOURCE_IO);
+	prep_init_resource(&hose->mem_resources[0], 0xc0000000, 0xfeffffff,
+			   IORESOURCE_MEM);
+	
+	printk("PReP architecture\n");
+	{
+#ifdef CONFIG_PREP_RESIDUAL	  
+		PPC_DEVICE *hostbridge;
+
+		hostbridge = residual_find_device(PROCESSORDEVICE, NULL,
+			BridgeController, PCIBridge, -1, 0);
+		if (hostbridge &&
+			hostbridge->DeviceId.Interface == PCIBridgeIndirect) {
+			PnP_TAG_PACKET * pkt;
+			pkt = PnP_find_large_vendor_packet(
+				res->DevicePnPHeap+hostbridge->AllocatedOffset,
+				3, 0);
+			if(pkt) {
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+				setup_indirect_pci(hose, 
+					ld_le32((unsigned *) (p.PPCData)),
+					ld_le32((unsigned *) (p.PPCData+8)));
+			} else
+				setup_indirect_pci(hose, 0x80000cf8, 0x80000cfc);
+		} else
+#endif /* CONFIG_PREP_RESIDUAL */
+			hose->ops = &prep_pci_ops;
+	}
+
+	ppc_md.pcibios_fixup = prep_pcibios_fixup;
+	ppc_md.pcibios_after_init = prep_pcibios_after_init;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/prep_setup.c linux-2.4.20/arch/ppc/platforms/prep_setup.c
--- linux-2.4.19/arch/ppc/platforms/prep_setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/prep_setup.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,890 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  linux/arch/ppc/kernel/setup.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * Support for PReP (Motorola MTX/MVME)
+ * by Troy Benjegerdes (hozer@drgw.net)
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+#include <linux/console.h>
+#include <linux/timex.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+
+#include <asm/sections.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/cache.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/mk48t59.h>
+#include <asm/prep_nvram.h>
+#include <asm/raven.h>
+#include <asm/keyboard.h>
+#include <asm/vga.h>
+#include <asm/time.h>
+#include <asm/i8259.h>
+#include <asm/open_pic.h>
+
+#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
+#include <../drivers/sound/sound_config.h>
+#include <../drivers/sound/dev_table.h>
+#endif
+
+unsigned char ucSystemType;
+unsigned char ucBoardRev;
+unsigned char ucBoardRevMaj, ucBoardRevMin;
+
+extern unsigned long mc146818_get_rtc_time(void);
+extern int mc146818_set_rtc_time(unsigned long nowtime);
+extern unsigned long mk48t59_get_rtc_time(void);
+extern int mk48t59_set_rtc_time(unsigned long nowtime);
+
+extern unsigned char prep_nvram_read_val(int addr);
+extern void prep_nvram_write_val(int addr,
+				 unsigned char val);
+extern unsigned char rs_nvram_read_val(int addr);
+extern void rs_nvram_write_val(int addr,
+				 unsigned char val);
+extern void ibm_prep_init(void);
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+		char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[];
+
+extern void prep_find_bridges(void);
+extern char saved_command_line[];
+
+int _prep_type;
+
+#define cached_21	(((char *)(ppc_cached_irq_mask))[3])
+#define cached_A1	(((char *)(ppc_cached_irq_mask))[2])
+
+/* for the mac fs */
+kdev_t boot_dev;
+/* used in nasty hack for sound - see prep_setup_arch() -- Cort */
+long ppc_cs4232_dma, ppc_cs4232_dma2;
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern int probingmem;
+extern unsigned long loops_per_jiffy;
+
+#ifdef CONFIG_SOUND_MODULE
+EXPORT_SYMBOL(ppc_cs4232_dma);
+EXPORT_SYMBOL(ppc_cs4232_dma2);
+#endif
+
+static int __prep
+prep_show_cpuinfo(struct seq_file *m)
+{
+	extern char *Motherboard_map_name;
+	int cachew;
+#ifdef CONFIG_PREP_RESIDUAL
+	int i;
+#endif
+
+	seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name);
+
+	switch ( _prep_type ) {
+	case _PREP_IBM:
+		cachew = inw(0x80c);
+		if (cachew & (1<<6))
+			seq_printf(m, "Upgrade CPU\n");
+		seq_printf(m, "L2\t\t: ");
+		if (cachew & (1<<7)) {
+			seq_printf(m, "not present\n");
+			goto no_l2;
+		}
+		seq_printf(m, "%sKb,", (cachew & (1 << 10))? "512" : "256");
+		seq_printf(m, "%ssync\n", (cachew & (1 << 15))? "" : "a");
+		break;
+	case _PREP_Motorola:
+		cachew = *((unsigned char *)CACHECRBA);
+		seq_printf(m, "L2\t\t: ");
+		switch (cachew & L2CACHE_MASK) {
+		case L2CACHE_512KB:
+			seq_printf(m, "512Kb");
+			break;
+		case L2CACHE_256KB:
+			seq_printf(m, "256Kb");
+			break;
+		case L2CACHE_1MB:
+			seq_printf(m, "1MB");
+			break;
+		case L2CACHE_NONE:
+			seq_printf(m, "none\n");
+			goto no_l2;
+			break;
+		default:
+			seq_printf(m, "%x\n", cachew);
+		}
+		
+		seq_printf(m, ", parity %s",
+			   (cachew & L2CACHE_PARITY)? "enabled" : "disabled");
+
+		seq_printf(m, " SRAM:");
+		
+		switch ( ((cachew & 0xf0) >> 4) & ~(0x3) ) {
+		case 1: seq_printf(m, "synchronous,parity,flow-through\n");
+			break;
+		case 2: seq_printf(m, "asynchronous,no parity\n");
+			break;
+		case 3: seq_printf(m, "asynchronous,parity\n");
+			break;
+		default:seq_printf(m, "synchronous,pipelined,no parity\n");
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+no_l2:
+#ifdef CONFIG_PREP_RESIDUAL
+	if (res->ResidualLength != 0) {
+		/* print info about SIMMs */
+		seq_printf(m, "simms\t\t: ");
+		for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) {
+			if (res->Memories[i].SIMMSize != 0)
+				seq_printf(m, "%d:%ldM ", i,
+					(res->Memories[i].SIMMSize > 1024) ? 
+					res->Memories[i].SIMMSize>>20 : 
+					res->Memories[i].SIMMSize);
+		}
+		seq_printf(m, "\n");
+	}
+#endif
+
+	return 0;
+}
+
+static int __prep
+prep_show_percpuinfo(struct seq_file *m, int i)
+{
+	/* PREP's without residual data will give incorrect values here */
+	seq_printf(m, "clock\t\t: ");
+#ifdef CONFIG_PREP_RESIDUAL	
+	if (res->ResidualLength)
+		seq_printf(m, "%ldMHz\n",
+			   (res->VitalProductData.ProcessorHz > 1024) ?
+			   res->VitalProductData.ProcessorHz / 1000000 :
+			   res->VitalProductData.ProcessorHz);
+	else
+#endif /* CONFIG_PREP_RESIDUAL */
+		seq_printf(m, "???\n");
+
+	return 0;
+}
+
+static void __init
+prep_setup_arch(void)
+{
+	unsigned char reg;
+#if 0 /* unused?? */
+	unsigned char ucMothMemType;
+	unsigned char ucEquipPres1;
+#endif
+
+	/* init to some ~sane value until calibrate_delay() runs */
+	loops_per_jiffy = 50000000;
+	
+	/* Lookup PCI host bridges */
+	prep_find_bridges();
+	
+	/* Set up floppy in PS/2 mode */
+	outb(0x09, SIO_CONFIG_RA);
+	reg = inb(SIO_CONFIG_RD);
+	reg = (reg & 0x3F) | 0x40;
+	outb(reg, SIO_CONFIG_RD);
+	outb(reg, SIO_CONFIG_RD);	/* Have to write twice to change! */
+
+	/* we should determine this according to what we find! -- Cort */
+	switch ( _prep_type )
+	{
+	case _PREP_IBM:
+		/* Enable L2.  Assume we don't need to flush -- Cort*/
+		*(unsigned char *)(0x8000081c) |= 3;
+		ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
+		break;
+	case _PREP_Motorola:
+		/* Enable L2.  Assume we don't need to flush -- Cort*/
+		*(unsigned char *)(0x8000081c) |= 3;
+#ifdef CONFIG_BLK_DEV_INITRD
+		if (initrd_start)
+			ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); /* /dev/ram */
+		else
+#endif
+#ifdef CONFIG_ROOT_NFS
+			ROOT_DEV = to_kdev_t(0x00ff); /* /dev/nfs */
+#else
+			ROOT_DEV = to_kdev_t(0x0802); /* /dev/sda2 */
+#endif
+		break;
+	}
+
+	/* Read in NVRAM data */ 
+	init_prep_nvram();
+
+	/* if no bootargs, look in NVRAM */
+	if ( cmd_line[0] == '\0' ) {
+		char *bootargs;
+		 bootargs = prep_nvram_get_var("bootargs");
+		 if (bootargs != NULL) {
+			 strcpy(cmd_line, bootargs);
+			 /* again.. */
+			 strcpy(saved_command_line, cmd_line);
+		}
+	}
+
+#ifdef CONFIG_SOUND_CS4232
+	/*
+	 * setup proper values for the cs4232 driver so we don't have
+	 * to recompile for the motorola or ibm workstations sound systems.
+	 * This is a really nasty hack, but unless we change the driver
+	 * it's the only way to support both addrs from one binary.
+	 * -- Cort
+	 */
+	if ( _machine == _MACH_prep )
+	{
+		extern struct card_info snd_installed_cards[];
+		struct card_info *snd_ptr;
+
+		for ( snd_ptr = snd_installed_cards; 
+			snd_ptr < &snd_installed_cards[num_sound_cards];
+			snd_ptr++ )
+		{
+			if ( snd_ptr->card_type == SNDCARD_CS4232 )
+			{
+				if ( _prep_type == _PREP_Motorola )
+				{
+					snd_ptr->config.io_base = 0x830;
+					snd_ptr->config.irq = 10;
+					snd_ptr->config.dma = ppc_cs4232_dma = 6;
+					snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7;
+				}
+				if ( _prep_type == _PREP_IBM )
+				{
+					snd_ptr->config.io_base = 0x530;
+					snd_ptr->config.irq = 5;
+					snd_ptr->config.dma = ppc_cs4232_dma = 1;
+					/* this is wrong - but leave it for now */
+					snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7;
+				}
+			}
+		}
+	}
+#endif /* CONFIG_SOUND_CS4232 */	
+
+	/*print_residual_device_info();*/
+
+	switch (_prep_type) {
+	case _PREP_Motorola:
+		raven_init();
+		break;
+	case _PREP_IBM:
+		ibm_prep_init();
+		break;
+	}
+
+#ifdef CONFIG_VGA_CONSOLE
+	/* remap the VGA memory */
+	vgacon_remap_base = 0xf0000000;
+	/*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/
+	conswitchp = &vga_con;
+#elif defined(CONFIG_DUMMY_CONSOLE)
+	conswitchp = &dummy_con;
+#endif
+}
+
+/*
+ * Determine the decrementer frequency from the residual data
+ * This allows for a faster boot as we do not need to calibrate the
+ * decrementer against another clock. This is important for embedded systems.
+ */
+static int __init
+prep_res_calibrate_decr(void)
+{
+#ifdef CONFIG_PREP_RESIDUAL
+	unsigned long freq, divisor = 4;
+
+	if ( res->VitalProductData.ProcessorBusHz ) {
+		freq = res->VitalProductData.ProcessorBusHz;
+		printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+				(freq/divisor)/1000000,
+				(freq/divisor)%1000000);
+		tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
+		tb_ticks_per_jiffy = freq / HZ / divisor;
+		return 0;
+	} else
+#endif	
+		return 1;
+}
+
+/*
+ * Uses the on-board timer to calibrate the on-chip decrementer register
+ * for prep systems.  On the pmac the OF tells us what the frequency is
+ * but on prep we have to figure it out.
+ * -- Cort
+ */
+/* Done with 3 interrupts: the first one primes the cache and the
+ * 2 following ones measure the interval. The precision of the method
+ * is still doubtful due to the short interval sampled.
+ */
+static volatile int calibrate_steps __initdata = 3;
+static unsigned tbstamp __initdata = 0;
+
+static void __init
+prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs *regs)
+{
+	unsigned long t, freq;
+	int step=--calibrate_steps;
+
+	t = get_tbl();
+	if (step > 0) {
+		tbstamp = t;
+	} else {
+		freq = (t - tbstamp)*HZ;
+		printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+			 freq/1000000, freq%1000000);
+		tb_ticks_per_jiffy = freq / HZ;
+		tb_to_us = mulhwu_scale_factor(freq, 1000000);
+	}
+}
+
+static void __init
+prep_calibrate_decr(void)
+{
+	int res;
+
+	/* Try and get this from the residual data. */
+	res = prep_res_calibrate_decr();
+
+	/* If we didn't get it from the residual data, try this. */
+	if ( res ) {
+		unsigned long flags;
+
+		save_flags(flags);
+
+#define TIMER0_COUNT 0x40
+#define TIMER_CONTROL 0x43
+		/* set timer to periodic mode */
+		outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */
+		/* set the clock to ~100 Hz */
+		outb_p(LATCH & 0xff , TIMER0_COUNT);	/* LSB */
+		outb(LATCH >> 8 , TIMER0_COUNT);	/* MSB */
+
+		if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0)
+			panic("Could not allocate timer IRQ!");
+		__sti();
+		/* wait for calibrate */
+		while ( calibrate_steps )
+			;
+		restore_flags(flags);
+		free_irq( 0, NULL);
+	}
+}
+
+static long __init
+mk48t59_init(void) {
+	unsigned char tmp;
+
+	tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
+	if (tmp & MK48T59_RTC_CB_STOP) {
+		printk("Warning: RTC was stopped, date will be wrong.\n");
+		ppc_md.nvram_write_val(MK48T59_RTC_CONTROLB, 
+					 tmp & ~MK48T59_RTC_CB_STOP);
+		/* Low frequency crystal oscillators may take a very long
+		 * time to startup and stabilize. For now just ignore the
+		 * the issue, but attempting to calibrate the decrementer
+		 * from the RTC just after this wakeup is likely to be very 
+		 * inaccurate. Firmware should not allow to load
+		 * the OS with the clock stopped anyway...
+		 */
+	}
+	/* Ensure that the clock registers are updated */
+	tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+	tmp &= ~(MK48T59_RTC_CA_READ | MK48T59_RTC_CA_WRITE);
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, tmp);
+	return 0;
+}
+
+/* We use the NVRAM RTC to time a second to calibrate the decrementer,
+ * the RTC registers have just been set up in the right state by the
+ * preceding routine.
+ */
+static void __init
+mk48t59_calibrate_decr(void)
+{
+	unsigned long freq;
+	unsigned long t1;
+	unsigned char save_control;
+	long i;
+	unsigned char sec;
+ 
+		
+	/* Make sure the time is not stopped. */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
+	
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			(save_control & (~MK48T59_RTC_CB_STOP)));
+
+	/* Now make sure the read bit is off so the value will change. */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+	save_control &= ~MK48T59_RTC_CA_READ;
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+
+	/* Read the seconds value to see when it changes. */
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+	/* Actually this is bad for precision, we should have a loop in
+	 * which we only read the seconds counter. nvram_read_val writes
+	 * the address bytes on every call and this takes a lot of time.
+	 * Perhaps an nvram_wait_change method returning a time
+	 * stamp with a loop count as parameter would be the  solution.
+	 */
+	for (i = 0 ; i < 1000000 ; i++)	{ /* may take up to 1 second... */
+		t1 = get_tbl();
+		if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+			break;
+		}
+	}
+
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+	for (i = 0 ; i < 1000000 ; i++)	{ /* Should take up 1 second... */
+		freq = get_tbl()-t1;
+		if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec)
+			break;
+	}
+
+	printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+		 freq/1000000, freq%1000000);
+	tb_ticks_per_jiffy = freq / HZ;
+	tb_to_us = mulhwu_scale_factor(freq, 1000000);
+}
+
+static void __prep
+prep_restart(char *cmd)
+{
+#define PREP_SP92	0x92	/* Special Port 92 */
+	__cli(); /* no interrupts */
+
+	/* set exception prefix high - to the prom */
+	_nmask_and_or_msr(0, MSR_IP);
+
+	/* make sure bit 0 (reset) is a 0 */
+	outb( inb(PREP_SP92) & ~1L , PREP_SP92);
+	/* signal a reset to system control port A - soft reset */
+	outb( inb(PREP_SP92) | 1 , PREP_SP92);
+
+	while ( 1 ) ;
+	/* not reached */
+#undef PREP_SP92
+}
+
+static void __prep
+prep_halt(void)
+{
+	__cli(); /* no interrupts */
+
+	/* set exception prefix high - to the prom */
+	_nmask_and_or_msr(0, MSR_IP);
+
+	while ( 1 ) ;
+	/* not reached */
+}
+
+/*
+ * On IBM PReP's, power management is handled by a Signetics 87c750 behind the
+ * Utah component on the ISA bus. To access the 750 you must write a series of
+ * nibbles to port 0x82a (decoded by the Utah). This is described somewhat in
+ * the IBM Carolina Technical Specification.
+ * -Hollis
+ */
+static void __prep
+utah_sig87c750_setbit(unsigned int bytenum, unsigned int bitnum, int value)
+{
+	/*
+	 * byte1: 0 0 0 1 0  d  a5 a4
+	 * byte2: 0 0 0 1 a3 a2 a1 a0
+	 *
+	 * d = the bit's value, enabled or disabled
+	 * (a5 a4 a3) = the byte number, minus 20
+	 * (a2 a1 a0) = the bit number
+	 *
+	 * example: set the 5th bit of byte 21 (21.5)
+	 *     a5 a4 a3 = 001 (byte 1)
+	 *     a2 a1 a0 = 101 (bit 5)
+	 *
+	 *     byte1 = 0001 0100 (0x14)
+	 *     byte2 = 0001 1101 (0x1d)
+	 */
+	unsigned char byte1=0x10, byte2=0x10;
+	const unsigned int pm_reg_1=0x82a; /* ISA address */
+
+	/* the 750's '20.0' is accessed as '0.0' through Utah (which adds 20) */
+	bytenum -= 20;
+
+	byte1 |= (!!value) << 2;		/* set d */
+	byte1 |= (bytenum >> 1) & 0x3;	/* set a5, a4 */
+
+	byte2 |= (bytenum & 0x1) << 3;	/* set a3 */
+	byte2 |= bitnum & 0x7;			/* set a2, a1, a0 */
+
+	outb(byte1, pm_reg_1);		/* first nibble */
+	mb();
+	udelay(100);				/* important: let controller recover */
+
+	outb(byte2, pm_reg_1);		/* second nibble */
+	mb();
+	udelay(100);				/* important: let controller recover */
+}
+
+static void __prep
+prep_power_off(void)
+{
+	if ( _prep_type == _PREP_IBM) {
+		/* tested on:
+		 * 		Carolina's: 7248-43P, 6070 (PowerSeries 850)
+		 * should work on:
+		 * 		Carolina: 6050 (PowerSeries 830)
+		 * 		7043-140 (Tiger 1)
+		 */
+		unsigned long flags;
+		__cli();
+		/* set exception prefix high - to the prom */
+		save_flags( flags );
+		restore_flags( flags|MSR_IP );
+
+		utah_sig87c750_setbit(21, 5, 1); /* set bit 21.5, "PMEXEC_OFF" */
+
+		while ( 1 ) ;
+		/* not reached */
+	} else {
+		prep_halt();
+	}
+}
+
+static unsigned int __prep
+prep_irq_cannonicalize(u_int irq)
+{
+	if (irq == 2)
+	{
+		return 9;
+	}
+	else
+	{
+		return irq;
+	}
+}
+
+static void __init
+prep_init_IRQ(void)
+{
+	int i;
+
+	if (OpenPIC_Addr != NULL)
+		openpic_init(1, NUM_8259_INTERRUPTS, 0, -1);
+	for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ )
+		irq_desc[i].handler = &i8259_pic;
+	i8259_init(0xbffffff0); /* PCI interrupt ack address for MPC105 and 106 */
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+static int __prep
+prep_ide_default_irq(ide_ioreg_t base)
+{
+	switch (base) {
+		case 0x1f0: return 13;
+		case 0x170: return 13;
+		case 0x1e8: return 11;
+		case 0x168: return 10;
+		case 0xfff0: return 14;		/* MCP(N)750 ide0 */
+		case 0xffe0: return 15;		/* MCP(N)750 ide1 */
+		default: return 0;
+	}
+}
+
+static ide_ioreg_t __prep
+prep_ide_default_io_base(int index)
+{
+	switch (index) {
+		case 0: return 0x1f0;
+		case 1: return 0x170;
+		case 2: return 0x1e8;
+		case 3: return 0x168;
+		default:
+			return 0;
+	}
+}
+
+static int __prep
+prep_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+	return check_region(from, extent);
+}
+
+static void __prep
+prep_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+	request_region(from, extent, name);
+}
+
+static void __prep
+prep_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+	release_region(from, extent);
+}
+
+static void __init
+prep_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+{
+	ide_ioreg_t reg = data_port;
+	int i;
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw->io_ports[i] = reg;
+		reg += 1;
+	}
+	if (ctrl_port) {
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+	} else {
+		hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
+	}
+	if (irq != NULL)
+		*irq = 0;
+}
+#endif
+
+#ifdef CONFIG_SMP
+/* PReP (MTX) support */
+static int __init
+smp_prep_probe(void)
+{
+	extern int mot_multi;
+
+	if (mot_multi) {
+		openpic_request_IPIs();
+		smp_hw_index[1] = 1;
+		return 2;
+	}
+
+	return 1;
+}
+
+static void __init
+smp_prep_kick_cpu(int nr)
+{
+	*(unsigned long *)KERNELBASE = nr;
+	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
+	printk("CPU1 reset, waiting\n");
+}
+
+static void __init
+smp_prep_setup_cpu(int cpu_nr)
+{
+	if (OpenPIC_Addr)
+		do_openpic_setup_cpu();
+}
+
+static struct smp_ops_t prep_smp_ops __prepdata = {
+	smp_openpic_message_pass,
+	smp_prep_probe,
+	smp_prep_kick_cpu,
+	smp_prep_setup_cpu,
+};
+#endif /* CONFIG_SMP */
+
+/*
+ * This finds the amount of physical ram and does necessary
+ * setup for prep.  This is pretty architecture specific so
+ * this will likely stay separate from the pmac.
+ * -- Cort
+ */
+static unsigned long __init
+prep_find_end_of_memory(void)
+{
+	unsigned long total = 0;
+	extern unsigned int boot_mem_size;
+
+#ifdef CONFIG_PREP_RESIDUAL	
+	total = res->TotalMemory;
+#endif	
+
+	if (total == 0 && boot_mem_size != 0)
+		total = boot_mem_size;
+	else if (total == 0) {
+		/*
+		 * I need a way to probe the amount of memory if the residual
+		 * data doesn't contain it. -- Cort
+		 */
+		total = 0x02000000;
+		printk(KERN_INFO "Ramsize from residual data was 0"
+			 " -- defaulting to %ldM\n", total>>20);
+	}
+
+	return (total);
+}
+
+/*
+ * Setup the bat mappings we're going to load that cover
+ * the io areas.  RAM was mapped by mapin_ram().
+ * -- Cort
+ */
+static void __init
+prep_map_io(void)
+{
+	io_block_mapping(0x80000000, PREP_ISA_IO_BASE, 0x10000000, _PAGE_IO);
+	io_block_mapping(0xf0000000, PREP_ISA_MEM_BASE, 0x08000000, _PAGE_IO);
+}
+
+static void __init
+prep_init2(void)
+{
+#ifdef CONFIG_NVRAM
+	request_region(PREP_NVRAM_AS0, 0x8, "nvram");
+#endif
+	request_region(0x20,0x20,"pic1");
+	request_region(0xa0,0x20,"pic2");
+	request_region(0x00,0x20,"dma1");
+	request_region(0x40,0x20,"timer");
+	request_region(0x80,0x10,"dma page reg");
+	request_region(0xc0,0x20,"dma2");
+}
+
+void __init
+prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
+		unsigned long r6, unsigned long r7)
+{
+#ifdef CONFIG_PREP_RESIDUAL	
+	/* make a copy of residual data */
+	if ( r3 ) {
+		memcpy((void *)res,(void *)(r3+KERNELBASE),
+			 sizeof(RESIDUAL));
+	}
+#endif
+
+	isa_io_base = PREP_ISA_IO_BASE;
+	isa_mem_base = PREP_ISA_MEM_BASE;
+	pci_dram_offset = PREP_PCI_DRAM_OFFSET;
+	ISA_DMA_THRESHOLD = 0x00ffffff;
+	DMA_MODE_READ = 0x44;
+	DMA_MODE_WRITE = 0x48;
+
+	/* figure out what kind of prep workstation we are */
+#ifdef CONFIG_PREP_RESIDUAL	
+	if ( res->ResidualLength != 0 )
+	{
+		if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
+			_prep_type = _PREP_IBM;
+		else
+			_prep_type = _PREP_Motorola;
+	}
+	else /* assume motorola if no residual (netboot?) */
+#endif
+	{
+		_prep_type = _PREP_Motorola;
+	}
+
+	ppc_md.setup_arch     = prep_setup_arch;
+	ppc_md.show_percpuinfo = prep_show_percpuinfo;
+	ppc_md.show_cpuinfo   = prep_show_cpuinfo;
+	ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
+	ppc_md.init_IRQ       = prep_init_IRQ;
+	/* this gets changed later on if we have an OpenPIC -- Cort */
+	ppc_md.get_irq        = i8259_irq;
+	ppc_md.init           = prep_init2;
+
+	ppc_md.restart        = prep_restart;
+	ppc_md.power_off      = prep_power_off;
+	ppc_md.halt           = prep_halt;
+
+	ppc_md.nvram_read_val = prep_nvram_read_val;
+	ppc_md.nvram_write_val = prep_nvram_write_val;
+
+	ppc_md.time_init      = NULL;
+	if (_prep_type == _PREP_IBM) {
+		ppc_md.set_rtc_time   = mc146818_set_rtc_time;
+		ppc_md.get_rtc_time   = mc146818_get_rtc_time;
+		ppc_md.calibrate_decr = prep_calibrate_decr;
+	} else {
+		ppc_md.set_rtc_time   = mk48t59_set_rtc_time;
+		ppc_md.get_rtc_time   = mk48t59_get_rtc_time;
+		ppc_md.calibrate_decr = mk48t59_calibrate_decr;
+		ppc_md.time_init      = mk48t59_init;
+	}
+
+	ppc_md.find_end_of_memory = prep_find_end_of_memory;
+	ppc_md.setup_io_mappings = prep_map_io;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+	ppc_ide_md.default_irq = prep_ide_default_irq;
+	ppc_ide_md.default_io_base = prep_ide_default_io_base;
+	ppc_ide_md.ide_check_region = prep_ide_check_region;
+	ppc_ide_md.ide_request_region = prep_ide_request_region;
+	ppc_ide_md.ide_release_region = prep_ide_release_region;
+	ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
+#endif
+
+#ifdef CONFIG_VT
+	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
+	ppc_md.kbd_translate     = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+	ppc_md.kbd_leds          = pckbd_leds;
+	ppc_md.kbd_init_hw       = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+	SYSRQ_KEY = 0x54;
+#endif
+#endif
+
+#ifdef CONFIG_SMP
+	ppc_md.smp_ops		 = &prep_smp_ops;
+#endif /* CONFIG_SMP */
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/prep_time.c linux-2.4.20/arch/ppc/platforms/prep_time.c
--- linux-2.4.19/arch/ppc/platforms/prep_time.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/prep_time.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,228 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/platforms/prep_time.c
+ *
+ *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *
+ * Adapted for PowerPC (PReP) by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu).
+ * Copied and modified from arch/i386/kernel/time.c
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+#include <linux/init.h>
+
+#include <asm/sections.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/prep_nvram.h>
+#include <asm/mk48t59.h>
+
+#include <asm/time.h>
+
+extern spinlock_t rtc_lock;
+
+/*
+ * The motorola uses the m48t18 rtc (includes DS1643) whose registers
+ * are at a higher end of nvram (1ff8-1fff) than the ibm mc146818
+ * rtc (ds1386) which has regs at addr 0-d).  The intel gets
+ * past this because the bios emulates the mc146818.
+ *
+ * Why in the world did they have to use different clocks?
+ *
+ * Right now things are hacked to check which machine we're on then
+ * use the appropriate macro.  This is very very ugly and I should
+ * probably have a function that checks which machine we're on then
+ * does things correctly transparently or a function pointer which
+ * is setup at boot time to use the correct addresses.
+ * -- Cort
+ */
+
+/*
+ * Set the hardware clock. -- Cort
+ */
+__prep
+int mc146818_set_rtc_time(unsigned long nowtime)
+{
+	unsigned char save_control, save_freq_select;
+	struct rtc_time tm;
+
+	spin_lock(&rtc_lock);
+	to_tm(nowtime, &tm);
+
+	/* tell the clock it's being set */
+	save_control = CMOS_READ(RTC_CONTROL);
+
+	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+	/* stop and reset prescaler */
+	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+
+	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+        tm.tm_year = (tm.tm_year - 1900) % 100;
+	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BIN_TO_BCD(tm.tm_sec);
+		BIN_TO_BCD(tm.tm_min);
+		BIN_TO_BCD(tm.tm_hour);
+		BIN_TO_BCD(tm.tm_mon);
+		BIN_TO_BCD(tm.tm_mday);
+		BIN_TO_BCD(tm.tm_year);
+	}
+	CMOS_WRITE(tm.tm_sec,  RTC_SECONDS);
+	CMOS_WRITE(tm.tm_min,  RTC_MINUTES);
+	CMOS_WRITE(tm.tm_hour, RTC_HOURS);
+	CMOS_WRITE(tm.tm_mon,  RTC_MONTH);
+	CMOS_WRITE(tm.tm_mday, RTC_DAY_OF_MONTH);
+	CMOS_WRITE(tm.tm_year, RTC_YEAR);
+
+	/* The following flags have to be released exactly in this order,
+	 * otherwise the DS12887 (popular MC146818A clone with integrated
+	 * battery and quartz) will not reset the oscillator and will not
+	 * update precisely 500 ms later. You won't find this mentioned in
+	 * the Dallas Semiconductor data sheets, but who believes data
+	 * sheets anyway ...                           -- Markus Kuhn
+	 */
+	CMOS_WRITE(save_control,     RTC_CONTROL);
+	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+	spin_unlock(&rtc_lock);
+
+	return 0;
+}
+
+__prep
+unsigned long mc146818_get_rtc_time(void)
+{
+	unsigned int year, mon, day, hour, min, sec;
+	int uip, i;
+
+	/* The Linux interpretation of the CMOS clock register contents:
+	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+	 * RTC registers show the second which has precisely just started.
+	 * Let's hope other operating systems interpret the RTC the same way.
+	 */
+
+	/* Since the UIP flag is set for about 2.2 ms and the clock
+	 * is typically written with a precision of 1 jiffy, trying
+	 * to obtain a precision better than a few milliseconds is 
+	 * an illusion. Only consistency is interesting, this also
+	 * allows to use the routine for /dev/rtc without a potential
+	 * 1 second kernel busy loop triggered by any reader of /dev/rtc. 
+	 */
+
+	for ( i = 0; i<1000000; i++) {
+		uip = CMOS_READ(RTC_FREQ_SELECT);
+		sec = CMOS_READ(RTC_SECONDS);
+		min = CMOS_READ(RTC_MINUTES);
+		hour = CMOS_READ(RTC_HOURS);
+		day = CMOS_READ(RTC_DAY_OF_MONTH);
+		mon = CMOS_READ(RTC_MONTH);
+		year = CMOS_READ(RTC_YEAR);
+		uip |= CMOS_READ(RTC_FREQ_SELECT);
+		if ((uip & RTC_UIP)==0) break;
+	}
+
+	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
+	    || RTC_ALWAYS_BCD)
+	{
+		BCD_TO_BIN(sec);
+		BCD_TO_BIN(min);
+		BCD_TO_BIN(hour);
+		BCD_TO_BIN(day);
+		BCD_TO_BIN(mon);
+		BCD_TO_BIN(year);
+	}
+	if ((year += 1900) < 1970)
+		year += 100;
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+__prep
+int mk48t59_set_rtc_time(unsigned long nowtime)
+{
+	unsigned char save_control;
+	struct rtc_time tm;
+
+	spin_lock(&rtc_lock);
+	to_tm(nowtime, &tm);
+
+	/* tell the clock it's being written */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			     (save_control | MK48T59_RTC_CA_WRITE));
+
+        tm.tm_year = (tm.tm_year - 1900) % 100;
+	BIN_TO_BCD(tm.tm_sec);
+	BIN_TO_BCD(tm.tm_min);
+	BIN_TO_BCD(tm.tm_hour);
+	BIN_TO_BCD(tm.tm_mon);
+	BIN_TO_BCD(tm.tm_mday);
+	BIN_TO_BCD(tm.tm_year);
+
+	ppc_md.nvram_write_val(MK48T59_RTC_SECONDS,      tm.tm_sec);
+	ppc_md.nvram_write_val(MK48T59_RTC_MINUTES,      tm.tm_min);
+	ppc_md.nvram_write_val(MK48T59_RTC_HOURS,        tm.tm_hour);
+	ppc_md.nvram_write_val(MK48T59_RTC_MONTH,        tm.tm_mon);
+	ppc_md.nvram_write_val(MK48T59_RTC_DAY_OF_MONTH, tm.tm_mday);
+	ppc_md.nvram_write_val(MK48T59_RTC_YEAR,         tm.tm_year);
+
+	/* Turn off the write bit. */
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+	spin_unlock(&rtc_lock);
+
+	return 0;
+}
+
+__prep
+unsigned long mk48t59_get_rtc_time(void)
+{
+	unsigned char save_control;
+	unsigned int year, mon, day, hour, min, sec;
+
+	/* Simple: freeze the clock, read it and allow updates again */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+	save_control &= ~MK48T59_RTC_CA_READ;
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+	/* Set the register to read the value. */
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			     (save_control | MK48T59_RTC_CA_READ));
+
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+	min = ppc_md.nvram_read_val(MK48T59_RTC_MINUTES);
+	hour = ppc_md.nvram_read_val(MK48T59_RTC_HOURS);
+	day = ppc_md.nvram_read_val(MK48T59_RTC_DAY_OF_MONTH);
+	mon = ppc_md.nvram_read_val(MK48T59_RTC_MONTH);
+	year = ppc_md.nvram_read_val(MK48T59_RTC_YEAR);
+
+	/* Let the time values change again. */
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+	BCD_TO_BIN(sec);
+	BCD_TO_BIN(min);
+	BCD_TO_BIN(hour);
+	BCD_TO_BIN(day);
+	BCD_TO_BIN(mon);
+	BCD_TO_BIN(year);
+
+	year = year + 1900;
+	if (year < 1970) {
+		year += 100;
+	}
+
+	return mktime(year, mon, day, hour, min, sec);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/proc_rtas.c linux-2.4.20/arch/ppc/platforms/proc_rtas.c
--- linux-2.4.19/arch/ppc/platforms/proc_rtas.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/proc_rtas.c	2002-10-29 11:18:51.000000000 +0000
@@ -0,0 +1,787 @@
+/*
+ * BK Id: SCCS/s.proc_rtas.c 1.5 05/17/01 18:14:22 cort
+ */
+/*
+ *   arch/ppc/kernel/proc_rtas.c
+ *   Copyright (C) 2000 Tilmann Bitterberg
+ *   (tilmann@bitterberg.de)
+ *
+ *   RTAS (Runtime Abstraction Services) stuff
+ *   Intention is to provide a clean user interface
+ *   to use the RTAS.
+ *
+ *   TODO:
+ *   Split off a header file and maybe move it to a different
+ *   location. Write Documentation on what the /proc/rtas/ entries
+ *   actually do.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/ctype.h>
+#include <linux/time.h>
+#include <linux/string.h>
+
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/machdep.h> /* for ppc_md */
+#include <asm/time.h>
+
+/* Token for Sensors */
+#define KEY_SWITCH		0x0001
+#define ENCLOSURE_SWITCH	0x0002
+#define THERMAL_SENSOR		0x0003
+#define LID_STATUS		0x0004
+#define POWER_SOURCE		0x0005
+#define BATTERY_VOLTAGE		0x0006
+#define BATTERY_REMAINING	0x0007
+#define BATTERY_PERCENTAGE	0x0008
+#define EPOW_SENSOR		0x0009
+#define BATTERY_CYCLESTATE	0x000a
+#define BATTERY_CHARGING	0x000b
+
+/* IBM specific sensors */
+#define IBM_SURVEILLANCE	0x2328 /* 9000 */
+#define IBM_FANRPM		0x2329 /* 9001 */
+#define IBM_VOLTAGE		0x232a /* 9002 */
+#define IBM_DRCONNECTOR		0x232b /* 9003 */
+#define IBM_POWERSUPPLY		0x232c /* 9004 */
+#define IBM_INTQUEUE		0x232d /* 9005 */
+
+/* Status return values */
+#define SENSOR_CRITICAL_HIGH	13
+#define SENSOR_WARNING_HIGH	12
+#define SENSOR_NORMAL		11
+#define SENSOR_WARNING_LOW	10
+#define SENSOR_CRITICAL_LOW	 9
+#define SENSOR_SUCCESS		 0
+#define SENSOR_HW_ERROR		-1
+#define SENSOR_BUSY		-2
+#define SENSOR_NOT_EXIST	-3
+#define SENSOR_DR_ENTITY	-9000
+
+/* Location Codes */
+#define LOC_SCSI_DEV_ADDR	'A'
+#define LOC_SCSI_DEV_LOC	'B'
+#define LOC_CPU			'C'
+#define LOC_DISKETTE		'D'
+#define LOC_ETHERNET		'E'
+#define LOC_FAN			'F'
+#define LOC_GRAPHICS		'G'
+/* reserved / not used		'H' */
+#define LOC_IO_ADAPTER		'I'
+/* reserved / not used		'J' */
+#define LOC_KEYBOARD		'K'
+#define LOC_LCD			'L'
+#define LOC_MEMORY		'M'
+#define LOC_NV_MEMORY		'N'
+#define LOC_MOUSE		'O'
+#define LOC_PLANAR		'P'
+#define LOC_OTHER_IO		'Q'
+#define LOC_PARALLEL		'R'
+#define LOC_SERIAL		'S'
+#define LOC_DEAD_RING		'T'
+#define LOC_RACKMOUNTED		'U' /* for _u_nit is rack mounted */
+#define LOC_VOLTAGE		'V'
+#define LOC_SWITCH_ADAPTER	'W'
+#define LOC_OTHER		'X'
+#define LOC_FIRMWARE		'Y'
+#define LOC_SCSI		'Z'
+
+/* Tokens for indicators */
+#define TONE_FREQUENCY		0x0001 /* 0 - 1000 (HZ)*/
+#define TONE_VOLUME		0x0002 /* 0 - 100 (%) */
+#define SYSTEM_POWER_STATE	0x0003 
+#define WARNING_LIGHT		0x0004
+#define DISK_ACTIVITY_LIGHT	0x0005
+#define HEX_DISPLAY_UNIT	0x0006
+#define BATTERY_WARNING_TIME	0x0007
+#define CONDITION_CYCLE_REQUEST	0x0008
+#define SURVEILLANCE_INDICATOR	0x2328 /* 9000 */
+#define DR_ACTION		0x2329 /* 9001 */
+#define DR_INDICATOR		0x232a /* 9002 */
+/* 9003 - 9004: Vendor specific */
+#define GLOBAL_INTERRUPT_QUEUE	0x232d /* 9005 */
+/* 9006 - 9999: Vendor specific */
+
+/* other */
+#define MAX_SENSORS		 17  /* I only know of 17 sensors */    
+#define MAX_LINELENGTH          256
+#define SENSOR_PREFIX		"ibm,sensor-"
+#define cel_to_fahr(x)		((x*9/5)+32)
+
+
+/* Globals */
+static struct proc_dir_entry *proc_rtas;
+static struct rtas_sensors sensors;
+static struct device_node *rtas;
+static unsigned long power_on_time = 0; /* Save the time the user set */
+static char progress_led[MAX_LINELENGTH];
+
+static unsigned long rtas_tone_frequency = 1000;
+static unsigned long rtas_tone_volume = 0;
+
+/* ****************STRUCTS******************************************* */
+struct individual_sensor {
+	unsigned int token;
+	unsigned int quant;
+};
+
+struct rtas_sensors {
+        struct individual_sensor sensor[MAX_SENSORS];
+	unsigned int quant;
+};
+
+/* ****************************************************************** */
+/* Declarations */
+static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off,
+		int count, int *eof, void *data);
+static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, 
+		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, 
+		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_progress_read(struct file * file, char * buf,
+		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf,
+		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf,
+		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf,
+		size_t count, loff_t *ppos);
+
+static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf,
+		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf,
+		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf,
+		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
+		size_t count, loff_t *ppos);
+
+struct file_operations ppc_rtas_poweron_operations = {
+	read:		ppc_rtas_poweron_read,
+	write:		ppc_rtas_poweron_write
+};
+struct file_operations ppc_rtas_progress_operations = {
+	read:		ppc_rtas_progress_read,
+	write:		ppc_rtas_progress_write
+};
+
+struct file_operations ppc_rtas_clock_operations = {
+	read:		ppc_rtas_clock_read,
+	write:		ppc_rtas_clock_write
+};
+
+struct file_operations ppc_rtas_tone_freq_operations = {
+	read:		ppc_rtas_tone_freq_read,
+	write:		ppc_rtas_tone_freq_write
+};
+struct file_operations ppc_rtas_tone_volume_operations = {
+	read:		ppc_rtas_tone_volume_read,
+	write:		ppc_rtas_tone_volume_write
+};
+
+int ppc_rtas_find_all_sensors (void);
+int ppc_rtas_process_sensor(struct individual_sensor s, int state, 
+		int error, char * buf);
+char * ppc_rtas_process_error(int error);
+int get_location_code(struct individual_sensor s, char * buf);
+int check_location_string (char *c, char * buf);
+int check_location (char *c, int idx, char * buf);
+
+/* ****************************************************************** */
+/* MAIN                                                               */
+/* ****************************************************************** */
+void proc_rtas_init(void)
+{
+	struct proc_dir_entry *entry;
+
+	rtas = find_devices("rtas");
+	if ((rtas == 0) || (_machine != _MACH_chrp)) {
+		return;
+	}
+	
+	proc_rtas = proc_mkdir("rtas", 0);
+	if (proc_rtas == 0)
+		return;
+
+	/* /proc/rtas entries */
+
+	entry = create_proc_entry("progress", S_IRUGO|S_IWUSR, proc_rtas);
+	if (entry) entry->proc_fops = &ppc_rtas_progress_operations;
+
+	entry = create_proc_entry("clock", S_IRUGO|S_IWUSR, proc_rtas); 
+	if (entry) entry->proc_fops = &ppc_rtas_clock_operations;
+
+	entry = create_proc_entry("poweron", S_IWUSR|S_IRUGO, proc_rtas); 
+	if (entry) entry->proc_fops = &ppc_rtas_poweron_operations;
+
+	create_proc_read_entry("sensors", S_IRUGO, proc_rtas, 
+			ppc_rtas_sensor_read, NULL);
+	
+	entry = create_proc_entry("frequency", S_IWUSR|S_IRUGO, proc_rtas); 
+	if (entry) entry->proc_fops = &ppc_rtas_tone_freq_operations;
+
+	entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, proc_rtas); 
+	if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations;
+}
+
+/* ****************************************************************** */
+/* POWER-ON-TIME                                                      */
+/* ****************************************************************** */
+static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf,
+		size_t count, loff_t *ppos)
+{
+	struct rtc_time tm;
+	unsigned long nowtime;
+	char *dest;
+	int error;
+
+	nowtime = simple_strtoul(buf, &dest, 10);
+	if (*dest != '\0' && *dest != '\n') {
+		printk("ppc_rtas_poweron_write: Invalid time\n");
+		return count;
+	}
+	power_on_time = nowtime; /* save the time */
+
+	to_tm(nowtime, &tm);
+
+	error = call_rtas("set-time-for-power-on", 7, 1, NULL, 
+			tm.tm_year, tm.tm_mon, tm.tm_mday, 
+			tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */);
+	if (error != 0)
+		printk(KERN_WARNING "error: setting poweron time returned: %s\n", 
+				ppc_rtas_process_error(error));
+	return count;
+}
+/* ****************************************************************** */
+static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf,
+		size_t count, loff_t *ppos)
+{
+	int n;
+	if (power_on_time == 0)
+		n = sprintf(buf, "Power on time not set\n");
+	else
+		n = sprintf(buf, "%lu\n", power_on_time);
+
+	if (*ppos >= strlen(buf))
+		return 0;
+	if (n > strlen(buf) - *ppos)
+		n = strlen(buf) - *ppos;
+	if (n > count)
+		n = count;
+	*ppos += n;
+	return n;
+}
+
+/* ****************************************************************** */
+/* PROGRESS                                                           */
+/* ****************************************************************** */
+static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf,
+		size_t count, loff_t *ppos)
+{
+	unsigned long hex;
+
+	strcpy(progress_led, buf); /* save the string */
+	/* Lets see if the user passed hexdigits */
+	hex = simple_strtoul(buf, NULL, 10);
+	
+	ppc_md.progress ((char *)buf, hex);
+	return count;
+
+	/* clear the line */ /* ppc_md.progress("                   ", 0xffff);*/
+}
+/* ****************************************************************** */
+static ssize_t ppc_rtas_progress_read(struct file * file, char * buf,
+		size_t count, loff_t *ppos)
+{
+	int n = 0;
+	if (progress_led != NULL)
+		n = sprintf (buf, "%s\n", progress_led);
+	if (*ppos >= strlen(buf))
+		return 0;
+	if (n > strlen(buf) - *ppos)
+		n = strlen(buf) - *ppos;
+	if (n > count)
+		n = count;
+	*ppos += n;
+	return n;
+}
+
+/* ****************************************************************** */
+/* CLOCK                                                              */
+/* ****************************************************************** */
+static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, 
+		size_t count, loff_t *ppos)
+{
+	struct rtc_time tm;
+	unsigned long nowtime;
+	char *dest;
+	int error;
+
+	nowtime = simple_strtoul(buf, &dest, 10);
+	if (*dest != '\0' && *dest != '\n') {
+		printk("ppc_rtas_clock_write: Invalid time\n");
+		return count;
+	}
+
+	to_tm(nowtime, &tm);
+	error = call_rtas("set-time-of-day", 7, 1, NULL, 
+			tm.tm_year, tm.tm_mon, tm.tm_mday, 
+			tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
+	if (error != 0)
+		printk(KERN_WARNING "error: setting the clock returned: %s\n", 
+				ppc_rtas_process_error(error));
+	return count;
+}
+/* ****************************************************************** */
+static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, 
+		size_t count, loff_t *ppos)
+{
+	unsigned int year, mon, day, hour, min, sec;
+	unsigned long *ret = kmalloc(4*8, GFP_KERNEL);
+	int n, error;
+
+	error = call_rtas("get-time-of-day", 0, 8, ret);
+	
+	year = ret[0]; mon  = ret[1]; day  = ret[2];
+	hour = ret[3]; min  = ret[4]; sec  = ret[5];
+
+	if (error != 0){
+		printk(KERN_WARNING "error: reading the clock returned: %s\n", 
+				ppc_rtas_process_error(error));
+		n = sprintf (buf, "0");
+	} else { 
+		n = sprintf (buf, "%lu\n", mktime(year, mon, day, hour, min, sec));
+	}
+	kfree(ret);
+
+	if (*ppos >= strlen(buf))
+		return 0;
+	if (n > strlen(buf) - *ppos)
+		n = strlen(buf) - *ppos;
+	if (n > count)
+		n = count;
+	*ppos += n;
+	return n;
+}
+
+/* ****************************************************************** */
+/* SENSOR STUFF                                                       */
+/* ****************************************************************** */
+static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off,
+		int count, int *eof, void *data)
+{
+	int i,j,n;
+	unsigned long ret;
+	int state, error;
+	char buffer[MAX_LINELENGTH*MAX_SENSORS]; /* May not be enough */
+
+	if (count < 0)
+		return -EINVAL;
+
+	n  = sprintf ( buffer  , "RTAS (RunTime Abstraction Services) Sensor Information\n");
+	n += sprintf ( buffer+n, "Sensor\t\tValue\t\tCondition\tLocation\n");
+	n += sprintf ( buffer+n, "********************************************************\n");
+
+	if (ppc_rtas_find_all_sensors() != 0) {
+		n += sprintf ( buffer+n, "\nNo sensors are available\n");
+		goto return_string;
+	}
+
+	for (i=0; i<sensors.quant; i++) {
+		j = sensors.sensor[i].quant;
+		/* A sensor may have multiple instances */
+		while (j >= 0) {
+			error =	call_rtas("get-sensor-state", 2, 2, &ret, 
+				  sensors.sensor[i].token, sensors.sensor[i].quant-j);
+			state = (int) ret;
+			n += ppc_rtas_process_sensor(sensors.sensor[i], state, error, buffer+n );
+			n += sprintf (buffer+n, "\n");
+			j--;
+		} /* while */
+	} /* for */
+
+return_string:
+	if (off >= strlen(buffer)) {
+		*eof = 1;
+		return 0;
+	}
+	if (n > strlen(buffer) - off)
+		n = strlen(buffer) - off;
+	if (n > count)
+		n = count;
+	else
+		*eof = 1;
+	memcpy(buf, buffer + off, n);
+	*start = buf;
+	return n;
+}
+
+/* ****************************************************************** */
+
+int ppc_rtas_find_all_sensors (void)
+{
+	unsigned long *utmp;
+	int len, i, j;
+
+	utmp = (unsigned long *) get_property(rtas, "rtas-sensors", &len);
+	if (utmp == NULL) {
+		printk (KERN_ERR "error: could not get rtas-sensors\n");
+		return 1;
+	}
+
+	sensors.quant = len / 8;      /* int + int */
+
+	for (i=0, j=0; j<sensors.quant; i+=2, j++) {
+		sensors.sensor[j].token = utmp[i];
+		sensors.sensor[j].quant = utmp[i+1];
+	}
+	return 0;
+}
+
+/* ****************************************************************** */
+/*
+ * Builds a string of what rtas returned
+ */
+char * ppc_rtas_process_error(int error)
+{
+	switch (error) {
+		case SENSOR_CRITICAL_HIGH:
+			return "(critical high)";
+		case SENSOR_WARNING_HIGH:
+			return "(warning high)";
+		case SENSOR_NORMAL:
+			return "(normal)";
+		case SENSOR_WARNING_LOW:
+			return "(warning low)";
+		case SENSOR_CRITICAL_LOW:
+			return "(critical low)";
+		case SENSOR_SUCCESS:
+			return "(read ok)";
+		case SENSOR_HW_ERROR:
+			return "(hardware error)";
+		case SENSOR_BUSY:
+			return "(busy)";
+		case SENSOR_NOT_EXIST:
+			return "(non existant)";
+		case SENSOR_DR_ENTITY:
+			return "(dr entity removed)";
+		default:
+			return "(UNKNOWN)";
+	}
+}
+
+/* ****************************************************************** */
+/*
+ * Builds a string out of what the sensor said
+ */
+
+int ppc_rtas_process_sensor(struct individual_sensor s, int state, 
+		int error, char * buf) 
+{
+	/* Defined return vales */
+	const char * key_switch[]        = { "Off\t", "Normal\t", "Secure\t", "Mainenance" };
+	const char * enclosure_switch[]  = { "Closed", "Open" };
+	const char * lid_status[]        = { " ", "Open", "Closed" };
+	const char * power_source[]      = { "AC\t", "Battery", "AC & Battery" };
+	const char * battery_remaining[] = { "Very Low", "Low", "Mid", "High" };
+	const char * epow_sensor[]       = { 
+		"EPOW Reset", "Cooling warning", "Power warning",
+		"System shutdown", "System halt", "EPOW main enclosure",
+		"EPOW power off" };
+	const char * battery_cyclestate[]  = { "None", "In progress", "Requested" };
+	const char * battery_charging[]    = { "Charging", "Discharching", "No current flow" };
+	const char * ibm_drconnector[]     = { "Empty", "Present" };
+	const char * ibm_intqueue[]        = { "Disabled", "Enabled" };
+
+	int have_strings = 0;
+	int temperature = 0;
+	int unknown = 0;
+	int n = 0;
+
+	/* What kind of sensor do we have here? */
+	switch (s.token) {
+		case KEY_SWITCH:
+			n += sprintf(buf+n, "Key switch:\t");
+			n += sprintf(buf+n, "%s\t", key_switch[state]);
+			have_strings = 1;
+			break;
+		case ENCLOSURE_SWITCH:
+			n += sprintf(buf+n, "Enclosure switch:\t");
+			n += sprintf(buf+n, "%s\t", enclosure_switch[state]);
+			have_strings = 1;
+			break;
+		case THERMAL_SENSOR:
+			n += sprintf(buf+n, "Temp. (C/F):\t");
+			temperature = 1;
+			break;
+		case LID_STATUS:
+			n += sprintf(buf+n, "Lid status:\t");
+			n += sprintf(buf+n, "%s\t", lid_status[state]);
+			have_strings = 1;
+			break;
+		case POWER_SOURCE:
+			n += sprintf(buf+n, "Power source:\t");
+			n += sprintf(buf+n, "%s\t", power_source[state]);
+			have_strings = 1;
+			break;
+		case BATTERY_VOLTAGE:
+			n += sprintf(buf+n, "Battery voltage:\t");
+			break;
+		case BATTERY_REMAINING:
+			n += sprintf(buf+n, "Battery remaining:\t");
+			n += sprintf(buf+n, "%s\t", battery_remaining[state]);
+			have_strings = 1;
+			break;
+		case BATTERY_PERCENTAGE:
+			n += sprintf(buf+n, "Battery percentage:\t");
+			break;
+		case EPOW_SENSOR:
+			n += sprintf(buf+n, "EPOW Sensor:\t");
+			n += sprintf(buf+n, "%s\t", epow_sensor[state]);
+			have_strings = 1;
+			break;
+		case BATTERY_CYCLESTATE:
+			n += sprintf(buf+n, "Battery cyclestate:\t");
+			n += sprintf(buf+n, "%s\t", battery_cyclestate[state]);
+			have_strings = 1;
+			break;
+		case BATTERY_CHARGING:
+			n += sprintf(buf+n, "Battery Charging:\t");
+			n += sprintf(buf+n, "%s\t", battery_charging[state]);
+			have_strings = 1;
+			break;
+		case IBM_SURVEILLANCE:
+			n += sprintf(buf+n, "Surveillance:\t");
+			break;
+		case IBM_FANRPM:
+			n += sprintf(buf+n, "Fan (rpm):\t");
+			break;
+		case IBM_VOLTAGE:
+			n += sprintf(buf+n, "Voltage (mv):\t");
+			break;
+		case IBM_DRCONNECTOR:
+			n += sprintf(buf+n, "DR connector:\t");
+			n += sprintf(buf+n, "%s\t", ibm_drconnector[state]);
+			have_strings = 1;
+			break;
+		case IBM_POWERSUPPLY:
+			n += sprintf(buf+n, "Powersupply:\t");
+			break;
+		case IBM_INTQUEUE:
+			n += sprintf(buf+n, "Interrupt queue:\t");
+			n += sprintf(buf+n, "%s\t", ibm_intqueue[state]);
+			have_strings = 1;
+			break;
+		default:
+			n += sprintf(buf+n,  "Unkown sensor (type %d), ignoring it\n",
+					s.token);
+			unknown = 1;
+			have_strings = 1;
+			break;
+	}
+	if (have_strings == 0) {
+		if (temperature) {
+			n += sprintf(buf+n, "%4d /%4d\t", state, cel_to_fahr(state));
+		} else
+			n += sprintf(buf+n, "%10d\t", state);
+	}
+	if (unknown == 0) {
+		n += sprintf ( buf+n, "%s\t", ppc_rtas_process_error(error));
+		n += get_location_code(s, buf+n);
+	}
+	return n;
+}
+
+/* ****************************************************************** */
+
+int check_location (char *c, int idx, char * buf)
+{
+	int n = 0;
+
+	switch (*(c+idx)) {
+		case LOC_PLANAR:
+			n += sprintf ( buf, "Planar #%c", *(c+idx+1));
+			break;
+		case LOC_CPU:
+			n += sprintf ( buf, "CPU #%c", *(c+idx+1));
+			break;
+		case LOC_FAN:
+			n += sprintf ( buf, "Fan #%c", *(c+idx+1));
+			break;
+		case LOC_RACKMOUNTED:
+			n += sprintf ( buf, "Rack #%c", *(c+idx+1));
+			break;
+		case LOC_VOLTAGE:
+			n += sprintf ( buf, "Voltage #%c", *(c+idx+1));
+			break;
+		case LOC_LCD:
+			n += sprintf ( buf, "LCD #%c", *(c+idx+1));
+			break;
+		case '.':
+			n += sprintf ( buf, "- %c", *(c+idx+1));
+		default:
+			n += sprintf ( buf, "Unknown location");
+			break;
+	}
+	return n;
+}
+
+
+/* ****************************************************************** */
+/* 
+ * Format: 
+ * ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ]
+ * the '.' may be an abbrevation
+ */
+int check_location_string (char *c, char *buf)
+{
+	int n=0,i=0;
+
+	while (c[i]) {
+		if (isalpha(c[i]) || c[i] == '.') {
+			 n += check_location(c, i, buf+n);
+		}
+		else if (c[i] == '/' || c[i] == '-')
+			n += sprintf(buf+n, " at ");
+		i++;
+	}
+	return n;
+}
+
+
+/* ****************************************************************** */
+
+int get_location_code(struct individual_sensor s, char * buffer)
+{
+	char rstr[512], tmp[10], tmp2[10];
+	int n=0, i=0, llen, len;
+	/* char *buf = kmalloc(MAX_LINELENGTH, GFP_KERNEL); */
+	char *ret;
+
+	static int pos = 0; /* remember position where buffer was */
+
+	/* construct the sensor number like 0003 */
+	/* fill with zeros */
+	n = sprintf(tmp, "%d", s.token);
+	len = strlen(tmp);
+	while (strlen(tmp) < 4)
+		n += sprintf (tmp+n, "0");
+	
+	/* invert the string */
+	while (tmp[i]) {
+		if (i<len)
+			tmp2[4-len+i] = tmp[i];
+		else
+			tmp2[3-i] = tmp[i];
+		i++;
+	}
+	tmp2[4] = '\0';
+
+	sprintf (rstr, SENSOR_PREFIX"%s", tmp2);
+
+	ret = (char *) get_property(rtas, rstr, &llen);
+
+	n=0;
+	if (ret[0] == '\0')
+		n += sprintf ( buffer+n, "--- ");/* does not have a location */
+	else {
+		char t[50];
+		ret += pos;
+
+		n += check_location_string(ret, buffer + n);
+		n += sprintf ( buffer+n, " ");
+		/* see how many characters we have printed */
+		sprintf ( t, "%s ", ret);
+
+		pos += strlen(t);
+		if (pos >= llen) pos=0;
+	}
+	return n;
+}
+/* ****************************************************************** */
+/* INDICATORS - Tone Frequency                                        */
+/* ****************************************************************** */
+static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf,
+		size_t count, loff_t *ppos)
+{
+	unsigned long freq;
+	char *dest;
+	int error;
+	freq = simple_strtoul(buf, &dest, 10);
+	if (*dest != '\0' && *dest != '\n') {
+		printk("ppc_rtas_tone_freq_write: Invalid tone freqency\n");
+		return count;
+	}
+	if (freq < 0) freq = 0;
+	rtas_tone_frequency = freq; /* save it for later */
+	error = call_rtas("set-indicator", 3, 1, NULL,
+			TONE_FREQUENCY, 0, freq);
+	if (error != 0)
+		printk(KERN_WARNING "error: setting tone frequency returned: %s\n", 
+				ppc_rtas_process_error(error));
+	return count;
+}
+/* ****************************************************************** */
+static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf,
+		size_t count, loff_t *ppos)
+{
+	int n;
+	n = sprintf(buf, "%lu\n", rtas_tone_frequency);
+
+	if (*ppos >= strlen(buf))
+		return 0;
+	if (n > strlen(buf) - *ppos)
+		n = strlen(buf) - *ppos;
+	if (n > count)
+		n = count;
+	*ppos += n;
+	return n;
+}
+/* ****************************************************************** */
+/* INDICATORS - Tone Volume                                           */
+/* ****************************************************************** */
+static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf,
+		size_t count, loff_t *ppos)
+{
+	unsigned long volume;
+	char *dest;
+	int error;
+	volume = simple_strtoul(buf, &dest, 10);
+	if (*dest != '\0' && *dest != '\n') {
+		printk("ppc_rtas_tone_volume_write: Invalid tone volume\n");
+		return count;
+	}
+	if (volume < 0) volume = 0;
+	if (volume > 100) volume = 100;
+	
+        rtas_tone_volume = volume; /* save it for later */
+	error = call_rtas("set-indicator", 3, 1, NULL,
+			TONE_VOLUME, 0, volume);
+	if (error != 0)
+		printk(KERN_WARNING "error: setting tone volume returned: %s\n", 
+				ppc_rtas_process_error(error));
+	return count;
+}
+/* ****************************************************************** */
+static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
+		size_t count, loff_t *ppos)
+{
+	int n;
+	n = sprintf(buf, "%lu\n", rtas_tone_volume);
+
+	if (*ppos >= strlen(buf))
+		return 0;
+	if (n > strlen(buf) - *ppos)
+		n = strlen(buf) - *ppos;
+	if (n > count)
+		n = count;
+	*ppos += n;
+	return n;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/residual.c linux-2.4.20/arch/ppc/platforms/residual.c
--- linux-2.4.19/arch/ppc/platforms/residual.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/residual.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,913 @@
+/*
+ * BK Id: SCCS/s.residual.c 1.15 02/05/02 18:08:35 trini
+ */
+/*
+ * Code to deal with the PReP residual data.
+ *
+ * Written by: Cort Dougan (cort@cs.nmt.edu)
+ * Improved _greatly_ and rewritten by Gabriel Paubert (paubert@iram.es)
+ *
+ *  This file is based on the following documentation:
+ *
+ *	IBM Power Personal Systems Architecture
+ *	Residual Data
+ * 	Document Number: PPS-AR-FW0001
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive
+ *  for more details.
+ *
+ */
+
+#include <linux/string.h>
+#include <asm/residual.h>
+#include <asm/pnp.h>
+#include <asm/byteorder.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/sections.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+
+
+unsigned char __res[sizeof(RESIDUAL)] __prepdata = {0,};
+RESIDUAL *res = (RESIDUAL *)&__res;
+
+char * PnP_BASE_TYPES[] __initdata = {
+  "Reserved",
+  "MassStorageDevice",
+  "NetworkInterfaceController",
+  "DisplayController",
+  "MultimediaController",
+  "MemoryController",
+  "BridgeController",
+  "CommunicationsDevice",
+  "SystemPeripheral",
+  "InputDevice",
+  "ServiceProcessor"
+  };
+
+/* Device Sub Type Codes */
+
+unsigned char * PnP_SUB_TYPES[] __initdata = {
+  "\001\000SCSIController",
+  "\001\001IDEController",
+  "\001\002FloppyController",
+  "\001\003IPIController",
+  "\001\200OtherMassStorageController",
+  "\002\000EthernetController",
+  "\002\001TokenRingController",
+  "\002\002FDDIController",
+  "\002\0x80OtherNetworkController",
+  "\003\000VGAController",
+  "\003\001SVGAController",
+  "\003\002XGAController",
+  "\003\200OtherDisplayController",
+  "\004\000VideoController",
+  "\004\001AudioController",
+  "\004\200OtherMultimediaController",
+  "\005\000RAM",
+  "\005\001FLASH",
+  "\005\200OtherMemoryDevice",
+  "\006\000HostProcessorBridge",
+  "\006\001ISABridge",
+  "\006\002EISABridge",
+  "\006\003MicroChannelBridge",
+  "\006\004PCIBridge",
+  "\006\005PCMCIABridge",
+  "\006\006VMEBridge",
+  "\006\200OtherBridgeDevice",
+  "\007\000RS232Device",
+  "\007\001ATCompatibleParallelPort",
+  "\007\200OtherCommunicationsDevice",
+  "\010\000ProgrammableInterruptController",
+  "\010\001DMAController",
+  "\010\002SystemTimer",
+  "\010\003RealTimeClock",
+  "\010\004L2Cache",
+  "\010\005NVRAM",
+  "\010\006PowerManagement",
+  "\010\007CMOS",
+  "\010\010OperatorPanel",
+  "\010\011ServiceProcessorClass1",
+  "\010\012ServiceProcessorClass2",
+  "\010\013ServiceProcessorClass3",
+  "\010\014GraphicAssist",
+  "\010\017SystemPlanar",
+  "\010\200OtherSystemPeripheral",
+  "\011\000KeyboardController",
+  "\011\001Digitizer",
+  "\011\002MouseController",
+  "\011\003TabletController",
+  "\011\0x80OtherInputController",
+  "\012\000GeneralMemoryController",
+  NULL
+};
+
+/* Device Interface Type Codes */
+
+unsigned char * PnP_INTERFACES[] __initdata = {
+  "\000\000\000General",
+  "\001\000\000GeneralSCSI",
+  "\001\001\000GeneralIDE",
+  "\001\001\001ATACompatible",
+
+  "\001\002\000GeneralFloppy",
+  "\001\002\001Compatible765",
+  "\001\002\002NS398_Floppy",         /* NS Super I/O wired to use index
+                                         register at port 398 and data
+                                         register at port 399               */
+  "\001\002\003NS26E_Floppy",         /* Ports 26E and 26F                  */
+  "\001\002\004NS15C_Floppy",         /* Ports 15C and 15D                  */
+  "\001\002\005NS2E_Floppy",          /* Ports 2E and 2F                    */
+  "\001\002\006CHRP_Floppy",          /* CHRP Floppy in PR*P system         */
+
+  "\001\003\000GeneralIPI",
+  
+  "\002\000\000GeneralEther",
+  "\002\001\000GeneralToken",
+  "\002\002\000GeneralFDDI",
+  
+  "\003\000\000GeneralVGA",
+  "\003\001\000GeneralSVGA",
+  "\003\002\000GeneralXGA",
+  
+  "\004\000\000GeneralVideo",
+  "\004\001\000GeneralAudio",
+  "\004\001\001CS4232Audio",            /* CS 4232 Plug 'n Play Configured    */
+
+  "\005\000\000GeneralRAM",
+  /* This one is obviously wrong ! */
+  "\005\000\000PCIMemoryController",    /* PCI Config Method                  */
+  "\005\000\001RS6KMemoryController",   /* RS6K Config Method                 */
+  "\005\001\000GeneralFLASH",
+  
+  "\006\000\000GeneralHostBridge",
+  "\006\001\000GeneralISABridge",
+  "\006\002\000GeneralEISABridge",
+  "\006\003\000GeneralMCABridge",
+  /* GeneralPCIBridge = 0, */
+  "\006\004\000PCIBridgeDirect",
+  "\006\004\001PCIBridgeIndirect",
+  "\006\004\002PCIBridgeRS6K",
+  "\006\005\000GeneralPCMCIABridge",
+  "\006\006\000GeneralVMEBridge",
+  
+  "\007\000\000GeneralRS232",
+  "\007\000\001COMx",
+  "\007\000\002Compatible16450",
+  "\007\000\003Compatible16550",
+  "\007\000\004NS398SerPort",         /* NS Super I/O wired to use index
+                                         register at port 398 and data
+                                         register at port 399               */
+  "\007\000\005NS26ESerPort",         /* Ports 26E and 26F                  */
+  "\007\000\006NS15CSerPort",         /* Ports 15C and 15D                  */
+  "\007\000\007NS2ESerPort",          /* Ports 2E and 2F                    */
+
+  "\007\001\000GeneralParPort",
+  "\007\001\001LPTx",
+  "\007\001\002NS398ParPort",         /* NS Super I/O wired to use index
+                                         register at port 398 and data
+                                         register at port 399               */
+  "\007\001\003NS26EParPort",         /* Ports 26E and 26F                  */
+  "\007\001\004NS15CParPort",         /* Ports 15C and 15D                  */
+  "\007\001\005NS2EParPort",          /* Ports 2E and 2F                    */
+  
+  "\010\000\000GeneralPIC",
+  "\010\000\001ISA_PIC",
+  "\010\000\002EISA_PIC",
+  "\010\000\003MPIC",
+  "\010\000\004RS6K_PIC",
+
+  "\010\001\000GeneralDMA",
+  "\010\001\001ISA_DMA",
+  "\010\001\002EISA_DMA",
+
+  "\010\002\000GeneralTimer",
+  "\010\002\001ISA_Timer",
+  "\010\002\002EISA_Timer",
+  "\010\003\000GeneralRTC",
+  "\010\003\001ISA_RTC",
+  
+  "\010\004\001StoreThruOnly",
+  "\010\004\002StoreInEnabled",
+  "\010\004\003RS6KL2Cache",
+
+  "\010\005\000IndirectNVRAM",        /* Indirectly addressed               */
+  "\010\005\001DirectNVRAM",          /* Memory Mapped                      */
+  "\010\005\002IndirectNVRAM24",      /* Indirectly addressed - 24 bit      */
+
+  "\010\006\000GeneralPowerManagement",
+  "\010\006\001EPOWPowerManagement",
+  "\010\006\002PowerControl",         // d1378
+  
+  "\010\007\000GeneralCMOS",
+
+  "\010\010\000GeneralOPPanel",
+  "\010\010\001HarddiskLight",
+  "\010\010\002CDROMLight",
+  "\010\010\003PowerLight",
+  "\010\010\004KeyLock",
+  "\010\010\005ANDisplay",            /* AlphaNumeric Display               */
+  "\010\010\006SystemStatusLED",      /* 3 digit 7 segment LED              */
+  "\010\010\007CHRP_SystemStatusLED", /* CHRP LEDs in PR*P system           */
+
+  "\010\011\000GeneralServiceProcessor",
+  "\010\012\000GeneralServiceProcessor",
+  "\010\013\000GeneralServiceProcessor",
+  
+  "\010\014\001TransferData",
+  "\010\014\002IGMC32",
+  "\010\014\003IGMC64",
+  
+  "\010\017\000GeneralSystemPlanar",   /* 10/5/95                            */
+  NULL
+  };
+
+static const unsigned char __init *PnP_SUB_TYPE_STR(unsigned char BaseType, 
+					     unsigned char SubType) {
+	unsigned char ** s=PnP_SUB_TYPES;
+	while (*s && !((*s)[0]==BaseType 
+		       && (*s)[1]==SubType)) s++;
+	if (*s) return *s+2;
+	else return("Unknown !");
+};
+
+static const unsigned char __init *PnP_INTERFACE_STR(unsigned char BaseType, 
+					      unsigned char SubType,
+					      unsigned char Interface) {
+	unsigned char ** s=PnP_INTERFACES;
+	while (*s && !((*s)[0]==BaseType 
+		       && (*s)[1]==SubType 
+		       && (*s)[2]==Interface)) s++;
+	if (*s) return *s+3;
+	else return NULL;
+};
+
+static void __init printsmallvendor(PnP_TAG_PACKET *pkt, int size) {
+	int i, c;
+	char decomp[4];
+#define p pkt->S14_Pack.S14_Data.S14_PPCPack
+	switch(p.Type) {
+	case 1:
+	  /* Decompress first 3 chars */
+	  c = *(unsigned short *)p.PPCData;
+	  decomp[0]='A'-1+((c>>10)&0x1F);
+	  decomp[1]='A'-1+((c>>5)&0x1F);
+	  decomp[2]='A'-1+(c&0x1F);
+	  decomp[3]=0;
+	  printk("    Chip identification: %s%4.4X\n",
+		 decomp, ld_le16((unsigned short *)(p.PPCData+2)));
+	  break;
+	default:
+	  printk("    Small vendor item type 0x%2.2x, data (hex): ",
+		 p.Type);
+	  for(i=0; i<size-2; i++) printk("%2.2x ", p.PPCData[i]);
+	  printk("\n");
+	  break;
+	}
+#undef p
+}
+
+static void __init printsmallpacket(PnP_TAG_PACKET * pkt, int size) {
+	static const unsigned char * intlevel[] = {"high", "low"};
+	static const unsigned char * intsense[] = {"edge", "level"};
+
+	switch (tag_small_item_name(pkt->S1_Pack.Tag)) {
+	case PnPVersion:
+	  printk("    PnPversion 0x%x.%x\n", 
+		 pkt->S1_Pack.Version[0], /* How to interpret version ? */
+		 pkt->S1_Pack.Version[1]);
+	  break;
+//	case Logicaldevice:
+	  break;
+//	case CompatibleDevice:
+	  break;
+	case IRQFormat:
+#define p pkt->S4_Pack
+	  printk("    IRQ Mask 0x%4.4x, %s %s sensitive\n", 
+		 ld_le16((unsigned short *)p.IRQMask),
+		 intlevel[(size>3) ? !(p.IRQInfo&0x05) : 0],
+		 intsense[(size>3) ? !(p.IRQInfo&0x03) : 0]);
+#undef p
+	  break;
+	case DMAFormat:
+#define p pkt->S5_Pack
+	  printk("    DMA channel mask 0x%2.2x, info 0x%2.2x\n",
+		 p.DMAMask, p.DMAInfo);
+#undef p
+	  break;
+	case StartDepFunc:
+	  printk("Start dependent function:\n");
+	  break;
+	case EndDepFunc:
+	  printk("End dependent function\n");
+	  break;
+	case IOPort:
+#define p pkt->S8_Pack
+	  printk("    Variable (%d decoded bits) I/O port\n"
+		 "      from 0x%4.4x to 0x%4.4x, alignment %d, %d ports\n",
+		 p.IOInfo&ISAAddr16bit?16:10,
+		 ld_le16((unsigned short *)p.RangeMin),
+ 		 ld_le16((unsigned short *)p.RangeMax),
+		 p.IOAlign, p.IONum); 
+#undef p
+	  break;
+	case FixedIOPort:
+#define p pkt->S9_Pack
+	  printk("    Fixed (10 decoded bits) I/O port from %3.3x to %3.3x\n",
+		 (p.Range[1]<<8)|p.Range[0],
+		 ((p.Range[1]<<8)|p.Range[0])+p.IONum-1);
+#undef p		 
+	  break;
+	case Res1:
+	case Res2:
+	case Res3:
+	  printk("    Undefined packet type %d!\n", 
+		 tag_small_item_name(pkt->S1_Pack.Tag));
+	  break;
+	case SmallVendorItem:
+	  printsmallvendor(pkt,size);
+	  break;
+	default:
+	  printk("    Type 0x2.2x%d, size=%d\n", 
+		 pkt->S1_Pack.Tag, size);    
+	  break;
+	}
+}
+
+static void __init printlargevendor(PnP_TAG_PACKET * pkt, int size) {
+	static const unsigned char * addrtype[] = {"I/O", "Memory", "System"};
+	static const unsigned char * inttype[] = {"8259", "MPIC", "RS6k BUID %d"};
+	static const unsigned char * convtype[] = {"Bus Memory", "Bus I/O", "DMA"};
+	static const unsigned char * transtype[] = {"direct", "mapped", "direct-store segment"};
+	static const unsigned char * L2type[] = {"WriteThru", "CopyBack"};
+	static const unsigned char * L2assoc[] = {"DirectMapped", "2-way set"};
+
+	int i;
+	char tmpstr[30], *t;
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+	switch(p.Type) {
+	case 2:
+	  printk("    %d K %s %s L2 cache, %d/%d bytes line/sector size\n",
+		 ld_le32((unsigned int *)p.PPCData),
+		 L2type[p.PPCData[10]-1],
+		 L2assoc[p.PPCData[4]-1],
+		 ld_le16((unsigned short *)p.PPCData+3),
+		 ld_le16((unsigned short *)p.PPCData+4));
+	  break;
+	case 3:
+	  printk("    PCI Bridge parameters\n"
+		 "      ConfigBaseAddress %0x\n"
+		 "      ConfigBaseData %0x\n"
+		 "      Bus number %d\n",
+		 ld_le32((unsigned int *)p.PPCData),
+		 ld_le32((unsigned int *)(p.PPCData+8)),
+		 p.PPCData[16]);
+	  for(i=20; i<size-4; i+=12) {
+	  	int j, first;
+	  	if(p.PPCData[i]) printk("      PCI Slot %d", p.PPCData[i]);
+		else printk ("      Integrated PCI device");
+		for(j=0, first=1, t=tmpstr; j<4; j++) {
+			int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j);
+			if(line!=0xffff){
+			        if(first) first=0; else *t++='/';
+				*t++='A'+j;
+			}
+		}
+		*t='\0';
+		printk(" DevFunc 0x%x interrupt line(s) %s routed to",
+		       p.PPCData[i+1],tmpstr);
+		sprintf(tmpstr,
+			inttype[p.PPCData[i+2]-1],
+			p.PPCData[i+3]);
+		printk(" %s line(s) ",
+		       tmpstr);
+		for(j=0, first=1, t=tmpstr; j<4; j++) {
+			int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j);
+			if(line!=0xffff){
+				if(first) first=0; else *t++='/';
+				t+=sprintf(t,"%d(%c)",
+					   line&0x7fff,
+					   line&0x8000?'E':'L');
+			}
+		}
+		printk("%s\n",tmpstr);
+	  }
+	  break;
+	case 5:
+	  printk("    Bridge address translation, %s decoding:\n"
+		 "      Processor  Bus        Size       Conversion Translation\n"
+		 "      0x%8.8x 0x%8.8x 0x%8.8x %s %s\n",
+		 p.PPCData[0]&1 ? "positive" : "subtractive",
+		 ld_le32((unsigned int *)p.PPCData+1),
+		 ld_le32((unsigned int *)p.PPCData+3),
+		 ld_le32((unsigned int *)p.PPCData+5),
+		 convtype[p.PPCData[2]-1],
+		 transtype[p.PPCData[1]-1]);
+	  break;
+	case 6:
+	  printk("    Bus speed %d Hz, %d slot(s)\n",
+		 ld_le32((unsigned int *)p.PPCData),
+		 p.PPCData[4]);
+	  break;
+	case 7:
+	  printk("    SCSI buses: %d, id(s):", p.PPCData[0]);
+	  for(i=1; i<=p.PPCData[0]; i++) 
+	    printk(" %d%c", p.PPCData[i], i==p.PPCData[0] ? '\n' : ',');
+	  break;
+	case 9:
+	  printk("    %s address (%d bits), at 0x%x size 0x%x bytes\n",
+		 addrtype[p.PPCData[0]-1],
+		 p.PPCData[1],
+		 ld_le32((unsigned int *)(p.PPCData+4)),
+		 ld_le32((unsigned int *)(p.PPCData+12)));
+	  break;
+	case 10:
+	  sprintf(tmpstr,
+		  inttype[p.PPCData[0]-1],
+		  p.PPCData[1]);
+
+	  printk("    ISA interrupts routed to %s\n"
+		 "      lines", 
+		 tmpstr);
+	  for(i=0; i<16; i++) {
+	  	int line=ld_le16((unsigned short *)p.PPCData+i+1);
+		if (line!=0xffff) printk(" %d(IRQ%d)", line, i); 
+	  }
+	  printk("\n");
+	  break;
+	default:
+	  printk("    Large vendor item type 0x%2.2x\n      Data (hex):",
+		 p.Type);
+	  for(i=0; i<size-4; i++) printk(" %2.2x", p.PPCData[i]);
+	  printk("\n");
+#undef p
+	}
+}
+
+static void __init printlargepacket(PnP_TAG_PACKET * pkt, int size) {
+	switch (tag_large_item_name(pkt->S1_Pack.Tag)) {
+	case LargeVendorItem:
+	  printlargevendor(pkt, size);
+	  break;
+	default:
+	  printk("    Type 0x2.2x%d, size=%d\n", 
+		 pkt->S1_Pack.Tag, size);    
+	  break;
+	}
+}
+static void __init printpackets(PnP_TAG_PACKET * pkt, const char * cat) {
+	if (pkt->S1_Pack.Tag== END_TAG) {
+		printk("  No packets describing %s resources.\n", cat);
+		return;
+	}
+	printk(  "  Packets describing %s resources:\n",cat);
+	do {
+		int size;
+		if (tag_type(pkt->S1_Pack.Tag)) {
+		  	size= 3 +
+			  pkt->L1_Pack.Count0 + 
+			  pkt->L1_Pack.Count1*256;
+			printlargepacket(pkt, size);
+		} else {
+			size=tag_small_count(pkt->S1_Pack.Tag)+1;
+			printsmallpacket(pkt, size);
+		}
+		(unsigned char *) pkt+=size;
+	} while (pkt->S1_Pack.Tag != END_TAG);
+}
+
+void __init print_residual_device_info(void)
+{
+	int i;
+	PPC_DEVICE *dev;
+#define did dev->DeviceId
+	
+	/* make sure we have residual data first */
+	if ( res->ResidualLength == 0 )
+		return;
+	
+	printk("Residual: %ld devices\n", res->ActualNumDevices);
+	for ( i = 0;
+	      i < res->ActualNumDevices ;
+	      i++)
+	{
+	  	char decomp[4], sn[20];
+		const char * s;
+		dev = &res->Devices[i];
+		s = PnP_INTERFACE_STR(did.BaseType, did.SubType, 
+				      did.Interface);
+		if(!s) {
+			sprintf(sn, "interface %d", did.Interface);
+			s=sn;
+		}
+		if ( did.BusId & PCIDEVICE ) 
+		  printk("PCI Device, Bus %d, DevFunc 0x%x:",
+			 dev->BusAccess.PCIAccess.BusNumber,
+			 dev->BusAccess.PCIAccess.DevFuncNumber);
+	       	if ( did.BusId & PNPISADEVICE ) printk("PNPISA Device:");
+		if ( did.BusId & ISADEVICE ) 
+		  printk("ISA Device, Slot %d, LogicalDev %d:",
+			 dev->BusAccess.ISAAccess.SlotNumber,
+			 dev->BusAccess.ISAAccess.LogicalDevNumber);
+		if ( did.BusId & EISADEVICE ) printk("EISA Device:");
+		if ( did.BusId & PROCESSORDEVICE ) 
+		  printk("ProcBus Device, Bus %d, BUID %d: ",
+			 dev->BusAccess.ProcBusAccess.BusNumber,
+			 dev->BusAccess.ProcBusAccess.BUID);
+		if ( did.BusId & PCMCIADEVICE ) printk("PCMCIA ");
+		if ( did.BusId & VMEDEVICE ) printk("VME ");
+		if ( did.BusId & MCADEVICE ) printk("MCA ");
+		if ( did.BusId & MXDEVICE ) printk("MX ");
+		/* Decompress first 3 chars */
+		decomp[0]='A'-1+((did.DevId>>26)&0x1F);
+		decomp[1]='A'-1+((did.DevId>>21)&0x1F);
+		decomp[2]='A'-1+((did.DevId>>16)&0x1F);
+		decomp[3]=0;
+		printk(" %s%4.4lX, %s, %s, %s\n", 
+		       decomp, did.DevId&0xffff,
+		       PnP_BASE_TYPES[did.BaseType],
+		       PnP_SUB_TYPE_STR(did.BaseType,did.SubType),
+		       s);
+		if ( dev->AllocatedOffset )
+			printpackets( (union _PnP_TAG_PACKET *)
+				      &res->DevicePnPHeap[dev->AllocatedOffset],
+				      "allocated");
+		if ( dev->PossibleOffset )
+			printpackets( (union _PnP_TAG_PACKET *)
+				      &res->DevicePnPHeap[dev->PossibleOffset],
+				      "possible");
+		if ( dev->CompatibleOffset )
+			printpackets( (union _PnP_TAG_PACKET *)
+				      &res->DevicePnPHeap[dev->CompatibleOffset],
+				      "compatible");
+	}
+}
+
+
+#if 0
+static void __init printVPD(void) {
+#define vpd res->VitalProductData
+	int ps=vpd.PageSize, i, j;
+	static const char* Usage[]={
+	  "FirmwareStack",  "FirmwareHeap",  "FirmwareCode", "BootImage",
+	  "Free", "Unpopulated", "ISAAddr", "PCIConfig",
+	  "IOMemory", "SystemIO", "SystemRegs", "PCIAddr", 
+	  "UnPopSystemRom", "SystemROM", "ResumeBlock", "Other" 
+	};
+	static const unsigned char *FWMan[]={
+	  "IBM", "Motorola", "FirmWorks", "Bull"
+	};
+	static const unsigned char *FWFlags[]={
+	  "Conventional", "OpenFirmware", "Diagnostics", "LowDebug",
+	  "MultiBoot", "LowClient", "Hex41", "FAT", 
+	  "ISO9660", "SCSI_ID_Override", "Tape_Boot", "FW_Boot_Path"
+	};
+	static const unsigned char *ESM[]={
+	  "Port92", "PCIConfigA8", "FF001030", "????????"
+	};
+	static const unsigned char *SIOM[]={
+	  "Port850", "????????", "PCIConfigA8", "????????"
+	};
+
+	printk("Model: %s\n",vpd.PrintableModel);
+	printk("Serial: %s\n", vpd.Serial);
+	printk("FirmwareSupplier: %s\n", FWMan[vpd.FirmwareSupplier]);
+	printk("FirmwareFlags:");
+	for(j=0; j<12; j++) {
+	  	if (vpd.FirmwareSupports & (1<<j)) {
+			printk(" %s%c", FWFlags[j], 
+			       vpd.FirmwareSupports&(-2<<j) ? ',' : '\n');
+		}
+	}
+	printk("NVRamSize: %ld\n", vpd.NvramSize);
+	printk("SIMMslots: %ld\n", vpd.NumSIMMSlots);
+	printk("EndianSwitchMethod: %s\n", 
+	       ESM[vpd.EndianSwitchMethod>2 ? 2 : vpd.EndianSwitchMethod]);
+	printk("SpreadIOMethod: %s\n", 
+	       SIOM[vpd.SpreadIOMethod>3 ? 3 : vpd.SpreadIOMethod]);
+	printk("Processor/Bus frequencies (Hz): %ld/%ld\n",
+	       vpd.ProcessorHz, vpd.ProcessorBusHz);
+	printk("Time Base Divisor: %ld\n", vpd.TimeBaseDivisor);
+	printk("WordWidth, PageSize: %ld, %d\n", vpd.WordWidth, ps);
+	printk("Cache sector size, Lock granularity: %ld, %ld\n",
+	       vpd.CoherenceBlockSize, vpd.GranuleSize);
+	for (i=0; i<res->ActualNumMemSegs; i++) {
+		int mask=res->Segs[i].Usage, first, j;
+		printk("%8.8lx-%8.8lx ", 
+		       res->Segs[i].BasePage*ps,
+		       (res->Segs[i].PageCount+res->Segs[i].BasePage)*ps-1);
+		for(j=15, first=1; j>=0; j--) {
+			if (mask&(1<<j)) {
+				if (first) first=0;
+				else printk(", ");
+				printk("%s", Usage[j]);
+			}
+		}
+		printk("\n");
+	}
+}
+
+/*
+ * Spit out some info about residual data
+ */
+void print_residual_device_info(void)
+{
+	int i;
+	union _PnP_TAG_PACKET *pkt;
+	PPC_DEVICE *dev;
+#define did dev->DeviceId
+	
+	/* make sure we have residual data first */
+	if ( res->ResidualLength == 0 )
+		return;
+	printk("Residual: %ld devices\n", res->ActualNumDevices);
+	for ( i = 0;
+	      i < res->ActualNumDevices ;
+	      i++)
+	{
+		dev = &res->Devices[i];
+		/*
+		 * pci devices
+		 */
+		if ( did.BusId & PCIDEVICE )
+		{
+			printk("PCI Device:");
+			/* unknown vendor */
+			if ( !strncmp( "Unknown", pci_strvendor(did.DevId>>16), 7) )
+				printk(" id %08lx types %d/%d", did.DevId,
+				       did.BaseType, did.SubType);
+			/* known vendor */
+			else
+				printk(" %s %s",
+				       pci_strvendor(did.DevId>>16),
+				       pci_strdev(did.DevId>>16,
+						  did.DevId&0xffff)
+					);
+			
+			if ( did.BusId & PNPISADEVICE )
+			{
+				printk(" pnp:");
+				/* get pnp info on the device */
+				pkt = (union _PnP_TAG_PACKET *)
+					&res->DevicePnPHeap[dev->AllocatedOffset];
+				for (; pkt->S1_Pack.Tag != DF_END_TAG;
+				     pkt++ )
+				{
+					if ( (pkt->S1_Pack.Tag == S4_Packet) ||
+					     (pkt->S1_Pack.Tag == S4_Packet_flags) )
+						printk(" irq %02x%02x",
+						       pkt->S4_Pack.IRQMask[0],
+						       pkt->S4_Pack.IRQMask[1]);
+				}
+			}
+			printk("\n");
+			continue;
+		}
+		/*
+		 * isa devices
+		 */
+		if ( did.BusId & ISADEVICE )
+		{
+			printk("ISA Device: basetype: %d subtype: %d",
+			       did.BaseType, did.SubType);
+			printk("\n");
+			continue;
+		}		
+		/*
+		 * eisa devices
+		 */
+		if ( did.BusId & EISADEVICE )
+		{
+			printk("EISA Device: basetype: %d subtype: %d",
+			       did.BaseType, did.SubType);
+			printk("\n");
+			continue;
+		}		
+		/*
+		 * proc bus devices
+		 */
+		if ( did.BusId & PROCESSORDEVICE )
+		{
+			printk("ProcBus Device: basetype: %d subtype: %d",
+			       did.BaseType, did.SubType);
+			printk("\n");
+			continue;
+		}
+		/*
+		 * pcmcia devices
+		 */
+		if ( did.BusId & PCMCIADEVICE )
+		{
+			printk("PCMCIA Device: basetype: %d subtype: %d",
+			       did.BaseType, did.SubType);
+			printk("\n");
+			continue;
+		}		
+		printk("Unknown bus access device: busid %lx\n",
+		       did.BusId);
+	}
+}
+#endif	
+
+/* Returns the device index in the residual data, 
+   any of the search items may be set as -1 for wildcard,
+   DevID number field (second halfword) is big endian ! 
+
+   Examples:
+   - search for the Interrupt controller (8259 type), 2 methods:
+     1) i8259 = residual_find_device(~0, 
+                                     NULL, 
+				     SystemPeripheral, 
+				     ProgrammableInterruptController, 
+				     ISA_PIC, 
+				     0);
+     2) i8259 = residual_find_device(~0, "PNP0000", -1, -1, -1, 0) 
+
+   - search for the first two serial devices, whatever their type)
+     iserial1 = residual_find_device(~0,NULL,
+                                     CommunicationsDevice,
+				     RS232Device,
+				     -1, 0)
+     iserial2 = residual_find_device(~0,NULL,
+                                     CommunicationsDevice,
+				     RS232Device,
+				     -1, 1)
+   - but search for typical COM1 and COM2 is not easy due to the
+     fact that the interface may be anything and the name "PNP0500" or 
+     "PNP0501". Quite bad. 
+
+*/
+
+/* devid are easier to uncompress than to compress, so to minimize bloat
+in this rarely used area we unencode and compare */
+
+/* in residual data number is big endian in the device table and
+little endian in the heap, so we use two parameters to avoid writing
+two very similar functions */
+
+static int __init same_DevID(unsigned short vendor,
+	       unsigned short Number,
+	       char * str) 
+{
+	static unsigned const char hexdigit[]="0123456789ABCDEF";
+	if (strlen(str)!=7) return 0;
+	if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0])  &&
+	     ( ((vendor>>5)&0x1f)+'A'-1 == str[1])   &&
+	     ( (vendor&0x1f)+'A'-1 == str[2])        &&
+	     (hexdigit[(Number>>12)&0x0f] == str[3]) &&
+	     (hexdigit[(Number>>8)&0x0f] == str[4])  &&
+	     (hexdigit[(Number>>4)&0x0f] == str[5])  &&
+	     (hexdigit[Number&0x0f] == str[6]) ) return 1;
+	return 0;
+}
+
+PPC_DEVICE __init *residual_find_device(unsigned long BusMask,
+			 unsigned char * DevID,
+			 int BaseType,
+			 int SubType,
+			 int Interface,
+			 int n)
+{
+	int i;
+	if ( !res->ResidualLength ) return NULL;
+	for (i=0; i<res->ActualNumDevices; i++) {
+#define Dev res->Devices[i].DeviceId
+		if ( (Dev.BusId&BusMask)                                  &&
+		     (BaseType==-1 || Dev.BaseType==BaseType)             &&
+		     (SubType==-1 || Dev.SubType==SubType)                &&
+		     (Interface==-1 || Dev.Interface==Interface)          &&
+		     (DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff,
+						Dev.DevId&0xffff, DevID)) &&
+		     !(n--) ) return res->Devices+i;
+#undef Dev
+	}
+	return 0;
+}
+
+PPC_DEVICE __init *residual_find_device_id(unsigned long BusMask,
+			 unsigned short DevID,
+			 int BaseType,
+			 int SubType,
+			 int Interface,
+			 int n)
+{
+	int i;
+	if ( !res->ResidualLength ) return NULL;
+	for (i=0; i<res->ActualNumDevices; i++) {
+#define Dev res->Devices[i].DeviceId
+		if ( (Dev.BusId&BusMask)                                  &&
+		     (BaseType==-1 || Dev.BaseType==BaseType)             &&
+		     (SubType==-1 || Dev.SubType==SubType)                &&
+		     (Interface==-1 || Dev.Interface==Interface)          &&
+		     (DevID==0xffff || (Dev.DevId&0xffff) == DevID)	  &&
+		     !(n--) ) return res->Devices+i;
+#undef Dev
+	}
+	return 0;
+}
+
+PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,
+				unsigned packet_tag,
+				int n)
+{
+	unsigned mask, masked_tag, size;
+	if(!p) return 0;
+	if (tag_type(packet_tag)) mask=0xff; else mask=0xF8;
+	masked_tag = packet_tag&mask;
+	for(; *p != END_TAG; p+=size) {
+		if ((*p & mask) == masked_tag && !(n--)) 
+			return (PnP_TAG_PACKET *) p;
+		if (tag_type(*p))
+			size=ld_le16((unsigned short *)(p+1))+3;
+		else 
+			size=tag_small_count(*p)+1;
+	}
+	return 0; /* not found */
+}
+
+PnP_TAG_PACKET __init *PnP_find_small_vendor_packet(unsigned char *p,
+					     unsigned packet_type,
+					     int n)
+{
+	int next=0;
+	while (p) {
+		p = (unsigned char *) PnP_find_packet(p, 0x70, next);
+		if (p && p[1]==packet_type && !(n--)) 
+			return (PnP_TAG_PACKET *) p;
+		next = 1;
+	};
+	return 0; /* not found */
+}
+
+PnP_TAG_PACKET __init *PnP_find_large_vendor_packet(unsigned char *p,
+					   unsigned packet_type,
+					   int n)
+{
+	int next=0;
+	while (p) {
+		p = (unsigned char *) PnP_find_packet(p, 0x84, next);
+		if (p && p[3]==packet_type && !(n--)) 
+			return (PnP_TAG_PACKET *) p;
+		next = 1;
+	};
+	return 0; /* not found */
+}
+
+#ifdef CONFIG_PROC_PREPRESIDUAL
+static int proc_prep_residual_read(char * buf, char ** start, off_t off,
+		int count, int *eof, void *data)
+{
+	int n;
+
+	n = res->ResidualLength - off;
+	if (n < 0) {
+		*eof = 1;
+		n = 0;
+	}
+	else {
+		if (n > count)
+			n = count;
+		else
+			*eof = 1;
+
+		memcpy(buf, (char *)res + off, n);
+		*start = buf;
+	}
+
+	return n;
+}
+
+void __init
+proc_prep_residual_init(void)
+{
+	if (res->ResidualLength)
+		create_proc_read_entry("residual", S_IRUGO, NULL,
+					proc_prep_residual_read, NULL);
+}
+
+__initcall(proc_prep_residual_init);
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/rpxclassic.h linux-2.4.20/arch/ppc/platforms/rpxclassic.h
--- linux-2.4.19/arch/ppc/platforms/rpxclassic.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/rpxclassic.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,104 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+
+/*
+ * A collection of structures, addresses, and values associated with
+ * the RPCG RPX-Classic board.  Copied from the RPX-Lite stuff.
+ *
+ * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
+ */
+#ifdef __KERNEL__
+#ifndef __MACH_RPX_DEFS
+#define __MACH_RPX_DEFS
+
+#include <linux/config.h>
+
+#ifndef __ASSEMBLY__
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+	unsigned int	bi_memstart;	/* Memory start address */
+	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
+	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
+	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
+	unsigned char	bi_enetaddr[6];
+	unsigned int	bi_baudrate;
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
+/* Memory map is configured by the PROM startup.
+ * We just map a few things we need.  The CSR is actually 4 byte-wide
+ * registers that can be accessed as 8-, 16-, or 32-bit values.
+ */
+#define PCI_ISA_IO_ADDR		((unsigned)0x80000000)
+#define PCI_ISA_IO_SIZE		((uint)(512 * 1024 * 1024))
+#define PCI_ISA_MEM_ADDR	((unsigned)0xc0000000)
+#define PCI_ISA_MEM_SIZE	((uint)(512 * 1024 * 1024))
+#define RPX_CSR_ADDR		((uint)0xfa400000)
+#define RPX_CSR_SIZE		((uint)(4 * 1024))
+#define IMAP_ADDR		((uint)0xfa200000)
+#define IMAP_SIZE		((uint)(64 * 1024))
+#define PCI_CSR_ADDR		((uint)0x80000000)
+#define PCI_CSR_SIZE		((uint)(64 * 1024))
+#define PCMCIA_MEM_ADDR		((uint)0xe0000000)
+#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
+#define PCMCIA_IO_ADDR		((uint)0xe4000000)
+#define PCMCIA_IO_SIZE		((uint)(4 * 1024))
+#define PCMCIA_ATTRB_ADDR	((uint)0xe8000000)
+#define PCMCIA_ATTRB_SIZE	((uint)(4 * 1024))
+
+/* Things of interest in the CSR.
+*/
+#define BCSR0_ETHEN		((uint)0x80000000)
+#define BCSR0_ETHLPBK		((uint)0x40000000)
+#define BCSR0_COLTESTDIS	((uint)0x20000000)
+#define BCSR0_FULLDPLXDIS	((uint)0x10000000)
+#define BCSR0_ENFLSHSEL		((uint)0x04000000)
+#define BCSR0_FLASH_SEL		((uint)0x02000000)
+#define BCSR0_ENMONXCVR		((uint)0x01000000)
+
+#define BCSR0_PCMCIAVOLT	((uint)0x000f0000)	/* CLLF */
+#define BCSR0_PCMCIA3VOLT	((uint)0x000a0000)	/* CLLF */
+#define BCSR0_PCMCIA5VOLT	((uint)0x00060000)	/* CLLF */
+
+#define BCSR1_IPB5SEL           ((uint)0x00100000)
+#define BCSR1_PCVCTL4           ((uint)0x00080000)
+#define BCSR1_PCVCTL5           ((uint)0x00040000)
+#define BCSR1_PCVCTL6           ((uint)0x00020000)
+#define BCSR1_PCVCTL7           ((uint)0x00010000)
+
+#define BCSR2_EN232XCVR		((uint)0x00008000)
+#define BCSR2_QSPACESEL		((uint)0x00004000)
+#define BCSR2_FETHLEDMODE	((uint)0x00000800)	/* CLLF */
+
+#if defined(CONFIG_HTDMSOUND)
+#include <platforms/rpxhiox.h>
+#endif
+
+/* define IO_BASE for pcmcia, CLLF only */
+#if !defined(CONFIG_PCI)
+#define _IO_BASE 0x80000000
+#define _IO_BASE_SIZE 0x1000
+
+/* for pcmcia sandisk */
+#ifdef CONFIG_IDE
+#define MAX_HWIFS 1
+#define ide_request_irq(irq,hand,flg,dev,id)    request_8xxirq((irq),(hand),(flg),(dev),(id))
+#endif
+#endif
+
+/* Interrupt level assignments.
+*/
+#define FEC_INTERRUPT	SIU_LEVEL1	/* FEC interrupt */
+
+#endif /* !__ASSEMBLY__ */
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS	0
+
+#endif
+#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/rpxhiox.h linux-2.4.20/arch/ppc/platforms/rpxhiox.h
--- linux-2.4.19/arch/ppc/platforms/rpxhiox.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/rpxhiox.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,45 @@
+/*
+ * BK Id: SCCS/s.rpxhiox.h 1.3 05/17/01 18:14:25 cort
+ */
+
+/*
+ * The Embedded Planet HIOX expansion card definitions.
+ * There were a few different versions of these cards, but only
+ * the one that escaped real production is defined here.
+ *
+ * Copyright (c) 2000 Dan Malek (dmalek@jlc.net)
+ */
+#ifndef __MACH_RPX_HIOX_DEFS
+#define __MACH_RPX_HIOX_DEFS
+
+#define HIOX_CSR_ADDR		((uint)0xfac00000)
+#define HIOX_CSR_SIZE		((uint)(4 * 1024))
+#define HIOX_CSR0_ADDR		HIOX_CSR_ADDR
+#define HIOX_CSR4_ADDR		((uint)0xfac00004)
+
+#define HIOX_CSR0_DEFAULT	((uint)0x380f3c00)
+#define HIOX_CSR0_ENSCC2	((uint)0x80000000)
+#define HIOX_CSR0_ENSMC2	((uint)0x04000000)
+#define HIOX_CSR0_ENVDOCLK	((uint)0x02000000)
+#define HIOX_CSR0_VDORST_HL	((uint)0x01000000)
+#define HIOX_CSR0_RS232SEL	((uint)0x0000c000)
+#define HIOX_CSR0_SCC3SEL	((uint)0x0000c000)
+#define HIOX_CSR0_SMC1SEL	((uint)0x00008000)
+#define HIOX_CSR0_SCC1SEL	((uint)0x00004000)
+#define HIOX_CSR0_ENTOUCH	((uint)0x00000080)
+#define HIOX_CSR0_PDOWN100	((uint)0x00000060)
+#define HIOX_CSR0_PDOWN10	((uint)0x00000040)
+#define HIOX_CSR0_PDOWN1	((uint)0x00000020)
+#define HIOX_CSR0_TSELSPI	((uint)0x00000010)
+#define HIOX_CSR0_TIRQSTAT	((uint)0x00000008)
+#define HIOX_CSR4_DEFAULT	((uint)0x00000000)
+#define HIOX_CSR4_ENTIRQ2	((uint)0x20000000)
+#define HIOX_CSR4_ENTIRQ3	((uint)0x10000000)
+#define HIOX_CSR4_ENAUDIO	((uint)0x00000080)
+#define HIOX_CSR4_RSTAUDIO	((uint)0x00000040)	/* 0 == reset */
+#define HIOX_CSR4_AUDCLKHI	((uint)0x00000020)
+#define HIOX_CSR4_AUDSPISEL	((uint)0x00000010)
+#define HIOX_CSR4_AUDIRQSTAT	((uint)0x00000008)
+#define HIOX_CSR4_AUDCLKSEL	((uint)0x00000007)
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/rpxlite.h linux-2.4.20/arch/ppc/platforms/rpxlite.h
--- linux-2.4.19/arch/ppc/platforms/rpxlite.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/rpxlite.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,84 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+
+/*
+ * A collection of structures, addresses, and values associated with
+ * the RPCG RPX-Lite board.  Copied from the MBX stuff.
+ *
+ * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
+ */
+#ifdef __KERNEL__
+#ifndef __MACH_RPX_DEFS
+#define __MACH_RPX_DEFS
+
+#include <linux/config.h>
+
+#ifndef __ASSEMBLY__
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+	unsigned int	bi_memstart;	/* Memory start address */
+	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
+	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
+	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
+	unsigned char	bi_enetaddr[6];
+	unsigned int	bi_baudrate;
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
+/* Memory map is configured by the PROM startup.
+ * We just map a few things we need.  The CSR is actually 4 byte-wide
+ * registers that can be accessed as 8-, 16-, or 32-bit values.
+ */
+#define RPX_CSR_ADDR		((uint)0xfa400000)
+#define RPX_CSR_SIZE		((uint)(4 * 1024))
+#define IMAP_ADDR		((uint)0xfa200000)
+#define IMAP_SIZE		((uint)(64 * 1024))
+#define PCMCIA_MEM_ADDR		((uint)0x04000000)
+#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
+#define PCMCIA_IO_ADDR		((uint)0x04400000)
+#define PCMCIA_IO_SIZE		((uint)(4 * 1024))
+
+/* Things of interest in the CSR.
+*/
+#define BCSR0_ETHEN		((uint)0x80000000)
+#define BCSR0_ETHLPBK		((uint)0x40000000)
+#define BCSR0_COLTESTDIS	((uint)0x20000000)
+#define BCSR0_FULLDPLXDIS	((uint)0x10000000)
+#define BCSR0_LEDOFF		((uint)0x08000000)
+#define BCSR0_USBDISABLE	((uint)0x04000000)
+#define BCSR0_USBHISPEED	((uint)0x02000000)
+#define BCSR0_USBPWREN		((uint)0x01000000)
+#define BCSR0_PCMCIAVOLT	((uint)0x000f0000)
+#define BCSR0_PCMCIA3VOLT	((uint)0x000a0000)
+#define BCSR0_PCMCIA5VOLT	((uint)0x00060000)
+
+#define BCSR1_IPB5SEL          ((uint)0x00100000)
+#define BCSR1_PCVCTL4          ((uint)0x00080000)
+#define BCSR1_PCVCTL5          ((uint)0x00040000)
+#define BCSR1_PCVCTL6          ((uint)0x00020000)
+#define BCSR1_PCVCTL7          ((uint)0x00010000)
+
+#if defined(CONFIG_HTDMSOUND)
+#include <platforms/rpxhiox.h>
+#endif
+#endif /* !__ASSEMBLY__ */
+
+/* define IO_BASE for pcmcia */
+#define _IO_BASE 0x80000000
+#define _IO_BASE_SIZE 0x1000
+
+#ifdef CONFIG_IDE
+#define MAX_HWIFS 1
+#define ide_request_irq(irq,hand,flg,dev,id)    request_8xxirq((irq),(hand),(flg),(dev),(id))
+#endif
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS	0
+
+#endif
+#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/spd8xx.h linux-2.4.20/arch/ppc/platforms/spd8xx.h
--- linux-2.4.19/arch/ppc/platforms/spd8xx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/spd8xx.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,69 @@
+/*
+ * BK Id: SCCS/s.spd8xx.h 1.8 10/27/01 13:39:41 trini
+ */
+/*
+ * Speech Design SPD8xxTS board specific definitions
+ * 
+ * Copyright (c) 2000,2001 Wolfgang Denk (wd@denx.de)
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_SPD8XX_H__
+#define __ASM_SPD8XX_H__
+
+#include <linux/config.h>
+ 
+#include <asm/ppcboot.h>
+
+#define SPD_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR */
+#define SPD_IMAP_SIZE	(64 * 1024)	/* size of mapped area */
+
+#define IMAP_ADDR	SPD_IMMR_BASE	/* physical base address of IMMR area */
+#define IMAP_SIZE	SPD_IMAP_SIZE	/* mapped size of IMMR area */
+
+#define PCMCIA_MEM_ADDR	((uint)0xFE100000)
+#define PCMCIA_MEM_SIZE	((uint)(64 * 1024))
+
+#define IDE0_INTERRUPT	10		/* = IRQ5 */
+#define IDE1_INTERRUPT	12		/* = IRQ6 */
+#define CPM_INTERRUPT	13		/* = SIU_LEVEL6 (was: SIU_LEVEL2) */
+
+/* override the default number of IDE hardware interfaces */
+#define MAX_HWIFS	2
+
+/*
+ * Definitions for IDE0 Interface
+ */
+#define IDE0_BASE_OFFSET		0x0000	/* Offset in PCMCIA memory */
+#define IDE0_DATA_REG_OFFSET		0x0000
+#define IDE0_ERROR_REG_OFFSET		0x0081
+#define IDE0_NSECTOR_REG_OFFSET		0x0082
+#define IDE0_SECTOR_REG_OFFSET		0x0083
+#define IDE0_LCYL_REG_OFFSET		0x0084
+#define IDE0_HCYL_REG_OFFSET		0x0085
+#define IDE0_SELECT_REG_OFFSET		0x0086
+#define IDE0_STATUS_REG_OFFSET		0x0087
+#define IDE0_CONTROL_REG_OFFSET		0x0106
+#define IDE0_IRQ_REG_OFFSET		0x000A	/* not used */
+
+/*
+ * Definitions for IDE1 Interface
+ */
+#define IDE1_BASE_OFFSET		0x0C00	/* Offset in PCMCIA memory */
+#define IDE1_DATA_REG_OFFSET		0x0000
+#define IDE1_ERROR_REG_OFFSET		0x0081
+#define IDE1_NSECTOR_REG_OFFSET		0x0082
+#define IDE1_SECTOR_REG_OFFSET		0x0083
+#define IDE1_LCYL_REG_OFFSET		0x0084
+#define IDE1_HCYL_REG_OFFSET		0x0085
+#define IDE1_SELECT_REG_OFFSET		0x0086
+#define IDE1_STATUS_REG_OFFSET		0x0087
+#define IDE1_CONTROL_REG_OFFSET		0x0106
+#define IDE1_IRQ_REG_OFFSET		0x000A	/* not used */
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS	0
+
+#endif /* __ASM_SPD8XX_H__ */
+#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/spruce.h linux-2.4.20/arch/ppc/platforms/spruce.h
--- linux-2.4.19/arch/ppc/platforms/spruce.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/spruce.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,99 @@
+/*
+ * include/asm-ppc/platforms/spruce.h
+ * 
+ * Definitions for IBM Spruce reference board support
+ *
+ * Authors: Matt Porter and Johnnie Peters
+ *          mporter@mvista.com
+ *          jpeters@mvista.com
+ *
+ * Copyright 2001 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_SPRUCE_H__
+#define __ASM_SPRUCE_H__
+
+#define SPRUCE_PCI_CONFIG_ADDR	0xfec00000
+#define SPRUCE_PCI_CONFIG_DATA	0xfec00004
+
+#define SPRUCE_PCI_PHY_IO_BASE	0xf8000000
+#define SPRUCE_PCI_IO_BASE	SPRUCE_PCI_PHY_IO_BASE
+
+#define SPRUCE_PCI_SYS_MEM_BASE	0x00000000
+
+#define SPRUCE_PCI_LOWER_MEM	0x80000000
+#define SPRUCE_PCI_UPPER_MEM	0x9fffffff
+#define SPRUCE_PCI_LOWER_IO	0x00000000
+#define SPRUCE_PCI_UPPER_IO	0x03ffffff
+
+#define	SPRUCE_ISA_IO_BASE	SPRUCE_PCI_IO_BASE
+
+#define SPRUCE_MEM_SIZE		0x04000000
+#define SPRUCE_BUS_SPEED	66666667
+
+#define SPRUCE_NVRAM_BASE_ADDR	0xff800000
+#define SPRUCE_RTC_BASE_ADDR	SPRUCE_NVRAM_BASE_ADDR
+
+#define KEYBOARD_IRQ    22
+#define AUX_IRQ 	21
+
+unsigned char spruce_read_keyb_data(void);
+unsigned char spruce_read_keyb_status(void);
+
+#define kbd_read_input  spruce_read_keyb_data
+#define kbd_read_status spruce_read_keyb_status
+#define kbd_write_output(val) *((unsigned char *)0xff810000) = (char)val
+#define kbd_write_command(val) *((unsigned char *)0xff810001) = (char)val
+
+/*
+ * Serial port defines
+ */ 
+#define SPRUCE_FPGA_REG_A	0xff820000
+#define SPRUCE_UARTCLK_33M	0x02
+#define SPRUCE_UARTCLK_IS_33M(reg)	(reg & SPRUCE_UARTCLK_33M)
+
+#define UART0_IO_BASE	0xff600300
+#define UART1_IO_BASE	0xff600400
+
+#define RS_TABLE_SIZE	2
+
+#define SPRUCE_BAUD_33M	33000000/64
+#define SPRUCE_BAUD_30M	30000000/64
+#define BASE_BAUD	SPRUCE_BAUD_33M
+
+#define UART0_INT	3
+#define UART1_INT	4
+
+#define STD_UART_OP(num)					\
+	{ 0, BASE_BAUD, 0, UART##num##_INT,			\
+		(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),	\
+		iomem_base: UART##num##_IO_BASE,		\
+		io_type: SERIAL_IO_MEM},
+
+#define SERIAL_PORT_DFNS	\
+	STD_UART_OP(0)		\
+	STD_UART_OP(1)
+
+#endif /* __ASM_SPRUCE_H__ */
+#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/spruce_pci.c linux-2.4.20/arch/ppc/platforms/spruce_pci.c
--- linux-2.4.19/arch/ppc/platforms/spruce_pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/spruce_pci.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,104 @@
+/*
+ * arch/ppc/platforms/spruce_pci.c
+ * 
+ * PCI support for IBM Spruce
+ *
+ * Author: Johnnie Peters
+ *         jpeters@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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <platforms/spruce.h>
+
+#include "cpc700.h"
+
+static inline int
+spruce_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+		/*
+		 * 	PCI IDSEL/INTPIN->INTLINE 
+		 * 	A	B	C	D
+		 */
+	{
+		{23, 24, 25, 26},	/* IDSEL 1 - PCI slot 3 */
+		{24, 25, 26, 23},	/* IDSEL 2 - PCI slot 2 */
+		{25, 26, 23, 24},	/* IDSEL 3 - PCI slot 1 */
+		{26, 23, 24, 25},	/* IDSEL 4 - PCI slot 0 */
+	};
+
+	const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+
+void __init
+spruce_setup_hose(void)
+{
+	struct pci_controller *hose;
+
+	/* Setup hose */
+	hose = pcibios_alloc_controller();
+	if (!hose) 
+		return;
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	pci_init_resource(&hose->io_resource,
+			SPRUCE_PCI_LOWER_IO,
+			SPRUCE_PCI_UPPER_IO,
+			IORESOURCE_IO,
+			"PCI host bridge");
+
+	pci_init_resource(&hose->mem_resources[0],
+			SPRUCE_PCI_LOWER_MEM,
+			SPRUCE_PCI_UPPER_MEM,
+			IORESOURCE_MEM,
+			"PCI host bridge");
+
+	hose->io_space.start = SPRUCE_PCI_LOWER_IO;
+	hose->io_space.end = SPRUCE_PCI_UPPER_IO;
+	hose->mem_space.start = SPRUCE_PCI_LOWER_MEM;
+	hose->mem_space.end = SPRUCE_PCI_UPPER_MEM;
+	hose->io_base_virt = (void *)SPRUCE_ISA_IO_BASE;
+
+	setup_indirect_pci(hose,
+			SPRUCE_PCI_CONFIG_ADDR,
+			SPRUCE_PCI_CONFIG_DATA);
+
+	hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+	ppc_md.pci_swizzle = common_swizzle;
+	ppc_md.pci_map_irq = spruce_map_irq;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/spruce_setup.c linux-2.4.20/arch/ppc/platforms/spruce_setup.c
--- linux-2.4.19/arch/ppc/platforms/spruce_setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/spruce_setup.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,327 @@
+/*
+ * arch/ppc/platforms/spruce_setup.c
+ *
+ * Board setup routines for IBM Spruce
+ *
+ * Authors: Johnnie Peters <jpeters@mvista.com>
+ *          Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2001-2002 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.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/ide.h>
+#include <linux/serial.h>
+
+#include <asm/keyboard.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+#include <platforms/spruce.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+
+#include "cpc700.h"
+
+extern void spruce_init_IRQ(void);
+extern int spruce_get_irq(struct pt_regs *);
+extern void spruce_setup_hose(void);
+
+extern int pckbd_setkeycode(unsigned int, unsigned int);
+extern int pckbd_getkeycode(unsigned int);
+extern int pckbd_translate(unsigned char, unsigned char *, char);
+extern char pckbd_unexpected_up(unsigned char);
+extern void pckbd_leds(unsigned char);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
+extern char cmd_line[];
+
+/*
+ * CPC700 PIC interrupt programming table
+ *
+ * First entry is the sensitivity (level/edge), second is the polarity.
+ */
+unsigned int cpc700_irq_assigns[32][2] = {
+	{ 1, 1 },       /* IRQ  0: ECC Correctable Error - rising edge */
+	{ 1, 1 },       /* IRQ  1: PCI Write Mem Range   - rising edge */
+	{ 0, 1 },       /* IRQ  2: PCI Write Command Reg - active high */
+	{ 0, 1 },       /* IRQ  3: UART 0                - active high */
+	{ 0, 1 },       /* IRQ  4: UART 1                - active high */
+	{ 0, 1 },       /* IRQ  5: ICC 0                 - active high */
+	{ 0, 1 },       /* IRQ  6: ICC 1                 - active high */
+	{ 0, 1 },       /* IRQ  7: GPT Compare 0         - active high */
+	{ 0, 1 },       /* IRQ  8: GPT Compare 1         - active high */
+	{ 0, 1 },       /* IRQ  9: GPT Compare 2         - active high */
+	{ 0, 1 },       /* IRQ 10: GPT Compare 3         - active high */
+	{ 0, 1 },       /* IRQ 11: GPT Compare 4         - active high */
+	{ 0, 1 },       /* IRQ 12: GPT Capture 0         - active high */
+	{ 0, 1 },       /* IRQ 13: GPT Capture 1         - active high */
+	{ 0, 1 },       /* IRQ 14: GPT Capture 2         - active high */
+	{ 0, 1 },       /* IRQ 15: GPT Capture 3         - active high */
+	{ 0, 1 },       /* IRQ 16: GPT Capture 4         - active high */
+	{ 0, 0 },       /* IRQ 17: Reserved */
+	{ 0, 0 },       /* IRQ 18: Reserved */
+	{ 0, 0 },       /* IRQ 19: Reserved */
+	{ 0, 1 },       /* IRQ 20: FPGA EXT_IRQ0         - active high */
+	{ 1, 1 },       /* IRQ 21: Mouse                 - rising edge */
+	{ 1, 1 },       /* IRQ 22: Keyboard              - rising edge */
+	{ 0, 0 },       /* IRQ 23: PCI Slot 3            - active low */
+	{ 0, 0 },       /* IRQ 24: PCI Slot 2            - active low */
+	{ 0, 0 },       /* IRQ 25: PCI Slot 1            - active low */
+	{ 0, 0 },       /* IRQ 26: PCI Slot 0            - active low */
+};
+
+static void __init
+spruce_calibrate_decr(void)
+{
+	int freq, divisor = 4;
+
+	/* determine processor bus speed */
+	freq = SPRUCE_BUS_SPEED;
+	tb_ticks_per_jiffy = freq / HZ / divisor;
+	tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
+}
+
+static int
+spruce_show_cpuinfo(struct seq_file *m)
+{
+	seq_printf(m, "vendor\t\t: IBM\n");
+	seq_printf(m, "machine\t\t: Spruce\n");
+
+	return 0;
+}
+
+TODC_ALLOC();
+
+static void __init
+spruce_setup_arch(void)
+{
+	u32 baud_base;
+	struct serial_struct serial_req;
+
+	/* Setup TODC access */
+	TODC_INIT(TODC_TYPE_DS1643, 0, 0, SPRUCE_RTC_BASE_ADDR, 8);
+
+	/* init to some ~sane value until calibrate_delay() runs */
+	loops_per_jiffy = 50000000 / HZ;
+
+	/* Setup PCI host bridge */
+	spruce_setup_hose();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); /* /dev/ram */
+	else
+#endif
+#ifdef CONFIG_ROOT_NFS
+		ROOT_DEV = to_kdev_t(0x00FF);	/* /dev/nfs pseudo device */
+#else
+		ROOT_DEV = to_kdev_t(0x0801);	/* /dev/sda1 */
+#endif
+
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+
+	if (SPRUCE_UARTCLK_IS_33M(readb(SPRUCE_FPGA_REG_A)))	
+		baud_base = SPRUCE_BAUD_33M;
+	else
+		baud_base = SPRUCE_BAUD_30M;
+
+	/* Setup serial port access */
+	memset(&serial_req, 0, sizeof(serial_req));
+	serial_req.baud_base = baud_base;
+	serial_req.line = 0;
+	serial_req.port = 0;
+	serial_req.irq = 3;
+	serial_req.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+	serial_req.io_type = SERIAL_IO_MEM;
+	serial_req.iomem_base = UART0_IO_BASE;
+	serial_req.iomem_reg_shift = 0;
+
+	if (early_serial_setup(&serial_req) != 0) {
+		printk("Early serial init of port 0 failed\n");
+	}
+
+	/* Assume early_serial_setup() doesn't modify serial_req */
+	serial_req.line = 1;
+	serial_req.port = 1;
+	serial_req.irq = 4; 
+	serial_req.iomem_base = UART1_IO_BASE;
+
+	if (early_serial_setup(&serial_req) != 0) {
+		printk("Early serial init of port 1 failed\n");
+	}
+
+	/* Identify the system */
+	printk("System Identification: IBM Spruce\n");
+	printk("IBM Spruce port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n");
+}
+
+static void
+spruce_restart(char *cmd)
+{
+	__cli();
+
+	/* SRR0 has system reset vector, SRR1 has default MSR value */
+	/* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
+	__asm__ __volatile__
+	("\n\
+	lis	3,0xfff0
+	ori	3,3,0x0100
+	mtspr	26,3
+	li	3,0
+	mtspr	27,3
+	rfi
+	");
+	for(;;);
+}
+
+static void
+spruce_power_off(void)
+{
+	for(;;);
+}
+
+static void
+spruce_halt(void)
+{
+	spruce_restart(NULL);
+}
+
+static unsigned long __init
+spruce_find_end_of_memory(void)
+{
+	return boot_mem_size;
+}
+
+static void __init
+spruce_map_io(void)
+{
+	io_block_mapping(SPRUCE_PCI_IO_BASE, SPRUCE_PCI_PHY_IO_BASE,
+			 0x08000000, _PAGE_IO);
+}
+
+unsigned char spruce_read_keyb_status(void)
+{
+	unsigned long kbd_status;
+
+	__raw_writel(0x00000088, 0xff500008);
+	eieio();
+
+	__raw_writel(0x03000000, 0xff50000c);
+	eieio();
+
+	asm volatile("	lis	7,0xff88	\n
+			ori	7,7,0x8		\n
+			lswi	6,7,0x8		\n
+			mr	%0,6		\n"
+			: "=r" (kbd_status) :: "6", "7");
+
+	__raw_writel(0x00000000, 0xff50000c);
+	eieio();
+
+	return (unsigned char)(kbd_status >> 24);
+}
+
+unsigned char spruce_read_keyb_data(void)
+{
+	unsigned long kbd_data;
+
+	__raw_writel(0x00000088, 0xff500008);
+	eieio();
+
+	__raw_writel(0x03000000, 0xff50000c);
+	eieio();
+
+	asm volatile("	lis	7,0xff88	\n
+			lswi	6,7,0x8		\n
+			mr	%0,6		\n"
+			: "=r" (kbd_data) :: "6", "7");
+
+	__raw_writel(0x00000000, 0xff50000c);
+	eieio();
+
+	return (unsigned char)(kbd_data >> 24);
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	parse_bootinfo(find_bootinfo());
+
+	isa_io_base = SPRUCE_ISA_IO_BASE;
+	pci_dram_offset = SPRUCE_PCI_SYS_MEM_BASE;
+
+	ppc_md.setup_arch = spruce_setup_arch;
+	ppc_md.show_cpuinfo = spruce_show_cpuinfo;
+	ppc_md.init_IRQ = cpc700_init_IRQ;
+	ppc_md.get_irq = cpc700_get_irq;
+
+	ppc_md.find_end_of_memory = spruce_find_end_of_memory;
+	ppc_md.setup_io_mappings = spruce_map_io;
+
+	ppc_md.restart = spruce_restart;
+	ppc_md.power_off = spruce_power_off;
+	ppc_md.halt = spruce_halt;
+
+	ppc_md.time_init = todc_time_init;
+	ppc_md.set_rtc_time = todc_set_rtc_time;
+	ppc_md.get_rtc_time = todc_get_rtc_time;
+	ppc_md.calibrate_decr = spruce_calibrate_decr;
+
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
+
+#ifdef CONFIG_VT
+	/* Spruce has a PS2 style keyboard */
+	ppc_md.kbd_setkeycode = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode = pckbd_getkeycode;
+	ppc_md.kbd_translate = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+	ppc_md.kbd_leds = pckbd_leds;
+	ppc_md.kbd_init_hw = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
+	SYSRQ_KEY = 0x54;
+#endif
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/tqm8xx.h linux-2.4.20/arch/ppc/platforms/tqm8xx.h
--- linux-2.4.19/arch/ppc/platforms/tqm8xx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/tqm8xx.h	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,54 @@
+/*
+ * BK Id: SCCS/s.tqm8xx.h 1.8 08/30/01 09:01:04 trini
+ */
+/*
+ * TQM8xx(L) board specific definitions
+ * 
+ * Copyright (c) 1999,2000,2001 Wolfgang Denk (wd@denx.de)
+ */
+
+#ifndef __MACH_TQM8xx_H
+#define __MACH_TQM8xx_H
+
+#include <linux/config.h>
+ 
+#include <asm/ppcboot.h>
+
+#define	TQM_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR */
+#define	TQM_IMAP_SIZE	(64 * 1024)	/* size of mapped area */
+
+#define	IMAP_ADDR	TQM_IMMR_BASE	/* physical base address of IMMR area */
+#define IMAP_SIZE	TQM_IMAP_SIZE	/* mapped size of IMMR area */
+
+/*-----------------------------------------------------------------------
+ * PCMCIA stuff
+ *-----------------------------------------------------------------------
+ *
+ */
+#define PCMCIA_MEM_SIZE		( 64 << 20 )
+
+#define	MAX_HWIFS	1	/* overwrite default in include/asm-ppc/ide.h */
+
+/*
+ * Definitions for IDE0 Interface
+ */
+#define IDE0_BASE_OFFSET		0
+#define IDE0_DATA_REG_OFFSET		(PCMCIA_MEM_SIZE + 0x320)
+#define IDE0_ERROR_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 1)
+#define IDE0_NSECTOR_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 2)
+#define IDE0_SECTOR_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 3)
+#define IDE0_LCYL_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 4)
+#define IDE0_HCYL_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 5)
+#define IDE0_SELECT_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 6)
+#define IDE0_STATUS_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 7)
+#define IDE0_CONTROL_REG_OFFSET		0x0106
+#define IDE0_IRQ_REG_OFFSET		0x000A	/* not used */
+
+#define	IDE0_INTERRUPT			13
+
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS	0
+
+#endif	/* __MACH_TQM8xx_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/walnut.c linux-2.4.20/arch/ppc/platforms/walnut.c
--- linux-2.4.19/arch/ppc/platforms/walnut.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/walnut.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,291 @@
+/*
+ * BK Id: SCCS/s.walnut_setup.c 1.10 11/13/01 21:26:07 paulus
+ */
+/*
+ *
+ *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: walnut_setup.c
+ *
+ *    Description:
+ *      Architecture- / platform-specific boot-time initialization code for
+ *      the IBM PowerPC 403GP "Walnut" evaluation board. Adapted from original
+ *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
+ *      <dan@net4x.com>.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/interrupt.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/seq_file.h>
+
+#include <asm/processor.h>
+#include <asm/board.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+
+#include "ppc4xx_pic.h"
+#include <asm/time.h>
+#include "walnut_setup.h"
+
+
+/* Function Prototypes */
+
+extern void abort(void);
+
+/* Global Variables */
+
+unsigned char __res[sizeof(bd_t)];
+
+
+/*
+ * void __init walnut_init()
+ *
+ * Description:
+ *   This routine...
+ *
+ * Input(s):
+ *   r3 - Optional pointer to a board information structure.
+ *   r4 - Optional pointer to the physical starting address of the init RAM
+ *        disk.
+ *   r5 - Optional pointer to the physical ending address of the init RAM
+ *        disk.
+ *   r6 - Optional pointer to the physical starting address of any kernel
+ *        command-line parameters.
+ *   r7 - Optional pointer to the physical ending address of any kernel
+ *        command-line parameters.
+ *
+ * Output(s):
+ *   N/A
+ *
+ * Returns:
+ *   N/A
+ *
+ */
+void __init
+walnut_init(unsigned long r3, unsigned long r4, unsigned long r5, 
+	    unsigned long r6, unsigned long r7)
+{
+	/*
+	 * If we were passed in a board information, copy it into the
+	 * residual data area.
+	 */
+	if (r3) {
+		memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t));
+	}
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+	/*
+	 * If the init RAM disk has been configured in, and there's a valid
+	 * starting address for it, set it up.
+	 */
+	if (r4) {
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	/* Copy the kernel command line arguments to a safe place. */
+
+	if (r6) {
+ 		*(char *)(r7 + KERNELBASE) = 0;
+		strcpy(cmd_line, (char *)(r6 + KERNELBASE));
+	}
+
+	/* Initialize machine-dependency vectors */
+
+	ppc_md.setup_arch	 	= walnut_setup_arch;
+	ppc_md.show_percpuinfo	 	= walnut_show_percpuinfo;
+	ppc_md.irq_cannonicalize 	= NULL;
+	ppc_md.init_IRQ		 	= walnut_init_IRQ;
+	ppc_md.get_irq		 	= walnut_get_irq;
+	ppc_md.init		 	= NULL;
+
+	ppc_md.restart		 	= walnut_restart;
+	ppc_md.power_off	 	= walnut_power_off;
+	ppc_md.halt		 	= walnut_halt;
+
+	ppc_md.time_init	 	= walnut_time_init;
+	ppc_md.set_rtc_time	 	= walnut_set_rtc_time;
+	ppc_md.get_rtc_time	 	= walnut_get_rtc_time;
+	ppc_md.calibrate_decr	 	= walnut_calibrate_decr;
+
+	ppc_md.kbd_setkeycode    	= NULL;
+	ppc_md.kbd_getkeycode    	= NULL;
+	ppc_md.kbd_translate     	= NULL;
+	ppc_md.kbd_unexpected_up 	= NULL;
+	ppc_md.kbd_leds          	= NULL;
+	ppc_md.kbd_init_hw       	= NULL;
+	ppc_md.ppc_kbd_sysrq_xlate	= NULL;
+}
+
+/*
+ * Document me.
+ */
+void __init
+walnut_setup_arch(void)
+{
+	/* XXX - Implement me */
+}
+
+/*
+ * int walnut_show_percpuinfo()
+ *
+ * Description:
+ *   This routine pretty-prints the platform's internal CPU and bus clock
+ *   frequencies into the buffer for usage in /proc/cpuinfo.
+ *
+ * Input(s):
+ *  *buffer - Buffer into which CPU and bus clock frequencies are to be
+ *            printed.
+ *
+ * Output(s):
+ *  *buffer - Buffer with the CPU and bus clock frequencies.
+ *
+ * Returns:
+ *   The number of bytes copied into 'buffer' if OK, otherwise zero or less
+ *   on error.
+ */
+int
+walnut_show_percpuinfo(struct seq_file *m)
+{
+	bd_t *bp = (bd_t *)__res;
+
+	seq_printf(m, "clock\t\t: %dMHz\n"
+		   "bus clock\t\t: %dMHz\n",
+		   bp->bi_intfreq / 1000000,
+		   bp->bi_busfreq / 1000000);
+
+	return 0;
+}
+
+/*
+ * Document me.
+ */
+void __init
+walnut_init_IRQ(void)
+{
+	int i;
+
+	ppc4xx_pic_init();
+
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc[i].handler = ppc4xx_pic;
+	}
+
+	return;
+}
+
+/*
+ * Document me.
+ */
+int
+walnut_get_irq(struct pt_regs *regs)
+{
+	return (ppc4xx_pic_get_irq(regs));
+}
+
+/*
+ * Document me.
+ */
+void
+walnut_restart(char *cmd)
+{
+	abort();
+}
+
+/*
+ * Document me.
+ */
+void
+walnut_power_off(void)
+{
+	walnut_restart(NULL);
+}
+
+/*
+ * Document me.
+ */
+void
+walnut_halt(void)
+{
+	walnut_restart(NULL);
+}
+
+/*
+ * Document me.
+ */
+long __init
+walnut_time_init(void)
+{
+	/* XXX - Implement me */
+	return 0;
+}
+
+/*
+ * Document me.
+ */
+int __init
+walnut_set_rtc_time(unsigned long time)
+{
+	/* XXX - Implement me */
+
+	return (0);
+}
+
+/*
+ * Document me.
+ */
+unsigned long __init
+walnut_get_rtc_time(void)
+{
+	/* XXX - Implement me */
+
+	return (0);
+}
+
+/*
+ * void __init walnut_calibrate_decr()
+ *
+ * Description:
+ *   This routine retrieves the internal processor frequency from the board
+ *   information structure, sets up the kernel timer decrementer based on
+ *   that value, enables the 403 programmable interval timer (PIT) and sets
+ *   it up for auto-reload.
+ *
+ * Input(s):
+ *   N/A
+ *
+ * Output(s):
+ *   N/A
+ *
+ * Returns:
+ *   N/A
+ *
+ */
+void __init
+walnut_calibrate_decr(void)
+{
+	unsigned int freq;
+	bd_t *bip = (bd_t *)__res;
+
+	freq = bip->bi_intfreq;
+
+	decrementer_count = freq / HZ;
+	count_period_num = 1;
+	count_period_den = freq;
+
+	/* Enable the PIT and set auto-reload of its value */
+
+	mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
+
+	/* Clear any pending timer interrupts */
+
+	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc/platforms/walnut.h linux-2.4.20/arch/ppc/platforms/walnut.h
--- linux-2.4.19/arch/ppc/platforms/walnut.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/walnut.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,53 @@
+/*
+ * BK Id: SCCS/s.walnut_setup.h 1.5 05/17/01 18:14:22 cort
+ */
+/*
+ *
+ *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: walnut_setup.c
+ *
+ *    Description:
+ *      Architecture- / platform-specific boot-time initialization code for
+ *      the IBM PowerPC 405GP "Walnut" evaluation board. Adapted from original
+ *      code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
+ *      <dan@netx4.com>.
+ *
+ */
+
+#ifndef	__WALNUT_SETUP_H__
+#define	__WALNUT_SETUP_H__
+
+#include <asm/ptrace.h>
+#include <asm/board.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned char	 __res[sizeof(bd_t)];
+
+extern void		 walnut_init(unsigned long r3,
+				  unsigned long ird_start,
+				  unsigned long ird_end,
+				  unsigned long cline_start,
+				  unsigned long cline_end);
+extern void		 walnut_setup_arch(void);
+extern int		 walnut_setup_residual(char *buffer);
+extern void		 walnut_init_IRQ(void);
+extern int		 walnut_get_irq(struct pt_regs *regs);
+extern void		 walnut_restart(char *cmd);
+extern void		 walnut_power_off(void);
+extern void		 walnut_halt(void);
+extern void		 walnut_time_init(void);
+extern int		 walnut_set_rtc_time(unsigned long now);
+extern unsigned long	 walnut_get_rtc_time(void);
+extern void		 walnut_calibrate_decr(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WALNUT_SETUP_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/Makefile linux-2.4.20/arch/ppc64/Makefile
--- linux-2.4.19/arch/ppc64/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/Makefile	2002-10-29 11:18:39.000000000 +0000
@@ -22,7 +22,8 @@
 LINKFLAGS	= -T arch/ppc64/vmlinux.lds -Bstatic \
 		-e $(KERNELLOAD) -Ttext $(KERNELLOAD)
 CFLAGS		:= $(CFLAGS) -fsigned-char -msoft-float -pipe \
-		-Wno-uninitialized -mminimal-toc -fno-builtin
+		-Wno-uninitialized -mminimal-toc -fno-builtin \
+		-mtraceback=full
 CPP		= $(CC) -E $(CFLAGS)
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/boot/addRamDisk.c linux-2.4.20/arch/ppc64/boot/addRamDisk.c
--- linux-2.4.19/arch/ppc64/boot/addRamDisk.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/boot/addRamDisk.c	2002-10-29 11:18:33.000000000 +0000
@@ -25,7 +25,7 @@
 
 void death(const char *msg, FILE *fdesc, const char *fname) 
 {
-	printf(msg);
+	fprintf(stderr, msg);
 	fclose(fdesc);
 	unlink(fname);
 	exit(1);
@@ -66,47 +66,47 @@
   
   
 	if (argc < 2) {
-		printf("Name of RAM disk file missing.\n");
+		fprintf(stderr, "Name of RAM disk file missing.\n");
 		exit(1);
 	}
 
 	if (argc < 3) {
-		printf("Name of System Map input file is missing.\n");
+		fprintf(stderr, "Name of System Map input file is missing.\n");
 		exit(1);
 	}
   
 	if (argc < 4) {
-		printf("Name of vmlinux file missing.\n");
+		fprintf(stderr, "Name of vmlinux file missing.\n");
 		exit(1);
 	}
 
 	if (argc < 5) {
-		printf("Name of vmlinux output file missing.\n");
+		fprintf(stderr, "Name of vmlinux output file missing.\n");
 		exit(1);
 	}
 
 
 	ramDisk = fopen(argv[1], "r");
 	if ( ! ramDisk ) {
-		printf("RAM disk file \"%s\" failed to open.\n", argv[1]);
+		fprintf(stderr, "RAM disk file \"%s\" failed to open.\n", argv[1]);
 		exit(1);
 	}
 
 	sysmap = fopen(argv[2], "r");
 	if ( ! sysmap ) {
-		printf("System Map file \"%s\" failed to open.\n", argv[2]);
+		fprintf(stderr, "System Map file \"%s\" failed to open.\n", argv[2]);
 		exit(1);
 	}
   
 	inputVmlinux = fopen(argv[3], "r");
 	if ( ! inputVmlinux ) {
-		printf("vmlinux file \"%s\" failed to open.\n", argv[3]);
+		fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", argv[3]);
 		exit(1);
 	}
   
 	outputVmlinux = fopen(argv[4], "w+");
 	if ( ! outputVmlinux ) {
-		printf("output vmlinux file \"%s\" failed to open.\n", argv[4]);
+		fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", argv[4]);
 		exit(1);
 	}
   
@@ -118,7 +118,7 @@
 	fseek(inputVmlinux, 0, SEEK_SET);
 	printf("kernel file size = %d\n", kernelLen);
 	if ( kernelLen == 0 ) {
-		printf("You must have a linux kernel specified as argv[3]\n");
+		fprintf(stderr, "You must have a linux kernel specified as argv[3]\n");
 		exit(1);
 	}
 
@@ -160,9 +160,9 @@
 	/* search for _end in the last page of the system map */
 	ptr_end = strstr(inbuf, " _end");
 	if (!ptr_end) {
-		printf("Unable to find _end in the sysmap file \n");
-		printf("inbuf: \n");
-		printf("%s \n", inbuf);
+		fprintf(stderr, "Unable to find _end in the sysmap file \n");
+		fprintf(stderr, "inbuf: \n");
+		fprintf(stderr, "%s \n", inbuf);
 		exit(1);
 	}
 	printf("Found _end in the last page of the sysmap - backing up 10 characters it looks like %s", ptr_end-10);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/boot/addSystemMap.c linux-2.4.20/arch/ppc64/boot/addSystemMap.c
--- linux-2.4.19/arch/ppc64/boot/addSystemMap.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/boot/addSystemMap.c	2002-10-29 11:18:49.000000000 +0000
@@ -64,38 +64,38 @@
 	long padPages = 0;
 	if ( argc < 2 )
 	{
-		printf("Name of System Map file missing.\n");
+		fprintf(stderr, "Name of System Map file missing.\n");
 		exit(1);
 	}
 
 	if ( argc < 3 )
 	{
-		printf("Name of vmlinux file missing.\n");
+		fprintf(stderr, "Name of vmlinux file missing.\n");
 		exit(1);
 	}
 
 	if ( argc < 4 )
 	{
-		printf("Name of vmlinux output file missing.\n");
+		fprintf(stderr, "Name of vmlinux output file missing.\n");
 		exit(1);
 	}
 
 	sysmap = fopen(argv[1], "r");
 	if ( ! sysmap )
 	{
-		printf("System Map file \"%s\" failed to open.\n", argv[1]);
+		fprintf(stderr, "System Map file \"%s\" failed to open.\n", argv[1]);
 		exit(1);
 	}
 	inputVmlinux = fopen(argv[2], "r");
 	if ( ! inputVmlinux )
 	{
-		printf("vmlinux file \"%s\" failed to open.\n", argv[2]);
+		fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", argv[2]);
 		exit(1);
 	}
 	outputVmlinux = fopen(argv[3], "w");
 	if ( ! outputVmlinux )
 	{
-		printf("output vmlinux file \"%s\" failed to open.\n", argv[3]);
+		fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", argv[3]);
 		exit(1);
 	}
 
@@ -107,7 +107,7 @@
 	printf("kernel file size = %ld\n", kernelLen);
 	if ( kernelLen == 0 )
 	{
-		printf("You must have a linux kernel specified as argv[2]\n");
+		fprintf(stderr, "You must have a linux kernel specified as argv[2]\n");
 		exit(1);
 	}
 
@@ -154,9 +154,9 @@
 	ptr_end = strstr(inbuf, " _end");
 	if (!ptr_end)
 	{
-		printf("Unable to find _end in the sysmap file \n");
-		printf("inbuf: \n");
-		printf("%s \n", inbuf);
+		fprintf(stderr, "Unable to find _end in the sysmap file \n");
+		fprintf(stderr, "inbuf: \n");
+		fprintf(stderr, "%s \n", inbuf);
 		exit(1);
 	}
 	printf("Found _end in the last page of the sysmap - backing up 10 characters it looks like %s", ptr_end-10);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/boot/zImage.c linux-2.4.20/arch/ppc64/boot/zImage.c
--- linux-2.4.19/arch/ppc64/boot/zImage.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/boot/zImage.c	2002-10-29 11:18:36.000000000 +0000
@@ -225,7 +225,7 @@
 
 	rec = bi_rec_alloc(rec, 2);
 	rec->tag = BI_MACHTYPE;
-	rec->data[0] = _MACH_pSeries;
+	rec->data[0] = PLATFORM_PSERIES;
 	rec->data[1] = 1;
 
 	if ( initrd.size > 0 ) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/config.in linux-2.4.20/arch/ppc64/config.in
--- linux-2.4.19/arch/ppc64/config.in	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/config.in	2002-10-29 11:18:34.000000000 +0000
@@ -37,6 +37,7 @@
    define_bool CONFIG_MSCHUNKS y
 else
 bool 'MsChunks Physical to Absolute address translation support' CONFIG_MSCHUNKS
+tristate 'Firmware flash interface' CONFIG_RTAS_FLASH
 fi
 
 
@@ -59,6 +60,7 @@
 define_bool CONFIG_MCA n
 define_bool CONFIG_EISA n
 define_bool CONFIG_PCI y
+define_bool CONFIG_PCMCIA n
 
 bool 'Networking support' CONFIG_NET
 bool 'Sysctl support' CONFIG_SYSCTL
@@ -70,9 +72,9 @@
    define_bool CONFIG_KCORE_ELF y
 fi
 
-bool 'Kernel Support for 64 bit ELF binaries' CONFIG_BINFMT_ELF
+bool 'Kernel support for 64 bit ELF binaries' CONFIG_BINFMT_ELF
 
-tristate 'Kernel support for 32 bit binaries' CONFIG_BINFMT_ELF32
+tristate 'Kernel support for 32 bit ELF binaries' CONFIG_BINFMT_ELF32
 
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
@@ -80,12 +82,6 @@
 
 bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
 
-if [ "$CONFIG_HOTPLUG" = "y" ]; then
-   source drivers/pcmcia/Config.in
-else
-   define_bool CONFIG_PCMCIA n
-fi
-
 source drivers/parport/Config.in
 
 if [ "$CONFIG_PPC_ISERIES" != "y" ]; then
@@ -93,12 +89,15 @@
    bool 'Support for frame buffer devices' CONFIG_FB
 
    bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
+
+   bool 'Default bootloader kernel arguments' CONFIG_CMDLINE_BOOL
+   if [ "$CONFIG_CMDLINE_BOOL" = "y" ] ; then
+     string 'Initial kernel command string' CONFIG_CMDLINE "console=ttyS0,9600 console=tty0 root=/dev/sda2"
+   fi
 fi
 
 endmenu
 
-source drivers/mtd/Config.in
-source drivers/pnp/Config.in
 source drivers/block/Config.in
 source drivers/md/Config.in
 
@@ -145,8 +144,6 @@
 
 source net/ax25/Config.in
 
-source net/irda/Config.in
-
 mainmenu_option next_comment
 comment 'ISDN subsystem'
 
@@ -165,12 +162,14 @@
 fi
 endmenu
 
+if [ "$CONFIG_PPC_ISERIES" != "y" ]; then
 mainmenu_option next_comment
 comment 'Console drivers'
 source drivers/video/Config.in
 endmenu
 
 source drivers/input/Config.in
+fi
 
 if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
 mainmenu_option next_comment
@@ -214,6 +213,7 @@
 source drivers/char/Config.in
 source fs/Config.in
 
+if [ "$CONFIG_PPC_ISERIES" != "y" ]; then
 mainmenu_option next_comment
 comment 'Sound'
 tristate 'Sound card support' CONFIG_SOUND
@@ -224,7 +224,9 @@
 
 endmenu
 
+source drivers/media/Config.in
 source drivers/usb/Config.in
+fi
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
@@ -232,10 +234,21 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 bool 'Include kgdb kernel debugger' CONFIG_KGDB
 bool 'Include xmon kernel debugger' CONFIG_XMON
-#bool 'Include kdb kernel debugger' CONFIG_KDB
-#if [ "$CONFIG_KDB" = "y" ]; then
-#  bool '  KDB off by default' CONFIG_KDB_OFF
-#  define_bool CONFIG_KALLSYMS y
-#fi
+bool 'Include kdb kernel debugger' CONFIG_KDB
+if [ "$CONFIG_KDB" = "y" ]; then
+  bool '  KDB off by default' CONFIG_KDB_OFF
+  define_bool CONFIG_KALLSYMS y
+  define_bool CONFIG_XMON n
+fi
+if [ "$CONFIG_XMON" = "y" ]; then
+  define_bool CONFIG_KDB n
+  define_bool CONFIG_KALLSYMS n
+fi
 bool 'Include PPCDBG realtime debugging' CONFIG_PPCDBG
+
+tristate 'Linux Kernel Crash Dump (LKCD) Support' CONFIG_DUMP
+if [ "$CONFIG_DUMP" = "y" -o "$CONFIG_DUMP" = "m" ]; then
+   dep_bool '  LKCD RLE compression' CONFIG_DUMP_COMPRESS_RLE $CONFIG_DUMP
+   dep_bool '  LKCD GZIP compression' CONFIG_DUMP_COMPRESS_GZIP $CONFIG_DUMP
+fi
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/configs/iSeries_devfs_defconfig linux-2.4.20/arch/ppc64/configs/iSeries_devfs_defconfig
--- linux-2.4.19/arch/ppc64/configs/iSeries_devfs_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/configs/iSeries_devfs_defconfig	2002-10-29 11:18:48.000000000 +0000
@@ -696,4 +696,10 @@
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_KGDB is not set
 # CONFIG_XMON is not set
+# CONFIG_KDB is not set
+# CONFIG_KDB_OFF is not set
+# CONFIG_KALLSYMS is not set
 # CONFIG_PPCDBG is not set
+CONFIG_DUMP=y
+CONFIG_DUMP_COMPRESS_RLE=y
+CONFIG_DUMP_COMPRESS_GZIP=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig linux-2.4.20/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig
--- linux-2.4.19/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig	2002-10-29 11:18:33.000000000 +0000
@@ -67,7 +67,6 @@
 #
 # CONFIG_PNP is not set
 # CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
 
 #
 # Block devices
@@ -77,6 +76,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
@@ -101,8 +101,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 CONFIG_FILTER=y
@@ -110,8 +108,6 @@
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_RTNETLINK=y
-CONFIG_NETLINK=y
 CONFIG_IP_MULTIPLE_TABLES=y
 CONFIG_IP_ROUTE_NAT=y
 CONFIG_IP_ROUTE_MULTIPATH=y
@@ -134,12 +130,18 @@
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
 
 #
 #  
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -155,6 +157,16 @@
 # 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_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
@@ -192,6 +204,7 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_DPT_I2O is not set
@@ -213,6 +226,7 @@
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
 # CONFIG_SCSI_NCR53C8XX is not set
 # CONFIG_SCSI_SYM53C8XX is not set
 # CONFIG_SCSI_PAS16 is not set
@@ -229,8 +243,6 @@
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_MESH is not set
-# CONFIG_SCSI_MAC53C94 is not set
 
 #
 # IEEE 1394 (FireWire) support (EXPERIMENTAL)
@@ -259,12 +271,10 @@
 # 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_HAPPYMEAL is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -278,6 +288,7 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_TULIP is not set
+# CONFIG_TC35815 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
@@ -293,11 +304,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_NEW_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
 # CONFIG_NET_POCKET is not set
 
@@ -312,6 +325,7 @@
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -329,6 +343,7 @@
 CONFIG_TR=y
 CONFIG_IBMOL=m
 # CONFIG_IBMLS is not set
+# CONFIG_3C359 is not set
 # CONFIG_TMS380TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_RCPCI is not set
@@ -380,6 +395,15 @@
 # CONFIG_FB is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
 # iSeries device drivers
 #
 CONFIG_VIOCONS=y
@@ -435,43 +459,20 @@
 # Joysticks
 #
 # CONFIG_INPUT_GAMEPORT is not set
-# CONFIG_INPUT_NS558 is not set
-# CONFIG_INPUT_LIGHTNING is not set
-# CONFIG_INPUT_PCIGAME is not set
-# CONFIG_INPUT_CS461X is not set
-# CONFIG_INPUT_EMU10K1 is not set
-# CONFIG_INPUT_SERIO is not set
-# CONFIG_INPUT_SERPORT is not set
 
 #
-# Joysticks
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
 #
-# CONFIG_INPUT_ANALOG is not set
-# CONFIG_INPUT_A3D is not set
-# CONFIG_INPUT_ADI is not set
-# CONFIG_INPUT_COBRA is not set
-# CONFIG_INPUT_GF2K is not set
-# CONFIG_INPUT_GRIP is not set
-# CONFIG_INPUT_INTERACT is not set
-# CONFIG_INPUT_TMDC is not set
-# CONFIG_INPUT_SIDEWINDER is not set
-# CONFIG_INPUT_IFORCE_USB is not set
-# CONFIG_INPUT_IFORCE_232 is not set
-# CONFIG_INPUT_WARRIOR is not set
-# CONFIG_INPUT_MAGELLAN is not set
-# CONFIG_INPUT_SPACEORB is not set
-# CONFIG_INPUT_SPACEBALL is not set
-# CONFIG_INPUT_STINGER is not set
-# CONFIG_INPUT_DB9 is not set
-# CONFIG_INPUT_GAMECON is not set
-# CONFIG_INPUT_TURBOGRAFX is not set
 # CONFIG_QIC02_TAPE is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -484,7 +485,6 @@
 # CONFIG_FTAPE is not set
 # CONFIG_AGP is not set
 # CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
 
 #
 # File systems
@@ -494,11 +494,15 @@
 CONFIG_AUTOFS4_FS=y
 CONFIG_REISERFS_FS=y
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
@@ -511,8 +515,10 @@
 CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
@@ -536,6 +542,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_ROOT_NFS is not set
@@ -555,6 +562,8 @@
 CONFIG_NCPFS_SMALLDOS=y
 CONFIG_NCPFS_NLS=y
 CONFIG_NCPFS_EXTRAS=y
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -589,6 +598,7 @@
 # CONFIG_NLS_CODEPAGE_949 is not set
 # CONFIG_NLS_CODEPAGE_874 is not set
 # CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_NLS_ISO8859_2 is not set
@@ -616,109 +626,15 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-# CONFIG_USB_HID is not set
-# CONFIG_USB_HIDDEV is not set
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_WACOM is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_PWC is not set
-# CONFIG_USB_SE401 is not set
-# CONFIG_USB_DSBR is not set
-# CONFIG_USB_DABUSB is not set
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
 # Kernel hacking
 #
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_KGDB is not set
 # CONFIG_XMON is not set
+# CONFIG_KDB is not set
+# CONFIG_KDB_OFF is not set
+# CONFIG_KALLSYMS is not set
 # CONFIG_PPCDBG is not set
+CONFIG_DUMP=y
+CONFIG_DUMP_COMPRESS_RLE=y
+CONFIG_DUMP_COMPRESS_GZIP=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/configs/pSeries_defconfig linux-2.4.20/arch/ppc64/configs/pSeries_defconfig
--- linux-2.4.19/arch/ppc64/configs/pSeries_defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/configs/pSeries_defconfig	2002-10-29 11:18:36.000000000 +0000
@@ -25,6 +25,7 @@
 CONFIG_IRQ_ALL_CPUS=y
 # CONFIG_HMT is not set
 # CONFIG_MSCHUNKS is not set
+CONFIG_RTAS_FLASH=m
 
 #
 # Loadable module support
@@ -61,6 +62,9 @@
 CONFIG_FB=y
 CONFIG_PROC_DEVICETREE=y
 
+CONFIG_CMDLINE_BOOL=n
+CONFIG_CMDLINE="console=ttyS0,9600 console=tty0 root=/dev/sda2"
+
 #
 # Memory Technology Devices (MTD)
 #
@@ -80,7 +84,9 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_NBD=y
 CONFIG_BLK_DEV_RAM=y
@@ -128,6 +134,11 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -145,6 +156,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 CONFIG_IDE=y
@@ -161,6 +177,7 @@
 # CONFIG_BLK_DEV_HD is not set
 # CONFIG_BLK_DEV_IDEDISK is not set
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -175,6 +192,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -186,12 +204,15 @@
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 # CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -199,6 +220,7 @@
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
@@ -349,6 +371,7 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_TULIP is not set
+# CONFIG_TC35815 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
@@ -380,12 +403,12 @@
 CONFIG_ACENIC=y
 # CONFIG_ACENIC_OMIT_TIGON_I is not set
 # CONFIG_DL2K is not set
-CONFIG_E1000=y
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -403,6 +426,7 @@
 CONFIG_TR=y
 CONFIG_IBMOL=y
 # CONFIG_IBMLS is not set
+# CONFIG_3C359 is not set
 # CONFIG_TMS380TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_RCPCI is not set
@@ -445,6 +469,7 @@
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_CLGEN is not set
 # CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_OF=y
 # CONFIG_FB_CONTROL is not set
@@ -464,6 +489,7 @@
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
@@ -517,6 +543,7 @@
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
 
 #
 # Joysticks
@@ -536,7 +563,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_RTC is not set
@@ -577,7 +603,7 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
@@ -691,112 +717,16 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_PWC is not set
-# CONFIG_USB_SE401 is not set
-# CONFIG_USB_STV680 is not set
-# CONFIG_USB_VICAM is not set
-# CONFIG_USB_DSBR is not set
-# CONFIG_USB_DABUSB is not set
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
 # Kernel hacking
 #
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_KGDB is not set
-CONFIG_XMON=y
+# CONFIG_XMON is not set
+CONFIG_KDB=y
+# CONFIG_KDB_OFF is not set
+# CONFIG_KALLSYMS is not set
 CONFIG_PPCDBG=y
+
+CONFIG_DUMP=y
+CONFIG_DUMP_COMPRESS_RLE=y
+CONFIG_DUMP_COMPRESS_GZIP=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/defconfig linux-2.4.20/arch/ppc64/defconfig
--- linux-2.4.19/arch/ppc64/defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/defconfig	2002-10-29 11:18:40.000000000 +0000
@@ -25,6 +25,7 @@
 CONFIG_IRQ_ALL_CPUS=y
 # CONFIG_HMT is not set
 # CONFIG_MSCHUNKS is not set
+CONFIG_RTAS_FLASH=m
 
 #
 # Loadable module support
@@ -61,6 +62,9 @@
 CONFIG_FB=y
 CONFIG_PROC_DEVICETREE=y
 
+CONFIG_CMDLINE_BOOL=n
+CONFIG_CMDLINE="console=ttyS0,9600 console=tty0 root=/dev/sda2"
+
 #
 # Memory Technology Devices (MTD)
 #
@@ -80,7 +84,9 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_NBD=y
 CONFIG_BLK_DEV_RAM=y
@@ -128,6 +134,11 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -145,6 +156,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 CONFIG_IDE=y
@@ -161,6 +177,7 @@
 # CONFIG_BLK_DEV_HD is not set
 # CONFIG_BLK_DEV_IDEDISK is not set
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -175,6 +192,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -186,12 +204,15 @@
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 # CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -199,6 +220,7 @@
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
@@ -349,6 +371,7 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_TULIP is not set
+# CONFIG_TC35815 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
@@ -378,14 +401,14 @@
 # Ethernet (1000 Mbit)
 #
 CONFIG_ACENIC=y
-# CONFIG_ACENIC_OMIT_TIGON_I is not set
+CONFIG_ACENIC_OMIT_TIGON_I=y
 # CONFIG_DL2K is not set
-CONFIG_E1000=y
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -403,6 +426,7 @@
 CONFIG_TR=y
 CONFIG_IBMOL=y
 # CONFIG_IBMLS is not set
+# CONFIG_3C359 is not set
 # CONFIG_TMS380TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_RCPCI is not set
@@ -445,6 +469,7 @@
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_CLGEN is not set
 # CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_OF=y
 # CONFIG_FB_CONTROL is not set
@@ -464,6 +489,7 @@
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
@@ -517,6 +543,7 @@
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
 
 #
 # Joysticks
@@ -536,7 +563,6 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_RTC is not set
@@ -577,7 +603,7 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
@@ -691,112 +717,16 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_PWC is not set
-# CONFIG_USB_SE401 is not set
-# CONFIG_USB_STV680 is not set
-# CONFIG_USB_VICAM is not set
-# CONFIG_USB_DSBR is not set
-# CONFIG_USB_DABUSB is not set
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
 # Kernel hacking
 #
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_KGDB is not set
-CONFIG_XMON=y
+# CONFIG_XMON is not set
+CONFIG_KDB=y
+# CONFIG_KDB_OFF is not set
+# CONFIG_KALLSYMS is not set
 CONFIG_PPCDBG=y
+
+CONFIG_DUMP=y
+CONFIG_DUMP_COMPRESS_RLE=y
+CONFIG_DUMP_COMPRESS_GZIP=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/LparData.c linux-2.4.20/arch/ppc64/kernel/LparData.c
--- linux-2.4.19/arch/ppc64/kernel/LparData.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/LparData.c	2002-10-29 11:18:32.000000000 +0000
@@ -6,14 +6,12 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#define __KERNEL__ 1
 #include <asm/types.h>
 #include <asm/page.h>
 #include <stddef.h>
 #include <linux/threads.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
-#include <asm/init.h>
 #include <asm/naca.h>
 #include <asm/abs_addr.h>
 #include <asm/bitops.h>
@@ -25,6 +23,7 @@
 #include <asm/iSeries/LparMap.h>
 #include <asm/iSeries/ItVpdAreas.h>
 #include <asm/iSeries/ItIplParmsReal.h>
+#include <asm/iSeries/ItExtVpdPanel.h>
 #include <asm/iSeries/ItLpQueue.h>
 #include <asm/iSeries/IoHriProcessorVpd.h>
 #include <asm/iSeries/ItSpCommArea.h>
@@ -144,6 +143,8 @@
 
 struct ItIplParmsReal xItIplParmsReal = {};
 
+struct ItExtVpdPanel xItExtVpdPanel = {};
+
 #define maxPhysicalProcessors 32
 
 struct IoHriProcessorVpd xIoHriProcessorVpd[maxPhysicalProcessors] = {
@@ -185,7 +186,8 @@
 	{0},		/* DMA lengths */
 	{0},		/* DMA tokens */
 	{		/* VPD lengths */
-		0,0,0,0,		/*  0 -  3 */
+	        0,0,0,		        /*  0 - 2 */
+		sizeof(xItExtVpdPanel), /*       3 Extended VPD   */
 		sizeof(struct paca_struct),	/*       4 length of Paca  */
 		0,			/*       5 */
 		sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */
@@ -202,7 +204,8 @@
 		0,0			/* 24 - 25 */
 		},
 	{			/* VPD addresses */
-		0,0,0,0,		/*	 0 -  3 */
+		0,0,0,  		/*	 0 -  2 */
+		&xItExtVpdPanel,        /*       3 Extended VPD */
 		&paca[0],		/*       4 first Paca */
 		0,			/*       5 */
 		&xItIplParmsReal,	/*	 6 IPL parms */
@@ -244,7 +247,3 @@
 
 	return mem;
 }
-
-
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/Makefile linux-2.4.20/arch/ppc64/kernel/Makefile
--- linux-2.4.19/arch/ppc64/kernel/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/Makefile	2002-10-29 11:18:39.000000000 +0000
@@ -27,19 +27,21 @@
 			pmc.o mf_proc.o proc_pmc.o proc_pcifr.o iSeries_setup.o \
 			ItLpQueue.o hvCall.o mf.o HvLpEvent.o ras.o \
 			iSeries_proc.o HvCall.o flight_recorder.o HvLpConfig.o \
-			rtc.o
+			rtc.o perfmon.o
 
-obj-$(CONFIG_PCI) +=  pci.o pci_dn.o pci_dma.o
+obj-$(CONFIG_PCI) +=  pci.o pci_dn.o pci_dma.o pSeries_lpar.o pSeries_hvCall.o
 
 ifeq ($(CONFIG_PPC_ISERIES),y)
 obj-$(CONFIG_PCI) += iSeries_pci.o iSeries_pci_reset.o iSeries_IoMmTable.o iSeries_irq.o iSeries_VpdInfo.o XmPciLpEvent.o 
 endif
 ifeq ($(CONFIG_PPC_PSERIES),y)
-obj-$(CONFIG_PCI) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o eeh.o
+obj-$(CONFIG_PCI) += pSeries_pci.o eeh.o
 
 obj-y += rtasd.o nvram.o
 endif
 
+obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o
+
 obj-$(CONFIG_KGDB) += ppc-stub.o
 
 obj-$(CONFIG_SMP) += smp.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/XmPciLpEvent.c linux-2.4.20/arch/ppc64/kernel/XmPciLpEvent.c
--- linux-2.4.19/arch/ppc64/kernel/XmPciLpEvent.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/XmPciLpEvent.c	2002-10-29 11:18:31.000000000 +0000
@@ -14,22 +14,32 @@
 #include <linux/bootmem.h>
 #include <linux/blk.h>
 #include <linux/ide.h>
+#include <linux/rtc.h>
+#include <linux/time.h>
 
 #include <asm/iSeries/HvTypes.h>
 #include <asm/iSeries/HvLpEvent.h>
 #include <asm/iSeries/HvCallPci.h>
 #include <asm/iSeries/XmPciLpEvent.h>
 #include <asm/ppcdebug.h>
+#include <asm/time.h>
+#include <asm/flight_recorder.h>
+
+extern struct flightRecorder* PciFr;
+
 
 long Pci_Interrupt_Count = 0;
 long Pci_Event_Count     = 0;
 
 enum XmPciLpEvent_Subtype {
 	XmPciLpEvent_BusCreated	   = 0,		// PHB has been created
-	XmPciLpEvent_BusFailed	   = 1,		// PHB has failed
-	XmPciLpEvent_BusRecovered  = 12,	// PHB has been recovered
+	XmPciLpEvent_BusError	   = 1,		// PHB has failed
+	XmPciLpEvent_BusFailed	   = 2,		// Msg to Seconday, Primary failed bus
 	XmPciLpEvent_NodeFailed	   = 4,		// Multi-adapter bridge has failed
 	XmPciLpEvent_NodeRecovered = 5,		// Multi-adapter bridge has recovered
+	XmPciLpEvent_BusRecovered  = 12,	// PHB has been recovered
+	XmPciLpEvent_UnQuiesceBus  = 18,	// Secondary bus unqiescing
+	XmPciLpEvent_BridgeError   = 21,	// Bridge Error
 	XmPciLpEvent_SlotInterrupt = 22		// Slot interrupt
 };
 
@@ -69,6 +79,7 @@
 };
 
 static void intReceived(struct XmPciLpEvent* eventParm, struct pt_regs* regsParm);
+static void logXmEvent( char* ErrorText, int busNumber);
 
 static void XmPciLpEvent_handler( struct HvLpEvent* eventParm, struct pt_regs* regsParm)
 {
@@ -81,10 +92,10 @@
 			intReceived( (struct XmPciLpEvent*)eventParm, regsParm );
 			break;
 		case HvLpEvent_Function_Ack:
-			printk(KERN_ERR "XmPciLpEvent.c: unexpected ack received\n");
+			printk(KERN_ERR "XmPciLpEvent.c: Unexpected ack received\n");
 			break;
 		default:
-			printk(KERN_ERR "XmPciLpEvent.c: unexpected event function %d\n",(int)eventParm->xFlags.xFunction);
+			printk(KERN_ERR "XmPciLpEvent.c: Unexpected event function %d\n",(int)eventParm->xFlags.xFunction);
 			break;
 		}
 	}
@@ -114,23 +125,25 @@
 		break;
 		/* Ignore error recovery events for now */
 	case XmPciLpEvent_BusCreated:
-		printk(KERN_INFO "XmPciLpEvent.c: system bus %d created\n", eventParm->eventData.busCreated.busNumber);
+	        logXmEvent("System bus created.",eventParm->eventData.busCreated.busNumber);
 		break;
+	case XmPciLpEvent_BusError:
 	case XmPciLpEvent_BusFailed:
-		printk(KERN_INFO "XmPciLpEvent.c: system bus %d failed\n", eventParm->eventData.busFailed.busNumber);
+		logXmEvent("System bus failed.", eventParm->eventData.busFailed.busNumber);
 		break;
 	case XmPciLpEvent_BusRecovered:
-		printk(KERN_INFO "XmPciLpEvent.c: system bus %d recovered\n", eventParm->eventData.busRecovered.busNumber);
+	case XmPciLpEvent_UnQuiesceBus:
+		logXmEvent("System bus recovered.",eventParm->eventData.busRecovered.busNumber);
 		break;
 	case XmPciLpEvent_NodeFailed:
-		printk(KERN_INFO "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d failed\n", eventParm->eventData.nodeFailed.busNumber, eventParm->eventData.nodeFailed.subBusNumber, eventParm->eventData.nodeFailed.deviceId);
-		break;
+	case XmPciLpEvent_BridgeError:
+	        logXmEvent("Multi-adapter bridge failed.",eventParm->eventData.nodeFailed.busNumber);
+	        break;
 	case XmPciLpEvent_NodeRecovered:
-		printk(KERN_INFO "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d recovered\n", eventParm->eventData.nodeRecovered.busNumber, eventParm->eventData.nodeRecovered.subBusNumber, eventParm->eventData.nodeRecovered.deviceId);
+		logXmEvent("Multi-adapter bridge recovered",eventParm->eventData.nodeRecovered.busNumber);
 		break;
 	default:
-		printk(KERN_ERR "XmPciLpEvent.c: unrecognized event subtype 0x%x\n",
-		       eventParm->hvLpEvent.xSubtype);
+	        logXmEvent("Unrecognized event subtype.",eventParm->hvLpEvent.xSubtype);
 		break;
 	};
 }
@@ -154,4 +167,25 @@
     	}
     return xRc;
 }
+/***********************************************************************/
+/* printk                                                              */
+/*   XmPciLpEvent: System bus failed, bus 0x4A. Time:128-16.10.44      */
+/* pcifr                                                               */
+/*  0045. XmPciLpEvent: System bus failed, bus 0x4A. Time:128-16.10.44 */
+/***********************************************************************/
+static void logXmEvent( char* ErrorText, int busNumber) {
+	struct  timeval  TimeClock;
+	struct  rtc_time CurTime;
+
+	do_gettimeofday(&TimeClock);
+	to_tm(TimeClock.tv_sec, &CurTime);
+	char    EventLog[128];
+
+	sprintf(EventLog,"XmPciLpEvent: %s, Bus:0x%03X.  Time:%02d.%02d.%02d",
+		ErrorText,busNumber,
+		CurTime.tm_hour,CurTime.tm_min,CurTime.tm_sec);
+
+	fr_Log_Entry(PciFr,EventLog);
+	printk(KERN_INFO "%s\n",EventLog);
+}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/align.c linux-2.4.20/arch/ppc64/kernel/align.c
--- linux-2.4.19/arch/ppc64/kernel/align.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/align.c	2002-10-29 11:18:36.000000000 +0000
@@ -238,7 +238,7 @@
 	dsisr = regs->dsisr;
 
 	/* Power4 doesn't set DSISR for an alignment interrupt */
-	if (__is_processor(PV_POWER4))
+	if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p))
 		dsisr = make_dsisr( *((unsigned *)regs->nip) );
 
 	/* extract the operation and registers from the dsisr */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/chrp_setup.c linux-2.4.20/arch/ppc64/kernel/chrp_setup.c
--- linux-2.4.19/arch/ppc64/kernel/chrp_setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/chrp_setup.c	2002-10-29 11:18:49.000000000 +0000
@@ -102,6 +102,8 @@
 extern int probingmem;
 extern unsigned long loops_per_jiffy;
 
+extern unsigned long ppc_proc_freq;
+extern unsigned long ppc_tb_freq;
 #ifdef CONFIG_BLK_DEV_RAM
 extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
 extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
@@ -114,6 +116,8 @@
 	struct device_node *root;
 	const char *model = "";
 
+	seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq);
+
 	root = find_path_device("/");
 	if (root)
 		model = get_property(root, "model", NULL);
@@ -174,7 +178,6 @@
 		for (openpic = 0; n > 0; --n)
 			openpic = (openpic << 32) + *opprop++;
 		printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic);
-		udbg_printf("OpenPIC addr: %lx\n", openpic);
 		OpenPIC_Addr = __ioremap(openpic, 0x40000, _PAGE_NO_CACHE);
 	}
 
@@ -191,7 +194,9 @@
 	 * -- tibit
 	 */
 	chrp_request_regions();
-	ppc_md.progress(UTS_RELEASE, 0x7777);
+	/* Manually leave the kernel version on the panel. */
+	ppc_md.progress("Linux ppc64\n", 0);
+	ppc_md.progress(UTS_RELEASE, 0);
 }
 
 /* Initialize firmware assisted non-maskable interrupts if
@@ -259,11 +264,9 @@
 	if(naca->interrupt_controller == IC_OPEN_PIC) {
 		ppc_md.init_IRQ       = openpic_init_IRQ; 
 		ppc_md.get_irq        = openpic_get_irq;
-		ppc_md.post_irq	      = NULL;
 	} else {
 		ppc_md.init_IRQ       = xics_init_IRQ;
 		ppc_md.get_irq        = xics_get_irq;
-		ppc_md.post_irq	      = NULL;
 	}
 	ppc_md.init_ras_IRQ = init_ras_IRQ;
 
@@ -301,8 +304,6 @@
 	SYSRQ_KEY = 0x63;	/* Print Screen */
 #endif
 #endif
-	
-	ppc_md.progress("Linux ppc64\n", 0x0);
 }
 
 void __chrp
@@ -314,10 +315,7 @@
 	static int display_character, set_indicator;
 	static int max_width;
 
-	if (hex)
-		udbg_printf("<chrp_progress> %s\n", s);
-
-	if (!rtas.base || (naca->platform != PLATFORM_PSERIES))
+	if (!rtas.base)
 		return;
 
 	if (max_width == 0) {
@@ -363,9 +361,6 @@
 
 extern void setup_default_decr(void);
 
-extern unsigned long ppc_proc_freq;
-extern unsigned long ppc_tb_freq;
-
 void __init pSeries_calibrate_decr(void)
 {
 	struct device_node *cpu;
@@ -401,7 +396,6 @@
 	tb_ticks_per_jiffy = freq / HZ;
 	tb_ticks_per_sec = tb_ticks_per_jiffy * HZ;
 	tb_ticks_per_usec = freq / 1000000;
-	tb_to_us = mulhwu_scale_factor(freq, 1000000);
 	div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres );
 	tb_to_xs = divres.result_low;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/eeh.c linux-2.4.20/arch/ppc64/kernel/eeh.c
--- linux-2.4.19/arch/ppc64/kernel/eeh.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/eeh.c	2002-10-29 11:18:39.000000000 +0000
@@ -59,15 +59,14 @@
 	return ((IO_UNMAPPED_REGION_ID << 60) | (phb << 48UL) | ((bus & 0xff) << 40UL) | (devfn << 32UL) | (offset & 0xffffffff));
 }
 
-
-
-int eeh_get_state(unsigned long ea) {
+int eeh_get_state(unsigned long ea)
+{
 	return 0;
 }
 
-
 /* Check for an eeh failure at the given token address.
- * The given value has been read and it should be 1's (0xff, 0xffff or 0xffffffff).
+ * The given value has been read and it should be 1's (0xff, 0xffff or
+ * 0xffffffff).
  *
  * Probe to determine if an error actually occurred.  If not return val.
  * Otherwise panic.
@@ -113,7 +112,8 @@
 	return val;	/* good case */
 }
 
-void eeh_init(void) {
+void eeh_init(void)
+{
 	extern char cmd_line[];	/* Very early cmd line parse.  Cheap, but works. */
 	char *eeh_force_off = strstr(cmd_line, "eeh-force-off");
 	char *eeh_force_on = strstr(cmd_line, "eeh-force-on");
@@ -334,6 +334,7 @@
 {
 	return eeh_parm(str, 0);
 }
+
 static int __init eehon_parm(char *str)
 {
 	return eeh_parm(str, 1);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/entry.S linux-2.4.20/arch/ppc64/kernel/entry.S
--- linux-2.4.19/arch/ppc64/kernel/entry.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/entry.S	2002-10-29 11:18:33.000000000 +0000
@@ -305,9 +305,7 @@
 	cmpdi	0,r5,0
 	beq	4f
 irq_recheck:
-	/*
-	 * Check for pending interrupts (iSeries)
-	 */
+	/* Check for pending interrupts (iSeries) */
 	CHECKANYINT(r3,r4)
 	beq+	4f	/* skip do_IRQ if no interrupts */
 
@@ -346,6 +344,7 @@
 	mtlr	r0
 	ld	r3,_XER(r1)
 	mtspr	XER,r3
+
 	REST_8GPRS(5, r1)
 	REST_10GPRS(14, r1)
 	REST_8GPRS(24, r1)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/head.S linux-2.4.20/arch/ppc64/kernel/head.S
--- linux-2.4.19/arch/ppc64/kernel/head.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/head.S	2002-10-29 11:18:31.000000000 +0000
@@ -31,7 +31,7 @@
 #include <asm/page.h>
 #include <linux/config.h>
 #include <asm/mmu.h>
-// #include <asm/paca.h>
+#include <asm/perfmon.h>
 
 #ifdef CONFIG_PPC_ISERIES
 #define DO_SOFT_DISABLE
@@ -154,12 +154,13 @@
  */
 
 /*
- * We make as much of the exception code common between native Pseries
- * and Iseries LPAR implementations as possible.
+ * We make as much of the exception code common between native
+ * exception handlers (including pSeries LPAR) and iSeries LPAR
+ * implementations as possible.
  */
 
 /*
- * This is the start of the interrupt handlers for Pseries
+ * This is the start of the interrupt handlers for pSeries
  * This code runs with relocation off.
  */
 #define EX_SRR0		0
@@ -200,13 +201,13 @@
 	rfid
 
 /*
- * This is the start of the interrupt handlers for i_series
+ * This is the start of the interrupt handlers for iSeries
  * This code runs with relocation on.
  */
 #define EXCEPTION_PROLOG_ISERIES(n)	                                      \
 	mtspr	SPRG2,r20;		    /* use SPRG2 as scratch reg    */ \
 	mtspr   SPRG1,r21;                  /* save r21                    */ \
-	mfspr	r20,SPRG3;		    /* get Paca                    */ \
+	mfspr	r20,SPRG3;		    /* get paca                    */ \
 	ld      r21,PACAEXCSP(r20);         /* get exception stack ptr     */ \
 	addi    r21,r21,EXC_FRAME_SIZE;     /* make exception frame        */ \
 	std	r22,EX_R22(r21);	    /* save r22 on exception frame */ \
@@ -302,9 +303,9 @@
 	.globl label##_Iseries;			\
 label##_Iseries:				\
 	EXCEPTION_PROLOG_ISERIES( n );		\
-	lbz	r22,PACAPROFENABLED(r20);	\
-	cmpi	0,r22,0;			\
-	bne-	label##_Iseries_profile;	\
+	lbz	r22,PACAPROFMODE(r20);		\
+	cmpi	0,r22,PMC_STATE_DECR_PROFILE;	\
+	beq-	label##_Iseries_profile;	\
 label##_Iseries_prof_ret:			\
 	lbz	r22,PACAPROCENABLED(r20);	\
 	cmpi	0,r22,0;			\
@@ -359,7 +360,7 @@
 
 	/* Space for the naca.  Architected to be located at real address
 	 * 0x4000.  Various tools rely on this location being fixed.
-	 * The first dword of the Naca is required by iSeries LPAR to
+	 * The first dword of the naca is required by iSeries LPAR to
 	 * point to itVpdAreas.  On pSeries native, this value is not used.
 	 */
 	. = 0x4000
@@ -430,7 +431,7 @@
 	STD_EXCEPTION_ISERIES( 0xc00, SystemCall )
 	STD_EXCEPTION_ISERIES( 0xd00, SingleStep )
 	STD_EXCEPTION_ISERIES( 0xe00, Trap_0e )
-	STD_EXCEPTION_ISERIES( 0xf00, PerformanceMonitor )
+	MASKABLE_EXCEPTION_ISERIES( 0xf00, PerformanceMonitor )
 
 	.globl SystemReset_Iseries
 SystemReset_Iseries:
@@ -484,6 +485,12 @@
 HardwareInterrupt_Iseries_masked:
 	b	maskable_exception_exit
 
+	.globl PerformanceMonitor_Iseries_masked
+PerformanceMonitor_Iseries_masked:
+	li	r22,1
+	stb	r22,PACALPPACA+LPPACAPDCINT(r20)
+	b	maskable_exception_exit
+
 	.globl Decrementer_Iseries_masked
 Decrementer_Iseries_masked:
 	li	r22,1
@@ -529,7 +536,6 @@
 	STD_EXCEPTION_COMMON( 0xb00, Trap_0b, .UnknownException )
 	STD_EXCEPTION_COMMON( 0xd00, SingleStep, .SingleStepException )
 	STD_EXCEPTION_COMMON( 0xe00, Trap_0e, .UnknownException )
-	STD_EXCEPTION_COMMON( 0xf00, PerformanceMonitor, .PerformanceMonitorException )
 	STD_EXCEPTION_COMMON(0x1300, InstructionBreakpoint, .InstructionBreakpointException )
 
 /*
@@ -583,7 +589,8 @@
 	bl	.do_stab_SI
 	b	1f
 
-2:	bl	.do_hash_page_DSI 	/* Try to handle as hpte fault */
+2:	li	r5,0x300
+	bl	.do_hash_page_DSI 	/* Try to handle as hpte fault */
 1:
 	ld      r4,_DAR(r1)
 	ld      r5,_DSISR(r1)
@@ -668,7 +675,7 @@
 #else
 	rldicl	r20,r23,49,63   	/* copy EE bit from saved MSR */
 #endif
-	li	r6,0x380
+	li	r6,0x480
 	bl      .save_remaining_regs
 	bl      .do_page_fault
 	b       .ret_from_except
@@ -787,6 +794,150 @@
 	bl      .DoSyscall
 	b       .ret_from_except
 
+	.globl PerformanceMonitor_common
+PerformanceMonitor_common:	
+	EXCEPTION_PROLOG_COMMON
+	bl	.PerformanceMonitorException
+	b	fast_exception_return
+	
+_GLOBAL(PerformanceMonitorException)
+	mfspr	r7,SPRG3
+	lbz	r8,PACAPROFMODE(r7)
+	cmpi	0,r8,PMC_STATE_PROFILE_KERN
+	beq 	5f
+	cmpi	0,r8,PMC_STATE_TRACE_KERN
+	beq 	6f
+	cmpi	0,r8,PMC_STATE_TRACE_USER
+	beq 	9f
+	blr
+
+	/* PMC Profile Kernel */
+5:	mfspr   r9,SIAR	
+	srdi    r8,r9,60
+	cmpi    0,r8,0xc
+	beq     3f
+	li	r9,0xc
+	sldi	r9,r9,60
+3:      ld	r8,PACAPROFSTEXT(r7)	/* _stext */
+	subf	r9,r8,r9		/* offset into kernel */
+	lwz	r8,PACAPROFSHIFT(r7)
+	srd	r9,r9,r8
+	lwz	r8,PACAPROFLEN(r7)	/* length of profile table (-1) */
+	srdi	r8,r8,2
+	cmpd	r9,r8		/* off end? */
+	ble	1f
+	mr	r9,r8			/* force into last entry */
+	srdi	r9,r9,2
+1:	sldi	r9,r9,2		/* convert to offset into buffer */
+	ld	r8,PACAPROFBUFFER(r7)	/* profile buffer */
+	add	r8,r8,r9
+2:	lwarx	r9,0,r8		/* atomically increment */
+	addi	r9,r9,1
+	stwcx.	r9,0,r8
+	bne-	2b
+	addi	r10,r7,PACAPMC1
+	addi	r7,r7,PACAPMCC1
+	b	7f
+
+	/* PMC Trace Kernel */
+6:	LOADADDR(r11, perfmon_base)
+  	addi	r8,r11,32
+	ld	r12,24(r11)
+	subi	r12,r12,1
+8:	ldarx	r10,0,r8
+	addi	r9,r10,16
+	and	r9,r9,r12
+	stdcx.	r9,0,r8
+	bne-	8b
+	ld	r9,16(r11)	/* profile buffer */
+	add	r8,r9,r10
+  	mfspr   r9,SIAR	
+	std	r9,0(r8)
+	mfspr   r9,SDAR	
+	std	r9,8(r8)
+	addi	r10,r7,PACAPMC1
+	addi	r7,r7,PACAPMCC1
+	b	7f
+
+	/* PMC Trace User */
+9:	LOADADDR(r11, perfmon_base)
+#if 0
+  	addi	r8,r11,32
+	ld	r12,24(r11)
+	subi	r12,r12,1
+8:	ldarx	r10,0,r8
+	addi	r9,r10,16
+	and	r9,r9,r12
+	stdcx.	r9,0,r8
+	bne-	8b
+	ld	r9,16(r11)	/* profile buffer */
+	add	r8,r9,r10
+  	mfspr   r9,SIAR	
+	std	r9,0(r8)
+	mfspr   r9,SDAR	
+	std	r9,8(r8)
+	addi	r10,r13,THREAD+THREAD_PMC1
+	addi	r7,r13,THREAD+THREAD_PMCC1
+#endif
+	/* Accumulate counter values for kernel traces */
+7:	ld	r9,0(r7)
+	mfspr   r8,PMC1	
+	add	r9,r9,r8
+	std	r9,0(r7)
+	ld	r9,8(r7)
+	mfspr	r8,PMC2
+	add	r9,r9,r8
+	std	r9,8(r7)
+	ld	r9,16(r7)
+	mfspr	r8,PMC3
+	add	r9,r9,r8
+	std	r9,16(r7)
+	ld	r9,24(r7)
+	mfspr	r8,PMC4
+	add	r9,r9,r8
+	std	r9,24(r7)
+	ld	r9,32(r7)
+	mfspr	r8,PMC5
+	add	r9,r9,r8
+	std	r9,32(r7)
+	ld	r9,40(r7)
+	mfspr	r8,PMC6
+	add	r9,r9,r8
+	std	r9,40(r7)
+	ld	r9,48(r7)
+	mfspr	r8,PMC7
+	add	r9,r9,r8
+	std	r9,48(r7)
+	ld	r9,56(r7)
+	mfspr	r8,PMC8
+	add	r9,r9,r8
+	std	r9,56(r7)
+
+	/* Reset all counters for kernel traces */
+	lwz	r9,0(r10)
+	mtspr	PMC1,r9
+	lwz	r9,4(r10)
+	mtspr	PMC2,r9
+	lwz	r9,8(r10)
+	mtspr	PMC3,r9
+	lwz	r9,12(r10)
+	mtspr	PMC4,r9
+	lwz	r9,16(r10)
+	mtspr	PMC5,r9
+	lwz	r9,20(r10)
+	mtspr	PMC6,r9
+	lwz	r9,24(r10)
+	mtspr	PMC7,r9
+	lwz	r9,28(r10)
+	mtspr	PMC8,r9
+	lwz	r9,32(r10)
+	mtspr	MMCR0,r9
+	lwz	r9,36(r10)
+	mtspr	MMCR1,r9
+	lwz	r9,40(r10)
+	mtspr	MMCRA,r9
+	blr
+
 _GLOBAL(do_hash_page_ISI)
 	li	r4,0
 _GLOBAL(do_hash_page_DSI)
@@ -812,6 +963,7 @@
 	/*
 	 * r3 contains the faulting address
 	 * r4 contains the required access permissions
+	 * r5 contains the trap number
 	 *
 	 * at return r3 = 0 for success
 	 */
@@ -1029,6 +1181,13 @@
 	ori	r20,r20,256    /* map kernel region with large ptes */
 #endif
 	
+	/* Invalidate the old entry */
+	slbmfee	r21,r22
+	lis	r23,-2049
+	ori	r23,r23,65535
+	and	r21,r21,r23
+	slbie	r21
+
 	/* Put together the esid portion of the entry. */
 	mfspr	r21,DAR        /* Get the new esid                     */
 	rldicl  r21,r21,36,28  /* Permits a full 36b of ESID           */
@@ -1104,7 +1263,7 @@
 
 	/*
 	 * Indicate that r1 contains the kernel stack and
-	 * get the Kernel TOC and CURRENT pointers from the Paca
+	 * get the Kernel TOC and CURRENT pointers from the paca
 	 */
 	mfspr	r23,SPRG3		/* Get PACA */
 	std	r22,PACAKSAVE(r23)	/* r1 is now kernel sp */
@@ -1129,7 +1288,9 @@
 	mtmsrd  r22
 	blr
 
-
+/*
+ * Kernel profiling with soft disable on iSeries
+ */
 do_profile:
 	ld	r22,8(r21)		/* Get SRR1 */
 	andi.	r22,r22,MSR_PR		/* Test if in kernel */
@@ -1163,7 +1324,7 @@
 	bl	.enable_64b_mode
 	isync
 
-	/* Set up a Paca value for this processor. */
+	/* Set up a paca value for this processor. */
 	LOADADDR(r24, paca) 		 /* Get base vaddr of Paca array  */
 	mulli	r25,r3,PACA_SIZE	 /* Calculate vaddr of right Paca */
 	add	r25,r25,r24              /* for this processor.           */
@@ -1208,7 +1369,7 @@
 	std	r4,0(r9)		/* set the naca pointer */
 
 	/* Get the pointer to the segment table */
-	ld	r6,PACA(r4)             /* Get the base Paca pointer       */
+	ld	r6,PACA(r4)             /* Get the base paca pointer       */
 	ld	r4,PACASTABVIRT(r6)
 
 	bl      .iSeries_fixup_klimit
@@ -1316,17 +1477,10 @@
 					/* executed here.                 */
 
         LOADADDR(r0, 4f)                /* Jump to the copy of this code  */
-	mtctr	r0			/* that we just made              */
+	mtctr	r0			/* that we just made/relocated    */
 	bctr
 
-4:	LOADADDR(r9,rtas)
-	sub	r9,r9,r26
-	ld	r5,RTASBASE(r9)		/* get the value of rtas->base */
-	ld	r9,RTASSIZE(r9)		/* get the value of rtas->size */
-	bl	.copy_and_flush		/* copy upto rtas->base */
-	add     r6,r6,r9		/* then skip over rtas->size bytes */
-
-	LOADADDR(r5,klimit)
+4:	LOADADDR(r5,klimit)
 	sub	r5,r5,r26
 	ld	r5,0(r5)		/* get the value of klimit */
 	sub	r5,r5,r27
@@ -1470,15 +1624,15 @@
 /*
  * This function is called after the master CPU has released the
  * secondary processors.  The execution environment is relocation off.
- * The Paca for this processor has the following fields initialized at
+ * The paca for this processor has the following fields initialized at
  * this point:
  *   1. Processor number
  *   2. Segment table pointer (virtual address)
  * On entry the following are set:
  *   r1    = stack pointer.  vaddr for iSeries, raddr (temp stack) for pSeries
  *   r24   = cpu# (in Linux terms)
- *   r25   = Paca virtual address
- *   SPRG3 = Paca virtual address
+ *   r25   = paca virtual address
+ *   SPRG3 = paca virtual address
  */
 _GLOBAL(__secondary_start)
 
@@ -1523,15 +1677,19 @@
 	sc				/* HvCall_setASR */
 #else
 	/* set the ASR */
-	addi  r3,0,0x4000     /* r3 = ptr to naca */
-	lhz   r3,PLATFORM(r3) /* r3 = platform flags */
-	cmpldi r3,PLATFORM_PSERIES_LPAR
-	bne   98f
-	li	r3,H_SET_ASR  /* hcall = H_SET_ASR */
-	HSC     			    /* Invoking hcall */
-	b     99f
-98:             /* This is not a hypervisor machine */
-	mtasr	r4			/* set the stab location            */
+	addi	r3,0,0x4000     /* r3 = ptr to naca */
+	lhz   	r3,PLATFORM(r3) /* r3 = platform flags */
+	cmpldi 	r3,PLATFORM_PSERIES_LPAR
+	bne   	98f
+	mfspr	r3,PVR
+	srwi	r3,r3,16
+	cmpwi	r3,0x37         /* SStar */
+	bne	98f
+	li	r3,H_SET_ASR    /* hcall = H_SET_ASR */
+	HSC     		/* Invoking hcall */
+	b	99f
+98:                             /* !(rpa hypervisor) || !(sstar) */
+	mtasr	r4	        /* set the stab location         */
 99:
 #endif
 	li	r7,0
@@ -1651,9 +1809,6 @@
 	addi    r2,r2,0x4000
 	sub	r2,r2,r26
 
-	/* Init naca->debug_switch so it can be used in stab & htab init.  */
-	bl	.ppcdbg_initialize
-
 	/* Get the pointer to the segment table which is used by           */
 	/* stab_initialize                                                 */
 	li	r27,0x4000
@@ -1662,15 +1817,19 @@
 	mtspr	SPRG3,r6		/* PPPBBB: Temp... -Peter */
 	ld	r3,PACASTABREAL(r6)
 	ori	r4,r3,1			/* turn on valid bit                */
-	
+
 	/* set the ASR */
-	addi  r3,0,0x4000     /* r3 = ptr to naca */
-	lhz   r3,PLATFORM(r3) /* r3 = platform flags */
-	cmpldi r3,PLATFORM_PSERIES_LPAR
-	bne   98f
-	li	r3,H_SET_ASR  /* hcall = H_SET_ASR */
-	HSC     			    /* Invoking hcall */
-	b     99f
+	addi	r3,0,0x4000     /* r3 = ptr to naca */
+	lhz   	r3,PLATFORM(r3) /* r3 = platform flags */
+	cmpldi 	r3,PLATFORM_PSERIES_LPAR
+	bne   	98f
+	mfspr	r3,PVR
+	srwi	r3,r3,16
+	cmpwi	r3,0x37         /* SStar */
+	bne	98f
+	li	r3,H_SET_ASR    /* hcall = H_SET_ASR */
+	HSC     	        /* Invoking hcall */
+	b     	99f
 98:                 /* This is not a hypervisor machine */
 	mtasr	r4			/* set the stab location            */
 99:
@@ -1681,11 +1840,15 @@
 	bl	.stab_initialize
 	bl	.htab_initialize
 
-	LOADADDR(r6,_SDR1)
+	addi  r3,0,0x4000     /* r3 = ptr to naca */
+	lhz   r3,PLATFORM(r3) /* r3 = platform flags */
+	cmpldi r3,PLATFORM_PSERIES
+	bne    98f
+	LOADADDR(r6,_SDR1)		/* Only if NOT LPAR */
 	sub	r6,r6,r26
 	ld	r6,0(r6)		/* get the value of _SDR1 */
 	mtspr	SDR1,r6			/* set the htab location  */
-
+98: 
 	LOADADDR(r3,.start_here_common)
 	SET_REG_TO_CONST(r4, MSR_KERNEL)
 	mtspr	SRR0,r3
@@ -1735,9 +1898,9 @@
 	addi	r8,r8,0x4000
 	std	r8,0(r9)		/* set the value of the naca ptr  */
 
-	LOADADDR(r4,naca)               /* Get Naca ptr address           */
+	LOADADDR(r4,naca)               /* Get naca ptr address           */
 	ld	r4,0(r4)                /* Get the location of the naca   */
-	ld	r4,PACA(r4)             /* Get the base Paca pointer      */
+	ld	r4,PACA(r4)             /* Get the base paca pointer      */
 	mtspr	SPRG3,r4
 
 	/* ptr to current */
@@ -1887,11 +2050,3 @@
 	.globl	stab_array
 stab_array:
         .space	4096 * (48 - 1)
-	
-/*
- * This space gets a copy of optional info passed to us by the bootstrap
- * Used to pass parameters into the kernel like root=/dev/sda1, etc.
- */
-	.globl	cmd_line
-cmd_line:
-	.space	512
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/htab.c linux-2.4.20/arch/ppc64/kernel/htab.c
--- linux-2.4.19/arch/ppc64/kernel/htab.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/htab.c	2002-10-29 11:18:49.000000000 +0000
@@ -1,10 +1,11 @@
 /*
- * 
- *
  * PowerPC64 port by Mike Corrigan and Dave Engebretsen
  *   {mikejc|engebret}@us.ibm.com
  *
  *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
+ *
+ * SMP scalability work:
+ *    Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
  * 
  *    Module name: htab.c
  *
@@ -18,17 +19,7 @@
  */
 
 #include <linux/config.h>
-#include <asm/processor.h>
-#include <asm/pgtable.h>
-#include <asm/mmu.h>
-#include <asm/mmu_context.h>
-#include <asm/page.h>
-#include <asm/types.h>
-#include <asm/init.h>
-#include <asm/system.h>
-#include <asm/iSeries/LparData.h>
 #include <linux/spinlock.h>
-#include <asm/ppcdebug.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
@@ -36,62 +27,74 @@
 #include <linux/sysctl.h>
 #include <linux/ctype.h>
 #include <linux/cache.h>
+
+#include <asm/ppcdebug.h>
+#include <asm/processor.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+#include <asm/page.h>
+#include <asm/types.h>
 #include <asm/uaccess.h>
 #include <asm/naca.h>
-#include <asm/system.h>
 #include <asm/pmc.h>
 #include <asm/machdep.h>
 #include <asm/lmb.h>
+#include <asm/abs_addr.h>
+#include <asm/io.h>
 #include <asm/eeh.h>
-
-/* For iSeries */
+#include <asm/hvcall.h>
+#include <asm/iSeries/LparData.h>
 #include <asm/iSeries/HvCallHpt.h>
 
-/* Note:  pte   --> Linux PTE
+/*
+ * Note:  pte   --> Linux PTE
  *        HPTE  --> PowerPC Hashed Page Table Entry
+ *
+ * Execution context:
+ *   htab_initialize is called with the MMU off (of course), but
+ *   the kernel has been copied down to zero so it can directly
+ *   reference global data.  At this point it is very difficult
+ *   to print debug info.
+ *
  */
 
 HTAB htab_data = {NULL, 0, 0, 0, 0};
 
-int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
-		   void *buffer, size_t *lenp);
-
-void htab_initialize(void);
-void make_pte_LPAR(HPTE *htab,
-	      unsigned long va, unsigned long pa, int mode,
-	      unsigned long hash_mask, int large);
-
-extern unsigned long reloc_offset(void);
-extern unsigned long get_kernel_vsid( unsigned long ea );
-extern void cacheable_memzero( void *, unsigned int );
-
 extern unsigned long _SDR1;
 extern unsigned long klimit;
 
-extern unsigned long _ASR;
-extern inline void make_ste(unsigned long stab,
-			    unsigned long esid, unsigned long vsid);
-
-extern char _stext[], _etext[], __start_naca[], __end_stab[];
-
-static spinlock_t hash_table_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
-
-#define PTRRELOC(x)	((typeof(x))((unsigned long)(x) - offset))
-#define PTRUNRELOC(x)	((typeof(x))((unsigned long)(x) + offset))
-#define RELOC(x)	(*PTRRELOC(&(x)))
-
-extern unsigned long htab_size( unsigned long );
-unsigned long hpte_getword0_iSeries( unsigned long slot );
+void make_pte(HPTE *htab, unsigned long va, unsigned long pa,
+	      int mode, unsigned long hash_mask, int large);
+long plpar_pte_enter(unsigned long flags,
+		     unsigned long ptex,
+		     unsigned long new_pteh, unsigned long new_ptel,
+		     unsigned long *old_pteh_ret, unsigned long *old_ptel_ret);
+static long hpte_remove(unsigned long hpte_group);
+static long rpa_lpar_hpte_remove(unsigned long hpte_group);
+static long iSeries_hpte_remove(unsigned long hpte_group);
+
+static spinlock_t pSeries_tlbie_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t pSeries_lpar_tlbie_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t hash_table_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 #define KB (1024)
 #define MB (1024*KB)
+
+static inline void
+loop_forever(void)
+{
+	volatile unsigned long x = 1;
+	for(;x;x|=1)
+		;
+}
+
 static inline void
 create_pte_mapping(unsigned long start, unsigned long end,
 		   unsigned long mode, unsigned long mask, int large)
 {
-	unsigned long addr, offset = reloc_offset();
-	HTAB *_htab_data = PTRRELOC(&htab_data);
-	HPTE  *htab  = (HPTE *)__v2a(_htab_data->htab);
+	unsigned long addr;
+	HPTE *htab = (HPTE *)__v2a(htab_data.htab);
 	unsigned int step;
 
 	if (large)
@@ -102,8 +105,8 @@
 	for (addr = start; addr < end; addr += step) {
 		unsigned long vsid = get_kernel_vsid(addr);
 		unsigned long va = (vsid << 28) | (addr & 0xfffffff);
-		make_pte(htab, va, (unsigned long)__v2a(addr), mode, mask,
-				large);
+		make_pte(htab, va, (unsigned long)__v2a(addr), 
+			 mode, mask, large);
 	}
 }
 
@@ -112,16 +115,21 @@
 {
 	unsigned long table, htab_size_bytes;
 	unsigned long pteg_count;
-	unsigned long mode_ro, mode_rw, mask;
-	unsigned long offset = reloc_offset();
-	struct naca_struct *_naca = RELOC(naca);
-	HTAB *_htab_data = PTRRELOC(&htab_data);
+	unsigned long mode_rw, mask;
 
+#if 0
+	/* Can't really do the call below since it calls the normal RTAS
+	 * entry point and we're still relocate off at the moment.
+	 * Temporarily diabling until it can call through the relocate off
+	 * RTAS entry point.  -Peter
+	 */
+	ppc64_boot_msg(0x05, "htab init");
+#endif
 	/*
 	 * Calculate the required size of the htab.  We want the number of
 	 * PTEGs to equal one half the number of real pages.
 	 */ 
-	htab_size_bytes = 1UL << _naca->pftSize;
+	htab_size_bytes = 1UL << naca->pftSize;
 	pteg_count = htab_size_bytes >> 7;
 
 	/* For debug, make the HTAB 1/8 as big as it normally would be. */
@@ -130,335 +138,499 @@
 		htab_size_bytes = pteg_count << 7;
 	}
 
-	_htab_data->htab_num_ptegs = pteg_count;
-	_htab_data->htab_hash_mask = pteg_count - 1;
+	htab_data.htab_num_ptegs = pteg_count;
+	htab_data.htab_hash_mask = pteg_count - 1;
 
-	if(_naca->platform == PLATFORM_PSERIES) {
+	if(naca->platform == PLATFORM_PSERIES) {
 		/* Find storage for the HPT.  Must be contiguous in
 		 * the absolute address space.
 		 */
 		table = lmb_alloc(htab_size_bytes, htab_size_bytes);
-		if ( !table )
-			panic("ERROR, cannot find space for HPTE\n");
-		_htab_data->htab = (HPTE *)__a2v(table);
+		if ( !table ) {
+			ppc64_terminate_msg(0x20, "hpt space");
+			loop_forever();
+		}
+		htab_data.htab = (HPTE *)__a2v(table);
 
 		/* htab absolute addr + encoded htabsize */
-		RELOC(_SDR1) = table + __ilog2(pteg_count) - 11;
+		_SDR1 = table + __ilog2(pteg_count) - 11;
 
 		/* Initialize the HPT with no entries */
-		cacheable_memzero((void *)table, htab_size_bytes);
+		memset((void *)table, 0, htab_size_bytes);
 	} else {
-		_htab_data->htab = NULL;
-		RELOC(_SDR1) = 0; 
+		/* Using a hypervisor which owns the htab */
+		htab_data.htab = NULL;
+		_SDR1 = 0; 
 	}
 
-	mode_ro = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RXRX;
 	mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX;
 	mask = pteg_count-1;
 
-	/* Create PTE's for the kernel text and data sections plus
-	 * the HPT and HPTX arrays.  Make the assumption that
-	 * (addr & KERNELBASE) == 0 (ie they are disjoint).
-	 * We also assume that the va is <= 64 bits.
-	 */
-#if 0
-	create_pte_mapping((unsigned long)_stext,       (unsigned long)__start_naca,                 mode_ro, mask);
-	create_pte_mapping((unsigned long)__start_naca, (unsigned long)__end_stab,                   mode_rw, mask);
-	create_pte_mapping((unsigned long)__end_stab,   (unsigned long)_etext,                       mode_ro, mask);
-	create_pte_mapping((unsigned long)_etext,       RELOC(klimit),                               mode_rw, mask);
-	create_pte_mapping((unsigned long)__a2v(table), (unsigned long)__a2v(table+htab_size_bytes), mode_rw, mask);
-#else
-#ifndef CONFIG_PPC_ISERIES
-	if (__is_processor(PV_POWER4) && _naca->physicalMemorySize > 256*MB) {
+	/* XXX we currently map kernel text rw, should fix this */
+	if ((naca->platform & PLATFORM_PSERIES) &&
+	   cpu_has_largepage() && (naca->physicalMemorySize > 256*MB)) {
 		create_pte_mapping((unsigned long)KERNELBASE, 
 				   KERNELBASE + 256*MB, mode_rw, mask, 0);
 		create_pte_mapping((unsigned long)KERNELBASE + 256*MB, 
-				   KERNELBASE + (_naca->physicalMemorySize), 
+				   KERNELBASE + (naca->physicalMemorySize), 
 				   mode_rw, mask, 1);
-		return;
+	} else {
+		create_pte_mapping((unsigned long)KERNELBASE, 
+				   KERNELBASE+(naca->physicalMemorySize), 
+				   mode_rw, mask, 0);
 	}
-#endif
-	create_pte_mapping((unsigned long)KERNELBASE, 
-			   KERNELBASE+(_naca->physicalMemorySize), 
-			   mode_rw, mask, 0);
+#if 0
+	/* Can't really do the call below since it calls the normal RTAS
+	 * entry point and we're still relocate off at the moment.
+	 * Temporarily diabling until it can call through the relocate off
+	 * RTAS entry point.  -Peter
+	 */
+	ppc64_boot_msg(0x06, "htab done");
 #endif
 }
 #undef KB
 #undef MB
 
 /*
- * Create a pte.  Used during initialization only.
+ * Create a pte. Used during initialization only.
  * We assume the PTE will fit in the primary PTEG.
  */
-void make_pte(HPTE *htab,
-	      unsigned long va, unsigned long pa, int mode,
-	      unsigned long hash_mask, int large)
+void make_pte(HPTE *htab, unsigned long va, unsigned long pa,
+	      int mode, unsigned long hash_mask, int large)
 {
-	HPTE  *hptep;
-	unsigned long hash, i;
-	volatile unsigned long x = 1;
-	unsigned long vpn;
-
-#ifdef CONFIG_PPC_PSERIES
-	if(naca->platform == PLATFORM_PSERIES_LPAR) {
-		make_pte_LPAR(htab, va, pa, mode, hash_mask, large); 
-		return;
-	}
-#endif
+	HPTE *hptep, local_hpte, rhpte;
+	unsigned long hash, vpn, flags, lpar_rc;
+	unsigned long i, dummy1, dummy2;
+	long slot;
 
 	if (large)
-		vpn = va >> 24;
+		vpn = va >> LARGE_PAGE_SHIFT;
 	else
-		vpn = va >> 12;
+		vpn = va >> PAGE_SHIFT;
 
 	hash = hpt_hash(vpn, large);
 
-	hptep  = htab +  ((hash & hash_mask)*HPTES_PER_GROUP);
-
-	for (i = 0; i < 8; ++i, ++hptep) {
-		if ( hptep->dw0.dw0.v == 0 ) {		/* !valid */
-			hptep->dw1.dword1 = pa | mode;
-			hptep->dw0.dword0 = 0;
-			hptep->dw0.dw0.avpn = va >> 23;
-			hptep->dw0.dw0.bolted = 1;	/* bolted */
-			hptep->dw0.dw0.v = 1;		/* make valid */
-			return;
+	local_hpte.dw1.dword1 = pa | mode;
+	local_hpte.dw0.dword0 = 0;
+	local_hpte.dw0.dw0.avpn = va >> 23;
+	local_hpte.dw0.dw0.bolted = 1;		/* bolted */
+	if (large) {
+		local_hpte.dw0.dw0.l = 1;	/* large page */
+		local_hpte.dw0.dw0.avpn &= ~0x1UL;
+	}
+	local_hpte.dw0.dw0.v = 1;
+
+	if (naca->platform == PLATFORM_PSERIES) {
+		hptep  = htab + ((hash & hash_mask)*HPTES_PER_GROUP);
+
+		for (i = 0; i < 8; ++i, ++hptep) {
+			if (hptep->dw0.dw0.v == 0) {		/* !valid */
+				*hptep = local_hpte;
+				return;
+			}
 		}
+	} else if (naca->platform == PLATFORM_PSERIES_LPAR) {
+		slot = ((hash & hash_mask)*HPTES_PER_GROUP);
+		
+		/* Set CEC cookie to 0                   */
+		/* Zero page = 0                         */
+		/* I-cache Invalidate = 0                */
+		/* I-cache synchronize = 0               */
+		/* Exact = 0 - modify any entry in group */
+		flags = 0;
+		
+		lpar_rc =  plpar_pte_enter(flags, slot, local_hpte.dw0.dword0,
+					   local_hpte.dw1.dword1, 
+					   &dummy1, &dummy2);
+		if (lpar_rc != H_Success) {
+			ppc64_terminate_msg(0x21, "hpte enter");
+			loop_forever();
+		}
+		return;
+	} else if (naca->platform == PLATFORM_ISERIES_LPAR) {
+		slot = HvCallHpt_findValid(&rhpte, vpn);
+		if (slot < 0) {
+			/* Must find space in primary group */
+			panic("hash_page: hpte already exists\n");
+		}
+		HvCallHpt_addValidate(slot, 0, (HPTE *)&local_hpte );
+		return;
 	}
 
 	/* We should _never_ get here and too early to call xmon. */
-	for(;x;x|=1);
+	ppc64_terminate_msg(0x22, "hpte platform");
+	loop_forever();
+}
+
+/*
+ * find_linux_pte returns the address of a linux pte for a given 
+ * effective address and directory.  If not found, it returns zero.
+ */
+pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea)
+{
+	pgd_t *pg;
+	pmd_t *pm;
+	pte_t *pt = NULL;
+	pte_t pte;
+
+	pg = pgdir + pgd_index(ea);
+	if (!pgd_none(*pg)) {
+		pm = pmd_offset(pg, ea);
+		if (!pmd_none(*pm)) { 
+			pt = pte_offset(pm, ea);
+			pte = *pt;
+			if (!pte_present(pte))
+				pt = NULL;
+		}
+	}
+
+	return pt;
 }
 
-/* Functions to invalidate a HPTE */
-static void hpte_invalidate_iSeries( unsigned long slot )
+static inline unsigned long computeHptePP(unsigned long pte)
 {
-	HvCallHpt_invalidateSetSwBitsGet( slot, 0, 0 );
+	return (pte & _PAGE_USER) |
+		(((pte & _PAGE_USER) >> 1) &
+		 ((~((pte >> 2) &	/* _PAGE_RW */
+		     (pte >> 7))) &	/* _PAGE_DIRTY */
+		  1));
 }
 
-static void hpte_invalidate_pSeries( unsigned long slot )
+/*
+ * Handle a fault by adding an HPTE. If the address can't be determined
+ * to be valid via Linux page tables, return 1. If handled return 0
+ */
+int __hash_page(unsigned long ea, unsigned long access, 
+		unsigned long vsid, pte_t *ptep)
 {
-	/* Local copy of the first doubleword of the HPTE */
-	union {
-		unsigned long d;
-		Hpte_dword0   h;
-	} hpte_dw0;
+	unsigned long va, vpn;
+	unsigned long newpp, prpn;
+	unsigned long hpteflags;
+	long slot;
+	pte_t old_pte, new_pte;
 
-	/* Locate the HPTE */
-	HPTE  * hptep  = htab_data.htab  + slot;
+	/* Search the Linux page table for a match with va */
+	va = (vsid << 28) | (ea & 0x0fffffff);
+	vpn = va >> PAGE_SHIFT;
 
-	/* Get the first doubleword of the HPTE */
-	hpte_dw0.d = hptep->dw0.dword0;
+	/* Acquire the hash table lock to guarantee that the linux
+	 * pte we fetch will not change
+	 */
+	spin_lock( &hash_table_lock );
+	
+	/* 
+	 * Check the user's access rights to the page.  If access should be
+	 * prevented then send the problem up to do_page_fault.
+	 */
+	access |= _PAGE_PRESENT;
+	if (unlikely(access & ~(pte_val(*ptep)))) {
+		spin_unlock( &hash_table_lock );
+		return 1;
+	}
 
-	/* Invalidate the hpte */
-	hptep->dw0.dword0 = 0;
+	/* 
+	 * We have found a pte (which was present).
+	 * The spinlocks prevent this status from changing
+	 * The hash_table_lock prevents the _PAGE_HASHPTE status
+	 * from changing (RPN, DIRTY and ACCESSED too)
+	 * The page_table_lock prevents the pte from being 
+	 * invalidated or modified
+	 */
 
-	/* Invalidate the tlb   */
-	{
-		unsigned long vsid, group, pi, pi_high;
-
-		vsid = hpte_dw0.h.avpn >> 5;
-		group = slot >> 3;
-		if(hpte_dw0.h.h) {
-			group = ~group;
-		} 
-		pi = (vsid ^ group) & 0x7ff;
-		pi_high = (hpte_dw0.h.avpn & 0x1f) << 11;
-		pi |= pi_high;
-		_tlbie(pi << 12);
-	}
-}
+	/*
+	 * At this point, we have a pte (old_pte) which can be used to build
+	 * or update an HPTE. There are 2 cases:
+	 *
+	 * 1. There is a valid (present) pte with no associated HPTE (this is 
+	 *	the most common case)
+	 * 2. There is a valid (present) pte with an associated HPTE. The
+	 *	current values of the pp bits in the HPTE prevent access
+	 *	because we are doing software DIRTY bit management and the
+	 *	page is currently not DIRTY. 
+	 */
 
+	old_pte = *ptep;
+	new_pte = old_pte;
 
-/* Select an available HPT slot for a new HPTE
- *   return slot index (if in primary group)
- *   return -slot index (if in secondary group) 
- */
-static long hpte_selectslot_iSeries( unsigned long vpn )
-{
-	HPTE hpte;
-	long ret_slot, orig_slot;
-	unsigned long primary_hash;
-	unsigned long hpteg_slot;
-	unsigned long slot;
-	unsigned i, k;
-	union {
-		unsigned long	d;
-		Hpte_dword0	h;
-	} hpte_dw0;
+	/* If the attempted access was a store */
+	if (access & _PAGE_RW)
+		pte_val(new_pte) |= _PAGE_ACCESSED | _PAGE_DIRTY;
+	else
+		pte_val(new_pte) |= _PAGE_ACCESSED;
+
+	newpp = computeHptePP(pte_val(new_pte));
+	
+	/* Check if pte already has an hpte (case 2) */
+	if (unlikely(pte_val(old_pte) & _PAGE_HASHPTE)) {
+		/* There MIGHT be an HPTE for this pte */
+		unsigned long hash, slot, secondary;
+
+		/* XXX fix large pte flag */
+		hash = hpt_hash(vpn, 0);
+		secondary = (pte_val(old_pte) & _PAGE_SECONDARY) >> 15;
+		if (secondary)
+			hash = ~hash;
+		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+		slot += (pte_val(old_pte) & _PAGE_GROUP_IX) >> 12;
 
-	ret_slot = orig_slot = HvCallHpt_findValid( &hpte, vpn );
-	if ( hpte.dw0.dw0.v ) {		/* If valid ...what do we do now? */
-		udbg_printf( "hpte_selectslot_iSeries: vpn 0x%016lx already valid at slot 0x%016lx\n", vpn, ret_slot );
-		udbg_printf( "hpte_selectslot_iSeries: returned hpte 0x%016lx 0x%016lx\n", hpte.dw0.dword0, hpte.dw1.dword1 );
-
-		return (0x8000000000000000); 
-		/*			panic("select_hpte_slot found entry already valid\n"); */
-	}
-	if ( ret_slot == -1 ) {		/* -1 indicates no available slots */
-
-		/* No available entry found in secondary group */
-
-		PMC_SW_SYSTEM(htab_capacity_castouts);
-
-		primary_hash = hpt_hash(vpn, 0);
-		hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-		k = htab_data.next_round_robin++ & 0x7;
-
-		for ( i=0; i<HPTES_PER_GROUP; ++i ) {
-			if ( k == HPTES_PER_GROUP )
-				k = 0;
-			slot = hpteg_slot + k;
-			hpte_dw0.d = hpte_getword0_iSeries( slot );
-			if ( !hpte_dw0.h.bolted ) {
-				hpte_invalidate_iSeries( slot );
-				ret_slot = slot;
+		/* XXX fix large pte flag */
+		if (ppc_md.hpte_updatepp(slot, secondary, 
+					 newpp, va, 0) == -1) {
+			pte_val(old_pte) &= ~_PAGE_HPTEFLAGS;
+		} else {
+			if (!pte_same(old_pte, new_pte)) {
+				*ptep = new_pte;
 			}
-			++k;
-		}
-	} else {
-		if ( ret_slot < 0 ) {
-			PMC_SW_SYSTEM(htab_primary_overflows);
-			ret_slot &= 0x7fffffffffffffff;
-			ret_slot = -ret_slot;
 		}
 	}
-	if ( ret_slot == -1 ) {
-		/* No non-bolted entry found in primary group - time to panic */
-        	udbg_printf("hpte_selectslot_pSeries - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);
-        	panic("No non-bolted HPTE in group %lx", (unsigned long)hpteg_slot/HPTES_PER_GROUP);
+
+	if (likely(!(pte_val(old_pte) & _PAGE_HASHPTE))) {
+		/* Update the linux pte with the HPTE slot */
+		pte_val(new_pte) &= ~_PAGE_HPTEFLAGS;
+		pte_val(new_pte) |= _PAGE_HASHPTE;
+		prpn = pte_val(old_pte) >> PTE_SHIFT;
+
+		/* copy appropriate flags from linux pte */
+		hpteflags = (pte_val(new_pte) & 0x1f8) | newpp;
+
+		slot = ppc_md.hpte_insert(vpn, prpn, hpteflags, 0, 0);
+
+		pte_val(new_pte) |= ((slot<<12) & 
+				     (_PAGE_GROUP_IX | _PAGE_SECONDARY));
+
+		*ptep = new_pte;
 	}
-	PPCDBG(PPCDBG_MM, "hpte_selectslot_iSeries: vpn=0x%016lx, orig_slot=0x%016lx, ret_slot=0x%016lx \n",
-	       vpn, orig_slot, ret_slot );	
-	return ret_slot;
+
+	spin_unlock(&hash_table_lock);
+
+	return 0;
 }
 
-static long hpte_selectslot_pSeries(unsigned long vpn)
+/*
+ * Handle a fault by adding an HPTE. If the address can't be determined
+ * to be valid via Linux page tables, return 1. If handled return 0
+ */
+int hash_page(unsigned long ea, unsigned long access)
 {
-	HPTE * hptep;
-	unsigned long primary_hash;
-	unsigned long hpteg_slot;
-	unsigned i, k;
+	void *pgdir;
+	unsigned long vsid;
+	struct mm_struct *mm;
+	pte_t *ptep;
+	int ret;
 
-	/* Search the primary group for an available slot */
+	/* Check for invalid addresses. */
+	if (!IS_VALID_EA(ea)) return 1;
 
-	primary_hash = hpt_hash(vpn, 0);
-	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-	hptep = htab_data.htab + hpteg_slot;
-	
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		if ( hptep->dw0.dw0.v == 0 ) {
-			/* If an available slot found, return it */
-			return hpteg_slot + i;
-		}
-		hptep++;
+ 	switch (REGION_ID(ea)) {
+	case USER_REGION_ID:
+		mm = current->mm;
+		if (mm == NULL) return 1;
+		vsid = get_vsid(mm->context, ea);
+		break;
+	case IO_REGION_ID:
+		mm = &ioremap_mm;
+		vsid = get_kernel_vsid(ea);
+		break;
+	case VMALLOC_REGION_ID:
+		mm = &init_mm;
+		vsid = get_kernel_vsid(ea);
+		break;
+	case IO_UNMAPPED_REGION_ID:
+		udbg_printf("EEH Error ea = 0x%lx\n", ea);
+		PPCDBG_ENTER_DEBUGGER();
+		panic("EEH Error ea = 0x%lx\n", ea);
+		break;
+	case KERNEL_REGION_ID:
+		/*
+		 * As htab_initialize is now, we shouldn't ever get here since
+		 * we're bolting the entire 0xC0... region.
+		 */
+		udbg_printf("Little faulted on kernel address 0x%lx\n", ea);
+		PPCDBG_ENTER_DEBUGGER();
+		panic("Little faulted on kernel address 0x%lx\n", ea);
+		break;
+	default:
+		/* Not a valid range, send the problem up to do_page_fault */
+		return 1;
+		break;
 	}
 
-	/* No available entry found in primary group */
-
-	PMC_SW_SYSTEM(htab_primary_overflows);
-
-	/* Search the secondary group */
+	pgdir = mm->pgd;
+	if (pgdir == NULL) return 1;
 
-	hpteg_slot = ( ~primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-	hptep = htab_data.htab + hpteg_slot;
+	/*
+	 * Lock the Linux page table to prevent mmap and kswapd
+	 * from modifying entries while we search and update
+	 */
+	spin_lock(&mm->page_table_lock);
 
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		if ( hptep->dw0.dw0.v == 0 ) {
-			/* If an available slot found, return it */
-			return -(hpteg_slot + i);
-		}
-		hptep++;
+	ptep = find_linux_pte(pgdir, ea);
+	/*
+	 * If no pte found or not present, send the problem up to
+	 * do_page_fault
+	 */
+	if (ptep && pte_present(*ptep)) {
+		ret = __hash_page(ea, access, vsid, ptep);
+	} else {	
+		/* If no pte, send the problem up to do_page_fault */
+		ret = 1;
 	}
 
-	/* No available entry found in secondary group */
+	spin_unlock(&mm->page_table_lock);
+
+	return ret;
+}
 
-	PMC_SW_SYSTEM(htab_capacity_castouts);
+void flush_hash_page(unsigned long context, unsigned long ea, pte_t *ptep)
+{
+	unsigned long vsid, vpn, va, hash, secondary, slot, flags;
+	unsigned long large = 0, local = 0;
+	pte_t pte;
 
-	/* Select an entry in the primary group to replace */
+	if ((ea >= USER_START) && (ea <= USER_END))
+		vsid = get_vsid(context, ea);
+	else
+		vsid = get_kernel_vsid(ea);
 
-	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-	hptep = htab_data.htab + hpteg_slot;
-	k = htab_data.next_round_robin++ & 0x7;
+	va = (vsid << 28) | (ea & 0x0fffffff);
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
+	hash = hpt_hash(vpn, large);
 
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		if (k == HPTES_PER_GROUP)
-			k = 0;
+	spin_lock_irqsave( &hash_table_lock, flags);
 
-		if (!hptep[k].dw0.dw0.bolted) {
-			hpteg_slot += k;
-			/* Invalidate the current entry */
-			ppc_md.hpte_invalidate(hpteg_slot); 
-			return hpteg_slot;
-		}
-		++k;
+	pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0));
+	secondary = (pte_val(pte) & _PAGE_SECONDARY) >> 15;
+	if (secondary) hash = ~hash;
+	slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+	slot += (pte_val(pte) & _PAGE_GROUP_IX) >> 12;
+	
+	if (pte_val(pte) & _PAGE_HASHPTE) {
+		ppc_md.hpte_invalidate(slot, secondary, va, large, local);
 	}
 
-	/* No non-bolted entry found in primary group - time to panic */
-        udbg_printf("hpte_selectslot_pSeries - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);
-	/*      xmon(0); */
-        panic("No non-bolted HPTE in group %lx", (unsigned long)hpteg_slot/HPTES_PER_GROUP);
+	spin_unlock_irqrestore( &hash_table_lock, flags );
+}
 
-	/* keep the compiler happy */
-	return 0;
+long plpar_pte_enter(unsigned long flags,
+		     unsigned long ptex,
+		     unsigned long new_pteh, unsigned long new_ptel,
+		     unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
+{
+	unsigned long dummy, ret;
+	ret = plpar_hcall(H_ENTER, flags, ptex, new_pteh, new_ptel,
+			   old_pteh_ret, old_ptel_ret, &dummy);
+	return(ret);
 }
 
-unsigned long hpte_getword0_iSeries( unsigned long slot )
+long plpar_pte_remove(unsigned long flags,
+		      unsigned long ptex,
+		      unsigned long avpn,
+		      unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
 {
-	unsigned long dword0;
+	unsigned long dummy;
+	return plpar_hcall(H_REMOVE, flags, ptex, avpn, 0,
+			   old_pteh_ret, old_ptel_ret, &dummy);
+}
 
-	HPTE hpte;
-	HvCallHpt_get( &hpte, slot );
-	dword0 = hpte.dw0.dword0;
+long plpar_pte_read(unsigned long flags,
+		    unsigned long ptex,
+		    unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
+{
+	unsigned long dummy;
+	return plpar_hcall(H_READ, flags, ptex, 0, 0,
+			   old_pteh_ret, old_ptel_ret, &dummy);
+}
 
-	return dword0;
+long plpar_pte_protect(unsigned long flags,
+		       unsigned long ptex,
+		       unsigned long avpn)
+{
+	return plpar_hcall_norets(H_PROTECT, flags, ptex, avpn);
+}
+
+static __inline__ void set_pp_bit(unsigned long pp, HPTE *addr)
+{
+	unsigned long old;
+	unsigned long *p = &addr->dw1.dword1;
+
+	__asm__ __volatile__(
+        "1:	ldarx	%0,0,%3\n\
+                rldimi  %0,%2,0,62\n\
+                stdcx.	%0,0,%3\n\
+            	bne	1b"
+        : "=&r" (old), "=m" (*p)
+        : "r" (pp), "r" (p), "m" (*p)
+        : "cc");
 }
 
-unsigned long hpte_getword0_pSeries( unsigned long slot )
+/*
+ * Functions used to retrieve word 0 of a given page table entry.
+ *
+ * Input : slot : PTE index within the page table of the entry to retrieve 
+ * Output: Contents of word 0 of the specified entry
+ */
+static unsigned long rpa_lpar_hpte_getword0(unsigned long slot)
 {
 	unsigned long dword0;
-	HPTE * hptep = htab_data.htab + slot;
+	unsigned long lpar_rc;
+	unsigned long dummy_word1;
+	unsigned long flags;
+
+	/* Read 1 pte at a time                        */
+	/* Do not need RPN to logical page translation */
+	/* No cross CEC PFT access                     */
+	flags = 0;
+	
+	lpar_rc = plpar_pte_read(flags, slot, &dword0, &dummy_word1);
+
+	if (lpar_rc != H_Success)
+		panic("Error on pte read in get_hpte0 rc = %lx\n", lpar_rc);
 
-	dword0 = hptep->dw0.dword0;
 	return dword0;
 }
 
-static long hpte_find_iSeries(unsigned long vpn)
+unsigned long iSeries_hpte_getword0(unsigned long slot)
 {
+	unsigned long dword0;
+
 	HPTE hpte;
-	long slot;
+	HvCallHpt_get(&hpte, slot);
+	dword0 = hpte.dw0.dword0;
 
-	slot = HvCallHpt_findValid( &hpte, vpn );
-	if ( hpte.dw0.dw0.v ) {
-		if ( slot < 0 ) {
-			slot &= 0x7fffffffffffffff;
-			slot = -slot;
-		}
-	} else
-		slot = -1;
-	return slot;
+	return dword0;
 }
 
-static long hpte_find_pSeries(unsigned long vpn)
+/*
+ * Functions used to find the PTE for a particular virtual address. 
+ * Only used during boot when bolting pages.
+ *
+ * Input : vpn      : virtual page number
+ * Output: PTE index within the page table of the entry
+ *         -1 on failure
+ */
+static long hpte_find(unsigned long vpn)
 {
-	union {
-		unsigned long d;
-		Hpte_dword0   h;
-	} hpte_dw0;
-	long slot;
+	HPTE *hptep;
 	unsigned long hash;
-	unsigned long i,j;
+	unsigned long i, j;
+	long slot;
+	Hpte_dword0 dw0;
 
 	hash = hpt_hash(vpn, 0);
-	for ( j=0; j<2; ++j ) {
+
+	for (j = 0; j < 2; j++) {
 		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
-		for ( i=0; i<HPTES_PER_GROUP; ++i ) {
-			hpte_dw0.d = hpte_getword0_pSeries( slot );
-			if ( ( hpte_dw0.h.avpn == ( vpn >> 11 ) ) &&
-			     ( hpte_dw0.h.v ) &&
-			     ( hpte_dw0.h.h == j ) ) {
+		for (i = 0; i < HPTES_PER_GROUP; i++) {
+			hptep = htab_data.htab + slot;
+			dw0 = hptep->dw0.dw0;
+
+			if ((dw0.avpn == (vpn >> 11)) && dw0.v &&
+			    (dw0.h == j)) {
 				/* HPTE matches */
-				if ( j )
+				if (j)
 					slot = -slot;
 				return slot;
 			}
@@ -466,247 +638,320 @@
 		}
 		hash = ~hash;
 	}
+
 	return -1;
-} 
+}
 
-/* This function is called by iSeries setup when initializing the hpt */
-void build_valid_hpte( unsigned long vsid, unsigned long ea, unsigned long pa,
-		       pte_t * ptep, unsigned hpteflags, unsigned bolted )
-{
-	unsigned long vpn, flags;
-	long hpte_slot;
-	unsigned hash;
-	pte_t pte;
+static long rpa_lpar_hpte_find(unsigned long vpn)
+{
+	unsigned long hash;
+	unsigned long i, j;
+	long slot;
+	union {
+		unsigned long dword0;
+		Hpte_dword0 dw0;
+	} hpte_dw0;
+	Hpte_dword0 dw0;
 
-	vpn = ((vsid << 28) | ( ea & 0xffff000 )) >> 12;
+	hash = hpt_hash(vpn, 0);
 
-	spin_lock_irqsave( &hash_table_lock, flags );
+	for (j = 0; j < 2; j++) {
+		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+		for (i = 0; i < HPTES_PER_GROUP; i++) {
+			hpte_dw0.dword0 = rpa_lpar_hpte_getword0(slot);
+			dw0 = hpte_dw0.dw0;
 
-	hpte_slot = ppc_md.hpte_selectslot( vpn );
-	hash = 0;
-	if ( hpte_slot < 0 ) {
-		if ( hpte_slot == 0x8000000000000000 ) {
-			udbg_printf("hash_page: ptep    = 0x%016lx\n", 
-				    (unsigned long)ptep );
-			udbg_printf("hash_page: ea      = 0x%016lx\n", ea );
-			udbg_printf("hash_page: vpn     = 0x%016lx\n", vpn );
-               
-			panic("hash_page: hpte already exists\n");
+			if ((dw0.avpn == (vpn >> 11)) && dw0.v &&
+			    (dw0.h == j)) {
+				/* HPTE matches */
+				if (j)
+					slot = -slot;
+				return slot;
+			}
+			++slot;
 		}
-		hash = 1;
-		hpte_slot = -hpte_slot;
+		hash = ~hash;
 	}
-	ppc_md.hpte_create_valid( hpte_slot, vpn, pa >> 12, hash, ptep,
-				  hpteflags, bolted );
-
-	if ( ptep ) {
-		/* Get existing pte flags */
-		pte = *ptep;
-		pte_val(pte) &= ~_PAGE_HPTEFLAGS;
-
-		/* Add in the has hpte flag */
-		pte_val(pte) |= _PAGE_HASHPTE;
-
-		/* Add in the _PAGE_SECONDARY flag */
-		pte_val(pte) |= hash << 15;
-
-		/* Add in the hpte slot */
-		pte_val(pte) |= (hpte_slot << 12) & _PAGE_GROUP_IX;
-               
-		/* Save the new pte.  */
-		*ptep = pte;
-               
-	}
-	spin_unlock_irqrestore( &hash_table_lock, flags );
-}
 
+	return -1;
+} 
 
-/* Create an HPTE and validate it
- *   It is assumed that the HPT slot currently is invalid.
- *   The HPTE is set with the vpn, rpn (converted to absolute)
- *   and flags
- */
-static void hpte_create_valid_iSeries(unsigned long slot, unsigned long vpn,
-				      unsigned long prpn, unsigned hash, 
-				      void * ptep, unsigned hpteflags, 
-				      unsigned bolted )
-{
-	/* Local copy of HPTE */
-	struct {
-		/* Local copy of first doubleword of HPTE */
-		union {
-			unsigned long d;
-			Hpte_dword0   h;
-		} dw0;
-		/* Local copy of second doubleword of HPTE */
-		union {
-			unsigned long     d;
-			Hpte_dword1       h;
-			Hpte_dword1_flags f;
-		} dw1;
-	} lhpte;
-	
-	unsigned long avpn = vpn >> 11;
-	unsigned long arpn = physRpn_to_absRpn( prpn );
+static long iSeries_hpte_find(unsigned long vpn)
+{
+	HPTE hpte;
+	long slot;
 
-	/* Fill in the local HPTE with absolute rpn, avpn and flags */
-	lhpte.dw1.d        = 0;
-	lhpte.dw1.h.rpn    = arpn;
-	lhpte.dw1.f.flags  = hpteflags;
-
-	lhpte.dw0.d        = 0;
-	lhpte.dw0.h.avpn   = avpn;
-	lhpte.dw0.h.h      = hash;
-	lhpte.dw0.h.bolted = bolted;
-	lhpte.dw0.h.v      = 1;
+	/*
+	 * The HvCallHpt_findValid interface is as follows:
+	 * 0xffffffffffffffff : No entry found.
+	 * 0x00000000xxxxxxxx : Entry found in primary group, slot x
+	 * 0x80000000xxxxxxxx : Entry found in secondary group, slot x
+	 */
+	slot = HvCallHpt_findValid(&hpte, vpn); 
+	if (hpte.dw0.dw0.v) {
+		if (slot < 0) {
+			slot &= 0x7fffffffffffffff;
+			slot = -slot;
+		}
+	} else {
+		slot = -1;
+	}
 
-	/* Now fill in the actual HPTE */
-	HvCallHpt_addValidate( slot, hash, (HPTE *)&lhpte );
+	return slot;
 }
 
-static void hpte_create_valid_pSeries(unsigned long slot, unsigned long vpn,
-				      unsigned long prpn, unsigned hash, 
-				      void * ptep, unsigned hpteflags, 
-				      unsigned bolted)
-{
-	/* Local copy of HPTE */
-	struct {
-		/* Local copy of first doubleword of HPTE */
-		union {
-			unsigned long d;
-			Hpte_dword0   h;
-		} dw0;
-		/* Local copy of second doubleword of HPTE */
-		union {
-			unsigned long     d;
-			Hpte_dword1       h;
-			Hpte_dword1_flags f;
-		} dw1;
-	} lhpte;
-	
-	unsigned long avpn = vpn >> 11;
-	unsigned long arpn = physRpn_to_absRpn( prpn );
+/*
+ * Functions used to invalidate a page table entry from the page table
+ * and tlb.
+ *
+ * Input : slot  : PTE index within the page table of the entry to invalidated
+ *         va    : Virtual address of the entry being invalidated
+ *         large : 1 = large page (16M)
+ *         local : 1 = Use tlbiel to only invalidate the local tlb 
+ */
+static void hpte_invalidate(unsigned long slot, 
+			    unsigned long secondary,
+			    unsigned long va,
+			    int large, int local)
+{
+	HPTE *hptep = htab_data.htab + slot;
+	Hpte_dword0 dw0;
+	unsigned long vpn, avpn;
+	unsigned long flags;
 
-	HPTE *hptep;
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
 
-	/* Fill in the local HPTE with absolute rpn, avpn and flags */
-	lhpte.dw1.d        = 0;
-	lhpte.dw1.h.rpn    = arpn;
-	lhpte.dw1.f.flags  = hpteflags;
-
-	lhpte.dw0.d        = 0;
-	lhpte.dw0.h.avpn   = avpn;
-	lhpte.dw0.h.h      = hash;
-	lhpte.dw0.h.bolted = bolted;
-	lhpte.dw0.h.v      = 1;
+	avpn = vpn >> 11;
 
-	/* Now fill in the actual HPTE */
-	hptep  = htab_data.htab  + slot;
+	dw0 = hptep->dw0.dw0;
 
-	/* Set the second dword first so that the valid bit
-	 * is the last thing set
+	/*
+	 * Do not remove bolted entries.  Alternatively, we could check
+	 * the AVPN, hash group, and valid bits.  By doing it this way,
+	 * it is common with the pSeries LPAR optimal path.
 	 */
-	
-	hptep->dw1.dword1 = lhpte.dw1.d;
+	if (dw0.bolted) return;
 
-	/* Guarantee the second dword is visible before
-	 * the valid bit
+	/* Invalidate the hpte. */
+	hptep->dw0.dword0 = 0;
+
+	/* Invalidate the tlb */
+	spin_lock_irqsave(&pSeries_tlbie_lock, flags);
+	_tlbie(va, large);
+	spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
+}
+
+static void rpa_lpar_hpte_invalidate(unsigned long slot, 
+				     unsigned long secondary,
+				     unsigned long va,
+				     int large, int local)
+{
+	unsigned long lpar_rc;
+	unsigned long dummy1, dummy2;
+
+	/* 
+	 * Don't remove a bolted entry.  This case can occur when we bolt
+	 * pages dynamically after initial boot.
 	 */
-	
-	__asm__ __volatile__ ("eieio" : : : "memory");
+	lpar_rc = plpar_pte_remove(H_ANDCOND, slot, (0x1UL << 4), 
+				   &dummy1, &dummy2);
+
+	if (lpar_rc != H_Success)
+		panic("Bad return code from invalidate rc = %lx\n", lpar_rc);
+}
 
-	/* Now set the first dword including the valid bit */
-	hptep->dw0.dword0 = lhpte.dw0.d;
+static void iSeries_hpte_invalidate(unsigned long slot, 
+				    unsigned long secondary,
+				    unsigned long va,
+				    int large, int local)
+{
+	HPTE lhpte;
+	unsigned long vpn, avpn;
 
-	__asm__ __volatile__ ("ptesync" : : : "memory");
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
+
+	avpn = vpn >> 11;
+
+	lhpte.dw0.dword0 = iSeries_hpte_getword0(slot);
+	
+	if ((lhpte.dw0.dw0.avpn == avpn) && 
+	    (lhpte.dw0.dw0.v) &&
+	    (lhpte.dw0.dw0.h == secondary)) {
+		HvCallHpt_invalidateSetSwBitsGet(slot, 0, 0);
+	}
 }
 
-/* find_linux_pte returns the address of a linux pte for a given 
- * effective address and directory.  If not found, it returns zero.
+/*
+ * Functions used to update page protection bits.
+ *
+ * Input : slot  : PTE index within the page table of the entry to update
+ *         newpp : new page protection bits
+ *         va    : Virtual address of the entry being updated
+ *         large : 1 = large page (16M)
+ * Output: 0 on success, -1 on failure
  */
+static long hpte_updatepp(unsigned long slot, 
+			  unsigned long secondary,
+			  unsigned long newpp,
+			  unsigned long va, int large)
+{
+	HPTE *hptep = htab_data.htab + slot;
+	Hpte_dword0 dw0;
+	Hpte_dword1 dw1;
+	unsigned long vpn, avpn;
+	unsigned long flags;
 
-pte_t  * find_linux_pte( pgd_t * pgdir, unsigned long ea )
-{
-	pgd_t *pg;
-	pmd_t *pm;
-	pte_t *pt = NULL;
-	pte_t pte;
-	pg = pgdir + pgd_index( ea );
-	if ( ! pgd_none( *pg ) ) {
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
 
-		pm = pmd_offset( pg, ea );
-		if ( ! pmd_none( *pm ) ) { 
-			pt = pte_offset( pm, ea );
-			pte = *pt;
-			if ( ! pte_present( pte ) )
-				pt = NULL;
-		}
-	}
+	avpn = vpn >> 11;
 
-	return pt;
+	dw0 = hptep->dw0.dw0;
+	if ((dw0.avpn == avpn) && 
+	    (dw0.v) && (dw0.h == secondary)) {
+		/* Turn off valid bit in HPTE */
+		dw0.v = 0;
+		hptep->dw0.dw0 = dw0;
+		
+		/* Ensure it is out of the tlb too */
+		spin_lock_irqsave(&pSeries_tlbie_lock, flags);
+		_tlbie(va, large);
+		spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
+		
+		/* Insert the new pp bits into the HPTE */
+		dw1 = hptep->dw1.dw1;
+		dw1.pp = newpp;
+		hptep->dw1.dw1 = dw1;
+		
+		/* Ensure it is visible before validating */
+		__asm__ __volatile__ ("eieio" : : : "memory");
+		
+		/* Turn the valid bit back on in HPTE */
+		dw0.v = 1;
+		hptep->dw0.dw0 = dw0;
+		
+		__asm__ __volatile__ ("ptesync" : : : "memory");
+		
+		return 0;
+	}
 
+	return -1;
 }
 
-static inline unsigned long computeHptePP( unsigned long pte )
-{
-	return (     pte & _PAGE_USER )           |
-		( ( ( pte & _PAGE_USER )    >> 1 ) &
-		  ( ( ~( ( pte >> 2 ) &		/* _PAGE_RW */
-		         ( pte >> 7 ) ) ) &     /* _PAGE_DIRTY */
-			 1 ) );
+static long rpa_lpar_hpte_updatepp(unsigned long slot, 
+				   unsigned long secondary,
+				   unsigned long newpp,
+				   unsigned long va, int large)
+{
+	unsigned long lpar_rc;
+	unsigned long flags = (newpp & 7);
+	unsigned long avpn = va >> 23;
+	HPTE hpte;
+
+	lpar_rc = plpar_pte_read(0, slot, &hpte.dw0.dword0, &hpte.dw1.dword1);
+
+	if ((hpte.dw0.dw0.avpn == avpn) &&
+	    (hpte.dw0.dw0.v) && 
+	    (hpte.dw0.dw0.h == secondary)) {
+		lpar_rc = plpar_pte_protect(flags, slot, 0);
+		if (lpar_rc != H_Success)
+			panic("bad return code from pte protect rc = %lx\n", 
+			      lpar_rc);
+		return 0;
+	}
+
+	return -1;
 }
 
-static void hpte_updatepp_iSeries(long slot, unsigned long newpp, unsigned long va)
+static long iSeries_hpte_updatepp(unsigned long slot, 
+				  unsigned long secondary,
+				  unsigned long newpp, 
+				  unsigned long va, int large)
 {
-	HvCallHpt_setPp( slot, newpp );
+	unsigned long vpn, avpn;
+	HPTE hpte;
+
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
+
+	avpn = vpn >> 11;
+
+	HvCallHpt_get(&hpte, slot);
+	if ((hpte.dw0.dw0.avpn == avpn) && 
+	    (hpte.dw0.dw0.v) &&
+	    (hpte.dw0.dw0.h == secondary)) {
+		HvCallHpt_setPp(slot, newpp);
+		return 0;
+	}
+	return -1;
 }
 
-static void hpte_updatepp_pSeries(long slot, unsigned long newpp, unsigned long va)
+/*
+ * Functions used to update the page protection bits. Intended to be used 
+ * to create guard pages for kernel data structures on pages which are bolted
+ * in the HPT. Assumes pages being operated on will not be stolen.
+ * Does not work on large pages. No need to lock here because we are the 
+ * only user.
+ * 
+ * Input : newpp : page protection flags
+ *         ea    : effective kernel address to bolt.
+ */
+static void hpte_updateboltedpp(unsigned long newpp, unsigned long ea)
 {
-	/* Local copy of first doubleword of HPTE */
-	union {
-		unsigned long d;
-		Hpte_dword0   h;
-	} hpte_dw0;
-	
-	/* Local copy of second doubleword of HPTE */
-	union {
-		unsigned long     d;
-		Hpte_dword1       h;
-		Hpte_dword1_flags f;
-	} hpte_dw1;	
-
-	HPTE *  hptep  = htab_data.htab  + slot;
-
-	/* Turn off valid bit in HPTE */
-	hpte_dw0.d = hptep->dw0.dword0;
-	hpte_dw0.h.v = 0;
-	hptep->dw0.dword0 = hpte_dw0.d;
+	unsigned long vsid, va, vpn, flags;
+	long slot;
+	HPTE *hptep;
+
+	vsid = get_kernel_vsid(ea);
+	va = (vsid << 28) | (ea & 0x0fffffff);
+	vpn = va >> PAGE_SHIFT;
+
+	slot = hpte_find(vpn);
+	if (slot == -1)
+		panic("could not find page to bolt\n");
+	hptep = htab_data.htab + slot;
+
+	set_pp_bit(newpp, hptep);
 
 	/* Ensure it is out of the tlb too */
-	_tlbie( va );
+	spin_lock_irqsave(&pSeries_tlbie_lock, flags);
+	_tlbie(va, 0);
+	spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
+}
 
-	/* Insert the new pp bits into the HPTE */
-	hpte_dw1.d = hptep->dw1.dword1;
-	hpte_dw1.h.pp = newpp;
-	hptep->dw1.dword1 = hpte_dw1.d;
+static void rpa_lpar_hpte_updateboltedpp(unsigned long newpp, unsigned long ea)
+{
+	unsigned long lpar_rc;
+	unsigned long vsid, va, vpn, flags;
+	long slot;
 
-	/* Ensure it is visible before validating */
-	__asm__ __volatile__ ("eieio" : : : "memory");
+	vsid = get_kernel_vsid(ea);
+	va = (vsid << 28) | (ea & 0x0fffffff);
+	vpn = va >> PAGE_SHIFT;
 
-	/* Turn the valid bit back on in HPTE */
-	hpte_dw0.h.v = 1;
-	hptep->dw0.dword0 = hpte_dw0.d;
+	slot = rpa_lpar_hpte_find(vpn);
+	if (slot == -1)
+		panic("updateboltedpp: Could not find page to bolt\n");
 
-	__asm__ __volatile__ ("ptesync" : : : "memory");
+	flags = newpp & 3;
+	lpar_rc = plpar_pte_protect(flags, slot, 0);
+
+	if (lpar_rc != H_Success)
+		panic("Bad return code from pte bolted protect rc = %lx\n",
+		      lpar_rc); 
 }
 
-/*
- * Update the page protection bits.  Intended to be used to create
- * guard pages for kernel data structures on pages which are bolted
- * in the HPT.  Assumes pages being operated on will not be stolen. 
- */
-void hpte_updateboltedpp_iSeries(unsigned long newpp, unsigned long ea )
+void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea)
 {
 	unsigned long vsid,va,vpn;
 	long slot;
@@ -715,518 +960,408 @@
 	va = ( vsid << 28 ) | ( ea & 0x0fffffff );
 	vpn = va >> PAGE_SHIFT;
 
-	slot = ppc_md.hpte_find( vpn );
-	HvCallHpt_setPp( slot, newpp );
-}
+	slot = iSeries_hpte_find(vpn); 
+	if (slot == -1)
+		panic("updateboltedpp: Could not find page to bolt\n");
 
-
-static __inline__ void set_pp_bit(unsigned long  pp, HPTE *addr)
-{
-	unsigned long old;
-	unsigned long *p = (unsigned long *)(&(addr->dw1));
-
-	__asm__ __volatile__(
-        "1:	ldarx	%0,0,%3\n\
-                rldimi  %0,%2,0,62\n\
-                stdcx.	%0,0,%3\n\
-            	bne	1b"
-        : "=&r" (old), "=m" (*p)
-        : "r" (pp), "r" (p), "m" (*p)
-        : "cc");
+	HvCallHpt_setPp(slot, newpp);
 }
 
 /*
- * Update the page protection bits.  Intended to be used to create
- * guard pages for kernel data structures on pages which are bolted
- * in the HPT.  Assumes pages being operated on will not be stolen. 
+ * Functions used to insert new hardware page table entries.
+ * Will castout non-bolted entries as necessary using a random
+ * algorithm.
+ *
+ * Input : vpn      : virtual page number
+ *         prpn     : real page number in absolute space
+ *         hpteflags: page protection flags
+ *         bolted   : 1 = bolt the page
+ *         large    : 1 = large page (16M)
+ * Output: hsss, where h = hash group, sss = slot within that group
  */
-void hpte_updateboltedpp_pSeries(unsigned long newpp, unsigned long ea)
+static long hpte_insert(unsigned long vpn, unsigned long prpn,
+			unsigned long hpteflags, int bolted, int large)
 {
-	unsigned long vsid,va,vpn,flags;
-	long slot;
 	HPTE *hptep;
+	Hpte_dword0 dw0;
+	HPTE lhpte;
+	int i, secondary;
+	unsigned long hash = hpt_hash(vpn, 0);
+	unsigned long avpn = vpn >> 11;
+	unsigned long arpn = physRpn_to_absRpn(prpn);
+	unsigned long hpte_group;
 
-	vsid = get_kernel_vsid( ea );
-	va = ( vsid << 28 ) | ( ea & 0x0fffffff );
-	vpn = va >> PAGE_SHIFT;
+repeat:
+	secondary = 0;
+	hpte_group = ((hash & htab_data.htab_hash_mask) *
+		      HPTES_PER_GROUP) & ~0x7UL;
+	hptep = htab_data.htab + hpte_group;
+
+	for (i = 0; i < HPTES_PER_GROUP; i++) {
+		dw0 = hptep->dw0.dw0;
+		if (!dw0.v) {
+			/* retry with lock held */
+			dw0 = hptep->dw0.dw0;
+			if (!dw0.v)
+				break;
+		}
+		hptep++;
+	}
 
-	slot = ppc_md.hpte_find( vpn );
-	hptep = htab_data.htab  + slot;
+	if (i == HPTES_PER_GROUP) {
+		secondary = 1;
+		hpte_group = ((~hash & htab_data.htab_hash_mask) *
+			      HPTES_PER_GROUP) & ~0x7UL;
+		hptep = htab_data.htab + hpte_group;
+
+		for (i = 0; i < HPTES_PER_GROUP; i++) {
+			dw0 = hptep->dw0.dw0;
+			if (!dw0.v) {
+				/* retry with lock held */
+				dw0 = hptep->dw0.dw0;
+				if (!dw0.v)
+					break;
+			}
+			hptep++;
+		}
+		if (i == HPTES_PER_GROUP) {
+			if (mftb() & 0x1)
+				hpte_group=((hash & htab_data.htab_hash_mask)* 
+					    HPTES_PER_GROUP) & ~0x7UL;
+			
+			hpte_remove(hpte_group);
+			goto repeat;
+		}
+	}
 
-	set_pp_bit(newpp , hptep);
+	lhpte.dw1.dword1      = 0;
+	lhpte.dw1.dw1.rpn     = arpn;
+	lhpte.dw1.flags.flags = hpteflags;
 
-	/* Ensure it is out of the tlb too */
-	spin_lock_irqsave( &hash_table_lock, flags );
-	_tlbie( va );
-	spin_unlock_irqrestore( &hash_table_lock, flags );
-}
+	lhpte.dw0.dword0      = 0;
+	lhpte.dw0.dw0.avpn    = avpn;
+	lhpte.dw0.dw0.h       = secondary;
+	lhpte.dw0.dw0.bolted  = bolted;
+	lhpte.dw0.dw0.v       = 1;
 
+	if (large) lhpte.dw0.dw0.l = 1;
 
+	hptep->dw1.dword1 = lhpte.dw1.dword1;
 
-/* This is called very early. */
-void hpte_init_iSeries(void)
-{
-	ppc_md.hpte_invalidate   = hpte_invalidate_iSeries;
-	ppc_md.hpte_updatepp     = hpte_updatepp_iSeries;
-	ppc_md.hpte_updateboltedpp = hpte_updateboltedpp_iSeries;
-	ppc_md.hpte_getword0     = hpte_getword0_iSeries;
-	ppc_md.hpte_selectslot   = hpte_selectslot_iSeries;
-	ppc_md.hpte_create_valid = hpte_create_valid_iSeries;
-	ppc_md.hpte_find	 = hpte_find_iSeries;
+	/* Guarantee the second dword is visible before the valid bit */
+	__asm__ __volatile__ ("eieio" : : : "memory");
+
+	/*
+	 * Now set the first dword including the valid bit
+	 * NOTE: this also unlocks the hpte
+	 */
+	hptep->dw0.dword0 = lhpte.dw0.dword0;
+
+	__asm__ __volatile__ ("ptesync" : : : "memory");
+
+	return ((secondary << 3) | i);
 }
-void hpte_init_pSeries(void)
+
+static long rpa_lpar_hpte_insert(unsigned long vpn, unsigned long prpn,
+				 unsigned long hpteflags,
+				 int bolted, int large)
 {
-	ppc_md.hpte_invalidate   = hpte_invalidate_pSeries;
-	ppc_md.hpte_updatepp     = hpte_updatepp_pSeries;
-	ppc_md.hpte_updateboltedpp = hpte_updateboltedpp_pSeries;
-	ppc_md.hpte_getword0     = hpte_getword0_pSeries;
-	ppc_md.hpte_selectslot   = hpte_selectslot_pSeries;
-	ppc_md.hpte_create_valid = hpte_create_valid_pSeries;
-	ppc_md.hpte_find	 = hpte_find_pSeries;
+	/* XXX fix for large page */
+	unsigned long lpar_rc;
+	unsigned long flags;
+	unsigned long slot;
+	HPTE lhpte;
+	int secondary;
+	unsigned long hash = hpt_hash(vpn, 0);
+	unsigned long avpn = vpn >> 11;
+	unsigned long arpn = physRpn_to_absRpn(prpn);
+	unsigned long hpte_group;
+
+	/* Fill in the local HPTE with absolute rpn, avpn and flags */
+	lhpte.dw1.dword1      = 0;
+	lhpte.dw1.dw1.rpn     = arpn;
+	lhpte.dw1.flags.flags = hpteflags;
+
+	lhpte.dw0.dword0      = 0;
+	lhpte.dw0.dw0.avpn    = avpn;
+	lhpte.dw0.dw0.bolted  = bolted;
+	lhpte.dw0.dw0.v       = 1;
+
+	if (large) lhpte.dw0.dw0.l = 1;
+
+	/* Now fill in the actual HPTE */
+	/* Set CEC cookie to 0         */
+	/* Large page = 0              */
+	/* Zero page = 0               */
+	/* I-cache Invalidate = 0      */
+	/* I-cache synchronize = 0     */
+	/* Exact = 0                   */
+	flags = 0;
+
+	/* XXX why is this here? - Anton */
+	/*   -- Because at one point we hit a case where non cachable
+	 *      pages where marked coherent & this is rejected by the HV.
+	 *      Perhaps it is no longer an issue ... DRENG.
+	 */ 
+	if (hpteflags & (_PAGE_GUARDED|_PAGE_NO_CACHE))
+		lhpte.dw1.flags.flags &= ~_PAGE_COHERENT;
+
+repeat:
+	secondary = 0;
+	lhpte.dw0.dw0.h = secondary;
+	hpte_group = ((hash & htab_data.htab_hash_mask) *
+		      HPTES_PER_GROUP) & ~0x7UL;
+
+	__asm__ __volatile__ (
+		H_ENTER_r3
+		"mr    4, %2\n"
+                "mr    5, %3\n"
+                "mr    6, %4\n"
+                "mr    7, %5\n"
+                HSC    
+                "mr    %0, 3\n"
+                "mr    %1, 4\n"
+		: "=r" (lpar_rc), "=r" (slot)
+		: "r" (flags), "r" (hpte_group), "r" (lhpte.dw0.dword0),
+		"r" (lhpte.dw1.dword1)
+		: "r0", "r3", "r4", "r5", "r6", "r7", 
+		  "r8", "r9", "r10", "r11", "r12", "cc");
+
+	if (lpar_rc == H_PTEG_Full) {
+		secondary = 1;
+		lhpte.dw0.dw0.h = secondary;
+		hpte_group = ((~hash & htab_data.htab_hash_mask) *
+			      HPTES_PER_GROUP) & ~0x7UL;
+
+		__asm__ __volatile__ (
+			      H_ENTER_r3
+			      "mr    4, %2\n"
+			      "mr    5, %3\n"
+			      "mr    6, %4\n"
+			      "mr    7, %5\n"
+			      HSC    
+			      "mr    %0, 3\n"
+			      "mr    %1, 4\n"
+			      : "=r" (lpar_rc), "=r" (slot)
+			      : "r" (flags), "r" (hpte_group), "r" (lhpte.dw0.dword0),
+			      "r" (lhpte.dw1.dword1)
+			      : "r0", "r3", "r4", "r5", "r6", "r7",
+			        "r8", "r9", "r10", "r11", "r12", "cc");
+		if (lpar_rc == H_PTEG_Full) {
+			if (mftb() & 0x1)
+				hpte_group=((hash & htab_data.htab_hash_mask)* 
+					    HPTES_PER_GROUP) & ~0x7UL;
+			
+			rpa_lpar_hpte_remove(hpte_group);
+			goto repeat;
+		}
+	}
+
+	if (lpar_rc != H_Success)
+		panic("Bad return code from pte enter rc = %lx\n", lpar_rc);
+
+	return ((secondary << 3) | (slot & 0x7));
 }
 
-/* Handle a fault by adding an HPTE 
- * If the address can't be determined to be valid
- * via Linux page tables, return 1.  If handled
- * return 0
- */
-int hash_page( unsigned long ea, unsigned long access )
+static long iSeries_hpte_insert(unsigned long vpn, unsigned long prpn,
+				unsigned long hpteflags,
+				int bolted, int large)
 {
-	int rc = 1;
-	void * pgdir = NULL;
-	unsigned long va, vsid, vpn;
-	unsigned long newpp, hash_ind, prpn;
-	unsigned long hpteflags, regionid;
+	HPTE lhpte;
+	unsigned long hash, hpte_group;
+	unsigned long avpn = vpn >> 11;
+	unsigned long arpn = physRpn_to_absRpn( prpn );
+	int secondary = 0;
 	long slot;
-	struct mm_struct * mm;
-	pte_t old_pte, new_pte, *ptep;
 
-	/* Check for invalid addresses. */
-	if (!IS_VALID_EA(ea)) {
-		return 1;
+	hash = hpt_hash(vpn, 0);
+
+repeat:
+	slot = HvCallHpt_findValid(&lhpte, vpn);
+	if (lhpte.dw0.dw0.v) {
+		panic("select_hpte_slot found entry already valid\n");
 	}
 
-	regionid =  REGION_ID(ea);
-	switch ( regionid ) {
-	case USER_REGION_ID:
-		mm = current->mm;
-		if ( mm == NULL ) {
-			PPCDBG(PPCDBG_MM, "hash_page returning; mm = 0\n"); 
-			return 1;
+	if (slot == -1) { /* No available entry found in either group */
+		if (mftb() & 0x1) {
+			hpte_group=((hash & htab_data.htab_hash_mask)* 
+				    HPTES_PER_GROUP) & ~0x7UL;
+		} else {
+			hpte_group=((~hash & htab_data.htab_hash_mask)* 
+				    HPTES_PER_GROUP) & ~0x7UL;
 		}
-		vsid = get_vsid(mm->context, ea );
-		break;
-	case IO_REGION_ID:
-		mm = &ioremap_mm;
-		vsid = get_kernel_vsid( ea );
-		break;
-	case VMALLOC_REGION_ID:
-		mm = &init_mm;
-		vsid = get_kernel_vsid( ea );
-		break;
-	case IO_UNMAPPED_REGION_ID:
-		udbg_printf("EEH Error ea = 0x%lx\n", ea);
- 		PPCDBG_ENTER_DEBUGGER();
-		panic("EEH Error ea = 0x%lx\n", ea);
-		break;
-	case KERNEL_REGION_ID:
-		/* As htab_initialize is now, we shouldn't ever get here since
-		 * we're bolting the entire 0xC0... region.
-		 */
-		udbg_printf("Little faulted on kernel address 0x%lx\n", ea);
- 		PPCDBG_ENTER_DEBUGGER();
-		panic("Little faulted on kernel address 0x%lx\n", ea);
-		break;
-	default:
-		/* Not a valid range, send the problem up to do_page_fault */
-		return 1;
-		break;
-	}
 
-	/* Search the Linux page table for a match with va */
-        va = ( vsid << 28 ) | ( ea & 0x0fffffff );
-	vpn = va >> PAGE_SHIFT;
-	pgdir = mm->pgd;
-	PPCDBG(PPCDBG_MM, "hash_page ea = 0x%16.16lx, va = 0x%16.16lx\n          current = 0x%16.16lx, access = %lx\n", ea, va, current, access); 
-                if ( pgdir == NULL ) {
-                return 1;
-	}
-	
-	/* Lock the Linux page table to prevent mmap and kswapd
-	 * from modifying entries while we search and update
-	 */
-	
-	spin_lock( &mm->page_table_lock );
-	
-	ptep = find_linux_pte( pgdir, ea );
-	/* If no pte found, send the problem up to do_page_fault */
-	if ( ! ptep ) {
-	  spin_unlock( &mm->page_table_lock );
-	  return 1;
-	}
-	
-	/* Acquire the hash table lock to guarantee that the linux
-	 * pte we fetch will not change
-	 */
-	spin_lock( &hash_table_lock );
-	
-	old_pte = *ptep;
-	
-	/* If the pte is not "present" (valid), send the problem
-	 * up to do_page_fault.
-	 */
-	if ( ! pte_present( old_pte ) ) {
-	  spin_unlock( &hash_table_lock );
-	  spin_unlock( &mm->page_table_lock );
-	  return 1;
-	}
-	
-	/* At this point we have found a pte (which was present).
-	 * The spinlocks prevent this status from changing
-	 * The hash_table_lock prevents the _PAGE_HASHPTE status
-	 * from changing (RPN, DIRTY and ACCESSED too)
-	 * The page_table_lock prevents the pte from being 
-	 * invalidated or modified
-	 */
+		hash = hpt_hash(vpn, 0);
+		iSeries_hpte_remove(hpte_group);
+		goto repeat;
+	} else if (slot < 0) {
+		slot &= 0x7fffffffffffffff;
+		secondary = 1;
+	}
+
+	/* Create the HPTE */
+	lhpte.dw1.dword1      = 0;
+	lhpte.dw1.dw1.rpn     = arpn;
+	lhpte.dw1.flags.flags = hpteflags;
+
+	lhpte.dw0.dword0     = 0;
+	lhpte.dw0.dw0.avpn   = avpn;
+	lhpte.dw0.dw0.h      = secondary;
+	lhpte.dw0.dw0.bolted = bolted;
+	lhpte.dw0.dw0.v      = 1;
 
-/* At this point, we have a pte (old_pte) which can be used to build or update
- * an HPTE.   There are 5 cases:
- *
- * 1. There is a valid (present) pte with no associated HPTE (this is 
- *	the most common case)
- * 2. There is a valid (present) pte with an associated HPTE.  The
- *	current values of the pp bits in the HPTE prevent access because the
- *	user doesn't have appropriate access rights.
- * 3. There is a valid (present) pte with an associated HPTE.  The
- *	current values of the pp bits in the HPTE prevent access because we are
- *	doing software DIRTY bit management and the page is currently not DIRTY. 
- * 4. This is a Kernel address (0xC---) for which there is no page directory.
- *	There is an HPTE for this page, but the pp bits prevent access.
- *      Since we always set up kernel pages with R/W access for the kernel
- *	this case only comes about for users trying to access the kernel.
- *	This case is always an error and is not dealt with further here.
- * 5. This is a Kernel address (0xC---) for which there is no page directory.
- *	There is no HPTE for this page.
+	/* Now fill in the actual HPTE */
+	HvCallHpt_addValidate(slot, secondary, (HPTE *)&lhpte);
+	return ((secondary << 3) | (slot & 0x7));
+}
 
- * Check the user's access rights to the page.  If access should be prevented
- * then send the problem up to do_page_fault.
+/*
+ * Functions used to remove hardware page table entries.
+ *
+ * Input : hpte_group: PTE index of the first entry in a group
+ * Output: offset within the group of the entry removed or
+ *         -1 on failure
  */
-
-	access |= _PAGE_PRESENT;
-	if ( 0 == ( access & ~(pte_val(old_pte)) ) ) {
-		/*
-		 * Check if pte might have an hpte, but we have
-		 * no slot information
-		 */
-		if ( pte_val(old_pte) & _PAGE_HPTENOIX ) {
-			unsigned long slot;	
-			pte_val(old_pte) &= ~_PAGE_HPTEFLAGS;
-			slot = ppc_md.hpte_find( vpn );
-			if ( slot != -1 ) {
-				if ( slot < 0 ) {
-					pte_val(old_pte) |= _PAGE_SECONDARY;
-					slot = -slot;
-				}
-				pte_val(old_pte) |= ((slot << 12) & _PAGE_GROUP_IX) | _PAGE_HASHPTE;
-				
-			}
+static long hpte_remove(unsigned long hpte_group)
+{
+	HPTE *hptep;
+	Hpte_dword0 dw0;
+	int i;
+	int slot_offset;
+	unsigned long vsid, group, pi, pi_high;
+	unsigned long slot;
+	unsigned long flags;
+	int large;
+	unsigned long va;
+
+	/* pick a random slot to start at */
+	slot_offset = mftb() & 0x7;
+
+	for (i = 0; i < HPTES_PER_GROUP; i++) {
+		hptep = htab_data.htab + hpte_group + slot_offset;
+		dw0 = hptep->dw0.dw0;
+
+		if (dw0.v && !dw0.bolted) {
+			/* retry with lock held */
+			dw0 = hptep->dw0.dw0;
+			if (dw0.v && !dw0.bolted)
+				break;
 		}
 
-		/* User has appropriate access rights. */
-		new_pte = old_pte;
-		/* If the attempted access was a store */
-		if ( access & _PAGE_RW )
-			pte_val(new_pte) |= _PAGE_ACCESSED |
-				_PAGE_DIRTY;
-		else
-			pte_val(new_pte) |= _PAGE_ACCESSED;
-
-		/* Only cases 1, 3 and 5 still in play */
-
-		newpp = computeHptePP( pte_val(new_pte) );
-
-		/* Check if pte already has an hpte (case 3) */
-		if ( pte_val(old_pte) & _PAGE_HASHPTE ) {
-			/* There MIGHT be an HPTE for this pte */
-			unsigned long hash, slot, secondary;
-			/* Local copy of first doubleword of HPTE */
-			union {
-				unsigned long d;
-				Hpte_dword0   h;
-			} hpte_dw0;
-			hash = hpt_hash(vpn, 0);
-			secondary = (pte_val(old_pte) & _PAGE_SECONDARY) >> 15;
-			if ( secondary )
-				hash = ~hash;
-			slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
-			slot += (pte_val(old_pte) & _PAGE_GROUP_IX) >> 12;
-			/* If there is an HPTE for this page it is indexed by slot */
-			hpte_dw0.d = ppc_md.hpte_getword0( slot );
-			if ( (hpte_dw0.h.avpn == (vpn >> 11) ) &&
-			     (hpte_dw0.h.v) && 
-			     (hpte_dw0.h.h == secondary ) ){
-				/* HPTE matches */
-				ppc_md.hpte_updatepp( slot, newpp, va );
-				if ( !pte_same( old_pte, new_pte ) )
-					*ptep = new_pte;
-			}
-			else {
-				/* HPTE is not for this pte */
-				pte_val(old_pte) &= ~_PAGE_HPTEFLAGS;
-			}
-		}
-		if ( !( pte_val(old_pte) & _PAGE_HASHPTE ) ) {
-			/* Cases 1 and 5 */
-			/* For these cases we need to create a new
-			 * HPTE and update the linux pte (for
-			 * case 1).  For case 5 there is no linux pte.
-			 *
-			 * Find an available HPTE slot
- 			 */
-			slot = ppc_md.hpte_selectslot( vpn );
-
-			/* If hpte_selectslot returns 0x8000000000000000 that means
-			 * that there was already an entry in the HPT even though
-			 * the linux PTE said there couldn't be. 
-			 */
-			/* Debug code */
-			if ( slot == 0x8000000000000000 ) {
-				unsigned long xold_pte = pte_val(old_pte);
-				unsigned long xnew_pte = pte_val(new_pte);
-				
-				udbg_printf("hash_page: ptep    = 0x%016lx\n", (unsigned long)ptep );
-				udbg_printf("hash_page: old_pte = 0x%016lx\n", xold_pte );
-				udbg_printf("hash_page: new_pte = 0x%016lx\n", xnew_pte );
-				udbg_printf("hash_page: ea      = 0x%016lx\n", ea );
-				udbg_printf("hash_page: va      = 0x%016lx\n", va );
-				udbg_printf("hash_page: access  = 0x%016lx\n", access );
-			
-				panic("hash_page: hpte already exists\n");
-			}
-			hash_ind = 0;
-			if ( slot < 0 ) {
-				slot = -slot;
-				hash_ind = 1;
-			}
+		slot_offset++;
+		slot_offset &= 0x7;
+	}
 
-			/* Set the physical address */
-			prpn = pte_val(old_pte) >> PTE_SHIFT;
-			
-			if ( ptep ) {
-				/* Update the linux pte with the HPTE slot */
-				pte_val(new_pte) &= ~_PAGE_HPTEFLAGS;
-				pte_val(new_pte) |= hash_ind << 15;
-				pte_val(new_pte) |= (slot<<12) & _PAGE_GROUP_IX;
-				pte_val(new_pte) |= _PAGE_HASHPTE;
-				/* No need to use ldarx/stdcx here because all
-				 * who might be updating the pte will hold the page_table_lock
-				 * or the hash_table_lock (we hold both)
-				 */
-				*ptep = new_pte;
-			}
+	if (i == HPTES_PER_GROUP)
+		return -1;
 
-			/* copy appropriate flags from linux pte */
-			hpteflags = (pte_val(new_pte) & 0x1f8) | newpp;
+	large = dw0.l;
 
-			/* Create the HPTE */
-			ppc_md.hpte_create_valid( slot, vpn, prpn, hash_ind, ptep, hpteflags, 0 ); 
+	/* Invalidate the hpte. NOTE: this also unlocks it */
+	hptep->dw0.dword0 = 0;
 
-		}
+	/* Invalidate the tlb */
+	vsid = dw0.avpn >> 5;
+	slot = hptep - htab_data.htab;
+	group = slot >> 3;
+	if (dw0.h)
+		group = ~group;
+	pi = (vsid ^ group) & 0x7ff;
+	pi_high = (dw0.avpn & 0x1f) << 11;
+	pi |= pi_high;
 
-		/* Indicate success */
-		rc = 0;
-	}		
-	
-	spin_unlock( &hash_table_lock );
-	if (ptep)
-		spin_unlock( &mm->page_table_lock );
+	if (large)
+		va = pi << LARGE_PAGE_SHIFT;
+	else
+		va = pi << PAGE_SHIFT;
+
+	spin_lock_irqsave(&pSeries_tlbie_lock, flags);
+	_tlbie(va, large);
+	spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
 
-	return rc;
+	return i;
 }
 
-void flush_hash_page( unsigned long context, unsigned long ea, pte_t *ptep )
+static long rpa_lpar_hpte_remove(unsigned long hpte_group)
 {
-	unsigned long vsid, vpn, va, hash, secondary, slot, flags;
-	/* Local copy of first doubleword of HPTE */
-	union {
-		unsigned long d;
-		Hpte_dword0   h;
-	} hpte_dw0;
-	pte_t pte;
+	unsigned long slot_offset;
+	unsigned long lpar_rc;
+	int i;
+	unsigned long dummy1, dummy2;
 
-	if ( (ea >= USER_START ) && ( ea <= USER_END ) )
-		vsid = get_vsid( context, ea );
-	else
-		vsid = get_kernel_vsid( ea );
-	va = (vsid << 28) | (ea & 0x0fffffff);
-	vpn = va >> PAGE_SHIFT;
-	hash = hpt_hash(vpn, 0);
+	/* pick a random slot to start at */
+	slot_offset = mftb() & 0x7;
 
-	spin_lock_irqsave( &hash_table_lock, flags);
-	pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0));
-	if ( pte_val(pte) & _PAGE_HASHPTE ) {
-		secondary = (pte_val(pte) & _PAGE_SECONDARY) >> 15;
-		if ( secondary )
-			hash = ~hash;
-		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
-		slot += (pte_val(pte) & _PAGE_GROUP_IX) >> 12;
-		/* If there is an HPTE for this page it is indexed by slot */
+	for (i = 0; i < HPTES_PER_GROUP; i++) {
 
-		hpte_dw0.d = ppc_md.hpte_getword0( slot );
-		if ( (hpte_dw0.h.avpn == (vpn >> 11) ) &&
-		     (hpte_dw0.h.v) && 
-		     (hpte_dw0.h.h == secondary ) ){
-			/* HPTE matches */
-			ppc_md.hpte_invalidate( slot );	
-		}
-		else {
-			unsigned k;
-			/* Temporarily lets check for the hpte in all possible slots */
-			for ( secondary = 0; secondary < 2; ++secondary ) {
-				hash = hpt_hash(vpn, 0);
-				if ( secondary )
-					hash = ~hash;
-				slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
-				for ( k=0; k<8; ++k ) {
-					hpte_dw0.d = ppc_md.hpte_getword0( slot+k );
-					if ( ( hpte_dw0.h.avpn == (vpn >> 11) ) &&
-					     ( hpte_dw0.h.v ) &&
-					     ( hpte_dw0.h.h == secondary ) ) {
-						while (1) ;
-					}
-				}
-			}
-		}
+		/* Don't remove a bolted entry */
+		lpar_rc = plpar_pte_remove(H_ANDCOND, hpte_group + slot_offset,
+					   (0x1UL << 4), &dummy1, &dummy2);
+
+		if (lpar_rc == H_Success)
+			return i;
+
+		if (lpar_rc != H_Not_Found)
+			panic("Bad return code from pte remove rc = %lx\n",
+			      lpar_rc);
+
+		slot_offset++;
+		slot_offset &= 0x7;
 	}
-	spin_unlock_irqrestore( &hash_table_lock, flags );
+
+	return -1;
 }
 
-int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
-		   void *buffer, size_t *lenp)
+static long iSeries_hpte_remove(unsigned long hpte_group)
 {
-	int vleft, first=1, len, left, val;
-#define TMPBUFLEN 256
-	char buf[TMPBUFLEN], *p;
-	static const char *sizestrings[4] = {
-		"2MB", "256KB", "512KB", "1MB"
-	};
-	static const char *clockstrings[8] = {
-		"clock disabled", "+1 clock", "+1.5 clock", "reserved(3)",
-		"+2 clock", "+2.5 clock", "+3 clock", "reserved(7)"
-	};
-	static const char *typestrings[4] = {
-		"flow-through burst SRAM", "reserved SRAM",
-		"pipelined burst SRAM", "pipelined late-write SRAM"
-	};
-	static const char *holdstrings[4] = {
-		"0.5", "1.0", "(reserved2)", "(reserved3)"
-	};
-
-	if ( ((_get_PVR() >> 16) != 8) && ((_get_PVR() >> 16) != 12))
-		return -EFAULT;
-	
-	if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) {
-		*lenp = 0;
-		return 0;
-	}
-	
-	vleft = table->maxlen / sizeof(int);
-	left = *lenp;
-	
-	for (; left /*&& vleft--*/; first=0) {
-		if (write) {
-			while (left) {
-				char c;
-				if(get_user(c,(char *) buffer))
-					return -EFAULT;
-				if (!isspace(c))
-					break;
-				left--;
-				((char *) buffer)++;
-			}
-			if (!left)
-				break;
-			len = left;
-			if (len > TMPBUFLEN-1)
-				len = TMPBUFLEN-1;
-			if(copy_from_user(buf, buffer, len))
-				return -EFAULT;
-			buf[len] = 0;
-			p = buf;
-			if (*p < '0' || *p > '9')
-				break;
-			val = simple_strtoul(p, &p, 0);
-			len = p-buf;
-			if ((len < left) && *p && !isspace(*p))
-				break;
-			buffer += len;
-			left -= len;
-#if 0
-			/* DRENG need a def */
-			_set_L2CR(0);
-			_set_L2CR(val);
-			while ( _get_L2CR() & 0x1 )
-				/* wait for invalidate to finish */;
-#endif
-			  
-		} else {
-			p = buf;
-			if (!first)
-				*p++ = '\t';
-#if 0
-			/* DRENG need a def */
-			val = _get_L2CR();
-#endif
-			p += sprintf(p, "0x%08x: ", val);
-			p += sprintf(p, " %s", (val >> 31) & 1 ? "enabled" :
-				     "disabled");
-			p += sprintf(p, ", %sparity", (val>>30)&1 ? "" : "no ");
-			p += sprintf(p, ", %s", sizestrings[(val >> 28) & 3]);
-			p += sprintf(p, ", %s", clockstrings[(val >> 25) & 7]);
-			p += sprintf(p, ", %s", typestrings[(val >> 23) & 2]);
-			p += sprintf(p, "%s", (val>>22)&1 ? ", data only" : "");
-			p += sprintf(p, "%s", (val>>20)&1 ? ", ZZ enabled": "");
-			p += sprintf(p, ", %s", (val>>19)&1 ? "write-through" :
-				     "copy-back");
-			p += sprintf(p, "%s", (val>>18)&1 ? ", testing" : "");
-			p += sprintf(p, ", %sns hold",holdstrings[(val>>16)&3]);
-			p += sprintf(p, "%s", (val>>15)&1 ? ", DLL slow" : "");
-			p += sprintf(p, "%s", (val>>14)&1 ? ", diff clock" :"");
-			p += sprintf(p, "%s", (val>>13)&1 ? ", DLL bypass" :"");
-			
-			p += sprintf(p,"\n");
-			
-			len = strlen(buf);
-			if (len > left)
-				len = left;
-			if(copy_to_user(buffer, buf, len))
-				return -EFAULT;
-			left -= len;
-			buffer += len;
-			break;
+	unsigned long slot_offset;
+	int i;
+	HPTE lhpte;
+
+	/* Pick a random slot to start at */
+	slot_offset = mftb() & 0x7;
+
+	for (i = 0; i < HPTES_PER_GROUP; i++) {
+		lhpte.dw0.dword0 = 
+			iSeries_hpte_getword0(hpte_group + slot_offset);
+
+		if (!lhpte.dw0.dw0.bolted) {
+			HvCallHpt_invalidateSetSwBitsGet(hpte_group + 
+							 slot_offset, 0, 0);
+			return i;
 		}
-	}
 
-	if (!write && !first && left) {
-		if(put_user('\n', (char *) buffer))
-			return -EFAULT;
-		left--, buffer++;
-	}
-	if (write) {
-		p = (char *) buffer;
-		while (left) {
-			char c;
-			if(get_user(c, p++))
-				return -EFAULT;
-			if (!isspace(c))
-				break;
-			left--;
-		}
+		slot_offset++;
+		slot_offset &= 0x7;
 	}
-	if (write && first)
-		return -EINVAL;
-	*lenp -= left;
-	filp->f_pos += *lenp;
-	return 0;
+
+	return -1;
+}
+
+void hpte_init_pSeries(void)
+{
+	ppc_md.hpte_invalidate     = hpte_invalidate;
+	ppc_md.hpte_updatepp       = hpte_updatepp;
+	ppc_md.hpte_updateboltedpp = hpte_updateboltedpp;
+	ppc_md.hpte_insert	   = hpte_insert;
+	ppc_md.hpte_remove	   = hpte_remove;
+}
+
+void pSeries_lpar_mm_init(void)
+{
+	ppc_md.hpte_invalidate     = rpa_lpar_hpte_invalidate;
+	ppc_md.hpte_updatepp       = rpa_lpar_hpte_updatepp;
+	ppc_md.hpte_updateboltedpp = rpa_lpar_hpte_updateboltedpp;
+	ppc_md.hpte_insert         = rpa_lpar_hpte_insert;
+	ppc_md.hpte_remove         = rpa_lpar_hpte_remove;
+}
+
+void hpte_init_iSeries(void)
+{
+	ppc_md.hpte_invalidate     = iSeries_hpte_invalidate;
+	ppc_md.hpte_updatepp       = iSeries_hpte_updatepp;
+	ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp;
+	ppc_md.hpte_insert         = iSeries_hpte_insert;
+	ppc_md.hpte_remove         = iSeries_hpte_remove;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/iSeries_IoMmTable.c linux-2.4.20/arch/ppc64/kernel/iSeries_IoMmTable.c
--- linux-2.4.19/arch/ppc64/kernel/iSeries_IoMmTable.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/iSeries_IoMmTable.c	2002-10-29 11:18:31.000000000 +0000
@@ -130,7 +130,7 @@
 /*   The HvCallPci_getBarParms is used to get the size of the BAR  */
 /*   space.  It calls iSeries_IoMmTable_AllocateEntry to allocate  */
 /*   each entry.                                                   */
-/* - Loops through The Bar resourses(0 - 5) including the the ROM  */
+/* - Loops through The Bar resourses(0 - 5) including the ROM      */
 /*   is resource(6).                                               */
 /*******************************************************************/
 void iSeries_allocateDeviceBars(struct pci_dev* PciDev)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/iSeries_pci.c linux-2.4.20/arch/ppc64/kernel/iSeries_pci.c
--- linux-2.4.19/arch/ppc64/kernel/iSeries_pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/iSeries_pci.c	2002-10-29 11:18:33.000000000 +0000
@@ -4,7 +4,7 @@
  * Copyright (C) 2001 Allan Trautman, IBM Corporation
  *
  * iSeries specific routines for PCI.
- * 
+ * /
  * Based on code from pci.c and iSeries_pci.c 32bit
  *
  * This program is free software; you can redistribute it and/or modify
@@ -28,6 +28,8 @@
 #include <linux/init.h>
 #include <linux/ide.h>
 #include <linux/pci.h>
+#include <linux/rtc.h>
+#include <linux/time.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -37,6 +39,8 @@
 #include <asm/ppcdebug.h>
 #include <asm/naca.h>
 #include <asm/flight_recorder.h>
+#include <asm/hardirq.h>
+#include <asm/time.h>
 #include <asm/pci_dma.h>
 
 #include <asm/iSeries/HvCallPci.h>
@@ -76,9 +80,6 @@
 extern int    Pci_Error_Flag;
 extern int    Pci_Trace_Flag;
 
-extern void iSeries_MmIoTest(void);
-
-
 /*******************************************************************
  * Forward declares of prototypes. 
  *******************************************************************/
@@ -379,7 +380,10 @@
 			if(DevInfo->deviceType == HvCallPci_NodeDevice) {
 				iSeries_Scan_EADs_Bridge(Bus, SubBus, IdSel);
 			}
-			else printk("PCI: Invalid System Configuration(0x%02X.\n",DevInfo->deviceType);
+			else {
+				printk("PCI: Invalid System Configuration(0x%02X).\n",DevInfo->deviceType);
+				PCIFR(      "Invalid System Configuration(0x%02X).",  DevInfo->deviceType);
+			}
 		}
 		else pci_Log_Error("getDeviceInfo",Bus, SubBus, IdSel,HvRc);
 	}
@@ -511,7 +515,7 @@
 /* I/0 Memory copy MUST use mmio commands on iSeries                    */
 /* To do; For performance, include the hv call directly                 */
 /************************************************************************/
-void* iSeries_memset(void* dest, char c, size_t Count)
+void* iSeries_memset_io(void* dest, char c, size_t Count)
 {
 	u8    ByteValue     = c;
 	long  NumberOfBytes = Count;
@@ -580,6 +584,18 @@
 	}
 	return Node;
 }
+/******************************************************************/
+/* Set and reset Device Node Lock                                 */
+/******************************************************************/
+#define setIoLock() \
+    unsigned long IrqFlags; \
+    spin_lock_irqsave(&DevNode->IoLock, IrqFlags ); 
+
+#define resetIoLock() \
+    int RtnCode = DevNode->ReturnCode; \
+    spin_unlock_irqrestore( &DevNode->IoLock, IrqFlags ); \
+    return RtnCode;
+
 /**********************************************************************************
  *
  * Read PCI Config Space Code 
@@ -588,8 +604,8 @@
 /** BYTE  *************************************************************************/
 int iSeries_Node_read_config_byte(struct iSeries_Device_Node* DevNode, int Offset, u8* ReadValue)
 {
-	u8  ReadData; 
-	if(DevNode == NULL) { return 0x301; } 
+	u8  ReadData;
+	setIoLock();
 	++Pci_Cfg_Read_Count;
 	DevNode->ReturnCode = HvCallPci_configLoad8(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
 	                                                Offset,&ReadData);
@@ -600,14 +616,14 @@
 		printk("PCI: RCB: 0x%04X.%02X  Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 		PCIFR(      "RCB: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 	}
-	*ReadValue = ReadData; 
- 	return DevNode->ReturnCode;
+	*ReadValue = ReadData;
+	resetIoLock();
 }
 /** WORD  *************************************************************************/
 int iSeries_Node_read_config_word(struct iSeries_Device_Node* DevNode, int Offset, u16* ReadValue)
 {
 	u16  ReadData; 
-	if(DevNode == NULL) { return 0x301; } 
+	setIoLock();
 	++Pci_Cfg_Read_Count;
 	DevNode->ReturnCode = HvCallPci_configLoad16(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
 	                                                Offset,&ReadData);
@@ -619,14 +635,14 @@
 		PCIFR(      "RCW: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 
 	}
-	*ReadValue = ReadData; 
- 	return DevNode->ReturnCode;
+	*ReadValue = ReadData;
+	resetIoLock();
 }
 /** DWORD *************************************************************************/
 int iSeries_Node_read_config_dword(struct iSeries_Device_Node* DevNode, int Offset, u32* ReadValue)
 {
  	u32  ReadData; 
-	if(DevNode == NULL) { return 0x301; } 
+	setIoLock();
 	++Pci_Cfg_Read_Count;
 	DevNode->ReturnCode = HvCallPci_configLoad32(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
 	                                                Offset,&ReadData);
@@ -637,8 +653,8 @@
 		printk("PCI: RCL: 0x%04X.%02X  Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 		PCIFR(      "RCL: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 	}
-	*ReadValue = ReadData; 
- 	return DevNode->ReturnCode;
+	*ReadValue = ReadData;
+	resetIoLock();
 }
 int iSeries_pci_read_config_byte(struct pci_dev* PciDev, int Offset, u8* ReadValue) { 
 	struct iSeries_Device_Node* DevNode = get_Device_Node(PciDev);
@@ -662,6 +678,7 @@
 /** BYTE  *************************************************************************/
 int iSeries_Node_write_config_byte(struct iSeries_Device_Node* DevNode, int Offset, u8 WriteData)
 {
+	setIoLock();
 	++Pci_Cfg_Write_Count;
 	DevNode->ReturnCode = HvCallPci_configStore8(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
 	                                                  Offset,WriteData);
@@ -672,11 +689,12 @@
 		printk("PCI: WCB: 0x%04X.%02X  Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 		PCIFR(      "WCB: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 	}
- 	return DevNode->ReturnCode;
+	resetIoLock();
 }
 /** WORD  *************************************************************************/
 int iSeries_Node_write_config_word(struct iSeries_Device_Node* DevNode, int Offset, u16 WriteData)
 {
+	setIoLock();
 	++Pci_Cfg_Write_Count;
 	DevNode->ReturnCode = HvCallPci_configStore16(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
 	                                                  Offset,WriteData);
@@ -687,11 +705,12 @@
 		printk("PCI: WCW: 0x%04X.%02X  Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 		PCIFR(      "WCW: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 	}
- 	return DevNode->ReturnCode;
+	resetIoLock();
 }
 /** DWORD *************************************************************************/
 int iSeries_Node_write_config_dword(struct iSeries_Device_Node* DevNode, int Offset, u32 WriteData)
 {
+	setIoLock();
 	++Pci_Cfg_Write_Count;
 	DevNode->ReturnCode = HvCallPci_configStore32(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
 	                                                  Offset,WriteData);
@@ -702,7 +721,7 @@
 		printk("PCI: WCL: 0x%04X.%02X  Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 		PCIFR(      "WCL: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
 	}
-	return DevNode->ReturnCode;
+	resetIoLock();
 }
 int iSeries_pci_write_config_byte( struct pci_dev* PciDev,int Offset, u8 WriteValue)
 {
@@ -736,69 +755,93 @@
 };
 
 /************************************************************************
- * Check Return Code
+ * Log Pci Error and check Retry Count 
  * -> On Failure, print and log information.
  *    Increment Retry Count, if exceeds max, panic partition.
- * -> If in retry, print and log success 
- ************************************************************************
- * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234
- * PCI: Device 23.90 ReadL Retry( 1)
- * PCI: Device 23.90 ReadL Retry Successful(1)
+ * -> If in retry, print and log success
  ************************************************************************/
-int  CheckReturnCode(char* TextHdr, struct iSeries_Device_Node* DevNode, u64 RtnCode)
+void logPciError(char* ErrorTxt, void* IoAddress, struct iSeries_Device_Node* DevNode, u64 RtnCode)
 {
-	if(RtnCode != 0)  {
-		++Pci_Error_Count;
-		++DevNode->IoRetry;
-		PCIFR(      "%s: Device 0x%04X:%02X  I/O Error(%2d): 0x%04X",
-			    TextHdr,ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->IoRetry,(int)RtnCode);
-		printk("PCI: %s: Device 0x%04X:%02X  I/O Error(%2d): 0x%04X\n",
-		            TextHdr,ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->IoRetry,(int)RtnCode);
-		/*******************************************************/
-		/* Bump the retry and check for retry count exceeded.  */
-		/* If, Exceeded, panic the system.                     */           
-		/*******************************************************/
-		if(DevNode->IoRetry > Pci_Retry_Max && Pci_Error_Flag > 0 ) {
-			mf_displaySrc(0xB6000103);
-			panic_timeout = 0; 
-			panic("PCI: Hardware I/O Error, SRC B6000103, Automatic Reboot Disabled.\n");
-		}
-		return -1;	/* Retry Try */
-	}
-	/********************************************************************
-	* If retry was in progress, log success and rest retry count        *
-	*********************************************************************/
-	else if(DevNode->IoRetry > 0) {
-		PCIFR("%s: Device 0x%04X:%02X Retry Successful(%2d).",
-		      TextHdr,ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->IoRetry);
-		DevNode->IoRetry = 0;
-		return 0; 
+	++DevNode->IoRetry;
+	++Pci_Error_Count;
+
+	PCIFR("%s: I/O Error(%1d/%1d):0x%04X  IoAddress:0x%p  Device:0x%04X:%02X",  
+	      ErrorTxt, DevNode->IoRetry, in_interrupt(), RtnCode, IoAddress, ISERIES_BUS(DevNode),DevNode->AgentId);
+	/*******************************************************/
+	/* Filter out EADs freeze and alignment errors         */
+	/*******************************************************/
+	if(RtnCode == 0x0102) {
+		PCIFR("EADS Freeze error.......Panic........");
+		mf_displaySrc(0xB6000103);
+		panic_timeout = 0; 
+		panic("PCI: EADs Freeze error SRC B6000103\n");
+	}
+	else if(RtnCode == 0x0241) {
+		PCIFR("MMIO Alignment error: 0x%p",IoAddress);
+		mf_displaySrc(0xB6000103);
+		panic_timeout = 0; 
+		panic("PCI: MMIO Alignment error. SRC B6000103\n");
+	}
+	/*******************************************************/
+	/* Bump the retry and check for retry count exceeded.  */
+	/* If, Exceeded, panic the system.                     */           
+	/*******************************************************/
+	if(DevNode->IoRetry > Pci_Retry_Max && Pci_Error_Flag != 0 ) {
+		mf_displaySrc(0xB6000103);
+		panic_timeout = 0; 
+		panic("PCI: Hardware I/O Error, SRC B6000103, Automatic Reboot Disabled.\n");
+	}
+	/**************************************************************/
+	/* Wait x ms before retrying I/O to give I/O time to recover. */
+	/* Retry wait delay logic.                                    */
+	/* - On first retry, no delay, maybe just glitch.             */
+	/* - On successify retries, vary the delay to avoid being in a*/
+        /*   repetitive timing window.                                */ 
+	/**************************************************************/
+	if(DevNode->IoRetry > 0) {
+		udelay(DevNode->IoRetry * 50);
 	}
-	return 0; 
 }
+
+/************************************************************************
+ * Retry was successful
+ ************************************************************************/
+void  pciRetrySuccessful(struct iSeries_Device_Node* DevNode)
+{
+	struct  timeval  TimeClock;
+	struct  rtc_time CurTime;
+	do_gettimeofday(&TimeClock);
+	to_tm(TimeClock.tv_sec, &CurTime);
+
+	PCIFR("Retry Successful(%2d) on Device 0x%04X:%02X at %02d.%02d.%02d",
+	      DevNode->IoRetry,ISERIES_BUS(DevNode),DevNode->AgentId,
+	      CurTime.tm_hour,CurTime.tm_min,CurTime.tm_sec);
+
+	DevNode->IoRetry = 0;
+}
+
 /************************************************************************/
 /* Translate the I/O Address into a device node, bar, and bar offset.   */
 /* Note: Make sure the passed variable end up on the stack to avoid     */
 /* the exposure of being device global.                                 */
+/* The Device Node is Lock to block other I/O to device.                */
 /************************************************************************/
-static inline struct iSeries_Device_Node* xlateIoMmAddress(void* IoAddress,
-							    union HvDsaMap* DsaPtr,
-							   u64* BarOffsetPtr) {
-
-	unsigned long BaseIoAddr = (unsigned long)IoAddress-iSeries_Base_Io_Memory;
-	long          TableIndex = BaseIoAddr/iSeries_IoMmTable_Entry_Size;
-	struct iSeries_Device_Node* DevNode = *(iSeries_IoMmTable +TableIndex);
-	if(DevNode != NULL) {
-		DsaPtr->DsaAddr       = ISERIES_DSA(DevNode);
-		DsaPtr->Dsa.barNumber = *(iSeries_IoBarTable+TableIndex);
-		*BarOffsetPtr         = BaseIoAddr % iSeries_IoMmTable_Entry_Size;
-	}
-	else {
-		panic("PCI: Invalid PCI IoAddress detected!\n");
-	}
-	return DevNode;
-}
-
+#define setUpMmIo(IoAddress,Type) \
+unsigned long   IrqFlags; \
+struct HvCallPci_LoadReturn Return; \
+union HvDsaMap  DsaData;  \
+u64             BarOffset;\
+unsigned long BaseIoAddr = (unsigned long)IoAddress-iSeries_Base_Io_Memory; \
+long          TableIndex = (BaseIoAddr/iSeries_IoMmTable_Entry_Size);       \
+struct iSeries_Device_Node* DevNode = *(iSeries_IoMmTable+TableIndex);      \
+if(DevNode != NULL) { \
+    DsaData.DsaAddr       = ISERIES_DSA(DevNode); \
+    DsaData.Dsa.barNumber = *(iSeries_IoBarTable+TableIndex); \
+    BarOffset             = BaseIoAddr % iSeries_IoMmTable_Entry_Size; \
+    ++Pci_Io_##Type##_Count; \
+    spin_lock_irqsave(&DevNode->IoLock, IrqFlags ); \
+} \
+else panic("PCI: Invalid PCI IoAddress detected 0x%p!\n",IoAddress);
 /************************************************************************/
 /* Read MM I/O Instructions for the iSeries                             */
 /* On MM I/O error, all ones are returned and iSeries_pci_IoError is cal*/
@@ -810,47 +853,53 @@
 /************************************************************************/
 u8  iSeries_Read_Byte(void* IoAddress)
 {
-	u64    BarOffset;
-	union  HvDsaMap DsaData;
-	struct HvCallPci_LoadReturn Return;
-	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
-
+	setUpMmIo(IoAddress,Read);
 	do {
-		++Pci_Io_Read_Count;
 		HvCall3Ret16(HvCallPciBarLoad8, &Return, DsaData.DsaAddr,BarOffset, 0);
-	} while (CheckReturnCode("RDB",DevNode, Return.rc) != 0);
-
-	if(Pci_Trace_Flag == 1)	PCIFR("RDB: IoAddress 0x%p = 0x%02X",IoAddress, (u8)Return.value); 
+		if(Return.rc != 0 ) {
+			logPciError("RDB",IoAddress, DevNode, Return.rc);
+		}
+		else if ( DevNode->IoRetry > 0) {
+			pciRetrySuccessful(DevNode);
+		}
+	} while (Return.rc != 0);
+	spin_unlock_irqrestore(&DevNode->IoLock, IrqFlags ); 
+	if(Pci_Trace_Flag == 1 ) PCIFR("RDB: IoAddress 0x%p = 0x%02X",IoAddress, (u8)Return.value);
 	return (u8)Return.value;
 }
+int Retry_Test = 0;
 u16  iSeries_Read_Word(void* IoAddress)
 {
-	u64    BarOffset;
-	union  HvDsaMap DsaData;
-	struct HvCallPci_LoadReturn Return;
-	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
-
+	setUpMmIo(IoAddress,Read);
 	do {
-		++Pci_Io_Read_Count;
 		HvCall3Ret16(HvCallPciBarLoad16,&Return, DsaData.DsaAddr,BarOffset, 0);
-	} while (CheckReturnCode("RDW",DevNode, Return.rc) != 0);
 
-	if(Pci_Trace_Flag == 1) PCIFR("RDW: IoAddress 0x%p = 0x%04X",IoAddress, swab16((u16)Return.value));
+		if(Return.rc != 0 ) {
+			logPciError("RDW",IoAddress, DevNode, Return.rc);
+		}
+		else if ( DevNode->IoRetry > 0) {
+			pciRetrySuccessful(DevNode);
+		}
+	} while (Return.rc != 0);
+	spin_unlock_irqrestore(&DevNode->IoLock, IrqFlags ); 
+	if(Pci_Trace_Flag == 1 ) PCIFR("RDW: IoAddress 0x%p = 0x%04X",IoAddress, (u16)Return.value);
 	return swab16((u16)Return.value);
 }
 u32  iSeries_Read_Long(void* IoAddress)
 {
-	u64    BarOffset;
-	union  HvDsaMap DsaData;
-	struct HvCallPci_LoadReturn Return;
-	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
-
+	setUpMmIo(IoAddress,Read);
 	do {
-		++Pci_Io_Read_Count;
 		HvCall3Ret16(HvCallPciBarLoad32,&Return, DsaData.DsaAddr,BarOffset, 0);
-	} while (CheckReturnCode("RDL",DevNode, Return.rc) != 0);
 
-	if(Pci_Trace_Flag == 1) PCIFR("RDL: IoAddress 0x%p = 0x%04X",IoAddress, swab32((u32)Return.value));
+		if(Return.rc != 0 ) {
+			logPciError("RDL",IoAddress, DevNode, Return.rc);
+		}
+		else if ( DevNode->IoRetry > 0) {
+			pciRetrySuccessful(DevNode);
+		}
+	} while (Return.rc != 0);
+	spin_unlock_irqrestore(&DevNode->IoLock, IrqFlags ); 
+	if(Pci_Trace_Flag == 1 ) PCIFR("RDL: IoAddress 0x%p = 0x%08X",IoAddress, swab32((u32)Return.value));
 	return swab32((u32)Return.value);
 }
 /************************************************************************/
@@ -862,41 +911,47 @@
 /************************************************************************/
 void iSeries_Write_Byte(u8 Data, void* IoAddress)
 {
-	u64    BarOffset;
-	union  HvDsaMap DsaData;
-	struct HvCallPci_LoadReturn Return;
-	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
-
+	setUpMmIo(IoAddress,Write);
 	do {
-		++Pci_Io_Write_Count;
 		Return.rc = HvCall4(HvCallPciBarStore8, DsaData.DsaAddr,BarOffset, Data, 0);
-	} while (CheckReturnCode("WWB",DevNode, Return.rc) != 0);
+		if(Return.rc != 0 ) {
+			logPciError("WWB",IoAddress, DevNode, Return.rc);
+		}
+		else if ( DevNode->IoRetry > 0) {
+			pciRetrySuccessful(DevNode);
+		}
+	} while (Return.rc != 0);
+	spin_unlock_irqrestore(&DevNode->IoLock, IrqFlags ); 
 	if(Pci_Trace_Flag == 1) PCIFR("WWB: IoAddress 0x%p = 0x%02X",IoAddress,Data);
 }
 void iSeries_Write_Word(u16 Data, void* IoAddress)
 {
-	u64    BarOffset;
-	union  HvDsaMap DsaData;
-	struct HvCallPci_LoadReturn Return;
-	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
-
+	setUpMmIo(IoAddress,Write);
 	do {
-		++Pci_Io_Write_Count;
 		Return.rc = HvCall4(HvCallPciBarStore16,DsaData.DsaAddr,BarOffset, swab16(Data), 0);
-	} while (CheckReturnCode("WWW",DevNode, Return.rc) != 0);
+		if(Return.rc != 0 ) {
+			logPciError("WWW",IoAddress, DevNode, Return.rc);
+		}
+		else if ( DevNode->IoRetry > 0) {
+			pciRetrySuccessful(DevNode);
+		}
+	} while (Return.rc != 0);
+	spin_unlock_irqrestore(&DevNode->IoLock, IrqFlags ); 
 	if(Pci_Trace_Flag == 1) PCIFR("WWW: IoAddress 0x%p = 0x%04X",IoAddress,Data);
 }
 void iSeries_Write_Long(u32 Data, void* IoAddress)
 {
-	u64    BarOffset;
-	union  HvDsaMap DsaData;
-	struct HvCallPci_LoadReturn Return;
-	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
-
+	setUpMmIo(IoAddress,Write);
 	do {
-		++Pci_Io_Write_Count;
 		Return.rc = HvCall4(HvCallPciBarStore32,DsaData.DsaAddr,BarOffset, swab32(Data), 0);
-	} while (CheckReturnCode("WWL",DevNode, Return.rc) != 0);
+		if(Return.rc != 0 ) {
+			logPciError("WWL",IoAddress, DevNode, Return.rc);
+		}
+		else if ( DevNode->IoRetry > 0) {
+			pciRetrySuccessful(DevNode);
+		}
+	} while (Return.rc != 0);
+	spin_unlock_irqrestore(&DevNode->IoLock, IrqFlags ); 
 	if(Pci_Trace_Flag == 1) PCIFR("WWL: IoAddress 0x%p = 0x%08X",IoAddress, Data);
 }
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/iSeries_pci_reset.c linux-2.4.20/arch/ppc64/kernel/iSeries_pci_reset.c
--- linux-2.4.19/arch/ppc64/kernel/iSeries_pci_reset.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/iSeries_pci_reset.c	2002-10-29 11:18:39.000000000 +0000
@@ -78,7 +78,7 @@
 		schedule_timeout(WaitDelay);
 	}
 	if (DeviceNode->ReturnCode == 0) {
-		PCIFR("Slot 0x%04X.%02 Reset\n",ISERIES_BUS(DeviceNode),DeviceNode->AgentId );
+		PCIFR("Slot 0x%04X.%02X Reset\n",ISERIES_BUS(DeviceNode),DeviceNode->AgentId );
 	} 
 	else {
 		printk("PCI: Slot 0x%04X.%02X Reset Failed, RCode: %04X\n",ISERIES_BUS(DeviceNode),DeviceNode->AgentId,DeviceNode->ReturnCode);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/iSeries_setup.c linux-2.4.20/arch/ppc64/kernel/iSeries_setup.c
--- linux-2.4.19/arch/ppc64/kernel/iSeries_setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/iSeries_setup.c	2002-10-29 11:18:39.000000000 +0000
@@ -49,6 +49,7 @@
 #include <asm/iSeries/IoHriMainStore.h>
 #include <asm/iSeries/iSeries_proc.h>
 #include <asm/proc_pmc.h>
+#include <asm/perfmon.h>
 #include <asm/iSeries/mf.h>
 
 /* Function Prototypes */
@@ -59,13 +60,10 @@
 static void setup_iSeries_cache_sizes( void );
 static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr);
 #endif
-void build_valid_hpte( unsigned long vsid, unsigned long ea, unsigned long pa,
-		       pte_t * ptep, unsigned hpteflags, unsigned bolted );
 extern void ppcdbg_initialize(void);
 extern void iSeries_pcibios_init(void);
 extern void iSeries_pcibios_fixup(void);
 extern void iSeries_pcibios_fixup_bus(int);
-static void iSeries_setup_dprofile(void);
 
 /* Global Variables */
 
@@ -77,10 +75,6 @@
 static unsigned long tbFreqMhz = 0;
 static unsigned long tbFreqMhzHundreths = 0;
 
-unsigned long dprof_shift = 0;
-unsigned long dprof_len = 0;
-unsigned int * dprof_buffer = NULL;
-
 int piranha_simulator = 0;
 
 extern char _end[];
@@ -257,7 +251,7 @@
 {
 	unsigned long i;
 	unsigned long mem_blocks = 0;
-	if ( __is_processor( PV_POWER4 ) )
+	if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p))
 		mem_blocks = iSeries_process_Regatta_mainstore_vpd( mb_array, max_entries );
 	else
 		mem_blocks = iSeries_process_Condor_mainstore_vpd( mb_array, max_entries );
@@ -283,8 +277,6 @@
 iSeries_init_early(void)
 {
 #ifdef CONFIG_PPC_ISERIES
-	ppcdbg_initialize();
-	
 #if defined(CONFIG_BLK_DEV_INITRD)
 	/*
 	 * If the init RAM disk has been configured and there is
@@ -397,28 +389,6 @@
 			*(p+1) = 0;
 	}
 
-        if (strstr(cmd_line, "dprofile=")) {
-                char *p, *q;
-
-                for (q = cmd_line; (p = strstr(q, "dprofile=")) != 0; ) {
-			unsigned long size, new_klimit;
-                        q = p + 9;
-                        if (p > cmd_line && p[-1] != ' ')
-                                continue;
-                        dprof_shift = simple_strtoul(q, &q, 0);
-			dprof_len = (unsigned long)&_etext - (unsigned long)&_stext;
-			dprof_len >>= dprof_shift;
-			size = ((dprof_len * sizeof(unsigned int)) + (PAGE_SIZE-1)) & PAGE_MASK;
-			dprof_buffer = (unsigned int *)((klimit + (PAGE_SIZE-1)) & PAGE_MASK);
-			new_klimit = ((unsigned long)dprof_buffer) + size;
-			lmb_reserve( __pa(klimit), (new_klimit-klimit));
-			klimit = new_klimit;
-			memset( dprof_buffer, 0, size );
-                }
-        }
-
-	iSeries_setup_dprofile();
-
 	iSeries_proc_early_init();	
 	mf_init();
 	mf_initialized = 1;
@@ -631,7 +601,6 @@
 /*
  * Bolt the kernel addr space into the HPT
  */
-
 static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr)
 {
 	unsigned long pa;
@@ -644,12 +613,13 @@
 		unsigned long va = ( vsid << 28 ) | ( pa & 0xfffffff );
 		unsigned long vpn = va >> PAGE_SHIFT;
 		unsigned long slot = HvCallHpt_findValid( &hpte, vpn );
-		if ( hpte.dw0.dw0.v ) {
+		if (hpte.dw0.dw0.v) {
 			/* HPTE exists, so just bolt it */
-			HvCallHpt_setSwBits( slot, 0x10, 0 );
+			HvCallHpt_setSwBits(slot, 0x10, 0);
 		} else {
 			/* No HPTE exists, so create a new bolted one */
-			build_valid_hpte(vsid, ea, pa, NULL, mode_rw, 1);
+			make_pte(NULL, va, (unsigned long)__v2a(ea), 
+				 mode_rw, 0, 0);
 		}
 	}
 }
@@ -852,7 +822,6 @@
 	 */
 	tb_ticks_per_sec   = tb_ticks_per_jiffy * HZ;
 	tb_ticks_per_usec = cyclesPerUsec;
-	tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000);
 	div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres );
 	tb_to_xs = divres.result_low;
 	setup_default_decr();
@@ -884,17 +853,3 @@
 	}
 }
 
-static void iSeries_setup_dprofile(void)
-{
-	if ( dprof_buffer ) {
-		unsigned i;
-		for (i=0; i<MAX_PACAS; ++i) {
-			paca[i].prof_shift = dprof_shift;
-			paca[i].prof_len = dprof_len-1;
-			paca[i].prof_buffer = dprof_buffer;
-			paca[i].prof_stext = (unsigned *)&_stext;
-			mb();
-			paca[i].prof_enabled = 1;
-		}
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/ioctl32.c linux-2.4.20/arch/ppc64/kernel/ioctl32.c
--- linux-2.4.19/arch/ppc64/kernel/ioctl32.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/ioctl32.c	2002-10-29 11:18:48.000000000 +0000
@@ -44,6 +44,7 @@
 #include <linux/ppp_defs.h>
 #include <linux/if_ppp.h>
 #include <linux/if_pppox.h>
+#include <linux/if_tun.h>
 #include <linux/mtio.h>
 #include <linux/cdrom.h>
 #include <linux/loop.h>
@@ -102,6 +103,7 @@
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/nbd.h>
+#include <linux/random.h>
 #include <asm/ppc32.h>
 #include <asm/ppcdebug.h>
 
@@ -469,6 +471,7 @@
 		return -ENODEV;
 
 	strcpy(ifr32.ifr_name, dev->name);
+	dev_put(dev);
 
 	err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32));
 	return (err ? -EFAULT : 0);
@@ -753,6 +756,11 @@
 
 extern struct socket *sockfd_lookup(int fd, int *err);
 
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+	fput(sock->file);
+}
+
 static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	int ret;
@@ -801,6 +809,9 @@
 	ret = sys_ioctl (fd, cmd, (long) r);
 	set_fs (old_fs);
 
+	if (mysock)
+		sockfd_put(mysock);
+
 	return ret;
 }
 
@@ -1157,6 +1168,234 @@
 	return err;
 }
 
+typedef struct sg_io_hdr32 {
+	s32 interface_id;	/* [i] 'S' for SCSI generic (required) */
+	s32 dxfer_direction;	/* [i] data transfer direction  */
+	u8  cmd_len;		/* [i] SCSI command length ( <= 16 bytes) */
+	u8  mx_sb_len;		/* [i] max length to write to sbp */
+	u16 iovec_count;	/* [i] 0 implies no scatter gather */
+	u32 dxfer_len;		/* [i] byte count of data transfer */
+	u32 dxferp;		/* [i], [*io] points to data transfer memory
+					      or scatter gather list */
+	u32 cmdp;		/* [i], [*i] points to command to perform */
+	u32 sbp;		/* [i], [*o] points to sense_buffer memory */
+	u32 timeout;		/* [i] MAX_UINT->no timeout (unit: millisec) */
+	u32 flags;		/* [i] 0 -> default, see SG_FLAG... */
+	s32 pack_id;		/* [i->o] unused internally (normally) */
+	u32 usr_ptr;		/* [i->o] unused internally */
+	u8  status;		/* [o] scsi status */
+	u8  masked_status;	/* [o] shifted, masked scsi status */
+	u8  msg_status;		/* [o] messaging level data (optional) */
+	u8  sb_len_wr;		/* [o] byte count actually written to sbp */
+	u16 host_status;	/* [o] errors from host adapter */
+	u16 driver_status;	/* [o] errors from software driver */
+	s32 resid;		/* [o] dxfer_len - actual_transferred */
+	u32 duration;		/* [o] time taken by cmd (unit: millisec) */
+	u32 info;		/* [o] auxiliary information */
+} sg_io_hdr32_t;  /* 64 bytes long (on sparc32) */
+
+typedef struct sg_iovec32 {
+	u32 iov_base;
+	u32 iov_len;
+} sg_iovec32_t;
+
+static int alloc_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
+{
+	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
+	sg_iovec_t *kiov;
+	int i;
+
+	sgp->dxferp = kmalloc(sgp->iovec_count *
+			      sizeof(sg_iovec_t), GFP_KERNEL);
+	if (!sgp->dxferp)
+		return -ENOMEM;
+	memset(sgp->dxferp, 0,
+	       sgp->iovec_count * sizeof(sg_iovec_t));
+
+	kiov = (sg_iovec_t *) sgp->dxferp;
+	for (i = 0; i < sgp->iovec_count; i++) {
+		u32 iov_base32;
+		if (__get_user(iov_base32, &uiov->iov_base) ||
+		    __get_user(kiov->iov_len, &uiov->iov_len))
+			return -EFAULT;
+
+		kiov->iov_base = kmalloc(kiov->iov_len, GFP_KERNEL);
+		if (!kiov->iov_base)
+			return -ENOMEM;
+		if (copy_from_user(kiov->iov_base,
+				   (void *) A(iov_base32),
+				   kiov->iov_len))
+			return -EFAULT;
+
+		uiov++;
+		kiov++;
+	}
+
+	return 0;
+}
+
+static int copy_back_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
+{
+	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
+	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
+	int i;
+
+	for (i = 0; i < sgp->iovec_count; i++) {
+		u32 iov_base32;
+
+		if (__get_user(iov_base32, &uiov->iov_base))
+			return -EFAULT;
+
+		if (copy_to_user((void *) A(iov_base32),
+				 kiov->iov_base,
+				 kiov->iov_len))
+			return -EFAULT;
+
+		uiov++;
+		kiov++;
+	}
+
+	return 0;
+}
+
+static void free_sg_iovec(sg_io_hdr_t *sgp)
+{
+	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
+	int i;
+
+	for (i = 0; i < sgp->iovec_count; i++) {
+		if (kiov->iov_base) {
+			kfree(kiov->iov_base);
+			kiov->iov_base = NULL;
+		}
+		kiov++;
+	}
+	kfree(sgp->dxferp);
+	sgp->dxferp = NULL;
+}
+
+static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	sg_io_hdr32_t *sg_io32;
+	sg_io_hdr_t sg_io64;
+	u32 dxferp32, cmdp32, sbp32;
+	mm_segment_t old_fs;
+	int err = 0;
+
+	sg_io32 = (sg_io_hdr32_t *)arg;
+	err = __get_user(sg_io64.interface_id, &sg_io32->interface_id);
+	err |= __get_user(sg_io64.dxfer_direction, &sg_io32->dxfer_direction);
+	err |= __get_user(sg_io64.cmd_len, &sg_io32->cmd_len);
+	err |= __get_user(sg_io64.mx_sb_len, &sg_io32->mx_sb_len);
+	err |= __get_user(sg_io64.iovec_count, &sg_io32->iovec_count);
+	err |= __get_user(sg_io64.dxfer_len, &sg_io32->dxfer_len);
+	err |= __get_user(sg_io64.timeout, &sg_io32->timeout);
+	err |= __get_user(sg_io64.flags, &sg_io32->flags);
+	err |= __get_user(sg_io64.pack_id, &sg_io32->pack_id);
+
+	sg_io64.dxferp = NULL;
+	sg_io64.cmdp = NULL;
+	sg_io64.sbp = NULL;
+
+	err |= __get_user(cmdp32, &sg_io32->cmdp);
+	sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL);
+	if (!sg_io64.cmdp) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (copy_from_user(sg_io64.cmdp,
+			   (void *) A(cmdp32),
+			   sg_io64.cmd_len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	err |= __get_user(sbp32, &sg_io32->sbp);
+	sg_io64.sbp = kmalloc(sg_io64.mx_sb_len, GFP_KERNEL);
+	if (!sg_io64.sbp) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (copy_from_user(sg_io64.sbp,
+			   (void *) A(sbp32),
+			   sg_io64.mx_sb_len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	err |= __get_user(dxferp32, &sg_io32->dxferp);
+	if (sg_io64.iovec_count) {
+		int ret;
+
+		if ((ret = alloc_sg_iovec(&sg_io64, dxferp32))) {
+			err = ret;
+			goto out;
+		}
+	} else {
+		sg_io64.dxferp = kmalloc(sg_io64.dxfer_len, GFP_KERNEL);
+		if (!sg_io64.dxferp) {
+			err = -ENOMEM;
+			goto out;
+		}
+		if (copy_from_user(sg_io64.dxferp,
+				   (void *) A(dxferp32),
+				   sg_io64.dxfer_len)) {
+			err = -EFAULT;
+			goto out;
+		}
+	}
+
+	/* Unused internally, do not even bother to copy it over. */
+	sg_io64.usr_ptr = NULL;
+
+	if (err)
+		return -EFAULT;
+
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long) &sg_io64);
+	set_fs (old_fs);
+
+	if (err < 0)
+		goto out;
+
+	err = __put_user(sg_io64.pack_id, &sg_io32->pack_id);
+	err |= __put_user(sg_io64.status, &sg_io32->status);
+	err |= __put_user(sg_io64.masked_status, &sg_io32->masked_status);
+	err |= __put_user(sg_io64.msg_status, &sg_io32->msg_status);
+	err |= __put_user(sg_io64.sb_len_wr, &sg_io32->sb_len_wr);
+	err |= __put_user(sg_io64.host_status, &sg_io32->host_status);
+	err |= __put_user(sg_io64.driver_status, &sg_io32->driver_status);
+	err |= __put_user(sg_io64.resid, &sg_io32->resid);
+	err |= __put_user(sg_io64.duration, &sg_io32->duration);
+	err |= __put_user(sg_io64.info, &sg_io32->info);
+	err |= copy_to_user((void *)A(sbp32), sg_io64.sbp, sg_io64.mx_sb_len);
+	if (sg_io64.dxferp) {
+		if (sg_io64.iovec_count)
+			err |= copy_back_sg_iovec(&sg_io64, dxferp32);
+		else
+			err |= copy_to_user((void *)A(dxferp32),
+					    sg_io64.dxferp,
+					    sg_io64.dxfer_len);
+	}
+	if (err)
+		err = -EFAULT;
+
+out:
+	if (sg_io64.cmdp)
+		kfree(sg_io64.cmdp);
+	if (sg_io64.sbp)
+		kfree(sg_io64.sbp);
+	if (sg_io64.dxferp) {
+		if (sg_io64.iovec_count) {
+			free_sg_iovec(&sg_io64);
+		} else {
+			kfree(sg_io64.dxferp);
+		}
+	}
+	return err;
+}
+
 struct ppp_option_data32 {
 	__kernel_caddr_t32	ptr;
 	__u32			length;
@@ -2161,12 +2400,11 @@
 		if (l->lv_block_exception) {
 			lbe32 = (lv_block_exception32_t *)A(ptr2);
 			memset(lbe, 0, size);
-                       for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
-                               err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
-                               err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
-                               err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
-                               err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
-
+			for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
+				err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
+				err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
+				err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
+				err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
 			}
 		}
 	}
@@ -2222,16 +2460,17 @@
 	switch (cmd) {
 	case VG_STATUS:
 		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
-		if (!v) return -ENOMEM;
+		if (!v)
+			return -ENOMEM;
 		karg = v;
 		break;
 
 	case VG_CREATE_OLD:
 	case VG_CREATE:
 		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
-		if (!v) return -ENOMEM;
-		if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc) ||
-		    __get_user(v->proc, &((vg32_t *)arg)->proc)) {
+		if (!v)
+			return -ENOMEM;
+		if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc)) {
 			kfree(v);
 			return -EFAULT;
 		}
@@ -2248,39 +2487,46 @@
 			return -EPERM;
 		for (i = 0; i < v->pv_max; i++) {
 			err = __get_user(ptr, &((vg32_t *)arg)->pv[i]);
-			if (err) break;
+			if (err)
+				break;
 			if (ptr) {
 				v->pv[i] = kmalloc(sizeof(pv_t), GFP_KERNEL);
 				if (!v->pv[i]) {
 					err = -ENOMEM;
 					break;
 				}
-				err = copy_from_user(v->pv[i], (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1);
+				err = copy_from_user(v->pv[i], (void *)A(ptr),
+						     sizeof(pv32_t) - 8 - UUID_LEN+1);
 				if (err) {
 					err = -EFAULT;
 					break;
 				}
-				err = copy_from_user(v->pv[i]->pv_uuid, ((pv32_t *)A(ptr))->pv_uuid, UUID_LEN+1);
+				err = copy_from_user(v->pv[i]->pv_uuid,
+						     ((pv32_t *)A(ptr))->pv_uuid,
+						     UUID_LEN+1);
 				if (err) {
 				        err = -EFAULT;
 					break;
 				}
 
-				
-				v->pv[i]->pe = NULL; v->pv[i]->inode = NULL;
+				v->pv[i]->pe = NULL;
+				v->pv[i]->bd = NULL;
 			}
 		}
 		if (!err) {
 			for (i = 0; i < v->lv_max; i++) {
 				err = __get_user(ptr, &((vg32_t *)arg)->lv[i]);
-				if (err) break;
+				if (err)
+					break;
 				if (ptr) {
 					v->lv[i] = get_lv_t(ptr, &err);
-					if (err) break;
+					if (err)
+						break;
 				}
 			}
 		}
 		break;
+
 	case LV_CREATE:
 	case LV_EXTEND:
 	case LV_REDUCE:
@@ -2288,54 +2534,70 @@
 	case LV_RENAME:
 	case LV_STATUS_BYNAME:
 	        err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name));
-		if (err) return -EFAULT;
+		if (err)
+			return -EFAULT;
 		if (cmd != LV_REMOVE) {
 			err = __get_user(ptr, &((lv_req32_t *)arg)->lv);
-			if (err) return err;
+			if (err)
+				return err;
 			u.lv_req.lv = get_lv_t(ptr, &err);
 		} else
 			u.lv_req.lv = NULL;
 		break;
 
-
 	case LV_STATUS_BYINDEX:
-		err = get_user(u.lv_byindex.lv_index, &((lv_status_byindex_req32_t *)arg)->lv_index);
+		err = get_user(u.lv_byindex.lv_index,
+			       &((lv_status_byindex_req32_t *)arg)->lv_index);
 		err |= __get_user(ptr, &((lv_status_byindex_req32_t *)arg)->lv);
-		if (err) return err;
+		if (err)
+			return err;
 		u.lv_byindex.lv = get_lv_t(ptr, &err);
 		break;
+
 	case LV_STATUS_BYDEV:
 	        err = get_user(u.lv_bydev.dev, &((lv_status_bydev_req32_t *)arg)->dev);
+		err |= __get_user(ptr, &((lv_status_bydev_req32_t *)arg)->lv);
+		if (err)
+			return err;
 		u.lv_bydev.lv = get_lv_t(ptr, &err);
-		if (err) return err;
-		u.lv_bydev.lv = &p;
-		p.pe = NULL; p.inode = NULL;		
-		break;		
+		break;
+
 	case VG_EXTEND:
 		err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8 - UUID_LEN+1);
-		if (err) return -EFAULT;
+		if (err)
+			return -EFAULT;
 		err = copy_from_user(p.pv_uuid, ((pv32_t *)arg)->pv_uuid, UUID_LEN+1);
-		if (err) return -EFAULT;
-		p.pe = NULL; p.inode = NULL;
+		if (err)
+			return -EFAULT;
+		p.pe = NULL;
+		p.bd = NULL;
 		karg = &p;
 		break;
+
 	case PV_CHANGE:
 	case PV_STATUS:
 		err = copy_from_user(&u.pv_status, arg, sizeof(u.lv_req.lv_name));
-		if (err) return -EFAULT;
+		if (err)
+			return -EFAULT;
 		err = __get_user(ptr, &((pv_status_req32_t *)arg)->pv);
-		if (err) return err;
+		if (err)
+			return err;
 		u.pv_status.pv = &p;
 		if (cmd == PV_CHANGE) {
-			err = copy_from_user(&p, (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1);
-			if (err) return -EFAULT;
-			p.pe = NULL; p.inode = NULL;
+			err = copy_from_user(&p, (void *)A(ptr),
+					     sizeof(pv32_t) - 8 - UUID_LEN+1);
+			if (err)
+				return -EFAULT;
+			p.pe = NULL;
+			p.bd = NULL;
 		}
 		break;
-	}
+	};
+
         old_fs = get_fs(); set_fs (KERNEL_DS);
         err = sys_ioctl (fd, cmd, (unsigned long)karg);
         set_fs (old_fs);
+
 	switch (cmd) {
 	case VG_STATUS:
 		if (!err) {
@@ -2361,17 +2623,23 @@
 		}
 		kfree(v);
 		break;
+
 	case LV_STATUS_BYNAME:
-		if (!err && u.lv_req.lv) err = copy_lv_t(ptr, u.lv_req.lv);
+		if (!err && u.lv_req.lv)
+			err = copy_lv_t(ptr, u.lv_req.lv);
 		/* Fall through */
+
         case LV_CREATE:
 	case LV_EXTEND:
 	case LV_REDUCE:
-		if (u.lv_req.lv) put_lv_t(u.lv_req.lv);
+		if (u.lv_req.lv)
+			put_lv_t(u.lv_req.lv);
 		break;
+
 	case LV_STATUS_BYINDEX:
 		if (u.lv_byindex.lv) {
-			if (!err) err = copy_lv_t(ptr, u.lv_byindex.lv);
+			if (!err)
+				err = copy_lv_t(ptr, u.lv_byindex.lv);
 			put_lv_t(u.lv_byindex.lv);
 		}
 		break;
@@ -2387,9 +2655,11 @@
 	case PV_STATUS:
 		if (!err) {
 			err = copy_to_user((void *)A(ptr), &p, sizeof(pv32_t) - 8 - UUID_LEN+1);
-			if (err) return -EFAULT;
+			if (err)
+				return -EFAULT;
 			err = copy_to_user(((pv_t *)A(ptr))->pv_uuid, p.pv_uuid, UUID_LEN + 1);
-			if (err) return -EFAULT;
+			if (err)
+				return -EFAULT;
 		}
 		break;
 	};
@@ -2977,6 +3247,7 @@
 		set_fs (KERNEL_DS);
 		err = sys_ioctl(fd, cmd, (unsigned long)&a);
 		set_fs (old_fs);
+		break;
 	default:
 		return -EINVAL;
 	}                                        
@@ -3435,119 +3706,6 @@
 	return ((0 == ret) ? 0 : -EFAULT);
 }	
 
-struct sg_io_hdr_32
-{
-	int interface_id;
-	int dxfer_direction;
-	unsigned char cmd_len;
-	unsigned char mx_sb_len;
-	unsigned short iovec_count;
-	unsigned int dxfer_len;
-	u32 dxferp;
-	u32 cmdp;
-	u32 sbp;
-	unsigned int timeout;
-	unsigned int flags;
-	int pack_id;
-	u32 usr_ptr;
-	unsigned char status;
-	unsigned char masked_status;
-	unsigned char msg_status;
-	unsigned char sb_len_wr;
-	unsigned short host_status;
-	unsigned short driver_status;
-	int resid;
-	unsigned int duration;
-	unsigned int info;
-};
-
-static int do_sg_io(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct sg_io_hdr *sg = kmalloc(sizeof(struct sg_io_hdr), GFP_KERNEL);
-	struct sg_io_hdr_32 *sg_32 = (struct sg_io_hdr_32 *)arg;
-	u32 dxferp_32;
-	u32 cmdp_32;
-	u32 sbp_32;
-	u32 usr_ptr_32;
-	int ret = -EFAULT;
-	int err;
-	mm_segment_t old_fs = get_fs();
-
-	if (!sg)
-		return -ENOMEM;
-
-	memset(sg, 0, sizeof(*sg));
-
-	err = copy_from_user(sg, sg_32, offsetof(struct sg_io_hdr, dxferp));
-	err |= __get_user(dxferp_32, &sg_32->dxferp);
-	err |= __get_user(cmdp_32, &sg_32->cmdp);
-	err |= __get_user(sbp_32, &sg_32->sbp);
-
-	if (err)
-		goto error;
-
-	sg->dxferp = (void *)A(dxferp_32);
-	sg->cmdp = (void *)A(cmdp_32);
-	sg->sbp = (void *)A(sbp_32);
-
-	err = __copy_from_user(&sg->timeout, &sg_32->timeout,
-			       (long)&sg->usr_ptr - (long)&sg->timeout);
-
-	err |= __get_user(usr_ptr_32, &sg_32->usr_ptr);
-
-	if (err)
-		goto error;
-
-	sg->usr_ptr = (void *)A(usr_ptr_32);
-
-	err = __copy_from_user(&sg->status, &sg_32->status,
-			       sizeof(struct sg_io_hdr) -
-			       offsetof(struct sg_io_hdr, status));
-
-	if (err)
-		goto error;
-
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, cmd, (unsigned long)sg);
-	set_fs(old_fs);
-
-	err = copy_to_user(sg_32, sg, offsetof(struct sg_io_hdr, dxferp));
-
-	dxferp_32 = (unsigned long)sg->dxferp;
-	cmdp_32 = (unsigned long)sg->cmdp;
-	sbp_32 = (unsigned long)sg->sbp;
-	err |= __put_user(dxferp_32, &sg_32->dxferp);
-	err |= __put_user(cmdp_32, &sg_32->cmdp);
-	err |= __put_user(sbp_32, &sg_32->sbp);
-
-	if (err) {
-		ret = -EFAULT;
-		goto error;
-	}
-
-	err = __copy_to_user(&sg_32->timeout, &sg->timeout,
-			     (long)&sg->usr_ptr - (long)&sg->timeout);
-
-	usr_ptr_32 = (unsigned long)sg->usr_ptr;
-	err |= __put_user(usr_ptr_32, &sg_32->usr_ptr);
-
-	if (err) {
-		ret = -EFAULT;
-		goto error;
-	}
-
-	err = __copy_to_user(&sg_32->status, &sg->status,
-			      sizeof(struct sg_io_hdr) -
-			      offsetof(struct sg_io_hdr, status));
-
-	if (err)
-		ret = -EFAULT;
-
-error:
-	kfree(sg);
-	return ret;
-}
-
 struct ioctl_trans {
 	unsigned long cmd;
 	unsigned long handler;
@@ -3736,6 +3894,12 @@
 COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE),
 COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER),
 COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND),
+/* Big T */
+COMPATIBLE_IOCTL(TUNSETNOCSUM),
+COMPATIBLE_IOCTL(TUNSETDEBUG),
+COMPATIBLE_IOCTL(TUNSETIFF),
+COMPATIBLE_IOCTL(TUNSETPERSIST),
+COMPATIBLE_IOCTL(TUNSETOWNER),
 /* Big V */
 COMPATIBLE_IOCTL(VT_SETMODE),
 COMPATIBLE_IOCTL(VT_GETMODE),
@@ -3812,6 +3976,8 @@
 COMPATIBLE_IOCTL(SIOCDRARP),
 COMPATIBLE_IOCTL(SIOCADDDLCI),
 COMPATIBLE_IOCTL(SIOCDELDLCI),
+COMPATIBLE_IOCTL(SIOCGIFVLAN),
+COMPATIBLE_IOCTL(SIOCSIFVLAN),
 /* SG stuff */
 COMPATIBLE_IOCTL(SG_SET_TIMEOUT),
 COMPATIBLE_IOCTL(SG_GET_TIMEOUT),
@@ -4145,10 +4311,19 @@
 COMPATIBLE_IOCTL(WDIOC_GETTEMP),
 COMPATIBLE_IOCTL(WDIOC_SETOPTIONS),
 COMPATIBLE_IOCTL(WDIOC_KEEPALIVE),
+/* Big R */
+COMPATIBLE_IOCTL(RNDGETENTCNT),
+COMPATIBLE_IOCTL(RNDADDTOENTCNT),
+COMPATIBLE_IOCTL(RNDGETPOOL),
+COMPATIBLE_IOCTL(RNDADDENTROPY),
+COMPATIBLE_IOCTL(RNDZAPENTCNT),
+COMPATIBLE_IOCTL(RNDCLEARPOOL),
 /* Bluetooth ioctls */
 COMPATIBLE_IOCTL(HCIDEVUP),
 COMPATIBLE_IOCTL(HCIDEVDOWN),
 COMPATIBLE_IOCTL(HCIDEVRESET),
+COMPATIBLE_IOCTL(HCIDEVRESTAT),
+COMPATIBLE_IOCTL(HCIGETDEVINFO),
 COMPATIBLE_IOCTL(HCIGETDEVLIST),
 COMPATIBLE_IOCTL(HCISETRAW),
 COMPATIBLE_IOCTL(HCISETSCAN),
@@ -4264,6 +4439,7 @@
 HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans),
 HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans),
 HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans),
+HANDLE_IOCTL(SG_IO,sg_ioctl_trans),
 HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans),
 HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans),
 HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans),
@@ -4358,7 +4534,6 @@
 HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb),
 HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb),
 HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal),
-HANDLE_IOCTL(SG_IO, do_sg_io),
 };
 
 unsigned long ioctl32_hash_table[1024];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/irq.c linux-2.4.20/arch/ppc64/kernel/irq.c
--- linux-2.4.19/arch/ppc64/kernel/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/irq.c	2002-10-29 11:18:49.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * 
- *
  *  arch/ppc/kernel/irq.c
  *
  *  Derived from arch/i386/kernel/irq.c
@@ -25,7 +23,6 @@
  * should be easier.
  */
 
-
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/threads.h>
@@ -42,6 +39,7 @@
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/random.h>
 
 #include <asm/uaccess.h>
@@ -56,6 +54,7 @@
 #include <asm/iSeries/LparData.h>
 #include <asm/machdep.h>
 #include <asm/paca.h>
+#include <asm/perfmon.h>
 
 #include "local_irq.h"
 
@@ -99,7 +98,7 @@
  * this needs to be removed.
  * -- Cort
  */
-#define IRQ_KMALLOC_ENTRIES 8
+#define IRQ_KMALLOC_ENTRIES 16
 static int cache_bitmask = 0;
 static struct irqaction malloc_cache[IRQ_KMALLOC_ENTRIES];
 extern int mem_init_done;
@@ -554,58 +553,61 @@
 	spin_unlock(&desc->lock);
 }
 
-int do_IRQ(struct pt_regs *regs, int isfake)
+int do_IRQ(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
-	int irq;
+	int irq, first = 1;
+#ifdef CONFIG_PPC_ISERIES
 	struct paca_struct *lpaca;
-	struct ItLpQueue * lpq;
-
-	/* if(cpu) udbg_printf("Entering do_IRQ\n");  */
-
-        irq_enter(cpu);
+	struct ItLpQueue *lpq;
+#endif
 
-	if (naca->platform != PLATFORM_ISERIES_LPAR) {
-	
-		/* every arch is required to have a get_irq -- Cort */
-		irq = ppc_md.get_irq( regs );
+	irq_enter(cpu);
 
-		if ( irq >= 0 ) {
-			ppc_irq_dispatch_handler( regs, irq );
-			if (ppc_md.post_irq)
-				ppc_md.post_irq( regs, irq );
-		} else {
-			/* -2 means ignore, already handled */
-			if (irq != -2) {
-				printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
-					irq, regs->nip);
-				ppc_spurious_interrupts++;
-			}
-		}
-	}
-	/* if on iSeries partition */
-	else {
-		lpaca = get_paca();
+#ifdef CONFIG_PPC_ISERIES
+	lpaca = get_paca();
 #ifdef CONFIG_SMP
-		if ( lpaca->xLpPaca.xIntDword.xFields.xIpiCnt ) {
-			lpaca->xLpPaca.xIntDword.xFields.xIpiCnt = 0;
-			iSeries_smp_message_recv( regs );
-		}
-#endif /* CONFIG_SMP */
-		lpq = lpaca->lpQueuePtr;
-		if ( lpq && ItLpQueue_isLpIntPending( lpq ) )
-			lpEvent_count += ItLpQueue_process( lpq, regs );
+	if (lpaca->xLpPaca.xIntDword.xFields.xIpiCnt) {
+		lpaca->xLpPaca.xIntDword.xFields.xIpiCnt = 0;
+		iSeries_smp_message_recv(regs);
 	}
-		
+#endif /* CONFIG_SMP */
+	lpq = lpaca->lpQueuePtr;
+	if (lpq && ItLpQueue_isLpIntPending(lpq))
+		lpEvent_count += ItLpQueue_process(lpq, regs);
+#else
+	/*
+	 * Every arch is required to implement ppc_md.get_irq.
+	 * This function will either return an irq number or -1 to
+	 * indicate there are no more pending.  But the first time
+	 * through the loop this means there wasn't an IRQ pending.
+	 * The value -2 is for buggy hardware and means that this IRQ
+	 * has already been handled. -- Tom
+	 */
+	while ((irq = ppc_md.get_irq(regs)) >= 0) {
+		ppc_irq_dispatch_handler(regs, irq);
+		first = 0;
+	}
+	if (irq != -2 && first)
+		/* That's not SMP safe ... but who cares ? */
+		ppc_spurious_interrupts++;
+#endif
+
         irq_exit(cpu);
 
-	if (naca->platform == PLATFORM_ISERIES_LPAR) {
-		if ( lpaca->xLpPaca.xIntDword.xFields.xDecrInt ) {
-			lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
-			/* Signal a fake decrementer interrupt */
-			timer_interrupt( regs );
-		}
+#ifdef CONFIG_PPC_ISERIES
+	if (lpaca->xLpPaca.xIntDword.xFields.xDecrInt) {
+		lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
+		/* Signal a fake decrementer interrupt */
+		timer_interrupt(regs);
+	}
+
+	if (lpaca->xLpPaca.xIntDword.xFields.xPdcInt) {
+		lpaca->xLpPaca.xIntDword.xFields.xPdcInt = 0;
+		/* Signal a fake PMC interrupt */
+		PerformanceMonitorException();
 	}
+#endif
 
 	if (softirq_pending(cpu))
 		do_softirq();
@@ -902,9 +904,11 @@
 		unsigned i;
 		for (i=0; i<MAX_PACAS; ++i) {
 			if ( paca[i].prof_buffer && (new_value & 1) )
-				paca[i].prof_enabled = 1;
-			else
-				paca[i].prof_enabled = 0;
+				paca[i].prof_mode = PMC_STATE_DECR_PROFILE;
+			else {
+				if(paca[i].prof_mode != PMC_STATE_INITIAL) 
+					paca[i].prof_mode = PMC_STATE_READY;
+			}
 			new_value >>= 1;
 		}
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/lmb.c linux-2.4.20/arch/ppc64/kernel/lmb.c
--- linux-2.4.19/arch/ppc64/kernel/lmb.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/lmb.c	2002-10-29 11:18:50.000000000 +0000
@@ -12,6 +12,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/kernel.h>
 #include <asm/types.h>
 #include <asm/page.h>
 #include <asm/prom.h>
@@ -27,7 +28,7 @@
 static long lmb_add_region(struct lmb_region *, unsigned long, unsigned long, unsigned long);
 
 struct lmb lmb = {
-	0,
+	0, 0,
 	{0,0,0,0,{{0,0,0}}},
 	{0,0,0,0,{{0,0,0}}}
 };
@@ -135,6 +136,10 @@
 	struct lmb *_lmb = PTRRELOC(&lmb);
 	struct lmb_region *_rgn = &(_lmb->memory);
 
+	/* On pSeries LPAR systems, the first LMB is our RMO region. */
+	if ( base == 0 )
+		_lmb->rmo_size = size;
+
 	return lmb_add_region(_rgn, base, size, LMB_MEMORY_AREA);
 
 }
@@ -242,12 +247,17 @@
 	return (i < rgn->cnt) ? i : -1;
 }
 
-
 unsigned long
 lmb_alloc(unsigned long size, unsigned long align)
 {
+	return lmb_alloc_base(size, align, LMB_ALLOC_ANYWHERE);
+}
+
+unsigned long
+lmb_alloc_base(unsigned long size, unsigned long align, unsigned long max_addr)
+{
 	long i, j;
-	unsigned long base;
+	unsigned long base = 0;
 	unsigned long offset = reloc_offset();
 	struct lmb *_lmb = PTRRELOC(&lmb);
 	struct lmb_region *_mem = &(_lmb->memory);
@@ -261,7 +271,12 @@
 		if ( lmbtype != LMB_MEMORY_AREA )
 			continue;
 
-		base = _ALIGN_DOWN(lmbbase+lmbsize-size, align);
+		if ( max_addr == LMB_ALLOC_ANYWHERE )
+			base = _ALIGN_DOWN(lmbbase+lmbsize-size, align);
+		else if ( lmbbase < max_addr )
+			base = _ALIGN_DOWN(min(lmbbase+lmbsize,max_addr)-size, align);
+		else
+			continue;
 
 		while ( (lmbbase <= base) &&
 			((j = lmb_overlaps_region(_rsv,base,size)) >= 0) ) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/mf.c linux-2.4.20/arch/ppc64/kernel/mf.c
--- linux-2.4.19/arch/ppc64/kernel/mf.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/mf.c	2002-10-29 11:18:30.000000000 +0000
@@ -410,7 +410,7 @@
 		mf_powerOff();
 	}
 	else
-		printk( KERN_ALERT "mf.c: init has been successfully notified to proceed with shutdown\n" );
+		printk( KERN_INFO "mf.c: init has been successfully notified to proceed with shutdown\n" );
 
 	return rc;
 }
@@ -436,7 +436,7 @@
 		case 0x5B:	/* power control notification */
 			if ( (event->xUnion.xCEMsgData.xCEMsg[5]&0x20) != 0 )
 			{
-				printk( KERN_ALERT "mf.c: Commencing partition shutdown\n" );
+				printk( KERN_INFO "mf.c: Commencing partition shutdown\n" );
 				if ( shutdown() == 0 )
 					signalCEMsg( "\x00\x00\x00\xDB\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
 			}
@@ -479,7 +479,7 @@
 			signalEvent( NULL );
 		break;
 	case 1:	/* IT sys shutdown */
-		printk( KERN_ALERT "mf.c: Commencing system shutdown\n" );
+		printk( KERN_INFO "mf.c: Commencing system shutdown\n" );
 		shutdown();
 		break;
 	}
@@ -666,7 +666,7 @@
  */
 void mf_powerOff( void )
 {
-	printk( KERN_ALERT "mf.c: Down it goes...\n" );
+	printk( KERN_INFO "mf.c: Down it goes...\n" );
 	signalCEMsg( "\x00\x00\x00\x4D\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
 	for (;;);
 }
@@ -677,7 +677,7 @@
  */
 void mf_reboot( void )
 {
-	printk( KERN_ALERT "mf.c: Preparing to bounce...\n" );
+	printk( KERN_INFO "mf.c: Preparing to bounce...\n" );
 	signalCEMsg( "\x00\x00\x00\x4E\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
 	for (;;);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/misc.S linux-2.4.20/arch/ppc64/kernel/misc.S
--- linux-2.4.19/arch/ppc64/kernel/misc.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/misc.S	2002-10-29 11:18:36.000000000 +0000
@@ -745,7 +745,8 @@
 	.llong .sys_fremovexattr	/* 220 */
 	.llong .sys_futex
 #endif
-	.rept NR_syscalls-221
+	.llong .sys_perfmonctl   /* Put this here for now ... */
+	.rept NR_syscalls-222
 		.llong .sys_ni_syscall
 	.endr
 #endif
@@ -975,6 +976,7 @@
 	.llong .sys_fremovexattr	/* 220 */
 	.llong .sys_futex
 #endif
-	.rept NR_syscalls-221
+	.llong .sys_perfmonctl   /* Put this here for now ... */
+	.rept NR_syscalls-222
 	.llong .sys_ni_syscall
 	.endr
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/mk_defs.c linux-2.4.20/arch/ppc64/kernel/mk_defs.c
--- linux-2.4.19/arch/ppc64/kernel/mk_defs.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/mk_defs.c	2002-10-29 11:18:51.000000000 +0000
@@ -79,11 +79,33 @@
 	DEFINE(PACAPROCENABLED, offsetof(struct paca_struct, xProcEnabled));
 	DEFINE(PACAHRDWINTCOUNT, offsetof(struct paca_struct, xHrdIntCount));
 	DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr));
-	DEFINE(PACAPROFENABLED, offsetof(struct paca_struct, prof_enabled));
+
+	DEFINE(PACAPROFMODE, offsetof(struct paca_struct, prof_mode));
 	DEFINE(PACAPROFLEN, offsetof(struct paca_struct, prof_len));
 	DEFINE(PACAPROFSHIFT, offsetof(struct paca_struct, prof_shift));
 	DEFINE(PACAPROFBUFFER, offsetof(struct paca_struct, prof_buffer));
 	DEFINE(PACAPROFSTEXT, offsetof(struct paca_struct, prof_stext));
+	DEFINE(PACAPROFETEXT, offsetof(struct paca_struct, prof_etext));
+	DEFINE(PACAPMC1, offsetof(struct paca_struct, pmc[0]));
+	DEFINE(PACAPMC2, offsetof(struct paca_struct, pmc[1]));
+	DEFINE(PACAPMC3, offsetof(struct paca_struct, pmc[2]));
+	DEFINE(PACAPMC4, offsetof(struct paca_struct, pmc[3]));
+	DEFINE(PACAPMC5, offsetof(struct paca_struct, pmc[4]));
+	DEFINE(PACAPMC6, offsetof(struct paca_struct, pmc[5]));
+	DEFINE(PACAPMC7, offsetof(struct paca_struct, pmc[6]));
+	DEFINE(PACAPMC8, offsetof(struct paca_struct, pmc[7]));
+	DEFINE(PACAMMCR0, offsetof(struct paca_struct, pmc[8]));
+	DEFINE(PACAMMCR1, offsetof(struct paca_struct, pmc[9]));
+	DEFINE(PACAMMCRA, offsetof(struct paca_struct, pmc[10]));
+	DEFINE(PACAPMCC1, offsetof(struct paca_struct, pmcc[0]));
+	DEFINE(PACAPMCC2, offsetof(struct paca_struct, pmcc[1]));
+	DEFINE(PACAPMCC3, offsetof(struct paca_struct, pmcc[2]));
+	DEFINE(PACAPMCC4, offsetof(struct paca_struct, pmcc[3]));
+	DEFINE(PACAPMCC5, offsetof(struct paca_struct, pmcc[4]));
+	DEFINE(PACAPMCC6, offsetof(struct paca_struct, pmcc[5]));
+	DEFINE(PACAPMCC7, offsetof(struct paca_struct, pmcc[6]));
+	DEFINE(PACAPMCC8, offsetof(struct paca_struct, pmcc[7]));
+
 	DEFINE(PACALPPACA, offsetof(struct paca_struct, xLpPaca));
         DEFINE(LPPACA, offsetof(struct paca_struct, xLpPaca));
         DEFINE(PACAREGSAV, offsetof(struct paca_struct, xRegSav));
@@ -93,6 +115,7 @@
         DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
 	DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt));
 	DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xIntDword.xFields.xDecrInt));
+	DEFINE(LPPACAPDCINT, offsetof(struct ItLpPaca, xIntDword.xFields.xPdcInt));
         DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr));
         DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending));
         DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/open_pic.c linux-2.4.20/arch/ppc64/kernel/open_pic.c
--- linux-2.4.19/arch/ppc64/kernel/open_pic.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/open_pic.c	2002-10-29 11:18:35.000000000 +0000
@@ -33,7 +33,6 @@
 static volatile struct OpenPIC *OpenPIC = NULL;
 u_int OpenPIC_NumInitSenses __initdata = 0;
 u_char *OpenPIC_InitSenses __initdata = NULL;
-extern int use_of_interrupt_tree;
 
 void find_ISUs(void);
 
@@ -47,7 +46,6 @@
 OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU];
 
 static void openpic_end_irq(unsigned int irq_nr);
-static void openpic_ack_irq(unsigned int irq_nr);
 static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask);
 
 struct hw_interrupt_type open_pic = {
@@ -56,14 +54,13 @@
 	NULL,
 	openpic_enable_irq,
 	openpic_disable_irq,
-	openpic_ack_irq,
+	NULL,
 	openpic_end_irq,
 	openpic_set_affinity
 };
 
 #ifdef CONFIG_SMP
 static void openpic_end_ipi(unsigned int irq_nr);
-static void openpic_ack_ipi(unsigned int irq_nr);
 static void openpic_enable_ipi(unsigned int irq_nr);
 static void openpic_disable_ipi(unsigned int irq_nr);
 
@@ -73,9 +70,9 @@
 	NULL,
 	openpic_enable_ipi,
 	openpic_disable_ipi,
-	openpic_ack_ipi,
+	NULL,
 	openpic_end_ipi,
-	0
+	NULL
 };
 #endif /* CONFIG_SMP */
 
@@ -293,7 +290,7 @@
 	}
 	OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr;
 
-	ppc_md.progress("openpic enter",0x122);
+	ppc64_boot_msg(0x20, "OpenPic Init");
 
 	t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
 	switch (t & OPENPIC_FEATURE_VERSION_MASK) {
@@ -330,7 +327,7 @@
 	find_ISUs();
 
 	/* Initialize timer interrupts */
-	ppc_md.progress("openpic timer",0x3ba);
+	ppc64_boot_msg(0x21, "OpenPic Timer");
 	for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
 		/* Disabled, Priority 0 */
 		openpic_inittimer(i, 0, openpic_vec_timer+i);
@@ -340,7 +337,7 @@
 
 #ifdef CONFIG_SMP
 	/* Initialize IPI interrupts */
-	ppc_md.progress("openpic ipi",0x3bb);
+	ppc64_boot_msg(0x22, "OpenPic IPI");
 	openpic_test_broken_IPI();
 	for (i = 0; i < OPENPIC_NUM_IPI; i++) {
 		/* Disabled, Priority 10..13 */
@@ -352,7 +349,7 @@
 #endif
 
 	/* Initialize external interrupts */
-	ppc_md.progress("openpic ext",0x3bc);
+	ppc64_boot_msg(0x23, "OpenPic Ext");
 
 	openpic_set_priority(0xf);
 
@@ -385,7 +382,7 @@
 		irq_desc[i].handler = &open_pic;
 
 	/* Initialize the spurious interrupt */
-	ppc_md.progress("openpic spurious",0x3bd);
+	ppc64_boot_msg(0x24, "OpenPic Spurious");
 	openpic_set_spurious(openpic_vec_spurious);
 
 	/* Initialize the cascade */
@@ -397,7 +394,7 @@
 	openpic_set_priority(0);
 	openpic_disable_8259_pass_through();
 
-	ppc_md.progress("openpic exit",0x222);
+	ppc64_boot_msg(0x25, "OpenPic Done");
 }
 
 void openpic_setup_ISU(int isu_num, unsigned long addr)
@@ -756,13 +753,6 @@
 				(sense ? OPENPIC_SENSE_LEVEL : 0));
 }
 
-/* No spinlocks, should not be necessary with the OpenPIC
- * (1 register = 1 interrupt and we have the desc lock).
- */
-static void openpic_ack_irq(unsigned int irq_nr)
-{
-}
-
 static void openpic_end_irq(unsigned int irq_nr)
 {
 	if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0)
@@ -775,10 +765,6 @@
 }
 
 #ifdef CONFIG_SMP
-static void openpic_ack_ipi(unsigned int irq_nr)
-{
-}
-
 static void openpic_end_ipi(unsigned int irq_nr)
 {
 	/* IPIs are marked IRQ_PER_CPU. This has the side effect of
@@ -825,4 +811,3 @@
 		irq = -1;
 	return irq;
 }
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/pSeries_lpar.c linux-2.4.20/arch/ppc64/kernel/pSeries_lpar.c
--- linux-2.4.19/arch/ppc64/kernel/pSeries_lpar.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/pSeries_lpar.c	2002-10-29 11:18:33.000000000 +0000
@@ -21,6 +21,7 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/fs.h>
 #include <asm/processor.h>
 #include <asm/semaphore.h>
 #include <asm/mmu.h>
@@ -33,128 +34,7 @@
 #include <asm/pci_dma.h>
 #include <linux/pci.h>
 #include <asm/naca.h>
-
-/* Status return values */
-#define H_Success	0
-#define H_Busy		1	/* Hardware busy -- retry later */
-#define H_Hardware	-1	/* Hardware error */
-#define H_Function	-2	/* Function not supported */
-#define H_Privilege	-3	/* Caller not privileged */
-#define H_Parameter	-4	/* Parameter invalid, out-of-range or conflicting */
-#define H_Bad_Mode	-5	/* Illegal msr value */
-#define H_PTEG_Full	-6	/* PTEG is full */
-#define H_Not_Found	-7	/* PTE was not found" */
-#define H_Reserved_DABR	-8	/* DABR address is reserved by the hypervisor on this processor" */
-
-/* Flags */
-#define H_LARGE_PAGE		(1UL<<(63-16))
-#define H_EXACT		    (1UL<<(63-24))	/* Use exact PTE or return H_PTEG_FULL */
-#define H_R_XLATE		(1UL<<(63-25))	/* include a valid logical page num in the pte if the valid bit is set */
-#define H_READ_4		(1UL<<(63-26))	/* Return 4 PTEs */
-#define H_AVPN			(1UL<<(63-32))	/* An avpn is provided as a sanity test */
-#define H_ICACHE_INVALIDATE	(1UL<<(63-40))	/* icbi, etc.  (ignored for IO pages) */
-#define H_ICACHE_SYNCHRONIZE	(1UL<<(63-41))	/* dcbst, icbi, etc (ignored for IO pages */
-#define H_ZERO_PAGE		(1UL<<(63-48))	/* zero the page before mapping (ignored for IO pages) */
-#define H_COPY_PAGE		(1UL<<(63-49))
-#define H_N			(1UL<<(63-61))
-#define H_PP1			(1UL<<(63-62))
-#define H_PP2			(1UL<<(63-63))
-
-
-
-/* pSeries hypervisor opcodes */
-#define H_REMOVE		0x04
-#define H_ENTER			0x08
-#define H_READ			0x0c
-#define H_CLEAR_MOD		0x10
-#define H_CLEAR_REF		0x14
-#define H_PROTECT		0x18
-#define H_GET_TCE		0x1c
-#define H_PUT_TCE		0x20
-#define H_SET_SPRG0		0x24
-#define H_SET_DABR		0x28
-#define H_PAGE_INIT		0x2c
-#define H_SET_ASR		0x30
-#define H_ASR_ON		0x34
-#define H_ASR_OFF		0x38
-#define H_LOGICAL_CI_LOAD	0x3c
-#define H_LOGICAL_CI_STORE	0x40
-#define H_LOGICAL_CACHE_LOAD	0x44
-#define H_LOGICAL_CACHE_STORE	0x48
-#define H_LOGICAL_ICBI		0x4c
-#define H_LOGICAL_DCBF		0x50
-#define H_GET_TERM_CHAR		0x54
-#define H_PUT_TERM_CHAR		0x58
-#define H_REAL_TO_LOGICAL	0x5c
-#define H_HYPERVISOR_DATA	0x60
-#define H_EOI			0x64
-#define H_CPPR			0x68
-#define H_IPI			0x6c
-#define H_IPOLL			0x70
-#define H_XIRR			0x74
-
-#define HSC			".long 0x44000022\n"
-#define H_ENTER_r3		"li	3, 0x08\n"
-
-/* plpar_hcall() -- Generic call interface using above opcodes
- *
- * The actual call interface is a hypervisor call instruction with
- * the opcode in R3 and input args in R4-R7.
- * Status is returned in R3 with variable output values in R4-R11.
- * Only H_PTE_READ with H_READ_4 uses R6-R11 so we ignore it for now
- * and return only two out args which MUST ALWAYS BE PROVIDED.
- */
-long plpar_hcall(unsigned long opcode,
-		 unsigned long arg1,
-		 unsigned long arg2,
-		 unsigned long arg3,
-		 unsigned long arg4,
-		 unsigned long *out1,
-		 unsigned long *out2,
-		 unsigned long *out3);
-
-/* Same as plpar_hcall but for those opcodes that return no values
- * other than status.  Slightly more efficient.
- */
-long plpar_hcall_norets(unsigned long opcode, ...);
-
-
-long plpar_pte_enter(unsigned long flags,
-		     unsigned long ptex,
-		     unsigned long new_pteh, unsigned long new_ptel,
-		     unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
-{
-	unsigned long dummy, ret;
-	ret = plpar_hcall(H_ENTER, flags, ptex, new_pteh, new_ptel,
-			   old_pteh_ret, old_ptel_ret, &dummy);
-	return(ret);
-}
-
-long plpar_pte_remove(unsigned long flags,
-		      unsigned long ptex,
-		      unsigned long avpn,
-		      unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
-{
-	unsigned long dummy;
-	return plpar_hcall(H_REMOVE, flags, ptex, avpn, 0,
-			   old_pteh_ret, old_ptel_ret, &dummy);
-}
-
-long plpar_pte_read(unsigned long flags,
-		    unsigned long ptex,
-		    unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
-{
-	unsigned long dummy;
-	return plpar_hcall(H_READ, flags, ptex, 0, 0,
-			   old_pteh_ret, old_ptel_ret, &dummy);
-}
-
-long plpar_pte_protect(unsigned long flags,
-		       unsigned long ptex,
-		       unsigned long avpn)
-{
-	return plpar_hcall_norets(H_PROTECT, flags, ptex);
-}
+#include <asm/hvcall.h>
 
 long plpar_tce_get(unsigned long liobn,
 		   unsigned long ioba,
@@ -222,357 +102,6 @@
 			   xirr_ret, mfrr_ret, &dummy);
 }
 
-/*
- * The following section contains code that ultimately should
- * be put in the relavent file (htab.c, xics.c, etc).  It has
- * been put here for the time being in order to ease maintainence
- * of the pSeries LPAR code until it can all be put into CVS.
- */
-static void hpte_invalidate_pSeriesLP(unsigned long slot)
-{
-	HPTE old_pte;
-	unsigned long lpar_rc;
-	unsigned long flags = 0;
-			
-	lpar_rc = plpar_pte_remove(flags,
-				   slot,
-				   0,
-				   &old_pte.dw0.dword0, 
-				   &old_pte.dw1.dword1);
-	if (lpar_rc != H_Success) BUG();
-}
-
-/* NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and
- * the low 3 bits of flags happen to line up.  So no transform is needed.
- * We can probably optimize here and assume the high bits of newpp are
- * already zero.  For now I am paranoid.
- */
-static void hpte_updatepp_pSeriesLP(long slot, unsigned long newpp, unsigned long va)
-{
-	unsigned long lpar_rc;
-	unsigned long flags;
-	flags =   newpp & 3;
-	lpar_rc = plpar_pte_protect( flags,
-				     slot,
-				     0);
-	if (lpar_rc != H_Success) {
-		udbg_printf( " bad return code from pte protect rc = %lx \n", lpar_rc); 
-		for (;;);
-	}
-}
-
-static void hpte_updateboltedpp_pSeriesLP(unsigned long newpp, unsigned long ea)
-{
-	unsigned long lpar_rc;
-	unsigned long vsid,va,vpn,flags;
-	long slot;
-
-	vsid = get_kernel_vsid( ea );
-	va = ( vsid << 28 ) | ( ea & 0x0fffffff );
-	vpn = va >> PAGE_SHIFT;
-
-	slot = ppc_md.hpte_find( vpn );
-	flags =   newpp & 3;
-	lpar_rc = plpar_pte_protect( flags,
-				     slot,
-				     0);
-	if (lpar_rc != H_Success) {
-		udbg_printf( " bad return code from pte bolted protect rc = %lx \n", lpar_rc); 
-		for (;;);
-	}
-}
-
-
-static unsigned long hpte_getword0_pSeriesLP(unsigned long slot)
-{
-	unsigned long dword0;
-	unsigned long lpar_rc;
-	unsigned long dummy_word1;
-	unsigned long flags;
-	/* Read 1 pte at a time                        */
-	/* Do not need RPN to logical page translation */
-	/* No cross CEC PFT access                     */
-	flags = 0;
-	
-	lpar_rc = plpar_pte_read(flags,
-				 slot,
-				 &dword0, &dummy_word1);
-	if (lpar_rc != H_Success) {
-		udbg_printf(" error on pte read in get_hpte0 rc = %lx \n", lpar_rc);
-		for (;;);
-	}
-
-	return(dword0);
-}
-
-static long hpte_selectslot_pSeriesLP(unsigned long vpn)
-{
-	unsigned long primary_hash;
-	unsigned long hpteg_slot;
-	unsigned i, k;
-	unsigned long flags;
-	HPTE  pte_read;
-	unsigned long lpar_rc;
-
-	/* Search the primary group for an available slot */
-	primary_hash = hpt_hash(vpn, 0);
-
-	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-
-	/* Read 1 pte at a time                        */
-	/* Do not need RPN to logical page translation */
-	/* No cross CEC PFT access                     */
-	flags = 0;
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		/* read the hpte entry from the slot */
-		lpar_rc = plpar_pte_read(flags,
-					 hpteg_slot + i,
-					 &pte_read.dw0.dword0, &pte_read.dw1.dword1);
-		if (lpar_rc != H_Success) {
-			udbg_printf(" read of hardware page table failed rc = %lx \n", lpar_rc); 
-			for (;;);
-		}
-		if ( pte_read.dw0.dw0.v == 0 ) {
-			/* If an available slot found, return it */
-			return hpteg_slot + i;
-		}
-
-	}
-
-
-	/* Search the secondary group for an available slot */
-	hpteg_slot = ( ~primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-
-
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		/* read the hpte entry from the slot */
-		lpar_rc = plpar_pte_read(flags,
-					 hpteg_slot + i,
-					 &pte_read.dw0.dword0, &pte_read.dw1.dword1);
-		if (lpar_rc != H_Success) {
-			udbg_printf(" read of hardware page table failed2 rc = %lx  \n", lpar_rc); 
-			for (;;);
-		}
-		if ( pte_read.dw0.dw0.v == 0 ) {
-			/* If an available slot found, return it */
-			return hpteg_slot + i;
-		}
-
-	}
-
-	/* No available entry found in secondary group */
-
-
-	/* Select an entry in the primary group to replace */
-
-	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-
-	k = htab_data.next_round_robin++ & 0x7;
-
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		if (k == HPTES_PER_GROUP)
-			k = 0;
-
-		lpar_rc = plpar_pte_read(flags,
-					 hpteg_slot + k,
-					 &pte_read.dw0.dword0, &pte_read.dw1.dword1);
-		if (lpar_rc != H_Success) {
-			udbg_printf( " pte read failed - rc = %lx", lpar_rc); 
-			for (;;);
-		}
-		if (  ! pte_read.dw0.dw0.bolted)
-		{
-			hpteg_slot += k;
-			/* Invalidate the current entry */
-			ppc_md.hpte_invalidate(hpteg_slot); 
-			return hpteg_slot;
-		}
-		++k;
-	}
-
-	/* No non-bolted entry found in primary group - time to panic */
-	udbg_printf("select_hpte_slot - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);
-	udbg_printf("No non-bolted HPTE in group %lx", (unsigned long)hpteg_slot/HPTES_PER_GROUP);
-	for (;;);
-
-	/* never executes - avoid compiler errors */
-	return 0;
-}
-
-
-static void hpte_create_valid_pSeriesLP(unsigned long slot, unsigned long vpn,
-					unsigned long prpn, unsigned hash, 
-					void *ptep, unsigned hpteflags, 
-					unsigned bolted)
-{
-	/* Local copy of HPTE */
-	struct {
-		/* Local copy of first doubleword of HPTE */
-		union {
-			unsigned long d;
-			Hpte_dword0   h;
-		} dw0;
-		/* Local copy of second doubleword of HPTE */
-		union {
-			unsigned long     d;
-			Hpte_dword1       h;
-			Hpte_dword1_flags f;
-		} dw1;
-	} lhpte;
-	
-	unsigned long avpn = vpn >> 11;
-	unsigned long arpn = physRpn_to_absRpn( prpn );
-
-	unsigned long lpar_rc;
-	unsigned long flags;
-	HPTE ret_hpte;
-
-	/* Fill in the local HPTE with absolute rpn, avpn and flags */
-	lhpte.dw1.d        = 0;
-	lhpte.dw1.h.rpn    = arpn;
-	lhpte.dw1.f.flags  = hpteflags;
-
-	lhpte.dw0.d        = 0;
-	lhpte.dw0.h.avpn   = avpn;
-	lhpte.dw0.h.h      = hash;
-	lhpte.dw0.h.bolted = bolted;
-	lhpte.dw0.h.v      = 1;
-
-	/* Now fill in the actual HPTE */
-	/* Set CEC cookie to 0                  */
-	/* Large page = 0                       */
-	/* Zero page = 0                        */
-	/* I-cache Invalidate = 0               */
-	/* I-cache synchronize = 0              */
-	/* Exact = 1 - only modify exact entry  */
-	flags = H_EXACT;
-
-	if (hpteflags & (_PAGE_GUARDED|_PAGE_NO_CACHE))
-		lhpte.dw1.f.flags &= ~_PAGE_COHERENT;
-#if 1
-	__asm__ __volatile__ (
-		 H_ENTER_r3
-		 "mr	4, %1\n"
-		 "mr	5, %2\n"
-		 "mr	6, %3\n"
-		 "mr	7, %4\n"
-		 HSC
-		 "mr	%0, 3\n"
-		 : "=r" (lpar_rc)
-		 : "r" (flags), "r" (slot), "r" (lhpte.dw0.d), "r" (lhpte.dw1.d)
-		 : "r3", "r4", "r5", "r6", "r7", "cc");
-#else
-	lpar_rc =  plpar_pte_enter(flags,
-				   slot,
-				   lhpte.dw0.d,
-				   lhpte.dw1.d,
-				   &ret_hpte.dw0.dword0,
-				   &ret_hpte.dw1.dword1);
-#endif
-	if (lpar_rc != H_Success) {
-		udbg_printf("error on pte enter lapar rc = %ld\n",lpar_rc);
-		udbg_printf("ent: s=%lx, dw0=%lx, dw1=%lx\n", slot, lhpte.dw0.d, lhpte.dw1.d);
-		/* xmon_backtrace("backtrace"); */
-		for (;;);
-	}
-}
-
-static long hpte_find_pSeriesLP(unsigned long vpn)
-{
-	union {
-		unsigned long d;
-		Hpte_dword0   h;
-	} hpte_dw0;
-	long slot;
-	unsigned long hash;
-	unsigned long i,j;
-
-	hash = hpt_hash(vpn, 0);
-	for ( j=0; j<2; ++j ) {
-		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
-		for ( i=0; i<HPTES_PER_GROUP; ++i ) {
-			hpte_dw0.d = hpte_getword0_pSeriesLP( slot );
-			if ( ( hpte_dw0.h.avpn == ( vpn >> 11 ) ) &&
-			     ( hpte_dw0.h.v ) &&
-			     ( hpte_dw0.h.h == j ) ) {
-				/* HPTE matches */
-				if ( j )
-					slot = -slot;
-				return slot;
-			}
-			++slot;
-		}
-		hash = ~hash;
-	}
-	return -1;
-} 
-
-/*
- * Create a pte - LPAR .  Used during initialization only.
- * We assume the PTE will fit in the primary PTEG.
- */
-void make_pte_LPAR(HPTE *htab,
-		   unsigned long va, unsigned long pa, int mode,
-		   unsigned long hash_mask, int large)
-{
-	HPTE  local_hpte, ret_hpte;
-	unsigned long hash, slot, flags,lpar_rc, vpn;
-
-	if (large)
-		vpn = va >> 24;
-	else
-		vpn = va >> 12;
-
-	hash = hpt_hash(vpn, large);
-
-	slot = ((hash & hash_mask)*HPTES_PER_GROUP);
-
-	local_hpte.dw1.dword1 = pa | mode;
-	local_hpte.dw0.dword0 = 0;
-	local_hpte.dw0.dw0.avpn = va >> 23;
-	local_hpte.dw0.dw0.bolted = 1;				/* bolted */
-	if (large)
-		local_hpte.dw0.dw0.l = 1;  /* large page */
-	local_hpte.dw0.dw0.v = 1;
-
-	/* Set CEC cookie to 0                   */
-	/* Zero page = 0                         */
-	/* I-cache Invalidate = 0                */
-	/* I-cache synchronize = 0               */
-	/* Exact = 0 - modify any entry in group */
-	flags = 0;
-#if 1
-	__asm__ __volatile__ (
-		 H_ENTER_r3
-		 "mr	4, %1\n"
-		 "mr	5, %2\n"
-		 "mr	6, %3\n"
-		 "mr	7, %4\n"
-		 HSC
-		 "mr	%0, 3\n"
-		 : "=r" (lpar_rc)
-		 : "r" (flags), "r" (slot), "r" (local_hpte.dw0.dword0), "r" (local_hpte.dw1.dword1)
-		 : "r3", "r4", "r5", "r6", "r7", "cc");
-#else
-	lpar_rc =  plpar_pte_enter(flags,
-				   slot,
-				   local_hpte.dw0.dword0,
-				   local_hpte.dw1.dword1,
-				   &ret_hpte.dw0.dword0,
-				   &ret_hpte.dw1.dword1);
-#endif
-#if 0 /* NOTE: we explicitly do not check return status here because it is
-       * "normal" for early boot code to map io regions for which a partition
-       * has no access.  However, we will die if we actually fault on these
-       * "permission denied" pages.
-       */
-	if (lpar_rc != H_Success) {
-		/* pSeriesLP_init_early(); */
-		udbg_printf("flags=%lx, slot=%lx, dword0=%lx, dword1=%lx, rc=%d\n", flags, slot, local_hpte.dw0.dword0,local_hpte.dw1.dword1, lpar_rc);
-		BUG();
-	}
-#endif
-}
 
 static void tce_build_pSeriesLP(struct TceTable *tbl, long tcenum, 
 				unsigned long uaddr, int direction )
@@ -746,55 +275,6 @@
 }
 
 
-/* This is called early in setup.c.
- * Use it to setup page table ppc_md stuff as well as udbg.
- */
-void pSeriesLP_init_early(void)
-{
-	ppc_md.hpte_invalidate   = hpte_invalidate_pSeriesLP;
-	ppc_md.hpte_updatepp     = hpte_updatepp_pSeriesLP;
-	ppc_md.hpte_updateboltedpp  = hpte_updateboltedpp_pSeriesLP;
-	ppc_md.hpte_getword0     = hpte_getword0_pSeriesLP;
-	ppc_md.hpte_selectslot   = hpte_selectslot_pSeriesLP;
-	ppc_md.hpte_create_valid = hpte_create_valid_pSeriesLP;
-	ppc_md.hpte_find	 = hpte_find_pSeriesLP;
-
-	ppc_md.tce_build	 = tce_build_pSeriesLP;
-	ppc_md.tce_free_one	 = tce_free_one_pSeriesLP;
-
-#ifdef CONFIG_SMP
-	smp_init_pSeries();
-#endif
-	pSeries_pcibios_init_early();
-
-	/* The keyboard is not useful in the LPAR environment.
-	 * Leave all the interfaces NULL.
-	 */
-
-	if (naca->serialPortAddr) {
-		void *comport = (void *)__ioremap(naca->serialPortAddr, 16, _PAGE_NO_CACHE);
-		udbg_init_uart(comport);
-		ppc_md.udbg_putc = udbg_putc;
-		ppc_md.udbg_getc = udbg_getc;
-		ppc_md.udbg_getc_poll = udbg_getc_poll;
-	} else {
-		/* lookup the first virtual terminal number in case we don't have a com port.
-		 * Zero is probably correct in case someone calls udbg before the init.
-		 * The property is a pair of numbers.  The first is the starting termno (the
-		 * one we use) and the second is the number of terminals.
-		 */
-		u32 *termno;
-		struct device_node *np = find_path_device("/rtas");
-		if (np) {
-			termno = (u32 *)get_property(np, "ibm,termno", 0);
-			if (termno)
-				vtermno = termno[0];
-		}
-		ppc_md.udbg_putc = udbg_putcLP;
-		ppc_md.udbg_getc = udbg_getcLP;
-		ppc_md.udbg_getc_poll = udbg_getc_pollLP;
-	}
-}
 
 /* Code for hvc_console.  Should move it back eventually. */
 
@@ -853,3 +333,43 @@
 	}
 	return 0;
 }
+
+#ifndef CONFIG_PPC_ISERIES
+void pSeries_lpar_mm_init(void);
+
+/* This is called early in setup.c.
+ * Use it to setup page table ppc_md stuff as well as udbg.
+ */
+void pSeriesLP_init_early(void)
+{
+	pSeries_lpar_mm_init();
+
+	ppc_md.tce_build	 = tce_build_pSeriesLP;
+	ppc_md.tce_free_one	 = tce_free_one_pSeriesLP;
+
+#ifdef CONFIG_SMP
+	smp_init_pSeries();
+#endif
+	pSeries_pcibios_init_early();
+
+	/* The keyboard is not useful in the LPAR environment.
+	 * Leave all the interfaces NULL.
+	 */
+
+	/* lookup the first virtual terminal number in case we don't have a com port.
+	 * Zero is probably correct in case someone calls udbg before the init.
+	 * The property is a pair of numbers.  The first is the starting termno (the
+	 * one we use) and the second is the number of terminals.
+	 */
+	u32 *termno;
+	struct device_node *np = find_path_device("/rtas");
+	if (np) {
+		termno = (u32 *)get_property(np, "ibm,termno", 0);
+		if (termno)
+			vtermno = termno[0];
+	}
+	ppc_md.udbg_putc = udbg_putcLP;
+	ppc_md.udbg_getc = udbg_getcLP;
+	ppc_md.udbg_getc_poll = udbg_getc_pollLP;
+}
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/pSeries_pci.c linux-2.4.20/arch/ppc64/kernel/pSeries_pci.c
--- linux-2.4.19/arch/ppc64/kernel/pSeries_pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/pSeries_pci.c	2002-10-29 11:18:35.000000000 +0000
@@ -22,13 +22,11 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/ide.h>
 #include <linux/bootmem.h>
 
 #include <asm/io.h>
@@ -80,14 +78,12 @@
 	 \
 	if (dn == NULL) { \
 		ret = -2; \
-	} else if (dn->status) { \
-		ret = -1; \
 	} else { \
 		addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
 		buid = dn->phb->buid; \
 		if (buid) { \
 			ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, addr, buid >> 32, buid & 0xffffffff, nbytes); \
-                        if (ret < 0) \
+                        if (ret < 0 || (returnval == 0xffffffff)) \
                                ret = rtas_fake_read(dn, offset, nbytes, &returnval); \
 		} else { \
 			ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, nbytes); \
@@ -113,8 +109,6 @@
 	 \
 	if (dn == NULL) { \
 		ret = -2; \
-	} else if (dn->status) { \
-		ret = -1; \
 	} else { \
 		buid = dn->phb->buid; \
 		addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
@@ -491,7 +485,7 @@
 					 0x100000); 
 
 		/* 
-		 * Firmware doesnt always clear this bit which is critical
+		 * Firmware doesn't always clear this bit which is critical
 		 * for good performance - Anton
 		 */
 		{
@@ -659,13 +653,20 @@
 			continue;
 		}
 
+		if (dev->resource[i].start > dev->resource[i].end) {
+			/* Bogus resource.  Just clear it out. */
+			dev->resource[i].start = dev->resource[i].end = 0;
+			continue;
+		}
+
+
 		if (dev->resource[i].flags & IORESOURCE_IO) {
 			if (is_eeh_implemented()) {
 				unsigned int busno = dev->bus ? dev->bus->number : 0;
 				unsigned long size = dev->resource[i].end - dev->resource[i].start;
 				unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->io_base_phys, size, _PAGE_NO_CACHE);
 				if (!addr)
-					panic("fixup_resources: ioremap failed!\n");
+					panic("fixup_resources: io ioremap failed!\n");
 				dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit;
 				dev->resource[i].end = dev->resource[i].start + size;
 			} else {
@@ -685,7 +686,7 @@
 					unsigned long size = dev->resource[i].end - dev->resource[i].start;
 					unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->pci_mem_offset, size, _PAGE_NO_CACHE);
 					if (!addr)
-						panic("fixup_resources: ioremap failed!\n");
+						panic("fixup_resources: mem ioremap failed!\n");
 					dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit;
 					dev->resource[i].end = dev->resource[i].start + size;
 				} else {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/pacaData.c linux-2.4.20/arch/ppc64/kernel/pacaData.c
--- linux-2.4.19/arch/ppc64/kernel/pacaData.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/pacaData.c	2002-10-29 11:18:48.000000000 +0000
@@ -7,7 +7,6 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#define __KERNEL__
 #include <asm/types.h>
 #include <asm/page.h>
 #include <stddef.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/pci.c linux-2.4.20/arch/ppc64/kernel/pci.c
--- linux-2.4.19/arch/ppc64/kernel/pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/pci.c	2002-10-29 11:18:48.000000000 +0000
@@ -74,7 +74,7 @@
 long   Pci_Cfg_Write_Count= 0;
 long   Pci_Error_Count    = 0;
 
-int    Pci_Retry_Max      = 3;	/* Only retry 3 times  */	
+int    Pci_Retry_Max      = 7;	/* Retry set to 7 times  */	
 int    Pci_Error_Flag     = 1;	/* Set Retry Error on. */
 int    Pci_Trace_Flag     = 0;
 
@@ -180,7 +180,8 @@
  * which might have be mirrored at 0x0100-0x03ff..
  */
 void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res, unsigned long size,
+		       unsigned long align)
 {
 	struct pci_dev *dev = data;
 
@@ -364,7 +365,7 @@
 
 
 int
-pcibios_enable_resources(struct pci_dev *dev)
+pcibios_enable_resources(struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
@@ -373,6 +374,8 @@
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for(idx=0; idx<6; idx++) {
+		if(!(mask & (1<<idx)))
+			continue;
 		r = &dev->resource[idx];
 		if (!r->start && r->end) {
 			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
@@ -452,9 +455,9 @@
 	iSeries_pcibios_init(); 
 #endif
 
+	ppc64_boot_msg(0x40, "PCI Probe");
 	printk("PCI: Probing PCI hardware\n");
 	PPCDBG(PPCDBG_BUSWALK,"PCI: Probing PCI hardware\n");
-				
 
 	/* Scan all of the recorded PCI controllers.  */
 	for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
@@ -489,11 +492,13 @@
 #endif
 
 	/* Cache the location of the ISA bridge (if we have one) */
-	if (ppc64_isabridge_dev = pci_find_class(PCI_CLASS_BRIDGE_ISA << 8, NULL))
+	ppc64_isabridge_dev = pci_find_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
+	if (ppc64_isabridge_dev != NULL )
 		printk("ISA bridge at %s\n", ppc64_isabridge_dev->slot_name);
 
 	printk("PCI: Probing PCI hardware done\n");
 	PPCDBG(PPCDBG_BUSWALK,"PCI: Probing PCI hardware done.\n");
+	ppc64_boot_msg(0x41, "PCI Done");
 
 }
 
@@ -511,11 +516,11 @@
 
 void __init pcibios_fixup_bus(struct pci_bus *bus)
 {
+#ifndef CONFIG_PPC_ISERIES
 	struct pci_controller *phb = PCI_GET_PHB_PTR(bus);
 	struct resource *res;
 	int i;
 
-#ifndef CONFIG_PPC_ISERIES
 	if (bus->parent == NULL) {
 		/* This is a host bridge - fill in its resources */
 		phb->bus = bus;
@@ -573,7 +578,7 @@
 	return str;
 }
 
-int pcibios_enable_device(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/pci_dma.c linux-2.4.20/arch/ppc64/kernel/pci_dma.c
--- linux-2.4.19/arch/ppc64/kernel/pci_dma.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/pci_dma.c	2002-10-29 11:18:39.000000000 +0000
@@ -1389,10 +1389,11 @@
 	PPCDBG(PPCDBG_TCE, "pci_unmap_sg:\n");
 	PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, sg = 0x%16.16lx, direction = 0x%16.16lx, nelms = 0x%16.16lx\n", hwdev, sg, direction, nelms);	
 
-	if ( direction == PCI_DMA_NONE )
+	if ( direction == PCI_DMA_NONE || nelms == 0 )
 		BUG();
 
 	dma_start_page = sg->dma_address & PAGE_MASK;
+ 	dma_end_page   = 0;
 	for ( i=nelms; i>0; --i ) {
 		unsigned k = i - 1;
 		if ( sg[k].dma_length ) {
@@ -1408,6 +1409,7 @@
  	/* Client asked for way to much space.  This is checked later anyway */
 	/* It is easier to debug here for the drivers than in the tce tables.*/
  	if(order >= NUM_TCE_LEVELS) {
+		printk("PCI_DMA: dma_start_page:0x%lx  dma_end_page:0x%lx\n",dma_start_page,dma_end_page);
 		printk("PCI_DMA: pci_unmap_sg size to large: 0x%x \n",(numTces << PAGE_SHIFT));
  		return;
  	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/pci_dn.c linux-2.4.20/arch/ppc64/kernel/pci_dn.c
--- linux-2.4.19/arch/ppc64/kernel/pci_dn.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/pci_dn.c	2002-10-29 11:18:32.000000000 +0000
@@ -249,8 +249,9 @@
 	*eads = *other_eads;
 	eads->devfn &= ~7;	/* make it function zero */
 	eads->tce_table = NULL;
-	/* NOTE: share properties.  We could copy but for now this should suffice.
-	 * The full_name is also incorrect...but seems harmless.
+	/*
+	 * NOTE: share properties.  We could copy but for now this should
+	 * suffice.  The full_name is also incorrect...but seems harmless.
 	 */
 	eads->child = NULL;
 	eads->next = NULL;
@@ -285,21 +286,25 @@
 		dev->sysdata = dn;
 		/* ToDo: call some device init hook here */
 	} else {
-		/* Now it is very possible that we can't find the device because it is
-		 * not the zero'th device of a mutifunction device and we don't have
-		 * permission to read the zero'th device.  If this is the case, Linux
-		 * would ordinarily skip all the other functions.
+		/* Now it is very possible that we can't find the device
+		 * because it is not the zero'th device of a mutifunction
+		 * device and we don't have permission to read the zero'th
+		 * device.  If this is the case, Linux would ordinarily skip
+		 * all the other functions.
 		 */
 		if ((searchval & 0x7) == 0) {
 			struct device_node *thisdevdn;
 			/* Ok, we are looking for fn == 0.  Let's check for other functions. */
 			thisdevdn = (struct device_node *)traverse_pci_devices(phb_dn, is_devfn_sub_node, NULL, (void *)searchval);
 			if (thisdevdn) {
-				/* Ah ha!  There does exist a sub function.  Now this isn't an exact
-				 * match for searchval, but in order to get Linux to believe the sub
-				 * functions exist we will need to manufacture a fake device_node
-				 * for this zero'th function.  To keept this simple for now we only
-				 * handle pci bridges and we just hand back the found node which
+				/* Ah ha!  There does exist a sub function.
+				 * Now this isn't an exact match for
+				 * searchval, but in order to get Linux to
+				 * believe the sub functions exist we will
+				 * need to manufacture a fake device_node for
+				 * this zero'th function.  To keept this
+				 * simple for now we only handle pci bridges
+				 * and we just hand back the found node which
 				 * isn't correct, but Linux won't care.
 				 */
 				char *device_type = (char *)get_property(thisdevdn, "device_type", 0);
@@ -368,7 +373,6 @@
 	}
 }
 
-
 /******************************************************************
  * Fixup the bus->sysdata ptrs to point to the bus' device_node.
  * This is done late in pcibios_init().  We do this mostly for
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/perfmon.c linux-2.4.20/arch/ppc64/kernel/perfmon.c
--- linux-2.4.19/arch/ppc64/kernel/perfmon.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/perfmon.c	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,404 @@
+/*
+ * This file contains the code to configure and utilize the ppc64 pmc hardware
+ * Copyright (C) 2002 David Engebretsen <engebret@us.ibm.com>
+ */
+
+#include <asm/proc_fs.h>
+#include <asm/paca.h>
+#include <asm/iSeries/ItLpPaca.h>
+#include <asm/iSeries/ItLpQueue.h>
+#include <asm/processor.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <asm/pmc.h>
+#include <asm/uaccess.h>
+#include <asm/naca.h>
+#include <asm/perfmon.h>
+
+extern char _stext[], _etext[], _end[];
+struct perfmon_base_struct perfmon_base = {0, 0, 0, 0, 0, PMC_STATE_INITIAL};
+
+int alloc_perf_buffer(int size);
+int free_perf_buffer(void);
+int clear_buffers(void);
+void pmc_stop(void *data);
+void pmc_start(void *data);
+void pmc_touch_bolted(void *data);
+void dump_pmc_struct(struct perfmon_struct *perfdata);
+void dump_hardware_pmc_struct(void *perfdata);
+int  decr_profile(struct perfmon_struct *perfdata);
+int  pmc_profile(struct perfmon_struct *perfdata);
+int  pmc_set_general(struct perfmon_struct *perfdata);
+int  pmc_set_user_general(struct perfmon_struct *perfdata);
+void pmc_configure(void *data);
+
+asmlinkage int
+sys_perfmonctl (int cmd, void *data) 
+{ 
+	struct perfmon_struct *pdata;
+	int err;
+
+	printk("sys_perfmonctl: cmd = 0x%x\n", cmd); 
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+	switch(cmd) {
+	case PMC_OP_ALLOC:
+		alloc_perf_buffer(0); 
+		break;
+	case PMC_OP_FREE:
+		free_perf_buffer(); 
+		break;
+	case PMC_OP_CLEAR:
+		clear_buffers();
+		break;
+	case PMC_OP_DUMP:
+		dump_pmc_struct(pdata);
+		copy_to_user(data, pdata, sizeof(struct perfmon_struct));
+		break;
+	case PMC_OP_DUMP_HARDWARE:
+		dump_hardware_pmc_struct(pdata);
+		smp_call_function(dump_hardware_pmc_struct, (void *)pdata, 0, 1);
+		break;
+	case PMC_OP_DECR_PROFILE: /* NIA time sampling */
+		decr_profile(pdata); 
+		break;
+	case PMC_OP_PMC_PROFILE:
+		pmc_profile(pdata); 
+		break;
+	case PMC_OP_SET:
+		pmc_set_general(pdata); 
+		break;
+	case PMC_OP_SET_USER:
+		pmc_set_user_general(pdata); 
+		break;
+	default:
+		printk("Perfmon: Unknown operation\n");
+		break;
+	}
+
+	kfree(pdata); 
+	return 0;
+}
+
+int alloc_perf_buffer(int size) 
+{
+	int i;
+
+	printk("Perfmon: allocate buffer\n");
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		perfmon_base.profile_length = (((unsigned long) &_etext - 
+				   (unsigned long) &_stext) >> 2) * sizeof(int);
+		perfmon_base.profile_buffer = (unsigned long)btmalloc(perfmon_base.profile_length);
+		perfmon_base.trace_length = 1024*1024*16;
+		perfmon_base.trace_buffer = (unsigned long)btmalloc(perfmon_base.trace_length);
+
+		if(perfmon_base.profile_buffer && perfmon_base.trace_buffer) {
+			memset((char *)perfmon_base.profile_buffer, 0, perfmon_base.profile_length);
+			printk("Profile buffer created at address 0x%lx of length 0x%lx\n",
+			       perfmon_base.profile_buffer, perfmon_base.profile_length); 
+		} else {
+			printk("Profile buffer creation failed\n");
+			return 0;
+		}
+
+		/* Fault in the first bolted segment - it then remains in the stab for all time */
+		pmc_touch_bolted(NULL); 
+		smp_call_function(pmc_touch_bolted, (void *)NULL, 0, 1);
+
+		for (i=0; i<MAX_PACAS; ++i) {
+			paca[i].prof_shift = 2;
+			paca[i].prof_len = perfmon_base.profile_length;
+			paca[i].prof_buffer = (unsigned *)(perfmon_base.profile_buffer);
+			paca[i].prof_stext = (unsigned *)&_stext;
+
+			paca[i].prof_etext = (unsigned *)&_etext;
+			mb();
+		} 
+
+		perfmon_base.state = PMC_STATE_READY; 
+	}
+
+	return 0;
+}
+
+int free_perf_buffer() 
+{
+	printk("Perfmon: free buffer\n");
+
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		printk("Perfmon: free buffer failed - no buffer was allocated.\n"); 
+		return -1;
+	}
+
+	btfree((void *)perfmon_base.profile_buffer); 
+	btfree((void *)perfmon_base.trace_buffer); 
+
+	perfmon_base.profile_length = 0;
+	perfmon_base.profile_buffer = 0;
+	perfmon_base.trace_buffer   = 0;
+	perfmon_base.trace_length   = 0;
+	perfmon_base.trace_end      = 0;
+	perfmon_base.state = PMC_STATE_INITIAL; 
+
+	return(0); 
+}
+
+int clear_buffers() 
+{
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		printk("Perfmon: clear buffer failed - no buffer was allocated.\n"); 
+		return -1;
+	}
+
+	printk("Perfmon: clear buffer\n");
+	
+	/* Stop counters on all processors -- blocking */
+	pmc_stop(NULL); 
+	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
+	
+	/* Clear the buffers */
+	memset((char *)perfmon_base.profile_buffer, 0, perfmon_base.profile_length);
+	memset((char *)perfmon_base.trace_buffer, 0, perfmon_base.trace_length);
+	
+	/* Reset the trace buffer point */
+	perfmon_base.trace_end = 0;
+	
+	/* Restart counters on all processors -- blocking */
+	pmc_start(NULL); 
+	smp_call_function(pmc_start, (void *)NULL, 0, 1);
+
+	return(0); 
+}
+
+void pmc_stop(void *data) 
+{
+	/* Freeze all counters, leave everything else alone */
+	mtspr( MMCR0, mfspr( MMCR0 ) | 0x80000000 );
+}
+
+void pmc_start(void *data) 
+{
+	/* Free all counters, leave everything else alone */
+	mtspr( MMCR0, mfspr( MMCR0 ) & 0x7fffffff );
+}
+
+void pmc_touch_bolted(void *data) 
+{
+	volatile int touch;
+
+	/* Hack to fault the buffer into the segment table */
+	touch = *((int *)(perfmon_base.profile_buffer));
+}
+
+void dump_pmc_struct(struct perfmon_struct *perfdata) 
+{
+	unsigned int cpu = perfdata->vdata.pmc_info.cpu, i;
+
+	if(cpu > MAX_PACAS) return;
+
+	printk("PMC Control Mode: 0x%lx\n", perfmon_base.state);
+	printk("PMC[1 - 2] = 0x%16.16lx 0x%16.16lx\n",
+	       paca[cpu].pmcc[0], paca[cpu].pmcc[1]);
+	printk("PMC[3 - 4] = 0x%16.16lx 0x%16.16lx\n",
+	       paca[cpu].pmcc[2], paca[cpu].pmcc[3]);
+	printk("PMC[5 - 6] = 0x%16.16lx 0x%16.16lx\n",
+	       paca[cpu].pmcc[4], paca[cpu].pmcc[5]);
+	printk("PMC[7 - 8] = 0x%16.16lx 0x%16.16lx\n",
+	       paca[cpu].pmcc[6], paca[cpu].pmcc[7]);
+
+	perfdata->vdata.pmc_info.mode = perfmon_base.state;
+	for(i = 0; i < 11; i++) 
+		perfdata->vdata.pmc_info.pmc_base[i]  = paca[cpu].pmc[i];
+
+	for(i = 0; i < 8; i++) 
+		perfdata->vdata.pmc_info.pmc_cumulative[i]  = paca[cpu].pmcc[i];
+}
+
+void dump_hardware_pmc_struct(void *perfdata) 
+{
+	unsigned int cpu = smp_processor_id();
+
+	printk("PMC[%2.2d][1 - 4]  = 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
+	       cpu, (u32) mfspr(PMC1),(u32) mfspr(PMC2),(u32) mfspr(PMC3),(u32) mfspr(PMC4));
+	printk("PMC[%2.2d][5 - 8]  = 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
+	       cpu, (u32) mfspr(PMC5),(u32) mfspr(PMC6),(u32) mfspr(PMC7),(u32) mfspr(PMC8));
+	printk("MMCR[%2.2d][0,1,A] = 0x%8.8x 0x%8.8x 0x%8.8x\n",
+	       cpu, (u32) mfspr(MMCR0),(u32) mfspr(MMCR1),(u32) mfspr(MMCRA));
+}
+
+int decr_profile(struct perfmon_struct *perfdata) 
+{
+	int i;
+
+	printk("Perfmon: NIA decrementer profile\n");
+
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		printk("Perfmon: failed - no buffer was allocated.\n"); 
+		return -1;
+	}
+	
+	/* Stop counters on all processors -- blocking */
+	pmc_stop(NULL); 
+	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
+	
+	for (i=0; i<MAX_PACAS; ++i) {
+		paca[i].prof_mode = PMC_STATE_DECR_PROFILE;
+	}
+	
+	perfmon_base.state = PMC_STATE_DECR_PROFILE; 
+	mb(); 
+
+	return 0;
+}
+
+int pmc_profile(struct perfmon_struct *perfdata) 
+{
+	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
+	int i;
+
+	printk("Perfmon: NIA PMC profile and CPI\n");
+
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		printk("Perfmon: failed - no buffer was allocated.\n"); 
+		return -1;
+	}
+
+	/* Stop counters on all processors -- blocking */
+	pmc_stop(NULL); 
+	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
+	
+	for (i=0; i<MAX_PACAS; ++i) {
+		paca[i].prof_mode = PMC_STATE_PROFILE_KERN;
+	}
+	perfmon_base.state = PMC_STATE_PROFILE_KERN; 
+
+	pdata->pmc[0] = 0x7f000000;
+	for(i = 1; i < 8; i++) 
+		pdata->pmc[i] = 0x0;
+	pdata->pmc[8] = 0x26000000 | (0x01 << (31 - 25) | (0x1));
+	pdata->pmc[9] = (0x3 << (31-4)); /* Instr completed */
+	pdata->pmc[10] = 0x00000000 | (0x1 << (31 - 30));
+
+	mb();
+
+	pmc_configure((void *)perfdata);
+	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
+
+	return 0;
+}
+
+int pmc_set_general(struct perfmon_struct *perfdata) 
+{
+	int i;
+
+	printk("Perfmon: PMC sampling - General\n");
+
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		printk("Perfmon: failed - no buffer was allocated.\n"); 
+		return -1;
+	}
+
+	/* Stop counters on all processors -- blocking */
+	pmc_stop(NULL); 
+	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
+	
+	for (i=0; i<MAX_PACAS; ++i) {
+		paca[i].prof_mode = PMC_STATE_TRACE_KERN;
+	}
+	perfmon_base.state = PMC_STATE_TRACE_KERN; 
+	mb();
+
+	pmc_configure((void *)perfdata);
+	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
+
+	return 0;
+}
+
+int pmc_set_user_general(struct perfmon_struct *perfdata) 
+{
+	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
+	int pid = perfdata->header.pid;
+	struct task_struct *task;
+	int i;
+
+	printk("Perfmon: PMC sampling - general user\n");
+
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		printk("Perfmon: failed - no buffer was allocated.\n"); 
+		return -1;
+	}
+
+	if(pid) {
+		printk("Perfmon: pid = 0x%x\n", pid);
+		read_lock(&tasklist_lock);
+		task = find_task_by_pid(pid);
+		if (task) {
+			printk("Perfmon: task = 0x%lx\n", (u64) task);
+			task->thread.regs->msr |= 0x4;
+#if 0
+			for(i = 0; i < 11; i++)
+				task->thread.pmc[i] = pdata->pmc[i];
+#endif
+		} else {
+			printk("Perfmon: task not found\n");
+			read_unlock(&tasklist_lock);
+			return -1;
+		}
+	}
+	read_unlock(&tasklist_lock);
+
+	/* Stop counters on all processors -- blocking */
+	pmc_stop(NULL); 
+	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
+	
+	for (i=0; i<MAX_PACAS; ++i) {
+		paca[i].prof_mode = PMC_STATE_TRACE_USER;
+	}
+	perfmon_base.state = PMC_STATE_TRACE_USER; 
+	mb();
+
+	pmc_configure((void *)perfdata);
+	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
+
+	return 0;
+}
+
+void pmc_configure(void *data)
+{
+	struct paca_struct *lpaca = get_paca();
+	struct perfmon_struct *perfdata = (struct perfmon_struct *)data;
+	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
+	unsigned long cmd_rec, i;
+
+	/* Indicate to hypervisor that we are using the PMCs */
+	if(naca->platform == PLATFORM_ISERIES_LPAR)
+		lpaca->xLpPacaPtr->xPMCRegsInUse = 1;
+
+	/* Freeze all counters */
+	mtspr( MMCR0, 0x80000000 ); mtspr( MMCR1, 0x00000000 );
+
+	cmd_rec = 0xFFUL << 56;
+	cmd_rec |= perfdata->header.type;
+	*((unsigned long *)(perfmon_base.trace_buffer + perfmon_base.trace_end)) = cmd_rec;
+	perfmon_base.trace_end += 8;
+
+	/* Clear all the PMCs */
+	mtspr( PMC1, 0 ); mtspr( PMC2, 0 ); mtspr( PMC3, 0 );
+	mtspr( PMC4, 0 ); mtspr( PMC5, 0 ); mtspr( PMC6, 0 );
+	mtspr( PMC7, 0 ); mtspr( PMC8, 0 );
+
+	for(i = 0; i < 11; i++)
+		lpaca->pmc[i]  = pdata->pmc[i];
+
+	mtspr(PMC1, lpaca->pmc[0]); mtspr(PMC2, lpaca->pmc[1]);
+	mtspr(PMC3, lpaca->pmc[2]); mtspr(PMC4, lpaca->pmc[3]);
+	mtspr(PMC5, lpaca->pmc[4]); mtspr(PMC6, lpaca->pmc[5]);
+	mtspr(PMC7, lpaca->pmc[6]); mtspr(PMC8, lpaca->pmc[7]);
+	mtspr(MMCR1, lpaca->pmc[9]); mtspr(MMCRA, lpaca->pmc[10]);
+
+	mb();
+	
+	/* Start all counters */
+	mtspr( MMCR0, lpaca->pmc[8]);
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/pmc.c linux-2.4.20/arch/ppc64/kernel/pmc.c
--- linux-2.4.19/arch/ppc64/kernel/pmc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/pmc.c	2002-10-29 11:18:31.000000000 +0000
@@ -31,7 +31,7 @@
 
 #include <linux/proc_fs.h>
 #include <linux/spinlock.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <asm/pmc.h>
 #include <asm/uaccess.h>
@@ -39,6 +39,10 @@
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
+#include <asm/page.h>
+#include <asm/machdep.h>
+#include <asm/lmb.h>
+#include <asm/abs_addr.h>
 #include <asm/ppcdebug.h>
 
 struct _pmc_sw pmc_sw_system = {
@@ -69,6 +73,8 @@
 struct mm_struct btmalloc_mm = {pgd             : bolted_dir,
                                 page_table_lock : SPIN_LOCK_UNLOCKED};
 
+extern spinlock_t hash_table_lock;
+
 char *
 ppc64_pmc_stab(int file)
 {
@@ -204,15 +210,16 @@
 void* btmalloc (unsigned long size) {
 	pgd_t *pgdp;
 	pmd_t *pmdp;
-	pte_t *ptep;
-	unsigned long ea_base, ea;
+	pte_t *ptep, pte;
+	unsigned long ea_base, ea, hpteflags;
 	struct vm_struct *area;
-	unsigned long pa, pg_count, page, vsid;
+	unsigned long pa, pg_count, page, vsid, slot, va, arpn, vpn;
   
 	size = PAGE_ALIGN(size);
 	if (!size || (size >> PAGE_SHIFT) > num_physpages) return NULL;
 
 	spin_lock(&btmalloc_mm.page_table_lock);
+	spin_lock(&hash_table_lock);
 
 	/* Get a virtual address region in the bolted space */
 	area = get_btm_area(size, 0);
@@ -228,6 +235,10 @@
 	for(page = 0; page < pg_count; page++) {
 		pa = get_free_page(GFP_KERNEL) - PAGE_OFFSET; 
 		ea = ea_base + (page * PAGE_SIZE);
+		vsid = get_kernel_vsid(ea);
+		va = ( vsid << 28 ) | ( pa & 0xfffffff );
+		vpn = va >> PAGE_SHIFT;
+		arpn = ((unsigned long)__v2a(ea)) >> PAGE_SHIFT;
 
 		/* Get a pointer to the linux page table entry for this page
 		 * allocating pmd or pte pages along the way as needed.  Note
@@ -236,15 +247,23 @@
 		pgdp = pgd_offset_b(ea);
 		pmdp = pmd_alloc(&btmalloc_mm, pgdp, ea);
 		ptep = pte_alloc(&btmalloc_mm, pmdp, ea);
+		pte = *ptep;
 
 		/* Clear any old hpte and set the new linux pte */
 		set_pte(ptep, mk_pte_phys(pa & PAGE_MASK, PAGE_KERNEL));
 
-		vsid = get_kernel_vsid(ea);
-		build_valid_hpte(vsid, ea, pa, ptep, 
-				  _PAGE_ACCESSED|_PAGE_COHERENT|PP_RWXX, 1);
+		hpteflags = _PAGE_ACCESSED|_PAGE_COHERENT|PP_RWXX;
+
+		pte_val(pte) &= ~_PAGE_HPTEFLAGS;
+		pte_val(pte) |= _PAGE_HASHPTE;
+
+		slot = ppc_md.hpte_insert(vpn, arpn, hpteflags, 1, 0);  
+
+		pte_val(pte) |= ((slot<<12) & 
+				 (_PAGE_GROUP_IX | _PAGE_SECONDARY));
 	}
 
+	spin_unlock(&hash_table_lock);
 	spin_unlock(&btmalloc_mm.page_table_lock);
 	return (void*)ea_base;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/ppc_ksyms.c linux-2.4.20/arch/ppc64/kernel/ppc_ksyms.c
--- linux-2.4.19/arch/ppc64/kernel/ppc_ksyms.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/ppc_ksyms.c	2002-10-29 11:18:51.000000000 +0000
@@ -40,15 +40,18 @@
 #include <asm/machdep.h>
 #include <asm/hw_irq.h>
 #include <asm/abs_addr.h>
-#ifdef CONFIG_SMP
 #include <asm/smplock.h>
-#endif /* CONFIG_SMP */
 #ifdef CONFIG_PPC_ISERIES
 #include <asm/iSeries/iSeries_pci.h>
 #include <asm/iSeries/iSeries_proc.h>
 #include <asm/iSeries/mf.h>
 #include <asm/iSeries/HvLpEvent.h>
 #include <asm/iSeries/HvLpConfig.h>
+#include <asm/iSeries/ItLpNaca.h>
+#include <asm/iSeries/ItExtVpdPanel.h>
+#include <asm/iSeries/LparData.h>
+#else
+#include <asm/rtas.h>
 #endif
 
 /* Tell string.h we don't want memcpy etc. as cpp defines */
@@ -61,6 +64,7 @@
 extern void AlignmentException(struct pt_regs *regs);
 extern void ProgramCheckException(struct pt_regs *regs);
 extern void SingleStepException(struct pt_regs *regs);
+extern int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 extern int sys_sigreturn(struct pt_regs *regs);
 extern int do_signal(sigset_t *, struct pt_regs *);
 extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
@@ -82,6 +86,7 @@
 EXPORT_SYMBOL(AlignmentException);
 EXPORT_SYMBOL(ProgramCheckException);
 EXPORT_SYMBOL(SingleStepException);
+EXPORT_SYMBOL(sys_ioctl);
 EXPORT_SYMBOL(sys_sigreturn);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
@@ -160,6 +165,8 @@
 EXPORT_SYMBOL(mf_allocateLpEvents);
 EXPORT_SYMBOL(mf_deallocateLpEvents);
 EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline);
+EXPORT_SYMBOL(itLpNaca);
+EXPORT_SYMBOL(xItExtVpdPanel);
 #endif
 
 EXPORT_SYMBOL(_insb);
@@ -189,6 +196,8 @@
 EXPORT_SYMBOL(iSeries_Read_Long);
 EXPORT_SYMBOL(iSeries_Device_ToggleReset);
 EXPORT_SYMBOL(iSeries_Write_Word);
+EXPORT_SYMBOL(iSeries_memset_io);
+EXPORT_SYMBOL(iSeries_memcpy_toio);
 EXPORT_SYMBOL(iSeries_memcpy_fromio);
 EXPORT_SYMBOL(iSeries_Read_Word);
 EXPORT_SYMBOL(iSeries_Read_Byte);
@@ -238,6 +247,13 @@
 EXPORT_SYMBOL(find_all_nodes);
 EXPORT_SYMBOL(get_property);
 
+#ifdef CONFIG_PPC_PSERIES
+EXPORT_SYMBOL(rtas_proc_dir);
+EXPORT_SYMBOL(rtas_firmware_flash_list);
+EXPORT_SYMBOL(rtas_token);
+EXPORT_SYMBOL(rtas_call);
+#endif
+
 #ifndef CONFIG_PPC_ISERIES
 EXPORT_SYMBOL(kd_mksound);
 #endif
@@ -288,3 +304,8 @@
 #endif
 
 EXPORT_SYMBOL(tb_ticks_per_usec);
+
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+extern void dump_send_ipi(int (*dump_ipi_callback)(struct pt_regs *));
+EXPORT_SYMBOL(dump_send_ipi);
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/proc_pmc.c linux-2.4.20/arch/ppc64/kernel/proc_pmc.c
--- linux-2.4.19/arch/ppc64/kernel/proc_pmc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/proc_pmc.c	2002-10-29 11:18:39.000000000 +0000
@@ -41,6 +41,8 @@
 #include <asm/pmc.h>
 #include <asm/uaccess.h>
 #include <asm/naca.h>
+#include <asm/rtas.h>
+#include <asm/perfmon.h>
 
 /* pci Flight Recorder AHT */
 extern void proc_pciFr_init(struct proc_dir_entry *proc_ppc64_root);
@@ -63,6 +65,10 @@
 			     int count, int *eof, void *data);
 int proc_ppc64_pmc_htab_read(char *page, char **start, off_t off,
 			     int count, int *eof, void *data);
+int proc_ppc64_pmc_profile_read(char *page, char **start, off_t off,
+				int count, int *eof, void *data);
+int proc_ppc64_pmc_profile_read(char *page, char **start, off_t off,
+				int count, int *eof, void *data);
 int proc_ppc64_pmc_hw_read(char *page, char **start, off_t off, 
 			   int count, int *eof, void *data);
 
@@ -88,6 +94,34 @@
 int proc_pmc_set_pmc7(  struct file *file, const char *buffer, unsigned long count, void *data);
 int proc_pmc_set_pmc8(  struct file *file, const char *buffer, unsigned long count, void *data);
 
+static loff_t  nacamap_seek( struct file *file, loff_t off, int whence);
+static ssize_t nacamap_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos);
+static int     nacamap_mmap( struct file *file, struct vm_area_struct *vma );
+
+static struct file_operations nacamap_fops = {
+	llseek:	nacamap_seek,
+	read:	nacamap_read,
+	mmap:	nacamap_mmap
+};
+
+static ssize_t read_profile(struct file *file, char *buf, size_t count, loff_t *ppos);
+static ssize_t write_profile(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos);
+static ssize_t read_trace(struct file *file, char *buf, size_t count, loff_t *ppos);
+static ssize_t write_trace(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos);
+
+static struct file_operations proc_profile_operations = {
+	read:		read_profile,
+	write:		write_profile,
+};
+
+static struct file_operations proc_trace_operations = {
+	read:		read_trace,
+	write:		write_trace,
+};
+
+extern struct perfmon_base_struct perfmon_base;
 
 void proc_ppc64_init(void)
 {
@@ -107,8 +141,14 @@
 	if (!proc_ppc64_root) return;
 	spin_unlock(&proc_ppc64_lock);
 
-	/* /proc/ppc64/naca -- raw naca contents.  Only readable to root */
-	create_proc_read_entry("naca", S_IRUSR, proc_ppc64_root, proc_ppc64_page_read, naca);
+	ent = create_proc_entry("naca", S_IFREG|S_IRUGO, proc_ppc64_root);
+	if ( ent ) {
+		ent->nlink = 1;
+		ent->data = 0;
+		ent->size = 4096;
+		ent->proc_fops = &nacamap_fops;
+	}
+
 	/* /proc/ppc64/paca/XX -- raw paca contents.  Only readable to root */
 	ent = proc_mkdir("paca", proc_ppc64_root);
 	if (ent) {
@@ -116,6 +156,9 @@
 			proc_ppc64_create_paca(i, ent);
 	}
 
+	/* Placeholder for rtas interfaces. */
+	rtas_proc_dir = proc_mkdir("rtas", proc_ppc64_root);
+
 	/* Create the /proc/ppc64/pcifr for the Pci Flight Recorder.	 */
 	proc_pciFr_init(proc_ppc64_root);
 
@@ -167,6 +210,20 @@
 		ent->write_proc = (void *)proc_ppc64_pmc_htab_read;
 	}
 
+	ent = create_proc_entry("profile", S_IWUSR | S_IRUGO, proc_ppc64_pmc_system_root);
+	if (ent) {
+		ent->nlink = 1;
+		ent->proc_fops = &proc_profile_operations;
+		/* ent->size = (1+prof_len) * sizeof(unsigned int); */
+	}
+
+	ent = create_proc_entry("trace", S_IWUSR | S_IRUGO, proc_ppc64_pmc_system_root);
+	if (ent) {
+		ent->nlink = 1;
+		ent->proc_fops = &proc_trace_operations;
+		/* ent->size = (1+prof_len) * sizeof(unsigned int); */
+	}
+
 	/* Create directories for the hardware counters. */
 	for (i = 0; i < naca->processorCount; i++) {
 		ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR, 
@@ -336,6 +393,60 @@
 	return n;
 }
 
+static ssize_t read_profile(struct file *file, char *buf,
+			    size_t count, loff_t *ppos)
+{
+	unsigned long p = *ppos;
+	ssize_t read;
+	char * pnt;
+	unsigned int sample_step = 4;
+
+	if (p >= (perfmon_base.profile_length+1)) return 0;
+	if (count > (perfmon_base.profile_length+1) - p)
+		count = (perfmon_base.profile_length+1) - p;
+	read = 0;
+
+	while (p < sizeof(unsigned int) && count > 0) {
+		put_user(*((char *)(&sample_step)+p),buf);
+		buf++; p++; count--; read++;
+	}
+	pnt = (char *)(perfmon_base.profile_buffer) + p - sizeof(unsigned int);
+	copy_to_user(buf,(void *)pnt,count);
+	read += count;
+	*ppos += read;
+	return read;
+}
+
+static ssize_t read_trace(struct file *file, char *buf,
+			    size_t count, loff_t *ppos)
+{
+	unsigned long p = *ppos;
+	ssize_t read;
+	char * pnt;
+	unsigned int sample_step = 4;
+
+	if (p >= (perfmon_base.trace_length)) return 0;
+	if (count > (perfmon_base.trace_length) - p)
+		count = (perfmon_base.trace_length) - p;
+	read = 0;
+
+	pnt = (char *)(perfmon_base.trace_buffer) + p; //  - sizeof(unsigned int);
+	copy_to_user(buf,(void *)pnt,count);
+	read += count;
+	*ppos += read;
+	return read;
+}
+
+static ssize_t write_trace(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos)
+{
+}
+
+static ssize_t write_profile(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos)
+{
+}
+
 int 
 proc_ppc64_pmc_hw_read(char *page, char **start, off_t off, 
 			     int count, int *eof, void *data)
@@ -377,6 +488,7 @@
     if (!ent) return;
     ent->nlink = 1;
     ent->data = (void *)0;
+    ent->size = 0;
     ent->read_proc = proc_get_titanTod;
     ent->write_proc = NULL;
 
@@ -838,3 +950,73 @@
 	return count;
 }
 
+static loff_t nacamap_seek( struct file *file, loff_t off, int whence)
+{
+	loff_t new;
+	struct proc_dir_entry *dp;
+
+	dp = file->f_dentry->d_inode->u.generic_ip;
+
+	switch(whence) {
+	case 0:
+		new = off;
+		break;
+	case 1:
+		new = file->f_pos + off;
+		break;
+	case 2:
+		new = dp->size + off;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if ( new < 0 || new > dp->size )
+		return -EINVAL;
+	return (file->f_pos = new);
+}
+
+static ssize_t nacamap_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos)
+{
+	unsigned pos = *ppos;
+	unsigned size;
+	char * fromaddr;
+	struct proc_dir_entry *dp;
+
+	dp = file->f_dentry->d_inode->u.generic_ip;
+
+	size = dp->size;
+	if ( pos >= size )
+		return 0;
+	if ( nbytes >= size )
+		nbytes = size;
+	if ( pos + nbytes > size )
+		nbytes = size - pos;
+	fromaddr = (char *)(KERNELBASE + 0x4000 + pos);
+
+	copy_to_user( buf, fromaddr, nbytes );
+	*ppos = pos + nbytes;
+	return nbytes;
+}
+
+static int nacamap_mmap( struct file *file, struct vm_area_struct *vma )
+{
+	unsigned long pa;
+	long size;
+	long fsize;
+	struct proc_dir_entry *dp;
+
+	dp = file->f_dentry->d_inode->u.generic_ip;
+
+	pa = 0x4000;
+	fsize = 4096;
+
+	vma->vm_flags |= VM_SHM | VM_LOCKED;
+
+	size = vma->vm_end - vma->vm_start;
+	if ( size != 4096 )
+		return -EINVAL;
+
+	remap_page_range( vma->vm_start, pa, 4096, vma->vm_page_prot );
+	return 0;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/process.c linux-2.4.20/arch/ppc64/kernel/process.c
--- linux-2.4.19/arch/ppc64/kernel/process.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/process.c	2002-10-29 11:18:34.000000000 +0000
@@ -278,87 +278,45 @@
 	current->thread.fpscr = 0;
 }
 
-asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
-			 struct pt_regs *regs)
+int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
+	      struct pt_regs *regs)
 {
-	unsigned long clone_flags = p1;
-	int res;
-
-	PPCDBG(PPCDBG_SYS64, "sys_clone - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
-	res = do_fork(clone_flags, regs->gpr[1], regs, 0);
-#ifdef CONFIG_SMP
-	/* When we clone the idle task we keep the same pid but
-	 * the return value of 0 for both causes problems.
-	 * -- Cort
-	 */
-	if ((current->pid == 0) && (current == &init_task))
-		res = 1;
-#endif /* CONFIG_SMP */
-
-	PPCDBG(PPCDBG_SYS64, "sys_clone - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
-	return res;
+	return do_fork(p1, regs->gpr[1], regs, 0);
 }
 
-asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
-			struct pt_regs *regs)
+int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
+	     struct pt_regs *regs)
 {
-	int res;
-	
-	PPCDBG(PPCDBG_SYS64, "sys_fork - entered - pid=%ld comm=%s \n", current->pid, current->comm);
-
-	res = do_fork(SIGCHLD, regs->gpr[1], regs, 0);
-
-#ifdef CONFIG_SMP
-	/* When we clone the idle task we keep the same pid but
-	 * the return value of 0 for both causes problems.
-	 * -- Cort
-	 */
-	if ((current->pid == 0) && (current == &init_task))
-		res = 1;
-#endif /* CONFIG_SMP */
-	
-	PPCDBG(PPCDBG_SYS64, "sys_fork - exited - pid=%ld comm=%s \n", current->pid, current->comm);
-
-	return res;
+	return do_fork(SIGCHLD, regs->gpr[1], regs, 0);
 }
 
-asmlinkage int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
+int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
 			 struct pt_regs *regs)
 {
-  	PPCDBG(PPCDBG_SYS64, "sys_vfork - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
 	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0);
 }
 
-asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
-			  unsigned long a3, unsigned long a4, unsigned long a5,
-			  struct pt_regs *regs)
+int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
+	       unsigned long a3, unsigned long a4, unsigned long a5,
+	       struct pt_regs *regs)
 {
 	int error;
 	char * filename;
-
-	PPCDBG(PPCDBG_SYS64, "sys_execve - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
+	
 	filename = getname((char *) a0);
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename))
 		goto out;
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
-
-	PPCDBG(PPCDBG_SYS64, "sys_execve - before do_execve : filename = %s\n", filename);
-
+  
 	error = do_execve(filename, (char **) a1, (char **) a2, regs);
-
+  
 	if (error == 0)
 		current->ptrace &= ~PT_DTRACE;
 	putname(filename);
 
-  out:
-	PPCDBG(PPCDBG_SYS64, "sys_execve - exited - pid=%ld current=%lx comm=%s error = %lx\n", current->pid, current, current->comm, error);
-
+out:
 	return error;
 }
 
@@ -405,7 +363,7 @@
 	 * __get_free_pages() might give us a page > KERNBASE+256M which
 	 * is mapped with large ptes so we can't set up the guard page.
 	 */
-	if (__is_processor(PV_POWER4))
+	if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p))
 		return;
 
 	for (i=0; i < naca->processorCount; i++) {
@@ -469,10 +427,10 @@
 
 	printk("Call backtrace: \n");
 	while (sp) {
-		if (__get_user( i, &sp[2] ))
+		if (__get_user(i, &sp[2]))
 			break;
 		printk("%016lX ", i);
-		printk("%s\n", ppc_find_proc_name( (unsigned *)i, name_buf, 256 ));
+		printk("%s\n", ppc_find_proc_name((unsigned *)i, name_buf, 256));
 		if (cnt > 32) break;
 		if (__get_user(sp, (unsigned long **)sp))
 			break;
@@ -499,7 +457,7 @@
 	do {
 		sp = *(unsigned long *)sp;
 		if (sp < (stack_page + (2 * PAGE_SIZE)) ||
-		    sp >= (stack_page + (THREAD_SIZE * PAGE_SIZE)))
+		    sp >= (stack_page + THREAD_SIZE))
 			return 0;
 		if (count > 0) {
 			ip = *(unsigned long *)(sp + 16);
@@ -524,7 +482,7 @@
 	do {
 		sp = *(unsigned long *)sp;
 		if (sp < (stack_page + (2 * PAGE_SIZE)) ||
-		    sp >= (stack_page + (THREAD_SIZE * PAGE_SIZE)))
+		    sp >= (stack_page + THREAD_SIZE))
 			break;
 		if (count > 0) {
 			ip = *(unsigned long *)(sp + 16);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/prom.c linux-2.4.20/arch/ppc64/kernel/prom.c
--- linux-2.4.19/arch/ppc64/kernel/prom.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/prom.c	2002-10-29 11:18:50.000000000 +0000
@@ -1,4 +1,4 @@
-/*
+/* - undefined for user space
  * 
  *
  * Procedures for interfacing to Open Firmware.
@@ -217,7 +217,10 @@
 
 void cacheable_memzero(void *, unsigned int);
 
-extern char cmd_line[512];	/* XXX */
+#ifndef CONFIG_CMDLINE
+#define CONFIG_CMDLINE ""
+#endif
+char cmd_line[512] = CONFIG_CMDLINE;
 unsigned long dev_tree_size;
 
 #ifdef CONFIG_HMT
@@ -340,6 +343,7 @@
 	struct prom_t *_prom = PTRRELOC(&prom);
         struct naca_struct *_naca = RELOC(naca);
 
+	/* NOTE: _naca->debug_switch is already initialized. */
 #ifdef DEBUG_PROM
 	prom_print(RELOC("prom_initialize_naca: start...\n"));
 #endif
@@ -358,23 +362,43 @@
 			 * d-cache and i-cache sizes... -Peter
 			 */
 			if ( num_cpus == 1 ) {
-				u32 size;
+				u32 size, lsize, sets;
 
 				call_prom(RELOC("getprop"), 4, 1, node,
-					  RELOC("d-cache-line-size"),
+					  RELOC("d-cache-size"),
 					  &size, sizeof(size));
 
-				_naca->dCacheL1LineSize     = size;
-				_naca->dCacheL1LogLineSize  = __ilog2(size);
-				_naca->dCacheL1LinesPerPage = PAGE_SIZE / size;
+				call_prom(RELOC("getprop"), 4, 1, node,
+					  RELOC("d-cache-line-size"),
+					  &lsize, sizeof(lsize));
+
+				call_prom(RELOC("getprop"), 4, 1, node,
+					  RELOC("d-cache-sets"),
+					  &sets, sizeof(sets));
+
+				_naca->dCacheL1Size         = size;
+				_naca->dCacheL1LineSize     = lsize;
+				_naca->dCacheL1LogLineSize  = __ilog2(lsize);
+				_naca->dCacheL1LinesPerPage = PAGE_SIZE/lsize;
+				_naca->dCacheL1Assoc = size / lsize / sets;
 
 				call_prom(RELOC("getprop"), 4, 1, node,
 					  RELOC("i-cache-line-size"),
 					  &size, sizeof(size));
 
-				_naca->iCacheL1LineSize     = size;
-				_naca->iCacheL1LogLineSize  = __ilog2(size);
-				_naca->iCacheL1LinesPerPage = PAGE_SIZE / size;
+				call_prom(RELOC("getprop"), 4, 1, node,
+					  RELOC("i-cache-line-size"),
+					  &lsize, sizeof(lsize));
+
+				call_prom(RELOC("getprop"), 4, 1, node,
+					  RELOC("i-cache-sets"),
+					  &sets, sizeof(sets));
+
+				_naca->iCacheL1Size         = size;
+				_naca->iCacheL1LineSize     = lsize;
+				_naca->iCacheL1LogLineSize  = __ilog2(lsize);
+				_naca->iCacheL1LinesPerPage = PAGE_SIZE/lsize;
+				_naca->iCacheL1Assoc = size / lsize / sets;
 
 				if (_naca->platform == PLATFORM_PSERIES_LPAR) {
 					u32 pft_size[2];
@@ -477,6 +501,11 @@
 	 */
 	_naca->slb_size = 64;
 
+	/* Add an eye catcher and the naca layout version number */
+	strcpy(_naca->eye_catcher, RELOC("PPC64"));
+	_naca->version     = 1;
+	_naca->processor   = _get_PVR() >> 16;
+
 #ifdef DEBUG_PROM
         prom_print(RELOC("naca->processorCount       = 0x"));
         prom_print_hex(_naca->processorCount);
@@ -620,8 +649,8 @@
 }
 
 
-static unsigned long __init
-prom_instantiate_rtas(unsigned long mem)
+static void __init
+prom_instantiate_rtas(void)
 {
 	unsigned long offset = reloc_offset();
 	struct prom_t *_prom = PTRRELOC(&prom);
@@ -654,16 +683,18 @@
 	        _rtas->size = getprop_rval;
 		prom_print(RELOC("instantiating rtas"));
 		if (_rtas->size != 0) {
-			/*
-			 * Ask OF for some space for RTAS.
-			 * Actually OF has bugs so we just arbitrarily
-			 * use memory at the 6MB point.
+			unsigned long rtas_region = RTAS_INSTANTIATE_MAX;
+
+			/* Grab some space within the first RTAS_INSTANTIATE_MAX bytes
+			 * of physical memory (or within the RMO region) because RTAS
+			 * runs in 32-bit mode and relocate off.
 			 */
-			// The new code...
-			mem = PAGE_ALIGN(mem);
-			_rtas->base = mem + offset - KERNELBASE;
+			if ( _naca->platform == PLATFORM_PSERIES_LPAR ) {
+				struct lmb *_lmb  = PTRRELOC(&lmb);
+				rtas_region = min(_lmb->rmo_size, RTAS_INSTANTIATE_MAX);
+			}
+			_rtas->base = lmb_alloc_base(_rtas->size, PAGE_SIZE, rtas_region);
 
-			mem += _rtas->size;
 			prom_print(RELOC(" at 0x"));
 			prom_print_hex(_rtas->base);
 
@@ -700,8 +731,6 @@
 #ifdef DEBUG_PROM
 	prom_print(RELOC("prom_instantiate_rtas: end...\n"));
 #endif
-
-	return mem;
 }
 
 unsigned long prom_strtoul(const char *cp)
@@ -912,8 +941,6 @@
 			    (strstr(model, RELOC("peedwagon")) == NULL) &&
 			    (strstr(model, RELOC("innipeg")) == NULL))
 				continue;
-		} else {
-			prom_print(RELOC("No known I/O bridge chip found.\n"));
 		}
 
 		if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) {
@@ -1231,6 +1258,110 @@
 #endif
 }
 
+#ifdef CONFIG_PPCDBG
+extern char *trace_names[];	/* defined in udbg.c -- need a better interface */
+
+static void parse_ppcdbg_optionlist(const char *cmd,
+				    const char *cmdend)
+{
+	unsigned long offset = reloc_offset();
+	char **_trace_names = PTRRELOC(&trace_names[0]);
+	const char *all = RELOC("all");
+        struct naca_struct *_naca = RELOC(naca);
+	const char *p, *pend;
+	int onoff, i, cmdidx;
+	unsigned long mask;
+	char cmdbuf[30];
+
+	for (p = cmd, pend = strchr(p, ',');
+	     p < cmdend;
+	     pend = strchr(p, ',')) {
+		if (pend == NULL || pend > cmdend)
+			pend = cmdend;
+		onoff = 1;	/* default */
+		if (*p == '+' || *p == '-') {
+			/* explicit on or off */
+			onoff = (*p == '+');
+			p++;
+		}
+		/* parse out p..pend here */
+		if (pend - p < sizeof(cmdbuf)) {
+			strncpy(cmdbuf, p, pend - p);
+			cmdbuf[pend - p] = '\0';
+			for (cmdidx = -1, i = 0; i < PPCDBG_NUM_FLAGS; i++) {
+				if (_trace_names[i] &&
+				    (strcmp(PTRRELOC(_trace_names[i]), cmdbuf) == 0)) {
+					cmdidx = i;
+					break;
+				}
+			}
+			mask = 0;
+			if (cmdidx >= 0) {
+				mask = (1 << cmdidx);
+			} else if (strcmp(cmdbuf, all) == 0) {
+				mask = PPCDBG_ALL;
+			} else {
+				prom_print(RELOC("ppcdbg: unknown debug: "));
+				prom_print(cmdbuf);
+				prom_print_nl();
+			}
+			if (mask) {
+				if (onoff)
+					_naca->debug_switch |= mask;
+				else
+					_naca->debug_switch &= ~mask;
+			}
+		}
+		p = pend+1;
+	}
+}
+
+/*
+ * Parse ppcdbg= cmdline option.
+ *
+ * Option names are listed in <asm/ppcdebug.h> in the trace_names
+ * table.  Multiple names may be listed separated by commas (no whitespace),
+ * and each option may be preceeded by a + or - to force on or off state.
+ * The special option "all" may also be used.  They are processed strictly
+ * left to right.  Multiple ppcdbg= options are the command line are treated
+ * as a single option list.
+ *
+ * Examples:  ppcdbg=phb_init,buswalk
+ *            ppcdbg=all,-mm,-tce
+ *
+ * ToDo: add "group" names that map to common combinations of flags.
+ */
+void parse_ppcdbg_cmd_line(const char *line)
+{
+	unsigned long offset = reloc_offset();
+	const char *ppcdbgopt = RELOC("ppcdbg=");
+	struct naca_struct *_naca = RELOC(naca);
+	const char *cmd, *end;
+
+	_naca->debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */
+	cmd = line;
+	while (cmd && (cmd = strstr(cmd, ppcdbgopt)) != NULL) {
+		cmd += 7;	/* skip ppcdbg= */
+		for (end = cmd;
+		     *end != '\0' && *end != '\t' && *end != ' ';
+		     end++)
+			; /* scan to whitespace or end */
+		parse_ppcdbg_optionlist(cmd, end);
+	}
+}
+#endif /* CONFIG_PPCDBG */
+
+
+/*
+ * Do minimal cmd_line parsing for early boot options.
+ */
+static void __init
+prom_parse_cmd_line(char *line)
+{
+#ifdef CONFIG_PPCDBG
+	parse_ppcdbg_cmd_line(line);
+#endif
+}
 
 /*
  * We enter here early on, when the Open Firmware prom is still
@@ -1246,13 +1377,14 @@
 	ihandle prom_mmu, prom_op, prom_root, prom_cpu;
 	phandle cpu_pkg;
 	unsigned long offset = reloc_offset();
-	long l;
+	long l, sz;
 	char *p, *d;
  	unsigned long phys;
         u32 getprop_rval;
         struct naca_struct   *_naca = RELOC(naca);
 	struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
 	struct prom_t *_prom = PTRRELOC(&prom);
+	char *_cmd_line = PTRRELOC(&cmd_line[0]);
 
 	/* Default machine type. */
 	_naca->platform = PLATFORM_PSERIES;
@@ -1337,6 +1469,15 @@
 	}
 	_prom->encode_phys_size = (getprop_rval==1) ? 32 : 64;
 
+	/* Fetch the cmd_line */
+	sz = (long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen,
+			    RELOC("bootargs"), _cmd_line,
+			    sizeof(cmd_line)-1);
+	if (sz > 0)
+		_cmd_line[sz] = '\0';
+
+	prom_parse_cmd_line(_cmd_line);
+
 #ifdef DEBUG_PROM
 	prom_print(RELOC("DRENG:    Detect OF version...\n"));
 #endif
@@ -1344,7 +1485,6 @@
 	prom_op = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/openprom"));
 	if (prom_op != (ihandle)-1) {
 		char model[64];
-		long sz;
 		sz = (long)call_prom(RELOC("getprop"), 4, 1, prom_op,
 				    RELOC("model"), model, 64);
 		if (sz > 0) {
@@ -1404,7 +1544,7 @@
 
 	mem = prom_bi_rec_reserve(mem);
 
-	mem = prom_instantiate_rtas(mem);
+	prom_instantiate_rtas();
         
         /* Initialize some system info into the Naca early... */
         mem = prom_initialize_naca(mem);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/ptrace.c linux-2.4.20/arch/ppc64/kernel/ptrace.c
--- linux-2.4.19/arch/ppc64/kernel/ptrace.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/ptrace.c	2002-10-29 11:18:48.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/ppc/kernel/ptrace.c
+ *  linux/arch/ppc64/kernel/ptrace.c
  *
  *  PowerPC version
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -126,14 +126,9 @@
 		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
-	ret = -ESRCH;
-	if (!(child->ptrace & PT_PTRACED))
-		goto out_tsk;
-	if (child->state != TASK_STOPPED) {
-		if (request != PTRACE_KILL)
-			goto out_tsk;
-	}
-	if (child->p_pptr != current)
+
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0)
 		goto out_tsk;
 
 	switch (request) {
@@ -153,16 +148,17 @@
 
 	/* read the word at location addr in the USER area. */
 	case PTRACE_PEEKUSR: {
-		unsigned long index, tmp;
+		unsigned long index;
+		unsigned long tmp;
 
 		ret = -EIO;
 		/* convert to index and check */
 		index = (unsigned long) addr >> 3;
-		if ((addr & 7) || index > PT_FPSCR)
+		if ((addr & 7) || (index > PT_FPSCR))
 			break;
 
 		if (index < PT_FPR0) {
-			tmp = get_reg(child, (int) index);
+			tmp = get_reg(child, (int)index);
 		} else {
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
@@ -176,7 +172,8 @@
 	case PTRACE_POKETEXT: /* write the word at location addr. */
 	case PTRACE_POKEDATA:
 		ret = 0;
-		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+		if (access_process_vm(child, addr, &data, sizeof(data), 1)
+				== sizeof(data))
 			break;
 		ret = -EIO;
 		break;
@@ -188,7 +185,7 @@
 		ret = -EIO;
 		/* convert to index and check */
 		index = (unsigned long) addr >> 3;
-		if ((addr & 7) || index > PT_FPSCR)
+		if ((addr & 7) || (index > PT_FPSCR))
 			break;
 
 		if (index == PT_ORIG_R3)
@@ -221,11 +218,11 @@
 		break;
 	}
 
-/*
- * make the child exit.  Best I can do is send it a sigkill. 
- * perhaps it should be put in the status that it wants to 
- * exit.
- */
+	/*
+	 * make the child exit.  Best I can do is send it a sigkill.
+	 * perhaps it should be put in the status that it wants to
+	 * exit.
+	 */
 	case PTRACE_KILL: {
 		ret = 0;
 		if (child->state == TASK_ZOMBIE)	/* already dead */
@@ -254,56 +251,50 @@
 		ret = ptrace_detach(child, data);
 		break;
 
-	case PPC_PTRACE_GETREGS:
-	{ /* Get GPRs 0 - 31. */
+	case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
 		u64 tmp;
 		u64 cntr;
+
 		ret = 0; 
-		for (cntr=0; cntr<32 && ret==0; ++cntr)
-		{
+		for (cntr=0; cntr<32 && ret==0; ++cntr) {
 			tmp = ((u64*)child->thread.regs)[cntr];
 			ret = put_user(tmp, (u64*)(data+cntr));
 		}
 		break;
 	}
 
-	case PPC_PTRACE_SETREGS:
-	{ /* Set GPRs 0 - 31. */
+	case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
 		u64 cntr;
+
 		ret = 0; 
 		for (cntr=0; cntr<32 && ret==0; ++cntr)
-		{
 			ret = put_reg(child, cntr, *(u64*)(data+cntr));
-		}
 		break;
 	}
 
-	case PPC_PTRACE_GETFPREGS:
-	{ /* Get FPRs 0 - 31. */
+	case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
 		u64 tmp;
 		u64 cntr;
+
 		ret = -EIO;
 		if (child->thread.regs->msr & MSR_FP)
 			giveup_fpu(child);
 		ret = 0; 
-		for (cntr=0; cntr<32 && ret==0; ++cntr)
-		{
+		for (cntr=0; cntr<32 && ret==0; ++cntr) {
 			tmp = ((u64*)child->thread.fpr)[cntr];
 			ret = put_user(tmp, (u64*)(data+cntr));
 		}
 		break;
 	}
 
-	case PPC_PTRACE_SETFPREGS:
-	{ /* Get FPRs 0 - 31. */
+	case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
 		u64 cntr;
+
 		ret = -EIO;
 		if (child->thread.regs->msr & MSR_FP)
 			giveup_fpu(child);
 		for (cntr=0; cntr<32; ++cntr)
-		{
 			((u64*)child->thread.fpr)[cntr] = *(u64*)(data+cntr);
-		}
 		ret = 0; 
 		break;
 	}
@@ -338,4 +329,3 @@
 		current->exit_code = 0;
 	}
 }
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/ptrace32.c linux-2.4.20/arch/ppc64/kernel/ptrace32.c
--- linux-2.4.19/arch/ppc64/kernel/ptrace32.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/ptrace32.c	2002-10-29 11:18:48.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/ppc/kernel/ptrace32.c
+ *  linux/arch/ppc64/kernel/ptrace32.c
  *
  *  PowerPC version
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -86,8 +86,8 @@
 int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data)
 {
 	struct task_struct *child;
-	int ret  = -EPERM;
-  
+	int ret = -EPERM;
+
 	lock_kernel();
 	if (request == PTRACE_TRACEME) {
 		/* are we already being traced? */
@@ -115,18 +115,12 @@
 		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
-	ret = -ESRCH;
-	if (!(child->ptrace & PT_PTRACED))
-		goto out_tsk;
-	if (child->state != TASK_STOPPED) {
-		if (request != PTRACE_KILL)
-			goto out_tsk;
-	}
-	if (child->p_pptr != current)
+
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0)
 		goto out_tsk;
 
-	switch (request)
-	{
+	switch (request) {
 	/* Read word at location ADDR */
 	/* when I and D space are separate, these will need to be fixed. */
 	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
@@ -143,11 +137,15 @@
 		break;
 	}
 
-	/* Read 4 bytes of the other process' storage */
-	/*  data is a pointer specifying where the user wants the 4 bytes copied into */
-	/*  addr is a pointer in the user's storage that contains an 8 byte address in the other process of the 4 bytes that is to be read */
-	/* (this is run in a 32-bit process looking at a 64-bit process) */
-	/* when I and D space are separate, these will need to be fixed. */
+	/*
+	 * Read 4 bytes of the other process' storage
+	 *  data is a pointer specifying where the user wants the
+	 *	4 bytes copied into
+	 *  addr is a pointer in the user's storage that contains an 8 byte
+	 *	address in the other process of the 4 bytes that is to be read
+	 * (this is run in a 32-bit process looking at a 64-bit process)
+	 * when I and D space are separate, these will need to be fixed.
+	 */
 	case PPC_PTRACE_PEEKTEXT_3264:
 	case PPC_PTRACE_PEEKDATA_3264: 
 	{
@@ -158,7 +156,7 @@
 		ret = -EIO;
 
 		/* Get the addr in the other process that we want to read */
-		if (get_user(addrOthers,(u32**)addr) != 0)
+		if (get_user(addrOthers, (u32**)addr) != 0)
 			break;
 
 		copied = access_process_vm(child, (u64)addrOthers, &tmp_mem_value, sizeof(tmp_mem_value), 0);
@@ -177,7 +175,7 @@
 		ret = -EIO;
 		/* convert to index and check */
 		index = (unsigned long) addr >> 2;
-		if ((addr & 3) || index > PT_FPSCR32)
+		if ((addr & 3) || (index > PT_FPSCR32))
 			break;
 
 		if (index < PT_FPR0) {
@@ -185,9 +183,10 @@
 		} else {
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
-			/* the user space code considers the floating point to be 
-			 *   an array of unsigned int (32 bits) - the index passed 
-			 *   in is based on this assumption.
+			/*
+			 * the user space code considers the floating point
+			 * to be an array of unsigned int (32 bits) - the
+			 * index passed in is based on this assumption.
 			 */
 			tmp_reg_value = ((unsigned int *)child->thread.fpr)[index - PT_FPR0];
 		}
@@ -196,12 +195,15 @@
 		break;
 	}
   
-	/* Read 4 bytes out of the other process' pt_regs area */
-	/*  data is a pointer specifying where the user wants the 4 bytes copied into */
-	/*  addr is the offset into the other process' pt_regs structure that is to be read */
-	/* (this is run in a 32-bit process looking at a 64-bit process) */
-	case PPC_PTRACE_PEEKUSR_3264:
-	{
+	/*
+	 * Read 4 bytes out of the other process' pt_regs area
+	 *  data is a pointer specifying where the user wants the
+	 *	4 bytes copied into
+	 *  addr is the offset into the other process' pt_regs structure
+	 *	that is to be read
+	 * (this is run in a 32-bit process looking at a 64-bit process)
+	 */
+	case PPC_PTRACE_PEEKUSR_3264: {
 		u32 index;
 		u32 reg32bits;
 		u64 tmp_reg_value;
@@ -222,8 +224,7 @@
 		if ((addr & 3) || numReg > PT_FPSCR)
 			break;
 
-		if (numReg >= PT_FPR0)
-		{
+		if (numReg >= PT_FPR0) {
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
 		        if (numReg == PT_FPSCR) 
@@ -251,11 +252,15 @@
 		break;
 	}
 
-	/* Write 4 bytes into the other process' storage */
-	/*  data is the 4 bytes that the user wants written */
-	/*  addr is a pointer in the user's storage that contains an 8 byte address in the other process where the 4 bytes that is to be written */
-	/* (this is run in a 32-bit process looking at a 64-bit process) */
-	/* when I and D space are separate, these will need to be fixed. */
+	/*
+	 * Write 4 bytes into the other process' storage
+	 *  data is the 4 bytes that the user wants written
+	 *  addr is a pointer in the user's storage that contains an
+	 *	8 byte address in the other process where the 4 bytes
+	 *	that is to be written
+	 * (this is run in a 32-bit process looking at a 64-bit process)
+	 * when I and D space are separate, these will need to be fixed.
+	 */
 	case PPC_PTRACE_POKETEXT_3264:
 	case PPC_PTRACE_POKEDATA_3264:
 	{
@@ -267,7 +272,6 @@
 		ret = -EIO;
 		if (get_user(addrOthers,(u32**)addr) != 0)
 			break;
-
 		ret = 0;
 		bytesWritten = access_process_vm(child, (u64)addrOthers, &tmp_value_to_write, sizeof(tmp_value_to_write), 1);
 		if (bytesWritten == sizeof(tmp_value_to_write))
@@ -281,63 +285,61 @@
 		unsigned long index;
 
 		ret = -EIO;
-
 		/* convert to index and check */
 		index = (unsigned long) addr >> 2;
-		if ((addr & 3) || index > PT_FPSCR32)
+		if ((addr & 3) || (index > PT_FPSCR32))
 			break;
 
 		if (index == PT_ORIG_R3)
 			break;
-
-
 		if (index < PT_FPR0) {
 			ret = put_reg(child, index, data);
 		} else {
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
-      /* the user space code considers the floating point to be 
-       *   an array of unsigned int (32 bits) - the index passed 
-       *   in is based on this assumption.
-       */
-
+			/*
+			 * the user space code considers the floating point
+			 * to be an array of unsigned int (32 bits) - the
+			 * index passed in is based on this assumption.
+			 */
 			((unsigned int *)child->thread.fpr)[index - PT_FPR0] = data;
 			ret = 0;
 		}
 		break;
 	}
 
-	/* Write 4 bytes into the other process' pt_regs area */
-	/*  data is the 4 bytes that the user wants written */
-	/*  addr is the offset into the other process' pt_regs structure that is to be written into */
-	/* (this is run in a 32-bit process looking at a 64-bit process) */
-	case PPC_PTRACE_POKEUSR_3264:
-	{
+	/*
+	 * Write 4 bytes into the other process' pt_regs area
+	 *  data is the 4 bytes that the user wants written
+	 *  addr is the offset into the other process' pt_regs structure
+	 *	that is to be written into
+	 * (this is run in a 32-bit process looking at a 64-bit process)
+	 */
+	case PPC_PTRACE_POKEUSR_3264: {
 		u32 index;
 		u32 numReg;
 
 		ret = -EIO;
-
 		/* Determine which register the user wants */
 		index = (u64)addr >> 2;  /* Divide addr by 4 */
 		numReg = index / 2;
-
-		/* Validate the input - check to see if address is on the wrong boundary or beyond the end of the user area */
-		if ((addr & 3) || numReg > PT_FPSCR)
+		/*
+		 * Validate the input - check to see if address is on the
+		 * wrong boundary or beyond the end of the user area
+		 */
+		if ((addr & 3) || (numReg > PT_FPSCR))
 			break;
 		/* Insure it is a register we let them change */
-		if ((numReg == PT_ORIG_R3) || ((numReg > PT_CCR) && (numReg < PT_FPR0)))
+		if ((numReg == PT_ORIG_R3)
+				|| ((numReg > PT_CCR) && (numReg < PT_FPR0)))
 			break;
-
-		if (numReg >= PT_FPR0)
-		{
+		if (numReg >= PT_FPR0) {
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
 		}
-
 		if (numReg == PT_MSR)
-			data = (data & MSR_DEBUGCHANGE) | (child->thread.regs->msr & ~MSR_DEBUGCHANGE);
-
+			data = (data & MSR_DEBUGCHANGE)
+				| (child->thread.regs->msr & ~MSR_DEBUGCHANGE);
 		((u32*)child->thread.regs)[index] = data;
 		ret = 0;
 		break;
@@ -361,8 +363,8 @@
 	}
 
 	/*
-	 * make the child exit.  Best I can do is send it a sigkill. 
-	 * perhaps it should be put in the status that it wants to 
+	 * make the child exit.  Best I can do is send it a sigkill.
+	 * perhaps it should be put in the status that it wants to
 	 * exit.
 	 */
 	case PTRACE_KILL: {
@@ -403,4 +405,3 @@
 	unlock_kernel();
 	return ret;
 }
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/rtas.c linux-2.4.20/arch/ppc64/kernel/rtas.c
--- linux-2.4.19/arch/ppc64/kernel/rtas.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/rtas.c	2002-10-29 11:18:47.000000000 +0000
@@ -15,6 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/spinlock.h>
+#include <linux/fs.h>
 
 #include <asm/init.h>
 #include <asm/prom.h>
@@ -24,8 +25,12 @@
 #include <asm/paca.h>
 #include <asm/page.h>
 #include <asm/system.h>
+#include <asm/abs_addr.h>
 #include <asm/udbg.h>
 
+struct proc_dir_entry *rtas_proc_dir;	/* /proc/ppc64/rtas dir */
+struct flash_block_list_header rtas_firmware_flash_list = {0, 0};
+
 /*
  * prom_init() is called very early on, before the kernel text
  * and data have been mapped to KERNELBASE.  At this point the code
@@ -103,18 +108,13 @@
 	enter_rtas((void *)__pa((unsigned long)rtas));	
 }
 
-#if 0
-#define DEBUG_RTAS
-#endif
 __openfirmware
 int
 rtas_token(const char *service)
 {
 	int *tokp;
 	if (rtas.dev == NULL) {
-#ifdef DEBUG_RTAS
-		udbg_printf("\tNo rtas device in device-tree...\n");
-#endif /* DEBUG_RTAS */
+		PPCDBG(PPCDBG_RTAS,"\tNo rtas device in device-tree...\n");
 		return RTAS_UNKNOWN_SERVICE;
 	}
 	tokp = (int *) get_property(rtas.dev, service, NULL);
@@ -131,13 +131,11 @@
 	unsigned long s;
 	struct rtas_args *rtas_args = &(get_paca()->xRtas);
 
-#ifdef DEBUG_RTAS
-	udbg_printf("Entering rtas_call\n");
-	udbg_printf("\ttoken    = 0x%x\n", token);
-	udbg_printf("\tnargs    = %d\n", nargs);
-	udbg_printf("\tnret     = %d\n", nret);
-	udbg_printf("\t&outputs = 0x%lx\n", outputs);
-#endif /* DEBUG_RTAS */
+	PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n");
+	PPCDBG(PPCDBG_RTAS, "\ttoken    = 0x%x\n", token);
+	PPCDBG(PPCDBG_RTAS, "\tnargs    = %d\n", nargs);
+	PPCDBG(PPCDBG_RTAS, "\tnret     = %d\n", nret);
+	PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs);
 	if (token == RTAS_UNKNOWN_SERVICE)
 		return -1;
 
@@ -147,10 +145,8 @@
 	rtas_args->rets  = (rtas_arg_t *)&(rtas_args->args[nargs]);
 	va_start(list, outputs);
 	for (i = 0; i < nargs; ++i) {
-	  rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong));
-#ifdef DEBUG_RTAS
-	  udbg_printf("\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]);
-#endif /* DEBUG_RTAS */
+		rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong));
+		PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]);
 	}
 	va_end(list);
 
@@ -162,22 +158,19 @@
 #else
 	spin_lock_irqsave(&rtas.lock, s);
 #endif
-#ifdef DEBUG_RTAS
-	udbg_printf("\tentering rtas with 0x%lx\n", (void *)__pa((unsigned long)rtas_args));
-#endif /* DEBUG_RTAS */
+	PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n",
+		(void *)__pa((unsigned long)rtas_args));
 	enter_rtas((void *)__pa((unsigned long)rtas_args));
-#ifdef DEBUG_RTAS
-	udbg_printf("\treturned from rtas ...\n");
-#endif /* DEBUG_RTAS */
+	PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n");
 #if 0   /* Gotta do something different here, use global lock for now... */
 	spin_unlock_irqrestore(&rtas_args->lock, s);
 #else
 	spin_unlock_irqrestore(&rtas.lock, s);
 #endif
-#ifdef DEBUG_RTAS
-	for(i=0; i < nret ;i++)
-	  udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]);
-#endif /* DEBUG_RTAS */
+	ifppcdebug(PPCDBG_RTAS) {
+		for(i=0; i < nret ;i++)
+			udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]);
+	}
 
 	if (nret > 1 && outputs != NULL)
 		for (i = 0; i < nret-1; ++i)
@@ -185,9 +178,87 @@
 	return (ulong)((nret > 0) ? rtas_args->rets[0] : 0);
 }
 
+#define FLASH_BLOCK_LIST_VERSION (1UL)
+static void
+rtas_flash_firmware(void)
+{
+	unsigned long image_size;
+	struct flash_block_list *f, *next, *flist;
+	unsigned long rtas_block_list;
+	int i, status, update_token;
+
+	update_token = rtas_token("ibm,update-flash-64-and-reboot");
+	if (update_token == RTAS_UNKNOWN_SERVICE) {
+		printk(KERN_ALERT "FLASH: ibm,update-flash-64-and-reboot is not available -- not a service partition?\n");
+		printk(KERN_ALERT "FLASH: firmware will not be flashed\n");
+		return;
+	}
+
+	/* NOTE: the "first" block list is a global var with no data
+	 * blocks in the kernel data segment.  We do this because
+	 * we want to ensure this block_list addr is under 4GB.
+	 */
+	rtas_firmware_flash_list.num_blocks = 0;
+	flist = (struct flash_block_list *)&rtas_firmware_flash_list;
+	rtas_block_list = virt_to_absolute((unsigned long)flist);
+	if (rtas_block_list >= (4UL << 20)) {
+		printk(KERN_ALERT "FLASH: kernel bug...flash list header addr above 4GB\n");
+		return;
+	}
+
+	printk(KERN_ALERT "FLASH: preparing saved firmware image for flash\n");
+	/* Update the block_list in place. */
+	image_size = 0;
+	for (f = flist; f; f = next) {
+		/* Translate data addrs to absolute */
+		for (i = 0; i < f->num_blocks; i++) {
+			f->blocks[i].data = (char *)virt_to_absolute((unsigned long)f->blocks[i].data);
+			image_size += f->blocks[i].length;
+		}
+		next = f->next;
+		f->next = (struct flash_block_list *)virt_to_absolute((unsigned long)f->next);
+		/* make num_blocks into the version/length field */
+		f->num_blocks = (FLASH_BLOCK_LIST_VERSION << 56) | ((f->num_blocks+1)*16);
+	}
+
+	printk(KERN_ALERT "FLASH: flash image is %ld bytes\n", image_size);
+	printk(KERN_ALERT "FLASH: performing flash and reboot\n");
+	ppc_md.progress("Flashing        \n", 0x0);
+	ppc_md.progress("Please Wait...  ", 0x0);
+	printk(KERN_ALERT "FLASH: this will take several minutes.  Do not power off!\n");
+	status = rtas_call(update_token, 1, 1, NULL, rtas_block_list);
+	switch (status) {	/* should only get "bad" status */
+	    case 0:
+		printk(KERN_ALERT "FLASH: success\n");
+		break;
+	    case -1:
+		printk(KERN_ALERT "FLASH: hardware error.  Firmware may not be not flashed\n");
+		break;
+	    case -3:
+		printk(KERN_ALERT "FLASH: image is corrupt or not correct for this platform.  Firmware not flashed\n");
+		break;
+	    case -4:
+		printk(KERN_ALERT "FLASH: flash failed when partially complete.  System may not reboot\n");
+		break;
+	    default:
+		printk(KERN_ALERT "FLASH: unknown flash return code %d\n", status);
+		break;
+	}
+}
+
+void rtas_flash_bypass_warning(void)
+{
+	printk(KERN_ALERT "FLASH: firmware flash requires a reboot\n");
+	printk(KERN_ALERT "FLASH: the firmware image will NOT be flashed\n");
+}
+
+
 void __chrp
 rtas_restart(char *cmd)
 {
+	if (rtas_firmware_flash_list.next)
+		rtas_flash_firmware();
+
         printk("RTAS system-reboot returned %ld\n",
 	       rtas_call(rtas_token("system-reboot"), 0, 1, NULL));
         for (;;);
@@ -196,6 +267,8 @@
 void __chrp
 rtas_power_off(void)
 {
+	if (rtas_firmware_flash_list.next)
+		rtas_flash_bypass_warning();
         /* allow power on only with power button press */
         printk("RTAS power-off returned %ld\n",
                rtas_call(rtas_token("power-off"), 2, 1, NULL,0xffffffff,0xffffffff));
@@ -205,5 +278,7 @@
 void __chrp
 rtas_halt(void)
 {
+	if (rtas_firmware_flash_list.next)
+		rtas_flash_bypass_warning();
         rtas_power_off();
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/rtas_flash.c linux-2.4.20/arch/ppc64/kernel/rtas_flash.c
--- linux-2.4.19/arch/ppc64/kernel/rtas_flash.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/rtas_flash.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,240 @@
+/*
+ *  c 2001 PPC 64 Team, IBM Corp
+ *
+ *      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.
+ *
+ * /proc/ppc64/rtas/firmware_flash interface
+ *
+ * This file implements a firmware_flash interface to pump a firmware
+ * image into the kernel.  At reboot time rtas_restart() will see the
+ * firmware image and flash it as it reboots (see rtas.c).
+ */
+
+#include <linux/module.h>
+
+#include <linux/config.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/rtas.h>
+
+#define MODULE_VERSION "1.0"
+#define MODULE_NAME "rtas_flash"
+
+#define FIRMWARE_FLASH_NAME "firmware_flash"
+
+/* Local copy of the flash block list.
+ * We only allow one open of the flash proc file and create this
+ * list as we go.  This list will be put in the kernel's
+ * rtas_firmware_flash_list global var once it is fully read.
+ *
+ * For convenience as we build the list we use virtual addrs,
+ * we do not fill in the version number, and the length field
+ * is treated as the number of entries currently in the block
+ * (i.e. not a byte count).  This is all fixed on release.
+ */
+static struct flash_block_list *flist;
+static char *flash_msg;
+static int flash_possible;
+
+static int rtas_flash_open(struct inode *inode, struct file *file)
+{
+	if ((file->f_mode & FMODE_WRITE) && flash_possible) {
+		if (flist)
+			return -EBUSY;
+		flist = (struct flash_block_list *)get_free_page(GFP_KERNEL);
+		if (!flist)
+			return -ENOMEM;
+	}
+	return 0;
+}
+
+/* Do simple sanity checks on the flash image. */
+static int flash_list_valid(struct flash_block_list *flist)
+{
+	struct flash_block_list *f;
+	int i;
+	unsigned long block_size, image_size;
+
+	flash_msg = NULL;
+	/* Paranoid self test here.  We also collect the image size. */
+	image_size = 0;
+	for (f = flist; f; f = f->next) {
+		for (i = 0; i < f->num_blocks; i++) {
+			if (f->blocks[i].data == NULL) {
+				flash_msg = "error: internal error null data\n";
+				return 0;
+			}
+			block_size = f->blocks[i].length;
+			if (block_size <= 0 || block_size > PAGE_SIZE) {
+				flash_msg = "error: internal error bad length\n";
+				return 0;
+			}
+			image_size += block_size;
+		}
+	}
+	if (image_size < (256 << 10)) {
+		if (image_size < 2)
+			flash_msg = NULL;	/* allow "clear" of image */
+		else
+			flash_msg = "error: flash image short\n";
+		return 0;
+	}
+	printk(KERN_INFO "FLASH: flash image with %ld bytes stored for hardware flash on reboot\n", image_size);
+	return 1;
+}
+
+static void free_flash_list(struct flash_block_list *f)
+{
+	struct flash_block_list *next;
+	int i;
+
+	while (f) {
+		for (i = 0; i < f->num_blocks; i++)
+			free_page((unsigned long)(f->blocks[i].data));
+		next = f->next;
+		free_page((unsigned long)f);
+		f = next;
+	}
+}
+
+static int rtas_flash_release(struct inode *inode, struct file *file)
+{
+	if (flist) {
+		/* Always clear saved list on a new attempt. */
+		if (rtas_firmware_flash_list.next) {
+			free_flash_list(rtas_firmware_flash_list.next);
+			rtas_firmware_flash_list.next = NULL;
+		}
+
+		if (flash_list_valid(flist))
+			rtas_firmware_flash_list.next = flist;
+		else
+			free_flash_list(flist);
+		flist = NULL;
+	}
+	return 0;
+}
+
+/* Reading the proc file will show status (not the firmware contents) */
+static ssize_t rtas_flash_read(struct file *file, char *buf,
+			       size_t count, loff_t *ppos)
+{
+	int error;
+	char *msg;
+	int msglen;
+
+	if (!flash_possible) {
+		msg = "error: this partition does not have service authority\n";
+	} else if (flist) {
+		msg = "info: this file is busy for write by some process\n";
+	} else if (flash_msg) {
+		msg = flash_msg;	/* message from last flash attempt */
+	} else if (rtas_firmware_flash_list.next) {
+		msg = "ready: firmware image ready for flash on reboot\n";
+	} else {
+		msg = "info: no firmware image for flash\n";
+	}
+	msglen = strlen(msg);
+	if (msglen > count)
+		msglen = count;
+
+	if (ppos && *ppos != 0)
+		return 0;	/* be cheap */
+
+	error = verify_area(VERIFY_WRITE, buf, msglen);
+	if (error)
+		return -EINVAL;
+
+	copy_to_user(buf, msg, msglen);
+
+	if (ppos)
+		*ppos = msglen;
+	return msglen;
+}
+
+/* We could be much more efficient here.  But to keep this function
+ * simple we allocate a page to the block list no matter how small the
+ * count is.  If the system is low on memory it will be just as well
+ * that we fail....
+ */
+static ssize_t rtas_flash_write(struct file *file, const char *buffer,
+				size_t count, loff_t *off)
+{
+	size_t len = count;
+	char *p;
+	int next_free;
+	struct flash_block_list *fl = flist;
+
+	if (!flash_possible || len == 0)
+		return len;	/* discard data */
+
+	while (fl->next)
+		fl = fl->next; /* seek to last block_list for append */
+	next_free = fl->num_blocks;
+	if (next_free == FLASH_BLOCKS_PER_NODE) {
+		/* Need to allocate another block_list */
+		fl->next = (struct flash_block_list *)get_free_page(GFP_KERNEL);
+		if (!fl->next)
+			return -ENOMEM;
+		fl = fl->next;
+		next_free = 0;
+	}
+
+	if (len > PAGE_SIZE)
+		len = PAGE_SIZE;
+	p = (char *)get_free_page(GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+	if(copy_from_user(p, buffer, len)) {
+		free_page((unsigned long)p);
+		return -EFAULT;
+	}
+	fl->blocks[next_free].data = p;
+	fl->blocks[next_free].length = len;
+	fl->num_blocks++;
+
+	return len;
+}
+
+static struct file_operations rtas_flash_operations = {
+	read:		rtas_flash_read,
+	write:		rtas_flash_write,
+	open:		rtas_flash_open,
+	release:	rtas_flash_release,
+};
+
+
+int __init rtas_flash_init(void)
+{
+	struct proc_dir_entry *ent = NULL;
+
+	if (!rtas_proc_dir) {
+		printk(KERN_WARNING "rtas proc dir does not already exist");
+		return -ENOENT;
+	}
+
+	if (rtas_token("ibm,update-flash-64-and-reboot") != RTAS_UNKNOWN_SERVICE)
+		flash_possible = 1;
+
+	if ((ent = create_proc_entry(FIRMWARE_FLASH_NAME, S_IRUSR | S_IWUSR, rtas_proc_dir)) != NULL) {
+		ent->nlink = 1;
+		ent->proc_fops = &rtas_flash_operations;
+		ent->owner = THIS_MODULE;
+	}
+	return 0;
+}
+
+void __exit rtas_flash_cleanup(void)
+{
+	if (!rtas_proc_dir)
+		return;
+	remove_proc_entry(FIRMWARE_FLASH_NAME, rtas_proc_dir);
+}
+
+module_init(rtas_flash_init);
+module_exit(rtas_flash_cleanup);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/rtasd.c linux-2.4.20/arch/ppc64/kernel/rtasd.c
--- linux-2.4.19/arch/ppc64/kernel/rtasd.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/rtasd.c	2002-10-29 11:18:33.000000000 +0000
@@ -98,9 +98,7 @@
 	rtas_log_size -= 1;
 	spin_unlock(&rtas_log_lock);
 
-	copy_to_user(buf, tmp, count);
-	error = count;
-
+	error = copy_to_user(buf, tmp, count) ? -EFAULT : count;
 out:
 	kfree(tmp);
 	return error;
@@ -624,6 +622,31 @@
 	}
 }
 
+#define MAX_LOG_DEBUG 10
+/* Print log debug data.  This appears after the location code.
+ * We limit the number of debug logs in case the data is somehow corrupt.
+ */
+static void printk_log_debug(char *buf)
+{
+	unsigned char *p = (unsigned char *)_ALIGN((unsigned long)buf, 8);
+	int len, n, logged;
+
+	logged = 0;
+	while ((logged < MAX_LOG_DEBUG) && (len = ((p[0] << 8) | p[1])) != 2) {
+		/* len includes 2-byte length thus len == 2 is the end */
+		printk("RTAS: Log Debug: ");
+		if (len >= 4)	/* next 2 bytes are an ascii code */
+			printk("%c%c ", p[2], p[3]);
+		for (n=4; n < len; n++)
+			printk("%02x", p[n]);
+		printk("\n");
+		p += len;
+		logged++;
+	}
+	if (logged == 0)
+		printk("RTAS: no log debug data present\n");
+}
+
 
 /* Yeah, the output here is ugly, but we want a CE to be
  * able to grep RTAS /var/log/messages and see all the info
@@ -637,8 +660,11 @@
 	if (strcmp(buf+8+40, "IBM") == 0) {
 		/* Location code follows */
 		char *loc = buf+8+40+4;
-		if (*loc >= 'A' && *loc <= 'Z')	/* Sanity check */
+		int len = strlen(loc);
+		if (len < 64) {	/* Sanity check */
 			printk(RTAS_ERR "Location Code: %s\n", loc);
+			printk_log_debug(loc+len+1);
+		}
 	}
 
 	printk(RTAS_ERR "%s: (%s) type: %s\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/setup.c linux-2.4.20/arch/ppc64/kernel/setup.c
--- linux-2.4.19/arch/ppc64/kernel/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/setup.c	2002-10-29 11:18:35.000000000 +0000
@@ -21,6 +21,8 @@
 #include <linux/ide.h>
 #include <linux/seq_file.h>
 #include <linux/ioport.h>
+#include <linux/console.h>
+#include <linux/version.h>
 #include <asm/init.h>
 #include <asm/io.h>
 #include <asm/prom.h>
@@ -40,6 +42,7 @@
 /* extern void *stab; */
 extern HTAB htab_data;
 extern unsigned long loops_per_jiffy;
+extern int preferred_console;	/* from kernel/printk.c */
 
 extern unsigned long embedded_sysmap_start;
 extern unsigned long embedded_sysmap_end;
@@ -68,6 +71,10 @@
 extern void xmon_map_scc(void);
 #endif
 
+#ifdef CONFIG_KDB
+extern void kdb_map_scc(void);
+#endif
+
 char saved_command_line[256];
 unsigned char aux_device_present;
 
@@ -109,15 +116,12 @@
 int icache_bsize;
 int ucache_bsize;
 
-/*
- * Initialize the PPCDBG state.  Called before relocation has been enabled.
- */
-void ppcdbg_initialize(void) {
-	unsigned long offset = reloc_offset();
-	struct naca_struct *_naca = RELOC(naca);
-
-	_naca->debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */;
-}
+static struct console udbg_console = {
+	name:	"udbg",
+	write:	udbg_console_write,
+	flags:	CON_PRINTBUFFER,
+	index:	-1,
+};
 
 /*
  * Do some initial setup of the system.  The paramters are those which 
@@ -157,66 +161,29 @@
 #endif
 	}
 
-	udbg_puts("\n-----------------------------------------------------\n");
-	udbg_puts("Naca Info...\n\n");
-	udbg_puts("naca                       = 0x");
-	udbg_puthex((unsigned long)naca);
-	udbg_putc('\n');
-
-	udbg_puts("naca->processorCount       = 0x");
-	udbg_puthex(naca->processorCount);
-	udbg_putc('\n');
-
-	udbg_puts("naca->physicalMemorySize   = 0x");
-	udbg_puthex(naca->physicalMemorySize);
-	udbg_putc('\n');
-
-	udbg_puts("naca->dCacheL1LineSize     = 0x");
-	udbg_puthex(naca->dCacheL1LineSize);
-	udbg_putc('\n');
-
-	udbg_puts("naca->dCacheL1LogLineSize  = 0x");
-	udbg_puthex(naca->dCacheL1LogLineSize);
-	udbg_putc('\n');
-
-	udbg_puts("naca->dCacheL1LinesPerPage = 0x");
-	udbg_puthex(naca->dCacheL1LinesPerPage);
-	udbg_putc('\n');
-
-	udbg_puts("naca->iCacheL1LineSize     = 0x");
-	udbg_puthex(naca->iCacheL1LineSize);
-	udbg_putc('\n');
-
-	udbg_puts("naca->iCacheL1LogLineSize  = 0x");
-	udbg_puthex(naca->iCacheL1LogLineSize);
-	udbg_putc('\n');
-
-	udbg_puts("naca->iCacheL1LinesPerPage = 0x");
-	udbg_puthex(naca->iCacheL1LinesPerPage);
-	udbg_putc('\n');
-
-	udbg_puts("naca->pftSize              = 0x");
-	udbg_puthex(naca->pftSize);
-	udbg_putc('\n');
-
-	udbg_puts("naca->serialPortAddr       = 0x");
-	udbg_puthex(naca->serialPortAddr);
-	udbg_putc('\n');
-
-	udbg_puts("naca->interrupt_controller = 0x");
-	udbg_puthex(naca->interrupt_controller);
-	udbg_putc('\n');
-
-	udbg_printf("\nHTAB Info ...\n\n"); 
-	udbg_puts("htab_data.htab             = 0x");
-	udbg_puthex((unsigned long)htab_data.htab);
-	udbg_putc('\n');
-	udbg_puts("htab_data.num_ptegs        = 0x");
-	udbg_puthex(htab_data.htab_num_ptegs);
-	udbg_putc('\n');
+	if (naca->platform & PLATFORM_PSERIES) {
+		register_console(&udbg_console);
+		preferred_console = -1;
+	}
 
-	udbg_puts("\n-----------------------------------------------------\n");
+	printk("Starting Linux PPC64 %s\n", UTS_RELEASE);
 
+	printk("-----------------------------------------------------\n");
+	printk("naca                       = 0x%p\n", naca);
+	printk("naca->processorCount       = 0x%x\n", naca->processorCount);
+	printk("naca->physicalMemorySize   = 0x%lx\n", naca->physicalMemorySize);
+	printk("naca->dCacheL1LineSize     = 0x%x\n", naca->dCacheL1LineSize);
+	printk("naca->dCacheL1LogLineSize  = 0x%x\n", naca->dCacheL1LogLineSize);
+	printk("naca->dCacheL1LinesPerPage = 0x%x\n", naca->dCacheL1LinesPerPage);
+	printk("naca->iCacheL1LineSize     = 0x%x\n", naca->iCacheL1LineSize);
+	printk("naca->iCacheL1LogLineSize  = 0x%x\n", naca->iCacheL1LogLineSize);
+	printk("naca->iCacheL1LinesPerPage = 0x%x\n", naca->iCacheL1LinesPerPage);
+	printk("naca->pftSize              = 0x%lx\n", naca->pftSize);
+	printk("naca->debug_switch         = 0x%lx\n", naca->debug_switch);
+	printk("naca->interrupt_controller = 0x%lx\n", naca->interrupt_controller);
+	printk("htab_data.htab             = 0x%p\n", htab_data.htab);
+	printk("htab_data.num_ptegs        = 0x%lx\n", htab_data.htab_num_ptegs);
+	printk("-----------------------------------------------------\n");
 
 	if (naca->platform & PLATFORM_PSERIES) {
 		finish_device_tree();
@@ -226,14 +193,28 @@
 	mm_init_ppc64();
 
 	switch (naca->platform) {
-	case PLATFORM_ISERIES_LPAR:
+	    case PLATFORM_ISERIES_LPAR:
 		iSeries_init();
 		break;
-	default:
+	    default:
 		/* The following relies on the device tree being */
 		/* fully configured.                             */
 		parse_cmd_line(r3, r4, r5, r6, r7);
 	}
+	ppc64_boot_msg(0x10, "Setup System");
+}
+
+/* This is called just before console_init().
+ * It will be obsolete when Linux gets real early console support (2.5?)
+ * We need to hack preferred_console to retain the correct behavior
+ */
+void setup_before_console_init(void)
+{
+	if (naca->platform & PLATFORM_PSERIES) {
+		int save = preferred_console;
+		unregister_console(&udbg_console);
+		preferred_console = save;
+	}
 }
 
 void machine_restart(char *cmd)
@@ -284,6 +265,9 @@
 	pvr = paca[cpu_id].pvr;
 
 	switch (PVR_VER(pvr)) {
+	case PV_NORTHSTAR:
+		seq_printf(m, "RS64-II (northstar)\n");
+		break;
 	case PV_PULSAR:
 		seq_printf(m, "RS64-III (pulsar)\n");
 		break;
@@ -302,6 +286,9 @@
 	case PV_630p:
 		seq_printf(m, "POWER3 (630+)\n");
 		break;
+	case PV_POWER4p:
+		seq_printf(m, "POWER4+ (gq)\n");
+		break;
 	default:
 		seq_printf(m, "Unknown (%08x)\n", pvr);
 		break;
@@ -328,7 +315,7 @@
 	if (ppc_md.setup_residual != NULL)
 		ppc_md.setup_residual(m, cpu_id);
 
-	seq_printf(m, "revision\t: %hd.%hd\n", maj, min);
+	seq_printf(m, "revision\t: %hd.%hd\n\n", maj, min);
 	
 	return 0;
 }
@@ -369,18 +356,9 @@
 	}
 #endif
 
-	cmd_line[0] = 0;
-	chosen = find_devices("chosen");
-	if (chosen != NULL) {
-		p = get_property(chosen, "bootargs", NULL);
-		if (p != NULL)
-			strncpy(cmd_line, p, sizeof(cmd_line));
-	}
-	cmd_line[sizeof(cmd_line) - 1] = 0;
-
 	/* Look for mem= option on command line */
 	if (strstr(cmd_line, "mem=")) {
-		char *p, *q;
+		char *q;
 		unsigned long maxmem = 0;
 		extern unsigned long __max_memory;
 
@@ -399,7 +377,6 @@
 		}
 		__max_memory = maxmem;
 	}
-	ppc_md.progress("id mach: done", 0x200);
 }
 
 
@@ -477,7 +454,6 @@
 	printk("Calibrating delay loop... %lu.%02lu BogoMips\n",
 			       loops_per_jiffy/(500000/HZ),
 			       loops_per_jiffy/(5000/HZ) % 100);
-
 }	
 
 extern void (*calibrate_delay)(void);
@@ -495,15 +471,18 @@
 
 	calibrate_delay = ppc64_calibrate_delay;
 
+	ppc64_boot_msg(0x12, "Setup Arch");
 #ifdef CONFIG_XMON
 	xmon_map_scc();
 	if (strstr(cmd_line, "xmon"))
 		xmon(0);
 #endif /* CONFIG_XMON */
+
 #ifdef CONFIG_KDB
-	xmon_map_scc();	/* in kdb/start.c --need to rename TAI */
+	kdb_map_scc();	
+	if (strstr(cmd_line, "kdb=early"))
+		kdb(KDB_REASON_CALL,0,0);
 #endif
-	ppc_md.progress("setup_arch:enter", 0x3eab);
 
 #if defined(CONFIG_KGDB)
 	kgdb_map_scc();
@@ -532,12 +511,11 @@
 
 	/* set up the bootmem stuff with available memory */
 	do_init_bootmem();
-	ppc_md.progress("setup_arch:bootmem", 0x3eab);
 
 	ppc_md.setup_arch();
 
 	paging_init();
-	ppc_md.progress("setup_arch: exit", 0x3eab);
+	ppc64_boot_msg(0x15, "Setup Done");
 }
 
 #ifdef CONFIG_IDE
@@ -638,6 +616,53 @@
 }
 #endif
 
+/* ToDo: do something useful if ppc_md is not yet setup. */
+#define PPC64_LINUX_FUNCTION 0x0f000000
+#define PPC64_IPL_MESSAGE 0xc0000000
+#define PPC64_TERM_MESSAGE 0xb0000000
+#define PPC64_ATTN_MESSAGE 0xa0000000
+#define PPC64_DUMP_MESSAGE 0xd0000000
+
+static void ppc64_do_msg(unsigned int src, const char *msg)
+{
+	if (ppc_md.progress) {
+		char buf[32];
+
+		sprintf(buf, "%08x        \n", src);
+		ppc_md.progress(buf, 0);
+		sprintf(buf, "%-16s", msg);
+		ppc_md.progress(buf, 0);
+	}
+}
+
+/* Print a boot progress message. */
+void ppc64_boot_msg(unsigned int src, const char *msg)
+{
+	ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_IPL_MESSAGE|src, msg);
+	printk("[boot]%04x %s\n", src, msg);
+}
+
+/* Print a termination message (print only -- does not stop the kernel) */
+void ppc64_terminate_msg(unsigned int src, const char *msg)
+{
+	ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg);
+	printk("[terminate]%04x %s\n", src, msg);
+}
+
+/* Print something that needs attention (device error, etc) */
+void ppc64_attention_msg(unsigned int src, const char *msg)
+{
+	ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_ATTN_MESSAGE|src, msg);
+	printk("[attention]%04x %s\n", src, msg);
+}
+
+/* Print a dump progress message. */
+void ppc64_dump_msg(unsigned int src, const char *msg)
+{
+	ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_DUMP_MESSAGE|src, msg);
+	printk("[dump]%04x %s\n", src, msg);
+}
+
 
 void exception_trace(unsigned long trap)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/signal.c linux-2.4.20/arch/ppc64/kernel/signal.c
--- linux-2.4.19/arch/ppc64/kernel/signal.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/signal.c	2002-10-29 11:18:50.000000000 +0000
@@ -1,8 +1,6 @@
 /*
  *  linux/arch/ppc64/kernel/signal.c
  *
- *  
- *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
@@ -637,11 +635,6 @@
 	 */
 	if (current->thread.flags & PPC_FLAG_32BIT)
 		return do_signal32(oldset, regs);
-  
-        PPCDBG(PPCDBG_SIGNAL, "do_signal - running - pid=%ld current=%lx comm=%s \n", 
-               current->pid, current, current->comm);
-
-  
 
         if (!oldset)
 		oldset = &current->blocked;
@@ -716,7 +709,7 @@
 				continue;
 
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
@@ -724,13 +717,16 @@
 					continue;
 				/* FALLTHRU */
 
-			case SIGSTOP:
+			case SIGSTOP: {
+				struct signal_struct *sig;
 				current->state = TASK_STOPPED;
 				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+				sig = current->p_pptr->sig;
+				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
+			}
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV:
@@ -740,10 +736,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/signal32.c linux-2.4.20/arch/ppc64/kernel/signal32.c
--- linux-2.4.19/arch/ppc64/kernel/signal32.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/signal32.c	2002-10-29 11:18:33.000000000 +0000
@@ -1406,7 +1406,7 @@
 				continue;
 
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
@@ -1430,10 +1430,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/smp.c linux-2.4.20/arch/ppc64/kernel/smp.c
--- linux-2.4.19/arch/ppc64/kernel/smp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/smp.c	2002-10-29 11:18:49.000000000 +0000
@@ -52,6 +52,14 @@
 #include <asm/ppcdebug.h>
 #include "open_pic.h"
 #include <asm/machdep.h>
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+int (*dump_ipi_function_ptr)(struct pt_regs *);
+#include <linux/dump.h>
+#endif
+
+#ifdef CONFIG_KDB
+#include <linux/kdb.h>
+#endif
 
 int smp_threads_ready = 0;
 volatile int smp_commenced = 0;
@@ -93,9 +101,21 @@
        } while(0)
 
 #ifdef CONFIG_KDB
+/* save regs here before calling kdb_ipi */
+struct pt_regs *kdb_smp_regs[NR_CPUS]; 
+
+/* called for each processor.. drop each into kdb. */
+void smp_kdb_stop_proc(void)
+{
+    kdb_ipi(kdb_smp_regs[smp_processor_id()], NULL);
+}
+
 void smp_kdb_stop(void)
 {
+  int ret=0;
+  ret =    smp_call_function(smp_kdb_stop_proc, NULL, 1, 0);
 }
+
 #endif
 
 static inline void set_tb(unsigned int upper, unsigned int lower)
@@ -161,7 +181,7 @@
 			paca[i].next_jiffy_update_tb = paca[0].next_jiffy_update_tb;
 		}
 	}
-	
+
 	smp_tb_synchronized = 1;
 	return np;
 }
@@ -263,8 +283,6 @@
 	paca[nr].xProcStart = 1;
 }
 
-extern struct gettimeofday_struct do_gtod;
-
 static void smp_space_timers( unsigned nr )
 {
 	unsigned long offset, i;
@@ -285,8 +303,8 @@
 		/* timebases already synced under the hypervisor. */
 		paca[cpu_nr].next_jiffy_update_tb = tb_last_stamp = get_tb();
 		if (cpu_nr == 0) {
-			do_gtod.tb_orig_stamp = tb_last_stamp;
-			/* Should update do_gtod.stamp_xsec.
+			naca->tb_orig_stamp = tb_last_stamp;
+			/* Should update naca->stamp_xsec.
 			 * For now we leave it which means the time can be some
 			 * number of msecs off until someone does a settimeofday()
 			 */
@@ -312,7 +330,7 @@
 			mb();
 			frozen = 0;
 			tb_last_stamp = get_tb();
-			do_gtod.tb_orig_stamp = tb_last_stamp;
+			naca->tb_orig_stamp = tb_last_stamp;
 			smp_tb_synchronized = 1;
 		} else {
 			atomic_inc(&ready);
@@ -346,7 +364,7 @@
 			set_bit(msg, &xics_ipi_message[i]);
 			mb();
 			xics_cause_IPI(i);
-			}
+		}
 	}
 }
 
@@ -387,6 +405,9 @@
 	
 	switch( msg ) {
 	case PPC_MSG_CALL_FUNCTION:
+#ifdef CONFIG_KDB
+		kdb_smp_regs[smp_processor_id()]=regs;
+#endif
 		smp_call_function_interrupt();
 		break;
 	case PPC_MSG_RESCHEDULE: 
@@ -394,15 +415,16 @@
 		break;
 #ifdef CONFIG_XMON
 	case PPC_MSG_XMON_BREAK:
-		xmon(regs);
+	        /* ToDo: need a nmi way to handle this.  Soft disable? */
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+	        if (dump_ipi_function_ptr) {
+			printk(KERN_ALERT "got dump ipi...\n");
+			dump_ipi_function_ptr(regs);
+		} else
+#endif
+			xmon(regs);
 		break;
 #endif /* CONFIG_XMON */
-#ifdef CONFIG_KDB
-	case PPC_MSG_XMON_BREAK:
-	        /* This isn't finished yet, obviously -TAI */
-		kdb(KDB_REASON_KEYBOARD,0, (kdb_eframe_t) regs);
-		break;
-#endif
 	default:
 		printk("SMP %d: smp_message_recv(): unknown msg %d\n",
 		       smp_processor_id(), msg);
@@ -422,6 +444,18 @@
 }
 #endif /* CONFIG_XMON */
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+void dump_send_ipi(int (*dump_ipi_callback)(struct pt_regs *))
+{
+	dump_ipi_function_ptr = dump_ipi_callback;
+	if (dump_ipi_callback) {
+		printk(KERN_ALERT "dump_send_ipi...\n");
+		mb();
+		smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_XMON_BREAK, 0, 0);
+	}
+}
+#endif
+
 static void stop_this_cpu(void *dummy)
 {
 	__cli();
@@ -463,7 +497,7 @@
  * remote CPUs are nearly ready to execute <<func>> or are or have executed.
  *
  * You must not call this function with disabled interrupts or from a
- * hardware interrupt handler, you may call it from a bottom half handler.
+ * hardware interrupt handler or from a bottom half handler.
  */
 int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
 			int wait)
@@ -498,6 +532,10 @@
 #ifdef CONFIG_XMON
                         xmon(0);
 #endif
+#ifdef CONFIG_KDB
+			kdb(KDB_REASON_CALL,0, (kdb_eframe_t) 0);
+#endif
+
 #ifdef CONFIG_PPC_ISERIES
 			HvCall_terminateMachineSrc();
 #endif
@@ -550,6 +588,7 @@
 		atomic_inc(&call_data->finished);
 }
 
+
 extern unsigned long decr_overclock;
 
 void __init smp_boot_cpus(void)
@@ -577,7 +616,7 @@
 	init_idle();
 
 	for (i = 0; i < NR_CPUS; i++) {
-		paca[i].prof_counter=1;
+		paca[i].prof_counter = 1;
 		paca[i].prof_multiplier = 1;
 		if(i != 0) {
 		        /*
@@ -611,7 +650,7 @@
 	if (cpu_nr > max_cpus)
 		cpu_nr = max_cpus;
 
-#ifdef CONFIG_ISERIES
+#ifdef CONFIG_PPC_ISERIES
 	smp_space_timers( cpu_nr );
 #endif
 
@@ -742,7 +781,7 @@
 {
 }
 
-int __init setup_profiling_timer(unsigned int multiplier)
+int setup_profiling_timer(unsigned int multiplier)
 {
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/stab.c linux-2.4.20/arch/ppc64/kernel/stab.c
--- linux-2.4.19/arch/ppc64/kernel/stab.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/stab.c	2002-10-29 11:18:37.000000000 +0000
@@ -35,7 +35,7 @@
 	esid = GET_ESID(KERNELBASE);
 	vsid = get_kernel_vsid(esid << SID_SHIFT); 
 
-	if (!__is_processor(PV_POWER4)) {
+	if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) {
                 __asm__ __volatile__("isync; slbia; isync":::"memory");
 		make_ste(stab, esid, vsid);
 	} else {
@@ -305,7 +305,7 @@
 	unsigned char *segments = get_paca()->xSegments;
 	unsigned long flags, i;
 
-	if(!__is_processor(PV_POWER4)) {
+	if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) {
 		unsigned long entry;
 		STE *ste;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/sys_ppc32.c linux-2.4.20/arch/ppc64/kernel/sys_ppc32.c
--- linux-2.4.19/arch/ppc64/kernel/sys_ppc32.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/sys_ppc32.c	2002-10-29 11:18:34.000000000 +0000
@@ -81,47 +81,6 @@
  */
 #define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
 
-/* In order to reduce some races, while at the same time doing additional
- * checking and hopefully speeding things up, we copy filenames to the
- * kernel data space before using them..
- *
- * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
- */
-static inline int do_getname32(const char *filename, char *page)
-{
-	int retval;
-
-	/* 32bit pointer will be always far below TASK_SIZE :)) */
-	retval = strncpy_from_user((char *)page, (char *)filename, PAGE_SIZE);
-	if (retval > 0) {
-		if (retval < PAGE_SIZE)
-			return 0;
-		return -ENAMETOOLONG;
-	} else if (!retval)
-		retval = -ENOENT;
-	return retval;
-}
-
-char * getname32(const char *filename)
-{
-	char *tmp, *result;
-
-	result = ERR_PTR(-ENOMEM);
-  tmp =  __getname();
-	if (tmp)  {
-		int retval = do_getname32(filename, tmp);
-
-		result = tmp;
-		if (retval < 0) {
-			putname(tmp);
-			result = ERR_PTR(retval);
-		}
-	}
-	return result;
-}
-
-
-
 extern asmlinkage long sys_utime(char * filename, struct utimbuf * times);
 
 struct utimbuf32 {
@@ -141,7 +100,7 @@
 		return sys_utime(filename, NULL);
 	if (get_user(t.actime, &times->actime) || __get_user(t.modtime, &times->modtime))
 		return -EFAULT;
-	filenam = getname32(filename);
+	filenam = getname(filename);
 
 	ret = PTR_ERR(filenam);
 	if (!IS_ERR(filenam)) {
@@ -554,7 +513,7 @@
 		return sys_quotactl(cmd, special,
 				    id, (caddr_t)addr);
 	}
-	spec = getname32 (special);
+	spec = getname (special);
 	err = PTR_ERR(spec);
 	if (IS_ERR(spec)) return err;
 	old_fs = get_fs ();
@@ -899,15 +858,6 @@
 	return ret;
 }
 
-
-
-
-/*
- * Due to some executables calling the wrong select we sometimes
- * get wrong args.  This determines how the args are being passed
- * (a single ptr to them all args passed) then calls
- * sys_select() with the appropriate args. -- Cort
- */
 /* Note: it is necessary to treat n as an unsigned int, 
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -915,14 +865,9 @@
  */
 asmlinkage int ppc32_select(u32 n, u32* inp, u32* outp, u32* exp, u32 tvp_x)
 {
-	if ((unsigned int)n >= 4096)
-		panic("ppc32_select - wrong arguments were passed in \n");
-
 	return sys32_select((int)n, inp, outp, exp, tvp_x);
 }
 
-
-
 static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf)
 {
 	unsigned long ino, blksize, blocks;
@@ -1090,7 +1035,7 @@
 	
 	PPCDBG(PPCDBG_SYS32X, "sys32_statfs - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
 	
-	pth = getname32 (path);
+	pth = getname (path);
 	ret = PTR_ERR(pth);
 	if (!IS_ERR(pth)) {
 		set_fs (KERNEL_DS);
@@ -2883,9 +2828,6 @@
 		}
 		break;
 	}
-#if 0
-	udbg_printf("  err3 = 0x%lx\n", err); 
-#endif
 	return err;
 }
 
@@ -4000,11 +3942,6 @@
 	int error;
 	char * filename;
 	
-	ifppcdebug(PPCDBG_SYS32) {
-		udbg_printf("sys32_execve - entered - pid=%ld, comm=%s \n", current->pid, current->comm);
-		//PPCDBG(PPCDBG_SYS32NI, "               a0=%lx, a1=%lx, a2=%lx, a3=%lx, a4=%lx, a5=%lx, regs=%p \n", a0, a1, a2, a3, a4, a5, regs);
-	}
-
 	filename = getname((char *) a0);
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename))
@@ -4019,10 +3956,6 @@
 	putname(filename);
 
 out:
-	ifppcdebug(PPCDBG_SYS32) {
-		udbg_printf("sys32_execve - exited - returning %x - pid=%ld \n", error, current->pid);
-		//udbg_printf("sys32_execve - at exit - regs->gpr[1]=%lx, gpr[3]=%lx, gpr[4]=%lx, gpr[5]=%lx, gpr[6]=%lx \n", regs->gpr[1], regs->gpr[3], regs->gpr[4], regs->gpr[5], regs->gpr[6]);
-	}
 	return error;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/time.c linux-2.4.20/arch/ppc64/kernel/time.c
--- linux-2.4.19/arch/ppc64/kernel/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/time.c	2002-10-29 11:18:35.000000000 +0000
@@ -47,6 +47,7 @@
 #include <linux/time.h>
 #include <linux/init.h>
 
+#include <asm/naca.h>
 #include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/processor.h>
@@ -64,6 +65,8 @@
 
 void smp_local_timer_interrupt(struct pt_regs *);
 
+extern void setup_before_console_init();
+
 /* keep track of when we need to update the rtc */
 time_t last_rtc_update;
 extern rwlock_t xtime_lock;
@@ -83,12 +86,9 @@
 unsigned long next_xtime_sync_tb;
 unsigned long xtime_sync_interval;
 unsigned long tb_to_xs;
-unsigned      tb_to_us;
 unsigned long processor_freq;
 spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
 
-struct gettimeofday_struct do_gtod;
-
 extern unsigned long wall_jiffies;
 extern unsigned long lpEvent_count;
 extern int smp_tb_synchronized;
@@ -99,15 +99,14 @@
 extern unsigned long prof_shift;
 extern char _stext;
 
+extern struct timezone sys_tz;
+
 void ppc_adjtimex(void);
 
 static unsigned adjusting_time = 0;
 
-static inline void ppc_do_profile (unsigned long nip)
+static void ppc_do_profile (unsigned long nip)
 {
-	if (!prof_buffer)
-		return;
-
 	/*
 	 * Only measure the CPUs specified by /proc/irq/prof_cpu_mask.
 	 * (default is all CPUs.)
@@ -181,9 +180,9 @@
 #ifdef CONFIG_PPC_ISERIES
 
 /* 
- * This function recalibrates the timebase based on the 49-bit time-of-day value in the Titan chip.
- * The Titan is much more accurate than the value returned by the service processor for the
- * timebase frequency.  
+ * This function recalibrates the timebase based on the 49-bit time-of-day
+ * value in the Titan chip.  The Titan is much more accurate than the value
+ * returned by the service processor for the timebase frequency.  
  */
 
 static void iSeries_tb_recal(void)
@@ -213,9 +212,9 @@
 				tb_ticks_per_jiffy = new_tb_ticks_per_jiffy;
 				tb_ticks_per_sec   = new_tb_ticks_per_sec;
 				div128_by_32( XSEC_PER_SEC, 0, tb_ticks_per_sec, &divres );
-				do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;
+				naca->tb_ticks_per_sec = tb_ticks_per_sec;
 				tb_to_xs = divres.result_low;
-				do_gtod.varp->tb_to_xs = tb_to_xs;
+				naca->tb_to_xs = tb_to_xs;
 			}
 			else {
 				printk( "Titan recalibrate: FAILED (difference > 4 percent)\n"
@@ -256,10 +255,8 @@
 
 	irq_enter(cpu);
 
-#ifndef CONFIG_PPC_ISERIES
-	if (!user_mode(regs))
+	if ((!user_mode(regs)) && (prof_buffer))
 		ppc_do_profile(instruction_pointer(regs));
-#endif
 
 	lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
 
@@ -306,17 +303,62 @@
 {
         unsigned long sec, usec, tb_ticks;
 	unsigned long xsec, tb_xsec;
-	struct gettimeofday_vars * temp_varp;
 	unsigned long temp_tb_to_xs, temp_stamp_xsec;
+	unsigned long tb_count_1, tb_count_2;
+	unsigned long always_zero;
+	struct naca_struct *gtdp;
+	
+	gtdp = (struct naca_struct *)0xC000000000004000;
+	/* 
+	 * The following loop guarantees that we see a consistent view of the
+	 * tb_to_xs and stamp_xsec variables.  These two variables can change
+	 * (eg. when xntpd adjusts the clock frequency) and an inconsistent
+	 * view (one variable changed, the other not) could result in a wildly
+	 * wrong result for do_gettimeofday. 
+	 *
+	 * The code which updates these variables (ppc_adjtimex below)
+	 * increments tb_update_count, then updates the two variables and then
+	 * increments tb_update_count again.  This code reads tb_update_count,
+	 * reads the two variables and then reads tb_update_count again.  It
+	 * loops doing this until the two reads of tb_update_count yield the
+	 * same value and that value is even.  This ensures a consistent view
+	 * of the two variables.
+	 *
+	 * The strange looking assembler code below causes the hardware to
+	 * think that reading the two variables is dependent on the first read
+	 * of tb_update_count and that the second reading of tb_update_count is
+	 * dependent on reading the two variables.  This assures ordering
+	 * without the need for a lwsync, which is much more expensive.
+	 */
+	do {
+		tb_ticks = get_tb() - gtdp->tb_orig_stamp;
+
+		tb_count_1 = gtdp->tb_update_count;
+
+		__asm__ __volatile__ (
+"		andc 	%0,%2,%2\n\
+		add	%1,%3,%0\n\
+"		: "=&r"(always_zero), "=r"(gtdp)
+		: "r"(tb_count_1), "r"(gtdp) );
+
+		temp_tb_to_xs = gtdp->tb_to_xs;
+		temp_stamp_xsec = gtdp->stamp_xsec;
+
+		__asm__ __volatile__ (
+"		add	%0,%2,%3\n\
+		andc	%0,%0,%0\n\
+		add	%1,%4,%0\n\
+"		: "=&r"(always_zero), "=r"(gtdp)
+		: "r"(temp_stamp_xsec), "r"(temp_tb_to_xs), "r"(gtdp) );
+
+		tb_count_2 = gtdp->tb_update_count;
+
+	} while ( tb_count_2 - ( tb_count_1 & 0xfffffffffffffffe ) ); 
 
 	/* These calculations are faster (gets rid of divides)
 	 * if done in units of 1/2^20 rather than microseconds.
 	 * The conversion to microseconds at the end is done
 	 * without a divide (and in fact, without a multiply) */
-	tb_ticks = get_tb() - do_gtod.tb_orig_stamp;
-	temp_varp = do_gtod.varp;
-	temp_tb_to_xs = temp_varp->tb_to_xs;
-	temp_stamp_xsec = temp_varp->stamp_xsec;
 	tb_xsec = mulhdu( tb_ticks, temp_tb_to_xs );
 	xsec = temp_stamp_xsec + tb_xsec;
 	sec = xsec / XSEC_PER_SEC;
@@ -370,21 +412,24 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 
-	delta_xsec = mulhdu( (tb_last_stamp-do_gtod.tb_orig_stamp), do_gtod.varp->tb_to_xs );
+	delta_xsec = mulhdu( (tb_last_stamp-naca->tb_orig_stamp), naca->tb_to_xs );
 	new_xsec = (new_usec * XSEC_PER_SEC) / USEC_PER_SEC;
 	new_xsec += new_sec * XSEC_PER_SEC;
 	if ( new_xsec > delta_xsec ) {
-		do_gtod.varp->stamp_xsec = new_xsec - delta_xsec;
+		naca->stamp_xsec = new_xsec - delta_xsec;
 	}
 	else {
 		/* This is only for the case where the user is setting the time
 		 * way back to a time such that the boot time would have been
-		 * before 1970 ... eg. we booted ten days ago, and we are setting
-		 * the time to Jan 5, 1970 */
-		do_gtod.varp->stamp_xsec = new_xsec;
-		do_gtod.tb_orig_stamp = tb_last_stamp;
+		 * before 1970 ... eg. we booted ten days ago, and we are
+		 * setting the time to Jan 5, 1970 */
+		naca->stamp_xsec = new_xsec;
+		naca->tb_orig_stamp = tb_last_stamp;
 	}
 
+	naca->tz_minuteswest = sys_tz.tz_minuteswest;
+	naca->tz_dsttime = sys_tz.tz_dsttime;
+
 	write_unlock_irqrestore(&xtime_lock, flags);
 }
 
@@ -453,13 +498,11 @@
 	xtime.tv_sec = mktime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
 			      tm.tm_hour, tm.tm_min, tm.tm_sec);
 	tb_last_stamp = get_tb();
-	do_gtod.tb_orig_stamp = tb_last_stamp;
-	do_gtod.varp = &do_gtod.vars[0];
-	do_gtod.var_idx = 0;
-	do_gtod.varp->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
-	do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;
-	do_gtod.varp->tb_to_xs = tb_to_xs;
-	do_gtod.tb_to_us = tb_to_us;
+	naca->tb_orig_stamp = tb_last_stamp;
+	naca->tb_update_count = 0;
+	naca->tb_ticks_per_sec = tb_ticks_per_sec;
+	naca->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
+	naca->tb_to_xs = tb_to_xs;
 
 	xtime_sync_interval = tb_ticks_per_sec - (tb_ticks_per_sec/8);
 	next_xtime_sync_tb = tb_last_stamp + xtime_sync_interval;
@@ -470,23 +513,21 @@
 	last_rtc_update = xtime.tv_sec;
 	write_unlock_irqrestore(&xtime_lock, flags);
 
-#ifdef CONFIG_PPC_ISERIES
-	/* HACK HACK This allows the iSeries profiling to use /proc/profile */
-	prof_shift = 0;
-#endif
-
 	/* Not exact, but the timer interrupt takes care of this */
 	set_dec(tb_ticks_per_jiffy);
+
+	/* This horrible hack gives setup a hook just before console_init */
+	setup_before_console_init();
 }
 
 /* 
  * After adjtimex is called, adjust the conversion of tb ticks
  * to microseconds to keep do_gettimeofday synchronized 
  * with ntpd.
-
+ *
  * Use the time_adjust, time_freq and time_offset computed by adjtimex to 
  * adjust the frequency.
-*/
+ */
 
 /* #define DEBUG_PPC_ADJTIMEX 1 */
 
@@ -497,8 +538,6 @@
 	long delta_freq, ltemp;
 	struct div_result divres; 
 	unsigned long flags;
-	struct gettimeofday_vars * temp_varp;
-	unsigned temp_idx;
 	long singleshot_ppm = 0;
 
 	/* Compute parts per million frequency adjustment to accomplish the time adjustment
@@ -529,8 +568,11 @@
 		
 		/* Compute parts per million frequency adjustment to match time_adjust */
 		singleshot_ppm = tickadj * HZ;	
-		/* The adjustment should be tickadj*HZ to match the code in linux/kernel/timer.c, but
-		   experiments show that this is too large. 3/4 of tickadj*HZ seems about right */
+		/*
+		 * The adjustment should be tickadj*HZ to match the code in
+		 * linux/kernel/timer.c, but experiments show that this is too
+		 * large. 3/4 of tickadj*HZ seems about right
+		 */
 		singleshot_ppm -= singleshot_ppm / 4;
 		/* Use SHIFT_USEC to get it into the same units as time_freq */	
 		singleshot_ppm <<= SHIFT_USEC;
@@ -564,36 +606,38 @@
 	printk("ppc_adjtimex: tb_ticks_per_sec - base = %ld  new = %ld\n", tb_ticks_per_sec, new_tb_ticks_per_sec);
 #endif
 				
-	/* Compute a new value of tb_to_xs (used to convert tb to microseconds and a new value of 
-	   stamp_xsec which is the time (in 1/2^20 second units) corresponding to tb_orig_stamp.  This 
-	   new value of stamp_xsec compensates for the change in frequency (implied by the new tb_to_xs)
-	   which guarantees that the current time remains the same */ 
-	tb_ticks = get_tb() - do_gtod.tb_orig_stamp;
+	/*
+	 * Compute a new value of tb_to_xs (used to convert tb to microseconds
+	 * and a new value of stamp_xsec which is the time (in 1/2^20 second
+	 * units) corresponding to tb_orig_stamp.  This new value of stamp_xsec
+	 * compensates for the change in frequency (implied by the new
+	 * tb_to_xs) and so guarantees that the current time remains the same
+	 *
+	 */ 
+	tb_ticks = get_tb() - naca->tb_orig_stamp;
 	div128_by_32( 1024*1024, 0, new_tb_ticks_per_sec, &divres );
 	new_tb_to_xs = divres.result_low;
 	new_xsec = mulhdu( tb_ticks, new_tb_to_xs );
 
 	write_lock_irqsave( &xtime_lock, flags );
-	old_xsec = mulhdu( tb_ticks, do_gtod.varp->tb_to_xs );
-	new_stamp_xsec = do_gtod.varp->stamp_xsec + old_xsec - new_xsec;
+	old_xsec = mulhdu( tb_ticks, naca->tb_to_xs );
+	new_stamp_xsec = naca->stamp_xsec + old_xsec - new_xsec;
 
-	/* There are two copies of tb_to_xs and stamp_xsec so that no lock is needed to access and use these
-	   values in do_gettimeofday.  We alternate the copies and as long as a reasonable time elapses between
-	   changes, there will never be inconsistent values.  ntpd has a minimum of one minute between updates */
-
-	if (do_gtod.var_idx == 0) {
-		temp_varp = &do_gtod.vars[1];
-		temp_idx  = 1;
-	}
-	else {
-		temp_varp = &do_gtod.vars[0];
-		temp_idx  = 0;
-	}
-	temp_varp->tb_to_xs = new_tb_to_xs;
-	temp_varp->stamp_xsec = new_stamp_xsec;
-	mb();
-	do_gtod.varp = temp_varp;
-	do_gtod.var_idx = temp_idx;
+	/*
+	 * tb_update_count is used to allow the problem state gettimeofday code
+	 * to assure itself that it sees a consistent view of the tb_to_xs and
+	 * stamp_xsec variables.  It reads the tb_update_count, then reads
+	 * tb_to_xs and stamp_xsec and then reads tb_update_count again.  If
+	 * the two values of tb_update_count match and are even then the
+	 * tb_to_xs and stamp_xsec values are consistent.  If not, then it
+	 * loops back and reads them again until this criteria is met.
+	 */
+	++(naca->tb_update_count);
+	wmb();
+	naca->tb_to_xs = new_tb_to_xs;
+	naca->stamp_xsec = new_stamp_xsec;
+	wmb();
+	++(naca->tb_update_count);
 
 	write_unlock_irqrestore( &xtime_lock, flags );
 
@@ -691,6 +735,7 @@
 	GregorianDay(tm);
 }
 
+#if 0
 /* Auxiliary function to compute scaling factors */
 /* Actually the choice of a timebase running at 1/4 the of the bus
  * frequency giving resolution of a few tens of nanoseconds is quite nice.
@@ -720,6 +765,7 @@
         if (err <= inscale/2) mlt++;
         return mlt;
   }
+#endif
 
 /*
  * Divide a 128-bit dividend by a 32-bit divisor, leaving a 128 bit
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/traps.c linux-2.4.20/arch/ppc64/kernel/traps.c
--- linux-2.4.19/arch/ppc64/kernel/traps.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/traps.c	2002-10-29 11:18:36.000000000 +0000
@@ -29,6 +29,8 @@
 #include <linux/interrupt.h>
 #include <linux/config.h>
 #include <linux/init.h>
+#include <asm/iSeries/HvCall.h>
+#include <asm/iSeries/HvCallCfg.h>
 
 #ifdef CONFIG_KDB
 #include <linux/kdb.h>
@@ -71,8 +73,23 @@
 int (*debugger_iabr_match)(struct pt_regs *regs);
 int (*debugger_dabr_match)(struct pt_regs *regs);
 void (*debugger_fault_handler)(struct pt_regs *regs);
-#endif
-#endif
+#else
+#ifdef CONFIG_KDB
+/* kdb has different call parms */
+/* ... */
+void (*debugger)(struct pt_regs *regs) = kdb;
+int (*debugger_bpt)(struct pt_regs *regs);
+int (*debugger_sstep)(struct pt_regs *regs);
+int (*debugger_iabr_match)(struct pt_regs *regs);
+int (*debugger_dabr_match)(struct pt_regs *regs);
+/* - only defined during (xmon) mread */
+void (*debugger_fault_handler)(struct pt_regs *regs);
+#endif /* kdb */
+#endif /* kgdb */
+#endif /* xmon */
+
+void set_local_DABR(void *valp);
+
 /*
  * Trap & Exception support
  */
@@ -151,7 +168,16 @@
 	xmon(regs);
 	udbg_printf("leaving xmon...\n");
 #endif
+#if defined(CONFIG_KDB)
+	kdb(KDB_REASON_ENTER, regs->trap, (kdb_eframe_t) regs);
+	udbg_printf("leaving kdb...\n");
+#endif
+
+/*
+allow system to resume after reset.
 	for(;;);
+*/
+
 }
 
 
@@ -272,14 +298,6 @@
 	_exception(SIGTRAP, regs);	
 }
 
-/* Dummy handler for Performance Monitor */
-
-void
-PerformanceMonitorException(struct pt_regs *regs)
-{
-	_exception(SIGTRAP, regs);
-}
-
 void
 AlignmentException(struct pt_regs *regs)
 {
@@ -307,3 +325,20 @@
 void __init trap_init(void)
 {
 }
+
+/*
+ * Set the DABR on all processors in the system.  The value is defined as:
+ * DAB(0:60), Break Translate(61), Write(62), Read(63)
+ */
+void
+set_all_DABR(unsigned long val) {
+	set_local_DABR(&val); 
+	smp_call_function(set_local_DABR, &val, 0, 0);
+}
+
+void
+set_local_DABR(void *valp) {
+	unsigned long val = *((unsigned long *)valp); 
+
+	HvCall_setDABR(val);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/udbg.c linux-2.4.20/arch/ppc64/kernel/udbg.c
--- linux-2.4.19/arch/ppc64/kernel/udbg.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/udbg.c	2002-10-29 11:18:36.000000000 +0000
@@ -52,8 +52,6 @@
 
 volatile struct NS16550 *udbg_comport;
 
-spinlock_t udbg_lock = SPIN_LOCK_UNLOCKED;
-
 void
 udbg_init_uart(void *comport)
 {
@@ -161,6 +159,12 @@
 }
 
 void
+udbg_console_write(struct console *con, const char *s, unsigned int n)
+{
+	udbg_write(s, n);
+}
+
+void
 udbg_puthex(unsigned long val)
 {
 	int i, nibbles = sizeof(val)*2;
@@ -190,16 +194,13 @@
 void
 udbg_printf(const char *fmt, ...)
 {
-	unsigned long flags;
 	unsigned char buf[256];
 
 	va_list args;
 	va_start(args, fmt);
 
-	spin_lock_irqsave(&udbg_lock, flags);
 	vsprintf(buf, fmt, args);
 	udbg_puts(buf);
-	spin_unlock_irqrestore(&udbg_lock, flags);
 
 	va_end(args);
 }
@@ -208,7 +209,6 @@
 void
 udbg_ppcdbg(unsigned long debug_flags, const char *fmt, ...)
 {
-	unsigned long flags;
 	unsigned long active_debugs = debug_flags & naca->debug_switch;
 
 	if ( active_debugs ) {
@@ -216,7 +216,6 @@
 		unsigned char buf[256];
 		unsigned long i, len = 0;
 
-		spin_lock_irqsave(&udbg_lock, flags);
 		for(i=0; i < PPCDBG_NUM_FLAGS ;i++) {
 			if (((1U << i) & active_debugs) && 
 			    trace_names[i]) {
@@ -237,7 +236,6 @@
 		va_start(ap, fmt);
 		vsprintf(buf, fmt, ap);
 		udbg_puts(buf);
-		spin_unlock_irqrestore(&udbg_lock, flags);
 		
 		va_end(ap);
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/kernel/xics.c linux-2.4.20/arch/ppc64/kernel/xics.c
--- linux-2.4.19/arch/ppc64/kernel/xics.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/kernel/xics.c	2002-10-29 11:18:35.000000000 +0000
@@ -231,9 +231,9 @@
 		}
 	} else if( vec == XICS_IRQ_SPURIOUS ) {
 		irq = -1;
-		printk("spurious PPC interrupt!\n");
-	} else
+	} else {
 		irq = real_irq_to_virt(vec) + XICS_IRQ_OFFSET;
+	}
 	return irq;
 }
 
@@ -285,6 +285,8 @@
 	struct device_node *np;
 	uint *ireg, ilen, indx=0;
 
+	ppc64_boot_msg(0x20, "XICS Init");
+
 	ibm_get_xive = rtas_token("ibm,get-xive");
 	ibm_set_xive = rtas_token("ibm,set-xive");
 	ibm_int_off = rtas_token("ibm,int-off");
@@ -347,6 +349,7 @@
 	np = find_type_devices("interrupt-controller");
 	if (!np) {
 		printk(KERN_WARNING "xics:  no ISA Interrupt Controller\n");
+		xics_irq_8259_cascade_real = -1;
 		xics_irq_8259_cascade = -1;
 	} else {
 		ireg = (uint *) get_property(np, "interrupts", 0);
@@ -399,6 +402,7 @@
 	request_irq(XICS_IPI + XICS_IRQ_OFFSET, xics_ipi_action, 0, "IPI", 0);
 	irq_desc[XICS_IPI+XICS_IRQ_OFFSET].status |= IRQ_PER_CPU;
 #endif
+	ppc64_boot_msg(0x21, "XICS Done");
 }
 
 void xics_isa_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/lib/string.S linux-2.4.20/arch/ppc64/lib/string.S
--- linux-2.4.19/arch/ppc64/lib/string.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/lib/string.S	2002-10-29 11:18:35.000000000 +0000
@@ -351,9 +351,9 @@
 #endif /* MAX_COPY_PREFETCH */
 
 	mtctr	r0
-53:
 	dcbt	r3,r4
-	dcbz	r11,r6
+53:
+54:	dcbz	r11,r6
 /* had to move these to keep extable in order */
 	.section __ex_table,"a"
 	.align	3
@@ -361,7 +361,7 @@
 	.llong	71b,101f
 	.llong	72b,102f
 	.llong	73b,103f
-	.llong	53b,105f
+	.llong	54b,105f
 	.text
 /* the main body of the cacheline loop */
 	COPY_16_BYTES_WITHEX(0)
@@ -504,11 +504,11 @@
 	add	r4,r0,r4
 	subf	r6,r0,r6
 	srwi	r0,r4,2
+	andi.	r4,r4,3
 	mtctr	r0
-	bdz	6f
+	bdz	7f
 1:	stwu	r5,4(r6)
 	bdnz	1b
-6:	andi.	r4,r4,3
 	/* clear byte sized chunks */
 7:	cmpwi	0,r4,0
 	beqlr
@@ -517,14 +517,20 @@
 8:	stbu	r5,1(r6)
 	bdnz	8b
 	blr
-99:	li	r3,-EFAULT
+90:	mr	r3,r4
+	blr
+91:	mfctr	r3
+	slwi	r3,r3,2
+	add	r3,r3,r4
+	blr
+92:	mfctr	r3
 	blr
 
 	.section __ex_table,"a"
 	.align	3
-	.llong	11b,99b
-	.llong	1b,99b
-	.llong	8b,99b
+	.llong	11b,90b
+	.llong	1b,91b
+	.llong	8b,92b
 	.text
 
 _GLOBAL(__strncpy_from_user)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/mm/fault.c linux-2.4.20/arch/ppc64/mm/fault.c
--- linux-2.4.19/arch/ppc64/mm/fault.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/mm/fault.c	2002-10-29 11:18:38.000000000 +0000
@@ -38,7 +38,11 @@
 
 #include <asm/ppcdebug.h>
 
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+#if defined(CONFIG_KDB)
+#include <linux/kdb.h>
+#endif
+	
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) || defined(CONFIG_KDB)
 extern void (*debugger)(struct pt_regs *);
 extern void (*debugger_fault_handler)(struct pt_regs *);
 extern int (*debugger_dabr_match)(struct pt_regs *);
@@ -118,7 +122,7 @@
 
 good_area:
 	code = SEGV_ACCERR;
-	
+
 	/* a write */
 	if (is_write) {
 		if (!(vma->vm_flags & VM_WRITE))
@@ -159,7 +163,7 @@
 
 bad_area:
 	up_read(&mm->mmap_sem);
-	
+
 	/* User mode accesses cause a SIGSEGV */
 	if (user_mode(regs)) {
 		info.si_signo = SIGSEGV;
@@ -224,8 +228,10 @@
 	if (debugger_kernel_faults)
 		debugger(regs);
 #endif
+#if defined(CONFIG_KDB)
+	kdb(KDB_REASON_FAULT, regs->trap, regs);
+#endif	
 	print_backtrace( (unsigned long *)regs->gpr[1] );
 	panic("kernel access of bad area pc %lx lr %lx address %lX tsk %s/%d",
 	      regs->nip,regs->link,address,current->comm,current->pid);
 }
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/mm/init.c linux-2.4.20/arch/ppc64/mm/init.c
--- linux-2.4.19/arch/ppc64/mm/init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/mm/init.c	2002-10-29 11:18:34.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- *  
- *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
@@ -214,7 +212,7 @@
 	else {
 		ea = ioremap_bot;
 		ioremap_bot += size;
-        }
+	}
 
 	if ((flags & _PAGE_PRESENT) == 0)
 		flags |= pgprot_val(PAGE_KERNEL);
@@ -231,9 +229,9 @@
 void iounmap(void *addr) 
 {
 #ifdef CONFIG_PPC_ISERIES
-     /* iSeries I/O Remap is a noop              */
+	/* iSeries I/O Remap is a noop              */
 	return;
-#else 
+#else
 	/* DRENG / PPPBBB todo */
 	return;
 #endif
@@ -264,7 +262,7 @@
 		/* If the mm subsystem is not fully up, we cannot create a
 		 * linux page table entry for this mapping.  Simply bolt an
 		 * entry in the hardware page table. 
- 		 */
+		 */
 		vsid = get_kernel_vsid(ea);
 		make_pte(htab_data.htab,
 			(vsid << 28) | (ea & 0xFFFFFFF), // va (NOT the ea)
@@ -434,12 +432,11 @@
 }
 #endif
 
-
-
 /*
  * Do very early mm setup.
  */
-void __init mm_init_ppc64(void) {
+void __init mm_init_ppc64(void)
+{
 	struct paca_struct *lpaca;
 	unsigned long guard_page, index;
 
@@ -467,8 +464,6 @@
 	ppc_md.progress("MM:exit", 0x211);
 }
 
-
-
 /*
  * Initialize the bootmem system and give it all the memory we
  * have available.
@@ -488,7 +483,7 @@
 	bootmap_pages = bootmem_bootmap_pages(total_pages);
 
 	start = (unsigned long)__a2p(lmb_alloc(bootmap_pages<<PAGE_SHIFT, PAGE_SIZE));
-	if( start == 0 ) {
+	if (start == 0) {
 		udbg_printf("do_init_bootmem: failed to allocate a bitmap.\n");
 		udbg_printf("\tbootmap_pages = 0x%lx.\n", bootmap_pages);
 		PPCDBG_ENTER_DEBUGGER(); 
@@ -502,7 +497,7 @@
 	PPCDBG(PPCDBG_MMINIT, "\tboot_mapsize        = 0x%lx\n", boot_mapsize);
 
 	/* add all physical memory to the bootmem map */
-	for (i=0; i < lmb.memory.cnt ;i++) {
+	for (i=0; i < lmb.memory.cnt; i++) {
 		unsigned long physbase, size;
 		unsigned long type = lmb.memory.region[i].type;
 
@@ -514,7 +509,7 @@
 		free_bootmem(physbase, size);
 	}
 	/* reserve the sections we're already using */
-	for (i=0; i < lmb.reserved.cnt ;i++) {
+	for (i=0; i < lmb.reserved.cnt; i++) {
 		unsigned long physbase = lmb.reserved.region[i].physbase;
 		unsigned long size = lmb.reserved.region[i].size;
 #if 0 /* PPPBBB */
@@ -538,19 +533,12 @@
 	/*
 	 * All pages are DMA-able so we put them all in the DMA zone.
 	 */
-	zones_size[0] = lmb_end_of_DRAM() >> PAGE_SHIFT;
+	zones_size[ZONE_DMA] = lmb_end_of_DRAM() >> PAGE_SHIFT;
 	for (i = 1; i < MAX_NR_ZONES; i++)
 		zones_size[i] = 0;
 	free_area_init(zones_size);
 }
 
-extern unsigned long prof_shift;
-extern unsigned long prof_len;
-extern unsigned int * prof_buffer;
-extern unsigned long dprof_shift;
-extern unsigned long dprof_len;
-extern unsigned int * dprof_buffer;
-
 void initialize_paca_hardware_interrupt_stack(void);
 
 void __init mem_init(void)
@@ -609,10 +597,6 @@
 
 #ifdef CONFIG_PPC_ISERIES
 	create_virtual_bus_tce_table();
-	/* HACK HACK This allows the iSeries profiling to use /proc/profile */
-	prof_shift = dprof_shift;
-	prof_len = dprof_len;
-	prof_buffer = dprof_buffer;
 #endif
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/xmon/privinst.h linux-2.4.20/arch/ppc64/xmon/privinst.h
--- linux-2.4.19/arch/ppc64/xmon/privinst.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/xmon/privinst.h	2002-10-29 11:18:33.000000000 +0000
@@ -6,7 +6,6 @@
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.
  */
-#include <linux/config.h>
 
 #define GETREG(reg)		\
     static inline unsigned long get_ ## reg (void)	\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/xmon/start.c linux-2.4.20/arch/ppc64/xmon/start.c
--- linux-2.4.19/arch/ppc64/xmon/start.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/xmon/start.c	2002-10-29 11:18:32.000000000 +0000
@@ -9,6 +9,7 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/sysrq.h>
+#include <linux/fs.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/page.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/ppc64/xmon/xmon.c linux-2.4.20/arch/ppc64/xmon/xmon.c
--- linux-2.4.19/arch/ppc64/xmon/xmon.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/ppc64/xmon/xmon.c	2002-10-29 11:18:35.000000000 +0000
@@ -123,12 +123,10 @@
 static void mem_check(void);
 static void mem_find_real(void);
 static void mem_find_vsid(void);
-static void mem_check_full_group(void);
 static void mem_check_pagetable_vsids (void);
 
 static void mem_map_check_slab(void);
 static void mem_map_lock_pages(void);
-static void mem_map_check_hash(void);
 static void mem_check_dup_rpn (void);
 static void debug_trace(void);
 
@@ -191,13 +189,6 @@
 	asm volatile("sync; isync");
 }
 
-extern inline void __delay(unsigned int loops)
-{
-	if (loops != 0)
-		__asm__ __volatile__("mtctr %0; 1: bdnz 1b" : :
-				     "r" (loops) : "ctr");
-}
-
 /* (Ref: 64-bit PowerPC ELF ABI Spplement; Ian Lance Taylor, Zembu Labs).
  A PPC stack frame looks like this:
 
@@ -544,7 +535,7 @@
 		}
 	}
 
-	if (!__is_processor(PV_POWER4)) {
+	if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) {
 		if (dabr.enabled)
 			set_dabr(dabr.address);
 		if (iabr.enabled)
@@ -561,7 +552,7 @@
 
 	if (naca->platform != PLATFORM_PSERIES)
 		return;
-	if (!__is_processor(PV_POWER4)) {
+	if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) {
 		set_dabr(0);
 		set_iabr(0);
 	}
@@ -634,15 +625,9 @@
 			case 'c':
 				mem_check();
 				break;
-			case 'g':
-				mem_check_full_group();
-				break;
 			case 'j':
 				mem_map_check_slab();
 				break;
-			case 'h':
-				mem_map_check_hash();
-				break;
 			case 'f':
 				mem_find_real();
 				break;
@@ -864,7 +849,7 @@
 	cmd = inchar();
 	switch (cmd) {
 	case 'd':	/* bd - hardware data breakpoint */
-		if (__is_processor(PV_POWER4)) {
+		if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) {
 			printf("Not implemented on POWER4\n");
 			break;
 		}
@@ -884,8 +869,7 @@
 			dabr.address = (dabr.address & ~7) | mode;
 		break;
 	case 'i':	/* bi - hardware instr breakpoint */
-		if (__is_processor(PV_POWER4)) {
-			printf("Not implemented on POWER4\n");
+		if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) {
 			break;
 		}
 		iabr.address = 0;
@@ -2490,34 +2474,6 @@
 	printf(" count of locked pages = %d \n", lock_count); 
 }
 
-
-
-void mem_map_check_hash()
-{
-	int i = max_mapnr;
-	
-	while (i-- > 0)  {
-		/* skip the reserved */
-		if (!PageReserved(mem_map+i)) {
-			if (((mem_map+i)->next_hash) != NULL) {
-				if ( REGION_ID((mem_map+i)->next_hash) != KERNEL_REGION_ID ) {
-					printf(" mem_map check hash - non c0 entry - "
-					       "address/value = %p %lx\n", mem_map+i,(mem_map+i)->next_hash);
-				} 
-				if ((unsigned long)((mem_map+i)->next_hash) ==  KERNELBASE){
-					printf(" mem_map check hash - 0x%lx  entry = %p \n",
-					       KERNELBASE, mem_map+i);
-				} 
-			}
-		} else {
-			if (page_count(mem_map+i) < 0) {
-				printf(" reserved page with negative count- entry = %lx \n", mem_map+i);
-			}
-		}
-	}
-	printf(" mem_map check hash completed \n");
-}
-
 void mem_check_dup_rpn ()
 {
 	unsigned long htab_size_bytes;
@@ -2727,70 +2683,6 @@
 
 }
 
-
-void mem_check_full_group()
-{
-	unsigned long htab_size_bytes;
-	unsigned count;
-	unsigned count_array[] = {0,0,0,0,0,0,0,0,0}; 
-	unsigned i;
-	unsigned long htab_end;
-	HPTE *hpte1, *hpte2, *hpte3;
-	u64  rpn = 0;
-
-	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
-	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
-
-	printf("\nHardware Page Find full groups \n-------------------\n");
-	printf("htab base      : %.16lx\n", htab_data.htab);
-	printf("htab size      : %.16lx\n", htab_size_bytes);
-
-	for (hpte1 = htab_data.htab; (unsigned long)hpte1 < htab_end; hpte1= hpte1 + 8)
-	{
-		count = 0;
-		hpte2 = hpte1;
-		for (i=0; i<8; ++i)
-		{
-			if ( hpte2->dw0.dw0.v != 0 )
-			{
-				count++;
-			}
-			hpte2++;
-		}
-		if (count == 8 )
-		{
-			printf("  full group starting with entry %lx \n", hpte1);
-			hpte3 = hpte1;
-			for (i=0; i<8; ++i)
-			{
-				if ( hpte3->dw0.dw0.v != 0 )
-				{
-					printf(" entry number %d   \n",i);
-					printf("          vsid: %.13lx   api: %.2lx  hash: %.1lx\n", 
-					       (hpte3->dw0.dw0.avpn)>>5, 
-					       (hpte3->dw0.dw0.avpn) & 0x1f,
-					       (hpte3->dw0.dw0.h));
-					printf("          rpn: %.13lx \n", (hpte3->dw1.dw1.rpn)); 
-					// Dump out the memmap array entry address, corresponding virtual address, and reference count.
-					rpn = hpte3->dw1.dw1.rpn;
-					printf("          mem_map+rpn=%p, virtual@=%p, count=%lx \n", mem_map+rpn, (mem_map+rpn)->virtual, (mem_map+rpn)->count);
-				}
-				hpte3++;
-			}
-			if (xmon_interrupted())
-				return;
-		}
-
-		count_array[count]++;
-	}
-	for (i=1; i<9; ++i)
-	{
-		printf("  group count for size  %i = %lx \n", i, count_array[i]);
-	}
-
-	printf("\nDone -------------------\n");
-}
-
 static void debug_trace(void) {
         unsigned long val, cmd, on;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390/config.in linux-2.4.20/arch/s390/config.in
--- linux-2.4.19/arch/s390/config.in	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390/config.in	2002-10-29 11:18:35.000000000 +0000
@@ -75,3 +75,4 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
 
+source lib/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390/defconfig linux-2.4.20/arch/s390/defconfig
--- linux-2.4.19/arch/s390/defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390/defconfig	2002-10-29 11:18:36.000000000 +0000
@@ -32,6 +32,8 @@
 # General setup
 #
 CONFIG_FAST_IRQ=y
+CONFIG_MACHCHK_WARNING=y
+CONFIG_CHSC=y
 CONFIG_IPL=y
 # CONFIG_IPL_TAPE is not set
 CONFIG_IPL_VM=y
@@ -146,9 +148,10 @@
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 CONFIG_IPV6=m
+CONFIG_SHARED_IPV6_CARDS=y
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
+CONFIG_VLAN_8021Q=m
 
 #
 #  
@@ -163,7 +166,7 @@
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-CONFIG_NET_FASTROUTE=y
+# CONFIG_NET_FASTROUTE is not set
 # CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390/kernel/debug.c linux-2.4.20/arch/s390/kernel/debug.c
--- linux-2.4.19/arch/s390/kernel/debug.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390/kernel/debug.c	2002-10-29 11:18:33.000000000 +0000
@@ -443,6 +443,7 @@
 {
 	size_t count = 0;
 	size_t entry_offset, size = 0;
+	int rc;
 	file_private_info_t *p_info;
 
 	p_info = ((file_private_info_t *) file->private_data);
@@ -458,9 +459,9 @@
 		size = MIN((len - count), (size - entry_offset));
 
 		if(size){
-			if (copy_to_user(user_buf + count, 
-					p_info->temp_buf + entry_offset, size))
-				return count ? count: -EFAULT;
+			if ((rc = copy_to_user(user_buf + count, 
+					p_info->temp_buf + entry_offset, size)))
+			return rc;
 		}
 		count += size;
 		entry_offset = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390/kernel/entry.S linux-2.4.20/arch/s390/kernel/entry.S
--- linux-2.4.19/arch/s390/kernel/entry.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390/kernel/entry.S	2002-10-29 11:18:34.000000000 +0000
@@ -221,11 +221,11 @@
 # call trace before and after sys_call
 #
 sysc_tracesys:
-	la	%r12,BASED(sysc_return)
+	la	%r11,BASED(sysc_return)
 
 #
 # call syscall_trace before and after system call
-# special linkage: %r12 contains the return address for trace_svc
+# special linkage: %r11 contains the return address for trace_svc
 #
 trace_svc:
         l       %r1,BASED(.Ltrace)
@@ -244,7 +244,7 @@
         basr    %r14,%r8          # call sys_xxx
         st      %r2,SP_R2(%r15)   # store return value
         l       %r1,BASED(.Ltrace)
-	lr	%r14,%r12	  # return point is in %r12
+	lr	%r14,%r11	  # return point is in %r11
         br      %r1
 
 #
@@ -678,7 +678,7 @@
 # call trace before and after sys_call
 #
 pgm_tracesys:
-	la	%r12,BASED(pgm_svcret)
+	la	%r11,BASED(pgm_svcret)
 	b	BASED(trace_svc)
 
 /*
@@ -758,25 +758,25 @@
 	SAVE_ALL_BASE
         SAVE_ALL __LC_EXT_OLD_PSW,0
         GET_CURRENT                    # load pointer to task_struct to R9
-        la      %r2,SP_PTREGS(%r15)    # address of register-save area
-        lh      %r3,__LC_EXT_INT_CODE  # error code
-        lr      %r1,%r3                # calculate index = code & 0xff
-        n       %r1,BASED(.Lc0xff)
-        sll     %r1,2
-        l       %r4,BASED(.Lext_hash)
-        l       %r4,0(%r1,%r4)         # get first list entry for hash value
-        ltr     %r4,%r4                # == NULL ?
-        bz      BASED(io_return)       # yes, nothing to do, exit
+	lh	%r6,__LC_EXT_INT_CODE  # get interruption code
+	lr	%r1,%r6		       # calculate index = code & 0xff
+	n	%r1,BASED(.Lc0xff)
+	sll	%r1,2
+	l	%r7,BASED(.Lext_hash)
+	l	%r7,0(%r1,%r7)	       # get first list entry for hash value
+	ltr	%r7,%r7		       # == NULL ?
+	bz	BASED(io_return)       # yes, nothing to do, exit
 ext_int_loop:
-        ch      %r3,8(%r4)             # compare external interrupt code
-        be      BASED(ext_int_found)
-        icm     %r4,15,0(%r4)          # next list entry
-        bnz     BASED(ext_int_loop)
-        b       BASED(io_return)
-ext_int_found:
-        l       %r4,4(%r4)             # get handler address
-        la      %r14,BASED(io_return)
-        br      %r4                    # branch to ext call handler
+	ch	%r6,8(%r7)	       # compare external interrupt code
+	bne	BASED(ext_int_next)
+	l	%r1,4(%r7)	       # get handler address
+	la	%r2,SP_PTREGS(%r15)    # address of register-save area
+	lr	%r3,%r6		       # interruption code
+	basr	%r14,%r1	       # call handler
+ext_int_next:
+	icm	%r7,15,0(%r7)	       # next list entry
+	bnz	BASED(ext_int_loop)
+	b	BASED(io_return)
 
 /*
  * Machine check handler routines
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390/kernel/ieee.h linux-2.4.20/arch/s390/kernel/ieee.h
--- linux-2.4.19/arch/s390/kernel/ieee.h	2000-05-12 18:41:44.000000000 +0000
+++ linux-2.4.20/arch/s390/kernel/ieee.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,90 +0,0 @@
-/*
- *  arch/s390/kernel/ieee.h
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
- */
-
-#include <linux/sched.h>
-
-static    inline void _adddf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = current->tss.fprs[R1].fd +
-                             current->tss.fprs[R2].fd;
-}
-
-static    inline void _subdf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = current->tss.fprs[R1].fd -
-                             current->tss.fprs[R2].fd;
-}
-
-static    inline void _muldf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = current->tss.fprs[R1].fd *
-                             current->tss.fprs[R2].fd;
-}
-
-static    inline void _divdf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = current->tss.fprs[R1].fd /
-                             current->tss.fprs[R2].fd;
-}
-
-static    inline void _negdf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = -current->tss.fprs[R1].fd;
-}
-
-static    inline void _fixdfsi(int R1,int R2)
-{
-  current->tss.regs->gprs[R1] = (__u32) current->tss.fprs[R2].fd;
-}
-
-static    inline void _extendsidf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = (double) current->tss.regs->gprs[R2];
-}
-
-
-static    inline  void _addsf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = current->tss.fprs[R1].ff +
-                             current->tss.fprs[R2].ff;
-}
-
-static    inline  void _subsf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = current->tss.fprs[R1].ff -
-                             current->tss.fprs[R2].ff;
-}
-
-static    inline void _mulsf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = current->tss.fprs[R1].ff *
-                             current->tss.fprs[R2].ff;
-}
-
-static    inline void _divsf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = current->tss.fprs[R1].ff /
-                             current->tss.fprs[R2].ff;
-}
-
-static    inline void _negsf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = -current->tss.fprs[R1].ff;
-}
-
-static    inline void _fixsfsi(int R1,int R2)
-{
-  current->tss.regs->gprs[R1] = (__u32) current->tss.fprs[R2].ff;
-}
-
-static    inline void _extendsisf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = (double) current->tss.regs->gprs[R2];
-}
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390/kernel/ptrace.c linux-2.4.20/arch/s390/kernel/ptrace.c
--- linux-2.4.19/arch/s390/kernel/ptrace.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390/kernel/ptrace.c	2002-10-29 11:18:49.000000000 +0000
@@ -121,10 +121,11 @@
 		else
 		{
 			if(realuseraddr==(addr_t)NULL)
-				retval=(clear_user((void *)copyaddr,len)==-EFAULT ? -EIO:0);
+				retval=clear_user((void *)copyaddr,len);
 			else
-				retval=(copy_to_user((void *)copyaddr,(void *)realuseraddr,len)==-EFAULT ? -EIO:0);
+				retval=copy_to_user((void *)copyaddr,(void *)realuseraddr,len);
 		}      
+		retval = retval ? -EFAULT : 0;
 	}
 	else
 	{
@@ -235,16 +236,18 @@
 	ret = -ESRCH;
 	read_lock(&tasklist_lock);
 	child = find_task_by_pid(pid);
+	if (child)
+		get_task_struct(child);
 	read_unlock(&tasklist_lock);
 	if (!child)
 		goto out;
 	ret = -EPERM;
 	if (pid == 1)		/* you may not mess with init */
-		goto out;
+		goto out_tsk;
 	if (request == PTRACE_ATTACH) 
 	{
 		ret = ptrace_attach(child);
-		goto out;
+		goto out_tsk;
 	}
 	ret = -ESRCH;
 	// printk("child=%lX child->flags=%lX",child,child->flags);
@@ -253,14 +256,14 @@
 	if(child!=current)
 	{
 		if (!(child->ptrace & PT_PTRACED))
-			goto out;
+			goto out_tsk;
 		if (child->state != TASK_STOPPED) 
 		{
 			if (request != PTRACE_KILL)
-				goto out;
+				goto out_tsk;
 		}
 		if (child->p_pptr != current)
-			goto out;
+			goto out_tsk;
 	}
 	switch (request) 
 	{
@@ -270,9 +273,9 @@
 		copied = access_process_vm(child,ADDR_BITS_REMOVE(addr), &tmp, sizeof(tmp), 0);
 		ret = -EIO;
 		if (copied != sizeof(tmp))
-			goto out;
+			break;
 		ret = put_user(tmp,(unsigned long *) data);
-		goto out;
+		break;
 
 		/* read the word at location addr in the USER area. */
 	case PTRACE_PEEKUSR:
@@ -284,9 +287,8 @@
 	case PTRACE_POKEDATA:
 		ret = 0;
 		if (access_process_vm(child,ADDR_BITS_REMOVE(addr), &data, sizeof(data), 1) == sizeof(data))
-			goto out;
+			break;
 		ret = -EIO;
-		goto out;
 		break;
 
 	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
@@ -343,14 +345,15 @@
 	case PTRACE_POKEUSR_AREA:
 		if(copy_from_user(&parea,(void *)addr,sizeof(parea))==0)  
 			ret=copy_user(child,parea.kernel_addr,parea.process_addr,
-				 parea.len,1,(request==PTRACE_POKEUSR_AREA));
-		else
-			ret = -EFAULT;
+				      parea.len,1,(request==PTRACE_POKEUSR_AREA));
+		else ret = -EFAULT;
 		break;
 	default:
 		ret = -EIO;
 		break;
 	}
+ out_tsk:
+	free_task_struct(child);
  out:
 	unlock_kernel();
 	return ret;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390/kernel/s390_ext.c linux-2.4.20/arch/s390/kernel/s390_ext.c
--- linux-2.4.19/arch/s390/kernel/s390_ext.c	2001-07-25 21:12:01.000000000 +0000
+++ linux-2.4.20/arch/s390/kernel/s390_ext.c	2002-10-29 11:18:40.000000000 +0000
@@ -21,34 +21,31 @@
  * iucv and 0x2603 pfault) this is always the first element. 
  */
 ext_int_info_t *ext_int_hash[256] = { 0, };
-ext_int_info_t ext_int_info_timer;
-ext_int_info_t ext_int_info_hwc;
-ext_int_info_t ext_int_pfault;
 
 int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
         ext_int_info_t *p;
         int index;
 
-        index = code & 0xff;
-        p = ext_int_hash[index];
-        while (p != NULL) {
-                if (p->code == code)
-                        return -EBUSY;
-                p = p->next;
-        }
-        if (code == 0x1004) /* time_init is done before kmalloc works :-/ */
-                p = &ext_int_info_timer;
-        else if (code == 0x2401) /* hwc_init is done too early too */
-                p = &ext_int_info_hwc;
-        else if (code == 0x2603) /* pfault_init is done too early too */
-		p = &ext_int_pfault;
-	else
-                p = (ext_int_info_t *)
-                          kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
+	p = (ext_int_info_t *) kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
         if (p == NULL)
                 return -ENOMEM;
         p->code = code;
         p->handler = handler;
+        index = code & 0xff;
+        p->next = ext_int_hash[index];
+        ext_int_hash[index] = p;
+        return 0;
+}
+
+int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+				      ext_int_info_t *p) {
+        int index;
+
+        if (p == NULL)
+                return -EINVAL;
+        p->code = code;
+        p->handler = handler;
+        index = code & 0xff;
         p->next = ext_int_hash[index];
         ext_int_hash[index] = p;
         return 0;
@@ -73,11 +70,33 @@
                 q->next = p->next;
         else
                 ext_int_hash[index] = p->next;
-        if (code != 0x1004 && code != 0x2401 && code != 0x2603)
-                kfree(p);
+	kfree(p);
         return 0;
 }
 
+int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+					ext_int_info_t *p) {
+	ext_int_info_t *q;
+	int index;
+
+	if (p == NULL || p->code != code || p->handler != handler)
+		return -EINVAL;
+	index = code & 0xff;
+	q = ext_int_hash[index];
+	if (p != q) {
+		while (q != NULL) {
+			if (q->next == p)
+				break;
+			q = q->next;
+		}
+		if (q == NULL)
+			return -ENOENT;
+		q->next = p->next;
+	} else
+		ext_int_hash[index] = p->next;
+	return 0;
+}
+
 EXPORT_SYMBOL(register_external_interrupt);
 EXPORT_SYMBOL(unregister_external_interrupt);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390/kernel/s390_ksyms.c linux-2.4.20/arch/s390/kernel/s390_ksyms.c
--- linux-2.4.19/arch/s390/kernel/s390_ksyms.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390/kernel/s390_ksyms.c	2002-10-29 11:18:32.000000000 +0000
@@ -9,6 +9,7 @@
 #include <asm/checksum.h>
 #include <asm/delay.h>
 #include <asm/setup.h>
+#include <asm/softirq.h>
 #if CONFIG_IP_MULTICAST
 #include <net/arp.h>
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390/kernel/setup.c linux-2.4.20/arch/s390/kernel/setup.c
--- linux-2.4.19/arch/s390/kernel/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390/kernel/setup.c	2002-10-29 11:18:33.000000000 +0000
@@ -165,15 +165,15 @@
 static int __init conmode_setup(char *str)
 {
 #if defined(CONFIG_HWC_CONSOLE)
-	if (strncmp(str, "hwc", 4) == 0 && !MACHINE_IS_P390)
+	if (strncmp(str, "hwc", 4) == 0)
                 SET_CONSOLE_HWC;
 #endif
 #if defined(CONFIG_TN3215_CONSOLE)
-	if (strncmp(str, "3215", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+	if (strncmp(str, "3215", 5) == 0)
 		SET_CONSOLE_3215;
 #endif
 #if defined(CONFIG_TN3270_CONSOLE)
-	if (strncmp(str, "3270", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+	if (strncmp(str, "3270", 5) == 0)
 		SET_CONSOLE_3270;
 #endif
         return 1;
@@ -233,32 +233,63 @@
 	}
 }
 
+#ifdef CONFIG_SMP
+extern void machine_restart_smp(char *);
+extern void machine_halt_smp(void);
+extern void machine_power_off_smp(void);
+
+void (*_machine_restart)(char *command) = machine_restart_smp;
+void (*_machine_halt)(void) = machine_halt_smp;
+void (*_machine_power_off)(void) = machine_power_off_smp;
+#else
 /*
  * Reboot, halt and power_off routines for non SMP.
  */
-
-#ifndef CONFIG_SMP
-void machine_restart(char * __unused)
+static void do_machine_restart_nonsmp(char * __unused)
 {
 	reipl(S390_lowcore.ipl_device);
 }
 
-void machine_halt(void)
+static void do_machine_halt_nonsmp(void)
 {
         if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
                 cpcmd(vmhalt_cmd, NULL, 0);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
 
-void machine_power_off(void)
+static void do_machine_power_off_nonsmp(void)
 {
         if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
                 cpcmd(vmpoff_cmd, NULL, 0);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
+
+void (*_machine_restart)(char *command) = do_machine_restart_nonsmp;
+void (*_machine_halt)(void) = do_machine_halt_nonsmp;
+void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
 #endif
 
 /*
+ * Reboot, halt and power_off stubs. They just call _machine_restart,
+ * _machine_halt or _machine_power_off. 
+ */
+
+void machine_restart(char *command)
+{
+	_machine_restart(command);
+}
+
+void machine_halt(void)
+{
+	_machine_halt();
+}
+
+void machine_power_off(void)
+{
+	_machine_power_off();
+}
+
+/*
  * Setup function called from init/main.c just after the banner
  * was printed.
  */
@@ -497,7 +528,7 @@
 	}
 	if (cpu_online_map & (1 << n)) {
 		cpuinfo = &safe_get_cpu_lowcore(n)->cpu_data;
-		seq_printf(m, "processor %i: "
+		seq_printf(m, "processor %li: "
 			       "version = %02X,  "
 			       "identification = %06X,  "
 			       "machine = %04X\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390/kernel/signal.c linux-2.4.20/arch/s390/kernel/signal.c
--- linux-2.4.19/arch/s390/kernel/signal.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390/kernel/signal.c	2002-10-29 11:18:35.000000000 +0000
@@ -335,6 +335,10 @@
 			goto give_sigsegv;
 	}
 
+	/* Set up backchain. */
+	if (__put_user(regs->gprs[15], (addr_t *) frame))
+		goto give_sigsegv;
+
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (addr_t)frame;
 	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
@@ -388,6 +392,10 @@
 	                          (u16 *)(frame->retcode));
 	}
 
+	/* Set up backchain. */
+	if (__put_user(regs->gprs[15], (addr_t *) frame))
+		goto give_sigsegv;
+
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (addr_t)frame;
 	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390/kernel/smp.c linux-2.4.20/arch/s390/kernel/smp.c
--- linux-2.4.19/arch/s390/kernel/smp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390/kernel/smp.c	2002-10-29 11:18:31.000000000 +0000
@@ -176,61 +176,132 @@
 	return 0;
 }
 
+static inline void do_send_stop(void)
+{
+        u32 dummy;
+        int i;
+
+        /* stop all processors */
+        for (i =  0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() != i) {
+                        int ccode;
+                        do {
+                                ccode = signal_processor_ps(
+                                   &dummy,
+                                   0,
+                                   i,
+                                   sigp_stop);
+                        } while(ccode == sigp_busy);
+                }
+        }
+}
+
+static inline void do_store_status(void)
+{
+        unsigned long low_core_addr;
+        u32 dummy;
+        int i;
+
+        /* store status of all processors in their lowcores (real 0) */
+        for (i =  0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() != i) {
+                        int ccode;
+                        low_core_addr = (unsigned long)get_cpu_lowcore(i);
+                        do {
+                                ccode = signal_processor_ps(
+                                   &dummy,
+                                   low_core_addr,
+                                   i,
+                                   sigp_store_status_at_address);
+                        } while(ccode == sigp_busy);
+                }
+        }
+}
 
 /*
- * Various special callbacks
+ * this function sends a 'stop' sigp to all other CPUs in the system.
+ * it goes straight through.
  */
-
-void do_machine_restart(void)
+void smp_send_stop(void)
 {
-        smp_send_stop();
-	reipl(S390_lowcore.ipl_device);
+        /* write magic number to zero page (absolute 0) */
+        get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC;
+
+	/* stop other processors. */
+	do_send_stop();
+
+	/* store status of other processors. */
+	do_store_status();
+}
+
+/*
+ * Reboot, halt and power_off routines for SMP.
+ */
+static volatile unsigned long cpu_restart_map;
+
+static void do_machine_restart(void * __unused)
+{
+	clear_bit(smp_processor_id(), &cpu_restart_map);
+	if (smp_processor_id() == 0) {
+		/* Wait for all other cpus to enter do_machine_restart. */
+		while (cpu_restart_map != 0);
+		/* Store status of other cpus. */
+		do_store_status();
+		/*
+		 * Finally call reipl. Because we waited for all other
+		 * cpus to enter this function we know that they do
+		 * not hold any s390irq-locks (the cpus have been
+		 * interrupted by an external interrupt and s390irq
+		 * locks are always held disabled).
+		 */
+		reipl(S390_lowcore.ipl_device);
+	}
+	signal_processor(smp_processor_id(), sigp_stop);
 }
 
-void machine_restart(char * __unused) 
+void machine_restart_smp(char * __unused) 
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_restart);
-		for (;;)
-			enabled_wait();
-        } else
-                do_machine_restart();
+	cpu_restart_map = cpu_online_map;
+        smp_call_function(do_machine_restart, NULL, 0, 0);
+	do_machine_restart(NULL);
 }
 
-void do_machine_halt(void)
+static void do_machine_halt(void * __unused)
 {
-        smp_send_stop();
-        if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
-                cpcmd(vmhalt_cmd, NULL, 0);
-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+	if (smp_processor_id() == 0) {
+		smp_send_stop();
+		if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
+			cpcmd(vmhalt_cmd, NULL, 0);
+		signal_processor(smp_processor_id(),
+				 sigp_stop_and_store_status);
+	}
+	for (;;)
+		enabled_wait();
 }
 
-void machine_halt(void)
+void machine_halt_smp(void)
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_halt);
-		for (;;)
-			enabled_wait();
-        } else
-                do_machine_halt();
+        smp_call_function(do_machine_halt, NULL, 0, 0);
+	do_machine_halt(NULL);
 }
 
-void do_machine_power_off(void)
+static void do_machine_power_off(void * __unused)
 {
-        smp_send_stop();
-        if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
-                cpcmd(vmpoff_cmd, NULL, 0);
-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+	if (smp_processor_id() == 0) {
+		smp_send_stop();
+		if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
+			cpcmd(vmpoff_cmd, NULL, 0);
+		signal_processor(smp_processor_id(),
+				 sigp_stop_and_store_status);
+	}
+	for (;;)
+		enabled_wait();
 }
 
-void machine_power_off(void)
+void machine_power_off_smp(void)
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_power_off);
-		for (;;)
-			enabled_wait();
-        } else
-                do_machine_power_off();
+        smp_call_function(do_machine_power_off, NULL, 0, 0);
+	do_machine_power_off(NULL);
 }
 
 /*
@@ -247,19 +318,11 @@
          *
          * For the ec_schedule signal we have to do nothing. All the work
          * is done automatically when we return from the interrupt.
-	 * For the ec_restart, ec_halt and ec_power_off we call the
-         * appropriate routine.
          */
         do {
                 bits = atomic_read(&S390_lowcore.ext_call_fast);
         } while (atomic_compare_and_swap(bits,0,&S390_lowcore.ext_call_fast));
 
-        if (test_bit(ec_restart, &bits))
-		do_machine_restart();
-        if (test_bit(ec_halt, &bits))
-		do_machine_halt();
-        if (test_bit(ec_power_off, &bits))
-		do_machine_power_off();
 	if (test_bit(ec_call_function, &bits)) 
 		do_call_function();
 }
@@ -288,7 +351,6 @@
 static void smp_ext_bitcall_others(ec_bit_sig sig)
 {
         struct _lowcore *lowcore;
-        sigp_ccode ccode;
         int i;
 
         for (i = 0; i < smp_num_cpus; i++) {
@@ -305,53 +367,6 @@
 }
 
 /*
- * this function sends a 'stop' sigp to all other CPUs in the system.
- * it goes straight through.
- */
-
-void smp_send_stop(void)
-{
-        int i;
-        u32 dummy;
-        unsigned long low_core_addr;
-
-        /* write magic number to zero page (absolute 0) */
-
-        get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC;
-
-        /* stop all processors */
-
-        for (i =  0; i < smp_num_cpus; i++) {
-                if (smp_processor_id() != i) {
-                        int ccode;
-                        do {
-                                ccode = signal_processor_ps(
-                                   &dummy,
-                                   0,
-                                   i,
-                                   sigp_stop);
-                        } while(ccode == sigp_busy);
-                }
-        }
-
-        /* store status of all processors in their lowcores (real 0) */
-
-        for (i =  0; i < smp_num_cpus; i++) {
-                if (smp_processor_id() != i) {
-                        int ccode;
-                        low_core_addr = (unsigned long)get_cpu_lowcore(i);
-                        do {
-                                ccode = signal_processor_ps(
-                                   &dummy,
-                                   low_core_addr,
-                                   i,
-                                   sigp_store_status_at_address);
-                        } while(ccode == sigp_busy);
-                }
-        }
-}
-
-/*
  * this function sends a 'purge tlb' signal to another CPU.
  */
 void smp_ptlb_callback(void *info)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390/kernel/time.c linux-2.4.20/arch/s390/kernel/time.c
--- linux-2.4.19/arch/s390/kernel/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390/kernel/time.c	2002-10-29 11:18:31.000000000 +0000
@@ -39,6 +39,7 @@
 
 #define TICK_SIZE tick
 
+static ext_int_info_t ext_int_info_timer;
 static uint64_t init_timer_cc;
 
 extern rwlock_t xtime_lock;
@@ -224,7 +225,8 @@
         tod_to_timeval(set_time_cc, &xtime);
 
         /* request the 0x1004 external interrupt */
-        if (register_external_interrupt(0x1004, do_comparator_interrupt) != 0)
+        if (register_early_external_interrupt(0x1004, do_comparator_interrupt,
+					      &ext_int_info_timer) != 0)
                 panic("Couldn't request external interrupt 0x1004");
 
         /* init CPU timer */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390/kernel/traps.c linux-2.4.20/arch/s390/kernel/traps.c
--- linux-2.4.19/arch/s390/kernel/traps.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390/kernel/traps.c	2002-10-29 11:18:36.000000000 +0000
@@ -58,6 +58,7 @@
 extern int pfault_init(void);
 extern void pfault_fini(void);
 extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
+static ext_int_info_t ext_int_pfault;
 #endif
 
 int kstack_depth_to_print = 12;
@@ -646,7 +647,8 @@
 #ifdef CONFIG_PFAULT
 	if (MACHINE_IS_VM) {
 		/* request the 0x2603 external interrupt */
-		if (register_external_interrupt(0x2603, pfault_interrupt) != 0)
+		if (register_early_external_interrupt(0x2603, pfault_interrupt,
+						      &ext_int_pfault) != 0)
 			panic("Couldn't request external interrupt 0x2603");
 		/*
 		 * First try to get pfault pseudo page faults going.
@@ -654,8 +656,9 @@
 		 */
 		if (pfault_init() != 0) {
 			/* Tough luck, no pfault. */
-			unregister_external_interrupt(0x2603,
-						      pfault_interrupt);
+			unregister_early_external_interrupt(0x2603,
+							    pfault_interrupt,
+							    &ext_int_pfault);
 			cpcmd("SET PAGEX ON", NULL, 0);
 		}
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390/mm/fault.c linux-2.4.20/arch/s390/mm/fault.c
--- linux-2.4.19/arch/s390/mm/fault.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390/mm/fault.c	2002-10-29 11:18:34.000000000 +0000
@@ -291,13 +291,11 @@
  * us unable to handle the page fault gracefully.
 */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
-		tsk->policy |= SCHED_YIELD;
-		schedule();
-		down_read(&mm->mmap_sem);
+		yield();
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (regs->psw.mask & PSW_PROBLEM_STATE)
 		do_exit(SIGKILL);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/config.in linux-2.4.20/arch/s390x/config.in
--- linux-2.4.19/arch/s390x/config.in	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390x/config.in	2002-10-29 11:18:33.000000000 +0000
@@ -40,6 +40,8 @@
 mainmenu_option next_comment
 comment 'General setup'
 bool 'Fast IRQ handling' CONFIG_FAST_IRQ
+bool 'Process warning machine checks' CONFIG_MACHCHK_WARNING
+bool 'Use chscs for Common I/O' CONFIG_CHSC
 bool 'Builtin IPL record support' CONFIG_IPL
 if [ "$CONFIG_IPL" = "y" ]; then
   choice 'IPL method generated into head.S' \
@@ -77,3 +79,4 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
 
+source lib/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/defconfig linux-2.4.20/arch/s390x/defconfig
--- linux-2.4.19/arch/s390x/defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390x/defconfig	2002-10-29 11:18:31.000000000 +0000
@@ -33,6 +33,8 @@
 # General setup
 #
 CONFIG_FAST_IRQ=y
+CONFIG_MACHCHK_WARNING=y
+CONFIG_CHSC=y
 CONFIG_IPL=y
 # CONFIG_IPL_TAPE is not set
 CONFIG_IPL_VM=y
@@ -146,9 +148,10 @@
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 CONFIG_IPV6=m
+CONFIG_SHARED_IPV6_CARDS=y
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
+CONFIG_VLAN_8021Q=m
 
 #
 #  
@@ -163,7 +166,7 @@
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-CONFIG_NET_FASTROUTE=y
+# CONFIG_NET_FASTROUTE is not set
 # CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/kernel/Makefile linux-2.4.20/arch/s390x/kernel/Makefile
--- linux-2.4.19/arch/s390x/kernel/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390x/kernel/Makefile	2002-10-29 11:18:38.000000000 +0000
@@ -34,6 +34,7 @@
 
 .PHONY: asm-offsets.h
 
+entry.S: asm-offsets.h
 #
 # This is just to get the dependencies...
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/kernel/debug.c linux-2.4.20/arch/s390x/kernel/debug.c
--- linux-2.4.19/arch/s390x/kernel/debug.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390x/kernel/debug.c	2002-10-29 11:18:33.000000000 +0000
@@ -443,6 +443,7 @@
 {
 	size_t count = 0;
 	size_t entry_offset, size = 0;
+	int rc;
 	file_private_info_t *p_info;
 
 	p_info = ((file_private_info_t *) file->private_data);
@@ -458,9 +459,9 @@
 		size = MIN((len - count), (size - entry_offset));
 
 		if(size){
-			if (copy_to_user(user_buf + count, 
-					p_info->temp_buf + entry_offset, size))
-				return count ? count : -EFAULT;
+			if ((rc = copy_to_user(user_buf + count, 
+					p_info->temp_buf + entry_offset, size)))
+			return rc;
 		}
 		count += size;
 		entry_offset = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/kernel/entry.S linux-2.4.20/arch/s390x/kernel/entry.S
--- linux-2.4.19/arch/s390x/kernel/entry.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390x/kernel/entry.S	2002-10-29 11:18:35.000000000 +0000
@@ -207,15 +207,15 @@
 # call trace before and after sys_call
 #
 sysc_tracesys:
-	larl	%r12,sysc_return
+	larl	%r11,sysc_return
 
 #
 # call syscall_trace before and after system call
-# special linkage: %r12 contains the return address for trace_svc
+# special linkage: %r11 contains the return address for trace_svc
 #
 trace_svc:
-	lghi    %r7,-ENOSYS
-	stg     %r7,SP_R2(%r15)     # give sysc_trace an -ENOSYS retval
+	lghi    %r0,-ENOSYS
+	stg     %r0,SP_R2(%r15)     # give sysc_trace an -ENOSYS retval
         brasl   %r14,syscall_trace
 	lg      %r2,SP_R2(%r15)
 	cghi    %r2,-ENOSYS
@@ -232,7 +232,7 @@
 	lg      %r2,SP_ORIG_R2(%r15)
         basr    %r14,%r8            # call sys_xxx
         stg     %r2,SP_R2(%r15)     # store return value
-	lgr	%r14,%r12	    # return point is in %r12
+	lgr	%r14,%r11	    # return point is in %r11
         jg      syscall_trace       # return point is sysc_return
 
 #
@@ -712,7 +712,7 @@
 # call trace before and after sys_call
 #
 pgm_tracesys:
-	larl	%r12,pgm_svcret
+	larl	%r11,pgm_svcret
 	j	trace_svc
 
 /*
@@ -786,26 +786,26 @@
 ext_int_handler:
         SAVE_ALL __LC_EXT_OLD_PSW,0
         GET_CURRENT                    # load pointer to task_struct to R9
-        la      %r2,SP_PTREGS(%r15)    # address of register-save area
-        llgh    %r3,__LC_EXT_INT_CODE  # error code
-        lgr     %r1,%r3                # calculate index = code & 0xff
-	nill    %r1,0xff
-        sll     %r1,3
-        larl    %r4,ext_int_hash
-        lg      %r4,0(%r1,%r4)         # get first list entry for hash value
-        ltgr    %r4,%r4                # == NULL ?
-        jz      io_return              # yes, nothing to do, exit
+	llgh	%r6,__LC_EXT_INT_CODE  # get interruption code
+	lgr	%r1,%r6		       # calculate index = code & 0xff
+	nill	%r1,0xff
+	sll	%r1,3
+	larl	%r7,ext_int_hash
+	lg	%r7,0(%r1,%r7)	       # get first list entry for hash value
+	ltgr	%r7,%r7		       # == NULL ?
+	jz	io_return	       # yes, nothing to do, exit
 ext_int_loop:
-        ch      %r3,16(%r4)            # compare external interrupt code
-        je      ext_int_found
-        lg      %r4,0(%r4)             # next list entry
-	ltgr    %r4,%r4
-        jnz     ext_int_loop
-        j       io_return
-ext_int_found:
-        lg      %r4,8(%r4)             # get handler address
-        larl    %r14,io_return
-        br      %r4                    # branch to ext call handler
+	ch	%r6,16(%r7)	       # compare external interrupt code
+	jne	ext_int_next
+	lg	%r1,8(%r7)	       # get handler address
+	la	%r2,SP_PTREGS(%r15)    # address of register-save area
+	lgr	%r3,%r6		       # interruption code
+	basr	%r14,%r1	       # call handler
+ext_int_next:
+	lg	%r7,0(%r7)	       # next list entry
+	ltgr	%r7,%r7
+	jnz	ext_int_loop
+	j	io_return
 
 /*
  * Machine check handler routines
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/kernel/head.S linux-2.4.20/arch/s390x/kernel/head.S
--- linux-2.4.19/arch/s390x/kernel/head.S	2001-11-09 21:58:02.000000000 +0000
+++ linux-2.4.20/arch/s390x/kernel/head.S	2002-10-29 11:18:33.000000000 +0000
@@ -326,7 +326,7 @@
         bnz   .Lrdcont
         st    %r2,INITRD_START+4-PARMAREA(%r12)# no ramdisk found, null it
 .Lrdcont:
-	l     %r2,INITRD_START-PARMAREA(%r12)
+	l     %r2,INITRD_START+4-PARMAREA(%r12)
 	clc   0(3,%r2),.L_hdr		       # skip HDRx and EOFx 
 	bz    .Lagain2
 	clc   0(3,%r2),.L_eof
@@ -555,6 +555,17 @@
 	oi     7(%r12),16               # set MVPG flag
 0:
 
+#
+# find out if the diag 0x44 works in 64 bit mode
+#
+	la     %r1,0f-.LPG1(%r13)	# set program check address
+	stg    %r1,__LC_PGM_NEW_PSW+8
+	mvc    __LC_DIAG44_OPCODE(8),.Lnop-.LPG1(%r13)
+	diag   0,0,0x44			# test diag 0x44
+	oi     7(%r12),32		# set diag44 flag
+	mvc    __LC_DIAG44_OPCODE(8),.Ldiag44-.LPG1(%r13)
+0:	
+
         lpswe .Lentry-.LPG1(13)         # jump to _stext in primary-space,
                                         # virtual and never return ...
         .align 16
@@ -578,6 +589,8 @@
 .Lpcmsk:.quad  0x0000000180000000
 .L4malign:.quad 0xffffffffffc00000
 .Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
+.Lnop:	.long  0x07000700
+.Ldiag44:.long 0x83000044
 
 	.org PARMAREA-64
 .Lduct:	.long 0,0,0,0,0,0,0,0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/kernel/process.c linux-2.4.20/arch/s390x/kernel/process.c
--- linux-2.4.19/arch/s390x/kernel/process.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390x/kernel/process.c	2002-10-29 11:18:34.000000000 +0000
@@ -183,6 +183,43 @@
         return 0;
 }
 
+/* 
+ * Allocation and freeing of basic task resources. 
+ * The task struct and the stack go together.
+ *
+ * NOTE: An order-2 allocation can easily fail.  If this
+ *       happens we fall back to using vmalloc ...
+ */
+
+struct task_struct *alloc_task_struct(void)
+{
+	struct task_struct *tsk = __get_free_pages(GFP_KERNEL, 2);
+	if (!tsk)
+		tsk = vmalloc(16384);
+	if (!tsk)
+		return NULL;
+
+        atomic_set((atomic_t *)(tsk + 1), 1);
+        return tsk;
+}
+
+void free_task_struct(struct task_struct *tsk)
+{
+	if (atomic_dec_and_test((atomic_t *)(tsk + 1)))
+	{
+		if ((unsigned long)tsk < VMALLOC_START)
+			free_pages((unsigned long)tsk, 2);
+		else
+			vfree(tsk);
+	}
+}
+
+void get_task_struct(struct task_struct *tsk)
+{
+	atomic_inc((atomic_t *)(tsk + 1));
+}
+
+
 asmlinkage int sys_fork(struct pt_regs regs)
 {
         return do_fork(SIGCHLD, regs.gprs[15], &regs, 0);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/kernel/ptrace.c linux-2.4.20/arch/s390x/kernel/ptrace.c
--- linux-2.4.19/arch/s390x/kernel/ptrace.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390x/kernel/ptrace.c	2002-10-29 11:18:33.000000000 +0000
@@ -38,6 +38,12 @@
 #include <asm/pgalloc.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#ifdef CONFIG_S390_SUPPORT
+#include "linux32.h"
+#else
+#define parent_31bit 0
+#endif
+
 
 void FixPerRegisters(struct task_struct *task)
 {
@@ -122,8 +128,8 @@
 				retval = clear_user(copyptr, len);
 			else
 				retval = copy_to_user(copyptr,realuserptr,len);
-                        retval = (retval == -EFAULT) ? -EIO : 0;
 		}      
+		retval = retval ? -EFAULT : 0;
 	} else {
 		if (writeuser)
 			memcpy(realuserptr, copyptr, len);
@@ -135,48 +141,180 @@
 	return retval;
 }
 
+#ifdef CONFIG_S390_SUPPORT
+
+typedef struct
+{
+	__u32 cr[3];
+} per_cr_words32  __attribute__((packed));
+
+typedef struct
+{
+	__u16          perc_atmid;          /* 0x096 */
+	__u32          address;             /* 0x098 */
+	__u8           access_id;           /* 0x0a1 */
+} per_lowcore_words32  __attribute__((packed));
+
+typedef struct
+{
+	union {
+		per_cr_words32   words;
+	} control_regs  __attribute__((packed));
+	/*
+	 * Use these flags instead of setting em_instruction_fetch
+	 * directly they are used so that single stepping can be
+	 * switched on & off while not affecting other tracing
+	 */
+	unsigned  single_step       : 1;
+	unsigned  instruction_fetch : 1;
+	unsigned                    : 30;
+	/*
+	 * These addresses are copied into cr10 & cr11 if single
+	 * stepping is switched off
+	 */
+	__u32     starting_addr;
+	__u32     ending_addr;
+	union {
+		per_lowcore_words32 words;
+	} lowcore; 
+} per_struct32 __attribute__((packed));
+
+struct user_regs_struct32
+{
+	_psw_t32 psw;
+	u32 gprs[NUM_GPRS];
+	u32 acrs[NUM_ACRS];
+	u32 orig_gpr2;
+	s390_fp_regs fp_regs;
+	/*
+	 * These per registers are in here so that gdb can modify them
+	 * itself as there is no "official" ptrace interface for hardware
+	 * watchpoints. This is the way intel does it.
+	 */
+	per_struct32 per_info;
+	u32  ieee_instruction_pointer; 
+	/* Used to give failing instruction back to user for ieee exceptions */
+};
+
+struct user32 {
+                                  /* We start with the registers, to mimic the way that "memory" is returned
+                                   from the ptrace(3,...) function.  */
+  struct user_regs_struct32 regs; /* Where the registers are actually stored */
+                                  /* The rest of this junk is to help gdb figure out what goes where */
+  u32 u_tsize;	                  /* Text segment size (pages). */
+  u32 u_dsize;	                  /* Data segment size (pages). */
+  u32 u_ssize;	                  /* Stack segment size (pages). */
+  u32 start_code;                 /* Starting virtual address of text. */
+  u32 start_stack;	          /* Starting virtual address of stack area.
+				   This is actually the bottom of the stack,
+				   the top of the stack is always found in the
+				   esp register.  */
+  s32 signal;     		  /* Signal that caused the core dump. */
+  u32 u_ar0;                      /* Used by gdb to help find the values for */
+				  /* the registers. */
+  u32 magic;		          /* To uniquely identify a core file */
+  char u_comm[32];		  /* User command that was responsible */
+};
+
+
+#define PT32_PSWMASK  0x0
+#define PT32_PSWADDR  0x04
+#define PT32_GPR0     0x08
+#define PT32_GPR15    0x44
+#define PT32_ACR0     0x48
+#define PT32_ACR15    0x84
+#define PT32_ORIGGPR2 0x88
+#define PT32_FPC      0x90
+#define PT32_FPR0_HI  0x98
+#define PT32_FPR15_LO 0x114
+#define PT32_CR_9     0x118
+#define PT32_CR_11    0x120
+#define PT32_IEEE_IP  0x13C
+#define PT32_LASTOFF  PT32_IEEE_IP
+#define PT32_ENDREGS  0x140-1
+#define U32OFFSETOF(member) offsetof(struct user32,regs.member)
+#define U64OFFSETOF(member) offsetof(struct user,regs.member)
+#define U6432DIFF(member) (U64OFFSETOF(member) - U32OFFSETOF(member))
+#define PT_SINGLE_STEP   (PT_CR_11+8)
+#define PT32_SINGLE_STEP (PT32_CR_11+4)
+
+#endif /* CONFIG_S390_SUPPORT */
+
 int copy_user(struct task_struct *task,saddr_t useraddr, addr_t copyaddr,
               int len, int tofromuser, int writingtouser)
 {
 	int copylen=0,copymax;
 	addr_t  realuseraddr;
 	saddr_t enduseraddr;
-	
 	unsigned long mask;
-
 #ifdef CONFIG_S390_SUPPORT
-	if (current->thread.flags & S390_FLAG_31BIT) {
-	/* adjust user offsets to 64 bit structure */
-		if (useraddr < PT_PSWADDR / 2)
-			useraddr = 2 * useraddr;
-		else if(useraddr < PT_ACR0 / 2)
-			useraddr = 2 * useraddr + sizeof(addr_t) / 2;
-		else if(useraddr < PT_ACR0 / 2 + (PT_ORIGGPR2 - PT_ACR0))
-			useraddr = useraddr + PT_ACR0 / 2;
-		else if(useraddr < PT_ACR0 / 2 + (sizeof(struct user_regs_struct) - sizeof(addr_t) / 2 - PT_ACR0))
-			useraddr = useraddr + PT_ACR0 / 2 + sizeof(addr_t) / 2; 
-        }
-#endif  
-    
+	int     parent_31bit=current->thread.flags & S390_FLAG_31BIT;
+	int     skip;
+#endif
 	enduseraddr=useraddr+len;
-
-	if (useraddr < 0 || enduseraddr > sizeof(struct user)||
-	   (useraddr < PT_ENDREGS && (useraddr&3))||
-	   (enduseraddr < PT_ENDREGS && (enduseraddr&3)))
+	if ((useraddr<0||useraddr&3||enduseraddr&3)||
+#ifdef CONFIG_S390_SUPPORT
+	    (parent_31bit && enduseraddr > sizeof(struct user32)) ||
+#endif
+	    enduseraddr > sizeof(struct user))
 		return (-EIO);
+
+#ifdef CONFIG_S390_SUPPORT
+	if(parent_31bit)
+	{
+		if(useraddr != PT32_PSWMASK)
+		{
+			if (useraddr == PT32_PSWADDR)
+				useraddr = PT_PSWADDR+4;
+			else if(useraddr <= PT32_GPR15)
+				useraddr = ((useraddr-PT32_GPR0)*2) + PT_GPR0+4;
+			else if(useraddr <= PT32_ACR15)
+				useraddr += PT_ACR0-PT32_ACR0;
+			else if(useraddr == PT32_ORIGGPR2)
+				useraddr = PT_ORIGGPR2+4;
+			else if(useraddr <= PT32_FPR15_LO)
+				useraddr += PT_FPR0-PT32_FPR0_HI;
+			else if(useraddr <= PT32_CR_11)
+				useraddr = ((useraddr-PT32_CR_9)*2) + PT_CR_9+4;
+			else if(useraddr ==  PT32_SINGLE_STEP)
+				useraddr = PT_SINGLE_STEP; 
+			else if(useraddr <= U32OFFSETOF(per_info.ending_addr))	
+				useraddr = (((useraddr-U32OFFSETOF(per_info.starting_addr)))*2) + 
+					U64OFFSETOF(per_info.starting_addr)+4;
+			else if( useraddr == U32OFFSETOF(per_info.lowcore.words.perc_atmid))
+				useraddr = U64OFFSETOF(per_info.lowcore.words.perc_atmid);
+			else if( useraddr == U32OFFSETOF(per_info.lowcore.words.address))
+				useraddr = U64OFFSETOF(per_info.lowcore.words.address)+4;
+			else if(useraddr == U32OFFSETOF(per_info.lowcore.words.access_id))
+				useraddr = U64OFFSETOF(per_info.lowcore.words.access_id);
+			else if(useraddr == PT32_IEEE_IP)
+				useraddr = PT_IEEE_IP+4;
+		}
+	}
+#endif /* CONFIG_S390_SUPPORT */
+
 	while(len>0)
 	{
+#ifdef CONFIG_S390_SUPPORT
+		skip=0;
+#endif
 		mask=PSW_ADDR_MASK;
 		if(useraddr<PT_FPC)
 		{
 			realuseraddr=((addr_t) __KSTK_PTREGS(task)) + useraddr;
-			if(useraddr<PT_PSWMASK)
+			if(useraddr<(PT_PSWMASK+8))
 			{
-				copymax=PT_PSWMASK;
-			}
-			else if(useraddr<(PT_PSWMASK+8))
-			{
-				copymax=(PT_PSWMASK+8);
+				if(parent_31bit)
+				{
+					copymax=PT_PSWMASK+4;
+#ifdef CONFIG_S390_SUPPORT
+					skip=8;
+#endif
+				}
+				else
+				{
+					copymax=PT_PSWMASK+8;
+				}
 				if(writingtouser)
 					mask=PSW_MASK_DEBUGCHANGE;
 			}
@@ -184,10 +322,25 @@
 			{
 				copymax=PT_PSWADDR+8;
 				mask=PSW_ADDR_DEBUGCHANGE;
+#ifdef CONFIG_S390_SUPPORT
+				if(parent_31bit)
+					skip=4;
+#endif
+
 			}
 			else
-				copymax=PT_FPC;
-			
+			{
+#ifdef CONFIG_S390_SUPPORT
+				if(parent_31bit && useraddr <= PT_GPR15+4)
+				{
+					copymax=useraddr+4;
+					if(useraddr<PT_GPR15+4)
+						skip=4;
+				}
+				else
+#endif
+					copymax=PT_FPC;
+			}
 		}
 		else if(useraddr<(PT_FPR15+sizeof(freg_t)))
 		{
@@ -196,7 +349,33 @@
 		}
 		else if(useraddr<sizeof(struct user_regs_struct))
 		{
-			copymax=sizeof(struct user_regs_struct);
+#ifdef CONFIG_S390_SUPPORT
+			if( parent_31bit && useraddr <= PT_IEEE_IP+4)
+			{
+				switch(useraddr)
+				{
+				case PT_CR_11+4:
+				case U64OFFSETOF(per_info.ending_addr)+4:
+				case U64OFFSETOF(per_info.lowcore.words.address)+4:
+					copymax=useraddr+4;
+					break;
+				case  PT_SINGLE_STEP:
+				case  U64OFFSETOF(per_info.lowcore.words.perc_atmid):
+					/* We copy 2 bytes in excess for the atmid member this also gets around */
+					/* alignment for this member in 32 bit */
+					skip=8;
+					copymax=useraddr+4;
+					break;
+				default: 
+					copymax=useraddr+4;
+					skip=4;
+				}
+			}
+			else
+#endif
+			{
+				copymax=sizeof(struct user_regs_struct);
+			}
 			realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]);
 		}
 		else 
@@ -210,7 +389,11 @@
 			return (-EIO);
 		copyaddr+=copylen;
 		len-=copylen;
-		useraddr+=copylen;
+		useraddr+=copylen
+#if CONFIG_S390_SUPPORT
+			+skip
+#endif
+			;
 	}
 	FixPerRegisters(task);
 	return(0);
@@ -227,150 +410,6 @@
 	clear_single_step(child);
 }
 
-asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
-{
-	struct task_struct *child;
-	int ret = -EPERM;
-	unsigned long flags;
-	unsigned long tmp;
-	int copied;
-	ptrace_area   parea; 
-
-	lock_kernel();
-	if (request == PTRACE_TRACEME) 
-	{
-		/* are we already being traced? */
-		if (current->ptrace & PT_PTRACED)
-			goto out;
-		/* set the ptrace bit in the process flags. */
-		current->ptrace |= PT_PTRACED;
-		ret = 0;
-		goto out;
-	}
-	ret = -ESRCH;
-	read_lock(&tasklist_lock);
-	child = find_task_by_pid(pid);
-	read_unlock(&tasklist_lock);
-	if (!child)
-		goto out;
-	ret = -EPERM;
-	if (pid == 1)		/* you may not mess with init */
-		goto out;
-	if (request == PTRACE_ATTACH) 
-	{
-		ret = ptrace_attach(child);
-		goto out;
-	}
-	ret = -ESRCH;
-	// printk("child=%lX child->flags=%lX",child,child->flags);
-	/* I added child!=current line so we can get the */
-	/* ieee_instruction_pointer from the user structure DJB */
-	if(child!=current)
-	{
-		if (!(child->ptrace & PT_PTRACED))
-			goto out;
-		if (child->state != TASK_STOPPED) 
-		{
-			if (request != PTRACE_KILL)
-				goto out;
-		}
-		if (child->p_pptr != current)
-			goto out;
-	}
-	switch (request) 
-	{
-		/* If I and D space are separate, these will need to be fixed. */
-	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
-	case PTRACE_PEEKDATA: 
-		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
-		ret = -EIO;
-		if (copied != sizeof(tmp))
-			goto out;
-		ret = put_user(tmp,(unsigned long *) data);
-		goto out;
-
-		/* read the word at location addr in the USER area. */
-	case PTRACE_PEEKUSR:
-		ret=copy_user(child,addr,data,sizeof(unsigned long),1,0);
-		break;
-
-		/* If I and D space are separate, this will have to be fixed. */
-	case PTRACE_POKETEXT: /* write the word at location addr. */
-	case PTRACE_POKEDATA:
-		ret = 0;
-		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
-			goto out;
-		ret = -EIO;
-		goto out;
-		break;
-
-	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-		ret=copy_user(child,addr,(addr_t)&data,sizeof(unsigned long),0,1);
-		break;
-
-	case PTRACE_SYSCALL: 	/* continue and stop at next (return from) syscall */
-	case PTRACE_CONT: 	 /* restart after signal. */
-		ret = -EIO;
-		if ((unsigned long) data >= _NSIG)
-			break;
-		if (request == PTRACE_SYSCALL)
-			child->ptrace |= PT_TRACESYS;
-		else
-			child->ptrace &= ~PT_TRACESYS;
-		child->exit_code = data;
-		/* make sure the single step bit is not set. */
-		clear_single_step(child);
-		wake_up_process(child);
-		ret = 0;
-		break;
-
-/*
- * make the child exit.  Best I can do is send it a sigkill. 
- * perhaps it should be put in the status that it wants to 
- * exit.
- */
-	case PTRACE_KILL:
-		ret = 0;
-		if (child->state == TASK_ZOMBIE) /* already dead */
-			break;
-		child->exit_code = SIGKILL;
-		clear_single_step(child);
-		wake_up_process(child);
-		/* make sure the single step bit is not set. */
-		break;
-
-	case PTRACE_SINGLESTEP:  /* set the trap flag. */
-		ret = -EIO;
-		if ((unsigned long) data >= _NSIG)
-			break;
-		child->ptrace &= ~PT_TRACESYS;
-		child->exit_code = data;
-		set_single_step(child);
-		/* give it a chance to run. */
-		wake_up_process(child);
-		ret = 0;
-		break;
-
-	case PTRACE_DETACH:  /* detach a process that was attached. */
-		ret = ptrace_detach(child, data);
-		break;
-
-	case PTRACE_PEEKUSR_AREA:
-	case PTRACE_POKEUSR_AREA:
-		if(copy_from_user(&parea,(void *)addr,sizeof(parea)) == 0)  
-			ret=copy_user(child,parea.kernel_addr,parea.process_addr,
-				 parea.len,1,(request==PTRACE_POKEUSR_AREA));
-		else ret = -EFAULT;
-		break;
-	default:
-		ret = -EIO;
-		break;
-	}
- out:
-	unlock_kernel();
-	return ret;
-}
-
 typedef struct
 {
 __u32	len;
@@ -378,15 +417,20 @@
 __u32	process_addr;
 } ptrace_area_emu31;
 
-asmlinkage int sys32_ptrace(long request, long pid, long addr, s32 data)
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
 	int ret = -EPERM;
-	unsigned long flags;
-	u32 tmp;
 	int copied;
-	ptrace_area   parea; 
-
+#ifdef CONFIG_S390_SUPPORT
+	int           parent_31bit;
+	int           sizeof_parent_long;
+	u8            *dataptr;
+#else
+#define sizeof_parent_long 8
+#define dataptr (u8 *)&data
+#endif
 	lock_kernel();
 	if (request == PTRACE_TRACEME) 
 	{
@@ -401,16 +445,18 @@
 	ret = -ESRCH;
 	read_lock(&tasklist_lock);
 	child = find_task_by_pid(pid);
+	if (child)
+		get_task_struct(child);
 	read_unlock(&tasklist_lock);
 	if (!child)
 		goto out;
 	ret = -EPERM;
 	if (pid == 1)		/* you may not mess with init */
-		goto out;
+		goto out_tsk;
 	if (request == PTRACE_ATTACH) 
 	{
 		ret = ptrace_attach(child);
-		goto out;
+		goto out_tsk;
 	}
 	ret = -ESRCH;
 	// printk("child=%lX child->flags=%lX",child,child->flags);
@@ -419,44 +465,52 @@
 	if(child!=current)
 	{
 		if (!(child->ptrace & PT_PTRACED))
-			goto out;
+			goto out_tsk;
 		if (child->state != TASK_STOPPED) 
 		{
 			if (request != PTRACE_KILL)
-				goto out;
+				goto out_tsk;
 		}
 		if (child->p_pptr != current)
-			goto out;
+			goto out_tsk;
 	}
+#ifdef CONFIG_S390_SUPPORT
+	parent_31bit=(current->thread.flags & S390_FLAG_31BIT);
+	sizeof_parent_long=(parent_31bit ? 4:8);
+	dataptr=&(((u8 *)&data)[parent_31bit ? 4:0]);
+#endif
 	switch (request) 
 	{
 		/* If I and D space are separate, these will need to be fixed. */
 	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 	case PTRACE_PEEKDATA: 
-		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+	{
+		u8 tmp[8];
+		copied = access_process_vm(child, addr, tmp, sizeof_parent_long, 0);
 		ret = -EIO;
-		if (copied != sizeof(tmp))
-			goto out;
-		ret = put_user(tmp,(u32 *)(unsigned long)data);
-		goto out;
-
+		if (copied != sizeof_parent_long)
+			break;
+		ret = copy_to_user((void *)data,tmp,sizeof_parent_long);
+		ret = ret ? -EFAULT : 0;
+		break;
+	
+	}
 		/* read the word at location addr in the USER area. */
 	case PTRACE_PEEKUSR:
-		ret=copy_user(child,addr,data,sizeof(u32),1,0);
+		ret=copy_user(child,addr,data,sizeof_parent_long,1,0);
 		break;
 
 		/* If I and D space are separate, this will have to be fixed. */
 	case PTRACE_POKETEXT: /* write the word at location addr. */
 	case PTRACE_POKEDATA:
 		ret = 0;
-		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
-			goto out;
+		if (access_process_vm(child, addr,dataptr, sizeof_parent_long, 1) == sizeof_parent_long)
+			break;
 		ret = -EIO;
-		goto out;
 		break;
 
 	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-		ret=copy_user(child,addr,(addr_t)&data,sizeof(u32),0,1);
+		ret=copy_user(child,addr,(addr_t)dataptr,sizeof_parent_long,0,1);
 		break;
 
 	case PTRACE_SYSCALL: 	/* continue and stop at next (return from) syscall */
@@ -503,44 +557,41 @@
 		break;
 
 	case PTRACE_DETACH:  /* detach a process that was attached. */
-		ret = -EIO;
-		if ((unsigned long) data >= _NSIG)
-			break;
-		child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
-		child->exit_code = data;
-		write_lock_irqsave(&tasklist_lock, flags);
-		REMOVE_LINKS(child);
-		child->p_pptr = child->p_opptr;
-		SET_LINKS(child);
-		write_unlock_irqrestore(&tasklist_lock, flags);
-		/* make sure the single step bit is not set. */
-		clear_single_step(child);
-		wake_up_process(child);
-		ret = 0;
+		ret = ptrace_detach(child, data);
 		break;
+
 	case PTRACE_PEEKUSR_AREA:
 	case PTRACE_POKEUSR_AREA:
+		if(parent_31bit)
 		{
-		ptrace_area_emu31 * parea31 = (void *)addr;
-		if (!access_ok(VERIFY_READ, parea31, sizeof(*parea31)))
-			return(-EFAULT);
-		ret = __get_user(parea.len, &parea31->len);
-		ret |= __get_user(parea.kernel_addr, &parea31->kernel_addr);
-		ret |= __get_user(parea.process_addr, &parea31->process_addr);
-		if(ret==0)  
-		   ret=copy_user(child,parea.kernel_addr,parea.process_addr,
-				 parea.len,1,(request==PTRACE_POKEUSR_AREA));
-		break;
+			ptrace_area_emu31   parea; 
+			if(copy_from_user(&parea,(void *)addr,sizeof(parea))==0)
+				ret=copy_user(child,parea.kernel_addr,parea.process_addr,
+					      parea.len,1,(request==PTRACE_POKEUSR_AREA));
+			else ret = -EFAULT;
 		}
+		else
+		{
+			ptrace_area   parea; 
+			if(copy_from_user(&parea,(void *)addr,sizeof(parea))==0)
+				ret=copy_user(child,parea.kernel_addr,parea.process_addr,
+					      parea.len,1,(request==PTRACE_POKEUSR_AREA));
+			else ret = -EFAULT;
+		}
+		break;
 	default:
 		ret = -EIO;
 		break;
 	}
+ out_tsk:
+	free_task_struct(child);
  out:
 	unlock_kernel();
 	return ret;
 }
 
+
+
 asmlinkage void syscall_trace(void)
 {
 	lock_kernel();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/kernel/s390_ext.c linux-2.4.20/arch/s390x/kernel/s390_ext.c
--- linux-2.4.19/arch/s390x/kernel/s390_ext.c	2001-07-25 21:12:01.000000000 +0000
+++ linux-2.4.20/arch/s390x/kernel/s390_ext.c	2002-10-29 11:18:34.000000000 +0000
@@ -21,34 +21,31 @@
  * iucv and 0x2603 pfault) this is always the first element. 
  */
 ext_int_info_t *ext_int_hash[256] = { 0, };
-ext_int_info_t ext_int_info_timer;
-ext_int_info_t ext_int_info_hwc;
-ext_int_info_t ext_int_pfault;
 
 int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
         ext_int_info_t *p;
         int index;
 
-        index = code & 0xff;
-        p = ext_int_hash[index];
-        while (p != NULL) {
-                if (p->code == code)
-                        return -EBUSY;
-                p = p->next;
-        }
-        if (code == 0x1004) /* time_init is done before kmalloc works :-/ */
-                p = &ext_int_info_timer;
-        else if (code == 0x2401) /* hwc_init is done too early too */
-                p = &ext_int_info_hwc;
-        else if (code == 0x2603) /* pfault_init is done too early too */
-                p = &ext_int_pfault;
-        else
-                p = (ext_int_info_t *)
-                          kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
+	p = (ext_int_info_t *) kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
         if (p == NULL)
                 return -ENOMEM;
         p->code = code;
         p->handler = handler;
+        index = code & 0xff;
+        p->next = ext_int_hash[index];
+        ext_int_hash[index] = p;
+        return 0;
+}
+
+int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+				      ext_int_info_t *p) {
+        int index;
+
+        if (p == NULL)
+                return -EINVAL;
+        p->code = code;
+        p->handler = handler;
+        index = code & 0xff;
         p->next = ext_int_hash[index];
         ext_int_hash[index] = p;
         return 0;
@@ -73,11 +70,33 @@
                 q->next = p->next;
         else
                 ext_int_hash[index] = p->next;
-        if (code != 0x1004 && code != 0x2401 && code != 0x2603)
-                kfree(p);
+	kfree(p);
         return 0;
 }
 
+int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+					ext_int_info_t *p) {
+	ext_int_info_t *q;
+	int index;
+
+	if (p == NULL || p->code != code || p->handler != handler)
+		return -EINVAL;
+	index = code & 0xff;
+	q = ext_int_hash[index];
+	if (p != q) {
+		while (q != NULL) {
+			if (q->next == p)
+				break;
+			q = q->next;
+		}
+		if (q == NULL)
+			return -ENOENT;
+		q->next = p->next;
+	} else
+		ext_int_hash[index] = p->next;
+	return 0;
+}
+
 EXPORT_SYMBOL(register_external_interrupt);
 EXPORT_SYMBOL(unregister_external_interrupt);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/kernel/s390_ksyms.c linux-2.4.20/arch/s390x/kernel/s390_ksyms.c
--- linux-2.4.19/arch/s390x/kernel/s390_ksyms.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390x/kernel/s390_ksyms.c	2002-10-29 11:18:35.000000000 +0000
@@ -12,6 +12,7 @@
 #include <asm/delay.h>
 #include <asm/pgalloc.h>
 #include <asm/setup.h>
+#include <asm/softirq.h>
 #if CONFIG_IP_MULTICAST
 #include <net/arp.h>
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/kernel/setup.c linux-2.4.20/arch/s390x/kernel/setup.c
--- linux-2.4.19/arch/s390x/kernel/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390x/kernel/setup.c	2002-10-29 11:18:38.000000000 +0000
@@ -165,15 +165,15 @@
 static int __init conmode_setup(char *str)
 {
 #if defined(CONFIG_HWC_CONSOLE)
-	if (strncmp(str, "hwc", 4) == 0 && !MACHINE_IS_P390)
+	if (strncmp(str, "hwc", 4) == 0)
                 SET_CONSOLE_HWC;
 #endif
 #if defined(CONFIG_TN3215_CONSOLE)
-	if (strncmp(str, "3215", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+	if (strncmp(str, "3215", 5) == 0)
 		SET_CONSOLE_3215;
 #endif
 #if defined(CONFIG_TN3270_CONSOLE)
-	if (strncmp(str, "3270", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+	if (strncmp(str, "3270", 5) == 0)
 		SET_CONSOLE_3270;
 #endif
         return 1;
@@ -233,31 +233,63 @@
 	}
 }
 
+#ifdef CONFIG_SMP
+extern void machine_restart_smp(char *);
+extern void machine_halt_smp(void);
+extern void machine_power_off_smp(void);
+
+void (*_machine_restart)(char *command) = machine_restart_smp;
+void (*_machine_halt)(void) = machine_halt_smp;
+void (*_machine_power_off)(void) = machine_power_off_smp;
+#else
 /*
  * Reboot, halt and power_off routines for non SMP.
  */
-#ifndef CONFIG_SMP
-void machine_restart(char * __unused)
+static void do_machine_restart_nonsmp(char * __unused)
 {
 	reipl(S390_lowcore.ipl_device);
 }
 
-void machine_halt(void)
+static void do_machine_halt_nonsmp(void)
 {
         if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
                 cpcmd(vmhalt_cmd, NULL, 0);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
 
-void machine_power_off(void)
+static void do_machine_power_off_nonsmp(void)
 {
         if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
                 cpcmd(vmpoff_cmd, NULL, 0);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
+
+void (*_machine_restart)(char *command) = do_machine_restart_nonsmp;
+void (*_machine_halt)(void) = do_machine_halt_nonsmp;
+void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
 #endif
 
 /*
+ * Reboot, halt and power_off stubs. They just call _machine_restart,
+ * _machine_halt or _machine_power_off. 
+ */
+
+void machine_restart(char *command)
+{
+	_machine_restart(command);
+}
+
+void machine_halt(void)
+{
+	_machine_halt();
+}
+
+void machine_power_off(void)
+{
+	_machine_power_off();
+}
+
+/*
  * Setup function called from init/main.c just after the banner
  * was printed.
  */
@@ -429,6 +461,10 @@
 	lowcore->async_stack = (__u64)
 		__alloc_bootmem(4*PAGE_SIZE, 4*PAGE_SIZE, 0) + 16384;
 	lowcore->jiffy_timer = -1LL;
+	if (MACHINE_HAS_DIAG44)
+		lowcore->diag44_opcode = 0x83000044;
+	else
+		lowcore->diag44_opcode = 0x07000700;
 	set_prefix((__u32)(__u64) lowcore);
         cpu_init();
         boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
@@ -486,7 +522,7 @@
 	}
 	if (cpu_online_map & (1 << n)) {
 		cpuinfo = &safe_get_cpu_lowcore(n)->cpu_data;
-		seq_printf(m, "processor %i: "
+		seq_printf(m, "processor %li: "
 				"version = %02X,  "
 				"identification = %06X,  "
 				"machine = %04X\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/kernel/signal.c linux-2.4.20/arch/s390x/kernel/signal.c
--- linux-2.4.19/arch/s390x/kernel/signal.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390x/kernel/signal.c	2002-10-29 11:18:48.000000000 +0000
@@ -333,6 +333,10 @@
 			goto give_sigsegv;
 	}
 
+	/* Set up backchain. */
+	if (__put_user(regs->gprs[15], (addr_t *) frame))
+		goto give_sigsegv;
+
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (addr_t)frame;
 	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
@@ -386,6 +390,10 @@
 	                          (u16 *)(frame->retcode));
 	}
 
+	/* Set up backchain. */
+	if (__put_user(regs->gprs[15], (addr_t *) frame))
+		goto give_sigsegv;
+
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (addr_t)frame;
 	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
@@ -567,7 +575,10 @@
                                 /* FALLTHRU */
 
 			default:
-				sig_exit(signr, exit_code, &info);
+				sigaddset(&current->pending.signal, signr);
+				recalc_sigpending(current);
+				current->flags |= PF_SIGNALED;
+				do_exit(exit_code);
 				/* NOTREACHED */
 			}
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/kernel/smp.c linux-2.4.20/arch/s390x/kernel/smp.c
--- linux-2.4.19/arch/s390x/kernel/smp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390x/kernel/smp.c	2002-10-29 11:18:48.000000000 +0000
@@ -176,61 +176,137 @@
 	return 0;
 }
 
+static inline void do_send_stop(void)
+{
+        u32 dummy;
+        int i;
+
+        /* stop all processors */
+        for (i =  0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() != i) {
+                        int ccode;
+                        do {
+                                ccode = signal_processor_ps(
+                                   &dummy,
+                                   0,
+                                   i,
+                                   sigp_stop);
+                        } while(ccode == sigp_busy);
+                }
+        }
+}
+
+static inline void do_store_status(void)
+{
+        unsigned long low_core_addr;
+        u32 dummy;
+        int i;
+
+        /* store status of all processors in their lowcores (real 0) */
+        for (i =  0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() != i) {
+                        int ccode;
+                        low_core_addr = (unsigned long)get_cpu_lowcore(i);
+                        do {
+                                ccode = signal_processor_ps(
+                                   &dummy,
+                                   low_core_addr,
+                                   i,
+                                   sigp_store_status_at_address);
+                        } while(ccode == sigp_busy);
+                }
+        }
+}
 
 /*
- * Various special callbacks
+ * this function sends a 'stop' sigp to all other CPUs in the system.
+ * it goes straight through.
  */
+void smp_send_stop(void)
+{
+        int i;
+        u32 dummy;
+        unsigned long low_core_addr;
+
+        /* write magic number to zero page (absolute 0) */
+        get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC;
+
+	/* stop other processors. */
+	do_send_stop();
+
+	/* store status of other processors. */
+	do_store_status();
+}
 
-void do_machine_restart(void)
+
+/*
+ * Reboot, halt and power_off routines for SMP.
+ */
+static volatile unsigned long cpu_restart_map;
+
+static void do_machine_restart(void * __unused)
 {
-        smp_send_stop();
-	reipl(S390_lowcore.ipl_device);
+	clear_bit(smp_processor_id(), &cpu_restart_map);
+	if (smp_processor_id() == 0) {
+		/* Wait for all other cpus to enter do_machine_restart. */
+		while (cpu_restart_map != 0);
+		/* Store status of other cpus. */
+		do_store_status();
+		/*
+		 * Finally call reipl. Because we waited for all other
+		 * cpus to enter this function we know that they do
+		 * not hold any s390irq-locks (the cpus have been
+		 * interrupted by an external interrupt and s390irq
+		 * locks are always held disabled).
+		 */
+		reipl(S390_lowcore.ipl_device);
+	}
+	signal_processor(smp_processor_id(), sigp_stop);
 }
 
-void machine_restart(char * __unused) 
+void machine_restart_smp(char * __unused) 
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_restart);
-		for (;;)
-			enabled_wait();
-        } else
-                do_machine_restart();
+	cpu_restart_map = cpu_online_map;
+        smp_call_function(do_machine_restart, NULL, 0, 0);
+	do_machine_restart(NULL);
 }
 
-void do_machine_halt(void)
+static void do_machine_halt(void * __unused)
 {
-        smp_send_stop();
-        if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
-                cpcmd(vmhalt_cmd, NULL, 0);
-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+	if (smp_processor_id() == 0) {
+		smp_send_stop();
+		if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
+			cpcmd(vmhalt_cmd, NULL, 0);
+		signal_processor(smp_processor_id(),
+				 sigp_stop_and_store_status);
+	}
+	for (;;)
+		enabled_wait();
 }
 
-void machine_halt(void)
+void machine_halt_smp(void)
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_halt);
-		for (;;)
-			enabled_wait();
-        } else
-                do_machine_halt();
+        smp_call_function(do_machine_halt, NULL, 0, 0);
+	do_machine_halt(NULL);
 }
 
-void do_machine_power_off(void)
+static void do_machine_power_off(void * __unused)
 {
-        smp_send_stop();
-        if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
-                cpcmd(vmpoff_cmd, NULL, 0);
-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+	if (smp_processor_id() == 0) {
+		smp_send_stop();
+		if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
+			cpcmd(vmpoff_cmd, NULL, 0);
+		signal_processor(smp_processor_id(),
+				 sigp_stop_and_store_status);
+	}
+	for (;;)
+		enabled_wait();
 }
 
-void machine_power_off(void)
+void machine_power_off_smp(void)
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_power_off);
-		for (;;)
-			enabled_wait();
-        } else
-                do_machine_power_off();
+        smp_call_function(do_machine_power_off, NULL, 0, 0);
+	do_machine_power_off(NULL);
 }
 
 /*
@@ -247,17 +323,9 @@
          *
          * For the ec_schedule signal we have to do nothing. All the work
          * is done automatically when we return from the interrupt.
-	 * For the ec_restart, ec_halt and ec_power_off we call the
-         * appropriate routine.
          */
 	bits = xchg(&S390_lowcore.ext_call_fast, 0);
 
-        if (test_bit(ec_restart, &bits))
-		do_machine_restart();
-        if (test_bit(ec_halt, &bits))
-		do_machine_halt();
-        if (test_bit(ec_power_off, &bits))
-		do_machine_power_off();
         if (test_bit(ec_call_function, &bits))
 		do_call_function();
 }
@@ -300,53 +368,6 @@
 }
 
 /*
- * this function sends a 'stop' sigp to all other CPUs in the system.
- * it goes straight through.
- */
-
-void smp_send_stop(void)
-{
-        int i;
-        u32 dummy;
-        unsigned long low_core_addr;
-
-        /* write magic number to zero page (absolute 0) */
-
-        get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC;
-
-        /* stop all processors */
-
-        for (i =  0; i < smp_num_cpus; i++) {
-                if (smp_processor_id() != i) {
-                        int ccode;
-                        do {
-                                ccode = signal_processor_ps(
-                                   &dummy,
-                                   0,
-                                   i,
-                                   sigp_stop);
-                        } while(ccode == sigp_busy);
-                }
-        }
-
-        /* store status of all processors in their lowcores (real 0) */
-
-        for (i =  0; i < smp_num_cpus; i++) {
-                if (smp_processor_id() != i) {
-                        int ccode;
-                        low_core_addr = (unsigned long)get_cpu_lowcore(i);
-                        do {
-                                ccode = signal_processor_ps(
-                                   &dummy,
-                                   low_core_addr,
-                                   i,
-                                   sigp_store_status_at_address);
-                        } while(ccode == sigp_busy);
-                }
-        }
-}
-
-/*
  * this function sends a 'reschedule' IPI to another CPU.
  * it goes straight through and wastes no time serializing
  * anything. Worst case is that we lose a reschedule ...
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/kernel/sys_s390.c linux-2.4.20/arch/s390x/kernel/sys_s390.c
--- linux-2.4.19/arch/s390x/kernel/sys_s390.c	2001-04-12 02:02:29.000000000 +0000
+++ linux-2.4.20/arch/s390x/kernel/sys_s390.c	2002-10-29 11:18:36.000000000 +0000
@@ -24,6 +24,7 @@
 #include <linux/mman.h>
 #include <linux/file.h>
 #include <linux/utsname.h>
+#include <linux/personality.h>
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
@@ -203,3 +204,30 @@
 	return -ERESTARTNOHAND;
 }
 
+extern asmlinkage int sys_newuname(struct new_utsname * name);
+
+asmlinkage int s390x_newuname(struct new_utsname * name)
+{
+	int ret = sys_newuname(name);
+
+	if (current->personality == PER_LINUX32 && !ret) {
+		ret = copy_to_user(name->machine, "s390\0\0\0\0", 8);
+		if (ret) ret = -EFAULT;
+	}
+	return ret;
+}
+
+extern asmlinkage long sys_personality(unsigned long);
+
+asmlinkage int s390x_personality(unsigned long personality)
+{
+	int ret;
+
+	if (current->personality == PER_LINUX32 && personality == PER_LINUX)
+		personality = PER_LINUX32;
+	ret = sys_personality(personality);
+	if (ret == PER_LINUX32)
+		ret = PER_LINUX;
+
+	return ret;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/kernel/time.c linux-2.4.20/arch/s390x/kernel/time.c
--- linux-2.4.19/arch/s390x/kernel/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390x/kernel/time.c	2002-10-29 11:18:35.000000000 +0000
@@ -39,6 +39,7 @@
 
 #define TICK_SIZE tick
 
+static ext_int_info_t ext_int_info_timer;
 static uint64_t init_timer_cc;
 
 extern rwlock_t xtime_lock;
@@ -197,7 +198,8 @@
         tod_to_timeval(set_time_cc, &xtime);
 
         /* request the 0x1004 external interrupt */
-        if (register_external_interrupt(0x1004, do_comparator_interrupt) != 0)
+        if (register_early_external_interrupt(0x1004, do_comparator_interrupt,
+					      &ext_int_info_timer) != 0)
                 panic("Couldn't request external interrupt 0x1004");
 
         /* init CPU timer */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/kernel/traps.c linux-2.4.20/arch/s390x/kernel/traps.c
--- linux-2.4.19/arch/s390x/kernel/traps.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390x/kernel/traps.c	2002-10-29 11:18:49.000000000 +0000
@@ -60,6 +60,7 @@
 extern int pfault_init(void);
 extern void pfault_fini(void);
 extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
+static ext_int_info_t ext_int_pfault;
 #endif
 
 int kstack_depth_to_print = 20;
@@ -499,15 +500,17 @@
 #ifdef CONFIG_PFAULT
 	if (MACHINE_IS_VM) {
 		/* request the 0x2603 external interrupt */
-		if (register_external_interrupt(0x2603, pfault_interrupt) != 0)
+		if (register_early_external_interrupt(0x2603, pfault_interrupt,
+						      &ext_int_pfault) != 0)
 			panic("Couldn't request external interrupt 0x2603");
 		/*
 		 * Try to get pfault pseudo page faults going.
 		 */
 		if (pfault_init() != 0) {
 			/* Tough luck, no pfault. */
-			unregister_external_interrupt(0x2603,
-						      pfault_interrupt);
+			unregister_early_external_interrupt(0x2603,
+							    pfault_interrupt,
+							    &ext_int_pfault);
 		}
 	}
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/mm/fault.c linux-2.4.20/arch/s390x/mm/fault.c
--- linux-2.4.19/arch/s390x/mm/fault.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390x/mm/fault.c	2002-10-29 11:18:36.000000000 +0000
@@ -291,13 +291,11 @@
  * us unable to handle the page fault gracefully.
 */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
-		tsk->policy |= SCHED_YIELD;
-		schedule();
-		down_read(&mm->mmap_sem);
+		yield();
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (regs->psw.mask & PSW_PROBLEM_STATE)
 		do_exit(SIGKILL);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/s390x/mm/init.c linux-2.4.20/arch/s390x/mm/init.c
--- linux-2.4.19/arch/s390x/mm/init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/s390x/mm/init.c	2002-10-29 11:18:36.000000000 +0000
@@ -44,6 +44,74 @@
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
 char  empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 
+pmd_t *pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
+{
+        unsigned long addr = (unsigned long) pgd;
+        unsigned long *pgd_slot =  (unsigned long *) (addr & -8);
+        unsigned long offset = addr & 4;
+	pmd_t *new, *pmd2;
+	int i;
+ 
+        if (offset == 0 && 
+	    ((*pgd_slot & _PGD_ENTRY_INV) != 0 ||
+	     (*pgd_slot & _PGD_ENTRY_LEN(2)) == 0)) {
+                /* Set lower pmd, upper pmd is empty. */
+                *pgd_slot = __pa(pmd) | _PGD_ENTRY_MASK |
+                                _PGD_ENTRY_OFF(0) | _PGD_ENTRY_LEN(1);
+                return pmd;
+        }
+        if (offset == 4 &&
+	    ((*pgd_slot & _PGD_ENTRY_INV) != 0 ||
+	     (*pgd_slot & _PGD_ENTRY_OFF(2)) != 0)) {
+                /* Lower pmd empty, set upper pmd. */
+                *pgd_slot = (__pa(pmd) - 0x2000) | _PGD_ENTRY_MASK |
+                                _PGD_ENTRY_OFF(2) | _PGD_ENTRY_LEN(3);
+                return pmd;
+        }
+        /* We have to enlarge the pmd to 16K if we arrive here. */
+	new = (pmd_t *) __get_free_pages(GFP_KERNEL, 2);
+	if (new == NULL) {
+		pmd_free(pmd);
+		return NULL;
+	}
+	/* Set the PG_arch_1 bit on the first and the third pmd page
+           so that pmd_free_fast can recognize pmds that have been
+           allocated with an order 2 allocation.  */
+	set_bit(PG_arch_1, &virt_to_page(new)->flags);
+	set_bit(PG_arch_1, &virt_to_page(new+PTRS_PER_PMD)->flags);
+	/* Now copy the two pmds to the new memory area. */
+	if (offset == 0) {
+		pmd2 = (pmd_t *)(*pgd_slot & PAGE_MASK) + PTRS_PER_PMD;
+		memcpy(new, pmd, sizeof(pmd_t)*PTRS_PER_PMD);
+		memcpy(new + PTRS_PER_PMD, pmd2, sizeof(pmd_t)*PTRS_PER_PMD);
+	} else {
+		pmd2 = (pmd_t *)(*pgd_slot & PAGE_MASK);
+		memcpy(new, pmd2, sizeof(pmd_t)*PTRS_PER_PMD);
+		memcpy(new + PTRS_PER_PMD, pmd, sizeof(pmd_t)*PTRS_PER_PMD);
+	}
+	*pgd_slot = __pa(new) | _PGD_ENTRY_MASK |
+			_PGD_ENTRY_OFF(0) | _PGD_ENTRY_LEN(3);
+	for (i = 0; i < PTRS_PER_PMD; i++) {
+		pmd_clear(pmd + i);
+		pmd_clear(pmd2 + i);
+	}
+	pmd_free(pmd);
+	pmd_free(pmd2);
+	return new;
+}
+
+void pmd_free_order2(pmd_t *pmd)
+{
+	pmd_t *pmd2 = (pmd_t *) ((unsigned long) pmd ^ 8192);
+
+	clear_bit(PG_arch_1, &virt_to_page(pmd)->flags);
+	if (test_bit(PG_arch_1, &virt_to_page(pmd2)->flags) == 0) {
+		/* The other pmd of the order 2 allocation has already
+		   been freed. Now we can release the order 2 allocation.  */
+		free_pages((unsigned long) pmd & ~8192, 2);
+	}
+}
+
 int do_check_pgt_cache(int low, int high)
 {
         int freed = 0;
@@ -51,11 +119,11 @@
                 do {
                         if(pgd_quicklist) {
 				free_pgd_slow(get_pgd_fast());
-				freed += 4;
+				freed += 2;
 			}
                         if(pmd_quicklist) {
 				pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
-				freed += 4;
+				freed += 2;
 			}
                         if(pte_quicklist) {
 				pte_free_slow(pte_alloc_one_fast(NULL, 0));
@@ -111,51 +179,45 @@
 
 void __init paging_init(void)
 {
+	unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
+	static const int ssm_mask = 0x04000000L;
+	unsigned long dma_pfn, address, end_mem;
         pgd_t * pg_dir;
-	pmd_t * pm_dir;
-        pte_t * pt_dir;
-        pte_t   pte;
 	int     i,j,k;
-        unsigned long address=0;
-        unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) |
-          _KERN_REGION_TABLE;
-	unsigned long end_mem = (unsigned long) __va(max_low_pfn*PAGE_SIZE);
-	static const int ssm_mask = 0x04000000L;
-
-	unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
-	unsigned long dma_pfn, high_pfn;
 
 	dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT;
-	high_pfn = max_low_pfn;
 
-	if (dma_pfn > high_pfn)
-		zones_size[ZONE_DMA] = high_pfn;
+	if (dma_pfn > max_low_pfn)
+		zones_size[ZONE_DMA] = max_low_pfn;
 	else {
 		zones_size[ZONE_DMA] = dma_pfn;
-		zones_size[ZONE_NORMAL] = high_pfn - dma_pfn;
+		zones_size[ZONE_NORMAL] = max_low_pfn - dma_pfn;
 	}
 
 	/* Initialize mem_map[].  */
 	free_area_init(zones_size);
 
-
 	/*
 	 * map whole physical memory to virtual memory (identity mapping) 
 	 */
-
         pg_dir = swapper_pg_dir;
-	
-        for (i = 0 ; i < PTRS_PER_PGD ; i++,pg_dir++) {
+	address = 0;
+	end_mem = (unsigned long) __va(max_low_pfn*PAGE_SIZE);
+        for (i = 0 ; i < PTRS_PER_PGD/2 ; i++, pg_dir += 2) {
+		pmd_t *pm_dir;
 
                 if (address >= end_mem) {
                         pgd_clear(pg_dir);
                         continue;
-                }          
+                }
         
 	        pm_dir = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE*4);
-                pgd_populate(&init_mm, pg_dir, pm_dir);
+		*((unsigned long *) pg_dir) = __pa(pm_dir) | _PGD_ENTRY_MASK |
+			_PGD_ENTRY_LEN(3) | _PGD_ENTRY_OFF(0);
+
+                for (j = 0 ; j < PTRS_PER_PMD*2 ; j++, pm_dir++) {
+			pte_t *pt_dir;
 
-                for (j = 0 ; j < PTRS_PER_PMD ; j++,pm_dir++) {
                         if (address >= end_mem) {
                                 pmd_clear(pm_dir);
                                 continue; 
@@ -165,7 +227,7 @@
                         pmd_populate(&init_mm, pm_dir, pt_dir);
 	
                         for (k = 0 ; k < PTRS_PER_PTE ; k++,pt_dir++) {
-                                pte = mk_pte_phys(address, PAGE_KERNEL);
+                                pte_t pte = mk_pte_phys(address, PAGE_KERNEL);
                                 if (address >= end_mem) {
                                         pte_clear(&pte); 
                                         continue;
@@ -181,8 +243,8 @@
                              "lctlg 7,7,%0\n\t"
                              "lctlg 13,13,%0\n\t"
                              "ssm   %1"
-			     : :"m" (pgdir_k), "m" (ssm_mask));
-
+			     : :"m" (__pa(swapper_pg_dir) | _KERN_REGION_TABLE),
+			        "m" (ssm_mask));
         local_flush_tlb();
 
         return;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sh/config.in linux-2.4.20/arch/sh/config.in
--- linux-2.4.19/arch/sh/config.in	2002-02-25 19:37:56.000000000 +0000
+++ linux-2.4.20/arch/sh/config.in	2002-10-29 11:18:48.000000000 +0000
@@ -386,3 +386,5 @@
    bool 'Early printk support' CONFIG_SH_EARLY_PRINTK
 fi
 endmenu
+
+source lib/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sh/kernel/pcibios.c linux-2.4.20/arch/sh/kernel/pcibios.c
--- linux-2.4.19/arch/sh/kernel/pcibios.c	2001-09-08 19:29:09.000000000 +0000
+++ linux-2.4.20/arch/sh/kernel/pcibios.c	2002-10-29 11:18:36.000000000 +0000
@@ -60,7 +60,8 @@
  * addresses to be allocated in the 0x000-0x0ff region
  * modulo 0x400.
  */
-void pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size, unsigned long align)
 {
 	if (res->flags & IORESOURCE_IO) {
 		unsigned long start = res->start;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sh/mm/fault.c linux-2.4.20/arch/sh/mm/fault.c
--- linux-2.4.19/arch/sh/mm/fault.c	2001-10-15 20:36:48.000000000 +0000
+++ linux-2.4.20/arch/sh/mm/fault.c	2002-10-29 11:18:35.000000000 +0000
@@ -205,13 +205,11 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up_read(&mm->mmap_sem);
 	if (current->pid == 1) {
-		current->policy |= SCHED_YIELD;
-		schedule();
-		down_read(&mm->mmap_sem);
+		yield();
 		goto survive;
 	}
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc/config.in linux-2.4.20/arch/sparc/config.in
--- linux-2.4.19/arch/sparc/config.in	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc/config.in	2002-10-29 11:18:32.000000000 +0000
@@ -97,11 +97,6 @@
 tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
 dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
 
-#tristate 'Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM N
-#if [ "$CONFIG_BLK_DEV_LVM" != "n" ]; then
-#   bool '   LVM information in proc filesystem' CONFIG_LVM_PROC_FS Y
-#fi
-
 source drivers/md/Config.in
 
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
@@ -206,7 +201,7 @@
           tristate '  Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP
         fi
       fi
-      tristate '  PPP (point-to-point) support' CONFIG_PPP
+      tristate '  PPP (point-to-point protocol) support' CONFIG_PPP
       if [ ! "$CONFIG_PPP" = "n" ]; then
         dep_tristate '  PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
         dep_tristate '  PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
@@ -271,3 +266,5 @@
 
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
+
+source lib/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc/kernel/devices.c linux-2.4.20/arch/sparc/kernel/devices.c
--- linux-2.4.19/arch/sparc/kernel/devices.c	2002-02-25 19:37:56.000000000 +0000
+++ linux-2.4.20/arch/sparc/kernel/devices.c	2002-10-29 11:18:49.000000000 +0000
@@ -22,8 +22,8 @@
 extern void clock_stop_probe(void); /* tadpole.c */
 extern void sun4c_probe_memerr_reg(void);
 
-unsigned long __init
-device_scan(unsigned long mem_start)
+void __init
+device_scan(void)
 {
 	char node_str[128];
 	int thismid;
@@ -37,46 +37,45 @@
 		int scan;
 		scan = prom_getchild(prom_root_node);
 		/* One can look it up in PROM instead */
-		/* prom_printf("root child is %08lx\n", (unsigned long) scan); */
-		while((scan = prom_getsibling(scan)) != 0) {
-			prom_getstring(scan, "device_type", node_str, sizeof(node_str));
-			if(strcmp(node_str, "cpu") == 0) {
+		while ((scan = prom_getsibling(scan)) != 0) {
+			prom_getstring(scan, "device_type",
+				       node_str, sizeof(node_str));
+			if (strcmp(node_str, "cpu") == 0) {
 				linux_cpus[linux_num_cpus].prom_node = scan;
-				prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
+				prom_getproperty(scan, "mid",
+						 (char *) &thismid, sizeof(thismid));
 				linux_cpus[linux_num_cpus].mid = thismid;
-				/* prom_printf("Found CPU %d <node=%08lx,mid=%d>\n", linux_num_cpus, (unsigned long) scan, thismid); */
-				printk("Found CPU %d <node=%08lx,mid=%d>\n", linux_num_cpus, (unsigned long) scan, thismid);
+				printk("Found CPU %d <node=%08lx,mid=%d>\n",
+				       linux_num_cpus, (unsigned long) scan, thismid);
 				linux_num_cpus++;
 			}
 		}
-		if(linux_num_cpus == 0) {
-			if (sparc_cpu_model == sun4d) {
-				scan = prom_getchild(prom_root_node);
-				for (scan = prom_searchsiblings(scan, "cpu-unit"); scan;
-				     scan = prom_searchsiblings(prom_getsibling(scan), "cpu-unit")) {
-					int node = prom_getchild(scan);
-
-					prom_getstring(node, "device_type", node_str, sizeof(node_str));
-					if (strcmp(node_str, "cpu") == 0) {
-						prom_getproperty(node, "cpu-id", (char *) &thismid, sizeof(thismid));
-						linux_cpus[linux_num_cpus].prom_node = node;
-						linux_cpus[linux_num_cpus].mid = thismid;
-						/* prom_printf("Found CPU %d <node=%08lx,mid=%d>\n", 
-							       linux_num_cpus, (unsigned long) node, thismid); */
-						printk("Found CPU %d <node=%08lx,mid=%d>\n", 
-						       linux_num_cpus, (unsigned long) node, thismid);
-						linux_num_cpus++;
-					}
+		if (linux_num_cpus == 0 && sparc_cpu_model == sun4d) {
+			scan = prom_getchild(prom_root_node);
+			for (scan = prom_searchsiblings(scan, "cpu-unit"); scan;
+			     scan = prom_searchsiblings(prom_getsibling(scan), "cpu-unit")) {
+				int node = prom_getchild(scan);
+
+				prom_getstring(node, "device_type",
+					       node_str, sizeof(node_str));
+				if (strcmp(node_str, "cpu") == 0) {
+					prom_getproperty(node, "cpu-id",
+							 (char *) &thismid, sizeof(thismid));
+					linux_cpus[linux_num_cpus].prom_node = node;
+					linux_cpus[linux_num_cpus].mid = thismid;
+					printk("Found CPU %d <node=%08lx,mid=%d>\n", 
+					       linux_num_cpus, (unsigned long) node, thismid);
+					linux_num_cpus++;
 				}
 			}
 		}
-		if(linux_num_cpus == 0) {
+		if (linux_num_cpus == 0) {
 			printk("No CPU nodes found, cannot continue.\n");
 			/* Probably a sun4e, Sun is trying to trick us ;-) */
 			halt();
 		}
 		printk("Found %d CPU prom device tree node(s).\n", linux_num_cpus);
-	};
+	}
 
 	cpu_probe();
 #ifdef CONFIG_SUN_AUXIO
@@ -92,5 +91,5 @@
 	if (ARCH_SUN4C_SUN4)
 		sun4c_probe_memerr_reg();
 
-	return mem_start;
+	return;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc/kernel/pcic.c linux-2.4.20/arch/sparc/kernel/pcic.c
--- linux-2.4.19/arch/sparc/kernel/pcic.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc/kernel/pcic.c	2002-10-29 11:18:31.000000000 +0000
@@ -865,11 +865,12 @@
 {
 }
 
-void pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size, unsigned long align)
 {
 }
 
-int pcibios_enable_device(struct pci_dev *pdev)
+int pcibios_enable_device(struct pci_dev *pdev, int mask)
 {
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc/kernel/sparc_ksyms.c linux-2.4.20/arch/sparc/kernel/sparc_ksyms.c
--- linux-2.4.19/arch/sparc/kernel/sparc_ksyms.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc/kernel/sparc_ksyms.c	2002-10-29 11:18:33.000000000 +0000
@@ -46,6 +46,9 @@
 #include <asm/sbus.h>
 #include <asm/dma.h>
 #endif
+#ifdef CONFIG_HIGHMEM
+#include <linux/highmem.h>
+#endif
 #include <asm/a.out.h>
 #include <asm/io-unit.h>
 
@@ -204,6 +207,12 @@
 EXPORT_SYMBOL(pci_dma_sync_single);
 #endif
 
+/* in arch/sparc/mm/highmem.c */
+#ifdef CONFIG_HIGHMEM
+EXPORT_SYMBOL(kmap_atomic);
+EXPORT_SYMBOL(kunmap_atomic);
+#endif
+
 /* Solaris/SunOS binary compatibility */
 EXPORT_SYMBOL(svr4_setcontext);
 EXPORT_SYMBOL(svr4_getcontext);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc/kernel/sys_sunos.c linux-2.4.20/arch/sparc/kernel/sys_sunos.c
--- linux-2.4.19/arch/sparc/kernel/sys_sunos.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc/kernel/sys_sunos.c	2002-10-29 11:18:39.000000000 +0000
@@ -488,7 +488,8 @@
 		ret |= __copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
 	}
 	up_read(&uts_sem);
-	return ret;
+
+	return (ret ? -EFAULT : 0);
 }
 
 asmlinkage int sunos_nosys(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc/mm/Makefile linux-2.4.20/arch/sparc/mm/Makefile
--- linux-2.4.19/arch/sparc/mm/Makefile	2000-12-29 22:07:21.000000000 +0000
+++ linux-2.4.20/arch/sparc/mm/Makefile	2002-10-29 11:18:49.000000000 +0000
@@ -10,19 +10,24 @@
 .S.o:
 	$(CC) $(AFLAGS) -ansi -c -o $*.o $<
 
-O_TARGET := mm.o
-obj-y    := fault.o init.o loadmmu.o generic.o extable.o btfixup.o
+O_TARGET	:= mm.o
+obj-y		:= fault.o init.o loadmmu.o generic.o extable.o btfixup.o
 
 ifeq ($(CONFIG_SUN4),y)
-obj-y	 += nosrmmu.o
+obj-y		+= nosrmmu.o
 else
-obj-y	 += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
+obj-y		+= srmmu.o iommu.o io-unit.o hypersparc.o viking.o \
+			tsunami.o swift.o
+endif
+
+ifdef CONFIG_HIGHMEM
+obj-y		+= highmem.o
 endif
 
 ifdef CONFIG_SMP
-obj-y   += nosun4c.o
+obj-y		+= nosun4c.o
 else
-obj-y   += sun4c.o
+obj-y		+= sun4c.o
 endif
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc/mm/highmem.c linux-2.4.20/arch/sparc/mm/highmem.c
--- linux-2.4.19/arch/sparc/mm/highmem.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/sparc/mm/highmem.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,84 @@
+/*
+ *  highmem.c: virtual kernel memory mappings for high memory
+ *
+ *  Provides kernel-static versions of atomic kmap functions originally
+ *  found as inlines in include/asm-sparc/highmem.h.  These became
+ *  needed as kmap_atomic() and kunmap_atomic() started getting
+ *  called from within modules.
+ *  -- Tomas Szepe <szepe@pinerecords.com>, September 2002
+ */
+
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <asm/pgalloc.h>
+
+/*
+ * The use of kmap_atomic/kunmap_atomic is discouraged -- kmap()/kunmap()
+ * gives a more generic (and caching) interface.  But kmap_atomic() can
+ * be used in IRQ contexts, so in some (very limited) cases we need it.
+ */
+void *kmap_atomic(struct page *page, enum km_type type)
+{
+	unsigned long idx;
+	unsigned long vaddr;
+
+	if (page < highmem_start_page)
+		return page_address(page);
+
+	idx = type + KM_TYPE_NR * smp_processor_id();
+	vaddr = fix_kmap_begin + idx * PAGE_SIZE;
+
+/* XXX Fix - Anton */
+#if 0
+	__flush_cache_one(vaddr);
+#else
+	flush_cache_all();
+#endif
+
+#if HIGHMEM_DEBUG
+	if (!pte_none(*(kmap_pte + idx)))
+		BUG();
+#endif
+	set_pte(kmap_pte + idx, mk_pte(page, kmap_prot));
+/* XXX Fix - Anton */
+#if 0
+	__flush_tlb_one(vaddr);
+#else
+	flush_tlb_all();
+#endif
+
+	return (void *) vaddr;
+}
+
+void kunmap_atomic(void *kvaddr, enum km_type type)
+{
+	unsigned long vaddr = (unsigned long) kvaddr;
+	unsigned long idx = type + KM_TYPE_NR * smp_processor_id();
+
+	if (vaddr < fix_kmap_begin) /* FIXME */
+		return;
+
+	if (vaddr != fix_kmap_begin + idx * PAGE_SIZE)
+		BUG();
+
+/* XXX Fix - Anton */
+#if 0
+	__flush_cache_one(vaddr);
+#else
+	flush_cache_all();
+#endif
+
+#ifdef HIGHMEM_DEBUG
+	/*
+	 *  Force other mappings to oops if they try to access
+	 *  this pte without first remapping it.
+	 */
+	pte_clear(kmap_pte + idx);
+/* XXX Fix - Anton */
+#if 0
+	__flush_tlb_one(vaddr);
+#else
+	flush_tlb_all();
+#endif
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc/mm/init.c linux-2.4.20/arch/sparc/mm/init.c
--- linux-2.4.19/arch/sparc/mm/init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc/mm/init.c	2002-10-29 11:18:39.000000000 +0000
@@ -61,13 +61,17 @@
 pte_t *kmap_pte;
 pgprot_t kmap_prot;
 
+/* These are set in {srmmu,sun4c}_paging_init() */
+unsigned long fix_kmap_begin;
+unsigned long fix_kmap_end;
+
 #define kmap_get_fixed_pte(vaddr) \
 	pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
 
 void __init kmap_init(void)
 {
 	/* cache the first kmap pte */
-	kmap_pte = kmap_get_fixed_pte(FIX_KMAP_BEGIN);
+	kmap_pte = kmap_get_fixed_pte(fix_kmap_begin);
 	kmap_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV | SRMMU_CACHE);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc/mm/srmmu.c linux-2.4.20/arch/sparc/mm/srmmu.c
--- linux-2.4.19/arch/sparc/mm/srmmu.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc/mm/srmmu.c	2002-10-29 11:18:48.000000000 +0000
@@ -114,8 +114,16 @@
 
 int srmmu_cache_pagetables;
 
-/* XXX Make this dynamic based on ram size - Anton */
-#define SRMMU_NOCACHE_BITMAP_SIZE (SRMMU_NOCACHE_NPAGES * 16)
+/* these will be initialized in srmmu_nocache_calcsize() */
+int srmmu_nocache_npages;
+unsigned long srmmu_nocache_size;
+unsigned long srmmu_nocache_end;
+unsigned long pkmap_base;
+unsigned long pkmap_base_end;
+unsigned long srmmu_nocache_bitmap_size;
+extern unsigned long fix_kmap_begin;
+extern unsigned long fix_kmap_end;
+
 #define SRMMU_NOCACHE_BITMAP_SHIFT (PAGE_SHIFT - 4)
 
 void *srmmu_nocache_pool;
@@ -248,7 +256,7 @@
 	spin_lock(&srmmu_nocache_spinlock);
 
 repeat:
-	offset = find_next_zero_bit(srmmu_nocache_bitmap, SRMMU_NOCACHE_BITMAP_SIZE, offset);
+	offset = find_next_zero_bit(srmmu_nocache_bitmap, srmmu_nocache_bitmap_size, offset);
 
 	/* we align on physical address */
 	if (align) {
@@ -258,7 +266,7 @@
 		offset = (va_tmp - SRMMU_NOCACHE_VADDR) >> SRMMU_NOCACHE_BITMAP_SHIFT;
 	}
 
-	if ((SRMMU_NOCACHE_BITMAP_SIZE - offset) < size) {
+	if ((srmmu_nocache_bitmap_size - offset) < size) {
 		printk("Run out of nocached RAM!\n");
 		spin_unlock(&srmmu_nocache_spinlock);
 		return 0;
@@ -322,6 +330,35 @@
 
 void srmmu_early_allocate_ptable_skeleton(unsigned long start, unsigned long end);
 
+extern unsigned long probe_memory(void);	/* in fault.c */
+
+/* Reserve nocache dynamically proportionally to the amount of
+ * system RAM. -- Tomas Szepe <szepe@pinerecords.com>, June 2002
+ */
+void srmmu_nocache_calcsize(void)
+{
+	unsigned long sysmemavail = probe_memory() / 1024;
+
+	srmmu_nocache_npages =
+		sysmemavail / SRMMU_NOCACHE_ALCRATIO / 1024 * 256;
+	if (sysmemavail % (SRMMU_NOCACHE_ALCRATIO * 1024))
+		srmmu_nocache_npages += 256;
+
+	/* anything above 1280 blows up */
+	if (srmmu_nocache_npages > 1280) srmmu_nocache_npages = 1280;
+
+	srmmu_nocache_size = srmmu_nocache_npages * PAGE_SIZE;
+	srmmu_nocache_bitmap_size = srmmu_nocache_npages * 16;
+	srmmu_nocache_end = SRMMU_NOCACHE_VADDR + srmmu_nocache_size;
+	fix_kmap_begin = srmmu_nocache_end;
+	fix_kmap_end = fix_kmap_begin + (KM_TYPE_NR * NR_CPUS - 1) * PAGE_SIZE;
+	pkmap_base = SRMMU_NOCACHE_VADDR + srmmu_nocache_size + 0x40000;
+	pkmap_base_end = pkmap_base + LAST_PKMAP * PAGE_SIZE;
+
+	/* printk("system memory available = %luk\nnocache ram size = %luk\n",
+		sysmemavail, srmmu_nocache_size / 1024); */
+}
+
 void srmmu_nocache_init(void)
 {
 	pgd_t *pgd;
@@ -330,24 +367,24 @@
 	unsigned long paddr, vaddr;
 	unsigned long pteval;
 
-	srmmu_nocache_pool = __alloc_bootmem(SRMMU_NOCACHE_SIZE, PAGE_SIZE, 0UL);
-	memset(srmmu_nocache_pool, 0, SRMMU_NOCACHE_SIZE);
+	srmmu_nocache_pool = __alloc_bootmem(srmmu_nocache_size, PAGE_SIZE, 0UL);
+	memset(srmmu_nocache_pool, 0, srmmu_nocache_size);
 
-	srmmu_nocache_bitmap = __alloc_bootmem(SRMMU_NOCACHE_BITMAP_SIZE, SMP_CACHE_BYTES, 0UL);
-	memset(srmmu_nocache_bitmap, 0, SRMMU_NOCACHE_BITMAP_SIZE);
+	srmmu_nocache_bitmap = __alloc_bootmem(srmmu_nocache_bitmap_size, SMP_CACHE_BYTES, 0UL);
+	memset(srmmu_nocache_bitmap, 0, srmmu_nocache_bitmap_size);
 
 	srmmu_swapper_pg_dir = (pgd_t *)__srmmu_get_nocache(SRMMU_PGD_TABLE_SIZE, SRMMU_PGD_TABLE_SIZE);
 	memset(__nocache_fix(srmmu_swapper_pg_dir), 0, SRMMU_PGD_TABLE_SIZE);
 	init_mm.pgd = srmmu_swapper_pg_dir;
 
-	srmmu_early_allocate_ptable_skeleton(SRMMU_NOCACHE_VADDR, SRMMU_NOCACHE_END);
+	srmmu_early_allocate_ptable_skeleton(SRMMU_NOCACHE_VADDR, srmmu_nocache_end);
 
 	spin_lock_init(&srmmu_nocache_spinlock);
 
 	paddr = __pa((unsigned long)srmmu_nocache_pool);
 	vaddr = SRMMU_NOCACHE_VADDR;
 
-	while (vaddr < SRMMU_NOCACHE_END) {
+	while (vaddr < srmmu_nocache_end) {
 		pgd = pgd_offset_k(vaddr);
 		pmd = srmmu_pmd_offset(__nocache_fix(pgd), vaddr);
 		pte = srmmu_pte_offset(__nocache_fix(pmd), vaddr);
@@ -1144,6 +1181,7 @@
 	pages_avail = 0;
 	last_valid_pfn = bootmem_init(&pages_avail);
 
+	srmmu_nocache_calcsize();
 	srmmu_nocache_init();
         srmmu_inherit_prom_mappings(0xfe400000,(LINUX_OPPROM_ENDVM-PAGE_SIZE));
 	map_kernel();
@@ -1165,12 +1203,12 @@
 	srmmu_allocate_ptable_skeleton(DVMA_VADDR, DVMA_END);
 #endif
 
-	srmmu_allocate_ptable_skeleton(FIX_KMAP_BEGIN, FIX_KMAP_END);
-	srmmu_allocate_ptable_skeleton(PKMAP_BASE, PKMAP_BASE_END);
+	srmmu_allocate_ptable_skeleton(fix_kmap_begin, fix_kmap_end);
+	srmmu_allocate_ptable_skeleton(pkmap_base, pkmap_base_end);
 
-	pgd = pgd_offset_k(PKMAP_BASE);
-	pmd = pmd_offset(pgd, PKMAP_BASE);
-	pte = pte_offset(pmd, PKMAP_BASE);
+	pgd = pgd_offset_k(pkmap_base);
+	pmd = pmd_offset(pgd, pkmap_base);
+	pte = pte_offset(pmd, pkmap_base);
 	pkmap_page_table = pte;
 
 	flush_cache_all();
@@ -1219,7 +1257,7 @@
 		   "nocache used\t: %d\n",
 		   srmmu_name,
 		   num_contexts,
-		   SRMMU_NOCACHE_SIZE,
+		   srmmu_nocache_size,
 		   (srmmu_nocache_used << SRMMU_NOCACHE_BITMAP_SHIFT));
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc/mm/sun4c.c linux-2.4.20/arch/sparc/mm/sun4c.c
--- linux-2.4.19/arch/sparc/mm/sun4c.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc/mm/sun4c.c	2002-10-29 11:18:34.000000000 +0000
@@ -35,6 +35,7 @@
 #include <asm/mmu_context.h>
 #include <asm/sun4paddr.h>
 #include <asm/highmem.h>
+#include <asm/btfixup.h>
 
 /* Because of our dynamic kernel TLB miss strategy, and how
  * our DVMA mapping allocation works, you _MUST_:
@@ -63,25 +64,17 @@
 
 #define SUN4C_KERNEL_BUCKETS 32
 
-#ifndef MAX
-#define MAX(a,b) ((a)<(b)?(b):(a))
-#endif
-#ifndef MIN
-#define MIN(a,b) ((a)<(b)?(a):(b))
-#endif
-
 /* Flushing the cache. */
 struct sun4c_vac_props sun4c_vacinfo;
 unsigned long sun4c_kernel_faults;
 
 /* Invalidate every sun4c cache line tag. */
-void sun4c_flush_all(void)
+static void __init sun4c_flush_all(void)
 {
 	unsigned long begin, end;
 
 	if (sun4c_vacinfo.on)
-		panic("SUN4C: AIEEE, trying to invalidate vac while"
-                      " it is on.");
+		panic("SUN4C: AIEEE, trying to invalidate vac while it is on.");
 
 	/* Clear 'valid' bit in all cache line tags */
 	begin = AC_CACHETAGS;
@@ -93,7 +86,7 @@
 	}
 }
 
-static __inline__ void sun4c_flush_context_hw(void)
+static void sun4c_flush_context_hw(void)
 {
 	unsigned long end = SUN4C_VAC_SIZE;
 
@@ -122,8 +115,17 @@
 	}
 }
 
+/* File local boot time fixups. */
+BTFIXUPDEF_CALL(void, sun4c_flush_page, unsigned long)
+BTFIXUPDEF_CALL(void, sun4c_flush_segment, unsigned long)
+BTFIXUPDEF_CALL(void, sun4c_flush_context, void)
+
+#define sun4c_flush_page(addr) BTFIXUP_CALL(sun4c_flush_page)(addr)
+#define sun4c_flush_segment(addr) BTFIXUP_CALL(sun4c_flush_segment)(addr)
+#define sun4c_flush_context() BTFIXUP_CALL(sun4c_flush_context)()
+
 /* Must be called minimally with interrupts disabled. */
-static __inline__ void sun4c_flush_page_hw(unsigned long addr)
+static void sun4c_flush_page_hw(unsigned long addr)
 {
 	addr &= PAGE_MASK;
 	if ((int)sun4c_get_pte(addr) < 0)
@@ -195,48 +197,6 @@
 	}
 }
 
-/* Bolix one page from the virtual cache. */
-static void sun4c_flush_page(unsigned long addr)
-{
-	addr &= PAGE_MASK;
-
-	if ((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) !=
-	    _SUN4C_PAGE_VALID)
-		return;
-
-	if (sun4c_vacinfo.do_hwflushes) {
-		__asm__ __volatile__("sta %%g0, [%0] %1;nop;nop;nop;\n\t" : :
-				     "r" (addr), "i" (ASI_HWFLUSHPAGE));
-	} else {
-		unsigned long left = PAGE_SIZE;
-		unsigned long lsize = sun4c_vacinfo.linesize;
-
-		__asm__ __volatile__("add	%2, %2, %%g1\n\t"
-				     "add	%2, %%g1, %%g2\n\t"
-				     "add	%2, %%g2, %%g3\n\t"
-				     "add	%2, %%g3, %%g4\n\t"
-				     "add	%2, %%g4, %%g5\n\t"
-				     "add	%2, %%g5, %%o4\n\t"
-				     "add	%2, %%o4, %%o5\n"
-				     "1:\n\t"
-				     "subcc	%1, %%o5, %1\n\t"
-				     "sta	%%g0, [%0] %6\n\t"
-				     "sta	%%g0, [%0 + %2] %6\n\t"
-				     "sta	%%g0, [%0 + %%g1] %6\n\t"
-				     "sta	%%g0, [%0 + %%g2] %6\n\t"
-				     "sta	%%g0, [%0 + %%g3] %6\n\t"
-				     "sta	%%g0, [%0 + %%g4] %6\n\t"
-				     "sta	%%g0, [%0 + %%g5] %6\n\t"
-				     "sta	%%g0, [%0 + %%o4] %6\n\t"
-				     "bg	1b\n\t"
-				     " add	%0, %%o5, %0\n\t"
-				     : "=&r" (addr), "=&r" (left), "=&r" (lsize)
-				     : "0" (addr), "1" (left), "2" (lsize),
-				       "i" (ASI_FLUSHPG)
-				     : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
-	}
-}
-
 /* Don't inline the software version as it eats too many cache lines if expanded. */
 static void sun4c_flush_page_sw(unsigned long addr)
 {
@@ -387,7 +347,8 @@
 			 prom_getintdefault(prom_root_node, "vac_hwflush", 0);
 
 		if (sun4c_vacinfo.num_bytes != 65536) {
-			prom_printf("WEIRD Sun4C VAC cache size, tell davem");
+			prom_printf("WEIRD Sun4C VAC cache size, "
+				    "tell sparclinux@vger.kernel.org");
 			prom_halt();
 		}
 	}
@@ -427,7 +388,7 @@
 		*daddr = *iaddr;	\
 	} while (0);
 
-static void patch_kernel_fault_handler(void)
+static void __init patch_kernel_fault_handler(void)
 {
 	unsigned long *iaddr, *daddr;
 
@@ -459,10 +420,6 @@
 		case 16:
 			PATCH_INSN(num_context_patch1_16,
 				   num_context_patch1);
-#if 0
-			PATCH_INSN(num_context_patch2_16,
-				   num_context_patch2);
-#endif
 			break;
 		default:
 			prom_printf("Unhandled number of contexts: %d\n",
@@ -867,33 +824,7 @@
 #define sun4c_user_unmap(__entry) \
 	sun4c_put_segmap((__entry)->vaddr, invalid_segment)
 
-static void sun4c_demap_context_hw(struct sun4c_mmu_ring *crp, unsigned char ctx)
-{
-	struct sun4c_mmu_entry *head = &crp->ringhd;
-	unsigned long flags;
-
-	save_and_cli(flags);
-	if (head->next != head) {
-		struct sun4c_mmu_entry *entry = head->next;
-		int savectx = sun4c_get_context();
-
-		flush_user_windows();
-		sun4c_set_context(ctx);
-		sun4c_flush_context_hw();
-		do {
-			struct sun4c_mmu_entry *next = entry->next;
-
-			sun4c_user_unmap(entry);
-			free_user_entry(ctx, entry);
-
-			entry = next;
-		} while (entry != head);
-		sun4c_set_context(savectx);
-	}
-	restore_flags(flags);
-}
-
-static void sun4c_demap_context_sw(struct sun4c_mmu_ring *crp, unsigned char ctx)
+static void sun4c_demap_context(struct sun4c_mmu_ring *crp, unsigned char ctx)
 {
 	struct sun4c_mmu_entry *head = &crp->ringhd;
 	unsigned long flags;
@@ -905,7 +836,7 @@
 
 		flush_user_windows();
 		sun4c_set_context(ctx);
-		sun4c_flush_context_sw();
+		sun4c_flush_context();
 		do {
 			struct sun4c_mmu_entry *next = entry->next;
 
@@ -919,8 +850,8 @@
 	restore_flags(flags);
 }
 
-static int sun4c_user_taken_entries = 0;  /* This is how much we have.             */
-static int max_user_taken_entries = 0;    /* This limits us and prevents deadlock. */
+static int sun4c_user_taken_entries;  /* This is how much we have.             */
+static int max_user_taken_entries;    /* This limits us and prevents deadlock. */
 
 static struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
 {
@@ -934,10 +865,7 @@
 
 	/* Else free one up. */
 	this_entry = sun4c_kernel_ring.ringhd.prev;
-	if (sun4c_vacinfo.do_hwflushes)
-		sun4c_flush_segment_hw(this_entry->vaddr);
-	else
-		sun4c_flush_segment_sw(this_entry->vaddr);
+	sun4c_flush_segment(this_entry->vaddr);
 	sun4c_kernel_unmap(this_entry);
 	free_kernel_entry(this_entry, &sun4c_kernel_ring);
 	this_entry = sun4c_kfree_ring.ringhd.next;
@@ -976,10 +904,7 @@
 	savectx = sun4c_get_context();
 	flush_user_windows();
 	sun4c_set_context(ctx);
-	if (sun4c_vacinfo.do_hwflushes)
-		sun4c_flush_segment_hw(entry->vaddr);
-	else
-		sun4c_flush_segment_sw(entry->vaddr);
+	sun4c_flush_segment(entry->vaddr);
 	sun4c_user_unmap(entry);
 	remove_ring(sun4c_context_ring + ctx, entry);
 	remove_lru(entry);
@@ -1068,10 +993,7 @@
 	entry = &mmu_entry_pool[pseg];
 
 	flush_user_windows();
-	if (sun4c_vacinfo.do_hwflushes)
-		sun4c_flush_segment_hw(addr);
-	else
-		sun4c_flush_segment_sw(addr);
+	sun4c_flush_segment(addr);
 	sun4c_kernel_unmap(entry);
 	add_ring(&sun4c_ufree_ring, entry);
 	max_user_taken_entries++;
@@ -1126,17 +1048,10 @@
 	/* We are changing the virtual color of the page(s)
 	 * so we must flush the cache to guarentee consistancy.
 	 */
-	if (sun4c_vacinfo.do_hwflushes) {
-		sun4c_flush_page_hw(pages);
-#ifndef CONFIG_SUN4	
-		sun4c_flush_page_hw(pages + PAGE_SIZE);
-#endif
-	} else {
-		sun4c_flush_page_sw(pages);
+	sun4c_flush_page(pages);
 #ifndef CONFIG_SUN4	
-		sun4c_flush_page_sw(pages + PAGE_SIZE);
+	sun4c_flush_page(pages + PAGE_SIZE);
 #endif
-	}
 
 	sun4c_put_pte(addr, BUCKET_PTE(pages));
 #ifndef CONFIG_SUN4	
@@ -1145,32 +1060,7 @@
 	return (struct task_struct *) addr;
 }
 
-static void sun4c_free_task_struct_hw(struct task_struct *tsk)
-{
-	unsigned long tsaddr = (unsigned long) tsk;
-	unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
-	int entry = BUCKET_NUM(tsaddr);
-
-	if (atomic_dec_and_test(&(tsk)->thread.refcount)) {
-		/* We are deleting a mapping, so the flush here is mandatory. */
-		sun4c_flush_page_hw(tsaddr);
-#ifndef CONFIG_SUN4	
-		sun4c_flush_page_hw(tsaddr + PAGE_SIZE);
-#endif
-		sun4c_put_pte(tsaddr, 0);
-#ifndef CONFIG_SUN4	
-		sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
-#endif
-		sun4c_bucket[entry] = BUCKET_EMPTY;
-		if (entry < sun4c_lowbucket_avail)
-			sun4c_lowbucket_avail = entry;
-
-		free_pages(pages, TASK_STRUCT_ORDER);
-		garbage_collect(entry);
-	}
-}
-
-static void sun4c_free_task_struct_sw(struct task_struct *tsk)
+static void sun4c_free_task_struct(struct task_struct *tsk)
 {
 	unsigned long tsaddr = (unsigned long) tsk;
 	unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
@@ -1178,9 +1068,9 @@
 
 	if (atomic_dec_and_test(&(tsk)->thread.refcount)) {
 		/* We are deleting a mapping, so the flush here is mandatory. */
-		sun4c_flush_page_sw(tsaddr);
+		sun4c_flush_page(tsaddr);
 #ifndef CONFIG_SUN4	
-		sun4c_flush_page_sw(tsaddr + PAGE_SIZE);
+		sun4c_flush_page(tsaddr + PAGE_SIZE);
 #endif
 		sun4c_put_pte(tsaddr, 0);
 #ifndef CONFIG_SUN4	
@@ -1452,130 +1342,7 @@
 	}
 }
 
-static void sun4c_flush_cache_mm_hw(struct mm_struct *mm)
-{
-	int new_ctx = mm->context;
-
-	if (new_ctx != NO_CONTEXT) {
-		flush_user_windows();
-		if (sun4c_context_ring[new_ctx].num_entries) {
-			struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
-			unsigned long flags;
-
-			save_and_cli(flags);
-			if (head->next != head) {
-				struct sun4c_mmu_entry *entry = head->next;
-				int savectx = sun4c_get_context();
-
-				sun4c_set_context(new_ctx);
-				sun4c_flush_context_hw();
-				do {
-					struct sun4c_mmu_entry *next = entry->next;
-
-					sun4c_user_unmap(entry);
-					free_user_entry(new_ctx, entry);
-
-					entry = next;
-				} while (entry != head);
-				sun4c_set_context(savectx);
-			}
-			restore_flags(flags);
-		}
-	}
-}
-
-static void sun4c_flush_cache_range_hw(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
-	int new_ctx = mm->context;
-	
-	if (new_ctx != NO_CONTEXT) {
-		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
-		struct sun4c_mmu_entry *entry;
-		unsigned long flags;
-
-		flush_user_windows();
-
-		save_and_cli(flags);
-
-		/* All user segmap chains are ordered on entry->vaddr. */
-		for (entry = head->next;
-		     (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
-		     entry = entry->next)
-			;
-
-		/* Tracing various job mixtures showed that this conditional
-		 * only passes ~35% of the time for most worse case situations,
-		 * therefore we avoid all of this gross overhead ~65% of the time.
-		 */
-		if ((entry != head) && (entry->vaddr < end)) {
-			int octx = sun4c_get_context();
-
-			sun4c_set_context(new_ctx);
-
-			/* At this point, always, (start >= entry->vaddr) and
-			 * (entry->vaddr < end), once the latter condition
-			 * ceases to hold, or we hit the end of the list, we
-			 * exit the loop.  The ordering of all user allocated
-			 * segmaps makes this all work out so beautifully.
-			 */
-			do {
-				struct sun4c_mmu_entry *next = entry->next;
-				unsigned long realend;
-
-				/* "realstart" is always >= entry->vaddr */
-				realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE;
-				if (end < realend)
-					realend = end;
-				if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
-					unsigned long page = entry->vaddr;
-					while (page < realend) {
-						sun4c_flush_page_hw(page);
-						page += PAGE_SIZE;
-					}
-				} else {
-					sun4c_flush_segment_hw(entry->vaddr);
-					sun4c_user_unmap(entry);
-					free_user_entry(new_ctx, entry);
-				}
-				entry = next;
-			} while ((entry != head) && (entry->vaddr < end));
-			sun4c_set_context(octx);
-		}
-		restore_flags(flags);
-	}
-}
-
-static void sun4c_flush_cache_page_hw(struct vm_area_struct *vma, unsigned long page)
-{
-	struct mm_struct *mm = vma->vm_mm;
-	int new_ctx = mm->context;
-
-	/* Sun4c has no separate I/D caches so cannot optimize for non
-	 * text page flushes.
-	 */
-	if (new_ctx != NO_CONTEXT) {
-		int octx = sun4c_get_context();
-		unsigned long flags;
-
-		flush_user_windows();
-		save_and_cli(flags);
-		sun4c_set_context(new_ctx);
-		sun4c_flush_page_hw(page);
-		sun4c_set_context(octx);
-		restore_flags(flags);
-	}
-}
-
-static void sun4c_flush_page_to_ram_hw(unsigned long page)
-{
-	unsigned long flags;
-
-	save_and_cli(flags);
-	sun4c_flush_page_hw(page);
-	restore_flags(flags);
-}
-
-static void sun4c_flush_cache_mm_sw(struct mm_struct *mm)
+static void sun4c_flush_cache_mm(struct mm_struct *mm)
 {
 	int new_ctx = mm->context;
 
@@ -1592,7 +1359,7 @@
 				int savectx = sun4c_get_context();
 
 				sun4c_set_context(new_ctx);
-				sun4c_flush_context_sw();
+				sun4c_flush_context();
 				do {
 					struct sun4c_mmu_entry *next = entry->next;
 
@@ -1608,7 +1375,7 @@
 	}
 }
 
-static void sun4c_flush_cache_range_sw(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void sun4c_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
 	int new_ctx = mm->context;
 
@@ -1651,11 +1418,11 @@
 				if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
 					unsigned long page = entry->vaddr;
 					while (page < realend) {
-						sun4c_flush_page_sw(page);
+						sun4c_flush_page(page);
 						page += PAGE_SIZE;
 					}
 				} else {
-					sun4c_flush_segment_sw(entry->vaddr);
+					sun4c_flush_segment(entry->vaddr);
 					sun4c_user_unmap(entry);
 					free_user_entry(new_ctx, entry);
 				}
@@ -1667,7 +1434,7 @@
 	}
 }
 
-static void sun4c_flush_cache_page_sw(struct vm_area_struct *vma, unsigned long page)
+static void sun4c_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
 {
 	struct mm_struct *mm = vma->vm_mm;
 	int new_ctx = mm->context;
@@ -1682,18 +1449,18 @@
 		flush_user_windows();
 		save_and_cli(flags);
 		sun4c_set_context(new_ctx);
-		sun4c_flush_page_sw(page);
+		sun4c_flush_page(page);
 		sun4c_set_context(octx);
 		restore_flags(flags);
 	}
 }
 
-static void sun4c_flush_page_to_ram_sw(unsigned long page)
+static void sun4c_flush_page_to_ram(unsigned long page)
 {
 	unsigned long flags;
 
 	save_and_cli(flags);
-	sun4c_flush_page_sw(page);
+	sun4c_flush_page(page);
 	restore_flags(flags);
 }
 
@@ -1721,10 +1488,7 @@
 	flush_user_windows();
 	while (sun4c_kernel_ring.num_entries) {
 		next_entry = this_entry->next;
-		if (sun4c_vacinfo.do_hwflushes)
-			sun4c_flush_segment_hw(this_entry->vaddr);
-		else
-			sun4c_flush_segment_sw(this_entry->vaddr);
+		sun4c_flush_segment(this_entry->vaddr);
 		for (ctx = 0; ctx < num_contexts; ctx++) {
 			sun4c_set_context(ctx);
 			sun4c_put_segmap(this_entry->vaddr, invalid_segment);
@@ -1736,7 +1500,7 @@
 	restore_flags(flags);
 }
 
-static void sun4c_flush_tlb_mm_hw(struct mm_struct *mm)
+static void sun4c_flush_tlb_mm(struct mm_struct *mm)
 {
 	int new_ctx = mm->context;
 
@@ -1750,7 +1514,7 @@
 			int savectx = sun4c_get_context();
 
 			sun4c_set_context(new_ctx);
-			sun4c_flush_context_hw();
+			sun4c_flush_context();
 			do {
 				struct sun4c_mmu_entry *next = entry->next;
 
@@ -1765,7 +1529,7 @@
 	}
 }
 
-static void sun4c_flush_tlb_range_hw(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void sun4c_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
 	int new_ctx = mm->context;
 
@@ -1775,7 +1539,7 @@
 		unsigned long flags;
 
 		save_and_cli(flags);
-		/* See commentary in sun4c_flush_cache_range_*(). */
+		/* See commentary in sun4c_flush_cache_range(). */
 		for (entry = head->next;
 		     (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
 		     entry = entry->next)
@@ -1788,7 +1552,7 @@
 			do {
 				struct sun4c_mmu_entry *next = entry->next;
 
-				sun4c_flush_segment_hw(entry->vaddr);
+				sun4c_flush_segment(entry->vaddr);
 				sun4c_user_unmap(entry);
 				free_user_entry(new_ctx, entry);
 
@@ -1800,7 +1564,7 @@
 	}
 }
 
-static void sun4c_flush_tlb_page_hw(struct vm_area_struct *vma, unsigned long page)
+static void sun4c_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 {
 	struct mm_struct *mm = vma->vm_mm;
 	int new_ctx = mm->context;
@@ -1812,90 +1576,7 @@
 		save_and_cli(flags);
 		sun4c_set_context(new_ctx);
 		page &= PAGE_MASK;
-		sun4c_flush_page_hw(page);
-		sun4c_put_pte(page, 0);
-		sun4c_set_context(savectx);
-		restore_flags(flags);
-	}
-}
-
-static void sun4c_flush_tlb_mm_sw(struct mm_struct *mm)
-{
-	int new_ctx = mm->context;
-
-	if (new_ctx != NO_CONTEXT) {
-		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
-		unsigned long flags;
-
-		save_and_cli(flags);
-		if (head->next != head) {
-			struct sun4c_mmu_entry *entry = head->next;
-			int savectx = sun4c_get_context();
-
-			sun4c_set_context(new_ctx);
-			sun4c_flush_context_sw();
-			do {
-				struct sun4c_mmu_entry *next = entry->next;
-
-				sun4c_user_unmap(entry);
-				free_user_entry(new_ctx, entry);
-
-				entry = next;
-			} while (entry != head);
-			sun4c_set_context(savectx);
-		}
-		restore_flags(flags);
-	}
-}
-
-static void sun4c_flush_tlb_range_sw(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
-	int new_ctx = mm->context;
-
-	if (new_ctx != NO_CONTEXT) {
-		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
-		struct sun4c_mmu_entry *entry;
-		unsigned long flags;
-
-		save_and_cli(flags);
-		/* See commentary in sun4c_flush_cache_range_*(). */
-		for (entry = head->next;
-		     (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
-		     entry = entry->next)
-			;
-
-		if ((entry != head) && (entry->vaddr < end)) {
-			int octx = sun4c_get_context();
-
-			sun4c_set_context(new_ctx);
-			do {
-				struct sun4c_mmu_entry *next = entry->next;
-
-				sun4c_flush_segment_sw(entry->vaddr);
-				sun4c_user_unmap(entry);
-				free_user_entry(new_ctx, entry);
-
-				entry = next;
-			} while ((entry != head) && (entry->vaddr < end));
-			sun4c_set_context(octx);
-		}
-		restore_flags(flags);
-	}
-}
-
-static void sun4c_flush_tlb_page_sw(struct vm_area_struct *vma, unsigned long page)
-{
-	struct mm_struct *mm = vma->vm_mm;
-	int new_ctx = mm->context;
-
-	if (new_ctx != NO_CONTEXT) {
-		int savectx = sun4c_get_context();
-		unsigned long flags;
-
-		save_and_cli(flags);
-		sun4c_set_context(new_ctx);
-		page &= PAGE_MASK;
-		sun4c_flush_page_sw(page);
+		sun4c_flush_page(page);
 		sun4c_put_pte(page, 0);
 		sun4c_set_context(savectx);
 		restore_flags(flags);
@@ -1919,7 +1600,7 @@
 	sun4c_put_pte(virt_addr, 0);
 }
 
-static void sun4c_alloc_context_hw(struct mm_struct *old_mm, struct mm_struct *mm)
+static void sun4c_alloc_context(struct mm_struct *old_mm, struct mm_struct *mm)
 {
 	struct ctx_list *ctxp;
 
@@ -1939,19 +1620,19 @@
 	ctxp->ctx_mm->context = NO_CONTEXT;
 	ctxp->ctx_mm = mm;
 	mm->context = ctxp->ctx_number;
-	sun4c_demap_context_hw(&sun4c_context_ring[ctxp->ctx_number],
+	sun4c_demap_context(&sun4c_context_ring[ctxp->ctx_number],
 			       ctxp->ctx_number);
 }
 
 /* Switch the current MM context. */
-static void sun4c_switch_mm_hw(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu)
+static void sun4c_switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu)
 {
 	struct ctx_list *ctx;
 	int dirty = 0;
 
 	if (mm->context == NO_CONTEXT) {
 		dirty = 1;
-		sun4c_alloc_context_hw(old_mm, mm);
+		sun4c_alloc_context(old_mm, mm);
 	} else {
 		/* Update the LRU ring of contexts. */
 		ctx = ctx_list_pool + mm->context;
@@ -1962,69 +1643,12 @@
 		sun4c_set_context(mm->context);
 }
 
-static void sun4c_destroy_context_hw(struct mm_struct *mm)
+static void sun4c_destroy_context(struct mm_struct *mm)
 {
 	struct ctx_list *ctx_old;
 
 	if (mm->context != NO_CONTEXT) {
-		sun4c_demap_context_hw(&sun4c_context_ring[mm->context], mm->context);
-		ctx_old = ctx_list_pool + mm->context;
-		remove_from_ctx_list(ctx_old);
-		add_to_free_ctxlist(ctx_old);
-		mm->context = NO_CONTEXT;
-	}
-}
-
-static void sun4c_alloc_context_sw(struct mm_struct *old_mm, struct mm_struct *mm)
-{
-	struct ctx_list *ctxp;
-
-	ctxp = ctx_free.next;
-	if (ctxp != &ctx_free) {
-		remove_from_ctx_list(ctxp);
-		add_to_used_ctxlist(ctxp);
-		mm->context = ctxp->ctx_number;
-		ctxp->ctx_mm = mm;
-		return;
-	}
-	ctxp = ctx_used.next;
-	if(ctxp->ctx_mm == old_mm)
-		ctxp = ctxp->next;
-	remove_from_ctx_list(ctxp);
-	add_to_used_ctxlist(ctxp);
-	ctxp->ctx_mm->context = NO_CONTEXT;
-	ctxp->ctx_mm = mm;
-	mm->context = ctxp->ctx_number;
-	sun4c_demap_context_sw(&sun4c_context_ring[ctxp->ctx_number],
-			       ctxp->ctx_number);
-}
-
-/* Switch the current MM context. */
-static void sun4c_switch_mm_sw(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu)
-{
-	struct ctx_list *ctx;
-	int dirty = 0;
-
-	if (mm->context == NO_CONTEXT) {
-		dirty = 1;
-		sun4c_alloc_context_sw(old_mm, mm);
-	} else {
-		/* Update the LRU ring of contexts. */
-		ctx = ctx_list_pool + mm->context;
-		remove_from_ctx_list(ctx);
-		add_to_used_ctxlist(ctx);
-	}
-
-	if (dirty || old_mm != mm)
-		sun4c_set_context(mm->context);
-}
-
-static void sun4c_destroy_context_sw(struct mm_struct *mm)
-{
-	struct ctx_list *ctx_old;
-
-	if (mm->context != NO_CONTEXT) {
-		sun4c_demap_context_sw(&sun4c_context_ring[mm->context], mm->context);
+		sun4c_demap_context(&sun4c_context_ring[mm->context], mm->context);
 		ctx_old = ctx_list_pool + mm->context;
 		remove_from_ctx_list(ctx_old);
 		add_to_free_ctxlist(ctx_old);
@@ -2091,7 +1715,7 @@
 
 static void sun4c_pmd_set(pmd_t * pmdp, pte_t * ptep)
 {
-	*pmdp = (PGD_TABLE | (unsigned long) ptep);
+	*pmdp = __pmd(PGD_TABLE | (unsigned long) ptep);
 }
 
 static int sun4c_pte_present(pte_t pte)
@@ -2174,10 +1798,7 @@
 	return (pmd_val(pmd) & PAGE_MASK);
 }
 
-static unsigned long sun4c_pgd_page(pgd_t pgd)
-{
-	return 0;
-}
+static unsigned long sun4c_pgd_page(pgd_t pgd) { return 0; }
 
 /* to find an entry in a page-table-directory */
 static inline pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address)
@@ -2271,9 +1892,7 @@
 	return NULL;
 }
 
-static void sun4c_free_pmd_fast(pmd_t * pmd)
-{
-}
+static void sun4c_free_pmd_fast(pmd_t * pmd) { }
 
 static int sun4c_check_pgt_cache(int low, int high)
 {
@@ -2352,6 +1971,9 @@
 extern unsigned long last_valid_pfn;
 extern void sun_serial_setup(void);
 
+extern unsigned long fix_kmap_begin;
+extern unsigned long fix_kmap_end;
+
 void __init sun4c_paging_init(void)
 {
 	int i, cnt;
@@ -2359,6 +1981,9 @@
 	extern struct resource sparc_iomap;
 	unsigned long end_pfn, pages_avail;
 
+	fix_kmap_begin = KERNBASE + SRMMU_MAXMEM; /* Why bother with SRMMU_MAXMEM? */
+	fix_kmap_end = fix_kmap_begin + ((KM_TYPE_NR*NR_CPUS)-1)*PAGE_SIZE;
+
 	kernel_end = (unsigned long) &end;
 	kernel_end += (SUN4C_REAL_PGDIR_SIZE * 4);
 	kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
@@ -2466,37 +2091,31 @@
 		    _SUN4C_PAGE_IO | _SUN4C_PAGE_NOCACHE;
 	
 	/* Functions */
-#ifndef CONFIG_SMP
 	BTFIXUPSET_CALL(___xchg32, ___xchg32_sun4c, BTFIXUPCALL_NORM);
-#endif
 	BTFIXUPSET_CALL(do_check_pgt_cache, sun4c_check_pgt_cache, BTFIXUPCALL_NORM);
 	
 	BTFIXUPSET_CALL(flush_cache_all, sun4c_flush_cache_all, BTFIXUPCALL_NORM);
 
 	if (sun4c_vacinfo.do_hwflushes) {
-		BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(__flush_page_to_ram, sun4c_flush_page_to_ram_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_tlb_mm, sun4c_flush_tlb_mm_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_tlb_range, sun4c_flush_tlb_range_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_tlb_page, sun4c_flush_tlb_page_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(free_task_struct, sun4c_free_task_struct_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(switch_mm, sun4c_switch_mm_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(destroy_context, sun4c_destroy_context_hw, BTFIXUPCALL_NORM);
+		BTFIXUPSET_CALL(sun4c_flush_page, sun4c_flush_page_hw, BTFIXUPCALL_NORM);
+		BTFIXUPSET_CALL(sun4c_flush_segment, sun4c_flush_segment_hw, BTFIXUPCALL_NORM);
+		BTFIXUPSET_CALL(sun4c_flush_context, sun4c_flush_context_hw, BTFIXUPCALL_NORM);
 	} else {
-		BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(__flush_page_to_ram, sun4c_flush_page_to_ram_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_tlb_mm, sun4c_flush_tlb_mm_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_tlb_range, sun4c_flush_tlb_range_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_tlb_page, sun4c_flush_tlb_page_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(free_task_struct, sun4c_free_task_struct_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(switch_mm, sun4c_switch_mm_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(destroy_context, sun4c_destroy_context_sw, BTFIXUPCALL_NORM);
+		BTFIXUPSET_CALL(sun4c_flush_page, sun4c_flush_page_sw, BTFIXUPCALL_NORM);
+		BTFIXUPSET_CALL(sun4c_flush_segment, sun4c_flush_segment_sw, BTFIXUPCALL_NORM);
+		BTFIXUPSET_CALL(sun4c_flush_context, sun4c_flush_context_sw, BTFIXUPCALL_NORM);
 	}
 
+	BTFIXUPSET_CALL(flush_tlb_mm, sun4c_flush_tlb_mm, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(destroy_context, sun4c_destroy_context, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(switch_mm, sun4c_switch_mm, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(flush_tlb_page, sun4c_flush_tlb_page, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(flush_tlb_range, sun4c_flush_tlb_range, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(free_task_struct, sun4c_free_task_struct, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(__flush_page_to_ram, sun4c_flush_page_to_ram, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(flush_tlb_all, sun4c_flush_tlb_all, BTFIXUPCALL_NORM);
 
 	BTFIXUPSET_CALL(flush_sig_insns, sun4c_flush_sig_insns, BTFIXUPCALL_NOP);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/config.in linux-2.4.20/arch/sparc64/config.in
--- linux-2.4.19/arch/sparc64/config.in	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/config.in	2002-10-29 11:18:36.000000000 +0000
@@ -262,10 +262,10 @@
 
 mainmenu_option next_comment
 comment 'XFree86 DRI support'
-bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
-dep_tristate '  Creator/Creator3D' CONFIG_DRM_FFB $CONFIG_DRM
-dep_tristate '  3dfx Banshee/Voodoo3+' CONFIG_DRM_TDFX $CONFIG_DRM
-dep_tristate '  ATI Rage 128' CONFIG_DRM_R128 $CONFIG_DRM
+bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM_NEW
+dep_tristate '  Creator/Creator3D' CONFIG_DRM_FFB $CONFIG_DRM_NEW
+dep_tristate '  3dfx Banshee/Voodoo3+' CONFIG_DRM_TDFX $CONFIG_DRM_NEW
+dep_tristate '  ATI Rage 128' CONFIG_DRM_R128 $CONFIG_DRM_NEW
 endmenu
 
 source drivers/input/Config.in
@@ -308,3 +308,5 @@
 fi
 
 endmenu
+
+source lib/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/defconfig linux-2.4.20/arch/sparc64/defconfig
--- linux-2.4.19/arch/sparc64/defconfig	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/defconfig	2002-10-29 11:18:36.000000000 +0000
@@ -225,6 +225,7 @@
 #
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
 CONFIG_NET_SCH_CSZ=m
 CONFIG_NET_SCH_PRIO=m
 CONFIG_NET_SCH_RED=m
@@ -417,9 +418,7 @@
 #
 # Device Drivers
 #
-CONFIG_IEEE1394_PCILYNX=m
-# CONFIG_IEEE1394_PCILYNX_LOCALRAM is not set
-# CONFIG_IEEE1394_PCILYNX_PORTS is not set
+# CONFIG_IEEE1394_PCILYNX is not set
 CONFIG_IEEE1394_OHCI1394=m
 
 #
@@ -427,6 +426,7 @@
 #
 # CONFIG_IEEE1394_VIDEO1394 is not set
 CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
 CONFIG_IEEE1394_ETH1394=m
 CONFIG_IEEE1394_DV1394=m
 CONFIG_IEEE1394_RAWIO=m
@@ -477,17 +477,16 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_TULIP=m
-# CONFIG_TC35815 is not set
 # CONFIG_TULIP_MWI is not set
 # CONFIG_TULIP_MMIO is not set
 CONFIG_DE4X5=m
 CONFIG_DGRS=m
 # CONFIG_DM9102 is not set
 CONFIG_EEPRO100=m
+CONFIG_E100=m
 # CONFIG_LNE390 is not set
 CONFIG_FEALNX=m
 CONFIG_NATSEMI=m
-# CONFIG_NATSEMI_CABLE_MAGIC is not set
 CONFIG_NE2K_PCI=m
 # CONFIG_NE3210 is not set
 # CONFIG_ES3210 is not set
@@ -496,11 +495,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 CONFIG_SIS900=m
 CONFIG_EPIC100=m
 CONFIG_SUNDANCE=m
+CONFIG_SUNDANCE_MMIO=y
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 CONFIG_VIA_RHINE=m
 # CONFIG_VIA_RHINE_MMIO is not set
 CONFIG_WINBOND_840=m
@@ -512,9 +513,10 @@
 CONFIG_ACENIC=m
 # CONFIG_ACENIC_OMIT_TIGON_I is not set
 CONFIG_DL2K=m
+CONFIG_E1000=m
 CONFIG_MYRI_SBUS=m
 CONFIG_NS83820=m
-CONFIG_HAMACHI=m
+# CONFIG_HAMACHI is not set
 CONFIG_YELLOWFIN=m
 CONFIG_SK98LIN=m
 CONFIG_TIGON3=m
@@ -571,7 +573,7 @@
 #
 # XFree86 DRI support
 #
-CONFIG_DRM=y
+CONFIG_DRM_NEW=y
 CONFIG_DRM_FFB=m
 CONFIG_DRM_TDFX=m
 # CONFIG_DRM_R128 is not set
@@ -600,6 +602,8 @@
 # CONFIG_ADFS_FS_RW is not set
 CONFIG_AFFS_FS=m
 # CONFIG_HFS_FS is not set
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
 CONFIG_BFS_FS=m
 CONFIG_EXT3_FS=m
 CONFIG_JBD=m
@@ -617,6 +621,9 @@
 CONFIG_ISO9660_FS=m
 CONFIG_JOLIET=y
 # CONFIG_ZISOFS is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
 CONFIG_MINIX_FS=m
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -647,6 +654,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=m
 CONFIG_NFSD_V3=y
+CONFIG_NFSD_TCP=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -661,7 +669,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -718,6 +725,7 @@
 # Sound
 #
 CONFIG_SOUND=m
+# CONFIG_SOUND_ALI5455 is not set
 CONFIG_SOUND_BT878=m
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
@@ -729,6 +737,7 @@
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
@@ -767,6 +776,7 @@
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_EMI26 is not set
 CONFIG_USB_BLUETOOTH=m
+CONFIG_USB_MIDI=m
 CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -775,6 +785,7 @@
 CONFIG_USB_STORAGE_DPCM=y
 CONFIG_USB_STORAGE_HP8200e=y
 CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
 CONFIG_USB_ACM=m
 CONFIG_USB_PRINTER=m
@@ -785,6 +796,7 @@
 CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_HIDDEV is not set
+CONFIG_USB_AIPTEK=m
 CONFIG_USB_WACOM=m
 
 #
@@ -827,6 +839,7 @@
 # USB Serial Converter support
 #
 CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_DEBUG is not set
 CONFIG_USB_SERIAL_GENERIC=y
 CONFIG_USB_SERIAL_BELKIN=m
 CONFIG_USB_SERIAL_WHITEHEAT=m
@@ -837,6 +850,7 @@
 CONFIG_USB_SERIAL_IPAQ=m
 # CONFIG_USB_SERIAL_IR is not set
 CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
 CONFIG_USB_SERIAL_KEYSPAN_PDA=m
 CONFIG_USB_SERIAL_KEYSPAN=m
 # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
@@ -846,6 +860,8 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 CONFIG_USB_SERIAL_MCT_U232=m
 CONFIG_USB_SERIAL_KLSI=m
@@ -859,6 +875,9 @@
 #
 CONFIG_USB_RIO500=m
 # CONFIG_USB_AUERSWALD is not set
+CONFIG_USB_TIGL=m
+# CONFIG_USB_BRLVGER is not set
+CONFIG_USB_LCD=m
 
 #
 # Bluetooth support
@@ -866,16 +885,20 @@
 CONFIG_BLUEZ=m
 CONFIG_BLUEZ_L2CAP=m
 CONFIG_BLUEZ_SCO=m
+CONFIG_BLUEZ_BNEP=m
+CONFIG_BNEP_MC_FILTER=y
+CONFIG_BNEP_PROTO_FILTER=y
 
 #
 # Bluetooth device drivers
 #
 CONFIG_BLUEZ_HCIUSB=m
-CONFIG_BLUEZ_USB_FW_LOAD=y
 CONFIG_BLUEZ_USB_ZERO_PACKET=y
 CONFIG_BLUEZ_HCIUART=m
 CONFIG_BLUEZ_HCIUART_H4=y
 # CONFIG_BLUEZ_HCIDTL1 is not set
+# CONFIG_BLUEZ_HCIBT3C is not set
+# CONFIG_BLUEZ_HCIBLUECARD is not set
 CONFIG_BLUEZ_HCIVHCI=m
 
 #
@@ -893,3 +916,9 @@
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_DCFLUSH is not set
 # CONFIG_STACK_DEBUG is not set
+
+#
+# Library routines
+#
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/chmc.c linux-2.4.20/arch/sparc64/kernel/chmc.c
--- linux-2.4.19/arch/sparc64/kernel/chmc.c	2001-04-12 19:10:25.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/chmc.c	2002-10-29 11:18:35.000000000 +0000
@@ -420,7 +420,7 @@
 	int index;
 
 	/* This driver is only for cheetah platforms. */
-	if (tlb_type != cheetah)
+	if (tlb_type != cheetah && tlb_type != cheetah_plus)
 		return -ENODEV;
 
 	index = probe_for_string("memory-controller", 0);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/cpu.c linux-2.4.20/arch/sparc64/kernel/cpu.c
--- linux-2.4.19/arch/sparc64/kernel/cpu.c	2001-03-26 02:14:21.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/cpu.c	2002-10-29 11:18:49.000000000 +0000
@@ -36,6 +36,7 @@
   { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"},
   { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"},
   { 0x3e, 0x14, 0, "UltraSparc III integrated FPU"},
+  { 0x3e, 0x15, 0, "UltraSparc III+ integrated FPU"},
 };
 
 #define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
@@ -47,6 +48,7 @@
   { 0x17, 0x12, "TI UltraSparc IIi"},
   { 0x17, 0x13, "TI UltraSparc IIe"},
   { 0x3e, 0x14, "TI UltraSparc III (Cheetah)"},
+  { 0x3e, 0x15, "TI UltraSparc III+ (Cheetah+)"},
 };
 
 #define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
@@ -63,48 +65,63 @@
 
 void __init cpu_probe(void)
 {
-	int manuf, impl;
-	unsigned i, cpuid;
-	long ver, fpu_vers;
-	long fprs;
+	unsigned long ver, fpu_vers, manuf, impl, fprs;
+	int i, cpuid;
 	
 	cpuid = hard_smp_processor_id();
 
-	fprs = fprs_read ();
-	fprs_write (FPRS_FEF);
-	__asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]" : "=&r" (ver) : "r" (&fpu_vers));
-	fprs_write (fprs);
+	fprs = fprs_read();
+	fprs_write(FPRS_FEF);
+	__asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]"
+			      : "=&r" (ver)
+			      : "r" (&fpu_vers));
+	fprs_write(fprs);
 	
-	manuf = ((ver >> 48)&0xffff);
-	impl = ((ver >> 32)&0xffff);
+	manuf = ((ver >> 48) & 0xffff);
+	impl = ((ver >> 32) & 0xffff);
 
-	fpu_vers = ((fpu_vers>>17)&0x7);
+	fpu_vers = ((fpu_vers >> 17) & 0x7);
 
-	for(i = 0; i<NSPARCCHIPS; i++) {
-		if(linux_sparc_chips[i].manuf == manuf)
-			if(linux_sparc_chips[i].impl == impl) {
-				sparc_cpu_type[cpuid] = linux_sparc_chips[i].cpu_name;
+ retry:
+	for (i = 0; i < NSPARCCHIPS; i++) {
+		if (linux_sparc_chips[i].manuf == manuf) {
+			if (linux_sparc_chips[i].impl == impl) {
+				sparc_cpu_type[cpuid]
+					= linux_sparc_chips[i].cpu_name;
 				break;
 			}
+		}
 	}
 
-	if(i==NSPARCCHIPS) {
-		printk("DEBUG: manuf = 0x%x   impl = 0x%x\n", manuf, 
-			    impl);
+	if (i == NSPARCCHIPS) {
+		/* Maybe it is a cheetah+ derivative, report it as cheetah+
+		 * in that case until we learn the real names.
+		 */
+		if (manuf == 0x3e &&
+		    impl > 0x15) {
+			impl = 0x15;
+			goto retry;
+		} else {
+			printk("DEBUG: manuf[%lx] impl[%lx]\n",
+			       manuf, impl);
+		}
 		sparc_cpu_type[cpuid] = "Unknown CPU";
 	}
 
-	for(i = 0; i<NSPARCFPU; i++) {
-		if(linux_sparc_fpu[i].manuf == manuf && linux_sparc_fpu[i].impl == impl)
-			if(linux_sparc_fpu[i].fpu_vers == fpu_vers) {
-				sparc_fpu_type[cpuid] = linux_sparc_fpu[i].fp_name;
+	for (i = 0; i < NSPARCFPU; i++) {
+		if (linux_sparc_fpu[i].manuf == manuf &&
+		    linux_sparc_fpu[i].impl == impl) {
+			if (linux_sparc_fpu[i].fpu_vers == fpu_vers) {
+				sparc_fpu_type[cpuid]
+					= linux_sparc_fpu[i].fp_name;
 				break;
 			}
+		}
 	}
 
-	if(i == NSPARCFPU) {
-		printk("DEBUG: manuf = 0x%x  impl = 0x%x fsr.vers = 0x%x\n", manuf, impl,
-			    (unsigned)fpu_vers);
+	if (i == NSPARCFPU) {
+		printk("DEBUG: manuf[%lx] impl[%lx] fsr.vers[%lx]\n",
+		       manuf, impl, fpu_vers);
 		sparc_fpu_type[cpuid] = "Unknown FPU";
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/devices.c linux-2.4.20/arch/sparc64/kernel/devices.c
--- linux-2.4.19/arch/sparc64/kernel/devices.c	2001-06-12 18:08:46.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/devices.c	2002-10-29 11:18:35.000000000 +0000
@@ -57,7 +57,8 @@
 				if (tlb_type == spitfire) {
 					prom_getproperty(scan, "upa-portid",
 							 (char *) &thismid, sizeof(thismid));
-				} else if (tlb_type == cheetah) {
+				} else if (tlb_type == cheetah ||
+					   tlb_type == cheetah_plus) {
 					prom_getproperty(scan, "portid",
 							 (char *) &thismid, sizeof(thismid));
 				}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/dtlb_base.S linux-2.4.20/arch/sparc64/kernel/dtlb_base.S
--- linux-2.4.19/arch/sparc64/kernel/dtlb_base.S	2001-10-17 21:16:39.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/dtlb_base.S	2002-10-29 11:18:40.000000000 +0000
@@ -70,7 +70,7 @@
 	CREATE_VPTE_OFFSET1(%g4, %g6)			! Create VPTE offset
 	be,pn		%xcc, 3f			! Yep, special processing
 	 CREATE_VPTE_OFFSET2(%g4, %g6)			! Create VPTE offset
-	cmp		%g5, 3				! Last trap level?
+	cmp		%g5, 4				! Last trap level?
 	be,pn		%xcc, longpath			! Yep, cannot risk VPTE miss
 	 nop						! delay slot
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/entry.S linux-2.4.20/arch/sparc64/kernel/entry.S
--- linux-2.4.19/arch/sparc64/kernel/entry.S	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/entry.S	2002-10-29 11:18:30.000000000 +0000
@@ -774,7 +774,14 @@
 	membar		#Sync
 	sethi		%hi(109f), %g7
 	ba,pt		%xcc, etraptl1
-	 or		%g7, %lo(109f), %g7	! Merge in below
+109:	 or		%g7, %lo(109b), %g7
+	mov		%l4, %o1
+	mov		%l5, %o2
+	call		instruction_access_exception_tl1
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+
 __do_instruction_access_exception:
 	rdpr		%pstate, %g4
 	wrpr		%g4, PSTATE_MG|PSTATE_AG, %pstate
@@ -1074,6 +1081,181 @@
 	jmpl		%g2 + %lo(cheetah_deferred_trap), %g0
 	 mov		1, %g1
 
+	/* Cheetah+ specific traps. These are for the new I/D cache parity
+	 * error traps.  The first argument to cheetah_plus_parity_handler
+	 * is encoded as follows:
+	 *
+	 * Bit0:	0=dcache,1=icache
+	 * Bit1:	0=recoverable,1=unrecoverable
+	 */
+	.globl		cheetah_plus_dcpe_trap_vector, cheetah_plus_dcpe_trap_vector_tl1
+cheetah_plus_dcpe_trap_vector:
+	membar		#Sync
+	sethi		%hi(do_cheetah_plus_data_parity), %g7
+	jmpl		%g7 + %lo(do_cheetah_plus_data_parity), %g0
+	 nop
+	nop
+	nop
+	nop
+	nop
+
+do_cheetah_plus_data_parity:
+	ba,pt		%xcc, etrap
+	 rd		%pc, %g7
+	mov		0x0, %o0
+	call		cheetah_plus_parity_error
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+
+cheetah_plus_dcpe_trap_vector_tl1:
+	membar		#Sync
+	wrpr		PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate
+	sethi		%hi(do_dcpe_tl1), %g3
+	jmpl		%g3 + %lo(do_dcpe_tl1), %g0
+	 nop
+	nop
+	nop
+	nop
+
+	.globl		cheetah_plus_icpe_trap_vector, cheetah_plus_icpe_trap_vector_tl1
+cheetah_plus_icpe_trap_vector:
+	membar		#Sync
+	sethi		%hi(do_cheetah_plus_insn_parity), %g7
+	jmpl		%g7 + %lo(do_cheetah_plus_insn_parity), %g0
+	 nop
+	nop
+	nop
+	nop
+	nop
+
+do_cheetah_plus_insn_parity:
+	ba,pt		%xcc, etrap
+	 rd		%pc, %g7
+	mov		0x1, %o0
+	call		cheetah_plus_parity_error
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+
+cheetah_plus_icpe_trap_vector_tl1:
+	membar		#Sync
+	wrpr		PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate
+	sethi		%hi(do_icpe_tl1), %g3
+	jmpl		%g3 + %lo(do_icpe_tl1), %g0
+	 nop
+	nop
+	nop
+	nop
+
+	/* If we take one of these traps when tl >= 1, then we
+	 * jump to interrupt globals.  If some trap level above us
+	 * was also using interrupt globals, we cannot recover.
+	 * We may use all interrupt global registers except %g6.
+	 */
+	.globl		do_dcpe_tl1, do_icpe_tl1
+do_dcpe_tl1:
+	rdpr		%tl, %g1		! Save original trap level
+	mov		1, %g2			! Setup TSTATE checking loop
+	sethi		%hi(TSTATE_IG), %g3	! TSTATE mask bit
+1:	wrpr		%g2, %tl		! Set trap level to check
+	rdpr		%tstate, %g4		! Read TSTATE for this level
+	andcc		%g4, %g3, %g0		! Interrupt globals in use?
+	bne,a,pn	%xcc, do_dcpe_tl1_fatal	! Yep, irrecoverable
+	 wrpr		%g1, %tl		! Restore original trap level
+	add		%g2, 1, %g2		! Next trap level
+	cmp		%g2, %g1		! Hit them all yet?
+	ble,pt		%icc, 1b		! Not yet
+	 nop
+	wrpr		%g1, %tl		! Restore original trap level
+do_dcpe_tl1_nonfatal:	/* Ok we may use interrupt globals safely. */
+	/* Reset D-cache parity */
+	sethi		%hi(1 << 16), %g1	! D-cache size
+	mov		(1 << 5), %g2		! D-cache line size
+	sub		%g1, %g2, %g1		! Move down 1 cacheline
+1:	srl		%g1, 14, %g3		! Compute UTAG
+	membar		#Sync
+	stxa		%g3, [%g1] ASI_DCACHE_UTAG
+	membar		#Sync
+	sub		%g2, 8, %g3		! 64-bit data word within line
+2:	membar		#Sync
+	stxa		%g0, [%g1 + %g3] ASI_DCACHE_DATA
+	membar		#Sync
+	subcc		%g3, 8, %g3		! Next 64-bit data word
+	bge,pt		%icc, 2b
+	 nop
+	subcc		%g1, %g2, %g1		! Next cacheline
+	bge,pt		%icc, 1b
+	 nop
+	ba,pt		%xcc, dcpe_icpe_tl1_common
+	 nop
+
+do_dcpe_tl1_fatal:
+	sethi		%hi(1f), %g7
+	ba,pt		%xcc, etraptl1
+1:	or		%g7, %lo(1b), %g7
+	mov		0x2, %o0
+	call		cheetah_plus_parity_error
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+
+do_icpe_tl1:
+	rdpr		%tl, %g1		! Save original trap level
+	mov		1, %g2			! Setup TSTATE checking loop
+	sethi		%hi(TSTATE_IG), %g3	! TSTATE mask bit
+1:	wrpr		%g2, %tl		! Set trap level to check
+	rdpr		%tstate, %g4		! Read TSTATE for this level
+	andcc		%g4, %g3, %g0		! Interrupt globals in use?
+	bne,a,pn	%xcc, do_icpe_tl1_fatal	! Yep, irrecoverable
+	 wrpr		%g1, %tl		! Restore original trap level
+	add		%g2, 1, %g2		! Next trap level
+	cmp		%g2, %g1		! Hit them all yet?
+	ble,pt		%icc, 1b		! Not yet
+	 nop
+	wrpr		%g1, %tl		! Restore original trap level
+do_icpe_tl1_nonfatal:	/* Ok we may use interrupt globals safely. */
+	/* Flush I-cache */
+	sethi		%hi(1 << 15), %g1	! I-cache size
+	mov		(1 << 5), %g2		! I-cache line size
+	sub		%g1, %g2, %g1
+1:	or		%g1, (2 << 3), %g3
+	stxa		%g0, [%g3] ASI_IC_TAG
+	membar		#Sync
+	subcc		%g1, %g2, %g1
+	bge,pt		%icc, 1b
+	 nop
+	ba,pt		%xcc, dcpe_icpe_tl1_common
+	 nop
+
+do_icpe_tl1_fatal:
+	sethi		%hi(1f), %g7
+	ba,pt		%xcc, etraptl1
+1:	or		%g7, %lo(1b), %g7
+	mov		0x3, %o0
+	call		cheetah_plus_parity_error
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+	
+dcpe_icpe_tl1_common:
+	/* Flush D-cache, re-enable D/I caches in DCU and finally
+	 * retry the trapping instruction.
+	 */
+	sethi		%hi(1 << 16), %g1	! D-cache size
+	mov		(1 << 5), %g2		! D-cache line size
+	sub		%g1, %g2, %g1
+1:	stxa		%g0, [%g1] ASI_DCACHE_TAG
+	membar		#Sync
+	subcc		%g1, %g2, %g1
+	bge,pt		%icc, 1b
+	 nop
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g1
+	or		%g1, (DCU_DC | DCU_IC), %g1
+	stxa		%g1, [%g0] ASI_DCU_CONTROL_REG
+	membar		#Sync
+	retry
+
 	/* Cheetah FECC trap handling, we get here from tl{0,1}_fecc
 	 * in the trap table.  That code has done a memory barrier
 	 * and has disabled both the I-cache and D-cache in the DCU
@@ -1636,18 +1818,13 @@
 	ldx	[%g3 + %lo(timer_tick_offset)], %g3
 	or	%g2, %lo(xtime), %g2
 	or	%g1, %lo(timer_tick_compare), %g1
-1:	rdpr	%ver, %o2
-	sethi	%hi(0x003e0014), %o1
-	srlx	%o2, 32, %o2
-	or	%o1, %lo(0x003e0014), %o1
-	membar	#Sync
+1:	membar	#Sync
 	ldda	[%g2] ASI_NUCLEUS_QUAD_LDD, %o4
-	cmp	%o2, %o1
-	bne,pt	%xcc, 2f
-	 nop
+	BRANCH_IF_ANY_CHEETAH(o2,o1,2f)
 	ba,pt	%xcc, 3f
+	 rd	%tick, %o1
+2:	ba,pt	%xcc, 3f
 	 rd	%asr24, %o1
-2:	rd	%tick, %o1
 3:	ldx	[%g1], %g7
 	membar	#Sync
 	ldda	[%g2] ASI_NUCLEUS_QUAD_LDD, %o2
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/etrap.S linux-2.4.20/arch/sparc64/kernel/etrap.S
--- linux-2.4.19/arch/sparc64/kernel/etrap.S	2001-09-20 21:11:57.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/etrap.S	2002-10-29 11:18:39.000000000 +0000
@@ -107,8 +107,65 @@
 		 stb	%g0, [%l4 + %l3]					! Store		Group
 		nop
 
-etraptl1:	rdpr	%tstate, %g1						! Single	Group+4bubbles
-		sub	%sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2		! IEU1
+etraptl1:	/* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself.
+		 * We place this right after pt_regs on the trap stack.  The layout
+		 * is:
+		 *	0x00	TL1's TSTATE
+		 *	0x08	TL1's TPC
+		 *	0x10	TL1's TNPC
+		 *	0x18	TL1's TT
+		 *	 ...
+		 *	0x58	TL4's TT
+		 *	0x60	TL
+		 */
+		sub	%sp, ((4 * 8) * 4) + 8, %g2
+		rdpr	%tl, %g1
+
+		wrpr	%g0, 1, %tl
+		rdpr	%tstate, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x00]
+		rdpr	%tpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x08]
+		rdpr	%tnpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x10]
+		rdpr	%tt, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x18]
+
+		wrpr	%g0, 2, %tl
+		rdpr	%tstate, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x20]
+		rdpr	%tpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x28]
+		rdpr	%tnpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x30]
+		rdpr	%tt, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x38]
+
+		wrpr	%g0, 3, %tl
+		rdpr	%tstate, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x40]
+		rdpr	%tpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x48]
+		rdpr	%tnpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x50]
+		rdpr	%tt, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x58]
+
+		wrpr	%g0, 4, %tl
+		rdpr	%tstate, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x60]
+		rdpr	%tpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x68]
+		rdpr	%tnpc, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x70]
+		rdpr	%tt, %g3
+		stx	%g3, [%g2 + STACK_BIAS + 0x78]
+
+		wrpr	%g1, %tl
+		stx	%g1, [%g2 + STACK_BIAS + 0x80]
+
+		rdpr	%tstate, %g1						! Single	Group+4bubbles
+		sub	%g2, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2		! IEU1
 		ba,pt	%xcc, 1b						! CTI		Group
 		 andcc	%g1, TSTATE_PRIV, %g0					! IEU0
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/head.S linux-2.4.20/arch/sparc64/kernel/head.S
--- linux-2.4.19/arch/sparc64/kernel/head.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/head.S	2002-10-29 11:18:37.000000000 +0000
@@ -78,25 +78,28 @@
 	 * PROM entry point is on %o4
 	 */
 sparc64_boot:
-	rdpr	%ver, %g1
-	sethi	%hi(0x003e0014), %g5
-	srlx	%g1, 32, %g1
-	or	%g5, %lo(0x003e0014), %g5
-	cmp	%g1, %g5
-	bne,pt	%icc, spitfire_boot
+	BRANCH_IF_CHEETAH_BASE(g1,g5,cheetah_boot)
+	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g5,cheetah_plus_boot)
+	ba,pt	%xcc, spitfire_boot
+	 nop
+
+cheetah_plus_boot:
+	/* Preserve OBP choosen DCU and DCR register settings.  */
+	ba,pt	%xcc, cheetah_generic_boot
 	 nop
 
 cheetah_boot:
 	mov	DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1
 	wr	%g1, %asr18
 
-	sethi	%uhi(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
-	or	%g5, %ulo(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
+	sethi	%uhi(DCU_ME|DCU_RE|DCU_HPE|DCU_SPE|DCU_SL|DCU_WE), %g5
+	or	%g5, %ulo(DCU_ME|DCU_RE|DCU_HPE|DCU_SPE|DCU_SL|DCU_WE), %g5
 	sllx	%g5, 32, %g5
 	or	%g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5
 	stxa	%g5, [%g0] ASI_DCU_CONTROL_REG
 	membar	#Sync
 
+cheetah_generic_boot:
 	mov	TSB_EXTENSION_P, %g3
 	stxa	%g0, [%g3] ASI_DMMU
 	stxa	%g0, [%g3] ASI_IMMU
@@ -149,6 +152,7 @@
 	 add	%l0, (1 << 3), %l0
 
 cheetah_got_tlbentry:
+	ldxa	[%l0] ASI_ITLB_DATA_ACCESS, %g0
 	ldxa	[%l0] ASI_ITLB_DATA_ACCESS, %g1
 	membar	#Sync
 	and	%g1, %g3, %g1
@@ -200,6 +204,32 @@
 	blu,pt	%xcc, 1b
 	 add	%l0, (1 << 3), %l0
 
+	/* On Cheetah+, have to check second DTLB.  */
+	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,l0,2f)
+	ba,pt	%xcc, 9f
+	 nop
+
+2:	set	3 << 16, %l0
+1:	ldxa	[%l0] ASI_DTLB_TAG_READ, %g1
+	membar	#Sync
+	andn	%g1, %l2, %g1
+	cmp	%g1, %g3
+	blu,pn	%xcc, 2f
+	 cmp	%g1, %g7
+	bgeu,pn	%xcc, 2f
+	 nop
+	stxa	%g0, [%l7] ASI_DMMU
+	membar	#Sync
+	stxa	%g0, [%l0] ASI_DTLB_DATA_ACCESS
+	membar	#Sync
+	
+2:	and	%l0, (511 << 3), %g1
+	cmp	%g1, (511 << 3)
+	blu,pt	%xcc, 1b
+	 add	%l0, (1 << 3), %l0
+
+9:
+
 	/* Now lock the TTE we created into ITLB-0 and DTLB-0,
 	 * entry 15 (and maybe 14 too).
 	 */
@@ -431,21 +461,20 @@
 	stxa	%g3, [%g2] ASI_DMMU
 	membar	#Sync
 
-	rdpr	%ver, %g1
-	sethi	%hi(0x003e0014), %g5
-	srlx	%g1, 32, %g1
-	or	%g5, %lo(0x003e0014), %g5
-	cmp	%g1, %g5
-	bne,pt	%icc, spitfire_tlb_fixup
+	BRANCH_IF_ANY_CHEETAH(g1,g5,cheetah_tlb_fixup)
+
+	ba,pt	%xcc, spitfire_tlb_fixup
 	 nop
 
 cheetah_tlb_fixup:
 	set	(0 << 16) | (15 << 3), %g7
+	ldxa	[%g7] ASI_ITLB_DATA_ACCESS, %g0
 	ldxa	[%g7] ASI_ITLB_DATA_ACCESS, %g1
 	andn	%g1, (_PAGE_G), %g1
 	stxa	%g1, [%g7] ASI_ITLB_DATA_ACCESS
 	membar	#Sync
 
+	ldxa	[%g7] ASI_DTLB_DATA_ACCESS, %g0
 	ldxa	[%g7] ASI_DTLB_DATA_ACCESS, %g1
 	andn	%g1, (_PAGE_G), %g1
 	stxa	%g1, [%g7] ASI_DTLB_DATA_ACCESS
@@ -455,9 +484,12 @@
 	flush	%g3
 	membar	#Sync
 
-	/* Set TLB type to cheetah. */
-	mov	1, %g2
-	sethi	%hi(tlb_type), %g5
+	mov	2, %g2		/* Set TLB type to cheetah+. */
+	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g5,g2,1f)
+
+	mov	1, %g2		/* Set TLB type to cheetah. */
+
+1:	sethi	%hi(tlb_type), %g5
 	stw	%g2, [%g5 + %lo(tlb_type)]
 
 	/* Patch copy/page operations to cheetah optimized versions. */
@@ -465,6 +497,8 @@
 	 nop
 	call	cheetah_patch_pgcopyops
 	 nop
+	call	cheetah_patch_cachetlbops
+	 nop
 
 	ba,pt	%xcc, tlb_fixup_done
 	 nop
@@ -576,19 +610,17 @@
 	sllx	%g2, 32, %g2
 	or	%g2, KERN_LOWBITS, %g2
 
-	rdpr		%ver, %g3
-	sethi		%hi(0x003e0014), %g7
-	srlx		%g3, 32, %g3
-	or		%g7, %lo(0x003e0014), %g7
-	cmp		%g3, %g7
-	bne,pt		%icc, 1f
+	BRANCH_IF_ANY_CHEETAH(g3,g7,cheetah_vpte_base)
+	ba,pt	%xcc, spitfire_vpte_base
 	 nop
 
+cheetah_vpte_base:
 	sethi		%uhi(VPTE_BASE_CHEETAH), %g3
 	or		%g3, %ulo(VPTE_BASE_CHEETAH), %g3
 	ba,pt		%xcc, 2f
 	 sllx		%g3, 32, %g3
-1:
+
+spitfire_vpte_base:
 	sethi		%uhi(VPTE_BASE_SPITFIRE), %g3
 	or		%g3, %ulo(VPTE_BASE_SPITFIRE), %g3
 	sllx		%g3, 32, %g3
@@ -615,14 +647,12 @@
 	 nop
 
 not_starfire:
-	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g5
-	srlx		%g1, 32, %g1
-	or		%g7, %lo(0x003e0014), %g5
-	cmp		%g1, %g5
-	bne,pt		%icc, not_cheetah
+	BRANCH_IF_ANY_CHEETAH(g1,g5,is_cheetah)
+
+	ba,pt	%xcc, not_cheetah
 	 nop
 
+is_cheetah:
 	ldxa		[%g0] ASI_SAFARI_CONFIG, %g1
 	srlx		%g1, 17, %g1
 	ba,pt		%xcc, set_worklist
@@ -645,23 +675,21 @@
 	/* Kill PROM timer */
 	wr	%g0, 0, %tick_cmpr
 
-	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g5
-	srlx		%g1, 32, %g1
-	or		%g7, %lo(0x003e0014), %g5
-	cmp		%g1, %g5
-	bne,pt		%icc, 1f
+	BRANCH_IF_ANY_CHEETAH(g1,g5,1f)
+
+	ba,pt	%xcc, 2f
 	 nop
 
 	/* Disable STICK_INT interrupts. */
-	sethi		%hi(0x80000000), %g1
-	sllx		%g1, 32, %g1
-	wr		%g1, %asr25
+1:
+	sethi	%hi(0x80000000), %g1
+	sllx	%g1, 32, %g1
+	wr	%g1, %asr25
 
 	/* Ok, we're done setting up all the state our trap mechanims needs,
 	 * now get back into normal globals and let the PROM know what is up.
 	 */
-1:
+2:
 	wrpr	%g0, %g0, %wstate
 	wrpr	%o1, PSTATE_IE, %pstate
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/ioctl32.c linux-2.4.20/arch/sparc64/kernel/ioctl32.c
--- linux-2.4.19/arch/sparc64/kernel/ioctl32.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/ioctl32.c	2002-10-29 11:18:49.000000000 +0000
@@ -46,6 +46,7 @@
 #include <linux/netdevice.h>
 #include <linux/raw.h>
 #include <linux/smb_fs.h>
+#include <linux/ncp_fs.h>
 #include <linux/blkpg.h>
 #include <linux/blk.h>
 #include <linux/elevator.h>
@@ -99,6 +100,7 @@
 #include <linux/usbdevice_fs.h>
 #include <linux/nbd.h>
 #include <linux/random.h>
+#include <linux/filter.h>
 
 /* Use this to get at 32-bit user passed pointers. 
    See sys_sparc32.c for description about these. */
@@ -482,7 +484,7 @@
 }
 #endif
 
-static inline int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct ifconf32 ifc32;
 	struct ifconf ifc;
@@ -667,7 +669,44 @@
 	return err;
 }
 
-static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg)
+static __inline__ void *alloc_user_space(long len)
+{
+	struct pt_regs *regs = current->thread.kregs;
+	unsigned long usp = regs->u_regs[UREG_I6];
+
+	if (!(current->thread.flags & SPARC_FLAG_32BIT))
+		usp += STACK_BIAS;
+
+	return (void *) (usp - len);
+}
+
+static int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifreq *u_ifreq64;
+	struct ifreq32 *u_ifreq32 = (struct ifreq32 *) arg;
+	char tmp_buf[IFNAMSIZ];
+	void *data64;
+	u32 data32;
+
+	if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]),
+			   IFNAMSIZ))
+		return -EFAULT;
+	if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data))
+		return -EFAULT;
+	data64 = (void *) A(data32);
+
+	u_ifreq64 = alloc_user_space(sizeof(*u_ifreq64));
+
+	/* Don't check these user accesses, just let that get trapped
+	 * in the ioctl handler instead.
+	 */
+	copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], IFNAMSIZ);
+	__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data);
+
+	return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64);
+}
+
+static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct ifreq ifr;
 	mm_segment_t old_fs;
@@ -685,15 +724,6 @@
 		if (err)
 			return -EFAULT;
 		break;
-	case SIOCGPPPSTATS:
-	case SIOCGPPPCSTATS:
-	case SIOCGPPPVER:
-		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
-			return -EFAULT;
-		ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
-		if (!ifr.ifr_data)
-			return -EAGAIN;
-		break;
 	default:
 		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
 			return -EFAULT;
@@ -719,27 +749,6 @@
 			if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32)))
 				return -EFAULT;
 			break;
-		case SIOCGPPPSTATS:
-		case SIOCGPPPCSTATS:
-		case SIOCGPPPVER:
-		{
-			u32 data;
-			int len;
-
-			__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
-			if(cmd == SIOCGPPPVER)
-				len = strlen((char *)ifr.ifr_data) + 1;
-			else if(cmd == SIOCGPPPCSTATS)
-				len = sizeof(struct ppp_comp_stats);
-			else
-				len = sizeof(struct ppp_stats);
-
-			len = copy_to_user((char *)A(data), ifr.ifr_data, len);
-			free_page((unsigned long)ifr.ifr_data);
-			if(len)
-				return -EFAULT;
-			break;
-		}
 		case SIOCGIFMAP:
 			err = copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(ifr.ifr_name));
 			err |= __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start));
@@ -752,14 +761,6 @@
 				err = -EFAULT;
 			break;
 		}
-	} else {
-		switch (cmd) {
-		case SIOCGPPPSTATS:
-		case SIOCGPPPCSTATS:
-		case SIOCGPPPVER:
-			free_page((unsigned long)ifr.ifr_data);
-			break;
-		}
 	}
 	return err;
 }
@@ -798,7 +799,12 @@
 
 extern struct socket *sockfd_lookup(int fd, int *err);
 
-static inline int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+	fput(sock->file);
+}
+
+static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	int ret;
 	void *r = NULL;
@@ -846,6 +852,9 @@
 	ret = sys_ioctl (fd, cmd, (long) r);
 	set_fs (old_fs);
 
+	if (mysock)
+		sockfd_put(mysock);
+
 	return ret;
 }
 
@@ -856,7 +865,7 @@
 	u32 start;
 };
                         
-static inline int hdio_getgeo(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int hdio_getgeo(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	mm_segment_t old_fs = get_fs();
 	struct hd_geometry geo;
@@ -866,10 +875,39 @@
 	err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo);
 	set_fs (old_fs);
 	if (!err) {
-		err = copy_to_user ((struct hd_geometry32 *)arg, &geo, 4);
-		err |= __put_user (geo.start, &(((struct hd_geometry32 *)arg)->start));
+		if (copy_to_user ((struct hd_geometry32 *)arg, &geo, 4) ||
+		    __put_user (geo.start, &(((struct hd_geometry32 *)arg)->start)))
+			err = -EFAULT;
+	}
+	return err;
+}
+
+struct hd_big_geometry32 {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned int cylinders;
+	u32 start;
+};
+                        
+static int hdio_getgeo_big(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct hd_big_geometry geo;
+	int err;
+	
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&geo);
+	set_fs (old_fs);
+	if (!err) {
+		struct hd_big_geometry32 *up = (struct hd_big_geometry32 *) arg;
+
+		if (put_user(geo.heads, &up->heads) ||
+		    __put_user(geo.sectors, &up->sectors) ||
+		    __put_user(geo.cylinders, &up->cylinders) ||
+		    __put_user(((u32) geo.start), &up->start))
+			err = -EFAULT;
 	}
-	return err ? -EFAULT : 0;
+	return err;
 }
 
 struct  fbcmap32 {
@@ -883,7 +921,7 @@
 #define FBIOPUTCMAP32	_IOW('F', 3, struct fbcmap32)
 #define FBIOGETCMAP32	_IOW('F', 4, struct fbcmap32)
 
-static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int fbiogetputcmap(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct fbcmap f;
 	int ret;
@@ -934,7 +972,7 @@
 #define FBIOSCURSOR32	_IOW('F', 24, struct fbcursor32)
 #define FBIOGCURSOR32	_IOW('F', 25, struct fbcursor32)
 
-static inline int fbiogscursor(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int fbiogscursor(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct fbcursor f;
 	int ret;
@@ -1669,6 +1707,40 @@
 	return err;
 }
 
+struct sock_fprog32 {
+	__u16	len;
+	__u32	filter;
+};
+
+#define PPPIOCSPASS32	_IOW('t', 71, struct sock_fprog32)
+#define PPPIOCSACTIVE32	_IOW('t', 70, struct sock_fprog32)
+
+static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct sock_fprog32 *u_fprog32 = (struct sock_fprog32 *) arg;
+	struct sock_fprog *u_fprog64 = alloc_user_space(sizeof(struct sock_fprog));
+	void *fptr64;
+	u32 fptr32;
+	u16 flen;
+
+	if (get_user(flen, &u_fprog32->len) ||
+	    get_user(fptr32, &u_fprog32->filter))
+		return -EFAULT;
+
+	fptr64 = (void *) A(fptr32);
+
+	if (put_user(flen, &u_fprog64->len) ||
+	    put_user(fptr64, &u_fprog64->filter))
+		return -EFAULT;
+
+	if (cmd == PPPIOCSPASS32)
+		cmd = PPPIOCSPASS;
+	else
+		cmd = PPPIOCSACTIVE;
+
+	return sys_ioctl(fd, cmd, (unsigned long) u_fprog64);
+}
+
 struct ppp_option_data32 {
 	__kernel_caddr_t32	ptr;
 	__u32			length;
@@ -2191,6 +2263,307 @@
 	return err;
 }
 
+struct ncp_ioctl_request_32 {
+	unsigned int function;
+	unsigned int size;
+	__kernel_caddr_t32 data;
+};
+
+struct ncp_fs_info_v2_32 {
+	int version;
+	unsigned int mounted_uid;
+	unsigned int connection;
+	unsigned int buffer_size;
+
+	unsigned int volume_number;
+	__u32 directory_id;
+
+	__u32 dummy1;
+	__u32 dummy2;
+	__u32 dummy3;
+};
+
+struct ncp_objectname_ioctl_32
+{
+	int		auth_type;
+	unsigned int	object_name_len;
+	__kernel_caddr_t32	object_name;	/* an userspace data, in most cases user name */
+};
+
+struct ncp_privatedata_ioctl_32
+{
+	unsigned int	len;
+	__kernel_caddr_t32	data;		/* ~1000 for NDS */
+};
+
+#define	NCP_IOC_NCPREQUEST_32		_IOR('n', 1, struct ncp_ioctl_request_32)
+
+#define NCP_IOC_GETMOUNTUID2_32		_IOW('n', 2, unsigned int)
+
+#define NCP_IOC_GET_FS_INFO_V2_32	_IOWR('n', 4, struct ncp_fs_info_v2_32)
+
+#define NCP_IOC_GETOBJECTNAME_32	_IOWR('n', 9, struct ncp_objectname_ioctl_32)
+#define NCP_IOC_SETOBJECTNAME_32	_IOR('n', 9, struct ncp_objectname_ioctl_32)
+#define NCP_IOC_GETPRIVATEDATA_32	_IOWR('n', 10, struct ncp_privatedata_ioctl_32)
+#define NCP_IOC_SETPRIVATEDATA_32	_IOR('n', 10, struct ncp_privatedata_ioctl_32)
+
+static int do_ncp_ncprequest(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ncp_ioctl_request_32 n32;
+	struct ncp_ioctl_request n;
+	mm_segment_t old_fs;
+	int err;
+
+	if (copy_from_user(&n32, (struct ncp_ioctl_request_32*)arg,
+	    sizeof(n32)))
+		return -EFAULT;
+
+	n.function = n32.function;
+	n.size = n32.size;
+	if (n.size > 65536)
+		return -EINVAL;
+	n.data = vmalloc(65536);	/* 65536 must be same as NCP_PACKET_SIZE_INTERNAL in ncpfs */
+	if (!n.data)
+		return -ENOMEM;
+	err = -EFAULT;
+	if (copy_from_user(n.data, A(n32.data), n.size))
+		goto out;
+
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, NCP_IOC_NCPREQUEST, (unsigned long)&n);
+	set_fs (old_fs);
+        if(err <= 0)
+		goto out;
+	if (err > 65536) {
+		err = -EINVAL;
+		goto out;
+	}
+	if (copy_to_user(A(n32.data), n.data, err)) {
+		err = -EFAULT;
+		goto out;
+	}
+ out:
+	vfree(n.data);
+	return err;
+}
+
+static int do_ncp_getmountuid2(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	__kernel_uid_t kuid;
+	int err;
+
+	cmd = NCP_IOC_GETMOUNTUID2;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&kuid);
+	set_fs(old_fs);
+
+	if (!err)
+		err = put_user(kuid, (unsigned int*)arg);
+
+	return err;
+}
+
+static int do_ncp_getfsinfo2(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct ncp_fs_info_v2_32 n32;
+	struct ncp_fs_info_v2 n;
+	int err;
+
+	if (copy_from_user(&n32, (struct ncp_fs_info_v2_32*)arg, sizeof(n32)))
+		return -EFAULT;
+	if (n32.version != NCP_GET_FS_INFO_VERSION_V2)
+		return -EINVAL;
+	n.version = NCP_GET_FS_INFO_VERSION_V2;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, NCP_IOC_GET_FS_INFO_V2, (unsigned long)&n);
+	set_fs(old_fs);
+
+	if (!err) {
+		n32.version = n.version;
+		n32.mounted_uid = n.mounted_uid;
+		n32.connection = n.connection;
+		n32.buffer_size = n.buffer_size;
+		n32.volume_number = n.volume_number;
+		n32.directory_id = n.directory_id;
+		n32.dummy1 = n.dummy1;
+		n32.dummy2 = n.dummy2;
+		n32.dummy3 = n.dummy3;
+		err = copy_to_user((struct ncp_fs_info_v2_32*)arg, &n32, sizeof(n32)) ? -EFAULT : 0;
+	}
+	return err;
+}
+
+static int do_ncp_getobjectname(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ncp_objectname_ioctl_32 n32;
+	struct ncp_objectname_ioctl n;
+	mm_segment_t old_fs;
+	int err;
+	size_t tl;
+
+	if (copy_from_user(&n32, (struct ncp_objectname_ioctl_32*)arg,
+	    sizeof(n32)))
+		return -EFAULT;
+
+	n.object_name_len = tl = n32.object_name_len;
+	if (tl) {
+		n.object_name = kmalloc(tl, GFP_KERNEL);
+		if (!n.object_name)
+			return -ENOMEM;
+	} else {
+		n.object_name = NULL;
+	}
+
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, NCP_IOC_GETOBJECTNAME, (unsigned long)&n);
+	set_fs (old_fs);
+        if(err)
+		goto out;
+		
+	if (tl > n.object_name_len)
+		tl = n.object_name_len;
+
+	err = -EFAULT;
+	if (tl && copy_to_user(A(n32.object_name), n.object_name, tl))
+		goto out;
+
+	n32.auth_type = n.auth_type;
+	n32.object_name_len = n.object_name_len;
+	
+	if (copy_to_user((struct ncp_objectname_ioctl_32*)arg, &n32, sizeof(n32)))
+		goto out;
+	
+	err = 0;
+ out:
+ 	if (n.object_name)
+		kfree(n.object_name);
+
+	return err;
+}
+
+static int do_ncp_setobjectname(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ncp_objectname_ioctl_32 n32;
+	struct ncp_objectname_ioctl n;
+	mm_segment_t old_fs;
+	int err;
+	size_t tl;
+
+	if (copy_from_user(&n32, (struct ncp_objectname_ioctl_32*)arg,
+	    sizeof(n32)))
+		return -EFAULT;
+
+	n.auth_type = n32.auth_type;
+	n.object_name_len = tl = n32.object_name_len;
+	if (tl) {
+		n.object_name = kmalloc(tl, GFP_KERNEL);
+		if (!n.object_name)
+			return -ENOMEM;
+		err = -EFAULT;
+		if (copy_from_user(n.object_name, A(n32.object_name), tl))
+			goto out;
+	} else {
+		n.object_name = NULL;
+	}
+	
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, NCP_IOC_SETOBJECTNAME, (unsigned long)&n);
+	set_fs (old_fs);
+		
+ out:
+	if (n.object_name)
+		kfree(n.object_name);
+
+	return err;
+}
+
+static int do_ncp_getprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ncp_privatedata_ioctl_32 n32;
+	struct ncp_privatedata_ioctl n;
+	mm_segment_t old_fs;
+	int err;
+	size_t tl;
+
+	if (copy_from_user(&n32, (struct ncp_privatedata_ioctl_32*)arg,
+	    sizeof(n32)))
+		return -EFAULT;
+
+	n.len = tl = n32.len;
+	if (tl) {
+		n.data = kmalloc(tl, GFP_KERNEL);
+		if (!n.data)
+			return -ENOMEM;
+	} else {
+		n.data = NULL;
+	}
+
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, NCP_IOC_GETPRIVATEDATA, (unsigned long)&n);
+	set_fs (old_fs);
+        if(err)
+		goto out;
+		
+	if (tl > n.len)
+		tl = n.len;
+
+	err = -EFAULT;
+	if (tl && copy_to_user(A(n32.data), n.data, tl))
+		goto out;
+
+	n32.len = n.len;
+	
+	if (copy_to_user((struct ncp_privatedata_ioctl_32*)arg, &n32, sizeof(n32)))
+		goto out;
+	
+	err = 0;
+ out:
+ 	if (n.data)
+		kfree(n.data);
+
+	return err;
+}
+
+static int do_ncp_setprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ncp_privatedata_ioctl_32 n32;
+	struct ncp_privatedata_ioctl n;
+	mm_segment_t old_fs;
+	int err;
+	size_t tl;
+
+	if (copy_from_user(&n32, (struct ncp_privatedata_ioctl_32*)arg,
+	    sizeof(n32)))
+		return -EFAULT;
+
+	n.len = tl = n32.len;
+	if (tl) {
+		n.data = kmalloc(tl, GFP_KERNEL);
+		if (!n.data)
+			return -ENOMEM;
+		err = -EFAULT;
+		if (copy_from_user(n.data, A(n32.data), tl))
+			goto out;
+	} else {
+		n.data = NULL;
+	}
+	
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, NCP_IOC_SETPRIVATEDATA, (unsigned long)&n);
+	set_fs (old_fs);
+		
+ out:
+	if (n.data)
+		kfree(n.data);
+
+	return err;
+}
+
+
 struct atmif_sioc32 {
         int                number;
         int                length;
@@ -3834,8 +4207,7 @@
 #define MEMWRITEOOB32 	_IOWR('M',3,struct mtd_oob_buf32)
 #define MEMREADOOB32 	_IOWR('M',4,struct mtd_oob_buf32)
 
-static inline int 
-mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	mm_segment_t 			old_fs 	= get_fs();
 	struct mtd_oob_buf32	*uarg 	= (struct mtd_oob_buf32 *)arg;
@@ -3881,6 +4253,39 @@
 	return ((0 == ret) ? 0 : -EFAULT);
 }	
 
+/* Fix sizeof(sizeof()) breakage */
+#define BLKELVGET_32	_IOR(0x12,106,int)
+#define BLKELVSET_32	_IOW(0x12,107,int)
+#define BLKBSZGET_32	_IOR(0x12,112,int)
+#define BLKBSZSET_32	_IOW(0x12,113,int)
+#define BLKGETSIZE64_32	_IOR(0x12,114,int)
+
+static int do_blkelvget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKELVGET, arg);
+}
+
+static int do_blkelvset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKELVSET, arg);
+}
+
+static int do_blkbszget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKBSZGET, arg);
+}
+
+static int do_blkbszset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKBSZSET, arg);
+}
+
+static int do_blkgetsize64(unsigned int fd, unsigned int cmd,
+			   unsigned long arg)
+{
+	return sys_ioctl(fd, BLKGETSIZE64, arg);
+}
+
 struct ioctl_trans {
 	unsigned int cmd;
 	unsigned int handler;
@@ -4007,10 +4412,6 @@
 COMPATIBLE_IOCTL(BLKFRASET)
 COMPATIBLE_IOCTL(BLKSECTSET)
 COMPATIBLE_IOCTL(BLKSSZGET)
-COMPATIBLE_IOCTL(BLKBSZGET)
-COMPATIBLE_IOCTL(BLKBSZSET)
-COMPATIBLE_IOCTL(BLKGETSIZE64)
-
 /* RAID */
 COMPATIBLE_IOCTL(RAID_VERSION)
 COMPATIBLE_IOCTL(GET_ARRAY_INFO)
@@ -4243,13 +4644,16 @@
 COMPATIBLE_IOCTL(PPPIOCSMRU)
 COMPATIBLE_IOCTL(PPPIOCSMAXCID)
 COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP)
-COMPATIBLE_IOCTL(LPGETSTATUS)
 COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP)
 COMPATIBLE_IOCTL(PPPIOCXFERUNIT)
+/* PPPIOCSCOMPRESS is translated */
 COMPATIBLE_IOCTL(PPPIOCGNPMODE)
 COMPATIBLE_IOCTL(PPPIOCSNPMODE)
+/* PPPIOCSPASS is translated */
+/* PPPIOCSACTIVE is translated */
 COMPATIBLE_IOCTL(PPPIOCGDEBUG)
 COMPATIBLE_IOCTL(PPPIOCSDEBUG)
+/* PPPIOCGIDLE is translated */
 COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
 COMPATIBLE_IOCTL(PPPIOCATTACH)
 COMPATIBLE_IOCTL(PPPIOCDETACH)
@@ -4258,6 +4662,8 @@
 COMPATIBLE_IOCTL(PPPIOCDISCONN)
 COMPATIBLE_IOCTL(PPPIOCATTCHAN)
 COMPATIBLE_IOCTL(PPPIOCGCHAN)
+/* LP */
+COMPATIBLE_IOCTL(LPGETSTATUS)
 /* PPPOX */
 COMPATIBLE_IOCTL(PPPOEIOCSFWD)
 COMPATIBLE_IOCTL(PPPOEIOCDFWD)
@@ -4474,6 +4880,18 @@
 COMPATIBLE_IOCTL(RAW_GETBIND)
 /* SMB ioctls which do not need any translations */
 COMPATIBLE_IOCTL(SMB_IOC_NEWCONN)
+/* NCP ioctls which do not need any translations */
+COMPATIBLE_IOCTL(NCP_IOC_CONN_LOGGED_IN)
+COMPATIBLE_IOCTL(NCP_IOC_SIGN_INIT)
+COMPATIBLE_IOCTL(NCP_IOC_SIGN_WANTED)
+COMPATIBLE_IOCTL(NCP_IOC_SET_SIGN_WANTED)
+COMPATIBLE_IOCTL(NCP_IOC_LOCKUNLOCK)
+COMPATIBLE_IOCTL(NCP_IOC_GETROOT)
+COMPATIBLE_IOCTL(NCP_IOC_SETROOT)
+COMPATIBLE_IOCTL(NCP_IOC_GETCHARSETS)
+COMPATIBLE_IOCTL(NCP_IOC_SETCHARSETS)
+COMPATIBLE_IOCTL(NCP_IOC_GETDENTRYTTL)
+COMPATIBLE_IOCTL(NCP_IOC_SETDENTRYTTL)
 /* Little a */
 COMPATIBLE_IOCTL(ATMSIGD_CTRL)
 COMPATIBLE_IOCTL(ATMARPD_CTRL)
@@ -4533,9 +4951,6 @@
 COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK)
 COMPATIBLE_IOCTL(DRM_IOCTL_FINISH)
 #endif /* DRM */
-/* elevator */
-COMPATIBLE_IOCTL(BLKELVGET)
-COMPATIBLE_IOCTL(BLKELVSET)
 /* Big W */
 /* WIOC_GETSUPPORT not yet implemented -E */
 COMPATIBLE_IOCTL(WDIOC_GETSTATUS)
@@ -4640,9 +5055,6 @@
 HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc)
 HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc)
 HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc)
-HANDLE_IOCTL(SIOCGPPPSTATS, dev_ifsioc)
-HANDLE_IOCTL(SIOCGPPPCSTATS, dev_ifsioc)
-HANDLE_IOCTL(SIOCGPPPVER, dev_ifsioc)
 HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc)
 HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc)
 HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl)
@@ -4658,6 +5070,8 @@
 HANDLE_IOCTL(SIOCRTMSG, ret_einval)
 HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp)
 HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo)
+HANDLE_IOCTL(HDIO_GETGEO_BIG, hdio_getgeo_big)
+HANDLE_IOCTL(HDIO_GETGEO_BIG_RAW, hdio_getgeo_big)
 HANDLE_IOCTL(BLKRAGET, w_long)
 HANDLE_IOCTL(BLKGETSIZE, w_long)
 HANDLE_IOCTL(0x1260, broken_blkgetsize)
@@ -4689,6 +5103,8 @@
 HANDLE_IOCTL(SG_IO,sg_ioctl_trans)
 HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans)
 HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans)
+HANDLE_IOCTL(PPPIOCSPASS32, ppp_sock_fprog_ioctl_trans)
+HANDLE_IOCTL(PPPIOCSACTIVE32, ppp_sock_fprog_ioctl_trans)
 HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans)
 HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans)
 HANDLE_IOCTL(MTIOCGETCONFIG32, mt_ioctl_trans)
@@ -4724,6 +5140,14 @@
 /* One SMB ioctl needs translations. */
 #define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, __kernel_uid_t32)
 HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid)
+/* NCPFS */
+HANDLE_IOCTL(NCP_IOC_NCPREQUEST_32, do_ncp_ncprequest)
+HANDLE_IOCTL(NCP_IOC_GETMOUNTUID2_32, do_ncp_getmountuid2)
+HANDLE_IOCTL(NCP_IOC_GET_FS_INFO_V2_32, do_ncp_getfsinfo2)
+HANDLE_IOCTL(NCP_IOC_GETOBJECTNAME_32, do_ncp_getobjectname)
+HANDLE_IOCTL(NCP_IOC_SETOBJECTNAME_32, do_ncp_setobjectname)
+HANDLE_IOCTL(NCP_IOC_GETPRIVATEDATA_32, do_ncp_getprivatedata)
+HANDLE_IOCTL(NCP_IOC_SETPRIVATEDATA_32, do_ncp_setprivatedata)
 HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl)
 HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl)
 HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl)
@@ -4788,6 +5212,14 @@
 HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb)
 HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb)
 HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
+/* take care of sizeof(sizeof()) breakage */
+/* elevator */
+HANDLE_IOCTL(BLKELVGET_32, do_blkelvget)
+HANDLE_IOCTL(BLKELVSET_32, do_blkelvset)
+/* block stuff */
+HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget)
+HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset)
+HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64)
 IOCTL_TABLE_END
 
 unsigned int ioctl32_hash_table[1024];
@@ -4864,13 +5296,15 @@
 	    (unsigned long)t < ((unsigned long)additional_ioctls) + PAGE_SIZE) {
 		ioctl32_hash_table[hash] = t->next;
 		t->cmd = 0;
+		t->next = 0;
 		return 0;
 	} else while (t->next) {
 		t1 = (struct ioctl_trans *)(long)t->next;
 		if (t1->cmd == cmd && t1 >= additional_ioctls &&
 		    (unsigned long)t1 < ((unsigned long)additional_ioctls) + PAGE_SIZE) {
-			t1->cmd = 0;
 			t->next = t1->next;
+			t1->cmd = 0;
+			t1->next = 0;
 			return 0;
 		}
 		t = t1;
@@ -4901,6 +5335,9 @@
 	if (t) {
 		handler = (void *)(long)t->handler;
 		error = handler(fd, cmd, arg, filp);
+	} else if (cmd >= SIOCDEVPRIVATE &&
+		   cmd <= (SIOCDEVPRIVATE + 15)) {
+		error = siocdevprivate_ioctl(fd, cmd, arg);
 	} else {
 		static int count;
 		if (++count <= 20)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/irq.c linux-2.4.20/arch/sparc64/kernel/irq.c
--- linux-2.4.19/arch/sparc64/kernel/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/irq.c	2002-10-29 11:18:38.000000000 +0000
@@ -147,7 +147,7 @@
 	if (imap == 0UL)
 		return;
 
-	if (tlb_type == cheetah) {
+	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		/* We set it to our Safari AID. */
 		__asm__ __volatile__("ldxa [%%g0] %1, %0"
 				     : "=r" (tid)
@@ -1139,7 +1139,7 @@
 	unsigned long imap = bucket->imap;
 	unsigned int tid;
 
-	if (tlb_type == cheetah) {
+	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		tid = __cpu_logical_map[goal_cpu] << 26;
 		tid &= IMAP_AID_SAFARI;
 	} else if (this_is_starfire == 0) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/pci.c linux-2.4.20/arch/sparc64/kernel/pci.c
--- linux-2.4.19/arch/sparc64/kernel/pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/pci.c	2002-10-29 11:18:30.000000000 +0000
@@ -311,11 +311,12 @@
 {
 }
 
-void pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size, unsigned long align)
 {
 }
 
-int pcibios_enable_device(struct pci_dev *pdev)
+int pcibios_enable_device(struct pci_dev *pdev, int mask)
 {
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/pci_schizo.c linux-2.4.20/arch/sparc64/kernel/pci_schizo.c
--- linux-2.4.19/arch/sparc64/kernel/pci_schizo.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/pci_schizo.c	2002-10-29 11:18:33.000000000 +0000
@@ -1112,7 +1112,7 @@
 	u64 tmp;
 
 	/* Build IRQs and register handlers. */
-	irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_UE_INO);
+	irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_UE_INO);
 	if (request_irq(irq, schizo_ue_intr,
 			SA_SHIRQ, "SCHIZO UE", p) < 0) {
 		prom_printf("SCHIZO%d: Cannot register UE interrupt.\n",
@@ -1123,7 +1123,7 @@
 	tmp = readl(bucket->imap);
 	upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_UE_INO) + 4));
 
-	irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_CE_INO);
+	irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_CE_INO);
 	if (request_irq(irq, schizo_ce_intr,
 			SA_SHIRQ, "SCHIZO CE", p) < 0) {
 		prom_printf("SCHIZO%d: Cannot register CE interrupt.\n",
@@ -1143,9 +1143,9 @@
 	}
 	bucket = __bucket(irq);
 	tmp = upa_readl(bucket->imap);
-	upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4));
+	upa_writel(tmp, (base + SCHIZO_PBM_A_REGS_OFF + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4));
 
-	irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_PCIERR_B_INO);
+	irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_PCIERR_B_INO);
 	if (request_irq(irq, schizo_pcierr_intr,
 			SA_SHIRQ, "SCHIZO PCIERR", pbm_b) < 0) {
 		prom_printf("SCHIZO%d(PBMB): Cannot register PciERR interrupt.\n",
@@ -1156,7 +1156,7 @@
 	tmp = upa_readl(bucket->imap);
 	upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4));
 
-	irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_SERR_INO);
+	irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_SERR_INO);
 	if (request_irq(irq, schizo_safarierr_intr,
 			SA_SHIRQ, "SCHIZO SERR", p) < 0) {
 		prom_printf("SCHIZO%d(PBMB): Cannot register SafariERR interrupt.\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/power.c linux-2.4.20/arch/sparc64/kernel/power.c
--- linux-2.4.19/arch/sparc64/kernel/power.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/power.c	2002-10-29 11:18:36.000000000 +0000
@@ -34,20 +34,28 @@
 #endif /* CONFIG_PCI */
 
 extern void machine_halt(void);
+extern void machine_alt_power_off(void);
+static void (*poweroff_method)(void) = machine_alt_power_off;
 
 extern int serial_console;
 
 void machine_power_off(void)
 {
+	if (!serial_console) {
 #ifdef CONFIG_PCI
-	if (power_reg != 0UL && !serial_console) {
-		/* Both register bits seem to have the
-		 * same effect, so until I figure out
-		 * what the difference is...
-		 */
-		writel(POWER_COURTESY_OFF | POWER_SYSTEM_OFF, power_reg);
-	}
+		if (power_reg != 0UL) {
+			/* Both register bits seem to have the
+			 * same effect, so until I figure out
+			 * what the difference is...
+			 */
+			writel(POWER_COURTESY_OFF | POWER_SYSTEM_OFF, power_reg);
+		} else
 #endif /* CONFIG_PCI */
+			if (poweroff_method != NULL) {
+				poweroff_method();
+				/* not reached */
+			}
+	}
 	machine_halt();
 }
 
@@ -98,6 +106,7 @@
 found:
 	power_reg = (unsigned long)ioremap(edev->resource[0].start, 0x4);
 	printk("power: Control reg at %016lx ... ", power_reg);
+	poweroff_method = machine_halt; /* able to use the standard poweroff */
 	if (edev->irqs[0] != PCI_IRQ_NONE) {
 		if (kernel_thread(powerd, 0, CLONE_FS) < 0) {
 			printk("Failed to start power daemon.\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/process.c linux-2.4.20/arch/sparc64/kernel/process.c
--- linux-2.4.19/arch/sparc64/kernel/process.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/process.c	2002-10-29 11:18:39.000000000 +0000
@@ -128,6 +128,21 @@
 	panic("Halt failed!");
 }
 
+void machine_alt_power_off(void)
+{
+	sti();
+	mdelay(8);
+	cli();
+#ifdef CONFIG_SUN_CONSOLE
+	if (!serial_console && prom_palette)
+		prom_palette(1);
+#endif
+	if (prom_keyboard)
+		prom_keyboard();
+	prom_halt_power_off();
+	panic("Power-off failed!");
+}
+
 void machine_restart(char * cmd)
 {
 	char *p;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/ptrace.c linux-2.4.20/arch/sparc64/kernel/ptrace.c
--- linux-2.4.19/arch/sparc64/kernel/ptrace.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/ptrace.c	2002-10-29 11:18:50.000000000 +0000
@@ -576,7 +576,7 @@
 	{
 		unsigned long va;
 
-		if (tlb_type == cheetah) {
+		if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 			for (va = 0; va < (1 << 16); va += (1 << 5))
 				spitfire_put_dcache_tag(va, 0x0);
 			/* No need to mess with I-cache on Cheetah. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/setup.c linux-2.4.20/arch/sparc64/kernel/setup.c
--- linux-2.4.19/arch/sparc64/kernel/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/setup.c	2002-10-29 11:18:36.000000000 +0000
@@ -182,7 +182,7 @@
 
 			if (tlb_type == spitfire)
 				tte = spitfire_get_dtlb_data(SPITFIRE_HIGHEST_LOCKED_TLBENT);
-			else if (tlb_type == cheetah)
+			else if (tlb_type == cheetah || tlb_type == cheetah_plus)
 				tte = cheetah_get_ldtlb_data(CHEETAH_HIGHEST_LOCKED_TLBENT);
 
 			res = PROM_TRUE;
@@ -497,7 +497,7 @@
 		extern unsigned int irqsz_patchme[1];
 		irqsz_patchme[0] |= ((i == SMP_CACHE_BYTES) ? SMP_CACHE_BYTES_SHIFT : \
 							SMP_CACHE_BYTES_SHIFT + 1);
-		flushi((long)&irqsz_patchme[1]);
+		flushi((long)&irqsz_patchme[0]);
 	} else {
 		prom_printf("Unexpected size of irq_stat[] elements\n");
 		prom_halt();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/smp.c linux-2.4.20/arch/sparc64/kernel/smp.c
--- linux-2.4.19/arch/sparc64/kernel/smp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/smp.c	2002-10-29 11:18:31.000000000 +0000
@@ -622,9 +622,9 @@
 extern unsigned long xcall_flush_tlb_page;
 extern unsigned long xcall_flush_tlb_mm;
 extern unsigned long xcall_flush_tlb_range;
-extern unsigned long xcall_flush_tlb_all;
-extern unsigned long xcall_tlbcachesync;
-extern unsigned long xcall_flush_cache_all;
+extern unsigned long xcall_flush_tlb_all_spitfire;
+extern unsigned long xcall_flush_tlb_all_cheetah;
+extern unsigned long xcall_flush_cache_all_spitfire;
 extern unsigned long xcall_report_regs;
 extern unsigned long xcall_receive_signal;
 extern unsigned long xcall_flush_dcache_page_cheetah;
@@ -744,13 +744,19 @@
 
 void smp_flush_cache_all(void)
 {
-	smp_cross_call(&xcall_flush_cache_all, 0, 0, 0);
-	__flush_cache_all();
+	/* Cheetah need do nothing. */
+	if (tlb_type == spitfire) {
+		smp_cross_call(&xcall_flush_cache_all_spitfire, 0, 0, 0);
+		__flush_cache_all();
+	}
 }
 
 void smp_flush_tlb_all(void)
 {
-	smp_cross_call(&xcall_flush_tlb_all, 0, 0, 0);
+	if (tlb_type == spitfire)
+		smp_cross_call(&xcall_flush_tlb_all_spitfire, 0, 0, 0);
+	else
+		smp_cross_call(&xcall_flush_tlb_all_cheetah, 0, 0, 0);
 	__flush_tlb_all();
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/sparc64_ksyms.c linux-2.4.20/arch/sparc64/kernel/sparc64_ksyms.c
--- linux-2.4.19/arch/sparc64/kernel/sparc64_ksyms.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/sparc64_ksyms.c	2002-10-29 11:18:35.000000000 +0000
@@ -136,7 +136,7 @@
 
 #if defined(CONFIG_MCOUNT)
 extern void mcount(void);
-EXPORT_SYMBOL(mcount);
+EXPORT_SYMBOL_NOVERS(mcount);
 #endif
 
 /* Per-CPU information table */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/sys_sparc32.c linux-2.4.20/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.4.19/arch/sparc64/kernel/sys_sparc32.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/sys_sparc32.c	2002-10-29 11:18:48.000000000 +0000
@@ -512,9 +512,9 @@
 
 	if (!p)
 		return -ENOMEM;
-	err = get_user (p->mtype, &up->mtype);
-	err |= __copy_from_user (p->mtext, &up->mtext, second);
-	if (err)
+	err = -EFAULT;
+	if (get_user (p->mtype, &up->mtype) ||
+	    __copy_from_user (p->mtext, &up->mtext, second))
 		goto out;
 	old_fs = get_fs ();
 	set_fs (KERNEL_DS);
@@ -1056,7 +1056,7 @@
 static long do_readv_writev32(int type, struct file *file,
 			      const struct iovec32 *vector, u32 count)
 {
-	unsigned long tot_len;
+	__kernel_ssize_t32 tot_len;
 	struct iovec iovstack[UIO_FASTIOV];
 	struct iovec *iov=iovstack, *ivp;
 	struct inode *inode;
@@ -1086,13 +1086,19 @@
 	tot_len = 0;
 	i = count;
 	ivp = iov;
+	retval = -EINVAL;
 	while(i > 0) {
-		u32 len;
+		__kernel_ssize_t32 tmp = tot_len;
+		__kernel_ssize_t32 len;
 		u32 buf;
 
 		__get_user(len, &vector->iov_len);
 		__get_user(buf, &vector->iov_base);
+		if (len < 0)	/* size_t not fittina an ssize_t32 .. */
+			goto out;
 		tot_len += len;
+		if (tot_len < tmp) /* maths overflow on the ssize_t32 */
+			goto out;
 		ivp->iov_base = (void *)A(buf);
 		ivp->iov_len = (__kernel_size_t) len;
 		vector++;
@@ -1610,7 +1616,7 @@
 	return sys_sysfs(option, arg1, arg2);
 }
 
-struct ncp_mount_data32 {
+struct ncp_mount_data32_v3 {
         int version;
         unsigned int ncp_fd;
         __kernel_uid_t32 mounted_uid;
@@ -1625,19 +1631,69 @@
         __kernel_mode_t32 dir_mode;
 };
 
+struct ncp_mount_data32_v4 {
+	int version;
+	/* all members below are "long" in ABI ... i.e. 32bit on sparc32, while 64bits on sparc64 */
+	unsigned int flags;
+	unsigned int mounted_uid;
+	int wdog_pid;
+
+	unsigned int ncp_fd;
+	unsigned int time_out;
+	unsigned int retry_count;
+
+	unsigned int uid;
+	unsigned int gid;
+	unsigned int file_mode;
+	unsigned int dir_mode;
+};
+
 static void *do_ncp_super_data_conv(void *raw_data)
 {
-	struct ncp_mount_data news, *n = &news; 
-	struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data;
-
-	n->dir_mode = n32->dir_mode;
-	n->file_mode = n32->file_mode;
-	n->gid = low2highgid(n32->gid);
-	n->uid = low2highuid(n32->uid);
-	memmove (n->mounted_vol, n32->mounted_vol, (sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int)));
-	n->wdog_pid = n32->wdog_pid;
-	n->mounted_uid = low2highuid(n32->mounted_uid);
-	memcpy(raw_data, n, sizeof(struct ncp_mount_data)); 
+	switch (*(int*)raw_data) {
+		case NCP_MOUNT_VERSION:
+			{
+				struct ncp_mount_data news, *n = &news; 
+				struct ncp_mount_data32_v3 *n32 = (struct ncp_mount_data32_v3 *)raw_data;
+
+				n->version = n32->version;
+				n->ncp_fd = n32->ncp_fd;
+				n->mounted_uid = low2highuid(n32->mounted_uid);
+				n->wdog_pid = n32->wdog_pid;
+				memmove (n->mounted_vol, n32->mounted_vol, sizeof (n32->mounted_vol));
+				n->time_out = n32->time_out;
+				n->retry_count = n32->retry_count;
+				n->flags = n32->flags;
+				n->uid = low2highuid(n32->uid);
+				n->gid = low2highgid(n32->gid);
+				n->file_mode = n32->file_mode;
+				n->dir_mode = n32->dir_mode;
+				memcpy(raw_data, n, sizeof(*n)); 
+			}
+			break;
+		case NCP_MOUNT_VERSION_V4:
+			{
+				struct ncp_mount_data_v4 news, *n = &news; 
+				struct ncp_mount_data32_v4 *n32 = (struct ncp_mount_data32_v4 *)raw_data;
+
+				n->version = n32->version;
+				n->flags = n32->flags;
+				n->mounted_uid = n32->mounted_uid;
+				n->wdog_pid = n32->wdog_pid;
+				n->ncp_fd = n32->ncp_fd;
+				n->time_out = n32->time_out;
+				n->retry_count = n32->retry_count;
+				n->uid = n32->uid;
+				n->gid = n32->gid;
+				n->file_mode = n32->file_mode;
+				n->dir_mode = n32->dir_mode;
+				memcpy(raw_data, n, sizeof(*n)); 
+			}
+			break;
+		default:
+			/* do not touch unknown structures */
+			break;
+	}
 	return raw_data;
 }
 
@@ -2887,6 +2943,8 @@
 		ret |= __copy_to_user(&oact->sa_mask, &set32, sizeof(sigset_t32));
 		ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
 		ret |= __put_user((long)old_ka.sa.sa_restorer, &oact->sa_restorer);
+		if (ret)
+			ret = -EFAULT;
         }
 
         return ret;
@@ -3613,7 +3671,7 @@
 	err |= copy_from_user(&karg->ca_client.cl_fhkey[0],
 			  &arg32->ca32_client.cl32_fhkey[0],
 			  NFSCLNT_KEYMAX);
-	return err;
+	return (err ? -EFAULT : 0);
 }
 
 static int nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
@@ -3639,7 +3697,7 @@
 		      &arg32->ca32_export.ex32_anon_gid);
 	karg->ca_export.ex_anon_uid = high2lowuid(karg->ca_export.ex_anon_uid);
 	karg->ca_export.ex_anon_gid = high2lowgid(karg->ca_export.ex_anon_gid);
-	return err;
+	return (err ? -EFAULT : 0);
 }
 
 static int nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
@@ -3687,7 +3745,7 @@
 		err |= __get_user(karg->ca_umap.ug_gdimap[i],
 			      &(((__kernel_gid_t32 *)A(uaddr))[i]));
 
-	return err;
+	return (err ? -EFAULT : 0);
 }
 
 static int nfs_getfh32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
@@ -3704,7 +3762,7 @@
 		      &arg32->ca32_getfh.gf32_ino);
 	err |= __get_user(karg->ca_getfh.gf_version,
 		      &arg32->ca32_getfh.gf32_version);
-	return err;
+	return (err ? -EFAULT : 0);
 }
 
 static int nfs_getfd32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
@@ -3720,7 +3778,7 @@
 			  (NFS_MAXPATHLEN+1));
 	err |= __get_user(karg->ca_getfd.gd_version,
 		      &arg32->ca32_getfd.gd32_version);
-	return err;
+	return (err ? -EFAULT : 0);
 }
 
 static int nfs_getfs32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
@@ -3736,7 +3794,7 @@
 			  (NFS_MAXPATHLEN+1));
 	err |= __get_user(karg->ca_getfs.gd_maxlen,
 		      &arg32->ca32_getfs.gd32_maxlen);
-	return err;
+	return (err ? -EFAULT : 0);
 }
 
 /* This really doesn't need translations, we are only passing
@@ -3744,7 +3802,7 @@
  */
 static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
 {
-	return copy_to_user(res32, kres, sizeof(*res32));
+	return (copy_to_user(res32, kres, sizeof(*res32)) ? -EFAULT : 0);
 }
 
 int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/sys_sunos32.c linux-2.4.20/arch/sparc64/kernel/sys_sunos32.c
--- linux-2.4.19/arch/sparc64/kernel/sys_sunos32.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/sys_sunos32.c	2002-10-29 11:18:48.000000000 +0000
@@ -446,7 +446,7 @@
 	ret |= copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
 	ret |= copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
 	up_read(&uts_sem);
-	return ret;
+	return (ret ? -EFAULT : 0);
 }
 
 asmlinkage int sunos_nosys(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/time.c linux-2.4.20/arch/sparc64/kernel/time.c
--- linux-2.4.19/arch/sparc64/kernel/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/time.c	2002-10-29 11:18:47.000000000 +0000
@@ -686,7 +686,7 @@
 
 	/* 
 	 * Not having a register set can lead to trouble.
-	 * Also starfire doesnt have a tod clock.
+	 * Also starfire doesn't have a tod clock.
 	 */
 	if (!mregs && !dregs) 
 		return -1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/trampoline.S linux-2.4.20/arch/sparc64/kernel/trampoline.S
--- linux-2.4.19/arch/sparc64/kernel/trampoline.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/trampoline.S	2002-10-29 11:18:38.000000000 +0000
@@ -33,25 +33,29 @@
 sparc64_cpu_startup:
 	flushw
 
-	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g5
-	srlx		%g1, 32, %g1
-	or		%g5, %lo(0x003e0014), %g5
-	cmp		%g1, %g5
-	bne,pt		%icc, spitfire_startup
+	BRANCH_IF_CHEETAH_BASE(g1,g5,cheetah_startup)
+	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g5,cheetah_plus_startup)
+
+	ba,pt	%xcc, spitfire_startup
+	 nop
+
+cheetah_plus_startup:
+	/* Preserve OBP choosen DCU and DCR register settings.  */
+	ba,pt	%xcc, cheetah_generic_startup
 	 nop
 
 cheetah_startup:
-	mov		DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1
-	wr		%g1, %asr18
+	mov	DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1
+	wr	%g1, %asr18
 
-	sethi		%uhi(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
-	or		%g5, %ulo(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
-	sllx		%g5, 32, %g5
-	or		%g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5
-	stxa		%g5, [%g0] ASI_DCU_CONTROL_REG
-	membar		#Sync
+	sethi	%uhi(DCU_ME|DCU_RE|DCU_HPE|DCU_SPE|DCU_SL|DCU_WE), %g5
+	or	%g5, %ulo(DCU_ME|DCU_RE|DCU_HPE|DCU_SPE|DCU_SL|DCU_WE), %g5
+	sllx	%g5, 32, %g5
+	or	%g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5
+	stxa	%g5, [%g0] ASI_DCU_CONTROL_REG
+	membar	#Sync
 
+cheetah_generic_startup:
 	mov	TSB_EXTENSION_P, %g3
 	stxa	%g0, [%g3] ASI_DMMU
 	stxa	%g0, [%g3] ASI_IMMU
@@ -117,14 +121,10 @@
 	ldx		[%g2 + %lo(kern_locked_tte_data)], %g2
 	stx		%g2, [%sp + 2047 + 128 + 0x30]
 
-	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g5
-	srlx		%g1, 32, %g1
-	or		%g5, %lo(0x003e0014), %g5
-	cmp		%g1, %g5
-	bne,a,pt	%icc, 1f
-	 mov		63, %g2
 	mov		15, %g2
+	BRANCH_IF_ANY_CHEETAH(g1,g5,1f)
+
+	mov		63, %g2
 1:
 	stx		%g2, [%sp + 2047 + 128 + 0x38]
 	sethi		%hi(p1275buf), %g2
@@ -152,14 +152,10 @@
 	ldx		[%g2 + %lo(kern_locked_tte_data)], %g2
 	stx		%g2, [%sp + 2047 + 128 + 0x30]
 
-	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g5
-	srlx		%g1, 32, %g1
-	or		%g5, %lo(0x003e0014), %g5
-	cmp		%g1, %g5
-	bne,a,pt	%icc, 1f
-	 mov		63, %g2
 	mov		15, %g2
+	BRANCH_IF_ANY_CHEETAH(g1,g5,1f)
+
+	mov		63, %g2
 1:
 
 	stx		%g2, [%sp + 2047 + 128 + 0x38]
@@ -227,14 +223,12 @@
 	sllx		%g2, 32, %g2
 	or		%g2, KERN_LOWBITS, %g2
 
-	rdpr		%ver, %g3
-	sethi		%hi(0x003e0014), %g7
-	srlx		%g3, 32, %g3
-	or		%g7, %lo(0x003e0014), %g7
-	cmp		%g3, %g7
-	bne,pt		%icc, 1f
+	BRANCH_IF_ANY_CHEETAH(g3,g7,9f)
+
+	ba,pt		%xcc, 1f
 	 nop
 
+9:
 	sethi		%uhi(VPTE_BASE_CHEETAH), %g3
 	or		%g3, %ulo(VPTE_BASE_CHEETAH), %g3
 	ba,pt		%xcc, 2f
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/traps.c linux-2.4.20/arch/sparc64/kernel/traps.c
--- linux-2.4.19/arch/sparc64/kernel/traps.c	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/traps.c	2002-10-29 11:18:40.000000000 +0000
@@ -36,6 +36,37 @@
 #include <linux/kmod.h>
 #endif
 
+/* When an irrecoverable trap occurs at tl > 0, the trap entry
+ * code logs the trap state registers at every level in the trap
+ * stack.  It is found at (pt_regs + sizeof(pt_regs)) and the layout
+ * is as follows:
+ */
+struct tl1_traplog {
+	struct {
+		unsigned long tstate;
+		unsigned long tpc;
+		unsigned long tnpc;
+		unsigned long tt;
+	} trapstack[4];
+	unsigned long tl;
+};
+
+static void dump_tl1_traplog(struct tl1_traplog *p)
+{
+	int i;
+
+	printk("TRAPLOG: Error at trap level 0x%lx, dumping track stack.\n",
+	       p->tl);
+	for (i = 0; i < 4; i++) {
+		printk(KERN_CRIT
+		       "TRAPLOG: Trap level %d TSTATE[%016lx] TPC[%016lx] "
+		       "TNPC[%016lx] TT[%lx]\n",
+		       i + 1,
+		       p->trapstack[i].tstate, p->trapstack[i].tpc,
+		       p->trapstack[i].tnpc, p->trapstack[i].tt);
+	}
+}
+
 void bad_trap (struct pt_regs *regs, long lvl)
 {
 	char buffer[32];
@@ -65,8 +96,10 @@
 
 void bad_trap_tl1 (struct pt_regs *regs, long lvl)
 {
-	char buffer[24];
+	char buffer[32];
 	
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+
 	sprintf (buffer, "Bad trap %lx at tl>0", lvl);
 	die_if_kernel (buffer, regs);
 }
@@ -79,8 +112,8 @@
 }
 #endif
 
-void instruction_access_exception (struct pt_regs *regs,
-				   unsigned long sfsr, unsigned long sfar)
+void instruction_access_exception(struct pt_regs *regs,
+				  unsigned long sfsr, unsigned long sfar)
 {
 	siginfo_t info;
 
@@ -101,6 +134,13 @@
 	force_sig_info(SIGSEGV, &info, current);
 }
 
+void instruction_access_exception_tl1(struct pt_regs *regs,
+				      unsigned long sfsr, unsigned long sfar)
+{
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+	instruction_access_exception(regs, sfsr, sfar);
+}
+
 void data_access_exception (struct pt_regs *regs,
 			    unsigned long sfsr, unsigned long sfar)
 {
@@ -145,43 +185,36 @@
 #endif
 
 /* When access exceptions happen, we must do this. */
-static void clean_and_reenable_l1_caches(void)
+static void spitfire_clean_and_reenable_l1_caches(void)
 {
 	unsigned long va;
 
-	if (tlb_type == spitfire) {
-		/* Clean 'em. */
-		for (va =  0; va < (PAGE_SIZE << 1); va += 32) {
-			spitfire_put_icache_tag(va, 0x0);
-			spitfire_put_dcache_tag(va, 0x0);
-		}
+	if (tlb_type != spitfire)
+		BUG();
 
-		/* Re-enable in LSU. */
-		__asm__ __volatile__("flush %%g6\n\t"
-				     "membar #Sync\n\t"
-				     "stxa %0, [%%g0] %1\n\t"
-				     "membar #Sync"
-				     : /* no outputs */
-				     : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC |
-					    LSU_CONTROL_IM | LSU_CONTROL_DM),
-				     "i" (ASI_LSU_CONTROL)
-				     : "memory");
-	} else if (tlb_type == cheetah) {
-		/* Flush D-cache */
-		for (va = 0; va < (1 << 16); va += (1 << 5)) {
-			__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
-					     "membar #Sync"
-					     : /* no outputs */
-					     : "r" (va), "i" (ASI_DCACHE_TAG));
-		}
+	/* Clean 'em. */
+	for (va =  0; va < (PAGE_SIZE << 1); va += 32) {
+		spitfire_put_icache_tag(va, 0x0);
+		spitfire_put_dcache_tag(va, 0x0);
 	}
+
+	/* Re-enable in LSU. */
+	__asm__ __volatile__("flush %%g6\n\t"
+			     "membar #Sync\n\t"
+			     "stxa %0, [%%g0] %1\n\t"
+			     "membar #Sync"
+			     : /* no outputs */
+			     : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC |
+				    LSU_CONTROL_IM | LSU_CONTROL_DM),
+			     "i" (ASI_LSU_CONTROL)
+			     : "memory");
 }
 
 void do_iae(struct pt_regs *regs)
 {
 	siginfo_t info;
 
-	clean_and_reenable_l1_caches();
+	spitfire_clean_and_reenable_l1_caches();
 
 	info.si_signo = SIGBUS;
 	info.si_errno = 0;
@@ -195,12 +228,12 @@
 {
 #ifdef CONFIG_PCI
 	if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
-		clean_and_reenable_l1_caches();
+		spitfire_clean_and_reenable_l1_caches();
 
 		pci_poke_faulted = 1;
 
 		/* Why the fuck did they have to change this? */
-		if (tlb_type == cheetah)
+		if (tlb_type == cheetah || tlb_type == cheetah_plus)
 			regs->tpc += 4;
 
 		regs->tnpc = regs->tpc + 4;
@@ -389,10 +422,14 @@
 	return p;
 }
 
+extern unsigned int tl0_icpe[], tl1_icpe[];
+extern unsigned int tl0_dcpe[], tl1_dcpe[];
 extern unsigned int tl0_fecc[], tl1_fecc[];
 extern unsigned int tl0_cee[], tl1_cee[];
 extern unsigned int tl0_iae[], tl1_iae[];
 extern unsigned int tl0_dae[], tl1_dae[];
+extern unsigned int cheetah_plus_icpe_trap_vector[], cheetah_plus_icpe_trap_vector_tl1[];
+extern unsigned int cheetah_plus_dcpe_trap_vector[], cheetah_plus_dcpe_trap_vector_tl1[];
 extern unsigned int cheetah_fecc_trap_vector[], cheetah_fecc_trap_vector_tl1[];
 extern unsigned int cheetah_cee_trap_vector[], cheetah_cee_trap_vector_tl1[];
 extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector_tl1[];
@@ -494,6 +531,12 @@
 	memcpy(tl1_iae, cheetah_deferred_trap_vector_tl1, (8 * 4));
 	memcpy(tl0_dae, cheetah_deferred_trap_vector, (8 * 4));
 	memcpy(tl1_dae, cheetah_deferred_trap_vector_tl1, (8 * 4));
+	if (tlb_type == cheetah_plus) {
+		memcpy(tl0_dcpe, cheetah_plus_dcpe_trap_vector, (8 * 4));
+		memcpy(tl1_dcpe, cheetah_plus_dcpe_trap_vector_tl1, (8 * 4));
+		memcpy(tl0_icpe, cheetah_plus_icpe_trap_vector, (8 * 4));
+		memcpy(tl1_icpe, cheetah_plus_icpe_trap_vector_tl1, (8 * 4));
+	}
 	flushi(PAGE_OFFSET);
 }
 
@@ -532,9 +575,22 @@
  *
  * So we must only flush the I-cache when it is disabled.
  */
+static void __cheetah_flush_icache(void)
+{
+	unsigned long i;
+
+	/* Clear the valid bits in all the tags. */
+	for (i = 0; i < (1 << 15); i += (1 << 5)) {
+		__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
+				     "membar #Sync"
+				     : /* no outputs */
+				     : "r" (i | (2 << 3)), "i" (ASI_IC_TAG));
+	}
+}
+
 static void cheetah_flush_icache(void)
 {
-	unsigned long dcu_save, i;
+	unsigned long dcu_save;
 
 	/* Save current DCU, disable I-cache. */
 	__asm__ __volatile__("ldxa [%%g0] %1, %0\n\t"
@@ -545,13 +601,7 @@
 			     : "i" (ASI_DCU_CONTROL_REG), "i" (DCU_IC)
 			     : "g1");
 
-	/* Clear the valid bits in all the tags. */
-	for (i = 0; i < (1 << 16); i += (1 << 5)) {
-		__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
-				     "membar #Sync"
-				     : /* no outputs */
-				     : "r" (i | (2 << 3)), "i" (ASI_IC_TAG));
-	}
+	__cheetah_flush_icache();
 
 	/* Restore DCU register */
 	__asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
@@ -572,6 +622,34 @@
 	}
 }
 
+/* In order to make the even parity correct we must do two things.
+ * First, we clear DC_data_parity and set DC_utag to an appropriate value.
+ * Next, we clear out all 32-bytes of data for that line.  Data of
+ * all-zero + tag parity value of zero == correct parity.
+ */
+static void cheetah_plus_zap_dcache_parity(void)
+{
+	unsigned long i;
+
+	for (i = 0; i < (1 << 16); i += (1 << 5)) {
+		unsigned long tag = (i >> 14);
+		unsigned long j;
+
+		__asm__ __volatile__("membar	#Sync\n\t"
+				     "stxa	%0, [%1] %2\n\t"
+				     "membar	#Sync"
+				     : /* no outputs */
+				     : "r" (tag), "r" (i),
+				       "i" (ASI_DCACHE_UTAG));
+		for (j = i; j < i + (1 << 5); j += (1 << 3))
+			__asm__ __volatile__("membar	#Sync\n\t"
+					     "stxa	%%g0, [%0] %1\n\t"
+					     "membar	#Sync"
+					     : /* no outputs */
+					     : "r" (j), "i" (ASI_DCACHE_DATA));
+	}
+}
+
 /* Conversion tables used to frob Cheetah AFSR syndrome values into
  * something palatable to the memory controller driver get_unumber
  * routine.
@@ -1294,6 +1372,46 @@
 		panic("Irrecoverable deferred error trap.\n");
 }
 
+/* Handle a D/I cache parity error trap.  TYPE is encoded as:
+ *
+ * Bit0:	0=dcache,1=icache
+ * Bit1:	0=recoverable,1=unrecoverable
+ *
+ * The hardware has disabled both the I-cache and D-cache in
+ * the %dcr register.  
+ */
+void cheetah_plus_parity_error(int type, struct pt_regs *regs)
+{
+	if (type & 0x1)
+		__cheetah_flush_icache();
+	else
+		cheetah_plus_zap_dcache_parity();
+	cheetah_flush_dcache();
+
+	/* Re-enable I-cache/D-cache */
+	__asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
+			     "or %%g1, %1, %%g1\n\t"
+			     "stxa %%g1, [%%g0] %0\n\t"
+			     "membar #Sync"
+			     : /* no outputs */
+			     : "i" (ASI_DCU_CONTROL_REG),
+			       "i" (DCU_DC | DCU_IC)
+			     : "g1");
+
+	if (type & 0x2) {
+		printk(KERN_EMERG "CPU[%d]: Cheetah+ %c-cache parity error at TPC[%016lx]\n",
+		       smp_processor_id(),
+		       (type & 0x1) ? 'I' : 'D',
+		       regs->tpc);
+		panic("Irrecoverable Cheetah+ parity error.");
+	}
+
+	printk(KERN_WARNING "CPU[%d]: Cheetah+ %c-cache parity error at TPC[%016lx]\n",
+	       smp_processor_id(),
+	       (type & 0x1) ? 'I' : 'D',
+	       regs->tpc);
+}
+
 void do_fpe_common(struct pt_regs *regs)
 {
 	if(regs->tstate & TSTATE_PRIV) {
@@ -1415,17 +1533,14 @@
 	printk("\n");
 }
 
-void show_trace_task(struct task_struct *tsk)
+void show_trace_raw(struct task_struct *tsk, unsigned long ksp)
 {
 	unsigned long pc, fp;
 	unsigned long task_base = (unsigned long)tsk;
 	struct reg_window *rw;
 	int count = 0;
 
-	if (!tsk)
-		return;
-
-	fp = tsk->thread.ksp + STACK_BIAS;
+	fp = ksp + STACK_BIAS;
 	do {
 		/* Bogus frame pointer? */
 		if (fp < (task_base + sizeof(struct task_struct)) ||
@@ -1439,6 +1554,12 @@
 	printk("\n");
 }
 
+void show_trace_task(struct task_struct *tsk)
+{
+	if (tsk)
+		show_trace_raw(tsk, tsk->thread.ksp);
+}
+
 void die_if_kernel(char *str, struct pt_regs *regs)
 {
 	extern void __show_regs(struct pt_regs * regs);
@@ -1571,56 +1692,67 @@
 
 void do_cee_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Cache Error Exception", regs);
 }
 
 void do_dae_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Data Access Exception", regs);
 }
 
 void do_iae_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Instruction Access Exception", regs);
 }
 
 void do_div0_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: DIV0 Exception", regs);
 }
 
 void do_fpdis_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: FPU Disabled", regs);
 }
 
 void do_fpieee_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: FPU IEEE Exception", regs);
 }
 
 void do_fpother_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: FPU Other Exception", regs);
 }
 
 void do_ill_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Illegal Instruction Exception", regs);
 }
 
 void do_irq_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: IRQ Exception", regs);
 }
 
 void do_lddfmna_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: LDDF Exception", regs);
 }
 
 void do_stdfmna_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: STDF Exception", regs);
 }
 
@@ -1631,6 +1763,7 @@
 
 void do_paw_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Phys Watchpoint Exception", regs);
 }
 
@@ -1641,11 +1774,13 @@
 
 void do_vaw_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Virt Watchpoint Exception", regs);
 }
 
 void do_tof_tl1(struct pt_regs *regs)
 {
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 	die_if_kernel("TL1: Tag Overflow Exception", regs);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/kernel/ttable.S linux-2.4.20/arch/sparc64/kernel/ttable.S
--- linux-2.4.19/arch/sparc64/kernel/ttable.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/kernel/ttable.S	2002-10-29 11:18:48.000000000 +0000
@@ -7,6 +7,8 @@
 #include <linux/config.h>
 
 	.globl	sparc64_ttable_tl0, sparc64_ttable_tl1
+	.globl	tl0_icpe, tl1_icpe
+	.globl	tl0_dcpe, tl1_dcpe
 	.globl	tl0_fecc, tl1_fecc
 	.globl	tl0_cee, tl1_cee
 	.globl	tl0_iae, tl1_iae
@@ -79,7 +81,9 @@
 tl0_daprot:
 #include	"dtlb_prot.S"
 tl0_fecc:	BTRAP(0x70)	/* Fast-ECC on Cheetah */
-tl0_resv071:	BTRAP(0x71) BTRAP(0x72) BTRAP(0x73) BTRAP(0x74) BTRAP(0x75)
+tl0_dcpe:	BTRAP(0x71)	/* D-cache Parity Error on Cheetah+ */
+tl0_icpe:	BTRAP(0x72)	/* I-cache Parity Error on Cheetah+ */
+tl0_resv073:	BTRAP(0x73) BTRAP(0x74) BTRAP(0x75)
 tl0_resv076:	BTRAP(0x76) BTRAP(0x77) BTRAP(0x78) BTRAP(0x79) BTRAP(0x7a) BTRAP(0x7b)
 tl0_resv07c:	BTRAP(0x7c) BTRAP(0x7d) BTRAP(0x7e) BTRAP(0x7f)
 tl0_s0n:	SPILL_0_NORMAL
@@ -235,8 +239,10 @@
 #include	"dtlb_backend.S"
 tl1_daprot:
 #include	"dtlb_prot.S"
-tl1_fecc:	BTRAP(0x70)	/* Fast-ECC on Cheetah */
-tl1_resc071:	BTRAPTL1(0x71) BTRAPTL1(0x72) BTRAPTL1(0x73)
+tl1_fecc:	BTRAPTL1(0x70)	/* Fast-ECC on Cheetah */
+tl1_dcpe:	BTRAPTL1(0x71)	/* D-cache Parity Error on Cheetah+ */
+tl1_icpe:	BTRAPTL1(0x72)	/* I-cache Parity Error on Cheetah+ */
+tl1_resv073:	BTRAPTL1(0x73)
 tl1_resv074:	BTRAPTL1(0x74) BTRAPTL1(0x75) BTRAPTL1(0x76) BTRAPTL1(0x77)
 tl1_resv078:	BTRAPTL1(0x78) BTRAPTL1(0x79) BTRAPTL1(0x7a) BTRAPTL1(0x7b)
 tl1_resv07c:	BTRAPTL1(0x7c) BTRAPTL1(0x7d) BTRAPTL1(0x7e) BTRAPTL1(0x7f)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/lib/U3copy_from_user.S linux-2.4.20/arch/sparc64/lib/U3copy_from_user.S
--- linux-2.4.19/arch/sparc64/lib/U3copy_from_user.S	2002-02-25 19:37:56.000000000 +0000
+++ linux-2.4.20/arch/sparc64/lib/U3copy_from_user.S	2002-10-29 11:18:34.000000000 +0000
@@ -7,6 +7,8 @@
 #ifdef __KERNEL__
 #include <asm/visasm.h>
 #include <asm/asi.h>
+#include <asm/dcu.h>
+#include <asm/spitfire.h>
 #undef SMALL_COPY_USES_FPU
 #define EXNV(x,y,a,b)			\
 98:	x,y;				\
@@ -181,6 +183,16 @@
 
 	.align		64
 U3copy_from_user_begin:
+#ifdef __KERNEL__
+	.globl		U3copy_from_user_nop_1_6
+U3copy_from_user_nop_1_6:
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g3
+	sethi		%uhi(DCU_PE), %o3
+	sllx		%o3, 32, %o3
+	or		%g3, %o3, %o3
+	stxa		%o3, [%g0] ASI_DCU_CONTROL_REG	! Enable P-cache
+	membar		#Sync
+#endif
 	prefetcha	[%o1 + 0x000] %asi, #one_read	! MS	Group1
 	prefetcha	[%o1 + 0x040] %asi, #one_read	! MS	Group2
 	andn		%o2, (0x40 - 1), %o4		! A0
@@ -321,6 +333,13 @@
 	stda		%f16, [%o0] ASI_BLK_P		! MS
 	add		%o0, 0x40, %o0			! A0
 	add		%o1, 0x40, %o1			! A1
+#ifdef __KERNEL__
+	.globl		U3copy_from_user_nop_2_3
+U3copy_from_user_nop_2_3:
+	mov		PRIMARY_CONTEXT, %o3
+	stxa		%g0, [%o3] ASI_DMMU		! Flush P-cache
+	stxa		%g3, [%g0] ASI_DCU_CONTROL_REG	! Disable P-cache
+#endif
 	membar		#Sync				! MS	Group26 (7-cycle stall)
 
 	/* Now we copy the (len modulo 64) bytes at the end.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/lib/U3copy_to_user.S linux-2.4.20/arch/sparc64/lib/U3copy_to_user.S
--- linux-2.4.19/arch/sparc64/lib/U3copy_to_user.S	2000-11-09 23:57:41.000000000 +0000
+++ linux-2.4.20/arch/sparc64/lib/U3copy_to_user.S	2002-10-29 11:18:30.000000000 +0000
@@ -7,6 +7,8 @@
 #ifdef __KERNEL__
 #include <asm/visasm.h>
 #include <asm/asi.h>
+#include <asm/dcu.h>
+#include <asm/spitfire.h>
 #undef SMALL_COPY_USES_FPU
 #define EXNV(x,y,a,b)	\
 98:	x,y;				\
@@ -228,6 +230,16 @@
 
 	.align		64
 U3copy_to_user_begin:
+#ifdef __KERNEL__
+	.globl		U3copy_to_user_nop_1_6
+U3copy_to_user_nop_1_6:
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g3
+	sethi		%uhi(DCU_PE), %o3
+	sllx		%o3, 32, %o3
+	or		%g3, %o3, %o3
+	stxa		%o3, [%g0] ASI_DCU_CONTROL_REG	! Enable P-cache
+	membar		#Sync
+#endif
 	prefetch	[%o1 + 0x000], #one_read	! MS	Group1
 	prefetch	[%o1 + 0x040], #one_read	! MS	Group2
 	andn		%o2, (0x40 - 1), %o4		! A0
@@ -368,6 +380,13 @@
 	EXBLK4(stda %f16, [%o0] ASI_BLK_AIUS)		! MS
 	add		%o0, 0x40, %o0			! A0
 	add		%o1, 0x40, %o1			! A1
+#ifdef __KERNEL__
+	.globl		U3copy_to_user_nop_2_3
+U3copy_to_user_nop_2_3:
+	mov		PRIMARY_CONTEXT, %o3
+	stxa		%g0, [%o3] ASI_DMMU		! Flush P-cache
+	stxa		%g3, [%g0] ASI_DCU_CONTROL_REG	! Disable P-cache
+#endif
 	membar		#Sync				! MS	Group26 (7-cycle stall)
 
 	/* Now we copy the (len modulo 64) bytes at the end.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/lib/U3memcpy.S linux-2.4.20/arch/sparc64/lib/U3memcpy.S
--- linux-2.4.19/arch/sparc64/lib/U3memcpy.S	2000-11-09 23:57:41.000000000 +0000
+++ linux-2.4.20/arch/sparc64/lib/U3memcpy.S	2002-10-29 11:18:51.000000000 +0000
@@ -7,6 +7,8 @@
 #ifdef __KERNEL__
 #include <asm/visasm.h>
 #include <asm/asi.h>
+#include <asm/dcu.h>
+#include <asm/spitfire.h>
 #undef SMALL_COPY_USES_FPU
 #else
 #define ASI_BLK_P 0xf0
@@ -109,6 +111,16 @@
 
 	.align		64
 U3memcpy_begin:
+#ifdef __KERNEL__
+	.globl		U3memcpy_nop_1_6
+U3memcpy_nop_1_6:
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g3
+	sethi		%uhi(DCU_PE), %o3
+	sllx		%o3, 32, %o3
+	or		%g3, %o3, %o3
+	stxa		%o3, [%g0] ASI_DCU_CONTROL_REG	! Enable P-cache
+	membar		#Sync
+#endif
 	prefetch	[%o1 + 0x000], #one_read	! MS	Group1
 	prefetch	[%o1 + 0x040], #one_read	! MS	Group2
 	andn		%o2, (0x40 - 1), %o4		! A0
@@ -249,6 +261,13 @@
 	stda		%f16, [%o0] ASI_BLK_P		! MS
 	add		%o0, 0x40, %o0			! A0
 	add		%o1, 0x40, %o1			! A1
+#ifdef __KERNEL__
+	.globl		U3memcpy_nop_2_3
+U3memcpy_nop_2_3:
+	mov		PRIMARY_CONTEXT, %o3
+	stxa		%g0, [%o3] ASI_DMMU		! Flush P-cache
+	stxa		%g3, [%g0] ASI_DCU_CONTROL_REG	! Disable P-cache
+#endif
 	membar		#Sync				! MS	Group26 (7-cycle stall)
 
 	/* Now we copy the (len modulo 64) bytes at the end.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/lib/VIScopy.S linux-2.4.20/arch/sparc64/lib/VIScopy.S
--- linux-2.4.19/arch/sparc64/lib/VIScopy.S	2001-10-01 16:19:56.000000000 +0000
+++ linux-2.4.20/arch/sparc64/lib/VIScopy.S	2002-10-29 11:18:33.000000000 +0000
@@ -368,6 +368,28 @@
 	or	%g3, %lo(NOP), %g3; \
 	stw	%g3, [%g2 + 0x4]; \
 	flush	%g2;
+#define ULTRA3_PCACHE_DO_NOP(symbol)	\
+	sethi	%hi(symbol##_nop_1_6), %g1; \
+	or	%g1, %lo(symbol##_nop_1_6), %g1; \
+	sethi	%hi(NOP), %g2; \
+	stw	%g2, [%g1 + 0x00]; \
+	stw	%g2, [%g1 + 0x04]; \
+	flush	%g1 + 0x00; \
+	stw	%g2, [%g1 + 0x08]; \
+	stw	%g2, [%g1 + 0x0c]; \
+	flush	%g1 + 0x08; \
+	stw	%g2, [%g1 + 0x10]; \
+	stw	%g2, [%g1 + 0x04]; \
+	flush	%g1 + 0x10; \
+	sethi	%hi(symbol##_nop_2_3), %g1; \
+	or	%g1, %lo(symbol##_nop_2_3), %g1; \
+	stw	%g2, [%g1 + 0x00]; \
+	stw	%g2, [%g1 + 0x04]; \
+	flush	%g1 + 0x00; \
+	stw	%g2, [%g1 + 0x08]; \
+	flush	%g1 + 0x08;
+
+#include <asm/dcu.h>
 
 	.globl	cheetah_patch_copyops
 cheetah_patch_copyops:
@@ -375,6 +397,23 @@
 	ULTRA3_DO_PATCH(__copy_from_user, U3copy_from_user)
 	ULTRA3_DO_PATCH(__copy_to_user, U3copy_to_user)
 	ULTRA3_DO_PATCH(__copy_in_user, U3copy_in_user)
+#if 0 /* Causes data corruption, nop out the optimization
+       * for now -DaveM
+       */
+	ldxa			[%g0] ASI_DCU_CONTROL_REG, %g3
+	sethi			%uhi(DCU_PE), %o3
+	sllx			%o3, 32, %o3
+	andcc			%g3, %o3, %g0
+	be,pn			%xcc, pcache_disabled
+	 nop
+#endif
+	ULTRA3_PCACHE_DO_NOP(U3memcpy)
+	ULTRA3_PCACHE_DO_NOP(U3copy_from_user)
+	ULTRA3_PCACHE_DO_NOP(U3copy_to_user)
+	ULTRA3_PCACHE_DO_NOP(cheetah_copy_user_page)
+#if 0
+pcache_disabled:
+#endif
 	retl
 	 nop
 #undef BRANCH_ALWAYS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/lib/VIScsum.S linux-2.4.20/arch/sparc64/lib/VIScsum.S
--- linux-2.4.19/arch/sparc64/lib/VIScsum.S	2000-02-22 00:32:27.000000000 +0000
+++ linux-2.4.20/arch/sparc64/lib/VIScsum.S	2002-10-29 11:18:50.000000000 +0000
@@ -212,6 +212,8 @@
 	mov		1, %g5			/*  IEU0	Group		*/
 	cmp		%o1, 6			/*  IEU1			*/
 	bl,pn		%icc, 21f		/*  CTI				*/
+	 andcc		%o0, 1, %g0		/*  IEU1	Group		*/
+	bne,pn		%icc, csump_really_slow /*  CTI				*/
 	 andcc		%o0, 2, %g0		/*  IEU1	Group		*/
 	be,pt		%icc, 1f		/*  CTI				*/
 	 and		%o0, 4, %g7		/*  IEU0			*/
@@ -449,3 +451,96 @@
 	 add		%o2, 1, %o2		/*  IEU0			*/
 1:	ba,pt		%xcc, 25b		/*  CTI		Group		*/
 	 sllx		%o2, 32, %g1		/*  IEU0			*/
+
+	/* When buff is byte aligned and len is large, we backoff to
+	 * this really slow handling.  The issue is that we cannot do
+	 * the VIS stuff when buff is byte aligned as unaligned.c will
+	 * not fix it up.
+	 */
+csump_really_slow:
+	mov	%o0, %o3
+	mov	%o1, %o4
+	cmp	%o1, 0
+	ble,pn	%icc, 9f
+	 mov	0, %o0
+	andcc	%o3, 1, %o5
+	be,pt	%icc, 1f
+	 sra	%o4, 1, %g3
+	add	%o1, -1, %o4
+	ldub	[%o3], %o0
+	add	%o3, 1, %o3
+	sra	%o4, 1, %g3
+1:
+	cmp	%g3, 0
+	be,pt	%icc, 3f
+	 and	%o4, 1, %g2
+	and	%o3, 2, %g2
+	brz,a,pt %g2, 1f
+	 sra	%g3, 1, %g3
+	add	%g3, -1, %g3
+	add	%o4, -2, %o4
+	lduh	[%o3], %g2
+	add	%o3, 2, %o3
+	add	%o0, %g2, %o0
+	sra	%g3, 1, %g3
+1:
+	cmp	%g3, 0
+	be,pt	%icc, 2f
+	 and	%o4, 2, %g2
+1:
+	ld	[%o3], %g2
+	addcc	%o0, %g2, %o0
+	addx	%o0, %g0, %o0
+	addcc	%g3, -1, %g3
+	bne,pt	%icc, 1b
+	 add	%o3, 4, %o3
+	srl	%o0, 16, %o1
+	sethi	%hi(64512), %g2
+	or	%g2, 1023, %g2
+	and	%o0, %g2, %g3
+	add	%g3, %o1, %g3
+	srl	%g3, 16, %o0
+	and	%g3, %g2, %g2
+	add	%g2, %o0, %g3
+	sll	%g3, 16, %g3
+	srl	%g3, 16, %o0
+	and	%o4, 2, %g2
+2:
+	cmp	%g2, 0
+	be,pt	%icc, 3f
+	 and	%o4, 1, %g2
+	lduh	[%o3], %g2
+	add	%o3, 2, %o3
+	add	%o0, %g2, %o0
+	and	%o4, 1, %g2
+3:
+	cmp	%g2, 0
+	be,pt	%icc, 1f
+	 srl	%o0, 16, %o1
+	ldub	[%o3], %g2
+	sll	%g2, 8, %g2
+	add	%o0, %g2, %o0
+	srl	%o0, 16, %o1
+1:
+	sethi	%hi(64512), %g2
+	or	%g2, 1023, %g2
+	cmp	%o5, 0
+	and	%o0, %g2, %g3
+	add	%g3, %o1, %g3
+	srl	%g3, 16, %o0
+	and	%g3, %g2, %g2
+	add	%g2, %o0, %g3
+	sll	%g3, 16, %g3
+	srl	%g3, 16, %o0
+	srl	%g3, 24, %g3
+	and	%o0, 255, %g2
+	sll	%g2, 8, %g2
+	bne,pt	%icc, 1f
+	 or	%g3, %g2, %g2
+9:
+	mov	%o0, %g2
+1:
+	addcc	%g2, %o2, %g2
+	addx	%g2, %g0, %g2
+	retl
+	 srl	%g2, 0, %o0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/lib/blockops.S linux-2.4.20/arch/sparc64/lib/blockops.S
--- linux-2.4.19/arch/sparc64/lib/blockops.S	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.20/arch/sparc64/lib/blockops.S	2002-10-29 11:18:31.000000000 +0000
@@ -8,6 +8,8 @@
 #include "VIS.h"
 #include <asm/visasm.h>
 #include <asm/page.h>
+#include <asm/dcu.h>
+#include <asm/spitfire.h>
 #include <asm/pgtable.h>
 #include <asm/asm_offsets.h>
 
@@ -64,14 +66,14 @@
 	ldub		[%g6 + AOFF_task_thread + AOFF_thread_use_blkcommit], %g3
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %o4
+	mov		PRIMARY_CONTEXT, %o4
 	stxa		%g0, [%o4] ASI_DMMU
 	membar		#Sync
 
 	ldxa		[%o3] ASI_DTLB_TAG_READ, %o4
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %o5
+	mov		PRIMARY_CONTEXT, %o5
 	stxa		%g0, [%o5] ASI_DMMU
 	membar		#Sync
 
@@ -83,14 +85,14 @@
 	add		%o3, (TLBTEMP_ENTSZ), %o3
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %g5
+	mov		PRIMARY_CONTEXT, %g5
 	stxa		%g0, [%g5] ASI_DMMU
 	membar		#Sync
 
 	ldxa		[%o3] ASI_DTLB_TAG_READ, %g5
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %g7
+	mov		PRIMARY_CONTEXT, %g7
 	stxa		%g0, [%g7] ASI_DMMU
 	membar		#Sync
 
@@ -104,14 +106,20 @@
 	bne,pn		%xcc, copy_page_using_blkcommit
 	 nop
 
-	rdpr		%ver, %g3
-	sllx		%g3, 16, %g3
-	srlx		%g3, 32 + 16, %g3
-	cmp		%g3, 0x14
-	bne,pt		%icc, spitfire_copy_user_page
+	BRANCH_IF_ANY_CHEETAH(g3,o2,cheetah_copy_user_page)
+	ba,pt		%xcc, spitfire_copy_user_page
 	 nop
 
 cheetah_copy_user_page:
+	.globl		cheetah_copy_user_page_nop_1_6
+cheetah_copy_user_page_nop_1_6:
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g3
+	sethi		%uhi(DCU_PE), %o2
+	sllx		%o2, 32, %o2
+	or		%g3, %o2, %o2
+	stxa		%o2, [%g0] ASI_DCU_CONTROL_REG	! Enable P-cache
+	membar		#Sync
+
 	sethi		%hi((PAGE_SIZE/64)-7), %o2	! A0 Group
 	prefetch	[%o1 + 0x000], #one_read	! MS
 	or		%o2, %lo((PAGE_SIZE/64)-7), %o2	! A1 Group
@@ -203,6 +211,11 @@
 	fmovd		%f12, %f44			! FGA Group
 	fmovd		%f14, %f46			! FGA Group
 	stda		%f32, [%o0] ASI_BLK_P		! MS
+	.globl		cheetah_copy_user_page_nop_2_3
+cheetah_copy_user_page_nop_2_3:
+	mov		PRIMARY_CONTEXT, %o2
+	stxa		%g0, [%o2] ASI_DMMU		! Flush P-cache
+	stxa		%g3, [%g0] ASI_DCU_CONTROL_REG	! Disable P-cache
 	ba,a,pt		%xcc, copy_user_page_continue
 
 spitfire_copy_user_page:
@@ -353,14 +366,14 @@
 	wrpr		%g3, PSTATE_IE, %pstate
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %g5
+	mov		PRIMARY_CONTEXT, %g5
 	stxa		%g0, [%g5] ASI_DMMU
 	membar		#Sync
 
 	ldxa		[%o3] ASI_DTLB_TAG_READ, %g5
 
 	/* Spitfire Errata #32 workaround */
-	mov		0x8, %g7
+	mov		PRIMARY_CONTEXT, %g7
 	stxa		%g0, [%g7] ASI_DMMU
 	membar		#Sync
 
@@ -405,7 +418,8 @@
 	retl
 	 nop
 
-1:	stxa		%g5, [%o2] ASI_DMMU
+1:
+	stxa		%g5, [%o2] ASI_DMMU
 	stxa		%g7, [%o3] ASI_DTLB_DATA_ACCESS
 	membar		#Sync
 	jmpl		%o7 + 0x8, %g0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/mm/fault.c linux-2.4.20/arch/sparc64/mm/fault.c
--- linux-2.4.19/arch/sparc64/mm/fault.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/mm/fault.c	2002-10-29 11:18:50.000000000 +0000
@@ -129,8 +129,8 @@
 	return tally;
 }
 
-void unhandled_fault(unsigned long address, struct task_struct *tsk,
-                     struct pt_regs *regs)
+static void unhandled_fault(unsigned long address, struct task_struct *tsk,
+			    struct pt_regs *regs)
 {
 	if ((unsigned long) address < PAGE_SIZE) {
 		printk(KERN_ALERT "Unable to handle kernel NULL "
@@ -147,6 +147,19 @@
 	die_if_kernel("Oops", regs);
 }
 
+extern void show_trace_raw(struct task_struct *, unsigned long);
+
+static void bad_kernel_pc(struct pt_regs *regs)
+{
+	unsigned long ksp;
+
+	printk(KERN_CRIT "OOPS: Bogus kernel PC [%016lx] in fault handler\n",
+	       regs->tpc);
+	__asm__("mov %%sp, %0" : "=r" (ksp));
+	show_trace_raw(current, ksp);
+	unhandled_fault(regs->tpc, current, regs);
+}
+
 /*
  * We now make sure that mmap_sem is held in all paths that call 
  * this. Additionally, to prevent kswapd from ripping ptes from
@@ -211,7 +224,7 @@
 		if (!regs->tpc || (regs->tpc & 0x3))
 			return 0;
 		if (regs->tstate & TSTATE_PRIV) {
-			insn = *(unsigned int *)regs->tpc;
+			insn = *(unsigned int *) regs->tpc;
 		} else {
 			insn = get_user_insn(regs->tpc);
 		}
@@ -302,6 +315,20 @@
 	    (fault_code & FAULT_CODE_DTLB))
 		BUG();
 
+	if (regs->tstate & TSTATE_PRIV) {
+		unsigned long tpc = regs->tpc;
+		extern unsigned int _etext;
+
+		/* Sanity check the PC. */
+		if ((tpc >= KERNBASE && tpc < (unsigned long) &_etext) ||
+		    (tpc >= MODULES_VADDR && tpc < MODULES_END)) {
+			/* Valid, no problems... */
+		} else {
+			bad_kernel_pc(regs);
+			return;
+		}
+	}
+
 	/*
 	 * If we're in an interrupt or have no user
 	 * context, we must not take the fault..
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/mm/init.c linux-2.4.20/arch/sparc64/mm/init.c
--- linux-2.4.19/arch/sparc64/mm/init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/mm/init.c	2002-10-29 11:18:37.000000000 +0000
@@ -258,6 +258,8 @@
 {
 	if (tlb_type == cheetah)
 		seq_printf(m, "MMU Type\t: Cheetah\n");
+	else if (tlb_type == cheetah_plus)
+		seq_printf(m, "MMU Type\t: Cheetah+\n");
 	else if (tlb_type == spitfire)
 		seq_printf(m, "MMU Type\t: Spitfire\n");
 	else
@@ -427,6 +429,7 @@
 		break;
 
 	case cheetah:
+	case cheetah_plus:
 		phys_page = cheetah_get_litlb_data(sparc64_highest_locked_tlbent());
 		break;
 	};
@@ -452,7 +455,7 @@
 			"i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS),
 			"i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS)
 			: "memory");
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		/* Lock this into i/d tlb-0 entry 11 */
 		__asm__ __volatile__(
 			"stxa	%%g0, [%2] %3\n\t"
@@ -597,9 +600,9 @@
 				spitfire_put_dtlb_data(i, 0x0UL);
 			}
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		for (i = 0; i < 512; i++) {
-			unsigned long tag = cheetah_get_dtlb_tag(i);
+			unsigned long tag = cheetah_get_dtlb_tag(i, 2);
 
 			if ((tag & ~PAGE_MASK) == 0 &&
 			    (tag & PAGE_MASK) >= prom_reserved_base) {
@@ -607,7 +610,21 @@
 						     "membar #Sync"
 						     : /* no outputs */
 						     : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
-				cheetah_put_dtlb_data(i, 0x0UL);
+				cheetah_put_dtlb_data(i, 0x0UL, 2);
+			}
+
+			if (tlb_type != cheetah_plus)
+				continue;
+
+			tag = cheetah_get_dtlb_tag(i, 3);
+
+			if ((tag & ~PAGE_MASK) == 0 &&
+			    (tag & PAGE_MASK) >= prom_reserved_base) {
+				__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
+						     "membar #Sync"
+						     : /* no outputs */
+						     : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
+				cheetah_put_dtlb_data(i, 0x0UL, 3);
 			}
 		}
 	} else {
@@ -656,7 +673,7 @@
 				if (tlb_type == spitfire)
 					spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
 							       prom_dtlb[i].tlb_data);
-				else if (tlb_type == cheetah)
+				else if (tlb_type == cheetah || tlb_type == cheetah_plus)
 					cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent,
 							       prom_dtlb[i].tlb_data);
 			}
@@ -669,7 +686,7 @@
 				if (tlb_type == spitfire)
 					spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
 							       prom_itlb[i].tlb_data);
-				else if (tlb_type == cheetah)
+				else if (tlb_type == cheetah || tlb_type == cheetah_plus)
 					cheetah_put_litlb_data(prom_itlb[i].tlb_ent,
 							       prom_itlb[i].tlb_data);
 			}
@@ -804,7 +821,7 @@
 					break;
 			}
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		int high = CHEETAH_HIGHEST_LOCKED_TLBENT - bigkernel;
 
 		for (i = 0; i < high; i++) {
@@ -876,7 +893,7 @@
 			if (tlb_type == spitfire)
 				spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
 						       prom_dtlb[i].tlb_data);
-			else if (tlb_type == cheetah)
+			else if (tlb_type == cheetah || tlb_type == cheetah_plus)
 				cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent,
 						      prom_dtlb[i].tlb_data);
 		}
@@ -977,7 +994,7 @@
 				spitfire_put_itlb_data(i, 0x0UL);
 			}
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		cheetah_flush_dtlb_all();
 		cheetah_flush_itlb_all();
 	}
@@ -1110,7 +1127,7 @@
 				slot+2,
 				spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2));
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		printk ("Contents of itlb0:\n");
 		for (slot = 0; slot < 16; slot+=2) {
 			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
@@ -1148,7 +1165,7 @@
 				slot+2,
 				spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2));
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		printk ("Contents of dtlb0:\n");
 		for (slot = 0; slot < 16; slot+=2) {
 			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
@@ -1161,9 +1178,19 @@
 		for (slot = 0; slot < 512; slot+=2) {
 			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
 				slot,
-				cheetah_get_dtlb_tag(slot), cheetah_get_dtlb_data(slot),
+				cheetah_get_dtlb_tag(slot, 2), cheetah_get_dtlb_data(slot, 2),
 				slot+1,
-				cheetah_get_dtlb_tag(slot+1), cheetah_get_dtlb_data(slot+1));
+				cheetah_get_dtlb_tag(slot+1, 2), cheetah_get_dtlb_data(slot+1, 2));
+		}
+		if (tlb_type == cheetah_plus) {
+			printk ("Contents of dtlb3:\n");
+			for (slot = 0; slot < 512; slot+=2) {
+				printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
+					slot,
+					cheetah_get_dtlb_tag(slot, 3), cheetah_get_dtlb_data(slot, 3),
+					slot+1,
+					cheetah_get_dtlb_tag(slot+1, 3), cheetah_get_dtlb_data(slot+1, 3));
+			}
 		}
 	}
 }
@@ -1241,6 +1268,8 @@
 	}
 #endif	
 	/* Initialize the boot-time allocator. */
+	max_pfn = max_low_pfn = end_pfn;
+	min_low_pfn = phys_base >> PAGE_SHIFT;
 	bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn, phys_base>>PAGE_SHIFT, end_pfn);
 
 	/* Now register the available physical memory with the
@@ -1341,7 +1370,7 @@
 			  "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (60 << 3)
 			: "memory");
 		}
-	} else if (tlb_type == cheetah) {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		__asm__ __volatile__(
 	"	stxa	%1, [%0] %3\n"
 	"	stxa	%2, [%5] %4\n"
@@ -1646,7 +1675,7 @@
 	       initpages << (PAGE_SHIFT-10), 
 	       PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT));
 
-	if (tlb_type == cheetah)
+	if (tlb_type == cheetah || tlb_type == cheetah_plus)
 		cheetah_ecache_flush_init();
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/mm/ultra.S linux-2.4.20/arch/sparc64/mm/ultra.S
--- linux-2.4.19/arch/sparc64/mm/ultra.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/mm/ultra.S	2002-10-29 11:18:49.000000000 +0000
@@ -13,21 +13,12 @@
 #include <asm/pil.h>
 #include <asm/head.h>
 
-	/* Basically, all this madness has to do with the
-	 * fact that Cheetah does not support IMMU flushes
-	 * out of the secondary context.  Someone needs to
-	 * throw a south lake birthday party for the folks
+	/* Basically, most of the Spitfire vs. Cheetah madness
+	 * has to do with the fact that Cheetah does not support
+	 * IMMU flushes out of the secondary context.  Someone needs
+	 * to throw a south lake birthday party for the folks
 	 * in Microelectronics who refused to fix this shit.
 	 */
-#define BRANCH_IF_CHEETAH(tmp1, tmp2, label)		\
-	rdpr	%ver, %tmp1;				\
-	sethi	%hi(0x003e0014), %tmp2;			\
-	srlx	%tmp1, 32, %tmp1;			\
-	or	%tmp2, %lo(0x003e0014), %tmp2;		\
-	cmp	%tmp1, %tmp2;				\
-	be,pn	%icc, label;				\
-	 nop;						\
-	nop;
 
 	/* This file is meant to be read efficiently by the CPU, not humans.
 	 * Staraj sie tego nikomu nie pierdolnac...
@@ -36,9 +27,7 @@
 	.align		32
 	.globl		__flush_tlb_page, __flush_tlb_mm, __flush_tlb_range
 __flush_tlb_page: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=page&PAGE_MASK, %o2=SECONDARY_CONTEXT */
-/*IC1*/	BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_page)
-__spitfire_flush_tlb_page:
-/*IC2*/	ldxa		[%o2] ASI_DMMU, %g2
+	ldxa		[%o2] ASI_DMMU, %g2
 	cmp		%g2, %o0
 	bne,pn		%icc, __spitfire_flush_tlb_page_slow
 	 or		%o1, 0x10, %g3
@@ -46,27 +35,17 @@
 	stxa		%g0, [%g3] ASI_IMMU_DEMAP
 	retl
 	 flush		%g6
-__cheetah_flush_tlb_page:
-/*IC3*/	rdpr		%pstate, %g5
-	andn		%g5, PSTATE_IE, %g2
-	wrpr		%g2, 0x0, %pstate
-	wrpr		%g0, 1, %tl
-	mov		PRIMARY_CONTEXT, %o2
-	ldxa		[%o2] ASI_DMMU, %g2
-	stxa		%o0, [%o2] ASI_DMMU
-	stxa		%g0, [%o1] ASI_DMMU_DEMAP
-/*IC4*/	stxa		%g0, [%o1] ASI_IMMU_DEMAP
-	stxa		%g2, [%o2] ASI_DMMU
-	flush		%g6
-	wrpr		%g0, 0, %tl
-	retl
-	 wrpr		%g5, 0x0, %pstate
 	nop
 	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
 __flush_tlb_mm: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=SECONDARY_CONTEXT */
-/*IC5*/	BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_mm)
-__spitfire_flush_tlb_mm:
-/*IC6*/	ldxa		[%o1] ASI_DMMU, %g2
+	ldxa		[%o1] ASI_DMMU, %g2
 	cmp		%g2, %o0
 	bne,pn		%icc, __spitfire_flush_tlb_mm_slow
 	 mov		0x50, %g3
@@ -74,30 +53,20 @@
 	stxa		%g0, [%g3] ASI_IMMU_DEMAP
 	retl
 	 flush		%g6
-__cheetah_flush_tlb_mm:
-/*IC7*/	rdpr		%pstate, %g5
-	andn		%g5, PSTATE_IE, %g2
-	wrpr		%g2, 0x0, %pstate
-	wrpr		%g0, 1, %tl
-	mov		PRIMARY_CONTEXT, %o2
-	mov		0x40, %g3
-	ldxa		[%o2] ASI_DMMU, %g2
-	stxa		%o0, [%o2] ASI_DMMU
-/*IC8*/	stxa		%g0, [%g3] ASI_DMMU_DEMAP
-	stxa		%g0, [%g3] ASI_IMMU_DEMAP
-	stxa		%g2, [%o2] ASI_DMMU
-	flush		%g6
-	wrpr		%g0, 0, %tl
-	retl
-	 wrpr		%g5, 0x0, %pstate
 	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
 __flush_tlb_range: /* %o0=(ctx&TAG_CONTEXT_BITS), %o1=start&PAGE_MASK, %o2=SECONDARY_CONTEXT,
 		    * %o3=end&PAGE_MASK, %o4=PAGE_SIZE, %o5=(end - start)
 		    */
-/*IC9*/	BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_range)
-__spitfire_flush_tlb_range:
 #define TLB_MAGIC	207 /* Students, do you know how I calculated this?  -DaveM */
-/*IC10*/cmp		%o5, %o4
+	cmp		%o5, %o4
 	bleu,pt		%xcc, __flush_tlb_page
 	 srlx		%o5, PAGE_SHIFT, %g5
 	cmp		%g5, TLB_MAGIC
@@ -106,7 +75,7 @@
 	ldxa		[%o2] ASI_DMMU, %g2
 	cmp		%g2, %o0
 __spitfire_flush_tlb_range_page_by_page:
-/*IC11*/bne,pn		%icc, __spitfire_flush_tlb_range_pbp_slow
+	bne,pn		%icc, __spitfire_flush_tlb_range_pbp_slow
 	 sub		%o5, %o4, %o5
 1:	stxa		%g0, [%g5 + %o5] ASI_DMMU_DEMAP
 	stxa		%g0, [%g5 + %o5] ASI_IMMU_DEMAP
@@ -115,10 +84,9 @@
 	retl
 	 flush		%g6
 __spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */
-/*IC12*/rdpr		%pstate, %g1
+	rdpr		%pstate, %g1
 	wrpr		%g1, PSTATE_IE, %pstate
 	mov		TLB_TAG_ACCESS, %g3
-	/* XXX Spitfire dependency... */
 	mov		((SPITFIRE_HIGHEST_LOCKED_TLBENT-1) << 3), %g2
 
 	/* Spitfire Errata #32 workaround. */
@@ -130,7 +98,7 @@
 	and		%o4, TAG_CONTEXT_BITS, %o5
 	cmp		%o5, %o0
 	bne,pt		%icc, 2f
-/*IC13*/ andn		%o4, TAG_CONTEXT_BITS, %o4
+	 andn		%o4, TAG_CONTEXT_BITS, %o4
 	cmp		%o4, %o1
 	blu,pt		%xcc, 2f
 	 cmp		%o4, %o3
@@ -138,7 +106,7 @@
 2:	 ldxa		[%g2] ASI_DTLB_TAG_READ, %o4
 	and		%o4, TAG_CONTEXT_BITS, %o5
 	cmp		%o5, %o0
-/*IC14*/andn		%o4, TAG_CONTEXT_BITS, %o4
+	andn		%o4, TAG_CONTEXT_BITS, %o4
 	bne,pt		%icc, 3f
 	 cmp		%o4, %o1
 	blu,pt		%xcc, 3f
@@ -146,7 +114,7 @@
 	blu,pn		%xcc, 5f
 	 nop
 3:	brnz,pt		%g2, 1b
-/*IC15*/ sub		%g2, (1 << 3), %g2
+	 sub		%g2, (1 << 3), %g2
 	retl
 	 wrpr		%g1, 0x0, %pstate
 4:	stxa		%g0, [%g3] ASI_IMMU
@@ -162,7 +130,7 @@
 	 nop
 
 5:	stxa		%g0, [%g3] ASI_DMMU
-/*IC16*/stxa		%g0, [%g2] ASI_DTLB_DATA_ACCESS
+	stxa		%g0, [%g2] ASI_DTLB_DATA_ACCESS
 	flush		%g6
 
 	/* Spitfire Errata #32 workaround. */
@@ -173,33 +141,6 @@
 	ba,pt		%xcc, 3b
 	 nop
 
-	.align		32
-__cheetah_flush_tlb_range:
-	cmp		%o5, %o4
-	bleu,pt		%xcc, __cheetah_flush_tlb_page
-	 nop
-/*IC17*/rdpr		%pstate, %g5
-	andn		%g5, PSTATE_IE, %g2
-	wrpr		%g2, 0x0, %pstate
-	wrpr		%g0, 1, %tl
-	mov		PRIMARY_CONTEXT, %o2
-	sub		%o5, %o4, %o5
-	ldxa		[%o2] ASI_DMMU, %g2
-	stxa		%o0, [%o2] ASI_DMMU
-
-/*IC18*/
-1:	stxa		%g0, [%o1 + %o5] ASI_DMMU_DEMAP
-	stxa		%g0, [%o1 + %o5] ASI_IMMU_DEMAP
-	membar		#Sync
-	brnz,pt		%o5, 1b
-	 sub		%o5, %o4, %o5
-
-	stxa		%g2, [%o2] ASI_DMMU
-	flush		%g6
-	wrpr		%g0, 0, %tl
-	retl
-/*IC19*/ wrpr		%g5, 0x0, %pstate
-
 __spitfire_flush_tlb_mm_slow:
 	rdpr		%pstate, %g1
 	wrpr		%g1, PSTATE_IE, %pstate
@@ -208,7 +149,7 @@
 	stxa		%g0, [%g3] ASI_IMMU_DEMAP
 	flush		%g6
 	stxa		%g2, [%o1] ASI_DMMU
-/*IC18*/flush		%g6
+	flush		%g6
 	retl
 	 wrpr		%g1, 0, %pstate
 
@@ -218,7 +159,7 @@
 	stxa		%o0, [%o2] ASI_DMMU
 	stxa		%g0, [%g3] ASI_DMMU_DEMAP
 	stxa		%g0, [%g3] ASI_IMMU_DEMAP
-/*IC20*/flush		%g6
+	flush		%g6
 	stxa		%g2, [%o2] ASI_DMMU
 	flush		%g6
 	retl
@@ -228,7 +169,7 @@
 	rdpr		%pstate, %g1
 	wrpr		%g1, PSTATE_IE, %pstate
 	stxa		%o0, [%o2] ASI_DMMU
-/*IC21*/
+
 2:	stxa		%g0, [%g5 + %o5] ASI_DMMU_DEMAP
 	stxa		%g0, [%g5 + %o5] ASI_IMMU_DEMAP
 	brnz,pt		%o5, 2b
@@ -237,7 +178,7 @@
 	stxa		%g2, [%o2] ASI_DMMU
 	flush		%g6
 	retl
-/*IC22*/ wrpr		%g1, 0x0, %pstate
+	 wrpr		%g1, 0x0, %pstate
 
 /*
  * The following code flushes one page_size worth.
@@ -301,30 +242,6 @@
 	flush		%g6
 	ba,a,pt		%xcc, 3b
 
-	.align		64
-	.globl		__flush_dcache_page
-__flush_dcache_page:	/* %o0=kaddr, %o1=flush_icache */
-	sub		%o0, %g4, %o0
-	
-	rdpr		%ver, %g1
-	sethi		%hi(0x003e0014), %g2
-	srlx		%g1, 32, %g1
-	or		%g2, %lo(0x003e0014), %g2
-	cmp		%g1, %g2
-	bne,pt		%icc, flush_dcpage_spitfire
-	 nop
-
-flush_dcpage_cheetah:
-	sethi		%hi(PAGE_SIZE), %o4
-1:	subcc		%o4, (1 << 5), %o4
-	stxa		%g0, [%o0 + %o4] ASI_DCACHE_INVALIDATE
-	bne,pt		%icc, 1b
-	 nop
-	membar		#Sync
-	/* I-cache flush never needed on Cheetah, see callers. */
-	retl
-	 nop
-
 #if (PAGE_SHIFT == 13)
 #define DTAG_MASK 0x3
 #elif (PAGE_SHIFT == 16)
@@ -335,7 +252,10 @@
 #define DTAG_MASK 0x3ff
 #endif
 
-flush_dcpage_spitfire:
+	.align		64
+	.globl		__flush_dcache_page
+__flush_dcache_page:	/* %o0=kaddr, %o1=flush_icache */
+	sub		%o0, %g4, %o0
 	clr		%o4
 	srlx		%o0, 11, %o0
 	sethi		%hi(1 << 14), %o2
@@ -424,6 +344,119 @@
 1:	retl
 	 nop
 
+	/* Cheetah specific versions, patched at boot time.  */
+__cheetah_flush_tlb_page: /* 14 insns */
+	rdpr		%pstate, %g5
+	andn		%g5, PSTATE_IE, %g2
+	wrpr		%g2, 0x0, %pstate
+	wrpr		%g0, 1, %tl
+	mov		PRIMARY_CONTEXT, %o2
+	ldxa		[%o2] ASI_DMMU, %g2
+	stxa		%o0, [%o2] ASI_DMMU
+	stxa		%g0, [%o1] ASI_DMMU_DEMAP
+	stxa		%g0, [%o1] ASI_IMMU_DEMAP
+	stxa		%g2, [%o2] ASI_DMMU
+	flush		%g6
+	wrpr		%g0, 0, %tl
+	retl
+	 wrpr		%g5, 0x0, %pstate
+
+__cheetah_flush_tlb_mm: /* 15 insns */
+	rdpr		%pstate, %g5
+	andn		%g5, PSTATE_IE, %g2
+	wrpr		%g2, 0x0, %pstate
+	wrpr		%g0, 1, %tl
+	mov		PRIMARY_CONTEXT, %o2
+	mov		0x40, %g3
+	ldxa		[%o2] ASI_DMMU, %g2
+	stxa		%o0, [%o2] ASI_DMMU
+	stxa		%g0, [%g3] ASI_DMMU_DEMAP
+	stxa		%g0, [%g3] ASI_IMMU_DEMAP
+	stxa		%g2, [%o2] ASI_DMMU
+	flush		%g6
+	wrpr		%g0, 0, %tl
+	retl
+	 wrpr		%g5, 0x0, %pstate
+
+__cheetah_flush_tlb_range: /* 20 insns */
+	cmp		%o5, %o4
+	blu,pt		%xcc, 9f
+	 rdpr		%pstate, %g5
+	andn		%g5, PSTATE_IE, %g2
+	wrpr		%g2, 0x0, %pstate
+	wrpr		%g0, 1, %tl
+	mov		PRIMARY_CONTEXT, %o2
+	sub		%o5, %o4, %o5
+	ldxa		[%o2] ASI_DMMU, %g2
+	stxa		%o0, [%o2] ASI_DMMU
+1:	stxa		%g0, [%o1 + %o5] ASI_DMMU_DEMAP
+	stxa		%g0, [%o1 + %o5] ASI_IMMU_DEMAP
+	membar		#Sync
+	brnz,pt		%o5, 1b
+	 sub		%o5, %o4, %o5
+	stxa		%g2, [%o2] ASI_DMMU
+	flush		%g6
+	wrpr		%g0, 0, %tl
+9:	retl
+	 wrpr		%g5, 0x0, %pstate
+
+flush_dcpage_cheetah: /* 9 insns */
+	sub		%o0, %g4, %o0
+	sethi		%hi(PAGE_SIZE), %o4
+1:	subcc		%o4, (1 << 5), %o4
+	stxa		%g0, [%o0 + %o4] ASI_DCACHE_INVALIDATE
+	membar		#Sync
+	bne,pt		%icc, 1b
+	 nop
+	retl		/* I-cache flush never needed on Cheetah, see callers. */
+	 nop
+
+cheetah_patch_one:
+1:	lduw		[%o1], %g1
+	stw		%g1, [%o0]
+	flush		%o0
+	subcc		%o2, 1, %o2
+	add		%o1, 4, %o1
+	bne,pt		%icc, 1b
+	 add		%o0, 4, %o0
+	retl
+	 nop
+
+	.globl		cheetah_patch_cachetlbops
+cheetah_patch_cachetlbops:
+	save		%sp, -128, %sp
+
+	sethi		%hi(__flush_tlb_page), %o0
+	or		%o0, %lo(__flush_tlb_page), %o0
+	sethi		%hi(__cheetah_flush_tlb_page), %o1
+	or		%o1, %lo(__cheetah_flush_tlb_page), %o1
+	call		cheetah_patch_one
+	 mov		14, %o2
+
+	sethi		%hi(__flush_tlb_mm), %o0
+	or		%o0, %lo(__flush_tlb_mm), %o0
+	sethi		%hi(__cheetah_flush_tlb_mm), %o1
+	or		%o1, %lo(__cheetah_flush_tlb_mm), %o1
+	call		cheetah_patch_one
+	 mov		15, %o2
+
+	sethi		%hi(__flush_tlb_range), %o0
+	or		%o0, %lo(__flush_tlb_range), %o0
+	sethi		%hi(__cheetah_flush_tlb_range), %o1
+	or		%o1, %lo(__cheetah_flush_tlb_range), %o1
+	call		cheetah_patch_one
+	 mov		20, %o2
+
+	sethi		%hi(__flush_dcache_page), %o0
+	or		%o0, %lo(__flush_dcache_page), %o0
+	sethi		%hi(flush_dcpage_cheetah), %o1
+	or		%o1, %lo(flush_dcpage_cheetah), %o1
+	call		cheetah_patch_one
+	 mov		9, %o2
+
+	ret
+	 restore
+
 #ifdef CONFIG_SMP
 	/* These are all called by the slaves of a cross call, at
 	 * trap level 1, with interrupts fully disabled.
@@ -522,9 +555,9 @@
 	sethi		%hi(PAGE_SIZE), %g3
 1:	subcc		%g3, (1 << 5), %g3
 	stxa		%g0, [%g1 + %g3] ASI_DCACHE_INVALIDATE
+	membar		#Sync
 	bne,pt		%icc, 1b
 	 nop
-	membar		#Sync
 	retry
 	nop
 
@@ -587,10 +620,8 @@
 	.text
 
 	/* These two are not performance critical... */
-	.globl		xcall_flush_tlb_all
-xcall_flush_tlb_all:
-	BRANCH_IF_CHEETAH(g2, g3, __cheetah_xcall_flush_tlb_all)
-__spitfire_xcall_flush_tlb_all:
+	.globl		xcall_flush_tlb_all_spitfire
+xcall_flush_tlb_all_spitfire:
 	/* Spitfire Errata #32 workaround. */
 	sethi		%hi(errata32_hwbug), %g4
 	stx		%g0, [%g4 + %lo(errata32_hwbug)]
@@ -632,16 +663,15 @@
 	flush		%g6
 	retry
 
-__cheetah_xcall_flush_tlb_all:
+	.globl		xcall_flush_tlb_all_cheetah
+xcall_flush_tlb_all_cheetah:
 	mov		0x80, %g2
 	stxa		%g0, [%g2] ASI_DMMU_DEMAP
 	stxa		%g0, [%g2] ASI_IMMU_DEMAP
 	retry
 
-	.globl		xcall_flush_cache_all
-xcall_flush_cache_all:
-	BRANCH_IF_CHEETAH(g2, g3, __cheetah_xcall_flush_cache_all)
-__spitfire_xcall_flush_cache_all:
+	.globl		xcall_flush_cache_all_spitfire
+xcall_flush_cache_all_spitfire:
 	sethi		%hi(16383), %g2
 	or		%g2, %lo(16383), %g2
 	clr		%g3
@@ -654,13 +684,6 @@
 	flush		%g6
 	retry
 
-	/* Cheetah's caches are fully coherent in the sense that
-	 * caches are flushed here.  We need to verify this and
-	 * really just not even send out the xcall at the top level.
-	 */
-__cheetah_xcall_flush_cache_all:
-	retry
-
 	/* These just get rescheduled to PIL vectors. */
 	.globl		xcall_call_function
 xcall_call_function:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/prom/misc.c linux-2.4.20/arch/sparc64/prom/misc.c
--- linux-2.4.19/arch/sparc64/prom/misc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/prom/misc.c	2002-10-29 11:18:34.000000000 +0000
@@ -97,6 +97,19 @@
 	goto again; /* PROM is out to get me -DaveM */
 }
 
+void
+prom_halt_power_off(void)
+{
+#ifdef CONFIG_SMP
+	smp_promstop_others();
+	udelay(8000);
+#endif
+	p1275_cmd ("SUNW,power-off", P1275_INOUT(0,0));
+
+	/* if nothing else helps, we just halt */
+	prom_halt ();
+}
+
 /* Set prom sync handler to call function 'funcp'. */
 void
 prom_setcallback(callback_func_t funcp)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/sparc64/solaris/misc.c linux-2.4.20/arch/sparc64/solaris/misc.c
--- linux-2.4.19/arch/sparc64/solaris/misc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/arch/sparc64/solaris/misc.c	2002-10-29 11:18:39.000000000 +0000
@@ -724,6 +724,7 @@
 
 MODULE_AUTHOR("Jakub Jelinek (jj@ultra.linux.cz), Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)");
 MODULE_DESCRIPTION("Solaris binary emulation module");
+MODULE_LICENSE("GPL");
 EXPORT_NO_SYMBOLS;
 
 #ifdef __sparc_v9__
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/Makefile linux-2.4.20/arch/x86_64/Makefile
--- linux-2.4.19/arch/x86_64/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/Makefile	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,123 @@
+#
+# x86_64/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1994 by Linus Torvalds
+#
+# 19990713  Artur Skawina <skawina@geocities.com>
+#           Added '-march' and '-mpreferred-stack-boundary' support
+# 20000913  Pavel Machek <pavel@suse.cz>
+#	    Converted for x86_64 architecture
+# 20010105  Andi Kleen, add IA32 compiler.
+#           ....and later removed it again....
+#
+# $Id: Makefile,v 1.31 2002/03/22 15:56:07 ak Exp $
+
+#
+# early bootup linking needs 32bit. You can either use real 32bit tools
+# here or 64bit tools switch to 32bit mode.
+# 
+IA32_CC := $(CROSS_COMPILE)gcc -m32 -O2 -fomit-frame-pointer -nostdinc -I $(HPATH)
+IA32_LD := $(CROSS_COMPILE)ld -m elf_i386
+IA32_AS := $(CROSS_COMPILE)gcc -m32 -Wa,--32 -D__ASSEMBLY__ -traditional -c -nostdinc -I $(HPATH) 
+IA32_OBJCOPY := $(CROSS_COMPILE)objcopy
+IA32_CPP := $(CROSS_COMPILE)gcc -m32 -E
+export IA32_CC IA32_LD IA32_AS IA32_OBJCOPY IA32_CPP
+
+
+LD=$(CROSS_COMPILE)ld -m elf_x86_64
+OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
+LDFLAGS=-e stext
+LINKFLAGS =-T $(TOPDIR)/arch/x86_64/vmlinux.lds $(LDFLAGS)
+
+CFLAGS += -mno-red-zone
+CFLAGS += -mcmodel=kernel
+CFLAGS += -pipe
+CFLAGS += -fno-reorder-blocks
+# needed for later gcc 3.1
+CFLAGS += -finline-limit=2000
+# needed for earlier gcc 3.1
+CFLAGS += -fno-strength-reduce
+#CFLAGS += -g
+
+# prevent gcc from keeping the stack 16 byte aligned (FIXME)
+#CFLAGS += -mpreferred-stack-boundary=2
+
+HEAD := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task.o
+
+SUBDIRS := arch/x86_64/tools $(SUBDIRS) arch/x86_64/kernel arch/x86_64/mm arch/x86_64/lib
+CORE_FILES := arch/x86_64/kernel/kernel.o $(CORE_FILES)
+CORE_FILES +=  arch/x86_64/mm/mm.o
+LIBS := $(TOPDIR)/arch/x86_64/lib/lib.a $(LIBS)
+
+ifdef CONFIG_IA32_EMULATION
+SUBDIRS += arch/x86_64/ia32
+CORE_FILES += arch/x86_64/ia32/ia32.o
+endif
+
+ifdef CONFIG_HOSTFS
+SUBDIRS += arch/x86_64/hostfs
+core-$(CONFIG_HOSTFS) += arch/x86_64/hostfs/hostfs.o
+endif
+
+CORE_FILES += $(core-y)
+
+arch/x86_64/tools: dummy
+	$(MAKE) linuxsubdirs SUBDIRS=arch/x86_64/tools 
+
+arch/x86_64/kernel: dummy 
+	$(MAKE) linuxsubdirs SUBDIRS=arch/x86_64/kernel
+
+arch/x86_64/mm: dummy
+	$(MAKE) linuxsubdirs SUBDIRS=arch/x86_64/mm
+
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+
+vmlinux: arch/x86_64/vmlinux.lds
+
+FORCE: ;
+
+.PHONY: zImage bzImage compressed zlilo bzlilo zdisk bzdisk install \
+		clean archclean archmrproper archdep checkoffset
+
+checkoffset: FORCE
+	make -C arch/$(ARCH)/tools $(TOPDIR)/include/asm-x86_64/offset.h
+
+bzImage: checkoffset vmlinux
+	@$(MAKEBOOT) bzImage
+
+bzImage-padded: checkoffset vmlinux
+	@$(MAKEBOOT) bzImage-padded
+
+tmp:
+	@$(MAKEBOOT) BOOTIMAGE=bzImage zlilo
+
+bzlilo: checkoffset vmlinux
+	@$(MAKEBOOT) BOOTIMAGE=bzImage zlilo
+
+bzdisk: checkoffset vmlinux
+	@$(MAKEBOOT) BOOTIMAGE=bzImage zdisk
+
+install: checkoffset vmlinux
+	@$(MAKEBOOT) BOOTIMAGE=bzImage install
+
+archclean:
+	@$(MAKEBOOT) clean
+	@$(MAKE) -C $(TOPDIR)/arch/x86_64/tools clean
+
+archmrproper:
+	rm -f $(TOPDIR)/arch/x86_64/tools/offset.h
+	rm -f $(TOPDIR)/arch/x86_64/tools/offset.tmp
+	rm -f $(TOPDIR)/include/asm-x86_64/offset.h
+
+archdep:
+	@$(MAKE) -C $(TOPDIR)/arch/x86_64/tools all
+	@$(MAKEBOOT) dep
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/boot/Makefile linux-2.4.20/arch/x86_64/boot/Makefile
--- linux-2.4.19/arch/x86_64/boot/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/boot/Makefile	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,92 @@
+#
+# arch/x86_64/boot/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1994 by Linus Torvalds
+#
+
+BOOT_INCL =	$(TOPDIR)/include/linux/config.h \
+		$(TOPDIR)/include/linux/autoconf.h \
+		$(TOPDIR)/include/asm/boot.h
+
+zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build
+	$(OBJCOPY) compressed/vmlinux compressed/vmlinux.out
+	tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
+
+bzImage: $(CONFIGURE) bbootsect bsetup compressed/bvmlinux tools/build
+	$(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out
+	tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage
+
+bzImage-padded: bzImage
+	dd if=/dev/zero bs=1k count=70 >> bzImage
+
+compressed/vmlinux: $(TOPDIR)/vmlinux
+	@$(MAKE) -C compressed vmlinux
+
+compressed/bvmlinux: $(TOPDIR)/vmlinux
+	@$(MAKE) -C compressed bvmlinux
+
+zdisk: $(BOOTIMAGE)
+	dd bs=8192 if=$(BOOTIMAGE) of=/dev/fd0
+
+zlilo: $(CONFIGURE) $(BOOTIMAGE)
+	if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
+	if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
+	cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz
+	cp $(TOPDIR)/System.map $(INSTALL_PATH)/
+	if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
+
+install: $(CONFIGURE) $(BOOTIMAGE)
+	sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map "$(INSTALL_PATH)"
+
+tools/build: tools/build.c
+	$(HOSTCC) $(HOSTCFLAGS) -o $@ $<
+
+bootsect: bootsect.o
+	$(IA32_LD) -Ttext 0x0 -s --oformat binary -o $@ $<
+
+bootsect.o: bootsect.s
+	$(IA32_AS) -o $@ $<
+
+bootsect.s: bootsect.S Makefile $(BOOT_INCL)
+	$(IA32_CPP) $(CPPFLAGS) -traditional -D__ASSEMBLY__ $(SVGA_MODE) $(RAMDISK) $< -o $@
+
+bbootsect: bbootsect.o
+	$(IA32_LD) -Ttext 0x0 -s --oformat binary $< -o $@
+
+bbootsect.o: bbootsect.s
+	$(IA32_AS) -o $@ $<
+
+bbootsect.s: bootsect.S Makefile $(BOOT_INCL)
+	$(IA32_CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
+
+setup: setup.o
+	$(IA32_LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
+
+setup.o: setup.s
+	$(IA32_AS) -o $@ $<
+
+setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
+	$(IA32_CPP) $(CPPFLAGS) -traditional -D__ASSEMBLY__ $(SVGA_MODE) $(RAMDISK) $< -o $@
+
+bsetup: bsetup.o
+	$(IA32_LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
+
+bsetup.o: bsetup.s
+	$(IA32_AS) -o $@ $<
+
+bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
+	$(IA32_CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
+
+dep:
+
+clean:
+	rm -f tools/build
+	rm -f setup bootsect zImage compressed/vmlinux.out
+	rm -f bsetup bbootsect bzImage compressed/bvmlinux.out
+	@$(MAKE) -C compressed clean
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/boot/bootsect.S linux-2.4.20/arch/x86_64/boot/bootsect.S
--- linux-2.4.19/arch/x86_64/boot/bootsect.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/boot/bootsect.S	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,418 @@
+/*
+ *	bootsect.S		Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ *	modified by Drew Eckhardt
+ *	modified by Bruce Evans (bde)
+ *	modified by Chris Noe (May 1999) (as86 -> gas)
+ *
+ * 360k/720k disk support: Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl>
+ *
+ * BIG FAT NOTE: We're in real mode using 64k segments.  Therefore segment
+ * addresses must be multiplied by 16 to obtain their respective linear
+ * addresses. To avoid confusion, linear addresses are written using leading
+ * hex while segment addresses are written as segment:offset.
+ *
+ * bde - should not jump blindly, there may be systems with only 512K low
+ * memory.  Use int 0x12 to get the top of memory, etc.
+ *
+ * It then loads 'setup' directly after itself (0x90200), and the system
+ * at 0x10000, using BIOS interrupts. 
+ *
+ * NOTE! currently system is at most (8*65536-4096) bytes long. This should 
+ * be no problem, even in the future. I want to keep it simple. This 508 kB
+ * kernel size should be enough, especially as this doesn't contain the
+ * buffer cache as in minix (and especially now that the kernel is 
+ * compressed :-)
+ *
+ * The loader has been made as simple as possible, and continuous
+ * read errors will result in a unbreakable loop. Reboot by hand. It
+ * loads pretty fast by getting whole tracks at a time whenever possible.
+ */
+
+#include <asm/boot.h>
+
+SETUPSECTS	= 4			/* default nr of setup-sectors */
+BOOTSEG		= 0x07C0		/* original address of boot-sector */
+INITSEG		= DEF_INITSEG		/* we move boot here - out of the way */
+SETUPSEG	= DEF_SETUPSEG		/* setup starts here */
+SYSSEG		= DEF_SYSSEG		/* system loaded at 0x10000 (65536) */
+SYSSIZE		= DEF_SYSSIZE		/* system size: # of 16-byte clicks */
+					/* to be loaded */
+ROOT_DEV	= 0 			/* ROOT_DEV is now written by "build" */
+SWAP_DEV	= 0			/* SWAP_DEV is now written by "build" */
+
+#ifndef SVGA_MODE
+#define SVGA_MODE ASK_VGA
+#endif
+
+#ifndef RAMDISK
+#define RAMDISK 0
+#endif
+
+#ifndef ROOT_RDONLY
+#define ROOT_RDONLY 1
+#endif
+
+.code16
+.text
+
+.global _start
+_start:
+
+# First things first. Move ourself from 0x7C00 -> 0x90000 and jump there.
+
+	movw	$BOOTSEG, %ax
+	movw	%ax, %ds		# %ds = BOOTSEG
+	movw	$INITSEG, %ax
+	movw	%ax, %es		# %ax = %es = INITSEG
+	movw	$256, %cx
+	subw	%si, %si
+	subw	%di, %di
+	cld
+	rep
+	movsw
+	ljmp	$INITSEG, $go
+
+# bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde).  We
+# wouldn't have to worry about this if we checked the top of memory.  Also
+# my BIOS can be configured to put the wini drive tables in high memory
+# instead of in the vector table.  The old stack might have clobbered the
+# drive table.
+
+go:	movw	$0x4000-12, %di		# 0x4000 is an arbitrary value >=
+					# length of bootsect + length of
+					# setup + room for stack;
+					# 12 is disk parm size.
+	movw	%ax, %ds		# %ax and %es already contain INITSEG
+	movw	%ax, %ss
+	movw	%di, %sp		# put stack at INITSEG:0x4000-12.
+
+# Many BIOS's default disk parameter tables will not recognize
+# multi-sector reads beyond the maximum sector number specified
+# in the default diskette parameter tables - this may mean 7
+# sectors in some cases.
+#
+# Since single sector reads are slow and out of the question,
+# we must take care of this by creating new parameter tables
+# (for the first disk) in RAM.  We will set the maximum sector
+# count to 36 - the most we will encounter on an ED 2.88.  
+#
+# High doesn't hurt.  Low does.
+#
+# Segments are as follows: %cs = %ds = %es = %ss = INITSEG, %fs = 0,
+# and %gs is unused.
+
+	movw	%cx, %fs		# %fs = 0
+	movw	$0x78, %bx		# %fs:%bx is parameter table address
+	pushw	%ds
+	ldsw	%fs:(%bx), %si		# %ds:%si is source
+	movb	$6, %cl			# copy 12 bytes
+	pushw	%di			# %di = 0x4000-12.
+	rep				# don't worry about cld
+	movsw				# already done above
+	popw	%di
+	popw	%ds
+	movb	$36, 0x4(%di)		# patch sector count
+	movw	%di, %fs:(%bx)
+	movw	%es, %fs:2(%bx)
+
+# Get disk drive parameters, specifically number of sectors/track.
+
+# It seems that there is no BIOS call to get the number of sectors.
+# Guess 36 sectors if sector 36 can be read, 18 sectors if sector 18
+# can be read, 15 if sector 15 can be read.  Otherwise guess 9.
+# Note that %cx = 0 from rep movsw above.
+
+	movw	$disksizes, %si		# table of sizes to try
+probe_loop:
+	lodsb
+	cbtw				# extend to word
+	movw	%ax, sectors
+	cmpw	$disksizes+4, %si
+	jae	got_sectors		# If all else fails, try 9
+
+	xchgw	%cx, %ax		# %cx = track and sector
+	xorw	%dx, %dx		# drive 0, head 0
+	movw	$0x0200, %bx		# address = 512, in INITSEG (%es = %cs)
+	movw	$0x0201, %ax		# service 2, 1 sector
+	int	$0x13
+	jc	probe_loop		# try next value
+
+got_sectors:
+	movb	$0x03, %ah		# read cursor pos
+	xorb	%bh, %bh
+	int	$0x10
+	movw	$9, %cx
+	movb	$0x07, %bl		# page 0, attribute 7 (normal)
+					# %bh is set above; int10 doesn't
+					# modify it
+	movw	$msg1, %bp
+	movw	$0x1301, %ax		# write string, move cursor
+	int	$0x10			# tell the user we're loading..
+
+# Load the setup-sectors directly after the moved bootblock (at 0x90200).
+# We should know the drive geometry to do it, as setup may exceed first
+# cylinder (for 9-sector 360K and 720K floppies).
+
+	movw	$0x0001, %ax		# set sread (sector-to-read) to 1 as
+	movw	$sread, %si		# the boot sector has already been read
+	movw	%ax, (%si)
+
+	xorw	%ax, %ax		# reset FDC
+	xorb	%dl, %dl
+	int	$0x13
+	movw	$0x0200, %bx		# address = 512, in INITSEG
+next_step:
+	movb	setup_sects, %al
+	movw	sectors, %cx
+	subw	(%si), %cx		# (%si) = sread
+	cmpb	%cl, %al
+	jbe	no_cyl_crossing
+	movw	sectors, %ax
+	subw	(%si), %ax		# (%si) = sread
+no_cyl_crossing:
+	call	read_track
+	pushw	%ax			# save it
+	call	set_next		# set %bx properly; it uses %ax,%cx,%dx
+	popw	%ax			# restore
+	subb	%al, setup_sects	# rest - for next step
+	jnz	next_step
+
+	pushw	$SYSSEG
+	popw	%es			# %es = SYSSEG
+	call	read_it
+	call	kill_motor
+	call	print_nl
+
+# After that we check which root-device to use. If the device is
+# defined (!= 0), nothing is done and the given device is used.
+# Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8)
+# depending on the number of sectors we pretend to know we have.
+
+# Segments are as follows: %cs = %ds = %ss = INITSEG,
+#	%es = SYSSEG, %fs = 0, %gs is unused.
+
+	movw	root_dev, %ax
+	orw	%ax, %ax
+	jne	root_defined
+
+	movw	sectors, %bx
+	movw	$0x0208, %ax		# /dev/ps0 - 1.2Mb
+	cmpw	$15, %bx
+	je	root_defined
+
+	movb	$0x1c, %al		# /dev/PS0 - 1.44Mb
+	cmpw	$18, %bx
+	je	root_defined
+
+	movb	$0x20, %al		# /dev/fd0H2880 - 2.88Mb
+	cmpw	$36, %bx
+	je	root_defined
+
+	movb	$0, %al			# /dev/fd0 - autodetect
+root_defined:
+	movw	%ax, root_dev
+
+# After that (everything loaded), we jump to the setup-routine
+# loaded directly after the bootblock:
+
+	ljmp	$SETUPSEG, $0
+
+# These variables are addressed via %si register as it gives shorter code.
+
+sread:	.word 0				# sectors read of current track
+head:	.word 0				# current head
+track:	.word 0				# current track
+
+# This routine loads the system at address SYSSEG, making sure
+# no 64kB boundaries are crossed. We try to load it as fast as
+# possible, loading whole tracks whenever we can.
+
+read_it:
+	movw	%es, %ax		# %es = SYSSEG when called
+	testw	$0x0fff, %ax
+die:	jne	die			# %es must be at 64kB boundary
+	xorw	%bx, %bx		# %bx is starting address within segment
+rp_read:
+#ifdef __BIG_KERNEL__			# look in setup.S for bootsect_kludge
+	bootsect_kludge = 0x220		# 0x200 + 0x20 which is the size of the
+	lcall	bootsect_kludge		# bootsector + bootsect_kludge offset
+#else
+	movw	%es, %ax
+	subw	$SYSSEG, %ax
+	movw	%bx, %cx
+	shr	$4, %cx
+	add	%cx, %ax		# check offset
+#endif
+	cmpw	syssize, %ax		# have we loaded everything yet?
+	jbe	ok1_read
+
+	ret
+
+ok1_read:
+	movw	sectors, %ax
+	subw	(%si), %ax		# (%si) = sread
+	movw	%ax, %cx
+	shlw	$9, %cx
+	addw	%bx, %cx
+	jnc	ok2_read
+
+	je	ok2_read
+
+	xorw	%ax, %ax
+	subw	%bx, %ax
+	shrw	$9, %ax
+ok2_read:
+	call	read_track
+	call	set_next
+	jmp	rp_read
+
+read_track:
+	pusha
+	pusha	
+	movw	$0xe2e, %ax 		# loading... message 2e = .
+	movw	$7, %bx
+ 	int	$0x10
+	popa		
+
+# Accessing head, track, sread via %si gives shorter code.
+
+	movw	4(%si), %dx		# 4(%si) = track
+	movw	(%si), %cx		# (%si)  = sread
+	incw	%cx
+	movb	%dl, %ch
+	movw	2(%si), %dx		# 2(%si) = head
+	movb	%dl, %dh
+	andw	$0x0100, %dx
+	movb	$2, %ah
+	pushw	%dx			# save for error dump
+	pushw	%cx
+	pushw	%bx
+	pushw	%ax
+	int	$0x13
+	jc	bad_rt
+
+	addw	$8, %sp
+	popa
+	ret
+
+set_next:
+	movw	%ax, %cx
+	addw	(%si), %ax		# (%si) = sread
+	cmp	sectors, %ax
+	jne	ok3_set
+	movw	$0x0001, %ax
+	xorw	%ax, 2(%si)		# change head
+	jne	ok4_set
+	incw	4(%si)			# next track
+ok4_set:
+	xorw	%ax, %ax
+ok3_set:
+	movw	%ax, (%si)		# set sread
+	shlw	$9, %cx
+	addw	%cx, %bx
+	jnc	set_next_fin
+	movw	%es, %ax
+	addb	$0x10, %ah
+	movw	%ax, %es
+	xorw	%bx, %bx
+set_next_fin:
+	ret
+
+bad_rt:
+	pushw	%ax			# save error code
+	call	print_all		# %ah = error, %al = read
+	xorb	%ah, %ah
+	xorb	%dl, %dl
+	int	$0x13
+	addw	$10, %sp
+	popa
+	jmp read_track
+
+# print_all is for debugging purposes.  
+#
+# it will print out all of the registers.  The assumption is that this is
+# called from a routine, with a stack frame like
+#
+#	%dx 
+#	%cx
+#	%bx
+#	%ax
+#	(error)
+#	ret <- %sp
+ 
+print_all:
+	movw	$5, %cx			# error code + 4 registers
+	movw	%sp, %bp
+print_loop:
+	pushw	%cx			# save count remaining
+	call	print_nl		# <-- for readability
+	cmpb	$5, %cl
+	jae	no_reg			# see if register name is needed
+	
+	movw	$0xe05 + 'A' - 1, %ax
+	subb	%cl, %al
+	int	$0x10
+	movb	$'X', %al
+	int	$0x10
+	movb	$':', %al
+	int	$0x10
+no_reg:
+	addw	$2, %bp			# next register
+	call	print_hex		# print it
+	popw	%cx
+	loop	print_loop
+	ret
+
+print_nl:
+	movw	$0xe0d, %ax		# CR
+	int	$0x10
+	movb	$0xa, %al		# LF
+	int 	$0x10
+	ret
+
+# print_hex is for debugging purposes, and prints the word
+# pointed to by %ss:%bp in hexadecimal.
+
+print_hex:
+	movw	$4, %cx			# 4 hex digits
+	movw	(%bp), %dx		# load word into %dx
+print_digit:
+	rolw	$4, %dx			# rotate to use low 4 bits
+	movw	$0xe0f, %ax		# %ah = request
+	andb	%dl, %al		# %al = mask for nybble
+	addb	$0x90, %al		# convert %al to ascii hex
+	daa				# in only four instructions!
+	adc	$0x40, %al
+	daa
+	int	$0x10
+	loop	print_digit
+	ret
+
+# This procedure turns off the floppy drive motor, so
+# that we enter the kernel in a known state, and
+# don't have to worry about it later.
+# NOTE: Doesn't save %ax or %dx; do it yourself if you need to.
+
+kill_motor:
+	movw	$0x3f2, %dx
+	xorb	%al, %al
+	outb	%al, %dx
+	ret
+
+sectors:	.word 0
+disksizes:	.byte 36, 18, 15, 9
+msg1:		.byte 13, 10
+		.ascii "Loading"
+
+# XXX: This is a fairly snug fit.
+
+.org 497
+setup_sects:	.byte SETUPSECTS
+root_flags:	.word ROOT_RDONLY
+syssize:	.word SYSSIZE
+swap_dev:	.word SWAP_DEV
+ram_size:	.word RAMDISK
+vid_mode:	.word SVGA_MODE
+root_dev:	.word ROOT_DEV
+boot_flag:	.word 0xAA55
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/boot/compressed/Makefile linux-2.4.20/arch/x86_64/boot/compressed/Makefile
--- linux-2.4.19/arch/x86_64/boot/compressed/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/boot/compressed/Makefile	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,43 @@
+#
+# linux/arch/i386/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux
+#
+
+HEAD = head.o
+SYSTEM = $(TOPDIR)/vmlinux
+
+OBJECTS = $(HEAD) misc.o
+
+IA32_CFLAGS := -O2 -DSTDC_HEADERS
+
+#
+# ZIMAGE_OFFSET is the load offset of the compression loader
+# BZIMAGE_OFFSET is the load offset of the high loaded compression loader
+#
+BZIMAGE_OFFSET = 0x100000
+
+BZLINKFLAGS = -Ttext $(BZIMAGE_OFFSET) $(ZLDFLAGS)
+
+all: vmlinux
+
+bvmlinux: piggy.o $(OBJECTS)
+	$(IA32_LD) $(BZLINKFLAGS) -o bvmlinux $(OBJECTS) piggy.o
+
+head.o: head.S
+	$(IA32_AS) -c head.S
+
+misc.o: misc.c
+	$(IA32_CC) $(IA32_CFLAGS) -c misc.c
+
+piggy.o:	$(SYSTEM)
+	tmppiggy=_tmp_$$$$piggy; \
+	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
+	$(OBJCOPY) $(SYSTEM) $$tmppiggy; \
+	gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
+	echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
+	$(IA32_LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \
+	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
+
+clean:
+	rm -f vmlinux bvmlinux _tmp_*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/boot/compressed/head.S linux-2.4.20/arch/x86_64/boot/compressed/head.S
--- linux-2.4.19/arch/x86_64/boot/compressed/head.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/boot/compressed/head.S	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,142 @@
+/*
+ *  linux/boot/head.S
+ *
+ *  Copyright (C) 1991, 1992, 1993  Linus Torvalds
+ *
+ *  $Id: head.S,v 1.3 2001/04/20 00:59:28 ak Exp $	 		
+ */
+
+/*
+ *  head.S contains the 32-bit startup code.
+ *
+ * NOTE!!! Startup happens at absolute address 0x00001000, which is also where
+ * the page directory will exist. The startup code will be overwritten by
+ * the page directory. [According to comments etc elsewhere on a compressed
+ * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
+ *
+ * Page 0 is deliberately kept safe, since System Management Mode code in 
+ * laptops may need to access the BIOS data stored there.  This is also
+ * useful for future device drivers that either access the BIOS via VM86 
+ * mode.
+ */
+
+/*
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996	
+ */
+.code32
+.text
+
+#include <linux/linkage.h>
+#include <asm/segment.h>
+
+	.code32
+	.globl startup_32
+	
+startup_32:
+	cld
+	cli
+	movl $(__KERNEL_DS),%eax
+	movl %eax,%ds
+	movl %eax,%es
+	movl %eax,%fs
+	movl %eax,%gs
+
+	lss SYMBOL_NAME(stack_start),%esp
+	xorl %eax,%eax
+1:	incl %eax		# check that A20 really IS enabled
+	movl %eax,0x000000	# loop forever if it isn't
+	cmpl %eax,0x100000
+	je 1b
+
+/*
+ * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
+ * confuse the debugger if this code is traced.
+ * XXX - best to initialize before switching to protected mode.
+ */
+	pushl $0
+	popfl
+/*
+ * Clear BSS
+ */
+	xorl %eax,%eax
+	movl $ SYMBOL_NAME(_edata),%edi
+	movl $ SYMBOL_NAME(_end),%ecx
+	subl %edi,%ecx
+	cld
+	rep
+	stosb
+/*
+ * Do the decompression, and jump to the new kernel..
+ */
+	subl $16,%esp	# place for structure on the stack
+	movl %esp,%eax
+	pushl %esi	# real mode pointer as second arg
+	pushl %eax	# address of structure as first arg
+	call SYMBOL_NAME(decompress_kernel)
+	orl  %eax,%eax 
+	jnz  3f
+	addl $8,%esp
+	xorl %ebx,%ebx
+	ljmp $(__KERNEL_CS), $0x100000
+
+/*
+ * We come here, if we were loaded high.
+ * We need to move the move-in-place routine down to 0x1000
+ * and then start it with the buffer addresses in registers,
+ * which we got from the stack.
+ */
+3:
+	movl %esi,%ebx	
+	movl $move_routine_start,%esi
+	movl $0x1000,%edi
+	movl $move_routine_end,%ecx
+	subl %esi,%ecx
+	addl $3,%ecx
+	shrl $2,%ecx
+	cld
+	rep
+	movsl
+
+	popl %esi	# discard the address
+	addl $4,%esp	# real mode pointer
+	popl %esi	# low_buffer_start
+	popl %ecx	# lcount
+	popl %edx	# high_buffer_start
+	popl %eax	# hcount
+	movl $0x100000,%edi
+	cli		# make sure we don't get interrupted
+	ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine
+
+/*
+ * Routine (template) for moving the decompressed kernel in place,
+ * if we were high loaded. This _must_ PIC-code !
+ */
+move_routine_start:
+	movl %ecx,%ebp
+	shrl $2,%ecx
+	rep
+	movsl
+	movl %ebp,%ecx
+	andl $3,%ecx
+	rep
+	movsb
+	movl %edx,%esi
+	movl %eax,%ecx	# NOTE: rep movsb won't move if %ecx == 0
+	addl $3,%ecx
+	shrl $2,%ecx
+	rep
+	movsl
+	movl %ebx,%esi	# Restore setup pointer
+	xorl %ebx,%ebx
+	ljmp $(__KERNEL_CS), $0x100000
+move_routine_end:
+
+
+/* Stack for uncompression */ 	
+	.align 32
+user_stack:	 	
+	.fill 4096,4,0
+stack_start:	
+	.long user_stack+4096
+	.word __KERNEL_DS
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/boot/compressed/misc.c linux-2.4.20/arch/x86_64/boot/compressed/misc.c
--- linux-2.4.19/arch/x86_64/boot/compressed/misc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/boot/compressed/misc.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,431 @@
+/*
+ * misc.c
+ * 
+ * This is a collection of several routines from gzip-1.0.3 
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ * puts by Nick Holloway 1993, better puts by Martin Mares 1995
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+ */
+
+#include "miscsetup.h"
+#include <asm/io.h>
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args)  args
+#define STATIC static
+
+#undef memset
+#undef memcpy
+#define memzero(s, n)     memset ((s), 0, (n))
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+#define WSIZE 0x8000		/* Window size must be at least 32k, */
+				/* and a power of two */
+
+static uch *inbuf;	     /* input buffer */
+static uch window[WSIZE];    /* Sliding window buffer */
+
+static unsigned insize = 0;  /* valid bytes in inbuf */
+static unsigned inptr = 0;   /* index of next byte to be processed in inbuf */
+static unsigned outcnt = 0;  /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+		
+/* Diagnostic functions */
+#ifdef DEBUG
+#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+static int  fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+  
+/*
+ * This is set up by the setup-routine at boot-time
+ */
+static unsigned char *real_mode; /* Pointer to real-mode data */
+
+#define EXT_MEM_K   (*(unsigned short *)(real_mode + 0x2))
+#ifndef STANDARD_MEMORY_BIOS_CALL
+#define ALT_MEM_K   (*(unsigned long *)(real_mode + 0x1e0))
+#endif
+#define SCREEN_INFO (*(struct screen_info *)(real_mode+0))
+
+extern char input_data[];
+extern int input_len;
+
+static long bytes_out = 0;
+static uch *output_data;
+static unsigned long output_ptr = 0;
+
+ 
+static void *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+ 
+static void puts(const char *);
+  
+extern int end;
+static long free_mem_ptr = (long)&end;
+static long free_mem_end_ptr;
+
+#define INPLACE_MOVE_ROUTINE  0x1000
+#define LOW_BUFFER_START      0x2000
+#define LOW_BUFFER_MAX       0x90000
+#define HEAP_SIZE             0x3000
+static unsigned int low_buffer_end, low_buffer_size;
+static int high_loaded =0;
+static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;
+
+static char *vidmem = (char *)0xb8000;
+static int vidport;
+static int lines, cols;
+
+#include "../../../../lib/inflate.c"
+
+static void *malloc(int size)
+{
+	void *p;
+
+	if (size <0) error("Malloc error\n");
+	if (free_mem_ptr <= 0) error("Memory error\n");
+
+	free_mem_ptr = (free_mem_ptr + 3) & ~3;	/* Align */
+
+	p = (void *)free_mem_ptr;
+	free_mem_ptr += size;
+
+	if (free_mem_ptr >= free_mem_end_ptr)
+		error("\nOut of memory\n");
+
+	return p;
+}
+
+static void free(void *where)
+{	/* Don't care */
+}
+
+static void gzip_mark(void **ptr)
+{
+	*ptr = (void *) free_mem_ptr;
+}
+
+static void gzip_release(void **ptr)
+{
+	free_mem_ptr = (long) *ptr;
+}
+ 
+static void scroll(void)
+{
+	int i;
+
+	memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
+	for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
+		vidmem[i] = ' ';
+}
+
+static void puts(const char *s)
+{
+	int x,y,pos;
+	char c;
+
+	x = SCREEN_INFO.orig_x;
+	y = SCREEN_INFO.orig_y;
+
+	while ( ( c = *s++ ) != '\0' ) {
+		if ( c == '\n' ) {
+			x = 0;
+			if ( ++y >= lines ) {
+				scroll();
+				y--;
+			}
+		} else {
+			vidmem [ ( x + cols * y ) * 2 ] = c; 
+			if ( ++x >= cols ) {
+				x = 0;
+				if ( ++y >= lines ) {
+					scroll();
+					y--;
+				}
+			}
+		}
+	}
+
+	SCREEN_INFO.orig_x = x;
+	SCREEN_INFO.orig_y = y;
+
+	pos = (x + cols * y) * 2;	/* Update cursor position */
+	outb_p(14, vidport);
+	outb_p(0xff & (pos >> 9), vidport+1);
+	outb_p(15, vidport);
+	outb_p(0xff & (pos >> 1), vidport+1);
+}
+
+void* memset(void* s, int c, size_t n)
+{
+	int i;
+	char *ss = (char*)s;
+
+	for (i=0;i<n;i++) ss[i] = c;
+	return s;
+}
+
+void* memcpy(void* __dest, __const void* __src,
+			    size_t __n)
+{
+	int i;
+	char *d = (char *)__dest, *s = (char *)__src;
+
+	for (i=0;i<__n;i++) d[i] = s[i];
+	return __dest;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+static int fill_inbuf(void)
+{
+	if (insize != 0) {
+		error("ran out of input data\n");
+	}
+
+	inbuf = input_data;
+	insize = input_len;
+	inptr = 1;
+	return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void flush_window_low(void)
+{
+    ulg c = crc;         /* temporary variable */
+    unsigned n;
+    uch *in, *out, ch;
+    
+    in = window;
+    out = &output_data[output_ptr]; 
+    for (n = 0; n < outcnt; n++) {
+	    ch = *out++ = *in++;
+	    c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+    }
+    crc = c;
+    bytes_out += (ulg)outcnt;
+    output_ptr += (ulg)outcnt;
+    outcnt = 0;
+}
+
+static void flush_window_high(void)
+{
+    ulg c = crc;         /* temporary variable */
+    unsigned n;
+    uch *in,  ch;
+    in = window;
+    for (n = 0; n < outcnt; n++) {
+	ch = *output_data++ = *in++;
+	if ((ulg)output_data == low_buffer_end) output_data=high_buffer_start;
+	c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+    }
+    crc = c;
+    bytes_out += (ulg)outcnt;
+    outcnt = 0;
+}
+
+static void flush_window(void)
+{
+	if (high_loaded) flush_window_high();
+	else flush_window_low();
+}
+
+static void error(char *x)
+{
+	puts("\n\n");
+	puts(x);
+	puts("\n\n -- System halted");
+
+	while(1);	/* Halt */
+}
+
+void setup_normal_output_buffer(void)
+{
+#ifdef STANDARD_MEMORY_BIOS_CALL
+	if (EXT_MEM_K < 1024) error("Less than 2MB of memory.\n");
+#else
+	if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory.\n");
+#endif
+	output_data = (char *)0x100000; /* Points to 1M */
+	free_mem_end_ptr = (long)real_mode;
+}
+
+struct moveparams {
+	uch *low_buffer_start;  int lcount;
+	uch *high_buffer_start; int hcount;
+};
+
+void setup_output_buffer_if_we_run_high(struct moveparams *mv)
+{
+	high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
+#ifdef STANDARD_MEMORY_BIOS_CALL
+	if (EXT_MEM_K < (3*1024)) error("Less than 4MB of memory.\n");
+#else
+	if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory.\n");
+#endif	
+	mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START;
+	low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX
+	  ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff;
+	low_buffer_size = low_buffer_end - LOW_BUFFER_START;
+	high_loaded = 1;
+	free_mem_end_ptr = (long)high_buffer_start;
+	if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) {
+		high_buffer_start = (uch *)(0x100000 + low_buffer_size);
+		mv->hcount = 0; /* say: we need not to move high_buffer */
+	}
+	else mv->hcount = -1;
+	mv->high_buffer_start = high_buffer_start;
+}
+
+void close_output_buffer_if_we_run_high(struct moveparams *mv)
+{
+	if (bytes_out > low_buffer_size) {
+		mv->lcount = low_buffer_size;
+		if (mv->hcount)
+			mv->hcount = bytes_out - low_buffer_size;
+	} else {
+		mv->lcount = bytes_out;
+		mv->hcount = 0;
+	}
+}
+
+void check_cpu(void)
+{
+	int res = 0;
+	asm volatile( " \n\
+	movl $3,%%edx		# at least 386 \n\
+	pushfl			# push EFLAGS \n\
+	popl %%eax		# get EFLAGS \n\
+	movl %%eax,%%ecx		# save original EFLAGS \n\
+	xorl $0x40000,%%eax	# flip AC bit in EFLAGS \n\
+	pushl %%eax		# copy to EFLAGS \n\
+	popfl			# set EFLAGS \n\
+	pushfl			# get new EFLAGS \n\
+	popl %%eax		# put it in eax \n\
+	xorl %%ecx,%%eax		# change in flags \n\
+	andl $0x40000,%%eax	# check if AC bit changed \n\
+	je 1f \n\
+\n\
+	movl $4,%%edx		# at least 486 \n\
+	movl %%ecx,%%eax \n\
+	xorl $0x200000,%%eax	# check ID flag \n\
+	pushl %%eax \n\
+	popfl			# if we are on a straight 486DX, SX, or \n\
+	pushfl			# 487SX we can't change it \n\
+	popl %%eax \n\
+	xorl %%ecx,%%eax \n\
+	pushl %%ecx		# restore original EFLAGS \n\
+	popfl \n\
+	andl $0x200000,%%eax \n\
+	je 1f \n\
+\n\
+	/* get vendor info */ \n\
+#	xorl %%eax,%%eax			# call CPUID with 0 -> return vendor ID \n\
+#	cpuid \n\
+#	movl $5, %%edx \n\
+#	cmpl $0x41757468,%%ebx		# check thats amd \n\
+#	jne 1f \n\
+\n\
+	mov $0x80000000,%%eax		# Is extended cpuid supported?\n\
+	cpuid\n\
+	test $0x80000000,%%eax\n\
+	movl $5, %%edx \n\
+	jz 1f\n\
+\n\
+	movl $0x80000001,%%eax \n\
+	cpuid \n\
+	andl $0x20000000,%%edx \n\
+	movl $6, %%edx \n\
+	jz 1f \n\
+\n\
+	movl $7, %%edx \n\
+1:" : "=d" (res) : : "eax", "ebx", "ecx" );
+
+	switch (res) {
+	case 3: puts( "386" );
+		break;
+	case 4: puts( "486" );
+		break;
+	case 5: puts( "no extended cpuid" );
+		break;
+	case 6: puts( "non-64bit 586+" );
+		break;
+	case 7: puts( "64bit" );
+		break;
+	default:puts( "internal error" );
+		break;
+	}
+	if (res !=7)
+		error( "Sorry, your CPU is not capable of running 64-bit kernel." );
+}
+
+int decompress_kernel(struct moveparams *mv, void *rmode)
+{
+	real_mode = rmode;
+
+	if (SCREEN_INFO.orig_video_mode == 7) {
+		vidmem = (char *) 0xb0000;
+		vidport = 0x3b4;
+	} else {
+		vidmem = (char *) 0xb8000;
+		vidport = 0x3d4;
+	}
+
+	lines = SCREEN_INFO.orig_video_lines;
+	cols = SCREEN_INFO.orig_video_cols;
+
+	if (free_mem_ptr < 0x100000) setup_normal_output_buffer();
+	else setup_output_buffer_if_we_run_high(mv);
+
+	makecrc();
+	puts("Checking CPU type...");
+	check_cpu();
+	puts(".\nDecompressing Linux...");
+	gunzip();
+	puts("done.\nBooting the kernel.\n");
+	if (high_loaded) close_output_buffer_if_we_run_high(mv);
+	return high_loaded;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/boot/compressed/miscsetup.h linux-2.4.20/arch/x86_64/boot/compressed/miscsetup.h
--- linux-2.4.19/arch/x86_64/boot/compressed/miscsetup.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/boot/compressed/miscsetup.h	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,39 @@
+#define NULL 0
+typedef unsigned int size_t; 
+
+
+struct screen_info {
+	unsigned char  orig_x;			/* 0x00 */
+	unsigned char  orig_y;			/* 0x01 */
+	unsigned short dontuse1;		/* 0x02 -- EXT_MEM_K sits here */
+	unsigned short orig_video_page;		/* 0x04 */
+	unsigned char  orig_video_mode;		/* 0x06 */
+	unsigned char  orig_video_cols;		/* 0x07 */
+	unsigned short unused2;			/* 0x08 */
+	unsigned short orig_video_ega_bx;	/* 0x0a */
+	unsigned short unused3;			/* 0x0c */
+	unsigned char  orig_video_lines;	/* 0x0e */
+	unsigned char  orig_video_isVGA;	/* 0x0f */
+	unsigned short orig_video_points;	/* 0x10 */
+
+	/* VESA graphic mode -- linear frame buffer */
+	unsigned short lfb_width;		/* 0x12 */
+	unsigned short lfb_height;		/* 0x14 */
+	unsigned short lfb_depth;		/* 0x16 */
+	unsigned long  lfb_base;		/* 0x18 */
+	unsigned long  lfb_size;		/* 0x1c */
+	unsigned short dontuse2, dontuse3;	/* 0x20 -- CL_MAGIC and CL_OFFSET here */
+	unsigned short lfb_linelength;		/* 0x24 */
+	unsigned char  red_size;		/* 0x26 */
+	unsigned char  red_pos;			/* 0x27 */
+	unsigned char  green_size;		/* 0x28 */
+	unsigned char  green_pos;		/* 0x29 */
+	unsigned char  blue_size;		/* 0x2a */
+	unsigned char  blue_pos;		/* 0x2b */
+	unsigned char  rsvd_size;		/* 0x2c */
+	unsigned char  rsvd_pos;		/* 0x2d */
+	unsigned short vesapm_seg;		/* 0x2e */
+	unsigned short vesapm_off;		/* 0x30 */
+	unsigned short pages;			/* 0x32 */
+						/* 0x34 -- 0x3f reserved for future expansion */
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/boot/install.sh linux-2.4.20/arch/x86_64/boot/install.sh
--- linux-2.4.19/arch/x86_64/boot/install.sh	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/boot/install.sh	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,39 @@
+#!/bin/sh
+#
+# arch/i386/boot/install.sh
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1995 by Linus Torvalds
+#
+# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
+#
+# "make install" script for i386 architecture
+#
+# Arguments:
+#   $1 - kernel version
+#   $2 - kernel image file
+#   $3 - kernel map file
+#   $4 - default install path (blank if root directory)
+#
+
+# User may have a custom install script
+
+if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi
+
+# Default install - same as make zlilo
+
+if [ -f $4/vmlinuz ]; then
+	mv $4/vmlinuz $4/vmlinuz.old
+fi
+
+if [ -f $4/System.map ]; then
+	mv $4/System.map $4/System.old
+fi
+
+cat $2 > $4/vmlinuz
+cp $3 $4/System.map
+
+if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/boot/setup.S linux-2.4.20/arch/x86_64/boot/setup.S
--- linux-2.4.19/arch/x86_64/boot/setup.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/boot/setup.S	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,863 @@
+/*
+ *	setup.S		Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * setup.s is responsible for getting the system data from the BIOS,
+ * and putting them into the appropriate places in system memory.
+ * both setup.s and system has been loaded by the bootblock.
+ *
+ * This code asks the bios for memory/disk/other parameters, and
+ * puts them in a "safe" place: 0x90000-0x901FF, ie where the
+ * boot-block used to be. It is then up to the protected mode
+ * system to read them from there before the area is overwritten
+ * for buffer-blocks.
+ *
+ * Move PS/2 aux init code to psaux.c
+ * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
+ *
+ * some changes and additional features by Christoph Niemann,
+ * March 1993/June 1994 (Christoph.Niemann@linux.org)
+ *
+ * add APM BIOS checking by Stephen Rothwell, May 1994
+ * (sfr@canb.auug.org.au)
+ *
+ * High load stuff, initrd support and position independency
+ * by Hans Lermen & Werner Almesberger, February 1996
+ * <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
+ *
+ * Video handling moved to video.S by Martin Mares, March 1996
+ * <mj@k332.feld.cvut.cz>
+ *
+ * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
+ * parsons) to avoid loadlin confusion, July 1997
+ *
+ * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
+ * <stiker@northlink.com>
+ *
+ * Fix to work around buggy BIOSes which dont use carry bit correctly
+ * and/or report extended memory in CX/DX for e801h memory size detection 
+ * call.  As a result the kernel got wrong figures.  The int15/e801h docs
+ * from Ralf Brown interrupt list seem to indicate AX/BX should be used
+ * anyway.  So to avoid breaking many machines (presumably there was a reason
+ * to orginally use CX/DX instead of AX/BX), we do a kludge to see
+ * if CX/DX have been changed in the e801 call and if so use AX/BX .
+ * Michael Miller, April 2001 <michaelm@mjmm.org>
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/segment.h>
+#include <linux/version.h>
+#include <linux/compile.h>
+#include <asm/boot.h>
+#include <asm/e820.h>
+
+/* Signature words to ensure LILO loaded us right */
+#define SIG1	0xAA55
+#define SIG2	0x5A5A
+
+INITSEG  = DEF_INITSEG		# 0x9000, we move boot here, out of the way
+SYSSEG   = DEF_SYSSEG		# 0x1000, system loaded at 0x10000 (65536).
+SETUPSEG = DEF_SETUPSEG		# 0x9020, this is the current segment
+				# ... and the former contents of CS
+
+DELTA_INITSEG = SETUPSEG - INITSEG	# 0x0020
+
+.code16
+.globl begtext, begdata, begbss, endtext, enddata, endbss
+
+.text
+begtext:
+.data
+begdata:
+.bss
+begbss:
+.text
+
+start:
+	jmp	trampoline
+
+# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
+
+		.ascii	"HdrS"		# header signature
+		.word	0x0202		# header version number (>= 0x0105)
+					# or else old loadlin-1.5 will fail)
+realmode_swtch:	.word	0, 0		# default_switch, SETUPSEG
+start_sys_seg:	.word	SYSSEG
+		.word	kernel_version	# pointing to kernel version string
+					# above section of header is compatible
+					# with loadlin-1.5 (header v1.5). Don't
+					# change it.
+
+type_of_loader:	.byte	0		# = 0, old one (LILO, Loadlin,
+					#      Bootlin, SYSLX, bootsect...)
+					# See Documentation/i386/boot.txt for
+					# assigned ids
+	
+# flags, unused bits must be zero (RFU) bit within loadflags
+loadflags:
+LOADED_HIGH	= 1			# If set, the kernel is loaded high
+CAN_USE_HEAP	= 0x80			# If set, the loader also has set
+					# heap_end_ptr to tell how much
+					# space behind setup.S can be used for
+					# heap purposes.
+					# Only the loader knows what is free
+#ifndef __BIG_KERNEL__
+		.byte	0
+#else
+		.byte	LOADED_HIGH
+#endif
+
+setup_move_size: .word  0x8000		# size to move, when setup is not
+					# loaded at 0x90000. We will move setup 
+					# to 0x90000 then just before jumping
+					# into the kernel. However, only the
+					# loader knows how much data behind
+					# us also needs to be loaded.
+
+code32_start:				# here loaders can put a different
+					# start address for 32-bit code.
+#ifndef __BIG_KERNEL__
+		.long	0x1000		#   0x1000 = default for zImage
+#else
+		.long	0x100000	# 0x100000 = default for big kernel
+#endif
+
+ramdisk_image:	.long	0		# address of loaded ramdisk image
+					# Here the loader puts the 32-bit
+					# address where it loaded the image.
+					# This only will be read by the kernel.
+
+ramdisk_size:	.long	0		# its size in bytes
+
+bootsect_kludge:
+		.word  bootsect_helper, SETUPSEG
+
+heap_end_ptr:	.word	modelist+1024	# (Header version 0x0201 or later)
+					# space from here (exclusive) down to
+					# end of setup code can be used by setup
+					# for local heap purposes.
+
+pad1:		.word	0
+cmd_line_ptr:	.long 0			# (Header version 0x0202 or later)
+					# If nonzero, a 32-bit pointer
+					# to the kernel command line.
+					# The command line should be
+					# located between the start of
+					# setup and the end of low
+					# memory (0xa0000), or it may
+					# get overwritten before it
+					# gets read.  If this field is
+					# used, there is no longer
+					# anything magical about the
+					# 0x90000 segment; the setup
+					# can be located anywhere in
+					# low memory 0x10000 or higher.
+
+trampoline:	call	start_of_setup
+		.space	1024
+# End of setup header #####################################################
+
+start_of_setup:
+# Bootlin depends on this being done early
+	movw	$0x01500, %ax
+	movb	$0x81, %dl
+	int	$0x13
+
+#ifdef SAFE_RESET_DISK_CONTROLLER
+# Reset the disk controller.
+	movw	$0x0000, %ax
+	movb	$0x80, %dl
+	int	$0x13
+#endif
+
+# Set %ds = %cs, we know that SETUPSEG = %cs at this point
+	movw	%cs, %ax		# aka SETUPSEG
+	movw	%ax, %ds
+# Check signature at end of setup
+	cmpw	$SIG1, setup_sig1
+	jne	bad_sig
+
+	cmpw	$SIG2, setup_sig2
+	jne	bad_sig
+
+	jmp	good_sig1
+
+# Routine to print asciiz string at ds:si
+prtstr:
+	lodsb
+	andb	%al, %al
+	jz	fin
+
+	call	prtchr
+	jmp	prtstr
+
+fin:	ret
+
+# Space printing
+prtsp2:	call	prtspc		# Print double space
+prtspc:	movb	$0x20, %al	# Print single space (note: fall-thru)
+
+# Part of above routine, this one just prints ascii al
+prtchr:	pushw	%ax
+	pushw	%cx
+	xorb	%bh, %bh
+	movw	$0x01, %cx
+	movb	$0x0e, %ah
+	int	$0x10
+	popw	%cx
+	popw	%ax
+	ret
+
+beep:	movb	$0x07, %al
+	jmp	prtchr
+	
+no_sig_mess: .string	"No setup signature found ..."
+
+good_sig1:
+	jmp	good_sig
+
+# We now have to find the rest of the setup code/data
+bad_sig:
+	movw	%cs, %ax			# SETUPSEG
+	subw	$DELTA_INITSEG, %ax		# INITSEG
+	movw	%ax, %ds
+	xorb	%bh, %bh
+	movb	(497), %bl			# get setup sect from bootsect
+	subw	$4, %bx				# LILO loads 4 sectors of setup
+	shlw	$8, %bx				# convert to words (1sect=2^8 words)
+	movw	%bx, %cx
+	shrw	$3, %bx				# convert to segment
+	addw	$SYSSEG, %bx
+	movw	%bx, %cs:start_sys_seg
+# Move rest of setup code/data to here
+	movw	$2048, %di			# four sectors loaded by LILO
+	subw	%si, %si
+	movw	%cs, %ax			# aka SETUPSEG
+	movw	%ax, %es
+	movw	$SYSSEG, %ax
+	movw	%ax, %ds
+	rep
+	movsw
+	movw	%cs, %ax			# aka SETUPSEG
+	movw	%ax, %ds
+	cmpw	$SIG1, setup_sig1
+	jne	no_sig
+
+	cmpw	$SIG2, setup_sig2
+	jne	no_sig
+
+	jmp	good_sig
+
+no_sig:
+	lea	no_sig_mess, %si
+	call	prtstr
+
+no_sig_loop:
+	jmp	no_sig_loop
+
+good_sig:
+	movw	%cs, %ax			# aka SETUPSEG
+	subw	$DELTA_INITSEG, %ax 		# aka INITSEG
+	movw	%ax, %ds
+# Check if an old loader tries to load a big-kernel
+	testb	$LOADED_HIGH, %cs:loadflags	# Do we have a big kernel?
+	jz	loader_ok			# No, no danger for old loaders.
+
+	cmpb	$0, %cs:type_of_loader 		# Do we have a loader that
+						# can deal with us?
+	jnz	loader_ok			# Yes, continue.
+
+	pushw	%cs				# No, we have an old loader,
+	popw	%ds				# die. 
+	lea	loader_panic_mess, %si
+	call	prtstr
+
+	jmp	no_sig_loop
+
+loader_panic_mess: .string "Wrong loader, giving up..."
+
+loader_ok:
+# Get memory size (extended mem, kB)
+
+	xorl	%eax, %eax
+	movl	%eax, (0x1e0)
+#ifndef STANDARD_MEMORY_BIOS_CALL
+	movb	%al, (E820NR)
+# Try three different memory detection schemes.  First, try
+# e820h, which lets us assemble a memory map, then try e801h,
+# which returns a 32-bit memory size, and finally 88h, which
+# returns 0-64m
+
+# method E820H:
+# the memory map from hell.  e820h returns memory classified into
+# a whole bunch of different types, and allows memory holes and
+# everything.  We scan through this memory map and build a list
+# of the first 32 memory areas, which we return at [E820MAP].
+# This is documented at http://www.teleport.com/~acpi/acpihtml/topic245.htm
+
+#define SMAP  0x534d4150
+
+meme820:
+	xorl	%ebx, %ebx			# continuation counter
+	movw	$E820MAP, %di			# point into the whitelist
+						# so we can have the bios
+						# directly write into it.
+
+jmpe820:
+	movl	$0x0000e820, %eax		# e820, upper word zeroed
+	movl	$SMAP, %edx			# ascii 'SMAP'
+	movl	$20, %ecx			# size of the e820rec
+	pushw	%ds				# data record.
+	popw	%es
+	int	$0x15				# make the call
+	jc	bail820				# fall to e801 if it fails
+
+	cmpl	$SMAP, %eax			# check the return is `SMAP'
+	jne	bail820				# fall to e801 if it fails
+
+#	cmpl	$1, 16(%di)			# is this usable memory?
+#	jne	again820
+
+	# If this is usable memory, we save it by simply advancing %di by
+	# sizeof(e820rec).
+	#
+good820:
+	movb	(E820NR), %al			# up to 32 entries
+	cmpb	$E820MAX, %al
+	jnl	bail820
+
+	incb	(E820NR)
+	movw	%di, %ax
+	addw	$20, %ax
+	movw	%ax, %di
+again820:
+	cmpl	$0, %ebx			# check to see if
+	jne	jmpe820				# %ebx is set to EOF
+bail820:
+
+
+# method E801H:
+# memory size is in 1k chunksizes, to avoid confusing loadlin.
+# we store the 0xe801 memory size in a completely different place,
+# because it will most likely be longer than 16 bits.
+# (use 1e0 because that's what Larry Augustine uses in his
+# alternative new memory detection scheme, and it's sensible
+# to write everything into the same place.)
+
+meme801:
+	stc					# fix to work around buggy
+	xorw	%cx,%cx				# BIOSes which dont clear/set
+	xorw	%dx,%dx				# carry on pass/error of
+						# e801h memory size call
+						# or merely pass cx,dx though
+						# without changing them.
+	movw	$0xe801, %ax
+	int	$0x15
+	jc	mem88
+
+	cmpw	$0x0, %cx			# Kludge to handle BIOSes
+	jne	e801usecxdx			# which report their extended
+	cmpw	$0x0, %dx			# memory in AX/BX rather than
+	jne	e801usecxdx			# CX/DX.  The spec I have read
+	movw	%ax, %cx			# seems to indicate AX/BX 
+	movw	%bx, %dx			# are more reasonable anyway...
+
+e801usecxdx:
+	andl	$0xffff, %edx			# clear sign extend
+	shll	$6, %edx			# and go from 64k to 1k chunks
+	movl	%edx, (0x1e0)			# store extended memory size
+	andl	$0xffff, %ecx			# clear sign extend
+ 	addl	%ecx, (0x1e0)			# and add lower memory into
+						# total size.
+
+# Ye Olde Traditional Methode.  Returns the memory size (up to 16mb or
+# 64mb, depending on the bios) in ax.
+mem88:
+
+#endif
+	movb	$0x88, %ah
+	int	$0x15
+	movw	%ax, (2)
+
+# Set the keyboard repeat rate to the max
+	movw	$0x0305, %ax
+	xorw	%bx, %bx
+	int	$0x16
+
+# Check for video adapter and its parameters and allow the
+# user to browse video modes.
+	call	video				# NOTE: we need %ds pointing
+						# to bootsector
+
+# Get hd0 data...
+	xorw	%ax, %ax
+	movw	%ax, %ds
+	ldsw	(4 * 0x41), %si
+	movw	%cs, %ax			# aka SETUPSEG
+	subw	$DELTA_INITSEG, %ax		# aka INITSEG
+	pushw	%ax
+	movw	%ax, %es
+	movw	$0x0080, %di
+	movw	$0x10, %cx
+	pushw	%cx
+	cld
+	rep
+ 	movsb
+# Get hd1 data...
+	xorw	%ax, %ax
+	movw	%ax, %ds
+	ldsw	(4 * 0x46), %si
+	popw	%cx
+	popw	%es
+	movw	$0x0090, %di
+	rep
+	movsb
+# Check that there IS a hd1 :-)
+	movw	$0x01500, %ax
+	movb	$0x81, %dl
+	int	$0x13
+	jc	no_disk1
+	
+	cmpb	$3, %ah
+	je	is_disk1
+
+no_disk1:
+	movw	%cs, %ax			# aka SETUPSEG
+	subw	$DELTA_INITSEG, %ax 		# aka INITSEG
+	movw	%ax, %es
+	movw	$0x0090, %di
+	movw	$0x10, %cx
+	xorw	%ax, %ax
+	cld
+	rep
+	stosb
+is_disk1:
+
+# Check for PS/2 pointing device
+	movw	%cs, %ax			# aka SETUPSEG
+	subw	$DELTA_INITSEG, %ax		# aka INITSEG
+	movw	%ax, %ds
+	movw	$0, (0x1ff)			# default is no pointing device
+	int	$0x11				# int 0x11: equipment list
+	testb	$0x04, %al			# check if mouse installed
+	jz	no_psmouse
+
+	movw	$0xAA, (0x1ff)			# device present
+no_psmouse:
+
+# Now we want to move to protected mode ...
+	cmpw	$0, %cs:realmode_swtch
+	jz	rmodeswtch_normal
+
+	lcall	%cs:realmode_swtch
+
+	jmp	rmodeswtch_end
+
+rmodeswtch_normal:
+        pushw	%cs
+	call	default_switch
+
+rmodeswtch_end:
+# we get the code32 start address and modify the below 'jmpi'
+# (loader may have changed it)
+	movl	%cs:code32_start, %eax
+	movl	%eax, %cs:code32
+
+# Now we move the system to its rightful place ... but we check if we have a
+# big-kernel. In that case we *must* not move it ...
+	testb	$LOADED_HIGH, %cs:loadflags
+	jz	do_move0			# .. then we have a normal low
+						# loaded zImage
+						# .. or else we have a high
+						# loaded bzImage
+	jmp	end_move			# ... and we skip moving
+
+do_move0:
+	movw	$0x100, %ax			# start of destination segment
+	movw	%cs, %bp			# aka SETUPSEG
+	subw	$DELTA_INITSEG, %bp		# aka INITSEG
+	movw	%cs:start_sys_seg, %bx		# start of source segment
+	cld
+do_move:
+	movw	%ax, %es			# destination segment
+	incb	%ah				# instead of add ax,#0x100
+	movw	%bx, %ds			# source segment
+	addw	$0x100, %bx
+	subw	%di, %di
+	subw	%si, %si
+	movw 	$0x800, %cx
+	rep
+	movsw
+	cmpw	%bp, %bx			# assume start_sys_seg > 0x200,
+						# so we will perhaps read one
+						# page more than needed, but
+						# never overwrite INITSEG
+						# because destination is a
+						# minimum one page below source
+	jb	do_move
+
+end_move:
+# then we load the segment descriptors
+	movw	%cs, %ax			# aka SETUPSEG
+	movw	%ax, %ds
+		
+# Check whether we need to be downward compatible with version <=201
+	cmpl	$0, cmd_line_ptr
+	jne	end_move_self		# loader uses version >=202 features
+	cmpb	$0x20, type_of_loader
+	je	end_move_self		# bootsect loader, we know of it
+
+# Boot loader doesnt support boot protocol version 2.02.
+# If we have our code not at 0x90000, we need to move it there now.
+# We also then need to move the params behind it (commandline)
+# Because we would overwrite the code on the current IP, we move
+# it in two steps, jumping high after the first one.
+	movw	%cs, %ax
+	cmpw	$SETUPSEG, %ax
+	je	end_move_self
+
+	cli					# make sure we really have
+						# interrupts disabled !
+						# because after this the stack
+						# should not be used
+	subw	$DELTA_INITSEG, %ax		# aka INITSEG
+	movw	%ss, %dx
+	cmpw	%ax, %dx
+	jb	move_self_1
+
+	addw	$INITSEG, %dx
+	subw	%ax, %dx			# this will go into %ss after
+						# the move
+move_self_1:
+	movw	%ax, %ds
+	movw	$INITSEG, %ax			# real INITSEG
+	movw	%ax, %es
+	movw	%cs:setup_move_size, %cx
+	std					# we have to move up, so we use
+						# direction down because the
+						# areas may overlap
+	movw	%cx, %di
+	decw	%di
+	movw	%di, %si
+	subw	$move_self_here+0x200, %cx
+	rep
+	movsb
+	ljmp	$SETUPSEG, $move_self_here
+
+move_self_here:
+	movw	$move_self_here+0x200, %cx
+	rep
+	movsb
+	movw	$SETUPSEG, %ax
+	movw	%ax, %ds
+	movw	%dx, %ss
+end_move_self:					# now we are at the right place
+	lidt	idt_48				# load idt with 0,0
+	xorl	%eax, %eax			# Compute gdt_base
+	movw	%ds, %ax			# (Convert %ds:gdt to a linear ptr)
+	shll	$4, %eax
+	addl	$gdt, %eax
+	movl	%eax, (gdt_48+2)
+	lgdt	gdt_48				# load gdt with whatever is
+						# appropriate
+
+# that was painless, now we enable a20
+	call	empty_8042
+
+	movb	$0xD1, %al			# command write
+	outb	%al, $0x64
+	call	empty_8042
+
+	movb	$0xDF, %al			# A20 on
+	outb	%al, $0x60
+	call	empty_8042
+
+#
+#	You must preserve the other bits here. Otherwise embarrasing things
+#	like laptops powering off on boot happen. Corrected version by Kira
+#	Brown from Linux 2.2
+#
+	inb	$0x92, %al			# 
+	orb	$02, %al			# "fast A20" version
+	outb	%al, $0x92			# some chips have only this
+
+# wait until a20 really *is* enabled; it can take a fair amount of
+# time on certain systems; Toshiba Tecras are known to have this
+# problem.  The memory location used here (0x200) is the int 0x80
+# vector, which should be safe to use.
+
+	xorw	%ax, %ax			# segment 0x0000
+	movw	%ax, %fs
+	decw	%ax				# segment 0xffff (HMA)
+	movw	%ax, %gs
+a20_wait:
+	incw	%ax				# unused memory location <0xfff0
+	movw	%ax, %fs:(0x200)		# we use the "int 0x80" vector
+	cmpw	%gs:(0x210), %ax		# and its corresponding HMA addr
+	je	a20_wait			# loop until no longer aliased
+
+# make sure any possible coprocessor is properly reset..
+	xorw	%ax, %ax
+	outb	%al, $0xf0
+	call	delay
+
+	outb	%al, $0xf1
+	call	delay
+
+# well, that went ok, I hope. Now we mask all interrupts - the rest
+# is done in init_IRQ().
+	movb	$0xFF, %al			# mask all interrupts for now
+	outb	%al, $0xA1
+	call	delay
+	
+	movb	$0xFB, %al			# mask all irq's but irq2 which
+	outb	%al, $0x21			# is cascaded
+
+# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't
+# need no steenking BIOS anyway (except for the initial loading :-).
+# The BIOS-routine wants lots of unnecessary data, and it's less
+# "interesting" anyway. This is how REAL programmers do it.
+#
+# Well, now's the time to actually move into protected mode. To make
+# things as simple as possible, we do no register set-up or anything,
+# we let the gnu-compiled 32-bit programs do that. We just jump to
+# absolute address 0x1000 (or the loader supplied one),
+# in 32-bit protected mode.
+#
+# Note that the short jump isn't strictly needed, although there are
+# reasons why it might be a good idea. It won't hurt in any case.
+	movw	$1, %ax				# protected mode (PE) bit
+	lmsw	%ax				# This is it!
+	jmp	flush_instr
+
+flush_instr:
+	xorw	%bx, %bx			# Flag to indicate a boot
+	xorl	%esi, %esi			# Pointer to real-mode code
+	movw	%cs, %si
+	subw	$DELTA_INITSEG, %si
+	shll	$4, %esi			# Convert to 32-bit pointer
+# NOTE: For high loaded big kernels we need a
+#	jmpi    0x100000,__KERNEL_CS
+#
+#	but we yet haven't reloaded the CS register, so the default size 
+#	of the target offset still is 16 bit.
+#       However, using an operand prefix (0x66), the CPU will properly
+#	take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
+#	Manual, Mixing 16-bit and 32-bit code, page 16-6)
+
+	.byte 0x66, 0xea			# prefix + jmpi-opcode
+code32:	.long	0x1000				# will be set to 0x100000
+						# for big kernels
+	.word	__KERNEL_CS
+
+# Here's a bunch of information about your current kernel..
+kernel_version:	.ascii	UTS_RELEASE
+		.ascii	" ("
+		.ascii	LINUX_COMPILE_BY
+		.ascii	"@"
+		.ascii	LINUX_COMPILE_HOST
+		.ascii	") "
+		.ascii	UTS_VERSION
+		.byte	0
+
+# This is the default real mode switch routine.
+# to be called just before protected mode transition
+default_switch:
+	cli					# no interrupts allowed !
+	movb	$0x80, %al			# disable NMI for bootup
+						# sequence
+	outb	%al, $0x70
+	lret
+
+# This routine only gets called, if we get loaded by the simple
+# bootsect loader _and_ have a bzImage to load.
+# Because there is no place left in the 512 bytes of the boot sector,
+# we must emigrate to code space here.
+bootsect_helper:
+	cmpw	$0, %cs:bootsect_es
+	jnz	bootsect_second
+
+	movb	$0x20, %cs:type_of_loader
+	movw	%es, %ax
+	shrw	$4, %ax
+	movb	%ah, %cs:bootsect_src_base+2
+	movw	%es, %ax
+	movw	%ax, %cs:bootsect_es
+	subw	$SYSSEG, %ax
+	lret					# nothing else to do for now
+
+bootsect_second:
+	pushw	%cx
+	pushw	%si
+	pushw	%bx
+	testw	%bx, %bx			# 64K full?
+	jne	bootsect_ex
+
+	movw	$0x8000, %cx			# full 64K, INT15 moves words
+	pushw	%cs
+	popw	%es
+	movw	$bootsect_gdt, %si
+	movw	$0x8700, %ax
+	int	$0x15
+	jc	bootsect_panic			# this, if INT15 fails
+
+	movw	%cs:bootsect_es, %es		# we reset %es to always point
+	incb	%cs:bootsect_dst_base+2		# to 0x10000
+bootsect_ex:
+	movb	%cs:bootsect_dst_base+2, %ah
+	shlb	$4, %ah				# we now have the number of
+						# moved frames in %ax
+	xorb	%al, %al
+	popw	%bx
+	popw	%si
+	popw	%cx
+	lret
+
+bootsect_gdt:
+	.word	0, 0, 0, 0
+	.word	0, 0, 0, 0
+
+bootsect_src:
+	.word	0xffff
+
+bootsect_src_base:
+	.byte	0x00, 0x00, 0x01		# base = 0x010000
+	.byte	0x93				# typbyte
+	.word	0				# limit16,base24 =0
+
+bootsect_dst:
+	.word	0xffff
+
+bootsect_dst_base:
+	.byte	0x00, 0x00, 0x10		# base = 0x100000
+	.byte	0x93				# typbyte
+	.word	0				# limit16,base24 =0
+	.word	0, 0, 0, 0			# BIOS CS
+	.word	0, 0, 0, 0			# BIOS DS
+
+bootsect_es:
+	.word	0
+
+bootsect_panic:
+	pushw	%cs
+	popw	%ds
+	cld
+	leaw	bootsect_panic_mess, %si
+	call	prtstr
+	
+bootsect_panic_loop:
+	jmp	bootsect_panic_loop
+
+bootsect_panic_mess:
+	.string	"INT15 refuses to access high mem, giving up."
+
+# This routine checks that the keyboard command queue is empty
+# (after emptying the output buffers)
+#
+# Some machines have delusions that the keyboard buffer is always full
+# with no keyboard attached...
+#
+# If there is no keyboard controller, we will usually get 0xff
+# to all the reads.  With each IO taking a microsecond and
+# a timeout of 100,000 iterations, this can take about half a
+# second ("delay" == outb to port 0x80). That should be ok,
+# and should also be plenty of time for a real keyboard controller
+# to empty.
+#
+
+empty_8042:
+	pushl	%ecx
+	movl	$100000, %ecx
+
+empty_8042_loop:
+	decl	%ecx
+	jz	empty_8042_end_loop
+
+	call	delay
+
+	inb	$0x64, %al			# 8042 status port
+	testb	$1, %al				# output buffer?
+	jz	no_output
+
+	call	delay
+	inb	$0x60, %al			# read it
+	jmp	empty_8042_loop
+
+no_output:
+	testb	$2, %al				# is input buffer full?
+	jnz	empty_8042_loop			# yes - loop
+empty_8042_end_loop:
+	popl	%ecx
+	ret
+
+# Read the cmos clock. Return the seconds in al
+gettime:
+	pushw	%cx
+	movb	$0x02, %ah
+	int	$0x1a
+	movb	%dh, %al			# %dh contains the seconds
+	andb	$0x0f, %al
+	movb	%dh, %ah
+	movb	$0x04, %cl
+	shrb	%cl, %ah
+	aad
+	popw	%cx
+	ret
+
+# Delay is needed after doing I/O
+delay:
+	outb	%al,$0x80
+	ret
+
+# Descriptor tables
+gdt:
+	.word	0, 0, 0, 0			# dummy
+
+	.word	0, 0, 0, 0			# unused
+
+	.word	0xFFFF				# 4Gb - (0x100000*0x1000 = 4Gb)
+	.word	0				# base address = 0
+	.word	0x9A00				# code read/exec
+	.word	0x00CF				# granularity = 4096, 386
+						#  (+5th nibble of limit)
+
+	.word	0xFFFF				# 4Gb - (0x100000*0x1000 = 4Gb)
+	.word	0				# base address = 0
+	.word	0x9200				# data read/write
+	.word	0x00CF				# granularity = 4096, 386
+						#  (+5th nibble of limit)
+# this is 64bit descriptor for code
+	.word	0xFFFF
+	.word	0
+	.word	0x9A00				# code read/exec
+	.word	0x00AF				# as above, but it is long mode and with D=0
+						# it does not seem to do the trick.
+
+idt_48:
+	.word	0				# idt limit = 0
+	.word	0, 0				# idt base = 0L
+gdt_48:
+	.word	0x8000				# gdt limit=2048,
+						#  256 GDT entries
+
+	.word	0, 0				# gdt base (filled in later)
+
+# Include video setup & detection code
+
+#include "video.S"
+
+# Setup signature -- must be last
+setup_sig1:	.word	SIG1
+setup_sig2:	.word	SIG2
+
+# After this point, there is some free space which is used by the video mode
+# handling code to store the temporary mode table (not used by the kernel).
+
+modelist:
+
+.text
+endtext:
+.data
+enddata:
+.bss
+endbss:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/boot/tools/build.c linux-2.4.20/arch/x86_64/boot/tools/build.c
--- linux-2.4.19/arch/x86_64/boot/tools/build.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/boot/tools/build.c	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,189 @@
+/*
+ *  $Id: build.c,v 1.3 2001/06/26 15:14:50 pavel Exp $
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1997 Martin Mares
+ */
+
+/*
+ * This file builds a disk-image from three different files:
+ *
+ * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest
+ * - setup: 8086 machine code, sets up system parm
+ * - system: 80386 code for actual system
+ *
+ * It does some checking that all files are of the correct type, and
+ * just writes the result to stdout, removing headers and padding to
+ * the right amount. It also writes some system data to stderr.
+ */
+
+/*
+ * Changes by tytso to allow root device specification
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+ * Cross compiling fixes by Gertjan van Wingerde, July 1996
+ * Rewritten by Martin Mares, April 1997
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <asm/boot.h>
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned long u32;
+
+#define DEFAULT_MAJOR_ROOT 0
+#define DEFAULT_MINOR_ROOT 0
+
+/* Minimal number of setup sectors (see also bootsect.S) */
+#define SETUP_SECTS 4
+
+byte buf[1024];
+int fd;
+int is_big_kernel;
+
+void die(const char * str, ...)
+{
+	va_list args;
+	va_start(args, str);
+	vfprintf(stderr, str, args);
+	fputc('\n', stderr);
+	exit(1);
+}
+
+void file_open(const char *name)
+{
+	if ((fd = open(name, O_RDONLY, 0)) < 0)
+		die("Unable to open `%s': %m", name);
+}
+
+void usage(void)
+{
+	die("Usage: build [-b] bootsect setup system [rootdev] [> image]");
+}
+
+int main(int argc, char ** argv)
+{
+	unsigned int i, c, sz, setup_sectors;
+	u32 sys_size;
+	byte major_root, minor_root;
+	struct stat sb;
+
+	if (argc > 2 && !strcmp(argv[1], "-b"))
+	  {
+	    is_big_kernel = 1;
+	    argc--, argv++;
+	  }
+	if ((argc < 4) || (argc > 5))
+		usage();
+	if (argc > 4) {
+		if (!strcmp(argv[4], "CURRENT")) {
+			if (stat("/", &sb)) {
+				perror("/");
+				die("Couldn't stat /");
+			}
+			major_root = major(sb.st_dev);
+			minor_root = minor(sb.st_dev);
+		} else if (strcmp(argv[4], "FLOPPY")) {
+			if (stat(argv[4], &sb)) {
+				perror(argv[4]);
+				die("Couldn't stat root device.");
+			}
+			major_root = major(sb.st_rdev);
+			minor_root = minor(sb.st_rdev);
+		} else {
+			major_root = 0;
+			minor_root = 0;
+		}
+	} else {
+		major_root = DEFAULT_MAJOR_ROOT;
+		minor_root = DEFAULT_MINOR_ROOT;
+	}
+	fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
+
+	file_open(argv[1]);
+	i = read(fd, buf, sizeof(buf));
+	fprintf(stderr,"Boot sector %d bytes.\n",i);
+	if (i != 512)
+		die("Boot block must be exactly 512 bytes");
+	if (buf[510] != 0x55 || buf[511] != 0xaa)
+		die("Boot block hasn't got boot flag (0xAA55)");
+	buf[508] = minor_root;
+	buf[509] = major_root;
+	if (write(1, buf, 512) != 512)
+		die("Write call failed");
+	close (fd);
+
+	file_open(argv[2]);				    /* Copy the setup code */
+	for (i=0 ; (c=read(fd, buf, sizeof(buf)))>0 ; i+=c )
+		if (write(1, buf, c) != c)
+			die("Write call failed");
+	if (c != 0)
+		die("read-error on `setup'");
+	close (fd);
+
+	setup_sectors = (i + 511) / 512;	/* Pad unused space with zeros */
+	/* for compatibility with ancient versions of LILO. */
+	if (setup_sectors < SETUP_SECTS)
+		setup_sectors = SETUP_SECTS;
+	fprintf(stderr, "Setup is %d bytes.\n", i);
+	memset(buf, 0, sizeof(buf));
+	while (i < setup_sectors * 512) {
+		c = setup_sectors * 512 - i;
+		if (c > sizeof(buf))
+			c = sizeof(buf);
+		if (write(1, buf, c) != c)
+			die("Write call failed");
+		i += c;
+	}
+
+	file_open(argv[3]);
+	if (fstat (fd, &sb))
+		die("Unable to stat `%s': %m", argv[3]);
+	sz = sb.st_size;
+	fprintf (stderr, "System is %d kB\n", sz/1024);
+	sys_size = (sz + 15) / 16;
+	/* 0x28000*16 = 2.5 MB, conservative estimate for the current maximum */
+	if (sys_size > (is_big_kernel ? 0x28000 : DEF_SYSSIZE))
+		die("System is too big. Try using %smodules.",
+			is_big_kernel ? "" : "bzImage or ");
+	if (sys_size > 0xefff)
+		fprintf(stderr,"warning: kernel is too big for standalone boot "
+		    "from floppy\n");
+	while (sz > 0) {
+		int l, n;
+
+		l = (sz > sizeof(buf)) ? sizeof(buf) : sz;
+		if ((n=read(fd, buf, l)) != l) {
+			if (n < 0)
+				die("Error reading %s: %m", argv[3]);
+			else
+				die("%s: Unexpected EOF", argv[3]);
+		}
+		if (write(1, buf, l) != l)
+			die("Write failed");
+		sz -= l;
+	}
+	close(fd);
+
+	if (lseek(1, 497, SEEK_SET) != 497)		    /* Write sizes to the bootsector */
+		die("Output: seek failed");
+	buf[0] = setup_sectors;
+	if (write(1, buf, 1) != 1)
+		die("Write of setup sector count failed");
+	if (lseek(1, 500, SEEK_SET) != 500)
+		die("Output: seek failed");
+	buf[0] = (sys_size & 0xff);
+	buf[1] = ((sys_size >> 8) & 0xff);
+	if (write(1, buf, 2) != 2)
+		die("Write of image length failed");
+
+	return 0;					    /* Everything is OK */
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/boot/video.S linux-2.4.20/arch/x86_64/boot/video.S
--- linux-2.4.19/arch/x86_64/boot/video.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/boot/video.S	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,1921 @@
+/*	video.S
+ *
+ *	Display adapter & video mode setup, version 2.13 (14-May-99)
+ *
+ *	Copyright (C) 1995 -- 1998 Martin Mares <mj@ucw.cz>
+ *	Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
+ *
+ *	Rewritten to use GNU 'as' by Chris Noe <stiker@northlink.com> May 1999
+ *
+ *	For further information, look at Documentation/svga.txt.
+ *
+ */
+
+#include <linux/config.h> /* for CONFIG_VIDEO_* */
+
+/* Enable autodetection of SVGA adapters and modes. */
+#undef CONFIG_VIDEO_SVGA
+
+/* Enable autodetection of VESA modes */
+#define CONFIG_VIDEO_VESA
+
+/* Enable compacting of mode table */
+#define CONFIG_VIDEO_COMPACT
+
+/* Retain screen contents when switching modes */
+#define CONFIG_VIDEO_RETAIN
+
+/* Enable local mode list */
+#undef CONFIG_VIDEO_LOCAL
+
+/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
+#undef CONFIG_VIDEO_400_HACK
+
+/* Hack that lets you force specific BIOS mode ID and specific dimensions */
+#undef CONFIG_VIDEO_GFX_HACK
+#define VIDEO_GFX_BIOS_AX 0x4f02	/* 800x600 on ThinkPad */
+#define VIDEO_GFX_BIOS_BX 0x0102
+#define VIDEO_GFX_DUMMY_RESOLUTION 0x6425	/* 100x37 */
+
+/* This code uses an extended set of video mode numbers. These include:
+ * Aliases for standard modes
+ *	NORMAL_VGA (-1)
+ *	EXTENDED_VGA (-2)
+ *	ASK_VGA (-3)
+ * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
+ * of compatibility when extending the table. These are between 0x00 and 0xff.
+ */
+#define VIDEO_FIRST_MENU 0x0000
+
+/* Standard BIOS video modes (BIOS number + 0x0100) */
+#define VIDEO_FIRST_BIOS 0x0100
+
+/* VESA BIOS video modes (VESA number + 0x0200) */
+#define VIDEO_FIRST_VESA 0x0200
+
+/* Video7 special modes (BIOS number + 0x0900) */
+#define VIDEO_FIRST_V7 0x0900
+
+/* Special video modes */
+#define VIDEO_FIRST_SPECIAL 0x0f00
+#define VIDEO_80x25 0x0f00
+#define VIDEO_8POINT 0x0f01
+#define VIDEO_80x43 0x0f02
+#define VIDEO_80x28 0x0f03
+#define VIDEO_CURRENT_MODE 0x0f04
+#define VIDEO_80x30 0x0f05
+#define VIDEO_80x34 0x0f06
+#define VIDEO_80x60 0x0f07
+#define VIDEO_LAST_SPECIAL 0x0f09
+
+/* Video modes given by resolution */
+#define VIDEO_FIRST_RESOLUTION 0x1000
+
+/* The "recalculate timings" flag */
+#define VIDEO_RECALC 0x8000
+
+/* Positions of various video parameters passed to the kernel */
+/* (see also include/linux/tty.h) */
+#define PARAM_CURSOR_POS	0x00
+#define PARAM_VIDEO_PAGE	0x04
+#define PARAM_VIDEO_MODE	0x06
+#define PARAM_VIDEO_COLS	0x07
+#define PARAM_VIDEO_EGA_BX	0x0a
+#define PARAM_VIDEO_LINES	0x0e
+#define PARAM_HAVE_VGA		0x0f
+#define PARAM_FONT_POINTS	0x10
+
+#define PARAM_LFB_WIDTH		0x12
+#define PARAM_LFB_HEIGHT	0x14
+#define PARAM_LFB_DEPTH		0x16
+#define PARAM_LFB_BASE		0x18
+#define PARAM_LFB_SIZE		0x1c
+#define PARAM_LFB_LINELENGTH	0x24
+#define PARAM_LFB_COLORS	0x26
+#define PARAM_VESAPM_SEG	0x2e
+#define PARAM_VESAPM_OFF	0x30
+#define PARAM_LFB_PAGES		0x32
+
+
+/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
+#ifdef CONFIG_VIDEO_RETAIN
+#define DO_STORE call store_screen
+#else
+#define DO_STORE
+#endif /* CONFIG_VIDEO_RETAIN */
+
+# This is the main entry point called by setup.S
+# %ds *must* be pointing to the bootsector
+video:	pushw	%ds		# We use different segments
+	pushw	%ds		# FS contains original DS
+	popw	%fs
+	pushw	%cs		# DS is equal to CS
+	popw	%ds
+	pushw	%cs		# ES is equal to CS
+	popw	%es
+	xorw	%ax, %ax
+	movw	%ax, %gs	# GS is zero
+	cld
+	call	basic_detect	# Basic adapter type testing (EGA/VGA/MDA/CGA)
+#ifdef CONFIG_VIDEO_SELECT
+	movw	%fs:(0x01fa), %ax		# User selected video mode
+	cmpw	$ASK_VGA, %ax			# Bring up the menu
+	jz	vid2
+
+	call	mode_set			# Set the mode
+	jc	vid1
+
+	leaw	badmdt, %si			# Invalid mode ID
+	call	prtstr
+vid2:	call	mode_menu
+vid1:
+#ifdef CONFIG_VIDEO_RETAIN
+	call	restore_screen			# Restore screen contents
+#endif /* CONFIG_VIDEO_RETAIN */
+#endif /* CONFIG_VIDEO_SELECT */
+	call	mode_params			# Store mode parameters
+	popw	%ds				# Restore original DS
+	ret
+
+# Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
+basic_detect:
+	movb	$0, %fs:(PARAM_HAVE_VGA)
+	movb	$0x12, %ah	# Check EGA/VGA
+	movb	$0x10, %bl
+	int	$0x10
+	movw	%bx, %fs:(PARAM_VIDEO_EGA_BX)	# Identifies EGA to the kernel
+	cmpb	$0x10, %bl			# No, it's a CGA/MDA/HGA card.
+	je	basret
+
+	incb	adapter
+	movw	$0x1a00, %ax			# Check EGA or VGA?
+	int	$0x10
+	cmpb	$0x1a, %al			# 1a means VGA...
+	jne	basret				# anything else is EGA.
+	
+	incb	%fs:(PARAM_HAVE_VGA)		# We've detected a VGA
+	incb	adapter
+basret:	ret
+
+# Store the video mode parameters for later usage by the kernel.
+# This is done by asking the BIOS except for the rows/columns
+# parameters in the default 80x25 mode -- these are set directly,
+# because some very obscure BIOSes supply insane values.
+mode_params:
+#ifdef CONFIG_VIDEO_SELECT
+	cmpb	$0, graphic_mode
+	jnz	mopar_gr
+#endif
+	movb	$0x03, %ah			# Read cursor position
+	xorb	%bh, %bh
+	int	$0x10
+	movw	%dx, %fs:(PARAM_CURSOR_POS)
+	movb	$0x0f, %ah			# Read page/mode/width
+	int	$0x10
+	movw	%bx, %fs:(PARAM_VIDEO_PAGE)
+	movw	%ax, %fs:(PARAM_VIDEO_MODE)	# Video mode and screen width
+	cmpb	$0x7, %al			# MDA/HGA => segment differs
+	jnz	mopar0
+
+	movw	$0xb000, video_segment
+mopar0: movw	%gs:(0x485), %ax		# Font size
+	movw	%ax, %fs:(PARAM_FONT_POINTS)	# (valid only on EGA/VGA)
+	movw	force_size, %ax			# Forced size?
+	orw	%ax, %ax
+	jz	mopar1
+
+	movb	%ah, %fs:(PARAM_VIDEO_COLS)
+	movb	%al, %fs:(PARAM_VIDEO_LINES)
+	ret
+
+mopar1:	movb	$25, %al
+	cmpb	$0, adapter			# If we are on CGA/MDA/HGA, the
+	jz	mopar2				# screen must have 25 lines.
+
+	movb	%gs:(0x484), %al		# On EGA/VGA, use the EGA+ BIOS
+	incb	%al				# location of max lines.
+mopar2: movb	%al, %fs:(PARAM_VIDEO_LINES)
+	ret
+
+#ifdef CONFIG_VIDEO_SELECT
+# Fetching of VESA frame buffer parameters
+mopar_gr:
+	leaw	modelist+1024, %di
+	movb	$0x23, %fs:(PARAM_HAVE_VGA)
+	movw	16(%di), %ax
+	movw	%ax, %fs:(PARAM_LFB_LINELENGTH)
+	movw	18(%di), %ax
+	movw	%ax, %fs:(PARAM_LFB_WIDTH)
+	movw	20(%di), %ax
+	movw	%ax, %fs:(PARAM_LFB_HEIGHT)
+	movb	25(%di), %al
+	movb	$0, %ah
+	movw	%ax, %fs:(PARAM_LFB_DEPTH)
+	movb	29(%di), %al	
+	movb	$0, %ah
+	movw	%ax, %fs:(PARAM_LFB_PAGES)
+	movl	40(%di), %eax
+	movl	%eax, %fs:(PARAM_LFB_BASE)
+	movl	31(%di), %eax
+	movl	%eax, %fs:(PARAM_LFB_COLORS)
+	movl	35(%di), %eax
+	movl	%eax, %fs:(PARAM_LFB_COLORS+4)
+
+# get video mem size
+	leaw	modelist+1024, %di
+	movw	$0x4f00, %ax
+	int	$0x10
+	xorl	%eax, %eax
+	movw	18(%di), %ax
+	movl	%eax, %fs:(PARAM_LFB_SIZE)
+# get protected mode interface informations
+	movw	$0x4f0a, %ax
+	xorw	%bx, %bx
+	xorw	%di, %di
+	int	$0x10
+	cmp	$0x004f, %ax
+	jnz	no_pm
+
+	movw	%es, %fs:(PARAM_VESAPM_SEG)
+	movw	%di, %fs:(PARAM_VESAPM_OFF)
+no_pm:	ret
+
+# The video mode menu
+mode_menu:
+	leaw	keymsg, %si			# "Return/Space/Timeout" message
+	call	prtstr
+	call	flush
+nokey:	call	getkt
+
+	cmpb	$0x0d, %al			# ENTER ?
+	je	listm				# yes - manual mode selection
+
+	cmpb	$0x20, %al			# SPACE ?
+	je	defmd1				# no - repeat
+
+	call 	beep
+	jmp	nokey
+
+defmd1:	ret					# No mode chosen? Default 80x25
+
+listm:	call	mode_table			# List mode table
+listm0:	leaw	name_bann, %si			# Print adapter name
+	call	prtstr
+	movw	card_name, %si
+	orw	%si, %si
+	jnz	an2
+
+	movb	adapter, %al
+	leaw	old_name, %si
+	orb	%al, %al
+	jz	an1
+
+	leaw	ega_name, %si
+	decb	%al
+	jz	an1
+
+	leaw	vga_name, %si
+	jmp	an1
+
+an2:	call	prtstr
+	leaw	svga_name, %si
+an1:	call	prtstr
+	leaw	listhdr, %si			# Table header
+	call	prtstr
+	movb	$0x30, %dl			# DL holds mode number
+	leaw	modelist, %si
+lm1:	cmpw	$ASK_VGA, (%si)			# End?
+	jz	lm2
+
+	movb	%dl, %al			# Menu selection number
+	call	prtchr
+	call	prtsp2
+	lodsw
+	call	prthw				# Mode ID
+	call	prtsp2
+	movb	0x1(%si), %al
+	call	prtdec				# Rows
+	movb	$0x78, %al			# the letter 'x'
+	call	prtchr
+	lodsw
+	call	prtdec				# Columns
+	movb	$0x0d, %al			# New line
+	call	prtchr
+	movb	$0x0a, %al
+	call	prtchr
+	incb	%dl				# Next character
+	cmpb	$0x3a, %dl
+	jnz	lm1
+
+	movb	$0x61, %dl
+	jmp	lm1
+
+lm2:	leaw	prompt, %si			# Mode prompt
+	call	prtstr
+	leaw	edit_buf, %di			# Editor buffer
+lm3:	call	getkey
+	cmpb	$0x0d, %al			# Enter?
+	jz	lment
+
+	cmpb	$0x08, %al			# Backspace?
+	jz	lmbs
+
+	cmpb	$0x20, %al			# Printable?
+	jc	lm3
+
+	cmpw	$edit_buf+4, %di		# Enough space?
+	jz	lm3
+
+	stosb
+	call	prtchr
+	jmp	lm3
+
+lmbs:	cmpw	$edit_buf, %di			# Backspace
+	jz	lm3
+
+	decw	%di
+	movb	$0x08, %al
+	call	prtchr
+	call	prtspc
+	movb	$0x08, %al
+	call	prtchr
+	jmp	lm3
+	
+lment:	movb	$0, (%di)
+	leaw	crlft, %si
+	call	prtstr
+	leaw	edit_buf, %si
+	cmpb	$0, (%si)			# Empty string = default mode
+	jz	lmdef
+
+	cmpb	$0, 1(%si)			# One character = menu selection
+	jz	mnusel
+
+	cmpw	$0x6373, (%si)			# "scan" => mode scanning
+	jnz	lmhx
+
+	cmpw	$0x6e61, 2(%si)
+	jz	lmscan
+
+lmhx:	xorw	%bx, %bx			# Else => mode ID in hex
+lmhex:	lodsb
+	orb	%al, %al
+	jz	lmuse1
+
+	subb	$0x30, %al
+	jc	lmbad
+
+	cmpb	$10, %al
+	jc	lmhx1
+
+	subb	$7, %al
+	andb	$0xdf, %al
+	cmpb	$10, %al
+	jc	lmbad
+
+	cmpb	$16, %al
+	jnc	lmbad
+
+lmhx1:	shlw	$4, %bx
+	orb	%al, %bl
+	jmp	lmhex
+
+lmuse1:	movw	%bx, %ax
+	jmp	lmuse
+
+mnusel:	lodsb					# Menu selection
+	xorb	%ah, %ah
+	subb	$0x30, %al
+	jc	lmbad
+
+	cmpb	$10, %al
+	jc	lmuse
+	
+	cmpb	$0x61-0x30, %al
+	jc	lmbad
+	
+	subb	$0x61-0x30-10, %al
+	cmpb	$36, %al
+	jnc	lmbad
+
+lmuse:	call	mode_set
+	jc	lmdef
+
+lmbad:	leaw	unknt, %si
+	call	prtstr
+	jmp	lm2
+lmscan:	cmpb	$0, adapter			# Scanning only on EGA/VGA
+	jz	lmbad
+
+	movw	$0, mt_end			# Scanning of modes is
+	movb	$1, scanning			# done as new autodetection.
+	call	mode_table
+	jmp	listm0
+lmdef:	ret
+
+# Additional parts of mode_set... (relative jumps, you know)
+setv7:						# Video7 extended modes
+	DO_STORE
+	subb	$VIDEO_FIRST_V7>>8, %bh
+	movw	$0x6f05, %ax
+	int	$0x10
+	stc
+	ret
+
+_setrec:	jmp	setrec			# Ugly...
+_set_80x25:	jmp	set_80x25
+
+# Aliases for backward compatibility.
+setalias:
+	movw	$VIDEO_80x25, %ax
+	incw	%bx
+	jz	mode_set
+
+	movb	$VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
+	incw	%bx
+	jnz	setbad				# Fall-through!
+
+# Setting of user mode (AX=mode ID) => CF=success
+mode_set:
+	movw	%ax, %bx
+	cmpb	$0xff, %ah
+	jz	setalias
+
+	testb	$VIDEO_RECALC>>8, %ah
+	jnz	_setrec
+
+	cmpb	$VIDEO_FIRST_RESOLUTION>>8, %ah
+	jnc	setres
+	
+	cmpb	$VIDEO_FIRST_SPECIAL>>8, %ah
+	jz	setspc
+	
+	cmpb	$VIDEO_FIRST_V7>>8, %ah
+	jz	setv7
+	
+	cmpb	$VIDEO_FIRST_VESA>>8, %ah
+	jnc	check_vesa
+	
+	orb	%ah, %ah
+	jz	setmenu
+	
+	decb	%ah
+	jz	setbios
+
+setbad:	clc
+	movb	$0, do_restore			# The screen needn't be restored
+	ret
+
+setvesa:
+	DO_STORE
+	subb	$VIDEO_FIRST_VESA>>8, %bh
+	movw	$0x4f02, %ax			# VESA BIOS mode set call
+	int	$0x10
+	cmpw	$0x004f, %ax			# AL=4f if implemented
+	jnz	setbad				# AH=0 if OK
+
+	stc
+	ret
+
+setbios:
+	DO_STORE
+	int	$0x10				# Standard BIOS mode set call
+	pushw	%bx
+	movb	$0x0f, %ah			# Check if really set
+	int	$0x10
+	popw	%bx
+	cmpb	%bl, %al
+	jnz	setbad
+	
+	stc
+	ret
+
+setspc:	xorb	%bh, %bh			# Set special mode
+	cmpb	$VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
+	jnc	setbad
+	
+	addw	%bx, %bx
+	jmp	*spec_inits(%bx)
+
+setmenu:
+	orb	%al, %al			# 80x25 is an exception
+	jz	_set_80x25
+	
+	pushw	%bx				# Set mode chosen from menu
+	call	mode_table			# Build the mode table
+	popw	%ax
+	shlw	$2, %ax
+	addw	%ax, %si
+	cmpw	%di, %si
+	jnc	setbad
+	
+	movw	(%si), %ax			# Fetch mode ID
+_m_s:	jmp	mode_set
+
+setres:	pushw	%bx				# Set mode chosen by resolution
+	call	mode_table
+	popw	%bx
+	xchgb	%bl, %bh
+setr1:	lodsw
+	cmpw	$ASK_VGA, %ax			# End of the list?
+	jz	setbad
+	
+	lodsw
+	cmpw	%bx, %ax
+	jnz	setr1
+	
+	movw	-4(%si), %ax			# Fetch mode ID
+	jmp	_m_s
+
+check_vesa:
+	leaw	modelist+1024, %di
+	subb	$VIDEO_FIRST_VESA>>8, %bh
+	movw	%bx, %cx			# Get mode information structure
+	movw	$0x4f01, %ax
+	int	$0x10
+	addb	$VIDEO_FIRST_VESA>>8, %bh
+	cmpw	$0x004f, %ax
+	jnz	setbad
+
+	movb	(%di), %al			# Check capabilities.
+	andb	$0x19, %al
+	cmpb	$0x09, %al
+	jz	setvesa				# This is a text mode
+
+	movb	(%di), %al			# Check capabilities.
+	andb	$0x99, %al
+	cmpb	$0x99, %al
+	jnz	_setbad				# Doh! No linear frame buffer.
+
+	subb	$VIDEO_FIRST_VESA>>8, %bh
+	orw	$0x4000, %bx			# Use linear frame buffer
+	movw	$0x4f02, %ax			# VESA BIOS mode set call
+	int	$0x10
+	cmpw	$0x004f, %ax			# AL=4f if implemented
+	jnz	_setbad				# AH=0 if OK
+
+	movb	$1, graphic_mode		# flag graphic mode
+	movb	$0, do_restore			# no screen restore
+	stc
+	ret
+
+_setbad:	jmp	setbad          	# Ugly...
+
+# Recalculate vertical display end registers -- this fixes various
+# inconsistencies of extended modes on many adapters. Called when
+# the VIDEO_RECALC flag is set in the mode ID.
+
+setrec:	subb	$VIDEO_RECALC>>8, %ah		# Set the base mode
+	call	mode_set
+	jnc	rct3
+
+	movw	%gs:(0x485), %ax		# Font size in pixels
+	movb	%gs:(0x484), %bl		# Number of rows
+	incb	%bl
+	mulb	%bl				# Number of visible
+	decw	%ax				# scan lines - 1
+	movw	$0x3d4, %dx
+	movw	%ax, %bx
+	movb	$0x12, %al			# Lower 8 bits
+	movb	%bl, %ah
+	outw	%ax, %dx
+	movb	$0x07, %al		# Bits 8 and 9 in the overflow register
+	call	inidx
+	xchgb	%al, %ah
+	andb	$0xbd, %ah
+	shrb	%bh
+	jnc	rct1
+	orb	$0x02, %ah
+rct1:	shrb	%bh
+	jnc	rct2
+	orb	$0x40, %ah
+rct2:	movb	$0x07, %al
+	outw	%ax, %dx
+	stc
+rct3:	ret
+
+# Table of routines for setting of the special modes.
+spec_inits:
+	.word	set_80x25
+	.word	set_8pixel
+	.word	set_80x43
+	.word	set_80x28
+	.word	set_current
+	.word	set_80x30
+	.word	set_80x34
+	.word	set_80x60
+	.word	set_gfx
+
+# Set the 80x25 mode. If already set, do nothing.
+set_80x25:
+	movw	$0x5019, force_size		# Override possibly broken BIOS
+use_80x25:
+#ifdef CONFIG_VIDEO_400_HACK
+	movw	$0x1202, %ax			# Force 400 scan lines
+	movb	$0x30, %bl
+	int	$0x10
+#else
+	movb	$0x0f, %ah			# Get current mode ID
+	int	$0x10
+	cmpw	$0x5007, %ax	# Mode 7 (80x25 mono) is the only one available
+	jz	st80		# on CGA/MDA/HGA and is also available on EGAM
+
+	cmpw	$0x5003, %ax	# Unknown mode, force 80x25 color
+	jnz	force3
+
+st80:	cmpb	$0, adapter	# CGA/MDA/HGA => mode 3/7 is always 80x25
+	jz	set80
+
+	movb	%gs:(0x0484), %al	# This is EGA+ -- beware of 80x50 etc.
+	orb	%al, %al		# Some buggy BIOS'es set 0 rows
+	jz	set80
+	
+	cmpb	$24, %al		# It's hopefully correct
+	jz	set80
+#endif /* CONFIG_VIDEO_400_HACK */
+force3:	DO_STORE
+	movw	$0x0003, %ax			# Forced set
+	int	$0x10
+set80:	stc
+	ret
+
+# Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
+set_8pixel:
+	DO_STORE
+	call	use_80x25			# The base is 80x25
+set_8pt:
+	movw	$0x1112, %ax			# Use 8x8 font
+	xorb	%bl, %bl
+	int	$0x10
+	movw	$0x1200, %ax			# Use alternate print screen
+	movb	$0x20, %bl
+	int	$0x10
+	movw	$0x1201, %ax			# Turn off cursor emulation
+	movb	$0x34, %bl
+	int	$0x10
+	movb	$0x01, %ah			# Define cursor scan lines 6-7
+	movw	$0x0607, %cx
+	int	$0x10
+set_current:
+	stc
+	ret
+
+# Set the 80x28 mode. This mode works on all VGA's, because it's a standard
+# 80x25 mode with 14-point fonts instead of 16-point.
+set_80x28:
+	DO_STORE
+	call	use_80x25			# The base is 80x25
+set14:	movw	$0x1111, %ax			# Use 9x14 font
+	xorb	%bl, %bl
+	int	$0x10
+	movb	$0x01, %ah			# Define cursor scan lines 11-12
+	movw	$0x0b0c, %cx
+	int	$0x10
+	stc
+	ret
+
+# Set the 80x43 mode. This mode is works on all VGA's.
+# It's a 350-scanline mode with 8-pixel font.
+set_80x43:
+	DO_STORE
+	movw	$0x1201, %ax			# Set 350 scans
+	movb	$0x30, %bl
+	int	$0x10
+	movw	$0x0003, %ax			# Reset video mode
+	int	$0x10
+	jmp	set_8pt				# Use 8-pixel font
+
+# Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
+set_80x30:
+	call	use_80x25			# Start with real 80x25
+	DO_STORE
+	movw	$0x3cc, %dx			# Get CRTC port
+	inb	%dx, %al
+	movb	$0xd4, %dl
+	rorb	%al				# Mono or color?
+	jc	set48a
+
+	movb	$0xb4, %dl
+set48a:	movw	$0x0c11, %ax		# Vertical sync end (also unlocks CR0-7)
+ 	call	outidx
+	movw	$0x0b06, %ax			# Vertical total
+ 	call	outidx
+	movw	$0x3e07, %ax			# (Vertical) overflow
+ 	call	outidx
+	movw	$0xea10, %ax			# Vertical sync start
+ 	call	outidx
+	movw	$0xdf12, %ax			# Vertical display end
+	call	outidx
+	movw	$0xe715, %ax			# Vertical blank start
+ 	call	outidx
+	movw	$0x0416, %ax			# Vertical blank end
+ 	call	outidx
+	pushw	%dx
+	movb	$0xcc, %dl			# Misc output register (read)
+ 	inb	%dx, %al
+ 	movb	$0xc2, %dl			# (write)
+ 	andb	$0x0d, %al	# Preserve clock select bits and color bit
+ 	orb	$0xe2, %al			# Set correct sync polarity
+ 	outb	%al, %dx
+	popw	%dx
+	movw	$0x501e, force_size
+	stc					# That's all.
+	ret
+
+# Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
+set_80x34:
+	call	set_80x30			# Set 480 scans
+	call	set14				# And 14-pt font
+	movw	$0xdb12, %ax			# VGA vertical display end
+	movw	$0x5022, force_size
+setvde:	call	outidx
+	stc
+	ret
+
+# Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
+set_80x60:
+	call	set_80x30			# Set 480 scans
+	call	set_8pt				# And 8-pt font
+	movw	$0xdf12, %ax			# VGA vertical display end
+	movw	$0x503c, force_size
+	jmp	setvde
+
+set_gfx:
+	ret
+
+#ifdef CONFIG_VIDEO_RETAIN
+
+# Store screen contents to temporary buffer.
+store_screen:
+	cmpb	$0, do_restore			# Already stored?
+	jnz	stsr
+
+	testb	$CAN_USE_HEAP, loadflags	# Have we space for storing?
+	jz	stsr
+	
+	pushw	%ax
+	pushw	%bx
+	pushw	force_size			# Don't force specific size
+	movw	$0, force_size
+	call	mode_params			# Obtain params of current mode
+	popw	force_size
+	movb	%fs:(PARAM_VIDEO_LINES), %ah
+	movb	%fs:(PARAM_VIDEO_COLS), %al
+	movw	%ax, %bx			# BX=dimensions
+	mulb	%ah
+	movw	%ax, %cx			# CX=number of characters
+	addw	%ax, %ax			# Calculate image size
+	addw	$modelist+1024+4, %ax
+	cmpw	heap_end_ptr, %ax
+	jnc	sts1				# Unfortunately, out of memory
+
+	movw	%fs:(PARAM_CURSOR_POS), %ax	# Store mode params
+	leaw	modelist+1024, %di
+	stosw
+	movw	%bx, %ax
+	stosw
+	pushw	%ds				# Store the screen
+	movw	video_segment, %ds
+	xorw	%si, %si
+	rep
+	movsw
+	popw	%ds
+	incb	do_restore			# Screen will be restored later
+sts1:	popw	%bx
+	popw	%ax
+stsr:	ret
+
+# Restore screen contents from temporary buffer.
+restore_screen:
+	cmpb	$0, do_restore			# Has the screen been stored?
+	jz	res1
+
+	call	mode_params			# Get parameters of current mode
+	movb	%fs:(PARAM_VIDEO_LINES), %cl
+	movb	%fs:(PARAM_VIDEO_COLS), %ch
+	leaw	modelist+1024, %si		# Screen buffer
+	lodsw					# Set cursor position
+	movw	%ax, %dx
+	cmpb	%cl, %dh
+	jc	res2
+	
+	movb	%cl, %dh
+	decb	%dh
+res2:	cmpb	%ch, %dl
+	jc	res3
+	
+	movb	%ch, %dl
+	decb	%dl
+res3:	movb	$0x02, %ah
+	movb	$0x00, %bh
+	int	$0x10
+	lodsw					# Display size
+	movb	%ah, %dl			# DL=number of lines
+	movb	$0, %ah				# BX=phys. length of orig. line
+	movw	%ax, %bx
+	cmpb	%cl, %dl			# Too many?
+	jc	res4
+
+	pushw	%ax
+	movb	%dl, %al
+	subb	%cl, %al
+	mulb	%bl
+	addw	%ax, %si
+	addw	%ax, %si
+	popw	%ax
+	movb	%cl, %dl
+res4:	cmpb	%ch, %al			# Too wide?
+	jc	res5
+	
+	movb	%ch, %al			# AX=width of src. line
+res5:	movb	$0, %cl
+	xchgb	%ch, %cl
+	movw	%cx, %bp			# BP=width of dest. line
+	pushw	%es
+	movw	video_segment, %es
+	xorw	%di, %di			# Move the data
+	addw	%bx, %bx			# Convert BX and BP to _bytes_
+	addw	%bp, %bp
+res6:	pushw	%si
+	pushw	%di
+	movw	%ax, %cx
+	rep
+	movsw
+	popw	%di
+	popw	%si
+	addw	%bp, %di
+	addw	%bx, %si
+	decb	%dl
+	jnz	res6
+	
+	popw	%es				# Done
+res1:	ret
+#endif /* CONFIG_VIDEO_RETAIN */
+
+# Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
+outidx:	outb	%al, %dx
+	pushw	%ax
+	movb	%ah, %al
+	incw	%dx
+	outb	%al, %dx
+	decw	%dx
+	popw	%ax
+	ret
+
+# Build the table of video modes (stored after the setup.S code at the
+# `modelist' label. Each video mode record looks like:
+#	.word	MODE-ID		(our special mode ID (see above))
+#	.byte	rows		(number of rows)
+#	.byte	columns		(number of columns)
+# Returns address of the end of the table in DI, the end is marked
+# with a ASK_VGA ID.
+mode_table:
+	movw	mt_end, %di			# Already filled?
+	orw	%di, %di
+	jnz	mtab1x
+	
+	leaw	modelist, %di			# Store standard modes:
+	movl	$VIDEO_80x25 + 0x50190000, %eax	# The 80x25 mode (ALL)
+	stosl
+	movb	adapter, %al			# CGA/MDA/HGA -- no more modes
+	orb	%al, %al
+	jz	mtabe
+	
+	decb	%al
+	jnz	mtabv
+	
+	movl	$VIDEO_8POINT + 0x502b0000, %eax	# The 80x43 EGA mode
+	stosl
+	jmp	mtabe
+
+mtab1x:	jmp	mtab1
+
+mtabv:	leaw	vga_modes, %si			# All modes for std VGA
+	movw	$vga_modes_end-vga_modes, %cx
+	rep	# I'm unable to use movsw as I don't know how to store a half
+	movsb	# of the expression above to cx without using explicit shr.
+
+	cmpb	$0, scanning			# Mode scan requested?
+	jz	mscan1
+	
+	call	mode_scan
+mscan1:
+
+#ifdef CONFIG_VIDEO_LOCAL
+	call	local_modes
+#endif /* CONFIG_VIDEO_LOCAL */
+
+#ifdef CONFIG_VIDEO_VESA
+	call	vesa_modes			# Detect VESA VGA modes
+#endif /* CONFIG_VIDEO_VESA */
+
+#ifdef CONFIG_VIDEO_SVGA
+	cmpb	$0, scanning			# Bypass when scanning
+	jnz	mscan2
+	
+	call	svga_modes			# Detect SVGA cards & modes
+mscan2:
+#endif /* CONFIG_VIDEO_SVGA */
+
+mtabe:
+
+#ifdef CONFIG_VIDEO_COMPACT
+	leaw	modelist, %si
+	movw	%di, %dx
+	movw	%si, %di
+cmt1:	cmpw	%dx, %si			# Scan all modes
+	jz	cmt2
+
+	leaw	modelist, %bx			# Find in previous entries
+	movw	2(%si), %cx
+cmt3:	cmpw	%bx, %si
+	jz	cmt4
+
+	cmpw	2(%bx), %cx			# Found => don't copy this entry
+	jz	cmt5
+
+	addw	$4, %bx
+	jmp	cmt3
+
+cmt4:	movsl					# Copy entry
+	jmp	cmt1
+
+cmt5:	addw	$4, %si				# Skip entry
+	jmp	cmt1
+
+cmt2:
+#endif	/* CONFIG_VIDEO_COMPACT */
+
+	movw	$ASK_VGA, (%di)			# End marker
+	movw	%di, mt_end
+mtab1:	leaw	modelist, %si			# SI=mode list, DI=list end
+ret0:	ret
+
+# Modes usable on all standard VGAs
+vga_modes:
+	.word	VIDEO_8POINT
+	.word	0x5032				# 80x50
+	.word	VIDEO_80x43
+	.word	0x502b				# 80x43
+	.word	VIDEO_80x28
+	.word	0x501c				# 80x28
+	.word	VIDEO_80x30
+	.word	0x501e				# 80x30
+	.word	VIDEO_80x34
+	.word	0x5022				# 80x34
+	.word	VIDEO_80x60
+	.word	0x503c				# 80x60
+
+vga_modes_end:
+# Detect VESA modes.
+
+#ifdef CONFIG_VIDEO_VESA
+vesa_modes:
+	cmpb	$2, adapter			# VGA only
+	jnz	ret0
+
+	movw	%di, %bp			# BP=original mode table end
+	addw	$0x200, %di			# Buffer space
+	movw	$0x4f00, %ax			# VESA Get card info call
+	int	$0x10
+	movw	%bp, %di
+	cmpw	$0x004f, %ax			# Successful?
+	jnz	ret0
+	
+	cmpw	$0x4556, 0x200(%di)
+	jnz	ret0
+	
+	cmpw	$0x4153, 0x202(%di)
+	jnz	ret0
+	
+	movw	$vesa_name, card_name		# Set name to "VESA VGA"
+	pushw	%gs
+	lgsw	0x20e(%di), %si			# GS:SI=mode list
+	movw	$128, %cx			# Iteration limit
+vesa1:
+# gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
+# XXX:	lodsw	%gs:(%si), %ax			# Get next mode in the list
+	gs; lodsw
+	cmpw	$0xffff, %ax			# End of the table?
+	jz	vesar
+	
+	cmpw	$0x0080, %ax			# Check validity of mode ID
+	jc	vesa2
+	
+	orb	%ah, %ah		# Valid IDs: 0x0000-0x007f/0x0100-0x07ff
+	jz	vesan			# Certain BIOSes report 0x80-0xff!
+
+	cmpw	$0x0800, %ax
+	jnc	vesae
+
+vesa2:	pushw	%cx
+	movw	%ax, %cx			# Get mode information structure
+	movw	$0x4f01, %ax
+	int	$0x10
+	movw	%cx, %bx			# BX=mode number
+	addb	$VIDEO_FIRST_VESA>>8, %bh
+	popw	%cx
+	cmpw	$0x004f, %ax
+	jnz	vesan			# Don't report errors (buggy BIOSES)
+
+	movb	(%di), %al			# Check capabilities. We require
+	andb	$0x19, %al			# a color text mode.
+	cmpb	$0x09, %al
+	jnz	vesan
+	
+	cmpw	$0xb800, 8(%di)		# Standard video memory address required
+	jnz	vesan
+
+	testb	$2, (%di)			# Mode characteristics supplied?
+	movw	%bx, (%di)			# Store mode number
+	jz	vesa3
+	
+	xorw	%dx, %dx
+	movw	0x12(%di), %bx			# Width
+	orb	%bh, %bh
+	jnz	vesan
+	
+	movb	%bl, 0x3(%di)
+	movw	0x14(%di), %ax			# Height
+	orb	%ah, %ah
+	jnz	vesan
+	
+	movb	%al, 2(%di)
+	mulb	%bl
+	cmpw	$8193, %ax		# Small enough for Linux console driver?
+	jnc	vesan
+
+	jmp	vesaok
+
+vesa3:	subw	$0x8108, %bx	# This mode has no detailed info specified,
+	jc	vesan		# so it must be a standard VESA mode.
+
+	cmpw	$5, %bx
+	jnc	vesan
+
+	movw	vesa_text_mode_table(%bx), %ax
+	movw	%ax, 2(%di)
+vesaok:	addw	$4, %di				# The mode is valid. Store it.
+vesan:	loop	vesa1			# Next mode. Limit exceeded => error
+vesae:	leaw	vesaer, %si
+	call	prtstr
+	movw	%bp, %di			# Discard already found modes.
+vesar:	popw	%gs
+	ret
+
+# Dimensions of standard VESA text modes
+vesa_text_mode_table:
+	.byte	60, 80				# 0108
+	.byte	25, 132				# 0109
+	.byte	43, 132				# 010A
+	.byte	50, 132				# 010B
+	.byte	60, 132				# 010C
+#endif	/* CONFIG_VIDEO_VESA */
+
+# Scan for video modes. A bit dirty, but should work.
+mode_scan:
+	movw	$0x0100, %cx			# Start with mode 0
+scm1:	movb	$0, %ah				# Test the mode
+	movb	%cl, %al
+	int	$0x10
+	movb	$0x0f, %ah
+	int	$0x10
+	cmpb	%cl, %al
+	jnz	scm2				# Mode not set
+
+	movw	$0x3c0, %dx			# Test if it's a text mode
+	movb	$0x10, %al			# Mode bits
+	call	inidx
+	andb	$0x03, %al
+	jnz	scm2
+	
+	movb	$0xce, %dl			# Another set of mode bits
+	movb	$0x06, %al
+	call	inidx
+	shrb	%al
+	jc	scm2
+	
+	movb	$0xd4, %dl			# Cursor location
+	movb	$0x0f, %al
+	call	inidx
+	orb	%al, %al
+	jnz	scm2
+	
+	movw	%cx, %ax			# Ok, store the mode
+	stosw
+	movb	%gs:(0x484), %al		# Number of rows
+	incb	%al
+	stosb
+	movw	%gs:(0x44a), %ax		# Number of columns
+	stosb
+scm2:	incb	%cl
+	jns	scm1
+	
+	movw	$0x0003, %ax			# Return back to mode 3
+	int	$0x10
+	ret
+
+tstidx:	outw	%ax, %dx			# OUT DX,AX and inidx
+inidx:	outb	%al, %dx			# Read from indexed VGA register
+	incw	%dx			# AL=index, DX=index reg port -> AL=data
+	inb	%dx, %al
+	decw	%dx
+	ret
+
+# Try to detect type of SVGA card and supply (usually approximate) video
+# mode table for it.
+
+#ifdef CONFIG_VIDEO_SVGA
+svga_modes:
+	leaw	svga_table, %si			# Test all known SVGA adapters
+dosvga:	lodsw
+	movw	%ax, %bp			# Default mode table
+	orw	%ax, %ax
+	jz	didsv1
+
+	lodsw					# Pointer to test routine
+	pushw	%si
+	pushw	%di
+	pushw	%es
+	movw	$0xc000, %bx
+	movw	%bx, %es
+	call	*%ax				# Call test routine
+	popw	%es
+	popw	%di
+	popw	%si
+	orw	%bp, %bp
+	jz	dosvga
+	
+	movw	%bp, %si			# Found, copy the modes
+	movb	svga_prefix, %ah
+cpsvga:	lodsb
+	orb	%al, %al
+	jz	didsv
+	
+	stosw
+	movsw
+	jmp	cpsvga
+
+didsv:	movw	%si, card_name			# Store pointer to card name
+didsv1:	ret
+
+# Table of all known SVGA cards. For each card, we store a pointer to
+# a table of video modes supported by the card and a pointer to a routine
+# used for testing of presence of the card. The video mode table is always
+# followed by the name of the card or the chipset.
+svga_table:
+	.word	ati_md, ati_test
+	.word	oak_md, oak_test
+	.word	paradise_md, paradise_test
+	.word	realtek_md, realtek_test
+	.word	s3_md, s3_test
+	.word	chips_md, chips_test
+	.word	video7_md, video7_test
+	.word	cirrus5_md, cirrus5_test
+	.word	cirrus6_md, cirrus6_test
+	.word	cirrus1_md, cirrus1_test
+	.word	ahead_md, ahead_test
+	.word	everex_md, everex_test
+	.word	genoa_md, genoa_test
+	.word	trident_md, trident_test
+	.word	tseng_md, tseng_test
+	.word	0
+
+# Test routines and mode tables:
+
+# S3 - The test algorithm was taken from the SuperProbe package
+# for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
+s3_test:
+	movw	$0x0f35, %cx	# we store some constants in cl/ch
+	movw	$0x03d4, %dx
+	movb	$0x38, %al
+	call	inidx
+	movb	%al, %bh	# store current CRT-register 0x38
+	movw	$0x0038, %ax
+	call	outidx		# disable writing to special regs
+	movb	%cl, %al	# check whether we can write special reg 0x35
+	call	inidx
+	movb	%al, %bl	# save the current value of CRT reg 0x35
+	andb	$0xf0, %al	# clear bits 0-3
+	movb	%al, %ah
+	movb	%cl, %al	# and write it to CRT reg 0x35
+	call	outidx
+	call	inidx		# now read it back
+	andb	%ch, %al	# clear the upper 4 bits
+	jz	s3_2		# the first test failed. But we have a
+
+	movb	%bl, %ah	# second chance
+	movb	%cl, %al
+	call	outidx
+	jmp	s3_1		# do the other tests
+
+s3_2:	movw	%cx, %ax	# load ah with 0xf and al with 0x35
+	orb	%bl, %ah	# set the upper 4 bits of ah with the orig value
+	call	outidx		# write ...
+	call	inidx		# ... and reread 
+	andb	%cl, %al	# turn off the upper 4 bits
+	pushw	%ax
+	movb	%bl, %ah	# restore old value in register 0x35
+	movb	%cl, %al
+	call	outidx
+	popw	%ax
+	cmpb	%ch, %al	# setting lower 4 bits was successful => bad
+	je	no_s3		# writing is allowed => this is not an S3
+
+s3_1:	movw	$0x4838, %ax	# allow writing to special regs by putting
+	call	outidx		# magic number into CRT-register 0x38
+	movb	%cl, %al	# check whether we can write special reg 0x35
+	call	inidx
+	movb	%al, %bl
+	andb	$0xf0, %al
+	movb	%al, %ah
+	movb	%cl, %al
+	call	outidx
+	call	inidx
+	andb	%ch, %al
+	jnz	no_s3		# no, we can't write => no S3
+
+	movw	%cx, %ax
+	orb	%bl, %ah
+	call	outidx
+	call	inidx
+	andb	%ch, %al
+	pushw	%ax
+	movb	%bl, %ah	# restore old value in register 0x35
+	movb	%cl, %al
+	call	outidx
+	popw	%ax
+	cmpb	%ch, %al
+	jne	no_s31		# writing not possible => no S3
+	movb	$0x30, %al
+	call	inidx		# now get the S3 id ...
+	leaw	idS3, %di
+	movw	$0x10, %cx
+	repne
+	scasb
+	je	no_s31
+
+	movb	%bh, %ah
+	movb	$0x38, %al
+	jmp	s3rest
+
+no_s3:	movb	$0x35, %al	# restore CRT register 0x35
+	movb	%bl, %ah
+	call	outidx
+no_s31:	xorw	%bp, %bp	# Detection failed
+s3rest:	movb	%bh, %ah
+	movb	$0x38, %al	# restore old value of CRT register 0x38
+	jmp	outidx
+
+idS3:	.byte	0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
+	.byte	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
+
+s3_md:	.byte	0x54, 0x2b, 0x84
+	.byte	0x55, 0x19, 0x84
+	.byte	0
+	.ascii	"S3"
+	.byte	0
+
+# ATI cards.
+ati_test:
+	leaw 	idati, %si
+	movw	$0x31, %di
+	movw	$0x09, %cx
+	repe
+	cmpsb
+	je	atiok
+
+	xorw	%bp, %bp
+atiok:	ret
+
+idati:	.ascii	"761295520"
+
+ati_md:	.byte	0x23, 0x19, 0x84
+	.byte	0x33, 0x2c, 0x84
+	.byte	0x22, 0x1e, 0x64
+	.byte	0x21, 0x19, 0x64
+	.byte	0x58, 0x21, 0x50
+	.byte	0x5b, 0x1e, 0x50
+	.byte	0
+	.ascii	"ATI"
+	.byte	0
+
+# AHEAD
+ahead_test:
+	movw	$0x200f, %ax
+	movw	$0x3ce, %dx
+	outw	%ax, %dx
+	incw	%dx
+	inb	%dx, %al
+	cmpb	$0x20, %al
+	je	isahed
+
+	cmpb	$0x21, %al
+	je	isahed
+	
+	xorw	%bp, %bp
+isahed:	ret
+
+ahead_md:
+	.byte	0x22, 0x2c, 0x84
+	.byte	0x23, 0x19, 0x84
+	.byte	0x24, 0x1c, 0x84
+	.byte	0x2f, 0x32, 0xa0
+	.byte	0x32, 0x22, 0x50
+	.byte	0x34, 0x42, 0x50
+	.byte	0
+	.ascii	"Ahead"
+	.byte	0
+
+# Chips & Tech.
+chips_test:
+	movw	$0x3c3, %dx
+	inb	%dx, %al
+	orb	$0x10, %al
+	outb	%al, %dx
+	movw	$0x104, %dx
+	inb	%dx, %al
+	movb	%al, %bl
+	movw	$0x3c3, %dx
+	inb	%dx, %al
+	andb	$0xef, %al
+	outb	%al, %dx
+	cmpb	$0xa5, %bl
+	je	cantok
+	
+	xorw	%bp, %bp
+cantok:	ret
+
+chips_md:
+	.byte	0x60, 0x19, 0x84
+	.byte	0x61, 0x32, 0x84
+	.byte	0
+	.ascii	"Chips & Technologies"
+	.byte	0
+
+# Cirrus Logic 5X0
+cirrus1_test:
+	movw	$0x3d4, %dx
+	movb	$0x0c, %al
+	outb	%al, %dx
+	incw	%dx
+	inb	%dx, %al
+	movb	%al, %bl
+	xorb	%al, %al
+	outb	%al, %dx
+	decw	%dx
+	movb	$0x1f, %al
+	outb	%al, %dx
+	incw	%dx
+	inb	%dx, %al
+	movb	%al, %bh
+	xorb	%ah, %ah
+	shlb	$4, %al
+	movw	%ax, %cx
+	movb	%bh, %al
+	shrb	$4, %al
+	addw	%ax, %cx
+	shlw	$8, %cx
+	addw	$6, %cx
+	movw	%cx, %ax
+	movw	$0x3c4, %dx
+	outw	%ax, %dx
+	incw	%dx
+	inb	%dx, %al
+	andb	%al, %al
+	jnz	nocirr
+	
+	movb	%bh, %al
+	outb	%al, %dx
+	inb	%dx, %al
+	cmpb	$0x01, %al
+	je	iscirr
+
+nocirr:	xorw	%bp, %bp
+iscirr: movw	$0x3d4, %dx
+	movb	%bl, %al
+	xorb	%ah, %ah
+	shlw	$8, %ax
+	addw	$0x0c, %ax
+	outw	%ax, %dx
+	ret
+
+cirrus1_md:
+	.byte	0x1f, 0x19, 0x84
+	.byte	0x20, 0x2c, 0x84
+	.byte	0x22, 0x1e, 0x84
+	.byte	0x31, 0x25, 0x64
+	.byte	0
+	.ascii	"Cirrus Logic 5X0"
+	.byte	0
+
+# Cirrus Logic 54XX
+cirrus5_test:
+	movw	$0x3c4, %dx
+	movb	$6, %al
+	call	inidx
+	movb	%al, %bl			# BL=backup
+	movw	$6, %ax
+	call	tstidx
+	cmpb	$0x0f, %al
+	jne	c5fail
+	
+	movw	$0x1206, %ax
+	call	tstidx
+	cmpb	$0x12, %al
+	jne	c5fail
+	
+	movb	$0x1e, %al
+	call	inidx
+	movb	%al, %bh
+	movb	%bh, %ah
+	andb	$0xc0, %ah
+	movb	$0x1e, %al
+	call	tstidx
+	andb	$0x3f, %al
+	jne	c5xx
+	
+	movb	$0x1e, %al
+	movb	%bh, %ah
+	orb	$0x3f, %ah
+	call	tstidx
+	xorb	$0x3f, %al
+	andb	$0x3f, %al
+c5xx:	pushf
+	movb	$0x1e, %al
+	movb	%bh, %ah
+	outw	%ax, %dx
+	popf
+	je	c5done
+
+c5fail:	xorw	%bp, %bp
+c5done:	movb	$6, %al
+	movb	%bl, %ah
+	outw	%ax, %dx
+	ret
+
+cirrus5_md:
+	.byte	0x14, 0x19, 0x84
+	.byte	0x54, 0x2b, 0x84
+	.byte	0
+	.ascii	"Cirrus Logic 54XX"
+	.byte	0
+
+# Cirrus Logic 64XX -- no known extra modes, but must be identified, because
+# it's misidentified by the Ahead test.
+cirrus6_test:
+	movw	$0x3ce, %dx
+	movb	$0x0a, %al
+	call	inidx
+	movb	%al, %bl	# BL=backup
+	movw	$0xce0a, %ax
+	call	tstidx
+	orb	%al, %al
+	jne	c2fail
+	
+	movw	$0xec0a, %ax
+	call	tstidx
+	cmpb	$0x01, %al
+	jne	c2fail
+	
+	movb	$0xaa, %al
+	call	inidx		# 4X, 5X, 7X and 8X are valid 64XX chip ID's. 
+	shrb	$4, %al
+	subb	$4, %al
+	jz	c6done
+	
+	decb	%al
+	jz	c6done
+	
+	subb	$2, %al
+	jz	c6done
+	
+	decb	%al
+	jz	c6done
+	
+c2fail:	xorw	%bp, %bp
+c6done:	movb	$0x0a, %al
+	movb	%bl, %ah
+	outw	%ax, %dx
+	ret
+
+cirrus6_md:
+	.byte	0
+	.ascii	"Cirrus Logic 64XX"
+	.byte	0
+
+# Everex / Trident
+everex_test:
+	movw	$0x7000, %ax
+	xorw	%bx, %bx
+	int	$0x10
+	cmpb	$0x70, %al
+	jne	noevrx
+	
+	shrw	$4, %dx
+	cmpw	$0x678, %dx
+	je	evtrid
+	
+	cmpw	$0x236, %dx
+	jne	evrxok
+
+evtrid:	leaw	trident_md, %bp
+evrxok:	ret
+
+noevrx:	xorw	%bp, %bp
+	ret
+
+everex_md:
+	.byte	0x03, 0x22, 0x50
+	.byte	0x04, 0x3c, 0x50
+	.byte	0x07, 0x2b, 0x64
+	.byte	0x08, 0x4b, 0x64
+	.byte	0x0a, 0x19, 0x84
+	.byte	0x0b, 0x2c, 0x84
+	.byte	0x16, 0x1e, 0x50
+	.byte	0x18, 0x1b, 0x64
+	.byte	0x21, 0x40, 0xa0
+	.byte	0x40, 0x1e, 0x84
+	.byte	0
+	.ascii	"Everex/Trident"
+	.byte	0
+
+# Genoa.
+genoa_test:
+	leaw	idgenoa, %si			# Check Genoa 'clues'
+	xorw	%ax, %ax
+	movb	%es:(0x37), %al
+	movw	%ax, %di
+	movw	$0x04, %cx
+	decw	%si
+	decw	%di
+l1:	incw	%si
+	incw	%di
+	movb	(%si), %al
+	testb	%al, %al
+	jz	l2
+
+	cmpb	%es:(%di), %al
+l2:	loope 	l1
+	orw	%cx, %cx
+	je	isgen
+	
+	xorw	%bp, %bp
+isgen:	ret
+
+idgenoa: .byte	0x77, 0x00, 0x99, 0x66
+
+genoa_md:
+	.byte	0x58, 0x20, 0x50
+	.byte	0x5a, 0x2a, 0x64
+	.byte	0x60, 0x19, 0x84
+	.byte	0x61, 0x1d, 0x84
+	.byte	0x62, 0x20, 0x84
+	.byte	0x63, 0x2c, 0x84
+	.byte	0x64, 0x3c, 0x84
+	.byte	0x6b, 0x4f, 0x64
+	.byte	0x72, 0x3c, 0x50
+	.byte	0x74, 0x42, 0x50
+	.byte	0x78, 0x4b, 0x64
+	.byte	0
+	.ascii	"Genoa"
+	.byte	0
+
+# OAK
+oak_test:
+	leaw	idoakvga, %si
+	movw	$0x08, %di
+	movw	$0x08, %cx
+	repe
+	cmpsb
+	je	isoak
+	
+	xorw	%bp, %bp
+isoak:	ret
+
+idoakvga: .ascii  "OAK VGA "
+
+oak_md: .byte	0x4e, 0x3c, 0x50
+	.byte	0x4f, 0x3c, 0x84
+	.byte	0x50, 0x19, 0x84
+	.byte	0x51, 0x2b, 0x84
+	.byte	0
+	.ascii	"OAK"
+	.byte	0
+
+# WD Paradise.
+paradise_test:
+	leaw	idparadise, %si
+	movw	$0x7d, %di
+	movw	$0x04, %cx
+	repe
+	cmpsb
+	je	ispara
+	
+	xorw	%bp, %bp
+ispara:	ret
+
+idparadise:	.ascii	"VGA="
+
+paradise_md:
+	.byte	0x41, 0x22, 0x50
+	.byte	0x47, 0x1c, 0x84
+	.byte	0x55, 0x19, 0x84
+	.byte	0x54, 0x2c, 0x84
+	.byte	0
+	.ascii	"Paradise"
+	.byte	0
+
+# Trident.
+trident_test:
+	movw	$0x3c4, %dx
+	movb	$0x0e, %al
+	outb	%al, %dx
+	incw	%dx
+	inb	%dx, %al
+	xchgb	%al, %ah
+	xorb	%al, %al
+	outb	%al, %dx
+	inb	%dx, %al
+	xchgb	%ah, %al
+	movb	%al, %bl	# Strange thing ... in the book this wasn't
+	andb	$0x02, %bl	# necessary but it worked on my card which
+	jz	setb2		# is a trident. Without it the screen goes
+				# blurred ...
+	andb	$0xfd, %al
+	jmp	clrb2		
+
+setb2:	orb	$0x02, %al	
+clrb2:	outb	%al, %dx
+	andb	$0x0f, %ah
+	cmpb	$0x02, %ah
+	je	istrid
+
+	xorw	%bp, %bp
+istrid:	ret
+
+trident_md:
+	.byte	0x50, 0x1e, 0x50
+	.byte	0x51, 0x2b, 0x50
+	.byte	0x52, 0x3c, 0x50
+	.byte	0x57, 0x19, 0x84
+	.byte	0x58, 0x1e, 0x84
+	.byte	0x59, 0x2b, 0x84
+	.byte	0x5a, 0x3c, 0x84
+	.byte	0
+	.ascii	"Trident"
+	.byte	0
+
+# Tseng.
+tseng_test:
+	movw	$0x3cd, %dx
+	inb	%dx, %al	# Could things be this simple ! :-)
+	movb	%al, %bl
+	movb	$0x55, %al
+	outb	%al, %dx
+	inb	%dx, %al
+	movb	%al, %ah
+	movb	%bl, %al
+	outb	%al, %dx
+	cmpb	$0x55, %ah
+ 	je	istsen
+
+isnot:	xorw	%bp, %bp
+istsen:	ret
+
+tseng_md:
+	.byte	0x26, 0x3c, 0x50
+	.byte	0x2a, 0x28, 0x64
+	.byte	0x23, 0x19, 0x84
+	.byte	0x24, 0x1c, 0x84
+	.byte	0x22, 0x2c, 0x84
+	.byte	0x21, 0x3c, 0x84
+	.byte	0
+	.ascii	"Tseng"
+	.byte	0
+
+# Video7.
+video7_test:
+	movw	$0x3cc, %dx
+	inb	%dx, %al
+	movw	$0x3b4, %dx
+	andb	$0x01, %al
+	jz	even7
+
+	movw	$0x3d4, %dx
+even7:	movb	$0x0c, %al
+	outb	%al, %dx
+	incw	%dx
+	inb	%dx, %al
+	movb	%al, %bl
+	movb	$0x55, %al
+	outb	%al, %dx
+	inb	%dx, %al
+	decw	%dx
+	movb	$0x1f, %al
+	outb	%al, %dx
+	incw	%dx
+	inb	%dx, %al
+	movb	%al, %bh
+	decw	%dx
+	movb	$0x0c, %al
+	outb	%al, %dx
+	incw	%dx
+	movb	%bl, %al
+	outb	%al, %dx
+	movb	$0x55, %al
+	xorb	$0xea, %al
+	cmpb	%bh, %al
+	jne	isnot
+	
+	movb	$VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching
+	ret
+
+video7_md:
+	.byte	0x40, 0x2b, 0x50
+	.byte	0x43, 0x3c, 0x50
+	.byte	0x44, 0x3c, 0x64
+	.byte	0x41, 0x19, 0x84
+	.byte	0x42, 0x2c, 0x84
+	.byte	0x45, 0x1c, 0x84
+	.byte	0
+	.ascii	"Video 7"
+	.byte	0
+
+# Realtek VGA
+realtek_test:
+	leaw	idrtvga, %si
+	movw	$0x45, %di
+	movw	$0x0b, %cx
+	repe
+	cmpsb
+	je	isrt
+	
+	xorw	%bp, %bp
+isrt:	ret
+
+idrtvga:	.ascii	"REALTEK VGA"
+
+realtek_md:
+	.byte	0x1a, 0x3c, 0x50
+	.byte	0x1b, 0x19, 0x84
+	.byte	0x1c, 0x1e, 0x84
+	.byte	0x1d, 0x2b, 0x84
+	.byte	0x1e, 0x3c, 0x84
+	.byte	0
+	.ascii	"REALTEK"
+	.byte	0
+
+#endif	/* CONFIG_VIDEO_SVGA */
+
+# User-defined local mode table (VGA only)
+#ifdef CONFIG_VIDEO_LOCAL
+local_modes:
+	leaw	local_mode_table, %si
+locm1:	lodsw
+	orw	%ax, %ax
+	jz	locm2
+	
+	stosw
+	movsw
+	jmp	locm1
+
+locm2:	ret
+
+# This is the table of local video modes which can be supplied manually
+# by the user. Each entry consists of mode ID (word) and dimensions
+# (byte for column count and another byte for row count). These modes
+# are placed before all SVGA and VESA modes and override them if table
+# compacting is enabled. The table must end with a zero word followed
+# by NUL-terminated video adapter name.
+local_mode_table:
+	.word	0x0100				# Example: 40x25
+	.byte	25,40
+	.word	0
+	.ascii	"Local"
+	.byte	0
+#endif	/* CONFIG_VIDEO_LOCAL */
+
+# Read a key and return the ASCII code in al, scan code in ah
+getkey:	xorb	%ah, %ah
+	int	$0x16
+	ret
+
+# Read a key with a timeout of 30 seconds.
+# The hardware clock is used to get the time.
+getkt:	call	gettime
+	addb	$30, %al			# Wait 30 seconds
+	cmpb	$60, %al
+	jl	lminute
+
+	subb	$60, %al
+lminute:
+	movb	%al, %cl
+again:	movb	$0x01, %ah
+	int	$0x16
+	jnz	getkey				# key pressed, so get it
+
+	call	gettime
+	cmpb	%cl, %al
+	jne	again
+
+	movb	$0x20, %al			# timeout, return `space'
+	ret
+
+# Flush the keyboard buffer
+flush:	movb	$0x01, %ah
+	int	$0x16
+	jz	empty
+	
+	xorb	%ah, %ah
+	int	$0x16
+	jmp	flush
+
+empty:	ret
+
+# Print hexadecimal number.
+prthw:	pushw	%ax
+	movb	%ah, %al
+	call	prthb
+	popw	%ax
+prthb:	pushw	%ax
+	shrb	$4, %al
+	call	prthn
+	popw	%ax
+	andb	$0x0f, %al
+prthn:	cmpb	$0x0a, %al
+	jc	prth1
+
+	addb	$0x07, %al
+prth1:	addb	$0x30, %al
+	jmp	prtchr
+
+# Print decimal number in al
+prtdec:	pushw	%ax
+	pushw	%cx
+	xorb	%ah, %ah
+	movb	$0x0a, %cl
+	idivb	%cl
+	cmpb	$0x09, %al
+	jbe	lt100
+
+	call	prtdec
+	jmp	skip10
+
+lt100:	addb	$0x30, %al
+	call	prtchr
+skip10:	movb	%ah, %al
+	addb	$0x30, %al
+	call	prtchr	
+	popw	%cx
+	popw	%ax
+	ret
+
+# VIDEO_SELECT-only variables
+mt_end:		.word	0	# End of video mode table if built
+edit_buf:	.space	6	# Line editor buffer
+card_name:	.word	0	# Pointer to adapter name
+scanning:	.byte	0	# Performing mode scan
+do_restore:	.byte	0	# Screen contents altered during mode change
+svga_prefix:	.byte	VIDEO_FIRST_BIOS>>8	# Default prefix for BIOS modes
+graphic_mode:	.byte	0	# Graphic mode with a linear frame buffer
+
+# Status messages
+keymsg:		.ascii	"Press <RETURN> to see video modes available, "
+		.ascii	"<SPACE> to continue or wait 30 secs"
+		.byte	0x0d, 0x0a, 0
+
+listhdr:	.byte	0x0d, 0x0a
+		.ascii	"Mode:    COLSxROWS:"
+
+crlft:		.byte	0x0d, 0x0a, 0
+
+prompt:		.byte	0x0d, 0x0a
+		.asciz	"Enter mode number or `scan': "
+
+unknt:		.asciz	"Unknown mode ID. Try again."
+
+badmdt:		.ascii	"You passed an undefined mode number."
+		.byte	0x0d, 0x0a, 0
+
+vesaer:		.ascii	"Error: Scanning of VESA modes failed. Please "
+		.ascii	"report to <mj@ucw.cz>."
+		.byte	0x0d, 0x0a, 0
+
+old_name:	.asciz	"CGA/MDA/HGA"
+
+ega_name:	.asciz	"EGA"
+
+svga_name:	.ascii	" "
+
+vga_name:	.asciz	"VGA"
+
+vesa_name:	.asciz	"VESA"
+
+name_bann:	.asciz	"Video adapter: "
+#endif /* CONFIG_VIDEO_SELECT */
+
+# Other variables:
+adapter:	.byte	0	# Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
+video_segment:	.word	0xb800	# Video memory segment
+force_size:	.word	0	# Use this size instead of the one in BIOS vars
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/config.in linux-2.4.20/arch/x86_64/config.in
--- linux-2.4.19/arch/x86_64/config.in	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/config.in	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,247 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/config-language.txt.
+#
+mainmenu_name "Linux Kernel Configuration"
+
+define_bool CONFIG_X86_64 y
+
+define_bool CONFIG_X86 y
+define_bool CONFIG_ISA n
+define_bool CONFIG_SBUS n
+
+define_bool CONFIG_UID16 y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+define_bool CONFIG_X86_CMPXCHG y
+define_bool CONFIG_EARLY_PRINTK y
+
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
+mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
+   bool '  Kernel module loader' CONFIG_KMOD
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Processor type and features'
+choice 'Processor family' \
+	"AMD-Hammer			CONFIG_MK8 \
+	 Generic-x86-64			CONFIG_GENERIC_CPU" AMD-Hammer
+	
+#
+# Define implied options from the CPU selection here
+#
+define_int CONFIG_X86_L1_CACHE_BYTES 64
+define_int CONFIG_X86_L1_CACHE_SHIFT 6
+define_bool CONFIG_X86_TSC y
+define_bool CONFIG_X86_GOOD_APIC y
+
+tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR
+tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID
+
+define_bool CONFIG_MATH_EMULATION n
+define_bool CONFIG_MCA n
+define_bool CONFIG_EISA n
+
+define_bool CONFIG_X86_IO_APIC y
+define_bool CONFIG_X86_LOCAL_APIC y
+
+bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
+bool 'Symmetric multi-processing support' CONFIG_SMP
+bool 'HPET timers' CONFIG_HPET_TIMER
+bool 'IOMMU support' CONFIG_GART_IOMMU
+
+if [ "$CONFIG_GART_IOMMU" != "y" ]; then
+   define_bool CONFIG_DUMMY_IOMMU y
+fi
+if [ "$CONFIG_SMP" != "y" ]; then
+   define_bool CONFIG_X86_UP_IOAPIC y
+else
+   define_bool CONFIG_HAVE_DEC_LOCK y
+fi
+
+bool 'Machine check support' CONFIG_MCE
+bool 'K8 NUMA support' CONFIG_K8_NUMA
+if [ "$CONFIG_K8_NUMA" = "y" ]; then
+   define_bool CONFIG_DISCONTIGMEM y 
+   define_bool CONFIG_NUMA y
+fi
+
+endmenu
+
+mainmenu_option next_comment
+comment 'General setup'
+
+bool 'Networking support' CONFIG_NET
+bool 'PCI support' CONFIG_PCI
+if [ "$CONFIG_PCI" = "y" ]; then
+   define_bool CONFIG_PCI_DIRECT y 
+fi
+
+source drivers/pci/Config.in
+
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+
+if [ "$CONFIG_HOTPLUG" = "y" ] ; then
+   source drivers/pcmcia/Config.in
+   source drivers/hotplug/Config.in
+else
+   define_bool CONFIG_PCMCIA n
+fi
+
+bool 'System V IPC' CONFIG_SYSVIPC
+bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+bool 'Sysctl support' CONFIG_SYSCTL
+if [ "$CONFIG_PROC_FS" = "y" ]; then
+   define_bool CONFIG_KCORE_ELF y
+fi
+#tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+
+bool 'Power Management support' CONFIG_PM
+
+bool 'IA32 Emulation' CONFIG_IA32_EMULATION
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   dep_bool '  ACPI support' CONFIG_ACPI $CONFIG_PM
+   if [ "$CONFIG_ACPI" != "n" ]; then
+      source drivers/acpi/Config.in
+   fi
+fi
+
+endmenu
+
+source drivers/mtd/Config.in
+
+source drivers/parport/Config.in
+
+source drivers/block/Config.in
+
+source drivers/md/Config.in
+
+if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
+fi
+
+source drivers/telephony/Config.in
+
+mainmenu_option next_comment
+comment 'ATA/IDE/MFM/RLL support'
+
+tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
+
+if [ "$CONFIG_IDE" != "n" ]; then
+  source drivers/ide/Config.in
+else
+  define_bool CONFIG_BLK_DEV_IDE_MODES n
+  define_bool CONFIG_BLK_DEV_HD n
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'SCSI support'
+
+tristate 'SCSI support' CONFIG_SCSI
+
+if [ "$CONFIG_SCSI" != "n" ]; then
+   source drivers/scsi/Config.in
+fi
+endmenu
+
+source drivers/message/fusion/Config.in
+
+source drivers/ieee1394/Config.in
+
+#Currently not 64bit safe
+#source drivers/message/i2o/Config.in
+
+if [ "$CONFIG_NET" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Network device support'
+
+   bool 'Network device support' CONFIG_NETDEVICES
+   if [ "$CONFIG_NETDEVICES" = "y" ]; then
+      source drivers/net/Config.in
+# seems to be largely not 64bit safe	   
+#      if [ "$CONFIG_ATM" = "y" ]; then
+#         source drivers/atm/Config.in
+#      fi
+   fi
+   endmenu
+fi
+
+source net/ax25/Config.in
+
+source net/irda/Config.in
+
+mainmenu_option next_comment
+comment 'ISDN subsystem'
+if [ "$CONFIG_NET" != "n" ]; then
+   tristate 'ISDN support' CONFIG_ISDN
+   if [ "$CONFIG_ISDN" != "n" ]; then
+      source drivers/isdn/Config.in
+   fi
+fi
+endmenu
+
+#
+# input before char - char/joystick depends on it. As does USB.
+#
+source drivers/input/Config.in
+source drivers/char/Config.in
+
+source net/bluetooth/Config.in
+
+source drivers/misc/Config.in
+
+source drivers/media/Config.in
+
+source fs/Config.in
+
+if [ "$CONFIG_VT" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Console drivers'
+   bool 'VGA text console' CONFIG_VGA_CONSOLE
+   bool 'Video mode selection support' CONFIG_VIDEO_SELECT
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'MDA text console (dual-headed) (EXPERIMENTAL)' CONFIG_MDA_CONSOLE
+      source drivers/video/Config.in
+   fi
+   endmenu
+fi
+
+mainmenu_option next_comment
+comment 'Sound'
+
+tristate 'Sound card support' CONFIG_SOUND
+if [ "$CONFIG_SOUND" != "n" ]; then
+   source drivers/sound/Config.in
+fi
+endmenu
+
+source drivers/usb/Config.in
+
+mainmenu_option next_comment
+comment 'Kernel hacking'
+
+bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
+if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
+   bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
+#   bool '  Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
+   bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
+   bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
+   bool '  Additional run-time checks' CONFIG_CHECKING
+   bool '  Debug __init statements' CONFIG_INIT_DEBUG
+   bool '  IOMMU leak tracing' CONFIG_IOMMU_LEAK
+   bool '  Probalistic stack overflow check' CONFIG_DEBUG_STACKOVERFLOW
+fi
+endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/defconfig linux-2.4.20/arch/x86_64/defconfig
--- linux-2.4.19/arch/x86_64/defconfig	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/defconfig	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,704 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_X86_64=y
+CONFIG_X86=y
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_X86_CMPXCHG=y
+CONFIG_EARLY_PRINTK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# Processor type and features
+#
+CONFIG_MK8=y
+# CONFIG_GENERIC_CPU is not set
+CONFIG_X86_L1_CACHE_BYTES=64
+CONFIG_X86_L1_CACHE_SHIFT=6
+CONFIG_X86_TSC=y
+CONFIG_X86_GOOD_APIC=y
+CONFIG_X86_MSR=y
+CONFIG_X86_CPUID=y
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_MCA is not set
+# CONFIG_EISA is not set
+CONFIG_X86_IO_APIC=y
+CONFIG_X86_LOCAL_APIC=y
+CONFIG_MTRR=y
+# CONFIG_SMP is not set
+CONFIG_HPET_TIMER=y
+# CONFIG_GART_IOMMU is not set
+CONFIG_DUMMY_IOMMU=y
+CONFIG_X86_UP_IOAPIC=y
+CONFIG_MCE=y
+# CONFIG_K8_NUMA is not set
+
+#
+# General setup
+#
+CONFIG_NET=y
+CONFIG_PCI=y
+CONFIG_PCI_DIRECT=y
+# CONFIG_PCI_NAMES is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PM=y
+CONFIG_IA32_EMULATION=y
+CONFIG_ACPI=y
+CONFIG_ACPI_DEBUG=y
+CONFIG_ACPI_BUSMGR=y
+CONFIG_ACPI_SYS=y
+CONFIG_ACPI_CPU=y
+CONFIG_ACPI_BUTTON=y
+CONFIG_ACPI_AC=y
+CONFIG_ACPI_EC=y
+CONFIG_ACPI_CMBATT=y
+CONFIG_ACPI_THERMAL=y
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=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=y
+# 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 is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+# CONFIG_PHONE_IXJ_PCMCIA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
+# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+CONFIG_BLK_DEV_AMD74XX=y
+# CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CMD680 is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_PIIX_TUNING is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_IDE_MODES=y
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=y
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_SYM53C8XX is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_BOOT is not set
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 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_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+# CONFIG_ELMC is not set
+# CONFIG_ELMC_II is not set
+CONFIG_VORTEX=y
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_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_SK98LIN is not set
+CONFIG_TIGON3=y
+# 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
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+CONFIG_VT=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 is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_AMD_RNG is not set
+# CONFIG_INTEL_RNG 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=y
+CONFIG_AGP_INTEL=y
+CONFIG_AGP_I810=y
+CONFIG_AGP_VIA=y
+CONFIG_AGP_AMD=y
+CONFIG_AGP_SIS=y
+CONFIG_AGP_ALI=y
+CONFIG_AGP_SWORKS=y
+# CONFIG_DRM is not set
+# CONFIG_MWAVE is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_REISERFS_FS=y
+# 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_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+# 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=y
+CONFIG_JOLIET=y
+# 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
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# 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=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Console drivers
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VIDEO_SELECT is not set
+# CONFIG_MDA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_CHECKING is not set
+# CONFIG_INIT_DEBUG is not set
+# CONFIG_IOMMU_LEAK is not set
+CONFIG_DEBUG_STACKOVERFLOW=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/ia32/Makefile linux-2.4.20/arch/x86_64/ia32/Makefile
--- linux-2.4.19/arch/x86_64/ia32/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/ia32/Makefile	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,20 @@
+#
+# Makefile for the ia32 kernel emulation subsystem.
+#
+
+.S.s:
+	$(CPP) $(AFLAGS) -o $*.s $<
+.S.o:
+	$(CC) $(AFLAGS) -c -o $*.o $<
+
+export-objs := ia32_ioctl.o	
+
+all: ia32.o
+
+O_TARGET := ia32.o
+obj-$(CONFIG_IA32_EMULATION) := ia32entry.o sys_ia32.o ia32_ioctl.o ia32_signal.o \
+	ia32_binfmt.o fpu32.o socket32.o ptrace32.o ipc32.o
+
+clean::
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/ia32/fpu32.c linux-2.4.20/arch/x86_64/ia32/fpu32.c
--- linux-2.4.19/arch/x86_64/ia32/fpu32.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/ia32/fpu32.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,172 @@
+/* 
+ * Copyright 2002 Andi Kleen, SuSE Labs.
+ * FXSAVE<->i387 conversion support. Based on code by Gareth Hughes.
+ * This is used for ptrace, signals and coredumps in 32bit emulation.
+ * $Id: fpu32.c,v 1.1 2002/03/21 14:16:32 ak Exp $
+ */ 
+
+#include <linux/sched.h>
+#include <asm/sigcontext32.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/i387.h>
+
+static inline unsigned short twd_i387_to_fxsr(unsigned short twd)
+{
+	unsigned int tmp; /* to avoid 16 bit prefixes in the code */
+ 
+	/* Transform each pair of bits into 01 (valid) or 00 (empty) */
+        tmp = ~twd;
+        tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
+        /* and move the valid bits to the lower byte. */
+        tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
+        tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
+        tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
+        return tmp;
+}
+
+static inline unsigned long twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave)
+{
+	struct _fpxreg *st = NULL;
+	unsigned long twd = (unsigned long) fxsave->twd;
+	unsigned long tag;
+	unsigned long ret = 0xffff0000;
+	int i;
+
+#define FPREG_ADDR(f, n)	((char *)&(f)->st_space + (n) * 16);
+
+	for (i = 0 ; i < 8 ; i++) {
+		if (twd & 0x1) {
+			st = (struct _fpxreg *) FPREG_ADDR( fxsave, i );
+
+			switch (st->exponent & 0x7fff) {
+			case 0x7fff:
+				tag = 2;		/* Special */
+				break;
+			case 0x0000:
+				if ( !st->significand[0] &&
+				     !st->significand[1] &&
+				     !st->significand[2] &&
+				     !st->significand[3] ) {
+					tag = 1;	/* Zero */
+				} else {
+					tag = 2;	/* Special */
+				}
+				break;
+			default:
+				if (st->significand[3] & 0x8000) {
+					tag = 0;	/* Valid */
+				} else {
+					tag = 2;	/* Special */
+				}
+				break;
+			}
+		} else {
+			tag = 3;			/* Empty */
+		}
+		ret |= (tag << (2 * i));
+		twd = twd >> 1;
+	}
+	return ret;
+}
+
+
+static inline int convert_fxsr_from_user(struct i387_fxsave_struct *fxsave,
+					 struct _fpstate_ia32 *buf)
+{
+	struct _fpxreg *to;
+	struct _fpreg *from;
+	int i;
+	int err; 
+	__u32 v;
+
+	err = __get_user(fxsave->cwd, (u16 *)&buf->cw); 
+	err |= __get_user(fxsave->swd, (u16 *)&buf->sw);
+	err |= __get_user(fxsave->twd, (u16 *)&buf->tag);
+	fxsave->twd = twd_i387_to_fxsr(fxsave->twd);
+	err |= __get_user(fxsave->rip, &buf->ipoff); 
+	err |= __get_user(fxsave->rdp, &buf->dataoff); 
+	err |= __get_user(v, &buf->cssel); 
+	fxsave->fop = v >> 16;
+	if (err) 
+		return -1; 
+
+	to = (struct _fpxreg *)&fxsave->st_space[0];
+	from = &buf->_st[0];
+	for (i = 0 ; i < 8 ; i++, to++, from++) {
+		if (__copy_from_user(to, from, sizeof(*from)))
+			return -1;
+	}
+	return 0;
+}
+
+
+static inline int convert_fxsr_to_user(struct _fpstate_ia32 *buf,
+				       struct i387_fxsave_struct *fxsave,
+				       struct pt_regs *regs,
+				       struct task_struct *tsk)
+{
+	struct _fpreg *to;
+	struct _fpxreg *from;
+	int i;
+	u32 ds; 
+	int err; 
+
+	err = __put_user((unsigned long)fxsave->cwd | 0xffff0000, &buf->cw);
+	err |= __put_user((unsigned long)fxsave->swd | 0xffff0000, &buf->sw);
+	err |= __put_user((u32)fxsave->rip, &buf->ipoff); 
+	err |= __put_user((u32)(regs->cs | ((u32)fxsave->fop << 16)), 
+			  &buf->cssel); 
+	err |= __put_user((u32)twd_fxsr_to_i387(fxsave), &buf->tag); 
+	err |= __put_user((u32)fxsave->rdp, &buf->dataoff); 
+	if (tsk == current) 
+		asm("movl %%ds,%0 " : "=r" (ds)); 
+	else /* ptrace. task has stopped. */
+		ds = tsk->thread.ds;
+	err |= __put_user(ds, &buf->datasel); 
+	if (err) 
+		return -1; 
+
+	to = &buf->_st[0];
+	from = (struct _fpxreg *) &fxsave->st_space[0];
+	for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
+		if (__copy_to_user(to, from, sizeof(*to)))
+			return -1;
+	}
+	return 0;
+}
+
+int restore_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 *buf, int fsave) 
+{ 
+	clear_fpu(tsk);
+	if (!fsave) { 
+		if (__copy_from_user(&tsk->thread.i387.fxsave, 
+				     &buf->_fxsr_env[0],
+				     sizeof(struct i387_fxsave_struct)))
+			return -1;
+	} 
+	tsk->thread.i387.fxsave.mxcsr &= 0xffbf;
+	return convert_fxsr_from_user(&tsk->thread.i387.fxsave, buf);
+}  
+
+int save_i387_ia32(struct task_struct *tsk, 
+		   struct _fpstate_ia32 *buf, 
+		   struct pt_regs *regs,
+		   int fsave)
+{
+	int err = 0;
+
+	if (!tsk->used_math) 
+		return 0;
+	tsk->used_math = 0; 
+	unlazy_fpu(tsk);
+	if (convert_fxsr_to_user(buf, &tsk->thread.i387.fxsave, regs, tsk))
+		return -1;
+	err |= __put_user(tsk->thread.i387.fxsave.swd, &buf->status);
+	if (fsave) 
+		return err ? -1 : 1; 	
+	err |= __put_user(X86_FXSR_MAGIC, &buf->magic);
+	err |= __copy_to_user(&buf->_fxsr_env[0], &tsk->thread.i387.fxsave,
+			      sizeof(struct i387_fxsave_struct));
+	return err ? -1 : 1;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/ia32/ia32_binfmt.c linux-2.4.20/arch/x86_64/ia32/ia32_binfmt.c
--- linux-2.4.19/arch/x86_64/ia32/ia32_binfmt.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/ia32/ia32_binfmt.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,300 @@
+/* 
+ * Written 2000,2002 by Andi Kleen. 
+ * 
+ * Losely based on the sparc64 and IA64 32bit emulation loaders.
+ * This tricks binfmt_elf.c into loading 32bit binaries using lots 
+ * of ugly preprocessor tricks. Talk about very very poor man's inheritance.
+ */ 
+#include <linux/types.h>
+#include <linux/config.h> 
+#include <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <asm/segment.h> 
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/user32.h>
+#include <asm/sigcontext32.h>
+#include <asm/fpu32.h>
+#include <asm/i387.h>
+
+struct file;
+struct elf_phdr; 
+
+#define IA32_EMULATOR 1
+
+#define IA32_PAGE_OFFSET 0xFFFFF000
+#define IA32_STACK_TOP IA32_PAGE_OFFSET
+#define ELF_ET_DYN_BASE		(IA32_PAGE_OFFSET/3 + 0x1000000)
+
+#undef ELF_ARCH
+#define ELF_ARCH EM_386
+
+#undef ELF_CLASS
+#define ELF_CLASS ELFCLASS32
+
+#define ELF_DATA	ELFDATA2LSB
+
+#define USE_ELF_CORE_DUMP 1
+
+/* Overwrite elfcore.h */ 
+#define _LINUX_ELFCORE_H 1
+typedef unsigned int elf_greg_t;
+
+#define ELF_NGREG (sizeof (struct user_regs_struct32) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+struct elf_siginfo
+{
+	int	si_signo;			/* signal number */
+	int	si_code;			/* extra code */
+	int	si_errno;			/* errno */
+};
+
+struct timeval32
+{
+    int tv_sec, tv_usec;
+};
+
+struct elf_prstatus
+{
+	struct elf_siginfo pr_info;	/* Info associated with signal */
+	short	pr_cursig;		/* Current signal */
+	unsigned int pr_sigpend;	/* Set of pending signals */
+	unsigned int pr_sighold;	/* Set of held signals */
+	pid_t	pr_pid;
+	pid_t	pr_ppid;
+	pid_t	pr_pgrp;
+	pid_t	pr_sid;
+	struct timeval32 pr_utime;	/* User time */
+	struct timeval32 pr_stime;	/* System time */
+	struct timeval32 pr_cutime;	/* Cumulative user time */
+	struct timeval32 pr_cstime;	/* Cumulative system time */
+	elf_gregset_t pr_reg;	/* GP registers */
+	int pr_fpvalid;		/* True if math co-processor being used.  */
+};
+
+#define ELF_PRARGSZ	(80)	/* Number of chars for args */
+
+struct elf_prpsinfo
+{
+	char	pr_state;	/* numeric process state */
+	char	pr_sname;	/* char for pr_state */
+	char	pr_zomb;	/* zombie */
+	char	pr_nice;	/* nice val */
+	unsigned int pr_flag;	/* flags */
+	__u16	pr_uid;
+	__u16	pr_gid;
+	pid_t	pr_pid, pr_ppid, pr_pgrp, pr_sid;
+	/* Lots missing */
+	char	pr_fname[16];	/* filename of executable */
+	char	pr_psargs[ELF_PRARGSZ];	/* initial part of arg list */
+};
+
+#define __STR(x) #x
+#define STR(x) __STR(x)
+
+#define _GET_SEG(x) \
+	({ __u32 seg; asm("movl %%" STR(x) ",%0" : "=r"(seg)); seg; })
+
+/* Assumes current==process to be dumped */
+#define ELF_CORE_COPY_REGS(pr_reg, regs)       		\
+	pr_reg[0] = regs->rbx;				\
+	pr_reg[1] = regs->rcx;				\
+	pr_reg[2] = regs->rdx;				\
+	pr_reg[3] = regs->rsi;				\
+	pr_reg[4] = regs->rdi;				\
+	pr_reg[5] = regs->rbp;				\
+	pr_reg[6] = regs->rax;				\
+	pr_reg[7] = _GET_SEG(ds);   			\
+	pr_reg[8] = _GET_SEG(es);			\
+	pr_reg[9] = _GET_SEG(fs);			\
+	pr_reg[10] = _GET_SEG(gs);			\
+	pr_reg[11] = regs->orig_rax;			\
+	pr_reg[12] = regs->rip;				\
+	pr_reg[13] = regs->cs;				\
+	pr_reg[14] = regs->eflags;			\
+	pr_reg[15] = regs->rsp;				\
+	pr_reg[16] = regs->ss;
+
+#define user user32
+
+#define dump_fpu dump_fpu_ia32
+
+#define __ASM_X86_64_ELF_H 1
+#include <asm/ia32.h>
+#include <linux/elf.h>
+
+typedef struct user_i387_ia32_struct elf_fpregset_t;
+typedef struct user32_fxsr_struct elf_fpxregset_t;
+
+#undef elf_check_arch
+#define elf_check_arch(x) \
+	((x)->e_machine == EM_386)
+
+#define ELF_EXEC_PAGESIZE PAGE_SIZE
+#define ELF_HWCAP (boot_cpu_data.x86_capability[0])
+#define ELF_PLATFORM  ("i686")
+#define SET_PERSONALITY(ex, ibcs2)			\
+do {							\
+	set_personality((ibcs2)?PER_SVR4:current->personality);	\
+} while (0)
+
+/* Override some function names */
+#define elf_format			elf32_format
+
+#define init_elf_binfmt			init_elf32_binfmt
+#define exit_elf_binfmt			exit_elf32_binfmt
+
+#define load_elf_binary load_elf32_binary
+
+#undef CONFIG_BINFMT_ELF
+#ifdef CONFIG_BINFMT_ELF32
+# define CONFIG_BINFMT_ELF		CONFIG_BINFMT_ELF32
+#endif
+
+#undef CONFIG_BINFMT_ELF_MODULE
+#ifdef CONFIG_BINFMT_ELF32_MODULE
+# define CONFIG_BINFMT_ELF_MODULE	CONFIG_BINFMT_ELF32_MODULE
+#endif
+
+#define ELF_PLAT_INIT(r)		elf32_init(r)
+#define setup_arg_pages(bprm)		ia32_setup_arg_pages(bprm)
+
+#undef start_thread
+#define start_thread(regs,new_rip,new_rsp) do { \
+	__asm__("movl %0,%%fs": :"r" (0)); \
+	__asm__("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); \
+	wrmsrl(MSR_KERNEL_GS_BASE, 0); \
+	(regs)->rip = (new_rip); \
+	(regs)->rsp = (new_rsp); \
+	(regs)->eflags = 0x200; \
+	(regs)->cs = __USER32_CS; \
+	(regs)->ss = __USER32_DS; \
+	set_fs(USER_DS); \
+} while(0) 
+
+
+#define elf_map elf32_map
+
+MODULE_DESCRIPTION("Binary format loader for compatibility with IA32 ELF binaries."); 
+MODULE_AUTHOR("Eric Youngdale, Andi Kleen");
+
+#undef MODULE_DESCRIPTION
+#undef MODULE_AUTHOR
+
+#define elf_addr_t __u32
+#define elf_caddr_t __u32
+
+static void elf32_init(struct pt_regs *);
+int ia32_setup_arg_pages(struct linux_binprm *bprm);
+
+#include "../../../fs/binfmt_elf.c" 
+
+static void elf32_init(struct pt_regs *regs)
+{
+	struct task_struct *me = current; 
+	regs->rdi = 0;
+	regs->rsi = 0;
+	regs->rdx = 0;
+	regs->rcx = 0;
+	regs->rax = 0;
+	regs->rbx = 0; 
+	regs->rbp = 0; 
+	me->thread.fs = 0; 
+	me->thread.gs = 0;
+	me->thread.fsindex = 0; 
+	me->thread.gsindex = 0;
+	me->thread.ds = __USER_DS; 
+	me->thread.es = __USER_DS;
+	me->thread.flags |= THREAD_IA32;
+}
+
+extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address);
+ 
+
+int ia32_setup_arg_pages(struct linux_binprm *bprm)
+{
+	unsigned long stack_base;
+	struct vm_area_struct *mpnt;
+	int i;
+
+	stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
+
+	bprm->p += stack_base;
+	if (bprm->loader)
+		bprm->loader += stack_base;
+	bprm->exec += stack_base;
+
+	mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+	if (!mpnt) 
+		return -ENOMEM; 
+	
+	down_write(&current->mm->mmap_sem);
+	{
+		mpnt->vm_mm = current->mm;
+		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
+		mpnt->vm_end = IA32_STACK_TOP;
+		mpnt->vm_page_prot = PAGE_COPY;
+		mpnt->vm_flags = VM_STACK_FLAGS;
+		mpnt->vm_ops = NULL;
+		mpnt->vm_pgoff = 0;
+		mpnt->vm_file = NULL;
+		mpnt->vm_private_data = (void *) 0;
+		insert_vm_struct(current->mm, mpnt);
+		current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
+	} 
+
+	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+		struct page *page = bprm->page[i];
+		if (page) {
+			bprm->page[i] = NULL;
+			current->mm->rss++;
+			put_dirty_page(current,page,stack_base);
+		}
+		stack_base += PAGE_SIZE;
+	}
+	up_write(&current->mm->mmap_sem);
+	
+	return 0;
+}
+static unsigned long
+elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type)
+{
+	unsigned long map_addr;
+	struct task_struct *me = current; 
+
+	if (prot & PROT_READ) 
+		prot |= PROT_EXEC; 
+
+	down_write(&me->mm->mmap_sem);
+	map_addr = do_mmap(filep, ELF_PAGESTART(addr),
+			   eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, 
+			   type|MAP_32BIT,
+			   eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
+	up_write(&me->mm->mmap_sem);
+	return(map_addr);
+}
+
+int dump_fpu_ia32(struct pt_regs *regs, elf_fpregset_t *fp)
+{
+	struct _fpstate_ia32 *fpu = (void*)fp; 
+	struct task_struct *tsk = current;
+	mm_segment_t oldfs = get_fs();
+	int ret;
+
+	if (!tsk->used_math) 
+		return 0;
+	if (!(tsk->thread.flags & THREAD_IA32))
+		BUG(); 
+	unlazy_fpu(tsk);
+	set_fs(KERNEL_DS); 
+	ret = save_i387_ia32(current, fpu, regs, 1);
+	/* Correct for i386 bug. It puts the fop into the upper 16bits of 
+	   the tag word (like FXSAVE), not into the fcs*/ 
+	fpu->cssel |= fpu->tag & 0xffff0000; 
+	set_fs(oldfs); 
+	return ret; 
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/ia32/ia32_ioctl.c linux-2.4.20/arch/x86_64/ia32/ia32_ioctl.c
--- linux-2.4.19/arch/x86_64/ia32/ia32_ioctl.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/ia32/ia32_ioctl.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,4192 @@
+/* $Id: ia32_ioctl.c,v 1.24 2002/09/17 15:23:41 ak Exp $
+ * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
+ *
+ * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
+ * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
+ * Copyright (C) 2001,2002  Andi Kleen, SuSE Labs 
+ *
+ * These routines maintain argument size conversion between 32bit and 64bit
+ * ioctls.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/ioctl.h>
+#include <linux/if.h>
+#include <linux/slab.h>
+#include <linux/hdreg.h>
+#include <linux/raid/md.h>
+#include <linux/kd.h>
+#include <linux/dirent.h>
+#include <linux/route.h>
+#include <linux/in6.h>
+#include <linux/ipv6_route.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/vt.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/fd.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#include <linux/if_pppox.h>
+#include <linux/mtio.h>
+#include <linux/cdrom.h>
+#include <linux/loop.h>
+#include <linux/auto_fs.h>
+#include <linux/devfs_fs.h>
+#include <linux/tty.h>
+#include <linux/vt_kern.h>
+#include <linux/fb.h>
+#include <linux/ext2_fs.h>
+#include <linux/videodev.h>
+#include <linux/netdevice.h>
+#include <linux/raw.h>
+#include <linux/smb_fs.h>
+#include <linux/blkpg.h>
+#include <linux/blk.h>
+#include <linux/elevator.h>
+#include <linux/rtc.h>
+#include <linux/pci.h>
+#include <linux/rtc.h>
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/reiserfs_fs.h>
+#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
+/* Ugh. This header really is not clean */
+#define min min
+#define max max
+#include <linux/lvm.h>
+#endif /* LVM */
+
+#include <scsi/scsi.h>
+/* Ugly hack. */
+#undef __KERNEL__
+#include <scsi/scsi_ioctl.h>
+#define __KERNEL__
+#include <scsi/sg.h>
+
+#include <asm/types.h>
+#include <asm/ia32.h>
+#include <asm/uaccess.h>
+#include <linux/ethtool.h>
+#include <asm/module.h>
+#include <asm/ioctl32.h>
+#include <linux/soundcard.h>
+
+#include <linux/atm.h>
+#include <linux/atmarp.h>
+#include <linux/atmclip.h>
+#include <linux/atmdev.h>
+#include <linux/atmioc.h>
+#include <linux/atmlec.h>
+#include <linux/atmmpc.h>
+#include <linux/atmsvc.h>
+#include <linux/atm_tcp.h>
+#include <linux/sonet.h>
+#include <linux/atm_suni.h>
+
+#define A(__x) ((void *)(unsigned long)(__x))
+#define AA(__x)	A(__x)
+
+/* Aiee. Someone does not find a difference between int and long */
+#define EXT2_IOC32_GETFLAGS               _IOR('f', 1, int)
+#define EXT2_IOC32_SETFLAGS               _IOW('f', 2, int)
+#define EXT2_IOC32_GETVERSION             _IOR('v', 1, int)
+#define EXT2_IOC32_SETVERSION             _IOW('v', 2, int)
+
+extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+
+static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	int err;
+	unsigned long val;
+	
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&val);
+	set_fs (old_fs);
+	if (!err && put_user(val, (u32 *)arg))
+		return -EFAULT;
+	return err;
+}
+ 
+static int rw_long(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	int err;
+	unsigned long val;
+	
+	if(get_user(val, (u32 *)arg))
+		return -EFAULT;
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&val);
+	set_fs (old_fs);
+	if (!err && put_user(val, (u32 *)arg))
+		return -EFAULT;
+	return err;
+}
+
+static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	/* These are just misnamed, they actually get/put from/to user an int */
+	switch (cmd) {
+	case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break;
+	case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break;
+	case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break;
+	case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break;
+	}
+	return sys_ioctl(fd, cmd, arg);
+}
+ 
+struct video_tuner32 {
+	s32 tuner;
+	u8 name[32];
+	u32 rangelow, rangehigh;
+	u32 flags;
+	u16 mode, signal;
+};
+
+static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up)
+{
+	int i;
+
+	if(get_user(kp->tuner, &up->tuner))
+		return -EFAULT;
+	for(i = 0; i < 32; i++)
+		__get_user(kp->name[i], &up->name[i]);
+	__get_user(kp->rangelow, &up->rangelow);
+	__get_user(kp->rangehigh, &up->rangehigh);
+	__get_user(kp->flags, &up->flags);
+	__get_user(kp->mode, &up->mode);
+	__get_user(kp->signal, &up->signal);
+	return 0;
+}
+
+static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up)
+{
+	int i;
+
+	if(put_user(kp->tuner, &up->tuner))
+		return -EFAULT;
+	for(i = 0; i < 32; i++)
+		__put_user(kp->name[i], &up->name[i]);
+	__put_user(kp->rangelow, &up->rangelow);
+	__put_user(kp->rangehigh, &up->rangehigh);
+	__put_user(kp->flags, &up->flags);
+	__put_user(kp->mode, &up->mode);
+	__put_user(kp->signal, &up->signal);
+	return 0;
+}
+
+struct video_buffer32 {
+	/* void * */ u32 base;
+	s32 height, width, depth, bytesperline;
+};
+
+static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up)
+{
+	u32 tmp;
+
+	if(get_user(tmp, &up->base))
+		return -EFAULT;
+	kp->base = (void *) ((unsigned long)tmp);
+	__get_user(kp->height, &up->height);
+	__get_user(kp->width, &up->width);
+	__get_user(kp->depth, &up->depth);
+	__get_user(kp->bytesperline, &up->bytesperline);
+	return 0;
+}
+
+static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up)
+{
+	u32 tmp = (u32)((unsigned long)kp->base);
+
+	if(put_user(tmp, &up->base))
+		return -EFAULT;
+	__put_user(kp->height, &up->height);
+	__put_user(kp->width, &up->width);
+	__put_user(kp->depth, &up->depth);
+	__put_user(kp->bytesperline, &up->bytesperline);
+	return 0;
+}
+
+struct video_clip32 {
+	s32 x, y, width, height;
+	/* struct video_clip32 * */ u32 next;
+};
+
+struct video_window32 {
+	u32 x, y, width, height, chromakey, flags;
+	/* struct video_clip32 * */ u32 clips;
+	s32 clipcount;
+};
+
+static void free_kvideo_clips(struct video_window *kp)
+{
+	struct video_clip *cp;
+
+	cp = kp->clips;
+	if(cp != NULL)
+		kfree(cp);
+}
+
+static int get_video_window32(struct video_window *kp, struct video_window32 *up)
+{
+	struct video_clip32 *ucp;
+	struct video_clip *kcp;
+	int nclips, err, i;
+	u32 tmp;
+
+	if(get_user(kp->x, &up->x))
+		return -EFAULT;
+	__get_user(kp->y, &up->y);
+	__get_user(kp->width, &up->width);
+	__get_user(kp->height, &up->height);
+	__get_user(kp->chromakey, &up->chromakey);
+	__get_user(kp->flags, &up->flags);
+	__get_user(kp->clipcount, &up->clipcount);
+	__get_user(tmp, &up->clips);
+	ucp = (struct video_clip32 *)A(tmp);
+	kp->clips = NULL;
+
+	nclips = kp->clipcount;
+	if(nclips == 0)
+		return 0;
+
+	if(ucp == 0)
+		return -EINVAL;
+
+	/* Peculiar interface... */
+	if(nclips < 0)
+		nclips = VIDEO_CLIPMAP_SIZE;
+
+	kcp = kmalloc(nclips * sizeof(struct video_clip), GFP_KERNEL);
+	err = -ENOMEM;
+	if(kcp == NULL)
+		goto cleanup_and_err;
+
+	kp->clips = kcp;
+	for(i = 0; i < nclips; i++) {
+		__get_user(kcp[i].x, &ucp[i].x);
+		__get_user(kcp[i].y, &ucp[i].y);
+		__get_user(kcp[i].width, &ucp[i].width);
+		__get_user(kcp[i].height, &ucp[i].height);
+		kcp[nclips].next = NULL;
+	}
+
+	return 0;
+
+cleanup_and_err:
+	free_kvideo_clips(kp);
+	return err;
+}
+
+/* You get back everything except the clips... */
+static int put_video_window32(struct video_window *kp, struct video_window32 *up)
+{
+	if(put_user(kp->x, &up->x))
+		return -EFAULT;
+	__put_user(kp->y, &up->y);
+	__put_user(kp->width, &up->width);
+	__put_user(kp->height, &up->height);
+	__put_user(kp->chromakey, &up->chromakey);
+	__put_user(kp->flags, &up->flags);
+	__put_user(kp->clipcount, &up->clipcount);
+	return 0;
+}
+
+#define VIDIOCGTUNER32		_IOWR('v',4, struct video_tuner32)
+#define VIDIOCSTUNER32		_IOW('v',5, struct video_tuner32)
+#define VIDIOCGWIN32		_IOR('v',9, struct video_window32)
+#define VIDIOCSWIN32		_IOW('v',10, struct video_window32)
+#define VIDIOCGFBUF32		_IOR('v',11, struct video_buffer32)
+#define VIDIOCSFBUF32		_IOW('v',12, struct video_buffer32)
+#define VIDIOCGFREQ32		_IOR('v',14, u32)
+#define VIDIOCSFREQ32		_IOW('v',15, u32)
+
+static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	union {
+		struct video_tuner vt;
+		struct video_buffer vb;
+		struct video_window vw;
+		unsigned long vx;
+	} karg;
+	mm_segment_t old_fs = get_fs();
+	void *up = (void *)arg;
+	int err = 0;
+
+	/* First, convert the command. */
+	switch(cmd) {
+	case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
+	case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
+	case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
+	case VIDIOCSWIN32: cmd = VIDIOCSWIN; break;
+	case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
+	case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
+	case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
+	case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
+	};
+
+	switch(cmd) {
+	case VIDIOCSTUNER:
+	case VIDIOCGTUNER:
+		err = get_video_tuner32(&karg.vt, up);
+		break;
+
+	case VIDIOCSWIN:
+		err = get_video_window32(&karg.vw, up);
+		break;
+
+	case VIDIOCSFBUF:
+		err = get_video_buffer32(&karg.vb, up);
+		break;
+
+	case VIDIOCSFREQ:
+		err = get_user(karg.vx, (u32 *)up);
+		break;
+	};
+	if(err)
+		goto out;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&karg);
+	set_fs(old_fs);
+
+	if(cmd == VIDIOCSWIN)
+		free_kvideo_clips(&karg.vw);
+
+	if(err == 0) {
+		switch(cmd) {
+		case VIDIOCGTUNER:
+			err = put_video_tuner32(&karg.vt, up);
+			break;
+
+		case VIDIOCGWIN:
+			err = put_video_window32(&karg.vw, up);
+			break;
+
+		case VIDIOCGFBUF:
+			err = put_video_buffer32(&karg.vb, up);
+			break;
+
+		case VIDIOCGFREQ:
+			err = put_user(((u32)karg.vx), (u32 *)up);
+			break;
+		};
+	}
+out:
+	return err;
+}
+
+struct timeval32 {
+	int tv_sec;
+	int tv_usec;
+};
+
+static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct timeval32 *up = (struct timeval32 *)arg;
+	struct timeval ktv;
+	mm_segment_t old_fs = get_fs();
+	int err;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&ktv);
+	set_fs(old_fs);
+	if(!err) {
+		err = put_user(ktv.tv_sec, &up->tv_sec);
+		err |= __put_user(ktv.tv_usec, &up->tv_usec);
+	}
+	return err;
+}
+
+struct ifmap32 {
+	u32 mem_start;
+	u32 mem_end;
+	unsigned short base_addr;
+	unsigned char irq;
+	unsigned char dma;
+	unsigned char port;
+};
+
+struct ifreq32 {
+#define IFHWADDRLEN     6
+#define IFNAMSIZ        16
+        union {
+                char    ifrn_name[IFNAMSIZ];            /* if name, e.g. "en0" */
+        } ifr_ifrn;
+        union {
+                struct  sockaddr ifru_addr;
+                struct  sockaddr ifru_dstaddr;
+                struct  sockaddr ifru_broadaddr;
+                struct  sockaddr ifru_netmask;
+                struct  sockaddr ifru_hwaddr;
+                short   ifru_flags;
+                int     ifru_ivalue;
+                int     ifru_mtu;
+                struct  ifmap32 ifru_map;
+                char    ifru_slave[IFNAMSIZ];   /* Just fits the size */
+		char	ifru_newname[IFNAMSIZ];
+                __kernel_caddr_t32 ifru_data;
+        } ifr_ifru;
+};
+
+struct ifconf32 {
+        int     ifc_len;                        /* size of buffer       */
+        __kernel_caddr_t32  ifcbuf;
+};
+
+static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct net_device *dev;
+	struct ifreq32 ifr32;
+	int err;
+
+	if (copy_from_user(&ifr32, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+		return -EFAULT;
+
+	dev = dev_get_by_index(ifr32.ifr_ifindex);
+	if (!dev)
+		return -ENODEV;
+
+	strncpy(ifr32.ifr_name, dev->name, sizeof(ifr32.ifr_name)-1);
+	ifr32.ifr_name[sizeof(ifr32.ifr_name)-1] = 0; 
+	
+	err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32));
+	return (err ? -EFAULT : 0);
+}
+
+static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifconf32 ifc32;
+	struct ifconf ifc;
+	struct ifreq32 *ifr32;
+	struct ifreq *ifr;
+	mm_segment_t old_fs;
+	unsigned int i, j;
+	int err;
+
+	if (copy_from_user(&ifc32, (struct ifconf32 *)arg, sizeof(struct ifconf32)))
+		return -EFAULT;
+
+	if(ifc32.ifcbuf == 0) {
+		ifc32.ifc_len = 0;
+		ifc.ifc_len = 0;
+		ifc.ifc_buf = NULL;
+	} else {
+		ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) *
+			sizeof (struct ifreq);
+		ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL);
+		if (!ifc.ifc_buf)
+			return -ENOMEM;
+	}
+	ifr = ifc.ifc_req;
+	ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf);
+	for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) {
+		if (copy_from_user(ifr, ifr32, sizeof (struct ifreq32))) {
+			kfree (ifc.ifc_buf);
+			return -EFAULT;
+		}
+		ifr++;
+		ifr32++; 
+	}
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc);	
+	set_fs (old_fs);
+	if (!err) {
+		ifr = ifc.ifc_req;
+		ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf);
+		for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len;
+		     i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) {
+			int k = copy_to_user(ifr32, ifr, sizeof (struct ifreq32));
+			ifr32++;
+			ifr++;
+			if (k) {
+				err = -EFAULT;
+				break;
+			}
+		       
+		}
+		if (!err) {
+			if (ifc32.ifcbuf == 0) {
+				/* Translate from 64-bit structure multiple to
+				 * a 32-bit one.
+				 */
+				i = ifc.ifc_len;
+				i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32));
+				ifc32.ifc_len = i;
+			} else {
+				if (i <= ifc32.ifc_len)
+					ifc32.ifc_len = i;
+				else
+					ifc32.ifc_len = i - sizeof (struct ifreq32);
+			}
+			if (copy_to_user((struct ifconf32 *)arg, &ifc32, sizeof(struct ifconf32)))
+				err = -EFAULT;
+		}
+	}
+	if(ifc.ifc_buf != NULL)
+		kfree (ifc.ifc_buf);
+	return err;
+}
+
+static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifreq ifr;
+	mm_segment_t old_fs;
+	int err, len;
+	u32 data, ethcmd;
+	
+	if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+		return -EFAULT;
+	ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+	if (!ifr.ifr_data)
+		return -EAGAIN;
+
+	__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+
+	if (get_user(ethcmd, (u32 *)A(data))) {
+		err = -EFAULT;
+		goto out;
+	}
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO:	len = sizeof(struct ethtool_drvinfo); break;
+	case ETHTOOL_GSET:
+	case ETHTOOL_SSET:
+	default:		len = sizeof(struct ethtool_cmd); break;
+	}
+
+	if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
+	set_fs (old_fs);
+	if (!err) {
+		u32 data;
+
+		__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+		len = copy_to_user((char *)A(data), ifr.ifr_data, len);
+		if (len)
+			err = -EFAULT;
+	}
+
+out:
+	free_page((unsigned long)ifr.ifr_data);
+	return err;
+}
+
+static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifreq ifr;
+	mm_segment_t old_fs;
+	int err;
+	
+	switch (cmd) {
+	case SIOCSIFMAP:
+		err = copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(ifr.ifr_name));
+		err |= __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start));
+		err |= __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end));
+		err |= __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr));
+		err |= __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq));
+		err |= __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma));
+		err |= __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port));
+		if (err)
+			return -EFAULT;
+		break;
+	case SIOCGPPPSTATS:
+	case SIOCGPPPCSTATS:
+	case SIOCGPPPVER:
+		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+			return -EFAULT;
+		ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+		if (!ifr.ifr_data)
+			return -EAGAIN;
+		break;
+	default:
+		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+			return -EFAULT;
+		break;
+	}
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
+	set_fs (old_fs);
+	if (!err) {
+		switch (cmd) {
+		case SIOCGIFFLAGS:
+		case SIOCGIFMETRIC:
+		case SIOCGIFMTU:
+		case SIOCGIFMEM:
+		case SIOCGIFHWADDR:
+		case SIOCGIFINDEX:
+		case SIOCGIFADDR:
+		case SIOCGIFBRDADDR:
+		case SIOCGIFDSTADDR:
+		case SIOCGIFNETMASK:
+		case SIOCGIFTXQLEN:
+			if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32)))
+				return -EFAULT;
+			break;
+		case SIOCGPPPSTATS:
+		case SIOCGPPPCSTATS:
+		case SIOCGPPPVER:
+		{
+			u32 data;
+			int len;
+
+			__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+			if(cmd == SIOCGPPPVER)
+				len = strlen((char *)ifr.ifr_data) + 1;
+			else if(cmd == SIOCGPPPCSTATS)
+				len = sizeof(struct ppp_comp_stats);
+			else
+				len = sizeof(struct ppp_stats);
+
+			len = copy_to_user((char *)A(data), ifr.ifr_data, len);
+			free_page((unsigned long)ifr.ifr_data);
+			if(len)
+				return -EFAULT;
+			break;
+		}
+		case SIOCGIFMAP:
+			err = copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(ifr.ifr_name));
+			err |= __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start));
+			err |= __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end));
+			err |= __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr));
+			err |= __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq));
+			err |= __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma));
+			err |= __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port));
+			if (err)
+				err = -EFAULT;
+			break;
+		}
+	} else {
+		switch (cmd) {
+		case SIOCGPPPSTATS:
+		case SIOCGPPPCSTATS:
+		case SIOCGPPPVER:
+			free_page((unsigned long)ifr.ifr_data);
+			break;
+		}
+	}
+	return err;
+}
+
+struct rtentry32 {
+        u32   		rt_pad1;
+        struct sockaddr rt_dst;         /* target address               */
+        struct sockaddr rt_gateway;     /* gateway addr (RTF_GATEWAY)   */
+        struct sockaddr rt_genmask;     /* target network mask (IP)     */
+        unsigned short  rt_flags;
+        short           rt_pad2;
+        u32   		rt_pad3;
+        unsigned char   rt_tos;
+        unsigned char   rt_class;
+        short           rt_pad4;
+        short           rt_metric;      /* +1 for binary compatibility! */
+        /* char * */ u32 rt_dev;        /* forcing the device at add    */
+        u32   		rt_mtu;         /* per route MTU/Window         */
+        u32   		rt_window;      /* Window clamping              */
+        unsigned short  rt_irtt;        /* Initial RTT                  */
+
+};
+
+struct in6_rtmsg32 {
+	struct in6_addr		rtmsg_dst;
+	struct in6_addr		rtmsg_src;
+	struct in6_addr		rtmsg_gateway;
+	u32			rtmsg_type;
+	u16			rtmsg_dst_len;
+	u16			rtmsg_src_len;
+	u32			rtmsg_metric;
+	u32			rtmsg_info;
+	u32			rtmsg_flags;
+	s32			rtmsg_ifindex;
+};
+
+extern struct socket *sockfd_lookup(int fd, int *err);
+
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+	fput(sock->file);
+}
+
+static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	int ret;
+	void *r = NULL;
+	struct in6_rtmsg r6;
+	struct rtentry r4;
+	char devname[16];
+	u32 rtdev;
+	mm_segment_t old_fs = get_fs();
+	
+	struct socket *mysock = sockfd_lookup(fd, &ret);
+
+	if (mysock && mysock->sk && mysock->sk->family == AF_INET6) { /* ipv6 */
+		ret = copy_from_user (&r6.rtmsg_dst, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst),
+			3 * sizeof(struct in6_addr));
+		ret |= __get_user (r6.rtmsg_type, &(((struct in6_rtmsg32 *)arg)->rtmsg_type));
+		ret |= __get_user (r6.rtmsg_dst_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst_len));
+		ret |= __get_user (r6.rtmsg_src_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_src_len));
+		ret |= __get_user (r6.rtmsg_metric, &(((struct in6_rtmsg32 *)arg)->rtmsg_metric));
+		ret |= __get_user (r6.rtmsg_info, &(((struct in6_rtmsg32 *)arg)->rtmsg_info));
+		ret |= __get_user (r6.rtmsg_flags, &(((struct in6_rtmsg32 *)arg)->rtmsg_flags));
+		ret |= __get_user (r6.rtmsg_ifindex, &(((struct in6_rtmsg32 *)arg)->rtmsg_ifindex));
+		
+		r = (void *) &r6;
+	} else { /* ipv4 */
+		ret = copy_from_user (&r4.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr));
+		ret |= __get_user (r4.rt_flags, &(((struct rtentry32 *)arg)->rt_flags));
+		ret |= __get_user (r4.rt_metric, &(((struct rtentry32 *)arg)->rt_metric));
+		ret |= __get_user (r4.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu));
+		ret |= __get_user (r4.rt_window, &(((struct rtentry32 *)arg)->rt_window));
+		ret |= __get_user (r4.rt_irtt, &(((struct rtentry32 *)arg)->rt_irtt));
+		ret |= __get_user (rtdev, &(((struct rtentry32 *)arg)->rt_dev));
+		if (rtdev) {
+			ret |= copy_from_user (devname, (char *)A(rtdev), 15);
+			r4.rt_dev = devname; devname[15] = 0;
+		} else
+			r4.rt_dev = 0;
+
+		r = (void *) &r4;
+	}
+
+	if (ret)
+		return -EFAULT;
+
+	set_fs (KERNEL_DS);
+	ret = sys_ioctl (fd, cmd, (long) r);
+	set_fs (old_fs);
+
+	if (mysock)
+		sockfd_put(mysock);
+
+	return ret;
+}
+
+struct hd_geometry32 {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned short cylinders;
+	u32 start;
+};
+                        
+static int hdio_getgeo(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct hd_geometry geo;
+	int err;
+	
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo);
+	set_fs (old_fs);
+	if (!err) {
+		err = copy_to_user ((struct hd_geometry32 *)arg, &geo, 4);
+		err |= __put_user (geo.start, &(((struct hd_geometry32 *)arg)->start));
+	}
+	return err ? -EFAULT : 0;
+}
+
+struct  fbcmap32 {
+	int             index;          /* first element (0 origin) */
+	int             count;
+	u32		red;
+	u32		green;
+	u32		blue;
+};
+
+struct fb_fix_screeninfo32 {
+	char			id[16];
+        __kernel_caddr_t32	smem_start;
+	__u32			smem_len;
+	__u32			type;
+	__u32			type_aux;
+	__u32			visual;
+	__u16			xpanstep;
+	__u16			ypanstep;
+	__u16			ywrapstep;
+	__u32			line_length;
+        __kernel_caddr_t32	mmio_start;
+	__u32			mmio_len;
+	__u32			accel;
+	__u16			reserved[3];
+};
+
+struct fb_cmap32 {
+	__u32			start;
+	__u32			len;
+	__kernel_caddr_t32	red;
+	__kernel_caddr_t32	green;
+	__kernel_caddr_t32	blue;
+	__kernel_caddr_t32	transp;
+};
+
+static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	u32 red = 0, green = 0, blue = 0, transp = 0;
+	struct fb_fix_screeninfo fix;
+	struct fb_cmap cmap;
+	void *karg;
+	int err = 0;
+
+	memset(&cmap, 0, sizeof(cmap));
+	switch (cmd) {
+	case FBIOGET_FSCREENINFO:
+		karg = &fix;
+		break;
+	case FBIOGETCMAP:
+	case FBIOPUTCMAP:
+		karg = &cmap;
+		err = __get_user(cmap.start, &((struct fb_cmap32 *)arg)->start);
+		err |= __get_user(cmap.len, &((struct fb_cmap32 *)arg)->len);
+		err |= __get_user(red, &((struct fb_cmap32 *)arg)->red);
+		err |= __get_user(green, &((struct fb_cmap32 *)arg)->green);
+		err |= __get_user(blue, &((struct fb_cmap32 *)arg)->blue);
+		err |= __get_user(transp, &((struct fb_cmap32 *)arg)->transp);
+		if (err) {
+			err = -EFAULT;
+			goto out;
+		}
+		err = -ENOMEM;
+		cmap.red = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
+		if (!cmap.red)
+			goto out;
+		cmap.green = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
+		if (!cmap.green)
+			goto out;
+		cmap.blue = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
+		if (!cmap.blue)
+			goto out;
+		if (transp) {
+			cmap.transp = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
+			if (!cmap.transp)
+				goto out;
+		}
+			
+		if (cmd == FBIOGETCMAP)
+			break;
+
+		err = __copy_from_user(cmap.red, (char *)A(red), cmap.len * sizeof(__u16));
+		err |= __copy_from_user(cmap.green, (char *)A(green), cmap.len * sizeof(__u16));
+		err |= __copy_from_user(cmap.blue, (char *)A(blue), cmap.len * sizeof(__u16));
+		if (cmap.transp) err |= __copy_from_user(cmap.transp, (char *)A(transp), cmap.len * sizeof(__u16));
+		if (err) {
+			err = -EFAULT;
+			goto out;
+		}
+		break;
+	default:
+		do {
+			static int count = 0;
+			if (++count <= 20)
+				printk("%s: Unknown fb ioctl cmd fd(%d) "
+				       "cmd(%08x) arg(%08lx)\n",
+				       __FUNCTION__, fd, cmd, arg);
+		} while(0);
+		return -ENOSYS;
+	}
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)karg);
+	set_fs(old_fs);
+	if (err)
+		goto out;
+	switch (cmd) {
+	case FBIOGET_FSCREENINFO:
+		err = __copy_to_user((char *)((struct fb_fix_screeninfo32 *)arg)->id, (char *)fix.id, sizeof(fix.id));
+		err |= __put_user((__u32)(unsigned long)fix.smem_start, &((struct fb_fix_screeninfo32 *)arg)->smem_start);
+		err |= __put_user(fix.smem_len, &((struct fb_fix_screeninfo32 *)arg)->smem_len);
+		err |= __put_user(fix.type, &((struct fb_fix_screeninfo32 *)arg)->type);
+		err |= __put_user(fix.type_aux, &((struct fb_fix_screeninfo32 *)arg)->type_aux);
+		err |= __put_user(fix.visual, &((struct fb_fix_screeninfo32 *)arg)->visual);
+		err |= __put_user(fix.xpanstep, &((struct fb_fix_screeninfo32 *)arg)->xpanstep);
+		err |= __put_user(fix.ypanstep, &((struct fb_fix_screeninfo32 *)arg)->ypanstep);
+		err |= __put_user(fix.ywrapstep, &((struct fb_fix_screeninfo32 *)arg)->ywrapstep);
+		err |= __put_user(fix.line_length, &((struct fb_fix_screeninfo32 *)arg)->line_length);
+		err |= __put_user((__u32)(unsigned long)fix.mmio_start, &((struct fb_fix_screeninfo32 *)arg)->mmio_start);
+		err |= __put_user(fix.mmio_len, &((struct fb_fix_screeninfo32 *)arg)->mmio_len);
+		err |= __put_user(fix.accel, &((struct fb_fix_screeninfo32 *)arg)->accel);
+		err |= __copy_to_user((char *)((struct fb_fix_screeninfo32 *)arg)->reserved, (char *)fix.reserved, sizeof(fix.reserved));
+		break;
+	case FBIOGETCMAP:
+		err = __copy_to_user((char *)A(red), cmap.red, cmap.len * sizeof(__u16));
+		err |= __copy_to_user((char *)A(green), cmap.blue, cmap.len * sizeof(__u16));
+		err |= __copy_to_user((char *)A(blue), cmap.blue, cmap.len * sizeof(__u16));
+		if (cmap.transp)
+			err |= __copy_to_user((char *)A(transp), cmap.transp, cmap.len * sizeof(__u16));
+		break;
+	case FBIOPUTCMAP:
+		break;
+	}
+	if (err)
+		err = -EFAULT;
+
+out:	if (cmap.red) kfree(cmap.red);
+	if (cmap.green) kfree(cmap.green);
+	if (cmap.blue) kfree(cmap.blue);
+	if (cmap.transp) kfree(cmap.transp);
+	return err;
+}
+
+static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	unsigned long kval;
+	unsigned int *uvp;
+	int error;
+
+	set_fs(KERNEL_DS);
+	error = sys_ioctl(fd, cmd, (long)&kval);
+	set_fs(old_fs);
+
+	if(error == 0) {
+		uvp = (unsigned int *)arg;
+		if(put_user(kval, uvp))
+			error = -EFAULT;
+	}
+	return error;
+}
+
+struct floppy_struct32 {
+	unsigned int	size;
+	unsigned int	sect;
+	unsigned int	head;
+	unsigned int	track;
+	unsigned int	stretch;
+	unsigned char	gap;
+	unsigned char	rate;
+	unsigned char	spec1;
+	unsigned char	fmt_gap;
+	const __kernel_caddr_t32 name;
+};
+
+struct floppy_drive_params32 {
+	char		cmos;
+	u32		max_dtr;
+	u32		hlt;
+	u32		hut;
+	u32		srt;
+	u32		spinup;
+	u32		spindown;
+	unsigned char	spindown_offset;
+	unsigned char	select_delay;
+	unsigned char	rps;
+	unsigned char	tracks;
+	u32		timeout;
+	unsigned char	interleave_sect;
+	struct floppy_max_errors max_errors;
+	char		flags;
+	char		read_track;
+	short		autodetect[8];
+	int		checkfreq;
+	int		native_format;
+};
+
+struct floppy_drive_struct32 {
+	signed char	flags;
+	u32		spinup_date;
+	u32		select_date;
+	u32		first_read_date;
+	short		probed_format;
+	short		track;
+	short		maxblock;
+	short		maxtrack;
+	int		generation;
+	int		keep_data;
+	int		fd_ref;
+	int		fd_device;
+	int		last_checked;
+	__kernel_caddr_t32 dmabuf;
+	int		bufblocks;
+};
+
+struct floppy_fdc_state32 {
+	int		spec1;
+	int		spec2;
+	int		dtr;
+	unsigned char	version;
+	unsigned char	dor;
+	u32		address;
+	unsigned int	rawcmd:2;
+	unsigned int	reset:1;
+	unsigned int	need_configure:1;
+	unsigned int	perp_mode:2;
+	unsigned int	has_fifo:1;
+	unsigned int	driver_version;
+	unsigned char	track[4];
+};
+
+struct floppy_write_errors32 {
+	unsigned int	write_errors;
+	u32		first_error_sector;
+	int		first_error_generation;
+	u32		last_error_sector;
+	int		last_error_generation;
+	unsigned int	badness;
+};
+
+#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32)
+#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32)
+#define FDGETPRM32 _IOR(2, 0x04, struct floppy_struct32)
+#define FDSETDRVPRM32 _IOW(2, 0x90, struct floppy_drive_params32)
+#define FDGETDRVPRM32 _IOR(2, 0x11, struct floppy_drive_params32)
+#define FDGETDRVSTAT32 _IOR(2, 0x12, struct floppy_drive_struct32)
+#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct floppy_drive_struct32)
+#define FDGETFDCSTAT32 _IOR(2, 0x15, struct floppy_fdc_state32)
+#define FDWERRORGET32  _IOR(2, 0x17, struct floppy_write_errors32)
+
+static struct {
+	unsigned int	cmd32;
+	unsigned int	cmd;
+} fd_ioctl_trans_table[] = {
+	{ FDSETPRM32, FDSETPRM },
+	{ FDDEFPRM32, FDDEFPRM },
+	{ FDGETPRM32, FDGETPRM },
+	{ FDSETDRVPRM32, FDSETDRVPRM },
+	{ FDGETDRVPRM32, FDGETDRVPRM },
+	{ FDGETDRVSTAT32, FDGETDRVSTAT },
+	{ FDPOLLDRVSTAT32, FDPOLLDRVSTAT },
+	{ FDGETFDCSTAT32, FDGETFDCSTAT },
+	{ FDWERRORGET32, FDWERRORGET }
+};
+
+#define NR_FD_IOCTL_TRANS (sizeof(fd_ioctl_trans_table)/sizeof(fd_ioctl_trans_table[0]))
+
+static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	void *karg = NULL;
+	unsigned int kcmd = 0;
+	int i, err;
+
+	for (i = 0; i < NR_FD_IOCTL_TRANS; i++)
+		if (cmd == fd_ioctl_trans_table[i].cmd32) {
+			kcmd = fd_ioctl_trans_table[i].cmd;
+			break;
+		}
+	if (!kcmd)
+		return -EINVAL;
+
+	switch (cmd) {
+		case FDSETPRM32:
+		case FDDEFPRM32:
+		case FDGETPRM32:
+		{
+			struct floppy_struct *f;
+
+			f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL);
+			if (!karg)
+				return -ENOMEM;
+			if (cmd == FDGETPRM32)
+				break;
+			err = __get_user(f->size, &((struct floppy_struct32 *)arg)->size);
+			err |= __get_user(f->sect, &((struct floppy_struct32 *)arg)->sect);
+			err |= __get_user(f->head, &((struct floppy_struct32 *)arg)->head);
+			err |= __get_user(f->track, &((struct floppy_struct32 *)arg)->track);
+			err |= __get_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch);
+			err |= __get_user(f->gap, &((struct floppy_struct32 *)arg)->gap);
+			err |= __get_user(f->rate, &((struct floppy_struct32 *)arg)->rate);
+			err |= __get_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1);
+			err |= __get_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap);
+			err |= __get_user((u64)f->name, &((struct floppy_struct32 *)arg)->name);
+			if (err) {
+				err = -EFAULT;
+				goto out;
+			}
+			break;
+		}
+		case FDSETDRVPRM32:
+		case FDGETDRVPRM32:
+		{
+			struct floppy_drive_params *f;
+
+			f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL);
+			if (!karg)
+				return -ENOMEM;
+			if (cmd == FDGETDRVPRM32)
+				break;
+			err = __get_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos);
+			err |= __get_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr);
+			err |= __get_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt);
+			err |= __get_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut);
+			err |= __get_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt);
+			err |= __get_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup);
+			err |= __get_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown);
+			err |= __get_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset);
+			err |= __get_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay);
+			err |= __get_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps);
+			err |= __get_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks);
+			err |= __get_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout);
+			err |= __get_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect);
+			err |= __copy_from_user(&f->max_errors, &((struct floppy_drive_params32 *)arg)->max_errors, sizeof(f->max_errors));
+			err |= __get_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags);
+			err |= __get_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track);
+			err |= __copy_from_user(f->autodetect, ((struct floppy_drive_params32 *)arg)->autodetect, sizeof(f->autodetect));
+			err |= __get_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq);
+			err |= __get_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format);
+			if (err) {
+				err = -EFAULT;
+				goto out;
+			}
+			break;
+		}
+		case FDGETDRVSTAT32:
+		case FDPOLLDRVSTAT32:
+			karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL);
+			if (!karg)
+				return -ENOMEM;
+			break;
+		case FDGETFDCSTAT32:
+			karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL);
+			if (!karg)
+				return -ENOMEM;
+			break;
+		case FDWERRORGET32:
+			karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL);
+			if (!karg)
+				return -ENOMEM;
+			break;
+		default:
+			return -EINVAL;
+	}
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, kcmd, (unsigned long)karg);
+	set_fs (old_fs);
+	if (err)
+		goto out;
+	switch (cmd) {
+		case FDGETPRM32:
+		{
+			struct floppy_struct *f = karg;
+
+			err = __put_user(f->size, &((struct floppy_struct32 *)arg)->size);
+			err |= __put_user(f->sect, &((struct floppy_struct32 *)arg)->sect);
+			err |= __put_user(f->head, &((struct floppy_struct32 *)arg)->head);
+			err |= __put_user(f->track, &((struct floppy_struct32 *)arg)->track);
+			err |= __put_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch);
+			err |= __put_user(f->gap, &((struct floppy_struct32 *)arg)->gap);
+			err |= __put_user(f->rate, &((struct floppy_struct32 *)arg)->rate);
+			err |= __put_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1);
+			err |= __put_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap);
+			err |= __put_user((u64)f->name, &((struct floppy_struct32 *)arg)->name);
+			break;
+		}
+		case FDGETDRVPRM32:
+		{
+			struct floppy_drive_params *f = karg;
+
+			err = __put_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos);
+			err |= __put_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr);
+			err |= __put_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt);
+			err |= __put_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut);
+			err |= __put_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt);
+			err |= __put_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup);
+			err |= __put_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown);
+			err |= __put_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset);
+			err |= __put_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay);
+			err |= __put_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps);
+			err |= __put_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks);
+			err |= __put_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout);
+			err |= __put_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect);
+			err |= __copy_to_user(&((struct floppy_drive_params32 *)arg)->max_errors, &f->max_errors, sizeof(f->max_errors));
+			err |= __put_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags);
+			err |= __put_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track);
+			err |= __copy_to_user(((struct floppy_drive_params32 *)arg)->autodetect, f->autodetect, sizeof(f->autodetect));
+			err |= __put_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq);
+			err |= __put_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format);
+			break;
+		}
+		case FDGETDRVSTAT32:
+		case FDPOLLDRVSTAT32:
+		{
+			struct floppy_drive_struct *f = karg;
+
+			err = __put_user(f->flags, &((struct floppy_drive_struct32 *)arg)->flags);
+			err |= __put_user(f->spinup_date, &((struct floppy_drive_struct32 *)arg)->spinup_date);
+			err |= __put_user(f->select_date, &((struct floppy_drive_struct32 *)arg)->select_date);
+			err |= __put_user(f->first_read_date, &((struct floppy_drive_struct32 *)arg)->first_read_date);
+			err |= __put_user(f->probed_format, &((struct floppy_drive_struct32 *)arg)->probed_format);
+			err |= __put_user(f->track, &((struct floppy_drive_struct32 *)arg)->track);
+			err |= __put_user(f->maxblock, &((struct floppy_drive_struct32 *)arg)->maxblock);
+			err |= __put_user(f->maxtrack, &((struct floppy_drive_struct32 *)arg)->maxtrack);
+			err |= __put_user(f->generation, &((struct floppy_drive_struct32 *)arg)->generation);
+			err |= __put_user(f->keep_data, &((struct floppy_drive_struct32 *)arg)->keep_data);
+			err |= __put_user(f->fd_ref, &((struct floppy_drive_struct32 *)arg)->fd_ref);
+			err |= __put_user(f->fd_device, &((struct floppy_drive_struct32 *)arg)->fd_device);
+			err |= __put_user(f->last_checked, &((struct floppy_drive_struct32 *)arg)->last_checked);
+			err |= __put_user((u64)f->dmabuf, &((struct floppy_drive_struct32 *)arg)->dmabuf);
+			err |= __put_user((u64)f->bufblocks, &((struct floppy_drive_struct32 *)arg)->bufblocks);
+			break;
+		}
+		case FDGETFDCSTAT32:
+		{
+			struct floppy_fdc_state *f = karg;
+
+			err = __put_user(f->spec1, &((struct floppy_fdc_state32 *)arg)->spec1);
+			err |= __put_user(f->spec2, &((struct floppy_fdc_state32 *)arg)->spec2);
+			err |= __put_user(f->dtr, &((struct floppy_fdc_state32 *)arg)->dtr);
+			err |= __put_user(f->version, &((struct floppy_fdc_state32 *)arg)->version);
+			err |= __put_user(f->dor, &((struct floppy_fdc_state32 *)arg)->dor);
+			err |= __put_user(f->address, &((struct floppy_fdc_state32 *)arg)->address);
+			err |= __copy_to_user((char *)&((struct floppy_fdc_state32 *)arg)->address
+			    		   + sizeof(((struct floppy_fdc_state32 *)arg)->address),
+					   (char *)&f->address + sizeof(f->address), sizeof(int));
+			err |= __put_user(f->driver_version, &((struct floppy_fdc_state32 *)arg)->driver_version);
+			err |= __copy_to_user(((struct floppy_fdc_state32 *)arg)->track, f->track, sizeof(f->track));
+			break;
+		}
+		case FDWERRORGET32:
+		{
+			struct floppy_write_errors *f = karg;
+
+			err = __put_user(f->write_errors, &((struct floppy_write_errors32 *)arg)->write_errors);
+			err |= __put_user(f->first_error_sector, &((struct floppy_write_errors32 *)arg)->first_error_sector);
+			err |= __put_user(f->first_error_generation, &((struct floppy_write_errors32 *)arg)->first_error_generation);
+			err |= __put_user(f->last_error_sector, &((struct floppy_write_errors32 *)arg)->last_error_sector);
+			err |= __put_user(f->last_error_generation, &((struct floppy_write_errors32 *)arg)->last_error_generation);
+			err |= __put_user(f->badness, &((struct floppy_write_errors32 *)arg)->badness);
+			break;
+		}
+		default:
+			break;
+	}
+	if (err)
+		err = -EFAULT;
+
+out:	if (karg) kfree(karg);
+	return err;
+}
+
+struct ppp_option_data32 {
+	__kernel_caddr_t32	ptr;
+	__u32			length;
+	int			transmit;
+};
+#define PPPIOCSCOMPRESS32	_IOW('t', 77, struct ppp_option_data32)
+
+struct ppp_idle32 {
+	__kernel_time_t32 xmit_idle;
+	__kernel_time_t32 recv_idle;
+};
+#define PPPIOCGIDLE32		_IOR('t', 63, struct ppp_idle32)
+
+static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct ppp_option_data32 data32;
+	struct ppp_option_data data;
+	struct ppp_idle32 idle32;
+	struct ppp_idle idle;
+	unsigned int kcmd;
+	void *karg;
+	int err = 0;
+
+	switch (cmd) {
+	case PPPIOCGIDLE32:
+		kcmd = PPPIOCGIDLE;
+		karg = &idle;
+		break;
+	case PPPIOCSCOMPRESS32:
+		if (copy_from_user(&data32, (struct ppp_option_data32 *)arg, sizeof(struct ppp_option_data32)))
+			return -EFAULT;
+		data.ptr = kmalloc (data32.length, GFP_KERNEL);
+		if (!data.ptr)
+			return -ENOMEM;
+		if (copy_from_user(data.ptr, (__u8 *)A(data32.ptr), data32.length)) {
+			kfree(data.ptr);
+			return -EFAULT;
+		}
+		data.length = data32.length;
+		data.transmit = data32.transmit;
+		kcmd = PPPIOCSCOMPRESS;
+		karg = &data;
+		break;
+	default:
+		do {
+			static int count = 0;
+			if (++count <= 20)
+				printk("ppp_ioctl: Unknown cmd fd(%d) "
+				       "cmd(%08x) arg(%08x)\n",
+				       (int)fd, (unsigned int)cmd, (unsigned int)arg);
+		} while(0);
+		return -EINVAL;
+	}
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, kcmd, (unsigned long)karg);
+	set_fs (old_fs);
+	switch (cmd) {
+	case PPPIOCGIDLE32:
+		if (err)
+			return err;
+		idle32.xmit_idle = idle.xmit_idle;
+		idle32.recv_idle = idle.recv_idle;
+		if (copy_to_user((struct ppp_idle32 *)arg, &idle32, sizeof(struct ppp_idle32)))
+			return -EFAULT;
+		break;
+	case PPPIOCSCOMPRESS32:
+		kfree(data.ptr);
+		break;
+	default:
+		break;
+	}
+	return err;
+}
+
+
+struct mtget32 {
+	__u32	mt_type;
+	__u32	mt_resid;
+	__u32	mt_dsreg;
+	__u32	mt_gstat;
+	__u32	mt_erreg;
+	__kernel_daddr_t32	mt_fileno;
+	__kernel_daddr_t32	mt_blkno;
+};
+#define MTIOCGET32	_IOR('m', 2, struct mtget32)
+
+struct mtpos32 {
+	__u32	mt_blkno;
+};
+#define MTIOCPOS32	_IOR('m', 3, struct mtpos32)
+
+struct mtconfiginfo32 {
+	__u32	mt_type;
+	__u32	ifc_type;
+	__u16	irqnr;
+	__u16	dmanr;
+	__u16	port;
+	__u32	debug;
+	__u32	have_dens:1;
+	__u32	have_bsf:1;
+	__u32	have_fsr:1;
+	__u32	have_bsr:1;
+	__u32	have_eod:1;
+	__u32	have_seek:1;
+	__u32	have_tell:1;
+	__u32	have_ras1:1;
+	__u32	have_ras2:1;
+	__u32	have_ras3:1;
+	__u32	have_qfa:1;
+	__u32	pad1:5;
+	char	reserved[10];
+};
+#define	MTIOCGETCONFIG32	_IOR('m', 4, struct mtconfiginfo32)
+#define	MTIOCSETCONFIG32	_IOW('m', 5, struct mtconfiginfo32)
+
+static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct mtconfiginfo info;
+	struct mtget get;
+	struct mtpos pos;
+	unsigned long kcmd;
+	void *karg;
+	int err = 0;
+
+	switch(cmd) {
+	case MTIOCPOS32:
+		kcmd = MTIOCPOS;
+		karg = &pos;
+		break;
+	case MTIOCGET32:
+		kcmd = MTIOCGET;
+		karg = &get;
+		break;
+	case MTIOCGETCONFIG32:
+		kcmd = MTIOCGETCONFIG;
+		karg = &info;
+		break;
+	case MTIOCSETCONFIG32:
+		kcmd = MTIOCSETCONFIG;
+		karg = &info;
+		err = __get_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type);
+		err |= __get_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type);
+		err |= __get_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr);
+		err |= __get_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr);
+		err |= __get_user(info.port, &((struct mtconfiginfo32 *)arg)->port);
+		err |= __get_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug);
+		err |= __copy_from_user((char *)&info.debug + sizeof(info.debug),
+				     (char *)&((struct mtconfiginfo32 *)arg)->debug
+				     + sizeof(((struct mtconfiginfo32 *)arg)->debug), sizeof(__u32));
+		if (err)
+			return -EFAULT;
+		break;
+	default:
+		do {
+			static int count = 0;
+			if (++count <= 20)
+				printk("mt_ioctl: Unknown cmd fd(%d) "
+				       "cmd(%08x) arg(%08x)\n",
+				       (int)fd, (unsigned int)cmd, (unsigned int)arg);
+		} while(0);
+		return -EINVAL;
+	}
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, kcmd, (unsigned long)karg);
+	set_fs (old_fs);
+	if (err)
+		return err;
+	switch (cmd) {
+	case MTIOCPOS32:
+		err = __put_user(pos.mt_blkno, &((struct mtpos32 *)arg)->mt_blkno);
+		break;
+	case MTIOCGET32:
+		err = __put_user(get.mt_type, &((struct mtget32 *)arg)->mt_type);
+		err |= __put_user(get.mt_resid, &((struct mtget32 *)arg)->mt_resid);
+		err |= __put_user(get.mt_dsreg, &((struct mtget32 *)arg)->mt_dsreg);
+		err |= __put_user(get.mt_gstat, &((struct mtget32 *)arg)->mt_gstat);
+		err |= __put_user(get.mt_erreg, &((struct mtget32 *)arg)->mt_erreg);
+		err |= __put_user(get.mt_fileno, &((struct mtget32 *)arg)->mt_fileno);
+		err |= __put_user(get.mt_blkno, &((struct mtget32 *)arg)->mt_blkno);
+		break;
+	case MTIOCGETCONFIG32:
+		err = __put_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type);
+		err |= __put_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type);
+		err |= __put_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr);
+		err |= __put_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr);
+		err |= __put_user(info.port, &((struct mtconfiginfo32 *)arg)->port);
+		err |= __put_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug);
+		err |= __copy_to_user((char *)&((struct mtconfiginfo32 *)arg)->debug
+			    		   + sizeof(((struct mtconfiginfo32 *)arg)->debug),
+					   (char *)&info.debug + sizeof(info.debug), sizeof(__u32));
+		break;
+	case MTIOCSETCONFIG32:
+		break;
+	}
+	return err ? -EFAULT: 0;
+}
+
+struct cdrom_read32 {
+	int			cdread_lba;
+	__kernel_caddr_t32	cdread_bufaddr;
+	int			cdread_buflen;
+};
+
+struct cdrom_read_audio32 {
+	union cdrom_addr	addr;
+	u_char			addr_format;
+	int			nframes;
+	__kernel_caddr_t32	buf;
+};
+
+struct cdrom_generic_command32 {
+	unsigned char		cmd[CDROM_PACKET_SIZE];
+	__kernel_caddr_t32	buffer;
+	unsigned int		buflen;
+	int			stat;
+	__kernel_caddr_t32	sense;
+	__kernel_caddr_t32	reserved[3];
+};
+
+static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct cdrom_read cdread;
+	struct cdrom_read_audio cdreadaudio;
+	struct cdrom_generic_command cgc;
+	__kernel_caddr_t32 addr;
+	char *data = 0;
+	void *karg;
+	int err = 0;
+
+	switch(cmd) {
+	case CDROMREADMODE2:
+	case CDROMREADMODE1:
+	case CDROMREADRAW:
+	case CDROMREADCOOKED:
+		karg = &cdread;
+		err = __get_user(cdread.cdread_lba, &((struct cdrom_read32 *)arg)->cdread_lba);
+		err |= __get_user(addr, &((struct cdrom_read32 *)arg)->cdread_bufaddr);
+		err |= __get_user(cdread.cdread_buflen, &((struct cdrom_read32 *)arg)->cdread_buflen);
+		if (err)
+			return -EFAULT;
+		data = kmalloc(cdread.cdread_buflen, GFP_KERNEL);
+		if (!data)
+			return -ENOMEM;
+		cdread.cdread_bufaddr = data;
+		break;
+	case CDROMREADAUDIO:
+		karg = &cdreadaudio;
+		err = copy_from_user(&cdreadaudio.addr, &((struct cdrom_read_audio32 *)arg)->addr, sizeof(cdreadaudio.addr));
+		err |= __get_user(cdreadaudio.addr_format, &((struct cdrom_read_audio32 *)arg)->addr_format);
+		err |= __get_user(cdreadaudio.nframes, &((struct cdrom_read_audio32 *)arg)->nframes); 
+		err |= __get_user(addr, &((struct cdrom_read_audio32 *)arg)->buf);
+		if (err)
+			return -EFAULT;
+		data = kmalloc(cdreadaudio.nframes * 2352, GFP_KERNEL);
+		if (!data)
+			return -ENOMEM;
+		cdreadaudio.buf = data;
+		break;
+	case CDROM_SEND_PACKET:
+		karg = &cgc;
+		err = copy_from_user(cgc.cmd, &((struct cdrom_generic_command32 *)arg)->cmd, sizeof(cgc.cmd));
+		err |= __get_user(addr, &((struct cdrom_generic_command32 *)arg)->buffer);
+		err |= __get_user(cgc.buflen, &((struct cdrom_generic_command32 *)arg)->buflen);
+		if (err)
+			return -EFAULT;
+		if ((data = kmalloc(cgc.buflen, GFP_KERNEL)) == NULL)
+			return -ENOMEM;
+		cgc.buffer = data;
+		break;
+	default:
+		do {
+			static int count = 0;
+			if (++count <= 20)
+				printk("cdrom_ioctl: Unknown cmd fd(%d) "
+				       "cmd(%08x) arg(%08x)\n",
+				       (int)fd, (unsigned int)cmd, (unsigned int)arg);
+		} while(0);
+		return -EINVAL;
+	}
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)karg);
+	set_fs (old_fs);
+	if (err)
+		goto out;
+	switch (cmd) {
+	case CDROMREADMODE2:
+	case CDROMREADMODE1:
+	case CDROMREADRAW:
+	case CDROMREADCOOKED:
+		err = copy_to_user((char *)A(addr), data, cdread.cdread_buflen);
+		break;
+	case CDROMREADAUDIO:
+		err = copy_to_user((char *)A(addr), data, cdreadaudio.nframes * 2352);
+		break;
+	case CDROM_SEND_PACKET:
+		err = copy_to_user((char *)A(addr), data, cgc.buflen);
+		break;
+	default:
+		break;
+	}
+out:	if (data)
+		kfree(data);
+	return err ? -EFAULT : 0;
+}
+
+struct loop_info32 {
+	int			lo_number;      /* ioctl r/o */
+	__kernel_dev_t32	lo_device;      /* ioctl r/o */
+	unsigned int		lo_inode;       /* ioctl r/o */
+	__kernel_dev_t32	lo_rdevice;     /* ioctl r/o */
+	int			lo_offset;
+	int			lo_encrypt_type;
+	int			lo_encrypt_key_size;    /* ioctl w/o */
+	int			lo_flags;       /* ioctl r/o */
+	char			lo_name[LO_NAME_SIZE];
+	unsigned char		lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+	unsigned int		lo_init[2];
+	char			reserved[4];
+};
+
+static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct loop_info l;
+	int err = -EINVAL;
+
+	switch(cmd) {
+	case LOOP_SET_STATUS:
+		err = get_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number);
+		err |= __get_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device);
+		err |= __get_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode);
+		err |= __get_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice);
+		err |= __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)arg)->lo_offset,
+					   8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
+		if (err) {
+			err = -EFAULT;
+		} else {
+			set_fs (KERNEL_DS);
+			err = sys_ioctl (fd, cmd, (unsigned long)&l);
+			set_fs (old_fs);
+		}
+		break;
+	case LOOP_GET_STATUS:
+		set_fs (KERNEL_DS);
+		err = sys_ioctl (fd, cmd, (unsigned long)&l);
+		set_fs (old_fs);
+		if (!err) {
+			err = put_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number);
+			err |= __put_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device);
+			err |= __put_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode);
+			err |= __put_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice);
+			err |= __copy_to_user((char *)&((struct loop_info32 *)arg)->lo_offset,
+					   (char *)&l.lo_offset, (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
+			if (err)
+				err = -EFAULT;
+		}
+		break;
+	default: {
+		static int count = 0;
+		if (++count <= 20)
+			printk("%s: Unknown loop ioctl cmd, fd(%d) "
+			       "cmd(%08x) arg(%08lx)\n",
+			       __FUNCTION__, fd, cmd, arg);
+	}
+	}
+	return err;
+}
+
+extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg);
+
+static int vt_check(struct file *file)
+{
+	struct tty_struct *tty;
+	struct inode *inode = file->f_dentry->d_inode;
+	
+	if (file->f_op->ioctl != tty_ioctl)
+		return -EINVAL;
+	                
+	tty = (struct tty_struct *)file->private_data;
+	if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))
+		return -EINVAL;
+	                                                
+	if (tty->driver.ioctl != vt_ioctl)
+		return -EINVAL;
+	
+	/*
+	 * To have permissions to do most of the vt ioctls, we either have
+	 * to be the owner of the tty, or super-user.
+	 */
+	if (current->tty == tty || suser())
+		return 1;
+	return 0;                                                    
+}
+
+struct consolefontdesc32 {
+	unsigned short charcount;       /* characters in font (256 or 512) */
+	unsigned short charheight;      /* scan lines per character (1-32) */
+	u32 chardata;			/* font data in expanded form */
+};
+
+static int do_fontx_ioctl(unsigned int fd, int cmd, struct consolefontdesc32 *user_cfd, struct file *file)
+{
+	struct consolefontdesc cfdarg;
+	struct console_font_op op;
+	int i, perm;
+
+	perm = vt_check(file);
+	if (perm < 0) return perm;
+	
+	if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc32)))
+		return -EFAULT;
+	
+	cfdarg.chardata = (unsigned char *)A(((struct consolefontdesc32 *)&cfdarg)->chardata);
+ 	
+	switch (cmd) {
+	case PIO_FONTX:
+		if (!perm)
+			return -EPERM;
+		op.op = KD_FONT_OP_SET;
+		op.flags = 0;
+		op.width = 8;
+		op.height = cfdarg.charheight;
+		op.charcount = cfdarg.charcount;
+		op.data = cfdarg.chardata;
+		return con_font_op(fg_console, &op);
+	case GIO_FONTX:
+		if (!cfdarg.chardata)
+			return 0;
+		op.op = KD_FONT_OP_GET;
+		op.flags = 0;
+		op.width = 8;
+		op.height = cfdarg.charheight;
+		op.charcount = cfdarg.charcount;
+		op.data = cfdarg.chardata;
+		i = con_font_op(fg_console, &op);
+		if (i)
+			return i;
+		cfdarg.charheight = op.height;
+		cfdarg.charcount = op.charcount;
+		((struct consolefontdesc32 *)&cfdarg)->chardata	= (unsigned long)cfdarg.chardata;
+		if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc32)))
+			return -EFAULT;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+struct console_font_op32 {
+	unsigned int op;        /* operation code KD_FONT_OP_* */
+	unsigned int flags;     /* KD_FONT_FLAG_* */
+	unsigned int width, height;     /* font size */
+	unsigned int charcount;
+	u32 data;    /* font data with height fixed to 32 */
+};
+                                        
+static int do_kdfontop_ioctl(unsigned int fd, unsigned int cmd, struct console_font_op32 *fontop, struct file *file)
+{
+	struct console_font_op op;
+	int perm = vt_check(file), i;
+	struct vt_struct *vt;
+	
+	if (perm < 0) return perm;
+	
+	if (copy_from_user(&op, (void *) fontop, sizeof(struct console_font_op32)))
+		return -EFAULT;
+	if (!perm && op.op != KD_FONT_OP_GET)
+		return -EPERM;
+	op.data = (unsigned char *)A(((struct console_font_op32 *)&op)->data);
+	op.flags |= KD_FONT_FLAG_OLD;
+	vt = (struct vt_struct *)((struct tty_struct *)file->private_data)->driver_data;
+	i = con_font_op(vt->vc_num, &op);
+	if (i) return i;
+	((struct console_font_op32 *)&op)->data = (unsigned long)op.data;
+	if (copy_to_user((void *) fontop, &op, sizeof(struct console_font_op32)))
+		return -EFAULT;
+	return 0;
+}
+
+struct unimapdesc32 {
+	unsigned short entry_ct;
+	u32 entries;
+};
+
+static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file)
+{
+	struct unimapdesc32 tmp;
+	int perm = vt_check(file);
+	
+	if (perm < 0) return perm;
+	if (copy_from_user(&tmp, user_ud, sizeof tmp))
+		return -EFAULT;
+	switch (cmd) {
+	case PIO_UNIMAP:
+		if (!perm) return -EPERM;
+		return con_set_unimap(fg_console, tmp.entry_ct, (struct unipair *)A(tmp.entries));
+	case GIO_UNIMAP:
+		return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), (struct unipair *)A(tmp.entries));
+	}
+	return 0;
+}
+
+static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	__kernel_uid_t kuid;
+	int err;
+
+	cmd = SMB_IOC_GETMOUNTUID;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&kuid);
+	set_fs(old_fs);
+
+	if (err >= 0)
+		err = put_user(kuid, (__kernel_uid_t32 *)arg);
+
+	return err;
+}
+
+struct atmif_sioc32 {
+        int                number;
+        int                length;
+        __kernel_caddr_t32 arg;
+};
+
+struct atm_iobuf32 {
+	int                length;
+	__kernel_caddr_t32 buffer;
+};
+
+#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct atmif_sioc32)
+#define ATM_GETNAMES32    _IOW('a', ATMIOC_ITF+3, struct atm_iobuf32)
+#define ATM_GETTYPE32     _IOW('a', ATMIOC_ITF+4, struct atmif_sioc32)
+#define ATM_GETESI32	  _IOW('a', ATMIOC_ITF+5, struct atmif_sioc32)
+#define ATM_GETADDR32	  _IOW('a', ATMIOC_ITF+6, struct atmif_sioc32)
+#define ATM_RSTADDR32	  _IOW('a', ATMIOC_ITF+7, struct atmif_sioc32)
+#define ATM_ADDADDR32	  _IOW('a', ATMIOC_ITF+8, struct atmif_sioc32)
+#define ATM_DELADDR32	  _IOW('a', ATMIOC_ITF+9, struct atmif_sioc32)
+#define ATM_GETCIRANGE32  _IOW('a', ATMIOC_ITF+10, struct atmif_sioc32)
+#define ATM_SETCIRANGE32  _IOW('a', ATMIOC_ITF+11, struct atmif_sioc32)
+#define ATM_SETESI32      _IOW('a', ATMIOC_ITF+12, struct atmif_sioc32)
+#define ATM_SETESIF32     _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32)
+#define ATM_GETSTAT32     _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32)
+#define ATM_GETSTATZ32    _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32)
+#define ATM_GETLOOP32	  _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32)
+#define ATM_SETLOOP32	  _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32)
+#define ATM_QUERYLOOP32	  _IOW('a', ATMIOC_SARCOM+4, struct atmif_sioc32)
+
+static struct {
+        unsigned int cmd32;
+        unsigned int cmd;
+} atm_ioctl_map[] = {
+        { ATM_GETLINKRATE32, ATM_GETLINKRATE },
+	{ ATM_GETNAMES32,    ATM_GETNAMES },
+        { ATM_GETTYPE32,     ATM_GETTYPE },
+        { ATM_GETESI32,      ATM_GETESI },
+        { ATM_GETADDR32,     ATM_GETADDR },
+        { ATM_RSTADDR32,     ATM_RSTADDR },
+        { ATM_ADDADDR32,     ATM_ADDADDR },
+        { ATM_DELADDR32,     ATM_DELADDR },
+        { ATM_GETCIRANGE32,  ATM_GETCIRANGE },
+	{ ATM_SETCIRANGE32,  ATM_SETCIRANGE },
+	{ ATM_SETESI32,      ATM_SETESI },
+	{ ATM_SETESIF32,     ATM_SETESIF },
+	{ ATM_GETSTAT32,     ATM_GETSTAT },
+	{ ATM_GETSTATZ32,    ATM_GETSTATZ },
+	{ ATM_GETLOOP32,     ATM_GETLOOP },
+	{ ATM_SETLOOP32,     ATM_SETLOOP },
+	{ ATM_QUERYLOOP32,   ATM_QUERYLOOP }
+};
+
+#define NR_ATM_IOCTL (sizeof(atm_ioctl_map)/sizeof(atm_ioctl_map[0]))
+
+
+static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct atm_iobuf32 iobuf32;
+	struct atm_iobuf   iobuf = { 0, NULL };
+	mm_segment_t old_fs;
+	int err;
+
+	err = copy_from_user(&iobuf32, (struct atm_iobuf32*)arg,
+	    sizeof(struct atm_iobuf32));
+	if (err)
+		return -EFAULT;
+
+	iobuf.length = iobuf32.length;
+
+	if (iobuf32.buffer == (__kernel_caddr_t32) NULL || iobuf32.length == 0) {
+		iobuf.buffer = (void*)(unsigned long)iobuf32.buffer;
+	} else {
+		iobuf.buffer = kmalloc(iobuf.length, GFP_KERNEL);
+		if (iobuf.buffer == NULL) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		err = copy_from_user(iobuf.buffer, A(iobuf32.buffer), iobuf.length);
+		if (err) {
+			err = -EFAULT;
+			goto out;
+		}
+	}
+
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&iobuf);      
+	set_fs (old_fs);
+        if(err)
+		goto out;
+
+        if(iobuf.buffer && iobuf.length > 0) {
+		err = copy_to_user(A(iobuf32.buffer), iobuf.buffer, iobuf.length);
+		if (err) {
+			err = -EFAULT;
+			goto out;
+		}
+	}
+	err = __put_user(iobuf.length, &(((struct atm_iobuf32*)arg)->length));
+
+ out:
+        if(iobuf32.buffer && iobuf32.length > 0)
+		kfree(iobuf.buffer);
+
+	return err;
+}
+
+
+static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+        struct atmif_sioc32 sioc32;
+        struct atmif_sioc   sioc = { 0, 0, NULL };
+        mm_segment_t old_fs;
+        int err;
+        
+        err = copy_from_user(&sioc32, (struct atmif_sioc32*)arg,
+			     sizeof(struct atmif_sioc32));
+        if (err)
+                return -EFAULT;
+
+        sioc.number = sioc32.number;
+        sioc.length = sioc32.length;
+        
+	if (sioc32.arg == (__kernel_caddr_t32) NULL || sioc32.length == 0) {
+		sioc.arg = (void*)(unsigned long)sioc32.arg;
+        } else {
+                sioc.arg = kmalloc(sioc.length, GFP_KERNEL);
+                if (sioc.arg == NULL) {
+                        err = -ENOMEM;
+			goto out;
+		}
+                
+                err = copy_from_user(sioc.arg, A(sioc32.arg), sioc32.length);
+                if (err) {
+                        err = -EFAULT;
+                        goto out;
+                }
+        }
+        
+        old_fs = get_fs(); set_fs (KERNEL_DS);
+        err = sys_ioctl (fd, cmd, (unsigned long)&sioc);	
+        set_fs (old_fs);
+        if(err) {
+                goto out;
+	}
+        
+        if(sioc.arg && sioc.length > 0) {
+                err = copy_to_user(A(sioc32.arg), sioc.arg, sioc.length);
+                if (err) {
+                        err = -EFAULT;
+                        goto out;
+                }
+        }
+        err = __put_user(sioc.length, &(((struct atmif_sioc32*)arg)->length));
+        
+ out:
+        if(sioc32.arg && sioc32.length > 0)
+		kfree(sioc.arg);
+        
+	return err;
+}
+
+
+static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg)
+{
+        int i;
+        unsigned int cmd = 0;
+        
+	switch (cmd32) {
+	case SONET_GETSTAT:
+	case SONET_GETSTATZ:
+	case SONET_GETDIAG:
+	case SONET_SETDIAG:
+	case SONET_CLRDIAG:
+	case SONET_SETFRAMING:
+	case SONET_GETFRAMING:
+	case SONET_GETFRSENSE:
+		return do_atmif_sioc(fd, cmd32, arg);
+	}
+
+		for (i = 0; i < NR_ATM_IOCTL; i++) {
+			if (cmd32 == atm_ioctl_map[i].cmd32) {
+				cmd = atm_ioctl_map[i].cmd;
+				break;
+			}
+		}
+	        if (i == NR_ATM_IOCTL) {
+	        return -EINVAL;
+	        }
+        
+        switch (cmd) {
+	case ATM_GETNAMES:
+		return do_atm_iobuf(fd, cmd, arg);
+	    
+	case ATM_GETLINKRATE:
+        case ATM_GETTYPE:
+        case ATM_GETESI:
+        case ATM_GETADDR:
+        case ATM_RSTADDR:
+        case ATM_ADDADDR:
+        case ATM_DELADDR:
+        case ATM_GETCIRANGE:
+	case ATM_SETCIRANGE:
+	case ATM_SETESI:
+	case ATM_SETESIF:
+	case ATM_GETSTAT:
+	case ATM_GETSTATZ:
+	case ATM_GETLOOP:
+	case ATM_SETLOOP:
+	case ATM_QUERYLOOP:
+                return do_atmif_sioc(fd, cmd, arg);
+        }
+
+        return -EINVAL;
+}
+
+#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
+/* Ugh, LVM. Pitty it was not cleaned up before accepted :((. */
+typedef struct {
+	uint8_t vg_name[NAME_LEN];
+	uint32_t vg_number;
+	uint32_t vg_access;
+	uint32_t vg_status;
+	uint32_t lv_max;
+	uint32_t lv_cur;
+	uint32_t lv_open;
+	uint32_t pv_max;
+	uint32_t pv_cur;
+	uint32_t pv_act;
+	uint32_t dummy;
+	uint32_t vgda;
+	uint32_t pe_size;
+	uint32_t pe_total;
+	uint32_t pe_allocated;
+	uint32_t pvg_total;
+	u32 proc;
+	u32 pv[ABS_MAX_PV + 1];
+	u32 lv[ABS_MAX_LV + 1];
+    	uint8_t vg_uuid[UUID_LEN+1];	/* volume group UUID */
+	uint8_t dummy1[200];
+} vg32_t;
+
+typedef struct {
+	uint8_t id[2];
+	uint16_t version;
+	lvm_disk_data_t pv_on_disk;
+	lvm_disk_data_t vg_on_disk;
+	lvm_disk_data_t pv_namelist_on_disk;
+	lvm_disk_data_t lv_on_disk;
+	lvm_disk_data_t pe_on_disk;
+	uint8_t pv_name[NAME_LEN];
+	uint8_t vg_name[NAME_LEN];
+	uint8_t system_id[NAME_LEN];
+	kdev_t pv_dev;
+	uint32_t pv_number;
+	uint32_t pv_status;
+	uint32_t pv_allocatable;
+	uint32_t pv_size;
+	uint32_t lv_cur;
+	uint32_t pe_size;
+	uint32_t pe_total;
+	uint32_t pe_allocated;
+	uint32_t pe_stale;
+	u32 pe;
+	u32 inode;
+	uint8_t pv_uuid[UUID_LEN+1];
+} pv32_t;
+
+typedef struct {
+	char lv_name[NAME_LEN];
+	u32 lv;
+} lv_req32_t;
+
+typedef struct {
+	u32 lv_index;
+	u32 lv;
+	/* Transfer size because user space and kernel space differ */
+	uint16_t size;
+} lv_status_byindex_req32_t;
+
+typedef struct {
+	__kernel_dev_t32 dev;
+	u32   lv;
+} lv_status_bydev_req32_t;
+
+typedef struct {
+	uint8_t lv_name[NAME_LEN];
+	kdev_t old_dev;
+	kdev_t new_dev;
+	u32 old_pe;
+	u32 new_pe;
+} le_remap_req32_t;
+
+typedef struct {
+	char pv_name[NAME_LEN];
+	u32 pv;
+} pv_status_req32_t;
+
+typedef struct {
+	uint8_t lv_name[NAME_LEN];
+	uint8_t vg_name[NAME_LEN];
+	uint32_t lv_access;
+	uint32_t lv_status;
+	uint32_t lv_open;
+	kdev_t lv_dev;
+	uint32_t lv_number;
+	uint32_t lv_mirror_copies;
+	uint32_t lv_recovery;
+	uint32_t lv_schedule;
+	uint32_t lv_size;
+	u32 lv_current_pe;
+	uint32_t lv_current_le;
+	uint32_t lv_allocated_le;
+	uint32_t lv_stripes;
+	uint32_t lv_stripesize;
+	uint32_t lv_badblock;
+	uint32_t lv_allocation;
+	uint32_t lv_io_timeout;
+	uint32_t lv_read_ahead;
+	/* delta to version 1 starts here */
+	u32 lv_snapshot_org;
+	u32 lv_snapshot_prev;
+	u32 lv_snapshot_next;
+	u32 lv_block_exception;
+	uint32_t lv_remap_ptr;
+	uint32_t lv_remap_end;
+	uint32_t lv_chunk_size;
+	uint32_t lv_snapshot_minor;
+	char dummy[200];
+} lv32_t;
+
+typedef struct {
+	u32 hash[2];
+	u32 rsector_org;
+	kdev_t rdev_org;
+	u32 rsector_new;
+	kdev_t rdev_new;
+} lv_block_exception32_t;
+
+static void put_lv_t(lv_t *l)
+{
+	if (l->lv_current_pe) vfree(l->lv_current_pe);
+	if (l->lv_block_exception) vfree(l->lv_block_exception);
+	kfree(l);
+}
+
+static lv_t *get_lv_t(u32 p, int *errp)
+{
+	int err, i;
+	u32 ptr1, ptr2;
+	size_t size;
+	lv_block_exception32_t *lbe32;
+	lv_block_exception_t *lbe;
+	lv32_t *ul = (lv32_t *)A(p);
+	lv_t *l = (lv_t *) kmalloc(sizeof(lv_t), GFP_KERNEL);
+
+	if (!l) {
+		*errp = -ENOMEM;
+		return NULL;
+	}
+	memset(l, 0, sizeof(lv_t));
+	err = copy_from_user(l, ul, (long)&((lv32_t *)0)->lv_current_pe);
+	err |= __copy_from_user(&l->lv_current_le, &ul->lv_current_le,
+				((long)&ul->lv_snapshot_org) - ((long)&ul->lv_current_le));
+	err |= __copy_from_user(&l->lv_remap_ptr, &ul->lv_remap_ptr,
+				((long)&ul->dummy[0]) - ((long)&ul->lv_remap_ptr));
+	err |= __get_user(ptr1, &ul->lv_current_pe);
+	err |= __get_user(ptr2, &ul->lv_block_exception);
+	if (err) {
+		kfree(l);
+		*errp = -EFAULT;
+		return NULL;
+	}
+	if (ptr1) {
+		size = l->lv_allocated_le * sizeof(pe_t);
+		l->lv_current_pe = vmalloc(size);
+		if (l->lv_current_pe)
+			err = copy_from_user(l->lv_current_pe, (void *)A(ptr1), size);
+	}
+	if (!err && ptr2) {
+		size = l->lv_remap_end * sizeof(lv_block_exception_t);
+		l->lv_block_exception = lbe = vmalloc(size);
+		if (l->lv_block_exception) {
+			lbe32 = (lv_block_exception32_t *)A(ptr2);
+			memset(lbe, 0, size);
+			for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
+				err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
+				err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
+				err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
+				err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
+			}
+		}
+	}
+	if (err || (ptr1 && !l->lv_current_pe) || (ptr2 && !l->lv_block_exception)) {
+		if (!err)
+			*errp = -ENOMEM;
+		else
+			*errp = -EFAULT;
+		put_lv_t(l);
+		return NULL;
+	}
+	return l;
+}
+
+static int copy_lv_t(u32 ptr, lv_t *l)
+{
+	int err;
+	lv32_t *ul = (lv32_t *)A(ptr);
+	u32 ptr1;
+	size_t size;
+
+	err = get_user(ptr1, &ul->lv_current_pe);
+	if (err)
+		return -EFAULT;
+	err = copy_to_user(ul, l, (long)&((lv32_t *)0)->lv_current_pe);
+	err |= __copy_to_user(&ul->lv_current_le, &l->lv_current_le,
+				((long)&ul->lv_snapshot_org) - ((long)&ul->lv_current_le));
+	err |= __copy_to_user(&ul->lv_remap_ptr, &l->lv_remap_ptr,
+				((long)&ul->dummy[0]) - ((long)&ul->lv_remap_ptr));
+	size = l->lv_allocated_le * sizeof(pe_t);
+	if (ptr1)
+		err |= __copy_to_user((void *)A(ptr1), l->lv_current_pe, size);
+	return err ? -EFAULT : 0;
+}
+
+static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	vg_t *v = NULL;
+	union {
+		lv_req_t lv_req;
+		le_remap_req_t le_remap;
+		lv_status_byindex_req_t lv_byindex;
+	        lv_status_bydev_req_t lv_bydev;
+		pv_status_req_t pv_status;
+	} u;
+	pv_t p;
+	int err;
+	u32 ptr = 0;
+	int i;
+	mm_segment_t old_fs;
+	void *karg = &u;
+
+	switch (cmd) {
+	case VG_STATUS:
+		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
+		if (!v)
+			return -ENOMEM;
+		karg = v;
+		break;
+
+	case VG_CREATE_OLD:
+	case VG_CREATE:
+		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
+		if (!v)
+			return -ENOMEM;
+		if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc)) {
+			kfree(v);
+			return -EFAULT;
+		}
+		/* 'proc' field is unused, just NULL it out. */
+		v->proc = NULL;
+		if (copy_from_user(v->vg_uuid, ((vg32_t *)arg)->vg_uuid, UUID_LEN+1)) {
+			kfree(v);
+			return -EFAULT;
+		}
+		    
+		karg = v;
+		memset(v->pv, 0, sizeof(v->pv) + sizeof(v->lv));
+		if (v->pv_max > ABS_MAX_PV || v->lv_max > ABS_MAX_LV)
+			return -EPERM;
+		for (i = 0; i < v->pv_max; i++) {
+			err = __get_user(ptr, &((vg32_t *)arg)->pv[i]);
+			if (err)
+				break;
+			if (ptr) {
+				v->pv[i] = kmalloc(sizeof(pv_t), GFP_KERNEL);
+				if (!v->pv[i]) {
+					err = -ENOMEM;
+					break;
+				}
+				err = copy_from_user(v->pv[i], (void *)A(ptr),
+						     sizeof(pv32_t) - 8 - UUID_LEN+1);
+				if (err) {
+					err = -EFAULT;
+					break;
+				}
+				err = copy_from_user(v->pv[i]->pv_uuid,
+						     ((pv32_t *)A(ptr))->pv_uuid,
+						     UUID_LEN+1);
+				if (err) {
+				        err = -EFAULT;
+					break;
+				}
+
+				v->pv[i]->pe = NULL;
+				v->pv[i]->bd = NULL;
+			}
+		}
+		if (!err) {
+			for (i = 0; i < v->lv_max; i++) {
+				err = __get_user(ptr, &((vg32_t *)arg)->lv[i]);
+				if (err)
+					break;
+				if (ptr) {
+					v->lv[i] = get_lv_t(ptr, &err);
+					if (err)
+						break;
+				}
+			}
+		}
+		break;
+
+	case LV_CREATE:
+	case LV_EXTEND:
+	case LV_REDUCE:
+	case LV_REMOVE:
+	case LV_RENAME:
+	case LV_STATUS_BYNAME:
+	        err = copy_from_user(&u.pv_status, (void*)arg, sizeof(u.pv_status.pv_name));
+		if (err)
+			return -EFAULT;
+		if (cmd != LV_REMOVE) {
+			err = __get_user(ptr, &((lv_req32_t *)arg)->lv);
+			if (err)
+				return err;
+			u.lv_req.lv = get_lv_t(ptr, &err);
+		} else
+			u.lv_req.lv = NULL;
+		break;
+
+	case LV_STATUS_BYINDEX:
+		err = get_user(u.lv_byindex.lv_index,
+			       &((lv_status_byindex_req32_t *)arg)->lv_index);
+		err |= __get_user(ptr, &((lv_status_byindex_req32_t *)arg)->lv);
+		if (err)
+			return err;
+		u.lv_byindex.lv = get_lv_t(ptr, &err);
+		break;
+
+	case LV_STATUS_BYDEV:
+	        err = get_user(u.lv_bydev.dev, &((lv_status_bydev_req32_t *)arg)->dev);
+		err |= __get_user(ptr, &((lv_status_bydev_req32_t *)arg)->lv);
+		if (err)
+			return err;
+		u.lv_bydev.lv = get_lv_t(ptr, &err);
+		break;
+
+	case VG_EXTEND:
+		err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8 - UUID_LEN+1);
+		if (err)
+			return -EFAULT;
+		err = copy_from_user(p.pv_uuid, ((pv32_t *)arg)->pv_uuid, UUID_LEN+1);
+		if (err)
+			return -EFAULT;
+		p.pe = NULL;
+		p.bd = NULL;
+		karg = &p;
+		break;
+
+	case PV_CHANGE:
+	case PV_STATUS:
+		err = copy_from_user(&u.pv_status, (void*)arg, sizeof(u.lv_req.lv_name));
+		if (err)
+			return -EFAULT;
+		err = __get_user(ptr, &((pv_status_req32_t *)arg)->pv);
+		if (err)
+			return err;
+		u.pv_status.pv = &p;
+		if (cmd == PV_CHANGE) {
+			err = copy_from_user(&p, (void *)A(ptr),
+					     sizeof(pv32_t) - 8 - UUID_LEN+1);
+			if (err)
+				return -EFAULT;
+			p.pe = NULL;
+			p.bd = NULL;
+		}
+		break;
+	};
+
+        old_fs = get_fs(); set_fs (KERNEL_DS);
+        err = sys_ioctl (fd, cmd, (unsigned long)karg);
+        set_fs (old_fs);
+
+	switch (cmd) {
+	case VG_STATUS:
+		if (!err) {
+			if (copy_to_user((void *)arg, v, (long)&((vg32_t *)0)->proc) ||
+			    clear_user(&((vg32_t *)arg)->proc, sizeof(vg32_t) - (long)&((vg32_t *)0)->proc))
+				err = -EFAULT;
+		}
+		if (copy_to_user(((vg32_t *)arg)->vg_uuid, v->vg_uuid, UUID_LEN+1)) {
+		        err = -EFAULT;
+		}
+		kfree(v);
+		break;
+
+	case VG_CREATE_OLD:
+	case VG_CREATE:
+		for (i = 0; i < v->pv_max; i++) {
+			if (v->pv[i])
+				kfree(v->pv[i]);
+		}
+		for (i = 0; i < v->lv_max; i++) {
+			if (v->lv[i])
+				put_lv_t(v->lv[i]);
+		}
+		kfree(v);
+		break;
+
+	case LV_STATUS_BYNAME:
+		if (!err && u.lv_req.lv)
+			err = copy_lv_t(ptr, u.lv_req.lv);
+		/* Fall through */
+
+        case LV_CREATE:
+	case LV_EXTEND:
+	case LV_REDUCE:
+		if (u.lv_req.lv)
+			put_lv_t(u.lv_req.lv);
+		break;
+
+	case LV_STATUS_BYINDEX:
+		if (u.lv_byindex.lv) {
+			if (!err)
+				err = copy_lv_t(ptr, u.lv_byindex.lv);
+			put_lv_t(u.lv_byindex.lv);
+		}
+		break;
+
+	case LV_STATUS_BYDEV:
+	        if (u.lv_bydev.lv) {
+			if (!err)
+				err = copy_lv_t(ptr, u.lv_bydev.lv);
+			put_lv_t(u.lv_byindex.lv);
+	        }
+	        break;
+
+	case PV_STATUS:
+		if (!err) {
+			err = copy_to_user((void *)A(ptr), &p, sizeof(pv32_t) - 8 - UUID_LEN+1);
+			if (err)
+				return -EFAULT;
+			err = copy_to_user(((pv_t *)A(ptr))->pv_uuid, p.pv_uuid, UUID_LEN + 1);
+			if (err)
+				return -EFAULT;
+		}
+		break;
+	};
+
+	return err;
+}
+#endif
+
+#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+/* This really belongs in include/linux/drm.h -DaveM */
+#include "../../../drivers/char/drm/drm.h"
+
+typedef struct drm32_version {
+	int    version_major;	  /* Major version			    */
+	int    version_minor;	  /* Minor version			    */
+	int    version_patchlevel;/* Patch level			    */
+	int    name_len;	  /* Length of name buffer		    */
+	u32    name;		  /* Name of driver			    */
+	int    date_len;	  /* Length of date buffer		    */
+	u32    date;		  /* User-space buffer to hold date	    */
+	int    desc_len;	  /* Length of desc buffer		    */
+	u32    desc;		  /* User-space buffer to hold desc	    */
+} drm32_version_t;
+#define DRM32_IOCTL_VERSION    DRM_IOWR(0x00, drm32_version_t)
+
+static int drm32_version(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_version_t *uversion = (drm32_version_t *)arg;
+	char *name_ptr, *date_ptr, *desc_ptr;
+	u32 tmp1, tmp2, tmp3;
+	drm_version_t kversion;
+	mm_segment_t old_fs;
+	int ret;
+
+	memset(&kversion, 0, sizeof(kversion));
+	if (get_user(kversion.name_len, &uversion->name_len) ||
+	    get_user(kversion.date_len, &uversion->date_len) ||
+	    get_user(kversion.desc_len, &uversion->desc_len) ||
+	    get_user(tmp1, &uversion->name) ||
+	    get_user(tmp2, &uversion->date) ||
+	    get_user(tmp3, &uversion->desc))
+		return -EFAULT;
+
+	name_ptr = (char *) A(tmp1);
+	date_ptr = (char *) A(tmp2);
+	desc_ptr = (char *) A(tmp3);
+
+	ret = -ENOMEM;
+	if (kversion.name_len && name_ptr) {
+		kversion.name = kmalloc(kversion.name_len, GFP_KERNEL);
+		if (!kversion.name)
+			goto out;
+	}
+	if (kversion.date_len && date_ptr) {
+		kversion.date = kmalloc(kversion.date_len, GFP_KERNEL);
+		if (!kversion.date)
+			goto out;
+	}
+	if (kversion.desc_len && desc_ptr) {
+		kversion.desc = kmalloc(kversion.desc_len, GFP_KERNEL);
+		if (!kversion.desc)
+			goto out;
+	}
+
+        old_fs = get_fs();
+	set_fs(KERNEL_DS);
+        ret = sys_ioctl (fd, DRM_IOCTL_VERSION, (unsigned long)&kversion);
+        set_fs(old_fs);
+
+	if (!ret) {
+		if ((kversion.name &&
+		     copy_to_user(name_ptr, kversion.name, kversion.name_len)) ||
+		    (kversion.date &&
+		     copy_to_user(date_ptr, kversion.date, kversion.date_len)) ||
+		    (kversion.desc &&
+		     copy_to_user(desc_ptr, kversion.desc, kversion.desc_len)))
+			ret = -EFAULT;
+		if (put_user(kversion.version_major, &uversion->version_major) ||
+		    put_user(kversion.version_minor, &uversion->version_minor) ||
+		    put_user(kversion.version_patchlevel, &uversion->version_patchlevel) ||
+		    put_user(kversion.name_len, &uversion->name_len) ||
+		    put_user(kversion.date_len, &uversion->date_len) ||
+		    put_user(kversion.desc_len, &uversion->desc_len))
+			ret = -EFAULT;
+	}
+
+out:
+	if (kversion.name)
+		kfree(kversion.name);
+	if (kversion.date)
+		kfree(kversion.date);
+	if (kversion.desc)
+		kfree(kversion.desc);
+	return ret;
+}
+
+typedef struct drm32_unique {
+	int	unique_len;	  /* Length of unique			    */
+	u32	unique;		  /* Unique name for driver instantiation   */
+} drm32_unique_t;
+#define DRM32_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm32_unique_t)
+#define DRM32_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm32_unique_t)
+
+static int drm32_getsetunique(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_unique_t *uarg = (drm32_unique_t *)arg;
+	drm_unique_t karg;
+	mm_segment_t old_fs;
+	char *uptr;
+	u32 tmp;
+	int ret;
+
+	if (get_user(karg.unique_len, &uarg->unique_len))
+		return -EFAULT;
+	karg.unique = NULL;
+
+	if (get_user(tmp, &uarg->unique))
+		return -EFAULT;
+
+	uptr = (char *) A(tmp);
+
+	if (uptr) {
+		karg.unique = kmalloc(karg.unique_len, GFP_KERNEL);
+		if (!karg.unique)
+			return -ENOMEM;
+		if (cmd == DRM32_IOCTL_SET_UNIQUE &&
+		    copy_from_user(karg.unique, uptr, karg.unique_len)) {
+			kfree(karg.unique);
+			return -EFAULT;
+		}
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	if (cmd == DRM32_IOCTL_GET_UNIQUE)
+		ret = sys_ioctl (fd, DRM_IOCTL_GET_UNIQUE, (unsigned long)&karg);
+	else
+		ret = sys_ioctl (fd, DRM_IOCTL_SET_UNIQUE, (unsigned long)&karg);
+        set_fs(old_fs);
+
+	if (!ret) {
+		if (cmd == DRM32_IOCTL_GET_UNIQUE &&
+		    uptr != NULL &&
+		    copy_to_user(uptr, karg.unique, karg.unique_len))
+			ret = -EFAULT;
+		if (put_user(karg.unique_len, &uarg->unique_len))
+			ret = -EFAULT;
+	}
+
+	if (karg.unique != NULL)
+		kfree(karg.unique);
+
+	return ret;
+}
+
+typedef struct drm32_map {
+	u32		offset;	 /* Requested physical address (0 for SAREA)*/
+	u32		size;	 /* Requested physical size (bytes)	    */
+	drm_map_type_t	type;	 /* Type of memory to map		    */
+	drm_map_flags_t flags;	 /* Flags				    */
+	u32		handle;  /* User-space: "Handle" to pass to mmap    */
+				 /* Kernel-space: kernel-virtual address    */
+	int		mtrr;	 /* MTRR slot used			    */
+				 /* Private data			    */
+} drm32_map_t;
+#define DRM32_IOCTL_ADD_MAP    DRM_IOWR(0x15, drm32_map_t)
+
+static int drm32_addmap(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_map_t *uarg = (drm32_map_t *) arg;
+	drm_map_t karg;
+	mm_segment_t old_fs;
+	u32 tmp;
+	int ret;
+
+	ret  = get_user(karg.offset, &uarg->offset);
+	ret |= get_user(karg.size, &uarg->size);
+	ret |= get_user(karg.type, &uarg->type);
+	ret |= get_user(karg.flags, &uarg->flags);
+	ret |= get_user(tmp, &uarg->handle);
+	ret |= get_user(karg.mtrr, &uarg->mtrr);
+	if (ret)
+		return -EFAULT;
+
+	karg.handle = (void *) A(tmp);
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_ADD_MAP, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		ret  = put_user(karg.offset, &uarg->offset);
+		ret |= put_user(karg.size, &uarg->size);
+		ret |= put_user(karg.type, &uarg->type);
+		ret |= put_user(karg.flags, &uarg->flags);
+		tmp = (u32) (long)karg.handle;
+		ret |= put_user(tmp, &uarg->handle);
+		ret |= put_user(karg.mtrr, &uarg->mtrr);
+		if (ret)
+			ret = -EFAULT;
+	}
+
+	return ret;
+}
+
+typedef struct drm32_buf_info {
+	int	       count;	/* Entries in list			     */
+	u32	       list;    /* (drm_buf_desc_t *) */ 
+} drm32_buf_info_t;
+#define DRM32_IOCTL_INFO_BUFS  DRM_IOWR(0x18, drm32_buf_info_t)
+
+static int drm32_info_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_buf_info_t *uarg = (drm32_buf_info_t *)arg;
+	drm_buf_desc_t *ulist;
+	drm_buf_info_t karg;
+	mm_segment_t old_fs;
+	int orig_count, ret;
+	u32 tmp;
+
+	if (get_user(karg.count, &uarg->count) ||
+	    get_user(tmp, &uarg->list))
+		return -EFAULT;
+
+	ulist = (drm_buf_desc_t *) A(tmp);
+
+	orig_count = karg.count;
+
+	karg.list = kmalloc(karg.count * sizeof(drm_buf_desc_t), GFP_KERNEL);
+	if (!karg.list)
+		return -EFAULT;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_INFO_BUFS, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		if (karg.count <= orig_count &&
+		    (copy_to_user(ulist, karg.list,
+				  karg.count * sizeof(drm_buf_desc_t))))
+			ret = -EFAULT;
+		if (put_user(karg.count, &uarg->count))
+			ret = -EFAULT;
+	}
+
+	kfree(karg.list);
+
+	return ret;
+}
+
+typedef struct drm32_buf_free {
+	int	       count;
+	u32	       list;	/* (int *) */
+} drm32_buf_free_t;
+#define DRM32_IOCTL_FREE_BUFS  DRM_IOW( 0x1a, drm32_buf_free_t)
+
+static int drm32_free_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_buf_free_t *uarg = (drm32_buf_free_t *)arg;
+	drm_buf_free_t karg;
+	mm_segment_t old_fs;
+	int *ulist;
+	int ret;
+	u32 tmp;
+
+	if (get_user(karg.count, &uarg->count) ||
+	    get_user(tmp, &uarg->list))
+		return -EFAULT;
+
+	ulist = (int *) A(tmp);
+
+	karg.list = kmalloc(karg.count * sizeof(int), GFP_KERNEL);
+	if (!karg.list)
+		return -ENOMEM;
+
+	ret = -EFAULT;
+	if (copy_from_user(karg.list, ulist, (karg.count * sizeof(int))))
+		goto out;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_FREE_BUFS, (unsigned long) &karg);
+	set_fs(old_fs);
+
+out:
+	kfree(karg.list);
+
+	return ret;
+}
+
+typedef struct drm32_buf_pub {
+	int		  idx;	       /* Index into master buflist	     */
+	int		  total;       /* Buffer size			     */
+	int		  used;	       /* Amount of buffer in use (for DMA)  */
+	u32		  address;     /* Address of buffer (void *)	     */
+} drm32_buf_pub_t;
+
+typedef struct drm32_buf_map {
+	int	      count;	/* Length of buflist			    */
+	u32	      virtual;	/* Mmaped area in user-virtual (void *)	    */
+	u32 	      list;	/* Buffer information (drm_buf_pub_t *)	    */
+} drm32_buf_map_t;
+#define DRM32_IOCTL_MAP_BUFS   DRM_IOWR(0x19, drm32_buf_map_t)
+
+static int drm32_map_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_buf_map_t *uarg = (drm32_buf_map_t *)arg;
+	drm32_buf_pub_t *ulist;
+	drm_buf_map_t karg;
+	mm_segment_t old_fs;
+	int orig_count, ret, i;
+	u32 tmp1, tmp2;
+
+	if (get_user(karg.count, &uarg->count) ||
+	    get_user(tmp1, &uarg->virtual) ||
+	    get_user(tmp2, &uarg->list))
+		return -EFAULT;
+
+	karg.virtual = (void *) A(tmp1);
+	ulist = (drm32_buf_pub_t *) A(tmp2);
+
+	orig_count = karg.count;
+
+	karg.list = kmalloc(karg.count * sizeof(drm_buf_pub_t), GFP_KERNEL);
+	if (!karg.list)
+		return -ENOMEM;
+
+	ret = -EFAULT;
+	for (i = 0; i < karg.count; i++) {
+		if (get_user(karg.list[i].idx, &ulist[i].idx) ||
+		    get_user(karg.list[i].total, &ulist[i].total) ||
+		    get_user(karg.list[i].used, &ulist[i].used) ||
+		    get_user(tmp1, &ulist[i].address))
+			goto out;
+
+		karg.list[i].address = (void *) A(tmp1);
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_MAP_BUFS, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		for (i = 0; i < orig_count; i++) {
+			tmp1 = (u32) (long) karg.list[i].address;
+			if (put_user(karg.list[i].idx, &ulist[i].idx) ||
+			    put_user(karg.list[i].total, &ulist[i].total) ||
+			    put_user(karg.list[i].used, &ulist[i].used) ||
+			    put_user(tmp1, &ulist[i].address)) {
+				ret = -EFAULT;
+				goto out;
+			}
+		}
+		if (put_user(karg.count, &uarg->count))
+			ret = -EFAULT;
+	}
+
+out:
+	kfree(karg.list);
+	return ret;
+}
+
+typedef struct drm32_dma {
+				/* Indices here refer to the offset into
+				   buflist in drm_buf_get_t.  */
+	int		context;	  /* Context handle		    */
+	int		send_count;	  /* Number of buffers to send	    */
+	u32		send_indices;	  /* List of handles to buffers (int *) */
+	u32		send_sizes;	  /* Lengths of data to send (int *) */
+	drm_dma_flags_t flags;		  /* Flags			    */
+	int		request_count;	  /* Number of buffers requested    */
+	int		request_size;	  /* Desired size for buffers	    */
+	u32		request_indices;  /* Buffer information (int *)	    */
+	u32		request_sizes;    /* (int *) */
+	int		granted_count;	  /* Number of buffers granted	    */
+} drm32_dma_t;
+#define DRM32_IOCTL_DMA	     DRM_IOWR(0x29, drm32_dma_t)
+
+/* RED PEN	The DRM layer blindly dereferences the send/request
+ * 		indice/size arrays even though they are userland
+ * 		pointers.  -DaveM
+ */
+static int drm32_dma(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_dma_t *uarg = (drm32_dma_t *) arg;
+	int *u_si, *u_ss, *u_ri, *u_rs;
+	drm_dma_t karg;
+	mm_segment_t old_fs;
+	int ret;
+	u32 tmp1, tmp2, tmp3, tmp4;
+
+	karg.send_indices = karg.send_sizes = NULL;
+	karg.request_indices = karg.request_sizes = NULL;
+
+	if (get_user(karg.context, &uarg->context) ||
+	    get_user(karg.send_count, &uarg->send_count) ||
+	    get_user(tmp1, &uarg->send_indices) ||
+	    get_user(tmp2, &uarg->send_sizes) ||
+	    get_user(karg.flags, &uarg->flags) ||
+	    get_user(karg.request_count, &uarg->request_count) ||
+	    get_user(karg.request_size, &uarg->request_size) ||
+	    get_user(tmp3, &uarg->request_indices) ||
+	    get_user(tmp4, &uarg->request_sizes) ||
+	    get_user(karg.granted_count, &uarg->granted_count))
+		return -EFAULT;
+
+	u_si = (int *) A(tmp1);
+	u_ss = (int *) A(tmp2);
+	u_ri = (int *) A(tmp3);
+	u_rs = (int *) A(tmp4);
+
+	if (karg.send_count) {
+		karg.send_indices = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
+		karg.send_sizes = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
+
+		ret = -ENOMEM;
+		if (!karg.send_indices || !karg.send_sizes)
+			goto out;
+
+		ret = -EFAULT;
+		if (copy_from_user(karg.send_indices, u_si,
+				   (karg.send_count * sizeof(int))) ||
+		    copy_from_user(karg.send_sizes, u_ss,
+				   (karg.send_count * sizeof(int))))
+			goto out;
+	}
+
+	if (karg.request_count) {
+		karg.request_indices = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
+		karg.request_sizes = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
+
+		ret = -ENOMEM;
+		if (!karg.request_indices || !karg.request_sizes)
+			goto out;
+
+		ret = -EFAULT;
+		if (copy_from_user(karg.request_indices, u_ri,
+				   (karg.request_count * sizeof(int))) ||
+		    copy_from_user(karg.request_sizes, u_rs,
+				   (karg.request_count * sizeof(int))))
+			goto out;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_DMA, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		if (put_user(karg.context, &uarg->context) ||
+		    put_user(karg.send_count, &uarg->send_count) ||
+		    put_user(karg.flags, &uarg->flags) ||
+		    put_user(karg.request_count, &uarg->request_count) ||
+		    put_user(karg.request_size, &uarg->request_size) ||
+		    put_user(karg.granted_count, &uarg->granted_count))
+			ret = -EFAULT;
+
+		if (karg.send_count) {
+			if (copy_to_user(u_si, karg.send_indices,
+					 (karg.send_count * sizeof(int))) ||
+			    copy_to_user(u_ss, karg.send_sizes,
+					 (karg.send_count * sizeof(int))))
+				ret = -EFAULT;
+		}
+		if (karg.request_count) {
+			if (copy_to_user(u_ri, karg.request_indices,
+					 (karg.request_count * sizeof(int))) ||
+			    copy_to_user(u_rs, karg.request_sizes,
+					 (karg.request_count * sizeof(int))))
+				ret = -EFAULT;
+		}
+	}
+
+out:
+	if (karg.send_indices)
+		kfree(karg.send_indices);
+	if (karg.send_sizes)
+		kfree(karg.send_sizes);
+	if (karg.request_indices)
+		kfree(karg.request_indices);
+	if (karg.request_sizes)
+		kfree(karg.request_sizes);
+
+	return ret;
+}
+
+typedef struct drm32_ctx_res {
+	int		count;
+	u32		contexts; /* (drm_ctx_t *) */
+} drm32_ctx_res_t;
+#define DRM32_IOCTL_RES_CTX    DRM_IOWR(0x26, drm32_ctx_res_t)
+
+static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_ctx_res_t *uarg = (drm32_ctx_res_t *) arg;
+	drm_ctx_t *ulist;
+	drm_ctx_res_t karg;
+	mm_segment_t old_fs;
+	int orig_count, ret;
+	u32 tmp;
+
+	karg.contexts = NULL;
+	if (get_user(karg.count, &uarg->count) ||
+	    get_user(tmp, &uarg->contexts))
+		return -EFAULT;
+
+	ulist = (drm_ctx_t *) A(tmp);
+
+	orig_count = karg.count;
+	if (karg.count && ulist) {
+		karg.contexts = kmalloc((karg.count * sizeof(drm_ctx_t)), GFP_KERNEL);
+		if (!karg.contexts)
+			return -ENOMEM;
+		if (copy_from_user(karg.contexts, ulist,
+				   (karg.count * sizeof(drm_ctx_t)))) {
+			kfree(karg.contexts);
+			return -EFAULT;
+		}
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_RES_CTX, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		if (orig_count) {
+			if (copy_to_user(ulist, karg.contexts,
+					 (orig_count * sizeof(drm_ctx_t))))
+				ret = -EFAULT;
+		}
+		if (put_user(karg.count, &uarg->count))
+			ret = -EFAULT;
+	}
+
+	if (karg.contexts)
+		kfree(karg.contexts);
+
+	return ret;
+}
+
+#endif
+
+static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return -EINVAL;
+}
+
+static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	/* The mkswap binary hard codes it to Intel value :-((( */
+	return w_long(fd, BLKGETSIZE, arg);
+}
+
+struct blkpg_ioctl_arg32 {
+	int op;
+	int flags;
+	int datalen;
+	u32 data;
+};
+                                
+static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg)
+{
+	struct blkpg_ioctl_arg a;
+	struct blkpg_partition p;
+	int err;
+	mm_segment_t old_fs = get_fs();
+	
+	err = get_user(a.op, &arg->op);
+	err |= __get_user(a.flags, &arg->flags);
+	err |= __get_user(a.datalen, &arg->datalen);
+	err |= __get_user((long)a.data, &arg->data);
+	if (err) return err;
+	switch (a.op) {
+	case BLKPG_ADD_PARTITION:
+	case BLKPG_DEL_PARTITION:
+		if (a.datalen < sizeof(struct blkpg_partition))
+			return -EINVAL;
+                if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
+			return -EFAULT;
+		a.data = &p;
+		set_fs (KERNEL_DS);
+		err = sys_ioctl(fd, cmd, (unsigned long)&a);
+		set_fs (old_fs);
+	default:
+		return -EINVAL;
+	}                                        
+	return err;
+}
+
+static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
+}
+
+/* SuSE extension */ 
+#ifndef TIOCGDEV
+#define TIOCGDEV       _IOR('T',0x32, unsigned int)
+#endif
+static int tiocgdev(unsigned fd, unsigned cmd,  unsigned int *ptr) 
+{ 
+
+	struct file *file = fget(fd);
+	struct tty_struct *real_tty;
+
+	if (!fd)
+		return -EBADF;
+	if (file->f_op->ioctl != tty_ioctl)
+		return -EINVAL; 
+	real_tty = (struct tty_struct *)file->private_data;
+	if (!real_tty) 	
+		return -EINVAL; 
+	return put_user(kdev_t_to_nr(real_tty->device), ptr); 
+} 
+
+
+struct raw32_config_request 
+{
+	int	raw_minor;
+	__u64	block_major;
+	__u64	block_minor;
+} __attribute__((packed));
+
+static int raw_ioctl(unsigned fd, unsigned cmd,  void *ptr) 
+{ 
+	int ret;
+	switch (cmd) { 
+	case RAW_SETBIND:
+	case RAW_GETBIND: {
+		struct raw_config_request req; 
+		struct raw32_config_request *user_req = ptr;
+		mm_segment_t oldfs = get_fs(); 
+
+		if (get_user(req.raw_minor, &user_req->raw_minor) ||
+		    get_user(req.block_major, &user_req->block_major) ||
+		    get_user(req.block_minor, &user_req->block_minor))
+			return -EFAULT;
+		set_fs(KERNEL_DS); 
+		ret = sys_ioctl(fd,cmd,(unsigned long)&req); 
+		set_fs(oldfs); 
+		break;
+	}
+	default:
+		ret = sys_ioctl(fd,cmd,(unsigned long)ptr);
+		break;
+	} 
+	return ret; 		
+} 
+
+struct serial_struct32 {
+	int	type;
+	int	line;
+	unsigned int	port;
+	int	irq;
+	int	flags;
+	int	xmit_fifo_size;
+	int	custom_divisor;
+	int	baud_base;
+	unsigned short	close_delay;
+	char	io_type;
+	char	reserved_char[1];
+	int	hub6;
+	unsigned short	closing_wait; /* time to wait before closing */
+	unsigned short	closing_wait2; /* no longer used... */
+	__u32 iomem_base;
+	unsigned short	iomem_reg_shift;
+	unsigned int	port_high;
+	int	reserved[1];
+};
+
+static int serial_struct_ioctl(unsigned fd, unsigned cmd,  void *ptr) 
+{
+	typedef struct serial_struct SS;
+	struct serial_struct32 *ss32 = ptr; 
+	int err = 0;
+	struct serial_struct ss; 
+	mm_segment_t oldseg = get_fs(); 
+	set_fs(KERNEL_DS);
+	if (cmd == TIOCSSERIAL) { 
+		err = -EFAULT;
+		if (copy_from_user(&ss, ss32, sizeof(struct serial_struct32)))
+			goto out;
+		memmove(&ss.iomem_reg_shift, ((char*)&ss.iomem_base)+4, 
+			sizeof(SS)-offsetof(SS,iomem_reg_shift)); 
+		ss.iomem_base = (void *)((unsigned long)ss.iomem_base & 0xffffffff);
+	}
+	if (!err)
+		err = sys_ioctl(fd,cmd,(unsigned long)(&ss)); 
+	if (cmd == TIOCGSERIAL && err >= 0) { 
+		__u32 base;
+		if (__copy_to_user(ss32,&ss,offsetof(SS,iomem_base)) ||
+		    __copy_to_user(&ss32->iomem_reg_shift,
+				   &ss.iomem_reg_shift,
+				   sizeof(SS) - offsetof(SS, iomem_reg_shift)))
+			err = -EFAULT;
+		if (ss.iomem_base > (unsigned char *)0xffffffff)
+			base = -1; 
+		else
+			base = (unsigned long)ss.iomem_base;
+		err |= __put_user(base, &ss32->iomem_base); 		
+	} 
+ out:
+	set_fs(oldseg);
+	return err;	
+}
+
+
+#define REISERFS_IOC_UNPACK32               _IOW(0xCD,1,int)
+
+static int reiserfs_ioctl32(unsigned fd, unsigned cmd, unsigned long ptr) 
+{ 
+	if (cmd == REISERFS_IOC_UNPACK32) 
+		cmd = REISERFS_IOC_UNPACK; 
+	return sys_ioctl(fd,cmd,ptr); 
+} 
+
+struct dirent32 {
+	unsigned int		d_ino;
+	__kernel_off_t32	d_off;
+	unsigned short	d_reclen;
+	char		d_name[256]; /* We must not include limits.h! */
+};
+
+#define	VFAT_IOCTL_READDIR_BOTH32	_IOR('r', 1, struct dirent32 [2])
+#define	VFAT_IOCTL_READDIR_SHORT32	_IOR('r', 2, struct dirent32 [2])
+
+static int put_dirent32(struct dirent *src, struct dirent32 *dst)
+{ 
+	int ret;
+	ret = put_user(src->d_ino, &dst->d_ino); 
+	ret |= __put_user(src->d_off, &dst->d_off); 
+	ret |= __put_user(src->d_reclen, &dst->d_reclen); 
+	if (__copy_to_user(&dst->d_name, src->d_name, src->d_reclen))
+		ret |= -EFAULT;
+	return ret;
+} 
+
+static int vfat_ioctl32(unsigned fd, unsigned cmd,  void *ptr) 
+{
+	int ret;
+	mm_segment_t oldfs = get_fs();
+	struct dirent d[2]; 
+
+	set_fs(KERNEL_DS); 
+	ret = sys_ioctl(fd,cmd,(unsigned long)&d); 
+	set_fs(oldfs); 
+	if (!ret) { 
+		ret |= put_dirent32(&d[0], (struct dirent32 *)ptr); 
+		ret |= put_dirent32(&d[1], ((struct dirent32 *)ptr) + 1); 
+	} 
+	return ret;
+}
+
+#define RTC_IRQP_READ32	_IOR('p', 0x0b, unsigned int)	 /* Read IRQ rate   */
+#define RTC_IRQP_SET32	_IOW('p', 0x0c, unsigned int)	 /* Set IRQ rate    */
+#define RTC_EPOCH_READ32	_IOR('p', 0x0d, unsigned)	 /* Read epoch      */
+#define RTC_EPOCH_SET32		_IOW('p', 0x0e, unsigned)	 /* Set epoch       */
+
+static int rtc32_ioctl(unsigned fd, unsigned cmd, unsigned long arg) 
+{
+	unsigned long val;
+	mm_segment_t oldfs = get_fs(); 
+	int ret; 
+	
+	switch (cmd) { 
+	case RTC_IRQP_READ32: 
+	set_fs(KERNEL_DS);
+		ret = sys_ioctl(fd, RTC_IRQP_READ, (unsigned long)&val); 
+		set_fs(oldfs); 
+		if (!ret)
+			ret = put_user(val, (unsigned int*) arg); 
+	return ret; 
+
+	case RTC_IRQP_SET32: 
+		cmd = RTC_EPOCH_SET; 
+		break; 
+
+	case RTC_EPOCH_READ32:
+		set_fs(KERNEL_DS); 
+		ret = sys_ioctl(fd, RTC_EPOCH_READ, (unsigned long) &val); 
+		set_fs(oldfs); 
+		if (!ret)
+			ret = put_user(val, (unsigned int*) arg); 
+		return ret; 
+
+	case RTC_EPOCH_SET32:
+		cmd = RTC_EPOCH_SET; 
+		break; 
+	} 
+	return sys_ioctl(fd,cmd,arg); 
+} 
+
+struct ioctl_trans {
+	unsigned long cmd;
+	int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
+	struct ioctl_trans *next;
+};
+
+#define REF_SYMBOL(handler) if (0) (void)handler;
+#define HANDLE_IOCTL2(cmd,handler) REF_SYMBOL(handler);  asm volatile(".quad %c0, " #handler ",0"::"i" (cmd)); 
+#define HANDLE_IOCTL(cmd,handler) HANDLE_IOCTL2(cmd,handler)
+#define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL(cmd,sys_ioctl)
+#define IOCTL_TABLE_START void ioctl_dummy(void) { asm volatile("\nioctl_start:\n\t" );
+#define IOCTL_TABLE_END  asm volatile("\nioctl_end:"); }
+
+IOCTL_TABLE_START
+/* List here explicitly which ioctl's are known to have
+ * compatable types passed or none at all...
+ */
+/* Big T */
+COMPATIBLE_IOCTL(TCGETA)
+COMPATIBLE_IOCTL(TCSETA)
+COMPATIBLE_IOCTL(TCSETAW)
+COMPATIBLE_IOCTL(TCSETAF)
+COMPATIBLE_IOCTL(TCSBRK)
+COMPATIBLE_IOCTL(TCXONC)
+COMPATIBLE_IOCTL(TCFLSH)
+COMPATIBLE_IOCTL(TCGETS)
+COMPATIBLE_IOCTL(TCSETS)
+COMPATIBLE_IOCTL(TCSETSW)
+COMPATIBLE_IOCTL(TCSETSF)
+COMPATIBLE_IOCTL(TIOCLINUX)
+HANDLE_IOCTL(TIOCGDEV, tiocgdev)
+/* Little t */
+COMPATIBLE_IOCTL(TIOCGETD)
+COMPATIBLE_IOCTL(TIOCSETD)
+COMPATIBLE_IOCTL(TIOCEXCL)
+COMPATIBLE_IOCTL(TIOCNXCL)
+COMPATIBLE_IOCTL(TIOCCONS)
+COMPATIBLE_IOCTL(TIOCGSOFTCAR)
+COMPATIBLE_IOCTL(TIOCSSOFTCAR)
+COMPATIBLE_IOCTL(TIOCSWINSZ)
+COMPATIBLE_IOCTL(TIOCGWINSZ)
+COMPATIBLE_IOCTL(TIOCMGET)
+COMPATIBLE_IOCTL(TIOCMBIC)
+COMPATIBLE_IOCTL(TIOCMBIS)
+COMPATIBLE_IOCTL(TIOCMSET)
+COMPATIBLE_IOCTL(TIOCPKT)
+COMPATIBLE_IOCTL(TIOCNOTTY)
+COMPATIBLE_IOCTL(TIOCSTI)
+COMPATIBLE_IOCTL(TIOCOUTQ)
+COMPATIBLE_IOCTL(TIOCSPGRP)
+COMPATIBLE_IOCTL(TIOCGPGRP)
+COMPATIBLE_IOCTL(TIOCSCTTY)
+COMPATIBLE_IOCTL(TIOCGPTN)
+COMPATIBLE_IOCTL(TIOCSPTLCK)
+COMPATIBLE_IOCTL(TIOCSERGETLSR)
+COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO)
+COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO)
+COMPATIBLE_IOCTL(FBIOPAN_DISPLAY)
+COMPATIBLE_IOCTL(FBIOGET_FCURSORINFO)
+COMPATIBLE_IOCTL(FBIOGET_VCURSORINFO)
+COMPATIBLE_IOCTL(FBIOPUT_VCURSORINFO)
+COMPATIBLE_IOCTL(FBIOGET_CURSORSTATE)
+COMPATIBLE_IOCTL(FBIOPUT_CURSORSTATE)
+COMPATIBLE_IOCTL(FBIOGET_CON2FBMAP)
+COMPATIBLE_IOCTL(FBIOPUT_CON2FBMAP)
+/* Little f */
+COMPATIBLE_IOCTL(FIOCLEX)
+COMPATIBLE_IOCTL(FIONCLEX)
+COMPATIBLE_IOCTL(FIOASYNC)
+COMPATIBLE_IOCTL(FIONBIO)
+COMPATIBLE_IOCTL(FIONREAD)  /* This is also TIOCINQ */
+/* 0x00 */
+COMPATIBLE_IOCTL(FIBMAP)
+COMPATIBLE_IOCTL(FIGETBSZ)
+/* 0x03 -- HD/IDE ioctl's used by hdparm and friends.
+ *         Some need translations, these do not.
+ */
+COMPATIBLE_IOCTL(HDIO_GET_IDENTITY)
+COMPATIBLE_IOCTL(HDIO_SET_DMA)
+COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS)
+COMPATIBLE_IOCTL(HDIO_SET_UNMASKINTR)
+COMPATIBLE_IOCTL(HDIO_SET_NOWERR)
+COMPATIBLE_IOCTL(HDIO_SET_32BIT)
+COMPATIBLE_IOCTL(HDIO_SET_MULTCOUNT)
+COMPATIBLE_IOCTL(HDIO_DRIVE_CMD)
+COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE)
+COMPATIBLE_IOCTL(HDIO_SCAN_HWIF)
+COMPATIBLE_IOCTL(HDIO_SET_NICE)
+/* 0x02 -- Floppy ioctls */
+COMPATIBLE_IOCTL(FDMSGON)
+COMPATIBLE_IOCTL(FDMSGOFF)
+COMPATIBLE_IOCTL(FDSETEMSGTRESH)
+COMPATIBLE_IOCTL(FDFLUSH)
+COMPATIBLE_IOCTL(FDWERRORCLR)
+COMPATIBLE_IOCTL(FDSETMAXERRS)
+COMPATIBLE_IOCTL(FDGETMAXERRS)
+COMPATIBLE_IOCTL(FDGETDRVTYP)
+COMPATIBLE_IOCTL(FDEJECT)
+COMPATIBLE_IOCTL(FDCLRPRM)
+COMPATIBLE_IOCTL(FDFMTBEG)
+COMPATIBLE_IOCTL(FDFMTEND)
+COMPATIBLE_IOCTL(FDRESET)
+COMPATIBLE_IOCTL(FDTWADDLE)
+COMPATIBLE_IOCTL(FDFMTTRK)
+COMPATIBLE_IOCTL(FDRAWCMD)
+/* 0x12 */
+COMPATIBLE_IOCTL(BLKROSET)
+COMPATIBLE_IOCTL(BLKROGET)
+COMPATIBLE_IOCTL(BLKRRPART)
+COMPATIBLE_IOCTL(BLKFLSBUF)
+COMPATIBLE_IOCTL(BLKRASET)
+COMPATIBLE_IOCTL(BLKFRASET)
+COMPATIBLE_IOCTL(BLKSECTSET)
+COMPATIBLE_IOCTL(BLKSSZGET)
+
+/* RAID */
+COMPATIBLE_IOCTL(RAID_VERSION)
+COMPATIBLE_IOCTL(GET_ARRAY_INFO)
+COMPATIBLE_IOCTL(GET_DISK_INFO)
+COMPATIBLE_IOCTL(PRINT_RAID_DEBUG)
+COMPATIBLE_IOCTL(CLEAR_ARRAY)
+COMPATIBLE_IOCTL(ADD_NEW_DISK)
+COMPATIBLE_IOCTL(HOT_REMOVE_DISK)
+COMPATIBLE_IOCTL(SET_ARRAY_INFO)
+COMPATIBLE_IOCTL(SET_DISK_INFO)
+COMPATIBLE_IOCTL(WRITE_RAID_INFO)
+COMPATIBLE_IOCTL(UNPROTECT_ARRAY)
+COMPATIBLE_IOCTL(PROTECT_ARRAY)
+COMPATIBLE_IOCTL(HOT_ADD_DISK)
+COMPATIBLE_IOCTL(SET_DISK_FAULTY)
+COMPATIBLE_IOCTL(RUN_ARRAY)
+COMPATIBLE_IOCTL(START_ARRAY)
+COMPATIBLE_IOCTL(STOP_ARRAY)
+COMPATIBLE_IOCTL(STOP_ARRAY_RO)
+COMPATIBLE_IOCTL(RESTART_ARRAY_RW)
+
+/* Big K */
+COMPATIBLE_IOCTL(PIO_FONT)
+COMPATIBLE_IOCTL(GIO_FONT)
+COMPATIBLE_IOCTL(KDSIGACCEPT)
+COMPATIBLE_IOCTL(KDGETKEYCODE)
+COMPATIBLE_IOCTL(KDSETKEYCODE)
+COMPATIBLE_IOCTL(KIOCSOUND)
+COMPATIBLE_IOCTL(KDMKTONE)
+COMPATIBLE_IOCTL(KDGKBTYPE)
+COMPATIBLE_IOCTL(KDSETMODE)
+COMPATIBLE_IOCTL(KDGETMODE)
+COMPATIBLE_IOCTL(KDSKBMODE)
+COMPATIBLE_IOCTL(KDGKBMODE)
+COMPATIBLE_IOCTL(KDSKBMETA)
+COMPATIBLE_IOCTL(KDGKBMETA)
+COMPATIBLE_IOCTL(KDGKBENT)
+COMPATIBLE_IOCTL(KDSKBENT)
+COMPATIBLE_IOCTL(KDGKBSENT)
+COMPATIBLE_IOCTL(KDSKBSENT)
+COMPATIBLE_IOCTL(KDGKBDIACR)
+COMPATIBLE_IOCTL(KDSKBDIACR)
+COMPATIBLE_IOCTL(KDGKBLED)
+COMPATIBLE_IOCTL(KDSKBLED)
+COMPATIBLE_IOCTL(KDGETLED)
+COMPATIBLE_IOCTL(KDSETLED)
+COMPATIBLE_IOCTL(GIO_SCRNMAP)
+COMPATIBLE_IOCTL(PIO_SCRNMAP)
+COMPATIBLE_IOCTL(GIO_UNISCRNMAP)
+COMPATIBLE_IOCTL(PIO_UNISCRNMAP)
+COMPATIBLE_IOCTL(PIO_FONTRESET)
+COMPATIBLE_IOCTL(PIO_UNIMAPCLR)
+/* Big S */
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
+COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
+COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
+COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
+COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_ENABLE)
+COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE)
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
+COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
+/* Big V */
+COMPATIBLE_IOCTL(VT_SETMODE)
+COMPATIBLE_IOCTL(VT_GETMODE)
+COMPATIBLE_IOCTL(VT_GETSTATE)
+COMPATIBLE_IOCTL(VT_OPENQRY)
+COMPATIBLE_IOCTL(VT_ACTIVATE)
+COMPATIBLE_IOCTL(VT_WAITACTIVE)
+COMPATIBLE_IOCTL(VT_RELDISP)
+COMPATIBLE_IOCTL(VT_DISALLOCATE)
+COMPATIBLE_IOCTL(VT_RESIZE)
+COMPATIBLE_IOCTL(VT_RESIZEX)
+COMPATIBLE_IOCTL(VT_LOCKSWITCH)
+COMPATIBLE_IOCTL(VT_UNLOCKSWITCH)
+/* Little v, the video4linux ioctls */
+COMPATIBLE_IOCTL(VIDIOCGCAP)
+COMPATIBLE_IOCTL(VIDIOCGCHAN)
+COMPATIBLE_IOCTL(VIDIOCSCHAN)
+COMPATIBLE_IOCTL(VIDIOCGPICT)
+COMPATIBLE_IOCTL(VIDIOCSPICT)
+COMPATIBLE_IOCTL(VIDIOCCAPTURE)
+COMPATIBLE_IOCTL(VIDIOCKEY)
+COMPATIBLE_IOCTL(VIDIOCGAUDIO)
+COMPATIBLE_IOCTL(VIDIOCSAUDIO)
+COMPATIBLE_IOCTL(VIDIOCSYNC)
+COMPATIBLE_IOCTL(VIDIOCMCAPTURE)
+COMPATIBLE_IOCTL(VIDIOCGMBUF)
+COMPATIBLE_IOCTL(VIDIOCGUNIT)
+COMPATIBLE_IOCTL(VIDIOCGCAPTURE)
+COMPATIBLE_IOCTL(VIDIOCSCAPTURE)
+/* BTTV specific... */
+COMPATIBLE_IOCTL(_IOW('v',  BASE_VIDIOCPRIVATE+0, char [256]))
+COMPATIBLE_IOCTL(_IOR('v',  BASE_VIDIOCPRIVATE+1, char [256]))
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int))
+COMPATIBLE_IOCTL(_IOW('v' , BASE_VIDIOCPRIVATE+3, char [16])) /* struct bttv_pll_info */
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+4, int))
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+5, int))
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+6, int))
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+7, int))
+/* Little p (/dev/rtc, /dev/envctrl, etc.) */
+COMPATIBLE_IOCTL(RTC_AIE_ON)
+COMPATIBLE_IOCTL(RTC_AIE_OFF)
+COMPATIBLE_IOCTL(RTC_UIE_ON)
+COMPATIBLE_IOCTL(RTC_UIE_OFF)
+COMPATIBLE_IOCTL(RTC_PIE_ON)
+COMPATIBLE_IOCTL(RTC_PIE_OFF)
+COMPATIBLE_IOCTL(RTC_WIE_ON)
+COMPATIBLE_IOCTL(RTC_WIE_OFF)
+COMPATIBLE_IOCTL(RTC_ALM_SET)
+COMPATIBLE_IOCTL(RTC_ALM_READ)
+COMPATIBLE_IOCTL(RTC_RD_TIME)
+COMPATIBLE_IOCTL(RTC_SET_TIME)
+COMPATIBLE_IOCTL(RTC_WKALM_SET)
+COMPATIBLE_IOCTL(RTC_WKALM_RD)
+HANDLE_IOCTL(RTC_IRQP_READ,  rtc32_ioctl)
+HANDLE_IOCTL(RTC_IRQP_READ32,rtc32_ioctl)
+HANDLE_IOCTL(RTC_IRQP_SET32, rtc32_ioctl)
+HANDLE_IOCTL(RTC_EPOCH_READ32, rtc32_ioctl)
+HANDLE_IOCTL(RTC_EPOCH_SET32, rtc32_ioctl)
+/* Little m */
+COMPATIBLE_IOCTL(MTIOCTOP)
+/* Socket level stuff */
+COMPATIBLE_IOCTL(FIOSETOWN)
+COMPATIBLE_IOCTL(SIOCSPGRP)
+COMPATIBLE_IOCTL(FIOGETOWN)
+COMPATIBLE_IOCTL(SIOCGPGRP)
+COMPATIBLE_IOCTL(SIOCATMARK)
+COMPATIBLE_IOCTL(SIOCSIFLINK)
+COMPATIBLE_IOCTL(SIOCSIFENCAP)
+COMPATIBLE_IOCTL(SIOCGIFENCAP)
+COMPATIBLE_IOCTL(SIOCSIFBR)
+COMPATIBLE_IOCTL(SIOCGIFBR)
+COMPATIBLE_IOCTL(SIOCSARP)
+COMPATIBLE_IOCTL(SIOCGARP)
+COMPATIBLE_IOCTL(SIOCDARP)
+COMPATIBLE_IOCTL(SIOCSRARP)
+COMPATIBLE_IOCTL(SIOCGRARP)
+COMPATIBLE_IOCTL(SIOCDRARP)
+COMPATIBLE_IOCTL(SIOCADDDLCI)
+COMPATIBLE_IOCTL(SIOCDELDLCI)
+/* SG stuff */
+COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
+COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
+COMPATIBLE_IOCTL(SG_EMULATED_HOST)
+COMPATIBLE_IOCTL(SG_SET_TRANSFORM)
+COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
+COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
+COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
+COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
+COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
+COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
+COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
+COMPATIBLE_IOCTL(SG_GET_PACK_ID)
+COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
+COMPATIBLE_IOCTL(SG_SET_DEBUG)
+COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
+COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
+COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
+COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
+COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
+COMPATIBLE_IOCTL(SG_SCSI_RESET)
+COMPATIBLE_IOCTL(SG_IO)
+COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
+COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
+COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
+/* PPP stuff */
+COMPATIBLE_IOCTL(PPPIOCGFLAGS)
+COMPATIBLE_IOCTL(PPPIOCSFLAGS)
+COMPATIBLE_IOCTL(PPPIOCGASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCSASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCGUNIT)
+COMPATIBLE_IOCTL(PPPIOCGRASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCSRASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCGMRU)
+COMPATIBLE_IOCTL(PPPIOCSMRU)
+COMPATIBLE_IOCTL(PPPIOCSMAXCID)
+COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCXFERUNIT)
+COMPATIBLE_IOCTL(PPPIOCGNPMODE)
+COMPATIBLE_IOCTL(PPPIOCSNPMODE)
+COMPATIBLE_IOCTL(PPPIOCGDEBUG)
+COMPATIBLE_IOCTL(PPPIOCSDEBUG)
+COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
+COMPATIBLE_IOCTL(PPPIOCATTACH)
+COMPATIBLE_IOCTL(PPPIOCDETACH)
+COMPATIBLE_IOCTL(PPPIOCSMRRU)
+COMPATIBLE_IOCTL(PPPIOCCONNECT)
+COMPATIBLE_IOCTL(PPPIOCDISCONN)
+COMPATIBLE_IOCTL(PPPIOCATTCHAN)
+COMPATIBLE_IOCTL(PPPIOCGCHAN)
+/* PPPOX */
+COMPATIBLE_IOCTL(PPPOEIOCSFWD);
+COMPATIBLE_IOCTL(PPPOEIOCDFWD);
+/* CDROM stuff */
+COMPATIBLE_IOCTL(CDROMPAUSE)
+COMPATIBLE_IOCTL(CDROMRESUME)
+COMPATIBLE_IOCTL(CDROMPLAYMSF)
+COMPATIBLE_IOCTL(CDROMPLAYTRKIND)
+COMPATIBLE_IOCTL(CDROMREADTOCHDR)
+COMPATIBLE_IOCTL(CDROMREADTOCENTRY)
+COMPATIBLE_IOCTL(CDROMSTOP)
+COMPATIBLE_IOCTL(CDROMSTART)
+COMPATIBLE_IOCTL(CDROMEJECT)
+COMPATIBLE_IOCTL(CDROMVOLCTRL)
+COMPATIBLE_IOCTL(CDROMSUBCHNL)
+COMPATIBLE_IOCTL(CDROMEJECT_SW)
+COMPATIBLE_IOCTL(CDROMMULTISESSION)
+COMPATIBLE_IOCTL(CDROM_GET_MCN)
+COMPATIBLE_IOCTL(CDROMRESET)
+COMPATIBLE_IOCTL(CDROMVOLREAD)
+COMPATIBLE_IOCTL(CDROMSEEK)
+COMPATIBLE_IOCTL(CDROMPLAYBLK)
+COMPATIBLE_IOCTL(CDROMCLOSETRAY)
+COMPATIBLE_IOCTL(CDROM_SET_OPTIONS)
+COMPATIBLE_IOCTL(CDROM_CLEAR_OPTIONS)
+COMPATIBLE_IOCTL(CDROM_SELECT_SPEED)
+COMPATIBLE_IOCTL(CDROM_SELECT_DISC)
+COMPATIBLE_IOCTL(CDROM_MEDIA_CHANGED)
+COMPATIBLE_IOCTL(CDROM_DRIVE_STATUS)
+COMPATIBLE_IOCTL(CDROM_DISC_STATUS)
+COMPATIBLE_IOCTL(CDROM_CHANGER_NSLOTS)
+COMPATIBLE_IOCTL(CDROM_LOCKDOOR)
+COMPATIBLE_IOCTL(CDROM_DEBUG)
+COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY)
+/* Big L */
+COMPATIBLE_IOCTL(LOOP_SET_FD)
+COMPATIBLE_IOCTL(LOOP_CLR_FD)
+/* Big Q for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_INFO)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_CTRLRATE)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETOUTCOUNT)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETINCOUNT)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_PERCMODE)
+COMPATIBLE_IOCTL(SNDCTL_FM_LOAD_INSTR)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_TESTMIDI)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_RESETSAMPLES)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_NRSYNTHS)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_NRMIDIS)
+COMPATIBLE_IOCTL(SNDCTL_MIDI_INFO)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_THRESHOLD)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_MEMAVL)
+COMPATIBLE_IOCTL(SNDCTL_FM_4OP_ENABLE)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_PANIC)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_OUTOFBAND)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETTIME)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_ID)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_CONTROL)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_REMOVESAMPLE)
+/* Big T for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_TMR_TIMEBASE)
+COMPATIBLE_IOCTL(SNDCTL_TMR_START)
+COMPATIBLE_IOCTL(SNDCTL_TMR_STOP)
+COMPATIBLE_IOCTL(SNDCTL_TMR_CONTINUE)
+COMPATIBLE_IOCTL(SNDCTL_TMR_TEMPO)
+COMPATIBLE_IOCTL(SNDCTL_TMR_SOURCE)
+COMPATIBLE_IOCTL(SNDCTL_TMR_METRONOME)
+COMPATIBLE_IOCTL(SNDCTL_TMR_SELECT)
+/* Little m for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_MIDI_PRETIME)
+COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUMODE)
+COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUCMD)
+/* Big P for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_DSP_RESET)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SYNC)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SPEED)
+COMPATIBLE_IOCTL(SNDCTL_DSP_STEREO)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETBLKSIZE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_CHANNELS)
+COMPATIBLE_IOCTL(SOUND_PCM_WRITE_FILTER)
+COMPATIBLE_IOCTL(SNDCTL_DSP_POST)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SUBDIVIDE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETFRAGMENT)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETFMTS)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETFMT)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETOSPACE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETISPACE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_NONBLOCK)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETCAPS)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETTRIGGER)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETTRIGGER)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETIPTR)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETOPTR)
+/* SNDCTL_DSP_MAPINBUF,  XXX needs translation */
+/* SNDCTL_DSP_MAPOUTBUF,  XXX needs translation */
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETSYNCRO)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETDUPLEX)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETODELAY)
+COMPATIBLE_IOCTL(SNDCTL_DSP_PROFILE)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_RATE)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_CHANNELS)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_BITS)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_FILTER)
+/* Big C for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_COPR_RESET)
+COMPATIBLE_IOCTL(SNDCTL_COPR_LOAD)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RDATA)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RCODE)
+COMPATIBLE_IOCTL(SNDCTL_COPR_WDATA)
+COMPATIBLE_IOCTL(SNDCTL_COPR_WCODE)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RUN)
+COMPATIBLE_IOCTL(SNDCTL_COPR_HALT)
+COMPATIBLE_IOCTL(SNDCTL_COPR_SENDMSG)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RCVMSG)
+/* Big M for sound/OSS */
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_VOLUME)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_BASS)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_TREBLE)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_SYNTH)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_PCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_SPEAKER)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_MIC)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_CD)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_IMIX)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_ALTPCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECLEV)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_IGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_OGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE1)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE2)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE3)
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL1))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL2))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL3))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEIN))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEOUT))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_VIDEO))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_RADIO))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_MONITOR))
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_MUTE)
+/* SOUND_MIXER_READ_ENHANCE,  same value as READ_MUTE */
+/* SOUND_MIXER_READ_LOUD,  same value as READ_MUTE */
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECSRC)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_DEVMASK)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECMASK)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_STEREODEVS)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_CAPS)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_VOLUME)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_BASS)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_TREBLE)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SYNTH)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_PCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SPEAKER)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MIC)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_CD)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IMIX)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_ALTPCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECLEV)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_OGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE1)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE2)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE3)
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL1))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL2))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL3))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEIN))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEOUT))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_VIDEO))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_RADIO))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_MONITOR))
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MUTE)
+/* SOUND_MIXER_WRITE_ENHANCE,  same value as WRITE_MUTE */
+/* SOUND_MIXER_WRITE_LOUD,  same value as WRITE_MUTE */
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECSRC)
+COMPATIBLE_IOCTL(SOUND_MIXER_INFO)
+COMPATIBLE_IOCTL(SOUND_OLD_MIXER_INFO)
+COMPATIBLE_IOCTL(SOUND_MIXER_ACCESS)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE1)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE2)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE3)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE4)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE5)
+COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS)
+COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS)
+COMPATIBLE_IOCTL(OSS_GETVERSION)
+/* AUTOFS */
+COMPATIBLE_IOCTL(AUTOFS_IOC_READY)
+COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL)
+COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
+/* DEVFS */
+COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV)
+COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK)
+COMPATIBLE_IOCTL(DEVFSDIOC_RELEASE_EVENT_QUEUE)
+COMPATIBLE_IOCTL(DEVFSDIOC_SET_DEBUG_MASK)
+/* SMB ioctls which do not need any translations */
+COMPATIBLE_IOCTL(SMB_IOC_NEWCONN)
+/* Little a */
+COMPATIBLE_IOCTL(ATMSIGD_CTRL)
+COMPATIBLE_IOCTL(ATMARPD_CTRL)
+COMPATIBLE_IOCTL(ATMLEC_CTRL)
+COMPATIBLE_IOCTL(ATMLEC_MCAST)
+COMPATIBLE_IOCTL(ATMLEC_DATA)
+COMPATIBLE_IOCTL(ATM_SETSC)
+COMPATIBLE_IOCTL(SIOCSIFATMTCP)
+COMPATIBLE_IOCTL(SIOCMKCLIP)
+COMPATIBLE_IOCTL(ATMARP_MKIP)
+COMPATIBLE_IOCTL(ATMARP_SETENTRY)
+COMPATIBLE_IOCTL(ATMARP_ENCAP)
+COMPATIBLE_IOCTL(ATMTCP_CREATE)
+COMPATIBLE_IOCTL(ATMTCP_REMOVE)
+COMPATIBLE_IOCTL(ATMMPC_CTRL)
+COMPATIBLE_IOCTL(ATMMPC_DATA)
+#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
+/* 0xfe - lvm */
+COMPATIBLE_IOCTL(VG_SET_EXTENDABLE)
+COMPATIBLE_IOCTL(VG_STATUS_GET_COUNT)
+COMPATIBLE_IOCTL(VG_STATUS_GET_NAMELIST)
+COMPATIBLE_IOCTL(VG_REMOVE)
+COMPATIBLE_IOCTL(VG_RENAME)
+COMPATIBLE_IOCTL(VG_REDUCE)
+COMPATIBLE_IOCTL(PE_LOCK_UNLOCK)
+COMPATIBLE_IOCTL(PV_FLUSH)
+COMPATIBLE_IOCTL(LVM_LOCK_LVM)
+COMPATIBLE_IOCTL(LVM_GET_IOP_VERSION)
+#ifdef LVM_TOTAL_RESET
+COMPATIBLE_IOCTL(LVM_RESET)
+#endif
+COMPATIBLE_IOCTL(LV_SET_ACCESS)
+COMPATIBLE_IOCTL(LV_SET_STATUS)
+COMPATIBLE_IOCTL(LV_SET_ALLOCATION)
+COMPATIBLE_IOCTL(LE_REMAP)
+COMPATIBLE_IOCTL(LV_BMAP)
+COMPATIBLE_IOCTL(LV_SNAPSHOT_USE_RATE)
+#endif /* LVM */
+#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC)
+COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID)
+COMPATIBLE_IOCTL(DRM_IOCTL_AUTH_MAGIC)
+COMPATIBLE_IOCTL(DRM_IOCTL_BLOCK)
+COMPATIBLE_IOCTL(DRM_IOCTL_UNBLOCK)
+COMPATIBLE_IOCTL(DRM_IOCTL_CONTROL)
+COMPATIBLE_IOCTL(DRM_IOCTL_ADD_BUFS)
+COMPATIBLE_IOCTL(DRM_IOCTL_MARK_BUFS)
+COMPATIBLE_IOCTL(DRM_IOCTL_ADD_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_RM_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_MOD_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_GET_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_SWITCH_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_NEW_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_ADD_DRAW)
+COMPATIBLE_IOCTL(DRM_IOCTL_RM_DRAW)
+COMPATIBLE_IOCTL(DRM_IOCTL_LOCK)
+COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK)
+COMPATIBLE_IOCTL(DRM_IOCTL_FINISH)
+#endif /* DRM */
+#ifdef CONFIG_AUTOFS_FS
+COMPATIBLE_IOCTL(AUTOFS_IOC_READY);
+COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL);
+COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC);
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER);
+COMPATIBLE_IOCTL(AUTOFS_IOC_SETTIMEOUT);
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE);
+#endif
+#ifdef CONFIG_RTC
+COMPATIBLE_IOCTL(RTC_AIE_ON);
+COMPATIBLE_IOCTL(RTC_AIE_OFF);
+COMPATIBLE_IOCTL(RTC_UIE_ON);
+COMPATIBLE_IOCTL(RTC_UIE_OFF);
+COMPATIBLE_IOCTL(RTC_PIE_ON);
+COMPATIBLE_IOCTL(RTC_PIE_OFF);
+COMPATIBLE_IOCTL(RTC_WIE_ON);
+COMPATIBLE_IOCTL(RTC_WIE_OFF);
+COMPATIBLE_IOCTL(RTC_ALM_SET);
+COMPATIBLE_IOCTL(RTC_ALM_READ);
+COMPATIBLE_IOCTL(RTC_RD_TIME);
+COMPATIBLE_IOCTL(RTC_SET_TIME);
+COMPATIBLE_IOCTL(RTC_IRQP_READ);
+COMPATIBLE_IOCTL(RTC_IRQP_SET);
+COMPATIBLE_IOCTL(RTC_EPOCH_READ);
+COMPATIBLE_IOCTL(RTC_EPOCH_SET);
+COMPATIBLE_IOCTL(RTC_WKALM_SET);
+COMPATIBLE_IOCTL(RTC_WKALM_RD);
+#endif
+HANDLE_IOCTL(REISERFS_IOC_UNPACK32, reiserfs_ioctl32);
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32);
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32);
+/* serial driver */ 
+HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl);
+HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl);
+/* elevator */
+COMPATIBLE_IOCTL(BLKELVGET)
+COMPATIBLE_IOCTL(BLKELVSET)
+/* Misc. */
+COMPATIBLE_IOCTL(0x41545900)		/* ATYIO_CLKR */
+COMPATIBLE_IOCTL(0x41545901)		/* ATYIO_CLKW */
+COMPATIBLE_IOCTL(PCIIOC_CONTROLLER)
+COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
+COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM)
+COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE)
+/* And these ioctls need translation */
+HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32)
+HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf)
+HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFMETRIC, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFMETRIC, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFMTU, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFMTU, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFMEM, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFMEM, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFHWADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFHWADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCADDMULTI, dev_ifsioc)
+HANDLE_IOCTL(SIOCDELMULTI, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFINDEX, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFMAP, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFBRDADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFBRDADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFDSTADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFDSTADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFNETMASK, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGPPPSTATS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGPPPCSTATS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGPPPVER, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc)
+HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl)
+HANDLE_IOCTL(SIOCADDRT, routing_ioctl)
+HANDLE_IOCTL(SIOCDELRT, routing_ioctl)
+/* Raw devices */
+HANDLE_IOCTL(RAW_SETBIND, raw_ioctl)
+/* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
+HANDLE_IOCTL(SIOCRTMSG, ret_einval)
+HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp)
+HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo)
+HANDLE_IOCTL(BLKRAGET, w_long)
+HANDLE_IOCTL(BLKGETSIZE, w_long)
+HANDLE_IOCTL(0x1260, broken_blkgetsize)
+HANDLE_IOCTL(BLKFRAGET, w_long)
+HANDLE_IOCTL(BLKSECTGET, w_long)
+HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans)
+HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans)
+HANDLE_IOCTL(FBIOPUTCMAP, fb_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_MULTCOUNT, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_NOWERR, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_NICE, hdio_ioctl_trans)
+HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans)
+HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans)
+HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans)
+HANDLE_IOCTL(FDSETDRVPRM32, fd_ioctl_trans)
+HANDLE_IOCTL(FDGETDRVPRM32, fd_ioctl_trans)
+HANDLE_IOCTL(FDGETDRVSTAT32, fd_ioctl_trans)
+HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans)
+HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans)
+HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans)
+HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans)
+HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans)
+HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans)
+HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans)
+HANDLE_IOCTL(MTIOCGETCONFIG32, mt_ioctl_trans)
+HANDLE_IOCTL(MTIOCSETCONFIG32, mt_ioctl_trans)
+HANDLE_IOCTL(CDROMREADMODE2, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADMODE1, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADRAW, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADCOOKED, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADALL, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans)
+HANDLE_IOCTL(LOOP_SET_STATUS, loop_status)
+HANDLE_IOCTL(LOOP_GET_STATUS, loop_status)
+#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
+HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout)
+HANDLE_IOCTL(PIO_FONTX, do_fontx_ioctl)
+HANDLE_IOCTL(GIO_FONTX, do_fontx_ioctl)
+HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl)
+HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl)
+HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl)
+HANDLE_IOCTL(EXT2_IOC32_GETFLAGS, do_ext2_ioctl)
+HANDLE_IOCTL(EXT2_IOC32_SETFLAGS, do_ext2_ioctl)
+HANDLE_IOCTL(EXT2_IOC32_GETVERSION, do_ext2_ioctl)
+HANDLE_IOCTL(EXT2_IOC32_SETVERSION, do_ext2_ioctl)
+HANDLE_IOCTL(VIDIOCGTUNER32, do_video_ioctl)
+HANDLE_IOCTL(VIDIOCSTUNER32, do_video_ioctl)
+HANDLE_IOCTL(VIDIOCGWIN32, do_video_ioctl)
+HANDLE_IOCTL(VIDIOCSWIN32, do_video_ioctl)
+HANDLE_IOCTL(VIDIOCGFBUF32, do_video_ioctl)
+HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl)
+HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl)
+HANDLE_IOCTL(VIDIOCSFREQ32, do_video_ioctl)
+/* One SMB ioctl needs translations. */
+#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, __kernel_uid_t32)
+HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid)
+HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETESI32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETADDR32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_RSTADDR32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_ADDADDR32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_DELADDR32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETCIRANGE32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_SETCIRANGE32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_QUERYLOOP32, do_atm_ioctl)
+HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl)
+HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl)
+HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl)
+HANDLE_IOCTL(SONET_SETDIAG, do_atm_ioctl)
+HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl)
+HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl)
+HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl)
+HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl)
+#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
+HANDLE_IOCTL(VG_STATUS, do_lvm_ioctl)
+HANDLE_IOCTL(VG_CREATE, do_lvm_ioctl)
+HANDLE_IOCTL(VG_EXTEND, do_lvm_ioctl)
+HANDLE_IOCTL(LV_CREATE, do_lvm_ioctl)
+HANDLE_IOCTL(LV_REMOVE, do_lvm_ioctl)
+HANDLE_IOCTL(LV_EXTEND, do_lvm_ioctl)
+HANDLE_IOCTL(LV_REDUCE, do_lvm_ioctl)
+HANDLE_IOCTL(LV_RENAME, do_lvm_ioctl)
+HANDLE_IOCTL(LV_STATUS_BYNAME, do_lvm_ioctl)
+HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl)
+HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl)
+HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl)
+#endif /* LVM */
+#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version);
+HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique);
+HANDLE_IOCTL(DRM32_IOCTL_SET_UNIQUE, drm32_getsetunique);
+HANDLE_IOCTL(DRM32_IOCTL_ADD_MAP, drm32_addmap);
+HANDLE_IOCTL(DRM32_IOCTL_INFO_BUFS, drm32_info_bufs);
+HANDLE_IOCTL(DRM32_IOCTL_FREE_BUFS, drm32_free_bufs);
+HANDLE_IOCTL(DRM32_IOCTL_MAP_BUFS, drm32_map_bufs);
+HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma);
+HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx);
+#endif /* DRM */
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32);
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32);
+IOCTL_TABLE_END
+
+#define IOCTL_HASHSIZE 256
+struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
+
+extern struct ioctl_trans ioctl_start[], ioctl_end[]; 
+
+static inline unsigned long ioctl32_hash(unsigned long cmd)
+{
+	return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
+}
+
+static void ioctl32_insert_translation(struct ioctl_trans *trans)
+{
+	unsigned long hash;
+	struct ioctl_trans *t;
+
+	hash = ioctl32_hash (trans->cmd);
+	if (!ioctl32_hash_table[hash])
+		ioctl32_hash_table[hash] = trans;
+	else {
+		t = ioctl32_hash_table[hash];
+		while (t->next)
+			t = t->next;
+		trans->next = 0;
+		t->next = trans;
+	}
+}
+
+static int __init init_sys32_ioctl(void)
+{
+	int i;
+
+	for (i = 0; &ioctl_start[i] < &ioctl_end[0]; i++) {
+		if (ioctl_start[i].next != 0) { 
+			printk("ioctl translation %d bad\n",i); 
+			return -1;
+		}
+
+		ioctl32_insert_translation(&ioctl_start[i]);
+	}
+	return 0;
+}
+
+__initcall(init_sys32_ioctl);
+
+static struct ioctl_trans *ioctl_free_list;
+
+/* Never free them really. This avoids SMP races. With a Read-Copy-Update
+   enabled kernel we could just use the RCU infrastructure for this. */
+static void free_ioctl(struct ioctl_trans *t) 
+{ 
+	t->cmd = 0; 
+	mb();
+	t->next = ioctl_free_list;
+	ioctl_free_list = t;
+} 
+
+int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *))
+{
+	struct ioctl_trans *t;
+	unsigned long hash = ioctl32_hash(cmd);
+
+	lock_kernel(); 
+	for (t = (struct ioctl_trans *)ioctl32_hash_table[hash];
+	     t;
+	     t = t->next) { 
+		if (t->cmd == cmd) {
+			printk("Trying to register duplicated ioctl32 handler %x\n", cmd);
+			unlock_kernel();
+			return -EINVAL;
+		}
+	}
+
+	if (ioctl_free_list) { 
+		t = ioctl_free_list; 
+		ioctl_free_list = t->next; 
+	} else { 
+		t = kmalloc(sizeof(struct ioctl_trans), GFP_KERNEL); 
+		if (!t) { 
+			unlock_kernel();
+		return -ENOMEM;
+	}
+	}
+	
+	t->next = NULL;
+	t->cmd = cmd;
+	t->handler = handler; 
+	ioctl32_insert_translation(t);
+
+	unlock_kernel();
+	return 0;
+}
+
+static inline int builtin_ioctl(struct ioctl_trans *t)
+{ 
+	return t >= (struct ioctl_trans *)ioctl_start &&
+	       t < (struct ioctl_trans *)ioctl_end; 
+} 
+
+/* Problem: 
+   This function cannot unregister duplicate ioctls, because they are not
+   unique.
+   When they happen we need to extend the prototype to pass handler too. */
+
+int unregister_ioctl32_conversion(unsigned int cmd)
+{
+	unsigned long hash = ioctl32_hash(cmd);
+	struct ioctl_trans *t, *t1;
+
+	lock_kernel(); 
+
+	t = (struct ioctl_trans *)ioctl32_hash_table[hash];
+	if (!t) { 
+		unlock_kernel();
+		return -EINVAL;
+	} 
+
+	if (t->cmd == cmd) { 
+		if (builtin_ioctl(t)) {
+			printk("%p tried to unregister builtin ioctl %x\n",
+			       __builtin_return_address(0), cmd);
+		} else { 
+		ioctl32_hash_table[hash] = t->next;
+			free_ioctl(t); 
+			unlock_kernel();
+		return 0;
+		}
+	} 
+	while (t->next) {
+		t1 = (struct ioctl_trans *)(long)t->next;
+		if (t1->cmd == cmd) { 
+			if (builtin_ioctl(t1)) {
+				printk("%p tried to unregister builtin ioctl %x\n",
+				       __builtin_return_address(0), cmd);
+				goto out;
+			} else { 
+			t->next = t1->next;
+				free_ioctl(t1); 
+				unlock_kernel();
+			return 0;
+		}
+		}
+		t = t1;
+	}
+	printk(KERN_ERR "Trying to free unknown 32bit ioctl handler %x\n", cmd);
+ out:
+	unlock_kernel();
+	return -EINVAL;
+}
+
+EXPORT_SYMBOL(register_ioctl32_conversion); 
+EXPORT_SYMBOL(unregister_ioctl32_conversion); 
+
+asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct file * filp;
+	int error = -EBADF;
+	int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
+	struct ioctl_trans *t;
+
+	filp = fget(fd);
+	if(!filp)
+		goto out2;
+
+	if (!filp->f_op || !filp->f_op->ioctl) {
+		error = sys_ioctl (fd, cmd, arg);
+		goto out;
+	}
+
+	t = (struct ioctl_trans *)ioctl32_hash_table [ioctl32_hash (cmd)];
+
+	while (t && t->cmd != cmd)
+		t = (struct ioctl_trans *)t->next;
+	if (t) {
+		handler = t->handler;
+		error = handler(fd, cmd, arg, filp);
+	} else {
+		static int count = 0;
+		if (++count <= 50)
+			printk("sys32_ioctl(%s:%d): Unknown cmd fd(%d) "
+			       "cmd(%08x) arg(%08x)\n",
+			       current->comm, current->pid,
+			       (int)fd, (unsigned int)cmd, (unsigned int)arg);
+		error = -EINVAL;
+	}
+out:
+	fput(filp);
+out2:
+	return error;
+}
+
+extern unsigned long ia32_sys_call_table[];
+EXPORT_SYMBOL(ia32_sys_call_table);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/ia32/ia32_signal.c linux-2.4.20/arch/x86_64/ia32/ia32_signal.c
--- linux-2.4.19/arch/x86_64/ia32/ia32_signal.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/ia32/ia32_signal.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,524 @@
+/*
+ *  linux/arch/x86_64/ia32/ia32_signal.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
+ *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
+ *  2000-12-*   x86-64 compatibility mode signal handling by Andi Kleen
+ * 
+ *  $Id: ia32_signal.c,v 1.22 2002/07/29 10:34:03 ak Exp $
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/personality.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#include <asm/i387.h>
+#include <asm/ia32.h>
+#include <asm/ptrace.h>
+#include <asm/ia32_unistd.h>
+#include <asm/user32.h>
+#include <asm/sigcontext32.h>
+#include <asm/fpu32.h>
+
+#define ptr_to_u32(x) ((u32)(u64)(x))	/* avoid gcc warning */ 
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
+void signal_fault(struct pt_regs *regs, void *frame, char *where);
+
+static int ia32_copy_siginfo_to_user(siginfo_t32 *to, siginfo_t *from)
+{
+	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+		return -EFAULT;
+	if (from->si_code < 0)
+		return __copy_to_user(to, from, sizeof(siginfo_t));
+	else {
+		int err;
+
+		/* If you change siginfo_t structure, please be sure
+		   this code is fixed accordingly.
+		   It should never copy any pad contained in the structure
+		   to avoid security leaks, but must copy the generic
+		   3 ints plus the relevant union member.  */
+		err = __put_user(from->si_signo, &to->si_signo);
+		err |= __put_user(from->si_errno, &to->si_errno);
+		err |= __put_user((short)from->si_code, &to->si_code);
+		/* First 32bits of unions are always present.  */
+		err |= __put_user(from->si_pid, &to->si_pid);
+		switch (from->si_code >> 16) {
+		case __SI_FAULT >> 16:
+			break;
+		case __SI_CHLD >> 16:
+			err |= __put_user(from->si_utime, &to->si_utime);
+			err |= __put_user(from->si_stime, &to->si_stime);
+			err |= __put_user(from->si_status, &to->si_status);
+		default:
+			err |= __put_user(from->si_uid, &to->si_uid);
+			break;
+		/* case __SI_RT: This is not generated by the kernel as of now.  */
+		}
+		return err;
+	}
+}
+
+asmlinkage int
+sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs regs)
+{
+	sigset_t saveset;
+
+	mask &= _BLOCKABLE;
+	spin_lock_irq(&current->sigmask_lock);
+	saveset = current->blocked;
+	siginitset(&current->blocked, mask);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	regs.rax = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(&regs, &saveset))
+			return -EINTR;
+	}
+}
+
+asmlinkage int
+sys32_sigaltstack(const stack_ia32_t *uss_ptr, stack_ia32_t *uoss_ptr, 
+				  struct pt_regs regs)
+{
+	stack_t uss,uoss; 
+	int ret;
+	mm_segment_t seg; 
+	if (!access_ok(VERIFY_READ,uss_ptr,sizeof(stack_ia32_t)) ||
+	    __get_user(ptr_to_u32(uss.ss_sp), &uss_ptr->ss_sp) ||
+	    __get_user((u32)uss.ss_flags, &uss_ptr->ss_flags) ||
+	    __get_user((u32)uss.ss_size, &uss_ptr->ss_size))
+		return -EFAULT;
+	seg = get_fs(); 
+	set_fs(KERNEL_DS); 
+	ret = do_sigaltstack(&uss, &uoss, regs.rsp);
+	set_fs(seg); 
+	if (ret >= 0 && uoss_ptr)  {
+		if (!access_ok(VERIFY_WRITE,uss_ptr,sizeof(stack_ia32_t)) ||
+		    __put_user(ptr_to_u32(uss.ss_sp), &uss_ptr->ss_sp) ||
+		    __put_user((u32)uss.ss_flags, &uss_ptr->ss_flags) ||
+		    __put_user((u32)uss.ss_size, &uss_ptr->ss_size))
+			ret = -EFAULT;
+	} 	
+	return ret;	
+}
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+
+struct sigframe
+{
+	u32 pretcode;
+	int sig;
+	struct sigcontext_ia32 sc;
+	struct _fpstate_ia32 fpstate;
+	unsigned int extramask[_IA32_NSIG_WORDS-1];
+	char retcode[8];
+};
+
+struct rt_sigframe
+{
+	u32 pretcode;
+	int sig;
+	u32 pinfo;
+	u32 puc;
+	struct siginfo32 info;
+	struct ucontext_ia32 uc;
+	struct _fpstate_ia32 fpstate;
+	char retcode[8];
+};
+
+static int
+ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 *sc, unsigned int *peax)
+{
+	unsigned int err = 0;
+	
+#if DEBUG_SIG
+	printk("SIG restore_sigcontext: sc=%p err(%x) eip(%x) cs(%x) flg(%x)\n",
+		sc, sc->err, sc->eip, sc->cs, sc->eflags);
+#endif
+#define COPY(x)		{ \
+	unsigned int reg;	\
+	err |= __get_user(reg, &sc->e ##x);	\
+	regs->r ## x = reg;			\
+}
+
+#define RELOAD_SEG(seg,mask)						\
+	{ unsigned int cur; 				\
+	  unsigned short pre;				\
+	  err |= __get_user(pre, &sc->seg);				\
+    	  asm volatile("movl %%" #seg ",%0" : "=r" (cur));		\
+	  pre |= mask; 							\
+	  if (pre != cur) loadsegment(seg,pre); }
+
+	/* Reload fs and gs if they have changed in the signal handler.
+	   This does not handle long fs/gs base changes in the handler, but 
+	   does not clobber them at least in the normal case. */ 
+	
+	{
+		unsigned short gs; 
+		err |= __get_user(gs, &sc->gs);
+		load_gs_index(gs); 
+	} 
+	RELOAD_SEG(fs,0);
+	RELOAD_SEG(ds,0);
+	RELOAD_SEG(es,0);
+
+	COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
+	COPY(dx); COPY(cx); COPY(ip);
+	/* Don't touch extended registers */ 
+
+#if 1	/* not ready for this yet */ 
+	err |= __get_user(regs->cs, &sc->cs); 
+	regs->cs |= 2; 	
+	err |= __get_user(regs->ss, &sc->ss); 
+	regs->ss |= 2; 
+#else
+	regs->cs = __USER32_CS;
+	regs->ss = __USER32_DS; 
+#endif
+	
+	{
+		unsigned int tmpflags;
+		err |= __get_user(tmpflags, &sc->eflags);
+		regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
+		regs->orig_rax = -1;		/* disable syscall checks */
+	}
+
+	{
+		u32 tmp;
+		struct _fpstate_ia32 * buf;
+		err |= __get_user(tmp, &sc->fpstate);
+		buf = (struct _fpstate_ia32 *) (u64)tmp;
+		if (buf) {
+			if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
+				goto badframe;
+			err |= restore_i387_ia32(current, buf, 0);
+		}
+	}
+
+	{ 
+		u32 tmp;
+		err |= __get_user(tmp, &sc->eax);
+		*peax = tmp;
+	}
+	return err;
+
+badframe:
+	return 1;
+}
+
+asmlinkage int sys32_sigreturn(struct pt_regs regs)
+{
+	struct sigframe *frame = (struct sigframe *)(regs.rsp - 8);
+	sigset_t set;
+	unsigned int eax;
+
+	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__get_user(set.sig[0], &frame->sc.oldmask)
+	    || (_IA32_NSIG_WORDS > 1
+		&& __copy_from_user((((char *) &set.sig) + 4), &frame->extramask,
+				    sizeof(frame->extramask))))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = set;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+	
+	if (ia32_restore_sigcontext(&regs, &frame->sc, &eax))
+		goto badframe;
+	return eax;
+
+badframe:
+	signal_fault(&regs,frame,"32bit sigreturn");
+	return 0;
+}	
+
+asmlinkage int sys32_rt_sigreturn(struct pt_regs regs)
+{
+	struct rt_sigframe *frame = (struct rt_sigframe *)(regs.rsp - 4);
+	sigset_t set;
+	stack_t st;
+	unsigned int eax;
+
+	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = set;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+	
+	if (ia32_restore_sigcontext(&regs, &frame->uc.uc_mcontext, &eax))
+		goto badframe;
+
+	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+		goto badframe;
+	/* It is more difficult to avoid calling this function than to
+	   call it and ignore errors.  */
+	{
+		mm_segment_t oldds = get_fs(); 
+		set_fs(KERNEL_DS); 
+		do_sigaltstack(&st, NULL, regs.rsp);
+		set_fs(oldds);  
+	}
+
+	return eax;
+
+badframe:
+	signal_fault(&regs,frame,"32bit rt sigreturn");
+	return 0;
+}	
+
+/*
+ * Set up a signal frame.
+ */
+
+static int
+ia32_setup_sigcontext(struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate,
+		 struct pt_regs *regs, unsigned int mask)
+{
+	int tmp, err = 0;
+
+	tmp = 0;
+	__asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
+	err |= __put_user(tmp, (unsigned int *)&sc->gs);
+	__asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
+	err |= __put_user(tmp, (unsigned int *)&sc->fs);
+	__asm__("movl %%ds,%0" : "=r"(tmp): "0"(tmp));
+	err |= __put_user(tmp, (unsigned int *)&sc->ds);
+	__asm__("movl %%es,%0" : "=r"(tmp): "0"(tmp));
+	err |= __put_user(tmp, (unsigned int *)&sc->es);
+
+	err |= __put_user((u32)regs->rdi, &sc->edi);
+	err |= __put_user((u32)regs->rsi, &sc->esi);
+	err |= __put_user((u32)regs->rbp, &sc->ebp);
+	err |= __put_user((u32)regs->rsp, &sc->esp);
+	err |= __put_user((u32)regs->rbx, &sc->ebx);
+	err |= __put_user((u32)regs->rdx, &sc->edx);
+	err |= __put_user((u32)regs->rcx, &sc->ecx);
+	err |= __put_user((u32)regs->rax, &sc->eax);
+	err |= __put_user((u32)regs->cs, &sc->cs); 
+	err |= __put_user((u32)regs->ss, &sc->ss); 
+	err |= __put_user(current->thread.trap_no, &sc->trapno);
+	err |= __put_user(current->thread.error_code, &sc->err);
+	err |= __put_user((u32)regs->rip, &sc->eip);
+	err |= __put_user((u32)regs->eflags, &sc->eflags);
+	err |= __put_user((u32)regs->rsp, &sc->esp_at_signal);
+
+	tmp = save_i387_ia32(current, fpstate, regs, 0);
+	if (tmp < 0)
+	  err = -EFAULT;
+	else
+	  err |= __put_user((u32)(u64)(tmp ? fpstate : NULL), &sc->fpstate);
+
+	/* non-iBCS2 extensions.. */
+	err |= __put_user(mask, &sc->oldmask);
+	err |= __put_user(current->thread.cr2, &sc->cr2);
+
+	return err;
+}
+
+/*
+ * Determine which stack to use..
+ */
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
+{
+	unsigned long rsp;
+
+	/* Default to using normal stack */
+	rsp = regs->rsp;
+
+	/* This is the X/Open sanctioned signal stack switching.  */
+	if (ka->sa.sa_flags & SA_ONSTACK) {
+		if (! on_sig_stack(rsp))
+			rsp = current->sas_ss_sp + current->sas_ss_size;
+	}
+
+	/* This is the legacy signal stack switching. */
+	else if ((regs->ss & 0xffff) != __USER_DS &&
+		!(ka->sa.sa_flags & SA_RESTORER) &&
+		 ka->sa.sa_restorer) {
+		rsp = (unsigned long) ka->sa.sa_restorer;
+	}
+
+	return (void *)((rsp - frame_size) & -8UL);
+}
+
+void ia32_setup_frame(int sig, struct k_sigaction *ka,
+			sigset32_t *set, struct pt_regs * regs)
+{
+	struct sigframe *frame;
+	int err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto give_sigsegv;
+
+	err |= __put_user((current->exec_domain
+		           && current->exec_domain->signal_invmap
+		           && sig < 32
+		           ? current->exec_domain->signal_invmap[sig]
+		           : sig),
+		          &frame->sig);
+	if (err)
+		goto give_sigsegv;
+
+	err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]);
+	if (err)
+		goto give_sigsegv;
+
+	if (_IA32_NSIG_WORDS > 1) {
+		err |= __copy_to_user(frame->extramask, &set->sig[1],
+				      sizeof(frame->extramask));
+	}
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		err |= __put_user((u32)(u64)ka->sa.sa_restorer, &frame->pretcode);
+	} else {
+		err |= __put_user((u32)(u64)frame->retcode, &frame->pretcode);
+		/* This is popl %eax ; movl $,%eax ; int $0x80 */
+		err |= __put_user((u16)0xb858, (short *)(frame->retcode+0));
+		err |= __put_user((u32)__NR_ia32_sigreturn, (int *)(frame->retcode+2));
+		err |= __put_user((u16)0x80cd, (short *)(frame->retcode+6));
+	}
+
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up registers for signal handler */
+	regs->rsp = (unsigned long) frame;
+	regs->rip = (unsigned long) ka->sa.sa_handler;
+
+	asm volatile("movl %0,%%ds" :: "r" (__USER32_DS)); 
+	asm volatile("movl %0,%%es" :: "r" (__USER32_DS)); 
+
+	regs->cs = __USER32_CS; 
+	regs->ss = __USER32_DS; 
+
+	set_fs(USER_DS);
+	regs->eflags &= ~TF_MASK;
+
+#if DEBUG_SIG
+	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+		current->comm, current->pid, frame, regs->rip, frame->pretcode);
+#endif
+
+	return;
+
+give_sigsegv:
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	signal_fault(regs,frame,"32bit signal deliver");
+}
+
+void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+			   sigset32_t *set, struct pt_regs * regs)
+{
+	struct rt_sigframe *frame;
+	int err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto give_sigsegv;
+
+	err |= __put_user((current->exec_domain
+		    	   && current->exec_domain->signal_invmap
+		    	   && sig < 32
+		    	   ? current->exec_domain->signal_invmap[sig]
+			   : sig),
+			  &frame->sig);
+	err |= __put_user((u32)(u64)&frame->info, &frame->pinfo);
+	err |= __put_user((u32)(u64)&frame->uc, &frame->puc);
+	err |= ia32_copy_siginfo_to_user(&frame->info, info);
+	if (err)
+		goto give_sigsegv;
+
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->uc.uc_flags);
+	err |= __put_user(0, &frame->uc.uc_link);
+	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(regs->rsp),
+			  &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+	err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
+			        regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		err |= __put_user((u32)(u64)ka->sa.sa_restorer, &frame->pretcode);
+	} else {
+		err |= __put_user(ptr_to_u32(frame->retcode), &frame->pretcode);
+		/* This is movl $,%eax ; int $0x80 */
+		err |= __put_user(0xb8, (char *)(frame->retcode+0));
+		err |= __put_user((u32)__NR_ia32_rt_sigreturn, (int *)(frame->retcode+1));
+		err |= __put_user(0x80cd, (short *)(frame->retcode+5));
+	}
+
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up registers for signal handler */
+	regs->rsp = (unsigned long) frame;
+	regs->rip = (unsigned long) ka->sa.sa_handler;
+
+	asm volatile("movl %0,%%ds" :: "r" (__USER32_DS)); 
+	asm volatile("movl %0,%%es" :: "r" (__USER32_DS)); 
+
+	regs->cs = __USER32_CS; 
+	regs->ss = __USER32_DS; 
+
+	set_fs(USER_DS);
+	regs->eflags &= ~TF_MASK;
+
+#if DEBUG_SIG
+	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+		current->comm, current->pid, frame, regs->rip, frame->pretcode);
+#endif
+
+	return;
+
+give_sigsegv:
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	signal_fault(regs,frame,"32bit rt signal deliver");
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/ia32/ia32entry.S linux-2.4.20/arch/x86_64/ia32/ia32entry.S
--- linux-2.4.19/arch/x86_64/ia32/ia32entry.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/ia32/ia32entry.S	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,390 @@
+/*
+ * Compatibility mode system call entry point for x86-64. 
+ * 		
+ * Copyright 2000,2001 Andi Kleen, SuSE Labs.
+ * 
+ * $Id: ia32entry.S,v 1.36 2002/09/12 12:55:05 ak Exp $ 		
+ */		 
+
+#include <asm/calling.h>
+#include <asm/offset.h>
+#include <asm/current.h>
+#include <linux/linkage.h>
+#include <asm/errno.h>
+#include <asm/ia32_unistd.h>	
+
+	.macro IA32_ARG_FIXUP
+	movl	%edi,%r8d
+	movl	%ebp,%r9d
+	xchg	%ecx,%esi
+	movl	%ebx,%edi
+	movl	%edx,%edx	/* zero extension */
+	.endm 
+
+/*
+ * 32bit SYSCALL instruction entry. 	
+ */ 	
+ENTRY(ia32_cstar_target)
+	movq $-ENOSYS,%rax
+	sysretl	
+	
+/* 
+ * Emulated IA32 system calls via int 0x80. 
+ *
+ * Arguments:	 
+ * %eax	System call number.
+ * %ebx Arg1
+ * %ecx Arg2
+ * %edx Arg3
+ * %esi Arg4
+ * %edi Arg5
+ * %ebp Arg6    [note: not saved in the stack frame, should not be touched]
+ *
+ * Notes:
+ * Uses the same stack frame as the x86-64 version.	
+ * All registers except %eax must be saved (but ptrace may violate that)
+ * Arguments are zero extended. For system calls that want sign extension and
+ * take long arguments a wrapper is needed. Most calls can just be called
+ * directly.
+ * Assumes it is only called from user space and entered with interrups off.		
+ */ 				
+
+ENTRY(ia32_syscall)
+	swapgs	
+	sti
+	pushq %rax
+	cld
+	SAVE_ARGS
+	GET_CURRENT(%r10)
+	testl $PT_TRACESYS,tsk_ptrace(%r10) 
+	jne  ia32_tracesys
+	cmpl $(IA32_NR_syscalls),%eax
+	jae  ia32_badsys
+	IA32_ARG_FIXUP
+	call *ia32_sys_call_table(,%rax,8) # xxx: rip relative
+	movq %rax,RAX-ARGOFFSET(%rsp)
+	jmp int_ret_from_sys_call 
+
+ia32_tracesys:			 
+	SAVE_REST
+	movq $-ENOSYS,RAX(%rsp)
+	movq %rsp,%rdi        /* &pt_regs -> arg1 */
+	call syscall_trace
+	LOAD_ARGS ARGOFFSET  /* reload args from stack in case ptrace changed it */
+	addq $ARGOFFSET,%rsp	
+	cmpl $(IA32_NR_syscalls),%eax
+	jae  1f
+	IA32_ARG_FIXUP
+	call *ia32_sys_call_table(,%rax,8)
+ia32_tracesys_end:	
+	movq %rax,RAX-ARGOFFSET(%rsp)
+1:	SAVE_REST
+	movq %rsp,%rdi		/* &pt_regs -> arg1 */ 
+	call syscall_trace
+	addq $ARGOFFSET,%rsp
+	jmp int_ret_from_sys_call
+		
+ia32_badsys:
+	movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
+	jmp int_ret_from_sys_call
+
+ni_syscall:
+	movq %rax,%rdi
+	jmp  sys32_ni_syscall			
+
+quiet_ni_syscall:
+	movl $-ENOSYS,%eax
+	ret	
+	
+	.macro PTREGSCALL label, func
+	.globl \label
+\label:
+	leaq \func(%rip),%rax
+	jmp  ia32_ptregs_common	
+	.endm
+
+	PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn
+	PTREGSCALL stub32_sigreturn, sys32_sigreturn
+	PTREGSCALL stub32_sigaltstack, sys32_sigaltstack
+	PTREGSCALL stub32_sigsuspend, sys32_sigsuspend
+	PTREGSCALL stub32_execve, sys32_execve
+	PTREGSCALL stub32_fork, sys32_fork
+	PTREGSCALL stub32_clone, sys32_clone
+	PTREGSCALL stub32_vfork, sys32_vfork
+	PTREGSCALL stub32_iopl, sys_iopl
+	PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend
+
+ENTRY(ia32_ptregs_common)
+	popq %r11
+	SAVE_REST
+	movq %r11, %r15
+	call *%rax
+	movq %r15, %r11
+	RESTORE_REST
+	pushq %r11
+	ret
+
+	.data
+	.align 8
+	.globl ia32_sys_call_table
+ia32_sys_call_table:
+	.quad ni_syscall	/* 0  -  old "setup" system call*/
+	.quad sys_exit
+	.quad stub32_fork
+	.quad sys_read
+	.quad sys_write
+	.quad sys_open		/* 5 */
+	.quad sys_close
+	.quad sys32_waitpid
+	.quad sys_creat
+	.quad sys_link
+	.quad sys_unlink		/* 10 */
+	.quad stub32_execve
+	.quad sys_chdir
+	.quad sys32_time
+	.quad sys_mknod
+	.quad sys_chmod		/* 15 */
+	.quad sys_lchown16
+	.quad ni_syscall			/* old break syscall holder */
+	.quad ni_syscall	/* (old)stat */ 
+	.quad sys32_lseek
+	.quad sys_getpid		/* 20 */
+	.quad sys_mount	/* mount  */
+	.quad sys_oldumount	/* old_umount  */
+	.quad sys_setuid16
+	.quad sys_getuid16
+	.quad sys_stime		/* stime */		/* 25 */
+	.quad sys32_ptrace	/* ptrace */
+	.quad sys_alarm		/* XXX sign extension??? */ 
+	.quad ni_syscall	/* (old)fstat */
+	.quad sys_pause
+	.quad sys32_utime	/* 30 */
+	.quad ni_syscall	/* old stty syscall holder */
+	.quad ni_syscall	/* old gtty syscall holder */
+	.quad sys_access
+	.quad sys_nice	
+	.quad ni_syscall	/* 35 */	/* old ftime syscall holder */
+	.quad sys_sync
+	.quad sys32_kill
+	.quad sys_rename
+	.quad sys_mkdir
+	.quad sys_rmdir		/* 40 */
+	.quad sys_dup
+	.quad sys32_pipe
+	.quad sys32_times
+	.quad ni_syscall			/* old prof syscall holder */
+	.quad sys_brk		/* 45 */
+	.quad sys_setgid16
+	.quad sys_getgid16
+	.quad ni_syscall	/* signal */
+	.quad sys_geteuid16
+	.quad sys_getegid16	/* 50 */
+	.quad sys_acct
+	.quad sys_umount			/* new_umount */
+	.quad ni_syscall			/* old lock syscall holder */
+	.quad sys32_ioctl
+	.quad sys32_fcntl		/* 55 */
+	.quad ni_syscall			/* old mpx syscall holder */
+	.quad sys_setpgid
+	.quad ni_syscall			/* old ulimit syscall holder */
+	.quad sys32_olduname
+	.quad sys_umask		/* 60 */
+	.quad sys_chroot
+	.quad sys32_ustat
+	.quad sys_dup2
+	.quad sys_getppid
+	.quad sys_getpgrp		/* 65 */
+	.quad sys_setsid
+	.quad sys32_sigaction
+	.quad sys_sgetmask
+	.quad sys_ssetmask
+	.quad sys_setreuid16	/* 70 */
+	.quad sys_setregid16
+	.quad stub32_sigsuspend
+	.quad sys32_sigpending
+	.quad sys_sethostname
+	.quad sys32_setrlimit	/* 75 */
+	.quad sys32_old_getrlimit	/* old_getrlimit */
+	.quad sys32_getrusage
+	.quad sys32_gettimeofday
+	.quad sys32_settimeofday
+	.quad sys_getgroups16	/* 80 */
+	.quad sys_setgroups16
+	.quad sys32_old_select
+	.quad sys_symlink
+	.quad ni_syscall	/* (old)lstat */
+	.quad sys_readlink		/* 85 */
+	.quad sys_uselib
+	.quad sys_swapon
+	.quad sys_reboot
+	.quad sys32_oldreaddir
+	.quad sys32_mmap		/* 90 */
+	.quad sys_munmap
+	.quad sys_truncate
+	.quad sys_ftruncate
+	.quad sys_fchmod
+	.quad sys_fchown16		/* 95 */
+	.quad sys_getpriority
+	.quad sys_setpriority
+	.quad ni_syscall			/* old profil syscall holder */
+	.quad sys32_statfs
+	.quad sys32_fstatfs		/* 100 */
+	.quad sys_ioperm
+	.quad sys32_socketcall
+	.quad sys_syslog
+	.quad sys32_setitimer
+	.quad sys32_getitimer	/* 105 */
+	.quad sys32_newstat
+	.quad sys32_newlstat
+	.quad sys32_newfstat
+	.quad sys32_uname
+	.quad stub32_iopl		/* 110 */
+	.quad sys_vhangup
+	.quad ni_syscall	/* old "idle" system call */
+	.quad ni_syscall	/* vm86old */ 
+	.quad sys32_wait4
+	.quad sys_swapoff		/* 115 */
+	.quad sys32_sysinfo
+	.quad sys32_ipc
+	.quad sys_fsync
+	.quad stub32_sigreturn
+	.quad stub32_clone		/* 120 */
+	.quad sys_setdomainname
+	.quad sys_uname
+	.quad sys_modify_ldt
+	.quad sys32_adjtimex
+	.quad sys32_mprotect		/* 125 */
+	.quad sys32_sigprocmask
+	.quad sys32_module_warning	/* create_module */
+	.quad sys32_module_warning	/* init_module */
+	.quad sys32_module_warning	/* delete module */
+	.quad sys32_module_warning	/* 130  get_kernel_syms */
+	.quad ni_syscall	/* quotactl */ 
+	.quad sys_getpgid
+	.quad sys_fchdir
+	.quad ni_syscall	/* bdflush */
+	.quad sys_sysfs		/* 135 */
+	.quad sys_personality
+	.quad ni_syscall	/* for afs_syscall */
+	.quad sys_setfsuid16
+	.quad sys_setfsgid16
+	.quad sys_llseek		/* 140 */
+	.quad sys32_getdents
+	.quad sys32_select
+	.quad sys_flock
+	.quad sys_msync
+	.quad sys32_readv		/* 145 */
+	.quad sys32_writev
+	.quad sys_getsid
+	.quad sys_fdatasync
+	.quad sys32_sysctl	/* sysctl */
+	.quad sys_mlock		/* 150 */
+	.quad sys_munlock
+	.quad sys_mlockall
+	.quad sys_munlockall
+	.quad sys_sched_setparam
+	.quad sys_sched_getparam   /* 155 */
+	.quad sys_sched_setscheduler
+	.quad sys_sched_getscheduler
+	.quad sys_sched_yield
+	.quad sys_sched_get_priority_max
+	.quad sys_sched_get_priority_min  /* 160 */
+	.quad sys_sched_rr_get_interval
+	.quad sys32_nanosleep
+	.quad sys_mremap
+	.quad sys_setresuid16
+	.quad sys_getresuid16	/* 165 */
+	.quad ni_syscall	/* vm86 */ 
+	.quad quiet_ni_syscall	/* query_module */
+	.quad sys_poll
+	.quad sys32_nfsservctl
+	.quad sys_setresgid16	/* 170 */
+	.quad sys_getresgid16
+	.quad sys_prctl
+	.quad stub32_rt_sigreturn
+	.quad sys32_rt_sigaction
+	.quad sys32_rt_sigprocmask	/* 175 */
+	.quad sys32_rt_sigpending
+	.quad sys32_rt_sigtimedwait
+	.quad sys32_rt_sigqueueinfo
+	.quad stub32_rt_sigsuspend
+	.quad sys32_pread		/* 180 */
+	.quad sys32_pwrite
+	.quad sys_chown16
+	.quad sys_getcwd
+	.quad sys_capget
+	.quad sys_capset
+	.quad stub32_sigaltstack
+	.quad sys32_sendfile
+	.quad ni_syscall		/* streams1 */
+	.quad ni_syscall		/* streams2 */
+	.quad stub32_vfork            /* 190 */
+	.quad sys32_getrlimit
+	.quad sys32_mmap2
+	.quad sys_truncate
+	.quad sys_ftruncate
+	.quad sys32_stat64		/* 195 */
+	.quad sys32_lstat64
+	.quad sys32_fstat64
+	.quad sys_lchown
+	.quad sys_getuid
+	.quad sys_getgid		/* 200 */
+	.quad sys_geteuid
+	.quad sys_getegid
+	.quad sys_setreuid
+	.quad sys_setregid
+	.quad sys_getgroups	/* 205 */
+	.quad sys_setgroups
+	.quad sys_fchown
+	.quad sys_setresuid
+	.quad sys_getresuid
+	.quad sys_setresgid	/* 210 */
+	.quad sys_getresgid
+	.quad sys_chown
+	.quad sys_setuid
+	.quad sys_setgid
+	.quad sys_setfsuid		/* 215 */
+	.quad sys_setfsgid
+	.quad sys_pivot_root
+	.quad sys_mincore
+	.quad sys_madvise
+	.quad sys_getdents64	/* 220 getdents64 */ 
+	.quad sys32_fcntl64	
+	.quad sys_ni_syscall	/* tux */
+	.quad sys_ni_syscall    /* security */
+	.quad sys_gettid	
+	.quad sys_readahead	/* 225 */ 
+	.quad sys_setxattr
+	.quad sys_lsetxattr
+	.quad sys_fsetxattr
+	.quad sys_getxattr
+	.quad sys_lgetxattr	/* 230 */
+	.quad sys_fgetxattr
+	.quad sys_listxattr
+	.quad sys_llistxattr
+	.quad sys_flistxattr
+	.quad sys_removexattr	/* 235 */
+	.quad sys_lremovexattr
+	.quad sys_fremovexattr
+	.quad sys_tkill		/* 238 */ 
+	.quad sys_ni_syscall	/* sendfile64 */
+	.quad sys_ni_syscall	/* futex */
+	.quad sys_ni_syscall	/* sched_setaffinity */
+	.quad sys_ni_syscall	/* sched_getaffinity */
+	.quad sys_ni_syscall	/* set_threadarea */
+	.quad sys_ni_syscall	/* get_threadarea */
+	.quad sys_ni_syscall	/* io_setup */
+	.quad sys_ni_syscall	/* io_destroy */
+	.quad sys_ni_syscall	/* io_getevents */
+	.quad sys_ni_syscall	/* io_submit */
+	.quad sys_ni_syscall	/* io_cancel */
+	.quad sys_ni_syscall	/* alloc_hugepages */
+	.quad sys_ni_syscall	/* free_hugepages */
+	.quad sys_ni_syscall	/* exit_group */
+
+ia32_syscall_end:		
+	.rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
+		.quad ni_syscall
+	.endr
+
+	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/ia32/ipc32.c linux-2.4.20/arch/x86_64/ia32/ipc32.c
--- linux-2.4.19/arch/x86_64/ia32/ipc32.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/ia32/ipc32.c	2002-10-29 11:18:41.000000000 +0000
@@ -0,0 +1,652 @@
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h> 
+#include <linux/file.h> 
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/mm.h>
+#include <linux/shm.h>
+#include <linux/slab.h>
+#include <linux/ipc.h>
+#include <asm/mman.h>
+#include <asm/types.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <asm/ipc.h>
+
+#include <asm/ia32.h>
+
+/*
+ * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation..
+ *
+ * This is really horribly ugly.
+ */
+
+struct msgbuf32 { 
+	s32 mtype; 
+	char mtext[1]; 
+};
+
+struct ipc_perm32 {
+	int key;
+	__kernel_uid_t32 uid;
+	__kernel_gid_t32 gid;
+	__kernel_uid_t32 cuid;
+	__kernel_gid_t32 cgid;
+	unsigned short mode;
+	unsigned short seq;
+};
+
+struct ipc64_perm32 {
+        unsigned key;
+	__kernel_uid32_t32 uid;
+	__kernel_gid32_t32 gid;
+	__kernel_uid32_t32 cuid;
+	__kernel_gid32_t32 cgid;
+	unsigned short mode;
+	unsigned short __pad1;
+	unsigned short seq;
+	unsigned short __pad2;
+	unsigned int unused1;
+	unsigned int unused2;
+};
+
+struct semid_ds32 {
+	struct ipc_perm32 sem_perm;               /* permissions .. see ipc.h */
+	__kernel_time_t32 sem_otime;              /* last semop time */
+	__kernel_time_t32 sem_ctime;              /* last change time */
+	u32 sem_base;              /* ptr to first semaphore in array */
+	u32 sem_pending;          /* pending operations to be processed */
+	u32 sem_pending_last;    /* last pending operation */
+	u32 undo;                  /* undo requests on this array */
+	unsigned short  sem_nsems;              /* no. of semaphores in array */
+};
+
+struct semid64_ds32 {
+	struct ipc64_perm32 sem_perm;
+	__kernel_time_t32 sem_otime;
+	unsigned int __unused1;
+	__kernel_time_t32 sem_ctime;
+	unsigned int __unused2;
+	unsigned int sem_nsems;
+	unsigned int __unused3;
+	unsigned int __unused4;
+};
+
+struct msqid_ds32 {
+	struct ipc_perm32 msg_perm;
+	u32 msg_first;
+	u32 msg_last;
+	__kernel_time_t32 msg_stime;
+	__kernel_time_t32 msg_rtime;
+	__kernel_time_t32 msg_ctime;
+	u32 wwait;
+	u32 rwait;
+	unsigned short msg_cbytes;
+	unsigned short msg_qnum;
+	unsigned short msg_qbytes;
+	__kernel_ipc_pid_t32 msg_lspid;
+	__kernel_ipc_pid_t32 msg_lrpid;
+};
+
+struct msqid64_ds32 {
+	struct ipc64_perm32 msg_perm;
+	__kernel_time_t32 msg_stime;
+	unsigned int __unused1;
+	__kernel_time_t32 msg_rtime;
+	unsigned int __unused2;
+	__kernel_time_t32 msg_ctime;
+	unsigned int __unused3;
+	unsigned int msg_cbytes;
+	unsigned int msg_qnum;
+	unsigned int msg_qbytes;
+	__kernel_pid_t32 msg_lspid;
+	__kernel_pid_t32 msg_lrpid;
+	unsigned int __unused4;
+	unsigned int __unused5;
+};
+
+struct shmid_ds32 {
+	struct ipc_perm32 shm_perm;
+	int shm_segsz;
+	__kernel_time_t32 shm_atime;
+	__kernel_time_t32 shm_dtime;
+	__kernel_time_t32 shm_ctime;
+	__kernel_ipc_pid_t32 shm_cpid;
+	__kernel_ipc_pid_t32 shm_lpid;
+	unsigned short shm_nattch;
+};
+
+struct shmid64_ds32 {
+	struct ipc64_perm32 shm_perm;
+	__kernel_size_t32 shm_segsz;
+	__kernel_time_t32 shm_atime;
+	unsigned int __unused1;
+	__kernel_time_t32 shm_dtime;
+	unsigned int __unused2;
+	__kernel_time_t32 shm_ctime;
+	unsigned int __unused3;
+	__kernel_pid_t32 shm_cpid;
+	__kernel_pid_t32 shm_lpid;
+	unsigned int shm_nattch;
+	unsigned int __unused4;
+	unsigned int __unused5;
+};
+
+struct shminfo64_32 {
+	unsigned int shmmax;
+	unsigned int shmmin;
+	unsigned int shmmni;
+	unsigned int shmseg;
+	unsigned int shmall;
+	unsigned int __unused1;
+	unsigned int __unused2;
+	unsigned int __unused3;
+	unsigned int __unused4;
+};
+
+struct shm_info32 {
+	int used_ids;
+	u32 shm_tot, shm_rss, shm_swp;
+	u32 swap_attempts, swap_successes;
+};
+
+struct ipc_kludge {
+	u32 msgp;
+	s32 msgtyp;
+};
+
+
+#define A(__x)		((unsigned long)(__x))
+#define AA(__x)		((unsigned long)(__x))
+
+#define SEMOP		 1
+#define SEMGET		 2
+#define SEMCTL		 3
+#define MSGSND		11
+#define MSGRCV		12
+#define MSGGET		13
+#define MSGCTL		14
+#define SHMAT		21
+#define SHMDT		22
+#define SHMGET		23
+#define SHMCTL		24
+
+#define IPCOP_MASK(__x)	(1UL << (__x))
+
+static int
+ipc_parse_version32 (int *cmd)
+{
+	if (*cmd & IPC_64) {
+		*cmd ^= IPC_64;
+		return IPC_64;
+	} else {
+		return IPC_OLD;
+	}
+}
+
+static int
+semctl32 (int first, int second, int third, void *uptr)
+{
+	union semun fourth;
+	u32 pad;
+	int err = 0, err2;
+	struct semid64_ds s;
+	mm_segment_t old_fs;
+	int version = ipc_parse_version32(&third);
+
+	if (!uptr)
+		return -EINVAL;
+	if (get_user(pad, (u32 *)uptr))
+		return -EFAULT;
+	if (third == SETVAL)
+		fourth.val = (int)pad;
+	else
+		fourth.__pad = (void *)A(pad);
+	switch (third) {
+	      case IPC_INFO:
+	      case IPC_RMID:
+	      case IPC_SET:
+	      case SEM_INFO:
+	      case GETVAL:
+	      case GETPID:
+	      case GETNCNT:
+	      case GETZCNT:
+	      case GETALL:
+	      case SETVAL:
+	      case SETALL:
+		err = sys_semctl(first, second, third, fourth);
+		break;
+
+	      case IPC_STAT:
+	      case SEM_STAT:
+		fourth.__pad = &s;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_semctl(first, second|IPC_64, third, fourth);
+		set_fs(old_fs);
+
+		if (version == IPC_64) {
+			struct semid64_ds32 *usp64 = (struct semid64_ds32 *) A(pad);
+
+			if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(s.sem_perm.key, &usp64->sem_perm.key);
+			err2 |= __put_user(s.sem_perm.uid, &usp64->sem_perm.uid);
+			err2 |= __put_user(s.sem_perm.gid, &usp64->sem_perm.gid);
+			err2 |= __put_user(s.sem_perm.cuid, &usp64->sem_perm.cuid);
+			err2 |= __put_user(s.sem_perm.cgid, &usp64->sem_perm.cgid);
+			err2 |= __put_user(s.sem_perm.mode, &usp64->sem_perm.mode);
+			err2 |= __put_user(s.sem_perm.seq, &usp64->sem_perm.seq);
+			err2 |= __put_user(s.sem_otime, &usp64->sem_otime);
+			err2 |= __put_user(s.sem_ctime, &usp64->sem_ctime);
+			err2 |= __put_user(s.sem_nsems, &usp64->sem_nsems);
+		} else {
+			struct semid_ds32 *usp32 = (struct semid_ds32 *) A(pad);
+
+			if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(s.sem_perm.key, &usp32->sem_perm.key);
+			err2 |= __put_user(s.sem_perm.uid, &usp32->sem_perm.uid);
+			err2 |= __put_user(s.sem_perm.gid, &usp32->sem_perm.gid);
+			err2 |= __put_user(s.sem_perm.cuid, &usp32->sem_perm.cuid);
+			err2 |= __put_user(s.sem_perm.cgid, &usp32->sem_perm.cgid);
+			err2 |= __put_user(s.sem_perm.mode, &usp32->sem_perm.mode);
+			err2 |= __put_user(s.sem_perm.seq, &usp32->sem_perm.seq);
+			err2 |= __put_user(s.sem_otime, &usp32->sem_otime);
+			err2 |= __put_user(s.sem_ctime, &usp32->sem_ctime);
+			err2 |= __put_user(s.sem_nsems, &usp32->sem_nsems);
+		}
+		if (err2)
+		    err = -EFAULT;
+		break;
+	}
+	return err;
+}
+
+#define MAXBUF (64*1024)
+
+static int
+do_sys32_msgsnd (int first, int second, int third, void *uptr)
+{
+	struct msgbuf *p;
+	struct msgbuf32 *up = (struct msgbuf32 *)uptr;
+	mm_segment_t old_fs;
+	int err;
+
+	if (second >= MAXBUF-sizeof(struct msgbuf))
+		return -EINVAL; 
+	p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
+	if (!p)
+		return -ENOMEM;
+	err = get_user(p->mtype, &up->mtype);
+	err |= copy_from_user(p->mtext, &up->mtext, second);
+	if (err)
+		goto out;
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_msgsnd(first, p, second, third);
+	set_fs(old_fs);
+  out:
+	kfree(p);
+	return err;
+}
+
+static int
+do_sys32_msgrcv (int first, int second, int msgtyp, int third, int version, void *uptr)
+{
+	struct msgbuf32 *up;
+	struct msgbuf *p;
+	mm_segment_t old_fs;
+	int err;
+
+	if (!version) {
+		struct ipc_kludge *uipck = (struct ipc_kludge *)uptr;
+		struct ipc_kludge ipck;
+
+		err = -EINVAL;
+		if (!uptr)
+			goto out;
+		err = -EFAULT;
+		if (copy_from_user(&ipck, uipck, sizeof(struct ipc_kludge)))
+			goto out;
+		uptr = (void *)A(ipck.msgp);
+		msgtyp = ipck.msgtyp;
+	}
+	if (second >= MAXBUF-sizeof(struct msgbuf)) 
+		return -EINVAL; 
+	err = -ENOMEM;
+	p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
+	if (!p)
+		goto out;
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_msgrcv(first, p, second, msgtyp, third);
+	set_fs(old_fs);
+	if (err < 0)
+		goto free_then_out;
+	up = (struct msgbuf32 *)uptr;
+	if (put_user(p->mtype, &up->mtype) || copy_to_user(&up->mtext, p->mtext, err))
+		err = -EFAULT;
+free_then_out:
+	kfree(p);
+out:
+	return err;
+}
+
+static int
+msgctl32 (int first, int second, void *uptr)
+{
+	int err = -EINVAL, err2;
+	struct msqid_ds m;
+	struct msqid64_ds m64;
+	struct msqid_ds32 *up32 = (struct msqid_ds32 *)uptr;
+	struct msqid64_ds32 *up64 = (struct msqid64_ds32 *)uptr;
+	mm_segment_t old_fs;
+	int version = ipc_parse_version32(&second);
+
+	switch (second) {
+	      case IPC_INFO:
+	      case IPC_RMID:
+	      case MSG_INFO:
+		err = sys_msgctl(first, second, (struct msqid_ds *)uptr);
+		break;
+
+	      case IPC_SET:
+		if (version == IPC_64) {
+			err = get_user(m.msg_perm.uid, &up64->msg_perm.uid);
+			err |= get_user(m.msg_perm.gid, &up64->msg_perm.gid);
+			err |= get_user(m.msg_perm.mode, &up64->msg_perm.mode);
+			err |= get_user(m.msg_qbytes, &up64->msg_qbytes);
+		} else {
+			err = get_user(m.msg_perm.uid, &up32->msg_perm.uid);
+			err |= get_user(m.msg_perm.gid, &up32->msg_perm.gid);
+			err |= get_user(m.msg_perm.mode, &up32->msg_perm.mode);
+			err |= get_user(m.msg_qbytes, &up32->msg_qbytes);
+		}
+		if (err)
+			break;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_msgctl(first, second, &m);
+		set_fs(old_fs);
+		break;
+
+	      case IPC_STAT:
+	      case MSG_STAT:
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_msgctl(first, second|IPC_64, (void *) &m64);
+		set_fs(old_fs);
+
+		if (version == IPC_64) {
+			if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(m64.msg_perm.key, &up64->msg_perm.key);
+			err2 |= __put_user(m64.msg_perm.uid, &up64->msg_perm.uid);
+			err2 |= __put_user(m64.msg_perm.gid, &up64->msg_perm.gid);
+			err2 |= __put_user(m64.msg_perm.cuid, &up64->msg_perm.cuid);
+			err2 |= __put_user(m64.msg_perm.cgid, &up64->msg_perm.cgid);
+			err2 |= __put_user(m64.msg_perm.mode, &up64->msg_perm.mode);
+			err2 |= __put_user(m64.msg_perm.seq, &up64->msg_perm.seq);
+			err2 |= __put_user(m64.msg_stime, &up64->msg_stime);
+			err2 |= __put_user(m64.msg_rtime, &up64->msg_rtime);
+			err2 |= __put_user(m64.msg_ctime, &up64->msg_ctime);
+			err2 |= __put_user(m64.msg_cbytes, &up64->msg_cbytes);
+			err2 |= __put_user(m64.msg_qnum, &up64->msg_qnum);
+			err2 |= __put_user(m64.msg_qbytes, &up64->msg_qbytes);
+			err2 |= __put_user(m64.msg_lspid, &up64->msg_lspid);
+			err2 |= __put_user(m64.msg_lrpid, &up64->msg_lrpid);
+			if (err2)
+				err = -EFAULT;
+		} else {
+			if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(m64.msg_perm.key, &up32->msg_perm.key);
+			err2 |= __put_user(m64.msg_perm.uid, &up32->msg_perm.uid);
+			err2 |= __put_user(m64.msg_perm.gid, &up32->msg_perm.gid);
+			err2 |= __put_user(m64.msg_perm.cuid, &up32->msg_perm.cuid);
+			err2 |= __put_user(m64.msg_perm.cgid, &up32->msg_perm.cgid);
+			err2 |= __put_user(m64.msg_perm.mode, &up32->msg_perm.mode);
+			err2 |= __put_user(m64.msg_perm.seq, &up32->msg_perm.seq);
+			err2 |= __put_user(m64.msg_stime, &up32->msg_stime);
+			err2 |= __put_user(m64.msg_rtime, &up32->msg_rtime);
+			err2 |= __put_user(m64.msg_ctime, &up32->msg_ctime);
+			err2 |= __put_user(m64.msg_cbytes, &up32->msg_cbytes);
+			err2 |= __put_user(m64.msg_qnum, &up32->msg_qnum);
+			err2 |= __put_user(m64.msg_qbytes, &up32->msg_qbytes);
+			err2 |= __put_user(m64.msg_lspid, &up32->msg_lspid);
+			err2 |= __put_user(m64.msg_lrpid, &up32->msg_lrpid);
+			if (err2)
+				err = -EFAULT;
+		}
+		break;
+	}
+	return err;
+}
+
+static int
+shmat32 (int first, int second, int third, int version, void *uptr)
+{
+	unsigned long raddr;
+	u32 *uaddr = (u32 *)A((u32)third);
+	int err;
+
+	if (version == 1)
+		return -EINVAL;	/* iBCS2 emulator entry point: unsupported */
+	err = sys_shmat(first, uptr, second, &raddr);
+	if (err)
+		return err;
+	return put_user(raddr, uaddr);
+}
+
+static int put_shmid64(struct shmid64_ds *s64p, void *uptr, int version) 
+{ 
+	int err2; 
+#define s64 (*s64p)
+	if (version == IPC_64) {
+		struct shmid64_ds32 *up64 = (struct shmid64_ds32 *)uptr;
+
+		if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
+			return -EFAULT;
+
+		err2 = __put_user(s64.shm_perm.key, &up64->shm_perm.key);
+		err2 |= __put_user(s64.shm_perm.uid, &up64->shm_perm.uid);
+		err2 |= __put_user(s64.shm_perm.gid, &up64->shm_perm.gid);
+		err2 |= __put_user(s64.shm_perm.cuid, &up64->shm_perm.cuid);
+		err2 |= __put_user(s64.shm_perm.cgid, &up64->shm_perm.cgid);
+		err2 |= __put_user(s64.shm_perm.mode, &up64->shm_perm.mode);
+		err2 |= __put_user(s64.shm_perm.seq, &up64->shm_perm.seq);
+		err2 |= __put_user(s64.shm_atime, &up64->shm_atime);
+		err2 |= __put_user(s64.shm_dtime, &up64->shm_dtime);
+		err2 |= __put_user(s64.shm_ctime, &up64->shm_ctime);
+		err2 |= __put_user(s64.shm_segsz, &up64->shm_segsz);
+		err2 |= __put_user(s64.shm_nattch, &up64->shm_nattch);
+		err2 |= __put_user(s64.shm_cpid, &up64->shm_cpid);
+		err2 |= __put_user(s64.shm_lpid, &up64->shm_lpid);
+	} else {
+		struct shmid_ds32 *up32 = (struct shmid_ds32 *)uptr;
+
+		if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) 
+			return -EFAULT;
+
+		err2 = __put_user(s64.shm_perm.key, &up32->shm_perm.key);
+		err2 |= __put_user(s64.shm_perm.uid, &up32->shm_perm.uid);
+		err2 |= __put_user(s64.shm_perm.gid, &up32->shm_perm.gid);
+		err2 |= __put_user(s64.shm_perm.cuid, &up32->shm_perm.cuid);
+		err2 |= __put_user(s64.shm_perm.cgid, &up32->shm_perm.cgid);
+		err2 |= __put_user(s64.shm_perm.mode, &up32->shm_perm.mode);
+		err2 |= __put_user(s64.shm_perm.seq, &up32->shm_perm.seq);
+		err2 |= __put_user(s64.shm_atime, &up32->shm_atime);
+		err2 |= __put_user(s64.shm_dtime, &up32->shm_dtime);
+		err2 |= __put_user(s64.shm_ctime, &up32->shm_ctime);
+		err2 |= __put_user(s64.shm_segsz, &up32->shm_segsz);
+		err2 |= __put_user(s64.shm_nattch, &up32->shm_nattch);
+		err2 |= __put_user(s64.shm_cpid, &up32->shm_cpid);
+		err2 |= __put_user(s64.shm_lpid, &up32->shm_lpid);
+	}
+#undef s64
+	return err2 ? -EFAULT : 0;
+}
+static int
+shmctl32 (int first, int second, void *uptr)
+{
+	int err = -EFAULT, err2;
+	struct shmid_ds s;
+	struct shmid64_ds s64;
+	mm_segment_t old_fs;
+	struct shm_info32 *uip = (struct shm_info32 *)uptr;
+	struct shm_info si;
+	int version = ipc_parse_version32(&second);
+	struct shminfo64 smi;
+	struct shminfo *usi32 = (struct shminfo *) uptr;
+	struct shminfo64_32 *usi64 = (struct shminfo64_32 *) uptr;
+
+	switch (second) {
+	      case IPC_INFO:
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_shmctl(first, second|IPC_64, (struct shmid_ds *)&smi);
+		set_fs(old_fs);
+
+		if (version == IPC_64) {
+			if (!access_ok(VERIFY_WRITE, usi64, sizeof(*usi64))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(smi.shmmax, &usi64->shmmax);
+			err2 |= __put_user(smi.shmmin, &usi64->shmmin);
+			err2 |= __put_user(smi.shmmni, &usi64->shmmni);
+			err2 |= __put_user(smi.shmseg, &usi64->shmseg);
+			err2 |= __put_user(smi.shmall, &usi64->shmall);
+		} else {
+			if (!access_ok(VERIFY_WRITE, usi32, sizeof(*usi32))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(smi.shmmax, &usi32->shmmax);
+			err2 |= __put_user(smi.shmmin, &usi32->shmmin);
+			err2 |= __put_user(smi.shmmni, &usi32->shmmni);
+			err2 |= __put_user(smi.shmseg, &usi32->shmseg);
+			err2 |= __put_user(smi.shmall, &usi32->shmall);
+		}
+		if (err2)
+			err = -EFAULT;
+		break;
+
+	      case IPC_RMID:
+	      case SHM_LOCK:
+	      case SHM_UNLOCK:
+		err = sys_shmctl(first, second, (struct shmid_ds *)uptr);
+		break;
+
+	      case IPC_SET: 
+		if (version == IPC_64) {
+			struct shmid64_ds32 *up64 = (struct shmid64_ds32 *)uptr;
+			err = get_user(s.shm_perm.uid, &up64->shm_perm.uid);
+			err |= get_user(s.shm_perm.gid, &up64->shm_perm.gid);
+			err |= get_user(s.shm_perm.mode, &up64->shm_perm.mode);
+		} else {
+			struct shmid_ds32 *up32 = (struct shmid_ds32 *)uptr;
+			err = get_user(s.shm_perm.uid, &up32->shm_perm.uid);
+			err |= get_user(s.shm_perm.gid, &up32->shm_perm.gid);
+			err |= get_user(s.shm_perm.mode, &up32->shm_perm.mode);
+		}
+		if (err)
+			break;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_shmctl(first, second, &s);
+		set_fs(old_fs);
+		break;
+
+	      case IPC_STAT:
+	      case SHM_STAT:
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_shmctl(first, second|IPC_64, (void *) &s64);
+		set_fs(old_fs);
+		
+		if (err < 0)
+			break;
+	        err2 = put_shmid64(&s64, uptr, version); 		
+		if (err2) 
+			err = err2;
+		break;
+
+	      case SHM_INFO:
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_shmctl(first, second, (void *)&si);
+		set_fs(old_fs);
+		if (err < 0)
+			break;
+
+		if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip))) {
+			err = -EFAULT;
+			break;
+		}
+		err2 = __put_user(si.used_ids, &uip->used_ids);
+		err2 |= __put_user(si.shm_tot, &uip->shm_tot);
+		err2 |= __put_user(si.shm_rss, &uip->shm_rss);
+		err2 |= __put_user(si.shm_swp, &uip->shm_swp);
+		err2 |= __put_user(si.swap_attempts, &uip->swap_attempts);
+		err2 |= __put_user(si.swap_successes, &uip->swap_successes);
+		if (err2)
+			err = -EFAULT;
+		break;
+
+	}
+	return err;
+}
+
+asmlinkage long
+sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
+{
+	int version;
+
+	version = call >> 16; /* hack for backward compatibility */
+	call &= 0xffff;
+
+	switch (call) {
+	      case SEMOP:
+		/* struct sembuf is the same on 32 and 64bit :)) */
+		return sys_semop(first, (struct sembuf *)AA(ptr), second);
+	      case SEMGET:
+		return sys_semget(first, second, third);
+	      case SEMCTL:
+		return semctl32(first, second, third, (void *)AA(ptr));
+
+	      case MSGSND:
+		return do_sys32_msgsnd(first, second, third, (void *)AA(ptr));
+	      case MSGRCV:
+		return do_sys32_msgrcv(first, second, fifth, third, version, (void *)AA(ptr));
+	      case MSGGET:
+		return sys_msgget((key_t) first, second);
+	      case MSGCTL:
+		return msgctl32(first, second, (void *)AA(ptr));
+
+	      case SHMAT:
+		return shmat32(first, second, third, version, (void *)AA(ptr));
+		break;
+	      case SHMDT:
+		return sys_shmdt((char *)AA(ptr));
+	      case SHMGET:
+		return sys_shmget(first, second, third);
+	      case SHMCTL:
+		return shmctl32(first, second, (void *)AA(ptr));
+
+	      default:
+		return -EINVAL;
+	}
+	return -EINVAL;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/ia32/ptrace32.c linux-2.4.20/arch/x86_64/ia32/ptrace32.c
--- linux-2.4.19/arch/x86_64/ia32/ptrace32.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/ia32/ptrace32.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,330 @@
+/* 
+ * 32bit ptrace for x86-64.
+ *
+ * Copyright 2001,2002 Andi Kleen, SuSE Labs.
+ * Some parts copied from arch/i386/kernel/ptrace.c. See that file for earlier 
+ * copyright.
+ * 
+ * This allows to access 64bit processes too; but there is no way to see the extended 
+ * register contents.
+ *
+ * $Id: ptrace32.c,v 1.13 2002/07/18 13:44:12 ak Exp $
+ */ 
+
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+#include <asm/user32.h>
+#include <asm/user.h>
+#include <asm/errno.h>
+#include <asm/debugreg.h>
+#include <asm/i387.h>
+#include <asm/fpu32.h>
+#include <linux/mm.h>
+
+#define R32(l,q) \
+	case offsetof(struct user32, regs.l): stack[offsetof(struct pt_regs, q)/8] = val; break
+
+static int putreg32(struct task_struct *child, unsigned regno, u32 val)
+{
+	int i;
+	__u64 *stack = (__u64 *)(child->thread.rsp0 - sizeof(struct pt_regs)); 
+
+	switch (regno) {
+	case offsetof(struct user32, regs.fs):
+        if (val && (val & 3) != 3) return -EIO;
+        child->thread.fs = val & 0xffff; 
+		break;
+	case offsetof(struct user32, regs.gs):
+	    if (val && (val & 3) != 3) return -EIO;
+		child->thread.gs = val & 0xffff;
+		break;
+	case offsetof(struct user32, regs.ds):
+		if (val && (val & 3) != 3) return -EIO; 
+		child->thread.ds = val & 0xffff;
+		break;
+	case offsetof(struct user32, regs.es):
+		child->thread.es = val & 0xffff;
+		break;
+    case offsetof(struct user32, regs.ss):
+		if ((val & 3) != 3) return -EIO; 
+        stack[offsetof(struct pt_regs, ss)/8] = val & 0xffff;
+        break;
+	case offsetof(struct user32, regs.cs):
+		if ((val & 3) != 3) return -EIO;
+		stack[offsetof(struct pt_regs, cs)/8] = val & 0xffff;
+		break;
+
+	R32(ebx, rbx); 
+	R32(ecx, rcx);
+	R32(edx, rdx);
+	R32(edi, rdi);
+	R32(esi, rsi);
+	R32(ebp, rbp);
+	R32(eax, rax);
+	R32(orig_eax, orig_rax);
+	R32(eip, rip);
+	R32(esp, rsp);
+
+	case offsetof(struct user32, regs.eflags): 
+		stack[offsetof(struct pt_regs, eflags)/8] = val & 0x44dd5; 
+		break;
+
+	case offsetof(struct user32, u_debugreg[0]) ... offsetof(struct user32, u_debugreg[6]):
+		child->thread.debugreg[(regno-offsetof(struct user32, u_debugreg[0]))/4] = val; 
+		break; 
+
+	case offsetof(struct user32, u_debugreg[7]):
+		val &= ~DR_CONTROL_RESERVED;
+		/* You are not expected to understand this ... I don't neither. */
+		for(i=0; i<4; i++)
+			if ((0x5454 >> ((val >> (16 + 4*i)) & 0xf)) & 1)
+			       return -EIO;
+		child->thread.debugreg[7] = val; 
+		break; 
+		    
+	default:
+		if (regno > sizeof(struct user32) || (regno & 3))
+			return -EIO;
+	       
+		/* Other dummy fields in the virtual user structure are ignored */ 
+		break; 		
+	}
+	return 0;
+}
+
+#undef R32
+
+#define R32(l,q) \
+	case offsetof(struct user32, regs.l): *val = stack[offsetof(struct pt_regs, q)/8]; break
+
+static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
+{
+	__u64 *stack = (__u64 *)(child->thread.rsp0 - sizeof(struct pt_regs)); 
+
+	switch (regno) {
+	case offsetof(struct user32, regs.fs):
+	        *val = child->thread.fs; 
+		break;
+	case offsetof(struct user32, regs.gs):
+		*val = child->thread.gs;
+		break;
+	case offsetof(struct user32, regs.ds):
+		*val = child->thread.ds;
+		break;
+	case offsetof(struct user32, regs.es):
+		*val = child->thread.es;
+		break;
+
+	R32(cs, cs);
+	R32(ss, ss);
+	R32(ebx, rbx); 
+	R32(ecx, rcx);
+	R32(edx, rdx);
+	R32(edi, rdi);
+	R32(esi, rsi);
+	R32(ebp, rbp);
+	R32(eax, rax);
+	R32(orig_eax, orig_rax);
+	R32(eip, rip);
+	R32(eflags, eflags);
+	R32(esp, rsp);
+
+	case offsetof(struct user32, u_debugreg[0]) ... offsetof(struct user32, u_debugreg[7]):
+		*val = child->thread.debugreg[(regno-offsetof(struct user32, u_debugreg[0]))/4]; 
+		break; 
+		    
+	default:
+		if (regno > sizeof(struct user32) || (regno & 3))
+			return -EIO;
+
+		/* Other dummy fields in the virtual user structure are ignored */ 
+		*val = 0;
+		break; 		
+	}
+	return 0;
+}
+
+#undef R32
+
+static struct task_struct *find_target(int request, int pid, int *err)
+{ 
+	struct task_struct *child;
+
+	*err = -EPERM; 
+	if (pid == 1)
+		return NULL; 
+
+	*err = -ESRCH;
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	if (child)
+		get_task_struct(child);
+	read_unlock(&tasklist_lock);
+	if (child) { 
+		*err = -ESRCH;
+		if (!(child->ptrace & PT_PTRACED))
+			goto out;
+		if (child->state != TASK_STOPPED) {
+			if (request != PTRACE_KILL)
+				goto out;
+		}
+		if (child->p_pptr != current)
+			goto out;
+
+		return child; 
+	} 
+ out:
+	free_task_struct(child);
+	return NULL; 
+	
+} 
+
+extern asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, unsigned long data);
+
+asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
+{
+	struct task_struct *child;
+	struct pt_regs *childregs; 
+	int ret;
+	__u32 val;
+
+	switch (request) { 
+	case PTRACE_TRACEME:
+	case PTRACE_ATTACH:
+	case PTRACE_SYSCALL:
+	case PTRACE_CONT:
+	case PTRACE_KILL:
+	case PTRACE_SINGLESTEP:
+	case PTRACE_DETACH:
+	case PTRACE_SETOPTIONS:
+		ret = sys_ptrace(request, pid, addr, data); 
+		return ret;
+
+	case PTRACE_PEEKTEXT:
+	case PTRACE_PEEKDATA:
+	case PTRACE_POKEDATA:
+	case PTRACE_POKETEXT:
+	case PTRACE_POKEUSR:       
+	case PTRACE_PEEKUSR:
+	case PTRACE_GETREGS:
+	case PTRACE_SETREGS:
+	case PTRACE_SETFPREGS:
+	case PTRACE_GETFPREGS:
+	case PTRACE_SETFPXREGS:
+	case PTRACE_GETFPXREGS:
+		break;
+		
+	default:
+		return -EIO;
+	} 
+
+	child = find_target(request, pid, &ret);
+	if (!child)
+		return ret;
+	
+	childregs = (struct pt_regs *)(child->thread.rsp0 - sizeof(struct pt_regs)); 
+
+	switch (request) {
+	case PTRACE_PEEKDATA:
+	case PTRACE_PEEKTEXT:
+		ret = 0;
+		if (access_process_vm(child, addr, &val, sizeof(u32), 0)!=sizeof(u32))
+			ret = -EIO;
+		else
+			ret = put_user(val, (unsigned int *)(u64)data); 
+		break; 
+
+	case PTRACE_POKEDATA:
+	case PTRACE_POKETEXT:
+		ret = 0;
+		if (access_process_vm(child, addr, &data, sizeof(u32), 1)!=sizeof(u32))
+			ret = -EIO; 
+		break;
+
+	case PTRACE_PEEKUSR:
+		ret = getreg32(child, addr, &val);
+		if (ret == 0)
+			ret = put_user(val, (__u32 *)(unsigned long) data);
+		break;
+
+	case PTRACE_POKEUSR:
+		ret = putreg32(child, addr, data);
+		break;
+
+	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
+		int i;
+	  	if (!access_ok(VERIFY_WRITE, (unsigned *)(unsigned long)data, 16*4)) {
+			ret = -EIO;
+			break;
+		}
+		ret = 0;
+		for ( i = 0; i <= 16*4 ; i += sizeof(__u32) ) {
+			getreg32(child, i, &val);
+			ret |= __put_user(val,(u32 *) (unsigned long) data);
+			data += sizeof(u32);
+		}
+		break;
+	}
+
+	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+		unsigned long tmp;
+		int i;
+	  	if (!access_ok(VERIFY_READ, (unsigned *)(unsigned long)data, 16*4)) {
+			ret = -EIO;
+			break;
+		}
+		empty_fpu(child); 
+		ret = 0; 
+		for ( i = 0; i <= 16*4; i += sizeof(u32) ) {
+			ret |= __get_user(tmp, (u32 *) (unsigned long) data);
+			putreg32(child, i, tmp);
+			data += sizeof(u32);
+		}
+		break;
+	}
+
+	case PTRACE_SETFPREGS:
+		empty_fpu(child); 
+		save_i387_ia32(child, (void *)(u64)data, childregs, 1);
+		ret = 0; 
+		break;
+
+	case PTRACE_GETFPREGS:
+		empty_fpu(child); 
+		restore_i387_ia32(child, (void *)(u64)data, 1);
+		ret = 0;
+		break;
+
+	case PTRACE_GETFPXREGS: { 
+		struct user32_fxsr_struct *u = (void *)(u64)data; 
+		empty_fpu(child); 
+		ret = copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u));
+		ret |= __put_user(childregs->cs, &u->fcs);
+		ret |= __put_user(child->thread.ds, &u->fos); 
+		if (ret) 
+			ret = -EFAULT;
+		break; 
+	} 
+	case PTRACE_SETFPXREGS: { 
+		struct user32_fxsr_struct *u = (void *)(u64)data; 
+		empty_fpu(child); 
+		/* no error checking to be bug to bug compatible with i386 */ 
+		copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u));
+	        child->thread.i387.fxsave.mxcsr &= 0xffbf;
+		ret = 0; 
+		break; 
+	} 
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	free_task_struct(child);
+	return ret;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/ia32/socket32.c linux-2.4.20/arch/x86_64/ia32/socket32.c
--- linux-2.4.19/arch/x86_64/ia32/socket32.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/ia32/socket32.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,686 @@
+/* 
+ * 32bit Socket syscall emulation. Based on arch/sparc64/kernel/sys_sparc32.c.
+ *
+ * Copyright (C) 2000		VA Linux Co
+ * Copyright (C) 2000		Don Dugger <n0ano@valinux.com>
+ * Copyright (C) 1999 		Arun Sharma <arun.sharma@intel.com>
+ * Copyright (C) 1997,1998 	Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 		David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 2000		Hewlett-Packard Co.
+ * Copyright (C) 2000		David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2000,2001	Andi Kleen, SuSE Labs 
+ */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/file.h>
+#include <linux/icmpv6.h>
+#include <linux/socket.h>
+#include <linux/filter.h>
+
+#include <net/scm.h>
+#include <net/sock.h>
+#include <asm/ia32.h>
+#include <asm/uaccess.h>
+#include <asm/socket32.h>
+
+#define A(__x)		((unsigned long)(__x))
+#define AA(__x)		((unsigned long)(__x))
+
+
+static inline int iov_from_user32_to_kern(struct iovec *kiov,
+					  struct iovec32 *uiov32,
+					  int niov)
+{
+	int tot_len = 0;
+
+	while(niov > 0) {
+		u32 len, buf;
+
+		if(get_user(len, &uiov32->iov_len) ||
+		   get_user(buf, &uiov32->iov_base)) {
+			tot_len = -EFAULT;
+			break;
+		}
+		tot_len += len;
+		kiov->iov_base = (void *)A(buf);
+		kiov->iov_len = (__kernel_size_t) len;
+		uiov32++;
+		kiov++;
+		niov--;
+	}
+	return tot_len;
+}
+
+static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg,
+					     struct msghdr32 *umsg)
+{
+	u32 tmp1, tmp2, tmp3;
+	int err;
+
+	err = get_user(tmp1, &umsg->msg_name);
+	err |= __get_user(tmp2, &umsg->msg_iov);
+	err |= __get_user(tmp3, &umsg->msg_control);
+	if (err)
+		return -EFAULT;
+
+	kmsg->msg_name = (void *)A(tmp1);
+	kmsg->msg_iov = (struct iovec *)A(tmp2);
+	kmsg->msg_control = (void *)A(tmp3);
+
+	err = get_user(kmsg->msg_namelen, &umsg->msg_namelen);
+	err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen);
+	err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen);
+	err |= get_user(kmsg->msg_flags, &umsg->msg_flags);
+	
+	return err;
+}
+
+/* I've named the args so it is easy to tell whose space the pointers are in. */
+static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov,
+			  char *kern_address, int mode)
+{
+	int tot_len;
+
+	if(kern_msg->msg_namelen) {
+		if(mode==VERIFY_READ) {
+			int err = move_addr_to_kernel(kern_msg->msg_name,
+						      kern_msg->msg_namelen,
+						      kern_address);
+			if(err < 0)
+				return err;
+		}
+		kern_msg->msg_name = kern_address;
+	} else
+		kern_msg->msg_name = NULL;
+
+	if(kern_msg->msg_iovlen > UIO_FASTIOV) {
+		kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec),
+				   GFP_KERNEL);
+		if(!kern_iov)
+			return -ENOMEM;
+	}
+
+	tot_len = iov_from_user32_to_kern(kern_iov,
+					  (struct iovec32 *)kern_msg->msg_iov,
+					  kern_msg->msg_iovlen);
+	if(tot_len >= 0)
+		kern_msg->msg_iov = kern_iov;
+	else if(kern_msg->msg_iovlen > UIO_FASTIOV)
+		kfree(kern_iov);
+
+	return tot_len;
+}
+
+/* There is a lot of hair here because the alignment rules (and
+ * thus placement) of cmsg headers and length are different for
+ * 32-bit apps.  -DaveM
+ */
+static int cmsghdr_from_user32_to_kern(struct msghdr *kmsg,
+				       unsigned char *stackbuf, int stackbuf_size)
+{
+	struct cmsghdr32 *ucmsg;
+	struct cmsghdr *kcmsg, *kcmsg_base;
+	__kernel_size_t32 ucmlen;
+	__kernel_size_t kcmlen, tmp;
+
+	kcmlen = 0;
+	kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
+	ucmsg = CMSG32_FIRSTHDR(kmsg);
+	while(ucmsg != NULL) {
+		if(get_user(ucmlen, &ucmsg->cmsg_len))
+			return -EFAULT;
+
+		/* Catch bogons. */
+		if(CMSG32_ALIGN(ucmlen) <
+		   CMSG32_ALIGN(sizeof(struct cmsghdr32)))
+			return -EINVAL;
+		if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
+				   + ucmlen) > kmsg->msg_controllen)
+			return -EINVAL;
+
+		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
+		       CMSG_ALIGN(sizeof(struct cmsghdr)));
+		kcmlen += tmp;
+		ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
+	}
+	if(kcmlen == 0)
+		return -EINVAL;
+
+	/* The kcmlen holds the 64-bit version of the control length.
+	 * It may not be modified as we do not stick it into the kmsg
+	 * until we have successfully copied over all of the data
+	 * from the user.
+	 */
+	if(kcmlen > stackbuf_size)
+		kcmsg_base = kcmsg = kmalloc(kcmlen, GFP_KERNEL);
+	if(kcmsg == NULL)
+		return -ENOBUFS;
+
+	/* Now copy them over neatly. */
+	memset(kcmsg, 0, kcmlen);
+	ucmsg = CMSG32_FIRSTHDR(kmsg);
+	while(ucmsg != NULL) {
+		__get_user(ucmlen, &ucmsg->cmsg_len);
+		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
+		       CMSG_ALIGN(sizeof(struct cmsghdr)));
+		kcmsg->cmsg_len = tmp;
+		__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level);
+		__get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type);
+
+		/* Copy over the data. */
+		if(copy_from_user(CMSG_DATA(kcmsg),
+				  CMSG32_DATA(ucmsg),
+				  (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
+			goto out_free_efault;
+
+		/* Advance. */
+		kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));
+		ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
+	}
+
+	/* Ok, looks like we made it.  Hook it up and return success. */
+	kmsg->msg_control = kcmsg_base;
+	kmsg->msg_controllen = kcmlen;
+	return 0;
+
+out_free_efault:
+	if(kcmsg_base != (struct cmsghdr *)stackbuf)
+		kfree(kcmsg_base);
+	return -EFAULT;
+}
+
+static void put_cmsg32(struct msghdr *kmsg, int level, int type,
+		       int len, void *data)
+{
+	struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;
+	struct cmsghdr32 cmhdr;
+	int cmlen = CMSG32_LEN(len);
+
+	if(cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {
+		kmsg->msg_flags |= MSG_CTRUNC;
+		return;
+	}
+
+	if(kmsg->msg_controllen < cmlen) {
+		kmsg->msg_flags |= MSG_CTRUNC;
+		cmlen = kmsg->msg_controllen;
+	}
+	cmhdr.cmsg_level = level;
+	cmhdr.cmsg_type = type;
+	cmhdr.cmsg_len = cmlen;
+
+	if(copy_to_user(cm, &cmhdr, sizeof cmhdr))
+		return;
+	if(copy_to_user(CMSG32_DATA(cm), data, cmlen - sizeof(struct cmsghdr32)))
+		return;
+	cmlen = CMSG32_SPACE(len);
+	kmsg->msg_control += cmlen;
+	kmsg->msg_controllen -= cmlen;
+}
+
+static void scm_detach_fds32(struct msghdr *kmsg, struct scm_cookie *scm)
+{
+	struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;
+	int fdmax = (kmsg->msg_controllen - sizeof(struct cmsghdr32)) / sizeof(int);
+	int fdnum = scm->fp->count;
+	struct file **fp = scm->fp->fp;
+	int *cmfptr;
+	int err = 0, i;
+
+	if (fdnum < fdmax)
+		fdmax = fdnum;
+
+	for (i = 0, cmfptr = (int *) CMSG32_DATA(cm); i < fdmax; i++, cmfptr++) {
+		int new_fd;
+		err = get_unused_fd();
+		if (err < 0)
+			break;
+		new_fd = err;
+		err = put_user(new_fd, cmfptr);
+		if (err) {
+			put_unused_fd(new_fd);
+			break;
+		}
+		/* Bump the usage count and install the file. */
+		get_file(fp[i]);
+		fd_install(new_fd, fp[i]);
+	}
+
+	if (i > 0) {
+		int cmlen = CMSG32_LEN(i * sizeof(int));
+		if (!err)
+			err = put_user(SOL_SOCKET, &cm->cmsg_level);
+		if (!err)
+			err = put_user(SCM_RIGHTS, &cm->cmsg_type);
+		if (!err)
+			err = put_user(cmlen, &cm->cmsg_len);
+		if (!err) {
+			cmlen = CMSG32_SPACE(i * sizeof(int));
+			kmsg->msg_control += cmlen;
+			kmsg->msg_controllen -= cmlen;
+		}
+	}
+	if (i < fdnum)
+		kmsg->msg_flags |= MSG_CTRUNC;
+
+	/*
+	 * All of the files that fit in the message have had their
+	 * usage counts incremented, so we just free the list.
+	 */
+	__scm_destroy(scm);
+}
+
+/* In these cases we (currently) can just copy to data over verbatim
+ * because all CMSGs created by the kernel have well defined types which
+ * have the same layout in both the 32-bit and 64-bit API.  One must add
+ * some special cased conversions here if we start sending control messages
+ * with incompatible types.
+ *
+ * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after
+ * we do our work.  The remaining cases are:
+ *
+ * SOL_IP	IP_PKTINFO	struct in_pktinfo	32-bit clean
+ *		IP_TTL		int			32-bit clean
+ *		IP_TOS		__u8			32-bit clean
+ *		IP_RECVOPTS	variable length		32-bit clean
+ *		IP_RETOPTS	variable length		32-bit clean
+ *		(these last two are clean because the types are defined
+ *		 by the IPv4 protocol)
+ *		IP_RECVERR	struct sock_extended_err +
+ *				struct sockaddr_in	32-bit clean
+ * SOL_IPV6	IPV6_RECVERR	struct sock_extended_err +
+ *				struct sockaddr_in6	32-bit clean
+ *		IPV6_PKTINFO	struct in6_pktinfo	32-bit clean
+ *		IPV6_HOPLIMIT	int			32-bit clean
+ *		IPV6_FLOWINFO	u32			32-bit clean
+ *		IPV6_HOPOPTS	ipv6 hop exthdr		32-bit clean
+ *		IPV6_DSTOPTS	ipv6 dst exthdr(s)	32-bit clean
+ *		IPV6_RTHDR	ipv6 routing exthdr	32-bit clean
+ *		IPV6_AUTHHDR	ipv6 auth exthdr	32-bit clean
+ */
+static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
+{
+	unsigned char *workbuf, *wp;
+	unsigned long bufsz, space_avail;
+	struct cmsghdr *ucmsg;
+
+	bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr;
+	space_avail = kmsg->msg_controllen + bufsz;
+	wp = workbuf = kmalloc(bufsz, GFP_KERNEL);
+	if(workbuf == NULL)
+		goto fail;
+
+	/* To make this more sane we assume the kernel sends back properly
+	 * formatted control messages.  Because of how the kernel will truncate
+	 * the cmsg_len for MSG_TRUNC cases, we need not check that case either.
+	 */
+	ucmsg = (struct cmsghdr *) orig_cmsg_uptr;
+	while(((unsigned long)ucmsg) <=
+	      (((unsigned long)kmsg->msg_control) - sizeof(struct cmsghdr))) {
+		struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp;
+		int clen64, clen32;
+
+		/* UCMSG is the 64-bit format CMSG entry in user-space.
+		 * KCMSG32 is within the kernel space temporary buffer
+		 * we use to convert into a 32-bit style CMSG.
+		 */
+		__get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len);
+		__get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level);
+		__get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
+
+		clen64 = kcmsg32->cmsg_len;
+		copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
+			       clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
+		clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
+			  CMSG32_ALIGN(sizeof(struct cmsghdr32)));
+		kcmsg32->cmsg_len = clen32;
+
+		ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64));
+		wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32));
+	}
+
+	/* Copy back fixed up data, and adjust pointers. */
+	bufsz = (wp - workbuf);
+	copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz);
+
+	kmsg->msg_control = (struct cmsghdr *)
+		(((char *)orig_cmsg_uptr) + bufsz);
+	kmsg->msg_controllen = space_avail - bufsz;
+
+	kfree(workbuf);
+	return;
+
+fail:
+	/* If we leave the 64-bit format CMSG chunks in there,
+	 * the application could get confused and crash.  So to
+	 * ensure greater recovery, we report no CMSGs.
+	 */
+	kmsg->msg_controllen += bufsz;
+	kmsg->msg_control = (void *) orig_cmsg_uptr;
+}
+
+asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
+{
+	struct socket *sock;
+	char address[MAX_SOCK_ADDR];
+	struct iovec iov[UIO_FASTIOV];
+	unsigned char ctl[sizeof(struct cmsghdr) + 20];
+	unsigned char *ctl_buf = ctl;
+	struct msghdr kern_msg;
+	int err, total_len;
+
+	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
+		return -EFAULT;
+	if(kern_msg.msg_iovlen > UIO_MAXIOV)
+		return -EINVAL;
+	err = verify_iovec32(&kern_msg, iov, address, VERIFY_READ);
+	if (err < 0)
+		goto out;
+	total_len = err;
+
+	if(kern_msg.msg_controllen) {
+		err = cmsghdr_from_user32_to_kern(&kern_msg, ctl, sizeof(ctl));
+		if(err)
+			goto out_freeiov;
+		ctl_buf = kern_msg.msg_control;
+	}
+	kern_msg.msg_flags = user_flags;
+
+	sock = sockfd_lookup(fd, &err);
+	if (sock != NULL) {
+		if (sock->file->f_flags & O_NONBLOCK)
+			kern_msg.msg_flags |= MSG_DONTWAIT;
+		err = sock_sendmsg(sock, &kern_msg, total_len);
+		sockfd_put(sock);
+	}
+
+	/* N.B. Use kfree here, as kern_msg.msg_controllen might change? */
+	if(ctl_buf != ctl)
+		kfree(ctl_buf);
+out_freeiov:
+	if(kern_msg.msg_iov != iov)
+		kfree(kern_msg.msg_iov);
+out:
+	return err;
+}
+
+asmlinkage int sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags)
+{
+	struct iovec iovstack[UIO_FASTIOV];
+	struct msghdr kern_msg;
+	char addr[MAX_SOCK_ADDR];
+	struct socket *sock;
+	struct iovec *iov = iovstack;
+	struct sockaddr *uaddr;
+	int *uaddr_len;
+	unsigned long cmsg_ptr;
+	int err, total_len, len = 0;
+
+	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
+		return -EFAULT;
+	if(kern_msg.msg_iovlen > UIO_MAXIOV)
+		return -EINVAL;
+
+	uaddr = kern_msg.msg_name;
+	uaddr_len = &user_msg->msg_namelen;
+	err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE);
+	if (err < 0)
+		goto out;
+	total_len = err;
+
+	cmsg_ptr = (unsigned long) kern_msg.msg_control;
+	kern_msg.msg_flags = 0;
+
+	sock = sockfd_lookup(fd, &err);
+	if (sock != NULL) {
+		struct scm_cookie scm;
+
+		if (sock->file->f_flags & O_NONBLOCK)
+			user_flags |= MSG_DONTWAIT;
+		memset(&scm, 0, sizeof(scm));
+		err = sock->ops->recvmsg(sock, &kern_msg, total_len,
+					 user_flags, &scm);
+		if(err >= 0) {
+			len = err;
+			if(!kern_msg.msg_control) {
+				if(sock->passcred || scm.fp)
+					kern_msg.msg_flags |= MSG_CTRUNC;
+				if(scm.fp)
+					__scm_destroy(&scm);
+			} else {
+				/* If recvmsg processing itself placed some
+				 * control messages into user space, it's is
+				 * using 64-bit CMSG processing, so we need
+				 * to fix it up before we tack on more stuff.
+				 */
+				if((unsigned long) kern_msg.msg_control != cmsg_ptr)
+					cmsg32_recvmsg_fixup(&kern_msg, cmsg_ptr);
+
+				/* Wheee... */
+				if(sock->passcred)
+					put_cmsg32(&kern_msg,
+						   SOL_SOCKET, SCM_CREDENTIALS,
+						   sizeof(scm.creds), &scm.creds);
+				if(scm.fp != NULL)
+					scm_detach_fds32(&kern_msg, &scm);
+			}
+		}
+		sockfd_put(sock);
+	}
+
+	if(uaddr != NULL && err >= 0)
+		err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
+	if(cmsg_ptr != 0 && err >= 0) {
+		unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control);
+		__kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr - cmsg_ptr);
+		err |= __put_user(uclen, &user_msg->msg_controllen);
+	}
+	if(err >= 0)
+		err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags);
+	if(kern_msg.msg_iov != iov)
+		kfree(kern_msg.msg_iov);
+out:
+	if(err < 0)
+		return err;
+	return len;
+}
+
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
+				     char *optval, int optlen);
+
+static int do_set_attach_filter(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	struct sock_fprog32 {
+		__u16 len;
+		__u32 filter;
+	} *fprog32 = (struct sock_fprog32 *)optval;
+	struct sock_fprog kfprog;
+	struct sock_filter *kfilter;
+	unsigned int fsize;
+	mm_segment_t old_fs;
+	__u32 uptr;
+	int ret;
+
+	if (get_user(kfprog.len, &fprog32->len) ||
+	    __get_user(uptr, &fprog32->filter))
+		return -EFAULT;
+
+	kfprog.filter = (struct sock_filter *)A(uptr);
+	fsize = kfprog.len * sizeof(struct sock_filter);
+
+	kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL);
+	if (kfilter == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(kfilter, kfprog.filter, fsize)) {
+		kfree(kfilter);
+		return -EFAULT;
+	}
+
+	kfprog.filter = kfilter;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_setsockopt(fd, level, optname,
+			     (char *)&kfprog, sizeof(kfprog));
+	set_fs(old_fs);
+
+	kfree(kfilter);
+
+	return ret;
+}
+
+static int do_set_icmpv6_filter(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	struct icmp6_filter kfilter;
+	mm_segment_t old_fs;
+	int ret, i;
+
+	if (copy_from_user(&kfilter, optval, sizeof(kfilter)))
+		return -EFAULT;
+
+
+	for (i = 0; i < 8; i += 2) {
+		u32 tmp = kfilter.data[i];
+
+		kfilter.data[i] = kfilter.data[i + 1];
+		kfilter.data[i + 1] = tmp;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_setsockopt(fd, level, optname,
+			     (char *) &kfilter, sizeof(kfilter));
+	set_fs(old_fs);
+
+	return ret;
+}
+
+asmlinkage int sys32_setsockopt(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	if (optname == SO_ATTACH_FILTER)
+		return do_set_attach_filter(fd, level, optname,
+					    optval, optlen);
+	if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER)
+		return do_set_icmpv6_filter(fd, level, optname,
+					    optval, optlen);
+
+	return sys_setsockopt(fd, level, optname, optval, optlen);
+}
+
+
+/* Argument list sizes for sys_socketcall */
+#define AL(x) ((x) * sizeof(u32))
+static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
+                                AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
+                                AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
+#undef AL
+
+extern asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
+extern asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr,
+				  int addrlen);
+extern asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr,
+				 int *upeer_addrlen); 
+extern asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr,
+				      int *usockaddr_len);
+extern asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr,
+				      int *usockaddr_len);
+extern asmlinkage long sys_send(int fd, void *buff, size_t len, unsigned flags);
+extern asmlinkage long sys_sendto(int fd, u32 buff, __kernel_size_t32 len,
+				   unsigned flags, u32 addr, int addr_len);
+extern asmlinkage long sys_recv(int fd, void *ubuf, size_t size, unsigned flags);
+extern asmlinkage long sys_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size,
+				     unsigned flags, u32 addr, u32 addr_len);
+extern asmlinkage long sys_getsockopt(int fd, int level, int optname,
+				       u32 optval, u32 optlen);
+
+extern asmlinkage long sys_socket(int family, int type, int protocol);
+extern asmlinkage long sys_socketpair(int family, int type, int protocol,
+				     int usockvec[2]);
+extern asmlinkage long sys_shutdown(int fd, int how);
+extern asmlinkage long sys_listen(int fd, int backlog);
+
+asmlinkage long sys32_socketcall(int call, u32 *args)
+{
+	int ret;
+	u32 a[6];
+	u32 a0,a1;
+				 
+	if (call<SYS_SOCKET||call>SYS_RECVMSG)
+		return -EINVAL;
+	if (copy_from_user(a, args, nas[call]))
+		return -EFAULT;
+	a0=a[0];
+	a1=a[1];
+	
+	switch(call) 
+	{
+		case SYS_SOCKET:
+			ret = sys_socket(a0, a1, a[2]);
+			break;
+		case SYS_BIND:
+			ret = sys_bind(a0, (struct sockaddr *)A(a1), a[2]);
+			break;
+		case SYS_CONNECT:
+			ret = sys_connect(a0, (struct sockaddr *)A(a1), a[2]);
+			break;
+		case SYS_LISTEN:
+			ret = sys_listen(a0, a1);
+			break;
+		case SYS_ACCEPT:
+			ret = sys_accept(a0, (struct sockaddr *)A(a1),
+					  (int *)A(a[2]));
+			break;
+		case SYS_GETSOCKNAME:
+			ret = sys_getsockname(a0, (struct sockaddr *)A(a1),
+					       (int *)A(a[2]));
+			break;
+		case SYS_GETPEERNAME:
+			ret = sys_getpeername(a0, (struct sockaddr *)A(a1),
+					       (int *)A(a[2]));
+			break;
+		case SYS_SOCKETPAIR:
+			ret = sys_socketpair(a0, a1, a[2], (int *)A(a[3]));
+			break;
+		case SYS_SEND:
+			ret = sys_send(a0, (void *)A(a1), a[2], a[3]);
+			break;
+		case SYS_SENDTO:
+			ret = sys_sendto(a0, a1, a[2], a[3], a[4], a[5]);
+			break;
+		case SYS_RECV:
+			ret = sys_recv(a0, (void *)A(a1), a[2], a[3]);
+			break;
+		case SYS_RECVFROM:
+			ret = sys_recvfrom(a0, a1, a[2], a[3], a[4], a[5]);
+			break;
+		case SYS_SHUTDOWN:
+			ret = sys_shutdown(a0,a1);
+			break;
+		case SYS_SETSOCKOPT:
+			ret = sys_setsockopt(a0, a1, a[2], (char *)A(a[3]),
+					      a[4]);
+			break;
+		case SYS_GETSOCKOPT:
+			ret = sys_getsockopt(a0, a1, a[2], a[3], a[4]);
+			break;
+		case SYS_SENDMSG:
+			ret = sys32_sendmsg(a0, (struct msghdr32 *)A(a1),
+					     a[2]);
+			break;
+		case SYS_RECVMSG:
+			ret = sys32_recvmsg(a0, (struct msghdr32 *)A(a1),
+					     a[2]);
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+	}
+	return ret;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/ia32/sys_ia32.c linux-2.4.20/arch/x86_64/ia32/sys_ia32.c
--- linux-2.4.19/arch/x86_64/ia32/sys_ia32.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/ia32/sys_ia32.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,2527 @@
+/*
+ * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Based on
+ *             sys_sparc32 
+ *
+ * Copyright (C) 2000		VA Linux Co
+ * Copyright (C) 2000		Don Dugger <n0ano@valinux.com>
+ * Copyright (C) 1999 		Arun Sharma <arun.sharma@intel.com>
+ * Copyright (C) 1997,1998 	Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 		David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 2000		Hewlett-Packard Co.
+ * Copyright (C) 2000		David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2000,2001	Andi Kleen, SuSE Labs (x86-64 port) 
+ *
+ * These routines maintain argument size conversion between 32bit and 64bit
+ * environment. In 2.5 most of this should be moved to a generic directory. 
+ *
+ * This file assumes that there is a hole at the end of user address space.
+ * $Id: sys_ia32.c,v 1.42 2002/09/17 15:23:41 ak Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h> 
+#include <linux/file.h> 
+#include <linux/signal.h>
+#include <linux/utime.h>
+#include <linux/resource.h>
+#include <linux/times.h>
+#include <linux/utsname.h>
+#include <linux/timex.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/mm.h>
+#include <linux/shm.h>
+#include <linux/slab.h>
+#include <linux/uio.h>
+#include <linux/nfs_fs.h>
+#include <linux/smb_fs.h>
+#include <linux/smb_mount.h>
+#include <linux/ncp_fs.h>
+#include <linux/quota.h>
+#include <linux/module.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/cache.h>
+#include <linux/nfsd/xdr.h>
+#include <linux/nfsd/syscall.h>
+#include <linux/poll.h>
+#include <linux/personality.h>
+#include <linux/stat.h>
+#include <linux/ipc.h>
+#include <linux/rwsem.h>
+#include <linux/binfmts.h>
+#include <linux/init.h>
+#include <asm/mman.h>
+#include <asm/types.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <asm/ipc.h>
+#include <asm/atomic.h>
+
+#include <net/scm.h>
+#include <net/sock.h>
+#include <asm/ia32.h>
+
+#define A(__x)		((unsigned long)(__x))
+#define AA(__x)		((unsigned long)(__x))
+#define ROUND_UP(x,a)	((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1)))
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+
+#undef high2lowuid
+#undef high2lowgid
+#undef low2highuid
+#undef low2highgid
+
+#define high2lowuid(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)
+#define high2lowgid(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid)
+#define low2highuid(uid) ((uid) == (u16)-1) ? (uid_t)-1 : (uid_t)(uid)
+#define low2highgid(gid) ((gid) == (u16)-1) ? (gid_t)-1 : (gid_t)(gid)
+extern int overflowuid,overflowgid; 
+
+
+static int
+putstat(struct stat32 *ubuf, struct stat *kbuf)
+{
+	if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct stat32)) ||
+	    __put_user (kbuf->st_dev, &ubuf->st_dev) ||
+	    __put_user (kbuf->st_ino, &ubuf->st_ino) ||
+	    __put_user (kbuf->st_mode, &ubuf->st_mode) ||
+	    __put_user (kbuf->st_nlink, &ubuf->st_nlink) ||
+	    __put_user (kbuf->st_uid, &ubuf->st_uid) ||
+	    __put_user (kbuf->st_gid, &ubuf->st_gid) ||
+	    __put_user (kbuf->st_rdev, &ubuf->st_rdev) ||
+	    __put_user (kbuf->st_size, &ubuf->st_size) ||
+	    __put_user (kbuf->st_atime, &ubuf->st_atime) ||
+	    __put_user (kbuf->st_mtime, &ubuf->st_mtime) ||
+	    __put_user (kbuf->st_ctime, &ubuf->st_ctime) ||
+	    __put_user (kbuf->st_blksize, &ubuf->st_blksize) ||
+	    __put_user (kbuf->st_blocks, &ubuf->st_blocks))
+		return -EFAULT;
+	return 0;
+}
+
+extern asmlinkage long sys_newstat(char * filename, struct stat * statbuf);
+
+asmlinkage long
+sys32_newstat(char * filename, struct stat32 *statbuf)
+{
+	int ret;
+	struct stat s;
+	mm_segment_t old_fs = get_fs();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_newstat(filename, &s);
+	set_fs (old_fs);
+	if (putstat (statbuf, &s))
+		return -EFAULT;
+	return ret;
+}
+
+extern asmlinkage long sys_newlstat(char * filename, struct stat * statbuf);
+
+asmlinkage long
+sys32_newlstat(char * filename, struct stat32 *statbuf)
+{
+	int ret;
+	struct stat s;
+	mm_segment_t old_fs = get_fs();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_newlstat(filename, &s);
+	set_fs (old_fs);
+	if (putstat (statbuf, &s))
+		return -EFAULT;
+	return ret;
+}
+
+extern asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf);
+
+asmlinkage long
+sys32_newfstat(unsigned int fd, struct stat32 *statbuf)
+{
+	int ret;
+	struct stat s;
+	mm_segment_t old_fs = get_fs();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_newfstat(fd, &s);
+	set_fs (old_fs);
+	if (putstat (statbuf, &s))
+		return -EFAULT;
+	return ret;
+}
+
+/* Another set for IA32/LFS -- x86_64 struct stat is different due to 
+   support for 64bit inode numbers. */
+
+static int
+putstat64(struct stat64 *ubuf, struct stat *kbuf)
+{
+	if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct stat64)) ||
+	    __put_user (kbuf->st_dev, &ubuf->st_dev) ||
+	    __put_user (kbuf->st_ino, &ubuf->__st_ino) ||
+	    __put_user (kbuf->st_ino, &ubuf->st_ino) ||
+	    __put_user (kbuf->st_mode, &ubuf->st_mode) ||
+	    __put_user (kbuf->st_nlink, &ubuf->st_nlink) ||
+	    __put_user (kbuf->st_uid, &ubuf->st_uid) ||
+	    __put_user (kbuf->st_gid, &ubuf->st_gid) ||
+	    __put_user (kbuf->st_rdev, &ubuf->st_rdev) ||
+	    __put_user (kbuf->st_size, &ubuf->st_size) ||
+	    __put_user (kbuf->st_atime, &ubuf->st_atime) ||
+	    __put_user (kbuf->st_mtime, &ubuf->st_mtime) ||
+	    __put_user (kbuf->st_ctime, &ubuf->st_ctime) ||
+	    __put_user (kbuf->st_blksize, &ubuf->st_blksize) ||
+	    __put_user (kbuf->st_blocks, &ubuf->st_blocks))
+		return -EFAULT;
+	return 0;
+}
+
+asmlinkage long
+sys32_stat64(char * filename, struct stat64 *statbuf)
+{
+	int ret;
+	struct stat s;
+	mm_segment_t old_fs = get_fs();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_newstat(filename, &s);
+	set_fs (old_fs);
+	if (putstat64 (statbuf, &s))
+		return -EFAULT;
+	return ret;
+}
+
+asmlinkage long
+sys32_lstat64(char * filename, struct stat64 *statbuf)
+{
+	int ret;
+	struct stat s;
+	mm_segment_t old_fs = get_fs();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_newlstat(filename, &s);
+	set_fs (old_fs);
+	if (putstat64 (statbuf, &s))
+		return -EFAULT;
+	return ret;
+}
+
+asmlinkage long
+sys32_fstat64(unsigned int fd, struct stat64 *statbuf)
+{
+	int ret;
+	struct stat s;
+	mm_segment_t old_fs = get_fs();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_newfstat(fd, &s);
+	set_fs (old_fs);
+	if (putstat64 (statbuf, &s))
+		return -EFAULT;
+	return ret;
+}
+
+
+
+/*
+ * Linux/i386 didn't use to be able to handle more than
+ * 4 system call parameters, so these system calls used a memory
+ * block for parameter passing..
+ */
+
+struct mmap_arg_struct {
+	unsigned int addr;
+	unsigned int len;
+	unsigned int prot;
+	unsigned int flags;
+	unsigned int fd;
+	unsigned int offset;
+};
+
+asmlinkage __u32
+sys32_mmap(struct mmap_arg_struct *arg)
+{
+	struct mmap_arg_struct a;
+	struct file *file = NULL;
+	unsigned long retval;
+	struct mm_struct *mm ;
+
+	if (copy_from_user(&a, arg, sizeof(a)))
+		return -EFAULT;
+
+	if (a.offset & ~PAGE_MASK)
+		return -EINVAL; 
+
+	if (!(a.flags & MAP_ANONYMOUS)) {
+		file = fget(a.fd);
+		if (!file)
+			return -EBADF;
+	}
+	if (a.prot & PROT_READ) 
+		a.prot |= PROT_EXEC; 
+
+	a.flags |= MAP_32BIT;
+
+	mm = current->mm; 
+	down_write(&mm->mmap_sem); 
+	retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset>>PAGE_SHIFT);
+	if (file)
+		fput(file);
+
+	/* Should not happen */
+	if (retval >= 0xFFFFFFFF && (long)retval > 0) { 
+		do_munmap(mm, retval, a.len); 
+		retval = -ENOMEM; 
+	} 
+	up_write(&mm->mmap_sem); 
+
+	return retval;
+}
+
+extern asmlinkage long sys_mprotect(unsigned long start,size_t len,unsigned long prot);
+
+asmlinkage int sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
+{
+	if (prot & PROT_READ) 
+		prot |= PROT_EXEC; 
+	return sys_mprotect(start,len,prot); 
+}
+
+asmlinkage long
+sys32_pipe(int *fd)
+{
+	int retval;
+	int fds[2];
+
+	retval = do_pipe(fds);
+	if (retval)
+		goto out;
+	if (copy_to_user(fd, fds, sizeof(fds)))
+		retval = -EFAULT;
+  out:
+	return retval;
+}
+
+asmlinkage long
+sys32_rt_sigaction(int sig, struct sigaction32 *act,
+		   struct sigaction32 *oact,  unsigned int sigsetsize)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+	sigset32_t set32;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset32_t))
+		return -EINVAL;
+
+	if (act) {
+		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		    __get_user((long)new_ka.sa.sa_handler, &act->sa_handler) ||
+		    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+		    __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer)||
+		    __copy_from_user(&set32, &act->sa_mask, sizeof(sigset32_t)))
+			return -EFAULT;
+
+		/* FIXME: here we rely on _IA32_NSIG_WORS to be >= than _NSIG_WORDS << 1 */
+		switch (_NSIG_WORDS) {
+		case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6]
+				| (((long)set32.sig[7]) << 32);
+		case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4]
+				| (((long)set32.sig[5]) << 32);
+		case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2]
+				| (((long)set32.sig[3]) << 32);
+		case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0]
+				| (((long)set32.sig[1]) << 32);
+		}
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		/* FIXME: here we rely on _IA32_NSIG_WORS to be >= than _NSIG_WORDS << 1 */
+		switch (_NSIG_WORDS) {
+		case 4:
+			set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32);
+			set32.sig[6] = old_ka.sa.sa_mask.sig[3];
+		case 3:
+			set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32);
+			set32.sig[4] = old_ka.sa.sa_mask.sig[2];
+		case 2:
+			set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32);
+			set32.sig[2] = old_ka.sa.sa_mask.sig[1];
+		case 1:
+			set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
+			set32.sig[0] = old_ka.sa.sa_mask.sig[0];
+		}
+		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		    __put_user((long)old_ka.sa.sa_handler, &oact->sa_handler) ||
+		    __put_user((long)old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+		    __copy_to_user(&oact->sa_mask, &set32, sizeof(sigset32_t)))
+			return -EFAULT;
+	}
+
+	return ret;
+}
+
+asmlinkage long
+sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact)
+{
+        struct k_sigaction new_ka, old_ka;
+        int ret;
+
+        if (act) {
+		old_sigset32_t mask;
+
+		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		    __get_user((long)new_ka.sa.sa_handler, &act->sa_handler) ||
+		    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+		    __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer) ||
+		    __get_user(mask, &act->sa_mask))
+			return -EFAULT;
+		siginitset(&new_ka.sa.sa_mask, mask);
+        }
+
+        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		    __put_user((long)old_ka.sa.sa_handler, &oact->sa_handler) ||
+		    __put_user((long)old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+		    __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
+			return -EFAULT;
+        }
+
+	return ret;
+}
+
+extern asmlinkage long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset,
+					  size_t sigsetsize);
+
+asmlinkage long
+sys32_rt_sigprocmask(int how, sigset32_t *set, sigset32_t *oset,
+		     unsigned int sigsetsize)
+{
+	sigset_t s;
+	sigset32_t s32;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	
+	if (set) {
+		if (copy_from_user (&s32, set, sizeof(sigset32_t)))
+			return -EFAULT;
+		switch (_NSIG_WORDS) {
+		case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
+		case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
+		case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
+		case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
+		}
+	}
+	set_fs (KERNEL_DS);
+	ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL,
+				 sigsetsize); 
+	set_fs (old_fs);
+	if (ret) return ret;
+	if (oset) {
+		switch (_NSIG_WORDS) {
+		case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
+		case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
+		case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
+		case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
+		}
+		if (copy_to_user (oset, &s32, sizeof(sigset32_t)))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+static int
+put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
+{
+	if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct statfs32)) ||
+	    __put_user (kbuf->f_type, &ubuf->f_type) ||
+	    __put_user (kbuf->f_bsize, &ubuf->f_bsize) ||
+	    __put_user (kbuf->f_blocks, &ubuf->f_blocks) ||
+	    __put_user (kbuf->f_bfree, &ubuf->f_bfree) ||
+	    __put_user (kbuf->f_bavail, &ubuf->f_bavail) ||
+	    __put_user (kbuf->f_files, &ubuf->f_files) ||
+	    __put_user (kbuf->f_ffree, &ubuf->f_ffree) ||
+	    __put_user (kbuf->f_namelen, &ubuf->f_namelen) ||
+	    __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
+	    __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]))
+		return -EFAULT;
+	return 0;
+}
+
+extern asmlinkage long sys_statfs(const char * path, struct statfs * buf);
+
+asmlinkage long
+sys32_statfs(const char * path, struct statfs32 *buf)
+{
+	int ret;
+	struct statfs s;
+	mm_segment_t old_fs = get_fs();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_statfs((const char *)path, &s);
+	set_fs (old_fs);
+	if (put_statfs(buf, &s))
+		return -EFAULT;
+	return ret;
+}
+
+extern asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf);
+
+asmlinkage long
+sys32_fstatfs(unsigned int fd, struct statfs32 *buf)
+{
+	int ret;
+	struct statfs s;
+	mm_segment_t old_fs = get_fs();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_fstatfs(fd, &s);
+	set_fs (old_fs);
+	if (put_statfs(buf, &s))
+		return -EFAULT;
+	return ret;
+}
+
+struct timeval32
+{
+    int tv_sec, tv_usec;
+};
+
+struct itimerval32
+{
+    struct timeval32 it_interval;
+    struct timeval32 it_value;
+};
+
+static inline long
+get_tv32(struct timeval *o, struct timeval32 *i)
+{
+	int err = -EFAULT; 
+	if (access_ok(VERIFY_READ, i, sizeof(*i))) { 
+		err = __get_user(o->tv_sec, &i->tv_sec);
+		err |= __get_user(o->tv_usec, &i->tv_usec);
+	}
+	return err; 
+}
+
+static inline long
+put_tv32(struct timeval32 *o, struct timeval *i)
+{
+	int err = -EFAULT;
+	if (access_ok(VERIFY_WRITE, o, sizeof(*o))) { 
+		err = __put_user(i->tv_sec, &o->tv_sec);
+		err |= __put_user(i->tv_usec, &o->tv_usec);
+	} 
+	return err; 
+}
+
+static inline long
+get_it32(struct itimerval *o, struct itimerval32 *i)
+{
+	int err = -EFAULT; 
+	if (access_ok(VERIFY_READ, i, sizeof(*i))) { 
+		err = __get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec);
+		err |= __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec);
+		err |= __get_user(o->it_value.tv_sec, &i->it_value.tv_sec);
+		err |= __get_user(o->it_value.tv_usec, &i->it_value.tv_usec);
+	}
+	return err;
+}
+
+static inline long
+put_it32(struct itimerval32 *o, struct itimerval *i)
+{
+	int err = -EFAULT;
+	if (access_ok(VERIFY_WRITE, o, sizeof(*o))) {
+		err = __put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec);
+		err |= __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec);
+		err |= __put_user(i->it_value.tv_sec, &o->it_value.tv_sec);
+		err |= __put_user(i->it_value.tv_usec, &o->it_value.tv_usec); 
+	} 
+	return err;
+}
+
+extern int do_getitimer(int which, struct itimerval *value);
+
+asmlinkage long
+sys32_getitimer(int which, struct itimerval32 *it)
+{
+	struct itimerval kit;
+	int error;
+
+	error = do_getitimer(which, &kit);
+	if (!error && put_it32(it, &kit))
+		error = -EFAULT;
+
+	return error;
+}
+
+extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
+
+asmlinkage long
+sys32_setitimer(int which, struct itimerval32 *in, struct itimerval32 *out)
+{
+	struct itimerval kin, kout;
+	int error;
+
+	if (in) {
+		if (get_it32(&kin, in))
+			return -EFAULT;
+	} else
+		memset(&kin, 0, sizeof(kin));
+
+	error = do_setitimer(which, &kin, out ? &kout : NULL);
+	if (error || !out)
+		return error;
+	if (put_it32(out, &kout))
+		return -EFAULT;
+
+	return 0;
+
+}
+asmlinkage unsigned long 
+sys32_alarm(unsigned int seconds)
+{
+	struct itimerval it_new, it_old;
+	unsigned int oldalarm;
+
+	it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
+	it_new.it_value.tv_sec = seconds;
+	it_new.it_value.tv_usec = 0;
+	do_setitimer(ITIMER_REAL, &it_new, &it_old);
+	oldalarm = it_old.it_value.tv_sec;
+	/* ehhh.. We can't return 0 if we have an alarm pending.. */
+	/* And we'd better return too much than too little anyway */
+	if (it_old.it_value.tv_usec)
+		oldalarm++;
+	return oldalarm;
+}
+
+/* Translations due to time_t size differences.  Which affects all
+   sorts of things, like timeval and itimerval.  */
+
+struct utimbuf_32 {
+	int	atime;
+	int	mtime;
+};
+
+extern asmlinkage long sys_utimes(char * filename, struct timeval * utimes);
+extern asmlinkage long sys_gettimeofday (struct timeval *tv, struct timezone *tz);
+
+extern struct timezone sys_tz;
+extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
+
+asmlinkage long
+sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz)
+{
+	if (tv) {
+		struct timeval ktv;
+		do_gettimeofday(&ktv);
+		if (put_tv32(tv, &ktv))
+			return -EFAULT;
+	}
+	if (tz) {
+		if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+asmlinkage long
+sys32_settimeofday(struct timeval32 *tv, struct timezone *tz)
+{
+	struct timeval ktv;
+	struct timezone ktz;
+
+ 	if (tv) {
+		if (get_tv32(&ktv, tv))
+			return -EFAULT;
+	}
+	if (tz) {
+		if (copy_from_user(&ktz, tz, sizeof(ktz)))
+			return -EFAULT;
+	}
+
+	return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL);
+}
+
+struct linux32_dirent {
+	u32	d_ino;
+	u32	d_off;
+	u16	d_reclen;
+	char	d_name[1];
+};
+
+struct old_linux32_dirent {
+	u32	d_ino;
+	u32	d_offset;
+	u16	d_namlen;
+	char	d_name[1];
+};
+
+struct getdents32_callback {
+	struct linux32_dirent * current_dir;
+	struct linux32_dirent * previous;
+	int count;
+	int error;
+};
+
+struct readdir32_callback {
+	struct old_linux32_dirent * dirent;
+	int count;
+};
+
+static int
+filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
+	   unsigned int d_type)
+{
+	struct linux32_dirent * dirent;
+	struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
+	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4);
+
+	buf->error = -EINVAL;	/* only used if we fail.. */
+	if (reclen > buf->count)
+		return -EINVAL;
+	dirent = buf->previous;
+	if (dirent)
+		put_user(offset, &dirent->d_off);
+	dirent = buf->current_dir;
+	buf->previous = dirent;
+	put_user(ino, &dirent->d_ino);
+	put_user(reclen, &dirent->d_reclen);
+	copy_to_user(dirent->d_name, name, namlen);
+	put_user(0, dirent->d_name + namlen);
+	((char *) dirent) += reclen;
+	buf->current_dir = dirent;
+	buf->count -= reclen;
+	return 0;
+}
+
+asmlinkage long
+sys32_getdents (unsigned int fd, void * dirent, unsigned int count)
+{
+	struct file * file;
+	struct linux32_dirent * lastdirent;
+	struct getdents32_callback buf;
+	int error;
+
+	error = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto out;
+
+	buf.current_dir = (struct linux32_dirent *) dirent;
+	buf.previous = NULL;
+	buf.count = count;
+	buf.error = 0;
+
+	error = vfs_readdir(file, filldir32, &buf);
+	if (error < 0)
+		goto out_putf;
+	error = buf.error;
+	lastdirent = buf.previous;
+	if (lastdirent) {
+		put_user(file->f_pos, &lastdirent->d_off);
+		error = count - buf.count;
+	}
+
+out_putf:
+	fput(file);
+out:
+	return error;
+}
+
+static int
+fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t ino, unsigned d_type)
+{
+	struct readdir32_callback * buf = (struct readdir32_callback *) __buf;
+	struct old_linux32_dirent * dirent;
+
+	if (buf->count)
+		return -EINVAL;
+	buf->count++;
+	dirent = buf->dirent;
+	put_user(ino, &dirent->d_ino);
+	put_user(offset, &dirent->d_offset);
+	put_user(namlen, &dirent->d_namlen);
+	copy_to_user(dirent->d_name, name, namlen);
+	put_user(0, dirent->d_name + namlen);
+	return 0;
+}
+
+asmlinkage long
+sys32_oldreaddir (unsigned int fd, void * dirent, unsigned int count)
+{
+	int error;
+	struct file * file;
+	struct readdir32_callback buf;
+
+	error = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto out;
+
+	buf.count = 0;
+	buf.dirent = dirent;
+
+	error = vfs_readdir(file, fillonedir32, &buf);
+	if (error >= 0)
+		error = buf.count;
+	fput(file);
+out:
+	return error;
+}
+
+/*
+ * We can actually return ERESTARTSYS instead of EINTR, but I'd
+ * like to be certain this leads to no problems. So I return
+ * EINTR just for safety.
+ *
+ * Update: ERESTARTSYS breaks at least the xview clock binary, so
+ * I'm trying ERESTARTNOHAND which restart only when you want to.
+ */
+#define MAX_SELECT_SECONDS \
+	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
+#define ROUND_UP_TIME(x,y) (((x)+(y)-1)/(y))
+
+asmlinkage long
+sys32_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval32 *tvp32)
+{
+	fd_set_bits fds;
+	char *bits;
+	long timeout;
+	int ret, size;
+
+	timeout = MAX_SCHEDULE_TIMEOUT;
+	if (tvp32) {
+		time_t sec, usec;
+
+		get_user(sec, &tvp32->tv_sec);
+		get_user(usec, &tvp32->tv_usec);
+
+		ret = -EINVAL;
+		if (sec < 0 || usec < 0)
+			goto out_nofds;
+
+		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
+			timeout = ROUND_UP_TIME(usec, 1000000/HZ);
+			timeout += sec * (unsigned long) HZ;
+		}
+	}
+
+	ret = -EINVAL;
+	if (n < 0)
+		goto out_nofds;
+
+	if (n > current->files->max_fdset)
+		n = current->files->max_fdset;
+
+	/*
+	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
+	 * since we used fdset we need to allocate memory in units of
+	 * long-words. 
+	 */
+	ret = -ENOMEM;
+	size = FDS_BYTES(n);
+	bits = kmalloc(6 * size, GFP_KERNEL);
+	if (!bits)
+		goto out_nofds;
+	fds.in      = (unsigned long *)  bits;
+	fds.out     = (unsigned long *) (bits +   size);
+	fds.ex      = (unsigned long *) (bits + 2*size);
+	fds.res_in  = (unsigned long *) (bits + 3*size);
+	fds.res_out = (unsigned long *) (bits + 4*size);
+	fds.res_ex  = (unsigned long *) (bits + 5*size);
+
+	if ((ret = get_fd_set(n, inp, fds.in)) ||
+	    (ret = get_fd_set(n, outp, fds.out)) ||
+	    (ret = get_fd_set(n, exp, fds.ex)))
+		goto out;
+	zero_fd_set(n, fds.res_in);
+	zero_fd_set(n, fds.res_out);
+	zero_fd_set(n, fds.res_ex);
+
+	ret = do_select(n, &fds, &timeout);
+
+	if (tvp32 && !(current->personality & STICKY_TIMEOUTS)) {
+		time_t sec = 0, usec = 0;
+		if (timeout) {
+			sec = timeout / HZ;
+			usec = timeout % HZ;
+			usec *= (1000000/HZ);
+		}
+		put_user(sec, (int *)&tvp32->tv_sec);
+		put_user(usec, (int *)&tvp32->tv_usec);
+	}
+
+	if (ret < 0)
+		goto out;
+	if (!ret) {
+		ret = -ERESTARTNOHAND;
+		if (signal_pending(current))
+			goto out;
+		ret = 0;
+	}
+
+	set_fd_set(n, inp, fds.res_in);
+	set_fd_set(n, outp, fds.res_out);
+	set_fd_set(n, exp, fds.res_ex);
+
+out:
+	kfree(bits);
+out_nofds:
+	return ret;
+}
+
+struct sel_arg_struct {
+	unsigned int n;
+	unsigned int inp;
+	unsigned int outp;
+	unsigned int exp;
+	unsigned int tvp;
+};
+
+asmlinkage long
+sys32_old_select(struct sel_arg_struct *arg)
+{
+	struct sel_arg_struct a;
+
+	if (copy_from_user(&a, arg, sizeof(a)))
+		return -EFAULT;
+	return sys32_select(a.n, (fd_set *)A(a.inp), (fd_set *)A(a.outp), (fd_set *)A(a.exp),
+			    (struct timeval32 *)A(a.tvp));
+}
+
+struct timespec32 {
+	int 	tv_sec;
+	int	tv_nsec;
+};
+
+extern asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp); 
+
+asmlinkage long
+sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp)
+{
+	struct timespec t;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+	
+	if (verify_area(VERIFY_READ, rqtp, sizeof(struct timespec32)) ||
+	    __get_user (t.tv_sec, &rqtp->tv_sec) ||
+	    __get_user (t.tv_nsec, &rqtp->tv_nsec))
+		return -EFAULT;
+	set_fs (KERNEL_DS);
+	ret = sys_nanosleep(&t, rmtp ? &t : NULL);
+	set_fs (old_fs);
+	if (rmtp && ret == -EINTR) {
+		if (verify_area(VERIFY_WRITE, rmtp, sizeof(struct timespec32)) ||
+		    __put_user (t.tv_sec, &rmtp->tv_sec) ||
+	    	    __put_user (t.tv_nsec, &rmtp->tv_nsec))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+asmlinkage ssize_t sys_readv(unsigned long,const struct iovec *,unsigned long);
+asmlinkage ssize_t sys_writev(unsigned long,const struct iovec *,unsigned long);
+
+struct iovec *
+get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type)
+{
+	int i;
+	u32 buf, len;
+	struct iovec *ivp, *iov;
+
+	/* Get the "struct iovec" from user memory */
+
+	if (!count)
+		return 0;
+	if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count))
+		return(struct iovec *)0;
+	if (count > UIO_MAXIOV)
+		return(struct iovec *)0;
+	if (count > UIO_FASTIOV) {
+		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
+		if (!iov)
+			return((struct iovec *)0);
+	} else
+		iov = iov_buf;
+
+	ivp = iov;
+	for (i = 0; i < count; i++) {
+		if (__get_user(len, &iov32->iov_len) ||
+		    __get_user(buf, &iov32->iov_base)) {
+			if (iov != iov_buf)
+				kfree(iov);
+			return((struct iovec *)0);
+		}
+		if (verify_area(type, (void *)A(buf), len)) {
+			if (iov != iov_buf)
+				kfree(iov);
+			return((struct iovec *)0);
+		}
+		ivp->iov_base = (void *)A(buf);
+		ivp->iov_len = (__kernel_size_t)len;
+		iov32++;
+		ivp++;
+	}
+	return(iov);
+}
+
+asmlinkage long
+sys32_readv(int fd, struct iovec32 *vector, u32 count)
+{
+	struct iovec iovstack[UIO_FASTIOV];
+	struct iovec *iov;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+
+	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE)) == (struct iovec *)0)
+		return -EFAULT;
+	set_fs(KERNEL_DS);
+	ret = sys_readv(fd, iov, count);
+	set_fs(old_fs);
+	if (iov != iovstack)
+		kfree(iov);
+	return ret;
+}
+
+asmlinkage long
+sys32_writev(int fd, struct iovec32 *vector, u32 count)
+{
+	struct iovec iovstack[UIO_FASTIOV];
+	struct iovec *iov;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+
+	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_READ)) == (struct iovec *)0)
+		return -EFAULT;
+	set_fs(KERNEL_DS);
+	ret = sys_writev(fd, iov, count);
+	set_fs(old_fs);
+	if (iov != iovstack)
+		kfree(iov);
+	return ret;
+}
+
+#define RLIM_INFINITY32	0xffffffff
+#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
+
+struct rlimit32 {
+	int	rlim_cur;
+	int	rlim_max;
+};
+
+extern asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit *rlim);
+
+asmlinkage long
+sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim)
+{
+	struct rlimit r;
+	int ret;
+	mm_segment_t old_fs;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_getrlimit(resource, &r);
+	set_fs(old_fs);
+	if (!ret) {
+		if (verify_area(VERIFY_WRITE, rlim, sizeof(struct rlimit32)) ||
+		    __put_user(RESOURCE32(r.rlim_cur), &rlim->rlim_cur) ||
+		    __put_user(RESOURCE32(r.rlim_max), &rlim->rlim_max))
+			ret = -EFAULT;
+	}
+	return ret;
+}
+
+extern asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit *rlim);
+
+asmlinkage long
+sys32_old_getrlimit(unsigned int resource, struct rlimit32 *rlim)
+{
+	struct rlimit r;
+	int ret;
+	mm_segment_t old_fs;
+	
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_old_getrlimit(resource, &r);
+	set_fs(old_fs);
+	if (!ret) {
+		if (verify_area(VERIFY_WRITE, rlim, sizeof(struct rlimit32)) ||
+		    __put_user(r.rlim_cur, &rlim->rlim_cur) ||
+		    __put_user(r.rlim_max, &rlim->rlim_max))
+			ret = -EFAULT;
+	}
+	return ret;
+}
+
+extern asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim);
+
+asmlinkage long
+sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim)
+{
+	struct rlimit r;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+
+	if (resource >= RLIM_NLIMITS) return -EINVAL;	
+	if (verify_area(VERIFY_READ, rlim, sizeof(struct rlimit32)) ||
+	    __get_user (r.rlim_cur, &rlim->rlim_cur) ||
+	    __get_user (r.rlim_max, &rlim->rlim_max))
+		return -EFAULT;
+	if (r.rlim_cur == RLIM_INFINITY32)
+		r.rlim_cur = RLIM_INFINITY;
+	if (r.rlim_max == RLIM_INFINITY32)
+		r.rlim_max = RLIM_INFINITY;
+	set_fs (KERNEL_DS);
+	ret = sys_setrlimit(resource, &r);
+	set_fs (old_fs);
+	return ret;
+}
+
+/*
+ * sys_time() can be implemented in user-level using
+ * sys_gettimeofday().  IA64 did this but i386 Linux did not
+ * so we have to implement this system call here.
+ */
+asmlinkage long sys32_time(int * tloc)
+{
+	int i;
+
+	/* SMP: This is fairly trivial. We grab CURRENT_TIME and 
+	   stuff it to user space. No side effects */
+	i = CURRENT_TIME;
+	if (tloc) {
+		if (put_user(i,tloc))
+			i = -EFAULT;
+	}
+	return i;
+}
+
+struct rusage32 {
+        struct timeval32 ru_utime;
+        struct timeval32 ru_stime;
+        int    ru_maxrss;
+        int    ru_ixrss;
+        int    ru_idrss;
+        int    ru_isrss;
+        int    ru_minflt;
+        int    ru_majflt;
+        int    ru_nswap;
+        int    ru_inblock;
+        int    ru_oublock;
+        int    ru_msgsnd; 
+        int    ru_msgrcv; 
+        int    ru_nsignals;
+        int    ru_nvcsw;
+        int    ru_nivcsw;
+};
+
+static int
+put_rusage (struct rusage32 *ru, struct rusage *r)
+{
+	if (verify_area(VERIFY_WRITE, ru, sizeof(struct rusage32)) ||
+	    __put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec) ||
+	    __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec) ||
+	    __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec) ||
+	    __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec) ||
+	    __put_user (r->ru_maxrss, &ru->ru_maxrss) ||
+	    __put_user (r->ru_ixrss, &ru->ru_ixrss) ||
+	    __put_user (r->ru_idrss, &ru->ru_idrss) ||
+	    __put_user (r->ru_isrss, &ru->ru_isrss) ||
+	    __put_user (r->ru_minflt, &ru->ru_minflt) ||
+	    __put_user (r->ru_majflt, &ru->ru_majflt) ||
+	    __put_user (r->ru_nswap, &ru->ru_nswap) ||
+	    __put_user (r->ru_inblock, &ru->ru_inblock) ||
+	    __put_user (r->ru_oublock, &ru->ru_oublock) ||
+	    __put_user (r->ru_msgsnd, &ru->ru_msgsnd) ||
+	    __put_user (r->ru_msgrcv, &ru->ru_msgrcv) ||
+	    __put_user (r->ru_nsignals, &ru->ru_nsignals) ||
+	    __put_user (r->ru_nvcsw, &ru->ru_nvcsw) ||
+	    __put_user (r->ru_nivcsw, &ru->ru_nivcsw))
+		return -EFAULT;
+	return 0;
+}
+
+extern asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr,
+				int options, struct rusage * ru);
+
+asmlinkage long
+sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options,
+	    struct rusage32 *ru)
+{
+	if (!ru)
+		return sys_wait4(pid, stat_addr, options, NULL);
+	else {
+		struct rusage r;
+		int ret;
+		unsigned int status;
+		mm_segment_t old_fs = get_fs();
+		
+		set_fs (KERNEL_DS);
+		ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
+		set_fs (old_fs);
+		if (put_rusage (ru, &r)) return -EFAULT;
+		if (stat_addr && put_user (status, stat_addr))
+			return -EFAULT;
+		return ret;
+	}
+}
+
+asmlinkage long
+sys32_waitpid(__kernel_pid_t32 pid, unsigned int *stat_addr, int options)
+{
+	return sys32_wait4(pid, stat_addr, options, NULL);
+}
+
+
+extern asmlinkage long
+sys_getrusage(int who, struct rusage *ru);
+
+asmlinkage long
+sys32_getrusage(int who, struct rusage32 *ru)
+{
+	struct rusage r;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+		
+	set_fs (KERNEL_DS);
+	ret = sys_getrusage(who, &r);
+	set_fs (old_fs);
+	if (put_rusage (ru, &r)) return -EFAULT;
+	return ret;
+}
+
+struct tms32 {
+	__kernel_clock_t32 tms_utime;
+	__kernel_clock_t32 tms_stime;
+	__kernel_clock_t32 tms_cutime;
+	__kernel_clock_t32 tms_cstime;
+};
+
+extern int sys_times(struct tms *);
+                               
+asmlinkage long
+sys32_times(struct tms32 *tbuf)
+{
+	struct tms t;
+	long ret;
+	mm_segment_t old_fs = get_fs ();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_times(tbuf ? &t : NULL);
+	set_fs (old_fs);
+	if (tbuf) {
+		if (verify_area(VERIFY_WRITE, tbuf, sizeof(struct tms32)) ||
+		    __put_user (t.tms_utime, &tbuf->tms_utime) ||
+		    __put_user (t.tms_stime, &tbuf->tms_stime) ||
+		    __put_user (t.tms_cutime, &tbuf->tms_cutime) ||
+		    __put_user (t.tms_cstime, &tbuf->tms_cstime))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+
+static inline int get_flock(struct flock *kfl, struct flock32 *ufl)
+{
+	int err;
+	
+	err = get_user(kfl->l_type, &ufl->l_type);
+	err |= __get_user(kfl->l_whence, &ufl->l_whence);
+	err |= __get_user(kfl->l_start, &ufl->l_start);
+	err |= __get_user(kfl->l_len, &ufl->l_len);
+	err |= __get_user(kfl->l_pid, &ufl->l_pid);
+	return err;
+}
+
+static inline int put_flock(struct flock *kfl, struct flock32 *ufl)
+{
+	int err;
+	
+	err = __put_user(kfl->l_type, &ufl->l_type);
+	err |= __put_user(kfl->l_whence, &ufl->l_whence);
+	err |= __put_user(kfl->l_start, &ufl->l_start);
+	err |= __put_user(kfl->l_len, &ufl->l_len);
+	err |= __put_user(kfl->l_pid, &ufl->l_pid);
+	return err;
+}
+
+extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
+asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg);
+
+
+asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+	case F_GETLK:
+	case F_SETLK:
+	case F_SETLKW:
+		{
+			struct flock f;
+			mm_segment_t old_fs;
+			long ret;
+			
+			if (get_flock(&f, (struct flock32 *)arg))
+				return -EFAULT;
+			old_fs = get_fs(); set_fs (KERNEL_DS);
+			ret = sys_fcntl(fd, cmd, (unsigned long)&f);
+			set_fs (old_fs);
+			if (ret) return ret;
+			if (put_flock(&f, (struct flock32 *)arg))
+				return -EFAULT;
+			return 0;
+		}
+	case F_GETLK64: 
+	case F_SETLK64: 
+	case F_SETLKW64: 
+		return sys32_fcntl64(fd,cmd,arg); 
+
+	default:
+		return sys_fcntl(fd, cmd, (unsigned long)arg);
+	}
+}
+
+static inline int get_flock64(struct ia32_flock64 *fl32, struct flock *fl64)
+{
+	if (access_ok(fl32, sizeof(struct ia32_flock64), VERIFY_WRITE)) {
+		int ret = __get_user(fl64->l_type, &fl32->l_type); 
+		ret |= __get_user(fl64->l_whence, &fl32->l_whence);
+		ret |= __get_user(fl64->l_start, &fl32->l_start); 
+		ret |= __get_user(fl64->l_len, &fl32->l_len); 
+		ret |= __get_user(fl64->l_pid, &fl32->l_pid); 
+		return ret; 
+	}
+	return -EFAULT; 
+}
+
+static inline int put_flock64(struct ia32_flock64 *fl32, struct flock *fl64)
+{
+	if (access_ok(fl32, sizeof(struct ia32_flock64), VERIFY_WRITE)) {
+		int ret = __put_user(fl64->l_type, &fl32->l_type); 
+		ret |= __put_user(fl64->l_whence, &fl32->l_whence);
+		ret |= __put_user(fl64->l_start, &fl32->l_start); 
+		ret |= __put_user(fl64->l_len, &fl32->l_len); 
+		ret |= __put_user(fl64->l_pid, &fl32->l_pid); 
+		return ret; 
+	}
+	return -EFAULT; 
+}
+
+asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct flock fl64;  
+	mm_segment_t oldfs = get_fs(); 
+	int ret = 0; 
+	int oldcmd = cmd;
+	unsigned long oldarg = arg;
+
+	switch (cmd) {
+	case F_GETLK64: 
+		cmd = F_GETLK; 
+		goto cnv;
+	case F_SETLK64: 
+		cmd = F_SETLK; 
+		goto cnv; 
+	case F_SETLKW64:
+		cmd = F_SETLKW; 
+	cnv:
+		ret = get_flock64((struct ia32_flock64 *)arg, &fl64); 
+		arg = (unsigned long)&fl64; 
+		set_fs(KERNEL_DS); 
+		break; 
+	case F_GETLK:
+	case F_SETLK:
+	case F_SETLKW:
+		return sys32_fcntl(fd,cmd,arg); 
+	}
+	if (!ret)
+		ret = sys_fcntl(fd, cmd, arg);
+	set_fs(oldfs); 
+	if (oldcmd == F_GETLK64 && !ret)
+		ret = put_flock64((struct ia32_flock64 *)oldarg, &fl64); 
+	return ret; 
+}
+
+int sys32_ni_syscall(int call)
+{ 
+	printk(KERN_INFO "IA32 syscall %d from %s not implemented\n", call,
+	       current->comm);
+	return -ENOSYS;	       
+} 
+
+/* 32-bit timeval and related flotsam.  */
+
+extern asmlinkage long sys_utime(char * filename, struct utimbuf * times);
+
+struct utimbuf32 {
+	__kernel_time_t32 actime, modtime;
+};
+
+asmlinkage long
+sys32_utime(char * filename, struct utimbuf32 *times)
+{
+	struct utimbuf t;
+	mm_segment_t old_fs;
+	int ret;
+	char *filenam;
+	
+	if (!times)
+		return sys_utime(filename, NULL);
+	if (verify_area(VERIFY_READ, times, sizeof(struct utimbuf32)) ||
+	    __get_user (t.actime, &times->actime) ||
+	    __get_user (t.modtime, &times->modtime))
+		return -EFAULT;
+	filenam = getname (filename);
+	ret = PTR_ERR(filenam);
+	if (!IS_ERR(filenam)) {
+		old_fs = get_fs();
+		set_fs (KERNEL_DS); 
+		ret = sys_utime(filenam, &t);
+		set_fs (old_fs);
+		putname(filenam);
+	}
+	return ret;
+}
+
+extern asmlinkage long sys_sysfs(int option, unsigned long arg1,
+				unsigned long arg2);
+
+asmlinkage long
+sys32_sysfs(int option, u32 arg1, u32 arg2)
+{
+	return sys_sysfs(option, arg1, arg2);
+}
+
+extern asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
+				unsigned long new_flags, void *data);
+
+static char *badfs[] = {
+	"smbfs", "ncpfs", NULL
+}; 	
+
+static int checktype(char *user_type) 
+{ 
+	int err = 0; 
+	char **s,*kernel_type = getname(user_type); 
+	if (!kernel_type || IS_ERR(kernel_type)) 
+		return -EFAULT; 
+	for (s = badfs; *s; ++s) 
+		if (!strcmp(kernel_type, *s)) { 
+			printk(KERN_ERR "mount32: unsupported fs `%s' -- use 64bit mount\n", *s); 
+			err = -EINVAL; 
+			break;
+		} 	
+	putname(user_type); 
+	return err;
+} 
+
+asmlinkage long
+sys32_mount(char *dev_name, char *dir_name, char *type,
+	    unsigned long new_flags, u32 data)
+{
+	int err;
+	if(!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	err = checktype(type);
+	if (err)
+		return err;
+	return sys_mount(dev_name, dir_name, type, new_flags, (void *)AA(data));
+}
+
+struct sysinfo32 {
+        s32 uptime;
+        u32 loads[3];
+        u32 totalram;
+        u32 freeram;
+        u32 sharedram;
+        u32 bufferram;
+        u32 totalswap;
+        u32 freeswap;
+        unsigned short procs;
+        char _f[22];
+};
+
+extern asmlinkage long sys_sysinfo(struct sysinfo *info);
+
+asmlinkage long
+sys32_sysinfo(struct sysinfo32 *info)
+{
+	struct sysinfo s;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_sysinfo(&s);
+	set_fs (old_fs);
+	if (verify_area(VERIFY_WRITE, info, sizeof(struct sysinfo32)) ||
+	    __put_user (s.uptime, &info->uptime) ||
+	    __put_user (s.loads[0], &info->loads[0]) ||
+	    __put_user (s.loads[1], &info->loads[1]) ||
+	    __put_user (s.loads[2], &info->loads[2]) ||
+	    __put_user (s.totalram, &info->totalram) ||
+	    __put_user (s.freeram, &info->freeram) ||
+	    __put_user (s.sharedram, &info->sharedram) ||
+	    __put_user (s.bufferram, &info->bufferram) ||
+	    __put_user (s.totalswap, &info->totalswap) ||
+	    __put_user (s.freeswap, &info->freeswap) ||
+	    __put_user (s.procs, &info->procs))
+		return -EFAULT;
+	return 0;
+}
+                
+extern asmlinkage long sys_sched_rr_get_interval(pid_t pid,
+						struct timespec *interval);
+
+asmlinkage long
+sys32_sched_rr_get_interval(__kernel_pid_t32 pid, struct timespec32 *interval)
+{
+	struct timespec t;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_sched_rr_get_interval(pid, &t);
+	set_fs (old_fs);
+	if (verify_area(VERIFY_WRITE, interval, sizeof(struct timespec32)) ||
+	    __put_user (t.tv_sec, &interval->tv_sec) ||
+	    __put_user (t.tv_nsec, &interval->tv_nsec))
+		return -EFAULT;
+	return ret;
+}
+
+extern asmlinkage long sys_sigprocmask(int how, old_sigset_t *set,
+				      old_sigset_t *oset);
+
+asmlinkage long
+sys32_sigprocmask(int how, old_sigset32_t *set, old_sigset32_t *oset)
+{
+	old_sigset_t s;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	
+	if (set && get_user (s, set)) return -EFAULT;
+	set_fs (KERNEL_DS);
+	ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL);
+	set_fs (old_fs);
+	if (ret) return ret;
+	if (oset && put_user (s, oset)) return -EFAULT;
+	return 0;
+}
+
+extern asmlinkage long sys_sigpending(old_sigset_t *set);
+
+asmlinkage long
+sys32_sigpending(old_sigset32_t *set)
+{
+	old_sigset_t s;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+		
+	set_fs (KERNEL_DS);
+	ret = sys_sigpending(&s);
+	set_fs (old_fs);
+	if (put_user (s, set)) return -EFAULT;
+	return ret;
+}
+
+extern asmlinkage long sys_rt_sigpending(sigset_t *set, size_t sigsetsize);
+
+asmlinkage long
+sys32_rt_sigpending(sigset32_t *set, __kernel_size_t32 sigsetsize)
+{
+	sigset_t s;
+	sigset32_t s32;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+		
+	set_fs (KERNEL_DS);
+	ret = sys_rt_sigpending(&s, sigsetsize);
+	set_fs (old_fs);
+	if (!ret) {
+		switch (_NSIG_WORDS) {
+		case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
+		case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
+		case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
+		case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
+		}
+		if (copy_to_user (set, &s32, sizeof(sigset32_t)))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+siginfo_t32 *
+siginfo64to32(siginfo_t32 *d, siginfo_t *s)
+{
+	memset (d, 0, sizeof(siginfo_t32));
+	d->si_signo = s->si_signo;
+	d->si_errno = s->si_errno;
+	d->si_code = s->si_code;
+	if (s->si_signo >= SIGRTMIN) {
+		d->si_pid = s->si_pid;
+		d->si_uid = s->si_uid;
+		/* XXX: Ouch, how to find this out??? */
+		d->si_int = s->si_int;
+	} else switch (s->si_signo) {
+	/* XXX: What about POSIX1.b timers */
+	case SIGCHLD:
+		d->si_pid = s->si_pid;
+		d->si_status = s->si_status;
+		d->si_utime = s->si_utime;
+		d->si_stime = s->si_stime;
+		break;
+	case SIGSEGV:
+	case SIGBUS:
+	case SIGFPE:
+	case SIGILL:
+		d->si_addr = (long)(s->si_addr);
+//		d->si_trapno = s->si_trapno;
+		break;
+	case SIGPOLL:
+		d->si_band = s->si_band;
+		d->si_fd = s->si_fd;
+		break;
+	default:
+		d->si_pid = s->si_pid;
+		d->si_uid = s->si_uid;
+		break;
+	}
+	return d;
+}
+
+siginfo_t *
+siginfo32to64(siginfo_t *d, siginfo_t32 *s)
+{
+	d->si_signo = s->si_signo;
+	d->si_errno = s->si_errno;
+	d->si_code = s->si_code;
+	if (s->si_signo >= SIGRTMIN) {
+		d->si_pid = s->si_pid;
+		d->si_uid = s->si_uid;
+		/* XXX: Ouch, how to find this out??? */
+		d->si_int = s->si_int;
+	} else switch (s->si_signo) {
+	/* XXX: What about POSIX1.b timers */
+	case SIGCHLD:
+		d->si_pid = s->si_pid;
+		d->si_status = s->si_status;
+		d->si_utime = s->si_utime;
+		d->si_stime = s->si_stime;
+		break;
+	case SIGSEGV:
+	case SIGBUS:
+	case SIGFPE:
+	case SIGILL:
+		d->si_addr = (void *)A(s->si_addr);
+//		d->si_trapno = s->si_trapno;
+		break;
+	case SIGPOLL:
+		d->si_band = s->si_band;
+		d->si_fd = s->si_fd;
+		break;
+	default:
+		d->si_pid = s->si_pid;
+		d->si_uid = s->si_uid;
+		break;
+	}
+	return d;
+}
+
+extern asmlinkage long
+sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo,
+		    const struct timespec *uts, size_t sigsetsize);
+
+asmlinkage long
+sys32_rt_sigtimedwait(sigset32_t *uthese, siginfo_t32 *uinfo,
+		      struct timespec32 *uts, __kernel_size_t32 sigsetsize)
+{
+	sigset_t s;
+	sigset32_t s32;
+	struct timespec t;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	siginfo_t info;
+	siginfo_t32 info32;
+		
+	if (copy_from_user (&s32, uthese, sizeof(sigset32_t)))
+		return -EFAULT;
+	switch (_NSIG_WORDS) {
+	case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
+	case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
+	case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
+	case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
+	}
+	if (uts) {
+		if (verify_area(VERIFY_READ, uts, sizeof(struct timespec32)) ||
+		    __get_user (t.tv_sec, &uts->tv_sec) ||
+		    __get_user (t.tv_nsec, &uts->tv_nsec))
+			return -EFAULT;
+	}
+	set_fs (KERNEL_DS);
+	ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize);
+	set_fs (old_fs);
+	if (ret >= 0 && uinfo) {
+		if (copy_to_user (uinfo, siginfo64to32(&info32, &info),
+				  sizeof(siginfo_t32)))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+extern asmlinkage long
+sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo);
+
+asmlinkage long
+sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo)
+{
+	siginfo_t info;
+	siginfo_t32 info32;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	
+	if (copy_from_user (&info32, uinfo, sizeof(siginfo_t32)))
+		return -EFAULT;
+	/* XXX: Is this correct? */
+	siginfo32to64(&info, &info32);
+	set_fs (KERNEL_DS);
+	ret = sys_rt_sigqueueinfo(pid, sig, &info);
+	set_fs (old_fs);
+	return ret;
+}
+
+extern void check_pending(int signum);
+
+asmlinkage long sys_utimes(char *, struct timeval *);
+
+asmlinkage long
+sys32_utimes(char *filename, struct timeval32 *tvs)
+{
+	char *kfilename;
+	struct timeval ktvs[2];
+	mm_segment_t old_fs;
+	int ret;
+
+	kfilename = getname(filename);
+	ret = PTR_ERR(kfilename);
+	if (!IS_ERR(kfilename)) {
+		if (tvs) {
+			if (get_tv32(&ktvs[0], tvs) ||
+			    get_tv32(&ktvs[1], 1+tvs))
+				return -EFAULT;
+		}
+
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		ret = sys_utimes(kfilename, &ktvs[0]);
+		set_fs(old_fs);
+
+		putname(kfilename);
+	}
+	return ret;
+}
+
+/* These are here just in case some old ia32 binary calls it. */
+asmlinkage long
+sys32_pause(void)
+{
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	return -ERESTARTNOHAND;
+}
+
+
+struct sysctl_ia32 {
+	unsigned int	name;
+	int		nlen;
+	unsigned int	oldval;
+	unsigned int	oldlenp;
+	unsigned int	newval;
+	unsigned int	newlen;
+	unsigned int	__unused[4];
+};
+
+
+asmlinkage long
+sys32_sysctl(struct sysctl_ia32 *args32)
+{
+#ifndef CONFIG_SYSCTL
+	return -ENOSYS; 
+#else
+	struct sysctl_ia32 a32;
+	mm_segment_t old_fs = get_fs ();
+	void *oldvalp, *newvalp;
+	size_t oldlen;
+	int *namep;
+	long ret;
+	extern int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
+		     void *newval, size_t newlen);
+
+
+	if (copy_from_user(&a32, args32, sizeof (a32)))
+		return -EFAULT;
+
+	/*
+	 * We need to pre-validate these because we have to disable address checking
+	 * before calling do_sysctl() because of OLDLEN but we can't run the risk of the
+	 * user specifying bad addresses here.  Well, since we're dealing with 32 bit
+	 * addresses, we KNOW that access_ok() will always succeed, so this is an
+	 * expensive NOP, but so what...
+	 */
+	namep = (int *) A(a32.name);
+	oldvalp = (void *) A(a32.oldval);
+	newvalp = (void *) A(a32.newval);
+
+	if ((oldvalp && get_user(oldlen, (int *) A(a32.oldlenp)))
+	    || !access_ok(VERIFY_WRITE, namep, 0)
+	    || !access_ok(VERIFY_WRITE, oldvalp, 0)
+	    || !access_ok(VERIFY_WRITE, newvalp, 0))
+		return -EFAULT;
+
+	set_fs(KERNEL_DS);
+	lock_kernel();
+	ret = do_sysctl(namep, a32.nlen, oldvalp, &oldlen, newvalp, (size_t) a32.newlen);
+	unlock_kernel();
+	set_fs(old_fs);
+
+	if (oldvalp && put_user (oldlen, (int *) A(a32.oldlenp)))
+		return -EFAULT;
+
+	return ret;
+#endif
+}
+
+extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
+				    size_t count, loff_t pos);
+
+extern asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
+				     size_t count, loff_t pos);
+
+typedef __kernel_ssize_t32 ssize_t32;
+
+
+/* warning: next two assume little endian */ 
+asmlinkage ssize_t32
+sys32_pread(unsigned int fd, char *ubuf, __kernel_size_t32 count,
+	    u32 poslo, u32 poshi)
+{
+	return sys_pread(fd, ubuf, count,
+			 ((loff_t)AA(poshi) << 32) | AA(poslo));
+}
+
+asmlinkage ssize_t32
+sys32_pwrite(unsigned int fd, char *ubuf, __kernel_size_t32 count,
+	     u32 poslo, u32 poshi)
+{
+	return sys_pwrite(fd, ubuf, count,
+			  ((loff_t)AA(poshi) << 32) | AA(poslo));
+}
+
+
+extern asmlinkage long sys_personality(unsigned long);
+
+asmlinkage long
+sys32_personality(unsigned long personality)
+{
+	int ret;
+	if (personality(current->personality) == PER_LINUX32 && 
+		personality == PER_LINUX)
+		personality = PER_LINUX32;
+	ret = sys_personality(personality);
+	if (ret == PER_LINUX32)
+		ret = PER_LINUX;
+	return ret;
+}
+
+extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset,
+				       size_t count); 
+
+asmlinkage long
+sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s32 count)
+{
+	mm_segment_t old_fs = get_fs();
+	int ret;
+	off_t of;
+	
+	if (offset && get_user(of, offset))
+		return -EFAULT;
+		
+	set_fs(KERNEL_DS);
+	ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
+	set_fs(old_fs);
+	
+	if (!ret && offset && put_user(of, offset))
+		return -EFAULT;
+		
+	return ret;
+}
+
+/* Handle adjtimex compatability. */
+
+struct timex32 {
+	u32 modes;
+	s32 offset, freq, maxerror, esterror;
+	s32 status, constant, precision, tolerance;
+	struct timeval32 time;
+	s32 tick;
+	s32 ppsfreq, jitter, shift, stabil;
+	s32 jitcnt, calcnt, errcnt, stbcnt;
+	s32  :32; s32  :32; s32  :32; s32  :32;
+	s32  :32; s32  :32; s32  :32; s32  :32;
+	s32  :32; s32  :32; s32  :32; s32  :32;
+};
+
+extern int do_adjtimex(struct timex *);
+
+asmlinkage long
+sys32_adjtimex(struct timex32 *utp)
+{
+	struct timex txc;
+	int ret;
+
+	memset(&txc, 0, sizeof(struct timex));
+
+	if(verify_area(VERIFY_READ, utp, sizeof(struct timex32)) ||
+	   __get_user(txc.modes, &utp->modes) ||
+	   __get_user(txc.offset, &utp->offset) ||
+	   __get_user(txc.freq, &utp->freq) ||
+	   __get_user(txc.maxerror, &utp->maxerror) ||
+	   __get_user(txc.esterror, &utp->esterror) ||
+	   __get_user(txc.status, &utp->status) ||
+	   __get_user(txc.constant, &utp->constant) ||
+	   __get_user(txc.precision, &utp->precision) ||
+	   __get_user(txc.tolerance, &utp->tolerance) ||
+	   __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
+	   __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
+	   __get_user(txc.tick, &utp->tick) ||
+	   __get_user(txc.ppsfreq, &utp->ppsfreq) ||
+	   __get_user(txc.jitter, &utp->jitter) ||
+	   __get_user(txc.shift, &utp->shift) ||
+	   __get_user(txc.stabil, &utp->stabil) ||
+	   __get_user(txc.jitcnt, &utp->jitcnt) ||
+	   __get_user(txc.calcnt, &utp->calcnt) ||
+	   __get_user(txc.errcnt, &utp->errcnt) ||
+	   __get_user(txc.stbcnt, &utp->stbcnt))
+		return -EFAULT;
+
+	ret = do_adjtimex(&txc);
+
+	if(verify_area(VERIFY_WRITE, utp, sizeof(struct timex32)) ||
+	   __put_user(txc.modes, &utp->modes) ||
+	   __put_user(txc.offset, &utp->offset) ||
+	   __put_user(txc.freq, &utp->freq) ||
+	   __put_user(txc.maxerror, &utp->maxerror) ||
+	   __put_user(txc.esterror, &utp->esterror) ||
+	   __put_user(txc.status, &utp->status) ||
+	   __put_user(txc.constant, &utp->constant) ||
+	   __put_user(txc.precision, &utp->precision) ||
+	   __put_user(txc.tolerance, &utp->tolerance) ||
+	   __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
+	   __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
+	   __put_user(txc.tick, &utp->tick) ||
+	   __put_user(txc.ppsfreq, &utp->ppsfreq) ||
+	   __put_user(txc.jitter, &utp->jitter) ||
+	   __put_user(txc.shift, &utp->shift) ||
+	   __put_user(txc.stabil, &utp->stabil) ||
+	   __put_user(txc.jitcnt, &utp->jitcnt) ||
+	   __put_user(txc.calcnt, &utp->calcnt) ||
+	   __put_user(txc.errcnt, &utp->errcnt) ||
+	   __put_user(txc.stbcnt, &utp->stbcnt))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+
+/* common code for old and new mmaps */
+static inline long do_mmap2(
+	unsigned long addr, unsigned long len,
+	unsigned long prot, unsigned long flags,
+	unsigned long fd, unsigned long pgoff)
+{
+	int error = -EBADF;
+	struct file * file = NULL;
+
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	if (!(flags & MAP_ANONYMOUS)) {
+		file = fget(fd);
+		if (!file)
+			goto out;
+	}
+
+	down_write(&current->mm->mmap_sem);
+	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+	up_write(&current->mm->mmap_sem);
+
+	if (file)
+		fput(file);
+out:
+	return error;
+}
+
+asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
+	unsigned long prot, unsigned long flags,
+	unsigned long fd, unsigned long pgoff)
+{
+	return do_mmap2(addr, len, prot, flags, fd, pgoff);
+}
+
+
+asmlinkage long sys32_olduname(struct oldold_utsname * name)
+{
+	int error;
+
+	if (!name)
+		return -EFAULT;
+	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+		return -EFAULT;
+  
+  	down_read(&uts_sem);
+	
+	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+	 __put_user(0,name->sysname+__OLD_UTS_LEN);
+	 __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+	 __put_user(0,name->nodename+__OLD_UTS_LEN);
+	 __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+	 __put_user(0,name->release+__OLD_UTS_LEN);
+	 __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+	 __put_user(0,name->version+__OLD_UTS_LEN);
+	 { 
+		 char *arch = (personality(current->personality) == PER_LINUX32)
+			 ? "i686" : "x86_64"; 
+		 
+		 __copy_to_user(&name->machine,arch,strlen(arch)+1);
+	 }
+	
+	 up_read(&uts_sem);
+	 
+	 error = error ? -EFAULT : 0;
+	 
+	 return error;
+}
+
+asmlinkage long sys32_uname(struct old_utsname * name)
+{
+	int err;
+	down_read(&uts_sem);
+	err=copy_to_user(name, &system_utsname, sizeof (*name));
+	up_read(&uts_sem);
+	if (personality(current->personality) == PER_LINUX32)
+		err = copy_to_user(name->machine, "i686", 5);
+	return err?-EFAULT:0;
+}
+
+extern int sys_ustat(dev_t, struct ustat *);
+
+int sys32_ustat(dev_t dev, struct ustat32 *u32p)
+{
+	struct ustat u;
+	mm_segment_t seg;
+	int ret;
+	
+	seg = get_fs(); 
+	set_fs(KERNEL_DS); 
+	ret = sys_ustat(dev,&u); 
+	set_fs(seg);
+	if (ret >= 0) { 
+		if (!access_ok(VERIFY_WRITE,u32p,sizeof(struct ustat32)) || 
+		    __put_user((__u32) u.f_tfree, &u32p->f_tfree) ||
+		    __put_user((__u32) u.f_tinode, &u32p->f_tfree) ||
+		    __copy_to_user(&u32p->f_fname, u.f_fname, sizeof(u.f_fname)) ||
+		    __copy_to_user(&u32p->f_fpack, u.f_fpack, sizeof(u.f_fpack)))
+			ret = -EFAULT;
+	}
+	return ret;
+} 
+
+static int nargs(u32 src, char **dst) 
+{ 
+	int cnt;
+	u32 val; 
+
+	cnt = 0; 
+	do { 		
+		int ret = get_user(val, (__u32 *)(u64)src); 
+		if (ret)
+			return ret;
+		if (dst)
+			dst[cnt] = (char *)(u64)val; 
+		cnt++;
+		src += 4;
+		if (cnt >= (MAX_ARG_PAGES*PAGE_SIZE)/sizeof(void*))
+			return -E2BIG; 
+	} while(val); 
+	if (dst)
+		dst[cnt-1] = 0; 
+	return cnt; 
+} 
+
+int sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs)
+{ 
+	mm_segment_t oldseg; 
+	char **buf; 
+	int na,ne;
+	int ret;
+	unsigned sz; 
+	
+	na = nargs(argv, NULL); 
+	if (na < 0) 
+		return -EFAULT; 
+	ne = nargs(envp, NULL); 
+	if (ne < 0) 
+		return -EFAULT; 
+
+	sz = (na+ne)*sizeof(void *); 
+	if (sz > PAGE_SIZE) 
+		buf = vmalloc(sz); 
+	else
+		buf = kmalloc(sz, GFP_KERNEL); 
+	if (!buf)
+		return -ENOMEM; 
+	
+	ret = nargs(argv, buf);
+	if (ret < 0)
+		goto free;
+
+	ret = nargs(envp, buf + na); 
+	if (ret < 0)
+		goto free; 
+
+	name = getname(name); 
+	ret = PTR_ERR(name); 
+	if (IS_ERR(name))
+		goto free; 
+
+	oldseg = get_fs(); 
+	set_fs(KERNEL_DS);
+	ret = do_execve(name, buf, buf+na, &regs);  
+	set_fs(oldseg); 
+
+	if (ret == 0)
+		current->ptrace &= ~PT_DTRACE;
+
+	putname(name);
+ 
+free:
+	if (sz > PAGE_SIZE)
+		vfree(buf); 
+	else
+		kfree(buf);
+	return ret; 
+} 
+
+asmlinkage int sys32_fork(struct pt_regs regs)
+{
+	return do_fork(SIGCHLD, regs.rsp, &regs, 0);
+}
+
+asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs)
+{
+	if (!newsp)
+		newsp = regs.rsp;
+	return do_fork(clone_flags, newsp, &regs, 0);
+}
+
+/*
+ * This is trivial, and on the face of it looks like it
+ * could equally well be done in user mode.
+ *
+ * Not so, for quite unobvious reasons - register pressure.
+ * In user mode vfork() cannot have a stack frame, and if
+ * done by calling the "clone()" system call directly, you
+ * do not have enough call-clobbered registers to hold all
+ * the information you need.
+ */
+asmlinkage int sys32_vfork(struct pt_regs regs)
+{
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0);
+}
+
+/*
+ * Some system calls that need sign extended arguments. This could be done by a generic wrapper.
+ */ 
+
+extern off_t sys_lseek (unsigned int fd, off_t offset, unsigned int origin);
+
+int sys32_lseek (unsigned int fd, int offset, unsigned int whence)
+{
+	return sys_lseek(fd, offset, whence);
+}
+
+extern int sys_kill(pid_t pid, int sig); 
+
+int sys32_kill(int pid, int sig)
+{
+	return sys_kill(pid, sig);
+}
+ 
+
+#if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
+/* Stuff for NFS server syscalls... */
+struct nfsctl_svc32 {
+	u16			svc32_port;
+	s32			svc32_nthreads;
+};
+
+struct nfsctl_client32 {
+	s8			cl32_ident[NFSCLNT_IDMAX+1];
+	s32			cl32_naddr;
+	struct in_addr		cl32_addrlist[NFSCLNT_ADDRMAX];
+	s32			cl32_fhkeytype;
+	s32			cl32_fhkeylen;
+	u8			cl32_fhkey[NFSCLNT_KEYMAX];
+};
+
+struct nfsctl_export32 {
+	s8			ex32_client[NFSCLNT_IDMAX+1];
+	s8			ex32_path[NFS_MAXPATHLEN+1];
+	__kernel_dev_t32	ex32_dev;
+	__kernel_ino_t32	ex32_ino;
+	s32			ex32_flags;
+	__kernel_uid_t32	ex32_anon_uid;
+	__kernel_gid_t32	ex32_anon_gid;
+};
+
+struct nfsctl_uidmap32 {
+	u32			ug32_ident;   /* char * */
+	__kernel_uid_t32	ug32_uidbase;
+	s32			ug32_uidlen;
+	u32			ug32_udimap;  /* uid_t * */
+	__kernel_uid_t32	ug32_gidbase;
+	s32			ug32_gidlen;
+	u32			ug32_gdimap;  /* gid_t * */
+};
+
+struct nfsctl_fhparm32 {
+	struct sockaddr		gf32_addr;
+	__kernel_dev_t32	gf32_dev;
+	__kernel_ino_t32	gf32_ino;
+	s32			gf32_version;
+};
+
+struct nfsctl_fdparm32 {
+	struct sockaddr		gd32_addr;
+	s8			gd32_path[NFS_MAXPATHLEN+1];
+	s32			gd32_version;
+};
+
+struct nfsctl_fsparm32 {
+	struct sockaddr		gd32_addr;
+	s8			gd32_path[NFS_MAXPATHLEN+1];
+	s32			gd32_maxlen;
+};
+
+struct nfsctl_arg32 {
+	s32			ca32_version;	/* safeguard */
+	union {
+		struct nfsctl_svc32	u32_svc;
+		struct nfsctl_client32	u32_client;
+		struct nfsctl_export32	u32_export;
+		struct nfsctl_uidmap32	u32_umap;
+		struct nfsctl_fhparm32	u32_getfh;
+		struct nfsctl_fdparm32	u32_getfd;
+		struct nfsctl_fsparm32	u32_getfs;
+	} u;
+#define ca32_svc	u.u32_svc
+#define ca32_client	u.u32_client
+#define ca32_export	u.u32_export
+#define ca32_umap	u.u32_umap
+#define ca32_getfh	u.u32_getfh
+#define ca32_getfd	u.u32_getfd
+#define ca32_getfs	u.u32_getfs
+#define ca32_authd	u.u32_authd
+};
+
+union nfsctl_res32 {
+	__u8			cr32_getfh[NFS_FHSIZE];
+	struct knfsd_fh		cr32_getfs;
+};
+
+static int nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	int err;
+	
+	err = get_user(karg->ca_version, &arg32->ca32_version);
+	err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port);
+	err |= __get_user(karg->ca_svc.svc_nthreads, &arg32->ca32_svc.svc32_nthreads);
+	return err;
+}
+
+static int nfs_clnt32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	int err;
+	
+	err = get_user(karg->ca_version, &arg32->ca32_version);
+	err |= copy_from_user(&karg->ca_client.cl_ident[0],
+			  &arg32->ca32_client.cl32_ident[0],
+			  NFSCLNT_IDMAX);
+	err |= __get_user(karg->ca_client.cl_naddr, &arg32->ca32_client.cl32_naddr);
+	err |= copy_from_user(&karg->ca_client.cl_addrlist[0],
+			  &arg32->ca32_client.cl32_addrlist[0],
+			  (sizeof(struct in_addr) * NFSCLNT_ADDRMAX));
+	err |= __get_user(karg->ca_client.cl_fhkeytype,
+		      &arg32->ca32_client.cl32_fhkeytype);
+	err |= __get_user(karg->ca_client.cl_fhkeylen,
+		      &arg32->ca32_client.cl32_fhkeylen);
+	err |= copy_from_user(&karg->ca_client.cl_fhkey[0],
+			  &arg32->ca32_client.cl32_fhkey[0],
+			  NFSCLNT_KEYMAX);
+	return err;
+}
+
+static int nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	int err;
+	
+	err = get_user(karg->ca_version, &arg32->ca32_version);
+	err |= copy_from_user(&karg->ca_export.ex_client[0],
+			  &arg32->ca32_export.ex32_client[0],
+			  NFSCLNT_IDMAX);
+	err |= copy_from_user(&karg->ca_export.ex_path[0],
+			  &arg32->ca32_export.ex32_path[0],
+			  NFS_MAXPATHLEN);
+	err |= __get_user(karg->ca_export.ex_dev,
+		      &arg32->ca32_export.ex32_dev);
+	err |= __get_user(karg->ca_export.ex_ino,
+		      &arg32->ca32_export.ex32_ino);
+	err |= __get_user(karg->ca_export.ex_flags,
+		      &arg32->ca32_export.ex32_flags);
+	err |= __get_user(karg->ca_export.ex_anon_uid,
+		      &arg32->ca32_export.ex32_anon_uid);
+	err |= __get_user(karg->ca_export.ex_anon_gid,
+		      &arg32->ca32_export.ex32_anon_gid);
+	karg->ca_export.ex_anon_uid = high2lowuid(karg->ca_export.ex_anon_uid);
+	karg->ca_export.ex_anon_gid = high2lowgid(karg->ca_export.ex_anon_gid);
+	return err;
+}
+
+static int nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	u32 uaddr;
+	int i;
+	int err;
+
+	memset(karg, 0, sizeof(*karg));
+	if(get_user(karg->ca_version, &arg32->ca32_version))
+		return -EFAULT;
+	karg->ca_umap.ug_ident = (char *)get_free_page(GFP_USER);
+	if(!karg->ca_umap.ug_ident)
+		return -ENOMEM;
+	err = get_user(uaddr, &arg32->ca32_umap.ug32_ident);
+	if(strncpy_from_user(karg->ca_umap.ug_ident,
+			     (char *)A(uaddr), PAGE_SIZE) <= 0)
+		return -EFAULT;
+	err |= __get_user(karg->ca_umap.ug_uidbase,
+		      &arg32->ca32_umap.ug32_uidbase);
+	err |= __get_user(karg->ca_umap.ug_uidlen,
+		      &arg32->ca32_umap.ug32_uidlen);
+	err |= __get_user(uaddr, &arg32->ca32_umap.ug32_udimap);
+	if (err)
+		return -EFAULT;
+	karg->ca_umap.ug_udimap = kmalloc((sizeof(uid_t) * karg->ca_umap.ug_uidlen),
+					  GFP_USER);
+	if(!karg->ca_umap.ug_udimap)
+		return -ENOMEM;
+	for(i = 0; i < karg->ca_umap.ug_uidlen; i++)
+		err |= __get_user(karg->ca_umap.ug_udimap[i],
+			      &(((__kernel_uid_t32 *)A(uaddr))[i]));
+	err |= __get_user(karg->ca_umap.ug_gidbase,
+		      &arg32->ca32_umap.ug32_gidbase);
+	err |= __get_user(karg->ca_umap.ug_uidlen,
+		      &arg32->ca32_umap.ug32_gidlen);
+	err |= __get_user(uaddr, &arg32->ca32_umap.ug32_gdimap);
+	if (err)
+		return -EFAULT;
+	karg->ca_umap.ug_gdimap = kmalloc((sizeof(gid_t) * karg->ca_umap.ug_uidlen),
+					  GFP_USER);
+	if(!karg->ca_umap.ug_gdimap)
+		return -ENOMEM;
+	for(i = 0; i < karg->ca_umap.ug_gidlen; i++)
+		err |= __get_user(karg->ca_umap.ug_gdimap[i],
+			      &(((__kernel_gid_t32 *)A(uaddr))[i]));
+
+	return err;
+}
+
+static int nfs_getfh32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	int err;
+	
+	err = get_user(karg->ca_version, &arg32->ca32_version);
+	err |= copy_from_user(&karg->ca_getfh.gf_addr,
+			  &arg32->ca32_getfh.gf32_addr,
+			  (sizeof(struct sockaddr)));
+	err |= __get_user(karg->ca_getfh.gf_dev,
+		      &arg32->ca32_getfh.gf32_dev);
+	err |= __get_user(karg->ca_getfh.gf_ino,
+		      &arg32->ca32_getfh.gf32_ino);
+	err |= __get_user(karg->ca_getfh.gf_version,
+		      &arg32->ca32_getfh.gf32_version);
+	return err;
+}
+
+static int nfs_getfd32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	int err;
+	
+	err = get_user(karg->ca_version, &arg32->ca32_version);
+	err |= copy_from_user(&karg->ca_getfd.gd_addr,
+			  &arg32->ca32_getfd.gd32_addr,
+			  (sizeof(struct sockaddr)));
+	err |= copy_from_user(&karg->ca_getfd.gd_path,
+			  &arg32->ca32_getfd.gd32_path,
+			  (NFS_MAXPATHLEN+1));
+	err |= get_user(karg->ca_getfd.gd_version,
+		      &arg32->ca32_getfd.gd32_version);
+	return err;
+}
+
+static int nfs_getfs32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	int err;
+	
+	err = get_user(karg->ca_version, &arg32->ca32_version);
+	err |= copy_from_user(&karg->ca_getfs.gd_addr,
+			  &arg32->ca32_getfs.gd32_addr,
+			  (sizeof(struct sockaddr)));
+	err |= copy_from_user(&karg->ca_getfs.gd_path,
+			  &arg32->ca32_getfs.gd32_path,
+			  (NFS_MAXPATHLEN+1));
+	err |= get_user(karg->ca_getfs.gd_maxlen,
+		      &arg32->ca32_getfs.gd32_maxlen);
+	return err;
+}
+
+/* This really doesn't need translations, we are only passing
+ * back a union which contains opaque nfs file handle data.
+ */
+static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
+{
+	return copy_to_user(res32, kres, sizeof(*res32));
+}
+
+int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
+{
+	struct nfsctl_arg *karg = NULL;
+	union nfsctl_res *kres = NULL;
+	mm_segment_t oldfs;
+	int err;
+
+	karg = kmalloc(sizeof(*karg), GFP_USER);
+	if(!karg)
+		return -ENOMEM;
+	if(res32) {
+		kres = kmalloc(sizeof(*kres), GFP_USER);
+		if(!kres) {
+			kfree(karg);
+			return -ENOMEM;
+		}
+	}
+	switch(cmd) {
+	case NFSCTL_SVC:
+		err = nfs_svc32_trans(karg, arg32);
+		break;
+	case NFSCTL_ADDCLIENT:
+		err = nfs_clnt32_trans(karg, arg32);
+		break;
+	case NFSCTL_DELCLIENT:
+		err = nfs_clnt32_trans(karg, arg32);
+		break;
+	case NFSCTL_EXPORT:
+	case NFSCTL_UNEXPORT:
+		err = nfs_exp32_trans(karg, arg32);
+		break;
+	/* This one is unimplemented, be we're ready for it. */
+	case NFSCTL_UGIDUPDATE:
+		err = nfs_uud32_trans(karg, arg32);
+		break;
+	case NFSCTL_GETFH:
+		err = nfs_getfh32_trans(karg, arg32);
+		break;
+	case NFSCTL_GETFD:
+		err = nfs_getfd32_trans(karg, arg32);
+		break;
+	case NFSCTL_GETFS:
+		err = nfs_getfs32_trans(karg, arg32);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+	if(err)
+		goto done;
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_nfsservctl(cmd, karg, kres);
+	set_fs(oldfs);
+
+	if (err)
+		goto done;
+
+	if((cmd == NFSCTL_GETFH) ||
+	   (cmd == NFSCTL_GETFD) ||
+	   (cmd == NFSCTL_GETFS))
+		err = nfs_getfh32_res_trans(kres, res32);
+
+done:
+	if(karg) {
+		if(cmd == NFSCTL_UGIDUPDATE) {
+			if(karg->ca_umap.ug_ident)
+				kfree(karg->ca_umap.ug_ident);
+			if(karg->ca_umap.ug_udimap)
+				kfree(karg->ca_umap.ug_udimap);
+			if(karg->ca_umap.ug_gdimap)
+				kfree(karg->ca_umap.ug_gdimap);
+		}
+		kfree(karg);
+	}
+	if(kres)
+		kfree(kres);
+	return err;
+}
+#else /* !NFSD */
+extern asmlinkage long sys_ni_syscall(void);
+int asmlinkage sys32_nfsservctl(int cmd, void *notused, void *notused2)
+{
+	return sys_ni_syscall();
+}
+#endif
+
+int sys32_module_warning(void)
+{ 
+	static long warn_time = -(60*HZ); 
+	if (time_before(warn_time + 60*HZ,jiffies) && strcmp(current->comm,"klogd")) { 
+		printk(KERN_INFO "%s: 32bit modutils not supported on 64bit kernel\n",
+		       current->comm);
+		warn_time = jiffies;
+	} 
+	return -ENOSYS ;
+} 
+
+struct exec_domain ia32_exec_domain = { 
+	name: "linux/x86",
+	pers_low: PER_LINUX32,
+	pers_high: PER_LINUX32,
+};      
+
+static int __init ia32_init (void)
+{
+	printk("IA32 emulation $Id: sys_ia32.c,v 1.42 2002/09/17 15:23:41 ak Exp $\n");  
+	ia32_exec_domain.signal_map = default_exec_domain.signal_map;
+	ia32_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
+	register_exec_domain(&ia32_exec_domain);
+	return 0;
+}
+
+__initcall(ia32_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/Makefile linux-2.4.20/arch/x86_64/kernel/Makefile
--- linux-2.4.19/arch/x86_64/kernel/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/Makefile	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,42 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.S.o:
+	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
+
+all: kernel.o head.o head64.o init_task.o
+
+O_TARGET := kernel.o
+
+
+export-objs     := mtrr.o msr.o cpuid.o x8664_ksyms.o pci-gart.o
+
+obj-y	:= process.o semaphore.o signal.o entry.o traps.o irq.o \
+		ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_x86_64.o \
+		pci-dma.o x8664_ksyms.o i387.o syscall.o vsyscall.o \
+		setup64.o acpitable.o e820.o
+
+ifdef CONFIG_PCI
+obj-y			+= pci-x86_64.o
+obj-y			+= pci-pc.o pci-irq.o
+endif
+
+obj-$(CONFIG_MTRR)	+= mtrr.o
+obj-$(CONFIG_X86_MSR)	+= msr.o
+obj-$(CONFIG_X86_CPUID)	+= cpuid.o
+obj-$(CONFIG_SMP)	+= smp.o smpboot.o trampoline.o
+obj-$(CONFIG_X86_LOCAL_APIC)	+= apic.o  nmi.o
+obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o mpparse.o
+obj-$(CONFIG_EARLY_PRINTK) +=  early_printk.o
+obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o
+obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o
+obj-$(CONFIG_MCE) += bluesmoke.o
+
+include $(TOPDIR)/Rules.make
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/acpitable.c linux-2.4.20/arch/x86_64/kernel/acpitable.c
--- linux-2.4.19/arch/x86_64/kernel/acpitable.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/acpitable.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,304 @@
+/*
+ *  acpitable.c - x86-64-specific ACPI (1.0 & 2.0) boot-time initialization
+ *
+ *  Copyright (C) 1999 Andrew Henroid
+ *  Copyright (C) 2001 Richard Schaal
+ *  Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ *  Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com>
+ *  Copyright (C) 2001 Arjan van de Ven <arjanv@redhat.com>
+ *  Copyright (C) 2002 Vojtech Pavlik <vojtech@suse.cz>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <asm/mpspec.h>
+#include <asm/io.h>
+#include <asm/apic.h>
+#include <asm/apicdef.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/fixmap.h>
+
+#include "acpitable.h"
+
+static acpi_table_handler acpi_boot_ops[ACPI_TABLE_COUNT];
+
+extern unsigned long end_pfn;
+static inline int bad_ptr(void *p) 
+{ 
+	if ((unsigned long)p  >> PAGE_SHIFT >= end_pfn) 
+		return 1; 
+	return 0; 	
+} 
+
+/*
+ * Checksum an ACPI table.
+ */
+
+static unsigned char __init acpi_checksum(void *buffer, int length)
+{
+	unsigned char sum = 0;
+	while (length--)
+		sum += *(unsigned char *)buffer++;
+	return sum;
+}
+
+/*
+ * Print an ACPI table header for debugging.
+ */
+
+static char __init *acpi_kill_spaces(char *t, char *s, int m)
+{
+	int l = strnlen(s, m);
+	strncpy(t, s, m);
+	t[l] = 0;
+	while (l > 0 && (t[l - 1] == ' ' || t[l - 1] == '\t')) t[--l] = 0;
+	while (t[0] == ' ' || t[0] == '\t') t++;
+	return t;
+}
+
+static void __init acpi_print_table_header(struct acpi_table_header * header)
+{
+	char oem[7], id[9];
+
+	printk(KERN_INFO "acpi: %.4s rev: %d oem: %s id: %s build: %d.%d\n",
+		header->signature, header->revision, acpi_kill_spaces(oem, header->oem_id, 6),
+		acpi_kill_spaces(id, header->oem_table_id, 8), header->oem_revision >> 16,
+		header->oem_revision & 0xffff);
+}
+
+/*
+ * Search a block of memory for the RSDP signature
+ */
+
+static void* __init acpi_tb_scan_memory_for_rsdp(void *address, int length)
+{
+	u32 offset = 0;
+
+	while (offset < length) {
+		if (strncmp(address, "RSD PTR ", 8) == 0 &&
+		    acpi_checksum(address, RSDP_CHECKSUM_LENGTH) == 0) {
+			printk(KERN_INFO "acpi: RSDP found at address %p\n", address);
+			return address;
+		}
+		offset += RSDP_SCAN_STEP;
+		address += RSDP_SCAN_STEP;
+	}
+	return NULL;
+}
+
+/*
+ * Search lower 1_mbyte of memory for the root system descriptor
+ * pointer structure. If it is found, set *RSDP to point to it.
+ */
+
+static struct acpi_table_rsdp* __init acpi_find_root_pointer(void)
+{
+	struct acpi_table_rsdp *rsdp;
+
+	if ((rsdp = acpi_tb_scan_memory_for_rsdp(__va(LO_RSDP_WINDOW_BASE), LO_RSDP_WINDOW_SIZE)))
+		return rsdp;
+
+	if ((rsdp = acpi_tb_scan_memory_for_rsdp(__va(HI_RSDP_WINDOW_BASE), HI_RSDP_WINDOW_SIZE)))
+		return rsdp;
+
+	return NULL;
+}
+
+static int __init acpi_process_table(u64 table)
+{
+	struct acpi_table_header *header;
+	int type;
+
+	header = __va(table);
+
+	acpi_print_table_header(header);
+
+	if (acpi_checksum(header, header->length)) {
+		printk(KERN_WARNING "acpi: ACPI table at %#lx has invalid checksum.\n", table);
+		return -1;
+	}
+
+	for (type = 0; type < ACPI_TABLE_COUNT; type++)
+		if (!strncmp(header->signature, acpi_table_signatures[type], 4))
+			break;
+
+	if (type == ACPI_TABLE_COUNT || !acpi_boot_ops[type])
+		return 0;
+
+	return acpi_boot_ops[type](header, table);
+}
+
+static int __init acpi_tables_init(void)
+{
+	struct acpi_table_rsdp *rsdp;
+	struct acpi_table_xsdt *xsdt = NULL;
+	struct acpi_table_rsdt *rsdt = NULL;
+	char oem[7];
+	int i;
+
+	if (!(rsdp = acpi_find_root_pointer())) {
+		printk(KERN_ERR "acpi: Couldn't find ACPI root pointer!\n");
+		return -1;
+	}
+
+	printk(KERN_INFO "acpi: RSDP rev: %d oem: %s\n",
+		rsdp->revision, acpi_kill_spaces(oem, rsdp->oem_id, 6));
+
+	if (!acpi_checksum(rsdp, RSDP2_CHECKSUM_LENGTH)
+		&& rsdp->length >= RSDP2_CHECKSUM_LENGTH) {	/* ACPI 2.0 might be present */
+		xsdt = __va(rsdp->xsdt_address);
+		if (bad_ptr(xsdt))
+			return -1; 
+		if (!strncmp(xsdt->header.signature, "XSDT", 4)) {
+			acpi_print_table_header(&xsdt->header);
+			for (i = 0; i < (xsdt->header.length - sizeof(struct acpi_table_header)) / sizeof(u64); i++)
+				if (acpi_process_table(xsdt->entry[i]))
+					return -1;
+			return 0;
+		}
+	}
+
+	rsdt = __va(rsdp->rsdt_address);
+	if (bad_ptr(rsdt))
+		return -1;
+	if (!strncmp(rsdt->header.signature, "RSDT", 4)) {
+		acpi_print_table_header(&rsdt->header);
+		for (i = 0; i < (rsdt->header.length - sizeof(struct acpi_table_header)) / sizeof(u32); i++)
+			if (acpi_process_table(rsdt->entry[i]))
+				return -1;
+		return 0;
+	}
+
+	printk(KERN_WARNING "acpi: No ACPI table directory found.\n");
+	return -1;
+}
+
+static void __init acpi_parse_lapic(struct acpi_table_lapic *local_apic)
+{
+	printk(KERN_INFO "acpi: LAPIC acpi_id: %d id: %d enabled: %d\n",
+		local_apic->acpi_id, local_apic->id, local_apic->flags.enabled);
+}
+
+static void __init acpi_parse_ioapic(struct acpi_table_ioapic *ioapic)
+{
+	printk(KERN_INFO "acpi: IOAPIC id: %d address: %#x global_irq_base: %#x\n",
+		ioapic->id, ioapic->address, ioapic->global_irq_base);
+}
+
+static void __init acpi_parse_int_src_ovr(struct acpi_table_int_src_ovr *intsrc)
+{
+	printk(KERN_INFO "acpi: INT_SRC_OVR bus: %d irq: %d global_irq: %d polarity: %d trigger: %d\n",
+		intsrc->bus, intsrc->bus_irq, intsrc->global_irq, intsrc->flags.polarity, intsrc->flags.trigger);
+}
+
+static void __init acpi_parse_nmi_src(struct acpi_table_nmi_src *nmisrc)
+{
+	printk(KERN_INFO "acpi: NMI_SRC polarity: %d trigger: %d global_irq: %d\n",
+		nmisrc->flags.polarity, nmisrc->flags.trigger, nmisrc->global_irq);
+}
+
+static void __init acpi_parse_lapic_nmi(struct acpi_table_lapic_nmi *localnmi)
+{
+	printk(KERN_INFO "acpi: LAPIC_NMI acpi_id: %d polarity: %d trigger: %d lint: %d\n",
+		localnmi->acpi_id, localnmi->flags.polarity, localnmi->flags.trigger, localnmi->lint);
+}
+
+static void __init acpi_parse_lapic_addr_ovr(struct acpi_table_lapic_addr_ovr *lapic_addr_ovr)
+{
+	printk(KERN_INFO "acpi: LAPIC_ADDR_OVR address: %#lx\n",
+		(unsigned long) lapic_addr_ovr->address);
+}
+
+static void __init acpi_parse_plat_int_src(struct acpi_table_plat_int_src *plintsrc)
+{
+	printk(KERN_INFO "acpi: PLAT_INT_SRC polarity: %d trigger: %d type: %d id: %d eid: %d iosapic_vector: %#x global_irq: %d\n",
+		plintsrc->flags.polarity, plintsrc->flags.trigger, plintsrc->type, plintsrc->id, plintsrc->eid,
+		plintsrc->iosapic_vector, plintsrc->global_irq);
+}
+
+static int __init acpi_parse_madt(struct acpi_table_header *header, unsigned long phys)
+{
+
+	struct acpi_table_madt *madt;
+	struct acpi_madt_entry_header *entry_header;
+	int table_size;
+
+	madt = __va(phys);
+	table_size = header->length - sizeof(*madt);
+	entry_header = (void *)madt + sizeof(*madt);
+
+	while (entry_header && table_size > 0) {
+
+		switch (entry_header->type) {
+			case ACPI_MADT_LAPIC:
+				acpi_parse_lapic((void *) entry_header);
+				break;
+			case ACPI_MADT_IOAPIC:
+				acpi_parse_ioapic((void *) entry_header);
+				break;
+			case ACPI_MADT_INT_SRC_OVR:
+				acpi_parse_int_src_ovr((void *) entry_header);
+				break;
+			case ACPI_MADT_NMI_SRC:
+				acpi_parse_nmi_src((void *) entry_header);
+				break;
+			case ACPI_MADT_LAPIC_NMI:
+				acpi_parse_lapic_nmi((void *) entry_header);
+				break;
+			case ACPI_MADT_LAPIC_ADDR_OVR:
+				acpi_parse_lapic_addr_ovr((void *) entry_header);
+				break;
+			case ACPI_MADT_PLAT_INT_SRC:
+				acpi_parse_plat_int_src((void *) entry_header);
+				break;
+			default:
+				printk(KERN_WARNING "acpi: Unsupported MADT entry type 0x%x\n", entry_header->type);
+				break;
+		}
+
+		table_size -= entry_header->length;
+		entry_header = (void *) entry_header + entry_header->length;
+	}
+
+	printk(KERN_INFO "acpi: Local APIC address %#x\n", madt->lapic_address);
+
+	return 0;
+}
+
+static int __init acpi_parse_hpet(struct acpi_table_header *header, unsigned long phys)
+{
+	struct acpi_table_hpet *hpet_tbl;
+
+	hpet_tbl = __va(phys);
+
+	if (hpet_tbl->addr.space_id != ACPI_SPACE_MEM) {
+		printk(KERN_WARNING "acpi: HPET timers must be located in memory.\n");
+		return -1;
+	}
+
+	hpet.address = hpet_tbl->addr.addrl | ((long) hpet_tbl->addr.addrh << 32);
+
+	printk(KERN_INFO "acpi: HPET id: %#x base: %#lx\n", hpet_tbl->id, hpet.address);
+
+	return 0;
+}
+
+/*
+ * Configure the processor info using MADT in the ACPI tables. If we fail to
+ * configure that, then we use the MPS tables.
+ */
+
+void __init config_acpi_tables(void)
+{
+	acpi_boot_ops[ACPI_APIC] = acpi_parse_madt;
+	acpi_boot_ops[ACPI_HPET] = acpi_parse_hpet;
+
+	if (acpi_tables_init())
+		printk(KERN_ERR "acpi: Init failed.\n");
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/acpitable.h linux-2.4.20/arch/x86_64/kernel/acpitable.h
--- linux-2.4.19/arch/x86_64/kernel/acpitable.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/acpitable.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,212 @@
+/*
+ *  acpitable.h - x86-64-specific ACPI boot-time initialization
+ *
+ *  Copyright (C) 1999 Andrew Henroid
+ *  Copyright (C) 2001 Richard Schaal
+ *  Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ *  Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com>
+ *  Copyright (C) 2001 Arjan van de Ven <arjanv@redhat.com>
+ *  Copyright (C) 2002 Vojtech Pavlik <vojtech@suse.cz>
+ */
+
+/*
+ * The following codes are cut&pasted from drivers/acpi. Part of the code
+ * there can be not updated or delivered yet.
+ * To avoid conflicts when CONFIG_ACPI is defined, the following codes are
+ * modified so that they are self-contained in this file.
+ * -- jun
+ */
+
+#ifndef _HEADER_ACPITABLE_H_
+#define _HEADER_ACPITABLE_H_
+
+struct acpi_table_header {		/* ACPI common table header */
+	char signature[4];		/* identifies type of table */
+	u32 length;			/* length of table,
+					   in bytes, * including header */
+	u8 revision;			/* specification minor version # */
+	u8 checksum;			/* to make sum of entire table == 0 */
+	char oem_id[6];			/* OEM identification */
+	char oem_table_id[8];		/* OEM table identification */
+	u32 oem_revision;		/* OEM revision number */
+	char asl_compiler_id[4];	/* ASL compiler vendor ID */
+	u32 asl_compiler_revision;	/* ASL compiler revision number */
+} __attribute__ ((packed));;
+
+enum {
+	ACPI_APIC = 0,
+	ACPI_FACP,
+	ACPI_HPET,
+	ACPI_TABLE_COUNT
+};
+
+static char *acpi_table_signatures[ACPI_TABLE_COUNT] = {
+	"APIC",
+	"FACP",
+	"HPET"
+};
+
+struct acpi_table_madt {
+	struct acpi_table_header header;
+	u32 lapic_address;
+	struct {
+		u32 pcat_compat:1;
+		u32 reserved:31;
+	} flags __attribute__ ((packed));
+} __attribute__ ((packed));;
+
+enum {
+	ACPI_MADT_LAPIC = 0,
+	ACPI_MADT_IOAPIC,
+	ACPI_MADT_INT_SRC_OVR,
+	ACPI_MADT_NMI_SRC,
+	ACPI_MADT_LAPIC_NMI,
+	ACPI_MADT_LAPIC_ADDR_OVR,
+	ACPI_MADT_IOSAPIC,
+	ACPI_MADT_LSAPIC,
+	ACPI_MADT_PLAT_INT_SRC,
+
+};
+
+#define LO_RSDP_WINDOW_BASE		0	/* Physical Address */
+#define HI_RSDP_WINDOW_BASE		0xE0000	/* Physical Address */
+#define LO_RSDP_WINDOW_SIZE		0x400
+#define HI_RSDP_WINDOW_SIZE		0x20000
+#define RSDP_SCAN_STEP			16
+#define RSDP_CHECKSUM_LENGTH		20
+#define RSDP2_CHECKSUM_LENGTH		36
+
+typedef int (*acpi_table_handler) (struct acpi_table_header *header, unsigned long);
+
+struct acpi_table_rsdp {
+	char signature[8];
+	u8 checksum;
+	char oem_id[6];
+	u8 revision;
+	u32 rsdt_address;
+	u32 length;
+	u64 xsdt_address;
+	u8 checksum2;
+	u8 reserved[3];
+} __attribute__ ((packed));
+
+struct acpi_table_rsdt {
+	struct acpi_table_header header;
+	u32 entry[0];
+} __attribute__ ((packed));
+
+struct acpi_table_xsdt {
+	struct acpi_table_header header;
+	u64 entry[0];
+} __attribute__ ((packed));
+
+struct acpi_madt_entry_header {
+	u8 type;
+	u8 length;
+}  __attribute__ ((packed));
+
+struct acpi_madt_int_flags {
+	u16 polarity:2;
+	u16 trigger:2;
+	u16 reserved:12;
+} __attribute__ ((packed));
+
+struct acpi_table_lapic {
+	struct acpi_madt_entry_header header;
+	u8 acpi_id;
+	u8 id;
+	struct {
+		u32 enabled:1;
+		u32 reserved:31;
+	} flags __attribute__ ((packed));
+} __attribute__ ((packed));
+
+struct acpi_table_ioapic {
+	struct acpi_madt_entry_header header;
+	u8 id;
+	u8 reserved;
+	u32 address;
+	u32 global_irq_base;
+} __attribute__ ((packed));
+
+struct acpi_table_int_src_ovr {
+	struct acpi_madt_entry_header header;
+	u8 bus;
+	u8 bus_irq;
+	u32 global_irq;
+	struct acpi_madt_int_flags flags;
+} __attribute__ ((packed));
+
+struct acpi_table_nmi_src {
+	struct acpi_madt_entry_header header;
+	struct acpi_madt_int_flags flags;
+	u32 global_irq;
+} __attribute__ ((packed));
+
+struct acpi_table_lapic_nmi {
+	struct acpi_madt_entry_header header;
+	u8 acpi_id;
+	struct acpi_madt_int_flags flags;
+	u8 lint;
+} __attribute__ ((packed));
+
+struct acpi_table_lapic_addr_ovr {
+	struct acpi_madt_entry_header header;
+	u8 reserved[2];
+	u64 address;
+} __attribute__ ((packed));
+
+struct acpi_table_iosapic {
+	struct acpi_madt_entry_header header;
+	u8 id;
+	u8 reserved;
+	u32 global_irq_base;
+	u64 address;
+} __attribute__ ((packed));
+
+struct acpi_table_lsapic {
+	struct acpi_madt_entry_header header;
+	u8 acpi_id;
+	u8 id;
+	u8 eid;
+	u8 reserved[3];
+	struct {
+		u32 enabled:1;
+		u32 reserved:31;
+	} flags;
+} __attribute__ ((packed));
+
+struct acpi_table_plat_int_src {
+	struct acpi_madt_entry_header header;
+	struct acpi_madt_int_flags flags;
+	u8 type;
+	u8 id;
+	u8 eid;
+	u8 iosapic_vector;
+	u32 global_irq;
+	u32 reserved;
+} __attribute__ ((packed));
+
+#define ACPI_SPACE_MEM		0
+#define ACPI_SPACE_IO		1
+#define ACPI_SPACE_PCICONF	2
+
+struct acpi_gen_regaddr {
+	u8  space_id;
+	u8  bit_width;
+	u8  bit_offset;
+	u8  resv;
+	u32 addrl;
+	u32 addrh;
+} __attribute__ ((packed));
+
+struct acpi_table_hpet {
+	struct acpi_table_header header;
+	u32 id;
+	struct acpi_gen_regaddr addr;
+	u8 number;
+	u16 min_tick;
+	u8 page_protect;
+} __attribute__ ((packed));
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/aperture.c linux-2.4.20/arch/x86_64/kernel/aperture.c
--- linux-2.4.19/arch/x86_64/kernel/aperture.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/aperture.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,123 @@
+/* 
+ * Firmware replacement code.
+ * 
+ * Work around broken BIOSes that don't set an aperture. 
+ * The IOMMU code needs an aperture even who no AGP is present in the system.
+ * Map the aperture over some low memory.  This is cheaper than doing bounce 
+ * buffering. The memory is lost. This is done at early boot because only
+ * the bootmem allocator can allocate 32+MB. 
+ * 
+ * Copyright 2002 Andi Kleen, SuSE Labs.
+ * $Id: aperture.c,v 1.2 2002/09/19 19:25:32 ak Exp $
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/mmzone.h>
+#include <linux/pci_ids.h>
+#include <asm/e820.h>
+#include <asm/io.h>
+#include <asm/proto.h>
+#include <asm/pci-direct.h>
+
+int fallback_aper_order __initdata = 1; /* 64MB */
+int fallback_aper_force __initdata = 0; 
+
+extern int no_iommu, force_mmu;
+
+/* This code runs before the PCI subsystem is initialized, so just 
+   access the northbridge directly. */
+
+#define NB_ID_3 (PCI_VENDOR_ID_AMD | (0x1103<<16))
+
+static u32 __init allocate_aperture(void) 
+{
+#ifdef CONFIG_DISCONTIGMEM
+	pg_data_t *nd0 = NODE_DATA(0);
+#else
+	pg_data_t *nd0 = &contig_page_data;
+#endif	
+	u32 aper_size;
+	void *p; 
+
+	if (fallback_aper_order > 7) 
+		fallback_aper_order = 7; 
+	aper_size = (32 * 1024 * 1024) << fallback_aper_order; 
+
+	/* 
+         * Aperture has to be naturally aligned it seems. This means an
+	 * 2GB aperture won't have much changes to succeed in the lower 4GB of 
+	 * memory. Unfortunately we cannot move it up because that would make
+	 * the IOMMU useless.
+	 */
+	p = __alloc_bootmem_node(nd0, aper_size, aper_size, 0); 
+	if (!p || __pa(p)+aper_size > 0xffffffff) {
+		printk("Cannot allocate aperture memory hole (%p,%uK)\n",
+		       p, aper_size>>10);
+		if (p)
+			free_bootmem_generic((unsigned long)p, aper_size); 
+		return 0;
+	}
+	printk("Mapping aperture over %d KB of RAM @ %lx\n",  
+	       aper_size >> 10, __pa(p)); 
+	return (u32)__pa(p); 
+}
+
+void __init iommu_hole_init(void) 
+{ 
+	int fix, num; 
+	u32 aper_size, aper_alloc, aper_order;
+	u64 aper_base; 
+
+	if (no_iommu)
+		return;
+	if (end_pfn < (0xffffffff>>PAGE_SHIFT) && !force_mmu) 
+		return;
+
+	printk("Checking aperture...\n"); 
+
+	fix = 0;
+	for (num = 24; num < 32; num++) {		
+		if (read_pci_config(0, num, 3, 0x00) != NB_ID_3) 
+			continue;	
+
+		aper_order = (read_pci_config(0, num, 3, 0x90) >> 1) & 7; 
+		aper_size = (32 * 1024 * 1024) << aper_order; 
+		aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff;
+		aper_base <<= 25; 
+
+		printk("CPU %d: aperture @ %Lx size %u KB\n", num-24, 
+		       aper_base, aper_size>>10);
+		if (!aper_base || aper_base + aper_size >= 0xffffffff) {
+			fix = 1; 
+			break; 
+		} 
+		
+		if (e820_mapped(aper_base, aper_base + aper_size, E820_RAM)) {  
+			printk("Aperture pointing to e820 RAM. Ignoring.\n");
+			fix = 1; 
+			break; 
+		} 
+	} 
+
+	if (!fix && !fallback_aper_force) 
+		return; 
+
+	printk("Your BIOS is broken and doesn't leave a aperture memory hole\n");
+	aper_alloc = allocate_aperture(); 
+	if (!aper_alloc) 
+		return; 
+
+	for (num = 24; num < 32; num++) { 		
+		if (read_pci_config(0, num, 3, 0x00) != NB_ID_3) 
+			continue;	
+
+		/* Don't enable translation yet. That is done later. 
+		   Assume this BIOS didn't initialise the GART so 
+		   just overwrite all previous bits */ 
+		write_pci_config(0, num, 3, 0x90, fallback_aper_order<<1); 
+		write_pci_config(0, num, 3, 0x94, aper_alloc>>25); 
+	} 
+} 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/apic.c linux-2.4.20/arch/x86_64/kernel/apic.c
--- linux-2.4.19/arch/x86_64/kernel/apic.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/apic.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,1094 @@
+/*
+ *	Local APIC handling, local APIC timers
+ *
+ *	(c) 1999, 2000 Ingo Molnar <mingo@redhat.com>
+ *
+ *	Fixes
+ *	Maciej W. Rozycki	:	Bits for genuine 82489DX APICs;
+ *					thanks to Eric Gilmore
+ *					and Rolf G. Tews
+ *					for testing these extensively.
+ *	Maciej W. Rozycki	:	Various updates and fixes.
+ *	Mikael Pettersson	:	Power Management for UP-APIC.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <linux/mm.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/bootmem.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/mc146818rtc.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/atomic.h>
+#include <asm/smp.h>
+#include <asm/mtrr.h>
+#include <asm/mpspec.h>
+#include <asm/pgalloc.h>
+#include <asm/timex.h>
+
+/* Using APIC to generate smp_local_timer_interrupt? */
+int using_apic_timer = 0;
+
+int prof_multiplier[NR_CPUS] = { 1, };
+int prof_old_multiplier[NR_CPUS] = { 1, };
+int prof_counter[NR_CPUS] = { 1, };
+
+int get_maxlvt(void)
+{
+	unsigned int v, ver, maxlvt;
+
+	v = apic_read(APIC_LVR);
+	ver = GET_APIC_VERSION(v);
+	/* 82489DXs do not report # of LVT entries. */
+	maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2;
+	return maxlvt;
+}
+
+void clear_local_APIC(void)
+{
+	int maxlvt;
+	unsigned int v;
+
+	maxlvt = get_maxlvt();
+
+	/*
+	 * Masking an LVT entry on a P6 can trigger a local APIC error
+	 * if the vector is zero. Mask LVTERR first to prevent this.
+	 */
+	if (maxlvt >= 3) {
+		v = ERROR_APIC_VECTOR; /* any non-zero vector will do */
+		apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED);
+	}
+	/*
+	 * Careful: we have to set masks only first to deassert
+	 * any level-triggered sources.
+	 */
+	v = apic_read(APIC_LVTT);
+	apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);
+	v = apic_read(APIC_LVT0);
+	apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
+	v = apic_read(APIC_LVT1);
+	apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED);
+	if (maxlvt >= 4) {
+		v = apic_read(APIC_LVTPC);
+		apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED);
+	}
+
+	/*
+	 * Clean APIC state for other OSs:
+	 */
+	apic_write_around(APIC_LVTT, APIC_LVT_MASKED);
+	apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
+	apic_write_around(APIC_LVT1, APIC_LVT_MASKED);
+	if (maxlvt >= 3)
+		apic_write_around(APIC_LVTERR, APIC_LVT_MASKED);
+	if (maxlvt >= 4)
+		apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);
+	v = GET_APIC_VERSION(apic_read(APIC_LVR));
+	if (APIC_INTEGRATED(v)) {	/* !82489DX */
+		if (maxlvt > 3)
+			apic_write(APIC_ESR, 0);
+		apic_read(APIC_ESR);
+	}
+}
+
+void __init connect_bsp_APIC(void)
+{
+	if (pic_mode) {
+		/*
+		 * Do not trust the local APIC being empty at bootup.
+		 */
+		clear_local_APIC();
+		/*
+		 * PIC mode, enable APIC mode in the IMCR, i.e.
+		 * connect BSP's local APIC to INT and NMI lines.
+		 */
+		printk("leaving PIC mode, enabling APIC mode.\n");
+		outb(0x70, 0x22);
+		outb(0x01, 0x23);
+	}
+}
+
+void disconnect_bsp_APIC(void)
+{
+	if (pic_mode) {
+		/*
+		 * Put the board back into PIC mode (has an effect
+		 * only on certain older boards).  Note that APIC
+		 * interrupts, including IPIs, won't work beyond
+		 * this point!  The only exception are INIT IPIs.
+		 */
+		printk("disabling APIC mode, entering PIC mode.\n");
+		outb(0x70, 0x22);
+		outb(0x00, 0x23);
+	}
+}
+
+void disable_local_APIC(void)
+{
+	unsigned int value;
+
+	clear_local_APIC();
+
+	/*
+	 * Disable APIC (implies clearing of registers
+	 * for 82489DX!).
+	 */
+	value = apic_read(APIC_SPIV);
+	value &= ~APIC_SPIV_APIC_ENABLED;
+	apic_write_around(APIC_SPIV, value);
+}
+
+/*
+ * This is to verify that we're looking at a real local APIC.
+ * Check these against your board if the CPUs aren't getting
+ * started for no apparent reason.
+ */
+int __init verify_local_APIC(void)
+{
+	unsigned int reg0, reg1;
+
+	/*
+	 * The version register is read-only in a real APIC.
+	 */
+	reg0 = apic_read(APIC_LVR);
+	Dprintk("Getting VERSION: %x\n", reg0);
+	apic_write(APIC_LVR, reg0 ^ APIC_LVR_MASK);
+	reg1 = apic_read(APIC_LVR);
+	Dprintk("Getting VERSION: %x\n", reg1);
+
+	/*
+	 * The two version reads above should print the same
+	 * numbers.  If the second one is different, then we
+	 * poke at a non-APIC.
+	 */
+	if (reg1 != reg0)
+		return 0;
+
+	/*
+	 * Check if the version looks reasonably.
+	 */
+	reg1 = GET_APIC_VERSION(reg0);
+	if (reg1 == 0x00 || reg1 == 0xff)
+		return 0;
+	reg1 = get_maxlvt();
+	if (reg1 < 0x02 || reg1 == 0xff)
+		return 0;
+
+	/*
+	 * The ID register is read/write in a real APIC.
+	 */
+	reg0 = apic_read(APIC_ID);
+	Dprintk("Getting ID: %x\n", reg0);
+	apic_write(APIC_ID, reg0 ^ APIC_ID_MASK);
+	reg1 = apic_read(APIC_ID);
+	Dprintk("Getting ID: %x\n", reg1);
+	apic_write(APIC_ID, reg0);
+	if (reg1 != (reg0 ^ APIC_ID_MASK))
+		return 0;
+
+	/*
+	 * The next two are just to see if we have sane values.
+	 * They're only really relevant if we're in Virtual Wire
+	 * compatibility mode, but most boxes are anymore.
+	 */
+	reg0 = apic_read(APIC_LVT0);
+	Dprintk("Getting LVT0: %x\n", reg0);
+	reg1 = apic_read(APIC_LVT1);
+	Dprintk("Getting LVT1: %x\n", reg1);
+
+	return 1;
+}
+
+void __init sync_Arb_IDs(void)
+{
+	/*
+	 * Wait for idle.
+	 */
+	apic_wait_icr_idle();
+
+	Dprintk("Synchronizing Arb IDs.\n");
+	apic_write_around(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG
+				| APIC_DM_INIT);
+}
+
+extern void __error_in_apic_c (void);
+
+/*
+ * An initial setup of the virtual wire mode.
+ */
+void __init init_bsp_APIC(void)
+{
+	unsigned int value, ver;
+
+	/*
+	 * Don't do the setup now if we have a SMP BIOS as the
+	 * through-I/O-APIC virtual wire mode might be active.
+	 */
+	if (smp_found_config || !cpu_has_apic)
+		return;
+
+	value = apic_read(APIC_LVR);
+	ver = GET_APIC_VERSION(value);
+
+	/*
+	 * Do not trust the local APIC being empty at bootup.
+	 */
+	clear_local_APIC();
+
+	/*
+	 * Enable APIC.
+	 */
+	value = apic_read(APIC_SPIV);
+	value &= ~APIC_VECTOR_MASK;
+	value |= APIC_SPIV_APIC_ENABLED;
+	value |= APIC_SPIV_FOCUS_DISABLED;
+	value |= SPURIOUS_APIC_VECTOR;
+	apic_write_around(APIC_SPIV, value);
+
+	/*
+	 * Set up the virtual wire mode.
+	 */
+	apic_write_around(APIC_LVT0, APIC_DM_EXTINT);
+	value = APIC_DM_NMI;
+	if (!APIC_INTEGRATED(ver))		/* 82489DX */
+		value |= APIC_LVT_LEVEL_TRIGGER;
+	apic_write_around(APIC_LVT1, value);
+}
+
+void __init setup_local_APIC (void)
+{
+	unsigned int value, ver, maxlvt;
+
+	/* Pound the ESR really hard over the head with a big hammer - mbligh */
+	if (esr_disable) {
+		apic_write(APIC_ESR, 0);
+		apic_write(APIC_ESR, 0);
+		apic_write(APIC_ESR, 0);
+		apic_write(APIC_ESR, 0);
+	}
+
+	value = apic_read(APIC_LVR);
+	ver = GET_APIC_VERSION(value);
+
+	if ((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f)
+		__error_in_apic_c();
+
+	/*
+	 * Double-check wether this APIC is really registered.
+	 * This is meaningless in clustered apic mode, so we skip it.
+	 */
+	if (!clustered_apic_mode &&
+	    !test_bit(GET_APIC_ID(apic_read(APIC_ID)), &phys_cpu_present_map))
+		BUG();
+
+	/*
+	 * Intel recommends to set DFR, LDR and TPR before enabling
+	 * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
+	 * document number 292116).  So here it goes...
+	 */
+
+	if (!clustered_apic_mode) {
+		/*
+		 * In clustered apic mode, the firmware does this for us
+		 * Put the APIC into flat delivery mode.
+		 * Must be "all ones" explicitly for 82489DX.
+		 */
+		apic_write_around(APIC_DFR, 0xffffffff);
+
+		/*
+		 * Set up the logical destination ID.
+		 */
+		value = apic_read(APIC_LDR);
+		value &= ~APIC_LDR_MASK;
+		value |= (1<<(smp_processor_id()+24));
+		apic_write_around(APIC_LDR, value);
+	}
+
+	/*
+	 * Set Task Priority to 'accept all'. We never change this
+	 * later on.
+	 */
+	value = apic_read(APIC_TASKPRI);
+	value &= ~APIC_TPRI_MASK;
+	apic_write_around(APIC_TASKPRI, value);
+
+	/*
+	 * Now that we are all set up, enable the APIC
+	 */
+	value = apic_read(APIC_SPIV);
+	value &= ~APIC_VECTOR_MASK;
+	/*
+	 * Enable APIC
+	 */
+	value |= APIC_SPIV_APIC_ENABLED;
+
+	/*
+	 * Some unknown Intel IO/APIC (or APIC) errata is biting us with
+	 * certain networking cards. If high frequency interrupts are
+	 * happening on a particular IOAPIC pin, plus the IOAPIC routing
+	 * entry is masked/unmasked at a high rate as well then sooner or
+	 * later IOAPIC line gets 'stuck', no more interrupts are received
+	 * from the device. If focus CPU is disabled then the hang goes
+	 * away, oh well :-(
+	 *
+	 * [ This bug can be reproduced easily with a level-triggered
+	 *   PCI Ne2000 networking cards and PII/PIII processors, dual
+	 *   BX chipset. ]
+	 */
+	/*
+	 * Actually disabling the focus CPU check just makes the hang less
+	 * frequent as it makes the interrupt distributon model be more
+	 * like LRU than MRU (the short-term load is more even across CPUs).
+	 * See also the comment in end_level_ioapic_irq().  --macro
+	 */
+#if 1
+	/* Enable focus processor (bit==0) */
+	value &= ~APIC_SPIV_FOCUS_DISABLED;
+#else
+	/* Disable focus processor (bit==1) */
+	value |= APIC_SPIV_FOCUS_DISABLED;
+#endif
+	/*
+	 * Set spurious IRQ vector
+	 */
+	value |= SPURIOUS_APIC_VECTOR;
+	apic_write_around(APIC_SPIV, value);
+
+	/*
+	 * Set up LVT0, LVT1:
+	 *
+	 * set up through-local-APIC on the BP's LINT0. This is not
+	 * strictly necessery in pure symmetric-IO mode, but sometimes
+	 * we delegate interrupts to the 8259A.
+	 */
+	/*
+	 * TODO: set up through-local-APIC from through-I/O-APIC? --macro
+	 */
+	value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
+	if (!smp_processor_id() && (pic_mode || !value)) {
+		value = APIC_DM_EXTINT;
+		printk("enabled ExtINT on CPU#%d\n", smp_processor_id());
+	} else {
+		value = APIC_DM_EXTINT | APIC_LVT_MASKED;
+		printk("masked ExtINT on CPU#%d\n", smp_processor_id());
+	}
+	apic_write_around(APIC_LVT0, value);
+
+	/*
+	 * only the BP should see the LINT1 NMI signal, obviously.
+	 */
+	if (!smp_processor_id())
+		value = APIC_DM_NMI;
+	else
+		value = APIC_DM_NMI | APIC_LVT_MASKED;
+	if (!APIC_INTEGRATED(ver))		/* 82489DX */
+		value |= APIC_LVT_LEVEL_TRIGGER;
+	apic_write_around(APIC_LVT1, value);
+
+	if (APIC_INTEGRATED(ver) && !esr_disable) {		/* !82489DX */
+		maxlvt = get_maxlvt();
+		if (maxlvt > 3)			/* Due to the Pentium erratum 3AP. */
+			apic_write(APIC_ESR, 0);
+		value = apic_read(APIC_ESR);
+		printk("ESR value before enabling vector: %08x\n", value);
+
+		value = ERROR_APIC_VECTOR;	/* enables sending errors */
+		apic_write_around(APIC_LVTERR, value);
+		/*
+		 * spec says clear errors after enabling vector.
+		 */
+		if (maxlvt > 3)
+			apic_write(APIC_ESR, 0);
+		value = apic_read(APIC_ESR);
+		printk("ESR value after enabling vector: %08x\n", value);
+	} else {
+		if (esr_disable)
+			/*
+			 * Something untraceble is creating bad interrupts on
+			 * secondary quads ... for the moment, just leave the
+			 * ESR disabled - we can't do anything useful with the
+			 * errors anyway - mbligh
+			 */
+			printk("Leaving ESR disabled.\n");
+		else
+			printk("No ESR for 82489DX.\n");
+	}
+
+	if (nmi_watchdog == NMI_LOCAL_APIC)
+		setup_apic_nmi_watchdog();
+}
+
+#ifdef CONFIG_PM
+
+#include <linux/slab.h>
+#include <linux/pm.h>
+
+static struct {
+	/* 'active' is true if the local APIC was enabled by us and
+	   not the BIOS; this signifies that we are also responsible
+	   for disabling it before entering apm/acpi suspend */
+	int active;
+	/* 'perfctr_pmdev' is here because the current (2.4.1) PM
+	   callback system doesn't handle hierarchical dependencies */
+	struct pm_dev *perfctr_pmdev;
+	/* r/w apic fields */
+	unsigned int apic_id;
+	unsigned int apic_taskpri;
+	unsigned int apic_ldr;
+	unsigned int apic_dfr;
+	unsigned int apic_spiv;
+	unsigned int apic_lvtt;
+	unsigned int apic_lvtpc;
+	unsigned int apic_lvt0;
+	unsigned int apic_lvt1;
+	unsigned int apic_lvterr;
+	unsigned int apic_tmict;
+	unsigned int apic_tdcr;
+} apic_pm_state;
+
+static void apic_pm_suspend(void *data)
+{
+	unsigned int l, h;
+	unsigned long flags;
+
+	if (apic_pm_state.perfctr_pmdev)
+		pm_send(apic_pm_state.perfctr_pmdev, PM_SUSPEND, data);
+	apic_pm_state.apic_id = apic_read(APIC_ID);
+	apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI);
+	apic_pm_state.apic_ldr = apic_read(APIC_LDR);
+	apic_pm_state.apic_dfr = apic_read(APIC_DFR);
+	apic_pm_state.apic_spiv = apic_read(APIC_SPIV);
+	apic_pm_state.apic_lvtt = apic_read(APIC_LVTT);
+	apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC);
+	apic_pm_state.apic_lvt0 = apic_read(APIC_LVT0);
+	apic_pm_state.apic_lvt1 = apic_read(APIC_LVT1);
+	apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR);
+	apic_pm_state.apic_tmict = apic_read(APIC_TMICT);
+	apic_pm_state.apic_tdcr = apic_read(APIC_TDCR);
+	__save_flags(flags);
+	__cli();
+	disable_local_APIC();
+	rdmsr(MSR_IA32_APICBASE, l, h);
+	l &= ~MSR_IA32_APICBASE_ENABLE;
+	wrmsr(MSR_IA32_APICBASE, l, h);
+	__restore_flags(flags);
+}
+
+static void apic_pm_resume(void *data)
+{
+	unsigned int l, h;
+	unsigned long flags;
+
+	__save_flags(flags);
+	__cli();
+	rdmsr(MSR_IA32_APICBASE, l, h);
+	l &= ~MSR_IA32_APICBASE_BASE;
+	l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
+	wrmsr(MSR_IA32_APICBASE, l, h);
+	apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
+	apic_write(APIC_ID, apic_pm_state.apic_id);
+	apic_write(APIC_DFR, apic_pm_state.apic_dfr);
+	apic_write(APIC_LDR, apic_pm_state.apic_ldr);
+	apic_write(APIC_TASKPRI, apic_pm_state.apic_taskpri);
+	apic_write(APIC_SPIV, apic_pm_state.apic_spiv);
+	apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);
+	apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);
+	apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc);
+	apic_write(APIC_LVTT, apic_pm_state.apic_lvtt);
+	apic_write(APIC_TDCR, apic_pm_state.apic_tdcr);
+	apic_write(APIC_TMICT, apic_pm_state.apic_tmict);
+	apic_write(APIC_ESR, 0);
+	apic_read(APIC_ESR);
+	apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr);
+	apic_write(APIC_ESR, 0);
+	apic_read(APIC_ESR);
+	__restore_flags(flags);
+	if (apic_pm_state.perfctr_pmdev)
+		pm_send(apic_pm_state.perfctr_pmdev, PM_RESUME, data);
+}
+
+static int apic_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+	switch (rqst) {
+	case PM_SUSPEND:
+		apic_pm_suspend(data);
+		break;
+	case PM_RESUME:
+		apic_pm_resume(data);
+		break;
+	}
+	return 0;
+}
+
+/* perfctr driver should call this instead of pm_register() */
+struct pm_dev *apic_pm_register(pm_dev_t type,
+				unsigned long id,
+				pm_callback callback)
+{
+	struct pm_dev *dev;
+
+	if (!apic_pm_state.active)
+		return pm_register(type, id, callback);
+	if (apic_pm_state.perfctr_pmdev)
+		return NULL;	/* we're busy */
+	dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL);
+	if (dev) {
+		memset(dev, 0, sizeof(*dev));
+		dev->type = type;
+		dev->id = id;
+		dev->callback = callback;
+		apic_pm_state.perfctr_pmdev = dev;
+	}
+	return dev;
+}
+
+/* perfctr driver should call this instead of pm_unregister() */
+void apic_pm_unregister(struct pm_dev *dev)
+{
+	if (!apic_pm_state.active) {
+		pm_unregister(dev);
+	} else if (dev == apic_pm_state.perfctr_pmdev) {
+		apic_pm_state.perfctr_pmdev = NULL;
+		kfree(dev);
+	}
+}
+
+static void __init apic_pm_init1(void)
+{
+	/* can't pm_register() at this early stage in the boot process
+	   (causes an immediate reboot), so just set the flag */
+	apic_pm_state.active = 1;
+}
+
+static void __init apic_pm_init2(void)
+{
+	if (apic_pm_state.active)
+		pm_register(PM_SYS_DEV, 0, apic_pm_callback);
+}
+
+#else	/* CONFIG_PM */
+
+static inline void apic_pm_init1(void) { }
+static inline void apic_pm_init2(void) { }
+
+#endif	/* CONFIG_PM */
+
+/*
+ * Detect and enable local APICs on non-SMP boards.
+ * Original code written by Keir Fraser.
+ */
+int dont_enable_local_apic __initdata = 0;
+
+static int __init detect_init_APIC (void)
+{
+	u32 h, l, features;
+	extern void get_cpu_vendor(struct cpuinfo_x86*);
+
+	/* Disabled by DMI scan or kernel option? */
+	if (dont_enable_local_apic)
+		return -1;
+
+	/* Workaround for us being called before identify_cpu(). */
+	get_cpu_vendor(&boot_cpu_data);
+
+	switch (boot_cpu_data.x86_vendor) {
+	case X86_VENDOR_AMD:
+		if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1)
+			break;
+		goto no_apic;
+	case X86_VENDOR_INTEL:
+		if (boot_cpu_data.x86 == 6 ||
+		    (boot_cpu_data.x86 == 15 && cpu_has_apic) ||
+		    (boot_cpu_data.x86 == 5 && cpu_has_apic))
+			break;
+		goto no_apic;
+	default:
+		goto no_apic;
+	}
+
+	if (!cpu_has_apic) {
+		/*
+		 * Some BIOSes disable the local APIC in the
+		 * APIC_BASE MSR. This can only be done in
+		 * software for Intel P6 and AMD K7 (Model > 1).
+		 */
+		rdmsr(MSR_IA32_APICBASE, l, h);
+		if (!(l & MSR_IA32_APICBASE_ENABLE)) {
+			printk("Local APIC disabled by BIOS -- reenabling.\n");
+			l &= ~MSR_IA32_APICBASE_BASE;
+			l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
+			wrmsr(MSR_IA32_APICBASE, l, h);
+		}
+	}
+	/*
+	 * The APIC feature bit should now be enabled
+	 * in `cpuid'
+	 */
+	features = cpuid_edx(1);
+	if (!(features & (1 << X86_FEATURE_APIC))) {
+		printk("Could not enable APIC!\n");
+		return -1;
+	}
+	set_bit(X86_FEATURE_APIC, &boot_cpu_data.x86_capability);
+	mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+	boot_cpu_id = 0;
+	if (nmi_watchdog != NMI_NONE)
+		nmi_watchdog = NMI_LOCAL_APIC;
+
+	printk("Found and enabled local APIC!\n");
+
+	apic_pm_init1();
+
+	return 0;
+
+no_apic:
+	printk("No local APIC present or hardware disabled\n");
+	return -1;
+}
+
+void __init init_apic_mappings(void)
+{
+	unsigned long apic_phys;
+
+	/*
+	 * If no local APIC can be found then set up a fake all
+	 * zeroes page to simulate the local APIC and another
+	 * one for the IO-APIC.
+	 */
+	if (!smp_found_config && detect_init_APIC()) {
+		apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
+		apic_phys = __pa(apic_phys);
+	} else
+		apic_phys = mp_lapic_addr;
+
+	set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
+	Dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys);
+
+	/*
+	 * Fetch the APIC ID of the BSP in case we have a
+	 * default configuration (or the MP table is broken).
+	 */
+	if (boot_cpu_id == -1U)
+		boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));
+
+#ifdef CONFIG_X86_IO_APIC
+	{
+		unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
+		int i;
+
+		for (i = 0; i < nr_ioapics; i++) {
+			if (smp_found_config) {
+				ioapic_phys = mp_ioapics[i].mpc_apicaddr;
+		if (!ioapic_phys) {
+					printk(KERN_ERR "WARNING: bogus zero IO-APIC address found in MPTABLE, disabling IO-APIC support\n");
+				    smp_found_config = 0;
+				    skip_ioapic_setup = 1;
+				    goto fake_ioapic_page;
+				}
+			} else {
+fake_ioapic_page:
+				ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
+				ioapic_phys = __pa(ioapic_phys);
+			}
+			set_fixmap_nocache(idx, ioapic_phys);
+			Dprintk("mapped IOAPIC to %08lx (%08lx)\n",
+					__fix_to_virt(idx), ioapic_phys);
+			idx++;
+		}
+	}
+#endif
+}
+
+/*
+ * This part sets up the APIC 32 bit clock in LVTT1, with HZ interrupts
+ * per second. We assume that the caller has already set up the local
+ * APIC.
+ */
+
+/*
+ * This function sets up the local APIC timer, with a timeout of
+ * 'clocks' APIC bus clock. During calibration we actually call
+ * this function twice on the boot CPU, once with a bogus timeout
+ * value, second time for real. The other (noncalibrating) CPUs
+ * call this function only once, with the real, calibrated value.
+ *
+ * We do reads before writes even if unnecessary, to get around the
+ * P5 APIC double write bug.
+ */
+
+#define APIC_DIVISOR 16
+
+void __setup_APIC_LVTT(unsigned int clocks)
+{
+	unsigned int lvtt1_value, tmp_value;
+
+	lvtt1_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) |
+			APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
+	apic_write_around(APIC_LVTT, lvtt1_value);
+
+	/*
+	 * Divide PICLK by 16
+	 */
+	tmp_value = apic_read(APIC_TDCR);
+	apic_write_around(APIC_TDCR, (tmp_value
+				& ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
+				| APIC_TDR_DIV_16);
+
+	apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR);
+}
+
+void setup_APIC_timer(void * data)
+{
+	unsigned int clocks = (unsigned long) data, slice, t0, t1;
+	int delta;
+
+	/*
+	 * ok, Intel has some smart code in their APIC that knows
+	 * if a CPU was in 'hlt' lowpower mode, and this increases
+	 * its APIC arbitration priority. To avoid the external timer
+	 * IRQ APIC event being in synchron with the APIC clock we
+	 * introduce an interrupt skew to spread out timer events.
+	 *
+	 * The number of slices within a 'big' timeslice is smp_num_cpus+1
+	 */
+
+	slice = clocks / (smp_num_cpus+1);
+	printk(KERN_INFO "cpu: %d, clocks: %d, slice: %d\n",
+		smp_processor_id(), clocks, slice);
+
+	/*
+	 * Wait for timer IRQ slice:
+	 */
+
+	if (hpet.address) {
+		int trigger = hpet_readl(HPET_T0_CMP);
+		while (hpet_readl(HPET_COUNTER) >= trigger);
+		while (hpet_readl(HPET_COUNTER) <  trigger);
+	} else {
+		int c1, c2;
+		outb_p(0x00, 0x43);
+		c2 = inb_p(0x40);
+		c2 |= inb_p(0x40) << 8;
+		do {
+			c1 = c2;
+			outb_p(0x00, 0x43);
+			c2 = inb_p(0x40);
+			c2 |= inb_p(0x40) << 8;
+		} while (c2 - c1 < 300);
+	}
+
+	__setup_APIC_LVTT(clocks);
+
+	t0 = apic_read(APIC_TMICT)*APIC_DIVISOR;
+
+	/* Wait till TMCCT gets reloaded from TMICT... */
+	do {
+		t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR;
+		delta = (int)(t0 - t1 - slice*(smp_processor_id()+1));
+	} while (delta >= 0);
+
+	/* Now wait for our slice for real. */
+	do {
+		t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR;
+		delta = (int)(t0 - t1 - slice*(smp_processor_id()+1));
+	} while (delta < 0);
+
+	__setup_APIC_LVTT(clocks);
+
+	printk(KERN_INFO "CPU%d<T0:%u,T1:%u,D:%d,S:%u,C:%u>\n",
+			smp_processor_id(), t0, t1, delta, slice, clocks);
+}
+
+/*
+ * In this function we calibrate APIC bus clocks to the external timer.
+ * Unlike on i386 we don't use the PIT to do that, but rely on a
+ * pre-calibrated TSC counter instead.
+ *
+ * We want to do the calibration only once since we want to have local timer
+ * irqs syncron. CPUs connected by the same APIC bus have the very same bus
+ * frequency.  And we want to have irqs off anyways, no accidental APIC irq
+ * that way.
+ */
+
+#define TICK_COUNT 100000000
+
+int __init calibrate_APIC_clock(void)
+{
+	int apic, apic_start, tsc, tsc_start;
+	int result;
+	/*
+	 * Put whatever arbitrary (but long enough) timeout
+	 * value into the APIC clock, we just want to get the
+	 * counter running for calibration.
+	 */
+	__setup_APIC_LVTT(1000000000);
+
+	apic_start = apic_read(APIC_TMCCT);
+	rdtscl(tsc_start);
+
+	do {
+		apic = apic_read(APIC_TMCCT);
+		rdtscl(tsc);
+	} while ((tsc - tsc_start) < TICK_COUNT && (apic - apic_start) < TICK_COUNT);
+
+	result = (apic_start - apic) * 1000L * cpu_khz / (tsc - tsc_start);
+
+	printk("Detected %d.%03d MHz APIC timer.\n",
+		result / 1000 / 1000, result / 1000 % 1000);
+
+	return result * APIC_DIVISOR / HZ;
+}
+
+static unsigned int calibration_result;
+
+int dont_use_local_apic_timer __initdata = 0;
+
+void __init setup_APIC_clocks (void)
+{
+	/* Disabled by DMI scan or kernel option? */
+	if (dont_use_local_apic_timer)
+		return;
+
+	printk("Using local APIC timer interrupts.\n");
+	using_apic_timer = 1;
+
+	__cli();
+
+	calibration_result = calibrate_APIC_clock();
+	/*
+	 * Now set up the timer for real.
+	 */
+	setup_APIC_timer((void *)(u64)calibration_result);
+
+	__sti();
+
+	/* and update all other cpus */
+	smp_call_function(setup_APIC_timer, (void *)(u64)calibration_result, 1, 1);
+}
+
+/*
+ * the frequency of the profiling timer can be changed
+ * by writing a multiplier value into /proc/profile.
+ */
+int setup_profiling_timer(unsigned int multiplier)
+{
+	int i;
+
+	/*
+	 * Sanity check. [at least 500 APIC cycles should be
+	 * between APIC interrupts as a rule of thumb, to avoid
+	 * irqs flooding us]
+	 */
+	if ( (!multiplier) || (calibration_result/multiplier < 500))
+		return -EINVAL;
+
+	/*
+	 * Set the new multiplier for each CPU. CPUs don't start using the
+	 * new values until the next timer interrupt in which they do process
+	 * accounting. At that time they also adjust their APIC timers
+	 * accordingly.
+	 */
+	for (i = 0; i < NR_CPUS; ++i)
+		prof_multiplier[i] = multiplier;
+
+	return 0;
+}
+
+#undef APIC_DIVISOR
+
+/*
+ * Local timer interrupt handler. It does both profiling and
+ * process statistics/rescheduling.
+ *
+ * We do profiling in every local tick, statistics/rescheduling
+ * happen only every 'profiling multiplier' ticks. The default
+ * multiplier is 1 and it can be changed by writing the new multiplier
+ * value into /proc/profile.
+ */
+
+inline void smp_local_timer_interrupt(struct pt_regs *regs)
+{
+	int user = user_mode(regs);
+	int cpu = smp_processor_id();
+
+	/*
+	 * The profiling function is SMP safe. (nothing can mess
+	 * around with "current", and the profiling counters are
+	 * updated with atomic operations). This is especially
+	 * useful with a profiling multiplier != 1
+	 */
+	if (!user)
+		x86_do_profile(regs->rip);
+
+	if (--prof_counter[cpu] <= 0) {
+		/*
+		 * The multiplier may have changed since the last time we got
+		 * to this point as a result of the user writing to
+		 * /proc/profile. In this case we need to adjust the APIC
+		 * timer accordingly.
+		 *
+		 * Interrupts are already masked off at this point.
+		 */
+		prof_counter[cpu] = prof_multiplier[cpu];
+		if (prof_counter[cpu] != prof_old_multiplier[cpu]) {
+			__setup_APIC_LVTT(calibration_result/prof_counter[cpu]);
+			prof_old_multiplier[cpu] = prof_counter[cpu];
+		}
+
+#ifdef CONFIG_SMP
+		update_process_times(user);
+#endif
+	}
+
+	/*
+	 * We take the 'long' return path, and there every subsystem
+	 * grabs the apropriate locks (kernel lock/ irq lock).
+	 *
+	 * we might want to decouple profiling from the 'long path',
+	 * and do the profiling totally in assembly.
+	 *
+	 * Currently this isn't too much of an issue (performance wise),
+	 * we can take more than 100K local irqs per second on a 100 MHz P5.
+	 */
+}
+
+/*
+ * Local APIC timer interrupt. This is the most natural way for doing
+ * local interrupts, but local timer interrupts can be emulated by
+ * broadcast interrupts too. [in case the hw doesnt support APIC timers]
+ *
+ * [ if a single-CPU system runs an SMP kernel then we call the local
+ *   interrupt as well. Thus we cannot inline the local irq ... ]
+ */
+unsigned int apic_timer_irqs [NR_CPUS];
+
+void smp_apic_timer_interrupt(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+
+	/*
+	 * the NMI deadlock-detector uses this.
+	 */
+	apic_timer_irqs[cpu]++;
+
+	/*
+	 * NOTE! We'd better ACK the irq immediately,
+	 * because timer handling can be slow.
+	 */
+	ack_APIC_irq();
+	/*
+	 * update_process_times() expects us to have done irq_enter().
+	 * Besides, if we don't timer interrupts ignore the global
+	 * interrupt lock, which is the WrongThing (tm) to do.
+	 */
+	irq_enter(cpu, 0);
+	smp_local_timer_interrupt(regs);
+	irq_exit(cpu, 0);
+
+	if (softirq_pending(cpu))
+		do_softirq();
+}
+
+/*
+ * This interrupt should _never_ happen with our APIC/SMP architecture
+ */
+asmlinkage void smp_spurious_interrupt(void)
+{
+	unsigned int v;
+	static unsigned long last_warning;
+	static unsigned long skipped;
+
+	/*
+	 * Check if this really is a spurious interrupt and ACK it
+	 * if it is a vectored one.  Just in case...
+	 * Spurious interrupts should not be ACKed.
+	 */
+	v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));
+	if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
+		ack_APIC_irq();
+
+	/* see sw-dev-man vol 3, chapter 7.4.13.5 */
+	if (last_warning+30*HZ < jiffies) {
+		printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
+		       smp_processor_id(), skipped);
+		last_warning = jiffies;
+	} else {
+		skipped++;
+	}
+}
+
+/*
+ * This interrupt should never happen with our APIC/SMP architecture
+ */
+
+asmlinkage void smp_error_interrupt(void)
+{
+	unsigned int v, v1;
+
+	/* First tickle the hardware, only then report what went on. -- REW */
+	v = apic_read(APIC_ESR);
+	apic_write(APIC_ESR, 0);
+	v1 = apic_read(APIC_ESR);
+	ack_APIC_irq();
+	atomic_inc(&irq_err_count);
+
+	/* Here is what the APIC error bits mean:
+	   0: Send CS error
+	   1: Receive CS error
+	   2: Send accept error
+	   3: Receive accept error
+	   4: Reserved
+	   5: Send illegal vector
+	   6: Received illegal vector
+	   7: Illegal register address
+	*/
+	printk (KERN_ERR "APIC error on CPU%d: %02x(%02x)\n",
+		smp_processor_id(), v , v1);
+}
+
+/*
+ * This initializes the IO-APIC and APIC hardware if this is
+ * a UP kernel.
+ */
+int __init APIC_init_uniprocessor (void)
+{
+	if (!smp_found_config && !cpu_has_apic)
+		return -1;
+
+	/*
+	 * Complain if the BIOS pretends there is one.
+	 */
+	if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_id])) {
+		printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
+			boot_cpu_id);
+		return -1;
+	}
+
+	verify_local_APIC();
+
+	connect_bsp_APIC();
+
+	phys_cpu_present_map = 1;
+	apic_write_around(APIC_ID, boot_cpu_id);
+
+	apic_pm_init2();
+
+	setup_local_APIC();
+
+	if (nmi_watchdog == NMI_LOCAL_APIC)
+		check_nmi_watchdog();
+#ifdef CONFIG_X86_IO_APIC
+	if (smp_found_config)
+		if (!skip_ioapic_setup && nr_ioapics)
+			setup_IO_APIC();
+#endif
+	setup_APIC_clocks();
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/bluesmoke.c linux-2.4.20/arch/x86_64/kernel/bluesmoke.c
--- linux-2.4.19/arch/x86_64/kernel/bluesmoke.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/bluesmoke.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,362 @@
+/* 
+ * Machine check handler.
+ * K8 parts Copyright 2002 Andi Kleen, SuSE Labs.
+ * Rest from unknown author(s). 
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <asm/processor.h> 
+#include <asm/msr.h>
+#include <asm/kdebug.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+
+static int mce_disabled __initdata = 1;
+
+/*
+ *	Machine Check Handler For PII/PIII/K7
+ */
+
+static int banks;
+static unsigned long ignored_banks, disabled_banks =  (1UL << 4); 
+
+static void generic_machine_check(struct pt_regs * regs, long error_code)
+{
+	int recover=1;
+	u32 alow, ahigh, high, low;
+	u32 mcgstl, mcgsth;
+	int i;
+	
+	rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
+	if(mcgstl&(1<<0))	/* Recoverable ? */
+		recover=0;
+
+	printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", smp_processor_id(), mcgsth, mcgstl);
+	
+	if (regs && (mcgstl & 2))
+		printk(KERN_EMERG "RIP <%02lx>:%016lx RSP %016lx\n", 
+		       regs->cs, regs->rip, regs->rsp); 
+
+	for(i=0;i<banks;i++)
+	{
+		if ((1UL<<i) & ignored_banks) 
+			continue; 
+
+		rdmsr(MSR_IA32_MC0_STATUS+i*4,low, high);
+		if(high&(1<<31))
+		{
+			if(high&(1<<29))
+				recover|=1;
+			if(high&(1<<25))
+				recover|=2;
+			printk(KERN_EMERG "Bank %d: %08x%08x", i, high, low);
+			high&=~(1<<31);
+			if(high&(1<<27))
+			{
+				rdmsr(MSR_IA32_MC0_MISC+i*4, alow, ahigh);
+				printk("[%08x%08x]", alow, ahigh);
+			}
+			if(high&(1<<26))
+			{
+				rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh);
+				printk(" at %08x%08x", 
+					ahigh, alow);
+			}
+			printk("\n");
+			/* Clear it */
+			wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
+			/* Serialize */
+			wmb();
+		}
+	}
+
+	if(recover&2)
+		panic("CPU context corrupt");
+	if(recover&1)
+		panic("Unable to continue");
+	printk(KERN_EMERG "Attempting to continue.\n");
+	mcgstl&=~(1<<2);
+	wrmsr(MSR_IA32_MCG_STATUS,mcgstl, mcgsth);
+}
+
+static void unexpected_machine_check(struct pt_regs *regs, long error_code)
+{ 
+	printk("unexpected machine check %lx\n", error_code); 
+} 
+
+/*
+ *	Call the installed machine check handler for this CPU setup.
+ */ 
+ 
+static void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
+
+void do_machine_check(struct pt_regs * regs, long error_code)
+{
+	notify_die(DIE_NMI, "machine check", regs, error_code);
+	machine_check_vector(regs, error_code);
+}
+
+/* 
+ *	K8 machine check.
+ */
+
+static struct pci_dev *find_k8_nb(void)
+{ 
+	struct pci_dev *dev;
+	int cpu = smp_processor_id(); 
+	pci_for_each_dev(dev) {
+		if (dev->bus->number==0 && PCI_FUNC(dev->devfn)==3 &&
+		    PCI_SLOT(dev->devfn) == (24+cpu))
+			return dev;
+	}
+	return NULL;
+}
+
+static void k8_machine_check(struct pt_regs * regs, long error_code)
+{ 
+	u64 status, nbstatus;
+	struct pci_dev *nb;
+
+	rdmsrl(MSR_IA32_MCG_STATUS, status); 
+	if ((status & (1<<2)) == 0) 
+		return; 
+	if (status & 1)
+		printk(KERN_EMERG "MCG_STATUS: unrecoverable\n"); 
+
+	rdmsrl(MSR_IA32_MC0_STATUS+4*4, nbstatus); 
+	if ((nbstatus & (1UL<<63)) == 0)
+		goto others; 
+	
+	printk(KERN_EMERG "Northbridge Machine Check %s %016lx %lx\n", 
+	       regs ? "exception" : "timer",
+	       (unsigned long)nbstatus, error_code); 
+	if (nbstatus & (1UL<<62))
+		printk(KERN_EMERG "Lost at least one NB error condition\n"); 	
+	if (nbstatus & (1UL<<61))
+		printk(KERN_EMERG "Uncorrectable condition\n"); 
+	if (nbstatus & (1UL<57))
+		printk(KERN_EMERG "Unrecoverable condition\n"); 
+		
+	nb = find_k8_nb(); 
+	if (nb != NULL) { 
+		u32 statuslow, statushigh;
+		pci_read_config_dword(nb, 0x48, &statuslow);
+		pci_read_config_dword(nb, 0x4c, &statushigh);
+		printk(KERN_EMERG "Northbridge status %08x%08x\n",
+		       statushigh,statuslow); 
+		if (statuslow & 0x10) 
+			printk(KERN_EMERG "GART error %d\n", statuslow & 0xf); 
+		if (statushigh & (1<<31))
+			printk(KERN_EMERG "Lost an northbridge error\n"); 
+		if (statushigh & (1<<25))
+			printk(KERN_EMERG "NB status: unrecoverable\n"); 
+		if (statushigh & (1<<26)) { 
+			u32 addrhigh, addrlow; 
+			pci_read_config_dword(nb, 0x54, &addrhigh); 
+			pci_read_config_dword(nb, 0x50, &addrlow); 
+			printk(KERN_EMERG "NB error address %08x%08x\n", addrhigh,addrlow); 
+		}
+		statushigh &= ~(1<<31); 
+		pci_write_config_dword(nb, 0x4c, statushigh); 		
+	} 
+
+	if (nbstatus & (1UL<<58)) { 
+		u64 adr;
+		rdmsrl(MSR_IA32_MC0_ADDR+4*4, adr);
+		printk(KERN_EMERG "Address: %016lx\n", (unsigned long)adr);
+	}
+	
+	wrmsrl(MSR_IA32_MC0_STATUS+4*4, 0); 
+	wrmsrl(MSR_IA32_MCG_STATUS, 0);
+       
+	if (regs && (status & (1<<1)))
+		printk(KERN_EMERG "MCE at EIP %lx ESP %lx\n", regs->rip, regs->rsp); 
+
+ others:
+	generic_machine_check(regs, error_code); 
+} 
+
+static struct timer_list mcheck_timer;
+int mcheck_interval = 30*HZ; 
+
+static void mcheck_timer_handler(unsigned long data)
+{
+	k8_machine_check(NULL,0);
+	BUG_ON(timer_pending(&mcheck_timer));
+	mcheck_timer.expires = jiffies + mcheck_interval;
+	add_timer(&mcheck_timer);
+}
+
+#ifdef CONFIG_SMP 
+/* SMP needs a process context trampoline because smp_call_function cannot be 
+   called from interrupt context */
+static void mcheck_timer_dist(void *data)
+{ 
+	/* preempt disabled on preemptive kernel */	
+	if (!data) 
+		smp_call_function((void (*)(void *))mcheck_timer_handler,(void*)1,0,0);
+	mcheck_timer_handler(0); 	
+} 
+
+static void mcheck_timer_trampoline(unsigned long data)
+{ 
+	static struct tq_struct mcheck_task = { 
+		routine: mcheck_timer_dist
+	}; 
+	schedule_task(&mcheck_task); 
+} 
+#define mcheck_timer_handler mcheck_timer_trampoline
+#endif 
+
+static int nok8 __initdata; 
+
+static void __init k8_mcheck_init(struct cpuinfo_x86 *c)
+{
+	u64 cap;
+	int i;
+	struct pci_dev *nb; 
+
+	if (!test_bit(X86_FEATURE_MCE, &c->x86_capability) || 
+	    !test_bit(X86_FEATURE_MCA, &c->x86_capability))
+		return; 
+
+	rdmsrl(MSR_IA32_MCG_CAP, cap); 
+	banks = cap&0xff; 
+	machine_check_vector = k8_machine_check; 
+	for (i = 0; i < banks; i++) { 
+		u64 val = ((1UL<<i) & disabled_banks) ? 0 : ~0UL; 
+		wrmsrl(MSR_IA32_MC0_CTL+4*i, val);
+		wrmsrl(MSR_IA32_MC0_STATUS+4*i,0); 
+	}
+
+	nb = find_k8_nb(); 
+	if (nb != NULL) {
+		u32 reg;
+		pci_read_config_dword(nb, 0x40, &reg); 
+		pci_write_config_dword(nb, 0x40, reg|(1<<11)|(1<<10)|(1<<9)|(1<<8)); 
+		printk(KERN_INFO "Machine Check Reporting for K8 Northbridge %d enabled\n",
+		       nb->devfn);
+		ignored_banks |= (1UL<<4); 
+	} 
+
+	set_in_cr4(X86_CR4_MCE);	   	
+
+	if (mcheck_interval) { 
+		init_timer(&mcheck_timer); 
+		mcheck_timer.function = (void (*)(unsigned long))mcheck_timer_handler; 
+		mcheck_timer.expires = jiffies + mcheck_interval; 
+		add_timer(&mcheck_timer); 
+	} 
+	
+	printk(KERN_INFO "Machine Check Reporting enabled for CPU#%d\n", smp_processor_id()); 
+} 
+
+/*
+ *	Set up machine check reporting for Intel processors
+ */
+
+static void __init generic_mcheck_init(struct cpuinfo_x86 *c)
+{
+	u32 l, h;
+	int i;
+	static int done;
+	
+	/*
+	 *	Check for MCE support
+	 */
+
+	if( !test_bit(X86_FEATURE_MCE, &c->x86_capability) )
+		return;	
+	
+	/*
+	 *	Check for PPro style MCA
+	 */
+	 		
+	if( !test_bit(X86_FEATURE_MCA, &c->x86_capability) )
+		return;
+		
+	/* Ok machine check is available */
+	
+	machine_check_vector = generic_machine_check;
+	wmb();
+	
+	if(done==0)
+		printk(KERN_INFO "Intel machine check architecture supported.\n");
+	rdmsr(MSR_IA32_MCG_CAP, l, h);
+	if(l&(1<<8))
+		wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
+	banks = l&0xff;
+
+	for(i=0;i<banks;i++)
+	{
+		u32 val = ((1UL<<i) & disabled_banks) ? 0 : ~0;
+		wrmsr(MSR_IA32_MC0_CTL+4*i, val, val);
+		wrmsr(MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
+	}
+	set_in_cr4(X86_CR4_MCE);
+	printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id());
+	done=1;
+}
+
+/*
+ *	This has to be run for each processor
+ */
+
+void __init mcheck_init(struct cpuinfo_x86 *c)
+{
+	if(mce_disabled==1)
+		return;
+		
+	switch(c->x86_vendor) {
+	case X86_VENDOR_AMD:
+		if (c->x86 == 15 && !nok8) {
+			k8_mcheck_init(c); 
+			break;
+		}
+		/* FALL THROUGH */
+	default:
+	case X86_VENDOR_INTEL:
+		generic_mcheck_init(c);
+		break;
+	}
+}
+
+static int __init mcheck_disable(char *str)
+{
+	mce_disabled = 1;
+	return 0;
+}
+
+
+/* mce=off disable machine check
+   mcenok8 disable k8 specific features
+   mce=disable<NUMBER> disable bank NUMBER
+   mce=enable<NUMBER> enable bank number
+   mce=NUMBER mcheck timer interval number seconds. 
+   Can be also comma separated in a single mce= */
+static int __init mcheck_enable(char *str)
+{
+	char *p;
+	while ((p = strsep(&str,",")) != NULL) { 
+		if (isdigit(*p))
+			mcheck_interval = simple_strtol(p,NULL,0) * HZ; 
+		else if (!strcmp(p,"off"))
+			mce_disabled = 1; 
+		else if (!strncmp(p,"enable",6))
+			disabled_banks &= ~(1<<simple_strtol(p+6,NULL,0));
+		else if (!strncmp(p,"disable",7))
+			disabled_banks |= ~(1<<simple_strtol(p+7,NULL,0));
+		else if (!strcmp(p,"nok8"))
+			nok8 = 1;
+		else
+			return -1;			
+	}
+	return 0;
+}
+
+__setup("nomce", mcheck_disable);
+__setup("mce", mcheck_enable);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/cpuid.c linux-2.4.20/arch/x86_64/kernel/cpuid.c
--- linux-2.4.19/arch/x86_64/kernel/cpuid.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/cpuid.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,166 @@
+#ident "$Id: cpuid.c,v 1.4 2001/10/24 23:58:53 ak Exp $"
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2000 H. Peter Anvin - All Rights Reserved
+ *
+ *   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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+
+/*
+ * cpuid.c
+ *
+ * x86 CPUID access device
+ *
+ * This device is accessed by lseek() to the appropriate CPUID level
+ * and then read in chunks of 16 bytes.  A larger size means multiple
+ * reads of consecutive levels.
+ *
+ * This driver uses /dev/cpu/%d/cpuid where %d is the minor number, and on
+ * an SMP box will direct the access to CPU %d.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/smp.h>
+#include <linux/major.h>
+
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#ifdef CONFIG_SMP
+
+struct cpuid_command {
+  int cpu;
+  u32 reg;
+  u32 *data;
+};
+
+static void cpuid_smp_cpuid(void *cmd_block)
+{
+  struct cpuid_command *cmd = (struct cpuid_command *) cmd_block;
+  
+  if ( cmd->cpu == smp_processor_id() )
+    cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2], &cmd->data[3]);
+}
+
+static inline void do_cpuid(int cpu, u32 reg, u32 *data)
+{
+  struct cpuid_command cmd;
+  
+  if ( cpu == smp_processor_id() ) {
+    cpuid(reg, &data[0], &data[1], &data[2], &data[3]);
+  } else {
+    cmd.cpu  = cpu;
+    cmd.reg  = reg;
+    cmd.data = data;
+    
+    smp_call_function(cpuid_smp_cpuid, &cmd, 1, 1);
+  }
+}
+#else /* ! CONFIG_SMP */
+
+static inline void do_cpuid(int cpu, u32 reg, u32 *data)
+{
+  cpuid(reg, &data[0], &data[1], &data[2], &data[3]);
+}
+
+#endif /* ! CONFIG_SMP */
+
+static loff_t cpuid_seek(struct file *file, loff_t offset, int orig)
+{
+  switch (orig) {
+  case 0:
+    file->f_pos = offset;
+    return file->f_pos;
+  case 1:
+    file->f_pos += offset;
+    return file->f_pos;
+  default:
+    return -EINVAL;	/* SEEK_END not supported */
+  }
+}
+
+static ssize_t cpuid_read(struct file * file, char * buf,
+			size_t count, loff_t *ppos)
+{
+  u32 *tmp = (u32 *)buf;
+  u32 data[4];
+  size_t rv;
+  u32 reg = *ppos;
+  int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+  
+  if ( count % 16 )
+    return -EINVAL; /* Invalid chunk size */
+  
+  for ( rv = 0 ; count ; count -= 16 ) {
+    do_cpuid(cpu, reg, data);
+    if ( copy_to_user(tmp,&data,16) )
+      return -EFAULT;
+    tmp += 4;
+    *ppos = reg++;
+  }
+  
+  return ((char *)tmp) - buf;
+}
+
+static int cpuid_open(struct inode *inode, struct file *file)
+{
+  int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+  struct cpuinfo_x86 *c = &(cpu_data)[cpu];
+
+  if ( !(cpu_online_map & (1UL << cpu)) )
+    return -ENXIO;		/* No such CPU */
+  if ( c->cpuid_level < 0 )
+    return -EIO;		/* CPUID not supported */
+  
+  return 0;
+}
+
+/*
+ * File operations we support
+ */
+static struct file_operations cpuid_fops = {
+  owner:	THIS_MODULE,
+  llseek:	cpuid_seek,
+  read:		cpuid_read,
+  open:		cpuid_open,
+};
+
+int __init cpuid_init(void)
+{
+  if (register_chrdev(CPUID_MAJOR, "cpu/cpuid", &cpuid_fops)) {
+    printk(KERN_ERR "cpuid: unable to get major %d for cpuid\n",
+	   CPUID_MAJOR);
+    return -EBUSY;
+  }
+
+  return 0;
+}
+
+void __exit cpuid_exit(void)
+{
+  unregister_chrdev(CPUID_MAJOR, "cpu/cpuid");
+}
+
+module_init(cpuid_init);
+module_exit(cpuid_exit)
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>");
+MODULE_DESCRIPTION("x86 generic CPUID driver");
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/e820.c linux-2.4.20/arch/x86_64/kernel/e820.c
--- linux-2.4.19/arch/x86_64/kernel/e820.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/e820.c	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,554 @@
+/* 
+ * Handle the memory map.
+ * The functions here do the job until bootmem takes over.
+ * $Id: e820.c,v 1.4 2002/09/19 19:25:32 ak Exp $
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/ioport.h>
+#include <asm/page.h>
+#include <asm/e820.h>
+#include <asm/proto.h>
+#include <asm/bootsetup.h>
+
+extern unsigned long table_start, table_end;
+extern char _end[];
+
+extern struct resource code_resource, data_resource, vram_resource;
+
+/* Check for some hardcoded bad areas that early boot is not allowed to touch */ 
+static inline int bad_addr(unsigned long *addrp, unsigned long size)
+{ 
+	unsigned long addr = *addrp, last = addr + size; 
+
+	/* various gunk below that needed for SMP startup */
+	if (addr < 7*PAGE_SIZE) { 
+		*addrp = 7*PAGE_SIZE; 
+		return 1; 
+	}
+	/* direct mapping tables of the kernel */
+	if (last >= table_start<<PAGE_SHIFT && addr < table_end<<PAGE_SHIFT) { 
+		*addrp = table_end << PAGE_SHIFT; 
+		return 1;
+	} 
+	/* initrd */ 
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (LOADER_TYPE && INITRD_START && last >= INITRD_START && 
+	    addr < INITRD_START+INITRD_SIZE) { 
+		*addrp = INITRD_START + INITRD_SIZE; 
+		return 1;
+	} 
+#endif
+	/* kernel code + 640k memory hole (later should not be needed, but 
+	   be paranoid for now) */
+	if (last >= 640*1024 && addr < __pa_symbol(&_end)) { 
+		*addrp = __pa_symbol(&_end);
+		return 1;
+	}
+	/* XXX ramdisk image here? */ 
+	return 0;
+} 
+
+int __init e820_mapped(unsigned long start, unsigned long end, int type) 
+{ 
+	int i;
+	for (i = 0; i < e820.nr_map; i++) { 
+		struct e820entry *ei = &e820.map[i]; 
+		if (type && ei->type != type) 
+			continue;
+		if (ei->addr >= end || ei->addr + ei->size < start) 
+			continue; 
+		return 1; 
+	} 
+	return 0;
+}
+
+/* 
+ * Find a free area in a specific range. 
+ */ 
+unsigned long __init find_e820_area(unsigned long start, unsigned long end, unsigned size) 
+{ 
+	int i; 
+	for (i = 0; i < e820.nr_map; i++) { 
+		struct e820entry *ei = &e820.map[i]; 
+		unsigned long addr = ei->addr, last; 
+		if (ei->type != E820_RAM) 
+			continue; 
+		if (addr < start) 
+			addr = start;
+		if (addr > ei->addr + ei->size) 
+			continue; 
+		while (bad_addr(&addr, size) && addr+size < ei->addr + ei->size)
+			;
+		last = addr + size;
+		if (last > ei->addr + ei->size)
+			continue;
+		if (last > end) 
+			continue;
+		return addr; 
+	} 
+	return -1UL;		
+} 
+
+/* 
+ * Free bootmem based on the e820 table for a node.
+ */
+void __init e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end)
+{
+	int i;
+	for (i = 0; i < e820.nr_map; i++) {
+		struct e820entry *ei = &e820.map[i]; 
+		unsigned long last, addr;
+
+		if (ei->type != E820_RAM || 
+		    ei->addr+ei->size <= start || 
+		    ei->addr > end)
+			continue;
+
+		addr = round_up(ei->addr, PAGE_SIZE);
+		if (addr < start) 
+			addr = start;
+
+		last = round_down(ei->addr + ei->size, PAGE_SIZE); 
+		if (last >= end)
+			last = end; 
+
+		if (last > addr && last-addr >= PAGE_SIZE)
+			free_bootmem_node(pgdat, addr, last-addr);
+	}
+}
+
+/*
+ * Find the highest page frame number we have available
+ */
+void __init e820_end_of_ram(void)
+{
+	int i;
+	end_pfn = 0;
+	for (i = 0; i < e820.nr_map; i++) {
+		struct e820entry *ei = &e820.map[i]; 
+		unsigned long start, end;
+
+		/* count all types of areas for now to map ACPI easily */
+		start = round_up(ei->addr, PAGE_SIZE); 
+		end = round_down(ei->addr + ei->size, PAGE_SIZE); 
+		if (start >= end)
+			continue;
+		if (end > end_pfn<<PAGE_SHIFT)
+			end_pfn = end>>PAGE_SHIFT;
+	}
+
+	if (end_pfn > MAXMEM >> PAGE_SHIFT)
+		end_pfn = MAXMEM >> PAGE_SHIFT;
+}
+
+/* 
+ * Mark e820 reserved areas as busy for the resource manager.
+ */
+void __init e820_reserve_resources(void)
+{
+	int i;
+	for (i = 0; i < e820.nr_map; i++) {
+		struct resource *res;
+		if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL)
+			continue;
+		res = alloc_bootmem_low(sizeof(struct resource));
+		switch (e820.map[i].type) {
+		case E820_RAM:	res->name = "System RAM"; break;
+		case E820_ACPI:	res->name = "ACPI Tables"; break;
+		case E820_NVS:	res->name = "ACPI Non-volatile Storage"; break;
+		default:	res->name = "reserved";
+		}
+		res->start = e820.map[i].addr;
+		res->end = res->start + e820.map[i].size - 1;
+		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+		request_resource(&iomem_resource, res);
+		if (e820.map[i].type == E820_RAM) {
+			/*
+			 *  We dont't know which RAM region contains kernel data,
+			 *  so we try it repeatedly and let the resource manager
+			 *  test it.
+			 */
+			request_resource(res, &code_resource);
+			request_resource(res, &data_resource);
+		}
+	}
+}
+
+/* 
+ * Add a memory region to the kernel e820 map.
+ */ 
+void __init add_memory_region(unsigned long start, unsigned long size, int type)
+{
+	int x = e820.nr_map;
+
+	if (x == E820MAX) {
+		printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
+		return;
+	}
+
+	e820.map[x].addr = start;
+	e820.map[x].size = size;
+	e820.map[x].type = type;
+	e820.nr_map++;
+}
+
+void __init e820_print_map(char *who)
+{
+	int i;
+
+	for (i = 0; i < e820.nr_map; i++) {
+		printk(" %s: %016Lx - %016Lx ", who,
+			(unsigned long long) e820.map[i].addr,
+			(unsigned long long) (e820.map[i].addr + e820.map[i].size));
+		switch (e820.map[i].type) {
+		case E820_RAM:	printk("(usable)\n");
+				break;
+		case E820_RESERVED:
+				printk("(reserved)\n");
+				break;
+		case E820_ACPI:
+				printk("(ACPI data)\n");
+				break;
+		case E820_NVS:
+				printk("(ACPI NVS)\n");
+				break;
+		default:	printk("type %u\n", e820.map[i].type);
+				break;
+		}
+	}
+}
+
+/*
+ * Sanitize the BIOS e820 map.
+ *
+ * Some e820 responses include overlapping entries.  The following 
+ * replaces the original e820 map with a new one, removing overlaps.
+ *
+ */
+static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
+{
+	struct change_member {
+		struct e820entry *pbios; /* pointer to original bios entry */
+		unsigned long long addr; /* address for this change point */
+	};
+	static struct change_member change_point_list[2*E820MAX] __initdata;
+	static struct change_member *change_point[2*E820MAX] __initdata;
+	static struct e820entry *overlap_list[E820MAX] __initdata;
+	static struct e820entry new_bios[E820MAX] __initdata;
+	struct change_member *change_tmp;
+	unsigned long current_type, last_type;
+	unsigned long long last_addr;
+	int chgidx, still_changing;
+	int overlap_entries;
+	int new_bios_entry;
+	int old_nr, new_nr;
+	int i;
+
+	/*
+		Visually we're performing the following (1,2,3,4 = memory types)...
+
+		Sample memory map (w/overlaps):
+		   ____22__________________
+		   ______________________4_
+		   ____1111________________
+		   _44_____________________
+		   11111111________________
+		   ____________________33__
+		   ___________44___________
+		   __________33333_________
+		   ______________22________
+		   ___________________2222_
+		   _________111111111______
+		   _____________________11_
+		   _________________4______
+
+		Sanitized equivalent (no overlap):
+		   1_______________________
+		   _44_____________________
+		   ___1____________________
+		   ____22__________________
+		   ______11________________
+		   _________1______________
+		   __________3_____________
+		   ___________44___________
+		   _____________33_________
+		   _______________2________
+		   ________________1_______
+		   _________________4______
+		   ___________________2____
+		   ____________________33__
+		   ______________________4_
+	*/
+
+	/* if there's only one memory region, don't bother */
+	if (*pnr_map < 2)
+		return -1;
+
+	old_nr = *pnr_map;
+
+	/* bail out if we find any unreasonable addresses in bios map */
+	for (i=0; i<old_nr; i++)
+		if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)
+			return -1;
+
+	/* create pointers for initial change-point information (for sorting) */
+	for (i=0; i < 2*old_nr; i++)
+		change_point[i] = &change_point_list[i];
+
+	/* record all known change-points (starting and ending addresses) */
+	chgidx = 0;
+	for (i=0; i < old_nr; i++)	{
+		change_point[chgidx]->addr = biosmap[i].addr;
+		change_point[chgidx++]->pbios = &biosmap[i];
+		change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
+		change_point[chgidx++]->pbios = &biosmap[i];
+	}
+
+	/* sort change-point list by memory addresses (low -> high) */
+	still_changing = 1;
+	while (still_changing)	{
+		still_changing = 0;
+		for (i=1; i < 2*old_nr; i++)  {
+			/* if <current_addr> > <last_addr>, swap */
+			/* or, if current=<start_addr> & last=<end_addr>, swap */
+			if ((change_point[i]->addr < change_point[i-1]->addr) ||
+				((change_point[i]->addr == change_point[i-1]->addr) &&
+				 (change_point[i]->addr == change_point[i]->pbios->addr) &&
+				 (change_point[i-1]->addr != change_point[i-1]->pbios->addr))
+			   )
+			{
+				change_tmp = change_point[i];
+				change_point[i] = change_point[i-1];
+				change_point[i-1] = change_tmp;
+				still_changing=1;
+			}
+		}
+	}
+
+	/* create a new bios memory map, removing overlaps */
+	overlap_entries=0;	 /* number of entries in the overlap table */
+	new_bios_entry=0;	 /* index for creating new bios map entries */
+	last_type = 0;		 /* start with undefined memory type */
+	last_addr = 0;		 /* start with 0 as last starting address */
+	/* loop through change-points, determining affect on the new bios map */
+	for (chgidx=0; chgidx < 2*old_nr; chgidx++)
+	{
+		/* keep track of all overlapping bios entries */
+		if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
+		{
+			/* add map entry to overlap list (> 1 entry implies an overlap) */
+			overlap_list[overlap_entries++]=change_point[chgidx]->pbios;
+		}
+		else
+		{
+			/* remove entry from list (order independent, so swap with last) */
+			for (i=0; i<overlap_entries; i++)
+			{
+				if (overlap_list[i] == change_point[chgidx]->pbios)
+					overlap_list[i] = overlap_list[overlap_entries-1];
+			}
+			overlap_entries--;
+		}
+		/* if there are overlapping entries, decide which "type" to use */
+		/* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */
+		current_type = 0;
+		for (i=0; i<overlap_entries; i++)
+			if (overlap_list[i]->type > current_type)
+				current_type = overlap_list[i]->type;
+		/* continue building up new bios map based on this information */
+		if (current_type != last_type)	{
+			if (last_type != 0)	 {
+				new_bios[new_bios_entry].size =
+					change_point[chgidx]->addr - last_addr;
+				/* move forward only if the new size was non-zero */
+				if (new_bios[new_bios_entry].size != 0)
+					if (++new_bios_entry >= E820MAX)
+						break; 	/* no more space left for new bios entries */
+			}
+			if (current_type != 0)	{
+				new_bios[new_bios_entry].addr = change_point[chgidx]->addr;
+				new_bios[new_bios_entry].type = current_type;
+				last_addr=change_point[chgidx]->addr;
+			}
+			last_type = current_type;
+		}
+	}
+	new_nr = new_bios_entry;   /* retain count for new bios entries */
+
+	/* copy new bios mapping into original location */
+	memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
+	*pnr_map = new_nr;
+
+	return 0;
+}
+
+/*
+ * Copy the BIOS e820 map into a safe place.
+ *
+ * Sanity-check it while we're at it..
+ *
+ * If we're lucky and live on a modern system, the setup code
+ * will have given us a memory map that we can use to properly
+ * set up memory.  If we aren't, we'll fake a memory map.
+ *
+ * We check to see that the memory map contains at least 2 elements
+ * before we'll use it, because the detection code in setup.S may
+ * not be perfect and most every PC known to man has two memory
+ * regions: one from 0 to 640k, and one from 1mb up.  (The IBM
+ * thinkpad 560x, for example, does not cooperate with the memory
+ * detection code.)
+ */
+static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
+{
+	/* Only one memory region (or negative)? Ignore it */
+	if (nr_map < 2)
+		return -1;
+
+	do {
+		unsigned long start = biosmap->addr;
+		unsigned long size = biosmap->size;
+		unsigned long end = start + size;
+		unsigned long type = biosmap->type;
+
+		/* Overflow in 64 bits? Ignore the memory map. */
+		if (start > end)
+			return -1;
+
+		/*
+		 * Some BIOSes claim RAM in the 640k - 1M region.
+		 * Not right. Fix it up.
+		 * 
+		 * This should be removed on Hammer which is supposed to not
+		 * have non e820 covered ISA mappings there, but I had some strange
+		 * problems so it stays for now.  -AK
+		 */
+		if (type == E820_RAM) {
+			if (start < 0x100000ULL && end > 0xA0000ULL) {
+				if (start < 0xA0000ULL)
+					add_memory_region(start, 0xA0000ULL-start, type);
+				if (end <= 0x100000ULL)
+					continue;
+				start = 0x100000ULL;
+				size = end - start;
+			}
+		}
+
+		add_memory_region(start, size, type);
+	} while (biosmap++,--nr_map);
+	return 0;
+}
+
+void __init setup_memory_region(void)
+{
+	char *who = "BIOS-e820";
+
+	/*
+	 * Try to copy the BIOS-supplied E820-map.
+	 *
+	 * Otherwise fake a memory map; one section from 0k->640k,
+	 * the next section from 1mb->appropriate_mem_k
+	 */
+	sanitize_e820_map(E820_MAP, &E820_MAP_NR);
+	if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
+		unsigned long mem_size;
+
+		/* compare results from other methods and take the greater */
+		if (ALT_MEM_K < EXT_MEM_K) {
+			mem_size = EXT_MEM_K;
+			who = "BIOS-88";
+		} else {
+			mem_size = ALT_MEM_K;
+			who = "BIOS-e801";
+		}
+
+		e820.nr_map = 0;
+		add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+		add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
+  	}
+	printk(KERN_INFO "BIOS-provided physical RAM map:\n");
+	e820_print_map(who);
+}
+
+extern char command_line[], saved_command_line[];
+extern int fallback_aper_order;
+extern int iommu_setup(char *opt);
+
+void __init parse_mem_cmdline (char ** cmdline_p)
+{
+	char c = ' ', *to = command_line, *from = COMMAND_LINE;
+	int len = 0;
+	int usermem = 0;
+
+	/* Save unparsed command line copy for /proc/cmdline */
+	memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
+	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
+
+	for (;;) {
+		if (c != ' ') 
+			goto next;
+
+		/*
+		 * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM
+		 * to <mem>, overriding the bios size.
+		 * "mem=XXX[KkmM]@XXX[KkmM]" defines a memory region from
+		 * <start> to <start>+<mem>, overriding the bios size.
+		 */
+		if (!memcmp(from, "mem=", 4)) {
+			if (to != command_line)
+				to--;
+			else if (!memcmp(from+4, "exactmap", 8)) {
+				from += 8+4;
+				e820.nr_map = 0;
+				usermem = 1;
+			} else {
+				/* If the user specifies memory size, we
+				 * blow away any automatically generated
+				 * size
+				 */
+				unsigned long long start_at, mem_size;
+ 
+				if (usermem == 0) {
+					/* first time in: zap the whitelist
+					 * and reinitialize it with the
+					 * standard low-memory region.
+					 */
+					e820.nr_map = 0;
+					usermem = 1;
+					add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+				}
+				mem_size = memparse(from+4, &from);
+				if (*from == '@')
+					start_at = memparse(from+1, &from);
+				else {
+					start_at = HIGH_MEMORY;
+					mem_size -= HIGH_MEMORY;
+					usermem=0;
+				}
+				add_memory_region(start_at, mem_size, E820_RAM);
+			}
+		}
+#ifdef CONFIG_GART_IOMMU 
+		else if (!memcmp(from,"iommu=",6)) { 
+			iommu_setup(from+6); 
+		} 	
+		
+#endif
+	next:
+		c = *(from++);
+		if (!c)
+			break;
+		if (COMMAND_LINE_SIZE <= ++len)
+			break;
+		*(to++) = c;
+	}
+	*to = '\0';
+	*cmdline_p = command_line;
+	if (usermem) {
+		printk(KERN_INFO "user-defined physical RAM map:\n");
+		e820_print_map("user");
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/early_printk.c linux-2.4.20/arch/x86_64/kernel/early_printk.c
--- linux-2.4.19/arch/x86_64/kernel/early_printk.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/early_printk.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,214 @@
+#include <linux/console.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <asm/io.h>
+#include <asm/proto.h>
+
+/* Simple VGA output */
+
+#define VGABASE		0xffffffff800b8000UL
+
+#define MAX_YPOS	25
+#define MAX_XPOS	80
+
+static int current_ypos = 1, current_xpos = 0; 
+
+static void early_vga_write(struct console *con, const char *str, unsigned n)
+{
+	char c;
+	int  i, k, j;
+
+	while ((c = *str++) != '\0' && n-- > 0) {
+		if (current_ypos >= MAX_YPOS) {
+			/* scroll 1 line up */
+			for(k = 1, j = 0; k < MAX_YPOS; k++, j++) {
+				for(i = 0; i < MAX_XPOS; i++) {
+					writew(readw(VGABASE + 2*(MAX_XPOS*k + i)),
+					       VGABASE + 2*(MAX_XPOS*j + i));
+				}
+			}
+			for(i = 0; i < MAX_XPOS; i++) {
+				writew(0x720, VGABASE + 2*(MAX_XPOS*j + i));
+			}
+			current_ypos = MAX_YPOS-1;
+		}
+		if (c == '\n') {
+			current_xpos = 0;
+			current_ypos++;
+		} else if (c != '\r')  {
+			writew(((0x7 << 8) | (unsigned short) c),
+			       VGABASE + 2*(MAX_XPOS*current_ypos + current_xpos++));
+			if (current_xpos >= MAX_XPOS) {
+				current_xpos = 0;
+				current_ypos++;
+			}
+		}
+	}
+}
+
+static struct console early_vga_console = {
+	name:		"earlyvga",
+	write:		early_vga_write,
+	flags:		CON_PRINTBUFFER,
+	index:		-1,
+};
+
+/* Serial functions losely based on a similar package from Klaus P. Gerlicher */ 
+
+int early_serial_base = 0x3f8;  /* ttyS0 */ 
+
+#define XMTRDY          0x20
+
+#define DLAB		0x80
+
+#define TXR             0       /*  Transmit register (WRITE) */
+#define RXR             0       /*  Receive register  (READ)  */
+#define IER             1       /*  Interrupt Enable          */
+#define IIR             2       /*  Interrupt ID              */
+#define FCR             2       /*  FIFO control              */
+#define LCR             3       /*  Line control              */
+#define MCR             4       /*  Modem control             */
+#define LSR             5       /*  Line Status               */
+#define MSR             6       /*  Modem Status              */
+#define DLL             0       /*  Divisor Latch Low         */
+#define DLH             1       /*  Divisor latch High        */
+
+static int early_serial_putc(unsigned char ch) 
+{ 
+	unsigned timeout = 0xffff; 
+	while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) 
+		rep_nop(); 
+	outb(ch, early_serial_base + TXR);
+	return timeout ? 0 : -1;
+} 
+
+static void early_serial_write(struct console *con, const char *s, unsigned n)
+{
+	while (*s && n-- > 0) { 
+		early_serial_putc(*s); 
+		if (*s == '\n') 
+			early_serial_putc('\r'); 
+		s++; 
+	} 
+} 
+
+static __init void early_serial_init(char *opt)
+{ 
+	unsigned char c; 
+	unsigned divisor, baud = 38400;
+	char *s, *e;
+
+	if (*opt == ',') 
+		++opt;
+
+	s = strsep(&opt, ","); 
+	if (s != NULL) { 
+		unsigned port; 
+		if (!strncmp(s,"0x",2))
+			early_serial_base = simple_strtoul(s, &e, 16);
+		else {	
+			static int bases[] = { 0x3f8, 0x2f8 };
+			if (!strncmp(s,"ttyS",4)) 
+				s+=4; 
+			port = simple_strtoul(s, &e, 10); 
+			if (port > 1 || s == e) 
+				port = 0; 
+			early_serial_base = bases[port];
+		} 	
+	}
+
+	outb(0x3, early_serial_base + LCR); /* 8n1 */
+	outb(0, early_serial_base + IER); /* no interrupt */ 
+	outb(0, early_serial_base + FCR); /* no fifo */ 
+	outb(0x3, early_serial_base + MCR); /* DTR + RTS */ 
+
+	s = strsep(&opt, ","); 
+	if (s != NULL) { 
+		baud = simple_strtoul(s, &e, 0); 
+		if (baud == 0 || s == e) 
+			baud = 38400;
+	} 
+	
+	divisor = 115200 / baud; 
+	c = inb(early_serial_base + LCR); 
+	outb(c | DLAB, early_serial_base + LCR); 
+	outb(divisor & 0xff, early_serial_base + DLL); 
+	outb((divisor >> 8) & 0xff, early_serial_base + DLH); 
+	outb(c & ~DLAB, early_serial_base + LCR);
+}
+
+static struct console early_serial_console = {
+	name:		"earlyser",
+	write:		early_serial_write,
+	flags:		CON_PRINTBUFFER,
+	index:		-1,
+};
+
+/* Direct interface for emergencies */
+struct console *early_console = &early_vga_console;
+static int early_console_initialized = 0;
+
+void early_printk(const char *fmt, ...)
+{ 
+	char buf[512]; 
+	int n; 
+	va_list ap;
+	va_start(ap,fmt); 
+	n = vsnprintf(buf,512,fmt,ap);
+	early_console->write(early_console,buf,n);
+	va_end(ap); 
+} 
+
+static int keep_early; 
+
+int __init setup_early_printk(char *opt) 
+{  
+	char *space;
+	char buf[256]; 
+
+	if (early_console_initialized)
+		return -1;
+
+	strncpy(buf,opt,256); 
+	buf[255] = 0; 
+	space = strchr(buf, ' '); 
+	if (space)
+		*space = 0; 
+	
+	if (strstr(buf,"keep"))
+		keep_early = 1; 
+
+	if (!strncmp(buf, "serial", 6)) { 
+		early_serial_init(buf + 6);
+		early_console = &early_serial_console;
+	} else if (!strncmp(buf, "vga", 3)) {
+		early_console = &early_vga_console; 
+	} else {
+		early_console = NULL; 		
+		return -1; 
+	}
+	early_console_initialized = 1;
+	register_console(early_console);       
+	return 0;
+} 
+
+void __init disable_early_printk(void)
+{ 
+	if (!early_console_initialized || !early_console)
+		return;
+	if (!keep_early) {
+		printk("Disabling early console\n");
+		unregister_console(early_console);
+		early_console_initialized = 0;
+	} 
+} 
+
+/* syntax: earlyprintk=vga
+           earlyprintk=serial[,ttySn[,baudrate]] 
+   Append ,keep to not disable it when the real console takes over.
+   Only vga or serial at a time, not both.
+   Currently only ttyS0 and ttyS1 are supported. 
+   Interaction with the standard serial driver is not very good. 
+   The VGA output is eventually overwritten by the real console. */
+__setup("earlyprintk=", setup_early_printk);  
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/entry.S linux-2.4.20/arch/x86_64/kernel/entry.S
--- linux-2.4.19/arch/x86_64/kernel/entry.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/entry.S	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,647 @@
+/*
+ *  linux/arch/x86_64/entry.S
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001, 2002  Andi Kleen SuSE Labs
+ *  Copyright (C) 2000  Pavel Machek <pavel@suse.cz>
+ * 
+ *  $Id: entry.S,v 1.81 2002/09/12 12:55:25 ak Exp $		
+ */
+
+/*
+ * entry.S contains the system-call and fault low-level handling routines.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after an interrupt and after each system call.
+ * 
+ * Normal syscalls and interrupts don't save a full stack frame, this is 
+ * only done for PT_TRACESYS, signals or fork/exec et.al.
+ * 
+ * TODO:	 
+ * - schedule it carefully for the final hardware.		 	
+ *
+ */
+
+#define ASSEMBLY 1
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/current.h>	
+#include <asm/smp.h>
+#include <asm/cache.h>
+#include <asm/errno.h>
+#include <asm/calling.h>
+#include <asm/offset.h>
+#include <asm/msr.h>
+#include <asm/unistd.h>
+
+	.code64
+
+#define PDAREF(field) %gs:field	 		
+
+/*
+ * C code is not supposed to know about partial frames. Everytime a C function
+ * that looks at the pt_regs is called these two macros are executed around it.
+ * RESTORE_TOP_OF_STACK syncs the syscall state after any possible ptregs
+ * manipulation.
+ */        	
+		
+	/* %rsp:at FRAMEEND */ 
+	.macro FIXUP_TOP_OF_STACK tmp
+	movq	PDAREF(pda_oldrsp),\tmp
+	movq  	\tmp,RSP(%rsp)
+	movq    $__USER_DS,SS(%rsp)
+	movq    $__USER_CS,CS(%rsp)
+	movq	$-1,RCX(%rsp)	/* contains return address, already in RIP */
+	movq	R11(%rsp),\tmp  /* get eflags */
+	movq	\tmp,EFLAGS(%rsp)
+	.endm
+
+	.macro RESTORE_TOP_OF_STACK tmp,offset=0
+	movq   RSP-\offset(%rsp),\tmp
+	movq   \tmp,PDAREF(pda_oldrsp)
+	movq   EFLAGS-\offset(%rsp),\tmp
+	movq   \tmp,R11-\offset(%rsp)
+	.endm
+
+
+/*
+ * A newly forked process directly context switches into this.
+ */ 	
+ENTRY(ret_from_fork)
+	movq %rax,%rdi		/* return value of __switch_to -> prev task */
+	call schedule_tail
+	GET_CURRENT(%rcx)
+	testb $PT_TRACESYS,tsk_ptrace(%rcx)
+	jnz 2f
+1:
+	RESTORE_REST
+	testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread?
+	jz   int_ret_from_sys_call
+	testl $ASM_THREAD_IA32,tsk_thread+thread_flags(%rcx)
+	jnz  int_ret_from_sys_call
+	RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
+	jmp ret_from_sys_call
+2:
+	movq %rsp,%rdi	
+	call syscall_trace
+	jmp 1b
+
+/*
+ * System call entry. Upto 6 arguments in registers are supported.
+ *
+ * SYSCALL does not save anything on the stack and does not change the
+ * stack pointer. Gets the per CPU area from the hidden GS MSR and finds the
+ * current kernel stack.
+ */
+		
+/*
+ * Register setup:	
+ * rax  system call number
+ * rdi  arg0
+ * rcx  return address for syscall/sysret, C arg3 
+ * rsi  arg1
+ * rdx  arg2	
+ * r10  arg3 	(--> moved to rcx for C)
+ * r8   arg4
+ * r9   arg5
+ * r11  eflags for syscall/sysret, temporary for C
+ * r12-r15,rbp,rbx saved by C code, not touched. 		
+ * 
+ * Interrupts are off on entry.
+ * Only called from user space.	
+ */ 			 		
+
+ENTRY(system_call)
+	swapgs
+	movq	%rsp,PDAREF(pda_oldrsp) 
+	movq	PDAREF(pda_kernelstack),%rsp
+	sti
+	SAVE_ARGS 8,1
+	movq  %rax,ORIG_RAX-ARGOFFSET(%rsp) 
+	movq  %rcx,RIP-ARGOFFSET(%rsp)	
+	GET_CURRENT(%rcx)
+	testl $PT_TRACESYS,tsk_ptrace(%rcx)
+	jne tracesys
+	cmpq $__NR_syscall_max,%rax
+	ja badsys
+	movq %r10,%rcx
+	call *sys_call_table(,%rax,8)  # XXX:	 rip relative
+	movq %rax,RAX-ARGOFFSET(%rsp)
+	.globl ret_from_sys_call
+ret_from_sys_call:	
+sysret_with_reschedule:
+	GET_CURRENT(%rcx)
+	cli 
+	cmpq $0,tsk_need_resched(%rcx)
+	jne sysret_reschedule
+	cmpl $0,tsk_sigpending(%rcx)
+	jne sysret_signal
+sysret_restore_args:
+	movq    RIP-ARGOFFSET(%rsp),%rcx
+	RESTORE_ARGS 0,-ARG_SKIP,1
+	movq	PDAREF(pda_oldrsp),%rsp
+	swapgs
+	sysretq
+	
+sysret_signal:
+	sti
+	xorl %esi,%esi		# oldset
+	leaq -ARGOFFSET(%rsp),%rdi	# regs
+	leaq do_signal(%rip),%rax
+	call ptregscall_common	
+sysret_signal_test:
+	GET_CURRENT(%rcx)
+	cli
+	cmpq $0,tsk_need_resched(%rcx)
+	je   sysret_restore_args
+	sti
+	call schedule
+	jmp sysret_signal_test
+	
+sysret_reschedule:
+	sti
+	call schedule
+	jmp sysret_with_reschedule	
+	
+tracesys:			 
+	SAVE_REST
+	movq $-ENOSYS,RAX(%rsp)
+	FIXUP_TOP_OF_STACK %rdi
+	movq %rsp,%rdi
+	call syscall_trace
+	LOAD_ARGS ARGOFFSET  /* reload args from stack in case ptrace changed it */
+	RESTORE_REST
+	cmpq $__NR_syscall_max,%rax
+	ja  tracesys_done
+tracesys_call:		/* backtrace marker */		
+	movq %r10,%rcx	/* fixup for C */
+	call *sys_call_table(,%rax,8)
+	movq %rax,RAX-ARGOFFSET(%rsp)
+tracesys_done:		/* backtrace marker */	
+	SAVE_REST
+	movq %rsp,%rdi
+	call syscall_trace
+	RESTORE_TOP_OF_STACK %rbx
+	RESTORE_REST
+	jmp ret_from_sys_call
+		
+badsys:
+	movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
+	jmp ret_from_sys_call
+
+/*
+ * Syscall return path ending with IRET.
+ * This can be either 64bit calls that require restoring of all registers 
+ * (impossible with sysret) or 32bit calls. 	 
+ */	
+ENTRY(int_ret_from_sys_call)	
+intret_test_kernel:
+	testl $3,CS-ARGOFFSET(%rsp)		
+	je retint_restore_args
+intret_with_reschedule:
+	GET_CURRENT(%rcx)
+	cli 
+	cmpq $0,tsk_need_resched(%rcx)
+	jne intret_reschedule
+	cmpl $0,tsk_sigpending(%rcx)
+	jne intret_signal
+	jmp retint_restore_args_swapgs
+	
+intret_reschedule:
+	sti
+	call schedule
+	jmp intret_with_reschedule	
+
+intret_signal:
+	sti
+	SAVE_REST
+	xorq %rsi,%rsi		# oldset -> arg2 
+	movq %rsp,%rdi		# &ptregs -> arg1		
+	call do_signal
+	RESTORE_REST
+intret_signal_test:		
+	GET_CURRENT(%rcx)
+	cli
+	cmpq $0,tsk_need_resched(%rcx)
+	je   retint_restore_args_swapgs
+	sti
+	call schedule
+	jmp  intret_signal_test
+	
+/* 
+ * Certain special system calls that need to save a complete stack frame.
+ */ 								
+	
+	.macro PTREGSCALL label,func
+	.globl \label
+\label:
+	leaq	\func(%rip),%rax
+	jmp	ptregscall_common
+	.endm
+
+	PTREGSCALL stub_clone, sys_clone
+	PTREGSCALL stub_fork, sys_fork
+	PTREGSCALL stub_vfork, sys_vfork
+	PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend
+	PTREGSCALL stub_sigaltstack, sys_sigaltstack
+	PTREGSCALL stub_iopl, sys_iopl
+
+ENTRY(ptregscall_common)
+	popq %r11
+	SAVE_REST
+	movq %r11, %r15
+	FIXUP_TOP_OF_STACK %r11
+	call *%rax
+	RESTORE_TOP_OF_STACK %r11
+	movq %r15, %r11
+	RESTORE_REST
+	pushq %r11
+	ret
+	
+ENTRY(stub_execve)
+	popq %r11
+	SAVE_REST
+	movq %r11, %r15
+	FIXUP_TOP_OF_STACK %r11
+	call sys_execve
+	GET_CURRENT(%rcx)
+	testl $ASM_THREAD_IA32,tsk_thread+thread_flags(%rcx)
+	jnz exec_32bit
+	RESTORE_TOP_OF_STACK %r11
+	movq %r15, %r11
+	RESTORE_REST
+	push %r11
+	ret
+
+exec_32bit:
+	movq %rax,RAX(%rsp)
+	RESTORE_REST
+	jmp int_ret_from_sys_call
+	
+/*
+ * sigreturn is special because it needs to restore all registers on return.
+ * This cannot be done with SYSRET, so use the IRET return path instead.
+ */                
+ENTRY(stub_rt_sigreturn)
+	addq $8, %rsp		
+	SAVE_REST
+	FIXUP_TOP_OF_STACK %r11
+	call sys_rt_sigreturn
+	movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
+	RESTORE_REST
+	jmp int_ret_from_sys_call
+
+/* 
+ * Interrupt entry/exit.
+ *
+ * Interrupt entry points save only callee clobbered registers, except
+ * for signals again.
+ *	
+ * Entry runs with interrupts off.	
+ */ 
+
+/* 0(%rsp): interrupt number */ 
+ENTRY(common_interrupt)
+	testl $3,16(%rsp)	# from kernel?
+	je   1f
+	swapgs
+1:	cld
+	SAVE_ARGS
+	leaq -ARGOFFSET(%rsp),%rdi	# arg1 for handler
+	addl $1,PDAREF(pda_irqcount)	# XXX: should be merged with irq.c irqcount
+	movq PDAREF(pda_irqstackptr),%rax
+	cmoveq %rax,%rsp
+	pushq %rdi			# save old stack
+	call do_IRQ
+	/* 0(%rsp): oldrsp-ARGOFFSET */ 
+ENTRY(ret_from_intr)
+	cli
+	popq  %rdi
+	subl $1,PDAREF(pda_irqcount)
+	leaq ARGOFFSET(%rdi),%rsp
+	testl $3,CS(%rdi)	# from kernel?
+	je	retint_restore_args
+	/* Interrupt came from user space */
+retint_with_reschedule:
+	GET_CURRENT(%rcx)
+	cmpq $0,tsk_need_resched(%rcx) 
+	jne retint_reschedule
+	cmpl $0,tsk_sigpending(%rcx)
+	jne retint_signal
+retint_restore_args_swapgs:		
+	swapgs
+retint_restore_args:				
+	RESTORE_ARGS 0,8						
+iret_label:	
+	iretq
+	.section __ex_table,"a"
+	.align 8
+	.quad iret_label,bad_iret
+	.previous
+	.section .fixup,"ax"
+	/* force a signal here? this matches i386 behaviour */
+bad_iret:
+	movq $-9999,%rdi	/* better code? */
+	jmp do_exit			
+	.previous	
+
+retint_signal:	
+	sti
+	SAVE_REST
+	movq $-1,ORIG_RAX(%rsp) 			
+	xorq %rsi,%rsi		# oldset
+	movq %rsp,%rdi		# &pt_regs
+	call do_signal
+	RESTORE_REST
+retint_signal_test:		
+	cli
+	GET_CURRENT(%rcx) 
+	cmpq $0,tsk_need_resched(%rcx) 
+	je   retint_restore_args_swapgs
+	sti
+	call schedule
+	jmp retint_signal_test			
+			
+retint_reschedule:
+	sti
+	call schedule
+	cli
+	jmp retint_with_reschedule
+		
+/*
+ * Exception entry points.
+ */ 		
+	.macro zeroentry sym
+	pushq $0	/* push error code/oldrax */ 
+	pushq %rax	/* push real oldrax to the rdi slot */ 
+	leaq  \sym(%rip),%rax
+	jmp error_entry
+	.endm	
+
+	.macro errorentry sym
+	pushq %rax
+	leaq  \sym(%rip),%rax
+	jmp error_entry
+	.endm
+
+/*
+ * Exception entry point. This expects an error code/orig_rax on the stack
+ * and the exception handler in %rax.	
+ */ 		  				
+ 	ALIGN
+error_entry:
+	/* rdi slot contains rax, oldrax contains error code */
+	pushq %rsi
+	movq  8(%rsp),%rsi	/* load rax */
+	pushq %rdx
+	pushq %rcx
+	pushq %rsi	/* store rax */ 
+	pushq %r8
+	pushq %r9
+	pushq %r10
+	pushq %r11
+	cld
+	SAVE_REST
+	testl $3,CS(%rsp)
+	je error_kernelspace
+	swapgs	
+	movl $1,%r15d	
+error_action:		
+	sti	
+	movq  %rdi,RDI(%rsp) 	
+	movq %rsp,%rdi
+	movq ORIG_RAX(%rsp),%rsi	/* get error code */ 
+	movq $-1,ORIG_RAX(%rsp)
+	call *%rax
+	/* r15d: swapgs flag */
+error_exit:
+	testl %r15d,%r15d
+	jz   error_restore
+error_test:		
+	cli	
+	GET_CURRENT(%rcx)
+	cmpq $0,tsk_need_resched(%rcx)
+	jne  error_reschedule
+	cmpl $0,tsk_sigpending(%rcx)
+	jne  error_signal
+error_restore_swapgs:					
+	swapgs
+error_restore:	
+	RESTORE_REST
+	jmp retint_restore_args
+	
+error_reschedule:
+	sti
+	call schedule
+	jmp  error_test
+
+error_signal:	
+	sti
+	xorq %rsi,%rsi
+	movq %rsp,%rdi
+	call do_signal
+error_signal_test:
+	GET_CURRENT(%rcx)	
+	cli
+	cmpq $0,tsk_need_resched(%rcx)
+	je   error_restore_swapgs
+	sti
+	call schedule
+	jmp  error_signal_test
+	
+error_kernelspace:	
+	xorl %r15d,%r15d
+	cmpq $iret_label,RIP(%rsp)
+	jne  error_action
+	movl $1,%r15d
+	swapgs
+	jmp error_action
+
+/*
+ * Create a kernel thread.
+ *
+ * C extern interface:
+ *	extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+ *
+ * asm input arguments:
+ *	rdi: fn, rsi: arg, rdx: flags
+ */
+ENTRY(kernel_thread)
+	FAKE_STACK_FRAME $child_rip
+	SAVE_ALL
+
+	# rdi: flags, rsi: usp, rdx: will be &pt_regs
+	movq %rdx,%rdi
+	orq  $CLONE_VM, %rdi
+
+	movq $-1, %rsi
+
+	movq %rsp, %rdx
+
+	# clone now
+	call do_fork
+	# save retval on the stack so it's popped before `ret`
+	movq %rax, RAX(%rsp)
+
+	/*
+	 * It isn't worth to check for reschedule here,
+	 * so internally to the x86_64 port you can rely on kernel_thread()
+	 * not to reschedule the child before returning, this avoids the need
+	 * of hacks for example to fork off the per-CPU idle tasks.
+         * [Hopefully no generic code relies on the reschedule -AK]	
+	 */
+	RESTORE_ALL
+	UNFAKE_STACK_FRAME
+	ret
+	
+child_rip:
+	/*
+	 * Here we are in the child and the registers are set as they were
+	 * at kernel_thread() invocation in the parent.
+	 */
+	movq %rdi, %rax
+	movq %rsi, %rdi
+	call *%rax
+	# exit
+	xorq %rdi, %rdi
+	call do_exit
+
+/*
+ * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
+ *
+ * C extern interface:
+ *	 extern long execve(char *name, char **argv, char **envp)
+ *
+ * asm input arguments:
+ *	rdi: name, rsi: argv, rdx: envp
+ *
+ * We want to fallback into:
+ *	extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
+ *
+ * do_sys_execve asm fallback arguments:
+ *	rdi: name, rsi: argv, rdx: envp, fake frame on the stack
+ */
+ENTRY(execve)
+	FAKE_STACK_FRAME $0
+	SAVE_ALL	
+	call sys_execve
+	movq %rax, RAX(%rsp)	
+	RESTORE_REST
+	testq %rax,%rax
+	je int_ret_from_sys_call
+	RESTORE_ARGS
+	UNFAKE_STACK_FRAME
+	ret
+
+ENTRY(page_fault)
+#ifdef CONFIG_KDB
+	pushq %rcx
+	pushq %rdx
+	pushq %rax
+	movl  $473,%ecx
+	rdmsr
+	andl  $0xfffffffe,%eax		/* Disable last branch recording */
+	wrmsr
+	popq  %rax
+	popq  %rdx
+	popq  %rcx
+#endif	
+	errorentry do_page_fault
+
+ENTRY(coprocessor_error)
+	zeroentry do_coprocessor_error
+
+ENTRY(simd_coprocessor_error)
+	zeroentry do_simd_coprocessor_error	
+
+ENTRY(device_not_available)
+	pushq $-1	
+	SAVE_ALL
+	xorl %r15d,%r15d
+	testl $3,CS(%rsp)
+	jz 1f
+	swapgs 
+	movl $1,%r15d
+1:	
+	movq  %cr0,%rax
+	leaq  math_state_restore(%rip),%rcx
+	leaq  math_emulate(%rip),%rbx
+	testl $0x4,%eax
+	cmoveq %rcx,%rbx
+	call  *%rbx
+	jmp  error_exit
+
+ENTRY(debug)
+	zeroentry do_debug
+
+ENTRY(nmi)
+	pushq $-1
+	SAVE_ALL
+	/* NMI could happen inside the critical section of a swapgs,
+	   so it is needed to use this expensive way to check.
+	   Rely on arch_prctl forbiding user space from setting a negative
+	   GS. Only the kernel value is negative. */
+	movl  $MSR_GS_BASE,%ecx
+	rdmsr
+	xorl  %ebx,%ebx
+	testl %edx,%edx
+	js    1f
+	swapgs
+	movl  $1,%ebx
+1:	movq %rsp,%rdi
+	call do_nmi
+	cli
+	testl %ebx,%ebx
+	jz error_restore
+	swapgs	
+	jmp error_restore
+	
+ENTRY(int3)
+	zeroentry do_int3	
+
+ENTRY(overflow)
+	zeroentry do_overflow
+
+ENTRY(bounds)
+	zeroentry do_bounds
+
+ENTRY(invalid_op)
+	zeroentry do_invalid_op	
+
+ENTRY(coprocessor_segment_overrun)
+	zeroentry do_coprocessor_segment_overrun
+
+ENTRY(reserved)
+	zeroentry do_reserved
+
+ENTRY(double_fault)
+	errorentry do_double_fault	
+
+ENTRY(invalid_TSS)
+	errorentry do_invalid_TSS
+
+ENTRY(segment_not_present)
+	errorentry do_segment_not_present
+
+ENTRY(stack_segment)
+	errorentry do_stack_segment
+
+ENTRY(general_protection)
+	errorentry do_general_protection
+
+ENTRY(alignment_check)
+	errorentry do_alignment_check
+
+ENTRY(divide_error)
+	zeroentry do_divide_error
+
+ENTRY(spurious_interrupt_bug)
+	zeroentry do_spurious_interrupt_bug
+
+ENTRY(machine_check)
+	zeroentry do_machine_check	
+
+ENTRY(call_debug)
+	zeroentry do_call_debug
+	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/head.S linux-2.4.20/arch/x86_64/kernel/head.S
--- linux-2.4.19/arch/x86_64/kernel/head.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/head.S	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,370 @@
+/*
+ *  linux/arch/x86_64/kernel/head.S -- start in 32bit and switch to 64bit
+ *
+ *  Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
+ *  Copyright (C) 2000 Pavel Machek <pavel@suse.cz>
+ *  Copyright (C) 2000 Karsten Keil <kkeil@suse.de>
+ *  Copyright (C) 2001,2002 Andi Kleen <ak@suse.de>
+ *
+ *  $Id: head.S,v 1.53 2002/07/18 09:49:42 ak Exp $
+ */
+
+
+#include <linux/linkage.h>
+#include <linux/threads.h>
+#include <asm/desc.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/msr.h>
+#include <asm/offset.h>
+	
+/* we are not able to switch in one step to the final KERNEL ADRESS SPACE
+ * because we need identity-mapped pages on setup so define __START_KERNEL to
+ * 0x100000 for this stage
+ * 
+ */
+
+	.text
+	.code32
+/* %bx:	 1 if comming from smp trampoline on secondary cpu */ 
+startup_32:
+	
+	/*
+	 * At this point the CPU runs in 32bit protected mode (CS.D = 1) with
+	 * paging disabled and the point of this file is to switch to 64bit
+	 * long mode with a kernel mapping for kerneland to jump into the
+	 * kernel virtual addresses.
+ 	 * There is no stack until we set one up.
+	 */
+
+	movl %ebx,%ebp	/* Save trampoline flag */
+	
+	/* First check if extended functions are implemented */
+	movl	$0x80000000, %eax
+	cpuid
+	cmpl	$0x80000000, %eax
+	jbe	no_long_mode
+	/* Check if long mode is implemented */
+	mov	$0x80000001, %eax
+	cpuid
+	btl	$29, %edx
+	jnc	no_long_mode
+
+	movl	%edx,%edi
+	
+	/*
+	 * Prepare for entering 64bits mode
+	 */
+
+	/* Enable PAE mode and PGE */
+	xorl	%eax, %eax
+	btsl	$5, %eax
+	btsl	$7, %eax
+	movl	%eax, %cr4
+	
+	/* Setup early boot stage 4 level pagetables */
+	movl	$0x101000, %eax
+	movl	%eax, %cr3
+
+	/* Setup EFER (Extended Feature Enable Register) */
+	movl	$MSR_EFER, %ecx
+	rdmsr
+	/* Fool rdmsr and reset %eax to avoid dependences */
+	xorl	%eax, %eax
+	/* Enable Long Mode */
+	btsl	$_EFER_LME, %eax
+	/* Enable System Call */
+	btsl	$_EFER_SCE, %eax
+
+#if 0
+	/* No Execute supported? */	
+	btl	$20,%edi
+	jnc     1f
+	btsl	$_EFER_NX, %eax
+1:
+#endif
+	
+	/* Make changes effective */
+	wrmsr
+
+	xorl	%eax, %eax
+	/* Enable paging and in turn activate Long Mode */
+	btsl	$31, %eax
+	/* Enable protected mode */
+	btsl	$0, %eax
+	/* Enable MP */
+	btsl	$1, %eax
+	/* Enable ET */
+	btsl	$4, %eax
+	/* Enable NE */
+	btsl	$5, %eax
+	/* Enable WP */
+	btsl	$16, %eax
+	/* Enable AM */
+	btsl	$18, %eax
+	/* Make changes effective */
+	movl	%eax, %cr0
+	jmp	reach_compatibility_mode
+reach_compatibility_mode:
+	
+	/*
+	 * At this point we're in long mode but in 32bit compatibility mode
+	 * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
+	 * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we load
+	 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
+	 */
+
+	testw %bp,%bp	/* secondary CPU? */ 
+	jnz   second	
+	
+	/* Load new GDT with the 64bit segment using 32bit descriptor */
+	/* to avoid 32bit relocations we use fixed adresses here */
+	movl	$0x100F00, %eax
+	lgdt	(%eax)
+
+	movl    $0x100F10, %eax
+	/* Finally jump in 64bit mode */
+	ljmp	*(%eax)
+
+second:
+	/* abuse syscall to get into 64bit mode. this way we don't need
+	   a working low identity mapping just for the short 32bit roundtrip. 
+	   XXX kludge. this should not be needed. */
+	movl  $MSR_STAR,%ecx
+	xorl  %eax,%eax
+	movl  $(__USER32_CS<<16)|__KERNEL_CS,%edx
+	wrmsr
+
+	movl  $MSR_CSTAR,%ecx
+	movl  $0xffffffff,%edx
+	movl  $0x80100100,%eax	# reach_long64 absolute
+	wrmsr
+	syscall
+
+	.code64
+	.org 0x100	
+reach_long64:
+	movq init_rsp(%rip),%rsp
+	
+	/* zero EFLAGS after setting rsp */
+	pushq $0
+	popfq
+
+	/*
+	 * We must switch to a new descriptor in kernel space for the GDT
+	 * because soon the kernel won't have access anymore to the userspace
+	 * addresses where we're currently running on. We have to do that here
+	 * because in 32bit we couldn't load a 64bit linear address.
+	 */
+	lgdt	pGDT64
+
+	/* 
+	 * Setup up a dummy PDA. this is just for some early bootup code
+	 * that does in_interrupt() 
+	 */ 
+	movl	$MSR_GS_BASE,%ecx
+	movq	$cpu_pda,%rax
+	movq    %rax,%rdx
+	shrq	$32,%rdx
+	wrmsr	
+
+	/* set up data segments. actually 0 would do too */	
+	movl $__KERNEL_DS,%eax
+	movl %eax,%ds
+	movl %eax,%ss
+	movl %eax,%es
+
+	/* esi is pointer to real mode structure with interesting info.
+	   pass it to C */
+	movl	%esi, %edi
+	
+	/* Finally jump to run C code and to be on real kernel address
+	 * Since we are running on identity-mapped space we have to jump
+	 * to the full 64bit address , this is only possible as indirect
+	 * jump
+	 */
+	movq	initial_code(%rip),%rax
+	jmp	*%rax
+
+	/* SMP bootup changes these two */	
+	.globl	initial_code
+initial_code:
+	.quad	x86_64_start_kernel
+	.globl init_rsp
+init_rsp:
+	.quad  init_task_union+THREAD_SIZE-8
+
+	
+.code32
+ENTRY(no_long_mode)
+	/* This isn't an x86-64 CPU so hang */
+1:
+	jmp	1b	
+	
+.org 0xf00
+pGDT32:
+	.word	gdt32_end-gdt_table32
+	.long	gdt_table32-__START_KERNEL+0x100000
+
+.org 0xf10	
+ljumpvector:
+	.long	reach_long64-__START_KERNEL+0x100000
+	.word	__KERNEL_CS
+
+ENTRY(stext)
+ENTRY(_stext)
+
+	/*
+	 * This default setting generates an ident mapping at address 0x100000
+	 * and a mapping for the kernel that precisely maps virtual address
+	 * 0xffffffff80000000 to physical address 0x000000. (always using
+	 * 2Mbyte large pages provided by PAE mode)
+	 */
+.org 0x1000
+ENTRY(init_level4_pgt)
+	.quad	0x0000000000102007		/* -> level3_ident_pgt */
+	.fill	255,8,0
+	.quad	0x000000000010a007
+	.fill	254,8,0
+	/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
+	.quad	0x0000000000103007		/* -> level3_kernel_pgt */
+
+.org 0x2000
+/* Kernel does not "know" about 4-th level of page tables. */
+ENTRY(level3_ident_pgt)
+	.quad	0x0000000000104007
+	.fill	511,8,0
+	
+.org 0x3000
+ENTRY(level3_kernel_pgt)
+	.fill	510,8,0
+	/* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
+	.quad	0x0000000000105007		/* -> level2_kernel_pgt */
+	.fill	1,8,0
+
+.org 0x4000
+ENTRY(level2_ident_pgt)
+	/* 40MB for bootup. 	*/
+	.quad	0x0000000000000283
+	.quad	0x0000000000200183
+	.quad	0x0000000000400183
+	.quad	0x0000000000600183
+	.quad	0x0000000000800183
+	.quad	0x0000000000A00183
+	.quad	0x0000000000C00183
+	.quad	0x0000000000E00183
+	.quad	0x0000000001000183
+	.quad	0x0000000001200183
+	.quad	0x0000000001400183
+	.quad	0x0000000001600183
+	.quad	0x0000000001800183
+	.quad	0x0000000001A00183
+	.quad	0x0000000001C00183
+	.quad	0x0000000001E00183
+	.quad	0x0000000002000183
+	.quad	0x0000000002200183
+	.quad	0x0000000002400183
+	.quad	0x0000000002600183
+	/* Temporary mappings for the super early allocator in arch/x86_64/mm/init.c */
+	.globl temp_boot_pmds
+temp_boot_pmds:
+	.fill	492,8,0
+		
+.org 0x5000
+ENTRY(level2_kernel_pgt)
+	/* 40MB kernel mapping. The kernel code cannot be bigger than that.
+	   When you change this change KERNEL_TEXT_SIZE in pgtable.h too. */
+	/* (2^48-(2*1024*1024*1024)-((2^39)*511)-((2^30)*510)) = 0 */
+	.quad	0x0000000000000183
+	.quad	0x0000000000200183
+	.quad	0x0000000000400183
+	.quad	0x0000000000600183
+	.quad	0x0000000000800183
+	.quad	0x0000000000A00183
+	.quad	0x0000000000C00183
+	.quad	0x0000000000E00183
+	.quad	0x0000000001000183
+	.quad	0x0000000001200183
+	.quad	0x0000000001400183
+	.quad	0x0000000001600183
+	.quad	0x0000000001800183
+	.quad	0x0000000001A00183
+	.quad	0x0000000001C00183
+	.quad	0x0000000001E00183
+	.quad	0x0000000002000183
+	.quad	0x0000000002200183
+	.quad	0x0000000002400183
+	.quad	0x0000000002600183
+	/* Module mapping starts here */
+	.fill	492,8,0
+
+.org 0x6000
+ENTRY(empty_zero_page)
+
+.org 0x7000
+ENTRY(empty_bad_page)
+
+.org 0x8000
+ENTRY(empty_bad_pte_table)
+
+.org 0x9000
+ENTRY(empty_bad_pmd_table)
+
+.org 0xa000
+ENTRY(level3_physmem_pgt)
+	.quad	0x0000000000105007		/* -> level2_kernel_pgt (so that __va works even before pagetable_init) */
+
+.org 0xb000
+.data
+
+.globl SYMBOL_NAME(gdt)
+
+	.word 0
+	.align 16
+	.word 0
+pGDT64:
+	.word	gdt_end-gdt_table
+SYMBOL_NAME_LABEL(gdt)
+	.quad	gdt_table
+	
+
+.align 64 /* cacheline aligned */
+ENTRY(gdt_table32)
+	.quad	0x0000000000000000	/* This one is magic */
+	.quad	0x0000000000000000	/* unused */
+	.quad	0x00af9a000000ffff	/* __KERNEL_CS */
+gdt32_end:	
+	
+/* We need valid kernel segments for data and code in long mode too
+ * IRET will check the segment types  kkeil 2000/10/28
+ * Also sysret mandates a special GDT layout 
+ */
+		 		
+.align 64 /* cacheline aligned, keep this synchronized with asm/desc.h */
+ENTRY(gdt_table)
+	.quad	0x0000000000000000	/* This one is magic */
+	.quad	0x0000000000000000	/* unused */
+	.quad	0x00af9a000000ffff	/* __KERNEL_CS */
+	.quad	0x00cf92000000ffff	/* __KERNEL_DS */
+	.quad	0x00cffe000000ffff	/* __USER32_CS */
+	.quad	0x00cff2000000ffff	/* __USER_DS, __USER32_DS  */		
+	.quad	0x00affa000000ffff	/* __USER_CS */
+	.word	0xFFFF				# 4Gb - (0x100000*0x1000 = 4Gb)
+	.word	0				# base address = 0
+	.word	0x9A00				# code read/exec
+	.word	0x00CF				# granularity = 4096, 386
+						#  (+5th nibble of limit)
+					/* __KERNEL32_CS */
+	/* when you add something here fix constant in desc.h */				
+	.globl gdt_cpu_table
+gdt_cpu_table:	
+	.fill NR_CPUS*PER_CPU_GDT_SIZE,1,0
+gdt_end:	
+	.globl gdt_end
+
+	.align  64
+ENTRY(idt_table)	
+	.rept   256
+	.quad   0
+	.quad 	0
+	.endr		
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/head64.c linux-2.4.20/arch/x86_64/kernel/head64.c
--- linux-2.4.19/arch/x86_64/kernel/head64.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/head64.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,87 @@
+/*
+ *  linux/arch/x86_64/kernel/head64.c -- prepare to run common code
+ *
+ *  Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
+ *
+ *  $Id: head64.c,v 1.25 2002/07/01 08:01:19 ak Exp $
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/processor.h>
+#include <asm/proto.h>
+
+static void __init clear_bss(void)
+{
+	extern char __bss_start[], __bss_end[];
+	printk("Clearing %ld bytes of bss...", (unsigned long) __bss_end - (unsigned long) __bss_start);
+	memset(__bss_start, 0,
+	       (unsigned long) __bss_end - (unsigned long) __bss_start);
+	printk("ok\n");
+}
+
+extern char x86_boot_params[2048];
+
+#define NEW_CL_POINTER		0x228	/* Relative to real mode data */
+#define OLD_CL_MAGIC_ADDR	0x90020
+#define OLD_CL_MAGIC            0xA33F
+#define OLD_CL_BASE_ADDR        0x90000
+#define OLD_CL_OFFSET           0x90022
+
+extern char saved_command_line[];
+
+static void __init copy_bootdata(char *real_mode_data)
+{
+	int new_data;
+	char * command_line;
+
+	memcpy(x86_boot_params, real_mode_data, 2048); 
+	new_data = *(int *) (x86_boot_params + NEW_CL_POINTER);
+	if (!new_data) {
+		if (OLD_CL_MAGIC != * (u16 *) OLD_CL_MAGIC_ADDR) {
+			printk("so old bootloader that it does not support commandline?!\n");
+			return;
+		}
+		new_data = OLD_CL_BASE_ADDR + * (u16 *) OLD_CL_OFFSET;
+		printk("old bootloader convention, maybe loadlin?\n");
+	}
+	command_line = (char *) ((u64)(new_data));
+	memcpy(saved_command_line, command_line, 2048);
+	printk("Bootdata ok (command line is %s)\n", saved_command_line);	
+}
+
+static void __init setup_boot_cpu_data(void)
+{
+	int dummy, eax;
+
+	/* get vendor info */
+	cpuid(0, &boot_cpu_data.cpuid_level,
+	      (int *)&boot_cpu_data.x86_vendor_id[0],
+	      (int *)&boot_cpu_data.x86_vendor_id[8],
+	      (int *)&boot_cpu_data.x86_vendor_id[4]);
+
+	/* get cpu type */
+	cpuid(1, &eax, &dummy, &dummy, (int *) &boot_cpu_data.x86_capability);
+	boot_cpu_data.x86 = (eax >> 8) & 0xf;
+	boot_cpu_data.x86_model = (eax >> 4) & 0xf;
+	boot_cpu_data.x86_mask = eax & 0xf;
+}
+
+void __init x86_64_start_kernel(char * real_mode_data)
+{
+	char *s; 
+
+	clear_bss(); /* must be the first thing in C and must not depend on .bss to be zero */
+	pda_init(0); 
+	copy_bootdata(real_mode_data);
+	s = strstr(saved_command_line, "earlyprintk="); 
+	if (s != NULL)
+		setup_early_printk(s+12); 
+	early_printk("booting x86_64 kernel... ");
+	setup_boot_cpu_data();
+	start_kernel();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/i387.c linux-2.4.20/arch/x86_64/kernel/i387.c
--- linux-2.4.19/arch/x86_64/kernel/i387.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/i387.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,113 @@
+/*
+ *  linux/arch/x86_64/kernel/i387.c
+ *
+ *  Copyright (C) 1994 Linus Torvalds
+ *  Copyright (C) 2002 Andi Kleen, SuSE Labs
+ *
+ *  Pentium III FXSR, SSE support
+ *  General FPU state handling cleanups
+ *	Gareth Hughes <gareth@valinux.com>, May 2000
+ * 
+ *  x86-64 rework 2002 Andi Kleen. 
+ *  Does direct fxsave in and out of user space now for signal handlers.
+ *  All the FSAVE<->FXSAVE conversion code has been moved to the 32bit emulation,
+ *  the 64bit user space sees a FXSAVE frame directly. 
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <asm/processor.h>
+#include <asm/i387.h>
+#include <asm/sigcontext.h>
+#include <asm/user.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+
+extern int exception_trace;
+
+/*
+ * The _current_ task is using the FPU for the first time
+ * so initialize it and set the mxcsr to its default
+ * value at reset if we support XMM instructions and then
+ * remeber the current task has used the FPU.
+ */
+void init_fpu(void)
+{
+	struct task_struct *me = current;
+	memset(&me->thread.i387.fxsave, 0, sizeof(struct i387_fxsave_struct));
+	me->thread.i387.fxsave.cwd = 0x37f;
+	me->thread.i387.fxsave.mxcsr = 0x1f80;
+	me->used_math = 1;
+}
+
+/*
+ * Signal frame handlers.
+ */
+
+int save_i387(struct _fpstate *buf)
+{
+	struct task_struct *tsk = current;
+	int err = 0;
+
+	{ 
+		extern void bad_user_i387_struct(void); 
+		if (sizeof(struct user_i387_struct) != sizeof(tsk->thread.i387.fxsave))
+			bad_user_i387_struct();
+	} 
+
+	if (!tsk->used_math) 
+		return 0; 
+	tsk->used_math = 0; /* trigger finit */ 
+	if (tsk->flags & PF_USEDFPU) { 
+		err = save_i387_checking((struct i387_fxsave_struct *)buf);
+		if (err) { 
+			if (exception_trace) 
+				printk("%s[%d] unaligned signal floating point context %p\n", 
+					tsk->comm, tsk->pid, buf); 
+			return err;
+		}
+		stts();
+	} else { 
+		if (__copy_to_user(buf, &tsk->thread.i387.fxsave, 
+				   sizeof(struct i387_fxsave_struct)))
+			return -1;
+	} 
+	return 1; 
+}
+
+/*
+ * ptrace request handlers.
+ */
+
+int get_fpregs(struct user_i387_struct *buf, struct task_struct *tsk)
+{
+	empty_fpu(tsk);
+	return __copy_to_user((void *)buf, &tsk->thread.i387.fxsave,
+			       sizeof(struct user_i387_struct)) ? -EFAULT : 0;
+}
+
+int set_fpregs(struct task_struct *tsk, struct user_i387_struct *buf)
+{	
+	if (__copy_from_user(&tsk->thread.i387.fxsave, buf, 
+			     sizeof(struct user_i387_struct)))
+		return -EFAULT;
+	/* mxcsr bit 6 and 31-16 must be zero for security reasons. */
+	tsk->thread.i387.fxsave.mxcsr &= 0xffbf;
+	return 0;
+}
+
+/*
+ * FPU state for core dumps.
+ */
+
+int dump_fpu( struct pt_regs *regs, struct user_i387_struct *fpu )
+{
+	struct task_struct *tsk = current;
+
+	if (!tsk->used_math) 
+		return 0;
+	unlazy_fpu(tsk);
+
+	memcpy(fpu, &tsk->thread.i387.fxsave, sizeof(struct user_i387_struct)); 
+	return 1; 
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/i8259.c linux-2.4.20/arch/x86_64/kernel/i8259.c
--- linux-2.4.19/arch/x86_64/kernel/i8259.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/i8259.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,464 @@
+#include <linux/linkage.h>
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hw_irq.h>
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+#include <asm/delay.h>
+#include <asm/desc.h>
+#include <asm/apic.h>
+
+#include <linux/irq.h>
+
+/* When we have things working, we can switch to always use
+   IOAPIC. --pavel */
+
+/*
+ * Common place to define all x86 IRQ vectors
+ *
+ * This builds up the IRQ handler stubs using some ugly macros in irq.h
+ *
+ * These macros create the low-level assembly IRQ routines that save
+ * register context and call do_IRQ(). do_IRQ() then does all the
+ * operations that are needed to keep the AT (or SMP IOAPIC)
+ * interrupt-controller happy.
+ */
+
+BUILD_COMMON_IRQ()
+
+#define BI(x,y) \
+	BUILD_IRQ(x##y)
+
+#define BUILD_16_IRQS(x) \
+	BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
+	BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
+	BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
+	BI(x,c) BI(x,d) BI(x,e) BI(x,f)
+
+/*
+ * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
+ * (these are usually mapped to vectors 0x20-0x2f)
+ */
+BUILD_16_IRQS(0x0)
+
+#ifdef CONFIG_X86_IO_APIC
+/*
+ * The IO-APIC gives us many more interrupt sources. Most of these
+ * are unused but an SMP system is supposed to have enough memory ...
+ * sometimes (mostly wrt. hw bugs) we get corrupted vectors all
+ * across the spectrum, so we really want to be prepared to get all
+ * of these. Plus, more powerful systems might have more than 64
+ * IO-APIC registers.
+ *
+ * (these are usually mapped into the 0x30-0xff vector range)
+ */
+		   BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
+BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
+BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
+BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd)
+#endif
+
+#undef BUILD_16_IRQS
+#undef BI
+
+
+/*
+ * The following vectors are part of the Linux architecture, there
+ * is no hardware IRQ pin equivalent for them, they are triggered
+ * through the ICC by us (IPIs)
+ */
+#ifdef CONFIG_SMP
+BUILD_SMP_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR);
+BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR);
+BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR);
+#endif
+
+#ifdef CONFIG_X86_LOCAL_APIC
+BUILD_SMP_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR);
+BUILD_SMP_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR);
+BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR);
+#endif
+
+#define IRQ(x,y) \
+	IRQ##x##y##_interrupt
+
+#define IRQLIST_16(x) \
+	IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
+	IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
+	IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
+	IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
+
+void (*interrupt[NR_IRQS])(void) = {
+	IRQLIST_16(0x0),
+
+#ifdef CONFIG_X86_IO_APIC
+			 IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3),
+	IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
+	IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
+	IRQLIST_16(0xc), IRQLIST_16(0xd)
+#endif
+};
+
+#undef IRQ
+#undef IRQLIST_16
+
+/*
+ * This is the 'legacy' 8259A Programmable Interrupt Controller,
+ * present in the majority of PC/AT boxes.
+ * plus some generic x86 specific things if generic specifics makes
+ * any sense at all.
+ * this file should become arch/i386/kernel/irq.c when the old irq.c
+ * moves to arch independent land
+ */
+
+spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED;
+
+static void end_8259A_irq (unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		enable_8259A_irq(irq);
+}
+
+#define shutdown_8259A_irq	disable_8259A_irq
+
+ void mask_and_ack_8259A(unsigned int);
+
+static unsigned int startup_8259A_irq(unsigned int irq)
+{
+	enable_8259A_irq(irq);
+	return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type i8259A_irq_type = {
+	"XT-PIC",
+	startup_8259A_irq,
+	shutdown_8259A_irq,
+	enable_8259A_irq,
+	disable_8259A_irq,
+	mask_and_ack_8259A,
+	end_8259A_irq,
+	NULL
+};
+
+/*
+ * 8259A PIC functions to handle ISA devices:
+ */
+
+/*
+ * This contains the irq mask for both 8259A irq controllers,
+ */
+static unsigned int cached_irq_mask = 0xffff;
+
+#define __byte(x,y)	(((unsigned char *)&(y))[x])
+#define cached_21	(__byte(0,cached_irq_mask))
+#define cached_A1	(__byte(1,cached_irq_mask))
+
+/*
+ * Not all IRQs can be routed through the IO-APIC, eg. on certain (older)
+ * boards the timer interrupt is not really connected to any IO-APIC pin,
+ * it's fed to the master 8259A's IR0 line only.
+ *
+ * Any '1' bit in this mask means the IRQ is routed through the IO-APIC.
+ * this 'mixed mode' IRQ handling costs nothing because it's only used
+ * at IRQ setup time.
+ */
+unsigned long io_apic_irqs;
+
+void disable_8259A_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8259A_lock, flags);
+	cached_irq_mask |= mask;
+	if (irq & 8)
+		outb(cached_A1,0xA1);
+	else
+		outb(cached_21,0x21);
+	spin_unlock_irqrestore(&i8259A_lock, flags);
+}
+
+void enable_8259A_irq(unsigned int irq)
+{
+	unsigned int mask = ~(1 << irq);
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8259A_lock, flags);
+	cached_irq_mask &= mask;
+	if (irq & 8)
+		outb(cached_A1,0xA1);
+	else
+		outb(cached_21,0x21);
+	spin_unlock_irqrestore(&i8259A_lock, flags);
+}
+
+int i8259A_irq_pending(unsigned int irq)
+{
+	unsigned int mask = 1<<irq;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&i8259A_lock, flags);
+	if (irq < 8)
+		ret = inb(0x20) & mask;
+	else
+		ret = inb(0xA0) & (mask >> 8);
+	spin_unlock_irqrestore(&i8259A_lock, flags);
+
+	return ret;
+}
+
+void make_8259A_irq(unsigned int irq)
+{
+	disable_irq_nosync(irq);
+	io_apic_irqs &= ~(1<<irq);
+	irq_desc[irq].handler = &i8259A_irq_type;
+	enable_irq(irq);
+}
+
+/*
+ * This function assumes to be called rarely. Switching between
+ * 8259A registers is slow.
+ * This has to be protected by the irq controller spinlock
+ * before being called.
+ */
+static inline int i8259A_irq_real(unsigned int irq)
+{
+	int value;
+	int irqmask = 1<<irq;
+
+	if (irq < 8) {
+		outb(0x0B,0x20);		/* ISR register */
+		value = inb(0x20) & irqmask;
+		outb(0x0A,0x20);		/* back to the IRR register */
+		return value;
+	}
+	outb(0x0B,0xA0);		/* ISR register */
+	value = inb(0xA0) & (irqmask >> 8);
+	outb(0x0A,0xA0);		/* back to the IRR register */
+	return value;
+}
+
+/*
+ * Careful! The 8259A is a fragile beast, it pretty
+ * much _has_ to be done exactly like this (mask it
+ * first, _then_ send the EOI, and the order of EOI
+ * to the two 8259s is important!
+ */
+void mask_and_ack_8259A(unsigned int irq)
+{
+	unsigned int irqmask = 1 << irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8259A_lock, flags);
+	/*
+	 * Lightweight spurious IRQ detection. We do not want
+	 * to overdo spurious IRQ handling - it's usually a sign
+	 * of hardware problems, so we only do the checks we can
+	 * do without slowing down good hardware unnecesserily.
+	 *
+	 * Note that IRQ7 and IRQ15 (the two spurious IRQs
+	 * usually resulting from the 8259A-1|2 PICs) occur
+	 * even if the IRQ is masked in the 8259A. Thus we
+	 * can check spurious 8259A IRQs without doing the
+	 * quite slow i8259A_irq_real() call for every IRQ.
+	 * This does not cover 100% of spurious interrupts,
+	 * but should be enough to warn the user that there
+	 * is something bad going on ...
+	 */
+	if (cached_irq_mask & irqmask)
+		goto spurious_8259A_irq;
+	cached_irq_mask |= irqmask;
+
+handle_real_irq:
+	if (irq & 8) {
+		inb(0xA1);		/* DUMMY - (do we need this?) */
+		outb(cached_A1,0xA1);
+		outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */
+		outb(0x62,0x20);	/* 'Specific EOI' to master-IRQ2 */
+	} else {
+		inb(0x21);		/* DUMMY - (do we need this?) */
+		outb(cached_21,0x21);
+		outb(0x60+irq,0x20);	/* 'Specific EOI' to master */
+	}
+	spin_unlock_irqrestore(&i8259A_lock, flags);
+	return;
+
+spurious_8259A_irq:
+	/*
+	 * this is the slow path - should happen rarely.
+	 */
+	if (i8259A_irq_real(irq))
+		/*
+		 * oops, the IRQ _is_ in service according to the
+		 * 8259A - not spurious, go handle it.
+		 */
+		goto handle_real_irq;
+
+	{
+		static int spurious_irq_mask;
+		/*
+		 * At this point we can be sure the IRQ is spurious,
+		 * lets ACK and report it. [once per IRQ]
+		 */
+		if (!(spurious_irq_mask & irqmask)) {
+			printk("spurious 8259A interrupt: IRQ%d.\n", irq);
+			spurious_irq_mask |= irqmask;
+		}
+		atomic_inc(&irq_err_count);
+		/*
+		 * Theoretically we do not have to handle this IRQ,
+		 * but in Linux this does not cause problems and is
+		 * simpler for us.
+		 */
+		goto handle_real_irq;
+	}
+}
+
+void __init init_8259A(int auto_eoi)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8259A_lock, flags);
+
+	outb(0xff, 0x21);	/* mask all of 8259A-1 */
+	outb(0xff, 0xA1);	/* mask all of 8259A-2 */
+
+	/*
+	 * outb_p - this has to work on a wide range of PC hardware.
+	 */
+	outb_p(0x11, 0x20);	/* ICW1: select 8259A-1 init */
+	outb_p(0x20 + 0, 0x21);	/* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */
+	outb_p(0x04, 0x21);	/* 8259A-1 (the master) has a slave on IR2 */
+	if (auto_eoi)
+		outb_p(0x03, 0x21);	/* master does Auto EOI */
+	else
+		outb_p(0x01, 0x21);	/* master expects normal EOI */
+
+	outb_p(0x11, 0xA0);	/* ICW1: select 8259A-2 init */
+	outb_p(0x20 + 8, 0xA1);	/* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */
+	outb_p(0x02, 0xA1);	/* 8259A-2 is a slave on master's IR2 */
+	outb_p(0x01, 0xA1);	/* (slave's support for AEOI in flat mode
+				    is to be investigated) */
+
+	if (auto_eoi)
+		/*
+		 * in AEOI mode we just have to mask the interrupt
+		 * when acking.
+		 */
+		i8259A_irq_type.ack = disable_8259A_irq;
+	else
+		i8259A_irq_type.ack = mask_and_ack_8259A;
+
+	udelay(100);		/* wait for 8259A to initialize */
+
+	outb(cached_21, 0x21);	/* restore master IRQ mask */
+	outb(cached_A1, 0xA1);	/* restore slave IRQ mask */
+
+	spin_unlock_irqrestore(&i8259A_lock, flags);
+}
+
+/*
+ * IRQ2 is cascade interrupt to second interrupt controller
+ */
+
+static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL};
+
+void __init init_ISA_irqs (void)
+{
+	int i;
+
+#ifdef CONFIG_X86_LOCAL_APIC
+	init_bsp_APIC();
+#endif
+	init_8259A(0);
+
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].action = 0;
+		irq_desc[i].depth = 1;
+
+		if (i < 16) {
+			/*
+			 * 16 old-style INTA-cycle interrupts:
+			 */
+			irq_desc[i].handler = &i8259A_irq_type;
+		} else {
+			/*
+			 * 'high' PCI IRQs filled in on demand
+			 */
+			irq_desc[i].handler = &no_irq_type;
+		}
+	}
+}
+
+void __init init_IRQ(void)
+{
+	int i;
+
+#ifndef CONFIG_X86_VISWS_APIC
+	init_ISA_irqs();
+#else
+	init_VISWS_APIC_irqs();
+#endif
+	/*
+	 * Cover the whole vector space, no vector can escape
+	 * us. (some of these will be overridden and become
+	 * 'special' SMP interrupts)
+	 */
+	for (i = 0; i < NR_IRQS; i++) {
+		int vector = FIRST_EXTERNAL_VECTOR + i;
+		if (vector != IA32_SYSCALL_VECTOR && vector != KDBENTER_VECTOR) {
+			set_intr_gate(vector, interrupt[i]);
+		}
+	}
+
+#ifdef CONFIG_SMP
+	/*
+	 * IRQ0 must be given a fixed assignment and initialized,
+	 * because it's used before the IO-APIC is set up.
+	 */
+	set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
+
+	/*
+	 * The reschedule interrupt is a CPU-to-CPU reschedule-helper
+	 * IPI, driven by wakeup.
+	 */
+	set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
+
+	/* IPI for invalidation */
+	set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
+
+	/* IPI for generic function call */
+	set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
+#endif
+
+#ifdef CONFIG_X86_LOCAL_APIC
+	/* self generated IPI for local APIC timer */
+	set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
+
+	/* IPI vectors for APIC spurious and error interrupts */
+	set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
+	set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
+#endif
+
+#ifndef CONFIG_VISWS
+	setup_irq(2, &irq2);
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/init_task.c linux-2.4.20/arch/x86_64/kernel/init_task.c
--- linux-2.4.19/arch/x86_64/kernel/init_task.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/init_task.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,38 @@
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/config.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/desc.h>
+
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM(init_mm);
+
+/*
+ * Initial task structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry..
+ */
+union task_union init_task_union 
+	__attribute__((__section__(".data.init_task"))) =
+		{ INIT_TASK(init_task_union.task) };
+
+/*
+ * per-CPU TSS segments. Threads are completely 'soft' on Linux,
+ * no more per-task TSS's. The TSS size is kept cacheline-aligned
+ * so they are allowed to end up in the .data.cacheline_aligned
+ * section. Since TSS's are completely CPU-local, we want them
+ * on exact cacheline boundaries, to eliminate cacheline ping-pong.
+ */ 
+struct tss_struct init_tss[NR_CPUS] __cacheline_aligned;
+
+
+#define ALIGN_TO_4K __attribute__((section(".data.init_task")))
+
+pgd_t boot_vmalloc_pgt[512]  ALIGN_TO_4K;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/io_apic.c linux-2.4.20/arch/x86_64/kernel/io_apic.c
--- linux-2.4.19/arch/x86_64/kernel/io_apic.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/io_apic.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,1651 @@
+/*
+ *	Intel IO-APIC support for multi-Pentium hosts.
+ *
+ *	Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar, Hajnalka Szabo
+ *
+ *	Many thanks to Stig Venaas for trying out countless experimental
+ *	patches and reporting/debugging problems patiently!
+ *
+ *	(c) 1999, Multiple IO-APIC support, developed by
+ *	Ken-ichi Yaku <yaku@css1.kbnes.nec.co.jp> and
+ *      Hidemi Kishimoto <kisimoto@css1.kbnes.nec.co.jp>,
+ *	further tested and cleaned up by Zach Brown <zab@redhat.com>
+ *	and Ingo Molnar <mingo@redhat.com>
+ *
+ *	Fixes
+ *	Maciej W. Rozycki	:	Bits for genuine 82489DX APICs;
+ *					thanks to Eric Gilmore
+ *					and Rolf G. Tews
+ *					for testing these extensively
+ */
+
+#include <linux/mm.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/config.h>
+#include <linux/smp_lock.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/desc.h>
+
+#undef APIC_LOCKUP_DEBUG
+
+#define APIC_LOCKUP_DEBUG
+
+static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * # of IRQ routing registers
+ */
+int nr_ioapic_registers[MAX_IO_APICS];
+
+/*
+ * Rough estimation of how many shared IRQs there are, can
+ * be changed anytime.
+ */
+#define MAX_PLUS_SHARED_IRQS NR_IRQS
+#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
+
+/*
+ * This is performance-critical, we want to do it O(1)
+ *
+ * the indexing order of this array favors 1:1 mappings
+ * between pins and IRQs.
+ */
+
+static struct irq_pin_list {
+	int apic, pin, next;
+} irq_2_pin[PIN_MAP_SIZE];
+
+/*
+ * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
+ * shared ISA-space IRQs, so we have to support them. We are super
+ * fast in the common case, and fast for shared ISA-space IRQs.
+ */
+static void __init add_pin_to_irq(unsigned int irq, int apic, int pin)
+{
+	static int first_free_entry = NR_IRQS;
+	struct irq_pin_list *entry = irq_2_pin + irq;
+
+	while (entry->next)
+		entry = irq_2_pin + entry->next;
+
+	if (entry->pin != -1) {
+		entry->next = first_free_entry;
+		entry = irq_2_pin + entry->next;
+		if (++first_free_entry >= PIN_MAP_SIZE)
+			panic("io_apic.c: whoops");
+	}
+	entry->apic = apic;
+	entry->pin = pin;
+}
+
+/*
+ * Reroute an IRQ to a different pin.
+ */
+static void __init replace_pin_at_irq(unsigned int irq,
+				      int oldapic, int oldpin,
+				      int newapic, int newpin)
+{
+	struct irq_pin_list *entry = irq_2_pin + irq;
+
+	while (1) {
+		if (entry->apic == oldapic && entry->pin == oldpin) {
+			entry->apic = newapic;
+			entry->pin = newpin;
+		}
+		if (!entry->next)
+			break;
+		entry = irq_2_pin + entry->next;
+	}
+}
+
+#define __DO_ACTION(R, ACTION, FINAL)					\
+									\
+{									\
+	int pin;							\
+	struct irq_pin_list *entry = irq_2_pin + irq;			\
+									\
+	for (;;) {							\
+		unsigned int reg;					\
+		pin = entry->pin;					\
+		if (pin == -1)						\
+			break;						\
+		reg = io_apic_read(entry->apic, 0x10 + R + pin*2);	\
+		reg ACTION;						\
+		io_apic_modify(entry->apic, reg);			\
+		if (!entry->next)					\
+			break;						\
+		entry = irq_2_pin + entry->next;			\
+	}								\
+	FINAL;								\
+}
+
+#define DO_ACTION(name,R,ACTION, FINAL)					\
+									\
+	static void name##_IO_APIC_irq (unsigned int irq)		\
+	__DO_ACTION(R, ACTION, FINAL)
+
+DO_ACTION( __mask,             0, |= 0x00010000, io_apic_sync(entry->apic) )
+						/* mask = 1 */
+DO_ACTION( __unmask,           0, &= 0xfffeffff, )
+						/* mask = 0 */
+DO_ACTION( __mask_and_edge,    0, = (reg & 0xffff7fff) | 0x00010000, )
+						/* mask = 1, trigger = 0 */
+DO_ACTION( __unmask_and_level, 0, = (reg & 0xfffeffff) | 0x00008000, )
+						/* mask = 0, trigger = 1 */
+
+static void mask_IO_APIC_irq (unsigned int irq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioapic_lock, flags);
+	__mask_IO_APIC_irq(irq);
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
+static void unmask_IO_APIC_irq (unsigned int irq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioapic_lock, flags);
+	__unmask_IO_APIC_irq(irq);
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
+void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
+{
+	struct IO_APIC_route_entry entry;
+	unsigned long flags;
+
+	/*
+	 * Disable it in the IO-APIC irq-routing table:
+	 */
+	memset(&entry, 0, sizeof(entry));
+	entry.mask = 1;
+	spin_lock_irqsave(&ioapic_lock, flags);
+	io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
+	io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
+static void clear_IO_APIC (void)
+{
+	int apic, pin;
+
+	for (apic = 0; apic < nr_ioapics; apic++)
+		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
+			clear_IO_APIC_pin(apic, pin);
+}
+
+/*
+ * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to
+ * specific CPU-side IRQs.
+ */
+
+#define MAX_PIRQS 8
+int pirq_entries [MAX_PIRQS];
+int pirqs_enabled;
+int skip_ioapic_setup;
+
+static int __init noioapic_setup(char *str)
+{
+	skip_ioapic_setup = 1;
+	return 1;
+}
+
+__setup("noapic", noioapic_setup);
+
+static int __init ioapic_setup(char *str)
+{
+	skip_ioapic_setup = 0;
+	return 1;
+}
+
+__setup("apic", ioapic_setup);
+
+
+static int __init ioapic_pirq_setup(char *str)
+{
+	int i, max;
+	int ints[MAX_PIRQS+1];
+
+	get_options(str, ARRAY_SIZE(ints), ints);
+
+	for (i = 0; i < MAX_PIRQS; i++)
+		pirq_entries[i] = -1;
+
+	pirqs_enabled = 1;
+	printk(KERN_INFO "PIRQ redirection, working around broken MP-BIOS.\n");
+	max = MAX_PIRQS;
+	if (ints[0] < MAX_PIRQS)
+		max = ints[0];
+
+	for (i = 0; i < max; i++) {
+		printk(KERN_DEBUG "... PIRQ%d -> IRQ %d\n", i, ints[i+1]);
+		/*
+		 * PIRQs are mapped upside down, usually.
+		 */
+		pirq_entries[MAX_PIRQS-i-1] = ints[i+1];
+	}
+	return 1;
+}
+
+__setup("pirq=", ioapic_pirq_setup);
+
+/*
+ * Find the IRQ entry number of a certain pin.
+ */
+static int __init find_irq_entry(int apic, int pin, int type)
+{
+	int i;
+
+	for (i = 0; i < mp_irq_entries; i++)
+		if (mp_irqs[i].mpc_irqtype == type &&
+		    (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid ||
+		     mp_irqs[i].mpc_dstapic == MP_APIC_ALL) &&
+		    mp_irqs[i].mpc_dstirq == pin)
+			return i;
+
+	return -1;
+}
+
+/*
+ * Find the pin to which IRQ[irq] (ISA) is connected
+ */
+static int __init find_isa_irq_pin(int irq, int type)
+{
+	int i;
+
+	for (i = 0; i < mp_irq_entries; i++) {
+		int lbus = mp_irqs[i].mpc_srcbus;
+
+		if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||
+		     mp_bus_id_to_type[lbus] == MP_BUS_EISA ||
+		     mp_bus_id_to_type[lbus] == MP_BUS_MCA) &&
+		    (mp_irqs[i].mpc_irqtype == type) &&
+		    (mp_irqs[i].mpc_srcbusirq == irq))
+
+			return mp_irqs[i].mpc_dstirq;
+	}
+	return -1;
+}
+
+/*
+ * Find a specific PCI IRQ entry.
+ * Not an __init, possibly needed by modules
+ */
+static int pin_2_irq(int idx, int apic, int pin);
+
+int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
+{
+	int apic, i, best_guess = -1;
+
+	Dprintk("querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
+		bus, slot, pin);
+	if (mp_bus_id_to_pci_bus[bus] == -1) {
+		printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
+		return -1;
+	}
+	for (i = 0; i < mp_irq_entries; i++) {
+		int lbus = mp_irqs[i].mpc_srcbus;
+
+		for (apic = 0; apic < nr_ioapics; apic++)
+			if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic ||
+			    mp_irqs[i].mpc_dstapic == MP_APIC_ALL)
+				break;
+
+		if ((mp_bus_id_to_type[lbus] == MP_BUS_PCI) &&
+		    !mp_irqs[i].mpc_irqtype &&
+		    (bus == lbus) &&
+		    (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) {
+			int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq);
+
+			if (!(apic || IO_APIC_IRQ(irq)))
+				continue;
+
+			if (pin == (mp_irqs[i].mpc_srcbusirq & 3))
+				return irq;
+			/*
+			 * Use the first all-but-pin matching entry as a
+			 * best-guess fuzzy result for broken mptables.
+			 */
+			if (best_guess < 0)
+				best_guess = irq;
+		}
+	}
+	return best_guess;
+}
+
+/*
+ * EISA Edge/Level control register, ELCR
+ */
+static int __init EISA_ELCR(unsigned int irq)
+{
+	if (irq < 16) {
+		unsigned int port = 0x4d0 + (irq >> 3);
+		return (inb(port) >> (irq & 7)) & 1;
+	}
+	printk(KERN_INFO "Broken MPtable reports ISA irq %d\n", irq);
+	return 0;
+}
+
+/* EISA interrupts are always polarity zero and can be edge or level
+ * trigger depending on the ELCR value.  If an interrupt is listed as
+ * EISA conforming in the MP table, that means its trigger type must
+ * be read in from the ELCR */
+
+#define default_EISA_trigger(idx)	(EISA_ELCR(mp_irqs[idx].mpc_srcbusirq))
+#define default_EISA_polarity(idx)	(0)
+
+/* ISA interrupts are always polarity zero edge triggered,
+ * when listed as conforming in the MP table. */
+
+#define default_ISA_trigger(idx)	(0)
+#define default_ISA_polarity(idx)	(0)
+
+/* PCI interrupts are always polarity one level triggered,
+ * when listed as conforming in the MP table. */
+
+#define default_PCI_trigger(idx)	(1)
+#define default_PCI_polarity(idx)	(1)
+
+/* MCA interrupts are always polarity zero level triggered,
+ * when listed as conforming in the MP table. */
+
+#define default_MCA_trigger(idx)	(1)
+#define default_MCA_polarity(idx)	(0)
+
+static int __init MPBIOS_polarity(int idx)
+{
+	int bus = mp_irqs[idx].mpc_srcbus;
+	int polarity;
+
+	/*
+	 * Determine IRQ line polarity (high active or low active):
+	 */
+	switch (mp_irqs[idx].mpc_irqflag & 3)
+	{
+		case 0: /* conforms, ie. bus-type dependent polarity */
+		{
+			switch (mp_bus_id_to_type[bus])
+			{
+				case MP_BUS_ISA: /* ISA pin */
+				{
+					polarity = default_ISA_polarity(idx);
+					break;
+				}
+				case MP_BUS_EISA: /* EISA pin */
+				{
+					polarity = default_EISA_polarity(idx);
+					break;
+				}
+				case MP_BUS_PCI: /* PCI pin */
+				{
+					polarity = default_PCI_polarity(idx);
+					break;
+				}
+				case MP_BUS_MCA: /* MCA pin */
+				{
+					polarity = default_MCA_polarity(idx);
+					break;
+				}
+				default:
+				{
+					printk(KERN_WARNING "broken BIOS!!\n");
+					polarity = 1;
+					break;
+				}
+			}
+			break;
+		}
+		case 1: /* high active */
+		{
+			polarity = 0;
+			break;
+		}
+		case 2: /* reserved */
+		{
+			printk(KERN_WARNING "broken BIOS!!\n");
+			polarity = 1;
+			break;
+		}
+		case 3: /* low active */
+		{
+			polarity = 1;
+			break;
+		}
+		default: /* invalid */
+		{
+			printk(KERN_WARNING "broken BIOS!!\n");
+			polarity = 1;
+			break;
+		}
+	}
+	return polarity;
+}
+
+static int __init MPBIOS_trigger(int idx)
+{
+	int bus = mp_irqs[idx].mpc_srcbus;
+	int trigger;
+
+	/*
+	 * Determine IRQ trigger mode (edge or level sensitive):
+	 */
+	switch ((mp_irqs[idx].mpc_irqflag>>2) & 3)
+	{
+		case 0: /* conforms, ie. bus-type dependent */
+		{
+			switch (mp_bus_id_to_type[bus])
+			{
+				case MP_BUS_ISA: /* ISA pin */
+				{
+					trigger = default_ISA_trigger(idx);
+					break;
+				}
+				case MP_BUS_EISA: /* EISA pin */
+				{
+					trigger = default_EISA_trigger(idx);
+					break;
+				}
+				case MP_BUS_PCI: /* PCI pin */
+				{
+					trigger = default_PCI_trigger(idx);
+					break;
+				}
+				case MP_BUS_MCA: /* MCA pin */
+				{
+					trigger = default_MCA_trigger(idx);
+					break;
+				}
+				default:
+				{
+					printk(KERN_WARNING "broken BIOS!!\n");
+					trigger = 1;
+					break;
+				}
+			}
+			break;
+		}
+		case 1: /* edge */
+		{
+			trigger = 0;
+			break;
+		}
+		case 2: /* reserved */
+		{
+			printk(KERN_WARNING "broken BIOS!!\n");
+			trigger = 1;
+			break;
+		}
+		case 3: /* level */
+		{
+			trigger = 1;
+			break;
+		}
+		default: /* invalid */
+		{
+			printk(KERN_WARNING "broken BIOS!!\n");
+			trigger = 0;
+			break;
+		}
+	}
+	return trigger;
+}
+
+static inline int irq_polarity(int idx)
+{
+	return MPBIOS_polarity(idx);
+}
+
+static inline int irq_trigger(int idx)
+{
+	return MPBIOS_trigger(idx);
+}
+
+static int pin_2_irq(int idx, int apic, int pin)
+{
+	int irq, i;
+	int bus = mp_irqs[idx].mpc_srcbus;
+
+	/*
+	 * Debugging check, we are in big trouble if this message pops up!
+	 */
+	if (mp_irqs[idx].mpc_dstirq != pin)
+		printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n");
+
+	switch (mp_bus_id_to_type[bus])
+	{
+		case MP_BUS_ISA: /* ISA pin */
+		case MP_BUS_EISA:
+		case MP_BUS_MCA:
+		{
+			irq = mp_irqs[idx].mpc_srcbusirq;
+			break;
+		}
+		case MP_BUS_PCI: /* PCI pin */
+		{
+			/*
+			 * PCI IRQs are mapped in order
+			 */
+			i = irq = 0;
+			while (i < apic)
+				irq += nr_ioapic_registers[i++];
+			irq += pin;
+			break;
+		}
+		default:
+		{
+			printk(KERN_ERR "unknown bus type %d.\n",bus); 
+			irq = 0;
+			break;
+		}
+	}
+
+	/*
+	 * PCI IRQ command line redirection. Yes, limits are hardcoded.
+	 */
+	if ((pin >= 16) && (pin <= 23)) {
+		if (pirq_entries[pin-16] != -1) {
+			if (!pirq_entries[pin-16]) {
+				printk(KERN_DEBUG "disabling PIRQ%d\n", pin-16);
+			} else {
+				irq = pirq_entries[pin-16];
+				printk(KERN_DEBUG "using PIRQ%d -> IRQ %d\n",
+						pin-16, irq);
+			}
+		}
+	}
+	return irq;
+}
+
+static inline int IO_APIC_irq_trigger(int irq)
+{
+	int apic, idx, pin;
+
+	for (apic = 0; apic < nr_ioapics; apic++) {
+		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+			idx = find_irq_entry(apic,pin,mp_INT);
+			if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin)))
+				return irq_trigger(idx);
+		}
+	}
+	/*
+	 * nonexistent IRQs are edge default
+	 */
+	return 0;
+}
+
+int irq_vector[NR_IRQS] = { FIRST_DEVICE_VECTOR , 0 };
+
+static int __init assign_irq_vector(int irq)
+{
+	static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
+	if (IO_APIC_VECTOR(irq) > 0)
+		return IO_APIC_VECTOR(irq);
+next:
+	current_vector += 8;
+	if (current_vector == IA32_SYSCALL_VECTOR)
+		goto next;
+
+	if (current_vector > FIRST_SYSTEM_VECTOR) {
+		offset++;
+		current_vector = FIRST_DEVICE_VECTOR + offset;
+	}
+
+	if (current_vector == FIRST_SYSTEM_VECTOR)
+		panic("ran out of interrupt sources!");
+
+	IO_APIC_VECTOR(irq) = current_vector;
+	return current_vector;
+}
+
+extern void (*interrupt[NR_IRQS])(void);
+static struct hw_interrupt_type ioapic_level_irq_type;
+static struct hw_interrupt_type ioapic_edge_irq_type;
+
+void __init setup_IO_APIC_irqs(void)
+{
+	struct IO_APIC_route_entry entry;
+	int apic, pin, idx, irq, first_notcon = 1, vector;
+	unsigned long flags;
+
+	printk(KERN_DEBUG "init IO_APIC IRQs\n");
+
+	for (apic = 0; apic < nr_ioapics; apic++) {
+	for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+
+		/*
+		 * add it to the IO-APIC irq-routing table:
+		 */
+		memset(&entry,0,sizeof(entry));
+
+		entry.delivery_mode = dest_LowestPrio;
+		entry.dest_mode = INT_DELIVERY_MODE;
+		entry.mask = 0;				/* enable IRQ */
+		entry.dest.logical.logical_dest = TARGET_CPUS;
+
+		idx = find_irq_entry(apic,pin,mp_INT);
+		if (idx == -1) {
+			if (first_notcon) {
+				printk(KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin);
+				first_notcon = 0;
+			} else
+				printk(", %d-%d", mp_ioapics[apic].mpc_apicid, pin);
+			continue;
+		}
+
+		entry.trigger = irq_trigger(idx);
+		entry.polarity = irq_polarity(idx);
+
+		if (irq_trigger(idx)) {
+			entry.trigger = 1;
+			entry.mask = 1;
+			entry.dest.logical.logical_dest = TARGET_CPUS;
+		}
+
+		irq = pin_2_irq(idx, apic, pin);
+		add_pin_to_irq(irq, apic, pin);
+
+		if (!apic && !IO_APIC_IRQ(irq))
+			continue;
+
+		if (IO_APIC_IRQ(irq)) {
+			vector = assign_irq_vector(irq);
+			entry.vector = vector;
+
+			if (IO_APIC_irq_trigger(irq))
+				irq_desc[irq].handler = &ioapic_level_irq_type;
+			else
+				irq_desc[irq].handler = &ioapic_edge_irq_type;
+
+			set_intr_gate(vector, interrupt[irq]);
+		
+			if (!apic && (irq < 16))
+				disable_8259A_irq(irq);
+		}
+		spin_lock_irqsave(&ioapic_lock, flags);
+		io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
+		io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
+		spin_unlock_irqrestore(&ioapic_lock, flags);
+	}
+	}
+
+	if (!first_notcon)
+		printk(" not connected.\n");
+}
+
+/*
+ * Set up the 8259A-master output pin as broadcast to all
+ * CPUs.
+ */
+void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector)
+{
+	struct IO_APIC_route_entry entry;
+	unsigned long flags;
+
+	memset(&entry,0,sizeof(entry));
+
+	disable_8259A_irq(0);
+
+	/* mask LVT0 */
+	apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
+
+	/*
+	 * We use logical delivery to get the timer IRQ
+	 * to the first CPU.
+	 */
+	entry.dest_mode = INT_DELIVERY_MODE;
+	entry.mask = 0;					/* unmask IRQ now */
+	entry.dest.logical.logical_dest = TARGET_CPUS;
+	entry.delivery_mode = dest_LowestPrio;
+	entry.polarity = 0;
+	entry.trigger = 0;
+	entry.vector = vector;
+
+	/*
+	 * The timer IRQ doesnt have to know that behind the
+	 * scene we have a 8259A-master in AEOI mode ...
+	 */
+	irq_desc[0].handler = &ioapic_edge_irq_type;
+
+	/*
+	 * Add it to the IO-APIC irq-routing table:
+	 */
+	spin_lock_irqsave(&ioapic_lock, flags);
+	io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
+	io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+
+	enable_8259A_irq(0);
+}
+
+void __init UNEXPECTED_IO_APIC(void)
+{
+	printk(KERN_WARNING " WARNING: unexpected IO-APIC, please mail\n");
+	printk(KERN_WARNING "          to linux-smp@vger.kernel.org\n");
+}
+
+void __init print_IO_APIC(void)
+{
+	int apic, i;
+	struct IO_APIC_reg_00 reg_00;
+	struct IO_APIC_reg_01 reg_01;
+	struct IO_APIC_reg_02 reg_02;
+	unsigned long flags;
+
+ 	printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
+	for (i = 0; i < nr_ioapics; i++)
+		printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n",
+		       mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]);
+
+	/*
+	 * We are a bit conservative about what we expect.  We have to
+	 * know about every hardware change ASAP.
+	 */
+	printk(KERN_INFO "testing the IO APIC.......................\n");
+
+	for (apic = 0; apic < nr_ioapics; apic++) {
+
+	spin_lock_irqsave(&ioapic_lock, flags);
+	*(int *)&reg_00 = io_apic_read(apic, 0);
+	*(int *)&reg_01 = io_apic_read(apic, 1);
+	if (reg_01.version >= 0x10)
+		*(int *)&reg_02 = io_apic_read(apic, 2);
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+
+	printk("\n");
+	printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid);
+	printk(KERN_DEBUG ".... register #00: %08X\n", *(int *)&reg_00);
+	printk(KERN_DEBUG ".......    : physical APIC id: %02X\n", reg_00.ID);
+	if (reg_00.__reserved_1 || reg_00.__reserved_2)
+		UNEXPECTED_IO_APIC();
+
+	printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)&reg_01);
+	printk(KERN_DEBUG ".......     : max redirection entries: %04X\n", reg_01.entries);
+	if (	(reg_01.entries != 0x0f) && /* older (Neptune) boards */
+		(reg_01.entries != 0x17) && /* typical ISA+PCI boards */
+		(reg_01.entries != 0x1b) && /* Compaq Proliant boards */
+		(reg_01.entries != 0x1f) && /* dual Xeon boards */
+		(reg_01.entries != 0x22) && /* bigger Xeon boards */
+		(reg_01.entries != 0x2E) &&
+		(reg_01.entries != 0x3F) &&
+		(reg_01.entries != 0x03)    /* Golem */
+	)
+		UNEXPECTED_IO_APIC();
+
+	printk(KERN_DEBUG ".......     : PRQ implemented: %X\n", reg_01.PRQ);
+	printk(KERN_DEBUG ".......     : IO APIC version: %04X\n", reg_01.version);
+	if (	(reg_01.version != 0x01) && /* 82489DX IO-APICs */
+		(reg_01.version != 0x02) && /* 82801BA IO-APICs (ICH2) */
+		(reg_01.version != 0x10) && /* oldest IO-APICs */
+		(reg_01.version != 0x11) && /* Pentium/Pro IO-APICs / GOLEM */
+		(reg_01.version != 0x13) && /* Xeon IO-APICs */
+		(reg_01.version != 0x20)    /* Intel P64H (82806 AA) */
+	)
+		UNEXPECTED_IO_APIC();
+	if (reg_01.__reserved_1 || reg_01.__reserved_2)
+		UNEXPECTED_IO_APIC();
+
+	if (reg_01.version >= 0x10) {
+		printk(KERN_DEBUG ".... register #02: %08X\n", *(int *)&reg_02);
+		printk(KERN_DEBUG ".......     : arbitration: %02X\n", reg_02.arbitration);
+		if (reg_02.__reserved_1 || reg_02.__reserved_2)
+			UNEXPECTED_IO_APIC();
+	}
+
+	printk(KERN_DEBUG ".... IRQ redirection table:\n");
+
+	printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol"
+			  " Stat Dest Deli Vect:   \n");
+
+	for (i = 0; i <= reg_01.entries; i++) {
+		struct IO_APIC_route_entry entry;
+
+		spin_lock_irqsave(&ioapic_lock, flags);
+		*(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2);
+		*(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2);
+		spin_unlock_irqrestore(&ioapic_lock, flags);
+
+		printk(KERN_DEBUG " %02x %03X %02X  ",
+			i,
+			entry.dest.logical.logical_dest,
+			entry.dest.physical.physical_dest
+		);
+
+		printk("%1d    %1d    %1d   %1d   %1d    %1d    %1d    %02X\n",
+			entry.mask,
+			entry.trigger,
+			entry.irr,
+			entry.polarity,
+			entry.delivery_status,
+			entry.dest_mode,
+			entry.delivery_mode,
+			entry.vector
+		);
+	}
+	}
+	printk(KERN_DEBUG "IRQ to pin mappings:\n");
+	for (i = 0; i < NR_IRQS; i++) {
+		struct irq_pin_list *entry = irq_2_pin + i;
+		if (entry->pin < 0)
+			continue;
+		printk(KERN_DEBUG "IRQ%d ", i);
+		for (;;) {
+			printk("-> %d:%d", entry->apic, entry->pin);
+			if (!entry->next)
+				break;
+			entry = irq_2_pin + entry->next;
+		}
+		printk("\n");
+	}
+
+	printk(KERN_INFO ".................................... done.\n");
+
+	return;
+}
+
+static void print_APIC_bitfield (int base)
+{
+	unsigned int v;
+	int i, j;
+
+	printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG);
+	for (i = 0; i < 8; i++) {
+		v = apic_read(base + i*0x10);
+		for (j = 0; j < 32; j++) {
+			if (v & (1<<j))
+				printk("1");
+			else
+				printk("0");
+		}
+		printk("\n");
+	}
+}
+
+void /*__init*/ print_local_APIC(void * dummy)
+{
+	unsigned int v, ver, maxlvt;
+
+	printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
+		smp_processor_id(), hard_smp_processor_id());
+	v = apic_read(APIC_ID);
+	printk(KERN_INFO "... APIC ID:      %08x (%01x)\n", v, GET_APIC_ID(v));
+	v = apic_read(APIC_LVR);
+	printk(KERN_INFO "... APIC VERSION: %08x\n", v);
+	ver = GET_APIC_VERSION(v);
+	maxlvt = get_maxlvt();
+
+	v = apic_read(APIC_TASKPRI);
+	printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);
+
+	if (APIC_INTEGRATED(ver)) {			/* !82489DX */
+		v = apic_read(APIC_ARBPRI);
+		printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v,
+			v & APIC_ARBPRI_MASK);
+		v = apic_read(APIC_PROCPRI);
+		printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v);
+	}
+
+	v = apic_read(APIC_EOI);
+	printk(KERN_DEBUG "... APIC EOI: %08x\n", v);
+	v = apic_read(APIC_RRR);
+	printk(KERN_DEBUG "... APIC RRR: %08x\n", v);
+	v = apic_read(APIC_LDR);
+	printk(KERN_DEBUG "... APIC LDR: %08x\n", v);
+	v = apic_read(APIC_DFR);
+	printk(KERN_DEBUG "... APIC DFR: %08x\n", v);
+	v = apic_read(APIC_SPIV);
+	printk(KERN_DEBUG "... APIC SPIV: %08x\n", v);
+
+	printk(KERN_DEBUG "... APIC ISR field:\n");
+	print_APIC_bitfield(APIC_ISR);
+	printk(KERN_DEBUG "... APIC TMR field:\n");
+	print_APIC_bitfield(APIC_TMR);
+	printk(KERN_DEBUG "... APIC IRR field:\n");
+	print_APIC_bitfield(APIC_IRR);
+
+	if (APIC_INTEGRATED(ver)) {		/* !82489DX */
+		if (maxlvt > 3)		/* Due to the Pentium erratum 3AP. */
+			apic_write(APIC_ESR, 0);
+		v = apic_read(APIC_ESR);
+		printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
+	}
+
+	v = apic_read(APIC_ICR);
+	printk(KERN_DEBUG "... APIC ICR: %08x\n", v);
+	v = apic_read(APIC_ICR2);
+	printk(KERN_DEBUG "... APIC ICR2: %08x\n", v);
+
+	v = apic_read(APIC_LVTT);
+	printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
+
+	if (maxlvt > 3) {                       /* PC is LVT#4. */
+		v = apic_read(APIC_LVTPC);
+		printk(KERN_DEBUG "... APIC LVTPC: %08x\n", v);
+	}
+	v = apic_read(APIC_LVT0);
+	printk(KERN_DEBUG "... APIC LVT0: %08x\n", v);
+	v = apic_read(APIC_LVT1);
+	printk(KERN_DEBUG "... APIC LVT1: %08x\n", v);
+
+	if (maxlvt > 2) {			/* ERR is LVT#3. */
+		v = apic_read(APIC_LVTERR);
+		printk(KERN_DEBUG "... APIC LVTERR: %08x\n", v);
+	}
+
+	v = apic_read(APIC_TMICT);
+	printk(KERN_DEBUG "... APIC TMICT: %08x\n", v);
+	v = apic_read(APIC_TMCCT);
+	printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v);
+	v = apic_read(APIC_TDCR);
+	printk(KERN_DEBUG "... APIC TDCR: %08x\n", v);
+	printk("\n");
+}
+
+void print_all_local_APICs (void)
+{
+	smp_call_function(print_local_APIC, NULL, 1, 1);
+	print_local_APIC(NULL);
+}
+
+void /*__init*/ print_PIC(void)
+{
+	extern spinlock_t i8259A_lock;
+	unsigned int v;
+	unsigned long flags;
+
+	printk(KERN_DEBUG "\nprinting PIC contents\n");
+
+	spin_lock_irqsave(&i8259A_lock, flags);
+
+	v = inb(0xa1) << 8 | inb(0x21);
+	printk(KERN_DEBUG "... PIC  IMR: %04x\n", v);
+
+	v = inb(0xa0) << 8 | inb(0x20);
+	printk(KERN_DEBUG "... PIC  IRR: %04x\n", v);
+
+	outb(0x0b,0xa0);
+	outb(0x0b,0x20);
+	v = inb(0xa0) << 8 | inb(0x20);
+	outb(0x0a,0xa0);
+	outb(0x0a,0x20);
+
+	spin_unlock_irqrestore(&i8259A_lock, flags);
+
+	printk(KERN_DEBUG "... PIC  ISR: %04x\n", v);
+
+	v = inb(0x4d1) << 8 | inb(0x4d0);
+	printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
+}
+
+static void __init enable_IO_APIC(void)
+{
+	struct IO_APIC_reg_01 reg_01;
+	int i;
+	unsigned long flags;
+
+	for (i = 0; i < PIN_MAP_SIZE; i++) {
+		irq_2_pin[i].pin = -1;
+		irq_2_pin[i].next = 0;
+	}
+	if (!pirqs_enabled)
+		for (i = 0; i < MAX_PIRQS; i++)
+			pirq_entries[i] = -1;
+
+	/*
+	 * The number of IO-APIC IRQ registers (== #pins):
+	 */
+	for (i = 0; i < nr_ioapics; i++) {
+		spin_lock_irqsave(&ioapic_lock, flags);
+		*(int *)&reg_01 = io_apic_read(i, 1);
+		spin_unlock_irqrestore(&ioapic_lock, flags);
+		nr_ioapic_registers[i] = reg_01.entries+1;
+	}
+
+	/*
+	 * Do not trust the IO-APIC being empty at bootup
+	 */
+	clear_IO_APIC();
+}
+
+/*
+ * Not an __init, needed by the reboot code
+ */
+void disable_IO_APIC(void)
+{
+	/*
+	 * Clear the IO-APIC before rebooting:
+	 */
+	clear_IO_APIC();
+
+	disconnect_bsp_APIC();
+}
+
+/*
+ * function to set the IO-APIC physical IDs based on the
+ * values stored in the MPC table.
+ *
+ * by Matt Domsch <Matt_Domsch@dell.com>  Tue Dec 21 12:25:05 CST 1999
+ */
+
+static void __init setup_ioapic_ids_from_mpc (void)
+{
+	struct IO_APIC_reg_00 reg_00;
+	unsigned long phys_id_present_map = phys_cpu_present_map;
+	int apic;
+	int i;
+	unsigned char old_id;
+	unsigned long flags;
+
+	/*
+	 * Set the IOAPIC ID to the value stored in the MPC table.
+	 */
+	for (apic = 0; apic < nr_ioapics; apic++) {
+
+		/* Read the register 0 value */
+		spin_lock_irqsave(&ioapic_lock, flags);
+		*(int *)&reg_00 = io_apic_read(apic, 0);
+		spin_unlock_irqrestore(&ioapic_lock, flags);
+		
+		old_id = mp_ioapics[apic].mpc_apicid;
+
+		if (mp_ioapics[apic].mpc_apicid >= 0xf) {
+			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
+				apic, mp_ioapics[apic].mpc_apicid);
+			printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
+				reg_00.ID);
+			mp_ioapics[apic].mpc_apicid = reg_00.ID;
+		}
+
+		/*
+		 * Sanity check, is the ID really free? Every APIC in a
+		 * system must have a unique ID or we get lots of nice
+		 * 'stuck on smp_invalidate_needed IPI wait' messages.
+	 	 */
+		if (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid)) {
+			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
+				apic, mp_ioapics[apic].mpc_apicid);
+			for (i = 0; i < 0xf; i++)
+				if (!(phys_id_present_map & (1 << i)))
+					break;
+			if (i >= 0xf)
+				panic("Max APIC ID exceeded!\n");
+			printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
+				i);
+			phys_id_present_map |= 1 << i;
+			mp_ioapics[apic].mpc_apicid = i;
+		} else {
+			printk("Setting %d in the phys_id_present_map\n", mp_ioapics[apic].mpc_apicid);
+			phys_id_present_map |= 1 << mp_ioapics[apic].mpc_apicid;
+		}
+
+
+		/*
+		 * We need to adjust the IRQ routing table
+		 * if the ID changed.
+		 */
+		if (old_id != mp_ioapics[apic].mpc_apicid)
+			for (i = 0; i < mp_irq_entries; i++)
+				if (mp_irqs[i].mpc_dstapic == old_id)
+					mp_irqs[i].mpc_dstapic
+						= mp_ioapics[apic].mpc_apicid;
+
+		/*
+		 * Read the right value from the MPC table and
+		 * write it into the ID register.
+	 	 */
+		printk(KERN_INFO "...changing IO-APIC physical APIC ID to %d ...",
+				mp_ioapics[apic].mpc_apicid);
+
+		reg_00.ID = mp_ioapics[apic].mpc_apicid;
+		spin_lock_irqsave(&ioapic_lock, flags);
+		io_apic_write(apic, 0, *(int *)&reg_00);
+		spin_unlock_irqrestore(&ioapic_lock, flags);
+
+		/*
+		 * Sanity check
+		 */
+		spin_lock_irqsave(&ioapic_lock, flags);
+		*(int *)&reg_00 = io_apic_read(apic, 0);
+		spin_unlock_irqrestore(&ioapic_lock, flags);
+		if (reg_00.ID != mp_ioapics[apic].mpc_apicid)
+			panic("could not set ID!\n");
+		else
+			printk(" ok.\n");
+	}
+}
+
+/*
+ * There is a nasty bug in some older SMP boards, their mptable lies
+ * about the timer IRQ. We do the following to work around the situation:
+ *
+ *	- timer IRQ defaults to IO-APIC IRQ
+ *	- if this function detects that timer IRQs are defunct, then we fall
+ *	  back to ISA timer IRQs
+ */
+static int __init timer_irq_works(void)
+{
+	unsigned int t1 = jiffies;
+
+	sti();
+	/* Let ten ticks pass... */
+	mdelay((10 * 1000) / HZ);
+
+	/*
+	 * Expect a few ticks at least, to be sure some possible
+	 * glue logic does not lock up after one or two first
+	 * ticks in a non-ExtINT mode.  Also the local APIC
+	 * might have cached one ExtINT interrupt.  Finally, at
+	 * least one tick may be lost due to delays.
+	 */
+	if (jiffies - t1 > 4)
+		return 1;
+
+	return 0;
+}
+
+/*
+ * In the SMP+IOAPIC case it might happen that there are an unspecified
+ * number of pending IRQ events unhandled. These cases are very rare,
+ * so we 'resend' these IRQs via IPIs, to the same CPU. It's much
+ * better to do it this way as thus we do not have to be aware of
+ * 'pending' interrupts in the IRQ path, except at this point.
+ */
+/*
+ * Edge triggered needs to resend any interrupt
+ * that was delayed but this is now handled in the device
+ * independent code.
+ */
+#define enable_edge_ioapic_irq unmask_IO_APIC_irq
+
+static void disable_edge_ioapic_irq (unsigned int irq) { /* nothing */ }
+
+/*
+ * Starting up a edge-triggered IO-APIC interrupt is
+ * nasty - we need to make sure that we get the edge.
+ * If it is already asserted for some reason, we need
+ * return 1 to indicate that is was pending.
+ *
+ * This is not complete - we should be able to fake
+ * an edge even if it isn't on the 8259A...
+ */
+
+static unsigned int startup_edge_ioapic_irq(unsigned int irq)
+{
+	int was_pending = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioapic_lock, flags);
+	if (irq < 16) {
+		disable_8259A_irq(irq);
+		if (i8259A_irq_pending(irq))
+			was_pending = 1;
+	}
+	__unmask_IO_APIC_irq(irq);
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+
+	return was_pending;
+}
+
+#define shutdown_edge_ioapic_irq	disable_edge_ioapic_irq
+
+/*
+ * Once we have recorded IRQ_PENDING already, we can mask the
+ * interrupt for real. This prevents IRQ storms from unhandled
+ * devices.
+ */
+static void ack_edge_ioapic_irq(unsigned int irq)
+{
+	if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
+					== (IRQ_PENDING | IRQ_DISABLED))
+		mask_IO_APIC_irq(irq);
+	ack_APIC_irq();
+}
+
+static void end_edge_ioapic_irq (unsigned int i) { /* nothing */ }
+
+
+/*
+ * Level triggered interrupts can just be masked,
+ * and shutting down and starting up the interrupt
+ * is the same as enabling and disabling them -- except
+ * with a startup need to return a "was pending" value.
+ *
+ * Level triggered interrupts are special because we
+ * do not touch any IO-APIC register while handling
+ * them. We ack the APIC in the end-IRQ handler, not
+ * in the start-IRQ-handler. Protection against reentrance
+ * from the same interrupt is still provided, both by the
+ * generic IRQ layer and by the fact that an unacked local
+ * APIC does not accept IRQs.
+ */
+static unsigned int startup_level_ioapic_irq (unsigned int irq)
+{
+	unmask_IO_APIC_irq(irq);
+
+	return 0; /* don't check for pending */
+}
+
+#define shutdown_level_ioapic_irq	mask_IO_APIC_irq
+#define enable_level_ioapic_irq		unmask_IO_APIC_irq
+#define disable_level_ioapic_irq	mask_IO_APIC_irq
+
+static void end_level_ioapic_irq (unsigned int irq)
+{
+	unsigned long v;
+	int i;
+
+/*
+ * It appears there is an erratum which affects at least version 0x11
+ * of I/O APIC (that's the 82093AA and cores integrated into various
+ * chipsets).  Under certain conditions a level-triggered interrupt is
+ * erroneously delivered as edge-triggered one but the respective IRR
+ * bit gets set nevertheless.  As a result the I/O unit expects an EOI
+ * message but it will never arrive and further interrupts are blocked
+ * from the source.  The exact reason is so far unknown, but the
+ * phenomenon was observed when two consecutive interrupt requests
+ * from a given source get delivered to the same CPU and the source is
+ * temporarily disabled in between.
+ *
+ * A workaround is to simulate an EOI message manually.  We achieve it
+ * by setting the trigger mode to edge and then to level when the edge
+ * trigger mode gets detected in the TMR of a local APIC for a
+ * level-triggered interrupt.  We mask the source for the time of the
+ * operation to prevent an edge-triggered interrupt escaping meanwhile.
+ * The idea is from Manfred Spraul.  --macro
+ */
+	i = IO_APIC_VECTOR(irq);
+	v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
+
+	ack_APIC_irq();
+
+	if (!(v & (1 << (i & 0x1f)))) {
+#ifdef APIC_LOCKUP_DEBUG
+		struct irq_pin_list *entry;
+#endif
+
+#ifdef APIC_MISMATCH_DEBUG
+		atomic_inc(&irq_mis_count);
+#endif
+		spin_lock(&ioapic_lock);
+		__mask_and_edge_IO_APIC_irq(irq);
+#ifdef APIC_LOCKUP_DEBUG
+		for (entry = irq_2_pin + irq;;) {
+			unsigned int reg;
+
+			if (entry->pin == -1)
+				break;
+			reg = io_apic_read(entry->apic, 0x10 + entry->pin * 2);
+			if (reg & 0x00004000)
+				printk(KERN_CRIT "Aieee!!!  Remote IRR"
+					" still set after unlock!\n");
+			if (!entry->next)
+				break;
+			entry = irq_2_pin + entry->next;
+		}
+#endif
+		__unmask_and_level_IO_APIC_irq(irq);
+		spin_unlock(&ioapic_lock);
+	}
+}
+
+static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ }
+
+static void set_ioapic_affinity (unsigned int irq, unsigned long mask)
+{
+	unsigned long flags;
+	/*
+	 * Only the first 8 bits are valid.
+	 */
+	mask = mask << 24;
+
+	spin_lock_irqsave(&ioapic_lock, flags);
+	__DO_ACTION(1, = mask, )
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
+/*
+ * Level and edge triggered IO-APIC interrupts need different handling,
+ * so we use two separate IRQ descriptors. Edge triggered IRQs can be
+ * handled with the level-triggered descriptor, but that one has slightly
+ * more overhead. Level-triggered interrupts cannot be handled with the
+ * edge-triggered handler, without risking IRQ storms and other ugly
+ * races.
+ */
+
+static struct hw_interrupt_type ioapic_edge_irq_type = {
+	"IO-APIC-edge",
+	startup_edge_ioapic_irq,
+	shutdown_edge_ioapic_irq,
+	enable_edge_ioapic_irq,
+	disable_edge_ioapic_irq,
+	ack_edge_ioapic_irq,
+	end_edge_ioapic_irq,
+	set_ioapic_affinity,
+};
+
+static struct hw_interrupt_type ioapic_level_irq_type = {
+	"IO-APIC-level",
+	startup_level_ioapic_irq,
+	shutdown_level_ioapic_irq,
+	enable_level_ioapic_irq,
+	disable_level_ioapic_irq,
+	mask_and_ack_level_ioapic_irq,
+	end_level_ioapic_irq,
+	set_ioapic_affinity,
+};
+
+static inline void init_IO_APIC_traps(void)
+{
+	int irq;
+
+	/*
+	 * NOTE! The local APIC isn't very good at handling
+	 * multiple interrupts at the same interrupt level.
+	 * As the interrupt level is determined by taking the
+	 * vector number and shifting that right by 4, we
+	 * want to spread these out a bit so that they don't
+	 * all fall in the same interrupt level.
+	 *
+	 * Also, we've got to be careful not to trash gate
+	 * 0x80, because int 0x80 is hm, kind of importantish. ;)
+	 */
+	for (irq = 0; irq < NR_IRQS ; irq++) {
+		if (IO_APIC_IRQ(irq) && !IO_APIC_VECTOR(irq)) {
+			/*
+			 * Hmm.. We don't have an entry for this,
+			 * so default to an old-fashioned 8259
+			 * interrupt if we can..
+			 */
+			if (irq < 16)
+				make_8259A_irq(irq);
+			else
+				/* Strange. Oh, well.. */
+				irq_desc[irq].handler = &no_irq_type;
+		}
+	}
+}
+
+static void enable_lapic_irq (unsigned int irq)
+{
+	unsigned long v;
+
+	v = apic_read(APIC_LVT0);
+	apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
+}
+
+static void disable_lapic_irq (unsigned int irq)
+{
+	unsigned long v;
+
+	v = apic_read(APIC_LVT0);
+	apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
+}
+
+static void ack_lapic_irq (unsigned int irq)
+{
+	ack_APIC_irq();
+}
+
+static void end_lapic_irq (unsigned int i) { /* nothing */ }
+
+static struct hw_interrupt_type lapic_irq_type = {
+	"local-APIC-edge",
+	NULL, /* startup_irq() not used for IRQ0 */
+	NULL, /* shutdown_irq() not used for IRQ0 */
+	enable_lapic_irq,
+	disable_lapic_irq,
+	ack_lapic_irq,
+	end_lapic_irq
+};
+
+void enable_NMI_through_LVT0 (void * dummy)
+{
+	unsigned int v, ver;
+
+	printk("enable NMI through LVT0 on cpu %d\n", smp_processor_id());
+
+	ver = apic_read(APIC_LVR);
+	ver = GET_APIC_VERSION(ver);
+	v = APIC_DM_NMI;			/* unmask and set to NMI */
+	if (!APIC_INTEGRATED(ver))		/* 82489DX */
+		v |= APIC_LVT_LEVEL_TRIGGER;
+	apic_write_around(APIC_LVT0, v);
+}
+
+static void setup_nmi (void)
+{
+	/*
+ 	 * Dirty trick to enable the NMI watchdog ...
+	 * We put the 8259A master into AEOI mode and
+	 * unmask on all local APICs LVT0 as NMI.
+	 *
+	 * The idea to use the 8259A in AEOI mode ('8259A Virtual Wire')
+	 * is from Maciej W. Rozycki - so we do not have to EOI from
+	 * the NMI handler or the timer interrupt.
+	 */ 
+	printk(KERN_INFO "activating NMI Watchdog ...");
+
+	smp_call_function(enable_NMI_through_LVT0, NULL, 1, 1);
+	enable_NMI_through_LVT0(NULL);
+
+	printk(" done.\n");
+}
+
+/*
+ * This looks a bit hackish but it's about the only one way of sending
+ * a few INTA cycles to 8259As and any associated glue logic.  ICR does
+ * not support the ExtINT mode, unfortunately.  We need to send these
+ * cycles as some i82489DX-based boards have glue logic that keeps the
+ * 8259A interrupt line asserted until INTA.  --macro
+ */
+static inline void unlock_ExtINT_logic(void)
+{
+	int pin, i;
+	struct IO_APIC_route_entry entry0, entry1;
+	unsigned char save_control, save_freq_select;
+	unsigned long flags;
+
+	pin = find_isa_irq_pin(8, mp_INT);
+	if (pin == -1)
+		return;
+
+	spin_lock_irqsave(&ioapic_lock, flags);
+	*(((int *)&entry0) + 1) = io_apic_read(0, 0x11 + 2 * pin);
+	*(((int *)&entry0) + 0) = io_apic_read(0, 0x10 + 2 * pin);
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+	clear_IO_APIC_pin(0, pin);
+
+	memset(&entry1, 0, sizeof(entry1));
+
+	entry1.dest_mode = 0;			/* physical delivery */
+	entry1.mask = 0;			/* unmask IRQ now */
+	entry1.dest.physical.physical_dest = hard_smp_processor_id();
+	entry1.delivery_mode = dest_ExtINT;
+	entry1.polarity = entry0.polarity;
+	entry1.trigger = 0;
+	entry1.vector = 0;
+
+	spin_lock_irqsave(&ioapic_lock, flags);
+	io_apic_write(0, 0x11 + 2 * pin, *(((int *)&entry1) + 1));
+	io_apic_write(0, 0x10 + 2 * pin, *(((int *)&entry1) + 0));
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+
+	save_control = CMOS_READ(RTC_CONTROL);
+	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+	CMOS_WRITE((save_freq_select & ~RTC_RATE_SELECT) | 0x6,
+		   RTC_FREQ_SELECT);
+	CMOS_WRITE(save_control | RTC_PIE, RTC_CONTROL);
+
+	i = 100;
+	while (i-- > 0) {
+		mdelay(10);
+		if ((CMOS_READ(RTC_INTR_FLAGS) & RTC_PF) == RTC_PF)
+			i -= 10;
+	}
+
+	CMOS_WRITE(save_control, RTC_CONTROL);
+	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+	clear_IO_APIC_pin(0, pin);
+
+	spin_lock_irqsave(&ioapic_lock, flags);
+	io_apic_write(0, 0x11 + 2 * pin, *(((int *)&entry0) + 1));
+	io_apic_write(0, 0x10 + 2 * pin, *(((int *)&entry0) + 0));
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
+/*
+ * This code may look a bit paranoid, but it's supposed to cooperate with
+ * a wide range of boards and BIOS bugs.  Fortunately only the timer IRQ
+ * is so screwy.  Thanks to Brian Perkins for testing/hacking this beast
+ * fanatically on his truly buggy board.
+ */
+static inline void check_timer(void)
+{
+	int pin1, pin2;
+	int vector;
+
+	/*
+	 * get/set the timer IRQ vector:
+	 */
+	disable_8259A_irq(0);
+	vector = assign_irq_vector(0);
+	set_intr_gate(vector, interrupt[0]);
+
+	/*
+	 * Subtle, code in do_timer_interrupt() expects an AEOI
+	 * mode for the 8259A whenever interrupts are routed
+	 * through I/O APICs.  Also IRQ0 has to be enabled in
+	 * the 8259A which implies the virtual wire has to be
+	 * disabled in the local APIC.
+	 */
+	apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
+	init_8259A(1);
+	enable_8259A_irq(0);
+
+	pin1 = find_isa_irq_pin(0, mp_INT);
+	pin2 = find_isa_irq_pin(0, mp_ExtINT);
+
+	printk(KERN_INFO "..TIMER: vector=0x%02X pin1=%d pin2=%d\n", vector, pin1, pin2);
+
+	if (pin1 != -1) {
+		/*
+		 * Ok, does IRQ0 through the IOAPIC work?
+		 */
+		unmask_IO_APIC_irq(0);
+		if (timer_irq_works()) {
+			if (nmi_watchdog == NMI_IO_APIC) {
+				disable_8259A_irq(0);
+				setup_nmi();
+				enable_8259A_irq(0);
+				check_nmi_watchdog();
+			}
+			return;
+		}
+		clear_IO_APIC_pin(0, pin1);
+		printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n");
+	}
+
+	printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... ");
+	if (pin2 != -1) {
+		printk("\n..... (found pin %d) ...", pin2);
+		/*
+		 * legacy devices should be connected to IO APIC #0
+		 */
+		setup_ExtINT_IRQ0_pin(pin2, vector);
+		if (timer_irq_works()) {
+			printk("works.\n");
+			if (pin1 != -1)
+				replace_pin_at_irq(0, 0, pin1, 0, pin2);
+			else
+				add_pin_to_irq(0, 0, pin2);
+			if (nmi_watchdog == NMI_IO_APIC) {
+				setup_nmi();
+				check_nmi_watchdog();
+			}
+			return;
+		}
+		/*
+		 * Cleanup, just in case ...
+		 */
+		clear_IO_APIC_pin(0, pin2);
+	}
+	printk(" failed.\n");
+
+	if (nmi_watchdog) {
+		printk(KERN_WARNING "timer doesnt work through the IO-APIC - disabling NMI Watchdog!\n");
+		nmi_watchdog = 0;
+	}
+
+	printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
+
+	disable_8259A_irq(0);
+	irq_desc[0].handler = &lapic_irq_type;
+	apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector);	/* Fixed mode */
+	enable_8259A_irq(0);
+
+	if (timer_irq_works()) {
+		printk(" works.\n");
+		return;
+	}
+	apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | vector);
+	printk(" failed.\n");
+
+	printk(KERN_INFO "...trying to set up timer as ExtINT IRQ...");
+
+	init_8259A(0);
+	make_8259A_irq(0);
+	apic_write_around(APIC_LVT0, APIC_DM_EXTINT);
+
+	unlock_ExtINT_logic();
+
+	if (timer_irq_works()) {
+		printk(" works.\n");
+		return;
+	}
+	printk(" failed :(.\n");
+	panic("IO-APIC + timer doesn't work! pester mingo@redhat.com");
+}
+
+/*
+ *
+ * IRQ's that are handled by the old PIC in all cases:
+ * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ.
+ *   Linux doesn't really care, as it's not actually used
+ *   for any interrupt handling anyway.
+ * - There used to be IRQ13 here as well, but all
+ *   MPS-compliant must not use it for FPU coupling and we
+ *   want to use exception 16 anyway.  And there are
+ *   systems who connect it to an I/O APIC for other uses.
+ *   Thus we don't mark it special any longer.
+ *
+ * Additionally, something is definitely wrong with irq9
+ * on PIIX4 boards.
+ */
+#define PIC_IRQS	(1<<2)
+
+void __init setup_IO_APIC(void)
+{
+	enable_IO_APIC();
+
+	io_apic_irqs = ~PIC_IRQS;
+	printk("ENABLING IO-APIC IRQs\n");
+
+	/*
+	 * Set up the IO-APIC IRQ routing table by parsing the MP-BIOS
+	 * mptable:
+	 */
+	setup_ioapic_ids_from_mpc();
+	sync_Arb_IDs();
+	setup_IO_APIC_irqs();
+	init_IO_APIC_traps();
+	check_timer();
+	print_IO_APIC();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/ioport.c linux-2.4.20/arch/x86_64/kernel/ioport.c
--- linux-2.4.19/arch/x86_64/kernel/ioport.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/ioport.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,115 @@
+/*
+ *	linux/arch/i386/kernel/ioport.c
+ *
+ * This contains the io-permission bitmap code - written by obz, with changes
+ * by Linus.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+
+/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
+static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value)
+{
+	int mask;
+	unsigned long *bitmap_base = bitmap + (base >> 6);
+	unsigned short low_index = base & 0x3f;
+	int length = low_index + extent;
+
+	if (low_index != 0) {
+		mask = (~0 << low_index);
+		if (length < 64)
+				mask &= ~(~0 << length);
+		if (new_value)
+			*bitmap_base++ |= mask;
+		else
+			*bitmap_base++ &= ~mask;
+		length -= 32;
+	}
+
+	mask = (new_value ? ~0 : 0);
+	while (length >= 64) {
+		*bitmap_base++ = mask;
+		length -= 64;
+	}
+
+	if (length > 0) {
+		mask = ~(~0 << length);
+		if (new_value)
+			*bitmap_base++ |= mask;
+		else
+			*bitmap_base++ &= ~mask;
+	}
+}
+
+/*
+ * this changes the io permissions bitmap in the current task.
+ */
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
+{
+	struct thread_struct * t = &current->thread;
+	struct tss_struct * tss = init_tss + smp_processor_id();
+
+	if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32))
+		return -EINVAL;
+	if (turn_on && !capable(CAP_SYS_RAWIO))
+		return -EPERM;
+	/*
+	 * If it's the first ioperm() call in this thread's lifetime, set the
+	 * IO bitmap up. ioperm() is much less timing critical than clone(),
+	 * this is why we delay this operation until now:
+	 */
+ 	if (!t->io_bitmap_ptr) {
+		t->io_bitmap_ptr = kmalloc((IO_BITMAP_SIZE+1)*4, GFP_KERNEL);
+		if (!t->io_bitmap_ptr) 
+			return -ENOMEM; 
+
+		memset(t->io_bitmap_ptr,0xff,(IO_BITMAP_SIZE+1)*4);
+		/*
+		 * this activates it in the TSS
+		 */
+		tss->io_map_base = IO_BITMAP_OFFSET;
+	}
+
+	/*
+	 * do it in the per-thread copy and in the TSS ...
+	 */
+	set_bitmap((unsigned long *) t->io_bitmap_ptr, from, num, !turn_on);
+	set_bitmap((unsigned long *) tss->io_bitmap, from, num, !turn_on);
+
+	return 0;
+}
+
+/*
+ * sys_iopl has to be used when you want to access the IO ports
+ * beyond the 0x3ff range: to get the full 65536 ports bitmapped
+ * you'd need 8kB of bitmaps/process, which is a bit excessive.
+ *
+ * Here we just change the eflags value on the stack: we allow
+ * only the super-user to do it. This depends on the stack-layout
+ * on system-call entry - see also fork() and the signal handling
+ * code.
+ */
+
+asmlinkage long sys_iopl(unsigned int level, struct pt_regs regs)
+{
+	unsigned int old = (regs.eflags >> 12) & 3;
+
+	if (level > 3)
+		return -EINVAL;
+	/* Trying to gain more privileges? */
+	if (level > old) {
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+	}
+	regs.eflags = (regs.eflags & 0xffffffffffffcfff) | (level << 12);
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/irq.c linux-2.4.20/arch/x86_64/kernel/irq.c
--- linux-2.4.19/arch/x86_64/kernel/irq.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/irq.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,1230 @@
+/*
+ *	linux/arch/x86_64/kernel/irq.c
+ *
+ *	Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
+ *
+ * This file contains the code used by various IRQ handling routines:
+ * asking for different IRQ's should be done through these routines
+ * instead of just grabbing them. Thus setups with different IRQ numbers
+ * shouldn't result in any weird surprises, and installing new handlers
+ * should be easier.
+ */
+
+/*
+ * (mostly architecture independent, will move to kernel/irq.c in 2.5.)
+ *
+ * IRQs are in fact implemented a bit like signal handlers for the kernel.
+ * Naturally it's not a 1:1 relation, but there are similarities.
+ */
+
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/irq.h>
+#include <linux/proc_fs.h>
+
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/delay.h>
+#include <asm/desc.h>
+#include <asm/irq.h>
+#include <asm/proto.h>
+
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+/* 
+ * Probalistic stack overflow check: 
+ * 
+ * Only check the stack in process context, because everything else
+ * runs on the big interrupt stacks. Checking reliably is too expensive,
+ * so we just check from interrupts. 
+ */ 
+static inline void stack_overflow_check(struct pt_regs *regs)
+{ 
+	u64 curbase = (u64) current;
+	static unsigned long warned = -60*HZ; 
+
+	if (regs->rsp >= curbase && regs->rsp <= curbase + THREAD_SIZE &&
+	    regs->rsp <  curbase + sizeof(struct task_struct) + 128 && 
+	    warned + 60*HZ >= jiffies) { 
+		printk("do_IRQ: %s near stack overflow (cur:%Lx,rsp:%lx)\n",
+		       current->comm, curbase, regs->rsp); 
+		show_stack(NULL);
+		warned = jiffies;
+	}
+}
+#endif
+
+/*
+ * Linux has a controller-independent x86 interrupt architecture.
+ * every controller has a 'controller-template', that is used
+ * by the main code to do the right thing. Each driver-visible
+ * interrupt source is transparently wired to the apropriate
+ * controller. Thus drivers need not be aware of the
+ * interrupt-controller.
+ *
+ * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
+ * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
+ * (IO-APICs assumed to be messaging to Pentium local-APICs)
+ *
+ * the code is designed to be easily extended with new/different
+ * interrupt controllers, without having to do assembly magic.
+ */
+
+/*
+ * Controller mappings for all interrupt sources:
+ */
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
+	{ [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}};
+
+static void register_irq_proc (unsigned int irq);
+
+/*
+ * Special irq handlers.
+ */
+
+void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+
+/*
+ * Generic no controller code
+ */
+
+static void enable_none(unsigned int irq) { }
+static unsigned int startup_none(unsigned int irq) { return 0; }
+static void disable_none(unsigned int irq) { }
+static void ack_none(unsigned int irq)
+{
+/*
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves, it doesnt deserve
+ * a generic callback i think.
+ */
+#if CONFIG_X86
+	printk("unexpected IRQ trap at vector %02x\n", irq);
+#ifdef CONFIG_X86_LOCAL_APIC
+	/*
+	 * Currently unexpected vectors happen only on SMP and APIC.
+	 * We _must_ ack these because every local APIC has only N
+	 * irq slots per priority level, and a 'hanging, unacked' IRQ
+	 * holds up an irq slot - in excessive cases (when multiple
+	 * unexpected vectors occur) that might lock up the APIC
+	 * completely.
+	 */
+	ack_APIC_irq();
+#endif
+#endif
+}
+
+/* startup is the same as "enable", shutdown is same as "disable" */
+#define shutdown_none	disable_none
+#define end_none	enable_none
+
+struct hw_interrupt_type no_irq_type = {
+	"none",
+	startup_none,
+	shutdown_none,
+	enable_none,
+	disable_none,
+	ack_none,
+	end_none
+};
+
+atomic_t irq_err_count;
+#ifdef CONFIG_X86_IO_APIC
+#ifdef APIC_MISMATCH_DEBUG
+atomic_t irq_mis_count;
+#endif
+#endif
+
+/*
+ * Generic, controller-independent functions:
+ */
+
+int get_irq_list(char *buf)
+{
+	int i, j;
+	struct irqaction * action;
+	char *p = buf;
+
+	p += sprintf(p, "           ");
+	for (j=0; j<smp_num_cpus; j++)
+		p += sprintf(p, "CPU%d       ",j);
+	*p++ = '\n';
+
+	for (i = 0 ; i < NR_IRQS ; i++) {
+		action = irq_desc[i].action;
+		if (!action) 
+			continue;
+		p += sprintf(p, "%3d: ",i);
+#ifndef CONFIG_SMP
+		p += sprintf(p, "%10u ", kstat_irqs(i));
+#else
+		for (j = 0; j < smp_num_cpus; j++)
+			p += sprintf(p, "%10u ",
+				kstat.irqs[cpu_logical_map(j)][i]);
+#endif
+		p += sprintf(p, " %14s", irq_desc[i].handler->typename);
+		p += sprintf(p, "  %s", action->name);
+
+		for (action=action->next; action; action = action->next)
+			p += sprintf(p, ", %s", action->name);
+		*p++ = '\n';
+	}
+	p += sprintf(p, "NMI: ");
+	for (j = 0; j < smp_num_cpus; j++)
+		p += sprintf(p, "%10u ",
+			nmi_count(cpu_logical_map(j)));
+	p += sprintf(p, "\n");
+#if CONFIG_X86_LOCAL_APIC
+	p += sprintf(p, "LOC: ");
+	for (j = 0; j < smp_num_cpus; j++)
+		p += sprintf(p, "%10u ",
+			apic_timer_irqs[cpu_logical_map(j)]);
+	p += sprintf(p, "\n");
+#endif
+	p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
+#ifdef CONFIG_X86_IO_APIC
+#ifdef APIC_MISMATCH_DEBUG
+	p += sprintf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
+#endif
+#endif
+	return p - buf;
+}
+
+
+/*
+ * Global interrupt locks for SMP. Allow interrupts to come in on any
+ * CPU, yet make cli/sti act globally to protect critical regions..
+ */
+
+#ifdef CONFIG_SMP
+unsigned char global_irq_holder = NO_PROC_ID;
+unsigned volatile long global_irq_lock; /* pendantic: long for set_bit --RR */
+
+extern void show_stack(unsigned long* esp);
+
+
+/* XXX: this unfortunately doesn't support irqs/exception stacks currently, 
+   should check the other PDAs */
+static void show(char * str)
+{
+	int i;
+	int cpu = smp_processor_id();
+
+	printk("\n%s, CPU %d:\n", str, cpu);
+	printk("irq:  %d [",irqs_running());
+	for(i=0;i < smp_num_cpus;i++)
+		printk(" %d",local_irq_count(i));
+	printk(" ]\nbh:   %d [",spin_is_locked(&global_bh_lock) ? 1 : 0);
+	for(i=0;i < smp_num_cpus;i++)
+		printk(" %d",local_bh_count(i));
+
+	printk(" ]\nStack dumps:");
+	for(i = 0; i < smp_num_cpus; i++) {
+		unsigned long esp;
+		if (i == cpu)
+			continue;
+		printk("\nCPU %d:",i);
+		esp = init_tss[i].rsp0;
+		if (!esp) {
+			/* tss->esp0 is set to NULL in cpu_init(),
+			 * it's initialized when the cpu returns to user
+			 * space. -- manfreds
+			 */
+			printk(" <unknown> ");
+			continue;
+		}
+		esp &= ~(THREAD_SIZE-1);
+		esp += sizeof(struct task_struct);
+		show_stack((void*)esp);
+ 	}
+	printk("\nCPU %d:",cpu);
+	show_stack(NULL);
+	printk("\n");
+}
+	
+#define MAXCOUNT 100000000
+
+/*
+ * I had a lockup scenario where a tight loop doing
+ * spin_unlock()/spin_lock() on CPU#1 was racing with
+ * spin_lock() on CPU#0. CPU#0 should have noticed spin_unlock(), but
+ * apparently the spin_unlock() information did not make it
+ * through to CPU#0 ... nasty, is this by design, do we have to limit
+ * 'memory update oscillation frequency' artificially like here?
+ *
+ * Such 'high frequency update' races can be avoided by careful design, but
+ * some of our major constructs like spinlocks use similar techniques,
+ * it would be nice to clarify this issue. Set this define to 0 if you
+ * want to check whether your system freezes.  I suspect the delay done
+ * by SYNC_OTHER_CORES() is in correlation with 'snooping latency', but
+ * i thought that such things are guaranteed by design, since we use
+ * the 'LOCK' prefix.
+ */
+#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 0
+
+#if SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND
+# define SYNC_OTHER_CORES(x) udelay(x+1)
+#else
+/*
+ * We have to allow irqs to arrive between __sti and __cli
+ */
+# define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop")
+#endif
+
+static inline void wait_on_irq(int cpu)
+{
+	int count = MAXCOUNT;
+
+	for (;;) {
+
+		/*
+		 * Wait until all interrupts are gone. Wait
+		 * for bottom half handlers unless we're
+		 * already executing in one..
+		 */
+		if (!irqs_running())
+			if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock))
+				break;
+
+		/* Duh, we have to loop. Release the lock to avoid deadlocks */
+		clear_bit(0,&global_irq_lock);
+
+		for (;;) {
+			if (!--count) {
+				show("wait_on_irq");
+				count = ~0;
+			}
+			__sti();
+			SYNC_OTHER_CORES(cpu);
+			__cli();
+			if (irqs_running())
+				continue;
+			if (global_irq_lock)
+				continue;
+			if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock))
+				continue;
+			if (!test_and_set_bit(0,&global_irq_lock))
+				break;
+		}
+	}
+}
+
+/*
+ * This is called when we want to synchronize with
+ * interrupts. We may for example tell a device to
+ * stop sending interrupts: but to make sure there
+ * are no interrupts that are executing on another
+ * CPU we need to call this function.
+ */
+void synchronize_irq(void)
+{
+	if (irqs_running()) {
+		/* Stupid approach */
+		cli();
+		sti();
+	}
+}
+
+static inline void get_irqlock(int cpu)
+{
+	if (test_and_set_bit(0,&global_irq_lock)) {
+		/* do we already hold the lock? */
+		if ((unsigned char) cpu == global_irq_holder)
+			return;
+		/* Uhhuh.. Somebody else got it. Wait.. */
+		do {
+			do {
+				rep_nop();
+			} while (test_bit(0,&global_irq_lock));
+		} while (test_and_set_bit(0,&global_irq_lock));		
+	}
+	/* 
+	 * We also to make sure that nobody else is running
+	 * in an interrupt context. 
+	 */
+	wait_on_irq(cpu);
+
+	/*
+	 * Ok, finally..
+	 */
+	global_irq_holder = cpu;
+}
+
+#define EFLAGS_IF_SHIFT 9
+
+/*
+ * A global "cli()" while in an interrupt context
+ * turns into just a local cli(). Interrupts
+ * should use spinlocks for the (very unlikely)
+ * case that they ever want to protect against
+ * each other.
+ *
+ * If we already have local interrupts disabled,
+ * this will not turn a local disable into a
+ * global one (problems with spinlocks: this makes
+ * save_flags+cli+sti usable inside a spinlock).
+ */
+void __global_cli(void)
+{
+	unsigned long flags;
+
+	__save_flags(flags);
+	if (flags & (1U << EFLAGS_IF_SHIFT)) {
+		int cpu = smp_processor_id();
+		__cli();
+		if (!local_irq_count(cpu))
+			get_irqlock(cpu);
+	}
+}
+
+void __global_sti(void)
+{
+	int cpu = smp_processor_id();
+
+	if (!local_irq_count(cpu))
+		release_irqlock(cpu);
+	__sti();
+}
+
+/*
+ * SMP flags value to restore to:
+ * 0 - global cli
+ * 1 - global sti
+ * 2 - local cli
+ * 3 - local sti
+ */
+unsigned long __global_save_flags(void)
+{
+	int retval;
+	int local_enabled;
+	unsigned long flags;
+	int cpu = smp_processor_id();
+
+	__save_flags(flags);
+	local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1;
+	/* default to local */
+	retval = 2 + local_enabled;
+
+	/* check for global flags if we're not in an interrupt */
+	if (!local_irq_count(cpu)) {
+		if (local_enabled)
+			retval = 1;
+		if (global_irq_holder == cpu)
+			retval = 0;
+	}
+	return retval;
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+	switch (flags) {
+	case 0:
+		__global_cli();
+		break;
+	case 1:
+		__global_sti();
+		break;
+	case 2:
+		__cli();
+		break;
+	case 3:
+		__sti();
+		break;
+	default:
+		printk("global_restore_flags: %08lx (%08lx)\n",
+			flags, (&flags)[-1]);
+	}
+}
+
+#endif
+
+/*
+ * This should really return information about whether
+ * we should do bottom half handling etc. Right now we
+ * end up _always_ checking the bottom half, which is a
+ * waste of time and is not what some drivers would
+ * prefer.
+ */
+int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action)
+{
+	int status;
+	int cpu = smp_processor_id();
+
+	irq_enter(cpu, irq);
+
+	status = 1;	/* Force the "do bottom halves" bit */
+
+	if (!(action->flags & SA_INTERRUPT))
+		__sti();
+
+	do {
+		status |= action->flags;
+		action->handler(irq, action->dev_id, regs);
+		action = action->next;
+	} while (action);
+	if (status & SA_SAMPLE_RANDOM)
+		add_interrupt_randomness(irq);
+	__cli();
+
+	irq_exit(cpu, irq);
+
+	return status;
+}
+
+/*
+ * Generic enable/disable code: this just calls
+ * down into the PIC-specific version for the actual
+ * hardware disable after having gotten the irq
+ * controller lock. 
+ */
+ 
+/**
+ *	disable_irq_nosync - disable an irq without waiting
+ *	@irq: Interrupt to disable
+ *
+ *	Disable the selected interrupt line.  Disables and Enables are
+ *	nested.
+ *	Unlike disable_irq(), this function does not ensure existing
+ *	instances of the IRQ handler have completed before returning.
+ *
+ *	This function may be called from IRQ context.
+ */
+ 
+inline void disable_irq_nosync(unsigned int irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&desc->lock, flags);
+	if (!desc->depth++) {
+		desc->status |= IRQ_DISABLED;
+		desc->handler->disable(irq);
+	}
+	spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/**
+ *	disable_irq - disable an irq and wait for completion
+ *	@irq: Interrupt to disable
+ *
+ *	Disable the selected interrupt line.  Enables and Disables are
+ *	nested.
+ *	This function waits for any pending IRQ handlers for this interrupt
+ *	to complete before returning. If you use this function while
+ *	holding a resource the IRQ handler may need you will deadlock.
+ *
+ *	This function may be called - with care - from IRQ context.
+ */
+ 
+void disable_irq(unsigned int irq)
+{
+	disable_irq_nosync(irq);
+
+	if (!local_irq_count(smp_processor_id())) {
+		do {
+			barrier();
+			cpu_relax();
+		} while (irq_desc[irq].status & IRQ_INPROGRESS);
+	}
+}
+
+/**
+ *	enable_irq - enable handling of an irq
+ *	@irq: Interrupt to enable
+ *
+ *	Undoes the effect of one call to disable_irq().  If this
+ *	matches the last disable, processing of interrupts on this
+ *	IRQ line is re-enabled.
+ *
+ *	This function may be called from IRQ context.
+ */
+ 
+void enable_irq(unsigned int irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&desc->lock, flags);
+	switch (desc->depth) {
+	case 1: {
+		unsigned int status = desc->status & ~IRQ_DISABLED;
+		desc->status = status;
+		if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+			desc->status = status | IRQ_REPLAY;
+			hw_resend_irq(desc->handler,irq);
+		}
+		desc->handler->enable(irq);
+		/* fall-through */
+	}
+	default:
+		desc->depth--;
+		break;
+	case 0:
+		printk("enable_irq(%u) unbalanced from %p\n", irq,
+		       __builtin_return_address(0));
+	}
+	spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/*
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
+asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
+{	
+	/* 
+	 * We ack quickly, we don't want the irq controller
+	 * thinking we're snobs just because some other CPU has
+	 * disabled global interrupts (we have already done the
+	 * INT_ACK cycles, it's too late to try to pretend to the
+	 * controller that we aren't taking the interrupt).
+	 *
+	 * 0 return value means that this irq is already being
+	 * handled by some other CPU. (or is disabled)
+	 */
+	int irq = regs->orig_rax & 0xff; /* high bits used in ret_from_ code  */
+	int cpu = smp_processor_id();
+	irq_desc_t *desc = irq_desc + irq;
+	struct irqaction * action;
+	unsigned int status;
+
+
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+	stack_overflow_check(regs); 
+#endif
+	       
+	kstat.irqs[cpu][irq]++;
+	spin_lock(&desc->lock);
+	desc->handler->ack(irq);
+	/*
+	   REPLAY is when Linux resends an IRQ that was dropped earlier
+	   WAITING is used by probe to mark irqs that are being tested */
+	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
+	status |= IRQ_PENDING; /* we _want_ to handle it */
+
+	/*
+	 * If the IRQ is disabled for whatever reason, we cannot
+	 * use the action we have.
+	 */
+	action = NULL;
+	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+		action = desc->action;
+		status &= ~IRQ_PENDING; /* we commit to handling */
+		status |= IRQ_INPROGRESS; /* we are handling it */
+	}
+	desc->status = status;
+
+	/*
+	 * If there is no IRQ handler or it was disabled, exit early.
+	   Since we set PENDING, if another processor is handling
+	   a different instance of this same irq, the other processor
+	   will take care of it.
+	 */
+	if (!action)
+		goto out;
+
+	/*
+	 * Edge triggered interrupts need to remember
+	 * pending events.
+	 * This applies to any hw interrupts that allow a second
+	 * instance of the same irq to arrive while we are in do_IRQ
+	 * or in the handler. But the code here only handles the _second_
+	 * instance of the irq, not the third or fourth. So it is mostly
+	 * useful for irq hardware that does not mask cleanly in an
+	 * SMP environment.
+	 */
+	for (;;) {
+		spin_unlock(&desc->lock);
+		handle_IRQ_event(irq, regs, action);
+		spin_lock(&desc->lock);
+		
+		if (!(desc->status & IRQ_PENDING))
+			break;
+		desc->status &= ~IRQ_PENDING;
+	}
+	desc->status &= ~IRQ_INPROGRESS;
+out:
+	/*
+	 * The ->end() handler has to deal with interrupts which got
+	 * disabled while the handler was running.
+	 */
+	desc->handler->end(irq);
+	spin_unlock(&desc->lock);
+
+	if (softirq_pending(cpu))
+		do_softirq();
+	return 1;
+}
+
+/**
+ *	request_irq - allocate an interrupt line
+ *	@irq: Interrupt line to allocate
+ *	@handler: Function to be called when the IRQ occurs
+ *	@irqflags: Interrupt type flags
+ *	@devname: An ascii name for the claiming device
+ *	@dev_id: A cookie passed back to the handler function
+ *
+ *	This call allocates interrupt resources and enables the
+ *	interrupt line and IRQ handling. From the point this
+ *	call is made your handler function may be invoked. Since
+ *	your handler function must clear any interrupt the board 
+ *	raises, you must take care both to initialise your hardware
+ *	and to set up the interrupt handler in the right order.
+ *
+ *	Dev_id must be globally unique. Normally the address of the
+ *	device data structure is used as the cookie. Since the handler
+ *	receives this value it makes sense to use it.
+ *
+ *	If your interrupt is shared you must pass a non NULL dev_id
+ *	as this is required when freeing the interrupt.
+ *
+ *	Flags:
+ *
+ *	SA_SHIRQ		Interrupt is shared
+ *
+ *	SA_INTERRUPT		Disable local interrupts while processing
+ *
+ *	SA_SAMPLE_RANDOM	The interrupt can be used for entropy
+ *
+ */
+ 
+int request_irq(unsigned int irq, 
+		void (*handler)(int, void *, struct pt_regs *),
+		unsigned long irqflags, 
+		const char * devname,
+		void *dev_id)
+{
+	int retval;
+	struct irqaction * action;
+
+#if 1
+	/*
+	 * Sanity-check: shared interrupts should REALLY pass in
+	 * a real dev-ID, otherwise we'll have trouble later trying
+	 * to figure out which interrupt is which (messes up the
+	 * interrupt freeing logic etc).
+	 */
+	if (irqflags & SA_SHIRQ) {
+		if (!dev_id)
+			printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]);
+	}
+#endif
+
+	if (irq >= NR_IRQS)
+		return -EINVAL;
+	if (!handler)
+		return -EINVAL;
+
+	action = (struct irqaction *)
+			kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+	if (!action)
+		return -ENOMEM;
+
+	action->handler = handler;
+	action->flags = irqflags;
+	action->mask = 0;
+	action->name = devname;
+	action->next = NULL;
+	action->dev_id = dev_id;
+
+	retval = setup_irq(irq, action);
+	if (retval)
+		kfree(action);
+	return retval;
+}
+
+/**
+ *	free_irq - free an interrupt
+ *	@irq: Interrupt line to free
+ *	@dev_id: Device identity to free
+ *
+ *	Remove an interrupt handler. The handler is removed and if the
+ *	interrupt line is no longer in use by any driver it is disabled.
+ *	On a shared IRQ the caller must ensure the interrupt is disabled
+ *	on the card it drives before calling this function. The function
+ *	does not return until any executing interrupts for this IRQ
+ *	have completed.
+ *
+ *	This function may be called from interrupt context. 
+ *
+ *	Bugs: Attempting to free an irq in a handler for the same irq hangs
+ *	      the machine.
+ */
+ 
+void free_irq(unsigned int irq, void *dev_id)
+{
+	irq_desc_t *desc;
+	struct irqaction **p;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS)
+		return;
+
+	desc = irq_desc + irq;
+	spin_lock_irqsave(&desc->lock,flags);
+	p = &desc->action;
+	for (;;) {
+		struct irqaction * action = *p;
+		if (action) {
+			struct irqaction **pp = p;
+			p = &action->next;
+			if (action->dev_id != dev_id)
+				continue;
+
+			/* Found it - now remove it from the list of entries */
+			*pp = action->next;
+			if (!desc->action) {
+				desc->status |= IRQ_DISABLED;
+				desc->handler->shutdown(irq);
+			}
+			spin_unlock_irqrestore(&desc->lock,flags);
+
+#ifdef CONFIG_SMP
+			/* Wait to make sure it's not being used on another CPU */
+			while (desc->status & IRQ_INPROGRESS) {
+				barrier();
+				cpu_relax();
+			}
+#endif
+			kfree(action);
+			return;
+		}
+		printk("Trying to free free IRQ%d\n",irq);
+		spin_unlock_irqrestore(&desc->lock,flags);
+		return;
+	}
+}
+
+/*
+ * IRQ autodetection code..
+ *
+ * This depends on the fact that any interrupt that
+ * comes in on to an unassigned handler will get stuck
+ * with "IRQ_WAITING" cleared and the interrupt
+ * disabled.
+ */
+
+static DECLARE_MUTEX(probe_sem);
+
+/**
+ *	probe_irq_on	- begin an interrupt autodetect
+ *
+ *	Commence probing for an interrupt. The interrupts are scanned
+ *	and a mask of potential interrupt lines is returned.
+ *
+ */
+ 
+unsigned long probe_irq_on(void)
+{
+	unsigned int i;
+	irq_desc_t *desc;
+	unsigned long val;
+	unsigned long delay;
+
+	down(&probe_sem);
+	/* 
+	 * something may have generated an irq long ago and we want to
+	 * flush such a longstanding irq before considering it as spurious. 
+	 */
+	for (i = NR_IRQS-1; i > 0; i--)  {
+		desc = irq_desc + i;
+
+		spin_lock_irq(&desc->lock);
+		if (!irq_desc[i].action) 
+			irq_desc[i].handler->startup(i);
+		spin_unlock_irq(&desc->lock);
+	}
+
+	/* Wait for longstanding interrupts to trigger. */
+	for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
+		/* about 20ms delay */ synchronize_irq();
+
+	/*
+	 * enable any unassigned irqs
+	 * (we must startup again here because if a longstanding irq
+	 * happened in the previous stage, it may have masked itself)
+	 */
+	for (i = NR_IRQS-1; i > 0; i--) {
+		desc = irq_desc + i;
+
+		spin_lock_irq(&desc->lock);
+		if (!desc->action) {
+			desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
+			if (desc->handler->startup(i))
+				desc->status |= IRQ_PENDING;
+		}
+		spin_unlock_irq(&desc->lock);
+	}
+
+	/*
+	 * Wait for spurious interrupts to trigger
+	 */
+	for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
+		/* about 100ms delay */ synchronize_irq();
+
+	/*
+	 * Now filter out any obviously spurious interrupts
+	 */
+	val = 0;
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc_t *desc = irq_desc + i;
+		unsigned int status;
+
+		spin_lock_irq(&desc->lock);
+		status = desc->status;
+
+		if (status & IRQ_AUTODETECT) {
+			/* It triggered already - consider it spurious. */
+			if (!(status & IRQ_WAITING)) {
+				desc->status = status & ~IRQ_AUTODETECT;
+				desc->handler->shutdown(i);
+			} else
+				if (i < 32)
+					val |= 1 << i;
+		}
+		spin_unlock_irq(&desc->lock);
+	}
+
+	return val;
+}
+
+/*
+ * Return a mask of triggered interrupts (this
+ * can handle only legacy ISA interrupts).
+ */
+ 
+/**
+ *	probe_irq_mask - scan a bitmap of interrupt lines
+ *	@val:	mask of interrupts to consider
+ *
+ *	Scan the ISA bus interrupt lines and return a bitmap of
+ *	active interrupts. The interrupt probe logic state is then
+ *	returned to its previous value.
+ *
+ *	Note: we need to scan all the irq's even though we will
+ *	only return ISA irq numbers - just so that we reset them
+ *	all to a known state.
+ */
+unsigned int probe_irq_mask(unsigned long val)
+{
+	int i;
+	unsigned int mask;
+
+	mask = 0;
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc_t *desc = irq_desc + i;
+		unsigned int status;
+
+		spin_lock_irq(&desc->lock);
+		status = desc->status;
+
+		if (status & IRQ_AUTODETECT) {
+			if (i < 16 && !(status & IRQ_WAITING))
+				mask |= 1 << i;
+
+			desc->status = status & ~IRQ_AUTODETECT;
+			desc->handler->shutdown(i);
+		}
+		spin_unlock_irq(&desc->lock);
+	}
+	up(&probe_sem);
+
+	return mask & val;
+}
+
+/*
+ * Return the one interrupt that triggered (this can
+ * handle any interrupt source).
+ */
+
+/**
+ *	probe_irq_off	- end an interrupt autodetect
+ *	@val: mask of potential interrupts (unused)
+ *
+ *	Scans the unused interrupt lines and returns the line which
+ *	appears to have triggered the interrupt. If no interrupt was
+ *	found then zero is returned. If more than one interrupt is
+ *	found then minus the first candidate is returned to indicate
+ *	their is doubt.
+ *
+ *	The interrupt probe logic state is returned to its previous
+ *	value.
+ *
+ *	BUGS: When used in a module (which arguably shouldnt happen)
+ *	nothing prevents two IRQ probe callers from overlapping. The
+ *	results of this are non-optimal.
+ */
+ 
+int probe_irq_off(unsigned long val)
+{
+	int i, irq_found, nr_irqs;
+
+	nr_irqs = 0;
+	irq_found = 0;
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc_t *desc = irq_desc + i;
+		unsigned int status;
+
+		spin_lock_irq(&desc->lock);
+		status = desc->status;
+
+		if (status & IRQ_AUTODETECT) {
+			if (!(status & IRQ_WAITING)) {
+				if (!nr_irqs)
+					irq_found = i;
+				nr_irqs++;
+			}
+			desc->status = status & ~IRQ_AUTODETECT;
+			desc->handler->shutdown(i);
+		}
+		spin_unlock_irq(&desc->lock);
+	}
+	up(&probe_sem);
+
+	if (nr_irqs > 1)
+		irq_found = -irq_found;
+	return irq_found;
+}
+
+/* this was setup_x86_irq but it seems pretty generic */
+int setup_irq(unsigned int irq, struct irqaction * new)
+{
+	int shared = 0;
+	unsigned long flags;
+	struct irqaction *old, **p;
+	irq_desc_t *desc = irq_desc + irq;
+
+	/*
+	 * Some drivers like serial.c use request_irq() heavily,
+	 * so we have to be careful not to interfere with a
+	 * running system.
+	 */
+	if (new->flags & SA_SAMPLE_RANDOM) {
+		/*
+		 * This function might sleep, we want to call it first,
+		 * outside of the atomic block.
+		 * Yes, this might clear the entropy pool if the wrong
+		 * driver is attempted to be loaded, without actually
+		 * installing a new handler, but is this really a problem,
+		 * only the sysadmin is able to do this.
+		 */
+		rand_initialize_irq(irq);
+	}
+
+	/*
+	 * The following block of code has to be executed atomically
+	 */
+	spin_lock_irqsave(&desc->lock,flags);
+	p = &desc->action;
+	if ((old = *p) != NULL) {
+		/* Can't share interrupts unless both agree to */
+		if (!(old->flags & new->flags & SA_SHIRQ)) {
+			spin_unlock_irqrestore(&desc->lock,flags);
+			return -EBUSY;
+		}
+
+		/* add new interrupt at end of irq queue */
+		do {
+			p = &old->next;
+			old = *p;
+		} while (old);
+		shared = 1;
+	}
+
+	*p = new;
+
+	if (!shared) {
+		desc->depth = 0;
+		desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
+		desc->handler->startup(irq);
+	}
+	spin_unlock_irqrestore(&desc->lock,flags);
+
+	register_irq_proc(irq);
+	return 0;
+}
+
+static struct proc_dir_entry * root_irq_dir;
+static struct proc_dir_entry * irq_dir [NR_IRQS];
+
+#define HEX_DIGITS 8
+
+static unsigned int parse_hex_value (const char *buffer,
+		unsigned long count, unsigned long *ret)
+{
+	unsigned char hexnum [HEX_DIGITS];
+	unsigned long value;
+	int i;
+
+	if (!count)
+		return -EINVAL;
+	if (count > HEX_DIGITS)
+		count = HEX_DIGITS;
+	if (copy_from_user(hexnum, buffer, count))
+		return -EFAULT;
+
+	/*
+	 * Parse the first 8 characters as a hex string, any non-hex char
+	 * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same.
+	 */
+	value = 0;
+
+	for (i = 0; i < count; i++) {
+		unsigned int c = hexnum[i];
+
+		switch (c) {
+			case '0' ... '9': c -= '0'; break;
+			case 'a' ... 'f': c -= 'a'-10; break;
+			case 'A' ... 'F': c -= 'A'-10; break;
+		default:
+			goto out;
+		}
+		value = (value << 4) | c;
+	}
+out:
+	*ret = value;
+	return 0;
+}
+
+#if CONFIG_SMP
+
+static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
+
+static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
+static int irq_affinity_read_proc (char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	if (count < HEX_DIGITS+1)
+		return -EINVAL;
+	return sprintf (page, "%08lx\n", irq_affinity[(long)data]);
+}
+
+static int irq_affinity_write_proc (struct file *file, const char *buffer,
+					unsigned long count, void *data)
+{
+	int irq = (long) data, full_count = count, err;
+	unsigned long new_value;
+
+	if (!irq_desc[irq].handler->set_affinity)
+		return -EIO;
+
+	err = parse_hex_value(buffer, count, &new_value);
+
+	/*
+	 * Do not allow disabling IRQs completely - it's a too easy
+	 * way to make the system unusable accidentally :-) At least
+	 * one online CPU still has to be targeted.
+	 */
+	if (!(new_value & cpu_online_map))
+		return -EINVAL;
+
+	irq_affinity[irq] = new_value;
+	irq_desc[irq].handler->set_affinity(irq, new_value);
+
+	return full_count;
+}
+
+#endif
+
+static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	unsigned long *mask = (unsigned long *) data;
+	if (count < HEX_DIGITS+1)
+		return -EINVAL;
+	return sprintf (page, "%08lx\n", *mask);
+}
+
+static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
+					unsigned long count, void *data)
+{
+	unsigned long *mask = (unsigned long *) data, full_count = count, err;
+	unsigned long new_value;
+
+	err = parse_hex_value(buffer, count, &new_value);
+	if (err)
+		return err;
+
+	*mask = new_value;
+	return full_count;
+}
+
+#define MAX_NAMELEN 10
+
+static void register_irq_proc (unsigned int irq)
+{
+	char name [MAX_NAMELEN];
+
+	if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
+			irq_dir[irq])
+		return;
+
+	memset(name, 0, MAX_NAMELEN);
+	sprintf(name, "%d", irq);
+
+	/* create /proc/irq/1234 */
+	irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+
+#if CONFIG_SMP
+	{
+		struct proc_dir_entry *entry;
+
+		/* create /proc/irq/1234/smp_affinity */
+		entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+
+		if (entry) {
+			entry->nlink = 1;
+			entry->data = (void *)(long)irq;
+			entry->read_proc = irq_affinity_read_proc;
+			entry->write_proc = irq_affinity_write_proc;
+		}
+
+		smp_affinity_entry[irq] = entry;
+	}
+#endif
+}
+
+unsigned long prof_cpu_mask = -1;
+
+void init_irq_proc (void)
+{
+	struct proc_dir_entry *entry;
+	int i;
+
+	/* create /proc/irq */
+	root_irq_dir = proc_mkdir("irq", 0);
+
+	/* create /proc/irq/prof_cpu_mask */
+	entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
+
+	if (!entry)
+	    return;
+
+	entry->nlink = 1;
+	entry->data = (void *)&prof_cpu_mask;
+	entry->read_proc = prof_cpu_mask_read_proc;
+	entry->write_proc = prof_cpu_mask_write_proc;
+
+	/*
+	 * Create entries for all existing IRQs.
+	 */
+	for (i = 0; i < NR_IRQS; i++)
+		register_irq_proc(i);
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/ldt.c linux-2.4.20/arch/x86_64/kernel/ldt.c
--- linux-2.4.19/arch/x86_64/kernel/ldt.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/ldt.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,176 @@
+/*
+ * linux/arch/x86_64/kernel/ldt.c
+ *
+ * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ * Copyright (C) 2002 Andi Kleen
+ * 
+ * Manage the local descriptor table for user processes.
+ * This handles calls from both 32bit and 64bit mode.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/ldt.h>
+#include <asm/desc.h>
+
+/*
+ * read_ldt() is not really atomic - this is not a problem since
+ * synchronization of reads and writes done to the LDT has to be
+ * assured by user-space anyway. Writes are atomic, to protect
+ * the security checks done on new descriptors.
+ */
+static int read_ldt(void * ptr, unsigned long bytecount)
+{
+	int err;
+	unsigned long size;
+	struct mm_struct * mm = current->mm;
+
+	err = 0;
+	if (!mm->context.segments)
+		goto out;
+
+	size = LDT_ENTRIES*LDT_ENTRY_SIZE;
+	if (size > bytecount)
+		size = bytecount;
+
+	err = size;
+	if (copy_to_user(ptr, mm->context.segments, size))
+		err = -EFAULT;
+out:
+	return err;
+}
+
+static int read_default_ldt(void * ptr, unsigned long bytecount)
+{
+	/* Arbitary number */ 
+	if (bytecount > 128) 
+		bytecount = 128; 	
+	if (clear_user(ptr, bytecount))
+		return -EFAULT;
+	return bytecount; 
+}
+
+static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
+{
+	struct task_struct *me = current;
+	struct mm_struct * mm = me->mm;
+	__u32 entry_1, entry_2, *lp;
+	int error;
+	struct modify_ldt_ldt_s ldt_info;
+
+	error = -EINVAL;
+
+	if (bytecount != sizeof(ldt_info))
+		goto out;
+	error = -EFAULT; 	
+	if (copy_from_user(&ldt_info, ptr, bytecount))
+		goto out;
+
+	error = -EINVAL;
+	if (ldt_info.entry_number >= LDT_ENTRIES)
+		goto out;
+	if (ldt_info.contents == 3) {
+		if (oldmode)
+			goto out;
+		if (ldt_info.seg_not_present == 0)
+			goto out;
+	}
+
+	me->thread.fsindex = 0; 
+	me->thread.gsindex = 0; 
+	me->thread.gs = 0; 
+	me->thread.fs = 0; 
+
+	/*
+	 * the GDT index of the LDT is allocated dynamically, and is
+	 * limited by MAX_LDT_DESCRIPTORS.
+	 */
+	down_write(&mm->mmap_sem);
+	if (!mm->context.segments) {
+		void * segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
+		error = -ENOMEM;
+		if (!segments)
+			goto out_unlock;
+		memset(segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
+		wmb();
+		mm->context.segments = segments;
+		mm->context.cpuvalid = 1UL << smp_processor_id();
+		load_LDT(mm);
+	}
+
+	lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.segments);
+
+   	/* Allow LDTs to be cleared by the user. */
+   	if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
+		if (oldmode ||
+		    (ldt_info.contents == 0		&&
+		     ldt_info.read_exec_only == 1	&&
+		     ldt_info.seg_32bit == 0		&&
+		     ldt_info.limit_in_pages == 0	&&
+		     ldt_info.seg_not_present == 1	&&
+		     ldt_info.useable == 0 && 
+		     ldt_info.lm == 0)) {
+			entry_1 = 0;
+			entry_2 = 0;
+			goto install;
+		}
+	}
+
+	entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
+		  (ldt_info.limit & 0x0ffff);
+	entry_2 = (ldt_info.base_addr & 0xff000000) |
+		  ((ldt_info.base_addr & 0x00ff0000) >> 16) |
+		  (ldt_info.limit & 0xf0000) |
+		  ((ldt_info.read_exec_only ^ 1) << 9) |
+		  (ldt_info.contents << 10) |
+		  ((ldt_info.seg_not_present ^ 1) << 15) |
+		  (ldt_info.seg_32bit << 22) |
+		  (ldt_info.limit_in_pages << 23) |
+		  (ldt_info.lm << 21) |
+		  0x7000;
+	if (!oldmode)
+		entry_2 |= (ldt_info.useable << 20);
+
+	/* Install the new entry ...  */
+install:
+	write_lock(&mm->context.ldtlock);
+	*lp	= entry_1;
+	*(lp+1)	= entry_2;
+	write_unlock(&mm->context.ldtlock);
+	error = 0;
+
+out_unlock:
+	up_write(&mm->mmap_sem);
+out:
+	return error;
+}
+
+asmlinkage long sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
+{
+	int ret = -ENOSYS;
+
+	switch (func) {
+	case 0:
+		ret = read_ldt(ptr, bytecount);
+		break;
+	case 1:
+		ret = write_ldt(ptr, bytecount, 1);
+		break;
+	case 2:
+		ret = read_default_ldt(ptr, bytecount);
+		break;
+	case 0x11:
+		ret = write_ldt(ptr, bytecount, 0);
+		break;
+	}
+	return ret;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/mpparse.c linux-2.4.20/arch/x86_64/kernel/mpparse.c
--- linux-2.4.19/arch/x86_64/kernel/mpparse.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/mpparse.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,616 @@
+/*
+ *	Intel Multiprocessor Specificiation 1.1 and 1.4
+ *	compliant MP-table parsing routines.
+ *
+ *	(c) 1995 Alan Cox, Building #3 <alan@redhat.com>
+ *	(c) 1998, 1999, 2000 Ingo Molnar <mingo@redhat.com>
+ *
+ *	Fixes
+ *		Erich Boleyn	:	MP v1.4 and additional changes.
+ *		Alan Cox	:	Added EBDA scanning
+ *		Ingo Molnar	:	various cleanups and rewrites
+ *	Maciej W. Rozycki	:	Bits for default MP configurations
+ */
+
+#include <linux/mm.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/config.h>
+#include <linux/bootmem.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/smp.h>
+#include <asm/mtrr.h>
+#include <asm/mpspec.h>
+#include <asm/pgalloc.h>
+#include <asm/e820.h>
+#include <asm/proto.h>
+
+/* Have we found an MP table */
+int smp_found_config = 0;
+
+/*
+ * Various Linux-internal data structures created from the
+ * MP-table.
+ */
+int apic_version [MAX_APICS];
+int mp_bus_id_to_type [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
+int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
+int mp_current_pci_id = 0;
+/* I/O APIC entries */
+struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
+
+/* # of MP IRQ source entries */
+struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+
+/* MP IRQ source entries */
+int mp_irq_entries;
+
+int nr_ioapics;
+int pic_mode;
+unsigned long mp_lapic_addr = 0;
+
+
+
+/* Processor that is doing the boot up */
+unsigned int boot_cpu_id = -1U;
+/* Internal processor count */
+static unsigned int num_processors = 0;
+
+/* Bitmask of physically existing CPUs */
+unsigned long phys_cpu_present_map = 0;
+
+/*
+ * Intel MP BIOS table parsing routines:
+ */
+
+/*
+ * Checksum an MP configuration block.
+ */
+
+static int __init mpf_checksum(unsigned char *mp, int len)
+{
+	int sum = 0;
+
+	while (len--)
+		sum += *mp++;
+
+	return sum & 0xFF;
+}
+
+static void __init MP_processor_info (struct mpc_config_processor *m)
+{
+	int ver;
+
+	if (!(m->mpc_cpuflag & CPU_ENABLED))
+		return;
+
+	printk("Processor #%d %d:%d APIC version %d\n",
+		m->mpc_apicid,
+	       (m->mpc_cpufeature & CPU_FAMILY_MASK)>>8,
+	       (m->mpc_cpufeature & CPU_MODEL_MASK)>>4,
+		m->mpc_apicver);
+
+	if (m->mpc_featureflag&(1<<0))
+		Dprintk("    Floating point unit present.\n");
+	if (m->mpc_featureflag&(1<<7))
+		Dprintk("    Machine Exception supported.\n");
+	if (m->mpc_featureflag&(1<<8))
+		Dprintk("    64 bit compare & exchange supported.\n");
+	if (m->mpc_featureflag&(1<<9))
+		Dprintk("    Internal APIC present.\n");
+
+	if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
+		Dprintk("    Bootup CPU\n");
+		boot_cpu_id = m->mpc_apicid;
+	}
+	num_processors++;
+
+	if (m->mpc_apicid > MAX_APICS) {
+		printk("Processor #%d INVALID. (Max ID: %d).\n",
+			m->mpc_apicid, MAX_APICS);
+		return;
+	}
+	ver = m->mpc_apicver;
+
+	phys_cpu_present_map |= 1 << m->mpc_apicid;
+	/*
+	 * Validate version
+	 */
+	if (ver == 0x0) {
+		printk("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid);
+		ver = 0x10;
+	}
+	apic_version[m->mpc_apicid] = ver;
+}
+
+static void __init MP_bus_info (struct mpc_config_bus *m)
+{
+	char str[7];
+
+	memcpy(str, m->mpc_bustype, 6);
+	str[6] = 0;
+	Dprintk("Bus #%d is %s\n", m->mpc_busid, str);
+
+	if (m->mpc_busid >= MAX_MP_BUSSES) {
+		printk(KERN_ERR "MAX_MP_BUSSES ERROR mpc_busid %d, max %d\n", m->mpc_busid, MAX_MP_BUSSES);
+	} else if (strncmp(str, "ISA", 3) == 0) {
+		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA;
+	} else if (strncmp(str, "EISA", 4) == 0) {
+		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA;
+	} else if (strncmp(str, "PCI", 3) == 0) {
+		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI;
+		mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id;
+		mp_current_pci_id++;
+	} else if (strncmp(str, "MCA", 3) == 0) {
+		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA;
+	} else {
+		printk("Unknown bustype %s\n", str);
+		panic("cannot handle bus - mail to linux-smp@vger.kernel.org");
+	}
+}
+
+static void __init MP_ioapic_info (struct mpc_config_ioapic *m)
+{
+	if (!(m->mpc_flags & MPC_APIC_USABLE))
+		return;
+
+	printk("I/O APIC #%d Version %d at 0x%X.\n",
+		m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr);
+	if (nr_ioapics >= MAX_IO_APICS) {
+		printk("Max # of I/O APICs (%d) exceeded (found %d).\n",
+			MAX_IO_APICS, nr_ioapics);
+		panic("Recompile kernel with bigger MAX_IO_APICS!.\n");
+	}
+	if (!m->mpc_apicaddr) {
+		printk(KERN_ERR "WARNING: bogus zero I/O APIC address"
+			" found in MP table, skipping!\n");
+		return;
+	}
+	mp_ioapics[nr_ioapics] = *m;
+	nr_ioapics++;
+}
+
+static void __init MP_intsrc_info (struct mpc_config_intsrc *m)
+{
+	mp_irqs [mp_irq_entries] = *m;
+	Dprintk("Int: type %d, pol %d, trig %d, bus %d,"
+		" IRQ %02x, APIC ID %x, APIC INT %02x\n",
+			m->mpc_irqtype, m->mpc_irqflag & 3,
+			(m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,
+			m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);
+	if (++mp_irq_entries == MAX_IRQ_SOURCES)
+		panic("Max # of irq sources exceeded!!\n");
+}
+
+static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m)
+{
+	Dprintk("Lint: type %d, pol %d, trig %d, bus %d,"
+		" IRQ %02x, APIC ID %x, APIC LINT %02x\n",
+			m->mpc_irqtype, m->mpc_irqflag & 3,
+			(m->mpc_irqflag >> 2) &3, m->mpc_srcbusid,
+			m->mpc_srcbusirq, m->mpc_destapic, m->mpc_destapiclint);
+	/*
+	 * Well it seems all SMP boards in existence
+	 * use ExtINT/LVT1 == LINT0 and
+	 * NMI/LVT2 == LINT1 - the following check
+	 * will show us if this assumptions is false.
+	 * Until then we do not have to add baggage.
+	 */
+	if ((m->mpc_irqtype == mp_ExtINT) &&
+		(m->mpc_destapiclint != 0))
+			BUG();
+	if ((m->mpc_irqtype == mp_NMI) &&
+		(m->mpc_destapiclint != 1))
+			BUG();
+}
+
+/*
+ * Read/parse the MPC
+ */
+
+static int __init smp_read_mpc(struct mp_config_table *mpc)
+{
+	char str[16];
+	int count=sizeof(*mpc);
+	unsigned char *mpt=((unsigned char *)mpc)+count;
+
+	if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) {
+		panic("SMP mptable: bad signature [%c%c%c%c]!\n",
+			mpc->mpc_signature[0],
+			mpc->mpc_signature[1],
+			mpc->mpc_signature[2],
+			mpc->mpc_signature[3]);
+		return 0;
+	}
+	if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) {
+		panic("SMP mptable: checksum error!\n");
+		return 0;
+	}
+	if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) {
+		printk(KERN_ERR "SMP mptable: bad table version (%d)!!\n",
+			mpc->mpc_spec);
+		return 0;
+	}
+	if (!mpc->mpc_lapic) {
+		printk(KERN_ERR "SMP mptable: null local APIC address!\n");
+		return 0;
+	}
+	memcpy(str,mpc->mpc_oem,8);
+	str[8]=0;
+	printk("OEM ID: %s ",str);
+
+	memcpy(str,mpc->mpc_productid,12);
+	str[12]=0;
+	printk("Product ID: %s ",str);
+
+	printk("APIC at: 0x%X\n",mpc->mpc_lapic);
+
+	/* save the local APIC address, it might be non-default */
+	mp_lapic_addr = mpc->mpc_lapic;
+
+	/*
+	 *	Now process the configuration blocks.
+	 */
+	while (count < mpc->mpc_length) {
+		switch(*mpt) {
+			case MP_PROCESSOR:
+			{
+				struct mpc_config_processor *m=
+					(struct mpc_config_processor *)mpt;
+				MP_processor_info(m);
+				mpt += sizeof(*m);
+				count += sizeof(*m);
+				break;
+			}
+			case MP_BUS:
+			{
+				struct mpc_config_bus *m=
+					(struct mpc_config_bus *)mpt;
+				MP_bus_info(m);
+				mpt += sizeof(*m);
+				count += sizeof(*m);
+				break;
+			}
+			case MP_IOAPIC:
+			{
+				struct mpc_config_ioapic *m=
+					(struct mpc_config_ioapic *)mpt;
+				MP_ioapic_info(m);
+				mpt+=sizeof(*m);
+				count+=sizeof(*m);
+				break;
+			}
+			case MP_INTSRC:
+			{
+				struct mpc_config_intsrc *m=
+					(struct mpc_config_intsrc *)mpt;
+
+				MP_intsrc_info(m);
+				mpt+=sizeof(*m);
+				count+=sizeof(*m);
+				break;
+			}
+			case MP_LINTSRC:
+			{
+				struct mpc_config_lintsrc *m=
+					(struct mpc_config_lintsrc *)mpt;
+				MP_lintsrc_info(m);
+				mpt+=sizeof(*m);
+				count+=sizeof(*m);
+				break;
+			}
+		}
+	}
+	if (!num_processors)
+		printk(KERN_ERR "SMP mptable: no processors registered!\n");
+	return num_processors;
+}
+
+static int __init ELCR_trigger(unsigned int irq)
+{
+	unsigned int port;
+
+	port = 0x4d0 + (irq >> 3);
+	return (inb(port) >> (irq & 7)) & 1;
+}
+
+static void __init construct_default_ioirq_mptable(int mpc_default_type)
+{
+	struct mpc_config_intsrc intsrc;
+	int i;
+	int ELCR_fallback = 0;
+
+	intsrc.mpc_type = MP_INTSRC;
+	intsrc.mpc_irqflag = 0;			/* conforming */
+	intsrc.mpc_srcbus = 0;
+	intsrc.mpc_dstapic = mp_ioapics[0].mpc_apicid;
+
+	intsrc.mpc_irqtype = mp_INT;
+
+	/*
+	 *  If true, we have an ISA/PCI system with no IRQ entries
+	 *  in the MP table. To prevent the PCI interrupts from being set up
+	 *  incorrectly, we try to use the ELCR. The sanity check to see if
+	 *  there is good ELCR data is very simple - IRQ0, 1, 2 and 13 can
+	 *  never be level sensitive, so we simply see if the ELCR agrees.
+	 *  If it does, we assume it's valid.
+	 */
+	if (mpc_default_type == 5) {
+		printk("ISA/PCI bus type with no IRQ information... falling back to ELCR\n");
+
+		if (ELCR_trigger(0) || ELCR_trigger(1) || ELCR_trigger(2) || ELCR_trigger(13))
+			printk("ELCR contains invalid data... not using ELCR\n");
+		else {
+			printk("Using ELCR to identify PCI interrupts\n");
+			ELCR_fallback = 1;
+		}
+	}
+
+	for (i = 0; i < 16; i++) {
+		switch (mpc_default_type) {
+		case 2:
+			if (i == 0 || i == 13)
+				continue;	/* IRQ0 & IRQ13 not connected */
+			/* fall through */
+		default:
+			if (i == 2)
+				continue;	/* IRQ2 is never connected */
+		}
+
+		if (ELCR_fallback) {
+			/*
+			 *  If the ELCR indicates a level-sensitive interrupt, we
+			 *  copy that information over to the MP table in the
+			 *  irqflag field (level sensitive, active high polarity).
+			 */
+			if (ELCR_trigger(i))
+				intsrc.mpc_irqflag = 13;
+			else
+				intsrc.mpc_irqflag = 0;
+		}
+
+		intsrc.mpc_srcbusirq = i;
+		intsrc.mpc_dstirq = i ? i : 2;		/* IRQ0 to INTIN2 */
+		MP_intsrc_info(&intsrc);
+	}
+
+	intsrc.mpc_irqtype = mp_ExtINT;
+	intsrc.mpc_srcbusirq = 0;
+	intsrc.mpc_dstirq = 0;				/* 8259A to INTIN0 */
+	MP_intsrc_info(&intsrc);
+}
+
+static inline void __init construct_default_ISA_mptable(int mpc_default_type)
+{
+	struct mpc_config_processor processor;
+	struct mpc_config_bus bus;
+	struct mpc_config_ioapic ioapic;
+	struct mpc_config_lintsrc lintsrc;
+	int linttypes[2] = { mp_ExtINT, mp_NMI };
+	int i;
+
+	/*
+	 * local APIC has default address
+	 */
+	mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+
+	/*
+	 * 2 CPUs, numbered 0 & 1.
+	 */
+	processor.mpc_type = MP_PROCESSOR;
+	/* Either an integrated APIC or a discrete 82489DX. */
+	processor.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
+	processor.mpc_cpuflag = CPU_ENABLED;
+	processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) |
+				   (boot_cpu_data.x86_model << 4) |
+				   boot_cpu_data.x86_mask;
+	processor.mpc_featureflag = boot_cpu_data.x86_capability[0];
+	processor.mpc_reserved[0] = 0;
+	processor.mpc_reserved[1] = 0;
+	for (i = 0; i < 2; i++) {
+		processor.mpc_apicid = i;
+		MP_processor_info(&processor);
+	}
+
+	bus.mpc_type = MP_BUS;
+	bus.mpc_busid = 0;
+	switch (mpc_default_type) {
+		default:
+			printk("???\nUnknown standard configuration %d\n",
+				mpc_default_type);
+			/* fall through */
+		case 1:
+		case 5:
+			memcpy(bus.mpc_bustype, "ISA   ", 6);
+			break;
+		case 2:
+		case 6:
+		case 3:
+			memcpy(bus.mpc_bustype, "EISA  ", 6);
+			break;
+		case 4:
+		case 7:
+			memcpy(bus.mpc_bustype, "MCA   ", 6);
+	}
+	MP_bus_info(&bus);
+	if (mpc_default_type > 4) {
+		bus.mpc_busid = 1;
+		memcpy(bus.mpc_bustype, "PCI   ", 6);
+		MP_bus_info(&bus);
+	}
+
+	ioapic.mpc_type = MP_IOAPIC;
+	ioapic.mpc_apicid = 2;
+	ioapic.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
+	ioapic.mpc_flags = MPC_APIC_USABLE;
+	ioapic.mpc_apicaddr = 0xFEC00000;
+	MP_ioapic_info(&ioapic);
+
+	/*
+	 * We set up most of the low 16 IO-APIC pins according to MPS rules.
+	 */
+	construct_default_ioirq_mptable(mpc_default_type);
+
+	lintsrc.mpc_type = MP_LINTSRC;
+	lintsrc.mpc_irqflag = 0;		/* conforming */
+	lintsrc.mpc_srcbusid = 0;
+	lintsrc.mpc_srcbusirq = 0;
+	lintsrc.mpc_destapic = MP_APIC_ALL;
+	for (i = 0; i < 2; i++) {
+		lintsrc.mpc_irqtype = linttypes[i];
+		lintsrc.mpc_destapiclint = i;
+		MP_lintsrc_info(&lintsrc);
+	}
+}
+
+static struct intel_mp_floating *mpf_found;
+
+/*
+ * Scan the memory blocks for an SMP configuration block.
+ */
+void __init get_smp_config (void)
+{
+	struct intel_mp_floating *mpf = mpf_found;
+	printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification);
+	if (mpf->mpf_feature2 & (1<<7)) {
+		printk("    IMCR and PIC compatibility mode.\n");
+		pic_mode = 1;
+	} else {
+		printk("    Virtual Wire compatibility mode.\n");
+		pic_mode = 0;
+	}
+
+	/*
+	 * Now see if we need to read further.
+	 */
+	if (mpf->mpf_feature1 != 0) {
+
+		printk("Default MP configuration #%d\n", mpf->mpf_feature1);
+		construct_default_ISA_mptable(mpf->mpf_feature1);
+
+	} else if (mpf->mpf_physptr) {
+		/*
+		 * Read the physical hardware table.  Anything here will
+		 * override the defaults.
+		 */
+		if (!smp_read_mpc(__va(mpf->mpf_physptr))) {
+			smp_found_config = 0;
+			printk(KERN_ERR "BIOS bug, MP table errors detected!...\n");
+			printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n");
+			return;
+		}
+		/*
+		 * If there are no explicit MP IRQ entries, then we are
+		 * broken.  We set up most of the low 16 IO-APIC pins to
+		 * ISA defaults and hope it will work.
+		 */
+		if (!mp_irq_entries) {
+			struct mpc_config_bus bus;
+
+			printk("BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n");
+
+			bus.mpc_type = MP_BUS;
+			bus.mpc_busid = 0;
+			memcpy(bus.mpc_bustype, "ISA   ", 6);
+			MP_bus_info(&bus);
+
+			construct_default_ioirq_mptable(0);
+		}
+
+	} else
+		BUG();
+
+	printk("Processors: %d\n", num_processors);
+	/*
+	 * Only use the first configuration found.
+	 */
+}
+
+static int __init smp_scan_config (unsigned long base, unsigned long length)
+{
+	unsigned int *bp = phys_to_virt(base);
+	struct intel_mp_floating *mpf;
+
+	printk("Scan SMP from %p for %ld bytes.\n", bp,length);
+	if (sizeof(*mpf) != 16)
+		printk("Error: MPF size\n");
+
+	while (length > 0) {
+		mpf = (struct intel_mp_floating *)bp;
+		if ((*bp == SMP_MAGIC_IDENT) &&
+			(mpf->mpf_length == 1) &&
+			!mpf_checksum((unsigned char *)bp, 16) &&
+			((mpf->mpf_specification == 1)
+				|| (mpf->mpf_specification == 4)) ) {
+
+			smp_found_config = 1;
+			printk(KERN_INFO "found SMP MP-table at %016lx\n",
+						virt_to_phys(mpf));
+			reserve_bootmem_generic(virt_to_phys(mpf), PAGE_SIZE); 
+			if (mpf->mpf_physptr)
+				reserve_bootmem_generic(mpf->mpf_physptr, PAGE_SIZE); 
+			mpf_found = mpf;
+			return 1;
+		}
+		bp += 4;
+		length -= 16;
+	}
+	return 0;
+}
+
+void __init find_intel_smp (void)
+{
+	unsigned long address;
+
+	/*
+	 * FIXME: Linux assumes you have 640K of base ram..
+	 * this continues the error...
+	 *
+	 * 1) Scan the bottom 1K for a signature
+	 * 2) Scan the top 1K of base RAM
+	 * 3) Scan the 64K of bios
+	 */
+	if (smp_scan_config(0x0,0x400) ||
+		smp_scan_config(639*0x400,0x400) ||
+			smp_scan_config(0xF0000,0x10000))
+		return;
+		printk("ok\n");
+		
+	/*
+	 * If it is an SMP machine we should know now, unless the
+	 * configuration is in an EISA/MCA bus machine with an
+	 * extended bios data area.
+	 *
+	 * there is a real-mode segmented pointer pointing to the
+	 * 4K EBDA area at 0x40E, calculate and scan it here.
+	 *
+	 * NOTE! There are Linux loaders that will corrupt the EBDA
+	 * area, and as such this kind of SMP config may be less
+	 * trustworthy, simply because the SMP table may have been
+	 * stomped on during early boot. These loaders are buggy and
+	 * should be fixed.
+	 *
+	 * MP1.4 SPEC states to only scan first 1K of 4K EBDA.
+	 */
+
+	address = *(unsigned short *)phys_to_virt(0x40E);
+	address <<= 4;
+	smp_scan_config(address, 0x400);
+	if (smp_found_config)
+		printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.kernel.org if you experience SMP problems!\n");
+}
+
+/*
+ * - Intel MP Configuration Table
+ */
+void __init find_smp_config (void)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+	find_intel_smp();
+#endif
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/msr.c linux-2.4.20/arch/x86_64/kernel/msr.c
--- linux-2.4.19/arch/x86_64/kernel/msr.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/msr.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,274 @@
+#ident "$Id: msr.c,v 1.7 2002/02/14 10:20:47 ak Exp $"
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2000 H. Peter Anvin - All Rights Reserved
+ *
+ *   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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * msr.c
+ *
+ * x86 MSR access device
+ *
+ * This device is accessed by lseek() to the appropriate register number
+ * and then read/write in chunks of 8 bytes.  A larger size means multiple
+ * reads or writes of the same register.
+ *
+ * This driver uses /dev/cpu/%d/msr where %d is the minor number, and on
+ * an SMP box will direct the access to CPU %d.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/smp.h>
+#include <linux/major.h>
+
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+/* Note: "err" is handled in a funny way below.  Otherwise one version
+   of gcc or another breaks. */
+
+static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
+{
+  int err;
+
+  asm volatile(
+	       "1:	wrmsr\n"
+	       "2:\n"
+	       ".section .fixup,\"ax\"\n"
+	       "3:	movl %4,%0\n"
+	       "	jmp 2b\n"
+	       ".previous\n"
+	       ".section __ex_table,\"a\"\n"
+	       "	.align 4\n"
+	       "	.quad 1b,3b\n"
+	       ".previous"
+	       : "=&bDS" (err)
+	       : "a" (eax), "d" (edx), "c" (reg), "i" (-EIO), "0" (0));
+
+  return err;
+}
+
+static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx)
+{
+  int err;
+
+  asm volatile(
+	       "1:	rdmsr\n"
+	       "2:\n"
+	       ".section .fixup,\"ax\"\n"
+	       "3:	movl %4,%0\n"
+	       "	jmp 2b\n"
+	       ".previous\n"
+	       ".section __ex_table,\"a\"\n"
+	       "	.align 4\n"
+	       "	.quad 1b,3b\n"
+	       ".previous"
+	       : "=&bDS" (err), "=a" (*eax), "=d" (*edx)
+	       : "c" (reg), "i" (-EIO), "0" (0));
+
+  return err;
+}
+
+#ifdef CONFIG_SMP
+
+struct msr_command {
+  int cpu;
+  int err;
+  u32 reg;
+  u32 data[2];
+};
+
+static void msr_smp_wrmsr(void *cmd_block)
+{
+  struct msr_command *cmd = (struct msr_command *) cmd_block;
+  
+  if ( cmd->cpu == smp_processor_id() )
+    cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]);
+}
+
+static void msr_smp_rdmsr(void *cmd_block)
+{
+  struct msr_command *cmd = (struct msr_command *) cmd_block;
+  
+  if ( cmd->cpu == smp_processor_id() )
+    cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]);
+}
+
+static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
+{
+  struct msr_command cmd;
+
+  if ( cpu == smp_processor_id() ) {
+    return wrmsr_eio(reg, eax, edx);
+  } else {
+    cmd.cpu = cpu;
+    cmd.reg = reg;
+    cmd.data[0] = eax;
+    cmd.data[1] = edx;
+    
+    smp_call_function(msr_smp_wrmsr, &cmd, 1, 1);
+    return cmd.err;
+  }
+}
+
+static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
+{
+  struct msr_command cmd;
+
+  if ( cpu == smp_processor_id() ) {
+    return rdmsr_eio(reg, eax, edx);
+  } else {
+    cmd.cpu = cpu;
+    cmd.reg = reg;
+
+    smp_call_function(msr_smp_rdmsr, &cmd, 1, 1);
+    
+    *eax = cmd.data[0];
+    *edx = cmd.data[1];
+
+    return cmd.err;
+  }
+}
+
+#else /* ! CONFIG_SMP */
+
+static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
+{
+  return wrmsr_eio(reg, eax, edx);
+}
+
+static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
+{
+  return rdmsr_eio(reg, eax, edx);
+}
+
+#endif /* ! CONFIG_SMP */
+
+static loff_t msr_seek(struct file *file, loff_t offset, int orig)
+{
+  switch (orig) {
+  case 0:
+    file->f_pos = offset;
+    return file->f_pos;
+  case 1:
+    file->f_pos += offset;
+    return file->f_pos;
+  default:
+    return -EINVAL;	/* SEEK_END not supported */
+  }
+}
+
+static ssize_t msr_read(struct file * file, char * buf,
+			size_t count, loff_t *ppos)
+{
+  u32 *tmp = (u32 *)buf;
+  u32 data[2];
+  size_t rv;
+  u32 reg = *ppos;
+  int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+  int err;
+
+  if ( count % 8 )
+    return -EINVAL; /* Invalid chunk size */
+  
+  for ( rv = 0 ; count ; count -= 8 ) {
+    err = do_rdmsr(cpu, reg, &data[0], &data[1]);
+    if ( err )
+      return err;
+    if ( copy_to_user(tmp,&data,8) )
+      return -EFAULT;
+    tmp += 2;
+  }
+
+  return ((char *)tmp) - buf;
+}
+
+static ssize_t msr_write(struct file * file, const char * buf,
+			 size_t count, loff_t *ppos)
+{
+  const u32 *tmp = (const u32 *)buf;
+  u32 data[2];
+  size_t rv;
+  u32 reg = *ppos;
+  int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+  int err;
+
+  if ( count % 8 )
+    return -EINVAL; /* Invalid chunk size */
+  
+  for ( rv = 0 ; count ; count -= 8 ) {
+    if ( copy_from_user(&data,tmp,8) )
+      return -EFAULT;
+    err = do_wrmsr(cpu, reg, data[0], data[1]);
+    if ( err )
+      return err;
+    tmp += 2;
+  }
+
+  return ((char *)tmp) - buf;
+}
+
+static int msr_open(struct inode *inode, struct file *file)
+{
+  int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+  struct cpuinfo_x86 *c = &(cpu_data)[cpu];
+  
+  if ( !(cpu_online_map & (1UL << cpu)) )
+    return -ENXIO;		/* No such CPU */
+  if ( !test_bit(X86_FEATURE_MSR, &c->x86_capability) )
+    return -EIO;		/* MSR not supported */
+  
+  return 0;
+}
+
+/*
+ * File operations we support
+ */
+static struct file_operations msr_fops = {
+  owner:	THIS_MODULE,
+  llseek:	msr_seek,
+  read:		msr_read,
+  write:	msr_write,
+  open:		msr_open,
+};
+
+int __init msr_init(void)
+{
+  if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) {
+    printk(KERN_ERR "msr: unable to get major %d for msr\n",
+	   MSR_MAJOR);
+    return -EBUSY;
+  }
+  
+  return 0;
+}
+
+void __exit msr_exit(void)
+{
+  unregister_chrdev(MSR_MAJOR, "cpu/msr");
+}
+
+module_init(msr_init);
+module_exit(msr_exit)
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>");
+MODULE_DESCRIPTION("x86 generic MSR driver");
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/mtrr.c linux-2.4.20/arch/x86_64/kernel/mtrr.c
--- linux-2.4.19/arch/x86_64/kernel/mtrr.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/mtrr.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,1314 @@
+/*  x86-64 MTRR (Memory Type Range Register) driver.
+	Based largely upon arch/i386/kernel/mtrr.c
+
+	Copyright (C) 1997-2000  Richard Gooch
+	Copyright (C) 2002 Dave Jones.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Library General Public
+	License as published by the Free Software Foundation; either
+	version 2 of the License, or (at your option) any later version.
+
+	This library 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
+	Library General Public License for more details.
+
+	You should have received a copy of the GNU Library General Public
+	License along with this library; if not, write to the Free
+	Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+	(For earlier history, see arch/i386/kernel/mtrr.c)
+	v2.00	September 2001	Dave Jones <davej@suse.de>
+	  Initial rewrite for x86-64.
+	  Removal of non-Intel style MTRR code.
+	v2.01  June 2002  Dave Jones <davej@suse.de>
+	  Removal of redundant abstraction layer.
+	  64-bit fixes.
+	v2.02  July 2002  Dave Jones <davej@suse.de>
+	  Fix gentry inconsistencies between kernel/userspace.
+	  More casts to clean up warnings.
+*/
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/timer.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/ctype.h>
+#include <linux/proc_fs.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#define MTRR_NEED_STRINGS
+#include <asm/mtrr.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/agp_backend.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/atomic.h>
+#include <asm/msr.h>
+
+#include <asm/hardirq.h>
+#include <linux/irq.h>
+
+#define MTRR_VERSION "2.02 (20020716)"
+
+#undef Dprintk
+
+#define Dprintk(...) 
+
+#define TRUE  1
+#define FALSE 0
+
+#define MSR_MTRRphysBase(reg) (0x200 + 2 * (reg))
+#define MSR_MTRRphysMask(reg) (0x200 + 2 * (reg) + 1)
+
+#define NUM_FIXED_RANGES 88
+
+#define MTRR_CHANGE_MASK_FIXED 0x01
+#define MTRR_CHANGE_MASK_VARIABLE 0x02
+#define MTRR_CHANGE_MASK_DEFTYPE 0x04
+
+typedef u8 mtrr_type;
+
+#define LINE_SIZE 80
+
+#ifdef CONFIG_SMP
+#define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type)
+#else
+#define set_mtrr(reg,base,size,type) set_mtrr_up (reg, base, size, type, TRUE)
+#endif
+
+#if defined(CONFIG_PROC_FS) || defined(CONFIG_DEVFS_FS)
+#define USERSPACE_INTERFACE
+#endif
+
+#ifdef USERSPACE_INTERFACE
+static char *ascii_buffer;
+static unsigned int ascii_buf_bytes;
+static void compute_ascii (void);
+#else
+#define compute_ascii() while (0)
+#endif
+
+static unsigned int *usage_table;
+static DECLARE_MUTEX (mtrr_lock);
+
+struct set_mtrr_context {
+	u32 deftype_lo;
+	u32 deftype_hi;
+	unsigned long flags;
+	u64 cr4val;
+};
+
+
+/*  Put the processor into a state where MTRRs can be safely set  */
+static void set_mtrr_prepare (struct set_mtrr_context *ctxt)
+{
+	u64 cr0;
+
+	/* Disable interrupts locally */
+	__save_flags(ctxt->flags);
+	__cli();
+
+	/* Save value of CR4 and clear Page Global Enable (bit 7) */
+	if (test_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability)) {
+		ctxt->cr4val = read_cr4();
+		write_cr4(ctxt->cr4val & ~(1UL << 7));
+	}
+
+	/* Disable and flush caches. Note that wbinvd flushes the TLBs as
+	   a side-effect */
+	cr0 = read_cr0() | 0x40000000;
+	wbinvd();
+	write_cr0(cr0);
+	wbinvd();
+
+	/* Disable MTRRs, and set the default type to uncached */
+	rdmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi);
+	wrmsr(MSR_MTRRdefType, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
+}
+
+
+/* Restore the processor after a set_mtrr_prepare */
+static void set_mtrr_done (struct set_mtrr_context *ctxt)
+{
+	/* Flush caches and TLBs */
+	wbinvd();
+
+	/* Restore MTRRdefType */
+	wrmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi);
+
+	/* Enable caches */
+	write_cr0(read_cr0() & 0xbfffffff);
+
+	/* Restore value of CR4 */
+	if (test_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability))
+		write_cr4 (ctxt->cr4val);
+
+	/* Re-enable interrupts locally (if enabled previously) */
+	__restore_flags(ctxt->flags);
+}
+
+
+/*  This function returns the number of variable MTRRs  */
+static unsigned int get_num_var_ranges (void)
+{
+	u32 config, dummy;
+
+	rdmsr (MSR_MTRRcap, config, dummy);
+	return (config & 0xff);
+}
+
+
+/*  Returns non-zero if we have the write-combining memory type  */
+static int have_wrcomb (void)
+{
+	u32 config, dummy;
+
+	rdmsr (MSR_MTRRcap, config, dummy);
+	return (config & (1 << 10));
+}
+
+
+static u64 size_or_mask, size_and_mask;
+
+static void get_mtrr (unsigned int reg, u64 *base, u32 *size, mtrr_type * type)
+{
+	u32 mask_lo, mask_hi, base_lo, base_hi;
+	u64 newsize;
+
+	rdmsr (MSR_MTRRphysMask(reg), mask_lo, mask_hi);
+	if ((mask_lo & 0x800) == 0) {
+		/*  Invalid (i.e. free) range  */
+		*base = 0;
+		*size = 0;
+		*type = 0;
+		return;
+	}
+
+	rdmsr (MSR_MTRRphysBase(reg), base_lo, base_hi);
+
+	/* Work out the shifted address mask. */
+	newsize = (u64) mask_hi << 32 | (mask_lo & ~0x800);
+	newsize = ~newsize+1;
+	*size = (u32) newsize >> PAGE_SHIFT;
+	*base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;
+	*type = base_lo & 0xff;
+}
+
+
+
+/*
+ * Set variable MTRR register on the local CPU.
+ *  <reg> The register to set.
+ *  <base> The base address of the region.
+ *  <size> The size of the region. If this is 0 the region is disabled.
+ *  <type> The type of the region.
+ *  <do_safe> If TRUE, do the change safely. If FALSE, safety measures should
+ *  be done externally.
+ */
+static void set_mtrr_up (unsigned int reg, u64 base,
+		   u32 size, mtrr_type type, int do_safe)
+{
+	struct set_mtrr_context ctxt;
+	u64 base64;
+	u64 size64;
+
+	if (do_safe)
+		set_mtrr_prepare (&ctxt);
+
+	if (size == 0) {
+		/* The invalid bit is kept in the mask, so we simply clear the
+		   relevant mask register to disable a range. */
+		wrmsr (MSR_MTRRphysMask(reg), 0, 0);
+	} else {
+		base64 = (base << PAGE_SHIFT) & size_and_mask;
+		wrmsr (MSR_MTRRphysBase(reg), base64 | type, base64 >> 32);
+
+		size64 = ~((size << PAGE_SHIFT) - 1);
+		size64 = size64 & size_and_mask;
+		wrmsr (MSR_MTRRphysMask(reg), (u32) (size64 | 0x800), (u32) (size64 >> 32));
+	}
+	if (do_safe)
+		set_mtrr_done (&ctxt);
+}
+
+
+#ifdef CONFIG_SMP
+
+struct mtrr_var_range {
+	u32 base_lo;
+	u32 base_hi;
+	u32 mask_lo;
+	u32 mask_hi;
+};
+
+/*  Get the MSR pair relating to a var range  */
+static void __init get_mtrr_var_range (unsigned int index,
+		struct mtrr_var_range *vr)
+{
+	rdmsr (MSR_MTRRphysBase(index), vr->base_lo, vr->base_hi);
+	rdmsr (MSR_MTRRphysMask(index), vr->mask_lo, vr->mask_hi);
+}
+
+
+/*  Set the MSR pair relating to a var range. Returns TRUE if
+    changes are made  */
+static int __init set_mtrr_var_range_testing (unsigned int index,
+		struct mtrr_var_range *vr)
+{
+	u32 lo, hi;
+	int changed = FALSE;
+
+	rdmsr (MSR_MTRRphysBase(index), lo, hi);
+	if ((vr->base_lo & 0xfffff0ff) != (lo & 0xfffff0ff) ||
+		(vr->base_hi & 0x000fffff) != (hi & 0x000fffff)) {
+		wrmsr (MSR_MTRRphysBase(index), vr->base_lo, vr->base_hi);
+		changed = TRUE;
+	}
+
+	rdmsr (MSR_MTRRphysMask(index), lo, hi);
+	if ((vr->mask_lo & 0xfffff800) != (lo & 0xfffff800) ||
+		(vr->mask_hi & 0x000fffff) != (hi & 0x000fffff)) {
+		wrmsr (MSR_MTRRphysMask(index), vr->mask_lo, vr->mask_hi);
+		changed = TRUE;
+	}
+	return changed;
+}
+
+
+static void __init get_fixed_ranges (mtrr_type * frs)
+{
+	u32 *p = (u32 *) frs;
+	int i;
+
+	rdmsr (MSR_MTRRfix64K_00000, p[0], p[1]);
+
+	for (i = 0; i < 2; i++)
+		rdmsr (MSR_MTRRfix16K_80000 + i, p[2 + i * 2], p[3 + i * 2]);
+	for (i = 0; i < 8; i++)
+		rdmsr (MSR_MTRRfix4K_C0000 + i, p[6 + i * 2], p[7 + i * 2]);
+}
+
+
+static int __init set_fixed_ranges_testing (mtrr_type * frs)
+{
+	u32 *p = (u32 *) frs;
+	int changed = FALSE;
+	int i;
+	u32 lo, hi;
+
+	Dprintk (KERN_INFO "mtrr: rdmsr 64K_00000\n");
+	rdmsr (MSR_MTRRfix64K_00000, lo, hi);
+	if (p[0] != lo || p[1] != hi) {
+		Dprintk (KERN_INFO "mtrr: Writing %x:%x to 64K MSR. lohi were %x:%x\n", p[0], p[1], lo, hi);
+		wrmsr (MSR_MTRRfix64K_00000, p[0], p[1]);
+		changed = TRUE;
+	}
+
+	Dprintk (KERN_INFO "mtrr: rdmsr 16K_80000\n");
+	for (i = 0; i < 2; i++) {
+		rdmsr (MSR_MTRRfix16K_80000 + i, lo, hi);
+		if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) {
+			Dprintk (KERN_INFO "mtrr: Writing %x:%x to 16K MSR%d. lohi were %x:%x\n", p[2 + i * 2], p[3 + i * 2], i, lo, hi );
+			wrmsr (MSR_MTRRfix16K_80000 + i, p[2 + i * 2], p[3 + i * 2]);
+			changed = TRUE;
+		}
+	}
+
+	Dprintk (KERN_INFO "mtrr: rdmsr 4K_C0000\n");
+	for (i = 0; i < 8; i++) {
+		rdmsr (MSR_MTRRfix4K_C0000 + i, lo, hi);
+		Dprintk (KERN_INFO "mtrr: MTRRfix4K_C0000+%d = %x:%x\n", i, lo, hi);
+		if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) {
+			Dprintk (KERN_INFO "mtrr: Writing %x:%x to 4K MSR%d. lohi were %x:%x\n", p[6 + i * 2], p[7 + i * 2], i, lo, hi);
+			wrmsr (MSR_MTRRfix4K_C0000 + i, p[6 + i * 2], p[7 + i * 2]);
+			changed = TRUE;
+		}
+	}
+	return changed;
+}
+
+
+struct mtrr_state {
+	unsigned int num_var_ranges;
+	struct mtrr_var_range *var_ranges;
+	mtrr_type fixed_ranges[NUM_FIXED_RANGES];
+	mtrr_type def_type;
+	unsigned char enabled;
+};
+
+
+/*  Grab all of the MTRR state for this CPU into *state  */
+static void __init get_mtrr_state (struct mtrr_state *state)
+{
+	unsigned int nvrs, i;
+	struct mtrr_var_range *vrs;
+	u32 lo, dummy;
+
+	nvrs = state->num_var_ranges = get_num_var_ranges();
+	vrs = state->var_ranges
+	    = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL);
+	if (vrs == NULL)
+		nvrs = state->num_var_ranges = 0;
+
+	for (i = 0; i < nvrs; i++)
+		get_mtrr_var_range (i, &vrs[i]);
+	get_fixed_ranges (state->fixed_ranges);
+
+	rdmsr (MSR_MTRRdefType, lo, dummy);
+	state->def_type = (lo & 0xff);
+	state->enabled = (lo & 0xc00) >> 10;
+}
+
+
+/*  Free resources associated with a struct mtrr_state  */
+static void __init finalize_mtrr_state (struct mtrr_state *state)
+{
+	if (state->var_ranges)
+		kfree (state->var_ranges);
+}
+
+
+/*
+ * Set the MTRR state for this CPU.
+ *  <state> The MTRR state information to read.
+ *  <ctxt> Some relevant CPU context.
+ *  [NOTE] The CPU must already be in a safe state for MTRR changes.
+ *  [RETURNS] 0 if no changes made, else a mask indication what was changed.
+ */
+static u64 __init set_mtrr_state (struct mtrr_state *state,
+		struct set_mtrr_context *ctxt)
+{
+	unsigned int i;
+	u64 change_mask = 0;
+
+	for (i = 0; i < state->num_var_ranges; i++)
+		if (set_mtrr_var_range_testing (i, &state->var_ranges[i]))
+			change_mask |= MTRR_CHANGE_MASK_VARIABLE;
+
+	if (set_fixed_ranges_testing (state->fixed_ranges))
+		change_mask |= MTRR_CHANGE_MASK_FIXED;
+	/* Set_mtrr_restore restores the old value of MTRRdefType,
+	   so to set it we fiddle with the saved value  */
+	if ((ctxt->deftype_lo & 0xff) != state->def_type
+	    || ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled) {
+		ctxt->deftype_lo |= (state->def_type | state->enabled << 10);
+		change_mask |= MTRR_CHANGE_MASK_DEFTYPE;
+	}
+
+	return change_mask;
+}
+
+
+static atomic_t undone_count;
+static volatile int wait_barrier_execute = FALSE;
+static volatile int wait_barrier_cache_enable = FALSE;
+
+struct set_mtrr_data {
+	u64 smp_base;
+	u32 smp_size;
+	unsigned int smp_reg;
+	mtrr_type smp_type;
+};
+
+/*
+ * Synchronisation handler. Executed by "other" CPUs.
+ */
+static void ipi_handler (void *info)
+{
+	struct set_mtrr_data *data = info;
+	struct set_mtrr_context ctxt;
+
+	set_mtrr_prepare (&ctxt);
+	/* Notify master that I've flushed and disabled my cache  */
+	atomic_dec (&undone_count);
+	while (wait_barrier_execute)
+		barrier ();
+
+	/* The master has cleared me to execute  */
+	set_mtrr_up (data->smp_reg, data->smp_base, data->smp_size,
+			data->smp_type, FALSE);
+
+	/* Notify master CPU that I've executed the function  */
+	atomic_dec (&undone_count);
+
+	/* Wait for master to clear me to enable cache and return  */
+	while (wait_barrier_cache_enable)
+		barrier ();
+	set_mtrr_done (&ctxt);
+}
+
+
+static void set_mtrr_smp (unsigned int reg, u64 base, u32 size, mtrr_type type)
+{
+	struct set_mtrr_data data;
+	struct set_mtrr_context ctxt;
+
+	data.smp_reg = reg;
+	data.smp_base = base;
+	data.smp_size = size;
+	data.smp_type = type;
+	wait_barrier_execute = TRUE;
+	wait_barrier_cache_enable = TRUE;
+	atomic_set (&undone_count, smp_num_cpus - 1);
+
+	/*  Start the ball rolling on other CPUs  */
+	if (smp_call_function (ipi_handler, &data, 1, 0) != 0)
+		panic ("mtrr: timed out waiting for other CPUs\n");
+
+	/* Flush and disable the local CPU's cache */
+	set_mtrr_prepare (&ctxt);
+
+	/*  Wait for all other CPUs to flush and disable their caches  */
+	while (atomic_read (&undone_count) > 0)
+		barrier ();
+
+	/* Set up for completion wait and then release other CPUs to change MTRRs */
+	atomic_set (&undone_count, smp_num_cpus - 1);
+	wait_barrier_execute = FALSE;
+	set_mtrr_up (reg, base, size, type, FALSE);
+
+	/*  Now wait for other CPUs to complete the function  */
+	while (atomic_read (&undone_count) > 0)
+		barrier ();
+
+	/*  Now all CPUs should have finished the function. Release the barrier to
+	   allow them to re-enable their caches and return from their interrupt,
+	   then enable the local cache and return  */
+	wait_barrier_cache_enable = FALSE;
+	set_mtrr_done (&ctxt);
+}
+
+
+/*  Some BIOS's are fucked and don't set all MTRRs the same!  */
+static void __init mtrr_state_warn (u32 mask)
+{
+	if (!mask)
+		return;
+	if (mask & MTRR_CHANGE_MASK_FIXED)
+		printk (KERN_INFO "mtrr: your CPUs had inconsistent fixed MTRR settings\n");
+	if (mask & MTRR_CHANGE_MASK_VARIABLE)
+		printk (KERN_INFO "mtrr: your CPUs had inconsistent variable MTRR settings\n");
+	if (mask & MTRR_CHANGE_MASK_DEFTYPE)
+		printk (KERN_INFO "mtrr: your CPUs had inconsistent MTRRdefType settings\n");
+	printk (KERN_INFO "mtrr: probably your BIOS does not setup all CPUs\n");
+}
+
+#endif	/*  CONFIG_SMP  */
+
+
+static inline char * attrib_to_str (int x)
+{
+	return (x <= 6) ? mtrr_strings[x] : "?";
+}
+
+
+static void __init init_table (void)
+{
+	int i, max;
+
+	max = get_num_var_ranges ();
+	if ((usage_table = kmalloc (max * sizeof *usage_table, GFP_KERNEL))==NULL) {
+		printk ("mtrr: could not allocate\n");
+		return;
+	}
+
+	for (i = 0; i < max; i++)
+		usage_table[i] = 1;
+
+#ifdef USERSPACE_INTERFACE
+	if ((ascii_buffer = kmalloc (max * LINE_SIZE, GFP_KERNEL)) == NULL) {
+		printk ("mtrr: could not allocate\n");
+		return;
+	}
+	ascii_buf_bytes = 0;
+	compute_ascii ();
+#endif
+}
+
+
+/*
+ * Get a free MTRR.
+ * returns the index of the region on success, else -1 on error.
+*/
+static int get_free_region(void)
+{
+	int i, max;
+	mtrr_type ltype;
+	u64 lbase;
+	u32 lsize;
+
+	max = get_num_var_ranges ();
+	for (i = 0; i < max; ++i) {
+		get_mtrr (i, &lbase, &lsize, &ltype);
+		if (lsize == 0)
+			return i;
+	}
+	return -ENOSPC;
+}
+
+
+/**
+ *	mtrr_add_page - Add a memory type region
+ *	@base: Physical base address of region in pages (4 KB)
+ *	@size: Physical size of region in pages (4 KB)
+ *	@type: Type of MTRR desired
+ *	@increment: If this is true do usage counting on the region
+ *	Returns The MTRR register on success, else a negative number
+ *	indicating the error code.
+ *
+ *	Memory type region registers control the caching on newer
+ *	processors. This function allows drivers to request an MTRR is added.
+ *	The caller should expect to need to provide a power of two size on
+ *	an equivalent power of two boundary.
+ *
+ *	If the region cannot be added either because all regions are in use
+ *	or the CPU cannot support it a negative value is returned. On success
+ *	the register number for this entry is returned, but should be treated
+ *	as a cookie only.
+ *
+ *	On a multiprocessor machine the changes are made to all processors.
+ *
+ *	The available types are
+ *
+ *	%MTRR_TYPE_UNCACHABLE	-	No caching
+ *	%MTRR_TYPE_WRBACK	-	Write data back in bursts whenever
+ *	%MTRR_TYPE_WRCOMB	-	Write data back soon but allow bursts
+ *	%MTRR_TYPE_WRTHROUGH	-	Cache reads but not writes
+ *
+ *	BUGS: Needs a quiet flag for the cases where drivers do not mind
+ *	failures and do not wish system log messages to be sent.
+ */
+
+int mtrr_add_page (u64 base, u32 size, unsigned int type, char increment)
+{
+	int i, max;
+	mtrr_type ltype;
+	u64 lbase, last;
+	u32 lsize;
+
+	if (base + size < 0x100) {
+		printk (KERN_WARNING
+			"mtrr: cannot set region below 1 MiB (0x%Lx000,0x%x000)\n",
+			base, size);
+		return -EINVAL;
+	}
+
+#if 0 && defined(__x86_64__) && defined(CONFIG_AGP) 
+	{
+	agp_kern_info info; 
+	if (type != MTRR_TYPE_UNCACHABLE && agp_copy_info(&info) >= 0 && 
+	    base<<PAGE_SHIFT >= info.aper_base && 
+            (base<<PAGE_SHIFT)+(size<<PAGE_SHIFT) >= 
+			info.aper_base+info.aper_size*1024*1024)
+		printk(KERN_INFO "%s[%d] setting conflicting mtrr into agp aperture\n",current->comm,current->pid); 
+	}
+#endif
+
+	/*  Check upper bits of base and last are equal and lower bits are 0
+	   for base and 1 for last  */
+	last = base + size - 1;
+	for (lbase = base; !(lbase & 1) && (last & 1);
+	     lbase = lbase >> 1, last = last >> 1) ;
+
+	if (lbase != last) {
+		printk (KERN_WARNING
+			"mtrr: base(0x%Lx000) is not aligned on a size(0x%x000) boundary\n",
+			base, size);
+		return -EINVAL;
+	}
+
+	if (type >= MTRR_NUM_TYPES) {
+		printk ("mtrr: type: %u illegal\n", type);
+		return -EINVAL;
+	}
+
+	/*  If the type is WC, check that this processor supports it  */
+	if ((type == MTRR_TYPE_WRCOMB) && !have_wrcomb()) {
+		printk (KERN_WARNING
+			"mtrr: your processor doesn't support write-combining\n");
+		return -ENOSYS;
+	}
+
+	if (base & (size_or_mask>>PAGE_SHIFT)) {
+		printk (KERN_WARNING "mtrr: base(%Lx) exceeds the MTRR width(%Lx)\n",
+				base, (size_or_mask>>PAGE_SHIFT));
+		return -EINVAL;
+	}
+
+	if (size & (size_or_mask>>PAGE_SHIFT)) {
+		printk (KERN_WARNING "mtrr: size exceeds the MTRR width\n");
+		return -EINVAL;
+	}
+
+	increment = increment ? 1 : 0;
+	max = get_num_var_ranges ();
+	/*  Search for existing MTRR  */
+	down (&mtrr_lock);
+	for (i = 0; i < max; ++i) {
+		get_mtrr (i, &lbase, &lsize, &ltype);
+		if (base >= lbase + lsize)
+			continue;
+		if ((base < lbase) && (base + size <= lbase))
+			continue;
+
+		/*  At this point we know there is some kind of overlap/enclosure  */
+		if ((base < lbase) || (base + size > lbase + lsize)) {
+			up (&mtrr_lock);
+			printk (KERN_WARNING
+				"mtrr: 0x%Lx000,0x%x000 overlaps existing"
+				" 0x%Lx000,0x%x000\n", base, size, lbase, lsize);
+			return -EINVAL;
+		}
+		/*  New region is enclosed by an existing region  */
+		if (ltype != type) {
+			if (type == MTRR_TYPE_UNCACHABLE)
+				continue;
+			up (&mtrr_lock);
+			printk
+			    ("mtrr: type mismatch for %Lx000,%x000 old: %s new: %s\n",
+			     base, size,
+				 attrib_to_str (ltype),
+			     attrib_to_str (type));
+			return -EINVAL;
+		}
+		if (increment)
+			++usage_table[i];
+		compute_ascii ();
+		up (&mtrr_lock);
+		return i;
+	}
+	/*  Search for an empty MTRR  */
+	i = get_free_region();
+	if (i < 0) {
+		up (&mtrr_lock);
+		printk ("mtrr: no more MTRRs available\n");
+		return i;
+	}
+	set_mtrr (i, base, size, type);
+	usage_table[i] = 1;
+	compute_ascii ();
+	up (&mtrr_lock);
+	return i;
+}
+
+
+/**
+ *	mtrr_add - Add a memory type region
+ *	@base: Physical base address of region
+ *	@size: Physical size of region
+ *	@type: Type of MTRR desired
+ *	@increment: If this is true do usage counting on the region
+ *	Return the MTRR register on success, else a negative numbe
+ *	indicating the error code.
+ *
+ *	Memory type region registers control the caching on newer processors.
+ *	This function allows drivers to request an MTRR is added.
+ *	The caller should expect to need to provide a power of two size on
+ *	an equivalent power of two boundary.
+ *
+ *	If the region cannot be added either because all regions are in use
+ *	or the CPU cannot support it a negative value is returned. On success
+ *	the register number for this entry is returned, but should be treated
+ *	as a cookie only.
+ *
+ *	On a multiprocessor machine the changes are made to all processors.
+ *	This is required on x86 by the Intel processors.
+ *
+ *	The available types are
+ *
+ *	%MTRR_TYPE_UNCACHABLE	-	No caching
+ *	%MTRR_TYPE_WRBACK	-	Write data back in bursts whenever
+ *	%MTRR_TYPE_WRCOMB	-	Write data back soon but allow bursts
+ *	%MTRR_TYPE_WRTHROUGH	-	Cache reads but not writes
+ *
+ *	BUGS: Needs a quiet flag for the cases where drivers do not mind
+ *	failures and do not wish system log messages to be sent.
+ */
+
+int mtrr_add (u64 base, u32 size, unsigned int type, char increment)
+{
+	if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
+		printk ("mtrr: size and base must be multiples of 4 kiB\n");
+		printk ("mtrr: size: 0x%x  base: 0x%Lx\n", size, base);
+		return -EINVAL;
+	}
+	return mtrr_add_page (base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
+			      increment);
+}
+
+
+/**
+ *	mtrr_del_page - delete a memory type region
+ *	@reg: Register returned by mtrr_add
+ *	@base: Physical base address
+ *	@size: Size of region
+ *
+ *	If register is supplied then base and size are ignored. This is
+ *	how drivers should call it.
+ *
+ *	Releases an MTRR region. If the usage count drops to zero the 
+ *	register is freed and the region returns to default state.
+ *	On success the register is returned, on failure a negative error
+ *	code.
+ */
+
+int mtrr_del_page (int reg, u64 base, u32 size)
+{
+	int i, max;
+	mtrr_type ltype;
+	u64 lbase;
+	u32 lsize;
+
+	max = get_num_var_ranges ();
+	down (&mtrr_lock);
+	if (reg < 0) {
+		/*  Search for existing MTRR  */
+		for (i = 0; i < max; ++i) {
+			get_mtrr (i, &lbase, &lsize, &ltype);
+			if (lbase == base && lsize == size) {
+				reg = i;
+				break;
+			}
+		}
+		if (reg < 0) {
+			up (&mtrr_lock);
+			printk ("mtrr: no MTRR for %Lx000,%x000 found\n", base, size);
+			return -EINVAL;
+		}
+	}
+
+	if (reg >= max) {
+		up (&mtrr_lock);
+		printk ("mtrr: register: %d too big\n", reg);
+		return -EINVAL;
+	}
+	get_mtrr (reg, &lbase, &lsize, &ltype);
+
+	if (lsize < 1) {
+		up (&mtrr_lock);
+		printk ("mtrr: MTRR %d not used\n", reg);
+		return -EINVAL;
+	}
+
+	if (usage_table[reg] < 1) {
+		up (&mtrr_lock);
+		printk ("mtrr: reg: %d has count=0\n", reg);
+		return -EINVAL;
+	}
+
+	if (--usage_table[reg] < 1)
+		set_mtrr (reg, 0, 0, 0);
+	compute_ascii ();
+	up (&mtrr_lock);
+	return reg;
+}
+
+
+/**
+ *	mtrr_del - delete a memory type region
+ *	@reg: Register returned by mtrr_add
+ *	@base: Physical base address
+ *	@size: Size of region
+ *
+ *	If register is supplied then base and size are ignored. This is
+ *	how drivers should call it.
+ *
+ *	Releases an MTRR region. If the usage count drops to zero the 
+ *	register is freed and the region returns to default state.
+ *	On success the register is returned, on failure a negative error
+ *	code.
+ */
+
+int mtrr_del (int reg, u64 base, u32 size)
+{
+	if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
+		printk ("mtrr: size and base must be multiples of 4 kiB\n");
+		printk ("mtrr: size: 0x%x  base: 0x%Lx\n", size, base);
+		return -EINVAL;
+	}
+	return mtrr_del_page (reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
+}
+
+
+#ifdef USERSPACE_INTERFACE
+
+static int mtrr_file_add (u64 base, u32 size, unsigned int type,
+		struct file *file, int page)
+{
+	int reg, max;
+	unsigned int *fcount = file->private_data;
+
+	max = get_num_var_ranges ();
+	if (fcount == NULL) {
+		if ((fcount =
+		     kmalloc (max * sizeof *fcount, GFP_KERNEL)) == NULL) {
+			printk ("mtrr: could not allocate\n");
+			return -ENOMEM;
+		}
+		memset (fcount, 0, max * sizeof *fcount);
+		file->private_data = fcount;
+	}
+
+	if (!page) {
+		if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
+			printk
+			    (KERN_INFO "mtrr: size and base must be multiples of 4 kiB\n");
+			printk (KERN_INFO "mtrr: size: 0x%x  base: 0x%Lx\n", size, base);
+			return -EINVAL;
+		}
+		base >>= PAGE_SHIFT;
+		size >>= PAGE_SHIFT;
+	}
+
+	reg = mtrr_add_page (base, size, type, 1);
+
+	if (reg >= 0)
+		++fcount[reg];
+	return reg;
+}
+
+
+static int mtrr_file_del (u64 base, u32 size,
+		struct file *file, int page)
+{
+	int reg;
+	unsigned int *fcount = file->private_data;
+
+	if (!page) {
+		if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
+			printk
+			    (KERN_INFO "mtrr: size and base must be multiples of 4 kiB\n");
+			printk (KERN_INFO "mtrr: size: 0x%x  base: 0x%Lx\n", size, base);
+			return -EINVAL;
+		}
+		base >>= PAGE_SHIFT;
+		size >>= PAGE_SHIFT;
+	}
+	reg = mtrr_del_page (-1, base, size);
+	if (reg < 0)
+		return reg;
+	if (fcount == NULL)
+		return reg;
+	if (fcount[reg] < 1)
+		return -EINVAL;
+	--fcount[reg];
+	return reg;
+}
+
+
+static ssize_t mtrr_read (struct file *file, char *buf, size_t len,
+		loff_t * ppos)
+{
+	if (*ppos >= ascii_buf_bytes)
+		return 0;
+
+	if (*ppos + len > ascii_buf_bytes)
+		len = ascii_buf_bytes - *ppos;
+
+	if (copy_to_user (buf, ascii_buffer + *ppos, len))
+		return -EFAULT;
+
+	*ppos += len;
+	return len;
+}
+
+
+static ssize_t mtrr_write (struct file *file, const char *buf,
+		size_t len, loff_t * ppos)
+/*  Format of control line:
+    "base=%Lx size=%Lx type=%s"     OR:
+    "disable=%d"
+*/
+{
+	int i, err, reg;
+	u64 base;
+	u32 size;
+	char *ptr;
+	char line[LINE_SIZE];
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	memset (line, 0, LINE_SIZE);
+
+	if (len > LINE_SIZE)
+		len = LINE_SIZE;
+
+	if (copy_from_user (line, buf, len - 1))
+		return -EFAULT;
+	ptr = line + strlen (line) - 1;
+
+	if (*ptr == '\n')
+		*ptr = '\0';
+
+	if (!strncmp (line, "disable=", 8)) {
+		reg = simple_strtoul (line + 8, &ptr, 0);
+		err = mtrr_del_page (reg, 0, 0);
+		if (err < 0)
+			return err;
+		return len;
+	}
+
+	if (strncmp (line, "base=", 5)) {
+		printk (KERN_INFO "mtrr: no \"base=\" in line: \"%s\"\n", line);
+		return -EINVAL;
+	}
+
+	base = simple_strtoull (line + 5, &ptr, 0);
+
+	for (; isspace (*ptr); ++ptr) ;
+
+	if (strncmp (ptr, "size=", 5)) {
+		printk (KERN_INFO "mtrr: no \"size=\" in line: \"%s\"\n", line);
+		return -EINVAL;
+	}
+
+	size = simple_strtoull (ptr + 5, &ptr, 0);
+
+	if ((base & 0xfff) || (size & 0xfff)) {
+		printk (KERN_INFO "mtrr: size and base must be multiples of 4 kiB\n");
+		printk (KERN_INFO "mtrr: size: 0x%x  base: 0x%Lx\n", size, base);
+		return -EINVAL;
+	}
+
+	for (; isspace (*ptr); ++ptr) ;
+
+	if (strncmp (ptr, "type=", 5)) {
+		printk (KERN_INFO "mtrr: no \"type=\" in line: \"%s\"\n", line);
+		return -EINVAL;
+	}
+	ptr += 5;
+
+	for (; isspace (*ptr); ++ptr) ;
+
+	for (i = 0; i < MTRR_NUM_TYPES; ++i) {
+		if (strcmp (ptr, mtrr_strings[i]))
+			continue;
+		base >>= PAGE_SHIFT;
+		size >>= PAGE_SHIFT;
+		err = mtrr_add_page ((u64) base, size, i, 1);
+		if (err < 0)
+			return err;
+		return len;
+	}
+	printk (KERN_INFO "mtrr: illegal type: \"%s\"\n", ptr);
+	return -EINVAL;
+}
+
+
+static int mtrr_ioctl (struct inode *inode, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	int err;
+	mtrr_type type;
+	struct mtrr_sentry sentry;
+	struct mtrr_gentry gentry;
+
+	switch (cmd) {
+	default:
+		return -ENOIOCTLCMD;
+
+	case MTRRIOC_ADD_ENTRY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
+			return -EFAULT;
+		err = mtrr_file_add (sentry.base, sentry.size, sentry.type,
+				   file, 0);
+		if (err < 0)
+			return err;
+		break;
+
+	case MTRRIOC_SET_ENTRY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
+			return -EFAULT;
+		err = mtrr_add (sentry.base, sentry.size, sentry.type, 0);
+		if (err < 0)
+			return err;
+		break;
+
+	case MTRRIOC_DEL_ENTRY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
+			return -EFAULT;
+		err = mtrr_file_del (sentry.base, sentry.size, file, 0);
+		if (err < 0)
+			return err;
+		break;
+
+	case MTRRIOC_KILL_ENTRY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
+			return -EFAULT;
+		err = mtrr_del (-1, sentry.base, sentry.size);
+		if (err < 0)
+			return err;
+		break;
+
+	case MTRRIOC_GET_ENTRY:
+		if (copy_from_user (&gentry, (void *) arg, sizeof gentry))
+			return -EFAULT;
+		if (gentry.regnum >= get_num_var_ranges ())
+			return -EINVAL;
+		get_mtrr (gentry.regnum, (u64*) &gentry.base, &gentry.size, &type);
+
+		/* Hide entries that go above 4GB */
+		if (gentry.base + gentry.size > 0x100000
+		    || gentry.size == 0x100000)
+			gentry.base = gentry.size = gentry.type = 0;
+		else {
+			gentry.base <<= PAGE_SHIFT;
+			gentry.size <<= PAGE_SHIFT;
+			gentry.type = type;
+		}
+
+		if (copy_to_user ((void *) arg, &gentry, sizeof gentry))
+			return -EFAULT;
+		break;
+
+	case MTRRIOC_ADD_PAGE_ENTRY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
+			return -EFAULT;
+		err = mtrr_file_add (sentry.base, sentry.size, sentry.type, file, 1);
+		if (err < 0)
+			return err;
+		break;
+
+	case MTRRIOC_SET_PAGE_ENTRY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
+			return -EFAULT;
+		err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0);
+		if (err < 0)
+			return err;
+		break;
+
+	case MTRRIOC_DEL_PAGE_ENTRY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
+			return -EFAULT;
+		err = mtrr_file_del (sentry.base, sentry.size, file, 1);
+		if (err < 0)
+			return err;
+		break;
+
+	case MTRRIOC_KILL_PAGE_ENTRY:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
+			return -EFAULT;
+		err = mtrr_del_page (-1, sentry.base, sentry.size);
+		if (err < 0)
+			return err;
+		break;
+
+	case MTRRIOC_GET_PAGE_ENTRY:
+		if (copy_from_user (&gentry, (void *) arg, sizeof gentry))
+			return -EFAULT;
+		if (gentry.regnum >= get_num_var_ranges ())
+			return -EINVAL;
+		get_mtrr (gentry.regnum, (u64*) &gentry.base, &gentry.size, &type);
+		gentry.type = type;
+
+		if (copy_to_user ((void *) arg, &gentry, sizeof gentry))
+			return -EFAULT;
+		break;
+	}
+	return 0;
+}
+
+
+static int mtrr_close (struct inode *ino, struct file *file)
+{
+	int i, max;
+	unsigned int *fcount = file->private_data;
+
+	if (fcount == NULL)
+		return 0;
+
+	lock_kernel ();
+	max = get_num_var_ranges ();
+	for (i = 0; i < max; ++i) {
+		while (fcount[i] > 0) {
+			if (mtrr_del (i, 0, 0) < 0)
+				printk ("mtrr: reg %d not used\n", i);
+			--fcount[i];
+		}
+	}
+	unlock_kernel ();
+	kfree (fcount);
+	file->private_data = NULL;
+	return 0;
+}
+
+
+static struct file_operations mtrr_fops = {
+	owner:	THIS_MODULE,
+	read:	mtrr_read,
+	write:	mtrr_write,
+	ioctl:	mtrr_ioctl,
+	release:mtrr_close,
+};
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *proc_root_mtrr;
+#endif
+
+static devfs_handle_t devfs_handle;
+
+static void compute_ascii (void)
+{
+	char factor;
+	int i, max;
+	mtrr_type type;
+	u64 base;
+	u32 size;
+
+	ascii_buf_bytes = 0;
+	max = get_num_var_ranges ();
+	for (i = 0; i < max; i++) {
+		get_mtrr (i, &base, &size, &type);
+		if (size == 0)
+			usage_table[i] = 0;
+		else {
+			if (size < (0x100000 >> PAGE_SHIFT)) {
+				/* less than 1MB */
+				factor = 'K';
+				size <<= PAGE_SHIFT - 10;
+			} else {
+				factor = 'M';
+				size >>= 20 - PAGE_SHIFT;
+			}
+			sprintf (ascii_buffer + ascii_buf_bytes,
+				"reg%02i: base=0x%05Lx000 (%4iMB), size=%4i%cB: %s, count=%d\n",
+				i, base, (u32) base >> (20 - PAGE_SHIFT), size, factor,
+				attrib_to_str (type), usage_table[i]);
+			ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes);
+		}
+	}
+	devfs_set_file_size (devfs_handle, ascii_buf_bytes);
+#ifdef CONFIG_PROC_FS
+	if (proc_root_mtrr)
+		proc_root_mtrr->size = ascii_buf_bytes;
+#endif
+}
+
+#endif	/*  USERSPACE_INTERFACE  */
+
+EXPORT_SYMBOL (mtrr_add);
+EXPORT_SYMBOL (mtrr_del);
+
+
+static void __init mtrr_setup (void)
+{
+	printk ("mtrr: v%s)\n", MTRR_VERSION);
+
+	if (test_bit (X86_FEATURE_MTRR, boot_cpu_data.x86_capability)) {
+		/* Query the width (in bits) of the physical
+		   addressable memory on the Hammer family. */
+		if ((cpuid_eax (0x80000000) >= 0x80000008)) {
+			u32 phys_addr;
+			phys_addr = cpuid_eax (0x80000008) & 0xff;
+			size_or_mask = ~((1L << phys_addr) - 1);
+			/*
+			 * top bits MBZ as its beyond the addressable range.
+			 * bottom bits MBZ as we don't care about lower 12 bits of addr.
+			 */
+			size_and_mask = (~size_or_mask) & 0x000ffffffffff000L;
+		}
+	}
+}
+
+#ifdef CONFIG_SMP
+
+static volatile u32 smp_changes_mask __initdata = 0;
+static struct mtrr_state smp_mtrr_state __initdata = { 0, 0 };
+
+void __init mtrr_init_boot_cpu (void)
+{
+	mtrr_setup();
+	get_mtrr_state (&smp_mtrr_state);
+}
+
+
+void __init mtrr_init_secondary_cpu (void)
+{
+	u64 mask;
+	int count;
+	struct set_mtrr_context ctxt;
+
+	/* Note that this is not ideal, since the cache is only flushed/disabled
+	   for this CPU while the MTRRs are changed, but changing this requires
+	   more invasive changes to the way the kernel boots  */
+	set_mtrr_prepare (&ctxt);
+	mask = set_mtrr_state (&smp_mtrr_state, &ctxt);
+	set_mtrr_done (&ctxt);
+
+	/*  Use the atomic bitops to update the global mask  */
+	for (count = 0; count < sizeof mask * 8; ++count) {
+		if (mask & 0x01)
+			set_bit (count, &smp_changes_mask);
+		mask >>= 1;
+	}
+}
+
+#endif	/*  CONFIG_SMP  */
+
+
+int __init mtrr_init (void)
+{
+#ifdef CONFIG_SMP
+	/* mtrr_setup() should already have been called from mtrr_init_boot_cpu() */
+
+	finalize_mtrr_state (&smp_mtrr_state);
+	mtrr_state_warn (smp_changes_mask);
+#else
+	mtrr_setup();
+#endif
+
+#ifdef CONFIG_PROC_FS
+	proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root);
+	if (proc_root_mtrr) {
+		proc_root_mtrr->owner = THIS_MODULE;
+		proc_root_mtrr->proc_fops = &mtrr_fops;
+	}
+#endif
+#ifdef CONFIG_DEVFS_FS
+	devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0,
+				S_IFREG | S_IRUGO | S_IWUSR,
+				&mtrr_fops, NULL);
+#endif
+	init_table ();
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/nmi.c linux-2.4.20/arch/x86_64/kernel/nmi.c
--- linux-2.4.19/arch/x86_64/kernel/nmi.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/nmi.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,390 @@
+/*
+ *  linux/arch/x86_64/nmi.c
+ *
+ *  NMI watchdog support on APIC systems
+ *
+ *  Started by Ingo Molnar <mingo@redhat.com>
+ *
+ *  Fixes:
+ *  Mikael Pettersson	: AMD K7 support for local APIC NMI watchdog.
+ *  Mikael Pettersson	: Power Management for local APIC NMI watchdog.
+ *  Mikael Pettersson	: Pentium 4 support for local APIC NMI watchdog.
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/bootmem.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/mc146818rtc.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/smp.h>
+#include <asm/mtrr.h>
+#include <asm/mpspec.h>
+#include <asm/proto.h>
+#include <asm/kdebug.h>
+
+unsigned int nmi_watchdog = NMI_LOCAL_APIC;
+static unsigned int nmi_hz = HZ;
+unsigned int nmi_perfctr_msr;	/* the MSR to reset in NMI handler */
+
+#define K7_EVNTSEL_ENABLE	(1 << 22)
+#define K7_EVNTSEL_INT		(1 << 20)
+#define K7_EVNTSEL_OS		(1 << 17)
+#define K7_EVNTSEL_USR		(1 << 16)
+#define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING	0x76
+#define K7_NMI_EVENT		K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING
+
+#define P6_EVNTSEL0_ENABLE	(1 << 22)
+#define P6_EVNTSEL_INT		(1 << 20)
+#define P6_EVNTSEL_OS		(1 << 17)
+#define P6_EVNTSEL_USR		(1 << 16)
+#define P6_EVENT_CPU_CLOCKS_NOT_HALTED	0x79
+#define P6_NMI_EVENT		P6_EVENT_CPU_CLOCKS_NOT_HALTED
+
+#define MSR_P4_MISC_ENABLE	0x1A0
+#define MSR_P4_MISC_ENABLE_PERF_AVAIL	(1<<7)
+#define MSR_P4_MISC_ENABLE_PEBS_UNAVAIL	(1<<12)
+#define MSR_P4_PERFCTR0		0x300
+#define MSR_P4_CCCR0		0x360
+#define P4_ESCR_EVENT_SELECT(N)	((N)<<25)
+#define P4_ESCR_OS		(1<<3)
+#define P4_ESCR_USR		(1<<2)
+#define P4_CCCR_OVF_PMI		(1<<26)
+#define P4_CCCR_THRESHOLD(N)	((N)<<20)
+#define P4_CCCR_COMPLEMENT	(1<<19)
+#define P4_CCCR_COMPARE		(1<<18)
+#define P4_CCCR_REQUIRED	(3<<16)
+#define P4_CCCR_ESCR_SELECT(N)	((N)<<13)
+#define P4_CCCR_ENABLE		(1<<12)
+/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
+   CRU_ESCR0 (with any non-null event selector) through a complemented
+   max threshold. [IA32-Vol3, Section 14.9.9] */
+#define MSR_P4_IQ_COUNTER0	0x30C
+#define MSR_P4_IQ_CCCR0		0x36C
+#define MSR_P4_CRU_ESCR0	0x3B8
+#define P4_NMI_CRU_ESCR0	(P4_ESCR_EVENT_SELECT(0x3F)|P4_ESCR_OS|P4_ESCR_USR)
+#define P4_NMI_IQ_CCCR0	\
+	(P4_CCCR_OVF_PMI|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT|	\
+	 P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE)
+
+/* Why is there no CPUID flag for this? */
+static __init int cpu_has_lapic(void)
+{
+    switch (boot_cpu_data.x86_vendor) { 
+    case X86_VENDOR_INTEL:
+    case X86_VENDOR_AMD: 
+	    return boot_cpu_data.x86 >= 6; 
+	    /* add more cpus here or find a better way to figure this out. */
+    default:
+	    return 0;
+    } 
+}
+
+int __init check_nmi_watchdog (void)
+{
+	irq_cpustat_t tmp[NR_CPUS];
+	int j, cpu;
+
+	if (nmi_watchdog == NMI_LOCAL_APIC && !cpu_has_lapic())
+	    return -1; 
+
+	printk(KERN_INFO "testing NMI watchdog ... ");
+
+	memcpy(tmp, irq_stat, sizeof(tmp));
+	sti();
+	mdelay((10*1000)/nmi_hz); // wait 10 ticks
+
+	for (j = 0; j < smp_num_cpus; j++) {
+		cpu = cpu_logical_map(j);
+		if (nmi_count(cpu) - tmp[cpu].__nmi_count <= 5) {
+			printk("CPU#%d: NMI appears to be stuck!\n", cpu);
+			return -1;
+		}
+	}
+	printk("OK.\n");
+
+	/* now that we know it works we can reduce NMI frequency to
+	   something more reasonable; makes a difference in some configs */
+	if (nmi_watchdog == NMI_LOCAL_APIC)
+		nmi_hz = 1;
+
+	return 0;
+}
+
+static int __init setup_nmi_watchdog(char *str)
+{
+	int nmi;
+
+	get_option(&str, &nmi);
+
+	if (nmi >= NMI_INVALID)
+		return 0;
+	if (nmi == NMI_NONE)
+		nmi_watchdog = nmi;
+	nmi_watchdog = nmi;
+	return 1;
+}
+
+__setup("nmi_watchdog=", setup_nmi_watchdog);
+
+#ifdef CONFIG_PM
+
+#include <linux/pm.h>
+
+struct pm_dev *nmi_pmdev;
+
+static void disable_apic_nmi_watchdog(void)
+{
+	switch (boot_cpu_data.x86_vendor) {
+	case X86_VENDOR_AMD:
+		if (strstr(boot_cpu_data.x86_model_id, "Screwdriver"))
+			return;	    
+		wrmsr(MSR_K7_EVNTSEL0, 0, 0);
+		break;
+	case X86_VENDOR_INTEL:
+		switch (boot_cpu_data.x86) {
+		case 6:
+			wrmsr(MSR_P6_EVNTSEL0, 0, 0);
+			break;
+		case 15:
+			wrmsr(MSR_P4_IQ_CCCR0, 0, 0);
+			wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
+			break;
+		}
+		break;
+	}
+}
+
+static int nmi_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+	switch (rqst) {
+	case PM_SUSPEND:
+		disable_apic_nmi_watchdog();
+		break;
+	case PM_RESUME:
+		setup_apic_nmi_watchdog();
+		break;
+	}
+	return 0;
+}
+
+static void nmi_pm_init(void)
+{
+	if (!nmi_pmdev)
+		nmi_pmdev = apic_pm_register(PM_SYS_DEV, 0, nmi_pm_callback);
+}
+
+#define __pminit	/*empty*/
+
+#else	/* CONFIG_PM */
+
+static inline void nmi_pm_init(void) { }
+
+#define __pminit	__init
+
+#endif	/* CONFIG_PM */
+
+/*
+ * Activate the NMI watchdog via the local APIC.
+ * Original code written by Keith Owens.
+ */
+
+static void __pminit clear_msr_range(unsigned int base, unsigned int n)
+{
+	unsigned int i;
+
+	for(i = 0; i < n; ++i)
+		wrmsr(base+i, 0, 0);
+}
+
+static void __pminit setup_k7_watchdog(void)
+{
+	unsigned int evntsel;
+
+	nmi_perfctr_msr = MSR_K7_PERFCTR0;
+
+	clear_msr_range(MSR_K7_EVNTSEL0, 4);
+	clear_msr_range(MSR_K7_PERFCTR0, 4);
+
+	evntsel = K7_EVNTSEL_INT
+		| K7_EVNTSEL_OS
+		| K7_EVNTSEL_USR
+		| K7_NMI_EVENT;
+
+	wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
+	Dprintk("setting K7_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000));
+	wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1);
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+	evntsel |= K7_EVNTSEL_ENABLE;
+	wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
+}
+
+static void __pminit setup_p6_watchdog(void)
+{
+	unsigned int evntsel;
+
+	nmi_perfctr_msr = MSR_P6_PERFCTR0;
+
+	clear_msr_range(MSR_P6_EVNTSEL0, 2);
+	clear_msr_range(MSR_P6_PERFCTR0, 2);
+
+	evntsel = P6_EVNTSEL_INT
+		| P6_EVNTSEL_OS
+		| P6_EVNTSEL_USR
+		| P6_NMI_EVENT;
+
+	wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
+	Dprintk("setting P6_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000));
+	wrmsr(MSR_P6_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0);
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+	evntsel |= P6_EVNTSEL0_ENABLE;
+	wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
+}
+
+static int __pminit setup_p4_watchdog(void)
+{
+	unsigned int misc_enable, dummy;
+
+	rdmsr(MSR_P4_MISC_ENABLE, misc_enable, dummy);
+	if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL))
+		return 0;
+
+	nmi_perfctr_msr = MSR_P4_IQ_COUNTER0;
+
+	if (!(misc_enable & MSR_P4_MISC_ENABLE_PEBS_UNAVAIL))
+		clear_msr_range(0x3F1, 2);
+	/* MSR 0x3F0 seems to have a default value of 0xFC00, but current
+	   docs doesn't fully define it, so leave it alone for now. */
+	clear_msr_range(0x3A0, 31);
+	clear_msr_range(0x3C0, 6);
+	clear_msr_range(0x3C8, 6);
+	clear_msr_range(0x3E0, 2);
+	clear_msr_range(MSR_P4_CCCR0, 18);
+	clear_msr_range(MSR_P4_PERFCTR0, 18);
+
+	wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0);
+	wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0);
+	Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz/nmi_hz*1000));
+	wrmsr(MSR_P4_IQ_COUNTER0, -(cpu_khz/nmi_hz*1000), -1);
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+	wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
+	return 1;
+}
+
+void __pminit setup_apic_nmi_watchdog (void)
+{
+	switch (boot_cpu_data.x86_vendor) {
+	case X86_VENDOR_AMD:
+		if (boot_cpu_data.x86 < 6)
+			return;
+		if (strstr(boot_cpu_data.x86_model_id, "Screwdriver"))
+			return;	    
+		setup_k7_watchdog();
+		break;
+	case X86_VENDOR_INTEL:
+		switch (boot_cpu_data.x86) {
+		case 6:
+			setup_p6_watchdog();
+			break;
+		case 15:
+			if (!setup_p4_watchdog())
+				return;
+			break;
+		default:
+			return;
+		}
+		break;
+	default:
+		return;
+	}
+	nmi_pm_init();
+}
+
+static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * the best way to detect whether a CPU has a 'hard lockup' problem
+ * is to check it's local APIC timer IRQ counts. If they are not
+ * changing then that CPU has some problem.
+ *
+ * as these watchdog NMI IRQs are generated on every CPU, we only
+ * have to check the current processor.
+ *
+ * since NMIs dont listen to _any_ locks, we have to be extremely
+ * careful not to rely on unsafe variables. The printk might lock
+ * up though, so we have to break up any console locks first ...
+ * [when there will be more tty-related locks, break them up
+ *  here too!]
+ */
+
+static unsigned int
+	last_irq_sums [NR_CPUS],
+	alert_counter [NR_CPUS];
+
+void touch_nmi_watchdog (void)
+{
+	int i;
+
+	/*
+	 * Just reset the alert counters, (other CPUs might be
+	 * spinning on locks we hold):
+	 */
+	for (i = 0; i < smp_num_cpus; i++)
+		alert_counter[i] = 0;
+}
+
+void nmi_watchdog_tick (struct pt_regs * regs)
+{
+
+	/*
+	 * Since current-> is always on the stack, and we always switch
+	 * the stack NMI-atomically, it's safe to use smp_processor_id().
+	 */
+	int sum, cpu = smp_processor_id();
+
+	sum = apic_timer_irqs[cpu];
+
+	if (last_irq_sums[cpu] == sum) {
+		/*
+		 * Ayiee, looks like this CPU is stuck ...
+		 * wait a few IRQs (5 seconds) before doing the oops ...
+		 */
+		alert_counter[cpu]++;
+		if (alert_counter[cpu] == 5*nmi_hz) {
+			spin_lock(&nmi_print_lock);
+			/*
+			 * We are in trouble anyway, lets at least try
+			 * to get a message out.
+			 */
+			bust_spinlocks(1);
+			printk("NMI Watchdog detected LOCKUP on CPU%d, eip %16lx, registers:\n", cpu, regs->rip);
+			show_registers(regs);
+			printk("console shuts up ...\n");
+			console_silent();
+			spin_unlock(&nmi_print_lock);
+			bust_spinlocks(0);
+			do_exit(SIGSEGV);
+		}
+	} else {
+		last_irq_sums[cpu] = sum;
+		alert_counter[cpu] = 0;
+	}
+	if (nmi_perfctr_msr) {
+		if (nmi_perfctr_msr == MSR_P4_IQ_COUNTER0) {
+			/*
+			 * P4 quirks:
+			 * - An overflown perfctr will assert its interrupt
+			 *   until the OVF flag in its CCCR is cleared.
+			 * - LVTPC is masked on interrupt and must be
+			 *   unmasked by the LVTPC handler.
+			 */
+			wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
+			apic_write(APIC_LVTPC, APIC_DM_NMI);
+		}
+		wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/pci-dma.c linux-2.4.20/arch/x86_64/kernel/pci-dma.c
--- linux-2.4.19/arch/x86_64/kernel/pci-dma.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/pci-dma.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,74 @@
+/*
+ * Dynamic DMA mapping support. Common code
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+dma_addr_t bad_dma_address = -1UL; 
+
+/* Map a set of buffers described by scatterlist in streaming
+ * mode for DMA.  This is the scather-gather version of the
+ * above pci_map_single interface.  Here the scatter gather list
+ * elements are each tagged with the appropriate dma address
+ * and length.  They are obtained via sg_dma_{address,length}(SG).
+ *
+ * NOTE: An implementation may be able to use a smaller number of
+ *       DMA address/length pairs than there are SG table elements.
+ *       (for example via virtual mapping capabilities)
+ *       The routine returns the number of addr/length pairs actually
+ *       used, at most nents.
+ *
+ * Device ownership issues as mentioned above for pci_map_single are
+ * the same here.
+ */
+int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+			     int nents, int direction)
+{
+	int i;
+
+	BUG_ON(direction == PCI_DMA_NONE);
+ 
+ 	/*
+ 	 * temporary 2.4 hack
+ 	 */
+ 	for (i = 0; i < nents; i++ ) {
+		struct scatterlist *s = &sg[i];
+ 		if (s->address) {
+			BUG_ON(s->page || s->offset); 
+ 			s->dma_address = pci_map_single(hwdev, s->address, s->length, 
+							direction); 
+ 		} else if (s->page) { 
+			s->dma_address = pci_map_page(hwdev, s->page, s->offset,
+						      s->length, direction); 
+		} else
+			BUG(); 
+
+		if (unlikely(s->dma_address == bad_dma_address))
+			goto error; 
+ 	}
+	return nents;
+
+ error: 
+	pci_unmap_sg(hwdev, sg, i, direction); 
+	return 0; 
+}
+
+/* Unmap a set of streaming mode DMA translations.
+ * Again, cpu read rules concerning calls here are the same as for
+ * pci_unmap_single() above.
+ */
+void pci_unmap_sg(struct pci_dev *dev, struct scatterlist *sg, 
+				  int nents, int dir)
+{
+	int i;
+	for (i = 0; i < nents; i++) { 
+		struct scatterlist *s = &sg[i];
+		BUG_ON(s->address == NULL && s->page == NULL); 
+		BUG_ON(s->dma_address == 0); 
+		pci_unmap_single(dev, s->dma_address, s->length, dir); 
+	} 
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/pci-gart.c linux-2.4.20/arch/x86_64/kernel/pci-gart.c
--- linux-2.4.19/arch/x86_64/kernel/pci-gart.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/pci-gart.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,560 @@
+/*
+ * Dynamic DMA mapping support for AMD Hammer.
+ * 
+ * Use the integrated AGP GART in the Hammer northbridge as an IOMMU for PCI.
+ * This allows to use PCI devices that only support 32bit addresses on systems
+ * with more than 4GB. 
+ *
+ * See Documentation/DMA-mapping.txt for the interface specification.
+ * 
+ * Copyright 2002 Andi Kleen, SuSE Labs.
+ * $Id: pci-gart.c,v 1.12 2002/09/19 19:25:32 ak Exp $
+ */
+
+/* 
+ * Notebook:
+
+agpgart_be
+ check if the simple reservation scheme is enough.
+
+possible future tuning: 
+ fast path for sg streaming mappings 
+ more intelligent flush strategy - flush only a single NB?
+ move boundary between IOMMU and AGP in GART dynamically
+ could use exact fit in the gart in alloc_consistent, not order of two.
+*/ 
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/agp_backend.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/mtrr.h>
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+#include <asm/proto.h>
+#include "pci-x86_64.h"
+
+unsigned long iommu_bus_base;	/* GART remapping area (physical) */
+static unsigned long iommu_size; 	/* size of remapping area bytes */
+static unsigned long iommu_pages;	/* .. and in pages */
+
+u32 *iommu_gatt_base; 		/* Remapping table */
+
+int no_iommu; 
+static int no_agp; 
+int force_mmu = 1;
+
+extern int fallback_aper_order;
+extern int fallback_aper_force;
+
+/* Allocation bitmap for the remapping area */ 
+static spinlock_t iommu_bitmap_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long *iommu_gart_bitmap; /* guarded by iommu_bitmap_lock */
+
+#define GPTE_MASK 0xfffffff000
+#define GPTE_VALID    1
+#define GPTE_COHERENT 2
+#define GPTE_ENCODE(x,flag) (((x) & 0xfffffff0) | ((x) >> 28) | GPTE_VALID | (flag))
+#define GPTE_DECODE(x) (((x) & 0xfffff000) | (((x) & 0xff0) << 28))
+
+#define for_all_nb(dev) \
+	pci_for_each_dev(dev) \
+		if (dev->bus->number == 0 && PCI_FUNC(dev->devfn) == 3 && \
+		    (PCI_SLOT(dev->devfn) >= 24) && (PCI_SLOT(dev->devfn) <= 31))
+
+#define EMERGENCY_PAGES 32 /* = 128KB */ 
+
+#ifdef CONFIG_AGP
+extern int agp_init(void);
+#define AGPEXTERN extern
+#else
+#define AGPEXTERN
+#endif
+
+/* backdoor interface to AGP driver */
+AGPEXTERN int agp_memory_reserved;
+AGPEXTERN __u32 *agp_gatt_table;
+
+static unsigned long next_bit;  /* protected by iommu_bitmap_lock */
+
+static unsigned long alloc_iommu(int size) 
+{ 	
+	unsigned long offset, flags;
+
+	spin_lock_irqsave(&iommu_bitmap_lock, flags);	
+
+	offset = find_next_zero_string(iommu_gart_bitmap,next_bit,iommu_pages,size);
+	if (offset == -1) 
+	       	offset = find_next_zero_string(iommu_gart_bitmap,0,next_bit,size);
+	if (offset != -1) { 
+		set_bit_string(iommu_gart_bitmap, offset, size); 
+		next_bit = offset+size; 
+		if (next_bit >= iommu_pages) 
+			next_bit = 0;
+	} 
+	spin_unlock_irqrestore(&iommu_bitmap_lock, flags);      
+	return offset;
+} 
+
+static void free_iommu(unsigned long offset, int size)
+{ 
+	unsigned long flags;
+	spin_lock_irqsave(&iommu_bitmap_lock, flags);
+	clear_bit_string(iommu_gart_bitmap, offset, size);
+	next_bit = offset;
+	spin_unlock_irqrestore(&iommu_bitmap_lock, flags);
+} 
+
+static inline void flush_gart(void) 
+{ 
+	struct pci_dev *nb; 
+	for_all_nb(nb) { 
+		u32 flag; 
+		pci_read_config_dword(nb, 0x9c, &flag); /* could cache this */ 
+		/* could complain for PTE walk errors here (bit 1 of flag) */ 
+		flag |= 1; 
+		pci_write_config_dword(nb, 0x9c, flag); 
+	} 
+} 
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+			   dma_addr_t *dma_handle)
+{
+	void *memory;
+	int gfp = GFP_ATOMIC;
+	int order, i;
+	unsigned long iommu_page;
+
+	if (hwdev == NULL || hwdev->dma_mask < 0xffffffff || no_iommu)
+		gfp |= GFP_DMA;
+
+	/* 
+	 * First try to allocate continuous and use directly if already 
+	 * in lowmem. 
+	 */ 
+	order = get_order(size);
+	memory = (void *)__get_free_pages(gfp, order);
+	if (memory == NULL) {
+		return NULL; 
+	} else {
+		int high = (unsigned long)virt_to_bus(memory) + size
+			>= 0xffffffff;
+		int mmu = high;
+		if (force_mmu) 
+			mmu = 1;
+		if (no_iommu) { 
+			if (high) goto error;
+			mmu = 0; 
+		} 	
+		memset(memory, 0, size); 
+		if (!mmu) { 
+			*dma_handle = virt_to_bus(memory);
+			return memory;
+		}
+	} 
+
+	iommu_page = alloc_iommu(1<<order);
+	if (iommu_page == -1)
+		goto error; 
+
+   	/* Fill in the GATT, allocating pages as needed. */
+	for (i = 0; i < 1<<order; i++) { 
+		unsigned long phys_mem; 
+		void *mem = memory + i*PAGE_SIZE;
+		if (i > 0) 
+			atomic_inc(&virt_to_page(mem)->count); 
+		phys_mem = virt_to_phys(mem); 
+		BUG_ON(phys_mem & ~PTE_MASK); 
+		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem,GPTE_COHERENT); 
+	} 
+
+	flush_gart();
+	*dma_handle = iommu_bus_base + (iommu_page << PAGE_SHIFT);
+	return memory; 
+	
+ error:
+	free_pages((unsigned long)memory, order); 
+	return NULL; 
+}
+
+/* 
+ * Unmap consistent memory.
+ * The caller must ensure that the device has finished accessing the mapping.
+ */
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+			 void *vaddr, dma_addr_t bus)
+{
+	u64 pte;
+	int order = get_order(size);
+	unsigned long iommu_page;
+	int i;
+
+	if (bus < iommu_bus_base || bus > iommu_bus_base + iommu_size) { 
+		free_pages((unsigned long)vaddr, order); 		
+		return;
+	} 
+	iommu_page = (bus - iommu_bus_base) / PAGE_SIZE;
+	for (i = 0; i < 1<<order; i++) {
+		pte = iommu_gatt_base[iommu_page + i];
+		BUG_ON((pte & GPTE_VALID) == 0); 
+		iommu_gatt_base[iommu_page + i] = 0; 		
+		free_page((unsigned long) __va(GPTE_DECODE(pte)));
+	} 
+	flush_gart(); 
+	free_iommu(iommu_page, 1<<order);
+}
+
+#ifdef CONFIG_IOMMU_LEAK
+/* Debugging aid for drivers that don't free their IOMMU tables */
+static void **iommu_leak_tab; 
+static int leak_trace;
+int iommu_leak_dumppages = 20; 
+void dump_leak(void)
+{
+	int i;
+	static int dump; 
+	if (dump || !iommu_leak_tab) return;
+	dump = 1;
+	show_stack(NULL);
+	printk("Dumping %d pages from end of IOMMU:\n", iommu_leak_dumppages); 
+	for (i = 0; i < iommu_leak_dumppages; i++) 
+		printk("[%lu: %lx] ",
+		       iommu_pages-i,(unsigned long) iommu_leak_tab[iommu_pages-i]); 
+	printk("\n");
+}
+#endif
+
+static void iommu_full(struct pci_dev *dev, void *addr, size_t size, int dir)
+{
+	/* 
+	 * Ran out of IOMMU space for this operation. This is very bad.
+	 * Unfortunately the drivers cannot handle this operation properly.
+	 * Return some non mapped prereserved space in the aperture and 
+	 * let the Northbridge deal with it. This will result in garbage
+	 * in the IO operation. When the size exceeds the prereserved space
+	 * memory corruption will occur or random memory will be DMAed 
+	 * out. Hopefully no network devices use single mappings that big.
+	 */ 
+	
+	printk(KERN_ERR 
+  "PCI-DMA: Error: ran out out IOMMU space for %p size %lu at device %s[%s]\n",
+	       addr,size, dev ? dev->name : "?", dev ? dev->slot_name : "?");
+
+	if (size > PAGE_SIZE*EMERGENCY_PAGES) {
+		if (dir == PCI_DMA_FROMDEVICE || dir == PCI_DMA_BIDIRECTIONAL)
+			panic("PCI-DMA: Memory will be corrupted\n");
+		if (dir == PCI_DMA_TODEVICE || dir == PCI_DMA_BIDIRECTIONAL) 
+			panic("PCI-DMA: Random memory will be DMAed\n"); 
+	} 
+
+#ifdef CONFIG_IOMMU_LEAK
+	dump_leak(); 
+#endif
+} 
+
+static inline int need_iommu(struct pci_dev *dev, unsigned long addr, size_t size)
+{ 
+	u64 mask = dev ? dev->dma_mask : 0xffffffff;
+	int high = (~mask & (unsigned long)(addr + size)) != 0;
+	int mmu = high;
+	if (force_mmu) 
+		mmu = 1; 
+	if (no_iommu) { 
+		if (high) 
+			panic("pci_map_single: high address but no IOMMU.\n"); 
+		mmu = 0; 
+	} 	
+	return mmu; 
+}
+
+dma_addr_t pci_map_single(struct pci_dev *dev, void *addr, size_t size,int dir)
+{ 
+	unsigned long iommu_page;
+	unsigned long phys_mem, bus;
+	int i, npages;
+
+	BUG_ON(dir == PCI_DMA_NONE);
+
+	phys_mem = virt_to_phys(addr); 
+	if (!need_iommu(dev, phys_mem, size))
+		return phys_mem; 
+
+	npages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT;
+
+	iommu_page = alloc_iommu(npages); 
+	if (iommu_page == -1) {
+		iommu_full(dev, addr, size, dir); 
+		return iommu_bus_base; 
+	} 
+
+	phys_mem &= PAGE_MASK;
+	for (i = 0; i < npages; i++, phys_mem += PAGE_SIZE) {
+		BUG_ON(phys_mem & ~PTE_MASK); 
+		
+		/* 
+		 * Set coherent mapping here to avoid needing to flush
+		 * the caches on mapping.
+		 */
+		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem, GPTE_COHERENT);
+
+#ifdef CONFIG_IOMMU_LEAK
+		/* XXX need eventually caller of pci_map_sg */
+		if (iommu_leak_tab) 
+			iommu_leak_tab[iommu_page + i] = __builtin_return_address(0); 
+#endif
+	}
+	flush_gart(); 
+
+	bus = iommu_bus_base + iommu_page*PAGE_SIZE; 
+	return bus + ((unsigned long)addr & ~PAGE_MASK); 	
+} 
+
+/*
+ * Free a temporary PCI mapping.
+ */ 
+void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+		      size_t size, int direction)
+{
+	unsigned long iommu_page; 
+	int i, npages;
+	if (dma_addr < iommu_bus_base + EMERGENCY_PAGES*PAGE_SIZE || 
+	    dma_addr > iommu_bus_base + iommu_size)
+		return;
+	iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT;	
+	npages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT;
+	for (i = 0; i < npages; i++) { 
+		iommu_gatt_base[iommu_page + i] = 0; 
+#ifdef CONFIG_IOMMU_LEAK
+		if (iommu_leak_tab)
+			iommu_leak_tab[iommu_page + i] = 0; 
+#endif
+	}
+	flush_gart(); 
+	free_iommu(iommu_page, npages);
+}
+
+EXPORT_SYMBOL(pci_map_single);
+EXPORT_SYMBOL(pci_unmap_single);
+
+static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size)
+{ 
+	unsigned long a; 
+	if (!iommu_size) { 
+		iommu_size = aper_size; 
+		if (!no_agp) 
+			iommu_size /= 2; 
+	} 
+
+	a = aper + iommu_size; 
+	iommu_size -= round_up(a, LARGE_PAGE_SIZE) - a;
+
+	if (iommu_size < 64*1024*1024) 
+		printk(KERN_WARNING
+  "PCI-DMA: Warning: Small IOMMU %luMB. Consider increasing the AGP aperture in BIOS\n",iommu_size>>20); 
+	
+	return iommu_size;
+} 
+
+static __init unsigned read_aperture(struct pci_dev *dev, u32 *size) 
+{ 
+	unsigned aper_size = 0, aper_base_32;
+	u64 aper_base;
+	unsigned aper_order;
+
+	pci_read_config_dword(dev, 0x94, &aper_base_32); 
+	pci_read_config_dword(dev, 0x90, &aper_order);
+	aper_order = (aper_order >> 1) & 7;	
+
+	aper_base = aper_base_32 & 0x7fff; 
+	aper_base <<= 25;
+
+	aper_size = (32 * 1024 * 1024) << aper_order; 
+	if (aper_base + aper_size >= 0xffffffff || !aper_size)
+		aper_base = 0;
+
+	*size = aper_size;
+	return aper_base;
+} 
+
+/* 
+ * Private Northbridge GATT initialization in case we cannot use the
+ * AGP driver for some reason.  
+ */
+static __init int init_k8_gatt(agp_kern_info *info)
+{ 
+	struct pci_dev *dev;
+	void *gatt;
+	unsigned aper_base, new_aper_base;
+	unsigned aper_size, gatt_size, new_aper_size;
+
+	aper_size = aper_base = info->aper_size = 0;
+	for_all_nb(dev) { 
+		new_aper_base = read_aperture(dev, &new_aper_size); 
+		if (!new_aper_base) 
+	goto nommu; 
+
+		if (!aper_base) { 
+			aper_size = new_aper_size;
+			aper_base = new_aper_base;
+	}
+		if (aper_size != new_aper_size || aper_base != new_aper_base) 
+		goto nommu;
+	} 
+	if (!aper_base)
+		goto nommu; 
+	info->aper_base = aper_base;
+	info->aper_size = aper_size>>20; 
+
+	gatt_size = (aper_size >> PAGE_SHIFT) * sizeof(u32); 
+	gatt = (void *)__get_free_pages(GFP_KERNEL, get_order(gatt_size)); 
+	if (!gatt) 
+		panic("Cannot allocate GATT table"); 
+	memset(gatt, 0, gatt_size); 
+	change_page_attr(virt_to_page(gatt), gatt_size/PAGE_SIZE, PAGE_KERNEL_NOCACHE);
+	agp_gatt_table = gatt;
+
+	for_all_nb(dev) { 
+		u32 ctl; 
+		u32 gatt_reg; 
+
+		gatt_reg = ((u64)gatt) >> 12; 
+		gatt_reg <<= 4; 
+		pci_write_config_dword(dev, 0x98, gatt_reg);
+		pci_read_config_dword(dev, 0x90, &ctl); 
+
+		ctl |= 1;
+		ctl &= ~((1<<4) | (1<<5));
+
+		pci_write_config_dword(dev, 0x90, ctl); 
+	}
+	flush_gart(); 
+	
+		
+	printk("PCI-DMA: aperture base @ %x size %u KB\n", aper_base, aper_size>>10); 
+		return 0;
+
+ nommu:
+	/* XXX: reject 0xffffffff mask now in pci mapping functions */
+		printk(KERN_ERR "PCI-DMA: More than 4GB of RAM and no IOMMU\n"
+	       KERN_ERR "PCI-DMA: 32bit PCI IO may malfunction."); 
+	return -1; 
+} 
+
+void __init pci_iommu_init(void)
+{ 
+	agp_kern_info info;
+	unsigned long aper_size;
+	unsigned long iommu_start;
+
+#ifndef CONFIG_AGP
+	no_agp = 1; 
+#else
+	no_agp = no_agp || (agp_init() < 0) || (agp_copy_info(&info) < 0); 
+#endif	
+
+	if (no_iommu || (!force_mmu && end_pfn < 0xffffffff>>PAGE_SHIFT)) { 
+		printk(KERN_INFO "PCI-DMA: Disabling IOMMU.\n"); 
+		no_iommu = 1;
+		return;
+	}
+
+	if (no_agp) { 
+		int err = -1;
+		printk(KERN_INFO "PCI-DMA: Disabling AGP.\n");
+		no_agp = 1;
+		if (force_mmu || end_pfn >= 0xffffffff>>PAGE_SHIFT)
+			err = init_k8_gatt(&info);
+		if (err < 0) { 
+			printk(KERN_INFO "PCI-DMA: Disabling IOMMU.\n"); 
+			no_iommu = 1;
+			return; 
+		}
+	} 
+	
+	aper_size = info.aper_size * 1024 * 1024;
+	iommu_size = check_iommu_size(info.aper_base, aper_size); 
+	iommu_pages = iommu_size >> PAGE_SHIFT; 
+
+	iommu_gart_bitmap = (void*)__get_free_pages(GFP_KERNEL, 
+						    get_order(iommu_pages/8)); 
+	if (!iommu_gart_bitmap) 
+		panic("Cannot allocate iommu bitmap\n"); 
+	memset(iommu_gart_bitmap, 0, iommu_pages/8);
+
+#ifdef CONFIG_IOMMU_LEAK
+	if (leak_trace) { 
+		iommu_leak_tab = (void *)__get_free_pages(GFP_KERNEL, 
+				  get_order(iommu_pages*sizeof(void *)));
+		if (iommu_leak_tab) 
+			memset(iommu_leak_tab, 0, iommu_pages * 8); 
+		else
+			printk("PCI-DMA: Cannot allocate leak trace area\n"); 
+	} 
+#endif
+
+	/* 
+	 * Out of IOMMU space handling.
+	 * Reserve some invalid pages at the beginning of the GART. 
+	 */ 
+	set_bit_string(iommu_gart_bitmap, 0, EMERGENCY_PAGES); 
+
+	agp_memory_reserved = iommu_size;	
+	printk(KERN_INFO"PCI-DMA: Reserving %luMB of IOMMU area in the AGP aperture\n",
+	       iommu_size>>20); 
+
+	iommu_start = aper_size - iommu_size;	
+	iommu_bus_base = info.aper_base + iommu_start; 
+	iommu_gatt_base = agp_gatt_table + (iommu_start>>PAGE_SHIFT);
+	bad_dma_address = iommu_bus_base;
+
+	asm volatile("wbinvd" ::: "memory");
+} 
+
+/* iommu=[size][,noagp][,off][,force][,noforce][,leak][,memaper[=order]]
+   size  set size of iommu (in bytes) 
+   noagp don't initialize the AGP driver and use full aperture.
+   off   don't use the IOMMU
+   leak  turn on simple iommu leak tracing (only when CONFIG_IOMMU_LEAK is on)
+   memaper[=order] allocate an own aperture over RAM with size 32MB^order.
+*/
+__init int iommu_setup(char *opt) 
+{ 
+    int arg;
+    char *p = opt;
+    
+    for (;;) { 
+	    if (!memcmp(p,"noagp", 5))
+		    no_agp = 1; 
+	    if (!memcmp(p,"off", 3))
+		    no_iommu = 1;
+	    if (!memcmp(p,"force", 5))
+		    force_mmu = 1;
+	    if (!memcmp(p,"noforce", 7))
+		    force_mmu = 0;
+	    if (!memcmp(p, "memaper", 7)) { 
+		    fallback_aper_force = 1; 
+		    p += 7; 
+		    if (*p == '=' && get_option(&p, &arg))
+			    fallback_aper_order = arg;
+	    } 
+#ifdef CONFIG_IOMMU_LEAK
+	    if (!memcmp(p,"leak", 4))
+		    leak_trace = 1;
+#endif
+	    if (isdigit(*p) && get_option(&p, &arg)) 
+		    iommu_size = arg;
+	    do {
+		    if (*p == ' ' || *p == 0) 
+			    return 0; 
+	    } while (*p++ != ','); 
+    }	
+    return 1;
+} 
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/pci-irq.c linux-2.4.20/arch/x86_64/kernel/pci-irq.c
--- linux-2.4.19/arch/x86_64/kernel/pci-irq.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/pci-irq.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,757 @@
+/*
+ *	Low-Level PCI Support for PC -- Routing of Interrupts
+ *
+ *	(c) 1999--2000 Martin Mares <mj@ucw.cz>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/io_apic.h>
+
+#include "pci-x86_64.h"
+
+#define PIRQ_SIGNATURE	(('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
+#define PIRQ_VERSION 0x0100
+
+static struct irq_routing_table *pirq_table;
+
+/*
+ * Never use: 0, 1, 2 (timer, keyboard, and cascade)
+ * Avoid using: 13, 14 and 15 (FP error and IDE).
+ * Penalize: 3, 4, 6, 7, 12 (known ISA uses: serial, floppy, parallel and mouse)
+ */
+unsigned int pcibios_irq_mask = 0xfff8;
+
+static int pirq_penalty[16] = {
+	1000000, 1000000, 1000000, 1000, 1000, 0, 1000, 1000,
+	0, 0, 0, 0, 1000, 100000, 100000, 100000
+};
+
+struct irq_router {
+	char *name;
+	u16 vendor, device;
+	int (*get)(struct pci_dev *router, struct pci_dev *dev, int pirq);
+	int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new);
+};
+
+/*
+ *  Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
+ */
+
+static struct irq_routing_table * __init pirq_find_routing_table(void)
+{
+	u8 *addr;
+	struct irq_routing_table *rt;
+	int i;
+	u8 sum;
+
+	for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {
+		rt = (struct irq_routing_table *) addr;
+		if (rt->signature != PIRQ_SIGNATURE ||
+		    rt->version != PIRQ_VERSION ||
+		    rt->size % 16 ||
+		    rt->size < sizeof(struct irq_routing_table))
+			continue;
+		sum = 0;
+		for(i=0; i<rt->size; i++)
+			sum += addr[i];
+		if (!sum) {
+			DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt);
+			return rt;
+		}
+	}
+	return NULL;
+}
+
+/*
+ *  If we have a IRQ routing table, use it to search for peer host
+ *  bridges.  It's a gross hack, but since there are no other known
+ *  ways how to get a list of buses, we have to go this way.
+ *
+ *  [maybe x86-64 architecture should define way to query this info in
+ more reasonable way?]
+ */
+
+static void __init pirq_peer_trick(void)
+{
+	struct irq_routing_table *rt = pirq_table;
+	u8 busmap[256];
+	int i;
+	struct irq_info *e;
+
+	memset(busmap, 0, sizeof(busmap));
+	for(i=0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) {
+		e = &rt->slots[i];
+#ifdef DEBUG
+		{
+			int j;
+			DBG("%02x:%02x slot=%02x", e->bus, e->devfn/8, e->slot);
+			for(j=0; j<4; j++)
+				DBG(" %d:%02x/%04x", j, e->irq[j].link, e->irq[j].bitmap);
+			DBG("\n");
+		}
+#endif
+		busmap[e->bus] = 1;
+	}
+	for(i=1; i<256; i++)
+		/*
+		 *  It might be a secondary bus, but in this case its parent is already
+		 *  known (ascending bus order) and therefore pci_scan_bus returns immediately.
+		 */
+		if (busmap[i] && pci_scan_bus(i, pci_root_bus->ops, NULL))
+			printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i);
+	pcibios_last_bus = -1;
+}
+
+/*
+ *  Code for querying and setting of IRQ routes on various interrupt routers.
+ */
+
+static void eisa_set_level_irq(unsigned int irq)
+{
+	unsigned char mask = 1 << (irq & 7);
+	unsigned int port = 0x4d0 + (irq >> 3);
+	unsigned char val = inb(port);
+
+	if (!(val & mask)) {
+		DBG(" -> edge");
+		outb(val | mask, port);
+	}
+}
+
+/*
+ * Common IRQ routing practice: nybbles in config space,
+ * offset by some magic constant.
+ */
+static unsigned int read_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr)
+{
+	u8 x;
+	unsigned reg = offset + (nr >> 1);
+
+	pci_read_config_byte(router, reg, &x);
+	return (nr & 1) ? (x >> 4) : (x & 0xf);
+}
+
+static void write_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr, unsigned int val)
+{
+	u8 x;
+	unsigned reg = offset + (nr >> 1);
+
+	pci_read_config_byte(router, reg, &x);
+	x = (nr & 1) ? ((x & 0x0f) | (val << 4)) : ((x & 0xf0) | val);
+	pci_write_config_byte(router, reg, x);
+}
+
+/*
+ * ALI pirq entries are damn ugly, and completely undocumented.
+ * This has been figured out from pirq tables, and it's not a pretty
+ * picture.
+ */
+static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	static unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
+
+	return irqmap[read_config_nybble(router, 0x48, pirq-1)];
+}
+
+static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	static unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
+	unsigned int val = irqmap[irq];
+		
+	if (val) {
+		write_config_nybble(router, 0x48, pirq-1, val);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * The Intel PIIX4 pirq rules are fairly simple: "pirq" is
+ * just a pointer to the config space.
+ */
+static int pirq_piix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	u8 x;
+
+	pci_read_config_byte(router, pirq, &x);
+	return (x < 16) ? x : 0;
+}
+
+static int pirq_piix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	pci_write_config_byte(router, pirq, irq);
+	return 1;
+}
+
+/*
+ * The VIA pirq rules are nibble-based, like ALI,
+ * but without the ugly irq number munging.
+ */
+static int pirq_via_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	return read_config_nybble(router, 0x55, pirq);
+}
+
+static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	write_config_nybble(router, 0x55, pirq, irq);
+	return 1;
+}
+
+/*
+ * OPTI: high four bits are nibble pointer..
+ * I wonder what the low bits do?
+ */
+static int pirq_opti_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	return read_config_nybble(router, 0xb8, pirq >> 4);
+}
+
+static int pirq_opti_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	write_config_nybble(router, 0xb8, pirq >> 4, irq);
+	return 1;
+}
+
+/*
+ * Cyrix: nibble offset 0x5C
+ */
+static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	return read_config_nybble(router, 0x5C, pirq-1);
+}
+
+static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	write_config_nybble(router, 0x5C, pirq-1, irq);
+	return 1;
+}
+
+/*
+ *	PIRQ routing for SiS 85C503 router used in several SiS chipsets
+ *	According to the SiS 5595 datasheet (preliminary V1.0, 12/24/1997)
+ *	the related registers work as follows:
+ *	
+ *	general: one byte per re-routable IRQ,
+ *		 bit 7      IRQ mapping enabled (0) or disabled (1)
+ *		 bits [6:4] reserved
+ *		 bits [3:0] IRQ to map to
+ *		     allowed: 3-7, 9-12, 14-15
+ *		     reserved: 0, 1, 2, 8, 13
+ *
+ *	individual registers in device config space:
+ *
+ *	0x41/0x42/0x43/0x44:	PCI INT A/B/C/D - bits as in general case
+ *
+ *	0x61:			IDEIRQ: bits as in general case - but:
+ *				bits [6:5] must be written 01
+ *				bit 4 channel-select primary (0), secondary (1)
+ *
+ *	0x62:			USBIRQ: bits as in general case - but:
+ *				bit 4 OHCI function disabled (0), enabled (1)
+ *	
+ *	0x6a:			ACPI/SCI IRQ - bits as in general case
+ *
+ *	0x7e:			Data Acq. Module IRQ - bits as in general case
+ *
+ *	Apparently there are systems implementing PCI routing table using both
+ *	link values 0x01-0x04 and 0x41-0x44 for PCI INTA..D, but register offsets
+ *	like 0x62 as link values for USBIRQ e.g. So there is no simple
+ *	"register = offset + pirq" relation.
+ *	Currently we support PCI INTA..D and USBIRQ and try our best to handle
+ *	both link mappings.
+ *	IDE/ACPI/DAQ mapping is currently unsupported (left untouched as set by BIOS).
+ */
+
+static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	u8 x;
+	int reg = pirq;
+
+	switch(pirq) {
+		case 0x01:
+		case 0x02:
+		case 0x03:
+		case 0x04:
+			reg += 0x40;
+		case 0x41:
+		case 0x42:
+		case 0x43:
+		case 0x44:
+		case 0x62:
+	pci_read_config_byte(router, reg, &x);
+			if (reg != 0x62)
+				break;
+			if (!(x & 0x40))
+				return 0;
+			break;
+		case 0x61:
+		case 0x6a:
+		case 0x7e:
+			printk(KERN_INFO "SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n");
+			return 0;
+		default:			
+			printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
+			return 0;
+	}
+	return (x & 0x80) ? 0 : (x & 0x0f);
+}
+
+static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	u8 x;
+	int reg = pirq;
+
+	switch(pirq) {
+		case 0x01:
+		case 0x02:
+		case 0x03:
+		case 0x04:
+			reg += 0x40;
+		case 0x41:
+		case 0x42:
+		case 0x43:
+		case 0x44:
+		case 0x62:
+			x = (irq&0x0f) ? (irq&0x0f) : 0x80;
+			if (reg != 0x62)
+				break;
+			/* always mark OHCI enabled, as nothing else knows about this */
+			x |= 0x40;
+			break;
+		case 0x61:
+		case 0x6a:
+		case 0x7e:
+			printk(KERN_INFO "advanced SiS pirq mapping not yet implemented\n");
+			return 0;
+		default:			
+			printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
+			return 0;
+	}
+	pci_write_config_byte(router, reg, x);
+
+	return 1;
+}
+
+/*
+ * VLSI: nibble offset 0x74 - educated guess due to routing table and
+ *       config space of VLSI 82C534 PCI-bridge/router (1004:0102)
+ *       Tested on HP OmniBook 800 covering PIRQ 1, 2, 4, 8 for onboard
+ *       devices, PIRQ 3 for non-pci(!) soundchip and (untested) PIRQ 6
+ *       for the busbridge to the docking station.
+ */
+
+static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	if (pirq > 8) {
+		printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
+		return 0;
+	}
+	return read_config_nybble(router, 0x74, pirq-1);
+}
+
+static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	if (pirq > 8) {
+		printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
+		return 0;
+	}
+	write_config_nybble(router, 0x74, pirq-1, irq);
+	return 1;
+}
+
+/*
+ * ServerWorks: PCI interrupts mapped to system IRQ lines through Index
+ * and Redirect I/O registers (0x0c00 and 0x0c01).  The Index register
+ * format is (PCIIRQ## | 0x10), e.g.: PCIIRQ10=0x1a.  The Redirect
+ * register is a straight binary coding of desired PIC IRQ (low nibble).
+ *
+ * The 'link' value in the PIRQ table is already in the correct format
+ * for the Index register.  There are some special index values:
+ * 0x00 for ACPI (SCI), 0x01 for USB, 0x02 for IDE0, 0x04 for IDE1,
+ * and 0x03 for SMBus.
+ */
+static int pirq_serverworks_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	outb_p(pirq, 0xc00);
+	return inb(0xc01) & 0xf;
+}
+
+static int pirq_serverworks_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	outb_p(pirq, 0xc00);
+	outb_p(irq, 0xc01);
+	return 1;
+}
+
+/* Support for AMD756 PCI IRQ Routing
+ * Jhon H. Caicedo <jhcaiced@osso.org.co>
+ * Jun/21/2001 0.2.0 Release, fixed to use "nybble" functions... (jhcaiced)
+ * Jun/19/2001 Alpha Release 0.1.0 (jhcaiced)
+ * The AMD756 pirq rules are nibble-based
+ * offset 0x56 0-3 PIRQA  4-7  PIRQB
+ * offset 0x57 0-3 PIRQC  4-7  PIRQD
+ */
+static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	u8 irq;
+	irq = 0;
+	if (pirq <= 4)
+	{
+		irq = read_config_nybble(router, 0x56, pirq - 1);
+	}
+	printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n",
+		dev->vendor, dev->device, pirq, irq);
+	return irq;
+}
+
+static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n", 
+		dev->vendor, dev->device, pirq, irq);
+	if (pirq <= 4)
+	{
+		write_config_nybble(router, 0x56, pirq - 1, irq);
+	}
+	return 1;
+}
+
+#ifdef CONFIG_PCI_BIOS
+
+static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	struct pci_dev *bridge;
+	int pin = pci_get_interrupt_pin(dev, &bridge);
+	return pcibios_set_irq_routing(bridge, pin, irq);
+}
+
+static struct irq_router pirq_bios_router =
+	{ "BIOS", 0, 0, NULL, pirq_bios_set };
+
+#endif
+
+static struct irq_router pirq_routers[] = {
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX,   pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, pirq_piix_get, pirq_piix_set },
+
+	{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
+
+	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set },
+	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set },
+	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, pirq_via_get, pirq_via_set },
+
+	{ "OPTI", PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C700, pirq_opti_get, pirq_opti_set },
+
+	{ "NatSemi", PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, pirq_cyrix_get, pirq_cyrix_set },
+	{ "SIS", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, pirq_sis_get, pirq_sis_set },
+	{ "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set },
+	{ "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4,
+	  pirq_serverworks_get, pirq_serverworks_set },
+	{ "AMD756 VIPER", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B,
+		pirq_amd756_get, pirq_amd756_set },
+	{ "AMD766", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413,
+		pirq_amd756_get, pirq_amd756_set },
+	{ "AMD768", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7443,
+		pirq_amd756_get, pirq_amd756_set },
+
+	{ "default", 0, 0, NULL, NULL }
+};
+
+static struct irq_router *pirq_router;
+static struct pci_dev *pirq_router_dev;
+
+static void __init pirq_find_router(void)
+{
+	struct irq_routing_table *rt = pirq_table;
+	struct irq_router *r;
+
+#ifdef CONFIG_PCI_BIOS
+	if (!rt->signature) {
+		printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n");
+		pirq_router = &pirq_bios_router;
+		return;
+	}
+#endif
+
+	DBG("PCI: Attempting to find IRQ router for %04x:%04x\n",
+	    rt->rtr_vendor, rt->rtr_device);
+
+	/* fall back to default router if nothing else found */
+	pirq_router = &pirq_routers[ARRAY_SIZE(pirq_routers) - 1];
+
+	pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn);
+	if (!pirq_router_dev) {
+		DBG("PCI: Interrupt router not found at %02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
+		return;
+	}
+
+	for(r=pirq_routers; r->vendor; r++) {
+		/* Exact match against router table entry? Use it! */
+		if (r->vendor == rt->rtr_vendor && r->device == rt->rtr_device) {
+			pirq_router = r;
+			break;
+		}
+		/* Match against router device entry? Use it as a fallback */
+		if (r->vendor == pirq_router_dev->vendor && r->device == pirq_router_dev->device) {
+	pirq_router = r;
+		}
+	}
+	printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n",
+		pirq_router->name,
+		pirq_router_dev->vendor,
+		pirq_router_dev->device,
+		pirq_router_dev->slot_name);
+}
+
+static struct irq_info *pirq_get_info(struct pci_dev *dev)
+{
+	struct irq_routing_table *rt = pirq_table;
+	int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
+	struct irq_info *info;
+
+	for (info = rt->slots; entries--; info++)
+		if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn))
+			return info;
+	return NULL;
+}
+
+static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
+{
+	u8 pin;
+	struct irq_info *info;
+	int i, pirq, newirq;
+	int irq = 0;
+	u32 mask;
+	struct irq_router *r = pirq_router;
+	struct pci_dev *dev2;
+	char *msg = NULL;
+
+	if (!pirq_table)
+		return 0;
+
+	/* Find IRQ routing entry */
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+	if (!pin) {
+		DBG(" -> no interrupt pin\n");
+		return 0;
+	}
+	pin = pin - 1;
+	
+	DBG("IRQ for %s:%d", dev->slot_name, pin);
+	info = pirq_get_info(dev);
+	if (!info) {
+		DBG(" -> not found in routing table\n");
+		return 0;
+	}
+	pirq = info->irq[pin].link;
+	mask = info->irq[pin].bitmap;
+	if (!pirq) {
+		DBG(" -> not routed\n");
+		return 0;
+	}
+	DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
+	mask &= pcibios_irq_mask;
+
+	/*
+	 * Find the best IRQ to assign: use the one
+	 * reported by the device if possible.
+	 */
+	newirq = dev->irq;
+	if (!newirq && assign) {
+		for (i = 0; i < 16; i++) {
+			if (!(mask & (1 << i)))
+				continue;
+			if (pirq_penalty[i] < pirq_penalty[newirq] &&
+			    !request_irq(i, pcibios_test_irq_handler, SA_SHIRQ, "pci-test", dev)) {
+				free_irq(i, dev);
+				newirq = i;
+			}
+		}
+	}
+	DBG(" -> newirq=%d", newirq);
+
+	/* Check if it is hardcoded */
+	if ((pirq & 0xf0) == 0xf0) {
+		irq = pirq & 0xf;
+		DBG(" -> hardcoded IRQ %d\n", irq);
+		msg = "Hardcoded";
+	} else if (r->get && (irq = r->get(pirq_router_dev, dev, pirq))) {
+		DBG(" -> got IRQ %d\n", irq);
+		msg = "Found";
+	} else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
+		DBG(" -> assigning IRQ %d", newirq);
+		if (r->set(pirq_router_dev, dev, pirq, newirq)) {
+			eisa_set_level_irq(newirq);
+			DBG(" ... OK\n");
+			msg = "Assigned";
+			irq = newirq;
+		}
+	}
+
+	if (!irq) {
+		DBG(" ... failed\n");
+		if (newirq && mask == (1 << newirq)) {
+			msg = "Guessed";
+			irq = newirq;
+		} else
+			return 0;
+	}
+	printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name);
+
+	/* Update IRQ for all devices with the same pirq value */
+	pci_for_each_dev(dev2) {
+		pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin);
+		if (!pin)
+			continue;
+		pin--;
+		info = pirq_get_info(dev2);
+		if (!info)
+			continue;
+		if (info->irq[pin].link == pirq) {
+			/* We refuse to override the dev->irq information. Give a warning! */
+		    	if (dev2->irq && dev2->irq != irq) {
+		    		printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n",
+				       dev2->slot_name, dev2->irq, irq);
+		    		continue;
+		    	}
+			dev2->irq = irq;
+			pirq_penalty[irq]++;
+			if (dev != dev2)
+				printk(KERN_INFO "PCI: Sharing IRQ %d with %s\n", irq, dev2->slot_name);
+		}
+	}
+	return 1;
+}
+
+void __init pcibios_irq_init(void)
+{
+	DBG("PCI: IRQ init\n");
+	pirq_table = pirq_find_routing_table();
+#ifdef CONFIG_PCI_BIOS
+	if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
+		pirq_table = pcibios_get_irq_routing_table();
+#endif
+	if (pirq_table) {
+		pirq_peer_trick();
+		pirq_find_router();
+		if (pirq_table->exclusive_irqs) {
+			int i;
+			for (i=0; i<16; i++)
+				if (!(pirq_table->exclusive_irqs & (1 << i)))
+					pirq_penalty[i] += 100;
+		}
+		/* If we're using the I/O APIC, avoid using the PCI IRQ routing table */
+		if (io_apic_assign_pci_irqs)
+			pirq_table = NULL;
+	}
+}
+
+void __init pcibios_fixup_irqs(void)
+{
+	struct pci_dev *dev;
+	u8 pin;
+
+	DBG("PCI: IRQ fixup\n");
+	pci_for_each_dev(dev) {
+		/*
+		 * If the BIOS has set an out of range IRQ number, just ignore it.
+		 * Also keep track of which IRQ's are already in use.
+		 */
+		if (dev->irq >= 16) {
+			DBG("%s: ignoring bogus IRQ %d\n", dev->slot_name, dev->irq);
+			dev->irq = 0;
+		}
+		/* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */
+		if (pirq_penalty[dev->irq] >= 100 && pirq_penalty[dev->irq] < 100000)
+			pirq_penalty[dev->irq] = 0;
+		pirq_penalty[dev->irq]++;
+	}
+
+	pci_for_each_dev(dev) {
+		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+#ifdef CONFIG_X86_IO_APIC
+		/*
+		 * Recalculate IRQ numbers if we use the I/O APIC.
+		 */
+		if (io_apic_assign_pci_irqs)
+		{
+			int irq;
+
+			if (pin) {
+				pin--;		/* interrupt pins are numbered starting from 1 */
+				irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
+	/*
+	 * Busses behind bridges are typically not listed in the MP-table.
+	 * In this case we have to look up the IRQ based on the parent bus,
+	 * parent slot, and pin number. The SMP code detects such bridged
+	 * busses itself so we should get into this branch reliably.
+	 */
+				if (irq < 0 && dev->bus->parent) { /* go back to the bridge */
+					struct pci_dev * bridge = dev->bus->self;
+
+					pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+					irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, 
+							PCI_SLOT(bridge->devfn), pin);
+					if (irq >= 0)
+						printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", 
+							bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq);
+				}
+				if (irq >= 0) {
+					printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
+						dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
+					dev->irq = irq;
+				}
+			}
+		}
+#endif
+		/*
+		 * Still no IRQ? Try to lookup one...
+		 */
+		if (pin && !dev->irq)
+			pcibios_lookup_irq(dev, 0);
+	}
+}
+
+void pcibios_penalize_isa_irq(int irq)
+{
+	/*
+	 *  If any ISAPnP device reports an IRQ in its list of possible
+	 *  IRQ's, we try to avoid assigning it to PCI devices.
+	 */
+	pirq_penalty[irq] += 100;
+}
+
+void pcibios_enable_irq(struct pci_dev *dev)
+{
+		u8 pin;
+		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+	if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
+			char *msg;
+			if (io_apic_assign_pci_irqs)
+				msg = " Probably buggy MP table.";
+			else if (pci_probe & PCI_BIOS_IRQ_SCAN)
+				msg = "";
+			else
+				msg = " Please try using pci=biosirq.";
+			printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
+			       'A' + pin - 1, dev->slot_name, msg);
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/pci-nommu.c linux-2.4.20/arch/x86_64/kernel/pci-nommu.c
--- linux-2.4.19/arch/x86_64/kernel/pci-nommu.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/pci-nommu.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,48 @@
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+
+/* 
+ * Dummy IO MMU functions
+ */
+
+extern unsigned long end_pfn;
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+			   dma_addr_t *dma_handle)
+{
+	void *ret;
+	int gfp = GFP_ATOMIC;
+	
+	if (hwdev == NULL ||
+	    end_pfn > (hwdev->dma_mask>>PAGE_SHIFT) ||  /* XXX */
+	    (u32)hwdev->dma_mask < 0xffffffff)
+		gfp |= GFP_DMA;
+	ret = (void *)__get_free_pages(gfp, get_order(size));
+
+	if (ret != NULL) {
+		memset(ret, 0, size);
+		*dma_handle = virt_to_bus(ret);
+	}
+	return ret;
+}
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+			 void *vaddr, dma_addr_t dma_handle)
+{
+	free_pages((unsigned long)vaddr, get_order(size));
+}
+
+
+static void __init check_ram(void) 
+{ 
+	if (end_pfn >= 0xffffffff>>PAGE_SHIFT) { 
+		printk(KERN_ERR "WARNING more than 4GB of memory but no IOMMU.\n"
+		       KERN_ERR "WARNING 32bit PCI may malfunction.\n"); 
+		/* Could play with highmem_start_page here to trick some subsystems
+		   into bounce buffers. Unfortunately that would require setting
+		   CONFIG_HIGHMEM too. 
+		 */ 
+	} 
+} 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/pci-pc.c linux-2.4.20/arch/x86_64/kernel/pci-pc.c
--- linux-2.4.19/arch/x86_64/kernel/pci-pc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/pci-pc.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,474 @@
+/*
+ *	Low-Level PCI Support for PC
+ *
+ *	(c) 1999--2000 Martin Mares <mj@ucw.cz>
+ * 	2001 Andi Kleen. Cleanup for x86-64. Removed PCI-BIOS access and fixups
+ *	for hardware that is unlikely to exist on any Hammer platform.
+ * 
+ * 	On x86-64 we don't have any access to the PCI-BIOS in long mode, so we
+ *	cannot sort the pci device table based on what the BIOS did. This might 
+ *	change the probing order of some devices compared to an i386 kernel.
+ * 	May need to use ACPI to fix this.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/mpspec.h>
+
+#include "pci-x86_64.h"
+
+unsigned int pci_probe = PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
+
+int pcibios_last_bus = -1;
+struct pci_bus *pci_root_bus;
+struct pci_ops *pci_root_ops;
+
+/*
+ * Direct access to PCI hardware...
+ */
+
+#ifdef CONFIG_PCI_DIRECT
+
+/*
+ * Functions for accessing PCI configuration space with type 1 accesses
+ */
+
+#define CONFIG_CMD(dev, where)   (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
+
+static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	*value = inb(0xCFC + (where&3));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);    
+	*value = inw(0xCFC + (where&2));
+	return PCIBIOS_SUCCESSFUL;    
+}
+
+static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	*value = inl(0xCFC);
+	return PCIBIOS_SUCCESSFUL;    
+}
+
+static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);    
+	outb(value, 0xCFC + (where&3));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	outw(value, 0xCFC + (where&2));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	outl(value, 0xCFC);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+#undef CONFIG_CMD
+
+static struct pci_ops pci_direct_conf1 = {
+	pci_conf1_read_config_byte,
+	pci_conf1_read_config_word,
+	pci_conf1_read_config_dword,
+	pci_conf1_write_config_byte,
+	pci_conf1_write_config_word,
+	pci_conf1_write_config_dword
+};
+
+/*
+ * Functions for accessing PCI configuration space with type 2 accesses
+ */
+
+#define IOADDR(devfn, where)	((0xC000 | ((devfn & 0x78) << 5)) + where)
+#define FUNC(devfn)		(((devfn & 7) << 1) | 0xf0)
+#define SET(dev)		if (dev->devfn & 0x80) return PCIBIOS_DEVICE_NOT_FOUND;		\
+				outb(FUNC(dev->devfn), 0xCF8);					\
+				outb(dev->bus->number, 0xCFA);
+
+static int pci_conf2_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	SET(dev);
+	*value = inb(IOADDR(dev->devfn,where));
+	outb (0, 0xCF8);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf2_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	SET(dev);
+	*value = inw(IOADDR(dev->devfn,where));
+	outb (0, 0xCF8);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf2_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	SET(dev);
+	*value = inl (IOADDR(dev->devfn,where));    
+	outb (0, 0xCF8);    
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf2_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	SET(dev);
+	outb (value, IOADDR(dev->devfn,where));
+	outb (0, 0xCF8);    
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf2_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	SET(dev);
+	outw (value, IOADDR(dev->devfn,where));
+	outb (0, 0xCF8);    
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf2_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	SET(dev);
+	outl (value, IOADDR(dev->devfn,where));    
+	outb (0, 0xCF8);    
+	return PCIBIOS_SUCCESSFUL;
+}
+
+#undef SET
+#undef IOADDR
+#undef FUNC
+
+static struct pci_ops pci_direct_conf2 = {
+	pci_conf2_read_config_byte,
+	pci_conf2_read_config_word,
+	pci_conf2_read_config_dword,
+	pci_conf2_write_config_byte,
+	pci_conf2_write_config_word,
+	pci_conf2_write_config_dword
+};
+
+/*
+ * Before we decide to use direct hardware access mechanisms, we try to do some
+ * trivial checks to ensure it at least _seems_ to be working -- we just test
+ * whether bus 00 contains a host bridge (this is similar to checking
+ * techniques used in XFree86, but ours should be more reliable since we
+ * attempt to make use of direct access hints provided by the PCI BIOS).
+ *
+ * This should be close to trivial, but it isn't, because there are buggy
+ * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
+ */
+static int __devinit pci_sanity_check(struct pci_ops *o)
+{
+	u16 x;
+	struct pci_bus bus;		/* Fake bus and device */
+	struct pci_dev dev;
+
+	if (pci_probe & PCI_NO_CHECKS)
+		return 1;
+	bus.number = 0;
+	dev.bus = &bus;
+	for(dev.devfn=0; dev.devfn < 0x100; dev.devfn++)
+		if ((!o->read_word(&dev, PCI_CLASS_DEVICE, &x) &&
+		     (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) ||
+		    (!o->read_word(&dev, PCI_VENDOR_ID, &x) &&
+		     (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ)))
+			return 1;
+	DBG("PCI: Sanity check failed\n");
+	return 0;
+}
+
+static struct pci_ops * __devinit pci_check_direct(void)
+{
+	unsigned int tmp;
+	unsigned long flags;
+
+	__save_flags(flags); __cli();
+
+	/*
+	 * Check if configuration type 1 works.
+	 */
+	if (pci_probe & PCI_PROBE_CONF1) {
+		outb (0x01, 0xCFB);
+		tmp = inl (0xCF8);
+		outl (0x80000000, 0xCF8);
+		if (inl (0xCF8) == 0x80000000 &&
+		    pci_sanity_check(&pci_direct_conf1)) {
+			outl (tmp, 0xCF8);
+			__restore_flags(flags);
+			printk(KERN_INFO "PCI: Using configuration type 1\n");
+			request_region(0xCF8, 8, "PCI conf1");
+			return &pci_direct_conf1;
+		}
+		outl (tmp, 0xCF8);
+	}
+
+	/*
+	 * Check if configuration type 2 works.
+	 */
+	if (pci_probe & PCI_PROBE_CONF2) {
+		outb (0x00, 0xCFB);
+		outb (0x00, 0xCF8);
+		outb (0x00, 0xCFA);
+		if (inb (0xCF8) == 0x00 && inb (0xCFA) == 0x00 &&
+		    pci_sanity_check(&pci_direct_conf2)) {
+			__restore_flags(flags);
+			printk(KERN_INFO "PCI: Using configuration type 2\n");
+			request_region(0xCF8, 4, "PCI conf2");
+			return &pci_direct_conf2;
+		}
+	}
+
+	__restore_flags(flags);
+	return NULL;
+}
+
+#endif
+
+
+/*
+ * Several buggy motherboards address only 16 devices and mirror
+ * them to next 16 IDs. We try to detect this `feature' on all
+ * primary buses (those containing host bridges as they are
+ * expected to be unique) and remove the ghost devices.
+ */
+
+static void __devinit pcibios_fixup_ghosts(struct pci_bus *b)
+{
+	struct list_head *ln, *mn;
+	struct pci_dev *d, *e;
+	int mirror = PCI_DEVFN(16,0);
+	int seen_host_bridge = 0;
+	int i;
+
+	DBG("PCI: Scanning for ghost devices on bus %d\n", b->number);
+	for (ln=b->devices.next; ln != &b->devices; ln=ln->next) {
+		d = pci_dev_b(ln);
+		if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
+			seen_host_bridge++;
+		for (mn=ln->next; mn != &b->devices; mn=mn->next) {
+			e = pci_dev_b(mn);
+			if (e->devfn != d->devfn + mirror ||
+			    e->vendor != d->vendor ||
+			    e->device != d->device ||
+			    e->class != d->class)
+				continue;
+			for(i=0; i<PCI_NUM_RESOURCES; i++)
+				if (e->resource[i].start != d->resource[i].start ||
+				    e->resource[i].end != d->resource[i].end ||
+				    e->resource[i].flags != d->resource[i].flags)
+					continue;
+			break;
+		}
+		if (mn == &b->devices)
+			return;
+	}
+	if (!seen_host_bridge)
+		return;
+	printk(KERN_INFO "PCI: Ignoring ghost devices on bus %02x\n", b->number);
+
+	ln = &b->devices;
+	while (ln->next != &b->devices) {
+		d = pci_dev_b(ln->next);
+		if (d->devfn >= mirror) {
+			list_del(&d->global_list);
+			list_del(&d->bus_list);
+			kfree(d);
+		} else
+			ln = ln->next;
+	}
+}
+
+/*
+ * Discover remaining PCI buses in case there are peer host bridges.
+ */
+static void __devinit pcibios_fixup_peer_bridges(void)
+{
+	int n;
+	struct pci_bus bus;
+	struct pci_dev dev;
+	u16 l;
+
+	if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff)
+		return;
+	DBG("PCI: Peer bridge fixup\n");
+	for (n=0; n <= pcibios_last_bus; n++) {
+		if (pci_bus_exists(&pci_root_buses, n))
+			continue;
+		bus.number = n;
+		bus.ops = pci_root_ops;
+		dev.bus = &bus;
+		for(dev.devfn=0; dev.devfn<256; dev.devfn += 8)
+			if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) &&
+			    l != 0x0000 && l != 0xffff) {
+				DBG("Found device at %02x:%02x [%04x]\n", n, dev.devfn, l);
+				printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
+				pci_scan_bus(n, pci_root_ops, NULL);
+				break;
+			}
+	}
+}
+
+static void __devinit pci_scan_mptable(void)
+{ 
+	int i; 
+
+	/* Handle ACPI here */
+	if (!smp_found_config) { 
+		printk(KERN_WARNING "PCI: Warning: no mptable. Scanning busses upto 0xff\n"); 
+		pcibios_last_bus = 0xff; 
+		return;
+	} 
+
+	pcibios_last_bus = 0xff;
+
+	for (i = 0; i < MAX_MP_BUSSES; i++) {
+		int n = mp_bus_id_to_pci_bus[i]; 
+		if (n < 0 || n >= 0xff)
+			continue; 
+		if (pci_bus_exists(&pci_root_buses, n))
+			continue;
+		printk(KERN_INFO "PCI: Scanning bus %02x from mptable\n", n); 
+		pci_scan_bus(n, pci_root_ops, NULL); 
+	} 			
+} 
+
+static void __devinit pci_fixup_ide_bases(struct pci_dev *d)
+{
+	int i;
+
+	/*
+	 * PCI IDE controllers use non-standard I/O port decoding, respect it.
+	 */
+	if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+		return;
+	DBG("PCI: IDE base address fixup for %s\n", d->slot_name);
+	for(i=0; i<4; i++) {
+		struct resource *r = &d->resource[i];
+		if ((r->start & ~0x80) == 0x374) {
+			r->start |= 2;
+			r->end = r->start;
+		}
+	}
+}
+
+struct pci_fixup pcibios_fixups[] = {
+	{ PCI_FIXUP_HEADER, PCI_ANY_ID,	PCI_ANY_ID, pci_fixup_ide_bases },
+	{ 0 }
+};
+
+/*
+ *  Called after each bus is probed, but before its children
+ *  are examined.
+ */
+
+void __devinit pcibios_fixup_bus(struct pci_bus *b)
+{
+	pcibios_fixup_ghosts(b);
+	pci_read_bridge_bases(b);
+}
+
+void __devinit pcibios_init(void)
+{
+	struct pci_ops *dir = NULL;
+
+#ifdef CONFIG_PCI_DIRECT
+	if (pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2))
+		dir = pci_check_direct();
+#endif
+	if (dir)
+		pci_root_ops = dir;
+	else {
+		printk(KERN_INFO "PCI: No PCI bus detected\n");
+		return;
+	}
+
+	printk(KERN_INFO "PCI: Probing PCI hardware\n");
+	pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL);
+	
+	pcibios_irq_init();
+	pci_scan_mptable(); 
+	pcibios_fixup_peer_bridges();
+	pcibios_fixup_irqs();
+	pcibios_resource_survey();
+
+#ifdef CONFIG_GART_IOMMU
+	pci_iommu_init();
+#endif
+}
+
+char * __devinit pcibios_setup(char *str)
+{
+	if (!strcmp(str, "off")) {
+		pci_probe = 0;
+		return NULL;
+	}
+	else if (!strncmp(str, "bios", 4)) {
+		printk(KERN_WARNING "PCI: No PCI bios access on x86-64. BIOS hint ignored.\n");
+		return NULL;
+	} else if (!strcmp(str, "nobios")) {
+		pci_probe &= ~PCI_PROBE_BIOS;
+		return NULL;
+	} else if (!strcmp(str, "nosort")) { /* Default */ 
+		pci_probe |= PCI_NO_SORT;
+		return NULL;
+	} 
+#ifdef CONFIG_PCI_DIRECT
+	else if (!strcmp(str, "conf1")) {
+		pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS;
+		return NULL;
+	}
+	else if (!strcmp(str, "conf2")) {
+		pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS;
+		return NULL;
+	}
+#endif
+	else if (!strcmp(str, "rom")) {
+		pci_probe |= PCI_ASSIGN_ROMS;
+		return NULL;
+	} else if (!strcmp(str, "assign-busses")) {
+		pci_probe |= PCI_ASSIGN_ALL_BUSSES;
+		return NULL;
+	} else if (!strncmp(str, "irqmask=", 8)) {
+		pcibios_irq_mask = simple_strtol(str+8, NULL, 0);
+		return NULL;
+	} else if (!strncmp(str, "lastbus=", 8)) {
+		pcibios_last_bus = simple_strtol(str+8, NULL, 0);
+		return NULL;
+	}
+	return str;
+}
+
+unsigned int pcibios_assign_all_busses(void)
+{
+	return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
+}
+
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+	int err;
+
+	if ((err = pcibios_enable_resources(dev, mask)) < 0)
+		return err;
+	pcibios_enable_irq(dev);
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/pci-x86_64.c linux-2.4.20/arch/x86_64/kernel/pci-x86_64.c
--- linux-2.4.19/arch/x86_64/kernel/pci-x86_64.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/pci-x86_64.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,387 @@
+/*
+ *	Low-Level PCI Access for x86-64 machines
+ *
+ * Copyright 1993, 1994 Drew Eckhardt
+ *      Visionary Computing
+ *      (Unix and Linux consulting and custom programming)
+ *      Drew@Colorado.EDU
+ *      +1 (303) 786-7975
+ *
+ * Drew's work was sponsored by:
+ *	iX Multiuser Multitasking Magazine
+ *	Hannover, Germany
+ *	hm@ix.de
+ *
+ * Copyright 1997--2000 Martin Mares <mj@ucw.cz>
+ *
+ * For more information, please consult the following manuals (look at
+ * http://www.pcisig.com/ for how to get them):
+ *
+ * PCI BIOS Specification
+ * PCI Local Bus Specification
+ * PCI to PCI Bridge Specification
+ * PCI System Design Guide
+ *
+ *
+ * CHANGELOG :
+ * Jun 17, 1994 : Modified to accommodate the broken pre-PCI BIOS SPECIFICATION
+ *	Revision 2.0 present on <thys@dennis.ee.up.ac.za>'s ASUS mainboard.
+ *
+ * Jan 5,  1995 : Modified to probe PCI hardware at boot time by Frederic
+ *     Potter, potter@cao-vlsi.ibp.fr
+ *
+ * Jan 10, 1995 : Modified to store the information about configured pci
+ *      devices into a list, which can be accessed via /proc/pci by
+ *      Curtis Varner, cvarner@cs.ucr.edu
+ *
+ * Jan 12, 1995 : CPU-PCI bridge optimization support by Frederic Potter.
+ *	Alpha version. Intel & UMC chipset support only.
+ *
+ * Apr 16, 1995 : Source merge with the DEC Alpha PCI support. Most of the code
+ *	moved to drivers/pci/pci.c.
+ *
+ * Dec 7, 1996  : Added support for direct configuration access of boards
+ *      with Intel compatible access schemes (tsbogend@alpha.franken.de)
+ *
+ * Feb 3, 1997  : Set internal functions to static, save/restore flags
+ *	avoid dead locks reading broken PCI BIOS, werner@suse.de 
+ *
+ * Apr 26, 1997 : Fixed case when there is BIOS32, but not PCI BIOS
+ *	(mj@atrey.karlin.mff.cuni.cz)
+ *
+ * May 7,  1997 : Added some missing cli()'s. [mj]
+ * 
+ * Jun 20, 1997 : Corrected problems in "conf1" type accesses.
+ *      (paubert@iram.es)
+ *
+ * Aug 2,  1997 : Split to PCI BIOS handling and direct PCI access parts
+ *	and cleaned it up...     Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * Feb 6,  1998 : No longer using BIOS to find devices and device classes. [mj]
+ *
+ * May 1,  1998 : Support for peer host bridges. [mj]
+ *
+ * Jun 19, 1998 : Changed to use spinlocks, so that PCI configuration space
+ *	can be accessed from interrupts even on SMP systems. [mj]
+ *
+ * August  1998 : Better support for peer host bridges and more paranoid
+ *	checks for direct hardware access. Ugh, this file starts to look as
+ *	a large gallery of common hardware bug workarounds (watch the comments)
+ *	-- the PCI specs themselves are sane, but most implementors should be
+ *	hit hard with \hammer scaled \magstep5. [mj]
+ *
+ * Jan 23, 1999 : More improvements to peer host bridge logic. i450NX fixup. [mj]
+ *
+ * Feb 8,  1999 : Added UM8886BF I/O address fixup. [mj]
+ *
+ * August  1999 : New resource management and configuration access stuff. [mj]
+ *
+ * Sep 19, 1999 : Use PCI IRQ routing tables for detection of peer host bridges.
+ *		  Based on ideas by Chris Frantz and David Hinds. [mj]
+ *
+ * Sep 28, 1999 : Handle unreported/unassigned IRQs. Thanks to Shuu Yamaguchi
+ *		  for a lot of patience during testing. [mj]
+ *
+ * Oct  8, 1999 : Split to pci-i386.c, pci-pc.c and pci-visws.c. [mj]
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+
+#include "pci-x86_64.h"
+
+void
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+			struct resource *res, int resource)
+{
+	u32 new, check;
+	int reg;
+
+	new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
+	if (resource < 6) {
+		reg = PCI_BASE_ADDRESS_0 + 4*resource;
+	} else if (resource == PCI_ROM_RESOURCE) {
+		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+		new |= PCI_ROM_ADDRESS_ENABLE;
+		reg = dev->rom_base_reg;
+	} else {
+		/* Somebody might have asked allocation of a non-standard resource */
+		return;
+	}
+	
+	pci_write_config_dword(dev, reg, new);
+	pci_read_config_dword(dev, reg, &check);
+	if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
+		printk(KERN_ERR "PCI: Error while updating region "
+		       "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
+		       new, check);
+	}
+}
+
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ *
+ * Why? Because some silly external IO cards only decode
+ * the low 10 bits of the IO address. The 0x00-0xff region
+ * is reserved for motherboard devices that decode all 16
+ * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
+ * but we want to try to avoid allocating at 0x2900-0x2bff
+ * which might have be mirrored at 0x0100-0x03ff..
+ */
+void
+pcibios_align_resource(void *data, struct resource *res, unsigned long size,
+		       unsigned long align)
+{
+	if (res->flags & IORESOURCE_IO) {
+		unsigned long start = res->start;
+
+		if (start & 0x300) {
+			start = (start + 0x3ff) & ~0x3ff;
+			res->start = start;
+		}
+	}
+}
+
+
+/*
+ *  Handle resources of PCI devices.  If the world were perfect, we could
+ *  just allocate all the resource regions and do nothing more.  It isn't.
+ *  On the other hand, we cannot just re-allocate all devices, as it would
+ *  require us to know lots of host bridge internals.  So we attempt to
+ *  keep as much of the original configuration as possible, but tweak it
+ *  when it's found to be wrong.
+ *
+ *  Known BIOS problems we have to work around:
+ *	- I/O or memory regions not configured
+ *	- regions configured, but not enabled in the command register
+ *	- bogus I/O addresses above 64K used
+ *	- expansion ROMs left enabled (this may sound harmless, but given
+ *	  the fact the PCI specs explicitly allow address decoders to be
+ *	  shared between expansion ROMs and other resource regions, it's
+ *	  at least dangerous)
+ *
+ *  Our solution:
+ *	(1) Allocate resources for all buses behind PCI-to-PCI bridges.
+ *	    This gives us fixed barriers on where we can allocate.
+ *	(2) Allocate resources for all enabled devices.  If there is
+ *	    a collision, just mark the resource as unallocated. Also
+ *	    disable expansion ROMs during this step.
+ *	(3) Try to allocate resources for disabled devices.  If the
+ *	    resources were assigned correctly, everything goes well,
+ *	    if they weren't, they won't disturb allocation of other
+ *	    resources.
+ *	(4) Assign new addresses to resources which were either
+ *	    not configured at all or misconfigured.  If explicitly
+ *	    requested by the user, configure expansion ROM address
+ *	    as well.
+ */
+
+static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
+{
+	struct list_head *ln;
+	struct pci_bus *bus;
+	struct pci_dev *dev;
+	int idx;
+	struct resource *r, *pr;
+
+	/* Depth-First Search on bus tree */
+	for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
+		bus = pci_bus_b(ln);
+		if ((dev = bus->self)) {
+			for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
+				r = &dev->resource[idx];
+				if (!r->start)
+					continue;
+				pr = pci_find_parent_resource(dev, r);
+				if (!pr || request_resource(pr, r) < 0)
+					printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
+			}
+		}
+		pcibios_allocate_bus_resources(&bus->children);
+	}
+}
+
+static void __init pcibios_allocate_resources(int pass)
+{
+	struct pci_dev *dev;
+	int idx, disabled;
+	u16 command;
+	struct resource *r, *pr;
+
+	pci_for_each_dev(dev) {
+		pci_read_config_word(dev, PCI_COMMAND, &command);
+		for(idx = 0; idx < 6; idx++) {
+			r = &dev->resource[idx];
+			if (r->parent)		/* Already allocated */
+				continue;
+			if (!r->start)		/* Address not assigned at all */
+				continue;
+			if (r->flags & IORESOURCE_IO)
+				disabled = !(command & PCI_COMMAND_IO);
+			else
+				disabled = !(command & PCI_COMMAND_MEMORY);
+			if (pass == disabled) {
+				DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
+				    r->start, r->end, r->flags, disabled, pass);
+				pr = pci_find_parent_resource(dev, r);
+				if (!pr || request_resource(pr, r) < 0) {
+					printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name);
+					/* We'll assign a new address later */
+					r->end -= r->start;
+					r->start = 0;
+				}
+			}
+		}
+		if (!pass) {
+			r = &dev->resource[PCI_ROM_RESOURCE];
+			if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
+				/* Turn the ROM off, leave the resource region, but keep it unregistered. */
+				u32 reg;
+				DBG("PCI: Switching off ROM of %s\n", dev->slot_name);
+				r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
+				pci_read_config_dword(dev, dev->rom_base_reg, &reg);
+				pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
+			}
+		}
+	}
+}
+
+static void __init pcibios_assign_resources(void)
+{
+	struct pci_dev *dev;
+	int idx;
+	struct resource *r;
+
+	pci_for_each_dev(dev) {
+		int class = dev->class >> 8;
+
+		/* Don't touch classless devices and host bridges */
+		if (!class || class == PCI_CLASS_BRIDGE_HOST)
+			continue;
+
+		for(idx=0; idx<6; idx++) {
+			r = &dev->resource[idx];
+
+			/*
+			 *  Don't touch IDE controllers and I/O ports of video cards!
+			 */
+			if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
+			    (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
+				continue;
+
+			/*
+			 *  We shall assign a new address to this resource, either because
+			 *  the BIOS forgot to do so or because we have decided the old
+			 *  address was unusable for some reason.
+			 */
+			if (!r->start && r->end)
+				pci_assign_resource(dev, idx);
+		}
+
+		if (pci_probe & PCI_ASSIGN_ROMS) {
+			r = &dev->resource[PCI_ROM_RESOURCE];
+			r->end -= r->start;
+			r->start = 0;
+			if (r->end)
+				pci_assign_resource(dev, PCI_ROM_RESOURCE);
+		}
+	}
+}
+
+void __init pcibios_resource_survey(void)
+{
+	DBG("PCI: Allocating resources\n");
+	pcibios_allocate_bus_resources(&pci_root_buses);
+	pcibios_allocate_resources(0);
+	pcibios_allocate_resources(1);
+	pcibios_assign_resources();
+}
+
+int pcibios_enable_resources(struct pci_dev *dev, int mask)
+{
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for(idx=0; idx<6; idx++) {
+		if (!(mask & (1<<idx)))
+			continue;
+		r = &dev->resource[idx];
+		if (!r->start && r->end) {
+			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (dev->resource[PCI_ROM_RESOURCE].start)
+		cmd |= PCI_COMMAND_MEMORY;
+	if (cmd != old_cmd) {
+		printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	return 0;
+}
+
+/*
+ *  If we set up a device for bus mastering, we need to check the latency
+ *  timer as certain crappy BIOSes forget to set it properly.
+ */
+unsigned int pcibios_max_latency = 255;
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+	u8 lat;
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+	if (lat < 16)
+		lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+	else if (lat > pcibios_max_latency)
+		lat = pcibios_max_latency;
+	else
+		return;
+	printk("PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
+
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+			enum pci_mmap_state mmap_state, int write_combine)
+{
+	unsigned long prot;
+
+	/* I/O space cannot be accessed via normal processor loads and
+	 * stores on this platform.
+	 */
+	if (mmap_state == pci_mmap_io)
+		return -EINVAL;
+
+	/* Leave vm_pgoff as-is, the PCI space address is the physical
+	 * address on this platform.
+	 */
+	vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
+
+	prot = pgprot_val(vma->vm_page_prot);
+	if (boot_cpu_data.x86 > 3)
+		prot |= _PAGE_PCD | _PAGE_PWT;
+	vma->vm_page_prot = __pgprot(prot);
+
+	/* Write-combine setting is ignored, it is changed via the mtrr
+	 * interfaces on this platform.
+	 */
+	if (remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
+			     vma->vm_end - vma->vm_start,
+			     vma->vm_page_prot))
+		return -EAGAIN;
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/pci-x86_64.h linux-2.4.20/arch/x86_64/kernel/pci-x86_64.h
--- linux-2.4.19/arch/x86_64/kernel/pci-x86_64.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/pci-x86_64.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,74 @@
+/*
+ *	Low-Level PCI Access for i386 machines.
+ *
+ *	(c) 1999 Martin Mares <mj@ucw.cz>
+ */
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#define PCI_PROBE_BIOS		0x0001
+#define PCI_PROBE_CONF1		0x0002
+#define PCI_PROBE_CONF2		0x0004
+#define PCI_NO_SORT		0x0100
+#define PCI_BIOS_SORT		0x0200
+#define PCI_NO_CHECKS		0x0400
+#define PCI_ASSIGN_ROMS		0x1000
+#define PCI_BIOS_IRQ_SCAN	0x2000
+#define PCI_ASSIGN_ALL_BUSSES	0x4000
+
+extern unsigned int pci_probe;
+
+/* pci-i386.c */
+
+extern unsigned int pcibios_max_latency;
+
+void pcibios_resource_survey(void);
+int pcibios_enable_resources(struct pci_dev *, int);
+
+/* pci-pc.c */
+
+extern int pcibios_last_bus;
+extern struct pci_bus *pci_root_bus;
+extern struct pci_ops *pci_root_ops;
+
+struct irq_routing_table *pcibios_get_irq_routing_table(void);
+int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
+
+/* pci-irq.c */
+
+struct irq_info {
+	u8 bus, devfn;			/* Bus, device and function */
+	struct {
+		u8 link;		/* IRQ line ID, chipset dependent, 0=not routed */
+		u16 bitmap;		/* Available IRQs */
+	} __attribute__((packed)) irq[4];
+	u8 slot;			/* Slot number, 0=onboard */
+	u8 rfu;
+} __attribute__((packed));
+
+struct irq_routing_table {
+	u32 signature;			/* PIRQ_SIGNATURE should be here */
+	u16 version;			/* PIRQ_VERSION */
+	u16 size;			/* Table size in bytes */
+	u8 rtr_bus, rtr_devfn;		/* Where the interrupt router lies */
+	u16 exclusive_irqs;		/* IRQs devoted exclusively to PCI usage */
+	u16 rtr_vendor, rtr_device;	/* Vendor and device ID of interrupt router */
+	u32 miniport_data;		/* Crap */
+	u8 rfu[11];
+	u8 checksum;			/* Modulo 256 checksum must give zero */
+	struct irq_info slots[0];
+} __attribute__((packed));
+
+extern unsigned int pcibios_irq_mask;
+
+void pcibios_irq_init(void);
+void pcibios_fixup_irqs(void);
+void pcibios_enable_irq(struct pci_dev *dev);
+
+void pci_iommu_init(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/process.c linux-2.4.20/arch/x86_64/kernel/process.c
--- linux-2.4.19/arch/x86_64/kernel/process.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/process.c	2002-10-29 11:18:38.000000000 +0000
@@ -0,0 +1,729 @@
+/*
+ *  linux/arch/x86-64/kernel/process.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *
+ *  Pentium III FXSR, SSE support
+ *	Gareth Hughes <gareth@valinux.com>, May 2000
+ * 
+ *  X86-64 port
+ *	Andi Kleen.
+ * 
+ *  $Id: process.c,v 1.57 2002/09/12 12:56:36 ak Exp $
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#define __KERNEL_SYSCALLS__
+#include <stdarg.h>
+
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/ldt.h>
+#include <asm/processor.h>
+#include <asm/i387.h>
+#include <asm/desc.h>
+#include <asm/mmu_context.h>
+#include <asm/pda.h>
+#include <asm/prctl.h>
+#include <asm/kdebug.h>
+#include <asm/proto.h>
+
+#include <linux/irq.h>
+
+asmlinkage extern void ret_from_fork(void);
+
+int hlt_counter;
+
+/*
+ * Powermanagement idle function, if any..
+ */
+void (*pm_idle)(void);
+
+/*
+ * Power off function, if any
+ */
+void (*pm_power_off)(void);
+
+void disable_hlt(void)
+{
+	hlt_counter++;
+}
+
+void enable_hlt(void)
+{
+	hlt_counter--;
+}
+
+/*
+ * We use this if we don't have any better
+ * idle routine..
+ */
+static void default_idle(void)
+{
+	if (!hlt_counter) {
+		__cli();
+		if (!current->need_resched)
+			safe_halt();
+		else
+			__sti();
+	}
+}
+
+/*
+ * On SMP it's slightly faster (but much more power-consuming!)
+ * to poll the ->need_resched flag instead of waiting for the
+ * cross-CPU IPI to arrive. Use this option with caution.
+ */
+static void poll_idle (void)
+{
+	int oldval;
+
+	__sti();
+
+	/*
+	 * Deal with another CPU just having chosen a thread to
+	 * run here:
+	 */
+	oldval = xchg(&current->need_resched, -1);
+
+	if (!oldval)
+		asm volatile(
+			"2:"
+			"cmpl $-1, %0;"
+			"rep; nop;"
+			"je 2b;"
+				: :"m" (current->need_resched));
+}
+
+/*
+ * The idle thread. There's no useful work to be
+ * done, so just try to conserve power and have a
+ * low exit latency (ie sit in a loop waiting for
+ * somebody to say that they'd like to reschedule)
+ */
+void cpu_idle (void)
+{
+	/* endless idle loop with no priority at all */
+	init_idle();
+	current->nice = 20;
+	current->counter = -100;
+
+	while (1) {
+		void (*idle)(void) = pm_idle;
+		if (!idle)
+			idle = default_idle;
+		while (!current->need_resched)
+			idle();
+		schedule();
+		check_pgt_cache();
+	}
+}
+
+static int __init idle_setup (char *str)
+{
+	if (!strncmp(str, "poll", 4)) {
+		printk("using polling idle threads.\n");
+		pm_idle = poll_idle;
+	}
+
+	return 1;
+}
+
+__setup("idle=", idle_setup);
+
+static long no_idt[3];
+static int reboot_mode;
+
+#ifdef CONFIG_SMP
+int reboot_smp = 0;
+static int reboot_cpu = -1;
+#endif
+static int __init reboot_setup(char *str)
+{
+	while(1) {
+		switch (*str) {
+		case 'w': /* "warm" reboot (no memory testing etc) */
+			reboot_mode = 0x1234;
+			break;
+		case 'c': /* "cold" reboot (with memory testing etc) */
+			reboot_mode = 0x0;
+			break;
+#ifdef CONFIG_SMP
+		case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
+			reboot_smp = 1;
+			if (isdigit(str[1]))
+				sscanf(str+1, "%d", &reboot_cpu);		
+			else if (!strncmp(str,"smp",3))
+				sscanf(str+3, "%d", &reboot_cpu); 
+			/* we will leave sorting out the final value 
+			   when we are ready to reboot, since we might not
+ 			   have set up boot_cpu_id or smp_num_cpu */
+			break;
+#endif
+		}
+		if((str = strchr(str,',')) != NULL)
+			str++;
+		else
+			break;
+	}
+	return 1;
+}
+
+__setup("reboot=", reboot_setup);
+
+static inline void kb_wait(void)
+{
+	int i;
+
+	for (i=0; i<0x10000; i++)
+		if ((inb_p(0x64) & 0x02) == 0)
+			break;
+}
+
+void machine_restart(char * __unused)
+{
+#if CONFIG_SMP
+	int cpuid;
+	
+	cpuid = GET_APIC_ID(apic_read(APIC_ID));
+
+	if (reboot_smp) {
+
+		/* check to see if reboot_cpu is valid 
+		   if its not, default to the BSP */
+		if ((reboot_cpu == -1) ||  
+		      (reboot_cpu > (NR_CPUS -1))  || 
+		      !(phys_cpu_present_map & (1<<cpuid))) 
+			reboot_cpu = boot_cpu_id;
+
+		reboot_smp = 0;  /* use this as a flag to only go through this once*/
+		/* re-run this function on the other CPUs
+		   it will fall though this section since we have 
+		   cleared reboot_smp, and do the reboot if it is the
+		   correct CPU, otherwise it halts. */
+		if (reboot_cpu != cpuid)
+			smp_call_function((void *)machine_restart , NULL, 1, 0);
+	}
+
+	/* if reboot_cpu is still -1, then we want a tradional reboot, 
+	   and if we are not running on the reboot_cpu,, halt */
+	if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {
+		for (;;)
+		__asm__ __volatile__ ("hlt");
+	}
+	/*
+	 * Stop all CPUs and turn off local APICs and the IO-APIC, so
+	 * other OSs see a clean IRQ state.
+	 */
+	if (notify_die(DIE_STOP,"cpustop",0,0) != NOTIFY_BAD)
+		smp_send_stop();
+	disable_IO_APIC();
+#endif
+	/* Could do reset through the northbridge of the Hammer here. */
+
+	/* rebooting needs to touch the page at absolute addr 0 */
+	*((unsigned short *)__va(0x472)) = reboot_mode;
+	for (;;) {
+		int i;
+		/* First fondle with the keyboard controller. */ 
+		for (i=0; i<100; i++) {
+			kb_wait();
+			udelay(50);
+			outb(0xfe,0x64);         /* pulse reset low */
+			udelay(50);
+		}
+		/* That didn't work - force a triple fault.. */
+		__asm__ __volatile__("lidt %0": :"m" (no_idt));
+		__asm__ __volatile__("int3");
+	}
+}
+
+void machine_halt(void)
+{
+}
+
+void machine_power_off(void)
+{
+	if (pm_power_off)
+		pm_power_off();
+}
+
+/* Prints also some state that isn't saved in the pt_regs */ 
+void show_regs(struct pt_regs * regs)
+{
+	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs;
+	unsigned int fsindex,gsindex;
+	unsigned int ds,cs,es; 
+
+	printk("\n");
+	printk("Pid: %d, comm: %.20s %s\n", current->pid, current->comm, print_tainted());
+	printk("RIP: %04lx:[<%016lx>]\n", regs->cs & 0xffff, regs->rip);
+	printk("RSP: %04lx:%016lx  EFLAGS: %08lx\n", regs->ss, regs->rsp, regs->eflags);
+	printk("RAX: %016lx RBX: %016lx RCX: %016lx\n",
+	       regs->rax, regs->rbx, regs->rcx);
+	printk("RDX: %016lx RSI: %016lx RDI: %016lx\n",
+	       regs->rdx, regs->rsi, regs->rdi); 
+	printk("RBP: %016lx R08: %016lx R09: %016lx\n",
+	       regs->rbp, regs->r8, regs->r9); 
+	printk("R10: %016lx R11: %016lx R12: %016lx\n",
+	       regs->r10, regs->r11, regs->r12); 
+	printk("R13: %016lx R14: %016lx R15: %016lx\n",
+	       regs->r13, regs->r14, regs->r15); 
+
+	asm("movl %%ds,%0" : "=r" (ds)); 
+	asm("movl %%cs,%0" : "=r" (cs)); 
+	asm("movl %%es,%0" : "=r" (es)); 
+	asm("movl %%fs,%0" : "=r" (fsindex));
+	asm("movl %%gs,%0" : "=r" (gsindex));
+
+	rdmsrl(MSR_FS_BASE, fs);
+	rdmsrl(MSR_GS_BASE, gs); 
+	rdmsrl(MSR_KERNEL_GS_BASE, shadowgs); 
+
+	asm("movq %%cr0, %0": "=r" (cr0));
+	asm("movq %%cr2, %0": "=r" (cr2));
+	asm("movq %%cr3, %0": "=r" (cr3));
+	asm("movq %%cr4, %0": "=r" (cr4));
+
+	printk("FS:  %016lx(%04x) GS:%016lx(%04x) knlGS:%016lx\n", 
+	       fs,fsindex,gs,gsindex,shadowgs); 
+	printk("CS:  %04x DS: %04x ES: %04x CR0: %016lx\n", cs, ds, es, cr0); 
+	printk("CR2: %016lx CR3: %016lx CR4: %016lx\n", cr2, cr3, cr4);
+}
+
+/*
+ * No need to lock the MM as we are the last user
+ */
+void release_segments(struct mm_struct *mm)
+{
+	void * ldt = mm->context.segments;
+
+	/*
+	 * free the LDT
+	 */
+	if (ldt) {
+		mm->context.segments = NULL;
+		clear_LDT();
+		vfree(ldt);
+	}
+}
+
+/* 
+ * Reloading %gs is a bit complicated because the kernel relies on it 
+ * This includes the exception handlers, so we cannot take any exceptions
+ * while doing this. Check the new gs value manually for validity and only
+ * then load it. This needs locking again parallel CPUs that share the same
+ * LDT. This has to be done in the context switch iff %gs changes.
+ */
+void load_gs_index(unsigned gs)
+{
+	struct mm_struct *mm = current->mm;
+	int access; 
+	/* paranoia: */
+	if ((gs & 3) != 2) gs = 0;
+	if (mm) 
+		read_lock(&mm->context.ldtlock); 
+	asm volatile("pushf\n\t" 
+		     "cli\n\t"
+		     "swapgs\n\t"
+		     /* cannot take any exception until the next swapgs */
+		     "lar %1,%0\n\t"
+		     "jnz 1f\n\t"
+		     "movl %1,%%eax\n\t"
+		     "movl %%eax,%%gs\n\t"
+		     "jmp 2f\n\t"
+		     "1: movl %2,%%gs\n\t"
+		     "2: swapgs\n\t"
+		     "popf" : "=g" (access) : "g" (gs), "r" (0) : "rax"); 
+	if (mm)
+		read_unlock(&mm->context.ldtlock);
+}
+	
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+	struct task_struct *me = current;
+	if (me->thread.io_bitmap_ptr) { 
+		(init_tss + smp_processor_id())->io_map_base = 
+			INVALID_IO_BITMAP_OFFSET;  
+		kfree(me->thread.io_bitmap_ptr); 
+		me->thread.io_bitmap_ptr = NULL; 		
+	} 
+}
+
+void flush_thread(void)
+{
+	struct task_struct *tsk = current;
+
+	memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
+	/*
+	 * Forget coprocessor state..
+	 */
+	clear_fpu(tsk);
+	tsk->used_math = 0;
+}
+
+void release_thread(struct task_struct *dead_task)
+{
+	if (dead_task->mm) {
+		void * ldt = dead_task->mm->context.segments;
+
+		// temporary debugging check
+		if (ldt) {
+			printk("WARNING: dead process %8s still has LDT? <%p>\n",
+					dead_task->comm, ldt);
+			BUG();
+		}
+	}
+}
+
+/*
+ * we do not have to muck with descriptors here, that is
+ * done in switch_mm() as needed.
+ */
+void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
+{
+	struct mm_struct * old_mm;
+	void *old_ldt, *ldt;
+ 
+	ldt = NULL;
+	old_mm = current->mm;
+	if (old_mm && (old_ldt = old_mm->context.segments) != NULL) {
+		/*
+		 * Completely new LDT, we initialize it from the parent:
+		 */
+		ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
+		if (!ldt)
+			printk(KERN_WARNING "ldt allocation failed\n");
+		else
+			memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
+	}
+	new_mm->context.segments = ldt;
+	new_mm->context.cpuvalid = 0UL;
+	return;
+}
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp, 
+		unsigned long unused,
+	struct task_struct * p, struct pt_regs * regs)
+{
+	struct pt_regs * childregs;
+	struct task_struct *me = current;
+
+	childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p)) - 1;
+
+	*childregs = *regs;
+
+	childregs->rax = 0;
+	childregs->rsp = rsp;
+	if (rsp == ~0) {
+		childregs->rsp = (unsigned long)childregs;
+	}
+
+	p->thread.rsp = (unsigned long) childregs;
+	p->thread.rsp0 = (unsigned long) (childregs+1);
+	p->thread.userrsp = current->thread.userrsp; 
+
+	p->thread.rip = (unsigned long) ret_from_fork;
+
+	p->thread.fs = me->thread.fs;
+	p->thread.gs = me->thread.gs;
+
+	asm("movl %%gs,%0" : "=m" (p->thread.gsindex));
+	asm("movl %%fs,%0" : "=m" (p->thread.fsindex));
+	asm("movl %%es,%0" : "=m" (p->thread.es));
+	asm("movl %%ds,%0" : "=m" (p->thread.ds));
+
+	unlazy_fpu(current);	
+	p->thread.i387 = current->thread.i387;
+
+	if (unlikely(me->thread.io_bitmap_ptr != NULL)) { 
+		p->thread.io_bitmap_ptr = kmalloc((IO_BITMAP_SIZE+1)*4, GFP_KERNEL);
+		if (!p->thread.io_bitmap_ptr) 
+			return -ENOMEM;
+		memcpy(p->thread.io_bitmap_ptr, me->thread.io_bitmap_ptr, 
+		       (IO_BITMAP_SIZE+1)*4);
+	} 
+
+	return 0;
+}
+
+/*
+ * This special macro can be used to load a debugging register
+ */
+#define loaddebug(thread,register) \
+		set_debug(thread->debugreg[register], register)
+
+/*
+ *	switch_to(x,y) should switch tasks from x to y.
+ *
+ * We fsave/fwait so that an exception goes off at the right time
+ * (as a call from the fsave or fwait in effect) rather than to
+ * the wrong process. 
+ * 
+ * This could still be optimized: 
+ * - fold all the options into a flag word and test it with a single test.
+ * - could test fs/gs bitsliced
+ */
+struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct *next_p)
+{
+	struct thread_struct *prev = &prev_p->thread,
+				 *next = &next_p->thread;
+	struct tss_struct *tss = init_tss + smp_processor_id();
+
+	unlazy_fpu(prev_p);
+
+	/*
+	 * Reload rsp0, LDT and the page table pointer:
+	 */
+	tss->rsp0 = next->rsp0;
+
+	/* 
+	 * Switch DS and ES.	 
+	 */
+	asm volatile("movl %%es,%0" : "=m" (prev->es)); 
+	if (unlikely(next->es | prev->es))
+		loadsegment(es, next->es); 
+	
+	asm volatile ("movl %%ds,%0" : "=m" (prev->ds)); 
+	if (unlikely(next->ds | prev->ds))
+		loadsegment(ds, next->ds);
+
+	/* 
+	 * Switch FS and GS.
+	 * XXX Check if this is safe on SMP (!= -> |)
+	 */
+	{ 
+		unsigned int fsindex;
+
+		asm volatile("movl %%fs,%0" : "=g" (fsindex)); 
+		if (unlikely(fsindex != next->fsindex)) /* or likely? */
+			loadsegment(fs, next->fsindex);
+		if (unlikely(fsindex != prev->fsindex))
+			prev->fs = 0; 
+		if ((fsindex != prev->fsindex) || (prev->fs != next->fs))
+			wrmsrl(MSR_FS_BASE, next->fs); 
+		prev->fsindex = fsindex;
+	}
+	{
+		unsigned int gsindex;
+
+		asm volatile("movl %%gs,%0" : "=g" (gsindex)); 
+		if (unlikely(gsindex != next->gsindex))
+			load_gs_index(next->gs); 
+		if (unlikely(gsindex != prev->gsindex)) 
+			prev->gs = 0;				
+		if (gsindex != prev->gsindex || prev->gs != next->gs)
+			wrmsrl(MSR_KERNEL_GS_BASE, next->gs); 
+		prev->gsindex = gsindex;
+	}
+
+	/* 
+	 * Switch the PDA context.
+	 */
+	prev->userrsp = read_pda(oldrsp); 
+	write_pda(oldrsp, next->userrsp); 
+	write_pda(pcurrent, next_p); 
+	write_pda(kernelstack, (unsigned long)next_p + THREAD_SIZE - PDA_STACKOFFSET);
+
+	/*
+	 * Now maybe reload the debug registers
+	 */
+	if (unlikely(next->debugreg[7])) {
+		loaddebug(next, 0);
+		loaddebug(next, 1);
+		loaddebug(next, 2);
+		loaddebug(next, 3);
+		/* no 4 and 5 */
+		loaddebug(next, 6);
+		loaddebug(next, 7);
+	}
+
+
+	/* 
+	 * Handle the IO bitmap 
+	 */ 
+	if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) {
+		if (next->io_bitmap_ptr) {
+			/*
+			 * 4 cachelines copy ... not good, but not that
+			 * bad either. Anyone got something better?
+			 * This only affects processes which use ioperm().
+			 * [Putting the TSSs into 4k-tlb mapped regions
+			 * and playing VM tricks to switch the IO bitmap
+			 * is not really acceptable.]
+			 */
+			memcpy(tss->io_bitmap, next->io_bitmap_ptr,
+				 IO_BITMAP_SIZE*sizeof(u32));
+			tss->io_map_base = IO_BITMAP_OFFSET;
+		} else {
+			/*
+			 * a bitmap offset pointing outside of the TSS limit
+			 * causes a nicely controllable SIGSEGV if a process
+			 * tries to use a port IO instruction. The first
+			 * sys_ioperm() call sets up the bitmap properly.
+			 */
+			tss->io_map_base = INVALID_IO_BITMAP_OFFSET;
+		}
+	}
+
+
+	return prev_p;
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage 
+long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
+{
+	long error;
+	char * filename;
+
+	filename = getname(name);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename)) 
+		return error;
+	error = do_execve(filename, argv, envp, &regs); 
+	if (error == 0)
+		current->ptrace &= ~PT_DTRACE;
+	putname(filename);
+	return error;
+}
+
+void set_personality_64bit(void)
+{
+	/* inherit personality from parent */
+
+	/* Make sure to be in 64bit mode */
+	current->thread.flags = 0;
+}
+
+asmlinkage long sys_fork(struct pt_regs regs)
+{
+	return do_fork(SIGCHLD, regs.rsp, &regs, 0);
+}
+
+asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs regs)
+{
+	if (!newsp)
+		newsp = regs.rsp;
+	return do_fork(clone_flags, newsp, &regs, 0);
+}
+
+/*
+ * This is trivial, and on the face of it looks like it
+ * could equally well be done in user mode.
+ *
+ * Not so, for quite unobvious reasons - register pressure.
+ * In user mode vfork() cannot have a stack frame, and if
+ * done by calling the "clone()" system call directly, you
+ * do not have enough call-clobbered registers to hold all
+ * the information you need.
+ */
+asmlinkage long sys_vfork(struct pt_regs regs)
+{
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0);
+}
+
+/*
+ * These bracket the sleeping functions..
+ */
+extern void scheduling_functions_start_here(void);
+extern void scheduling_functions_end_here(void);
+#define first_sched	((unsigned long) scheduling_functions_start_here)
+#define last_sched	((unsigned long) scheduling_functions_end_here)
+
+unsigned long get_wchan(struct task_struct *p)
+{
+	u64 fp,rip;
+	int count = 0;
+
+	if (!p || p == current || p->state==TASK_RUNNING)
+		return 0; 
+	if (p->thread.rsp < (u64)p || p->thread.rsp > (u64)p + THREAD_SIZE)
+		return 0;
+	fp = *(u64 *)(p->thread.rsp);
+	do { 
+		if (fp < (unsigned long)p || fp > (unsigned long)p+THREAD_SIZE)
+			return 0; 
+		rip = *(u64 *)(fp+8); 
+		if (rip < first_sched || rip >= last_sched)
+			return rip; 
+		fp = *(u64 *)fp; 
+	} while (count++ < 16); 
+	return 0;
+}
+#undef last_sched
+#undef first_sched
+
+asmlinkage long sys_arch_prctl(int code, unsigned long addr)
+{ 
+	int ret = 0; 
+	unsigned long tmp; 
+
+	switch (code) { 
+	case ARCH_SET_GS:
+		if (addr >= TASK_SIZE) 
+			return -EPERM; 
+		asm volatile("movw %%gs,%0" : "=g" (current->thread.gsindex)); 
+		current->thread.gs = addr;
+		ret = checking_wrmsrl(MSR_KERNEL_GS_BASE, addr); 
+		break;
+	case ARCH_SET_FS:
+		/* Not strictly needed for fs, but do it for symmetry
+		   with gs */
+		if (addr >= TASK_SIZE)
+			return -EPERM; 
+		asm volatile("movw %%fs,%0" : "=g" (current->thread.fsindex)); 
+		current->thread.fs = addr;
+		ret = checking_wrmsrl(MSR_FS_BASE, addr); 
+		break;
+
+		/* Returned value may not be correct when the user changed fs/gs */ 
+	case ARCH_GET_FS:
+		rdmsrl(MSR_FS_BASE, tmp);
+		ret = put_user(tmp, (unsigned long *)addr); 
+		break; 
+
+	case ARCH_GET_GS: 
+		rdmsrl(MSR_KERNEL_GS_BASE, tmp); 
+		ret = put_user(tmp, (unsigned long *)addr); 
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	} 
+	return ret;	
+} 
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/ptrace.c linux-2.4.20/arch/x86_64/kernel/ptrace.c
--- linux-2.4.19/arch/x86_64/kernel/ptrace.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/ptrace.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,449 @@
+/* ptrace.c */
+/* By Ross Biro 1/23/92 */
+/*
+ * Pentium III FXSR, SSE support
+ *	Gareth Hughes <gareth@valinux.com>, May 2000
+ * 
+ * x86-64 port 2000-2002 Andi Kleen
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/i387.h>
+#include <asm/debugreg.h>
+
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/* determines which flags the user has access to. */
+/* 1 = access 0 = no access */
+#define FLAG_MASK 0x44dd5UL
+
+/* set's the trap flag. */
+#define TRAP_FLAG 0x100UL
+
+/*
+ * eflags and offset of eflags on child stack..
+ */
+#define EFLAGS offsetof(struct pt_regs, eflags)
+#define EFL_OFFSET ((int)(EFLAGS-sizeof(struct pt_regs)))
+
+/*
+ * this routine will get a word off of the processes privileged stack. 
+ * the offset is how far from the base addr as stored in the TSS.  
+ * this routine assumes that all the privileged stacks are in our
+ * data space.
+ */   
+static inline unsigned long get_stack_long(struct task_struct *task, int offset)
+{
+	unsigned char *stack;
+
+	stack = (unsigned char *)task->thread.rsp0;
+	stack += offset;
+	return (*((unsigned long *)stack));
+}
+
+/*
+ * this routine will put a word on the processes privileged stack. 
+ * the offset is how far from the base addr as stored in the TSS.  
+ * this routine assumes that all the privileged stacks are in our
+ * data space.
+ */
+static inline long put_stack_long(struct task_struct *task, int offset,
+	unsigned long data)
+{
+	unsigned char * stack;
+
+	stack = (unsigned char *) task->thread.rsp0;
+	stack += offset;
+	*(unsigned long *) stack = data;
+	return 0;
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure the single step bit is not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{ 
+	long tmp;
+
+	tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
+	put_stack_long(child, EFL_OFFSET, tmp);
+}
+
+static int putreg(struct task_struct *child,
+	unsigned long regno, unsigned long value)
+{
+	unsigned long tmp; 
+	switch (regno) {
+		case offsetof(struct user_regs_struct,fs):
+			if (value && (value & 3) != 3)
+				return -EIO;
+			child->thread.fsindex = value & 0xffff; 
+			return 0; 
+		case offsetof(struct user_regs_struct,gs):
+			if (value && (value & 3) != 3)
+				return -EIO;
+			child->thread.gsindex = value & 0xffff;
+			return 0;
+		case offsetof(struct user_regs_struct,ds):
+			if (value && (value & 3) != 3)
+				return -EIO;
+			child->thread.ds = value & 0xffff;
+			return 0;
+		case offsetof(struct user_regs_struct,es): 
+			if (value && (value & 3) != 3)
+				return -EIO;
+			child->thread.es = value & 0xffff;
+			return 0;
+		case offsetof(struct user_regs_struct,fs_base):
+			if (!((value >> 48) == 0 || (value >> 48) == 0xffff))
+				return -EIO; 
+			child->thread.fs = value;
+			return 0;
+		case offsetof(struct user_regs_struct,gs_base):
+			if (!((value >> 48) == 0 || (value >> 48) == 0xffff))
+				return -EIO; 
+			child->thread.gs = value;
+			return 0;
+		case offsetof(struct user_regs_struct, eflags):
+			value &= FLAG_MASK;
+			tmp = get_stack_long(child, EFL_OFFSET); 
+			tmp &= ~FLAG_MASK; 
+			value |= tmp;
+			break;
+		case offsetof(struct user_regs_struct,cs): 
+			if ((value & 3) != 3)
+				return -EIO;
+			value &= 0xffff;
+			break;
+		case offsetof(struct user_regs_struct,ss):
+			if ((value & 3) != 3)
+				return -EIO;
+			value &= 0xffff;
+            break;
+	}      
+	put_stack_long(child, regno - sizeof(struct pt_regs), value);
+	return 0;
+}
+
+static unsigned long getreg(struct task_struct *child, unsigned long regno)
+{
+	switch (regno) {
+		case offsetof(struct user_regs_struct, fs):
+			return child->thread.fsindex;
+		case offsetof(struct user_regs_struct, gs):
+			return child->thread.gsindex;
+		case offsetof(struct user_regs_struct, ds):
+			return child->thread.ds;
+		case offsetof(struct user_regs_struct, es):
+			return child->thread.es; 
+		case offsetof(struct user_regs_struct, fs_base):
+			return child->thread.fs;
+		case offsetof(struct user_regs_struct, gs_base):
+			return child->thread.gs;
+		default:
+			regno = regno - sizeof(struct pt_regs);
+			return get_stack_long(child, regno);
+	}
+
+}
+
+asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	struct user * dummy = NULL;
+	long i, ret;
+
+	/* This lock_kernel fixes a subtle race with suid exec */
+	lock_kernel();
+	ret = -EPERM;
+	if (request == PTRACE_TRACEME) {
+		/* are we already being traced? */
+		if (current->ptrace & PT_PTRACED)
+			goto out;
+		/* set the ptrace bit in the process flags. */
+		current->ptrace |= PT_PTRACED;
+		ret = 0;
+		goto out;
+	}
+	ret = -ESRCH;
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	if (child)
+		get_task_struct(child);
+	read_unlock(&tasklist_lock);
+	if (!child)
+		goto out;
+
+	ret = -EPERM;
+	if (pid == 1)		/* you may not mess with init */
+		goto out_tsk;
+
+	if (request == PTRACE_ATTACH) {
+		ret = ptrace_attach(child);
+		goto out_tsk;
+	}
+	ret = -ESRCH;
+	if (!(child->ptrace & PT_PTRACED))
+		goto out_tsk;
+	if (child->state != TASK_STOPPED) {
+		if (request != PTRACE_KILL)
+			goto out_tsk;
+	}
+	if (child->p_pptr != current)
+		goto out_tsk;
+	switch (request) {
+	/* when I and D space are separate, these will need to be fixed. */
+	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+	case PTRACE_PEEKDATA: {
+		unsigned long tmp;
+		int copied;
+
+		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+		ret = -EIO;
+		if (copied != sizeof(tmp))
+			break;
+		ret = put_user(tmp,(unsigned long *) data);
+		break;
+	}
+
+	/* read the word at location addr in the USER area. */
+	case PTRACE_PEEKUSR: {
+		unsigned long tmp;
+
+		ret = -EIO;
+		if ((addr & 3) || addr < 0 || 
+		    addr > sizeof(struct user) - 3)
+			break;
+
+		tmp = 0;  /* Default return condition */
+		if(addr < sizeof(struct user_regs_struct))
+			tmp = getreg(child, addr);
+		if(addr >= (long) &dummy->u_debugreg[0] &&
+		   addr <= (long) &dummy->u_debugreg[7]){
+			addr -= (long) &dummy->u_debugreg[0];
+			addr = addr >> 2;
+			tmp = child->thread.debugreg[addr];
+		}
+		ret = put_user(tmp,(unsigned long *) data);
+		break;
+	}
+
+	/* when I and D space are separate, this will have to be fixed. */
+	case PTRACE_POKETEXT: /* write the word at location addr. */
+	case PTRACE_POKEDATA:
+		ret = 0;
+		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+			break;
+		ret = -EIO;
+		break;
+
+	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+		ret = -EIO;
+		if ((addr & 3) || addr < 0 || 
+		    addr > sizeof(struct user) - 3)
+			break;
+
+		if (addr < sizeof(struct user_regs_struct)) {
+			ret = putreg(child, addr, data);
+			break;
+		}
+		/* We need to be very careful here.  We implicitly
+		   want to modify a portion of the task_struct, and we
+		   have to be selective about what portions we allow someone
+		   to modify. */
+
+		  ret = -EIO;
+		  if(addr >= (long) &dummy->u_debugreg[0] &&
+		     addr <= (long) &dummy->u_debugreg[7]){
+
+			  if(addr == (long) &dummy->u_debugreg[4]) break;
+			  if(addr == (long) &dummy->u_debugreg[5]) break;
+			  if(addr < (long) &dummy->u_debugreg[4] &&
+			     ((unsigned long) data) >= TASK_SIZE-3) break;
+			  
+			  if(addr == (long) &dummy->u_debugreg[7]) {
+				  data &= ~DR_CONTROL_RESERVED;
+				  for(i=0; i<4; i++)
+					  if ((0x5454 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
+						  goto out_tsk;
+			  }
+
+			  addr -= (long) &dummy->u_debugreg;
+			  addr = addr >> 2;
+			  child->thread.debugreg[addr] = data;
+			  ret = 0;
+		  }
+		  break;
+
+	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+	case PTRACE_CONT: { /* restart after signal. */
+		long tmp;
+
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		if (request == PTRACE_SYSCALL)
+			child->ptrace |= PT_TRACESYS;
+		else
+			child->ptrace &= ~PT_TRACESYS;
+		child->exit_code = data;
+	/* make sure the single step bit is not set. */
+		tmp = get_stack_long(child, EFL_OFFSET);
+		tmp &= ~TRAP_FLAG;
+		put_stack_long(child, EFL_OFFSET,tmp);
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
+
+/*
+ * make the child exit.  Best I can do is send it a sigkill. 
+ * perhaps it should be put in the status that it wants to 
+ * exit.
+ */
+	case PTRACE_KILL: {
+		long tmp;
+
+		ret = 0;
+		if (child->state == TASK_ZOMBIE)	/* already dead */
+			break;
+		child->exit_code = SIGKILL;
+		/* make sure the single step bit is not set. */
+		tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
+		put_stack_long(child, EFL_OFFSET, tmp);
+		wake_up_process(child);
+		break;
+	}
+
+	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
+		long tmp;
+
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		child->ptrace &= ~PT_TRACESYS;
+		if ((child->ptrace & PT_DTRACE) == 0) {
+			/* Spurious delayed TF traps may occur */
+			child->ptrace |= PT_DTRACE;
+		}
+		tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
+		put_stack_long(child, EFL_OFFSET, tmp);
+		child->exit_code = data;
+		/* give it a chance to run. */
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
+
+	case PTRACE_DETACH:
+		/* detach a process that was attached. */
+		ret = ptrace_detach(child, data);
+		break;
+
+	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
+	  	if (!access_ok(VERIFY_WRITE, (unsigned *)data, FRAME_SIZE)) {
+			ret = -EIO;
+			break;
+		}
+		for ( i = 0; i < sizeof(struct user_regs_struct); i += sizeof(long) ) {
+			__put_user(getreg(child, i),(unsigned long *) data);
+			data += sizeof(long);
+		}
+		ret = 0;
+		break;
+	}
+
+	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+		unsigned long tmp;
+	  	if (!access_ok(VERIFY_READ, (unsigned *)data, FRAME_SIZE)) {
+			ret = -EIO;
+			break;
+		}
+		for ( i = 0; i < sizeof(struct user_regs_struct); i += sizeof(long) ) {
+			__get_user(tmp, (unsigned long *) data);
+			putreg(child, i, tmp);
+			data += sizeof(long);
+		}
+		ret = 0;
+		break;
+	}
+
+	case PTRACE_GETFPREGS: { /* Get the child extended FPU state. */
+		if (!access_ok(VERIFY_WRITE, (unsigned *)data,
+			       sizeof(struct user_i387_struct))) {
+			ret = -EIO;
+			break;
+		}
+		ret = get_fpregs((struct user_i387_struct *)data, child);
+		break;
+	}
+
+	case PTRACE_SETFPREGS: { /* Set the child extended FPU state. */
+		if (!access_ok(VERIFY_READ, (unsigned *)data,
+			       sizeof(struct user_i387_struct))) {
+			ret = -EIO;
+			break;
+		}
+		child->used_math = 1;
+		ret = set_fpregs(child, (struct user_i387_struct *)data);
+		break;
+	}
+
+	case PTRACE_SETOPTIONS: {
+		if (data & PTRACE_O_TRACESYSGOOD)
+			child->ptrace |= PT_TRACESYSGOOD;
+		else
+			child->ptrace &= ~PT_TRACESYSGOOD;
+		ret = 0;
+		break;
+	}
+
+	default:
+		ret = -EIO;
+		break;
+	}
+out_tsk:
+	free_task_struct(child);
+out:
+	unlock_kernel();
+	return ret;
+}
+
+asmlinkage void syscall_trace(struct pt_regs *regs)
+{
+	if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) !=
+			(PT_PTRACED|PT_TRACESYS))
+		return;
+	
+	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+					? 0x80 : 0);
+	current->state = TASK_STOPPED;
+	notify_parent(current, SIGCHLD);
+	schedule();
+	/*
+	 * this isn't the same as continuing with a signal, but it will do
+	 * for normal use.  strace only continues with a signal if the
+	 * stopping signal is not SIGTRAP.  -brl
+	 */
+	if (current->exit_code) {
+		send_sig(current->exit_code, current, 1);
+		current->exit_code = 0;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/semaphore.c linux-2.4.20/arch/x86_64/kernel/semaphore.c
--- linux-2.4.19/arch/x86_64/kernel/semaphore.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/semaphore.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,170 @@
+/*
+ * x86_64 semaphore implementation.
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ *
+ * Portions Copyright 1999 Red Hat, 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.
+ *
+ * rw semaphores implemented November 1999 by Benjamin LaHaise <bcrl@redhat.com>
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+
+#include <asm/semaphore.h>
+
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to acquire the semaphore, while the "sleeping"
+ * variable is a count of such acquires.
+ *
+ * Notably, the inline "up()" and "down()" functions can
+ * efficiently test if they need to do any extra work (up
+ * needs to do something only if count was negative before
+ * the increment operation.
+ *
+ * "sleeping" and the contention routine ordering is
+ * protected by the semaphore spinlock.
+ *
+ * Note that these functions are only called when there is
+ * contention on the lock, and as such all this is the
+ * "non-critical" part of the whole semaphore business. The
+ * critical part is the inline stuff in <asm/semaphore.h>
+ * where we want to avoid any extra jumps and calls.
+ */
+
+/*
+ * Logic:
+ *  - only on a boundary condition do we need to care. When we go
+ *    from a negative count to a non-negative, we wake people up.
+ *  - when we go from a non-negative count to a negative do we
+ *    (a) synchronize with the "sleeper" count and (b) make sure
+ *    that we're on the wakeup list before we synchronize so that
+ *    we cannot lose wakeup events.
+ */
+
+void __up(struct semaphore *sem)
+{
+	wake_up(&sem->wait);
+}
+
+static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED;
+
+void __down(struct semaphore * sem)
+{
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+	tsk->state = TASK_UNINTERRUPTIBLE;
+	add_wait_queue_exclusive(&sem->wait, &wait);
+
+	spin_lock_irq(&semaphore_lock);
+	sem->sleepers++;
+	for (;;) {
+		int sleepers = sem->sleepers;
+
+		/*
+		 * Add "everybody else" into it. They aren't
+		 * playing, because we own the spinlock.
+		 */
+		if (!atomic_add_negative(sleepers - 1, &sem->count)) {
+			sem->sleepers = 0;
+			break;
+		}
+		sem->sleepers = 1;	/* us - see -1 above */
+		spin_unlock_irq(&semaphore_lock);
+
+		schedule();
+		tsk->state = TASK_UNINTERRUPTIBLE;
+		spin_lock_irq(&semaphore_lock);
+	}
+	spin_unlock_irq(&semaphore_lock);
+	remove_wait_queue(&sem->wait, &wait);
+	tsk->state = TASK_RUNNING;
+	wake_up(&sem->wait);
+}
+
+int __down_interruptible(struct semaphore * sem)
+{
+	int retval = 0;
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+	tsk->state = TASK_INTERRUPTIBLE;
+	add_wait_queue_exclusive(&sem->wait, &wait);
+
+	spin_lock_irq(&semaphore_lock);
+	sem->sleepers ++;
+	for (;;) {
+		int sleepers = sem->sleepers;
+
+		/*
+		 * With signals pending, this turns into
+		 * the trylock failure case - we won't be
+		 * sleeping, and we* can't get the lock as
+		 * it has contention. Just correct the count
+		 * and exit.
+		 */
+		if (signal_pending(current)) {
+			retval = -EINTR;
+			sem->sleepers = 0;
+			atomic_add(sleepers, &sem->count);
+			break;
+		}
+
+		/*
+		 * Add "everybody else" into it. They aren't
+		 * playing, because we own the spinlock. The
+		 * "-1" is because we're still hoping to get
+		 * the lock.
+		 */
+		if (!atomic_add_negative(sleepers - 1, &sem->count)) {
+			sem->sleepers = 0;
+			break;
+		}
+		sem->sleepers = 1;	/* us - see -1 above */
+		spin_unlock_irq(&semaphore_lock);
+
+		schedule();
+		tsk->state = TASK_INTERRUPTIBLE;
+		spin_lock_irq(&semaphore_lock);
+	}
+	spin_unlock_irq(&semaphore_lock);
+	tsk->state = TASK_RUNNING;
+	remove_wait_queue(&sem->wait, &wait);
+	wake_up(&sem->wait);
+	return retval;
+}
+
+/*
+ * Trylock failed - make sure we correct for
+ * having decremented the count.
+ *
+ * We could have done the trylock with a
+ * single "cmpxchg" without failure cases,
+ * but then it wouldn't work on a 386.
+ */
+int __down_trylock(struct semaphore * sem)
+{
+	int sleepers;
+	unsigned long flags;
+
+	spin_lock_irqsave(&semaphore_lock, flags);
+	sleepers = sem->sleepers + 1;
+	sem->sleepers = 0;
+
+	/*
+	 * Add "everybody else" and us into it. They aren't
+	 * playing, because we own the spinlock.
+	 */
+	if (!atomic_add_negative(sleepers, &sem->count))
+		wake_up(&sem->wait);
+
+	spin_unlock_irqrestore(&semaphore_lock, flags);
+	return 1;
+}
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/setup.c linux-2.4.20/arch/x86_64/kernel/setup.c
--- linux-2.4.19/arch/x86_64/kernel/setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/setup.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,686 @@
+/*
+ *  linux/arch/x86-64/kernel/setup.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *
+ *  Nov 2001 Dave Jones <davej@suse.de>
+ *  Forked from i386 setup code.
+ */
+
+/*
+ * This file handles the architecture-dependent parts of initialization
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/highmem.h>
+#include <linux/bootmem.h>
+#include <asm/processor.h>
+#include <linux/console.h>
+#include <linux/seq_file.h>
+#include <asm/mtrr.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/msr.h>
+#include <asm/desc.h>
+#include <asm/e820.h>
+#include <asm/dma.h>
+#include <asm/mpspec.h>
+#include <asm/mmu_context.h>
+#include <asm/bootsetup.h>
+#include <asm/proto.h>
+
+/*
+ * Machine setup..
+ */
+
+struct cpuinfo_x86 boot_cpu_data = { 
+	cpuid_level: -1, 
+};
+
+unsigned long mmu_cr4_features;
+
+/* For PCI or other memory-mapped resources */
+unsigned long pci_mem_start = 0x10000000;
+
+/*
+ * Setup options
+ */
+struct drive_info_struct { char dummy[32]; } drive_info;
+struct screen_info screen_info;
+struct sys_desc_table_struct {
+	unsigned short length;
+	unsigned char table[0];
+};
+
+struct e820map e820;
+
+unsigned char aux_device_present;
+
+extern int root_mountflags;
+extern char _text, _etext, _edata, _end;
+
+static int disable_x86_fxsr __initdata = 0;
+
+char command_line[COMMAND_LINE_SIZE];
+char saved_command_line[COMMAND_LINE_SIZE];
+
+struct resource standard_io_resources[] = {
+	{ "dma1", 0x00, 0x1f, IORESOURCE_BUSY },
+	{ "pic1", 0x20, 0x3f, IORESOURCE_BUSY },
+	{ "timer", 0x40, 0x5f, IORESOURCE_BUSY },
+	{ "keyboard", 0x60, 0x6f, IORESOURCE_BUSY },
+	{ "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY },
+	{ "pic2", 0xa0, 0xbf, IORESOURCE_BUSY },
+	{ "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
+	{ "fpu", 0xf0, 0xff, IORESOURCE_BUSY }
+};
+
+#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
+
+struct resource code_resource = { "Kernel code", 0x100000, 0 };
+struct resource data_resource = { "Kernel data", 0, 0 };
+struct resource vram_resource = { "Video RAM area", 0xa0000, 0xbffff, IORESOURCE_BUSY };
+
+
+/* System ROM resources */
+#define MAXROMS 6
+static struct resource rom_resources[MAXROMS] = {
+	{ "System ROM", 0xF0000, 0xFFFFF, IORESOURCE_BUSY },
+	{ "Video ROM", 0xc0000, 0xc7fff, IORESOURCE_BUSY }
+};
+
+#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
+
+static void __init probe_roms(void)
+{
+	int roms = 1;
+	unsigned long base;
+	unsigned char *romstart;
+
+	request_resource(&iomem_resource, rom_resources+0);
+
+	/* Video ROM is standard at C000:0000 - C7FF:0000, check signature */
+	for (base = 0xC0000; base < 0xE0000; base += 2048) {
+		romstart = bus_to_virt(base);
+		if (!romsignature(romstart))
+			continue;
+		request_resource(&iomem_resource, rom_resources + roms);
+		roms++;
+		break;
+	}
+
+	/* Extension roms at C800:0000 - DFFF:0000 */
+	for (base = 0xC8000; base < 0xE0000; base += 2048) {
+		unsigned long length;
+
+		romstart = bus_to_virt(base);
+		if (!romsignature(romstart))
+			continue;
+		length = romstart[2] * 512;
+		if (length) {
+			unsigned int i;
+			unsigned char chksum;
+
+			chksum = 0;
+			for (i = 0; i < length; i++)
+				chksum += romstart[i];
+
+			/* Good checksum? */
+			if (!chksum) {
+				rom_resources[roms].start = base;
+				rom_resources[roms].end = base + length - 1;
+				rom_resources[roms].name = "Extension ROM";
+				rom_resources[roms].flags = IORESOURCE_BUSY;
+
+				request_resource(&iomem_resource, rom_resources + roms);
+				roms++;
+				if (roms >= MAXROMS)
+					return;
+			}
+		}
+	}
+
+	/* Final check for motherboard extension rom at E000:0000 */
+	base = 0xE0000;
+	romstart = bus_to_virt(base);
+
+	if (romsignature(romstart)) {
+		rom_resources[roms].start = base;
+		rom_resources[roms].end = base + 65535;
+		rom_resources[roms].name = "Extension ROM";
+		rom_resources[roms].flags = IORESOURCE_BUSY;
+
+		request_resource(&iomem_resource, rom_resources + roms);
+	}
+}
+
+unsigned long start_pfn, end_pfn; 
+extern unsigned long table_start, table_end;
+
+#ifndef CONFIG_DISCONTIGMEM
+static void __init contig_initmem_init(void)
+{
+	unsigned long bootmap_size, bootmap; 
+	bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
+	bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size);
+	if (bootmap == -1L) 
+		panic("Cannot find bootmem map of size %ld\n",bootmap_size);
+	bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
+	e820_bootmem_free(&contig_page_data, 0, end_pfn << PAGE_SHIFT); 
+	reserve_bootmem(bootmap, bootmap_size);
+}
+#endif
+
+void __init setup_arch(char **cmdline_p)
+{
+	int i;
+	unsigned long kernel_end; 
+
+ 	ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
+ 	drive_info = DRIVE_INFO;
+ 	screen_info = SCREEN_INFO;
+	aux_device_present = AUX_DEVICE_INFO;
+
+#ifdef CONFIG_BLK_DEV_RAM
+	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
+	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
+	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
+#endif
+	setup_memory_region();
+
+	if (!MOUNT_ROOT_RDONLY)
+		root_mountflags &= ~MS_RDONLY;
+	init_mm.start_code = (unsigned long) &_text;
+	init_mm.end_code = (unsigned long) &_etext;
+	init_mm.end_data = (unsigned long) &_edata;
+	init_mm.brk = (unsigned long) &_end;
+
+	code_resource.start = virt_to_bus(&_text);
+	code_resource.end = virt_to_bus(&_etext)-1;
+	data_resource.start = virt_to_bus(&_etext);
+	data_resource.end = virt_to_bus(&_edata)-1;
+
+	parse_mem_cmdline(cmdline_p);
+
+	e820_end_of_ram();
+
+	init_memory_mapping(); 
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (LOADER_TYPE && INITRD_START) {
+		if (INITRD_START + INITRD_SIZE <= (end_pfn << PAGE_SHIFT)) {
+			initrd_start =
+				INITRD_START ? INITRD_START + PAGE_OFFSET : 0;
+			initrd_end = initrd_start+INITRD_SIZE;
+	}
+		else {
+			printk(KERN_ERR "initrd extends beyond end of memory "
+			    "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+			    (unsigned long)INITRD_START + INITRD_SIZE,
+			    (unsigned long)(end_pfn << PAGE_SHIFT));
+			initrd_start = 0;
+	}
+	}
+#endif
+
+#ifdef CONFIG_DISCONTIGMEM
+	numa_initmem_init(0, end_pfn); 	
+#else
+	contig_initmem_init(); 
+#endif	
+
+	/* Reserve direct mapping */
+	reserve_bootmem_generic(table_start << PAGE_SHIFT, 
+				(table_end - table_start) << PAGE_SHIFT);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start) 
+		reserve_bootmem_generic(INITRD_START, INITRD_SIZE);
+#endif
+
+	/* Reserve BIOS data page. Some things still need it */
+	reserve_bootmem_generic(0, PAGE_SIZE);
+
+#ifdef CONFIG_SMP
+	/*
+	 * But first pinch a few for the stack/trampoline stuff
+	 * FIXME: Don't need the extra page at 4K, but need to fix
+	 * trampoline before removing it. (see the GDT stuff)
+	 */
+	reserve_bootmem_generic(PAGE_SIZE, PAGE_SIZE); 
+
+	/* Reserve SMP trampoline */
+	reserve_bootmem_generic(0x6000, PAGE_SIZE);
+#endif
+	/* Reserve Kernel */
+	kernel_end = round_up(__pa_symbol(&_end), PAGE_SIZE);
+	reserve_bootmem_generic(HIGH_MEMORY, kernel_end - HIGH_MEMORY);
+
+#ifdef CONFIG_X86_LOCAL_APIC
+	/*
+	 * Find and reserve possible boot-time SMP configuration:
+	 */
+	find_smp_config();
+#endif
+
+#ifdef CONFIG_SMP
+	/* AP processor realmode stacks in low memory*/
+	smp_alloc_memory();
+#endif
+
+	paging_init();
+#ifdef CONFIG_X86_LOCAL_APIC
+	/*
+	 * get boot-time SMP configuration:
+	 */
+	if (smp_found_config)
+		get_smp_config();
+	init_apic_mappings();	
+#endif
+
+	/*
+	 * Request address space for all standard RAM and ROM resources
+	 * and also for regions reported as reserved by the e820.
+	 */
+	probe_roms();
+	e820_reserve_resources(); 
+	request_resource(&iomem_resource, &vram_resource);
+
+	/* request I/O space for devices used on all i[345]86 PCs */
+	for (i = 0; i < STANDARD_IO_RESOURCES; i++)
+		request_resource(&ioport_resource, standard_io_resources+i);
+
+	/* We put PCI memory up to make sure VALID_PAGE with DISCONTIGMEM
+	   never returns true for it */ 
+
+	/* Tell the PCI layer not to allocate too close to the RAM area.. */
+	pci_mem_start = IOMAP_START;
+
+#ifdef CONFIG_GART_IOMMU
+	iommu_hole_init();
+#endif
+
+#ifdef CONFIG_VT
+#if defined(CONFIG_VGA_CONSOLE)
+	conswitchp = &vga_con;
+#elif defined(CONFIG_DUMMY_CONSOLE)
+	conswitchp = &dummy_con;
+#endif
+#endif
+
+	num_mappedpages = end_pfn;
+}
+
+#ifndef CONFIG_X86_TSC
+static int tsc_disable __initdata = 0;
+
+static int __init tsc_setup(char *str)
+{
+	tsc_disable = 1;
+	return 1;
+}
+
+__setup("notsc", tsc_setup);
+#endif
+
+static int __init get_model_name(struct cpuinfo_x86 *c)
+{
+	unsigned int *v;
+
+	if (cpuid_eax(0x80000000) < 0x80000004)
+		return 0;
+
+	v = (unsigned int *) c->x86_model_id;
+	cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
+	cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
+	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
+	c->x86_model_id[48] = 0;
+	return 1;
+}
+
+
+static void __init display_cacheinfo(struct cpuinfo_x86 *c)
+{
+	unsigned int n, dummy, ecx, edx, eax, ebx, eax_2, ebx_2, ecx_2;
+
+	n = cpuid_eax(0x80000000);
+
+
+	if (n >= 0x80000005) {
+		if (n >= 0x80000006) 
+			cpuid(0x80000006, &eax_2, &ebx_2, &ecx_2, &dummy); 
+	
+		cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
+		printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line/%d way), D cache %dK (%d bytes/line/%d way)\n",
+		       edx>>24, edx&0xFF, (edx>>16)&0xff, 
+		       ecx>>24, ecx&0xFF, (ecx>>16)&0xff);
+		c->x86_cache_size=(ecx>>24)+(edx>>24);	
+		if (n >= 0x80000006) {
+			printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line/%d way)\n",
+			       ecx_2>>16, ecx_2&0xFF, (ecx_2>>12)&0xf);
+			c->x86_cache_size = ecx_2 >> 16;
+		}		
+		printk(KERN_INFO "CPU: DTLB L1 %d 4K %d 2MB L2: %d 4K %d 2MB\n",
+		       (ebx>>16)&0xff, (eax>>16)&0xff, 
+		       (ebx_2>>16)&0xfff, (eax_2>>16)&0xfff);
+		printk(KERN_INFO "CPU: ITLB L1 %d 4K %d 2MB L2: %d 4K %d 2MB\n",
+		       ebx&0xff, (eax)&0xff, 
+		       (ebx_2)&0xfff, (eax_2)&0xfff);		
+		c->x86_tlbsize = ((ebx>>16)&0xff) + ((ebx_2>>16)&0xfff) + 
+			(ebx&0xff) + ((ebx_2)&0xfff);
+	}
+}
+
+static int __init init_amd(struct cpuinfo_x86 *c)
+{
+	int r;
+
+	/* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
+	   3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
+	clear_bit(0*32+31, &c->x86_capability);
+	
+	r = get_model_name(c);
+	if (!r) { 
+		switch (c->x86) { 
+		case 15:
+			/* Should distingush Models here, but this is only
+			   a fallback anyways. */
+			strcpy(c->x86_model_id, "Hammer");
+			break; 
+		} 
+	} 
+	display_cacheinfo(c);
+	return r;
+}
+
+
+void __init get_cpu_vendor(struct cpuinfo_x86 *c)
+{
+	char *v = c->x86_vendor_id;
+
+	if (!strcmp(v, "AuthenticAMD"))
+		c->x86_vendor = X86_VENDOR_AMD;
+	else
+		c->x86_vendor = X86_VENDOR_UNKNOWN;
+}
+
+struct cpu_model_info {
+	int vendor;
+	int family;
+	char *model_names[16];
+};
+
+int __init x86_fxsr_setup(char * s)
+{
+	disable_x86_fxsr = 1;
+	return 1;
+}
+__setup("nofxsr", x86_fxsr_setup);
+
+
+
+/*
+ * This does the hard work of actually picking apart the CPU stuff...
+ */
+void __init identify_cpu(struct cpuinfo_x86 *c)
+{
+	int junk, i;
+	u32 xlvl, tfms;
+
+	c->loops_per_jiffy = loops_per_jiffy;
+	c->x86_cache_size = -1;
+	c->x86_vendor = X86_VENDOR_UNKNOWN;
+	c->x86_model = c->x86_mask = 0;	/* So far unknown... */
+	c->x86_vendor_id[0] = '\0'; /* Unset */
+	c->x86_model_id[0] = '\0';  /* Unset */
+	memset(&c->x86_capability, 0, sizeof c->x86_capability);
+
+	/* Get vendor name */
+	cpuid(0x00000000, &c->cpuid_level,
+	      (int *)&c->x86_vendor_id[0],
+	      (int *)&c->x86_vendor_id[8],
+	      (int *)&c->x86_vendor_id[4]);
+		
+	get_cpu_vendor(c);
+	/* Initialize the standard set of capabilities */
+	/* Note that the vendor-specific code below might override */
+
+	/* Intel-defined flags: level 0x00000001 */
+	if ( c->cpuid_level >= 0x00000001 ) {	
+		__u32 misc;
+		cpuid(0x00000001, &tfms, &misc, &junk,
+		      &c->x86_capability[0]);
+		c->x86 = (tfms >> 8) & 15;
+		if (c->x86 == 0xf)
+			c->x86 += (tfms >> 20) & 0xff;
+		c->x86_model = (tfms >> 4) & 15;
+		if (c->x86_model == 0xf)
+			c->x86_model += ((tfms >> 16) & 0xF) << 4; 
+		c->x86_mask = tfms & 15;
+		if (c->x86_capability[0] & (1<<19)) 
+			c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
+	} else {
+		/* Have CPUID level 0 only - unheard of */
+		c->x86 = 4;
+	}
+
+	/* AMD-defined flags: level 0x80000001 */
+	xlvl = cpuid_eax(0x80000000);
+	if ( (xlvl & 0xffff0000) == 0x80000000 ) {
+		if ( xlvl >= 0x80000001 )
+			c->x86_capability[1] = cpuid_edx(0x80000001);
+		if ( xlvl >= 0x80000004 )
+			get_model_name(c); /* Default name */
+	}
+
+	/* Transmeta-defined flags: level 0x80860001 */
+	xlvl = cpuid_eax(0x80860000);
+	if ( (xlvl & 0xffff0000) == 0x80860000 ) {
+		if (  xlvl >= 0x80860001 )
+			c->x86_capability[2] = cpuid_edx(0x80860001);
+	}
+
+
+	/*
+	 * Vendor-specific initialization.  In this section we
+	 * canonicalize the feature flags, meaning if there are
+	 * features a certain CPU supports which CPUID doesn't
+	 * tell us, CPUID claiming incorrect flags, or other bugs,
+	 * we handle them here.
+	 *
+	 * At the end of this section, c->x86_capability better
+	 * indicate the features this CPU genuinely supports!
+	 */
+	switch ( c->x86_vendor ) {
+
+		case X86_VENDOR_AMD:
+			init_amd(c);
+			break;
+
+		case X86_VENDOR_UNKNOWN:
+		default:
+			/* Not much we can do here... */
+			break;
+	}
+
+	/*
+	 * The vendor-specific functions might have changed features.  Now
+	 * we do "generic changes."
+	 */
+
+	/* TSC disabled? */
+#ifndef CONFIG_X86_TSC
+	if ( tsc_disable )
+		clear_bit(X86_FEATURE_TSC, &c->x86_capability);
+#endif
+
+	/* FXSR disabled? */
+	if (disable_x86_fxsr) {
+		clear_bit(X86_FEATURE_FXSR, &c->x86_capability);
+		clear_bit(X86_FEATURE_XMM, &c->x86_capability);
+	}
+
+	/*
+	 * On SMP, boot_cpu_data holds the common feature set between
+	 * all CPUs; so make sure that we indicate which features are
+	 * common between the CPUs.  The first time this routine gets
+	 * executed, c == &boot_cpu_data.
+	 */
+	if ( c != &boot_cpu_data ) {
+		/* AND the already accumulated flags with these */
+		for ( i = 0 ; i < NCAPINTS ; i++ )
+			boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
+	}
+
+#ifdef CONFIG_MCE
+	mcheck_init(c);
+#endif
+}
+ 
+void __init print_cpu_info(struct cpuinfo_x86 *c)
+{
+	if (c->x86_model_id[0])
+		printk("%s", c->x86_model_id);
+
+	if (c->x86_mask || c->cpuid_level >= 0) 
+		printk(" stepping %02x\n", c->x86_mask);
+	else
+		printk("\n");
+}
+
+/*
+ *	Get CPU information for use by the procfs.
+ */
+
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+	struct cpuinfo_x86 *c = v;
+
+	/* 
+	 * These flag bits must match the definitions in <asm/cpufeature.h>.
+	 * NULL means this bit is undefined or reserved; either way it doesn't
+	 * have meaning as far as Linux is concerned.  Note that it's important
+	 * to realize there is a difference between this table and CPUID -- if
+	 * applications want to get the raw CPUID data, they should access
+	 * /dev/cpu/<cpu_nr>/cpuid instead.
+	 */
+	static char *x86_cap_flags[] = {
+		/* Intel-defined */
+	        "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
+	        "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
+	        "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
+	        "fxsr", "sse", "sse2", "ss", NULL, "tm", "ia64", NULL,
+
+		/* AMD-defined */
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL,
+		NULL, NULL, NULL, NULL, NULL, "lm", "3dnowext", "3dnow",
+
+		/* Transmeta-defined */
+		"recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+		/* Other (Linux-defined) */
+		"cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+	};
+
+#ifdef CONFIG_SMP
+	if (!(cpu_online_map & (1<<(c-cpu_data))))
+		return 0;
+#endif
+
+	seq_printf(m,"processor\t: %u\n"
+		     "vendor_id\t: %s\n"
+		     "cpu family\t: %d\n"
+		     "model\t\t: %d\n"
+		     "model name\t: %s\n",
+		     (unsigned)(c-cpu_data),
+		     c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
+		     c->x86,
+		     (int)c->x86_model,
+		     c->x86_model_id[0] ? c->x86_model_id : "unknown");
+	
+	if (c->x86_mask || c->cpuid_level >= 0)
+		seq_printf(m, "stepping\t: %d\n", c->x86_mask);
+	else
+		seq_printf(m, "stepping\t: unknown\n");
+	
+	if ( test_bit(X86_FEATURE_TSC, &c->x86_capability) ) {
+		seq_printf(m, "cpu MHz\t\t: %u.%03u\n",
+			     cpu_khz / 1000, (cpu_khz % 1000));
+	}
+
+	seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
+	
+	seq_printf(m,
+	        "fpu\t\t: yes\n"
+	        "fpu_exception\t: yes\n"
+	        "cpuid level\t: %d\n"
+	        "wp\t\t: yes\n"
+	        "flags\t\t:",
+		   c->cpuid_level);
+
+	{ 
+		int i; 
+		for ( i = 0 ; i < 32*NCAPINTS ; i++ )
+			if ( test_bit(i, &c->x86_capability) &&
+			     x86_cap_flags[i] != NULL )
+				seq_printf(m, " %s", x86_cap_flags[i]);
+	}
+		
+	seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
+		   c->loops_per_jiffy/(500000/HZ),
+		   (c->loops_per_jiffy/(5000/HZ)) % 100);
+
+	if (c->x86_tlbsize > 0) 
+		seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize);
+	seq_printf(m, "clflush size\t: %d\n", c->x86_clflush_size);
+
+	seq_printf(m, "\n"); 
+	return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+	return *pos < NR_CPUS ? cpu_data + *pos : NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	++*pos;
+	return c_start(m, pos);
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+struct seq_operations cpuinfo_op = {
+	start:	c_start,
+	next:	c_next,
+	stop:	c_stop,
+	show:	show_cpuinfo,
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/setup64.c linux-2.4.20/arch/x86_64/kernel/setup64.c
--- linux-2.4.19/arch/x86_64/kernel/setup64.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/setup64.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,201 @@
+/* 
+ * X86-64 specific CPU setup.
+ * Copyright (C) 1995  Linus Torvalds
+ * Copyright 2001, 2002 SuSE Labs / Andi Kleen.
+ * See setup.c for older changelog.
+ * $Id: setup64.c,v 1.15 2002/09/05 15:25:43 ak Exp $
+ */ 
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <asm/pda.h>
+#include <asm/pda.h>
+#include <asm/processor.h>
+#include <asm/desc.h>
+#include <asm/bitops.h>
+#include <asm/atomic.h>
+#include <asm/mmu_context.h>
+#include <asm/proto.h>
+
+char x86_boot_params[2048] __initdata = {0,};
+
+static unsigned long cpu_initialized __initdata = 0;
+
+struct x8664_pda cpu_pda[NR_CPUS] __cacheline_aligned; 
+
+extern void system_call(void); 
+extern void ia32_cstar_target(void); 
+
+struct desc_ptr gdt_descr = { 0 /* filled in */, (unsigned long) gdt_table }; 
+struct desc_ptr idt_descr = { 256 * 16, (unsigned long) idt_table }; 
+
+unsigned long __supported_pte_mask = ~_PAGE_NX; 
+static int do_not_nx = 1; 
+
+char boot_cpu_stack[IRQSTACKSIZE] __cacheline_aligned;
+
+
+static int __init nonx_setup(char *str)
+{
+	if (strstr(str,"off")) { 
+		__supported_pte_mask &= ~_PAGE_NX; 
+		do_not_nx = 1; 
+	} else if (strstr(str, "on")) { 
+		do_not_nx = 0; 
+		__supported_pte_mask |= _PAGE_NX; 
+	} 
+	return 1;
+} 
+
+__setup("noexec=", nonx_setup); 
+
+void pda_init(int cpu)
+{ 
+        pml4_t *level4;
+	
+	if (cpu == 0) {
+		/* others are initialized in smpboot.c */
+		cpu_pda[cpu].pcurrent = init_tasks[cpu];
+		cpu_pda[cpu].irqstackptr = boot_cpu_stack; 
+		level4 = init_level4_pgt; 
+	} else {
+		cpu_pda[cpu].irqstackptr = (char *)
+			__get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER);
+		if (!cpu_pda[cpu].irqstackptr)
+			panic("cannot allocate irqstack for cpu %d\n", cpu); 
+		level4 = (pml4_t *)__get_free_pages(GFP_ATOMIC, 0); 
+	}   
+	if (!level4) 
+		panic("Cannot allocate top level page for cpu %d", cpu); 
+
+	cpu_pda[cpu].level4_pgt = (unsigned long *)level4; 
+	if (level4 != init_level4_pgt)
+		memcpy(level4, &init_level4_pgt, PAGE_SIZE); 
+	set_pml4(level4 + 510, 
+		 mk_kernel_pml4(__pa_symbol(boot_vmalloc_pgt), KERNPG_TABLE));
+	asm volatile("movq %0,%%cr3" :: "r" (__pa(level4))); 
+
+	cpu_pda[cpu].irqstackptr += IRQSTACKSIZE-64;
+	cpu_pda[cpu].cpunumber = cpu; 
+	cpu_pda[cpu].irqcount = -1;
+
+	asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0)); 
+	wrmsrl(MSR_GS_BASE, cpu_pda + cpu);
+} 
+
+#define EXCEPTION_STK_ORDER 0 /* >= N_EXCEPTION_STACKS*EXCEPTION_STKSZ */
+char boot_exception_stacks[N_EXCEPTION_STACKS*EXCEPTION_STKSZ];
+
+/*
+ * cpu_init() initializes state that is per-CPU. Some data is already
+ * initialized (naturally) in the bootstrap process, such as the GDT
+ * and IDT. We reload them nevertheless, this function acts as a
+ * 'CPU state barrier', nothing should get across.
+ * A lot of state is already set up in PDA init.
+ */
+void __init cpu_init (void)
+{
+#ifdef CONFIG_SMP
+	int nr = stack_smp_processor_id();
+#else
+	int nr = smp_processor_id();
+#endif
+	struct tss_struct * t = &init_tss[nr];
+	unsigned long v, efer; 	
+	char *estacks; 
+
+	/* CPU 0 is initialised in head64.c */
+	if (nr != 0) {
+		estacks = (char *)__get_free_pages(GFP_ATOMIC, 0); 
+		if (!estacks)
+			panic("Can't allocate exception stacks for CPU %d\n",nr);
+		pda_init(nr);  
+	} else 
+		estacks = boot_exception_stacks; 
+
+	if (test_and_set_bit(nr, &cpu_initialized))
+		panic("CPU#%d already initialized!\n", nr);
+
+	printk("Initializing CPU#%d\n", nr);
+	
+	clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
+
+	gdt_descr.size = NR_CPUS * sizeof(struct per_cpu_gdt) + __GDT_HEAD_SIZE; 
+
+	__asm__ __volatile__("lgdt %0": "=m" (gdt_descr));
+	__asm__ __volatile__("lidt %0": "=m" (idt_descr));
+
+	/*
+	 * Delete NT
+	 */
+
+	asm volatile("pushfq ; popq %%rax ; btr $14,%%rax ; pushq %%rax ; popfq" ::: "eax");
+
+	/* 
+	 * LSTAR and STAR live in a bit strange symbiosis.
+	 * They both write to the same internal register. STAR allows to set CS/DS
+	 * but only a 32bit target. LSTAR sets the 64bit rip. 	 
+	 */ 
+	wrmsrl(MSR_STAR,  ((u64)__USER32_CS)<<48  | ((u64)__KERNEL_CS)<<32); 
+	wrmsrl(MSR_LSTAR, system_call); 
+
+#ifdef CONFIG_IA32_EMULATION   		
+	wrmsrl(MSR_CSTAR, ia32_cstar_target); 
+#endif
+
+	if (!do_not_nx) { 
+		rdmsrl(MSR_EFER, efer); 
+		if (!(efer & EFER_NX)) { 
+			__supported_pte_mask &= ~_PAGE_NX; 
+		} 
+	}
+
+	t->io_map_base = INVALID_IO_BITMAP_OFFSET;	
+	memset(t->io_bitmap, 0xff, sizeof(t->io_bitmap));
+
+	/* Flags to clear on syscall */
+	wrmsrl(MSR_SYSCALL_MASK, EF_TF|EF_DF|EF_IE); 
+
+	wrmsrl(MSR_FS_BASE, 0);
+	wrmsrl(MSR_KERNEL_GS_BASE, 0);
+	barrier(); 
+
+	/*
+	 * set up and load the per-CPU TSS
+	 */
+	estacks += EXCEPTION_STKSZ;
+	for (v = 0; v < N_EXCEPTION_STACKS; v++) {
+		t->ist[v] = (unsigned long)estacks;
+		estacks += EXCEPTION_STKSZ;
+	}
+
+	atomic_inc(&init_mm.mm_count);
+	current->active_mm = &init_mm;
+	if(current->mm)
+		BUG();
+	enter_lazy_tlb(&init_mm, current, nr);
+
+	set_tss_desc(nr, t);
+	load_TR(nr);
+	load_LDT(&init_mm);
+
+	/*
+	 * Clear all 6 debug registers:
+	 */
+
+	set_debug(0UL, 0);
+	set_debug(0UL, 1);
+	set_debug(0UL, 2);
+	set_debug(0UL, 3);
+	set_debug(0UL, 6);
+	set_debug(0UL, 7);
+
+	/*
+	 * Force FPU initialization:
+	 */
+	current->flags &= ~PF_USEDFPU;
+	current->used_math = 0;
+	stts();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/signal.c linux-2.4.20/arch/x86_64/kernel/signal.c
--- linux-2.4.19/arch/x86_64/kernel/signal.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/signal.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,595 @@
+/*
+ *  linux/arch/x86_64/kernel/signal.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001  SuSE Labs
+ *
+ *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
+ *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
+ *  2000-2001   x86-64 support by Andi Kleen
+ * 
+ *  $Id: signal.c,v 1.35 2002/07/29 10:34:03 ak Exp $
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/tty.h>
+#include <linux/personality.h>
+#include <linux/compiler.h>
+#include <linux/binfmts.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#include <asm/i387.h>
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
+
+void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+               sigset_t *set, struct pt_regs * regs); 
+void ia32_setup_frame(int sig, struct k_sigaction *ka,
+            sigset_t *set, struct pt_regs * regs); 
+void signal_fault(struct pt_regs *regs, void *frame, char *where);
+extern int exception_trace;
+
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+		return -EFAULT;
+	if (from->si_code < 0)
+		return __copy_to_user(to, from, sizeof(siginfo_t));
+	else {
+		int err;
+
+		/* If you change siginfo_t structure, please be sure
+		   this code is fixed accordingly.
+		   It should never copy any pad contained in the structure
+		   to avoid security leaks, but must copy the generic
+		   3 ints plus the relevant union member.  */
+		err = __put_user(from->si_signo, &to->si_signo);
+		err |= __put_user(from->si_errno, &to->si_errno);
+		err |= __put_user((short)from->si_code, &to->si_code);
+		/* First 32bits of unions are always present.  */
+		err |= __put_user(from->si_pid, &to->si_pid);
+		switch (from->si_code >> 16) {
+		case __SI_FAULT >> 16:
+			break;
+		case __SI_CHLD >> 16:
+			err |= __put_user(from->si_utime, &to->si_utime);
+			err |= __put_user(from->si_stime, &to->si_stime);
+			err |= __put_user(from->si_status, &to->si_status);
+		default:
+			err |= __put_user(from->si_uid, &to->si_uid);
+			break;
+		/* case __SI_RT: This is not generated by the kernel as of now.  */
+		}
+		return err;
+	}
+}
+
+asmlinkage long
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs regs)
+{
+	sigset_t saveset, newset;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset_t))
+		return -EINVAL;
+
+	if (copy_from_user(&newset, unewset, sizeof(newset)))
+		return -EFAULT;
+	sigdelsetmask(&newset, ~_BLOCKABLE);
+
+	spin_lock_irq(&current->sigmask_lock);
+	saveset = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+#if DEBUG_SIG
+	printk("rt_sigsuspend savset(%lx) newset(%lx) regs(%p) rip(%lx)\n",
+		saveset, newset, &regs, regs.rip);
+#endif 
+	regs.rax = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(&regs, &saveset))
+			return -EINTR;
+	}
+}
+
+asmlinkage long
+sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs regs)
+{
+	return do_sigaltstack(uss, uoss, regs.rsp);
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+
+struct rt_sigframe
+{
+	char *pretcode;
+	struct ucontext uc;
+	struct siginfo info;
+};
+
+static int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, unsigned long *prax)
+{
+	unsigned int err = 0;
+
+
+#define COPY(x)		err |= __get_user(regs->x, &sc->x)
+#define COPY_CANON(x)   \
+	COPY(x); \
+	if ((regs->x >> 48)  != 0 && (regs->x >> 48) != 0xffff) \
+				regs->x = 0; 
+
+	{ 
+		unsigned int seg; 
+		err |= __get_user(seg, &sc->gs); 
+		load_gs_index(seg); 
+		err |= __get_user(seg, &sc->fs);
+		loadsegment(fs,seg);
+	}
+
+	COPY(rdi); COPY(rsi); COPY(rbp); COPY_CANON(rsp); COPY(rbx);
+	COPY(rdx); COPY(rcx); COPY_CANON(rip);
+	COPY(r8);
+	COPY(r9);
+	COPY(r10);
+	COPY(r11);
+	COPY(r12);
+	COPY(r13);
+	COPY(r14);
+	COPY(r15);
+
+	/* do not copy CS/SS because 64bit should not need it. 
+	   also need IRET exception handling anyways. */
+
+	{
+		unsigned int tmpflags;
+		err |= __get_user(tmpflags, &sc->eflags);
+		regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
+		regs->orig_rax = -1;		/* disable syscall checks */
+	}
+
+	{
+		struct _fpstate * buf;
+		err |= __get_user(buf, &sc->fpstate);
+		if (buf) {
+			if (unlikely(verify_area(VERIFY_READ, buf, sizeof(*buf))))
+				return 1;
+			err |= restore_i387(buf);
+		}
+	}
+
+	err |= __get_user(*prax, &sc->rax);
+	return err;
+}
+#undef COPY
+
+asmlinkage long sys_rt_sigreturn(struct pt_regs regs)
+{
+	struct rt_sigframe *frame = (struct rt_sigframe *)(regs.rsp - 8);
+	sigset_t set;
+	stack_t st;
+	long eax;
+
+	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = set;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+	
+	if (restore_sigcontext(&regs, &frame->uc.uc_mcontext, &eax))
+		goto badframe;
+
+#if DEBUG_SIG
+	printk("%d sigreturn rip:%lx rsp:%lx frame:%p rax:%lx\n",current->pid,regs.rip,regs.rsp,frame,eax);
+#endif
+
+	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+		goto badframe;
+	/* It is more difficult to avoid calling this function than to
+	   call it and ignore errors.  */
+	do_sigaltstack(&st, NULL, regs.rsp);
+
+	return eax;
+
+badframe:
+	signal_fault(&regs, frame, "rt_sigreturn"); 
+	return 0;
+}	
+
+/*
+ * Set up a signal frame.
+ */
+
+static int
+setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, unsigned long mask)
+{
+	int tmp, err = 0;
+	struct task_struct *me = current;
+
+	tmp = 0;
+	__asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
+	err |= __put_user(tmp, (unsigned int *)&sc->gs);
+	__asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
+	err |= __put_user(tmp, (unsigned int *)&sc->fs);
+
+	err |= __put_user(regs->rdi, &sc->rdi);
+	err |= __put_user(regs->rsi, &sc->rsi);
+	err |= __put_user(regs->rbp, &sc->rbp);
+	err |= __put_user(regs->rsp, &sc->rsp);
+	err |= __put_user(regs->rbx, &sc->rbx);
+	err |= __put_user(regs->rdx, &sc->rdx);
+	err |= __put_user(regs->rcx, &sc->rcx);
+	err |= __put_user(regs->rax, &sc->rax);
+	err |= __put_user(regs->r8, &sc->r8);
+	err |= __put_user(regs->r9, &sc->r9);
+	err |= __put_user(regs->r10, &sc->r10);
+	err |= __put_user(regs->r11, &sc->r11);
+	err |= __put_user(regs->r12, &sc->r12);
+	err |= __put_user(regs->r13, &sc->r13);
+	err |= __put_user(regs->r14, &sc->r14);
+	err |= __put_user(regs->r15, &sc->r15);
+	err |= __put_user(me->thread.trap_no, &sc->trapno);
+	err |= __put_user(me->thread.error_code, &sc->err);
+	err |= __put_user(regs->rip, &sc->rip);
+	err |= __put_user(regs->cs, &sc->cs);
+	err |= __put_user(regs->eflags, &sc->eflags);
+	err |= __put_user(mask, &sc->oldmask);
+	err |= __put_user(me->thread.cr2, &sc->cr2);
+
+	return err;
+}
+
+/*
+ * Determine which stack to use..
+ */
+#define round_down(p, r) ((void *)  ((unsigned long)((p) - (r) + 1) & ~((r)-1)))
+
+
+static void * 
+get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size)
+{
+	unsigned long rsp;
+
+	/* Default to using normal stack - redzone*/
+	rsp = regs->rsp - 128;
+
+	/* This is the X/Open sanctioned signal stack switching.  */
+	if (ka->sa.sa_flags & SA_ONSTACK) {
+		if (! sas_ss_flags(rsp) == 0)
+			rsp = current->sas_ss_sp + current->sas_ss_size;
+	}
+
+	return round_down(rsp - size, 16); 	
+}
+
+static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+			   sigset_t *set, struct pt_regs * regs)
+{
+	struct rt_sigframe *frame = NULL;
+	struct _fpstate *fp = NULL; 
+	int err = 0;
+
+	if (current->used_math) {
+		fp = get_stack(ka, regs, sizeof(struct _fpstate)); 
+		frame = round_down((char *)fp - sizeof(struct rt_sigframe), 16) - 8;
+
+		if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) { 
+			goto give_sigsegv;
+		}
+		if (save_i387(fp) < 0) 
+			err |= -1; 
+	}
+
+	if (!frame)
+		frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) {
+		goto give_sigsegv;
+	}
+
+
+	if (ka->sa.sa_flags & SA_SIGINFO) { 
+		err |= copy_siginfo_to_user(&frame->info, info);
+		if (err)
+			goto give_sigsegv;
+	}
+		
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->uc.uc_flags);
+	err |= __put_user(0, &frame->uc.uc_link);
+	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(regs->rsp),
+			  &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
+	err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	/* x86-64 should always use SA_RESTORER. */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
+	} else {
+		printk("%s forgot to set SA_RESTORER for signal %d.\n", current->comm, sig); 
+		goto give_sigsegv; 
+	}
+
+	if (err)
+		goto give_sigsegv;
+
+#if DEBUG_SIG
+	printk("%d old rip %lx old rsp %lx old rax %lx\n", current->pid,regs->rip,regs->rsp,regs->rax);
+#endif
+
+	/* Set up registers for signal handler */
+	{ 
+		struct exec_domain *ed = current->exec_domain;
+		if (unlikely(ed && ed->signal_invmap && sig < 32))
+			sig = ed->signal_invmap[sig];
+	} 
+	regs->rdi = sig;
+
+	/* could reload DS/ES to __USER_DS here, but assume for now
+	   that 64bit does not care */
+
+	/* In case the signal handler was declared without prototypes */ 
+	regs->rax = 0;
+
+	/* This also works for non SA_SIGINFO handlers because they expect the
+	   next argument after the signal number on the stack. */
+	regs->rsi = (unsigned long)&frame->info; 
+	regs->rdx = (unsigned long)&frame->uc; 
+	regs->rsp = (unsigned long) frame;
+	regs->rip = (unsigned long) ka->sa.sa_handler;
+	regs->cs = __USER_CS;
+	regs->ss = __USER_DS; 
+
+	set_fs(USER_DS);
+	regs->eflags &= ~TF_MASK;
+
+#if DEBUG_SIG
+	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+		current->comm, current->pid, frame, regs->rip, frame->pretcode);
+#endif
+
+	return;
+
+give_sigsegv:
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	signal_fault(regs, frame, "signal deliver"); 
+}
+
+/*
+ * OK, we're invoking a handler
+ */	
+
+static void
+handle_signal(unsigned long sig, struct k_sigaction *ka,
+	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+{
+#if DEBUG_SIG
+	printk("handle_signal pid:%d sig:%lu rip:%lx rsp:%lx regs=%p\n", current->pid, sig, 
+		regs->rip, regs->rsp, regs);
+#endif
+
+	/* Are we from a system call? */
+	if (regs->orig_rax >= 0) {
+		/* If so, check system call restarting.. */
+		switch (regs->rax) {
+			case -ERESTARTNOHAND:
+				regs->rax = -EINTR;
+				break;
+
+			case -ERESTARTSYS:
+				if (!(ka->sa.sa_flags & SA_RESTART)) {
+					regs->rax = -EINTR;
+					break;
+				}
+			/* fallthrough */
+			case -ERESTARTNOINTR:
+				regs->rax = regs->orig_rax;
+				regs->rip -= 2;
+				break; 
+		}
+	}
+
+#ifdef CONFIG_IA32_EMULATION
+	if (current->thread.flags & THREAD_IA32) { 
+		if (ka->sa.sa_flags & SA_SIGINFO)
+			ia32_setup_rt_frame(sig, ka, info, oldset, regs);
+		else
+			ia32_setup_frame(sig, ka, oldset, regs);
+	} else 
+#endif
+	setup_rt_frame(sig, ka, info, oldset, regs);
+
+	if (ka->sa.sa_flags & SA_ONESHOT)
+		ka->sa.sa_handler = SIG_DFL;
+
+	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+		spin_lock_irq(&current->sigmask_lock);
+		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigaddset(&current->blocked,sig);
+		recalc_sigpending(current);
+		spin_unlock_irq(&current->sigmask_lock);
+	}
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+int do_signal(struct pt_regs *regs, sigset_t *oldset)
+{
+	siginfo_t info;
+	struct k_sigaction *ka;
+
+	/*
+	 * We want the common case to go fast, which
+	 * is why we may in certain cases get here from
+	 * kernel mode. Just return without doing anything
+	 * if so.
+	 */
+	if ((regs->cs & 3) != 3) {
+		return 1;
+	} 	
+
+	if (!oldset)
+		oldset = &current->blocked;
+
+	for (;;) {
+		unsigned long signr;
+
+		spin_lock_irq(&current->sigmask_lock);
+		signr = dequeue_signal(&current->blocked, &info);
+		spin_unlock_irq(&current->sigmask_lock);
+
+		if (!signr) { 
+			break;
+		}
+
+		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
+			/* Let the debugger run.  */
+			current->exit_code = signr;
+			current->state = TASK_STOPPED;
+			notify_parent(current, SIGCHLD);
+			schedule();
+
+			/* We're back.  Did the debugger cancel the sig?  */
+			if (!(signr = current->exit_code))
+				continue;
+			current->exit_code = 0;
+
+			/* The debugger continued.  Ignore SIGSTOP.  */
+			if (signr == SIGSTOP)
+				continue;
+
+			/* Update the siginfo structure.  Is this good?  */
+			if (signr != info.si_signo) {
+				info.si_signo = signr;
+				info.si_errno = 0;
+				info.si_code = SI_USER;
+				info.si_pid = current->p_pptr->pid;
+				info.si_uid = current->p_pptr->uid;
+			}
+
+			/* If the (new) signal is now blocked, requeue it.  */
+			if (sigismember(&current->blocked, signr)) {
+				send_sig_info(signr, &info, current);
+				continue;
+			}
+		}
+
+		ka = &current->sig->action[signr-1];
+		if (ka->sa.sa_handler == SIG_IGN) {
+			if (signr != SIGCHLD)
+				continue;
+			/* Check for SIGCHLD: it's special.  */
+			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+				/* nothing */;
+			continue;
+		}
+
+		if (ka->sa.sa_handler == SIG_DFL) {
+			int exit_code = signr;
+
+			/* Init gets no signals it doesn't want.  */
+			if (current->pid == 1)			      
+				continue;
+
+			switch (signr) {
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
+				continue;
+
+			case SIGTSTP: case SIGTTIN: case SIGTTOU:
+				if (is_orphaned_pgrp(current->pgrp))
+					continue;
+				/* FALLTHRU */
+
+			case SIGSTOP: {
+				struct signal_struct *sig;
+				current->state = TASK_STOPPED;
+				current->exit_code = signr;
+				sig = current->p_pptr->sig;
+				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+					notify_parent(current, SIGCHLD);
+				schedule();
+				continue;
+			}
+
+			case SIGQUIT: case SIGILL: case SIGTRAP:
+			case SIGABRT: case SIGFPE: case SIGSEGV:
+			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
+				if (do_coredump(signr, regs))
+					exit_code |= 0x80;
+				/* FALLTHRU */
+
+			default:
+				sig_exit(signr, exit_code, &info);
+				/* NOTREACHED */
+			}
+		}
+
+		/* Reenable any watchpoints before delivering the
+		 * signal to user space. The processor register will
+		 * have been cleared if the watchpoint triggered
+		 * inside the kernel.
+		 */
+		__asm__("movq %0,%%db7"	: : "r" (current->thread.debugreg[7]));
+
+		/* Whee!  Actually deliver the signal.  */
+		handle_signal(signr, ka, &info, oldset, regs);
+		return 1;
+	}
+
+	/* Did we come from a system call? */
+	if (regs->orig_rax >= 0) {
+		/* Restart the system call - no handlers present */
+		if (regs->rax == -ERESTARTNOHAND ||
+		    regs->rax == -ERESTARTSYS ||
+		    regs->rax == -ERESTARTNOINTR) {
+			regs->rax = regs->orig_rax;
+			regs->rip -= 2;
+		}
+	}
+	return 0;
+}
+
+
+void signal_fault(struct pt_regs *regs, void *frame, char *where)
+{ 
+	struct task_struct *me = current; 
+	if (exception_trace)
+		printk("%s[%d] bad frame in %s frame:%p rip:%lx rsp:%lx orax:%lx\n",
+	       me->comm,me->pid,where,frame,regs->rip,regs->rsp,regs->orig_rax); 
+
+	force_sig(SIGSEGV, me); 
+} 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/smp.c linux-2.4.20/arch/x86_64/kernel/smp.c
--- linux-2.4.19/arch/x86_64/kernel/smp.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/smp.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,555 @@
+/*
+ *	Intel SMP support routines.
+ *
+ *	(c) 1995 Alan Cox, Building #3 <alan@redhat.com>
+ *	(c) 1998-99, 2000 Ingo Molnar <mingo@redhat.com>
+ *
+ *	This code is released under the GNU General Public License version 2 or
+ *	later.
+ */
+
+#include <linux/init.h>
+
+#include <linux/mm.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/mtrr.h>
+#include <asm/pgalloc.h>
+
+/*
+ *	Some notes on x86 processor bugs affecting SMP operation:
+ *
+ *	Pentium, Pentium Pro, II, III (and all CPUs) have bugs.
+ *	The Linux implications for SMP are handled as follows:
+ *
+ *	Pentium III / [Xeon]
+ *		None of the E1AP-E3AP errata are visible to the user.
+ *
+ *	E1AP.	see PII A1AP
+ *	E2AP.	see PII A2AP
+ *	E3AP.	see PII A3AP
+ *
+ *	Pentium II / [Xeon]
+ *		None of the A1AP-A3AP errata are visible to the user.
+ *
+ *	A1AP.	see PPro 1AP
+ *	A2AP.	see PPro 2AP
+ *	A3AP.	see PPro 7AP
+ *
+ *	Pentium Pro
+ *		None of 1AP-9AP errata are visible to the normal user,
+ *	except occasional delivery of 'spurious interrupt' as trap #15.
+ *	This is very rare and a non-problem.
+ *
+ *	1AP.	Linux maps APIC as non-cacheable
+ *	2AP.	worked around in hardware
+ *	3AP.	fixed in C0 and above steppings microcode update.
+ *		Linux does not use excessive STARTUP_IPIs.
+ *	4AP.	worked around in hardware
+ *	5AP.	symmetric IO mode (normal Linux operation) not affected.
+ *		'noapic' mode has vector 0xf filled out properly.
+ *	6AP.	'noapic' mode might be affected - fixed in later steppings
+ *	7AP.	We do not assume writes to the LVT deassering IRQs
+ *	8AP.	We do not enable low power mode (deep sleep) during MP bootup
+ *	9AP.	We do not use mixed mode
+ *
+ *	Pentium
+ *		There is a marginal case where REP MOVS on 100MHz SMP
+ *	machines with B stepping processors can fail. XXX should provide
+ *	an L1cache=Writethrough or L1cache=off option.
+ *
+ *		B stepping CPUs may hang. There are hardware work arounds
+ *	for this. We warn about it in case your board doesnt have the work
+ *	arounds. Basically thats so I can tell anyone with a B stepping
+ *	CPU and SMP problems "tough".
+ *
+ *	Specific items [From Pentium Processor Specification Update]
+ *
+ *	1AP.	Linux doesn't use remote read
+ *	2AP.	Linux doesn't trust APIC errors
+ *	3AP.	We work around this
+ *	4AP.	Linux never generated 3 interrupts of the same priority
+ *		to cause a lost local interrupt.
+ *	5AP.	Remote read is never used
+ *	6AP.	not affected - worked around in hardware
+ *	7AP.	not affected - worked around in hardware
+ *	8AP.	worked around in hardware - we get explicit CS errors if not
+ *	9AP.	only 'noapic' mode affected. Might generate spurious
+ *		interrupts, we log only the first one and count the
+ *		rest silently.
+ *	10AP.	not affected - worked around in hardware
+ *	11AP.	Linux reads the APIC between writes to avoid this, as per
+ *		the documentation. Make sure you preserve this as it affects
+ *		the C stepping chips too.
+ *	12AP.	not affected - worked around in hardware
+ *	13AP.	not affected - worked around in hardware
+ *	14AP.	we always deassert INIT during bootup
+ *	15AP.	not affected - worked around in hardware
+ *	16AP.	not affected - worked around in hardware
+ *	17AP.	not affected - worked around in hardware
+ *	18AP.	not affected - worked around in hardware
+ *	19AP.	not affected - worked around in BIOS
+ *
+ *	If this sounds worrying believe me these bugs are either ___RARE___,
+ *	or are signal timing bugs worked around in hardware and there's
+ *	about nothing of note with C stepping upwards.
+ */
+
+/* The 'big kernel lock' */
+spinlock_cacheline_t kernel_flag_cacheline = {SPIN_LOCK_UNLOCKED};
+
+struct tlb_state cpu_tlbstate[NR_CPUS] __cacheline_aligned = {[0 ... NR_CPUS-1] = { &init_mm, 0, }};
+
+/*
+ * the following functions deal with sending IPIs between CPUs.
+ *
+ * We use 'broadcast', CPU->CPU IPIs and self-IPIs too.
+ */
+
+static inline unsigned int __prepare_ICR (unsigned int shortcut, int vector)
+{
+	unsigned int icr =  APIC_DM_FIXED | shortcut | vector | APIC_DEST_LOGICAL;
+	if (vector == KDB_VECTOR) 
+		icr = (icr & (~APIC_VECTOR_MASK)) | APIC_DM_NMI; 		
+	return icr;
+}
+
+static inline int __prepare_ICR2 (unsigned int mask)
+{
+	return SET_APIC_DEST_FIELD(mask);
+}
+
+static inline void __send_IPI_shortcut(unsigned int shortcut, int vector)
+{
+	/*
+	 * Subtle. In the case of the 'never do double writes' workaround
+	 * we have to lock out interrupts to be safe.  As we don't care
+	 * of the value read we use an atomic rmw access to avoid costly
+	 * cli/sti.  Otherwise we use an even cheaper single atomic write
+	 * to the APIC.
+	 */
+	unsigned int cfg;
+
+	/*
+	 * Wait for idle.
+	 */
+	apic_wait_icr_idle();
+
+	/*
+	 * No need to touch the target chip field
+	 */
+	cfg = __prepare_ICR(shortcut, vector);
+
+	/*
+	 * Send the IPI. The write to APIC_ICR fires this off.
+	 */
+	apic_write_around(APIC_ICR, cfg);
+}
+
+static inline void send_IPI_allbutself(int vector)
+{
+	/*
+	 * if there are no other CPUs in the system then
+	 * we get an APIC send error if we try to broadcast.
+	 * thus we have to avoid sending IPIs in this case.
+	 */
+	if (smp_num_cpus > 1)
+		__send_IPI_shortcut(APIC_DEST_ALLBUT, vector);
+}
+
+static inline void send_IPI_all(int vector)
+{
+	__send_IPI_shortcut(APIC_DEST_ALLINC, vector);
+}
+
+void send_IPI_self(int vector)
+{
+	__send_IPI_shortcut(APIC_DEST_SELF, vector);
+}
+
+static inline void send_IPI_mask(int mask, int vector)
+{
+	unsigned long cfg;
+	unsigned long flags;
+
+	__save_flags(flags);
+	__cli();
+
+	/*
+	 * Wait for idle.
+	 */
+	apic_wait_icr_idle();
+
+	/*
+	 * prepare target chip field
+	 */
+	cfg = __prepare_ICR2(mask);
+	apic_write_around(APIC_ICR2, cfg);
+
+	/*
+	 * program the ICR 
+	 */
+	cfg = __prepare_ICR(0, vector);
+	
+	/*
+	 * Send the IPI. The write to APIC_ICR fires this off.
+	 */
+	apic_write_around(APIC_ICR, cfg);
+	__restore_flags(flags);
+}
+
+/*
+ *	Smarter SMP flushing macros. 
+ *		c/o Linus Torvalds.
+ *
+ *	These mean you can really definitely utterly forget about
+ *	writing to user space from interrupts. (Its not allowed anyway).
+ *
+ *	Optimizations Manfred Spraul <manfred@colorfullife.com>
+ */
+
+static volatile unsigned long flush_cpumask;
+static struct mm_struct * flush_mm;
+static unsigned long flush_va;
+static spinlock_t tlbstate_lock = SPIN_LOCK_UNLOCKED;
+#define FLUSH_ALL	0xffffffff
+
+/*
+ * We cannot call mmdrop() because we are in interrupt context, 
+ * instead update mm->cpu_vm_mask.
+ */
+static void inline leave_mm (unsigned long cpu)
+{
+	if (cpu_tlbstate[cpu].state == TLBSTATE_OK)
+		BUG();
+	clear_bit(cpu, &cpu_tlbstate[cpu].active_mm->cpu_vm_mask);
+	/* flush TLB before it goes away. this stops speculative prefetches */
+	__flush_tlb(); 
+}
+
+/*
+ *
+ * The flush IPI assumes that a thread switch happens in this order:
+ * [cpu0: the cpu that switches]
+ * 1) switch_mm() either 1a) or 1b)
+ * 1a) thread switch to a different mm
+ * 1a1) clear_bit(cpu, &old_mm->cpu_vm_mask);
+ * 	Stop ipi delivery for the old mm. This is not synchronized with
+ * 	the other cpus, but smp_invalidate_interrupt ignore flush ipis
+ * 	for the wrong mm, and in the worst case we perform a superflous
+ * 	tlb flush.
+ * 1a2) set cpu_tlbstate to TLBSTATE_OK
+ * 	Now the smp_invalidate_interrupt won't call leave_mm if cpu0
+ *	was in lazy tlb mode.
+ * 1a3) update cpu_tlbstate[].active_mm
+ * 	Now cpu0 accepts tlb flushes for the new mm.
+ * 1a4) set_bit(cpu, &new_mm->cpu_vm_mask);
+ * 	Now the other cpus will send tlb flush ipis.
+ * 1a4) change cr3.
+ * 1b) thread switch without mm change
+ *	cpu_tlbstate[].active_mm is correct, cpu0 already handles
+ *	flush ipis.
+ * 1b1) set cpu_tlbstate to TLBSTATE_OK
+ * 1b2) test_and_set the cpu bit in cpu_vm_mask.
+ * 	Atomically set the bit [other cpus will start sending flush ipis],
+ * 	and test the bit.
+ * 1b3) if the bit was 0: leave_mm was called, flush the tlb.
+ * 2) switch %%esp, ie current
+ *
+ * The interrupt must handle 2 special cases:
+ * - cr3 is changed before %%esp, ie. it cannot use current->{active_,}mm.
+ * - the cpu performs speculative tlb reads, i.e. even if the cpu only
+ *   runs in kernel space, the cpu could load tlb entries for user space
+ *   pages.
+ *
+ * The good news is that cpu_tlbstate is local to each cpu, no
+ * write/read ordering problems.
+ */
+
+/*
+ * TLB flush IPI:
+ *
+ * 1) Flush the tlb entries if the cpu uses the mm that's being flushed.
+ * 2) Leave the mm if we are in the lazy tlb mode.
+ */
+
+asmlinkage void smp_invalidate_interrupt (void)
+{
+	unsigned long cpu = smp_processor_id();
+
+	if (!test_bit(cpu, &flush_cpumask))
+		return;
+		/* 
+		 * This was a BUG() but until someone can quote me the
+		 * line from the intel manual that guarantees an IPI to
+		 * multiple CPUs is retried _only_ on the erroring CPUs
+		 * its staying as a return
+		 *
+		 * BUG();
+		 */
+		 
+	if (flush_mm == cpu_tlbstate[cpu].active_mm) {
+		if (cpu_tlbstate[cpu].state == TLBSTATE_OK) {
+			if (flush_va == FLUSH_ALL)
+				local_flush_tlb();
+			else
+				__flush_tlb_one(flush_va);
+		} else
+			leave_mm(cpu);
+	}
+	ack_APIC_irq();
+	clear_bit(cpu, &flush_cpumask);
+}
+
+static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm,
+						unsigned long va)
+{
+	/*
+	 * A couple of (to be removed) sanity checks:
+	 *
+	 * - we do not send IPIs to not-yet booted CPUs.
+	 * - current CPU must not be in mask
+	 * - mask must exist :)
+	 */
+	if (!cpumask)
+		BUG();
+	if ((cpumask & cpu_online_map) != cpumask)
+		BUG();
+	if (cpumask & (1 << smp_processor_id()))
+		BUG();
+	if (!mm)
+		BUG();
+
+	/*
+	 * i'm not happy about this global shared spinlock in the
+	 * MM hot path, but we'll see how contended it is.
+	 * Temporarily this turns IRQs off, so that lockups are
+	 * detected by the NMI watchdog.
+	 */
+	spin_lock(&tlbstate_lock);
+	
+	flush_mm = mm;
+	flush_va = va;
+	atomic_set_mask(cpumask, &flush_cpumask);
+	/*
+	 * We have to send the IPI only to
+	 * CPUs affected.
+	 */
+	send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR);
+
+	while (flush_cpumask)
+		/* nothing. lockup detection does not belong here */;
+
+	flush_mm = NULL;
+	flush_va = 0;
+	spin_unlock(&tlbstate_lock);
+}
+	
+void flush_tlb_current_task(void)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id());
+
+	local_flush_tlb();
+	if (cpu_mask)
+		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+}
+
+void flush_tlb_mm (struct mm_struct * mm)
+{
+	unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id());
+
+	if (current->active_mm == mm) {
+		if (current->mm)
+			local_flush_tlb();
+		else
+			leave_mm(smp_processor_id());
+	}
+	if (cpu_mask)
+		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+}
+
+void flush_tlb_page(struct vm_area_struct * vma, unsigned long va)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id());
+
+	if (current->active_mm == mm) {
+		if(current->mm)
+			__flush_tlb_one(va);
+		 else
+		 	leave_mm(smp_processor_id());
+	}
+
+	if (cpu_mask)
+		flush_tlb_others(cpu_mask, mm, va);
+}
+
+static inline void do_flush_tlb_all_local(void)
+{
+	unsigned long cpu = smp_processor_id();
+
+	__flush_tlb_all();
+	if (cpu_tlbstate[cpu].state == TLBSTATE_LAZY)
+		leave_mm(cpu);
+}
+
+static void flush_tlb_all_ipi(void* info)
+{
+	do_flush_tlb_all_local();
+}
+
+void flush_tlb_all(void)
+{
+	smp_call_function (flush_tlb_all_ipi,0,1,1);
+
+	do_flush_tlb_all_local();
+}
+
+void smp_kdb_stop(void)
+{
+	send_IPI_allbutself(KDB_VECTOR);
+} 
+
+/*
+ * this function sends a 'reschedule' IPI to another CPU.
+ * it goes straight through and wastes no time serializing
+ * anything. Worst case is that we lose a reschedule ...
+ */
+
+void smp_send_reschedule(int cpu)
+{
+	send_IPI_mask(1 << cpu, RESCHEDULE_VECTOR);
+}
+
+/*
+ * Structure and data for smp_call_function(). This is designed to minimise
+ * static memory requirements. It also looks cleaner.
+ */
+static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
+
+struct call_data_struct {
+	void (*func) (void *info);
+	void *info;
+	atomic_t started;
+	atomic_t finished;
+	int wait;
+};
+
+static struct call_data_struct * call_data;
+
+/*
+ * this function sends a 'generic call function' IPI to all other CPUs
+ * in the system.
+ */
+
+int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
+			int wait)
+/*
+ * [SUMMARY] Run a function on all other CPUs.
+ * <func> The function to run. This must be fast and non-blocking.
+ * <info> An arbitrary pointer to pass to the function.
+ * <nonatomic> currently unused.
+ * <wait> If true, wait (atomically) until function has completed on other CPUs.
+ * [RETURNS] 0 on success, else a negative status code. Does not return until
+ * remote CPUs are nearly ready to execute <<func>> or are or have executed.
+ *
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler or from a bottom half handler.
+ */
+{
+	struct call_data_struct data;
+	int cpus = smp_num_cpus-1;
+
+	if (!cpus)
+		return 0;
+
+	data.func = func;
+	data.info = info;
+	atomic_set(&data.started, 0);
+	data.wait = wait;
+	if (wait)
+		atomic_set(&data.finished, 0);
+
+	spin_lock(&call_lock);
+	call_data = &data;
+	wmb();
+	/* Send a message to all other CPUs and wait for them to respond */
+	send_IPI_allbutself(CALL_FUNCTION_VECTOR);
+
+	/* Wait for response */
+	while (atomic_read(&data.started) != cpus)
+		barrier();
+
+	if (wait)
+		while (atomic_read(&data.finished) != cpus)
+			barrier();
+	spin_unlock(&call_lock);
+
+	return 0;
+}
+
+static void stop_this_cpu (void * dummy)
+{
+	/*
+	 * Remove this CPU:
+	 */
+	clear_bit(smp_processor_id(), &cpu_online_map);
+	__cli();
+	disable_local_APIC();
+	for(;;) __asm__("hlt");
+	for (;;);
+}
+
+/*
+ * this function calls the 'stop' function on all other CPUs in the system.
+ */
+
+void smp_send_stop(void)
+{
+	smp_call_function(stop_this_cpu, NULL, 1, 0);
+	smp_num_cpus = 1;
+
+	__cli();
+	disable_local_APIC();
+	__sti();
+}
+
+/*
+ * Reschedule call back. Nothing to do,
+ * all the work is done automatically when
+ * we return from the interrupt.
+ */
+asmlinkage void smp_reschedule_interrupt(void)
+{
+	ack_APIC_irq();
+}
+
+asmlinkage void smp_call_function_interrupt(void)
+{
+	void (*func) (void *info) = call_data->func;
+	void *info = call_data->info;
+	int wait = call_data->wait;
+
+	ack_APIC_irq();
+	/*
+	 * Notify initiating CPU that I've grabbed the data and am
+	 * about to execute the function
+	 */
+	mb();
+	atomic_inc(&call_data->started);
+	/*
+	 * At this point the info structure may be out of scope unless wait==1
+	 */
+	(*func)(info);
+	if (wait) {
+		mb();
+		atomic_inc(&call_data->finished);
+	}
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/smpboot.c linux-2.4.20/arch/x86_64/kernel/smpboot.c
--- linux-2.4.19/arch/x86_64/kernel/smpboot.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/smpboot.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,1006 @@
+/*
+ *	x86 SMP booting functions
+ *
+ *	(c) 1995 Alan Cox, Building #3 <alan@redhat.com>
+ *	(c) 1998, 1999, 2000 Ingo Molnar <mingo@redhat.com>
+ *	Copyright 2001 Andi Kleen, SuSE Labs.
+ *
+ *	Much of the core SMP work is based on previous work by Thomas Radke, to
+ *	whom a great many thanks are extended.
+ *
+ *	Thanks to Intel for making available several different Pentium,
+ *	Pentium Pro and Pentium-II/Xeon MP machines.
+ *	Original development of Linux SMP code supported by Caldera.
+ *
+ *	This code is released under the GNU General Public License version 2 or
+ *	later.
+ *
+ *	Fixes
+ *		Felix Koop	:	NR_CPUS used properly
+ *		Jose Renau	:	Handle single CPU case.
+ *		Alan Cox	:	By repeated request 8) - Total BogoMIP report.
+ *		Greg Wright	:	Fix for kernel stacks panic.
+ *		Erich Boleyn	:	MP v1.4 and additional changes.
+ *	Matthias Sattler	:	Changes for 2.1 kernel map.
+ *	Michel Lespinasse	:	Changes for 2.1 kernel map.
+ *	Michael Chastain	:	Change trampoline.S to gnu as.
+ *		Alan Cox	:	Dumb bug: 'B' step PPro's are fine
+ *		Ingo Molnar	:	Added APIC timers, based on code
+ *					from Jose Renau
+ *		Ingo Molnar	:	various cleanups and rewrites
+ *		Tigran Aivazian	:	fixed "0.00 in /proc/uptime on SMP" bug.
+ *	Maciej W. Rozycki	:	Bits for genuine 82489DX APICs
+ *	Andi Kleen		:	Changed for SMP boot into long mode.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <linux/mm.h>
+#include <linux/kernel_stat.h>
+#include <linux/smp_lock.h>
+#include <linux/irq.h>
+#include <linux/bootmem.h>
+
+#include <linux/delay.h>
+#include <linux/mc146818rtc.h>
+#include <asm/mtrr.h>
+#include <asm/pgalloc.h>
+#include <asm/desc.h>
+#include <asm/kdebug.h>
+#include <asm/timex.h>
+#include <asm/proto.h>
+
+/* Setup configured maximum number of CPUs to activate */
+static int max_cpus = -1;
+
+static int cpu_mask = -1; 
+
+/* Total count of live CPUs */
+int smp_num_cpus = 1;
+
+/* Bitmask of currently online CPUs */
+unsigned long cpu_online_map;
+
+/* which CPU (physical APIC ID) maps to which logical CPU number */
+volatile int x86_apicid_to_cpu[NR_CPUS];
+/* which logical CPU number maps to which CPU (physical APIC ID) */
+volatile int x86_cpu_to_apicid[NR_CPUS];
+
+static volatile unsigned long cpu_callin_map;
+static volatile unsigned long cpu_callout_map;
+
+/* Per CPU bogomips and other parameters */
+struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
+
+/* Set when the idlers are all forked */
+int smp_threads_ready;
+
+/*
+ * Setup routine for controlling SMP activation
+ *
+ * Command-line option of "nosmp" or "maxcpus=0" will disable SMP
+ * activation entirely (the MPS table probe still happens, though).
+ *
+ * Command-line option of "maxcpus=<NUM>", where <NUM> is an integer
+ * greater than 0, limits the maximum number of CPUs activated in
+ * SMP mode to <NUM>.
+ */
+
+static int __init nosmp(char *str)
+{
+	max_cpus = 0;
+	return 1;
+}
+
+__setup("nosmp", nosmp);
+
+static int __init maxcpus(char *str)
+{
+	get_option(&str, &max_cpus);
+	return 1;
+}
+
+__setup("maxcpus=", maxcpus);
+
+
+static int __init cpumask(char *str)
+{
+	get_option(&str, &cpu_mask);
+	return 1;
+}
+
+__setup("cpumask=", cpumask); 
+
+/*
+ * Trampoline 80x86 program as an array.
+ */
+
+extern unsigned char trampoline_data [];
+extern unsigned char trampoline_end  [];
+static unsigned char *trampoline_base;
+
+/*
+ * Currently trivial. Write the real->protected mode
+ * bootstrap into the page concerned. The caller
+ * has made sure it's suitably aligned.
+ */
+
+static unsigned long __init setup_trampoline(void)
+{
+	extern volatile __u32 tramp_gdt_ptr; 
+	tramp_gdt_ptr = __pa_symbol(&gdt_table); 
+	memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data);
+	return virt_to_phys(trampoline_base);
+}
+
+/*
+ * We are called very early to get the low memory for the
+ * SMP bootup trampoline page.
+ */
+void __init smp_alloc_memory(void)
+{
+	trampoline_base = __va(0x6000); /* reserved in setup.c */
+}
+
+/*
+ * The bootstrap kernel entry code has set these up. Save them for
+ * a given CPU
+ */
+
+void __init smp_store_cpu_info(int id)
+{
+	struct cpuinfo_x86 *c = cpu_data + id;
+
+	*c = boot_cpu_data;
+	identify_cpu(c);
+}
+
+/*
+ * Architecture specific routine called by the kernel just before init is
+ * fired off. This allows the BP to have everything in order [we hope].
+ * At the end of this all the APs will hit the system scheduling and off
+ * we go. Each AP will load the system gdt's and jump through the kernel
+ * init into idle(). At this point the scheduler will one day take over
+ * and give them jobs to do. smp_callin is a standard routine
+ * we use to track CPUs as they power up.
+ */
+
+static atomic_t smp_commenced = ATOMIC_INIT(0);
+
+void __init smp_commence(void)
+{
+	/*
+	 * Lets the callins below out of their loop.
+	 */
+	Dprintk("Setting commenced=1, go go go\n");
+
+	wmb();
+	atomic_set(&smp_commenced,1);
+}
+
+/*
+ * TSC synchronization.
+ *
+ * We first check wether all CPUs have their TSC's synchronized,
+ * then we print a warning if not, and always resync.
+ */
+
+static atomic_t tsc_start_flag = ATOMIC_INIT(0);
+static atomic_t tsc_count_start = ATOMIC_INIT(0);
+static atomic_t tsc_count_stop = ATOMIC_INIT(0);
+static unsigned long long tsc_values[NR_CPUS];
+
+#define NR_LOOPS 5
+
+static inline unsigned long long div64 (unsigned long long a, unsigned long b)
+{
+	return a/b;
+}
+
+static void __init synchronize_tsc_bp (void)
+{
+	int i;
+	unsigned long long t0;
+	unsigned long long sum, avg;
+	long long delta;
+	unsigned long one_usec;
+	int buggy = 0;
+
+	printk("checking TSC synchronization across CPUs: ");
+
+	one_usec = cpu_khz / 1000;
+
+	atomic_set(&tsc_start_flag, 1);
+	wmb();
+
+	/*
+	 * We loop a few times to get a primed instruction cache,
+	 * then the last pass is more or less synchronized and
+	 * the BP and APs set their cycle counters to zero all at
+	 * once. This reduces the chance of having random offsets
+	 * between the processors, and guarantees that the maximum
+	 * delay between the cycle counters is never bigger than
+	 * the latency of information-passing (cachelines) between
+	 * two CPUs.
+	 */
+	for (i = 0; i < NR_LOOPS; i++) {
+		/*
+		 * all APs synchronize but they loop on '== num_cpus'
+		 */
+		while (atomic_read(&tsc_count_start) != smp_num_cpus-1) mb();
+		atomic_set(&tsc_count_stop, 0);
+		wmb();
+		/*
+		 * this lets the APs save their current TSC:
+		 */
+		atomic_inc(&tsc_count_start);
+
+		rdtscll(tsc_values[smp_processor_id()]);
+		/*
+		 * We clear the TSC in the last loop:
+		 */
+		if (i == NR_LOOPS-1)
+			write_tsc(0, 0);
+
+		/*
+		 * Wait for all APs to leave the synchronization point:
+		 */
+		while (atomic_read(&tsc_count_stop) != smp_num_cpus-1) mb();
+		atomic_set(&tsc_count_start, 0);
+		wmb();
+		atomic_inc(&tsc_count_stop);
+	}
+
+	sum = 0;
+	for (i = 0; i < smp_num_cpus; i++) {
+		t0 = tsc_values[i];
+		sum += t0;
+	}
+	avg = div64(sum, smp_num_cpus);
+
+	sum = 0;
+	for (i = 0; i < smp_num_cpus; i++) {
+		delta = tsc_values[i] - avg;
+		if (delta < 0)
+			delta = -delta;
+		/*
+		 * We report bigger than 2 microseconds clock differences.
+		 */
+		if (delta > 2*one_usec) {
+			long realdelta;
+			if (!buggy) {
+				buggy = 1;
+				printk("\n");
+			}
+			realdelta = div64(delta, one_usec);
+			if (tsc_values[i] < avg)
+				realdelta = -realdelta;
+
+			printk("BIOS BUG: CPU#%d improperly initialized, has %ld usecs TSC skew! FIXED.\n",
+				i, realdelta);
+		}
+
+		sum += delta;
+	}
+	if (!buggy)
+		printk("passed.\n");
+}
+
+static void __init synchronize_tsc_ap (void)
+{
+	int i;
+
+	/*
+	 * smp_num_cpus is not necessarily known at the time
+	 * this gets called, so we first wait for the BP to
+	 * finish SMP initialization:
+	 */
+	while (!atomic_read(&tsc_start_flag)) mb();
+
+	for (i = 0; i < NR_LOOPS; i++) {
+		atomic_inc(&tsc_count_start);
+		while (atomic_read(&tsc_count_start) != smp_num_cpus) mb();
+
+		rdtscll(tsc_values[smp_processor_id()]);
+		if (i == NR_LOOPS-1)
+			write_tsc(0, 0);
+
+		atomic_inc(&tsc_count_stop);
+		while (atomic_read(&tsc_count_stop) != smp_num_cpus) mb();
+	}
+}
+#undef NR_LOOPS
+
+extern void calibrate_delay(void);
+
+static atomic_t init_deasserted;
+
+void __init smp_callin(void)
+{
+	int cpuid, phys_id;
+	unsigned long timeout;
+
+	/*
+	 * If waken up by an INIT in an 82489DX configuration
+	 * we may get here before an INIT-deassert IPI reaches
+	 * our local APIC.  We have to wait for the IPI or we'll
+	 * lock up on an APIC access.
+	 */
+	while (!atomic_read(&init_deasserted));
+
+	/*
+	 * (This works even if the APIC is not enabled.)
+	 */
+	phys_id = GET_APIC_ID(apic_read(APIC_ID));
+	cpuid = current->processor;
+	if (test_and_set_bit(cpuid, &cpu_online_map)) {
+		printk("huh, phys CPU#%d, CPU#%d already present??\n",
+					phys_id, cpuid);
+		BUG();
+	}
+	Dprintk("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpuid, phys_id);
+
+	/*
+	 * STARTUP IPIs are fragile beasts as they might sometimes
+	 * trigger some glue motherboard logic. Complete APIC bus
+	 * silence for 1 second, this overestimates the time the
+	 * boot CPU is spending to send the up to 2 STARTUP IPIs
+	 * by a factor of two. This should be enough.
+	 */
+
+	/*
+	 * Waiting 2s total for startup (udelay is not yet working)
+	 */
+	timeout = jiffies + 2*HZ;
+	while (time_before(jiffies, timeout)) {
+		/*
+		 * Has the boot CPU finished it's STARTUP sequence?
+		 */
+		if (test_bit(cpuid, &cpu_callout_map))
+			break;
+		rep_nop();
+	}
+
+	if (!time_before(jiffies, timeout)) {
+		printk("BUG: CPU%d started up but did not get a callout!\n",
+			cpuid);
+		BUG();
+	}
+
+	/*
+	 * the boot CPU has finished the init stage and is spinning
+	 * on callin_map until we finish. We are free to set up this
+	 * CPU, first the APIC. (this is probably redundant on most
+	 * boards)
+	 */
+
+	Dprintk("CALLIN, before setup_local_APIC().\n");
+	setup_local_APIC();
+
+	if (nmi_watchdog == NMI_IO_APIC) {
+		disable_8259A_irq(0);
+		enable_NMI_through_LVT0(NULL);
+		enable_8259A_irq(0);
+	}
+
+	sti();
+
+#ifdef CONFIG_MTRR
+	/*
+	 * Must be done before calibration delay is computed
+	 */
+	mtrr_init_secondary_cpu ();
+#endif
+	/*
+	 * Get our bogomips.
+	 */
+	calibrate_delay();
+	Dprintk("Stack at about %p\n",&cpuid);
+
+	/*
+	 * Save our processor parameters
+	 */
+ 	smp_store_cpu_info(cpuid);
+
+	notify_die(DIE_CPUINIT, "cpuinit", NULL, 0);
+
+	/*
+	 * Allow the master to continue.
+	 */
+	set_bit(cpuid, &cpu_callin_map);
+
+	/*
+	 *      Synchronize the TSC with the BP
+	 */
+	if (cpu_has_tsc)
+		synchronize_tsc_ap();
+}
+
+int cpucount;
+
+/*
+ * Activate a secondary processor.
+ */
+int __init start_secondary(void *unused)
+{
+	/*
+	 * Dont put anything before smp_callin(), SMP
+	 * booting is too fragile that we want to limit the
+	 * things done here to the most necessary things.
+	 */
+	cpu_init();
+	smp_callin();
+	while (!atomic_read(&smp_commenced))
+		rep_nop();
+	/*
+	 * low-memory mappings have been cleared, flush them from
+	 * the local TLBs too.
+	 */
+	local_flush_tlb();
+
+	cpu_idle();
+	return 0;
+}
+
+/*
+ * Everything has been set up for the secondary
+ * CPUs - they just need to reload everything
+ * from the task structure
+ * This function must not return.
+ */
+void __init initialize_secondary(void)
+{
+	struct task_struct *me = stack_current();
+
+	/*
+	 * We don't actually need to load the full TSS,
+	 * basically just the stack pointer and the eip.
+	 */
+
+	asm volatile(
+		"movq %0,%%rsp\n\t"
+		"jmp *%1"
+		:
+		:"r" (me->thread.rsp),"r" (me->thread.rip));
+}
+
+extern volatile void *init_rsp; 
+extern void (*initial_code)(void);
+
+static int __init fork_by_hand(void)
+{
+	struct pt_regs regs;
+	/*
+	 * don't care about the eip and regs settings since
+	 * we'll never reschedule the forked task.
+	 */
+	return do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0);
+}
+
+#if APIC_DEBUG
+static inline void inquire_remote_apic(int apicid)
+{
+	int i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
+	char *names[] = { "ID", "VERSION", "SPIV" };
+	int timeout, status;
+
+	printk("Inquiring remote APIC #%d...\n", apicid);
+
+	for (i = 0; i < sizeof(regs) / sizeof(*regs); i++) {
+		printk("... APIC #%d %s: ", apicid, names[i]);
+
+		/*
+		 * Wait for idle.
+		 */
+		apic_wait_icr_idle();
+
+		apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+		apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]);
+
+		timeout = 0;
+		do {
+			udelay(100);
+			status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK;
+		} while (status == APIC_ICR_RR_INPROG && timeout++ < 1000);
+
+		switch (status) {
+		case APIC_ICR_RR_VALID:
+			status = apic_read(APIC_RRR);
+			printk("%08x\n", status);
+			break;
+		default:
+			printk("failed\n");
+		}
+	}
+}
+#endif
+
+static int __init do_boot_cpu (int apicid)
+{
+	struct task_struct *idle;
+	unsigned long send_status, accept_status, boot_status, maxlvt;
+	int timeout, num_starts, j, cpu;
+	unsigned long start_eip;
+
+	cpu = ++cpucount;
+
+	/*
+	 * We can't use kernel_thread since we must avoid to
+	 * reschedule the child.
+	 */
+	if (fork_by_hand() < 0)
+		panic("failed fork for CPU %d", cpu);
+
+	/*
+	 * We remove it from the pidhash and the runqueue
+	 * once we got the process:
+	 */
+	idle = init_task.prev_task;
+	if (!idle)
+		panic("No idle process for CPU %d", cpu);
+
+	idle->processor = cpu;
+	x86_cpu_to_apicid[cpu] = apicid;
+	x86_apicid_to_cpu[apicid] = cpu;
+	idle->cpus_runnable = 1<<cpu; 
+	idle->cpus_allowed = 1<<cpu;
+	idle->thread.rip = (unsigned long)start_secondary;
+	idle->thread.rsp = (unsigned long)idle + THREAD_SIZE - 8;
+
+	del_from_runqueue(idle);
+	unhash_process(idle);
+	cpu_pda[cpu].pcurrent = init_tasks[cpu] = idle;
+
+	/* start_eip had better be page-aligned! */
+	start_eip = setup_trampoline();
+
+	/* So we see what's up   */
+	printk("Booting processor %d/%d rip %lx page %p\n", cpu, apicid, start_eip, idle);
+	init_rsp = (void *) (THREAD_SIZE + (char *)idle - 16);
+	initial_code = initialize_secondary; 
+
+	/*
+	 * This grunge runs the startup process for
+	 * the targeted processor.
+	 */
+
+	atomic_set(&init_deasserted, 0);
+
+	Dprintk("Setting warm reset code and vector.\n");
+
+	CMOS_WRITE(0xa, 0xf);
+	local_flush_tlb();
+	Dprintk("1.\n");
+	*((volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4;
+	Dprintk("2.\n");
+	*((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf;
+	Dprintk("3.\n");
+
+	/*
+	 * Be paranoid about clearing APIC errors.
+	 */
+	if (APIC_INTEGRATED(apic_version[apicid])) {
+		apic_read_around(APIC_SPIV);
+		apic_write(APIC_ESR, 0);
+		apic_read(APIC_ESR);
+	}
+
+	/*
+	 * Status is now clean
+	 */
+	send_status = 0;
+	accept_status = 0;
+	boot_status = 0;
+
+	/*
+	 * Starting actual IPI sequence...
+	 */
+
+	Dprintk("Asserting INIT.\n");
+
+	/*
+	 * Turn INIT on target chip
+	 */
+	apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+
+	/*
+	 * Send IPI
+	 */
+	apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
+				| APIC_DM_INIT);
+
+	Dprintk("Waiting for send to finish...\n");
+	timeout = 0;
+	do {
+		Dprintk("+");
+		udelay(100);
+		send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+	} while (send_status && (timeout++ < 1000));
+
+	mdelay(10);
+
+	Dprintk("Deasserting INIT.\n");
+
+	/* Target chip */
+	apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+
+	/* Send IPI */
+	apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
+
+	Dprintk("Waiting for send to finish...\n");
+	timeout = 0;
+	do {
+		Dprintk("+");
+		udelay(100);
+		send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+	} while (send_status && (timeout++ < 1000));
+
+	atomic_set(&init_deasserted, 1);
+
+	/*
+	 * Should we send STARTUP IPIs ?
+	 *
+	 * Determine this based on the APIC version.
+	 * If we don't have an integrated APIC, don't
+	 * send the STARTUP IPIs.
+	 */
+	if (APIC_INTEGRATED(apic_version[apicid]))
+		num_starts = 2;
+	else
+		num_starts = 0;
+
+	/*
+	 * Run STARTUP IPI loop.
+	 */
+	Dprintk("#startup loops: %d.\n", num_starts);
+
+	maxlvt = get_maxlvt();
+
+	for (j = 1; j <= num_starts; j++) {
+		Dprintk("Sending STARTUP #%d.\n",j);
+		apic_read_around(APIC_SPIV);
+		apic_write(APIC_ESR, 0);
+		apic_read(APIC_ESR);
+		Dprintk("After apic_write.\n");
+
+		/*
+		 * STARTUP IPI
+		 */
+
+		/* Target chip */
+		Dprintk("target apic %x\n", SET_APIC_DEST_FIELD(apicid));
+		apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+
+		Dprintk("after target chip\n"); 
+
+		/* Boot on the stack */
+		/* Kick the second */
+		apic_write_around(APIC_ICR, APIC_DM_STARTUP
+					| (start_eip >> 12));
+
+		Dprintk("after eip write\n"); 
+
+		/*
+		 * Give the other CPU some time to accept the IPI.
+		 */
+		udelay(300);
+
+		Dprintk("Startup point 1.\n");
+
+		Dprintk("Waiting for send to finish...\n");
+		timeout = 0;
+		do {
+			Dprintk("+");
+			udelay(100);
+			send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+		} while (send_status && (timeout++ < 1000));
+
+		/*
+		 * Give the other CPU some time to accept the IPI.
+		 */
+		udelay(200);
+		/*
+		 * Due to the Pentium erratum 3AP.
+		 */
+		if (maxlvt > 3) {
+			apic_read_around(APIC_SPIV);
+			apic_write(APIC_ESR, 0);
+		}
+		accept_status = (apic_read(APIC_ESR) & 0xEF);
+		if (send_status || accept_status)
+			break;
+	}
+	Dprintk("After Startup.\n");
+
+	if (send_status)
+		printk("APIC never delivered???\n");
+	if (accept_status)
+		printk("APIC delivery error (%lx).\n", accept_status);
+
+	if (!send_status && !accept_status) {
+		/*
+		 * allow APs to start initializing.
+		 */
+		Dprintk("Before Callout %d.\n", cpu);
+		set_bit(cpu, &cpu_callout_map);
+		Dprintk("After Callout %d.\n", cpu);
+
+		/*
+		 * Wait 5s total for a response
+		 */
+		for (timeout = 0; timeout < 50000; timeout++) {
+			if (test_bit(cpu, &cpu_callin_map))
+				break;	/* It has booted */
+			udelay(100);
+		}
+
+		if (test_bit(cpu, &cpu_callin_map)) {
+			/* number CPUs logically, starting from 1 (BSP is 0) */
+			Dprintk("OK.\n");
+			printk("CPU%d: ", cpu);
+			print_cpu_info(&cpu_data[cpu]);
+			Dprintk("CPU has booted.\n");
+		} else {
+			boot_status = 1;
+			if (*((volatile unsigned char *)phys_to_virt(8192))
+					== 0xA5)
+				/* trampoline started but...? */
+				printk("Stuck ??\n");
+			else
+				/* trampoline code not run */
+				printk("Not responding.\n");
+#if APIC_DEBUG
+			inquire_remote_apic(apicid);
+#endif
+		}
+	}
+	if (send_status || accept_status || boot_status) {
+		x86_cpu_to_apicid[cpu] = -1;
+		x86_apicid_to_cpu[apicid] = -1;
+		cpucount--;
+	}
+
+	/* mark "stuck" area as not stuck */
+	*((volatile unsigned int *)phys_to_virt(8192)) = 0;
+	
+	return cpu; 
+}
+
+cycles_t cacheflush_time;
+
+static __init void smp_tune_scheduling (void)
+{
+	unsigned long cachesize;       /* kB   */
+	unsigned long bandwidth = 350; /* MB/s */
+	/*
+	 * Rough estimation for SMP scheduling, this is the number of
+	 * cycles it takes for a fully memory-limited process to flush
+	 * the SMP-local cache.
+	 *
+	 * (For a P5 this pretty much means we will choose another idle
+	 *  CPU almost always at wakeup time (this is due to the small
+	 *  L1 cache), on PIIs it's around 50-100 usecs, depending on
+	 *  the cache size)
+	 */
+
+	if (!cpu_khz) {
+		/*
+		 * this basically disables processor-affinity
+		 * scheduling on SMP without a TSC.
+		 */
+		cacheflush_time = 0;
+		return;
+	} else {
+		cachesize = boot_cpu_data.x86_cache_size;
+		if (cachesize == -1) {
+			cachesize = 16; /* Pentiums, 2x8kB cache */
+			bandwidth = 100;
+		}
+
+		cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth;
+	}
+
+	printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
+		(long)cacheflush_time/(cpu_khz/1000),
+		((long)cacheflush_time*100/(cpu_khz/1000)) % 100);
+}
+
+/*
+ * Cycle through the processors sending APIC IPIs to boot each.
+ */
+
+extern int prof_multiplier[NR_CPUS];
+extern int prof_old_multiplier[NR_CPUS];
+extern int prof_counter[NR_CPUS];
+
+void __init smp_boot_cpus(void)
+{
+	int apicid, cpu, maxcpu;
+
+#ifdef CONFIG_MTRR
+	/*  Must be done before other processors booted  */
+	mtrr_init_boot_cpu ();
+#endif
+	/*
+	 * Initialize the logical to physical CPU number mapping
+	 * and the per-CPU profiling counter/multiplier
+	 */
+
+	for (apicid = 0; apicid < NR_CPUS; apicid++) {
+		x86_apicid_to_cpu[apicid] = -1;
+		prof_counter[apicid] = 1;
+		prof_old_multiplier[apicid] = 1;
+		prof_multiplier[apicid] = 1;
+	}
+
+	/*
+	 * Setup boot CPU information
+	 */
+	smp_store_cpu_info(0); /* Final full version of the data */
+	printk("CPU%d: ", 0);
+	print_cpu_info(&cpu_data[0]);
+
+	/*
+	 * We have the boot CPU online for sure.
+	 */
+	set_bit(0, &cpu_online_map);
+	x86_apicid_to_cpu[boot_cpu_id] = 0;
+	x86_cpu_to_apicid[0] = boot_cpu_id;
+	global_irq_holder = 0;
+	current->processor = 0;
+	init_idle();
+	smp_tune_scheduling();
+
+	/*
+	 * If we couldnt find an SMP configuration at boot time,
+	 * get out of here now!
+	 */
+	if (!smp_found_config) {
+		printk(KERN_NOTICE "SMP motherboard not detected.\n");
+		io_apic_irqs = 0;
+		cpu_online_map = phys_cpu_present_map = 1;
+		smp_num_cpus = 1;
+		if (APIC_init_uniprocessor())
+			printk(KERN_NOTICE "Local APIC not detected."
+					   " Using dummy APIC emulation.\n");
+		goto smp_done;
+	}
+
+	/*
+	 * Should not be necessary because the MP table should list the boot
+	 * CPU too, but we do it for the sake of robustness anyway.
+	 */
+	if (!test_bit(boot_cpu_id, &phys_cpu_present_map)) {
+		printk("weird, boot CPU (#%d) not listed by the BIOS.\n",
+								 boot_cpu_id);
+		phys_cpu_present_map |= (1 << hard_smp_processor_id());
+	}
+
+	/*
+	 * If we couldn't find a local APIC, then get out of here now!
+	 */
+	if (APIC_INTEGRATED(apic_version[boot_cpu_id]) &&
+	    !test_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability)) {
+		printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
+			boot_cpu_id);
+		printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
+		io_apic_irqs = 0;
+		cpu_online_map = phys_cpu_present_map = 1;
+		smp_num_cpus = 1;
+		goto smp_done;
+	}
+
+	verify_local_APIC();
+
+	/*
+	 * If SMP should be disabled, then really disable it!
+	 */
+	if (!max_cpus) {
+		smp_found_config = 0;
+		printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
+		io_apic_irqs = 0;
+		cpu_online_map = phys_cpu_present_map = 1;
+		smp_num_cpus = 1;
+		goto smp_done;
+	}
+
+	connect_bsp_APIC();
+	setup_local_APIC();
+
+	if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_id)
+		BUG();
+
+	/*
+	 * Now scan the CPU present map and fire up the other CPUs.
+	 */
+	Dprintk("CPU present map: %lx\n", phys_cpu_present_map);
+
+	maxcpu = 0;
+	for (apicid = 0; apicid < NR_CPUS; apicid++) {
+		/*
+		 * Don't even attempt to start the boot CPU!
+		 */
+		if (apicid == boot_cpu_id)
+			continue;
+
+		if (!(phys_cpu_present_map & (1 << apicid)))
+			continue;
+		if (((1<<apicid) & cpu_mask) == 0) 
+			continue;
+		if ((max_cpus >= 0) && (max_cpus <= cpucount+1))
+			continue;
+
+		cpu = do_boot_cpu(apicid);
+
+		/*
+		 * Make sure we unmap all failed CPUs
+		 */
+		if ((x86_apicid_to_cpu[apicid] == -1) &&
+				(phys_cpu_present_map & (1 << apicid)))
+			printk("phys CPU #%d not responding - cannot use it.\n",apicid);
+		else if (cpu > maxcpu) 
+			maxcpu = cpu; 
+	}
+
+	/*
+	 * Cleanup possible dangling ends...
+	 */
+	{
+		/*
+		 * Install writable page 0 entry to set BIOS data area.
+		 */
+		local_flush_tlb();
+
+		/*
+		 * Paranoid:  Set warm reset code and vector here back
+		 * to default values.
+		 */
+		CMOS_WRITE(0, 0xf);
+
+		*((volatile int *) phys_to_virt(0x467)) = 0;
+	}
+
+	/*
+	 * Allow the user to impress friends.
+	 */
+
+	Dprintk("Before bogomips.\n");
+	if (!cpucount) {
+		printk(KERN_ERR "Only one processor found.\n");
+	} else {
+		unsigned long bogosum = 0;
+		for (cpu = 0; cpu < NR_CPUS; cpu++)
+			if (cpu_online_map & (1<<cpu))
+				bogosum += cpu_data[cpu].loops_per_jiffy;
+		printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+			cpucount+1,
+			bogosum/(500000/HZ),
+			(bogosum/(5000/HZ))%100);
+		Dprintk("Before bogocount - setting activated=1.\n");
+	}
+	smp_num_cpus = maxcpu + 1;
+
+	Dprintk("Boot done.\n");
+
+	/*
+	 * Here we can be sure that there is an IO-APIC in the system. Let's
+	 * go and set it up:
+	 */
+	if (!skip_ioapic_setup && nr_ioapics)
+		setup_IO_APIC();
+
+	/*
+	 * Set up all local APIC timers in the system:
+	 */
+	setup_APIC_clocks();
+
+	/*
+	 * Synchronize the TSC with the AP
+	 */
+	if (cpu_has_tsc && cpucount)
+		synchronize_tsc_bp();
+
+smp_done:
+	zap_low_mappings();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/sys_x86_64.c linux-2.4.20/arch/x86_64/kernel/sys_x86_64.c
--- linux-2.4.19/arch/x86_64/kernel/sys_x86_64.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/sys_x86_64.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,119 @@
+/*
+ * linux/arch/x86_64/kernel/sys_x86_64.c
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+#include <linux/utsname.h>
+#include <linux/personality.h>
+
+#include <asm/uaccess.h>
+#include <asm/ipc.h>
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way Unix traditionally does this, though.
+ */
+asmlinkage long sys_pipe(unsigned long * fildes)
+{
+	int fd[2];
+	int error;
+
+	error = do_pipe(fd);
+	if (!error) {
+		if (copy_to_user(fildes, fd, 2*sizeof(int)))
+			error = -EFAULT;
+	}
+	return error;
+}
+
+long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
+	unsigned long fd, unsigned long off)
+{
+	long error;
+	struct file * file;
+
+	error = -EINVAL;
+	if (off & ~PAGE_MASK)
+		goto out;
+
+	error = -EBADF;
+	file = NULL;
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	if (!(flags & MAP_ANONYMOUS)) {
+		file = fget(fd);
+		if (!file)
+			goto out;
+	}
+
+	down_write(&current->mm->mmap_sem);
+	error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT);
+	up_write(&current->mm->mmap_sem);
+
+	if (file)
+		fput(file);
+out:
+	return error;
+}
+
+unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+	struct vm_area_struct *vma;
+	unsigned long end = TASK_SIZE;
+
+	if (current->thread.flags & THREAD_IA32)
+		flags |= MAP_32BIT; 
+	if (flags & MAP_32BIT)
+		end = 0xffffffff-1;
+	if (len > end)
+		return -ENOMEM;
+	if (!addr) { 
+		addr = TASK_UNMAPPED_64;
+		if (flags & MAP_32BIT) {
+			addr = TASK_UNMAPPED_32;
+		}
+	} 
+	addr = PAGE_ALIGN(addr);
+
+	for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
+		/* At this point:  (!vma || addr < vma->vm_end). */
+		if (end - len < addr)
+			return -ENOMEM;
+		if (!vma || addr + len <= vma->vm_start)
+			return addr;
+		addr = vma->vm_end;
+	}
+}
+
+asmlinkage long sys_uname(struct new_utsname * name)
+{
+	int err;
+	down_read(&uts_sem);
+	err=copy_to_user(name, &system_utsname, sizeof (*name));
+	up_read(&uts_sem);
+	if (personality(current->personality) == PER_LINUX32)
+		err = copy_to_user(name->machine, "i686", 5);
+	return err?-EFAULT:0;
+}
+
+asmlinkage long sys_pause(void)
+{
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	return -ERESTARTNOHAND;
+}
+
+asmlinkage long wrap_sys_shmat(int shmid, char *shmaddr, int shmflg)
+{
+	unsigned long raddr;
+	return sys_shmat(shmid,shmaddr,shmflg,&raddr) ?: raddr;
+} 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/syscall.c linux-2.4.20/arch/x86_64/kernel/syscall.c
--- linux-2.4.19/arch/x86_64/kernel/syscall.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/syscall.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,25 @@
+/* System call table for x86-64. */ 
+
+#include <linux/linkage.h>
+#include <linux/sys.h>
+#include <linux/cache.h>
+
+#define __NO_STUBS
+
+#define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ; 
+#undef _ASM_X86_64_UNISTD_H_
+#include <asm-x86_64/unistd.h>
+
+#undef __SYSCALL
+#define __SYSCALL(nr, sym) [ nr ] = sym, 
+#undef _ASM_X86_64_UNISTD_H_
+
+typedef void (*sys_call_ptr_t)(void); 
+
+extern void sys_ni_syscall(void);
+
+sys_call_ptr_t sys_call_table[__NR_syscall_max+1] __cacheline_aligned = { 
+	/* Smells like a like a compiler bug -- it doesn't work when the & below is removed. */ 
+	[0 ... __NR_syscall_max] = &sys_ni_syscall,
+#include <asm-x86_64/unistd.h>
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/time.c linux-2.4.20/arch/x86_64/kernel/time.c
--- linux-2.4.19/arch/x86_64/kernel/time.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/time.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,445 @@
+/*
+ *  linux/arch/x86-64/kernel/time.c
+ *
+ *  "High Precision Event Timer" based timekeeping.
+ *
+ *  Copyright (c) 1991,1992,1995  Linus Torvalds
+ *  Copyright (c) 1994  Alan Modra
+ *  Copyright (c) 1995  Markus Kuhn
+ *  Copyright (c) 1996  Ingo Molnar
+ *  Copyright (c) 1998  Andrea Arcangeli
+ *  Copyright (c) 2002  Vojtech Pavlik
+ *
+ */
+
+#define HPET_BIOS_SUPPORT_WORKING
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/mc146818rtc.h>
+#include <linux/irq.h>
+#include <linux/ioport.h>
+#include <asm/vsyscall.h>
+#include <asm/timex.h>
+
+extern rwlock_t xtime_lock;
+spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+
+unsigned int cpu_khz;					/* TSC clocks / usec, not used here */
+unsigned long hpet_period;				/* fsecs / HPET clock */
+unsigned long hpet_tick;				/* HPET clocks / interrupt */
+int hpet_report_lost_ticks;				/* command line option */
+
+struct hpet_data __hpet __section_hpet;			/* address, quotient, trigger, hz */
+
+volatile unsigned long __jiffies __section_jiffies;
+unsigned long __wall_jiffies __section_wall_jiffies;
+struct timeval __xtime __section_xtime;
+struct timezone __sys_tz __section_sys_tz;
+
+/*
+ * do_gettimeoffset() returns microseconds since last timer interrupt was
+ * triggered by hardware. A memory read of HPET is slower than a register read
+ * of TSC, but much more reliable. It's also synchronized to the timer
+ * interrupt. Note that do_gettimeoffset() may return more than hpet_tick, if a
+ * timer interrupt has happened already, but hpet.trigger wasn't updated yet.
+ * This is not a problem, because jiffies hasn't updated either. They are bound
+ * together by xtime_lock.
+ */
+
+static spinlock_t time_offset_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long timeoffset = 0;
+
+inline unsigned int do_gettimeoffset(void)
+{
+	unsigned long t;
+	rdtscll(t);	
+	return (t  - hpet.last_tsc) * (1000000L / HZ) / hpet.ticks + hpet.offset;
+}
+
+/*
+ * This version of gettimeofday() has microsecond resolution and better than
+ * microsecond precision, as we're using at least a 10 MHz (usually 14.31818
+ * MHz) HPET timer.
+ */
+
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned long flags, t;
+ 	unsigned int sec, usec;
+
+	read_lock_irqsave(&xtime_lock, flags);
+	spin_lock(&time_offset_lock);
+
+	sec = xtime.tv_sec;
+	usec = xtime.tv_usec;
+
+	t = (jiffies - wall_jiffies) * (1000000L / HZ) + do_gettimeoffset();
+	if (t > timeoffset) timeoffset = t;
+	usec += timeoffset;
+
+	spin_unlock(&time_offset_lock);
+	read_unlock_irqrestore(&xtime_lock, flags);
+
+	tv->tv_sec = sec + usec / 1000000;
+	tv->tv_usec = usec % 1000000;
+}
+
+/*
+ * settimeofday() first undoes the correction that gettimeofday would do
+ * on the time, and then saves it. This is ugly, but has been like this for
+ * ages already.
+ */
+
+void do_settimeofday(struct timeval *tv)
+{
+	write_lock_irq(&xtime_lock);
+	vxtime_lock();
+
+	tv->tv_usec -= do_gettimeoffset() +
+		(jiffies - wall_jiffies) * tick;
+
+	while (tv->tv_usec < 0) {
+		tv->tv_usec += 1000000;
+		tv->tv_sec--;
+	}
+
+	xtime = *tv;
+	vxtime_unlock();
+
+	time_adjust = 0;		/* stop active adjtime() */
+	time_status |= STA_UNSYNC;
+	time_maxerror = NTP_PHASE_LIMIT;
+	time_esterror = NTP_PHASE_LIMIT;
+
+	write_unlock_irq(&xtime_lock);
+}
+
+/*
+ * In order to set the CMOS clock precisely, set_rtc_mmss has to be called 500
+ * ms after the second nowtime has started, because when nowtime is written
+ * into the registers of the CMOS clock, it will jump to the next second
+ * precisely 500 ms later. Check the Motorola MC146818A or Dallas DS12887 data
+ * sheet for details.
+ */
+
+static void set_rtc_mmss(unsigned long nowtime)
+{
+	int real_seconds, real_minutes, cmos_minutes;
+	unsigned char control, freq_select;
+
+/*
+ * IRQs are disabled when we're called from the timer interrupt,
+ * no need for spin_lock_irqsave()
+ */
+
+	spin_lock(&rtc_lock);
+
+/*
+ * Tell the clock it's being set and stop it.
+ */
+
+	control = CMOS_READ(RTC_CONTROL);
+	CMOS_WRITE(control | RTC_SET, RTC_CONTROL);
+
+	freq_select = CMOS_READ(RTC_FREQ_SELECT);
+	CMOS_WRITE(freq_select | RTC_DIV_RESET2, RTC_FREQ_SELECT);
+
+	cmos_minutes = CMOS_READ(RTC_MINUTES);
+	BCD_TO_BIN(cmos_minutes);
+
+/*
+ * since we're only adjusting minutes and seconds, don't interfere with hour
+ * overflow. This avoids messing with unknown time zones but requires your RTC
+ * not to be off by more than 15 minutes. Since we're calling it only when
+ * our clock is externally synchronized using NTP, this shouldn't be a problem.
+ */
+
+	real_seconds = nowtime % 60;
+	real_minutes = nowtime / 60;
+	if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
+		real_minutes += 30;	/* correct for half hour time zone */
+	real_minutes %= 60;
+
+	if (abs(real_minutes - cmos_minutes) < 30) {
+		BIN_TO_BCD(real_seconds);
+		BIN_TO_BCD(real_minutes);
+		CMOS_WRITE(real_seconds, RTC_SECONDS);
+		CMOS_WRITE(real_minutes, RTC_MINUTES);
+	} else
+		printk(KERN_WARNING "time.c: can't update CMOS clock from %d to %d\n",
+			cmos_minutes, real_minutes);
+
+/*
+ * The following flags have to be released exactly in this order, otherwise the
+ * DS12887 (popular MC146818A clone with integrated battery and quartz) will
+ * not reset the oscillator and will not update precisely 500 ms later. You
+ * won't find this mentioned in the Dallas Semiconductor data sheets, but who
+ * believes data sheets anyway ... -- Markus Kuhn
+ */
+
+	CMOS_WRITE(control, RTC_CONTROL);
+	CMOS_WRITE(freq_select, RTC_FREQ_SELECT);
+
+	spin_unlock(&rtc_lock);
+}
+
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	static unsigned long rtc_update = 0;
+
+/*
+ * Here we are in the timer irq handler. We have irqs locally disabled (so we
+ * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running
+ * on the other CPU, so we need a lock. We also need to lock the vsyscall
+ * variables, because both do_timer() and us change them -arca+vojtech
+ */
+
+	write_lock(&xtime_lock);
+	vxtime_lock();
+
+	{
+		unsigned long t;
+
+		rdtscll(t);
+		hpet.offset = (t  - hpet.last_tsc) * (1000000L / HZ) / hpet.ticks + hpet.offset - 1000000L / HZ;
+		if (hpet.offset >= 1000000L / HZ)
+			hpet.offset = 0;
+		hpet.ticks = min_t(long, max_t(long, (t  - hpet.last_tsc) * (1000000L / HZ) / (1000000L / HZ - hpet.offset),
+				cpu_khz * 1000/HZ * 15 / 16), cpu_khz * 1000/HZ * 16 / 15); 
+		hpet.last_tsc = t;
+	}
+
+/*
+ * Do the timer stuff.
+ */
+
+	do_timer(regs);
+
+/*
+ * If we have an externally synchronized Linux clock, then update CMOS clock
+ * accordingly every ~11 minutes. set_rtc_mmss() will be called in the jiffy
+ * closest to exactly 500 ms before the next second. If the update fails, we
+ * don'tcare, as it'll be updated on the next turn, and the problem (time way
+ * off) isn't likely to go away much sooner anyway.
+ */
+
+	if ((~time_status & STA_UNSYNC) && xtime.tv_sec > rtc_update &&
+		abs(xtime.tv_usec - 500000) <= tick / 2) {
+		set_rtc_mmss(xtime.tv_sec);
+		rtc_update = xtime.tv_sec + 660;
+	}
+
+	vxtime_unlock();
+	write_unlock(&xtime_lock);
+}
+
+static unsigned long get_cmos_time(void)
+{
+	unsigned int timeout, year, mon, day, hour, min, sec;
+	unsigned char last, this;
+
+/*
+ * The Linux interpretation of the CMOS clock register contents: When the
+ * Update-In-Progress (UIP) flag goes from 1 to 0, the RTC registers show the
+ * second which has precisely just started. Waiting for this can take up to 1
+ * second, we timeout approximately after 2.4 seconds on a machine with
+ * standard 8.3 MHz ISA bus.
+ */
+
+	spin_lock(&rtc_lock);
+
+	timeout = 1000000;
+	last = this = 0;
+
+	while (timeout && last && !this) {
+		last = this;
+		this = CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP;
+		timeout--;
+	}
+
+/*
+ * Here we are safe to assume the registers won't change for a whole second, so
+ * we just go ahead and read them.
+ */
+
+	sec = CMOS_READ(RTC_SECONDS);
+	min = CMOS_READ(RTC_MINUTES);
+	hour = CMOS_READ(RTC_HOURS);
+	day = CMOS_READ(RTC_DAY_OF_MONTH);
+	mon = CMOS_READ(RTC_MONTH);
+	year = CMOS_READ(RTC_YEAR);
+
+	spin_unlock(&rtc_lock);
+
+/*
+ * We know that x86-64 always uses BCD format, no need to check the config
+ * register.
+ */
+
+	BCD_TO_BIN(sec);
+	BCD_TO_BIN(min);
+	BCD_TO_BIN(hour);
+	BCD_TO_BIN(day);
+	BCD_TO_BIN(mon);
+	BCD_TO_BIN(year);
+
+/*
+ * This will work up to Dec 31, 2069.
+ */
+
+	if ((year += 1900) < 1970)
+		year += 100;
+
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+/*
+ * calibrate_tsc() calibrates the processor TSC in a very simple way, comparing
+ * it to the HPET timer of known frequency.
+ */
+
+#define TICK_COUNT 100000000
+
+static unsigned int __init hpet_calibrate_tsc(void)
+{
+	int tsc_start, hpet_start;
+	int tsc_now, hpet_now;
+	unsigned long flags;
+
+	__save_flags(flags);
+	__cli();
+
+	hpet_start = hpet_readl(HPET_COUNTER);
+	rdtscl(tsc_start);
+
+	do {
+		__cli();
+		hpet_now = hpet_readl(HPET_COUNTER);
+		rdtscl(tsc_now);
+		__restore_flags(flags);
+	} while ((tsc_now - tsc_start) < TICK_COUNT && (hpet_now - hpet_start) < TICK_COUNT);
+
+	return (tsc_now - tsc_start) * 1000000000L
+		/ ((hpet_now - hpet_start) * hpet_period / 1000);
+}
+
+/*
+ * pit_calibrate_tsc() uses the speaker output (channel 2) of
+ * the PIT. This is better than using the timer interrupt output,
+ * because we can read the value of the speaker with just one inb(),
+ * where we need three i/o operations for the interrupt channel.
+ * We count how many ticks the TSC does in 50 ms.
+ */
+
+static unsigned int __init pit_calibrate_tsc(void)
+{
+	unsigned long start, end;
+	unsigned long flags;
+
+	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+	__save_flags(flags);
+	__cli();
+
+	outb(0xb0, 0x43);
+	outb((1193182 / (1000 / 50)) & 0xff, 0x42);
+	outb((1193182 / (1000 / 50)) >> 8, 0x42);
+	rdtscll(start);
+
+	while ((inb(0x61) & 0x20) == 0);
+	rdtscll(end);
+
+	__restore_flags(flags);
+
+	return (end - start) / 50;
+}
+
+static int hpet_init(void)
+{
+	unsigned int cfg, id;
+
+	if (!hpet.address)
+		return -1;
+	set_fixmap_nocache(FIX_HPET_BASE, hpet.address);
+
+/*
+ * Read the period, compute tick and quotient.
+ */
+
+	id = hpet_readl(HPET_ID);
+
+	if (!(id & HPET_ID_VENDOR) || !(id & HPET_ID_NUMBER) || !(id & HPET_ID_LEGSUP))
+		return -1;
+
+	hpet_period = hpet_readl(HPET_PERIOD);
+	if (hpet_period < 100000 || hpet_period > 100000000)
+		return -1;
+
+	hpet_tick = (1000000000L * tick + hpet_period / 2) / hpet_period;
+
+/*
+ * Stop the timers and reset the main counter.
+ */
+
+	cfg = hpet_readl(HPET_CFG);
+	cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY);
+	hpet_writel(cfg, HPET_CFG);
+	hpet_writel(0, HPET_COUNTER);
+	hpet_writel(0, HPET_COUNTER + 4);
+
+/*
+ * Set up timer 0, as periodic with first interrupt to happen at hpet_tick,
+ * and period also hpet_tick.
+ */
+
+	hpet_writel(HPET_T0_ENABLE | HPET_T0_PERIODIC | HPET_T0_SETVAL | HPET_T0_32BIT, HPET_T0_CFG);
+	hpet_writel(hpet_tick, HPET_T0_CMP);
+	hpet_writel(hpet_tick, HPET_T0_CMP);
+
+/*
+ * Go!
+ */
+
+	cfg |= HPET_CFG_ENABLE | HPET_CFG_LEGACY;
+	hpet_writel(cfg, HPET_CFG);
+
+	return 0;
+}
+
+void __init pit_init(void)
+{
+	outb_p(0x34, 0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
+	outb_p(LATCH & 0xff, 0x40);	/* LSB */
+	outb_p(LATCH >> 8, 0x40);	/* MSB */
+}
+
+int __init time_setup(char *str)
+{
+	hpet_report_lost_ticks = 1;
+	return 1;
+}
+
+static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
+
+extern void __init config_acpi_tables(void);
+
+void __init time_init(void)
+{
+	xtime.tv_sec = get_cmos_time();
+	xtime.tv_usec = 0;
+
+		printk(KERN_WARNING "time.c: HPET timer not found, precise timing unavailable.\n");
+		pit_init();
+		printk(KERN_INFO "time.c: Using 1.1931816 MHz PIT timer.\n");
+		setup_irq(0, &irq0);
+		cpu_khz = pit_calibrate_tsc();
+		printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
+			cpu_khz / 1000, cpu_khz % 1000);
+	hpet.ticks = cpu_khz * (1000 / HZ);
+	rdtscll(hpet.last_tsc);
+}
+
+__setup("report_lost_ticks", time_setup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/trampoline.S linux-2.4.20/arch/x86_64/kernel/trampoline.S
--- linux-2.4.19/arch/x86_64/kernel/trampoline.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/trampoline.S	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,76 @@
+/*
+ *
+ *	Trampoline.S	Derived from Setup.S by Linus Torvalds
+ *
+ *	4 Jan 1997 Michael Chastain: changed to gnu as.
+ *
+ *	Entry: CS:IP point to the start of our code, we are 
+ *	in real mode with no stack, but the rest of the 
+ *	trampoline page to make our stack and everything else
+ *	is a mystery.
+ *
+ *	In fact we don't actually need a stack so we don't
+ *	set one up.
+ *
+ *	On entry to trampoline_data, the processor is in real mode
+ *	with 16-bit addressing and 16-bit data.  CS has some value
+ *	and IP is zero.  Thus, data addresses need to be absolute
+ *	(no relocation) and are taken with regard to r_base.
+ *
+ *	If you work on this file, check the object module with objdump
+ *	--full-contents --reloc to make sure there are no relocation
+ *	entries. For the GDT entry we do hand relocation in smpboot.c
+ *	because of 64bit linker limitations.
+ */
+
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+
+.data
+
+.code16
+
+ENTRY(trampoline_data)
+r_base = .
+
+	mov	%cs, %ax	# Code and data in the same place
+	mov	%ax, %ds
+
+	mov	$1, %bx		# Flag an SMP trampoline
+	cli			# We should be safe anyway
+
+	movl	$0xA5A5A5A5, trampoline_data - r_base
+				# write marker for master knows we're running
+
+	lidt	idt_48 - r_base	# load idt with 0, 0
+	lgdt	gdt_48 - r_base	# load gdt with whatever is appropriate
+
+	movw    $__KERNEL_DS,%ax
+	movw    %ax,%ds
+	movw    %ax,%es
+	
+	xor	%ax, %ax
+	inc	%ax		# protected mode (PE) bit
+	lmsw	%ax		# into protected mode
+	jmp	flush_instr
+flush_instr:
+	ljmpl	$__KERNEL32_CS, $0x00100000
+			# jump to startup_32 in arch/x86_64/kernel/head.S
+
+idt_48:
+	.word	0			# idt limit = 0
+	.word	0, 0			# idt base = 0L
+
+gdt_48:
+	.short	0x0800			# gdt limit = 2048, 256 GDT entries
+	.globl tramp_gdt_ptr
+tramp_gdt_ptr:
+	.long	0			# gdt base = gdt (first SMP CPU)
+					# this is filled in by C because the 64bit
+					# linker doesn't support absolute 32bit
+					# relocations.
+
+	
+.globl trampoline_end
+trampoline_end:	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/traps.c linux-2.4.20/arch/x86_64/kernel/traps.c
--- linux-2.4.19/arch/x86_64/kernel/traps.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/traps.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,860 @@
+/*
+ *  linux/arch/x86-64/traps.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
+ *
+ *  Pentium III FXSR, SSE support
+ *	Gareth Hughes <gareth@valinux.com>, May 2000
+ *
+ *  $Id: traps.c,v 1.51 2002/09/12 12:57:46 ak Exp $
+ */
+
+/*
+ * 'Traps.c' handles hardware traps and faults after we have saved some
+ * state in 'entry.S'.
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/debugreg.h>
+#include <asm/desc.h>
+#include <asm/i387.h>
+#include <asm/kdebug.h>
+
+#include <asm/smp.h>
+#include <asm/pgalloc.h>
+#include <asm/pda.h>
+#include <asm/proto.h>
+
+#include <linux/irq.h>
+
+extern int exception_trace;
+
+extern struct gate_struct idt_table[256]; 
+
+asmlinkage void divide_error(void);
+asmlinkage void debug(void);
+asmlinkage void nmi(void);
+asmlinkage void int3(void);
+asmlinkage void overflow(void);
+asmlinkage void bounds(void);
+asmlinkage void invalid_op(void);
+asmlinkage void device_not_available(void);
+asmlinkage void double_fault(void);
+asmlinkage void coprocessor_segment_overrun(void);
+asmlinkage void invalid_TSS(void);
+asmlinkage void segment_not_present(void);
+asmlinkage void stack_segment(void);
+asmlinkage void general_protection(void);
+asmlinkage void page_fault(void);
+asmlinkage void coprocessor_error(void);
+asmlinkage void simd_coprocessor_error(void);
+asmlinkage void reserved(void);
+asmlinkage void alignment_check(void);
+asmlinkage void machine_check(void);
+asmlinkage void spurious_interrupt_bug(void);
+asmlinkage void call_debug(void);
+
+extern char iret_address[];
+
+struct notifier_block *die_chain;
+
+int kstack_depth_to_print = 40;
+
+#ifdef CONFIG_KALLSYMS
+#include <linux/kallsyms.h> 
+int printk_address(unsigned long address)
+{ 
+	unsigned long dummy; 
+	const char *modname, *secname, *symname;
+	unsigned long symstart; 
+	char *delim = ":"; 
+
+	/* What a function call! */
+	if (!kallsyms_address_to_symbol(address, 
+					&modname, &dummy, &dummy, 
+					&secname, &dummy, &dummy,
+					&symname, &symstart, &dummy)) {
+		return printk("[<%016lx>]", address);
+	} 
+	if (!strcmp(modname, "kernel"))
+		modname = delim = ""; 		
+        return printk("[%016lx%s%s%s%s%+ld]",
+		      address,delim,modname,delim,symname,address-symstart); 
+} 
+#else
+int printk_address(unsigned long address)
+{ 
+	return printk("[<%016lx>]", address);
+} 
+#endif
+
+
+#ifdef CONFIG_MODULES
+
+extern struct module *module_list;
+extern struct module kernel_module;
+
+static inline int kernel_text_address(unsigned long addr)
+{
+   int retval = 0;
+   struct module *mod;
+
+   if (addr >= (unsigned long) &_stext &&
+       addr <= (unsigned long) &_etext)
+       return 1;
+
+   for (mod = module_list; mod != &kernel_module; mod = mod->next) {
+       /* mod_bound tests for addr being inside the vmalloc'ed
+        * module area. Of course it'd be better to test only
+        * for the .text subset... */
+       if (mod_bound(addr, 0, mod)) {
+           retval = 1;
+           break;
+       }
+   }
+
+   return retval;
+}
+
+#else
+
+static inline int kernel_text_address(unsigned long addr)
+{
+   return (addr >= (unsigned long) &_stext &&
+       addr <= (unsigned long) &_etext);
+}
+
+#endif
+
+static inline unsigned long *in_exception_stack(int cpu, unsigned long stack) 
+{ 
+	int k;
+	for (k = 0; k < N_EXCEPTION_STACKS; k++) {
+		unsigned long end = init_tss[cpu].ist[k] + EXCEPTION_STKSZ; 
+
+		if (stack >= init_tss[cpu].ist[k]  && stack <= end) 
+			return (unsigned long *)end;
+	}
+	return 0;
+} 
+
+void show_trace(unsigned long *stack)
+{
+	unsigned long addr;
+	unsigned long *irqstack, *irqstack_end, *estack_end;
+	/* FIXME: should read the cpuid from the APIC; to still work with bogus %gs */
+	const int cpu = smp_processor_id();
+	int i;
+
+	printk("\nCall Trace: ");
+
+	i = 1;
+	estack_end = in_exception_stack(cpu, (unsigned long)stack); 
+	if (estack_end) { 
+		while (stack < estack_end) { 
+			addr = *stack++; 
+			if (kernel_text_address(addr)) {  
+				i += printk_address(addr);
+				i += printk(" "); 
+				if (i > 50) { 
+					printk("\n       ");
+					i = 0;
+				} 
+			}
+		}
+		printk(" <EOE> "); 
+		i += 7;
+		stack = (unsigned long *) estack_end[-2]; 
+	}  
+
+
+	irqstack_end = (unsigned long *) (cpu_pda[cpu].irqstackptr);
+	irqstack = (unsigned long *) (cpu_pda[cpu].irqstackptr - IRQSTACKSIZE + 8);
+
+	if (stack >= irqstack && stack < irqstack_end) {
+		while (stack < irqstack_end) {
+			addr = *stack++;
+			/*
+			 * If the address is either in the text segment of the
+			 * kernel, or in the region which contains vmalloc'ed
+			 * memory, it *may* be the address of a calling
+			 * routine; if so, print it so that someone tracing
+			 * down the cause of the crash will be able to figure
+			 * out the call path that was taken.
+			 */
+			 if (kernel_text_address(addr)) {  
+				 i += printk_address(addr);
+				 i += printk(" "); 
+				 if (i > 50) { 
+					 printk("\n       ");
+					 i = 0;
+				 } 
+			 }
+		} 
+		stack = (unsigned long *) (irqstack_end[-1]);
+		i += 7; 
+		printk(" <EOI> ");
+	} 
+
+	
+
+	while (((long) stack & (THREAD_SIZE-1)) != 0) {
+		addr = *stack++;
+		if (kernel_text_address(addr)) {  
+			i += printk_address(addr);
+			i += printk(" "); 
+			if (i > 50) { 
+				printk("\n       ");
+				i = 0;
+			} 
+		}
+	}
+	printk("\n");
+}
+
+void show_trace_task(struct task_struct *tsk)
+{
+	unsigned long rsp = tsk->thread.rsp;
+
+	/* User space on another CPU? */
+	if ((rsp ^ (unsigned long)tsk) & (PAGE_MASK<<1))
+		return;
+	show_trace((unsigned long *)rsp);
+}
+
+void show_stack(unsigned long * rsp)
+{
+	unsigned long *stack;
+	int i;
+	const int cpu = smp_processor_id();
+	unsigned long *irqstack_end = (unsigned long *) (cpu_pda[cpu].irqstackptr);
+	unsigned long *irqstack = (unsigned long *) (cpu_pda[cpu].irqstackptr - IRQSTACKSIZE);    
+
+	// debugging aid: "show_stack(NULL);" prints the
+	// back trace for this cpu.
+
+	if(rsp==NULL)
+		rsp=(unsigned long*)&rsp;
+
+	stack = rsp;
+	for(i=0; i < kstack_depth_to_print; i++) {
+		if (stack >= irqstack && stack <= irqstack_end) {
+			if (stack == irqstack_end) {
+				stack = (unsigned long *) (irqstack_end[-1]);
+				printk(" <EOI> ");
+			}
+		} else {
+			if (((long) stack & (THREAD_SIZE-1)) == 0)
+				break;
+		}
+		if (i && ((i % 4) == 0))
+			printk("\n       ");
+		printk("%016lx ", *stack++);
+	}
+	show_trace((unsigned long *)rsp);
+}
+
+void dump_stack(void)
+{
+	show_stack(0);
+} 
+
+void show_registers(struct pt_regs *regs)
+{
+	int i;
+	int in_kernel = 1;
+	unsigned long rsp;
+#ifdef CONFIG_SMP
+	/* For SMP should get the APIC id here, just to protect against corrupted GS */ 
+	const int cpu = smp_processor_id(); 
+#else
+	const int cpu = 0;
+#endif	
+	struct task_struct *cur = cpu_pda[cpu].pcurrent; 
+
+	rsp = (unsigned long) (&regs->rsp);
+	if (regs->rsp < TASK_SIZE) {
+		in_kernel = 0;
+		rsp = regs->rsp;
+	}
+	printk("CPU %d ", cpu);
+	show_regs(regs);
+	printk("Process %s (pid: %d, stackpage=%08lx)\n",
+		cur->comm, cur->pid, 4096+(unsigned long)cur);
+
+	/*
+	 * When in-kernel, we also print out the stack and code at the
+	 * time of the fault..
+	 */
+	if (in_kernel) {
+
+		printk("Stack: ");
+		show_stack((unsigned long*)rsp);
+
+		printk("\nCode: ");
+		if(regs->rip < PAGE_OFFSET)
+			goto bad;
+
+		for(i=0;i<20;i++)
+		{
+			unsigned char c;
+			if(__get_user(c, &((unsigned char*)regs->rip)[i])) {
+bad:
+				printk(" Bad RIP value.");
+				break;
+			}
+			printk("%02x ", c);
+		}
+	}
+	printk("\n");
+}	
+
+void handle_BUG(struct pt_regs *regs)
+{ 
+	struct bug_frame f;
+	char tmp;
+
+	if (regs->cs & 3)
+		return; 
+	if (__copy_from_user(&f, (struct bug_frame *) regs->rip, 
+			     sizeof(struct bug_frame)))
+		return; 
+	if ((unsigned long)f.filename < __PAGE_OFFSET || 
+	    f.ud2[0] != 0x0f || f.ud2[1] != 0x0b) 
+		return;
+	if (__get_user(tmp, f.filename))
+		f.filename = "unmapped filename"; 
+	printk(KERN_EMERG "Kernel BUG at %.50s:%d\n", f.filename, f.line); 	
+} 
+
+spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
+int die_owner = -1;
+
+void die(const char * str, struct pt_regs * regs, long err)
+{
+	int cpu;
+	struct die_args args = { regs, str, err };
+	console_verbose();
+	notifier_call_chain(&die_chain,  DIE_DIE, &args); 
+	bust_spinlocks(1);
+	handle_BUG(regs);		
+	printk(KERN_EMERG "%s: %04lx\n", str, err & 0xffff);
+	cpu = smp_processor_id(); 
+	/* racy, but better than risking deadlock. */ 
+	__cli();
+	if (!spin_trylock(&die_lock)) { 
+		if (cpu == die_owner) 
+			/* nested oops. should stop eventually */;
+		else
+			spin_lock(&die_lock); 
+	}
+	die_owner = cpu; 
+	show_registers(regs);
+	bust_spinlocks(0);
+	spin_unlock_irq(&die_lock);
+	notify_die(DIE_OOPS, (char *)str, regs, err);
+	do_exit(SIGSEGV);
+}
+
+static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
+{
+	if (regs->cs == __KERNEL_CS)
+		die(str, regs, err);
+}
+
+static inline unsigned long get_cr2(void)
+{
+	unsigned long address;
+
+	/* get the address */
+	__asm__("movq %%cr2,%0":"=r" (address));
+	return address;
+}
+
+static void do_trap(int trapnr, int signr, char *str, 
+		    struct pt_regs * regs, long error_code, siginfo_t *info)
+{
+#if defined(CONFIG_CHECKING) && defined(CONFIG_LOCAL_APIC)
+	{ 
+		unsigned long gs; 
+		struct x8664_pda *pda = cpu_pda + hard_smp_processor_id(); 
+		rdmsrl(MSR_GS_BASE, gs); 
+		if (gs != (unsigned long)pda) { 
+			wrmsrl(MSR_GS_BASE, pda); 
+			printk("%s: wrong gs %lx expected %p\n", str, gs, pda);
+		}
+	}
+#endif
+
+	if ((regs->cs & 3)  != 0) { 
+		struct task_struct *tsk = current;
+		tsk->thread.error_code = error_code;
+		tsk->thread.trap_no = trapnr;
+		if (exception_trace)
+			printk("%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n",
+			       tsk->comm, tsk->pid, str,
+			       regs->rip,regs->rsp,error_code); 
+		if (info)
+			force_sig_info(signr, info, tsk);
+		else
+			force_sig(signr, tsk);
+		return;
+	}
+
+
+	/* kernel trap */ 
+	{	     
+		unsigned long fixup = search_exception_table(regs->rip);
+		if (fixup) {
+			extern int exception_trace; 
+			if (0 && exception_trace)
+	       printk(KERN_ERR
+	             "%s: fixed kernel exception at %lx err:%ld\n",
+	             current->comm, regs->rip, error_code);
+		
+			regs->rip = fixup;
+		} else	
+			die(str, regs, error_code);
+		return;
+	}
+}
+
+#define DO_ERROR(trapnr, signr, str, name) \
+asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
+{ \
+	do_trap(trapnr, signr, str, regs, error_code, NULL); \
+}
+
+#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
+asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
+{ \
+	siginfo_t info; \
+	info.si_signo = signr; \
+	info.si_errno = 0; \
+	info.si_code = sicode; \
+	info.si_addr = (void *)siaddr; \
+	do_trap(trapnr, signr, str, regs, error_code, &info); \
+}
+
+DO_ERROR_INFO( 0, SIGFPE,  "divide error", divide_error, FPE_INTDIV, regs->rip)
+DO_ERROR( 4, SIGSEGV, "overflow", overflow)
+DO_ERROR( 5, SIGSEGV, "bounds", bounds)
+DO_ERROR_INFO( 6, SIGILL,  "invalid operand", invalid_op, ILL_ILLOPN, regs->rip)
+DO_ERROR( 7, SIGSEGV, "device not available", device_not_available)
+DO_ERROR( 8, SIGSEGV, "double fault", double_fault)
+DO_ERROR( 9, SIGFPE,  "coprocessor segment overrun", coprocessor_segment_overrun)
+DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
+DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present)
+DO_ERROR(12, SIGBUS,  "stack segment", stack_segment)
+DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2())
+DO_ERROR(18, SIGSEGV, "reserved", reserved)
+
+asmlinkage void do_int3(struct pt_regs * regs, long error_code)
+{
+	if (notify_die(DIE_INT3, "int3", regs, error_code) == NOTIFY_BAD)
+		return;
+	do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
+}
+
+extern void dump_pagetable(unsigned long);
+
+asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
+{
+#ifdef CONFIG_CHECKING
+	{ 
+		unsigned long gs; 
+		struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); 
+		rdmsrl(MSR_GS_BASE, gs); 
+		if (gs != (unsigned long)pda) { 
+			wrmsrl(MSR_GS_BASE, pda); 
+			printk("general protection handler: wrong gs %lx expected %p\n", gs, pda);
+		}
+	}
+#endif
+
+	if (regs->cs & 3) { 		
+		current->thread.error_code = error_code;
+		current->thread.trap_no = 13;
+		if (exception_trace)
+			printk("%s[%d] general protection rip:%lx rsp:%lx error:%lx\n",
+			       current->comm, current->pid,
+			       regs->rip,regs->rsp,error_code); 
+		force_sig(SIGSEGV, current);
+		return;
+	} 
+
+	/* kernel gp */
+	{
+		unsigned long fixup;
+		fixup = search_exception_table(regs->rip);
+		if (fixup) {
+			extern int exception_trace; 
+			if (exception_trace)
+				printk(KERN_ERR
+			       "%s: fixed kernel exception at %lx err:%ld\n",
+				       current->comm, regs->rip, error_code);
+
+			regs->rip = fixup;
+			return;
+		}
+		die("general protection fault", regs, error_code);
+	}
+}
+
+static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
+{
+	printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
+	printk("You probably have a hardware problem with your RAM chips\n");
+
+	/* Clear and disable the memory parity error line. */
+	reason = (reason & 0xf) | 4;
+	outb(reason, 0x61);
+}
+
+static void io_check_error(unsigned char reason, struct pt_regs * regs)
+{
+	printk("NMI: IOCK error (debug interrupt?)\n");
+	show_registers(regs);
+
+	/* Re-enable the IOCK line, wait for a few seconds */
+	reason = (reason & 0xf) | 8;
+	outb(reason, 0x61);
+	mdelay(2000);
+	reason &= ~8;
+	outb(reason, 0x61);
+}
+
+static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
+{
+	printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
+	printk("Dazed and confused, but trying to continue\n");
+	printk("Do you have a strange power saving mode enabled?\n");
+}
+
+asmlinkage void do_nmi(struct pt_regs * regs)
+{
+	unsigned char reason = inb(0x61);
+
+	++nmi_count(smp_processor_id());
+	
+	if (!(reason & 0xc0)) {
+#if CONFIG_X86_LOCAL_APIC
+		/*
+		 * Ok, so this is none of the documented NMI sources,
+		 * so it must be the NMI watchdog.
+		 */
+		if (nmi_watchdog) {
+			nmi_watchdog_tick(regs);
+			return;
+		}
+#endif
+		if (notify_die(DIE_NMI, "nmi", regs, reason) == NOTIFY_BAD)
+			return;
+		unknown_nmi_error(reason, regs);
+		return;
+	}
+	if (notify_die(DIE_NMI, "nmi", regs, reason) == NOTIFY_BAD)
+		return; 
+	if (reason & 0x80)
+		mem_parity_error(reason, regs);
+	if (reason & 0x40)
+		io_check_error(reason, regs);
+
+	/*
+	 * Reassert NMI in case it became active meanwhile
+	 * as it's edge-triggered.
+	 */
+	outb(0x8f, 0x70);
+	inb(0x71);		/* dummy */
+	outb(0x0f, 0x70);
+	inb(0x71);		/* dummy */
+}
+
+asmlinkage void do_debug(struct pt_regs * regs, long error_code)
+{
+	unsigned long condition;
+	struct task_struct *tsk = current;
+	siginfo_t info;
+
+#ifdef CONFIG_CHECKING
+	{ 
+		unsigned long gs; 
+		struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); 
+		rdmsrl(MSR_GS_BASE, gs); 
+		if (gs != (unsigned long)pda) { 
+			wrmsrl(MSR_GS_BASE, pda); 
+			printk("debug handler: wrong gs %lx expected %p\n", gs, pda);
+		}
+	}
+#endif
+
+	asm("movq %%db6,%0" : "=r" (condition));
+
+	if (notify_die(DIE_DEBUG, "debug", regs, error_code) == NOTIFY_BAD)
+		return; 
+
+	/* If the user set TF, it's simplest to clear it right away. */
+	/* AK: dubious check, likely wrong */
+	if ((regs->cs & 3) == 0 && (regs->eflags & TF_MASK))
+		goto clear_TF;
+
+	/* Mask out spurious debug traps due to lazy DR7 setting */
+	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
+		if (!tsk->thread.debugreg[7]) { 
+			goto clear_dr7;
+		}
+	}
+
+	tsk->thread.debugreg[6] = condition;
+
+	/* Mask out spurious TF errors due to lazy TF clearing */
+	if (condition & DR_STEP) {
+		/*
+		 * The TF error should be masked out only if the current
+		 * process is not traced and if the TRAP flag has been set
+		 * previously by a tracing process (condition detected by
+		 * the PT_DTRACE flag); remember that the i386 TRAP flag
+		 * can be modified by the process itself in user mode,
+		 * allowing programs to debug themselves without the ptrace()
+		 * interface.
+		 */
+                if ((regs->cs & 3) == 0)
+                       goto clear_TF;
+		if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
+			goto clear_TF;
+	}
+
+	/* Ok, finally something we can handle */
+	tsk->thread.trap_no = 1;
+	tsk->thread.error_code = error_code;
+	info.si_signo = SIGTRAP;
+	info.si_errno = 0;
+	info.si_code = TRAP_BRKPT;
+	info.si_addr = ((regs->cs & 3) == 0) ? (void *)tsk->thread.rip : 
+	                                        (void *)regs->rip;
+	force_sig_info(SIGTRAP, &info, tsk);	
+clear_dr7:
+	asm("movq %0,%%db7"::"r"(0UL));
+	return;
+
+clear_TF:
+	regs->eflags &= ~TF_MASK;
+	return;
+}
+
+/*
+ * Note that we play around with the 'TS' bit in an attempt to get
+ * the correct behaviour even in the presence of the asynchronous
+ * IRQ13 behaviour
+ */
+void math_error(void *rip)
+{
+	struct task_struct * task;
+	siginfo_t info;
+	unsigned short cwd, swd;
+
+	/*
+	 * Save the info for the exception handler and clear the error.
+	 */
+	task = current;
+	save_init_fpu(task);
+	task->thread.trap_no = 16;
+	task->thread.error_code = 0;
+	info.si_signo = SIGFPE;
+	info.si_errno = 0;
+	info.si_code = __SI_FAULT;
+	info.si_addr = rip;
+	/*
+	 * (~cwd & swd) will mask out exceptions that are not set to unmasked
+	 * status.  0x3f is the exception bits in these regs, 0x200 is the
+	 * C1 reg you need in case of a stack fault, 0x040 is the stack
+	 * fault bit.  We should only be taking one exception at a time,
+	 * so if this combination doesn't produce any single exception,
+	 * then we have a bad program that isn't syncronizing its FPU usage
+	 * and it will suffer the consequences since we won't be able to
+	 * fully reproduce the context of the exception
+	 */
+	cwd = get_fpu_cwd(task);
+	swd = get_fpu_swd(task);
+	switch (((~cwd) & swd & 0x3f) | (swd & 0x240)) {
+		case 0x000:
+		default:
+			break;
+		case 0x001: /* Invalid Op */
+		case 0x041: /* Stack Fault */
+		case 0x241: /* Stack Fault | Direction */
+			info.si_code = FPE_FLTINV;
+			break;
+		case 0x002: /* Denormalize */
+		case 0x010: /* Underflow */
+			info.si_code = FPE_FLTUND;
+			break;
+		case 0x004: /* Zero Divide */
+			info.si_code = FPE_FLTDIV;
+			break;
+		case 0x008: /* Overflow */
+			info.si_code = FPE_FLTOVF;
+			break;
+		case 0x020: /* Precision */
+			info.si_code = FPE_FLTRES;
+			break;
+	}
+	force_sig_info(SIGFPE, &info, task);
+}
+
+asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
+{
+	math_error((void *)regs->rip);
+}
+
+asmlinkage void bad_intr(void)
+{
+	printk("bad interrupt"); 
+}
+
+static inline void simd_math_error(void *rip)
+{
+	struct task_struct * task;
+	siginfo_t info;
+	unsigned short mxcsr;
+
+	/*
+	 * Save the info for the exception handler and clear the error.
+	 */
+	task = current;
+	save_init_fpu(task);
+	task->thread.trap_no = 19;
+	task->thread.error_code = 0;
+	info.si_signo = SIGFPE;
+	info.si_errno = 0;
+	info.si_code = __SI_FAULT;
+	info.si_addr = rip;
+	/*
+	 * The SIMD FPU exceptions are handled a little differently, as there
+	 * is only a single status/control register.  Thus, to determine which
+	 * unmasked exception was caught we must mask the exception mask bits
+	 * at 0x1f80, and then use these to mask the exception bits at 0x3f.
+	 */
+	mxcsr = get_fpu_mxcsr(task);
+	switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
+		case 0x000:
+		default:
+			break;
+		case 0x001: /* Invalid Op */
+			info.si_code = FPE_FLTINV;
+			break;
+		case 0x002: /* Denormalize */
+		case 0x010: /* Underflow */
+			info.si_code = FPE_FLTUND;
+			break;
+		case 0x004: /* Zero Divide */
+			info.si_code = FPE_FLTDIV;
+			break;
+		case 0x008: /* Overflow */
+			info.si_code = FPE_FLTOVF;
+			break;
+		case 0x020: /* Precision */
+			info.si_code = FPE_FLTRES;
+			break;
+	}
+	force_sig_info(SIGFPE, &info, task);
+}
+
+asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs,
+					  long error_code)
+{
+	simd_math_error((void *)regs->rip);
+}
+
+asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs)
+{
+}
+
+/*
+ *  'math_state_restore()' saves the current math information in the
+ * old math state array, and gets the new ones from the current task
+ *
+ * Careful.. There are problems with IBM-designed IRQ13 behaviour.
+ * Don't touch unless you *really* know how it works.
+ */
+asmlinkage void math_state_restore(void)
+{
+	struct task_struct *me = current;
+	clts();			/* Allow maths ops (or we recurse) */
+
+	if (!me->used_math)
+		init_fpu();        
+	restore_fpu_checking(&me->thread.i387.fxsave);
+	me->flags |= PF_USEDFPU;	/* So we fxsave on switch_to() */
+}
+
+asmlinkage void math_emulate(void)
+{
+	BUG();
+}
+
+void do_call_debug(struct pt_regs *regs) 
+{ 
+	notify_die(DIE_CALL, "debug call", regs, 0); 
+} 
+
+#ifndef CONFIG_MCE
+void do_machine_check(struct pt_regs *regs)
+{ 
+	printk("Machine check ignored\n");
+} 
+#endif
+
+void __init trap_init(void)
+{
+	set_intr_gate(0,&divide_error);
+	set_intr_gate(1,&debug);
+	set_intr_gate_ist(2,&nmi,NMI_STACK);
+	set_system_gate(3,&int3);	/* int3-5 can be called from all */
+	set_system_gate(4,&overflow);
+	set_system_gate(5,&bounds);
+	set_intr_gate(6,&invalid_op);
+	set_intr_gate(7,&device_not_available);
+	set_intr_gate_ist(8,&double_fault, DOUBLEFAULT_STACK);
+	set_intr_gate(9,&coprocessor_segment_overrun);
+	set_intr_gate(10,&invalid_TSS);
+	set_intr_gate(11,&segment_not_present);
+	set_intr_gate_ist(12,&stack_segment,STACKFAULT_STACK);
+	set_intr_gate(13,&general_protection);
+	set_intr_gate(14,&page_fault);
+	set_intr_gate(15,&spurious_interrupt_bug);
+	set_intr_gate(16,&coprocessor_error);
+	set_intr_gate(17,&alignment_check);
+	set_intr_gate(18,&machine_check); 
+	set_intr_gate(19,&simd_coprocessor_error);
+
+#ifdef CONFIG_IA32_EMULATION
+	set_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
+#endif
+
+	set_intr_gate(KDB_VECTOR, call_debug);
+       
+	notify_die(DIE_TRAPINIT, "traps initialized", 0, 0); 
+	
+	/*
+	 * Should be a barrier for any external CPU state.
+	 */
+	cpu_init();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/vsyscall.c linux-2.4.20/arch/x86_64/kernel/vsyscall.c
--- linux-2.4.19/arch/x86_64/kernel/vsyscall.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/vsyscall.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,161 @@
+/*
+ *  linux/arch/x86_64/kernel/vsyscall.c
+ *
+ *  Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE
+ *
+ *  Thanks to hpa@transmeta.com for some useful hint.
+ *  Special thanks to Ingo Molnar for his early experience with
+ *  a different vsyscall implementation for Linux/IA32 and for the name.
+ *
+ *  vsyscall 1 is located at -10Mbyte, vsyscall 2 is located
+ *  at virtual address -10Mbyte+1024bytes etc... There are at max 8192
+ *  vsyscalls. One vsyscall can reserve more than 1 slot to avoid
+ *  jumping out of line if necessary.
+ *
+ *  $Id: vsyscall.c,v 1.19 2002/07/19 02:24:08 vojtech Exp $
+ */
+
+/*
+ * TODO 2001-03-20:
+ *
+ * 1) make page fault handler detect faults on page1-page-last of the vsyscall
+ *    virtual space, and make it increase %rip and write -ENOSYS in %rax (so
+ *    we'll be able to upgrade to a new glibc without upgrading kernel after
+ *    we add more vsyscalls.
+ * 2) Possibly we need a fixmap table for the vsyscalls too if we want
+ *    to avoid SIGSEGV and we want to return -EFAULT from the vsyscalls as well.
+ *    Can we segfault inside a "syscall"? We can fix this anytime and those fixes
+ *    won't be visible for userspace. Not fixing this is a noop for correct programs,
+ *    broken programs will segfault and there's no security risk until we choose to
+ *    fix it.
+ *
+ * These are not urgent things that we need to address only before shipping the first
+ * production binary kernels.
+ */
+
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+
+#include <asm/vsyscall.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/fixmap.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/msr.h>
+
+#define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
+
+long __vxtime_sequence[2] __section_vxtime_sequence;
+
+#undef USE_VSYSCALL
+
+#ifdef USE_VSYSCALL
+
+static inline void do_vgettimeofday(struct timeval * tv)
+{
+	long sequence, t;
+	unsigned long sec, usec;
+
+	do {
+		sequence = __vxtime_sequence[1];
+		rmb();
+
+		rdtscll(t);
+		sec = __xtime.tv_sec;
+		usec = __xtime.tv_usec +
+			(__jiffies - __wall_jiffies) * (1000000 / HZ) +
+			(t  - __hpet.last_tsc) * (1000000 / HZ) / __hpet.ticks + __hpet.offset;
+
+		rmb();
+	} while (sequence != __vxtime_sequence[0]);
+
+	tv->tv_sec = sec + usec / 1000000;
+	tv->tv_usec = usec % 1000000;
+}
+
+static inline void do_get_tz(struct timezone * tz)
+{
+	long sequence;
+
+	do {
+		sequence = __vxtime_sequence[1];
+		rmb();
+
+		*tz = __sys_tz;
+
+		rmb();
+	} while (sequence != __vxtime_sequence[0]);
+}
+
+static long __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
+{
+	if (tv) do_vgettimeofday(tv);
+	if (tz) do_get_tz(tz);
+	return 0;
+}
+
+#else
+
+#include <asm/unistd.h>
+
+static long __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
+{
+	int r;
+	asm volatile("syscall"
+		     : "=a" (r)
+		     : "0" (__NR_gettimeofday), "D" (tv), "S" (tz)
+		     : "r11", "rcx","memory");
+	return r;
+}
+
+#endif
+
+static time_t __vsyscall(1) vtime(time_t * tp)
+{
+	struct timeval tv;
+	vgettimeofday(&tv, NULL);
+	if (tp) *tp = tv.tv_sec;
+	return tv.tv_sec;
+}
+
+static long __vsyscall(2) venosys_0(void)
+{
+	return -ENOSYS;
+}
+
+static long __vsyscall(3) venosys_1(void)
+{
+	return -ENOSYS;
+}
+
+static void __init map_vsyscall(void)
+{
+	extern char __vsyscall_0;
+	unsigned long physaddr_page0 = (unsigned long) &__vsyscall_0 - __START_KERNEL_map;
+
+	__set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL);
+	if (hpet.address)
+		__set_fixmap(VSYSCALL_HPET, hpet.address, PAGE_KERNEL_VSYSCALL);
+}
+
+static int __init vsyscall_init(void)
+{
+	printk("VSYSCALL: consistency checks...");
+	if ((unsigned long) &vgettimeofday != VSYSCALL_ADDR(__NR_vgettimeofday))
+		panic("vgettimeofday link addr broken");
+	if ((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime))
+		panic("vtime link addr broken");
+	if (VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE))
+		panic("fixmap first vsyscall %lx should be %lx", __fix_to_virt(VSYSCALL_FIRST_PAGE),
+			VSYSCALL_ADDR(0));
+	printk("passed...mapping...");
+	map_vsyscall();
+	printk("done.\n");
+
+	return 0;
+}
+
+__initcall(vsyscall_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/kernel/x8664_ksyms.c linux-2.4.20/arch/x86_64/kernel/x8664_ksyms.c
--- linux-2.4.19/arch/x86_64/kernel/x8664_ksyms.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/kernel/x8664_ksyms.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,222 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/user.h>
+#include <linux/mca.h>
+#include <linux/sched.h>
+#include <linux/in6.h>
+#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
+#include <linux/pm.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <linux/string.h>
+
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/i387.h>
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+#include <asm/io.h>
+#include <asm/hardirq.h>
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/mmx.h>
+#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/kdebug.h>
+#include <asm/pgtable.h>
+#include <asm/proto.h>
+#define __KERNEL_SYSCALLS__ 1
+#include <asm/unistd.h>
+
+extern spinlock_t rtc_lock;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
+extern struct drive_info_struct drive_info;
+EXPORT_SYMBOL(drive_info);
+#endif
+
+/* platform dependent support */
+EXPORT_SYMBOL(boot_cpu_data);
+EXPORT_SYMBOL(dump_fpu);
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(iounmap);
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(disable_irq_nosync);
+EXPORT_SYMBOL(probe_irq_mask);
+EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(pm_idle);
+EXPORT_SYMBOL(pm_power_off);
+
+#ifdef CONFIG_IO_DEBUG
+EXPORT_SYMBOL(__io_virt_debug);
+#endif
+
+EXPORT_SYMBOL_NOVERS(__down_failed);
+EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
+EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
+EXPORT_SYMBOL_NOVERS(__up_wakeup);
+/* Networking helper routines. */
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
+/* Delay loops */
+EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(__delay);
+EXPORT_SYMBOL(__const_udelay);
+
+EXPORT_SYMBOL_NOVERS(__get_user_1);
+EXPORT_SYMBOL_NOVERS(__get_user_2);
+EXPORT_SYMBOL_NOVERS(__get_user_4);
+EXPORT_SYMBOL_NOVERS(__get_user_8);
+EXPORT_SYMBOL_NOVERS(__put_user_1);
+EXPORT_SYMBOL_NOVERS(__put_user_2);
+EXPORT_SYMBOL_NOVERS(__put_user_4);
+EXPORT_SYMBOL_NOVERS(__put_user_8);
+
+EXPORT_SYMBOL_NOVERS(clear_page);
+
+EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strstr);
+
+EXPORT_SYMBOL(strncpy_from_user);
+EXPORT_SYMBOL(__strncpy_from_user);
+EXPORT_SYMBOL(clear_user);
+EXPORT_SYMBOL(__clear_user);
+EXPORT_SYMBOL(strnlen_user);
+
+EXPORT_SYMBOL(pci_alloc_consistent);
+EXPORT_SYMBOL(pci_free_consistent);
+
+EXPORT_SYMBOL(pci_map_sg);
+EXPORT_SYMBOL(pci_unmap_sg);
+
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL(pcibios_penalize_isa_irq);
+EXPORT_SYMBOL(pci_mem_start);
+#endif
+
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(cpu_data);
+EXPORT_SYMBOL(kernel_flag_cacheline);
+EXPORT_SYMBOL(smp_num_cpus);
+EXPORT_SYMBOL(cpu_online_map);
+extern void __read_lock_failed(void);
+extern void __write_lock_failed(void);
+EXPORT_SYMBOL_NOVERS(__write_lock_failed);
+EXPORT_SYMBOL_NOVERS(__read_lock_failed);
+
+/* Global SMP irq stuff */
+EXPORT_SYMBOL(synchronize_irq);
+EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(smp_call_function);
+
+/* TLB flushing */
+EXPORT_SYMBOL(flush_tlb_page);
+#endif
+
+#ifdef CONFIG_MCA
+EXPORT_SYMBOL(machine_id);
+#endif
+
+#ifdef CONFIG_VT
+EXPORT_SYMBOL(screen_info);
+#endif
+
+EXPORT_SYMBOL(get_wchan);
+
+EXPORT_SYMBOL(rtc_lock);
+
+/* Export string functions. We normally rely on gcc builtin for most of these,
+   but gcc sometimes decides not to inline them. */    
+#undef memcpy
+#undef memset
+#undef memmove
+#undef strlen
+#undef strcpy
+#undef strcmp
+#undef strncmp
+#undef strncpy
+#undef strchr	
+#undef strcmp 
+#undef bcopy
+extern void * memcpy(void *,const void *,__kernel_size_t);
+extern void * memset(void *,int,__kernel_size_t);
+extern __kernel_size_t strlen(const char *);
+extern int strcmp(const char *,const char *);
+extern char * strcpy(char *,const char *);
+extern char * bcopy(const char * src, char * dest, int count);
+
+EXPORT_SYMBOL_NOVERS(memcpy);
+EXPORT_SYMBOL_NOVERS(__memcpy);
+EXPORT_SYMBOL_NOVERS(memset);
+EXPORT_SYMBOL_NOVERS(strlen);
+EXPORT_SYMBOL_NOVERS(strcpy);
+EXPORT_SYMBOL_NOVERS(memmove);
+EXPORT_SYMBOL_NOVERS(strncmp);
+EXPORT_SYMBOL_NOVERS(strncpy);
+EXPORT_SYMBOL_NOVERS(strchr);
+EXPORT_SYMBOL_NOVERS(strcat);
+EXPORT_SYMBOL_NOVERS(strcmp);
+EXPORT_SYMBOL_NOVERS(strncat);
+EXPORT_SYMBOL_NOVERS(memchr);
+EXPORT_SYMBOL_NOVERS(strrchr);
+EXPORT_SYMBOL_NOVERS(strnlen);
+EXPORT_SYMBOL_NOVERS(memcmp);
+EXPORT_SYMBOL_NOVERS(memscan);
+EXPORT_SYMBOL_NOVERS(bcopy);
+
+EXPORT_SYMBOL(empty_zero_page);
+
+#ifdef CONFIG_HAVE_DEC_LOCK
+EXPORT_SYMBOL(atomic_dec_and_lock);
+#endif
+
+EXPORT_SYMBOL(die_chain);
+
+extern void do_softirq_thunk(void);
+EXPORT_SYMBOL_NOVERS(do_softirq_thunk);
+
+extern unsigned long __supported_pte_mask; 
+EXPORT_SYMBOL(__supported_pte_mask);
+
+EXPORT_SYMBOL(init_level4_pgt);
+
+EXPORT_SYMBOL(copy_from_user);
+EXPORT_SYMBOL(copy_to_user);
+EXPORT_SYMBOL(copy_user_generic);
+
+/* Export kernel syscalls */
+EXPORT_SYMBOL(sys_wait4);
+EXPORT_SYMBOL(sys_exit);
+EXPORT_SYMBOL(sys_write);
+EXPORT_SYMBOL(sys_read);
+EXPORT_SYMBOL(sys_open);
+EXPORT_SYMBOL(sys_lseek);
+EXPORT_SYMBOL(sys_dup);
+EXPORT_SYMBOL(sys_delete_module);
+EXPORT_SYMBOL(sys_sync);
+EXPORT_SYMBOL(sys_pause);
+EXPORT_SYMBOL(sys_setsid);	/* Rather dubious */
+
+
+EXPORT_SYMBOL(memcpy_fromio);
+EXPORT_SYMBOL(memcpy_toio);
+
+EXPORT_SYMBOL(ip_compute_csum);
+
+
+#ifdef CONFIG_DISCONTIGMEM
+EXPORT_SYMBOL(memnode_shift);
+EXPORT_SYMBOL(memnodemap);
+EXPORT_SYMBOL(plat_node_data);
+EXPORT_SYMBOL(fake_node);
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/Makefile linux-2.4.20/arch/x86_64/lib/Makefile
--- linux-2.4.19/arch/x86_64/lib/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/Makefile	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,21 @@
+#
+# Makefile for x86_64-specific library files..
+#
+
+.S.o:
+	$(CC) $(AFLAGS) -c $< -o $*.o
+
+CFLAGS_csum-partial.o := $(PROFILING) -funroll-loops
+
+export-objs := csum-wrappers.o
+
+L_TARGET = lib.a
+obj-y  = csum-partial.o csum-copy.o csum-wrappers.o delay.o \
+	usercopy.o getuser.o putuser.o  \
+	thunk.o io.o clear_page.o copy_page.o copy_user.o \
+	memcpy.o memset.o memmove.o bitstr.o
+
+obj-$(CONFIG_IO_DEBUG) += iodebug.o
+obj-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/bitstr.c linux-2.4.20/arch/x86_64/lib/bitstr.c
--- linux-2.4.19/arch/x86_64/lib/bitstr.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/bitstr.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,25 @@
+#include <asm/bitops.h>
+
+/* Find string of zero bits in a bitmap */ 
+unsigned long 
+find_next_zero_string(unsigned long *bitmap, long start, long nbits, int len)
+{ 
+	unsigned long n, end, i; 	
+
+ again:
+	n = find_next_zero_bit(bitmap, nbits, start);
+	if (n == -1) 
+		return -1;
+	
+	/* could test bitsliced, but it's hardly worth it */
+	end = n+len;
+	if (end >= nbits) 
+		return -1; 
+	for (i = n+1; i < end; i++) { 
+		if (test_bit(i, bitmap)) {  
+			start = i+1; 
+			goto again; 
+		} 
+	}
+	return n;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/clear_page.S linux-2.4.20/arch/x86_64/lib/clear_page.S
--- linux-2.4.19/arch/x86_64/lib/clear_page.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/clear_page.S	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,34 @@
+	#include <linux/linkage.h>
+
+/*
+ * Zero a page. 	
+ * rdi	page
+ */			
+ENTRY(clear_page)
+	xorl   %eax,%eax
+	movl   $4096/128,%ecx
+	movl   $128,%edx
+loop:
+#define PUT(x) movq %rax,x*8(%rdi) 
+	PUT(0)
+	PUT(1)
+	PUT(2)
+	PUT(3)
+	PUT(4)
+	PUT(5)
+	PUT(6)
+	PUT(7)
+	PUT(8)
+	PUT(9)
+	PUT(10)
+	PUT(11)
+	PUT(12)
+	PUT(13)
+	PUT(14)
+	PUT(15)
+	addq    %rdx,%rdi
+	decl	%ecx
+	jnz	loop
+	sfence	
+	ret
+	    	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/copy_page.S linux-2.4.20/arch/x86_64/lib/copy_page.S
--- linux-2.4.19/arch/x86_64/lib/copy_page.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/copy_page.S	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,70 @@
+	#include <linux/linkage.h>
+	#include <linux/config.h>
+	#ifdef CONFIG_PREEMPT
+	#warning "check your fpu context saving!"
+	#endif
+
+/*
+ * Copy a page. 
+ *		
+ * rdi destination page
+ * rsi source page
+ *		
+ * src/dst must be aligned to 16 bytes.
+ * 
+ * Warning: in case of super lazy FP save this needs to be preempt_stop	
+ */
+	
+	.globl copy_page
+	.p2align
+copy_page:
+	prefetchnta (%rsi) 
+	prefetchnta 64(%rsi)
+	    
+	movq %rsp,%rax
+	subq $16*4,%rsp
+	andq $~15,%rsp		
+	movdqa %xmm0,(%rsp) 
+	movdqa %xmm1,16(%rsp) 
+	movdqa %xmm2,32(%rsp) 
+	movdqa %xmm3,48(%rsp)
+	
+	movl   $(4096/128)-2,%ecx
+	movl   $128,%edx
+loop:
+	prefetchnta (%rsi) 
+	prefetchnta 64(%rsi) 
+loop_no_prefetch:	
+	movdqa (%rsi),%xmm0 	 			 
+	movdqa 16(%rsi),%xmm1
+	movdqa 32(%rsi),%xmm2 	 			 
+	movdqa 48(%rsi),%xmm3 	 			 
+	movntdq %xmm0,(%rdi)	 
+	movntdq %xmm1,16(%rdi)	 
+	movntdq %xmm2,32(%rdi)	 
+	movntdq %xmm3,48(%rdi)
+	
+	movdqa 64(%rsi),%xmm0 	 			 
+	movdqa 80(%rsi),%xmm1
+	movdqa 96(%rsi),%xmm2 	 			 
+	movdqa 112(%rsi),%xmm3 	 			 
+	movntdq %xmm0,64(%rdi)	 
+	movntdq %xmm1,80(%rdi)	 
+	movntdq %xmm2,96(%rdi)	 
+	movntdq %xmm3,112(%rdi)
+
+	addq   %rdx,%rdi	
+	addq   %rdx,%rsi
+	decl   %ecx
+	jns    loop
+	cmpl   $-1,%ecx
+	je     loop_no_prefetch
+	
+	sfence
+
+	movdqa (%rsp),%xmm0
+	movdqa 16(%rsp),%xmm1
+	movdqa 32(%rsp),%xmm2
+	movdqa 48(%rsp),%xmm3
+	movq   %rax,%rsp
+	ret
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/copy_user.S linux-2.4.20/arch/x86_64/lib/copy_user.S
--- linux-2.4.19/arch/x86_64/lib/copy_user.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/copy_user.S	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,236 @@
+/* Copyright 2002 Andi Kleen, SuSE Labs.
+ * Subject to the GNU Public License v2.
+ * 
+ * Functions to copy from and to user space.		
+ */		 
+
+#define FIX_ALIGNMENT 1
+
+#define movnti movq  /* write to cache for now */
+#define prefetch prefetcht2
+		
+	#include <asm/current.h>
+	#include <asm/offset.h>
+
+/* Standard copy_to_user with segment limit checking */		
+	.globl copy_to_user
+	.p2align 	
+copy_to_user:
+	GET_CURRENT(%rax)
+	movq %rdi,%rcx
+	addq %rdx,%rcx
+	jc  bad_to_user
+	cmpq tsk_addr_limit(%rax),%rcx
+	jae bad_to_user
+	jmp copy_user_generic
+
+/* Standard copy_from_user with segment limit checking */	
+	.globl copy_from_user
+	.p2align 	
+copy_from_user:
+	GET_CURRENT(%rax)
+	movq %rsi,%rcx
+	addq %rdx,%rcx
+	jc  bad_from_user
+	cmpq tsk_addr_limit(%rax),%rcx
+	jae  bad_from_user
+	/* FALL THROUGH to copy_user_generic */
+	
+	.section .fixup,"ax"
+	/* must zero dest */
+bad_from_user:
+	movl %edx,%ecx
+	xorl %eax,%eax
+	rep
+	stosb
+bad_to_user:
+	movl	%edx,%eax
+	ret
+	.previous
+	
+/*
+ * copy_user_generic - memory copy with exception handling.
+ * 	
+ * Input:	
+ * rdi destination
+ * rsi source
+ * rdx count
+ *
+ * Output:		
+ * eax uncopied bytes or 0 if successfull. 
+ */
+	.globl copy_user_generic	
+copy_user_generic:	
+	/* Put the first cacheline into cache. This should handle
+	   the small movements in ioctls etc., but not penalize the bigger
+	   filesystem data copies too much. */
+	pushq %rbx
+	prefetch (%rsi)
+	xorl %eax,%eax		/*zero for the exception handler */
+
+#ifdef FIX_ALIGNMENT
+	/* check for bad alignment of destination */
+	movl %edi,%ecx
+	andl $7,%ecx
+	jnz  bad_alignment
+after_bad_alignment:
+#endif
+
+	movq %rdx,%rcx
+
+	movl $64,%ebx	
+	shrq $6,%rdx
+	decq %rdx
+	js   handle_tail
+	jz   loop_no_prefetch
+	
+loop:
+	prefetch 64(%rsi)
+	
+loop_no_prefetch:	
+s1:	movq (%rsi),%r11
+s2:	movq 1*8(%rsi),%r8
+s3:	movq 2*8(%rsi),%r9
+s4:	movq 3*8(%rsi),%r10
+d1:	movnti %r11,(%rdi)
+d2:	movnti %r8,1*8(%rdi)
+d3:	movnti %r9,2*8(%rdi)
+d4:	movnti %r10,3*8(%rdi)
+		
+s5:	movq 4*8(%rsi),%r11
+s6:	movq 5*8(%rsi),%r8
+s7:	movq 6*8(%rsi),%r9
+s8:	movq 7*8(%rsi),%r10
+d5:	movnti %r11,4*8(%rdi)
+d6:	movnti %r8,5*8(%rdi)
+d7:	movnti %r9,6*8(%rdi)
+d8:	movnti %r10,7*8(%rdi)
+
+	addq %rbx,%rsi	
+	addq %rbx,%rdi
+	
+	decq %rdx
+	jz   loop_no_prefetch
+	jns  loop
+
+handle_tail:
+	movl %ecx,%edx
+	andl $63,%ecx
+	shrl $3,%ecx
+	jz   handle_7
+	movl $8,%ebx
+loop_8:
+s9:	movq (%rsi),%r8
+d9:	movq %r8,(%rdi)
+	addq %rbx,%rdi
+	addq %rbx,%rsi
+	decl %ecx
+	jnz loop_8
+	
+handle_7:		
+	movl %edx,%ecx	
+	andl $7,%ecx
+	jz   ende
+loop_1:
+s10:	movb (%rsi),%bl
+d10:	movb %bl,(%rdi)
+	incq %rdi
+	incq %rsi
+	decl %ecx
+	jnz loop_1
+			
+ende:
+	sfence
+	popq %rbx
+	ret	
+
+#ifdef FIX_ALIGNMENT		  		
+	/* align destination */
+bad_alignment:
+	movl $8,%r9d
+	subl %ecx,%r9d
+	movl %r9d,%ecx
+	subq %r9,%rdx
+	jz   small_align
+	js   small_align
+align_1:		
+s11:	movb (%rsi),%bl
+d11:	movb %bl,(%rdi)
+	incq %rsi
+	incq %rdi
+	decl %ecx
+	jnz align_1
+	jmp after_bad_alignment
+small_align:
+	addq %r9,%rdx
+	jmp handle_7
+#endif
+	
+	/* table sorted by exception address */	
+	.section __ex_table,"a"
+	.align 8
+	.quad s1,s1e
+	.quad s2,s2e
+	.quad s3,s3e
+	.quad s4,s4e	
+	.quad d1,s1e
+	.quad d2,s2e
+	.quad d3,s3e
+	.quad d4,s4e
+	.quad s5,s5e
+	.quad s6,s6e
+	.quad s7,s7e
+	.quad s8,s8e	
+	.quad d5,s5e
+	.quad d6,s6e
+	.quad d7,s7e
+	.quad d8,s8e
+	.quad s9,e_quad
+	.quad d9,e_quad
+	.quad s10,e_byte
+	.quad d10,e_byte
+#ifdef FIX_ALIGNMENT	
+	.quad s11,e_byte
+	.quad d11,e_byte
+#endif
+	.quad e5,e_zero
+	.previous
+
+	/* compute 64-offset for main loop. 8 bytes accuracy with error on the 
+	   pessimistic side. this is gross. it would be better to fix the 
+	   interface. */	
+	/* eax: zero, ebx: 64 */
+s1e: 	addl $8,%eax
+s2e: 	addl $8,%eax
+s3e: 	addl $8,%eax
+s4e: 	addl $8,%eax
+s5e: 	addl $8,%eax
+s6e: 	addl $8,%eax
+s7e: 	addl $8,%eax
+s8e: 	addl $8,%eax
+	addq %rbx,%rdi	/* +64 */
+	subq %rax,%rdi  /* correct destination with computed offset */
+
+	shlq $6,%rdx	/* loop counter * 64 (stride length) */
+	addq %rax,%rdx	/* add offset to loopcnt */
+	andl $63,%ecx	/* remaining bytes */
+	addq %rcx,%rdx	/* add them */
+	jmp zero_rest
+
+	/* exception on quad word loop in tail handling */
+	/* ecx:	loopcnt/8, %edx: length, rdi: correct */
+e_quad:
+	shll $3,%ecx
+	andl $7,%edx
+	addl %ecx,%edx
+	/* edx: bytes to zero, rdi: dest, eax:zero */
+zero_rest:
+	movq %rdx,%rcx
+e_byte:
+	xorl %eax,%eax
+e5:	rep 
+	stosb
+	/* when there is another exception while zeroing the rest just return */
+e_zero:		
+	movq %rdx,%rax
+	jmp ende
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/csum-copy.S linux-2.4.20/arch/x86_64/lib/csum-copy.S
--- linux-2.4.19/arch/x86_64/lib/csum-copy.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/csum-copy.S	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2002 Andi Kleen
+ *	
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details. No warranty for anything given at all.
+ */
+ 	#include <linux/linkage.h>
+	#include <asm/errno.h>
+
+//	#define FIX_ALIGNMENT 1
+/*
+ * Checksum copy with exception handling.
+ * On exceptions src_err_ptr or dst_err_ptr is set to -EFAULT and the 
+ * destination is zeroed.
+ * 
+ * Input
+ * rdi  source
+ * rsi  destination
+ * edx  len (32bit)
+ * ecx  sum (32bit) 
+ * r8   src_err_ptr (int)
+ * r9   dst_err_ptr (int)
+ *
+ * Output
+ * eax  64bit sum. undefined in case of exception.
+ * 
+ * Wrappers need to take care of valid exception sum and zeroing.		 
+ */
+
+/* for now - should vary this based on direction */
+ #define prefetch prefetcht2
+ #define movnti   movq
+
+	.macro source
+10:
+	.section __ex_table,"a"
+	.align 8
+	.quad 10b,bad_source
+	.previous
+	.endm
+		
+	.macro dest
+20:
+	.section __ex_table,"a"
+	.align 8
+	.quad 20b,bad_dest
+	.previous
+	.endm
+			
+	.globl csum_partial_copy_generic
+	.p2align
+csum_partial_copy_generic:
+	prefetchnta (%rdi)
+	
+	pushq %rbx
+	pushq %r12
+	pushq %r14
+	pushq %r15
+	movq %r8,%r14
+	movq %r9,%r15
+	movl  %ecx,%eax
+	movl  %edx,%ecx
+
+#ifdef FIX_ALIGNMENT
+	/* align source to 8 bytes */	
+	movl %edi,%r8d
+	andl $7,%r8d
+	jnz  bad_alignment	
+after_bad_alignment:
+#endif
+
+	movl  $64,%r10d
+	xorl  %r9d,%r9d
+	movq  %rcx,%r12
+
+	shrq  $6,%r12
+	/* loopcounter is maintained as one less to test efficiently for the
+	   previous to last iteration. This is needed to stop the prefetching. */
+	decq  %r12
+	js    handle_tail       /* < 64 */
+	jz    loop_no_prefetch  /* = 64 + X */ 
+	
+	/* main loop. clear in 64 byte blocks */
+	/* tries hard not to prefetch over the boundary */
+	/* r10:	64, r9: zero, r8: temp2, rbx: temp1, rax: sum, rcx: saved length */
+	/* r11:	temp3, rdx: temp4, r12 loopcnt */
+	.p2align
+loop:
+	/* Could prefetch more than one loop, but then it would be even
+	   trickier to avoid prefetching over the boundary. The hardware prefetch
+	   should take care of this anyways. The reason for this prefetch is
+	   just the non temporal hint to avoid cache pollution. Hopefully this
+	   will be handled properly by the hardware. */
+	prefetchnta 64(%rdi) 
+	
+loop_no_prefetch:
+	source
+	movq  (%rdi),%rbx
+	source
+	movq  8(%rdi),%r8
+	source
+	movq  16(%rdi),%r11
+	source
+	movq  24(%rdi),%rdx
+
+	dest
+	movnti %rbx,(%rsi)
+	dest
+	movnti %r8,8(%rsi)
+	dest
+	movnti %r11,16(%rsi)
+	dest
+	movnti %rdx,24(%rsi)
+		
+	addq  %rbx,%rax
+	adcq  %r8,%rax
+	adcq  %r11,%rax
+	adcq  %rdx,%rax
+
+	source
+	movq  32(%rdi),%rbx
+	source
+	movq  40(%rdi),%r8
+	source
+	movq  48(%rdi),%r11
+	source
+	movq  56(%rdi),%rdx
+	
+	dest
+	movnti %rbx,32(%rsi)
+	dest
+	movnti %r8,40(%rsi)
+	dest
+	movnti %r11,48(%rsi)
+	dest
+	movnti %rdx,56(%rsi)
+
+	adcq %rbx,%rax
+	adcq %r8,%rax
+	adcq %r11,%rax
+	adcq %rdx,%rax
+	
+	adcq %r9,%rax	/* add in carry */
+	
+	addq %r10,%rdi		
+	addq %r10,%rsi
+
+	decq %r12
+	jz   loop_no_prefetch	/* previous to last iteration? */
+	jns  loop
+
+	/* do last upto 56 bytes */
+handle_tail:
+	/* ecx:	count */
+	movl %ecx,%r10d
+	andl $63,%ecx
+	shrl $3,%ecx
+	jz 	 fold
+	clc
+	movl $8,%edx
+loop_8:	
+	source
+	movq (%rdi),%rbx
+	adcq %rbx,%rax
+	dest
+	movnti %rbx,(%rsi)
+	leaq (%rsi,%rdx),%rsi /* preserve carry */
+	leaq (%rdi,%rdx),%rdi
+	decl %ecx
+	jnz	loop_8
+	adcq %r9,%rax	/* add in carry */
+
+fold:
+	movl %eax,%ebx
+	shrq $32,%rax
+	addq %rbx,%rax
+
+	/* do last upto 6 bytes */	
+handle_7:
+	movl %r10d,%ecx
+	andl $7,%ecx
+	shrl $1,%ecx
+	jz   handle_1
+	movl $2,%edx
+	xorl %ebx,%ebx
+	clc  
+loop_1:	
+	source
+	movw (%rdi),%bx
+	adcq %rbx,%rax
+	dest
+	movw %bx,(%rsi)
+	addq %rdx,%rdi
+	addq %rdx,%rsi
+	decl %ecx
+	jnz loop_1
+	adcw %r9w,%ax	/* add in carry */
+	
+	/* handle last odd byte */
+handle_1:	
+	testl $1,%r10d
+	jz    ende
+	xorl  %ebx,%ebx
+	source
+	movb (%rdi),%bl
+	dest
+	movb %bl,(%rsi)
+	addw %bx,%ax
+	adcw %r9w,%ax		/* carry */
+			
+ende:		
+	sfence
+	popq %r15
+	popq %r14
+	popq %r12
+	popq %rbx
+	ret
+
+#ifdef FIX_ALIGNMENT
+	/* align source to 8 bytes. */
+	/* r8d:	unalignedness, ecx len */
+bad_alignment:
+	testl $1,%edi
+	jnz   odd_source
+
+	/* compute distance to next aligned position */
+	movl $8,%r8d
+	xchgl %r8d,%ecx
+	subl %r8d,%ecx
+
+	/* handle unaligned part */
+	shrl $1,%ecx
+	xorl %ebx,%ebx	
+	movl $2,%r10d
+align_loop:
+	source
+	movw (%rdi),%bx
+	addq %rbx,%rax	/* carry cannot happen */
+	dest
+	movw %bx,(%rsi)
+	addq %r10,%rdi
+	addq %r10,%rsi
+	decl %ecx
+	jnz align_loop
+	jmp after_bad_alignment
+
+	/* weird case. need to swap the sum at the end because the spec requires
+	   16 bit words of the sum to be always paired. 
+	   handle it recursively because it should be rather rare. */
+odd_source:
+	/* copy odd byte */
+	xorl %ebx,%ebx
+	source
+	movb (%rdi),%bl
+	addl %ebx,%eax       /* add to old checksum */
+	adcl $0,%ecx
+	dest
+	movb %al,(%rsi)
+	
+	/* fix arguments */
+	movl %eax,%ecx
+	incq %rsi
+	incq %rdi
+	decq %rdx 
+	call csum_partial_copy_generic
+	bswap %eax        /* this should work, but check */
+	jmp ende
+#endif
+
+	/* Exception handlers. Very simple, zeroing is done in the wrappers */
+bad_source:
+	movl $-EFAULT,(%r14)
+	jmp  ende
+	
+bad_dest:
+	movl $-EFAULT,(%r15)
+	jmp ende
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/csum-partial.c linux-2.4.20/arch/x86_64/lib/csum-partial.c
--- linux-2.4.19/arch/x86_64/lib/csum-partial.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/csum-partial.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,123 @@
+/*
+ * arch/x86_64/lib/csum-partial.c
+ *
+ * This file contains network checksum routines that are better done
+ * in an architecture-specific manner due to speed.
+ */
+ 
+#include <linux/compiler.h>
+#include <linux/module.h>
+
+/* Better way for this sought */
+static inline unsigned short from64to16(unsigned long x)
+{
+	/* add up 32-bit words for 33 bits */
+	x = (x & 0xffffffff) + (x >> 32);
+	/* add up 16-bit and 17-bit words for 17+c bits */
+	x = (x & 0xffff) + (x >> 16);
+	/* add up 16-bit and 2-bit for 16+c bit */
+	x = (x & 0xffff) + (x >> 16);
+	/* add up carry.. */
+	x = (x & 0xffff) + (x >> 16);
+	return x;
+}
+
+/*
+ * Do a 64-bit checksum on an arbitrary memory area.
+ * Returns a 32bit checksum.
+ *
+ * This isn't a great routine, but it's not _horrible_ either. 
+ * We rely on the compiler to unroll.
+ */
+static inline unsigned do_csum(const unsigned char * buff, int len)
+{
+	int odd, count;
+	unsigned long result = 0;
+
+	if (len <= 0)
+		goto out;
+	odd = 1 & (unsigned long) buff;
+	if (unlikely(odd)) {
+		result = *buff << 8;
+		len--;
+		buff++;
+	}
+	count = len >> 1;		/* nr of 16-bit words.. */
+	if (count) {
+		if (2 & (unsigned long) buff) {
+			result += *(unsigned short *) buff;
+			count--;
+			len -= 2;
+			buff += 2;
+		}
+		count >>= 1;		/* nr of 32-bit words.. */
+		if (count) {
+			if (4 & (unsigned long) buff) {
+				result += *(unsigned int *) buff;
+				count--;
+				len -= 4;
+				buff += 4;
+			}
+			count >>= 1;	/* nr of 64-bit words.. */
+			if (count) {
+				unsigned long zero = 0; 
+				do {
+					asm("  addq %1,%0\n"
+					    "  adcq %2,%0\n" 
+					    : "=r" (result)
+					    : "m"  (*buff), "r" (zero),  "0" (result));
+					count--;
+					buff += 8;
+				} while (count);
+				result = (result & 0xffffffff) + (result >> 32);
+			}
+			if (len & 4) {
+				result += *(unsigned int *) buff;
+				buff += 4;
+			}
+		}
+		if (len & 2) {
+			result += *(unsigned short *) buff;
+			buff += 2;
+		}
+	}
+	if (len & 1)
+		result += *buff;
+	result = from64to16(result);
+	if (unlikely(odd))
+		return ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+out:
+	return result;
+}
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 64-bit boundary
+ */
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
+{
+	unsigned result = do_csum(buff, len);
+
+	/* add in old sum, and carry.. */
+	asm("addl %1,%0\n\t"
+	    "adcl $0,%0" : "=r" (result) : "r" (sum), "0" (result)); 
+	return result;
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+unsigned short ip_compute_csum(unsigned char * buff, int len)
+{
+	return ~csum_partial(buff,len,0); 
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/csum-wrappers.c linux-2.4.20/arch/x86_64/lib/csum-wrappers.c
--- linux-2.4.19/arch/x86_64/lib/csum-wrappers.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/csum-wrappers.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,109 @@
+/* Copyright 2002 Andi Kleen, SuSE Labs.
+ * Subject to the GNU Public License v.2
+ * 
+ * Wrappers of assembly checksum functions for x86-64.
+ */
+
+#include <asm/checksum.h>
+#include <linux/module.h>
+
+/* Better way for this sought */
+static inline unsigned from64to32(unsigned long x)
+{
+	/* add up 32-bit words for 33 bits */
+        x = (x & 0xffffffff) + (x >> 32);
+        /* add up 16-bit and 17-bit words for 17+c bits */
+        x = (x & 0xffff) + (x >> 16);
+        /* add up 16-bit and 2-bit for 16+c bit */
+        x = (x & 0xffff) + (x >> 16);
+        return x;
+}
+
+/** 
+ * csum_partial_copy_from_user - Copy and checksum from user space. 
+ * @src: source address (user space) 
+ * @dst: destination address
+ * @len: number of bytes to be copied.
+ * @isum: initial sum that is added into the result (32bit unfolded)
+ * @errp: set to -EFAULT for an bad source address.
+ * 
+ * Returns an 32bit unfolded checksum of the buffer.
+ * src and dst are best aligned to 64bits. 
+ */ 
+unsigned int 
+csum_partial_copy_from_user(const char *src, char *dst, 
+			    int len, unsigned int isum, int *errp)
+{ 
+	*errp = 0;
+	if (likely(access_ok(VERIFY_READ,src, len))) { 
+		unsigned long sum; 
+		sum = csum_partial_copy_generic(src,dst,len,isum,errp,NULL);
+		if (likely(*errp == 0)) 
+			return from64to32(sum); 
+	} 
+	*errp = -EFAULT;
+	memset(dst,0,len); 
+	return 0;		
+} 
+
+EXPORT_SYMBOL(csum_partial_copy_from_user);
+
+/** 
+ * csum_partial_copy_to_user - Copy and checksum to user space. 
+ * @src: source address
+ * @dst: destination address (user space)
+ * @len: number of bytes to be copied.
+ * @isum: initial sum that is added into the result (32bit unfolded)
+ * @errp: set to -EFAULT for an bad destination address.
+ * 
+ * Returns an 32bit unfolded checksum of the buffer.
+ * src and dst are best aligned to 64bits.
+ */ 
+unsigned int 
+csum_partial_copy_to_user(const char *src, char *dst, 
+			  int len, unsigned int isum, int *errp)
+{ 
+	if (unlikely(!access_ok(VERIFY_WRITE, dst, len))) {
+		*errp = -EFAULT;
+		return 0; 
+	}
+	*errp = 0;
+	return from64to32(csum_partial_copy_generic(src,dst,len,isum,NULL,errp)); 
+} 
+
+EXPORT_SYMBOL(csum_partial_copy_to_user);
+
+/** 
+ * csum_partial_copy_nocheck - Copy and checksum.
+ * @src: source address
+ * @dst: destination address
+ * @len: number of bytes to be copied.
+ * @isum: initial sum that is added into the result (32bit unfolded)
+ * 
+ * Returns an 32bit unfolded checksum of the buffer.
+ */ 
+unsigned int 
+csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum)
+{ 
+	return from64to32(csum_partial_copy_generic(src,dst,len,sum,NULL,NULL));
+} 
+
+//EXPORT_SYMBOL(csum_partial_copy_nocheck);
+
+unsigned short csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr,
+			       __u32 len, unsigned short proto, unsigned int sum) 
+{
+	__u64 rest, sum64;
+     
+	rest = (__u64)htonl(len) + (__u64)htons(proto) + (__u64)sum;
+	asm("  addq (%[saddr]),%[sum]\n"
+	    "  adcq 8(%[saddr]),%[sum]\n"
+	    "  adcq (%[daddr]),%[sum]\n" 
+	    "  adcq 8(%[daddr]),%[sum]\n"
+	    "  adcq $0,%[sum]\n"
+	    : [sum] "=r" (sum64) 
+	    : "[sum]" (rest),[saddr] "r" (saddr), [daddr] "r" (daddr));
+	return csum_fold(from64to32(sum64)); 
+}
+
+EXPORT_SYMBOL(csum_ipv6_magic);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/dec_and_lock.c linux-2.4.20/arch/x86_64/lib/dec_and_lock.c
--- linux-2.4.19/arch/x86_64/lib/dec_and_lock.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/dec_and_lock.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,40 @@
+/*
+ * x86 version of "atomic_dec_and_lock()" using
+ * the atomic "cmpxchg" instruction.
+ *
+ * (For CPU's lacking cmpxchg, we use the slow
+ * generic version, and this one never even gets
+ * compiled).
+ */
+
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+
+int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+{
+	int counter;
+	int newcount;
+
+repeat:
+	counter = atomic_read(atomic);
+	newcount = counter-1;
+
+	if (!newcount)
+		goto slow_path;
+
+	asm volatile("lock; cmpxchgl %1,%2"
+		:"=a" (newcount)
+		:"r" (newcount), "m" (atomic->counter), "0" (counter));
+
+	/* If the above failed, "eax" will have changed */
+	if (newcount != counter)
+		goto repeat;
+	return 0;
+
+slow_path:
+	spin_lock(lock);
+	if (atomic_dec_and_test(atomic))
+		return 1;
+	spin_unlock(lock);
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/delay.c linux-2.4.20/arch/x86_64/lib/delay.c
--- linux-2.4.19/arch/x86_64/lib/delay.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/delay.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,43 @@
+/*
+ *	Precise Delay Loops for i386
+ *
+ *	Copyright (C) 1993 Linus Torvalds
+ *	Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ *	The __delay function must _NOT_ be inlined as its execution time
+ *	depends wildly on alignment on many x86 processors. 
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <asm/delay.h>
+
+#ifdef CONFIG_SMP
+#include <asm/smp.h>
+#endif
+
+void __delay(unsigned long loops)
+{
+#ifndef CONFIG_SIMNOW
+	unsigned long bclock, now;
+	
+	rdtscl(bclock);
+	do
+	{
+		rep_nop(); 
+		rdtscl(now);
+	}
+	while((now-bclock) < loops);
+#endif
+}
+
+inline void __const_udelay(unsigned long xloops)
+{
+        __delay(((xloops * current_cpu_data.loops_per_jiffy) >> 32) * HZ);
+}
+
+void __udelay(unsigned long usecs)
+{
+	__const_udelay(usecs * 0x000010c6);  /* 2**32 / 1000000 */
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/getuser.S linux-2.4.20/arch/x86_64/lib/getuser.S
--- linux-2.4.19/arch/x86_64/lib/getuser.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/getuser.S	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,91 @@
+/*
+ * __get_user functions.
+ *
+ * (C) Copyright 1998 Linus Torvalds
+ *
+ * These functions have a non-standard call interface
+ * to make them more efficient, especially as they
+ * return an error value in addition to the "real"
+ * return value.
+ */
+
+/*
+ * __get_user_X
+ *
+ * Inputs:	%rax contains the address
+ *
+ * Outputs:	%rax is error code (0 or -EFAULT)
+ *		%rdx contains zero-extended value
+ * 
+ * %rbx is destroyed.
+ *
+ * These functions should not modify any other registers,
+ * as they get called from within inline assembly.
+ */
+
+#include <linux/linkage.h>
+#include <asm/page.h>
+#include <asm/errno.h>
+#include <asm/current.h>
+#include <asm/offset.h>
+#include <asm/calling.h>
+	
+	.text
+	.p2align
+.globl __get_user_1
+__get_user_1:	
+	GET_CURRENT(%rbx)
+	cmpq tsk_addr_limit(%rbx),%rax
+	jae bad_get_user
+1:	movzb (%rax),%edx
+	xorq %rax,%rax
+	ret
+
+	.p2align	
+.globl __get_user_2
+__get_user_2:
+	GET_CURRENT(%rbx) 
+	addq $1,%rax
+	jc bad_get_user
+	cmpq tsk_addr_limit(%rbx),%rax 
+	jae	 bad_get_user
+2:	movzwl -1(%rax),%edx
+	xorq %rax,%rax
+	ret
+
+	.p2align
+.globl __get_user_4
+__get_user_4:
+	GET_CURRENT(%rbx) 
+	addq $3,%rax
+	jc bad_get_user
+	cmpq tsk_addr_limit(%rbx),%rax 
+	jae bad_get_user
+3:	movl -3(%rax),%edx
+	xorq %rax,%rax
+	ret
+
+	.p2align
+.globl __get_user_8
+__get_user_8:
+	GET_CURRENT(%rbx) 
+	addq $7,%rax
+	jc bad_get_user
+	cmpq tsk_addr_limit(%rbx),%rax
+	jae	bad_get_user
+4:	movq -7(%rax),%rdx
+	xorq %rax,%rax
+	ret
+
+ENTRY(bad_get_user)
+bad_get_user:
+	xorq %rdx,%rdx
+	movq $(-EFAULT),%rax
+	ret
+
+.section __ex_table,"a"
+	.quad 1b,bad_get_user
+	.quad 2b,bad_get_user
+	.quad 3b,bad_get_user
+	.quad 4b,bad_get_user
+.previous
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/io.c linux-2.4.20/arch/x86_64/lib/io.c
--- linux-2.4.19/arch/x86_64/lib/io.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/io.c	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,13 @@
+#include <linux/string.h>
+#include <linux/module.h>
+#include <asm/io.h>
+
+void *memcpy_toio(void *dst,const void*src,unsigned len)
+{
+	return __inline_memcpy(__io_virt(dst),src,len);
+}
+
+void *memcpy_fromio(void *dst,const void*src,unsigned len)
+{
+	return __inline_memcpy(dst,__io_virt(src),len);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/iodebug.c linux-2.4.20/arch/x86_64/lib/iodebug.c
--- linux-2.4.19/arch/x86_64/lib/iodebug.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/iodebug.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,19 @@
+#include <asm/io.h>
+
+void * __io_virt_debug(unsigned long x, const char *file, int line)
+{
+	if (x < PAGE_OFFSET) {
+		printk("io mapaddr 0x%05lx not valid at %s:%d!\n", x, file, line);
+		return __va(x);
+	}
+	return (void *)x;
+}
+
+unsigned long __io_phys_debug(unsigned long x, const char *file, int line)
+{
+	if (x < PAGE_OFFSET) {
+		printk("io mapaddr 0x%05lx not valid at %s:%d!\n", x, file, line);
+		return x;
+	}
+	return __pa(x);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/memcpy.S linux-2.4.20/arch/x86_64/lib/memcpy.S
--- linux-2.4.19/arch/x86_64/lib/memcpy.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/memcpy.S	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,114 @@
+/* Copyright 2002 Andi Kleen */
+	
+/*
+ * memcpy - Copy a memory block.
+ *
+ * Input:	
+ * rdi destination
+ * rsi source
+ * rdx count
+ * 
+ * Output:
+ * rax original destination
+ */	
+
+ // #define FIX_ALIGNMENT
+ 	.globl __memcpy
+	.globl memcpy
+	.p2align
+__memcpy:
+memcpy:		
+	pushq %rbx
+	movq %rdi,%rax
+
+#ifdef FIX_ALIGNMENT
+	movl %edi,%ecx
+	andl $7,%ecx
+	jnz  bad_alignment	
+after_bad_alignment:
+#endif
+
+	movq %rdx,%rcx
+	movl $64,%ebx
+	shrq $6,%rcx
+	jz handle_tail
+	
+loop_64:
+	movq (%rsi),%r11
+	movq 8(%rsi),%r8
+	movq 2*8(%rsi),%r9
+	movq 3*8(%rsi),%r10
+	movq %r11,(%rdi)
+	movq %r8,1*8(%rdi)
+	movq %r9,2*8(%rdi)
+	movq %r10,3*8(%rdi)
+		
+	movq 4*8(%rsi),%r11
+	movq 5*8(%rsi),%r8
+	movq 6*8(%rsi),%r9
+	movq 7*8(%rsi),%r10
+	movq %r11,4*8(%rdi)
+	movq %r8,5*8(%rdi)
+	movq %r9,6*8(%rdi)
+	movq %r10,7*8(%rdi)
+
+	addq %rbx,%rsi	
+	addq %rbx,%rdi
+	decl %ecx
+	jnz  loop_64
+
+handle_tail:
+	movl %edx,%ecx
+	andl $63,%ecx
+	shrl $3,%ecx
+	jz   handle_7
+	movl $8,%ebx
+loop_8: 
+	movq (%rsi),%r8
+	movq %r8,(%rdi) 
+	addq %rbx,%rdi
+	addq %rbx,%rsi
+	decl %ecx
+	jnz  loop_8
+
+handle_7:
+	movl %edx,%ecx
+	andl $7,%ecx
+	jz ende
+loop_1:
+	movb (%rsi),%r8b
+	movb %r8b,(%rdi) 
+	incq %rdi
+	incq %rsi
+	decl %ecx
+	jnz loop_1
+	
+ende: 	
+	sfence
+	popq %rbx
+	ret
+
+
+#ifdef FIX_ALIGNMENT
+	/* align destination */
+	/* This is simpleminded. For bigger blocks it may make sense to align
+	   src and dst to their aligned subset and handle the rest separately */
+bad_alignment:
+	movl $8,%r9d
+	subl %ecx,%r9d
+	movl %r9d,%ecx
+	subq %r9,%rdx
+	js   small_alignment
+	jz   small_alignment
+align_1:
+	movb (%rsi),%r8b
+	movb %r8b,(%rdi) 
+	incq %rdi
+	incq %rsi
+	decl %ecx
+	jnz  align_1
+	jmp after_bad_alignment
+small_alignment:
+	addq %r9,%rdx
+	jmp handle_7
+#endif	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/memmove.c linux-2.4.20/arch/x86_64/lib/memmove.c
--- linux-2.4.19/arch/x86_64/lib/memmove.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/memmove.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,27 @@
+/* Normally compiler builtins are used, but sometimes the compiler calls out
+   of line code. Based on asm-i386/string.h.
+ */
+#define _STRING_C
+#include <linux/string.h>
+
+#undef memmove
+void *memmove(void * dest,const void *src,size_t count)
+{
+	if (dest < src) { 
+		__inline_memcpy(dest,src,count);
+	} else {
+		/* Could be more clever and move longs */
+		unsigned long d0, d1, d2;
+		__asm__ __volatile__(
+			"std\n\t"
+			"rep\n\t"
+			"movsb\n\t"
+			"cld"
+			: "=&c" (d0), "=&S" (d1), "=&D" (d2)
+			:"0" (count),
+			"1" (count-1+(const char *)src),
+			"2" (count-1+(char *)dest)
+			:"memory");
+	}
+	return dest;
+} 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/memset.S linux-2.4.20/arch/x86_64/lib/memset.S
--- linux-2.4.19/arch/x86_64/lib/memset.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/memset.S	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,84 @@
+/* Copyright 2002 Andi Kleen, SuSE Labs */
+
+/*
+ * ISO C memset - set a memory block to a byte value.
+ *	
+ * rdi   destination
+ * rsi   value (char) 
+ * rdx   count (bytes) 
+ * 
+ * rax   original destination
+ */	
+ 	.globl __memset
+	.globl memset
+	.p2align
+memset:	
+__memset:
+	movq %rdi,%r10
+	movq %rdx,%r11
+
+	/* expand byte value  */
+	movzbl %sil,%ecx
+	movabs $0x0101010101010101,%rax
+	mul    %rcx		/* with rax, clobbers rdx */
+
+	/* align dst */
+	movl  %edi,%r9d
+	andl  $7,%r9d	
+	jnz  bad_alignment
+after_bad_alignment:
+
+	movq %r11,%rcx
+	movl $64,%r8d
+	shrq $6,%rcx
+	jz	 handle_tail
+
+loop_64:	
+	movq  %rax,(%rdi) 
+	movq  %rax,8(%rdi) 
+	movq  %rax,16(%rdi) 
+	movq  %rax,24(%rdi) 
+	movq  %rax,32(%rdi) 
+	movq  %rax,40(%rdi) 
+	movq  %rax,48(%rdi) 
+	movq  %rax,56(%rdi) 
+	addq    %r8,%rdi
+	decl   %ecx
+	jnz    loop_64
+
+	/* Handle tail in loops. The loops should be faster than hard
+	   to predict jump tables. */ 
+handle_tail:
+	movl	%r11d,%ecx
+	andl    $63&(~7),%ecx
+	jz 		handle_7
+	shrl	$3,%ecx
+loop_8:
+	movq  %rax,(%rdi) 
+	addq    $8,%rdi
+	decl   %ecx
+	jnz    loop_8
+
+handle_7:
+	movl	%r11d,%ecx
+	andl	$7,%ecx
+	jz      ende
+loop_1:
+	movb 	%al,(%rdi)
+	addq	$1,%rdi
+	decl    %ecx
+	jnz     loop_1
+	
+ende:	
+	movq	%r10,%rax
+	ret
+
+bad_alignment:
+	cmpq $7,%r11
+	jbe	handle_7
+	movq %rax,(%rdi)	/* unaligned store */
+	movq $8,%r8
+	subq %r9,%r8 
+	addq %r8,%rdi
+	subq %r8,%r11
+	jmp after_bad_alignment
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/old-checksum.c linux-2.4.20/arch/x86_64/lib/old-checksum.c
--- linux-2.4.19/arch/x86_64/lib/old-checksum.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/old-checksum.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,33 @@
+/*
+ * Temporal C versions of the checksum functions until optimized assembler versions
+ * can go in.
+ */
+
+#include <net/checksum.h>
+
+/*
+ * Copy from userspace and compute checksum.  If we catch an exception
+ * then zero the rest of the buffer.
+ */
+unsigned int csum_partial_copy_from_user (const char *src, char *dst,
+                                          int len, unsigned int sum,
+                                          int *err_ptr)
+{
+	int missing;
+
+	missing = copy_from_user(dst, src, len);
+	if (missing) {
+		memset(dst + len - missing, 0, missing);
+		*err_ptr = -EFAULT;
+	}
+		
+	return csum_partial(dst, len, sum);
+}
+
+unsigned int csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum)
+{
+	memcpy(dst,src,len);
+	return csum_partial(dst,len,sum);
+}
+
+/* Fallback for csum_and_copy_to_user is currently in include/net/checksum.h */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/putuser.S linux-2.4.20/arch/x86_64/lib/putuser.S
--- linux-2.4.19/arch/x86_64/lib/putuser.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/putuser.S	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,88 @@
+/*
+ * __put_user functions.
+ *
+ * (C) Copyright 1998 Linus Torvalds
+ *
+ * These functions have a non-standard call interface
+ * to make them more efficient.
+ */
+
+/*
+ * __put_user_X
+ *
+ * Inputs:	%rax contains the address
+ *		%rdx contains the value
+ *
+ * Outputs:	%rax is error code (0 or -EFAULT)
+ *		%rbx is corrupted (will contain "current_task").
+ *
+ * These functions should not modify any other registers,
+ * as they get called from within inline assembly.
+ */
+
+/* FIXME: putuser.S should be really merged with getuser.S, and preprocessor should be used to keep code duplication lower */
+
+#include <linux/linkage.h>
+#include <asm/page.h>
+#include <asm/errno.h>
+#include <asm/current.h>
+#include <asm/offset.h>
+
+.text
+.p2align
+.globl __put_user_1
+__put_user_1:
+	GET_CURRENT(%rbx)
+	cmpq tsk_addr_limit(%rbx),%rax
+	jae bad_put_user
+1:	movb %dl,(%rax)
+	xorq %rax,%rax
+	ret
+
+.p2align
+.globl __put_user_2
+__put_user_2:
+	GET_CURRENT(%rbx) 
+	addq $1,%rax
+	jc		bad_put_user
+	cmpq	tsk_addr_limit(%rbx),%rax
+	jae 	bad_put_user
+2:	movw %dx,-1(%rax)
+	xorq %rax,%rax
+	ret
+
+.p2align
+.globl __put_user_4
+__put_user_4:
+	GET_CURRENT(%rbx) 
+	addq $3,%rax
+	jc		bad_put_user
+	cmpq	tsk_addr_limit(%rbx),%rax
+	jae 	bad_put_user
+3:	movl %edx,-3(%rax)
+	xorq %rax,%rax
+	ret
+
+.p2align
+.globl __put_user_8
+__put_user_8:
+	GET_CURRENT(%rbx) 
+	addq $7,%rax
+	jc	bad_put_user
+	cmpq	tsk_addr_limit(%rbx),%rax
+	jae 	bad_put_user
+4:	movq %rdx,-7(%rax)
+	xorq %rax,%rax
+	ret
+
+ENTRY(bad_put_user)	
+bad_put_user:
+	movq $(-EFAULT),%rax
+	ret
+
+.section __ex_table,"a"
+	.quad 1b,bad_put_user
+	.quad 2b,bad_put_user
+	.quad 3b,bad_put_user
+	.quad 4b,bad_put_user	
+.previous
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/thunk.S linux-2.4.20/arch/x86_64/lib/thunk.S
--- linux-2.4.19/arch/x86_64/lib/thunk.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/thunk.S	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,81 @@
+	/*
+	 * Save registers before calling assembly functions. This avoids
+	 * disturbance of register allocation in some inline assembly constructs.
+	 * Copyright 2001,2002 by Andi Kleen, SuSE Labs.
+	 * Subject to the GNU public license, v.2. No warranty of any kind.
+	 * $Id: thunk.S,v 1.2 2002/03/13 20:06:58 ak Exp $
+	 */
+
+	#include <linux/config.h>
+	#include <linux/linkage.h>
+	#include <asm/calling.h>			
+	#include <asm/rwlock.h>
+		
+	/* rdi:	arg1 ... normal C conventions. rax is saved/restored. */ 	
+	.macro thunk name,func
+	.globl \name
+\name:	
+	SAVE_ARGS
+	call \func
+	jmp  restore
+	.endm
+
+	/* rdi:	arg1 ... normal C conventions. rax is passed from C. */ 	
+	.macro thunk_retrax name,func
+	.globl \name
+\name:	
+	SAVE_ARGS
+	call \func
+	jmp  restore_norax
+	.endm
+	
+
+#ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM
+	thunk rwsem_down_read_failed_thunk,rwsem_down_read_failed
+	thunk rwsem_down_write_failed_thunk,rwsem_down_write_failed
+	thunk rwsem_wake_thunk,rwsem_wake
+#endif	
+	thunk do_softirq_thunk,do_softirq
+	
+	thunk __down_failed,__down
+	thunk_retrax __down_failed_interruptible,__down_interruptible
+	thunk_retrax __down_failed_trylock,__down_trylock
+	thunk __up_wakeup,__up
+	
+restore:
+	RESTORE_ARGS
+	ret	
+	
+restore_norax:	
+	RESTORE_ARGS 1
+	ret
+
+#ifdef CONFIG_SMP
+/* Support for read/write spinlocks. */
+	
+/* rax:	pointer to rwlock_t */	
+ENTRY(__write_lock_failed)
+	lock
+	addl $RW_LOCK_BIAS,(%rax)
+1:	rep
+	nop
+	cmpl $RW_LOCK_BIAS,(%rax)
+	jne 1b
+	lock 
+	subl $RW_LOCK_BIAS,(%rax)
+	jnz  __write_lock_failed
+	ret
+
+/* rax:	pointer to rwlock_t */	
+ENTRY(__read_lock_failed)
+	lock
+	incl (%rax)
+1:	rep
+	nop
+	cmpl $1,(%rax)
+	js 1b
+	lock
+	decl (%rax)
+	js __read_lock_failed
+	ret
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/lib/usercopy.c linux-2.4.20/arch/x86_64/lib/usercopy.c
--- linux-2.4.19/arch/x86_64/lib/usercopy.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/lib/usercopy.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,128 @@
+/* 
+ * User address space access functions.
+ *
+ * Copyright 1997 Andi Kleen <ak@muc.de>
+ * Copyright 1997 Linus Torvalds
+ * Copyright 2002 Andi Kleen <ak@suse.de>
+ */
+#include <asm/uaccess.h>
+
+/*
+ * Copy a null terminated string from userspace.
+ */
+
+#define __do_strncpy_from_user(dst,src,count,res)			   \
+do {									   \
+	long __d0, __d1, __d2;						   \
+	__asm__ __volatile__(						   \
+		"	testq %1,%1\n"					   \
+		"	jz 2f\n"					   \
+		"0:	lodsb\n"					   \
+		"	stosb\n"					   \
+		"	testb %%al,%%al\n"				   \
+		"	jz 1f\n"					   \
+		"	decq %1\n"					   \
+		"	jnz 0b\n"					   \
+		"1:	subq %1,%0\n"					   \
+		"2:\n"							   \
+		".section .fixup,\"ax\"\n"				   \
+		"3:	movq %5,%0\n"					   \
+		"	jmp 2b\n"					   \
+		".previous\n"						   \
+		".section __ex_table,\"a\"\n"				   \
+		"	.align 4\n"					   \
+		"	.quad 0b,3b\n"					   \
+		".previous"						   \
+		: "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1),	   \
+		  "=&D" (__d2)						   \
+		: "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
+		: "memory");						   \
+} while (0)
+
+long
+__strncpy_from_user(char *dst, const char *src, long count)
+{
+	long res;
+	__do_strncpy_from_user(dst, src, count, res);
+	return res;
+}
+
+long
+strncpy_from_user(char *dst, const char *src, long count)
+{
+	long res = -EFAULT;
+	if (access_ok(VERIFY_READ, src, 1))
+		__do_strncpy_from_user(dst, src, count, res);
+	return res;
+}
+
+/*
+ * Zero Userspace
+ */
+
+unsigned long __clear_user(void *addr, unsigned long size)
+{
+	long __d0;
+	/* no memory constraint because it doesn't change any memory gcc knows
+	   about */
+	asm volatile(
+		"	testq  %[size8],%[size8]\n"
+		"	jz     4f\n"
+		"0:	movnti %[zero],(%[dst])\n"
+		"	addq   %[eight],%[dst]\n"
+		"	decl %%ecx ; jnz   0b\n"
+		"4:	movq  %[size1],%%rcx\n"
+		"	testl %%ecx,%%ecx\n"
+		"	jz     2f\n"
+		"1:	movb   %b[zero],(%[dst])\n"
+		"	incq   %[dst]\n"
+		"	decl %%ecx ; jnz  1b\n"
+		"2:	sfence\n"
+		".section .fixup,\"ax\"\n"
+		"3:	lea 0(%[size1],%[size8],8),%[size8]\n"
+		"	jmp 2b\n"
+		".previous\n"
+		".section __ex_table,\"a\"\n"
+		"       .align 8\n"
+		"	.quad 0b,3b\n"
+		"	.quad 1b,2b\n"
+		".previous"
+		: [size8] "=c"(size), [dst] "=&D" (__d0)
+		: [size1] "r"(size & 7), "[size8]" (size / 8), "[dst] "(addr),
+		  [zero] "r" (0UL), [eight] "r" (8UL));
+	return size;
+}
+
+
+unsigned long clear_user(void *to, unsigned long n)
+{
+	if (access_ok(VERIFY_WRITE, to, n))
+		return __clear_user(to, n);
+	return n;
+}
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 on exception, a value greater than N if too long
+ */
+
+long strnlen_user(const char *s, long n)
+{
+	unsigned long res = 0;
+	char c;
+
+	if (!access_ok(VERIFY_READ, s, n))
+		return 0;
+
+	while (1) {
+		if (get_user(c, s))
+			return 0;
+		if (!c)
+			return res+1;
+		if (res>n)
+			return n+1;
+		res++;
+		s++;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/math-emu/README linux-2.4.20/arch/x86_64/math-emu/README
--- linux-2.4.19/arch/x86_64/math-emu/README	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/math-emu/README	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1 @@
+x86-64 machines should never require math emulation.
\ No newline at end of file
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/mm/Makefile linux-2.4.20/arch/x86_64/mm/Makefile
--- linux-2.4.19/arch/x86_64/mm/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/mm/Makefile	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,17 @@
+#
+# Makefile for the linux i386-specific parts of the memory manager.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := mm.o
+obj-y	 := init.o fault.o ioremap.o extable.o modutil.o pageattr.o
+obj-$(CONFIG_DISCONTIGMEM) += numa.o
+obj-$(CONFIG_K8_NUMA) += k8topology.o
+
+export-objs := pageattr.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/mm/extable.c linux-2.4.20/arch/x86_64/mm/extable.c
--- linux-2.4.19/arch/x86_64/mm/extable.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/mm/extable.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,62 @@
+/*
+ * linux/arch/i386/mm/extable.c
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+
+extern const struct exception_table_entry __start___ex_table[];
+extern const struct exception_table_entry __stop___ex_table[];
+
+static inline unsigned long
+search_one_table(const struct exception_table_entry *first,
+		 const struct exception_table_entry *last,
+		 unsigned long value)
+{
+        while (first <= last) {
+		const struct exception_table_entry *mid;
+		long diff;
+
+		mid = (last - first) / 2 + first;
+		diff = mid->insn - value;
+                if (diff == 0)
+                        return mid->fixup;
+                else if (diff < 0)
+                        first = mid+1;
+                else
+                        last = mid-1;
+        }
+        return 0;
+}
+
+extern spinlock_t modlist_lock;
+
+unsigned long
+search_exception_table(unsigned long addr)
+{
+	unsigned long ret = 0;
+	unsigned long flags;
+
+#ifndef CONFIG_MODULES
+	/* There is only the kernel to search.  */
+	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
+	return ret;
+#else
+	/* The kernel is the last "module" -- no need to treat it special.  */
+	struct module *mp;
+
+	spin_lock_irqsave(&modlist_lock, flags);
+	for (mp = module_list; mp != NULL; mp = mp->next) {
+		if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING)))
+			continue;
+		ret = search_one_table(mp->ex_table_start,
+				       mp->ex_table_end - 1, addr);
+		if (ret)
+			break;
+	}
+	spin_unlock_irqrestore(&modlist_lock, flags);
+	return ret;
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/mm/fault.c linux-2.4.20/arch/x86_64/mm/fault.c
--- linux-2.4.19/arch/x86_64/mm/fault.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/mm/fault.c	2002-10-29 11:18:51.000000000 +0000
@@ -0,0 +1,357 @@
+/*
+ *  linux/arch/x86-64/mm/fault.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Copyright (C) 2001,2002 Andi Kleen, SuSE Labs.
+ */
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/vt_kern.h>		/* For unblank_screen() */
+#include <linux/compiler.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/hardirq.h>
+#include <asm/smp.h>
+#include <asm/proto.h>
+#include <asm/kdebug.h>
+
+spinlock_t pcrash_lock; 
+int crashing_cpu;
+
+extern spinlock_t console_lock, timerlist_lock;
+
+void bust_spinlocks(int yes)
+{
+ 	spin_lock_init(&timerlist_lock);
+	if (yes) {
+		oops_in_progress = 1;
+#ifdef CONFIG_SMP
+		global_irq_lock = 0;	/* Many serial drivers do __global_cli() */
+#endif
+	} else {
+	int loglevel_save = console_loglevel;
+#ifdef CONFIG_VT
+		unblank_screen();
+#endif
+		oops_in_progress = 0;
+		/*
+		 * OK, the message is on the console.  Now we call printk()
+		 * without oops_in_progress set so that printk will give klogd
+		 * a poke.  Hold onto your hats...
+		 */
+		console_loglevel = 15;		/* NMI oopser may have shut the console up */
+		printk(" ");
+		console_loglevel = loglevel_save;
+	}
+}
+
+void dump_pagetable(unsigned long address)
+{
+	static char *name[] = { "PML4", "PGD", "PDE", "PTE" }; 
+	int i, shift;
+	unsigned long page;
+
+	shift = 9+9+9+12;
+	address &= ~0xFFFF000000000000UL;
+	asm("movq %%cr3,%0" : "=r" (page)); 
+	for (i = 0; i < 4; i++) { 	
+		unsigned long *padr = (unsigned long *) __va(page); 
+		padr += (address >> shift) & 0x1FFU;
+		if (__get_user(page, padr)) { 
+			printk("%s: bad %p\n", name[i], padr); 
+			break;
+		}
+		printk("%s: %016lx ", name[i], page); 
+		if ((page & (1 | (1<<7))) != 1) /* Not present or 2MB page */
+			break;
+		page &= ~0xFFFUL;
+		shift -= (i == 0) ? 12 : 9;
+	} 
+	printk("\n");
+}
+
+int page_fault_trace; 
+int exception_trace = 1;
+
+/*
+ * This routine handles page faults.  It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ *
+ * error_code:
+ *	bit 0 == 0 means no page found, 1 means protection fault
+ *	bit 1 == 0 means read, 1 means write
+ *	bit 2 == 0 means kernel, 1 means user-mode
+ *      bit 3 == 1 means fault was an instruction fetch
+ */
+asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+{
+	struct task_struct *tsk;
+	struct mm_struct *mm;
+	struct vm_area_struct * vma;
+	unsigned long address;
+	unsigned long fixup;
+	int write;
+	siginfo_t info;
+
+	/* get the address */
+	__asm__("movq %%cr2,%0":"=r" (address));
+
+#ifdef CONFIG_CHECKING
+	if (page_fault_trace) 
+		printk("pfault %d rip:%lx rsp:%lx cs:%lu ss:%lu addr %lx error %lx\n",
+		       stack_smp_processor_id(), regs->rip,regs->rsp,regs->cs,
+			   regs->ss,address,error_code); 
+
+	{ 
+		unsigned long gs; 
+		struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); 
+		rdmsrl(MSR_GS_BASE, gs); 
+		if (gs != (unsigned long)pda) { 
+			wrmsrl(MSR_GS_BASE, pda); 
+			printk("page_fault: wrong gs %lx expected %p\n", gs, pda);
+		}
+	}
+#endif
+			
+	tsk = current;
+	mm = tsk->mm;
+	info.si_code = SEGV_MAPERR;
+
+	/* 5 => page not present and from supervisor mode */
+	if (unlikely(!(error_code & 5) &&
+		     ((address >= VMALLOC_START && address <= VMALLOC_END) ||
+		      (address >= MODULES_VADDR && address <= MODULES_END))))
+		goto vmalloc_fault;
+  
+	/*
+	 * If we're in an interrupt or have no user
+	 * context, we must not take the fault..
+	 */
+	if (in_interrupt() || !mm)
+		goto no_context;
+
+again:
+	down_read(&mm->mmap_sem);
+
+	vma = find_vma(mm, address);
+	if (!vma)
+		goto bad_area;
+	if (vma->vm_start <= address)
+		goto good_area;
+	if (!(vma->vm_flags & VM_GROWSDOWN))
+		goto bad_area;
+	if (error_code & 4) {
+		// XXX: align red zone size with ABI 
+		if (address + 128 < regs->rsp)
+			goto bad_area;
+	}
+	if (expand_stack(vma, address))
+		goto bad_area;
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+	info.si_code = SEGV_ACCERR;
+	write = 0;
+	switch (error_code & 3) {
+		default:	/* 3: write, present */
+			/* fall through */
+		case 2:		/* write, not present */
+			if (!(vma->vm_flags & VM_WRITE))
+				goto bad_area;
+			write++;
+			break;
+		case 1:		/* read, present */
+			goto bad_area;
+		case 0:		/* read, not present */
+			if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+				goto bad_area;
+	}
+
+	/*
+	 * If for any reason at all we couldn't handle the fault,
+	 * make sure we exit gracefully rather than endlessly redo
+	 * the fault.
+	 */
+	switch (handle_mm_fault(mm, vma, address, write)) {
+	case 1:
+		tsk->min_flt++;
+		break;
+	case 2:
+		tsk->maj_flt++;
+		break;
+	case 0:
+		goto do_sigbus;
+	default:
+		goto out_of_memory;
+	}
+
+	up_read(&mm->mmap_sem);
+	return;
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+	up_read(&mm->mmap_sem);
+
+bad_area_nosemaphore:
+
+	/* User mode accesses just cause a SIGSEGV */
+	if (error_code & 4) {
+		if (exception_trace) {
+#if 1
+			dump_pagetable(address);
+#endif	
+			printk("%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n",
+					current->comm, current->pid, address, regs->rip,
+					regs->rsp, error_code);
+		}
+		tsk->thread.cr2 = address;
+		tsk->thread.error_code = error_code;
+		tsk->thread.trap_no = 14;
+		info.si_signo = SIGSEGV;
+		info.si_errno = 0;
+		/* info.si_code has been set above */
+		info.si_addr = (void *)address;
+		force_sig_info(SIGSEGV, &info, tsk);
+		return;
+	}
+
+no_context:
+	
+	/* Are we prepared to handle this kernel fault?  */
+	if ((fixup = search_exception_table(regs->rip)) != 0) {
+		regs->rip = fixup;
+		if (0 && exception_trace) 
+		printk(KERN_ERR 
+		       "%s: fixed kernel exception at %lx address %lx err:%ld\n", 
+		       current->comm, regs->rip, address, error_code);
+		return;
+	}
+
+/*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+
+	console_verbose();
+	bust_spinlocks(1); 
+
+	if (!in_interrupt()) { 
+		if (!spin_trylock(&pcrash_lock)) { 
+			if (crashing_cpu != smp_processor_id()) 
+				spin_lock(&pcrash_lock);  		    
+		} 
+		crashing_cpu = smp_processor_id();
+	} 
+
+	if (address < PAGE_SIZE)
+		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+	else
+		printk(KERN_ALERT "Unable to handle kernel paging request");
+	printk(" at virtual address %016lx\n",address);
+	printk(" printing rip:\n");
+	printk("%016lx\n", regs->rip);
+	dump_pagetable(address);
+
+	die("Oops", regs, error_code);
+
+	if (!in_interrupt()) { 
+		crashing_cpu = -1;  /* small harmless window */ 
+		spin_unlock(&pcrash_lock);
+	}
+
+	bust_spinlocks(0); 
+	do_exit(SIGKILL);
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+out_of_memory:
+	up_read(&mm->mmap_sem);
+	if (current->pid == 1) { 
+		tsk->policy |= SCHED_YIELD;
+		schedule();
+		goto again;
+	}
+	printk("VM: killing process %s\n", tsk->comm);
+	if (error_code & 4)
+		do_exit(SIGKILL);
+	goto no_context;
+
+do_sigbus:
+	up_read(&mm->mmap_sem);
+
+	/*
+	 * Send a sigbus, regardless of whether we were in kernel
+	 * or user mode.
+	 */
+	tsk->thread.cr2 = address;
+	tsk->thread.error_code = error_code;
+	tsk->thread.trap_no = 14;
+	info.si_signo = SIGBUS;
+	info.si_errno = 0;
+	info.si_code = BUS_ADRERR;
+	info.si_addr = (void *)address;
+	force_sig_info(SIGBUS, &info, tsk);
+
+	/* Kernel mode? Handle exceptions or die */
+	if (!(error_code & 4))
+		goto no_context;
+	return;
+
+
+vmalloc_fault:
+	{
+		pgd_t *pgd;
+		pmd_t *pmd;
+		pte_t *pte; 
+
+		/* 
+		 * x86-64 has the same kernel 3rd level pages for all CPUs.
+		 * But for vmalloc/modules the TLB synchronization works lazily,
+		 * so it can happen that we get a page fault for something
+		 * that is really already in the page table. Just check if it
+		 * is really there and when yes flush the local TLB. 
+		 */
+#if 0
+		printk("vmalloc fault %lx index %lu\n",address,pml4_index(address));
+		dump_pagetable(address);
+#endif
+
+		pgd = pgd_offset_k(address);
+		if (pgd != current_pgd_offset_k(address)) 
+			goto bad_area_nosemaphore;	 
+		if (!pgd_present(*pgd))
+			goto bad_area_nosemaphore;
+		pmd = pmd_offset(pgd, address);
+		if (!pmd_present(*pmd))
+			goto bad_area_nosemaphore;
+		pte = pte_offset(pmd, address); 
+		if (!pte_present(*pte))
+			goto bad_area_nosemaphore; 
+
+		__flush_tlb_all();		
+		return;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/mm/init.c linux-2.4.20/arch/x86_64/mm/init.c
--- linux-2.4.19/arch/x86_64/mm/init.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/mm/init.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,515 @@
+/*
+ *  linux/arch/x86_64/mm/init.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Copyright (C) 2000  Pavel Machek <pavel@suse.cz>
+ *  Copyright (C) 2002  Andi Kleen <ak@suse.de>
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/pagemap.h>
+#include <linux/bootmem.h>
+
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/dma.h>
+#include <asm/fixmap.h>
+#include <asm/e820.h>
+#include <asm/apic.h>
+#include <asm/tlb.h>
+#include <asm/pda.h>
+#include <asm/mmu_context.h>
+#include <asm/proto.h>
+
+mmu_gather_t mmu_gathers[NR_CPUS];
+
+static unsigned long totalram_pages;
+
+int do_check_pgt_cache(int low, int high)
+{
+	int freed = 0;
+	if(read_pda(pgtable_cache_sz) > high) {
+		do {
+			if (read_pda(pgd_quick)) {
+				pgd_free_slow(pgd_alloc_one_fast());
+				freed++;
+			}
+			if (read_pda(pmd_quick)) {
+				pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
+				freed++;
+			}
+			if (read_pda(pte_quick)) {
+				pte_free_slow(pte_alloc_one_fast(NULL, 0));
+				freed++;
+			}
+		} while(read_pda(pgtable_cache_sz) > low);
+	}
+	return freed;
+}
+
+#ifndef CONFIG_DISCONTIGMEM
+/*
+ * NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the
+ * physical space so we can cache the place of the first one and move
+ * around without checking the pgd every time.
+ */
+
+void show_mem(void)
+{
+	int i, total = 0, reserved = 0;
+	int shared = 0, cached = 0;
+
+	printk("Mem-info:\n");
+	show_free_areas();
+	printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+	i = max_mapnr;
+	while (i-- > 0) {
+		total++;
+		if (PageReserved(mem_map+i))
+			reserved++;
+		else if (PageSwapCache(mem_map+i))
+			cached++;
+		else if (page_count(mem_map+i))
+			shared += page_count(mem_map+i) - 1;
+	}
+	printk("%d pages of RAM\n", total);
+	printk("%d reserved pages\n",reserved);
+	printk("%d pages shared\n",shared);
+	printk("%d pages swap cached\n",cached);
+	printk("%ld pages in page table cache\n",read_pda(pgtable_cache_sz));
+	show_buffers();
+}
+#endif
+
+/* References to section boundaries */
+
+extern char _text, _etext, _edata, __bss_start, _end;
+extern char __init_begin, __init_end;
+
+int after_bootmem;
+
+static void *spp_getpage(void)
+{ 
+	void *ptr;
+	if (after_bootmem)
+		ptr = (void *) get_free_page(GFP_ATOMIC); 
+	else
+		ptr = alloc_bootmem_low_pages(PAGE_SIZE); 
+	if (!ptr)
+		panic("set_pte_phys: cannot allocate page data %s\n", after_bootmem?"after bootmem":"");
+	return ptr;
+} 
+
+static void set_pte_phys(unsigned long vaddr,
+			 unsigned long phys, pgprot_t prot)
+{
+	pml4_t *level4;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	level4 = pml4_offset_k(vaddr);
+	if (pml4_none(*level4)) {
+		printk("PML4 FIXMAP MISSING, it should be setup in head.S!\n");
+		return;
+	}
+	pgd = level3_offset_k(level4, vaddr);
+	if (pgd_none(*pgd)) {
+		pmd = (pmd_t *) spp_getpage(); 
+		set_pgd(pgd, __pgd(__pa(pmd) | _KERNPG_TABLE | _PAGE_USER));
+		if (pmd != pmd_offset(pgd, 0)) {
+			printk("PAGETABLE BUG #01!\n");
+			return;
+		}
+	}
+	pmd = pmd_offset(pgd, vaddr);
+	if (pmd_none(*pmd)) {
+		pte = (pte_t *) spp_getpage();
+		set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE | _PAGE_USER));
+		if (pte != pte_offset(pmd, 0)) {
+			printk("PAGETABLE BUG #02!\n");
+			return;
+		}
+	}
+	pte = pte_offset(pmd, vaddr);
+	set_pte(pte, mk_pte_phys(phys, prot));
+
+	/*
+	 * It's enough to flush this one mapping.
+	 * (PGE mappings get flushed as well)
+	 */
+	__flush_tlb_one(vaddr);
+}
+
+void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
+{
+	unsigned long address = __fix_to_virt(idx);
+
+	if (idx >= __end_of_fixed_addresses) {
+		printk("Invalid __set_fixmap\n");
+		return;
+	}
+	set_pte_phys(address, phys, prot);
+}
+
+extern pmd_t temp_boot_pmds[]; 
+
+unsigned long __initdata table_start, table_end; 
+
+static  struct temp_map { 
+	pmd_t *pmd; 
+	void  *address; 
+	int    allocated; 
+} temp_mappings[] __initdata = { 
+	{ &temp_boot_pmds[0], (void *)(40UL * 1024 * 1024) },
+	{ &temp_boot_pmds[1], (void *)(42UL * 1024 * 1024) }, 
+	{}
+}; 
+
+static __init void *alloc_low_page(int *index, unsigned long *phys) 
+{ 
+	struct temp_map *ti;
+	int i; 
+	unsigned long pfn = table_end++, paddr; 
+	void *adr;
+
+	if (table_end >= end_pfn) 
+		panic("alloc_low_page: ran out of page mappings"); 
+	for (i = 0; temp_mappings[i].allocated; i++) {
+		if (!temp_mappings[i].pmd) 
+			panic("alloc_low_page: ran out of temp mappings"); 
+	} 
+	ti = &temp_mappings[i];
+	paddr = (pfn << PAGE_SHIFT) & PMD_MASK; 
+	set_pmd(ti->pmd, __pmd(paddr | _KERNPG_TABLE | _PAGE_PSE)); 
+	ti->allocated = 1; 
+	__flush_tlb(); 	       
+	adr = ti->address + ((pfn << PAGE_SHIFT) & ~PMD_MASK); 
+	*index = i; 
+	*phys  = pfn * PAGE_SIZE;  
+	return adr; 
+} 
+
+static __init void unmap_low_page(int i)
+{ 
+	struct temp_map *ti = &temp_mappings[i];
+	set_pmd(ti->pmd, __pmd(0));
+	ti->allocated = 0; 
+} 
+
+static void __init phys_pgd_init(pgd_t *pgd, unsigned long address, unsigned long end)
+{ 
+	long i, j; 
+
+	i = pgd_index(address);
+	pgd = pgd + i;
+	for (; i < PTRS_PER_PGD; pgd++, i++) {
+		int map; 
+		unsigned long paddr, pmd_phys;
+		pmd_t *pmd;
+
+		paddr = (address & PML4_MASK) + i*PGDIR_SIZE; 
+		if (paddr >= end) { 
+			for (; i < PTRS_PER_PGD; i++, pgd++) 
+				set_pgd(pgd, __pgd(0)); 
+			break;
+		} 
+
+		if (!e820_mapped(paddr, paddr+PGDIR_SIZE, 0)) { 
+			set_pgd(pgd, __pgd(0)); 
+			continue;
+		} 
+
+		pmd = alloc_low_page(&map, &pmd_phys);
+		set_pgd(pgd, __pgd(pmd_phys | _KERNPG_TABLE));
+		for (j = 0; j < PTRS_PER_PMD; pmd++, j++ , paddr += PMD_SIZE) {
+			unsigned long pe;
+
+			if (paddr >= end) { 
+				for (; j < PTRS_PER_PMD; j++, pmd++)
+					set_pmd(pmd,  __pmd(0)); 
+				break;
+			}
+			pe = _PAGE_PSE | _KERNPG_TABLE | _PAGE_GLOBAL | paddr;
+			set_pmd(pmd, __pmd(pe));
+		}
+		unmap_low_page(map);
+	}
+	__flush_tlb();
+} 
+
+/* Setup the direct mapping of the physical memory at PAGE_OFFSET.
+   This runs before bootmem is initialized and gets pages directly from the 
+   physical memory. To access them they are temporarily mapped. */
+void __init init_memory_mapping(void) 
+{ 
+	unsigned long adr;	       
+	unsigned long end;
+	unsigned long next; 
+	unsigned long pgds, pmds, tables; 
+
+	end = end_pfn << PAGE_SHIFT; 
+
+	/* 
+	 * Find space for the kernel direct mapping tables.
+	 * Later we should allocate these tables in the local node of the memory
+	 * mapped.  Unfortunately this is done currently before the nodes are 
+	 * discovered.
+	 */
+
+	pgds = (end + PGDIR_SIZE - 1) >> PGDIR_SHIFT;
+	pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; 
+	tables = round_up(pgds*8, PAGE_SIZE) + round_up(pmds * 8, PAGE_SIZE); 
+
+	/* Direct mapping must currently fit below the kernel in the first MB.
+	   This is because we have no way to tell the later passes to not reuse
+	   the memory, until bootmem is initialised */
+	/* Should limit MAXMEM for this */
+	table_start = find_e820_area(/*0*/ 0x8000, __pa_symbol(&_text), tables); 
+	if (table_start == -1UL) 
+		panic("Cannot find space for the kernel page tables"); 
+
+	table_start >>= PAGE_SHIFT; 
+	table_end = table_start;
+       
+	end += __PAGE_OFFSET; /* turn virtual */  
+
+	for (adr = PAGE_OFFSET; adr < end; adr = next) { 
+		int map;
+		unsigned long pgd_phys; 
+		pgd_t *pgd = alloc_low_page(&map, &pgd_phys);
+		next = adr + PML4_SIZE;
+		if (next > end) 
+			next = end; 
+
+		phys_pgd_init(pgd, adr-PAGE_OFFSET, next-PAGE_OFFSET); 
+		set_pml4(init_level4_pgt + pml4_index(adr), 
+			 mk_kernel_pml4(pgd_phys, KERNPG_TABLE));
+		unmap_low_page(map);   
+	} 
+	asm volatile("movq %%cr4,%0" : "=r" (mmu_cr4_features));
+	__flush_tlb_all();
+	printk("kernel direct mapping tables upto %lx @ %lx-%lx\n", end, 
+	       table_start<<PAGE_SHIFT, 
+	       table_end<<PAGE_SHIFT);
+} 
+
+void __init zap_low_mappings (void)
+{
+	int i;
+	for (i = 0; i < NR_CPUS; i++) {
+		if (cpu_pda[i].level4_pgt) 
+			cpu_pda[i].level4_pgt[0] = 0; 
+	}
+
+	flush_tlb_all();
+}
+
+#ifndef CONFIG_DISCONTIGMEM
+void __init paging_init(void)
+{
+	unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
+	unsigned int max_dma;
+	
+	max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+	if (end_pfn < max_dma)
+		zones_size[ZONE_DMA] = end_pfn;
+	else {
+		zones_size[ZONE_DMA] = max_dma;
+		zones_size[ZONE_NORMAL] = end_pfn - max_dma;
+	}
+	free_area_init(zones_size);
+}
+
+static inline int page_is_ram (unsigned long pagenr)
+{
+	int i;
+
+	for (i = 0; i < e820.nr_map; i++) {
+		unsigned long addr, end;
+
+		if (e820.map[i].type != E820_RAM)	/* not usable memory */
+			continue;
+		/*
+		 *	!!!FIXME!!! Some BIOSen report areas as RAM that
+		 *	are not. Notably the 640->1Mb area. We need a sanity
+		 *	check here.
+		 */
+		addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT;
+		end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT;
+		if  ((pagenr >= addr) && (pagenr < end))
+			return 1;
+	}
+	return 0;
+}
+#endif
+
+void __init mem_init(void)
+{
+	unsigned long codesize, reservedpages, datasize, initsize;
+	unsigned long tmp;
+
+	max_mapnr = end_pfn; 
+	num_physpages = end_pfn; /* XXX not true because of holes */
+	high_memory = (void *) __va(end_pfn << PAGE_SHIFT);
+
+	/* clear the zero-page */
+	memset(empty_zero_page, 0, PAGE_SIZE);
+
+	reservedpages = 0;
+
+	/* this will put all low memory onto the freelists */
+#ifdef CONFIG_DISCONTIGMEM
+	totalram_pages += numa_free_all_bootmem();
+	tmp = 0;
+	/* should count reserved pages here for all nodes */ 
+#else
+	if (!mem_map) BUG();
+
+	totalram_pages += free_all_bootmem();
+
+	for (tmp = 0; tmp < end_pfn; tmp++)
+		/*
+		 * Only count reserved RAM pages
+		 */
+		if (page_is_ram(tmp) && PageReserved(mem_map+tmp))
+			reservedpages++;
+#endif
+
+	after_bootmem = 1;
+
+	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
+	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
+	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
+
+	printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, %ldk data, %ldk init)\n",
+		(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
+		max_mapnr << (PAGE_SHIFT-10),
+		codesize >> 10,
+		reservedpages << (PAGE_SHIFT-10),
+		datasize >> 10,
+		initsize >> 10);
+
+	/*
+	 * Subtle. SMP is doing its boot stuff late (because it has to
+	 * fork idle threads) - but it also needs low mappings for the
+	 * protected-mode entry to work. We zap these entries only after
+	 * the WP-bit has been tested.
+	 */
+#ifndef CONFIG_SMP
+	zap_low_mappings();
+#endif
+}
+
+void __init __map_kernel_range(void *address, int len, pgprot_t prot) 
+{ 
+	int i;
+	void *end = address + len;
+	BUG_ON((pgprot_val(prot) & _PAGE_PSE) == 0);
+	address = (void *)((unsigned long)address & LARGE_PAGE_MASK); 
+	for (; address < end; address += LARGE_PAGE_SIZE) { 
+		pml4_t *pml4;
+		pgd_t *pgd;
+		pmd_t *pmd;
+
+		pml4 = pml4_offset_k((unsigned long) address); 
+		if (pml4_none(*pml4)) { 
+			void *p = (void *)get_zeroed_page(GFP_KERNEL); 
+			if (!p) panic("Cannot map kernel range"); 
+			for (i = 0; i < smp_num_cpus; i++) {
+				set_pml4((pml4_t *)(cpu_pda[i].level4_pgt) + 
+					 pml4_index((unsigned long)address),
+					 mk_kernel_pml4(virt_to_phys(p),KERNPG_TABLE));
+			}
+		} 
+		pgd = pgd_offset_k((unsigned long)address); 
+		if (pgd_none(*pgd)) { 
+			void *p = (void *)get_zeroed_page(GFP_KERNEL); 
+			if (!p) panic("Cannot map kernel range"); 
+			set_pgd(pgd, __mk_pgd(virt_to_phys(p), KERNPG_TABLE));
+		} 
+		pmd = pmd_offset(pgd, (unsigned long) address); 
+		set_pmd(pmd, __mk_pmd(virt_to_phys(address), prot));
+	} 
+	__flush_tlb_all(); 
+} 
+
+void free_initmem(void)
+{
+	void *addr;
+
+	addr = (&__init_begin);
+	for (; addr < (void *)(&__init_end); addr += PAGE_SIZE) {
+		ClearPageReserved(virt_to_page(addr));
+		set_page_count(virt_to_page(addr), 1);
+#ifdef CONFIG_INIT_DEBUG
+		memset((unsigned long)addr & ~(PAGE_SIZE-1), 0xcc, PAGE_SIZE); 
+#endif
+		free_page((unsigned long)addr);
+		totalram_pages++;
+	}
+	printk ("Freeing unused kernel memory: %luk freed\n", (&__init_end - &__init_begin) >> 10);
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+	if (start < (unsigned long)&_end)
+		return;
+	printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+	for (; start < end; start += PAGE_SIZE) {
+		ClearPageReserved(virt_to_page(start));
+		set_page_count(virt_to_page(start), 1);
+		free_page(start);
+		totalram_pages++;
+	}
+}
+#endif
+
+void si_meminfo(struct sysinfo *val)
+{
+	val->totalram = totalram_pages;
+	val->sharedram = 0;
+	val->freeram = nr_free_pages();
+	val->bufferram = atomic_read(&buffermem_pages);
+	val->totalhigh = 0;
+	val->freehigh = nr_free_highpages();
+	val->mem_unit = PAGE_SIZE;
+	return;
+}
+
+void reserve_bootmem_generic(unsigned long phys, unsigned len) 
+{ 
+	/* Should check here against the e820 map to avoid double free */ 
+#ifdef CONFIG_DISCONTIGMEM
+	reserve_bootmem_node(NODE_DATA(phys_to_nid(phys)), phys, len);
+#else       		
+	reserve_bootmem(phys, len);    
+#endif
+}
+
+
+void free_bootmem_generic(unsigned long phys, unsigned len) 
+{ 
+#ifdef CONFIG_DISCONTIGMEM
+	free_bootmem_node(NODE_DATA(phys_to_nid(phys)), phys, len);
+#else       		
+	free_bootmem(phys, len);    
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/mm/ioremap.c linux-2.4.20/arch/x86_64/mm/ioremap.c
--- linux-2.4.19/arch/x86_64/mm/ioremap.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/mm/ioremap.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,165 @@
+/*
+ * arch/x86_64/mm/ioremap.c
+ *
+ * Re-map IO memory to kernel address space so that we can access it.
+ * This is needed for high PCI addresses that aren't mapped in the
+ * 640k-1MB IO memory area on PC's
+ *
+ * (C) Copyright 1995 1996 Linus Torvalds
+ */
+
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+
+static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+	unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	if (address >= end)
+		BUG();
+	do {
+		if (!pte_none(*pte)) {
+			printk("remap_area_pte: page already exists\n");
+			BUG();
+		}
+		set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | _PAGE_RW |
+					_PAGE_GLOBAL | _PAGE_DIRTY | _PAGE_ACCESSED | flags)));
+		address += PAGE_SIZE;
+		phys_addr += PAGE_SIZE;
+		pte++;
+	} while (address && (address < end));
+}
+
+static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+	unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	phys_addr -= address;
+	if (address >= end)
+		BUG();
+	do {
+		pte_t * pte = pte_alloc(&init_mm, pmd, address);
+		if (!pte)
+			return -ENOMEM;
+		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address && (address < end));
+	return 0;
+}
+
+static int remap_area_pages(unsigned long address, unsigned long phys_addr,
+				 unsigned long size, unsigned long flags)
+{
+	int error;
+	pgd_t * dir;
+	unsigned long end = address + size;
+
+	phys_addr -= address;
+	dir = pgd_offset_k(address);
+	flush_cache_all();
+	if (address >= end)
+		BUG();
+	spin_lock(&init_mm.page_table_lock);
+	do {
+		pmd_t *pmd;
+		pmd = pmd_alloc(&init_mm, dir, address);
+		error = -ENOMEM;
+		if (!pmd)
+			break;
+		if (remap_area_pmd(pmd, address, end - address,
+					 phys_addr + address, flags))
+			break;
+		error = 0;
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	} while (address && (address < end));
+	spin_unlock(&init_mm.page_table_lock);
+	flush_tlb_all();
+	return error;
+}
+
+/*
+ * Generic mapping function (not visible outside):
+ */
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ *
+ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
+ * have to convert them into an offset in a page-aligned mapping, but the
+ * caller shouldn't need to know that small detail.
+ */
+void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
+{
+	void * addr;
+	struct vm_struct * area;
+	unsigned long offset, last_addr;
+
+	/* Don't allow wraparound or zero size */
+	last_addr = phys_addr + size - 1;
+	if (!size || last_addr < phys_addr)
+		return NULL;
+
+	/*
+	 * Don't remap the low PCI/ISA area, it's always mapped..
+	 */
+	if (phys_addr >= 0xA0000 && last_addr < 0x100000)
+		return phys_to_virt(phys_addr);
+
+	/*
+	 * Don't allow anybody to remap normal RAM that we're using..
+	 */
+	if (phys_addr < virt_to_phys(high_memory)) {
+		char *t_addr, *t_end;
+		struct page *page;
+
+		t_addr = __va(phys_addr);
+		t_end = t_addr + (size - 1);
+	   
+#ifndef CONFIG_DISCONTIGMEM
+		for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++)
+			if(!PageReserved(page))
+				return NULL;
+#endif
+	}
+
+	/*
+	 * Mappings have to be page-aligned
+	 */
+	offset = phys_addr & ~PAGE_MASK;
+	phys_addr &= PAGE_MASK;
+	size = PAGE_ALIGN(last_addr) - phys_addr;
+
+	/*
+	 * Ok, go for it..
+	 */
+	area = get_vm_area(size, VM_IOREMAP);
+	if (!area)
+		return NULL;
+	addr = area->addr;
+	if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
+		vfree(addr);
+		return NULL;
+	}
+	return (void *) (offset + (char *)addr);
+}
+
+void iounmap(void *addr)
+{
+	if (addr > high_memory)
+		return vfree((void *) (PAGE_MASK & (unsigned long) addr));
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/mm/k8topology.c linux-2.4.20/arch/x86_64/mm/k8topology.c
--- linux-2.4.19/arch/x86_64/mm/k8topology.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/mm/k8topology.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,185 @@
+/* 
+ * AMD K8 NUMA support.
+ * Discover the memory map and associated nodes.
+ * 
+ * Doesn't use the ACPI SRAT table because it has a questionable license.
+ * Instead the northbridge registers are read directly. 
+ * 
+ * Copyright 2002 Andi Kleen, SuSE Labs.
+ * $Id: k8topology.c,v 1.3 2002/09/12 12:51:39 ak Exp $
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <linux/pci_ids.h>
+#include <asm/types.h>
+#include <asm/mmzone.h>
+#include <asm/proto.h>
+#include <asm/e820.h>
+#include <asm/pci-direct.h>
+
+int memnode_shift;
+u8  memnodemap[NODEMAPSIZE];
+
+static int find_northbridge(void)
+{
+	int num; 
+
+	for (num = 0; num < 32; num++) { 
+		u32 header;
+		
+		header = read_pci_config(0, num, 0, 0x00);  
+		if (header != (PCI_VENDOR_ID_AMD | (0x1100<<16)))
+			continue; 	
+
+		header = read_pci_config(0, num, 1, 0x00); 
+		if (header != (PCI_VENDOR_ID_AMD | (0x1101<<16)))
+			continue;	
+		return num; 
+	} 
+
+	return -1; 	
+}
+
+#define MAXNODE 8 
+#define NODEMASK 0xff
+
+struct node { 
+	u64 start,end; 
+};
+
+#define for_all_nodes(n) \
+	for (n=0; n<MAXNODE;n++) if (nodes[n].start!=nodes[n].end)
+
+static int compute_hash_shift(struct node *nodes, int numnodes, u64 maxmem)
+{
+	int i; 
+	int shift = 24;
+	u64 addr;
+	
+	/* When in doubt use brute force. */
+	while (shift < 48) { 
+		memset(memnodemap,0xff,sizeof(*memnodemap) * NODEMAPSIZE); 
+		for_all_nodes (i) { 
+			for (addr = nodes[i].start; 
+			     addr < nodes[i].end; 
+			     addr += (1UL << shift)) {
+				if (memnodemap[addr >> shift] != 0xff) { 
+					printk("node %d shift %d addr %Lx conflict %d\n", 
+					       i, shift, addr, memnodemap[addr>>shift]);
+					goto next; 
+				} 
+				memnodemap[addr >> shift] = i; 
+			} 
+		} 
+		return shift; 
+	next:
+		shift++; 
+	} 
+	memset(memnodemap,0,sizeof(*memnodemap) * NODEMAPSIZE); 
+	return -1; 
+}
+
+extern unsigned long nodes_present;
+extern unsigned long end_pfn;
+
+int __init k8_scan_nodes(unsigned long start, unsigned long end)
+{ 
+	unsigned long prevbase;
+	struct node nodes[MAXNODE];
+	int nodeid, numnodes, maxnode, i, nb; 
+
+	nb = find_northbridge(); 
+	if (nb < 0) 
+		return nb;
+
+	printk(KERN_INFO "Scanning NUMA topology in Northbridge %d\n", nb); 
+
+	numnodes = (read_pci_config(0, nb, 0, 0x60 ) >> 4) & 3; 
+
+	memset(&nodes,0,sizeof(nodes)); 
+	prevbase = 0;
+	maxnode = -1; 
+	for (i = 0; i < MAXNODE; i++) { 
+		unsigned long base,limit; 
+
+		base = read_pci_config(0, nb, 1, 0x40 + i*8);
+		limit = read_pci_config(0, nb, 1, 0x44 + i*8);
+
+		nodeid = limit & 3; 
+		if (!limit) { 
+			printk(KERN_INFO "Skipping node entry %d (base %lx)\n", i,			       base);
+			continue;
+		}
+		if ((base >> 8) & 3 || (limit >> 8) & 3) {
+			printk(KERN_ERR "Node %d using interleaving mode %lx/%lx\n", 
+			       nodeid, (base>>8)&3, (limit>>8) & 3); 
+			return -1; 
+		}	
+		if (nodeid > maxnode) 
+			maxnode = nodeid; 
+		if ((1UL << nodeid) & nodes_present) { 
+			printk("Node %d already present. Skipping\n", nodeid);
+			continue;
+		}
+
+		limit >>= 16; 
+		limit <<= 24; 
+
+		if (limit > end_pfn << PAGE_SHIFT) 
+			limit = end_pfn << PAGE_SHIFT; 
+		if (limit <= base) { 
+			printk(KERN_INFO "Node %d beyond memory map\n", nodeid);
+			continue; 
+		} 
+			
+		base >>= 16;
+		base <<= 24; 
+
+		if (base < start) 
+			base = start; 
+		if (limit > end) 
+			limit = end; 
+		if (limit == base) 
+			continue; 
+		if (limit < base) { 
+			printk(KERN_INFO"Node %d bogus settings %lx-%lx. Ignored.\n",
+			       nodeid, base, limit); 			       
+			continue; 
+		} 
+		
+		/* Could sort here, but pun for now. Should not happen anyroads. */
+		if (prevbase > base) { 
+			printk(KERN_INFO "Node map not sorted %lx,%lx\n",
+			       prevbase,base);
+			return -1;
+		}
+			
+		printk(KERN_INFO "Node %d MemBase %016lx Limit %016lx\n", 
+		       nodeid, base, limit); 
+		
+		nodes[nodeid].start = base; 
+		nodes[nodeid].end = limit;
+
+		prevbase = base;
+	} 
+
+	if (maxnode <= 0)
+		return -1; 
+
+	memnode_shift = compute_hash_shift(nodes,maxnode,end);
+	if (memnode_shift < 0) { 
+		printk(KERN_ERR "No NUMA node hash function found. Contact maintainer\n"); 
+		return -1; 
+	} 
+	printk(KERN_INFO "Using node hash shift of %d\n", memnode_shift); 
+
+	for_all_nodes(i) { 
+		setup_node_bootmem(i, nodes[i].start, nodes[i].end); 
+	} 
+
+	return 0;
+} 
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/mm/modutil.c linux-2.4.20/arch/x86_64/mm/modutil.c
--- linux-2.4.19/arch/x86_64/mm/modutil.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/mm/modutil.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,68 @@
+/*  arch/x86_64/mm/modutil.c
+ *
+ *  Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *  Based upon code written by Linus Torvalds and others.
+ * 
+ *  Blatantly copied from sparc64 for x86-64 by Andi Kleen. 
+ *  Should use direct mapping with 2MB pages. This would need extension
+ *  of the kernel mapping.
+ */
+ 
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+static struct vm_struct * modvmlist = NULL;
+
+void module_unmap (void * addr)
+{
+	struct vm_struct **p, *tmp;
+
+	if (!addr)
+		return;
+	if ((PAGE_SIZE-1) & (unsigned long) addr) {
+		printk("Trying to unmap module with bad address (%p)\n", addr);
+		return;
+	}
+	for (p = &modvmlist ; (tmp = *p) ; p = &tmp->next) {
+		if (tmp->addr == addr) {
+			*p = tmp->next;
+			vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size);
+			kfree(tmp);
+			return;
+		}
+	}
+	printk("Trying to unmap nonexistent module vm area (%p)\n", addr);
+}
+
+void * module_map (unsigned long size)
+{
+	void * addr;
+	struct vm_struct **p, *tmp, *area;
+
+	size = PAGE_ALIGN(size);
+	if (!size || size > MODULES_LEN) return NULL;
+		
+	addr = (void *) MODULES_VADDR;
+	for (p = &modvmlist; (tmp = *p) ; p = &tmp->next) {
+		if (size + (unsigned long) addr < (unsigned long) tmp->addr)
+			break;
+		addr = (void *) (tmp->size + (unsigned long) tmp->addr);
+	}
+	if ((unsigned long) addr + size >= MODULES_END) return NULL;
+	
+	area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
+	if (!area) return NULL;
+	area->size = size + PAGE_SIZE;
+	area->addr = addr;
+	area->next = *p;
+	*p = area;
+
+	if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL)) {
+		module_unmap(addr);
+		return NULL;
+	}
+	return addr;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/mm/numa.c linux-2.4.20/arch/x86_64/mm/numa.c
--- linux-2.4.19/arch/x86_64/mm/numa.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/mm/numa.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,194 @@
+/* 
+ * Generic VM initialization for x86-64 NUMA setups.
+ * Copyright 2002 Andi Kleen, SuSE Labs.
+ * $Id: numa.c,v 1.4 2002/09/05 15:28:12 ak Exp $
+ */ 
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/mmzone.h>
+#include <linux/blk.h>
+#include <asm/e820.h>
+#include <asm/proto.h>
+#include <asm/dma.h>
+
+#undef Dprintk
+#define Dprintk(...) 
+
+plat_pg_data_t *plat_node_data[MAXNODE];
+bootmem_data_t plat_node_bdata[MAX_NUMNODES];
+
+#define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT))
+
+static int numa_off __initdata; 
+
+unsigned long nodes_present; 
+int maxnode;
+
+/* Initialize bootmem allocator for a node */
+void __init setup_node_bootmem(int nodeid, unsigned long start, unsigned long end)
+{ 
+	unsigned long start_pfn, end_pfn, bootmap_pages, bootmap_size, bootmap_start; 
+	unsigned long nodedata_phys;
+	const int pgdat_size = round_up(sizeof(plat_pg_data_t), PAGE_SIZE);
+
+	start = round_up(start, ZONE_ALIGN); 
+
+	printk("Bootmem setup node %d %016lx-%016lx\n", nodeid, start, end);
+
+	start_pfn = start >> PAGE_SHIFT;
+	end_pfn = end >> PAGE_SHIFT;
+
+	nodedata_phys = find_e820_area(start, end, pgdat_size); 
+	if (nodedata_phys == -1L) 
+		panic("Cannot find memory pgdat in node %d\n", nodeid);
+
+	Dprintk("nodedata_phys %lx\n", nodedata_phys); 
+
+	PLAT_NODE_DATA(nodeid) = phys_to_virt(nodedata_phys);
+	memset(PLAT_NODE_DATA(nodeid), 0, sizeof(plat_pg_data_t));
+	NODE_DATA(nodeid)->bdata = &plat_node_bdata[nodeid];
+
+	/* Find a place for the bootmem map */
+	bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn); 
+	bootmap_start = round_up(nodedata_phys + pgdat_size, PAGE_SIZE);
+	bootmap_start = find_e820_area(bootmap_start, end, bootmap_pages<<PAGE_SHIFT);
+	if (bootmap_start == -1L) 
+		panic("Not enough continuous space for bootmap on node %d", nodeid); 
+	Dprintk("bootmap start %lu pages %lu\n", bootmap_start, bootmap_pages); 
+	
+	bootmap_size = init_bootmem_node(NODE_DATA(nodeid),
+					 bootmap_start >> PAGE_SHIFT, 
+					 start_pfn, end_pfn); 
+
+	e820_bootmem_free(NODE_DATA(nodeid), start, end);
+
+	reserve_bootmem_node(NODE_DATA(nodeid), nodedata_phys, pgdat_size); 
+	reserve_bootmem_node(NODE_DATA(nodeid), bootmap_start, bootmap_pages<<PAGE_SHIFT);
+
+	PLAT_NODE_DATA(nodeid)->start_pfn = start_pfn;
+	PLAT_NODE_DATA(nodeid)->end_pfn = end_pfn;
+
+	if (nodeid > maxnode) 
+		maxnode = nodeid;
+	nodes_present |= (1UL << nodeid); 
+} 
+
+/* Initialize final allocator for a zone */
+void __init setup_node_zones(int nodeid)
+{ 
+	unsigned long start_pfn, end_pfn; 
+	unsigned long zones[MAX_NR_ZONES];
+	unsigned long dma_end_pfn;
+	unsigned long lmax_mapnr;
+
+	memset(zones, 0, sizeof(unsigned long) * MAX_NR_ZONES); 
+
+	start_pfn = PLAT_NODE_DATA(nodeid)->start_pfn; 
+	end_pfn = PLAT_NODE_DATA(nodeid)->end_pfn; 
+
+	printk("setting up node %d %lx-%lx\n", nodeid, start_pfn, end_pfn); 
+	
+	/* All nodes > 0 have a zero length zone DMA */ 
+	dma_end_pfn = __pa(MAX_DMA_ADDRESS) >> PAGE_SHIFT; 
+	if (start_pfn < dma_end_pfn) { 
+		zones[ZONE_DMA] = dma_end_pfn - start_pfn;
+		zones[ZONE_NORMAL] = end_pfn - dma_end_pfn; 
+	} else { 
+		zones[ZONE_NORMAL] = end_pfn - start_pfn; 
+	} 
+    
+	free_area_init_node(nodeid, NODE_DATA(nodeid), NULL, zones, 
+			    start_pfn<<PAGE_SHIFT, NULL); 
+	lmax_mapnr = PLAT_NODE_DATA_STARTNR(nodeid) + PLAT_NODE_DATA_SIZE(nodeid);
+	if (lmax_mapnr > max_mapnr)
+		max_mapnr = lmax_mapnr;
+} 
+
+int fake_node;
+
+int __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
+{ 
+#ifdef CONFIG_K8_NUMA
+	if (!numa_off && !k8_scan_nodes(start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT))
+		return 0; 
+#endif
+	printk(KERN_INFO "%s\n",
+	       numa_off ? "NUMA turned off" : "No NUMA configuration found");
+		   
+	printk(KERN_INFO "Faking a node at %016lx-%016lx\n", 
+	       start_pfn << PAGE_SHIFT,
+	       end_pfn << PAGE_SHIFT); 
+	/* setup dummy node covering all memory */ 
+	fake_node = 1; 	
+	memnode_shift = 63; 
+	memnodemap[0] = 0;
+	setup_node_bootmem(0, start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
+	return -1; 
+} 
+
+#define for_all_nodes(x) for ((x) = 0; (x) <= maxnode; (x)++) \
+				if ((1UL << (x)) & nodes_present)
+
+unsigned long __init numa_free_all_bootmem(void) 
+{ 
+	int i;
+	unsigned long pages = 0;
+	for_all_nodes(i) {
+		pages += free_all_bootmem_node(NODE_DATA(i));
+	}
+	return pages;
+} 
+
+void __init paging_init(void)
+{ 
+	int i;
+	for_all_nodes(i) { 
+		setup_node_zones(i); 
+	}
+} 
+
+void show_mem(void)
+{
+	long i,free = 0,total = 0,reserved = 0;
+	long shared = 0, cached = 0;
+	int nid;
+
+	printk("\nMem-info:\n");
+	show_free_areas();
+	printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+	for_all_nodes (nid) { 
+		mem_map_t * lmem_map = NODE_MEM_MAP(nid);
+		i = PLAT_NODE_DATA_SIZE(nid);
+		while (i-- > 0) {
+			total++;
+			if (PageReserved(lmem_map+i))
+				reserved++;
+			else if (PageSwapCache(lmem_map+i))
+				cached++;
+			else if (!page_count(lmem_map+i))
+				free++;
+			else
+				shared += atomic_read(&lmem_map[i].count) - 1;
+		}
+	}
+	printk("%ld pages of RAM\n",total);
+	printk("%ld free pages\n",free);
+	printk("%ld reserved pages\n",reserved);
+	printk("%ld pages shared\n",shared);
+	printk("%ld pages swap cached\n",cached);
+	show_buffers();
+}
+
+/* [numa=off] */
+static __init int numa_setup(char *opt) 
+{ 
+	if (!strcmp(opt,"off"))
+		numa_off = 1;
+	return 1;
+} 
+
+__setup("numa=", numa_setup); 
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/mm/pageattr.c linux-2.4.20/arch/x86_64/mm/pageattr.c
--- linux-2.4.19/arch/x86_64/mm/pageattr.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/mm/pageattr.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,172 @@
+/* 
+ * Copyright 2002 Andi Kleen, SuSE Labs. 
+ * Thanks to Ben LaHaise for precious feedback.
+ */ 
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/highmem.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+static inline pte_t *lookup_address(unsigned long address) 
+{ 
+	pgd_t *pgd = pgd_offset_k(address);
+	pmd_t *pmd;
+	
+	if (!pgd) return NULL; 
+	pmd = pmd_offset(pgd, address);
+	if (!pmd) return NULL; 
+	if ((pmd_val(*pmd) & PAGE_LARGE) == PAGE_LARGE)
+		return (pte_t *)pmd; 
+
+        return pte_offset(pmd, address);
+} 
+
+static struct page *split_large_page(unsigned long address, pgprot_t prot)
+{ 
+	int i; 
+	unsigned long addr;
+	struct page *base = alloc_pages(GFP_KERNEL, 0);
+	pte_t *pbase;
+	if (!base) 
+		return NULL;
+	address = __pa(address);
+	addr = address & LARGE_PAGE_MASK; 
+	pbase = (pte_t *)page_address(base);
+	for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) {
+		pbase[i] = mk_pte_phys(addr, 
+				      addr == address ? prot : PAGE_KERNEL);
+	}
+	return base;
+} 
+
+static void flush_kernel_map(void * address) 
+{
+	struct cpuinfo_x86 *cpu = &cpu_data[smp_processor_id()]; 
+	wmb(); 
+	/* Disabled for now because there seem to be some problems with CLFLUSH */
+	if (0 && test_bit(X86_FEATURE_CLFLSH, &cpu->x86_capability)) { 
+		/* is this worth it? */ 
+		int i;
+		for (i = 0; i < PAGE_SIZE; i += cpu->x86_clflush_size) 
+			asm volatile("clflush %0" :: "m" (__pa(address) + i)); 
+	} else
+		asm volatile("wbinvd":::"memory"); 
+	__flush_tlb_one(address);
+}
+
+/* no more special protections in this 2/4MB area - revert to a
+   large page again. */
+static inline void revert_page(struct page *kpte_page, unsigned long address)
+{
+	pgd_t *pgd;
+	pmd_t *pmd; 
+	pte_t large_pte; 
+
+	pgd = pgd_offset_k(address); 
+	if (!pgd) BUG(); 
+	pmd = pmd_offset(pgd, address);
+	if (!pmd) BUG(); 
+	if ((pmd_val(*pmd) & _PAGE_GLOBAL) == 0) BUG(); 
+	
+	large_pte = mk_pte_phys(__pa(address) & LARGE_PAGE_MASK, PAGE_KERNEL_LARGE); 
+	set_pte((pte_t *)pmd, large_pte);
+}	
+ 
+/*
+ * Change the page attributes of an page in the linear mapping.
+ *
+ * This should be used when a page is mapped with a different caching policy
+ * than write-back somewhere - some CPUs do not like it when mappings with
+ * different caching policies exist. This changes the page attributes of the
+ * in kernel linear mapping too.
+ * 
+ * The caller needs to ensure that there are no conflicting mappings elsewhere.
+ * This function only deals with the kernel linear map.
+ * When page is in highmem it must never be kmap'ed.
+ */
+static int 
+__change_page_attr(unsigned long address, struct page *page, pgprot_t prot, 
+		   struct page **oldpage) 
+{ 
+	pte_t *kpte; 
+	struct page *kpte_page;
+
+	kpte = lookup_address(address);
+	if (!kpte) 
+		return 0; /* not mapped in kernel */
+	kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK);
+	if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) { 
+		if ((pte_val(*kpte) & _PAGE_PSE) == 0) { 
+			pte_t old = *kpte;
+			pte_t standard = mk_pte(page, PAGE_KERNEL); 
+
+			set_pte(kpte, mk_pte(page, prot)); 
+			if (pte_same(old,standard))
+				atomic_inc(&kpte_page->count);
+		} else {
+			struct page *split = split_large_page(address, prot); 
+			if (!split)
+				return -ENOMEM;
+			set_pte(kpte,mk_pte(split, PAGE_KERNEL));
+		}	
+	} else if ((pte_val(*kpte) & _PAGE_PSE) == 0) { 
+		set_pte(kpte, mk_pte(page, PAGE_KERNEL));
+		atomic_dec(&kpte_page->count); 
+	}
+
+	if (atomic_read(&kpte_page->count) == 1) { 
+		*oldpage = kpte_page;
+		revert_page(kpte_page, address);
+	} 
+	return 0;
+} 
+
+static inline void flush_and_free(void *address, struct page *fpage)
+{
+#ifdef CONFIG_SMP			
+	smp_call_function(flush_kernel_map, address, 1, 1);
+#endif				
+	flush_kernel_map(address); 
+	if (fpage)
+		__free_page(fpage); 
+}
+
+int change_page_attr(struct page *page, int numpages, pgprot_t prot)
+{
+	int err = 0; 
+	struct page *fpage, *fpage2; 
+	int i; 
+
+	down_write(&init_mm.mmap_sem);
+	for (i = 0; i < numpages; i++, page++) { 
+		fpage = fpage2 = NULL;
+		err = __change_page_attr((unsigned long)page_address(page), 
+					 page, prot, &fpage); 
+		
+		/* Handle kernel mapping too which aliases part of the lowmem */
+		if (!err && page_to_phys(page) < KERNEL_TEXT_SIZE) { 
+			err = __change_page_attr((unsigned long) __START_KERNEL_map + 
+						 page_to_phys(page),
+						 page, prot, &fpage2); 
+		} 
+
+		if (err) 
+			break; 
+		
+		if (fpage || fpage2 || i == numpages-1) { 
+			flush_and_free(page_address(page), fpage); 
+			if (unlikely(fpage2 != NULL))
+				flush_and_free((char *)__START_KERNEL_map + 
+					       page_to_phys(page), fpage2);
+		} 
+	} 	
+	up_write(&init_mm.mmap_sem); 
+	return err;
+}
+
+EXPORT_SYMBOL(change_page_attr);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/tools/Makefile linux-2.4.20/arch/x86_64/tools/Makefile
--- linux-2.4.19/arch/x86_64/tools/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/tools/Makefile	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,31 @@
+
+TARGET = $(TOPDIR)/include/asm-x86_64/offset.h
+
+all: 
+
+mrproper:
+
+fastdep: $(TARGET)
+
+.PHONY: all
+
+$(TARGET): offset.h
+	cmp -s $^ $@ || (cp $^ $(TARGET).new && mv $(TARGET).new $(TARGET))
+
+.PHONY : offset.h all modules modules_install
+
+offset.h: offset.sed offset.c FORCE_RECOMPILE
+	$(CC) $(CFLAGS) -S -o offset.tmp offset.c
+	sed -n -f offset.sed < offset.tmp > offset.h   
+
+FORCE_RECOMPILE:
+
+clean:
+	rm -f offset.[hs] $(TARGET).new offset.tmp
+
+mrproper:	
+	rm -f offset.[hs] $(TARGET)
+	rm -f $(TARGET)
+
+include $(TOPDIR)/Rules.make
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/tools/offset.c linux-2.4.20/arch/x86_64/tools/offset.c
--- linux-2.4.19/arch/x86_64/tools/offset.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/tools/offset.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,71 @@
+/* Written 2000 by Andi Kleen */
+/* This program is never executed, just its assembly is examined for offsets 
+   (this trick is needed to get cross compiling right) */  
+/* $Id: offset.c,v 1.16 2002/07/18 13:41:46 ak Exp $ */
+#define ASM_OFFSET_H 1
+#ifndef __KERNEL__
+#define __KERNEL__ 
+#endif
+#include <linux/sched.h> 
+#include <linux/stddef.h>
+#include <linux/errno.h> 
+#include <asm/pda.h>
+#include <asm/hardirq.h>
+#include <asm/processor.h>
+#include <asm/desc.h>
+
+#define output(x) asm volatile ("--- " x)
+#define outconst(x,y) asm volatile ("--- " x : : "i" (y)) 
+
+int main(void) 
+{ 
+	output("/* Auto generated by arch/../tools/offset.c at " __DATE__ ". Do not edit. */\n"); 
+	output("#ifndef ASM_OFFSET_H\n");
+	output("#define ASM_OFFSET_H 1\n"); 
+
+	// task struct entries needed by entry.S
+#define ENTRY(entry) outconst("#define tsk_" #entry " %0", offsetof(struct task_struct, entry))
+	ENTRY(state);
+	ENTRY(flags); 
+	ENTRY(sigpending); 
+	ENTRY(addr_limit); 
+	ENTRY(need_resched); 
+	ENTRY(exec_domain); 
+	ENTRY(ptrace); 
+	ENTRY(processor);
+	ENTRY(need_resched); 
+	ENTRY(thread); 
+#undef ENTRY
+#define ENTRY(entry) outconst("#define pda_" #entry " %0", offsetof(struct x8664_pda, entry))
+	ENTRY(kernelstack); 
+	ENTRY(oldrsp); 
+	ENTRY(pcurrent); 
+	ENTRY(irqrsp);
+	ENTRY(irqcount);
+	ENTRY(pgd_quick);
+	ENTRY(pmd_quick);
+	ENTRY(pte_quick);
+	ENTRY(pgtable_cache_sz);
+	ENTRY(cpunumber);
+	ENTRY(irqstackptr);
+	ENTRY(level4_pgt);
+#undef ENTRY
+	output("#ifdef __ASSEMBLY__"); 
+	outconst("#define PT_TRACESYS %0", PT_TRACESYS);
+	outconst("#define TASK_SIZE %0", TASK_SIZE); 
+	outconst("#define SIGCHLD %0", SIGCHLD);
+	outconst("#define CLONE_VFORK %0", CLONE_VFORK); 
+	outconst("#define CLONE_VM %0", CLONE_VM); 
+
+
+	outconst("#define thread_flags %0" , offsetof(struct thread_struct, flags));
+	outconst("#define ASM_THREAD_IA32 %0", THREAD_IA32);
+
+	outconst("#define PER_CPU_GDT_SIZE %0", sizeof(struct per_cpu_gdt)); 
+	output("#endif"); 
+
+	output("#endif\n"); 
+
+	return(0); 
+} 
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/tools/offset.sed linux-2.4.20/arch/x86_64/tools/offset.sed
--- linux-2.4.19/arch/x86_64/tools/offset.sed	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/tools/offset.sed	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,7 @@
+/---/ {
+	s/---//
+	s/\$//
+	s/^	//
+	s/^ //
+	p
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/arch/x86_64/vmlinux.lds linux-2.4.20/arch/x86_64/vmlinux.lds
--- linux-2.4.19/arch/x86_64/vmlinux.lds	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/x86_64/vmlinux.lds	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,119 @@
+/* ld script to make x86-64 Linux kernel
+ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
+ */
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(_start)
+SECTIONS
+{
+  . = 0xffffffff80100000;
+  _text = .;			/* Text and read-only data */
+  .text : {
+	*(.text)
+	*(.fixup)
+	*(.gnu.warning)
+	} = 0x9090
+  .text.lock : { *(.text.lock) }	/* out-of-line lock text */
+
+  _etext = .;			/* End of text section */
+
+  .rodata : { *(.rodata) *(.rodata.*) }
+  .kstrtab : { *(.kstrtab) }
+
+  . = ALIGN(16);		/* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___ksymtab = .;	/* Kernel symbol table */
+  __ksymtab : { *(__ksymtab) }
+  __stop___ksymtab = .;
+
+  __start___kallsyms = .;	/* All kernel symbols */
+  __kallsyms : { *(__kallsyms) }
+  __stop___kallsyms = .;
+
+  .data : {			/* Data */
+	*(.data)
+	CONSTRUCTORS
+	}
+
+  _edata = .;			/* End of data section */
+
+  __bss_start = .;		/* BSS */
+  .bss : {
+	*(.bss)
+	}
+  __bss_end = .;
+
+  . = ALIGN(64);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+  .vsyscall_0 -10*1024*1024: AT ((LOADADDR(.data.cacheline_aligned) + SIZEOF(.data.cacheline_aligned) + 4095) & ~(4095)) { *(.vsyscall_0) }
+  __vsyscall_0 = LOADADDR(.vsyscall_0);
+  . = ALIGN(64);
+  .vxtime_sequence : AT ((LOADADDR(.vsyscall_0) + SIZEOF(.vsyscall_0) + 63) & ~(63)) { *(.vxtime_sequence) }
+  vxtime_sequence = LOADADDR(.vxtime_sequence);
+  . = ALIGN(16);
+  .hpet : AT ((LOADADDR(.vxtime_sequence) + SIZEOF(.vxtime_sequence) + 15) & ~(15)) { *(.hpet) }
+  hpet = LOADADDR(.hpet);
+  . = ALIGN(16);
+  .wall_jiffies : AT ((LOADADDR(.hpet) + SIZEOF(.hpet) + 15) & ~(15)) { *(.wall_jiffies) }
+  wall_jiffies = LOADADDR(.wall_jiffies);
+  . = ALIGN(16);
+  .sys_tz : AT ((LOADADDR(.wall_jiffies) + SIZEOF(.wall_jiffies) + 15) & ~(15)) { *(.sys_tz) }
+  sys_tz = LOADADDR(.sys_tz);
+  . = ALIGN(16);
+  .jiffies : AT ((LOADADDR(.sys_tz) + SIZEOF(.sys_tz) + 15) & ~(15)) { *(.jiffies) }
+  jiffies = LOADADDR(.jiffies);
+  . = ALIGN(16);
+  .xtime : AT ((LOADADDR(.jiffies) + SIZEOF(.jiffies) + 15) & ~(15)) { *(.xtime) }
+  xtime = LOADADDR(.xtime);
+  .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT (LOADADDR(.vsyscall_0) + 1024) { *(.vsyscall_1) }
+  . = LOADADDR(.vsyscall_0) + 4096;
+
+  . = ALIGN(8192);		/* init_task */
+  .data.init_task : { *(.data.init_task) }
+
+  . = ALIGN(4096); 
+  .data.boot_pgt : { *(.data.boot_pgt) }
+
+  . = ALIGN(4096);		/* Init code and data */
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(16);
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
+  . = ALIGN(4096);
+  __init_end = .;
+
+  _end = . ;
+
+  /* Sections to be discarded */
+  /DISCARD/ : {
+	*(.data.exit)
+	*(.exitcall.exit)
+	}
+
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+
+
+  .comment 0 : { *(.comment) }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/Makefile linux-2.4.20/drivers/Makefile
--- linux-2.4.19/drivers/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/Makefile	2002-10-29 11:18:49.000000000 +0000
@@ -6,7 +6,7 @@
 #
 
 
-mod-subdirs :=	dio mtd sbus video macintosh usb input telephony sgi ide \
+mod-subdirs :=	dio hil mtd sbus video macintosh usb input telephony sgi ide \
 		message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
 		fc4 net/hamradio i2c acpi bluetooth
 
@@ -16,6 +16,8 @@
 
 subdir-$(CONFIG_DIO)		+= dio
 subdir-$(CONFIG_PCI)		+= pci
+subdir-$(CONFIG_GSC)		+= gsc
+subdir-$(CONFIG_HIL)		+= hil
 subdir-$(CONFIG_PCMCIA)		+= pcmcia
 subdir-$(CONFIG_MTD)		+= mtd
 subdir-$(CONFIG_SBUS)		+= sbus
@@ -24,7 +26,7 @@
 subdir-$(CONFIG_TC)		+= tc
 subdir-$(CONFIG_VT)		+= video
 subdir-$(CONFIG_MAC)		+= macintosh
-subdir-$(CONFIG_PPC)		+= macintosh
+subdir-$(CONFIG_PPC32)		+= macintosh
 subdir-$(CONFIG_USB)		+= usb
 subdir-$(CONFIG_INPUT)		+= input
 subdir-$(CONFIG_PHONE)		+= telephony
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acorn/block/fd1772.c linux-2.4.20/drivers/acorn/block/fd1772.c
--- linux-2.4.19/drivers/acorn/block/fd1772.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/acorn/block/fd1772.c	2002-10-29 11:18:36.000000000 +0000
@@ -1567,6 +1567,7 @@
 
 int fd1772_init(void)
 {
+	int err;
 	int i;
 
 	if (!machine_is_archimedes())
@@ -1584,24 +1585,28 @@
 
 	if (request_dma(FIQ_FD1772, "fd1772 end")) {
 		printk("Unable to grab DMA%d for the floppy (1772) driver\n", FIQ_FD1772);
-		free_dma(FLOPPY_DMA);
-		return 1;
+		err = 1; /* XXX */
+		goto cleanup_dma;
 	};
-	enable_dma(FIQ_FD1772);	/* This inserts a call to our command end routine */
 
 	/* initialize variables */
+	err = -ENOMEM;
 	SelectedDrive = -1;
 #ifdef TRACKBUFFER
 	BufferDrive = BufferSide = BufferTrack = -1;
 	/* Atari uses 512 - I want to eventually cope with 1K sectors */
 	DMABuffer = (char *)kmalloc((FD1772_MAX_SECTORS+1)*512,GFP_KERNEL);
+	if (DMABuffer == NULL)
+		goto cleanup_dma;
 	TrackBuffer = DMABuffer + 512;
 #else
 	/* Allocate memory for the DMAbuffer - on the Atari this takes it
 	   out of some special memory... */
 	DMABuffer = (char *) kmalloc(2048);	/* Copes with pretty large sectors */
+	if (DMABuffer == NULL)
+		goto cleanup_dma;
 #endif
-
+	enable_dma(FIQ_FD1772);	/* This inserts a call to our command end routine */
 	for (i = 0; i < FD_MAX_UNITS; i++) {
 		unit[i].track = -1;
 	}
@@ -1619,4 +1624,7 @@
 	config_types();
 
 	return 0;
+cleanup_dma:
+	free_dma(FLOPPY_DMA);
+	return err;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acorn/char/mouse_ps2.c linux-2.4.20/drivers/acorn/char/mouse_ps2.c
--- linux-2.4.19/drivers/acorn/char/mouse_ps2.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/acorn/char/mouse_ps2.c	2002-10-29 11:18:34.000000000 +0000
@@ -273,9 +273,15 @@
 	iomd_writeb(0, IOMD_MSECTL);
 	iomd_writeb(8, IOMD_MSECTL);
   
-	if (misc_register(&psaux_mouse))
-		return -ENODEV;
 	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
+	if (queue == NULL)
+		return -ENOMEM;
+
+	if (misc_register(&psaux_mouse)) {
+		kfree(queue);
+		return -ENODEV;
+	}
+
 	memset(queue, 0, sizeof(*queue));
 	queue->head = queue->tail = 0;
 	init_waitqueue_head(&queue->proc_list);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acorn/char/pcf8583.c linux-2.4.20/drivers/acorn/char/pcf8583.c
--- linux-2.4.19/drivers/acorn/char/pcf8583.c	2001-03-03 02:38:37.000000000 +0000
+++ linux-2.4.20/drivers/acorn/char/pcf8583.c	2002-10-29 11:18:50.000000000 +0000
@@ -73,6 +73,7 @@
 pcf8583_detach(struct i2c_client *client)
 {
 	i2c_detach_client(client);
+	kfree(client);
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acorn/scsi/Config.in linux-2.4.20/drivers/acorn/scsi/Config.in
--- linux-2.4.19/drivers/acorn/scsi/Config.in	2000-01-13 21:30:31.000000000 +0000
+++ linux-2.4.20/drivers/acorn/scsi/Config.in	2002-10-29 11:18:32.000000000 +0000
@@ -14,10 +14,10 @@
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    comment 'The following drivers are not fully supported'
 
-   dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI
+   dep_tristate 'CumanaSCSI I support (EXPERIMENTAL)' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI
    if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then
-      dep_tristate 'EcoScsi support' CONFIG_SCSI_ECOSCSI $CONFIG_SCSI
+      dep_tristate 'EcoScsi support (EXPERIMENTAL)' CONFIG_SCSI_ECOSCSI $CONFIG_SCSI
    fi
-   dep_tristate 'Oak SCSI support' CONFIG_SCSI_OAK1 $CONFIG_SCSI
+   dep_tristate 'Oak SCSI support (EXPERIMENTAL)' CONFIG_SCSI_OAK1 $CONFIG_SCSI
 fi
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acpi/dispatcher/dsfield.c linux-2.4.20/drivers/acpi/dispatcher/dsfield.c
--- linux-2.4.19/drivers/acpi/dispatcher/dsfield.c	2001-10-24 21:06:22.000000000 +0000
+++ linux-2.4.20/drivers/acpi/dispatcher/dsfield.c	2002-10-29 11:18:33.000000000 +0000
@@ -181,7 +181,7 @@
 	acpi_status             status;
 
 
-	FUNCTION_TRACE_U32 ("Ds_get_field_names", info);
+	PROC_NAME("acpi_ds_get_field_names"); 
 
 
 	/* First field starts at bit zero */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acpi/dispatcher/dswexec.c linux-2.4.20/drivers/acpi/dispatcher/dswexec.c
--- linux-2.4.19/drivers/acpi/dispatcher/dswexec.c	2001-10-24 21:06:22.000000000 +0000
+++ linux-2.4.20/drivers/acpi/dispatcher/dswexec.c	2002-10-29 11:18:50.000000000 +0000
@@ -577,7 +577,7 @@
 		(walk_state->control_state->common.state ==
 			CONTROL_PREDICATE_EXECUTING) &&
 		(walk_state->control_state->control.predicate_op == op)) {
-		status = acpi_ds_get_predicate_value (walk_state, (u32) walk_state->result_obj);
+		status = acpi_ds_get_predicate_value (walk_state, !! walk_state->result_obj);
 		walk_state->result_obj = NULL;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acpi/events/evevent.c linux-2.4.20/drivers/acpi/events/evevent.c
--- linux-2.4.19/drivers/acpi/events/evevent.c	2001-10-24 21:06:22.000000000 +0000
+++ linux-2.4.20/drivers/acpi/events/evevent.c	2002-10-29 11:18:35.000000000 +0000
@@ -683,7 +683,7 @@
 acpi_ev_asynch_execute_gpe_method (
 	void                    *context)
 {
-	u32                     gpe_number = (u32) context;
+	unsigned long           gpe_number = (unsigned long) context;
 	acpi_gpe_level_info     gpe_info;
 
 
@@ -800,7 +800,7 @@
 	 */
 	else if (gpe_info.method_handle) {
 		if (ACPI_FAILURE(acpi_os_queue_for_execution (OSD_PRIORITY_GPE,
-			acpi_ev_asynch_execute_gpe_method, (void*) gpe_number))) {
+			acpi_ev_asynch_execute_gpe_method, (void*) (u64)gpe_number))) {
 			/*
 			 * Shoudn't occur, but if it does report an error. Note that
 			 * the GPE will remain disabled until the ACPI Core Subsystem
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acpi/executer/exstore.c linux-2.4.20/drivers/acpi/executer/exstore.c
--- linux-2.4.19/drivers/acpi/executer/exstore.c	2001-10-24 21:06:22.000000000 +0000
+++ linux-2.4.20/drivers/acpi/executer/exstore.c	2002-10-29 11:18:39.000000000 +0000
@@ -181,8 +181,8 @@
 
 		case ACPI_TYPE_PACKAGE:
 
-			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Elements - 0x%X\n",
-				(u32) source_desc->package.elements));
+			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Elements - %p\n",
+				source_desc->package.elements));
 			break;
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acpi/include/acglobal.h linux-2.4.20/drivers/acpi/include/acglobal.h
--- linux-2.4.19/drivers/acpi/include/acglobal.h	2001-10-24 21:06:22.000000000 +0000
+++ linux-2.4.20/drivers/acpi/include/acglobal.h	2002-10-29 11:18:30.000000000 +0000
@@ -156,7 +156,7 @@
 ACPI_EXTERN u32                         acpi_gbl_current_node_count;
 ACPI_EXTERN u32                         acpi_gbl_current_node_size;
 ACPI_EXTERN u32                         acpi_gbl_max_concurrent_node_count;
-ACPI_EXTERN u32                         acpi_gbl_entry_stack_pointer;
+ACPI_EXTERN unsigned long               acpi_gbl_entry_stack_pointer;
 ACPI_EXTERN u32                         acpi_gbl_lowest_stack_pointer;
 ACPI_EXTERN u32                         acpi_gbl_deepest_nesting;
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acpi/include/actypes.h linux-2.4.20/drivers/acpi/include/actypes.h
--- linux-2.4.19/drivers/acpi/include/actypes.h	2001-10-24 21:06:22.000000000 +0000
+++ linux-2.4.20/drivers/acpi/include/actypes.h	2002-10-29 11:18:32.000000000 +0000
@@ -48,8 +48,11 @@
  * UCHAR        Character. 1 byte unsigned value.
  */
 
+#ifndef BITS_PER_LONG
+#error "define BITS_PER_LONG"
+#endif
 
-#ifdef _IA64
+#if BITS_PER_LONG == 64
 /*
  * 64-bit type definitions
  */
@@ -62,7 +65,7 @@
 typedef COMPILER_DEPENDENT_UINT64       UINT64;
 
 typedef UINT64                          NATIVE_UINT;
-typedef INT64                           NATIVE_INT;
+typedef long long                          NATIVE_INT;
 
 typedef NATIVE_UINT                     ACPI_TBLPTR;
 typedef UINT64                          ACPI_IO_ADDRESS;
@@ -72,7 +75,7 @@
 #define ACPI_USE_NATIVE_DIVIDE                          /* Native 64-bit integer support */
 
 
-#elif _IA16
+#elif BITS_PER_LONG == 16
 /*
  * 16-bit type definitions
  */
@@ -109,7 +112,7 @@
 #define ACPI_NO_INTEGER64_SUPPORT
 
 
-#else
+#elif BITS_PER_LONG == 32
 /*
  * 32-bit type definitions (default)
  */
@@ -130,6 +133,9 @@
 
 #define ALIGNED_ADDRESS_BOUNDARY        0x00000004
 #define _HW_ALIGNMENT_SUPPORT
+
+#else
+#error "unknown BITS_PER_LONG"
 #endif
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acpi/include/platform/acgcc.h linux-2.4.20/drivers/acpi/include/platform/acgcc.h
--- linux-2.4.19/drivers/acpi/include/platform/acgcc.h	2001-10-24 21:06:22.000000000 +0000
+++ linux-2.4.20/drivers/acpi/include/platform/acgcc.h	2002-10-29 11:18:50.000000000 +0000
@@ -92,8 +92,7 @@
 /*! [End] no source code translation !*/
 
 
-#else /* DO IA32 */
-
+#elif __i386__ /* DO IA32 */
 #define COMPILER_DEPENDENT_UINT64   unsigned long long
 #define ACPI_ASM_MACROS
 #define causeinterrupt(level)
@@ -138,31 +137,60 @@
 			"andl   $0x1,%%eax" \
 			:"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~3L):"dx"); \
 	} while(0)
+#elif __x86_64__ 
+#define COMPILER_DEPENDENT_UINT64   unsigned long long
+#define ACPI_ASM_MACROS
+#define causeinterrupt(level)
+#define BREAKPOINT3
+#define disable() __cli()
+#define enable()  __sti()
+#define halt()    __asm__ __volatile__ ("sti; hlt":::"memory")
 
-
-/*
- * Math helper asm macros
+/*! [Begin] no source code translation
+ *
+ * A brief explanation as GNU inline assembly is a bit hairy
+ *  %0 is the output parameter in RAX ("=a")
+ *  %1 and %2 are the input parameters in RCX ("c")
+ *  and an immediate value ("i") respectively
+ *  All actual register references are preceded with "%%" as in "%%edx"
+ *  Immediate values in the assembly are preceded by "$" as in "$0x1"
+ *  The final asm parameter are the operation altered non-output registers.
  */
-#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) \
-		asm("divl %2;"        \
-		:"=a"(q32), "=d"(r32) \
-		:"r"(d32),            \
-		"0"(n_lo), "1"(n_hi))
-
+#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
+	do { \
+		unsigned long dummy; \
+		asm("1:     movl (%2),%%eax;" \
+			"movl   %%eax,%%edx;" \
+			"andq   %2,%%rdx;" \
+			"btsl   $0x1,%%edx;" \
+			"adcl   $0x0,%%edx;" \
+			"lock;  cmpxchgl %%edx,(%1);" \
+			"jnz    1b;" \
+			"cmpb   $0x3,%%dl;" \
+			"sbbl   %%eax,%%eax" \
+			:"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~1L):"dx"); \
+	} while(0)
 
-#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \
-	asm("shrl   $1,%2;"             \
-	    "rcrl   $1,%3;"             \
-	    :"=r"(n_hi), "=r"(n_lo)     \
-	    :"0"(n_hi), "1"(n_lo))
+#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
+	do { \
+		unsigned long dummy; \
+		asm("1:     movl (%2),%%eax;" \
+			"movl   %%eax,%%edx;" \
+			"andq   %2,%%rdx;" \
+			"lock;  cmpxchgl %%edx,(%1);" \
+			"jnz    1b;" \
+			"andl   $0x1,%%eax" \
+			:"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~3L):"dx"); \
+	} while(0)
 
 /*! [End] no source code translation !*/
 
-#endif /* IA 32 */
+#endif
 
 /* This macro is used to tag functions as "printf-like" because
  * some compilers (like GCC) can catch printf format string problems.
  */
 #define ACPI_PRINTF_LIKE_FUNC __attribute__ ((__format__ (__printf__, 4, 5)))
 
+
 #endif /* __ACGCC_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acpi/include/platform/aclinux.h linux-2.4.20/drivers/acpi/include/platform/aclinux.h
--- linux-2.4.19/drivers/acpi/include/platform/aclinux.h	2001-10-24 21:06:22.000000000 +0000
+++ linux-2.4.20/drivers/acpi/include/platform/aclinux.h	2002-10-29 11:18:34.000000000 +0000
@@ -58,5 +58,14 @@
 #undef DEBUGGER_THREADING
 #define DEBUGGER_THREADING          DEBUGGER_SINGLE_THREADED
 
+#if BITS_PER_LONG < 64
+/* Linux ia32 can't do int64 well */
+#define ACPI_NO_INTEGER64_SUPPORT
+/* And the ia32 kernel doesn't include 64-bit divide support */
+#define ACPI_DIV64(dividend, divisor) do_div(dividend, divisor)
+#else
+#define ACPI_DIV64(dividend, divisor) ACPI_DIVIDE(dividend, divisor)
+#endif
+
 
 #endif /* __ACLINUX_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acpi/namespace/nsdump.c linux-2.4.20/drivers/acpi/namespace/nsdump.c
--- linux-2.4.19/drivers/acpi/namespace/nsdump.c	2001-10-24 21:06:22.000000000 +0000
+++ linux-2.4.20/drivers/acpi/namespace/nsdump.c	2002-10-29 11:18:50.000000000 +0000
@@ -226,7 +226,7 @@
 			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " ID %d Addr %.4X Len %.4X\n",
 					 obj_desc->processor.proc_id,
 					 obj_desc->processor.address,
-					 obj_desc->processor.length));
+					 (unsigned)obj_desc->processor.length));
 			break;
 
 		case ACPI_TYPE_DEVICE:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acpi/os.c linux-2.4.20/drivers/acpi/os.c
--- linux-2.4.19/drivers/acpi/os.c	2001-11-09 21:39:25.000000000 +0000
+++ linux-2.4.20/drivers/acpi/os.c	2002-10-29 11:18:39.000000000 +0000
@@ -42,7 +42,7 @@
 #include <acpi.h>
 
 #ifdef CONFIG_ACPI_EFI
-#include <asm/efi.h>
+#include <linux/efi.h>
 #endif
 
 #ifdef _IA64
@@ -361,7 +361,7 @@
 acpi_status
 acpi_os_write_memory(
 	ACPI_PHYSICAL_ADDRESS	phys_addr,
-	u32			value,
+	NATIVE_UINT		value,
 	u32			width)
 {
 	switch (width)
@@ -421,7 +421,7 @@
 	return (result ? AE_ERROR : AE_OK);
 }
 
-acpi_status
+ACPI_STATUS
 acpi_os_write_pci_configuration (
 	acpi_pci_id             *pci_id,
 	u32                     reg,
@@ -491,7 +491,7 @@
 acpi_os_write_pci_configuration (
 	acpi_pci_id	*pci_id,
 	u32		reg,
-	u32		value,
+	NATIVE_UINT	value,
 	u32		width)
 {
 	int devfn = PCI_DEVFN(pci_id->device, pci_id->function);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acpi/ospm/busmgr/bm_osl.c linux-2.4.20/drivers/acpi/ospm/busmgr/bm_osl.c
--- linux-2.4.19/drivers/acpi/ospm/busmgr/bm_osl.c	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.20/drivers/acpi/ospm/busmgr/bm_osl.c	2002-10-29 11:18:48.000000000 +0000
@@ -108,7 +108,7 @@
 	u32			event_data)
 {
 	BM_OSL_EVENT		*event = NULL;
-	u32			flags = 0;
+	unsigned long		flags = 0;
 
 	/* drop event on the floor if no one's listening */
 	if (!event_is_open)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acpi/ospm/ec/ectransx.c linux-2.4.20/drivers/acpi/ospm/ec/ectransx.c
--- linux-2.4.19/drivers/acpi/ospm/ec/ectransx.c	2001-09-23 16:42:32.000000000 +0000
+++ linux-2.4.20/drivers/acpi/ospm/ec/ectransx.c	2002-10-29 11:18:40.000000000 +0000
@@ -104,7 +104,7 @@
 acpi_status
 ec_io_read (
 	EC_CONTEXT              *ec,
-	ACPI_IO_ADDRESS         io_port,
+	u32		        io_port,
 	u8                      *data,
 	EC_EVENT                wait_event)
 {
@@ -139,7 +139,7 @@
 acpi_status
 ec_io_write (
 	EC_CONTEXT              *ec,
-	ACPI_IO_ADDRESS         io_port,
+	u32		       io_port,
 	u8                      data,
 	EC_EVENT                wait_event)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acpi/ospm/system/sm_osl.c linux-2.4.20/drivers/acpi/ospm/system/sm_osl.c
--- linux-2.4.19/drivers/acpi/ospm/system/sm_osl.c	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.20/drivers/acpi/ospm/system/sm_osl.c	2002-10-29 11:18:36.000000000 +0000
@@ -685,6 +685,9 @@
 	 */
 	if (state == ACPI_S2 || state == ACPI_S3) {
 #ifdef DONT_USE_UNTIL_LOWLEVEL_CODE_EXISTS
+		/* That && trick is *not going to work*. Read gcc
+		   specs. That explicitely says: jumping from other
+		   function is *not allowed*. */ 
 		wakeup_address = acpi_save_state_mem((unsigned long)&&acpi_sleep_done);
 
 		if (!wakeup_address) goto acpi_sleep_done;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acpi/ospm/thermal/tzpolicy.c linux-2.4.20/drivers/acpi/ospm/thermal/tzpolicy.c
--- linux-2.4.19/drivers/acpi/ospm/thermal/tzpolicy.c	2001-10-24 21:06:22.000000000 +0000
+++ linux-2.4.20/drivers/acpi/ospm/thermal/tzpolicy.c	2002-10-29 11:18:35.000000000 +0000
@@ -413,7 +413,7 @@
 		if (timer_pending(&(policy->timer)))
 			mod_timer(&(policy->timer), (HZ*sleep_time)/1000);
 		else {
-			policy->timer.data = (u32)tz;
+			policy->timer.data = (unsigned long)tz;
 			policy->timer.function = tz_policy_run;
 			policy->timer.expires = jiffies + (HZ*sleep_time)/1000;
 			add_timer(&(policy->timer));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/acpi/utilities/utdebug.c linux-2.4.20/drivers/acpi/utilities/utdebug.c
--- linux-2.4.19/drivers/acpi/utilities/utdebug.c	2001-10-24 21:06:22.000000000 +0000
+++ linux-2.4.20/drivers/acpi/utilities/utdebug.c	2002-10-29 11:18:48.000000000 +0000
@@ -57,7 +57,7 @@
 	u32                 current_sp;
 
 
-	acpi_gbl_entry_stack_pointer = (u32) &current_sp;
+	acpi_gbl_entry_stack_pointer = (unsigned long) &current_sp;
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/atm/atmtcp.c linux-2.4.20/drivers/atm/atmtcp.c
--- linux-2.4.19/drivers/atm/atmtcp.c	2001-09-13 22:21:32.000000000 +0000
+++ linux-2.4.20/drivers/atm/atmtcp.c	2002-10-29 11:18:49.000000000 +0000
@@ -173,7 +173,7 @@
 static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb)
 {
 	struct atmtcp_dev_data *dev_data;
-	struct atm_vcc *out_vcc;
+	struct atm_vcc *out_vcc=NULL; /* Initializer quietens GCC warning */
 	struct sk_buff *new_skb;
 	struct atmtcp_hdr *hdr;
 	int size;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/atm/firestream.c linux-2.4.20/drivers/atm/firestream.c
--- linux-2.4.19/drivers/atm/firestream.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.20/drivers/atm/firestream.c	2002-10-29 11:18:33.000000000 +0000
@@ -330,8 +330,8 @@
 #define FS_DEBUG_QSIZE   0x00001000
 
 
-#define func_enter() fs_dprintk (FS_DEBUG_FLOW, "fs: enter " __FUNCTION__ "\n")
-#define func_exit()  fs_dprintk (FS_DEBUG_FLOW, "fs: exit  " __FUNCTION__ "\n")
+#define func_enter() fs_dprintk (FS_DEBUG_FLOW, "fs: enter %s\n", __FUNCTION__)
+#define func_exit()  fs_dprintk (FS_DEBUG_FLOW, "fs: exit  %s\n", __FUNCTION__)
 
 
 struct fs_dev *fs_boards = NULL;
@@ -760,6 +760,7 @@
 		default:
 			/* Here we get the tx purge inhibit command ... */
 			/* Action, I believe, is "don't do anything". -- REW */
+			break;
 		}
     
 		write_fs (dev, Q_RP(q->offset), Q_INCWRAP);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/atm/iphase.c linux-2.4.20/drivers/atm/iphase.c
--- linux-2.4.19/drivers/atm/iphase.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.20/drivers/atm/iphase.c	2002-10-29 11:18:50.000000000 +0000
@@ -124,7 +124,7 @@
 }
 
 static int ia_enque_rtn_q (IARTN_Q *que, struct desc_tbl_t data) {
-   IARTN_Q *entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+   IARTN_Q *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
    if (!entry) return -1;
    entry->data = data;
    entry->next = NULL;
@@ -208,8 +208,7 @@
         ltimeout = dev->desc_tbl[i].iavcc->ltimeout; 
         delta = jiffies - dev->desc_tbl[i].timestamp;
         if (delta >= ltimeout) {
-           IF_ABR(printk("RECOVER run!! desc_tbl %d = %d  delta = %ld, 
-               time = %ld\n", i,dev->desc_tbl[i].timestamp, delta, jiffies);)
+           IF_ABR(printk("RECOVER run!! desc_tbl %d = %d  delta = %ld,  time = %ld\n", i,dev->desc_tbl[i].timestamp, delta, jiffies);)
            if (dev->ffL.tcq_rd == dev->ffL.tcq_st) 
               dev->ffL.tcq_rd =  dev->ffL.tcq_ed;
            else 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/atm/lanai.c linux-2.4.20/drivers/atm/lanai.c
--- linux-2.4.19/drivers/atm/lanai.c	2001-10-25 20:53:46.000000000 +0000
+++ linux-2.4.20/drivers/atm/lanai.c	2002-10-29 11:18:35.000000000 +0000
@@ -2108,8 +2108,8 @@
 	}
 	result = pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &w);
 	if (result != PCIBIOS_SUCCESSFUL) {
-		printk(KERN_ERR DEV_LABEL "(itf %d): can't read ""
-		    PCI_SUBSYSTEM_ID: %d\n", lanai->number, result);
+		printk(KERN_ERR DEV_LABEL "(itf %d): can't read "
+		    "PCI_SUBSYSTEM_ID: %d\n", lanai->number, result);
 		return -EINVAL;
 	}
 	if ((result = check_board_id_and_rev("PCI", w, NULL)) != 0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/Config.in linux-2.4.20/drivers/block/Config.in
--- linux-2.4.19/drivers/block/Config.in	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/block/Config.in	2002-10-29 11:18:35.000000000 +0000
@@ -4,7 +4,7 @@
 mainmenu_option next_comment
 comment 'Block devices'
 
-tristate 'Normal PC floppy disk support' CONFIG_BLK_DEV_FD
+tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD
 if [ "$CONFIG_AMIGA" = "y" ]; then
    tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY
 fi
@@ -37,7 +37,7 @@
 dep_tristate 'Compaq Smart Array 5xxx support' CONFIG_BLK_CPQ_CISS_DA $CONFIG_PCI 
 dep_mbool '       SCSI tape drive support for Smart Array 5xxx' CONFIG_CISS_SCSI_TAPE $CONFIG_BLK_CPQ_CISS_DA $CONFIG_SCSI
 dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI
-dep_tristate 'Micro Memory MM5415 Battery Backed RAM support' CONFIG_BLK_DEV_UMEM $CONFIG_PCI $CONFIG_EXPERIMENTAL
+dep_tristate 'Micro Memory MM5415 Battery Backed RAM support (EXPERIMENTAL)' CONFIG_BLK_DEV_UMEM $CONFIG_PCI $CONFIG_EXPERIMENTAL
 
 tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
 dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
@@ -48,4 +48,6 @@
 fi
 dep_bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
 
+bool 'Per partition statistics in /proc/partitions' CONFIG_BLK_STATS
+
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/DAC960.c linux-2.4.20/drivers/block/DAC960.c
--- linux-2.4.19/drivers/block/DAC960.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/block/DAC960.c	2002-10-29 11:18:49.000000000 +0000
@@ -2488,8 +2488,12 @@
 	    DAC960_V1_QueueReadWriteCommand;
 	  break;
 	case DAC960_PD_Controller:
-	  request_region(Controller->IO_Address, 0x80,
-			 Controller->FullModelName);
+	  if (!request_region(Controller->IO_Address, 0x80,
+			      Controller->FullModelName)) {
+		DAC960_Error("IO port 0x%d busy for Controller at\n",
+			     Controller, Controller->IO_Address);
+		goto Failure;
+	  }
 	  DAC960_PD_DisableInterrupts(BaseAddress);
 	  DAC960_PD_AcknowledgeStatus(BaseAddress);
 	  udelay(1000);
@@ -2499,7 +2503,7 @@
 					    &Parameter0, &Parameter1) &&
 		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
 					   Parameter0, Parameter1))
-		goto Failure;
+		goto Failure1;
 	      udelay(10);
 	    }
 	  DAC960_PD_EnableInterrupts(Controller->BaseAddress);
@@ -2514,8 +2518,12 @@
 	    DAC960_V1_QueueReadWriteCommand;
 	  break;
 	case DAC960_P_Controller:
-	  request_region(Controller->IO_Address, 0x80,
-			 Controller->FullModelName);
+	  if (!request_region(Controller->IO_Address, 0x80,
+			      Controller->FullModelName)){
+		DAC960_Error("IO port 0x%d busy for Controller at\n",
+		   	     Controller, Controller->IO_Address);
+		goto Failure;
+	  }
 	  DAC960_PD_DisableInterrupts(BaseAddress);
 	  DAC960_PD_AcknowledgeStatus(BaseAddress);
 	  udelay(1000);
@@ -2525,7 +2533,7 @@
 					    &Parameter0, &Parameter1) &&
 		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
 					   Parameter0, Parameter1))
-		goto Failure;
+		goto Failure1;
 	      udelay(10);
 	    }
 	  DAC960_PD_EnableInterrupts(Controller->BaseAddress);
@@ -2547,7 +2555,7 @@
 	{
 	  DAC960_Error("IRQ Channel %d illegal for Controller at\n",
 		       Controller, IRQ_Channel);
-	  goto Failure;
+	  goto Failure1;
 	}
       strcpy(Controller->FullModelName, "DAC960");
       if (request_irq(IRQ_Channel, InterruptHandler, SA_SHIRQ,
@@ -2555,7 +2563,7 @@
 	{
 	  DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n",
 		       Controller, IRQ_Channel);
-	  goto Failure;
+	  goto Failure1;
 	}
       Controller->IRQ_Channel = IRQ_Channel;
       DAC960_ActiveControllerCount++;
@@ -2565,6 +2573,8 @@
       Controller->FreeCommands = &Controller->InitialCommand;
       Controller->ControllerDetectionSuccessful = true;
       continue;
+    Failure1:
+      if (Controller->IO_Address) release_region(Controller->IO_Address, 0x80);
     Failure:
       if (IO_Address == 0)
 	DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
@@ -5534,7 +5544,7 @@
 static int DAC960_UserIOCTL(Inode_T *Inode, File_T *File,
 			    unsigned int Request, unsigned long Argument)
 {
-  int ErrorCode;
+  int ErrorCode = 0 ;
   if (!capable(CAP_SYS_ADMIN)) return -EACCES;
   switch (Request)
     {
@@ -5585,9 +5595,11 @@
 	int ControllerNumber, DataTransferLength;
 	unsigned char *DataTransferBuffer = NULL;
 	if (UserSpaceUserCommand == NULL) return -EINVAL;
-	ErrorCode = copy_from_user(&UserCommand, UserSpaceUserCommand,
-				   sizeof(DAC960_V1_UserCommand_T));
-	if (ErrorCode != 0) goto Failure1;
+	if (copy_from_user(&UserCommand, UserSpaceUserCommand,
+				   sizeof(DAC960_V1_UserCommand_T))) {
+		ErrorCode = -EFAULT;
+		goto Failure1;
+	}
 	ControllerNumber = UserCommand.ControllerNumber;
 	if (ControllerNumber < 0 ||
 	    ControllerNumber > DAC960_ControllerCount - 1)
@@ -5600,9 +5612,11 @@
 	if (CommandOpcode & 0x80) return -EINVAL;
 	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
-	    ErrorCode =
-	      copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_V1_DCDB_T));
-	    if (ErrorCode != 0) goto Failure1;
+	    if (copy_from_user(&DCDB, UserCommand.DCDB,
+			       sizeof(DAC960_V1_DCDB_T))) {
+		ErrorCode = -EFAULT;
+		goto Failure1;
+	    }
 	    if (DCDB.Channel >= DAC960_V1_MaxChannels) return -EINVAL;
 	    if (!((DataTransferLength == 0 &&
 		   DCDB.Direction
@@ -5628,10 +5642,12 @@
 	  {
 	    DataTransferBuffer = kmalloc(-DataTransferLength, GFP_KERNEL);
 	    if (DataTransferBuffer == NULL) return -ENOMEM;
-	    ErrorCode = copy_from_user(DataTransferBuffer,
-				       UserCommand.DataTransferBuffer,
-				       -DataTransferLength);
-	    if (ErrorCode != 0) goto Failure1;
+	    if (copy_from_user(DataTransferBuffer,
+			       UserCommand.DataTransferBuffer,
+			       -DataTransferLength)) {
+		ErrorCode = -EFAULT;
+		goto Failure1;
+	    }
 	  }
 	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
@@ -5679,17 +5695,20 @@
 	DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
 	if (DataTransferLength > 0)
 	  {
-	    ErrorCode = copy_to_user(UserCommand.DataTransferBuffer,
-				     DataTransferBuffer, DataTransferLength);
-	    if (ErrorCode != 0) goto Failure1;
+	    if (copy_to_user(UserCommand.DataTransferBuffer,
+			     DataTransferBuffer, DataTransferLength))
+		ErrorCode = -EFAULT;
+		goto Failure1;
 	  }
 	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
 	    Controller->V1.DirectCommandActive[DCDB.Channel]
 					      [DCDB.TargetID] = false;
-	    ErrorCode =
-	      copy_to_user(UserCommand.DCDB, &DCDB, sizeof(DAC960_V1_DCDB_T));
-	    if (ErrorCode != 0) goto Failure1;
+	    if (copy_to_user(UserCommand.DCDB, &DCDB,
+			     sizeof(DAC960_V1_DCDB_T))) {
+		ErrorCode = -EFAULT;
+		goto Failure1;
+	    }
 	  }
 	ErrorCode = CommandStatus;
       Failure1:
@@ -5712,9 +5731,11 @@
 	unsigned char *DataTransferBuffer = NULL;
 	unsigned char *RequestSenseBuffer = NULL;
 	if (UserSpaceUserCommand == NULL) return -EINVAL;
-	ErrorCode = copy_from_user(&UserCommand, UserSpaceUserCommand,
-				   sizeof(DAC960_V2_UserCommand_T));
-	if (ErrorCode != 0) goto Failure2;
+	if (copy_from_user(&UserCommand, UserSpaceUserCommand,
+			   sizeof(DAC960_V2_UserCommand_T))) {
+		ErrorCode = -EFAULT;
+		goto Failure2;
+	}
 	ControllerNumber = UserCommand.ControllerNumber;
 	if (ControllerNumber < 0 ||
 	    ControllerNumber > DAC960_ControllerCount - 1)
@@ -5733,10 +5754,12 @@
 	  {
 	    DataTransferBuffer = kmalloc(-DataTransferLength, GFP_KERNEL);
 	    if (DataTransferBuffer == NULL) return -ENOMEM;
-	    ErrorCode = copy_from_user(DataTransferBuffer,
-				       UserCommand.DataTransferBuffer,
-				       -DataTransferLength);
-	    if (ErrorCode != 0) goto Failure2;
+	    if (copy_from_user(DataTransferBuffer,
+			       UserCommand.DataTransferBuffer,
+			       -DataTransferLength)) {
+		ErrorCode = -EFAULT;
+		goto Failure2;
+	    }
 	  }
 	RequestSenseLength = UserCommand.RequestSenseLength;
 	if (RequestSenseLength > 0)
@@ -5806,25 +5829,32 @@
 	DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
 	if (RequestSenseLength > UserCommand.RequestSenseLength)
 	  RequestSenseLength = UserCommand.RequestSenseLength;
-	ErrorCode = copy_to_user(&UserSpaceUserCommand->DataTransferLength,
+	if (copy_to_user(&UserSpaceUserCommand->DataTransferLength,
 				 &DataTransferResidue,
-				 sizeof(DataTransferResidue));
-	if (ErrorCode != 0) goto Failure2;
-	ErrorCode = copy_to_user(&UserSpaceUserCommand->RequestSenseLength,
-				 &RequestSenseLength,
-				 sizeof(RequestSenseLength));
-	if (ErrorCode != 0) goto Failure2;
+				 sizeof(DataTransferResidue))) {
+		ErrorCode = -EFAULT;
+		goto Failure2;
+	}
+	if (copy_to_user(&UserSpaceUserCommand->RequestSenseLength,
+			 &RequestSenseLength, sizeof(RequestSenseLength))) {
+		ErrorCode = -EFAULT;
+		goto Failure2;
+	}
 	if (DataTransferLength > 0)
 	  {
-	    ErrorCode = copy_to_user(UserCommand.DataTransferBuffer,
-				     DataTransferBuffer, DataTransferLength);
-	    if (ErrorCode != 0) goto Failure2;
+	    if (copy_to_user(UserCommand.DataTransferBuffer,
+			     DataTransferBuffer, DataTransferLength)) {
+		ErrorCode = -EFAULT;
+		goto Failure2;
+	    }
 	  }
 	if (RequestSenseLength > 0)
 	  {
-	    ErrorCode = copy_to_user(UserCommand.RequestSenseBuffer,
-				     RequestSenseBuffer, RequestSenseLength);
-	    if (ErrorCode != 0) goto Failure2;
+	    if (copy_to_user(UserCommand.RequestSenseBuffer,
+			     RequestSenseBuffer, RequestSenseLength)) {
+		ErrorCode = -EFAULT;
+		goto Failure2;
+	    }
 	  }
 	ErrorCode = CommandStatus;
       Failure2:
@@ -5843,9 +5873,9 @@
 	DAC960_Controller_T *Controller;
 	int ControllerNumber;
 	if (UserSpaceGetHealthStatus == NULL) return -EINVAL;
-	ErrorCode = copy_from_user(&GetHealthStatus, UserSpaceGetHealthStatus,
-				   sizeof(DAC960_V2_GetHealthStatus_T));
-	if (ErrorCode != 0) return ErrorCode;
+	if (copy_from_user(&GetHealthStatus, UserSpaceGetHealthStatus,
+			   sizeof(DAC960_V2_GetHealthStatus_T)))
+		return -EFAULT;
 	ControllerNumber = GetHealthStatus.ControllerNumber;
 	if (ControllerNumber < 0 ||
 	    ControllerNumber > DAC960_ControllerCount - 1)
@@ -5853,10 +5883,10 @@
 	Controller = DAC960_Controllers[ControllerNumber];
 	if (Controller == NULL) return -ENXIO;
 	if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL;
-	ErrorCode = copy_from_user(&HealthStatusBuffer,
-				   GetHealthStatus.HealthStatusBuffer,
-				   sizeof(DAC960_V2_HealthStatusBuffer_T));
-	if (ErrorCode != 0) return ErrorCode;
+	if (copy_from_user(&HealthStatusBuffer,
+			   GetHealthStatus.HealthStatusBuffer,
+			   sizeof(DAC960_V2_HealthStatusBuffer_T)))
+		return -EFAULT;
 	while (Controller->V2.HealthStatusBuffer->StatusChangeCounter
 	       == HealthStatusBuffer.StatusChangeCounter &&
 	       Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
@@ -5866,10 +5896,11 @@
 					   DAC960_MonitoringTimerInterval);
 	    if (signal_pending(current)) return -EINTR;
 	  }
-	ErrorCode = copy_to_user(GetHealthStatus.HealthStatusBuffer,
-				 Controller->V2.HealthStatusBuffer,
-				 sizeof(DAC960_V2_HealthStatusBuffer_T));
-	return ErrorCode;
+	if (copy_to_user(GetHealthStatus.HealthStatusBuffer,
+			 Controller->V2.HealthStatusBuffer,
+			 sizeof(DAC960_V2_HealthStatusBuffer_T)))
+		return -EFAULT;
+	return 0;
       }
     }
   return -EINVAL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/acsi.c linux-2.4.20/drivers/block/acsi.c
--- linux-2.4.19/drivers/block/acsi.c	2001-11-09 21:58:03.000000000 +0000
+++ linux-2.4.20/drivers/block/acsi.c	2002-10-29 11:18:40.000000000 +0000
@@ -374,7 +374,9 @@
 /************************* End of Prototypes **************************/
 
 
-struct timer_list acsi_timer = { NULL, NULL, 0, 0, acsi_times_out };
+struct timer_list acsi_timer = {
+    function:	acsi_times_out
+};
 
 
 #ifdef CONFIG_ATARI_SLM
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/acsi_slm.c linux-2.4.20/drivers/block/acsi_slm.c
--- linux-2.4.19/drivers/block/acsi_slm.c	2001-05-22 17:23:16.000000000 +0000
+++ linux-2.4.20/drivers/block/acsi_slm.c	2002-10-29 11:18:31.000000000 +0000
@@ -1003,7 +1003,7 @@
 		return -EBUSY;
 	}
 	
-	if (!(SLMBuffer = atari_stram_alloc( SLM_BUFFER_SIZE, NULL, "SLM" ))) {
+	if (!(SLMBuffer = atari_stram_alloc( SLM_BUFFER_SIZE, "SLM" ))) {
 		printk( KERN_ERR "Unable to get SLM ST-Ram buffer.\n" );
 		devfs_unregister_chrdev( MAJOR_NR, "slm" );
 		return -ENOMEM;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/ataflop.c linux-2.4.20/drivers/block/ataflop.c
--- linux-2.4.19/drivers/block/ataflop.c	2001-10-25 20:58:35.000000000 +0000
+++ linux-2.4.20/drivers/block/ataflop.c	2002-10-29 11:18:33.000000000 +0000
@@ -355,7 +355,7 @@
 static void fd_select_drive( int drive );
 static void fd_deselect( void );
 static void fd_motor_off_timer( unsigned long dummy );
-static void check_change( void );
+static void check_change( unsigned long dummy );
 static __inline__ void set_head_settle_flag( void );
 static __inline__ int get_head_settle_flag( void );
 static void floppy_irq (int irq, void *dummy, struct pt_regs *fp);
@@ -536,7 +536,7 @@
  * as possible) and keep track of the current state of the write protection.
  */
 
-static void check_change( void )
+static void check_change( unsigned long dummy )
 {
 	static int    drive = 0;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/cciss.c linux-2.4.20/drivers/block/cciss.c
--- linux-2.4.19/drivers/block/cciss.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/block/cciss.c	2002-10-29 11:18:50.000000000 +0000
@@ -1166,20 +1166,22 @@
 static inline void complete_command( CommandList_struct *cmd, int timeout)
 {
 	int status = 1;
-	int i;
+	int i, ddir;
 	u64bit temp64;
 		
 	if (timeout)
 		status = 0; 
 	/* unmap the DMA mapping for all the scatter gather elements */
+	if (cmd->Request.Type.Direction == XFER_READ)
+		ddir = PCI_DMA_FROMDEVICE;
+	else
+		ddir = PCI_DMA_TODEVICE;
 	for(i=0; i<cmd->Header.SGList; i++)
 	{
 		temp64.val32.lower = cmd->SG[i].Addr.lower;
 		temp64.val32.upper = cmd->SG[i].Addr.upper;
-		pci_unmap_single(hba[cmd->ctlr]->pdev,
-			temp64.val, cmd->SG[i].Len, 
-			(cmd->Request.Type.Direction == XFER_READ) ? 
-				PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+		pci_unmap_page(hba[cmd->ctlr]->pdev,
+			temp64.val, cmd->SG[i].Len, ddir);
 	}
 
 	if(cmd->err_info->CommandStatus != 0) 
@@ -1287,7 +1289,7 @@
 static int cpq_back_merge_fn(request_queue_t *q, struct request *rq,
                              struct buffer_head *bh, int max_segments)
 {
-        if (rq->bhtail->b_data + rq->bhtail->b_size == bh->b_data)
+	if (blk_seg_merge_ok(rq->bhtail, bh))
                 return 1;
         return cpq_new_segment(q, rq, max_segments);
 }
@@ -1295,7 +1297,7 @@
 static int cpq_front_merge_fn(request_queue_t *q, struct request *rq,
                              struct buffer_head *bh, int max_segments)
 {
-        if (bh->b_data + bh->b_size == rq->bh->b_data)
+	if (blk_seg_merge_ok(bh, rq->bh))
                 return 1;
         return cpq_new_segment(q, rq, max_segments);
 }
@@ -1305,7 +1307,7 @@
 {
         int total_segments = rq->nr_segments + nxt->nr_segments;
 
-        if (rq->bhtail->b_data + rq->bhtail->b_size == nxt->bh->b_data)
+	if (blk_seg_merge_ok(rq->bhtail, nxt->bh))
                 total_segments--;
 
         if (total_segments > MAXSGENTRIES)
@@ -1326,18 +1328,18 @@
 	ctlr_info_t *h= q->queuedata; 
 	CommandList_struct *c;
 	int log_unit, start_blk, seg;
-	char *lastdataend;
+	unsigned long long lastdataend;
 	struct buffer_head *bh;
 	struct list_head *queue_head = &q->queue_head;
 	struct request *creq;
 	u64bit temp64;
-	struct my_sg tmp_sg[MAXSGENTRIES];
-	int i;
+	struct scatterlist tmp_sg[MAXSGENTRIES];
+	int i, ddir;
 
 	if (q->plugged)
 		goto startio;
 
-queue_next:
+next:
 	if (list_empty(queue_head))
 		goto startio;
 
@@ -1363,8 +1365,8 @@
 	spin_unlock_irq(&io_request_lock);
 
 	c->cmd_type = CMD_RWREQ;      
-	bh = creq->bh;
 	c->rq = creq;
+	bh = creq->bh;
 	
 	/* fill in the request */ 
 	log_unit = MINOR(creq->rq_dev) >> NWD_SHIFT; 
@@ -1386,34 +1388,36 @@
 	printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",(int) creq->sector,
 		(int) creq->nr_sectors);	
 #endif /* CCISS_DEBUG */
-	seg = 0; 
-	lastdataend = NULL;
+	seg = 0;
+	lastdataend = ~0ULL;
 	while(bh)
 	{
-		if (bh->b_data == lastdataend)
+		if (bh_phys(bh) == lastdataend)
 		{  // tack it on to the last segment 
-			tmp_sg[seg-1].len +=bh->b_size;
+			tmp_sg[seg-1].length +=bh->b_size;
 			lastdataend += bh->b_size;
 		} else
 		{
 			if (seg == MAXSGENTRIES)
 				BUG();
-			tmp_sg[seg].len = bh->b_size;
-			tmp_sg[seg].start_addr = bh->b_data;
-			lastdataend = bh->b_data + bh->b_size;
+			tmp_sg[seg].page = bh->b_page;
+			tmp_sg[seg].length = bh->b_size;
+			tmp_sg[seg].offset = bh_offset(bh);
+			lastdataend = bh_phys(bh) + bh->b_size;
 			seg++;
 		}
 		bh = bh->b_reqnext;
 	}
+
 	/* get the DMA records for the setup */ 
-	for (i=0; i<seg; i++)
-	{
-		c->SG[i].Len = tmp_sg[i].len;
-		temp64.val = (__u64) pci_map_single( h->pdev,
-			tmp_sg[i].start_addr,
-			tmp_sg[i].len,
-			(c->Request.Type.Direction == XFER_READ) ? 
-                                PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+	if (c->Request.Type.Direction == XFER_READ)
+		ddir = PCI_DMA_FROMDEVICE;
+	else
+		ddir = PCI_DMA_TODEVICE;
+	for (i=0; i<seg; i++) {
+		c->SG[i].Len = tmp_sg[i].length;
+		temp64.val = pci_map_page(h->pdev, tmp_sg[i].page,
+			    tmp_sg[i].offset, tmp_sg[i].length, ddir);
 		c->SG[i].Addr.lower = temp64.val32.lower;
                 c->SG[i].Addr.upper = temp64.val32.upper;
                 c->SG[i].Ext = 0;  // we are not chaining
@@ -1423,7 +1427,7 @@
 		h->maxSG = seg; 
 
 #ifdef CCISS_DEBUG
-	printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n", creq->nr_sectors, seg);
+	printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n", sect, seg);
 #endif /* CCISS_DEBUG */
 
 	c->Header.SGList = c->Header.SGTotal = seg;
@@ -1444,7 +1448,8 @@
 	if(h->Qdepth > h->maxQsinceinit)
 		h->maxQsinceinit = h->Qdepth; 
 
-	goto queue_next;
+	goto next;
+
 startio:
 	start_io(h);
 }
@@ -1969,7 +1974,18 @@
 	sprintf(hba[i]->devname, "cciss%d", i);
 	hba[i]->ctlr = i;
 	hba[i]->pdev = pdev;
-			
+
+	/* configure PCI DMA stuff */
+	if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff))
+		printk("cciss: using DAC cycles\n");
+	else if (!pci_set_dma_mask(pdev, (u64) 0xffffffff))
+		printk("cciss: not using DAC cycles\n");
+	else {
+		printk("cciss: no suitable DMA available\n");
+		free_hba(i);
+		return -ENODEV;
+	}
+		
 	if( register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops))
 	{
 		printk(KERN_ERR "cciss:  Unable to get major number "
@@ -2043,9 +2059,10 @@
 	cciss_procinit(i);
 
 	q = BLK_DEFAULT_QUEUE(MAJOR_NR + i);
-        q->queuedata = hba[i];
-        blk_init_queue(q, do_cciss_request);
-        blk_queue_headactive(q, 0);		
+	q->queuedata = hba[i];
+	blk_init_queue(q, do_cciss_request);
+	blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask);
+	blk_queue_headactive(q, 0);		
 
 	/* fill in the other Kernel structs */
 	blksize_size[MAJOR_NR+i] = hba[i]->blocksizes;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/cciss.h linux-2.4.20/drivers/block/cciss.h
--- linux-2.4.19/drivers/block/cciss.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/block/cciss.h	2002-10-29 11:18:31.000000000 +0000
@@ -15,11 +15,6 @@
 
 #define MAJOR_NR COMPAQ_CISS_MAJOR 
 
-struct my_sg {
-	int len;
-	char *start_addr;
-};
-
 struct ctlr_info;
 typedef struct ctlr_info ctlr_info_t;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/cciss_scsi.c linux-2.4.20/drivers/block/cciss_scsi.c
--- linux-2.4.19/drivers/block/cciss_scsi.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/block/cciss_scsi.c	2002-10-29 11:18:31.000000000 +0000
@@ -233,8 +233,8 @@
 		printk( "cciss: %d scsi commands are still outstanding.\n",
 			CMD_STACK_SIZE - stk->top);
 		// BUG();
-		printk("WE HAVE A BUG HERE!!! stk=0x%08x\n",
-			(unsigned int) stk);
+		printk("WE HAVE A BUG HERE!!! stk=%p\n",
+			stk);
 	}
 	size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
 
@@ -1578,7 +1578,7 @@
 cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len)
 {
 	int size;
-	unsigned int flags;
+	unsigned long flags;
 
 	*pos = *pos -1; *len = *len - 1; // cut off the last trailing newline
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/cpqarray.c linux-2.4.20/drivers/block/cpqarray.c
--- linux-2.4.19/drivers/block/cpqarray.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/block/cpqarray.c	2002-10-29 11:18:33.000000000 +0000
@@ -443,7 +443,7 @@
 static int cpq_back_merge_fn(request_queue_t *q, struct request *rq,
 			     struct buffer_head *bh, int max_segments)
 {
-	if (rq->bhtail->b_data + rq->bhtail->b_size == bh->b_data)
+	if (blk_seg_merge_ok(rq->bhtail, bh))
 		return 1;
 	return cpq_new_segment(q, rq, max_segments);
 }
@@ -451,7 +451,7 @@
 static int cpq_front_merge_fn(request_queue_t *q, struct request *rq,
 			     struct buffer_head *bh, int max_segments)
 {
-	if (bh->b_data + bh->b_size == rq->bh->b_data)
+	if (blk_seg_merge_ok(bh, rq->bh))
 		return 1;
 	return cpq_new_segment(q, rq, max_segments);
 }
@@ -461,7 +461,7 @@
 {
 	int total_segments = rq->nr_segments + nxt->nr_segments;
 
-	if (rq->bhtail->b_data + rq->bhtail->b_size == nxt->bh->b_data)
+	if (blk_seg_merge_ok(rq->bhtail, nxt->bh))
 		total_segments--;
 
 	if (total_segments > SG_MAX)
@@ -566,6 +566,7 @@
 	q = BLK_DEFAULT_QUEUE(MAJOR_NR + i);
 	q->queuedata = hba[i];
 	blk_init_queue(q, do_ida_request);
+	blk_queue_bounce_limit(q, hba[i]->pci_dev->dma_mask);
 	blk_queue_headactive(q, 0);
 	blksize_size[MAJOR_NR+i] = hba[i]->blocksizes;
 	hardsect_size[MAJOR_NR+i] = hba[i]->hardsizes;
@@ -966,17 +967,17 @@
 {
 	ctlr_info_t *h = q->queuedata;
 	cmdlist_t *c;
-	char *lastdataend;
+	unsigned long lastdataend;
 	struct list_head * queue_head = &q->queue_head;
 	struct buffer_head *bh;
 	struct request *creq;
-	struct my_sg tmp_sg[SG_MAX];
+	struct scatterlist tmp_sg[SG_MAX];
 	int i, seg;
 
 	if (q->plugged)
 		goto startio;
 
-queue_next:
+next:
 	if (list_empty(queue_head))
 		goto startio;
 
@@ -1017,17 +1018,19 @@
 	
 	printk("sector=%d, nr_sectors=%d\n", creq->sector, creq->nr_sectors);
 );
-	seg = 0; lastdataend = NULL;
+	seg = 0;
+	lastdataend = ~0UL;
 	while(bh) {
-		if (bh->b_data == lastdataend) {
-			tmp_sg[seg-1].size += bh->b_size;
+		if (bh_phys(bh) == lastdataend) {
+			tmp_sg[seg-1].length += bh->b_size;
 			lastdataend += bh->b_size;
 		} else {
 			if (seg == SG_MAX)
 				BUG();
-			tmp_sg[seg].size = bh->b_size;
-			tmp_sg[seg].start_addr = bh->b_data;
-			lastdataend = bh->b_data + bh->b_size;
+			tmp_sg[seg].page = bh->b_page;
+			tmp_sg[seg].length = bh->b_size;
+			tmp_sg[seg].offset = bh_offset(bh);
+			lastdataend = bh_phys(bh) + bh->b_size;
 			seg++;
 		}
 		bh = bh->b_reqnext;
@@ -1035,10 +1038,10 @@
 	/* Now do all the DMA Mappings */
 	for( i=0; i < seg; i++)
 	{
-		c->req.sg[i].size = tmp_sg[i].size;
-		c->req.sg[i].addr = (__u32) pci_map_single(
-                		h->pci_dev, tmp_sg[i].start_addr, 
-				tmp_sg[i].size,
+		c->req.sg[i].size = tmp_sg[i].length;
+		c->req.sg[i].addr = (__u32) pci_map_page(
+                		h->pci_dev, tmp_sg[i].page, tmp_sg[i].offset,
+				tmp_sg[i].length,
                                 (creq->cmd == READ) ? 
 					PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
 	}
@@ -1056,7 +1059,7 @@
 	if (h->Qdepth > h->maxQsinceinit) 
 		h->maxQsinceinit = h->Qdepth;
 
-	goto queue_next;
+	goto next;
 
 startio:
 	start_io(h);
@@ -1132,17 +1135,14 @@
 	/* unmap the DMA mapping for all the scatter gather elements */
         for(i=0; i<cmd->req.hdr.sg_cnt; i++)
         {
-                pci_unmap_single(hba[cmd->ctlr]->pci_dev,
+                pci_unmap_page(hba[cmd->ctlr]->pci_dev,
                         cmd->req.sg[i].addr, cmd->req.sg[i].size,
                         (cmd->req.hdr.cmd == IDA_READ) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
         }
 
 	complete_buffers(cmd->rq->bh, ok);
-
 	DBGPX(printk("Done with %p\n", cmd->rq););
 	end_that_request_last(cmd->rq);
-
-
 }
 
 /*
@@ -1301,7 +1301,8 @@
 		if (error) return error;
 		error = ida_ctlr_ioctl(ctlr, dsk, &my_io);
 		if (error) return error;
-		error = copy_to_user(io, &my_io, sizeof(my_io));
+		if(copy_to_user(io, &my_io, sizeof(my_io)))
+			return -EFAULT;
 		return error;
 	case IDAGETCTLRSIG:
 		if (!arg) return -EINVAL;
@@ -1416,7 +1417,11 @@
 			cmd_free(h, c, 0); 
 			return(error);
 		}
-		copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size);
+		if (copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size)) {
+			kfree(p);
+			cmd_free(h, c, 0); 
+			return -EFAULT;
+		}
 		c->req.hdr.blk = pci_map_single(h->pci_dev, &(io->c), 
 				sizeof(ida_ioctl_t), 
 				PCI_DMA_BIDIRECTIONAL);
@@ -1453,7 +1458,11 @@
                         cmd_free(h, c, 0);
                         return(error);
                 }
-		copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size);
+		if (copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size)) {
+			kfree(p);
+                        cmd_free(h, c, 0);
+			return -EFAULT;
+		}
 		c->req.sg[0].size = io->sg[0].size;
 		c->req.sg[0].addr = pci_map_single(h->pci_dev, p, 
 			c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL); 
@@ -1490,7 +1499,10 @@
 	case DIAG_PASS_THRU:
 	case SENSE_CONTROLLER_PERFORMANCE:
 	case READ_FLASH_ROM:
-		copy_to_user((void*)io->sg[0].addr, p, io->sg[0].size);
+		if (copy_to_user((void*)io->sg[0].addr, p, io->sg[0].size)) {
+			kfree(p);
+			return -EFAULT;
+		}
 		/* fall through and free p */
 	case IDA_WRITE:
 	case IDA_WRITE_MEDIA:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/cpqarray.h linux-2.4.20/drivers/block/cpqarray.h
--- linux-2.4.19/drivers/block/cpqarray.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/block/cpqarray.h	2002-10-29 11:18:49.000000000 +0000
@@ -57,11 +57,6 @@
 
 #ifdef __KERNEL__
 
-struct my_sg {
-	int size;
-	char *start_addr;
-};
-
 struct ctlr_info;
 typedef struct ctlr_info ctlr_info_t;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/elevator.c linux-2.4.20/drivers/block/elevator.c
--- linux-2.4.19/drivers/block/elevator.c	2001-07-20 03:59:41.000000000 +0000
+++ linux-2.4.20/drivers/block/elevator.c	2002-10-29 11:18:34.000000000 +0000
@@ -82,14 +82,15 @@
 {
 	struct list_head *entry = &q->queue_head;
 	unsigned int count = bh->b_size >> 9, ret = ELEVATOR_NO_MERGE;
+	struct request *__rq;
 
 	while ((entry = entry->prev) != head) {
-		struct request *__rq = blkdev_entry_to_request(entry);
+		__rq = blkdev_entry_to_request(entry);
 
 		/*
-		 * simply "aging" of requests in queue
+		 * we can't insert beyond a zero sequence point
 		 */
-		if (__rq->elevator_sequence-- <= 0)
+		if (__rq->elevator_sequence <= 0)
 			break;
 
 		if (__rq->waiting)
@@ -102,34 +103,33 @@
 			continue;
 		if (__rq->nr_sectors + count > max_sectors)
 			continue;
-		if (__rq->elevator_sequence < count)
-			break;
 		if (__rq->sector + __rq->nr_sectors == bh->b_rsector) {
 			ret = ELEVATOR_BACK_MERGE;
 			*req = __rq;
 			break;
 		} else if (__rq->sector - count == bh->b_rsector) {
 			ret = ELEVATOR_FRONT_MERGE;
-			__rq->elevator_sequence -= count;
+			__rq->elevator_sequence--;
 			*req = __rq;
 			break;
 		}
 	}
 
-	return ret;
-}
-
-void elevator_linus_merge_cleanup(request_queue_t *q, struct request *req, int count)
-{
-	struct list_head *entry = &req->queue, *head = &q->queue_head;
-
 	/*
-	 * second pass scan of requests that got passed over, if any
+	 * account merge (ret != 0, cost is 1) or seeky insert (*req is set,
+	 * cost is ELV_LINUS_SEEK_COST
 	 */
-	while ((entry = entry->next) != head) {
-		struct request *tmp = blkdev_entry_to_request(entry);
-		tmp->elevator_sequence -= count;
+	if (*req) {
+		int scan_cost = ret ? 1 : ELV_LINUS_SEEK_COST;
+		struct list_head *entry = &(*req)->queue;
+
+		while ((entry = entry->next) != &q->queue_head) {
+			__rq = blkdev_entry_to_request(entry);
+			__rq->elevator_sequence -= scan_cost;
+		}
 	}
+
+	return ret;
 }
 
 void elevator_linus_merge_req(struct request *req, struct request *next)
@@ -177,8 +177,6 @@
 	return ELEVATOR_NO_MERGE;
 }
 
-void elevator_noop_merge_cleanup(request_queue_t *q, struct request *req, int count) {}
-
 void elevator_noop_merge_req(struct request *req, struct request *next) {}
 
 int blkelvget_ioctl(elevator_t * elevator, blkelv_ioctl_arg_t * arg)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/genhd.c linux-2.4.20/drivers/block/genhd.c
--- linux-2.4.19/drivers/block/genhd.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/block/genhd.c	2002-10-29 11:18:40.000000000 +0000
@@ -22,10 +22,9 @@
 #include <linux/blk.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/seq_file.h>
 
 
-static rwlock_t gendisk_lock;
-
 /*
  * Global kernel list of partitioning information.
  *
@@ -34,6 +33,7 @@
  */
 /*static*/ struct gendisk *gendisk_head;
 static struct gendisk *gendisk_array[MAX_BLKDEV];
+static rwlock_t gendisk_lock = RW_LOCK_UNLOCKED;
 
 EXPORT_SYMBOL(gendisk_head);
 
@@ -153,46 +153,82 @@
 	return error;
 }
 
-
 #ifdef CONFIG_PROC_FS
-int
-get_partition_list(char *page, char **start, off_t offset, int count)
+/* iterator */
+static void *part_start(struct seq_file *s, loff_t *ppos)
 {
 	struct gendisk *gp;
-	struct hd_struct *hd;
-	char buf[64];
-	int len, n;
+	loff_t pos = *ppos;
 
-	len = sprintf(page, "major minor  #blocks  name\n\n");
-		
 	read_lock(&gendisk_lock);
-	for (gp = gendisk_head; gp; gp = gp->next) {
-		for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) {
-			if (gp->part[n].nr_sects == 0)
-				continue;
-
-			hd = &gp->part[n]; disk_round_stats(hd);
-			len += sprintf(page + len,
-				"%4d  %4d %10d %s\n", gp->major,
-				n, gp->sizes[n], disk_name(gp, n, buf));
-
-			if (len < offset)
-				offset -= len, len = 0;
-			else if (len >= offset + count)
-				goto out;
-		}
-	}
+	for (gp = gendisk_head; gp; gp = gp->next)
+		if (!pos--)
+			return gp;
+	return NULL;
+}
 
-out:
+static void *part_next(struct seq_file *s, void *v, loff_t *pos)
+{
+	++*pos;
+	return ((struct gendisk *)v)->next;
+}
+
+static void part_stop(struct seq_file *s, void *v)
+{
 	read_unlock(&gendisk_lock);
-	*start = page + offset;
-	len -= offset;
-	if (len < 0)
-		len = 0;
-	return len > count ? count : len;
 }
+
+static int part_show(struct seq_file *s, void *v)
+{
+	struct gendisk *gp = v;
+	char buf[64];
+	int n;
+
+	if (gp == gendisk_head) {
+		seq_puts(s, "major minor  #blocks  name"
+#ifdef CONFIG_BLK_STATS
+			    "     rio rmerge rsect ruse wio wmerge "
+			    "wsect wuse running use aveq"
 #endif
+			   "\n\n");
+	}
+
+	/* show the full disk and all non-0 size partitions of it */
+	for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) {
+		if (gp->part[n].nr_sects) {
+#ifdef CONFIG_BLK_STATS
+			struct hd_struct *hd = &gp->part[n];
+
+			disk_round_stats(hd);
+			seq_printf(s, "%4d  %4d %10d %s "
+				      "%d %d %d %d %d %d %d %d %d %d %d\n",
+				      gp->major, n, gp->sizes[n],
+				      disk_name(gp, n, buf),
+				      hd->rd_ios, hd->rd_merges,
+#define MSEC(x) ((x) * 1000 / HZ)
+				      hd->rd_sectors, MSEC(hd->rd_ticks),
+				      hd->wr_ios, hd->wr_merges,
+				      hd->wr_sectors, MSEC(hd->wr_ticks),
+				      hd->ios_in_flight, MSEC(hd->io_ticks),
+				      MSEC(hd->aveq));
+#else
+			seq_printf(s, "%4d  %4d %10d %s\n",
+				   gp->major, n, gp->sizes[n],
+				   disk_name(gp, n, buf));
+#endif /* CONFIG_BLK_STATS */
+		}
+	}
+
+	return 0;
+}
 
+struct seq_operations partitions_op = {
+	.start		= part_start,
+	.next		= part_next,
+	.stop		= part_stop,
+	.show		= part_show,
+};
+#endif
 
 extern int blk_dev_init(void);
 extern int net_dev_init(void);
@@ -201,7 +237,6 @@
 
 int __init device_init(void)
 {
-	rwlock_init(&gendisk_lock);
 	blk_dev_init();
 	sti();
 #ifdef CONFIG_NET
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/ll_rw_blk.c linux-2.4.20/drivers/block/ll_rw_blk.c
--- linux-2.4.19/drivers/block/ll_rw_blk.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/block/ll_rw_blk.c	2002-10-29 11:18:33.000000000 +0000
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
+#include <linux/bootmem.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -117,6 +118,9 @@
  */
 int * max_sectors[MAX_BLKDEV];
 
+unsigned long blk_max_low_pfn, blk_max_pfn;
+int blk_nohighio = 0;
+
 static inline int get_max_sectors(kdev_t dev)
 {
 	if (!max_sectors[MAJOR(dev)])
@@ -238,6 +242,55 @@
 	q->make_request_fn = mfn;
 }
 
+/**
+ * blk_queue_bounce_limit - set bounce buffer limit for queue
+ * @q:  the request queue for the device
+ * @dma_addr:   bus address limit
+ *
+ * Description:
+ *    Different hardware can have different requirements as to what pages
+ *    it can do I/O directly to. A low level driver can call
+ *    blk_queue_bounce_limit to have lower memory pages allocated as bounce
+ *    buffers for doing I/O to pages residing above @page. By default
+ *    the block layer sets this to the highest numbered "low" memory page.
+ **/
+void blk_queue_bounce_limit(request_queue_t *q, u64 dma_addr)
+{
+	unsigned long bounce_pfn = dma_addr >> PAGE_SHIFT;
+	unsigned long mb = dma_addr >> 20;
+	static request_queue_t *old_q;
+
+	/*
+	 * keep this for debugging for now...
+	 */
+	if (dma_addr != BLK_BOUNCE_HIGH && q != old_q) {
+		old_q = q;
+		printk("blk: queue %p, ", q);
+		if (dma_addr == BLK_BOUNCE_ANY)
+			printk("no I/O memory limit\n");
+		else
+			printk("I/O limit %luMb (mask 0x%Lx)\n", mb,
+			       (long long) dma_addr);
+	}
+
+	q->bounce_pfn = bounce_pfn;
+}
+
+
+/*
+ * can we merge the two segments, or do we need to start a new one?
+ */
+inline int blk_seg_merge_ok(struct buffer_head *bh, struct buffer_head *nxt)
+{
+	/*
+	 * if bh and nxt are contigous and don't cross a 4g boundary, it's ok
+	 */
+	if (BH_CONTIG(bh, nxt) && BH_PHYS_4G(bh, nxt))
+		return 1;
+
+	return 0;
+}
+
 static inline int ll_new_segment(request_queue_t *q, struct request *req, int max_segments)
 {
 	if (req->nr_segments < max_segments) {
@@ -250,16 +303,18 @@
 static int ll_back_merge_fn(request_queue_t *q, struct request *req, 
 			    struct buffer_head *bh, int max_segments)
 {
-	if (req->bhtail->b_data + req->bhtail->b_size == bh->b_data)
+	if (blk_seg_merge_ok(req->bhtail, bh))
 		return 1;
+
 	return ll_new_segment(q, req, max_segments);
 }
 
 static int ll_front_merge_fn(request_queue_t *q, struct request *req, 
 			     struct buffer_head *bh, int max_segments)
 {
-	if (bh->b_data + bh->b_size == req->bh->b_data)
+	if (blk_seg_merge_ok(bh, req->bh))
 		return 1;
+
 	return ll_new_segment(q, req, max_segments);
 }
 
@@ -268,9 +323,9 @@
 {
 	int total_segments = req->nr_segments + next->nr_segments;
 
-	if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data)
+	if (blk_seg_merge_ok(req->bhtail, next->bh))
 		total_segments--;
-    
+
 	if (total_segments > max_segments)
 		return 0;
 
@@ -444,6 +499,8 @@
 	 */
 	q->plug_device_fn 	= generic_plug_device;
 	q->head_active    	= 1;
+
+	blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
 }
 
 #define blkdev_free_rq(list) list_entry((list)->next, struct request, queue);
@@ -540,7 +597,7 @@
 		if (q->rq[rw].count == 0)
 			schedule();
 		spin_lock_irq(&io_request_lock);
-		rq = get_request(q,rw);
+		rq = get_request(q, rw);
 		spin_unlock_irq(&io_request_lock);
 	} while (rq == NULL);
 	remove_wait_queue(&q->wait_for_requests[rw], &wait);
@@ -594,9 +651,14 @@
 		printk(KERN_ERR "drive_stat_acct: cmd not R/W?\n");
 }
 
-/* Return up to two hd_structs on which to do IO accounting for a given
- * request.  On a partitioned device, we want to account both against
- * the partition and against the whole disk.  */
+#ifdef CONFIG_BLK_STATS
+/*
+ * Return up to two hd_structs on which to do IO accounting for a given
+ * request.
+ *
+ * On a partitioned device, we want to account both against the partition
+ * and against the whole disk.
+ */
 static void locate_hd_struct(struct request *req, 
 			     struct hd_struct **hd1,
 			     struct hd_struct **hd2)
@@ -611,22 +673,26 @@
 		/* Mask out the partition bits: account for the entire disk */
 		int devnr = MINOR(req->rq_dev) >> gd->minor_shift;
 		int whole_minor = devnr << gd->minor_shift;
+
 		*hd1 = &gd->part[whole_minor];
 		if (whole_minor != MINOR(req->rq_dev))
 			*hd2= &gd->part[MINOR(req->rq_dev)];
 	}
 }
 
-/* Round off the performance stats on an hd_struct.  The average IO
- * queue length and utilisation statistics are maintained by observing
- * the current state of the queue length and the amount of time it has
- * been in this state for.  Normally, that accounting is done on IO
- * completion, but that can result in more than a second's worth of IO
- * being accounted for within any one second, leading to >100%
- * utilisation.  To deal with that, we do a round-off before returning
- * the results when reading /proc/partitions, accounting immediately for
- * all queue usage up to the current jiffies and restarting the counters
- * again. */
+/*
+ * Round off the performance stats on an hd_struct.
+ *
+ * The average IO queue length and utilisation statistics are maintained
+ * by observing the current state of the queue length and the amount of
+ * time it has been in this state for.
+ * Normally, that accounting is done on IO completion, but that can result
+ * in more than a second's worth of IO being accounted for within any one
+ * second, leading to >100% utilisation.  To deal with that, we do a
+ * round-off before returning the results when reading /proc/partitions,
+ * accounting immediately for all queue usage up to the current jiffies and
+ * restarting the counters again.
+ */
 void disk_round_stats(struct hd_struct *hd)
 {
 	unsigned long now = jiffies;
@@ -639,7 +705,6 @@
 	hd->last_idle_time = now;	
 }
 
-
 static inline void down_ios(struct hd_struct *hd)
 {
 	disk_round_stats(hd);	
@@ -690,6 +755,7 @@
 void req_new_io(struct request *req, int merge, int sectors)
 {
 	struct hd_struct *hd1, *hd2;
+
 	locate_hd_struct(req, &hd1, &hd2);
 	if (hd1)
 		account_io_start(hd1, req, merge, sectors);
@@ -697,15 +763,29 @@
 		account_io_start(hd2, req, merge, sectors);
 }
 
+void req_merged_io(struct request *req)
+{
+	struct hd_struct *hd1, *hd2;
+
+	locate_hd_struct(req, &hd1, &hd2);
+	if (hd1)
+		down_ios(hd1);
+	if (hd2)	
+		down_ios(hd2);
+}
+
 void req_finished_io(struct request *req)
 {
 	struct hd_struct *hd1, *hd2;
+
 	locate_hd_struct(req, &hd1, &hd2);
 	if (hd1)
 		account_io_end(hd1, req);
 	if (hd2)	
 		account_io_end(hd2, req);
 }
+EXPORT_SYMBOL(req_finished_io);
+#endif /* CONFIG_BLK_STATS */
 
 /*
  * add-request adds a request to the linked list.
@@ -764,7 +844,6 @@
 			  int max_segments)
 {
 	struct request *next;
-	struct hd_struct *hd1, *hd2;
   
 	next = blkdev_next_request(req);
 	if (req->sector + req->nr_sectors != next->sector)
@@ -791,12 +870,8 @@
 
 	/* One last thing: we have removed a request, so we now have one
 	   less expected IO to complete for accounting purposes. */
+	req_merged_io(req);
 
-	locate_hd_struct(req, &hd1, &hd2);
-	if (hd1)
-		down_ios(hd1);
-	if (hd2)	
-		down_ios(hd2);
 	blkdev_release_request(next);
 }
 
@@ -866,9 +941,7 @@
 	 * driver. Create a bounce buffer if the buffer data points into
 	 * high memory - keep the original buffer otherwise.
 	 */
-#if CONFIG_HIGHMEM
-	bh = create_bounce(rw, bh);
-#endif
+	bh = blk_queue_bounce(q, rw, bh);
 
 /* look for a free request. */
 	/*
@@ -900,7 +973,6 @@
 				insert_here = &req->queue;
 				break;
 			}
-			elevator->elevator_merge_cleanup_fn(q, req, count);
 			req->bhtail->b_reqnext = bh;
 			req->bhtail = bh;
 			req->nr_sectors = req->hard_nr_sectors += count;
@@ -915,11 +987,15 @@
 				insert_here = req->queue.prev;
 				break;
 			}
-			elevator->elevator_merge_cleanup_fn(q, req, count);
 			bh->b_reqnext = req->bh;
 			req->bh = bh;
+			/*
+			 * may not be valid, but queues not having bounce
+			 * enabled for highmem pages must not look at
+			 * ->buffer anyway
+			 */
 			req->buffer = bh->b_data;
-			req->current_nr_sectors = count;
+			req->current_nr_sectors = req->hard_cur_sectors = count;
 			req->sector = req->hard_sector = sector;
 			req->nr_sectors = req->hard_nr_sectors += count;
 			blk_started_io(count);
@@ -978,7 +1054,7 @@
 	req->errors = 0;
 	req->hard_sector = req->sector = sector;
 	req->hard_nr_sectors = req->nr_sectors = count;
-	req->current_nr_sectors = count;
+	req->current_nr_sectors = req->hard_cur_sectors = count;
 	req->nr_segments = 1; /* Always 1 for a new request. */
 	req->nr_hw_segments = 1; /* Always 1 for a new request. */
 	req->buffer = bh->b_data;
@@ -1286,6 +1362,7 @@
 			req->nr_sectors = req->hard_nr_sectors;
 
 			req->current_nr_sectors = bh->b_size >> 9;
+			req->hard_cur_sectors = req->current_nr_sectors;
 			if (req->nr_sectors < req->current_nr_sectors) {
 				req->nr_sectors = req->current_nr_sectors;
 				printk("end_request: buffer-list destroyed\n");
@@ -1324,6 +1401,9 @@
 	memset(max_readahead, 0, sizeof(max_readahead));
 	memset(max_sectors, 0, sizeof(max_sectors));
 
+	blk_max_low_pfn = max_low_pfn - 1;
+	blk_max_pfn = max_pfn - 1;
+
 #ifdef CONFIG_AMIGA_Z2RAM
 	z2_init();
 #endif
@@ -1439,5 +1519,9 @@
 EXPORT_SYMBOL(blk_queue_make_request);
 EXPORT_SYMBOL(generic_make_request);
 EXPORT_SYMBOL(blkdev_release_request);
-EXPORT_SYMBOL(req_finished_io);
 EXPORT_SYMBOL(generic_unplug_device);
+EXPORT_SYMBOL(blk_queue_bounce_limit);
+EXPORT_SYMBOL(blk_max_low_pfn);
+EXPORT_SYMBOL(blk_max_pfn);
+EXPORT_SYMBOL(blk_seg_merge_ok);
+EXPORT_SYMBOL(blk_nohighio);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/loop.c linux-2.4.20/drivers/block/loop.c
--- linux-2.4.19/drivers/block/loop.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/block/loop.c	2002-10-29 11:18:48.000000000 +0000
@@ -154,7 +154,7 @@
 
 #define MAX_DISK_SIZE 1024*1024*1024
 
-static unsigned long compute_loop_size(struct loop_device *lo, struct dentry * lo_dentry, kdev_t lodev)
+static int compute_loop_size(struct loop_device *lo, struct dentry * lo_dentry, kdev_t lodev)
 {
 	if (S_ISREG(lo_dentry->d_inode->i_mode))
 		return (lo_dentry->d_inode->i_size - lo->lo_offset) >> BLOCK_SIZE_BITS;
@@ -483,9 +483,7 @@
 		goto err;
 	}
 
-#if CONFIG_HIGHMEM
-	rbh = create_bounce(rw, rbh);
-#endif
+	rbh = blk_queue_bounce(q, rw, rbh);
 
 	/*
 	 * file backed, queue for loop_thread to handle
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/paride/epat.c linux-2.4.20/drivers/block/paride/epat.c
--- linux-2.4.19/drivers/block/paride/epat.c	2001-10-25 07:07:39.000000000 +0000
+++ linux-2.4.20/drivers/block/paride/epat.c	2002-10-29 11:18:48.000000000 +0000
@@ -303,7 +303,6 @@
 static void epat_init_proto( PIA *pi)
 
 {  	MOD_INC_USE_COUNT;
-	printk("epat_init_proto");
 }
 
 static void epat_release_proto( PIA *pi)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/paride/paride.c linux-2.4.20/drivers/block/paride/paride.c
--- linux-2.4.19/drivers/block/paride/paride.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/block/paride/paride.c	2002-10-29 11:18:33.000000000 +0000
@@ -71,7 +71,7 @@
 static void pi_wake_up( void *p)
 
 {       PIA  *pi = (PIA *) p;
-	long flags;
+	unsigned long flags;
 	void (*cont)(void) = NULL;
 
 	spin_lock_irqsave(&pi_spinlock,flags);
@@ -95,7 +95,7 @@
 
 #ifdef CONFIG_PARPORT
 
-{	long flags;
+{	unsigned long flags;
 
 	spin_lock_irqsave(&pi_spinlock,flags); 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/paride/pcd.c linux-2.4.20/drivers/block/paride/pcd.c
--- linux-2.4.19/drivers/block/paride/pcd.c	2001-10-27 09:03:47.000000000 +0000
+++ linux-2.4.20/drivers/block/paride/pcd.c	2002-10-29 11:18:39.000000000 +0000
@@ -810,7 +810,7 @@
 {	int	unit = pcd_unit;
 	int	b, i;
 	char	rd_cmd[12] = {0xa8,0,0,0,0,0,0,0,0,1,0,0};
-	long    saved_flags;
+	unsigned long    saved_flags;
 
 	pcd_bufblk = pcd_sector / 4;
         b = pcd_bufblk;
@@ -839,7 +839,7 @@
 
 
 {	int	unit = pcd_unit;
-	long    saved_flags;
+	unsigned long    saved_flags;
 
 	pcd_busy = 1;
 	pcd_retries = 0;
@@ -859,7 +859,7 @@
 static void do_pcd_read_drq( void )
 
 {	int	unit = pcd_unit;
-	long    saved_flags;
+	unsigned long    saved_flags;
 
 	if (pcd_completion(unit,pcd_buffer,"read block")) {
                 if (pcd_retries < PCD_RETRIES) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/paride/pd.c linux-2.4.20/drivers/block/paride/pd.c
--- linux-2.4.19/drivers/block/paride/pd.c	2001-11-09 21:58:03.000000000 +0000
+++ linux-2.4.20/drivers/block/paride/pd.c	2002-10-29 11:18:49.000000000 +0000
@@ -180,7 +180,8 @@
 
 void pd_setup( char *str, int *ints)
 
-{	generic_setup(pd_stt,7,str);
+{
+	generic_setup(pd_stt,7,str);
 }
 
 #endif
@@ -299,6 +300,7 @@
 	int heads;                	/* physical geometry */
 	int sectors;
 	int cylinders;
+        int can_lba;
 	int drive;			/* master=0 slave=1 */
 	int changed;			/* Have we seen a disk change ? */
 	int removable;			/* removable media device  ?  */
@@ -306,7 +308,7 @@
 	int alt_geom;
 	int present;
 	char name[PD_NAMELEN];		/* pda, pdb, etc ... */
-	};
+};
 
 struct pd_unit pd[PD_UNITS];
 
@@ -656,14 +658,20 @@
 
 /* Don't use this call if the capacity is zero. */
 
-{       int c1, c0, h, s;
-
-        s  = ( block % PD.sectors) + 1;
-        h  = ( block / PD.sectors) % PD.heads;
-        c0 = ( block / (PD.sectors*PD.heads)) % 256;
-        c1 = ( block / (PD.sectors*PD.heads*256));
-
-        pd_send_command(unit,count,s,h,c0,c1,func);
+{
+       int c1, c0, h, s;
+       if (PD.can_lba) {
+               s = block & 255;
+               c0 = (block >>= 8) & 255;
+               c1 = (block >>= 8) & 255;
+               h = ((block >>= 8) & 15) + 0x40;
+       } else {
+               s  = ( block % PD.sectors) + 1;
+               h  = ( block /= PD.sectors) % PD.heads;
+               c0 = ( block /= PD.heads) % 256;
+               c1 = (block >>= 8);
+       }
+       pd_send_command(unit,count,s,h,c0,c1,func);
 }
 
 /* According to the ATA standard, the default CHS geometry should be
@@ -762,10 +770,14 @@
         }
         pi_read_block(PI,pd_scratch,512);
         pi_disconnect(PI);
-        PD.sectors = word_val(6);
-        PD.heads = word_val(3);
-        PD.cylinders  = word_val(1);
-        PD.capacity = PD.sectors*PD.heads*PD.cylinders;
+	PD.can_lba = pd_scratch[99] & 2;
+	PD.sectors = le16_to_cpu(*(u16*)(pd_scratch+12));
+	PD.heads = le16_to_cpu(*(u16*)(pd_scratch+6));
+	PD.cylinders  = le16_to_cpu(*(u16*)(pd_scratch+2));
+	if (PD.can_lba)
+	  PD.capacity = le32_to_cpu(*(u32*)(pd_scratch + 120));
+	else
+	  PD.capacity = PD.sectors*PD.heads*PD.cylinders;
 
         for(j=0;j<PD_ID_LEN;j++) id[j^1] = pd_scratch[j+PD_ID_OFF];
         j = PD_ID_LEN-1;
@@ -888,7 +900,7 @@
 
 static void pd_next_buf( int unit )
 
-{	long	saved_flags;
+{	unsigned long	saved_flags;
 
 	spin_lock_irqsave(&io_request_lock,saved_flags);
 	end_request(1);
@@ -919,7 +931,7 @@
 static void do_pd_read_start( void )
  
 {       int	unit = pd_unit;
-	long    saved_flags;
+	unsigned long    saved_flags;
 
 	pd_busy = 1;
 
@@ -945,7 +957,7 @@
 static void do_pd_read_drq( void )
 
 {       int	unit = pd_unit;
-	long    saved_flags;
+	unsigned long    saved_flags;
 
 	while (1) {
             if (pd_wait_for(unit,STAT_DRQ,"do_pd_read_drq") & STAT_ERR) {
@@ -985,7 +997,7 @@
 static void do_pd_write_start( void )
 
 {       int 	unit = pd_unit;
-	long    saved_flags;
+	unsigned long    saved_flags;
 
 	pd_busy = 1;
 
@@ -1033,7 +1045,7 @@
 static void do_pd_write_done( void )
 
 {       int	unit = pd_unit;
-	long    saved_flags;
+	unsigned long    saved_flags;
 
         if (pd_wait_for(unit,STAT_READY,"do_pd_write_done") & STAT_ERR) {
                 pi_disconnect(PI);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/paride/pf.c linux-2.4.20/drivers/block/paride/pf.c
--- linux-2.4.19/drivers/block/paride/pf.c	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.20/drivers/block/paride/pf.c	2002-10-29 11:18:33.000000000 +0000
@@ -930,7 +930,7 @@
 
 static void pf_next_buf( int unit )
 
-{	long	saved_flags;
+{	unsigned long	saved_flags;
 
 	spin_lock_irqsave(&io_request_lock,saved_flags);
 	end_request(1);
@@ -963,7 +963,7 @@
 static void do_pf_read_start( void )
 
 {       int	unit = pf_unit;
-	long	saved_flags;
+	unsigned long	saved_flags;
 
 	pf_busy = 1;
 
@@ -988,7 +988,7 @@
 static void do_pf_read_drq( void )
 
 {       int	unit = pf_unit;
-	long	saved_flags;
+	unsigned long	saved_flags;
 	
 	while (1) {
             if (pf_wait(unit,STAT_BUSY,STAT_DRQ|STAT_ERR,
@@ -1030,7 +1030,7 @@
 static void do_pf_write_start( void )
 
 {       int	unit = pf_unit;
-	long	saved_flags;
+	unsigned long	saved_flags;
 
 	pf_busy = 1;
 
@@ -1079,7 +1079,7 @@
 static void do_pf_write_done( void )
 
 {       int	unit = pf_unit;
-	long	saved_flags;
+	unsigned long	saved_flags;
 
         if (pf_wait(unit,STAT_BUSY,0,"write block","done") & STAT_ERR) {
                 pi_disconnect(PI);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/paride/pseudo.h linux-2.4.20/drivers/block/paride/pseudo.h
--- linux-2.4.19/drivers/block/paride/pseudo.h	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.20/drivers/block/paride/pseudo.h	2002-10-29 11:18:35.000000000 +0000
@@ -56,7 +56,7 @@
 			 int (*ready)(void),
 			 int timeout, int nice )
 
-{       long	flags;
+{       unsigned long	flags;
 
 	spin_lock_irqsave(&ps_spinlock,flags);
 
@@ -86,7 +86,7 @@
 static void ps_tq_int( void *data )
 
 {       void (*con)(void);
-	long flags;
+	unsigned long flags;
 
 	spin_lock_irqsave(&ps_spinlock,flags);
 
@@ -121,7 +121,7 @@
 static void ps_timer_int( unsigned long data)
 
 {       void (*con)(void);
-	long	flags;
+	unsigned long	flags;
 
 	spin_lock_irqsave(&ps_spinlock,flags);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/ps2esdi.c linux-2.4.20/drivers/block/ps2esdi.c
--- linux-2.4.19/drivers/block/ps2esdi.c	2001-11-09 22:01:21.000000000 +0000
+++ linux-2.4.20/drivers/block/ps2esdi.c	2002-10-29 11:18:31.000000000 +0000
@@ -466,7 +466,6 @@
 	u_int block, count;
 	/* since, this routine is called with interrupts cleared - they 
 	   must be before it finishes  */
-	sti();
 
 #if 0
 	printk("%s:got request. device : %d minor : %d command : %d  sector : %ld count : %ld, buffer: %p\n",
@@ -563,6 +562,7 @@
 
 	u_short track, head, cylinder, sector;
 	u_short cmd_blk[TYPE_1_CMD_BLK_LENGTH];
+	int err;
 
 	/* do some relevant arithmatic */
 	track = block / ps2esdi_info[drive].sect;
@@ -580,9 +580,13 @@
 	     cylinder, head, sector,
 	     CURRENT->current_nr_sectors, drive);
 
+	spin_unlock_irq(&io_request_lock);
 	/* send the command block to the controller */
-	if (ps2esdi_out_cmd_blk(cmd_blk)) {
-		printk("%s: Controller failed\n", DEVICE_NAME);
+	err = ps2esdi_out_cmd_blk(cmd_blk);
+	spin_lock_irq(&io_request_lock);
+	
+	if (err) {
+		printk(KERN_ERR "%s: Controller failed\n", DEVICE_NAME);
 		if ((++CURRENT->errors) >= MAX_RETRIES)
 			end_request(FAIL);
 	}
@@ -1135,9 +1139,7 @@
 	int start = target << ps2esdi_gendisk.minor_shift;
 	int partition;
 
-	cli();
 	ps2esdi_valid[target] = (access_count[target] != 1);
-	sti();
 	if (ps2esdi_valid[target])
 		return (-EBUSY);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/rd.c linux-2.4.20/drivers/block/rd.c
--- linux-2.4.19/drivers/block/rd.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/block/rd.c	2002-10-29 11:18:48.000000000 +0000
@@ -217,7 +217,7 @@
 		bh_kunmap(sbh);
 
 		if (rw == READ) {
-			flush_dcache_page(page);
+			flush_dcache_page(sbh->b_page);
 		} else {
 			SetPageDirty(page);
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/umem.c linux-2.4.20/drivers/block/umem.c
--- linux-2.4.19/drivers/block/umem.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/block/umem.c	2002-10-29 11:18:49.000000000 +0000
@@ -341,9 +341,7 @@
 	offset = ((char*)desc) - ((char*)page->desc);
 	writel(cpu_to_le32((page->page_dma+offset)&0xffffffff),
 	       card->csr_remap + DMA_DESCRIPTOR_ADDR);
-	/* Force the valiue to u64 before shifting otherwise >> 32 is undefined C
-	   and on some ports will do nothing ! */
-	writel(((u64)cpu_to_le32((page->page_dma)>>32)),
+	writel(cpu_to_le32((page->page_dma)>>31>>1),
 	       card->csr_remap + DMA_DESCRIPTOR_ADDR + 4);
 
 	/* Go, go, go */
@@ -1373,8 +1371,7 @@
 	mm_gendisk.part      = mm_partitions;
 	mm_gendisk.nr_real   = num_cards;
 
-	mm_gendisk.next   = gendisk_head;
-	gendisk_head = &mm_gendisk;
+	add_gendisk(&mm_gendisk);
 
 	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR),
 			       mm_make_request);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/xd.c linux-2.4.20/drivers/block/xd.c
--- linux-2.4.19/drivers/block/xd.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/block/xd.c	2002-10-29 11:18:35.000000000 +0000
@@ -144,32 +144,40 @@
 	release:	xd_release,
 	ioctl:		xd_ioctl,
 };
+
 static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int);
 static DECLARE_WAIT_QUEUE_HEAD(xd_wait_open);
-static u_char xd_valid[XD_MAXDRIVES] = { 0,0 };
-static u_char xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors;
-static u_char xd_override __initdata = 0, xd_type __initdata = 0;
-static u_short xd_iobase = 0x320;
+static u8 xd_valid[XD_MAXDRIVES] = { 0,0 };
+static u8 xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors;
+static u8 xd_override __initdata = 0, xd_type __initdata = 0;
+static u16 xd_iobase = 0x320;
 static int xd_geo[XD_MAXDRIVES*3] __initdata = { 0, };
 
 static volatile int xdc_busy;
-static DECLARE_WAIT_QUEUE_HEAD(xdc_wait);
 
-static struct timer_list xd_timer, xd_watchdog_int;
+static struct timer_list xd_watchdog_int;
 
-static volatile u_char xd_error;
+static volatile u8 xd_error;
 static int nodma = XD_DONT_USE_DMA;
 
 static devfs_handle_t devfs_handle = NULL;
 
 /* xd_init: register the block device number and set up pointer tables */
-int __init xd_init (void)
+int __init xd_init(void)
 {
-	init_timer (&xd_timer); xd_timer.function = xd_wakeup;
-	init_timer (&xd_watchdog_int); xd_watchdog_int.function = xd_watchdog;
+	init_timer (&xd_watchdog_int); 
+	xd_watchdog_int.function = xd_watchdog;
+
+	if (!xd_dma_buffer)
+		xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
+	if (!xd_dma_buffer)
+	{
+		printk(KERN_ERR "xd: Out of memory.\n");
+		return -ENOMEM;
+	}
 
 	if (devfs_register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
-		printk("xd: Unable to get major number %d\n",MAJOR_NR);
+		printk(KERN_ERR "xd: Unable to get major number %d\n",MAJOR_NR);
 		return -1;
 	}
 	devfs_handle = devfs_mk_dir (NULL, xd_gendisk.major_name, NULL);
@@ -182,9 +190,10 @@
 }
 
 /* xd_detect: scan the possible BIOS ROM locations for the signature strings */
-static u_char __init xd_detect (u_char *controller, unsigned int *address)
+
+static u8 __init xd_detect (u8 *controller, unsigned int *address)
 {
-	u_char i,j,found = 0;
+	u8 i,j,found = 0;
 
 	if (xd_override)
 	{
@@ -206,32 +215,32 @@
 
 /* xd_geninit: grab the IRQ and DMA channel, initialise the drives */
 /* and set up the "raw" device entries in the table */
+
 static void __init xd_geninit (void)
 {
-	u_char i,controller;
+	u8 i,controller;
 	unsigned int address;
 
-	for(i=0;i<(XD_MAXDRIVES << 6);i++) xd_blocksizes[i] = 1024;
+	for(i=0;i<(XD_MAXDRIVES << 6);i++)
+		xd_blocksizes[i] = 1024;
+		
 	blksize_size[MAJOR_NR] = xd_blocksizes;
 
 	if (xd_detect(&controller,&address)) {
-
-		printk("Detected a%s controller (type %d) at address %06x\n",
+		printk(KERN_INFO "Detected a%s controller (type %d) at address %06x\n",
 			xd_sigs[controller].name,controller,address);
-		if (check_region(xd_iobase,4)) {
-			printk("xd: Ports at 0x%x are not available\n",
-				xd_iobase);
+		if (!request_region(xd_iobase,4, "xd")) {
+			printk(KERN_ERR "xd: Ports at 0x%x are not available\n", xd_iobase);
 			return;
 		}
-		request_region(xd_iobase,4,"xd");
 		if (controller)
 			xd_sigs[controller].init_controller(address);
 		xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
 		
-		printk("Detected %d hard drive%s (using IRQ%d & DMA%d)\n",
+		printk(KERN_INFO "Detected %d hard drive%s (using IRQ%d & DMA%d)\n",
 			xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
 		for (i = 0; i < xd_drives; i++)
-			printk(" xd%c: CHS=%d/%d/%d\n",'a'+i,
+			printk(KERN_INFO " xd%c: CHS=%d/%d/%d\n",'a'+i,
 				xd_info[i].cylinders,xd_info[i].heads,
 				xd_info[i].sectors);
 
@@ -239,12 +248,12 @@
 	if (xd_drives) {
 		if (!request_irq(xd_irq,xd_interrupt_handler, 0, "XT hard disk", NULL)) {
 			if (request_dma(xd_dma,"xd")) {
-				printk("xd: unable to get DMA%d\n",xd_dma);
+				printk(KERN_ERR "xd: unable to get DMA%d\n",xd_dma);
 				free_irq(xd_irq, NULL);
 			}
 		}
 		else
-			printk("xd: unable to get IRQ%d\n",xd_irq);
+			printk(KERN_ERR "xd: unable to get IRQ%d\n",xd_irq);
 	}
 
 	/* xd_maxsectors depends on controller - so set after detection */
@@ -270,9 +279,7 @@
 	if (dev < xd_drives) {
 		while (!xd_valid[dev])
 			sleep_on(&xd_wait_open);
-
 		xd_access[dev]++;
-
 		return (0);
 	}
 
@@ -282,18 +289,16 @@
 /* do_xd_request: handle an incoming request */
 static void do_xd_request (request_queue_t * q)
 {
-	u_int block,count,retry;
+	unsigned int block,count,retry;
 	int code;
 
-	sti();
 	if (xdc_busy)
 		return;
+		
 	while (code = 0, !QUEUE_EMPTY) {
 		INIT_REQUEST;	/* do some checking on the request structure */
 
-		if (CURRENT_DEV < xd_drives
-		    && CURRENT->sector + CURRENT->nr_sectors
-		         <= xd_struct[MINOR(CURRENT->rq_dev)].nr_sects) {
+		if (CURRENT_DEV < xd_drives && CURRENT->sector + CURRENT->nr_sectors <= xd_struct[MINOR(CURRENT->rq_dev)].nr_sects) {
 			block = CURRENT->sector + xd_struct[MINOR(CURRENT->rq_dev)].start_sect;
 			count = CURRENT->nr_sectors;
 
@@ -304,8 +309,7 @@
 						code = xd_readwrite(CURRENT->cmd,CURRENT_DEV,CURRENT->buffer,block,count);
 					break;
 				default:
-					printk("do_xd_request: unknown request\n");
-					break;
+					BUG();
 			}
 		}
 		end_request(code);	/* wrap up, 0 = fail, 1 = success */
@@ -313,7 +317,8 @@
 }
 
 /* xd_ioctl: handle device ioctl's */
-static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
+
+static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
 {
 	int dev;
 
@@ -327,7 +332,6 @@
 		{
 			struct hd_geometry g;
 			struct hd_geometry *geometry = (struct hd_geometry *) arg;
-			if (!geometry) return -EINVAL;
 			g.heads = xd_info[dev].heads;
 			g.sectors = xd_info[dev].sectors;
 			g.cylinders = xd_info[dev].cylinders;
@@ -335,12 +339,23 @@
 			return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0;
 		}
 		case HDIO_SET_DMA:
-			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-			if (xdc_busy) return -EBUSY;
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+			if (xdc_busy)
+				return -EBUSY;
+				
 			nodma = !arg;
+			
 			if (nodma && xd_dma_buffer) {
 				xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200);
 				xd_dma_buffer = 0;
+			} else if (!nodma && !xd_dma_buffer) {
+				xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
+				if (!xd_dma_buffer)
+				{
+					nodma = XD_DONT_USE_DMA;
+					return -ENOMEM;
+				}
 			}
 			return 0;
 		case HDIO_GET_DMA:
@@ -351,7 +366,6 @@
 			if (!capable(CAP_SYS_ADMIN)) 
 				return -EACCES;
 			return xd_reread_partitions(inode->i_rdev);
-
 		case BLKGETSIZE:
 		case BLKGETSIZE64:
 		case BLKFLSBUF:
@@ -361,7 +375,6 @@
 		case BLKRAGET:
 		case BLKPG:
 			return blk_ioctl(inode->i_rdev, cmd, arg);
-
 		default:
 			return -EINVAL;
 	}
@@ -409,21 +422,20 @@
 }
 
 /* xd_readwrite: handle a read/write request */
-static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count)
+static int xd_readwrite (u8 operation,u8 drive,char *buffer,unsigned int block,unsigned int count)
 {
-	u_char cmdblk[6],sense[4];
-	u_short track,cylinder;
-	u_char head,sector,control,mode = PIO_MODE,temp;
+	u8 cmdblk[6],sense[4];
+	u16 track,cylinder;
+	u8 head,sector,control,mode = PIO_MODE,temp;
 	char **real_buffer;
-	register int i;
 	
 #ifdef DEBUG_READWRITE
-	printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
+	printk(KERN_DEBUG "xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
 #endif /* DEBUG_READWRITE */
 
+	spin_unlock_irq(&io_request_lock);
+
 	control = xd_info[drive].control;
-	if (!xd_dma_buffer)
-		xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
 	while (count) {
 		temp = count < xd_maxsectors ? count : xd_maxsectors;
 
@@ -433,28 +445,28 @@
 		sector = block % xd_info[drive].sectors;
 
 #ifdef DEBUG_READWRITE
-		printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
+		printk(KERN_DEBUG "xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
 #endif /* DEBUG_READWRITE */
 
 		if (xd_dma_buffer) {
-			mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)(xd_dma_buffer),temp * 0x200);
+			mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u8 *)(xd_dma_buffer),temp * 0x200);
 			real_buffer = &xd_dma_buffer;
-			for (i=0; i < (temp * 0x200); i++)
-				xd_dma_buffer[i] = buffer[i];
+			memcpy(xd_dma_buffer, buffer, temp * 0x200);
 		}
 		else
 			real_buffer = &buffer;
 
 		xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
 
-		switch (xd_command(cmdblk,mode,(u_char *)(*real_buffer),(u_char *)(*real_buffer),sense,XD_TIMEOUT)) {
+		switch (xd_command(cmdblk,mode,(u8 *)(*real_buffer),(u8 *)(*real_buffer),sense,XD_TIMEOUT)) 
+		{
 			case 1:
-				printk("xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write"));
+				printk(KERN_WARNING "xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write"));
 				xd_recalibrate(drive);
-				return (0);
+				goto fail;
 			case 2:
 				if (sense[0] & 0x30) {
-					printk("xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing"));
+					printk(KERN_ERR "xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing"));
 					switch ((sense[0] & 0x30) >> 4) {
 					case 0: printk("drive error, code = 0x%X",sense[0] & 0x0F);
 						break;
@@ -471,25 +483,30 @@
 				/*	reported drive number = (sense[1] & 0xE0) >> 5 */
 				else
 					printk(" - no valid disk address\n");
-				return (0);
+				goto fail;
 		}
 		if (xd_dma_buffer)
-			for (i=0; i < (temp * 0x200); i++)
-				buffer[i] = xd_dma_buffer[i];
+			memcpy(buffer, xd_dma_buffer, (temp * 0x200));
 
 		count -= temp, buffer += temp * 0x200, block += temp;
 	}
-	return (1);
+	spin_lock_irq(&io_request_lock);
+	return 1;
+
+fail:
+	spin_lock_irq(&io_request_lock);
+	return 0;
+
 }
 
 /* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
-static void xd_recalibrate (u_char drive)
+static void xd_recalibrate (u8 drive)
 {
-	u_char cmdblk[6];
+	u8 cmdblk[6];
 	
 	xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
 	if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8))
-		printk("xd%c: warning! error recalibrating, controller may be unstable\n", 'a'+drive);
+		printk(KERN_WARNING "xd%c: warning! error recalibrating, controller may be unstable\n", 'a'+drive);
 }
 
 /* xd_interrupt_handler: interrupt service routine */
@@ -497,17 +514,17 @@
 {
 	if (inb(XD_STATUS) & STAT_INTERRUPT) {							/* check if it was our device */
 #ifdef DEBUG_OTHER
-		printk("xd_interrupt_handler: interrupt detected\n");
+		printk(KERN_DEBUG "xd_interrupt_handler: interrupt detected\n");
 #endif /* DEBUG_OTHER */
 		outb(0,XD_CONTROL);								/* acknowledge interrupt */
 		wake_up(&xd_wait_int);								/* and wake up sleeping processes */
 	}
 	else
-		printk("xd: unexpected interrupt\n");
+		printk(KERN_DEBUG "xd: unexpected interrupt\n");
 }
 
 /* xd_setup_dma: set up the DMA controller for a data transfer */
-static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
+static u8 xd_setup_dma (u8 mode,u8 *buffer,unsigned int count)
 {
 	unsigned long f;
 	
@@ -515,9 +532,9 @@
 		return (PIO_MODE);
 	if (((unsigned long) buffer & 0xFFFF0000) != (((unsigned long) buffer + count) & 0xFFFF0000)) {
 #ifdef DEBUG_OTHER
-		printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
+		printk(KERN_DEBUG "xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
 #endif /* DEBUG_OTHER */
-		return (PIO_MODE);
+		return PIO_MODE;
 	}
 	
 	f=claim_dma_lock();
@@ -529,11 +546,11 @@
 	
 	release_dma_lock(f);
 
-	return (DMA_MODE);			/* use DMA and INT */
+	return DMA_MODE;			/* use DMA and INT */
 }
 
 /* xd_build: put stuff into an array in a format suitable for the controller */
-static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control)
+static u8 *xd_build (u8 *cmdblk,u8 command,u8 drive,u8 head,u16 cylinder,u8 sector,u8 count,u8 control)
 {
 	cmdblk[0] = command;
 	cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
@@ -542,13 +559,7 @@
 	cmdblk[4] = count;
 	cmdblk[5] = control;
 	
-	return (cmdblk);
-}
-
-/* xd_wakeup is called from timer interrupt */
-static void xd_wakeup (unsigned long unused)
-{
-	wake_up(&xdc_wait);
+	return cmdblk;
 }
 
 /* xd_wakeup is called from timer interrupt */
@@ -559,25 +570,21 @@
 }
 
 /* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
-static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout)
+static inline u8 xd_waitport (u16 port,u8 flags,u8 mask,unsigned long timeout)
 {
-	u_long expiry = jiffies + timeout;
+	unsigned long expiry = jiffies + timeout;
 	int success;
 
 	xdc_busy = 1;
 	while ((success = ((inb(port) & mask) != flags)) && time_before(jiffies, expiry)) {
-		xd_timer.expires = jiffies;
-		cli();
-		add_timer(&xd_timer);
-		sleep_on(&xdc_wait);
-		del_timer(&xd_timer);
-		sti();
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
 	}
 	xdc_busy = 0;
 	return (success);
 }
 
-static inline u_int xd_wait_for_IRQ (void)
+static inline unsigned int xd_wait_for_IRQ (void)
 {
 	unsigned long flags;
 	xd_watchdog_int.expires = jiffies + 8 * HZ;
@@ -588,7 +595,7 @@
 	release_dma_lock(flags);
 	
 	sleep_on(&xd_wait_int);
-	del_timer(&xd_watchdog_int);
+	del_timer_sync(&xd_watchdog_int);
 	xdc_busy = 0;
 	
 	flags=claim_dma_lock();
@@ -596,7 +603,7 @@
 	release_dma_lock(flags);
 	
 	if (xd_error) {
-		printk("xd: missed IRQ - command aborted\n");
+		printk(KERN_DEBUG "xd: missed IRQ - command aborted\n");
 		xd_error = 0;
 		return (1);
 	}
@@ -604,12 +611,13 @@
 }
 
 /* xd_command: handle all data transfers necessary for a single command */
-static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout)
+static unsigned int xd_command (u8 *command,u8 mode,u8 *indata,u8 *outdata,u8 *sense,unsigned long timeout)
 {
-	u_char cmdblk[6],csb,complete = 0;
+	u8 cmdblk[6];
+	u8 csb,complete = 0;
 
 #ifdef DEBUG_COMMAND
-	printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
+	printk(KERN_DEBUG "xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
 #endif /* DEBUG_COMMAND */
 
 	outb(0,XD_SELECT);
@@ -656,55 +664,57 @@
 	if (csb & CSB_ERROR) {									/* read sense data if error */
 		xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
 		if (xd_command(cmdblk,0,sense,0,0,XD_TIMEOUT))
-			printk("xd: warning! sense command failed!\n");
+			printk(KERN_DEBUG "xd: warning! sense command failed!\n");
 	}
 
 #ifdef DEBUG_COMMAND
-	printk("xd_command: completed with csb = 0x%X\n",csb);
+	printk(KERN_DEBUG "xd_command: completed with csb = 0x%X\n",csb);
 #endif /* DEBUG_COMMAND */
 
 	return (csb & CSB_ERROR);
 }
 
-static u_char __init xd_initdrives (void (*init_drive)(u_char drive))
+static u8 __init xd_initdrives (void (*init_drive)(u8 drive))
 {
-	u_char cmdblk[6],i,count = 0;
+	u8 cmdblk[6],i,count = 0;
 
 	for (i = 0; i < XD_MAXDRIVES; i++) {
 		xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
 		if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8)) {
-	 		xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
-			add_timer(&xd_timer);
-			sleep_on(&xdc_wait);
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(XD_INIT_DISK_DELAY);
 
 			init_drive(count);
 			count++;
 
-	 		xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
-			add_timer(&xd_timer);
-			sleep_on(&xdc_wait);
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(XD_INIT_DISK_DELAY);
 		}
 	}
 	return (count);
 }
 
-static void __init xd_manual_geo_set (u_char drive)
+static void __init xd_manual_geo_set (u8 drive)
 {
-	xd_info[drive].heads = (u_char)(xd_geo[3 * drive + 1]);
-	xd_info[drive].cylinders = (u_short)(xd_geo[3 * drive]);
-	xd_info[drive].sectors = (u_char)(xd_geo[3 * drive + 2]);
+	xd_info[drive].heads 	= xd_geo[3 * drive + 1];
+	xd_info[drive].cylinders= xd_geo[3 * drive];
+	xd_info[drive].sectors =  xd_geo[3 * drive + 2];
 }
 
 static void __init xd_dtc_init_controller (unsigned int address)
 {
 	switch (address) {
 		case 0x00000:
-		case 0xC8000:	break;			/*initial: 0x320 */
-		case 0xCA000:	xd_iobase = 0x324; 
-		case 0xD0000:				/*5150CX*/
-		case 0xD8000:	break;			/*5150CX & 5150XL*/
-		default:        printk("xd_dtc_init_controller: unsupported BIOS address %06x\n",address);
-				break;
+		case 0xC8000:
+			break;			/*initial: 0x320 */
+		case 0xCA000:
+			xd_iobase = 0x324; 
+		case 0xD0000:			/*5150CX*/
+		case 0xD8000:
+			break;			/*5150CX & 5150XL*/
+		default:        
+			printk(KERN_ERR "xd_dtc_init_controller: unsupported BIOS address %06x\n",address);
+			break;
 	}
 	xd_maxsectors = 0x01;		/* my card seems to have trouble doing multi-block transfers? */
 
@@ -712,10 +722,10 @@
 }
 
 
-static void __init xd_dtc5150cx_init_drive (u_char drive)
+static void __init xd_dtc5150cx_init_drive (u8 drive)
 {
 	/* values from controller's BIOS - BIOS chip may be removed */
-	static u_short geometry_table[][4] = {
+	static u16 geometry_table[][4] = {
 		{0x200,8,0x200,0x100},
 		{0x267,2,0x267,0x267},
 		{0x264,4,0x264,0x80},
@@ -732,7 +742,7 @@
 		{0x2B9,5,0x2B9,0x2B9},
 		{0x280,6,0x280,0x100},
 		{0x132,4,0x132,0x0}};
-	u_char n;
+	u8 n;
 
 	n = inb(XD_JUMPER);
 	n = (drive ? n : (n >> 2)) & 0x33;
@@ -741,7 +751,7 @@
 		xd_manual_geo_set(drive);
 	else
 		if (n != 7) {	
-			xd_info[drive].heads = (u_char)(geometry_table[n][1]);			/* heads */
+			xd_info[drive].heads = (u8)(geometry_table[n][1]);			/* heads */
 			xd_info[drive].cylinders = geometry_table[n][0];	/* cylinders */
 			xd_info[drive].sectors = 17;				/* sectors */
 #if 0
@@ -751,7 +761,7 @@
 #endif /* 0 */
 		}
 		else {
-			printk("xd%c: undetermined drive geometry\n",'a'+drive);
+			printk(KERN_WARNING "xd%c: undetermined drive geometry\n",'a'+drive);
 			return;
 		}
 	xd_info[drive].control = 5;				/* control byte */
@@ -759,31 +769,31 @@
 	xd_recalibrate(drive);
 }
 
-static void __init xd_dtc_init_drive (u_char drive)
+static void __init xd_dtc_init_drive (u8 drive)
 {
-	u_char cmdblk[6],buf[64];
+	u8 cmdblk[6],buf[64];
 
 	xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0);
 	if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 		xd_info[drive].heads = buf[0x0A];			/* heads */
-		xd_info[drive].cylinders = ((u_short *) (buf))[0x04];	/* cylinders */
+		xd_info[drive].cylinders = ((u16 *) (buf))[0x04];	/* cylinders */
 		xd_info[drive].sectors = 17;				/* sectors */
 		if (xd_geo[3*drive])
 			xd_manual_geo_set(drive);
 #if 0
-		xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05];	/* reduced write */
-		xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06];	/* write precomp */
+		xd_info[drive].rwrite = ((u16 *) (buf + 1))[0x05];	/* reduced write */
+		xd_info[drive].precomp = ((u16 *) (buf + 1))[0x06];	/* write precomp */
 		xd_info[drive].ecc = buf[0x0F];				/* ecc length */
 #endif /* 0 */
 		xd_info[drive].control = 0;				/* control byte */
 
-		xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf + 1))[0x05],((u_short *) (buf + 1))[0x06],buf[0x0F]);
+		xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u16 *) (buf + 1))[0x05],((u16 *) (buf + 1))[0x06],buf[0x0F]);
 		xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
 		if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
-			printk("xd_dtc_init_drive: error setting step rate for xd%c\n", 'a'+drive);
+			printk(KERN_WARNING "xd_dtc_init_drive: error setting step rate for xd%c\n", 'a'+drive);
 	}
 	else
-		printk("xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive);
+		printk(KERN_WARNING "xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive);
 }
 
 static void __init xd_wd_init_controller (unsigned int address)
@@ -796,22 +806,21 @@
 		case 0xCE000:   xd_iobase = 0x32C; break;
 		case 0xD0000:	xd_iobase = 0x328; break; /* ? */
 		case 0xD8000:	xd_iobase = 0x32C; break; /* ? */
-		default:        printk("xd_wd_init_controller: unsupported BIOS address %06x\n",address);
+		default:        printk(KERN_ERR "xd_wd_init_controller: unsupported BIOS address %06x\n",address);
 				break;
 	}
 	xd_maxsectors = 0x01;		/* this one doesn't wrap properly either... */
 
 	outb(0,XD_RESET);		/* reset the controller */
 
-	xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
-	add_timer(&xd_timer);
-	sleep_on(&xdc_wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(XD_INIT_DISK_DELAY);
 }
 
-static void __init xd_wd_init_drive (u_char drive)
+static void __init xd_wd_init_drive (u8 drive)
 {
 	/* values from controller's BIOS - BIOS may be disabled */
-	static u_short geometry_table[][4] = {
+	static u16 geometry_table[][4] = {
 		{0x264,4,0x1C2,0x1C2},   /* common part */
 		{0x132,4,0x099,0x0},
 		{0x267,2,0x1C2,0x1C2},
@@ -827,9 +836,9 @@
 		{0x264,4,0x265,0x265},
 		{0x267,4,0x268,0x268}};
 
-	u_char cmdblk[6],buf[0x200];
-	u_char n = 0,rll,jumper_state,use_jumper_geo;
-	u_char wd_1002 = (xd_sigs[xd_type].string[7] == '6');
+	u8 cmdblk[6],buf[0x200];
+	u8 n = 0,rll,jumper_state,use_jumper_geo;
+	u8 wd_1002 = (xd_sigs[xd_type].string[7] == '6');
 	
 	jumper_state = ~(inb(0x322));
 	if (jumper_state & 0x40)
@@ -838,13 +847,13 @@
 	xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
 	if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 		xd_info[drive].heads = buf[0x1AF];				/* heads */
-		xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6];	/* cylinders */
+		xd_info[drive].cylinders = ((u16 *) (buf + 1))[0xD6];	/* cylinders */
 		xd_info[drive].sectors = 17;					/* sectors */
 		if (xd_geo[3*drive])
 			xd_manual_geo_set(drive);
 #if 0
-		xd_info[drive].rwrite = ((u_short *) (buf))[0xD8];		/* reduced write */
-		xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA];		/* write precomp */
+		xd_info[drive].rwrite = ((u16 *) (buf))[0xD8];		/* reduced write */
+		xd_info[drive].wprecomp = ((u16 *) (buf))[0xDA];		/* write precomp */
 		xd_info[drive].ecc = buf[0x1B4];				/* ecc length */
 #endif /* 0 */
 		xd_info[drive].control = buf[0x1B5];				/* control byte */
@@ -856,7 +865,7 @@
 		else if (use_jumper_geo) {
 			n = (((jumper_state & 0x0F) >> (drive << 1)) & 0x03) | rll;
 			xd_info[drive].cylinders = geometry_table[n][0];
-			xd_info[drive].heads = (u_char)(geometry_table[n][1]);
+			xd_info[drive].heads = (u8)(geometry_table[n][1]);
 			xd_info[drive].control = rll ? 7 : 5;
 #if 0
 			xd_info[drive].rwrite = geometry_table[n][2];
@@ -870,7 +879,7 @@
 					geometry_table[n][2],geometry_table[n][3],0x0B);
 			else
 				xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
-					((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
+					((u16 *) (buf))[0xD8],((u16 *) (buf))[0xDA],buf[0x1B4]);
 		}
 	/* 1002 based RLL controller requests converted addressing, but reports physical 
 	   (physical 26 sec., logical 17 sec.) 
@@ -888,7 +897,7 @@
 		}
 	}
 	else
-		printk("xd_wd_init_drive: error reading geometry for xd%c\n",'a'+drive);	
+		printk(KERN_WARNING "xd_wd_init_drive: error reading geometry for xd%c\n",'a'+drive);	
 
 }
 
@@ -900,7 +909,7 @@
 		case 0xD0000:	xd_iobase = 0x324; break;
 		case 0xD8000:	xd_iobase = 0x328; break;
 		case 0xE0000:	xd_iobase = 0x32C; break;
-		default:	printk("xd_seagate_init_controller: unsupported BIOS address %06x\n",address);
+		default:	printk(KERN_ERR "xd_seagate_init_controller: unsupported BIOS address %06x\n",address);
 				break;
 	}
 	xd_maxsectors = 0x40;
@@ -908,9 +917,9 @@
 	outb(0,XD_RESET);		/* reset the controller */
 }
 
-static void __init xd_seagate_init_drive (u_char drive)
+static void __init xd_seagate_init_drive (u8 drive)
 {
-	u_char cmdblk[6],buf[0x200];
+	u8 cmdblk[6],buf[0x200];
 
 	xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0);
 	if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
@@ -920,7 +929,7 @@
 		xd_info[drive].control = 0;					/* control byte */
 	}
 	else
-		printk("xd_seagate_init_drive: error reading geometry from xd%c\n", 'a'+drive);
+		printk(KERN_WARNING "xd_seagate_init_drive: error reading geometry from xd%c\n", 'a'+drive);
 }
 
 /* Omti support courtesy Dirk Melchers */
@@ -932,7 +941,7 @@
 		case 0xD0000:	xd_iobase = 0x324; break;
 		case 0xD8000:	xd_iobase = 0x328; break;
 		case 0xE0000:	xd_iobase = 0x32C; break;
-		default:	printk("xd_omti_init_controller: unsupported BIOS address %06x\n",address);
+		default:	printk(KERN_ERR "xd_omti_init_controller: unsupported BIOS address %06x\n",address);
 				break;
 	}
 	
@@ -941,7 +950,7 @@
 	outb(0,XD_RESET);		/* reset the controller */
 }
 
-static void __init xd_omti_init_drive (u_char drive)
+static void __init xd_omti_init_drive (u8 drive)
 {
 	/* gets infos from drive */
 	xd_override_init_drive(drive);
@@ -972,22 +981,21 @@
 		case 0xDC000:
 		case 0xDE000:
 		case 0xE0000:	break;
-		default:	printk("xd_xebec_init_controller: unsupported BIOS address %06x\n",address);
+		default:	printk(KERN_ERR "xd_xebec_init_controller: unsupported BIOS address %06x\n",address);
 				break;
 		}
 
 	xd_maxsectors = 0x01;
 	outb(0,XD_RESET);		/* reset the controller */
 
-	xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
-	add_timer(&xd_timer);
-	sleep_on(&xdc_wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(XD_INIT_DISK_DELAY);
 }
 
-static void __init xd_xebec_init_drive (u_char drive)
+static void __init xd_xebec_init_drive (u8 drive)
 {
 	/* values from controller's BIOS - BIOS chip may be removed */
-	static u_short geometry_table[][5] = {
+	static u16 geometry_table[][5] = {
 		{0x132,4,0x080,0x080,0x7},
 		{0x132,4,0x080,0x080,0x17},
 		{0x264,2,0x100,0x100,0x7},
@@ -1004,14 +1012,14 @@
 		{0x400,6,0x400,0x400,0x7},
 		{0x264,8,0x264,0x200,0x17},
 		{0x33E,7,0x33E,0x200,0x7}};
-	u_char n;
+	u8 n;
 
 	n = inb(XD_JUMPER) & 0x0F; /* BIOS's drive number: same geometry 
 					is assumed for BOTH drives */
 	if (xd_geo[3*drive])
 		xd_manual_geo_set(drive);
 	else {
-		xd_info[drive].heads = (u_char)(geometry_table[n][1]);			/* heads */
+		xd_info[drive].heads = (u8)(geometry_table[n][1]);			/* heads */
 		xd_info[drive].cylinders = geometry_table[n][0];	/* cylinders */
 		xd_info[drive].sectors = 17;				/* sectors */
 #if 0
@@ -1027,10 +1035,10 @@
 
 /* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
    etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
-static void __init xd_override_init_drive (u_char drive)
+static void __init xd_override_init_drive (u8 drive)
 {
-	u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
-	u_char cmdblk[6],i;
+	u16 min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
+	u8 cmdblk[6],i;
 
 	if (xd_geo[3*drive])
 		xd_manual_geo_set(drive);
@@ -1038,7 +1046,7 @@
 		for (i = 0; i < 3; i++) {
 			while (min[i] != max[i] - 1) {
 				test[i] = (min[i] + max[i]) / 2;
-				xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
+				xd_build(cmdblk,CMD_SEEK,drive,(u8) test[0],(u16) test[1],(u8) test[2],0,0);
 				if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
 					min[i] = test[i];
 				else
@@ -1046,9 +1054,9 @@
 			}
 			test[i] = min[i];
 		}
-		xd_info[drive].heads = (u_char) min[0] + 1;
-		xd_info[drive].cylinders = (u_short) min[1] + 1;
-		xd_info[drive].sectors = (u_char) min[2] + 1;
+		xd_info[drive].heads = (u8) min[0] + 1;
+		xd_info[drive].cylinders = (u16) min[1] + 1;
+		xd_info[drive].sectors = (u8) min[2] + 1;
 	}
 	xd_info[drive].control = 0;
 }
@@ -1069,30 +1077,30 @@
 			if ((integers[1] >= 0) && (integers[1] < (sizeof(xd_sigs) / sizeof(xd_sigs[0]))))
 				xd_type = integers[1];
 		case 0: break;
-		default:printk("xd: too many parameters for xd\n");
+		default:printk(KERN_ERR "xd: too many parameters for xd\n");
 	}
 	xd_maxsectors = 0x01;
 }
 
 /* xd_setparam: set the drive characteristics */
-static void __init xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
+static void __init xd_setparam (u8 command,u8 drive,u8 heads,u16 cylinders,u16 rwrite,u16 wprecomp,u8 ecc)
 {
-	u_char cmdblk[14];
+	u8 cmdblk[14];
 
 	xd_build(cmdblk,command,drive,0,0,0,0,0);
-	cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
-	cmdblk[7] = (u_char) (cylinders & 0xFF);
+	cmdblk[6] = (u8) (cylinders >> 8) & 0x03;
+	cmdblk[7] = (u8) (cylinders & 0xFF);
 	cmdblk[8] = heads & 0x1F;
-	cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
-	cmdblk[10] = (u_char) (rwrite & 0xFF);
-	cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
-	cmdblk[12] = (u_char) (wprecomp & 0xFF);
+	cmdblk[9] = (u8) (rwrite >> 8) & 0x03;
+	cmdblk[10] = (u8) (rwrite & 0xFF);
+	cmdblk[11] = (u8) (wprecomp >> 8) & 0x03;
+	cmdblk[12] = (u8) (wprecomp & 0xFF);
 	cmdblk[13] = ecc;
 
 	/* Some controllers require geometry info as data, not command */
 
 	if (xd_command(cmdblk,PIO_MODE,0,&cmdblk[6],0,XD_TIMEOUT * 2))
-		printk("xd: error setting characteristics for xd%c\n", 'a'+drive);
+		printk(KERN_WARNING "xd: error setting characteristics for xd%c\n", 'a'+drive);
 }
 
 
@@ -1145,7 +1153,7 @@
 {
 	devfs_unregister_blkdev(MAJOR_NR, "xd");
 	xd_done();
-	devfs_unregister (devfs_handle);
+	devfs_unregister(devfs_handle);
 	if (xd_drives) {
 		free_irq(xd_irq, NULL);
 		free_dma(xd_dma);
@@ -1171,7 +1179,7 @@
 
 	get_options (str, ARRAY_SIZE (integers), integers);
 	if (integers[0]%3 != 0) {
-		printk("xd: incorrect number of parameters for xd_geo\n");
+		printk(KERN_ERR "xd: incorrect number of parameters for xd_geo\n");
 		return 1;
 	}
 	for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/block/xd.h linux-2.4.20/drivers/block/xd.h
--- linux-2.4.19/drivers/block/xd.h	2000-08-09 20:49:29.000000000 +0000
+++ linux-2.4.20/drivers/block/xd.h	2002-10-29 11:18:35.000000000 +0000
@@ -80,10 +80,10 @@
 
 /* this structure defines the XT drives and their types */
 typedef struct {
-	u_char heads;
-	u_short cylinders;
-	u_char sectors;
-	u_char control;
+	u8 heads;
+	u16 cylinders;
+	u8 sectors;
+	u8 control;
 } XD_INFO;
 
 /* this structure is returned to the HDIO_GETGEO ioctl */
@@ -99,15 +99,15 @@
 	unsigned int offset;
 	const char *string;
 	void (*init_controller)(unsigned int address);
-	void (*init_drive)(u_char drive);
+	void (*init_drive)(u8 drive);
 	const char *name;
 } XD_SIGNATURE;
 
 #ifndef MODULE
 static int xd_manual_geo_init (char *command);
 #endif /* MODULE */
-static u_char xd_detect (u_char *controller, unsigned int *address);
-static u_char xd_initdrives (void (*init_drive)(u_char drive));
+static u8 xd_detect (u8 *controller, unsigned int *address);
+static u8 xd_initdrives (void (*init_drive)(u8 drive));
 static void xd_geninit (void);
 
 static int xd_open (struct inode *inode,struct file *file);
@@ -115,30 +115,29 @@
 static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg);
 static int xd_release (struct inode *inode,struct file *file);
 static int xd_reread_partitions (kdev_t dev);
-static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count);
-static void xd_recalibrate (u_char drive);
+static int xd_readwrite (u8 operation,u8 drive,char *buffer,u_int block,u_int count);
+static void xd_recalibrate (u8 drive);
 
 static void xd_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
-static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count);
-static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control);
-static void xd_wakeup (unsigned long unused);
+static u8 xd_setup_dma (u8 opcode,u8 *buffer,u_int count);
+static u8 *xd_build (u8 *cmdblk,u8 command,u8 drive,u8 head,u16 cylinder,u8 sector,u8 count,u8 control);
 static void xd_watchdog (unsigned long unused);
-static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout);
-static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout);
+static inline u8 xd_waitport (u16 port,u8 flags,u8 mask,unsigned long timeout);
+static u_int xd_command (u8 *command,u8 mode,u8 *indata,u8 *outdata,u8 *sense,unsigned long timeout);
 
 /* card specific setup and geometry gathering code */
 static void xd_dtc_init_controller (unsigned int address);
-static void xd_dtc5150cx_init_drive (u_char drive);
-static void xd_dtc_init_drive (u_char drive);
+static void xd_dtc5150cx_init_drive (u8 drive);
+static void xd_dtc_init_drive (u8 drive);
 static void xd_wd_init_controller (unsigned int address);
-static void xd_wd_init_drive (u_char drive);
+static void xd_wd_init_drive (u8 drive);
 static void xd_seagate_init_controller (unsigned int address);
-static void xd_seagate_init_drive (u_char drive);
+static void xd_seagate_init_drive (u8 drive);
 static void xd_omti_init_controller (unsigned int address);
-static void xd_omti_init_drive (u_char drive);
+static void xd_omti_init_drive (u8 drive);
 static void xd_xebec_init_controller (unsigned int address);
-static void xd_xebec_init_drive (u_char drive);
-static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc);
-static void xd_override_init_drive (u_char drive);
+static void xd_xebec_init_drive (u8 drive);
+static void xd_setparam (u8 command,u8 drive,u8 heads,u16 cylinders,u16 rwrite,u16 wprecomp,u8 ecc);
+static void xd_override_init_drive (u8 drive);
 
 #endif /* _LINUX_XD_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/bluetooth/Config.in linux-2.4.20/drivers/bluetooth/Config.in
--- linux-2.4.19/drivers/bluetooth/Config.in	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/bluetooth/Config.in	2002-10-29 11:18:31.000000000 +0000
@@ -3,7 +3,6 @@
 
 dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB
 if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then
-   bool '  Firmware download support'  CONFIG_BLUEZ_USB_FW_LOAD
    bool '  USB zero packet support'  CONFIG_BLUEZ_USB_ZERO_PACKET
 fi
 
@@ -14,6 +13,10 @@
 
 dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
 
+dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ
+
+dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ
+
 dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
 
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/bluetooth/Makefile linux-2.4.20/drivers/bluetooth/Makefile
--- linux-2.4.19/drivers/bluetooth/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/bluetooth/Makefile	2002-10-29 11:18:50.000000000 +0000
@@ -14,6 +14,8 @@
 uart-$(CONFIG_BLUEZ_HCIUART_H4)	+= hci_h4.o
 
 obj-$(CONFIG_BLUEZ_HCIDTL1)	+= dtl1_cs.o
+obj-$(CONFIG_BLUEZ_HCIBT3C)	+= bt3c_cs.o
+obj-$(CONFIG_BLUEZ_HCIBLUECARD)	+= bluecard_cs.o
 
 include $(TOPDIR)/Rules.make
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/bluetooth/bluecard_cs.c linux-2.4.20/drivers/bluetooth/bluecard_cs.c
--- linux-2.4.19/drivers/bluetooth/bluecard_cs.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/bluetooth/bluecard_cs.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,1113 @@
+/*
+ *
+ *  Bluetooth driver for the Anycom BlueCard (LSE039/LSE041)
+ *
+ *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS
+ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ *  implied. See the License for the specific language governing
+ *  rights and limitations under the License.
+ *
+ *  The initial developer of the original code is David A. Hinds
+ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <asm/io.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+
+
+/* ======================== Module parameters ======================== */
+
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0x86bc;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("BlueZ driver for the Anycom BlueCard (LSE039/LSE041)");
+MODULE_LICENSE("GPL");
+
+
+
+/* ======================== Local structures ======================== */
+
+
+typedef struct bluecard_info_t {
+	dev_link_t link;
+	dev_node_t node;
+
+	struct hci_dev hdev;
+
+	spinlock_t lock;		/* For serializing operations */
+	struct timer_list timer;	/* For LED control */
+
+	struct sk_buff_head txq;
+	unsigned long tx_state;
+
+	unsigned long rx_state;
+	unsigned long rx_count;
+	struct sk_buff *rx_skb;
+
+	unsigned char ctrl_reg;
+	unsigned long hw_state;		/* Status of the hardware and LED control */
+} bluecard_info_t;
+
+
+void bluecard_config(dev_link_t *link);
+void bluecard_release(u_long arg);
+int bluecard_event(event_t event, int priority, event_callback_args_t *args);
+
+static dev_info_t dev_info = "bluecard_cs";
+
+dev_link_t *bluecard_attach(void);
+void bluecard_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+
+/* Default baud rate: 57600, 115200, 230400 or 460800 */
+#define DEFAULT_BAUD_RATE  230400
+
+
+/* Hardware states */
+#define CARD_READY             1
+#define CARD_HAS_PCCARD_ID     4
+#define CARD_HAS_POWER_LED     5
+#define CARD_HAS_ACTIVITY_LED  6
+
+/* Transmit states  */
+#define XMIT_SENDING         1
+#define XMIT_WAKEUP          2
+#define XMIT_BUFFER_NUMBER   5	/* unset = buffer one, set = buffer two */
+#define XMIT_BUF_ONE_READY   6
+#define XMIT_BUF_TWO_READY   7
+#define XMIT_SENDING_READY   8
+
+/* Receiver states */
+#define RECV_WAIT_PACKET_TYPE   0
+#define RECV_WAIT_EVENT_HEADER  1
+#define RECV_WAIT_ACL_HEADER    2
+#define RECV_WAIT_SCO_HEADER    3
+#define RECV_WAIT_DATA          4
+
+/* Special packet types */
+#define PKT_BAUD_RATE_57600   0x80
+#define PKT_BAUD_RATE_115200  0x81
+#define PKT_BAUD_RATE_230400  0x82
+#define PKT_BAUD_RATE_460800  0x83
+
+
+/* These are the register offsets */
+#define REG_COMMAND     0x20
+#define REG_INTERRUPT   0x21
+#define REG_CONTROL     0x22
+#define REG_RX_CONTROL  0x24
+#define REG_CARD_RESET  0x30
+#define REG_LED_CTRL    0x30
+
+/* REG_COMMAND */
+#define REG_COMMAND_TX_BUF_ONE  0x01
+#define REG_COMMAND_TX_BUF_TWO  0x02
+#define REG_COMMAND_RX_BUF_ONE  0x04
+#define REG_COMMAND_RX_BUF_TWO  0x08
+#define REG_COMMAND_RX_WIN_ONE  0x00
+#define REG_COMMAND_RX_WIN_TWO  0x10
+
+/* REG_CONTROL */
+#define REG_CONTROL_BAUD_RATE_57600   0x00
+#define REG_CONTROL_BAUD_RATE_115200  0x01
+#define REG_CONTROL_BAUD_RATE_230400  0x02
+#define REG_CONTROL_BAUD_RATE_460800  0x03
+#define REG_CONTROL_RTS               0x04
+#define REG_CONTROL_BT_ON             0x08
+#define REG_CONTROL_BT_RESET          0x10
+#define REG_CONTROL_BT_RES_PU         0x20
+#define REG_CONTROL_INTERRUPT         0x40
+#define REG_CONTROL_CARD_RESET        0x80
+
+/* REG_RX_CONTROL */
+#define RTS_LEVEL_SHIFT_BITS  0x02
+
+
+
+/* ======================== LED handling routines ======================== */
+
+
+void bluecard_activity_led_timeout(u_long arg)
+{
+	bluecard_info_t *info = (bluecard_info_t *)arg;
+	unsigned int iobase = info->link.io.BasePort1;
+
+	if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) {
+		/* Disable activity LED */
+		outb(0x08 | 0x20, iobase + 0x30);
+	} else {
+		/* Disable power LED */
+		outb(0x00, iobase + 0x30);
+	}
+}
+
+
+static void bluecard_enable_activity_led(bluecard_info_t *info)
+{
+	unsigned int iobase = info->link.io.BasePort1;
+
+	if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) {
+		/* Enable activity LED */
+		outb(0x10 | 0x40, iobase + 0x30);
+
+		/* Stop the LED after HZ/4 */
+		mod_timer(&(info->timer), jiffies + HZ / 4);
+	} else {
+		/* Enable power LED */
+		outb(0x08 | 0x20, iobase + 0x30);
+
+		/* Stop the LED after HZ/2 */
+		mod_timer(&(info->timer), jiffies + HZ / 2);
+	}
+}
+
+
+
+/* ======================== Interrupt handling ======================== */
+
+
+static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, int len)
+{
+	int i, actual;
+
+	actual = (len > 15) ? 15 : len;
+
+	outb_p(actual, iobase + offset);
+
+	for (i = 0; i < actual; i++)
+		outb_p(buf[i], iobase + offset + i + 1);
+
+	return actual;
+}
+
+
+static void bluecard_write_wakeup(bluecard_info_t *info)
+{
+	if (!info) {
+		printk(KERN_WARNING "bluecard_cs: Call of write_wakeup for unknown device.\n");
+		return;
+	}
+
+	if (!test_bit(XMIT_SENDING_READY, &(info->tx_state)))
+		return;
+
+	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
+		set_bit(XMIT_WAKEUP, &(info->tx_state));
+		return;
+	}
+
+	do {
+		register unsigned int iobase = info->link.io.BasePort1;
+		register unsigned int offset;
+		register unsigned char command;
+		register unsigned long ready_bit;
+		register struct sk_buff *skb;
+		register int len;
+
+		clear_bit(XMIT_WAKEUP, &(info->tx_state));
+
+		if (!(info->link.state & DEV_PRESENT))
+			return;
+
+		if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) {
+			if (!test_bit(XMIT_BUF_TWO_READY, &(info->tx_state)))
+				break;
+			offset = 0x10;
+			command = REG_COMMAND_TX_BUF_TWO;
+			ready_bit = XMIT_BUF_TWO_READY;
+		} else {
+			if (!test_bit(XMIT_BUF_ONE_READY, &(info->tx_state)))
+				break;
+			offset = 0x00;
+			command = REG_COMMAND_TX_BUF_ONE;
+			ready_bit = XMIT_BUF_ONE_READY;
+		}
+
+		if (!(skb = skb_dequeue(&(info->txq))))
+			break;
+
+		if (skb->pkt_type & 0x80) {
+			/* Disable RTS */
+			info->ctrl_reg |= REG_CONTROL_RTS;
+			outb(info->ctrl_reg, iobase + REG_CONTROL);
+		}
+
+		/* Activate LED */
+		bluecard_enable_activity_led(info);
+
+		/* Send frame */
+		len = bluecard_write(iobase, offset, skb->data, skb->len);
+
+		/* Tell the FPGA to send the data */
+		outb_p(command, iobase + REG_COMMAND);
+
+		/* Mark the buffer as dirty */
+		clear_bit(ready_bit, &(info->tx_state));
+
+		if (skb->pkt_type & 0x80) {
+
+			wait_queue_head_t wait;
+			unsigned char baud_reg;
+
+			switch (skb->pkt_type) {
+			case PKT_BAUD_RATE_460800:
+				baud_reg = REG_CONTROL_BAUD_RATE_460800;
+				break;
+			case PKT_BAUD_RATE_230400:
+				baud_reg = REG_CONTROL_BAUD_RATE_230400;
+				break;
+			case PKT_BAUD_RATE_115200:
+				baud_reg = REG_CONTROL_BAUD_RATE_115200;
+				break;
+			case PKT_BAUD_RATE_57600:
+				/* Fall through... */
+			default:
+				baud_reg = REG_CONTROL_BAUD_RATE_57600;
+				break;
+			}
+
+			/* Wait until the command reaches the baseband */
+			init_waitqueue_head(&wait);
+			interruptible_sleep_on_timeout(&wait, HZ / 10);
+
+			/* Set baud on baseband */
+			info->ctrl_reg &= ~0x03;
+			info->ctrl_reg |= baud_reg;
+			outb(info->ctrl_reg, iobase + REG_CONTROL);
+
+			/* Enable RTS */
+			info->ctrl_reg &= ~REG_CONTROL_RTS;
+			outb(info->ctrl_reg, iobase + REG_CONTROL);
+
+			/* Wait before the next HCI packet can be send */
+			interruptible_sleep_on_timeout(&wait, HZ);
+
+		}
+
+		if (len == skb->len) {
+			kfree_skb(skb);
+		} else {
+			skb_pull(skb, len);
+			skb_queue_head(&(info->txq), skb);
+		}
+
+		info->hdev.stat.byte_tx += len;
+
+		/* Change buffer */
+		change_bit(XMIT_BUFFER_NUMBER, &(info->tx_state));
+
+	} while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
+
+	clear_bit(XMIT_SENDING, &(info->tx_state));
+}
+
+
+static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, int size)
+{
+	int i, n, len;
+
+	outb(REG_COMMAND_RX_WIN_ONE, iobase + REG_COMMAND);
+
+	len = inb(iobase + offset);
+	n = 0;
+	i = 1;
+
+	while (n < len) {
+
+		if (i == 16) {
+			outb(REG_COMMAND_RX_WIN_TWO, iobase + REG_COMMAND);
+			i = 0;
+		}
+
+		buf[n] = inb(iobase + offset + i);
+
+		n++;
+		i++;
+
+	}
+
+	return len;
+}
+
+
+static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
+{
+	unsigned int iobase;
+	unsigned char buf[31];
+	int i, len;
+
+	if (!info) {
+		printk(KERN_WARNING "bluecard_cs: Call of receive for unknown device.\n");
+		return;
+	}
+
+	iobase = info->link.io.BasePort1;
+
+	if (test_bit(XMIT_SENDING_READY, &(info->tx_state)))
+		bluecard_enable_activity_led(info);
+
+	len = bluecard_read(iobase, offset, buf, sizeof(buf));
+
+	for (i = 0; i < len; i++) {
+
+		/* Allocate packet */
+		if (info->rx_skb == NULL) {
+			info->rx_state = RECV_WAIT_PACKET_TYPE;
+			info->rx_count = 0;
+			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+				printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
+				return;
+			}
+		}
+
+		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
+
+			info->rx_skb->dev = (void *)&(info->hdev);
+			info->rx_skb->pkt_type = buf[i];
+
+			switch (info->rx_skb->pkt_type) {
+
+			case 0x00:
+				/* init packet */
+				if (offset != 0x00) {
+					set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
+					set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
+					set_bit(XMIT_SENDING_READY, &(info->tx_state));
+					bluecard_write_wakeup(info);
+				}
+
+				kfree_skb(info->rx_skb);
+				info->rx_skb = NULL;
+				break;
+
+			case HCI_EVENT_PKT:
+				info->rx_state = RECV_WAIT_EVENT_HEADER;
+				info->rx_count = HCI_EVENT_HDR_SIZE;
+				break;
+
+			case HCI_ACLDATA_PKT:
+				info->rx_state = RECV_WAIT_ACL_HEADER;
+				info->rx_count = HCI_ACL_HDR_SIZE;
+				break;
+
+			case HCI_SCODATA_PKT:
+				info->rx_state = RECV_WAIT_SCO_HEADER;
+				info->rx_count = HCI_SCO_HDR_SIZE;
+				break;
+
+			default:
+				/* unknown packet */
+				printk(KERN_WARNING "bluecard_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
+				info->hdev.stat.err_rx++;
+
+				kfree_skb(info->rx_skb);
+				info->rx_skb = NULL;
+				break;
+
+			}
+
+		} else {
+
+			*skb_put(info->rx_skb, 1) = buf[i];
+			info->rx_count--;
+
+			if (info->rx_count == 0) {
+
+				int dlen;
+				hci_event_hdr *eh;
+				hci_acl_hdr *ah;
+				hci_sco_hdr *sh;
+
+				switch (info->rx_state) {
+
+				case RECV_WAIT_EVENT_HEADER:
+					eh = (hci_event_hdr *)(info->rx_skb->data);
+					info->rx_state = RECV_WAIT_DATA;
+					info->rx_count = eh->plen;
+					break;
+
+				case RECV_WAIT_ACL_HEADER:
+					ah = (hci_acl_hdr *)(info->rx_skb->data);
+					dlen = __le16_to_cpu(ah->dlen);
+					info->rx_state = RECV_WAIT_DATA;
+					info->rx_count = dlen;
+					break;
+
+				case RECV_WAIT_SCO_HEADER:
+					sh = (hci_sco_hdr *)(info->rx_skb->data);
+					info->rx_state = RECV_WAIT_DATA;
+					info->rx_count = sh->dlen;
+					break;
+
+				case RECV_WAIT_DATA:
+					hci_recv_frame(info->rx_skb);
+					info->rx_skb = NULL;
+					break;
+
+				}
+
+			}
+
+		}
+
+
+	}
+
+	info->hdev.stat.byte_rx += len;
+}
+
+
+void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
+{
+	bluecard_info_t *info = dev_inst;
+	unsigned int iobase;
+	unsigned char reg;
+
+	if (!info) {
+		printk(KERN_WARNING "bluecard_cs: Call of irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	if (!test_bit(CARD_READY, &(info->hw_state)))
+		return;
+
+	iobase = info->link.io.BasePort1;
+
+	spin_lock(&(info->lock));
+
+	/* Disable interrupt */
+	info->ctrl_reg &= ~REG_CONTROL_INTERRUPT;
+	outb(info->ctrl_reg, iobase + REG_CONTROL);
+
+	reg = inb(iobase + REG_INTERRUPT);
+
+	if ((reg != 0x00) && (reg != 0xff)) {
+
+		if (reg & 0x04) {
+			bluecard_receive(info, 0x00);
+			outb(0x04, iobase + REG_INTERRUPT);
+			outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND);
+		}
+
+		if (reg & 0x08) {
+			bluecard_receive(info, 0x10);
+			outb(0x08, iobase + REG_INTERRUPT);
+			outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND);
+		}
+
+		if (reg & 0x01) {
+			set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
+			outb(0x01, iobase + REG_INTERRUPT);
+			bluecard_write_wakeup(info);
+		}
+
+		if (reg & 0x02) {
+			set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
+			outb(0x02, iobase + REG_INTERRUPT);
+			bluecard_write_wakeup(info);
+		}
+
+	}
+
+	/* Enable interrupt */
+	info->ctrl_reg |= REG_CONTROL_INTERRUPT;
+	outb(info->ctrl_reg, iobase + REG_CONTROL);
+
+	spin_unlock(&(info->lock));
+}
+
+
+
+/* ======================== Device specific HCI commands ======================== */
+
+
+static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
+{
+	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
+	struct sk_buff *skb;
+
+	/* Ericsson baud rate command */
+	unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 };
+
+	if (!(skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+		printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
+		return -1;
+	}
+
+	switch (baud) {
+	case 460800:
+		cmd[4] = 0x00;
+		skb->pkt_type = PKT_BAUD_RATE_460800;
+		break;
+	case 230400:
+		cmd[4] = 0x01;
+		skb->pkt_type = PKT_BAUD_RATE_230400;
+		break;
+	case 115200:
+		cmd[4] = 0x02;
+		skb->pkt_type = PKT_BAUD_RATE_115200;
+		break;
+	case 57600:
+		/* Fall through... */
+	default:
+		cmd[4] = 0x03;
+		skb->pkt_type = PKT_BAUD_RATE_57600;
+		break;
+	}
+
+	memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd));
+
+	skb_queue_tail(&(info->txq), skb);
+
+	bluecard_write_wakeup(info);
+
+	return 0;
+}
+
+
+
+/* ======================== HCI interface ======================== */
+
+
+static int bluecard_hci_flush(struct hci_dev *hdev)
+{
+	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
+
+	/* Drop TX queue */
+	skb_queue_purge(&(info->txq));
+
+	return 0;
+}
+
+
+static int bluecard_hci_open(struct hci_dev *hdev)
+{
+	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
+	unsigned int iobase = info->link.io.BasePort1;
+
+	bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
+
+	if (test_and_set_bit(HCI_RUNNING, &(hdev->flags)))
+		return 0;
+
+	/* Enable LED */
+	outb(0x08 | 0x20, iobase + 0x30);
+
+	return 0;
+}
+
+
+static int bluecard_hci_close(struct hci_dev *hdev)
+{
+	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
+	unsigned int iobase = info->link.io.BasePort1;
+
+	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
+		return 0;
+
+	bluecard_hci_flush(hdev);
+
+	/* Disable LED */
+	outb(0x00, iobase + 0x30);
+
+	return 0;
+}
+
+
+static int bluecard_hci_send_frame(struct sk_buff *skb)
+{
+	bluecard_info_t *info;
+	struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
+
+	if (!hdev) {
+		printk(KERN_WARNING "bluecard_cs: Frame for unknown HCI device (hdev=NULL).");
+		return -ENODEV;
+	}
+
+	info = (bluecard_info_t *)(hdev->driver_data);
+
+	switch (skb->pkt_type) {
+	case HCI_COMMAND_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+	case HCI_ACLDATA_PKT:
+		hdev->stat.acl_tx++;
+		break;
+	case HCI_SCODATA_PKT:
+		hdev->stat.sco_tx++;
+		break;
+	};
+
+	/* Prepend skb with frame type */
+	memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
+	skb_queue_tail(&(info->txq), skb);
+
+	bluecard_write_wakeup(info);
+
+	return 0;
+}
+
+
+static void bluecard_hci_destruct(struct hci_dev *hdev)
+{
+}
+
+
+static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
+{
+	return -ENOIOCTLCMD;
+}
+
+
+
+/* ======================== Card services HCI interaction ======================== */
+
+
+int bluecard_open(bluecard_info_t *info)
+{
+	unsigned int iobase = info->link.io.BasePort1;
+	struct hci_dev *hdev;
+	unsigned char id;
+
+	spin_lock_init(&(info->lock));
+
+	init_timer(&(info->timer));
+	info->timer.function = &bluecard_activity_led_timeout;
+	info->timer.data = (u_long)info;
+
+	skb_queue_head_init(&(info->txq));
+
+	info->rx_state = RECV_WAIT_PACKET_TYPE;
+	info->rx_count = 0;
+	info->rx_skb = NULL;
+
+	id = inb(iobase + 0x30);
+
+	if ((id & 0x0f) == 0x02)
+		set_bit(CARD_HAS_PCCARD_ID, &(info->hw_state));
+
+	if (id & 0x10)
+		set_bit(CARD_HAS_POWER_LED, &(info->hw_state));
+
+	if (id & 0x20)
+		set_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state));
+
+	/* Reset card */
+	info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET;
+	outb(info->ctrl_reg, iobase + REG_CONTROL);
+
+	/* Turn FPGA off */
+	outb(0x80, iobase + 0x30);
+
+	/* Wait some time */
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout(HZ / 100);
+
+	/* Turn FPGA on */
+	outb(0x00, iobase + 0x30);
+
+	/* Activate card */
+	info->ctrl_reg = REG_CONTROL_BT_ON | REG_CONTROL_BT_RES_PU;
+	outb(info->ctrl_reg, iobase + REG_CONTROL);
+
+	/* Enable interrupt */
+	outb(0xff, iobase + REG_INTERRUPT);
+	info->ctrl_reg |= REG_CONTROL_INTERRUPT;
+	outb(info->ctrl_reg, iobase + REG_CONTROL);
+
+	/* Start the RX buffers */
+	outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND);
+	outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND);
+
+	/* Signal that the hardware is ready */
+	set_bit(CARD_READY, &(info->hw_state));
+
+	/* Drop TX queue */
+	skb_queue_purge(&(info->txq));
+
+	/* Control the point at which RTS is enabled */
+	outb((0x0f << RTS_LEVEL_SHIFT_BITS) | 1, iobase + REG_RX_CONTROL);
+
+	/* Timeout before it is safe to send the first HCI packet */
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout((HZ * 5) / 4);		// or set it to 3/2
+
+
+	/* Initialize and register HCI device */
+
+	hdev = &(info->hdev);
+
+	hdev->type = HCI_PCCARD;
+	hdev->driver_data = info;
+
+	hdev->open = bluecard_hci_open;
+	hdev->close = bluecard_hci_close;
+	hdev->flush = bluecard_hci_flush;
+	hdev->send = bluecard_hci_send_frame;
+	hdev->destruct = bluecard_hci_destruct;
+	hdev->ioctl = bluecard_hci_ioctl;
+
+	if (hci_register_dev(hdev) < 0) {
+		printk(KERN_WARNING "bluecard_cs: Can't register HCI device %s.\n", hdev->name);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+
+int bluecard_close(bluecard_info_t *info)
+{
+	unsigned int iobase = info->link.io.BasePort1;
+	struct hci_dev *hdev = &(info->hdev);
+
+	bluecard_hci_close(hdev);
+
+	clear_bit(CARD_READY, &(info->hw_state));
+
+	/* Reset card */
+	info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET;
+	outb(info->ctrl_reg, iobase + REG_CONTROL);
+
+	/* Turn FPGA off */
+	outb(0x80, iobase + 0x30);
+
+	if (hci_unregister_dev(hdev) < 0)
+		printk(KERN_WARNING "bluecard_cs: Can't unregister HCI device %s.\n", hdev->name);
+
+	return 0;
+}
+
+
+
+/* ======================== Card services ======================== */
+
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+
+	CardServices(ReportError, handle, &err);
+}
+
+
+dev_link_t *bluecard_attach(void)
+{
+	bluecard_info_t *info;
+	client_reg_t client_reg;
+	dev_link_t *link;
+	int i, ret;
+
+	/* Create new info device */
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return NULL;
+	memset(info, 0, sizeof(*info));
+
+	link = &info->link;
+	link->priv = info;
+
+	link->release.function = &bluecard_release;
+	link->release.data = (u_long)link;
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	link->io.NumPorts1 = 8;
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+
+	if (irq_list[0] == -1)
+		link->irq.IRQInfo2 = irq_mask;
+	else
+		for (i = 0; i < 4; i++)
+			link->irq.IRQInfo2 |= 1 << irq_list[i];
+
+	link->irq.Handler = bluecard_interrupt;
+	link->irq.Instance = info;
+
+	link->conf.Attributes = CONF_ENABLE_IRQ;
+	link->conf.Vcc = 50;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+
+	/* Register with Card Services */
+	link->next = dev_list;
+	dev_list = link;
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask =
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.event_handler = &bluecard_event;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+
+	ret = CardServices(RegisterClient, &link->handle, &client_reg);
+	if (ret != CS_SUCCESS) {
+		cs_error(link->handle, RegisterClient, ret);
+		bluecard_detach(link);
+		return NULL;
+	}
+
+	return link;
+}
+
+
+void bluecard_detach(dev_link_t *link)
+{
+	bluecard_info_t *info = link->priv;
+	dev_link_t **linkp;
+	int ret;
+
+	/* Locate device structure */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+		if (*linkp == link)
+			break;
+
+	if (*linkp == NULL)
+		return;
+
+	del_timer(&link->release);
+	if (link->state & DEV_CONFIG)
+		bluecard_release((u_long)link);
+
+	if (link->handle) {
+		ret = CardServices(DeregisterClient, link->handle);
+		if (ret != CS_SUCCESS)
+			cs_error(link->handle, DeregisterClient, ret);
+	}
+
+	/* Unlink device structure, free bits */
+	*linkp = link->next;
+
+	kfree(info);
+}
+
+
+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+{
+	int i;
+
+	i = CardServices(fn, handle, tuple);
+	if (i != CS_SUCCESS)
+		return CS_NO_MORE_ITEMS;
+
+	i = CardServices(GetTupleData, handle, tuple);
+	if (i != CS_SUCCESS)
+		return i;
+
+	return CardServices(ParseTuple, handle, tuple, parse);
+}
+
+
+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
+
+void bluecard_config(dev_link_t *link)
+{
+	client_handle_t handle = link->handle;
+	bluecard_info_t *info = link->priv;
+	tuple_t tuple;
+	u_short buf[256];
+	cisparse_t parse;
+	config_info_t config;
+	int i, n, last_ret, last_fn;
+
+	tuple.TupleData = (cisdata_t *)buf;
+	tuple.TupleOffset = 0;
+	tuple.TupleDataMax = 255;
+	tuple.Attributes = 0;
+
+	/* Get configuration register information */
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	last_ret = first_tuple(handle, &tuple, &parse);
+	if (last_ret != CS_SUCCESS) {
+		last_fn = ParseTuple;
+		goto cs_failed;
+	}
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.Present = parse.config.rmask[0];
+
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+	i = CardServices(GetConfigurationInfo, handle, &config);
+	link->conf.Vcc = config.Vcc;
+
+	link->conf.ConfigIndex = 0x20;
+	link->io.NumPorts1 = 64;
+	link->io.IOAddrLines = 6;
+
+	for (n = 0; n < 0x400; n += 0x40) {
+		link->io.BasePort1 = n ^ 0x300;
+		i = CardServices(RequestIO, link->handle, &link->io);
+		if (i == CS_SUCCESS)
+			break;
+	}
+
+	if (i != CS_SUCCESS) {
+		cs_error(link->handle, RequestIO, i);
+		goto failed;
+	}
+
+	i = CardServices(RequestIRQ, link->handle, &link->irq);
+	if (i != CS_SUCCESS) {
+		cs_error(link->handle, RequestIRQ, i);
+		link->irq.AssignedIRQ = 0;
+	}
+
+	i = CardServices(RequestConfiguration, link->handle, &link->conf);
+	if (i != CS_SUCCESS) {
+		cs_error(link->handle, RequestConfiguration, i);
+		goto failed;
+	}
+
+	MOD_INC_USE_COUNT;
+
+	if (bluecard_open(info) != 0)
+		goto failed;
+
+	strcpy(info->node.dev_name, info->hdev.name);
+	link->dev = &info->node;
+	link->state &= ~DEV_CONFIG_PENDING;
+
+	return;
+
+cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+
+failed:
+	bluecard_release((u_long)link);
+}
+
+
+void bluecard_release(u_long arg)
+{
+	dev_link_t *link = (dev_link_t *)arg;
+	bluecard_info_t *info = link->priv;
+
+	if (link->state & DEV_PRESENT)
+		bluecard_close(info);
+
+	MOD_DEC_USE_COUNT;
+
+	link->dev = NULL;
+
+	CardServices(ReleaseConfiguration, link->handle);
+	CardServices(ReleaseIO, link->handle, &link->io);
+	CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+	link->state &= ~DEV_CONFIG;
+}
+
+
+int bluecard_event(event_t event, int priority, event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+	bluecard_info_t *info = link->priv;
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			bluecard_close(info);
+			mod_timer(&link->release, jiffies + HZ / 20);
+		}
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		bluecard_config(link);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		if (link->state & DEV_CONFIG)
+			CardServices(ReleaseConfiguration, link->handle);
+		break;
+	case CS_EVENT_PM_RESUME:
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		if (DEV_OK(link))
+			CardServices(RequestConfiguration, link->handle, &link->conf);
+		break;
+	}
+
+	return 0;
+}
+
+
+
+/* ======================== Module initialization ======================== */
+
+
+int __init init_bluecard_cs(void)
+{
+	servinfo_t serv;
+	int err;
+
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		printk(KERN_NOTICE "bluecard_cs: Card Services release does not match!\n");
+		return -1;
+	}
+
+	err = register_pccard_driver(&dev_info, &bluecard_attach, &bluecard_detach);
+
+	return err;
+}
+
+
+void __exit exit_bluecard_cs(void)
+{
+	unregister_pccard_driver(&dev_info);
+
+	while (dev_list != NULL)
+		bluecard_detach(dev_list);
+}
+
+
+module_init(init_bluecard_cs);
+module_exit(exit_bluecard_cs);
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/bluetooth/bt3c_cs.c linux-2.4.20/drivers/bluetooth/bt3c_cs.c
--- linux-2.4.19/drivers/bluetooth/bt3c_cs.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/bluetooth/bt3c_cs.c	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,946 @@
+/*
+ *
+ *  Driver for the 3Com Bluetooth PCMCIA card
+ *
+ *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
+ *                           Jose Orlando Pereira <jop@di.uminho.pt>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS
+ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ *  implied. See the License for the specific language governing
+ *  rights and limitations under the License.
+ *
+ *  The initial developer of the original code is David A. Hinds
+ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+
+
+/* ======================== Module parameters ======================== */
+
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xffff;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>");
+MODULE_DESCRIPTION("BlueZ driver for the 3Com Bluetooth PCMCIA card");
+MODULE_LICENSE("GPL");
+
+
+
+/* ======================== Local structures ======================== */
+
+
+typedef struct bt3c_info_t {
+	dev_link_t link;
+	dev_node_t node;
+
+	struct hci_dev hdev;
+
+	spinlock_t lock;		/* For serializing operations */
+
+	struct sk_buff_head txq;
+	unsigned long tx_state;
+
+	unsigned long rx_state;
+	unsigned long rx_count;
+	struct sk_buff *rx_skb;
+} bt3c_info_t;
+
+
+void bt3c_config(dev_link_t *link);
+void bt3c_release(u_long arg);
+int bt3c_event(event_t event, int priority, event_callback_args_t *args);
+
+static dev_info_t dev_info = "bt3c_cs";
+
+dev_link_t *bt3c_attach(void);
+void bt3c_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+
+/* Transmit states  */
+#define XMIT_SENDING  1
+#define XMIT_WAKEUP   2
+#define XMIT_WAITING  8
+
+/* Receiver states */
+#define RECV_WAIT_PACKET_TYPE   0
+#define RECV_WAIT_EVENT_HEADER  1
+#define RECV_WAIT_ACL_HEADER    2
+#define RECV_WAIT_SCO_HEADER    3
+#define RECV_WAIT_DATA          4
+
+
+
+/* ======================== Special I/O functions ======================== */
+
+
+#define DATA_L   0
+#define DATA_H   1
+#define ADDR_L   2
+#define ADDR_H   3
+#define CONTROL  4
+
+
+inline void bt3c_address(unsigned int iobase, unsigned short addr)
+{
+	outb(addr & 0xff, iobase + ADDR_L);
+	outb((addr >> 8) & 0xff, iobase + ADDR_H);
+}
+
+
+inline void bt3c_put(unsigned int iobase, unsigned short value)
+{
+	outb(value & 0xff, iobase + DATA_L);
+	outb((value >> 8) & 0xff, iobase + DATA_H);
+}
+
+
+inline void bt3c_io_write(unsigned int iobase, unsigned short addr, unsigned short value)
+{
+	bt3c_address(iobase, addr);
+	bt3c_put(iobase, value);
+}
+
+
+inline unsigned short bt3c_get(unsigned int iobase)
+{
+	unsigned short value = inb(iobase + DATA_L);
+
+	value |= inb(iobase + DATA_H) << 8;
+
+	return value;
+}
+
+
+inline unsigned short bt3c_read(unsigned int iobase, unsigned short addr)
+{
+	bt3c_address(iobase, addr);
+
+	return bt3c_get(iobase);
+}
+
+
+
+/* ======================== Interrupt handling ======================== */
+
+
+static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
+{
+	int actual = 0;
+
+	bt3c_address(iobase, 0x7080);
+
+	/* Fill FIFO with current frame */
+	while (actual < len) {
+		/* Transmit next byte */
+		bt3c_put(iobase, buf[actual]);
+		actual++;
+	}
+
+	bt3c_io_write(iobase, 0x7005, actual);
+
+	return actual;
+}
+
+
+static void bt3c_write_wakeup(bt3c_info_t *info, int from)
+{
+	unsigned long flags;
+
+	if (!info) {
+		printk(KERN_WARNING "bt3c_cs: Call of write_wakeup for unknown device.\n");
+		return;
+	}
+
+	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state)))
+		return;
+
+	spin_lock_irqsave(&(info->lock), flags);
+
+	do {
+		register unsigned int iobase = info->link.io.BasePort1;
+		register struct sk_buff *skb;
+		register int len;
+
+		if (!(info->link.state & DEV_PRESENT))
+			break;
+
+
+		if (!(skb = skb_dequeue(&(info->txq)))) {
+			clear_bit(XMIT_SENDING, &(info->tx_state));
+			break;
+		}
+
+		/* Send frame */
+		len = bt3c_write(iobase, 256, skb->data, skb->len);
+
+		if (len != skb->len) {
+			printk(KERN_WARNING "bt3c_cs: very strange\n");
+		}
+
+		kfree_skb(skb);
+
+		info->hdev.stat.byte_tx += len;
+
+	} while (0);
+
+	spin_unlock_irqrestore(&(info->lock), flags);
+}
+
+
+static void bt3c_receive(bt3c_info_t *info)
+{
+	unsigned int iobase;
+	int size = 0, avail;
+
+	if (!info) {
+		printk(KERN_WARNING "bt3c_cs: Call of receive for unknown device.\n");
+		return;
+	}
+
+	iobase = info->link.io.BasePort1;
+
+	avail = bt3c_read(iobase, 0x7006);
+	//printk("bt3c_cs: receiving %d bytes\n", avail);
+
+	bt3c_address(iobase, 0x7480);
+	while (size < avail) {
+		size++;
+		info->hdev.stat.byte_rx++;
+
+		/* Allocate packet */
+		if (info->rx_skb == NULL) {
+			info->rx_state = RECV_WAIT_PACKET_TYPE;
+			info->rx_count = 0;
+			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+				printk(KERN_WARNING "bt3c_cs: Can't allocate mem for new packet.\n");
+				return;
+			}
+		}
+
+
+		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
+
+			info->rx_skb->dev = (void *)&(info->hdev);
+			info->rx_skb->pkt_type = inb(iobase + DATA_L);
+			inb(iobase + DATA_H);
+			//printk("bt3c: PACKET_TYPE=%02x\n", info->rx_skb->pkt_type);
+
+			switch (info->rx_skb->pkt_type) {
+
+			case HCI_EVENT_PKT:
+				info->rx_state = RECV_WAIT_EVENT_HEADER;
+				info->rx_count = HCI_EVENT_HDR_SIZE;
+				break;
+
+			case HCI_ACLDATA_PKT:
+				info->rx_state = RECV_WAIT_ACL_HEADER;
+				info->rx_count = HCI_ACL_HDR_SIZE;
+				break;
+
+			case HCI_SCODATA_PKT:
+				info->rx_state = RECV_WAIT_SCO_HEADER;
+				info->rx_count = HCI_SCO_HDR_SIZE;
+				break;
+
+			default:
+				/* Unknown packet */
+				printk(KERN_WARNING "bt3c_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
+				info->hdev.stat.err_rx++;
+				clear_bit(HCI_RUNNING, &(info->hdev.flags));
+
+				kfree_skb(info->rx_skb);
+				info->rx_skb = NULL;
+				break;
+
+			}
+
+		} else {
+
+			__u8 x = inb(iobase + DATA_L);
+
+			*skb_put(info->rx_skb, 1) = x;
+			inb(iobase + DATA_H);
+			info->rx_count--;
+
+			if (info->rx_count == 0) {
+
+				int dlen;
+				hci_event_hdr *eh;
+				hci_acl_hdr *ah;
+				hci_sco_hdr *sh;
+
+				switch (info->rx_state) {
+
+				case RECV_WAIT_EVENT_HEADER:
+					eh = (hci_event_hdr *)(info->rx_skb->data);
+					info->rx_state = RECV_WAIT_DATA;
+					info->rx_count = eh->plen;
+					break;
+
+				case RECV_WAIT_ACL_HEADER:
+					ah = (hci_acl_hdr *)(info->rx_skb->data);
+					dlen = __le16_to_cpu(ah->dlen);
+					info->rx_state = RECV_WAIT_DATA;
+					info->rx_count = dlen;
+					break;
+
+				case RECV_WAIT_SCO_HEADER:
+					sh = (hci_sco_hdr *)(info->rx_skb->data);
+					info->rx_state = RECV_WAIT_DATA;
+					info->rx_count = sh->dlen;
+					break;
+
+				case RECV_WAIT_DATA:
+					hci_recv_frame(info->rx_skb);
+					info->rx_skb = NULL;
+					break;
+
+				}
+
+			}
+
+		}
+
+	}
+
+	bt3c_io_write(iobase, 0x7006, 0x0000);
+}
+
+
+void bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
+{
+	bt3c_info_t *info = dev_inst;
+	unsigned int iobase;
+	int iir;
+
+	if (!info) {
+		printk(KERN_WARNING "bt3c_cs: Call of irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	iobase = info->link.io.BasePort1;
+
+	spin_lock(&(info->lock));
+
+	iir = inb(iobase + CONTROL);
+	if (iir & 0x80) {
+		int stat = bt3c_read(iobase, 0x7001);
+
+		if ((stat & 0xff) == 0x7f) {
+			printk(KERN_WARNING "bt3c_cs: STRANGE stat=%04x\n", stat);
+		} else if ((stat & 0xff) != 0xff) {
+			if (stat & 0x0020) {
+				int stat = bt3c_read(iobase, 0x7002) & 0x10;
+				printk(KERN_WARNING "bt3c_cs: antena %s\n", stat ? "OUT" : "IN");
+			}
+			if (stat & 0x0001)
+				bt3c_receive(info);
+			if (stat & 0x0002) {
+				//printk("bt3c_cs: ACK %04x\n", stat);
+				clear_bit(XMIT_SENDING, &(info->tx_state));
+				bt3c_write_wakeup(info, 1);
+			}
+
+			bt3c_io_write(iobase, 0x7001, 0x0000);
+
+			outb(iir, iobase + CONTROL);
+		}
+	}
+
+	spin_unlock(&(info->lock));
+}
+
+
+
+
+/* ======================== HCI interface ======================== */
+
+
+static int bt3c_hci_flush(struct hci_dev *hdev)
+{
+	bt3c_info_t *info = (bt3c_info_t *)(hdev->driver_data);
+
+	/* Drop TX queue */
+	skb_queue_purge(&(info->txq));
+
+	return 0;
+}
+
+
+static int bt3c_hci_open(struct hci_dev *hdev)
+{
+	set_bit(HCI_RUNNING, &(hdev->flags));
+
+	return 0;
+}
+
+
+static int bt3c_hci_close(struct hci_dev *hdev)
+{
+	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
+		return 0;
+
+	bt3c_hci_flush(hdev);
+
+	return 0;
+}
+
+
+static int bt3c_hci_send_frame(struct sk_buff *skb)
+{
+	bt3c_info_t *info;
+	struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
+
+	if (!hdev) {
+		printk(KERN_WARNING "bt3c_cs: Frame for unknown HCI device (hdev=NULL).");
+		return -ENODEV;
+	}
+
+	info = (bt3c_info_t *) (hdev->driver_data);
+
+	switch (skb->pkt_type) {
+	case HCI_COMMAND_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+	case HCI_ACLDATA_PKT:
+		hdev->stat.acl_tx++;
+		break;
+	case HCI_SCODATA_PKT:
+		hdev->stat.sco_tx++;
+		break;
+	};
+
+	/* Prepend skb with frame type */
+	memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
+	skb_queue_tail(&(info->txq), skb);
+
+	bt3c_write_wakeup(info, 0);
+
+	return 0;
+}
+
+
+static void bt3c_hci_destruct(struct hci_dev *hdev)
+{
+}
+
+
+static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
+{
+	return -ENOIOCTLCMD;
+}
+
+
+
+/* ======================== User mode firmware loader ======================== */
+
+
+#define FW_LOADER  "/sbin/bluefw"
+static int errno;
+
+
+static int bt3c_fw_loader_exec(void *dev)
+{
+	char *argv[] = { FW_LOADER, "pccard", dev, NULL };
+	char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
+	int err;
+
+	err = exec_usermodehelper(FW_LOADER, argv, envp);
+	if (err)
+		printk(KERN_WARNING "bt3c_cs: Failed to exec \"%s pccard %s\".\n", FW_LOADER, (char *)dev);
+
+	return err;
+}
+
+
+static int bt3c_firmware_load(bt3c_info_t *info)
+{
+	sigset_t tmpsig;
+	char dev[16];
+	pid_t pid;
+	int result;
+
+	/* Check if root fs is mounted */
+	if (!current->fs->root) {
+		printk(KERN_WARNING "bt3c_cs: Root filesystem is not mounted.\n");
+		return -EPERM;
+	}
+
+	sprintf(dev, "%04x", info->link.io.BasePort1);
+
+	pid = kernel_thread(bt3c_fw_loader_exec, (void *)dev, 0);
+	if (pid < 0) {
+		printk(KERN_WARNING "bt3c_cs: Forking of kernel thread failed (errno=%d).\n", -pid);
+		return pid;
+	}
+
+	/* Block signals, everything but SIGKILL/SIGSTOP */
+	spin_lock_irq(&current->sigmask_lock);
+	tmpsig = current->blocked;
+	siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	result = waitpid(pid, NULL, __WCLONE);
+
+	/* Allow signals again */
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = tmpsig;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	if (result != pid) {
+		printk(KERN_WARNING "bt3c_cs: Waiting for pid %d failed (errno=%d).\n", pid, -result);
+		return -result;
+	}
+
+	return 0;
+}
+
+
+
+/* ======================== Card services HCI interaction ======================== */
+
+
+int bt3c_open(bt3c_info_t *info)
+{
+	struct hci_dev *hdev;
+	int err;
+
+	spin_lock_init(&(info->lock));
+
+	skb_queue_head_init(&(info->txq));
+
+	info->rx_state = RECV_WAIT_PACKET_TYPE;
+	info->rx_count = 0;
+	info->rx_skb = NULL;
+
+	/* Load firmware */
+
+	if ((err = bt3c_firmware_load(info)) < 0)
+		return err;
+
+	/* Timeout before it is safe to send the first HCI packet */
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout(HZ);
+
+
+	/* Initialize and register HCI device */
+
+	hdev = &(info->hdev);
+
+	hdev->type = HCI_PCCARD;
+	hdev->driver_data = info;
+
+	hdev->open = bt3c_hci_open;
+	hdev->close = bt3c_hci_close;
+	hdev->flush = bt3c_hci_flush;
+	hdev->send = bt3c_hci_send_frame;
+	hdev->destruct = bt3c_hci_destruct;
+	hdev->ioctl = bt3c_hci_ioctl;
+
+	if (hci_register_dev(hdev) < 0) {
+		printk(KERN_WARNING "bt3c_cs: Can't register HCI device %s.\n", hdev->name);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+
+int bt3c_close(bt3c_info_t *info)
+{
+	struct hci_dev *hdev = &(info->hdev);
+
+	bt3c_hci_close(hdev);
+
+	if (hci_unregister_dev(hdev) < 0)
+		printk(KERN_WARNING "bt3c_cs: Can't unregister HCI device %s.\n", hdev->name);
+
+	return 0;
+}
+
+
+
+/* ======================== Card services ======================== */
+
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+
+	CardServices(ReportError, handle, &err);
+}
+
+
+dev_link_t *bt3c_attach(void)
+{
+	bt3c_info_t *info;
+	client_reg_t client_reg;
+	dev_link_t *link;
+	int i, ret;
+
+	/* Create new info device */
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return NULL;
+	memset(info, 0, sizeof(*info));
+
+	link = &info->link;
+	link->priv = info;
+
+	link->release.function = &bt3c_release;
+	link->release.data = (u_long)link;
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	link->io.NumPorts1 = 8;
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+
+	if (irq_list[0] == -1)
+		link->irq.IRQInfo2 = irq_mask;
+	else
+		for (i = 0; i < 4; i++)
+			link->irq.IRQInfo2 |= 1 << irq_list[i];
+
+	link->irq.Handler = bt3c_interrupt;
+	link->irq.Instance = info;
+
+	link->conf.Attributes = CONF_ENABLE_IRQ;
+	link->conf.Vcc = 50;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+
+	/* Register with Card Services */
+	link->next = dev_list;
+	dev_list = link;
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask =
+	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.event_handler = &bt3c_event;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+
+	ret = CardServices(RegisterClient, &link->handle, &client_reg);
+	if (ret != CS_SUCCESS) {
+		cs_error(link->handle, RegisterClient, ret);
+		bt3c_detach(link);
+		return NULL;
+	}
+
+	return link;
+}
+
+
+void bt3c_detach(dev_link_t *link)
+{
+	bt3c_info_t *info = link->priv;
+	dev_link_t **linkp;
+	int ret;
+
+	/* Locate device structure */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+		if (*linkp == link)
+			break;
+
+	if (*linkp == NULL)
+		return;
+
+	del_timer(&link->release);
+
+	if (link->state & DEV_CONFIG)
+		bt3c_release((u_long)link);
+
+	if (link->handle) {
+		ret = CardServices(DeregisterClient, link->handle);
+		if (ret != CS_SUCCESS)
+			cs_error(link->handle, DeregisterClient, ret);
+	}
+
+	/* Unlink device structure, free bits */
+	*linkp = link->next;
+
+	kfree(info);
+}
+
+
+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+{
+	int i;
+
+	i = CardServices(fn, handle, tuple);
+	if (i != CS_SUCCESS)
+		return CS_NO_MORE_ITEMS;
+
+	i = CardServices(GetTupleData, handle, tuple);
+	if (i != CS_SUCCESS)
+		return i;
+
+	return CardServices(ParseTuple, handle, tuple, parse);
+}
+
+
+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
+
+void bt3c_config(dev_link_t *link)
+{
+	static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+	client_handle_t handle = link->handle;
+	bt3c_info_t *info = link->priv;
+	tuple_t tuple;
+	u_short buf[256];
+	cisparse_t parse;
+	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+	config_info_t config;
+	int i, j, try, last_ret, last_fn;
+
+	tuple.TupleData = (cisdata_t *)buf;
+	tuple.TupleOffset = 0;
+	tuple.TupleDataMax = 255;
+	tuple.Attributes = 0;
+
+	/* Get configuration register information */
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	last_ret = first_tuple(handle, &tuple, &parse);
+	if (last_ret != CS_SUCCESS) {
+		last_fn = ParseTuple;
+		goto cs_failed;
+	}
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.Present = parse.config.rmask[0];
+
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+	i = CardServices(GetConfigurationInfo, handle, &config);
+	link->conf.Vcc = config.Vcc;
+
+	/* First pass: look for a config entry that looks normal. */
+	tuple.TupleData = (cisdata_t *)buf;
+	tuple.TupleOffset = 0;
+	tuple.TupleDataMax = 255;
+	tuple.Attributes = 0;
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	/* Two tries: without IO aliases, then with aliases */
+	for (try = 0; try < 2; try++) {
+		i = first_tuple(handle, &tuple, &parse);
+		while (i != CS_NO_MORE_ITEMS) {
+			if (i != CS_SUCCESS)
+				goto next_entry;
+			if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
+				link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+			if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
+				link->conf.ConfigIndex = cf->index;
+				link->io.BasePort1 = cf->io.win[0].base;
+				link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+				i = CardServices(RequestIO, link->handle, &link->io);
+				if (i == CS_SUCCESS)
+					goto found_port;
+			}
+next_entry:
+			i = next_tuple(handle, &tuple, &parse);
+		}
+	}
+
+	/* Second pass: try to find an entry that isn't picky about
+	   its base address, then try to grab any standard serial port
+	   address, and finally try to get any free port. */
+	i = first_tuple(handle, &tuple, &parse);
+	while (i != CS_NO_MORE_ITEMS) {
+		if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
+			link->conf.ConfigIndex = cf->index;
+			for (j = 0; j < 5; j++) {
+				link->io.BasePort1 = base[j];
+				link->io.IOAddrLines = base[j] ? 16 : 3;
+				i = CardServices(RequestIO, link->handle, &link->io);
+				if (i == CS_SUCCESS)
+					goto found_port;
+			}
+		}
+		i = next_tuple(handle, &tuple, &parse);
+	}
+
+found_port:
+	if (i != CS_SUCCESS) {
+		printk(KERN_NOTICE "bt3c_cs: No usable port range found. Giving up.\n");
+		cs_error(link->handle, RequestIO, i);
+		goto failed;
+	}
+
+	i = CardServices(RequestIRQ, link->handle, &link->irq);
+	if (i != CS_SUCCESS) {
+		cs_error(link->handle, RequestIRQ, i);
+		link->irq.AssignedIRQ = 0;
+	}
+
+	i = CardServices(RequestConfiguration, link->handle, &link->conf);
+	if (i != CS_SUCCESS) {
+		cs_error(link->handle, RequestConfiguration, i);
+		goto failed;
+	}
+
+	MOD_INC_USE_COUNT;
+
+	if (bt3c_open(info) != 0)
+		goto failed;
+
+	strcpy(info->node.dev_name, info->hdev.name);
+	link->dev = &info->node;
+	link->state &= ~DEV_CONFIG_PENDING;
+
+	return;
+
+cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+
+failed:
+	bt3c_release((u_long)link);
+}
+
+
+void bt3c_release(u_long arg)
+{
+	dev_link_t *link = (dev_link_t *)arg;
+	bt3c_info_t *info = link->priv;
+
+	if (link->state & DEV_PRESENT)
+		bt3c_close(info);
+
+	MOD_DEC_USE_COUNT;
+
+	link->dev = NULL;
+
+	CardServices(ReleaseConfiguration, link->handle);
+	CardServices(ReleaseIO, link->handle, &link->io);
+	CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+	link->state &= ~DEV_CONFIG;
+}
+
+
+int bt3c_event(event_t event, int priority, event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+	bt3c_info_t *info = link->priv;
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			bt3c_close(info);
+			mod_timer(&link->release, jiffies + HZ / 20);
+		}
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		bt3c_config(link);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		if (link->state & DEV_CONFIG)
+			CardServices(ReleaseConfiguration, link->handle);
+		break;
+	case CS_EVENT_PM_RESUME:
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		if (DEV_OK(link))
+			CardServices(RequestConfiguration, link->handle, &link->conf);
+		break;
+	}
+
+	return 0;
+}
+
+
+
+/* ======================== Module initialization ======================== */
+
+
+int __init init_bt3c_cs(void)
+{
+	servinfo_t serv;
+	int err;
+
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		printk(KERN_NOTICE "bt3c_cs: Card Services release does not match!\n");
+		return -1;
+	}
+
+	err = register_pccard_driver(&dev_info, &bt3c_attach, &bt3c_detach);
+
+	return err;
+}
+
+
+void __exit exit_bt3c_cs(void)
+{
+	unregister_pccard_driver(&dev_info);
+
+	while (dev_list != NULL)
+		bt3c_detach(dev_list);
+}
+
+
+module_init(init_bt3c_cs);
+module_exit(exit_bt3c_cs);
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/bluetooth/dtl1_cs.c linux-2.4.20/drivers/bluetooth/dtl1_cs.c
--- linux-2.4.19/drivers/bluetooth/dtl1_cs.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/bluetooth/dtl1_cs.c	2002-10-29 11:18:33.000000000 +0000
@@ -75,23 +75,22 @@
 
 
 typedef struct dtl1_info_t {
-  dev_link_t link;
-  dev_node_t node;
+	dev_link_t link;
+	dev_node_t node;
 
-  struct hci_dev hdev;
+	struct hci_dev hdev;
 
-  spinlock_t lock;          /* For serializing operations */
+	spinlock_t lock;		/* For serializing operations */
 
-  unsigned long flowmask;   /* HCI flow mask */
-  int ri_latch;
+	unsigned long flowmask;		/* HCI flow mask */
+	int ri_latch;
 
-  struct sk_buff_head txq;
-  unsigned long tx_state;
-
-  unsigned long rx_state;
-  unsigned long rx_count;
-  struct sk_buff *rx_skb;
+	struct sk_buff_head txq;
+	unsigned long tx_state;
 
+	unsigned long rx_state;
+	unsigned long rx_count;
+	struct sk_buff *rx_skb;
 } dtl1_info_t;
 
 
@@ -104,7 +103,7 @@
 dev_link_t *dtl1_attach(void);
 void dtl1_detach(dev_link_t *);
 
-dev_link_t *dev_list = NULL;
+static dev_link_t *dev_list = NULL;
 
 
 /* Transmit states  */
@@ -118,282 +117,253 @@
 
 
 typedef struct {
-  u8 type;
-  u8 zero;
-  u16 len;
-} __attribute__ ((packed)) nsh_t;   /* Nokia Specific Header */
+	u8 type;
+	u8 zero;
+	u16 len;
+} __attribute__ ((packed)) nsh_t;	/* Nokia Specific Header */
 
-#define NSHL  4    /* Nokia Specific Header Length */
+#define NSHL  4				/* Nokia Specific Header Length */
 
 
 
 /* ======================== Interrupt handling ======================== */
 
 
-static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) {
-
-  int actual = 0;
-
-
-  /* Tx FIFO should be empty */
-  if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
-    return 0;
-
-
-  /* Fill FIFO with current frame */
-  while ((fifo_size-- > 0) && (actual < len)) {
-    /* Transmit next byte */
-    outb(buf[actual], iobase + UART_TX);
-    actual++;
-  }
-
-
-  return actual;
-
-}
-
-
-static void dtl1_write_wakeup(dtl1_info_t *info) {
-
-  if (!info) {
-    printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n");
-    return;
-  }
-
-
-  if (test_bit(XMIT_WAITING, &(info->tx_state))) {
-    set_bit(XMIT_WAKEUP, &(info->tx_state));
-    return;
-  }
-
-  if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
-    set_bit(XMIT_WAKEUP, &(info->tx_state));
-    return;
-  }
-
-
-  do {
-    register unsigned int iobase = info->link.io.BasePort1;
-    register struct sk_buff *skb;
-    register int len;
-
-    clear_bit(XMIT_WAKEUP, &(info->tx_state));
-
-    if (!(info->link.state & DEV_PRESENT))
-      return;
-
-
-    if (!(skb = skb_dequeue(&(info->txq))))
-      break;
-
-
-    /* Send frame */
-    len = dtl1_write(iobase, 32, skb->data, skb->len);
-
-    if (len == skb->len) {
-      set_bit(XMIT_WAITING, &(info->tx_state));
-      kfree_skb(skb);
-    }
-    else {
-      skb_pull(skb, len);
-      skb_queue_head(&(info->txq), skb);
-    }
-
-    info->hdev.stat.byte_tx += len;
-
-  } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
-
-
-  clear_bit(XMIT_SENDING, &(info->tx_state));
-
-}
-
-
-static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb) {
-
-  u8 flowmask = *(u8 *)skb->data;
-  int i;
-
-
-  printk(KERN_INFO "dtl1_cs: Nokia control data = ");
-  for (i = 0; i < skb->len; i++) {
-    printk("%02x ", skb->data[i]);
-  }
-  printk("\n");
-
-
-  /* transition to active state */
-  if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) {
-    clear_bit(XMIT_WAITING, &(info->tx_state));
-    dtl1_write_wakeup(info);
-  }
-
-  info->flowmask = flowmask;
-
-
-  kfree_skb(skb);
-
-}
-
-
-static void dtl1_receive(dtl1_info_t *info) {
-
-  unsigned int iobase;
-  nsh_t *nsh;
-  int boguscount = 0;
-
-
-  if (!info) {
-    printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n");
-    return;
-  }
-
-
-  iobase = info->link.io.BasePort1;
-
-  do {
-    info->hdev.stat.byte_rx++;
-
-    /* Allocate packet */
-    if (info->rx_skb == NULL)
-      if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-        printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n");
-        info->rx_state = RECV_WAIT_NSH;
-        info->rx_count = NSHL;
-        return;
-    }
-
-
-    *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
-    nsh = (nsh_t *)info->rx_skb->data;
-
-    info->rx_count--;
-
-
-    if (info->rx_count == 0) {
-
-      switch (info->rx_state) {
-      case RECV_WAIT_NSH:
-        info->rx_state = RECV_WAIT_DATA;
-        info->rx_count = nsh->len + (nsh->len & 0x0001);
-        break;
-      case RECV_WAIT_DATA:
-        info->rx_skb->pkt_type = nsh->type;
-
-        /* remove PAD byte if it exists */
-        if (nsh->len & 0x0001) {
-          info->rx_skb->tail--;
-          info->rx_skb->len--;
-        }
-
-        /* remove NSH */
-        skb_pull(info->rx_skb, NSHL);
-
-
-        switch (info->rx_skb->pkt_type) {
-        case 0x80:
-          /* control data for the Nokia Card */
-          dtl1_control(info, info->rx_skb);
-          break;
-        case 0x82:
-        case 0x83:
-        case 0x84:
-          /* send frame to the HCI layer */
-          info->rx_skb->dev = (void *)&(info->hdev);
-          info->rx_skb->pkt_type &= 0x0f;
-          hci_recv_frame(info->rx_skb);
-          break;
-        default:
-          /* unknown packet */
-          printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
-          kfree_skb(info->rx_skb);
-          break;
-        }
-
-
-        info->rx_state = RECV_WAIT_NSH;
-        info->rx_count = NSHL;
-        info->rx_skb = NULL;
-        break;
-      }
-
-    }
-
-
-    /* Make sure we don't stay here to long */
-    if (boguscount++ > 32)
-      break;
-
-  } while (inb(iobase + UART_LSR) & UART_LSR_DR);
-
-
-}
-
-
-void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) {
-
-  dtl1_info_t *info = dev_inst;
-  unsigned int iobase;
-  unsigned char msr;
-  int boguscount = 0;
-  int iir, lsr;
-
-
-  if (!info) {
-    printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq);
-    return;
-  }
-
-
-  iobase = info->link.io.BasePort1;
-
-
-  spin_lock(&(info->lock));
-
-  iir = inb(iobase + UART_IIR) & UART_IIR_ID;
-  while (iir) {
-
-    /* Clear interrupt */
-    lsr = inb(iobase + UART_LSR);
-
-    switch (iir) {
-    case UART_IIR_RLSI:
-      printk(KERN_NOTICE "dtl1_cs: RLSI\n");
-      break;
-    case UART_IIR_RDI:
-      /* Receive interrupt */
-      dtl1_receive(info);
-      break;
-    case UART_IIR_THRI:
-      if (lsr & UART_LSR_THRE) {
-        /* Transmitter ready for data */
-        dtl1_write_wakeup(info);
-      }
-      break;
-    default:
-      printk(KERN_NOTICE "dtl1_cs: Unhandled IIR=%#x\n", iir);
-      break;
-    }
-
-    /* Make sure we don't stay here to long */
-    if (boguscount++ > 100)
-      break;
-
-    iir = inb(iobase + UART_IIR) & UART_IIR_ID;
-
-  }
-
-
-  msr = inb(iobase + UART_MSR);
-
-  if (info->ri_latch ^ (msr & UART_MSR_RI)) {
-    info->ri_latch = msr & UART_MSR_RI;
-    clear_bit(XMIT_WAITING, &(info->tx_state));
-    dtl1_write_wakeup(info);
-  }
-
-  spin_unlock(&(info->lock));
+static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
+{
+	int actual = 0;
+
+	/* Tx FIFO should be empty */
+	if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
+		return 0;
+
+	/* Fill FIFO with current frame */
+	while ((fifo_size-- > 0) && (actual < len)) {
+		/* Transmit next byte */
+		outb(buf[actual], iobase + UART_TX);
+		actual++;
+	}
+
+	return actual;
+}
+
+
+static void dtl1_write_wakeup(dtl1_info_t *info)
+{
+	if (!info) {
+		printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n");
+		return;
+	}
+
+	if (test_bit(XMIT_WAITING, &(info->tx_state))) {
+		set_bit(XMIT_WAKEUP, &(info->tx_state));
+		return;
+	}
+
+	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
+		set_bit(XMIT_WAKEUP, &(info->tx_state));
+		return;
+	}
+
+	do {
+		register unsigned int iobase = info->link.io.BasePort1;
+		register struct sk_buff *skb;
+		register int len;
+
+		clear_bit(XMIT_WAKEUP, &(info->tx_state));
+
+		if (!(info->link.state & DEV_PRESENT))
+			return;
+
+		if (!(skb = skb_dequeue(&(info->txq))))
+			break;
+
+		/* Send frame */
+		len = dtl1_write(iobase, 32, skb->data, skb->len);
+
+		if (len == skb->len) {
+			set_bit(XMIT_WAITING, &(info->tx_state));
+			kfree_skb(skb);
+		} else {
+			skb_pull(skb, len);
+			skb_queue_head(&(info->txq), skb);
+		}
+
+		info->hdev.stat.byte_tx += len;
+
+	} while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
+
+	clear_bit(XMIT_SENDING, &(info->tx_state));
+}
+
+
+static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb)
+{
+	u8 flowmask = *(u8 *)skb->data;
+	int i;
+
+	printk(KERN_INFO "dtl1_cs: Nokia control data = ");
+	for (i = 0; i < skb->len; i++) {
+		printk("%02x ", skb->data[i]);
+	}
+	printk("\n");
+
+	/* transition to active state */
+	if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) {
+		clear_bit(XMIT_WAITING, &(info->tx_state));
+		dtl1_write_wakeup(info);
+	}
+
+	info->flowmask = flowmask;
+
+	kfree_skb(skb);
+}
+
+
+static void dtl1_receive(dtl1_info_t *info)
+{
+	unsigned int iobase;
+	nsh_t *nsh;
+	int boguscount = 0;
+
+	if (!info) {
+		printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n");
+		return;
+	}
+
+	iobase = info->link.io.BasePort1;
+
+	do {
+		info->hdev.stat.byte_rx++;
+
+		/* Allocate packet */
+		if (info->rx_skb == NULL)
+			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+				printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n");
+				info->rx_state = RECV_WAIT_NSH;
+				info->rx_count = NSHL;
+				return;
+			}
+
+		*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
+		nsh = (nsh_t *)info->rx_skb->data;
+
+		info->rx_count--;
+
+		if (info->rx_count == 0) {
+
+			switch (info->rx_state) {
+			case RECV_WAIT_NSH:
+				info->rx_state = RECV_WAIT_DATA;
+				info->rx_count = nsh->len + (nsh->len & 0x0001);
+				break;
+			case RECV_WAIT_DATA:
+				info->rx_skb->pkt_type = nsh->type;
+
+				/* remove PAD byte if it exists */
+				if (nsh->len & 0x0001) {
+					info->rx_skb->tail--;
+					info->rx_skb->len--;
+				}
+
+				/* remove NSH */
+				skb_pull(info->rx_skb, NSHL);
+
+				switch (info->rx_skb->pkt_type) {
+				case 0x80:
+					/* control data for the Nokia Card */
+					dtl1_control(info, info->rx_skb);
+					break;
+				case 0x82:
+				case 0x83:
+				case 0x84:
+					/* send frame to the HCI layer */
+					info->rx_skb->dev = (void *)&(info->hdev);
+					info->rx_skb->pkt_type &= 0x0f;
+					hci_recv_frame(info->rx_skb);
+					break;
+				default:
+					/* unknown packet */
+					printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
+					kfree_skb(info->rx_skb);
+					break;
+				}
+
+				info->rx_state = RECV_WAIT_NSH;
+				info->rx_count = NSHL;
+				info->rx_skb = NULL;
+				break;
+			}
+
+		}
+
+		/* Make sure we don't stay here to long */
+		if (boguscount++ > 32)
+			break;
+
+	} while (inb(iobase + UART_LSR) & UART_LSR_DR);
+}
+
+
+void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
+{
+	dtl1_info_t *info = dev_inst;
+	unsigned int iobase;
+	unsigned char msr;
+	int boguscount = 0;
+	int iir, lsr;
+
+	if (!info) {
+		printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	iobase = info->link.io.BasePort1;
+
+	spin_lock(&(info->lock));
+
+	iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+	while (iir) {
+
+		/* Clear interrupt */
+		lsr = inb(iobase + UART_LSR);
+
+		switch (iir) {
+		case UART_IIR_RLSI:
+			printk(KERN_NOTICE "dtl1_cs: RLSI\n");
+			break;
+		case UART_IIR_RDI:
+			/* Receive interrupt */
+			dtl1_receive(info);
+			break;
+		case UART_IIR_THRI:
+			if (lsr & UART_LSR_THRE) {
+				/* Transmitter ready for data */
+				dtl1_write_wakeup(info);
+			}
+			break;
+		default:
+			printk(KERN_NOTICE "dtl1_cs: Unhandled IIR=%#x\n", iir);
+			break;
+		}
+
+		/* Make sure we don't stay here to long */
+		if (boguscount++ > 100)
+			break;
+
+		iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+
+	}
+
+	msr = inb(iobase + UART_MSR);
+
+	if (info->ri_latch ^ (msr & UART_MSR_RI)) {
+		info->ri_latch = msr & UART_MSR_RI;
+		clear_bit(XMIT_WAITING, &(info->tx_state));
+		dtl1_write_wakeup(info);
+	}
 
+	spin_unlock(&(info->lock));
 }
 
 
@@ -401,107 +371,94 @@
 /* ======================== HCI interface ======================== */
 
 
-static int dtl1_hci_open(struct hci_dev *hdev) {
-
-  set_bit(HCI_RUNNING, &(hdev->flags));
-
-
-  return 0;
+static int dtl1_hci_open(struct hci_dev *hdev)
+{
+	set_bit(HCI_RUNNING, &(hdev->flags));
 
+	return 0;
 }
 
 
-static int dtl1_hci_flush(struct hci_dev *hdev) {
-
-  dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data);
-
-
-  /* Drop TX queue */
-  skb_queue_purge(&(info->txq));
-
+static int dtl1_hci_flush(struct hci_dev *hdev)
+{
+	dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data);
 
-  return 0;
+	/* Drop TX queue */
+	skb_queue_purge(&(info->txq));
 
+	return 0;
 }
 
 
-static int dtl1_hci_close(struct hci_dev *hdev) {
+static int dtl1_hci_close(struct hci_dev *hdev)
+{
+	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
+		return 0;
 
-  if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
-    return 0;
-
-
-  dtl1_hci_flush(hdev);
-
-
-  return 0;
+	dtl1_hci_flush(hdev);
 
+	return 0;
 }
 
 
-static int dtl1_hci_send_frame(struct sk_buff *skb) {
-
-  dtl1_info_t *info;
-  struct hci_dev* hdev = (struct hci_dev *)(skb->dev);
-  struct sk_buff *s;
-  nsh_t nsh;
-
+static int dtl1_hci_send_frame(struct sk_buff *skb)
+{
+	dtl1_info_t *info;
+	struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
+	struct sk_buff *s;
+	nsh_t nsh;
 
-  if (!hdev) {
-    printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL).");
-    return -ENODEV;
-  }
+	if (!hdev) {
+		printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL).");
+		return -ENODEV;
+	}
 
-  info = (dtl1_info_t *)(hdev->driver_data);
+	info = (dtl1_info_t *)(hdev->driver_data);
 
+	switch (skb->pkt_type) {
+	case HCI_COMMAND_PKT:
+		hdev->stat.cmd_tx++;
+		nsh.type = 0x81;
+		break;
+	case HCI_ACLDATA_PKT:
+		hdev->stat.acl_tx++;
+		nsh.type = 0x82;
+		break;
+	case HCI_SCODATA_PKT:
+		hdev->stat.sco_tx++;
+		nsh.type = 0x83;
+		break;
+	};
 
-  switch (skb->pkt_type) {
-  case HCI_COMMAND_PKT:
-    hdev->stat.cmd_tx++;
-    nsh.type = 0x81;
-    break;
-  case HCI_ACLDATA_PKT:
-    hdev->stat.acl_tx++;
-    nsh.type = 0x82;
-    break;
-  case HCI_SCODATA_PKT:
-    hdev->stat.sco_tx++;
-    nsh.type = 0x83;
-    break;
-  };
+	nsh.zero = 0;
+	nsh.len = skb->len;
 
-  nsh.zero = 0;
-  nsh.len = skb->len;
+	s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
+	skb_reserve(s, NSHL);
+	memcpy(skb_put(s, skb->len), skb->data, skb->len);
+	if (skb->len & 0x0001)
+		*skb_put(s, 1) = 0;	/* PAD */
 
-  s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
-  skb_reserve(s, NSHL);
-  memcpy(skb_put(s, skb->len), skb->data, skb->len);
-  if (skb->len & 0x0001)
-    *skb_put(s, 1) = 0;  /* PAD */
+	/* Prepend skb with Nokia frame header and queue */
+	memcpy(skb_push(s, NSHL), &nsh, NSHL);
+	skb_queue_tail(&(info->txq), s);
 
-  /* Prepend skb with Nokia frame header and queue */
-  memcpy(skb_push(s, NSHL), &nsh, NSHL);
-  skb_queue_tail(&(info->txq), s);
+	dtl1_write_wakeup(info);
 
+	kfree_skb(skb);
 
-  dtl1_write_wakeup(info);
-
-  kfree_skb(skb);
-
-
-  return 0;
-
+	return 0;
 }
 
 
-static void dtl1_hci_destruct(struct hci_dev *hdev) {
+static void dtl1_hci_destruct(struct hci_dev *hdev)
+{
 }
 
 
-static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) {
-
-  return -ENOIOCTLCMD;
-
+static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd,  unsigned long arg)
+{
+	return -ENOIOCTLCMD;
 }
 
 
@@ -509,101 +466,91 @@
 /* ======================== Card services HCI interaction ======================== */
 
 
-int dtl1_open(dtl1_info_t *info) {
+int dtl1_open(dtl1_info_t *info)
+{
+	unsigned long flags;
+	unsigned int iobase = info->link.io.BasePort1;
+	struct hci_dev *hdev;
 
-  unsigned long flags;
-  unsigned int iobase = info->link.io.BasePort1;
-  struct hci_dev *hdev;
+	spin_lock_init(&(info->lock));
 
+	skb_queue_head_init(&(info->txq));
 
-  spin_lock_init(&(info->lock));
+	info->rx_state = RECV_WAIT_NSH;
+	info->rx_count = NSHL;
+	info->rx_skb = NULL;
 
-  skb_queue_head_init(&(info->txq));
+	set_bit(XMIT_WAITING, &(info->tx_state));
 
-  info->rx_state = RECV_WAIT_NSH;
-  info->rx_count = NSHL;
-  info->rx_skb = NULL;
+	spin_lock_irqsave(&(info->lock), flags);
 
-  set_bit(XMIT_WAITING, &(info->tx_state));
+	/* Reset UART */
+	outb(0, iobase + UART_MCR);
 
+	/* Turn off interrupts */
+	outb(0, iobase + UART_IER);
 
-  spin_lock_irqsave(&(info->lock), flags);
+	/* Initialize UART */
+	outb(UART_LCR_WLEN8, iobase + UART_LCR);	/* Reset DLAB */
+	outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
 
-  /* Reset UART */
-  outb(0, iobase + UART_MCR);
+	info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI;
 
-  /* Turn off interrupts */
-  outb(0, iobase + UART_IER);
+	/* Turn on interrupts */
+	outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
 
-  /* Initialize UART */
-  outb(UART_LCR_WLEN8, iobase + UART_LCR);  /* Reset DLAB */
-  outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
+	spin_unlock_irqrestore(&(info->lock), flags);
 
-  info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI;
+	/* Timeout before it is safe to send the first HCI packet */
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout(HZ * 2);
 
-  /* Turn on interrupts */
-  outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
 
-  spin_unlock_irqrestore(&(info->lock), flags);
+	/* Initialize and register HCI device */
 
+	hdev = &(info->hdev);
 
-  /* Timeout before it is safe to send the first HCI packet */
-  set_current_state(TASK_INTERRUPTIBLE);
-  schedule_timeout(HZ * 2);
+	hdev->type = HCI_PCCARD;
+	hdev->driver_data = info;
 
+	hdev->open = dtl1_hci_open;
+	hdev->close = dtl1_hci_close;
+	hdev->flush = dtl1_hci_flush;
+	hdev->send = dtl1_hci_send_frame;
+	hdev->destruct = dtl1_hci_destruct;
+	hdev->ioctl = dtl1_hci_ioctl;
 
-  /* Initialize and register HCI device */
-
-  hdev = &(info->hdev);
-
-  hdev->type = HCI_PCCARD;
-  hdev->driver_data = info;
-
-  hdev->open     = dtl1_hci_open;
-  hdev->close    = dtl1_hci_close;
-  hdev->flush    = dtl1_hci_flush;
-  hdev->send     = dtl1_hci_send_frame;
-  hdev->destruct = dtl1_hci_destruct;
-  hdev->ioctl    = dtl1_hci_ioctl;
-
-  if (hci_register_dev(hdev) < 0) {
-    printk(KERN_WARNING "dtl1_cs: Can't register HCI device %s.\n", hdev->name);
-    return -ENODEV;
-  }
-
-
-  return 0;
+	if (hci_register_dev(hdev) < 0) {
+		printk(KERN_WARNING "dtl1_cs: Can't register HCI device %s.\n", hdev->name);
+		return -ENODEV;
+	}
 
+	return 0;
 }
 
 
-int dtl1_close(dtl1_info_t *info) {
-
-  unsigned long flags;
-  unsigned int iobase = info->link.io.BasePort1;
-  struct hci_dev *hdev = &(info->hdev);
-
-
-  dtl1_hci_close(hdev);
-
-
-  spin_lock_irqsave(&(info->lock), flags);
-
-  /* Reset UART */
-  outb(0, iobase + UART_MCR);
+int dtl1_close(dtl1_info_t *info)
+{
+	unsigned long flags;
+	unsigned int iobase = info->link.io.BasePort1;
+	struct hci_dev *hdev = &(info->hdev);
 
-  /* Turn off interrupts */
-  outb(0, iobase + UART_IER);
+	dtl1_hci_close(hdev);
 
-  spin_unlock_irqrestore(&(info->lock), flags);
+	spin_lock_irqsave(&(info->lock), flags);
 
+	/* Reset UART */
+	outb(0, iobase + UART_MCR);
 
-  if (hci_unregister_dev(hdev) < 0)
-    printk(KERN_WARNING "dtl1_cs: Can't unregister HCI device %s.\n", hdev->name);
+	/* Turn off interrupts */
+	outb(0, iobase + UART_IER);
 
+	spin_unlock_irqrestore(&(info->lock), flags);
 
-  return 0;
+	if (hci_unregister_dev(hdev) < 0)
+		printk(KERN_WARNING "dtl1_cs: Can't unregister HCI device %s.\n", hdev->name);
 
+	return 0;
 }
 
 
@@ -611,291 +558,267 @@
 /* ======================== Card services ======================== */
 
 
-static void cs_error(client_handle_t handle, int func, int ret) {
-
-  error_info_t err = { func, ret };
-
-
-  CardServices(ReportError, handle, &err);
-
-}
-
-
-dev_link_t *dtl1_attach(void) {
-
-  dtl1_info_t *info;
-  client_reg_t client_reg;
-  dev_link_t *link;
-  int i, ret;
-
-
-  /* Create new info device */
-  info = kmalloc(sizeof(*info), GFP_KERNEL);
-  if (!info)
-    return NULL;
-  memset(info, 0, sizeof(*info));
-
-
-  link = &info->link;
-  link->priv = info;
-
-  link->release.function = &dtl1_release;
-  link->release.data = (u_long)link;
-  link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-  link->io.NumPorts1 = 8;
-  link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-  link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-
-  if (irq_list[0] == -1)
-    link->irq.IRQInfo2 = irq_mask;
-  else
-    for (i = 0; i < 4; i++)
-      link->irq.IRQInfo2 |= 1 << irq_list[i];
-
-  link->irq.Handler = dtl1_interrupt;
-  link->irq.Instance = info;
-
-  link->conf.Attributes = CONF_ENABLE_IRQ;
-  link->conf.Vcc = 50;
-  link->conf.IntType = INT_MEMORY_AND_IO;
-
-
-  /* Register with Card Services */
-  link->next = dev_list;
-  dev_list = link;
-  client_reg.dev_info = &dev_info;
-  client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-  client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-                         CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-                         CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-  client_reg.event_handler = &dtl1_event;
-  client_reg.Version = 0x0210;
-  client_reg.event_callback_args.client_data = link;
-
-  ret = CardServices(RegisterClient, &link->handle, &client_reg);
-  if (ret != CS_SUCCESS) {
-    cs_error(link->handle, RegisterClient, ret);
-    dtl1_detach(link);
-    return NULL;
-  }
-
-
-  return link;
-
-}
-
-
-void dtl1_detach(dev_link_t *link) {
-
-  dtl1_info_t *info = link->priv;
-  dev_link_t **linkp;
-  int ret;
-
-
-  /* Locate device structure */
-  for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-    if (*linkp == link)
-      break;
-
-  if (*linkp == NULL)
-    return;
-
-
-  del_timer(&link->release);
-  if (link->state & DEV_CONFIG)
-    dtl1_release((u_long)link);
-
-
-  if (link->handle) {
-    ret = CardServices(DeregisterClient, link->handle);
-    if (ret != CS_SUCCESS)
-      cs_error(link->handle, DeregisterClient, ret);
-  }
-
-
-  /* Unlink device structure, free bits */
-  *linkp = link->next;
-
-  kfree(info);
-
-}
-
-
-static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple,
-		     cisparse_t *parse) {
-
-  int i;
-
-
-  i = CardServices(fn, handle, tuple);
-  if (i != CS_SUCCESS)
-    return CS_NO_MORE_ITEMS;
-
-  i = CardServices(GetTupleData, handle, tuple);
-  if (i != CS_SUCCESS)
-    return i;
-
-  return CardServices(ParseTuple, handle, tuple, parse);
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+
+	CardServices(ReportError, handle, &err);
+}
+
+
+dev_link_t *dtl1_attach(void)
+{
+	dtl1_info_t *info;
+	client_reg_t client_reg;
+	dev_link_t *link;
+	int i, ret;
+
+	/* Create new info device */
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return NULL;
+	memset(info, 0, sizeof(*info));
+
+	link = &info->link;
+	link->priv = info;
+
+	link->release.function = &dtl1_release;
+	link->release.data = (u_long)link;
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	link->io.NumPorts1 = 8;
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+
+	if (irq_list[0] == -1)
+		link->irq.IRQInfo2 = irq_mask;
+	else
+		for (i = 0; i < 4; i++)
+			link->irq.IRQInfo2 |= 1 << irq_list[i];
+
+	link->irq.Handler = dtl1_interrupt;
+	link->irq.Instance = info;
+
+	link->conf.Attributes = CONF_ENABLE_IRQ;
+	link->conf.Vcc = 50;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+
+	/* Register with Card Services */
+	link->next = dev_list;
+	dev_list = link;
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask =
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.event_handler = &dtl1_event;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+
+	ret = CardServices(RegisterClient, &link->handle, &client_reg);
+	if (ret != CS_SUCCESS) {
+		cs_error(link->handle, RegisterClient, ret);
+		dtl1_detach(link);
+		return NULL;
+	}
+
+	return link;
+}
+
+
+void dtl1_detach(dev_link_t *link)
+{
+	dtl1_info_t *info = link->priv;
+	dev_link_t **linkp;
+	int ret;
+
+	/* Locate device structure */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+		if (*linkp == link)
+			break;
+
+	if (*linkp == NULL)
+		return;
+
+	del_timer(&link->release);
+	if (link->state & DEV_CONFIG)
+		dtl1_release((u_long)link);
+
+	if (link->handle) {
+		ret = CardServices(DeregisterClient, link->handle);
+		if (ret != CS_SUCCESS)
+			cs_error(link->handle, DeregisterClient, ret);
+	}
+
+	/* Unlink device structure, free bits */
+	*linkp = link->next;
+
+	kfree(info);
+}
+
+
+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+{
+	int i;
+
+	i = CardServices(fn, handle, tuple);
+	if (i != CS_SUCCESS)
+		return CS_NO_MORE_ITEMS;
+
+	i = CardServices(GetTupleData, handle, tuple);
+	if (i != CS_SUCCESS)
+		return i;
 
+	return CardServices(ParseTuple, handle, tuple, parse);
 }
 
 
 #define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
 #define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
 
-void dtl1_config(dev_link_t *link) {
-
-  client_handle_t handle = link->handle;
-  dtl1_info_t *info = link->priv;
-  tuple_t tuple;
-  u_short buf[256];
-  cisparse_t parse;
-  cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-  config_info_t config;
-  int i, last_ret, last_fn;
-
-
-  tuple.TupleData = (cisdata_t *)buf;
-  tuple.TupleOffset = 0;
-  tuple.TupleDataMax = 255;
-  tuple.Attributes = 0;
-
-  /* Get configuration register information */
-  tuple.DesiredTuple = CISTPL_CONFIG;
-  last_ret = first_tuple(handle, &tuple, &parse);
-  if (last_ret != CS_SUCCESS) {
-    last_fn = ParseTuple;
-    goto cs_failed;
-  }
-  link->conf.ConfigBase = parse.config.base;
-  link->conf.Present = parse.config.rmask[0];
-
-
-  /* Configure card */
-  link->state |= DEV_CONFIG;
-  i = CardServices(GetConfigurationInfo, handle, &config);
-  link->conf.Vcc = config.Vcc;
-
-  tuple.TupleData = (cisdata_t *)buf;
-  tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-  tuple.Attributes = 0;
-  tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-
-  /* Look for a generic full-sized window */
-  link->io.NumPorts1 = 8;
-  i = first_tuple(handle, &tuple, &parse);
-  while (i != CS_NO_MORE_ITEMS) {
-    if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
-      link->conf.ConfigIndex = cf->index;
-      link->io.BasePort1 = cf->io.win[0].base;
-      link->io.NumPorts1 = cf->io.win[0].len; /*yo*/
-      link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
-      i = CardServices(RequestIO, link->handle, &link->io);
-      if (i == CS_SUCCESS)
-        break;
-    }
-    i = next_tuple(handle, &tuple, &parse);
-  }
-
-  if (i != CS_SUCCESS) {
-    cs_error(link->handle, RequestIO, i);
-    goto failed;
-  }
-
-  i = CardServices(RequestIRQ, link->handle, &link->irq);
-  if (i != CS_SUCCESS) {
-    cs_error(link->handle, RequestIRQ, i);
-    link->irq.AssignedIRQ = 0;
-  }
-
-  i = CardServices(RequestConfiguration, link->handle, &link->conf);
-  if (i != CS_SUCCESS) {
-    cs_error(link->handle, RequestConfiguration, i);
-    goto failed;
-  }
-
-
-  MOD_INC_USE_COUNT;
-
-  if (dtl1_open(info) != 0)
-    goto failed;
-
-
-  link->dev = &info->node;
-  link->state &= ~DEV_CONFIG_PENDING;
-
-
-  return;
+void dtl1_config(dev_link_t *link)
+{
+	client_handle_t handle = link->handle;
+	dtl1_info_t *info = link->priv;
+	tuple_t tuple;
+	u_short buf[256];
+	cisparse_t parse;
+	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+	config_info_t config;
+	int i, last_ret, last_fn;
+
+	tuple.TupleData = (cisdata_t *)buf;
+	tuple.TupleOffset = 0;
+	tuple.TupleDataMax = 255;
+	tuple.Attributes = 0;
+
+	/* Get configuration register information */
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	last_ret = first_tuple(handle, &tuple, &parse);
+	if (last_ret != CS_SUCCESS) {
+		last_fn = ParseTuple;
+		goto cs_failed;
+	}
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.Present = parse.config.rmask[0];
+
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+	i = CardServices(GetConfigurationInfo, handle, &config);
+	link->conf.Vcc = config.Vcc;
+
+	tuple.TupleData = (cisdata_t *)buf;
+	tuple.TupleOffset = 0;
+	tuple.TupleDataMax = 255;
+	tuple.Attributes = 0;
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+
+	/* Look for a generic full-sized window */
+	link->io.NumPorts1 = 8;
+	i = first_tuple(handle, &tuple, &parse);
+	while (i != CS_NO_MORE_ITEMS) {
+		if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
+			link->conf.ConfigIndex = cf->index;
+			link->io.BasePort1 = cf->io.win[0].base;
+			link->io.NumPorts1 = cf->io.win[0].len;	/*yo */
+			link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
+			i = CardServices(RequestIO, link->handle, &link->io);
+			if (i == CS_SUCCESS)
+				break;
+		}
+		i = next_tuple(handle, &tuple, &parse);
+	}
+
+	if (i != CS_SUCCESS) {
+		cs_error(link->handle, RequestIO, i);
+		goto failed;
+	}
+
+	i = CardServices(RequestIRQ, link->handle, &link->irq);
+	if (i != CS_SUCCESS) {
+		cs_error(link->handle, RequestIRQ, i);
+		link->irq.AssignedIRQ = 0;
+	}
+
+	i = CardServices(RequestConfiguration, link->handle, &link->conf);
+	if (i != CS_SUCCESS) {
+		cs_error(link->handle, RequestConfiguration, i);
+		goto failed;
+	}
+
+	MOD_INC_USE_COUNT;
+
+	if (dtl1_open(info) != 0)
+		goto failed;
+
+	strcpy(info->node.dev_name, info->hdev.name);
+	link->dev = &info->node;
+	link->state &= ~DEV_CONFIG_PENDING;
 
+	return;
 
 cs_failed:
-  cs_error(link->handle, last_fn, last_ret);
-failed:
-  dtl1_release((u_long)link);
+	cs_error(link->handle, last_fn, last_ret);
 
+failed:
+	dtl1_release((u_long)link);
 }
 
 
-void dtl1_release(u_long arg) {
-
-  dev_link_t *link = (dev_link_t *)arg;
-  dtl1_info_t *info = link->priv;
-
-
-  if (link->state & DEV_PRESENT)
-    dtl1_close(info);
-
-  MOD_DEC_USE_COUNT;
-
-
-  link->dev = NULL;
-
-  CardServices(ReleaseConfiguration, link->handle);
-  CardServices(ReleaseIO, link->handle, &link->io);
-  CardServices(ReleaseIRQ, link->handle, &link->irq);
-
-  link->state &= ~DEV_CONFIG;
-
+void dtl1_release(u_long arg)
+{
+	dev_link_t *link = (dev_link_t *)arg;
+	dtl1_info_t *info = link->priv;
+
+	if (link->state & DEV_PRESENT)
+		dtl1_close(info);
+
+	MOD_DEC_USE_COUNT;
+
+	link->dev = NULL;
+
+	CardServices(ReleaseConfiguration, link->handle);
+	CardServices(ReleaseIO, link->handle, &link->io);
+	CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+	link->state &= ~DEV_CONFIG;
 }
 
 
-int dtl1_event(event_t event, int priority, event_callback_args_t *args) {
-
-  dev_link_t *link = args->client_data;
-  dtl1_info_t *info = link->priv;
-
-
-  switch (event) {
-  case CS_EVENT_CARD_REMOVAL:
-    link->state &= ~DEV_PRESENT;
-    if (link->state & DEV_CONFIG) {
-      dtl1_close(info);
-      mod_timer(&link->release, jiffies + HZ/20);
-    }
-    break;
-  case CS_EVENT_CARD_INSERTION:
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    dtl1_config(link);
-    break;
-  case CS_EVENT_PM_SUSPEND:
-    link->state |= DEV_SUSPEND;
-    /* Fall through... */
-  case CS_EVENT_RESET_PHYSICAL:
-    if (link->state & DEV_CONFIG)
-      CardServices(ReleaseConfiguration, link->handle);
-    break;
-  case CS_EVENT_PM_RESUME:
-    link->state &= ~DEV_SUSPEND;
-    /* Fall through... */
-  case CS_EVENT_CARD_RESET:
-    if (DEV_OK(link))
-      CardServices(RequestConfiguration, link->handle, &link->conf);
-    break;
-  }
-
-
-  return 0;
+int dtl1_event(event_t event, int priority, event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+	dtl1_info_t *info = link->priv;
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			dtl1_close(info);
+			mod_timer(&link->release, jiffies + HZ / 20);
+		}
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		dtl1_config(link);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		if (link->state & DEV_CONFIG)
+			CardServices(ReleaseConfiguration, link->handle);
+		break;
+	case CS_EVENT_PM_RESUME:
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		if (DEV_OK(link))
+			CardServices(RequestConfiguration, link->handle, &link->conf);
+		break;
+	}
 
+	return 0;
 }
 
 
@@ -903,33 +826,29 @@
 /* ======================== Module initialization ======================== */
 
 
-int __init init_dtl1_cs(void) {
+int __init init_dtl1_cs(void)
+{
+	servinfo_t serv;
+	int err;
 
-  servinfo_t serv;
-  int err;
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n");
+		return -1;
+	}
 
+	err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach);
 
-  CardServices(GetCardServicesInfo, &serv);
-  if (serv.Revision != CS_RELEASE_CODE) {
-    printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n");
-    return -1;
-  }
-
-
-  err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach);
-
-
-  return err;
-
+	return err;
 }
 
-void __exit exit_dtl1_cs(void) {
-
-  unregister_pccard_driver(&dev_info);
 
-  while (dev_list != NULL)
-    dtl1_detach(dev_list);
+void __exit exit_dtl1_cs(void)
+{
+	unregister_pccard_driver(&dev_info);
 
+	while (dev_list != NULL)
+		dtl1_detach(dev_list);
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/bluetooth/hci_ldisc.c linux-2.4.20/drivers/bluetooth/hci_ldisc.c
--- linux-2.4.19/drivers/bluetooth/hci_ldisc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/bluetooth/hci_ldisc.c	2002-10-29 11:18:36.000000000 +0000
@@ -33,7 +33,6 @@
 #include <linux/module.h>
 
 #include <linux/version.h>
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/bluetooth/hci_usb.c linux-2.4.20/drivers/bluetooth/hci_usb.c
--- linux-2.4.19/drivers/bluetooth/hci_usb.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/bluetooth/hci_usb.c	2002-10-29 11:18:38.000000000 +0000
@@ -28,9 +28,9 @@
  *    Copyright (c) 2000 Greg Kroah-Hartman        <greg@kroah.com>
  *    Copyright (c) 2000 Mark Douglas Corner       <mcorner@umich.edu>
  *
- * $Id: hci_usb.c,v 1.6 2002/04/17 17:37:20 maxk Exp $    
+ * $Id: hci_usb.c,v 1.8 2002/07/18 17:23:09 maxk Exp $    
  */
-#define VERSION "2.0"
+#define VERSION "2.1"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -73,7 +73,7 @@
 
 static struct usb_driver hci_usb_driver; 
 
-static struct usb_device_id usb_bluetooth_ids [] = {
+static struct usb_device_id bluetooth_ids[] = {
 	/* Generic Bluetooth USB device */
 	{ USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) },
 
@@ -83,16 +83,23 @@
 	{ }	/* Terminating entry */
 };
 
-MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids);
+MODULE_DEVICE_TABLE (usb, bluetooth_ids);
+
+static struct usb_device_id ignore_ids[] = {
+	/* Broadcom BCM2033 without firmware */
+	{ USB_DEVICE(0x0a5c, 0x2033) },
+
+	{ }	/* Terminating entry */
+};
 
 static void hci_usb_interrupt(struct urb *urb);
 static void hci_usb_rx_complete(struct urb *urb);
 static void hci_usb_tx_complete(struct urb *urb);
 
-static purb_t hci_usb_get_completed(struct hci_usb *husb)
+static struct urb *hci_usb_get_completed(struct hci_usb *husb)
 {
 	struct sk_buff *skb;
-	purb_t urb = NULL;
+	struct urb *urb = NULL;
 
 	skb = skb_dequeue(&husb->completed_q);
 	if (skb) {
@@ -194,22 +201,26 @@
 {
 	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
 	int i, err;
-	long flags;
+	unsigned long flags;
 
 	BT_DBG("%s", hdev->name);
 
 	if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
 		return 0;
 
+	MOD_INC_USE_COUNT;
+
 	write_lock_irqsave(&husb->completion_lock, flags);
 
 	err = hci_usb_enable_intr(husb);
 	if (!err) {
 		for (i = 0; i < HCI_MAX_BULK_TX; i++)
 			hci_usb_rx_submit(husb, NULL);
-	} else 
+	} else {
 		clear_bit(HCI_RUNNING, &hdev->flags);
-		
+		MOD_DEC_USE_COUNT;
+	}
+
 	write_unlock_irqrestore(&husb->completion_lock, flags);
 	return err;
 }
@@ -229,7 +240,7 @@
 static inline void hci_usb_unlink_urbs(struct hci_usb *husb)
 {
 	struct sk_buff *skb;
-	purb_t urb;
+	struct urb *urb;
 
 	BT_DBG("%s", husb->hdev.name);
 
@@ -247,7 +258,7 @@
 static int hci_usb_close(struct hci_dev *hdev)
 {
 	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-	long flags;
+	unsigned long flags;
 	
 	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
 		return 0;
@@ -261,14 +272,16 @@
 	hci_usb_flush(hdev);
 
 	write_unlock_irqrestore(&husb->completion_lock, flags);
+
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
 static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
 {
 	struct hci_usb_scb *scb = (void *) skb->cb;
-	purb_t urb = hci_usb_get_completed(husb);
-	devrequest *dr;
+	struct urb *urb = hci_usb_get_completed(husb);
+	struct usb_ctrlrequest *dr;
 	int pipe, err;
 
 	if (!urb && !(urb = usb_alloc_urb(0)))
@@ -281,11 +294,11 @@
 	
 	pipe = usb_sndctrlpipe(husb->udev, 0);
 
-	dr->requesttype = HCI_CTRL_REQ;
-	dr->request = 0;
-	dr->index   = 0;
-	dr->value   = 0;
-	dr->length  = __cpu_to_le16(skb->len);
+	dr->bRequestType = HCI_CTRL_REQ;
+	dr->bRequest = 0;
+	dr->wIndex   = 0;
+	dr->wValue   = 0;
+	dr->wLength  = __cpu_to_le16(skb->len);
 
 	FILL_CONTROL_URB(urb, husb->udev, pipe, (void *) dr,
 			skb->data, skb->len, hci_usb_tx_complete, skb);
@@ -308,7 +321,7 @@
 static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
 {
 	struct hci_usb_scb *scb = (void *) skb->cb;
-	purb_t urb = hci_usb_get_completed(husb);
+	struct urb *urb = hci_usb_get_completed(husb);
 	int pipe, err;
 
 	if (!urb && !(urb = usb_alloc_urb(0)))
@@ -588,76 +601,9 @@
 
 	husb = (struct hci_usb *) hdev->driver_data;
 	kfree(husb);
-
-	MOD_DEC_USE_COUNT;
-}
-
-#ifdef CONFIG_BLUEZ_USB_FW_LOAD
-
-/* Support for user mode Bluetooth USB firmware loader */
-
-#define FW_LOADER "/sbin/bluefw"
-static int errno;
-
-static int hci_usb_fw_exec(void *dev)
-{
-	char *envp[] = { "HOME=/", "TERM=linux", 
-			 "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
-	char *argv[] = { FW_LOADER, dev, NULL };
-	int err;
-
-	err = exec_usermodehelper(FW_LOADER, argv, envp);
-	if (err)
-		BT_ERR("failed to exec %s %s", FW_LOADER, (char *)dev);
-	return err;
 }
 
-static int hci_usb_fw_load(struct usb_device *udev)
-{
-	sigset_t tmpsig;
-	char dev[16];
-	pid_t pid;
-	int result;
-
-	/* Check if root fs is mounted */
-	if (!current->fs->root) {
-		BT_ERR("root fs not mounted");
-		return -EPERM;
-	}
-
-	sprintf(dev, "%3.3d/%3.3d", udev->bus->busnum, udev->devnum);
-
-	pid = kernel_thread(hci_usb_fw_exec, (void *)dev, 0);
-	if (pid < 0) {
-		BT_ERR("fork failed, errno %d\n", -pid);
-		return pid;
-	}
-
-	/* Block signals, everything but SIGKILL/SIGSTOP */
-	spin_lock_irq(&current->sigmask_lock);
-	tmpsig = current->blocked;
-	siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
-	recalc_sigpending(current);
-	spin_unlock_irq(&current->sigmask_lock);
-
-	result = waitpid(pid, NULL, __WCLONE);
-
-	/* Allow signals again */
-	spin_lock_irq(&current->sigmask_lock);
-	current->blocked = tmpsig;
-	recalc_sigpending(current);
-	spin_unlock_irq(&current->sigmask_lock);
-
-	if (result != pid) {
-		BT_ERR("waitpid failed pid %d errno %d\n", pid, -result);
-		return -result;
-	}
-	return 0;
-}
-
-#endif /* CONFIG_BLUEZ_USB_FW_LOAD */
-
-static void * hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
+static void *hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
 {
 	struct usb_endpoint_descriptor *bulk_out_ep[HCI_MAX_IFACE_NUM];
 	struct usb_endpoint_descriptor *isoc_out_ep[HCI_MAX_IFACE_NUM];
@@ -673,16 +619,16 @@
 
 	BT_DBG("udev %p ifnum %d", udev, ifnum);
 
+	iface = &udev->actconfig->interface[0];
+
+	/* Check our black list */
+	if (usb_match_id(udev, iface, ignore_ids))
+		return NULL;
+
 	/* Check number of endpoints */
 	if (udev->actconfig->interface[ifnum].altsetting[0].bNumEndpoints < 3)
 		return NULL;
 
-	MOD_INC_USE_COUNT;
-
-#ifdef CONFIG_BLUEZ_USB_FW_LOAD
-	hci_usb_fw_load(udev);
-#endif
-
 	memset(bulk_out_ep, 0, sizeof(bulk_out_ep));
 	memset(isoc_out_ep, 0, sizeof(isoc_out_ep));
 	memset(bulk_in_ep,  0, sizeof(bulk_in_ep));
@@ -801,7 +747,6 @@
 	kfree(husb);
 
 done:
-	MOD_DEC_USE_COUNT;
 	return NULL;
 }
 
@@ -828,7 +773,7 @@
 	name:           "hci_usb",
 	probe:          hci_usb_probe,
 	disconnect:     hci_usb_disconnect,
-	id_table:       usb_bluetooth_ids,
+	id_table:       bluetooth_ids,
 };
 
 int hci_usb_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/bluetooth/hci_usb.h linux-2.4.20/drivers/bluetooth/hci_usb.h
--- linux-2.4.19/drivers/bluetooth/hci_usb.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/bluetooth/hci_usb.h	2002-10-29 11:18:32.000000000 +0000
@@ -55,7 +55,7 @@
 
 	__u8			intr_ep;
 	__u8			intr_interval;
-	purb_t			intr_urb;
+	struct urb		*intr_urb;
 	struct sk_buff *	intr_skb;
 
 	rwlock_t		completion_lock;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/cdrom/cdrom.c linux-2.4.20/drivers/cdrom/cdrom.c
--- linux-2.4.19/drivers/cdrom/cdrom.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/cdrom/cdrom.c	2002-10-29 11:18:33.000000000 +0000
@@ -1916,6 +1916,7 @@
 {		
 	struct cdrom_device_ops *cdo = cdi->ops;
 	struct cdrom_generic_command cgc;
+	struct request_sense sense;
 	kdev_t dev = cdi->dev;
 	char buffer[32];
 	int ret = 0;
@@ -1951,9 +1952,11 @@
 		cgc.buffer = (char *) kmalloc(blocksize, GFP_KERNEL);
 		if (cgc.buffer == NULL)
 			return -ENOMEM;
+		memset(&sense, 0, sizeof(sense));
+		cgc.sense = &sense;
 		cgc.data_direction = CGC_DATA_READ;
 		ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize);
-		if (ret) {
+		if (ret && sense.sense_key==0x05 && sense.asc==0x20 && sense.ascq==0x00) {
 			/*
 			 * SCSI-II devices are not required to support
 			 * READ_CD, so let's try switching block size
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/cdrom/cdu31a.c linux-2.4.20/drivers/cdrom/cdu31a.c
--- linux-2.4.19/drivers/cdrom/cdu31a.c	2001-10-25 20:58:35.000000000 +0000
+++ linux-2.4.20/drivers/cdrom/cdu31a.c	2002-10-29 11:18:33.000000000 +0000
@@ -3385,7 +3385,8 @@
 	if (drive_found) {
 		int deficiency = 0;
 
-		request_region(cdu31a_port, 4, "cdu31a");
+		if (!request_region(cdu31a_port, 4, "cdu31a"))
+			goto errout3;
 
 		if (devfs_register_blkdev(MAJOR_NR, "cdu31a", &scd_bdops)) {
 			printk("Unable to get major %d for CDU-31a\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/ChangeLog linux-2.4.20/drivers/char/ChangeLog
--- linux-2.4.19/drivers/char/ChangeLog	2001-08-13 23:37:33.000000000 +0000
+++ linux-2.4.20/drivers/char/ChangeLog	2002-10-29 11:18:48.000000000 +0000
@@ -550,7 +550,7 @@
 		the StarTech 16650 chip.  Treat it as a 16450 for now,
 		because of its FIFO bugs.
 
-Thu Jan  5 21:21:57 1995  <dhinds@allegro.stanford.edu>
+Thu Jan  5 21:21:57 1995  <dahinds@users.sourceforge.net>
 
 	* serial.c: (receive_char): Added counter to prevent infinite loop
 		when a PCMCIA serial device is ejected.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/Config.in linux-2.4.20/drivers/char/Config.in
--- linux-2.4.19/drivers/char/Config.in	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/Config.in	2002-10-29 11:18:34.000000000 +0000
@@ -7,10 +7,16 @@
 bool 'Virtual terminal' CONFIG_VT
 if [ "$CONFIG_VT" = "y" ]; then
    bool '  Support for console on virtual terminal' CONFIG_VT_CONSOLE
+   if [ "$CONFIG_GSC_LASI" = "y" ]; then
+      bool '    Support for Lasi/Dino PS2 port' CONFIG_GSC_PS2
+   fi
 fi
 tristate 'Standard/generic (8250/16550 and compatible UARTs) serial support' CONFIG_SERIAL
 if [ "$CONFIG_SERIAL" = "y" ]; then
    bool '  Support for console on serial port' CONFIG_SERIAL_CONSOLE
+   if [ "$CONFIG_GSC_LASI" = "y" ]; then
+      bool '   serial port on GSC support' CONFIG_SERIAL_GSC
+   fi
    if [ "$CONFIG_IA64" = "y" ]; then
       bool 'Support for serial console port described by EFI HCDP table' CONFIG_SERIAL_HCDP
    fi
@@ -35,27 +41,32 @@
    if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_CYCLADES" != "n" ]; then
       bool '    Cyclades-Z interrupt mode operation (EXPERIMENTAL)' CONFIG_CYZ_INTR
    fi
-   tristate '  Digiboard Intelligent Async Support' CONFIG_DIGIEPCA
-   if [ "$CONFIG_DIGIEPCA" = "n" ]; then
-      tristate '  Digiboard PC/Xx Support' CONFIG_DIGI
+   if [ "$CONFIG_X86_64" != "y" ]; then
+      tristate '  Digiboard Intelligent Async Support' CONFIG_DIGIEPCA
+      if [ "$CONFIG_DIGIEPCA" = "n" ]; then
+         tristate '  Digiboard PC/Xx Support' CONFIG_DIGI
+      fi
    fi
-   tristate '  Hayes ESP serial port support' CONFIG_ESPSERIAL
+   dep_tristate '  Hayes ESP serial port support' CONFIG_ESPSERIAL $CONFIG_ISA
    tristate '  Moxa Intellio support' CONFIG_MOXA_INTELLIO
    tristate '  Moxa SmartIO support' CONFIG_MOXA_SMARTIO
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       dep_tristate '  Multi-Tech multiport card support (EXPERIMENTAL)' CONFIG_ISI m
    fi
    tristate '  Microgate SyncLink card support' CONFIG_SYNCLINK
+   tristate '  SyncLink Multiport support' CONFIG_SYNCLINKMP
    tristate '  HDLC line discipline support' CONFIG_N_HDLC
    tristate '  SDL RISCom/8 card support' CONFIG_RISCOM8
-   tristate '  Specialix IO8+ card support' CONFIG_SPECIALIX
-   if [ "$CONFIG_SPECIALIX" != "n" ]; then
-      bool '  Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS
-   fi 
-   tristate '  Specialix SX (and SI) card support' CONFIG_SX
-   tristate '  Specialix RIO system support' CONFIG_RIO
-   if [ "$CONFIG_RIO" != "n" ]; then
-     bool '    Support really old RIO/PCI cards' CONFIG_RIO_OLDPCI
+   if [ "$CONFIG_X86_64" != "y" ]; then
+      tristate '  Specialix IO8+ card support' CONFIG_SPECIALIX
+      if [ "$CONFIG_SPECIALIX" != "n" ]; then
+         bool '  Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS
+      fi 
+      tristate '  Specialix SX (and SI) card support' CONFIG_SX
+      tristate '  Specialix RIO system support' CONFIG_RIO
+      if [ "$CONFIG_RIO" != "n" ]; then
+        bool '    Support really old RIO/PCI cards' CONFIG_RIO_OLDPCI
+      fi
    fi
    bool '  Stallion multiport serial support' CONFIG_STALDRV
    if [ "$CONFIG_STALDRV" = "y" ]; then
@@ -105,6 +116,9 @@
          bool '        Enable Au1000 serial console' CONFIG_AU1000_SERIAL_CONSOLE
      fi
    fi
+   if [ "$CONFIG_PARISC" = "y" ]; then
+     bool '  PDC software console support' CONFIG_PDC_CONSOLE
+   fi
 fi
 if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then
    bool 'Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD
@@ -135,6 +149,10 @@
    dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
 fi
 
+if [ "$CONFIG_PPC64" ] ; then 
+bool 'pSeries Hypervisor Virtual Console support' CONFIG_HVC_CONSOLE
+fi
+
 source drivers/i2c/Config.in
 
 mainmenu_option next_comment
@@ -209,6 +227,7 @@
       fi
    fi
    tristate '  ZF MachZ Watchdog' CONFIG_MACHZ_WDT
+   dep_tristate '  AMD 766/768 TCO Timer/Watchdog' CONFIG_AMD7XX_TCO $CONFIG_EXPERIMENTAL
 fi
 endmenu
 
@@ -233,14 +252,14 @@
    bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC
 fi
 if [ "$CONFIG_OBSOLETE" = "y" -a "$CONFIG_ALPHA_BOOK1" = "y" ]; then
-   bool 'Tadpole ANA H8 Support'  CONFIG_H8
+   bool 'Tadpole ANA H8 Support (OBSOLETE)'  CONFIG_H8
 fi
 
 tristate 'Double Talk PC internal speech card support' CONFIG_DTLK
 tristate 'Siemens R3964 line discipline' CONFIG_R3964
 tristate 'Applicom intelligent fieldbus card support' CONFIG_APPLICOM
-if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_X86" = "y" ]; then
-   dep_tristate 'Sony Vaio Programmable I/O Control Device support' CONFIG_SONYPI $CONFIG_PCI
+if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_X86" = "y" -a "$CONFIG_X86_64" != "y" ]; then
+   dep_tristate 'Sony Vaio Programmable I/O Control Device support (EXPERIMENTAL)' CONFIG_SONYPI $CONFIG_PCI
 fi
 
 mainmenu_option next_comment
@@ -251,12 +270,20 @@
 fi
 endmenu
 
-tristate '/dev/agpgart (AGP Support)' CONFIG_AGP
+if [ "$CONFIG_GART_IOMMU" = "y" ]; then
+	bool '/dev/agpgart (AGP Support)' CONFIG_AGP
+	define_bool CONFIG_AGP_AMD_8151 y
+else
+	tristate '/dev/agpgart (AGP Support)' CONFIG_AGP
+fi      
 if [ "$CONFIG_AGP" != "n" ]; then
    bool '  Intel 440LX/BX/GX and I815/I820/I830M/I830MP/I840/I845/I850/I860 support' CONFIG_AGP_INTEL
    bool '  Intel I810/I815/I830M (on-board) support' CONFIG_AGP_I810
    bool '  VIA chipset support' CONFIG_AGP_VIA
    bool '  AMD Irongate, 761, and 762 support' CONFIG_AGP_AMD
+   if [ "$CONFIG_GART_IOMMU" != "y" ]; then
+      bool '  AMD 8151 support' CONFIG_AGP_AMD_8151
+   fi   
    bool '  Generic SiS support' CONFIG_AGP_SIS
    bool '  ALI chipset support' CONFIG_AGP_ALI
    bool '  Serverworks LE/HE support' CONFIG_AGP_SWORKS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/Makefile linux-2.4.20/drivers/char/Makefile
--- linux-2.4.19/drivers/char/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/Makefile	2002-10-29 11:18:39.000000000 +0000
@@ -24,7 +24,7 @@
 export-objs     :=	busmouse.o console.o keyboard.o sysrq.o \
 			misc.o pty.o random.o selection.o serial.o \
 			sonypi.o tty_io.o tty_ioctl.o generic_serial.o \
-			au1000_gpio.o
+			au1000_gpio.o hp_psaux.o nvram.o
 
 mod-subdirs	:=	joystick ftape drm drm-4.0 pcmcia
 
@@ -71,6 +71,21 @@
   SERIAL = serial.o
 endif
 
+ifdef CONFIG_APOLLO
+  KEYBD += dn_keyb.o
+endif
+
+ifeq ($(ARCH),parisc)
+   ifdef CONFIG_GSC_PS2
+      KEYBD   = hp_psaux.o hp_keyb.o
+   else
+      KEYBD   =
+   endif
+   ifdef CONFIG_PDC_CONSOLE
+      CONSOLE += pdc_console.o
+   endif
+endif
+
 ifeq ($(ARCH),arm)
   ifneq ($(CONFIG_PC_KEYMAP),y)
     KEYMAP   =
@@ -150,6 +165,7 @@
   obj-$(CONFIG_PCI) += keyboard.o $(KEYMAP)
 endif
 
+obj-$(CONFIG_HIL) += hp_keyb.o
 obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
 obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
 obj-$(CONFIG_ROCKETPORT) += rocket.o
@@ -166,6 +182,7 @@
 obj-$(CONFIG_ISI) += isicom.o
 obj-$(CONFIG_ESPSERIAL) += esp.o
 obj-$(CONFIG_SYNCLINK) += synclink.o
+obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o
 obj-$(CONFIG_N_HDLC) += n_hdlc.o
 obj-$(CONFIG_SPECIALIX) += specialix.o
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
@@ -177,6 +194,7 @@
 obj-$(CONFIG_MVME147_SCC) += generic_serial.o vme_scc.o
 obj-$(CONFIG_MVME162_SCC) += generic_serial.o vme_scc.o
 obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o
+obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o
 obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o
 obj-$(CONFIG_TXX927_SERIAL) += serial_txx927.o
 
@@ -258,10 +276,12 @@
 obj-$(CONFIG_SH_WDT) += shwdt.o
 obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
 obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
+#obj-$(CONFIG_ALIM1535_WDT) += alim1535d_wdt.o
 obj-$(CONFIG_INDYDOG) += indydog.o
 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
 obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
 obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
+obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o
 
 subdir-$(CONFIG_MWAVE) += mwave
 ifeq ($(CONFIG_MWAVE),y)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/acquirewdt.c linux-2.4.20/drivers/char/acquirewdt.c
--- linux-2.4.19/drivers/char/acquirewdt.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/acquirewdt.c	2002-10-29 11:18:48.000000000 +0000
@@ -17,6 +17,9 @@
  *
  *	(c) Copyright 1995    Alan Cox <alan@redhat.com>
  *
+ *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ *          Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ *          Can't add timeout - driver doesn't allow changing value
  */
 
 #include <linux/config.h>
@@ -42,6 +45,7 @@
 
 static int acq_is_open;
 static spinlock_t acq_lock;
+static int expect_close = 0;
 
 /*
  *	You must set these - there is no sane way to probe for this board.
@@ -50,8 +54,14 @@
 #define WDT_STOP 0x43
 #define WDT_START 0x443
 
-#define WD_TIMO (100*60)		/* 1 minute */
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
 
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
 /*
  *	Kernel methods.
@@ -72,6 +82,21 @@
 
 	if(count)
 	{
+		if (!nowayout)
+		{
+			size_t i;
+
+			expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
+
 		acq_ping();
 		return 1;
 	}
@@ -90,7 +115,7 @@
 {
 	static struct watchdog_info ident=
 	{
-		WDIOF_KEEPALIVEPING, 1, "Acquire WDT"
+		WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 1, "Acquire WDT"
 	};
 	
 	switch(cmd)
@@ -126,10 +151,12 @@
 				spin_unlock(&acq_lock);
 				return -EBUSY;
 			}
+			if (nowayout) {
+				MOD_INC_USE_COUNT;
+			}
 			/*
 			 *	Activate 
 			 */
-	 
 			acq_is_open=1;
 			inb_p(WDT_START);      
 			spin_unlock(&acq_lock);
@@ -145,9 +172,14 @@
 	if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
 	{
 		spin_lock(&acq_lock);
-#ifndef CONFIG_WATCHDOG_NOWAYOUT	
-		inb_p(WDT_STOP);
-#endif		
+		if (expect_close)
+		{
+			inb_p(WDT_STOP);
+		}
+		else
+		{
+			printk(KERN_CRIT "WDT closed unexpectedly.  WDT will not stop!\n");
+		}
 		acq_is_open=0;
 		spin_unlock(&acq_lock);
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/advantechwdt.c linux-2.4.20/drivers/char/advantechwdt.c
--- linux-2.4.19/drivers/char/advantechwdt.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/advantechwdt.c	2002-10-29 11:18:38.000000000 +0000
@@ -20,6 +20,8 @@
  *
  *	(c) Copyright 1995    Alan Cox <alan@redhat.com>
  *
+ *	14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ *	    Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  */
 
 #include <linux/config.h>
@@ -57,6 +59,15 @@
 
 static int wd_margin = 60; /* 60 sec default timeout */
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 /*
  *	Kernel methods.
  */
@@ -108,17 +119,20 @@
 		return -ESPIPE;
 
 	if (count) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-		size_t i;
+		if (!nowayout) {
+			size_t i;
 
-		adv_expect_close = 0;
-
-		for (i = 0; i != count; i++) {
-			if (buf[i] == 'V')
-				adv_expect_close = 42;
+			adv_expect_close = 0;
+	
+			for (i = 0; i != count; i++) {
+				char c;
+				if(get_user(c, buf+i))
+					return -EFAULT;
+				if (c == 'V')
+					adv_expect_close = 42;
+			}
 		}
-#endif
-		advwdt_ping();
+			advwdt_ping();
 	}
 	return count;
 }
@@ -129,7 +143,7 @@
 {
 	int new_margin;
 	static struct watchdog_info ident = {
-		options:		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+		options:		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
 		firmware_version:	0,
 		identity:		"Advantech WDT"
 	};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/agp/agp.h linux-2.4.20/drivers/char/agp/agp.h
--- linux-2.4.19/drivers/char/agp/agp.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/agp/agp.h	2002-10-29 11:18:39.000000000 +0000
@@ -84,8 +84,8 @@
 	void *dev_private_data;
 	struct pci_dev *dev;
 	gatt_mask *masks;
-	unsigned long *gatt_table;
-	unsigned long *gatt_table_real;
+	u32 *gatt_table;
+	u32 *gatt_table_real;
 	unsigned long scratch_page;
 	unsigned long gart_bus_addr;
 	unsigned long gatt_bus_addr;
@@ -238,6 +238,9 @@
 #ifndef PCI_DEVICE_ID_AMD_762_0
 #define PCI_DEVICE_ID_AMD_762_0		0x700C
 #endif
+#ifndef PCI_DEVICE_ID_AMD_8151_0
+#define PCI_DEVICE_ID_AMD_8151_0	0x7454
+#endif
 #ifndef PCI_VENDOR_ID_AL
 #define PCI_VENDOR_ID_AL		0x10b9
 #endif
@@ -364,6 +367,22 @@
 #define AMD_TLBFLUSH    0x0c	/* In mmio region (32-bit register) */
 #define AMD_CACHEENTRY  0x10	/* In mmio region (32-bit register) */
 
+#define AMD_8151_APSIZE	0xb4
+#define AMD_8151_GARTBLOCK	0xb8
+
+#define AMD_X86_64_GARTAPERTURECTL	0x90
+#define AMD_X86_64_GARTAPERTUREBASE	0x94
+#define AMD_X86_64_GARTTABLEBASE	0x98
+#define AMD_X86_64_GARTCACHECTL		0x9c
+#define AMD_X86_64_GARTEN	1<<0
+
+#define AMD_8151_VMAPERTURE		0x10
+#define AMD_8151_AGP_CTL		0xb0
+#define AMD_8151_APERTURESIZE	0xb4
+#define AMD_8151_GARTPTR		0xb8
+#define AMD_8151_GTLBEN	1<<7
+#define AMD_8151_APEREN	1<<8
+
 /* ALi registers */
 #define ALI_APBASE	0x10
 #define ALI_AGPCTRL	0xb8
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/agp/agpgart_be.c linux-2.4.20/drivers/char/agp/agpgart_be.c
--- linux-2.4.19/drivers/char/agp/agpgart_be.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/agp/agpgart_be.c	2002-10-29 11:18:33.000000000 +0000
@@ -64,6 +64,8 @@
 static struct agp_bridge_data agp_bridge;
 static int agp_try_unsupported __initdata = 0;
 
+int agp_memory_reserved;
+__u32 *agp_gatt_table;
 
 static inline void flush_cache(void)
 {
@@ -300,12 +302,14 @@
 		break;
 	}
 
+	current_size -= (agp_memory_reserved / (1024*1024));
+
 	return current_size;
 }
 
 /* Routine to copy over information structure */
 
-void agp_copy_info(agp_kern_info * info)
+int agp_copy_info(agp_kern_info * info)
 {
 	unsigned long page_mask = 0;
 	int i;
@@ -313,7 +317,7 @@
 	memset(info, 0, sizeof(agp_kern_info));
 	if (agp_bridge.type == NOT_SUPPORTED) {
 		info->chipset = agp_bridge.type;
-		return;
+		return -1;
 	}
 	info->version.major = agp_bridge.version->major;
 	info->version.minor = agp_bridge.version->minor;
@@ -330,6 +334,7 @@
 		page_mask |= agp_bridge.mask_memory(page_mask, i);
 
 	info->page_mask = ~page_mask;
+	return 0;
 }
 
 /* End - Routine to copy over information structure */
@@ -397,7 +402,7 @@
 static void agp_generic_agp_enable(u32 mode)
 {
 	struct pci_dev *device = NULL;
-	u32 command, scratch, cap_id;
+	u32 command, scratch;
 	u8 cap_ptr;
 
 	pci_read_config_dword(agp_bridge.dev,
@@ -497,6 +502,7 @@
 	int i;
 	void *temp;
 	struct page *page;
+	int err = 0;
 
 	/* The generic routines can't handle 2 level gatt's */
 	if (agp_bridge.size_type == LVL2_APER_SIZE) {
@@ -561,6 +567,7 @@
 					    agp_bridge.current_size;
 					break;
 				}
+				temp = agp_bridge.current_size;
 			} else {
 				agp_bridge.aperture_size_idx = i;
 			}
@@ -582,12 +589,16 @@
 		SetPageReserved(page);
 
 	agp_bridge.gatt_table_real = (unsigned long *) table;
-	CACHE_FLUSH();
+	agp_gatt_table = (void *)table;
+#ifdef CONFIG_X86
+	err = change_page_attr(virt_to_page(table), 1<<page_order, PAGE_KERNEL_NOCACHE);
+#endif
+	if (!err) 
 	agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table),
 					(PAGE_SIZE * (1 << page_order)));
 	CACHE_FLUSH();
 
-	if (agp_bridge.gatt_table == NULL) {
+	if (agp_bridge.gatt_table == NULL || err) {
 		for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
 			ClearPageReserved(page);
 
@@ -651,6 +662,10 @@
 	 * from the table.
 	 */
 
+#ifdef CONFIG_X86
+	change_page_attr(virt_to_page(agp_bridge.gatt_table_real), 1<<page_order, 
+			 PAGE_KERNEL);
+#endif
 	iounmap(agp_bridge.gatt_table);
 	table = (char *) agp_bridge.gatt_table_real;
 	table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
@@ -692,6 +707,9 @@
 		break;
 	}
 
+	num_entries -= agp_memory_reserved/PAGE_SIZE;
+	if (num_entries < 0) num_entries = 0;
+
 	if (type != 0 || mem->type != 0) {
 		/* The generic routines know nothing of memory types */
 		return -EINVAL;
@@ -769,6 +787,12 @@
 	if (page == NULL) {
 		return 0;
 	}
+#ifdef CONFIG_X86
+	if (change_page_attr(page, 1, PAGE_KERNEL_NOCACHE) < 0) {
+		__free_page(page); 
+		return 0;
+	}
+#endif
 	get_page(page);
 	LockPage(page);
 	atomic_inc(&agp_bridge.current_memory_agp);
@@ -785,6 +809,9 @@
 	}
 	
 	page = virt_to_page(pt);
+#ifdef CONFIG_X86
+	change_page_attr(page, 1, PAGE_KERNEL); 
+#endif	
 	put_page(page);
 	UnlockPage(page);
 	free_page((unsigned long) pt);
@@ -1406,7 +1433,7 @@
         /* Intel 815 chipsets have a _weird_ APSIZE register with only
          * one non-reserved bit, so mask the others out ... */
         if (agp_bridge.type == INTEL_I815) 
-          temp &= (1 << 3);
+		temp &= (1 << 3);
         
 	values = A_SIZE_8(agp_bridge.aperture_sizes);
 
@@ -1686,6 +1713,12 @@
 	return 0;
 }
 
+static void intel_845_resume(void)
+{
+   intel_845_configure();
+}
+
+
 static int intel_850_configure(void)
 {
 	u32 temp;
@@ -1994,7 +2027,7 @@
 	agp_bridge.agp_alloc_page = agp_generic_alloc_page;
 	agp_bridge.agp_destroy_page = agp_generic_destroy_page;
 	agp_bridge.suspend = agp_generic_suspend;
-	agp_bridge.resume = agp_generic_resume;
+	agp_bridge.resume = intel_845_resume;
 	agp_bridge.cant_use_aperture = 0;
 
 	return 0;
@@ -2318,6 +2351,7 @@
 static int amd_create_page_map(amd_page_map *page_map)
 {
 	int i;
+	int err = 0;
 
 	page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
 	if (page_map->real == NULL) {
@@ -2325,9 +2359,13 @@
 	}
 	SetPageReserved(virt_to_page(page_map->real));
 	CACHE_FLUSH();
+#ifdef CONFIG_X86
+	err = change_page_attr(virt_to_page(page_map->real), 1, PAGE_KERNEL_NOCACHE);
+#endif
+	if (!err) 
 	page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), 
 					    PAGE_SIZE);
-	if (page_map->remapped == NULL) {
+	if (page_map->remapped == NULL || err) {
 		ClearPageReserved(virt_to_page(page_map->real));
 		free_page((unsigned long) page_map->real);
 		page_map->real = NULL;
@@ -2345,6 +2383,9 @@
 static void amd_free_page_map(amd_page_map *page_map)
 {
 	iounmap(page_map->remapped);
+#ifdef CONFIG_X86
+	change_page_attr(virt_to_page(page_map->real), 1, PAGE_KERNEL);
+#endif
 	ClearPageReserved(virt_to_page(page_map->real));
 	free_page((unsigned long) page_map->real);
 }
@@ -2680,6 +2721,472 @@
 
 #endif /* CONFIG_AGP_AMD */
 
+#ifdef CONFIG_AGP_AMD_8151
+
+/* Begin AMD-8151 support */
+
+static u_int64_t pci_read64 (struct pci_dev *dev, int reg)
+{
+	union {
+		u64 full;
+		struct {
+			u32 high;
+			u32 low;
+		} split;
+	} tmp;
+	pci_read_config_dword(dev, reg, &tmp.split.high);
+	pci_read_config_dword(dev, reg+4, &tmp.split.low);
+	return tmp.full;
+}
+
+static void pci_write64 (struct pci_dev *dev, int reg, u64 value)
+{
+	union {
+		u64 full;
+		struct {
+			u32 high;
+			u32 low;
+		} split;
+	} tmp;
+	tmp.full = value;
+	pci_write_config_dword(dev, reg, tmp.split.high);
+	pci_write_config_dword(dev, reg+4, tmp.split.low);
+}
+
+
+static int x86_64_insert_memory(agp_memory * mem, off_t pg_start, int type)
+{
+	int i, j, num_entries;
+	void *temp;
+	long tmp;
+	u32 pte;
+	u64 addr;
+
+	temp = agp_bridge.current_size;
+
+	num_entries = A_SIZE_32(temp)->num_entries;
+
+	num_entries -= agp_memory_reserved>>PAGE_SHIFT;
+
+	if (type != 0 || mem->type != 0)
+		return -EINVAL;
+
+	/* Make sure we can fit the range in the gatt table. */
+	if ((pg_start + mem->page_count) > num_entries)
+		return -EINVAL;
+
+	j = pg_start;
+
+	/* gatt table should be empty. */
+	while (j < (pg_start + mem->page_count)) {
+		if (!PGE_EMPTY(agp_bridge.gatt_table[j]))
+			return -EBUSY;
+		j++;
+	}
+
+	if (mem->is_flushed == FALSE) {
+		CACHE_FLUSH();
+		mem->is_flushed = TRUE;
+	}
+
+	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+		addr = mem->memory[i];
+
+		tmp = addr;
+		BUG_ON(tmp & 0xffffff0000000ffc);
+		pte = (tmp & 0x000000ff00000000) >> 28;
+		pte |=(tmp & 0x00000000fffff000);
+		pte |= 1<<1|1<<0;
+
+		agp_bridge.gatt_table[j] = pte;
+	}
+	agp_bridge.tlb_flush(mem);
+	return 0;
+}
+
+/*
+ * This hack alters the order element according
+ * to the size of a long. It sucks. I totally disown this, even
+ * though it does appear to work for the most part.
+ */
+static aper_size_info_32 x86_64_aperture_sizes[7] =
+{
+	{32,   8192,   3+(sizeof(long)/8), 0 },
+	{64,   16384,  4+(sizeof(long)/8), 1<<1 },
+	{128,  32768,  5+(sizeof(long)/8), 1<<2 },
+	{256,  65536,  6+(sizeof(long)/8), 1<<1 | 1<<2 },
+	{512,  131072, 7+(sizeof(long)/8), 1<<3 },
+	{1024, 262144, 8+(sizeof(long)/8), 1<<1 | 1<<3},
+	{2048, 524288, 9+(sizeof(long)/8), 1<<2 | 1<<3}
+};
+
+
+/*
+ * Get the current Aperture size from the x86-64.
+ * Note, that there may be multiple x86-64's, but we just return
+ * the value from the first one we find. The set_size functions
+ * keep the rest coherent anyway. Or at least should do.
+ */
+static int amd_x86_64_fetch_size(void)
+{
+	struct pci_dev *dev;
+	int i;
+	u32 temp;
+	aper_size_info_32 *values;
+
+	pci_for_each_dev(dev) {
+		if (dev->bus->number==0 &&
+			PCI_FUNC(dev->devfn)==3 &&
+			PCI_SLOT(dev->devfn)>=24 && PCI_SLOT(dev->devfn)<=31) {
+
+			pci_read_config_dword(dev, AMD_X86_64_GARTAPERTURECTL, &temp);
+			temp = (temp & 0xe);
+			values = A_SIZE_32(x86_64_aperture_sizes);
+
+			for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+				if (temp == values[i].size_value) {
+					agp_bridge.previous_size =
+					    agp_bridge.current_size = (void *) (values + i);
+
+					agp_bridge.aperture_size_idx = i;
+					return values[i].size;
+				}
+			}
+		}
+	}
+	/* erk, couldn't find an x86-64 ? */
+	return 0;
+}
+
+
+static void inline flush_x86_64_tlb(struct pci_dev *dev)
+{
+	u32 tmp;
+
+	pci_read_config_dword (dev, AMD_X86_64_GARTCACHECTL, &tmp);
+	tmp |= 1<<0;
+	pci_write_config_dword (dev, AMD_X86_64_GARTCACHECTL, tmp);
+}
+
+
+void amd_x86_64_tlbflush(agp_memory * temp)
+{
+	struct pci_dev *dev;
+
+	pci_for_each_dev(dev) {
+		if (dev->bus->number==0 && PCI_FUNC(dev->devfn)==3 &&
+		    PCI_SLOT(dev->devfn) >=24 && PCI_SLOT(dev->devfn) <=31) {
+			flush_x86_64_tlb (dev);
+		}
+	}
+}
+
+
+/*
+ * In a multiprocessor x86-64 system, this function gets
+ * called once for each CPU.
+ */
+u64 amd_x86_64_configure (struct pci_dev *hammer, u64 gatt_table)
+{
+	u64 aperturebase;
+	u32 tmp;
+	u64 addr, aper_base;
+
+	/* Address to map to */
+	pci_read_config_dword (hammer, AMD_X86_64_GARTAPERTUREBASE, &tmp);
+	aperturebase = tmp << 25;
+	aper_base = (aperturebase & PCI_BASE_ADDRESS_MEM_MASK);
+
+	/* address of the mappings table */
+	addr = (u64) gatt_table;
+	addr >>= 12;
+	tmp = (u32) addr<<4;
+	tmp &= ~0xf;
+	pci_write_config_dword (hammer, AMD_X86_64_GARTTABLEBASE, tmp);
+
+	/* Enable GART translation for this hammer. */
+	pci_read_config_dword(hammer, AMD_X86_64_GARTAPERTURECTL, &tmp);
+	tmp &= 0x3f;
+	tmp |= 1<<0;
+	pci_write_config_dword(hammer, AMD_X86_64_GARTAPERTURECTL, tmp);
+
+	/* keep CPU's coherent. */
+	flush_x86_64_tlb (hammer);
+	
+	return aper_base;
+}
+
+
+static aper_size_info_32 amd_8151_sizes[7] =
+{
+	{2048, 524288, 9, 0x00000000 },	/* 0 0 0 0 0 0 */
+	{1024, 262144, 8, 0x00000400 },	/* 1 0 0 0 0 0 */
+	{512,  131072, 7, 0x00000600 },	/* 1 1 0 0 0 0 */
+	{256,  65536,  6, 0x00000700 },	/* 1 1 1 0 0 0 */
+	{128,  32768,  5, 0x00000720 },	/* 1 1 1 1 0 0 */
+	{64,   16384,  4, 0x00000730 },	/* 1 1 1 1 1 0 */
+	{32,   8192,   3, 0x00000738 } 	/* 1 1 1 1 1 1 */
+};
+
+static int amd_8151_configure(void)
+{
+	struct pci_dev *dev, *hammer=NULL;
+	int current_size;
+	int tmp, tmp2, i;
+	u64 aperbar;
+	unsigned long gatt_bus = virt_to_phys(agp_bridge.gatt_table_real);
+
+	/* Configure AGP regs in each x86-64 host bridge. */
+	pci_for_each_dev(dev) {
+		if (dev->bus->number==0 &&
+			PCI_FUNC(dev->devfn)==3 &&
+			PCI_SLOT(dev->devfn)>=24 && PCI_SLOT(dev->devfn)<=31) {
+			agp_bridge.gart_bus_addr = amd_x86_64_configure(dev,gatt_bus);
+			hammer = dev;
+
+			/*
+			 * TODO: Cache pci_dev's of x86-64's in private struct to save us
+			 * having to scan the pci list each time.
+			 */
+		}
+	}
+
+	if (hammer == NULL) {
+		return -ENODEV;
+	}
+
+	/* Shadow x86-64 registers into 8151 registers. */
+
+	dev = agp_bridge.dev;
+	if (!dev) 
+		return -ENODEV;
+
+	current_size = amd_x86_64_fetch_size();
+
+	pci_read_config_dword(dev, AMD_8151_APERTURESIZE, &tmp);
+	tmp &= ~(0xfff);
+
+	/* translate x86-64 size bits to 8151 size bits*/
+	for (i=0 ; i<7; i++) {
+		if (amd_8151_sizes[i].size == current_size)
+			tmp |= (amd_8151_sizes[i].size_value) << 3;
+	}
+	pci_write_config_dword(dev, AMD_8151_APERTURESIZE, tmp);
+
+	pci_read_config_dword (hammer, AMD_X86_64_GARTAPERTUREBASE, &tmp);
+	aperbar = pci_read64 (dev, AMD_8151_VMAPERTURE);
+	aperbar |= (tmp & 0x7fff) <<25;
+	aperbar &= 0x000000ffffffffff;
+	aperbar |= 1<<2;	/* This address is a 64bit ptr FIXME: Make conditional in 32bit mode */
+	pci_write64 (dev, AMD_8151_VMAPERTURE, aperbar);
+
+	pci_read_config_dword(dev, AMD_8151_AGP_CTL , &tmp);
+	tmp &= ~(AMD_8151_GTLBEN | AMD_8151_APEREN);
+	
+	pci_read_config_dword(hammer, AMD_X86_64_GARTAPERTURECTL, &tmp2);
+	if (tmp2 & AMD_X86_64_GARTEN)
+		tmp |= AMD_8151_APEREN;
+	// FIXME: bit 7 of AMD_8151_AGP_CTL (GTLBEN) must be copied if set.
+	// But where is it set ?
+	pci_write_config_dword(dev, AMD_8151_AGP_CTL, tmp);
+
+	return 0;
+}
+
+
+static void amd_8151_cleanup(void)
+{
+	struct pci_dev *dev;
+	u32 tmp;
+
+	pci_for_each_dev(dev) {
+		/* disable gart translation */
+		if (dev->bus->number==0 && PCI_FUNC(dev->devfn)==3 &&
+		    (PCI_SLOT(dev->devfn) >=24) && (PCI_SLOT(dev->devfn) <=31)) {
+
+			pci_read_config_dword (dev, AMD_X86_64_GARTAPERTURECTL, &tmp);
+			tmp &= ~(AMD_X86_64_GARTEN);
+			pci_write_config_dword (dev, AMD_X86_64_GARTAPERTURECTL, tmp);
+		}
+
+		/* Now shadow the disable in the 8151 */
+		if (dev->vendor == PCI_VENDOR_ID_AMD &&
+			dev->device == PCI_DEVICE_ID_AMD_8151_0) {
+
+			pci_read_config_dword (dev, AMD_8151_AGP_CTL, &tmp);
+			tmp &= ~(AMD_8151_APEREN);	
+			pci_write_config_dword (dev, AMD_8151_AGP_CTL, tmp);
+		}
+	}
+}
+
+
+
+static unsigned long amd_8151_mask_memory(unsigned long addr, int type)
+{
+	return addr | agp_bridge.masks[0].mask;
+}
+
+
+static gatt_mask amd_8151_masks[] =
+{
+	{0x00000001, 0}
+};
+
+
+/*
+ * Try to configure an AGP v3 capable setup.
+ * If we fail (typically because we don't have an AGP v3
+ * card in the system) we fall back to the generic AGP v2
+ * routines.
+ */
+static void agp_x86_64_agp_enable(u32 mode)
+{
+	struct pci_dev *device = NULL;
+	u32 command, scratch; 
+	u8 cap_ptr;
+	u8 agp_v3;
+	u8 v3_devs=0;
+
+	/* FIXME: If 'mode' is x1/x2/x4 should we call the AGPv2 routines directly ?
+	 * Messy, as some AGPv3 cards can only do x4 as a minimum.
+	 */
+
+	/* PASS1: Count # of devs capable of AGPv3 mode. */
+	pci_for_each_dev(device) {
+		cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
+		if (cap_ptr != 0x00) {
+			pci_read_config_dword(device, cap_ptr, &scratch);
+			scratch &= (1<<20|1<<21|1<<22|1<<23);
+			scratch = scratch>>20;
+			/* AGP v3 capable ? */
+			if (scratch>=3) {
+				v3_devs++;
+				printk (KERN_INFO "AGP: Found AGPv3 capable device at %d:%d:%d\n",
+					device->bus->number, PCI_FUNC(device->devfn), PCI_SLOT(device->devfn));
+			} else {
+				printk (KERN_INFO "AGP: Meh. version %x AGP device found.\n", scratch);
+			}
+		}
+	}
+	/* If not enough, go to AGP v2 setup */
+	if (v3_devs<2) {
+		printk (KERN_INFO "AGP: Only %d devices found, not enough, trying AGPv2\n", v3_devs);
+		return agp_generic_agp_enable(mode);
+	} else {
+		printk (KERN_INFO "AGP: Enough AGPv3 devices found, setting up...\n");
+	}
+
+
+	pci_read_config_dword(agp_bridge.dev, agp_bridge.capndx + 4, &command);
+
+	/*
+	 * PASS2: go through all devices that claim to be
+	 *        AGP devices and collect their data.
+	 */
+
+	pci_for_each_dev(device) {
+		cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
+		if (cap_ptr != 0x00) {
+			/*
+			 * Ok, here we have a AGP device. Disable impossible 
+			 * settings, and adjust the readqueue to the minimum.
+			 */
+
+			printk (KERN_INFO "AGP: Setting up AGPv3 capable device at %d:%d:%d\n",
+					device->bus->number, PCI_FUNC(device->devfn), PCI_SLOT(device->devfn));
+			pci_read_config_dword(device, cap_ptr + 4, &scratch);
+			agp_v3 = (scratch & (1<<3) ) >>3;
+
+			/* adjust RQ depth */
+			command =
+			    ((command & ~0xff000000) |
+			     min_t(u32, (mode & 0xff000000),
+				 min_t(u32, (command & 0xff000000),
+				     (scratch & 0xff000000))));
+
+			/* disable SBA if it's not supported */
+			if (!((command & 0x200) && (scratch & 0x200) && (mode & 0x200)))
+				command &= ~0x200;
+
+			/* disable FW if it's not supported */
+			if (!((command & 0x10) && (scratch & 0x10) && (mode & 0x10)))
+				command &= ~0x10;
+
+			if (!((command & 2) && (scratch & 2) && (mode & 2))) {
+				command &= ~2;		/* 8x */
+				printk (KERN_INFO "AGP: Putting device into 8x mode\n");
+			}
+
+			if (!((command & 1) && (scratch & 1) && (mode & 1))) {
+				command &= ~1;		/* 4x */
+				printk (KERN_INFO "AGP: Putting device into 4x mode\n");
+			}
+		}
+	}
+	/*
+	 * PASS3: Figure out the 8X/4X setting and enable the
+	 *        target (our motherboard chipset).
+	 */
+
+	if (command & 2)
+		command &= ~5;	/* 8X */
+
+	if (command & 1)
+		command &= ~6;	/* 4X */
+
+	command |= 0x100;
+
+	pci_write_config_dword(agp_bridge.dev, agp_bridge.capndx + 8, command);
+
+	/*
+	 * PASS4: Go through all AGP devices and update the
+	 *        command registers.
+	 */
+
+	pci_for_each_dev(device) {
+		cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
+		if (cap_ptr != 0x00)
+			pci_write_config_dword(device, cap_ptr + 8, command);
+	}
+}
+
+
+static int __init amd_8151_setup (struct pci_dev *pdev)
+{
+	agp_bridge.masks = amd_8151_masks;
+	agp_bridge.num_of_masks = 1;
+	agp_bridge.aperture_sizes = (void *) amd_8151_sizes;
+	agp_bridge.size_type = U32_APER_SIZE;
+	agp_bridge.num_aperture_sizes = 7;
+	agp_bridge.dev_private_data = NULL;
+	agp_bridge.needs_scratch_page = FALSE;
+	agp_bridge.configure = amd_8151_configure;
+	agp_bridge.fetch_size = amd_x86_64_fetch_size;
+	agp_bridge.cleanup = amd_8151_cleanup;
+	agp_bridge.tlb_flush = amd_x86_64_tlbflush;
+	agp_bridge.mask_memory = amd_8151_mask_memory;
+	agp_bridge.agp_enable = agp_x86_64_agp_enable;
+	agp_bridge.cache_flush = global_cache_flush;
+	agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+	agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+	agp_bridge.insert_memory = x86_64_insert_memory;
+	agp_bridge.remove_memory = agp_generic_remove_memory;
+	agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+	agp_bridge.free_by_type = agp_generic_free_by_type;
+	agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+	agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+	agp_bridge.suspend = agp_generic_suspend;
+	agp_bridge.resume = agp_generic_resume;
+	agp_bridge.cant_use_aperture = 0;
+
+	return 0;
+	
+	(void) pdev; /* unused */
+}
+
+#endif /* CONFIG_AGP_AMD_8151 */
+
 #ifdef CONFIG_AGP_ALI
 
 static int ali_fetch_size(void)
@@ -2824,36 +3331,31 @@
 	}
 }
 
+
 static unsigned long ali_alloc_page(void)
 {
-	struct page *page;
-	u32 temp;
-
-	page = alloc_page(GFP_KERNEL);
-	if (page == NULL)
+	unsigned long p = agp_generic_alloc_page(); 
+	if (!p) 
 		return 0;
 
-	get_page(page);
-	LockPage(page);
-	atomic_inc(&agp_bridge.current_memory_agp);
-
+	/* probably not needed anymore */
 	global_cache_flush();
 
 	if (agp_bridge.type == ALI_M1541) {
+		u32 temp;
 		pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp);
 		pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL,
 				(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
-				  virt_to_phys(page_address(page))) |
+				  virt_to_phys((void *)p)) |
 				    ALI_CACHE_FLUSH_EN ));
 	}
-	return (unsigned long)page_address(page);
+	return p;
 }
 
 static void ali_destroy_page(unsigned long addr)
 {
 	u32 temp;
 	void *pt = (void *) addr;
-	struct page *page;
 
 	if (pt == NULL)
 		return;
@@ -2864,15 +3366,11 @@
 		pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp);
 		pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL,
 				(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
-				  virt_to_phys((void *)pt)) |
+				  virt_to_phys(pt)) |
 				    ALI_CACHE_FLUSH_EN));
 	}
 
-	page = virt_to_page(pt);
-	put_page(page);
-	UnlockPage(page);
-	free_page((unsigned long) pt);
-	atomic_dec(&agp_bridge.current_memory_agp);
+	agp_generic_destroy_page(addr);
 }
 
 /* Setup function */
@@ -2947,16 +3445,21 @@
 static int serverworks_create_page_map(serverworks_page_map *page_map)
 {
 	int i;
+	int err = 0;
 
 	page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
 	if (page_map->real == NULL) {
 		return -ENOMEM;
 	}
 	SetPageReserved(virt_to_page(page_map->real));
+#ifdef CONFIG_X86
+	err = change_page_attr(virt_to_page(page_map->real), 1, PAGE_KERNEL_NOCACHE);
+#endif
 	CACHE_FLUSH();
+	if (!err) 
 	page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), 
 					    PAGE_SIZE);
-	if (page_map->remapped == NULL) {
+	if (page_map->remapped == NULL || err) {
 		ClearPageReserved(virt_to_page(page_map->real));
 		free_page((unsigned long) page_map->real);
 		page_map->real = NULL;
@@ -2973,6 +3476,9 @@
 
 static void serverworks_free_page_map(serverworks_page_map *page_map)
 {
+#ifdef CONFIG_X86
+	change_page_attr(virt_to_page(page_map->real),1,PAGE_KERNEL); 
+#endif
 	iounmap(page_map->remapped);
 	ClearPageReserved(virt_to_page(page_map->real));
 	free_page((unsigned long) page_map->real);
@@ -3993,6 +4499,15 @@
 		amd_irongate_setup },
 #endif /* CONFIG_AGP_AMD */
 
+#ifdef CONFIG_AGP_AMD_8151
+	{ PCI_DEVICE_ID_AMD_8151_0,
+		PCI_VENDOR_ID_AMD,
+		AMD_8151,
+		"AMD",
+		"8151",
+		amd_8151_setup },
+#endif /* CONFIG_AGP_AMD */
+
 #ifdef CONFIG_AGP_INTEL
 	{ PCI_DEVICE_ID_INTEL_82443LX_0,
 		PCI_VENDOR_ID_INTEL,
@@ -4094,6 +4609,12 @@
 		"SiS",
 		"645",
 		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_646,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"646",
+		sis_generic_setup },
 	{ PCI_DEVICE_ID_SI_735,
 		PCI_VENDOR_ID_SI,
 		SIS_GENERIC,
@@ -4295,7 +4816,6 @@
 {
 	struct pci_dev *dev = NULL;
 	u8 cap_ptr = 0x00;
-	u32 cap_id, scratch;
 
 	if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) == NULL)
 		return -ENODEV;
@@ -4512,7 +5032,7 @@
 {
 	long memory, index, result;
 
-	memory = virt_to_phys(high_memory) >> 20;
+	memory = (num_physpages << PAGE_SHIFT) >> 20;
 	index = 1;
 
 	while ((memory > maxes_table[index].mem) &&
@@ -4662,7 +5182,7 @@
 	&agp_copy_info
 };
 
-static int __init agp_init(void)
+int __init agp_init(void)
 {
 	int ret_val;
 
@@ -4695,5 +5215,7 @@
 	inter_module_unregister("drm_agp");
 }
 
+#ifndef CONFIG_GART_IOMMU
 module_init(agp_init);
 module_exit(agp_cleanup);
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/alim1535d_wdt.c linux-2.4.20/drivers/char/alim1535d_wdt.c
--- linux-2.4.19/drivers/char/alim1535d_wdt.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/alim1535d_wdt.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,356 @@
+/*
+ *	Watchdog for the 7101 PMU version found in the ALi1535 chipsets
+ *
+ *	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.
+ */
+ 
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+static spinlock_t ali_lock;	/* Guards the hardware */
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+static unsigned long timer_alive;
+static char ali_expect_close;
+static u32 ali_timeout = 60;			/* 60 seconds */
+static u32 ali_timeout_bits = 1 | (1<<7);	/* 1 count in minutes */
+
+static struct pci_dev *ali_pci;
+
+/**
+ *	ali_timer_start		-	start watchdog countdown
+ *	@dev: PCI device of the PMU
+ *
+ *	Starts the timer running providing the timer has a counter
+ *	configuration set.
+ */
+ 
+static void ali_timer_start(struct pci_dev *pdev)
+{
+	u32 val;
+
+	spin_lock(&ali_lock);
+	
+	pci_read_config_dword(pdev, 0xCC, &val);
+	val &= ~0x3F;	/* Mask count */
+	val |= (1<<25) | ali_timeout_bits;
+	pci_write_config_dword(pdev, 0xCC, val);
+	spin_unlock(&ali_lock);
+}
+
+/**
+ *	ali_timer_stop	-	stop the timer countdown
+ *	@pdev: PCI device of the PMU
+ *
+ *	Stop the ALi watchdog countdown
+ */
+ 
+static void ali_timer_stop (struct pci_dev *pdev)
+{
+	u32 val;
+
+	spin_lock(&ali_lock);
+	pci_read_config_dword(pdev, 0xCC, &val);
+	val &= ~0x3F;	/* Mask count to zero (disabled) */
+	val &= ~(1<<25);/* and for safety mask the reset enable */
+	pci_write_config_dword(pdev, 0xCC, val);
+	spin_unlock(&ali_lock);
+}
+
+/**
+ *	ali_timer_settimer	-	compute the timer reload value
+ *	@pdev: PCI device of the PMU
+ *	@t: time in seconds
+ *
+ *	Computes the timeout values needed and then restarts the timer
+ *	running with the new timeout values
+ */
+
+static int ali_timer_settimer(struct pci_dev *pdev, unsigned long t)
+{
+	if(t < 60)
+		ali_timeout_bits = t|(1<<6);
+	else if(t < 3600)
+		ali_timeout_bits = (t/60)|(1<<7);
+	else if(t < 18000)
+		ali_timeout_bits = (t/300)|(1<<6)|(1<<7);
+	else return -EINVAL;
+	
+	ali_timeout = t;
+	ali_timer_start(pdev);
+	return 0;
+}
+
+/**
+ *	ali_open	-	handle open of ali watchdog
+ *	@inode: inode from VFS
+ *	@file: file from VFS
+ *
+ *	Open the ALi watchdog device. Ensure only one person opens it
+ *	at a time. Also start the watchdog running.
+ */
+
+static int ali_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(0, &timer_alive))
+		return -EBUSY;
+	ali_timer_start (ali_pci);
+	return 0;
+}
+
+/**
+ *	ali_release	-	close an ALi watchdog
+ *	@inode: inode from VFS
+ *	@file: file from VFS
+ *
+ *	Close the ALi watchdog device. Actual shutdown of the timer
+ *	only occurs if the magic sequence has been set or nowayout is 
+ *	disabled
+ */
+ 
+static int ali_release (struct inode *inode, struct file *file)
+{
+	/*
+	 *      Shut off the timer.
+	 */
+	if (ali_expect_close == 42 && !nowayout) {
+		ali_timer_stop(ali_pci);
+	} else {
+		ali_timer_start(ali_pci);
+		printk(KERN_CRIT  "ali1535_wdt: Unexpected close, not stopping watchdog!\n");
+	}
+	clear_bit(0, &timer_alive);
+	ali_expect_close = 0;
+	return 0;
+}
+
+/**
+ *	ali_write	-	writes to ALi watchdog
+ *	@file: file from VFS
+ *	@data: user address of data
+ *	@len: length of data
+ *	@ppos: pointer to the file offset
+ *
+ *	Handle a write to the ALi watchdog. Writing to the file pings
+ *	the watchdog and resets it. Writing the magic 'V' sequence allows
+ *	the next close to turn off the watchdog.
+ */
+ 
+static ssize_t ali_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;
+
+	/* See if we got the magic character 'V' and reload the timer */
+	if (len) {
+		size_t i;
+
+		ali_expect_close = 0;
+
+		/* scan to see wether or not we got the magic character */
+		for (i = 0; i != len; i++) {
+			u8 c;
+			if(get_user(c, data+i))
+				return -EFAULT;
+			if (c == 'V')
+				ali_expect_close = 42;
+		}
+
+		/* someone wrote to us, we should reload the timer */
+		ali_timer_start(ali_pci);
+		return 1;
+	}
+	return 0;
+}
+
+/**
+ *	ali_ioctl	-	handle watchdog ioctls
+ *	@inode: VFS inode
+ *	@file: VFS file pointer
+ *	@cmd: ioctl number
+ *	@arg: arguments to the ioctl
+ *
+ *	Handle the watchdog ioctls supported by the ALi driver. Really
+ *	we want an extension to enable irq ack monitoring and the like
+ */
+
+static int ali_ioctl (struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	int options, retval = -EINVAL;
+	u32 t;
+	static struct watchdog_info ident = {
+		options:		WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+		firmware_version:	0,
+		identity:		"ALi 1535D+ TCO timer",
+	};
+	switch (cmd) {
+		default:
+			return -ENOTTY;
+		case WDIOC_GETSUPPORT:
+			if (copy_to_user((struct watchdog_info *) arg, &ident, sizeof (ident)))
+				return -EFAULT;
+			return 0;
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, (int *) arg);
+		case WDIOC_SETOPTIONS:
+			if (get_user (options, (int *) arg))
+				return -EFAULT;
+			if (options & WDIOS_DISABLECARD) {
+				ali_timer_stop(ali_pci);
+				retval = 0;
+			}
+			if (options & WDIOS_ENABLECARD) {
+				ali_timer_start(ali_pci);
+				retval = 0;
+			}
+			return retval;
+		case WDIOC_KEEPALIVE:
+			ali_timer_start(ali_pci);
+			return 0;
+		case WDIOC_SETTIMEOUT:
+			if (get_user(t, (int *) arg))
+				return -EFAULT;
+			if (ali_timer_settimer(ali_pci, t))
+			    return -EINVAL;
+			ali_timer_start(ali_pci);
+			/* Fall */
+		case WDIOC_GETTIMEOUT:
+			return put_user(ali_timeout, (int *)arg);
+	}
+}
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+ 
+static struct pci_device_id ali_pci_tbl[] __initdata = {
+	{ PCI_VENDOR_ID_AL, 1535, PCI_ANY_ID, PCI_ANY_ID,},
+	{ 0, },
+};
+MODULE_DEVICE_TABLE (pci, ali_pci_tbl);
+
+
+/**
+ *	ali_find_watchdog	-	find a 1535 and 7101
+ *	
+ *	Scans the PCI hardware for a 1535 series bridge and matching 7101
+ *	watchdog device. This may be overtight but it is better to be safe
+ */	
+
+static int __init ali_find_watchdog(void)
+{
+	struct pci_dev *pdev;
+	u32 wdog;
+	
+	/* Check for a 1535 series bridge */
+	pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x1535, NULL);
+	if(pdev == NULL)
+		return -ENODEV;
+
+	/* Check for the a 7101 PMU */
+	pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x7101, NULL);
+	if(pdev == NULL)
+		return -ENODEV;
+
+	if(pci_enable_device(pdev))
+		return -EIO;
+		
+	ali_pci = pdev;
+	
+	/*
+	 *	Initialize the timer bits
+	 */
+	 
+	pci_read_config_dword(pdev, 0xCC, &wdog);
+	
+	wdog &= ~0x3F;		/* Timer bits */
+	wdog &= ~((1<<27)|(1<<26)|(1<<25)|(1<<24));	/* Issued events */
+	wdog &= ~((1<<16)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9));	/* No monitor bits */
+
+	pci_write_config_dword(pdev, 0xCC, wdog);
+	return 0;
+}
+
+static struct file_operations ali_fops = {
+	owner:		THIS_MODULE,
+	write:		ali_write,
+	ioctl:		ali_ioctl,
+	open:		ali_open,
+	release:	ali_release,
+};
+
+static struct miscdevice ali_miscdev = {
+	minor:		WATCHDOG_MINOR,
+	name:		"watchdog",
+	fops:		&ali_fops,
+};
+
+/**
+ *	watchdog_init	-	module initialiser
+ *	
+ *	Scan for a suitable watchdog and if so initialize it. Return an error
+ *	if we cannot, the error causes the module to unload
+ */
+ 
+static int __init watchdog_init (void)
+{
+	spin_lock_init(&ali_lock);
+	if (!ali_find_watchdog())
+		return -ENODEV;
+	if (misc_register (&ali_miscdev) != 0) {
+		printk (KERN_ERR "alim1535d: cannot register watchdog device node.\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+/**
+ *	watchdog_cleanup	-	unload watchdog
+ *
+ *	Called on the unload of a successfully installed watchdog module.
+ */
+ 
+static void __exit watchdog_cleanup (void)
+{
+	ali_timer_stop(ali_pci);
+	misc_deregister (&ali_miscdev);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_cleanup);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("Watchdog driver for the ALi 1535+ PMU");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/alim7101_wdt.c linux-2.4.20/drivers/char/alim7101_wdt.c
--- linux-2.4.19/drivers/char/alim7101_wdt.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/alim7101_wdt.c	2002-10-29 11:18:33.000000000 +0000
@@ -79,6 +79,15 @@
 static int wdt_expect_close;
 static struct pci_dev *alim7101_pmu;
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 /*
  *	Whack the dog
  */
@@ -157,16 +166,23 @@
 	/* See if we got the magic character */
 	if(count) 
 	{
-		size_t ofs;
-
-		/* note: just in case someone wrote the magic character
-		 * five months ago... */
-		wdt_expect_close = 0;
-
-		/* now scan */
-		for(ofs = 0; ofs != count; ofs++)
-			if(buf[ofs] == 'V')
-				wdt_expect_close = 1;
+		if (!nowayout) {
+			size_t ofs;
+	
+			/* note: just in case someone wrote the magic character
+			 * five months ago... */
+			wdt_expect_close = 0;
+	
+			/* now scan */
+			for(ofs = 0; ofs != count; ofs++)
+			{
+				char c;
+				if(get_user(c, buf+ofs))
+					return -EFAULT;
+				if(c == 'V')
+					wdt_expect_close = 1;
+			}
+		}
 
 		/* someone wrote to us, we should restart timer */
 		next_heartbeat = jiffies + WDT_HEARTBEAT;
@@ -193,15 +209,11 @@
 
 static int fop_close(struct inode * inode, struct file * file)
 {
-#ifdef CONFIG_WDT_NOWAYOUT
 	if(wdt_expect_close)
 		wdt_turnoff();
 	else {
 		printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n");
 	}
-#else
-	wdt_turnoff();
-#endif
 	clear_bit(0, &wdt_is_open);
 	return 0;
 }
@@ -210,7 +222,7 @@
 {
 	static struct watchdog_info ident=
 	{
-		0,
+		WDIOF_MAGICCLOSE,
 		1,
 		"ALiM7101"
 	};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/amd76x_pm.c linux-2.4.20/drivers/char/amd76x_pm.c
--- linux-2.4.19/drivers/char/amd76x_pm.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/amd76x_pm.c	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,688 @@
+/*
+ * ACPI sytle PM for SMP AMD-760MP(X) based systems.
+ * For use until the ACPI project catches up. :-)
+ *
+ * Copyright (C) 2002 Johnathan Hicks <thetech@folkwolf.net>
+ *
+ * History:
+ * 
+ *   20020702 - amd-smp-idle: Tony Lindgren <tony@atomide.com>
+ *	Influenced by Vcool, and LVCool. Rewrote everything from scratch to
+ *	use the PCI features in Linux, and to support SMP systems. Provides
+ *	C2 idling on SMP AMD-760MP systems.
+ *	
+ *   20020722: JH
+ *   	I adapted Tony's code for the AMD-765/766 southbridge and adapted it
+ *   	according to the AMD-768 data sheet to provide the same capability for
+ *   	SMP AMD-760MPX systems. Posted to acpi-devel list.
+ *   	
+ *   20020722: Alan Cox
+ *   	Replaces non-functional amd76x_pm code in -ac tree.
+ *   	
+ *   20020730: JH
+ *   	Added ability to do normal throttling (the non-thermal kind), C3 idling
+ *   	and Power On Suspend (S1 sleep). It would be very easy to tie swsusp
+ *   	into activate_amd76x_SLP(). C3 idling doesn't happen yet; see my note
+ *   	in amd76x_smp_idle(). I've noticed that when NTH and idling are both
+ *   	enabled, my hardware locks and requires a hard reset, so I have
+ *   	#ifndefed around the idle loop setting to prevent this. POS locks it up
+ *   	too, both ought to be fixable. I've also noticed that idling and NTH
+ *   	make some interference that is picked up by the onboard sound chip on
+ *   	my ASUS A7M266-D motherboard.
+ *
+ *
+ * TODO: Thermal throttling (TTH).
+ * 	 /proc interface for normal throttling level.
+ * 	 /proc interface for POS.
+ *
+ *
+ *    <Notes from 20020722-ac revision>
+ *
+ * Processor idle mode module for AMD SMP 760MP(X) based systems
+ *
+ * Copyright (C) 2002 Tony Lindgren <tony@atomide.com>
+ *                    Johnathan Hicks (768 support)
+ *
+ * Using this module saves about 70 - 90W of energy in the idle mode compared
+ * to the default idle mode. Waking up from the idle mode is fast to keep the
+ * system response time good. Currently no CPU load calculation is done, the
+ * system exits the idle mode if the idle function runs twice on the same
+ * processor in a row. This only works on SMP systems, but maybe the idle mode
+ * enabling can be integrated to ACPI to provide C2 mode at some point.
+ *
+ * NOTE: Currently there's a bug somewhere where the reading the
+ *       P_LVL2 for the first time causes the system to sleep instead of 
+ *       idling. This means that you need to hit the power button once to
+ *       wake the system after loading the module for the first time after
+ *       reboot. After that the system idles as supposed.
+ *
+ *
+ * Influenced by Vcool, and LVCool. Rewrote everything from scratch to
+ * use the PCI features in Linux, and to support SMP systems.
+ * 
+ * Currently only tested on a TYAN S2460 (760MP) system (Tony) and an
+ * ASUS A7M266-D (760MPX) system (Johnathan). Adding support for other Athlon
+ * SMP or single processor systems should be easy if desired.
+ *
+ * This software is licensed under GNU General Public License Version 2 
+ * as specified in file COPYING in the Linux kernel source tree main 
+ * directory.
+ * 
+ *   </Notes from 20020722-ac revision>
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+
+#include "amd76x_pm.h"
+
+#define VERSION	"20020730"
+
+// #define AMD76X_C3  1
+// #define AMD76X_NTH 1
+// #define AMD76X_POS 1
+
+
+extern void default_idle(void);
+static void amd76x_smp_idle(void);
+static int amd76x_pm_main(void);
+static int __devinit amd_nb_init(struct pci_dev *pdev,
+				 const struct pci_device_id *ent);
+static void amd_nb_remove(struct pci_dev *pdev);
+static int __devinit amd_sb_init(struct pci_dev *pdev,
+				 const struct pci_device_id *ent);
+static void amd_sb_remove(struct pci_dev *pdev);
+
+
+static struct pci_dev *pdev_nb;
+static struct pci_dev *pdev_sb;
+
+struct PM_cfg {
+	unsigned int status_reg;
+	unsigned int C2_reg;
+	unsigned int C3_reg;
+	unsigned int NTH_reg;
+	unsigned int slp_reg;
+	unsigned int resume_reg;
+	void (*orig_idle) (void);
+	void (*curr_idle) (void);
+	unsigned long C2_cnt, C3_cnt;
+	int last_pr;
+};
+static struct PM_cfg amd76x_pm_cfg;
+
+struct cpu_idle_state {
+	int idle;
+	int count;
+};
+static struct cpu_idle_state prs[2];
+
+static struct pci_device_id amd_nb_tbl[] __devinitdata = {
+	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, PCI_ANY_ID, PCI_ANY_ID,},
+	{0,}
+};
+
+static struct pci_device_id amd_sb_tbl[] __devinitdata = {
+	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, PCI_ANY_ID, PCI_ANY_ID,},
+	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7443, PCI_ANY_ID, PCI_ANY_ID,},
+	{0,}
+};
+
+static struct pci_driver amd_nb_driver = {
+	name:"amd76x_pm-nb",
+	id_table:amd_nb_tbl,
+	probe:amd_nb_init,
+	remove:__devexit_p(amd_nb_remove),
+};
+
+static struct pci_driver amd_sb_driver = {
+	name:"amd76x_pm-sb",
+	id_table:amd_sb_tbl,
+	probe:amd_sb_init,
+	remove:__devexit_p(amd_sb_remove),
+};
+
+
+static int __devinit
+amd_nb_init(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	pdev_nb = pdev;
+	printk(KERN_INFO "amd76x_pm: Initializing northbridge %s\n",
+	       pdev_nb->name);
+
+	return 0;
+}
+
+
+static void __devexit
+amd_nb_remove(struct pci_dev *pdev)
+{
+}
+
+
+static int __devinit
+amd_sb_init(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	pdev_sb = pdev;
+	printk(KERN_INFO "amd76x_pm: Initializing southbridge %s\n",
+	       pdev_sb->name);
+
+	return 0;
+}
+
+
+static void __devexit
+amd_sb_remove(struct pci_dev *pdev)
+{
+}
+
+
+/*
+ * Configures the AMD-762 northbridge to support PM calls
+ */
+static int
+config_amd762(int enable)
+{
+	unsigned int regdword;
+
+	/* Enable STPGNT in BIU Status/Control for cpu0 */
+	pci_read_config_dword(pdev_nb, 0x60, &regdword);
+	regdword |= (1 << 17);
+	pci_write_config_dword(pdev_nb, 0x60, regdword);
+
+	/* Enable STPGNT in BIU Status/Control for cpu1 */
+	pci_read_config_dword(pdev_nb, 0x68, &regdword);
+	regdword |= (1 << 17);
+	pci_write_config_dword(pdev_nb, 0x68, regdword);
+
+	/* DRAM refresh enable */
+	pci_read_config_dword(pdev_nb, 0x58, &regdword);
+	regdword &= ~(1 << 19);
+	pci_write_config_dword(pdev_nb, 0x58, regdword);
+
+	/* Self refresh enable */
+	pci_read_config_dword(pdev_nb, 0x70, &regdword);
+	regdword |= (1 << 18);
+	pci_write_config_dword(pdev_nb, 0x70, regdword);
+
+	return 0;
+}
+
+
+/*
+ * Get the base PMIO address and set the pm registers in amd76x_pm_cfg.
+ */
+static void
+amd76x_get_PM(void)
+{
+	unsigned int regdword;
+
+	/* Get the address for pm status, P_LVL2, etc */
+	pci_read_config_dword(pdev_sb, 0x58, &regdword);
+	regdword &= 0xff80;
+	amd76x_pm_cfg.status_reg = (regdword + 0x00);
+	amd76x_pm_cfg.slp_reg =    (regdword + 0x04);
+	amd76x_pm_cfg.NTH_reg =    (regdword + 0x10);
+	amd76x_pm_cfg.C2_reg =     (regdword + 0x14);
+	amd76x_pm_cfg.C3_reg =     (regdword + 0x15);
+	amd76x_pm_cfg.resume_reg = (regdword + 0x16); /* N/A for 768 */
+}
+
+
+/*
+ * En/Disable PMIO and configure W4SG & STPGNT.
+ */
+static int
+config_PMIO_amd76x(int is_766, int enable)
+{
+	unsigned char regbyte;
+
+	/* Clear W4SG, and set PMIOEN, if using a 765/766 set STPGNT as well.
+	 * AMD-766: C3A41; page 59 in AMD-766 doc
+	 * AMD-768: DevB:3x41C; page 94 in AMD-768 doc */
+	pci_read_config_byte(pdev_sb, 0x41, &regbyte);
+	if(enable) {
+		regbyte |= ((0 << 0) | (is_766?1:0 << 1) | (1 << 7));
+	}
+	else {
+		regbyte |= (0 << 7);
+	}
+	pci_write_config_byte(pdev_sb, 0x41, regbyte);
+
+	return 0;
+}
+
+/*
+ * C2 idle support for AMD-766.
+ */
+static void
+config_amd766_C2(int enable)
+{
+	unsigned int regdword;
+
+	/* Set C2 options in C3A50, page 63 in AMD-766 doc */
+	pci_read_config_dword(pdev_sb, 0x50, &regdword);
+	if(enable) {
+		regdword &= ~((DCSTOP_EN | CPUSTP_EN | PCISTP_EN | SUSPND_EN |
+					CPURST_EN) << C2_REGS);
+		regdword |= (STPCLK_EN	/* ~ 20 Watt savings max */
+			 |  CPUSLP_EN)	/* Additional ~ 70 Watts max! */
+			 << C2_REGS;
+	}
+	else
+		regdword &= ~((STPCLK_EN | CPUSLP_EN) << C2_REGS);
+	pci_write_config_dword(pdev_sb, 0x50, regdword);
+}
+
+
+#ifdef AMD76X_C3
+/*
+ * Untested C3 idle support for AMD-766.
+ */
+static void
+config_amd766_C3(int enable)
+{
+	unsigned int regdword;
+
+	/* Set C3 options in C3A50, page 63 in AMD-766 doc */
+	pci_read_config_dword(pdev_sb, 0x50, &regdword);
+	if(enable) {
+		regdword &= ~((DCSTOP_EN | PCISTP_EN | SUSPND_EN | CPURST_EN)
+				<< C3_REGS);
+		regdword |= (STPCLK_EN	/* ~ 20 Watt savings max */
+			 |  CPUSLP_EN	/* Additional ~ 70 Watts max! */
+			 |  CPUSTP_EN)	/* yet more savings! */
+			 << C3_REGS;
+	}
+	else
+		regdword &= ~((STPCLK_EN | CPUSLP_EN | CPUSTP_EN) << C3_REGS);
+	pci_write_config_dword(pdev_sb, 0x50, regdword);
+}
+#endif
+
+
+#ifdef AMD76X_POS
+static void
+config_amd766_POS(int enable)
+{
+	unsigned int regdword;
+
+	/* Set C3 options in C3A50, page 63 in AMD-766 doc */
+	pci_read_config_dword(pdev_sb, 0x50, &regdword);
+	if(enable) {
+		regdword &= ~((ZZ_CACHE_EN | CPURST_EN) << POS_REGS);
+		regdword |= ((DCSTOP_EN | STPCLK_EN | CPUSTP_EN | PCISTP_EN |
+					CPUSLP_EN | SUSPND_EN) << POS_REGS);
+	}
+	else
+		regdword ^= (0xff << POS_REGS);
+	pci_write_config_dword(pdev_sb, 0x50, regdword);
+}
+#endif
+
+
+/*
+ * Configures the 765 & 766 southbridges.
+ */
+static int
+config_amd766(int enable)
+{
+	amd76x_get_PM();
+	config_PMIO_amd76x(1, 1);
+
+	config_amd766_C2(enable);
+#ifdef AMD76X_C3
+	config_amd766_C3(enable);
+#endif
+#ifdef AMD76X_POS
+	config_amd766_POS(enable);
+#endif
+
+	return 0;
+}
+
+
+/*
+ * C2 idling support for AMD-768.
+ */
+static void
+config_amd768_C2(int enable)
+{
+	unsigned char regbyte;
+	
+	/* Set C2 options in DevB:3x4F, page 100 in AMD-768 doc */
+	pci_read_config_byte(pdev_sb, 0x4F, &regbyte);
+	if(enable)
+		regbyte |= C2EN;
+	else
+		regbyte ^= C2EN;
+	pci_write_config_byte(pdev_sb, 0x4F, regbyte);
+}
+
+
+#ifdef AMD76X_C3
+/*
+ * C3 idle support for AMD-768. The idle loop would need some extra
+ * handling for C3, but it would make more sense for ACPI to handle CX level
+ * transitions like it is supposed to. Unfortunately ACPI doesn't do CX
+ * levels on SMP systems yet.
+ */
+static void
+config_amd768_C3(int enable)
+{
+	unsigned char regbyte;
+	
+	/* Set C3 options in DevB:3x4F, page 100 in AMD-768 doc */
+	pci_read_config_byte(pdev_sb, 0x4F, &regbyte);
+	if(enable)
+		regbyte |= (C3EN /* | ZZ_C3EN | CSLP_C3EN | CSTP_C3EN */);
+	else
+		regbyte ^= C3EN;
+	pci_write_config_byte(pdev_sb, 0x4F, regbyte);
+}
+#endif
+
+
+#ifdef AMD76X_POS
+/*
+ * Untested Power On Suspend support for AMD-768. This should also be handled
+ * by ACPI.
+ */
+static void
+config_amd768_POS(int enable)
+{
+	unsigned int regdword;
+
+	/* Set POS options in DevB:3x50, page 101 in AMD-768 doc */
+	pci_read_config_dword(pdev_sb, 0x50, &regdword);
+	if(enable) 
+		regdword |= (POSEN | CSTP | PSTP | ASTP | DCSTP | CSLP | SUSP);
+	else
+		regdword ^= POSEN;
+	pci_write_config_dword(pdev_sb, 0x50, regdword);
+}
+#endif
+
+
+#ifdef AMD76X_NTH
+/*
+ * Normal Throttling support for AMD-768. There are several settings
+ * that can be set depending on how long you want some of the delays to be.
+ * I'm not sure if this is even neccessary at all as the 766 doesn't need this.
+ */
+static void
+config_amd768_NTH(int enable, int ntper, int thminen)
+{
+	unsigned char regbyte;
+
+	/* DevB:3x40, pg 93 of 768 doc */
+	pci_read_config_byte(pdev_sb, 0x40, &regbyte);
+	/* Is it neccessary to use THMINEN at ANY time? */
+	regbyte |= (NTPER(ntper) | THMINEN(thminen));
+	pci_write_config_byte(pdev_sb, 0x40, regbyte);
+}
+#endif
+
+
+/*
+ * Configures the 768 southbridge to support idle calls, and gets
+ * the processor idle call register location.
+ */
+static int
+config_amd768(int enable)
+{
+	amd76x_get_PM();
+	config_PMIO_amd76x(0, 1);
+
+	config_amd768_C2(enable);
+#ifdef AMD76X_C3
+	config_amd768_C3(enable);
+#endif
+#ifdef AMD76X_POS
+	config_amd768_POS(enable);
+#endif
+#ifdef AMD76X_NTH
+	config_amd768_NTH(enable, 1, 2);
+#endif
+
+	return 0;
+}
+
+
+#ifdef AMD76X_NTH
+/*
+ * Activate normal throttling via its ACPI register (P_CNT).
+ */
+static void
+activate_amd76x_NTH(int enable, int ratio)
+{
+	unsigned int regdword;
+
+	/* PM10, pg 110 of 768 doc, pg 70 of 766 doc */
+	regdword=inl(amd76x_pm_cfg.NTH_reg);
+	if(enable)
+		regdword |= (NTH_EN | NTH_RATIO(ratio));
+	else
+		regdword ^= NTH_EN;
+	outl(regdword, amd76x_pm_cfg.NTH_reg);
+}
+#endif
+
+
+/*
+ * Activate sleep state via its ACPI register (PM1_CNT).
+ */
+static void
+activate_amd76x_SLP(int type)
+{
+	unsigned short regshort;
+
+	/* PM04, pg 109 of 768 doc, pg 69 of 766 doc */
+	regshort=inw(amd76x_pm_cfg.slp_reg);
+	regshort |= (SLP_EN | SLP_TYP(type)) ;
+	outw(regshort, amd76x_pm_cfg.slp_reg);
+}
+
+
+#ifdef AMD76X_POS
+/*
+ * Wrapper function to activate POS sleep state.
+ */
+static void
+activate_amd76x_POS(void)
+{
+	activate_amd76x_SLP(1);
+}
+#endif
+
+
+#if 0
+/*
+ * Idle loop for single processor systems
+ */
+void
+amd76x_up_idle(void)
+{
+	// FIXME: Optionally add non-smp idle loop here
+}
+#endif
+
+
+/*
+ * Idle loop for SMP systems, supports currently only 2 processors.
+ *
+ * Note; for 2.5 folks - not pre-empt safe
+ */
+static void
+amd76x_smp_idle(void)
+{
+
+	/*
+	 * Exit idle mode immediately if the CPU does not change.
+	 * Usually that means that we have some load on another CPU.
+	 */
+	if (prs[0].idle && prs[1].idle && amd76x_pm_cfg.last_pr == smp_processor_id()) {
+		prs[0].idle = 0;
+		prs[1].idle = 0;
+		/* This looks redundent as it was just checked in the if() */
+		/* amd76x_pm_cfg.last_pr = smp_processor_id(); */
+		return;
+	}
+
+	prs[smp_processor_id()].count++;
+
+	/* Don't start the idle mode immediately */
+	if (prs[smp_processor_id()].count >= LAZY_IDLE_DELAY) {
+
+		/* Put the current processor into idle mode */
+		prs[smp_processor_id()].idle =
+			(prs[smp_processor_id()].idle ? 2 : 1);
+
+		/* Only idle if both processors are idle */
+		if ((prs[0].idle==1) && (prs[1].idle==1)) {
+			amd76x_pm_cfg.C2_cnt++;
+			inb(amd76x_pm_cfg.C2_reg);
+		}
+	#ifdef AMD76X_C3
+		/*
+		 * JH: I've not been able to get into here. Could this have
+		 * something to do with the way the kernel handles the idle
+		 * loop, or and error that I've made?
+		 */
+		else if ((prs[0].idle==2) && (prs[1].idle==2)) {
+			amd76x_pm_cfg.C3_cnt++;
+			inb(amd76x_pm_cfg.C3_reg);
+		}
+	#endif
+
+		prs[smp_processor_id()].count = 0;
+
+	}
+	amd76x_pm_cfg.last_pr = smp_processor_id();
+}
+
+
+/*
+ * Finds and initializes the bridges, and then sets the idle function
+ */
+static int
+amd76x_pm_main(void)
+{
+	int found;
+
+	/* Find northbridge */
+	found = pci_module_init(&amd_nb_driver);
+	if (found < 0) {
+		printk(KERN_ERR "amd76x_pm: Could not find northbridge\n");
+		return 1;
+	}
+
+	/* Find southbridge */
+	found = pci_module_init(&amd_sb_driver);
+	if (found < 0) {
+		printk(KERN_ERR "amd76x_pm: Could not find southbridge\n");
+		pci_unregister_driver(&amd_nb_driver);
+		return 1;
+	}
+
+	/* Init southbridge */
+	switch (pdev_sb->device) {
+	case PCI_DEVICE_ID_AMD_VIPER_7413:	/* AMD-765 or 766 */
+		config_amd766(1);
+		break;
+	case PCI_DEVICE_ID_AMD_VIPER_7443:	/* AMD-768 */
+		config_amd768(1);
+		break;
+	default:
+		printk(KERN_ERR "amd76x_pm: No southbridge to initialize\n");
+		break;
+	}
+
+	/* Init northbridge and queue the new idle function */
+	switch (pdev_nb->device) {
+	case PCI_DEVICE_ID_AMD_FE_GATE_700C:	/* AMD-762 */
+		config_amd762(1);
+#ifndef AMD76X_NTH
+		amd76x_pm_cfg.curr_idle = amd76x_smp_idle;
+#endif
+		break;
+	default:
+		printk(KERN_ERR "amd76x_pm: No northbridge to initialize\n");
+		break;
+	}
+
+#ifndef AMD76X_NTH
+	if (!amd76x_pm_cfg.curr_idle) {
+		printk(KERN_ERR "amd76x_pm: Idle function not changed\n");
+		return 1;
+	}
+
+	amd76x_pm_cfg.orig_idle = pm_idle;
+	pm_idle = amd76x_pm_cfg.curr_idle;
+#endif
+
+#ifdef AMD76X_NTH
+	/* Turn NTH on with maxium throttling for testing. */
+	activate_amd76x_NTH(1, 1);
+#endif
+
+#ifdef AMD76X_POS
+	/* Testing here only. */
+	activate_amd76x_POS();
+#endif
+
+	return 0;
+}
+
+
+static int __init
+amd76x_pm_init(void)
+{
+	printk(KERN_INFO "amd76x_pm: Version %s\n", VERSION);
+	return amd76x_pm_main();
+}
+
+
+static void __exit
+amd76x_pm_cleanup(void)
+{
+#ifndef AMD76X_NTH
+	pm_idle = amd76x_pm_cfg.orig_idle;
+
+	/* This isn't really needed. */
+	printk(KERN_INFO "amd76x_pm: %lu C2 calls\n", amd76x_pm_cfg.C2_cnt);
+#ifdef AMD76X_C3
+	printk(KERN_INFO "amd76x_pm: %lu C3 calls\n", amd76x_pm_cfg.C3_cnt);
+#endif
+
+	/* 
+	 * FIXME: We want to wait until all CPUs have set the new
+	 * idle function, otherwise we will oops. This may not be
+	 * the right way to do it, but seems to work.
+	 *
+	 * - Best answer is going to be to ban unload, but when its debugged
+	 *   --- Alan
+	 */
+	schedule();
+	mdelay(1000);
+#endif
+
+#ifdef AMD76X_NTH
+	/* Turn NTH off*/
+	activate_amd76x_NTH(0, 0);
+#endif
+
+	pci_unregister_driver(&amd_nb_driver);
+	pci_unregister_driver(&amd_sb_driver);
+
+}
+
+
+MODULE_LICENSE("GPL");
+module_init(amd76x_pm_init);
+module_exit(amd76x_pm_cleanup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/amd76x_pm.h linux-2.4.20/drivers/char/amd76x_pm.h
--- linux-2.4.19/drivers/char/amd76x_pm.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/amd76x_pm.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,59 @@
+/* 
+ * Begin 765/766
+ */
+/* C2/C3/POS options in C3A50, page 63 in AMD-766 doc */
+#define ZZ_CACHE_EN	1
+#define DCSTOP_EN	(1 << 1)
+#define STPCLK_EN	(1 << 2)
+#define CPUSTP_EN	(1 << 3)
+#define PCISTP_EN	(1 << 4)
+#define CPUSLP_EN	(1 << 5)
+#define SUSPND_EN	(1 << 6)
+#define CPURST_EN	(1 << 7)
+
+#define C2_REGS		0
+#define C3_REGS		8
+#define POS_REGS	16	
+/*
+ * End 765/766
+ */
+
+
+/*
+ * Begin 768
+ */
+/* C2/C3 options in DevB:3x4F, page 100 in AMD-768 doc */
+#define C2EN		1
+#define C3EN		(1 << 1)
+#define ZZ_C3EN		(1 << 2)
+#define CSLP_C3EN	(1 << 3)
+#define CSTP_C3EN	(1 << 4)
+
+/* POS options in DevB:3x50, page 101 in AMD-768 doc */
+#define POSEN	1
+#define CSTP	(1 << 2)
+#define PSTP	(1 << 3)
+#define ASTP	(1 << 4)
+#define DCSTP	(1 << 5)
+#define CSLP	(1 << 6)
+#define SUSP	(1 << 8)
+#define MSRSM	(1 << 14)
+#define PITRSM	(1 << 15)
+
+/* NTH options DevB:3x40, pg 93 of 768 doc */
+#define NTPER(x) (x << 3)
+#define THMINEN(x) (x << 4)
+
+/*
+ * End 768
+ */
+
+/* NTH activate. PM10, pg 110 of 768 doc, pg 70 of 766 doc */
+#define NTH_RATIO(x) (x << 1)
+#define NTH_EN (1 << 4)
+
+/* Sleep state. PM04, pg 109 of 768 doc, pg 69 of 766 doc */
+#define SLP_EN (1 << 13)
+#define SLP_TYP(x) (x << 10)
+
+#define LAZY_IDLE_DELAY	800	/* 0: Best savings,  3000: More responsive */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/amd7xx_tco.c linux-2.4.20/drivers/char/amd7xx_tco.c
--- linux-2.4.19/drivers/char/amd7xx_tco.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/amd7xx_tco.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,377 @@
+/*
+ *	AMD 766/768 TCO Timer Driver
+ *	(c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>
+ *	All Rights Reserved.
+ *
+ *	Parts from;
+ *	Hardware driver for the AMD 768 Random Number Generator (RNG)
+ *	(c) Copyright 2001 Red Hat Inc <alan@redhat.com>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License version 2
+ *	as published by the Free Software Foundation.
+ *
+ *	The author(s) of this software shall not be held liable for damages
+ *	of any nature resulting due to the use of this software. This
+ *	software is provided AS-IS with no warranties.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+#include <asm/semaphore.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#define AMDTCO_MODULE_VER	"build 20020601"
+#define AMDTCO_MODULE_NAME	"amd7xx_tco"
+#define PFX			AMDTCO_MODULE_NAME ": "
+
+#define	MAX_TIMEOUT	38	/* max of 38 seconds */
+
+/* pmbase registers */
+#define GLOBAL_SMI_REG	0x2a
+#define TCO_EN		(1 << 1)	/* bit 1 in global SMI register */
+#define TCO_RELOAD_REG	0x40		/* bits 0-5 are current count, 6-7 are reserved */
+#define TCO_INITVAL_REG	0x41		/* bits 0-5 are value to load, 6-7 are reserved */
+#define TCO_TIMEOUT_MASK	0x3f
+#define TCO_STATUS2_REG	0x46
+#define NDTO_STS2	(1 << 1)	/* we're interested in the second timeout */ 
+#define BOOT_STS	(1 << 2)	/* will be set if NDTO_STS2 was set before reboot */
+#define TCO_CTRL1_REG	0x48
+#define TCO_HALT	(1 << 11)
+
+static char banner[] __initdata = KERN_INFO PFX AMDTCO_MODULE_VER;
+static int timeout = 38;
+static u32 pmbase;		/* PMxx I/O base */
+static struct pci_dev *dev;
+static struct semaphore open_sem;
+spinlock_t amdtco_lock;	/* only for device access */
+static int expect_close = 0;
+
+MODULE_PARM(timeout, "i");
+MODULE_PARM_DESC(timeout, "range is 0-38 seconds, default is 38");
+
+static inline int amdtco_status(void)
+{
+	u16 reg;
+	int status = 0;
+
+	reg = inb(pmbase+TCO_CTRL1_REG);
+	if ((reg & TCO_HALT) == 0)
+		status |= WDIOF_KEEPALIVEPING;
+
+	reg = inb(pmbase+TCO_STATUS2_REG);
+	if (reg & BOOT_STS)
+		status |= WDIOF_CARDRESET;
+
+	return status;
+}
+
+static inline void amdtco_ping(void)
+{
+	u8 reg;
+
+	spin_lock(&amdtco_lock);
+	reg = inb(pmbase+TCO_RELOAD_REG);
+	outb(1 | reg, pmbase+TCO_RELOAD_REG);
+	spin_unlock(&amdtco_lock);
+}
+
+static inline int amdtco_gettimeout(void)
+{
+	return inb(TCO_RELOAD_REG) & TCO_TIMEOUT_MASK;
+}
+
+static inline void amdtco_settimeout(unsigned int timeout)
+{
+	u8 reg;
+
+	spin_lock(&amdtco_lock);
+	reg = inb(pmbase+TCO_INITVAL_REG);
+	reg |= timeout & TCO_TIMEOUT_MASK;
+	outb(reg, pmbase+TCO_INITVAL_REG);
+	spin_unlock(&amdtco_lock);
+}
+
+static inline void amdtco_global_enable(void)
+{
+	u16 reg;
+
+	spin_lock(&amdtco_lock);
+	reg = inw(pmbase+GLOBAL_SMI_REG);
+	reg |= TCO_EN;
+	outw(reg, pmbase+GLOBAL_SMI_REG);
+	spin_unlock(&amdtco_lock);
+}
+
+static inline void amdtco_enable(void)
+{
+	u16 reg;
+	
+	spin_lock(&amdtco_lock);
+	reg = inw(pmbase+TCO_CTRL1_REG);
+	reg &= ~TCO_HALT;
+	outw(reg, pmbase+TCO_CTRL1_REG);
+	spin_unlock(&amdtco_lock);
+}
+
+static inline void amdtco_disable(void)
+{
+	u16 reg;
+
+	spin_lock(&amdtco_lock);
+	reg = inw(pmbase+TCO_CTRL1_REG);
+	reg |= TCO_HALT;
+	outw(reg, pmbase+TCO_CTRL1_REG);
+	spin_unlock(&amdtco_lock);
+}
+
+static int amdtco_fop_open(struct inode *inode, struct file *file)
+{
+	if (down_trylock(&open_sem))
+		return -EBUSY;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT	
+	MOD_INC_USE_COUNT;
+#endif
+
+	if (timeout > MAX_TIMEOUT)
+		timeout = MAX_TIMEOUT;
+
+	amdtco_settimeout(timeout);	
+	amdtco_global_enable();
+	amdtco_ping();
+	printk(KERN_INFO PFX "Watchdog enabled, timeout = %d/%d seconds",
+		amdtco_gettimeout(), timeout);
+	
+	return 0;
+}
+
+
+static int amdtco_fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int new_timeout;
+	int tmp;
+
+	static struct watchdog_info ident = {
+		options:	WDIOF_SETTIMEOUT | WDIOF_CARDRESET,
+		identity:	"AMD 766/768"
+	};
+
+	switch (cmd) {
+		default:
+			return -ENOTTY;	
+
+		case WDIOC_GETSUPPORT:
+			if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof ident))
+				return -EFAULT;
+			return 0;
+
+		case WDIOC_GETSTATUS:
+			return put_user(amdtco_status(), (int *)arg);
+	
+		case WDIOC_KEEPALIVE:
+			amdtco_ping();
+			return 0;
+
+		case WDIOC_SETTIMEOUT:
+			if (get_user(new_timeout, (int *)arg))
+				return -EFAULT;
+			
+			if (new_timeout < 0)
+				return -EINVAL;
+		
+			if (new_timeout > MAX_TIMEOUT)
+				new_timeout = MAX_TIMEOUT;
+
+			timeout = new_timeout;
+			amdtco_settimeout(timeout);
+			/* fall through and return the new timeout */
+
+		case WDIOC_GETTIMEOUT:
+			return put_user(amdtco_gettimeout(), (int *)arg);
+	
+		case WDIOC_SETOPTIONS:
+			if (copy_from_user(&tmp, (int *)arg, sizeof tmp))
+                                return -EFAULT;
+
+			if (tmp & WDIOS_DISABLECARD)
+				amdtco_disable();
+
+			if (tmp & WDIOS_ENABLECARD)
+				amdtco_enable();
+			
+			return 0;
+	}
+}
+
+
+static int amdtco_fop_release(struct inode *inode, struct file *file)
+{
+	if (expect_close) {
+		amdtco_disable();	
+		printk(KERN_INFO PFX "Watchdog disabled\n");
+	} else {
+		amdtco_ping();
+		printk(KERN_CRIT PFX "Unexpected close!, timeout in %d seconds)\n", timeout);
+	}	
+	
+	up(&open_sem);
+	return 0;
+}
+
+
+static ssize_t amdtco_fop_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	
+	if (len) {
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+		size_t i;
+		char c;
+		expect_close = 0;
+		
+		for (i = 0; i != len; i++) {
+			if (get_user(c, data + i))
+				return -EFAULT;
+
+			if (c == 'V')
+				expect_close = 1;
+		}
+#endif
+		amdtco_ping();
+		return len;
+	}
+
+	return 0;
+}
+
+
+static int amdtco_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code == SYS_DOWN || code == SYS_HALT)
+		amdtco_disable();
+
+	return NOTIFY_DONE;
+}
+
+
+static struct notifier_block amdtco_notifier =
+{
+	notifier_call:	amdtco_notify_sys
+};
+
+static struct file_operations amdtco_fops =
+{
+	owner:		THIS_MODULE,
+	write:		amdtco_fop_write,
+	ioctl:		amdtco_fop_ioctl,
+	open:		amdtco_fop_open,
+	release:	amdtco_fop_release
+};
+
+static struct miscdevice amdtco_miscdev =
+{
+	minor:		WATCHDOG_MINOR,
+	name:		"watchdog",
+	fops:		&amdtco_fops
+};
+
+static struct pci_device_id amdtco_pci_tbl[] __initdata = {
+	/* AMD 766 PCI_IDs here */
+	{ 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, amdtco_pci_tbl);
+
+static int __init amdtco_init(void)
+{
+	int ret;
+
+	sema_init(&open_sem, 1);
+	spin_lock_init(&amdtco_lock);
+
+	pci_for_each_dev(dev) {
+		if (pci_match_device (amdtco_pci_tbl, dev) != NULL)
+			goto found_one;
+	}
+
+	return -ENODEV;
+
+found_one:
+	
+	if ((ret = register_reboot_notifier(&amdtco_notifier))) {
+		printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret);
+		goto out_clean;
+	}
+
+	if ((ret = misc_register(&amdtco_miscdev))) {
+		printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR);
+		goto out_unreg_reboot;
+	}
+
+	pci_read_config_dword(dev, 0x58, &pmbase);
+	pmbase &= 0x0000FF00;
+
+	if (pmbase == 0) {
+		printk (KERN_ERR PFX "power management base not set\n");
+		ret = -EIO;
+		goto out_unreg_misc;
+	}
+
+	/* ret = 0; */
+	printk(banner);
+	goto out_clean;
+
+out_unreg_misc:
+	misc_deregister(&amdtco_miscdev);
+out_unreg_reboot:
+	unregister_reboot_notifier(&amdtco_notifier);
+out_clean:
+	return ret;
+}
+
+static void __exit amdtco_exit(void)
+{
+	misc_deregister(&amdtco_miscdev);
+	unregister_reboot_notifier(&amdtco_notifier);
+}
+
+
+#ifndef MODULE
+static int __init amdtco_setup(char *str)
+{
+	int ints[4];
+
+	str = get_options (str, ARRAY_SIZE(ints), ints);
+	if (ints[0] > 0)
+		timeout = ints[1];
+
+	return 1;
+}
+
+__setup("amd7xx_tco=", amdtco_setup);
+#endif
+
+module_init(amdtco_init);
+module_exit(amdtco_exit);
+
+MODULE_AUTHOR("Zwane Mwaikambo <zwane@commfireservices.com>");
+MODULE_DESCRIPTION("AMD 766/768 TCO Timer Driver");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/amiserial.c linux-2.4.20/drivers/char/amiserial.c
--- linux-2.4.19/drivers/char/amiserial.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/amiserial.c	2002-10-29 11:18:51.000000000 +0000
@@ -2054,8 +2054,8 @@
 	return ret;
 }
 
-int rs_read_proc(char *page, char **start, off_t off, int count,
-		 int *eof, void *data)
+static int rs_read_proc(char *page, char **start, off_t off, int count,
+			int *eof, void *data)
 {
 	int len = 0, l;
 	off_t	begin = 0;
@@ -2306,43 +2306,17 @@
 	custom.intena = IF_SETCLR | (intena & IF_TBE);
 }
 
-/*
- *	Receive character from the serial port
- */
-static int serial_console_wait_key(struct console *co)
-{
-	unsigned short intena = custom.intenar;
-	int ch;
-
-	custom.intena = IF_RBF;
-
-	while (!(custom.intreqr & IF_RBF))
-		barrier();
-	ch = custom.serdatr & 0xff;
-	custom.intreq = IF_RBF;
-
-	custom.intena = IF_SETCLR | (intena & IF_RBF);
-
-	return ch;
-}
-
 static kdev_t serial_console_device(struct console *c)
 {
 	return MKDEV(TTY_MAJOR, 64);
 }
 
 static struct console sercons = {
-	"ttyS",
-	serial_console_write,
-	NULL,
-	serial_console_device,
-	serial_console_wait_key,
-	NULL,
-	NULL,
-	CON_PRINTBUFFER,
-	-1,
-	0,
-	NULL
+	name:	"ttyS",
+	write:	serial_console_write,
+	device:	serial_console_device,
+	flags:	CON_PRINTBUFFER,
+	index:	-1,
 };
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/console.c linux-2.4.20/drivers/char/console.c
--- linux-2.4.19/drivers/char/console.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/console.c	2002-10-29 11:18:36.000000000 +0000
@@ -1421,7 +1421,10 @@
 	kbd_table[currcons].slockstate = 0;
 	kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
 	kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
-	set_leds();
+	
+	/* Only schedule the keyboard_tasklet if it is enabled. */
+	if(!atomic_read(&keyboard_tasklet.count))
+		set_leds();
 
 	cursor_type = CUR_DEFAULT;
 	complement_mask = s_complement_mask;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/cyclades.c linux-2.4.20/drivers/char/cyclades.c
--- linux-2.4.19/drivers/char/cyclades.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.20/drivers/char/cyclades.c	2002-10-29 11:18:34.000000000 +0000
@@ -3446,8 +3446,8 @@
 		}
 #ifdef CY_DEBUG_DTR
 		printk("cyc:set_line_char dropping DTR\n");
-		printk("     status: 0x%x,
-		    0x%x\n", cy_readb(base_addr+(CyMSVR1<<index)),
+		printk("     status: 0x%x, 0x%x\n", 
+		    cy_readb(base_addr+(CyMSVR1<<index)),
 		    cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
 	    }else{
@@ -5175,7 +5175,6 @@
 		/* Although we don't use this I/O region, we should
 		   request it from the kernel anyway, to avoid problems
 		   with other drivers accessing it. */
-		request_region(cy_pci_phys1, CyPCI_Zctl, "Cyclades-Z");
 		resource = request_region(cy_pci_phys1, CyPCI_Zctl, 
 					  "Cyclades-Z");
 		if (resource == NULL) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/dn_keyb.c linux-2.4.20/drivers/char/dn_keyb.c
--- linux-2.4.19/drivers/char/dn_keyb.c	2000-07-14 19:20:22.000000000 +0000
+++ linux-2.4.20/drivers/char/dn_keyb.c	2002-10-29 11:18:35.000000000 +0000
@@ -5,6 +5,7 @@
 #include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/kd.h>
+#include <linux/kbd_ll.h>
 #include <linux/random.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -19,8 +20,6 @@
 
 #include "busmouse.h"
 
-/* extern void handle_scancode(unsigned char,int ); */
-
 #define DNKEY_CAPS 0x7e
 #define BREAK_FLAG 0x80
 #define DNKEY_REPEAT_DELAY 50
@@ -336,7 +335,8 @@
 
 	static short mouse_byte_count=0;
 	static u_char mouse_packet[3];
-	short mouse_buttons;	
+	short buttons;
+	int dx, dy;
 
 	mouse_packet[mouse_byte_count++]=mouse_data;
 
@@ -347,24 +347,12 @@
 /*			printk("modechange: %d\n",mouse_packet[1]); */
 			if(kbd_mode==APOLLO_KBD_MODE_KEYB)
 				dn_keyb_process_key_event(mouse_packet[2]);
-		}				
+		}
 		if((mouse_packet[0] & 0x8f) == 0x80) {
-			if(mouse_update_allowed) {
-				mouse_ready=1;
-				mouse_buttons=(mouse_packet[0] >> 4) & 0x7;
-				mouse_dx+=mouse_packet[1] == 0xff ? 0 : (signed char)mouse_packet[1];
-				mouse_dy+=mouse_packet[2] == 0xff ? 0 : (signed char)mouse_packet[2];
-				wake_up_interruptible(&mouse_wait);
-				if (mouse_dx < -2048)
-              				mouse_dx = -2048;
-          			else if (mouse_dx >  2048)
-              				mouse_dx =  2048;
-         	 		if (mouse_dy < -2048)
-              				mouse_dy = -2048;
-          			else if (mouse_dy >  2048)
-             			 	mouse_dy =  2048;
-              			kill_fasync(&mouse_fasyncptr, SIGIO, POLL_IN);
-			}
+			buttons = (mouse_packet[0] >> 4) & 0x7;
+			dx = mouse_packet[1] == 0xff ? 0 : (signed char)mouse_packet[1];
+			dy = mouse_packet[2] == 0xff ? 0 : (signed char)mouse_packet[2];
+			busmouse_add_movementbuttons(msedev, dx, dy, buttons);
 			mouse_byte_count=0;
 /*			printk("mouse: %d, %d, %x\n",mouse_x,mouse_y,buttons); */
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/Config.in linux-2.4.20/drivers/char/drm/Config.in
--- linux-2.4.19/drivers/char/drm/Config.in	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/Config.in	2002-10-29 11:18:50.000000000 +0000
@@ -10,5 +10,7 @@
 tristate '  ATI Rage 128' CONFIG_DRM_R128
 dep_tristate '  ATI Radeon' CONFIG_DRM_RADEON $CONFIG_AGP
 dep_tristate '  Intel I810' CONFIG_DRM_I810 $CONFIG_AGP
+dep_mbool    '    Enabled XFree 4.1 ioctl interface by default' CONFIG_DRM_I810_XFREE_41 $CONFIG_DRM_I810
+dep_tristate '  Intel 830M' CONFIG_DRM_I830 $CONFIG_AGP
 dep_tristate '  Matrox g200/g400' CONFIG_DRM_MGA $CONFIG_AGP
 dep_tristate '  SiS' CONFIG_DRM_SIS $CONFIG_AGP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/Makefile linux-2.4.20/drivers/char/drm/Makefile
--- linux-2.4.19/drivers/char/drm/Makefile	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/Makefile	2002-10-29 11:18:50.000000000 +0000
@@ -3,13 +3,15 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 O_TARGET	:= drm.o
-list-multi	:= gamma.o tdfx.o r128.o mga.o i810.o radeon.o ffb.o sis.o
+list-multi	:= gamma.o tdfx.o r128.o mga.o i810.o i830.o radeon.o ffb.o sis.o
 
 gamma-objs  := gamma_drv.o gamma_dma.o
 tdfx-objs   := tdfx_drv.o
 r128-objs   := r128_drv.o r128_cce.o r128_state.o
 mga-objs    := mga_drv.o mga_dma.o mga_state.o mga_warp.o
 i810-objs   := i810_drv.o i810_dma.o
+i830-objs   := i830_drv.o i830_dma.o
+
 radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o
 ffb-objs    := ffb_drv.o ffb_context.o
 sis-objs    := sis_drv.o sis_ds.o sis_mm.o
@@ -20,6 +22,7 @@
 obj-$(CONFIG_DRM_RADEON)+= radeon.o
 obj-$(CONFIG_DRM_MGA)	+= mga.o
 obj-$(CONFIG_DRM_I810)	+= i810.o
+obj-$(CONFIG_DRM_I830)	+= i830.o
 obj-$(CONFIG_DRM_FFB)   += ffb.o
 obj-$(CONFIG_DRM_SIS)   += sis.o
 
@@ -37,6 +40,9 @@
 i810.o: $(i810-objs) $(lib)
 	$(LD) -r -o $@ $(i810-objs) $(lib)
 
+i830.o: $(i830-objs) $(lib)
+	$(LD) -r -o $@ $(i830-objs) $(lib)
+
 r128.o: $(r128-objs) $(lib)
 	$(LD) -r -o $@ $(r128-objs) $(lib)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/ati_pcigart.h linux-2.4.20/drivers/char/drm/ati_pcigart.h
--- linux-2.4.19/drivers/char/drm/ati_pcigart.h	2001-11-22 19:46:37.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/ati_pcigart.h	2002-10-29 11:18:49.000000000 +0000
@@ -27,17 +27,22 @@
  *   Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
-#if PAGE_SIZE == 8192
+#if PAGE_SIZE == 65536
+# define ATI_PCIGART_TABLE_ORDER 	0
+# define ATI_PCIGART_TABLE_PAGES 	(1 << 0)
+#elif PAGE_SIZE == 16384
+# define ATI_PCIGART_TABLE_ORDER 	1
+# define ATI_PCIGART_TABLE_PAGES 	(1 << 1)
+#elif PAGE_SIZE == 8192
 # define ATI_PCIGART_TABLE_ORDER 	2
 # define ATI_PCIGART_TABLE_PAGES 	(1 << 2)
 #elif PAGE_SIZE == 4096
 # define ATI_PCIGART_TABLE_ORDER 	3
 # define ATI_PCIGART_TABLE_PAGES 	(1 << 3)
 #else
-# error - PAGE_SIZE not 8K or 4K
+# error - PAGE_SIZE not 64K, 16K, 8K or 4K
 #endif
 
 # define ATI_MAX_PCIGART_PAGES		8192	/* 32 MB aperture, 4K pages */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm.h linux-2.4.20/drivers/char/drm/drm.h
--- linux-2.4.19/drivers/char/drm/drm.h	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm.h	2002-10-29 11:18:34.000000000 +0000
@@ -104,9 +104,8 @@
 #include "i810_drm.h"
 #include "r128_drm.h"
 #include "radeon_drm.h"
-#if defined(CONFIG_DRM_SIS) || defined(CONFIG_DRM_SIS_MODULE)
 #include "sis_drm.h"
-#endif
+#include "i830_drm.h"
 
 typedef struct drm_version {
 	int    version_major;	  /* Major version			    */
@@ -449,6 +448,12 @@
 #define DRM_IOCTL_I810_SWAP		DRM_IO(  0x46)
 #define DRM_IOCTL_I810_COPY		DRM_IOW( 0x47, drm_i810_copy_t)
 #define DRM_IOCTL_I810_DOCOPY		DRM_IO(  0x48)
+#define DRM_IOCTL_I810_OV0INFO		DRM_IOR( 0x49, drm_i810_overlay_t)
+#define DRM_IOCTL_I810_FSTATUS		DRM_IO ( 0x4a)
+#define DRM_IOCTL_I810_OV0FLIP		DRM_IO ( 0x4b)
+#define DRM_IOCTL_I810_MC		DRM_IOW( 0x4c, drm_i810_mc_t)
+#define DRM_IOCTL_I810_RSTATUS		DRM_IO ( 0x4d )
+
 
 /* Rage 128 specific ioctls */
 #define DRM_IOCTL_R128_INIT		DRM_IOW( 0x40, drm_r128_init_t)
@@ -483,7 +488,6 @@
 #define DRM_IOCTL_RADEON_INDIRECT	DRM_IOWR(0x4d, drm_radeon_indirect_t)
 #define DRM_IOCTL_RADEON_TEXTURE	DRM_IOWR(0x4e, drm_radeon_texture_t)
 
-#if defined(CONFIG_DRM_SIS) || defined(CONFIG_DRM_SIS_MODULE)
 /* SiS specific ioctls */
 #define SIS_IOCTL_FB_ALLOC		DRM_IOWR(0x44, drm_sis_mem_t)
 #define SIS_IOCTL_FB_FREE		DRM_IOW( 0x45, drm_sis_mem_t)
@@ -493,6 +497,16 @@
 #define SIS_IOCTL_FLIP			DRM_IOW( 0x48, drm_sis_flip_t)
 #define SIS_IOCTL_FLIP_INIT		DRM_IO(  0x49)
 #define SIS_IOCTL_FLIP_FINAL		DRM_IO(  0x50)
-#endif
+
+/* I830 specific ioctls */
+#define DRM_IOCTL_I830_INIT		DRM_IOW( 0x40, drm_i830_init_t)
+#define DRM_IOCTL_I830_VERTEX		DRM_IOW( 0x41, drm_i830_vertex_t)
+#define DRM_IOCTL_I830_CLEAR		DRM_IOW( 0x42, drm_i830_clear_t)
+#define DRM_IOCTL_I830_FLUSH		DRM_IO ( 0x43)
+#define DRM_IOCTL_I830_GETAGE		DRM_IO ( 0x44)
+#define DRM_IOCTL_I830_GETBUF		DRM_IOWR(0x45, drm_i830_dma_t)
+#define DRM_IOCTL_I830_SWAP		DRM_IO ( 0x46)
+#define DRM_IOCTL_I830_COPY		DRM_IOW( 0x47, drm_i830_copy_t)
+#define DRM_IOCTL_I830_DOCOPY		DRM_IO ( 0x48)
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drmP.h linux-2.4.20/drivers/char/drm/drmP.h
--- linux-2.4.19/drivers/char/drm/drmP.h	2001-11-22 19:46:37.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drmP.h	2002-10-29 11:18:49.000000000 +0000
@@ -66,13 +66,8 @@
 #include <linux/types.h>
 #include <linux/agp_backend.h>
 #endif
-#if LINUX_VERSION_CODE >= 0x020100 /* KERNEL_VERSION(2,1,0) */
 #include <linux/tqueue.h>
 #include <linux/poll.h>
-#endif
-#if LINUX_VERSION_CODE < 0x020400
-#include "compat-pre24.h"
-#endif
 #include <asm/pgalloc.h>
 #include "drm.h"
 
@@ -81,12 +76,6 @@
 #define page_to_bus(page)	((unsigned int)(virt_to_bus(page_address(page))))
 #endif
 
-/* We just use virt_to_bus for pci_map_single on older kernels */
-#if LINUX_VERSION_CODE < 0x020400
-#define pci_map_single(hwdev, ptr, size, direction)	virt_to_bus(ptr)
-#define pci_unmap_single(hwdev, dma_addr, size, direction)
-#endif
-
 /* DRM template customization defaults
  */
 #ifndef __HAVE_AGP
@@ -119,87 +108,6 @@
 #define __REALLY_HAVE_MTRR	(__HAVE_MTRR && defined(CONFIG_MTRR))
 
 
-/* Begin the DRM...
- */
-
-#define DRM_DEBUG_CODE 2	  /* Include debugging code (if > 1, then
-				     also include looping detection. */
-
-#define DRM_HASH_SIZE	      16 /* Size of key hash table		  */
-#define DRM_KERNEL_CONTEXT    0	 /* Change drm_resctx if changed	  */
-#define DRM_RESERVED_CONTEXTS 1	 /* Change drm_resctx if changed	  */
-#define DRM_LOOPING_LIMIT     5000000
-#define DRM_BSZ		      1024 /* Buffer size for /dev/drm? output	  */
-#define DRM_TIME_SLICE	      (HZ/20)  /* Time slice for GLXContexts	  */
-#define DRM_LOCK_SLICE	      1	/* Time slice for lock, in jiffies	  */
-
-#define DRM_FLAG_DEBUG	  0x01
-#define DRM_FLAG_NOCTX	  0x02
-
-#define DRM_MEM_DMA	   0
-#define DRM_MEM_SAREA	   1
-#define DRM_MEM_DRIVER	   2
-#define DRM_MEM_MAGIC	   3
-#define DRM_MEM_IOCTLS	   4
-#define DRM_MEM_MAPS	   5
-#define DRM_MEM_VMAS	   6
-#define DRM_MEM_BUFS	   7
-#define DRM_MEM_SEGS	   8
-#define DRM_MEM_PAGES	   9
-#define DRM_MEM_FILES	  10
-#define DRM_MEM_QUEUES	  11
-#define DRM_MEM_CMDS	  12
-#define DRM_MEM_MAPPINGS  13
-#define DRM_MEM_BUFLISTS  14
-#define DRM_MEM_AGPLISTS  15
-#define DRM_MEM_TOTALAGP  16
-#define DRM_MEM_BOUNDAGP  17
-#define DRM_MEM_CTXBITMAP 18
-#define DRM_MEM_STUB      19
-#define DRM_MEM_SGLISTS   20
-
-#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
-
-				/* Backward compatibility section */
-				/* _PAGE_WT changed to _PAGE_PWT in 2.2.6 */
-#ifndef _PAGE_PWT
-#define _PAGE_PWT _PAGE_WT
-#endif
-				/* Wait queue declarations changed in 2.3.1 */
-#ifndef DECLARE_WAITQUEUE
-#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = { c, NULL }
-typedef struct wait_queue *wait_queue_head_t;
-#define init_waitqueue_head(q) *q = NULL;
-#endif
-
-				/* _PAGE_4M changed to _PAGE_PSE in 2.3.23 */
-#ifndef _PAGE_PSE
-#define _PAGE_PSE _PAGE_4M
-#endif
-
-				/* vm_offset changed to vm_pgoff in 2.3.25 */
-#if LINUX_VERSION_CODE < 0x020319
-#define VM_OFFSET(vma) ((vma)->vm_offset)
-#else
-#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
-#endif
-
-				/* *_nopage return values defined in 2.3.26 */
-#ifndef NOPAGE_SIGBUS
-#define NOPAGE_SIGBUS 0
-#endif
-#ifndef NOPAGE_OOM
-#define NOPAGE_OOM 0
-#endif
-
-				/* module_init/module_exit added in 2.3.13 */
-#ifndef module_init
-#define module_init(x)  int init_module(void) { return x(); }
-#endif
-#ifndef module_exit
-#define module_exit(x)  void cleanup_module(void) { x(); }
-#endif
-
 				/* Generic cmpxchg added in 2.3.x */
 #ifndef __HAVE_ARCH_CMPXCHG
 				/* Include this here so that driver can be
@@ -211,7 +119,7 @@
 	unsigned long prev, cmp;
 
 	__asm__ __volatile__(
-	"1:	ldl_l %0,%5\n"
+	"1:	ldl_l %0,%2\n"
 	"	cmpeq %0,%3,%1\n"
 	"	beq %1,2f\n"
 	"	mov %4,%1\n"
@@ -222,8 +130,7 @@
 	"3:	br 1b\n"
 	".previous"
 	: "=&r"(prev), "=&r"(cmp), "=m"(*m)
-	: "r"((long) old), "r"(new), "m"(*m)
-	: "memory" );
+	: "r"((long) old), "r"(new), "m"(*m));
 
 	return prev;
 }
@@ -234,7 +141,7 @@
 	unsigned long prev, cmp;
 
 	__asm__ __volatile__(
-	"1:	ldq_l %0,%5\n"
+	"1:	ldq_l %0,%2\n"
 	"	cmpeq %0,%3,%1\n"
 	"	beq %1,2f\n"
 	"	mov %4,%1\n"
@@ -245,8 +152,7 @@
 	"3:	br 1b\n"
 	".previous"
 	: "=&r"(prev), "=&r"(cmp), "=m"(*m)
-	: "r"((long) old), "r"(new), "m"(*m)
-	: "memory" );
+	: "r"((long) old), "r"(new), "m"(*m));
 
 	return prev;
 }
@@ -298,42 +204,82 @@
 	return old;
 }
 
-#elif defined(__powerpc__)
-extern void __cmpxchg_called_with_bad_pointer(void);
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-                                      unsigned long new, int size)
-{
-	unsigned long prev;
-
-	switch (size) {
-	case 4:
-		__asm__ __volatile__(
-			"sync;"
-			"0:    lwarx %0,0,%1 ;"
-			"      cmpl 0,%0,%3;"
-			"      bne 1f;"
-			"      stwcx. %2,0,%1;"
-			"      bne- 0b;"
-			"1:    "
-			"sync;"
-			: "=&r"(prev)
-			: "r"(ptr), "r"(new), "r"(old)
-			: "cr0", "memory");
-		return prev;
-	}
-	__cmpxchg_called_with_bad_pointer();
-	return old;
-}
-
-#endif /* i386, powerpc & alpha */
-
-#ifndef __alpha__
 #define cmpxchg(ptr,o,n)						\
   ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),		\
 				 (unsigned long)(n),sizeof(*(ptr))))
+#endif /* i386 & alpha */
 #endif
 
-#endif /* !__HAVE_ARCH_CMPXCHG */
+/* Begin the DRM...
+ */
+
+#define DRM_DEBUG_CODE 2	  /* Include debugging code (if > 1, then
+				     also include looping detection. */
+
+#define DRM_HASH_SIZE	      16 /* Size of key hash table		  */
+#define DRM_KERNEL_CONTEXT    0	 /* Change drm_resctx if changed	  */
+#define DRM_RESERVED_CONTEXTS 1	 /* Change drm_resctx if changed	  */
+#define DRM_LOOPING_LIMIT     5000000
+#define DRM_BSZ		      1024 /* Buffer size for /dev/drm? output	  */
+#define DRM_TIME_SLICE	      (HZ/20)  /* Time slice for GLXContexts	  */
+#define DRM_LOCK_SLICE	      1	/* Time slice for lock, in jiffies	  */
+
+#define DRM_FLAG_DEBUG	  0x01
+#define DRM_FLAG_NOCTX	  0x02
+
+#define DRM_MEM_DMA	   0
+#define DRM_MEM_SAREA	   1
+#define DRM_MEM_DRIVER	   2
+#define DRM_MEM_MAGIC	   3
+#define DRM_MEM_IOCTLS	   4
+#define DRM_MEM_MAPS	   5
+#define DRM_MEM_VMAS	   6
+#define DRM_MEM_BUFS	   7
+#define DRM_MEM_SEGS	   8
+#define DRM_MEM_PAGES	   9
+#define DRM_MEM_FILES	  10
+#define DRM_MEM_QUEUES	  11
+#define DRM_MEM_CMDS	  12
+#define DRM_MEM_MAPPINGS  13
+#define DRM_MEM_BUFLISTS  14
+#define DRM_MEM_AGPLISTS  15
+#define DRM_MEM_TOTALAGP  16
+#define DRM_MEM_BOUNDAGP  17
+#define DRM_MEM_CTXBITMAP 18
+#define DRM_MEM_STUB      19
+#define DRM_MEM_SGLISTS   20
+
+#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
+
+#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
+
+/* Macros to make printk easier */
+
+#if ( __GNUC__ > 2 )
+
+#define DRM_ERROR(fmt, arg...) \
+	printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __FUNCTION__, ##arg)
+#define DRM_MEM_ERROR(area, fmt, arg...) \
+	printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __FUNCTION__, \
+	       DRM(mem_stats)[area].name , ##arg)
+#define DRM_INFO(fmt, arg...)  printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg)
+
+#if DRM_DEBUG_CODE
+#define DRM_DEBUG(fmt, arg...)						\
+	do {								\
+		if ( DRM(flags) & DRM_FLAG_DEBUG )			\
+			printk(KERN_DEBUG				\
+			       "[" DRM_NAME ":%s] " fmt ,		\
+			       __FUNCTION__,				\
+			       ##arg);					\
+	} while (0)
+#else
+#define DRM_DEBUG(fmt, arg...)		 do { } while (0)
+#endif
+
+#else	/* Gcc 2.x */
+
+/* Work around a C preprocessor bug */
 
 				/* Macros to make printk easier */
 #define DRM_ERROR(fmt, arg...) \
@@ -355,6 +301,9 @@
 #define DRM_DEBUG(fmt, arg...)		 do { } while (0)
 #endif
 
+#endif	/* Gcc 2.x */
+
+
 #define DRM_PROC_LIMIT (PAGE_SIZE-80)
 
 #define DRM_PROC_PRINT(fmt, arg...)					\
@@ -730,12 +679,8 @@
 #endif
 	struct pci_dev *pdev;
 #ifdef __alpha__
-#if LINUX_VERSION_CODE < 0x020403
-	struct pci_controler *hose;
-#else
 	struct pci_controller *hose;
 #endif
-#endif
 	drm_sg_mem_t      *sg;  /* Scatter gather memory */
 	unsigned long     *ctx_bitmap;
 	void		  *dev_private;
@@ -778,21 +723,6 @@
 			       struct poll_table_struct *wait);
 
 				/* Mapping support (drm_vm.h) */
-#if LINUX_VERSION_CODE < 0x020317
-extern unsigned long DRM(vm_nopage)(struct vm_area_struct *vma,
-				    unsigned long address,
-				    int unused);
-extern unsigned long DRM(vm_shm_nopage)(struct vm_area_struct *vma,
-					unsigned long address,
-					int unused);
-extern unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma,
-					unsigned long address,
-					int unused);
-extern unsigned long DRM(vm_sg_nopage)(struct vm_area_struct *vma,
-				       unsigned long address,
-				       int unused);
-#else
-				/* Return type changed in 2.3.23 */
 extern struct page *DRM(vm_nopage)(struct vm_area_struct *vma,
 				   unsigned long address,
 				   int unused);
@@ -805,7 +735,6 @@
 extern struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma,
 				      unsigned long address,
 				      int unused);
-#endif
 extern void	     DRM(vm_open)(struct vm_area_struct *vma);
 extern void	     DRM(vm_close)(struct vm_area_struct *vma);
 extern void	     DRM(vm_shm_close)(struct vm_area_struct *vma);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_agpsupport.h linux-2.4.20/drivers/char/drm/drm_agpsupport.h
--- linux-2.4.19/drivers/char/drm/drm_agpsupport.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_agpsupport.h	2002-10-29 11:18:30.000000000 +0000
@@ -29,18 +29,13 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 #include <linux/module.h>
 
 #if __REALLY_HAVE_AGP
 
-#if LINUX_VERSION_CODE < 0x020400
-#include "agpsupport-pre24.h"
-#else
 #define DRM_AGP_GET (drm_agp_t *)inter_module_get("drm_agp")
 #define DRM_AGP_PUT inter_module_put("drm_agp")
-#endif
 
 static const drm_agp_t *drm_agp = NULL;
 
@@ -270,35 +265,30 @@
 		case INTEL_BX:		head->chipset = "Intel 440BX";   break;
 		case INTEL_GX:		head->chipset = "Intel 440GX";   break;
 		case INTEL_I810:	head->chipset = "Intel i810";    break;
-
-#if LINUX_VERSION_CODE >= 0x020400
 		case INTEL_I815:	head->chipset = "Intel i815";	 break;
 	 	case INTEL_I820:	head->chipset = "Intel i820";	 break;
 		case INTEL_I840:	head->chipset = "Intel i840";    break;
 		case INTEL_I845:	head->chipset = "Intel i845";    break;
 		case INTEL_I850:	head->chipset = "Intel i850";	 break;
-#endif
 
 		case VIA_GENERIC:	head->chipset = "VIA";           break;
 		case VIA_VP3:		head->chipset = "VIA VP3";       break;
 		case VIA_MVP3:		head->chipset = "VIA MVP3";      break;
-#if LINUX_VERSION_CODE >= 0x020400
 		case VIA_MVP4:		head->chipset = "VIA MVP4";      break;
 		case VIA_APOLLO_KX133:	head->chipset = "VIA Apollo KX133";
 			break;
 		case VIA_APOLLO_KT133:	head->chipset = "VIA Apollo KT133";
 			break;
-#endif
-
 		case VIA_APOLLO_PRO: 	head->chipset = "VIA Apollo Pro";
 			break;
+
 		case SIS_GENERIC:	head->chipset = "SiS";           break;
 		case AMD_GENERIC:	head->chipset = "AMD";           break;
 		case AMD_IRONGATE:	head->chipset = "AMD Irongate";  break;
+		case AMD_8151:		head->chipset = "AMD 8151";      break;
 		case ALI_GENERIC:	head->chipset = "ALi";           break;
 		case ALI_M1541: 	head->chipset = "ALi M1541";     break;
 
-#if LINUX_VERSION_CODE >= 0x020402
 		case ALI_M1621: 	head->chipset = "ALi M1621";	 break;
 		case ALI_M1631: 	head->chipset = "ALi M1631";	 break;
 		case ALI_M1632: 	head->chipset = "ALi M1632";	 break;
@@ -306,28 +296,21 @@
 		case ALI_M1644: 	head->chipset = "ALi M1644";	 break;
 		case ALI_M1647: 	head->chipset = "ALi M1647";	 break;
 		case ALI_M1651: 	head->chipset = "ALi M1651";	 break;
-#endif
 
-#if LINUX_VERSION_CODE >= 0x020406
 		case SVWRKS_HE: 	head->chipset = "Serverworks HE";
 			break;
 		case SVWRKS_LE: 	head->chipset = "Serverworks LE";
 			break;
 		case SVWRKS_GENERIC: 	head->chipset = "Serverworks Generic";
 			break;
-#endif
 
 		case HP_ZX1:		head->chipset = "HP ZX1";	 break;
 
 		default:		head->chipset = "Unknown";       break;
 		}
-#if LINUX_VERSION_CODE <= 0x020408
-		head->cant_use_aperture = 0;
-		head->page_mask = ~(0xfff);
-#else
+
 		head->cant_use_aperture = head->agp_info.cant_use_aperture;
 		head->page_mask = head->agp_info.page_mask;
-#endif
 
 		DRM_INFO("AGP %d.%d on %s @ 0x%08lx %ZuMB\n",
 			 head->agp_info.version.major,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_auth.h linux-2.4.20/drivers/char/drm/drm_auth.h
--- linux-2.4.19/drivers/char/drm/drm_auth.h	2001-11-22 19:46:37.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_auth.h	2002-10-29 11:18:49.000000000 +0000
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 static int DRM(hash_magic)(drm_magic_t magic)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_bufs.h linux-2.4.20/drivers/char/drm/drm_bufs.h
--- linux-2.4.19/drivers/char/drm/drm_bufs.h	2001-11-22 19:46:37.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_bufs.h	2002-10-29 11:18:34.000000000 +0000
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include <linux/vmalloc.h>
 #include "drmP.h"
 
@@ -229,11 +228,7 @@
 	DRM(free)(list, sizeof(*list), DRM_MEM_MAPS);
 
 	for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
-#if LINUX_VERSION_CODE >= 0x020300
 		if (pt->vma->vm_private_data == map) found_maps++;
-#else
-		if (pt->vma->vm_pte == map) found_maps++;
-#endif
 	}
 
 	if(!found_maps) {
@@ -1063,34 +1058,18 @@
 				goto done;
 			}
 
-#if LINUX_VERSION_CODE <= 0x020402
-			down( &current->mm->mmap_sem );
-#else
 			down_write( &current->mm->mmap_sem );
-#endif
 			virtual = do_mmap( filp, 0, map->size,
 					   PROT_READ | PROT_WRITE,
 					   MAP_SHARED,
 					   (unsigned long)map->offset );
-#if LINUX_VERSION_CODE <= 0x020402
-			up( &current->mm->mmap_sem );
-#else
 			up_write( &current->mm->mmap_sem );
-#endif
 		} else {
-#if LINUX_VERSION_CODE <= 0x020402
-			down( &current->mm->mmap_sem );
-#else
 			down_write( &current->mm->mmap_sem );
-#endif
 			virtual = do_mmap( filp, 0, dma->byte_count,
 					   PROT_READ | PROT_WRITE,
 					   MAP_SHARED, 0 );
-#if LINUX_VERSION_CODE <= 0x020402
-			up( &current->mm->mmap_sem );
-#else
 			up_write( &current->mm->mmap_sem );
-#endif
 		}
 		if ( virtual > -1024UL ) {
 			/* Real error */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_context.h linux-2.4.20/drivers/char/drm/drm_context.h
--- linux-2.4.19/drivers/char/drm/drm_context.h	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_context.h	2002-10-29 11:18:30.000000000 +0000
@@ -33,7 +33,6 @@
  *		needed by SiS driver's memory management.
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 #if __HAVE_CTX_BITMAP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_dma.h linux-2.4.20/drivers/char/drm/drm_dma.h
--- linux-2.4.19/drivers/char/drm/drm_dma.h	2001-11-22 19:46:37.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_dma.h	2002-10-29 11:18:48.000000000 +0000
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 #include <linux/interrupt.h>	/* For task queue support */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_drawable.h linux-2.4.20/drivers/char/drm/drm_drawable.h
--- linux-2.4.19/drivers/char/drm/drm_drawable.h	2001-11-22 19:46:37.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_drawable.h	2002-10-29 11:18:49.000000000 +0000
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 int DRM(adddraw)(struct inode *inode, struct file *filp,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_drv.h linux-2.4.20/drivers/char/drm/drm_drv.h
--- linux-2.4.19/drivers/char/drm/drm_drv.h	2001-10-21 17:40:36.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_drv.h	2002-10-29 11:18:35.000000000 +0000
@@ -113,7 +113,6 @@
 #define DRIVER_IOCTLS
 #endif
 #ifndef DRIVER_FOPS
-#if LINUX_VERSION_CODE >= 0x020400
 #define DRIVER_FOPS				\
 static struct file_operations	DRM(fops) = {	\
 	owner:   THIS_MODULE,			\
@@ -126,19 +125,6 @@
 	fasync:	 DRM(fasync),			\
 	poll:	 DRM(poll),			\
 }
-#else
-#define DRIVER_FOPS				\
-static struct file_operations	DRM(fops) = {	\
-	open:	 DRM(open),			\
-	flush:	 DRM(flush),			\
-	release: DRM(release),			\
-	ioctl:	 DRM(ioctl),			\
-	mmap:	 DRM(mmap),			\
-	read:	 DRM(read),			\
-	fasync:	 DRM(fasync),			\
-	poll:	 DRM(poll),			\
-}
-#endif
 #endif
 
 
@@ -732,9 +718,6 @@
 
 	retcode = DRM(open_helper)( inode, filp, dev );
 	if ( !retcode ) {
-#if LINUX_VERSION_CODE < 0x020333
-		MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
 		atomic_inc( &dev->counts[_DRM_STAT_OPENS] );
 		spin_lock( &dev->count_lock );
 		if ( !dev->open_count++ ) {
@@ -853,9 +836,6 @@
 	 * End inline drm_release
 	 */
 
-#if LINUX_VERSION_CODE < 0x020333
-	MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
 	atomic_inc( &dev->counts[_DRM_STAT_CLOSES] );
 	spin_lock( &dev->count_lock );
 	if ( !--dev->open_count ) {
@@ -1047,25 +1027,6 @@
 
 	atomic_inc( &dev->counts[_DRM_STAT_UNLOCKS] );
 
-#if __HAVE_KERNEL_CTX_SWITCH
-	/* We no longer really hold it, but if we are the next
-	 * agent to request it then we should just be able to
-	 * take it immediately and not eat the ioctl.
-	 */
-	dev->lock.pid = 0;
-	{
-		__volatile__ unsigned int *plock = &dev->lock.hw_lock->lock;
-		unsigned int old, new, prev, ctx;
-
-		ctx = lock.context;
-		do {
-			old  = *plock;
-			new  = ctx;
-			prev = cmpxchg(plock, old, new);
-		} while (prev != old);
-	}
-	wake_up_interruptible(&dev->lock.lock_queue);
-#else
 	DRM(lock_transfer)( dev, &dev->lock.hw_lock->lock,
 			    DRM_KERNEL_CONTEXT );
 #if __HAVE_DMA_SCHEDULE
@@ -1080,7 +1041,6 @@
 			DRM_ERROR( "\n" );
 		}
 	}
-#endif /* !__HAVE_KERNEL_CTX_SWITCH */
 
 	unblock_all_signals();
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_fops.h linux-2.4.20/drivers/char/drm/drm_fops.h
--- linux-2.4.19/drivers/char/drm/drm_fops.h	2001-11-22 19:46:37.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_fops.h	2002-10-29 11:18:31.000000000 +0000
@@ -30,7 +30,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 #include <linux/poll.h>
 
@@ -97,6 +96,23 @@
 
 	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
 		  current->pid, dev->device, dev->open_count);
+	if ( dev->lock.hw_lock &&
+	     _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
+	     dev->lock.pid == current->pid ) {
+		DRM_DEBUG( "Process %d closed fd, freeing lock for context %d\n",
+			   current->pid,
+			   _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) );
+#if __HAVE_RELEASE
+		DRIVER_RELEASE();
+#endif
+		DRM(lock_free)( dev, &dev->lock.hw_lock->lock,
+				_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) );
+
+				/* FIXME: may require heavy-handed reset of
+                                   hardware at this point, possibly
+                                   processed via a callback to the X
+                                   server. */
+	}
 	return 0;
 }
 
@@ -125,21 +141,31 @@
 	int	      avail;
 	int	      send;
 	int	      cur;
+	DECLARE_WAITQUEUE(wait, current);
 
 	DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp);
 
+	add_wait_queue(&dev->buf_readers, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
 	while (dev->buf_rp == dev->buf_wp) {
 		DRM_DEBUG("  sleeping\n");
 		if (filp->f_flags & O_NONBLOCK) {
+			remove_wait_queue(&dev->buf_readers, &wait);
+			set_current_state(TASK_RUNNING);
 			return -EAGAIN;
 		}
-		interruptible_sleep_on(&dev->buf_readers);
+		schedule(); /* wait for dev->buf_readers */
 		if (signal_pending(current)) {
 			DRM_DEBUG("  interrupted\n");
+			remove_wait_queue(&dev->buf_readers, &wait);
+			set_current_state(TASK_RUNNING);
 			return -ERESTARTSYS;
 		}
 		DRM_DEBUG("  awake\n");
+		set_current_state(TASK_INTERRUPTIBLE);
 	}
+	remove_wait_queue(&dev->buf_readers, &wait);
+	set_current_state(TASK_RUNNING);
 
 	left  = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
 	avail = DRM_BSZ - left;
@@ -191,24 +217,8 @@
 		send -= count;
 	}
 
-#if LINUX_VERSION_CODE < 0x020315 && !defined(KILLFASYNCHASTHREEPARAMETERS)
-	/* The extra parameter to kill_fasync was added in 2.3.21, and is
-           _not_ present in _stock_ 2.2.14 and 2.2.15.  However, some
-           distributions patch 2.2.x kernels to add this parameter.  The
-           Makefile.linux attempts to detect this addition and defines
-           KILLFASYNCHASTHREEPARAMETERS if three parameters are found. */
-	if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO);
-#else
-
-				/* Parameter added in 2.3.21. */
-#if LINUX_VERSION_CODE < 0x020400
-	if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_IN);
-#else
-				/* Type of first parameter changed in
-                                   Linux 2.4.0-test2... */
 	if (dev->buf_async) kill_fasync(&dev->buf_async, SIGIO, POLL_IN);
-#endif
-#endif
+
 	DRM_DEBUG("waking\n");
 	wake_up_interruptible(&dev->buf_readers);
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_init.h linux-2.4.20/drivers/char/drm/drm_init.h
--- linux-2.4.19/drivers/char/drm/drm_init.h	2001-11-22 19:46:37.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_init.h	2002-10-29 11:18:36.000000000 +0000
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 #if 0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_ioctl.h linux-2.4.20/drivers/char/drm/drm_ioctl.h
--- linux-2.4.19/drivers/char/drm/drm_ioctl.h	2001-11-22 19:46:37.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_ioctl.h	2002-10-29 11:18:34.000000000 +0000
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 int DRM(irq_busid)(struct inode *inode, struct file *filp,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_lists.h linux-2.4.20/drivers/char/drm/drm_lists.h
--- linux-2.4.19/drivers/char/drm/drm_lists.h	2001-08-08 16:42:14.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_lists.h	2002-10-29 11:18:35.000000000 +0000
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 #if __HAVE_DMA_WAITLIST
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_lock.h linux-2.4.20/drivers/char/drm/drm_lock.h
--- linux-2.4.19/drivers/char/drm/drm_lock.h	2001-11-22 19:46:37.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_lock.h	2002-10-29 11:18:49.000000000 +0000
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 int DRM(block)(struct inode *inode, struct file *filp, unsigned int cmd,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_memory.h linux-2.4.20/drivers/char/drm/drm_memory.h
--- linux-2.4.19/drivers/char/drm/drm_memory.h	2001-11-22 19:46:37.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_memory.h	2002-10-29 11:18:34.000000000 +0000
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include <linux/config.h>
 #include "drmP.h"
 #include <linux/wrapper.h>
@@ -85,12 +84,7 @@
 	}
 
 	si_meminfo(&si);
-#if LINUX_VERSION_CODE < 0x020317
-				/* Changed to page count in 2.3.23 */
-	DRM(ram_available) = si.totalram >> PAGE_SHIFT;
-#else
 	DRM(ram_available) = si.totalram;
-#endif
 	DRM(ram_used)	   = 0;
 }
 
@@ -257,12 +251,7 @@
 	for (addr = address, sz = bytes;
 	     sz > 0;
 	     addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-#if LINUX_VERSION_CODE >= 0x020400
-				/* Argument type changed in 2.4.0-test6/pre8 */
 		mem_map_reserve(virt_to_page(addr));
-#else
-		mem_map_reserve(MAP_NR(addr));
-#endif
 	}
 
 	return address;
@@ -283,12 +272,7 @@
 		for (addr = address, sz = bytes;
 		     sz > 0;
 		     addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-#if LINUX_VERSION_CODE >= 0x020400
-				/* Argument type changed in 2.4.0-test6/pre8 */
 			mem_map_unreserve(virt_to_page(addr));
-#else
-			mem_map_unreserve(MAP_NR(addr));
-#endif
 		}
 		free_pages(address, order);
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_proc.h linux-2.4.20/drivers/char/drm/drm_proc.h
--- linux-2.4.19/drivers/char/drm/drm_proc.h	2001-11-22 19:46:37.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_proc.h	2002-10-29 11:18:33.000000000 +0000
@@ -33,7 +33,6 @@
  *    the problem with the proc files not outputting all their information.
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 static int	   DRM(name_info)(char *buf, char **start, off_t offset,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_scatter.h linux-2.4.20/drivers/char/drm/drm_scatter.h
--- linux-2.4.19/drivers/char/drm/drm_scatter.h	2001-11-22 19:46:37.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_scatter.h	2002-10-29 11:18:48.000000000 +0000
@@ -27,7 +27,6 @@
  *   Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include <linux/config.h>
 #include <linux/vmalloc.h>
 #include "drmP.h"
@@ -66,9 +65,6 @@
 	drm_scatter_gather_t request;
 	drm_sg_mem_t *entry;
 	unsigned long pages, i, j;
-	pgd_t *pgd;
-	pmd_t *pmd;
-	pte_t *pte;
 
 	DRM_DEBUG( "%s\n", __FUNCTION__ );
 
@@ -135,21 +131,10 @@
 	DRM_DEBUG( "sg alloc virtual = %p\n", entry->virtual );
 
 	for ( i = entry->handle, j = 0 ; j < pages ; i += PAGE_SIZE, j++ ) {
-		pgd = pgd_offset_k( i );
-		if ( !pgd_present( *pgd ) )
+		entry->pagelist[j] = vmalloc_to_page((void *)i);
+		if (!entry->pagelist[j])
 			goto failed;
-
-		pmd = pmd_offset( pgd, i );
-		if ( !pmd_present( *pmd ) )
-			goto failed;
-
-		pte = pte_offset( pmd, i );
-		if ( !pte_present( *pte ) )
-			goto failed;
-
-		entry->pagelist[j] = pte_page( *pte );
-
-		SetPageReserved( entry->pagelist[j] );
+		SetPageReserved(entry->pagelist[j]);
 	}
 
 	request.handle = entry->handle;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_stub.h linux-2.4.20/drivers/char/drm/drm_stub.h
--- linux-2.4.19/drivers/char/drm/drm_stub.h	2001-11-22 19:46:37.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_stub.h	2002-10-29 11:18:49.000000000 +0000
@@ -28,13 +28,8 @@
  *
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
-#if LINUX_VERSION_CODE < 0x020400
-#include "stubsupport-pre24.h"
-#endif
-
 #define DRM_STUB_MAXCARDS 16	/* Enough for one machine */
 
 static struct drm_stub_list {
@@ -70,9 +65,7 @@
 }
 
 static struct file_operations DRM(stub_fops) = {
-#if LINUX_VERSION_CODE >= 0x020400
 	owner:   THIS_MODULE,
-#endif
 	open:	 DRM(stub_open)
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/drm_vm.h linux-2.4.20/drivers/char/drm/drm_vm.h
--- linux-2.4.19/drivers/char/drm/drm_vm.h	2001-11-22 19:46:37.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/drm_vm.h	2002-10-29 11:18:40.000000000 +0000
@@ -29,7 +29,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "drmP.h"
 
 struct vm_operations_struct   DRM(vm_ops) = {
@@ -56,16 +55,9 @@
 	close:   DRM(vm_close),
 };
 
-#if LINUX_VERSION_CODE < 0x020317
-unsigned long DRM(vm_nopage)(struct vm_area_struct *vma,
-			     unsigned long address,
-			     int unused)
-#else
-				/* Return type changed in 2.3.23 */
 struct page *DRM(vm_nopage)(struct vm_area_struct *vma,
 			    unsigned long address,
 			    int unused)
-#endif
 {
 #if __REALLY_HAVE_AGP
 	drm_file_t *priv  = vma->vm_file->private_data;
@@ -122,11 +114,7 @@
 		DRM_DEBUG("baddr = 0x%lx page = 0x%p, offset = 0x%lx\n",
 			  baddr, __va(agpmem->memory->memory[offset]), offset);
 
-#if LINUX_VERSION_CODE < 0x020317
-		return page_address(page);
-#else
 		return page;
-#endif
         }
 vm_nopage_error:
 #endif /* __REALLY_HAVE_AGP */
@@ -134,27 +122,13 @@
 	return NOPAGE_SIGBUS;		/* Disallow mremap */
 }
 
-#if LINUX_VERSION_CODE < 0x020317
-unsigned long DRM(vm_shm_nopage)(struct vm_area_struct *vma,
-				 unsigned long address,
-				 int unused)
-#else
-				/* Return type changed in 2.3.23 */
 struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma,
 				unsigned long address,
-				int unused)
-#endif
+				int write_access)
 {
-#if LINUX_VERSION_CODE >= 0x020300
 	drm_map_t	 *map	 = (drm_map_t *)vma->vm_private_data;
-#else
-	drm_map_t	 *map	 = (drm_map_t *)vma->vm_pte;
-#endif
 	unsigned long	 offset;
 	unsigned long	 i;
-	pgd_t		 *pgd;
-	pmd_t		 *pmd;
-	pte_t		 *pte;
 	struct page	 *page;
 
 	if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */
@@ -162,25 +136,15 @@
 
 	offset	 = address - vma->vm_start;
 	i = (unsigned long)map->handle + offset;
-	/* We have to walk page tables here because we need large SAREA's, and
-	 * they need to be virtually contiguous in kernel space.
-	 */
-	pgd = pgd_offset_k( i );
-	if( !pgd_present( *pgd ) ) return NOPAGE_OOM;
-	pmd = pmd_offset( pgd, i );
-	if( !pmd_present( *pmd ) ) return NOPAGE_OOM;
-	pte = pte_offset( pmd, i );
-	if( !pte_present( *pte ) ) return NOPAGE_OOM;
-
-	page = pte_page(*pte);
+	page = vmalloc_to_page((void *)i);
+	if (!page)
+		return NOPAGE_OOM;
 	get_page(page);
 
-	DRM_DEBUG("shm_nopage 0x%lx\n", address);
-#if LINUX_VERSION_CODE < 0x020317
-	return page_address(page);
-#else
-	return page;
+#if 0	/* XXX page_to_bus is not a portable interface available on all platforms. */
+	DRM_DEBUG("0x%08lx => 0x%08llx\n", address, (u64)page_to_bus(page));
 #endif
+	return page;
 }
 
 /* Special close routine which deletes map information if we are the last
@@ -199,25 +163,14 @@
 
 	DRM_DEBUG("0x%08lx,0x%08lx\n",
 		  vma->vm_start, vma->vm_end - vma->vm_start);
-#if LINUX_VERSION_CODE < 0x020333
-	MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
 	atomic_dec(&dev->vma_count);
 
-#if LINUX_VERSION_CODE >= 0x020300
 	map = vma->vm_private_data;
-#else
-	map = vma->vm_pte;
-#endif
 
 	down(&dev->struct_sem);
 	for (pt = dev->vmalist, prev = NULL; pt; pt = next) {
 		next = pt->next;
-#if LINUX_VERSION_CODE >= 0x020300
 		if (pt->vma->vm_private_data == map) found_maps++;
-#else
-		if (pt->vma->vm_pte == map) found_maps++;
-#endif
 		if (pt->vma == vma) {
 			if (prev) {
 				prev->next = pt->next;
@@ -270,16 +223,9 @@
 	up(&dev->struct_sem);
 }
 
-#if LINUX_VERSION_CODE < 0x020317
-unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma,
-				 unsigned long address,
-				 int unused)
-#else
-				/* Return type changed in 2.3.23 */
 struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma,
 				unsigned long address,
-				int unused)
-#endif
+				int write_access)
 {
 	drm_file_t	 *priv	 = vma->vm_file->private_data;
 	drm_device_t	 *dev	 = priv->dev;
@@ -299,30 +245,18 @@
 
 	get_page(page);
 
-	DRM_DEBUG("dma_nopage 0x%lx (page %lu)\n", address, page_nr); 
-#if LINUX_VERSION_CODE < 0x020317
-	return page_address(page);
-#else
-	return page;
+#if 0	/* XXX page_to_bus is not a portable interface available on all platforms. */
+	DRM_DEBUG("0x%08lx (page %lu) => 0x%08llx\n", address, page_nr, 
+		  (u64)page_to_bus(page));
 #endif
+	return page;
 }
 
-#if LINUX_VERSION_CODE < 0x020317
-unsigned long DRM(vm_sg_nopage)(struct vm_area_struct *vma,
-				unsigned long address,
-				int unused)
-#else
-				/* Return type changed in 2.3.23 */
 struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma,
 			       unsigned long address,
-			       int unused)
-#endif
+			       int write_access)
 {
-#if LINUX_VERSION_CODE >= 0x020300
 	drm_map_t        *map    = (drm_map_t *)vma->vm_private_data;
-#else
-	drm_map_t        *map    = (drm_map_t *)vma->vm_pte;
-#endif
 	drm_file_t *priv = vma->vm_file->private_data;
 	drm_device_t *dev = priv->dev;
 	drm_sg_mem_t *entry = dev->sg;
@@ -342,11 +276,7 @@
 	page = entry->pagelist[page_offset];
 	get_page(page);
 
-#if LINUX_VERSION_CODE < 0x020317
-	return page_address(page);
-#else
 	return page;
-#endif
 }
 
 void DRM(vm_open)(struct vm_area_struct *vma)
@@ -358,10 +288,6 @@
 	DRM_DEBUG("0x%08lx,0x%08lx\n",
 		  vma->vm_start, vma->vm_end - vma->vm_start);
 	atomic_inc(&dev->vma_count);
-#if LINUX_VERSION_CODE < 0x020333
-				/* The map can exist after the fd is closed. */
-	MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
 
 	vma_entry = DRM(alloc)(sizeof(*vma_entry), DRM_MEM_VMAS);
 	if (vma_entry) {
@@ -382,9 +308,6 @@
 
 	DRM_DEBUG("0x%08lx,0x%08lx\n",
 		  vma->vm_start, vma->vm_end - vma->vm_start);
-#if LINUX_VERSION_CODE < 0x020333
-	MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
 	atomic_dec(&dev->vma_count);
 
 	down(&dev->struct_sem);
@@ -424,12 +347,6 @@
 
 	vma->vm_ops   = &DRM(vm_dma_ops);
 	vma->vm_flags |= VM_RESERVED; /* Don't swap */
-
-#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
-				/* In Linux 2.2.3 and above, this is
-				   handled in do_mmap() in mm/mmap.c. */
-	++filp->f_count;
-#endif
 	vma->vm_file  =	 filp;	/* Needed for drm_vm_open() */
 	DRM(vm_open)(vma);
 	return 0;
@@ -551,34 +468,19 @@
 		break;
 	case _DRM_SHM:
 		vma->vm_ops = &DRM(vm_shm_ops);
-#if LINUX_VERSION_CODE >= 0x020300
 		vma->vm_private_data = (void *)map;
-#else
-		vma->vm_pte = (unsigned long)map;
-#endif
 				/* Don't let this area swap.  Change when
 				   DRM_KERNEL advisory is supported. */
-		vma->vm_flags |= VM_RESERVED;
 		break;
 	case _DRM_SCATTER_GATHER:
 		vma->vm_ops = &DRM(vm_sg_ops);
-#if LINUX_VERSION_CODE >= 0x020300
 		vma->vm_private_data = (void *)map;
-#else
-		vma->vm_pte = (unsigned long)map;
-#endif
-                vma->vm_flags |= VM_RESERVED;
                 break;
 	default:
 		return -EINVAL;	/* This should never happen. */
 	}
 	vma->vm_flags |= VM_RESERVED; /* Don't swap */
 
-#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
-				/* In Linux 2.2.3 and above, this is
-				   handled in do_mmap() in mm/mmap.c. */
-	++filp->f_count;
-#endif
 	vma->vm_file  =	 filp;	/* Needed for drm_vm_open() */
 	DRM(vm_open)(vma);
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/gamma_dma.c linux-2.4.20/drivers/char/drm/gamma_dma.c
--- linux-2.4.19/drivers/char/drm/gamma_dma.c	2001-08-08 16:42:14.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/gamma_dma.c	2002-10-29 11:18:50.000000000 +0000
@@ -29,7 +29,6 @@
  *
  */
 
-#define __NO_VERSION__
 #include "gamma.h"
 #include "drmP.h"
 #include "gamma_drv.h"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/i810_dma.c linux-2.4.20/drivers/char/drm/i810_dma.c
--- linux-2.4.19/drivers/char/drm/i810_dma.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/i810_dma.c	2002-10-29 11:18:36.000000000 +0000
@@ -30,11 +30,12 @@
  *
  */
 
-#define __NO_VERSION__
+#include <linux/config.h>
 #include "i810.h"
 #include "drmP.h"
 #include "i810_drv.h"
 #include <linux/interrupt.h>	/* For task queue support */
+#include <linux/module.h>
 
 /* in case we don't have a 2.3.99-pre6 kernel or later: */
 #ifndef VM_DONTCOPY
@@ -73,7 +74,7 @@
 	*(volatile unsigned int *)(virt + outring) = n;			\
 	outring += 4;							\
 	outring &= ringmask;						\
-} while (0);
+} while (0)
 
 static inline void i810_print_status_page(drm_device_t *dev)
 {
@@ -86,6 +87,7 @@
    	DRM_DEBUG(  "hw_status: LpRing Head ptr : %x\n", temp[1]);
    	DRM_DEBUG(  "hw_status: IRing Head ptr : %x\n", temp[2]);
       	DRM_DEBUG(  "hw_status: Reserved : %x\n", temp[3]);
+	DRM_DEBUG(  "hw_status: Last Render: %x\n", temp[4]);
    	DRM_DEBUG(  "hw_status: Driver Counter : %d\n", temp[5]);
    	for(i = 6; i < dma->buf_count + 6; i++) {
 	   	DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]);
@@ -182,11 +184,7 @@
 	if(buf_priv->currently_mapped == I810_BUF_MAPPED) return -EINVAL;
 
 	if(VM_DONTCOPY != 0) {
-#if LINUX_VERSION_CODE <= 0x020402
-		down( &current->mm->mmap_sem );
-#else
 		down_write( &current->mm->mmap_sem );
-#endif
 		old_fops = filp->f_op;
 		filp->f_op = &i810_buffer_fops;
 		dev_priv->mmap_buffer = buf;
@@ -202,11 +200,7 @@
 			retcode = (signed int)buf_priv->virtual;
 			buf_priv->virtual = 0;
 		}
-#if LINUX_VERSION_CODE <= 0x020402
-		up( &current->mm->mmap_sem );
-#else
 		up_write( &current->mm->mmap_sem );
-#endif
 	} else {
 		buf_priv->virtual = buf_priv->kernel_virtual;
    		buf_priv->currently_mapped = I810_BUF_MAPPED;
@@ -222,24 +216,11 @@
 	if(VM_DONTCOPY != 0) {
 		if(buf_priv->currently_mapped != I810_BUF_MAPPED)
 			return -EINVAL;
-#if LINUX_VERSION_CODE <= 0x020402
-		down( &current->mm->mmap_sem );
-#else
 		down_write( &current->mm->mmap_sem );
-#endif
-#if LINUX_VERSION_CODE < 0x020399
-        	retcode = do_munmap((unsigned long)buf_priv->virtual,
-				    (size_t) buf->total);
-#else
         	retcode = do_munmap(current->mm,
 				    (unsigned long)buf_priv->virtual,
 				    (size_t) buf->total);
-#endif
-#if LINUX_VERSION_CODE <= 0x020402
-		up( &current->mm->mmap_sem );
-#else
 		up_write( &current->mm->mmap_sem );
-#endif
 	}
    	buf_priv->currently_mapped = I810_BUF_UNMAPPED;
    	buf_priv->virtual = 0;
@@ -278,30 +259,6 @@
 	return retcode;
 }
 
-static unsigned long i810_alloc_page(drm_device_t *dev)
-{
-	unsigned long address;
-
-	address = __get_free_page(GFP_KERNEL);
-	if(address == 0UL)
-		return 0;
-
-	get_page(virt_to_page(address));
-	LockPage(virt_to_page(address));
-
-	return address;
-}
-
-static void i810_free_page(drm_device_t *dev, unsigned long page)
-{
-	if (page) {
-		struct page *p = virt_to_page(page);
-		put_page(p);
-		UnlockPage(p);
-		free_page(page);
-	}
-}
-
 static int i810_dma_cleanup(drm_device_t *dev)
 {
 	drm_device_dma_t *dma = dev->dma;
@@ -316,7 +273,8 @@
 					 dev_priv->ring.Size);
 		}
 	   	if(dev_priv->hw_status_page != 0UL) {
-		   	i810_free_page(dev, dev_priv->hw_status_page);
+		   	pci_free_consistent(dev->pdev, PAGE_SIZE, (void *)dev_priv->hw_status_page,
+		   		dev_priv->dma_status_page);
 		   	/* Need to rewrite hardware status page */
 		   	I810_WRITE(0x02080, 0x1ffff000);
 		}
@@ -474,12 +432,16 @@
 	dev_priv->back_offset = init->back_offset;
 	dev_priv->depth_offset = init->depth_offset;
 
+	dev_priv->overlay_offset = init->overlay_offset;
+	dev_priv->overlay_physical = init->overlay_physical;
+
 	dev_priv->front_di1 = init->front_offset | init->pitch_bits;
 	dev_priv->back_di1 = init->back_offset | init->pitch_bits;
 	dev_priv->zi1 = init->depth_offset | init->pitch_bits;
 
    	/* Program Hardware Status Page */
-   	dev_priv->hw_status_page = i810_alloc_page(dev);
+   	dev_priv->hw_status_page = (unsigned long)pci_alloc_consistent(dev->pdev, PAGE_SIZE,
+   			&dev_priv->dma_status_page);
    	if(dev_priv->hw_status_page == 0UL) {
 		dev->dev_private = (void *)dev_priv;
 		i810_dma_cleanup(dev);
@@ -489,7 +451,7 @@
    	memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE);
    	DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page);
 
-   	I810_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page));
+   	I810_WRITE(0x02080, dev_priv->dma_status_page);
    	DRM_DEBUG("Enabled hardware status page\n");
 
    	/* Now we need to init our freelist */
@@ -505,6 +467,15 @@
    	return 0;
 }
 
+#ifdef CONFIG_DRM_I810_XFREE_41
+int xfreeversion = 41;
+#else
+int xfreeversion = -1;
+#endif
+
+MODULE_PARM(xfreeversion, "i");
+MODULE_PARM_DESC(xfreeversion, "The version of XFree86 that needs to be supported");
+
 int i810_dma_init(struct inode *inode, struct file *filp,
 		  unsigned int cmd, unsigned long arg)
 {
@@ -516,6 +487,28 @@
 
   	if (copy_from_user(&init, (drm_i810_init_t *)arg, sizeof(init)))
 		return -EFAULT;
+		
+	if ((xfreeversion == 41) ||
+	    ((xfreeversion == -1) && (init.pitch == 0))) {
+		/*
+		 * Ok we have a problem here.  Someone decided it was
+		 * funny to add two fields in the middle of the
+		 * drm_i810_init_it structure in the transition between
+		 * XFree86 4.1.0 and 4.2.0.
+		 *
+		 * The code below tries to fix this ABI breakage up as
+		 * good as possible, unfortionatly it's impossible to
+		 * autodetect which interface the user wants, hence the
+		 * module parameter -- Arjan
+		 */
+
+	 	init.pitch_bits = init.h;
+	 	init.pitch = init.w;
+	 	init.h = init.overlay_physical;
+	 	init.w = init.overlay_offset;
+	 	init.overlay_physical = 0;
+	 	init.overlay_offset = 0;
+	}
 
    	switch(init.func) {
 	 	case I810_INIT_DMA:
@@ -1262,3 +1255,156 @@
 	if(VM_DONTCOPY == 0) return 1;
 	return 0;
 }
+
+static void i810_dma_dispatch_mc(drm_device_t *dev, drm_buf_t *buf, int used,
+		unsigned int last_render)
+{
+	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned long address = (unsigned long)buf->bus_address;
+	unsigned long start = address - dev->agp->base;
+	int u;
+	RING_LOCALS;
+
+	i810_kernel_lost_context(dev);
+
+	u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
+		I810_BUF_HARDWARE);
+	if(u != I810_BUF_CLIENT) {
+		DRM_DEBUG("MC found buffer that isn't mine!\n");
+	}
+
+	if (used > 4*1024)
+		used = 0;
+
+	sarea_priv->dirty = 0x7f;
+
+	DRM_DEBUG("dispatch mc addr 0x%lx, used 0x%x\n",
+		address, used);
+
+	dev_priv->counter++;
+	DRM_DEBUG("dispatch counter : %ld\n", dev_priv->counter);
+	DRM_DEBUG("i810_dma_dispatch_mc\n");
+	DRM_DEBUG("start : %lx\n", start);
+	DRM_DEBUG("used : %d\n", used);
+	DRM_DEBUG("start + used - 4 : %ld\n", start + used - 4);
+
+	if (buf_priv->currently_mapped == I810_BUF_MAPPED) {
+		if (used & 4) {
+			*(u32 *)((u32)buf_priv->virtual + used) = 0;
+			used += 4;
+		}
+
+		i810_unmap_buffer(buf);
+	}
+	BEGIN_LP_RING(4);
+	OUT_RING( CMD_OP_BATCH_BUFFER );
+	OUT_RING( start | BB1_PROTECTED );
+	OUT_RING( start + used - 4 );
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
+
+
+	BEGIN_LP_RING(8);
+	OUT_RING( CMD_STORE_DWORD_IDX );
+	OUT_RING( buf_priv->my_use_idx );
+	OUT_RING( I810_BUF_FREE );
+	OUT_RING( 0 );
+
+	OUT_RING( CMD_STORE_DWORD_IDX );
+	OUT_RING( 16 );
+	OUT_RING( last_render );
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
+}
+
+int i810_dma_mc(struct inode *inode, struct file *filp,
+	unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_device_dma_t *dma = dev->dma;
+	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+		dev_priv->sarea_priv;
+	drm_i810_mc_t mc;
+
+	if (copy_from_user(&mc, (drm_i810_mc_t *)arg, sizeof(mc)))
+		return -EFAULT;
+
+
+	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_dma_mc called without lock held\n");
+		return -EINVAL;
+	}
+
+	i810_dma_dispatch_mc(dev, dma->buflist[mc.idx], mc.used,
+		mc.last_render );
+
+	atomic_add(mc.used, &dev->counts[_DRM_STAT_SECONDARY]);
+	atomic_inc(&dev->counts[_DRM_STAT_DMA]);
+	sarea_priv->last_enqueue = dev_priv->counter-1;
+	sarea_priv->last_dispatch = (int) hw_status[5];
+
+	return 0;
+}
+
+int i810_rstatus(struct inode *inode, struct file *filp,
+		unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+
+	return (int)(((u32 *)(dev_priv->hw_status_page))[4]);
+}
+
+int i810_ov0_info(struct inode *inode, struct file *filp,
+		unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+	drm_i810_overlay_t data;
+
+	data.offset = dev_priv->overlay_offset;
+	data.physical = dev_priv->overlay_physical;
+	copy_to_user((drm_i810_overlay_t *)arg,&data,sizeof(data));
+	return 0;
+}
+
+int i810_fstatus(struct inode *inode, struct file *filp,
+		unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+
+	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_fstatus called without lock held\n");
+		return -EINVAL;
+	}
+	return I810_READ(0x30008);
+}
+
+int i810_ov0_flip(struct inode *inode, struct file *filp,
+		unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+
+	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_ov0_flip called without lock held\n");
+		return -EINVAL;
+	}
+
+	//Tell the overlay to update
+	I810_WRITE(0x30000,dev_priv->overlay_physical | 0x80000000);
+
+	return 0;
+}
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/i810_drm.h linux-2.4.20/drivers/char/drm/i810_drm.h
--- linux-2.4.19/drivers/char/drm/i810_drm.h	2001-08-08 16:42:15.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/i810_drm.h	2002-10-29 11:18:31.000000000 +0000
@@ -112,6 +112,8 @@
 	unsigned int front_offset;
 	unsigned int back_offset;
 	unsigned int depth_offset;
+	unsigned int overlay_offset;
+	unsigned int overlay_physical;
 	unsigned int w;
 	unsigned int h;
 	unsigned int pitch;
@@ -196,4 +198,18 @@
 	int granted;
 } drm_i810_dma_t;
 
+typedef struct _drm_i810_overlay_t {
+	unsigned int offset;    /* Address of the Overlay Regs */
+	unsigned int physical;
+} drm_i810_overlay_t;
+
+typedef struct _drm_i810_mc {
+	int idx;                /* buffer index */
+	int used;               /* nr bytes in use */
+	int num_blocks;         /* number of GFXBlocks */
+	int *length;            /* List of lengths for GFXBlocks (FUTURE)*/
+	unsigned int last_render; /* Last Render Request */
+} drm_i810_mc_t;
+
+
 #endif /* _I810_DRM_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/i810_drv.c linux-2.4.20/drivers/char/drm/i810_drv.c
--- linux-2.4.19/drivers/char/drm/i810_drv.c	2001-08-08 16:42:15.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/i810_drv.c	2002-10-29 11:18:50.000000000 +0000
@@ -39,10 +39,10 @@
 
 #define DRIVER_NAME		"i810"
 #define DRIVER_DESC		"Intel i810"
-#define DRIVER_DATE		"20010616"
+#define DRIVER_DATE		"20010920"
 
 #define DRIVER_MAJOR		1
-#define DRIVER_MINOR		1
+#define DRIVER_MINOR		2	
 #define DRIVER_PATCHLEVEL	0
 
 #define DRIVER_IOCTLS							    \
@@ -54,7 +54,12 @@
 	[DRM_IOCTL_NR(DRM_IOCTL_I810_GETBUF)] = { i810_getbuf,      1, 0 }, \
    	[DRM_IOCTL_NR(DRM_IOCTL_I810_SWAP)]   = { i810_swap_bufs,   1, 0 }, \
    	[DRM_IOCTL_NR(DRM_IOCTL_I810_COPY)]   = { i810_copybuf,     1, 0 }, \
-   	[DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy,      1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy,      1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I810_OV0INFO)] = { i810_ov0_info,   1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I810_FSTATUS)] = { i810_fstatus,    1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I810_OV0FLIP)] = { i810_ov0_flip,   1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I810_MC)]      = { i810_dma_mc,     1, 1 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I810_RSTATUS)] = { i810_rstatus,    1, 0 }
 
 
 #define __HAVE_COUNTERS         4
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/i810_drv.h linux-2.4.20/drivers/char/drm/i810_drv.h
--- linux-2.4.19/drivers/char/drm/i810_drv.h	2001-08-08 16:42:15.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/i810_drv.h	2002-10-29 11:18:38.000000000 +0000
@@ -63,6 +63,7 @@
 
       	unsigned long hw_status_page;
    	unsigned long counter;
+   	dma_addr_t dma_status_page;
 
    	atomic_t flush_done;
    	wait_queue_head_t flush_queue;	/* Processes waiting until flush    */
@@ -73,6 +74,8 @@
 
 	int back_offset;
 	int depth_offset;
+	int overlay_offset;
+	int overlay_physical;
 	int w, h;
 	int pitch;
 } drm_i810_private_t;
@@ -94,6 +97,18 @@
 extern int i810_docopy(struct inode *inode, struct file *filp,
 		       unsigned int cmd, unsigned long arg);
 
+extern int i810_rstatus(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int i810_ov0_info(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int i810_fstatus(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int i810_ov0_flip(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int i810_dma_mc(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+
+
 extern void i810_dma_quiescent(drm_device_t *dev);
 
 #define I810_VERBOSE 0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/i830.h linux-2.4.20/drivers/char/drm/i830.h
--- linux-2.4.19/drivers/char/drm/i830.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/i830.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,116 @@
+/* i830.h -- Intel I830 DRM template customization -*- linux-c -*-
+ * Created: Thu Feb 15 00:01:12 2001 by gareth@valinux.com
+ *
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Gareth Hughes <gareth@valinux.com>
+ */
+
+#ifndef __I830_H__
+#define __I830_H__
+
+/* This remains constant for all DRM template files.
+ */
+#define DRM(x) i830_##x
+
+/* General customization:
+ */
+#define __HAVE_AGP		1
+#define __MUST_HAVE_AGP		1
+#define __HAVE_MTRR		1
+#define __HAVE_CTX_BITMAP	1
+
+/* Driver customization:
+ */
+#define __HAVE_RELEASE		1
+#define DRIVER_RELEASE() do {						\
+	i830_reclaim_buffers( dev, priv->pid );				\
+} while (0)
+
+/* DMA customization:
+ */
+#define __HAVE_DMA		1
+#define __HAVE_DMA_QUEUE	1
+#define __HAVE_DMA_WAITLIST	1
+#define __HAVE_DMA_RECLAIM	1
+
+#define __HAVE_DMA_QUIESCENT	1
+#define DRIVER_DMA_QUIESCENT() do {					\
+	i830_dma_quiescent( dev );					\
+} while (0)
+
+#define __HAVE_DMA_IRQ		1
+#define __HAVE_DMA_IRQ_BH	1
+#define __HAVE_SHARED_IRQ       1
+#define DRIVER_PREINSTALL() do {					\
+	drm_i830_private_t *dev_priv =					\
+		(drm_i830_private_t *)dev->dev_private;			\
+	u16 tmp;							\
+   	tmp = I830_READ16( I830REG_HWSTAM );				\
+   	tmp = tmp & 0x6000;						\
+   	I830_WRITE16( I830REG_HWSTAM, tmp );				\
+									\
+      	tmp = I830_READ16( I830REG_INT_MASK_R );			\
+   	tmp = tmp & 0x6000;		/* Unmask interrupts */		\
+   	I830_WRITE16( I830REG_INT_MASK_R, tmp );			\
+   	tmp = I830_READ16( I830REG_INT_ENABLE_R );			\
+   	tmp = tmp & 0x6000;		/* Disable all interrupts */	\
+      	I830_WRITE16( I830REG_INT_ENABLE_R, tmp );			\
+} while (0)
+
+#define DRIVER_POSTINSTALL() do {					\
+	drm_i830_private_t *dev_priv =					\
+		(drm_i830_private_t *)dev->dev_private;	\
+	u16 tmp;							\
+   	tmp = I830_READ16( I830REG_INT_ENABLE_R );			\
+   	tmp = tmp & 0x6000;						\
+   	tmp = tmp | 0x0003;	/* Enable bp & user interrupts */	\
+   	I830_WRITE16( I830REG_INT_ENABLE_R, tmp );			\
+} while (0)
+
+#define DRIVER_UNINSTALL() do {						\
+	drm_i830_private_t *dev_priv =					\
+		(drm_i830_private_t *)dev->dev_private;			\
+	u16 tmp;							\
+	if ( dev_priv ) {						\
+		tmp = I830_READ16( I830REG_INT_IDENTITY_R );		\
+		tmp = tmp & ~(0x6000);	/* Clear all interrupts */	\
+		if ( tmp != 0 )						\
+			I830_WRITE16( I830REG_INT_IDENTITY_R, tmp );	\
+									\
+		tmp = I830_READ16( I830REG_INT_ENABLE_R );		\
+		tmp = tmp & 0x6000;	/* Disable all interrupts */	\
+		I830_WRITE16( I830REG_INT_ENABLE_R, tmp );		\
+	}								\
+} while (0)
+
+/* Buffer customization:
+ */
+
+#define DRIVER_BUF_PRIV_T	drm_i830_buf_priv_t
+
+#define DRIVER_AGP_BUFFERS_MAP( dev )					\
+	((drm_i830_private_t *)((dev)->dev_private))->buffer_map
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/i830_dma.c linux-2.4.20/drivers/char/drm/i830_dma.c
--- linux-2.4.19/drivers/char/drm/i830_dma.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/i830_dma.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,1369 @@
+/* i830_dma.c -- DMA support for the I830 -*- linux-c -*-
+ * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	    Jeff Hartmann <jhartmann@valinux.com>
+ *      Keith Whitwell <keithw@valinux.com>
+ *      Abraham vd Merwe <abraham@2d3d.co.za>
+ *
+ */
+
+#include "i830.h"
+#include "drmP.h"
+#include "i830_drv.h"
+#include <linux/interrupt.h>	/* For task queue support */
+#include <linux/delay.h>
+/* in case we don't have a 2.3.99-pre6 kernel or later: */
+#ifndef VM_DONTCOPY
+#define VM_DONTCOPY 0
+#endif
+
+#define I830_BUF_FREE		2
+#define I830_BUF_CLIENT		1
+#define I830_BUF_HARDWARE      	0
+
+#define I830_BUF_UNMAPPED 0
+#define I830_BUF_MAPPED   1
+
+#define RING_LOCALS	unsigned int outring, ringmask; volatile char *virt;
+
+
+#define DO_IDLE_WORKAROUND()					\
+do {								\
+   int _head;							\
+   int _tail;							\
+   do { 							\
+      _head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;	\
+      _tail = I830_READ(LP_RING + RING_TAIL) & TAIL_ADDR;	\
+      udelay(1);						\
+   } while(_head != _tail);					\
+} while(0)
+
+#define I830_SYNC_WORKAROUND 0
+
+#define BEGIN_LP_RING(n) do {				\
+	if (I830_VERBOSE)				\
+		DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n",	\
+			  n, __FUNCTION__);		\
+	if (I830_SYNC_WORKAROUND)			\
+		DO_IDLE_WORKAROUND();			\
+	if (dev_priv->ring.space < n*4) 		\
+		i830_wait_ring(dev, n*4);		\
+	dev_priv->ring.space -= n*4;			\
+	outring = dev_priv->ring.tail;			\
+	ringmask = dev_priv->ring.tail_mask;		\
+	virt = dev_priv->ring.virtual_start;		\
+} while (0)
+
+#define ADVANCE_LP_RING() do {					\
+	if (I830_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n");	\
+	dev_priv->ring.tail = outring;				\
+	I830_WRITE(LP_RING + RING_TAIL, outring);		\
+} while(0)
+
+#define OUT_RING(n) do {						\
+	if (I830_VERBOSE) DRM_DEBUG("   OUT_RING %x\n", (int)(n));	\
+	*(volatile unsigned int *)(virt + outring) = n;			\
+	outring += 4;							\
+	outring &= ringmask;						\
+} while (0);
+
+static inline void i830_print_status_page(drm_device_t *dev)
+{
+   	drm_device_dma_t *dma = dev->dma;
+      	drm_i830_private_t *dev_priv = dev->dev_private;
+	u8 *temp = dev_priv->hw_status_page;
+   	int i;
+
+   	DRM_DEBUG(  "hw_status: Interrupt Status : %x\n", temp[0]);
+   	DRM_DEBUG(  "hw_status: LpRing Head ptr : %x\n", temp[1]);
+   	DRM_DEBUG(  "hw_status: IRing Head ptr : %x\n", temp[2]);
+      	DRM_DEBUG(  "hw_status: Reserved : %x\n", temp[3]);
+   	DRM_DEBUG(  "hw_status: Driver Counter : %d\n", temp[5]);
+   	for(i = 9; i < dma->buf_count + 9; i++) {
+	   	DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 9, temp[i]);
+	}
+}
+
+static drm_buf_t *i830_freelist_get(drm_device_t *dev)
+{
+   	drm_device_dma_t *dma = dev->dma;
+	int		 i;
+   	int 		 used;
+   
+	/* Linear search might not be the best solution */
+
+   	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+		/* In use is already a pointer */
+	   	used = cmpxchg(buf_priv->in_use, I830_BUF_FREE, 
+			       I830_BUF_CLIENT);
+	   	if(used == I830_BUF_FREE) {
+			return buf;
+		}
+	}
+   	return NULL;
+}
+
+/* This should only be called if the buffer is not sent to the hardware
+ * yet, the hardware updates in use for us once its on the ring buffer.
+ */
+
+static int i830_freelist_put(drm_device_t *dev, drm_buf_t *buf)
+{
+   	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+   	int used;
+   
+   	/* In use is already a pointer */
+   	used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, I830_BUF_FREE);
+   	if(used != I830_BUF_CLIENT) {
+	   	DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
+	   	return -EINVAL;
+	}
+   
+   	return 0;
+}
+
+static struct file_operations i830_buffer_fops = {
+	open:	 DRM(open),
+	flush:	 DRM(flush),
+	release: DRM(release),
+	ioctl:	 DRM(ioctl),
+	mmap:	 i830_mmap_buffers,
+	read:	 DRM(read),
+	fasync:	 DRM(fasync),
+      	poll:	 DRM(poll),
+};
+
+int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
+{
+	drm_file_t	    *priv	  = filp->private_data;
+	drm_device_t	    *dev;
+	drm_i830_private_t  *dev_priv;
+	drm_buf_t           *buf;
+	drm_i830_buf_priv_t *buf_priv;
+
+	lock_kernel();
+	dev	 = priv->dev;
+	dev_priv = dev->dev_private;
+	buf      = dev_priv->mmap_buffer;
+	buf_priv = buf->dev_private;
+   
+	vma->vm_flags |= (VM_IO | VM_DONTCOPY);
+	vma->vm_file = filp;
+   
+   	buf_priv->currently_mapped = I830_BUF_MAPPED;
+	unlock_kernel();
+
+	if (remap_page_range(vma->vm_start,
+			     VM_OFFSET(vma),
+			     vma->vm_end - vma->vm_start,
+			     vma->vm_page_prot)) return -EAGAIN;
+	return 0;
+}
+
+static int i830_map_buffer(drm_buf_t *buf, struct file *filp)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+      	drm_i830_private_t *dev_priv = dev->dev_private;
+   	struct file_operations *old_fops;
+	int retcode = 0;
+
+	if(buf_priv->currently_mapped == I830_BUF_MAPPED) return -EINVAL;
+
+	if(VM_DONTCOPY != 0) {
+		down_write( &current->mm->mmap_sem );
+		old_fops = filp->f_op;
+		filp->f_op = &i830_buffer_fops;
+		dev_priv->mmap_buffer = buf;
+		buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total, 
+						    PROT_READ|PROT_WRITE,
+						    MAP_SHARED, 
+						    buf->bus_address);
+		dev_priv->mmap_buffer = NULL;
+   		filp->f_op = old_fops;
+		if ((unsigned long)buf_priv->virtual > -1024UL) {
+			/* Real error */
+			DRM_DEBUG("mmap error\n");
+			retcode = (signed int)buf_priv->virtual;
+			buf_priv->virtual = 0;
+		}
+		up_write( &current->mm->mmap_sem );
+	} else {
+		buf_priv->virtual = buf_priv->kernel_virtual;
+   		buf_priv->currently_mapped = I830_BUF_MAPPED;
+	}
+	return retcode;
+}
+
+static int i830_unmap_buffer(drm_buf_t *buf)
+{
+	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+	int retcode = 0;
+
+	if(VM_DONTCOPY != 0) {
+		if(buf_priv->currently_mapped != I830_BUF_MAPPED) 
+			return -EINVAL;
+		down_write( &current->mm->mmap_sem );
+        	retcode = do_munmap(current->mm, 
+				    (unsigned long)buf_priv->virtual, 
+				    (size_t) buf->total);
+   		up_write( &current->mm->mmap_sem );
+	}
+   	buf_priv->currently_mapped = I830_BUF_UNMAPPED;
+   	buf_priv->virtual = 0;
+
+	return retcode;
+}
+
+static int i830_dma_get_buffer(drm_device_t *dev, drm_i830_dma_t *d, 
+			       struct file *filp)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_buf_t	  *buf;
+	drm_i830_buf_priv_t *buf_priv;
+	int retcode = 0;
+
+	buf = i830_freelist_get(dev);
+	if (!buf) {
+		retcode = -ENOMEM;
+	   	DRM_DEBUG("retcode=%d\n", retcode);
+		return retcode;
+	}
+   
+	retcode = i830_map_buffer(buf, filp);
+	if(retcode) {
+		i830_freelist_put(dev, buf);
+	   	DRM_DEBUG("mapbuf failed, retcode %d\n", retcode);
+		return retcode;
+	}
+	buf->pid     = priv->pid;
+	buf_priv = buf->dev_private;	
+	d->granted = 1;
+   	d->request_idx = buf->idx;
+   	d->request_size = buf->total;
+   	d->virtual = buf_priv->virtual;
+
+	return retcode;
+}
+
+static int i830_dma_cleanup(drm_device_t *dev)
+{
+	drm_device_dma_t *dma = dev->dma;
+
+	if(dev->dev_private) {
+		int i;
+	   	drm_i830_private_t *dev_priv = 
+	     		(drm_i830_private_t *) dev->dev_private;
+	   
+	   	if(dev_priv->ring.virtual_start) {
+		   	DRM(ioremapfree)((void *) dev_priv->ring.virtual_start,
+					 dev_priv->ring.Size);
+		}
+	   	if(dev_priv->hw_status_page != NULL) {
+	   		pci_free_consistent(dev->pdev, PAGE_SIZE, 
+	   		    dev_priv->hw_status_page, dev_priv->dma_status_page);
+		   	/* Need to rewrite hardware status page */
+		   	I830_WRITE(0x02080, 0x1ffff000);
+		}
+	   	DRM(free)(dev->dev_private, sizeof(drm_i830_private_t), 
+			 DRM_MEM_DRIVER);
+	   	dev->dev_private = NULL;
+
+		for (i = 0; i < dma->buf_count; i++) {
+			drm_buf_t *buf = dma->buflist[ i ];
+			drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+			DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total);
+		}
+	}
+   	return 0;
+}
+
+static int i830_wait_ring(drm_device_t *dev, int n)
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+   	drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
+   	int iters = 0;
+   	unsigned long end;
+	unsigned int last_head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+
+	end = jiffies + (HZ*3);
+   	while (ring->space < n) {
+	   	ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+	   	ring->space = ring->head - (ring->tail+8);
+		if (ring->space < 0) ring->space += ring->Size;
+	   
+		if (ring->head != last_head) {
+			end = jiffies + (HZ*3);
+			last_head = ring->head;
+		}
+	  
+	   	iters++;
+		if(time_before(end,jiffies)) {
+		   	DRM_ERROR("space: %d wanted %d\n", ring->space, n);
+		   	DRM_ERROR("lockup\n");
+		   	goto out_wait_ring;
+		}
+
+	   	udelay(1);
+	}
+
+out_wait_ring:   
+   	return iters;
+}
+
+static void i830_kernel_lost_context(drm_device_t *dev)
+{
+      	drm_i830_private_t *dev_priv = dev->dev_private;
+   	drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
+      
+   	ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+     	ring->tail = I830_READ(LP_RING + RING_TAIL);
+     	ring->space = ring->head - (ring->tail+8);
+     	if (ring->space < 0) ring->space += ring->Size;
+}
+
+static int i830_freelist_init(drm_device_t *dev, drm_i830_private_t *dev_priv)
+{
+      	drm_device_dma_t *dma = dev->dma;
+   	int my_idx = 36;
+   	u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx);
+   	int i;
+
+   	if(dma->buf_count > 1019) {
+	   	/* Not enough space in the status page for the freelist */
+	   	return -EINVAL;
+	}
+
+   	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+
+	   	buf_priv->in_use = hw_status++;
+	   	buf_priv->my_use_idx = my_idx;
+	   	my_idx += 4;
+
+	   	*buf_priv->in_use = I830_BUF_FREE;
+
+		buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address, 
+							buf->total);
+	}
+	return 0;
+}
+
+static int i830_dma_initialize(drm_device_t *dev, 
+			       drm_i830_private_t *dev_priv,
+			       drm_i830_init_t *init)
+{
+	struct list_head *list;
+
+   	memset(dev_priv, 0, sizeof(drm_i830_private_t));
+
+	list_for_each(list, &dev->maplist->head) {
+		drm_map_list_t *r_list = (drm_map_list_t *)list;
+		if( r_list->map &&
+		    r_list->map->type == _DRM_SHM &&
+		    r_list->map->flags & _DRM_CONTAINS_LOCK ) {
+			dev_priv->sarea_map = r_list->map;
+ 			break;
+ 		}
+ 	}
+
+	if(!dev_priv->sarea_map) {
+		dev->dev_private = (void *)dev_priv;
+		i830_dma_cleanup(dev);
+		DRM_ERROR("can not find sarea!\n");
+		return -EINVAL;
+	}
+	DRM_FIND_MAP( dev_priv->mmio_map, init->mmio_offset );
+	if(!dev_priv->mmio_map) {
+		dev->dev_private = (void *)dev_priv;
+		i830_dma_cleanup(dev);
+		DRM_ERROR("can not find mmio map!\n");
+		return -EINVAL;
+	}
+	DRM_FIND_MAP( dev_priv->buffer_map, init->buffers_offset );
+	if(!dev_priv->buffer_map) {
+		dev->dev_private = (void *)dev_priv;
+		i830_dma_cleanup(dev);
+		DRM_ERROR("can not find dma buffer map!\n");
+		return -EINVAL;
+	}
+
+	dev_priv->sarea_priv = (drm_i830_sarea_t *)
+		((u8 *)dev_priv->sarea_map->handle +
+		 init->sarea_priv_offset);
+
+   	atomic_set(&dev_priv->flush_done, 0);
+	init_waitqueue_head(&dev_priv->flush_queue);
+
+   	dev_priv->ring.Start = init->ring_start;
+   	dev_priv->ring.End = init->ring_end;
+   	dev_priv->ring.Size = init->ring_size;
+
+   	dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base + 
+						    init->ring_start, 
+						    init->ring_size);
+
+   	if (dev_priv->ring.virtual_start == NULL) {
+		dev->dev_private = (void *) dev_priv;
+	   	i830_dma_cleanup(dev);
+	   	DRM_ERROR("can not ioremap virtual address for"
+			  " ring buffer\n");
+	   	return -ENOMEM;
+	}
+
+   	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+   
+	dev_priv->w = init->w;
+	dev_priv->h = init->h;
+	dev_priv->pitch = init->pitch;
+	dev_priv->back_offset = init->back_offset;
+	dev_priv->depth_offset = init->depth_offset;
+
+	dev_priv->front_di1 = init->front_offset | init->pitch_bits;
+	dev_priv->back_di1 = init->back_offset | init->pitch_bits;
+	dev_priv->zi1 = init->depth_offset | init->pitch_bits;
+
+	dev_priv->cpp = init->cpp;
+	/* We are using seperate values as placeholders for mechanisms for
+	 * private backbuffer/depthbuffer usage.
+	 */
+
+	dev_priv->back_pitch = init->back_pitch;
+	dev_priv->depth_pitch = init->depth_pitch;
+
+   	/* Program Hardware Status Page */
+   	dev_priv->hw_status_page = pci_alloc_consistent(dev->pdev, PAGE_SIZE, 
+						&dev_priv->dma_status_page);
+   	if(dev_priv->hw_status_page == NULL) {
+		dev->dev_private = (void *)dev_priv;
+		i830_dma_cleanup(dev);
+		DRM_ERROR("Can not allocate hardware status page\n");
+		return -ENOMEM;
+	}
+   	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
+   
+   	I830_WRITE(0x02080, dev_priv->dma_status_page);
+	DRM_DEBUG("Enabled hardware status page\n");
+   
+   	/* Now we need to init our freelist */
+   	if(i830_freelist_init(dev, dev_priv) != 0) {
+		dev->dev_private = (void *)dev_priv;
+	   	i830_dma_cleanup(dev);
+	   	DRM_ERROR("Not enough space in the status page for"
+			  " the freelist\n");
+	   	return -ENOMEM;
+	}
+	dev->dev_private = (void *)dev_priv;
+
+   	return 0;
+}
+
+int i830_dma_init(struct inode *inode, struct file *filp,
+		  unsigned int cmd, unsigned long arg)
+{
+   	drm_file_t *priv = filp->private_data;
+   	drm_device_t *dev = priv->dev;
+   	drm_i830_private_t *dev_priv;
+   	drm_i830_init_t init;
+   	int retcode = 0;
+	
+  	if (copy_from_user(&init, (drm_i830_init_t *)arg, sizeof(init)))
+		return -EFAULT;
+	
+   	switch(init.func) {
+	 	case I830_INIT_DMA:
+			dev_priv = DRM(alloc)(sizeof(drm_i830_private_t), 
+					      DRM_MEM_DRIVER);
+	   		if(dev_priv == NULL) return -ENOMEM;
+	   		retcode = i830_dma_initialize(dev, dev_priv, &init);
+	   	break;
+	 	case I830_CLEANUP_DMA:
+	   		retcode = i830_dma_cleanup(dev);
+	   	break;
+	 	default:
+	   		retcode = -EINVAL;
+	   	break;
+	}
+   
+   	return retcode;
+}
+
+/* Most efficient way to verify state for the i830 is as it is
+ * emitted.  Non-conformant state is silently dropped.
+ *
+ * Use 'volatile' & local var tmp to force the emitted values to be
+ * identical to the verified ones.
+ */
+static void i830EmitContextVerified( drm_device_t *dev, 
+				     volatile unsigned int *code )
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	int i, j = 0;
+	unsigned int tmp;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( I830_CTX_SETUP_SIZE );
+	for ( i = 0 ; i < I830_CTX_SETUP_SIZE ; i++ ) {
+		tmp = code[i];
+
+#if 0
+		if ((tmp & (7<<29)) == (3<<29) &&
+		    (tmp & (0x1f<<24)) < (0x1d<<24)) {
+			OUT_RING( tmp ); 
+			j++;
+		} else {
+			printk("Skipping %d\n", i);
+		}
+#else
+		OUT_RING( tmp ); 
+		j++;
+#endif
+	}
+
+	if (j & 1) 
+		OUT_RING( 0 ); 
+
+	ADVANCE_LP_RING();
+}
+
+static void i830EmitTexVerified( drm_device_t *dev, 
+				 volatile unsigned int *code ) 
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	int i, j = 0;
+	unsigned int tmp;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( I830_TEX_SETUP_SIZE );
+
+	OUT_RING( GFX_OP_MAP_INFO );
+	OUT_RING( code[I830_TEXREG_MI1] );
+	OUT_RING( code[I830_TEXREG_MI2] );
+	OUT_RING( code[I830_TEXREG_MI3] );
+	OUT_RING( code[I830_TEXREG_MI4] );
+	OUT_RING( code[I830_TEXREG_MI5] );
+
+	for ( i = 6 ; i < I830_TEX_SETUP_SIZE ; i++ ) {
+		tmp = code[i];
+		OUT_RING( tmp ); 
+		j++;
+	} 
+
+	if (j & 1) 
+		OUT_RING( 0 ); 
+
+	ADVANCE_LP_RING();
+}
+
+static void i830EmitTexBlendVerified( drm_device_t *dev, 
+				     volatile unsigned int *code,
+				     volatile unsigned int num)
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	int i, j = 0;
+	unsigned int tmp;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( num );
+
+	for ( i = 0 ; i < num ; i++ ) {
+		tmp = code[i];
+		OUT_RING( tmp );
+		j++;
+	}
+
+	if (j & 1) 
+		OUT_RING( 0 ); 
+
+	ADVANCE_LP_RING();
+}
+
+static void i830EmitTexPalette( drm_device_t *dev,
+			        unsigned int *palette,
+			        int number,
+			        int is_shared )
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	int i;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( 258 );
+
+	if(is_shared == 1) {
+		OUT_RING(CMD_OP_MAP_PALETTE_LOAD |
+			 MAP_PALETTE_NUM(0) |
+			 MAP_PALETTE_BOTH);
+	} else {
+		OUT_RING(CMD_OP_MAP_PALETTE_LOAD | MAP_PALETTE_NUM(number));
+	}
+	for(i = 0; i < 256; i++) {
+		OUT_RING(palette[i]);
+	}
+	OUT_RING(0);
+}
+
+/* Need to do some additional checking when setting the dest buffer.
+ */
+static void i830EmitDestVerified( drm_device_t *dev, 
+				  volatile unsigned int *code ) 
+{	
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	unsigned int tmp;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( I830_DEST_SETUP_SIZE + 6 );
+
+	tmp = code[I830_DESTREG_CBUFADDR];
+	if (tmp == dev_priv->front_di1) {
+		/* Don't use fence when front buffer rendering */
+		OUT_RING( CMD_OP_DESTBUFFER_INFO );
+		OUT_RING( BUF_3D_ID_COLOR_BACK | 
+			  BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) );
+		OUT_RING( tmp );
+
+		OUT_RING( CMD_OP_DESTBUFFER_INFO );
+		OUT_RING( BUF_3D_ID_DEPTH |
+			  BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp));
+		OUT_RING( dev_priv->zi1 );
+	} else if(tmp == dev_priv->back_di1) {
+		OUT_RING( CMD_OP_DESTBUFFER_INFO );
+		OUT_RING( BUF_3D_ID_COLOR_BACK | 
+			  BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) |
+			  BUF_3D_USE_FENCE);
+		OUT_RING( tmp );
+
+		OUT_RING( CMD_OP_DESTBUFFER_INFO );
+		OUT_RING( BUF_3D_ID_DEPTH | BUF_3D_USE_FENCE | 
+			  BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp));
+		OUT_RING( dev_priv->zi1 );
+	} else {
+		DRM_DEBUG("bad di1 %x (allow %x or %x)\n",
+			  tmp, dev_priv->front_di1, dev_priv->back_di1);
+	}
+
+	/* invarient:
+	 */
+
+
+	OUT_RING( GFX_OP_DESTBUFFER_VARS );
+	OUT_RING( code[I830_DESTREG_DV1] );
+
+	OUT_RING( GFX_OP_DRAWRECT_INFO );
+	OUT_RING( code[I830_DESTREG_DR1] );
+	OUT_RING( code[I830_DESTREG_DR2] );
+	OUT_RING( code[I830_DESTREG_DR3] );
+	OUT_RING( code[I830_DESTREG_DR4] );
+
+	/* Need to verify this */
+	tmp = code[I830_DESTREG_SENABLE];
+	if((tmp & ~0x3) == GFX_OP_SCISSOR_ENABLE) {
+		OUT_RING( tmp );
+	} else {
+		DRM_DEBUG("bad scissor enable\n");
+		OUT_RING( 0 );
+	}
+
+	OUT_RING( code[I830_DESTREG_SENABLE] );
+
+	OUT_RING( GFX_OP_SCISSOR_RECT );
+	OUT_RING( code[I830_DESTREG_SR1] );
+	OUT_RING( code[I830_DESTREG_SR2] );
+
+	ADVANCE_LP_RING();
+}
+
+static void i830EmitState( drm_device_t *dev )
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+      	drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int dirty = sarea_priv->dirty;
+
+	if (dirty & I830_UPLOAD_BUFFERS) {
+		i830EmitDestVerified( dev, sarea_priv->BufferState );
+		sarea_priv->dirty &= ~I830_UPLOAD_BUFFERS;
+	}
+
+	if (dirty & I830_UPLOAD_CTX) {
+		i830EmitContextVerified( dev, sarea_priv->ContextState );
+		sarea_priv->dirty &= ~I830_UPLOAD_CTX;
+	}
+
+	if (dirty & I830_UPLOAD_TEX0) {
+		i830EmitTexVerified( dev, sarea_priv->TexState[0] );
+		sarea_priv->dirty &= ~I830_UPLOAD_TEX0;
+	}
+
+	if (dirty & I830_UPLOAD_TEX1) {
+		i830EmitTexVerified( dev, sarea_priv->TexState[1] );
+		sarea_priv->dirty &= ~I830_UPLOAD_TEX1;
+	}
+
+	if (dirty & I830_UPLOAD_TEXBLEND0) {
+		i830EmitTexBlendVerified( dev, sarea_priv->TexBlendState[0],
+				sarea_priv->TexBlendStateWordsUsed[0]);
+		sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND0;
+	}
+
+	if (dirty & I830_UPLOAD_TEXBLEND1) {
+		i830EmitTexBlendVerified( dev, sarea_priv->TexBlendState[1],
+				sarea_priv->TexBlendStateWordsUsed[1]);
+		sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND1;
+	}
+
+	if (dirty & I830_UPLOAD_TEX_PALETTE_SHARED) {
+	   i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 1);
+	} else {
+	   if (dirty & I830_UPLOAD_TEX_PALETTE_N(0)) {
+	      i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 0);
+	      sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(0);
+	   }
+	   if (dirty & I830_UPLOAD_TEX_PALETTE_N(1)) {
+	      i830EmitTexPalette(dev, sarea_priv->Palette[1], 1, 0);
+	      sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(1);
+	   }
+	}
+}
+
+static void i830_dma_dispatch_clear( drm_device_t *dev, int flags, 
+				    unsigned int clear_color,
+				    unsigned int clear_zval,
+				    unsigned int clear_depthmask)
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+      	drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	int nbox = sarea_priv->nbox;
+	drm_clip_rect_t *pbox = sarea_priv->boxes;
+	int pitch = dev_priv->pitch;
+	int cpp = dev_priv->cpp;
+	int i;
+	unsigned int BR13, CMD, D_CMD;
+	RING_LOCALS;
+
+  	i830_kernel_lost_context(dev);
+
+	switch(cpp) {
+	case 2: 
+		BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24);
+		D_CMD = CMD = XY_COLOR_BLT_CMD;
+		break;
+	case 4:
+		BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24) | (1<<25);
+		CMD = (XY_COLOR_BLT_CMD | XY_COLOR_BLT_WRITE_ALPHA | 
+		       XY_COLOR_BLT_WRITE_RGB);
+		D_CMD = XY_COLOR_BLT_CMD;
+		if(clear_depthmask & 0x00ffffff)
+			D_CMD |= XY_COLOR_BLT_WRITE_RGB;
+		if(clear_depthmask & 0xff000000)
+			D_CMD |= XY_COLOR_BLT_WRITE_ALPHA;
+		break;
+	default:
+		BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24);
+		D_CMD = CMD = XY_COLOR_BLT_CMD;
+		break;
+	}
+
+      	if (nbox > I830_NR_SAREA_CLIPRECTS)
+     		nbox = I830_NR_SAREA_CLIPRECTS;
+
+	for (i = 0 ; i < nbox ; i++, pbox++) {
+		if (pbox->x1 > pbox->x2 ||
+		    pbox->y1 > pbox->y2 ||
+		    pbox->x2 > dev_priv->w ||
+		    pbox->y2 > dev_priv->h)
+			continue;
+
+	   	if ( flags & I830_FRONT ) {	    
+		   	DRM_DEBUG("clear front\n");
+			BEGIN_LP_RING( 6 );	    
+			OUT_RING( CMD );
+			OUT_RING( BR13 );
+			OUT_RING( (pbox->y1 << 16) | pbox->x1 );
+			OUT_RING( (pbox->y2 << 16) | pbox->x2 );
+			OUT_RING( 0 );
+			OUT_RING( clear_color );
+			ADVANCE_LP_RING();
+		}
+
+		if ( flags & I830_BACK ) {
+			DRM_DEBUG("clear back\n");
+			BEGIN_LP_RING( 6 );	    
+			OUT_RING( CMD );
+			OUT_RING( BR13 );
+			OUT_RING( (pbox->y1 << 16) | pbox->x1 );
+			OUT_RING( (pbox->y2 << 16) | pbox->x2 );
+			OUT_RING( dev_priv->back_offset );
+			OUT_RING( clear_color );
+			ADVANCE_LP_RING();
+		}
+
+		if ( flags & I830_DEPTH ) {
+			DRM_DEBUG("clear depth\n");
+			BEGIN_LP_RING( 6 );
+			OUT_RING( D_CMD );
+			OUT_RING( BR13 );
+			OUT_RING( (pbox->y1 << 16) | pbox->x1 );
+			OUT_RING( (pbox->y2 << 16) | pbox->x2 );
+			OUT_RING( dev_priv->depth_offset );
+			OUT_RING( clear_zval );
+			ADVANCE_LP_RING();
+		}
+	}
+}
+
+static void i830_dma_dispatch_swap( drm_device_t *dev )
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+      	drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	int nbox = sarea_priv->nbox;
+	drm_clip_rect_t *pbox = sarea_priv->boxes;
+	int pitch = dev_priv->pitch;
+	int cpp = dev_priv->cpp;
+	int ofs = dev_priv->back_offset;
+	int i;
+	unsigned int CMD, BR13;
+	RING_LOCALS;
+
+	DRM_DEBUG("swapbuffers\n");
+
+	switch(cpp) {
+	case 2: 
+		BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
+		CMD = XY_SRC_COPY_BLT_CMD;
+		break;
+	case 4:
+		BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24) | (1<<25);
+		CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
+		       XY_SRC_COPY_BLT_WRITE_RGB);
+		break;
+	default:
+		BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
+		CMD = XY_SRC_COPY_BLT_CMD;
+		break;
+	}
+
+  	i830_kernel_lost_context(dev);
+
+      	if (nbox > I830_NR_SAREA_CLIPRECTS)
+     		nbox = I830_NR_SAREA_CLIPRECTS;
+
+	for (i = 0 ; i < nbox; i++, pbox++) 
+	{
+		if (pbox->x1 > pbox->x2 ||
+		    pbox->y1 > pbox->y2 ||
+		    pbox->x2 > dev_priv->w ||
+		    pbox->y2 > dev_priv->h)
+			continue;
+ 
+		DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n",
+			  pbox->x1, pbox->y1,
+			  pbox->x2, pbox->y2);
+
+		BEGIN_LP_RING( 8 );
+		OUT_RING( CMD );
+		OUT_RING( BR13 );
+
+		OUT_RING( (pbox->y1 << 16) |
+			  pbox->x1 );
+		OUT_RING( (pbox->y2 << 16) |
+			  pbox->x2 );
+
+		OUT_RING( 0 /* front ofs always zero */ );
+		OUT_RING( (pbox->y1 << 16) |
+			  pbox->x1 );
+
+		OUT_RING( BR13 & 0xffff );
+		OUT_RING( ofs );
+
+		ADVANCE_LP_RING();
+	}
+}
+
+
+static void i830_dma_dispatch_vertex(drm_device_t *dev, 
+				     drm_buf_t *buf,
+				     int discard,
+				     int used)
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+   	drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
+   	drm_clip_rect_t *box = sarea_priv->boxes;
+   	int nbox = sarea_priv->nbox;
+	unsigned long address = (unsigned long)buf->bus_address;
+	unsigned long start = address - dev->agp->base;     
+	int i = 0, u;
+   	RING_LOCALS;
+
+   	i830_kernel_lost_context(dev);
+
+   	if (nbox > I830_NR_SAREA_CLIPRECTS) 
+		nbox = I830_NR_SAREA_CLIPRECTS;
+
+	if (discard) {
+		u = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, 
+			    I830_BUF_HARDWARE);
+		if(u != I830_BUF_CLIENT) {
+			DRM_DEBUG("xxxx 2\n");
+		}
+	}
+
+	if (used > 4*1024) 
+		used = 0;
+
+	if (sarea_priv->dirty)
+	   i830EmitState( dev );
+
+  	DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n", 
+		  address, used, nbox);
+
+   	dev_priv->counter++;
+   	DRM_DEBUG(  "dispatch counter : %ld\n", dev_priv->counter);
+   	DRM_DEBUG(  "i830_dma_dispatch\n");
+   	DRM_DEBUG(  "start : %lx\n", start);
+	DRM_DEBUG(  "used : %d\n", used);
+   	DRM_DEBUG(  "start + used - 4 : %ld\n", start + used - 4);
+
+	if (buf_priv->currently_mapped == I830_BUF_MAPPED) {
+		*(u32 *)buf_priv->virtual = (GFX_OP_PRIMITIVE |
+					     sarea_priv->vertex_prim |
+					     ((used/4)-2));
+		
+		if (used & 4) {
+			*(u32 *)((u32)buf_priv->virtual + used) = 0;
+			used += 4;
+		}
+
+		i830_unmap_buffer(buf);
+	}
+		   
+	if (used) {
+		do {
+			if (i < nbox) {
+				BEGIN_LP_RING(6);
+				OUT_RING( GFX_OP_DRAWRECT_INFO );
+				OUT_RING( sarea_priv->BufferState[I830_DESTREG_DR1] );
+				OUT_RING( box[i].x1 | (box[i].y1<<16) );
+				OUT_RING( box[i].x2 | (box[i].y2<<16) );
+				OUT_RING( sarea_priv->BufferState[I830_DESTREG_DR4] );
+				OUT_RING( 0 );
+				ADVANCE_LP_RING();
+			}
+
+			BEGIN_LP_RING(4);
+
+			OUT_RING( MI_BATCH_BUFFER );
+			OUT_RING( start | MI_BATCH_NON_SECURE );
+			OUT_RING( start + used - 4 );
+			OUT_RING( 0 );
+			ADVANCE_LP_RING();
+			
+		} while (++i < nbox);
+	}
+
+	BEGIN_LP_RING(10);
+	OUT_RING( CMD_STORE_DWORD_IDX );
+	OUT_RING( 20 );
+	OUT_RING( dev_priv->counter );
+	OUT_RING( 0 );
+
+	if (discard) {
+		OUT_RING( CMD_STORE_DWORD_IDX );
+		OUT_RING( buf_priv->my_use_idx );
+		OUT_RING( I830_BUF_FREE );
+		OUT_RING( 0 );
+	}
+
+      	OUT_RING( CMD_REPORT_HEAD );
+	OUT_RING( 0 );
+   	ADVANCE_LP_RING();
+}
+
+/* Interrupts are only for flushing */
+void i830_dma_service(int irq, void *device, struct pt_regs *regs)
+{
+	drm_device_t	 *dev = (drm_device_t *)device;
+      	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+   	u16 temp;
+   
+      	temp = I830_READ16(I830REG_INT_IDENTITY_R);
+   	temp = temp & ~(0x6000);
+   	if(temp != 0) I830_WRITE16(I830REG_INT_IDENTITY_R, 
+				   temp); /* Clear all interrupts */
+	else
+	   return;
+ 
+   	queue_task(&dev->tq, &tq_immediate);
+   	mark_bh(IMMEDIATE_BH);
+}
+
+void DRM(dma_immediate_bh)(void *device)
+{
+	drm_device_t *dev = (drm_device_t *) device;
+      	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+
+   	atomic_set(&dev_priv->flush_done, 1);
+   	wake_up_interruptible(&dev_priv->flush_queue);
+}
+
+static inline void i830_dma_emit_flush(drm_device_t *dev)
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+   	RING_LOCALS;
+
+   	i830_kernel_lost_context(dev);
+
+   	BEGIN_LP_RING(2);
+      	OUT_RING( CMD_REPORT_HEAD );
+      	OUT_RING( GFX_OP_USER_INTERRUPT );
+      	ADVANCE_LP_RING();
+
+	i830_wait_ring( dev, dev_priv->ring.Size - 8 );
+	atomic_set(&dev_priv->flush_done, 1);
+	wake_up_interruptible(&dev_priv->flush_queue);
+}
+
+static inline void i830_dma_quiescent_emit(drm_device_t *dev)
+{
+      	drm_i830_private_t *dev_priv = dev->dev_private;
+   	RING_LOCALS;
+
+  	i830_kernel_lost_context(dev);
+
+   	BEGIN_LP_RING(4);
+   	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );
+   	OUT_RING( CMD_REPORT_HEAD );
+      	OUT_RING( 0 );
+      	OUT_RING( GFX_OP_USER_INTERRUPT );
+   	ADVANCE_LP_RING();
+
+	i830_wait_ring( dev, dev_priv->ring.Size - 8 );
+	atomic_set(&dev_priv->flush_done, 1);
+	wake_up_interruptible(&dev_priv->flush_queue);
+}
+
+void i830_dma_quiescent(drm_device_t *dev)
+{
+      	DECLARE_WAITQUEUE(entry, current);
+  	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+	unsigned long end;      
+
+   	if(dev_priv == NULL) {
+	   	return;
+	}
+      	atomic_set(&dev_priv->flush_done, 0);
+   	add_wait_queue(&dev_priv->flush_queue, &entry);
+   	end = jiffies + (HZ*3);
+   
+   	for (;;) {
+		current->state = TASK_INTERRUPTIBLE;
+	      	i830_dma_quiescent_emit(dev);
+	   	if (atomic_read(&dev_priv->flush_done) == 1) break;
+		if(time_before(end, jiffies)) {
+		   	DRM_ERROR("lockup\n");
+		   	break;
+		}	   
+	      	schedule_timeout(HZ*3);
+	      	if (signal_pending(current)) {
+		   	break;
+		}
+	}
+   
+   	current->state = TASK_RUNNING;
+   	remove_wait_queue(&dev_priv->flush_queue, &entry);
+   
+   	return;
+}
+
+static int i830_flush_queue(drm_device_t *dev)
+{
+   	DECLARE_WAITQUEUE(entry, current);
+  	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+	drm_device_dma_t *dma = dev->dma;
+	unsigned long end;
+   	int i, ret = 0;      
+
+   	if(dev_priv == NULL) {
+	   	return 0;
+	}
+      	atomic_set(&dev_priv->flush_done, 0);
+   	add_wait_queue(&dev_priv->flush_queue, &entry);
+   	end = jiffies + (HZ*3);
+   	for (;;) {
+		current->state = TASK_INTERRUPTIBLE;
+	      	i830_dma_emit_flush(dev);
+	   	if (atomic_read(&dev_priv->flush_done) == 1) break;
+		if(time_before(end, jiffies)) {
+		   	DRM_ERROR("lockup\n");
+		   	break;
+		}	   
+	      	schedule_timeout(HZ*3);
+	      	if (signal_pending(current)) {
+		   	ret = -EINTR; /* Can't restart */
+		   	break;
+		}
+	}
+   
+   	current->state = TASK_RUNNING;
+   	remove_wait_queue(&dev_priv->flush_queue, &entry);
+
+
+   	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+	   
+		int used = cmpxchg(buf_priv->in_use, I830_BUF_HARDWARE, 
+				   I830_BUF_FREE);
+
+		if (used == I830_BUF_HARDWARE)
+			DRM_DEBUG("reclaimed from HARDWARE\n");
+		if (used == I830_BUF_CLIENT)
+			DRM_DEBUG("still on client HARDWARE\n");
+	}
+
+   	return ret;
+}
+
+/* Must be called with the lock held */
+void i830_reclaim_buffers(drm_device_t *dev, pid_t pid)
+{
+	drm_device_dma_t *dma = dev->dma;
+	int		 i;
+
+	if (!dma) return;
+      	if (!dev->dev_private) return;
+	if (!dma->buflist) return;
+
+        i830_flush_queue(dev);
+
+	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+	   
+		if (buf->pid == pid && buf_priv) {
+			int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, 
+					   I830_BUF_FREE);
+
+			if (used == I830_BUF_CLIENT)
+				DRM_DEBUG("reclaimed from client\n");
+		   	if(buf_priv->currently_mapped == I830_BUF_MAPPED)
+		     		buf_priv->currently_mapped = I830_BUF_UNMAPPED;
+		}
+	}
+}
+
+int i830_flush_ioctl(struct inode *inode, struct file *filp, 
+		     unsigned int cmd, unsigned long arg)
+{
+   	drm_file_t	  *priv	  = filp->private_data;
+   	drm_device_t	  *dev	  = priv->dev;
+   
+   	DRM_DEBUG("i830_flush_ioctl\n");
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i830_flush_ioctl called without lock held\n");
+		return -EINVAL;
+	}
+
+   	i830_flush_queue(dev);
+   	return 0;
+}
+
+int i830_dma_vertex(struct inode *inode, struct file *filp,
+	       unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_device_dma_t *dma = dev->dma;
+   	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+      	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+   	drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) 
+     					dev_priv->sarea_priv; 
+	drm_i830_vertex_t vertex;
+
+	if (copy_from_user(&vertex, (drm_i830_vertex_t *)arg, sizeof(vertex)))
+		return -EFAULT;
+
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i830_dma_vertex called without lock held\n");
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("i830 dma vertex, idx %d used %d discard %d\n",
+		  vertex.idx, vertex.used, vertex.discard);
+
+	if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL;
+
+	i830_dma_dispatch_vertex( dev, 
+				  dma->buflist[ vertex.idx ], 
+				  vertex.discard, vertex.used );
+
+	sarea_priv->last_enqueue = dev_priv->counter-1;
+   	sarea_priv->last_dispatch = (int) hw_status[5];
+   
+	return 0;
+}
+
+int i830_clear_bufs(struct inode *inode, struct file *filp,
+		   unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_i830_clear_t clear;
+
+   	if (copy_from_user(&clear, (drm_i830_clear_t *)arg, sizeof(clear)))
+		return -EFAULT;
+   
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i830_clear_bufs called without lock held\n");
+		return -EINVAL;
+	}
+
+	/* GH: Someone's doing nasty things... */
+	if (!dev->dev_private) {
+		return -EINVAL;
+	}
+
+	i830_dma_dispatch_clear( dev, clear.flags, 
+				 clear.clear_color, 
+				 clear.clear_depth,
+			         clear.clear_depthmask);
+   	return 0;
+}
+
+int i830_swap_bufs(struct inode *inode, struct file *filp,
+		  unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+   
+	DRM_DEBUG("i830_swap_bufs\n");
+
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i830_swap_buf called without lock held\n");
+		return -EINVAL;
+	}
+
+	i830_dma_dispatch_swap( dev );
+   	return 0;
+}
+
+int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+   	drm_file_t	  *priv	    = filp->private_data;
+	drm_device_t	  *dev	    = priv->dev;
+   	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+      	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+   	drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) 
+     					dev_priv->sarea_priv; 
+
+      	sarea_priv->last_dispatch = (int) hw_status[5];
+	return 0;
+}
+
+int i830_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	  *priv	    = filp->private_data;
+	drm_device_t	  *dev	    = priv->dev;
+	int		  retcode   = 0;
+	drm_i830_dma_t	  d;
+   	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+   	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+   	drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) 
+     					dev_priv->sarea_priv; 
+
+	DRM_DEBUG("getbuf\n");
+   	if (copy_from_user(&d, (drm_i830_dma_t *)arg, sizeof(d)))
+		return -EFAULT;
+   
+	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i830_dma called without lock held\n");
+		return -EINVAL;
+	}
+	
+	d.granted = 0;
+
+	retcode = i830_dma_get_buffer(dev, &d, filp);
+
+	DRM_DEBUG("i830_dma: %d returning %d, granted = %d\n",
+		  current->pid, retcode, d.granted);
+
+	if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d)))
+		return -EFAULT;
+   	sarea_priv->last_dispatch = (int) hw_status[5];
+
+	return retcode;
+}
+
+int i830_copybuf(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	  *priv	    = filp->private_data;
+	drm_device_t	  *dev	    = priv->dev;
+	drm_i830_copy_t	  d;
+   	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+   	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+   	drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) 
+     					dev_priv->sarea_priv; 
+	drm_buf_t *buf;
+	drm_i830_buf_priv_t *buf_priv;
+	drm_device_dma_t *dma = dev->dma;
+
+	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i830_dma called without lock held\n");
+		return -EINVAL;
+	}
+   
+   	if (copy_from_user(&d, (drm_i830_copy_t *)arg, sizeof(d)))
+		return -EFAULT;
+
+	if(d.idx < 0 || d.idx > dma->buf_count) return -EINVAL;
+	buf = dma->buflist[ d.idx ];
+   	buf_priv = buf->dev_private;
+	if (buf_priv->currently_mapped != I830_BUF_MAPPED) return -EPERM;
+
+	if(d.used < 0 || d.used > buf->total) return -EINVAL;
+
+   	if (copy_from_user(buf_priv->virtual, d.address, d.used))
+		return -EFAULT;
+
+   	sarea_priv->last_dispatch = (int) hw_status[5];
+
+	return 0;
+}
+
+int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	if(VM_DONTCOPY == 0) return 1;
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/i830_drm.h linux-2.4.20/drivers/char/drm/i830_drm.h
--- linux-2.4.19/drivers/char/drm/i830_drm.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/i830_drm.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,238 @@
+#ifndef _I830_DRM_H_
+#define _I830_DRM_H_
+
+/* WARNING: These defines must be the same as what the Xserver uses.
+ * if you change them, you must change the defines in the Xserver.
+ */
+
+#ifndef _I830_DEFINES_
+#define _I830_DEFINES_
+
+#define I830_DMA_BUF_ORDER		12
+#define I830_DMA_BUF_SZ 		(1<<I830_DMA_BUF_ORDER)
+#define I830_DMA_BUF_NR 		256
+#define I830_NR_SAREA_CLIPRECTS 	8
+
+/* Each region is a minimum of 64k, and there are at most 64 of them.
+ */
+#define I830_NR_TEX_REGIONS 64
+#define I830_LOG_MIN_TEX_REGION_SIZE 16
+
+/* if defining I830_ENABLE_4_TEXTURES, do it in i830_3d_reg.h, too */
+#if !defined(I830_ENABLE_4_TEXTURES)
+#define I830_TEXTURE_COUNT	2
+#define I830_TEXBLEND_COUNT	2	/* always same as TEXTURE_COUNT? */
+#else /* defined(I830_ENABLE_4_TEXTURES) */
+#define I830_TEXTURE_COUNT	4
+#define I830_TEXBLEND_COUNT	4	/* always same as TEXTURE_COUNT? */
+#endif /* I830_ENABLE_4_TEXTURES */
+
+#define I830_TEXBLEND_SIZE	12	/* (4 args + op) * 2 + COLOR_FACTOR */
+
+#define I830_UPLOAD_CTX			0x1
+#define I830_UPLOAD_BUFFERS		0x2
+#define I830_UPLOAD_CLIPRECTS		0x4
+#define I830_UPLOAD_TEX0_IMAGE		0x100 /* handled clientside */
+#define I830_UPLOAD_TEX0_CUBE		0x200 /* handled clientside */
+#define I830_UPLOAD_TEX1_IMAGE		0x400 /* handled clientside */
+#define I830_UPLOAD_TEX1_CUBE		0x800 /* handled clientside */
+#define I830_UPLOAD_TEX2_IMAGE		0x1000 /* handled clientside */
+#define I830_UPLOAD_TEX2_CUBE		0x2000 /* handled clientside */
+#define I830_UPLOAD_TEX3_IMAGE		0x4000 /* handled clientside */
+#define I830_UPLOAD_TEX3_CUBE		0x8000 /* handled clientside */
+#define I830_UPLOAD_TEX_N_IMAGE(n)	(0x100 << (n * 2))
+#define I830_UPLOAD_TEX_N_CUBE(n)	(0x200 << (n * 2))
+#define I830_UPLOAD_TEXIMAGE_MASK	0xff00
+#define I830_UPLOAD_TEX0			0x10000
+#define I830_UPLOAD_TEX1			0x20000
+#define I830_UPLOAD_TEX2			0x40000
+#define I830_UPLOAD_TEX3			0x80000
+#define I830_UPLOAD_TEX_N(n)		(0x10000 << (n))
+#define I830_UPLOAD_TEX_MASK		0xf0000
+#define I830_UPLOAD_TEXBLEND0		0x100000
+#define I830_UPLOAD_TEXBLEND1		0x200000
+#define I830_UPLOAD_TEXBLEND2		0x400000
+#define I830_UPLOAD_TEXBLEND3		0x800000
+#define I830_UPLOAD_TEXBLEND_N(n)	(0x100000 << (n))
+#define I830_UPLOAD_TEXBLEND_MASK	0xf00000
+#define I830_UPLOAD_TEX_PALETTE_N(n)    (0x1000000 << (n))
+#define I830_UPLOAD_TEX_PALETTE_SHARED	0x4000000
+
+/* Indices into buf.Setup where various bits of state are mirrored per
+ * context and per buffer.  These can be fired at the card as a unit,
+ * or in a piecewise fashion as required.
+ */
+
+/* Destbuffer state 
+ *    - backbuffer linear offset and pitch -- invarient in the current dri
+ *    - zbuffer linear offset and pitch -- also invarient
+ *    - drawing origin in back and depth buffers.
+ *
+ * Keep the depth/back buffer state here to acommodate private buffers
+ * in the future.
+ */
+
+#define I830_DESTREG_CBUFADDR 0
+/* Invarient */
+#define I830_DESTREG_DBUFADDR 1
+#define I830_DESTREG_DV0 2
+#define I830_DESTREG_DV1 3
+#define I830_DESTREG_SENABLE 4
+#define I830_DESTREG_SR0 5
+#define I830_DESTREG_SR1 6
+#define I830_DESTREG_SR2 7
+#define I830_DESTREG_DR0 8
+#define I830_DESTREG_DR1 9
+#define I830_DESTREG_DR2 10
+#define I830_DESTREG_DR3 11
+#define I830_DESTREG_DR4 12
+#define I830_DEST_SETUP_SIZE 13
+
+/* Context state
+ */
+#define I830_CTXREG_STATE1		0
+#define I830_CTXREG_STATE2		1
+#define I830_CTXREG_STATE3		2
+#define I830_CTXREG_STATE4		3
+#define I830_CTXREG_STATE5		4
+#define I830_CTXREG_IALPHAB		5
+#define I830_CTXREG_STENCILTST		6
+#define I830_CTXREG_ENABLES_1		7
+#define I830_CTXREG_ENABLES_2		8
+#define I830_CTXREG_AA			9
+#define I830_CTXREG_FOGCOLOR		10
+#define I830_CTXREG_BLENDCOLR0		11
+#define I830_CTXREG_BLENDCOLR		12 /* Dword 1 of 2 dword command */
+#define I830_CTXREG_VF			13
+#define I830_CTXREG_VF2			14
+#define I830_CTXREG_MCSB0		15
+#define I830_CTXREG_MCSB1		16
+#define I830_CTX_SETUP_SIZE		17
+
+/* Texture state (per tex unit)
+ */
+
+#define I830_TEXREG_MI0	0	/* GFX_OP_MAP_INFO (6 dwords) */
+#define I830_TEXREG_MI1	1
+#define I830_TEXREG_MI2	2
+#define I830_TEXREG_MI3	3
+#define I830_TEXREG_MI4	4
+#define I830_TEXREG_MI5	5
+#define I830_TEXREG_MF	6	/* GFX_OP_MAP_FILTER */
+#define I830_TEXREG_MLC	7	/* GFX_OP_MAP_LOD_CTL */
+#define I830_TEXREG_MLL	8	/* GFX_OP_MAP_LOD_LIMITS */
+#define I830_TEXREG_MCS	9	/* GFX_OP_MAP_COORD_SETS */
+#define I830_TEX_SETUP_SIZE 10
+
+#define I830_FRONT   0x1
+#define I830_BACK    0x2
+#define I830_DEPTH   0x4
+
+#endif /* _I830_DEFINES_ */
+
+typedef struct _drm_i830_init {
+	enum {
+		I830_INIT_DMA = 0x01,
+		I830_CLEANUP_DMA = 0x02
+	} func;
+	unsigned int mmio_offset;
+	unsigned int buffers_offset;
+	int sarea_priv_offset;
+	unsigned int ring_start;
+	unsigned int ring_end;
+	unsigned int ring_size;
+	unsigned int front_offset;
+	unsigned int back_offset;
+	unsigned int depth_offset;
+	unsigned int w;
+	unsigned int h;
+	unsigned int pitch;
+	unsigned int pitch_bits;
+	unsigned int back_pitch;
+	unsigned int depth_pitch;
+	unsigned int cpp;
+} drm_i830_init_t;
+
+/* Warning: If you change the SAREA structure you must change the Xserver
+ * structure as well */
+
+typedef struct _drm_i830_tex_region {
+	unsigned char next, prev; /* indices to form a circular LRU  */
+	unsigned char in_use;	/* owned by a client, or free? */
+	int age;		/* tracked by clients to update local LRU's */
+} drm_i830_tex_region_t;
+
+typedef struct _drm_i830_sarea {
+	unsigned int ContextState[I830_CTX_SETUP_SIZE];
+   	unsigned int BufferState[I830_DEST_SETUP_SIZE];
+	unsigned int TexState[I830_TEXTURE_COUNT][I830_TEX_SETUP_SIZE];
+	unsigned int TexBlendState[I830_TEXBLEND_COUNT][I830_TEXBLEND_SIZE];
+	unsigned int TexBlendStateWordsUsed[I830_TEXBLEND_COUNT];
+	unsigned int Palette[2][256];
+   	unsigned int dirty;
+
+	unsigned int nbox;
+	drm_clip_rect_t boxes[I830_NR_SAREA_CLIPRECTS];
+
+	/* Maintain an LRU of contiguous regions of texture space.  If
+	 * you think you own a region of texture memory, and it has an
+	 * age different to the one you set, then you are mistaken and
+	 * it has been stolen by another client.  If global texAge
+	 * hasn't changed, there is no need to walk the list.
+	 *
+	 * These regions can be used as a proxy for the fine-grained
+	 * texture information of other clients - by maintaining them
+	 * in the same lru which is used to age their own textures,
+	 * clients have an approximate lru for the whole of global
+	 * texture space, and can make informed decisions as to which
+	 * areas to kick out.  There is no need to choose whether to
+	 * kick out your own texture or someone else's - simply eject
+	 * them all in LRU order.  
+	 */
+
+	drm_i830_tex_region_t texList[I830_NR_TEX_REGIONS+1]; 
+				/* Last elt is sentinal */
+        int texAge;		/* last time texture was uploaded */
+        int last_enqueue;	/* last time a buffer was enqueued */
+	int last_dispatch;	/* age of the most recently dispatched buffer */
+	int last_quiescent;     /*  */
+	int ctxOwner;		/* last context to upload state */
+
+	int vertex_prim;
+} drm_i830_sarea_t;
+
+typedef struct _drm_i830_clear {
+	int clear_color;
+	int clear_depth;
+	int flags;
+	unsigned int clear_colormask;
+	unsigned int clear_depthmask;
+} drm_i830_clear_t;
+
+
+
+/* These may be placeholders if we have more cliprects than
+ * I830_NR_SAREA_CLIPRECTS.  In that case, the client sets discard to
+ * false, indicating that the buffer will be dispatched again with a
+ * new set of cliprects.
+ */
+typedef struct _drm_i830_vertex {
+   	int idx;		/* buffer index */
+	int used;		/* nr bytes in use */
+	int discard;		/* client is finished with the buffer? */
+} drm_i830_vertex_t;
+
+typedef struct _drm_i830_copy_t {
+   	int idx;		/* buffer index */
+	int used;		/* nr bytes in use */
+	void *address;		/* Address to copy from */
+} drm_i830_copy_t;
+
+typedef struct drm_i830_dma {
+	void *virtual;
+	int request_idx;
+	int request_size;
+	int granted;
+} drm_i830_dma_t;
+
+#endif /* _I830_DRM_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/i830_drv.c linux-2.4.20/drivers/char/drm/i830_drv.c
--- linux-2.4.19/drivers/char/drm/i830_drv.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/i830_drv.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,102 @@
+/* i830_drv.c -- I810 driver -*- linux-c -*-
+ * Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *    Jeff Hartmann <jhartmann@valinux.com>
+ *    Gareth Hughes <gareth@valinux.com>
+ *    Abraham vd Merwe <abraham@2d3d.co.za>
+ */
+
+#include <linux/config.h>
+#include "i830.h"
+#include "drmP.h"
+#include "i830_drv.h"
+
+#define DRIVER_AUTHOR		"VA Linux Systems Inc."
+
+#define DRIVER_NAME		"i830"
+#define DRIVER_DESC		"Intel 830M"
+#define DRIVER_DATE		"20011004"
+
+#define DRIVER_MAJOR		1
+#define DRIVER_MINOR		2
+#define DRIVER_PATCHLEVEL	0
+
+#define DRIVER_IOCTLS							    \
+	[DRM_IOCTL_NR(DRM_IOCTL_I830_INIT)]   = { i830_dma_init,    1, 1 }, \
+   	[DRM_IOCTL_NR(DRM_IOCTL_I830_VERTEX)] = { i830_dma_vertex,  1, 0 }, \
+   	[DRM_IOCTL_NR(DRM_IOCTL_I830_CLEAR)]  = { i830_clear_bufs,  1, 0 }, \
+      	[DRM_IOCTL_NR(DRM_IOCTL_I830_FLUSH)]  = { i830_flush_ioctl, 1, 0 }, \
+   	[DRM_IOCTL_NR(DRM_IOCTL_I830_GETAGE)] = { i830_getage,      1, 0 }, \
+	[DRM_IOCTL_NR(DRM_IOCTL_I830_GETBUF)] = { i830_getbuf,      1, 0 }, \
+   	[DRM_IOCTL_NR(DRM_IOCTL_I830_SWAP)]   = { i830_swap_bufs,   1, 0 }, \
+   	[DRM_IOCTL_NR(DRM_IOCTL_I830_COPY)]   = { i830_copybuf,     1, 0 }, \
+   	[DRM_IOCTL_NR(DRM_IOCTL_I830_DOCOPY)] = { i830_docopy,      1, 0 },
+
+#define __HAVE_COUNTERS         4
+#define __HAVE_COUNTER6         _DRM_STAT_IRQ
+#define __HAVE_COUNTER7         _DRM_STAT_PRIMARY
+#define __HAVE_COUNTER8         _DRM_STAT_SECONDARY
+#define __HAVE_COUNTER9         _DRM_STAT_DMA
+
+
+#include "drm_agpsupport.h"
+#include "drm_auth.h"
+#include "drm_bufs.h"
+#include "drm_context.h"
+#include "drm_dma.h"
+#include "drm_drawable.h"
+#include "drm_drv.h"
+
+#ifndef MODULE
+/* DRM(options) is called by the kernel to parse command-line options
+ * passed via the boot-loader (e.g., LILO).  It calls the insmod option
+ * routine, drm_parse_drm.
+ */
+
+/* JH- We have to hand expand the string ourselves because of the cpp.  If
+ * anyone can think of a way that we can fit into the __setup macro without
+ * changing it, then please send the solution my way.
+ */
+static int __init i830_options( char *str )
+{
+   DRM(parse_options)( str );
+   return 1;
+}
+
+__setup( DRIVER_NAME "=", i830_options );
+#endif
+
+#include "drm_fops.h"
+#include "drm_init.h"
+#include "drm_ioctl.h"
+#include "drm_lock.h"
+#include "drm_lists.h"
+#include "drm_memory.h"
+#include "drm_proc.h"
+#include "drm_vm.h"
+#include "drm_stub.h"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/i830_drv.h linux-2.4.20/drivers/char/drm/i830_drv.h
--- linux-2.4.19/drivers/char/drm/i830_drv.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/i830_drv.h	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,215 @@
+/* i830_drv.h -- Private header for the I830 driver -*- linux-c -*-
+ * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ * 	    Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#ifndef _I830_DRV_H_
+#define _I830_DRV_H_
+
+typedef struct drm_i830_buf_priv {
+   	u32 *in_use;
+   	int my_use_idx;
+	int currently_mapped;
+	void *virtual;
+	void *kernel_virtual;
+	int map_count;
+   	struct vm_area_struct *vma;
+} drm_i830_buf_priv_t;
+
+typedef struct _drm_i830_ring_buffer{
+	int tail_mask;
+	unsigned long Start;
+	unsigned long End;
+	unsigned long Size;
+	u8 *virtual_start;
+	int head;
+	int tail;
+	int space;
+} drm_i830_ring_buffer_t;
+
+typedef struct drm_i830_private {
+	drm_map_t *sarea_map;
+	drm_map_t *buffer_map;
+	drm_map_t *mmio_map;
+
+	drm_i830_sarea_t *sarea_priv;
+   	drm_i830_ring_buffer_t ring;
+
+      	u8 *hw_status_page;
+   	unsigned long counter;
+   	
+   	dma_addr_t dma_status_page;
+
+   	atomic_t flush_done;
+   	wait_queue_head_t flush_queue;	/* Processes waiting until flush    */
+	drm_buf_t *mmap_buffer;
+	
+	u32 front_di1, back_di1, zi1;
+	
+	int back_offset;
+	int depth_offset;
+	int w, h;
+	int pitch;
+	int back_pitch;
+	int depth_pitch;
+	unsigned int cpp;
+} drm_i830_private_t;
+
+				/* i830_dma.c */
+extern int  i830_dma_schedule(drm_device_t *dev, int locked);
+extern int  i830_getbuf(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  i830_dma_init(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  i830_flush_ioctl(struct inode *inode, struct file *filp,
+			     unsigned int cmd, unsigned long arg);
+extern void i830_reclaim_buffers(drm_device_t *dev, pid_t pid);
+extern int  i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
+			unsigned long arg);
+extern int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma);
+extern int i830_copybuf(struct inode *inode, struct file *filp, 
+			unsigned int cmd, unsigned long arg);
+extern int i830_docopy(struct inode *inode, struct file *filp, 
+		       unsigned int cmd, unsigned long arg);
+
+extern void i830_dma_quiescent(drm_device_t *dev);
+
+extern int i830_dma_vertex(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+
+extern int i830_swap_bufs(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+
+extern int i830_clear_bufs(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+
+#define I830_VERBOSE 0
+
+#define I830_BASE(reg)		((unsigned long) \
+				dev_priv->mmio_map->handle)
+#define I830_ADDR(reg)		(I830_BASE(reg) + reg)
+#define I830_DEREF(reg)		*(__volatile__ int *)I830_ADDR(reg)
+#define I830_READ(reg)		I830_DEREF(reg)
+#define I830_WRITE(reg,val) 	do { I830_DEREF(reg) = val; } while (0)
+#define I830_DEREF16(reg)	*(__volatile__ u16 *)I830_ADDR(reg)
+#define I830_READ16(reg) 	I830_DEREF16(reg)
+#define I830_WRITE16(reg,val)	do { I830_DEREF16(reg) = val; } while (0)
+
+#define GFX_OP_USER_INTERRUPT 		((0<<29)|(2<<23))
+#define GFX_OP_BREAKPOINT_INTERRUPT	((0<<29)|(1<<23))
+#define CMD_REPORT_HEAD			(7<<23)
+#define CMD_STORE_DWORD_IDX		((0x21<<23) | 0x1)
+#define CMD_OP_BATCH_BUFFER  ((0x0<<29)|(0x30<<23)|0x1)
+
+#define INST_PARSER_CLIENT   0x00000000
+#define INST_OP_FLUSH        0x02000000
+#define INST_FLUSH_MAP_CACHE 0x00000001
+
+
+#define BB1_START_ADDR_MASK   (~0x7)
+#define BB1_PROTECTED         (1<<0)
+#define BB1_UNPROTECTED       (0<<0)
+#define BB2_END_ADDR_MASK     (~0x7)
+
+#define I830REG_HWSTAM		0x02098
+#define I830REG_INT_IDENTITY_R	0x020a4
+#define I830REG_INT_MASK_R 	0x020a8
+#define I830REG_INT_ENABLE_R	0x020a0
+
+#define LP_RING     		0x2030
+#define HP_RING     		0x2040
+#define RING_TAIL      		0x00
+#define TAIL_ADDR		0x000FFFF8
+#define RING_HEAD      		0x04
+#define HEAD_WRAP_COUNT     	0xFFE00000
+#define HEAD_WRAP_ONE       	0x00200000
+#define HEAD_ADDR           	0x001FFFFC
+#define RING_START     		0x08
+#define START_ADDR          	0x00FFFFF8
+#define RING_LEN       		0x0C
+#define RING_NR_PAGES       	0x000FF000 
+#define RING_REPORT_MASK    	0x00000006
+#define RING_REPORT_64K     	0x00000002
+#define RING_REPORT_128K    	0x00000004
+#define RING_NO_REPORT      	0x00000000
+#define RING_VALID_MASK     	0x00000001
+#define RING_VALID          	0x00000001
+#define RING_INVALID        	0x00000000
+
+#define GFX_OP_SCISSOR         ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define SC_UPDATE_SCISSOR       (0x1<<1)
+#define SC_ENABLE_MASK          (0x1<<0)
+#define SC_ENABLE               (0x1<<0)
+
+#define GFX_OP_SCISSOR_INFO    ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
+#define SCI_YMIN_MASK      (0xffff<<16)
+#define SCI_XMIN_MASK      (0xffff<<0)
+#define SCI_YMAX_MASK      (0xffff<<16)
+#define SCI_XMAX_MASK      (0xffff<<0)
+
+#define GFX_OP_SCISSOR_ENABLE	 ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define GFX_OP_SCISSOR_RECT	 ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1)
+#define GFX_OP_COLOR_FACTOR      ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
+#define GFX_OP_STIPPLE           ((0x3<<29)|(0x1d<<24)|(0x83<<16))
+#define GFX_OP_MAP_INFO          ((0x3<<29)|(0x1d<<24)|0x4)
+#define GFX_OP_DESTBUFFER_VARS   ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
+#define GFX_OP_DRAWRECT_INFO     ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
+#define GFX_OP_PRIMITIVE         ((0x3<<29)|(0x1f<<24))
+
+#define CMD_OP_DESTBUFFER_INFO	 ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
+
+
+#define BR00_BITBLT_CLIENT   0x40000000
+#define BR00_OP_COLOR_BLT    0x10000000
+#define BR00_OP_SRC_COPY_BLT 0x10C00000
+#define BR13_SOLID_PATTERN   0x80000000
+
+#define BUF_3D_ID_COLOR_BACK    (0x3<<24)
+#define BUF_3D_ID_DEPTH         (0x7<<24)
+#define BUF_3D_USE_FENCE        (1<<23)
+#define BUF_3D_PITCH(x)         (((x)/4)<<2)
+
+#define CMD_OP_MAP_PALETTE_LOAD	((3<<29)|(0x1d<<24)|(0x82<<16)|255)
+#define MAP_PALETTE_NUM(x)	((x<<8) & (1<<8))
+#define MAP_PALETTE_BOTH	(1<<11)
+
+#define XY_COLOR_BLT_CMD		((2<<29)|(0x50<<22)|0x4)
+#define XY_COLOR_BLT_WRITE_ALPHA	(1<<21)
+#define XY_COLOR_BLT_WRITE_RGB		(1<<20)
+
+#define XY_SRC_COPY_BLT_CMD             ((2<<29)|(0x53<<22)|6)
+#define XY_SRC_COPY_BLT_WRITE_ALPHA     (1<<21)
+#define XY_SRC_COPY_BLT_WRITE_RGB       (1<<20)
+
+#define MI_BATCH_BUFFER 	((0x30<<23)|1)
+#define MI_BATCH_NON_SECURE	(1)
+
+
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/mga_dma.c linux-2.4.20/drivers/char/drm/mga_dma.c
--- linux-2.4.19/drivers/char/drm/mga_dma.c	2001-08-08 16:42:15.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/mga_dma.c	2002-10-29 11:18:36.000000000 +0000
@@ -33,7 +33,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "mga.h"
 #include "drmP.h"
 #include "mga_drv.h"
@@ -159,9 +158,18 @@
 {
 	drm_mga_primary_buffer_t *primary = &dev_priv->prim;
 	u32 head, tail;
+	u32 status = 0;
+	int i;
 	DMA_LOCALS;
 	DRM_DEBUG( "%s:\n", __FUNCTION__ );
 
+        /* We need to wait so that we can do an safe flush */
+	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
+		status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK;
+		if ( status == MGA_ENDPRDMASTS ) break;
+		udelay( 1 );
+	}
+
 	if ( primary->tail == primary->last_flush ) {
 		DRM_DEBUG( "   bailing out...\n" );
 		return;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/mga_drv.h linux-2.4.20/drivers/char/drm/mga_drv.h
--- linux-2.4.19/drivers/char/drm/mga_drv.h	2001-08-27 14:40:33.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/mga_drv.h	2002-10-29 11:18:49.000000000 +0000
@@ -38,7 +38,7 @@
 
 	u32 tail;
 	int space;
-	volatile int wrapped;
+	volatile long wrapped;
 
 	volatile u32 *status;
 
@@ -213,7 +213,7 @@
 		} else if ( dev_priv->prim.space <			\
 			    dev_priv->prim.high_mark ) {		\
 			if ( MGA_DMA_DEBUG )				\
-				DRM_INFO( __FUNCTION__": wrap...\n" );	\
+				DRM_INFO( "%s: wrap...\n", __FUNCTION__ );	\
 			return -EBUSY;					\
 		}							\
 	}								\
@@ -224,7 +224,7 @@
 	if ( test_bit( 0, &dev_priv->prim.wrapped ) ) {			\
 		if ( mga_do_wait_for_idle( dev_priv ) < 0 ) {		\
 			if ( MGA_DMA_DEBUG )				\
-				DRM_INFO( __FUNCTION__": wrap...\n" );	\
+				DRM_INFO( "%s: wrap...\n", __FUNCTION__ );	\
 			return -EBUSY;					\
 		}							\
 		mga_do_dma_wrap_end( dev_priv );			\
@@ -276,7 +276,7 @@
 #define FLUSH_DMA()							\
 do {									\
 	if ( 0 ) {							\
-		DRM_INFO( __FUNCTION__ ":\n" );				\
+		DRM_INFO( "%s:\n" , __FUNCTION__);			\
 		DRM_INFO( "   tail=0x%06x head=0x%06lx\n",		\
 			  dev_priv->prim.tail,				\
 			  MGA_READ( MGA_PRIMADDRESS ) -			\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/mga_state.c linux-2.4.20/drivers/char/drm/mga_state.c
--- linux-2.4.19/drivers/char/drm/mga_state.c	2001-08-08 16:42:15.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/mga_state.c	2002-10-29 11:18:38.000000000 +0000
@@ -32,7 +32,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "mga.h"
 #include "drmP.h"
 #include "mga_drv.h"
@@ -513,7 +512,7 @@
 	int nbox = sarea_priv->nbox;
 	int i;
 	DMA_LOCALS;
-	DRM_DEBUG( __FUNCTION__ ":\n" );
+	DRM_DEBUG("%s:\n" , __FUNCTION__);
 
 	BEGIN_DMA( 1 );
 
@@ -607,7 +606,7 @@
 	int nbox = sarea_priv->nbox;
 	int i;
 	DMA_LOCALS;
-	DRM_DEBUG( __FUNCTION__ ":\n" );
+	DRM_DEBUG( "%s:\n", __FUNCTION__ );
 
 	sarea_priv->last_frame.head = dev_priv->prim.tail;
 	sarea_priv->last_frame.wrap = dev_priv->prim.last_wrap;
@@ -816,7 +815,7 @@
 	int nbox = sarea_priv->nbox;
 	u32 scandir = 0, i;
 	DMA_LOCALS;
-	DRM_DEBUG( __FUNCTION__ ":\n" );
+	DRM_DEBUG( "%s:\n", __FUNCTION__ );
 
 	BEGIN_DMA( 4 + nbox );
 
@@ -1019,7 +1018,7 @@
 	drm_buf_t *buf;
 	drm_mga_buf_priv_t *buf_priv;
 	drm_mga_iload_t iload;
-	DRM_DEBUG( __FUNCTION__ ":\n" );
+	DRM_DEBUG( "%s:\n", __FUNCTION__ );
 
 	LOCK_TEST_WITH_RETURN( dev );
 
@@ -1029,7 +1028,7 @@
 #if 0
 	if ( mga_do_wait_for_idle( dev_priv ) < 0 ) {
 		if ( MGA_DMA_DEBUG )
-			DRM_INFO( __FUNCTION__": -EBUSY\n" );
+			DRM_INFO( "%s: -EBUSY\n" , __FUNCTION__);
 		return -EBUSY;
 	}
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/mga_warp.c linux-2.4.20/drivers/char/drm/mga_warp.c
--- linux-2.4.19/drivers/char/drm/mga_warp.c	2001-08-08 16:42:15.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/mga_warp.c	2002-10-29 11:18:39.000000000 +0000
@@ -27,7 +27,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "mga.h"
 #include "drmP.h"
 #include "mga_drv.h"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/r128_cce.c linux-2.4.20/drivers/char/drm/r128_cce.c
--- linux-2.4.19/drivers/char/drm/r128_cce.c	2001-08-27 14:40:33.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/r128_cce.c	2002-10-29 11:18:33.000000000 +0000
@@ -28,7 +28,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "r128.h"
 #include "drmP.h"
 #include "r128_drv.h"
@@ -352,8 +351,8 @@
 
 		R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR,
      			    entry->busaddr[page_ofs]);
-		DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n",
-			   entry->busaddr[page_ofs],
+		DRM_DEBUG( "ring rptr: offset=0x%08llx handle=0x%08lx\n",
+			   (u64)entry->busaddr[page_ofs],
      			   entry->handle + tmp_ofs );
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/r128_drv.c linux-2.4.20/drivers/char/drm/r128_drv.c
--- linux-2.4.19/drivers/char/drm/r128_drv.c	2001-08-08 16:42:15.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/r128_drv.c	2002-10-29 11:18:35.000000000 +0000
@@ -39,11 +39,11 @@
 
 #define DRIVER_NAME		"r128"
 #define DRIVER_DESC		"ATI Rage 128"
-#define DRIVER_DATE		"20010405"
+#define DRIVER_DATE		"20010917"
 
 #define DRIVER_MAJOR		2
-#define DRIVER_MINOR		1
-#define DRIVER_PATCHLEVEL	6
+#define DRIVER_MINOR		2
+#define DRIVER_PATCHLEVEL	0
 
 #define DRIVER_IOCTLS							    \
    [DRM_IOCTL_NR(DRM_IOCTL_DMA)]             = { r128_cce_buffers,  1, 0 }, \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/r128_drv.h linux-2.4.20/drivers/char/drm/r128_drv.h
--- linux-2.4.19/drivers/char/drm/r128_drv.h	2001-08-27 14:40:33.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/r128_drv.h	2002-10-29 11:18:51.000000000 +0000
@@ -469,7 +469,7 @@
 		DRM_ERROR( "ring space check failed!\n" );		\
 		return -EBUSY;						\
 	}								\
- __ring_space_done:							\
+ __ring_space_done: ;							\
 } while (0)
 
 #define VB_AGE_TEST_WITH_RETURN( dev_priv )				\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/r128_state.c linux-2.4.20/drivers/char/drm/r128_state.c
--- linux-2.4.19/drivers/char/drm/r128_state.c	2001-08-08 16:42:15.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/r128_state.c	2002-10-29 11:18:33.000000000 +0000
@@ -27,7 +27,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "r128.h"
 #include "drmP.h"
 #include "r128_drv.h"
@@ -1519,10 +1518,75 @@
 {
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->dev;
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_device_dma_t *dma = dev->dma;
+	drm_buf_t *buf;
+	drm_r128_buf_priv_t *buf_priv;
+	drm_r128_indirect_t indirect;
+#if 0
+	RING_LOCALS;
+#endif
 
 	LOCK_TEST_WITH_RETURN( dev );
 
-	/* Indirect buffer firing is not supported at this time.
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return -EINVAL;
+	}
+
+	if ( copy_from_user( &indirect, (drm_r128_indirect_t *)arg,
+			     sizeof(indirect) ) )
+		return -EFAULT;
+
+	DRM_DEBUG( "indirect: idx=%d s=%d e=%d d=%d\n",
+		   indirect.idx, indirect.start,
+		   indirect.end, indirect.discard );
+
+	if ( indirect.idx < 0 || indirect.idx >= dma->buf_count ) {
+		DRM_ERROR( "buffer index %d (of %d max)\n",
+			   indirect.idx, dma->buf_count - 1 );
+		return -EINVAL;
+	}
+
+	buf = dma->buflist[indirect.idx];
+	buf_priv = buf->dev_private;
+
+	if ( buf->pid != current->pid ) {
+		DRM_ERROR( "process %d using buffer owned by %d\n",
+			   current->pid, buf->pid );
+		return -EINVAL;
+	}
+	if ( buf->pending ) {
+		DRM_ERROR( "sending pending buffer %d\n", indirect.idx );
+		return -EINVAL;
+	}
+
+	if ( indirect.start < buf->used ) {
+		DRM_ERROR( "reusing indirect: start=0x%x actual=0x%x\n",
+			   indirect.start, buf->used );
+		return -EINVAL;
+	}
+
+	RING_SPACE_TEST_WITH_RETURN( dev_priv );
+	VB_AGE_TEST_WITH_RETURN( dev_priv );
+
+	buf->used = indirect.end;
+	buf_priv->discard = indirect.discard;
+
+#if 0
+	/* Wait for the 3D stream to idle before the indirect buffer
+	 * containing 2D acceleration commands is processed.
 	 */
-	return -EINVAL;
+	BEGIN_RING( 2 );
+	RADEON_WAIT_UNTIL_3D_IDLE();
+	ADVANCE_RING();
+#endif
+
+	/* Dispatch the indirect buffer full of commands from the
+	 * X server.  This is insecure and is thus only available to
+	 * privileged clients.
+	 */
+	r128_cce_dispatch_indirect( dev, buf, indirect.start, indirect.end );
+
+	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/radeon_cp.c linux-2.4.20/drivers/char/drm/radeon_cp.c
--- linux-2.4.19/drivers/char/drm/radeon_cp.c	2001-09-14 21:29:41.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/radeon_cp.c	2002-10-29 11:18:34.000000000 +0000
@@ -28,7 +28,6 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "radeon.h"
 #include "drmP.h"
 #include "radeon_drv.h"
@@ -623,8 +622,8 @@
 
 		RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR,
 			     entry->busaddr[page_ofs]);
-		DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n",
-			   entry->busaddr[page_ofs],
+		DRM_DEBUG( "ring rptr: offset=0x%08llx handle=0x%08lx\n",
+			   (u64)entry->busaddr[page_ofs],
 			   entry->handle + tmp_ofs );
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/radeon_drv.h linux-2.4.20/drivers/char/drm/radeon_drv.h
--- linux-2.4.19/drivers/char/drm/radeon_drv.h	2001-08-27 14:40:33.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/radeon_drv.h	2002-10-29 11:18:48.000000000 +0000
@@ -660,7 +660,7 @@
 		DRM_ERROR( "ring space check failed!\n" );		\
 		return -EBUSY;						\
 	}								\
- __ring_space_done:							\
+ __ring_space_done: ;							\
 } while (0)
 
 #define VB_AGE_TEST_WITH_RETURN( dev_priv )				\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/radeon_state.c linux-2.4.20/drivers/char/drm/radeon_state.c
--- linux-2.4.19/drivers/char/drm/radeon_state.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/radeon_state.c	2002-10-29 11:18:35.000000000 +0000
@@ -27,7 +27,6 @@
  *    Kevin E. Martin <martin@valinux.com>
  */
 
-#define __NO_VERSION__
 #include "radeon.h"
 #include "drmP.h"
 #include "radeon_drv.h"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/sis_drm.h linux-2.4.20/drivers/char/drm/sis_drm.h
--- linux-2.4.19/drivers/char/drm/sis_drm.h	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/sis_drm.h	2002-10-29 11:18:51.000000000 +0000
@@ -6,7 +6,7 @@
   int context;
   unsigned int offset;
   unsigned int size;
-  unsigned int free;
+  unsigned long free;
 } drm_sis_mem_t;
 
 typedef struct {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/sis_ds.c linux-2.4.20/drivers/char/drm/sis_ds.c
--- linux-2.4.19/drivers/char/drm/sis_ds.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/sis_ds.c	2002-10-29 11:18:35.000000000 +0000
@@ -28,7 +28,6 @@
  * 
  */
 
-#define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
@@ -50,15 +49,16 @@
   set_t *set;
 
   set = (set_t *)MALLOC(sizeof(set_t));
-  for(i = 0; i < SET_SIZE; i++){
-    set->list[i].free_next = i+1;    
-    set->list[i].alloc_next = -1;
-  }    
-  set->list[SET_SIZE-1].free_next = -1;
-  set->free = 0;
-  set->alloc = -1;
-  set->trace = -1;
-  
+  if (set) {
+    for(i = 0; i < SET_SIZE; i++){
+      set->list[i].free_next = i+1;    
+      set->list[i].alloc_next = -1;
+    }    
+    set->list[SET_SIZE-1].free_next = -1;
+    set->free = 0;
+    set->alloc = -1;
+    set->trace = -1;
+  }
   return set;
 }
 
@@ -172,7 +172,8 @@
 {
   void *addr;
   addr = kmalloc(nmemb*size, GFP_KERNEL);
-  memset(addr, 0, nmemb*size);
+  if (addr)
+    memset(addr, 0, nmemb*size);
   return addr;
 }
 #define free(n) kfree(n)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm/sis_mm.c linux-2.4.20/drivers/char/drm/sis_mm.c
--- linux-2.4.19/drivers/char/drm/sis_mm.c	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.20/drivers/char/drm/sis_mm.c	2002-10-29 11:18:49.000000000 +0000
@@ -28,7 +28,6 @@
  * 
  */
 
-#define __NO_VERSION__
 #include "sis.h"
 #include <linux/sisfb.h>
 #include "drmP.h"
@@ -125,7 +124,7 @@
   if(!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
     retval = -1;
 
-  DRM_DEBUG("free fb, offset = %d\n", fb.free);
+  DRM_DEBUG("free fb, offset = %ld\n", fb.free);
   
   return retval;
 }
@@ -183,7 +182,7 @@
   if(block){
     /* TODO */
     agp.offset = block->ofs;
-    agp.free = (unsigned int)block;
+    agp.free = (unsigned long)block;
     if(!add_alloc_set(agp.context, AGP_TYPE, agp.free)){
       DRM_DEBUG("adding to allocation set fails\n");
       mmFreeMem((PMemBlock)agp.free);
@@ -223,7 +222,7 @@
   if(!del_alloc_set(agp.context, AGP_TYPE, agp.free))
     retval = -1;
 
-  DRM_DEBUG("free agp, free = %d\n", agp.free);
+  DRM_DEBUG("free agp, free = %ld\n", agp.free);
   
   return retval;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm-4.0/ffb_drv.c linux-2.4.20/drivers/char/drm-4.0/ffb_drv.c
--- linux-2.4.19/drivers/char/drm-4.0/ffb_drv.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.20/drivers/char/drm-4.0/ffb_drv.c	2002-10-29 11:18:48.000000000 +0000
@@ -710,8 +710,7 @@
 		/* Contention */
 		atomic_inc(&dev->total_sleeps);
 		current->state = TASK_INTERRUPTIBLE;
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		if (signal_pending(current)) {
 			ret = -ERESTARTSYS;
 			break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm-4.0/i810_dma.c linux-2.4.20/drivers/char/drm-4.0/i810_dma.c
--- linux-2.4.19/drivers/char/drm-4.0/i810_dma.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/drm-4.0/i810_dma.c	2002-10-29 11:18:48.000000000 +0000
@@ -83,7 +83,7 @@
 	*(volatile unsigned int *)(virt + outring) = n;			\
 	outring += 4;							\
 	outring &= ringmask;						\
-} while (0);
+} while (0)
 
 static inline void i810_print_status_page(drm_device_t *dev)
 {
@@ -279,7 +279,7 @@
 	address = __get_free_page(GFP_KERNEL);
 	if(address == 0UL) 
 		return 0;
-	
+
 	get_page(virt_to_page(address));
 	LockPage(virt_to_page(address));
    
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/drm-4.0/tdfx_drv.c linux-2.4.20/drivers/char/drm-4.0/tdfx_drv.c
--- linux-2.4.19/drivers/char/drm-4.0/tdfx_drv.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.20/drivers/char/drm-4.0/tdfx_drv.c	2002-10-29 11:18:33.000000000 +0000
@@ -578,10 +578,7 @@
 
                                 /* Contention */
                         atomic_inc(&dev->total_sleeps);
-#if 1
-			current->policy |= SCHED_YIELD;
-#endif
-                        schedule();
+			yield();
                         if (signal_pending(current)) {
                                 ret = -ERESTARTSYS;
                                 break;
@@ -604,8 +601,7 @@
                    when dev->last_context == lock.context
                    NOTE WE HOLD THE LOCK THROUGHOUT THIS
                    TIME! */
-		current->policy |= SCHED_YIELD;
-	        schedule();
+		yield();
 	        current->state = TASK_RUNNING;
 	        remove_wait_queue(&dev->context_wait, &entry);
 	        if (signal_pending(current)) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/efirtc.c linux-2.4.20/drivers/char/efirtc.c
--- linux-2.4.19/drivers/char/efirtc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/efirtc.c	2002-10-29 11:18:49.000000000 +0000
@@ -35,8 +35,8 @@
 #include <linux/init.h>
 #include <linux/rtc.h>
 #include <linux/proc_fs.h>
+#include <linux/efi.h>
 
-#include <asm/efi.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/eurotechwdt.c linux-2.4.20/drivers/char/eurotechwdt.c
--- linux-2.4.19/drivers/char/eurotechwdt.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/eurotechwdt.c	2002-10-29 11:18:33.000000000 +0000
@@ -35,6 +35,9 @@
  *
  * 2001 - Rodolfo Giometti
  *	Initial release
+ *
+ * 2002.05.30 - Joel Becker <joel.becker@oracle.com>
+ * 	Added Matt Domsch's nowayout module option.
  */
 
 #include <linux/config.h>
@@ -68,6 +71,14 @@
  
 #define WDT_TIMEOUT		60                /* 1 minute */
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
 /*
  * Some symbolic names 
@@ -127,48 +138,48 @@
 
 static inline void eurwdt_write_reg(u8 index, u8 data)
 {
-   outb(index, io);
-   outb(data, io+1);
+	outb(index, io);
+	outb(data, io+1);
 }
 
 static inline void eurwdt_lock_chip(void)
 {
-   outb(0xaa, io);
+	outb(0xaa, io);
 }
 
 static inline void eurwdt_unlock_chip(void)
 {
-   outb(0x55, io);
-   eurwdt_write_reg(0x07, 0x08);   /* set the logical device */
+	outb(0x55, io);
+	eurwdt_write_reg(0x07, 0x08);   /* set the logical device */
 }
 
 static inline void eurwdt_set_timeout(int timeout)
 {
-   eurwdt_write_reg(WDT_TIMEOUT_VAL, (u8) timeout);
+	eurwdt_write_reg(WDT_TIMEOUT_VAL, (u8) timeout);
 }
 
 static inline void eurwdt_disable_timer(void)
 {
-   eurwdt_set_timeout(0);
+	eurwdt_set_timeout(0);
 }
  
 static void eurwdt_activate_timer(void)
 {
-   eurwdt_disable_timer();
-   eurwdt_write_reg(WDT_CTRL_REG, 0x01);      /* activate the WDT */
-   eurwdt_write_reg(WDT_OUTPIN_CFG, !strcmp("int", ev) ?
+	eurwdt_disable_timer();
+	eurwdt_write_reg(WDT_CTRL_REG, 0x01);      /* activate the WDT */
+	eurwdt_write_reg(WDT_OUTPIN_CFG, !strcmp("int", ev) ?
                                     WDT_EVENT_INT : WDT_EVENT_REBOOT);
-   /* Setting interrupt line */
-   if (irq == 2 || irq > 15 || irq < 0) {
-      printk(KERN_ERR ": invalid irq number\n");
-      irq = 0;   /* if invalid we disable interrupt */
-   }
-   if (irq == 0)
-      printk(KERN_INFO ": interrupt disabled\n");
-   eurwdt_write_reg(WDT_TIMER_CFG, irq<<4);
+	/* Setting interrupt line */
+	if (irq == 2 || irq > 15 || irq < 0) {
+		printk(KERN_ERR ": invalid irq number\n");
+		irq = 0;   /* if invalid we disable interrupt */
+	}
+	if (irq == 0)
+		printk(KERN_INFO ": interrupt disabled\n");
+	eurwdt_write_reg(WDT_TIMER_CFG, irq<<4);
 
-   eurwdt_write_reg(WDT_UNIT_SEL, WDT_UNIT_SECS);   /* we use seconds */
-   eurwdt_set_timeout(0);                           /* the default timeout */ 
+	eurwdt_write_reg(WDT_UNIT_SEL, WDT_UNIT_SECS);   /* we use seconds */
+	eurwdt_set_timeout(0);                           /* the default timeout */ 
 }
 
 
@@ -178,13 +189,13 @@
  
 void eurwdt_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-   printk(KERN_CRIT "timeout WDT timeout\n");
+	printk(KERN_CRIT "timeout WDT timeout\n");
  
 #ifdef ONLY_TESTING
-   printk(KERN_CRIT "Would Reboot.\n");
+	printk(KERN_CRIT "Would Reboot.\n");
 #else
-   printk(KERN_CRIT "Initiating system reboot.\n");
-   machine_restart(NULL);
+	printk(KERN_CRIT "Initiating system reboot.\n");
+	machine_restart(NULL);
 #endif
 }
 
@@ -197,8 +208,8 @@
  
 static void eurwdt_ping(void)
 {
-   /* Write the watchdog default value */
-   eurwdt_set_timeout(eurwdt_timeout);
+	/* Write the watchdog default value */
+	eurwdt_set_timeout(eurwdt_timeout);
 }
  
 /**
@@ -212,28 +223,29 @@
  *      write of data will do, as we we don't define content meaning.
  */
  
-static ssize_t eurwdt_write(struct file *file, const char *buf, size_t count,
-loff_t *ppos)
+static ssize_t eurwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
-   /*  Can't seek (pwrite) on this device  */
-   if (ppos != &file->f_pos)
-      return -ESPIPE;
- 
-   if (count) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-      size_t i;
-
-      eur_expect_close = 0;
-
-      for (i = 0; i != count; i++) {
-         if (buf[i] == 'V')
-            eur_expect_close = 42;
-      }
-#endif
-      eurwdt_ping();   /* the default timeout */
-   }
-
-   return count;
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+ 
+	if (count) {
+		if (!nowayout) {
+			size_t i;
+
+			eur_expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if(get_user(c, buf+i))
+					return -EFAULT;
+				if (c == 'V')
+					eur_expect_close = 42;
+			}
+		}
+		eurwdt_ping();   /* the default timeout */
+	}
+	return count;
 }
 
 /**
@@ -250,66 +262,54 @@
 static int eurwdt_ioctl(struct inode *inode, struct file *file,
         unsigned int cmd, unsigned long arg)
 {
-   static struct watchdog_info ident = {
-      options		: WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
-      firmware_version	: 0,
-      identity		: "WDT Eurotech CPU-1220/1410"
-   };
-
-   int time;
- 
-   switch(cmd) {
-      default:
-         return -ENOTTY;
-
-      case WDIOC_GETSUPPORT:
-         return copy_to_user((struct watchdog_info *)arg, &ident,
-               sizeof(ident)) ? -EFAULT : 0;
- 
-      case WDIOC_GETSTATUS:
-      case WDIOC_GETBOOTSTATUS:
-         return put_user(0, (int *) arg);
-
-      case WDIOC_KEEPALIVE:
-         eurwdt_ping();
-         return 0;
-
-      case WDIOC_SETTIMEOUT:
-         if (copy_from_user(&time, (int *) arg, sizeof(int)))
-            return -EFAULT;
-
-         /* Sanity check */
-         if (time < 0 || time > 255)
-            return -EINVAL;
-
-         eurwdt_timeout = time; 
-         eurwdt_set_timeout(time); 
-	 /* Fall */
-
-      case WDIOC_GETTIMEOUT:
-	 return put_user(eurwdt_timeout, (int *)arg);
-
-      case WDIOC_SETOPTIONS:
-      {
-	 int options, retval = -EINVAL;
-
-	 if (get_user(options, (int *)arg))
-	    return -EFAULT;
-
-	 if (options & WDIOS_DISABLECARD) {
-	    eurwdt_disable_timer();
-	    retval = 0;
-	 }
-
-	 if (options & WDIOS_ENABLECARD) {
-	    eurwdt_activate_timer();
-	    eurwdt_ping();
-	    retval = 0;
-	 }
-
-	 return retval;
-      }
-   }
+	static struct watchdog_info ident = {
+		options		: WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+		firmware_version	: 0,
+		identity		: "WDT Eurotech CPU-1220/1410"
+	};
+	int time;
+ 
+	switch(cmd) {
+		default:
+			return -ENOTTY;
+		case WDIOC_GETSUPPORT:
+			return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)) ? -EFAULT : 0;
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, (int *) arg);
+		case WDIOC_KEEPALIVE:
+			eurwdt_ping();
+			return 0;
+		case WDIOC_SETTIMEOUT:
+			if (copy_from_user(&time, (int *) arg, sizeof(int)))
+				return -EFAULT;
+			/* Sanity check */
+			if (time < 0 || time > 255)
+				return -EINVAL;
+			eurwdt_timeout = time; 
+			eurwdt_set_timeout(time); 
+			/* Fall */
+		case WDIOC_GETTIMEOUT:
+			return put_user(eurwdt_timeout, (int *)arg);
+		case WDIOC_SETOPTIONS:
+		{
+			int options, retval = -EINVAL;
+
+			if (get_user(options, (int *)arg))
+				return -EFAULT;
+			if (options & WDIOS_DISABLECARD) {
+				eurwdt_disable_timer();
+				retval = 0;
+			}
+
+			if (options & WDIOS_ENABLECARD) {
+				eurwdt_activate_timer();
+				eurwdt_ping();
+				retval = 0;
+			}
+			return retval;
+		}
+	}
 }
 
 /**
@@ -323,15 +323,15 @@
  
 static int eurwdt_open(struct inode *inode, struct file *file)
 {
-   if (test_and_set_bit(0, &eurwdt_is_open))
-      return -EBUSY;
+	if (test_and_set_bit(0, &eurwdt_is_open))
+		return -EBUSY;
 
-   eurwdt_timeout = WDT_TIMEOUT;   /* initial timeout */
+	eurwdt_timeout = WDT_TIMEOUT;   /* initial timeout */
 
-   /* Activate the WDT */
-   eurwdt_activate_timer(); 
+	/* Activate the WDT */
+	eurwdt_activate_timer(); 
 
-   return 0;
+	return 0;
 }
  
 /**
@@ -348,16 +348,15 @@
  
 static int eurwdt_release(struct inode *inode, struct file *file)
 {
-   if (eur_expect_close == 42) {
-      eurwdt_disable_timer();
-   } else {
-      printk(KERN_CRIT "eurwdt: Unexpected close, not stopping watchdog!\n");
-      eurwdt_ping();
-   }
-   clear_bit(0, &eurwdt_is_open);
-   eur_expect_close = 0;
-
-   return 0;
+	if (eur_expect_close == 42) {
+		eurwdt_disable_timer();
+	} else {
+		printk(KERN_CRIT "eurwdt: Unexpected close, not stopping watchdog!\n");
+		eurwdt_ping();
+	}
+	clear_bit(0, &eurwdt_is_open);
+	eur_expect_close = 0;
+	return 0;
 }
  
 /**
@@ -375,12 +374,11 @@
 static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code,
         void *unused)
 {
-   if (code == SYS_DOWN || code == SYS_HALT) {
-      /* Turn the card off */
-      eurwdt_disable_timer();
-   }
-
-   return NOTIFY_DONE;
+	if (code == SYS_DOWN || code == SYS_HALT) {
+		/* Turn the card off */
+		eurwdt_disable_timer();
+	}
+	return NOTIFY_DONE;
 }
  
 /*
@@ -428,13 +426,11 @@
  
 static void __exit eurwdt_exit(void)
 {
-   eurwdt_lock_chip();
-
-   misc_deregister(&eurwdt_miscdev);
-
-   unregister_reboot_notifier(&eurwdt_notifier);
-   release_region(io, 2);
-   free_irq(irq, NULL);
+	eurwdt_lock_chip();
+	misc_deregister(&eurwdt_miscdev);
+	unregister_reboot_notifier(&eurwdt_notifier);
+	release_region(io, 2);
+	free_irq(irq, NULL);
 }
  
 /**
@@ -447,52 +443,44 @@
  
 static int __init eurwdt_init(void)
 {
-   int ret;
- 
-   ret = misc_register(&eurwdt_miscdev);
-   if (ret) {
-      printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
-            WATCHDOG_MINOR);
-      goto out;
-   }
-
-   ret = request_irq(irq, eurwdt_interrupt, SA_INTERRUPT, "eurwdt", NULL);
-   if(ret) {
-      printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq);
-      goto outmisc;
-   }
-
-   if (!request_region(io, 2, "eurwdt")) {
-       printk(KERN_ERR "eurwdt: IO %X is not free.\n", io);
-       ret = -EBUSY;
-       goto outirq;
-   }
-
-   ret = register_reboot_notifier(&eurwdt_notifier);
-   if (ret) {
-      printk(KERN_ERR "eurwdt: can't register reboot notifier (err=%d)\n", ret);
-      goto outreg;
-   }
-
-   eurwdt_unlock_chip();
+	int ret;
  
-   ret = 0;
-   printk(KERN_INFO "Eurotech WDT driver 0.01 at %X (Interrupt %d)"
-                    " - timeout event: %s\n", 
-         io, irq, (!strcmp("int", ev) ? "int" : "reboot"));
-
-   out:
-      return ret;
- 
-   outreg:
-      release_region(io, 2);
-
-   outirq:
-      free_irq(irq, NULL);
-
-   outmisc:
-      misc_deregister(&eurwdt_miscdev);
-      goto out;
+	ret = misc_register(&eurwdt_miscdev);
+	if (ret) {
+		printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n", WATCHDOG_MINOR);
+		goto out;
+	}
+	ret = request_irq(irq, eurwdt_interrupt, SA_INTERRUPT, "eurwdt", NULL);
+	if(ret) {
+		printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq);
+		goto outmisc;
+	}
+
+	if (!request_region(io, 2, "eurwdt")) {
+		printk(KERN_ERR "eurwdt: IO %X is not free.\n", io);
+		ret = -EBUSY;
+		goto outirq;
+	}
+
+	ret = register_reboot_notifier(&eurwdt_notifier);
+	if (ret) {
+		printk(KERN_ERR "eurwdt: can't register reboot notifier (err=%d)\n", ret);
+		goto outreg;
+	}
+	eurwdt_unlock_chip();
+ 
+	ret = 0;
+	printk(KERN_INFO "Eurotech WDT driver 0.01 at %X (Interrupt %d)"
+                    " - timeout event: %s\n",  io, irq, (!strcmp("int", ev) ? "int" : "reboot"));
+	return ret;
+outreg:
+	release_region(io, 2);
+outirq:
+	free_irq(irq, NULL);
+outmisc:
+	misc_deregister(&eurwdt_miscdev);
+out:
+	return ret;
 }
  
 module_init(eurwdt_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/ftape/Config.in linux-2.4.20/drivers/char/ftape/Config.in
--- linux-2.4.19/drivers/char/ftape/Config.in	2000-01-24 19:04:37.000000000 +0000
+++ linux-2.4.20/drivers/char/ftape/Config.in	2002-10-29 11:18:34.000000000 +0000
@@ -35,7 +35,7 @@
    int '  Maximal data rate to use (EXPERIMENTAL)' CONFIG_FT_FDC_MAX_RATE 2000
 fi
 
-if [ "$ARCH" = "alpha" ]; then
+if [ "$CONFIG_ALPHA" = "y" ]; then
    int '  CPU clock frequency of your DEC Alpha' CONFIG_FT_ALPHA_CLOCK 0
 else
    define_int CONFIG_FT_ALPHA_CLOCK 0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/ftape/lowlevel/ftape-calibr.c linux-2.4.20/drivers/char/ftape/lowlevel/ftape-calibr.c
--- linux-2.4.19/drivers/char/ftape/lowlevel/ftape-calibr.c	2001-09-14 21:40:00.000000000 +0000
+++ linux-2.4.20/drivers/char/ftape/lowlevel/ftape-calibr.c	2002-10-29 11:18:35.000000000 +0000
@@ -31,7 +31,10 @@
 #include <asm/io.h>
 #if defined(__alpha__)
 # include <asm/hwrpb.h>
-#elif defined(__i386__) || defined(__x86_64__)
+#elif defined(__x86_64__)
+# include <asm/msr.h>
+# include <asm/timex.h>
+#elif defined(__i386__) 
 # include <linux/timex.h>
 #endif
 #include <linux/ftape.h>
@@ -45,10 +48,14 @@
 # error Ftape is not implemented for this architecture!
 #endif
 
-#if defined(__alpha__)
+#if defined(__alpha__) || defined(__x86_64__)
 static unsigned long ps_per_cycle = 0;
 #endif
 
+#if defined(__i386__)
+extern spinlock_t i8253_lock;
+#endif
+
 /*
  * Note: On Intel PCs, the clock ticks at 100 Hz (HZ==100) which is
  * too slow for certain timeouts (and that clock doesn't even tick
@@ -67,48 +74,58 @@
 {
 #if defined(__alpha__)
 	unsigned long r;
-
 	asm volatile ("rpcc %0" : "=r" (r));
 	return r;
-#elif defined(__i386__) || defined(__x86_64__)
+#elif defined(__x86_64__)
+	unsigned long r;
+	rdtscl(r);
+	return r;
+#elif defined(__i386__)
+
+/*
+ * Note that there is some time between counter underflowing and jiffies
+ * increasing, so the code below won't always give correct output.
+ * -Vojtech
+ */
+
 	unsigned long flags;
 	__u16 lo;
 	__u16 hi;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&i8253_lock, flags); 
 	outb_p(0x00, 0x43);	/* latch the count ASAP */
 	lo = inb_p(0x40);	/* read the latched count */
 	lo |= inb(0x40) << 8;
 	hi = jiffies;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&i8253_lock, flags); 
+
 	return ((hi + 1) * (unsigned int) LATCH) - lo;  /* downcounter ! */
 #endif
 }
 
 static unsigned int short_ftape_timestamp(void)
 {
-#if defined(__alpha__)
+#if defined(__alpha__) || defined(__x86_64__)
 	return ftape_timestamp();
-#elif defined(__i386__) || defined(__x86_64__)
+#elif defined(__i386__)
 	unsigned int count;
  	unsigned long flags;
  
- 	save_flags(flags);
- 	cli();
+	spin_lock_irqsave(&i8253_lock, flags); 
  	outb_p(0x00, 0x43);	/* latch the count ASAP */
 	count = inb_p(0x40);	/* read the latched count */
 	count |= inb(0x40) << 8;
- 	restore_flags(flags);
+	spin_unlock_irqrestore(&i8253_lock, flags); 
+
 	return (LATCH - count);	/* normal: downcounter */
 #endif
 }
 
 static unsigned int diff(unsigned int t0, unsigned int t1)
 {
-#if defined(__alpha__)
-	return (t1 <= t0) ? t1 + (1UL << 32) - t0 : t1 - t0;
-#elif defined(__i386__) || defined(__x86_64__)
+#if defined(__alpha__) || defined(__x86_64__)
+	return (t1 - t0);
+#elif defined(__i386__)
 	/*
 	 * This is tricky: to work for both short and full ftape_timestamps
 	 * we'll have to discriminate between these.
@@ -122,9 +139,9 @@
 
 static unsigned int usecs(unsigned int count)
 {
-#if defined(__alpha__)
+#if defined(__alpha__) || defined(__x86_64__)
 	return (ps_per_cycle * count) / 1000000UL;
-#elif defined(__i386__) || defined(__x86_64__)
+#elif defined(__i386__)
 	return (10000 * count) / ((CLOCK_TICK_RATE + 50) / 100);
 #endif
 }
@@ -153,49 +170,24 @@
 	save_flags(flags);
 	cli();
 	t0 = short_ftape_timestamp();
-	for (i = 0; i < 1000; ++i) {
+	for (i = 0; i < 1000; ++i)
 		status = inb(fdc.msr);
-	}
 	t1 = short_ftape_timestamp();
 	restore_flags(flags);
+
 	TRACE(ft_t_info, "inb() duration: %d nsec", ftape_timediff(t0, t1));
 	TRACE_EXIT;
 }
 
 static void init_clock(void)
 {
-#if defined(__i386__) || defined(__x86_64__)
-	unsigned int t;
-	int i;
 	TRACE_FUN(ft_t_any);
 
-	/*  Haven't studied on why, but there sometimes is a problem
-	 *  with the tick timer readout. The two bytes get swapped.
-	 *  This hack solves that problem by doing one extra input.
-	 */
-	for (i = 0; i < 1000; ++i) {
-		t = short_ftape_timestamp();
-		if (t > LATCH) {
-			inb_p(0x40);	/* get in sync again */
-			TRACE(ft_t_warn, "clock counter fixed");
-			break;
-		}
-	}
+#if defined(__x86_64__)
+	ps_per_cycle = 1000000000UL / cpu_khz;
 #elif defined(__alpha__)
-#if CONFIG_FT_ALPHA_CLOCK == 0
-#error You must define and set CONFIG_FT_ALPHA_CLOCK in 'make config' !
-#endif
 	extern struct hwrpb_struct *hwrpb;
-	TRACE_FUN(ft_t_any);
-
-	if (hwrpb->cycle_freq != 0) {
 		ps_per_cycle = (1000*1000*1000*1000UL) / hwrpb->cycle_freq;
-	} else {
-		/*
-		 * HELP:  Linux 2.0.x doesn't set cycle_freq on my noname !
-		 */
-		ps_per_cycle = (1000*1000*1000*1000UL) / CONFIG_FT_ALPHA_CLOCK;
-	}
 #endif
 	TRACE_EXIT;
 }
@@ -214,7 +206,7 @@
 	unsigned int tc = 0;
 	unsigned int count;
 	unsigned int time;
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__)
 	unsigned int old_tc = 0;
 	unsigned int old_count = 1;
 	unsigned int old_time = 1;
@@ -257,15 +249,14 @@
 		tc = (1000 * time) / (count - 1);
 		TRACE(ft_t_any, "once:%3d us,%6d times:%6d us, TC:%5d ns",
 			usecs(once), count - 1, usecs(multiple), tc);
-#if defined(__alpha__)
+#if defined(__alpha__) || defined(__x86_64__)
 		/*
 		 * Increase the calibration count exponentially until the
 		 * calibration time exceeds 100 ms.
 		 */
-		if (time >= 100*1000) {
+		if (time >= 100*1000)
 			break;
-		}
-#elif defined(__i386__) || defined(__x86_64__)
+#elif defined(__i386__)
 		/*
 		 * increase the count until the resulting time nears 2/HZ,
 		 * then the tc will drop sharply because we lose LATCH counts.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/generic_serial.c linux-2.4.20/drivers/char/generic_serial.c
--- linux-2.4.19/drivers/char/generic_serial.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.20/drivers/char/generic_serial.c	2002-10-29 11:18:48.000000000 +0000
@@ -41,8 +41,8 @@
 #define gs_dprintk(f, str...) /* nothing */
 #endif
 
-#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter " __FUNCTION__ "\n")
-#define func_exit()  gs_dprintk (GS_DEBUG_FLOW, "gs: exit  " __FUNCTION__ "\n")
+#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter %s\n", __FUNCTION__)
+#define func_exit()  gs_dprintk (GS_DEBUG_FLOW, "gs: exit  %s\n", __FUNCTION__)
 
 #if NEW_WRITE_LOCKING
 #define DECL      /* Nothing */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/hcdp_serial.c linux-2.4.20/drivers/char/hcdp_serial.c
--- linux-2.4.19/drivers/char/hcdp_serial.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/hcdp_serial.c	2002-10-29 11:18:40.000000000 +0000
@@ -15,9 +15,9 @@
 #include <linux/init.h>
 #include <linux/serial.h>
 #include <linux/serialP.h>
+#include <linux/efi.h>
 #include <asm/serial.h>
 #include <asm/io.h>
-#include <asm/efi.h>
 #include <linux/hcdp_serial.h>
 
 #undef SERIAL_DEBUG_HCDP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/hp_keyb.c linux-2.4.20/drivers/char/hp_keyb.c
--- linux-2.4.19/drivers/char/hp_keyb.c	2001-11-09 22:01:21.000000000 +0000
+++ linux-2.4.20/drivers/char/hp_keyb.c	2002-10-29 11:18:37.000000000 +0000
@@ -176,7 +176,7 @@
 /* 30 */  K_NONE, K_N   , K_B   , K_H   , K_G   , K_Y   , K_6   , K_NONE,
 /* 38 */  K_NONE, K_NONE, K_M   , K_J   , K_U   , K_7   , K_8   , K_NONE,
 /* 40 */  K_NONE, K_COMA, K_K   , K_I   , K_O   , K_0   , K_9   , K_NONE,
-/* 48 */  K_NONE, K_DOT , K_FSLH, K_L   , K_SEMI, K_P   , K_MINS, K_NONE,
+/* 48 */  K_PGUP, K_DOT , K_FSLH, K_L   , K_SEMI, K_P   , K_MINS, K_NONE,
 /* 50 */  K_NONE, K_NONE, K_SQOT, K_NONE, K_LSBK, K_EQLS, K_NONE, K_NONE,
 /* 58 */  K_CAPS, K_RSFT, K_ENTR, K_RSBK, K_NONE, K_BSLH, K_NONE, K_NONE,
 /* 60 */  K_NONE, K_HASH, K_NONE, K_NONE, K_NONE, K_NONE, K_BKSP, K_NONE,
@@ -267,6 +267,12 @@
 #define FOCUS_PF12 123
 
 #define JAP_86     124
+
+/* On one Compaq UK keyboard, at least, bar/backslash generates scancode
+ * 0x7f.  0x7f generated on some .de and .no keyboards also.
+ */
+#define UK_86	   86
+
 /* tfj@olivia.ping.dk:
  * The four keys are located over the numeric keypad, and are
  * labelled A1-A4. It's an rc930 keyboard, from
@@ -284,7 +290,7 @@
   0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12,          /* 0x68-0x6f */
   0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3,    /* 0x70-0x77 */
   FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7,        /* 0x78-0x7b */
-  FOCUS_PF8, JAP_86, FOCUS_PF10, 0                   /* 0x7c-0x7f */
+  FOCUS_PF8, JAP_86, FOCUS_PF10, UK_86               /* 0x7c-0x7f */
 };
 
 /* BTC */
@@ -327,7 +333,7 @@
   0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x60-0x67 */
   0, 0, 0, 0, 0, 0, 0, E0_MACRO,		      /* 0x68-0x6f */
   0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x70-0x77 */
-  0, 0, 0, 0, 0, 0, 0, 0			      /* 0x78-0x7f */
+  0, 0, 0, 0, 0, 0, 0, E0_MSLW			      /* 0x78-0x7f */
 };
 
 int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/hp_psaux.c linux-2.4.20/drivers/char/hp_psaux.c
--- linux-2.4.19/drivers/char/hp_psaux.c	2001-11-09 22:01:21.000000000 +0000
+++ linux-2.4.20/drivers/char/hp_psaux.c	2002-10-29 11:18:50.000000000 +0000
@@ -6,18 +6,16 @@
  *	Copyright 1999, 2000 Philipp Rumpf <prumpf@tux.org>
  *
  *	2000/10/26	Debacker Xavier (debackex@esiee.fr)
+ *	implemented the psaux and controlled the mouse scancode based on pc_keyb.c
  *			Marteau Thomas (marteaut@esiee.fr)
- * 			Djoudi Malek (djoudim@esiee.fr)
  *	fixed leds control
- *	implemented the psaux and controlled the mouse scancode based on pc_keyb.c
+ *
+ *	2001/12/17	Marteau Thomas (marteaut@esiee.fr)
+ *	get nice initialisation procedure
  */
 
 #include <linux/config.h>
 
-#include <asm/hardware.h>
-#include <asm/keyboard.h>
-#include <asm/gsc.h>
-
 #include <linux/types.h>
 #include <linux/ptrace.h>	/* interrupt.h wants struct pt_regs defined */
 #include <linux/interrupt.h>
@@ -28,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/module.h>
 #include <linux/pc_keyb.h>
 #include <linux/kbd_kern.h>
 
@@ -37,11 +36,16 @@
 #include <linux/random.h>
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
-#include <asm/uaccess.h>
 #include <linux/poll.h>
 
+#include <asm/hardware.h>
+#include <asm/keyboard.h>
+#include <asm/gsc.h>
+#include <asm/uaccess.h>
+
 /* HP specific LASI PS/2 keyboard and psaux constants */
 #define	AUX_REPLY_ACK	0xFA	/* Command byte ACK. */
+#define	AUX_RESEND	0xFE	/* Sent by the keyb. Asking for resending the last command. */
 #define	AUX_RECONNECT	0xAA	/* scancode when ps2 device is plugged (back) in */
 
 #define	LASI_PSAUX_OFFSET 0x0100 /* offset from keyboard to psaux port */
@@ -69,50 +73,63 @@
 #define LASI_STAT_DATSHD 0x40
 #define LASI_STAT_CLKSHD 0x80
 
-static void *lasikbd_hpa;
-static void *lasips2_hpa;
+static spinlock_t	kbd_controller_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long lasikbd_hpa;
 
+static volatile int cmd_status;
 
-static inline u8 read_input(void *hpa)
+static inline u8 read_input(unsigned long hpa)
 {
 	return gsc_readb(hpa+LASI_RCVDATA);
 }
 
-static inline u8 read_control(void *hpa)
+static inline u8 read_control(unsigned long hpa)
 {
         return gsc_readb(hpa+LASI_CONTROL);
 }
 
-static inline void write_control(u8 val, void *hpa)
+static inline void write_control(u8 val, unsigned long hpa)
 {
 	gsc_writeb(val, hpa+LASI_CONTROL);
 }
 
-static inline u8 read_status(void *hpa)
+static inline u8 read_status(unsigned long hpa)
 {
         return gsc_readb(hpa+LASI_STATUS);
 }
 
-static int write_output(u8 val, void *hpa)
+/* XXX should this grab the spinlock? */
+
+static int write_output(u8 val, unsigned long hpa)
 {
-	int wait = 0;
+	int wait = 250;
 
 	while (read_status(hpa) & LASI_STAT_TBNE) {
-		wait++;
-		if (wait>10000) {
-			/* printk(KERN_WARNING "Lasi PS/2 transmit buffer timeout\n"); */
+		if (!--wait) {
 			return 0;
 		}
+		mdelay(1);
 	}
-
-	if (wait)
-		printk(KERN_DEBUG "Lasi PS/2 wait %d\n", wait);
-	
 	gsc_writeb(val, hpa+LASI_XMTDATA);
 
 	return 1;
 }
 
+/* XXX should this grab the spinlock? */
+
+static u8 wait_input(unsigned long hpa)
+{
+	int wait = 250;
+
+	while (!(read_status(hpa) & LASI_STAT_RBNE)) {
+		if (!--wait) {
+			return 0;
+		}
+		mdelay(1);
+	}
+	return read_input(hpa);      
+}
+
 /* This function is the PA-RISC adaptation of i386 source */
 
 static inline int aux_write_ack(u8 val)
@@ -120,11 +137,37 @@
       return write_output(val, lasikbd_hpa+LASI_PSAUX_OFFSET);
 }
 
+/* This is wrong, should do something like the pc driver, which sends
+ * the command up to 3 times at 1 second intervals, checking once
+ * per millisecond for an acknowledge.
+ */
+
 static void lasikbd_leds(unsigned char leds)
 {
-	write_output(KBD_CMD_SET_LEDS, lasikbd_hpa);
-	write_output(leds, lasikbd_hpa);
-	write_output(KBD_CMD_ENABLE, lasikbd_hpa);
+	int loop = 1000;
+
+	if (!lasikbd_hpa)
+		return;
+
+	cmd_status=2;
+	while (cmd_status!=0 && --loop > 0) {
+		write_output(KBD_CMD_SET_LEDS, lasikbd_hpa);
+		mdelay(5); 
+	}
+   
+	cmd_status=2;
+	while (cmd_status!=0 && --loop > 0) {
+		write_output(leds, lasikbd_hpa);
+		mdelay(5);
+	}
+
+	cmd_status=2;
+	while (cmd_status!=0 && --loop > 0) {
+	   write_output(KBD_CMD_ENABLE, lasikbd_hpa);   
+	   mdelay(5);
+	}
+	if (loop <= 0)
+		printk("lasikbd_leds: timeout\n");
 }
 
 #if 0
@@ -154,10 +197,30 @@
 }
 #endif 
 
-static int __init lasi_ps2_reset(void *hpa, int id)
+static int init_keyb(unsigned long hpa)
+{
+	int res = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&kbd_controller_lock, flags);
+
+	if (write_output(KBD_CMD_SET_LEDS, hpa) &&
+			wait_input(hpa) == AUX_REPLY_ACK &&
+			write_output(0, hpa) &&
+			wait_input(hpa) == AUX_REPLY_ACK &&
+			write_output(KBD_CMD_ENABLE, hpa) &&
+			wait_input(hpa) == AUX_REPLY_ACK)
+		res = 1;
+
+	spin_unlock_irqrestore(&kbd_controller_lock, flags);
+
+	return res;
+}
+
+
+static void __init lasi_ps2_reset(unsigned long hpa)
 {
 	u8 control;
-	int ret = 1;
 
 	/* reset the interface */
 	gsc_writeb(0xff, hpa+LASI_RESET);
@@ -166,25 +229,8 @@
 	/* enable it */
 	control = read_control(hpa);
 	write_control(control | LASI_CTRL_ENBL, hpa);
-
-        /* initializes the leds at the default state */
-        if (id==0) {
-           write_output(KBD_CMD_SET_LEDS, hpa);
-	   write_output(0, hpa);
-	   ret = write_output(KBD_CMD_ENABLE, hpa);
-	}
-
-	return ret;
-}
-
-static int inited;
-
-static void lasi_ps2_init_hw(void)
-{
-	++inited;
 }
 
-
 /* Greatly inspired by pc_keyb.c */
 
 /*
@@ -202,7 +248,6 @@
 #ifdef CONFIG_PSMOUSE
 
 static struct aux_queue	*queue;
-static spinlock_t	kbd_controller_lock = SPIN_LOCK_UNLOCKED;
 static unsigned char	mouse_reply_expected;
 static int 		aux_count;
 
@@ -315,7 +360,7 @@
 			schedule();
 			goto repeat;
 		}
-		set_current_state(TASK_RUNNING);
+		current->state = TASK_RUNNING;
 		remove_wait_queue(&queue->proc_list, &wait);
 	}
 	while (i > 0 && !queue_empty()) {
@@ -362,7 +407,7 @@
 	lock_kernel();
 	fasync_aux(-1, file, 0);
 	if (--aux_count) {
-	   unlock_kernel();
+		unlock_kernel();
 		return 0;
 	}
 	unlock_kernel();
@@ -389,7 +434,7 @@
 
 /* This function is looking at the PS2 controller and empty the two buffers */
 
-static u8 handle_lasikbd_event(void *hpa)
+static u8 handle_lasikbd_event(unsigned long hpa)
 {
         u8 status_keyb,status_mouse,scancode,id;
         extern void handle_at_scancode(int); /* in drivers/char/keyb_at.c */
@@ -398,62 +443,64 @@
         id = gsc_readb(hpa+LASI_ID) & 0x0f;
         
         if (id==1) 
-           hpa -= LASI_PSAUX_OFFSET; 
-        lasikbd_hpa = hpa;
-        
-
+		hpa -= LASI_PSAUX_OFFSET; 
+	
         status_keyb = read_status(hpa);
         status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
 
         while ((status_keyb|status_mouse) & LASI_STAT_RBNE){
            
-           while (status_keyb & LASI_STAT_RBNE) {
+		while (status_keyb & LASI_STAT_RBNE) {
 	      
-              scancode = read_input(hpa);
+		scancode = read_input(hpa);
 
-	      /* XXX don't know if this is a valid fix, but filtering
-	       * 0xfa avoids 'unknown scancode' errors on, eg, capslock
-	       * on some keyboards.
-	       */
-	      if (inited && scancode != 0xfa)
-		 handle_at_scancode(scancode); 
+	        /* XXX don't know if this is a valid fix, but filtering
+	         * 0xfa avoids 'unknown scancode' errors on, eg, capslock
+	         * on some keyboards.
+	         */
+	      	      
+		if (scancode == AUX_REPLY_ACK) 
+			cmd_status=0;
+			
+		else if (scancode == AUX_RESEND)
+			cmd_status=1;
+		else 
+			handle_at_scancode(scancode); 
 	      
-	      status_keyb =read_status(hpa);
-           }
+		status_keyb =read_status(hpa);
+		}
 	   
 #ifdef CONFIG_PSMOUSE
-           while (status_mouse & LASI_STAT_RBNE) {
-	      scancode = read_input(hpa+LASI_PSAUX_OFFSET);
-	      handle_mouse_scancode(scancode);
-              status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
-	   }
-           status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
+		while (status_mouse & LASI_STAT_RBNE) {
+			scancode = read_input(hpa+LASI_PSAUX_OFFSET);
+			handle_mouse_scancode(scancode);
+			status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
+		}
+		status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
 #endif /* CONFIG_PSMOUSE */
-           status_keyb = read_status(hpa);
+		status_keyb = read_status(hpa);
         }
 
         tasklet_schedule(&keyboard_tasklet);
         return (status_keyb|status_mouse);
 }
-
-
-
 	
 extern struct pt_regs *kbd_pt_regs;
 
 static void lasikbd_interrupt(int irq, void *dev, struct pt_regs *regs)
 {
-	lasips2_hpa = dev; /* save "hpa" for lasikbd_leds() */
 	kbd_pt_regs = regs;
-	handle_lasikbd_event(lasips2_hpa);
+	handle_lasikbd_event((unsigned long) dev);
 }
 
-
 extern int pckbd_translate(unsigned char, unsigned char *, char);
+extern int pckbd_setkeycode(unsigned int, unsigned int);
+extern int pckbd_getkeycode(unsigned int);
 
 static struct kbd_ops gsc_ps2_kbd_ops = {
-	translate:	pckbd_translate,
-	init_hw:	lasi_ps2_init_hw,
+	setkeycode:     pckbd_setkeycode,
+        getkeycode:     pckbd_getkeycode,
+        translate:	pckbd_translate,
 	leds:		lasikbd_leds,
 #ifdef CONFIG_MAGIC_SYSRQ
 	sysrq_key:	0x54,
@@ -461,13 +508,27 @@
 #endif
 };
 
+
+
+#if 1
+/* XXX: HACK !!!
+ * remove this function and the call in hil_kbd.c 
+ * if hp_psaux.c/hp_keyb.c is converted to the input layer... */
+int register_ps2_keybfuncs(void)
+{
+	gsc_ps2_kbd_ops.leds = NULL;
+	register_kbd_ops(&gsc_ps2_kbd_ops);
+}
+EXPORT_SYMBOL(register_ps2_keybfuncs);
+#endif
+
+
 static int __init
-lasi_ps2_register(struct hp_device *d, struct pa_iodc_driver *dri)
+lasi_ps2_register(struct parisc_device *dev)
 {
-	void *hpa = (void *) d->hpa;
-	unsigned int irq;
+	unsigned long hpa = dev->hpa;
 	char *name;
-	int device_found;
+	int device_found = 0;
 	u8 id;
 
 	id = gsc_readb(hpa+LASI_ID) & 0x0f;
@@ -475,7 +536,7 @@
 	switch (id) {
 	case 0:
 		name = "keyboard";
-		lasikbd_hpa = hpa;
+		lasikbd_hpa = hpa;	/* save "hpa" for lasikbd_leds() */
 		break;
 	case 1:
 		name = "psaux";
@@ -487,21 +548,12 @@
 	}
 	
 	/* reset the PS/2 port */
-	device_found = lasi_ps2_reset(hpa,id);
-
-	/* allocate the irq and memory region for that device */
-	if (!(irq = busdevice_alloc_irq(d)))
-		return -ENODEV;
-		    
-	if (request_irq(irq, lasikbd_interrupt, 0, name, hpa))
-		return -ENODEV;
-	
-	if (!request_mem_region((unsigned long)hpa, LASI_STATUS + 4, name))
-		return -ENODEV;
+	lasi_ps2_reset(hpa);
 
 	switch (id) {
 	case 0:	
-		register_kbd_ops(&gsc_ps2_kbd_ops);
+	        device_found = init_keyb(hpa);
+		if (device_found) register_kbd_ops(&gsc_ps2_kbd_ops);
 		break;
 	case 1:
 #ifdef CONFIG_PSMOUSE
@@ -526,26 +578,42 @@
 #endif
 	} /* of case */
 	
-	printk(KERN_INFO "PS/2 %s controller at 0x%08lx (irq %d) found, "
+	if (device_found) {
+	/* Here we claim only if we have a device attached */   
+		/* allocate the irq and memory region for that device */
+		if (!dev->irq)
+	 	return -ENODEV;
+	   
+	  	if (request_irq(dev->irq, lasikbd_interrupt, 0, name, (void *)hpa))
+	  	return -ENODEV;
+	   
+	  	if (!request_mem_region(hpa, LASI_STATUS + 4, name))
+	  	return -ENODEV;
+	}
+	
+	printk(KERN_INFO "PS/2 %s port at 0x%08lx (irq %d) found, "
 			 "%sdevice attached.\n",
-			name, (unsigned long)hpa, irq,
-			device_found ? "":"no ");
+			name, hpa, dev->irq, device_found ? "":"no ");
 
 	return 0;
 }
 
+static struct parisc_device_id lasi_psaux_tbl[] = {
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 },
+	{ 0, } /* 0 terminated list */
+};
+
+MODULE_DEVICE_TABLE(parisc, lasi_psaux_tbl);
 
-static struct pa_iodc_driver lasi_psaux_drivers_for[] __initdata = {
-	{HPHW_FIO, 0x0, 0,0x00084, 0, 0,
-		DRIVER_CHECK_HWTYPE + DRIVER_CHECK_SVERSION,
-		"Lasi psaux", "generic", (void *) lasi_ps2_register},
-	{ 0, }
+static struct parisc_driver lasi_psaux_driver = {
+	name:		"Lasi psaux",
+	id_table:	lasi_psaux_tbl,
+	probe:		lasi_ps2_register,
 };
 
 static int __init gsc_ps2_init(void) 
 {
-	return pdc_register_driver(lasi_psaux_drivers_for);
+	return register_parisc_driver(&lasi_psaux_driver);
 }
 
 module_init(gsc_ps2_init);
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/hvc_console.c linux-2.4.20/drivers/char/hvc_console.c
--- linux-2.4.19/drivers/char/hvc_console.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/hvc_console.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
+ * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM
+ *
+ * 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
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/major.h>
+#include <linux/kernel.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/sched.h>
+#include <linux/kbd_kern.h>
+#include <asm/uaccess.h>
+#include <linux/spinlock.h>
+
+extern int hvc_count(int *);
+extern int hvc_get_chars(int index, char *buf, int count);
+extern int hvc_put_chars(int index, const char *buf, int count);
+
+#define HVC_MAJOR	229
+#define HVC_MINOR	0
+
+#define MAX_NR_HVC_CONSOLES	4
+
+#define TIMEOUT		((HZ + 99) / 100)
+
+struct tty_driver hvc_driver;
+static int hvc_refcount;
+static struct tty_struct *hvc_table[MAX_NR_HVC_CONSOLES];
+static struct termios *hvc_termios[MAX_NR_HVC_CONSOLES];
+static struct termios *hvc_termios_locked[MAX_NR_HVC_CONSOLES];
+static int hvc_offset;
+#ifdef CONFIG_MAGIC_SYSRQ
+static int sysrq_pressed;
+#endif
+
+#define N_OUTBUF	16
+
+#define __ALIGNED__	__attribute__((__aligned__(8)))
+
+struct hvc_struct {
+	spinlock_t lock;
+	int index;
+	struct tty_struct *tty;
+	unsigned int count;
+	int do_wakeup;
+	char outbuf[N_OUTBUF] __ALIGNED__;
+	int n_outbuf;
+};
+
+struct hvc_struct hvc_struct[MAX_NR_HVC_CONSOLES];
+
+static int hvc_open(struct tty_struct *tty, struct file * filp)
+{
+	int line = MINOR(tty->device) - tty->driver.minor_start;
+	struct hvc_struct *hp;
+	unsigned long flags;
+
+	if (line < 0 || line >= MAX_NR_HVC_CONSOLES)
+		return -ENODEV;
+	hp = &hvc_struct[line];
+
+	tty->driver_data = hp;
+	spin_lock_irqsave(&hp->lock, flags);
+	hp->tty = tty;
+	hp->count++;
+	spin_unlock_irqrestore(&hp->lock, flags);
+
+	return 0;
+}
+
+static void hvc_close(struct tty_struct *tty, struct file * filp)
+{
+	struct hvc_struct *hp = tty->driver_data;
+	unsigned long flags;
+
+	if (tty_hung_up_p(filp))
+		return;
+	spin_lock_irqsave(&hp->lock, flags);
+	if (--hp->count == 0)
+		hp->tty = NULL;
+	else if (hp->count < 0)
+		printk(KERN_ERR "hvc_close %lu: oops, count is %d\n",
+		       hp - hvc_struct, hp->count);
+	spin_unlock_irqrestore(&hp->lock, flags);
+}
+
+static void hvc_hangup(struct tty_struct *tty)
+{
+	struct hvc_struct *hp = tty->driver_data;
+
+	hp->count = 0;
+	hp->tty = NULL;
+}
+
+/* called with hp->lock held */
+static void hvc_push(struct hvc_struct *hp)
+{
+	int n;
+
+	n = hvc_put_chars(hp->index + hvc_offset, hp->outbuf, hp->n_outbuf);
+	if (n <= 0) {
+		if (n == 0)
+			return;
+		/* throw away output on error; this happens when
+		   there is no session connected to the vterm. */
+		hp->n_outbuf = 0;
+	} else
+		hp->n_outbuf -= n;
+	if (hp->n_outbuf > 0)
+		memmove(hp->outbuf, hp->outbuf + n, hp->n_outbuf);
+	else
+		hp->do_wakeup = 1;
+}
+
+static int hvc_write(struct tty_struct *tty, int from_user,
+		     const unsigned char *buf, int count)
+{
+	struct hvc_struct *hp = tty->driver_data;
+	char *p;
+	int todo, written = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&hp->lock, flags);
+	while (count > 0 && (todo = N_OUTBUF - hp->n_outbuf) > 0) {
+		if (todo > count)
+			todo = count;
+		p = hp->outbuf + hp->n_outbuf;
+		if (from_user) {
+			todo -= copy_from_user(p, buf, todo);
+			if (todo == 0) {
+				if (written == 0)
+					written = -EFAULT;
+				break;
+			}
+		} else
+			memcpy(p, buf, todo);
+		count -= todo;
+		buf += todo;
+		hp->n_outbuf += todo;
+		written += todo;
+		hvc_push(hp);
+	}
+	spin_unlock_irqrestore(&hp->lock, flags);
+
+	return written;
+}
+
+static int hvc_write_room(struct tty_struct *tty)
+{
+	struct hvc_struct *hp = tty->driver_data;
+
+	return N_OUTBUF - hp->n_outbuf;
+}
+
+static int hvc_chars_in_buffer(struct tty_struct *tty)
+{
+	struct hvc_struct *hp = tty->driver_data;
+
+	return hp->n_outbuf;
+}
+
+static void hvc_poll(int index)
+{
+	struct hvc_struct *hp = &hvc_struct[index];
+	struct tty_struct *tty;
+	int i, n;
+	char buf[16] __ALIGNED__;
+	unsigned long flags;
+
+	spin_lock_irqsave(&hp->lock, flags);
+
+	if (hp->n_outbuf > 0)
+		hvc_push(hp);
+
+	tty = hp->tty;
+	if (tty) {
+		for (;;) {
+			if (TTY_FLIPBUF_SIZE - tty->flip.count < sizeof(buf))
+				break;
+			n = hvc_get_chars(index + hvc_offset, buf, sizeof(buf));
+			if (n <= 0)
+				break;
+			for (i = 0; i < n; ++i) {
+#ifdef CONFIG_MAGIC_SYSRQ		/* Handle the SysRq Hack */
+				if (buf[i] == '\x0f') {	/* ^O -- should support a sequence */
+					sysrq_pressed = 1;
+					continue;
+				} else if (sysrq_pressed) {
+					handle_sysrq(buf[i], NULL, NULL, tty);
+					sysrq_pressed = 0;
+					continue;
+				}
+#endif
+				tty_insert_flip_char(tty, buf[i], 0);
+			}
+		}
+		if (tty->flip.count)
+			tty_schedule_flip(tty);
+
+		if (hp->do_wakeup) {
+			hp->do_wakeup = 0;
+			if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
+			    && tty->ldisc.write_wakeup)
+				(tty->ldisc.write_wakeup)(tty);
+			wake_up_interruptible(&tty->write_wait);
+		}
+	}
+
+	spin_unlock_irqrestore(&hp->lock, flags);
+}
+
+int khvcd(void *unused)
+{
+	int i;
+
+	daemonize();
+	reparent_to_init();
+	strcpy(current->comm, "khvcd");
+	sigfillset(&current->blocked);
+
+	for (;;) {
+		for (i = 0; i < MAX_NR_HVC_CONSOLES; ++i)
+			hvc_poll(i);
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(TIMEOUT);
+	}
+}
+
+int __init hvc_init(void)
+{
+	int i;
+
+	memset(&hvc_driver, 0, sizeof(struct tty_driver));
+
+	hvc_driver.magic = TTY_DRIVER_MAGIC;
+	hvc_driver.driver_name = "hvc";
+	hvc_driver.name = "hvc/%d";
+	hvc_driver.major = HVC_MAJOR;
+	hvc_driver.minor_start = HVC_MINOR;
+	hvc_driver.num = hvc_count(&hvc_offset);
+	if (hvc_driver.num > MAX_NR_HVC_CONSOLES)
+		hvc_driver.num = MAX_NR_HVC_CONSOLES;
+	hvc_driver.type = TTY_DRIVER_TYPE_SYSTEM;
+	hvc_driver.init_termios = tty_std_termios;
+	hvc_driver.flags = TTY_DRIVER_REAL_RAW;
+	hvc_driver.refcount = &hvc_refcount;
+	hvc_driver.table = hvc_table;
+	hvc_driver.termios = hvc_termios;
+	hvc_driver.termios_locked = hvc_termios_locked;
+
+	hvc_driver.open = hvc_open;
+	hvc_driver.close = hvc_close;
+	hvc_driver.write = hvc_write;
+	hvc_driver.hangup = hvc_hangup;
+	hvc_driver.write_room = hvc_write_room;
+	hvc_driver.chars_in_buffer = hvc_chars_in_buffer;
+
+	for (i = 0; i < hvc_driver.num; i++) {
+		hvc_struct[i].lock = SPIN_LOCK_UNLOCKED;
+		hvc_struct[i].index = i;
+		tty_register_devfs(&hvc_driver, 0, hvc_driver.minor_start + i);
+	}
+
+	if (tty_register_driver(&hvc_driver))
+		panic("Couldn't register hvc console driver\n");
+
+	if (hvc_driver.num > 0)
+		kernel_thread(khvcd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
+
+	return 0;
+}
+
+static void __exit hvc_exit(void)
+{
+}
+
+void hvc_console_print(struct console *co, const char *b, unsigned count)
+{
+	char c[16] __ALIGNED__;
+	unsigned i, n;
+	int r, donecr = 0;
+
+	i = n = 0;
+	while (count > 0 || i > 0) {
+		if (count > 0 && i < sizeof(c)) {
+			if (b[n] == '\n' && !donecr) {
+				c[i++] = '\r';
+				donecr = 1;
+			} else {
+				c[i++] = b[n++];
+				donecr = 0;
+				--count;
+			}
+		} else {
+			r = hvc_put_chars(co->index + hvc_offset, c, i);
+			if (r < 0) {
+				/* throw away chars on error */
+				i = 0;
+			} else if (r > 0) {
+				i -= r;
+				if (i > 0)
+					memmove(c, c+r, i);
+			}
+		}
+	}
+}
+
+static kdev_t hvc_console_device(struct console *c)
+{
+	return MKDEV(HVC_MAJOR, HVC_MINOR + c->index);
+}
+
+int hvc_wait_for_keypress(struct console *co)
+{
+	char c[16] __ALIGNED__;
+
+	while (hvc_get_chars(co->index, &c[0], 1) < 1)
+		;
+	return 0;
+}
+
+static int __init hvc_console_setup(struct console *co, char *options)
+{
+	if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES
+	    || co->index >= hvc_count(&hvc_offset))
+		return -1;
+	return 0;
+}
+
+struct console hvc_con_driver = {
+	name:		"hvc",
+	write:		hvc_console_print,
+	device:		hvc_console_device,
+	setup:		hvc_console_setup,
+	flags:		CON_PRINTBUFFER,
+	index:		-1,
+};
+
+int __init hvc_console_init(void)
+{
+	register_console(&hvc_con_driver);
+	return 0;
+}
+
+module_init(hvc_init);
+module_exit(hvc_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/i810-tco.c linux-2.4.20/drivers/char/i810-tco.c
--- linux-2.4.19/drivers/char/i810-tco.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/i810-tco.c	2002-10-29 11:18:31.000000000 +0000
@@ -223,7 +223,10 @@
 
 		/* scan to see wether or not we got the magic character */
 		for (i = 0; i != len; i++) {
-			if (data[i] == 'V')
+			u8 c;
+			if(get_user(c, data+i))
+				return -EFAULT;
+			if (c == 'V')
 				tco_expect_close = 42;
 		}
 
@@ -241,7 +244,9 @@
 	int options, retval = -EINVAL;
 
 	static struct watchdog_info ident = {
-		options:		WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+		options:		WDIOF_SETTIMEOUT |
+					WDIOF_KEEPALIVEPING |
+					WDIOF_MAGICCLOSE,
 		firmware_version:	0,
 		identity:		"i810 TCO timer",
 	};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/i8k.c linux-2.4.20/drivers/char/i8k.c
--- linux-2.4.19/drivers/char/i8k.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/char/i8k.c	2002-10-29 11:18:34.000000000 +0000
@@ -22,12 +22,15 @@
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/apm_bios.h>
+#include <linux/kbd_kern.h>
+#include <linux/kbd_ll.h>
+#include <linux/timer.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
 #include <linux/i8k.h>
 
-#define I8K_VERSION		"1.7 21/11/2001"
+#define I8K_VERSION		"1.13 14/05/2002"
 
 #define I8K_SMM_FN_STATUS	0x0025
 #define I8K_SMM_POWER_STATUS	0x0069
@@ -55,6 +58,19 @@
 
 #define DELL_SIGNATURE		"Dell Computer"
 
+/* Interval between polling of keys, in jiffies. */
+#define I8K_POLL_INTERVAL	(HZ/20)
+#define I8K_REPEAT_DELAY	250	/* 250 ms */
+#define I8K_REPEAT_RATE		10
+
+/*
+ * (To be escaped) Scancodes for the keys.  These were chosen to match other
+ * "Internet" keyboards.
+ */
+#define I8K_KEYS_UP_SCANCODE	0x30
+#define I8K_KEYS_DOWN_SCANCODE	0x2e
+#define I8K_KEYS_MUTE_SCANCODE	0x20
+
 static char *supported_models[] = {
     "Inspiron",
     "Latitude",
@@ -67,19 +83,34 @@
 static char serial_number[16] = "?";
 
 int force = 0;
+int restricted = 0;
+int handle_buttons = 0;
+int repeat_delay = I8K_REPEAT_DELAY;
+int repeat_rate = I8K_REPEAT_RATE;
 int power_status = 0;
 
+static struct timer_list  i8k_keys_timer;
+
 MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
 MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
 MODULE_LICENSE("GPL");
 MODULE_PARM(force, "i");
+MODULE_PARM(restricted, "i");
+MODULE_PARM(handle_buttons, "i");
+MODULE_PARM(repeat_delay, "i");
+MODULE_PARM(repeat_rate, "i");
 MODULE_PARM(power_status, "i");
 MODULE_PARM_DESC(force, "Force loading without checking for supported models");
+MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set");
+MODULE_PARM_DESC(handle_buttons, "Generate keyboard events for i8k buttons");
+MODULE_PARM_DESC(repeat_delay, "I8k buttons repeat delay (ms)");
+MODULE_PARM_DESC(repeat_rate, "I8k buttons repeat rate");
 MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
 
 static ssize_t i8k_read(struct file *, char *, size_t, loff_t *);
 static int i8k_ioctl(struct inode *, struct file *, unsigned int,
 		     unsigned long);
+static void i8k_keys_set_timer(void);
 
 static struct file_operations i8k_fops = {
     read:	i8k_read,
@@ -370,6 +401,9 @@
 	break;
 
     case I8K_SET_FAN:
+	if (restricted && !capable(CAP_SYS_ADMIN)) {
+	    return -EPERM;
+	}
 	if (copy_from_user(&val, (int *)arg, sizeof(int))) {
 	    return -EFAULT;
 	}
@@ -483,6 +517,61 @@
     return len;
 }
 
+/*
+ * i8k_keys stuff. Thanks to David Bustos <bustos@caltech.edu>
+ */
+
+static unsigned char i8k_keys_make_scancode(int x) {
+    switch (x) {
+    case I8K_FN_UP:	return I8K_KEYS_UP_SCANCODE;
+    case I8K_FN_DOWN:	return I8K_KEYS_DOWN_SCANCODE;
+    case I8K_FN_MUTE:	return I8K_KEYS_MUTE_SCANCODE;
+    }
+
+    return 0;
+}
+
+static void i8k_keys_poll(unsigned long data) {
+    static int last = 0;
+    static int repeat = 0;
+
+    int  curr;
+
+    curr = i8k_get_fn_status();
+    if (curr >= 0) {
+	if (curr != last) {
+	    repeat = jiffies + (HZ * repeat_delay / 1000);
+
+	    if (last != 0) {
+		handle_scancode(0xe0, 0);
+		handle_scancode(i8k_keys_make_scancode(last), 0);
+	    }
+
+	    if (curr != 0) {
+		handle_scancode(0xe0, 1);
+		handle_scancode(i8k_keys_make_scancode(curr), 1);
+	    }
+	} else {
+	    /* Generate keyboard repeat events with current scancode -- dz */
+	    if ((curr) && (repeat_rate > 0) && (jiffies >= repeat)) {
+		repeat = jiffies + (HZ / repeat_rate);
+		handle_scancode(0xe0, 1);
+		handle_scancode(i8k_keys_make_scancode(curr), 1);
+	    }
+	}
+
+	last = curr;
+    }
+
+    /* Reset the timer. */
+    i8k_keys_set_timer();
+}
+
+static void i8k_keys_set_timer() {
+    i8k_keys_timer.expires = jiffies + I8K_POLL_INTERVAL;
+    add_timer(&i8k_keys_timer);
+}
+
 static char* __init string_trim(char *s, int size)
 {
     int len;
@@ -757,6 +846,16 @@
 	   "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
 	   I8K_VERSION);
 
+    /* Register the i8k_keys timer. */
+    if (handle_buttons) {
+	printk(KERN_INFO
+	       "i8k: enabling buttons events, delay=%d, rate=%d\n",
+	       repeat_delay, repeat_rate);
+	init_timer(&i8k_keys_timer);
+	i8k_keys_timer.function = i8k_keys_poll;
+	i8k_keys_set_timer();
+    }
+
     return 0;
 }
 
@@ -771,6 +870,11 @@
     /* Remove the proc entry */
     remove_proc_entry("i8k", NULL);
 
+    /* Unregister the i8k_keys timer. */
+    while (handle_buttons && !del_timer(&i8k_keys_timer)) {
+	schedule_timeout(I8K_POLL_INTERVAL);
+    }
+
     printk(KERN_INFO "i8k: module unloaded\n");
 }
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/ib700wdt.c linux-2.4.20/drivers/char/ib700wdt.c
--- linux-2.4.19/drivers/char/ib700wdt.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.20/drivers/char/ib700wdt.c	2002-10-29 11:18:37.000000000 +0000
@@ -50,6 +50,7 @@
 
 static int ibwdt_is_open;
 static spinlock_t ibwdt_lock;
+static int expect_close = 0;
 
 /*
  *
@@ -114,6 +115,15 @@
 
 static int wd_margin = WD_TIMO;
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 
 /*
  *	Kernel methods.
@@ -134,6 +144,20 @@
 		return -ESPIPE;
 
 	if (count) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
 		ibwdt_ping();
 		return 1;
 	}
@@ -153,7 +177,10 @@
 	int i, new_margin;
 
 	static struct watchdog_info ident = {
-		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, 1, "IB700 WDT"
+		WDIOF_KEEPALIVEPING |
+		WDIOF_SETTIMEOUT |
+		WDIOF_MAGICCLOSE,
+		1, "IB700 WDT"
 	};
 
 	switch (cmd) {
@@ -222,9 +249,11 @@
 	lock_kernel();
 	if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
 		spin_lock(&ibwdt_lock);
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-		outb_p(wd_times[wd_margin], WDT_STOP);
-#endif
+		if (expect_close) {
+			outb_p(wd_times[wd_margin], WDT_STOP);
+		} else {
+			printk(KERN_CRIT "WDT device closed unexpectedly.  WDT will not stop!\n");
+		}
 		ibwdt_is_open = 0;
 		spin_unlock(&ibwdt_lock);
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/indydog.c linux-2.4.20/drivers/char/indydog.c
--- linux-2.4.19/drivers/char/indydog.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/indydog.c	2002-10-29 11:18:34.000000000 +0000
@@ -26,6 +26,16 @@
 
 static unsigned long indydog_alive;
 static struct sgimc_misc_ctrl *mcmisc_regs; 
+static int expect_close = 0;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
 static void indydog_ping()
 {
@@ -43,9 +53,9 @@
 	
 	if( test_and_set_bit(0,&indydog_alive) )
 		return -EBUSY;
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
-	MOD_INC_USE_COUNT;
-#endif
+	if (nowayout) {
+		MOD_INC_USE_COUNT;
+	}
 	/*
 	 *	Activate timer
 	 */
@@ -63,16 +73,19 @@
 {
 	/*
 	 *	Shut off the timer.
-	 * 	Lock it in if it's a module and we defined ...NOWAYOUT
+	 * 	Lock it in if it's a module and we set nowayout.
 	 */
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
+	if (expect_close)
 	{
-	u32 mc_ctrl0 = mcmisc_regs->cpuctrl0; 
-	mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
-	mcmisc_regs->cpuctrl0 = mc_ctrl0;
-	printk("Stopped watchdog timer.\n");
+		u32 mc_ctrl0 = mcmisc_regs->cpuctrl0; 
+		mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
+		mcmisc_regs->cpuctrl0 = mc_ctrl0;
+		printk("Stopped watchdog timer.\n");
+	}
+	else
+	{
+		printk(KERN_CRIT "WDT device closed unexpectedly.  WDT will not stop!\n");
 	}
-#endif
 	clear_bit(0,&indydog_alive);
 	return 0;
 }
@@ -87,6 +100,20 @@
 	 *	Refresh the timer.
 	 */
 	if(len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != len; i++) {
+				char c;
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
 		indydog_ping();
 		return 1;
 	}
@@ -97,6 +124,7 @@
 	unsigned int cmd, unsigned long arg)
 {
 	static struct watchdog_info ident = {
+		options: WDIOF_MAGICCLOSE,
 		identity: "Hardware Watchdog for SGI IP22",
 	};
 	switch (cmd) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/ip2main.c linux-2.4.20/drivers/char/ip2main.c
--- linux-2.4.19/drivers/char/ip2main.c	2001-11-03 01:26:17.000000000 +0000
+++ linux-2.4.20/drivers/char/ip2main.c	2002-10-29 11:18:48.000000000 +0000
@@ -1001,12 +1001,10 @@
 	printk(KERN_INFO "IP2: Board %d: addr=0x%x irq=%d\n", boardnum + 1,
 	       ip2config.addr[boardnum], ip2config.irq[boardnum] );
 
-	if (0 != ( rc = check_region( ip2config.addr[boardnum], 8))) {
-		printk(KERN_ERR "IP2: bad addr=0x%x rc = %d\n",
-				ip2config.addr[boardnum], rc );
+	if (!request_region( ip2config.addr[boardnum], 8, pcName )) {
+		printk(KERN_ERR "IP2: bad addr=0x%x\n", ip2config.addr[boardnum]);
 		goto err_initialize;
 	}
-	request_region( ip2config.addr[boardnum], 8, pcName );
 
 	if ( iiDownloadAll ( pB, (loadHdrStrPtr)Fip_firmware, 1, Fip_firmware_size )
 	    != II_DOWN_GOOD ) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/joystick/Config.in linux-2.4.20/drivers/char/joystick/Config.in
--- linux-2.4.19/drivers/char/joystick/Config.in	2001-09-12 22:34:06.000000000 +0000
+++ linux-2.4.20/drivers/char/joystick/Config.in	2002-10-29 11:18:49.000000000 +0000
@@ -9,7 +9,7 @@
    dep_tristate 'Game port support' CONFIG_INPUT_GAMEPORT $CONFIG_INPUT
       dep_tristate '  Classic ISA/PnP gameports' CONFIG_INPUT_NS558 $CONFIG_INPUT_GAMEPORT
       dep_tristate '  PDPI Lightning 4 gamecard' CONFIG_INPUT_LIGHTNING $CONFIG_INPUT_GAMEPORT
-      dep_tristate '  Aureal Vortex and Trident 4DWave gameports' CONFIG_INPUT_PCIGAME $CONFIG_INPUT_GAMEPORT
+      dep_tristate '  Aureal Vortex, Trident 4DWave, and ALi 5451 gameports' CONFIG_INPUT_PCIGAME $CONFIG_INPUT_GAMEPORT
       dep_tristate '  Crystal SoundFusion gameports' CONFIG_INPUT_CS461X  $CONFIG_INPUT_GAMEPORT
       dep_tristate '  SoundBlaster Live! gameports' CONFIG_INPUT_EMU10K1 $CONFIG_INPUT_GAMEPORT
    tristate 'Serial port device support' CONFIG_INPUT_SERIO
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/joystick/Makefile linux-2.4.20/drivers/char/joystick/Makefile
--- linux-2.4.19/drivers/char/joystick/Makefile	2001-09-12 22:34:06.000000000 +0000
+++ linux-2.4.20/drivers/char/joystick/Makefile	2002-10-29 11:18:49.000000000 +0000
@@ -6,7 +6,7 @@
 
 # Objects that export symbols.
 
-export-objs	:= serio.o gameport.o
+export-objs	:= serio.o gameport.o pcigame.o
 
 # I-Force may need both USB and RS-232
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/joystick/analog.c linux-2.4.20/drivers/char/joystick/analog.c
--- linux-2.4.19/drivers/char/joystick/analog.c	2001-10-25 21:01:51.000000000 +0000
+++ linux-2.4.20/drivers/char/joystick/analog.c	2002-10-29 11:18:37.000000000 +0000
@@ -137,10 +137,9 @@
  */
 
 #ifdef __i386__
-#define TSC_PRESENT	(test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability))
-#define GET_TIME(x)	do { if (TSC_PRESENT) rdtscl(x); else { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } } while (0)
-#define DELTA(x,y)	(TSC_PRESENT?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0)))
-#define TIME_NAME	(TSC_PRESENT?"TSC":"PIT")
+#define GET_TIME(x)	do { if (cpu_has_tsc) rdtscl(x); else { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } } while (0)
+#define DELTA(x,y)	(cpu_has_tsc?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0)))
+#define TIME_NAME	(cpu_has_tsc?"TSC":"PIT")
 #elif __x86_64__
 #define GET_TIME(x)	rdtscl(x)
 #define DELTA(x,y)	((y)-(x))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/joystick/iforce.c linux-2.4.20/drivers/char/joystick/iforce.c
--- linux-2.4.19/drivers/char/joystick/iforce.c	2001-09-12 22:34:06.000000000 +0000
+++ linux-2.4.20/drivers/char/joystick/iforce.c	2002-10-29 11:18:33.000000000 +0000
@@ -134,7 +134,7 @@
 #ifdef IFORCE_USB
 	struct usb_device *usbdev;	/* USB transfer */
 	struct urb irq, out, ctrl;
-	devrequest dr;
+	struct usb_ctrlrequest dr;
 #endif
 					/* Force Feedback */
 	wait_queue_head_t wait;
@@ -283,7 +283,7 @@
 #ifdef IFORCE_USB
 		case IFORCE_USB:
 
-			iforce->dr.request = packet[0];
+			iforce->dr.bRequest = packet[0];
 			iforce->ctrl.dev = iforce->usbdev;
 
 			set_current_state(TASK_INTERRUPTIBLE);
@@ -1027,9 +1027,9 @@
 	iforce->bus = IFORCE_USB;
 	iforce->usbdev = dev;
 
-	iforce->dr.requesttype = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
-	iforce->dr.index = 0;
-	iforce->dr.length = 16;
+	iforce->dr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
+	iforce->dr.wIndex = 0;
+	iforce->dr.wLength = 16;
 
 	FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
 			iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/joystick/pcigame.c linux-2.4.20/drivers/char/joystick/pcigame.c
--- linux-2.4.19/drivers/char/joystick/pcigame.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/joystick/pcigame.c	2002-10-29 11:18:33.000000000 +0000
@@ -43,35 +43,18 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/gameport.h>
+#include <linux/pci_gameport.h>
 
 #define PCI_VENDOR_ID_AUREAL	0x12eb
 
 #define PCIGAME_DATA_WAIT	20	/* 20 ms */
 
-#define PCIGAME_4DWAVE		0
-#define PCIGAME_VORTEX		1
-#define PCIGAME_VORTEX2		2
-
-struct pcigame_data {
-	int gcr;	/* Gameport control register */
-	int legacy;	/* Legacy port location */
-	int axes;	/* Axes start */
-	int axsize;	/* Axis field size */
-	int axmax;	/* Axis field max value */
-	int adcmode;	/* Value to enable ADC mode in GCR */
-};
-
-static struct pcigame_data pcigame_data[] __devinitdata =
-{{ 0x00030, 0x00031, 0x00034, 2, 0xffff, 0x80 },
- { 0x1100c, 0x11008, 0x11010, 4, 0x1fff, 0x40 },
- { 0x2880c, 0x28808, 0x28810, 4, 0x1fff, 0x40 },
- { 0 }};
 
-struct pcigame {
-	struct gameport gameport;
-	struct pci_dev *dev;
-        unsigned char *base;
-	struct pcigame_data *data;
+static struct pcigame_data pcigame_data[] __devinitdata = {
+	{ 0x00030, 0x00031, 0x00034, 2, 0xffff, 0x80 },
+	{ 0x1100c, 0x11008, 0x11010, 4, 0x1fff, 0x40 },
+	{ 0x2880c, 0x28808, 0x28810, 4, 0x1fff, 0x40 },
+	{ 0 }
 };
 
 static unsigned char pcigame_read(struct gameport *gameport)
@@ -120,20 +103,19 @@
 	return 0;
 }
 
-static int __devinit pcigame_probe(struct pci_dev *dev, const struct pci_device_id *id)
+struct pcigame *pcigame_attach(struct pci_dev *dev, int type)
 {
 	struct pcigame *pcigame;
 	int i;
 
 	if (!(pcigame = kmalloc(sizeof(struct pcigame), GFP_KERNEL)))
-		return -1;
+		return NULL;
         memset(pcigame, 0, sizeof(struct pcigame));
 
 
-	pcigame->data = pcigame_data + id->driver_data;
+	pcigame->data = pcigame_data + type;
 
 	pcigame->dev = dev;
-	pci_set_drvdata(dev, pcigame);
 
 	pcigame->gameport.driver = pcigame;
 	pcigame->gameport.fuzz = 64;
@@ -146,6 +128,8 @@
 	for (i = 0; i < 6; i++)
 		if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
 			break;
+	if(i==6)
+		return NULL;
 
 	pci_enable_device(dev);
 
@@ -158,20 +142,46 @@
 		pcigame->gameport.number, dev->name, dev->bus->number,
 			PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), pcigame->gameport.speed);
 
+	return pcigame;
+}
+
+EXPORT_SYMBOL_GPL(pcigame_attach);
+
+
+void pcigame_detach(struct pcigame *game)
+{
+	gameport_unregister_port(&game->gameport);
+	iounmap(game->base);
+	kfree(game);
+}
+
+EXPORT_SYMBOL_GPL(pcigame_detach);
+
+static __devinit int pcigame_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct pcigame *r = pcigame_attach(dev, id->driver_data);
+	if(r == NULL)
+		return -1;
+	pci_set_drvdata(dev, r);
 	return 0;
 }
 
 static void __devexit pcigame_remove(struct pci_dev *dev)
 {
 	struct pcigame *pcigame = pci_get_drvdata(dev);
-	gameport_unregister_port(&pcigame->gameport);
-	iounmap(pcigame->base);
-	kfree(pcigame);
+	pcigame_detach(pcigame);
 }
 
+
 static struct pci_device_id pcigame_id_table[] __devinitdata =
-{{ PCI_VENDOR_ID_TRIDENT, 0x2000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE  },
+{
+/* If the trident is configured in audio grabs it and we get called by
+   that */
+#if !defined(CONFIG_SOUND_TRIDENT) && !defined(CONFIG_SOUND_TRIDENT_MODULE)
+ { PCI_VENDOR_ID_TRIDENT, 0x2000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE  },
  { PCI_VENDOR_ID_TRIDENT, 0x2001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE  },
+ { PCI_VENDOR_ID_AL,      0x5451, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE  },
+#endif 
  { PCI_VENDOR_ID_AUREAL,  0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX  },
  { PCI_VENDOR_ID_AUREAL,  0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX2 },
  { 0 }};
@@ -185,7 +195,9 @@
 
 int __init pcigame_init(void)
 {
-	return pci_module_init(&pcigame_driver);
+	pci_module_init(&pcigame_driver);
+	/* Needed by other modules */
+	return 0;
 }
 
 void __exit pcigame_exit(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/machzwd.c linux-2.4.20/drivers/char/machzwd.c
--- linux-2.4.19/drivers/char/machzwd.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/machzwd.c	2002-10-29 11:18:34.000000000 +0000
@@ -24,6 +24,8 @@
  *  a system RESET and it starts wd#2 that unconditionaly will RESET 
  *  the system when the counter reaches zero.
  *
+ *  14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * 	Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  */
 
 #include <linux/config.h>
@@ -103,10 +105,19 @@
 MODULE_PARM(action, "i");
 MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*)  1 = SMI  2 = NMI  3 = SCI");
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 #define PFX "machzwd"
 
 static struct watchdog_info zf_info = {
-	options:		WDIOF_KEEPALIVEPING, 
+	options:		WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 
 	firmware_version:	1, 
 	identity:		"ZF-Logic watchdog"
 };
@@ -303,27 +314,30 @@
 	/* See if we got the magic character */
 	if(count){
 
-/*
- * no need to check for close confirmation
- * no way to disable watchdog ;)
- */
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-		size_t ofs;
-
-		/* 
-		 * note: just in case someone wrote the magic character
-		 * five months ago...
+		/*
+		 * no need to check for close confirmation
+		 * no way to disable watchdog ;)
 		 */
-		zf_expect_close = 0;
+		if (!nowayout) {
+			size_t ofs;
 
-		/* now scan */
-		for(ofs = 0; ofs != count; ofs++){
-			if(buf[ofs] == 'V'){
-				zf_expect_close = 1;
-				dprintk("zf_expect_close 1\n");
+			/* 
+			 * note: just in case someone wrote the
+			 * magic character five months ago...
+			 */
+			zf_expect_close = 0;
+
+			/* now scan */
+			for(ofs = 0; ofs != count; ofs++){
+				char c;
+				if(get_user(c, buf+ofs))
+					return -EFAULT;
+				if(c == 'V'){
+					zf_expect_close = 1;
+					dprintk("zf_expect_close 1\n");
+				}
 			}
 		}
-#endif
 		/*
 		 * Well, anyhow someone wrote to us,
 		 * we should return that favour
@@ -381,9 +395,9 @@
 				return -EBUSY;
 			}
 
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
-			MOD_INC_USE_COUNT;
-#endif
+			if (nowayout) {
+				MOD_INC_USE_COUNT;
+			}
 			zf_is_open = 1;
 
 			spin_unlock(&zf_lock);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/mixcomwd.c linux-2.4.20/drivers/char/mixcomwd.c
--- linux-2.4.19/drivers/char/mixcomwd.c	2001-09-13 22:21:32.000000000 +0000
+++ linux-2.4.20/drivers/char/mixcomwd.c	2002-10-29 11:18:35.000000000 +0000
@@ -27,10 +27,13 @@
  *
  * Version 0.4 (99/11/15):
  *		- support for one more type board
+ *
+ * Version 0.5 (2001/12/14) Matt Domsch <Matt_Domsch@dell.com>
+ * 		- added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  *	
  */
 
-#define VERSION "0.4" 
+#define VERSION "0.5" 
   
 #include <linux/module.h>
 #include <linux/config.h>
@@ -58,25 +61,31 @@
 
 static int watchdog_port;
 
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
 static int mixcomwd_timer_alive;
 static struct timer_list mixcomwd_timer;
+static int expect_close = 0;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
 #endif
 
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 static void mixcomwd_ping(void)
 {
 	outb_p(55,watchdog_port);
 	return;
 }
 
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
 static void mixcomwd_timerfun(unsigned long d)
 {
 	mixcomwd_ping();
 	
 	mod_timer(&mixcomwd_timer,jiffies+ 5*HZ);
 }
-#endif
 
 /*
  *	Allow only one person to hold it open
@@ -89,12 +98,13 @@
 	}
 	mixcomwd_ping();
 	
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
+	if (nowayout) {
+		MOD_INC_USE_COUNT;
+	}
 	if(mixcomwd_timer_alive) {
 		del_timer(&mixcomwd_timer);
 		mixcomwd_timer_alive=0;
 	} 
-#endif
 	return 0;
 }
 
@@ -102,19 +112,21 @@
 {
 
 	lock_kernel();
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-	if(mixcomwd_timer_alive) {
-		printk(KERN_ERR "mixcomwd: release called while internal timer alive");
-		unlock_kernel();
-		return -EBUSY;
+	if (expect_close) {
+		if(mixcomwd_timer_alive) {
+			printk(KERN_ERR "mixcomwd: release called while internal timer alive");
+			unlock_kernel();
+			return -EBUSY;
+		}
+		init_timer(&mixcomwd_timer);
+		mixcomwd_timer.expires=jiffies + 5 * HZ;
+		mixcomwd_timer.function=mixcomwd_timerfun;
+		mixcomwd_timer.data=0;
+		mixcomwd_timer_alive=1;
+		add_timer(&mixcomwd_timer);
+	} else {
+		printk(KERN_CRIT "mixcomwd: WDT device closed unexpectedly.  WDT will not stop!\n");
 	}
-	init_timer(&mixcomwd_timer);
-	mixcomwd_timer.expires=jiffies + 5 * HZ;
-	mixcomwd_timer.function=mixcomwd_timerfun;
-	mixcomwd_timer.data=0;
-	mixcomwd_timer_alive=1;
-	add_timer(&mixcomwd_timer);
-#endif
 
 	clear_bit(0,&mixcomwd_opened);
 	unlock_kernel();
@@ -130,6 +142,20 @@
 
 	if(len)
 	{
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != len; i++) {
+				char c;
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
 		mixcomwd_ping();
 		return 1;
 	}
@@ -141,16 +167,17 @@
 {
 	int status;
         static struct watchdog_info ident = {
-		WDIOF_KEEPALIVEPING, 1, "MixCOM watchdog"
+		WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+		1, "MixCOM watchdog"
 	};
                                         
 	switch(cmd)
 	{
 		case WDIOC_GETSTATUS:
 			status=mixcomwd_opened;
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-			status|=mixcomwd_timer_alive;
-#endif
+			if (!nowayout) {
+				status|=mixcomwd_timer_alive;
+			}
 			if (copy_to_user((int *)arg, &status, sizeof(int))) {
 				return -EFAULT;
 			}
@@ -255,14 +282,14 @@
 
 static void __exit mixcomwd_exit(void)
 {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-	if(mixcomwd_timer_alive) {
-		printk(KERN_WARNING "mixcomwd: I quit now, hardware will"
-			" probably reboot!\n");
-		del_timer(&mixcomwd_timer);
-		mixcomwd_timer_alive=0;
+	if (!nowayout) {
+		if(mixcomwd_timer_alive) {
+			printk(KERN_WARNING "mixcomwd: I quit now, hardware will"
+				" probably reboot!\n");
+			del_timer(&mixcomwd_timer);
+			mixcomwd_timer_alive=0;
+		}
 	}
-#endif
 	release_region(watchdog_port,1);
 	misc_deregister(&mixcomwd_miscdev);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/mwave/smapi.c linux-2.4.20/drivers/char/mwave/smapi.c
--- linux-2.4.19/drivers/char/mwave/smapi.c	2001-09-30 19:26:05.000000000 +0000
+++ linux-2.4.20/drivers/char/mwave/smapi.c	2002-10-29 11:18:50.000000000 +0000
@@ -280,10 +280,11 @@
 				if ((usSI & 0xFF) == mwave_uart_irq) {
 #ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
 					PRINTK_ERROR(KERN_ERR_MWAVE
+						"smapi::smapi_set_DSP_cfg: Serial port A irq %x conflicts with mwave_uart_irq %x\n", usSI & 0xFF, mwave_uart_irq);
 #else
 					PRINTK_3(TRACE_SMAPI,
+						"smapi::smapi_set_DSP_cfg: Serial port A irq %x conflicts with mwave_uart_irq %x\n", usSI & 0xFF, mwave_uart_irq);
 #endif
-						"smapi::smapi_set_DSP_cfg: Serial port A irq %x conflicts with mwave_uart_irq %x\n", usSI, mwave_uart_irq);
 #ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
 					PRINTK_1(TRACE_SMAPI,
 						"smapi::smapi_set_DSP_cfg Disabling conflicting serial port\n");
@@ -300,13 +301,14 @@
 					if ((usSI >> 8) == uartio_index) {
 #ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
 						PRINTK_ERROR(KERN_ERR_MWAVE
+							"smapi::smapi_set_DSP_cfg: Serial port A base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI >> 8], ausUartBases[uartio_index]);
 #else
 						PRINTK_3(TRACE_SMAPI,
+							"smapi::smapi_set_DSP_cfg: Serial port A base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI >> 8], ausUartBases[uartio_index]);
 #endif
-							"smapi::smapi_set_DSP_cfg: Serial port A base I/O address index %x conflicts with uartio_index %x\n", usSI >> 8, uartio_index);
 #ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
 						PRINTK_1(TRACE_SMAPI,
-							"smapi::smapi_set_DSP_cfg Disabling conflicting serial port\n");
+							"smapi::smapi_set_DSP_cfg Disabling conflicting serial port A\n");
 						bRC = smapi_request (0x1403, 0x0100, 0, usSI,
 							&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
 						if (bRC) goto exit_smapi_request_error;
@@ -331,13 +333,14 @@
 				if ((usSI & 0xFF) == mwave_uart_irq) {
 #ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
 					PRINTK_ERROR(KERN_ERR_MWAVE
+						"smapi::smapi_set_DSP_cfg: Serial port B irq %x conflicts with mwave_uart_irq %x\n", usSI & 0xFF, mwave_uart_irq);
 #else
 					PRINTK_3(TRACE_SMAPI,
+						"smapi::smapi_set_DSP_cfg: Serial port B irq %x conflicts with mwave_uart_irq %x\n", usSI & 0xFF, mwave_uart_irq);
 #endif
-						"smapi::smapi_set_DSP_cfg: Serial port B irq %x conflicts with mwave_uart_irq %x\n", usSI, mwave_uart_irq);
 #ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
 					PRINTK_1(TRACE_SMAPI,
-						"smapi::smapi_set_DSP_cfg Disabling conflicting serial port\n");
+						"smapi::smapi_set_DSP_cfg Disabling conflicting serial port B\n");
 					bRC = smapi_request(0x1405, 0x0100, 0, usSI,
 						&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
 					if (bRC) goto exit_smapi_request_error;
@@ -351,13 +354,14 @@
 					if ((usSI >> 8) == uartio_index) {
 #ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
 						PRINTK_ERROR(KERN_ERR_MWAVE
+							"smapi::smapi_set_DSP_cfg: Serial port B base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI >> 8], ausUartBases[uartio_index]);
 #else
 						PRINTK_3(TRACE_SMAPI,
+							"smapi::smapi_set_DSP_cfg: Serial port B base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI >> 8], ausUartBases[uartio_index]);
 #endif
-							"smapi::smapi_set_DSP_cfg: Serial port B base I/O address index %x conflicts with uartio_index %x\n", usSI >> 8, uartio_index);
 #ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
 						PRINTK_1 (TRACE_SMAPI,
-						    "smapi::smapi_set_DSP_cfg Disabling conflicting serial port\n");
+						    "smapi::smapi_set_DSP_cfg Disabling conflicting serial port B\n");
 						bRC = smapi_request (0x1405, 0x0100, 0, usSI,
 							&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
 						if (bRC) goto exit_smapi_request_error;
@@ -380,39 +384,15 @@
 			&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
 		if (bRC) goto exit_smapi_request_error;
 		/* bRC == 0 */
-		if ((usCX & 0xff) == mwave_uart_irq) {	/* serial port is enabled */
-#ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
-			PRINTK_ERROR(KERN_ERR_MWAVE
-#else
-			PRINTK_3(TRACE_SMAPI,
-#endif
-				"smapi::smapi_set_DSP_cfg: IR port irq %x conflicts with mwave_uart_irq %x\n", usSI, mwave_uart_irq);
-#ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
-			PRINTK_1(TRACE_SMAPI,
-				"smapi::smapi_set_DSP_cfg Disabling conflicting IR port\n");
-			bRC = smapi_request(0x1701, 0x0100, 0, 0,
-				&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
-			if (bRC) goto exit_smapi_request_error;
-			bRC = smapi_request(0x1700, 0, 0, 0,
-				&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
-			if (bRC) goto exit_smapi_request_error;
-			bRC = smapi_request(0x1705, 0x01ff, 0, usSI,
-				&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
-			if (bRC) goto exit_smapi_request_error;
-			bRC = smapi_request(0x1704, 0x0000, 0, 0,
-				&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
-			if (bRC) goto exit_smapi_request_error;
-#else
-			goto exit_conflict;
-#endif
-		} else {
-			if ((usSI & 0xff) == uartio_index) {
+		if ((usCX & 0xff) != 0xff) { /* IR port not disabled */
+			if ((usCX & 0xff) == mwave_uart_irq) {
 #ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
 				PRINTK_ERROR(KERN_ERR_MWAVE
+					"smapi::smapi_set_DSP_cfg: IR port irq %x conflicts with mwave_uart_irq %x\n", usCX & 0xff, mwave_uart_irq);
 #else
 				PRINTK_3(TRACE_SMAPI,
+					"smapi::smapi_set_DSP_cfg: IR port irq %x conflicts with mwave_uart_irq %x\n", usCX & 0xff, mwave_uart_irq);
 #endif
-					"smapi::smapi_set_DSP_cfg: IR port base I/O address index %x conflicts with uartio_index %x\n", usSI & 0xff, uartio_index);
 #ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
 				PRINTK_1(TRACE_SMAPI,
 					"smapi::smapi_set_DSP_cfg Disabling conflicting IR port\n");
@@ -431,6 +411,34 @@
 #else
 				goto exit_conflict;
 #endif
+			} else {
+				if ((usSI & 0xff) == uartio_index) {
+#ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
+					PRINTK_ERROR(KERN_ERR_MWAVE
+						"smapi::smapi_set_DSP_cfg: IR port base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI & 0xff], ausUartBases[uartio_index]);
+#else
+					PRINTK_3(TRACE_SMAPI,
+						"smapi::smapi_set_DSP_cfg: IR port base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI & 0xff], ausUartBases[uartio_index]);
+#endif
+#ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
+					PRINTK_1(TRACE_SMAPI,
+						"smapi::smapi_set_DSP_cfg Disabling conflicting IR port\n");
+					bRC = smapi_request(0x1701, 0x0100, 0, 0,
+						&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
+					if (bRC) goto exit_smapi_request_error;
+					bRC = smapi_request(0x1700, 0, 0, 0,
+						&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
+					if (bRC) goto exit_smapi_request_error;
+					bRC = smapi_request(0x1705, 0x01ff, 0, usSI,
+						&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
+					if (bRC) goto exit_smapi_request_error;
+					bRC = smapi_request(0x1704, 0x0000, 0, 0,
+						&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
+					if (bRC) goto exit_smapi_request_error;
+#else
+					goto exit_conflict;
+#endif
+				}
 			}
 		}
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/mxser.c linux-2.4.20/drivers/char/mxser.c
--- linux-2.4.19/drivers/char/mxser.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/mxser.c	2002-10-29 11:18:49.000000000 +0000
@@ -653,7 +653,7 @@
 		n = (sizeof(mxser_pcibrds) / sizeof(mxser_pcibrds[0])) - 1;
 		index = 0;
 		for (b = 0; b < n; b++) {
-			while (pdev = pci_find_device(mxser_pcibrds[b].vendor, mxser_pcibrds[b].device, pdev)) 
+			while ((pdev = pci_find_device(mxser_pcibrds[b].vendor, mxser_pcibrds[b].device, pdev)) != NULL)
 			{
 				if (pci_enable_device(pdev))
 					continue;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/nvram.c linux-2.4.20/drivers/char/nvram.c
--- linux-2.4.19/drivers/char/nvram.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/nvram.c	2002-10-29 11:18:38.000000000 +0000
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 1997 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
  * idea by and with help from Richard Jelinek <rj@suse.de>
+ * Portions copyright (c) 2001,2002 Sun Microsystems (thockin@sun.com)
  *
  * This driver allows you to access the contents of the non-volatile memory in
  * the mc146818rtc.h real-time clock. This chip is built into all PCs and into
@@ -10,9 +11,10 @@
  * "NVRAM" (NV stands for non-volatile).
  *
  * The data are supplied as a (seekable) character device, /dev/nvram. The
- * size of this file is 50, the number of freely available bytes in the memory
- * (i.e., not used by the RTC itself).
- * 
+ * size of this file is dependant on the controller.  The usual size is 114,
+ * the number of freely available bytes in the memory (i.e., not used by the
+ * RTC itself).
+ *
  * Checksums over the NVRAM contents are managed by this driver. In case of a
  * bad checksum, reads and writes return -EIO. The checksum can be initialized
  * to a sane state either by ioctl(NVRAM_INIT) (clear whole NVRAM) or
@@ -28,40 +30,63 @@
  *
  * 	1.1	Cesar Barros: SMP locking fixes
  * 		added changelog
+ * 	1.2	Erik Gilling: Cobalt Networks support
+ * 		Tim Hockin: general cleanup, Cobalt support
  */
 
-#define NVRAM_VERSION		"1.1"
+#define NVRAM_VERSION	"1.2"
 
 #include <linux/module.h>
 #include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/smp_lock.h>
+#include <linux/nvram.h>
 
 #define PC		1
-#define ATARI	2
+#define ATARI		2
+#define COBALT		3
 
 /* select machine configuration */
 #if defined(CONFIG_ATARI)
-#define MACH ATARI
-#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) /* and others?? */
+#  define MACH ATARI
+#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)  /* and others?? */
 #define MACH PC
+#  if defined(CONFIG_COBALT)
+#    include <linux/cobalt-nvram.h>
+#    define MACH COBALT
+#  else
+#    define MACH PC
+#  endif
 #else
-#error Cannot build nvram driver for this machine configuration.
+#  error Cannot build nvram driver for this machine configuration.
 #endif
 
 #if MACH == PC
 
 /* RTC in a PC */
-#define CHECK_DRIVER_INIT() 1
+#define CHECK_DRIVER_INIT()	1
 
 /* On PCs, the checksum is built only over bytes 2..31 */
 #define PC_CKS_RANGE_START	2
 #define PC_CKS_RANGE_END	31
-#define PC_CKS_LOC			32
+#define PC_CKS_LOC		32
+#define NVRAM_BYTES		(128-NVRAM_FIRST_BYTE)
 
-#define	mach_check_checksum	pc_check_checksum
-#define	mach_set_checksum	pc_set_checksum
-#define	mach_proc_infos		pc_proc_infos
+#define mach_check_checksum	pc_check_checksum
+#define mach_set_checksum	pc_set_checksum
+#define mach_proc_infos		pc_proc_infos
+
+#endif
+
+#if MACH == COBALT
+
+#define CHECK_DRIVER_INIT()     1
+
+#define NVRAM_BYTES		(128-NVRAM_FIRST_BYTE)
+
+#define mach_check_checksum	cobalt_check_checksum
+#define mach_set_checksum	cobalt_set_checksum
+#define mach_proc_infos		cobalt_proc_infos
 
 #endif
 
@@ -70,18 +95,18 @@
 /* Special parameters for RTC in Atari machines */
 #include <asm/atarihw.h>
 #include <asm/atariints.h>
-#define RTC_PORT(x)			(TT_RTC_BAS + 2*(x))
-#define CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
+#define RTC_PORT(x)		(TT_RTC_BAS + 2*(x))
+#define CHECK_DRIVER_INIT()	(MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
 
 /* On Ataris, the checksum is over all bytes except the checksum bytes
  * themselves; these are at the very end */
 #define ATARI_CKS_RANGE_START	0
-#define ATARI_CKS_RANGE_END		47
-#define ATARI_CKS_LOC			48
+#define ATARI_CKS_RANGE_END	47
+#define ATARI_CKS_LOC		48
 
-#define	mach_check_checksum	atari_check_checksum
-#define	mach_set_checksum	atari_set_checksum
-#define	mach_proc_infos		atari_proc_infos
+#define mach_check_checksum	atari_check_checksum
+#define mach_set_checksum	atari_set_checksum
+#define mach_proc_infos		atari_proc_infos
 
 #endif
 
@@ -98,7 +123,6 @@
 #include <linux/ioport.h>
 #include <linux/fcntl.h>
 #include <linux/mc146818rtc.h>
-#include <linux/nvram.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/spinlock.h>
@@ -107,289 +131,304 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
+static spinlock_t nvram_state_lock = SPIN_LOCK_UNLOCKED;
 static int nvram_open_cnt;	/* #times opened */
-static int nvram_open_mode;		/* special open modes */
-#define	NVRAM_WRITE		1		/* opened for writing (exclusive) */
-#define	NVRAM_EXCL		2		/* opened with O_EXCL */
+static int nvram_open_mode;	/* special open modes */
+#define NVRAM_WRITE		1 /* opened for writing (exclusive) */
+#define NVRAM_EXCL		2 /* opened with O_EXCL */
 
-#define	RTC_FIRST_BYTE		14	/* RTC register number of first NVRAM byte */
-#define	NVRAM_BYTES			128-RTC_FIRST_BYTE	/* number of NVRAM bytes */
+static int mach_check_checksum(void);
+static void mach_set_checksum(void);
 
-
-static int mach_check_checksum( void );
-static void mach_set_checksum( void );
 #ifdef CONFIG_PROC_FS
-static int mach_proc_infos( unsigned char *contents, char *buffer, int *len,
-							off_t *begin, off_t offset, int size );
+static int mach_proc_infos(unsigned char *contents, char *buffer, int *len,
+    off_t *begin, off_t offset, int size);
 #endif
 
-
 /*
- * These are the internal NVRAM access functions, which do NOT disable
- * interrupts and do not check the checksum. Both tasks are left to higher
- * level function, so they need to be done only once per syscall.
+ * These functions are provided to be called internally or by other parts of
+ * the kernel. It's up to the caller to ensure correct checksum before reading
+ * or after writing (needs to be done only once).
+ *
+ * It is worth noting that these functions all access bytes of general
+ * purpose memory in the NVRAM - that is to say, they all add the
+ * NVRAM_FIRST_BYTE offset.  Pass them offsets into NVRAM as if you did not 
+ * know about the RTC cruft.
  */
 
-static __inline__ unsigned char nvram_read_int( int i )
+unsigned char
+__nvram_read_byte(int i)
 {
-	return( CMOS_READ( RTC_FIRST_BYTE+i ) );
+	return CMOS_READ(NVRAM_FIRST_BYTE + i);
 }
 
-static __inline__ void nvram_write_int( unsigned char c, int i )
+unsigned char
+nvram_read_byte(int i)
 {
-	CMOS_WRITE( c, RTC_FIRST_BYTE+i );
-}
+	unsigned long flags;
+	unsigned char c;
 
-static __inline__ int nvram_check_checksum_int( void )
-{
-	return( mach_check_checksum() );
+	spin_lock_irqsave(&rtc_lock, flags);
+	c = __nvram_read_byte(i);
+	spin_unlock_irqrestore(&rtc_lock, flags);
+	return c;
 }
 
-static __inline__ void nvram_set_checksum_int( void )
+/* This races nicely with trying to read with checksum checking (nvram_read) */
+void
+__nvram_write_byte(unsigned char c, int i)
 {
-	mach_set_checksum();
+	CMOS_WRITE(c, NVRAM_FIRST_BYTE + i);
 }
 
-#if MACH == ATARI
-
-/*
- * These non-internal functions are provided to be called by other parts of
- * the kernel. It's up to the caller to ensure correct checksum before reading
- * or after writing (needs to be done only once).
- *
- * They're only built if CONFIG_ATARI is defined, because Atari drivers use
- * them. For other configurations (PC), the rest of the kernel can't rely on
- * them being present (this driver may not be configured at all, or as a
- * module), so they access config information themselves.
- */
-
-unsigned char nvram_read_byte( int i )
+void
+nvram_write_byte(unsigned char c, int i)
 {
 	unsigned long flags;
-	unsigned char c;
 
-	spin_lock_irqsave (&rtc_lock, flags);
-	c = nvram_read_int( i );
-	spin_unlock_irqrestore (&rtc_lock, flags);
-	return( c );
+	spin_lock_irqsave(&rtc_lock, flags);
+	__nvram_write_byte(c, i);
+	spin_unlock_irqrestore(&rtc_lock, flags);
 }
 
-/* This races nicely with trying to read with checksum checking (nvram_read) */
-void nvram_write_byte( unsigned char c, int i )
+int
+__nvram_check_checksum(void)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave (&rtc_lock, flags);
-	nvram_write_int( c, i );
-	spin_unlock_irqrestore (&rtc_lock, flags);
+	return mach_check_checksum();
 }
 
-int nvram_check_checksum( void )
+int
+nvram_check_checksum(void)
 {
 	unsigned long flags;
 	int rv;
 
-	spin_lock_irqsave (&rtc_lock, flags);
-	rv = nvram_check_checksum_int();
-	spin_unlock_irqrestore (&rtc_lock, flags);
-	return( rv );
+	spin_lock_irqsave(&rtc_lock, flags);
+	rv = __nvram_check_checksum();
+	spin_unlock_irqrestore(&rtc_lock, flags);
+	return rv;
 }
 
-void nvram_set_checksum( void )
+void
+__nvram_set_checksum(void)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave (&rtc_lock, flags);
-	nvram_set_checksum_int();
-	spin_unlock_irqrestore (&rtc_lock, flags);
+	mach_set_checksum();
 }
 
-#endif /* MACH == ATARI */
+void
+nvram_set_checksum(void)
+{
+	unsigned long flags;
 
+	spin_lock_irqsave(&rtc_lock, flags);
+	__nvram_set_checksum();
+	spin_unlock_irqrestore(&rtc_lock, flags);
+}
 
 /*
  * The are the file operation function for user access to /dev/nvram
  */
 
-static long long nvram_llseek(struct file *file,loff_t offset, int origin )
+static long long
+nvram_llseek(struct file *file, loff_t offset, int origin)
 {
-	switch( origin ) {
-	  case 0:
+	switch (origin) {
+	case 0:
 		/* nothing to do */
 		break;
-	  case 1:
+	case 1:
 		offset += file->f_pos;
 		break;
-	  case 2:
+	case 2:
 		offset += NVRAM_BYTES;
 		break;
 	}
-	return( (offset >= 0) ? (file->f_pos = offset) : -EINVAL );
+	return (offset >= 0) ? (file->f_pos = offset) : -EINVAL;
 }
 
-static ssize_t nvram_read(struct file * file,
-	char * buf, size_t count, loff_t *ppos )
+static ssize_t
+nvram_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 {
-	char contents [NVRAM_BYTES];
+	unsigned char contents[NVRAM_BYTES];
 	unsigned i = *ppos;
-	char *tmp;
+	unsigned char *tmp;
 
-	spin_lock_irq (&rtc_lock);
-	
-	if (!nvram_check_checksum_int())
+	spin_lock_irq(&rtc_lock);
+
+	if (!__nvram_check_checksum())
 		goto checksum_err;
 
 	for (tmp = contents; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp)
-		*tmp = nvram_read_int(i);
+		*tmp = __nvram_read_byte(i);
 
-	spin_unlock_irq (&rtc_lock);
+	spin_unlock_irq(&rtc_lock);
 
-	if (copy_to_user (buf, contents, tmp - contents))
+	if (copy_to_user(buf, contents, tmp - contents))
 		return -EFAULT;
 
 	*ppos = i;
 
-	return (tmp - contents);
+	return tmp - contents;
 
-checksum_err:
-	spin_unlock_irq (&rtc_lock);
+      checksum_err:
+	spin_unlock_irq(&rtc_lock);
 	return -EIO;
 }
 
-static ssize_t nvram_write(struct file * file,
-		const char * buf, size_t count, loff_t *ppos )
+static ssize_t
+nvram_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
-	char contents [NVRAM_BYTES];
+	unsigned char contents[NVRAM_BYTES];
 	unsigned i = *ppos;
-	char * tmp;
+	unsigned char *tmp;
+	int len;
 
-	if (copy_from_user (contents, buf, (NVRAM_BYTES - i) < count ?
-						(NVRAM_BYTES - i) : count))
+	len = (NVRAM_BYTES - i) < count ? (NVRAM_BYTES - i) : count;
+	if (copy_from_user(contents, buf, len))
 		return -EFAULT;
 
-	spin_lock_irq (&rtc_lock);
+	spin_lock_irq(&rtc_lock);
 
-	if (!nvram_check_checksum_int())
+	if (!__nvram_check_checksum())
 		goto checksum_err;
 
 	for (tmp = contents; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp)
-		nvram_write_int (*tmp, i);
+		__nvram_write_byte(*tmp, i);
 
-	nvram_set_checksum_int();
+	__nvram_set_checksum();
 
-	spin_unlock_irq (&rtc_lock);
+	spin_unlock_irq(&rtc_lock);
 
 	*ppos = i;
 
-	return (tmp - contents);
+	return tmp - contents;
 
-checksum_err:
-	spin_unlock_irq (&rtc_lock);
+      checksum_err:
+	spin_unlock_irq(&rtc_lock);
 	return -EIO;
 }
 
-static int nvram_ioctl( struct inode *inode, struct file *file,
-						unsigned int cmd, unsigned long arg )
+static int
+nvram_ioctl(struct inode *inode, struct file *file,
+    unsigned int cmd, unsigned long arg)
 {
 	int i;
-	
-	switch( cmd ) {
 
-	  case NVRAM_INIT:			/* initialize NVRAM contents and checksum */
+	switch (cmd) {
+
+	case NVRAM_INIT:
+		/* initialize NVRAM contents and checksum */
 		if (!capable(CAP_SYS_ADMIN))
-			return( -EACCES );
+			return -EACCES;
+
+		spin_lock_irq(&rtc_lock);
 
-		spin_lock_irq (&rtc_lock);
+		for (i = 0; i < NVRAM_BYTES; ++i)
+			__nvram_write_byte(0, i);
+		__nvram_set_checksum();
 
-		for( i = 0; i < NVRAM_BYTES; ++i )
-			nvram_write_int( 0, i );
-		nvram_set_checksum_int();
-		
-		spin_unlock_irq (&rtc_lock);
-		return( 0 );
-	  
-	  case NVRAM_SETCKS:		/* just set checksum, contents unchanged
-								 * (maybe useful after checksum garbaged
-								 * somehow...) */
+		spin_unlock_irq(&rtc_lock);
+		return 0;
+
+	case NVRAM_SETCKS:
+		/* just set checksum, contents unchanged (maybe useful after 
+		 * checksum garbaged somehow...) */
 		if (!capable(CAP_SYS_ADMIN))
-			return( -EACCES );
+			return -EACCES;
 
-		spin_lock_irq (&rtc_lock);
-		nvram_set_checksum_int();
-		spin_unlock_irq (&rtc_lock);
-		return( 0 );
+		spin_lock_irq(&rtc_lock);
+		__nvram_set_checksum();
+		spin_unlock_irq(&rtc_lock);
+		return 0;
 
-	  default:
-		return( -ENOTTY );
+	default:
+		return -ENOTTY;
 	}
 }
 
-static int nvram_open( struct inode *inode, struct file *file )
+static int
+nvram_open(struct inode *inode, struct file *file)
 {
+	spin_lock(&nvram_state_lock);
+
 	if ((nvram_open_cnt && (file->f_flags & O_EXCL)) ||
-		(nvram_open_mode & NVRAM_EXCL) ||
-		((file->f_mode & 2) && (nvram_open_mode & NVRAM_WRITE)))
-		return( -EBUSY );
+	    (nvram_open_mode & NVRAM_EXCL) ||
+	    ((file->f_mode & 2) && (nvram_open_mode & NVRAM_WRITE))) {
+		spin_unlock(&nvram_state_lock);
+		return -EBUSY;
+	}
 
 	if (file->f_flags & O_EXCL)
 		nvram_open_mode |= NVRAM_EXCL;
 	if (file->f_mode & 2)
 		nvram_open_mode |= NVRAM_WRITE;
 	nvram_open_cnt++;
-	return( 0 );
+
+	spin_unlock(&nvram_state_lock);
+
+	return 0;
 }
 
-static int nvram_release( struct inode *inode, struct file *file )
+static int
+nvram_release(struct inode *inode, struct file *file)
 {
-	lock_kernel();
+	spin_lock(&nvram_state_lock);
+
 	nvram_open_cnt--;
-	if (file->f_flags & O_EXCL)
+
+	/* if only one instance is open, clear the EXCL bit */
+	if (nvram_open_mode & NVRAM_EXCL)
 		nvram_open_mode &= ~NVRAM_EXCL;
 	if (file->f_mode & 2)
 		nvram_open_mode &= ~NVRAM_WRITE;
-	unlock_kernel();
 
-	return( 0 );
-}
+	spin_unlock(&nvram_state_lock);
 
+	return 0;
+}
 
 #ifndef CONFIG_PROC_FS
-static int nvram_read_proc( char *buffer, char **start, off_t offset,
-			    int size, int *eof, void *data) { return 0; }
+static int
+nvram_read_proc(char *buffer, char **start, off_t offset,
+    int size, int *eof, void *data)
+{
+	return 0;
+}
 #else
 
-static int nvram_read_proc( char *buffer, char **start, off_t offset,
-							int size, int *eof, void *data )
+static int
+nvram_read_proc(char *buffer, char **start, off_t offset,
+    int size, int *eof, void *data)
 {
 	unsigned char contents[NVRAM_BYTES];
-    int i, len = 0;
-    off_t begin = 0;
+	int i, len = 0;
+	off_t begin = 0;
+
+	spin_lock_irq(&rtc_lock);
+	for (i = 0; i < NVRAM_BYTES; ++i)
+		contents[i] = __nvram_read_byte(i);
+	spin_unlock_irq(&rtc_lock);
+
+	*eof = mach_proc_infos(contents, buffer, &len, &begin, offset, size);
+
+	if (offset >= begin + len)
+		return 0;
+	*start = buffer + (offset - begin);
+	return (size < begin + len - offset) ? size : begin + len - offset;
 
-	spin_lock_irq (&rtc_lock);
-	for( i = 0; i < NVRAM_BYTES; ++i )
-		contents[i] = nvram_read_int( i );
-	spin_unlock_irq (&rtc_lock);
-	
-	*eof = mach_proc_infos( contents, buffer, &len, &begin, offset, size );
-
-    if (offset >= begin + len)
-		return( 0 );
-    *start = buffer + (offset - begin);
-    return( size < begin + len - offset ? size : begin + len - offset );
-	
 }
 
 /* This macro frees the machine specific function from bounds checking and
  * this like that... */
-#define	PRINT_PROC(fmt,args...)							\
-	do {												\
-		*len += sprintf( buffer+*len, fmt, ##args );	\
-		if (*begin + *len > offset + size)				\
-			return( 0 );								\
-		if (*begin + *len < offset) {					\
-			*begin += *len;								\
-			*len = 0;									\
-		}												\
+#define PRINT_PROC(fmt,args...)					\
+	do {							\
+		*len += sprintf(buffer+*len, fmt, ##args);	\
+		if (*begin + *len > offset + size)		\
+			return 0;				\
+		if (*begin + *len < offset) {			\
+			*begin += *len;				\
+			*len = 0;				\
+		}						\
 	} while(0)
 
 #endif /* CONFIG_PROC_FS */
@@ -410,72 +449,76 @@
 	&nvram_fops
 };
 
-
-static int __init nvram_init(void)
+static int __init
+nvram_init(void)
 {
 	int ret;
 
 	/* First test whether the driver should init at all */
 	if (!CHECK_DRIVER_INIT())
-	    return( -ENXIO );
+		return -ENXIO;
 
-	ret = misc_register( &nvram_dev );
+	ret = misc_register(&nvram_dev);
 	if (ret) {
-		printk(KERN_ERR "nvram: can't misc_register on minor=%d\n", NVRAM_MINOR);
+		printk(KERN_ERR "nvram: can't misc_register on minor=%d\n",
+		    NVRAM_MINOR);
 		goto out;
 	}
-	if (!create_proc_read_entry("driver/nvram",0,0,nvram_read_proc,NULL)) {
+	if (!create_proc_read_entry("driver/nvram", 0, 0, nvram_read_proc,
+		NULL)) {
 		printk(KERN_ERR "nvram: can't create /proc/driver/nvram\n");
 		ret = -ENOMEM;
 		goto outmisc;
 	}
 	ret = 0;
 	printk(KERN_INFO "Non-volatile memory driver v" NVRAM_VERSION "\n");
-out:
-	return( ret );
-outmisc:
-	misc_deregister( &nvram_dev );
+      out:
+	return ret;
+      outmisc:
+	misc_deregister(&nvram_dev);
 	goto out;
 }
 
-static void __exit nvram_cleanup_module (void)
+static void __exit
+nvram_cleanup_module(void)
 {
-	remove_proc_entry( "driver/nvram", 0 );
-	misc_deregister( &nvram_dev );
+	remove_proc_entry("driver/nvram", 0);
+	misc_deregister(&nvram_dev);
 }
 
 module_init(nvram_init);
 module_exit(nvram_cleanup_module);
 
-
 /*
  * Machine specific functions
  */
 
-
 #if MACH == PC
 
-static int pc_check_checksum( void )
+static int
+pc_check_checksum(void)
 {
 	int i;
 	unsigned short sum = 0;
-	
-	for( i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i )
-		sum += nvram_read_int( i );
-	return( (sum & 0xffff) ==
-			((nvram_read_int(PC_CKS_LOC) << 8) |
-			 nvram_read_int(PC_CKS_LOC+1)) );
+	unsigned short expect;
+
+	for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
+		sum += __nvram_read_byte(i);
+	expect = __nvram_read_byte(PC_CKS_LOC)<<8 |
+	    __nvram_read_byte(PC_CKS_LOC+1);
+	return ((sum & 0xffff) == expect);
 }
 
-static void pc_set_checksum( void )
+static void
+pc_set_checksum(void)
 {
 	int i;
 	unsigned short sum = 0;
-	
-	for( i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i )
-		sum += nvram_read_int( i );
-	nvram_write_int( sum >> 8, PC_CKS_LOC );
-	nvram_write_int( sum & 0xff, PC_CKS_LOC+1 );
+
+	for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
+		sum += __nvram_read_byte(i);
+	__nvram_write_byte(sum >> 8, PC_CKS_LOC);
+	__nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1);
 }
 
 #ifdef CONFIG_PROC_FS
@@ -492,96 +535,267 @@
 	"monochrome",
 };
 
-static int pc_proc_infos( unsigned char *nvram, char *buffer, int *len,
-						  off_t *begin, off_t offset, int size )
+static int
+pc_proc_infos(unsigned char *nvram, char *buffer, int *len,
+    off_t *begin, off_t offset, int size)
 {
 	int checksum;
 	int type;
 
-	spin_lock_irq (&rtc_lock);
-	checksum = nvram_check_checksum_int();
-	spin_unlock_irq (&rtc_lock);
-
-	PRINT_PROC( "Checksum status: %svalid\n", checksum ? "" : "not " );
-
-	PRINT_PROC( "# floppies     : %d\n",
-				(nvram[6] & 1) ? (nvram[6] >> 6) + 1 : 0 );
-	PRINT_PROC( "Floppy 0 type  : " );
+	spin_lock_irq(&rtc_lock);
+	checksum = __nvram_check_checksum();
+	spin_unlock_irq(&rtc_lock);
+
+	PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not ");
+
+	PRINT_PROC("# floppies     : %d\n",
+	    (nvram[6] & 1) ? (nvram[6] >> 6) + 1 : 0);
+	PRINT_PROC("Floppy 0 type  : ");
 	type = nvram[2] >> 4;
-	if (type < sizeof(floppy_types)/sizeof(*floppy_types))
-		PRINT_PROC( "%s\n", floppy_types[type] );
+	if (type < sizeof (floppy_types) / sizeof (*floppy_types))
+		PRINT_PROC("%s\n", floppy_types[type]);
 	else
-		PRINT_PROC( "%d (unknown)\n", type );
-	PRINT_PROC( "Floppy 1 type  : " );
+		PRINT_PROC("%d (unknown)\n", type);
+	PRINT_PROC("Floppy 1 type  : ");
 	type = nvram[2] & 0x0f;
-	if (type < sizeof(floppy_types)/sizeof(*floppy_types))
-		PRINT_PROC( "%s\n", floppy_types[type] );
+	if (type < sizeof (floppy_types) / sizeof (*floppy_types))
+		PRINT_PROC("%s\n", floppy_types[type]);
 	else
-		PRINT_PROC( "%d (unknown)\n", type );
+		PRINT_PROC("%d (unknown)\n", type);
 
-	PRINT_PROC( "HD 0 type      : " );
+	PRINT_PROC("HD 0 type      : ");
 	type = nvram[4] >> 4;
 	if (type)
-		PRINT_PROC( "%02x\n", type == 0x0f ? nvram[11] : type );
+		PRINT_PROC("%02x\n", type == 0x0f ? nvram[11] : type);
 	else
-		PRINT_PROC( "none\n" );
+		PRINT_PROC("none\n");
 
-	PRINT_PROC( "HD 1 type      : " );
+	PRINT_PROC("HD 1 type      : ");
 	type = nvram[4] & 0x0f;
 	if (type)
-		PRINT_PROC( "%02x\n", type == 0x0f ? nvram[12] : type );
+		PRINT_PROC("%02x\n", type == 0x0f ? nvram[12] : type);
 	else
-		PRINT_PROC( "none\n" );
+		PRINT_PROC("none\n");
 
-	PRINT_PROC( "HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
-				nvram[18] | (nvram[19] << 8),
-				nvram[20], nvram[25],
-				nvram[21] | (nvram[22] << 8),
-				nvram[23] | (nvram[24] << 8) );
-	PRINT_PROC( "HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
-				nvram[39] | (nvram[40] << 8),
-				nvram[41], nvram[46],
-				nvram[42] | (nvram[43] << 8),
-				nvram[44] | (nvram[45] << 8) );
-
-	PRINT_PROC( "DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8) );
-	PRINT_PROC( "Extended memory: %d kB (configured), %d kB (tested)\n",
-				nvram[9] | (nvram[10] << 8),
-				nvram[34] | (nvram[35] << 8) );
-
-	PRINT_PROC( "Gfx adapter    : %s\n", gfx_types[ (nvram[6] >> 4)&3 ] );
-
-	PRINT_PROC( "FPU            : %sinstalled\n",
-				(nvram[6] & 2) ? "" : "not " );
-	
-	return( 1 );
+	PRINT_PROC("HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
+	    nvram[18] | (nvram[19] << 8),
+	    nvram[20], nvram[25],
+	    nvram[21] | (nvram[22] << 8), nvram[23] | (nvram[24] << 8));
+	PRINT_PROC("HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
+	    nvram[39] | (nvram[40] << 8),
+	    nvram[41], nvram[46],
+	    nvram[42] | (nvram[43] << 8), nvram[44] | (nvram[45] << 8));
+
+	PRINT_PROC("DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8));
+	PRINT_PROC("Extended memory: %d kB (configured), %d kB (tested)\n",
+	    nvram[9] | (nvram[10] << 8), nvram[34] | (nvram[35] << 8));
+
+	PRINT_PROC("Gfx adapter    : %s\n", gfx_types[(nvram[6] >> 4) & 3]);
+
+	PRINT_PROC("FPU            : %sinstalled\n",
+	    (nvram[6] & 2) ? "" : "not ");
+
+	return 1;
 }
 #endif
 
 #endif /* MACH == PC */
 
+#if MACH == COBALT
+
+/* the cobalt CMOS has a wider range of it's checksum */
+static int cobalt_check_checksum(void)
+{
+	int i;
+	unsigned short sum = 0;
+	unsigned short expect;
+
+	for (i = COBT_CMOS_CKS_START; i <= COBT_CMOS_CKS_END; ++i) {
+		if ((i == COBT_CMOS_CHECKSUM) || (i == (COBT_CMOS_CHECKSUM+1)))
+			continue;
+
+		sum += __nvram_read_byte(i);
+	}
+	expect = __nvram_read_byte(COBT_CMOS_CHECKSUM) << 8 |
+	    __nvram_read_byte(COBT_CMOS_CHECKSUM+1);
+	return ((sum & 0xffff) == expect);
+}
+
+static void cobalt_set_checksum(void)
+{
+	int i;
+	unsigned short sum = 0;
+
+	for (i = COBT_CMOS_CKS_START; i <= COBT_CMOS_CKS_END; ++i) {
+		if ((i == COBT_CMOS_CHECKSUM) || (i == (COBT_CMOS_CHECKSUM+1)))
+			continue;
+
+		sum += __nvram_read_byte(i);
+	}
+
+	__nvram_write_byte(sum >> 8, COBT_CMOS_CHECKSUM);
+	__nvram_write_byte(sum & 0xff, COBT_CMOS_CHECKSUM+1);
+}
+
+#ifdef CONFIG_PROC_FS
+
+static int cobalt_proc_infos(unsigned char *nvram, char *buffer, int *len,
+	off_t *begin, off_t offset, int size)
+{
+	int i;
+	unsigned int checksum;
+	unsigned int flags;
+	char sernum[14];
+	char *key = "cNoEbTaWlOtR!";
+	unsigned char bto_csum;
+
+	spin_lock_irq(&rtc_lock);
+	checksum = __nvram_check_checksum();
+	spin_unlock_irq(&rtc_lock);
+
+	PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not ");
+
+	flags = nvram[COBT_CMOS_FLAG_BYTE_0] << 8 
+	    | nvram[COBT_CMOS_FLAG_BYTE_1];
+
+	PRINT_PROC("Console: %s\n",
+		flags & COBT_CMOS_CONSOLE_FLAG ?  "on": "off");
+
+	PRINT_PROC("Firmware Debug Messages: %s\n",
+		flags & COBT_CMOS_DEBUG_FLAG ? "on": "off");
+
+	PRINT_PROC("Auto Prompt: %s\n",
+		flags & COBT_CMOS_AUTO_PROMPT_FLAG ? "on": "off");
+
+	PRINT_PROC("Shutdown Status: %s\n",
+		flags & COBT_CMOS_CLEAN_BOOT_FLAG ? "clean": "dirty");
+
+	PRINT_PROC("Hardware Probe: %s\n",
+		flags & COBT_CMOS_HW_NOPROBE_FLAG ? "partial": "full");
+
+	PRINT_PROC("System Fault: %sdetected\n",
+		flags & COBT_CMOS_SYSFAULT_FLAG ? "": "not ");
+
+	PRINT_PROC("Panic on OOPS: %s\n",
+		flags & COBT_CMOS_OOPSPANIC_FLAG ? "yes": "no");
+
+	PRINT_PROC("Delayed Cache Initialization: %s\n",
+		flags & COBT_CMOS_DELAY_CACHE_FLAG ? "yes": "no");
+
+	PRINT_PROC("Show Logo at Boot: %s\n",
+		flags & COBT_CMOS_NOLOGO_FLAG ? "no": "yes");
+
+	PRINT_PROC("Boot Method: ");
+	switch (nvram[COBT_CMOS_BOOT_METHOD]) {
+	case COBT_CMOS_BOOT_METHOD_DISK:
+		PRINT_PROC("disk\n");
+		break;
+
+	case COBT_CMOS_BOOT_METHOD_ROM:
+		PRINT_PROC("rom\n");
+		break;
+
+	case COBT_CMOS_BOOT_METHOD_NET:
+		PRINT_PROC("net\n");
+		break;
+
+	default:
+		PRINT_PROC("unknown\n");
+		break;
+	}
+
+	PRINT_PROC("Primary Boot Device: %d:%d\n",
+		nvram[COBT_CMOS_BOOT_DEV0_MAJ],
+		nvram[COBT_CMOS_BOOT_DEV0_MIN] );
+	PRINT_PROC("Secondary Boot Device: %d:%d\n",
+		nvram[COBT_CMOS_BOOT_DEV1_MAJ],
+		nvram[COBT_CMOS_BOOT_DEV1_MIN] );
+	PRINT_PROC("Tertiary Boot Device: %d:%d\n",
+		nvram[COBT_CMOS_BOOT_DEV2_MAJ],
+		nvram[COBT_CMOS_BOOT_DEV2_MIN] );
+
+	PRINT_PROC("Uptime: %d\n",
+		nvram[COBT_CMOS_UPTIME_0] << 24 |
+		nvram[COBT_CMOS_UPTIME_1] << 16 |
+		nvram[COBT_CMOS_UPTIME_2] << 8  |
+		nvram[COBT_CMOS_UPTIME_3]);
+
+	PRINT_PROC("Boot Count: %d\n",
+		nvram[COBT_CMOS_BOOTCOUNT_0] << 24 |
+		nvram[COBT_CMOS_BOOTCOUNT_1] << 16 |
+		nvram[COBT_CMOS_BOOTCOUNT_2] << 8  |
+		nvram[COBT_CMOS_BOOTCOUNT_3]);
+
+	/* 13 bytes of serial num */
+	for (i=0 ; i<13 ; i++) {
+		sernum[i] = nvram[COBT_CMOS_SYS_SERNUM_0 + i];
+	}
+	sernum[13] = '\0';
+
+	checksum = 0;
+	for (i=0 ; i<13 ; i++) {
+		checksum += sernum[i] ^ key[i];
+	}
+	checksum = ((checksum & 0x7f) ^ (0xd6)) & 0xff;
+
+	PRINT_PROC("Serial Number: %s", sernum);
+	if (checksum != nvram[COBT_CMOS_SYS_SERNUM_CSUM]) {
+		PRINT_PROC(" (invalid checksum)");
+	}
+	PRINT_PROC("\n");
+
+	PRINT_PROC("Rom Revison: %d.%d.%d\n", nvram[COBT_CMOS_ROM_REV_MAJ],
+		nvram[COBT_CMOS_ROM_REV_MIN], nvram[COBT_CMOS_ROM_REV_REV]);
+
+	PRINT_PROC("BTO Server: %d.%d.%d.%d", nvram[COBT_CMOS_BTO_IP_0],
+		nvram[COBT_CMOS_BTO_IP_1], nvram[COBT_CMOS_BTO_IP_2],
+		nvram[COBT_CMOS_BTO_IP_3]);
+	bto_csum = nvram[COBT_CMOS_BTO_IP_0] + nvram[COBT_CMOS_BTO_IP_1]
+		+ nvram[COBT_CMOS_BTO_IP_2] + nvram[COBT_CMOS_BTO_IP_3];
+	if (bto_csum != nvram[COBT_CMOS_BTO_IP_CSUM]) {
+		PRINT_PROC(" (invalid checksum)");
+	}
+	PRINT_PROC("\n");
+
+	if (flags & COBT_CMOS_VERSION_FLAG
+	 && nvram[COBT_CMOS_VERSION] >= COBT_CMOS_VER_BTOCODE) {
+		PRINT_PROC("BTO Code: 0x%x\n",
+			nvram[COBT_CMOS_BTO_CODE_0] << 24 |
+			nvram[COBT_CMOS_BTO_CODE_1] << 16 |
+			nvram[COBT_CMOS_BTO_CODE_2] << 8 |
+			nvram[COBT_CMOS_BTO_CODE_3]);
+	}
+
+	return 1;
+}
+#endif /* CONFIG_PROC_FS */
+
+#endif /* MACH == COBALT */
+
 #if MACH == ATARI
 
-static int atari_check_checksum( void )
+static int
+atari_check_checksum(void)
 {
 	int i;
 	unsigned char sum = 0;
-	
-	for( i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i )
-		sum += nvram_read_int( i );
-	return( nvram_read_int( ATARI_CKS_LOC ) == (~sum & 0xff) &&
-			nvram_read_int( ATARI_CKS_LOC+1 ) == (sum & 0xff) );
+
+	for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
+		sum += __nvram_read_byte(i);
+	return (__nvram_read_byte(ATARI_CKS_LOC) == (~sum & 0xff) &&
+	    __nvram_read_byte(ATARI_CKS_LOC + 1) == (sum & 0xff));
 }
 
-static void atari_set_checksum( void )
+static void
+atari_set_checksum(void)
 {
 	int i;
 	unsigned char sum = 0;
-	
-	for( i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i )
-		sum += nvram_read_int( i );
-	nvram_write_int( ~sum, ATARI_CKS_LOC );
-	nvram_write_int( sum, ATARI_CKS_LOC+1 );
+
+	for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
+		sum += __nvram_read_byte(i);
+	__nvram_write_byte(~sum, ATARI_CKS_LOC);
+	__nvram_write_byte(sum, ATARI_CKS_LOC + 1);
 }
 
 #ifdef CONFIG_PROC_FS
@@ -626,70 +840,71 @@
 
 #define fieldsize(a)	(sizeof(a)/sizeof(*a))
 
-static int atari_proc_infos( unsigned char *nvram, char *buffer, int *len,
-			    off_t *begin, off_t offset, int size )
+static int
+atari_proc_infos(unsigned char *nvram, char *buffer, int *len,
+    off_t *begin, off_t offset, int size)
 {
 	int checksum = nvram_check_checksum();
 	int i;
 	unsigned vmode;
-	
-	PRINT_PROC( "Checksum status  : %svalid\n", checksum ? "" : "not " );
 
-	PRINT_PROC( "Boot preference  : " );
-	for( i = fieldsize(boot_prefs)-1; i >= 0; --i ) {
+	PRINT_PROC("Checksum status  : %svalid\n", checksum ? "" : "not ");
+
+	PRINT_PROC("Boot preference  : ");
+	for (i = fieldsize(boot_prefs) - 1; i >= 0; --i) {
 		if (nvram[1] == boot_prefs[i].val) {
-			PRINT_PROC( "%s\n", boot_prefs[i].name );
+			PRINT_PROC("%s\n", boot_prefs[i].name);
 			break;
 		}
 	}
 	if (i < 0)
-		PRINT_PROC( "0x%02x (undefined)\n", nvram[1] );
+		PRINT_PROC("0x%02x (undefined)\n", nvram[1]);
 
-	PRINT_PROC( "SCSI arbitration : %s\n", (nvram[16] & 0x80) ? "on" : "off" );
-	PRINT_PROC( "SCSI host ID     : " );
+	PRINT_PROC("SCSI arbitration : %s\n",
+	    (nvram[16] & 0x80) ? "on" : "off");
+	PRINT_PROC("SCSI host ID     : ");
 	if (nvram[16] & 0x80)
-		PRINT_PROC( "%d\n", nvram[16] & 7 );
+		PRINT_PROC("%d\n", nvram[16] & 7);
 	else
-		PRINT_PROC( "n/a\n" );
+		PRINT_PROC("n/a\n");
 
 	/* the following entries are defined only for the Falcon */
 	if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON)
 		return 1;
 
-	PRINT_PROC( "OS language      : " );
+	PRINT_PROC("OS language      : ");
 	if (nvram[6] < fieldsize(languages))
-		PRINT_PROC( "%s\n", languages[nvram[6]] );
+		PRINT_PROC("%s\n", languages[nvram[6]]);
 	else
-		PRINT_PROC( "%u (undefined)\n", nvram[6] );
-	PRINT_PROC( "Keyboard language: " );
+		PRINT_PROC("%u (undefined)\n", nvram[6]);
+	PRINT_PROC("Keyboard language: ");
 	if (nvram[7] < fieldsize(languages))
-		PRINT_PROC( "%s\n", languages[nvram[7]] );
+		PRINT_PROC("%s\n", languages[nvram[7]]);
 	else
-		PRINT_PROC( "%u (undefined)\n", nvram[7] );
-	PRINT_PROC( "Date format      : " );
-	PRINT_PROC( dateformat[nvram[8]&7],
-				nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/' );
-	PRINT_PROC( ", %dh clock\n", nvram[8] & 16 ? 24 : 12 );
-	PRINT_PROC( "Boot delay       : " );
+		PRINT_PROC("%u (undefined)\n", nvram[7]);
+	PRINT_PROC("Date format      : ");
+	PRINT_PROC(dateformat[nvram[8] & 7],
+	    nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/');
+	PRINT_PROC(", %dh clock\n", nvram[8] & 16 ? 24 : 12);
+	PRINT_PROC("Boot delay       : ");
 	if (nvram[10] == 0)
-		PRINT_PROC( "default" );
+		PRINT_PROC("default");
 	else
-		PRINT_PROC( "%ds%s\n", nvram[10],
-					nvram[10] < 8 ? ", no memory test" : "" );
+		PRINT_PROC("%ds%s\n", nvram[10],
+		    nvram[10] < 8 ? ", no memory test" : "");
 
 	vmode = (nvram[14] << 8) || nvram[15];
-	PRINT_PROC( "Video mode       : %s colors, %d columns, %s %s monitor\n",
-				colors[vmode & 7],
-				vmode & 8 ? 80 : 40,
-				vmode & 16 ? "VGA" : "TV",
-				vmode & 32 ? "PAL" : "NTSC" );
-	PRINT_PROC( "                   %soverscan, compat. mode %s%s\n",
-				vmode & 64 ? "" : "no ",
-				vmode & 128 ? "on" : "off",
-				vmode & 256 ?
-				  (vmode & 16 ? ", line doubling" : ", half screen") : "" );
-		
-	return( 1 );
+	PRINT_PROC("Video mode       : %s colors, %d columns, %s %s monitor\n",
+	    colors[vmode & 7],
+	    vmode & 8 ? 80 : 40,
+	    vmode & 16 ? "VGA" : "TV", vmode & 32 ? "PAL" : "NTSC");
+	PRINT_PROC("                   %soverscan, compat. mode %s%s\n",
+	    vmode & 64 ? "" : "no ",
+	    vmode & 128 ? "on" : "off",
+	    vmode & 256 ?
+	    (vmode & 16 ? ", line doubling" : ", half screen") : "");
+
+	return 1;
 }
 #endif
 
@@ -697,12 +912,11 @@
 
 MODULE_LICENSE("GPL");
 
-EXPORT_NO_SYMBOLS;
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  tab-width: 4
- * End:
- */
-
+EXPORT_SYMBOL(__nvram_read_byte);
+EXPORT_SYMBOL(nvram_read_byte);
+EXPORT_SYMBOL(__nvram_write_byte);
+EXPORT_SYMBOL(nvram_write_byte);
+EXPORT_SYMBOL(__nvram_check_checksum);
+EXPORT_SYMBOL(nvram_check_checksum);
+EXPORT_SYMBOL(__nvram_set_checksum);
+EXPORT_SYMBOL(nvram_set_checksum);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/pc_keyb.c linux-2.4.20/drivers/char/pc_keyb.c
--- linux-2.4.19/drivers/char/pc_keyb.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/pc_keyb.c	2002-10-29 11:18:39.000000000 +0000
@@ -69,6 +69,9 @@
 static int aux_reconnect = 0;
 #endif
 
+#ifndef kbd_controller_present
+#define kbd_controller_present()	1
+#endif
 static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
 static unsigned char handle_kbd_event(void);
 
@@ -895,6 +898,11 @@
 
 void __init pckbd_init_hw(void)
 {
+	if (!kbd_controller_present()) {
+		kbd_exists = 0;
+		return;
+	}
+
 	kbd_request_region();
 
 	/* Flush any pending input. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/pcmcia/Config.in linux-2.4.20/drivers/char/pcmcia/Config.in
--- linux-2.4.19/drivers/char/pcmcia/Config.in	2001-03-07 03:28:35.000000000 +0000
+++ linux-2.4.20/drivers/char/pcmcia/Config.in	2002-10-29 11:18:32.000000000 +0000
@@ -10,5 +10,7 @@
    define_bool CONFIG_PCMCIA_CHRDEV y
 fi
 
+tristate 'SyncLink PC Card support' CONFIG_SYNCLINK_CS
+
 endmenu
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/pcmcia/Makefile linux-2.4.20/drivers/char/pcmcia/Makefile
--- linux-2.4.19/drivers/char/pcmcia/Makefile	2001-03-07 03:28:35.000000000 +0000
+++ linux-2.4.20/drivers/char/pcmcia/Makefile	2002-10-29 11:18:33.000000000 +0000
@@ -16,5 +16,6 @@
 obj-		:=
 
 obj-$(CONFIG_PCMCIA_SERIAL_CS)	+= serial_cs.o
+obj-$(CONFIG_SYNCLINK_CS) += synclink_cs.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/pcmcia/synclink_cs.c linux-2.4.20/drivers/char/pcmcia/synclink_cs.c
--- linux-2.4.19/drivers/char/pcmcia/synclink_cs.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/pcmcia/synclink_cs.c	2002-10-29 11:18:47.000000000 +0000
@@ -0,0 +1,4568 @@
+/*
+ * linux/drivers/char/synclink_cs.c
+ *
+ * $Id: synclink_cs.c,v 3.4 2002/04/22 14:36:41 paulkf Exp $
+ *
+ * Device driver for Microgate SyncLink PC Card
+ * multiprotocol serial adapter.
+ *
+ * written by Paul Fulghum for Microgate Corporation
+ * paulkf@microgate.com
+ *
+ * Microgate and SyncLink are trademarks of Microgate Corporation
+ *
+ * This code is released under the GNU General Public License (GPL)
+ *
+ * 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.
+ */
+
+#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
+#if defined(__i386__)
+#  define BREAKPOINT() asm("   int $3");
+#else
+#  define BREAKPOINT() { }
+#endif
+
+#define MAX_DEVICE_COUNT 4
+
+#include <linux/config.h>	
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <asm/serial.h>
+#include <linux/delay.h>
+#include <linux/ioctl.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/bitops.h>
+#include <asm/types.h>
+#include <linux/termios.h>
+#include <linux/tqueue.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/bus_ops.h>
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE
+#define CONFIG_SYNCLINK_SYNCPPP 1
+#endif
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+#if LINUX_VERSION_CODE < VERSION(2,4,3) 
+#include "../net/wan/syncppp.h"
+#else
+#include <net/syncppp.h>
+#endif
+#endif
+
+#include <asm/segment.h>
+#define GET_USER(error,value,addr) error = get_user(value,addr)
+#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
+#define PUT_USER(error,value,addr) error = put_user(value,addr)
+#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
+
+#include <asm/uaccess.h>
+
+#include "linux/synclink.h"
+
+static MGSL_PARAMS default_params = {
+	MGSL_MODE_HDLC,			/* unsigned long mode */
+	0,				/* unsigned char loopback; */
+	HDLC_FLAG_UNDERRUN_ABORT15,	/* unsigned short flags; */
+	HDLC_ENCODING_NRZI_SPACE,	/* unsigned char encoding; */
+	0,				/* unsigned long clock_speed; */
+	0xff,				/* unsigned char addr_filter; */
+	HDLC_CRC_16_CCITT,		/* unsigned short crc_type; */
+	HDLC_PREAMBLE_LENGTH_8BITS,	/* unsigned char preamble_length; */
+	HDLC_PREAMBLE_PATTERN_NONE,	/* unsigned char preamble; */
+	9600,				/* unsigned long data_rate; */
+	8,				/* unsigned char data_bits; */
+	1,				/* unsigned char stop_bits; */
+	ASYNC_PARITY_NONE		/* unsigned char parity; */
+};
+
+typedef struct
+{
+	int count;
+	unsigned char status;
+	char data[1];
+} RXBUF;
+
+/* The queue of BH actions to be performed */
+
+#define BH_RECEIVE  1
+#define BH_TRANSMIT 2
+#define BH_STATUS   4
+
+#define IO_PIN_SHUTDOWN_LIMIT 100
+
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+struct _input_signal_events {
+	int	ri_up;	
+	int	ri_down;
+	int	dsr_up;
+	int	dsr_down;
+	int	dcd_up;
+	int	dcd_down;
+	int	cts_up;
+	int	cts_down;
+};
+
+
+/*
+ * Device instance data structure
+ */
+ 
+typedef struct _mgslpc_info {
+	void *if_ptr;	/* General purpose pointer (used by SPPP) */
+	int			magic;
+	int			flags;
+	int			count;		/* count of opens */
+	int			line;
+	unsigned short		close_delay;
+	unsigned short		closing_wait;	/* time to wait before closing */
+	
+	struct mgsl_icount	icount;
+	
+	struct termios		normal_termios;
+	struct termios		callout_termios;
+	
+	struct tty_struct 	*tty;
+	int			timeout;
+	int			x_char;		/* xon/xoff character */
+	int			blocked_open;	/* # of blocked opens */
+	long			session;	/* Session of opening process */
+	long			pgrp;		/* pgrp of opening process */
+	unsigned char		read_status_mask;
+	unsigned char		ignore_status_mask;	
+
+	unsigned char *tx_buf;
+	int            tx_put;
+	int            tx_get;
+	int            tx_count;
+
+	/* circular list of fixed length rx buffers */
+
+	unsigned char  *rx_buf;        /* memory allocated for all rx buffers */
+	int            rx_buf_total_size; /* size of memory allocated for rx buffers */
+	int            rx_put;         /* index of next empty rx buffer */
+	int            rx_get;         /* index of next full rx buffer */
+	int            rx_buf_size;    /* size in bytes of single rx buffer */
+	int            rx_buf_count;   /* total number of rx buffers */
+	int            rx_frame_count; /* number of full rx buffers */
+	
+	wait_queue_head_t	open_wait;
+	wait_queue_head_t	close_wait;
+	
+	wait_queue_head_t	status_event_wait_q;
+	wait_queue_head_t	event_wait_q;
+	struct timer_list	tx_timer;	/* HDLC transmit timeout timer */
+	struct _mgslpc_info	*next_device;	/* device list link */
+
+	unsigned short imra_value;
+	unsigned short imrb_value;
+	unsigned char  pim_value;
+
+	spinlock_t lock;
+	struct tq_struct task;		/* task structure for scheduling bh */
+
+	u32 max_frame_size;
+
+	u32 pending_bh;
+
+	int bh_running;
+	int bh_requested;
+	
+	int dcd_chkcount; /* check counts to prevent */
+	int cts_chkcount; /* too many IRQs if a signal */
+	int dsr_chkcount; /* is floating */
+	int ri_chkcount;
+
+	int rx_enabled;
+	int rx_overflow;
+
+	int tx_enabled;
+	int tx_active;
+	int tx_aborting;
+	u32 idle_mode;
+
+	int if_mode; /* serial interface selection (RS-232, v.35 etc) */
+
+	char device_name[25];		/* device instance name */
+
+	unsigned int io_base;	/* base I/O address of adapter */
+	unsigned int irq_level;
+	
+	MGSL_PARAMS params;		/* communications parameters */
+
+	unsigned char serial_signals;	/* current serial signal states */
+
+	char irq_occurred;		/* for diagnostics use */
+	char testing_irq;
+	unsigned int init_error;	/* startup error (DIAGS)	*/
+
+	char flag_buf[MAX_ASYNC_BUFFER_SIZE];
+	BOOLEAN drop_rts_on_tx_done;
+
+	struct	_input_signal_events	input_signal_events;
+
+	/* PCMCIA support */
+	dev_link_t	      link;
+	dev_node_t	      node;
+	int		      stop;
+	struct bus_operations *bus;
+
+	/* SPPP/Cisco HDLC device parts */
+	int netcount;
+	int dosyncppp;
+	spinlock_t netlock;
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+	struct ppp_device pppdev;
+	char netname[10];
+	struct net_device *netdev;
+	struct net_device_stats netstats;
+	struct net_device netdevice;
+#endif
+} MGSLPC_INFO;
+
+#define MGSLPC_MAGIC 0x5402
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define TXBUFSIZE 4096
+
+    
+#define CHA     0x00   /* channel A offset */
+#define CHB     0x40   /* channel B offset */
+    
+#define RXFIFO  0
+#define TXFIFO  0
+#define STAR    0x20
+#define CMDR    0x20
+#define RSTA    0x21
+#define PRE     0x21
+#define MODE    0x22
+#define TIMR    0x23
+#define XAD1    0x24
+#define XAD2    0x25
+#define RAH1    0x26
+#define RAH2    0x27
+#define DAFO    0x27
+#define RAL1    0x28
+#define RFC     0x28
+#define RHCR    0x29
+#define RAL2    0x29
+#define RBCL    0x2a
+#define XBCL    0x2a
+#define RBCH    0x2b
+#define XBCH    0x2b
+#define CCR0    0x2c
+#define CCR1    0x2d
+#define CCR2    0x2e
+#define CCR3    0x2f
+#define VSTR    0x34
+#define BGR     0x34
+#define RLCR    0x35
+#define AML     0x36
+#define AMH     0x37
+#define GIS     0x38
+#define IVA     0x38
+#define IPC     0x39
+#define ISR     0x3a
+#define IMR     0x3a
+#define PVR     0x3c
+#define PIS     0x3d
+#define PIM     0x3d
+#define PCR     0x3e
+#define CCR4    0x3f
+    
+// IMR/ISR
+    
+#define IRQ_BREAK_ON    BIT15   // rx break detected
+#define IRQ_DATAOVERRUN BIT14	// receive data overflow
+#define IRQ_ALLSENT     BIT13	// all sent
+#define IRQ_UNDERRUN    BIT12	// transmit data underrun
+#define IRQ_TIMER       BIT11	// timer interrupt
+#define IRQ_CTS         BIT10	// CTS status change
+#define IRQ_TXREPEAT    BIT9	// tx message repeat
+#define IRQ_TXFIFO      BIT8	// transmit pool ready
+#define IRQ_RXEOM       BIT7	// receive message end
+#define IRQ_EXITHUNT    BIT6	// receive frame start
+#define IRQ_RXTIME      BIT6    // rx char timeout
+#define IRQ_DCD         BIT2	// carrier detect status change
+#define IRQ_OVERRUN     BIT1	// receive frame overflow
+#define IRQ_RXFIFO      BIT0	// receive pool full
+    
+// STAR
+    
+#define XFW   BIT6		// transmit FIFO write enable
+#define CEC   BIT2		// command executing
+#define CTS   BIT1		// CTS state
+    
+#define PVR_DTR      BIT0
+#define PVR_DSR      BIT1
+#define PVR_RI       BIT2
+#define PVR_AUTOCTS  BIT3
+#define PVR_RS232    0x20   /* 0010b */
+#define PVR_V35      0xe0   /* 1110b */
+#define PVR_RS422    0x40   /* 0100b */
+    
+/* Register access functions */ 
+    
+#define write_reg(info, reg, val) outb((val),(info)->io_base + (reg))
+#define read_reg(info, reg) inb((info)->io_base + (reg))
+
+#define read_reg16(info, reg) inw((info)->io_base + (reg))  
+#define write_reg16(info, reg, val) outw((val), (info)->io_base + (reg))
+    
+#define set_reg_bits(info, reg, mask) \
+    write_reg(info, (reg), \
+		 (unsigned char) (read_reg(info, (reg)) | (mask)))  
+#define clear_reg_bits(info, reg, mask) \
+    write_reg(info, (reg), \
+		 (unsigned char) (read_reg(info, (reg)) & ~(mask)))  
+/*
+ * interrupt enable/disable routines
+ */ 
+static void irq_disable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask) 
+{
+	if (channel == CHA) {
+		info->imra_value |= mask;
+		write_reg16(info, CHA + IMR, info->imra_value);
+	} else {
+		info->imrb_value |= mask;
+		write_reg16(info, CHB + IMR, info->imrb_value);
+	}
+}
+static void irq_enable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask) 
+{
+	if (channel == CHA) {
+		info->imra_value &= ~mask;
+		write_reg16(info, CHA + IMR, info->imra_value);
+	} else {
+		info->imrb_value &= ~mask;
+		write_reg16(info, CHB + IMR, info->imrb_value);
+	}
+}
+
+#define port_irq_disable(info, mask) \
+  { info->pim_value |= (mask); write_reg(info, PIM, info->pim_value); }
+
+#define port_irq_enable(info, mask) \
+  { info->pim_value &= ~(mask); write_reg(info, PIM, info->pim_value); }
+
+static void rx_start(MGSLPC_INFO *info);
+static void rx_stop(MGSLPC_INFO *info);
+
+static void tx_start(MGSLPC_INFO *info);
+static void tx_stop(MGSLPC_INFO *info);
+static void tx_set_idle(MGSLPC_INFO *info);
+
+static void get_signals(MGSLPC_INFO *info);
+static void set_signals(MGSLPC_INFO *info);
+
+static void reset_device(MGSLPC_INFO *info);
+
+static void hdlc_mode(MGSLPC_INFO *info);
+static void async_mode(MGSLPC_INFO *info);
+
+static void tx_timeout(unsigned long context);
+
+static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg);
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+/* SPPP/HDLC stuff */
+static void mgslpc_sppp_init(MGSLPC_INFO *info);
+static void mgslpc_sppp_delete(MGSLPC_INFO *info);
+static int  mgslpc_sppp_open(struct net_device *d);
+static int  mgslpc_sppp_close(struct net_device *d);
+static void mgslpc_sppp_tx_timeout(struct net_device *d);
+static int  mgslpc_sppp_tx(struct sk_buff *skb, struct net_device *d);
+static void mgslpc_sppp_rx_done(MGSLPC_INFO *info, char *buf, int size);
+static void mgslpc_sppp_tx_done(MGSLPC_INFO *info);
+static int  mgslpc_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+struct net_device_stats *mgslpc_net_stats(struct net_device *dev);
+#endif
+
+static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit);
+
+static BOOLEAN register_test(MGSLPC_INFO *info);
+static BOOLEAN irq_test(MGSLPC_INFO *info);
+static int adapter_test(MGSLPC_INFO *info);
+
+static int claim_resources(MGSLPC_INFO *info);
+static void release_resources(MGSLPC_INFO *info);
+static void mgslpc_add_device(MGSLPC_INFO *info);
+static void mgslpc_remove_device(MGSLPC_INFO *info);
+
+static int  rx_get_frame(MGSLPC_INFO *info);
+static void rx_reset_buffers(MGSLPC_INFO *info);
+static int  rx_alloc_buffers(MGSLPC_INFO *info);
+static void rx_free_buffers(MGSLPC_INFO *info);
+
+static void mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs);
+
+/*
+ * Bottom half interrupt handlers
+ */
+static void bh_handler(void* Context);
+static void bh_transmit(MGSLPC_INFO *info);
+static void bh_status(MGSLPC_INFO *info);
+
+/*
+ * ioctl handlers
+ */
+static int set_modem_info(MGSLPC_INFO *info, unsigned int cmd,
+			  unsigned int *value);
+static int get_modem_info(MGSLPC_INFO *info, unsigned int *value);
+static int get_stats(MGSLPC_INFO *info, struct mgsl_icount *user_icount);
+static int get_params(MGSLPC_INFO *info, MGSL_PARAMS *user_params);
+static int set_params(MGSLPC_INFO *info, MGSL_PARAMS *new_params);
+static int get_txidle(MGSLPC_INFO *info, int*idle_mode);
+static int set_txidle(MGSLPC_INFO *info, int idle_mode);
+static int set_txenable(MGSLPC_INFO *info, int enable);
+static int tx_abort(MGSLPC_INFO *info);
+static int set_rxenable(MGSLPC_INFO *info, int enable);
+static int wait_events(MGSLPC_INFO *info, int *mask);
+
+#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
+
+static MGSLPC_INFO *mgslpc_device_list = NULL;
+static int mgslpc_device_count = 0;
+
+/*
+ * Set this param to non-zero to load eax with the
+ * .text section address and breakpoint on module load.
+ * This is useful for use with gdb and add-symbol-file command.
+ */
+static int break_on_load=0;
+
+/*
+ * Driver major number, defaults to zero to get auto
+ * assigned major number. May be forced as module parameter.
+ */
+static int ttymajor=0;
+static int cuamajor=0;
+
+static int debug_level = 0;
+static int maxframe[MAX_DEVICE_COUNT] = {0,};
+
+/* The old way: bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static u_int irq_mask = 0xdeb8;
+
+/* Newer, simpler way of listing specific interrupts */
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+MODULE_PARM(break_on_load,"i");
+MODULE_PARM(ttymajor,"i");
+MODULE_PARM(cuamajor,"i");
+MODULE_PARM(debug_level,"i");
+MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICE_COUNT) "i");
+
+static char *driver_name = "SyncLink PC Card driver";
+static char *driver_version = "$Revision: 3.4 $";
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+static void mgslpc_change_params(MGSLPC_INFO *info);
+static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout);
+
+static struct tty_struct *serial_table[MAX_DEVICE_COUNT];
+static struct termios *serial_termios[MAX_DEVICE_COUNT];
+static struct termios *serial_termios_locked[MAX_DEVICE_COUNT];
+
+#ifndef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#endif
+
+/* PCMCIA prototypes */
+
+static void mgslpc_config(dev_link_t *link);
+static void mgslpc_release(u_long arg);
+static int  mgslpc_event(event_t event, int priority,
+			 event_callback_args_t *args);
+static dev_link_t *mgslpc_attach(void);
+static void mgslpc_detach(dev_link_t *);
+
+static dev_info_t dev_info = "synclink_cs";
+static dev_link_t *dev_list = NULL;
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*
+ * 1st function defined in .text section. Calling this function in
+ * init_module() followed by a breakpoint allows a remote debugger
+ * (gdb) to get the .text address for the add-symbol-file command.
+ * This allows remote debugging of dynamically loadable modules.
+ */
+static void* mgslpc_get_text_ptr(void);
+static void* mgslpc_get_text_ptr() {return mgslpc_get_text_ptr;}
+
+static dev_link_t *mgslpc_attach(void)
+{
+    MGSLPC_INFO *info;
+    dev_link_t *link;
+    client_reg_t client_reg;
+    int ret, i;
+    
+    if (debug_level >= DEBUG_LEVEL_INFO)
+	    printk("mgslpc_attach\n");
+	
+    info = (MGSLPC_INFO *)kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
+    if (!info) {
+	    printk("Error can't allocate device instance data\n");
+	    return NULL;
+    }
+
+    memset(info, 0, sizeof(MGSLPC_INFO));
+    info->magic = MGSLPC_MAGIC;
+    info->task.sync = 0;
+    info->task.routine = bh_handler;
+    info->task.data    = info;
+    info->max_frame_size = 4096;
+    info->close_delay = 5*HZ/10;
+    info->closing_wait = 30*HZ;
+    init_waitqueue_head(&info->open_wait);
+    init_waitqueue_head(&info->close_wait);
+    init_waitqueue_head(&info->status_event_wait_q);
+    init_waitqueue_head(&info->event_wait_q);
+    spin_lock_init(&info->lock);
+    spin_lock_init(&info->netlock);
+    memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS));
+    info->idle_mode = HDLC_TXIDLE_FLAGS;		
+    info->imra_value = 0xffff;
+    info->imrb_value = 0xffff;
+    info->pim_value = 0xff;
+
+    link = &info->link;
+    link->priv = info;
+    
+    /* Initialize the dev_link_t structure */
+    link->release.function = &mgslpc_release;
+    link->release.data = (u_long)link;
+
+    /* Interrupt setup */
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1   = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	    link->irq.IRQInfo2 = irq_mask;
+    else
+	    for (i = 0; i < 4; i++)
+		    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.Handler = NULL;
+    
+    link->conf.Attributes = 0;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &mgslpc_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+	    cs_error(link->handle, RegisterClient, ret);
+	    mgslpc_detach(link);
+	    return NULL;
+    }
+
+    mgslpc_add_device(info);
+
+    memset(serial_table,0,sizeof(struct tty_struct*)*MAX_DEVICE_COUNT);
+    memset(serial_termios,0,sizeof(struct termios*)*MAX_DEVICE_COUNT);
+    memset(serial_termios_locked,0,sizeof(struct termios*)*MAX_DEVICE_COUNT);
+		
+    info->callout_termios = callout_driver.init_termios;
+    info->normal_termios  = serial_driver.init_termios;
+
+    return link;
+}
+
+/* Card has been inserted.
+ */
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
+
+static void mgslpc_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    MGSLPC_INFO *info = link->priv;
+    tuple_t tuple;
+    cisparse_t parse;
+    int last_fn, last_ret;
+    u_char buf[64];
+    config_info_t conf;
+    cistpl_cftable_entry_t dflt = { 0 };
+    cistpl_cftable_entry_t *cfg;
+    
+    if (debug_level >= DEBUG_LEVEL_INFO)
+	    printk("mgslpc_config(0x%p)\n", link);
+
+    /* read CONFIG tuple to find its configuration registers */
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    tuple.Attributes = 0;
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = sizeof(buf);
+    tuple.TupleOffset = 0;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* Look up the current Vcc */
+    CS_CHECK(GetConfigurationInfo, handle, &conf);
+    link->conf.Vcc = conf.Vcc;
+
+    /* get CIS configuration entry */
+
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+
+    cfg = &(parse.cftable_entry);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+
+    if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
+    if (cfg->index == 0)
+	    goto cs_failed;
+
+    link->conf.ConfigIndex = cfg->index;
+    link->conf.Attributes |= CONF_ENABLE_IRQ;
+	
+    /* IO window settings */
+    link->io.NumPorts1 = 0;
+    if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+	    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+	    if (!(io->flags & CISTPL_IO_8BIT))
+		    link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+	    if (!(io->flags & CISTPL_IO_16BIT))
+		    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+	    link->io.BasePort1 = io->win[0].base;
+	    link->io.NumPorts1 = io->win[0].len;
+	    CS_CHECK(RequestIO, link->handle, &link->io);
+    }
+
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.ConfigIndex = 8;
+    link->conf.Present = PRESENT_OPTION;
+    
+    link->irq.Attributes |= IRQ_HANDLE_PRESENT;
+    link->irq.Handler     = mgslpc_isr;
+    link->irq.Instance    = info;
+    CS_CHECK(RequestIRQ, link->handle, &link->irq);
+
+    CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+
+    info->io_base = link->io.BasePort1;
+    info->irq_level = link->irq.AssignedIRQ;
+
+    /* add to linked list of devices */
+    sprintf(info->node.dev_name, "mgslpc0");
+    info->node.major = info->node.minor = 0;
+    link->dev = &info->node;
+
+    printk(KERN_INFO "%s: index 0x%02x:",
+	   info->node.dev_name, link->conf.ConfigIndex);
+    if (link->conf.Attributes & CONF_ENABLE_IRQ)
+	    printk(", irq %d", link->irq.AssignedIRQ);
+    if (link->io.NumPorts1)
+	    printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+		   link->io.BasePort1+link->io.NumPorts1-1);
+    printk("\n");
+    
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+    mgslpc_release((u_long)link);
+}
+
+/* Card has been removed.
+ * Unregister device and release PCMCIA configuration.
+ * If device is open, postpone until it is closed.
+ */
+static void mgslpc_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+
+    if (debug_level >= DEBUG_LEVEL_INFO)
+	    printk("mgslpc_release(0x%p)\n", link);
+
+    if (link->open) {
+	    if (debug_level >= DEBUG_LEVEL_INFO)
+		    printk("synclink_cs: release postponed, '%s' still open\n",
+			   link->dev->dev_name);
+	    link->state |= DEV_STALE_CONFIG;
+	    return;
+    }
+
+    /* Unlink the device chain */
+    link->dev = NULL;
+    link->state &= ~DEV_CONFIG;
+
+    CardServices(ReleaseConfiguration, link->handle);
+    if (link->io.NumPorts1)
+	    CardServices(ReleaseIO, link->handle, &link->io);
+    if (link->irq.AssignedIRQ)
+	    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    if (link->state & DEV_STALE_LINK)
+	    mgslpc_detach(link);
+}
+
+static void mgslpc_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+
+    if (debug_level >= DEBUG_LEVEL_INFO)
+	    printk("mgslpc_detach(0x%p)\n", link);
+    
+    /* find device */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	    if (*linkp == link) break;
+    if (*linkp == NULL)
+	    return;
+
+    if (link->state & DEV_CONFIG) {
+	    /* device is configured/active, mark it so when
+	     * release() is called a proper detach() occurs.
+	     */
+	    if (debug_level >= DEBUG_LEVEL_INFO)
+		    printk(KERN_DEBUG "synclinkpc: detach postponed, '%s' "
+			   "still locked\n", link->dev->dev_name);
+	    link->state |= DEV_STALE_LINK;
+	    return;
+    }
+
+    /* Break the link with Card Services */
+    if (link->handle)
+	    CardServices(DeregisterClient, link->handle);
+    
+    /* Unlink device structure, and free it */
+    *linkp = link->next;
+    mgslpc_remove_device((MGSLPC_INFO *)link->priv);
+}
+
+static int mgslpc_event(event_t event, int priority,
+			event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    MGSLPC_INFO *info = link->priv;
+    
+    if (debug_level >= DEBUG_LEVEL_INFO)
+	    printk("mgslpc_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	    link->state &= ~DEV_PRESENT;
+	    if (link->state & DEV_CONFIG) {
+		    ((MGSLPC_INFO *)link->priv)->stop = 1;
+		    mod_timer(&link->release, jiffies + HZ/20);
+	    }
+	    break;
+    case CS_EVENT_CARD_INSERTION:
+	    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	    info->bus = args->bus;
+	    mgslpc_config(link);
+	    break;
+    case CS_EVENT_PM_SUSPEND:
+	    link->state |= DEV_SUSPEND;
+	    /* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	    /* Mark the device as stopped, to block IO until later */
+	    info->stop = 1;
+	    if (link->state & DEV_CONFIG)
+		    CardServices(ReleaseConfiguration, link->handle);
+	    break;
+    case CS_EVENT_PM_RESUME:
+	    link->state &= ~DEV_SUSPEND;
+	    /* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	    if (link->state & DEV_CONFIG)
+		    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    info->stop = 0;
+	    break;
+    }
+    return 0;
+}
+
+static inline int mgslpc_paranoia_check(MGSLPC_INFO *info,
+					kdev_t device, const char *routine)
+{
+#ifdef MGSLPC_PARANOIA_CHECK
+	static const char *badmagic =
+		"Warning: bad magic number for mgsl struct (%s) in %s\n";
+	static const char *badinfo =
+		"Warning: null mgslpc_info for (%s) in %s\n";
+
+	if (!info) {
+		printk(badinfo, kdevname(device), routine);
+		return 1;
+	}
+	if (info->magic != MGSLPC_MAGIC) {
+		printk(badmagic, kdevname(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+
+#define CMD_RXFIFO      BIT7	// release current rx FIFO
+#define CMD_RXRESET     BIT6	// receiver reset
+#define CMD_RXFIFO_READ BIT5
+#define CMD_START_TIMER BIT4
+#define CMD_TXFIFO      BIT3	// release current tx FIFO
+#define CMD_TXEOM       BIT1	// transmit end message
+#define CMD_TXRESET     BIT0	// transmit reset
+
+static BOOLEAN wait_command_complete(MGSLPC_INFO *info, unsigned char channel) 
+{
+	int i = 0;
+	unsigned char status;
+	/* wait for command completion */ 
+	while ((status = read_reg(info, (unsigned char)(channel+STAR)) & BIT2)) {
+		udelay(1);
+		if (i++ == 1000)
+			return FALSE;
+	}
+	return TRUE;
+}
+
+static void issue_command(MGSLPC_INFO *info, unsigned char channel, unsigned char cmd) 
+{
+	wait_command_complete(info, channel);
+	write_reg(info, (unsigned char) (channel + CMDR), cmd);
+}
+
+static void tx_pause(struct tty_struct *tty)
+{
+	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
+	unsigned long flags;
+	
+	if (mgslpc_paranoia_check(info, tty->device, "tx_pause"))
+		return;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("tx_pause(%s)\n",info->device_name);	
+		
+	spin_lock_irqsave(&info->lock,flags);
+	if (info->tx_enabled)
+	 	tx_stop(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+static void tx_release(struct tty_struct *tty)
+{
+	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
+	unsigned long flags;
+	
+	if (mgslpc_paranoia_check(info, tty->device, "tx_release"))
+		return;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("tx_release(%s)\n",info->device_name);	
+		
+	spin_lock_irqsave(&info->lock,flags);
+	if (!info->tx_enabled)
+	 	tx_start(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/* Return next bottom half action to perform.
+ * or 0 if nothing to do.
+ */
+int bh_action(MGSLPC_INFO *info)
+{
+	unsigned long flags;
+	int rc = 0;
+	
+	spin_lock_irqsave(&info->lock,flags);
+
+	if (info->pending_bh & BH_RECEIVE) {
+		info->pending_bh &= ~BH_RECEIVE;
+		rc = BH_RECEIVE;
+	} else if (info->pending_bh & BH_TRANSMIT) {
+		info->pending_bh &= ~BH_TRANSMIT;
+		rc = BH_TRANSMIT;
+	} else if (info->pending_bh & BH_STATUS) {
+		info->pending_bh &= ~BH_STATUS;
+		rc = BH_STATUS;
+	}
+
+	if (!rc) {
+		/* Mark BH routine as complete */
+		info->bh_running   = 0;
+		info->bh_requested = 0;
+	}
+	
+	spin_unlock_irqrestore(&info->lock,flags);
+	
+	return rc;
+}
+
+void bh_handler(void* Context)
+{
+	MGSLPC_INFO *info = (MGSLPC_INFO*)Context;
+	int action;
+
+	if (!info)
+		return;
+		
+	if (debug_level >= DEBUG_LEVEL_BH)
+		printk( "%s(%d):bh_handler(%s) entry\n",
+			__FILE__,__LINE__,info->device_name);
+	
+	info->bh_running = 1;
+
+	while((action = bh_action(info)) != 0) {
+	
+		/* Process work item */
+		if ( debug_level >= DEBUG_LEVEL_BH )
+			printk( "%s(%d):bh_handler() work item action=%d\n",
+				__FILE__,__LINE__,action);
+
+		switch (action) {
+		
+		case BH_RECEIVE:
+			while(rx_get_frame(info));
+			break;
+		case BH_TRANSMIT:
+			bh_transmit(info);
+			break;
+		case BH_STATUS:
+			bh_status(info);
+			break;
+		default:
+			/* unknown work item ID */
+			printk("Unknown work item ID=%08X!\n", action);
+			break;
+		}
+	}
+
+	if (debug_level >= DEBUG_LEVEL_BH)
+		printk( "%s(%d):bh_handler(%s) exit\n",
+			__FILE__,__LINE__,info->device_name);
+}
+
+void bh_transmit(MGSLPC_INFO *info)
+{
+	struct tty_struct *tty = info->tty;
+	if (debug_level >= DEBUG_LEVEL_BH)
+		printk("bh_transmit() entry on %s\n", info->device_name);
+
+	if (tty) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup) {
+			if ( debug_level >= DEBUG_LEVEL_BH )
+				printk( "%s(%d):calling ldisc.write_wakeup on %s\n",
+					__FILE__,__LINE__,info->device_name);
+			(tty->ldisc.write_wakeup)(tty);
+		}
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+void bh_status(MGSLPC_INFO *info)
+{
+	info->ri_chkcount = 0;
+	info->dsr_chkcount = 0;
+	info->dcd_chkcount = 0;
+	info->cts_chkcount = 0;
+}
+
+/* eom: non-zero = end of frame */ 
+void rx_ready_hdlc(MGSLPC_INFO *info, int eom) 
+{
+	unsigned char data[2];
+	unsigned char fifo_count, read_count, i;
+	RXBUF *buf = (RXBUF*)(info->rx_buf + (info->rx_put * info->rx_buf_size));
+
+	if (debug_level >= DEBUG_LEVEL_ISR)
+		printk("%s(%d):rx_ready_hdlc(eom=%d)\n",__FILE__,__LINE__,eom);
+	
+	if (!info->rx_enabled)
+		return;
+
+	if (info->rx_frame_count >= info->rx_buf_count) {
+		/* no more free buffers */
+		issue_command(info, CHA, CMD_RXRESET);
+		info->pending_bh |= BH_RECEIVE;
+		info->rx_overflow = 1;
+		info->icount.buf_overrun++;
+		return;
+	}
+
+	if (eom) {
+		/* end of frame, get FIFO count from RBCL register */ 
+		if (!(fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f)))
+			fifo_count = 32;
+	} else
+		fifo_count = 32;
+	
+	do {
+		if (fifo_count == 1) {
+			read_count = 1;
+			data[0] = read_reg(info, CHA + RXFIFO);
+		} else {
+			read_count = 2;
+			*((unsigned short *) data) = read_reg16(info, CHA + RXFIFO);
+		}
+		fifo_count -= read_count;
+		if (!fifo_count && eom)
+			buf->status = data[--read_count];
+
+		for (i = 0; i < read_count; i++) {
+			if (buf->count >= info->max_frame_size) {
+				/* frame too large, reset receiver and reset current buffer */
+				issue_command(info, CHA, CMD_RXRESET);
+				buf->count = 0;
+				return;
+			}
+			*(buf->data + buf->count) = data[i];
+			buf->count++;
+		}
+	} while (fifo_count);
+
+	if (eom) {
+		info->pending_bh |= BH_RECEIVE;
+		info->rx_frame_count++;
+		info->rx_put++;
+		if (info->rx_put >= info->rx_buf_count)
+			info->rx_put = 0;
+	}
+	issue_command(info, CHA, CMD_RXFIFO);
+}
+
+void rx_ready_async(MGSLPC_INFO *info, int tcd) 
+{
+	unsigned char data, status;
+	int fifo_count;
+ 	struct tty_struct *tty = info->tty;
+ 	struct mgsl_icount *icount = &info->icount;
+
+	if (tcd) {
+		/* early termination, get FIFO count from RBCL register */ 
+		fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f);
+
+		/* Zero fifo count could mean 0 or 32 bytes available.
+		 * If BIT5 of STAR is set then at least 1 byte is available.
+		 */
+		if (!fifo_count && (read_reg(info,CHA+STAR) & BIT5))
+			fifo_count = 32;
+	} else
+		fifo_count = 32;
+	
+	/* Flush received async data to receive data buffer. */ 
+	while (fifo_count) {
+		data   = read_reg(info, CHA + RXFIFO);
+		status = read_reg(info, CHA + RXFIFO);
+		fifo_count -= 2;
+
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+			break;
+			
+		*tty->flip.char_buf_ptr = data;
+		icount->rx++;
+		
+		*tty->flip.flag_buf_ptr = 0;
+
+		// if no frameing/crc error then save data
+		// BIT7:parity error
+		// BIT6:framing error
+
+		if (status & (BIT7 + BIT6)) {
+			if (status & BIT7) 
+				icount->parity++;
+			else
+				icount->frame++;
+
+			/* discard char if tty control flags say so */
+			if (status & info->ignore_status_mask)
+				continue;
+				
+			status &= info->read_status_mask;
+
+			if (status & BIT7)
+				*tty->flip.flag_buf_ptr = TTY_PARITY;
+			else if (status & BIT6)
+				*tty->flip.flag_buf_ptr = TTY_FRAME;
+		}
+		
+		tty->flip.flag_buf_ptr++;
+		tty->flip.char_buf_ptr++;
+		tty->flip.count++;
+	}
+	issue_command(info, CHA, CMD_RXFIFO);
+
+	if (debug_level >= DEBUG_LEVEL_ISR) {
+		printk("%s(%d):rx_ready_async count=%d\n",
+			__FILE__,__LINE__,tty->flip.count);
+		printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n",
+			__FILE__,__LINE__,icount->rx,icount->brk,
+			icount->parity,icount->frame,icount->overrun);
+	}
+			
+	if (tty->flip.count)
+		tty_flip_buffer_push(tty);
+}
+
+
+void tx_done(MGSLPC_INFO *info) 
+{
+	if (!info->tx_active)
+		return;
+			
+	info->tx_active = 0;
+	info->tx_aborting = 0;
+
+	if (info->params.mode == MGSL_MODE_ASYNC)
+		return;
+
+	info->tx_count = info->tx_put = info->tx_get = 0;
+	del_timer(&info->tx_timer);	
+	
+	if (info->drop_rts_on_tx_done) {
+		get_signals(info);
+		if (info->serial_signals & SerialSignal_RTS) {
+			info->serial_signals &= ~SerialSignal_RTS;
+			set_signals(info);
+		}
+		info->drop_rts_on_tx_done = 0;
+	}
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP	
+	if (info->netcount)
+		mgslpc_sppp_tx_done(info);
+	else 
+#endif
+	{
+		if (info->tty->stopped || info->tty->hw_stopped) {
+			tx_stop(info);
+			return;
+		}
+		info->pending_bh |= BH_TRANSMIT;
+	}
+}
+
+void tx_ready(MGSLPC_INFO *info) 
+{
+	unsigned char fifo_count = 32;
+	int c;
+
+	if (debug_level >= DEBUG_LEVEL_ISR)
+		printk("%s(%d):tx_ready(%s)\n", __FILE__,__LINE__,info->device_name);
+
+	if (info->params.mode == MGSL_MODE_HDLC) {
+		if (!info->tx_active)
+			return;
+	} else {
+		if (info->tty->stopped || info->tty->hw_stopped) {
+			tx_stop(info);
+			return;
+		}
+		if (!info->tx_count)
+			info->tx_active = 0;
+	}
+
+	if (!info->tx_count)
+		return;
+
+	while (info->tx_count && fifo_count) {
+		c = MIN(2, MIN(fifo_count, MIN(info->tx_count, TXBUFSIZE - info->tx_get)));
+		
+		if (c == 1) {
+			write_reg(info, CHA + TXFIFO, *(info->tx_buf + info->tx_get));
+		} else {
+			write_reg16(info, CHA + TXFIFO,
+					  *((unsigned short*)(info->tx_buf + info->tx_get)));
+		}
+		info->tx_count -= c;
+		info->tx_get = (info->tx_get + c) & (TXBUFSIZE - 1);
+		fifo_count -= c;
+	}
+
+	if (info->params.mode == MGSL_MODE_ASYNC) {
+		if (info->tx_count < WAKEUP_CHARS)
+			info->pending_bh |= BH_TRANSMIT;
+		issue_command(info, CHA, CMD_TXFIFO);
+	} else {
+		if (info->tx_count)
+			issue_command(info, CHA, CMD_TXFIFO);
+		else
+			issue_command(info, CHA, CMD_TXFIFO + CMD_TXEOM);
+	}
+}
+
+void cts_change(MGSLPC_INFO *info) 
+{
+	get_signals(info);
+	if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
+		irq_disable(info, CHB, IRQ_CTS);
+	info->icount.cts++;
+	if (info->serial_signals & SerialSignal_CTS)
+		info->input_signal_events.cts_up++;
+	else
+		info->input_signal_events.cts_down++;
+	wake_up_interruptible(&info->status_event_wait_q);
+	wake_up_interruptible(&info->event_wait_q);
+
+	if (info->flags & ASYNC_CTS_FLOW) {
+		if (info->tty->hw_stopped) {
+			if (info->serial_signals & SerialSignal_CTS) {
+				if (debug_level >= DEBUG_LEVEL_ISR)
+					printk("CTS tx start...");
+				if (info->tty)
+					info->tty->hw_stopped = 0;
+				tx_start(info);
+				info->pending_bh |= BH_TRANSMIT;
+				return;
+			}
+		} else {
+			if (!(info->serial_signals & SerialSignal_CTS)) {
+				if (debug_level >= DEBUG_LEVEL_ISR)
+					printk("CTS tx stop...");
+				if (info->tty)
+					info->tty->hw_stopped = 1;
+				tx_stop(info);
+			}
+		}
+	}
+	info->pending_bh |= BH_STATUS;
+}
+
+void dcd_change(MGSLPC_INFO *info) 
+{
+	get_signals(info);
+	if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
+		irq_disable(info, CHB, IRQ_DCD);
+	info->icount.dcd++;
+	if (info->serial_signals & SerialSignal_DCD) {
+		info->input_signal_events.dcd_up++;
+#ifdef CONFIG_SYNCLINK_SYNCPPP	
+		if (info->netcount)
+			sppp_reopen(info->netdev);
+#endif
+	}
+	else
+		info->input_signal_events.dcd_down++;
+	wake_up_interruptible(&info->status_event_wait_q);
+	wake_up_interruptible(&info->event_wait_q);
+
+	if (info->flags & ASYNC_CHECK_CD) {
+		if (debug_level >= DEBUG_LEVEL_ISR)
+			printk("%s CD now %s...", info->device_name,
+			       (info->serial_signals & SerialSignal_DCD) ? "on" : "off");
+		if (info->serial_signals & SerialSignal_DCD)
+			wake_up_interruptible(&info->open_wait);
+		else if (!(info->flags & (ASYNC_CALLOUT_ACTIVE | ASYNC_CALLOUT_NOHUP))) {
+			if (debug_level >= DEBUG_LEVEL_ISR)
+				printk("doing serial hangup...");
+			if (info->tty)
+				tty_hangup(info->tty);
+		}
+	}
+	info->pending_bh |= BH_STATUS;
+}
+
+void dsr_change(MGSLPC_INFO *info) 
+{
+	get_signals(info);
+	if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
+		port_irq_disable(info, PVR_DSR);
+	info->icount.dsr++;
+	if (info->serial_signals & SerialSignal_DSR)
+		info->input_signal_events.dsr_up++;
+	else
+		info->input_signal_events.dsr_down++;
+	wake_up_interruptible(&info->status_event_wait_q);
+	wake_up_interruptible(&info->event_wait_q);
+	info->pending_bh |= BH_STATUS;
+}
+
+void ri_change(MGSLPC_INFO *info) 
+{
+	get_signals(info);
+	if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
+		port_irq_disable(info, PVR_RI);
+	info->icount.rng++;
+	if (info->serial_signals & SerialSignal_RI)
+		info->input_signal_events.ri_up++;
+	else
+		info->input_signal_events.ri_down++;
+	wake_up_interruptible(&info->status_event_wait_q);
+	wake_up_interruptible(&info->event_wait_q);
+	info->pending_bh |= BH_STATUS;
+}
+
+/* Interrupt service routine entry point.
+ * 	
+ * Arguments:
+ * 
+ * irq     interrupt number that caused interrupt
+ * dev_id  device ID supplied during interrupt registration
+ * regs    interrupted processor context
+ */
+static void mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs)
+{
+	MGSLPC_INFO * info = (MGSLPC_INFO *)dev_id;
+	unsigned short isr;
+	unsigned char gis, pis;
+	int count=0;
+
+	if (debug_level >= DEBUG_LEVEL_ISR)	
+		printk("mgslpc_isr(%d) entry.\n", irq);
+	if (!info)
+		return;
+		
+	if (!(info->link.state & DEV_CONFIG))
+		return;
+
+	spin_lock(&info->lock);
+
+	while ((gis = read_reg(info, CHA + GIS))) {
+		if (debug_level >= DEBUG_LEVEL_ISR)	
+			printk("mgslpc_isr %s gis=%04X\n", info->device_name,gis);
+
+		if ((gis & 0x70) || count > 1000) {
+			printk("synclink_cs:hardware failed or ejected\n");
+			break;
+		}
+		count++;
+
+		if (gis & (BIT1 + BIT0)) {
+			isr = read_reg16(info, CHB + ISR);
+			if (isr & IRQ_DCD)
+				dcd_change(info);
+			if (isr & IRQ_CTS)
+				cts_change(info);
+		}
+		if (gis & (BIT3 + BIT2))
+		{
+			isr = read_reg16(info, CHA + ISR);
+			if (isr & IRQ_TIMER) {
+				info->irq_occurred = 1;
+				irq_disable(info, CHA, IRQ_TIMER);
+			}
+
+			/* receive IRQs */ 
+			if (isr & IRQ_EXITHUNT) {
+				info->icount.exithunt++;
+				wake_up_interruptible(&info->event_wait_q);
+			}
+			if (isr & IRQ_BREAK_ON) {
+				info->icount.brk++;
+				if (info->flags & ASYNC_SAK)
+					do_SAK(info->tty);
+			}
+			if (isr & IRQ_RXTIME) {
+				issue_command(info, CHA, CMD_RXFIFO_READ);
+			}
+			if (isr & (IRQ_RXEOM + IRQ_RXFIFO)) {
+				if (info->params.mode == MGSL_MODE_HDLC)
+					rx_ready_hdlc(info, isr & IRQ_RXEOM); 
+				else
+					rx_ready_async(info, isr & IRQ_RXEOM);
+			}
+
+			/* transmit IRQs */ 
+			if (isr & IRQ_UNDERRUN) {
+				if (info->tx_aborting)
+					info->icount.txabort++;
+				else
+					info->icount.txunder++;
+				tx_done(info);
+			}
+			else if (isr & IRQ_ALLSENT) {
+				info->icount.txok++;
+				tx_done(info);
+			}
+			else if (isr & IRQ_TXFIFO)
+				tx_ready(info);
+		}
+		if (gis & BIT7) {
+			pis = read_reg(info, CHA + PIS);
+			if (pis & BIT1)
+				dsr_change(info);
+			if (pis & BIT2)
+				ri_change(info);
+		}
+	}
+	
+	/* Request bottom half processing if there's something 
+	 * for it to do and the bh is not already running
+	 */
+
+	if (info->pending_bh && !info->bh_running && !info->bh_requested) {
+		if ( debug_level >= DEBUG_LEVEL_ISR )	
+			printk("%s(%d):%s queueing bh task.\n",
+				__FILE__,__LINE__,info->device_name);
+		queue_task(&info->task, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+		info->bh_requested = 1;
+	}
+
+	spin_unlock(&info->lock);
+	
+	if (debug_level >= DEBUG_LEVEL_ISR)	
+		printk("%s(%d):mgslpc_isr(%d)exit.\n",
+		       __FILE__,__LINE__,irq);
+}
+
+/* Initialize and start device.
+ */
+static int startup(MGSLPC_INFO * info)
+{
+	int retval = 0;
+	
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):startup(%s)\n",__FILE__,__LINE__,info->device_name);
+		
+	if (info->flags & ASYNC_INITIALIZED)
+		return 0;
+	
+	if (!info->tx_buf) {
+		/* allocate a page of memory for a transmit buffer */
+		info->tx_buf = (unsigned char *)get_free_page(GFP_KERNEL);
+		if (!info->tx_buf) {
+			printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n",
+				__FILE__,__LINE__,info->device_name);
+			return -ENOMEM;
+		}
+	}
+
+	info->pending_bh = 0;
+	
+	init_timer(&info->tx_timer);
+	info->tx_timer.data = (unsigned long)info;
+	info->tx_timer.function = tx_timeout;
+
+	/* Allocate and claim adapter resources */
+	retval = claim_resources(info);
+	
+	/* perform existance check and diagnostics */
+	if ( !retval )
+		retval = adapter_test(info);
+		
+	if ( retval ) {
+  		if (capable(CAP_SYS_ADMIN) && info->tty)
+			set_bit(TTY_IO_ERROR, &info->tty->flags);
+		release_resources(info);
+  		return retval;
+  	}
+
+	/* program hardware for current parameters */
+	mgslpc_change_params(info);
+	
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->flags |= ASYNC_INITIALIZED;
+	
+	return 0;
+}
+
+/* Called by mgslpc_close() and mgslpc_hangup() to shutdown hardware
+ */
+static void shutdown(MGSLPC_INFO * info)
+{
+	unsigned long flags;
+	
+	if (!(info->flags & ASYNC_INITIALIZED))
+		return;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_shutdown(%s)\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	/* clear status wait queue because status changes */
+	/* can't happen after shutting down the hardware */
+	wake_up_interruptible(&info->status_event_wait_q);
+	wake_up_interruptible(&info->event_wait_q);
+
+	del_timer(&info->tx_timer);	
+
+	if (info->tx_buf) {
+		free_page((unsigned long) info->tx_buf);
+		info->tx_buf = 0;
+	}
+
+	spin_lock_irqsave(&info->lock,flags);
+
+	rx_stop(info);
+	tx_stop(info);
+
+	/* TODO:disable interrupts instead of reset to preserve signal states */
+	reset_device(info);
+	
+ 	if (!info->tty || info->tty->termios->c_cflag & HUPCL) {
+ 		info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
+		set_signals(info);
+	}
+	
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	release_resources(info);	
+	
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->flags &= ~ASYNC_INITIALIZED;
+}
+
+static void mgslpc_program_hw(MGSLPC_INFO *info)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock,flags);
+	
+	rx_stop(info);
+	tx_stop(info);
+	info->tx_count = info->tx_put = info->tx_get = 0;
+	
+	if (info->params.mode == MGSL_MODE_HDLC || info->netcount)
+		hdlc_mode(info);
+	else
+		async_mode(info);
+		
+	set_signals(info);
+	
+	info->dcd_chkcount = 0;
+	info->cts_chkcount = 0;
+	info->ri_chkcount = 0;
+	info->dsr_chkcount = 0;
+
+	irq_enable(info, CHB, IRQ_DCD | IRQ_CTS);
+	port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI);
+	get_signals(info);
+		
+	if (info->netcount || info->tty->termios->c_cflag & CREAD)
+		rx_start(info);
+		
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/* Reconfigure adapter based on new parameters
+ */
+static void mgslpc_change_params(MGSLPC_INFO *info)
+{
+	unsigned cflag;
+	int bits_per_char;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+		
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_change_params(%s)\n",
+			 __FILE__,__LINE__, info->device_name );
+			 
+	cflag = info->tty->termios->c_cflag;
+
+	/* if B0 rate (hangup) specified then negate DTR and RTS */
+	/* otherwise assert DTR and RTS */
+ 	if (cflag & CBAUD)
+		info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+	else
+		info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
+	
+	/* byte size and parity */
+	
+	switch (cflag & CSIZE) {
+	case CS5: info->params.data_bits = 5; break;
+	case CS6: info->params.data_bits = 6; break;
+	case CS7: info->params.data_bits = 7; break;
+	case CS8: info->params.data_bits = 8; break;
+	default:  info->params.data_bits = 7; break;
+	}
+	      
+	if (cflag & CSTOPB)
+		info->params.stop_bits = 2;
+	else
+		info->params.stop_bits = 1;
+
+	info->params.parity = ASYNC_PARITY_NONE;
+	if (cflag & PARENB) {
+		if (cflag & PARODD)
+			info->params.parity = ASYNC_PARITY_ODD;
+		else
+			info->params.parity = ASYNC_PARITY_EVEN;
+#ifdef CMSPAR
+		if (cflag & CMSPAR)
+			info->params.parity = ASYNC_PARITY_SPACE;
+#endif
+	}
+
+	/* calculate number of jiffies to transmit a full
+	 * FIFO (32 bytes) at specified data rate
+	 */
+	bits_per_char = info->params.data_bits + 
+			info->params.stop_bits + 1;
+
+	/* if port data rate is set to 460800 or less then
+	 * allow tty settings to override, otherwise keep the
+	 * current data rate.
+	 */
+	if (info->params.data_rate <= 460800) {
+		info->params.data_rate = tty_get_baud_rate(info->tty);
+	}
+	
+	if ( info->params.data_rate ) {
+		info->timeout = (32*HZ*bits_per_char) / 
+				info->params.data_rate;
+	}
+	info->timeout += HZ/50;		/* Add .02 seconds of slop */
+
+	if (cflag & CRTSCTS)
+		info->flags |= ASYNC_CTS_FLOW;
+	else
+		info->flags &= ~ASYNC_CTS_FLOW;
+		
+	if (cflag & CLOCAL)
+		info->flags &= ~ASYNC_CHECK_CD;
+	else
+		info->flags |= ASYNC_CHECK_CD;
+
+	/* process tty input control flags */
+	
+	info->read_status_mask = 0;
+	if (I_INPCK(info->tty))
+		info->read_status_mask |= BIT7 | BIT6;
+	if (I_IGNPAR(info->tty))
+		info->ignore_status_mask |= BIT7 | BIT6;
+
+	mgslpc_program_hw(info);
+}
+
+/* Add a character to the transmit buffer
+ */
+static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO) {
+		printk( "%s(%d):mgslpc_put_char(%d) on %s\n",
+			__FILE__,__LINE__,ch,info->device_name);
+	}
+
+	if (mgslpc_paranoia_check(info, tty->device, "mgslpc_put_char"))
+		return;
+
+	if (!tty || !info->tx_buf)
+		return;
+
+	spin_lock_irqsave(&info->lock,flags);
+	
+	if (info->params.mode == MGSL_MODE_ASYNC || !info->tx_active) {
+		if (info->tx_count < TXBUFSIZE - 1) {
+			info->tx_buf[info->tx_put++] = ch;
+			info->tx_put &= TXBUFSIZE-1;
+			info->tx_count++;
+		}
+	}
+	
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/* Enable transmitter so remaining characters in the
+ * transmit buffer are sent.
+ */
+static void mgslpc_flush_chars(struct tty_struct *tty)
+{
+	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
+	unsigned long flags;
+				
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk( "%s(%d):mgslpc_flush_chars() entry on %s tx_count=%d\n",
+			__FILE__,__LINE__,info->device_name,info->tx_count);
+	
+	if (mgslpc_paranoia_check(info, tty->device, "mgslpc_flush_chars"))
+		return;
+
+	if (info->tx_count <= 0 || tty->stopped ||
+	    tty->hw_stopped || !info->tx_buf)
+		return;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk( "%s(%d):mgslpc_flush_chars() entry on %s starting transmitter\n",
+			__FILE__,__LINE__,info->device_name);
+
+	spin_lock_irqsave(&info->lock,flags);
+	if (!info->tx_active)
+	 	tx_start(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/* Send a block of data
+ * 	
+ * Arguments:
+ * 
+ * tty        pointer to tty information structure
+ * from_user  flag: 1 = from user process
+ * buf	      pointer to buffer containing send data
+ * count      size of send data in bytes
+ * 	
+ * Returns: number of characters written
+ */
+static int mgslpc_write(struct tty_struct * tty, int from_user,
+			const unsigned char *buf, int count)
+{
+	int c, ret = 0, err;
+	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
+	unsigned long flags;
+	
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk( "%s(%d):mgslpc_write(%s) count=%d\n",
+			__FILE__,__LINE__,info->device_name,count);
+	
+	if (mgslpc_paranoia_check(info, tty->device, "mgslpc_write") ||
+	    !tty || !info->tx_buf)
+		goto cleanup;
+
+	if (info->params.mode == MGSL_MODE_HDLC) {
+		if (count > TXBUFSIZE) {
+			ret = -EIO;
+			goto cleanup;
+		}
+		if (info->tx_active)
+			goto cleanup;
+		else if (info->tx_count)
+			goto start;
+	}
+
+	for (;;) {
+		c = MIN(count,
+			MIN(TXBUFSIZE - info->tx_count - 1,
+			    TXBUFSIZE - info->tx_put));
+		if (c <= 0)
+			break;
+			
+		if (from_user) {
+			COPY_FROM_USER(err, info->tx_buf + info->tx_put, buf, c);
+			if (err) {
+				if (!ret)
+					ret = -EFAULT;
+				break;
+			}
+		} else
+			memcpy(info->tx_buf + info->tx_put, buf, c);
+
+		spin_lock_irqsave(&info->lock,flags);
+		info->tx_put = (info->tx_put + c) & (TXBUFSIZE-1);
+		info->tx_count += c;
+		spin_unlock_irqrestore(&info->lock,flags);
+
+		buf += c;
+		count -= c;
+		ret += c;
+	}
+start:
+ 	if (info->tx_count && !tty->stopped && !tty->hw_stopped) {
+		spin_lock_irqsave(&info->lock,flags);
+		if (!info->tx_active)
+		 	tx_start(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+ 	}
+cleanup:	
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk( "%s(%d):mgslpc_write(%s) returning=%d\n",
+			__FILE__,__LINE__,info->device_name,ret);
+	return ret;
+}
+
+/* Return the count of free bytes in transmit buffer
+ */
+static int mgslpc_write_room(struct tty_struct *tty)
+{
+	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
+	int ret;
+				
+	if (mgslpc_paranoia_check(info, tty->device, "mgslpc_write_room"))
+		return 0;
+
+	if (info->params.mode == MGSL_MODE_HDLC) {
+		/* HDLC (frame oriented) mode */
+		if (info->tx_active)
+			return 0;
+		else
+			return HDLC_MAX_FRAME_SIZE;
+	} else {
+		ret = TXBUFSIZE - info->tx_count - 1;
+		if (ret < 0)
+			ret = 0;
+	}
+	
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_write_room(%s)=%d\n",
+			 __FILE__,__LINE__, info->device_name, ret);
+	return ret;
+}
+
+/* Return the count of bytes in transmit buffer
+ */
+static int mgslpc_chars_in_buffer(struct tty_struct *tty)
+{
+	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
+	int rc;
+		 
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_chars_in_buffer(%s)\n",
+			 __FILE__,__LINE__, info->device_name );
+			 
+	if (mgslpc_paranoia_check(info, tty->device, "mgslpc_chars_in_buffer"))
+		return 0;
+		
+	if (info->params.mode == MGSL_MODE_HDLC)
+		rc = info->tx_active ? info->max_frame_size : 0;
+	else
+		rc = info->tx_count;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_chars_in_buffer(%s)=%d\n",
+			 __FILE__,__LINE__, info->device_name, rc);
+			 
+	return rc;
+}
+
+/* Discard all data in the send buffer
+ */
+static void mgslpc_flush_buffer(struct tty_struct *tty)
+{
+	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
+	unsigned long flags;
+	
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_flush_buffer(%s) entry\n",
+			 __FILE__,__LINE__, info->device_name );
+	
+	if (mgslpc_paranoia_check(info, tty->device, "mgslpc_flush_buffer"))
+		return;
+		
+	spin_lock_irqsave(&info->lock,flags); 
+	info->tx_count = info->tx_put = info->tx_get = 0;
+	del_timer(&info->tx_timer);	
+	spin_unlock_irqrestore(&info->lock,flags);
+	
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/* Send a high-priority XON/XOFF character
+ */
+static void mgslpc_send_xchar(struct tty_struct *tty, char ch)
+{
+	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_send_xchar(%s,%d)\n",
+			 __FILE__,__LINE__, info->device_name, ch );
+			 
+	if (mgslpc_paranoia_check(info, tty->device, "mgslpc_send_xchar"))
+		return;
+
+	info->x_char = ch;
+	if (ch) {
+		spin_lock_irqsave(&info->lock,flags);
+		if (!info->tx_enabled)
+		 	tx_start(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+}
+
+/* Signal remote device to throttle send data (our receive data)
+ */
+static void mgslpc_throttle(struct tty_struct * tty)
+{
+	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
+	unsigned long flags;
+	
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_throttle(%s) entry\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	if (mgslpc_paranoia_check(info, tty->device, "mgslpc_throttle"))
+		return;
+	
+	if (I_IXOFF(tty))
+		mgslpc_send_xchar(tty, STOP_CHAR(tty));
+ 
+ 	if (tty->termios->c_cflag & CRTSCTS) {
+		spin_lock_irqsave(&info->lock,flags);
+		info->serial_signals &= ~SerialSignal_RTS;
+	 	set_signals(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+}
+
+/* Signal remote device to stop throttling send data (our receive data)
+ */
+static void mgslpc_unthrottle(struct tty_struct * tty)
+{
+	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
+	unsigned long flags;
+	
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_unthrottle(%s) entry\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	if (mgslpc_paranoia_check(info, tty->device, "mgslpc_unthrottle"))
+		return;
+	
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			mgslpc_send_xchar(tty, START_CHAR(tty));
+	}
+	
+ 	if (tty->termios->c_cflag & CRTSCTS) {
+		spin_lock_irqsave(&info->lock,flags);
+		info->serial_signals |= SerialSignal_RTS;
+	 	set_signals(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+}
+
+/* get the current serial statistics
+ */
+static int get_stats(MGSLPC_INFO * info, struct mgsl_icount *user_icount)
+{
+	int err;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("get_params(%s)\n", info->device_name);
+	COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount));
+	if (err)
+		return -EFAULT;
+	return 0;
+}
+
+/* get the current serial parameters
+ */
+static int get_params(MGSLPC_INFO * info, MGSL_PARAMS *user_params)
+{
+	int err;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("get_params(%s)\n", info->device_name);
+	COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS));
+	if (err)
+		return -EFAULT;
+	return 0;
+}
+
+/* set the serial parameters
+ * 	
+ * Arguments:
+ * 
+ * 	info		pointer to device instance data
+ * 	new_params	user buffer containing new serial params
+ *
+ * Returns:	0 if success, otherwise error code
+ */
+static int set_params(MGSLPC_INFO * info, MGSL_PARAMS *new_params)
+{
+ 	unsigned long flags;
+	MGSL_PARAMS tmp_params;
+	int err;
+ 
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):set_params %s\n", __FILE__,__LINE__,
+			info->device_name );
+	COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS));
+	if (err) {
+		if ( debug_level >= DEBUG_LEVEL_INFO )
+			printk( "%s(%d):set_params(%s) user buffer copy failed\n",
+				__FILE__,__LINE__,info->device_name);
+		return -EFAULT;
+	}
+	
+	spin_lock_irqsave(&info->lock,flags);
+	memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS));
+	spin_unlock_irqrestore(&info->lock,flags);
+	
+ 	mgslpc_change_params(info);
+	
+	return 0;
+}
+
+static int get_txidle(MGSLPC_INFO * info, int*idle_mode)
+{
+	int err;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("get_txidle(%s)=%d\n", info->device_name, info->idle_mode);
+	COPY_TO_USER(err,idle_mode, &info->idle_mode, sizeof(int));
+	if (err)
+		return -EFAULT;
+	return 0;
+}
+
+static int set_txidle(MGSLPC_INFO * info, int idle_mode)
+{
+ 	unsigned long flags;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("set_txidle(%s,%d)\n", info->device_name, idle_mode);
+	spin_lock_irqsave(&info->lock,flags);
+	info->idle_mode = idle_mode;
+	tx_set_idle(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+	return 0;
+}
+
+static int get_interface(MGSLPC_INFO * info, int*if_mode)
+{
+	int err;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("get_interface(%s)=%d\n", info->device_name, info->if_mode);
+	COPY_TO_USER(err,if_mode, &info->if_mode, sizeof(int));
+	if (err)
+		return -EFAULT;
+	return 0;
+}
+
+static int set_interface(MGSLPC_INFO * info, int if_mode)
+{
+ 	unsigned long flags;
+	unsigned char val;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("set_interface(%s,%d)\n", info->device_name, if_mode);
+	spin_lock_irqsave(&info->lock,flags);
+	info->if_mode = if_mode;
+
+	val = read_reg(info, PVR) & 0x0f;
+	switch (info->if_mode)
+	{
+	case MGSL_INTERFACE_RS232: val |= PVR_RS232; break;
+	case MGSL_INTERFACE_V35:   val |= PVR_V35;   break;
+	case MGSL_INTERFACE_RS422: val |= PVR_RS422; break;
+	}
+	write_reg(info, PVR, val);
+
+	spin_unlock_irqrestore(&info->lock,flags);
+	return 0;
+}
+
+static int set_txenable(MGSLPC_INFO * info, int enable)
+{
+ 	unsigned long flags;
+ 
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("set_txenable(%s,%d)\n", info->device_name, enable);
+			
+	spin_lock_irqsave(&info->lock,flags);
+	if (enable) {
+		if (!info->tx_enabled)
+			tx_start(info);
+	} else {
+		if (info->tx_enabled)
+			tx_stop(info);
+	}
+	spin_unlock_irqrestore(&info->lock,flags);
+	return 0;
+}
+
+static int tx_abort(MGSLPC_INFO * info)
+{
+ 	unsigned long flags;
+ 
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("tx_abort(%s)\n", info->device_name);
+			
+	spin_lock_irqsave(&info->lock,flags);
+	if (info->tx_active && info->tx_count &&
+	    info->params.mode == MGSL_MODE_HDLC) {
+		/* clear data count so FIFO is not filled on next IRQ.
+		 * This results in underrun and abort transmission.
+		 */
+		info->tx_count = info->tx_put = info->tx_get = 0;
+		info->tx_aborting = TRUE;
+	}
+	spin_unlock_irqrestore(&info->lock,flags);
+	return 0;
+}
+
+static int set_rxenable(MGSLPC_INFO * info, int enable)
+{
+ 	unsigned long flags;
+ 
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("set_rxenable(%s,%d)\n", info->device_name, enable);
+			
+	spin_lock_irqsave(&info->lock,flags);
+	if (enable) {
+		if (!info->rx_enabled)
+			rx_start(info);
+	} else {
+		if (info->rx_enabled)
+			rx_stop(info);
+	}
+	spin_unlock_irqrestore(&info->lock,flags);
+	return 0;
+}
+
+/* wait for specified event to occur
+ * 	
+ * Arguments:	 	info	pointer to device instance data
+ * 			mask	pointer to bitmask of events to wait for
+ * Return Value:	0 	if successful and bit mask updated with
+ *				of events triggerred,
+ * 			otherwise error code
+ */
+static int wait_events(MGSLPC_INFO * info, int * mask_ptr)
+{
+ 	unsigned long flags;
+	int s;
+	int rc=0;
+	struct mgsl_icount cprev, cnow;
+	int events;
+	int mask;
+	struct	_input_signal_events oldsigs, newsigs;
+	DECLARE_WAITQUEUE(wait, current);
+
+	COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int));
+	if (rc)
+		return  -EFAULT;
+		 
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("wait_events(%s,%d)\n", info->device_name, mask);
+
+	spin_lock_irqsave(&info->lock,flags);
+
+	/* return immediately if state matches requested events */
+	get_signals(info);
+	s = info->serial_signals;
+	events = mask &
+		( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) +
+ 		  ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) +
+		  ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) +
+		  ((s & SerialSignal_RI)  ? MgslEvent_RiActive :MgslEvent_RiInactive) );
+	if (events) {
+		spin_unlock_irqrestore(&info->lock,flags);
+		goto exit;
+	}
+
+	/* save current irq counts */
+	cprev = info->icount;
+	oldsigs = info->input_signal_events;
+	
+	if ((info->params.mode == MGSL_MODE_HDLC) &&
+	    (mask & MgslEvent_ExitHuntMode))
+		irq_enable(info, CHA, IRQ_EXITHUNT);
+	
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&info->event_wait_q, &wait);
+	
+	spin_unlock_irqrestore(&info->lock,flags);
+	
+	
+	for(;;) {
+		schedule();
+		if (signal_pending(current)) {
+			rc = -ERESTARTSYS;
+			break;
+		}
+			
+		/* get current irq counts */
+		spin_lock_irqsave(&info->lock,flags);
+		cnow = info->icount;
+		newsigs = info->input_signal_events;
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_unlock_irqrestore(&info->lock,flags);
+
+		/* if no change, wait aborted for some reason */
+		if (newsigs.dsr_up   == oldsigs.dsr_up   &&
+		    newsigs.dsr_down == oldsigs.dsr_down &&
+		    newsigs.dcd_up   == oldsigs.dcd_up   &&
+		    newsigs.dcd_down == oldsigs.dcd_down &&
+		    newsigs.cts_up   == oldsigs.cts_up   &&
+		    newsigs.cts_down == oldsigs.cts_down &&
+		    newsigs.ri_up    == oldsigs.ri_up    &&
+		    newsigs.ri_down  == oldsigs.ri_down  &&
+		    cnow.exithunt    == cprev.exithunt   &&
+		    cnow.rxidle      == cprev.rxidle) {
+			rc = -EIO;
+			break;
+		}
+
+		events = mask &
+			( (newsigs.dsr_up   != oldsigs.dsr_up   ? MgslEvent_DsrActive:0)   +
+			  (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) +
+			  (newsigs.dcd_up   != oldsigs.dcd_up   ? MgslEvent_DcdActive:0)   +
+			  (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) +
+			  (newsigs.cts_up   != oldsigs.cts_up   ? MgslEvent_CtsActive:0)   +
+			  (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) +
+			  (newsigs.ri_up    != oldsigs.ri_up    ? MgslEvent_RiActive:0)    +
+			  (newsigs.ri_down  != oldsigs.ri_down  ? MgslEvent_RiInactive:0)  +
+			  (cnow.exithunt    != cprev.exithunt   ? MgslEvent_ExitHuntMode:0) +
+			  (cnow.rxidle      != cprev.rxidle     ? MgslEvent_IdleReceived:0) );
+		if (events)
+			break;
+		
+		cprev = cnow;
+		oldsigs = newsigs;
+	}
+	
+	remove_wait_queue(&info->event_wait_q, &wait);
+	set_current_state(TASK_RUNNING);
+
+	if (mask & MgslEvent_ExitHuntMode) {
+		spin_lock_irqsave(&info->lock,flags);
+		if (!waitqueue_active(&info->event_wait_q))
+			irq_disable(info, CHA, IRQ_EXITHUNT);
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+exit:
+	if (rc == 0)
+		PUT_USER(rc, events, mask_ptr);
+	return rc;
+}
+
+static int modem_input_wait(MGSLPC_INFO *info,int arg)
+{
+ 	unsigned long flags;
+	int rc;
+	struct mgsl_icount cprev, cnow;
+	DECLARE_WAITQUEUE(wait, current);
+
+	/* save current irq counts */
+	spin_lock_irqsave(&info->lock,flags);
+	cprev = info->icount;
+	add_wait_queue(&info->status_event_wait_q, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	for(;;) {
+		schedule();
+		if (signal_pending(current)) {
+			rc = -ERESTARTSYS;
+			break;
+		}
+
+		/* get new irq counts */
+		spin_lock_irqsave(&info->lock,flags);
+		cnow = info->icount;
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_unlock_irqrestore(&info->lock,flags);
+
+		/* if no change, wait aborted for some reason */
+		if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+		    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
+			rc = -EIO;
+			break;
+		}
+
+		/* check for change in caller specified modem input */
+		if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) ||
+		    (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) ||
+		    (arg & TIOCM_CD  && cnow.dcd != cprev.dcd) ||
+		    (arg & TIOCM_CTS && cnow.cts != cprev.cts)) {
+			rc = 0;
+			break;
+		}
+
+		cprev = cnow;
+	}
+	remove_wait_queue(&info->status_event_wait_q, &wait);
+	set_current_state(TASK_RUNNING);
+	return rc;
+}
+
+/* Return state of the serial control/status signals
+ * 	
+ * Arguments:	 	info	pointer to device instance data
+ * 			value	pointer to int to hold returned info
+ * 	
+ * Return Value:	0 if success, otherwise error code
+ */
+static int get_modem_info(MGSLPC_INFO * info, unsigned int *value)
+{
+	unsigned int result;
+ 	unsigned long flags;
+	int err;
+ 
+	spin_lock_irqsave(&info->lock,flags);
+ 	get_signals(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	result = ((info->serial_signals & SerialSignal_RTS) ? TIOCM_RTS:0) |
+		 ((info->serial_signals & SerialSignal_DTR) ? TIOCM_DTR:0) |
+		 ((info->serial_signals & SerialSignal_DCD) ? TIOCM_CAR:0) |
+		 ((info->serial_signals & SerialSignal_RI)  ? TIOCM_RNG:0) |
+		 ((info->serial_signals & SerialSignal_DSR) ? TIOCM_DSR:0) |
+		 ((info->serial_signals & SerialSignal_CTS) ? TIOCM_CTS:0);
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("mgslpc_get_modem_info %s value=%08X\n", info->device_name, result);
+			
+	PUT_USER(err,result,value);
+	return err ? -EFAULT : 0;
+}
+
+/* Set the state of the modem control signals (DTR/RTS)
+ * 	
+ * Arguments:
+ * 
+ * 	info	pointer to device instance data
+ * 	cmd	signal command: TIOCMBIS = set bit TIOCMBIC = clear bit
+ *		TIOCMSET = set/clear signal values
+ * 	value	bit mask for command
+ * 	
+ * Return Value:	0 if success, otherwise error code
+ */
+static int set_modem_info(MGSLPC_INFO * info, unsigned int cmd,
+			  unsigned int *value)
+{
+ 	int error;
+ 	unsigned int arg;
+ 	unsigned long flags;
+ 
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("mgslpc_set_modem_info %s\n", info->device_name);
+			
+ 	GET_USER(error,arg,value);
+ 	if (error)
+ 		return error;
+		
+ 	switch (cmd) {
+ 	case TIOCMBIS: 
+ 		if (arg & TIOCM_RTS)
+ 			info->serial_signals |= SerialSignal_RTS;
+ 		if (arg & TIOCM_DTR)
+ 			info->serial_signals |= SerialSignal_DTR;
+ 		break;
+ 	case TIOCMBIC:
+ 		if (arg & TIOCM_RTS)
+ 			info->serial_signals &= ~SerialSignal_RTS;
+ 		if (arg & TIOCM_DTR)
+ 			info->serial_signals &= ~SerialSignal_DTR;
+ 		break;
+ 	case TIOCMSET:
+ 		if (arg & TIOCM_RTS)
+ 			info->serial_signals |= SerialSignal_RTS;
+		else
+ 			info->serial_signals &= ~SerialSignal_RTS;
+		
+ 		if (arg & TIOCM_DTR)
+ 			info->serial_signals |= SerialSignal_DTR;
+		else
+ 			info->serial_signals &= ~SerialSignal_DTR;
+ 		break;
+ 	default:
+ 		return -EINVAL;
+ 	}
+	
+	spin_lock_irqsave(&info->lock,flags);
+ 	set_signals(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+	
+	return 0;
+}
+
+/* Set or clear transmit break condition
+ *
+ * Arguments:		tty		pointer to tty instance data
+ *			break_state	-1=set break condition, 0=clear
+ */
+static void mgslpc_break(struct tty_struct *tty, int break_state)
+{
+	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
+	unsigned long flags;
+	
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_break(%s,%d)\n",
+			 __FILE__,__LINE__, info->device_name, break_state);
+			 
+	if (mgslpc_paranoia_check(info, tty->device, "mgslpc_break"))
+		return;
+
+	spin_lock_irqsave(&info->lock,flags);
+ 	if (break_state == -1)
+		set_reg_bits(info, CHA+DAFO, BIT6);
+	else 
+		clear_reg_bits(info, CHA+DAFO, BIT6);
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/* Service an IOCTL request
+ * 	
+ * Arguments:
+ * 
+ * 	tty	pointer to tty instance data
+ * 	file	pointer to associated file object for device
+ * 	cmd	IOCTL command code
+ * 	arg	command argument/context
+ * 	
+ * Return Value:	0 if success, otherwise error code
+ */
+static int mgslpc_ioctl(struct tty_struct *tty, struct file * file,
+			unsigned int cmd, unsigned long arg)
+{
+	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
+	
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__,
+			info->device_name, cmd );
+	
+	if (mgslpc_paranoia_check(info, tty->device, "mgslpc_ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+
+	return ioctl_common(info, cmd, arg);
+}
+
+int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg)
+{
+	int error;
+	struct mgsl_icount cnow;	/* kernel counter temps */
+	struct serial_icounter_struct *p_cuser;	/* user space */
+	unsigned long flags;
+	
+	switch (cmd) {
+	case TIOCMGET:
+		return get_modem_info(info, (unsigned int *) arg);
+	case TIOCMBIS:
+	case TIOCMBIC:
+	case TIOCMSET:
+		return set_modem_info(info, cmd, (unsigned int *) arg);
+	case MGSL_IOCGPARAMS:
+		return get_params(info,(MGSL_PARAMS *)arg);
+	case MGSL_IOCSPARAMS:
+		return set_params(info,(MGSL_PARAMS *)arg);
+	case MGSL_IOCGTXIDLE:
+		return get_txidle(info,(int*)arg);
+	case MGSL_IOCSTXIDLE:
+		return set_txidle(info,(int)arg);
+	case MGSL_IOCGIF:
+		return get_interface(info,(int*)arg);
+	case MGSL_IOCSIF:
+		return set_interface(info,(int)arg);
+	case MGSL_IOCTXENABLE:
+		return set_txenable(info,(int)arg);
+	case MGSL_IOCRXENABLE:
+		return set_rxenable(info,(int)arg);
+	case MGSL_IOCTXABORT:
+		return tx_abort(info);
+	case MGSL_IOCGSTATS:
+		return get_stats(info,(struct mgsl_icount*)arg);
+	case MGSL_IOCWAITEVENT:
+		return wait_events(info,(int*)arg);
+	case MGSL_IOCCLRMODCOUNT:
+		while(MOD_IN_USE)
+			MOD_DEC_USE_COUNT;
+		return 0;
+	case TIOCMIWAIT:
+		return modem_input_wait(info,(int)arg);
+	case TIOCGICOUNT:
+		spin_lock_irqsave(&info->lock,flags);
+		cnow = info->icount;
+		spin_unlock_irqrestore(&info->lock,flags);
+		p_cuser = (struct serial_icounter_struct *) arg;
+		PUT_USER(error,cnow.cts, &p_cuser->cts);
+		if (error) return error;
+		PUT_USER(error,cnow.dsr, &p_cuser->dsr);
+		if (error) return error;
+		PUT_USER(error,cnow.rng, &p_cuser->rng);
+		if (error) return error;
+		PUT_USER(error,cnow.dcd, &p_cuser->dcd);
+		if (error) return error;
+		PUT_USER(error,cnow.rx, &p_cuser->rx);
+		if (error) return error;
+		PUT_USER(error,cnow.tx, &p_cuser->tx);
+		if (error) return error;
+		PUT_USER(error,cnow.frame, &p_cuser->frame);
+		if (error) return error;
+		PUT_USER(error,cnow.overrun, &p_cuser->overrun);
+		if (error) return error;
+		PUT_USER(error,cnow.parity, &p_cuser->parity);
+		if (error) return error;
+		PUT_USER(error,cnow.brk, &p_cuser->brk);
+		if (error) return error;
+		PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);
+		if (error) return error;
+		return 0;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+/* Set new termios settings
+ * 	
+ * Arguments:
+ * 
+ * 	tty		pointer to tty structure
+ * 	termios		pointer to buffer to hold returned old termios
+ */
+static void mgslpc_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
+	unsigned long flags;
+	
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_set_termios %s\n", __FILE__,__LINE__,
+			tty->driver.name );
+	
+	/* just return if nothing has changed */
+	if ((tty->termios->c_cflag == old_termios->c_cflag)
+	    && (RELEVANT_IFLAG(tty->termios->c_iflag) 
+		== RELEVANT_IFLAG(old_termios->c_iflag)))
+	  return;
+
+	mgslpc_change_params(info);
+
+	/* Handle transition to B0 status */
+	if (old_termios->c_cflag & CBAUD &&
+	    !(tty->termios->c_cflag & CBAUD)) {
+		info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
+		spin_lock_irqsave(&info->lock,flags);
+	 	set_signals(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+	
+	/* Handle transition away from B0 status */
+	if (!(old_termios->c_cflag & CBAUD) &&
+	    tty->termios->c_cflag & CBAUD) {
+		info->serial_signals |= SerialSignal_DTR;
+ 		if (!(tty->termios->c_cflag & CRTSCTS) || 
+ 		    !test_bit(TTY_THROTTLED, &tty->flags)) {
+			info->serial_signals |= SerialSignal_RTS;
+ 		}
+		spin_lock_irqsave(&info->lock,flags);
+	 	set_signals(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+	
+	/* Handle turning off CRTSCTS */
+	if (old_termios->c_cflag & CRTSCTS &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		tx_release(tty);
+	}
+}
+
+static void mgslpc_close(struct tty_struct *tty, struct file * filp)
+{
+	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
+
+	if (!info || mgslpc_paranoia_check(info, tty->device, "mgslpc_close"))
+		return;
+	
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_close(%s) entry, count=%d\n",
+			 __FILE__,__LINE__, info->device_name, info->count);
+			 
+	if (!info->count || tty_hung_up_p(filp))
+		goto cleanup;
+			
+	if ((tty->count == 1) && (info->count != 1)) {
+		/*
+		 * tty->count is 1 and the tty structure will be freed.
+		 * info->count should be one in this case.
+		 * if it's not, correct it so that the port is shutdown.
+		 */
+		printk("mgslpc_close: bad refcount; tty->count is 1, "
+		       "info->count is %d\n", info->count);
+		info->count = 1;
+	}
+	
+	info->count--;
+	
+	/* if at least one open remaining, leave hardware active */
+	if (info->count)
+		goto cleanup;
+	
+	info->flags |= ASYNC_CLOSING;
+	
+	/* Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->callout_termios = *tty->termios;
+		
+	/* set tty->closing to notify line discipline to 
+	 * only process XON/XOFF characters. Only the N_TTY
+	 * discipline appears to use this (ppp does not).
+	 */
+	tty->closing = 1;
+	
+	/* wait for transmit data to clear all layers */
+	
+	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
+		if (debug_level >= DEBUG_LEVEL_INFO)
+			printk("%s(%d):mgslpc_close(%s) calling tty_wait_until_sent\n",
+				 __FILE__,__LINE__, info->device_name );
+		tty_wait_until_sent(tty, info->closing_wait);
+	}
+		
+ 	if (info->flags & ASYNC_INITIALIZED)
+ 		mgslpc_wait_until_sent(tty, info->timeout);
+
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+		
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+		
+	shutdown(info);
+	
+	tty->closing = 0;
+	info->tty = 0;
+	
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+			 ASYNC_CLOSING);
+			 
+	wake_up_interruptible(&info->close_wait);
+	
+cleanup:			
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_close(%s) exit, count=%d\n", __FILE__,__LINE__,
+			tty->driver.name, info->count);
+	if(MOD_IN_USE)
+		MOD_DEC_USE_COUNT;
+}
+
+/* Wait until the transmitter is empty.
+ */
+static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
+	unsigned long orig_jiffies, char_time;
+
+	if (!info )
+		return;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_wait_until_sent(%s) entry\n",
+			 __FILE__,__LINE__, info->device_name );
+      
+	if (mgslpc_paranoia_check(info, tty->device, "mgslpc_wait_until_sent"))
+		return;
+
+	if (!(info->flags & ASYNC_INITIALIZED))
+		goto exit;
+	 
+	orig_jiffies = jiffies;
+      
+	/* Set check interval to 1/5 of estimated time to
+	 * send a character, and make it at least 1. The check
+	 * interval should also be less than the timeout.
+	 * Note: use tight timings here to satisfy the NIST-PCTS.
+	 */ 
+       
+	if ( info->params.data_rate ) {
+	       	char_time = info->timeout/(32 * 5);
+		if (!char_time)
+			char_time++;
+	} else
+		char_time = 1;
+		
+	if (timeout)
+		char_time = MIN(char_time, timeout);
+		
+	if (info->params.mode == MGSL_MODE_HDLC) {
+		while (info->tx_active) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(char_time);
+			if (signal_pending(current))
+				break;
+			if (timeout && ((orig_jiffies + timeout) < jiffies))
+				break;
+		}
+	} else {
+		while ((info->tx_count || info->tx_active) &&
+			info->tx_enabled) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(char_time);
+			if (signal_pending(current))
+				break;
+			if (timeout && ((orig_jiffies + timeout) < jiffies))
+				break;
+		}
+	}
+      
+exit:
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_wait_until_sent(%s) exit\n",
+			 __FILE__,__LINE__, info->device_name );
+}
+
+/* Called by tty_hangup() when a hangup is signaled.
+ * This is the same as closing all open files for the port.
+ */
+static void mgslpc_hangup(struct tty_struct *tty)
+{
+	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
+	
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_hangup(%s)\n",
+			 __FILE__,__LINE__, info->device_name );
+			 
+	if (mgslpc_paranoia_check(info, tty->device, "mgslpc_hangup"))
+		return;
+
+	mgslpc_flush_buffer(tty);
+	shutdown(info);
+	
+	info->count = 0;	
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->tty = 0;
+
+	wake_up_interruptible(&info->open_wait);
+}
+
+/* Block the current process until the specified port
+ * is ready to be opened.
+ */
+static int block_til_ready(struct tty_struct *tty, struct file *filp,
+			   MGSLPC_INFO *info)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int		retval;
+	int		do_clocal = 0, extra_count = 0;
+	unsigned long	flags;
+	
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):block_til_ready on %s\n",
+			 __FILE__,__LINE__, tty->driver.name );
+
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		/* this is a callout device */
+		/* just verify that normal device is not in use */
+		if (info->flags & ASYNC_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
+		    (info->session != current->session))
+		    return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
+		    (info->pgrp != current->pgrp))
+		    return -EBUSY;
+		info->flags |= ASYNC_CALLOUT_ACTIVE;
+		return 0;
+	}
+	
+	if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
+		/* nonblock mode is set or port is not enabled */
+		/* just verify that callout device is not active */
+		if (info->flags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (info->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+	
+	/* Wait for carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, info->count is dropped by one, so that
+	 * mgslpc_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	 
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+	
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):block_til_ready before block on %s count=%d\n",
+			 __FILE__,__LINE__, tty->driver.name, info->count );
+
+	save_flags(flags); cli();
+	if (!tty_hung_up_p(filp)) {
+		extra_count = 1;
+		info->count--;
+	}
+	restore_flags(flags);
+	info->blocked_open++;
+	
+	while (1) {
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ 		    (tty->termios->c_cflag & CBAUD)) {
+			spin_lock_irqsave(&info->lock,flags);
+			info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+		 	set_signals(info);
+			spin_unlock_irqrestore(&info->lock,flags);
+		}
+		
+		set_current_state(TASK_INTERRUPTIBLE);
+		
+		if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){
+			retval = (info->flags & ASYNC_HUP_NOTIFY) ?
+					-EAGAIN : -ERESTARTSYS;
+			break;
+		}
+		
+		spin_lock_irqsave(&info->lock,flags);
+	 	get_signals(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+		
+ 		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ 		    !(info->flags & ASYNC_CLOSING) &&
+ 		    (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
+ 			break;
+		}
+			
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+		
+		if (debug_level >= DEBUG_LEVEL_INFO)
+			printk("%s(%d):block_til_ready blocking on %s count=%d\n",
+				 __FILE__,__LINE__, tty->driver.name, info->count );
+				 
+		schedule();
+	}
+	
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&info->open_wait, &wait);
+	
+	if (extra_count)
+		info->count++;
+	info->blocked_open--;
+	
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):block_til_ready after blocking on %s count=%d\n",
+			 __FILE__,__LINE__, tty->driver.name, info->count );
+			 
+	if (!retval)
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+		
+	return retval;
+}
+
+static int mgslpc_open(struct tty_struct *tty, struct file * filp)
+{
+	MGSLPC_INFO	*info;
+	int 			retval, line;
+	unsigned long flags;
+
+	/* verify range of specified line number */	
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= mgslpc_device_count)) {
+		printk("%s(%d):mgslpc_open with illegal line #%d.\n",
+			__FILE__,__LINE__,line);
+		return -ENODEV;
+	}
+
+	/* find the info structure for the specified line */
+	info = mgslpc_device_list;
+	while(info && info->line != line)
+		info = info->next_device;
+	if ( !info ){
+		printk("%s(%d):Can't find specified device on open (line=%d)\n",
+			__FILE__,__LINE__,line);
+		return -ENODEV;
+	}
+	
+	tty->driver_data = info;
+	info->tty = tty;
+	if (mgslpc_paranoia_check(info, tty->device, "mgslpc_open"))
+		return -ENODEV;
+		
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_open(%s), old ref count = %d\n",
+			 __FILE__,__LINE__,tty->driver.name, info->count);
+
+	MOD_INC_USE_COUNT;
+	
+	/* If port is closing, signal caller to try again */
+	if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+		retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+		goto cleanup;
+	}
+	
+	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+	spin_lock_irqsave(&info->netlock, flags);
+	if (info->netcount) {
+		retval = -EBUSY;
+		spin_unlock_irqrestore(&info->netlock, flags);
+		goto cleanup;
+	}
+	info->count++;
+	spin_unlock_irqrestore(&info->netlock, flags);
+
+	if (info->count == 1) {
+		/* 1st open on this device, init hardware */
+		retval = startup(info);
+		if (retval < 0)
+			goto cleanup;
+	}
+
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+		if (debug_level >= DEBUG_LEVEL_INFO)
+			printk("%s(%d):block_til_ready(%s) returned %d\n",
+				 __FILE__,__LINE__, info->device_name, retval);
+		goto cleanup;
+	}
+
+	if ((info->count == 1) &&
+	    info->flags & ASYNC_SPLIT_TERMIOS) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->normal_termios;
+		else 
+			*tty->termios = info->callout_termios;
+		mgslpc_change_params(info);
+	}
+	
+	info->session = current->session;
+	info->pgrp    = current->pgrp;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_open(%s) success\n",
+			 __FILE__,__LINE__, info->device_name);
+	retval = 0;
+	
+cleanup:			
+	if (retval) {
+		if(MOD_IN_USE)
+			MOD_DEC_USE_COUNT;
+		if(info->count)
+			info->count--;
+	}
+	
+	return retval;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static inline int line_info(char *buf, MGSLPC_INFO *info)
+{
+	char	stat_buf[30];
+	int	ret;
+	unsigned long flags;
+
+	ret = sprintf(buf, "%s:io:%04X irq:%d",
+		      info->device_name, info->io_base, info->irq_level);
+
+	/* output current serial signal states */
+	spin_lock_irqsave(&info->lock,flags);
+ 	get_signals(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+	
+	stat_buf[0] = 0;
+	stat_buf[1] = 0;
+	if (info->serial_signals & SerialSignal_RTS)
+		strcat(stat_buf, "|RTS");
+	if (info->serial_signals & SerialSignal_CTS)
+		strcat(stat_buf, "|CTS");
+	if (info->serial_signals & SerialSignal_DTR)
+		strcat(stat_buf, "|DTR");
+	if (info->serial_signals & SerialSignal_DSR)
+		strcat(stat_buf, "|DSR");
+	if (info->serial_signals & SerialSignal_DCD)
+		strcat(stat_buf, "|CD");
+	if (info->serial_signals & SerialSignal_RI)
+		strcat(stat_buf, "|RI");
+
+	if (info->params.mode == MGSL_MODE_HDLC) {
+		ret += sprintf(buf+ret, " HDLC txok:%d rxok:%d",
+			      info->icount.txok, info->icount.rxok);
+		if (info->icount.txunder)
+			ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder);
+		if (info->icount.txabort)
+			ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);
+		if (info->icount.rxshort)
+			ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);	
+		if (info->icount.rxlong)
+			ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);
+		if (info->icount.rxover)
+			ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);
+		if (info->icount.rxcrc)
+			ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxcrc);
+	} else {
+		ret += sprintf(buf+ret, " ASYNC tx:%d rx:%d",
+			      info->icount.tx, info->icount.rx);
+		if (info->icount.frame)
+			ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+		if (info->icount.parity)
+			ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+		if (info->icount.brk)
+			ret += sprintf(buf+ret, " brk:%d", info->icount.brk);	
+		if (info->icount.overrun)
+			ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+	}
+	
+	/* Append serial signal status to end */
+	ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+	
+	ret += sprintf(buf+ret, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
+		       info->tx_active,info->bh_requested,info->bh_running,
+		       info->pending_bh);
+	
+	return ret;
+}
+
+/* Called to print information about devices
+ */
+int mgslpc_read_proc(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
+{
+	int len = 0, l;
+	off_t	begin = 0;
+	MGSLPC_INFO *info;
+	
+	len += sprintf(page, "synclink driver:%s\n", driver_version);
+	
+	info = mgslpc_device_list;
+	while( info ) {
+		l = line_info(page + len, info);
+		len += l;
+		if (len+begin > off+count)
+			goto done;
+		if (len+begin < off) {
+			begin += len;
+			len = 0;
+		}
+		info = info->next_device;
+	}
+
+	*eof = 1;
+done:
+	if (off >= len+begin)
+		return 0;
+	*start = page + (off-begin);
+	return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+int rx_alloc_buffers(MGSLPC_INFO *info)
+{
+	/* each buffer has header and data */
+	info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
+
+	/* calculate total allocation size for 8 buffers */
+	info->rx_buf_total_size = info->rx_buf_size * 8;
+
+	/* limit total allocated memory */
+	if (info->rx_buf_total_size > 0x10000)
+		info->rx_buf_total_size = 0x10000;
+
+	/* calculate number of buffers */
+	info->rx_buf_count = info->rx_buf_total_size / info->rx_buf_size;
+
+	info->rx_buf = kmalloc(info->rx_buf_total_size, GFP_KERNEL);
+	if (info->rx_buf == NULL)
+		return -ENOMEM;
+
+	rx_reset_buffers(info);
+	return 0;
+}
+
+void rx_free_buffers(MGSLPC_INFO *info)
+{
+	if (info->rx_buf)
+		kfree(info->rx_buf);
+	info->rx_buf = NULL;
+}
+
+int claim_resources(MGSLPC_INFO *info)
+{
+	if (rx_alloc_buffers(info) < 0 ) {
+		printk( "Cant allocate rx buffer %s\n", info->device_name);
+		release_resources(info);
+		return -ENODEV;
+	}	
+	return 0;
+}
+
+void release_resources(MGSLPC_INFO *info)
+{
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("release_resources(%s)\n", info->device_name);
+	rx_free_buffers(info);
+}
+
+/* Add the specified device instance data structure to the
+ * global linked list of devices and increment the device count.
+ * 	
+ * Arguments:		info	pointer to device instance data
+ */
+void mgslpc_add_device(MGSLPC_INFO *info)
+{
+	info->next_device = NULL;
+	info->line = mgslpc_device_count;
+	sprintf(info->device_name,"ttySLP%d",info->line);
+	
+	if (info->line < MAX_DEVICE_COUNT) {
+		if (maxframe[info->line])
+			info->max_frame_size = maxframe[info->line];
+//		info->dosyncppp = dosyncppp[info->line];
+		info->dosyncppp = 1;
+	}
+
+	mgslpc_device_count++;
+	
+	if (!mgslpc_device_list)
+		mgslpc_device_list = info;
+	else {	
+		MGSLPC_INFO *current_dev = mgslpc_device_list;
+		while( current_dev->next_device )
+			current_dev = current_dev->next_device;
+		current_dev->next_device = info;
+	}
+	
+	if (info->max_frame_size < 4096)
+		info->max_frame_size = 4096;
+	else if (info->max_frame_size > 65535)
+		info->max_frame_size = 65535;
+	
+	printk( "SyncLink PC Card %s:IO=%04X IRQ=%d\n",
+		info->device_name, info->io_base, info->irq_level);
+
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+#ifdef MODULE
+	if (info->dosyncppp)
+#endif
+		mgslpc_sppp_init(info);
+#endif
+}
+
+void mgslpc_remove_device(MGSLPC_INFO *remove_info)
+{
+	MGSLPC_INFO *info = mgslpc_device_list;
+	MGSLPC_INFO *last = NULL;
+
+	while(info) {
+		if (info == remove_info) {
+			if (last)
+				last->next_device = info->next_device;
+			else
+				mgslpc_device_list = info->next_device;
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+			if (info->dosyncppp)
+				mgslpc_sppp_delete(info);
+#endif
+			release_resources(info);
+			kfree(info);
+			mgslpc_device_count--;
+			return;
+		}
+		last = info;
+		info = info->next_device;
+	}
+}
+
+static int __init synclink_cs_init(void)
+{
+    servinfo_t serv;
+
+    EXPORT_NO_SYMBOLS;
+	
+    if (break_on_load) {
+	    mgslpc_get_text_ptr();
+	    BREAKPOINT();
+    }
+
+    printk("%s %s\n", driver_name, driver_version);
+
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	    printk(KERN_NOTICE "synclink_cs: Card Services release "
+		   "does not match!\n");
+	    return -1;
+    }
+    register_pccard_driver(&dev_info, &mgslpc_attach, &mgslpc_detach);
+
+    /* Initialize the tty_driver structure */
+	
+    memset(&serial_driver, 0, sizeof(struct tty_driver));
+    serial_driver.magic = TTY_DRIVER_MAGIC;
+    serial_driver.driver_name = "synclink_cs";
+    serial_driver.name = "ttySLP";
+    serial_driver.major = ttymajor;
+    serial_driver.minor_start = 64;
+    serial_driver.num = MAX_DEVICE_COUNT;
+    serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+    serial_driver.subtype = SERIAL_TYPE_NORMAL;
+    serial_driver.init_termios = tty_std_termios;
+    serial_driver.init_termios.c_cflag =
+	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+    serial_driver.flags = TTY_DRIVER_REAL_RAW;
+    serial_driver.refcount = &serial_refcount;
+    serial_driver.table = serial_table;
+    serial_driver.termios = serial_termios;
+    serial_driver.termios_locked = serial_termios_locked;
+
+    serial_driver.open = mgslpc_open;
+    serial_driver.close = mgslpc_close;
+    serial_driver.write = mgslpc_write;
+    serial_driver.put_char = mgslpc_put_char;
+    serial_driver.flush_chars = mgslpc_flush_chars;
+    serial_driver.write_room = mgslpc_write_room;
+    serial_driver.chars_in_buffer = mgslpc_chars_in_buffer;
+    serial_driver.flush_buffer = mgslpc_flush_buffer;
+    serial_driver.ioctl = mgslpc_ioctl;
+    serial_driver.throttle = mgslpc_throttle;
+    serial_driver.unthrottle = mgslpc_unthrottle;
+    serial_driver.send_xchar = mgslpc_send_xchar;
+    serial_driver.break_ctl = mgslpc_break;
+    serial_driver.wait_until_sent = mgslpc_wait_until_sent;
+    serial_driver.read_proc = mgslpc_read_proc;
+    serial_driver.set_termios = mgslpc_set_termios;
+    serial_driver.stop = tx_pause;
+    serial_driver.start = tx_release;
+    serial_driver.hangup = mgslpc_hangup;
+	
+    /*
+     * The callout device is just like normal device except for
+     * major number and the subtype code.
+     */
+    callout_driver = serial_driver;
+    callout_driver.name = "cuaSLP";
+    callout_driver.major = cuamajor;
+    callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+    callout_driver.read_proc = 0;
+    callout_driver.proc_entry = 0;
+
+    if (tty_register_driver(&serial_driver) < 0)
+	    printk("%s(%d):Couldn't register serial driver\n",
+		   __FILE__,__LINE__);
+			
+    if (tty_register_driver(&callout_driver) < 0)
+	    printk("%s(%d):Couldn't register callout driver\n",
+		   __FILE__,__LINE__);
+
+    printk("%s %s, tty major#%d callout major#%d\n",
+	   driver_name, driver_version,
+	   serial_driver.major, callout_driver.major);
+	
+    return 0;
+}
+
+static void __exit synclink_cs_exit(void) 
+{
+	unsigned long flags;
+	int rc;
+
+	printk("Unloading %s: version %s\n", driver_name, driver_version);
+
+	while(mgslpc_device_list)
+		mgslpc_remove_device(mgslpc_device_list);
+
+	save_flags(flags);
+	cli();
+	if ((rc = tty_unregister_driver(&serial_driver)))
+		printk("%s(%d) failed to unregister tty driver err=%d\n",
+		       __FILE__,__LINE__,rc);
+	if ((rc = tty_unregister_driver(&callout_driver)))
+		printk("%s(%d) failed to unregister callout driver err=%d\n",
+		       __FILE__,__LINE__,rc);
+	restore_flags(flags);
+
+	unregister_pccard_driver(&dev_info);
+	while (dev_list != NULL) {
+		del_timer(&dev_list->release);
+		if (dev_list->state & DEV_CONFIG)
+			mgslpc_release((u_long)dev_list);
+		mgslpc_detach(dev_list);
+	}
+}
+
+module_init(synclink_cs_init);
+module_exit(synclink_cs_exit);
+
+void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned int rate) 
+{
+	unsigned int M, N;
+	unsigned char val;
+
+	/* note:standard BRG mode is broken in V3.2 chip 
+	 * so enhanced mode is always used 
+	 */
+
+	if (rate) {
+		N = 3686400 / rate;
+		if (!N)
+			N = 1;
+		N >>= 1;
+		for (M = 1; N > 64 && M < 16; M++)
+			N >>= 1;
+		N--;
+
+		/* BGR[5..0] = N
+		 * BGR[9..6] = M
+		 * BGR[7..0] contained in BGR register
+		 * BGR[9..8] contained in CCR2[7..6]
+		 * divisor = (N+1)*2^M
+		 *
+		 * Note: M *must* not be zero (causes asymetric duty cycle)
+		 */ 
+		write_reg(info, (unsigned char) (channel + BGR),
+				  (unsigned char) ((M << 6) + N));
+		val = read_reg(info, (unsigned char) (channel + CCR2)) & 0x3f;
+		val |= ((M << 4) & 0xc0);
+		write_reg(info, (unsigned char) (channel + CCR2), val);
+	}
+}
+
+/* Enabled the AUX clock output at the specified frequency.
+ */
+void enable_auxclk(MGSLPC_INFO *info)
+{
+	unsigned char val;
+	
+	/* MODE
+	 *
+	 * 07..06  MDS[1..0] 10 = transparent HDLC mode
+	 * 05      ADM Address Mode, 0 = no addr recognition
+	 * 04      TMD Timer Mode, 0 = external
+	 * 03      RAC Receiver Active, 0 = inactive
+	 * 02      RTS 0=RTS active during xmit, 1=RTS always active
+	 * 01      TRS Timer Resolution, 1=512
+	 * 00      TLP Test Loop, 0 = no loop
+	 *
+	 * 1000 0010
+	 */ 
+	val = 0x82;
+	
+	/* channel B RTS is used to enable AUXCLK driver on SP505 */ 
+	if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed)
+		val |= BIT2;
+	write_reg(info, CHB + MODE, val);
+	
+	/* CCR0
+	 *
+	 * 07      PU Power Up, 1=active, 0=power down
+	 * 06      MCE Master Clock Enable, 1=enabled
+	 * 05      Reserved, 0
+	 * 04..02  SC[2..0] Encoding
+	 * 01..00  SM[1..0] Serial Mode, 00=HDLC
+	 *
+	 * 11000000
+	 */ 
+	write_reg(info, CHB + CCR0, 0xc0);
+	
+	/* CCR1
+	 *
+	 * 07      SFLG Shared Flag, 0 = disable shared flags
+	 * 06      GALP Go Active On Loop, 0 = not used
+	 * 05      GLP Go On Loop, 0 = not used
+	 * 04      ODS Output Driver Select, 1=TxD is push-pull output
+	 * 03      ITF Interframe Time Fill, 0=mark, 1=flag
+	 * 02..00  CM[2..0] Clock Mode
+	 *
+	 * 0001 0111
+	 */ 
+	write_reg(info, CHB + CCR1, 0x17);
+	
+	/* CCR2 (Channel B)
+	 *
+	 * 07..06  BGR[9..8] Baud rate bits 9..8
+	 * 05      BDF Baud rate divisor factor, 0=1, 1=BGR value
+	 * 04      SSEL Clock source select, 1=submode b
+	 * 03      TOE 0=TxCLK is input, 1=TxCLK is output
+	 * 02      RWX Read/Write Exchange 0=disabled
+	 * 01      C32, CRC select, 0=CRC-16, 1=CRC-32
+	 * 00      DIV, data inversion 0=disabled, 1=enabled
+	 *
+	 * 0011 1000
+	 */ 
+	if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed)
+		write_reg(info, CHB + CCR2, 0x38);
+	else
+		write_reg(info, CHB + CCR2, 0x30);
+	
+	/* CCR4
+	 *
+	 * 07      MCK4 Master Clock Divide by 4, 1=enabled
+	 * 06      EBRG Enhanced Baud Rate Generator Mode, 1=enabled
+	 * 05      TST1 Test Pin, 0=normal operation
+	 * 04      ICD Ivert Carrier Detect, 1=enabled (active low)
+	 * 03..02  Reserved, must be 0
+	 * 01..00  RFT[1..0] RxFIFO Threshold 00=32 bytes
+	 *
+	 * 0101 0000
+	 */ 
+	write_reg(info, CHB + CCR4, 0x50);
+	
+	/* if auxclk not enabled, set internal BRG so
+	 * CTS transitions can be detected (requires TxC)
+	 */ 
+	if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed)
+		mgslpc_set_rate(info, CHB, info->params.clock_speed);
+	else
+		mgslpc_set_rate(info, CHB, 921600);
+}
+
+static void loopback_enable(MGSLPC_INFO *info) 
+{
+	unsigned char val;
+	
+	/* CCR1:02..00  CM[2..0] Clock Mode = 111 (clock mode 7) */ 
+	val = read_reg(info, CHA + CCR1) | (BIT2 + BIT1 + BIT0);
+	write_reg(info, CHA + CCR1, val);
+	
+	/* CCR2:04 SSEL Clock source select, 1=submode b */ 
+	val = read_reg(info, CHA + CCR2) | (BIT4 + BIT5);
+	write_reg(info, CHA + CCR2, val);
+	
+	/* set LinkSpeed if available, otherwise default to 2Mbps */ 
+	if (info->params.clock_speed)
+		mgslpc_set_rate(info, CHA, info->params.clock_speed);
+	else
+		mgslpc_set_rate(info, CHA, 1843200);
+	
+	/* MODE:00 TLP Test Loop, 1=loopback enabled */ 
+	val = read_reg(info, CHA + MODE) | BIT0;
+	write_reg(info, CHA + MODE, val);
+}
+
+void hdlc_mode(MGSLPC_INFO *info)
+{
+	unsigned char val;
+	unsigned char clkmode, clksubmode;
+
+	/* disable all interrupts */ 
+	irq_disable(info, CHA, 0xffff);
+	irq_disable(info, CHB, 0xffff);
+	port_irq_disable(info, 0xff);
+	
+	/* assume clock mode 0a, rcv=RxC xmt=TxC */ 
+	clkmode = clksubmode = 0;
+	if (info->params.flags & HDLC_FLAG_RXC_DPLL
+	    && info->params.flags & HDLC_FLAG_TXC_DPLL) {
+		/* clock mode 7a, rcv = DPLL, xmt = DPLL */ 
+		clkmode = 7;
+	} else if (info->params.flags & HDLC_FLAG_RXC_BRG
+		 && info->params.flags & HDLC_FLAG_TXC_BRG) {
+		/* clock mode 7b, rcv = BRG, xmt = BRG */ 
+		clkmode = 7;
+		clksubmode = 1;
+	} else if (info->params.flags & HDLC_FLAG_RXC_DPLL) {
+		if (info->params.flags & HDLC_FLAG_TXC_BRG) {
+			/* clock mode 6b, rcv = DPLL, xmt = BRG/16 */ 
+			clkmode = 6;
+			clksubmode = 1;
+		} else {
+			/* clock mode 6a, rcv = DPLL, xmt = TxC */ 
+			clkmode = 6;
+		}
+	} else if (info->params.flags & HDLC_FLAG_TXC_BRG) {
+		/* clock mode 0b, rcv = RxC, xmt = BRG */ 
+		clksubmode = 1;
+	}
+	
+	/* MODE
+	 *
+	 * 07..06  MDS[1..0] 10 = transparent HDLC mode
+	 * 05      ADM Address Mode, 0 = no addr recognition
+	 * 04      TMD Timer Mode, 0 = external
+	 * 03      RAC Receiver Active, 0 = inactive
+	 * 02      RTS 0=RTS active during xmit, 1=RTS always active
+	 * 01      TRS Timer Resolution, 1=512
+	 * 00      TLP Test Loop, 0 = no loop
+	 *
+	 * 1000 0010
+	 */ 
+	val = 0x82;
+	if (info->params.loopback)
+		val |= BIT0;
+	
+	/* preserve RTS state */ 
+	if (info->serial_signals & SerialSignal_RTS)
+		val |= BIT2;
+	write_reg(info, CHA + MODE, val);
+	
+	/* CCR0
+	 *
+	 * 07      PU Power Up, 1=active, 0=power down
+	 * 06      MCE Master Clock Enable, 1=enabled
+	 * 05      Reserved, 0
+	 * 04..02  SC[2..0] Encoding
+	 * 01..00  SM[1..0] Serial Mode, 00=HDLC
+	 *
+	 * 11000000
+	 */ 
+	val = 0xc0;
+	switch (info->params.encoding)
+	{
+	case HDLC_ENCODING_NRZI:
+		val |= BIT3;
+		break;
+	case HDLC_ENCODING_BIPHASE_SPACE:
+		val |= BIT4;
+		break;		// FM0
+	case HDLC_ENCODING_BIPHASE_MARK:
+		val |= BIT4 + BIT2;
+		break;		// FM1
+	case HDLC_ENCODING_BIPHASE_LEVEL:
+		val |= BIT4 + BIT3;
+		break;		// Manchester
+	}
+	write_reg(info, CHA + CCR0, val);
+	
+	/* CCR1
+	 *
+	 * 07      SFLG Shared Flag, 0 = disable shared flags
+	 * 06      GALP Go Active On Loop, 0 = not used
+	 * 05      GLP Go On Loop, 0 = not used
+	 * 04      ODS Output Driver Select, 1=TxD is push-pull output
+	 * 03      ITF Interframe Time Fill, 0=mark, 1=flag
+	 * 02..00  CM[2..0] Clock Mode
+	 *
+	 * 0001 0000
+	 */ 
+	val = 0x10 + clkmode;
+	write_reg(info, CHA + CCR1, val);
+	
+	/* CCR2
+	 *
+	 * 07..06  BGR[9..8] Baud rate bits 9..8
+	 * 05      BDF Baud rate divisor factor, 0=1, 1=BGR value
+	 * 04      SSEL Clock source select, 1=submode b
+	 * 03      TOE 0=TxCLK is input, 0=TxCLK is input
+	 * 02      RWX Read/Write Exchange 0=disabled
+	 * 01      C32, CRC select, 0=CRC-16, 1=CRC-32
+	 * 00      DIV, data inversion 0=disabled, 1=enabled
+	 *
+	 * 0000 0000
+	 */ 
+	val = 0x00;
+	if (clkmode == 2 || clkmode == 3 || clkmode == 6
+	    || clkmode == 7 || (clkmode == 0 && clksubmode == 1))
+		val |= BIT5;
+	if (clksubmode)
+		val |= BIT4;
+	if (info->params.crc_type == HDLC_CRC_32_CCITT)
+		val |= BIT1;
+	if (info->params.encoding == HDLC_ENCODING_NRZB)
+		val |= BIT0;
+	write_reg(info, CHA + CCR2, val);
+	
+	/* CCR3
+	 *
+	 * 07..06  PRE[1..0] Preamble count 00=1, 01=2, 10=4, 11=8
+	 * 05      EPT Enable preamble transmission, 1=enabled
+	 * 04      RADD Receive address pushed to FIFO, 0=disabled
+	 * 03      CRL CRC Reset Level, 0=FFFF
+	 * 02      RCRC Rx CRC 0=On 1=Off
+	 * 01      TCRC Tx CRC 0=On 1=Off
+	 * 00      PSD DPLL Phase Shift Disable
+	 *
+	 * 0000 0000
+	 */ 
+	val = 0x00;
+	if (info->params.crc_type == HDLC_CRC_NONE)
+		val |= BIT2 + BIT1;
+	if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE)
+		val |= BIT5;
+	switch (info->params.preamble_length)
+	{
+	case HDLC_PREAMBLE_LENGTH_16BITS:
+		val |= BIT6;
+		break;
+	case HDLC_PREAMBLE_LENGTH_32BITS:
+		val |= BIT6;
+		break;
+	case HDLC_PREAMBLE_LENGTH_64BITS:
+		val |= BIT7 + BIT6;
+		break;
+	}
+	write_reg(info, CHA + CCR3, val);
+	
+	/* PRE - Preamble pattern */ 
+	val = 0;
+	switch (info->params.preamble)
+	{
+	case HDLC_PREAMBLE_PATTERN_FLAGS: val = 0x7e; break;
+	case HDLC_PREAMBLE_PATTERN_10:    val = 0xaa; break;
+	case HDLC_PREAMBLE_PATTERN_01:    val = 0x55; break;
+	case HDLC_PREAMBLE_PATTERN_ONES:  val = 0xff; break;
+	}
+	write_reg(info, CHA + PRE, val);
+	
+	/* CCR4
+	 *
+	 * 07      MCK4 Master Clock Divide by 4, 1=enabled
+	 * 06      EBRG Enhanced Baud Rate Generator Mode, 1=enabled
+	 * 05      TST1 Test Pin, 0=normal operation
+	 * 04      ICD Ivert Carrier Detect, 1=enabled (active low)
+	 * 03..02  Reserved, must be 0
+	 * 01..00  RFT[1..0] RxFIFO Threshold 00=32 bytes
+	 *
+	 * 0101 0000
+	 */ 
+	val = 0x50;
+	write_reg(info, CHA + CCR4, val);
+	if (info->params.flags & HDLC_FLAG_RXC_DPLL)
+		mgslpc_set_rate(info, CHA, info->params.clock_speed * 16);
+	else
+		mgslpc_set_rate(info, CHA, info->params.clock_speed);
+	
+	/* RLCR Receive length check register
+	 *
+	 * 7     1=enable receive length check
+	 * 6..0  Max frame length = (RL + 1) * 32
+	 */ 
+	write_reg(info, CHA + RLCR, 0);
+	
+	/* XBCH Transmit Byte Count High
+	 *
+	 * 07      DMA mode, 0 = interrupt driven
+	 * 06      NRM, 0=ABM (ignored)
+	 * 05      CAS Carrier Auto Start
+	 * 04      XC Transmit Continuously (ignored)
+	 * 03..00  XBC[10..8] Transmit byte count bits 10..8
+	 *
+	 * 0000 0000
+	 */ 
+	val = 0x00;
+	if (info->params.flags & HDLC_FLAG_AUTO_DCD)
+		val |= BIT5;
+	write_reg(info, CHA + XBCH, val);
+	enable_auxclk(info);
+	if (info->params.loopback || info->testing_irq)
+		loopback_enable(info);
+	if (info->params.flags & HDLC_FLAG_AUTO_CTS)
+	{
+		irq_enable(info, CHB, IRQ_CTS);
+		/* PVR[3] 1=AUTO CTS active */ 
+		set_reg_bits(info, CHA + PVR, BIT3);
+	} else
+		clear_reg_bits(info, CHA + PVR, BIT3);
+
+	irq_enable(info, CHA,
+			 IRQ_RXEOM + IRQ_RXFIFO + IRQ_ALLSENT +
+			 IRQ_UNDERRUN + IRQ_TXFIFO);
+	issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET);
+	wait_command_complete(info, CHA);
+	read_reg16(info, CHA + ISR);	/* clear pending IRQs */
+	
+	/* Master clock mode enabled above to allow reset commands
+	 * to complete even if no data clocks are present.
+	 *
+	 * Disable master clock mode for normal communications because
+	 * V3.2 of the ESCC2 has a bug that prevents the transmit all sent
+	 * IRQ when in master clock mode.
+	 *
+	 * Leave master clock mode enabled for IRQ test because the
+	 * timer IRQ used by the test can only happen in master clock mode.
+	 */ 
+	if (!info->testing_irq)
+		clear_reg_bits(info, CHA + CCR0, BIT6);
+
+	tx_set_idle(info);
+
+	tx_stop(info);
+	rx_stop(info);
+}
+
+void rx_stop(MGSLPC_INFO *info)
+{
+	if (debug_level >= DEBUG_LEVEL_ISR)
+		printk("%s(%d):rx_stop(%s)\n",
+			 __FILE__,__LINE__, info->device_name );
+			 
+	/* MODE:03 RAC Receiver Active, 0=inactive */ 
+	clear_reg_bits(info, CHA + MODE, BIT3);
+
+	info->rx_enabled = 0;
+	info->rx_overflow = 0;
+}
+
+void rx_start(MGSLPC_INFO *info)
+{
+	if (debug_level >= DEBUG_LEVEL_ISR)
+		printk("%s(%d):rx_start(%s)\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	rx_reset_buffers(info);
+	info->rx_enabled = 0;
+	info->rx_overflow = 0;
+
+	/* MODE:03 RAC Receiver Active, 1=active */ 
+	set_reg_bits(info, CHA + MODE, BIT3);
+
+	info->rx_enabled = 1;
+}
+
+void tx_start(MGSLPC_INFO *info)
+{
+	if (debug_level >= DEBUG_LEVEL_ISR)
+		printk("%s(%d):tx_start(%s)\n",
+			 __FILE__,__LINE__, info->device_name );
+			 
+	if (info->tx_count) {
+		/* If auto RTS enabled and RTS is inactive, then assert */
+		/* RTS and set a flag indicating that the driver should */
+		/* negate RTS when the transmission completes. */
+		info->drop_rts_on_tx_done = 0;
+
+		if (info->params.flags & HDLC_FLAG_AUTO_RTS) {
+			get_signals(info);
+			if (!(info->serial_signals & SerialSignal_RTS)) {
+				info->serial_signals |= SerialSignal_RTS;
+				set_signals(info);
+				info->drop_rts_on_tx_done = 1;
+			}
+		}
+
+		if (info->params.mode == MGSL_MODE_ASYNC) {
+			if (!info->tx_active) {
+				info->tx_active = 1;
+				tx_ready(info);
+			}
+		} else {
+			info->tx_active = 1;
+			tx_ready(info);
+			info->tx_timer.expires = jiffies + jiffies_from_ms(5000);
+			add_timer(&info->tx_timer);	
+		}
+	}
+
+	if (!info->tx_enabled)
+		info->tx_enabled = 1;
+}
+
+void tx_stop(MGSLPC_INFO *info)
+{
+	if (debug_level >= DEBUG_LEVEL_ISR)
+		printk("%s(%d):tx_stop(%s)\n",
+			 __FILE__,__LINE__, info->device_name );
+			 
+	del_timer(&info->tx_timer);	
+
+	info->tx_enabled = 0;
+	info->tx_active  = 0;
+}
+
+/* Reset the adapter to a known state and prepare it for further use.
+ */
+void reset_device(MGSLPC_INFO *info)
+{
+	/* power up both channels (set BIT7) */ 
+	write_reg(info, CHA + CCR0, 0x80);
+	write_reg(info, CHB + CCR0, 0x80);
+	write_reg(info, CHA + MODE, 0);
+	write_reg(info, CHB + MODE, 0);
+	
+	/* disable all interrupts */ 
+	irq_disable(info, CHA, 0xffff);
+	irq_disable(info, CHB, 0xffff);
+	port_irq_disable(info, 0xff);
+	
+	/* PCR Port Configuration Register
+	 *
+	 * 07..04  DEC[3..0] Serial I/F select outputs
+	 * 03      output, 1=AUTO CTS control enabled
+	 * 02      RI Ring Indicator input 0=active
+	 * 01      DSR input 0=active
+	 * 00      DTR output 0=active
+	 *
+	 * 0000 0110
+	 */ 
+	write_reg(info, PCR, 0x06);
+	
+	/* PVR Port Value Register
+	 *
+	 * 07..04  DEC[3..0] Serial I/F select (0000=disabled)
+	 * 03      AUTO CTS output 1=enabled
+	 * 02      RI Ring Indicator input
+	 * 01      DSR input
+	 * 00      DTR output (1=inactive)
+	 *
+	 * 0000 0001
+	 */
+//	write_reg(info, PVR, PVR_DTR);
+	
+	/* IPC Interrupt Port Configuration
+	 *
+	 * 07      VIS 1=Masked interrupts visible
+	 * 06..05  Reserved, 0
+	 * 04..03  SLA Slave address, 00 ignored
+	 * 02      CASM Cascading Mode, 1=daisy chain
+	 * 01..00  IC[1..0] Interrupt Config, 01=push-pull output, active low
+	 *
+	 * 0000 0101
+	 */ 
+	write_reg(info, IPC, 0x05);
+}
+
+void async_mode(MGSLPC_INFO *info)
+{
+	unsigned char val;
+
+	/* disable all interrupts */ 
+	irq_disable(info, CHA, 0xffff);
+	irq_disable(info, CHB, 0xffff);
+	port_irq_disable(info, 0xff);
+	
+	/* MODE
+	 *
+	 * 07      Reserved, 0
+	 * 06      FRTS RTS State, 0=active
+	 * 05      FCTS Flow Control on CTS
+	 * 04      FLON Flow Control Enable
+	 * 03      RAC Receiver Active, 0 = inactive
+	 * 02      RTS 0=Auto RTS, 1=manual RTS
+	 * 01      TRS Timer Resolution, 1=512
+	 * 00      TLP Test Loop, 0 = no loop
+	 *
+	 * 0000 0110
+	 */ 
+	val = 0x06;
+	if (info->params.loopback)
+		val |= BIT0;
+	
+	/* preserve RTS state */ 
+	if (!(info->serial_signals & SerialSignal_RTS))
+		val |= BIT6;
+	write_reg(info, CHA + MODE, val);
+	
+	/* CCR0
+	 *
+	 * 07      PU Power Up, 1=active, 0=power down
+	 * 06      MCE Master Clock Enable, 1=enabled
+	 * 05      Reserved, 0
+	 * 04..02  SC[2..0] Encoding, 000=NRZ
+	 * 01..00  SM[1..0] Serial Mode, 11=Async
+	 *
+	 * 1000 0011
+	 */ 
+	write_reg(info, CHA + CCR0, 0x83);
+	
+	/* CCR1
+	 *
+	 * 07..05  Reserved, 0
+	 * 04      ODS Output Driver Select, 1=TxD is push-pull output
+	 * 03      BCR Bit Clock Rate, 1=16x
+	 * 02..00  CM[2..0] Clock Mode, 111=BRG
+	 *
+	 * 0001 1111
+	 */ 
+	write_reg(info, CHA + CCR1, 0x1f);
+	
+	/* CCR2 (channel A)
+	 *
+	 * 07..06  BGR[9..8] Baud rate bits 9..8
+	 * 05      BDF Baud rate divisor factor, 0=1, 1=BGR value
+	 * 04      SSEL Clock source select, 1=submode b
+	 * 03      TOE 0=TxCLK is input, 0=TxCLK is input
+	 * 02      RWX Read/Write Exchange 0=disabled
+	 * 01      Reserved, 0
+	 * 00      DIV, data inversion 0=disabled, 1=enabled
+	 *
+	 * 0001 0000
+	 */ 
+	write_reg(info, CHA + CCR2, 0x10);
+	
+	/* CCR3
+	 *
+	 * 07..01  Reserved, 0
+	 * 00      PSD DPLL Phase Shift Disable
+	 *
+	 * 0000 0000
+	 */ 
+	write_reg(info, CHA + CCR3, 0);
+	
+	/* CCR4
+	 *
+	 * 07      MCK4 Master Clock Divide by 4, 1=enabled
+	 * 06      EBRG Enhanced Baud Rate Generator Mode, 1=enabled
+	 * 05      TST1 Test Pin, 0=normal operation
+	 * 04      ICD Ivert Carrier Detect, 1=enabled (active low)
+	 * 03..00  Reserved, must be 0
+	 *
+	 * 0101 0000
+	 */ 
+	write_reg(info, CHA + CCR4, 0x50);
+	mgslpc_set_rate(info, CHA, info->params.data_rate * 16);
+	
+	/* DAFO Data Format
+	 *
+	 * 07      Reserved, 0
+	 * 06      XBRK transmit break, 0=normal operation
+	 * 05      Stop bits (0=1, 1=2)
+	 * 04..03  PAR[1..0] Parity (01=odd, 10=even)
+	 * 02      PAREN Parity Enable
+	 * 01..00  CHL[1..0] Character Length (00=8, 01=7)
+	 *
+	 */ 
+	val = 0x00;
+	if (info->params.data_bits != 8)
+		val |= BIT0;	/* 7 bits */
+	if (info->params.stop_bits != 1)
+		val |= BIT5;
+	if (info->params.parity != ASYNC_PARITY_NONE)
+	{
+		val |= BIT2;	/* Parity enable */
+		if (info->params.parity == ASYNC_PARITY_ODD)
+			val |= BIT3;
+		else
+			val |= BIT4;
+	}
+	write_reg(info, CHA + DAFO, val);
+	
+	/* RFC Rx FIFO Control
+	 *
+	 * 07      Reserved, 0
+	 * 06      DPS, 1=parity bit not stored in data byte
+	 * 05      DXS, 0=all data stored in FIFO (including XON/XOFF)
+	 * 04      RFDF Rx FIFO Data Format, 1=status byte stored in FIFO
+	 * 03..02  RFTH[1..0], rx threshold, 11=16 status + 16 data byte
+	 * 01      Reserved, 0
+	 * 00      TCDE Terminate Char Detect Enable, 0=disabled
+	 *
+	 * 0101 1100
+	 */ 
+	write_reg(info, CHA + RFC, 0x5c);
+	
+	/* RLCR Receive length check register
+	 *
+	 * Max frame length = (RL + 1) * 32
+	 */ 
+	write_reg(info, CHA + RLCR, 0);
+	
+	/* XBCH Transmit Byte Count High
+	 *
+	 * 07      DMA mode, 0 = interrupt driven
+	 * 06      NRM, 0=ABM (ignored)
+	 * 05      CAS Carrier Auto Start
+	 * 04      XC Transmit Continuously (ignored)
+	 * 03..00  XBC[10..8] Transmit byte count bits 10..8
+	 *
+	 * 0000 0000
+	 */ 
+	val = 0x00;
+	if (info->params.flags & HDLC_FLAG_AUTO_DCD)
+		val |= BIT5;
+	write_reg(info, CHA + XBCH, val);
+	if (info->params.flags & HDLC_FLAG_AUTO_CTS)
+		irq_enable(info, CHA, IRQ_CTS);
+	
+	/* MODE:03 RAC Receiver Active, 1=active */ 
+	set_reg_bits(info, CHA + MODE, BIT3);
+	enable_auxclk(info);
+	if (info->params.flags & HDLC_FLAG_AUTO_CTS) {
+		irq_enable(info, CHB, IRQ_CTS);
+		/* PVR[3] 1=AUTO CTS active */ 
+		set_reg_bits(info, CHA + PVR, BIT3);
+	} else
+		clear_reg_bits(info, CHA + PVR, BIT3);
+	irq_enable(info, CHA,
+			  IRQ_RXEOM + IRQ_RXFIFO + IRQ_BREAK_ON + IRQ_RXTIME +
+			  IRQ_ALLSENT + IRQ_TXFIFO);
+	issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET);
+	wait_command_complete(info, CHA);
+	read_reg16(info, CHA + ISR);	/* clear pending IRQs */
+}
+
+/* Set the HDLC idle mode for the transmitter.
+ */
+void tx_set_idle(MGSLPC_INFO *info)
+{
+	/* Note: ESCC2 only supports flags and one idle modes */ 
+	if (info->idle_mode == HDLC_TXIDLE_FLAGS)
+		set_reg_bits(info, CHA + CCR1, BIT3);
+	else
+		clear_reg_bits(info, CHA + CCR1, BIT3);
+}
+
+/* get state of the V24 status (input) signals.
+ */
+void get_signals(MGSLPC_INFO *info)
+{
+	unsigned char status = 0;
+	
+	/* preserve DTR and RTS */ 
+	info->serial_signals &= SerialSignal_DTR + SerialSignal_RTS;
+
+	if (read_reg(info, CHB + VSTR) & BIT7)
+		info->serial_signals |= SerialSignal_DCD;
+	if (read_reg(info, CHB + STAR) & BIT1)
+		info->serial_signals |= SerialSignal_CTS;
+
+	status = read_reg(info, CHA + PVR);
+	if (!(status & PVR_RI))
+		info->serial_signals |= SerialSignal_RI;
+	if (!(status & PVR_DSR))
+		info->serial_signals |= SerialSignal_DSR;
+}
+
+/* Set the state of DTR and RTS based on contents of
+ * serial_signals member of device extension.
+ */
+void set_signals(MGSLPC_INFO *info)
+{
+	unsigned char val;
+
+	val = read_reg(info, CHA + MODE);
+	if (info->params.mode == MGSL_MODE_ASYNC) {
+		if (info->serial_signals & SerialSignal_RTS)
+			val &= ~BIT6;
+		else
+			val |= BIT6;
+	} else {
+		if (info->serial_signals & SerialSignal_RTS)
+			val |= BIT2;
+		else
+			val &= ~BIT2;
+	}
+	write_reg(info, CHA + MODE, val);
+
+	if (info->serial_signals & SerialSignal_DTR)
+		clear_reg_bits(info, CHA + PVR, PVR_DTR);
+	else
+		set_reg_bits(info, CHA + PVR, PVR_DTR);
+}
+
+void rx_reset_buffers(MGSLPC_INFO *info)
+{
+	RXBUF *buf;
+	int i;
+
+	info->rx_put = 0;
+	info->rx_get = 0;
+	info->rx_frame_count = 0;
+	for (i=0 ; i < info->rx_buf_count ; i++) {
+		buf = (RXBUF*)(info->rx_buf + (i * info->rx_buf_size));
+		buf->status = buf->count = 0;
+	}
+}
+
+/* Attempt to return a received HDLC frame
+ * Only frames received without errors are returned.
+ *
+ * Returns 1 if frame returned, otherwise 0
+ */
+int rx_get_frame(MGSLPC_INFO *info)
+{
+	unsigned short status;
+	RXBUF *buf;
+	unsigned int framesize = 0;
+	unsigned long flags;
+	struct tty_struct *tty = info->tty;
+	int return_frame = 0;
+	
+	if (info->rx_frame_count == 0)
+		return 0;
+
+	buf = (RXBUF*)(info->rx_buf + (info->rx_get * info->rx_buf_size));
+
+	status = buf->status;
+
+	/* 07  VFR  1=valid frame
+	 * 06  RDO  1=data overrun
+	 * 05  CRC  1=OK, 0=error
+	 * 04  RAB  1=frame aborted
+	 */
+	if ((status & 0xf0) != 0xA0) {
+		if (!(status & BIT7) || (status & BIT4))
+			info->icount.rxabort++;
+		else if (status & BIT6)
+			info->icount.rxover++;
+		else if (!(status & BIT5)) {
+			info->icount.rxcrc++;
+			if (info->params.crc_type & HDLC_CRC_RETURN_EX)
+				return_frame = 1;
+		}
+		framesize = 0;
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+		info->netstats.rx_errors++;
+		info->netstats.rx_frame_errors++;
+#endif
+	} else
+		return_frame = 1;
+
+	if (return_frame)
+		framesize = buf->count;
+
+	if (debug_level >= DEBUG_LEVEL_BH)
+		printk("%s(%d):rx_get_frame(%s) status=%04X size=%d\n",
+			__FILE__,__LINE__,info->device_name,status,framesize);
+			
+	if (debug_level >= DEBUG_LEVEL_DATA)
+		trace_block(info, buf->data, framesize, 0);	
+		
+	if (framesize) {
+		if ((info->params.crc_type & HDLC_CRC_RETURN_EX &&
+		      framesize+1 > info->max_frame_size) ||
+		    framesize > info->max_frame_size)
+			info->icount.rxlong++;
+		else {
+			if (status & BIT5)
+				info->icount.rxok++;
+
+			if (info->params.crc_type & HDLC_CRC_RETURN_EX) {
+				*(buf->data + framesize) = status & BIT5 ? RX_OK:RX_CRC_ERROR;
+				++framesize;
+			}
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+			if (info->netcount) {
+				/* pass frame to syncppp device */
+				mgslpc_sppp_rx_done(info, buf->data, framesize);
+			} 
+			else
+#endif
+			{
+				/* Call the line discipline receive callback directly. */
+				if (tty && tty->ldisc.receive_buf)
+					tty->ldisc.receive_buf(tty, buf->data, info->flag_buf, framesize);
+			}
+		}
+	}
+
+	spin_lock_irqsave(&info->lock,flags);
+	buf->status = buf->count = 0;
+	info->rx_frame_count--;
+	info->rx_get++;
+	if (info->rx_get >= info->rx_buf_count)
+		info->rx_get = 0;
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	return 1;
+}
+
+BOOLEAN register_test(MGSLPC_INFO *info)
+{
+	static unsigned char patterns[] = 
+	    { 0x00, 0xff, 0xaa, 0x55, 0x69, 0x96, 0x0f };
+	static unsigned int count = sizeof(patterns) / sizeof(patterns[0]);
+	unsigned int i;
+	BOOLEAN rc = TRUE;
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock,flags);
+	reset_device(info);
+
+	for (i = 0; i < count; i++) {
+		write_reg(info, XAD1, patterns[i]);
+		write_reg(info, XAD2, patterns[(i + 1) % count]);
+		if ((read_reg(info, XAD1) != patterns[i]) || 
+		    (read_reg(info, XAD2) != patterns[(i + 1) % count])) {
+			rc = FALSE;
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&info->lock,flags);
+	return rc;
+}
+
+BOOLEAN irq_test(MGSLPC_INFO *info)
+{
+	unsigned long end_time;
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock,flags);
+	reset_device(info);
+
+	info->testing_irq = TRUE;
+	hdlc_mode(info);
+
+	info->irq_occurred = FALSE;
+
+	/* init hdlc mode */
+
+	irq_enable(info, CHA, IRQ_TIMER);
+	write_reg(info, CHA + TIMR, 0);	/* 512 cycles */
+	issue_command(info, CHA, CMD_START_TIMER);
+
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	end_time=100;
+	while(end_time-- && !info->irq_occurred) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(jiffies_from_ms(10));
+	}
+	
+	info->testing_irq = FALSE;
+
+	spin_lock_irqsave(&info->lock,flags);
+	reset_device(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+	
+	return info->irq_occurred ? TRUE : FALSE;
+}
+
+int adapter_test(MGSLPC_INFO *info)
+{
+	if (!register_test(info)) {
+		info->init_error = DiagStatus_AddressFailure;
+		printk( "%s(%d):Register test failure for device %s Addr=%04X\n",
+			__FILE__,__LINE__,info->device_name, (unsigned short)(info->io_base) );
+		return -ENODEV;
+	}
+
+	if (!irq_test(info)) {
+		info->init_error = DiagStatus_IrqFailure;
+		printk( "%s(%d):Interrupt test failure for device %s IRQ=%d\n",
+			__FILE__,__LINE__,info->device_name, (unsigned short)(info->irq_level) );
+		return -ENODEV;
+	}
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):device %s passed diagnostics\n",
+			__FILE__,__LINE__,info->device_name);
+	return 0;
+}
+
+void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit)
+{
+	int i;
+	int linecount;
+	if (xmit)
+		printk("%s tx data:\n",info->device_name);
+	else
+		printk("%s rx data:\n",info->device_name);
+		
+	while(count) {
+		if (count > 16)
+			linecount = 16;
+		else
+			linecount = count;
+			
+		for(i=0;i<linecount;i++)
+			printk("%02X ",(unsigned char)data[i]);
+		for(;i<17;i++)
+			printk("   ");
+		for(i=0;i<linecount;i++) {
+			if (data[i]>=040 && data[i]<=0176)
+				printk("%c",data[i]);
+			else
+				printk(".");
+		}
+		printk("\n");
+		
+		data  += linecount;
+		count -= linecount;
+	}
+}
+
+/* HDLC frame time out
+ * update stats and do tx completion processing
+ */
+void tx_timeout(unsigned long context)
+{
+	MGSLPC_INFO *info = (MGSLPC_INFO*)context;
+	unsigned long flags;
+	
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk( "%s(%d):tx_timeout(%s)\n",
+			__FILE__,__LINE__,info->device_name);
+	if(info->tx_active &&
+	   info->params.mode == MGSL_MODE_HDLC) {
+		info->icount.txtimeout++;
+	}
+	spin_lock_irqsave(&info->lock,flags);
+	info->tx_active = 0;
+	info->tx_count = info->tx_put = info->tx_get = 0;
+
+	spin_unlock_irqrestore(&info->lock,flags);
+	
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+	if (info->netcount)
+		mgslpc_sppp_tx_done(info);
+	else
+#endif
+		bh_transmit(info);
+}
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+/* syncppp net device routines
+ */
+
+void mgslpc_sppp_init(MGSLPC_INFO *info)
+{
+	struct net_device *d;
+
+	sprintf(info->netname,"mgslp%d",info->line);
+
+	info->if_ptr = &info->pppdev;
+	info->netdev = info->pppdev.dev = &info->netdevice;
+
+	sppp_attach(&info->pppdev);
+
+	d = info->netdev;
+	strcpy(d->name,info->netname);
+	d->base_addr = info->io_base;
+	d->irq = info->irq_level;
+	d->priv = info;
+	d->init = NULL;
+	d->open = mgslpc_sppp_open;
+	d->stop = mgslpc_sppp_close;
+	d->hard_start_xmit = mgslpc_sppp_tx;
+	d->do_ioctl = mgslpc_sppp_ioctl;
+	d->get_stats = mgslpc_net_stats;
+	d->tx_timeout = mgslpc_sppp_tx_timeout;
+	d->watchdog_timeo = 10*HZ;
+
+#if LINUX_VERSION_CODE < VERSION(2,4,4) 
+	dev_init_buffers(d);
+#endif
+
+	if (register_netdev(d) == -1) {
+		printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
+		sppp_detach(info->netdev);
+		return;
+	}
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("mgslpc_sppp_init()\n");	
+}
+
+void mgslpc_sppp_delete(MGSLPC_INFO *info)
+{
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("mgslpc_sppp_delete(%s)\n",info->netname);	
+	sppp_detach(info->netdev);
+	unregister_netdev(info->netdev);
+}
+
+int mgslpc_sppp_open(struct net_device *d)
+{
+	MGSLPC_INFO *info = d->priv;
+	int err, flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("mgslpc_sppp_open(%s)\n",info->netname);	
+
+	spin_lock_irqsave(&info->netlock, flags);
+	if (info->count != 0 || info->netcount != 0) {
+		printk(KERN_WARNING "%s: sppp_open returning busy\n", info->netname);
+		spin_unlock_irqrestore(&info->netlock, flags);
+		return -EBUSY;
+	}
+	info->netcount=1;
+	MOD_INC_USE_COUNT;
+	spin_unlock_irqrestore(&info->netlock, flags);
+
+	/* claim resources and init adapter */
+	if ((err = startup(info)) != 0)
+		goto open_fail;
+
+	/* allow syncppp module to do open processing */
+	if ((err = sppp_open(d)) != 0) {
+		shutdown(info);
+		goto open_fail;
+	}
+
+	info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+	mgslpc_program_hw(info);
+
+	d->trans_start = jiffies;
+	netif_start_queue(d);
+	return 0;
+
+open_fail:
+	spin_lock_irqsave(&info->netlock, flags);
+	info->netcount=0;
+	MOD_DEC_USE_COUNT;
+	spin_unlock_irqrestore(&info->netlock, flags);
+	return err;
+}
+
+void mgslpc_sppp_tx_timeout(struct net_device *dev)
+{
+	MGSLPC_INFO *info = dev->priv;
+	int flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("mgslpc_sppp_tx_timeout(%s)\n",info->netname);	
+
+	info->netstats.tx_errors++;
+	info->netstats.tx_aborted_errors++;
+
+	spin_lock_irqsave(&info->lock,flags);
+	tx_stop(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	netif_wake_queue(dev);
+}
+
+int mgslpc_sppp_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	MGSLPC_INFO *info = dev->priv;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("mgslpc_sppp_tx(%s)\n",info->netname);	
+
+	netif_stop_queue(dev);
+
+	info->tx_count = skb->len;
+
+	memcpy(info->tx_buf, skb->data, skb->len);
+	info->tx_get = 0;
+	info->tx_put = info->tx_count = skb->len;
+
+	info->netstats.tx_packets++;
+	info->netstats.tx_bytes += skb->len;
+	dev_kfree_skb(skb);
+
+	dev->trans_start = jiffies;
+
+	spin_lock_irqsave(&info->lock,flags);
+	if (!info->tx_active)
+	 	tx_start(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	return 0;
+}
+
+int mgslpc_sppp_close(struct net_device *d)
+{
+	MGSLPC_INFO *info = d->priv;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("mgslpc_sppp_close(%s)\n",info->netname);	
+
+	/* shutdown adapter and release resources */
+	shutdown(info);
+
+	/* allow syncppp to do close processing */
+	sppp_close(d);
+	netif_stop_queue(d);
+
+	spin_lock_irqsave(&info->netlock, flags);
+	info->netcount=0;
+	MOD_DEC_USE_COUNT;
+	spin_unlock_irqrestore(&info->netlock, flags);
+	return 0;
+}
+
+void mgslpc_sppp_rx_done(MGSLPC_INFO *info, char *buf, int size)
+{
+	struct sk_buff *skb = dev_alloc_skb(size);
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("mgslpc_sppp_rx_done(%s)\n",info->netname);	
+	if (skb == NULL) {
+		printk(KERN_NOTICE "%s: cant alloc skb, dropping packet\n",
+			info->netname);
+		info->netstats.rx_dropped++;
+		return;
+	}
+
+	memcpy(skb_put(skb, size),buf,size);
+
+	skb->protocol = htons(ETH_P_WAN_PPP);
+	skb->dev = info->netdev;
+	skb->mac.raw = skb->data;
+	info->netstats.rx_packets++;
+	info->netstats.rx_bytes += size;
+	netif_rx(skb);
+	info->netdev->trans_start = jiffies;
+}
+
+void mgslpc_sppp_tx_done(MGSLPC_INFO *info)
+{
+	if (netif_queue_stopped(info->netdev))
+	    netif_wake_queue(info->netdev);
+}
+
+struct net_device_stats *mgslpc_net_stats(struct net_device *dev)
+{
+	MGSLPC_INFO *info = dev->priv;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("mgslpc_net_stats(%s)\n",info->netname);	
+	return &info->netstats;
+}
+
+int mgslpc_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	MGSLPC_INFO *info = (MGSLPC_INFO *)dev->priv;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__,
+			info->netname, cmd );
+	return sppp_do_ioctl(dev, ifr, cmd);
+}
+
+#endif /* ifdef CONFIG_SYNCLINK_SYNCPPP */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/pcwd.c linux-2.4.20/drivers/char/pcwd.c
--- linux-2.4.19/drivers/char/pcwd.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/pcwd.c	2002-10-29 11:18:32.000000000 +0000
@@ -88,6 +88,7 @@
 
 static int timeout_val;
 static int timeout = 2;
+static int expect_close = 0;
 
 MODULE_PARM (timeout, "i");
 MODULE_PARM_DESC (timeout, "Watchdog timeout in seconds (default=2)");
@@ -213,7 +214,7 @@
 	spin_unlock (&io_lock);
 
 	/* Transform the card register to the ioctl bits we use internally */
-	retval = 0;
+	retval = WDIOF_MAGICCLOSE;
 	if (status & WD_WDRST)
 		retval |= WDIOF_CARDRESET;
 	if (status & WD_T110)
@@ -385,6 +386,20 @@
 		return -ESPIPE;
 
 	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != len; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
 		pcwd_info.card_info->wd_tickle ();
 		return 1;
 	}
@@ -450,7 +465,7 @@
 {
 	switch (MINOR (ino->i_rdev)) {
 	case WATCHDOG_MINOR:
-		if (!nowayout)
+		if (expect_close)
 			pcwd_info.card_info->enable_card (0);
 
 		atomic_inc (&pcwd_info.open_allowed);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/pcxx.c linux-2.4.20/drivers/char/pcxx.c
--- linux-2.4.19/drivers/char/pcxx.c	2001-09-13 22:21:32.000000000 +0000
+++ linux-2.4.20/drivers/char/pcxx.c	2002-10-29 11:18:32.000000000 +0000
@@ -153,7 +153,6 @@
 DECLARE_TASK_QUEUE(tq_pcxx);
 
 static void pcxxpoll(unsigned long dummy);
-static void pcxxdelay(int);
 static void fepcmd(struct channel *, int, int, int, int, int);
 static void pcxe_put_char(struct tty_struct *, unsigned char);
 static void pcxe_flush_chars(struct tty_struct *);
@@ -1271,7 +1270,7 @@
 	for(crd=0; crd < numcards; crd++) {
 		bd = &boards[crd];
 		outb(FEPRST, bd->port);
-		pcxxdelay(1);
+		mdelay(1);
 
 		for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) {
 			if(i > 100) {
@@ -1283,7 +1282,7 @@
 #ifdef MODULE
 			schedule();
 #endif
-			pcxxdelay(10);
+			mdelay(10);
 		}
 		if(bd->status == DISABLED)
 			continue;
@@ -1362,7 +1361,7 @@
 #ifdef MODULE
 			schedule();
 #endif
-			pcxxdelay(1);
+			mdelay(1);
 		}
 		if(bd->status == DISABLED)
 			continue;
@@ -1413,7 +1412,7 @@
 #ifdef MODULE
 				schedule();
 #endif
-				pcxxdelay(50);
+				mdelay(50);
 			}
 
 			printk("\nPC/Xx: BIOS download failed for board at 0x%x(addr=%lx-%lx)!\n",
@@ -1443,7 +1442,7 @@
 #ifdef MODULE
 				schedule();
 #endif
-				pcxxdelay(10);
+				mdelay(10);
 			}
 
 			printk("\nPC/Xx: BIOS download failed on the %s at 0x%x!\n",
@@ -1487,7 +1486,7 @@
 #ifdef MODULE
 			schedule();
 #endif
-			pcxxdelay(1);
+			mdelay(1);
 		}
 
 		if(bd->status == DISABLED)
@@ -1520,7 +1519,7 @@
 #ifdef MODULE
 			schedule();
 #endif
-			pcxxdelay(1);
+			mdelay(1);
 		}
 		if(bd->status == DISABLED)
 			continue;
@@ -1825,15 +1824,6 @@
 }
 
 
-/*
- * pcxxdelay - delays a specified number of milliseconds
- */
-static void pcxxdelay(int msec)
-{
-	mdelay(msec);
-}
-
-
 static void 
 fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds,
 						int bytecmd)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/pdc_console.c linux-2.4.20/drivers/char/pdc_console.c
--- linux-2.4.19/drivers/char/pdc_console.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/pdc_console.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,681 @@
+/*
+ *  linux/drivers/char/pdc_console.c
+ *
+ *  2001, Christoph Plattner
+ * 
+ *  Driver template was linux's serial.c
+ *
+ */
+
+static char *pdc_drv_version = "0.3";
+static char *pdc_drv_revdate = "2001-11-17";
+#define AUTHOR "christoph.plattner@gmx.at"
+#include <linux/config.h>
+#include <linux/version.h>
+
+#undef PDC_DRV_DEBUG
+
+#undef SERIAL_PARANOIA_CHECK
+#define CONFIG_SERIAL_NOPAUSE_IO
+#define SERIAL_DO_RESTART
+
+#define PDC_POLL_DELAY (30 * HZ / 1000)
+
+/*
+ * End of serial driver configuration section.
+ */
+
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/serial_reg.h>
+#include <asm/serial.h>
+#define LOCAL_VERSTRING ""
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+
+#ifdef CONFIG_GSC
+#include <asm/gsc.h>
+#endif
+
+extern int pdc_console_poll_key(void *);
+extern void pdc_outc(unsigned char);
+
+static char *pdc_drv_name = "PDC Software Console";
+
+static struct tty_driver pdc_drv_driver;
+static int pdc_drv_refcount = 0;
+static struct async_struct *pdc_drv_info;
+
+static struct timer_list pdc_drv_timer;
+
+/* serial subtype definitions */
+#ifndef SERIAL_TYPE_NORMAL
+#define SERIAL_TYPE_NORMAL	1
+#define SERIAL_TYPE_CALLOUT	2
+#endif
+
+#define NR_PORTS 1
+#define PDC_DUMMY_BUF 2048
+
+static struct tty_struct *pdc_drv_table[NR_PORTS];
+static struct termios *pdc_drv_termios[NR_PORTS];
+static struct termios *pdc_drv_termios_locked[NR_PORTS];
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char *tmp_buf;
+#ifdef DECLARE_MUTEX
+static DECLARE_MUTEX(tmp_buf_sem);
+#else
+static struct semaphore tmp_buf_sem = MUTEX;
+#endif
+
+/*
+ * ------------------------------------------------------------
+ * pdc_stop() and pdc_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void
+pdc_stop(struct tty_struct *tty)
+{
+}
+
+static void
+pdc_start(struct tty_struct *tty)
+{
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+static void
+receive_chars(struct async_struct *info, int *status, struct pt_regs *regs)
+{
+	struct tty_struct *tty = info->tty;
+	unsigned char ch;
+	int __ch;
+
+	while (1) {
+		__ch = pdc_console_poll_key(NULL);
+
+		if (__ch == -1)	/* no character available */
+			break;
+
+		ch = (unsigned char) ((unsigned) __ch & 0x000000ffu);
+
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+			continue;
+
+		*tty->flip.char_buf_ptr = ch;
+		*tty->flip.flag_buf_ptr = 0;
+
+		tty->flip.flag_buf_ptr++;
+		tty->flip.char_buf_ptr++;
+		tty->flip.count++;
+	}
+
+	tty_flip_buffer_push(tty);
+}
+
+static void
+pdc_drv_poll(unsigned long dummy)
+{
+	struct async_struct *info;
+	int status = 0;
+
+	info = pdc_drv_info;
+
+	if (!info || !info->tty || (pdc_drv_refcount == 0)) {
+		/* do nothing */
+	} else {
+		receive_chars(info, &status, NULL);
+		info->last_active = jiffies;
+	}
+
+	mod_timer(&pdc_drv_timer, jiffies + PDC_POLL_DELAY);
+}
+
+static void
+pdc_put_char(struct tty_struct *tty, unsigned char ch)
+{
+#ifdef PDC_DRV_DEBUG
+	printk(KERN_NOTICE "[%s] %c return\n", __FUNCTION__, ch);
+#endif
+	pdc_outc(ch);
+}
+
+static void
+pdc_flush_chars(struct tty_struct *tty)
+{
+	/* PCD console always flushed all characters */
+
+#ifdef PDC_DRV_DEBUG
+	printk(KERN_NOTICE "[%s] return\n", __FUNCTION__);
+#endif
+
+	/* nothing to do */
+}
+
+static int
+pdc_write(struct tty_struct *tty, int from_user,
+	  const unsigned char *buf, int count)
+{
+	char pdc_tmp_buf[PDC_DUMMY_BUF];
+	char *pdc_tmp_buf_ptr;
+	int len;
+	int ret = 0;
+
+#ifdef PDC_DRV_DEBUG
+	printk(KERN_NOTICE "[%s] entry\n", __FUNCTION__);
+#endif
+	while (count) {
+		if (count < PDC_DUMMY_BUF)
+			len = count;
+		else
+			len = PDC_DUMMY_BUF;
+
+		if (from_user) {
+			copy_from_user(pdc_tmp_buf, buf, len);
+			pdc_tmp_buf_ptr = pdc_tmp_buf;
+		} else
+			pdc_tmp_buf_ptr = (char *) buf;
+
+		while (len) {
+			pdc_outc(*pdc_tmp_buf_ptr);
+			buf++;
+			pdc_tmp_buf_ptr++;
+			ret++;
+			count--;
+			len--;
+		}
+	}
+#ifdef PDC_DRV_DEBUG
+	printk(KERN_NOTICE "[%s] return\n", __FUNCTION__);
+#endif
+	return ret;
+}
+
+static int
+pdc_write_room(struct tty_struct *tty)
+{
+#ifdef PDC_DRV_DEBUG
+	printk(KERN_NOTICE "[%s] entry\n", __FUNCTION__);
+#endif
+	return PDC_DUMMY_BUF;
+}
+
+static int
+pdc_chars_in_buffer(struct tty_struct *tty)
+{
+#ifdef PDC_DRV_DEBUG
+	printk(KERN_NOTICE "[%s] entry\n", __FUNCTION__);
+#endif
+	return 0;		/* no characters in buffer, always flushed ! */
+}
+
+static void
+pdc_flush_buffer(struct tty_struct *tty)
+{
+#ifdef PDC_DRV_DEBUG
+	printk(KERN_NOTICE "[%s] return\n", __FUNCTION__);
+#endif
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void
+pdc_send_xchar(struct tty_struct *tty, char ch)
+{
+}
+
+/*
+ * ------------------------------------------------------------
+ * pdc_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void
+pdc_throttle(struct tty_struct *tty)
+{
+}
+
+static void
+pdc_unthrottle(struct tty_struct *tty)
+{
+}
+
+/*
+ * ------------------------------------------------------------
+ * pdc_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static void
+pdc_break(struct tty_struct *tty, int break_state)
+{
+}
+
+static int
+get_serial_info(struct async_struct * info,
+                           struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+
+	if (!retinfo)
+		return -EFAULT;
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.line = info->line;
+	tmp.port = info->line;
+	tmp.flags = info->flags;
+	tmp.close_delay = info->close_delay;
+	return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0;
+}
+
+static int get_modem_info(struct async_struct * info, unsigned int *value)
+{
+	unsigned int result = TIOCM_DTR|TIOCM_CAR|TIOCM_CTS|TIOCM_RTS;
+
+	return copy_to_user(value, &result, sizeof(int)) ? -EFAULT : 0;
+}
+
+static int get_lsr_info(struct async_struct * info, unsigned int *value)
+{
+	unsigned int result = TIOCSER_TEMT;
+
+	return copy_to_user(value, &result, sizeof(int)) ? -EFAULT : 0;
+}
+
+static int
+pdc_ioctl(struct tty_struct *tty, struct file *file,
+	  unsigned int cmd, unsigned long arg)
+{
+	struct async_struct *info = (struct async_struct *) tty->driver_data;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+			return -EIO;
+	}
+
+	switch (cmd) {
+	case TIOCMGET:
+		return get_modem_info(info, (unsigned int *) arg);
+	case TIOCMBIS:
+	case TIOCMBIC:
+	case TIOCMSET:
+		return 0;
+	case TIOCGSERIAL:
+		return get_serial_info(info, (struct serial_struct *) arg);
+	case TIOCSSERIAL:
+		return 0;
+	case TIOCSERCONFIG:
+		return 0;
+
+	case TIOCSERGETLSR:	/* Get line status register */
+		return get_lsr_info(info, (unsigned int *) arg);
+
+	case TIOCSERGSTRUCT:
+		if (copy_to_user((struct async_struct *) arg,
+				 info, sizeof (struct async_struct)))
+			return -EFAULT;
+		return 0;
+
+	case TIOCMIWAIT:
+		return 0;
+
+	case TIOCGICOUNT:
+		return 0;
+	case TIOCSERGWILD:
+	case TIOCSERSWILD:
+		/* "setserial -W" is called in Debian boot */
+		printk("TIOCSER?WILD ioctl obsolete, ignored.\n");
+		return 0;
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static void
+pdc_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+
+#if 0				/* XXX CP, has to be checked, if there is stuff to do */
+	struct async_struct *info = (struct async_struct *) tty->driver_data;
+	unsigned long flags;
+	unsigned int cflag = tty->termios->c_cflag;
+
+	if ((cflag == old_termios->c_cflag)
+	    && (RELEVANT_IFLAG(tty->termios->c_iflag)
+		== RELEVANT_IFLAG(old_termios->c_iflag)))
+		return;
+#if 0
+	change_speed(info, old_termios);
+#endif
+	/* Handle turning off CRTSCTS */
+	if ((old_termios->c_cflag & CRTSCTS) &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		pdc_start(tty);
+	}
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * pdc_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void
+pdc_close(struct tty_struct *tty, struct file *filp)
+{
+	struct async_struct *info = (struct async_struct *) tty->driver_data;
+
+#ifdef PDC_DEBUG_OPEN
+	printk("pdc_close ttyB%d, count = %d\n", info->line, state->count);
+#endif
+	pdc_drv_refcount--;
+	if (pdc_drv_refcount > 0)
+		return;
+
+	info->flags |= ASYNC_CLOSING;
+
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->state->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->state->callout_termios = *tty->termios;
+
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+
+	/* XXX CP: make mask for receive !!! */
+
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	pdc_drv_info = NULL;
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE |
+			 ASYNC_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * pdc_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void
+pdc_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	/* we always send immideate */
+}
+
+/*
+ * pdc_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void
+pdc_hangup(struct tty_struct *tty)
+{
+}
+
+/*
+ * ------------------------------------------------------------
+ * pdc_open() and friends
+ * ------------------------------------------------------------
+ */
+
+static int
+get_async_struct(int line, struct async_struct **ret_info)
+{
+	struct async_struct *info;
+
+	info = kmalloc(sizeof (struct async_struct), GFP_KERNEL);
+	if (!info) {
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof (struct async_struct));
+	init_waitqueue_head(&info->open_wait);
+	init_waitqueue_head(&info->close_wait);
+	init_waitqueue_head(&info->delta_msr_wait);
+	info->magic = SERIAL_MAGIC;
+	info->port = 0;
+	info->flags = 0;
+	info->io_type = 0;
+	info->iomem_base = 0;
+	info->iomem_reg_shift = 0;
+	info->xmit_fifo_size = PDC_DUMMY_BUF;
+	info->line = line;
+	info->tqueue.routine = NULL;
+	info->tqueue.data = info;
+	info->state = NULL;
+	*ret_info = info;
+	return 0;
+}
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int
+pdc_open(struct tty_struct *tty, struct file *filp)
+{
+	struct async_struct *info;
+	int retval, line;
+	unsigned long page;
+
+	MOD_INC_USE_COUNT;
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_PORTS)) {
+		MOD_DEC_USE_COUNT;
+		return -ENODEV;
+	}
+	retval = get_async_struct(line, &info);
+	if (retval) {
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+	tty->driver_data = info;
+	info->tty = tty;
+	pdc_drv_info = info;
+
+#ifdef PDC_DEBUG_OPEN
+	printk("pdc_open %s%d, count = %d\n", tty->driver.name, info->line,
+	       info->state->count);
+#endif
+	info->tty->low_latency = 0;
+	if (!tmp_buf) {
+		page = get_zeroed_page(GFP_KERNEL);
+		if (!page) {
+			MOD_DEC_USE_COUNT;
+			return -ENOMEM;
+		}
+		if (tmp_buf)
+			free_page(page);
+		else
+			tmp_buf = (unsigned char *) page;
+	}
+
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+
+#ifdef PDC_DEBUG_OPEN
+	printk("pdc_open ttyB%d successful...", info->line);
+#endif
+	pdc_drv_refcount++;
+	return 0;
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * pdc_init() and friends
+ *
+ * pdc_init() is called at boot-time to initialize the pdc driver.
+ * ---------------------------------------------------------------------
+ */
+
+static void
+show_pdc_drv_version(void)
+{
+	printk(KERN_INFO "%s version %s%s (%s), %s\n", pdc_drv_name,
+	       pdc_drv_version, LOCAL_VERSTRING, pdc_drv_revdate, AUTHOR);
+}
+
+/*
+ * The serial driver boot-time initialization code!
+ */
+static int __init
+pdc_drv_init(void)
+{
+	init_timer(&pdc_drv_timer);
+	pdc_drv_timer.function = pdc_drv_poll;
+	mod_timer(&pdc_drv_timer, jiffies + PDC_POLL_DELAY);
+
+	show_pdc_drv_version();
+
+	/* Initialize the tty_driver structure */
+
+	memset(&pdc_drv_driver, 0, sizeof (struct tty_driver));
+	pdc_drv_driver.magic = TTY_DRIVER_MAGIC;
+	pdc_drv_driver.driver_name = "pdc_console";
+#ifdef CONFIG_DEVFS_FS
+	pdc_drv_driver.name = "ttb/%d";
+#else
+	pdc_drv_driver.name = "ttyB";
+#endif
+	pdc_drv_driver.major = PDCCONS_MAJOR;
+	pdc_drv_driver.minor_start = 0;
+	pdc_drv_driver.num = NR_PORTS;
+	pdc_drv_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	pdc_drv_driver.subtype = SERIAL_TYPE_NORMAL;
+	pdc_drv_driver.init_termios = tty_std_termios;
+	pdc_drv_driver.init_termios.c_cflag =
+	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	pdc_drv_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+	pdc_drv_driver.refcount = &pdc_drv_refcount;
+	pdc_drv_driver.table = pdc_drv_table;
+	pdc_drv_driver.termios = pdc_drv_termios;
+	pdc_drv_driver.termios_locked = pdc_drv_termios_locked;
+
+	pdc_drv_driver.open = pdc_open;
+	pdc_drv_driver.close = pdc_close;
+	pdc_drv_driver.write = pdc_write;
+	pdc_drv_driver.put_char = pdc_put_char;
+	pdc_drv_driver.flush_chars = pdc_flush_chars;
+	pdc_drv_driver.write_room = pdc_write_room;
+	pdc_drv_driver.chars_in_buffer = pdc_chars_in_buffer;
+	pdc_drv_driver.flush_buffer = pdc_flush_buffer;
+	pdc_drv_driver.ioctl = pdc_ioctl;
+	pdc_drv_driver.throttle = pdc_throttle;
+	pdc_drv_driver.unthrottle = pdc_unthrottle;
+	pdc_drv_driver.set_termios = pdc_set_termios;
+	pdc_drv_driver.stop = pdc_stop;
+	pdc_drv_driver.start = pdc_start;
+	pdc_drv_driver.hangup = pdc_hangup;
+	pdc_drv_driver.break_ctl = pdc_break;
+	pdc_drv_driver.send_xchar = pdc_send_xchar;
+	pdc_drv_driver.wait_until_sent = pdc_wait_until_sent;
+	pdc_drv_driver.read_proc = NULL;
+
+	if (tty_register_driver(&pdc_drv_driver))
+		panic("Couldn't register pdc_console driver\n");
+
+	return 0;
+}
+
+static void __exit
+pdc_fini(void)
+{
+	int e1;
+
+	if ((e1 = tty_unregister_driver(&pdc_drv_driver)))
+		printk("pdc_console: failed to unregister pdc_drv driver (%d)\n",
+		       e1);
+}
+
+module_init(pdc_drv_init);
+module_exit(pdc_fini);
+MODULE_DESCRIPTION("PDC Software Console");
+MODULE_AUTHOR(AUTHOR);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/q40_keyb.c linux-2.4.20/drivers/char/q40_keyb.c
--- linux-2.4.19/drivers/char/q40_keyb.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/q40_keyb.c	2002-10-29 11:18:48.000000000 +0000
@@ -427,7 +427,7 @@
 }
 
 
-void __init q40kbd_init_hw(void)
+int __init q40kbd_init_hw(void)
 {
 
 	/* Flush any pending input. */
@@ -438,5 +438,6 @@
 	master_outb(-1,KEYBOARD_UNLOCK_REG);
 	master_outb(1,KEY_IRQ_ENABLE_REG);
 
+	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/random.c linux-2.4.20/drivers/char/random.c
--- linux-2.4.19/drivers/char/random.c	2001-11-09 22:01:21.000000000 +0000
+++ linux-2.4.20/drivers/char/random.c	2002-10-29 11:18:32.000000000 +0000
@@ -412,13 +412,13 @@
  * deal with a variable rotate of x bits.  So we use a bit of asm magic.
  */
 #if (!defined (__i386__))
-extern inline __u32 rotate_left(int i, __u32 word)
+static inline __u32 rotate_left(int i, __u32 word)
 {
 	return (word << i) | (word >> (32 - i));
 	
 }
 #else
-extern inline __u32 rotate_left(int i, __u32 word)
+static inline __u32 rotate_left(int i, __u32 word)
 {
 	__asm__("roll %%cl,%0"
 		:"=r" (word)
@@ -735,7 +735,7 @@
 	int		entropy = 0;
 
 #if defined (__i386__)
-	if ( test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability) ) {
+	if (cpu_has_tsc) {
 		__u32 high;
 		rdtsc(time, high);
 		num ^= high;
@@ -1643,7 +1643,7 @@
 			return -EINVAL;
 		if (size > random_state->poolinfo.poolwords)
 			size = random_state->poolinfo.poolwords;
-		if (copy_to_user(p, random_state->pool, size * 4))
+		if (copy_to_user(p, random_state->pool, size * sizeof(__u32)))
 			return -EFAULT;
 		return 0;
 	case RNDADDENTROPY:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/rio/linux_compat.h linux-2.4.20/drivers/char/rio/linux_compat.h
--- linux-2.4.19/drivers/char/rio/linux_compat.h	2001-07-04 21:41:33.000000000 +0000
+++ linux-2.4.20/drivers/char/rio/linux_compat.h	2002-10-29 11:18:36.000000000 +0000
@@ -60,9 +60,6 @@
 
 #define getpid()    (current->pid)
 
-#define major(dev) MAJOR(dev)
-#define minor(dev) MINOR(dev)
-
 #define QSIZE SERIAL_XMIT_SIZE
 
 #define pseterr(errno) return (- errno)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/rio/rio_linux.h linux-2.4.20/drivers/char/rio/rio_linux.h
--- linux-2.4.19/drivers/char/rio/rio_linux.h	2001-07-04 21:41:33.000000000 +0000
+++ linux-2.4.20/drivers/char/rio/rio_linux.h	2002-10-29 11:18:33.000000000 +0000
@@ -178,10 +178,10 @@
 
 #ifdef DEBUG
 #define rio_dprintk(f, str...) do { if (rio_debug & f) printk (str);} while (0)
-#define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter " __FUNCTION__ "\n")
-#define func_exit()  rio_dprintk (RIO_DEBUG_FLOW, "rio: exit  " __FUNCTION__ "\n")
-#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter " __FUNCTION__ \
-                                   "(port %d)\n", port->line)
+#define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s\n", __FUNCTION__)
+#define func_exit()  rio_dprintk (RIO_DEBUG_FLOW, "rio: exit  %s\n", __FUNCTION__)
+#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s (port %d)\n",  \
+				__FUNCTION__, port->line)
 #else
 #define rio_dprintk(f, str...) /* nothing */
 #define func_enter()
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/rio/riocmd.c linux-2.4.20/drivers/char/rio/riocmd.c
--- linux-2.4.19/drivers/char/rio/riocmd.c	2001-09-07 16:28:38.000000000 +0000
+++ linux-2.4.20/drivers/char/rio/riocmd.c	2002-10-29 11:18:36.000000000 +0000
@@ -462,8 +462,8 @@
 		rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Length	  0x%x (%d)\n", PacketP->len,PacketP->len );
 		rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Control	 0x%x (%d)\n", PacketP->control, PacketP->control);
 		rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Check	   0x%x (%d)\n", PacketP->csum, PacketP->csum );
-		rio_dprintk (RIO_DEBUG_CMD, "COMMAND information: Host Port Number 0x%x, 
-					Command Code 0x%x\n", PktCmdP->PhbNum, PktCmdP->Command );
+		rio_dprintk (RIO_DEBUG_CMD, "COMMAND information: Host Port Number 0x%x, "
+					"Command Code 0x%x\n", PktCmdP->PhbNum, PktCmdP->Command );
 		return TRUE;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/sbc60xxwdt.c linux-2.4.20/drivers/char/sbc60xxwdt.c
--- linux-2.4.19/drivers/char/sbc60xxwdt.c	2001-09-13 22:21:32.000000000 +0000
+++ linux-2.4.20/drivers/char/sbc60xxwdt.c	2002-10-29 11:18:33.000000000 +0000
@@ -234,7 +234,7 @@
 {
 	static struct watchdog_info ident=
 	{
-		0,
+		WDIOF_MAGICCLOSE,
 		1,
 		"SB60xx"
 	};
@@ -300,15 +300,16 @@
 
 	unregister_reboot_notifier(&wdt_notifier);
 	release_region(WDT_START,1);
-	release_region(WDT_STOP,1);
+//	release_region(WDT_STOP,1);
 }
 
 static int __init sbc60xxwdt_init(void)
 {
 	int rc = -EBUSY;
 
-	if (!request_region(WDT_STOP, 1, "SBC 60XX WDT"))
-		goto err_out;
+//	We cannot reserve 0x45 - the kernel already has!
+//	if (!request_region(WDT_STOP, 1, "SBC 60XX WDT"))
+//		goto err_out;
 	if (!request_region(WDT_START, 1, "SBC 60XX WDT"))
 		goto err_out_region1;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/sc1200wdt.c linux-2.4.20/drivers/char/sc1200wdt.c
--- linux-2.4.19/drivers/char/sc1200wdt.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/sc1200wdt.c	2002-10-29 11:18:36.000000000 +0000
@@ -22,6 +22,8 @@
  *		 <rob@osinvestor.com>	Return proper status instead of temperature warning
  *					Add WDIOC_GETBOOTSTATUS and WDIOC_SETOPTIONS ioctls
  *					Fix CONFIG_WATCHDOG_NOWAYOUT
+ *	20020530 Joel Becker		Add Matt Domsch's nowayout
+ *					module option
  */
 
 #include <linux/config.h>
@@ -86,6 +88,14 @@
 MODULE_PARM(timeout, "i");
 MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1");
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
 
 /* Read from Data Register */
@@ -161,7 +171,7 @@
 {
 	int new_timeout;
 	static struct watchdog_info ident = {
-		options:		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+		options:		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
 		firmware_version:	0,
 		identity:		"PC87307/PC97307"
 	};
@@ -246,17 +256,20 @@
 		return -ESPIPE;
 	
 	if (len) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-		size_t i;
+		if (!nowayout) {
+			size_t i;
 
-		expect_close = 0;
+			expect_close = 0;
 
-		for (i = 0; i != len; i++)
-		{
-			if (data[i] == 'V')
-				expect_close = 42;
+			for (i = 0; i != len; i++)
+			{
+				char c;
+				if(get_user(c, data+i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 42;
+			}
 		}
-#endif
 		sc1200wdt_write_data(WDTO, timeout);
 		return len;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/sc520_wdt.c linux-2.4.20/drivers/char/sc520_wdt.c
--- linux-2.4.19/drivers/char/sc520_wdt.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/sc520_wdt.c	2002-10-29 11:18:49.000000000 +0000
@@ -110,6 +110,15 @@
 static unsigned long wdt_is_open;
 static int wdt_expect_close;
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 static spinlock_t wdt_spinlock;
 /*
  *	Whack the dog
@@ -172,12 +181,12 @@
 
 static void wdt_turnoff(void)
 {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-	/* Stop the timer */
-	del_timer(&timer);
-	wdt_config(0);
-	printk(OUR_NAME ": Watchdog timer is now disabled...\n");
-#endif
+	if (!nowayout) {
+		/* Stop the timer */
+		del_timer(&timer);
+		wdt_config(0);
+		printk(OUR_NAME ": Watchdog timer is now disabled...\n");
+	}
 }
 
 
@@ -201,9 +210,13 @@
 		wdt_expect_close = 0;
 
 		/* now scan */
-		for(ofs = 0; ofs != count; ofs++) 
-			if(buf[ofs] == 'V')
+		for(ofs = 0; ofs != count; ofs++) {
+			char c;
+			if (get_user(c, buf + ofs))
+				return -EFAULT;
+			if(c == 'V')
 				wdt_expect_close = 1;
+		}
 
 		/* Well, anyhow someone wrote to us, we should return that favour */
 		next_heartbeat = jiffies + WDT_HEARTBEAT;
@@ -222,9 +235,9 @@
 				return -EBUSY;
 			/* Good, fire up the show */
 			wdt_startup();
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
-			MOD_INC_USE_COUNT;
-#endif	
+			if (nowayout) {
+				MOD_INC_USE_COUNT;
+			}
 			return 0;
 		default:
 			return -ENODEV;
@@ -256,7 +269,7 @@
 {
 	static struct watchdog_info ident=
 	{
-		0,
+		WDIOF_MAGICCLOSE,
 		1,
 		"SC520"
 	};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/serial.c linux-2.4.20/drivers/char/serial.c
--- linux-2.4.19/drivers/char/serial.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/serial.c	2002-10-29 11:18:36.000000000 +0000
@@ -3326,8 +3326,8 @@
 	return ret;
 }
 
-int rs_read_proc(char *page, char **start, off_t off, int count,
-		 int *eof, void *data)
+static int rs_read_proc(char *page, char **start, off_t off, int count,
+			int *eof, void *data)
 {
 	int i, len = 0, l;
 	off_t	begin = 0;
@@ -5237,7 +5237,7 @@
 	{	0, }
 };
 
-static void inline avoid_irq_share(struct pci_dev *dev)
+static inline void avoid_irq_share(struct pci_dev *dev)
 {
 	int i, map = 0x1FF8;
 	struct serial_state *state = rs_table;
@@ -5274,7 +5274,7 @@
        return 0;
 }
 
-static int inline check_compatible_id(struct pci_dev *dev)
+static inline int check_compatible_id(struct pci_dev *dev)
 {
        int i;
        for (i = 0; i < DEVICE_COUNT_COMPATIBLE; i++)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/serial167.c linux-2.4.20/drivers/char/serial167.c
--- linux-2.4.19/drivers/char/serial167.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/serial167.c	2002-10-29 11:18:39.000000000 +0000
@@ -62,6 +62,7 @@
 #include <linux/major.h>
 #include <linux/mm.h>
 #include <linux/console.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/shwdt.c linux-2.4.20/drivers/char/shwdt.c
--- linux-2.4.19/drivers/char/shwdt.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/shwdt.c	2002-10-29 11:18:35.000000000 +0000
@@ -1,9 +1,9 @@
 /*
  * drivers/char/shwdt.c
  *
- * Watchdog driver for integrated watchdog in the SuperH 3/4 processors.
+ * Watchdog driver for integrated watchdog in the SuperH processors.
  *
- * Copyright (C) 2001 Paul Mundt <lethal@chaoticdreams.org>
+ * Copyright (C) 2001, 2002 Paul Mundt <lethal@0xd6.org>
  *
  * 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
@@ -30,14 +30,17 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
-#if defined(CONFIG_CPU_SH4)
+#if defined(CONFIG_CPU_SH5)
+  #define WTCNT		CPRC_BASE + 0x10
+  #define WTCSR		CPRC_BASE + 0x18
+#elif defined(CONFIG_CPU_SH4)
   #define WTCNT		0xffc00008
   #define WTCSR		0xffc0000c
 #elif defined(CONFIG_CPU_SH3)
   #define WTCNT		0xffffff84
   #define WTCSR		0xffffff86
 #else
-  #error "Can't use SH 3/4 watchdog on non-SH 3/4 processor."
+  #error "Can't use SuperH watchdog on this platform"
 #endif
 
 #define WTCNT_HIGH	0x5a00
@@ -237,7 +240,10 @@
 		shwdt_expect_close = 0;
 
 		for (i = 0; i != count; i++) {
-			if (buf[i] == 'V')
+			char c;
+			if (get_user(c, buf + i))
+				return -EFAULT;
+			if (c == 'V')
 				shwdt_expect_close = 42;
 		}
 		next_heartbeat = jiffies + (sh_heartbeat * HZ);
@@ -344,7 +350,7 @@
 };
 
 static struct watchdog_info sh_wdt_info = {
-	options:		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+	options:		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
 	firmware_version:	0,
 	identity:		"SH WDT",
 };
@@ -423,8 +429,8 @@
 MODULE_PARM(clock_division_ratio, "i");
 MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7.");
 
-MODULE_AUTHOR("Paul Mundt <lethal@chaoticdreams.org>");
-MODULE_DESCRIPTION("SH 3/4 watchdog driver");
+MODULE_AUTHOR("Paul Mundt <lethal@0xd6.org>");
+MODULE_DESCRIPTION("SuperH watchdog driver");
 MODULE_LICENSE("GPL");
 
 module_init(sh_wdt_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/softdog.c linux-2.4.20/drivers/char/softdog.c
--- linux-2.4.19/drivers/char/softdog.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/softdog.c	2002-10-29 11:18:39.000000000 +0000
@@ -31,6 +31,9 @@
  *	Added soft_noboot; Allows testing the softdog trigger without 
  *	requiring a recompile.
  *	Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
+ *
+ *  20020530 Joel Becker <joel.becker@oracle.com>
+ *  	Added Matt Domsch's nowayout module option.
  */
  
 #include <linux/module.h>
@@ -48,6 +51,7 @@
 
 #define TIMER_MARGIN	60		/* (secs) Default is 1 minute */
 
+static int expect_close = 0;
 static int soft_margin = TIMER_MARGIN;	/* in seconds */
 #ifdef ONLY_TESTING
 static int soft_noboot = 1;
@@ -59,6 +63,15 @@
 MODULE_PARM(soft_noboot,"i");
 MODULE_LICENSE("GPL");
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 /*
  *	Our timer
  */
@@ -95,9 +108,9 @@
 {
 	if(test_and_set_bit(0, &timer_alive))
 		return -EBUSY;
-#ifdef CONFIG_WATCHDOG_NOWAYOUT	 
-	MOD_INC_USE_COUNT;
-#endif	
+	if (nowayout) {
+		MOD_INC_USE_COUNT;
+	}
 	/*
 	 *	Activate timer
 	 */
@@ -109,11 +122,13 @@
 {
 	/*
 	 *	Shut off the timer.
-	 * 	Lock it in if it's a module and we defined ...NOWAYOUT
+	 * 	Lock it in if it's a module and we set nowayout
 	 */
-#ifndef CONFIG_WATCHDOG_NOWAYOUT	 
-	del_timer(&watchdog_ticktock);
-#endif	
+	if (expect_close) {
+		del_timer(&watchdog_ticktock);
+	} else {
+		printk(KERN_CRIT "SOFTDOG: WDT device closed unexpectedly.  WDT will not stop!\n");
+	}
 	clear_bit(0, &timer_alive);
 	return 0;
 }
@@ -128,6 +143,20 @@
 	 *	Refresh the timer.
 	 */
 	if(len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != len; i++) {
+				char c;
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
 		mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
 		return 1;
 	}
@@ -139,7 +168,7 @@
 {
 	int new_margin;
 	static struct watchdog_info ident = {
-		WDIOF_SETTIMEOUT,
+		WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
 		0,
 		"Software Watchdog"
 	};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/sonypi.h linux-2.4.20/drivers/char/sonypi.h
--- linux-2.4.19/drivers/char/sonypi.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/sonypi.h	2002-10-29 11:18:32.000000000 +0000
@@ -214,6 +214,7 @@
 /* The set of possible back button events */
 static struct sonypi_event sonypi_backev[] = {
 	{ 0x20, SONYPI_EVENT_BACK_PRESSED },
+	{ 0x3b, SONYPI_EVENT_HELP_PRESSED },
 	{ 0x00, 0x00 }
 };
 
@@ -258,7 +259,7 @@
 	while (--n && (command)) \
 		udelay(1); \
 	if (!n && (verbose || !quiet)) \
-		printk(KERN_WARNING "sonypi command failed at " __FILE__ " : " __FUNCTION__ "(line %d)\n", __LINE__); \
+		printk(KERN_WARNING "sonypi command failed at " __FILE__ " : %s (line %d)\n", __FUNCTION__, __LINE__); \
 }
 
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/stallion.c linux-2.4.20/drivers/char/stallion.c
--- linux-2.4.19/drivers/char/stallion.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/stallion.c	2002-10-29 11:18:34.000000000 +0000
@@ -2315,7 +2315,6 @@
 	stlpanel_t	*panelp;
 	unsigned int	status;
 	char		*name;
-	int		rc;
 
 #if DEBUG
 	printk("stl_initeio(brdp=%x)\n", (int) brdp);
@@ -2436,10 +2435,10 @@
 	if (request_irq(brdp->irq, stl_intr, SA_SHIRQ, name, brdp) != 0) {
 		printk("STALLION: failed to register interrupt "
 		       "routine for %s irq=%d\n", name, brdp->irq);
-		rc = -ENODEV;
+		return -ENODEV;
 	}
 
-	return(rc);
+	return 0;
 }
 
 /*****************************************************************************/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/sx.c linux-2.4.20/drivers/char/sx.c
--- linux-2.4.19/drivers/char/sx.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/sx.c	2002-10-29 11:18:39.000000000 +0000
@@ -407,11 +407,11 @@
 
 
 
-#define func_enter() sx_dprintk (SX_DEBUG_FLOW, "sx: enter " __FUNCTION__ "\n")
-#define func_exit()  sx_dprintk (SX_DEBUG_FLOW, "sx: exit  " __FUNCTION__ "\n")
+#define func_enter() sx_dprintk (SX_DEBUG_FLOW, "sx: enter %s\b",__FUNCTION__)
+#define func_exit()  sx_dprintk (SX_DEBUG_FLOW, "sx: exit  %s\n", __FUNCTION__)
 
-#define func_enter2() sx_dprintk (SX_DEBUG_FLOW, "sx: enter " __FUNCTION__ \
-                                  "(port %d)\n", port->line)
+#define func_enter2() sx_dprintk (SX_DEBUG_FLOW, "sx: enter %s (port %d)\n", \
+					__FUNCTION__, port->line)
 
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/synclink.c linux-2.4.20/drivers/char/synclink.c
--- linux-2.4.19/drivers/char/synclink.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/synclink.c	2002-10-29 11:18:37.000000000 +0000
@@ -880,22 +880,22 @@
  * Global linked list of SyncLink devices
  */
 struct mgsl_struct *mgsl_device_list;
-int mgsl_device_count;
+static int mgsl_device_count;
 
 /*
  * Set this param to non-zero to load eax with the
  * .text section address and breakpoint on module load.
  * This is useful for use with gdb and add-symbol-file command.
  */
-int break_on_load;
+static int break_on_load;
 
 /*
  * Driver major number, defaults to zero to get auto
  * assigned major number. May be forced as module parameter.
  */
-int ttymajor;
+static int ttymajor;
 
-int cuamajor;
+static int cuamajor;
 
 /*
  * Array of user specified options for ISA adapters.
@@ -8016,7 +8016,7 @@
 {
 	struct mgsl_struct *info = d->priv;
 	int err;
-	long flags;
+	unsigned long flags;
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("mgsl_sppp_open(%s)\n",info->netname);	
@@ -8059,7 +8059,7 @@
 void mgsl_sppp_tx_timeout(struct net_device *dev)
 {
 	struct mgsl_struct *info = dev->priv;
-	long flags;
+	unsigned long flags;
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("mgsl_sppp_tx_timeout(%s)\n",info->netname);	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/synclinkmp.c linux-2.4.20/drivers/char/synclinkmp.c
--- linux-2.4.19/drivers/char/synclinkmp.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/synclinkmp.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,5611 @@
+/*
+ * $Id: synclinkmp.c,v 3.17 2002/04/22 16:05:39 paulkf Exp $
+ *
+ * Device driver for Microgate SyncLink Multiport
+ * high speed multiprotocol serial adapter.
+ *
+ * written by Paul Fulghum for Microgate Corporation
+ * paulkf@microgate.com
+ *
+ * Microgate and SyncLink are trademarks of Microgate Corporation
+ *
+ * Derived from serial.c written by Theodore Ts'o and Linus Torvalds
+ * This code is released under the GNU General Public License (GPL)
+ *
+ * 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.
+ */
+
+#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
+#if defined(__i386__)
+#  define BREAKPOINT() asm("   int $3");
+#else
+#  define BREAKPOINT() { }
+#endif
+
+#define MAX_DEVICES 12
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <asm/serial.h>
+#include <linux/delay.h>
+#include <linux/ioctl.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/bitops.h>
+#include <asm/types.h>
+#include <linux/termios.h>
+#include <linux/tqueue.h>
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE
+#define CONFIG_SYNCLINK_SYNCPPP 1
+#endif
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+#include <net/syncppp.h>
+#endif
+
+#include <asm/segment.h>
+#define GET_USER(error,value,addr) error = get_user(value,addr)
+#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
+#define PUT_USER(error,value,addr) error = put_user(value,addr)
+#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
+
+#include <asm/uaccess.h>
+
+#include "linux/synclink.h"
+
+static MGSL_PARAMS default_params = {
+	MGSL_MODE_HDLC,			/* unsigned long mode */
+	0,				/* unsigned char loopback; */
+	HDLC_FLAG_UNDERRUN_ABORT15,	/* unsigned short flags; */
+	HDLC_ENCODING_NRZI_SPACE,	/* unsigned char encoding; */
+	0,				/* unsigned long clock_speed; */
+	0xff,				/* unsigned char addr_filter; */
+	HDLC_CRC_16_CCITT,		/* unsigned short crc_type; */
+	HDLC_PREAMBLE_LENGTH_8BITS,	/* unsigned char preamble_length; */
+	HDLC_PREAMBLE_PATTERN_NONE,	/* unsigned char preamble; */
+	9600,				/* unsigned long data_rate; */
+	8,				/* unsigned char data_bits; */
+	1,				/* unsigned char stop_bits; */
+	ASYNC_PARITY_NONE		/* unsigned char parity; */
+};
+
+/* size in bytes of DMA data buffers */
+#define SCABUFSIZE 	1024
+#define SCA_MEM_SIZE	0x40000
+#define SCA_BASE_SIZE   512
+#define SCA_REG_SIZE    16
+#define SCA_MAX_PORTS   4
+#define SCAMAXDESC 	128
+
+#define	BUFFERLISTSIZE	4096
+
+/* SCA-I style DMA buffer descriptor */
+typedef struct _SCADESC
+{
+	u16	next;		/* lower l6 bits of next descriptor addr */
+	u16	buf_ptr;	/* lower 16 bits of buffer addr */
+	u8	buf_base;	/* upper 8 bits of buffer addr */
+	u8	pad1;
+	u16	length;		/* length of buffer */
+	u8	status;		/* status of buffer */
+	u8	pad2;
+} SCADESC, *PSCADESC;
+
+typedef struct _SCADESC_EX
+{
+	/* device driver bookkeeping section */
+	char 	*virt_addr;    	/* virtual address of data buffer */
+	u16	phys_entry;	/* lower 16-bits of physical address of this descriptor */
+} SCADESC_EX, *PSCADESC_EX;
+
+/* The queue of BH actions to be performed */
+
+#define BH_RECEIVE  1
+#define BH_TRANSMIT 2
+#define BH_STATUS   4
+
+#define IO_PIN_SHUTDOWN_LIMIT 100
+
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+struct	_input_signal_events {
+	int	ri_up;
+	int	ri_down;
+	int	dsr_up;
+	int	dsr_down;
+	int	dcd_up;
+	int	dcd_down;
+	int	cts_up;
+	int	cts_down;
+};
+
+/*
+ * Device instance data structure
+ */
+typedef struct _synclinkmp_info {
+	void *if_ptr;				/* General purpose pointer (used by SPPP) */
+	int			magic;
+	int			flags;
+	int			count;		/* count of opens */
+	int			line;
+	unsigned short		close_delay;
+	unsigned short		closing_wait;	/* time to wait before closing */
+
+	struct mgsl_icount	icount;
+
+	struct termios		normal_termios;
+	struct termios		callout_termios;
+
+	struct tty_struct 	*tty;
+	int			timeout;
+	int			x_char;		/* xon/xoff character */
+	int			blocked_open;	/* # of blocked opens */
+	long			session;	/* Session of opening process */
+	long			pgrp;		/* pgrp of opening process */
+	u16			read_status_mask1;  /* break detection (SR1 indications) */
+	u16			read_status_mask2;  /* parity/framing/overun (SR2 indications) */
+	unsigned char 		ignore_status_mask1;  /* break detection (SR1 indications) */
+	unsigned char		ignore_status_mask2;  /* parity/framing/overun (SR2 indications) */
+	unsigned char 		*tx_buf;
+	int			tx_put;
+	int			tx_get;
+	int			tx_count;
+
+	wait_queue_head_t	open_wait;
+	wait_queue_head_t	close_wait;
+
+	wait_queue_head_t	status_event_wait_q;
+	wait_queue_head_t	event_wait_q;
+	struct timer_list	tx_timer;	/* HDLC transmit timeout timer */
+	struct _synclinkmp_info	*next_device;	/* device list link */
+	struct timer_list	status_timer;	/* input signal status check timer */
+
+	spinlock_t lock;		/* spinlock for synchronizing with ISR */
+	struct tq_struct task;	 		/* task structure for scheduling bh */
+
+	u32 max_frame_size;			/* as set by device config */
+
+	u32 pending_bh;
+
+	int bh_running;				/* Protection from multiple */
+	int isr_overflow;
+	int bh_requested;
+
+	int dcd_chkcount;			/* check counts to prevent */
+	int cts_chkcount;			/* too many IRQs if a signal */
+	int dsr_chkcount;			/* is floating */
+	int ri_chkcount;
+
+	char *buffer_list;			/* virtual address of Rx & Tx buffer lists */
+	unsigned long buffer_list_phys;
+
+	unsigned int rx_buf_count;		/* count of total allocated Rx buffers */
+	SCADESC *rx_buf_list;   		/* list of receive buffer entries */
+	SCADESC_EX rx_buf_list_ex[SCAMAXDESC]; /* list of receive buffer entries */
+	unsigned int current_rx_buf;
+
+	unsigned int tx_buf_count;		/* count of total allocated Tx buffers */
+	SCADESC *tx_buf_list;		/* list of transmit buffer entries */
+	SCADESC_EX tx_buf_list_ex[SCAMAXDESC]; /* list of transmit buffer entries */
+	unsigned int last_tx_buf;
+
+	unsigned char *tmp_rx_buf;
+	unsigned int tmp_rx_buf_count;
+
+	int rx_enabled;
+	int rx_overflow;
+
+	int tx_enabled;
+	int tx_active;
+	u32 idle_mode;
+
+	unsigned char ie0_value;
+	unsigned char ie1_value;
+	unsigned char ie2_value;
+	unsigned char ctrlreg_value;
+	unsigned char old_signals;
+
+	char device_name[25];			/* device instance name */
+
+	int port_count;
+	int adapter_num;
+	int port_num;
+
+	struct _synclinkmp_info *port_array[SCA_MAX_PORTS];
+
+	unsigned int bus_type;			/* expansion bus type (ISA,EISA,PCI) */
+
+	unsigned int irq_level;			/* interrupt level */
+	unsigned long irq_flags;
+	int irq_requested;			/* nonzero if IRQ requested */
+
+	MGSL_PARAMS params;			/* communications parameters */
+
+	unsigned char serial_signals;		/* current serial signal states */
+
+	int irq_occurred;			/* for diagnostics use */
+	unsigned int init_error;		/* Initialization startup error */
+
+	u32 last_mem_alloc;
+	unsigned char* memory_base;		/* shared memory address (PCI only) */
+	u32 phys_memory_base;
+    	int shared_mem_requested;
+
+	unsigned char* sca_base;		/* HD64570 SCA Memory address */
+	u32 phys_sca_base;
+	u32 sca_offset;
+	int sca_base_requested;
+
+	unsigned char* lcr_base;		/* local config registers (PCI only) */
+	u32 phys_lcr_base;
+	u32 lcr_offset;
+	int lcr_mem_requested;
+
+	unsigned char* statctrl_base;		/* status/control register memory */
+	u32 phys_statctrl_base;
+	u32 statctrl_offset;
+	int sca_statctrl_requested;
+
+	u32 misc_ctrl_value;
+	char flag_buf[MAX_ASYNC_BUFFER_SIZE];
+	char char_buf[MAX_ASYNC_BUFFER_SIZE];
+	BOOLEAN drop_rts_on_tx_done;
+
+	struct	_input_signal_events	input_signal_events;
+
+	/* SPPP/Cisco HDLC device parts */
+	int netcount;
+	int dosyncppp;
+	spinlock_t netlock;
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+	struct ppp_device pppdev;
+	char netname[10];
+	struct net_device *netdev;
+	struct net_device_stats netstats;
+	struct net_device netdevice;
+#endif
+} SLMP_INFO;
+
+#define MGSL_MAGIC 0x5401
+
+/*
+ * define serial signal status change macros
+ */
+#define	MISCSTATUS_DCD_LATCHED	(SerialSignal_DCD<<8)	/* indicates change in DCD */
+#define MISCSTATUS_RI_LATCHED	(SerialSignal_RI<<8)	/* indicates change in RI */
+#define MISCSTATUS_CTS_LATCHED	(SerialSignal_CTS<<8)	/* indicates change in CTS */
+#define MISCSTATUS_DSR_LATCHED	(SerialSignal_DSR<<8)	/* change in DSR */
+
+/* Common Register macros */
+#define LPR	0x00
+#define PABR0	0x02
+#define PABR1	0x03
+#define WCRL	0x04
+#define WCRM	0x05
+#define WCRH	0x06
+#define DPCR	0x08
+#define DMER	0x09
+#define ISR0	0x10
+#define ISR1	0x11
+#define ISR2	0x12
+#define IER0	0x14
+#define IER1	0x15
+#define IER2	0x16
+#define ITCR	0x18
+#define INTVR 	0x1a
+#define IMVR	0x1c
+
+/* MSCI Register macros */
+#define TRB	0x20
+#define TRBL	0x20
+#define TRBH	0x21
+#define SR0	0x22
+#define SR1	0x23
+#define SR2	0x24
+#define SR3	0x25
+#define FST	0x26
+#define IE0	0x28
+#define IE1	0x29
+#define IE2	0x2a
+#define FIE	0x2b
+#define CMD	0x2c
+#define MD0	0x2e
+#define MD1	0x2f
+#define MD2	0x30
+#define CTL	0x31
+#define SA0	0x32
+#define SA1	0x33
+#define IDL	0x34
+#define TMC	0x35
+#define RXS	0x36
+#define TXS	0x37
+#define TRC0	0x38
+#define TRC1	0x39
+#define RRC	0x3a
+#define CST0	0x3c
+#define CST1	0x3d
+
+/* Timer Register Macros */
+#define TCNT	0x60
+#define TCNTL	0x60
+#define TCNTH	0x61
+#define TCONR	0x62
+#define TCONRL	0x62
+#define TCONRH	0x63
+#define TMCS	0x64
+#define TEPR	0x65
+
+/* DMA Controller Register macros */
+#define DAR	0x80
+#define DARL	0x80
+#define DARH	0x81
+#define DARB	0x82
+#define BAR	0x80
+#define BARL	0x80
+#define BARH	0x81
+#define BARB	0x82
+#define SAR	0x84
+#define SARL	0x84
+#define SARH	0x85
+#define SARB	0x86
+#define CPB	0x86
+#define CDA	0x88
+#define CDAL	0x88
+#define CDAH	0x89
+#define EDA	0x8a
+#define EDAL	0x8a
+#define EDAH	0x8b
+#define BFL	0x8c
+#define BFLL	0x8c
+#define BFLH	0x8d
+#define BCR	0x8e
+#define BCRL	0x8e
+#define BCRH	0x8f
+#define DSR	0x90
+#define DMR	0x91
+#define FCT	0x93
+#define DIR	0x94
+#define DCMD	0x95
+
+/* combine with timer or DMA register address */
+#define TIMER0	0x00
+#define TIMER1	0x08
+#define TIMER2	0x10
+#define TIMER3	0x18
+#define RXDMA 	0x00
+#define TXDMA 	0x20
+
+/* SCA Command Codes */
+#define NOOP		0x00
+#define TXRESET		0x01
+#define TXENABLE	0x02
+#define TXDISABLE	0x03
+#define TXCRCINIT	0x04
+#define TXCRCEXCL	0x05
+#define TXEOM		0x06
+#define TXABORT		0x07
+#define MPON		0x08
+#define TXBUFCLR	0x09
+#define RXRESET		0x11
+#define RXENABLE	0x12
+#define RXDISABLE	0x13
+#define RXCRCINIT	0x14
+#define RXREJECT	0x15
+#define SEARCHMP	0x16
+#define RXCRCEXCL	0x17
+#define RXCRCCALC	0x18
+#define CHRESET		0x21
+#define HUNT		0x31
+
+/* DMA command codes */
+#define SWABORT		0x01
+#define FEICLEAR	0x02
+
+/* IE0 */
+#define TXINTE 		BIT7
+#define RXINTE 		BIT6
+#define TXRDYE 		BIT1
+#define RXRDYE 		BIT0
+
+/* IE1 & SR1 */
+#define UDRN   	BIT7
+#define IDLE   	BIT6
+#define SYNCD  	BIT4
+#define FLGD   	BIT4
+#define CCTS   	BIT3
+#define CDCD   	BIT2
+#define BRKD   	BIT1
+#define ABTD   	BIT1
+#define GAPD   	BIT1
+#define BRKE   	BIT0
+#define IDLD	BIT0
+
+/* IE2 & SR2 */
+#define EOM	BIT7
+#define PMP	BIT6
+#define SHRT	BIT6
+#define PE	BIT5
+#define ABT	BIT5
+#define FRME	BIT4
+#define RBIT	BIT4
+#define OVRN	BIT3
+#define CRCE	BIT2
+
+
+#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
+
+/*
+ * Global linked list of SyncLink devices
+ */
+static SLMP_INFO *synclinkmp_device_list = NULL;
+static int synclinkmp_adapter_count = -1;
+static int synclinkmp_device_count = 0;
+
+/*
+ * Set this param to non-zero to load eax with the
+ * .text section address and breakpoint on module load.
+ * This is useful for use with gdb and add-symbol-file command.
+ */
+static int break_on_load=0;
+
+/*
+ * Driver major number, defaults to zero to get auto
+ * assigned major number. May be forced as module parameter.
+ */
+static int ttymajor=0;
+static int cuamajor=0;
+
+/*
+ * Array of user specified options for ISA adapters.
+ */
+static int debug_level = 0;
+static int maxframe[MAX_DEVICES] = {0,};
+static int dosyncppp[MAX_DEVICES] = {0,};
+
+MODULE_PARM(break_on_load,"i");
+MODULE_PARM(ttymajor,"i");
+MODULE_PARM(cuamajor,"i");
+MODULE_PARM(debug_level,"i");
+MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICES) "i");
+MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i");
+
+static char *driver_name = "SyncLink MultiPort driver";
+static char *driver_version = "$Revision: 3.17 $";
+
+static int __devinit synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent);
+static void __devexit synclinkmp_remove_one(struct pci_dev *dev);
+
+static struct pci_device_id synclinkmp_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_SCA, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, }, /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, synclinkmp_pci_tbl);
+
+static struct pci_driver synclinkmp_pci_driver = {
+	name:		"synclinkmp",
+	id_table:	synclinkmp_pci_tbl,
+	probe:		synclinkmp_init_one,
+	remove:		__devexit_p(synclinkmp_remove_one),
+};
+
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+static struct tty_struct *serial_table[MAX_DEVICES];
+static struct termios *serial_termios[MAX_DEVICES];
+static struct termios *serial_termios_locked[MAX_DEVICES];
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+
+/* tty callbacks */
+
+static int  open(struct tty_struct *tty, struct file * filp);
+static void close(struct tty_struct *tty, struct file * filp);
+static void hangup(struct tty_struct *tty);
+static void set_termios(struct tty_struct *tty, struct termios *old_termios);
+
+static int  write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
+static void put_char(struct tty_struct *tty, unsigned char ch);
+static void send_xchar(struct tty_struct *tty, char ch);
+static void wait_until_sent(struct tty_struct *tty, int timeout);
+static int  write_room(struct tty_struct *tty);
+static void flush_chars(struct tty_struct *tty);
+static void flush_buffer(struct tty_struct *tty);
+static void tx_hold(struct tty_struct *tty);
+static void tx_release(struct tty_struct *tty);
+
+static int  ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
+static int  read_proc(char *page, char **start, off_t off, int count,int *eof, void *data);
+static int  chars_in_buffer(struct tty_struct *tty);
+static void throttle(struct tty_struct * tty);
+static void unthrottle(struct tty_struct * tty);
+static void set_break(struct tty_struct *tty, int break_state);
+
+/* sppp support and callbacks */
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+static void sppp_init(SLMP_INFO *info);
+static void sppp_delete(SLMP_INFO *info);
+static void sppp_rx_done(SLMP_INFO *info, char *buf, int size);
+static void sppp_tx_done(SLMP_INFO *info);
+
+static int  sppp_cb_open(struct net_device *d);
+static int  sppp_cb_close(struct net_device *d);
+static int  sppp_cb_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static int  sppp_cb_tx(struct sk_buff *skb, struct net_device *dev);
+static void sppp_cb_tx_timeout(struct net_device *dev);
+static struct net_device_stats *sppp_cb_net_stats(struct net_device *dev);
+#endif
+
+/* ioctl handlers */
+
+static int  get_stats(SLMP_INFO *info, struct mgsl_icount *user_icount);
+static int  get_params(SLMP_INFO *info, MGSL_PARAMS *params);
+static int  set_params(SLMP_INFO *info, MGSL_PARAMS *params);
+static int  get_txidle(SLMP_INFO *info, int*idle_mode);
+static int  set_txidle(SLMP_INFO *info, int idle_mode);
+static int  tx_enable(SLMP_INFO *info, int enable);
+static int  tx_abort(SLMP_INFO *info);
+static int  rx_enable(SLMP_INFO *info, int enable);
+static int  map_status(int signals);
+static int  modem_input_wait(SLMP_INFO *info,int arg);
+static int  wait_mgsl_event(SLMP_INFO *info, int *mask_ptr);
+static int  get_modem_info(SLMP_INFO *info, unsigned int *value);
+static int  set_modem_info(SLMP_INFO *info, unsigned int cmd,unsigned int *value);
+static void set_break(struct tty_struct *tty, int break_state);
+
+static void add_device(SLMP_INFO *info);
+static void device_init(int adapter_num, struct pci_dev *pdev);
+static int  claim_resources(SLMP_INFO *info);
+static void release_resources(SLMP_INFO *info);
+
+static int  startup(SLMP_INFO *info);
+static int  block_til_ready(struct tty_struct *tty, struct file * filp,SLMP_INFO *info);
+static void shutdown(SLMP_INFO *info);
+static void program_hw(SLMP_INFO *info);
+static void change_params(SLMP_INFO *info);
+
+static int  init_adapter(SLMP_INFO *info);
+static int  register_test(SLMP_INFO *info);
+static int  irq_test(SLMP_INFO *info);
+static int  loopback_test(SLMP_INFO *info);
+static int  adapter_test(SLMP_INFO *info);
+static int  memory_test(SLMP_INFO *info);
+
+static void reset_adapter(SLMP_INFO *info);
+static void reset_port(SLMP_INFO *info);
+static void async_mode(SLMP_INFO *info);
+static void hdlc_mode(SLMP_INFO *info);
+
+static void rx_stop(SLMP_INFO *info);
+static void rx_start(SLMP_INFO *info);
+static void rx_reset_buffers(SLMP_INFO *info);
+static void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last);
+static int  rx_get_frame(SLMP_INFO *info);
+
+static void tx_start(SLMP_INFO *info);
+static void tx_stop(SLMP_INFO *info);
+static void tx_load_fifo(SLMP_INFO *info);
+static void tx_set_idle(SLMP_INFO *info);
+static void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count);
+
+static void get_signals(SLMP_INFO *info);
+static void set_signals(SLMP_INFO *info);
+static void enable_loopback(SLMP_INFO *info, int enable);
+static void set_rate(SLMP_INFO *info, u32 data_rate);
+
+static int  bh_action(SLMP_INFO *info);
+static void bh_handler(void* Context);
+static void bh_receive(SLMP_INFO *info);
+static void bh_transmit(SLMP_INFO *info);
+static void bh_status(SLMP_INFO *info);
+static void isr_timer(SLMP_INFO *info);
+static void isr_rxint(SLMP_INFO *info);
+static void isr_rxrdy(SLMP_INFO *info);
+static void isr_txint(SLMP_INFO *info);
+static void isr_txrdy(SLMP_INFO *info);
+static void isr_rxdmaok(SLMP_INFO *info);
+static void isr_rxdmaerror(SLMP_INFO *info);
+static void isr_txdmaok(SLMP_INFO *info);
+static void isr_txdmaerror(SLMP_INFO *info);
+static void isr_io_pin(SLMP_INFO *info, u16 status);
+static void synclinkmp_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+
+static int  alloc_dma_bufs(SLMP_INFO *info);
+static void free_dma_bufs(SLMP_INFO *info);
+static int  alloc_buf_list(SLMP_INFO *info);
+static int  alloc_frame_bufs(SLMP_INFO *info, SCADESC *list, SCADESC_EX *list_ex,int count);
+static int  alloc_tmp_rx_buf(SLMP_INFO *info);
+static void free_tmp_rx_buf(SLMP_INFO *info);
+
+static void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count);
+static void trace_block(SLMP_INFO *info, const char* data, int count, int xmit);
+static void tx_timeout(unsigned long context);
+static void status_timeout(unsigned long context);
+
+static unsigned char read_reg(SLMP_INFO *info, unsigned char addr);
+static void write_reg(SLMP_INFO *info, unsigned char addr, unsigned char val);
+static u16 read_reg16(SLMP_INFO *info, unsigned char addr);
+static void write_reg16(SLMP_INFO *info, unsigned char addr, u16 val);
+static unsigned char read_status_reg(SLMP_INFO * info);
+static void write_control_reg(SLMP_INFO * info);
+
+
+static unsigned char rx_active_fifo_level = 16;	// rx request FIFO activation level in bytes
+static unsigned char tx_active_fifo_level = 16;	// tx request FIFO activation level in bytes
+static unsigned char tx_negate_fifo_level = 32;	// tx request FIFO negation level in bytes
+
+static u32 misc_ctrl_value = 0x007e4040;
+static u32 lcr1_brdr_value = 0x0080002d;
+
+static u32 read_ahead_count = 8;
+
+/* DPCR, DMA Priority Control
+ *
+ * 07..05  Not used, must be 0
+ * 04      BRC, bus release condition: 0=all transfers complete
+ *              1=release after 1 xfer on all channels
+ * 03      CCC, channel change condition: 0=every cycle
+ *              1=after each channel completes all xfers
+ * 02..00  PR<2..0>, priority 100=round robin
+ *
+ * 00000100 = 0x00
+ */
+static unsigned char dma_priority = 0x04;
+
+// Number of bytes that can be written to shared RAM
+// in a single write operation
+static u32 sca_pci_load_interval = 64;
+
+/*
+ * 1st function defined in .text section. Calling this function in
+ * init_module() followed by a breakpoint allows a remote debugger
+ * (gdb) to get the .text address for the add-symbol-file command.
+ * This allows remote debugging of dynamically loadable modules.
+ */
+static void* synclinkmp_get_text_ptr(void);
+static void* synclinkmp_get_text_ptr() {return synclinkmp_get_text_ptr;}
+
+static inline int sanity_check(SLMP_INFO *info,
+			       kdev_t device, const char *routine)
+{
+#ifdef SANITY_CHECK
+	static const char *badmagic =
+		"Warning: bad magic number for synclinkmp_struct (%s) in %s\n";
+	static const char *badinfo =
+		"Warning: null synclinkmp_struct for (%s) in %s\n";
+
+	if (!info) {
+		printk(badinfo, kdevname(device), routine);
+		return 1;
+	}
+	if (info->magic != MGSL_MAGIC) {
+		printk(badmagic, kdevname(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/* tty callbacks */
+
+/* Called when a port is opened.  Init and enable port.
+ */
+static int open(struct tty_struct *tty, struct file *filp)
+{
+	SLMP_INFO *info;
+	int retval, line;
+	unsigned long flags;
+
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= synclinkmp_device_count)) {
+		printk("%s(%d): open with illegal line #%d.\n",
+			__FILE__,__LINE__,line);
+		return -ENODEV;
+	}
+
+	info = synclinkmp_device_list;
+	while(info && info->line != line)
+		info = info->next_device;
+	if ( !info ){
+		printk("%s(%d):%s Can't find specified device on open (line=%d)\n",
+			__FILE__,__LINE__,info->device_name,line);
+		return -ENODEV;
+	}
+
+	if ( info->init_error ) {
+		printk("%s(%d):%s device is not allocated, init error=%d\n",
+			__FILE__,__LINE__,info->device_name,info->init_error);
+		return -ENODEV;
+	}
+
+	tty->driver_data = info;
+	info->tty = tty;
+	if (sanity_check(info, tty->device, "open"))
+		return -ENODEV;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s open(), old ref count = %d\n",
+			 __FILE__,__LINE__,tty->driver.name, info->count);
+
+	MOD_INC_USE_COUNT;
+
+	/* If port is closing, signal caller to try again */
+	if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+		retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+		goto cleanup;
+	}
+
+	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+	spin_lock_irqsave(&info->netlock, flags);
+	if (info->netcount) {
+		retval = -EBUSY;
+		spin_unlock_irqrestore(&info->netlock, flags);
+		goto cleanup;
+	}
+	info->count++;
+	spin_unlock_irqrestore(&info->netlock, flags);
+
+	if (info->count == 1) {
+		/* 1st open on this device, init hardware */
+		retval = startup(info);
+		if (retval < 0)
+			goto cleanup;
+	}
+
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+		if (debug_level >= DEBUG_LEVEL_INFO)
+			printk("%s(%d):%s block_til_ready() returned %d\n",
+				 __FILE__,__LINE__, info->device_name, retval);
+		goto cleanup;
+	}
+
+	if ((info->count == 1) &&
+	    info->flags & ASYNC_SPLIT_TERMIOS) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->normal_termios;
+		else
+			*tty->termios = info->callout_termios;
+		change_params(info);
+	}
+
+	info->session = current->session;
+	info->pgrp    = current->pgrp;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s open() success\n",
+			 __FILE__,__LINE__, info->device_name);
+	retval = 0;
+
+cleanup:
+	if (retval) {
+		if(MOD_IN_USE)
+			MOD_DEC_USE_COUNT;
+		if(info->count)
+			info->count--;
+	}
+
+	return retval;
+}
+
+/* Called when port is closed. Wait for remaining data to be
+ * sent. Disable port and free resources.
+ */
+static void close(struct tty_struct *tty, struct file *filp)
+{
+	SLMP_INFO * info = (SLMP_INFO *)tty->driver_data;
+
+	if (!info || sanity_check(info, tty->device, "close"))
+		return;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s close() entry, count=%d\n",
+			 __FILE__,__LINE__, info->device_name, info->count);
+
+	if (!info->count || tty_hung_up_p(filp))
+		goto cleanup;
+
+	if ((tty->count == 1) && (info->count != 1)) {
+		/*
+		 * tty->count is 1 and the tty structure will be freed.
+		 * info->count should be one in this case.
+		 * if it's not, correct it so that the port is shutdown.
+		 */
+		printk("%s(%d):%s close: bad refcount; tty->count is 1, "
+		       "info->count is %d\n",
+			 __FILE__,__LINE__, info->device_name, info->count);
+		info->count = 1;
+	}
+
+	info->count--;
+
+	/* if at least one open remaining, leave hardware active */
+	if (info->count)
+		goto cleanup;
+
+	info->flags |= ASYNC_CLOSING;
+
+	/* Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->callout_termios = *tty->termios;
+
+	/* set tty->closing to notify line discipline to
+	 * only process XON/XOFF characters. Only the N_TTY
+	 * discipline appears to use this (ppp does not).
+	 */
+	tty->closing = 1;
+
+	/* wait for transmit data to clear all layers */
+
+	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
+		if (debug_level >= DEBUG_LEVEL_INFO)
+			printk("%s(%d):%s close() calling tty_wait_until_sent\n",
+				 __FILE__,__LINE__, info->device_name );
+		tty_wait_until_sent(tty, info->closing_wait);
+	}
+
+ 	if (info->flags & ASYNC_INITIALIZED)
+ 		wait_until_sent(tty, info->timeout);
+
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+
+	shutdown(info);
+
+	tty->closing = 0;
+	info->tty = 0;
+
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+			 ASYNC_CLOSING);
+
+	wake_up_interruptible(&info->close_wait);
+
+cleanup:
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s close() exit, count=%d\n", __FILE__,__LINE__,
+			tty->driver.name, info->count);
+	if(MOD_IN_USE)
+		MOD_DEC_USE_COUNT;
+}
+
+/* Called by tty_hangup() when a hangup is signaled.
+ * This is the same as closing all open descriptors for the port.
+ */
+static void hangup(struct tty_struct *tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s hangup()\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	if (sanity_check(info, tty->device, "hangup"))
+		return;
+
+	flush_buffer(tty);
+	shutdown(info);
+
+	info->count = 0;
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->tty = 0;
+
+	wake_up_interruptible(&info->open_wait);
+}
+
+/* Set new termios settings
+ */
+static void set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s set_termios()\n", __FILE__,__LINE__,
+			tty->driver.name );
+
+	/* just return if nothing has changed */
+	if ((tty->termios->c_cflag == old_termios->c_cflag)
+	    && (RELEVANT_IFLAG(tty->termios->c_iflag)
+		== RELEVANT_IFLAG(old_termios->c_iflag)))
+	  return;
+
+	change_params(info);
+
+	/* Handle transition to B0 status */
+	if (old_termios->c_cflag & CBAUD &&
+	    !(tty->termios->c_cflag & CBAUD)) {
+		info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
+		spin_lock_irqsave(&info->lock,flags);
+	 	set_signals(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+
+	/* Handle transition away from B0 status */
+	if (!(old_termios->c_cflag & CBAUD) &&
+	    tty->termios->c_cflag & CBAUD) {
+		info->serial_signals |= SerialSignal_DTR;
+ 		if (!(tty->termios->c_cflag & CRTSCTS) ||
+ 		    !test_bit(TTY_THROTTLED, &tty->flags)) {
+			info->serial_signals |= SerialSignal_RTS;
+ 		}
+		spin_lock_irqsave(&info->lock,flags);
+	 	set_signals(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+
+	/* Handle turning off CRTSCTS */
+	if (old_termios->c_cflag & CRTSCTS &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		tx_release(tty);
+	}
+}
+
+/* Send a block of data
+ *
+ * Arguments:
+ *
+ * 	tty		pointer to tty information structure
+ * 	from_user	flag: 1 = from user process
+ * 	buf		pointer to buffer containing send data
+ * 	count		size of send data in bytes
+ *
+ * Return Value:	number of characters written
+ */
+static int write(struct tty_struct *tty, int from_user,
+		 const unsigned char *buf, int count)
+{
+	int	c, ret = 0, err;
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s write() count=%d\n",
+		       __FILE__,__LINE__,info->device_name,count);
+
+	if (sanity_check(info, tty->device, "write"))
+		goto cleanup;
+
+	if (!tty || !info->tx_buf)
+		goto cleanup;
+
+	if (info->params.mode == MGSL_MODE_HDLC) {
+		if (count > info->max_frame_size) {
+			ret = -EIO;
+			goto cleanup;
+		}
+		if (info->tx_active)
+			goto cleanup;
+		if (info->tx_count) {
+			/* send accumulated data from send_char() calls */
+			/* as frame and wait before accepting more data. */
+			tx_load_dma_buffer(info, info->tx_buf, info->tx_count);
+			goto start;
+		}
+		if (!from_user) {
+			ret = info->tx_count = count;
+			tx_load_dma_buffer(info, buf, count);
+			goto start;
+		}
+	}
+
+	for (;;) {
+		c = MIN(count,
+			MIN(info->max_frame_size - info->tx_count - 1,
+			    info->max_frame_size - info->tx_put));
+		if (c <= 0)
+			break;
+			
+		if (from_user) {
+			COPY_FROM_USER(err, info->tx_buf + info->tx_put, buf, c);
+			if (err) {
+				if (!ret)
+					ret = -EFAULT;
+				break;
+			}
+		} else
+			memcpy(info->tx_buf + info->tx_put, buf, c);
+
+		spin_lock_irqsave(&info->lock,flags);
+		info->tx_put += c;
+		if (info->tx_put >= info->max_frame_size)
+			info->tx_put -= info->max_frame_size;
+		info->tx_count += c;
+		spin_unlock_irqrestore(&info->lock,flags);
+
+		buf += c;
+		count -= c;
+		ret += c;
+	}
+
+	if (info->params.mode == MGSL_MODE_HDLC) {
+		if (count) {
+			ret = info->tx_count = 0;
+			goto cleanup;
+		}
+		tx_load_dma_buffer(info, info->tx_buf, info->tx_count);
+	}
+start:
+ 	if (info->tx_count && !tty->stopped && !tty->hw_stopped) {
+		spin_lock_irqsave(&info->lock,flags);
+		if (!info->tx_active)
+		 	tx_start(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+ 	}
+
+cleanup:
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk( "%s(%d):%s write() returning=%d\n",
+			__FILE__,__LINE__,info->device_name,ret);
+	return ret;
+}
+
+/* Add a character to the transmit buffer.
+ */
+static void put_char(struct tty_struct *tty, unsigned char ch)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if ( debug_level >= DEBUG_LEVEL_INFO ) {
+		printk( "%s(%d):%s put_char(%d)\n",
+			__FILE__,__LINE__,info->device_name,ch);
+	}
+
+	if (sanity_check(info, tty->device, "put_char"))
+		return;
+
+	if (!tty || !info->tx_buf)
+		return;
+
+	spin_lock_irqsave(&info->lock,flags);
+
+	if ( (info->params.mode != MGSL_MODE_HDLC) ||
+	     !info->tx_active ) {
+
+		if (info->tx_count < info->max_frame_size - 1) {
+			info->tx_buf[info->tx_put++] = ch;
+			if (info->tx_put >= info->max_frame_size)
+				info->tx_put -= info->max_frame_size;
+			info->tx_count++;
+		}
+	}
+
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/* Send a high-priority XON/XOFF character
+ */
+static void send_xchar(struct tty_struct *tty, char ch)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s send_xchar(%d)\n",
+			 __FILE__,__LINE__, info->device_name, ch );
+
+	if (sanity_check(info, tty->device, "send_xchar"))
+		return;
+
+	info->x_char = ch;
+	if (ch) {
+		/* Make sure transmit interrupts are on */
+		spin_lock_irqsave(&info->lock,flags);
+		if (!info->tx_enabled)
+		 	tx_start(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+}
+
+/* Wait until the transmitter is empty.
+ */
+static void wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	SLMP_INFO * info = (SLMP_INFO *)tty->driver_data;
+	unsigned long orig_jiffies, char_time;
+
+	if (!info )
+		return;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s wait_until_sent() entry\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	if (sanity_check(info, tty->device, "wait_until_sent"))
+		return;
+
+	if (!(info->flags & ASYNC_INITIALIZED))
+		goto exit;
+
+	orig_jiffies = jiffies;
+
+	/* Set check interval to 1/5 of estimated time to
+	 * send a character, and make it at least 1. The check
+	 * interval should also be less than the timeout.
+	 * Note: use tight timings here to satisfy the NIST-PCTS.
+	 */
+
+	if ( info->params.data_rate ) {
+	       	char_time = info->timeout/(32 * 5);
+		if (!char_time)
+			char_time++;
+	} else
+		char_time = 1;
+
+	if (timeout)
+		char_time = MIN(char_time, timeout);
+
+	if ( info->params.mode == MGSL_MODE_HDLC ) {
+		while (info->tx_active) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(char_time);
+			if (signal_pending(current))
+				break;
+			if (timeout && ((orig_jiffies + timeout) < jiffies))
+				break;
+		}
+	} else {
+		//TODO: determine if there is something similar to USC16C32
+		// 	TXSTATUS_ALL_SENT status
+		while ( info->tx_active && info->tx_enabled) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(char_time);
+			if (signal_pending(current))
+				break;
+			if (timeout && ((orig_jiffies + timeout) < jiffies))
+				break;
+		}
+	}
+
+exit:
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s wait_until_sent() exit\n",
+			 __FILE__,__LINE__, info->device_name );
+}
+
+/* Return the count of free bytes in transmit buffer
+ */
+static int write_room(struct tty_struct *tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	int ret;
+
+	if (sanity_check(info, tty->device, "write_room"))
+		return 0;
+
+	if (info->params.mode == MGSL_MODE_HDLC) {
+		ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE;
+	} else {
+		ret = info->max_frame_size - info->tx_count - 1;
+		if (ret < 0)
+			ret = 0;
+	}
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s write_room()=%d\n",
+		       __FILE__, __LINE__, info->device_name, ret);
+
+	return ret;
+}
+
+/* enable transmitter and send remaining buffered characters
+ */
+static void flush_chars(struct tty_struct *tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk( "%s(%d):%s flush_chars() entry tx_count=%d\n",
+			__FILE__,__LINE__,info->device_name,info->tx_count);
+
+	if (sanity_check(info, tty->device, "flush_chars"))
+		return;
+
+	if (info->tx_count <= 0 || tty->stopped || tty->hw_stopped ||
+	    !info->tx_buf)
+		return;
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk( "%s(%d):%s flush_chars() entry, starting transmitter\n",
+			__FILE__,__LINE__,info->device_name );
+
+	spin_lock_irqsave(&info->lock,flags);
+
+	if (!info->tx_active) {
+		if ( (info->params.mode == MGSL_MODE_HDLC) &&
+			info->tx_count ) {
+			/* operating in synchronous (frame oriented) mode */
+			/* copy data from circular tx_buf to */
+			/* transmit DMA buffer. */
+			tx_load_dma_buffer(info,
+				 info->tx_buf,info->tx_count);
+		}
+	 	tx_start(info);
+	}
+
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/* Discard all data in the send buffer
+ */
+static void flush_buffer(struct tty_struct *tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s flush_buffer() entry\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	if (sanity_check(info, tty->device, "flush_buffer"))
+		return;
+
+	spin_lock_irqsave(&info->lock,flags);
+	info->tx_count = info->tx_put = info->tx_get = 0;
+	del_timer(&info->tx_timer);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/* throttle (stop) transmitter
+ */
+static void tx_hold(struct tty_struct *tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (sanity_check(info, tty->device, "tx_hold"))
+		return;
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk("%s(%d):%s tx_hold()\n",
+			__FILE__,__LINE__,info->device_name);
+
+	spin_lock_irqsave(&info->lock,flags);
+	if (info->tx_enabled)
+	 	tx_stop(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/* release (start) transmitter
+ */
+static void tx_release(struct tty_struct *tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (sanity_check(info, tty->device, "tx_release"))
+		return;
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk("%s(%d):%s tx_release()\n",
+			__FILE__,__LINE__,info->device_name);
+
+	spin_lock_irqsave(&info->lock,flags);
+	if (!info->tx_enabled)
+	 	tx_start(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/* Service an IOCTL request
+ *
+ * Arguments:
+ *
+ * 	tty	pointer to tty instance data
+ * 	file	pointer to associated file object for device
+ * 	cmd	IOCTL command code
+ * 	arg	command argument/context
+ *
+ * Return Value:	0 if success, otherwise error code
+ */
+static int ioctl(struct tty_struct *tty, struct file *file,
+		 unsigned int cmd, unsigned long arg)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	int error;
+	struct mgsl_icount cnow;	/* kernel counter temps */
+	struct serial_icounter_struct *p_cuser;	/* user space */
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s ioctl() cmd=%08X\n", __FILE__,__LINE__,
+			info->device_name, cmd );
+
+	if (sanity_check(info, tty->device, "ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+
+	switch (cmd) {
+	case TIOCMGET:
+		return get_modem_info(info, (unsigned int *) arg);
+	case TIOCMBIS:
+	case TIOCMBIC:
+	case TIOCMSET:
+		return set_modem_info(info, cmd, (unsigned int *) arg);
+	case MGSL_IOCGPARAMS:
+		return get_params(info,(MGSL_PARAMS *)arg);
+	case MGSL_IOCSPARAMS:
+		return set_params(info,(MGSL_PARAMS *)arg);
+	case MGSL_IOCGTXIDLE:
+		return get_txidle(info,(int*)arg);
+	case MGSL_IOCSTXIDLE:
+		return set_txidle(info,(int)arg);
+	case MGSL_IOCTXENABLE:
+		return tx_enable(info,(int)arg);
+	case MGSL_IOCRXENABLE:
+		return rx_enable(info,(int)arg);
+	case MGSL_IOCTXABORT:
+		return tx_abort(info);
+	case MGSL_IOCGSTATS:
+		return get_stats(info,(struct mgsl_icount*)arg);
+	case MGSL_IOCWAITEVENT:
+		return wait_mgsl_event(info,(int*)arg);
+	case MGSL_IOCLOOPTXDONE:
+		return 0; // TODO: Not supported, need to document
+	case MGSL_IOCCLRMODCOUNT:
+		while(MOD_IN_USE)
+			MOD_DEC_USE_COUNT;
+		return 0;
+		/* Wait for modem input (DCD,RI,DSR,CTS) change
+		 * as specified by mask in arg (TIOCM_RNG/DSR/CD/CTS)
+		 */
+	case TIOCMIWAIT:
+		return modem_input_wait(info,(int)arg);
+		
+		/*
+		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+		 * Return: write counters to the user passed counter struct
+		 * NB: both 1->0 and 0->1 transitions are counted except for
+		 *     RI where only 0->1 is counted.
+		 */
+	case TIOCGICOUNT:
+		spin_lock_irqsave(&info->lock,flags);
+		cnow = info->icount;
+		spin_unlock_irqrestore(&info->lock,flags);
+		p_cuser = (struct serial_icounter_struct *) arg;
+		PUT_USER(error,cnow.cts, &p_cuser->cts);
+		if (error) return error;
+		PUT_USER(error,cnow.dsr, &p_cuser->dsr);
+		if (error) return error;
+		PUT_USER(error,cnow.rng, &p_cuser->rng);
+		if (error) return error;
+		PUT_USER(error,cnow.dcd, &p_cuser->dcd);
+		if (error) return error;
+		PUT_USER(error,cnow.rx, &p_cuser->rx);
+		if (error) return error;
+		PUT_USER(error,cnow.tx, &p_cuser->tx);
+		if (error) return error;
+		PUT_USER(error,cnow.frame, &p_cuser->frame);
+		if (error) return error;
+		PUT_USER(error,cnow.overrun, &p_cuser->overrun);
+		if (error) return error;
+		PUT_USER(error,cnow.parity, &p_cuser->parity);
+		if (error) return error;
+		PUT_USER(error,cnow.brk, &p_cuser->brk);
+		if (error) return error;
+		PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);
+		if (error) return error;
+		return 0;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static inline int line_info(char *buf, SLMP_INFO *info)
+{
+	char	stat_buf[30];
+	int	ret;
+	unsigned long flags;
+
+	ret = sprintf(buf, "%s: SCABase=%08x Mem=%08X StatusControl=%08x LCR=%08X\n"
+		       "\tIRQ=%d MaxFrameSize=%u\n",
+		info->device_name,
+		info->phys_sca_base,
+		info->phys_memory_base,
+		info->phys_statctrl_base,
+		info->phys_lcr_base,
+		info->irq_level,
+		info->max_frame_size );
+
+	/* output current serial signal states */
+	spin_lock_irqsave(&info->lock,flags);
+ 	get_signals(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	stat_buf[0] = 0;
+	stat_buf[1] = 0;
+	if (info->serial_signals & SerialSignal_RTS)
+		strcat(stat_buf, "|RTS");
+	if (info->serial_signals & SerialSignal_CTS)
+		strcat(stat_buf, "|CTS");
+	if (info->serial_signals & SerialSignal_DTR)
+		strcat(stat_buf, "|DTR");
+	if (info->serial_signals & SerialSignal_DSR)
+		strcat(stat_buf, "|DSR");
+	if (info->serial_signals & SerialSignal_DCD)
+		strcat(stat_buf, "|CD");
+	if (info->serial_signals & SerialSignal_RI)
+		strcat(stat_buf, "|RI");
+
+	if (info->params.mode == MGSL_MODE_HDLC) {
+		ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d",
+			      info->icount.txok, info->icount.rxok);
+		if (info->icount.txunder)
+			ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder);
+		if (info->icount.txabort)
+			ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);
+		if (info->icount.rxshort)
+			ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);
+		if (info->icount.rxlong)
+			ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);
+		if (info->icount.rxover)
+			ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);
+		if (info->icount.rxcrc)
+			ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxcrc);
+	} else {
+		ret += sprintf(buf+ret, "\tASYNC tx:%d rx:%d",
+			      info->icount.tx, info->icount.rx);
+		if (info->icount.frame)
+			ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+		if (info->icount.parity)
+			ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+		if (info->icount.brk)
+			ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
+		if (info->icount.overrun)
+			ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+	}
+
+	/* Append serial signal status to end */
+	ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+
+	ret += sprintf(buf+ret, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
+	 info->tx_active,info->bh_requested,info->bh_running,
+	 info->pending_bh);
+
+	return ret;
+}
+
+/* Called to print information about devices
+ */
+int read_proc(char *page, char **start, off_t off, int count,
+	      int *eof, void *data)
+{
+	int len = 0, l;
+	off_t	begin = 0;
+	SLMP_INFO *info;
+
+	len += sprintf(page, "synclinkmp driver:%s\n", driver_version);
+
+	info = synclinkmp_device_list;
+	while( info ) {
+		l = line_info(page + len, info);
+		len += l;
+		if (len+begin > off+count)
+			goto done;
+		if (len+begin < off) {
+			begin += len;
+			len = 0;
+		}
+		info = info->next_device;
+	}
+
+	*eof = 1;
+done:
+	if (off >= len+begin)
+		return 0;
+	*start = page + (off-begin);
+	return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/* Return the count of bytes in transmit buffer
+ */
+static int chars_in_buffer(struct tty_struct *tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+
+	if (sanity_check(info, tty->device, "chars_in_buffer"))
+		return 0;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s chars_in_buffer()=%d\n",
+		       __FILE__, __LINE__, info->device_name, info->tx_count);
+
+	return info->tx_count;
+}
+
+/* Signal remote device to throttle send data (our receive data)
+ */
+static void throttle(struct tty_struct * tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s throttle() entry\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	if (sanity_check(info, tty->device, "throttle"))
+		return;
+
+	if (I_IXOFF(tty))
+		send_xchar(tty, STOP_CHAR(tty));
+
+ 	if (tty->termios->c_cflag & CRTSCTS) {
+		spin_lock_irqsave(&info->lock,flags);
+		info->serial_signals &= ~SerialSignal_RTS;
+	 	set_signals(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+}
+
+/* Signal remote device to stop throttling send data (our receive data)
+ */
+static void unthrottle(struct tty_struct * tty)
+{
+	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s unthrottle() entry\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	if (sanity_check(info, tty->device, "unthrottle"))
+		return;
+
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			send_xchar(tty, START_CHAR(tty));
+	}
+
+ 	if (tty->termios->c_cflag & CRTSCTS) {
+		spin_lock_irqsave(&info->lock,flags);
+		info->serial_signals |= SerialSignal_RTS;
+	 	set_signals(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+}
+
+/* set or clear transmit break condition
+ * break_state	-1=set break condition, 0=clear
+ */
+static void set_break(struct tty_struct *tty, int break_state)
+{
+	unsigned char RegValue;
+	SLMP_INFO * info = (SLMP_INFO *)tty->driver_data;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s set_break(%d)\n",
+			 __FILE__,__LINE__, info->device_name, break_state);
+
+	if (sanity_check(info, tty->device, "set_break"))
+		return;
+
+	spin_lock_irqsave(&info->lock,flags);
+	RegValue = read_reg(info, CTL);
+ 	if (break_state == -1)
+		RegValue |= BIT3;
+	else
+		RegValue &= ~BIT3;
+	write_reg(info, CTL, RegValue);
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+
+/* syncppp support and callbacks */
+
+static void sppp_init(SLMP_INFO *info)
+{
+	struct net_device *d;
+
+	sprintf(info->netname,"mgslm%dp%d",info->adapter_num,info->port_num);
+
+	info->if_ptr = &info->pppdev;
+	info->netdev = info->pppdev.dev = &info->netdevice;
+
+	sppp_attach(&info->pppdev);
+
+	d = info->netdev;
+	strcpy(d->name,info->netname);
+	d->base_addr = 0;
+	d->irq = info->irq_level;
+	d->dma = 0;
+	d->priv = info;
+	d->init = NULL;
+	d->open = sppp_cb_open;
+	d->stop = sppp_cb_close;
+	d->hard_start_xmit = sppp_cb_tx;
+	d->do_ioctl = sppp_cb_ioctl;
+	d->get_stats = sppp_cb_net_stats;
+	d->tx_timeout = sppp_cb_tx_timeout;
+	d->watchdog_timeo = 10*HZ;
+
+#if LINUX_VERSION_CODE < VERSION(2,4,4) 
+	dev_init_buffers(d);
+#endif
+
+	if (register_netdev(d) == -1) {
+		printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
+		sppp_detach(info->netdev);
+		return;
+	}
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("sppp_init(%s)\n",info->netname);
+}
+
+static void sppp_delete(SLMP_INFO *info)
+{
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("sppp_delete(%s)\n",info->netname);
+	sppp_detach(info->netdev);
+	unregister_netdev(info->netdev);
+}
+
+static int sppp_cb_open(struct net_device *d)
+{
+	SLMP_INFO *info = d->priv;
+	int err, flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("sppp_cb_open(%s)\n",info->netname);
+
+	spin_lock_irqsave(&info->netlock, flags);
+	if (info->count != 0 || info->netcount != 0) {
+		printk(KERN_WARNING "%s: sppp_cb_open returning busy\n", info->netname);
+		spin_unlock_irqrestore(&info->netlock, flags);
+		return -EBUSY;
+	}
+	info->netcount=1;
+	MOD_INC_USE_COUNT;
+	spin_unlock_irqrestore(&info->netlock, flags);
+
+	/* claim resources and init adapter */
+	if ((err = startup(info)) != 0)
+		goto open_fail;
+
+	/* allow syncppp module to do open processing */
+	if ((err = sppp_open(d)) != 0) {
+		shutdown(info);
+		goto open_fail;
+	}
+
+	info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+	program_hw(info);
+
+	d->trans_start = jiffies;
+	netif_start_queue(d);
+	return 0;
+
+open_fail:
+	spin_lock_irqsave(&info->netlock, flags);
+	info->netcount=0;
+	MOD_DEC_USE_COUNT;
+	spin_unlock_irqrestore(&info->netlock, flags);
+	return err;
+}
+
+static void sppp_cb_tx_timeout(struct net_device *dev)
+{
+	SLMP_INFO *info = dev->priv;
+	int flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("sppp_tx_timeout(%s)\n",info->netname);
+
+	info->netstats.tx_errors++;
+	info->netstats.tx_aborted_errors++;
+
+	spin_lock_irqsave(&info->lock,flags);
+	tx_stop(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	netif_wake_queue(dev);
+}
+
+static int sppp_cb_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	SLMP_INFO *info = dev->priv;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("sppp_tx(%s)\n",info->netname);
+
+	netif_stop_queue(dev);
+
+	info->tx_count = skb->len;
+	tx_load_dma_buffer(info, skb->data, skb->len);
+	info->netstats.tx_packets++;
+	info->netstats.tx_bytes += skb->len;
+	dev_kfree_skb(skb);
+
+	dev->trans_start = jiffies;
+
+	spin_lock_irqsave(&info->lock,flags);
+	if (!info->tx_active)
+	 	tx_start(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	return 0;
+}
+
+static int sppp_cb_close(struct net_device *d)
+{
+	SLMP_INFO *info = d->priv;
+	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("sppp_cb_close(%s)\n",info->netname);
+
+	/* shutdown adapter and release resources */
+	shutdown(info);
+
+	/* allow syncppp to do close processing */
+	sppp_close(d);
+	netif_stop_queue(d);
+
+	spin_lock_irqsave(&info->netlock, flags);
+	info->netcount=0;
+	MOD_DEC_USE_COUNT;
+	spin_unlock_irqrestore(&info->netlock, flags);
+	return 0;
+}
+
+static void sppp_rx_done(SLMP_INFO *info, char *buf, int size)
+{
+	struct sk_buff *skb = dev_alloc_skb(size);
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("sppp_rx_done(%s)\n",info->netname);
+	if (skb == NULL) {
+		printk(KERN_NOTICE "%s: cant alloc skb, dropping packet\n",
+			info->netname);
+		info->netstats.rx_dropped++;
+		return;
+	}
+
+	memcpy(skb_put(skb, size),buf,size);
+
+	skb->protocol = htons(ETH_P_WAN_PPP);
+	skb->dev = info->netdev;
+	skb->mac.raw = skb->data;
+	info->netstats.rx_packets++;
+	info->netstats.rx_bytes += size;
+	netif_rx(skb);
+	info->netdev->trans_start = jiffies;
+}
+
+static void sppp_tx_done(SLMP_INFO *info)
+{
+	if (netif_queue_stopped(info->netdev))
+	    netif_wake_queue(info->netdev);
+}
+
+static struct net_device_stats *sppp_cb_net_stats(struct net_device *dev)
+{
+	SLMP_INFO *info = dev->priv;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("net_stats(%s)\n",info->netname);
+	return &info->netstats;
+}
+
+static int sppp_cb_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	SLMP_INFO *info = (SLMP_INFO *)dev->priv;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):ioctl %s cmd=%08X\n", __FILE__,__LINE__,
+			info->netname, cmd );
+	return sppp_do_ioctl(dev, ifr, cmd);
+}
+
+#endif /* ifdef CONFIG_SYNCLINK_SYNCPPP */
+
+
+/* Return next bottom half action to perform.
+ * Return Value:	BH action code or 0 if nothing to do.
+ */
+int bh_action(SLMP_INFO *info)
+{
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&info->lock,flags);
+
+	if (info->pending_bh & BH_RECEIVE) {
+		info->pending_bh &= ~BH_RECEIVE;
+		rc = BH_RECEIVE;
+	} else if (info->pending_bh & BH_TRANSMIT) {
+		info->pending_bh &= ~BH_TRANSMIT;
+		rc = BH_TRANSMIT;
+	} else if (info->pending_bh & BH_STATUS) {
+		info->pending_bh &= ~BH_STATUS;
+		rc = BH_STATUS;
+	}
+
+	if (!rc) {
+		/* Mark BH routine as complete */
+		info->bh_running   = 0;
+		info->bh_requested = 0;
+	}
+
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	return rc;
+}
+
+/* Perform bottom half processing of work items queued by ISR.
+ */
+void bh_handler(void* Context)
+{
+	SLMP_INFO *info = (SLMP_INFO*)Context;
+	int action;
+
+	if (!info)
+		return;
+
+	if ( debug_level >= DEBUG_LEVEL_BH )
+		printk( "%s(%d):%s bh_handler() entry\n",
+			__FILE__,__LINE__,info->device_name);
+
+	info->bh_running = 1;
+
+	while((action = bh_action(info)) != 0) {
+
+		/* Process work item */
+		if ( debug_level >= DEBUG_LEVEL_BH )
+			printk( "%s(%d):%s bh_handler() work item action=%d\n",
+				__FILE__,__LINE__,info->device_name, action);
+
+		switch (action) {
+
+		case BH_RECEIVE:
+			bh_receive(info);
+			break;
+		case BH_TRANSMIT:
+			bh_transmit(info);
+			break;
+		case BH_STATUS:
+			bh_status(info);
+			break;
+		default:
+			/* unknown work item ID */
+			printk("%s(%d):%s Unknown work item ID=%08X!\n",
+				__FILE__,__LINE__,info->device_name,action);
+			break;
+		}
+	}
+
+	if ( debug_level >= DEBUG_LEVEL_BH )
+		printk( "%s(%d):%s bh_handler() exit\n",
+			__FILE__,__LINE__,info->device_name);
+}
+
+void bh_receive(SLMP_INFO *info)
+{
+	if ( debug_level >= DEBUG_LEVEL_BH )
+		printk( "%s(%d):%s bh_receive()\n",
+			__FILE__,__LINE__,info->device_name);
+
+	while( rx_get_frame(info) );
+}
+
+void bh_transmit(SLMP_INFO *info)
+{
+	struct tty_struct *tty = info->tty;
+
+	if ( debug_level >= DEBUG_LEVEL_BH )
+		printk( "%s(%d):%s bh_transmit() entry\n",
+			__FILE__,__LINE__,info->device_name);
+
+	if (tty) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup) {
+			if ( debug_level >= DEBUG_LEVEL_BH )
+				printk( "%s(%d):%s calling ldisc.write_wakeup\n",
+					__FILE__,__LINE__,info->device_name);
+			(tty->ldisc.write_wakeup)(tty);
+		}
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+void bh_status(SLMP_INFO *info)
+{
+	if ( debug_level >= DEBUG_LEVEL_BH )
+		printk( "%s(%d):%s bh_status() entry\n",
+			__FILE__,__LINE__,info->device_name);
+
+	info->ri_chkcount = 0;
+	info->dsr_chkcount = 0;
+	info->dcd_chkcount = 0;
+	info->cts_chkcount = 0;
+}
+
+void isr_timer(SLMP_INFO * info)
+{
+	unsigned char timer = (info->port_num & 1) ? TIMER2 : TIMER0;
+
+	/* IER2<7..4> = timer<3..0> interrupt enables (0=disabled) */
+	write_reg(info, IER2, 0);
+
+	/* TMCS, Timer Control/Status Register
+	 *
+	 * 07      CMF, Compare match flag (read only) 1=match
+	 * 06      ECMI, CMF Interrupt Enable: 0=disabled
+	 * 05      Reserved, must be 0
+	 * 04      TME, Timer Enable
+	 * 03..00  Reserved, must be 0
+	 *
+	 * 0000 0000
+	 */
+	write_reg(info, (unsigned char)(timer + TMCS), 0);
+
+	info->irq_occurred = TRUE;
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_timer()\n",
+			__FILE__,__LINE__,info->device_name);
+}
+
+void isr_rxint(SLMP_INFO * info)
+{
+ 	struct tty_struct *tty = info->tty;
+ 	struct	mgsl_icount *icount = &info->icount;
+	unsigned char status = read_reg(info, SR1);
+	unsigned char status2 = read_reg(info, SR2);
+
+	/* clear status bits */
+	if ( status & (FLGD + IDLD + CDCD + BRKD) )
+		write_reg(info, SR1, 
+				(unsigned char)(status & (FLGD + IDLD + CDCD + BRKD)));
+
+	if ( status2 & OVRN )
+		write_reg(info, SR2, (unsigned char)(status2 & OVRN));
+	
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_rxint status=%02X %02x\n",
+			__FILE__,__LINE__,info->device_name,status,status2);
+
+	if (info->params.mode == MGSL_MODE_ASYNC) {
+		if (status & BRKD) {
+			icount->brk++;
+
+			/* process break detection if tty control
+			 * is not set to ignore it
+			 */
+			if ( tty ) {
+				if (!(status & info->ignore_status_mask1)) {
+					if (info->read_status_mask1 & BRKD) {
+						*tty->flip.flag_buf_ptr = TTY_BREAK;
+						if (info->flags & ASYNC_SAK)
+							do_SAK(tty);
+					}
+				}
+			}
+		}
+	}
+	else {
+		if (status & (FLGD|IDLD)) {
+			if (status & FLGD)
+				info->icount.exithunt++;
+			else if (status & IDLD)
+				info->icount.rxidle++;
+			wake_up_interruptible(&info->event_wait_q);
+		}
+	}
+
+	if (status & CDCD) {
+		/* simulate a common modem status change interrupt
+		 * for our handler
+		 */
+		get_signals( info );
+		isr_io_pin(info,
+			MISCSTATUS_DCD_LATCHED|(info->serial_signals&SerialSignal_DCD));
+	}
+}
+
+/*
+ * handle async rx data interrupts
+ */
+void isr_rxrdy(SLMP_INFO * info)
+{
+	u16 status;
+	unsigned char DataByte;
+ 	struct tty_struct *tty = info->tty;
+ 	struct	mgsl_icount *icount = &info->icount;
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_rxrdy\n",
+			__FILE__,__LINE__,info->device_name);
+
+	while((status = read_reg(info,CST0)) & BIT0)
+	{
+		DataByte = read_reg(info,TRB);
+
+		if ( tty ) {
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+				continue;
+
+			*tty->flip.char_buf_ptr = DataByte;
+			*tty->flip.flag_buf_ptr = 0;
+		}
+
+		icount->rx++;
+
+		if ( status & (PE + FRME + OVRN) ) {
+			printk("%s(%d):%s rxerr=%04X\n",
+				__FILE__,__LINE__,info->device_name,status);
+
+			/* update error statistics */
+			if (status & PE)
+				icount->parity++;
+			else if (status & FRME)
+				icount->frame++;
+			else if (status & OVRN)
+				icount->overrun++;
+
+			/* discard char if tty control flags say so */
+			if (status & info->ignore_status_mask2)
+				continue;
+
+			status &= info->read_status_mask2;
+
+			if ( tty ) {
+				if (status & PE)
+					*tty->flip.flag_buf_ptr = TTY_PARITY;
+				else if (status & FRME)
+					*tty->flip.flag_buf_ptr = TTY_FRAME;
+				if (status & OVRN) {
+					/* Overrun is special, since it's
+					 * reported immediately, and doesn't
+					 * affect the current character
+					 */
+					if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+						tty->flip.count++;
+						tty->flip.flag_buf_ptr++;
+						tty->flip.char_buf_ptr++;
+						*tty->flip.flag_buf_ptr = TTY_OVERRUN;
+					}
+				}
+			}
+		}	/* end of if (error) */
+
+		if ( tty ) {
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+	}
+
+	if ( debug_level >= DEBUG_LEVEL_ISR ) {
+		printk("%s(%d):%s isr_rxrdy() flip count=%d\n",
+			__FILE__,__LINE__,info->device_name,
+			tty ? tty->flip.count : 0);
+		printk("%s(%d):%s rx=%d brk=%d parity=%d frame=%d overrun=%d\n",
+			__FILE__,__LINE__,info->device_name,
+			icount->rx,icount->brk,icount->parity,
+			icount->frame,icount->overrun);
+	}
+
+	if ( tty && tty->flip.count )
+		tty_flip_buffer_push(tty);
+}
+
+void isr_txeom(SLMP_INFO * info, unsigned char status)
+{
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_txeom status=%02x\n",
+			__FILE__,__LINE__,info->device_name,status);
+
+	/* disable and clear MSCI interrupts */
+	info->ie1_value &= ~(IDLE + UDRN);
+	write_reg(info, IE1, info->ie1_value);
+	write_reg(info, SR1, (unsigned char)(UDRN + IDLE));
+
+	write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */
+	write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */
+	write_reg(info, TXDMA + DCMD, SWABORT);	/* reset/init DMA channel */
+
+	if ( info->tx_active ) {
+		if (info->params.mode != MGSL_MODE_ASYNC) {
+			if (status & UDRN)
+				info->icount.txunder++;
+			else if (status & IDLE)
+				info->icount.txok++;
+		}
+
+		info->tx_active = 0;
+		info->tx_count = info->tx_put = info->tx_get = 0;
+
+		del_timer(&info->tx_timer);
+
+		if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done ) {
+			info->serial_signals &= ~SerialSignal_RTS;
+			info->drop_rts_on_tx_done = 0;
+			set_signals(info);
+		}
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+		if (info->netcount)
+			sppp_tx_done(info);
+		else
+#endif
+		{
+			if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) {
+				tx_stop(info);
+				return;
+			}
+			info->pending_bh |= BH_TRANSMIT;
+		}
+	}
+}
+
+
+/*
+ * handle tx status interrupts
+ */
+void isr_txint(SLMP_INFO * info)
+{
+	unsigned char status = read_reg(info, SR1);
+
+	/* clear status bits */
+	write_reg(info, SR1, (unsigned char)(status & (UDRN + IDLE + CCTS)));
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_txint status=%02x\n",
+			__FILE__,__LINE__,info->device_name,status);
+
+	if (status & (UDRN + IDLE))
+		isr_txeom(info, status);
+
+	if (status & CCTS) {
+		/* simulate a common modem status change interrupt
+		 * for our handler
+		 */
+		get_signals( info );
+		isr_io_pin(info,
+			MISCSTATUS_CTS_LATCHED|(info->serial_signals&SerialSignal_CTS));
+
+	}
+}
+
+/*
+ * handle async tx data interrupts
+ */
+void isr_txrdy(SLMP_INFO * info)
+{
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_txrdy() tx_count=%d\n",
+			__FILE__,__LINE__,info->device_name,info->tx_count);
+
+	if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) {
+		tx_stop(info);
+		return;
+	}
+
+	if ( info->tx_count )
+		tx_load_fifo( info );
+	else {
+		info->tx_active = 0;
+		info->ie0_value &= ~TXRDYE;
+		write_reg(info, IE0, info->ie0_value);
+	}
+
+	if (info->tx_count < WAKEUP_CHARS)
+		info->pending_bh |= BH_TRANSMIT;
+}
+
+void isr_rxdmaok(SLMP_INFO * info)
+{
+	/* BIT7 = EOT (end of transfer)
+	 * BIT6 = EOM (end of message/frame)
+	 */
+	unsigned char status = read_reg(info,RXDMA + DSR) & 0xc0;
+
+	/* clear IRQ (BIT0 must be 1 to prevent clearing DE bit) */
+	write_reg(info, RXDMA + DSR, (unsigned char)(status | 1));
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_rxdmaok(), status=%02x\n",
+			__FILE__,__LINE__,info->device_name,status);
+
+	info->pending_bh |= BH_RECEIVE;
+}
+
+void isr_rxdmaerror(SLMP_INFO * info)
+{
+	/* BIT5 = BOF (buffer overflow)
+	 * BIT4 = COF (counter overflow)
+	 */
+	unsigned char status = read_reg(info,RXDMA + DSR) & 0x30;
+
+	/* clear IRQ (BIT0 must be 1 to prevent clearing DE bit) */
+	write_reg(info, RXDMA + DSR, (unsigned char)(status | 1));
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_rxdmaerror(), status=%02x\n",
+			__FILE__,__LINE__,info->device_name,status);
+
+	info->rx_overflow = TRUE;
+	info->pending_bh |= BH_RECEIVE;
+}
+
+void isr_txdmaok(SLMP_INFO * info)
+{
+	/* BIT7 = EOT (end of transfer, used for async mode)
+	 * BIT6 = EOM (end of message/frame, used for sync mode)
+	 *
+	 * We don't look at DMA status because only EOT is enabled
+	 * and we always clear and disable all tx DMA IRQs.
+	 */
+//	unsigned char dma_status = read_reg(info,TXDMA + DSR) & 0xc0;
+	unsigned char status_reg1 = read_reg(info, SR1);
+
+	write_reg(info, TXDMA + DIR, 0x00);	/* disable Tx DMA IRQs */
+	write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */
+	write_reg(info, TXDMA + DCMD, SWABORT);	/* reset/init DMA channel */
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_txdmaok(), status=%02x\n",
+			__FILE__,__LINE__,info->device_name,status_reg1);
+
+	/* If transmitter already idle, do end of frame processing,
+	 * otherwise enable interrupt for tx IDLE.
+	 */
+	if (status_reg1 & IDLE)
+		isr_txeom(info, IDLE);
+	else {
+		/* disable and clear underrun IRQ, enable IDLE interrupt */
+		info->ie1_value |= IDLE;
+		info->ie1_value &= ~UDRN;
+		write_reg(info, IE1, info->ie1_value);
+
+		write_reg(info, SR1, UDRN);
+	}
+}
+
+void isr_txdmaerror(SLMP_INFO * info)
+{
+	/* BIT5 = BOF (buffer overflow)
+	 * BIT4 = COF (counter overflow)
+	 */
+	unsigned char status = read_reg(info,TXDMA + DSR) & 0x30;
+
+	/* clear IRQ (BIT0 must be 1 to prevent clearing DE bit) */
+	write_reg(info, TXDMA + DSR, (unsigned char)(status | 1));
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):%s isr_txdmaerror(), status=%02x\n",
+			__FILE__,__LINE__,info->device_name,status);
+}
+
+/* handle input serial signal changes
+ */
+void isr_io_pin( SLMP_INFO *info, u16 status )
+{
+ 	struct	mgsl_icount *icount;
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):isr_io_pin status=%04X\n",
+			__FILE__,__LINE__,status);
+
+	if (status & (MISCSTATUS_CTS_LATCHED | MISCSTATUS_DCD_LATCHED |
+	              MISCSTATUS_DSR_LATCHED | MISCSTATUS_RI_LATCHED) ) {
+		icount = &info->icount;
+		/* update input line counters */
+		if (status & MISCSTATUS_RI_LATCHED) {
+			icount->rng++;
+			if ( status & SerialSignal_RI )
+				info->input_signal_events.ri_up++;
+			else
+				info->input_signal_events.ri_down++;
+		}
+		if (status & MISCSTATUS_DSR_LATCHED) {
+			icount->dsr++;
+			if ( status & SerialSignal_DSR )
+				info->input_signal_events.dsr_up++;
+			else
+				info->input_signal_events.dsr_down++;
+		}
+		if (status & MISCSTATUS_DCD_LATCHED) {
+			if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) {
+				info->ie1_value &= ~CDCD;
+				write_reg(info, IE1, info->ie1_value);
+			}
+			icount->dcd++;
+			if (status & SerialSignal_DCD) {
+				info->input_signal_events.dcd_up++;
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+				if (info->netcount)
+					sppp_reopen(info->netdev);
+#endif
+			} else
+				info->input_signal_events.dcd_down++;
+		}
+		if (status & MISCSTATUS_CTS_LATCHED)
+		{
+			if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) {
+				info->ie1_value &= ~CCTS;
+				write_reg(info, IE1, info->ie1_value);
+			}
+			icount->cts++;
+			if ( status & SerialSignal_CTS )
+				info->input_signal_events.cts_up++;
+			else
+				info->input_signal_events.cts_down++;
+		}
+		wake_up_interruptible(&info->status_event_wait_q);
+		wake_up_interruptible(&info->event_wait_q);
+
+		if ( (info->flags & ASYNC_CHECK_CD) &&
+		     (status & MISCSTATUS_DCD_LATCHED) ) {
+			if ( debug_level >= DEBUG_LEVEL_ISR )
+				printk("%s CD now %s...", info->device_name,
+				       (status & SerialSignal_DCD) ? "on" : "off");
+			if (status & SerialSignal_DCD)
+				wake_up_interruptible(&info->open_wait);
+			else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+				   (info->flags & ASYNC_CALLOUT_NOHUP))) {
+				if ( debug_level >= DEBUG_LEVEL_ISR )
+					printk("doing serial hangup...");
+				if (info->tty)
+					tty_hangup(info->tty);
+			}
+		}
+
+		if ( (info->flags & ASYNC_CTS_FLOW) &&
+		     (status & MISCSTATUS_CTS_LATCHED) ) {
+			if ( info->tty ) {
+				if (info->tty->hw_stopped) {
+					if (status & SerialSignal_CTS) {
+						if ( debug_level >= DEBUG_LEVEL_ISR )
+							printk("CTS tx start...");
+			 			info->tty->hw_stopped = 0;
+						tx_start(info);
+						info->pending_bh |= BH_TRANSMIT;
+						return;
+					}
+				} else {
+					if (!(status & SerialSignal_CTS)) {
+						if ( debug_level >= DEBUG_LEVEL_ISR )
+							printk("CTS tx stop...");
+			 			info->tty->hw_stopped = 1;
+						tx_stop(info);
+					}
+				}
+			}
+		}
+	}
+
+	info->pending_bh |= BH_STATUS;
+}
+
+/* Interrupt service routine entry point.
+ *
+ * Arguments:
+ * 	irq		interrupt number that caused interrupt
+ * 	dev_id		device ID supplied during interrupt registration
+ * 	regs		interrupted processor context
+ */
+static void synclinkmp_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	SLMP_INFO * info;
+	unsigned char status, status0, status1=0;
+	unsigned char dmastatus, dmastatus0, dmastatus1=0;
+	unsigned char timerstatus0, timerstatus1=0;
+	unsigned char shift;
+	unsigned int i;
+	unsigned short tmp;
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d): synclinkmp_interrupt(%d)entry.\n",
+			__FILE__,__LINE__,irq);
+
+	info = (SLMP_INFO *)dev_id;
+	if (!info)
+		return;
+
+	spin_lock(&info->lock);
+
+	for(;;) {
+
+		/* get status for SCA0 (ports 0-1) */
+		tmp = read_reg16(info, ISR0);	/* get ISR0 and ISR1 in one read */
+		status0 = (unsigned char)tmp;
+		dmastatus0 = (unsigned char)(tmp>>8);
+		timerstatus0 = read_reg(info, ISR2);
+
+		if ( debug_level >= DEBUG_LEVEL_ISR )
+			printk("%s(%d):%s status0=%02x, dmastatus0=%02x, timerstatus0=%02x\n",
+				__FILE__,__LINE__,info->device_name,
+				status0,dmastatus0,timerstatus0);
+
+		if (info->port_count == 4) {
+			/* get status for SCA1 (ports 2-3) */
+			tmp = read_reg16(info->port_array[2], ISR0);
+			status1 = (unsigned char)tmp;
+			dmastatus1 = (unsigned char)(tmp>>8);
+			timerstatus1 = read_reg(info->port_array[2], ISR2);
+
+			if ( debug_level >= DEBUG_LEVEL_ISR )
+				printk("%s(%d):%s status1=%02x, dmastatus1=%02x, timerstatus1=%02x\n",
+					__FILE__,__LINE__,info->device_name,
+					status1,dmastatus1,timerstatus1);
+		}
+
+		if (!status0 && !dmastatus0 && !timerstatus0 &&
+			 !status1 && !dmastatus1 && !timerstatus1)
+			break;
+
+		for(i=0; i < info->port_count ; i++) {
+			if (info->port_array[i] == NULL)
+				continue;
+			if (i < 2) {
+				status = status0;
+				dmastatus = dmastatus0;
+			} else {
+				status = status1;
+				dmastatus = dmastatus1;
+			}
+
+			shift = i & 1 ? 4 :0;
+
+			if (status & BIT0 << shift)
+				isr_rxrdy(info->port_array[i]);
+			if (status & BIT1 << shift)
+				isr_txrdy(info->port_array[i]);
+			if (status & BIT2 << shift)
+				isr_rxint(info->port_array[i]);
+			if (status & BIT3 << shift)
+				isr_txint(info->port_array[i]);
+
+			if (dmastatus & BIT0 << shift)
+				isr_rxdmaerror(info->port_array[i]);
+			if (dmastatus & BIT1 << shift)
+				isr_rxdmaok(info->port_array[i]);
+			if (dmastatus & BIT2 << shift)
+				isr_txdmaerror(info->port_array[i]);
+			if (dmastatus & BIT3 << shift)
+				isr_txdmaok(info->port_array[i]);
+		}
+
+		if (timerstatus0 & (BIT5 | BIT4))
+			isr_timer(info->port_array[0]);
+		if (timerstatus0 & (BIT7 | BIT6))
+			isr_timer(info->port_array[1]);
+		if (timerstatus1 & (BIT5 | BIT4))
+			isr_timer(info->port_array[2]);
+		if (timerstatus1 & (BIT7 | BIT6))
+			isr_timer(info->port_array[3]);
+	}
+
+	for(i=0; i < info->port_count ; i++) {
+		SLMP_INFO * port = info->port_array[i];
+
+		/* Request bottom half processing if there's something
+		 * for it to do and the bh is not already running.
+		 *
+		 * Note: startup adapter diags require interrupts.
+		 * do not request bottom half processing if the
+		 * device is not open in a normal mode.
+		 */
+		if ( port && (port->count || port->netcount) &&
+		     port->pending_bh && !port->bh_running &&
+		     !port->bh_requested ) {
+			if ( debug_level >= DEBUG_LEVEL_ISR )
+				printk("%s(%d):%s queueing bh task.\n",
+					__FILE__,__LINE__,port->device_name);
+			queue_task(&port->task, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
+			port->bh_requested = 1;
+		}
+	}
+
+	spin_unlock(&info->lock);
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):synclinkmp_interrupt(%d)exit.\n",
+			__FILE__,__LINE__,irq);
+}
+
+/* Initialize and start device.
+ */
+static int startup(SLMP_INFO * info)
+{
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk("%s(%d):%s tx_releaseup()\n",__FILE__,__LINE__,info->device_name);
+
+	if (info->flags & ASYNC_INITIALIZED)
+		return 0;
+
+	if (!info->tx_buf) {
+		info->tx_buf = (unsigned char *)kmalloc(info->max_frame_size, GFP_KERNEL);
+		if (!info->tx_buf) {
+			printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n",
+				__FILE__,__LINE__,info->device_name);
+			return -ENOMEM;
+		}
+	}
+
+	info->pending_bh = 0;
+
+	init_timer(&info->tx_timer);
+	info->tx_timer.data = (unsigned long)info;
+	info->tx_timer.function = tx_timeout;
+
+	/* program hardware for current parameters */
+	reset_port(info);
+
+	change_params(info);
+
+	init_timer(&info->status_timer);
+	info->status_timer.data = (unsigned long)info;
+	info->status_timer.function = status_timeout;
+	info->status_timer.expires = jiffies + jiffies_from_ms(10);
+	add_timer(&info->status_timer);
+
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->flags |= ASYNC_INITIALIZED;
+
+	return 0;
+}
+
+/* Called by close() and hangup() to shutdown hardware
+ */
+static void shutdown(SLMP_INFO * info)
+{
+	unsigned long flags;
+
+	if (!(info->flags & ASYNC_INITIALIZED))
+		return;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s synclinkmp_shutdown()\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	/* clear status wait queue because status changes */
+	/* can't happen after shutting down the hardware */
+	wake_up_interruptible(&info->status_event_wait_q);
+	wake_up_interruptible(&info->event_wait_q);
+
+	del_timer(&info->tx_timer);
+	del_timer(&info->status_timer);
+
+	if (info->tx_buf) {
+		free_page((unsigned long) info->tx_buf);
+		info->tx_buf = 0;
+	}
+
+	spin_lock_irqsave(&info->lock,flags);
+
+	reset_port(info);
+
+ 	if (!info->tty || info->tty->termios->c_cflag & HUPCL) {
+ 		info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
+		set_signals(info);
+	}
+
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->flags &= ~ASYNC_INITIALIZED;
+}
+
+static void program_hw(SLMP_INFO *info)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock,flags);
+
+	rx_stop(info);
+	tx_stop(info);
+
+	info->tx_count = info->tx_put = info->tx_get = 0;
+
+	if (info->params.mode == MGSL_MODE_HDLC || info->netcount)
+		hdlc_mode(info);
+	else
+		async_mode(info);
+
+	set_signals(info);
+
+	info->dcd_chkcount = 0;
+	info->cts_chkcount = 0;
+	info->ri_chkcount = 0;
+	info->dsr_chkcount = 0;
+
+	info->ie1_value |= (CDCD|CCTS);
+	write_reg(info, IE1, info->ie1_value);
+
+	get_signals(info);
+
+	if (info->netcount || (info->tty && info->tty->termios->c_cflag & CREAD) )
+		rx_start(info);
+
+	spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/* Reconfigure adapter based on new parameters
+ */
+static void change_params(SLMP_INFO *info)
+{
+	unsigned cflag;
+	int bits_per_char;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s change_params()\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	cflag = info->tty->termios->c_cflag;
+
+	/* if B0 rate (hangup) specified then negate DTR and RTS */
+	/* otherwise assert DTR and RTS */
+ 	if (cflag & CBAUD)
+		info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+	else
+		info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
+
+	/* byte size and parity */
+
+	switch (cflag & CSIZE) {
+	      case CS5: info->params.data_bits = 5; break;
+	      case CS6: info->params.data_bits = 6; break;
+	      case CS7: info->params.data_bits = 7; break;
+	      case CS8: info->params.data_bits = 8; break;
+	      /* Never happens, but GCC is too dumb to figure it out */
+	      default:  info->params.data_bits = 7; break;
+	      }
+
+	if (cflag & CSTOPB)
+		info->params.stop_bits = 2;
+	else
+		info->params.stop_bits = 1;
+
+	info->params.parity = ASYNC_PARITY_NONE;
+	if (cflag & PARENB) {
+		if (cflag & PARODD)
+			info->params.parity = ASYNC_PARITY_ODD;
+		else
+			info->params.parity = ASYNC_PARITY_EVEN;
+#ifdef CMSPAR
+		if (cflag & CMSPAR)
+			info->params.parity = ASYNC_PARITY_SPACE;
+#endif
+	}
+
+	/* calculate number of jiffies to transmit a full
+	 * FIFO (32 bytes) at specified data rate
+	 */
+	bits_per_char = info->params.data_bits +
+			info->params.stop_bits + 1;
+
+	/* if port data rate is set to 460800 or less then
+	 * allow tty settings to override, otherwise keep the
+	 * current data rate.
+	 */
+	if (info->params.data_rate <= 460800) {
+		info->params.data_rate = tty_get_baud_rate(info->tty);
+	}
+
+	if ( info->params.data_rate ) {
+		info->timeout = (32*HZ*bits_per_char) /
+				info->params.data_rate;
+	}
+	info->timeout += HZ/50;		/* Add .02 seconds of slop */
+
+	if (cflag & CRTSCTS)
+		info->flags |= ASYNC_CTS_FLOW;
+	else
+		info->flags &= ~ASYNC_CTS_FLOW;
+
+	if (cflag & CLOCAL)
+		info->flags &= ~ASYNC_CHECK_CD;
+	else
+		info->flags |= ASYNC_CHECK_CD;
+
+	/* process tty input control flags */
+
+	info->read_status_mask2 = OVRN;
+	if (I_INPCK(info->tty))
+		info->read_status_mask2 |= PE | FRME;
+ 	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+ 		info->read_status_mask1 |= BRKD;
+	if (I_IGNPAR(info->tty))
+		info->ignore_status_mask2 |= PE | FRME;
+	if (I_IGNBRK(info->tty)) {
+		info->ignore_status_mask1 |= BRKD;
+		/* If ignoring parity and break indicators, ignore
+		 * overruns too.  (For real raw support).
+		 */
+		if (I_IGNPAR(info->tty))
+			info->ignore_status_mask2 |= OVRN;
+	}
+
+	program_hw(info);
+}
+
+static int get_stats(SLMP_INFO * info, struct mgsl_icount *user_icount)
+{
+	int err;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s get_params()\n",
+			 __FILE__,__LINE__, info->device_name);
+
+	COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount));
+	if (err) {
+		if ( debug_level >= DEBUG_LEVEL_INFO )
+			printk( "%s(%d):%s get_stats() user buffer copy failed\n",
+				__FILE__,__LINE__,info->device_name);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int get_params(SLMP_INFO * info, MGSL_PARAMS *user_params)
+{
+	int err;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s get_params()\n",
+			 __FILE__,__LINE__, info->device_name);
+
+	COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS));
+	if (err) {
+		if ( debug_level >= DEBUG_LEVEL_INFO )
+			printk( "%s(%d):%s get_params() user buffer copy failed\n",
+				__FILE__,__LINE__,info->device_name);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int set_params(SLMP_INFO * info, MGSL_PARAMS *new_params)
+{
+ 	unsigned long flags;
+	MGSL_PARAMS tmp_params;
+	int err;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s set_params\n",
+			__FILE__,__LINE__,info->device_name );
+	COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS));
+	if (err) {
+		if ( debug_level >= DEBUG_LEVEL_INFO )
+			printk( "%s(%d):%s set_params() user buffer copy failed\n",
+				__FILE__,__LINE__,info->device_name);
+		return -EFAULT;
+	}
+
+	spin_lock_irqsave(&info->lock,flags);
+	memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS));
+	spin_unlock_irqrestore(&info->lock,flags);
+
+ 	change_params(info);
+
+	return 0;
+}
+
+static int get_txidle(SLMP_INFO * info, int*idle_mode)
+{
+	int err;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s get_txidle()=%d\n",
+			 __FILE__,__LINE__, info->device_name, info->idle_mode);
+
+	COPY_TO_USER(err,idle_mode, &info->idle_mode, sizeof(int));
+	if (err) {
+		if ( debug_level >= DEBUG_LEVEL_INFO )
+			printk( "%s(%d):%s get_txidle() user buffer copy failed\n",
+				__FILE__,__LINE__,info->device_name);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int set_txidle(SLMP_INFO * info, int idle_mode)
+{
+ 	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s set_txidle(%d)\n",
+			__FILE__,__LINE__,info->device_name, idle_mode );
+
+	spin_lock_irqsave(&info->lock,flags);
+	info->idle_mode = idle_mode;
+	tx_set_idle( info );
+	spin_unlock_irqrestore(&info->lock,flags);
+	return 0;
+}
+
+static int tx_enable(SLMP_INFO * info, int enable)
+{
+ 	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s tx_enable(%d)\n",
+			__FILE__,__LINE__,info->device_name, enable);
+
+	spin_lock_irqsave(&info->lock,flags);
+	if ( enable ) {
+		if ( !info->tx_enabled ) {
+			tx_start(info);
+		}
+	} else {
+		if ( info->tx_enabled )
+			tx_stop(info);
+	}
+	spin_unlock_irqrestore(&info->lock,flags);
+	return 0;
+}
+
+/* abort send HDLC frame
+ */
+static int tx_abort(SLMP_INFO * info)
+{
+ 	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s tx_abort()\n",
+			__FILE__,__LINE__,info->device_name);
+
+	spin_lock_irqsave(&info->lock,flags);
+	if ( info->tx_active && info->params.mode == MGSL_MODE_HDLC ) {
+		info->ie1_value &= ~UDRN;
+		info->ie1_value |= IDLE;
+		write_reg(info, IE1, info->ie1_value);	/* disable tx status interrupts */
+		write_reg(info, SR1, (unsigned char)(IDLE + UDRN));	/* clear pending */
+
+		write_reg(info, TXDMA + DSR, 0);		/* disable DMA channel */
+		write_reg(info, TXDMA + DCMD, SWABORT);	/* reset/init DMA channel */
+
+   		write_reg(info, CMD, TXABORT);
+	}
+	spin_unlock_irqrestore(&info->lock,flags);
+	return 0;
+}
+
+static int rx_enable(SLMP_INFO * info, int enable)
+{
+ 	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s rx_enable(%d)\n",
+			__FILE__,__LINE__,info->device_name,enable);
+
+	spin_lock_irqsave(&info->lock,flags);
+	if ( enable ) {
+		if ( !info->rx_enabled )
+			rx_start(info);
+	} else {
+		if ( info->rx_enabled )
+			rx_stop(info);
+	}
+	spin_unlock_irqrestore(&info->lock,flags);
+	return 0;
+}
+
+static int map_status(int signals)
+{
+	/* Map status bits to API event bits */
+
+	return ((signals & SerialSignal_DSR) ? MgslEvent_DsrActive : MgslEvent_DsrInactive) +
+	       ((signals & SerialSignal_CTS) ? MgslEvent_CtsActive : MgslEvent_CtsInactive) +
+	       ((signals & SerialSignal_DCD) ? MgslEvent_DcdActive : MgslEvent_DcdInactive) +
+	       ((signals & SerialSignal_RI)  ? MgslEvent_RiActive : MgslEvent_RiInactive);
+}
+
+/* wait for specified event to occur
+ */
+static int wait_mgsl_event(SLMP_INFO * info, int * mask_ptr)
+{
+ 	unsigned long flags;
+	int s;
+	int rc=0;
+	struct mgsl_icount cprev, cnow;
+	int events;
+	int mask;
+	struct	_input_signal_events oldsigs, newsigs;
+	DECLARE_WAITQUEUE(wait, current);
+
+	COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int));
+	if (rc) {
+		return  -EFAULT;
+	}
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s wait_mgsl_event(%d)\n",
+			__FILE__,__LINE__,info->device_name,mask);
+
+	spin_lock_irqsave(&info->lock,flags);
+
+	/* return immediately if state matches requested events */
+	get_signals(info);
+	s = map_status(info->serial_signals);
+
+	events = mask &
+		( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) +
+ 		  ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) +
+		  ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) +
+		  ((s & SerialSignal_RI)  ? MgslEvent_RiActive :MgslEvent_RiInactive) );
+	if (events) {
+		spin_unlock_irqrestore(&info->lock,flags);
+		goto exit;
+	}
+
+	/* save current irq counts */
+	cprev = info->icount;
+	oldsigs = info->input_signal_events;
+
+	/* enable hunt and idle irqs if needed */
+	if (mask & (MgslEvent_ExitHuntMode+MgslEvent_IdleReceived)) {
+		unsigned char oldval = info->ie1_value;
+		unsigned char newval = oldval +
+			 (mask & MgslEvent_ExitHuntMode ? FLGD:0) +
+			 (mask & MgslEvent_IdleReceived ? IDLE:0);
+		if ( oldval != newval ) {
+			info->ie1_value = newval;
+			write_reg(info, IE1, info->ie1_value);
+		}
+	}
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&info->event_wait_q, &wait);
+
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	for(;;) {
+		schedule();
+		if (signal_pending(current)) {
+			rc = -ERESTARTSYS;
+			break;
+		}
+
+		/* get current irq counts */
+		spin_lock_irqsave(&info->lock,flags);
+		cnow = info->icount;
+		newsigs = info->input_signal_events;
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_unlock_irqrestore(&info->lock,flags);
+
+		/* if no change, wait aborted for some reason */
+		if (newsigs.dsr_up   == oldsigs.dsr_up   &&
+		    newsigs.dsr_down == oldsigs.dsr_down &&
+		    newsigs.dcd_up   == oldsigs.dcd_up   &&
+		    newsigs.dcd_down == oldsigs.dcd_down &&
+		    newsigs.cts_up   == oldsigs.cts_up   &&
+		    newsigs.cts_down == oldsigs.cts_down &&
+		    newsigs.ri_up    == oldsigs.ri_up    &&
+		    newsigs.ri_down  == oldsigs.ri_down  &&
+		    cnow.exithunt    == cprev.exithunt   &&
+		    cnow.rxidle      == cprev.rxidle) {
+			rc = -EIO;
+			break;
+		}
+
+		events = mask &
+			( (newsigs.dsr_up   != oldsigs.dsr_up   ? MgslEvent_DsrActive:0)   +
+			  (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) +
+			  (newsigs.dcd_up   != oldsigs.dcd_up   ? MgslEvent_DcdActive:0)   +
+			  (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) +
+			  (newsigs.cts_up   != oldsigs.cts_up   ? MgslEvent_CtsActive:0)   +
+			  (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) +
+			  (newsigs.ri_up    != oldsigs.ri_up    ? MgslEvent_RiActive:0)    +
+			  (newsigs.ri_down  != oldsigs.ri_down  ? MgslEvent_RiInactive:0)  +
+			  (cnow.exithunt    != cprev.exithunt   ? MgslEvent_ExitHuntMode:0) +
+			  (cnow.rxidle      != cprev.rxidle     ? MgslEvent_IdleReceived:0) );
+		if (events)
+			break;
+
+		cprev = cnow;
+		oldsigs = newsigs;
+	}
+
+	remove_wait_queue(&info->event_wait_q, &wait);
+	set_current_state(TASK_RUNNING);
+
+
+	if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) {
+		spin_lock_irqsave(&info->lock,flags);
+		if (!waitqueue_active(&info->event_wait_q)) {
+			/* disable enable exit hunt mode/idle rcvd IRQs */
+			info->ie1_value &= ~(FLGD|IDLE);
+			write_reg(info, IE1, info->ie1_value);
+		}
+		spin_unlock_irqrestore(&info->lock,flags);
+	}
+exit:
+	if ( rc == 0 )
+		PUT_USER(rc, events, mask_ptr);
+
+	return rc;
+}
+
+static int modem_input_wait(SLMP_INFO *info,int arg)
+{
+ 	unsigned long flags;
+	int rc;
+	struct mgsl_icount cprev, cnow;
+	DECLARE_WAITQUEUE(wait, current);
+
+	/* save current irq counts */
+	spin_lock_irqsave(&info->lock,flags);
+	cprev = info->icount;
+	add_wait_queue(&info->status_event_wait_q, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	for(;;) {
+		schedule();
+		if (signal_pending(current)) {
+			rc = -ERESTARTSYS;
+			break;
+		}
+
+		/* get new irq counts */
+		spin_lock_irqsave(&info->lock,flags);
+		cnow = info->icount;
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_unlock_irqrestore(&info->lock,flags);
+
+		/* if no change, wait aborted for some reason */
+		if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+		    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
+			rc = -EIO;
+			break;
+		}
+
+		/* check for change in caller specified modem input */
+		if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) ||
+		    (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) ||
+		    (arg & TIOCM_CD  && cnow.dcd != cprev.dcd) ||
+		    (arg & TIOCM_CTS && cnow.cts != cprev.cts)) {
+			rc = 0;
+			break;
+		}
+
+		cprev = cnow;
+	}
+	remove_wait_queue(&info->status_event_wait_q, &wait);
+	set_current_state(TASK_RUNNING);
+	return rc;
+}
+
+/* return the state of the serial control and status signals
+ */
+static int get_modem_info(SLMP_INFO * info, unsigned int *value)
+{
+	unsigned int result;
+ 	unsigned long flags;
+	int err;
+
+	spin_lock_irqsave(&info->lock,flags);
+ 	get_signals(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	result = ((info->serial_signals & SerialSignal_RTS) ? TIOCM_RTS:0) +
+		((info->serial_signals & SerialSignal_DTR) ? TIOCM_DTR:0) +
+		((info->serial_signals & SerialSignal_DCD) ? TIOCM_CAR:0) +
+		((info->serial_signals & SerialSignal_RI)  ? TIOCM_RNG:0) +
+		((info->serial_signals & SerialSignal_DSR) ? TIOCM_DSR:0) +
+		((info->serial_signals & SerialSignal_CTS) ? TIOCM_CTS:0);
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s synclinkmp_get_modem_info() value=%08X\n",
+			 __FILE__,__LINE__, info->device_name, result );
+
+	PUT_USER(err,result,value);
+	return err;
+}
+
+/* set modem control signals (DTR/RTS)
+ *
+ * 	cmd	signal command: TIOCMBIS = set bit TIOCMBIC = clear bit
+ *		TIOCMSET = set/clear signal values
+ * 	value	bit mask for command
+ */
+static int set_modem_info(SLMP_INFO * info, unsigned int cmd,
+			  unsigned int *value)
+{
+ 	int error;
+ 	unsigned int arg;
+ 	unsigned long flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s synclinkmp_set_modem_info()\n",
+			__FILE__,__LINE__,info->device_name );
+
+ 	GET_USER(error,arg,value);
+ 	if (error)
+ 		return error;
+
+ 	switch (cmd) {
+ 	case TIOCMBIS:
+ 		if (arg & TIOCM_RTS)
+ 			info->serial_signals |= SerialSignal_RTS;
+ 		if (arg & TIOCM_DTR)
+ 			info->serial_signals |= SerialSignal_DTR;
+ 		break;
+ 	case TIOCMBIC:
+ 		if (arg & TIOCM_RTS)
+ 			info->serial_signals &= ~SerialSignal_RTS;
+ 		if (arg & TIOCM_DTR)
+ 			info->serial_signals &= ~SerialSignal_DTR;
+ 		break;
+ 	case TIOCMSET:
+ 		if (arg & TIOCM_RTS)
+ 			info->serial_signals |= SerialSignal_RTS;
+		else
+ 			info->serial_signals &= ~SerialSignal_RTS;
+
+ 		if (arg & TIOCM_DTR)
+ 			info->serial_signals |= SerialSignal_DTR;
+		else
+ 			info->serial_signals &= ~SerialSignal_DTR;
+ 		break;
+ 	default:
+ 		return -EINVAL;
+ 	}
+
+	spin_lock_irqsave(&info->lock,flags);
+ 	set_signals(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	return 0;
+}
+
+
+
+/* Block the current process until the specified port is ready to open.
+ */
+static int block_til_ready(struct tty_struct *tty, struct file *filp,
+			   SLMP_INFO *info)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int		retval;
+	int		do_clocal = 0, extra_count = 0;
+	unsigned long	flags;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s block_til_ready()\n",
+			 __FILE__,__LINE__, tty->driver.name );
+
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		/* this is a callout device */
+		/* just verify that normal device is not in use */
+		if (info->flags & ASYNC_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
+		    (info->session != current->session))
+		    return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
+		    (info->pgrp != current->pgrp))
+		    return -EBUSY;
+		info->flags |= ASYNC_CALLOUT_ACTIVE;
+		return 0;
+	}
+
+	if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
+		/* nonblock mode is set or port is not enabled */
+		/* just verify that callout device is not active */
+		if (info->flags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (info->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+
+	/* Wait for carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, info->count is dropped by one, so that
+	 * close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s block_til_ready() before block, count=%d\n",
+			 __FILE__,__LINE__, tty->driver.name, info->count );
+
+	save_flags(flags); cli();
+	if (!tty_hung_up_p(filp)) {
+		extra_count = 1;
+		info->count--;
+	}
+	restore_flags(flags);
+	info->blocked_open++;
+
+	while (1) {
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ 		    (tty->termios->c_cflag & CBAUD)) {
+			spin_lock_irqsave(&info->lock,flags);
+			info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+		 	set_signals(info);
+			spin_unlock_irqrestore(&info->lock,flags);
+		}
+
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){
+			retval = (info->flags & ASYNC_HUP_NOTIFY) ?
+					-EAGAIN : -ERESTARTSYS;
+			break;
+		}
+
+		spin_lock_irqsave(&info->lock,flags);
+	 	get_signals(info);
+		spin_unlock_irqrestore(&info->lock,flags);
+
+ 		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ 		    !(info->flags & ASYNC_CLOSING) &&
+ 		    (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
+ 			break;
+		}
+
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+
+		if (debug_level >= DEBUG_LEVEL_INFO)
+			printk("%s(%d):%s block_til_ready() count=%d\n",
+				 __FILE__,__LINE__, tty->driver.name, info->count );
+
+		schedule();
+	}
+
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&info->open_wait, &wait);
+
+	if (extra_count)
+		info->count++;
+	info->blocked_open--;
+
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("%s(%d):%s block_til_ready() after, count=%d\n",
+			 __FILE__,__LINE__, tty->driver.name, info->count );
+
+	if (!retval)
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+
+	return retval;
+}
+
+int alloc_dma_bufs(SLMP_INFO *info)
+{
+	unsigned short BuffersPerFrame;
+	unsigned short BufferCount;
+
+	// Force allocation to start at 64K boundary for each port.
+	// This is necessary because *all* buffer descriptors for a port
+	// *must* be in the same 64K block. All descriptors on a port
+	// share a common 'base' address (upper 8 bits of 24 bits) programmed
+	// into the CBP register.
+	info->port_array[0]->last_mem_alloc = (SCA_MEM_SIZE/4) * info->port_num;
+
+	/* Calculate the number of DMA buffers necessary to hold the */
+	/* largest allowable frame size. Note: If the max frame size is */
+	/* not an even multiple of the DMA buffer size then we need to */
+	/* round the buffer count per frame up one. */
+
+	BuffersPerFrame = (unsigned short)(info->max_frame_size/SCABUFSIZE);
+	if ( info->max_frame_size % SCABUFSIZE )
+		BuffersPerFrame++;
+
+	/* calculate total number of data buffers (SCABUFSIZE) possible
+	 * in one ports memory (SCA_MEM_SIZE/4) after allocating memory
+	 * for the descriptor list (BUFFERLISTSIZE).
+	 */
+	BufferCount = (SCA_MEM_SIZE/4 - BUFFERLISTSIZE)/SCABUFSIZE;
+
+	/* limit number of buffers to maximum amount of descriptors */
+	if (BufferCount > BUFFERLISTSIZE/sizeof(SCADESC))
+		BufferCount = BUFFERLISTSIZE/sizeof(SCADESC);
+
+	/* use enough buffers to transmit one max size frame */
+	info->tx_buf_count = BuffersPerFrame + 1;
+
+	/* never use more than half the available buffers for transmit */
+	if (info->tx_buf_count > (BufferCount/2))
+		info->tx_buf_count = BufferCount/2;
+
+	if (info->tx_buf_count > SCAMAXDESC)
+		info->tx_buf_count = SCAMAXDESC;
+
+	/* use remaining buffers for receive */
+	info->rx_buf_count = BufferCount - info->tx_buf_count;
+
+	if (info->rx_buf_count > SCAMAXDESC)
+		info->rx_buf_count = SCAMAXDESC;
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk("%s(%d):%s Allocating %d TX and %d RX DMA buffers.\n",
+			__FILE__,__LINE__, info->device_name,
+			info->tx_buf_count,info->rx_buf_count);
+
+	if ( alloc_buf_list( info ) < 0 ||
+		alloc_frame_bufs(info,
+		  			info->rx_buf_list,
+		  			info->rx_buf_list_ex,
+					info->rx_buf_count) < 0 ||
+		alloc_frame_bufs(info,
+					info->tx_buf_list,
+					info->tx_buf_list_ex,
+					info->tx_buf_count) < 0 ||
+		alloc_tmp_rx_buf(info) < 0 ) {
+		printk("%s(%d):%s Can't allocate DMA buffer memory\n",
+			__FILE__,__LINE__, info->device_name);
+		return -ENOMEM;
+	}
+
+	rx_reset_buffers( info );
+
+	return 0;
+}
+
+/* Allocate DMA buffers for the transmit and receive descriptor lists.
+ */
+int alloc_buf_list(SLMP_INFO *info)
+{
+	unsigned int i;
+
+	/* build list in adapter shared memory */
+	info->buffer_list = info->memory_base + info->port_array[0]->last_mem_alloc;
+	info->buffer_list_phys = info->port_array[0]->last_mem_alloc;
+	info->port_array[0]->last_mem_alloc += BUFFERLISTSIZE;
+
+	memset(info->buffer_list, 0, BUFFERLISTSIZE);
+
+	/* Save virtual address pointers to the receive and */
+	/* transmit buffer lists. (Receive 1st). These pointers will */
+	/* be used by the processor to access the lists. */
+	info->rx_buf_list = (SCADESC *)info->buffer_list;
+
+	info->tx_buf_list = (SCADESC *)info->buffer_list;
+	info->tx_buf_list += info->rx_buf_count;
+
+	/* Build links for circular buffer entry lists (tx and rx)
+	 *
+	 * Note: links are physical addresses read by the SCA device
+	 * to determine the next buffer entry to use.
+	 */
+
+	for ( i = 0; i < info->rx_buf_count; i++ ) {
+		/* calculate and store physical address of this buffer entry */
+		info->rx_buf_list_ex[i].phys_entry =
+			info->buffer_list_phys + (i * sizeof(SCABUFSIZE));
+
+		/* calculate and store physical address of */
+		/* next entry in cirular list of entries */
+		info->rx_buf_list[i].next = info->buffer_list_phys;
+		if ( i < info->rx_buf_count - 1 )
+			info->rx_buf_list[i].next += (i + 1) * sizeof(SCADESC);
+
+		info->rx_buf_list[i].length = SCABUFSIZE;
+	}
+
+	for ( i = 0; i < info->tx_buf_count; i++ ) {
+		/* calculate and store physical address of this buffer entry */
+		info->tx_buf_list_ex[i].phys_entry = info->buffer_list_phys +
+			((info->rx_buf_count + i) * sizeof(SCADESC));
+
+		/* calculate and store physical address of */
+		/* next entry in cirular list of entries */
+
+		info->tx_buf_list[i].next = info->buffer_list_phys +
+			info->rx_buf_count * sizeof(SCADESC);
+
+		if ( i < info->tx_buf_count - 1 )
+			info->tx_buf_list[i].next += (i + 1) * sizeof(SCADESC);
+	}
+
+	return 0;
+}
+
+/* Allocate the frame DMA buffers used by the specified buffer list.
+ */
+int alloc_frame_bufs(SLMP_INFO *info, SCADESC *buf_list,SCADESC_EX *buf_list_ex,int count)
+{
+	int i;
+	unsigned long phys_addr;
+
+	for ( i = 0; i < count; i++ ) {
+		buf_list_ex[i].virt_addr = info->memory_base + info->port_array[0]->last_mem_alloc;
+		phys_addr = info->port_array[0]->last_mem_alloc;
+		info->port_array[0]->last_mem_alloc += SCABUFSIZE;
+
+		buf_list[i].buf_ptr  = (unsigned short)phys_addr;
+		buf_list[i].buf_base = (unsigned char)(phys_addr >> 16);
+	}
+
+	return 0;
+}
+
+void free_dma_bufs(SLMP_INFO *info)
+{
+	info->buffer_list = NULL;
+	info->rx_buf_list = NULL;
+	info->tx_buf_list = NULL;
+}
+
+/* allocate buffer large enough to hold max_frame_size.
+ * This buffer is used to pass an assembled frame to the line discipline.
+ */
+int alloc_tmp_rx_buf(SLMP_INFO *info)
+{
+	info->tmp_rx_buf = kmalloc(info->max_frame_size, GFP_KERNEL);
+	if (info->tmp_rx_buf == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+void free_tmp_rx_buf(SLMP_INFO *info)
+{
+	if (info->tmp_rx_buf)
+		kfree(info->tmp_rx_buf);
+	info->tmp_rx_buf = NULL;
+}
+
+int claim_resources(SLMP_INFO *info)
+{
+	if (request_mem_region(info->phys_memory_base,0x40000,"synclinkmp") == NULL) {
+		printk( "%s(%d):%s mem addr conflict, Addr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_memory_base);
+		goto errout;
+	}
+	else
+		info->shared_mem_requested = 1;
+
+	if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclinkmp") == NULL) {
+		printk( "%s(%d):%s lcr mem addr conflict, Addr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_lcr_base);
+		goto errout;
+	}
+	else
+		info->lcr_mem_requested = 1;
+
+	if (request_mem_region(info->phys_sca_base + info->sca_offset,512,"synclinkmp") == NULL) {
+		printk( "%s(%d):%s sca mem addr conflict, Addr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_sca_base);
+		goto errout;
+	}
+	else
+		info->sca_base_requested = 1;
+
+	if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,16,"synclinkmp") == NULL) {
+		printk( "%s(%d):%s stat/ctrl mem addr conflict, Addr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_statctrl_base);
+		goto errout;
+	}
+	else
+		info->sca_statctrl_requested = 1;
+
+	info->memory_base = ioremap(info->phys_memory_base,SCA_MEM_SIZE);
+	if (!info->memory_base) {
+		printk( "%s(%d):%s Cant map shared memory, MemAddr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_memory_base );
+		goto errout;
+	}
+
+	if ( !memory_test(info) ) {
+		printk( "%s(%d):Shared Memory Test failed for device %s MemAddr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_memory_base );
+		goto errout;
+	}
+
+	info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset;
+	if (!info->lcr_base) {
+		printk( "%s(%d):%s Cant map LCR memory, MemAddr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_lcr_base );
+		goto errout;
+	}
+
+	info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE) + info->sca_offset;
+	if (!info->sca_base) {
+		printk( "%s(%d):%s Cant map SCA memory, MemAddr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_sca_base );
+		goto errout;
+	}
+
+	info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE) + info->statctrl_offset;
+	if (!info->statctrl_base) {
+		printk( "%s(%d):%s Cant map SCA Status/Control memory, MemAddr=%08X\n",
+			__FILE__,__LINE__,info->device_name, info->phys_statctrl_base );
+		goto errout;
+	}
+
+	return 0;
+
+errout:
+	release_resources( info );
+	return -ENODEV;
+}
+
+void release_resources(SLMP_INFO *info)
+{
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk( "%s(%d):%s release_resources() entry\n",
+			__FILE__,__LINE__,info->device_name );
+
+	if ( info->irq_requested ) {
+		free_irq(info->irq_level, info);
+		info->irq_requested = 0;
+	}
+
+	if ( info->shared_mem_requested ) {
+		release_mem_region(info->phys_memory_base,0x40000);
+		info->shared_mem_requested = 0;
+	}
+	if ( info->lcr_mem_requested ) {
+		release_mem_region(info->phys_lcr_base + info->lcr_offset,128);
+		info->lcr_mem_requested = 0;
+	}
+	if ( info->sca_base_requested ) {
+		release_mem_region(info->phys_sca_base + info->sca_offset,512);
+		info->sca_base_requested = 0;
+	}
+	if ( info->sca_statctrl_requested ) {
+		release_mem_region(info->phys_statctrl_base + info->statctrl_offset,16);
+		info->sca_statctrl_requested = 0;
+	}
+
+	if (info->memory_base){
+		iounmap(info->memory_base);
+		info->memory_base = 0;
+	}
+
+	if (info->sca_base) {
+		iounmap(info->sca_base - info->sca_offset);
+		info->sca_base=0;
+	}
+
+	if (info->statctrl_base) {
+		iounmap(info->statctrl_base - info->statctrl_offset);
+		info->statctrl_base=0;
+	}
+
+	if (info->lcr_base){
+		iounmap(info->lcr_base - info->lcr_offset);
+		info->lcr_base = 0;
+	}
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk( "%s(%d):%s release_resources() exit\n",
+			__FILE__,__LINE__,info->device_name );
+}
+
+/* Add the specified device instance data structure to the
+ * global linked list of devices and increment the device count.
+ */
+void add_device(SLMP_INFO *info)
+{
+	info->next_device = NULL;
+	info->line = synclinkmp_device_count;
+	sprintf(info->device_name,"ttySLM%dp%d",info->adapter_num,info->port_num);
+
+	if (info->line < MAX_DEVICES) {
+		if (maxframe[info->line])
+			info->max_frame_size = maxframe[info->line];
+		info->dosyncppp = dosyncppp[info->line];
+	}
+
+	synclinkmp_device_count++;
+
+	if ( !synclinkmp_device_list )
+		synclinkmp_device_list = info;
+	else {
+		SLMP_INFO *current_dev = synclinkmp_device_list;
+		while( current_dev->next_device )
+			current_dev = current_dev->next_device;
+		current_dev->next_device = info;
+	}
+
+	if ( info->max_frame_size < 4096 )
+		info->max_frame_size = 4096;
+	else if ( info->max_frame_size > 65535 )
+		info->max_frame_size = 65535;
+
+	printk( "SyncLink MultiPort %s: "
+		"Mem=(%08x %08X %08x %08X) IRQ=%d MaxFrameSize=%u\n",
+		info->device_name,
+		info->phys_sca_base,
+		info->phys_memory_base,
+		info->phys_statctrl_base,
+		info->phys_lcr_base,
+		info->irq_level,
+		info->max_frame_size );
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+	if (info->dosyncppp)
+		sppp_init(info);
+#endif
+}
+
+/* Allocate and initialize a device instance structure
+ *
+ * Return Value:	pointer to SLMP_INFO if success, otherwise NULL
+ */
+SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
+{
+	SLMP_INFO *info;
+
+	info = (SLMP_INFO *)kmalloc(sizeof(SLMP_INFO),
+		 GFP_KERNEL);
+
+	if (!info) {
+		printk("%s(%d) Error can't allocate device instance data for adapter %d, port %d\n",
+			__FILE__,__LINE__, adapter_num, port_num);
+	} else {
+		memset(info, 0, sizeof(SLMP_INFO));
+		info->magic = MGSL_MAGIC;
+		info->task.sync = 0;
+		info->task.routine = bh_handler;
+		info->task.data    = info;
+		info->max_frame_size = 4096;
+		info->close_delay = 5*HZ/10;
+		info->closing_wait = 30*HZ;
+		init_waitqueue_head(&info->open_wait);
+		init_waitqueue_head(&info->close_wait);
+		init_waitqueue_head(&info->status_event_wait_q);
+		init_waitqueue_head(&info->event_wait_q);
+		spin_lock_init(&info->netlock);
+		memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS));
+		info->idle_mode = HDLC_TXIDLE_FLAGS;
+		info->adapter_num = adapter_num;
+		info->port_num = port_num;
+
+		/* Copy configuration info to device instance data */
+		info->irq_level = pdev->irq;
+		info->phys_lcr_base = pci_resource_start(pdev,0);
+		info->phys_sca_base = pci_resource_start(pdev,2);
+		info->phys_memory_base = pci_resource_start(pdev,3);
+		info->phys_statctrl_base = pci_resource_start(pdev,4);
+
+		/* Because veremap only works on page boundaries we must map
+		 * a larger area than is actually implemented for the LCR
+		 * memory range. We map a full page starting at the page boundary.
+		 */
+		info->lcr_offset    = info->phys_lcr_base & (PAGE_SIZE-1);
+		info->phys_lcr_base &= ~(PAGE_SIZE-1);
+
+		info->sca_offset    = info->phys_sca_base & (PAGE_SIZE-1);
+		info->phys_sca_base &= ~(PAGE_SIZE-1);
+
+		info->statctrl_offset    = info->phys_statctrl_base & (PAGE_SIZE-1);
+		info->phys_statctrl_base &= ~(PAGE_SIZE-1);
+
+		info->bus_type = MGSL_BUS_TYPE_PCI;
+		info->irq_flags = SA_SHIRQ;
+
+		/* Store the PCI9050 misc control register value because a flaw
+		 * in the PCI9050 prevents LCR registers from being read if
+		 * BIOS assigns an LCR base address with bit 7 set.
+		 *
+		 * Only the misc control register is accessed for which only
+		 * write access is needed, so set an initial value and change
+		 * bits to the device instance data as we write the value
+		 * to the actual misc control register.
+		 */
+		info->misc_ctrl_value = 0x087e4546;
+
+		/* initial port state is unknown - if startup errors
+		 * occur, init_error will be set to indicate the
+		 * problem. Once the port is fully initialized,
+		 * this value will be set to 0 to indicate the
+		 * port is available.
+		 */
+		info->init_error = -1;
+	}
+
+	return info;
+}
+
+void device_init(int adapter_num, struct pci_dev *pdev)
+{
+	SLMP_INFO *port_array[SCA_MAX_PORTS];
+	int port;
+
+	/* allocate device instances for up to SCA_MAX_PORTS devices */
+	for ( port = 0; port < SCA_MAX_PORTS; ++port ) {
+		port_array[port] = alloc_dev(adapter_num,port,pdev);
+		if( port_array[port] == NULL ) {
+			for ( --port; port >= 0; --port )
+				kfree(port_array[port]);
+			return;
+		}
+	}
+
+	/* give copy of port_array to all ports and add to device list  */
+	for ( port = 0; port < SCA_MAX_PORTS; ++port ) {
+		memcpy(port_array[port]->port_array,port_array,sizeof(port_array));
+		add_device( port_array[port] );
+		spin_lock_init(&port_array[port]->lock);
+	}
+
+	/* Allocate and claim adapter resources */
+	if ( !claim_resources(port_array[0]) ) {
+
+		alloc_dma_bufs(port_array[0]);
+
+		/* copy resource information from first port to others */
+		for ( port = 1; port < SCA_MAX_PORTS; ++port ) {
+			port_array[port]->lock  = port_array[0]->lock;
+			port_array[port]->irq_level     = port_array[0]->irq_level;
+			port_array[port]->memory_base   = port_array[0]->memory_base;
+			port_array[port]->sca_base      = port_array[0]->sca_base;
+			port_array[port]->statctrl_base = port_array[0]->statctrl_base;
+			port_array[port]->lcr_base      = port_array[0]->lcr_base;
+			alloc_dma_bufs(port_array[port]);
+		}
+
+		if ( request_irq(port_array[0]->irq_level,
+					synclinkmp_interrupt,
+					port_array[0]->irq_flags,
+					port_array[0]->device_name,
+					port_array[0]) < 0 ) {
+			printk( "%s(%d):%s Cant request interrupt, IRQ=%d\n",
+				__FILE__,__LINE__,
+				port_array[0]->device_name,
+				port_array[0]->irq_level );
+		}
+		else {
+			port_array[0]->irq_requested = 1;
+			adapter_test(port_array[0]);
+		}
+	}
+}
+
+/* Driver initialization entry point.
+ */
+
+static int __init synclinkmp_init(void)
+{
+	SLMP_INFO *info;
+
+	EXPORT_NO_SYMBOLS;
+
+	if (break_on_load) {
+	 	synclinkmp_get_text_ptr();
+  		BREAKPOINT();
+	}
+
+ 	printk("%s %s\n", driver_name, driver_version);
+
+	synclinkmp_adapter_count = -1;
+	pci_register_driver(&synclinkmp_pci_driver);
+
+	if ( !synclinkmp_device_list ) {
+		printk("%s(%d):No SyncLink devices found.\n",__FILE__,__LINE__);
+		return -ENODEV;
+	}
+
+	memset(serial_table,0,sizeof(struct tty_struct*)*MAX_DEVICES);
+	memset(serial_termios,0,sizeof(struct termios*)*MAX_DEVICES);
+	memset(serial_termios_locked,0,sizeof(struct termios*)*MAX_DEVICES);
+
+	/* Initialize the tty_driver structure */
+
+	memset(&serial_driver, 0, sizeof(struct tty_driver));
+	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.driver_name = "synclinkmp";
+	serial_driver.name = "ttySLM";
+	serial_driver.major = ttymajor;
+	serial_driver.minor_start = 64;
+	serial_driver.num = synclinkmp_device_count;
+	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	serial_driver.subtype = SERIAL_TYPE_NORMAL;
+	serial_driver.init_termios = tty_std_termios;
+	serial_driver.init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	serial_driver.flags = TTY_DRIVER_REAL_RAW;
+	serial_driver.refcount = &serial_refcount;
+	serial_driver.table = serial_table;
+	serial_driver.termios = serial_termios;
+	serial_driver.termios_locked = serial_termios_locked;
+
+	serial_driver.open = open;
+	serial_driver.close = close;
+	serial_driver.write = write;
+	serial_driver.put_char = put_char;
+	serial_driver.flush_chars = flush_chars;
+	serial_driver.write_room = write_room;
+	serial_driver.chars_in_buffer = chars_in_buffer;
+	serial_driver.flush_buffer = flush_buffer;
+	serial_driver.ioctl = ioctl;
+	serial_driver.throttle = throttle;
+	serial_driver.unthrottle = unthrottle;
+	serial_driver.send_xchar = send_xchar;
+	serial_driver.break_ctl = set_break;
+	serial_driver.wait_until_sent = wait_until_sent;
+ 	serial_driver.read_proc = read_proc;
+	serial_driver.set_termios = set_termios;
+	serial_driver.stop = tx_hold;
+	serial_driver.start = tx_release;
+	serial_driver.hangup = hangup;
+
+	/*
+	 * The callout device is just like normal device except for
+	 * major number and the subtype code.
+	 */
+	callout_driver = serial_driver;
+	callout_driver.name = "cuaSLM";
+	callout_driver.major = cuamajor;
+	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+	callout_driver.read_proc = 0;
+	callout_driver.proc_entry = 0;
+
+	if (tty_register_driver(&serial_driver) < 0)
+		printk("%s(%d):Couldn't register serial driver\n",
+			__FILE__,__LINE__);
+
+	if (tty_register_driver(&callout_driver) < 0)
+		printk("%s(%d):Couldn't register callout driver\n",
+			__FILE__,__LINE__);
+
+ 	printk("%s %s, tty major#%d callout major#%d\n",
+		driver_name, driver_version,
+		serial_driver.major, callout_driver.major);
+
+	/* Propagate these values to all device instances */
+
+	info = synclinkmp_device_list;
+	while(info){
+		info->callout_termios = callout_driver.init_termios;
+		info->normal_termios  = serial_driver.init_termios;
+		info = info->next_device;
+	}
+
+	return 0;
+}
+
+static void __exit synclinkmp_exit(void)
+{
+	unsigned long flags;
+	int rc;
+	SLMP_INFO *info;
+	SLMP_INFO *tmp;
+
+	printk("Unloading %s %s\n", driver_name, driver_version);
+	save_flags(flags);
+	cli();
+	if ((rc = tty_unregister_driver(&serial_driver)))
+		printk("%s(%d) failed to unregister tty driver err=%d\n",
+		       __FILE__,__LINE__,rc);
+	if ((rc = tty_unregister_driver(&callout_driver)))
+		printk("%s(%d) failed to unregister callout driver err=%d\n",
+		       __FILE__,__LINE__,rc);
+	restore_flags(flags);
+
+	info = synclinkmp_device_list;
+	while(info) {
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+		if (info->dosyncppp)
+			sppp_delete(info);
+#endif
+		reset_port(info);
+		if ( info->port_num == 0 ) {
+			if ( info->irq_requested ) {
+				free_irq(info->irq_level, info);
+				info->irq_requested = 0;
+			}
+		}
+		info = info->next_device;
+	}
+
+	/* port 0 of each adapter originally claimed
+	 * all resources, release those now
+	 */
+	info = synclinkmp_device_list;
+	while(info) {
+		free_dma_bufs(info);
+		free_tmp_rx_buf(info);
+		if ( info->port_num == 0 ) {
+			spin_lock_irqsave(&info->lock,flags);
+			reset_adapter(info);
+			write_reg(info, LPR, 1);		/* set low power mode */
+			spin_unlock_irqrestore(&info->lock,flags);
+			release_resources(info);
+		}
+		tmp = info;
+		info = info->next_device;
+		kfree(tmp);
+	}
+
+	pci_unregister_driver(&synclinkmp_pci_driver);
+}
+
+module_init(synclinkmp_init);
+module_exit(synclinkmp_exit);
+
+/* Set the port for internal loopback mode.
+ * The TxCLK and RxCLK signals are generated from the BRG and
+ * the TxD is looped back to the RxD internally.
+ */
+void enable_loopback(SLMP_INFO *info, int enable)
+{
+	if (enable) {
+		/* MD2 (Mode Register 2)
+		 * 01..00  CNCT<1..0> Channel Connection 11=Local Loopback
+		 */
+		write_reg(info, MD2, (unsigned char)(read_reg(info, MD2) | (BIT1 + BIT0)));
+
+		/* degate external TxC clock source */
+		info->port_array[0]->ctrlreg_value |= (BIT0 << (info->port_num * 2));
+		write_control_reg(info);
+
+		/* RXS/TXS (Rx/Tx clock source)
+		 * 07      Reserved, must be 0
+		 * 06..04  Clock Source, 100=BRG
+		 * 03..00  Clock Divisor, 0000=1
+		 */
+		write_reg(info, RXS, 0x40);
+		write_reg(info, TXS, 0x40);
+
+	} else {
+		/* MD2 (Mode Register 2)
+	 	 * 01..00  CNCT<1..0> Channel connection, 0=normal
+		 */
+		write_reg(info, MD2, (unsigned char)(read_reg(info, MD2) & ~(BIT1 + BIT0)));
+
+		/* RXS/TXS (Rx/Tx clock source)
+		 * 07      Reserved, must be 0
+		 * 06..04  Clock Source, 000=RxC/TxC Pin
+		 * 03..00  Clock Divisor, 0000=1
+		 */
+		write_reg(info, RXS, 0x00);
+		write_reg(info, TXS, 0x00);
+	}
+
+	/* set LinkSpeed if available, otherwise default to 2Mbps */
+	if (info->params.clock_speed)
+		set_rate(info, info->params.clock_speed);
+	else
+		set_rate(info, 3686400);
+}
+
+/* Set the baud rate register to the desired speed
+ *
+ *	data_rate	data rate of clock in bits per second
+ *			A data rate of 0 disables the AUX clock.
+ */
+void set_rate( SLMP_INFO *info, u32 data_rate )
+{
+       	u32 TMCValue;
+       	unsigned char BRValue;
+	u32 Divisor=0;
+
+	/* fBRG = fCLK/(TMC * 2^BR)
+	 */
+	if (data_rate != 0) {
+		Divisor = 14745600/data_rate;
+		if (!Divisor)
+			Divisor = 1;
+
+		TMCValue = Divisor;
+
+		BRValue = 0;
+		if (TMCValue != 1 && TMCValue != 2) {
+			/* BRValue of 0 provides 50/50 duty cycle *only* when
+			 * TMCValue is 1 or 2. BRValue of 1 to 9 always provides
+			 * 50/50 duty cycle.
+			 */
+			BRValue = 1;
+			TMCValue >>= 1;
+		}
+
+		/* while TMCValue is too big for TMC register, divide
+		 * by 2 and increment BR exponent.
+		 */
+		for(; TMCValue > 256 && BRValue < 10; BRValue++)
+			TMCValue >>= 1;
+
+		write_reg(info, TXS,
+			(unsigned char)((read_reg(info, TXS) & 0xf0) | BRValue));
+		write_reg(info, RXS,
+			(unsigned char)((read_reg(info, RXS) & 0xf0) | BRValue));
+		write_reg(info, TMC, (unsigned char)TMCValue);
+	}
+	else {
+		write_reg(info, TXS,0);
+		write_reg(info, RXS,0);
+		write_reg(info, TMC, 0);
+	}
+}
+
+/* Disable receiver
+ */
+void rx_stop(SLMP_INFO *info)
+{
+	if (debug_level >= DEBUG_LEVEL_ISR)
+		printk("%s(%d):%s rx_stop()\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	write_reg(info, CMD, RXRESET);
+
+	info->ie0_value &= ~RXRDYE;
+	write_reg(info, IE0, info->ie0_value);	/* disable Rx data interrupts */
+
+	write_reg(info, RXDMA + DSR, 0);	/* disable Rx DMA */
+	write_reg(info, RXDMA + DCMD, SWABORT);	/* reset/init Rx DMA */
+	write_reg(info, RXDMA + DIR, 0);	/* disable Rx DMA interrupts */
+
+	info->rx_enabled = 0;
+	info->rx_overflow = 0;
+}
+
+/* enable the receiver
+ */
+void rx_start(SLMP_INFO *info)
+{
+	int i;
+
+	if (debug_level >= DEBUG_LEVEL_ISR)
+		printk("%s(%d):%s rx_start()\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	write_reg(info, CMD, RXRESET);
+
+	if ( info->params.mode == MGSL_MODE_HDLC ) {
+		/* HDLC, disabe IRQ on rxdata */
+		info->ie0_value &= ~RXRDYE;
+		write_reg(info, IE0, info->ie0_value);
+
+		/* Reset all Rx DMA buffers and program rx dma */
+		write_reg(info, RXDMA + DSR, 0);		/* disable Rx DMA */
+		write_reg(info, RXDMA + DCMD, SWABORT);	/* reset/init Rx DMA */
+
+		for (i = 0; i < info->rx_buf_count; i++) {
+			info->rx_buf_list[i].status = 0xff;
+
+			// throttle to 4 shared memory writes at a time to prevent
+			// hogging local bus (keep latency time for DMA requests low).
+			if (!(i % 4))
+				read_status_reg(info);
+		}
+		info->current_rx_buf = 0;
+
+		/* set current/1st descriptor address */
+		write_reg16(info, RXDMA + CDA,
+			info->rx_buf_list_ex[0].phys_entry);
+
+		/* set new last rx descriptor address */
+		write_reg16(info, RXDMA + EDA,
+			info->rx_buf_list_ex[info->rx_buf_count - 1].phys_entry);
+
+		/* set buffer length (shared by all rx dma data buffers) */
+		write_reg16(info, RXDMA + BFL, SCABUFSIZE);
+
+		write_reg(info, RXDMA + DIR, 0x60);	/* enable Rx DMA interrupts (EOM/BOF) */
+		write_reg(info, RXDMA + DSR, 0xf2);	/* clear Rx DMA IRQs, enable Rx DMA */
+	} else {
+		/* async, enable IRQ on rxdata */
+		info->ie0_value |= RXRDYE;
+		write_reg(info, IE0, info->ie0_value);
+	}
+
+	write_reg(info, CMD, RXENABLE);
+
+	info->rx_overflow = FALSE;
+	info->rx_enabled = 1;
+}
+
+/* Enable the transmitter and send a transmit frame if
+ * one is loaded in the DMA buffers.
+ */
+void tx_start(SLMP_INFO *info)
+{
+	if (debug_level >= DEBUG_LEVEL_ISR)
+		printk("%s(%d):%s tx_start() tx_count=%d\n",
+			 __FILE__,__LINE__, info->device_name,info->tx_count );
+
+	if (!info->tx_enabled ) {
+		write_reg(info, CMD, TXRESET);
+		write_reg(info, CMD, TXENABLE);
+		info->tx_enabled = TRUE;
+	}
+
+	if ( info->tx_count ) {
+
+		/* If auto RTS enabled and RTS is inactive, then assert */
+		/* RTS and set a flag indicating that the driver should */
+		/* negate RTS when the transmission completes. */
+
+		info->drop_rts_on_tx_done = 0;
+
+		if (info->params.mode != MGSL_MODE_ASYNC) {
+
+			if ( info->params.flags & HDLC_FLAG_AUTO_RTS ) {
+				get_signals( info );
+				if ( !(info->serial_signals & SerialSignal_RTS) ) {
+					info->serial_signals |= SerialSignal_RTS;
+					set_signals( info );
+					info->drop_rts_on_tx_done = 1;
+				}
+			}
+
+			write_reg(info, TXDMA + DSR, 0); 		/* disable DMA channel */
+			write_reg(info, TXDMA + DCMD, SWABORT);	/* reset/init DMA channel */
+	
+			/* set TX CDA (current descriptor address) */
+			write_reg16(info, TXDMA + CDA,
+				info->tx_buf_list_ex[0].phys_entry);
+	
+			/* set TX EDA (last descriptor address) */
+			write_reg16(info, TXDMA + EDA,
+				info->tx_buf_list_ex[info->last_tx_buf].phys_entry);
+	
+			/* clear IDLE and UDRN status bit */
+			info->ie1_value &= ~(IDLE + UDRN);
+			if (info->params.mode != MGSL_MODE_ASYNC)
+				info->ie1_value |= UDRN;     		/* HDLC, IRQ on underrun */
+			write_reg(info, IE1, info->ie1_value);	/* enable MSCI interrupts */
+			write_reg(info, SR1, (unsigned char)(IDLE + UDRN));
+	
+			write_reg(info, TXDMA + DIR, 0x40);		/* enable Tx DMA interrupts (EOM) */
+			write_reg(info, TXDMA + DSR, 0xf2);		/* clear Tx DMA IRQs, enable Tx DMA */
+	
+			info->tx_timer.expires = jiffies + jiffies_from_ms(5000);
+			add_timer(&info->tx_timer);
+		}
+		else {
+			tx_load_fifo(info);
+			/* async, enable IRQ on txdata */
+			info->ie0_value |= TXRDYE;
+			write_reg(info, IE0, info->ie0_value);
+		}
+
+		info->tx_active = 1;
+	}
+}
+
+/* stop the transmitter and DMA
+ */
+void tx_stop( SLMP_INFO *info )
+{
+	if (debug_level >= DEBUG_LEVEL_ISR)
+		printk("%s(%d):%s tx_stop()\n",
+			 __FILE__,__LINE__, info->device_name );
+
+	del_timer(&info->tx_timer);
+
+	write_reg(info, TXDMA + DSR, 0);		/* disable DMA channel */
+	write_reg(info, TXDMA + DCMD, SWABORT);	/* reset/init DMA channel */
+
+	write_reg(info, CMD, TXRESET);
+
+	info->ie1_value &= ~(UDRN + IDLE);
+	write_reg(info, IE1, info->ie1_value);	/* disable tx status interrupts */
+	write_reg(info, SR1, (unsigned char)(IDLE + UDRN));	/* clear pending */
+
+	info->ie0_value &= ~TXRDYE;
+	write_reg(info, IE0, info->ie0_value);	/* disable tx data interrupts */
+
+	info->tx_enabled = 0;
+	info->tx_active  = 0;
+}
+
+/* Fill the transmit FIFO until the FIFO is full or
+ * there is no more data to load.
+ */
+void tx_load_fifo(SLMP_INFO *info)
+{
+	u8 TwoBytes[2];
+
+	/* do nothing is now tx data available and no XON/XOFF pending */
+
+	if ( !info->tx_count && !info->x_char )
+		return;
+
+	/* load the Transmit FIFO until FIFOs full or all data sent */
+
+	while( info->tx_count && (read_reg(info,SR0) & BIT1) ) {
+
+		/* there is more space in the transmit FIFO and */
+		/* there is more data in transmit buffer */
+
+		if ( (info->tx_count > 1) && !info->x_char ) {
+ 			/* write 16-bits */
+			TwoBytes[0] = info->tx_buf[info->tx_get++];
+			if (info->tx_get >= info->max_frame_size)
+				info->tx_get -= info->max_frame_size;
+			TwoBytes[1] = info->tx_buf[info->tx_get++];
+			if (info->tx_get >= info->max_frame_size)
+				info->tx_get -= info->max_frame_size;
+
+			write_reg16(info, TRB, *((u16 *)TwoBytes));
+
+			info->tx_count -= 2;
+			info->icount.tx += 2;
+		} else {
+			/* only 1 byte left to transmit or 1 FIFO slot left */
+
+			if (info->x_char) {
+				/* transmit pending high priority char */
+				write_reg(info, TRB, info->x_char);
+				info->x_char = 0;
+			} else {
+				write_reg(info, TRB, info->tx_buf[info->tx_get++]);
+				if (info->tx_get >= info->max_frame_size)
+					info->tx_get -= info->max_frame_size;
+				info->tx_count--;
+			}
+			info->icount.tx++;
+		}
+	}
+}
+
+/* Reset a port to a known state
+ */
+void reset_port(SLMP_INFO *info)
+{
+	if (info->sca_base) {
+
+		tx_stop(info);
+		rx_stop(info);
+
+		info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
+		set_signals(info);
+
+		/* disable all port interrupts */
+		info->ie0_value = 0;
+		info->ie1_value = 0;
+		info->ie2_value = 0;
+		write_reg(info, IE0, info->ie0_value);
+		write_reg(info, IE1, info->ie1_value);
+		write_reg(info, IE2, info->ie2_value);
+
+		write_reg(info, CMD, CHRESET);
+	}
+}
+
+/* Reset all the ports to a known state.
+ */
+void reset_adapter(SLMP_INFO *info)
+{
+	int i;
+
+	for ( i=0; i < SCA_MAX_PORTS; ++i) {
+		if (info->port_array[i])
+			reset_port(info->port_array[i]);
+	}
+}
+
+/* Program port for asynchronous communications.
+ */
+void async_mode(SLMP_INFO *info)
+{
+
+  	unsigned char RegValue;
+
+	tx_stop(info);
+	rx_stop(info);
+
+	/* MD0, Mode Register 0
+	 *
+	 * 07..05  PRCTL<2..0>, Protocol Mode, 000=async
+	 * 04      AUTO, Auto-enable (RTS/CTS/DCD)
+	 * 03      Reserved, must be 0
+	 * 02      CRCCC, CRC Calculation, 0=disabled
+	 * 01..00  STOP<1..0> Stop bits (00=1,10=2)
+	 *
+	 * 0000 0000
+	 */
+	RegValue = 0x00;
+	if (info->params.stop_bits != 1)
+		RegValue |= BIT1;
+	write_reg(info, MD0, RegValue);
+
+	/* MD1, Mode Register 1
+	 *
+	 * 07..06  BRATE<1..0>, bit rate, 00=1/1 01=1/16 10=1/32 11=1/64
+	 * 05..04  TXCHR<1..0>, tx char size, 00=8 bits,01=7,10=6,11=5
+	 * 03..02  RXCHR<1..0>, rx char size
+	 * 01..00  PMPM<1..0>, Parity mode, 00=none 10=even 11=odd
+	 *
+	 * 0100 0000
+	 */
+	RegValue = 0x40;
+	switch (info->params.data_bits) {
+	case 7: RegValue |= BIT4 + BIT2; break;
+	case 6: RegValue |= BIT5 + BIT3; break;
+	case 5: RegValue |= BIT5 + BIT4 + BIT3 + BIT2; break;
+	}
+	if (info->params.parity != ASYNC_PARITY_NONE) {
+		RegValue |= BIT1;
+		if (info->params.parity == ASYNC_PARITY_ODD)
+			RegValue |= BIT0;
+	}
+	write_reg(info, MD1, RegValue);
+
+	/* MD2, Mode Register 2
+	 *
+	 * 07..02  Reserved, must be 0
+	 * 01..00  CNCT<1..0> Channel connection, 0=normal
+	 *
+	 * 0000 0000
+	 */
+	RegValue = 0x00;
+	write_reg(info, MD2, RegValue);
+
+	/* RXS, Receive clock source
+	 *
+	 * 07      Reserved, must be 0
+	 * 06..04  RXCS<2..0>, clock source, 000=RxC Pin, 100=BRG, 110=DPLL
+	 * 03..00  RXBR<3..0>, rate divisor, 0000=1
+	 */
+	RegValue=BIT6;
+	write_reg(info, RXS, RegValue);
+
+	/* TXS, Transmit clock source
+	 *
+	 * 07      Reserved, must be 0
+	 * 06..04  RXCS<2..0>, clock source, 000=TxC Pin, 100=BRG, 110=Receive Clock
+	 * 03..00  RXBR<3..0>, rate divisor, 0000=1
+	 */
+	RegValue=BIT6;
+	write_reg(info, TXS, RegValue);
+
+	/* Control Register
+	 *
+	 * 6,4,2,0  CLKSEL<3..0>, 0 = TcCLK in, 1 = Auxclk out
+	 */
+	info->port_array[0]->ctrlreg_value |= (BIT0 << (info->port_num * 2));
+	write_control_reg(info);
+
+	tx_set_idle(info);
+
+	/* RRC Receive Ready Control 0
+	 *
+	 * 07..05  Reserved, must be 0
+	 * 04..00  RRC<4..0> Rx FIFO trigger active 0x00 = 1 byte
+	 */
+	write_reg(info, TRC0, 0x00);
+
+	/* TRC0 Transmit Ready Control 0
+	 *
+	 * 07..05  Reserved, must be 0
+	 * 04..00  TRC<4..0> Tx FIFO trigger active 0x10 = 16 bytes
+	 */
+	write_reg(info, TRC0, 0x10);
+
+	/* TRC1 Transmit Ready Control 1
+	 *
+	 * 07..05  Reserved, must be 0
+	 * 04..00  TRC<4..0> Tx FIFO trigger inactive 0x1e = 31 bytes (full-1)
+	 */
+	write_reg(info, TRC1, 0x1e);
+
+	/* CTL, MSCI control register
+	 *
+	 * 07..06  Reserved, set to 0
+	 * 05      UDRNC, underrun control, 0=abort 1=CRC+flag (HDLC/BSC)
+	 * 04      IDLC, idle control, 0=mark 1=idle register
+	 * 03      BRK, break, 0=off 1 =on (async)
+	 * 02      SYNCLD, sync char load enable (BSC) 1=enabled
+	 * 01      GOP, go active on poll (LOOP mode) 1=enabled
+	 * 00      RTS, RTS output control, 0=active 1=inactive
+	 *
+	 * 0001 0001
+	 */
+	RegValue = 0x10;
+	if (!(info->serial_signals & SerialSignal_RTS))
+		RegValue |= 0x01;
+	write_reg(info, CTL, RegValue);
+
+	/* enable status interrupts */
+	info->ie0_value |= TXINTE + RXINTE;
+	write_reg(info, IE0, info->ie0_value);
+
+	/* enable break detect interrupt */
+	info->ie1_value = BRKD;
+	write_reg(info, IE1, info->ie1_value);
+
+	/* enable rx overrun interrupt */
+	info->ie2_value = OVRN;
+	write_reg(info, IE2, info->ie2_value);
+
+	set_rate( info, info->params.data_rate * 16 );
+
+	if (info->params.loopback)
+		enable_loopback(info,1);
+}
+
+/* Program the SCA for HDLC communications.
+ */
+void hdlc_mode(SLMP_INFO *info)
+{
+	unsigned char RegValue;
+	u32 DpllDivisor;
+
+	// Can't use DPLL because SCA outputs recovered clock on RxC when
+	// DPLL mode selected. This causes output contention with RxC receiver.
+	// Use of DPLL would require external hardware to disable RxC receiver
+	// when DPLL mode selected.
+	info->params.flags &= ~(HDLC_FLAG_TXC_DPLL + HDLC_FLAG_RXC_DPLL);
+
+	/* disable DMA interrupts */
+	write_reg(info, TXDMA + DIR, 0);
+	write_reg(info, RXDMA + DIR, 0);
+
+	/* MD0, Mode Register 0
+	 *
+	 * 07..05  PRCTL<2..0>, Protocol Mode, 100=HDLC
+	 * 04      AUTO, Auto-enable (RTS/CTS/DCD)
+	 * 03      Reserved, must be 0
+	 * 02      CRCCC, CRC Calculation, 1=enabled
+	 * 01      CRC1, CRC selection, 0=CRC-16,1=CRC-CCITT-16
+	 * 00      CRC0, CRC initial value, 1 = all 1s
+	 *
+	 * 1000 0001
+	 */
+	RegValue = 0x81;
+	if (info->params.flags & HDLC_FLAG_AUTO_CTS)
+		RegValue |= BIT4;
+	if (info->params.flags & HDLC_FLAG_AUTO_DCD)
+		RegValue |= BIT4;
+	if (info->params.crc_type == HDLC_CRC_16_CCITT)
+		RegValue |= BIT2 + BIT1;
+	write_reg(info, MD0, RegValue);
+
+	/* MD1, Mode Register 1
+	 *
+	 * 07..06  ADDRS<1..0>, Address detect, 00=no addr check
+	 * 05..04  TXCHR<1..0>, tx char size, 00=8 bits
+	 * 03..02  RXCHR<1..0>, rx char size, 00=8 bits
+	 * 01..00  PMPM<1..0>, Parity mode, 00=no parity
+	 *
+	 * 0000 0000
+	 */
+	RegValue = 0x00;
+	write_reg(info, MD1, RegValue);
+
+	/* MD2, Mode Register 2
+	 *
+	 * 07      NRZFM, 0=NRZ, 1=FM
+	 * 06..05  CODE<1..0> Encoding, 00=NRZ
+	 * 04..03  DRATE<1..0> DPLL Divisor, 00=8
+	 * 02      Reserved, must be 0
+	 * 01..00  CNCT<1..0> Channel connection, 0=normal
+	 *
+	 * 0000 0000
+	 */
+	RegValue = 0x00;
+	switch(info->params.encoding) {
+	case HDLC_ENCODING_NRZI:	  RegValue |= BIT5; break;
+	case HDLC_ENCODING_BIPHASE_MARK:  RegValue |= BIT7 + BIT5; break; /* aka FM1 */
+	case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT7 + BIT6; break; /* aka FM0 */
+	case HDLC_ENCODING_BIPHASE_LEVEL: RegValue |= BIT7; break; 	/* aka Manchester */
+#if 0
+	case HDLC_ENCODING_NRZB:	       				/* not supported */
+	case HDLC_ENCODING_NRZI_MARK:          				/* not supported */
+	case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: 				/* not supported */
+#endif
+	}
+	if ( info->params.flags & HDLC_FLAG_DPLL_DIV16 ) {
+		DpllDivisor = 16;
+		RegValue |= BIT3;
+	} else if ( info->params.flags & HDLC_FLAG_DPLL_DIV8 ) {
+		DpllDivisor = 8;
+	} else {
+		DpllDivisor = 32;
+		RegValue |= BIT4;
+	}
+	write_reg(info, MD2, RegValue);
+
+
+	/* RXS, Receive clock source
+	 *
+	 * 07      Reserved, must be 0
+	 * 06..04  RXCS<2..0>, clock source, 000=RxC Pin, 100=BRG, 110=DPLL
+	 * 03..00  RXBR<3..0>, rate divisor, 0000=1
+	 */
+	RegValue=0;
+	if (info->params.flags & HDLC_FLAG_RXC_BRG)
+		RegValue |= BIT6;
+	if (info->params.flags & HDLC_FLAG_RXC_DPLL)
+		RegValue |= BIT6 + BIT5;
+	write_reg(info, RXS, RegValue);
+
+	/* TXS, Transmit clock source
+	 *
+	 * 07      Reserved, must be 0
+	 * 06..04  RXCS<2..0>, clock source, 000=TxC Pin, 100=BRG, 110=Receive Clock
+	 * 03..00  RXBR<3..0>, rate divisor, 0000=1
+	 */
+	RegValue=0;
+	if (info->params.flags & HDLC_FLAG_TXC_BRG)
+		RegValue |= BIT6;
+	if (info->params.flags & HDLC_FLAG_TXC_DPLL)
+		RegValue |= BIT6 + BIT5;
+	write_reg(info, TXS, RegValue);
+
+	if (info->params.flags & HDLC_FLAG_RXC_DPLL)
+		set_rate(info, info->params.clock_speed * DpllDivisor);
+	else
+		set_rate(info, info->params.clock_speed);
+
+	/* GPDATA (General Purpose I/O Data Register)
+	 *
+	 * 6,4,2,0  CLKSEL<3..0>, 0 = TcCLK in, 1 = Auxclk out
+	 */
+	if (info->params.flags & HDLC_FLAG_TXC_BRG)
+		info->port_array[0]->ctrlreg_value |= (BIT0 << (info->port_num * 2));
+	else
+		info->port_array[0]->ctrlreg_value &= ~(BIT0 << (info->port_num * 2));
+	write_control_reg(info);
+
+	/* RRC Receive Ready Control 0
+	 *
+	 * 07..05  Reserved, must be 0
+	 * 04..00  RRC<4..0> Rx FIFO trigger active
+	 */
+	write_reg(info, RRC, rx_active_fifo_level);
+
+	/* TRC0 Transmit Ready Control 0
+	 *
+	 * 07..05  Reserved, must be 0
+	 * 04..00  TRC<4..0> Tx FIFO trigger active
+	 */
+	write_reg(info, TRC0, tx_active_fifo_level);
+
+	/* TRC1 Transmit Ready Control 1
+	 *
+	 * 07..05  Reserved, must be 0
+	 * 04..00  TRC<4..0> Tx FIFO trigger inactive 0x1f = 32 bytes (full)
+	 */
+	write_reg(info, TRC1, (unsigned char)(tx_negate_fifo_level - 1));
+
+	/* DMR, DMA Mode Register
+	 *
+	 * 07..05  Reserved, must be 0
+	 * 04      TMOD, Transfer Mode: 1=chained-block
+	 * 03      Reserved, must be 0
+	 * 02      NF, Number of Frames: 1=multi-frame
+	 * 01      CNTE, Frame End IRQ Counter enable: 0=disabled
+	 * 00      Reserved, must be 0
+	 *
+	 * 0001 0100
+	 */
+	write_reg(info, TXDMA + DMR, 0x14);
+	write_reg(info, RXDMA + DMR, 0x14);
+
+	/* Set chain pointer base (upper 8 bits of 24 bit addr) */
+	write_reg(info, RXDMA + CPB,
+		(unsigned char)(info->buffer_list_phys >> 16));
+
+	/* Set chain pointer base (upper 8 bits of 24 bit addr) */
+	write_reg(info, TXDMA + CPB,
+		(unsigned char)(info->buffer_list_phys >> 16));
+
+	/* enable status interrupts. other code enables/disables
+	 * the individual sources for these two interrupt classes.
+	 */
+	info->ie0_value |= TXINTE + RXINTE;
+	write_reg(info, IE0, info->ie0_value);
+
+	/* CTL, MSCI control register
+	 *
+	 * 07..06  Reserved, set to 0
+	 * 05      UDRNC, underrun control, 0=abort 1=CRC+flag (HDLC/BSC)
+	 * 04      IDLC, idle control, 0=mark 1=idle register
+	 * 03      BRK, break, 0=off 1 =on (async)
+	 * 02      SYNCLD, sync char load enable (BSC) 1=enabled
+	 * 01      GOP, go active on poll (LOOP mode) 1=enabled
+	 * 00      RTS, RTS output control, 0=active 1=inactive
+	 *
+	 * 0001 0001
+	 */
+	RegValue = 0x10;
+	if (!(info->serial_signals & SerialSignal_RTS))
+		RegValue |= 0x01;
+	write_reg(info, CTL, RegValue);
+
+	/* preamble not supported ! */
+
+	tx_set_idle(info);
+	tx_stop(info);
+	rx_stop(info);
+
+	set_rate(info, info->params.clock_speed);
+
+	if (info->params.loopback)
+		enable_loopback(info,1);
+}
+
+/* Set the transmit HDLC idle mode
+ */
+void tx_set_idle(SLMP_INFO *info)
+{
+	unsigned char RegValue = 0xff;
+
+	/* Map API idle mode to SCA register bits */
+	switch(info->idle_mode) {
+	case HDLC_TXIDLE_FLAGS:			RegValue = 0x7e; break;
+	case HDLC_TXIDLE_ALT_ZEROS_ONES:	RegValue = 0xaa; break;
+	case HDLC_TXIDLE_ZEROS:			RegValue = 0x00; break;
+	case HDLC_TXIDLE_ONES:			RegValue = 0xff; break;
+	case HDLC_TXIDLE_ALT_MARK_SPACE:	RegValue = 0xaa; break;
+	case HDLC_TXIDLE_SPACE:			RegValue = 0x00; break;
+	case HDLC_TXIDLE_MARK:			RegValue = 0xff; break;
+	}
+
+	write_reg(info, IDL, RegValue);
+}
+
+/* Query the adapter for the state of the V24 status (input) signals.
+ */
+void get_signals(SLMP_INFO *info)
+{
+	u16 status = read_reg(info, SR3);
+	u16 gpstatus = read_status_reg(info);
+	u16 testbit;
+
+	/* clear all serial signals except DTR and RTS */
+	info->serial_signals &= SerialSignal_DTR + SerialSignal_RTS;
+
+	/* set serial signal bits to reflect MISR */
+
+	if (!(status & BIT3))
+		info->serial_signals |= SerialSignal_CTS;
+
+	if ( !(status & BIT2))
+		info->serial_signals |= SerialSignal_DCD;
+
+	testbit = BIT1 << (info->port_num * 2); // Port 0..3 RI is GPDATA<1,3,5,7>
+	if (!(gpstatus & testbit))
+		info->serial_signals |= SerialSignal_RI;
+
+	testbit = BIT0 << (info->port_num * 2); // Port 0..3 DSR is GPDATA<0,2,4,6>
+	if (!(gpstatus & testbit))
+		info->serial_signals |= SerialSignal_DSR;
+}
+
+/* Set the state of DTR and RTS based on contents of
+ * serial_signals member of device context.
+ */
+void set_signals(SLMP_INFO *info)
+{
+	unsigned char RegValue;
+	u16 EnableBit;
+
+	RegValue = read_reg(info, CTL);
+	if (info->serial_signals & SerialSignal_RTS)
+		RegValue &= ~BIT0;
+	else
+		RegValue |= BIT0;
+	write_reg(info, CTL, RegValue);
+
+	// Port 0..3 DTR is ctrl reg <1,3,5,7>
+	EnableBit = BIT1 << (info->port_num*2);
+	if (info->serial_signals & SerialSignal_DTR)
+		info->port_array[0]->ctrlreg_value &= ~EnableBit;
+	else
+		info->port_array[0]->ctrlreg_value |= EnableBit;
+	write_control_reg(info);
+}
+
+/*******************/
+/* DMA Buffer Code */
+/*******************/
+
+/* Set the count for all receive buffers to SCABUFSIZE
+ * and set the current buffer to the first buffer. This effectively
+ * makes all buffers free and discards any data in buffers.
+ */
+void rx_reset_buffers(SLMP_INFO *info)
+{
+	rx_free_frame_buffers(info, 0, info->rx_buf_count - 1);
+}
+
+/* Free the buffers used by a received frame
+ *
+ * info   pointer to device instance data
+ * first  index of 1st receive buffer of frame
+ * last   index of last receive buffer of frame
+ */
+void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last)
+{
+	int done = 0;
+
+	while(!done) {
+	        /* reset current buffer for reuse */
+		info->rx_buf_list[first].status = 0xff;
+
+	        if (first == last) {
+	                done = 1;
+	                /* set new last rx descriptor address */
+			write_reg16(info, RXDMA + EDA, info->rx_buf_list_ex[first].phys_entry);
+	        }
+
+	        first++;
+		if (first == info->rx_buf_count)
+			first = 0;
+	}
+
+	/* set current buffer to next buffer after last buffer of frame */
+	info->current_rx_buf = first;
+}
+
+/* Return a received frame from the receive DMA buffers.
+ * Only frames received without errors are returned.
+ *
+ * Return Value:	1 if frame returned, otherwise 0
+ */
+int rx_get_frame(SLMP_INFO *info)
+{
+	unsigned int StartIndex, EndIndex;	/* index of 1st and last buffers of Rx frame */
+	unsigned short status;
+	unsigned int framesize = 0;
+	int ReturnCode = 0;
+	unsigned long flags;
+	struct tty_struct *tty = info->tty;
+	unsigned char addr_field = 0xff;
+   	SCADESC *desc;
+	SCADESC_EX *desc_ex;
+
+CheckAgain:
+	/* assume no frame returned, set zero length */
+	framesize = 0;
+	addr_field = 0xff;
+
+	/*
+	 * current_rx_buf points to the 1st buffer of the next available
+	 * receive frame. To find the last buffer of the frame look for
+	 * a non-zero status field in the buffer entries. (The status
+	 * field is set by the 16C32 after completing a receive frame.
+	 */
+	StartIndex = EndIndex = info->current_rx_buf;
+
+	for ( ;; ) {
+		desc = &info->rx_buf_list[EndIndex];
+		desc_ex = &info->rx_buf_list_ex[EndIndex];
+
+		if (desc->status == 0xff)
+			goto Cleanup;	/* current desc still in use, no frames available */
+
+		if (framesize == 0 && info->params.addr_filter != 0xff)
+			addr_field = desc_ex->virt_addr[0];
+
+		framesize += desc->length;
+
+		/* Status != 0 means last buffer of frame */
+		if (desc->status)
+			break;
+
+		EndIndex++;
+		if (EndIndex == info->rx_buf_count)
+			EndIndex = 0;
+
+		if (EndIndex == info->current_rx_buf) {
+			/* all buffers have been 'used' but none mark	   */
+			/* the end of a frame. Reset buffers and receiver. */
+			if ( info->rx_enabled ){
+				spin_lock_irqsave(&info->lock,flags);
+				rx_start(info);
+				spin_unlock_irqrestore(&info->lock,flags);
+			}
+			goto Cleanup;
+		}
+
+	}
+
+	/* check status of receive frame */
+
+	/* frame status is byte stored after frame data
+	 *
+	 * 7 EOM (end of msg), 1 = last buffer of frame
+	 * 6 Short Frame, 1 = short frame
+	 * 5 Abort, 1 = frame aborted
+	 * 4 Residue, 1 = last byte is partial
+	 * 3 Overrun, 1 = overrun occurred during frame reception
+	 * 2 CRC,     1 = CRC error detected
+	 *
+	 */
+	status = desc->status;
+
+	/* ignore CRC bit if not using CRC (bit is undefined) */
+	/* Note:CRC is not save to data buffer */
+	if (info->params.crc_type == HDLC_CRC_NONE)
+		status &= ~BIT2;
+
+	if (framesize == 0 ||
+		 (addr_field != 0xff && addr_field != info->params.addr_filter)) {
+		/* discard 0 byte frames, this seems to occur sometime
+		 * when remote is idling flags.
+		 */
+		rx_free_frame_buffers(info, StartIndex, EndIndex);
+		goto CheckAgain;
+	}
+
+	if (framesize < 2)
+		status |= BIT6;
+
+	if (status & (BIT6+BIT5+BIT3+BIT2)) {
+		/* received frame has errors,
+		 * update counts and mark frame size as 0
+		 */
+		if (status & BIT6)
+			info->icount.rxshort++;
+		else if (status & BIT5)
+			info->icount.rxabort++;
+		else if (status & BIT3)
+			info->icount.rxover++;
+		else
+			info->icount.rxcrc++;
+
+		framesize = 0;
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+		info->netstats.rx_errors++;
+		info->netstats.rx_frame_errors++;
+#endif
+	}
+
+	if ( debug_level >= DEBUG_LEVEL_BH )
+		printk("%s(%d):%s rx_get_frame() status=%04X size=%d\n",
+			__FILE__,__LINE__,info->device_name,status,framesize);
+
+	if ( debug_level >= DEBUG_LEVEL_DATA )
+		trace_block(info,info->rx_buf_list_ex[StartIndex].virt_addr,
+			MIN(framesize,SCABUFSIZE),0);
+
+	if (framesize) {
+		if (framesize > info->max_frame_size)
+			info->icount.rxlong++;
+		else {
+			/* copy dma buffer(s) to contiguous intermediate buffer */
+			int copy_count = framesize;
+			int index = StartIndex;
+			unsigned char *ptmp = info->tmp_rx_buf;
+			info->tmp_rx_buf_count = framesize;
+
+			info->icount.rxok++;
+
+			while(copy_count) {
+				int partial_count = MIN(copy_count,SCABUFSIZE);
+				memcpy( ptmp,
+					info->rx_buf_list_ex[index].virt_addr,
+					partial_count );
+				ptmp += partial_count;
+				copy_count -= partial_count;
+
+				if ( ++index == info->rx_buf_count )
+					index = 0;
+			}
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+			if (info->netcount) {
+				/* pass frame to syncppp device */
+				sppp_rx_done(info,info->tmp_rx_buf,framesize);
+			}
+			else
+#endif
+			{
+				if ( tty && tty->ldisc.receive_buf ) {
+					/* Call the line discipline receive callback directly. */
+					tty->ldisc.receive_buf(tty,
+						info->tmp_rx_buf,
+						info->flag_buf,
+						framesize);
+				}
+			}
+		}
+	}
+	/* Free the buffers used by this frame. */
+	rx_free_frame_buffers( info, StartIndex, EndIndex );
+
+	ReturnCode = 1;
+
+Cleanup:
+	if ( info->rx_enabled && info->rx_overflow ) {
+		/* Receiver is enabled, but needs to restarted due to
+		 * rx buffer overflow. If buffers are empty, restart receiver.
+		 */
+		if (info->rx_buf_list[EndIndex].status == 0xff) {
+			spin_lock_irqsave(&info->lock,flags);
+			rx_start(info);
+			spin_unlock_irqrestore(&info->lock,flags);
+		}
+	}
+
+	return ReturnCode;
+}
+
+/* load the transmit DMA buffer with data
+ */
+void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count)
+{
+	unsigned short copy_count;
+	unsigned int i = 0;
+	SCADESC *desc;
+	SCADESC_EX *desc_ex;
+
+	if ( debug_level >= DEBUG_LEVEL_DATA )
+		trace_block(info,buf, MIN(count,SCABUFSIZE), 1);
+
+	/* Copy source buffer to one or more DMA buffers, starting with
+	 * the first transmit dma buffer.
+	 */
+	for(i=0;;)
+	{
+		copy_count = MIN(count,SCABUFSIZE);
+
+		desc = &info->tx_buf_list[i];
+		desc_ex = &info->tx_buf_list_ex[i];
+
+		load_pci_memory(info, desc_ex->virt_addr,buf,copy_count);
+
+		desc->length = copy_count;
+		desc->status = 0;
+
+		buf += copy_count;
+		count -= copy_count;
+
+		if (!count)
+			break;
+
+		i++;
+		if (i >= info->tx_buf_count)
+			i = 0;
+	}
+
+	info->tx_buf_list[i].status = 0x81;	/* set EOM and EOT status */
+	info->last_tx_buf = ++i;
+}
+
+int register_test(SLMP_INFO *info)
+{
+	static unsigned char testval[] = {0x00, 0xff, 0xaa, 0x55, 0x69, 0x96};
+	static unsigned int count = sizeof(testval)/sizeof(unsigned char);
+	unsigned int i;
+	int rc = TRUE;
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock,flags);
+	reset_port(info);
+
+	/* assume failure */
+	info->init_error = DiagStatus_AddressFailure;
+
+	/* Write bit patterns to various registers but do it out of */
+	/* sync, then read back and verify values. */
+
+	for (i = 0 ; i < count ; i++) {
+		write_reg(info, TMC, testval[i]);
+		write_reg(info, IDL, testval[(i+1)%count]);
+		write_reg(info, SA0, testval[(i+2)%count]);
+		write_reg(info, SA1, testval[(i+3)%count]);
+
+		if ( (read_reg(info, TMC) != testval[i]) ||
+			  (read_reg(info, IDL) != testval[(i+1)%count]) ||
+			  (read_reg(info, SA0) != testval[(i+2)%count]) ||
+			  (read_reg(info, SA1) != testval[(i+3)%count]) )
+		{
+			rc = FALSE;
+			break;
+		}
+	}
+
+	reset_port(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	return rc;
+}
+
+int irq_test(SLMP_INFO *info)
+{
+	unsigned long timeout;
+	unsigned long flags;
+
+	unsigned char timer = (info->port_num & 1) ? TIMER2 : TIMER0;
+
+	spin_lock_irqsave(&info->lock,flags);
+	reset_port(info);
+
+	/* assume failure */
+	info->init_error = DiagStatus_IrqFailure;
+	info->irq_occurred = FALSE;
+
+	/* setup timer0 on SCA0 to interrupt */
+
+	/* IER2<7..4> = timer<3..0> interrupt enables (1=enabled) */
+	write_reg(info, IER2, (unsigned char)((info->port_num & 1) ? BIT6 : BIT4));
+
+	write_reg(info, (unsigned char)(timer + TEPR), 0);	/* timer expand prescale */
+	write_reg16(info, (unsigned char)(timer + TCONR), 1);	/* timer constant */
+
+
+	/* TMCS, Timer Control/Status Register
+	 *
+	 * 07      CMF, Compare match flag (read only) 1=match
+	 * 06      ECMI, CMF Interrupt Enable: 1=enabled
+	 * 05      Reserved, must be 0
+	 * 04      TME, Timer Enable
+	 * 03..00  Reserved, must be 0
+	 *
+	 * 0101 0000
+	 */
+	write_reg(info, (unsigned char)(timer + TMCS), 0x50);
+
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	timeout=100;
+	while( timeout-- && !info->irq_occurred ) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(jiffies_from_ms(10));
+	}
+
+	spin_lock_irqsave(&info->lock,flags);
+	reset_port(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	return info->irq_occurred;
+}
+
+/* initialize individual SCA device (2 ports)
+ */
+int sca_init(SLMP_INFO *info)
+{
+	/* set wait controller to single mem partition (low), no wait states */
+	write_reg(info, PABR0, 0);	/* wait controller addr boundary 0 */
+	write_reg(info, PABR1, 0);	/* wait controller addr boundary 1 */
+	write_reg(info, WCRL, 0);	/* wait controller low range */
+	write_reg(info, WCRM, 0);	/* wait controller mid range */
+	write_reg(info, WCRH, 0);	/* wait controller high range */
+
+	/* DPCR, DMA Priority Control
+	 *
+	 * 07..05  Not used, must be 0
+	 * 04      BRC, bus release condition: 0=all transfers complete
+	 * 03      CCC, channel change condition: 0=every cycle
+	 * 02..00  PR<2..0>, priority 100=round robin
+	 *
+	 * 00000100 = 0x04
+	 */
+	write_reg(info, DPCR, dma_priority);
+
+	/* DMA Master Enable, BIT7: 1=enable all channels */
+	write_reg(info, DMER, 0x80);
+
+	/* enable all interrupt classes */
+	write_reg(info, IER0, 0xff);	/* TxRDY,RxRDY,TxINT,RxINT (ports 0-1) */
+	write_reg(info, IER1, 0xff);	/* DMIB,DMIA (channels 0-3) */
+	write_reg(info, IER2, 0xf0);	/* TIRQ (timers 0-3) */
+
+	/* ITCR, interrupt control register
+	 * 07      IPC, interrupt priority, 0=MSCI->DMA
+	 * 06..05  IAK<1..0>, Acknowledge cycle, 00=non-ack cycle
+	 * 04      VOS, Vector Output, 0=unmodified vector
+	 * 03..00  Reserved, must be 0
+	 */
+	write_reg(info, ITCR, 0);
+
+	return TRUE;
+}
+
+/* initialize adapter hardware
+ */
+int init_adapter(SLMP_INFO *info)
+{
+	int i;
+
+	/* Set BIT30 of Local Control Reg 0x50 to reset SCA */
+	volatile u32 *MiscCtrl = (u32 *)(info->lcr_base + 0x50);
+	u32 readval;
+
+	info->misc_ctrl_value |= BIT30;
+	*MiscCtrl = info->misc_ctrl_value;
+
+	/*
+	 * Force at least 170ns delay before clearing
+	 * reset bit. Each read from LCR takes at least
+	 * 30ns so 10 times for 300ns to be safe.
+	 */
+	for(i=0;i<10;i++)
+		readval = *MiscCtrl;
+
+	info->misc_ctrl_value &= ~BIT30;
+	*MiscCtrl = info->misc_ctrl_value;
+
+	/* init control reg (all DTRs off, all clksel=input) */
+	info->ctrlreg_value = 0xaa;
+	write_control_reg(info);
+
+	{
+		volatile u32 *LCR1BRDR = (u32 *)(info->lcr_base + 0x2c);
+		lcr1_brdr_value &= ~(BIT5 + BIT4 + BIT3);
+
+		switch(read_ahead_count)
+		{
+		case 16:
+			lcr1_brdr_value |= BIT5 + BIT4 + BIT3;
+			break;
+		case 8:
+			lcr1_brdr_value |= BIT5 + BIT4;
+			break;
+		case 4:
+			lcr1_brdr_value |= BIT5 + BIT3;
+			break;
+		case 0:
+			lcr1_brdr_value |= BIT5;
+			break;
+		}
+
+		*LCR1BRDR = lcr1_brdr_value;
+		*MiscCtrl = misc_ctrl_value;
+	}
+
+	sca_init(info->port_array[0]);
+	sca_init(info->port_array[2]);
+
+	return TRUE;
+}
+
+/* Loopback an HDLC frame to test the hardware
+ * interrupt and DMA functions.
+ */
+int loopback_test(SLMP_INFO *info)
+{
+#define TESTFRAMESIZE 20
+
+	unsigned long timeout;
+	u16 count = TESTFRAMESIZE;
+	unsigned char buf[TESTFRAMESIZE];
+	int rc = FALSE;
+	unsigned long flags;
+
+	struct tty_struct *oldtty = info->tty;
+	u32 speed = info->params.clock_speed;
+
+	info->params.clock_speed = 3686400;
+	info->tty = 0;
+
+	/* assume failure */
+	info->init_error = DiagStatus_DmaFailure;
+
+	/* build and send transmit frame */
+	for (count = 0; count < TESTFRAMESIZE;++count)
+		buf[count] = (unsigned char)count;
+
+	memset(info->tmp_rx_buf,0,TESTFRAMESIZE);
+
+	/* program hardware for HDLC and enabled receiver */
+	spin_lock_irqsave(&info->lock,flags);
+	hdlc_mode(info);
+	enable_loopback(info,1);
+       	rx_start(info);
+	info->tx_count = count;
+	tx_load_dma_buffer(info,buf,count);
+	tx_start(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	/* wait for receive complete */
+	/* Set a timeout for waiting for interrupt. */
+	for ( timeout = 100; timeout; --timeout ) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(jiffies_from_ms(10));
+
+		if (rx_get_frame(info)) {
+			rc = TRUE;
+			break;
+		}
+	}
+
+	/* verify received frame length and contents */
+	if (rc == TRUE &&
+		( info->tmp_rx_buf_count != count ||
+		  memcmp(buf, info->tmp_rx_buf,count))) {
+		rc = FALSE;
+	}
+
+	spin_lock_irqsave(&info->lock,flags);
+	reset_adapter(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	info->params.clock_speed = speed;
+	info->tty = oldtty;
+
+	return rc;
+}
+
+/* Perform diagnostics on hardware
+ */
+int adapter_test( SLMP_INFO *info )
+{
+	unsigned long flags;
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk( "%s(%d):Testing device %s\n",
+			__FILE__,__LINE__,info->device_name );
+
+	spin_lock_irqsave(&info->lock,flags);
+	init_adapter(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	info->port_array[0]->port_count = 0;
+
+	if ( register_test(info->port_array[0]) &&
+		register_test(info->port_array[1])) {
+
+		info->port_array[0]->port_count = 2;
+
+		if ( register_test(info->port_array[2]) &&
+			register_test(info->port_array[3]) )
+			info->port_array[0]->port_count += 2;
+	}
+	else {
+		printk( "%s(%d):Register test failure for device %s Addr=%08lX\n",
+			__FILE__,__LINE__,info->device_name, (unsigned long)(info->phys_sca_base));
+		return -ENODEV;
+	}
+
+	if ( !irq_test(info->port_array[0]) ||
+		!irq_test(info->port_array[1]) ||
+		 (info->port_count == 4 && !irq_test(info->port_array[2])) ||
+		 (info->port_count == 4 && !irq_test(info->port_array[3]))) {
+		printk( "%s(%d):Interrupt test failure for device %s IRQ=%d\n",
+			__FILE__,__LINE__,info->device_name, (unsigned short)(info->irq_level) );
+		return -ENODEV;
+	}
+
+	if (!loopback_test(info->port_array[0]) ||
+		!loopback_test(info->port_array[1]) ||
+		 (info->port_count == 4 && !loopback_test(info->port_array[2])) ||
+		 (info->port_count == 4 && !loopback_test(info->port_array[3]))) {
+		printk( "%s(%d):DMA test failure for device %s\n",
+			__FILE__,__LINE__,info->device_name);
+		return -ENODEV;
+	}
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk( "%s(%d):device %s passed diagnostics\n",
+			__FILE__,__LINE__,info->device_name );
+
+	info->port_array[0]->init_error = 0;
+	info->port_array[1]->init_error = 0;
+	if ( info->port_count > 2 ) {
+		info->port_array[2]->init_error = 0;
+		info->port_array[3]->init_error = 0;
+	}
+
+	return 0;
+}
+
+/* Test the shared memory on a PCI adapter.
+ */
+int memory_test(SLMP_INFO *info)
+{
+	static unsigned long testval[] = { 0x0, 0x55555555, 0xaaaaaaaa,
+		0x66666666, 0x99999999, 0xffffffff, 0x12345678 };
+	unsigned long count = sizeof(testval)/sizeof(unsigned long);
+	unsigned long i;
+	unsigned long limit = SCA_MEM_SIZE/sizeof(unsigned long);
+	unsigned long * addr = (unsigned long *)info->memory_base;
+
+	/* Test data lines with test pattern at one location. */
+
+	for ( i = 0 ; i < count ; i++ ) {
+		*addr = testval[i];
+		if ( *addr != testval[i] )
+			return FALSE;
+	}
+
+	/* Test address lines with incrementing pattern over */
+	/* entire address range. */
+
+	for ( i = 0 ; i < limit ; i++ ) {
+		*addr = i * 4;
+		addr++;
+	}
+
+	addr = (unsigned long *)info->memory_base;
+
+	for ( i = 0 ; i < limit ; i++ ) {
+		if ( *addr != i * 4 )
+			return FALSE;
+		addr++;
+	}
+
+	memset( info->memory_base, 0, SCA_MEM_SIZE );
+	return TRUE;
+}
+
+/* Load data into PCI adapter shared memory.
+ *
+ * The PCI9050 releases control of the local bus
+ * after completing the current read or write operation.
+ *
+ * While the PCI9050 write FIFO not empty, the
+ * PCI9050 treats all of the writes as a single transaction
+ * and does not release the bus. This causes DMA latency problems
+ * at high speeds when copying large data blocks to the shared memory.
+ *
+ * This function breaks a write into multiple transations by
+ * interleaving a read which flushes the write FIFO and 'completes'
+ * the write transation. This allows any pending DMA request to gain control
+ * of the local bus in a timely fasion.
+ */
+void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count)
+{
+	/* A load interval of 16 allows for 4 32-bit writes at */
+	/* 136ns each for a maximum latency of 542ns on the local bus.*/
+
+	unsigned short interval = count / sca_pci_load_interval;
+	unsigned short i;
+
+	for ( i = 0 ; i < interval ; i++ )
+	{
+		memcpy(dest, src, sca_pci_load_interval);
+		read_status_reg(info);
+		dest += sca_pci_load_interval;
+		src += sca_pci_load_interval;
+	}
+
+	memcpy(dest, src, count % sca_pci_load_interval);
+}
+
+void trace_block(SLMP_INFO *info,const char* data, int count, int xmit)
+{
+	int i;
+	int linecount;
+	if (xmit)
+		printk("%s tx data:\n",info->device_name);
+	else
+		printk("%s rx data:\n",info->device_name);
+
+	while(count) {
+		if (count > 16)
+			linecount = 16;
+		else
+			linecount = count;
+
+		for(i=0;i<linecount;i++)
+			printk("%02X ",(unsigned char)data[i]);
+		for(;i<17;i++)
+			printk("   ");
+		for(i=0;i<linecount;i++) {
+			if (data[i]>=040 && data[i]<=0176)
+				printk("%c",data[i]);
+			else
+				printk(".");
+		}
+		printk("\n");
+
+		data  += linecount;
+		count -= linecount;
+	}
+}	/* end of trace_block() */
+
+/* called when HDLC frame times out
+ * update stats and do tx completion processing
+ */
+void tx_timeout(unsigned long context)
+{
+	SLMP_INFO *info = (SLMP_INFO*)context;
+	unsigned long flags;
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk( "%s(%d):%s tx_timeout()\n",
+			__FILE__,__LINE__,info->device_name);
+	if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) {
+		info->icount.txtimeout++;
+	}
+	spin_lock_irqsave(&info->lock,flags);
+	info->tx_active = 0;
+	info->tx_count = info->tx_put = info->tx_get = 0;
+
+	spin_unlock_irqrestore(&info->lock,flags);
+
+#ifdef CONFIG_SYNCLINK_SYNCPPP
+	if (info->netcount)
+		sppp_tx_done(info);
+	else
+#endif
+		bh_transmit(info);
+}
+
+/* called to periodically check the DSR/RI modem signal input status
+ */
+void status_timeout(unsigned long context)
+{
+	u16 status = 0;
+	SLMP_INFO *info = (SLMP_INFO*)context;
+	unsigned long flags;
+	unsigned char delta;
+
+
+	spin_lock_irqsave(&info->lock,flags);
+	get_signals(info);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	/* check for DSR/RI state change */
+
+	delta = info->old_signals ^ info->serial_signals;
+	info->old_signals = info->serial_signals;
+
+	if (delta & SerialSignal_DSR)
+		status |= MISCSTATUS_DSR_LATCHED|(info->serial_signals&SerialSignal_DSR);
+
+	if (delta & SerialSignal_RI)
+		status |= MISCSTATUS_RI_LATCHED|(info->serial_signals&SerialSignal_RI);
+
+	if (delta & SerialSignal_DCD)
+		status |= MISCSTATUS_DCD_LATCHED|(info->serial_signals&SerialSignal_DCD);
+
+	if (delta & SerialSignal_CTS)
+		status |= MISCSTATUS_CTS_LATCHED|(info->serial_signals&SerialSignal_CTS);
+
+	if (status)
+		isr_io_pin(info,status);
+
+	info->status_timer.data = (unsigned long)info;
+	info->status_timer.function = status_timeout;
+	info->status_timer.expires = jiffies + jiffies_from_ms(10);
+	add_timer(&info->status_timer);
+}
+
+
+/* Register Access Routines -
+ * All registers are memory mapped
+ */
+#define CALC_REGADDR() \
+	unsigned char * RegAddr = (unsigned char*)(info->sca_base + Addr); \
+	if (info->port_num > 1) \
+		RegAddr += 256;	    		/* port 0-1 SCA0, 2-3 SCA1 */ \
+	if ( info->port_num & 1) { \
+		if (Addr > 0x7f) \
+			RegAddr += 0x40;	/* DMA access */ \
+		else if (Addr > 0x1f && Addr < 0x60) \
+			RegAddr += 0x20;	/* MSCI access */ \
+	}
+
+
+unsigned char read_reg(SLMP_INFO * info, unsigned char Addr)
+{
+	CALC_REGADDR();
+	return *RegAddr;
+}
+void write_reg(SLMP_INFO * info, unsigned char Addr, unsigned char Value)
+{
+	CALC_REGADDR();
+	*RegAddr = Value;
+}
+
+u16 read_reg16(SLMP_INFO * info, unsigned char Addr)
+{
+	CALC_REGADDR();
+	return *((u16 *)RegAddr);
+}
+
+void write_reg16(SLMP_INFO * info, unsigned char Addr, u16 Value)
+{
+	CALC_REGADDR();
+	*((u16 *)RegAddr) = Value;
+}
+
+unsigned char read_status_reg(SLMP_INFO * info)
+{
+	unsigned char *RegAddr = (unsigned char *)info->statctrl_base;
+	return *RegAddr;
+}
+
+void write_control_reg(SLMP_INFO * info)
+{
+	unsigned char *RegAddr = (unsigned char *)info->statctrl_base;
+	*RegAddr = info->port_array[0]->ctrlreg_value;
+}
+
+
+static int __devinit synclinkmp_init_one (struct pci_dev *dev,
+				          const struct pci_device_id *ent)
+{
+	if (pci_enable_device(dev)) {
+		printk("error enabling pci device %p\n", dev);
+		return -EIO;
+	}
+	device_init( ++synclinkmp_adapter_count, dev );
+	return 0;
+}
+
+static void __devexit synclinkmp_remove_one (struct pci_dev *dev)
+{
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/toshiba.c linux-2.4.20/drivers/char/toshiba.c
--- linux-2.4.19/drivers/char/toshiba.c	2001-10-11 16:04:57.000000000 +0000
+++ linux-2.4.20/drivers/char/toshiba.c	2002-10-29 11:18:38.000000000 +0000
@@ -84,8 +84,6 @@
 
 MODULE_PARM(tosh_fn, "i");
 
-MODULE_LICENSE("GPL");
-
 
 static int tosh_get_info(char *, char **, off_t, int);
 static int tosh_ioctl(struct inode *, struct file *, unsigned int,
@@ -524,3 +522,10 @@
 	misc_deregister(&tosh_device);
 }
 #endif
+
+MODULE_LICENSE("GPL");
+MODULE_PARM_DESC(tosh_fn, "User specified Fn key detection port");
+MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>");
+MODULE_DESCRIPTION("Toshiba laptop SMM driver");
+MODULE_SUPPORTED_DEVICE("toshiba");
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/tpqic02.c linux-2.4.20/drivers/char/tpqic02.c
--- linux-2.4.19/drivers/char/tpqic02.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/tpqic02.c	2002-10-29 11:18:40.000000000 +0000
@@ -1815,7 +1815,6 @@
 static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count,
 			       loff_t * ppos)
 {
-	int err;
 	kdev_t dev = filp->f_dentry->d_inode->i_rdev;
 	unsigned short flags = filp->f_flags;
 	unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
@@ -2009,7 +2008,6 @@
 static ssize_t qic02_tape_write(struct file *filp, const char *buf,
 				size_t count, loff_t * ppos)
 {
-	int err;
 	kdev_t dev = filp->f_dentry->d_inode->i_rdev;
 	unsigned short flags = filp->f_flags;
 	unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/tty_io.c linux-2.4.20/drivers/char/tty_io.c
--- linux-2.4.19/drivers/char/tty_io.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/tty_io.c	2002-10-29 11:18:48.000000000 +0000
@@ -106,6 +106,8 @@
 extern void con_init_devfs (void);
 #endif
 
+extern void disable_early_printk(void);
+
 #define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
 #define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
 #define SYSCONS_DEV MKDEV(TTYAUX_MAJOR,1)
@@ -1659,6 +1661,21 @@
 	return 0;
 }
 
+static int tty_generic_brk(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	if (cmd == TCSBRK && arg) 
+	{
+		/* tcdrain case */
+		int retval = tty_check_change(tty);
+		if (retval)
+			return retval;
+		tty_wait_until_sent(tty, 0);
+		if (signal_pending(current))
+			return -EINTR;
+	}
+	return 0;
+}
+
 /*
  * Split this up, as gcc can choke on it otherwise..
  */
@@ -1692,11 +1709,12 @@
 		/* the driver doesn't support them. */
 		case TCSBRK:
 		case TCSBRKP:
-			if (!tty->driver.ioctl)
-				return 0;
-			retval = tty->driver.ioctl(tty, file, cmd, arg);
+			retval = -ENOIOCTLCMD;
+			if (tty->driver.ioctl)
+				retval = tty->driver.ioctl(tty, file, cmd, arg);
+			/* Not driver handled */
 			if (retval == -ENOIOCTLCMD)
-				retval = 0;
+				retval = tty_generic_brk(tty, file, cmd, arg);
 			return retval;
 		}
 	}
@@ -2184,6 +2202,9 @@
 	 * set up the console device so that later boot sequences can 
 	 * inform about problems etc..
 	 */
+#ifdef CONFIG_EARLY_PRINTK
+	disable_early_printk(); 
+#endif
 #ifdef CONFIG_VT
 	con_init();
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/tty_ioctl.c linux-2.4.20/drivers/char/tty_ioctl.c
--- linux-2.4.19/drivers/char/tty_ioctl.c	2001-09-18 05:52:35.000000000 +0000
+++ linux-2.4.20/drivers/char/tty_ioctl.c	2002-10-29 11:18:40.000000000 +0000
@@ -394,7 +394,7 @@
 				return -EFAULT;
 			return 0;
 		case TCSETSF:
-			return set_termios(real_tty, arg,  TERMIOS_FLUSH);
+			return set_termios(real_tty, arg,  TERMIOS_FLUSH | TERMIOS_WAIT);
 		case TCSETSW:
 			return set_termios(real_tty, arg, TERMIOS_WAIT);
 		case TCSETS:
@@ -402,7 +402,7 @@
 		case TCGETA:
 			return get_termio(real_tty,(struct termio *) arg);
 		case TCSETAF:
-			return set_termios(real_tty, arg, TERMIOS_FLUSH | TERMIOS_TERMIO);
+			return set_termios(real_tty, arg, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
 		case TCSETAW:
 			return set_termios(real_tty, arg, TERMIOS_WAIT | TERMIOS_TERMIO);
 		case TCSETA:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/vt.c linux-2.4.20/drivers/char/vt.c
--- linux-2.4.19/drivers/char/vt.c	2001-11-16 18:08:28.000000000 +0000
+++ linux-2.4.20/drivers/char/vt.c	2002-10-29 11:18:49.000000000 +0000
@@ -90,7 +90,7 @@
  * comments - KDMKTONE doesn't put the process to sleep.
  */
 
-#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \
+#if defined(__i386__) || defined(__alpha__) || defined(CONFIG_PPC_ISATIMER) \
     || (defined(__mips__) && defined(CONFIG_ISA)) \
     || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE)) \
     || defined(__x86_64__)
@@ -481,7 +481,7 @@
 		ucval = keyboard_type;
 		goto setchar;
 
-#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__)
+#if defined(CONFIG_X86)
 		/*
 		 * These cannot be implemented on any machine that implements
 		 * ioperm() in user level (such as Alpha PCs).
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/w83877f_wdt.c linux-2.4.20/drivers/char/w83877f_wdt.c
--- linux-2.4.19/drivers/char/w83877f_wdt.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/w83877f_wdt.c	2002-10-29 11:18:48.000000000 +0000
@@ -192,8 +192,13 @@
 
 		/* now scan */
 		for(ofs = 0; ofs != count; ofs++)
-			if(buf[ofs] == 'V')
+		{
+			char c;
+			if(get_user(c, buf + ofs))
+				return -EFAULT;
+			if(c == 'V')
 				wdt_expect_close = 1;
+		}
 
 		/* someone wrote to us, we should restart timer */
 		next_heartbeat = jiffies + WDT_HEARTBEAT;
@@ -246,7 +251,7 @@
 {
 	static struct watchdog_info ident=
 	{
-		0,
+		WDIOF_MAGICCLOSE,
 		1,
 		"W83877F"
 	};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/wafer5823wdt.c linux-2.4.20/drivers/char/wafer5823wdt.c
--- linux-2.4.19/drivers/char/wafer5823wdt.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/wafer5823wdt.c	2002-10-29 11:18:50.000000000 +0000
@@ -40,6 +40,7 @@
 
 static unsigned long wafwdt_is_open;
 static spinlock_t wafwdt_lock;
+static int expect_close = 0;
 
 /*
  *	You must set these - there is no sane way to probe for this board.
@@ -54,6 +55,16 @@
 #define WDT_STOP 0x843
 
 #define WD_TIMO 60		/* 1 minute */
+static int wd_margin = WD_TIMO;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
 static void wafwdt_ping(void)
 {
@@ -67,7 +78,7 @@
 static void wafwdt_start(void)
 {
 	/* start up watchdog */
-	outb_p(WD_TIMO, WDT_START);
+	outb_p(wd_margin, WDT_START);
 	inb_p(WDT_START);
 }
 
@@ -85,6 +96,20 @@
 		return -ESPIPE;
 
 	if (count) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
 		wafwdt_ping();
 		return 1;
 	}
@@ -94,8 +119,12 @@
 static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 	     unsigned long arg)
 {
+	int new_margin;
 	static struct watchdog_info ident = {
-		WDIOF_KEEPALIVEPING, 1, "Wafer 5823 WDT"
+		WDIOF_KEEPALIVEPING |
+		WDIOF_SETTIMEOUT |
+		WDIOF_MAGICCLOSE,
+		1, "Wafer 5823 WDT"
 	};
 	int one=1;
 
@@ -115,6 +144,18 @@
 		wafwdt_ping();
 		break;
 
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_margin, (int *)arg))
+			return -EFAULT;
+		if ((new_margin < 1) || (new_margin > 255))
+			return -EINVAL;
+		wd_margin = new_margin;
+		wafwdt_stop();
+		wafwdt_start();
+		/* Fall */
+	case WDIOC_GETTIMEOUT:
+		return put_user(wd_margin, (int *)arg);
+
 	default:
 		return -ENOTTY;
 	}
@@ -133,9 +174,11 @@
 wafwdt_close(struct inode *inode, struct file *file)
 {
 	clear_bit(0, &wafwdt_is_open);
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-        wafwdt_stop();
-#endif
+	if (expect_close) {
+        	wafwdt_stop();
+	} else {
+		printk(KERN_CRIT "WDT device closed unexpectedly.  WDT will not stop!\n");
+	}
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/wdt.c linux-2.4.20/drivers/char/wdt.c
--- linux-2.4.19/drivers/char/wdt.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/wdt.c	2002-10-29 11:18:48.000000000 +0000
@@ -28,6 +28,7 @@
  *					Parameterized timeout
  *		Tigran Aivazian	:	Restructured wdt_init() to handle failures
  *		Joel Becker	:	Added WDIOC_GET/SETTIMEOUT
+ *		Matt Domsch	:	Added nowayout module option
  */
 
 #include <linux/config.h>
@@ -52,6 +53,7 @@
 #include <linux/init.h>
 
 static unsigned long wdt_is_open;
+static int expect_close;
 
 /*
  *	You must set these - there is no sane way to probe for this board.
@@ -66,6 +68,15 @@
 
 static int wd_margin = WD_TIMO;
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 #ifndef MODULE
 
 /**
@@ -243,6 +254,20 @@
 
 	if(count)
 	{
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
 		wdt_ping();
 		return 1;
 	}
@@ -304,7 +329,7 @@
 	{
 		WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER
 			|WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT
-			|WDIOF_SETTIMEOUT,
+			|WDIOF_SETTIMEOUT|WDIOF_MAGICCLOSE,
 		1,
 		"WDT500/501"
 	};
@@ -394,10 +419,12 @@
 {
 	if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
 	{
-#ifndef CONFIG_WATCHDOG_NOWAYOUT	
-		inb_p(WDT_DC);		/* Disable counters */
-		wdt_ctr_load(2,0);	/* 0 length reset pulses now */
-#endif		
+		if (expect_close) {
+			inb_p(WDT_DC);		/* Disable counters */
+			wdt_ctr_load(2,0);	/* 0 length reset pulses now */
+		} else {
+			printk(KERN_CRIT "wdt: WDT device closed unexpectedly.  WDT will not stop!\n");
+		}
 		clear_bit(0, &wdt_is_open);
 	}
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/wdt977.c linux-2.4.20/drivers/char/wdt977.c
--- linux-2.4.19/drivers/char/wdt977.c	2001-09-07 16:28:38.000000000 +0000
+++ linux-2.4.20/drivers/char/wdt977.c	2002-10-29 11:18:35.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *	Wdt977	0.01:	A Watchdog Device for Netwinder W83977AF chip
+ *	Wdt977	0.02:	A Watchdog Device for Netwinder W83977AF chip
  *
  *	(c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
  *
@@ -11,6 +11,8 @@
  *	2 of the License, or (at your option) any later version.
  *
  *			-----------------------
+ *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ *           Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  */
  
 #include <linux/module.h>
@@ -31,6 +33,17 @@
 static	int timeout = 3;
 static	int timer_alive;
 static	int testmode;
+static	int expect_close = 0;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 
 /*
  *	Allow only one person to hold it open
@@ -40,9 +53,9 @@
 {
 	if(timer_alive)
 		return -EBUSY;
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
-	MOD_INC_USE_COUNT;
-#endif
+	if (nowayout) {
+		MOD_INC_USE_COUNT;
+	}
 	timer_alive++;
 
 	//max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog.
@@ -89,50 +102,66 @@
 {
 	/*
 	 *	Shut off the timer.
-	 * 	Lock it in if it's a module and we defined ...NOWAYOUT
+	 * 	Lock it in if it's a module and we set nowayout
 	 */
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
 	lock_kernel();
+	if (expect_close) {
 
-	// unlock the SuperIO chip
-	outb(0x87,0x370); 
-	outb(0x87,0x370); 
-	
-	//select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
-	//F3 is reset to its default state
-	//F4 can clear the TIMEOUT'ed state (bit 0) - back to default
-	//We can not use GP17 as a PowerLed, as we use its usage as a RedLed
+		// unlock the SuperIO chip
+		outb(0x87,0x370); 
+		outb(0x87,0x370); 
+	
+		//select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
+		//F3 is reset to its default state
+		//F4 can clear the TIMEOUT'ed state (bit 0) - back to default
+		//We can not use GP17 as a PowerLed, as we use its usage as a RedLed
 	
-	outb(0x07,0x370);
-	outb(0x08,0x371);
-	outb(0xF2,0x370);
-	outb(0xFF,0x371);
-	outb(0xF3,0x370);
-	outb(0x00,0x371);
-	outb(0xF4,0x370);
-	outb(0x00,0x371);
-	outb(0xF2,0x370);
-	outb(0x00,0x371);
+		outb(0x07,0x370);
+		outb(0x08,0x371);
+		outb(0xF2,0x370);
+		outb(0xFF,0x371);
+		outb(0xF3,0x370);
+		outb(0x00,0x371);
+		outb(0xF4,0x370);
+		outb(0x00,0x371);
+		outb(0xF2,0x370);
+		outb(0x00,0x371);
 	
-	//at last select device Aux1 (dev=7) and set GP16 as a watchdog output
-	outb(0x07,0x370);
-	outb(0x07,0x371);
-	outb(0xE6,0x370);
-	outb(0x08,0x371);
+		//at last select device Aux1 (dev=7) and set GP16 as a watchdog output
+		outb(0x07,0x370);
+		outb(0x07,0x371);
+		outb(0xE6,0x370);
+		outb(0x08,0x371);
 	
-	// lock the SuperIO chip
-	outb(0xAA,0x370);
+		// lock the SuperIO chip
+		outb(0xAA,0x370);
+		printk(KERN_INFO "Watchdog: shutdown.\n");
+	} else {
+		printk(KERN_CRIT "WDT device closed unexpectedly.  WDT will not stop!\n");
+	}
 
 	timer_alive=0;
 	unlock_kernel();
 
-	printk(KERN_INFO "Watchdog: shutdown.\n");
-#endif
 	return 0;
 }
 
 static ssize_t wdt977_write(struct file *file, const char *data, size_t len, loff_t *ppos)
 {
+	if (!nowayout) {
+		size_t i;
+
+		/* In case it was set long ago */
+		expect_close = 0;
+
+		for (i = 0; i != len; i++) {
+			char c;
+			if (get_user(c, data + i))
+				return -EFAULT;
+			if (c == 'V')
+				expect_close = 1;
+		}
+	}
 
 	//max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog.
 	if (timeout>255)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/char/wdt_pci.c linux-2.4.20/drivers/char/wdt_pci.c
--- linux-2.4.19/drivers/char/wdt_pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/char/wdt_pci.c	2002-10-29 11:18:48.000000000 +0000
@@ -32,6 +32,7 @@
  *		Tigran Aivazian	:	Restructured wdtpci_init_one() to handle failures
  *		Joel Becker	:	Added WDIOC_GET/SETTIMEOUT
  *		Zwane Mwaikambo :	Magic char closing, locking changes, cleanups
+ *		Matt Domsch	:	nowayout module option
  */
 
 #include <linux/config.h>
@@ -87,6 +88,15 @@
 
 static int wd_margin = WD_TIMO;
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 /*
  *	Programming support
  */
@@ -231,16 +241,19 @@
 		return -ESPIPE;
 
 	if (count) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-		size_t i;
+		if (!nowayout) {
+			size_t i;
 
-		expect_close = 0;
+			expect_close = 0;
 
-		for (i = 0; i != count; i++) {
-			if (buf[i] == 'V')
-				expect_close = 1;
+			for (i = 0; i != count; i++) {
+				char c;
+				if(get_user(c, buf+i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
 		}
-#endif
 		wdtpci_ping();
 	}
 
@@ -301,7 +314,7 @@
 	{
 		WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER
 			|WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT
-			|WDIOF_SETTIMEOUT,
+			|WDIOF_SETTIMEOUT|WDIOF_MAGICCLOSE,
 		1,
 		"WDT500/501PCI"
 	};
@@ -355,12 +368,12 @@
 	switch(MINOR(inode->i_rdev))
 	{
 		case WATCHDOG_MINOR:
-			 if (down_trylock(&open_sem))
-                        	return -EBUSY;
+			if (down_trylock(&open_sem))
+				return -EBUSY;
 
-#ifdef CONFIG_WATCHDOG_NOWAYOUT	
-			MOD_INC_USE_COUNT;
-#endif
+			if (nowayout) {
+				MOD_INC_USE_COUNT;
+			}
 			/*
 			 *	Activate 
 			 */
@@ -415,7 +428,6 @@
 {
 
 	if (MINOR(inode->i_rdev)==WATCHDOG_MINOR) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
 		unsigned long flags;
 		if (expect_close) {
 			spin_lock_irqsave(&wdtpci_lock, flags);
@@ -426,7 +438,6 @@
 			printk(KERN_CRIT PFX "Unexpected close, not stopping timer!");
 			wdtpci_ping();
 		}
-#endif		
 		up(&open_sem);
 	}
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/dio/Makefile linux-2.4.20/drivers/dio/Makefile
--- linux-2.4.19/drivers/dio/Makefile	1998-06-13 20:14:31.000000000 +0000
+++ linux-2.4.20/drivers/dio/Makefile	2002-10-29 11:18:35.000000000 +0000
@@ -13,7 +13,8 @@
 MOD_SUB_DIRS := $(SUB_DIRS)
 ALL_SUB_DIRS := $(SUB_DIRS)
 
-L_OBJS   := dio.o
 L_TARGET := dio.a
 
+obj-$(CONFIG_DIO)   += dio.o
+
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/dio/dio.c linux-2.4.20/drivers/dio/dio.c
--- linux-2.4.19/drivers/dio/dio.c	2001-02-09 19:30:23.000000000 +0000
+++ linux-2.4.20/drivers/dio/dio.c	2002-10-29 11:18:34.000000000 +0000
@@ -31,7 +31,7 @@
 #include <linux/slab.h>                         /* kmalloc() */
 #include <linux/init.h>
 #include <asm/hwtest.h>                           /* hwreg_present() */
-#include <asm/io.h>                               /* readb() */
+#include <asm/io.h>
 /* not a real config option yet! */
 #define CONFIG_DIO_CONSTANTS
 
@@ -115,8 +115,14 @@
 static int __init dio_find_slow(int deviceid)
 {
 	/* Called to find a DIO device before the full bus scan has run.  Basically
-	   only used by the console driver.  */
+         * only used by the console driver.
+         * We don't do the primary+secondary ID encoding thing here. Maybe we should.
+         * (that would break the topcat detection, though. I need to think about
+         * the whole primary/secondary ID thing.)
+         */
 	int scode;
+        u_char prid;
+
 	for (scode = 0; scode < DIO_SCMAX; scode++)
 	{
 		void *va;
@@ -128,12 +134,23 @@
                 if (!va || !hwreg_present(va + DIO_IDOFF))
                         continue;             /* no board present at that select code */
 
-		if (DIO_ID(va) == deviceid)
+                /* We aren't very likely to want to use this to get at the IHPIB,
+                 * but maybe it's returning the same ID as the card we do want...
+                 */
+                if (!DIO_ISIHPIB(scode))
+                        prid = DIO_ID(va);
+                else
+                        prid = DIO_ID_IHPIB;
+
+		if (prid == deviceid)
 			return scode;
 	}
 	return 0;
 }
 
+/* Aargh: we use 0 for an error return code, but select code 0 exists!
+ * FIXME (trivial, use -1, but requires changes to all the drivers :-< )
+ */
 int dio_find(int deviceid)
 {
 	if (blist) 
@@ -193,10 +210,10 @@
                 b->scode = scode;
                 b->ipl = DIO_IPL(va);
                 b->name = dio_getname(b->id);
-                printk("select code %3d: ID %02X", scode, prid);
+                printk("select code %3d: ipl %d: ID %02X", scode, b->ipl, prid);
                 if (DIO_NEEDSSECID(b->id))
                         printk(":%02X", secid);
-                printk(" %s\n", b->name);
+                printk(": %s\n", b->name);
                 
                 b->next = NULL;
 
@@ -222,9 +239,9 @@
                 return 0;
         else if (DIO_SCINHOLE(scode))
                 return 0;
-        else if (scode == DIO_IHPIBSCODE) /* this should really be #ifdef CONFIG_IHPIB */
-                return (void*)DIO_IHPIBADDR;   /* or something similar... */
-        
+        else if (DIO_ISIHPIB(scode))
+                return (void*)DIO_IHPIBADDR;
+
         return (void*)(DIO_VIRADDRBASE + DIO_BASE + scode * 0x10000);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/fc4/Config.in linux-2.4.20/drivers/fc4/Config.in
--- linux-2.4.19/drivers/fc4/Config.in	1999-11-03 22:43:54.000000000 +0000
+++ linux-2.4.20/drivers/fc4/Config.in	2002-10-29 11:18:36.000000000 +0000
@@ -7,13 +7,13 @@
 tristate 'Fibre Channel and FC4 SCSI support' CONFIG_FC4
 if [ ! "$CONFIG_FC4" = "n" ]; then
    comment 'FC4 drivers'
-   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
       tristate 'Sun SOC/Sbus' CONFIG_FC4_SOC
       tristate 'Sun SOC+ (aka SOCAL)' CONFIG_FC4_SOCAL
    fi
    comment 'FC4 targets'
    dep_tristate 'SparcSTORAGE Array 100 and 200 series' CONFIG_SCSI_PLUTO $CONFIG_SCSI
-   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
       dep_tristate 'Sun Enterprise Network Array (A5000 and EX500)' CONFIG_SCSI_FCAL $CONFIG_SCSI
    else
       dep_tristate 'Generic FC-AL disk driver' CONFIG_SCSI_FCAL $CONFIG_SCSI
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/gsc/Makefile linux-2.4.20/drivers/gsc/Makefile
--- linux-2.4.19/drivers/gsc/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/gsc/Makefile	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,25 @@
+#
+# Makefile for most of the non-PCI devices in PA-RISC machines
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now inherited from the
+# parent makefile.
+#
+
+O_TARGET := gscbus.o
+
+obj-y := gsc.o
+obj-m :=
+obj-n :=
+obj-  :=
+
+obj-$(CONFIG_GSC_DINO) += dino.o
+obj-$(CONFIG_GSC_LASI) += lasi.o asp.o
+obj-$(CONFIG_GSC_WAX) += wax.o
+obj-$(CONFIG_SERIAL_GSC) += serial.o
+obj-$(CONFIG_EISA) += eisa.o eisa_enumerator.o eisa_eeprom.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/gsc/README.dino linux-2.4.20/drivers/gsc/README.dino
--- linux-2.4.19/drivers/gsc/README.dino	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/gsc/README.dino	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,28 @@
+/*
+** HP VISUALIZE Workstation PCI Bus Defect
+**
+** "HP has discovered a potential system defect that can affect
+** the behavior of five models of HP VISUALIZE workstations when
+** equipped with third-party or customer-installed PCI I/O expansion
+** cards. The defect is limited to the HP C180, C160, C160L, B160L,
+** and B132L VISUALIZE workstations, and will only be encountered
+** when data is transmitted through PCI I/O expansion cards on the
+** PCI bus. HP-supplied graphics cards that utilize the PCI bus are
+** not affected."
+**
+** REVISIT: "go/pci_defect" link below is stale.
+**	HP Internal can use <http://hpfcdma.fc.hp.com:80/Dino/>
+**
+**	Product		First Good Serial Number
+**  C200/C240 (US)	US67350000
+**B132L+/B180 (US)	US67390000
+**   C200 (Europe)	3713G01000
+**  B180L (Europe)	3720G01000
+**
+** Note that many boards were fixed/replaced under a free replacement
+** program. Assume a machine is only "suspect" until proven otherwise.
+**
+** "The pci_check program will also be available as application
+**  patch PHSS_12295"
+*/
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/gsc/asp.c linux-2.4.20/drivers/gsc/asp.c
--- linux-2.4.19/drivers/gsc/asp.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/gsc/asp.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,131 @@
+/*
+ *	ASP Device Driver
+ *
+ *	(c) Copyright 2000 The Puffin Group 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.
+ *
+ *	by Helge Deller <deller@gmx.de>
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <asm/gsc.h>
+#include <asm/led.h>
+
+#include "busdevice.h"
+
+#define ASP_GSC_IRQ	3		/* hardcoded interrupt for GSC */
+
+#define ASP_VER_OFFSET 	0x20		/* offset of ASP version */
+
+#define ASP_LED_ADDR	0xf0800020
+
+#define VIPER_INT_WORD  0xFFFBF088      /* addr of viper interrupt word */
+
+static int asp_choose_irq(struct parisc_device *dev)
+{
+	int irq = -1;
+
+	switch (dev->id.sversion) {
+	case 0x71:	irq = 22; break; /* SCSI */
+	case 0x72:	irq = 23; break; /* LAN */
+	case 0x73:	irq = 30; break; /* HIL */
+	case 0x74:	irq = 24; break; /* Centronics */
+	case 0x75:	irq = (dev->hw_path == 4) ? 26 : 25; break; /* RS232 */
+	case 0x76:	irq = 21; break; /* EISA BA */
+	case 0x77:	irq = 20; break; /* Graphics1 */
+	case 0x7a:	irq = 18; break; /* Audio (Bushmaster) */
+	case 0x7b:	irq = 18; break; /* Audio (Scorpio) */
+	case 0x7c:	irq = 28; break; /* FW SCSI */
+	case 0x7d:	irq = 27; break; /* FDDI */
+	case 0x7f:	irq = 18; break; /* Audio (Outfield) */
+	}
+	return irq;
+}
+
+/* There are two register ranges we're interested in.  Interrupt /
+ * Status / LED are at 0xf080xxxx and Asp special registers are at
+ * 0xf082fxxx.  PDC only tells us that Asp is at 0xf082f000, so for
+ * the purposes of interrupt handling, we have to tell other bits of
+ * the kernel to look at the other registers.
+ */
+#define ASP_INTERRUPT_ADDR 0xf0800000
+
+int __init
+asp_init_chip(struct parisc_device *dev)
+{
+	struct busdevice *asp;
+	struct gsc_irq gsc_irq;
+	int irq, ret;
+
+	asp = kmalloc(sizeof(struct busdevice), GFP_KERNEL);
+	if(!asp)
+		return -ENOMEM;
+
+	asp->version = gsc_readb(dev->hpa + ASP_VER_OFFSET) & 0xf;
+	asp->name = (asp->version == 1) ? "Asp" : "Cutoff";
+	asp->hpa = ASP_INTERRUPT_ADDR;
+
+	printk(KERN_INFO "%s version %d at 0x%lx found.\n", 
+		asp->name, asp->version, dev->hpa);
+
+	/* the IRQ ASP should use */
+	ret = -EBUSY;
+	irq = gsc_claim_irq(&gsc_irq, ASP_GSC_IRQ);
+	if (irq < 0) {
+		printk(KERN_ERR "%s(): cannot get GSC irq\n", __FUNCTION__);
+		goto out;
+	}
+
+	ret = request_irq(gsc_irq.irq, busdev_barked, 0, "asp", asp);
+	if (ret < 0)
+		goto out;
+
+	/* Save this for debugging later */
+	asp->parent_irq = gsc_irq.irq;
+	asp->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
+
+	/* Program VIPER to interrupt on the ASP irq */
+	gsc_writel((1 << (31 - ASP_GSC_IRQ)),VIPER_INT_WORD);
+
+	/* Done init'ing, register this driver */
+	ret = gsc_common_irqsetup(dev, asp);
+	if (ret)
+		goto out;
+
+	fixup_child_irqs(dev, asp->busdev_region->data.irqbase, asp_choose_irq);
+	/* Mongoose is a sibling of Asp, not a child... */
+	fixup_child_irqs(dev->parent, asp->busdev_region->data.irqbase,
+			asp_choose_irq);
+
+	/* initialize the chassis LEDs */ 
+#ifdef CONFIG_CHASSIS_LCD_LED	
+	register_led_driver(DISPLAY_MODEL_OLD_ASP, LED_CMD_REG_NONE, 
+		    (char *)ASP_LED_ADDR);
+#endif
+
+	return 0;
+
+out:
+	kfree(asp);
+	return ret;
+}
+
+static struct parisc_device_id asp_tbl[] = {
+	{ HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00070 },
+	{ 0, }
+};
+
+struct parisc_driver asp_driver = {
+	name:		"Asp",
+	id_table:	asp_tbl,
+	probe:		asp_init_chip,
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/gsc/busdevice.h linux-2.4.20/drivers/gsc/busdevice.h
--- linux-2.4.19/drivers/gsc/busdevice.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/gsc/busdevice.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,34 @@
+#ifndef BUSDEVICE_H
+#define BUSDEVICE_H
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <asm/hardware.h>
+#include <asm/gsc.h>
+
+#define OFFSET_IRR 0x0000   /* Interrupt request register */
+#define OFFSET_IMR 0x0004   /* Interrupt mask register */
+#define OFFSET_IPR 0x0008   /* Interrupt pending register */
+#define OFFSET_ICR 0x000C   /* Interrupt control register */
+#define OFFSET_IAR 0x0010   /* Interrupt address register */
+
+
+struct busdevice {
+	struct parisc_device *gsc;
+	unsigned long hpa;
+	char *name;
+	int version;
+	int type;
+	int parent_irq;
+	int eim;
+	struct irq_region *busdev_region;
+};
+
+/* short cut to keep the compiler happy */
+#define BUSDEV_DEV(x)	((struct busdevice *) (x))
+
+int gsc_common_irqsetup(struct parisc_device *parent, struct busdevice *busdev);
+
+void busdev_barked(int busdev_irq, void *dev, struct pt_regs *regs);
+
+#endif /* BUSDEVICE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/gsc/dino.c linux-2.4.20/drivers/gsc/dino.c
--- linux-2.4.19/drivers/gsc/dino.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/gsc/dino.c	2002-10-29 11:18:51.000000000 +0000
@@ -0,0 +1,931 @@
+/*
+**	DINO manager
+**
+**	(c) Copyright 1999 Red Hat Software
+**	(c) Copyright 1999 SuSE GmbH
+**	(c) Copyright 1999,2000 Hewlett-Packard Company
+**	(c) Copyright 2000 Grant Grundler
+**
+**	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 module provides access to Dino PCI bus (config/IOport spaces)
+**	and helps manage Dino IRQ lines.
+**
+**	Dino interrupt handling is a bit complicated.
+**	Dino always writes to the broadcast EIR via irr0 for now.
+**	(BIG WARNING: using broadcast EIR is a really bad thing for SMP!)
+**	Only one processor interrupt is used for the 11 IRQ line 
+**	inputs to dino.
+**
+**	The different between Built-in Dino and Card-Mode
+**	dino is in chip initialization and pci device initialization.
+**
+**	Linux drivers can only use Card-Mode Dino if pci devices I/O port
+**	BARs are configured and used by the driver. Programming MMIO address 
+**	requires substantial knowledge of available Host I/O address ranges
+**	is currently not supported.  Port/Config accessor functions are the
+**	same. "BIOS" differences are handled within the existing routines.
+*/
+
+/*	Changes :
+**	2001-06-14 : Clement Moyroud (moyroudc@esiee.fr)
+**		- added support for the integrated RS232. 	
+*/
+
+/*
+** TODO: create a virtual address for each Dino HPA.
+**       GSC code might be able to do this since IODC data tells us
+**       how many pages are used. PCI subsystem could (must?) do this
+**       for PCI drivers devices which implement/use MMIO registers.
+*/
+
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>	/* for struct irqaction */
+#include <linux/spinlock.h>	/* for spinlock_t and prototypes */
+
+#include <asm/pdc.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include <asm/irq.h>		/* for "gsc" irq functions */
+#include <asm/gsc.h>
+
+#undef DINO_DEBUG
+
+#ifdef DINO_DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/*
+** Config accessor functions only pass in the 8-bit bus number
+** and not the 8-bit "PCI Segment" number. Each Dino will be
+** assigned a PCI bus number based on "when" it's discovered.
+**
+** The "secondary" bus number is set to this before calling
+** pci_scan_bus(). If any PPB's are present, the scan will
+** discover them and update the "secondary" and "subordinate"
+** fields in Dino's pci_bus structure.
+**
+** Changes in the configuration *will* result in a different
+** bus number for each dino.
+*/
+
+#define is_card_dino(id) ((id)->hw_type == HPHW_A_DMA)
+
+#define DINO_IAR0		0x004
+#define DINO_IODC_ADDR		0x008
+#define DINO_IODC_DATA_0	0x008
+#define DINO_IODC_DATA_1	0x008
+#define DINO_IRR0		0x00C
+#define DINO_IAR1		0x010
+#define DINO_IRR1		0x014
+#define DINO_IMR		0x018
+#define DINO_IPR		0x01C
+#define DINO_TOC_ADDR		0x020
+#define DINO_ICR		0x024
+#define DINO_ILR		0x028
+#define DINO_IO_COMMAND		0x030
+#define DINO_IO_STATUS		0x034
+#define DINO_IO_CONTROL		0x038
+#define DINO_IO_GSC_ERR_RESP	0x040
+#define DINO_IO_ERR_INFO	0x044
+#define DINO_IO_PCI_ERR_RESP	0x048
+#define DINO_IO_FBB_EN		0x05c
+#define DINO_IO_ADDR_EN		0x060
+#define DINO_PCI_ADDR		0x064
+#define DINO_CONFIG_DATA	0x068
+#define DINO_IO_DATA		0x06c
+#define DINO_MEM_DATA		0x070	/* Dino 3.x only */
+#define DINO_GSC2X_CONFIG	0x7b4
+#define DINO_GMASK		0x800
+#define DINO_PAMR		0x804
+#define DINO_PAPR		0x808
+#define DINO_DAMODE		0x80c
+#define DINO_PCICMD		0x810
+#define DINO_PCISTS		0x814
+#define DINO_MLTIM		0x81c
+#define DINO_BRDG_FEAT		0x820
+#define DINO_PCIROR		0x824
+#define DINO_PCIWOR		0x828
+#define DINO_TLTIM		0x830
+
+#define DINO_IRQS 11		/* bits 0-10 are architected */
+#define DINO_IRR_MASK	0x5ff	/* only 10 bits are implemented */
+
+#define DINO_MASK_IRQ(x)	(1<<(x))
+
+#define PCIINTA   0x001
+#define PCIINTB   0x002
+#define PCIINTC   0x004
+#define PCIINTD   0x008
+#define PCIINTE   0x010
+#define PCIINTF   0x020
+#define GSCEXTINT 0x040
+/* #define xxx       0x080 - bit 7 is "default" */
+/* #define xxx    0x100 - bit 8 not used */
+/* #define xxx    0x200 - bit 9 not used */
+#define RS232INT  0x400
+
+struct dino_device
+{
+	struct pci_hba_data	hba;	/* 'C' inheritance - must be first */
+	spinlock_t		dinosaur_pen;
+	unsigned long		txn_addr; /* EIR addr to generate interrupt */ 
+	u32			txn_data; /* EIR data assign to each dino */ 
+	int			irq;      /* Virtual IRQ dino uses */
+	struct irq_region	*dino_region;  /* region for this Dino */
+
+	u32 			imr; /* IRQ's which are enabled */ 
+#ifdef DINO_DEBUG
+	unsigned int		dino_irr0; /* save most recent IRQ line stat */ 
+#endif
+};
+
+/* Looks nice and keeps the compiler happy */
+#define DINO_DEV(d) ((struct dino_device *) d)
+
+
+
+/***********************************************
+**
+** Dino Configuration Space Accessor Functions
+**
+************************************************/
+
+#define le8_to_cpu(x)	(x)
+#define cpu_to_le8(x)	(x)
+
+#define DINO_CFG_TOK(bus,dfn,pos) ((u32) ((bus)<<16 | (dfn)<<8 | (pos)))
+
+#define DINO_CFG_RD(type, size, mask) \
+static int dino_cfg_read##size (struct pci_dev *dev, int pos, u##size *data) \
+{ \
+	struct dino_device *d = DINO_DEV(dev->sysdata); \
+	u32 local_bus = (dev->bus->parent == NULL) ? 0 : dev->bus->secondary; \
+	u32 v = DINO_CFG_TOK(local_bus, dev->devfn, (pos&~3)); \
+	unsigned long flags; \
+	spin_lock_irqsave(&d->dinosaur_pen, flags); \
+	/* tell HW which CFG address */ \
+	gsc_writel(v, d->hba.base_addr + DINO_PCI_ADDR); \
+	/* generate cfg read cycle */ \
+	*data = le##size##_to_cpu(gsc_read##type(d->hba.base_addr+DINO_CONFIG_DATA+(pos&mask))); \
+	spin_unlock_irqrestore(&d->dinosaur_pen, flags); \
+	return 0; \
+}
+
+DINO_CFG_RD(b,  8, 3)
+DINO_CFG_RD(w, 16, 2)
+DINO_CFG_RD(l, 32, 0)
+
+
+/*
+** Dino address stepping "feature":
+** When address stepping, Dino attempts to drive the bus one cycle too soon
+** even though the type of cycle (config vs. MMIO) might be different. 
+** The read of Ven/Prod ID is harmless and avoids Dino's address stepping.
+*/
+#define DINO_CFG_WR(type, size, mask) \
+static int dino_cfg_write##size (struct pci_dev *dev, int pos, u##size data) \
+{ \
+	struct dino_device *d = DINO_DEV(dev->sysdata);	\
+	u32 local_bus = (dev->bus->parent == NULL) ? 0 : dev->bus->secondary; \
+	u32 v = DINO_CFG_TOK(local_bus, dev->devfn, (pos&~3)); \
+	unsigned long flags; \
+	spin_lock_irqsave(&d->dinosaur_pen, flags); \
+	/* avoid address stepping feature */ \
+	gsc_writel(v & 0xffffff00, d->hba.base_addr + DINO_PCI_ADDR); \
+	(volatile int) gsc_readl(d->hba.base_addr + DINO_CONFIG_DATA); \
+	/* tell HW which CFG address */ \
+	gsc_writel(v, d->hba.base_addr + DINO_PCI_ADDR); \
+	/* generate cfg read cycle */ \
+	gsc_write##type(cpu_to_le##size(data), d->hba.base_addr+DINO_CONFIG_DATA+(pos&mask)); \
+	spin_unlock_irqrestore(&d->dinosaur_pen, flags); \
+	return 0; \
+}
+
+DINO_CFG_WR(b,  8, 3)
+DINO_CFG_WR(w, 16, 2)
+DINO_CFG_WR(l, 32, 0)
+
+static struct pci_ops dino_cfg_ops = {
+	read_byte:	dino_cfg_read8,
+	read_word:	dino_cfg_read16,
+	read_dword:	dino_cfg_read32,
+	write_byte:	dino_cfg_write8,
+	write_word:	dino_cfg_write16,
+	write_dword:	dino_cfg_write32
+};
+
+
+
+/*******************************************************
+**
+** Dino "I/O Port" Space Accessor Functions
+**
+** Many PCI devices don't require use of I/O port space (eg Tulip,
+** NCR720) since they export the same registers to both MMIO and
+** I/O port space.  Performance is going to stink if drivers use
+** I/O port instead of MMIO.
+**
+********************************************************/
+
+
+#define DINO_PORT_IN(type, size, mask) \
+static u##size dino_in##size (struct pci_hba_data *d, u16 addr) \
+{ \
+	u##size v; \
+	unsigned long flags; \
+	spin_lock_irqsave(&(DINO_DEV(d)->dinosaur_pen), flags); \
+	/* tell HW which IO Port address */ \
+	gsc_writel((u32) addr & ~3, d->base_addr + DINO_PCI_ADDR); \
+	/* generate I/O PORT read cycle */ \
+	v = gsc_read##type(d->base_addr+DINO_IO_DATA+(addr&mask)); \
+	spin_unlock_irqrestore(&(DINO_DEV(d)->dinosaur_pen), flags); \
+	return le##size##_to_cpu(v); \
+}
+
+DINO_PORT_IN(b,  8, 3)
+DINO_PORT_IN(w, 16, 2)
+DINO_PORT_IN(l, 32, 0)
+
+#define DINO_PORT_OUT(type, size, mask) \
+static void dino_out##size (struct pci_hba_data *d, u16 addr, u##size val) \
+{ \
+	unsigned long flags; \
+	spin_lock_irqsave(&(DINO_DEV(d)->dinosaur_pen), flags); \
+	/* tell HW which CFG address */ \
+	gsc_writel((u32) addr, d->base_addr + DINO_PCI_ADDR); \
+	/* generate cfg write cycle */ \
+	gsc_write##type(cpu_to_le##size(val), d->base_addr+DINO_IO_DATA+(addr&mask)); \
+	spin_unlock_irqrestore(&(DINO_DEV(d)->dinosaur_pen), flags); \
+}
+
+DINO_PORT_OUT(b,  8, 3)
+DINO_PORT_OUT(w, 16, 2)
+DINO_PORT_OUT(l, 32, 0)
+
+struct pci_port_ops dino_port_ops = {
+	inb:	dino_in8,
+	inw:	dino_in16,
+	inl:	dino_in32,
+	outb:	dino_out8,
+	outw:	dino_out16,
+	outl:	dino_out32
+};
+
+static void
+dino_mask_irq(void *irq_dev, int irq)
+{
+	struct dino_device *dino_dev = DINO_DEV(irq_dev);
+
+	DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, irq_dev, irq);
+
+	if (NULL == irq_dev || irq > DINO_IRQS || irq < 0) {
+		printk(KERN_WARNING "%s(0x%lx, %d) - not a dino irq?\n",
+			__FUNCTION__, (long) irq_dev, irq);
+		BUG();
+	} else {
+		/*
+		** Clear the matching bit in the IMR register
+		*/
+		dino_dev->imr &= ~(DINO_MASK_IRQ(irq));
+		gsc_writel(dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR);
+	}
+}
+
+
+static void
+dino_unmask_irq(void *irq_dev, int irq)
+{
+	struct dino_device *dino_dev = DINO_DEV(irq_dev);
+	u32 tmp;
+
+	DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, irq_dev, irq);
+
+	if (NULL == irq_dev || irq > DINO_IRQS) {
+		printk(KERN_WARNING "%s(): %d not a dino irq?\n",
+				__FUNCTION__, irq);
+		BUG();
+		return;
+	}
+
+	/* set the matching bit in the IMR register */
+	dino_dev->imr |= DINO_MASK_IRQ(irq);          /* used in dino_isr() */
+	gsc_writel( dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR);
+
+	/* Emulate "Level Triggered" Interrupt
+	** Basically, a driver is blowing it if the IRQ line is asserted
+	** while the IRQ is disabled.  But tulip.c seems to do that....
+	** Give 'em a kluge award and a nice round of applause!
+	**
+	** The gsc_write will generate an interrupt which invokes dino_isr().
+	** dino_isr() will read IPR and find nothing. But then catch this
+	** when it also checks ILR.
+	*/
+	tmp = gsc_readl(dino_dev->hba.base_addr+DINO_ILR);
+	if (tmp & DINO_MASK_IRQ(irq)) {
+		DBG(KERN_WARNING "%s(): IRQ asserted! (ILR 0x%x)\n",
+				__FUNCTION__, tmp);
+		gsc_writel(dino_dev->txn_data, dino_dev->txn_addr);
+	}
+}
+
+
+
+static void
+dino_enable_irq(void *irq_dev, int irq)
+{
+	struct dino_device *dino_dev = DINO_DEV(irq_dev);
+
+	/*
+	** clear pending IRQ bits
+	**
+	** This does NOT change ILR state!
+	** See comments in dino_unmask_irq() for ILR usage.
+	*/
+	gsc_readl(dino_dev->hba.base_addr+DINO_IPR);
+
+	dino_unmask_irq(irq_dev, irq);
+}
+
+
+static struct irq_region_ops dino_irq_ops = {
+	disable_irq:	dino_mask_irq,	/* ??? */
+	enable_irq:	dino_enable_irq, 
+	mask_irq:	dino_mask_irq,
+	unmask_irq:	dino_unmask_irq
+};
+
+
+/*
+ * Handle a Processor interrupt generated by Dino.
+ *
+ * ilr_loop counter is a kluge to prevent a "stuck" IRQ line from
+ * wedging the CPU. Could be removed or made optional at some point.
+ */
+static void
+dino_isr(int irq, void *intr_dev, struct pt_regs *regs)
+{
+	struct dino_device *dino_dev = DINO_DEV(intr_dev);
+	u32 mask;
+	int ilr_loop = 100;
+	extern void do_irq(struct irqaction *a, int i, struct pt_regs *p);
+
+
+	/* read and acknowledge pending interrupts */
+#ifdef DINO_DEBUG
+	dino_dev->dino_irr0 =
+#endif
+	mask = gsc_readl(dino_dev->hba.base_addr+DINO_IRR0) & DINO_IRR_MASK;
+
+ilr_again:
+	while (mask)
+	{
+		int irq;
+
+		/*
+		 * Perform a binary search on set bits.
+		 * `Less than Fatal' and PS2 interupts aren't supported.
+		 */
+		if (mask & 0xf) {
+			if (mask & 0x3) {
+				irq = (mask & 0x1) ? 0 : 1; /* PCI INT A, B */
+			} else {
+				irq = (mask & 0x4) ? 2 : 3; /* PCI INT C, D */
+			}
+		} else {
+			if (mask & 0x30) {
+				irq = (mask & 0x10) ? 4 : 5; /* PCI INT E, F */
+			} else {
+				irq = (mask & 0x40) ? 6 : 10; /* GSC, RS232 */
+			}
+		}
+
+		mask &= ~(1<<irq);
+
+		DBG(KERN_WARNING "%s(%x, %p) mask %0x\n",
+			__FUNCTION__, irq, intr_dev, mask);
+		do_irq(&dino_dev->dino_region->action[irq],
+			dino_dev->dino_region->data.irqbase + irq,
+			regs);
+
+	}
+
+	/* Support for level triggered IRQ lines.
+	** 
+	** Dropping this support would make this routine *much* faster.
+	** But since PCI requires level triggered IRQ line to share lines...
+	** device drivers may assume lines are level triggered (and not
+	** edge triggered like EISA/ISA can be).
+	*/
+	mask = gsc_readl(dino_dev->hba.base_addr+DINO_ILR) & dino_dev->imr;
+	if (mask) {
+		if (--ilr_loop > 0)
+			goto ilr_again;
+		printk("Dino %lx: stuck interrupt %d\n", dino_dev->hba.base_addr, mask);
+	}
+}
+
+static int dino_choose_irq(struct parisc_device *dev)
+{
+	int irq = -1;
+
+	switch (dev->id.sversion) {
+		case 0x00084:	irq =  8; break; /* PS/2 */
+		case 0x0008c:	irq = 10; break; /* RS232 */
+		case 0x00096:	irq =  8; break; /* PS/2 */
+	}
+
+	return irq;
+}
+
+static void __init
+dino_bios_init(void)
+{
+	DBG("dino_bios_init\n");
+}
+
+/*
+ * dino_card_setup - Set up the memory space for a Dino in card mode.
+ * @bus: the bus under this dino
+ *
+ * Claim an 8MB chunk of unused IO space and call the generic PCI routines
+ * to set up the addresses of the devices on this bus.
+ */
+#define _8MB 0x00800000UL
+static void __init
+dino_card_setup(struct pci_bus *bus, unsigned long base_addr)
+{
+	int i;
+	struct dino_device *dino_dev = DINO_DEV(bus->sysdata);
+	struct resource *res;
+
+	res = &dino_dev->hba.lmmio_space;
+	res->flags = IORESOURCE_MEM;
+
+	if (ccio_allocate_resource(dino_dev->hba.dev, res, _8MB,
+				(unsigned long) 0xfffffffff0000000UL | _8MB,
+				0xffffffffffffffffUL &~ _8MB, _8MB,
+				NULL, NULL) < 0) {
+		printk(KERN_WARNING "Dino: Failed to allocate memory region\n");
+		return;
+	}
+	bus->resource[1] = res;
+	bus->resource[0] = &(dino_dev->hba.io_space);
+
+	/* Now tell dino what range it has */
+	for (i = 1; i < 31; i++) {
+		if (res->start == (0xfffffffff0000000UL | i * _8MB))
+			break;
+	}
+	gsc_writel(1 << i, base_addr + DINO_IO_ADDR_EN);
+
+	pcibios_assign_unassigned_resources(bus);
+}
+
+static void __init
+dino_card_fixup(struct pci_dev *dev)
+{
+	u8 irq_pin;
+
+	/*
+	** REVISIT: card-mode PCI-PCI expansion chassis do exist.
+	**         Not sure they were ever productized.
+	**         Die here since we'll die later in dino_inb() anyway.
+	*/
+	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+		panic("Card-Mode Dino: PCI-PCI Bridge not supported\n");
+	}
+
+	/*
+	** Set Latency Timer to 0xff (not a shared bus)
+	** Set CACHELINE_SIZE.
+	*/
+	dino_cfg_write16(dev, PCI_CACHE_LINE_SIZE, 0xff00 | L1_CACHE_BYTES/4); 
+
+	/*
+	** Program INT_LINE for card-mode devices.
+	** The cards are hardwired according to this algorithm.
+	** And it doesn't matter if PPB's are present or not since
+	** the IRQ lines bypass the PPB.
+	**
+	** "-1" converts INTA-D (1-4) to PCIINTA-D (0-3) range.
+	** The additional "-1" adjusts for skewing the IRQ<->slot.
+	*/
+	dino_cfg_read8(dev, PCI_INTERRUPT_PIN, &irq_pin); 
+	dev->irq = (irq_pin + PCI_SLOT(dev->devfn) - 1) % 4 ;
+
+	/* Shouldn't really need to do this but it's in case someone tries
+	** to bypass PCI services and look at the card themselves.
+	*/
+	dino_cfg_write8(dev, PCI_INTERRUPT_LINE, dev->irq); 
+}
+
+
+static void __init
+dino_fixup_bus(struct pci_bus *bus)
+{
+	struct list_head *ln;
+        struct pci_dev *dev;
+        struct dino_device *dino_dev = DINO_DEV(bus->sysdata);
+	int port_base = HBA_PORT_BASE(dino_dev->hba.hba_num);
+
+	DBG(KERN_WARNING "%s(0x%p) bus %d sysdata 0x%p\n",
+			__FUNCTION__, bus, bus->secondary, bus->sysdata);
+
+	/* Firmware doesn't set up card-mode dino, so we have to */
+	if (is_card_dino(&dino_dev->hba.dev->id))
+		dino_card_setup(bus, dino_dev->hba.base_addr);
+
+	/* If this is a PCI-PCI Bridge, read the window registers etc */
+	if (bus->self)
+		pci_read_bridge_bases(bus);
+
+	list_for_each(ln, &bus->devices) {
+		int i;
+
+		dev = pci_dev_b(ln);
+		if (is_card_dino(&dino_dev->hba.dev->id))
+			dino_card_fixup(dev);
+
+		/*
+		** P2PB's only have 2 BARs, no IRQs.
+		** I'd like to just ignore them for now.
+		*/
+		if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
+			continue;
+
+		/* Adjust the I/O Port space addresses */
+		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+			struct resource *res = &dev->resource[i];
+			if (res->flags & IORESOURCE_IO) {
+				res->start |= port_base;
+				res->end |= port_base;
+			}
+#ifdef __LP64__
+			/* Sign Extend MMIO addresses */
+			else if (res->flags & IORESOURCE_MEM) {
+				res->start |= 0xffffffff00000000UL;
+				res->end   |= 0xffffffff00000000UL;
+			}
+#endif
+		}
+
+		/* Adjust INT_LINE for that busses region */
+		dev->irq = dino_dev->dino_region->data.irqbase + dev->irq;
+	}
+}
+
+
+struct pci_bios_ops dino_bios_ops = {
+	dino_bios_init,
+	dino_fixup_bus	/* void dino_fixup_bus(struct pci_bus *bus) */
+};
+
+
+/*
+ *	Initialise a DINO controller chip
+ */
+static void __init
+dino_card_init(struct dino_device *dino_dev)
+{
+	u32 brdg_feat = 0x00784e05;
+
+	gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_GMASK);
+	gsc_writel(0x00000001, dino_dev->hba.base_addr+DINO_IO_FBB_EN);
+	gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_ICR);
+
+#if 1
+/* REVISIT - should be a runtime check (eg if (CPU_IS_PCX_L) ...) */
+	/*
+	** PCX-L processors don't support XQL like Dino wants it.
+	** PCX-L2 ignore XQL signal and it doesn't matter.
+	*/
+	brdg_feat &= ~0x4;	/* UXQL */
+#endif
+	gsc_writel( brdg_feat, dino_dev->hba.base_addr+DINO_BRDG_FEAT);
+
+	/*
+	** Don't enable address decoding until we know which I/O range
+	** currently is available from the host. Only affects MMIO
+	** and not I/O port space.
+	*/
+	gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_IO_ADDR_EN);
+
+	gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_DAMODE);
+	gsc_writel(0x00222222, dino_dev->hba.base_addr+DINO_PCIROR);
+	gsc_writel(0x00222222, dino_dev->hba.base_addr+DINO_PCIWOR);
+
+	gsc_writel(0x00000040, dino_dev->hba.base_addr+DINO_MLTIM);
+	gsc_writel(0x00000080, dino_dev->hba.base_addr+DINO_IO_CONTROL);
+	gsc_writel(0x0000008c, dino_dev->hba.base_addr+DINO_TLTIM);
+
+	/* Disable PAMR before writing PAPR */
+	gsc_writel(0x0000007e, dino_dev->hba.base_addr+DINO_PAMR);
+	gsc_writel(0x0000007f, dino_dev->hba.base_addr+DINO_PAPR);
+	gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_PAMR);
+
+	/*
+	** Dino ERS encourages enabling FBB (0x6f).
+	** We can't until we know *all* devices below us can support it.
+	** (Something in device configuration header tells us).
+	*/
+	gsc_writel(0x0000004f, dino_dev->hba.base_addr+DINO_PCICMD);
+
+	/* Somewhere, the PCI spec says give devices 1 second
+	** to recover from the #RESET being de-asserted.
+	** Experience shows most devices only need 10ms.
+	** This short-cut speeds up booting significantly.
+	*/
+	mdelay(pci_post_reset_delay);
+}
+
+static int __init
+dino_bridge_init(struct dino_device *dino_dev, const char *name)
+{
+	unsigned long io_addr, bpos;
+	int result;
+	struct resource *res;
+	/*
+	 * Decoding IO_ADDR_EN only works for Built-in Dino
+	 * since PDC has already initialized this.
+	 */
+
+	io_addr = gsc_readl(dino_dev->hba.base_addr + DINO_IO_ADDR_EN);
+	if (io_addr == 0) {
+		printk(KERN_WARNING "%s: No PCI devices enabled.\n", name);
+		return -ENODEV;
+	}
+
+	for (bpos = 0; (io_addr & (1 << bpos)) == 0; bpos++)
+		;
+
+	res = &dino_dev->hba.lmmio_space;
+	res->flags = IORESOURCE_MEM;
+
+	res->start = (unsigned long)(signed int)(0xf0000000 | (bpos << 23));
+	res->end = res->start + 8 * 1024 * 1024 - 1;
+
+	result = ccio_request_resource(dino_dev->hba.dev, res);
+	if (result < 0) {
+		printk(KERN_ERR "%s: failed to claim PCI Bus address space!\n", name);
+		return result;
+	}
+
+	return 0;
+}
+
+static int __init dino_common_init(struct parisc_device *dev,
+		struct dino_device *dino_dev, const char *name)
+{
+	int status;
+	u32 eim;
+	struct gsc_irq gsc_irq;
+	struct resource *res;
+
+	pcibios_register_hba(&dino_dev->hba);
+
+	pci_bios = &dino_bios_ops;   /* used by pci_scan_bus() */
+	pci_port = &dino_port_ops;
+
+	/*
+	** Note: SMP systems can make use of IRR1/IAR1 registers
+	**   But it won't buy much performance except in very
+	**   specific applications/configurations. Note Dino
+	**   still only has 11 IRQ input lines - just map some of them
+	**   to a different processor.
+	*/
+	dino_dev->irq = gsc_alloc_irq(&gsc_irq);
+	dino_dev->txn_addr = gsc_irq.txn_addr;
+	dino_dev->txn_data = gsc_irq.txn_data;
+	eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
+
+	/* 
+	** Dino needs a PA "IRQ" to get a processor's attention.
+	** arch/parisc/kernel/irq.c returns an EIRR bit.
+	*/
+	if (dino_dev->irq < 0) {
+		printk(KERN_WARNING "%s: gsc_alloc_irq() failed\n", name);
+		return 1;
+	}
+
+	status = request_irq(dino_dev->irq, dino_isr, 0, name, dino_dev);
+	if (status) {
+		printk(KERN_WARNING "%s: request_irq() failed with %d\n", 
+			name, status);
+		return 1;
+	}
+
+	/*
+	** Tell generic interrupt support we have 11 bits which need
+	** be checked in the interrupt handler.
+	*/
+	dino_dev->dino_region = alloc_irq_region(DINO_IRQS, &dino_irq_ops,
+						name, dino_dev);
+
+	if (NULL == dino_dev->dino_region) {
+		printk(KERN_WARNING "%s: alloc_irq_region() failed\n", name);
+		return 1;
+	}
+
+	/* Support the serial port which is sometimes attached on built-in
+	 * Dino / Cujo chips.
+	 */
+
+	fixup_child_irqs(dev, dino_dev->dino_region->data.irqbase,
+			dino_choose_irq);
+
+	/*
+	** This enables DINO to generate interrupts when it sees
+	** any of it's inputs *change*. Just asserting an IRQ
+	** before it's enabled (ie unmasked) isn't good enough.
+	*/
+	gsc_writel(eim, dino_dev->hba.base_addr+DINO_IAR0);
+
+	/*
+	** Some platforms don't clear Dino's IRR0 register at boot time.
+	** Reading will clear it now.
+	*/
+	gsc_readl(dino_dev->hba.base_addr+DINO_IRR0);
+
+	/* allocate I/O Port resource region */
+	res = &dino_dev->hba.io_space;
+	if (dev->id.hversion == 0x680 || is_card_dino(&dev->id)) {
+		res->name = "Dino I/O Port";
+	        dino_dev->hba.lmmio_space.name = "Dino LMMIO";
+	} else {
+		res->name = "Cujo I/O Port";
+	        dino_dev->hba.lmmio_space.name = "Cujo LMMIO";
+	}
+	res->start = HBA_PORT_BASE(dino_dev->hba.hba_num);
+	res->end = res->start + (HBA_PORT_SPACE_SIZE - 1);
+	res->flags = IORESOURCE_IO; /* do not mark it busy ! */
+	if (request_resource(&ioport_resource, res) < 0) {
+		printk(KERN_ERR "%s: request I/O Port region failed 0x%lx/%lx (hpa 0x%lx)\n",
+				name, res->start, res->end, dino_dev->hba.base_addr);
+		return 1;
+	}
+
+	return 0;
+}
+
+#define CUJO_RAVEN_ADDR		0xfffffffff1000000UL
+#define CUJO_FIREHAWK_ADDR	0xfffffffff1604000UL
+#define CUJO_RAVEN_BADPAGE	0x01003000UL
+#define CUJO_FIREHAWK_BADPAGE	0x01607000UL
+
+static const char *dino_vers[] = {
+	"2.0",
+	"2.1",
+	"3.0",
+	"3.1"
+};
+
+static const char *cujo_vers[] = {
+	"1.0",
+	"2.0"
+};
+
+void ccio_cujo20_fixup(struct parisc_device *dev, u32 iovp);
+
+/*
+** Determine if dino should claim this chip (return 0) or not (return 1).
+** If so, initialize the chip appropriately (card-mode vs bridge mode).
+** Much of the initialization is common though.
+*/
+static int __init
+dino_driver_callback(struct parisc_device *dev)
+{
+	struct dino_device *dino_dev;	// Dino specific control struct
+	const char *version = "unknown";
+	const char *name = "Dino";
+	int is_cujo = 0;
+
+	if (is_card_dino(&dev->id)) {
+		version = "3.x (card mode)";
+	} else {
+		if(dev->id.hversion == 0x680) {
+			if (dev->id.hversion_rev < 4) {
+				version = dino_vers[dev->id.hversion_rev];
+			}
+		} else {
+			name = "Cujo";
+			is_cujo = 1;
+			if (dev->id.hversion_rev < 2) {
+				version = cujo_vers[dev->id.hversion_rev];
+			}
+		}
+	}
+
+	printk("%s version %s found at 0x%lx\n", name, version, dev->hpa);
+
+	if (!request_mem_region(dev->hpa, PAGE_SIZE, name)) {
+		printk(KERN_ERR "DINO: Hey! Someone took my MMIO space (0x%ld)!\n",
+			dev->hpa);
+		return 1;
+	}
+
+	/* Check for bugs */
+	if (is_cujo && dev->id.hversion_rev == 1) {
+#ifdef CONFIG_IOMMU_CCIO
+		printk(KERN_WARNING "Enabling Cujo 2.0 bug workaround\n");
+		if (dev->hpa == CUJO_RAVEN_ADDR) {
+			ccio_cujo20_fixup(dev->parent, CUJO_RAVEN_BADPAGE);
+		} else if (dev->hpa == CUJO_FIREHAWK_ADDR) {
+			ccio_cujo20_fixup(dev->parent, CUJO_FIREHAWK_BADPAGE);
+		} else {
+			printk("Don't recognise Cujo at address 0x%lx, not enabling workaround\n", dev->hpa);
+		}
+#endif
+	} else if (!is_cujo && !is_card_dino(&dev->id) &&
+			dev->id.hversion_rev < 3) {
+		printk(KERN_WARNING
+"The GSCtoPCI (Dino hrev %d) bus converter found may exhibit\n"
+"data corruption.  See Service Note Numbers: A4190A-01, A4191A-01.\n"
+"Systems shipped after Aug 20, 1997 will not exhibit this problem.\n"
+"Models affected: C180, C160, C160L, B160L, and B132L workstations.\n\n",
+			dev->id.hversion_rev);
+/* REVISIT: why are C200/C240 listed in the README table but not
+**   "Models affected"? Could be an omission in the original literature.
+*/
+	}
+
+	dino_dev = kmalloc(sizeof(struct dino_device), GFP_KERNEL);
+	if (!dino_dev) {
+		printk("dino_init_chip - couldn't alloc dino_device\n");
+		return 1;
+	}
+
+	memset(dino_dev, 0, sizeof(struct dino_device));
+
+	dino_dev->hba.dev = dev;
+	dino_dev->hba.base_addr = dev->hpa;  /* faster access */
+	dino_dev->hba.lmmio_space_offset = 0;	/* CPU addrs == bus addrs */
+	dino_dev->dinosaur_pen = SPIN_LOCK_UNLOCKED;
+	dino_dev->hba.iommu = ccio_get_iommu(dev);
+
+	if (is_card_dino(&dev->id)) {
+		dino_card_init(dino_dev);
+	} else {
+		dino_bridge_init(dino_dev, name);
+	}
+
+	if (dino_common_init(dev, dino_dev, name))
+		return 1;
+
+	/*
+	** It's not used to avoid chicken/egg problems
+	** with configuration accessor functions.
+	*/
+	dino_dev->hba.hba_bus = pci_scan_bus(dino_dev->hba.hba_num,
+			&dino_cfg_ops, dino_dev);
+
+	return 0;
+}
+
+/*
+ * Normally, we would just test sversion.  But the Elroy PCI adapter has
+ * the same sversion as Dino, so we have to check hversion as well.
+ * Unfortunately, the J2240 PDC reports the wrong hversion for the first
+ * Dino, so we have to test for Dino, Cujo and Dino-in-a-J2240.
+ */
+static struct parisc_device_id dino_tbl[] = {
+	{ HPHW_A_DMA, HVERSION_REV_ANY_ID, 0x004, 0x0009D }, /* Card-mode Dino. */
+	{ HPHW_A_DMA, HVERSION_REV_ANY_ID, 0x444, 0x08080 }, /* Same card in a 715.  Bug? */
+	{ HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x680, 0xa }, /* Bridge-mode Dino */
+	{ HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x682, 0xa }, /* Bridge-mode Cujo */
+	{ HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x05d, 0xa }, /* Dino in a J2240 */
+	{ 0, }
+};
+
+static struct parisc_driver dino_driver = {
+	name:		"Dino",
+	id_table:	dino_tbl,
+	probe:		dino_driver_callback,
+};
+
+/*
+ * One time initialization to let the world know Dino is here.
+ * This is the only routine which is NOT static.
+ * Must be called exactly once before pci_init().
+ */
+int __init dino_init(void)
+{
+	register_parisc_driver(&dino_driver);
+	return 0;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/gsc/eisa.c linux-2.4.20/drivers/gsc/eisa.c
--- linux-2.4.19/drivers/gsc/eisa.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/gsc/eisa.c	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,454 @@
+/*
+ * eisa.c - provide support for EISA adapters in PA-RISC machines
+ *
+ * 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.
+ *
+ * Copyright (c) 2001 Matthew Wilcox for Hewlett Packard
+ * Copyright (c) 2001 Daniel Engstrom <5116@telia.com>
+ *
+ * There are two distinct EISA adapters.  Mongoose is found in machines
+ * before the 712; then the Wax ASIC is used.  To complicate matters, the
+ * Wax ASIC also includes a PS/2 and RS-232 controller, but those are
+ * dealt with elsewhere; this file is concerned only with the EISA portions
+ * of Wax.
+ * 
+ * 
+ * HINT:
+ * -----
+ * To allow an ISA card to work properly in the EISA slot you need to
+ * set an edge trigger level. This may be done on the palo command line 
+ * by adding the kernel parameter "eisa_irq_edge=n,n2,[...]]", with 
+ * n and n2 as the irq levels you want to use.
+ * 
+ * Example: "eisa_irq_edge=10,11" allows ISA cards to operate at 
+ * irq levels 10 and 11.
+ */
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+
+#include <asm/byteorder.h>
+#include <asm/gsc.h>
+#include <asm/hardware.h>
+#include <asm/processor.h>
+#include <asm/delay.h>
+#include <asm/eisa_bus.h>
+
+#if 0
+#define EISA_DBG(msg, arg... ) printk(KERN_DEBUG "eisa: " msg , ## arg )
+#else
+#define EISA_DBG(msg, arg... )  
+#endif
+
+#define SNAKES_EEPROM_BASE_ADDR 0xF0810400
+#define MIRAGE_EEPROM_BASE_ADDR 0xF00C0400
+
+static spinlock_t eisa_irq_lock = SPIN_LOCK_UNLOCKED;
+
+/* We can only have one EISA adapter in the system because neither
+ * implementation can be flexed.
+ */
+static struct eisa_ba {
+	struct pci_hba_data	hba;
+	unsigned long eeprom_addr;
+} eisa_dev;
+
+/* Port ops */
+
+static inline unsigned long eisa_permute(unsigned short port)
+{
+	if (port & 0x300) {
+		return 0xfc000000 | ((port & 0xfc00) >> 6)
+			| ((port & 0x3f8) << 9) | (port & 7);
+	} else {
+		return 0xfc000000 | port;
+	}
+}
+
+unsigned char eisa_in8(unsigned short port)
+{
+	if (EISA_bus)
+		return gsc_readb(eisa_permute(port));
+	return 0xff;
+}
+
+unsigned short eisa_in16(unsigned short port)
+{
+	if (EISA_bus)
+		return le16_to_cpu(gsc_readw(eisa_permute(port)));
+	return 0xffff;
+}
+
+unsigned int eisa_in32(unsigned short port)
+{
+	if (EISA_bus)
+		return le32_to_cpu(gsc_readl(eisa_permute(port)));
+	return 0xffffffff;
+}
+
+void eisa_out8(unsigned char data, unsigned short port)
+{
+	if (EISA_bus)
+		gsc_writeb(data, eisa_permute(port));
+}
+
+void eisa_out16(unsigned short data, unsigned short port)
+{
+	if (EISA_bus)	
+		gsc_writew(cpu_to_le16(data), eisa_permute(port));
+}
+
+void eisa_out32(unsigned int data, unsigned short port)
+{
+	if (EISA_bus)
+		gsc_writel(cpu_to_le32(data), eisa_permute(port));
+}
+
+/* Interrupt handling */
+
+/* cached interrupt mask registers */
+static int master_mask;
+static int slave_mask;
+
+/* the trig level can be set with the
+ * eisa_irq_edge=n,n,n commandline parameter 
+ * We should really read this from the EEPROM 
+ * in the furure. 
+ */
+/* irq 13,8,2,1,0 must be edge */
+static unsigned int eisa_irq_level; /* default to edge triggered */
+
+
+/* called by free irq */
+static void eisa_disable_irq(void *irq_dev, int irq)
+{
+	unsigned long flags;
+
+	EISA_DBG("disable irq %d\n", irq);
+	/* just mask for now */
+	spin_lock_irqsave(&eisa_irq_lock, flags);
+        if (irq & 8) {
+		slave_mask |= (1 << (irq&7));
+		eisa_out8(slave_mask, 0xa1);
+	} else {
+		master_mask |= (1 << (irq&7));
+		eisa_out8(master_mask, 0x21);
+	}
+	spin_unlock_irqrestore(&eisa_irq_lock, flags);
+	EISA_DBG("pic0 mask %02x\n", eisa_in8(0x21));
+	EISA_DBG("pic1 mask %02x\n", eisa_in8(0xa1));
+}
+
+/* called by request irq */
+static void eisa_enable_irq(void *irq_dev, int irq)
+{
+	unsigned long flags;
+	EISA_DBG("enable irq %d\n", irq);
+		
+	spin_lock_irqsave(&eisa_irq_lock, flags);
+        if (irq & 8) {
+		slave_mask &= ~(1 << (irq&7));
+		eisa_out8(slave_mask, 0xa1);
+	} else {
+		master_mask &= ~(1 << (irq&7));
+		eisa_out8(master_mask, 0x21);
+	}
+	spin_unlock_irqrestore(&eisa_irq_lock, flags);
+	EISA_DBG("pic0 mask %02x\n", eisa_in8(0x21));
+	EISA_DBG("pic1 mask %02x\n", eisa_in8(0xa1));
+}
+
+static void eisa_mask_irq(void *irq_dev, int irq)
+{
+	unsigned long flags;
+	EISA_DBG("mask irq %d\n", irq);
+	
+        /* mask irq */
+	spin_lock_irqsave(&eisa_irq_lock, flags);
+	if (irq & 8) {
+		slave_mask |= (1 << (irq&7));
+		eisa_out8(slave_mask, 0xa1);
+	} else {
+		master_mask |= (1 << (irq&7));
+		eisa_out8(master_mask, 0x21);
+	}
+	spin_unlock_irqrestore(&eisa_irq_lock, flags);
+}
+
+static void eisa_unmask_irq(void *irq_dev, int irq)
+{
+	unsigned long flags;
+	EISA_DBG("unmask irq %d\n", irq);
+        
+	/* unmask */
+	spin_lock_irqsave(&eisa_irq_lock, flags);
+	if (irq & 8) {
+		slave_mask &= ~(1 << (irq&7));
+		eisa_out8(slave_mask, 0xa1);
+	} else {
+		master_mask &= ~(1 << (irq&7));
+		eisa_out8(master_mask, 0x21);
+	}
+	spin_unlock_irqrestore(&eisa_irq_lock, flags);
+}
+
+static struct irqaction action[IRQ_PER_REGION];
+
+/* EISA needs to be fixed at IRQ region #0 (EISA_IRQ_REGION) */
+static struct irq_region eisa_irq_region = {
+	ops:	{ eisa_disable_irq, eisa_enable_irq, eisa_mask_irq, eisa_unmask_irq },
+	data:	{ name: "EISA", irqbase: 0 },
+	action:	action,
+};
+
+static void eisa_irq(int _, void *intr_dev, struct pt_regs *regs)
+{
+	extern void do_irq(struct irqaction *a, int i, struct pt_regs *p);
+	int irq = gsc_readb(0xfc01f000); /* EISA supports 16 irqs */
+	unsigned long flags;
+        
+	spin_lock_irqsave(&eisa_irq_lock, flags);
+	/* read IRR command */
+	eisa_out8(0x0a, 0x20);
+	eisa_out8(0x0a, 0xa0);
+
+	EISA_DBG("irq IAR %02x 8259-1 irr %02x 8259-2 irr %02x\n",
+		   irq, eisa_in8(0x20), eisa_in8(0xa0));
+   
+	/* read ISR command */
+	eisa_out8(0x0a, 0x20);
+	eisa_out8(0x0a, 0xa0);
+	EISA_DBG("irq 8259-1 isr %02x imr %02x 8259-2 isr %02x imr %02x\n",
+		 eisa_in8(0x20), eisa_in8(0x21), eisa_in8(0xa0), eisa_in8(0xa1));
+	
+	irq &= 0xf;
+	
+	/* mask irq and write eoi */
+	if (irq & 8) {
+		slave_mask |= (1 << (irq&7));
+		eisa_out8(slave_mask, 0xa1);
+		eisa_out8(0x60 | (irq&7),0xa0);/* 'Specific EOI' to slave */
+		eisa_out8(0x62,0x20);	/* 'Specific EOI' to master-IRQ2 */
+		
+	} else {
+		master_mask |= (1 << (irq&7));
+		eisa_out8(master_mask, 0x21);
+		eisa_out8(0x60|irq,0x20);	/* 'Specific EOI' to master */
+	}
+	spin_unlock_irqrestore(&eisa_irq_lock, flags);
+
+   
+	do_irq(&eisa_irq_region.action[irq], EISA_IRQ_REGION + irq, regs);
+   
+	spin_lock_irqsave(&eisa_irq_lock, flags);
+	/* unmask */
+        if (irq & 8) {
+		slave_mask &= ~(1 << (irq&7));
+		eisa_out8(slave_mask, 0xa1);
+	} else {
+		master_mask &= ~(1 << (irq&7));
+		eisa_out8(master_mask, 0x21);
+	}
+	spin_unlock_irqrestore(&eisa_irq_lock, flags);
+}
+
+static void dummy_irq2_handler(int _, void *dev, struct pt_regs *regs)
+{
+	printk(KERN_ALERT "eisa: uhh, irq2?\n");
+}
+
+static void init_eisa_pic(void)
+{
+	unsigned long flags;
+	
+	spin_lock_irqsave(&eisa_irq_lock, flags);
+
+	eisa_out8(0xff, 0x21); /* mask during init */
+	eisa_out8(0xff, 0xa1); /* mask during init */
+	
+	/* master pic */
+	eisa_out8(0x11,0x20); /* ICW1 */   
+	eisa_out8(0x00,0x21); /* ICW2 */   
+	eisa_out8(0x04,0x21); /* ICW3 */   
+	eisa_out8(0x01,0x21); /* ICW4 */   
+	eisa_out8(0x40,0x20); /* OCW2 */   
+	
+	/* slave pic */
+	eisa_out8(0x11,0xa0); /* ICW1 */   
+	eisa_out8(0x08,0xa1); /* ICW2 */   
+        eisa_out8(0x02,0xa1); /* ICW3 */   
+	eisa_out8(0x01,0xa1); /* ICW4 */   
+	eisa_out8(0x40,0xa0); /* OCW2 */   
+        
+	udelay(100);
+	
+	slave_mask = 0xff; 
+	master_mask = 0xfb; 
+	eisa_out8(slave_mask, 0xa1); /* OCW1 */
+	eisa_out8(master_mask, 0x21); /* OCW1 */
+	
+	/* setup trig level */
+	EISA_DBG("EISA edge/level %04x\n", eisa_irq_level);
+	
+	eisa_out8(eisa_irq_level&0xff, 0x4d0); /* Set all irq's to edge  */
+	eisa_out8((eisa_irq_level >> 8) & 0xff, 0x4d1); 
+	
+	EISA_DBG("pic0 mask %02x\n", eisa_in8(0x21));
+	EISA_DBG("pic1 mask %02x\n", eisa_in8(0xa1));
+	EISA_DBG("pic0 edge/level %02x\n", eisa_in8(0x4d0));
+	EISA_DBG("pic1 edge/level %02x\n", eisa_in8(0x4d1));
+	
+	spin_unlock_irqrestore(&eisa_irq_lock, flags);
+}
+
+/* Device initialisation */
+
+#define is_mongoose(dev) (dev->id.sversion == 0x00076)
+
+static int __devinit eisa_probe(struct parisc_device *dev)
+{
+	int result;
+
+	char *name = is_mongoose(dev) ? "Mongoose" : "Wax";
+
+	printk(KERN_INFO "%s EISA Adapter found at 0x%08lx\n", 
+		name, dev->hpa);
+
+	eisa_dev.hba.dev = dev;
+	eisa_dev.hba.iommu = ccio_get_iommu(dev);
+
+	eisa_dev.hba.lmmio_space.name = "EISA";
+	eisa_dev.hba.lmmio_space.start = (unsigned long) 0xfffffffffc000000;
+	eisa_dev.hba.lmmio_space.end = (unsigned long) 0xffffffffffbfffff;
+	eisa_dev.hba.lmmio_space.flags = IORESOURCE_MEM;
+	result = ccio_request_resource(dev, &eisa_dev.hba.lmmio_space);
+	if (result < 0) {
+		printk(KERN_ERR "EISA: failed to claim EISA Bus address space!\n");
+		return result;
+	}
+	eisa_dev.hba.io_space.name = "EISA";
+	eisa_dev.hba.io_space.start = 0;
+	eisa_dev.hba.io_space.end = 0xffff;
+	eisa_dev.hba.lmmio_space.flags = IORESOURCE_IO;
+	result = request_resource(&ioport_resource, &eisa_dev.hba.io_space);
+	if (result < 0) {
+		printk(KERN_ERR "EISA: failed to claim EISA Bus port space!\n");
+		return result;
+	}
+	pcibios_register_hba(&eisa_dev.hba);
+
+	result = request_irq(dev->irq, eisa_irq, SA_SHIRQ, "EISA", NULL);
+	if (result) {
+		printk(KERN_ERR "EISA: request_irq failed!\n");
+		return result;
+	}
+	
+	/* Reserve IRQ2 */
+	action[2].handler = dummy_irq2_handler;
+	action[2].name = "cascade";
+	
+	eisa_irq_region.data.dev = dev;
+	irq_region[0] = &eisa_irq_region;
+	
+	EISA_bus = 1;
+	if (dev->num_addrs) {
+		/* newer firmware hand out the eeprom address */
+		eisa_dev.eeprom_addr = dev->addr[0];
+	} else {
+		/* old firmware, need to figure out the box */
+		if (is_mongoose(dev)) {
+			eisa_dev.eeprom_addr = SNAKES_EEPROM_BASE_ADDR;
+		} else {
+			eisa_dev.eeprom_addr = MIRAGE_EEPROM_BASE_ADDR;
+		}
+	}
+	eisa_eeprom_init(eisa_dev.eeprom_addr);
+	eisa_enumerator(eisa_dev.eeprom_addr, &eisa_dev.hba.io_space, &eisa_dev.hba.lmmio_space);
+	init_eisa_pic();
+	
+	return 0;
+}
+
+static struct parisc_device_id __devinitdata eisa_tbl[] = {
+	{ HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00076 }, /* Mongoose */
+	{ HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00090 }, /* Wax EISA */
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, eisa_tbl);
+
+static struct parisc_driver eisa_driver = {
+	name:		"EISA Bus Adapter",
+	id_table:	eisa_tbl,
+	probe:		eisa_probe,
+};
+
+void __init eisa_init(void)
+{
+	register_parisc_driver(&eisa_driver);
+}
+
+
+static unsigned int eisa_irq_configured;
+void eisa_make_irq_level(int num)
+{
+	if (eisa_irq_configured& (1<<num)) {
+		printk(KERN_WARNING
+		       "IRQ %d polarity configured twice (last to level)\n", 
+		       num);
+	}
+	eisa_irq_level |= (1<<num); /* set the corresponding bit */
+	eisa_irq_configured |= (1<<num); /* set the corresponding bit */
+}
+
+void eisa_make_irq_edge(int num)
+{
+	if (eisa_irq_configured& (1<<num)) {
+		printk(KERN_WARNING 
+		       "IRQ %d polarity configured twice (last to edge)\n",
+		       num);
+	}
+	eisa_irq_level &= ~(1<<num); /* clear the corresponding bit */
+	eisa_irq_configured |= (1<<num); /* set the corresponding bit */
+}
+
+static int __init eisa_irq_setup(char *str)
+{
+	char *cur = str;
+	int val;
+
+	EISA_DBG("IRQ setup\n");
+	while (cur != NULL) {
+		char *pe;
+		
+		val = (int) simple_strtoul(cur, &pe, 0);
+		if (val > 15 || val < 0) {
+			printk(KERN_ERR "eisa: EISA irq value are 0-15\n");
+			continue;
+		}
+		if (val == 2) { 
+			val = 9;
+		}
+		eisa_make_irq_edge(val); /* clear the corresponding bit */
+		EISA_DBG("setting IRQ %d to edge-triggered mode\n", val);
+		
+		if ((cur = strchr(cur, ','))) {
+			cur++;
+		} else {
+			break;
+		}
+	}
+	return 1;
+}
+
+__setup("eisa_irq_edge=", eisa_irq_setup);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/gsc/eisa_eeprom.c linux-2.4.20/drivers/gsc/eisa_eeprom.c
--- linux-2.4.19/drivers/gsc/eisa_eeprom.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/gsc/eisa_eeprom.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,107 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <asm/gsc.h>
+#include <asm/uaccess.h>
+#include <asm/eisa_eeprom.h>
+
+#define 	EISA_EEPROM_MINOR 241
+
+static unsigned long eeprom_addr;
+
+static long long eisa_eeprom_llseek(struct file *file, loff_t offset, int origin )
+{
+	switch (origin) {
+	  case 0:
+		/* nothing to do */
+		break;
+	  case 1:
+		offset += file->f_pos;
+		break;
+	  case 2:
+		offset += HPEE_MAX_LENGTH;
+		break;
+	}
+	return (offset >= 0 && offset < HPEE_MAX_LENGTH) ? (file->f_pos = offset) : -EINVAL;
+}
+
+static ssize_t eisa_eeprom_read(struct file * file,
+			      char *buf, size_t count, loff_t *ppos )
+{
+	unsigned char *tmp;
+	ssize_t ret;
+	int i;
+	
+	if (*ppos >= HPEE_MAX_LENGTH)
+		return 0;
+	
+	count = *ppos + count < HPEE_MAX_LENGTH ? count : HPEE_MAX_LENGTH - *ppos;
+	tmp = kmalloc(count, GFP_KERNEL);
+	if (tmp) {
+		for (i = 0; i < count; i++)
+			tmp[i] = gsc_readb(eeprom_addr+(*ppos)++);
+
+		if (copy_to_user (buf, tmp, count))
+			ret = -EFAULT;
+		else
+			ret = count;
+		kfree (tmp);
+	} else
+		ret = -ENOMEM;
+	
+	return ret;
+}
+
+static int eisa_eeprom_ioctl(struct inode *inode, struct file *file, 
+			   unsigned int cmd,
+			   unsigned long arg)
+{
+	return -ENOTTY;
+}
+
+static int eisa_eeprom_open(struct inode *inode, struct file *file)
+{
+	if (file->f_mode & 2 || eeprom_addr == 0)
+		return -EINVAL;
+   
+	return 0;
+}
+
+static int eisa_eeprom_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+/*
+ *	The various file operations we support.
+ */
+static struct file_operations eisa_eeprom_fops = {
+	owner:		THIS_MODULE,
+	llseek:		eisa_eeprom_llseek,
+	read:		eisa_eeprom_read,
+	ioctl:		eisa_eeprom_ioctl,
+	open:		eisa_eeprom_open,
+	release:	eisa_eeprom_release,
+};
+
+static struct miscdevice eisa_eeprom_dev=
+{
+	EISA_EEPROM_MINOR,
+	"eisa eeprom",
+	&eisa_eeprom_fops
+};
+
+int __init eisa_eeprom_init(unsigned long addr)
+{
+	if (addr) {
+		eeprom_addr = addr;
+		misc_register(&eisa_eeprom_dev);
+		printk(KERN_INFO "EISA EEPROM at 0x%lx\n", eeprom_addr);
+	}
+	return 0;
+}
+
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/gsc/eisa_enumerator.c linux-2.4.20/drivers/gsc/eisa_enumerator.c
--- linux-2.4.19/drivers/gsc/eisa_enumerator.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/gsc/eisa_enumerator.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,518 @@
+/*
+ * eisa_enumerator.c - provide support for EISA adapters in PA-RISC machines
+ *
+ * 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.
+ *
+ * Copyright (c) 2002 Daniel Engstrom <5116@telia.com>
+ *
+ */
+
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <asm/gsc.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+#include <asm/eisa_bus.h>
+#include <asm/eisa_eeprom.h>
+
+
+/*
+ * Todo:
+ * 
+ * PORT init with MASK attr and other size than byte
+ * MEMORY with other decode than 20 bit
+ * CRC stuff
+ * FREEFORM stuff
+ */
+
+#define EPI 0xc80
+#define NUM_SLOT 16
+#define SLOT2PORT(x) (x<<12)
+
+
+/* macros to handle unaligned accesses and 
+ * byte swapping. The data in the EEPROM is
+ * little-endian on the big-endian PAROSC */
+#define get_8(x) (*(u_int8_t*)(x))
+
+static inline u_int16_t get_16(const unsigned char *x)
+{ 
+	return (x[1] << 8) | x[0];
+}
+
+static inline u_int32_t get_32(const unsigned char *x)
+{
+	return (x[3] << 24) | (x[2] << 16) | (x[1] << 8) | x[0];
+}
+
+static inline u_int32_t get_24(const unsigned char *x)
+{
+	return (x[2] << 24) | (x[1] << 16) | (x[0] << 8);
+}
+
+static void print_eisa_id(char *s, u_int32_t id)
+{
+	char vendor[4];
+	int rev;
+	int device;
+	
+	rev = id & 0xff;
+	id >>= 8;
+	device = id & 0xff;
+	id >>= 8;
+	vendor[3] = '\0';
+	vendor[2] = '@' + (id & 0x1f);
+	id >>= 5;	
+	vendor[1] = '@' + (id & 0x1f);
+	id >>= 5;	
+	vendor[0] = '@' + (id & 0x1f);
+	id >>= 5;	
+	
+	sprintf(s, "%s%02X%02X", vendor, device, rev);
+}
+       
+static int configure_memory(const unsigned char *buf, 
+		       struct resource *mem_parent,
+		       char *name)
+{
+	int len;
+	u_int8_t c;
+	int i;
+	struct resource *res;
+	
+	len=0;
+	
+	for (i=0;i<HPEE_MEMORY_MAX_ENT;i++) {
+		c = get_8(buf+len);
+		
+		if (NULL != (res = kmalloc(sizeof(struct resource), GFP_KERNEL))) {
+			int result;
+			
+			res->name = name;
+			res->start = mem_parent->start + get_24(buf+len+2);
+			res->end = res->start + get_16(buf+len+5)*1024;
+			res->flags = IORESOURCE_MEM;
+			printk("memory %lx-%lx ", res->start, res->end);
+			result = request_resource(mem_parent, res);
+			if (result < 0) {
+				printk("\n" KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
+				return result;
+			}
+		}
+		 	
+		len+=7;      
+	
+		if (!(c & HPEE_MEMORY_MORE)) {
+			break;
+		}
+	}
+	
+	return len;
+}
+
+
+static int configure_irq(const unsigned char *buf)
+{
+	int len;
+	u_int8_t c;
+	int i;
+	
+	len=0;
+	
+	for (i=0;i<HPEE_IRQ_MAX_ENT;i++) {
+		c = get_8(buf+len);
+		
+		printk("IRQ %d ", c & HPEE_IRQ_CHANNEL_MASK);
+		if (c & HPEE_IRQ_TRIG_LEVEL) {
+			eisa_make_irq_level(c & HPEE_IRQ_CHANNEL_MASK);
+		} else {
+			eisa_make_irq_edge(c & HPEE_IRQ_CHANNEL_MASK);
+		}
+		
+		len+=2; 
+		/* hpux seems to allow for
+		 * two bytes of irq data but only defines one of
+		 * them, I think */
+		if  (!(c & HPEE_IRQ_MORE)) {
+			break;
+		}
+	}
+	
+	return len;
+}
+
+
+static int configure_dma(const unsigned char *buf)
+{
+	int len;
+	u_int8_t c;
+	int i;
+	
+	len=0;
+	
+	for (i=0;i<HPEE_DMA_MAX_ENT;i++) {
+		c = get_8(buf+len);
+		printk("DMA %d ", c&HPEE_DMA_CHANNEL_MASK);
+		/* fixme: maybe initialize the dma channel withthe timing ? */
+		len+=2;      
+		if (!(c & HPEE_DMA_MORE)) {
+			break;
+		}
+	}
+	
+	return len;
+}
+
+static int configure_port(const unsigned char *buf, struct resource *io_parent,
+		     char *board)
+{
+	int len;
+	u_int8_t c;
+	int i;
+	struct resource *res;
+	int result;
+	
+	len=0;
+	
+	for (i=0;i<HPEE_PORT_MAX_ENT;i++) {
+		c = get_8(buf+len);
+		
+		if (NULL != (res = kmalloc(sizeof(struct resource), GFP_KERNEL))) {
+			res->name = board;
+			res->start = get_16(buf+len+1);
+			res->end = get_16(buf+len+1)+(c&HPEE_PORT_SIZE_MASK)+1;
+			res->flags = IORESOURCE_IO;
+			printk("ioports %lx-%lx ", res->start, res->end);
+			result = request_resource(io_parent, res);
+			if (result < 0) {
+				printk("\n" KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
+				return result;
+			}
+		}
+
+		len+=3;      
+		if (!(c & HPEE_PORT_MORE)) {
+			break;
+		}
+	}
+	
+	return len;
+}
+
+
+/* byte 1 and 2 is the port number to write
+ * and at byte 3 the value to write starts.
+ * I assume that there are and- and or- masks
+ * here when HPEE_PORT_INIT_MASK is set but I have 
+ * not yet encountered this. */
+static int configure_port_init(const unsigned char *buf)
+{
+	int len=0;
+	u_int8_t c;
+	
+	while (len<HPEE_PORT_INIT_MAX_LEN) {
+		int s=0;
+		c = get_8(buf+len);
+		
+		switch (c & HPEE_PORT_INIT_WIDTH_MASK)  {
+		 case HPEE_PORT_INIT_WIDTH_BYTE:
+			s=1;
+			if (c & HPEE_PORT_INIT_MASK) {
+				printk("\n" KERN_WARNING "port_init: unverified mask attribute\n");
+				outb((inb(get_16(buf+len+1) & 
+					  get_8(buf+len+3)) | 
+				      get_8(buf+len+4)), get_16(buf+len+1));
+				      
+			} else {
+				outb(get_8(buf+len+3), get_16(buf+len+1));
+				      
+			}
+			break;
+		 case HPEE_PORT_INIT_WIDTH_WORD:
+			s=2;
+			if (c & HPEE_PORT_INIT_MASK) {
+ 				printk(KERN_WARNING "port_init: unverified mask attribute\n");
+				       outw((inw(get_16(buf+len+1)) &
+					     get_16(buf+len+3)) |
+					    get_16(buf+len+5), 
+					    get_16(buf+len+1));
+			} else {
+				outw(cpu_to_le16(get_16(buf+len+3)), get_16(buf+len+1));
+			}
+			break;
+		 case HPEE_PORT_INIT_WIDTH_DWORD:
+			s=4;
+			if (c & HPEE_PORT_INIT_MASK) {
+ 				printk("\n" KERN_WARNING "port_init: unverified mask attribute\n");
+				outl((inl(get_16(buf+len+1) &
+					  get_32(buf+len+3)) |
+				      get_32(buf+len+7)), get_16(buf+len+1));
+			} else {
+				outl(cpu_to_le32(get_32(buf+len+3)), get_16(buf+len+1));
+			}
+
+			break;
+		 default:
+			printk("\n" KERN_ERR "Invalid port init word %02x\n", c);
+			return 0;
+		}
+		
+		if (c & HPEE_PORT_INIT_MASK) {   
+			s*=2;
+		}
+		
+		len+=s+3;
+		if (!(c & HPEE_PORT_INIT_MORE)) {
+			break;
+		}
+	}
+	
+	return len;
+}
+
+static int configure_choise(const unsigned char *buf, u_int8_t *info)
+{
+	int len;
+	
+	/* theis record contain the value of the functions
+	 * configuration choises and an info byte which 
+	 * describes which other records to expect in this 
+	 * function */
+	len = get_8(buf);
+	*info=get_8(buf+len+1);
+	 
+	return len+2;
+}
+
+static int configure_type_string(const unsigned char *buf) 
+{
+	int len;
+	
+	/* just skip past the type field */
+	len = get_8(buf);
+	if (len > 80) {
+		printk("\n" KERN_ERR "eisa_enumerator: type info field too long (%d, max is 80)\n", len);
+	}
+	
+	return 1+len;
+}
+
+static int configure_function(const unsigned char *buf, int *more) 
+{
+	/* the init field seems to be a two-byte field
+	 * which is non-zero if there are an other function following
+	 * I think it is the length of the function def 
+	 */
+	*more = get_16(buf);
+	
+	return 2;
+}
+
+static int parse_slot_config(int slot,
+			     const unsigned char *buf,
+			     struct eeprom_eisa_slot_info *es, 
+			     struct resource *io_parent,
+			     struct resource *mem_parent)
+{
+	int res=0;
+	int function_len;
+	unsigned int pos=0;
+	unsigned int maxlen;
+	int num_func=0;
+	u_int8_t flags;
+	int p0;
+	
+	char *board;
+	int id_string_used=0;
+	
+	if (NULL == (board = kmalloc(8, GFP_KERNEL))) {
+		return -1;
+	}
+	print_eisa_id(board, es->eisa_slot_id);
+	printk(KERN_INFO "EISA slot %d: %s %s ", 
+	       slot, board, es->flags&HPEE_FLAG_BOARD_IS_ISA ? "ISA" : "EISA");
+	
+	maxlen = es->config_data_length < HPEE_MAX_LENGTH ?
+			 es->config_data_length : HPEE_MAX_LENGTH;
+	while ((pos < maxlen) && (num_func <= es->num_functions)) {
+		pos+=configure_function(buf+pos, &function_len); 
+		
+		if (!function_len) {
+			break;
+		}
+		num_func++;
+		p0 = pos;
+		pos += configure_choise(buf+pos, &flags);
+
+		if (flags & HPEE_FUNCTION_INFO_F_DISABLED) {
+			/* function disabled, skip silently */
+			pos = p0 + function_len;
+			continue;
+		}
+		if (flags & HPEE_FUNCTION_INFO_CFG_FREE_FORM) {
+			/* I have no idea how to handle this */
+			printk("function %d have free-form confgiuration, skipping ",
+				num_func);
+			pos = p0 + function_len;
+			continue;
+		}
+
+		/* the ordering of the sections need
+		 * more investigation.
+		 * Currently I think that memory comaed before IRQ
+		 * I assume the order is LSB to MSB in the 
+		 * info flags 
+		 * eg type, memory, irq, dma, port, HPEE_PORT_init 
+		 */
+
+		if (flags & HPEE_FUNCTION_INFO_HAVE_TYPE) {
+			pos += configure_type_string(buf+pos);
+		}
+		
+		if (flags & HPEE_FUNCTION_INFO_HAVE_MEMORY) {
+			id_string_used=1;
+			pos += configure_memory(buf+pos, mem_parent, board);
+		} 
+		
+		if (flags & HPEE_FUNCTION_INFO_HAVE_IRQ) {
+			pos += configure_irq(buf+pos);
+		} 
+		
+		if (flags & HPEE_FUNCTION_INFO_HAVE_DMA) {
+			pos += configure_dma(buf+pos);
+		} 
+		
+		if (flags & HPEE_FUNCTION_INFO_HAVE_PORT) {
+			id_string_used=1;
+			pos += configure_port(buf+pos, io_parent, board);
+		} 
+		
+		if (flags &  HPEE_FUNCTION_INFO_HAVE_PORT_INIT) {
+			pos += configure_port_init(buf+pos);
+		}
+		
+		if (p0 + function_len < pos) {
+			printk("\n" KERN_ERR "eisa_enumerator: function %d length mis-match "
+			       "got %d, expected %d\n",
+			       num_func, pos-p0, function_len);
+			res=-1;
+			break;
+		}
+		pos = p0 + function_len;
+	}
+	printk("\n");
+	if (!id_string_used) {
+		kfree(board);
+	}
+	
+	if (pos != es->config_data_length) {
+		printk(KERN_ERR "eisa_enumerator: config data length mis-match got %d, expected %d\n",
+			pos, es->config_data_length);
+		res=-1;
+	}
+	
+	if (num_func != es->num_functions) {
+		printk(KERN_ERR "eisa_enumerator: number of functions mis-match got %d, expected %d\n",
+			num_func, es->num_functions);
+		res=-2;
+	}
+	
+	return res;
+	
+}
+
+static int init_slot(int slot, struct eeprom_eisa_slot_info *es)
+{
+	unsigned int id;
+	
+	char id_string[8];
+	
+	if (!(es->slot_info&HPEE_SLOT_INFO_NO_READID)) {
+		/* try to read the id of the board in the slot */
+		id = le32_to_cpu(inl(SLOT2PORT(slot)+EPI));
+		
+		if (0xffffffff == id) {
+			/* this board is not here or it does not 
+			 * support readid 
+			 */
+			printk(KERN_ERR "EISA slot %d a configured board was not detected (", 
+			       slot);
+			
+			print_eisa_id(id_string, es->eisa_slot_id);
+			printk(" expected %s)\n", id_string);
+		
+			return -1;	
+
+		}
+		if (es->eisa_slot_id != id) {
+			print_eisa_id(id_string, id);
+			printk(KERN_ERR "EISA slot %d id mis-match: got %s", 
+			       slot, id_string);
+			
+			print_eisa_id(id_string, es->eisa_slot_id);
+			printk(" expected %s \n", id_string);
+		
+			return -1;	
+			
+		}
+	}
+	
+	/* now: we need to enable the board if 
+	 * it supports enabling and run through
+	 * the port init sction if present
+	 * and finally record any interrupt polarity
+	 */
+	if (es->slot_features & HPEE_SLOT_FEATURES_ENABLE) {
+		/* enable board */
+		outb(0x01| inb(SLOT2PORT(slot)+EPI+4),
+		     SLOT2PORT(slot)+EPI+4);
+	}
+	
+	return 0;
+}
+
+
+int eisa_enumerator(unsigned long eeprom_addr,
+		    struct resource *io_parent, struct resource *mem_parent) 
+{
+	int i;
+	struct eeprom_header *eh;
+	static char eeprom_buf[HPEE_MAX_LENGTH];
+	
+	for (i=0; i < HPEE_MAX_LENGTH; i++) {
+		eeprom_buf[i] = gsc_readb(eeprom_addr+i);
+	}
+	
+	printk(KERN_INFO "Enumerating EISA bus\n");
+		    	
+	eh = (struct eeprom_header*)(eeprom_buf);
+	for (i=0;i<eh->num_slots;i++) {
+		struct eeprom_eisa_slot_info *es;
+		
+		es = (struct eeprom_eisa_slot_info*)
+			(&eeprom_buf[HPEE_SLOT_INFO(i)]);
+	        
+		if (-1==init_slot(i+1, es)) {
+			return -1;
+			
+		}
+		
+		if (es->config_data_offset < HPEE_MAX_LENGTH) {
+			if (parse_slot_config(i+1, &eeprom_buf[es->config_data_offset],
+					      es, io_parent, mem_parent)) {
+				return -1;
+			}
+		} else {
+			printk (KERN_WARNING "EISA EEPROM offset 0x%x out of range\n",es->config_data_offset);
+			return -1;
+		}
+	}
+	return 0;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/gsc/gsc.c linux-2.4.20/drivers/gsc/gsc.c
--- linux-2.4.19/drivers/gsc/gsc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/gsc/gsc.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,204 @@
+/*
+ * Interrupt management for most GSC and related devices.
+ *
+ * (c) Copyright 1999 Alex deVries for The Puffin Group
+ * (c) Copyright 1999 Grant Grundler for Hewlett-Packard
+ * (c) Copyright 1999 Matthew Wilcox
+ * (c) Copyright 2000 Helge Deller
+ * (c) Copyright 2001 Matthew Wilcox for Hewlett-Packard
+ *
+ *	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.
+ */
+
+#include <linux/bitops.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/gsc.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "busdevice.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DEBPRINTK printk
+#else
+#define DEBPRINTK(x,...)
+#endif
+
+int gsc_alloc_irq(struct gsc_irq *i)
+{
+	int irq = txn_alloc_irq();
+	if (irq < 0) {
+		printk("cannot get irq\n");
+		return irq;
+	}
+
+	i->txn_addr = txn_alloc_addr(irq);
+	i->txn_data = txn_alloc_data(irq, GSC_EIM_WIDTH);
+	i->irq = irq;
+
+	return irq;
+}
+
+
+int gsc_claim_irq(struct gsc_irq *i, int irq)
+{
+	int c = irq;
+
+	irq += IRQ_FROM_REGION(CPU_IRQ_REGION); /* virtualize the IRQ first */
+
+	irq = txn_claim_irq(irq);
+	if (irq < 0) {
+		printk("cannot claim irq %d\n", c);
+		return irq;
+	}
+
+	i->txn_addr = txn_alloc_addr(irq);
+	i->txn_data = txn_alloc_data(irq, GSC_EIM_WIDTH);
+	i->irq = irq;
+
+	return irq;
+}
+
+
+/* IRQ bits must be numbered from Most Significant Bit */
+#define GSC_FIX_IRQ(x)	(31-(x))
+#define GSC_MASK_IRQ(x)	(1<<(GSC_FIX_IRQ(x)))
+
+/* Common interrupt demultiplexer used by Asp, Lasi & Wax.  */
+void busdev_barked(int busdev_irq, void *dev, struct pt_regs *regs)
+{
+	unsigned long irq;
+	struct busdevice *busdev = (struct busdevice *) dev;
+
+	/* 
+	    Don't need to protect OFFSET_IRR with spinlock since this is
+	    the only place it's touched.
+	    Protect busdev_region by disabling this region's interrupts,
+	    modifying the region, and then re-enabling the region.
+	*/
+
+	irq = gsc_readl(busdev->hpa+OFFSET_IRR);
+	if (irq == 0) {
+		printk(KERN_ERR "%s: barking without apparent reason.\n", busdev->name);
+	} else {
+		DEBPRINTK ("%s (0x%x) barked, mask=0x%x, irq=%d\n", 
+		    busdev->name, busdev->busdev_region->data.irqbase, 
+		    irq, GSC_FIX_IRQ(ffs(irq))+1 );
+
+		do_irq_mask(irq, busdev->busdev_region, regs);
+	}
+}
+
+static void
+busdev_disable_irq(void *irq_dev, int irq)
+{
+	/* Disable the IRQ line by clearing the bit in the IMR */
+	u32 imr = gsc_readl(BUSDEV_DEV(irq_dev)->hpa+OFFSET_IMR);
+	imr &= ~(GSC_MASK_IRQ(irq));
+
+	DEBPRINTK( KERN_WARNING "%s(%p, %d) %s: IMR 0x%x\n", 
+		    __FUNCTION__, irq_dev, irq, BUSDEV_DEV(irq_dev)->name, imr);
+
+	gsc_writel(imr, BUSDEV_DEV(irq_dev)->hpa+OFFSET_IMR);
+}
+
+
+static void
+busdev_enable_irq(void *irq_dev, int irq)
+{
+	/* Enable the IRQ line by setting the bit in the IMR */
+	unsigned long addr = BUSDEV_DEV(irq_dev)->hpa + OFFSET_IMR;
+	u32 imr = gsc_readl(addr);
+	imr |= GSC_MASK_IRQ(irq);
+
+	DEBPRINTK (KERN_WARNING "%s(%p, %d) %s: IMR 0x%x\n", 
+		    __FUNCTION__, irq_dev, irq, BUSDEV_DEV(irq_dev)->name, imr);
+
+	gsc_writel(imr, addr);
+//	gsc_writel(~0L, addr);
+
+/* FIXME: read IPR to make sure the IRQ isn't already pending.
+**   If so, we need to read IRR and manually call do_irq_mask().
+**   This code should be shared with busdev_unmask_irq().
+*/
+}
+
+static void
+busdev_mask_irq(void *irq_dev, int irq)
+{
+/* FIXME: Clear the IMR bit in busdev for that IRQ */
+}
+
+static void
+busdev_unmask_irq(void *irq_dev, int irq)
+{
+/* FIXME: Read IPR. Set the IMR bit in busdev for that IRQ.
+   call do_irq_mask() if IPR is non-zero
+*/
+}
+
+struct irq_region_ops busdev_irq_ops = {
+	disable_irq:	busdev_disable_irq,
+	enable_irq:	busdev_enable_irq,
+	mask_irq:	busdev_mask_irq,
+	unmask_irq:	busdev_unmask_irq
+};
+
+
+int gsc_common_irqsetup(struct parisc_device *parent, struct busdevice *busdev)
+{
+	struct resource *res;
+
+	busdev->gsc = parent;
+
+	/* the IRQs we simulate */
+	busdev->busdev_region = alloc_irq_region(32, &busdev_irq_ops,
+						 busdev->name, busdev);
+	if (!busdev->busdev_region)
+		return -ENOMEM;
+
+	/* allocate resource region */
+	res = request_mem_region(busdev->hpa, 0x100000, busdev->name);
+	if (res) {
+		res->flags = IORESOURCE_MEM; 	/* do not mark it busy ! */
+	}
+
+#if 0
+	printk(KERN_WARNING "%s IRQ %d EIM 0x%x", busdev->name,
+			busdev->parent_irq, busdev->eim);
+	if (gsc_readl(busdev->hpa + OFFSET_IMR))
+		printk("  IMR is non-zero! (0x%x)",
+				gsc_readl(busdev->hpa + OFFSET_IMR));
+	printk("\n");
+#endif
+
+	return 0;
+}
+
+extern struct parisc_driver lasi_driver;
+extern struct parisc_driver asp_driver;
+extern struct parisc_driver wax_driver;
+
+void __init gsc_init(void)
+{
+#ifdef CONFIG_GSC_LASI
+	register_parisc_driver(&lasi_driver);
+	register_parisc_driver(&asp_driver);
+#endif
+#ifdef CONFIG_GSC_WAX
+	register_parisc_driver(&wax_driver);
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/gsc/lasi.c linux-2.4.20/drivers/gsc/lasi.c
--- linux-2.4.19/drivers/gsc/lasi.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/gsc/lasi.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,245 @@
+/*
+ *	LASI Device Driver
+ *
+ *	(c) Copyright 1999 Red Hat Software
+ *	Portions (c) Copyright 1999 The Puffin Group Inc.
+ *	Portions (c) Copyright 1999 Hewlett-Packard
+ *
+ *	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.
+ *
+ *	by Alan Cox <alan@redhat.com> and 
+ * 	   Alex deVries <adevries@thepuffingroup.com> 
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/gsc.h>
+#include <asm/hardware.h>
+#include <asm/led.h>
+
+#include "busdevice.h"
+
+
+#define LASI_VER	0xC008	/* LASI Version */
+
+#define LASI_IO_CONF	0x7FFFE	/* LASI primary configuration register */
+#define LASI_IO_CONF2	0x7FFFF	/* LASI secondary configuration register */
+
+static int lasi_choose_irq(struct parisc_device *dev)
+{
+	int irq;
+
+	/*
+	** "irq" bits below are numbered relative to most significant bit.
+	*/
+	switch (dev->id.sversion) {
+		case 0x74:	irq = 24; break; /* Centronics */
+		case 0x7B:	irq = 18; break; /* Audio */
+		case 0x81:	irq = 17; break; /* Lasi itself */
+		case 0x82:	irq = 22; break; /* SCSI */
+		case 0x83:	irq = 11; break; /* Floppy */
+		case 0x84:	irq =  5; break; /* PS/2 Keyboard */
+		case 0x87:	irq = 13; break; /* ISDN */
+		case 0x8A:	irq = 23; break; /* LAN */
+		case 0x8C:	irq = 26; break; /* RS232 */
+		case 0x8D:	irq = (dev->hw_path == 13) ? 15 : 14;
+						break; /* Telephone */
+		default: 	irq = -1; break; /* unknown */
+	}
+
+	return irq;
+}
+
+static void __init
+lasi_init_irq(struct busdevice *this_lasi)
+{
+	unsigned long lasi_base = this_lasi->hpa;
+
+	/* Stop LASI barking for a bit */
+	gsc_writel(0x00000000, lasi_base+OFFSET_IMR);
+
+	/* clear pending interrupts */
+	gsc_readl(lasi_base+OFFSET_IRR);
+
+	/* We're not really convinced we want to reset the onboard
+         * devices. Firmware does it for us...
+	 */
+
+	/* Resets */
+	/* gsc_writel(0xFFFFFFFF, lasi_base+0x2000);*/	/* Parallel */
+	gsc_writel(0xFFFFFFFF, lasi_base+0x4004);	/* Audio */
+	/* gsc_writel(0xFFFFFFFF, lasi_base+0x5000);*/	/* Serial */ 
+	/* gsc_writel(0xFFFFFFFF, lasi_base+0x6000);*/	/* SCSI */
+	gsc_writel(0xFFFFFFFF, lasi_base+0x7000);	/* LAN */
+	gsc_writel(0xFFFFFFFF, lasi_base+0x8000);	/* Keyboard */
+	gsc_writel(0xFFFFFFFF, lasi_base+0xA000);	/* FDC */
+	
+	/* Ok we hit it on the head with a hammer, our Dog is now
+	** comatose and muzzled.  Devices will now unmask LASI
+	** interrupts as they are registered as irq's in the LASI range.
+	*/
+	/* XXX: I thought it was `awks that got `it on the `ead with an
+	 * `ammer.  -- willy
+	 */
+}
+
+
+/*
+   ** lasi_led_init()
+   ** 
+   ** lasi_led_init() initializes the LED controller on the LASI.
+   **
+   ** Since Mirage and Electra machines use a different LED
+   ** address register, we need to check for these machines 
+   ** explicitly.
+ */
+
+#ifndef CONFIG_CHASSIS_LCD_LED
+
+#define lasi_led_init(x)	/* nothing */
+
+#else
+
+void __init lasi_led_init(unsigned long lasi_hpa)
+{
+	unsigned long datareg;
+
+	switch (CPU_HVERSION) {
+	/* Gecko machines have only one single LED, which can be permanently 
+	   turned on by writing a zero into the power control register. */ 
+	case 0x600:		/* Gecko (712/60) */
+	case 0x601:		/* Gecko (712/80) */
+	case 0x602:		/* Gecko (712/100) */
+	case 0x603:		/* Anole 64 (743/64) */
+	case 0x604:		/* Anole 100 (743/100) */
+	case 0x605:		/* Gecko (712/120) */
+		datareg = lasi_hpa + 0x0000C000;
+		gsc_writeb(0, datareg);
+		return; /* no need to register the LED interrupt-function */  
+
+	/* Mirage and Electra machines need special offsets */
+	case 0x60A:		/* Mirage Jr (715/64) */
+	case 0x60B:		/* Mirage 100 */
+	case 0x60C:		/* Mirage 100+ */
+	case 0x60D:		/* Electra 100 */
+	case 0x60E:		/* Electra 120 */
+		datareg = lasi_hpa - 0x00020000;
+		break;
+
+	default:
+		datareg = lasi_hpa + 0x0000C000;
+		break;
+	} /* switch() */
+
+	register_led_driver(DISPLAY_MODEL_LASI, LED_CMD_REG_NONE, (char *)datareg);
+}
+#endif
+
+/*
+ * lasi_power_off
+ *
+ * Function for lasi to turn off the power.  This is accomplished by setting a
+ * 1 to PWR_ON_L in the Power Control Register
+ * 
+ */
+
+static unsigned long lasi_power_off_hpa;
+
+static void lasi_power_off(void)
+{
+	unsigned long datareg;
+
+	/* calculate addr of the Power Control Register */
+	datareg = lasi_power_off_hpa + 0x0000C000;
+
+	/* Power down the machine */
+	gsc_writel(0x02, datareg);
+}
+
+int __init
+lasi_init_chip(struct parisc_device *dev)
+{
+	struct busdevice *lasi;
+	struct gsc_irq gsc_irq;
+	int irq, ret;
+
+	lasi = kmalloc(sizeof(struct busdevice), GFP_KERNEL);
+	if (!lasi)
+		return -ENOMEM;
+
+	lasi->name = "Lasi";
+	lasi->hpa = dev->hpa;
+
+	/* Check the 4-bit (yes, only 4) version register */
+	lasi->version = gsc_readl(lasi->hpa + LASI_VER) & 0xf;
+	printk(KERN_INFO "%s version %d at 0x%lx found.\n",
+		lasi->name, lasi->version, lasi->hpa);
+
+	/* initialize the chassis LEDs really early */ 
+	lasi_led_init(lasi->hpa);
+
+	/* Stop LASI barking for a bit */
+	lasi_init_irq(lasi);
+
+	/* the IRQ lasi should use */
+	irq = gsc_alloc_irq(&gsc_irq);
+	if (irq < 0) {
+		printk(KERN_ERR "%s(): cannot get GSC irq\n",
+				__FUNCTION__);
+		kfree(lasi);
+		return -EBUSY;
+	}
+
+	ret = request_irq(gsc_irq.irq, busdev_barked, 0, "lasi", lasi);
+	if (ret < 0) {
+		kfree(lasi);
+		return ret;
+	}
+
+	/* Save this for debugging later */
+	lasi->parent_irq = gsc_irq.irq;
+	lasi->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
+
+	/* enable IRQ's for devices below LASI */
+	gsc_writel(lasi->eim, lasi->hpa + OFFSET_IAR);
+
+	/* Done init'ing, register this driver */
+	ret = gsc_common_irqsetup(dev, lasi);
+	if (ret) {
+		kfree(lasi);
+		return ret;
+	}    
+
+	fixup_child_irqs(dev, lasi->busdev_region->data.irqbase,
+			lasi_choose_irq);
+
+	/* initialize the power off function */
+	/* FIXME: Record the LASI HPA for the power off function.  This should
+	 * ensure that only the first LASI (the one controlling the power off)
+	 * should set the HPA here */
+	lasi_power_off_hpa = lasi->hpa;
+	pm_power_off = lasi_power_off;
+	
+	return ret;
+}
+
+static struct parisc_device_id lasi_tbl[] = {
+	{ HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00081 },
+	{ 0, }
+};
+
+struct parisc_driver lasi_driver = {
+	name:		"Lasi",
+	id_table:	lasi_tbl,
+	probe:		lasi_init_chip,
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/gsc/serial.c linux-2.4.20/drivers/gsc/serial.c
--- linux-2.4.19/drivers/gsc/serial.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/gsc/serial.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,133 @@
+/*
+ *	Serial Device Initialisation for LASI/ASP/WAX/DINO
+ *
+ *	(c) Copyright 2000 The Puffin Group Inc.
+ *	(c) Copyright 2000-2001 Helge Deller <deller@gmx.de>
+ *
+ *	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.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/slab.h>
+
+#include <asm/serial.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/gsc.h>
+
+#include "busdevice.h"
+
+static void setup_parisc_serial(struct serial_struct *serial,
+		unsigned long address, int irq, int line)
+{
+	memset(serial, 0, sizeof(struct serial_struct));
+
+	/* autoconfig() sets state->type.  This sets info->type */
+	serial->type = PORT_16550A;
+
+	serial->line = line;
+	serial->iomem_base = ioremap(address, 0x8);
+
+	serial->irq = irq;
+	serial->io_type = SERIAL_IO_MEM;	/* define access method */
+	serial->flags = 0;
+	serial->xmit_fifo_size = 16;
+	serial->custom_divisor = 0;
+	serial->baud_base = LASI_BASE_BAUD;
+}
+
+static int __init 
+serial_init_chip(struct parisc_device *dev)
+{
+	static int serial_line_nr;
+	unsigned long address;
+
+	struct serial_struct *serial;
+
+	if (!dev->irq) {
+		if (dev->parent->id.hw_type != HPHW_IOA) {
+			printk(KERN_INFO "Serial: device 0x%lx not configured.\n"
+				"Enable support for Wax, Lasi, Asp or Dino.\n", dev->hpa);
+		}
+		return -ENODEV;
+	}
+
+	serial = kmalloc(sizeof(*serial), GFP_KERNEL);
+	if (!serial)
+		return -ENOMEM;
+
+	address = dev->hpa;
+	if (dev->id.sversion != 0x8d) {
+		address += 0x800;
+	}
+
+	setup_parisc_serial(serial, address, dev->irq, serial_line_nr++);
+
+	if (register_serial(serial) < 0) {
+		printk(KERN_WARNING "register_serial returned error\n");
+		kfree(serial);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static struct parisc_device_id serial_tbl[] = {
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00075 },
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008c },
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008d },
+	{ 0 }
+};
+
+/* Hack.  Dino's serial port will get listed first on some machines.
+ * So we register this driver first which knows about Lasi's serial port.
+ * This needs to get fixed properly somehow.
+ */
+static struct parisc_device_id serial1_tbl[] = {
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x03B, 0x0008C }, /* C1xx/C1xxL */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x03C, 0x0008C }, /* B132L */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x03D, 0x0008C }, /* B160L */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x03E, 0x0008C }, /* B132L+ */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x03F, 0x0008C }, /* B180L+ */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x046, 0x0008C }, /* Rocky2 120 */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x047, 0x0008C }, /* Rocky2 150 */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x04E, 0x0008C }, /* Kiji L2 132 */
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x056, 0x0008C }, /* Raven+ */
+	{ 0 }
+};
+
+
+MODULE_DEVICE_TABLE(parisc, serial_tbl);
+
+static struct parisc_driver serial1_driver = {
+	name:		"Serial RS232",
+	id_table:	serial1_tbl,
+	probe:		serial_init_chip,
+};
+
+static struct parisc_driver serial_driver = {
+	name:		"Serial RS232",
+	id_table:	serial_tbl,
+	probe:		serial_init_chip,
+};
+
+void __init probe_serial_gsc(void)
+{
+	register_parisc_driver(&serial1_driver);
+	register_parisc_driver(&serial_driver);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/gsc/wax.c linux-2.4.20/drivers/gsc/wax.c
--- linux-2.4.19/drivers/gsc/wax.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/gsc/wax.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,142 @@
+/*
+ *	WAX Device Driver
+ *
+ *	(c) Copyright 2000 The Puffin Group 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.
+ *
+ *	by Helge Deller <deller@gmx.de>
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/gsc.h>
+#include <asm/irq.h>
+
+#include "busdevice.h"
+
+#define WAX_GSC_IRQ	7	/* Hardcoded Interrupt for GSC */
+#define WAX_GSC_NMI_IRQ	29
+
+static int wax_choose_irq(struct parisc_device *dev)
+{
+	int irq = -1;
+
+	switch (dev->id.sversion) {
+		case 0x73:	irq = 30; break; /* HIL */
+		case 0x8c:	irq = 25; break; /* RS232 */
+		case 0x90:	irq = 21; break; /* WAX EISA BA */
+	}
+
+	return irq;
+}
+
+static void __init
+wax_init_irq(struct busdevice *wax)
+{
+	unsigned long base = wax->hpa;
+
+	/* Stop WAX barking for a bit */
+	gsc_writel(0x00000000, base+OFFSET_IMR);
+
+	/* clear pending interrupts */
+	(volatile u32) gsc_readl(base+OFFSET_IRR);
+
+	/* We're not really convinced we want to reset the onboard
+         * devices. Firmware does it for us...
+	 */
+
+	/* Resets */
+//	gsc_writel(0xFFFFFFFF, base+0x1000); /* HIL */
+//	gsc_writel(0xFFFFFFFF, base+0x2000); /* RS232-B on Wax */
+	
+	/* Ok we hit it on the head with a hammer, our Dog is now
+	** comatose and muzzled.  Devices will now unmask WAX
+	** interrupts as they are registered as irq's in the WAX range.
+	*/
+}
+
+int __init
+wax_init_chip(struct parisc_device *dev)
+{
+	struct busdevice *wax;
+	struct gsc_irq gsc_irq;
+	int irq, ret;
+
+	wax = kmalloc(sizeof(struct busdevice), GFP_KERNEL);
+	if (!wax)
+		return -ENOMEM;
+
+	wax->name = "Wax";
+	wax->hpa = dev->hpa;
+
+	wax->version = 0;   /* gsc_readb(wax->hpa+WAX_VER); */
+	printk(KERN_INFO "%s at 0x%lx found.\n", wax->name, wax->hpa);
+
+	/* Stop wax hissing for a bit */
+	wax_init_irq(wax);
+
+	/* the IRQ wax should use */
+	irq = gsc_claim_irq(&gsc_irq, WAX_GSC_IRQ);
+	if (irq < 0) {
+		printk(KERN_ERR "%s(): cannot get GSC irq\n",
+				__FUNCTION__);
+		kfree(wax);
+		return -EBUSY;
+	}
+
+	ret = request_irq(gsc_irq.irq, busdev_barked, 0, "wax", wax);
+	if (ret < 0) {
+		kfree(wax);
+		return ret;
+	}
+
+	/* Save this for debugging later */
+	wax->parent_irq = gsc_irq.irq;
+	wax->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
+
+	/* enable IRQ's for devices below WAX */
+	gsc_writel(wax->eim, wax->hpa + OFFSET_IAR);
+
+	/* Done init'ing, register this driver */
+	ret = gsc_common_irqsetup(dev, wax);
+	if (ret) {
+		kfree(wax);
+		return ret;
+	}
+
+	fixup_child_irqs(dev, wax->busdev_region->data.irqbase,
+			wax_choose_irq);
+	/* On 715-class machines, Wax EISA is a sibling of Wax, not a child. */
+	if (dev->parent->id.hw_type != HPHW_IOA) {
+		fixup_child_irqs(dev->parent, wax->busdev_region->data.irqbase,
+				wax_choose_irq);
+	}
+
+	return ret;
+}
+
+static struct parisc_device_id wax_tbl[] = {
+  	{ HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008e },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, wax_tbl);
+
+struct parisc_driver wax_driver = {
+	name:		"Wax",
+	id_table:	wax_tbl,
+	probe:		wax_init_chip,
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hil/Config.in linux-2.4.20/drivers/hil/Config.in
--- linux-2.4.19/drivers/hil/Config.in	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/hil/Config.in	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,48 @@
+#
+# HIL device driver configuration
+#
+
+mainmenu_option next_comment
+comment 'HIL support'
+
+
+if [ "$CONFIG_INPUT" = "n" ]; then
+   comment 'Input support needed for HIL support'
+else
+   bool 'HIL core support' CONFIG_HIL
+
+   if [ "$CONFIG_HIL" != "n" ]; then
+    dep_tristate '  HIL Keyboard (basic) support' CONFIG_HIL_KBD_BASIC $CONFIG_INPUT_KEYBDEV
+
+    comment ' HIL driver core support'
+    tristate '  HP System Device Controller i8042 Support' CONFIG_HP_SDC
+    dep_tristate '  HP SDC Real Time Clock' CONFIG_HP_SDC_RTC $CONFIG_HP_SDC
+
+    dep_tristate '  HIL MLC Support' CONFIG_HIL_MLC $CONFIG_HP_SDC $CONFIG_INPUT_SERIO
+    if [ "$CONFIG_INPUT_SERIO" = "n"  ]; then
+      comment '  Serial IO support needed for HIL keyboard and mouse support'
+    else
+      # This is not accurate but for now it will save confusion.
+      define_tristate CONFIG_HP_SDC_MLC $CONFIG_HIL_MLC
+    fi
+    
+    comment ' HIL device driver'
+  
+    if [ "$CONFIG_HIL_MLC" != "n"  ]; then
+      if [ "$CONFIG_INPUT_KEYBDEV" = "n" ]; then
+        comment '  Keyboard input needed for HIL keyboard support'
+      else
+        dep_tristate '  HIL Keyboard (full) support' CONFIG_HIL_KBD $CONFIG_INPUT_KEYBDEV $CONFIG_HIL_MLC
+      fi
+
+      if [ "$CONFIG_INPUT_MOUSEDEV" = "n" ]; then
+        comment '  Mouse input support needed for HIL mouse/pointer support'
+      else
+        dep_tristate '  HIL Mouse & Pointer support' CONFIG_HIL_PTR $CONFIG_INPUT_MOUSEDEV $CONFIG_HIL_MLC
+      fi
+    fi
+
+   fi
+fi
+
+endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hil/Makefile linux-2.4.20/drivers/hil/Makefile
--- linux-2.4.19/drivers/hil/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/hil/Makefile	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,39 @@
+#
+# Makefile for the kernel HIL device drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+#
+
+O_TARGET := hil.o
+
+obj-y	 += 
+
+# All of the (potential) objects that export symbols.
+# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
+export-objs     :=	hp_sdc.o hil_mlc.o 
+
+mod-subdirs	:=	
+
+list-multi	:=	
+
+
+obj-$(CONFIG_HIL_KBD_BASIC)	+= hilkbd.o
+
+obj-$(CONFIG_HP_SDC)		+= hp_sdc.o
+obj-$(CONFIG_HP_SDC_MLC)	+= hp_sdc_mlc.o
+obj-$(CONFIG_HP_SDC_RTC)	+= hp_sdc_rtc.o
+obj-$(CONFIG_HIL_MLC)		+= hil_mlc.o
+
+obj-$(CONFIG_HIL_KBD)		+= hil_kbd.o
+obj-$(CONFIG_HIL_PTR)		+= hil_ptr.o
+
+
+include $(TOPDIR)/Rules.make
+
+fastdep:
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hil/hil_kbd.c linux-2.4.20/drivers/hil/hil_kbd.c
--- linux-2.4.19/drivers/hil/hil_kbd.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/hil/hil_kbd.c	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,458 @@
+/*
+ * Generic linux-input device driver for keyboard devices
+ *
+ * Copyright (c) 2001 Brian S. Julin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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
+ *
+ * References:
+ * HP-HIL Technical Reference Manual.  Hewlett Packard Product No. 45918A
+ *
+ */
+
+#include <linux/hil.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#ifdef DEBUG	/* DEBUG */
+#undef input_report_key
+#define input_report_key(a,b,c) { printk("input_report_key(%p, %d, %d)\n", a, b, !!(c)); input_event(a, EV_KEY, b, !!(c)); }
+#endif
+
+#define PREFIX "HIL KEYB: "
+#define HIL_GENERIC_NAME "generic HIL keyboard device"
+
+MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
+MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+#define HIL_KBD_MAX_LENGTH 16
+
+#define HIL_KBD_SET1_UPBIT 0x01
+#define HIL_KBD_SET1_SHIFT 1
+
+static uint8_t hil_kbd_set1[128] = {
+   KEY_5,		KEY_RESERVED,	KEY_RIGHTALT,	KEY_LEFTALT, 
+   KEY_RIGHTSHIFT,	KEY_LEFTSHIFT,	KEY_LEFTCTRL,	KEY_SYSRQ,
+   KEY_KP4,		KEY_KP8,	KEY_KP5,	KEY_KP9,
+   KEY_KP6,		KEY_KP7,	KEY_KPCOMMA,	KEY_KPENTER,
+   KEY_KP1,		KEY_KPSLASH,	KEY_KP2,	KEY_KPPLUS,
+   KEY_KP3,		KEY_KPASTERISK,	KEY_KP0,	KEY_KPMINUS,
+   KEY_B,		KEY_V,		KEY_C,		KEY_X,
+   KEY_Z,		KEY_UNKNOWN,	KEY_RESERVED,   KEY_ESC,
+   KEY_6,		KEY_F10,	KEY_3,		KEY_F11,
+   KEY_KPDOT,		KEY_F9,		KEY_TAB /*KP*/,	KEY_F12,
+   KEY_H,		KEY_G,		KEY_F,		KEY_D,
+   KEY_S,		KEY_A,		KEY_RESERVED,	KEY_CAPSLOCK,
+   KEY_U,		KEY_Y,		KEY_T,		KEY_R,
+   KEY_E,		KEY_W,		KEY_Q,		KEY_TAB,
+   KEY_7,		KEY_6,		KEY_5,		KEY_4,
+   KEY_3,		KEY_2,		KEY_1,		KEY_GRAVE,
+   KEY_INTL1,		KEY_INTL2,	KEY_INTL3,	KEY_INTL4, /*Buttons*/
+   KEY_INTL5,		KEY_INTL6,	KEY_INTL7,	KEY_INTL8,
+   KEY_MENU,		KEY_F4,		KEY_F3,		KEY_F2,
+   KEY_F1,		KEY_VOLUMEUP,	KEY_STOP,	KEY_SENDFILE/*Enter/Print*/, 
+   KEY_SYSRQ,		KEY_F5,		KEY_F6,		KEY_F7,
+   KEY_F8,		KEY_VOLUMEDOWN,	KEY_CUT /*CLEAR_LINE*/, KEY_REFRESH /*CLEAR_DISPLAY*/,
+   KEY_8,		KEY_9,		KEY_0,		KEY_MINUS,
+   KEY_EQUAL,		KEY_BACKSPACE,	KEY_INSERT/*KPINSERT_LINE*/, KEY_DELETE /*KPDELETE_LINE*/,
+   KEY_I,		KEY_O,		KEY_P,		KEY_LEFTBRACE,
+   KEY_RIGHTBRACE,	KEY_BACKSLASH,	KEY_INSERT,	KEY_DELETE,
+   KEY_J,		KEY_K,		KEY_L,		KEY_SEMICOLON,
+   KEY_APOSTROPHE,	KEY_ENTER,	KEY_HOME,	KEY_SCROLLUP,
+   KEY_M,		KEY_COMMA,	KEY_DOT,	KEY_SLASH,
+   KEY_RESERVED,	KEY_OPEN/*Select*/,KEY_RESERVED,KEY_SCROLLDOWN/*KPNEXT*/,
+   KEY_N,		KEY_SPACE,	KEY_SCROLLDOWN/*Next*/, KEY_UNKNOWN,
+   KEY_LEFT,		KEY_DOWN,	KEY_UP,		KEY_RIGHT
+};
+
+#define HIL_KBD_SET2_UPBIT 0x01
+#define HIL_KBD_SET2_SHIFT 1
+
+/* Set2 is user defined */
+
+#define HIL_KBD_SET3_UPBIT 0x80
+#define HIL_KBD_SET3_SHIFT 0
+
+static uint8_t hil_kbd_set3[128] = {
+  KEY_RESERVED,	KEY_ESC,	KEY_1,		KEY_2,
+  KEY_3,	KEY_4,		KEY_5,		KEY_6,
+  KEY_7,	KEY_8,		KEY_9,		KEY_0,
+  KEY_MINUS,	KEY_EQUAL,	KEY_BACKSPACE,	KEY_TAB,
+  KEY_Q,	KEY_W,		KEY_E,		KEY_R,
+  KEY_T,	KEY_Y,		KEY_U,		KEY_I,
+  KEY_O,	KEY_P,		KEY_LEFTBRACE,	KEY_RIGHTBRACE,
+  KEY_ENTER,	KEY_LEFTCTRL,	KEY_A,		KEY_S,
+  KEY_D,	KEY_F,		KEY_G,		KEY_H,
+  KEY_J,	KEY_K,		KEY_L,		KEY_SEMICOLON,
+  KEY_APOSTROPHE,KEY_GRAVE,	KEY_LEFTSHIFT,	KEY_BACKSLASH,
+  KEY_Z,	KEY_X,		KEY_C,		KEY_V,
+  KEY_B,	KEY_N,		KEY_M,		KEY_COMMA,
+  KEY_DOT,	KEY_SLASH,	KEY_RIGHTSHIFT,	KEY_KPASTERISK,
+  KEY_LEFTALT,	KEY_SPACE,	KEY_CAPSLOCK,	KEY_F1,
+  KEY_F2,	KEY_F3,		KEY_F4,		KEY_F5,
+  KEY_F6,	KEY_F7,		KEY_F8,		KEY_F9,
+  KEY_F10,	KEY_NUMLOCK,	KEY_SCROLLLOCK,	KEY_KP7,
+  KEY_KP8,	KEY_KP9,	KEY_KPMINUS,	KEY_KP4,
+  KEY_KP5,	KEY_KP6,	KEY_KPPLUS,	KEY_KP1,
+  KEY_KP2,	KEY_KP3,	KEY_KP0,	KEY_KPDOT,
+  KEY_SYSRQ,	KEY_RESERVED,	KEY_RESERVED,	KEY_RESERVED,
+  KEY_RESERVED,	KEY_RESERVED,	KEY_RESERVED,	KEY_RESERVED,
+  KEY_RESERVED,	KEY_RESERVED,	KEY_UNKNOWN,	KEY_UNKNOWN,
+  KEY_UP,	KEY_LEFT,	KEY_DOWN,	KEY_RIGHT,
+  KEY_HOME,	KEY_PAGEUP,	KEY_END,	KEY_PAGEDOWN,
+  KEY_INSERT,	KEY_DELETE,	KEY_102ND,	KEY_RESERVED,
+  KEY_RESERVED,	KEY_RESERVED,	KEY_RESERVED,	KEY_RESERVED,
+  KEY_F1,	KEY_F2,		KEY_F3,		KEY_F4,
+  KEY_F5,	KEY_F6,		KEY_F7,		KEY_F8,
+  KEY_RESERVED,	KEY_RESERVED,	KEY_RESERVED,	KEY_RESERVED,
+  KEY_RESERVED,	KEY_RESERVED,	KEY_RESERVED,	KEY_RESERVED
+};
+
+static char *hil_language[] = { HIL_LOCALE_MAP };
+
+struct hil_kbd {
+	struct input_dev dev;
+	struct serio *serio;
+
+	/* Input buffer and index for packets from HIL bus. */
+	hil_packet data[HIL_KBD_MAX_LENGTH];
+	int idx4; /* four counts per packet */
+
+	/* Raw device info records from HIL bus, see hil.h for fields. */
+	char	idd[HIL_KBD_MAX_LENGTH];	/* DID byte and IDD record */
+	char	rsc[HIL_KBD_MAX_LENGTH];	/* RSC record */
+	char	exd[HIL_KBD_MAX_LENGTH];	/* EXD record */
+	char	rnm[HIL_KBD_MAX_LENGTH + 1];	/* RNM record + NULL term. */
+
+	/* Something to sleep around with. */
+	struct semaphore sem;
+};
+
+/* Process a complete packet after transfer from the HIL */
+static void hil_kbd_process_record(struct hil_kbd *kbd)
+{
+	struct input_dev *dev = &kbd->dev;
+	hil_packet *data = kbd->data;
+	hil_packet p;
+	int idx, i, cnt;
+
+	idx = kbd->idx4/4;
+	p = data[idx - 1];
+
+	if ((p & ~HIL_CMDCT_POL) == 
+	    (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report;
+	if ((p & ~HIL_CMDCT_RPL) == 
+	    (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report;
+
+	/* Not a poll response.  See if we are loading config records. */
+	switch (p & HIL_PKT_DATA_MASK) {
+	case HIL_CMD_IDD:
+		for (i = 0; i < idx; i++)
+			kbd->idd[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
+		for (; i < HIL_KBD_MAX_LENGTH; i++)
+			kbd->idd[i] = 0;
+		break;
+	case HIL_CMD_RSC:
+		for (i = 0; i < idx; i++)
+			kbd->rsc[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
+		for (; i < HIL_KBD_MAX_LENGTH; i++)
+			kbd->rsc[i] = 0;
+		break;
+	case HIL_CMD_EXD:
+		for (i = 0; i < idx; i++)
+			kbd->exd[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
+		for (; i < HIL_KBD_MAX_LENGTH; i++)
+			kbd->exd[i] = 0;
+		break;
+	case HIL_CMD_RNM:
+		for (i = 0; i < idx; i++)
+			kbd->rnm[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
+		for (; i < HIL_KBD_MAX_LENGTH + 1; i++)
+			kbd->rnm[i] = '\0';
+		break;
+	default:
+		/* These occur when device isn't present */
+		if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break; 
+		/* Anything else we'd like to know about. */
+		printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
+		break;
+	}
+	goto out;
+
+ report:
+	cnt = 1;
+	switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) {
+	case HIL_POL_CHARTYPE_NONE:
+		break;
+	case HIL_POL_CHARTYPE_ASCII:
+		while (cnt < idx - 1)
+			input_report_key(dev, kbd->data[cnt++] & 0x7f, 1);
+		break;
+	case HIL_POL_CHARTYPE_RSVD1:
+	case HIL_POL_CHARTYPE_RSVD2:
+	case HIL_POL_CHARTYPE_BINARY:
+		while (cnt < idx - 1)
+			input_report_key(dev, kbd->data[cnt++], 1);
+		break;
+	case HIL_POL_CHARTYPE_SET1:
+		while (cnt < idx - 1) {
+			unsigned int key;
+			int up;
+			key = kbd->data[cnt++];
+			up = key & HIL_KBD_SET1_UPBIT;
+			key &= (~HIL_KBD_SET1_UPBIT & 0xff);
+			key = key >> HIL_KBD_SET1_SHIFT;
+			if (key != KEY_RESERVED && key != KEY_UNKNOWN)
+				input_report_key(dev, hil_kbd_set1[key], !up);
+		}
+		break;
+	case HIL_POL_CHARTYPE_SET2:
+		while (cnt < idx - 1) {
+			unsigned int key;
+			int up;
+			key = kbd->data[cnt++];
+			up = key & HIL_KBD_SET2_UPBIT;
+			key &= (~HIL_KBD_SET1_UPBIT & 0xff);
+			key = key >> HIL_KBD_SET2_SHIFT;
+			if (key != KEY_RESERVED && key != KEY_UNKNOWN)
+				input_report_key(dev, key, !up);
+		}
+		break;
+	case HIL_POL_CHARTYPE_SET3:
+		while (cnt < idx - 1) {
+			unsigned int key;
+			int up;
+			key = kbd->data[cnt++];
+			up = key & HIL_KBD_SET3_UPBIT;
+			key &= (~HIL_KBD_SET1_UPBIT & 0xff);
+			key = key >> HIL_KBD_SET3_SHIFT;
+			if (key != KEY_RESERVED && key != KEY_UNKNOWN)
+				input_report_key(dev, hil_kbd_set3[key], !up);
+		}
+		break;
+	}
+ out:
+	kbd->idx4 = 0;
+	up(&kbd->sem);
+}
+
+static void hil_kbd_process_err(struct hil_kbd *kbd) {
+	printk(KERN_WARNING PREFIX "errored HIL packet\n");
+	kbd->idx4 = 0;
+	up(&kbd->sem);
+	return;
+}
+
+static void hil_kbd_interrupt(struct serio *serio, 
+			      unsigned char data, 
+			      unsigned int flags)
+{
+	struct hil_kbd *kbd;
+	hil_packet packet;
+	int idx;
+
+	kbd = (struct hil_kbd *)serio->private;
+	if (kbd == NULL) {
+		BUG();
+		return;
+	}
+
+	if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) {
+		hil_kbd_process_err(kbd);
+		return;
+	}
+	idx = kbd->idx4/4;
+	if (!(kbd->idx4 % 4)) kbd->data[idx] = 0;
+	packet = kbd->data[idx];
+	packet |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8);
+	kbd->data[idx] = packet;
+
+	/* Records of N 4-byte hil_packets must terminate with a command. */
+	if ((++(kbd->idx4)) % 4) return;
+	if ((packet & 0xffff0000) != HIL_ERR_INT) {
+		hil_kbd_process_err(kbd);
+		return;
+	}
+	if (packet & HIL_PKT_CMD) hil_kbd_process_record(kbd);
+}
+
+static void hil_kbd_disconnect(struct serio *serio)
+{
+	struct hil_kbd *kbd;
+
+	kbd = (struct hil_kbd *)serio->private;
+	if (kbd == NULL) {
+		BUG();
+		return;
+	}
+
+	input_unregister_device(&kbd->dev);
+	serio_close(serio);
+	kfree(kbd);
+}
+
+static void hil_kbd_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct hil_kbd	*kbd;
+	uint8_t		did, *idd;
+	int		i;
+	
+	if (serio->type != (SERIO_HIL_MLC | SERIO_HIL)) return;
+
+	if (!(kbd = kmalloc(sizeof(struct hil_kbd), GFP_KERNEL))) return;
+	memset(kbd, 0, sizeof(struct hil_kbd));
+
+	if (serio_open(serio, dev)) goto bail0;
+
+	serio->private = kbd;
+	kbd->serio = serio;
+	kbd->dev.private = kbd;
+
+	init_MUTEX_LOCKED(&(kbd->sem));
+
+	/* Get device info.  MLC driver supplies devid/status/etc. */
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_IDD);
+	down(&(kbd->sem));
+
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_RSC);
+	down(&(kbd->sem));
+
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_RNM);
+	down(&(kbd->sem));
+
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_EXD);
+	down(&(kbd->sem));
+
+	up(&(kbd->sem));
+
+	did = kbd->idd[0];
+	idd = kbd->idd + 1;
+	switch (did & HIL_IDD_DID_TYPE_MASK) {
+	case HIL_IDD_DID_TYPE_KB_INTEGRAL:
+	case HIL_IDD_DID_TYPE_KB_ITF:
+	case HIL_IDD_DID_TYPE_KB_RSVD:
+	case HIL_IDD_DID_TYPE_CHAR:
+		printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n",
+			did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]);
+		break;
+	default:
+		goto bail1;
+	}
+
+	if(HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) {
+		printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n");
+		goto bail1;
+	}
+
+	kbd->dev.name = strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME;
+
+	kbd->dev.idbus		= BUS_HIL;
+	kbd->dev.idvendor	= SERIO_HIL;
+	kbd->dev.idproduct	= 0x0001; /* TODO: get from kbd->rsc */
+	kbd->dev.idversion	= 0x0100; /* TODO: get from kbd->rsc */
+
+	kbd->dev.evbit[0] |= BIT(EV_KEY);
+
+	for (i = 0; i < 128; i++) {
+		set_bit(hil_kbd_set1[i], kbd->dev.keybit);
+		set_bit(hil_kbd_set3[i], kbd->dev.keybit);
+	}
+	clear_bit(0, kbd->dev.keybit);
+
+#if 1
+	/* XXX: HACK !!!
+	 * remove this call if hp_psaux.c/hp_keyb.c is converted
+	 * to the input layer... */
+	register_ps2_keybfuncs();
+#endif
+	
+	input_register_device(&kbd->dev);
+	printk(KERN_INFO "input%d: %s on hil%d\n",
+		kbd->dev.number, "HIL keyboard", 0);
+
+	/* HIL keyboards don't have a numlock key,
+	 * simulate a up-down sequence of numlock to 
+	 * make the keypad work at expected. */
+	input_report_key(&kbd->dev, KEY_NUMLOCK, 1);
+/*	input_report_key(&kbd->dev, KEY_NUMLOCK, 0); */
+
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */
+	down(&(kbd->sem));
+	up(&(kbd->sem));
+
+	return;
+ bail1:
+	serio_close(serio);
+ bail0:
+	kfree(kbd);
+	return;
+}
+
+
+struct serio_dev hil_kbd_serio_dev = {
+	connect:	hil_kbd_connect,
+	disconnect:	hil_kbd_disconnect,
+	interrupt:	hil_kbd_interrupt
+};
+
+static int __init hil_kbd_init(void)
+{
+	serio_register_device(&hil_kbd_serio_dev);
+        return 0;
+}
+                
+static void __exit hil_kbd_exit(void)
+{
+	serio_unregister_device(&hil_kbd_serio_dev);
+
+#if 1
+	/* XXX: HACK !!!
+	 * remove this call if hp_psaux.c/hp_keyb.c is converted
+	 * to the input layer... */
+	unregister_kbd_ops();
+#endif
+}
+                        
+module_init(hil_kbd_init);
+module_exit(hil_kbd_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hil/hil_mlc.c linux-2.4.20/drivers/hil/hil_mlc.c
--- linux-2.4.19/drivers/hil/hil_mlc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/hil/hil_mlc.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,951 @@
+/*
+ * HIL MLC state machine and serio interface driver
+ *
+ * Copyright (c) 2001 Brian S. Julin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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
+ *
+ * References:
+ * HP-HIL Technical Reference Manual.  Hewlett Packard Product No. 45918A
+ *
+ *
+ *	Driver theory of operation:
+ *
+ *	Some access methods and an ISR is defined by the sub-driver 
+ *	(e.g. hp_sdc_mlc.c).  These methods are expected to provide a 
+ *	few bits of logic in addition to raw access to the HIL MLC, 
+ *	specifically, the ISR, which is entirely registered by the 
+ *	sub-driver and invoked directly, must check for record 
+ *	termination or packet match, at which point a semaphore must
+ *	be cleared and then the hil_mlcs_tasklet must be scheduled.
+ *
+ *	The hil_mlcs_tasklet processes the state machine for all MLCs
+ *	each time it runs, checking each MLC's progress at the current
+ *	node in the state machine, and moving the MLC to subsequent nodes
+ *	in the state machine when appropriate.  It will reschedule
+ *	itself if output is pending.  (This rescheduling should be replaced
+ *	at some point with a sub-driver-specific mechanism.)
+ *
+ *	A timer task prods the tasket once per second to prevent 
+ *	hangups when attached devices do not return expected data
+ *	and to initiate probes of the loop for new devices.
+ */
+
+#include <linux/hil_mlc.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+
+MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
+MODULE_DESCRIPTION("HIL MLC serio");
+MODULE_LICENSE("Dual BSD/GPL");
+
+EXPORT_SYMBOL(hil_mlc_register);
+EXPORT_SYMBOL(hil_mlc_unregister);
+
+#define PREFIX "HIL MLC: "
+
+static LIST_HEAD(hil_mlcs);
+static rwlock_t			hil_mlcs_lock = RW_LOCK_UNLOCKED;
+static struct timer_list	hil_mlcs_kicker;
+static int			hil_mlcs_probe;
+
+static void hil_mlcs_process(unsigned long unused);
+DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0);
+
+
+/* #define HIL_MLC_DEBUG */
+
+/********************** Device info/instance management **********************/
+
+static void hil_mlc_clear_di_map (hil_mlc *mlc, int val) {
+	int j;
+	for (j = val; j < 7 ; j++) {
+		mlc->di_map[j] = -1;
+	}
+}
+
+static void hil_mlc_clear_di_scratch (hil_mlc *mlc) {
+	memset(&(mlc->di_scratch), 0, sizeof(mlc->di_scratch));
+}
+
+static void hil_mlc_copy_di_scratch (hil_mlc *mlc, int idx) {
+	memcpy(&(mlc->di[idx]), &(mlc->di_scratch), sizeof(mlc->di_scratch));
+}
+
+static int hil_mlc_match_di_scratch (hil_mlc *mlc) {
+	int idx;
+
+	for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
+		int j, found;
+
+		/* In-use slots are not eligible. */
+		found = 0;
+		for (j = 0; j < 7 ; j++) {
+			if (mlc->di_map[j] == idx) found++;
+		}
+		if (found) continue;
+		if (!memcmp(mlc->di + idx, 
+			    &(mlc->di_scratch), 
+			    sizeof(mlc->di_scratch))) break;
+	}
+	return((idx >= HIL_MLC_DEVMEM) ? -1 : idx);
+}
+
+static int hil_mlc_find_free_di(hil_mlc *mlc) {
+	int idx;
+	/* TODO: Pick all-zero slots first, failing that, 
+	 * randomize the slot picked among those eligible. 
+	 */
+	for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
+		int j, found;
+		found = 0;
+		for (j = 0; j < 7 ; j++) {
+			if (mlc->di_map[j] == idx) found++;
+		}
+		if (!found) break;
+	}
+	return(idx); /* Note: It is guaranteed at least one above will match */
+}
+
+static inline void hil_mlc_clean_serio_map(hil_mlc *mlc) {
+	int idx;
+	for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
+		int j, found;
+		found = 0;
+		for (j = 0; j < 7 ; j++) {
+			if (mlc->di_map[j] == idx) found++;
+		}
+		if (!found) mlc->serio_map[idx].di_revmap = -1;
+	}
+}
+
+static void hil_mlc_send_polls(hil_mlc *mlc) {
+	int did, i, cnt;
+	struct serio *serio;
+	struct serio_dev *dev;
+
+	i = cnt = 0;
+	did = (mlc->ipacket[0] & HIL_PKT_ADDR_MASK) >> 8;
+	serio = did ? &(mlc->serio[mlc->di_map[did - 1]]) : NULL;
+	dev = (serio != NULL) ? serio->dev : NULL;
+
+	while (mlc->icount < 15 - i) {
+		hil_packet p;
+		p = mlc->ipacket[i];
+		if (did != (p & HIL_PKT_ADDR_MASK) >> 8) {
+			if (dev == NULL || dev->interrupt == NULL) goto skip;
+
+			dev->interrupt(serio, 0, 0);
+			dev->interrupt(serio, HIL_ERR_INT >> 16, 0);
+			dev->interrupt(serio, HIL_PKT_CMD >> 8, 0);
+			dev->interrupt(serio, HIL_CMD_POL + cnt, 0);
+		skip:
+			did = (p & HIL_PKT_ADDR_MASK) >> 8;
+			serio = did ? &(mlc->serio[mlc->di_map[did-1]]) : NULL;
+			dev = (serio != NULL) ? serio->dev : NULL;
+			cnt = 0;
+		}
+		cnt++; i++;
+		if (dev == NULL || dev->interrupt == NULL) continue;
+		dev->interrupt(serio, (p >> 24), 0);
+		dev->interrupt(serio, (p >> 16) & 0xff, 0);
+		dev->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0);
+		dev->interrupt(serio, p & 0xff, 0);
+	}
+}
+
+/*************************** State engine *********************************/
+
+#define HILSEN_SCHED	0x000100	/* Schedule the tasklet		*/
+#define HILSEN_BREAK	0x000200	/* Wait until next pass		*/
+#define HILSEN_UP	0x000400	/* relative node#, decrement	*/
+#define HILSEN_DOWN	0x000800	/* relative node#, increment	*/
+#define HILSEN_FOLLOW	0x001000	/* use retval as next node#	*/
+
+#define HILSEN_MASK	0x0000ff
+#define HILSEN_START	0
+#define HILSEN_RESTART	1
+#define HILSEN_DHR	9
+#define HILSEN_DHR2	10
+#define HILSEN_IFC	14
+#define HILSEN_HEAL0	16
+#define HILSEN_HEAL	18
+#define HILSEN_ACF      21
+#define HILSEN_ACF2	22
+#define HILSEN_DISC0	25
+#define HILSEN_DISC	27
+#define HILSEN_MATCH	40
+#define HILSEN_OPERATE	41
+#define HILSEN_PROBE	44
+#define HILSEN_DSR	52
+#define HILSEN_REPOLL	55
+#define HILSEN_IFCACF	58
+#define HILSEN_END	60
+
+#define HILSEN_NEXT	(HILSEN_DOWN | 1)
+#define HILSEN_SAME	(HILSEN_DOWN | 0)
+#define HILSEN_LAST	(HILSEN_UP | 1)
+
+#define HILSEN_DOZE	(HILSEN_SAME | HILSEN_SCHED | HILSEN_BREAK)
+#define HILSEN_SLEEP	(HILSEN_SAME | HILSEN_BREAK)
+
+static int hilse_match(hil_mlc *mlc, int unused) {
+	int rc;
+	rc = hil_mlc_match_di_scratch(mlc);
+	if (rc == -1) {
+		rc = hil_mlc_find_free_di(mlc);
+		if (rc == -1) goto err;
+#ifdef HIL_MLC_DEBUG
+		printk(KERN_DEBUG PREFIX "new in slot %i\n", rc);
+#endif
+		hil_mlc_copy_di_scratch(mlc, rc);
+		mlc->di_map[mlc->ddi] = rc;
+		mlc->serio_map[rc].di_revmap = mlc->ddi;
+		hil_mlc_clean_serio_map(mlc);
+		serio_rescan(mlc->serio + rc);
+		return -1;
+	}
+	mlc->di_map[mlc->ddi] = rc;
+#ifdef HIL_MLC_DEBUG
+	printk(KERN_DEBUG PREFIX "same in slot %i\n", rc);
+#endif
+	mlc->serio_map[rc].di_revmap = mlc->ddi;
+	hil_mlc_clean_serio_map(mlc);
+	return 0;
+ err:
+	printk(KERN_ERR PREFIX "Residual device slots exhausted, close some serios!\n");
+	return 1;
+}
+
+/* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */
+static int hilse_init_lcv(hil_mlc *mlc, int unused) {
+	struct timeval tv;
+
+	do_gettimeofday(&tv);
+
+	if(mlc->lcv == 0) goto restart;  /* First init, no need to dally */
+	if(tv.tv_sec - mlc->lcv_tv.tv_sec < 5) return -1;
+ restart:
+	mlc->lcv_tv = tv;
+	mlc->lcv = 0;
+	return 0;
+}
+
+static int hilse_inc_lcv(hil_mlc *mlc, int lim) {
+	if (mlc->lcv++ >= lim) return -1;
+	return 0;
+}
+
+#if 0
+static int hilse_set_lcv(hil_mlc *mlc, int val) {
+	mlc->lcv = val;
+	return 0;
+}
+#endif
+
+/* Management of the discovered device index (zero based, -1 means no devs) */
+static int hilse_set_ddi(hil_mlc *mlc, int val) {
+	mlc->ddi = val;
+	hil_mlc_clear_di_map(mlc, val + 1);
+	return 0;
+}
+
+static int hilse_dec_ddi(hil_mlc *mlc, int unused) {
+	mlc->ddi--;
+	if (mlc->ddi <= -1) { 
+		mlc->ddi = -1;
+		hil_mlc_clear_di_map(mlc, 0);
+		return -1;
+	}
+	hil_mlc_clear_di_map(mlc, mlc->ddi + 1);
+	return 0;
+}
+
+static int hilse_inc_ddi(hil_mlc *mlc, int unused) {
+	if (mlc->ddi >= 6) {
+		BUG();
+		return -1;
+	}
+	mlc->ddi++;
+	return 0;
+}
+
+static int hilse_take_idd(hil_mlc *mlc, int unused) {
+	int i;
+
+	/* Help the state engine: 
+	 * Is this a real IDD response or just an echo? 
+	 *
+	 * Real IDD response does not start with a command. 
+	 */
+	if (mlc->ipacket[0] & HIL_PKT_CMD) goto bail;
+	/* Should have the command echoed further down. */
+	for (i = 1; i < 16; i++) {
+		if (((mlc->ipacket[i] & HIL_PKT_ADDR_MASK) == 
+		     (mlc->ipacket[0] & HIL_PKT_ADDR_MASK)) &&
+		    (mlc->ipacket[i] & HIL_PKT_CMD) && 
+		    ((mlc->ipacket[i] & HIL_PKT_DATA_MASK) == HIL_CMD_IDD))
+			break;
+	}
+	if (i > 15) goto bail;
+	/* And the rest of the packets should still be clear. */
+	while (++i < 16) {
+		if (mlc->ipacket[i]) break;
+	}
+	if (i < 16) goto bail;
+	for (i = 0; i < 16; i++) {
+		mlc->di_scratch.idd[i] = 
+			mlc->ipacket[i] & HIL_PKT_DATA_MASK;
+	}
+	/* Next step is to see if RSC supported */
+	if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_RSC) 
+		return HILSEN_NEXT;
+	if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD) 
+		return HILSEN_DOWN | 4;
+	return 0;
+ bail:
+	mlc->ddi--;
+	return -1; /* This should send us off to ACF */
+}
+
+static int hilse_take_rsc(hil_mlc *mlc, int unused) {
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		mlc->di_scratch.rsc[i] = 
+			mlc->ipacket[i] & HIL_PKT_DATA_MASK;
+	}
+	/* Next step is to see if EXD supported (IDD has already been read) */
+	if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD) 
+		return HILSEN_NEXT;
+	return 0;
+}
+
+static int hilse_take_exd(hil_mlc *mlc, int unused) {
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		mlc->di_scratch.exd[i] = 
+			mlc->ipacket[i] & HIL_PKT_DATA_MASK;
+	}
+	/* Next step is to see if RNM supported. */
+	if (mlc->di_scratch.exd[0] & HIL_EXD_HEADER_RNM) 
+		return HILSEN_NEXT;
+	return 0;
+}
+
+static int hilse_take_rnm(hil_mlc *mlc, int unused) {
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		mlc->di_scratch.rnm[i] = 
+			mlc->ipacket[i] & HIL_PKT_DATA_MASK;
+	}
+	do {
+	  char nam[17];
+	  snprintf(nam, 16, "%s", mlc->di_scratch.rnm);
+	  nam[16] = '\0';
+	  printk(KERN_INFO PREFIX "Device name gotten: %s\n", nam);
+	} while (0);
+	return 0;
+}
+
+static int hilse_operate(hil_mlc *mlc, int repoll) { 
+
+	if (mlc->opercnt == 0) hil_mlcs_probe = 0;
+	mlc->opercnt = 1;
+
+	hil_mlc_send_polls(mlc);
+
+	if (!hil_mlcs_probe) return 0;
+	hil_mlcs_probe = 0;
+	mlc->opercnt = 0;
+	return 1;
+}
+
+#define FUNC(funct, funct_arg, zero_rc, neg_rc, pos_rc) \
+{ HILSE_FUNC,		{ func: &funct }, funct_arg, zero_rc, neg_rc, pos_rc },
+#define OUT(pack) \
+{ HILSE_OUT,		{ packet: pack }, 0, HILSEN_NEXT, HILSEN_DOZE, 0 },
+#define CTS \
+{ HILSE_CTS,		{ packet: 0    }, 0, HILSEN_NEXT | HILSEN_SCHED | HILSEN_BREAK, HILSEN_DOZE, 0 },
+#define EXPECT(comp, to, got, got_wrong, timed_out) \
+{ HILSE_EXPECT,		{ packet: comp }, to, got, got_wrong, timed_out },
+#define EXPECT_LAST(comp, to, got, got_wrong, timed_out) \
+{ HILSE_EXPECT_LAST,	{ packet: comp }, to, got, got_wrong, timed_out },
+#define EXPECT_DISC(comp, to, got, got_wrong, timed_out) \
+{ HILSE_EXPECT_DISC,	{ packet: comp }, to, got, got_wrong, timed_out },
+#define IN(to, got, got_error, timed_out) \
+{ HILSE_IN,		{ packet: 0    }, to, got, got_error, timed_out },
+#define OUT_DISC(pack) \
+{ HILSE_OUT_DISC,	{ packet: pack }, 0, 0, 0, 0 },
+#define OUT_LAST(pack) \
+{ HILSE_OUT_LAST,	{ packet: pack }, 0, 0, 0, 0 },
+
+struct hilse_node hil_mlc_se[HILSEN_END] = {
+
+	/* 0  HILSEN_START */
+	FUNC(hilse_init_lcv, 0,	HILSEN_NEXT,	HILSEN_SLEEP,	0)
+
+	/* 1  HILSEN_RESTART */
+	FUNC(hilse_inc_lcv, 10,	HILSEN_NEXT,	HILSEN_START,  0)
+	OUT(HIL_CTRL_ONLY)			/* Disable APE */
+	CTS
+
+#define TEST_PACKET(x) \
+(HIL_PKT_CMD | (x << HIL_PKT_ADDR_SHIFT) | x << 4 | x)
+
+	OUT(HIL_DO_ALTER_CTRL | HIL_CTRL_TEST | TEST_PACKET(0x5))
+	EXPECT(HIL_ERR_INT | TEST_PACKET(0x5),
+	       2000,		HILSEN_NEXT,	HILSEN_RESTART,	HILSEN_RESTART)
+	OUT(HIL_DO_ALTER_CTRL | HIL_CTRL_TEST | TEST_PACKET(0xa))
+	EXPECT(HIL_ERR_INT | TEST_PACKET(0xa),
+	       2000,		HILSEN_NEXT,	HILSEN_RESTART,	HILSEN_RESTART)
+	OUT(HIL_CTRL_ONLY | 0)			/* Disable test mode */
+	
+	/* 9  HILSEN_DHR */
+	FUNC(hilse_init_lcv, 0,	HILSEN_NEXT,	HILSEN_SLEEP,	0)
+
+	/* 10 HILSEN_DHR2 */
+	FUNC(hilse_inc_lcv, 10,	HILSEN_NEXT,	HILSEN_START,	0)
+	FUNC(hilse_set_ddi, -1,	HILSEN_NEXT,	0,		0)
+	OUT(HIL_PKT_CMD | HIL_CMD_DHR)
+	IN(300000,		HILSEN_DHR2,	HILSEN_DHR2,	HILSEN_NEXT)
+
+	/* 14 HILSEN_IFC */
+  	OUT(HIL_PKT_CMD | HIL_CMD_IFC)
+	EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT,
+	       20000,		HILSEN_DISC,	HILSEN_DHR2,	HILSEN_NEXT )
+
+	/* If devices are there, they weren't in PUP or other loopback mode.
+	 * We're more concerned at this point with restoring operation
+	 * to devices than discovering new ones, so we try to salvage
+	 * the loop configuration by closing off the loop.
+	 */
+
+	/* 16 HILSEN_HEAL0 */
+	FUNC(hilse_dec_ddi, 0,	HILSEN_NEXT,	HILSEN_ACF,	0)
+	FUNC(hilse_inc_ddi, 0,	HILSEN_NEXT,	0,		0)
+
+	/* 18 HILSEN_HEAL */
+	OUT_LAST(HIL_CMD_ELB)
+	EXPECT_LAST(HIL_CMD_ELB | HIL_ERR_INT, 
+		    20000,	HILSEN_REPOLL,	HILSEN_DSR,	HILSEN_NEXT)
+	FUNC(hilse_dec_ddi, 0,	HILSEN_HEAL,	HILSEN_NEXT,	0)
+
+	/* 21 HILSEN_ACF */
+	FUNC(hilse_init_lcv, 0,	HILSEN_NEXT,	HILSEN_DOZE,	0)
+
+	/* 22 HILSEN_ACF2 */
+	FUNC(hilse_inc_lcv, 10,	HILSEN_NEXT,	HILSEN_START,	0)
+	OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1)
+	IN(20000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_NEXT)
+
+	/* 25 HILSEN_DISC0 */
+	OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB)
+	EXPECT_DISC(HIL_PKT_CMD | HIL_CMD_ELB | HIL_ERR_INT,
+	       20000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_DSR)
+
+	/* Only enter here if response just received */
+	/* 27 HILSEN_DISC */
+	OUT_DISC(HIL_PKT_CMD | HIL_CMD_IDD)
+	EXPECT_DISC(HIL_PKT_CMD | HIL_CMD_IDD | HIL_ERR_INT,
+	       20000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_START)
+	FUNC(hilse_inc_ddi,  0,	HILSEN_NEXT,	HILSEN_START,	0)
+	FUNC(hilse_take_idd, 0,	HILSEN_MATCH,	HILSEN_IFCACF,	HILSEN_FOLLOW)
+	OUT_LAST(HIL_PKT_CMD | HIL_CMD_RSC)
+	EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_RSC | HIL_ERR_INT,
+	       30000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_DSR)
+	FUNC(hilse_take_rsc, 0,	HILSEN_MATCH,	0,		HILSEN_FOLLOW)
+	OUT_LAST(HIL_PKT_CMD | HIL_CMD_EXD)
+	EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_EXD | HIL_ERR_INT,
+	       30000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_DSR)
+	FUNC(hilse_take_exd, 0,	HILSEN_MATCH,	0,		HILSEN_FOLLOW)
+	OUT_LAST(HIL_PKT_CMD | HIL_CMD_RNM)
+	EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_RNM | HIL_ERR_INT,
+	       30000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_DSR)
+	FUNC(hilse_take_rnm, 0, HILSEN_MATCH,	0,		0)
+
+	/* 40 HILSEN_MATCH */
+	FUNC(hilse_match, 0,	HILSEN_NEXT,	HILSEN_NEXT,	/* TODO */ 0)
+
+	/* 41 HILSEN_OPERATE */
+	OUT(HIL_PKT_CMD | HIL_CMD_POL)
+	EXPECT(HIL_PKT_CMD | HIL_CMD_POL | HIL_ERR_INT,
+	       20000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_NEXT)
+	FUNC(hilse_operate, 0,	HILSEN_OPERATE,	HILSEN_IFC,	HILSEN_NEXT)
+
+	/* 44 HILSEN_PROBE */
+	OUT_LAST(HIL_PKT_CMD | HIL_CMD_EPT)
+	IN(10000, 		HILSEN_DISC,	HILSEN_DSR,	HILSEN_NEXT)
+	OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB)
+	IN(10000,		HILSEN_DISC,	HILSEN_DSR,	HILSEN_NEXT)
+	OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1)
+	IN(10000,		HILSEN_DISC0,	HILSEN_DSR,	HILSEN_NEXT)
+	OUT_LAST(HIL_PKT_CMD | HIL_CMD_ELB)
+	IN(10000,		HILSEN_OPERATE,	HILSEN_DSR,	HILSEN_DSR)
+
+	/* 52 HILSEN_DSR */
+	FUNC(hilse_set_ddi, -1,	HILSEN_NEXT,	0,		0)
+	OUT(HIL_PKT_CMD | HIL_CMD_DSR)
+	IN(20000, 		HILSEN_DHR,	HILSEN_DHR,	HILSEN_IFC)
+
+	/* 55 HILSEN_REPOLL */
+	OUT(HIL_PKT_CMD | HIL_CMD_RPL)
+	EXPECT(HIL_PKT_CMD | HIL_CMD_RPL | HIL_ERR_INT,
+	       20000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_NEXT)
+	FUNC(hilse_operate, 1,	HILSEN_OPERATE,	HILSEN_IFC,	HILSEN_PROBE)
+
+	/* 58 HILSEN_IFCACF */
+  	OUT(HIL_PKT_CMD | HIL_CMD_IFC)
+	EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT,
+	       20000,		HILSEN_ACF2,	HILSEN_DHR2,	HILSEN_HEAL)
+
+	/* 60 HILSEN_END */
+};
+
+static inline void hilse_setup_input(hil_mlc *mlc, struct hilse_node *node) {
+
+	switch (node->act) {
+	case HILSE_EXPECT_DISC:
+		mlc->imatch = node->object.packet;
+		mlc->imatch |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT);
+		break;
+	case HILSE_EXPECT_LAST:
+		mlc->imatch = node->object.packet;
+		mlc->imatch |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT);
+		break;
+	case HILSE_EXPECT:
+		mlc->imatch = node->object.packet;
+		break;
+	case HILSE_IN:
+		mlc->imatch = 0;
+		break;
+	default:
+		BUG();
+	}
+	mlc->istarted = 1;
+	mlc->intimeout = node->arg;
+	do_gettimeofday(&(mlc->instart));
+	mlc->icount = 15;
+	memset(mlc->ipacket, 0, 16 * sizeof(hil_packet));
+	if (down_trylock(&(mlc->isem))) BUG();
+
+	return;
+}
+
+#ifdef HIL_MLC_DEBUG
+static int doze = 0;
+static int seidx; /* For debug */
+static int kick = 1;
+#endif
+
+static int hilse_donode (hil_mlc *mlc) {
+	struct hilse_node *node;
+	int nextidx = 0;
+	int sched_long = 0;
+	unsigned long flags;
+
+#ifdef HIL_MLC_DEBUG
+	if (mlc->seidx && (mlc->seidx != seidx)  && mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) {
+	  printk(KERN_DEBUG PREFIX "z%i \n%s {%i}", doze, kick ? "K" : "", mlc->seidx);
+		doze = 0;
+	}
+	kick = 0;
+
+	seidx = mlc->seidx;
+#endif
+	node = hil_mlc_se + mlc->seidx;
+
+	switch (node->act) {
+		int rc;
+		hil_packet pack;
+
+	case HILSE_FUNC:
+		if (node->object.func == NULL) break;
+		rc = node->object.func(mlc, node->arg);
+		nextidx = (rc > 0) ? node->ugly : 
+			((rc < 0) ? node->bad : node->good);
+		if (nextidx == HILSEN_FOLLOW) nextidx = rc;
+		break;
+	case HILSE_EXPECT_LAST:
+	case HILSE_EXPECT_DISC:
+	case HILSE_EXPECT:
+	case HILSE_IN:
+		/* Already set up from previous HILSE_OUT_* */
+		write_lock_irqsave(&(mlc->lock), flags);
+		rc = mlc->in(mlc, node->arg);
+		if (rc == 2)  {
+			nextidx = HILSEN_DOZE;
+			sched_long = 1;
+			write_unlock_irqrestore(&(mlc->lock), flags);
+			break;
+		}
+		if (rc == 1)		nextidx = node->ugly;
+		else if (rc == 0)	nextidx = node->good;
+		else			nextidx = node->bad;
+		mlc->istarted = 0;
+		write_unlock_irqrestore(&(mlc->lock), flags);
+		break;
+	case HILSE_OUT_LAST:
+		write_lock_irqsave(&(mlc->lock), flags);
+		pack = node->object.packet;
+		pack |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT);
+		goto out;
+	case HILSE_OUT_DISC:
+		write_lock_irqsave(&(mlc->lock), flags);
+		pack = node->object.packet;
+		pack |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT);
+		goto out;
+	case HILSE_OUT:
+		write_lock_irqsave(&(mlc->lock), flags);
+		pack = node->object.packet;
+	out:
+		if (mlc->istarted) goto out2;
+		/* Prepare to receive input */
+		if ((node + 1)->act & HILSE_IN)
+			hilse_setup_input(mlc, node + 1);
+
+	out2:
+		write_unlock_irqrestore(&(mlc->lock), flags);
+
+		if (down_trylock(&mlc->osem)) {
+			nextidx = HILSEN_DOZE;
+			break;
+		}
+		up(&mlc->osem);
+
+		write_lock_irqsave(&(mlc->lock), flags);
+		if (!(mlc->ostarted)) {
+			mlc->ostarted = 1;
+			mlc->opacket = pack;
+			mlc->out(mlc);
+			nextidx = HILSEN_DOZE;
+			write_unlock_irqrestore(&(mlc->lock), flags);
+			break;
+		}
+		mlc->ostarted = 0;
+		do_gettimeofday(&(mlc->instart));
+		write_unlock_irqrestore(&(mlc->lock), flags);
+		nextidx = HILSEN_NEXT;
+		break;
+	case HILSE_CTS:
+		nextidx = mlc->cts(mlc) ? node->bad : node->good;
+		break;
+	default:
+		BUG();
+		nextidx = 0;
+		break;
+	}
+
+#ifdef HIL_MLC_DEBUG
+	if (nextidx == HILSEN_DOZE) doze++;
+#endif
+
+	while (nextidx & HILSEN_SCHED) {
+		struct timeval tv;
+
+		if (!sched_long) goto sched;
+
+		do_gettimeofday(&tv);
+		tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec);
+		tv.tv_usec -= mlc->instart.tv_usec;
+		if (tv.tv_usec >= mlc->intimeout) goto sched;
+		tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / 1000000;
+		if (!tv.tv_usec) goto sched;
+		mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec);
+		break;
+	sched:
+		tasklet_schedule(&hil_mlcs_tasklet);
+		break;
+	} 
+	if (nextidx & HILSEN_DOWN) mlc->seidx += nextidx & HILSEN_MASK;
+	else if (nextidx & HILSEN_UP) mlc->seidx -= nextidx & HILSEN_MASK;
+	else mlc->seidx = nextidx & HILSEN_MASK;
+
+	if (nextidx & HILSEN_BREAK)	return 1;
+	return 0;
+}
+
+/******************** tasklet context functions **************************/
+static void hil_mlcs_process(unsigned long unused) {
+	struct list_head *tmp;
+
+	read_lock(&hil_mlcs_lock);
+	list_for_each(tmp, &hil_mlcs) {
+		struct hil_mlc *mlc = list_entry(tmp, hil_mlc, list);
+		while (hilse_donode(mlc) == 0) {
+#ifdef HIL_MLC_DEBUG
+		  if (mlc->seidx != 41 && 
+		      mlc->seidx != 42 && 
+		      mlc->seidx != 43) 
+		    printk(KERN_DEBUG PREFIX " + ");
+#endif
+		};
+	}
+	read_unlock(&hil_mlcs_lock);
+}
+
+/************************* Keepalive timer task *********************/
+
+void hil_mlcs_timer (unsigned long data) {
+	hil_mlcs_probe = 1;
+	tasklet_schedule(&hil_mlcs_tasklet);
+	/* Re-insert the periodic task. */
+	if (!timer_pending(&hil_mlcs_kicker))
+		mod_timer(&hil_mlcs_kicker, jiffies + HZ);
+}
+
+/******************** user/kernel context functions **********************/
+
+static int hil_mlc_serio_write(struct serio *serio, unsigned char c) {
+	struct hil_mlc_serio_map *map;
+	struct hil_mlc *mlc;
+	struct serio_dev *dev;
+	uint8_t *idx, *last;
+
+	map = serio->driver;
+	if (map == NULL) {
+		BUG();
+		return -EIO;
+	}
+	mlc = map->mlc;
+	if (mlc == NULL) {
+		BUG();
+		return -EIO;
+	}
+	mlc->serio_opacket[map->didx] |= 
+		((hil_packet)c) << (8 * (3 - mlc->serio_oidx[map->didx]));
+
+	if (mlc->serio_oidx[map->didx] >= 3) {
+		/* for now only commands */
+		if (!(mlc->serio_opacket[map->didx] & HIL_PKT_CMD)) 
+			return -EIO;
+		switch (mlc->serio_opacket[map->didx] & HIL_PKT_DATA_MASK) {
+		case HIL_CMD_IDD:
+			idx = mlc->di[map->didx].idd;
+			goto emu;
+		case HIL_CMD_RSC:
+			idx = mlc->di[map->didx].rsc;
+			goto emu;
+		case HIL_CMD_EXD:
+			idx = mlc->di[map->didx].exd;
+			goto emu;
+		case HIL_CMD_RNM:
+			idx = mlc->di[map->didx].rnm;
+			goto emu;
+		default:
+			break;
+		}
+		mlc->serio_oidx[map->didx] = 0;
+		mlc->serio_opacket[map->didx] = 0;
+	}
+
+	mlc->serio_oidx[map->didx]++;
+	return -EIO;
+ emu:
+	dev = serio->dev;
+	if (dev == NULL) {
+		BUG();
+		return -EIO;
+	}
+	last = idx + 15;
+	while ((last != idx) && (*last == 0)) last--;
+
+	while (idx != last) {
+		dev->interrupt(serio, 0, 0);
+		dev->interrupt(serio, HIL_ERR_INT >> 16, 0);
+		dev->interrupt(serio, 0, 0);
+		dev->interrupt(serio, *idx, 0);
+		idx++;
+	}
+	dev->interrupt(serio, 0, 0);
+	dev->interrupt(serio, HIL_ERR_INT >> 16, 0);
+	dev->interrupt(serio, HIL_PKT_CMD >> 8, 0);
+	dev->interrupt(serio, *idx, 0);
+	
+	mlc->serio_oidx[map->didx] = 0;
+	mlc->serio_opacket[map->didx] = 0;
+
+	return 0;
+}
+
+static int hil_mlc_serio_open(struct serio *serio) {
+	struct hil_mlc_serio_map *map;
+	struct hil_mlc *mlc;
+
+	if (serio->private != NULL) return -EBUSY;
+
+	map = serio->driver;
+	if (map == NULL) {
+		BUG();
+		return -ENODEV;
+	}
+	mlc = map->mlc;
+	if (mlc == NULL) {
+		BUG();
+		return -ENODEV;
+	}
+
+	mlc->inc_use_count();
+
+	return 0;
+}
+
+static void hil_mlc_serio_close(struct serio *serio) {
+	struct hil_mlc_serio_map *map;
+	struct hil_mlc *mlc;
+
+	map = serio->driver;
+	if (map == NULL) {
+		BUG();
+		return;
+	}
+	mlc = map->mlc;
+	if (mlc == NULL) {
+		BUG();
+		return;
+	}
+
+	mlc->dec_use_count();
+
+	serio->private = NULL;
+	serio->dev = NULL;
+	/* TODO wake up interruptable */
+}
+
+int hil_mlc_register(hil_mlc *mlc) {
+	int i;
+        unsigned long flags;
+
+	MOD_INC_USE_COUNT;
+	if (mlc == NULL) {
+		MOD_DEC_USE_COUNT;
+		return -EINVAL;
+	}
+
+	mlc->istarted = 0;
+        mlc->ostarted = 0;
+
+        mlc->lock = RW_LOCK_UNLOCKED;
+        init_MUTEX(&(mlc->osem));
+
+        init_MUTEX(&(mlc->isem));
+        mlc->icount = -1;
+        mlc->imatch = 0;
+
+	mlc->opercnt = 0;
+
+        init_MUTEX_LOCKED(&(mlc->csem));
+
+	hil_mlc_clear_di_scratch(mlc);
+	hil_mlc_clear_di_map(mlc, 0);
+	for (i = 0; i < HIL_MLC_DEVMEM; i++) {
+		hil_mlc_copy_di_scratch(mlc, i);
+		memset(&(mlc->serio[i]), 0, sizeof(mlc->serio[0]));
+		mlc->serio[i].type		= SERIO_HIL | SERIO_HIL_MLC;
+		mlc->serio[i].write		= hil_mlc_serio_write;
+		mlc->serio[i].open		= hil_mlc_serio_open;
+		mlc->serio[i].close		= hil_mlc_serio_close;
+		mlc->serio[i].driver		= &(mlc->serio_map[i]);
+		mlc->serio_map[i].mlc		= mlc;
+		mlc->serio_map[i].didx		= i;
+		mlc->serio_map[i].di_revmap	= -1;
+		mlc->serio_opacket[i]		= 0;
+		mlc->serio_oidx[i]		= 0;
+		serio_register_port(&(mlc->serio[i]));
+	}
+
+	mlc->tasklet = &hil_mlcs_tasklet;
+
+	write_lock_irqsave(&hil_mlcs_lock, flags);
+	list_add_tail(&mlc->list, &hil_mlcs);
+	mlc->seidx = HILSEN_START;
+	write_unlock_irqrestore(&hil_mlcs_lock, flags);
+
+	tasklet_schedule(&hil_mlcs_tasklet);
+	return 0;
+}
+
+int hil_mlc_unregister(hil_mlc *mlc) {
+	struct list_head *tmp;
+        unsigned long flags;
+	int i;
+
+	if (mlc == NULL)
+		return -EINVAL;
+
+	write_lock_irqsave(&hil_mlcs_lock, flags);
+	list_for_each(tmp, &hil_mlcs) {
+		if (list_entry(tmp, hil_mlc, list) == mlc)
+			goto found;
+	}
+
+	/* not found in list */
+	write_unlock_irqrestore(&hil_mlcs_lock, flags);
+	tasklet_schedule(&hil_mlcs_tasklet);
+	return -ENODEV;
+
+ found:
+	list_del(tmp);
+        write_unlock_irqrestore(&hil_mlcs_lock, flags);
+	MOD_DEC_USE_COUNT;
+
+	for (i = 0; i < HIL_MLC_DEVMEM; i++)
+		serio_unregister_port(&(mlc->serio[i]));
+
+	tasklet_schedule(&hil_mlcs_tasklet);
+	return 0;
+}
+
+/**************************** Module interface *************************/
+
+static int __init hil_mlc_init(void)
+{
+	init_timer(&hil_mlcs_kicker);
+	hil_mlcs_kicker.expires = jiffies + HZ;
+	hil_mlcs_kicker.function = &hil_mlcs_timer;
+	add_timer(&hil_mlcs_kicker);
+
+	tasklet_enable(&hil_mlcs_tasklet);
+
+	return 0;
+}
+                
+static void __exit hil_mlc_exit(void)
+{
+	del_timer(&hil_mlcs_kicker);
+
+	tasklet_disable(&hil_mlcs_tasklet);
+	tasklet_kill(&hil_mlcs_tasklet);
+}
+                        
+module_init(hil_mlc_init);
+module_exit(hil_mlc_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hil/hil_ptr.c linux-2.4.20/drivers/hil/hil_ptr.c
--- linux-2.4.19/drivers/hil/hil_ptr.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/hil/hil_ptr.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,406 @@
+/*
+ * Generic linux-input device driver for axis-bearing devices
+ *
+ * Copyright (c) 2001 Brian S. Julin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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
+ *
+ * References:
+ * HP-HIL Technical Reference Manual.  Hewlett Packard Product No. 45918A
+ *
+ */
+
+#include <linux/hil.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#define PREFIX "HIL PTR: "
+#define HIL_GENERIC_NAME "generic HIL pointer device"
+
+MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
+MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+
+#define TABLET_SIMULATES_MOUSE	/* allow tablet to be used as mouse */
+#undef  TABLET_AUTOADJUST	/* auto-adjust valid tablet ranges */
+
+
+#define HIL_PTR_MAX_LENGTH 16
+
+struct hil_ptr {
+	struct input_dev dev;
+	struct serio *serio;
+
+	/* Input buffer and index for packets from HIL bus. */
+	hil_packet data[HIL_PTR_MAX_LENGTH];
+	int idx4; /* four counts per packet */
+
+	/* Raw device info records from HIL bus, see hil.h for fields. */
+	char	idd[HIL_PTR_MAX_LENGTH];	/* DID byte and IDD record */
+	char	rsc[HIL_PTR_MAX_LENGTH];	/* RSC record */
+	char	exd[HIL_PTR_MAX_LENGTH];	/* EXD record */
+	char	rnm[HIL_PTR_MAX_LENGTH + 1];	/* RNM record + NULL term. */
+
+	/* Extra device details not contained in struct input_dev. */
+	unsigned int nbtn, naxes;
+	unsigned int btnmap[7];
+
+	/* Something to sleep around with. */
+	struct semaphore sem;
+};
+
+/* Process a complete packet after transfer from the HIL */
+static void hil_ptr_process_record(struct hil_ptr *ptr)
+{
+	struct input_dev *dev = &ptr->dev;
+	hil_packet *data = ptr->data;
+	hil_packet p;
+	int idx, i, cnt, laxis;
+	int ax16, absdev;
+
+	idx = ptr->idx4/4;
+	p = data[idx - 1];
+
+	if ((p & ~HIL_CMDCT_POL) == 
+	    (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report;
+	if ((p & ~HIL_CMDCT_RPL) == 
+	    (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report;
+
+	/* Not a poll response.  See if we are loading config records. */
+	switch (p & HIL_PKT_DATA_MASK) {
+	case HIL_CMD_IDD:
+		for (i = 0; i < idx; i++)
+			ptr->idd[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
+		for (; i < HIL_PTR_MAX_LENGTH; i++)
+			ptr->idd[i] = 0;
+		break;
+	case HIL_CMD_RSC:
+		for (i = 0; i < idx; i++)
+			ptr->rsc[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
+		for (; i < HIL_PTR_MAX_LENGTH; i++)
+			ptr->rsc[i] = 0;
+		break;
+	case HIL_CMD_EXD:
+		for (i = 0; i < idx; i++)
+			ptr->exd[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
+		for (; i < HIL_PTR_MAX_LENGTH; i++)
+			ptr->exd[i] = 0;
+		break;
+	case HIL_CMD_RNM:
+		for (i = 0; i < idx; i++)
+			ptr->rnm[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
+		for (; i < HIL_PTR_MAX_LENGTH + 1; i++)
+			ptr->rnm[i] = '\0';
+		break;
+	default:
+		/* These occur when device isn't present */
+		if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break; 
+		/* Anything else we'd like to know about. */
+		printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
+		break;
+	}
+	goto out;
+
+ report:
+	if ((p & HIL_CMDCT_POL) != idx - 1) {
+		printk(KERN_WARNING PREFIX "Malformed poll packet %x (idx = %i)\n", p, idx);
+		goto out;
+	}
+
+	i = (ptr->data[0] & HIL_POL_AXIS_ALT) ? 3 : 0;
+	laxis = ptr->data[0] & HIL_POL_NUM_AXES_MASK;
+	laxis += i;
+
+	ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */
+	absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS; 
+
+	for (cnt = 1; i < laxis; i++) {
+		unsigned int lo,hi,val;
+		lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK;
+		hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0;
+		if (absdev) {
+			val = lo + (hi<<8);
+#ifdef TABLET_AUTOADJUST
+			if (val < ptr->dev.absmin[ABS_X + i])
+				ptr->dev.absmin[ABS_X + i] = val;
+			if (val > ptr->dev.absmax[ABS_X + i])
+				ptr->dev.absmax[ABS_X + i] = val;
+#endif
+			if (i%3) val = ptr->dev.absmax[ABS_X + i] - val;
+			input_report_abs(dev, ABS_X + i, val);
+		} else {
+			val = (int) (((int8_t)lo) | ((int8_t)hi<<8));
+			if (i%3) val *= -1;
+			input_report_rel(dev, REL_X + i, val);
+		}
+	}
+
+	while (cnt < idx - 1) {
+		unsigned int btn;
+		int up;
+		btn = ptr->data[cnt++];
+		up = btn & 1;
+		btn &= 0xfe;
+		if (btn == 0x8e) {
+			continue; /* TODO: proximity == touch? */
+		}
+		else if ((btn > 0x8c) || (btn < 0x80)) continue;
+		btn = (btn - 0x80) >> 1;
+		btn = ptr->btnmap[btn];
+		input_report_key(dev, btn, !up);
+	}
+ out:
+	ptr->idx4 = 0;
+	up(&ptr->sem);
+}
+
+static void hil_ptr_process_err(struct hil_ptr *ptr) {
+	printk(KERN_WARNING PREFIX "errored HIL packet\n");
+	ptr->idx4 = 0;
+	up(&ptr->sem);
+	return;
+}
+
+static void hil_ptr_interrupt(struct serio *serio, 
+			      unsigned char data, 
+			      unsigned int flags)
+{
+	struct hil_ptr *ptr;
+	hil_packet packet;
+	int idx;
+
+	ptr = (struct hil_ptr *)serio->private;
+	if (ptr == NULL) {
+		BUG();
+		return;
+	}
+
+	if (ptr->idx4 >= (HIL_PTR_MAX_LENGTH * sizeof(hil_packet))) {
+		hil_ptr_process_err(ptr);
+		return;
+	}
+	idx = ptr->idx4/4;
+	if (!(ptr->idx4 % 4)) ptr->data[idx] = 0;
+	packet = ptr->data[idx];
+	packet |= ((hil_packet)data) << ((3 - (ptr->idx4 % 4)) * 8);
+	ptr->data[idx] = packet;
+
+	/* Records of N 4-byte hil_packets must terminate with a command. */
+	if ((++(ptr->idx4)) % 4) return;
+	if ((packet & 0xffff0000) != HIL_ERR_INT) {
+		hil_ptr_process_err(ptr);
+		return;
+	}
+	if (packet & HIL_PKT_CMD) 
+		hil_ptr_process_record(ptr);
+}
+
+static void hil_ptr_disconnect(struct serio *serio)
+{
+	struct hil_ptr *ptr;
+
+	ptr = (struct hil_ptr *)serio->private;
+	if (ptr == NULL) {
+		BUG();
+		return;
+	}
+
+	input_unregister_device(&ptr->dev);
+	serio_close(serio);
+	kfree(ptr);
+}
+
+static void hil_ptr_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct hil_ptr	*ptr;
+	char		*txt;
+	unsigned int	i, naxsets, btntype;
+	uint8_t		did, *idd;
+
+	if (serio->type != (SERIO_HIL_MLC | SERIO_HIL)) return;
+
+	if (!(ptr = kmalloc(sizeof(struct hil_ptr), GFP_KERNEL))) return;
+	memset(ptr, 0, sizeof(struct hil_ptr));
+
+	if (serio_open(serio, dev)) goto bail0;
+
+	serio->private = ptr;
+	ptr->serio = serio;
+	ptr->dev.private = ptr;
+
+	init_MUTEX_LOCKED(&(ptr->sem));
+
+	/* Get device info.  MLC driver supplies devid/status/etc. */
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_IDD);
+	down(&(ptr->sem));
+
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_RSC);
+	down(&(ptr->sem));
+
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_RNM);
+	down(&(ptr->sem));
+
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_EXD);
+	down(&(ptr->sem));
+
+	up(&(ptr->sem));
+
+	did = ptr->idd[0];
+	idd = ptr->idd + 1;
+	txt = "unknown";
+	if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
+		ptr->dev.evbit[0] = BIT(EV_REL);
+		txt = "relative";
+	}
+
+	if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_ABS) {
+		ptr->dev.evbit[0] = BIT(EV_ABS);
+		txt = "absolute";
+	}
+	if (!ptr->dev.evbit[0]) {
+		goto bail1;
+	}
+
+	ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd);
+	if (ptr->nbtn) ptr->dev.evbit[0] |= BIT(EV_KEY);
+
+	naxsets = HIL_IDD_NUM_AXSETS(*idd);
+	ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);
+
+	printk(KERN_INFO PREFIX "HIL pointer device found (did: 0x%02x, axis: %s)\n",
+			did, txt);
+	printk(KERN_INFO PREFIX "HIL pointer has %i buttons and %i sets of %i axes\n",
+			ptr->nbtn, naxsets, ptr->naxes);
+	
+	btntype = BTN_MISC;
+	if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET)
+#ifdef TABLET_SIMULATES_MOUSE
+		btntype = BTN_TOUCH;
+#else
+		btntype = BTN_DIGI;
+#endif
+	if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN)
+		btntype = BTN_TOUCH;
+		
+	if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE)
+		btntype = BTN_MOUSE;
+
+	for (i = 0; i < ptr->nbtn; i++) {
+		set_bit(btntype | i, ptr->dev.keybit);
+		ptr->btnmap[i] = btntype | i;
+	}
+
+	if (btntype == BTN_MOUSE) {
+		/* Swap buttons 2 and 3 */
+		ptr->btnmap[1] = BTN_MIDDLE;
+		ptr->btnmap[2] = BTN_RIGHT;
+	}
+
+	if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
+		for (i = 0; i < ptr->naxes; i++) {
+			set_bit(REL_X + i, ptr->dev.relbit);
+		}
+		for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) {
+			set_bit(REL_X + i, ptr->dev.relbit);
+		}
+	} else {
+		for (i = 0; i < ptr->naxes; i++) {
+	  		set_bit(ABS_X + i, ptr->dev.absbit);
+			ptr->dev.absmin[ABS_X + i] = 0;
+			ptr->dev.absmax[ABS_X + i] = 
+				HIL_IDD_AXIS_MAX((ptr->idd + 1), i);
+		}
+		for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) {
+			set_bit(ABS_X + i, ptr->dev.absbit);
+			ptr->dev.absmin[ABS_X + i] = 0;
+			ptr->dev.absmax[ABS_X + i] = 
+				HIL_IDD_AXIS_MAX((ptr->idd + 1), (i - 3));
+		}
+#ifdef TABLET_AUTOADJUST
+		for (i = 0; i < ABS_MAX; i++) {
+			int diff = ptr->dev.absmax[ABS_X + i] / 10;
+			ptr->dev.absmin[ABS_X + i] += diff;
+			ptr->dev.absmax[ABS_X + i] -= diff;
+		}
+#endif
+	}
+
+	ptr->dev.name = strlen(ptr->rnm) ? ptr->rnm : HIL_GENERIC_NAME;
+
+	ptr->dev.idbus = BUS_HIL;
+	ptr->dev.idvendor = SERIO_HIL;
+	ptr->dev.idproduct = 0x0001; /* TODO: get from ptr->rsc */
+	ptr->dev.idversion = 0x0100; /* TODO: get from ptr->rsc */
+
+	input_register_device(&ptr->dev);
+	printk(KERN_INFO "input%d: %s on hil%d\n",
+		ptr->dev.number, 
+		(btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad",
+		0);
+
+	return;
+ bail1:
+	serio_close(serio);
+ bail0:
+	kfree(ptr);
+	return;
+}
+
+
+struct serio_dev hil_ptr_serio_dev = {
+	connect: hil_ptr_connect,
+	disconnect: hil_ptr_disconnect,
+	interrupt: hil_ptr_interrupt
+};
+
+static int __init hil_ptr_init(void)
+{
+	serio_register_device(&hil_ptr_serio_dev);
+        return 0;
+}
+                
+static void __exit hil_ptr_exit(void)
+{
+	serio_unregister_device(&hil_ptr_serio_dev);
+}
+                        
+module_init(hil_ptr_init);
+module_exit(hil_ptr_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hil/hilkbd.c linux-2.4.20/drivers/hil/hilkbd.c
--- linux-2.4.19/drivers/hil/hilkbd.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/hil/hilkbd.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,389 @@
+/*
+ *  linux/drivers/hil/hilkbd.c
+ *
+ *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *  Copyright (C) 1999 Matthew Wilcox <willy@bofh.ai>
+ *  Copyright (C) 1999-2002 Helge Deller <deller@gmx.de>
+ *
+ *  Very basic HP Human Interface Loop (HIL) driver.
+ *  This driver handles the keyboard on HP300 (m68k) and on some 
+ *  HP700 (parisc) series machines.
+ *
+ * 
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License version 2.  See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+#include <linux/pci_ids.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/hil.h>
+
+
+MODULE_AUTHOR("Philip Blundell, Matthew Wilcox, Helge Deller");
+MODULE_DESCRIPTION("HIL driver (basic functionality)");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
+
+
+#if defined(CONFIG_PARISC)
+
+ #include <asm/gsc.h>
+ #include <asm/hardware.h>
+ static unsigned long hil_base;	/* HPA for the HIL device */
+ static unsigned int hil_irq;
+ #define HILBASE		hil_base /* HPPA (parisc) port address */
+ #define HIL_DATA		0x800
+ #define HIL_CMD		0x801
+ #define HIL_IRQ		hil_irq
+ #define hil_readb(p)		gsc_readb(p)
+ #define hil_writeb(v,p)	gsc_writeb((v),(p))
+
+#elif defined(CONFIG_HP300)
+
+ #define HILBASE		0xf0428000 /* HP300 (m86k) port address */
+ #define HIL_DATA		0x1
+ #define HIL_CMD		0x3
+ #define HIL_IRQ		2
+ #define hil_readb(p)		readb(p)
+ #define hil_writeb(v,p)	writeb((v),(p))
+
+#else
+#error "HIL is not supported on this platform"
+#endif
+
+
+ 
+/* HIL helper functions */
+ 
+#define hil_busy()              (hil_readb(HILBASE + HIL_CMD) & HIL_BUSY)
+#define hil_data_available()    (hil_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY)
+#define hil_status()            (hil_readb(HILBASE + HIL_CMD))
+#define hil_command(x)          do { hil_writeb((x), HILBASE + HIL_CMD); } while (0)
+#define hil_read_data()         (hil_readb(HILBASE + HIL_DATA))
+#define hil_write_data(x)       do { hil_writeb((x), HILBASE + HIL_DATA); } while (0)
+
+/* HIL constants */
+ 
+#define	HIL_BUSY		0x02
+#define	HIL_DATA_RDY		0x01
+
+#define	HIL_SETARD		0xA0		/* set auto-repeat delay */
+#define	HIL_SETARR		0xA2		/* set auto-repeat rate */
+#define	HIL_SETTONE		0xA3		/* set tone generator */
+#define	HIL_CNMT		0xB2		/* clear nmi */
+#define	HIL_INTON		0x5C		/* Turn on interrupts. */
+#define	HIL_INTOFF		0x5D		/* Turn off interrupts. */
+#define	HIL_TRIGGER		0xC5		/* trigger command */
+#define	HIL_STARTCMD		0xE0		/* start loop command */
+#define	HIL_TIMEOUT		0xFE		/* timeout */
+#define	HIL_READTIME		0x13		/* Read real time register */
+
+#define	HIL_READBUSY		0x02		/* internal "busy" register */
+#define	HIL_READKBDLANG		0x12		/* read keyboard language code */
+#define	HIL_READKBDSADR	 	0xF9
+#define	HIL_WRITEKBDSADR 	0xE9
+#define	HIL_READLPSTAT  	0xFA
+#define	HIL_WRITELPSTAT 	0xEA
+#define	HIL_READLPCTRL  	0xFB
+#define	HIL_WRITELPCTRL 	0xEB
+
+
+static unsigned char hil_kbd_set1[128] = {
+   KEY_5,		KEY_RESERVED,	KEY_RIGHTALT,	KEY_LEFTALT, 
+   KEY_RIGHTSHIFT,	KEY_LEFTSHIFT,	KEY_LEFTCTRL,	KEY_SYSRQ,
+   KEY_KP4,		KEY_KP8,	KEY_KP5,	KEY_KP9,
+   KEY_KP6,		KEY_KP7,	KEY_KPCOMMA,	KEY_KPENTER,
+   KEY_KP1,		KEY_KPSLASH,	KEY_KP2,	KEY_KPPLUS,
+   KEY_KP3,		KEY_KPASTERISK,	KEY_KP0,	KEY_KPMINUS,
+   KEY_B,		KEY_V,		KEY_C,		KEY_X,
+   KEY_Z,		KEY_UNKNOWN,	KEY_RESERVED,   KEY_ESC,
+   KEY_6,		KEY_F10,	KEY_3,		KEY_F11,
+   KEY_KPDOT,		KEY_F9,		KEY_TAB /*KP*/,	KEY_F12,
+   KEY_H,		KEY_G,		KEY_F,		KEY_D,
+   KEY_S,		KEY_A,		KEY_RESERVED,	KEY_CAPSLOCK,
+   KEY_U,		KEY_Y,		KEY_T,		KEY_R,
+   KEY_E,		KEY_W,		KEY_Q,		KEY_TAB,
+   KEY_7,		KEY_6,		KEY_5,		KEY_4,
+   KEY_3,		KEY_2,		KEY_1,		KEY_GRAVE,
+   KEY_INTL1,		KEY_INTL2,	KEY_INTL3,	KEY_INTL4, /*Buttons*/
+   KEY_INTL5,		KEY_INTL6,	KEY_INTL7,	KEY_INTL8,
+   KEY_MENU,		KEY_F4,		KEY_F3,		KEY_F2,
+   KEY_F1,		KEY_VOLUMEUP,	KEY_STOP,	KEY_SENDFILE/*Enter/Print*/, 
+   KEY_SYSRQ,		KEY_F5,		KEY_F6,		KEY_F7,
+   KEY_F8,		KEY_VOLUMEDOWN,	KEY_CUT /*CLEAR_LINE*/, KEY_REFRESH /*CLEAR_DISPLAY*/,
+   KEY_8,		KEY_9,		KEY_0,		KEY_MINUS,
+   KEY_EQUAL,		KEY_BACKSPACE,	KEY_INSERT/*KPINSERT_LINE*/, KEY_DELETE /*KPDELETE_LINE*/,
+   KEY_I,		KEY_O,		KEY_P,		KEY_LEFTBRACE,
+   KEY_RIGHTBRACE,	KEY_BACKSLASH,	KEY_INSERT,	KEY_DELETE,
+   KEY_J,		KEY_K,		KEY_L,		KEY_SEMICOLON,
+   KEY_APOSTROPHE,	KEY_ENTER,	KEY_HOME,	KEY_SCROLLUP,
+   KEY_M,		KEY_COMMA,	KEY_DOT,	KEY_SLASH,
+   KEY_RESERVED,	KEY_OPEN/*Select*/,KEY_RESERVED,KEY_SCROLLDOWN/*KPNEXT*/,
+   KEY_N,		KEY_SPACE,	KEY_SCROLLDOWN/*Next*/, KEY_UNKNOWN,
+   KEY_LEFT,		KEY_DOWN,	KEY_UP,		KEY_RIGHT
+};
+
+
+/* HIL structure */
+static struct {
+	struct input_dev dev;
+
+	unsigned int curdev;
+	
+	unsigned char s;
+	unsigned char c;
+	int valid;
+	
+	unsigned char data[16];
+	unsigned int ptr;
+
+	void *dev_id;	/* native bus device */
+} hil_dev;
+
+
+static void poll_finished(void)
+{
+	int down;
+	int key;
+	unsigned char scode;
+	
+	switch (hil_dev.data[0]) {
+	case 0x40:
+		down = (hil_dev.data[1] & 1) == 0;
+		scode = hil_dev.data[1] >> 1;
+		key = hil_kbd_set1[scode & 0x7f];
+		input_report_key(&hil_dev.dev, key, down);
+		break;
+	}
+	hil_dev.curdev = 0;
+}
+
+static inline void handle_status(unsigned char s, unsigned char c)
+{
+	if (c & 0x8) {
+		/* End of block */
+		if (c & 0x10)
+			poll_finished();
+	} else {
+		if (c & 0x10) {
+			if (hil_dev.curdev)
+				poll_finished();  /* just in case */
+			hil_dev.curdev = c & 7;
+			hil_dev.ptr = 0;
+		}
+	}
+}
+
+static inline void handle_data(unsigned char s, unsigned char c)
+{
+	if (hil_dev.curdev) {
+		hil_dev.data[hil_dev.ptr++] = c;
+		hil_dev.ptr &= 15;
+	}
+}
+
+
+/* 
+ * Handle HIL interrupts.
+ */
+static void hil_interrupt(int irq, void *handle, struct pt_regs *regs)
+{
+	unsigned char s, c;
+	
+	s = hil_status();
+	c = hil_read_data();
+
+	switch (s >> 4) {
+	case 0x5:
+		handle_status(s, c);
+		break;
+	case 0x6:
+		handle_data(s, c);
+		break;
+	case 0x4:
+		hil_dev.s = s;
+		hil_dev.c = c;
+		mb();
+		hil_dev.valid = 1;
+		break;
+	}
+}
+
+/*
+ * Send a command to the HIL
+ */
+
+static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	while (hil_busy())
+		/* wait */;
+	hil_command(cmd);
+	while (len--) {
+		while (hil_busy())
+			/* wait */;
+		hil_write_data(*(data++));
+	}
+	restore_flags(flags);
+}
+
+
+/*
+ * Initialise HIL. 
+ */
+
+static int __init
+hil_keyb_init(void)
+{
+	unsigned char c;
+	unsigned int i, kbid, n = 0;
+
+	if (hil_dev.dev.idbus) {
+		printk("HIL: already initialized\n");
+		return -ENODEV;
+	}
+	
+#if defined(CONFIG_HP300)
+	if (!hwreg_present((void *)(HILBASE + HIL_DATA)))
+		return -ENODEV;
+	
+	request_region(HILBASE+HIL_DATA, 2, "hil");
+#endif
+	
+	request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id);
+
+	/* Turn on interrupts */
+	hil_do(HIL_INTON, NULL, 0);
+
+	/* Look for keyboards */
+	hil_dev.valid = 0;	/* clear any pending data */
+	hil_do(HIL_READKBDSADR, NULL, 0);
+	while (!hil_dev.valid) {
+		if (n++ > 100000) {
+			printk(KERN_DEBUG "HIL: timed out, assuming no keyboard present.\n");
+			break;
+		}
+		mb();
+	}
+
+	c = hil_dev.c; 
+	hil_dev.valid = 0;
+	if (c == 0) {
+		kbid = -1;
+		printk(KERN_WARNING "HIL: no keyboard present.\n");
+	} else {
+		kbid = ffz(~c);
+		printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid);
+	}
+
+	/* set it to raw mode */
+	c = 0;
+	hil_do(HIL_WRITEKBDSADR, &c, 1);
+	
+
+	/* register input interface */
+	hil_dev.dev.name 	= "HIL keyboard";
+	hil_dev.dev.idbus	= BUS_HIL;
+	hil_dev.dev.idvendor	= PCI_VENDOR_ID_HP;
+	hil_dev.dev.idproduct	= 0x0001;
+	hil_dev.dev.idversion	= 0x0100;
+
+	hil_dev.dev.evbit[0] |= BIT(EV_KEY);
+	for (i = 0; i < 128; i++)
+		set_bit(hil_kbd_set1[i], hil_dev.dev.keybit);
+	clear_bit(0, hil_dev.dev.keybit);
+
+#if 1
+	/* XXX: HACK !!!
+	 * remove this call if hp_psaux.c/hp_keyb.c is converted
+	 * to the input layer... */
+	register_ps2_keybfuncs();
+#endif
+	
+	input_register_device(&hil_dev.dev);
+	printk(KERN_INFO "input%d: %s on hil%d (id %d)\n",
+		hil_dev.dev.number, hil_dev.dev.name, 0, kbid);
+
+	/* HIL keyboards don't have a numlock key,
+	 * simulate a up-down sequence of numlock to 
+	 * make the keypad work at expected. */
+	input_report_key(&hil_dev.dev, KEY_NUMLOCK, 1);
+
+	return 0;
+}
+
+#if defined(CONFIG_PARISC)
+static int __init
+hil_init_chip(struct parisc_device *dev)
+{
+	if (!dev->irq) {
+		printk(KERN_WARNING "HIL: IRQ not found for HIL at 0x%lx\n", dev->hpa);
+		return -ENODEV;
+	}
+
+	hil_base = dev->hpa;
+	hil_irq  = dev->irq;
+	hil_dev.dev_id = dev;
+	
+	printk(KERN_INFO "Found HIL at 0x%lx, IRQ %d\n", hil_base, hil_irq);
+
+	return hil_keyb_init();
+}
+
+static struct parisc_device_id hil_tbl[] = {
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00073 },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, hil_tbl);
+
+static struct parisc_driver hil_driver = {
+	name:		"HIL",
+	id_table:	hil_tbl,
+	probe:		hil_init_chip,
+};
+#endif /* CONFIG_PARISC */
+
+
+
+
+
+static int __init hil_init(void)
+{
+#if defined(CONFIG_PARISC)
+	return register_parisc_driver(&hil_driver);
+#else
+	return hil_keyb_init();
+#endif
+}
+
+
+static void __exit hil_exit(void)
+{
+	if (HIL_IRQ) {
+		disable_irq(HIL_IRQ);
+		free_irq(HIL_IRQ, hil_dev.dev_id);
+	}
+
+	input_unregister_device(&hil_dev.dev);
+
+#if defined(CONFIG_PARISC)
+	unregister_parisc_driver(&hil_driver);
+#else
+	release_region(HILBASE+HIL_DATA, 2);
+#endif
+}
+
+module_init(hil_init);
+module_exit(hil_exit);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hil/hp_sdc.c linux-2.4.20/drivers/hil/hp_sdc.c
--- linux-2.4.19/drivers/hil/hp_sdc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/hil/hp_sdc.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,1012 @@
+/*
+ * HP i8042-based System Device Controller driver.
+ *
+ * Copyright (c) 2001 Brian S. Julin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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
+ *
+ * References:
+ * System Device Controller Microprocessor Firmware Theory of Operation
+ *      for Part Number 1820-4784 Revision B.  Dwg No. A-1820-4784-2
+ * Helge Deller's original hilkbd.c port for PA-RISC.
+ *
+ *
+ * Driver theory of operation:
+ *
+ * hp_sdc_put does all writing to the SDC.  ISR can run on a different 
+ * CPU than hp_sdc_put, but only one CPU runs hp_sdc_put at a time 
+ * (it cannot really benefit from SMP anyway.)  A tasket fit this perfectly.
+ *
+ * All data coming back from the SDC is sent via interrupt and can be read 
+ * fully in the ISR, so there are no latency/throughput problems there.  
+ * The problem is with output, due to the slow clock speed of the SDC 
+ * compared to the CPU.  This should not be too horrible most of the time, 
+ * but if used with HIL devices that support the multibyte transfer command, 
+ * keeping outbound throughput flowing at the 6500KBps that the HIL is 
+ * capable of is more than can be done at HZ=100.
+ *
+ * Busy polling for IBF clear wastes CPU cycles and bus cycles.  hp_sdc.ibf 
+ * is set to 0 when the IBF flag in the status register has cleared.  ISR 
+ * may do this, and may also access the parts of queued transactions related 
+ * to reading data back from the SDC, but otherwise will not touch the 
+ * hp_sdc state. Whenever a register is written hp_sdc.ibf is set to 1.
+ *
+ * The i8042 write index and the values in the 4-byte input buffer
+ * starting at 0x70 are kept track of in hp_sdc.wi, and .r7[], respectively,
+ * to minimize the amount of IO needed to the SDC.  However these values 
+ * do not need to be locked since they are only ever accessed by hp_sdc_put.
+ *
+ * A timer task schedules the tasklet once per second just to make
+ * sure it doesn't freeze up and to allow for bad reads to time out.
+ */
+
+#include <linux/hp_sdc.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/time.h>
+#include <linux/slab.h>
+#include <linux/hil.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <asm/gsc.h>
+
+#define PREFIX "HP SDC: "
+
+MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
+MODULE_DESCRIPTION("HP i8042-based SDC Driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+EXPORT_SYMBOL(hp_sdc_request_timer_irq);
+EXPORT_SYMBOL(hp_sdc_request_hil_irq);
+EXPORT_SYMBOL(hp_sdc_request_cooked_irq);
+
+EXPORT_SYMBOL(hp_sdc_release_timer_irq);
+EXPORT_SYMBOL(hp_sdc_release_hil_irq);
+EXPORT_SYMBOL(hp_sdc_release_cooked_irq);
+
+EXPORT_SYMBOL(hp_sdc_enqueue_transaction);
+EXPORT_SYMBOL(hp_sdc_dequeue_transaction);
+
+static hp_i8042_sdc	hp_sdc;	/* All driver state is kept in here. */
+
+/*************** primitives for use in any context *********************/
+static inline uint8_t hp_sdc_status_in8 (void) {
+	uint8_t status;
+	unsigned long flags;
+
+	write_lock_irqsave(&hp_sdc.ibf_lock, flags);
+	status = gsc_readb(hp_sdc.status_io);
+	if (!(status & HP_SDC_STATUS_IBF)) hp_sdc.ibf = 0;
+	write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
+
+	return status;
+}
+
+static inline uint8_t hp_sdc_data_in8 (void) {
+	return gsc_readb(hp_sdc.data_io); 
+}
+
+static inline void hp_sdc_status_out8 (uint8_t val) {
+	unsigned long flags;
+
+	write_lock_irqsave(&hp_sdc.ibf_lock, flags);
+	hp_sdc.ibf = 1;
+	if ((val & 0xf0) == 0xe0) hp_sdc.wi = 0xff;
+	gsc_writeb(val, hp_sdc.status_io);
+	write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
+}
+
+static inline void hp_sdc_data_out8 (uint8_t val) {
+	unsigned long flags;
+
+	write_lock_irqsave(&hp_sdc.ibf_lock, flags);
+	hp_sdc.ibf = 1;
+	gsc_writeb(val, hp_sdc.data_io);
+	write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
+}
+
+/*	Care must be taken to only invoke hp_sdc_spin_ibf when 
+ *	absolutely needed, or in rarely invoked subroutines.  
+ *	Not only does it waste CPU cycles, it also wastes bus cycles. 
+ */
+static inline void hp_sdc_spin_ibf(void) {
+	unsigned long flags;
+	rwlock_t *lock;
+
+	lock = &hp_sdc.ibf_lock;
+
+	read_lock_irqsave(lock, flags);
+	if (!hp_sdc.ibf) {
+		read_unlock_irqrestore(lock, flags);
+		return;
+	}
+	read_unlock(lock);
+	write_lock(lock);
+	while (gsc_readb(hp_sdc.status_io) & HP_SDC_STATUS_IBF) {};
+	hp_sdc.ibf = 0;
+	write_unlock_irqrestore(lock, flags);
+}
+
+
+/************************ Interrupt context functions ************************/
+static void hp_sdc_take (int irq, void *dev_id, uint8_t status, uint8_t data) {
+	hp_sdc_transaction *curr;
+
+	read_lock(&hp_sdc.rtq_lock);
+	if (hp_sdc.rcurr < 0) {
+	  	read_unlock(&hp_sdc.rtq_lock);
+		return;
+	}
+	curr = hp_sdc.tq[hp_sdc.rcurr];
+	read_unlock(&hp_sdc.rtq_lock);
+
+	curr->seq[curr->idx++] = status;
+	curr->seq[curr->idx++] = data;
+	hp_sdc.rqty -= 2;
+	do_gettimeofday(&hp_sdc.rtv);
+
+	if (hp_sdc.rqty <= 0) {
+		/* All data has been gathered. */
+		if(curr->seq[curr->actidx] & HP_SDC_ACT_SEMAPHORE) {
+			if (curr->act.semaphore) up(curr->act.semaphore);
+		}
+		if(curr->seq[curr->actidx] & HP_SDC_ACT_CALLBACK) {
+			if (curr->act.irqhook)
+				curr->act.irqhook(irq, dev_id, status, data);
+		}
+		curr->actidx = curr->idx;
+		curr->idx++;
+		/* Return control of this transaction */
+		write_lock(&hp_sdc.rtq_lock);
+		hp_sdc.rcurr = -1; 
+		hp_sdc.rqty = 0;
+		write_unlock(&hp_sdc.rtq_lock);
+		tasklet_schedule(&hp_sdc.task);
+	}
+}
+
+static void hp_sdc_isr(int irq, void *dev_id, struct pt_regs * regs) {
+	uint8_t status, data;
+
+	status = hp_sdc_status_in8();
+	/* Read data unconditionally to advance i8042. */
+	data =   hp_sdc_data_in8();
+
+	/* For now we are ignoring these until we get the SDC to behave. */
+	if (((status & 0xf1) == 0x51) && data == 0x82) {
+	  return;
+	}
+
+	switch(status & HP_SDC_STATUS_IRQMASK) {
+	      case 0: /* This case is not documented. */
+		break;
+	      case HP_SDC_STATUS_USERTIMER:
+	      case HP_SDC_STATUS_PERIODIC:
+	      case HP_SDC_STATUS_TIMER:
+		read_lock(&hp_sdc.hook_lock);
+	      	if (hp_sdc.timer != NULL)
+			hp_sdc.timer(irq, dev_id, status, data);
+		read_unlock(&hp_sdc.hook_lock);
+		break;
+	      case HP_SDC_STATUS_REG:
+		hp_sdc_take(irq, dev_id, status, data);
+		break;
+	      case HP_SDC_STATUS_HILCMD:
+	      case HP_SDC_STATUS_HILDATA:
+		read_lock(&hp_sdc.hook_lock);
+		if (hp_sdc.hil != NULL)
+			hp_sdc.hil(irq, dev_id, status, data);
+		read_unlock(&hp_sdc.hook_lock);
+		break;
+	      case HP_SDC_STATUS_PUP:
+		read_lock(&hp_sdc.hook_lock);
+		if (hp_sdc.pup != NULL)
+			hp_sdc.pup(irq, dev_id, status, data);
+		else printk(KERN_INFO PREFIX "HP SDC reports successful PUP.\n");
+		read_unlock(&hp_sdc.hook_lock);
+		break;
+	      default:
+		read_lock(&hp_sdc.hook_lock);
+		if (hp_sdc.cooked != NULL)
+			hp_sdc.cooked(irq, dev_id, status, data);
+		read_unlock(&hp_sdc.hook_lock);
+		break;
+	}
+}
+
+
+static void hp_sdc_nmisr(int irq, void *dev_id, struct pt_regs * regs) {
+	int status;
+	
+	status = hp_sdc_status_in8();
+	printk(KERN_WARNING PREFIX "NMI !\n");
+
+#if 0	
+	if (status & HP_SDC_NMISTATUS_FHS) {
+		read_lock(&hp_sdc.hook_lock);
+	      	if (hp_sdc.timer != NULL)
+			hp_sdc.timer(irq, dev_id, status, 0);
+		read_unlock(&hp_sdc.hook_lock);
+	}
+	else {
+		/* TODO: pass this on to the HIL handler, or do SAK here? */
+		printk(KERN_WARNING PREFIX "HIL NMI\n");
+	}
+#endif
+}
+
+
+/***************** Kernel (tasklet) context functions ****************/
+
+unsigned long hp_sdc_put(void);
+
+static void hp_sdc_tasklet(unsigned long foo) {
+
+	write_lock_irq(&hp_sdc.rtq_lock);
+	if (hp_sdc.rcurr >= 0) {
+		struct timeval tv;
+		do_gettimeofday(&tv);
+		if (tv.tv_sec > hp_sdc.rtv.tv_sec) tv.tv_usec += 1000000;
+		if (tv.tv_usec - hp_sdc.rtv.tv_usec > HP_SDC_MAX_REG_DELAY) {
+			hp_sdc_transaction *curr;
+			uint8_t tmp;
+
+			curr = hp_sdc.tq[hp_sdc.rcurr];
+			/* If this turns out to be a normal failure mode
+			 * we'll need to figure out a way to communicate
+			 * it back to the application. and be less verbose.
+			 */
+			printk(KERN_WARNING PREFIX "read timeout (%ius)!\n",
+			       tv.tv_usec - hp_sdc.rtv.tv_usec);
+			curr->idx += hp_sdc.rqty;
+			hp_sdc.rqty = 0;
+			tmp = curr->seq[curr->actidx];
+			curr->seq[curr->actidx] |= HP_SDC_ACT_DEAD;
+			if(tmp & HP_SDC_ACT_SEMAPHORE) {
+				if (curr->act.semaphore) 
+					up(curr->act.semaphore);
+			}
+			if(tmp & HP_SDC_ACT_CALLBACK) {
+				/* Note this means that irqhooks may be called
+				 * in tasklet/bh context.
+				 */
+				if (curr->act.irqhook) 
+					curr->act.irqhook(0, 0, 0, 0);
+			}
+			curr->actidx = curr->idx;
+			curr->idx++;
+			hp_sdc.rcurr = -1; 
+		}
+	}
+	write_unlock_irq(&hp_sdc.rtq_lock);
+	hp_sdc_put();
+}
+
+unsigned long hp_sdc_put(void) {
+	hp_sdc_transaction *curr;
+	uint8_t act;
+	int idx, curridx;
+
+	int limit = 0;
+
+	write_lock(&hp_sdc.lock);
+
+	/* If i8042 buffers are full, we cannot do anything that
+	   requires output, so we skip to the administrativa. */
+	if (hp_sdc.ibf) {
+		hp_sdc_status_in8();
+		if (hp_sdc.ibf) goto finish;
+	}
+
+ anew:
+	/* See if we are in the middle of a sequence. */
+	if (hp_sdc.wcurr < 0) hp_sdc.wcurr = 0;
+	read_lock_irq(&hp_sdc.rtq_lock);
+	if (hp_sdc.rcurr == hp_sdc.wcurr) hp_sdc.wcurr++;
+	read_unlock_irq(&hp_sdc.rtq_lock);
+	if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
+	curridx = hp_sdc.wcurr;
+
+	if (hp_sdc.tq[curridx] != NULL) goto start;
+
+	while (++curridx != hp_sdc.wcurr) {
+		if (curridx >= HP_SDC_QUEUE_LEN) {
+			curridx = -1; /* Wrap to top */
+			continue;
+		}
+		read_lock_irq(&hp_sdc.rtq_lock);
+		if (hp_sdc.rcurr == curridx) {
+			read_unlock_irq(&hp_sdc.rtq_lock);
+			continue;
+		}
+		read_unlock_irq(&hp_sdc.rtq_lock);
+		if (hp_sdc.tq[curridx] != NULL) break; /* Found one. */
+	}
+	if (curridx == hp_sdc.wcurr) { /* There's nothing queued to do. */
+		curridx = -1;
+	}
+	hp_sdc.wcurr = curridx;
+
+ start:
+
+	/* Check to see if the interrupt mask needs to be set. */
+	if (hp_sdc.set_im) {
+		hp_sdc_status_out8(hp_sdc.im | HP_SDC_CMD_SET_IM);
+		hp_sdc.set_im = 0;
+		goto finish;
+	}
+
+	if (hp_sdc.wcurr == -1) goto done;
+
+	curr = hp_sdc.tq[curridx];
+	idx = curr->actidx;
+
+	if (curr->actidx >= curr->endidx) {
+		hp_sdc.tq[curridx] = NULL;
+		/* Interleave outbound data between the transactions. */
+		hp_sdc.wcurr++;
+		if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
+		goto finish;	
+	}
+
+	act = curr->seq[idx];
+	idx++;
+
+	if (curr->idx >= curr->endidx) {
+		if (act & HP_SDC_ACT_DEALLOC) kfree(curr);
+		hp_sdc.tq[curridx] = NULL;
+		/* Interleave outbound data between the transactions. */
+		hp_sdc.wcurr++;
+		if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
+		goto finish;	
+	}
+
+	while (act & HP_SDC_ACT_PRECMD) {
+		if (curr->idx != idx) {
+			idx++;
+			act &= ~HP_SDC_ACT_PRECMD;
+			break;
+		}
+		hp_sdc_status_out8(curr->seq[idx]);
+		curr->idx++;
+		/* act finished? */
+		if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_PRECMD)
+		  goto actdone;
+		/* skip quantity field if data-out sequence follows. */
+		if (act & HP_SDC_ACT_DATAOUT) curr->idx++;
+		goto finish;
+	}
+	if (act & HP_SDC_ACT_DATAOUT) {
+		int qty;
+
+		qty = curr->seq[idx];
+		idx++;
+		if (curr->idx - idx < qty) {
+			hp_sdc_data_out8(curr->seq[curr->idx]);
+			curr->idx++;
+			/* act finished? */
+			if ((curr->idx - idx >= qty) && 
+			    ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT))
+				goto actdone;
+			goto finish;
+		}
+		idx += qty;
+		act &= ~HP_SDC_ACT_DATAOUT;
+	}
+	else while (act & HP_SDC_ACT_DATAREG) {
+		int mask;
+		uint8_t w7[4];
+
+		mask = curr->seq[idx];
+		if (idx != curr->idx) {
+			idx++;
+			idx += !!(mask & 1);
+			idx += !!(mask & 2);
+			idx += !!(mask & 4);
+			idx += !!(mask & 8);
+			act &= ~HP_SDC_ACT_DATAREG;
+			break;
+		}
+		
+		w7[0] = (mask & 1) ? curr->seq[++idx] : hp_sdc.r7[0];
+		w7[1] = (mask & 2) ? curr->seq[++idx] : hp_sdc.r7[1];
+		w7[2] = (mask & 4) ? curr->seq[++idx] : hp_sdc.r7[2];
+		w7[3] = (mask & 8) ? curr->seq[++idx] : hp_sdc.r7[3];
+		
+		if (hp_sdc.wi > 0x73 || hp_sdc.wi < 0x70 ||
+		        w7[hp_sdc.wi-0x70] == hp_sdc.r7[hp_sdc.wi-0x70]) {
+			int i = 0;
+
+			/* Need to point the write index register */	
+			while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++;
+			if (i < 4) {
+				hp_sdc_status_out8(HP_SDC_CMD_SET_D0 + i);
+				hp_sdc.wi = 0x70 + i;
+				goto finish;
+			}
+			idx++;
+			if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAREG)
+				goto actdone;
+			curr->idx = idx;
+			act &= ~HP_SDC_ACT_DATAREG;
+			break;
+		}
+
+		hp_sdc_data_out8(w7[hp_sdc.wi - 0x70]);
+		hp_sdc.r7[hp_sdc.wi - 0x70] = w7[hp_sdc.wi - 0x70];
+		hp_sdc.wi++; /* write index register autoincrements */
+		{
+			int i = 0;
+
+			while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++;
+			if (i >= 4) {
+				curr->idx = idx + 1;
+				if ((act & HP_SDC_ACT_DURING) == 
+				    HP_SDC_ACT_DATAREG)
+				        goto actdone;
+			}
+		}
+		goto finish;
+	}
+	/* We don't go any further in the command if there is a pending read,
+	   because we don't want interleaved results. */
+	read_lock_irq(&hp_sdc.rtq_lock);
+	if (hp_sdc.rcurr >= 0) {
+		read_unlock_irq(&hp_sdc.rtq_lock);
+		goto finish;
+	}
+	read_unlock_irq(&hp_sdc.rtq_lock);
+
+
+	if (act & HP_SDC_ACT_POSTCMD) {
+	  	uint8_t postcmd;
+
+		/* curr->idx should == idx at this point. */
+		postcmd = curr->seq[idx];
+		curr->idx++;
+		if (act & HP_SDC_ACT_DATAIN) {
+
+			/* Start a new read */
+	  		hp_sdc.rqty = curr->seq[curr->idx];
+			do_gettimeofday(&hp_sdc.rtv);
+			curr->idx++;
+			/* Still need to lock here in case of spurious irq. */
+			write_lock_irq(&hp_sdc.rtq_lock);
+			hp_sdc.rcurr = curridx; 
+			write_unlock_irq(&hp_sdc.rtq_lock);
+			hp_sdc_status_out8(postcmd);
+			goto finish;
+		}
+		hp_sdc_status_out8(postcmd);
+		goto actdone;
+	}
+
+actdone:
+	if (act & HP_SDC_ACT_SEMAPHORE) {
+		up(curr->act.semaphore);
+	}
+	else if (act & HP_SDC_ACT_CALLBACK) {
+		curr->act.irqhook(0,0,0,0);
+	}
+	if (curr->idx >= curr->endidx) { /* This transaction is over. */
+		if (act & HP_SDC_ACT_DEALLOC) kfree(curr);
+		hp_sdc.tq[curridx] = NULL;
+	}
+	else {
+		curr->actidx = idx + 1;
+		curr->idx = idx + 2;
+	}
+	/* Interleave outbound data between the transactions. */
+	hp_sdc.wcurr++;
+	if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
+
+ finish:
+	/* If by some quirk IBF has cleared and our ISR has run to 
+	   see that that has happened, do it all again. */
+	if (!hp_sdc.ibf && limit++ < 20) goto anew;
+
+ done:
+	if (hp_sdc.wcurr >= 0) tasklet_schedule(&hp_sdc.task);
+	write_unlock(&hp_sdc.lock);
+	return 0;
+}
+
+/******* Functions called in either user or kernel context ****/
+int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) {
+	int i;
+
+	if (this == NULL) {
+		tasklet_schedule(&hp_sdc.task);
+		return -EINVAL;
+	};
+
+	write_lock_bh(&hp_sdc.lock);
+
+	/* Can't have same transaction on queue twice */
+	for (i=0; i < HP_SDC_QUEUE_LEN; i++)
+		if (hp_sdc.tq[i] == this) goto fail;
+
+	this->actidx = 0;
+	this->idx = 1;
+
+	/* Search for empty slot */
+	for (i=0; i < HP_SDC_QUEUE_LEN; i++) {
+		if (hp_sdc.tq[i] == NULL) {
+			hp_sdc.tq[i] = this;
+			tasklet_schedule(&hp_sdc.task);
+			write_unlock_bh(&hp_sdc.lock);
+			return 0;
+		}
+	}
+	write_unlock_bh(&hp_sdc.lock);
+	printk(KERN_WARNING PREFIX "No free slot to add transaction.\n");
+	return -EBUSY;
+
+ fail:
+	write_unlock_bh(&hp_sdc.lock);
+	printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n");
+	return -EINVAL;
+}
+
+int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) {
+	int i;
+
+	write_lock_bh(&hp_sdc.lock);
+
+	/* TODO: don't remove it if it's not done. */
+
+	for (i=0; i < HP_SDC_QUEUE_LEN; i++)
+		if (hp_sdc.tq[i] == this) hp_sdc.tq[i] = NULL;
+
+	write_unlock_bh(&hp_sdc.lock);
+	return 0;
+}
+
+
+
+/********************** User context functions **************************/
+int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) {
+
+	MOD_INC_USE_COUNT;
+	if (callback == NULL || hp_sdc.dev == NULL) {
+		MOD_DEC_USE_COUNT;
+		return -EINVAL;
+	}
+	write_lock_irq(&hp_sdc.hook_lock);
+	if (hp_sdc.timer != NULL) {
+		write_unlock_irq(&hp_sdc.hook_lock);
+		MOD_DEC_USE_COUNT;
+		return -EBUSY;
+	}
+
+	hp_sdc.timer = callback;
+	/* Enable interrupts from the timers */
+	hp_sdc.im &= ~HP_SDC_IM_FH;
+        hp_sdc.im &= ~HP_SDC_IM_PT;
+	hp_sdc.im &= ~HP_SDC_IM_TIMERS;
+	hp_sdc.set_im = 1;
+	write_unlock_irq(&hp_sdc.hook_lock);
+
+	tasklet_schedule(&hp_sdc.task);
+
+	return 0;
+}
+
+int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback) {
+
+	MOD_INC_USE_COUNT;
+	if (callback == NULL || hp_sdc.dev == NULL) {
+		MOD_DEC_USE_COUNT;
+		return -EINVAL;
+	}
+	write_lock_irq(&hp_sdc.hook_lock);
+	if (hp_sdc.hil != NULL) {
+		write_unlock_irq(&hp_sdc.hook_lock);
+		MOD_DEC_USE_COUNT;
+		return -EBUSY;
+	}
+
+	hp_sdc.hil = callback;
+	hp_sdc.im &= ~HP_SDC_IM_HIL;
+	hp_sdc.set_im = 1;
+	write_unlock_irq(&hp_sdc.hook_lock);
+
+	tasklet_schedule(&hp_sdc.task);
+
+	return 0;
+}
+
+int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback) {
+
+	MOD_INC_USE_COUNT;
+	if (callback == NULL || hp_sdc.dev == NULL) {
+		MOD_DEC_USE_COUNT;
+		return -EINVAL;
+	}
+	write_lock_irq(&hp_sdc.hook_lock);
+	if (hp_sdc.cooked != NULL) {
+		write_unlock_irq(&hp_sdc.hook_lock);
+		MOD_DEC_USE_COUNT;
+		return -EBUSY;
+	}
+
+	/* Enable interrupts from the HIL MLC */
+	hp_sdc.cooked = callback;
+	hp_sdc.im &= ~HP_SDC_IM_HIL;
+	hp_sdc.set_im = 1;
+	write_unlock_irq(&hp_sdc.hook_lock);
+
+	tasklet_schedule(&hp_sdc.task);
+
+	return 0;
+}
+
+int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback) {
+
+
+	write_lock_irq(&hp_sdc.hook_lock);
+	if ((callback != hp_sdc.timer) ||
+	    (hp_sdc.timer == NULL)) {
+		write_unlock_irq(&hp_sdc.hook_lock);
+		return -EINVAL;
+	}
+
+	/* Disable interrupts from the timers */
+	hp_sdc.timer = NULL;
+	hp_sdc.im |= HP_SDC_IM_TIMERS;
+	hp_sdc.im |= HP_SDC_IM_FH;
+	hp_sdc.im |= HP_SDC_IM_PT;
+	hp_sdc.set_im = 1;
+	write_unlock_irq(&hp_sdc.hook_lock);
+	tasklet_schedule(&hp_sdc.task);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback) {
+
+	write_lock_irq(&hp_sdc.hook_lock);
+	if ((callback != hp_sdc.hil) ||
+	    (hp_sdc.hil == NULL)) {
+		write_unlock_irq(&hp_sdc.hook_lock);
+		return -EINVAL;
+	}
+
+	hp_sdc.hil = NULL;
+	/* Disable interrupts from HIL only if there is no cooked driver. */
+	if(hp_sdc.cooked == NULL) {
+		hp_sdc.im |= HP_SDC_IM_HIL;
+		hp_sdc.set_im = 1;
+	}
+	write_unlock_irq(&hp_sdc.hook_lock);
+	tasklet_schedule(&hp_sdc.task);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) {
+
+	write_lock_irq(&hp_sdc.hook_lock);
+	if ((callback != hp_sdc.cooked) ||
+	    (hp_sdc.cooked == NULL)) {
+		write_unlock_irq(&hp_sdc.hook_lock);
+		return -EINVAL;
+	}
+
+	hp_sdc.cooked = NULL;
+	/* Disable interrupts from HIL only if there is no raw HIL driver. */
+	if(hp_sdc.hil == NULL) {
+		hp_sdc.im |= HP_SDC_IM_HIL;
+		hp_sdc.set_im = 1;
+	}
+	write_unlock_irq(&hp_sdc.hook_lock);
+	tasklet_schedule(&hp_sdc.task);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/************************* Keepalive timer task *********************/
+
+void hp_sdc_kicker (unsigned long data) {
+	tasklet_schedule(&hp_sdc.task);
+	/* Re-insert the periodic task. */
+	mod_timer(&hp_sdc.kicker, jiffies + HZ);
+}
+
+/************************** Module Initialization ***************************/
+
+static struct parisc_device_id hp_sdc_tbl[] = {
+	{
+		hw_type:	HPHW_FIO, 
+		hversion_rev:	HVERSION_REV_ANY_ID,
+		hversion:	HVERSION_ANY_ID,
+		sversion:	0x73, 
+	 },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, hp_sdc_tbl);
+
+static int __init hp_sdc_init(struct parisc_device *d);
+
+static struct parisc_driver hp_sdc_driver = {
+	name:		"HP SDC",
+	id_table:	hp_sdc_tbl,
+	probe:		hp_sdc_init,
+};
+
+static int __init hp_sdc_init(struct parisc_device *d)
+{
+	int i;
+	char *errstr = NULL;
+	hp_sdc_transaction t_sync;
+	uint8_t ts_sync[6];
+	struct semaphore s_sync;
+
+
+	errstr = "foo\n";
+
+	if (!d) return 1;
+	if (hp_sdc.dev != NULL) return 1;	/* We only expect one SDC */
+
+	hp_sdc.dev = d;
+	hp_sdc.irq		= d->irq;
+	/* TODO: Is NMI == IRQ - 1 all cases, or is there a way to query? */
+	hp_sdc.nmi		= d->irq - 1;
+	hp_sdc.base_io		= (unsigned long) d->hpa;
+	hp_sdc.data_io		= (unsigned long) d->hpa + 0x800;
+	hp_sdc.status_io	= (unsigned long) d->hpa + 0x801;
+
+  	hp_sdc.lock		= RW_LOCK_UNLOCKED;
+  	hp_sdc.ibf_lock		= RW_LOCK_UNLOCKED;
+  	hp_sdc.rtq_lock		= RW_LOCK_UNLOCKED;
+  	hp_sdc.hook_lock	= RW_LOCK_UNLOCKED;
+
+	hp_sdc.timer		= NULL;
+	hp_sdc.hil		= NULL;
+	hp_sdc.pup		= NULL;
+	hp_sdc.cooked		= NULL;
+	hp_sdc.im		= HP_SDC_IM_MASK;  /* Mask maskable irqs */
+	hp_sdc.set_im		= 1;
+	hp_sdc.wi		= 0xff;
+	hp_sdc.r7[0]		= 0xff;
+	hp_sdc.r7[1]		= 0xff;
+	hp_sdc.r7[2]		= 0xff;
+	hp_sdc.r7[3]		= 0xff;
+	hp_sdc.ibf		= 1;
+
+	for (i = 0; i < HP_SDC_QUEUE_LEN; i++) hp_sdc.tq[i] = NULL;
+	hp_sdc.wcurr		= -1;
+        hp_sdc.rcurr		= -1;
+	hp_sdc.rqty		= 0;
+
+	hp_sdc.dev_err = -ENODEV;
+
+	errstr = "IO not found for";
+	if (!hp_sdc.base_io) goto err0;
+
+	errstr = "IRQ not found for";
+	if (!hp_sdc.irq) goto err0;
+
+	hp_sdc.dev_err = -EBUSY;
+
+	errstr = "IO not available for";
+        if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name)) goto err0;
+
+	errstr = "IRQ not available for";
+        if(request_irq(hp_sdc.irq, &hp_sdc_isr, 0, hp_sdc_driver.name, 
+		       (void *) hp_sdc.base_io)) goto err1;
+
+	errstr = "NMI not available for";
+        if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, 0, "HP SDC NMI", 
+			(void*)d->hpa)) goto err2;
+
+	printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n", 
+	       (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
+
+	hp_sdc_status_in8();
+	hp_sdc_data_in8();
+
+	tasklet_init(&hp_sdc.task, hp_sdc_tasklet, 0);
+
+	/* Sync the output buffer registers, thus scheduling hp_sdc_tasklet. */
+	t_sync.actidx	= 0;
+	t_sync.idx	= 1;
+	t_sync.endidx	= 6;
+	t_sync.seq	= ts_sync;
+	ts_sync[0]	= HP_SDC_ACT_DATAREG | HP_SDC_ACT_SEMAPHORE;
+	ts_sync[1]	= 0x0f;
+	ts_sync[2] = ts_sync[3]	= ts_sync[4] = ts_sync[5] = 0;
+	t_sync.act.semaphore = &s_sync;
+	init_MUTEX_LOCKED(&s_sync);
+	hp_sdc_enqueue_transaction(&t_sync);
+	down(&s_sync); /* Wait for t_sync to complete */
+
+	/* Create the keepalive task */
+	init_timer(&hp_sdc.kicker);
+	hp_sdc.kicker.expires = jiffies + HZ;
+	hp_sdc.kicker.function = &hp_sdc_kicker;
+	add_timer(&hp_sdc.kicker);
+
+	hp_sdc.dev_err = 0;
+	return 0;
+ err2:
+	free_irq(hp_sdc.irq, NULL);
+ err1:
+	release_region(hp_sdc.data_io, 2);
+ err0:
+	printk(KERN_WARNING PREFIX ": %s SDC IO=0x%p IRQ=0x%x NMI=0x%x\n", 
+		errstr, (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
+	hp_sdc.dev = NULL;
+	return hp_sdc.dev_err;
+}
+
+static void __exit hp_sdc_exit(void)
+{
+	write_lock_irq(&hp_sdc.lock);
+
+	/* Turn off all maskable "sub-function" irq's. */
+	hp_sdc_spin_ibf();
+	gsc_writeb(HP_SDC_CMD_SET_IM | HP_SDC_IM_MASK, hp_sdc.status_io);
+
+	/* Wait until we know this has been processed by the i8042 */
+	hp_sdc_spin_ibf();
+
+	free_irq(hp_sdc.nmi, NULL);
+	free_irq(hp_sdc.irq, NULL);
+	write_unlock_irq(&hp_sdc.lock);
+
+	del_timer(&hp_sdc.kicker);
+
+	tasklet_kill(&hp_sdc.task);
+
+/*        release_region(hp_sdc.data_io, 2); */
+
+	if (unregister_parisc_driver(&hp_sdc_driver)) 
+		printk(KERN_WARNING PREFIX "Error unregistering HP SDC");
+}
+
+static int __init hp_sdc_register(void)
+{
+	hp_sdc.dev = NULL;
+	hp_sdc.dev_err = 0;
+	hp_sdc_transaction tq_init;
+	uint8_t tq_init_seq[5];
+	struct semaphore tq_init_sem;
+
+	if (register_parisc_driver(&hp_sdc_driver)) {
+		printk(KERN_WARNING PREFIX "Error registering SDC with system bus tree.\n");
+		return -ENODEV;
+	}
+	if (hp_sdc.dev == NULL) {
+		printk(KERN_WARNING PREFIX "No SDC found.\n");
+		return hp_sdc.dev_err;
+	}
+
+	init_MUTEX_LOCKED(&tq_init_sem);
+
+	tq_init.actidx		= 0;
+	tq_init.idx		= 1;
+	tq_init.endidx		= 5;
+	tq_init.seq		= tq_init_seq;
+	tq_init.act.semaphore	= &tq_init_sem;
+
+	tq_init_seq[0] = 
+	  HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
+	tq_init_seq[1] = HP_SDC_CMD_READ_KCC;
+	tq_init_seq[2] = 1;
+	tq_init_seq[3] = 0;
+	tq_init_seq[4] = 0;
+
+	hp_sdc_enqueue_transaction(&tq_init);
+
+	down(&tq_init_sem);
+	up(&tq_init_sem);
+
+	if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) {
+		printk(KERN_WARNING PREFIX "Error reading config byte.\n");
+		hp_sdc_exit();
+		return -ENODEV;
+	}
+	hp_sdc.r11 = tq_init_seq[4];
+	if (hp_sdc.r11 & HP_SDC_CFG_NEW) {
+		char *str;
+		printk(KERN_INFO PREFIX "New style SDC\n");
+		tq_init_seq[1] = HP_SDC_CMD_READ_XTD;
+		tq_init.actidx		= 0;
+		tq_init.idx		= 1;
+		down(&tq_init_sem);
+		hp_sdc_enqueue_transaction(&tq_init);		
+		down(&tq_init_sem);
+		up(&tq_init_sem);
+		if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) {
+			printk(KERN_WARNING PREFIX "Error reading extended config byte.\n");
+			return -ENODEV;
+		}
+		hp_sdc.r7e = tq_init_seq[4];
+		HP_SDC_XTD_REV_STRINGS(hp_sdc.r7e & HP_SDC_XTD_REV, str)
+		printk(KERN_INFO PREFIX "Revision: %s\n", str);
+		if (hp_sdc.r7e & HP_SDC_XTD_BEEPER) {
+			printk(KERN_INFO PREFIX "TI SN76494 beeper present\n");
+		}
+		if (hp_sdc.r7e & HP_SDC_XTD_BBRTC) {
+			printk(KERN_INFO PREFIX "OKI MSM-58321 BBRTC present\n");
+		}
+		printk(KERN_INFO PREFIX "Spunking the self test register to force PUP "
+		       "on next firmware reset.\n");
+		tq_init_seq[0] = HP_SDC_ACT_PRECMD | 
+			HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
+		tq_init_seq[1] = HP_SDC_CMD_SET_STR;
+		tq_init_seq[2] = 1;
+		tq_init_seq[3] = 0;
+		tq_init.actidx		= 0;
+		tq_init.idx		= 1;
+		tq_init.endidx		= 4;
+		down(&tq_init_sem);
+		hp_sdc_enqueue_transaction(&tq_init);		
+		down(&tq_init_sem);
+		up(&tq_init_sem);
+	}
+	else {
+		printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n", 
+		       (hp_sdc.r11 & HP_SDC_CFG_REV) ? "3300" : "2564/3087");
+	}
+
+        return 0;
+}
+
+module_init(hp_sdc_register);
+module_exit(hp_sdc_exit);
+
+/* Timing notes:  These measurements taken on my 64MHz 7100-LC (715/64) 
+ *                                              cycles cycles-adj    time
+ * between two consecutive mfctl(16)'s:              4        n/a    63ns
+ * hp_sdc_spin_ibf when idle:                      119        115   1.7us
+ * gsc_writeb status register:                      83         79   1.2us
+ * IBF to clear after sending SET_IM:             6204       6006    93us
+ * IBF to clear after sending LOAD_RT:            4467       4352    68us  
+ * IBF to clear after sending two LOAD_RTs:      18974      18859   295us
+ * READ_T1, read status/data, IRQ, call handler: 35564        n/a   556us
+ * cmd to ~IBF READ_T1 2nd time right after:   5158403        n/a    81ms
+ * between IRQ received and ~IBF for above:    2578877        n/a    40ms
+ *
+ * Performance stats after a run of this module configuring HIL and
+ * receiving a few mouse events:
+ *
+ * status in8  282508 cycles 7128 calls
+ * status out8   8404 cycles  341 calls
+ * data out8     1734 cycles   78 calls
+ * isr         174324 cycles  617 calls (includes take)
+ * take          1241 cycles    2 calls
+ * put        1411504 cycles 6937 calls
+ * task       1655209 cycles 6937 calls (includes put)
+ *
+ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hil/hp_sdc_mlc.c linux-2.4.20/drivers/hil/hp_sdc_mlc.c
--- linux-2.4.19/drivers/hil/hp_sdc_mlc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/hil/hp_sdc_mlc.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,370 @@
+/*
+ * Access to HP-HIL MLC through HP System Device Controller.
+ *
+ * Copyright (c) 2001 Brian S. Julin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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
+ *
+ * References:
+ * HP-HIL Technical Reference Manual.  Hewlett Packard Product No. 45918A
+ * System Device Controller Microprocessor Firmware Theory of Operation
+ *      for Part Number 1820-4784 Revision B.  Dwg No. A-1820-4784-2
+ *
+ */
+
+#include <linux/hil_mlc.h>
+#include <linux/hp_sdc.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#define PREFIX "HP SDC MLC: "
+
+static hil_mlc hp_sdc_mlc;
+
+MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
+MODULE_DESCRIPTION("Glue for onboard HIL MLC in HP-PARISC machines");
+MODULE_LICENSE("Dual BSD/GPL");
+
+struct hp_sdc_mlc_priv_s {
+	int emtestmode;
+	hp_sdc_transaction trans;
+	u8 tseq[16];
+	int got5x;
+} hp_sdc_mlc_priv;
+
+/************************* Interrupt context ******************************/
+static void hp_sdc_mlc_isr (int irq, void *dev_id, 
+			    uint8_t status, uint8_t data) {
+  	int idx;
+	hil_mlc *mlc = &hp_sdc_mlc;
+
+	write_lock(&(mlc->lock));
+	if (mlc->icount < 0) {
+		printk(KERN_WARNING PREFIX "HIL Overflow!\n");
+		up(&mlc->isem);
+		goto out;
+	}
+	idx = 15 - mlc->icount;
+	if ((status & HP_SDC_STATUS_IRQMASK) == HP_SDC_STATUS_HILDATA) {
+		mlc->ipacket[idx] |= data | HIL_ERR_INT;
+		mlc->icount--;
+		if (hp_sdc_mlc_priv.got5x) goto check;
+		if (!idx) goto check;
+		if ((mlc->ipacket[idx-1] & HIL_PKT_ADDR_MASK) !=
+		    (mlc->ipacket[idx] & HIL_PKT_ADDR_MASK)) {
+			mlc->ipacket[idx] &= ~HIL_PKT_ADDR_MASK;
+			mlc->ipacket[idx] |= (mlc->ipacket[idx-1] 
+						    & HIL_PKT_ADDR_MASK);
+		}
+		goto check;
+	}
+	/* We know status is 5X */
+	if (data & HP_SDC_HIL_ISERR) goto err;
+	mlc->ipacket[idx] = 
+		(data & HP_SDC_HIL_R1MASK) << HIL_PKT_ADDR_SHIFT;
+	hp_sdc_mlc_priv.got5x = 1;
+	goto out;
+
+ check:
+	hp_sdc_mlc_priv.got5x = 0;
+	if (mlc->imatch == 0) goto done;
+	if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) 
+	    && (mlc->ipacket[idx] == (mlc->imatch | idx))) goto done;
+	if (mlc->ipacket[idx] == mlc->imatch) goto done;
+	goto out;
+
+ err:				
+	printk(KERN_DEBUG PREFIX "err code %x\n", data);
+	switch (data) {
+	case HP_SDC_HIL_RC_DONE:
+		printk(KERN_WARNING PREFIX "Bastard SDC reconfigured loop!\n");
+		break;
+	case HP_SDC_HIL_ERR:
+		mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR | 
+		  HIL_ERR_FERR | HIL_ERR_FOF;
+		break;
+	case HP_SDC_HIL_TO:
+		mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_LERR;
+		break;
+	case HP_SDC_HIL_RC:
+		printk(KERN_WARNING PREFIX "Bastard SDC decided to reconfigure loop!\n");
+		break;
+	default:
+		printk(KERN_WARNING PREFIX "Unkown HIL Error status (%x)!\n", data);
+		break;
+	}
+	/* No more data will be coming due to an error. */
+ done:
+	tasklet_schedule(mlc->tasklet);
+	up(&(mlc->isem));
+ out:
+	write_unlock(&(mlc->lock));
+}
+
+
+/******************** Tasklet or userspace context functions ****************/
+
+static int hp_sdc_mlc_in (hil_mlc *mlc, suseconds_t timeout) {
+	unsigned long flags;
+	struct hp_sdc_mlc_priv_s *priv;
+	int rc = 2;
+
+	priv = mlc->priv;
+
+	write_lock_irqsave(&(mlc->lock), flags);
+
+	/* Try to down the semaphore */
+	if (down_trylock(&(mlc->isem))) {
+		struct timeval tv;
+		if (priv->emtestmode) {
+			mlc->ipacket[0] = 
+				HIL_ERR_INT | (mlc->opacket & 
+					       (HIL_PKT_CMD | 
+						HIL_PKT_ADDR_MASK | 
+						HIL_PKT_DATA_MASK));
+			mlc->icount = 14;
+			/* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */
+			goto wasup;
+		}
+		do_gettimeofday(&tv);
+		tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec);
+		if (tv.tv_usec - mlc->instart.tv_usec > mlc->intimeout) {
+		  /*		  printk("!%i %i", 
+				  tv.tv_usec - mlc->instart.tv_usec, 
+				  mlc->intimeout);
+		  */
+			rc = 1;
+			up(&(mlc->isem));
+		}
+		goto done;
+	}
+ wasup:
+	up(&(mlc->isem));
+	rc = 0;
+	goto done;
+ done:
+	write_unlock_irqrestore(&(mlc->lock), flags);
+	return rc;
+}
+
+static int hp_sdc_mlc_cts (hil_mlc *mlc) {
+	struct hp_sdc_mlc_priv_s *priv;
+	unsigned long flags;
+
+	priv = mlc->priv;	
+
+	write_lock_irqsave(&(mlc->lock), flags);
+
+	/* Try to down the semaphores -- they should be up. */
+	if (down_trylock(&(mlc->isem))) {
+		BUG();
+		goto busy;
+	}
+	if (down_trylock(&(mlc->osem))) {
+	 	BUG();
+		up(&(mlc->isem));
+		goto busy;
+	}
+	up(&(mlc->isem));
+	up(&(mlc->osem));
+
+	if (down_trylock(&(mlc->csem))) {
+		if (priv->trans.act.semaphore != &(mlc->csem)) goto poll;
+		goto busy;
+	}
+	if (!(priv->tseq[4] & HP_SDC_USE_LOOP)) goto done;
+
+ poll:
+	priv->trans.act.semaphore = &(mlc->csem);
+	priv->trans.actidx = 0;
+	priv->trans.idx = 1;
+	priv->trans.endidx = 5;
+	priv->tseq[0] = 
+		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
+	priv->tseq[1] = HP_SDC_CMD_READ_USE;
+	priv->tseq[2] = 1;
+	priv->tseq[3] = 0;
+	priv->tseq[4] = 0;
+	hp_sdc_enqueue_transaction(&(priv->trans));
+ busy:
+	write_unlock_irqrestore(&(mlc->lock), flags);
+	return 1;
+ done:
+	priv->trans.act.semaphore = &(mlc->osem);
+	up(&(mlc->csem));
+	write_unlock_irqrestore(&(mlc->lock), flags);
+	return 0;
+}
+
+static void hp_sdc_mlc_out (hil_mlc *mlc) {
+	struct hp_sdc_mlc_priv_s *priv;
+	unsigned long flags;
+
+	priv = mlc->priv;
+
+	write_lock_irqsave(&(mlc->lock), flags);
+	
+	/* Try to down the semaphore -- it should be up. */
+	if (down_trylock(&(mlc->osem))) {
+	 	BUG();
+		goto done;
+	}
+
+	if (mlc->opacket & HIL_DO_ALTER_CTRL) goto do_control;
+
+ do_data:
+	if (priv->emtestmode) {
+		up(&(mlc->osem));
+		goto done;
+	}
+	/* Shouldn't be sending commands when loop may be busy */
+	if (down_trylock(&(mlc->csem))) {
+	 	BUG();
+		goto done;
+	}
+	up(&(mlc->csem));
+
+	priv->trans.actidx = 0;
+	priv->trans.idx = 1;
+	priv->trans.act.semaphore = &(mlc->osem);
+	priv->trans.endidx = 6;
+	priv->tseq[0] = 
+		HP_SDC_ACT_DATAREG | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_SEMAPHORE;
+	priv->tseq[1] = 0x7;
+	priv->tseq[2] = 
+		(mlc->opacket & 
+		 (HIL_PKT_ADDR_MASK | HIL_PKT_CMD))
+		   >> HIL_PKT_ADDR_SHIFT;
+	priv->tseq[3] = 
+		(mlc->opacket & HIL_PKT_DATA_MASK) 
+		  >> HIL_PKT_DATA_SHIFT;
+	priv->tseq[4] = 0;  /* No timeout */
+	if (priv->tseq[3] == HIL_CMD_DHR) priv->tseq[4] = 1;
+	priv->tseq[5] = HP_SDC_CMD_DO_HIL;
+	goto enqueue;
+
+ do_control:
+	priv->emtestmode = mlc->opacket & HIL_CTRL_TEST;
+	if ((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE) {
+		BUG(); /* we cannot emulate this, it should not be used. */
+	}
+	if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY) goto control_only;
+	if (mlc->opacket & HIL_CTRL_APE) { 
+		BUG(); /* Should not send command/data after engaging APE */
+		goto done;
+	}
+	/* Disengaging APE this way would not be valid either since 
+	 * the loop must be allowed to idle.
+	 *
+	 * So, it works out that we really never actually send control 
+	 * and data when using SDC, we just send the data. 
+	 */
+	goto do_data;
+
+ control_only:
+	priv->trans.actidx = 0;
+	priv->trans.idx = 1;
+	priv->trans.act.semaphore = &(mlc->osem);
+	priv->trans.endidx = 4;
+	priv->tseq[0] = 
+	  HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
+	priv->tseq[1] = HP_SDC_CMD_SET_LPC;
+	priv->tseq[2] = 1;
+	//	priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC;
+	priv->tseq[3] = 0;
+	if (mlc->opacket & HIL_CTRL_APE) {
+		priv->tseq[3] |= HP_SDC_LPC_APE_IPF;
+		down_trylock(&(mlc->csem));
+	} 
+ enqueue:
+	hp_sdc_enqueue_transaction(&(priv->trans));
+ done:
+	write_unlock_irqrestore(&(mlc->lock), flags);
+}
+
+
+static void hp_sdc_mlc_inc_use_count (void) {
+	MOD_INC_USE_COUNT;
+}
+
+static void hp_sdc_mlc_dec_use_count (void) {
+	MOD_DEC_USE_COUNT;
+}
+
+static int __init hp_sdc_mlc_init(void)
+{
+	hil_mlc *mlc = &hp_sdc_mlc;
+
+	printk(KERN_INFO PREFIX "Registering the System Domain Controller's HIL MLC.\n");
+
+	hp_sdc_mlc_priv.emtestmode = 0;
+	hp_sdc_mlc_priv.trans.seq = hp_sdc_mlc_priv.tseq;
+	hp_sdc_mlc_priv.trans.act.semaphore = &(mlc->osem);
+	hp_sdc_mlc_priv.got5x = 0;
+
+	mlc->cts		= &hp_sdc_mlc_cts;
+	mlc->in			= &hp_sdc_mlc_in;
+	mlc->out		= &hp_sdc_mlc_out;
+
+	mlc->inc_use_count 	= &hp_sdc_mlc_inc_use_count;
+	mlc->dec_use_count 	= &hp_sdc_mlc_dec_use_count;
+
+	if (hil_mlc_register(mlc)) {
+		printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n");
+		goto err0;
+	}
+	mlc->priv		= &hp_sdc_mlc_priv;
+
+	if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) {
+		printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n");
+		goto err1;
+	}
+	return 0;
+ err1:
+	if (hil_mlc_unregister(mlc)) {
+		printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
+			"This is bad.  Could cause an oops.\n");
+	}
+ err0:
+	return -EBUSY;
+}
+
+static void __exit hp_sdc_mlc_exit(void)
+{
+	hil_mlc *mlc = &hp_sdc_mlc;
+	if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr)) {
+		printk(KERN_ERR PREFIX "Failed to release the raw HIL ISR hook.\n"
+			"This is bad.  Could cause an oops.\n");
+	}
+	if (hil_mlc_unregister(mlc)) {
+		printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
+			"This is bad.  Could cause an oops.\n");
+	}
+}
+
+module_init(hp_sdc_mlc_init);
+module_exit(hp_sdc_mlc_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hil/hp_sdc_rtc.c linux-2.4.20/drivers/hil/hp_sdc_rtc.c
--- linux-2.4.19/drivers/hil/hp_sdc_rtc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/hil/hp_sdc_rtc.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,720 @@
+/*
+ * HP i8042 SDC + MSM-58321 BBRTC driver.
+ *
+ * Copyright (c) 2001 Brian S. Julin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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
+ *
+ * References:
+ * System Device Controller Microprocessor Firmware Theory of Operation
+ *      for Part Number 1820-4784 Revision B.  Dwg No. A-1820-4784-2
+ * efirtc.c by Stephane Eranian/Hewlett Packard
+ *
+ */
+
+#include <linux/hp_sdc.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/miscdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/poll.h>
+#include <linux/rtc.h>
+
+MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
+MODULE_DESCRIPTION("HP i8042 SDC + MSM-58321 RTC Driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+#define RTC_VERSION "1.10d"
+
+static unsigned long epoch = 2000;
+
+static struct semaphore i8042tregs;
+
+static hp_sdc_irqhook hp_sdc_rtc_isr;
+
+static struct fasync_struct *hp_sdc_rtc_async_queue;
+
+static DECLARE_WAIT_QUEUE_HEAD(hp_sdc_rtc_wait);
+
+static loff_t hp_sdc_rtc_llseek(struct file *file, loff_t offset, int origin);
+
+static ssize_t hp_sdc_rtc_read(struct file *file, char *buf,
+			       size_t count, loff_t *ppos);
+
+static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file,
+			    unsigned int cmd, unsigned long arg);
+
+static unsigned int hp_sdc_rtc_poll(struct file *file, poll_table *wait);
+
+static int hp_sdc_rtc_open(struct inode *inode, struct file *file);
+static int hp_sdc_rtc_release(struct inode *inode, struct file *file);
+static int hp_sdc_rtc_fasync (int fd, struct file *filp, int on);
+
+static int hp_sdc_rtc_read_proc(char *page, char **start, off_t off,
+				int count, int *eof, void *data);
+
+static void hp_sdc_rtc_isr (int irq, void *dev_id, 
+			    uint8_t status, uint8_t data) 
+{
+	return;
+}
+
+static int hp_sdc_rtc_do_read_bbrtc (struct rtc_time *rtctm)
+{
+	struct semaphore tsem;
+	hp_sdc_transaction t;
+	uint8_t tseq[91];
+	int i;
+	
+	i = 0;
+	while (i < 91) {
+		tseq[i++] = HP_SDC_ACT_DATAREG |
+			HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN;
+		tseq[i++] = 0x01;			/* write i8042[0x70] */
+	  	tseq[i]   = i / 7;			/* BBRTC reg address */
+		i++;
+		tseq[i++] = HP_SDC_CMD_DO_RTCR;		/* Trigger command   */
+		tseq[i++] = 2;		/* expect 1 stat/dat pair back.   */
+		i++; i++;               /* buffer for stat/dat pair       */
+	}
+	tseq[84] |= HP_SDC_ACT_SEMAPHORE;
+	t.endidx =		91;
+	t.seq =			tseq;
+	t.act.semaphore =	&tsem;
+	init_MUTEX_LOCKED(&tsem);
+	
+	if (hp_sdc_enqueue_transaction(&t)) return -1;
+	
+	down_interruptible(&tsem);  /* Put ourselves to sleep for results. */
+	
+	/* Check for nonpresence of BBRTC */
+	if (!((tseq[83] | tseq[90] | tseq[69] | tseq[76] |
+	       tseq[55] | tseq[62] | tseq[34] | tseq[41] |
+	       tseq[20] | tseq[27] | tseq[6]  | tseq[13]) & 0x0f))
+		return -1;
+
+	memset(rtctm, 0, sizeof(struct rtc_time));
+	rtctm->tm_year = (tseq[83] & 0x0f) + (tseq[90] & 0x0f) * 10;
+	rtctm->tm_mon  = (tseq[69] & 0x0f) + (tseq[76] & 0x0f) * 10;
+	rtctm->tm_mday = (tseq[55] & 0x0f) + (tseq[62] & 0x0f) * 10;
+	rtctm->tm_wday = (tseq[48] & 0x0f);
+	rtctm->tm_hour = (tseq[34] & 0x0f) + (tseq[41] & 0x0f) * 10;
+	rtctm->tm_min  = (tseq[20] & 0x0f) + (tseq[27] & 0x0f) * 10;
+	rtctm->tm_sec  = (tseq[6]  & 0x0f) + (tseq[13] & 0x0f) * 10;
+	
+	return 0;
+}
+
+static int hp_sdc_rtc_read_bbrtc (struct rtc_time *rtctm)
+{
+	struct rtc_time tm, tm_last;
+	int i = 0;
+
+	/* MSM-58321 has no read latch, so must read twice and compare. */
+
+	if (hp_sdc_rtc_do_read_bbrtc(&tm_last)) return -1;
+	if (hp_sdc_rtc_do_read_bbrtc(&tm)) return -1;
+
+	while (memcmp(&tm, &tm_last, sizeof(struct rtc_time))) {
+		if (i++ > 4) return -1;
+		memcpy(&tm_last, &tm, sizeof(struct rtc_time));
+		if (hp_sdc_rtc_do_read_bbrtc(&tm)) return -1;
+	}
+
+	memcpy(rtctm, &tm, sizeof(struct rtc_time));
+
+	return 0;
+}
+
+
+static int64_t hp_sdc_rtc_read_i8042timer (uint8_t loadcmd, int numreg)
+{
+	hp_sdc_transaction t;
+	uint8_t tseq[26] = {
+		HP_SDC_ACT_PRECMD | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN,
+		0,
+		HP_SDC_CMD_READ_T1, 2, 0, 0,
+		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 
+		HP_SDC_CMD_READ_T2, 2, 0, 0,
+		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 
+		HP_SDC_CMD_READ_T3, 2, 0, 0,
+		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 
+		HP_SDC_CMD_READ_T4, 2, 0, 0,
+		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 
+		HP_SDC_CMD_READ_T5, 2, 0, 0
+	};
+
+	t.endidx = numreg * 5;
+
+	tseq[1] = loadcmd;
+	tseq[t.endidx - 4] |= HP_SDC_ACT_SEMAPHORE; /* numreg assumed > 1 */
+
+	t.seq =			tseq;
+	t.act.semaphore =	&i8042tregs;
+
+	down_interruptible(&i8042tregs);  /* Sleep if output regs in use. */
+
+	if (hp_sdc_enqueue_transaction(&t)) return -1;
+	
+	down_interruptible(&i8042tregs);  /* Sleep until results come back. */
+	up(&i8042tregs);
+
+	return (tseq[5] | 
+		((uint64_t)(tseq[10]) << 8)  | ((uint64_t)(tseq[15]) << 16) |
+		((uint64_t)(tseq[20]) << 24) | ((uint64_t)(tseq[25]) << 32));
+}
+
+
+/* Read the i8042 real-time clock */
+static inline int hp_sdc_rtc_read_rt(struct timeval *res) {
+	int64_t raw;
+	uint32_t tenms; 
+	unsigned int days;
+
+	raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_RT, 5);
+	if (raw < 0) return -1;
+
+	tenms = (uint32_t)raw & 0xffffff;
+	days  = (unsigned int)(raw >> 24) & 0xffff;
+
+	res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
+	res->tv_sec =  (time_t)(tenms / 100) + days * 86400;
+
+	return 0;
+}
+
+
+/* Read the i8042 fast handshake timer */
+static inline int hp_sdc_rtc_read_fhs(struct timeval *res) {
+	uint64_t raw;
+	unsigned int tenms;
+
+	raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_FHS, 2);
+	if (raw < 0) return -1;
+
+	tenms = (unsigned int)raw & 0xffff;
+
+	res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
+	res->tv_sec  = (time_t)(tenms / 100);
+
+	return 0;
+}
+
+
+/* Read the i8042 match timer (a.k.a. alarm) */
+static inline int hp_sdc_rtc_read_mt(struct timeval *res) {
+	int64_t raw;	
+	uint32_t tenms; 
+
+	raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_MT, 3);
+	if (raw < 0) return -1;
+
+	tenms = (uint32_t)raw & 0xffffff;
+
+	res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
+	res->tv_sec  = (time_t)(tenms / 100);
+
+	return 0;
+}
+
+
+/* Read the i8042 delay timer */
+static inline int hp_sdc_rtc_read_dt(struct timeval *res) {
+	int64_t raw;
+	uint32_t tenms;
+
+	raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_DT, 3);
+	if (raw < 0) return -1;
+
+	tenms = (uint32_t)raw & 0xffffff;
+
+	res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
+	res->tv_sec  = (time_t)(tenms / 100);
+
+	return 0;
+}
+
+
+/* Read the i8042 cycle timer (a.k.a. periodic) */
+static inline int hp_sdc_rtc_read_ct(struct timeval *res) {
+	int64_t raw;
+	uint32_t tenms;
+
+	raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_CT, 3);
+	if (raw < 0) return -1;
+
+	tenms = (uint32_t)raw & 0xffffff;
+
+	res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
+	res->tv_sec  = (time_t)(tenms / 100);
+
+	return 0;
+}
+
+
+/* Set the i8042 real-time clock */
+static int hp_sdc_rtc_set_rt (struct timeval *setto)
+{
+	uint32_t tenms;
+	unsigned int days;
+	hp_sdc_transaction t;
+	uint8_t tseq[11] = {
+		HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT,
+		HP_SDC_CMD_SET_RTMS, 3, 0, 0, 0,
+		HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT,
+		HP_SDC_CMD_SET_RTD, 2, 0, 0 
+	};
+
+	t.endidx = 10;
+
+	if (0xffff < setto->tv_sec / 86400) return -1;
+	days = setto->tv_sec / 86400;
+	if (0xffff < setto->tv_usec / 1000000 / 86400) return -1;
+	days += ((setto->tv_sec % 86400) + setto->tv_usec / 1000000) / 86400;
+	if (days > 0xffff) return -1;
+
+	if (0xffffff < setto->tv_sec) return -1;
+	tenms  = setto->tv_sec * 100;
+	if (0xffffff < setto->tv_usec / 10000) return -1;
+	tenms += setto->tv_usec / 10000;
+	if (tenms > 0xffffff) return -1;
+
+	tseq[3] = (uint8_t)(tenms & 0xff);
+	tseq[4] = (uint8_t)((tenms >> 8)  & 0xff);
+	tseq[5] = (uint8_t)((tenms >> 16) & 0xff);
+
+	tseq[9] = (uint8_t)(days & 0xff);
+	tseq[10] = (uint8_t)((days >> 8) & 0xff);
+
+	t.seq =	tseq;
+
+	if (hp_sdc_enqueue_transaction(&t)) return -1;
+	return 0;
+}
+
+/* Set the i8042 fast handshake timer */
+static int hp_sdc_rtc_set_fhs (struct timeval *setto)
+{
+	uint32_t tenms;
+	hp_sdc_transaction t;
+	uint8_t tseq[5] = {
+		HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT,
+		HP_SDC_CMD_SET_FHS, 2, 0, 0
+	};
+
+	t.endidx = 4;
+
+	if (0xffff < setto->tv_sec) return -1;
+	tenms  = setto->tv_sec * 100;
+	if (0xffff < setto->tv_usec / 10000) return -1;
+	tenms += setto->tv_usec / 10000;
+	if (tenms > 0xffff) return -1;
+
+	tseq[3] = (uint8_t)(tenms & 0xff);
+	tseq[4] = (uint8_t)((tenms >> 8)  & 0xff);
+
+	t.seq =	tseq;
+
+	if (hp_sdc_enqueue_transaction(&t)) return -1;
+	return 0;
+}
+
+
+/* Set the i8042 match timer (a.k.a. alarm) */
+#define hp_sdc_rtc_set_mt (setto) \
+	hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_MT)
+
+/* Set the i8042 delay timer */
+#define hp_sdc_rtc_set_dt (setto) \
+	hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_DT)
+
+/* Set the i8042 cycle timer (a.k.a. periodic) */
+#define hp_sdc_rtc_set_ct (setto) \
+	hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_CT)
+
+/* Set one of the i8042 3-byte wide timers */
+static int hp_sdc_rtc_set_i8042timer (struct timeval *setto, uint8_t setcmd)
+{
+	uint32_t tenms;
+	hp_sdc_transaction t;
+	uint8_t tseq[6] = {
+		HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT,
+		0, 3, 0, 0, 0
+	};
+
+	t.endidx = 6;
+
+	if (0xffffff < setto->tv_sec) return -1;
+	tenms  = setto->tv_sec * 100;
+	if (0xffffff < setto->tv_usec / 10000) return -1;
+	tenms += setto->tv_usec / 10000;
+	if (tenms > 0xffffff) return -1;
+
+	tseq[1] = setcmd;
+	tseq[3] = (uint8_t)(tenms & 0xff);
+	tseq[4] = (uint8_t)((tenms >> 8)  & 0xff);
+	tseq[5] = (uint8_t)((tenms >> 16)  & 0xff);
+
+	t.seq =			tseq;
+
+	if (hp_sdc_enqueue_transaction(&t)) { 
+		return -1;
+	}
+	return 0;
+}
+
+static loff_t hp_sdc_rtc_llseek(struct file *file, loff_t offset, int origin)
+{
+        return -ESPIPE;
+}
+
+static ssize_t hp_sdc_rtc_read(struct file *file, char *buf,
+			       size_t count, loff_t *ppos) {
+	ssize_t retval;
+
+        if (count < sizeof(unsigned long))
+                return -EINVAL;
+
+	retval = put_user(68, (unsigned long *)buf);
+	return retval;
+}
+
+static unsigned int hp_sdc_rtc_poll(struct file *file, poll_table *wait)
+{
+        unsigned long l;
+
+	l = 0;
+        if (l != 0)
+                return POLLIN | POLLRDNORM;
+        return 0;
+}
+
+static int hp_sdc_rtc_open(struct inode *inode, struct file *file)
+{
+	MOD_INC_USE_COUNT;
+        return 0;
+}
+
+static int hp_sdc_rtc_release(struct inode *inode, struct file *file)
+{
+	/* Turn off interrupts? */
+
+        if (file->f_flags & FASYNC) {
+                hp_sdc_rtc_fasync (-1, file, 0);
+        }
+
+	MOD_DEC_USE_COUNT;
+        return 0;
+}
+
+static int hp_sdc_rtc_fasync (int fd, struct file *filp, int on)
+{
+        return fasync_helper (fd, filp, on, &hp_sdc_rtc_async_queue);
+}
+
+static int hp_sdc_rtc_proc_output (char *buf)
+{
+#define YN(bit) ("no")
+#define NY(bit) ("yes")
+        char *p;
+        struct rtc_time tm;
+	struct timeval tv;
+
+	memset(&tm, 0, sizeof(struct rtc_time));
+
+	p = buf;
+
+	if (hp_sdc_rtc_read_bbrtc(&tm)) {
+		p += sprintf(p, "BBRTC\t\t: READ FAILED!\n");
+	} else {
+		p += sprintf(p,
+			     "rtc_time\t: %02d:%02d:%02d\n"
+			     "rtc_date\t: %04d-%02d-%02d\n"
+			     "rtc_epoch\t: %04lu\n",
+			     tm.tm_hour, tm.tm_min, tm.tm_sec,
+			     tm.tm_year + 1900, tm.tm_mon + 1, 
+			     tm.tm_mday, epoch);
+	}
+
+	if (hp_sdc_rtc_read_rt(&tv)) {
+		p += sprintf(p, "i8042 rtc\t: READ FAILED!\n");
+	} else {
+		p += sprintf(p, "i8042 rtc\t: %d.%02d seconds\n", 
+			     tv.tv_sec, tv.tv_usec/1000);
+	}
+
+	if (hp_sdc_rtc_read_fhs(&tv)) {
+		p += sprintf(p, "handshake\t: READ FAILED!\n");
+	} else {
+        	p += sprintf(p, "handshake\t: %d.%02d seconds\n", 
+			     tv.tv_sec, tv.tv_usec/1000);
+	}
+
+	if (hp_sdc_rtc_read_mt(&tv)) {
+		p += sprintf(p, "alarm\t\t: READ FAILED!\n");
+	} else {
+		p += sprintf(p, "alarm\t\t: %d.%02d seconds\n", 
+			     tv.tv_sec, tv.tv_usec/1000);
+	}
+
+	if (hp_sdc_rtc_read_dt(&tv)) {
+		p += sprintf(p, "delay\t\t: READ FAILED!\n");
+	} else {
+		p += sprintf(p, "delay\t\t: %d.%02d seconds\n", 
+			     tv.tv_sec, tv.tv_usec/1000);
+	}
+
+	if (hp_sdc_rtc_read_ct(&tv)) {
+		p += sprintf(p, "periodic\t: READ FAILED!\n");
+	} else {
+		p += sprintf(p, "periodic\t: %d.%02d seconds\n", 
+			     tv.tv_sec, tv.tv_usec/1000);
+	}
+
+        p += sprintf(p,
+                     "DST_enable\t: %s\n"
+                     "BCD\t\t: %s\n"
+                     "24hr\t\t: %s\n"
+                     "square_wave\t: %s\n"
+                     "alarm_IRQ\t: %s\n"
+                     "update_IRQ\t: %s\n"
+                     "periodic_IRQ\t: %s\n"
+		     "periodic_freq\t: %ld\n"
+                     "batt_status\t: %s\n",
+                     YN(RTC_DST_EN),
+                     NY(RTC_DM_BINARY),
+                     YN(RTC_24H),
+                     YN(RTC_SQWE),
+                     YN(RTC_AIE),
+                     YN(RTC_UIE),
+                     YN(RTC_PIE),
+                     1UL,
+                     1 ? "okay" : "dead");
+
+        return  p - buf;
+#undef YN
+#undef NY
+}
+
+static int hp_sdc_rtc_read_proc(char *page, char **start, off_t off,
+                         int count, int *eof, void *data)
+{
+	int len = hp_sdc_rtc_proc_output (page);
+        if (len <= off+count) *eof = 1;
+        *start = page + off;
+        len -= off;
+        if (len>count) len = count;
+        if (len<0) len = 0;
+        return len;
+}
+
+static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file, 
+			    unsigned int cmd, unsigned long arg)
+{
+#if 1
+	return -EINVAL;
+#else
+	
+        struct rtc_time wtime; 
+	struct timeval ttime;
+	int use_wtime = 0;
+
+	/* This needs major work. */
+
+        switch (cmd) {
+
+        case RTC_AIE_OFF:       /* Mask alarm int. enab. bit    */
+        case RTC_AIE_ON:        /* Allow alarm interrupts.      */
+	case RTC_PIE_OFF:       /* Mask periodic int. enab. bit */
+        case RTC_PIE_ON:        /* Allow periodic ints          */
+        case RTC_UIE_ON:        /* Allow ints for RTC updates.  */
+        case RTC_UIE_OFF:       /* Allow ints for RTC updates.  */
+        {
+		/* We cannot mask individual user timers and we
+		   cannot tell them apart when they occur, so it 
+		   would be disingenuous to succeed these IOCTLs */
+		return -EINVAL;
+        }
+        case RTC_ALM_READ:      /* Read the present alarm time */
+        {
+		if (hp_sdc_rtc_read_mt(&ttime)) return -EFAULT;
+                break;
+        }
+        case RTC_IRQP_READ:     /* Read the periodic IRQ rate.  */
+        {
+                return put_user(hp_sdc_rtc_freq, (unsigned long *)arg);
+        }
+        case RTC_IRQP_SET:      /* Set periodic IRQ rate.       */
+        {
+                /* 
+                 * The max we can do is 100Hz.
+		 */
+
+                if ((arg < 1) || (arg > 100)) return -EINVAL;
+		ttime.tv_sec = 0;
+		ttime.tv_usec = 1000000 / arg;
+		if (hp_sdc_rtc_set_ct(&ttime)) return -EFAULT;
+		hp_sdc_rtc_freq = arg;
+                return 0;
+        }
+        case RTC_ALM_SET:       /* Store a time into the alarm */
+        {
+                /*
+                 * This expects a struct hp_sdc_rtc_time. Writing 0xff means
+                 * "don't care" or "match all" for PC timers.  The HP SDC
+		 * does not support that perk, but it could be emulated fairly
+		 * easily.  Only the tm_hour, tm_min and tm_sec are used.
+		 * We could do it with 10ms accuracy with the HP SDC, if the 
+		 * rtc interface left us a way to do that.
+                 */
+                struct hp_sdc_rtc_time alm_tm;
+
+                if (copy_from_user(&alm_tm, (struct hp_sdc_rtc_time*)arg,
+                                   sizeof(struct hp_sdc_rtc_time)))
+                       return -EFAULT;
+
+                if (alm_tm.tm_hour > 23) return -EINVAL;
+		if (alm_tm.tm_min  > 59) return -EINVAL;
+		if (alm_tm.tm_sec  > 59) return -EINVAL;  
+
+		ttime.sec = alm_tm.tm_hour * 3600 + 
+		  alm_tm.tm_min * 60 + alm_tm.tm_sec;
+		ttime.usec = 0;
+		if (hp_sdc_rtc_set_mt(&ttime)) return -EFAULT;
+                return 0;
+        }
+        case RTC_RD_TIME:       /* Read the time/date from RTC  */
+        {
+		if (hp_sdc_rtc_read_bbrtc(&wtime)) return -EFAULT;
+                break;
+        }
+        case RTC_SET_TIME:      /* Set the RTC */
+        {
+                struct rtc_time hp_sdc_rtc_tm;
+                unsigned char mon, day, hrs, min, sec, leap_yr;
+                unsigned int yrs;
+
+                if (!capable(CAP_SYS_TIME))
+                        return -EACCES;
+		if (copy_from_user(&hp_sdc_rtc_tm, (struct rtc_time *)arg,
+                                   sizeof(struct rtc_time)))
+                        return -EFAULT;
+
+                yrs = hp_sdc_rtc_tm.tm_year + 1900;
+                mon = hp_sdc_rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
+                day = hp_sdc_rtc_tm.tm_mday;
+                hrs = hp_sdc_rtc_tm.tm_hour;
+                min = hp_sdc_rtc_tm.tm_min;
+                sec = hp_sdc_rtc_tm.tm_sec;
+
+                if (yrs < 1970)
+                        return -EINVAL;
+
+                leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
+
+                if ((mon > 12) || (day == 0))
+                        return -EINVAL;
+                if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
+                        return -EINVAL;
+		if ((hrs >= 24) || (min >= 60) || (sec >= 60))
+                        return -EINVAL;
+
+                if ((yrs -= eH) > 255)    /* They are unsigned */
+                        return -EINVAL;
+
+
+                return 0;
+        }
+        case RTC_epoch_READ:    /* Read the epoch.      */
+        {
+                return put_user (epoch, (unsigned long *)arg);
+        }
+        case RTC_EPOCH_SET:     /* Set the epoch.       */
+        {
+                /* 
+                 * There were no RTC clocks before 1900.
+                 */
+                if (arg < 1900)
+		  return -EINVAL;
+		if (!capable(CAP_SYS_TIME))
+		  return -EACCES;
+		
+                epoch = arg;
+                return 0;
+        }
+        default:
+                return -EINVAL;
+        }
+        return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
+#endif
+}
+
+static struct file_operations hp_sdc_rtc_fops = {
+        owner:          THIS_MODULE,
+        llseek:         hp_sdc_rtc_llseek,
+        read:           hp_sdc_rtc_read,
+        poll:           hp_sdc_rtc_poll,
+        ioctl:          hp_sdc_rtc_ioctl,
+        open:           hp_sdc_rtc_open,
+        release:        hp_sdc_rtc_release,
+        fasync:         hp_sdc_rtc_fasync,
+};
+
+static struct miscdevice hp_sdc_rtc_dev = {
+        minor:		RTC_MINOR,
+        name:		"rtc",
+        fops:		&hp_sdc_rtc_fops
+};
+
+static int __init hp_sdc_rtc_init(void)
+{
+	int ret;
+
+	init_MUTEX(&i8042tregs);
+
+	if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr)))
+		return ret;
+	misc_register(&hp_sdc_rtc_dev);
+        create_proc_read_entry ("driver/rtc", 0, 0, 
+				hp_sdc_rtc_read_proc, NULL);
+
+	printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support loaded "
+			 "(RTC v " RTC_VERSION ")\n");
+
+	return 0;
+}
+
+static void __exit hp_sdc_rtc_exit(void)
+{
+	remove_proc_entry ("driver/rtc", NULL);
+        misc_deregister(&hp_sdc_rtc_dev);
+	hp_sdc_release_timer_irq(hp_sdc_rtc_isr);
+        printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support unloaded\n");
+}
+
+module_init(hp_sdc_rtc_init);
+module_exit(hp_sdc_rtc_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/Makefile linux-2.4.20/drivers/hotplug/Makefile
--- linux-2.4.19/drivers/hotplug/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/Makefile	2002-10-29 11:18:33.000000000 +0000
@@ -4,14 +4,14 @@
 
 O_TARGET	:= vmlinux-obj.o
 
-list-multi	:= cpqphp.o pci_hotplug.o ibmphp.o pcihpacpi.o 
+list-multi	:= cpqphp.o pci_hotplug.o ibmphp.o acpiphp.o 
 
 export-objs	:= pci_hotplug_core.o pci_hotplug_util.o
 
 obj-$(CONFIG_HOTPLUG_PCI)		+= pci_hotplug.o
 obj-$(CONFIG_HOTPLUG_PCI_COMPAQ)	+= cpqphp.o
 obj-$(CONFIG_HOTPLUG_PCI_IBM)		+= ibmphp.o
-obj-$(CONFIG_HOTPLUG_PCI_ACPI)		+= pcihpacpi.o
+obj-$(CONFIG_HOTPLUG_PCI_ACPI)		+= acpiphp.o
 
 pci_hotplug-objs	:=	pci_hotplug_core.o	\
 				pci_hotplug_util.o
@@ -34,8 +34,10 @@
   endif
 endif
 
-pcihp_acpi_objs		:=	pcihp_acpi.o	\
-				pcihp_acpi_glue.o
+acpiphp_objs		:=	acpiphp_core.o	\
+				acpiphp_glue.o	\
+				acpiphp_pci.o	\
+				acpiphp_res.o
 
 ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y)
 	cpqphp-objs += cpqphp_nvram.o
@@ -53,5 +55,5 @@
 ibmphp.o: $(ibmphp-objs)
 	$(LD) -r -o $@ $(ibmphp-objs)
 
-pcihpacpi.o: $(pcihp_acpi_objs)
-	$(LD) -r -o $@ $(pcihp_acpi_objs)
+acpiphp.o: $(acpiphp_objs)
+	$(LD) -r -o $@ $(acpiphp_objs)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/acpiphp.h linux-2.4.20/drivers/hotplug/acpiphp.h
--- linux-2.4.19/drivers/hotplug/acpiphp.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/acpiphp.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,322 @@
+/*
+ * ACPI PCI Hot Plug Controller Driver
+ *
+ * Copyright (c) 1995,2001 Compaq Computer Corporation
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001 IBM Corp.
+ * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
+ * Copyright (c) 2002 NEC Corporation
+ *
+ * All rights reserved.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>,
+ *		    <h-aono@ap.jp.nec.com>,
+ *		    <t-kouchi@cq.jp.nec.com>
+ *
+ */
+
+#ifndef _ACPIPHP_H
+#define _ACPIPHP_H
+
+#include "include/acpi.h"
+#include "pci_hotplug.h"
+
+#if ACPI_CA_VERSION < 0x20020201
+/* until we get a new version of the ACPI driver for both ia32 and ia64 ... */
+#define acpi_util_eval_error(h,p,s)
+
+static acpi_status
+acpi_evaluate_integer (
+	acpi_handle		handle,
+	acpi_string		pathname,
+	acpi_object_list	*arguments,
+	unsigned long		*data)
+{
+	acpi_status		status = AE_OK;
+	acpi_object		element;
+	acpi_buffer		buffer = {sizeof(acpi_object), &element};
+
+	if (!data)
+		return AE_BAD_PARAMETER;
+
+	status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
+	if (ACPI_FAILURE(status)) {
+		acpi_util_eval_error(handle, pathname, status);
+		return status;
+	}
+
+	if (element.type != ACPI_TYPE_INTEGER) {
+		acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
+		return AE_BAD_DATA;
+	}
+
+	*data = element.integer.value;
+
+	return AE_OK;
+}
+#else  /* ACPI_CA_VERSION < 0x20020201 */
+#include "acpi_bus.h"
+#endif
+
+/* compatibility stuff for ACPI CA */
+#ifndef ACPI_MEMORY_RANGE
+#define ACPI_MEMORY_RANGE MEMORY_RANGE
+#endif
+
+#ifndef ACPI_IO_RANGE
+#define ACPI_IO_RANGE IO_RANGE
+#endif
+
+#ifndef ACPI_BUS_NUMBER_RANGE
+#define ACPI_BUS_NUMBER_RANGE BUS_NUMBER_RANGE
+#endif
+
+#ifndef ACPI_PREFETCHABLE_MEMORY
+#define ACPI_PREFETCHABLE_MEMORY PREFETCHABLE_MEMORY
+#endif
+
+#ifndef ACPI_PRODUCER
+#define ACPI_PRODUCER PRODUCER
+#endif
+
+#define dbg(format, arg...)					\
+	do {							\
+		if (debug)					\
+			printk (KERN_DEBUG "%s: " format "\n",	\
+				MY_NAME , ## arg); 		\
+	} while (0)
+#define err(format, arg...) printk (KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
+#define info(format, arg...) printk (KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
+#define warn(format, arg...) printk (KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
+
+#define SLOT_MAGIC	0x67267322
+/* name size which is used for entries in pcihpfs */
+#define SLOT_NAME_SIZE	16		/* ACPIxxxx */
+
+struct acpiphp_bridge;
+struct acpiphp_slot;
+struct pci_resource;
+
+/*
+ * struct slot - slot information for each *physical* slot
+ */
+struct slot {
+	u32 magic;
+	u8 number;
+	struct hotplug_slot	*hotplug_slot;
+	struct list_head	slot_list;
+
+	/* if there are multiple corresponding ACPI slot objects,
+	   this points to one of them */
+	struct acpiphp_slot	*acpi_slot;
+};
+
+/*
+ * struct pci_resource - describes pci resource (mem, pfmem, io, bus)
+ */
+struct pci_resource {
+	struct pci_resource * next;
+	u64 base;
+	u32 length;
+};
+
+/**
+ * struct hpp_param - ACPI 2.0 _HPP Hot Plug Parameters
+ * @cache_line_size in DWORD
+ * @latency_timer in PCI clock
+ * @enable_SERR 0 or 1
+ * @enable_PERR 0 or 1
+ */
+struct hpp_param {
+	u8 cache_line_size;
+	u8 latency_timer;
+	u8 enable_SERR;
+	u8 enable_PERR;
+};
+
+
+/**
+ * struct acpiphp_bridge - PCI bridge information
+ *
+ * for each bridge device in ACPI namespace
+ */
+struct acpiphp_bridge {
+	struct list_head list;
+	acpi_handle handle;
+	struct acpiphp_slot *slots;
+	int type;
+	int nr_slots;
+
+	u8 seg;
+	u8 bus;
+	u8 sub;
+
+	u32 flags;
+
+	/* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */
+	struct pci_bus *pci_bus;
+
+	/* PCI-to-PCI bridge device */
+	struct pci_dev *pci_dev;
+
+	struct pci_ops *pci_ops;
+
+	/* ACPI 2.0 _HPP parameters */
+	struct hpp_param hpp;
+
+	spinlock_t res_lock;
+
+	/* available resources on this bus */
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+};
+
+
+/**
+ * struct acpiphp_slot - PCI slot information
+ *
+ * PCI slot information for each *physical* PCI slot
+ */
+struct acpiphp_slot {
+	struct acpiphp_slot *next;
+	struct acpiphp_bridge *bridge;	/* parent */
+	struct list_head funcs;		/* one slot may have different
+					   objects (i.e. for each function) */
+	struct acpiphp_func *func;	/* functions */
+	struct semaphore crit_sect;
+
+	u32		id;		/* slot id (serial #) for hotplug core */
+	u8		device;		/* pci device# */
+
+	u32		sun;		/* ACPI _SUN (slot unique number) */
+	u32		slotno;		/* slot number relative to bridge */
+	u32		flags;		/* see below */
+};
+
+
+/**
+ * struct acpiphp_func - PCI slot information
+ *
+ * PCI function information for each object in ACPI namespace
+ * typically 8 objects per slot (i.e. for each PCI function)
+ */
+struct acpiphp_func {
+	struct acpiphp_slot *slot;	/* parent */
+
+	struct list_head sibling;
+	struct pci_dev *pci_dev;
+
+	acpi_handle	handle;
+
+	u8		function;	/* pci function# */
+	u32		flags;		/* see below */
+
+	/* resources used for this function */
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+};
+
+
+/* PCI bus bridge HID */
+#define ACPI_PCI_HOST_HID		"PNP0A03"
+
+/* PCI BRIDGE type */
+#define BRIDGE_TYPE_HOST		0
+#define BRIDGE_TYPE_P2P			1
+
+/* ACPI _STA method value (ignore bit 4; battery present) */
+#define ACPI_STA_PRESENT		(0x00000001)
+#define ACPI_STA_ENABLED		(0x00000002)
+#define ACPI_STA_SHOW_IN_UI		(0x00000004)
+#define ACPI_STA_FUNCTIONING		(0x00000008)
+#define ACPI_STA_ALL			(0x0000000f)
+
+/* bridge flags */
+#define BRIDGE_HAS_STA		(0x00000001)
+#define BRIDGE_HAS_EJ0		(0x00000002)
+#define BRIDGE_HAS_HPP		(0x00000004)
+#define BRIDGE_HAS_PS0		(0x00000010)
+#define BRIDGE_HAS_PS1		(0x00000020)
+#define BRIDGE_HAS_PS2		(0x00000040)
+#define BRIDGE_HAS_PS3		(0x00000080)
+
+/* slot flags */
+
+#define SLOT_POWEREDON		(0x00000001)
+#define SLOT_ENABLED		(0x00000002)
+#define SLOT_MULTIFUNCTION	(x000000004)
+
+/* function flags */
+
+#define FUNC_HAS_STA		(0x00000001)
+#define FUNC_HAS_EJ0		(0x00000002)
+#define FUNC_HAS_PS0		(0x00000010)
+#define FUNC_HAS_PS1		(0x00000020)
+#define FUNC_HAS_PS2		(0x00000040)
+#define FUNC_HAS_PS3		(0x00000080)
+
+/* not yet */
+#define SLOT_SUPPORT_66MHZ	(0x00010000)
+#define SLOT_SUPPORT_100MHZ	(0x00020000)
+#define SLOT_SUPPORT_133MHZ	(0x00040000)
+#define SLOT_SUPPORT_PCIX	(0x00080000)
+
+/* function prototypes */
+
+/* acpiphp_glue.c */
+extern int acpiphp_glue_init (void);
+extern void acpiphp_glue_exit (void);
+extern int acpiphp_get_num_slots (void);
+extern struct acpiphp_slot *get_slot_from_id (int id);
+typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
+extern int acpiphp_for_each_slot (acpiphp_callback fn, void *data);
+
+extern int acpiphp_check_bridge (struct acpiphp_bridge *bridge);
+extern int acpiphp_enable_slot (struct acpiphp_slot *slot);
+extern int acpiphp_disable_slot (struct acpiphp_slot *slot);
+extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot);
+extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot);
+extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot);
+extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot);
+
+/* acpiphp_pci.c */
+extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn);
+extern int acpiphp_configure_slot (struct acpiphp_slot *slot);
+extern int acpiphp_configure_function (struct acpiphp_func *func);
+extern int acpiphp_unconfigure_function (struct acpiphp_func *func);
+extern int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge);
+extern int acpiphp_init_func_resource (struct acpiphp_func *func);
+
+/* acpiphp_res.c */
+extern struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size);
+extern struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size);
+extern struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size);
+extern struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size);
+extern int acpiphp_resource_sort_and_combine (struct pci_resource **head);
+extern struct pci_resource *acpiphp_make_resource (u64 base, u32 length);
+extern void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to);
+extern void acpiphp_free_resource (struct pci_resource **res);
+extern void acpiphp_dump_resource (struct acpiphp_bridge *bridge); /* debug */
+extern void acpiphp_dump_func_resource (struct acpiphp_func *func); /* debug */
+
+#endif /* _ACPIPHP_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/acpiphp_core.c linux-2.4.20/drivers/hotplug/acpiphp_core.c
--- linux-2.4.19/drivers/hotplug/acpiphp_core.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/acpiphp_core.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,470 @@
+/*
+ * ACPI PCI Hot Plug Controller Driver
+ *
+ * Copyright (c) 1995,2001 Compaq Computer Corporation
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001 IBM Corp.
+ * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
+ * Copyright (c) 2002 NEC Corporation
+ *
+ * All rights reserved.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>,
+ *                  <h-aono@ap.jp.nec.com>,
+ *		    <t-kouchi@cq.jp.nec.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include "pci_hotplug.h"
+#include "acpiphp.h"
+
+static LIST_HEAD(slot_list);
+
+#if !defined(CONFIG_HOTPLUG_PCI_ACPI_MODULE)
+	#define MY_NAME	"acpiphp"
+#else
+	#define MY_NAME	THIS_MODULE->name
+#endif
+
+/* local variables */
+static int debug = 1;			/* XXX set to 0 after debug */
+static int num_slots;
+
+#define DRIVER_VERSION	"0.3"
+#define DRIVER_AUTHOR	"Greg Kroah-Hartman <gregkh@us.ibm.com>"
+#define DRIVER_DESC	"ACPI Hot Plug PCI Controller Driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+
+static int enable_slot		(struct hotplug_slot *slot);
+static int disable_slot		(struct hotplug_slot *slot);
+static int set_attention_status (struct hotplug_slot *slot, u8 value);
+static int hardware_test	(struct hotplug_slot *slot, u32 value);
+static int get_power_status	(struct hotplug_slot *slot, u8 *value);
+static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
+static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
+static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+
+static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
+	owner:			THIS_MODULE,
+	enable_slot:		enable_slot,
+	disable_slot:		disable_slot,
+	set_attention_status:	set_attention_status,
+	hardware_test:		hardware_test,
+	get_power_status:	get_power_status,
+	get_attention_status:	get_attention_status,
+	get_latch_status:	get_latch_status,
+	get_adapter_status:	get_adapter_status,
+};
+
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+static inline int slot_paranoia_check (struct slot *slot, const char *function)
+{
+	if (!slot) {
+		dbg("%s - slot == NULL", function);
+		return -1;
+	}
+	if (slot->magic != SLOT_MAGIC) {
+		dbg("%s - bad magic number for slot", function);
+		return -1;
+	}
+	if (!slot->hotplug_slot) {
+		dbg("%s - slot->hotplug_slot == NULL!", function);
+		return -1;
+	}
+	return 0;
+}
+
+
+static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
+{ 
+	struct slot *slot;
+
+	if (!hotplug_slot) {
+		dbg("%s - hotplug_slot == NULL", function);
+		return NULL;
+	}
+
+	slot = (struct slot *)hotplug_slot->private;
+	if (slot_paranoia_check (slot, function))
+                return NULL;
+	return slot;
+}
+
+
+/**
+ * enable_slot - power on and enable a slot
+ * @hotplug_slot: slot to enable
+ *
+ * Actual tasks are done in acpiphp_enable_slot()
+ *
+ */
+static int enable_slot (struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	/* enable the specified slot */
+	retval = acpiphp_enable_slot (slot->acpi_slot);
+
+	return retval;
+}
+
+
+/**
+ * disable_slot - disable and power off a slot
+ * @hotplug_slot: slot to disable
+ *
+ * Actual tasks are done in acpiphp_disable_slot()
+ *
+ */
+static int disable_slot (struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	/* disable the specified slot */
+	retval = acpiphp_disable_slot (slot->acpi_slot);
+
+	return retval;
+}
+
+
+/**
+ * set_attention_status - set attention LED
+ *
+ * TBD:
+ * ACPI doesn't have known method to manipulate
+ * attention status LED.
+ *
+ */
+static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
+{
+	int retval = 0;
+	
+	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	switch (status) {
+		case 0:
+			/* FIXME turn light off */
+			hotplug_slot->info->attention_status = 0;
+			break;
+
+		case 1:
+		default:
+			/* FIXME turn light on */
+			hotplug_slot->info->attention_status = 1;
+			break;
+	}
+
+	return retval;
+}
+
+
+/**
+ * hardware_test - hardware test
+ *
+ * We have nothing to do for now...
+ *
+ */
+static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	err ("No hardware tests are defined for this driver");
+	retval = -ENODEV;
+
+	return retval;
+}
+
+
+/**
+ * get_power_status - get power status of a slot
+ * @hotplug_slot: slot to get status
+ * @value: pointer to store status
+ *
+ * Some platforms may not implement _STA method properly.
+ * In that case, the value returned may not be reliable.
+ *
+ */
+static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_power_status (slot->acpi_slot);
+
+	return retval;
+}
+
+
+/**
+ * get_attention_status - get attention LED status
+ *
+ * TBD:
+ * ACPI doesn't provide any formal means to access attention LED status.
+ *
+ */
+static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	int retval = 0;
+	
+	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	*value = hotplug_slot->info->attention_status;
+
+	return retval;
+}
+
+
+/**
+ * get_latch_status - get latch status of a slot
+ * @hotplug_slot: slot to get status
+ * @value: pointer to store status
+ *
+ * ACPI doesn't provide any formal means to access latch status.
+ * Instead, we fake latch status from _STA
+ *
+ */
+static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_latch_status (slot->acpi_slot);
+
+	return retval;
+}
+
+
+/**
+ * get_adapter_status - get adapter status of a slot
+ * @hotplug_slot: slot to get status
+ * @value: pointer to store status
+ *
+ * ACPI doesn't provide any formal means to access adapter status.
+ * Instead, we fake adapter status from _STA
+ *
+ */
+static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_adapter_status (slot->acpi_slot);
+
+	return retval;
+}
+
+
+static int init_acpi (void)
+{
+	int retval;
+
+	/* initialize internal data structure etc. */
+	retval = acpiphp_glue_init();
+
+	/* read initial number of slots */
+	if (!retval) {
+		num_slots = acpiphp_get_num_slots();
+		if (num_slots == 0)
+			retval = -ENODEV;
+	}
+
+	return retval;
+}
+
+
+static void exit_acpi (void)
+{
+	/* deallocate internal data structures etc. */
+	acpiphp_glue_exit();
+}
+
+
+/**
+ * make_slot_name - make a slot name that appears in pcihpfs
+ * @slot: slot to name
+ *
+ */
+static void make_slot_name (struct slot *slot)
+{
+	snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%x", slot->acpi_slot->sun);
+}
+
+/**
+ * init_slots - initialize 'struct slot' structures for each slot
+ *
+ */
+static int init_slots (void)
+{
+	struct slot *slot;
+	int retval = 0;
+	int i;
+
+	for (i = 0; i < num_slots; ++i) {
+		slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
+		if (!slot)
+			return -ENOMEM;
+		memset(slot, 0, sizeof(struct slot));
+
+		slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
+		if (!slot->hotplug_slot) {
+			kfree (slot);
+			return -ENOMEM;
+		}
+		memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
+
+		slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+		if (!slot->hotplug_slot->info) {
+			kfree (slot->hotplug_slot);
+			kfree (slot);
+			return -ENOMEM;
+		}
+		memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
+
+		slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
+		if (!slot->hotplug_slot->name) {
+			kfree (slot->hotplug_slot->info);
+			kfree (slot->hotplug_slot);
+			kfree (slot);
+			return -ENOMEM;
+		}
+
+		slot->magic = SLOT_MAGIC;
+		slot->number = i;
+
+		slot->hotplug_slot->private = slot;
+		slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
+
+		slot->acpi_slot = get_slot_from_id (i);
+		slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
+		slot->hotplug_slot->info->attention_status = acpiphp_get_attention_status(slot->acpi_slot);
+		slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
+		slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
+
+		make_slot_name (slot);
+
+		retval = pci_hp_register (slot->hotplug_slot);
+		if (retval) {
+			err ("pci_hp_register failed with error %d", retval);
+			kfree (slot->hotplug_slot->info);
+			kfree (slot->hotplug_slot->name);
+			kfree (slot->hotplug_slot);
+			kfree (slot);
+			return retval;
+		}
+
+		/* add slot to our internal list */
+		list_add (&slot->slot_list, &slot_list);
+	}
+
+	return retval;
+}
+
+
+static void cleanup_slots (void)
+{
+	struct list_head *tmp;
+	struct slot *slot;
+
+	list_for_each (tmp, &slot_list) {
+		slot = list_entry (tmp, struct slot, slot_list);
+		list_del (&slot->slot_list);
+		pci_hp_deregister (slot->hotplug_slot);
+		kfree (slot->hotplug_slot->info);
+		kfree (slot->hotplug_slot->name);
+		kfree (slot->hotplug_slot);
+		kfree (slot);
+	}
+
+	return;
+}
+
+
+static int __init acpiphp_init(void)
+{
+	int retval;
+
+	/* read all the ACPI info from the system */
+	retval = init_acpi();
+	if (retval)
+		return retval;
+
+	retval = init_slots();
+	if (retval)
+		return retval;
+
+	info (DRIVER_DESC " version: " DRIVER_VERSION);
+	return 0;
+}
+
+
+static void __exit acpiphp_exit(void)
+{
+	cleanup_slots();
+	exit_acpi();
+}
+
+module_init(acpiphp_init);
+module_exit(acpiphp_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/acpiphp_glue.c linux-2.4.20/drivers/hotplug/acpiphp_glue.c
--- linux-2.4.19/drivers/hotplug/acpiphp_glue.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/acpiphp_glue.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,1514 @@
+/*
+ * ACPI PCI HotPlug glue functions to ACPI CA subsystem
+ *
+ * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
+ * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (c) 2002 NEC Corporation
+ *
+ * All rights reserved.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <t-kouchi@cq.jp.nec.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <asm/semaphore.h>
+
+#include "pci_hotplug.h"
+#include "acpiphp.h"
+
+static LIST_HEAD(bridge_list);
+
+static int debug = 1;			/* XXX set 0 after debug */
+#define MY_NAME "acpiphp_glue"
+
+static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
+static void handle_hotplug_event_func (acpi_handle, u32, void *);
+static struct pci_ops *default_ops;
+
+/*
+ * initialization & terminatation routines
+ */
+
+/**
+ * is_ejectable - determine if a slot is ejectable
+ * @handle: handle to acpi namespace
+ *
+ * Ejectable slot should satisfy at least these conditions:
+ *
+ *  1. has _ADR method
+ *  2. has _EJ0 method
+ *
+ * optionally
+ *
+ *  1. has _STA method
+ *  2. has _PS0 method
+ *  3. has _PS3 method
+ *  4. ..
+ *
+ */
+static int is_ejectable (acpi_handle handle)
+{
+	acpi_status status;
+	acpi_handle tmp;
+
+	status = acpi_get_handle(handle, "_ADR", &tmp);
+	if (ACPI_FAILURE(status)) {
+		return 0;
+	}
+
+	status = acpi_get_handle(handle, "_EJ0", &tmp);
+	if (ACPI_FAILURE(status)) {
+		return 0;
+	}
+
+	return 1;
+}
+
+
+/* callback routine to check the existence of ejectable slots */
+static acpi_status
+is_ejectable_slot (acpi_handle handle, u32 lvl,	void *context, void **rv)
+{
+	acpi_status status;
+	acpi_handle tmp;
+	int *count = (int *)context;
+
+	if (is_ejectable(handle)) {
+		(*count)++;
+		/* only one ejectable slot is enough */
+		return AE_CTRL_TERMINATE;
+	} else {
+		return AE_OK;
+	}
+}
+
+
+/* callback routine to register each ACPI PCI slot object */
+static acpi_status
+register_slot (acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context;
+	struct acpiphp_slot *slot;
+	struct acpiphp_func *newfunc;
+	acpi_handle tmp;
+	acpi_status status = AE_OK;
+	unsigned long adr, sun;
+	int device, function;
+	static int num_slots = 0;	/* XXX if we support I/O node hotplug... */
+
+	status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
+
+	if (ACPI_FAILURE(status))
+		return AE_OK;
+
+	status = acpi_get_handle(handle, "_EJ0", &tmp);
+
+	if (ACPI_FAILURE(status))
+		return AE_OK;
+
+	device = (adr >> 16) & 0xffff;
+	function = adr & 0xffff;
+
+	newfunc = kmalloc(sizeof(struct acpiphp_func), GFP_KERNEL);
+	if (!newfunc)
+		return AE_NO_MEMORY;
+	memset(newfunc, 0, sizeof(struct acpiphp_func));
+
+	INIT_LIST_HEAD(&newfunc->sibling);
+	newfunc->handle = handle;
+	newfunc->function = function;
+	newfunc->flags = FUNC_HAS_EJ0;
+
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp)))
+		newfunc->flags |= FUNC_HAS_STA;
+
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp)))
+		newfunc->flags |= FUNC_HAS_PS0;
+
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp)))
+		newfunc->flags |= FUNC_HAS_PS3;
+
+	status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
+	if (ACPI_FAILURE(status))
+		sun = -1;
+
+	/* search for objects that share the same slot */
+	for (slot = bridge->slots; slot; slot = slot->next)
+		if (slot->device == device) {
+			if (slot->sun != sun)
+				warn("sibling found, but _SUN doesn't match!");
+			break;
+		}
+
+	if (!slot) {
+		slot = kmalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
+		if (!slot) {
+			kfree(newfunc);
+			return AE_NO_MEMORY;
+		}
+
+		memset(slot, 0, sizeof(struct acpiphp_slot));
+		slot->bridge = bridge;
+		slot->id = num_slots++;
+		slot->device = device;
+		slot->sun = sun;
+		INIT_LIST_HEAD(&slot->funcs);
+		init_MUTEX(&slot->crit_sect);
+
+		slot->next = bridge->slots;
+		bridge->slots = slot;
+
+		bridge->nr_slots++;
+
+		dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d",
+		    slot->bridge->bus, slot->device, slot->sun);
+	}
+
+	newfunc->slot = slot;
+	list_add_tail(&newfunc->sibling, &slot->funcs);
+
+	/* associate corresponding pci_dev */
+	newfunc->pci_dev = pci_find_slot(bridge->bus,
+					 PCI_DEVFN(device, function));
+	if (newfunc->pci_dev) {
+		if (acpiphp_init_func_resource(newfunc) < 0) {
+			kfree(newfunc);
+			return AE_ERROR;
+		}
+		slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
+	}
+
+	/* install notify handler */
+	status = acpi_install_notify_handler(handle,
+					     ACPI_SYSTEM_NOTIFY,
+					     handle_hotplug_event_func,
+					     newfunc);
+
+	if (ACPI_FAILURE(status)) {
+		err("failed to register interrupt notify handler");
+		return status;
+	}
+
+	return AE_OK;
+}
+
+
+/* see if it's worth looking at this bridge */
+static int detect_ejectable_slots (acpi_handle *bridge_handle)
+{
+	acpi_status status;
+	int count;
+
+	count = 0;
+
+	/* only check slots defined directly below bridge object */
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1,
+				     is_ejectable_slot, (void *)&count, NULL);
+
+	return count;
+}
+
+
+/* decode ACPI _CRS data and convert into our internal resource list
+ * TBD: _TRA, etc.
+ */
+static void
+decode_acpi_resource (acpi_resource *resource, struct acpiphp_bridge *bridge)
+{
+	acpi_resource_address16 *address16_data;
+	acpi_resource_address32 *address32_data;
+	acpi_resource_address64 *address64_data;
+	struct pci_resource *res;
+
+	u32 resource_type, producer_consumer, address_length;
+	u64 min_address_range, max_address_range;
+	u16 cache_attribute = 0;
+
+	int done = 0, found;
+
+	/* shut up gcc */
+	resource_type = producer_consumer = address_length = 0;
+	min_address_range = max_address_range = 0;
+
+	while (!done) {
+		found = 0;
+
+		switch (resource->id) {
+		case ACPI_RSTYPE_ADDRESS16:
+			address16_data = (acpi_resource_address16 *)&resource->data;
+			resource_type = address16_data->resource_type;
+			producer_consumer = address16_data->producer_consumer;
+			min_address_range = address16_data->min_address_range;
+			max_address_range = address16_data->max_address_range;
+			address_length = address16_data->address_length;
+			if (resource_type == ACPI_MEMORY_RANGE)
+				cache_attribute = address16_data->attribute.memory.cache_attribute;
+			found = 1;
+			break;
+
+		case ACPI_RSTYPE_ADDRESS32:
+			address32_data = (acpi_resource_address32 *)&resource->data;
+			resource_type = address32_data->resource_type;
+			producer_consumer = address32_data->producer_consumer;
+			min_address_range = address32_data->min_address_range;
+			max_address_range = address32_data->max_address_range;
+			address_length = address32_data->address_length;
+			if (resource_type == ACPI_MEMORY_RANGE)
+				cache_attribute = address32_data->attribute.memory.cache_attribute;
+			found = 1;
+			break;
+
+		case ACPI_RSTYPE_ADDRESS64:
+			address64_data = (acpi_resource_address64 *)&resource->data;
+			resource_type = address64_data->resource_type;
+			producer_consumer = address64_data->producer_consumer;
+			min_address_range = address64_data->min_address_range;
+			max_address_range = address64_data->max_address_range;
+			address_length = address64_data->address_length;
+			if (resource_type == ACPI_MEMORY_RANGE)
+				cache_attribute = address64_data->attribute.memory.cache_attribute;
+			found = 1;
+			break;
+
+		case ACPI_RSTYPE_END_TAG:
+			done = 1;
+			break;
+
+		default:
+			/* ignore */
+			break;
+		}
+
+		resource = (acpi_resource *)((char*)resource + resource->length);
+
+		if (found && producer_consumer == ACPI_PRODUCER && address_length > 0) {
+			switch (resource_type) {
+			case ACPI_MEMORY_RANGE:
+				if (cache_attribute == ACPI_PREFETCHABLE_MEMORY) {
+					dbg("resource type: prefetchable memory 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
+					res = acpiphp_make_resource(min_address_range,
+							    address_length);
+					if (!res) {
+						err("out of memory");
+						return;
+					}
+					res->next = bridge->p_mem_head;
+					bridge->p_mem_head = res;
+				} else {
+					dbg("resource type: memory 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
+					res = acpiphp_make_resource(min_address_range,
+							    address_length);
+					if (!res) {
+						err("out of memory");
+						return;
+					}
+					res->next = bridge->mem_head;
+					bridge->mem_head = res;
+				}
+				break;
+			case ACPI_IO_RANGE:
+				dbg("resource type: io 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
+				res = acpiphp_make_resource(min_address_range,
+						    address_length);
+				if (!res) {
+					err("out of memory");
+					return;
+				}
+				res->next = bridge->io_head;
+				bridge->io_head = res;
+				break;
+			case ACPI_BUS_NUMBER_RANGE:
+				dbg("resource type: bus number %d - %d", (u32)min_address_range, (u32)max_address_range);
+				res = acpiphp_make_resource(min_address_range,
+						    address_length);
+				if (!res) {
+					err("out of memory");
+					return;
+				}
+				res->next = bridge->bus_head;
+				bridge->bus_head = res;
+				break;
+			default:
+				/* invalid type */
+				break;
+			}
+		}
+	}
+
+	acpiphp_resource_sort_and_combine(&bridge->io_head);
+	acpiphp_resource_sort_and_combine(&bridge->mem_head);
+	acpiphp_resource_sort_and_combine(&bridge->p_mem_head);
+	acpiphp_resource_sort_and_combine(&bridge->bus_head);
+#if 1
+	info("ACPI _CRS resource:");
+	acpiphp_dump_resource(bridge);
+#endif
+}
+
+
+/* find pci_bus structure associated to specific bus number */
+static struct pci_bus *find_pci_bus(const struct list_head *list, int bus)
+{
+	const struct list_head *l;
+
+	list_for_each(l, list) {
+		struct pci_bus *b = pci_bus_b(l);
+		if (b->number == bus)
+			return b;
+
+		if (!list_empty(&b->children)) {
+			/* XXX recursive call */
+			b = find_pci_bus(&b->children, bus);
+
+			if (b)
+				return b;
+		}
+	}
+
+	return 0;
+}
+
+
+/* decode ACPI 2.0 _HPP hot plug parameters */
+static void decode_hpp(struct acpiphp_bridge *bridge)
+{
+	acpi_status status;
+#if ACPI_CA_VERSION < 0x20020201
+	acpi_buffer buffer;
+#else
+	acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+#endif
+	acpi_object *package;
+	int i;
+
+	/* default numbers */
+	bridge->hpp.cache_line_size = 0x10;
+	bridge->hpp.latency_timer = 0x40;
+	bridge->hpp.enable_SERR = 0;
+	bridge->hpp.enable_PERR = 0;
+
+#if ACPI_CA_VERSION < 0x20020201
+	buffer.length = 0;
+	buffer.pointer = NULL;
+
+	status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer);
+
+	if (status == AE_BUFFER_OVERFLOW) {
+		buffer.pointer = kmalloc(buffer.length, GFP_KERNEL);
+		if (!buffer.pointer)
+			return;
+		status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer);
+	}
+#else
+	status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer);
+#endif
+
+	if (ACPI_FAILURE(status)) {
+		dbg("_HPP evaluation failed");
+		return;
+	}
+
+	package = (acpi_object *) buffer.pointer;
+
+	if (!package || package->type != ACPI_TYPE_PACKAGE ||
+	    package->package.count != 4 || !package->package.elements) {
+		err("invalid _HPP object; ignoring");
+		goto err_exit;
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (package->package.elements[i].type != ACPI_TYPE_INTEGER) {
+			err("invalid _HPP parameter type; ignoring");
+			goto err_exit;
+		}
+	}
+
+	bridge->hpp.cache_line_size = package->package.elements[0].integer.value;
+	bridge->hpp.latency_timer = package->package.elements[1].integer.value;
+	bridge->hpp.enable_SERR = package->package.elements[2].integer.value;
+	bridge->hpp.enable_PERR = package->package.elements[3].integer.value;
+
+	dbg("_HPP parameter = (%02x, %02x, %02x, %02x)",
+	    bridge->hpp.cache_line_size,
+	    bridge->hpp.latency_timer,
+	    bridge->hpp.enable_SERR,
+	    bridge->hpp.enable_PERR);
+
+	bridge->flags |= BRIDGE_HAS_HPP;
+
+ err_exit:
+	kfree(buffer.pointer);
+}
+
+
+/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */
+static void init_bridge_misc (struct acpiphp_bridge *bridge)
+{
+	acpi_status status;
+
+	/* decode ACPI 2.0 _HPP (hot plug parameters) */
+	decode_hpp(bridge);
+
+	/* subtract all resources already allocated */
+	acpiphp_detect_pci_resource(bridge);
+
+	/* register all slot objects under this bridge */
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1,
+				     register_slot, bridge, NULL);
+
+	/* install notify handler */
+	status = acpi_install_notify_handler(bridge->handle,
+					     ACPI_SYSTEM_NOTIFY,
+					     handle_hotplug_event_bridge,
+					     bridge);
+
+	if (ACPI_FAILURE(status)) {
+		err("failed to register interrupt notify handler");
+	}
+
+	list_add(&bridge->list, &bridge_list);
+
+#if 1
+	dbg("Bridge resource:");
+	acpiphp_dump_resource(bridge);
+#endif
+}
+
+
+/* allocate and initialize host bridge data structure */
+static void add_host_bridge (acpi_handle *handle, int seg, int bus)
+{
+	acpi_status status;
+#if ACPI_CA_VERSION < 0x20020201
+	acpi_buffer buffer;
+#else
+	acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+#endif
+	struct acpiphp_bridge *bridge;
+
+	bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
+	if (bridge == NULL)
+		return;
+
+	memset(bridge, 0, sizeof(struct acpiphp_bridge));
+
+	bridge->type = BRIDGE_TYPE_HOST;
+	bridge->handle = handle;
+	bridge->seg = seg;
+	bridge->bus = bus;
+
+	bridge->pci_bus = find_pci_bus(&pci_root_buses, bus);
+	bridge->pci_ops = bridge->pci_bus->ops;
+
+	bridge->res_lock = SPIN_LOCK_UNLOCKED;
+
+	/* to be overridden when we decode _CRS	*/
+	bridge->sub = bridge->bus;
+
+	/* decode resources */
+
+#if ACPI_CA_VERSION < 0x20020201
+	buffer.length = 0;
+	buffer.pointer = NULL;
+
+	status = acpi_get_current_resources(handle, &buffer);
+
+	if (status == AE_BUFFER_OVERFLOW) {
+		buffer.pointer = kmalloc(buffer.length, GFP_KERNEL);
+		if (!buffer.pointer)
+			return;
+		status = acpi_get_current_resources(handle, &buffer);
+	}
+#else
+	status = acpi_get_current_resources(handle, &buffer);
+#endif
+
+	if (ACPI_FAILURE(status)) {
+		err("failed to decode bridge resources");
+		kfree(bridge);
+		return;
+	}
+
+	decode_acpi_resource(buffer.pointer, bridge);
+	kfree(buffer.pointer);
+
+	if (bridge->bus_head) {
+		bridge->bus = bridge->bus_head->base;
+		bridge->sub = bridge->bus_head->base + bridge->bus_head->length - 1;
+	}
+
+	init_bridge_misc(bridge);
+}
+
+
+/* allocate and initialize PCI-to-PCI bridge data structure */
+static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int fn)
+{
+	acpi_status status;
+	struct acpiphp_bridge *bridge;
+	u8 tmp8;
+	u16 tmp16;
+	u32 tmp;
+	u64 base64, limit64;
+	u32 base, limit, base32u, limit32u;
+
+	bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
+	if (bridge == NULL) {
+		err("out of memory");
+		return;
+	}
+
+	memset(bridge, 0, sizeof(struct acpiphp_bridge));
+
+	bridge->type = BRIDGE_TYPE_P2P;
+	bridge->handle = handle;
+	bridge->seg = seg;
+
+	bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn));
+	if (!bridge->pci_dev) {
+		err("Can't get pci_dev");
+		kfree(bridge);
+		return;
+	}
+
+	bridge->pci_bus = bridge->pci_dev->subordinate;
+	if (!bridge->pci_bus) {
+		err("This is not a PCI-to-PCI bridge!");
+		kfree(bridge);
+		return;
+	}
+	bridge->pci_ops = bridge->pci_bus->ops;
+
+	bridge->res_lock = SPIN_LOCK_UNLOCKED;
+
+	bridge->bus = bridge->pci_bus->number;
+	bridge->sub = bridge->pci_bus->subordinate;
+
+	/*
+	 * decode resources under this P2P bridge
+	 */
+
+	/* I/O resources */
+	pci_read_config_byte(bridge->pci_dev, PCI_IO_BASE, &tmp8);
+	base = tmp8;
+	pci_read_config_byte(bridge->pci_dev, PCI_IO_LIMIT, &tmp8);
+	limit = tmp8;
+
+	switch (base & PCI_IO_RANGE_TYPE_MASK) {
+	case PCI_IO_RANGE_TYPE_16:
+		base = (base << 8) & 0xf000;
+		limit = ((limit << 8) & 0xf000) + 0xfff;
+		bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
+		if (!bridge->io_head) {
+			err("out of memory");
+			return;
+		}
+		dbg("16bit I/O range: %04x-%04x",
+		    (u32)bridge->io_head->base,
+		    (u32)(bridge->io_head->base + bridge->io_head->length - 1));
+		break;
+	case PCI_IO_RANGE_TYPE_32:
+		pci_read_config_word(bridge->pci_dev, PCI_IO_BASE_UPPER16, &tmp16);
+		base = ((u32)tmp16 << 16) | ((base << 8) & 0xf000);
+		pci_read_config_word(bridge->pci_dev, PCI_IO_LIMIT_UPPER16, &tmp16);
+		limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff;
+		bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
+		if (!bridge->io_head) {
+			err("out of memory");
+			return;
+		}
+		dbg("32bit I/O range: %08x-%08x",
+		    (u32)bridge->io_head->base,
+		    (u32)(bridge->io_head->base + bridge->io_head->length - 1));
+		break;
+	case 0x0f:
+		dbg("I/O space unsupported");
+		break;
+	default:
+		warn("Unknown I/O range type");
+	}
+
+	/* Memory resources (mandatory for P2P bridge) */
+	pci_read_config_word(bridge->pci_dev, PCI_MEMORY_BASE, &tmp16);
+	base = (tmp16 & 0xfff0) << 16;
+	pci_read_config_word(bridge->pci_dev, PCI_MEMORY_LIMIT, &tmp16);
+	limit = ((tmp16 & 0xfff0) << 16) | 0xfffff;
+	bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
+	if (!bridge->mem_head) {
+		err("out of memory");
+		return;
+	}
+	dbg("32bit Memory range: %08x-%08x",
+	    (u32)bridge->mem_head->base,
+	    (u32)(bridge->mem_head->base + bridge->mem_head->length-1));
+
+	/* Prefetchable Memory resources (optional) */
+	pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_BASE, &tmp16);
+	base = tmp16;
+	pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_LIMIT, &tmp16);
+	limit = tmp16;
+
+	switch (base & PCI_MEMORY_RANGE_TYPE_MASK) {
+	case PCI_PREF_RANGE_TYPE_32:
+		base = (base & 0xfff0) << 16;
+		limit = ((limit & 0xfff0) << 16) | 0xfffff;
+		bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
+		if (!bridge->p_mem_head) {
+			err("out of memory");
+			return;
+		}
+		dbg("32bit Prefetchable memory range: %08x-%08x",
+		    (u32)bridge->p_mem_head->base,
+		    (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1));
+		break;
+	case PCI_PREF_RANGE_TYPE_64:
+		pci_read_config_dword(bridge->pci_dev, PCI_PREF_BASE_UPPER32, &base32u);
+		pci_read_config_dword(bridge->pci_dev, PCI_PREF_LIMIT_UPPER32, &limit32u);
+		base64 = ((u64)base32u << 32) | ((base & 0xfff0) << 16);
+		limit64 = (((u64)limit32u << 32) | ((limit & 0xfff0) << 16)) + 0xfffff;
+
+		bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1);
+		if (!bridge->p_mem_head) {
+			err("out of memory");
+			return;
+		}
+		dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x",
+		    (u32)(bridge->p_mem_head->base >> 32),
+		    (u32)(bridge->p_mem_head->base & 0xffffffff),
+		    (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32),
+		    (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) & 0xffffffff));
+		break;
+	case 0x0f:
+		break;
+	default:
+		warn("Unknown prefetchale memory type");
+	}
+
+	init_bridge_misc(bridge);
+}
+
+
+/* callback routine to find P2P bridges */
+static acpi_status
+find_p2p_bridge (acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	acpi_status status;
+	acpi_handle dummy_handle;
+	unsigned long *segbus = context;
+	unsigned long tmp;
+	int seg, bus, device, function;
+	struct pci_dev *dev;
+	u32 val;
+
+	/* get PCI address */
+	seg = (*segbus >> 8) & 0xff;
+	bus = *segbus & 0xff;
+
+	status = acpi_get_handle(handle, "_ADR", &dummy_handle);
+	if (ACPI_FAILURE(status))
+		return AE_OK;		/* continue */
+
+	status = acpi_evaluate_integer(handle, "_ADR", NULL, &tmp);
+	if (ACPI_FAILURE(status)) {
+		dbg("%s: _ADR evaluation failure", __FUNCTION__);
+		return AE_OK;
+	}
+
+	device = (tmp >> 16) & 0xffff;
+	function = tmp & 0xffff;
+
+	dev = pci_find_slot(bus, PCI_DEVFN(device, function));
+
+	if (!dev)
+		return AE_OK;
+
+	if (!dev->subordinate)
+		return AE_OK;
+
+	/* check if this bridge has ejectable slots */
+	if (detect_ejectable_slots(handle) > 0) {
+		dbg("found PCI-to-PCI bridge at PCI %02x:%02x.%d", bus, device, function);
+		add_p2p_bridge(handle, seg, bus, device, function);
+	}
+
+	return AE_OK;
+}
+
+
+/* find hot-pluggable slots, and then find P2P bridge */
+static int add_bridges (acpi_handle *handle)
+{
+	acpi_status status;
+	unsigned long tmp;
+	int seg, bus;
+	acpi_handle dummy_handle;
+	int sta = -1;
+
+	/* if the bridge doesn't have _STA, we assume it is always there */
+	status = acpi_get_handle(handle, "_STA", &dummy_handle);
+	if (ACPI_SUCCESS(status)) {
+		status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
+		if (ACPI_FAILURE(status)) {
+			dbg("%s: _STA evaluation failure", __FUNCTION__);
+			return 0;
+		}
+		if ((tmp & ACPI_STA_FUNCTIONING) == 0)
+			/* don't register this object */
+			return 0;
+	}
+
+	/* get PCI segment number */
+	status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp);
+
+	seg = ACPI_SUCCESS(status) ? tmp : 0;
+
+	/* get PCI bus number */
+	status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp);
+
+	if (ACPI_SUCCESS(status)) {
+		bus = tmp;
+	} else {
+		warn("can't get bus number, assuming 0");
+		bus = 0;
+	}
+
+	/* check if this bridge has ejectable slots */
+	if (detect_ejectable_slots(handle) > 0) {
+		dbg("found PCI host-bus bridge with hot-pluggable slots");
+		add_host_bridge(handle, seg, bus);
+		return 0;
+	}
+
+	tmp = seg << 8 | bus;
+
+	/* search P2P bridges under this host bridge */
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
+				     find_p2p_bridge, &tmp, NULL);
+
+	if (ACPI_FAILURE(status))
+		warn("find_p2p_bridge faied (error code = 0x%x)",status);
+
+	return 0;
+}
+
+
+/* callback routine to enumerate all the bridges in ACPI namespace */
+static acpi_status
+find_host_bridge (acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	acpi_status status;
+	acpi_device_info info;
+	char objname[5];
+	acpi_buffer buffer = { sizeof(objname), objname };
+
+	status = acpi_get_object_info(handle, &info);
+	if (ACPI_FAILURE(status)) {
+		dbg("%s: failed to get bridge information", __FUNCTION__);
+		return AE_OK;		/* continue */
+	}
+
+	info.hardware_id[sizeof(info.hardware_id)-1] = '\0';
+
+	/* TBD check _CID also */
+	if (strcmp(info.hardware_id, ACPI_PCI_HOST_HID) == 0) {
+
+		acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
+		dbg("checking PCI-hotplug capable bridges under [%s]", objname);
+		add_bridges(handle);
+	}
+	return AE_OK;
+}
+
+
+static int power_on_slot (struct acpiphp_slot *slot)
+{
+	acpi_status status;
+	struct acpiphp_func *func;
+	struct list_head *l;
+	int retval = 0;
+
+	/* is this already enabled? */
+	if (slot->flags & SLOT_POWEREDON)
+		goto err_exit;
+
+	list_for_each(l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		if (func->flags & FUNC_HAS_PS0) {
+			dbg("%s: executing _PS0 on %02x:%02x.%d", __FUNCTION__,
+			    slot->bridge->bus, slot->device, func->function);
+			status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
+			if (ACPI_FAILURE(status)) {
+				warn("%s: _PS0 failed", __FUNCTION__);
+				retval = -1;
+				goto err_exit;
+			}
+		}
+	}
+
+	/* TBD: evaluate _STA to check if the slot is enabled */
+
+	slot->flags |= SLOT_POWEREDON;
+
+ err_exit:
+	return retval;
+}
+
+
+static int power_off_slot (struct acpiphp_slot *slot)
+{
+	acpi_status status;
+	struct acpiphp_func *func;
+	struct list_head *l;
+	acpi_object_list arg_list;
+	acpi_object arg;
+
+	int retval = 0;
+
+	/* is this already enabled? */
+	if ((slot->flags & SLOT_POWEREDON) == 0)
+		goto err_exit;
+
+	list_for_each(l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		if (func->flags & FUNC_HAS_PS3) {
+			dbg("%s: executing _PS3 on %02x:%02x.%d", __FUNCTION__,
+			    slot->bridge->bus, slot->device, func->function);
+			status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
+			if (ACPI_FAILURE(status)) {
+				warn("%s: _PS3 failed", __FUNCTION__);
+				retval = -1;
+				goto err_exit;
+			}
+		}
+	}
+
+	list_for_each(l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		if (func->flags & FUNC_HAS_EJ0) {
+			dbg("%s: executing _EJ0 on %02x:%02x.%d", __FUNCTION__,
+			    slot->bridge->bus, slot->device, func->function);
+
+			/* _EJ0 method take one argument */
+			arg_list.count = 1;
+			arg_list.pointer = &arg;
+			arg.type = ACPI_TYPE_INTEGER;
+			arg.integer.value = 1;
+
+			status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
+			if (ACPI_FAILURE(status)) {
+				warn("%s: _EJ0 failed", __FUNCTION__);
+				retval = -1;
+				goto err_exit;
+			}
+		}
+	}
+
+	/* TBD: evaluate _STA to check if the slot is disabled */
+
+	slot->flags &= (~SLOT_POWEREDON);
+
+ err_exit:
+	return retval;
+}
+
+
+/**
+ * enable_device - enable, configure a slot
+ * @slot: slot to be enabled
+ *
+ * This function should be called per *physical slot*,
+ * not per each slot object in ACPI namespace.
+ *
+ */
+static int enable_device (struct acpiphp_slot *slot)
+{
+	acpi_status status;
+	u8 bus;
+	struct pci_dev dev0, *dev;
+	struct pci_bus *child;
+	struct list_head *l;
+	struct acpiphp_func *func;
+	int retval = 0;
+
+	if (slot->flags & SLOT_ENABLED)
+		goto err_exit;
+
+	/* sanity check: dev should be NULL when hot-plugged in */
+	dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));
+	if (dev) {
+		/* This case shouldn't happen */
+		err("pci_dev structure already exists.");
+		retval = -1;
+		goto err_exit;
+	}
+
+	/* allocate resources to device */
+	retval = acpiphp_configure_slot(slot);
+	if (retval)
+		goto err_exit;
+
+	memset(&dev0, 0, sizeof (struct pci_dev));
+
+	dev0.bus = slot->bridge->pci_bus;
+	dev0.devfn = PCI_DEVFN(slot->device, 0);
+	dev0.sysdata = dev0.bus->sysdata;
+
+	/* returned `dev' is the *first function* only! */
+	dev = pci_scan_slot (&dev0);
+
+	if (!dev) {
+		err("No new device found");
+		retval = -1;
+		goto err_exit;
+	}
+
+	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		pci_read_config_byte(dev, PCI_SECONDARY_BUS, &bus);
+		child = (struct pci_bus*) pci_add_new_bus(dev->bus, dev, bus);
+		pci_do_scan_bus(child);
+	}
+
+	/* associate pci_dev to our representation */
+	list_for_each(l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		func->pci_dev = pci_find_slot(slot->bridge->bus,
+					      PCI_DEVFN(slot->device,
+							func->function));
+		if (!func->pci_dev)
+			continue;
+
+		/* configure device */
+		retval = acpiphp_configure_function(func);
+		if (retval)
+			goto err_exit;
+	}
+
+	slot->flags |= SLOT_ENABLED;
+
+#if 1
+	dbg("Available resources:");
+	acpiphp_dump_resource(slot->bridge);
+#endif
+
+ err_exit:
+	return retval;
+}
+
+
+/**
+ * disable_device - disable a slot
+ */
+static int disable_device (struct acpiphp_slot *slot)
+{
+	int retval = 0;
+	struct acpiphp_func *func;
+	struct list_head *l;
+	acpi_status status;
+
+	/* is this slot already disabled? */
+	if (!(slot->flags & SLOT_ENABLED))
+		goto err_exit;
+
+	list_for_each(l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		if (func->pci_dev) {
+			if (acpiphp_unconfigure_function(func) == 0) {
+				func->pci_dev = NULL;
+			} else {
+				err("failed to unconfigure device");
+				retval = -1;
+				goto err_exit;
+			}
+		}
+	}
+
+	slot->flags &= (~SLOT_ENABLED);
+
+ err_exit:
+	return retval;
+}
+
+
+/**
+ * get_slot_status - get ACPI slot status
+ *
+ * if a slot has _STA for each function and if any one of them
+ * returned non-zero status, return it
+ *
+ * if a slot doesn't have _STA and if any one of its functions'
+ * configuration space is configured, return 0x0f as a _STA
+ *
+ * otherwise return 0
+ */
+static unsigned int get_slot_status (struct acpiphp_slot *slot)
+{
+	acpi_status status;
+	unsigned long sta = 0;
+	int fn;
+	u32 dvid;
+	struct list_head *l;
+	struct acpiphp_func *func;
+
+	list_for_each(l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		if (func->flags & FUNC_HAS_STA) {
+			status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta);
+			if (ACPI_SUCCESS(status) && sta)
+				break;
+		} else {
+			pci_read_config_dword_nodev(default_ops,
+						    slot->bridge->bus,
+						    slot->device,
+						    func->function,
+						    PCI_VENDOR_ID, &dvid);
+			if (dvid != 0xffffffff) {
+				sta = ACPI_STA_ALL;
+				break;
+			}
+		}
+	}
+
+	return (unsigned int)sta;
+}
+
+
+/*
+ * ACPI event handlers
+ */
+
+/**
+ * handle_hotplug_event_bridge - handle ACPI event on bridges
+ *
+ * @handle: Notify()'ed acpi_handle 
+ * @type: Notify code
+ * @context: pointer to acpiphp_bridge structure
+ *
+ * handles ACPI event notification on {host,p2p} bridges
+ *
+ */
+static void handle_hotplug_event_bridge (acpi_handle handle, u32 type, void *context)
+{
+	struct acpiphp_bridge *bridge;
+	char objname[64];
+	acpi_buffer buffer = { sizeof(objname), objname };
+
+	bridge = (struct acpiphp_bridge *)context;
+
+	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+
+	switch (type) {
+	case ACPI_NOTIFY_BUS_CHECK:
+		/* bus re-enumerate */
+		dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
+		acpiphp_check_bridge(bridge);
+		break;
+
+	case ACPI_NOTIFY_DEVICE_CHECK:
+		/* device check */
+		dbg("%s: Device check notify on %s", __FUNCTION__, objname);
+		acpiphp_check_bridge(bridge);
+		break;
+
+	case ACPI_NOTIFY_DEVICE_WAKE:
+		/* wake event */
+		dbg("%s: Device wake notify on %s", __FUNCTION__, objname);
+		break;
+
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		/* request device eject */
+		dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
+		break;
+
+	default:
+		warn("notify_handler: unknown event type 0x%x for %s", type, objname);
+		break;
+	}
+}
+
+
+/**
+ * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
+ *
+ * @handle: Notify()'ed acpi_handle 
+ * @type: Notify code
+ * @context: pointer to acpiphp_func structure
+ *
+ * handles ACPI event notification on slots
+ *
+ */
+static void handle_hotplug_event_func (acpi_handle handle, u32 type, void *context)
+{
+	struct acpiphp_func *func;
+	char objname[64];
+	acpi_buffer buffer = { sizeof(objname), objname };
+
+	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+
+	func = (struct acpiphp_func *)context;
+
+	switch (type) {
+	case ACPI_NOTIFY_BUS_CHECK:
+		/* bus re-enumerate */
+		dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
+		acpiphp_enable_slot(func->slot);
+		break;
+
+	case ACPI_NOTIFY_DEVICE_CHECK:
+		/* device check : re-enumerate from parent bus */
+		dbg("%s: Device check notify on %s", __FUNCTION__, objname);
+		acpiphp_check_bridge(func->slot->bridge);
+		break;
+
+	case ACPI_NOTIFY_DEVICE_WAKE:
+		/* wake event */
+		dbg("%s: Device wake notify on %s", __FUNCTION__, objname);
+		break;
+
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		/* request device eject */
+		dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
+		acpiphp_disable_slot(func->slot);
+		break;
+
+	default:
+		warn("notify_handler: unknown event type 0x%x for %s", type, objname);
+		break;
+	}
+}
+
+
+/**
+ * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures
+ *
+ */
+int acpiphp_glue_init (void)
+{
+	acpi_status status;
+
+	if (list_empty(&pci_root_buses))
+		return -1;
+
+	/* set default pci_ops for configuration space operation */
+	default_ops = pci_bus_b(pci_root_buses.next)->ops;
+	if (!default_ops)
+		return -1;
+
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+				     ACPI_UINT32_MAX, find_host_bridge,
+				     NULL, NULL);
+
+	if (ACPI_FAILURE(status)) {
+		err("%s: acpi_walk_namespace() failed", __FUNCTION__);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures
+ *
+ * This function frees all data allocated in acpiphp_glue_init()
+ */
+void acpiphp_glue_exit (void)
+{
+	struct list_head *node, *shead, *l, *n;
+	struct acpiphp_bridge *bridge;
+	struct acpiphp_slot *slot, *next;
+	struct acpiphp_func *func;
+	acpi_status status;
+
+	list_for_each(node, &bridge_list) {
+		bridge = (struct acpiphp_bridge *)node;
+		slot = bridge->slots;
+		while (slot) {
+			next = slot->next;
+			list_for_each_safe(l, n, &slot->funcs) {
+				func = list_entry(l, struct acpiphp_func, sibling);
+				acpiphp_free_resource(&func->io_head);
+				acpiphp_free_resource(&func->mem_head);
+				acpiphp_free_resource(&func->p_mem_head);
+				acpiphp_free_resource(&func->bus_head);
+				status = acpi_remove_notify_handler(func->handle,
+								    ACPI_SYSTEM_NOTIFY,
+								    handle_hotplug_event_func);
+				if (ACPI_FAILURE(status))
+					err("failed to remove notify handler");
+				kfree(func);
+			}
+			kfree(slot);
+			slot = next;
+		}
+		status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
+						    handle_hotplug_event_bridge);
+		if (ACPI_FAILURE(status))
+			err("failed to remove notify handler");
+
+		acpiphp_free_resource(&bridge->io_head);
+		acpiphp_free_resource(&bridge->mem_head);
+		acpiphp_free_resource(&bridge->p_mem_head);
+		acpiphp_free_resource(&bridge->bus_head);
+
+		kfree(bridge);
+	}
+}
+
+
+/**
+ * acpiphp_get_num_slots - count number of slots in a system
+ */
+int acpiphp_get_num_slots (void)
+{
+	struct list_head *node;
+	struct acpiphp_bridge *bridge;
+	int num_slots;
+
+	num_slots = 0;
+
+	list_for_each(node, &bridge_list) {
+		bridge = (struct acpiphp_bridge *)node;
+		dbg("Bus%d %dslot(s)", bridge->bus, bridge->nr_slots);
+		num_slots += bridge->nr_slots;
+	}
+
+	dbg("Total %dslots", num_slots);
+	return num_slots;
+}
+
+
+/**
+ * acpiphp_for_each_slot - call function for each slot
+ * @fn: callback function
+ * @data: context to be passed to callback function
+ *
+ */
+int acpiphp_for_each_slot(acpiphp_callback fn, void *data)
+{
+	struct list_head *node;
+	struct acpiphp_bridge *bridge;
+	struct acpiphp_slot *slot;
+	int retval = 0;
+
+	list_for_each(node, &bridge_list) {
+		bridge = (struct acpiphp_bridge *)node;
+		for (slot = bridge->slots; slot; slot = slot->next) {
+			retval = fn(slot, data);
+			if (!retval)
+				goto err_exit;
+		}
+	}
+
+ err_exit:
+	return retval;
+}
+
+
+/* search matching slot from id  */
+struct acpiphp_slot *get_slot_from_id (int id)
+{
+	struct list_head *node;
+	struct acpiphp_bridge *bridge;
+	struct acpiphp_slot *slot;
+
+	list_for_each(node, &bridge_list) {
+		bridge = (struct acpiphp_bridge *)node;
+		for (slot = bridge->slots; slot; slot = slot->next)
+			if (slot->id == id)
+				return slot;
+	}
+
+	/* should never happen! */
+	err("%s: no object for id %d",__FUNCTION__, id);
+	return 0;
+}
+
+
+/**
+ * acpiphp_enable_slot - power on slot
+ */
+int acpiphp_enable_slot (struct acpiphp_slot *slot)
+{
+	int retval;
+	int online = 0;
+
+	down(&slot->crit_sect);
+
+	/* wake up all functions */
+	retval = power_on_slot(slot);
+	if (retval)
+		goto err_exit;
+
+	if (get_slot_status(slot) == ACPI_STA_ALL)
+		/* configure all functions */
+		retval = enable_device(slot);
+
+ err_exit:
+	up(&slot->crit_sect);
+	return retval;
+}
+
+
+/**
+ * acpiphp_disable_slot - power off slot
+ */
+int acpiphp_disable_slot (struct acpiphp_slot *slot)
+{
+	struct list_head *l;
+	struct acpiphp_func *func;
+	int retval = 0;
+
+	down(&slot->crit_sect);
+
+	/* unconfigure all functions */
+	retval = disable_device(slot);
+	if (retval)
+		goto err_exit;
+
+	/* power off all functions */
+	retval = power_off_slot(slot);
+	if (retval)
+		goto err_exit;
+
+#if 1
+	acpiphp_resource_sort_and_combine(&slot->bridge->io_head);
+	acpiphp_resource_sort_and_combine(&slot->bridge->mem_head);
+	acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head);
+	acpiphp_resource_sort_and_combine(&slot->bridge->bus_head);
+	dbg("Available resources:");
+	acpiphp_dump_resource(slot->bridge);
+#endif
+
+ err_exit:
+	up(&slot->crit_sect);
+	return retval;
+}
+
+
+/**
+ * acpiphp_check_bridge - re-enumerate devices
+ */
+int acpiphp_check_bridge (struct acpiphp_bridge *bridge)
+{
+	struct acpiphp_slot *slot;
+	unsigned int sta;
+	int retval = 0;
+	int enabled, disabled;
+
+	enabled = disabled = 0;
+
+	for (slot = bridge->slots; slot; slot = slot->next) {
+		sta = get_slot_status(slot);
+		if (slot->flags & SLOT_ENABLED) {
+			/* if enabled but not present, disable */
+			if (sta != ACPI_STA_ALL) {
+				retval = acpiphp_disable_slot(slot);
+				if (retval) {
+					err("Error occured in enabling");
+					up(&slot->crit_sect);
+					goto err_exit;
+				}
+				enabled++;
+			}
+		} else {
+			/* if disabled but present, enable */
+			if (sta == ACPI_STA_ALL) {
+				retval = acpiphp_enable_slot(slot);
+				if (retval) {
+					err("Error occured in enabling");
+					up(&slot->crit_sect);
+					goto err_exit;
+				}
+				disabled++;
+			}
+		}
+	}
+
+	dbg("%s: %d enabled, %d disabled", __FUNCTION__, enabled, disabled);
+
+ err_exit:
+	return retval;
+}
+
+
+/*
+ * slot enabled:  1
+ * slot disabled: 0
+ */
+u8 acpiphp_get_power_status (struct acpiphp_slot *slot)
+{
+	unsigned int sta;
+
+	sta = get_slot_status(slot);
+
+	return (sta & ACPI_STA_ENABLED) ? 1 : 0;
+}
+
+
+/*
+ * attention LED ON: 1
+ *              OFF: 0
+ *
+ * TBD
+ * no direct attention led status information via ACPI
+ *
+ */
+u8 acpiphp_get_attention_status (struct acpiphp_slot *slot)
+{
+	return 0;
+}
+
+
+/*
+ * latch closed:  1
+ * latch   open:  0
+ */
+u8 acpiphp_get_latch_status (struct acpiphp_slot *slot)
+{
+	unsigned int sta;
+
+	sta = get_slot_status(slot);
+
+	return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0;
+}
+
+
+/*
+ * adapter presence : 1
+ *          absence : 0
+ */
+u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot)
+{
+	unsigned int sta;
+
+	sta = get_slot_status(slot);
+
+	return (sta == 0) ? 0 : 1;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/acpiphp_pci.c linux-2.4.20/drivers/hotplug/acpiphp_pci.c
--- linux-2.4.19/drivers/hotplug/acpiphp_pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/acpiphp_pci.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,763 @@
+/*
+ * ACPI PCI HotPlug PCI configuration space management
+ *
+ * Copyright (c) 1995,2001 Compaq Computer Corporation
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001,2002 IBM Corp.
+ * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
+ * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (c) 2002 NEC Corporation
+ *
+ * All rights reserved.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <t-kouchi@cq.jp.nec.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include "pci_hotplug.h"
+#include "acpiphp.h"
+
+static int debug = 1;			/* XXX set 0 after debug */
+#define MY_NAME "acpiphp_pci"
+
+static void acpiphp_configure_irq (struct pci_dev *dev);
+
+
+/* allocate mem/pmem/io resource to a new function */
+static int alloc_resource (struct acpiphp_func *func)
+{
+	u64 base;
+	u32 bar, len;
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		PCI_BASE_ADDRESS_2,
+		PCI_BASE_ADDRESS_3,
+		PCI_BASE_ADDRESS_4,
+		PCI_BASE_ADDRESS_5,
+		0
+	};
+	int count;
+	struct acpiphp_bridge *bridge;
+	struct pci_resource *res;
+	struct pci_ops *ops;
+	int bus, device, function;
+
+	bridge = func->slot->bridge;
+	bus = bridge->bus;
+	device = func->slot->device;
+	function = func->function;
+	ops = bridge->pci_ops;
+
+	for (count = 0; address[count]; count++) {	/* for 6 BARs */
+		pci_write_config_dword_nodev (ops, bus, device, function, address[count], 0xFFFFFFFF);
+		pci_read_config_dword_nodev(ops, bus, device, function, address[count], &bar);
+
+		if (!bar)	/* This BAR is not implemented */
+			continue;
+
+		dbg("Device %02x.%02x BAR %d wants %x", device, function, count, bar);
+
+		if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
+			/* This is IO */
+
+			len = bar & 0xFFFFFFFC;
+			len = ~len + 1;
+
+			dbg ("len in IO %x, BAR %d", len, count);
+
+			spin_lock(&bridge->res_lock);
+			res = acpiphp_get_io_resource(&bridge->io_head, len);
+			spin_unlock(&bridge->res_lock);
+
+			if (!res) {
+				err("cannot allocate requested io for %02x:%02x.%d len %x\n",
+				    bus, device, function, len);
+				return -1;
+			}
+			pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+			res->next = func->io_head;
+			func->io_head = res;
+
+		} else {
+			/* This is Memory */
+			if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				/* pfmem */
+
+				len = bar & 0xFFFFFFF0;
+				len = ~len + 1;
+
+				dbg("len in PFMEM %x, BAR %d", len, count);
+
+				spin_lock(&bridge->res_lock);
+				res = acpiphp_get_resource(&bridge->p_mem_head, len);
+				spin_unlock(&bridge->res_lock);
+
+				if (!res) {
+					err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
+					    bus, device, function, len);
+					return -1;
+				}
+
+				pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+
+				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
+					dbg ("inside the pfmem 64 case, count %d", count);
+					count += 1;
+					pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)(res->base >> 32));
+				}
+
+				res->next = func->p_mem_head;
+				func->p_mem_head = res;
+
+			} else {
+				/* regular memory */
+
+				len = bar & 0xFFFFFFF0;
+				len = ~len + 1;
+
+				dbg("len in MEM %x, BAR %d", len, count);
+
+				spin_lock(&bridge->res_lock);
+				res = acpiphp_get_resource(&bridge->mem_head, len);
+				spin_unlock(&bridge->res_lock);
+
+				if (!res) {
+					err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
+					    bus, device, function, len);
+					return -1;
+				}
+
+				pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+
+				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					dbg ("inside mem 64 case, reg. mem, count %d", count);
+					count += 1;
+					pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)(res->base >> 32));
+				}
+
+				res->next = func->mem_head;
+				func->mem_head = res;
+
+			}
+		}
+	}
+
+	/* disable expansion rom */
+	pci_write_config_dword_nodev(ops, bus, device, function, PCI_ROM_ADDRESS, 0x00000000);
+
+	return 0;
+}
+
+
+/* enable pci_dev */
+static int configure_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus)
+{
+	u16 tmp;
+	struct acpiphp_func *func;
+	struct acpiphp_bridge *bridge;
+	struct pci_dev *dev;
+
+	func = (struct acpiphp_func *)wrapped_dev->data;
+	bridge = (struct acpiphp_bridge *)wrapped_bus->data;
+	dev = wrapped_dev->dev;
+
+	/* TBD: support PCI-to-PCI bridge case */
+	if (!func || !bridge)
+		return 0;
+
+	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, bridge->hpp.cache_line_size);
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, bridge->hpp.latency_timer);
+
+	pci_read_config_word(dev, PCI_COMMAND, &tmp);
+	if (bridge->hpp.enable_SERR)
+		tmp |= PCI_COMMAND_SERR;
+	if (bridge->hpp.enable_PERR)
+		tmp |= PCI_COMMAND_PARITY;
+	//tmp |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+	pci_write_config_word(dev, PCI_COMMAND, tmp);
+
+	acpiphp_configure_irq(dev);
+#ifdef CONFIG_PROC_FS
+	pci_proc_attach_device(dev);
+#endif
+	pci_announce_device_to_drivers(dev);
+
+	return 0;
+}
+
+
+static int is_pci_dev_in_use (struct pci_dev* dev) 
+{
+	/* 
+	 * dev->driver will be set if the device is in use by a new-style 
+	 * driver -- otherwise, check the device's regions to see if any
+	 * driver has claimed them
+	 */
+
+	int i, inuse=0;
+
+	if (dev->driver) return 1; //assume driver feels responsible
+
+	for (i = 0; !dev->driver && !inuse && (i < 6); i++) {
+		if (!pci_resource_start(dev, i))
+			continue;
+
+		if (pci_resource_flags(dev, i) & IORESOURCE_IO)
+			inuse = check_region(pci_resource_start(dev, i),
+					     pci_resource_len(dev, i));
+		else if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
+			inuse = check_mem_region(pci_resource_start(dev, i),
+						 pci_resource_len(dev, i));
+	}
+
+	return inuse;
+}
+
+
+static int pci_hp_remove_device (struct pci_dev *dev)
+{
+	if (is_pci_dev_in_use(dev)) {
+		err("***Cannot safely power down device -- "
+		       "it appears to be in use***\n");
+		return -EBUSY;
+	}
+	pci_remove_device(dev);
+	return 0;
+}
+
+
+/* remove device driver */
+static int unconfigure_pci_dev_driver (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus)
+{
+	struct pci_dev *dev = wrapped_dev->dev;
+
+	dbg("attempting removal of driver for device %s", dev->slot_name);
+
+	/* Now, remove the Linux Driver Representation */
+	if (dev->driver) {
+		if (dev->driver->remove) {
+			dev->driver->remove(dev);
+			dbg("driver was properly removed");
+		}
+		dev->driver = NULL;
+	}
+
+	return is_pci_dev_in_use(dev);
+}
+
+
+/* remove pci_dev itself from system */
+static int unconfigure_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus)
+{
+	struct pci_dev *dev = wrapped_dev->dev;
+
+	/* Now, remove the Linux Representation */
+	if (dev) {
+		if (pci_hp_remove_device(dev) == 0) {
+			kfree(dev); /* Now, remove */
+		} else {
+			return -1; /* problems while freeing, abort visitation */
+		}
+	}
+
+	return 0;
+}
+
+
+/* remove pci_bus itself from system */
+static int unconfigure_pci_bus (struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_dev)
+{
+	struct pci_bus *bus = wrapped_bus->bus;
+
+#ifdef CONFIG_PROC_FS
+	/* Now, remove the Linux Representation */
+	if (bus->procdir) {
+		pci_proc_detach_bus(bus);
+	}
+#endif
+	/* the cleanup code should live in the kernel ... */
+	bus->self->subordinate = NULL;
+	/* unlink from parent bus */
+	list_del(&bus->node);
+
+	/* Now, remove */
+	if (bus)
+		kfree(bus);
+
+	return 0;
+}
+
+
+/* detect_used_resource - subtract resource under dev from bridge */
+static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev)
+{
+	u32 bar, len, pin;
+	u64 base;
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		PCI_BASE_ADDRESS_2,
+		PCI_BASE_ADDRESS_3,
+		PCI_BASE_ADDRESS_4,
+		PCI_BASE_ADDRESS_5,
+		0
+	};
+	int count;
+	struct pci_resource *res;
+
+	dbg("Device %s", dev->slot_name);
+
+	for (count = 0; address[count]; count++) {	/* for 6 BARs */
+		pci_read_config_dword(dev, address[count], &bar);
+
+		if (!bar)	/* This BAR is not implemented */
+			continue;
+
+		pci_write_config_dword(dev, address[count], 0xFFFFFFFF);
+		pci_read_config_dword(dev, address[count], &len);
+
+		if (len & PCI_BASE_ADDRESS_SPACE_IO) {
+			/* This is IO */
+			base = bar & 0xFFFFFFFC;
+			len &= 0xFFFFFFFC;
+			len = ~len + 1;
+
+			dbg("BAR[%d] %08x - %08x (IO)", count, (u32)base, (u32)base + len - 1);
+
+			spin_lock(&bridge->res_lock);
+			res = acpiphp_get_resource_with_base(&bridge->io_head, base, len);
+			spin_unlock(&bridge->res_lock);
+			if (res)
+				kfree(res);
+		} else {
+			/* This is Memory */
+			base = bar & 0xFFFFFFF0;
+			if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				/* pfmem */
+
+				len &= 0xFFFFFFF0;
+				len = ~len + 1;
+
+				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
+					dbg ("prefetch mem 64");
+					count += 1;
+				}
+				dbg("BAR[%d] %08x - %08x (PMEM)", count, (u32)base, (u32)base + len - 1);
+				spin_lock(&bridge->res_lock);
+				res = acpiphp_get_resource_with_base(&bridge->p_mem_head, base, len);
+				spin_unlock(&bridge->res_lock);
+				if (res)
+					kfree(res);
+			} else {
+				/* regular memory */
+
+				len &= 0xFFFFFFF0;
+				len = ~len + 1;
+
+				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					dbg ("mem 64");
+					count += 1;
+				}
+				dbg("BAR[%d] %08x - %08x (MEM)", count, (u32)base, (u32)base + len - 1);
+				spin_lock(&bridge->res_lock);
+				res = acpiphp_get_resource_with_base(&bridge->mem_head, base, len);
+				spin_unlock(&bridge->res_lock);
+				if (res)
+					kfree(res);
+			}
+		}
+
+		pci_write_config_dword(dev, address[count], bar);
+	}
+
+	return 0;
+}
+
+
+/* detect_pci_resource_bus - subtract resource under pci_bus */
+static void detect_used_resource_bus(struct acpiphp_bridge *bridge, struct pci_bus *bus)
+{
+	struct list_head *l;
+	struct pci_dev *dev;
+
+	list_for_each(l, &bus->devices) {
+		dev = pci_dev_b(l);
+		detect_used_resource(bridge, dev);
+		/* XXX recursive call */
+		if (dev->subordinate)
+			detect_used_resource_bus(bridge, dev->subordinate);
+	}
+}
+
+
+/**
+ * acpiphp_detect_pci_resource - detect resources under bridge
+ * @bridge: detect all resources already used under this bridge
+ *
+ * collect all resources already allocated for all devices under a bridge.
+ */
+int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge)
+{
+	struct list_head *l;
+	struct pci_dev *dev;
+
+	detect_used_resource_bus(bridge, bridge->pci_bus);
+
+	return 0;
+}
+
+
+/**
+ * acpiphp_init_slot_resource - gather resource usage information of a slot
+ * @slot: ACPI slot object to be checked, should have valid pci_dev member
+ *
+ * TBD: PCI-to-PCI bridge case
+ *      use pci_dev->resource[]
+ */
+int acpiphp_init_func_resource (struct acpiphp_func *func)
+{
+	u64 base;
+	u32 bar, len;
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		PCI_BASE_ADDRESS_2,
+		PCI_BASE_ADDRESS_3,
+		PCI_BASE_ADDRESS_4,
+		PCI_BASE_ADDRESS_5,
+		0
+	};
+	int count;
+	struct pci_resource *res;
+	struct pci_ops *ops;
+	struct pci_dev *dev;
+
+	dev = func->pci_dev;
+	dbg("Hot-pluggable device %s", dev->slot_name);
+
+	for (count = 0; address[count]; count++) {	/* for 6 BARs */
+		pci_read_config_dword (dev, address[count], &bar);
+
+		if (!bar)	/* This BAR is not implemented */
+			continue;
+
+		pci_write_config_dword (dev, address[count], 0xFFFFFFFF);
+		pci_read_config_dword (dev, address[count], &len);
+
+		if (len & PCI_BASE_ADDRESS_SPACE_IO) {
+			/* This is IO */
+			base = bar & 0xFFFFFFFC;
+			len &= 0xFFFFFFFC;
+			len = ~len + 1;
+
+			dbg("BAR[%d] %08x - %08x (IO)", count, (u32)base, (u32)base + len - 1);
+
+			res = acpiphp_make_resource(base, len);
+			if (!res)
+				goto no_memory;
+
+			res->next = func->io_head;
+			func->io_head = res;
+
+		} else {
+			/* This is Memory */
+			base = bar & 0xFFFFFFF0;
+			if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				/* pfmem */
+
+				len &= 0xFFFFFFF0;
+				len = ~len + 1;
+
+				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
+					dbg ("prefetch mem 64");
+					count += 1;
+				}
+				dbg("BAR[%d] %08x - %08x (PMEM)", count, (u32)base, (u32)base + len - 1);
+				res = acpiphp_make_resource(base, len);
+				if (!res)
+					goto no_memory;
+
+				res->next = func->p_mem_head;
+				func->p_mem_head = res;
+
+			} else {
+				/* regular memory */
+
+				len &= 0xFFFFFFF0;
+				len = ~len + 1;
+
+				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					dbg ("mem 64");
+					count += 1;
+				}
+				dbg("BAR[%d] %08x - %08x (MEM)", count, (u32)base, (u32)base + len - 1);
+				res = acpiphp_make_resource(base, len);
+				if (!res)
+					goto no_memory;
+
+				res->next = func->mem_head;
+				func->mem_head = res;
+
+			}
+		}
+
+		pci_write_config_dword (dev, address[count], bar);
+	}
+#if 1
+	acpiphp_dump_func_resource(func);
+#endif
+
+	return 0;
+
+ no_memory:
+	err("out of memory");
+	acpiphp_free_resource(&func->io_head);
+	acpiphp_free_resource(&func->mem_head);
+	acpiphp_free_resource(&func->p_mem_head);
+
+	return -1;
+}
+
+
+/**
+ * acpiphp_configure_slot - allocate PCI resources
+ * @slot: slot to be configured
+ *
+ * initializes a PCI functions on a device inserted
+ * into the slot
+ *
+ */
+int acpiphp_configure_slot (struct acpiphp_slot *slot)
+{
+	struct acpiphp_func *func;
+	struct list_head *l;
+	u8 hdr;
+	u32 dvid;
+	int retval = 0;
+	int is_multi = 0;
+
+	pci_read_config_byte_nodev(slot->bridge->pci_ops,
+				   slot->bridge->bus, slot->device, 0,
+				   PCI_HEADER_TYPE, &hdr);
+
+	if (hdr & 0x80)
+		is_multi = 1;
+
+	list_for_each(l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+		if (is_multi || func->function == 0) {
+			pci_read_config_dword_nodev(slot->bridge->pci_ops,
+						    slot->bridge->bus,
+						    slot->device,
+						    func->function,
+						    PCI_VENDOR_ID, &dvid);
+			if (dvid != 0xffffffff) {
+				retval = alloc_resource(func);
+				if (retval)
+					break;
+			}
+		}
+	}
+
+	return retval;
+}
+
+
+/* for pci_visit_dev() */
+static struct pci_visit configure_functions = {
+	post_visit_pci_dev:	configure_pci_dev
+};
+
+static struct pci_visit unconfigure_functions_phase1 = {
+	post_visit_pci_dev:	unconfigure_pci_dev_driver
+};
+
+static struct pci_visit unconfigure_functions_phase2 = {
+	post_visit_pci_bus:	unconfigure_pci_bus,
+	post_visit_pci_dev:	unconfigure_pci_dev
+};
+
+
+/**
+ * acpiphp_configure_function - configure PCI function
+ * @func: function to be configured
+ *
+ * initializes a PCI functions on a device inserted
+ * into the slot
+ *
+ */
+int acpiphp_configure_function (struct acpiphp_func *func)
+{
+	int retval = 0;
+	struct pci_dev_wrapped wrapped_dev;
+	struct pci_bus_wrapped wrapped_bus;
+	struct acpiphp_bridge *bridge;
+
+	/* if pci_dev is NULL, ignore it */
+	if (!func->pci_dev)
+		goto err_exit;
+
+	bridge = func->slot->bridge;
+
+	memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
+	memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
+	wrapped_dev.dev = func->pci_dev;
+	wrapped_dev.data = func;
+	wrapped_bus.bus = bridge->pci_bus;
+	wrapped_bus.data = bridge;
+
+	retval = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus);
+	if (retval)
+		goto err_exit;
+
+ err_exit:
+	return retval;
+}
+
+
+/**
+ * acpiphp_unconfigure_function - unconfigure PCI function
+ * @func: function to be unconfigured
+ *
+ */
+int acpiphp_unconfigure_function (struct acpiphp_func *func)
+{
+	struct acpiphp_bridge *bridge;
+	struct pci_resource *tmp;
+	struct pci_dev_wrapped wrapped_dev;
+	struct pci_bus_wrapped wrapped_bus;
+	int retval = 0;
+
+	/* if pci_dev is NULL, ignore it */
+	if (!func->pci_dev)
+		goto err_exit;
+
+	memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
+	memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
+	wrapped_dev.dev = func->pci_dev;
+	//wrapped_dev.data = func;
+	wrapped_bus.bus = func->slot->bridge->pci_bus;
+	//wrapped_bus.data = func->slot->bridge;
+
+	retval = pci_visit_dev(&unconfigure_functions_phase1, &wrapped_dev, &wrapped_bus);
+	if (retval)
+		goto err_exit;
+
+	retval = pci_visit_dev(&unconfigure_functions_phase2, &wrapped_dev, &wrapped_bus);
+	if (retval)
+		goto err_exit;
+
+	/* free all resources */
+	bridge = func->slot->bridge;
+
+	spin_lock(&bridge->res_lock);
+	acpiphp_move_resource(&func->io_head, &bridge->io_head);
+	acpiphp_move_resource(&func->mem_head, &bridge->mem_head);
+	acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head);
+	acpiphp_move_resource(&func->bus_head, &bridge->bus_head);
+	spin_unlock(&bridge->res_lock);
+
+ err_exit:
+	return retval;
+}
+
+
+/* XXX IA64 specific */
+#ifdef CONFIG_IA64
+static int ia64_get_irq(struct pci_dev *dev, int pin)
+{
+	extern int pci_pin_to_vector(int bus, int slot, int pci_pin);
+	int irq;
+
+	irq = pci_pin_to_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
+
+	if (irq < 0 && dev->bus->parent) {
+		/* go back to the bridge */
+		struct pci_dev *bridge = dev->bus->self;
+
+		if (bridge) {
+			/* allow for multiple bridges on an adapter */
+			do {
+				/* do the bridge swizzle... */
+				pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+				irq = pci_pin_to_vector(bridge->bus->number,
+							PCI_SLOT(bridge->devfn),
+							   pin);
+			} while (irq < 0 && (bridge = bridge->bus->self));
+		}
+		if (irq >= 0)
+			printk(KERN_WARNING
+			       "PCI: using PPB(B%d,I%d,P%d) to get vector %02x\n",
+			       dev->bus->number, PCI_SLOT(dev->devfn),
+			       pin, irq);
+		else
+			printk(KERN_WARNING
+			       "PCI: Couldn't map irq for (B%d,I%d,P%d)\n",
+			       dev->bus->number, PCI_SLOT(dev->devfn), pin);
+	}
+
+	return irq;
+}
+#endif
+
+
+/*
+ * acpiphp_configure_irq - configure PCI_INTERRUPT_PIN
+ *
+ * for x86 platforms, pcibios_enable_device calls pcibios_enable_irq,
+ * which allocates irq for pci_dev
+ *
+ * for IA64 platforms, we have to program dev->irq from pci IRQ routing
+ * information derived from ACPI table
+ *
+ * TBD:
+ * separate architecture dependent part
+ * (preferably, pci_enable_device() cares for allocating irq...)
+ */
+static void acpiphp_configure_irq (struct pci_dev *dev)
+{
+#if CONFIG_IA64		    /* XXX IA64 specific, need i386 version */
+	int bus, device, function, irq;
+	u8 tmp;
+
+	bus = dev->bus->number;
+	device = PCI_SLOT(dev->devfn);
+	function = PCI_FUNC(dev->devfn);
+
+	pci_read_config_byte (dev, PCI_INTERRUPT_PIN, &tmp);
+
+	if ((tmp > 0x00) && (tmp < 0x05)) {
+		irq = ia64_get_irq(dev, tmp - 1);
+		if (irq > 0) {
+			dev->irq = irq;
+			pci_write_config_byte (dev, PCI_INTERRUPT_LINE, irq);
+		} else {
+			err("Couldn't get IRQ for INT%c", 'A' + tmp - 1);
+		}
+	}
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/acpiphp_res.c linux-2.4.20/drivers/hotplug/acpiphp_res.c
--- linux-2.4.19/drivers/hotplug/acpiphp_res.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/acpiphp_res.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,708 @@
+/*
+ * ACPI PCI HotPlug Utility functions
+ *
+ * Copyright (c) 1995,2001 Compaq Computer Corporation
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001 IBM Corp.
+ * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
+ * Copyright (c) 2002 NEC Corporation
+ *
+ * All rights reserved.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>,<h-aono@ap.jp.nec.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#include <linux/pci.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+
+#include <linux/ioctl.h>
+#include <linux/fcntl.h>
+
+#include <linux/list.h>
+
+#include "pci_hotplug.h"
+#include "acpiphp.h"
+
+#define MY_NAME "acpiphp_res"
+
+/* local variables */
+static int debug = 0;
+
+/*
+ * sort_by_size - sort nodes by their length, smallest first
+ */
+static int sort_by_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return 1;
+
+	if (!((*head)->next))
+		return 0;
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->length > (*head)->next->length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)->next;
+			current_res->next = (*head)->next;
+			(*head)->next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res->next && current_res->next->next) {
+			if (current_res->next->length > current_res->next->next->length) {
+				out_of_order++;
+				next_res = current_res->next;
+				current_res->next = current_res->next->next;
+				current_res = current_res->next;
+				next_res->next = current_res->next;
+				current_res->next = next_res;
+			} else
+				current_res = current_res->next;
+		}
+	}  /* End of out_of_order loop */
+
+	return 0;
+}
+
+
+/*
+ * sort_by_max_size - sort nodes by their length, largest first
+ */
+static int sort_by_max_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return 1;
+
+	if (!((*head)->next))
+		return 0;
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->length < (*head)->next->length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)->next;
+			current_res->next = (*head)->next;
+			(*head)->next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res->next && current_res->next->next) {
+			if (current_res->next->length < current_res->next->next->length) {
+				out_of_order++;
+				next_res = current_res->next;
+				current_res->next = current_res->next->next;
+				current_res = current_res->next;
+				next_res->next = current_res->next;
+				current_res->next = next_res;
+			} else
+				current_res = current_res->next;
+		}
+	}  /* End of out_of_order loop */
+
+	return 0;
+}
+
+/**
+ * get_io_resource - get resource for I/O ports
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length that is not in the
+ * ISA aliasing window.  If it finds a node larger than "size"
+ * it will split it up.
+ *
+ * size must be a power of two.
+ *
+ * difference from get_resource is handling of ISA aliasing space.
+ *
+ */
+struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u64 temp_qword;
+
+	if (!(*head))
+		return NULL;
+
+	if (acpiphp_resource_sort_and_combine(head))
+		return NULL;
+
+	if (sort_by_size(head))
+		return NULL;
+
+	for (node = *head; node; node = node->next) {
+		if (node->length < size)
+			continue;
+
+		if (node->base & (size - 1)) {
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_qword = (node->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node->length - (temp_qword - node->base)) < size)
+				continue;
+
+			split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
+
+			if (!split_node)
+				return NULL;
+
+			node->base = temp_qword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			/* this one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = acpiphp_make_resource(node->base + size, node->length - size);
+
+			if (!split_node)
+				return NULL;
+
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		/* For IO make sure it's not in the ISA aliasing space */
+		if (node->base & 0x300L)
+			continue;
+
+		/* If we got here, then it is the right size
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+
+	return node;
+}
+
+
+/**
+ * get_max_resource - get the largest resource
+ *
+ * Gets the largest node that is at least "size" big from the
+ * list pointed to by head.  It aligns the node on top and bottom
+ * to "size" alignment before returning it.
+ */
+struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *max;
+	struct pci_resource *temp;
+	struct pci_resource *split_node;
+	u64 temp_qword;
+
+	if (!(*head))
+		return NULL;
+
+	if (acpiphp_resource_sort_and_combine(head))
+		return NULL;
+
+	if (sort_by_max_size(head))
+		return NULL;
+
+	for (max = *head;max; max = max->next) {
+
+		/* If not big enough we could probably just bail, 
+		   instead we'll continue to the next. */
+		if (max->length < size)
+			continue;
+
+		if (max->base & (size - 1)) {
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_qword = (max->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((max->length - (temp_qword - max->base)) < size)
+				continue;
+
+			split_node = acpiphp_make_resource(max->base, temp_qword - max->base);
+
+			if (!split_node)
+				return NULL;
+
+			max->base = temp_qword;
+			max->length -= split_node->length;
+
+			/* Put it next in the list */
+			split_node->next = max->next;
+			max->next = split_node;
+		}
+
+		if ((max->base + max->length) & (size - 1)) {
+			/* this one isn't end aligned properly at the top
+			   so we'll make a new entry and split it up */
+			temp_qword = ((max->base + max->length) & ~(size - 1));
+
+			split_node = acpiphp_make_resource(temp_qword,
+							   max->length + max->base - temp_qword);
+
+			if (!split_node)
+				return NULL;
+
+			max->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = max->next;
+			max->next = split_node;
+		}
+
+		/* Make sure it didn't shrink too much when we aligned it */
+		if (max->length < size)
+			continue;
+
+		/* Now take it out of the list */
+		temp = (struct pci_resource*) *head;
+		if (temp == max) {
+			*head = max->next;
+		} else {
+			while (temp && temp->next != max) {
+				temp = temp->next;
+			}
+
+			temp->next = max->next;
+		}
+
+		max->next = NULL;
+		return max;
+	}
+
+	/* If we get here, we couldn't find one */
+	return NULL;
+}
+
+
+/**
+ * get_resource - get resource (mem, pfmem)
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length.  If it finds a node
+ * larger than "size" it will split it up.
+ *
+ * size must be a power of two.
+ *
+ */
+struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u64 temp_qword;
+
+	if (!(*head))
+		return NULL;
+
+	if (acpiphp_resource_sort_and_combine(head))
+		return NULL;
+
+	if (sort_by_size(head))
+		return NULL;
+
+	for (node = *head; node; node = node->next) {
+		dbg("%s: req_size =%x node=%p, base=%x, length=%x",
+		    __FUNCTION__, size, node, (u32)node->base, node->length);
+		if (node->length < size)
+			continue;
+
+		if (node->base & (size - 1)) {
+			dbg("%s: not aligned", __FUNCTION__);
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_qword = (node->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node->length - (temp_qword - node->base)) < size)
+				continue;
+
+			split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
+
+			if (!split_node)
+				return NULL;
+
+			node->base = temp_qword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			dbg("%s: too big", __FUNCTION__);
+			/* this one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = acpiphp_make_resource(node->base + size, node->length - size);
+
+			if (!split_node)
+				return NULL;
+
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		dbg("%s: got one!!!", __FUNCTION__);
+		/* If we got here, then it is the right size
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+	return node;
+}
+
+/**
+ * get_resource_with_base - get resource with specific base address
+ *
+ * this function 
+ * returns the first node of "size" length located at specified base address.
+ * If it finds a node larger than "size" it will split it up.
+ *
+ * size must be a power of two.
+ *
+ */
+struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u64 temp_qword;
+
+	if (!(*head))
+		return NULL;
+
+	if (acpiphp_resource_sort_and_combine(head))
+		return NULL;
+
+	for (node = *head; node; node = node->next) {
+		dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x",
+		    (u32)base, size, node, (u32)node->base, node->length);
+		if (node->base > base)
+			continue;
+
+		if ((node->base + node->length) < (base + size))
+			continue;
+
+		if (node->base < base) {
+			dbg(": split 1");
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_qword = base;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node->length - (temp_qword - node->base)) < size)
+				continue;
+
+			split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
+
+			if (!split_node)
+				return NULL;
+
+			node->base = temp_qword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}
+
+		dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x",
+		    (u32)base, size, node, (u32)node->base, node->length);
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			dbg(": split 2");
+			/* this one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = acpiphp_make_resource(node->base + size, node->length - size);
+
+			if (!split_node)
+				return NULL;
+
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		dbg(": got one!!!");
+		/* If we got here, then it is the right size
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+	return node;
+}
+
+
+/**
+ * acpiphp_resource_sort_and_combine
+ *
+ * Sorts all of the nodes in the list in ascending order by
+ * their base addresses.  Also does garbage collection by
+ * combining adjacent nodes.
+ *
+ * returns 0 if success
+ */
+int acpiphp_resource_sort_and_combine (struct pci_resource **head)
+{
+	struct pci_resource *node1;
+	struct pci_resource *node2;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return 1;
+
+	dbg("*head->next = %p",(*head)->next);
+
+	if (!(*head)->next)
+		return 0;	/* only one item on the list, already sorted! */
+
+	dbg("*head->base = 0x%x",(u32)(*head)->base);
+	dbg("*head->next->base = 0x%x", (u32)(*head)->next->base);
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->base > (*head)->next->base)) {
+			node1 = *head;
+			(*head) = (*head)->next;
+			node1->next = (*head)->next;
+			(*head)->next = node1;
+			out_of_order++;
+		}
+
+		node1 = (*head);
+
+		while (node1->next && node1->next->next) {
+			if (node1->next->base > node1->next->next->base) {
+				out_of_order++;
+				node2 = node1->next;
+				node1->next = node1->next->next;
+				node1 = node1->next;
+				node2->next = node1->next;
+				node1->next = node2;
+			} else
+				node1 = node1->next;
+		}
+	}  /* End of out_of_order loop */
+
+	node1 = *head;
+
+	while (node1 && node1->next) {
+		if ((node1->base + node1->length) == node1->next->base) {
+			/* Combine */
+			dbg("8..");
+			node1->length += node1->next->length;
+			node2 = node1->next;
+			node1->next = node1->next->next;
+			kfree(node2);
+		} else
+			node1 = node1->next;
+	}
+
+	return 0;
+}
+
+
+/**
+ * acpiphp_make_resource - make resource structure
+ * @base: base address of a resource
+ * @length: length of a resource
+ */
+struct pci_resource *acpiphp_make_resource (u64 base, u32 length)
+{
+	struct pci_resource *res;
+
+	res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+	if (res) {
+		memset(res, 0, sizeof(struct pci_resource));
+		res->base = base;
+		res->length = length;
+	}
+
+	return res;
+}
+
+
+/**
+ * acpiphp_move_resource - move linked resources from one to another
+ * @from: head of linked resource list
+ * @to: head of linked resource list
+ */
+void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to)
+{
+	struct pci_resource *tmp;
+
+	while (*from) {
+		tmp = (*from)->next;
+		(*from)->next = *to;
+		*to = *from;
+		*from = tmp;
+	}
+
+	/* *from = NULL is guaranteed */
+}
+
+
+/**
+ * acpiphp_free_resource - free all linked resources
+ * @res: head of linked resource list
+ */
+void acpiphp_free_resource (struct pci_resource **res)
+{
+	struct pci_resource *tmp;
+
+	while (*res) {
+		tmp = (*res)->next;
+		kfree(*res);
+		*res = tmp;
+	}
+
+	/* *res = NULL is guaranteed */
+}
+
+
+/* debug support functions;  will go away sometime :) */
+static void dump_resource(struct pci_resource *head)
+{
+	struct pci_resource *p;
+	int cnt;
+
+	p = head;
+	cnt = 0;
+
+	while (p) {
+		info("[%02d] %08x - %08x",
+		     cnt++, (u32)p->base, (u32)p->base + p->length - 1);
+		p = p->next;
+	}
+}
+
+void acpiphp_dump_resource(struct acpiphp_bridge *bridge)
+{
+	info("I/O resource:");
+	dump_resource(bridge->io_head);
+	info("MEM resource:");
+	dump_resource(bridge->mem_head);
+	info("PMEM resource:");
+	dump_resource(bridge->p_mem_head);
+	info("BUS resource:");
+	dump_resource(bridge->bus_head);
+}
+
+void acpiphp_dump_func_resource(struct acpiphp_func *func)
+{
+	info("I/O resource:");
+	dump_resource(func->io_head);
+	info("MEM resource:");
+	dump_resource(func->mem_head);
+	info("PMEM resource:");
+	dump_resource(func->p_mem_head);
+	info("BUS resource:");
+	dump_resource(func->bus_head);
+}
+
+/*
+EXPORT_SYMBOL(acpiphp_get_io_resource);
+EXPORT_SYMBOL(acpiphp_get_max_resource);
+EXPORT_SYMBOL(acpiphp_get_resource);
+EXPORT_SYMBOL(acpiphp_resource_sort_and_combine);
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/cpqphp.h linux-2.4.20/drivers/hotplug/cpqphp.h
--- linux-2.4.19/drivers/hotplug/cpqphp.h	2001-11-09 22:01:21.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/cpqphp.h	2002-10-29 11:18:35.000000000 +0000
@@ -307,8 +307,8 @@
 	u8 first_slot;
 	u8 add_support;
 	u8 push_flag;
-	u8 speed;			/* 0 = 33MHz, 1 = 66MHz */
-	u8 speed_capability;		/* 0 = 33MHz, 1 = 66MHz */
+	enum pci_bus_speed speed;
+	enum pci_bus_speed speed_capability;
 	u8 push_button;			/* 0 = no pushbutton, 1 = pushbutton present */
 	u8 slot_switch_type;		/* 0 = no switch, 1 = switch present */
 	u8 defeature_PHP;		/* 0 = PHP not supported, 1 = PHP supported */
@@ -323,9 +323,6 @@
 	wait_queue_head_t queue;	/* sleep & wake process */
 };
 
-#define CTRL_SPEED_33MHz	0
-#define CTRL_SPEED_66MHz	1
-
 struct irq_mapping {
 	u8 barber_pole;
 	u8 valid_INT;
@@ -637,7 +634,7 @@
 	u16 misc;
 	
 	misc = readw(ctrl->hpc_reg + MISC);
-	return (misc & 0x0800) ? 1 : 0;
+	return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/cpqphp_core.c linux-2.4.20/drivers/hotplug/cpqphp_core.c
--- linux-2.4.19/drivers/hotplug/cpqphp_core.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/cpqphp_core.c	2002-10-29 11:18:30.000000000 +0000
@@ -78,17 +78,21 @@
 static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
 static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
 static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+static int get_max_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+static int get_cur_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
 
 static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = {
-	owner:			THIS_MODULE,
-	set_attention_status:	set_attention_status,
-	enable_slot:		process_SI,
-	disable_slot:		process_SS,
-	hardware_test:		hardware_test,
-	get_power_status:	get_power_status,
-	get_attention_status:	get_attention_status,
-	get_latch_status:	get_latch_status,
-	get_adapter_status:	get_adapter_status,
+	.owner =		THIS_MODULE,
+	.set_attention_status =	set_attention_status,
+	.enable_slot =		process_SI,
+	.disable_slot =		process_SS,
+	.hardware_test =	hardware_test,
+	.get_power_status =	get_power_status,
+	.get_attention_status =	get_attention_status,
+	.get_latch_status =	get_latch_status,
+	.get_adapter_status =	get_adapter_status,
+ 	.get_max_bus_speed =	get_max_bus_speed,
+ 	.get_cur_bus_speed =	get_cur_bus_speed,
 };
 
 
@@ -377,7 +381,7 @@
 			new_slot->capabilities |= PCISLOT_64_BIT_SUPPORTED;
 		if (is_slot66mhz(new_slot))
 			new_slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED;
-		if (ctrl->speed == 1)
+		if (ctrl->speed == PCI_SPEED_66MHz)
 			new_slot->capabilities |= PCISLOT_66_MHZ_OPERATION;
 
 		ctrl_slot = slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4);
@@ -781,6 +785,44 @@
 	return 0;
 }
 
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct controller *ctrl;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	ctrl = slot->ctrl;
+	if (ctrl == NULL)
+		return -ENODEV;
+	
+	*value = ctrl->speed_capability;
+
+	return 0;
+}
+
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct controller *ctrl;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	ctrl = slot->ctrl;
+	if (ctrl == NULL)
+		return -ENODEV;
+	
+	*value = ctrl->speed;
+
+	return 0;
+}
+
 static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	u8 num_of_slots = 0;
@@ -852,28 +894,28 @@
 					case PCI_SUB_HPC_ID:
 						/* Original 6500/7000 implementation */
 						ctrl->slot_switch_type = 1;		// Switch is present
-						ctrl->speed_capability = CTRL_SPEED_33MHz;
+						ctrl->speed_capability = PCI_SPEED_33MHz;
 						ctrl->push_button = 0;			// No pushbutton
 						ctrl->pci_config_space = 1;		// Index/data access to working registers 0 = not supported, 1 = supported
-						ctrl->defeature_PHP = 1;			// PHP is supported
+						ctrl->defeature_PHP = 1;		// PHP is supported
 						ctrl->pcix_support = 0;			// PCI-X not supported
-						ctrl->pcix_speed_capability = 0;		// N/A since PCI-X not supported
+						ctrl->pcix_speed_capability = 0;	// N/A since PCI-X not supported
 						break;
 					case PCI_SUB_HPC_ID2:
 						/* First Pushbutton implementation */
 						ctrl->push_flag = 1;
 						ctrl->slot_switch_type = 1;		// Switch is present
-						ctrl->speed_capability = CTRL_SPEED_33MHz;
+						ctrl->speed_capability = PCI_SPEED_33MHz;
 						ctrl->push_button = 1;			// Pushbutton is present
 						ctrl->pci_config_space = 1;		// Index/data access to working registers 0 = not supported, 1 = supported
-						ctrl->defeature_PHP = 1;			// PHP is supported
+						ctrl->defeature_PHP = 1;		// PHP is supported
 						ctrl->pcix_support = 0;			// PCI-X not supported
-						ctrl->pcix_speed_capability = 0;		// N/A since PCI-X not supported
+						ctrl->pcix_speed_capability = 0;	// N/A since PCI-X not supported
 						break;
 					case PCI_SUB_HPC_ID_INTC:
 						/* Third party (6500/7000) */
 						ctrl->slot_switch_type = 1;		// Switch is present
-						ctrl->speed_capability = CTRL_SPEED_33MHz;
+						ctrl->speed_capability = PCI_SPEED_33MHz;
 						ctrl->push_button = 0;			// No pushbutton
 						ctrl->pci_config_space = 1;		// Index/data access to working registers 0 = not supported, 1 = supported
 						ctrl->defeature_PHP = 1;			// PHP is supported
@@ -884,7 +926,7 @@
 						/* First 66 Mhz implementation */
 						ctrl->push_flag = 1;
 						ctrl->slot_switch_type = 1;		// Switch is present
-						ctrl->speed_capability = CTRL_SPEED_66MHz;
+						ctrl->speed_capability = PCI_SPEED_66MHz;
 						ctrl->push_button = 1;			// Pushbutton is present
 						ctrl->pci_config_space = 1;		// Index/data access to working registers 0 = not supported, 1 = supported
 						ctrl->defeature_PHP = 1;		// PHP is supported
@@ -902,9 +944,9 @@
 			case PCI_VENDOR_ID_INTEL:
 				/* Check for speed capability (0=33, 1=66) */
 				if (subsystem_deviceid & 0x0001) {
-					ctrl->speed_capability = CTRL_SPEED_66MHz;
+					ctrl->speed_capability = PCI_SPEED_66MHz;
 				} else {
-					ctrl->speed_capability = CTRL_SPEED_33MHz;
+					ctrl->speed_capability = PCI_SPEED_33MHz;
 				}
 
 				/* Check for push button */
@@ -981,7 +1023,7 @@
 	info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number);
 
 	dbg ("Hotplug controller capabilities:\n");
-	dbg ("    speed_capability       %s\n", ctrl->speed_capability == CTRL_SPEED_33MHz ? "33MHz" : "66Mhz");
+	dbg ("    speed_capability       %s\n", ctrl->speed_capability == PCI_SPEED_33MHz ? "33MHz" : "66Mhz");
 	dbg ("    slot_switch_type       %s\n", ctrl->slot_switch_type == 0 ? "no switch" : "switch present");
 	dbg ("    defeature_PHP          %s\n", ctrl->defeature_PHP == 0 ? "PHP not supported" : "PHP supported");
 	dbg ("    alternate_base_address %s\n", ctrl->alternate_base_address == 0 ? "not supported" : "supported");
@@ -1059,6 +1101,9 @@
 	/*
 	 * Get IO, memory, and IRQ resources for new devices
 	 */
+	// The next line is required for cpqhp_find_available_resources
+	ctrl->interrupt = pdev->irq;
+
 	rc = cpqhp_find_available_resources(ctrl, cpqhp_rom_start);
 	ctrl->add_support = !rc;
 	if (rc) {
@@ -1087,7 +1132,6 @@
 	writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_MASK);
 
 	/* set up the interrupt */
-	ctrl->interrupt = pdev->irq;
 	dbg("HPC interrupt = %d \n", ctrl->interrupt);
 	if (request_irq(ctrl->interrupt,
 			(void (*)(int, void *, struct pt_regs *)) &cpqhp_ctrl_intr,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/cpqphp_ctrl.c linux-2.4.20/drivers/hotplug/cpqphp_ctrl.c
--- linux-2.4.19/drivers/hotplug/cpqphp_ctrl.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/cpqphp_ctrl.c	2002-10-29 11:18:37.000000000 +0000
@@ -1186,7 +1186,7 @@
 		//*********************************
 		rc = CARD_FUNCTIONING;
 	} else {
-		if (ctrl->speed == 1) {
+		if (ctrl->speed == PCI_SPEED_66MHz) {
 			// Wait for exclusive access to hardware
 			down(&ctrl->crit_sect);
 
@@ -1384,7 +1384,7 @@
 	dbg(__FUNCTION__": func->device, slot_offset, hp_slot = %d, %d ,%d\n",
 	    func->device, ctrl->slot_device_offset, hp_slot);
 
-	if (ctrl->speed == 1) {
+	if (ctrl->speed == PCI_SPEED_66MHz) {
 		// Wait for exclusive access to hardware
 		down(&ctrl->crit_sect);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/cpqphp_nvram.c linux-2.4.20/drivers/hotplug/cpqphp_nvram.c
--- linux-2.4.19/drivers/hotplug/cpqphp_nvram.c	2001-11-09 22:01:22.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/cpqphp_nvram.c	2002-10-29 11:18:36.000000000 +0000
@@ -176,12 +176,12 @@
 	
 	spin_lock_irqsave(&int15_lock, flags);
 	__asm__ (
-		"xorl   %%ebx,%%ebx
-		xorl    %%edx,%%edx
-		pushf
-		push    %%cs
-		cli
-		call    *%6"
+		"xorl   %%ebx,%%ebx \n"
+		"xorl   %%edx,%%edx \n"
+		"pushf              \n"
+		"push    %%cs       \n"
+		"cli                \n"
+		"call    *%6        \n"
 		: "=c" (*buf_size), "=a" (ret_val)
 		: "a" (op), "c" (*buf_size), "S" (ev_name),
 		"D" (buffer), "m" (compaq_int15_entry_point)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/cpqphp_pci.c linux-2.4.20/drivers/hotplug/cpqphp_pci.c
--- linux-2.4.19/drivers/hotplug/cpqphp_pci.c	2001-11-09 22:01:22.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/cpqphp_pci.c	2002-10-29 11:18:38.000000000 +0000
@@ -358,8 +358,8 @@
 	    dev_num, bus_num, int_pin, irq_num);
 	rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num);
 	dbg(__FUNCTION__":rc %d\n", rc);
-	if (rc)
-		return rc;
+	if (!rc)
+		return !rc;
 
 	// set the Edge Level Control Register (ELCR)
 	temp_word = inb(0x4d0);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/ibmphp.h linux-2.4.20/drivers/hotplug/ibmphp.h
--- linux-2.4.19/drivers/hotplug/ibmphp.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/ibmphp.h	2002-10-29 11:18:48.000000000 +0000
@@ -39,7 +39,8 @@
 #else
 	#define MY_NAME THIS_MODULE->name
 #endif
-#define debug(fmt, arg...) do { if (ibmphp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0)
+#define debug(fmt, arg...) do { if (ibmphp_debug == 1) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0)
+#define debug_pci(fmt, arg...) do { if (ibmphp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0)
 #define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
 #define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
 #define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)
@@ -121,6 +122,7 @@
 	u8 port1_port_connect;
 	u8 port2_node_connect;
 	u8 port2_port_connect;
+	u8 chassis_num;
 //	struct list_head scal_detail_list;
 };
 
@@ -139,9 +141,27 @@
 	u8 port1_port_connect;
 	u8 first_slot_num;
 	u8 status;
-//	struct list_head rio_detail_list;
+	u8 wpindex;
+	u8 chassis_num;
+	struct list_head rio_detail_list;
 };
 
+struct opt_rio {
+	u8 rio_type;
+	u8 chassis_num;
+	u8 first_slot_num;
+	u8 middle_num;
+	struct list_head opt_rio_list;
+};	
+
+struct opt_rio_lo {
+	u8 rio_type;
+	u8 chassis_num;
+	u8 first_slot_num;
+	u8 middle_num;
+	u8 pack_count;
+	struct list_head opt_rio_lo_list;
+};	
 
 /****************************************************************
 *  HPC DESCRIPTOR NODE                                          *
@@ -153,7 +173,6 @@
 	short phys_addr;
 //      struct list_head ebda_hpc_list;
 };
-
 /*****************************************************************
 *   IN HPC DATA STRUCTURE, THE ASSOCIATED SLOT AND BUS           *
 *   STRUCTURE                                                    *
@@ -168,13 +187,11 @@
 
 struct ebda_hpc_bus {
 	u32 bus_num;
-/*
 	u8 slots_at_33_conv;
 	u8 slots_at_66_conv;
 	u8 slots_at_66_pcix;
 	u8 slots_at_100_pcix;
 	u8 slots_at_133_pcix;
-*/
 };
 
 
@@ -197,6 +214,9 @@
 	u8 i2c_addr;
 };
 
+#define HPC_DEVICE_ID		0x0246
+#define HPC_SUBSYSTEM_ID	0x0247
+#define HPC_PCI_OFFSET		0x40
 /*************************************************************************
 *   RSTC DESCRIPTOR NODE                                                 *
 *************************************************************************/
@@ -217,8 +237,9 @@
 	u8 rsrc_type;
 	u8 bus_num;
 	u8 dev_fun;
-	ulong start_addr;
-	ulong end_addr;
+	u32 start_addr;
+	u32 end_addr;
+	u8 marked;	/* for NVRAM */
 	struct list_head ebda_pci_rsrc_list;
 };
 
@@ -232,12 +253,15 @@
 	u8 slot_max;
 	u8 slot_count;
 	u8 busno;
-	u8 current_speed;
-	u8 supported_speed;
 	u8 controller_id;
-	u8 supported_bus_mode;
+	u8 current_speed;
 	u8 current_bus_mode;
 	u8 index;
+	u8 slots_at_33_conv;
+	u8 slots_at_66_conv;
+	u8 slots_at_66_pcix;
+	u8 slots_at_100_pcix;
+	u8 slots_at_133_pcix;
 	struct list_head bus_info_list;
 };
 
@@ -247,7 +271,7 @@
 ***********************************************************/
 extern struct list_head ibmphp_ebda_pci_rsrc_head;
 extern struct list_head ibmphp_slot_head;
-
+extern struct list_head ibmphp_res_head;
 /***********************************************************
 * FUNCTION PROTOTYPES                                      *
 ***********************************************************/
@@ -262,6 +286,7 @@
 extern struct bus_info *ibmphp_find_same_bus_num (u32);
 extern int ibmphp_get_bus_index (u8);
 extern u16 ibmphp_get_total_controllers (void);
+extern int ibmphp_register_pci (void);
 
 /* passed parameters */
 #define MEM		0
@@ -690,8 +715,11 @@
 	u8 bus;
 	u8 device;
 	u8 number;
+	u8 real_physical_slot_num;
 	char name[100];
 	u32 capabilities;
+	u8 supported_speed;
+	u8 supported_bus_mode;
 	struct hotplug_slot *hotplug_slot;
 	struct controller *ctrl;
 	struct pci_func *func;
@@ -709,10 +737,13 @@
 struct controller {
 	struct ebda_hpc_slot *slots;
 	struct ebda_hpc_bus *buses;
+	struct pci_dev *ctrl_dev; /* in case where controller is PCI */
+	u8 starting_slot_num;	/* starting and ending slot #'s this ctrl controls*/
+	u8 ending_slot_num;
 	u8 revision;
 	u8 options;		/* which options HPC supports */
 	u8 status;
-	u8 ctlr_id;		/* TONI */
+	u8 ctlr_id;
 	u8 slot_count;
 	u8 bus_count;
 	u8 ctlr_relative_id;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/ibmphp_core.c linux-2.4.20/drivers/hotplug/ibmphp_core.c
--- linux-2.4.19/drivers/hotplug/ibmphp_core.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/ibmphp_core.c	2002-10-29 11:18:50.000000000 +0000
@@ -44,7 +44,7 @@
 #define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev)
 #define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt)
 
-#define DRIVER_VERSION	"0.1"
+#define DRIVER_VERSION	"0.6"
 #define DRIVER_DESC	"IBM Hot Plug PCI Controller Driver"
 
 int ibmphp_debug;
@@ -88,6 +88,8 @@
 	slot_cur->bus_on->current_speed = CURRENT_BUS_SPEED (slot_cur->busstatus);
 	if (READ_BUS_MODE (slot_cur->ctrl))
 		slot_cur->bus_on->current_bus_mode = CURRENT_BUS_MODE (slot_cur->busstatus);
+	else
+		slot_cur->bus_on->current_bus_mode = 0xFF;
 
 	debug ("busstatus = %x, bus_speed = %x, bus_mode = %x\n", slot_cur->busstatus, slot_cur->bus_on->current_speed, slot_cur->bus_on->current_bus_mode);
 	
@@ -106,13 +108,17 @@
 	return rc;
 }
 
-static int get_max_slots (void)
+static int __init get_max_slots (void)
 {
+	struct slot * slot_cur;
 	struct list_head * tmp;
-	int slot_count = 0;
+	u8 slot_count = 0;
 
-	list_for_each (tmp, &ibmphp_slot_head) 
-		++slot_count;
+	list_for_each (tmp, &ibmphp_slot_head) {
+		slot_cur = list_entry (tmp, struct slot, ibm_slot_list);
+		/* sometimes the hot-pluggable slots start with 4 (not always from 1 */
+		slot_count = max (slot_count, slot_cur->number);
+	}
 	return slot_count;
 }
 
@@ -330,7 +336,7 @@
 			memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot));
 			hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status));
 			if (!hpcrc) {
-				*value = SLOT_POWER (myslot.status);
+				*value = SLOT_PWRGD (myslot.status);
 				rc = 0;
 			}
 		}
@@ -378,14 +384,15 @@
 	debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
 	return rc;
 }
-/*
-static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value)
+
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
 {
 	int rc = -ENODEV;
 	struct slot *pslot;
 	u8 mode = 0;
 
-	debug ("get_max_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+	debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__,
+		hotplug_slot, value);
 
 	ibmphp_lock_operations ();
 
@@ -393,32 +400,40 @@
 		pslot = (struct slot *) hotplug_slot->private;
 		if (pslot) {
 			rc = 0;
-			mode = pslot->bus_on->supported_bus_mode;
-			*value = pslot->bus_on->supported_speed;
-			*value &= 0x0f;
-
-			if (mode == BUS_MODE_PCIX)
-				*value |= 0x80;
-			else if (mode == BUS_MODE_PCI)
-				*value |= 0x40;
-			else
-				*value |= 0x20;
+			mode = pslot->supported_bus_mode;
+			*value = pslot->supported_speed; 
+			switch (*value) {
+			case BUS_SPEED_33:
+				break;
+			case BUS_SPEED_66:
+				if (mode == BUS_MODE_PCIX) 
+					*value += 0x01;
+				break;
+			case BUS_SPEED_100:
+			case BUS_SPEED_133:
+				*value = pslot->supported_speed + 0x01;
+				break;
+			default:
+				/* Note (will need to change): there would be soon 256, 512 also */
+				rc = -ENODEV;
+			}
 		}
 	} else
 		rc = -ENODEV;
 
 	ibmphp_unlock_operations ();
-	debug ("get_max_bus_speed - Exit rc[%d] value[%x]\n", rc, *value);
+	debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value);
 	return rc;
 }
 
-static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value)
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
 {
 	int rc = -ENODEV;
 	struct slot *pslot;
 	u8 mode = 0;
 
-	debug ("get_cur_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+	debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__,
+		hotplug_slot, value);
 
 	ibmphp_lock_operations ();
 
@@ -429,24 +444,35 @@
 			if (!rc) {
 				mode = pslot->bus_on->current_bus_mode;
 				*value = pslot->bus_on->current_speed;
-				*value &= 0x0f;
-				
-				if (mode == BUS_MODE_PCIX)
-					*value |= 0x80;
-				else if (mode == BUS_MODE_PCI)
-					*value |= 0x40;
-				else
-					*value |= 0x20;	
+				switch (*value) {
+				case BUS_SPEED_33:
+					break;
+				case BUS_SPEED_66:
+					if (mode == BUS_MODE_PCIX) 
+						*value += 0x01;
+					else if (mode == BUS_MODE_PCI)
+						;
+					else
+						*value = PCI_SPEED_UNKNOWN;
+					break;
+				case BUS_SPEED_100:
+				case BUS_SPEED_133:
+					*value += 0x01;
+					break;
+				default:
+					/* Note of change: there would also be 256, 512 soon */
+					rc = -ENODEV;
+				}
 			}
 		}
 	} else
 		rc = -ENODEV;
 
 	ibmphp_unlock_operations ();
-	debug ("get_cur_bus_speed - Exit rc[%d] value[%x]\n", rc, *value);
+	debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value);
 	return rc;
 }
-
+/*
 static int get_max_adapter_speed_1 (struct hotplug_slot *hotplug_slot, u8 * value, u8 flag)
 {
 	int rc = -ENODEV;
@@ -454,7 +480,7 @@
 	int hpcrc = 0;
 	struct slot myslot;
 
-	debug ("get_max_adapter_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+	debug ("get_max_adapter_speed_1 - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
 
 	if (flag)
 		ibmphp_lock_operations ();
@@ -485,17 +511,16 @@
 	if (flag)
 		ibmphp_unlock_operations ();
 
-	debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
+	debug ("get_max_adapter_speed_1 - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
 	return rc;
 }
 
-static int get_card_bus_names (struct hotplug_slot *hotplug_slot, char * value)
+static int get_bus_name (struct hotplug_slot *hotplug_slot, char * value)
 {
 	int rc = -ENODEV;
 	struct slot *pslot = NULL;
-	struct pci_dev * dev = NULL;
 
-	debug ("get_card_bus_names - Entry hotplug_slot[%lx] \n", (ulong)hotplug_slot);
+	debug ("get_bus_name - Entry hotplug_slot[%lx] \n", (ulong)hotplug_slot);
 
 	ibmphp_lock_operations ();
 
@@ -503,40 +528,33 @@
 		pslot = (struct slot *) hotplug_slot->private;
 		if (pslot) {
 			rc = 0;
-			if (pslot->func)
-				dev = pslot->func->dev;
-			else
-                		dev = pci_find_slot (pslot->bus, (pslot->device << 3) | (0x00 & 0x7));
-			if (dev) 
-				snprintf (value, 100, "Bus %d : %s", pslot->bus,dev->name);
-			else
-				snprintf (value, 100, "Bus %d", pslot->bus);
-			
-				
+			snprintf (value, 100, "Bus %x", pslot->bus);
 		}
 	} else
 		rc = -ENODEV;
 
 	ibmphp_unlock_operations ();
-	debug ("get_card_bus_names - Exit rc[%d] value[%x]\n", rc, *value);
+	debug ("get_bus_name - Exit rc[%d] value[%x]\n", rc, *value);
 	return rc;
 }
-
 */
+
 /*******************************************************************************
  * This routine will initialize the ops data structure used in the validate
  * function. It will also power off empty slots that are powered on since BIOS
  * leaves those on, albeit disconnected
  ******************************************************************************/
-static int init_ops (void)
+static int __init init_ops (void)
 {
 	struct slot *slot_cur;
+	struct list_head *tmp;
 	int retval;
-	int j;
 	int rc;
+	int j;
 
 	for (j = 0; j < MAX_OPS; j++) {
 		ops[j] = (int *) kmalloc ((max_slots + 1) * sizeof (int), GFP_KERNEL);
+		memset (ops[j], 0, (max_slots + 1) * sizeof (int));
 		if (!ops[j]) {
 			err ("out of system memory \n");
 			return -ENOMEM;
@@ -547,12 +565,13 @@
 	ops[REMOVE][0] = 0;
 	ops[DETAIL][0] = 0;
 
-	for (j = 1; j <= max_slots; j++) {
+	list_for_each (tmp, &ibmphp_slot_head) {
+		slot_cur = list_entry (tmp, struct slot, ibm_slot_list);
 
-		slot_cur = ibmphp_get_slot_from_physical_num (j);
+		if (!slot_cur)
+			return -ENODEV;
 
 		debug ("BEFORE GETTING SLOT STATUS, slot # %x\n", slot_cur->number);
-
 		if (slot_cur->ctrl->revision == 0xFF) 
 			if (get_ctrl_revision (slot_cur, &slot_cur->ctrl->revision))
 				return -1;
@@ -572,21 +591,21 @@
 		debug ("status = %x, ext_status = %x\n", slot_cur->status, slot_cur->ext_status);
 		debug ("SLOT_POWER = %x, SLOT_PRESENT = %x, SLOT_LATCH = %x\n", SLOT_POWER (slot_cur->status), SLOT_PRESENT (slot_cur->status), SLOT_LATCH (slot_cur->status));
 
-		if (!(SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status)))
+		if (!(SLOT_PWRGD (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status)))
 			/* No power, adapter, and latch closed */
-			ops[ADD][j] = 1;
+			ops[ADD][slot_cur->number] = 1;
 		else
-			ops[ADD][j] = 0;
+			ops[ADD][slot_cur->number] = 0;
 
-		ops[DETAIL][j] = 1;
+		ops[DETAIL][slot_cur->number] = 1;
 
-		if ((SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status)))
+		if ((SLOT_PWRGD (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status)))
 			/*Power,adapter,latch closed */
-			ops[REMOVE][j] = 1;
+			ops[REMOVE][slot_cur->number] = 1;
 		else
-			ops[REMOVE][j] = 0;
+			ops[REMOVE][slot_cur->number] = 0;
 
-		if ((SLOT_POWER (slot_cur->status)) && !(SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status))) {
+		if ((SLOT_PWRGD (slot_cur->status)) && !(SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status))) {
 			debug ("BEFORE POWER OFF COMMAND\n");
 				rc = power_off (slot_cur);
 				if (rc)
@@ -624,7 +643,7 @@
 	if (retval)
 		return retval;
 
-	if (!(SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status))
+	if (!(SLOT_PWRGD (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status))
 	    && !(SLOT_LATCH (slot_cur->status)))
 		ops[ADD][number] = 1;
 	else
@@ -632,7 +651,7 @@
 
 	ops[DETAIL][number] = 1;
 
-	if ((SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status))
+	if ((SLOT_PWRGD (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status))
 	    && !(SLOT_LATCH (slot_cur->status)))
 		ops[REMOVE][number] = 1;
 	else
@@ -667,9 +686,10 @@
 int ibmphp_update_slot_info (struct slot *slot_cur)
 {
 	struct hotplug_slot_info *info;
-	char buffer[10];
+	char buffer[30];
 	int rc;
-//	u8 bus_speed;
+	u8 bus_speed;
+	u8 mode;
 
 	info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
 	if (!info) {
@@ -677,8 +697,8 @@
 		return -ENOMEM;
 	}
         
-	snprintf (buffer, 10, "%d", slot_cur->number);
-	info->power_status = SLOT_POWER (slot_cur->status);
+	strncpy (buffer, slot_cur->hotplug_slot->name, 30);
+	info->power_status = SLOT_PWRGD (slot_cur->status);
 	info->attention_status = SLOT_ATTN (slot_cur->status, slot_cur->ext_status);
 	info->latch_status = SLOT_LATCH (slot_cur->status);
         if (!SLOT_PRESENT (slot_cur->status)) {
@@ -688,21 +708,33 @@
                 info->adapter_status = 1;
 //		get_max_adapter_speed_1 (slot_cur->hotplug_slot, &info->max_adapter_speed_status, 0);
 	}
-/*
+
 	bus_speed = slot_cur->bus_on->current_speed;
-	bus_speed &= 0x0f;
-                        
-	if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX)
-		bus_speed |= 0x80;
-	else if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCI)
-		bus_speed |= 0x40;
-	else
-		bus_speed |= 0x20;
+	mode = slot_cur->bus_on->current_bus_mode;
 
-	info->cur_bus_speed_status = bus_speed;
-	info->max_bus_speed_status = slot_cur->hotplug_slot->info->max_bus_speed_status;
-	// To do: card_bus_names 
-*/	
+	switch (bus_speed) {
+	case BUS_SPEED_33:
+		break;
+	case BUS_SPEED_66:
+		if (mode == BUS_MODE_PCIX) 
+			bus_speed += 0x01;
+		else if (mode == BUS_MODE_PCI)
+			;
+		else
+			bus_speed = PCI_SPEED_UNKNOWN;
+		break;
+	case BUS_SPEED_100:
+	case BUS_SPEED_133:
+		bus_speed += 0x01;
+		break;
+	default:
+		bus_speed = PCI_SPEED_UNKNOWN;
+	}
+
+	info->cur_bus_speed = bus_speed;
+	info->max_bus_speed = slot_cur->hotplug_slot->info->max_bus_speed;
+	// To do: bus_names 
+	
 	rc = pci_hp_change_slot_info (buffer, info);
 	kfree (info);
 	return rc;
@@ -775,8 +807,10 @@
 	struct list_head * tmp;
 	struct list_head * next;
 
-	list_for_each_safe (tmp, next, &ibmphp_slot_head) {
+	debug ("%s -- enter\n", __FUNCTION__);
 
+	list_for_each_safe (tmp, next, &ibmphp_slot_head) {
+	
 		slot_cur = list_entry (tmp, struct slot, ibm_slot_list);
 
 		pci_hp_deregister (slot_cur->hotplug_slot);
@@ -795,7 +829,9 @@
 		ibmphp_unconfigure_card (&slot_cur, -1);  /* we don't want to actually remove the resources, since free_resources will do just that */
 
 		kfree (slot_cur);
+		slot_cur = NULL;
 	}
+	debug ("%s -- exit\n", __FUNCTION__);
 }
 
 static int ibm_is_pci_dev_in_use (struct pci_dev *dev)
@@ -851,7 +887,7 @@
 	if (temp_func)
 		temp_func->dev = NULL;
 	else
-		err ("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn);
+		debug ("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn);
 
 	return 0;
 }
@@ -893,12 +929,12 @@
 }
 
 static struct pci_visit ibm_unconfigure_functions_phase1 = {
-	post_visit_pci_dev:	ibm_unconfigure_visit_pci_dev_phase1,
+	.post_visit_pci_dev =	ibm_unconfigure_visit_pci_dev_phase1,
 };
 
 static struct pci_visit ibm_unconfigure_functions_phase2 = {
-	post_visit_pci_bus:	ibm_unconfigure_visit_pci_bus_phase2,
-	post_visit_pci_dev:	ibm_unconfigure_visit_pci_dev_phase2,
+	.post_visit_pci_bus =	ibm_unconfigure_visit_pci_bus_phase2,
+	.post_visit_pci_dev =	ibm_unconfigure_visit_pci_dev_phase2,
 };
 
 static int ibm_unconfigure_device (struct pci_func *func)
@@ -962,9 +998,37 @@
 }
 
 static struct pci_visit configure_functions = {
-	visit_pci_dev:	configure_visit_pci_dev,
+	.visit_pci_dev =configure_visit_pci_dev,
 };
 
+
+/*
+ * The following function is to fix kernel bug regarding 
+ * getting bus entries, here we manually add those primary 
+ * bus entries to kernel bus structure whenever apply
+ */
+
+static u8 bus_structure_fixup (u8 busno)
+{
+	struct pci_bus bus_t;
+	struct pci_dev dev_t;
+	u16 l;
+
+	if (find_bus (busno) || !(ibmphp_find_same_bus_num (busno)))
+		return 1;
+	bus_t.number = busno;
+	bus_t.ops = ibmphp_pci_root_ops;
+	dev_t.bus = &bus_t;
+	for (dev_t.devfn=0; dev_t.devfn<256; dev_t.devfn += 8) {
+		if (!pci_read_config_word (&dev_t, PCI_VENDOR_ID, &l) &&  l != 0x0000 && l != 0xffff) {
+			debug ("%s - Inside bus_struture_fixup() \n", __FUNCTION__);
+			pci_scan_bus (busno, ibmphp_pci_root_ops, NULL);
+			break;
+		}
+	}
+	return 0;
+}
+
 static int ibm_configure_device (struct pci_func *func)
 {
 	unsigned char bus;
@@ -972,6 +1036,7 @@
 	struct pci_bus *child;
 	struct pci_dev *temp;
 	int rc = 0;
+	int flag = 0;	/* this is to make sure we don't double scan the bus, for bridged devices primarily */
 
 	struct pci_dev_wrapped wrapped_dev;
 	struct pci_bus_wrapped wrapped_bus;
@@ -980,6 +1045,8 @@
 	memset (&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
 	memset (&dev0, 0, sizeof (struct pci_dev));
 
+	if (!(bus_structure_fixup (func->busno)))
+		flag = 1;
 	if (func->dev == NULL)
 		func->dev = pci_find_slot (func->busno, (func->device << 3) | (func->function & 0x7));
 
@@ -995,7 +1062,7 @@
 			return 0;
 		}
 	}
-	if (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+	if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) {
 		pci_read_config_byte (func->dev, PCI_SECONDARY_BUS, &bus);
 		child = (struct pci_bus *) pci_add_new_bus (func->dev->bus, (func->dev), bus);
 		pci_do_scan_bus (child);
@@ -1009,6 +1076,7 @@
 	}
 	return rc;
 }
+
 /*******************************************************
  * Returns whether the bus is empty or not 
  *******************************************************/
@@ -1027,7 +1095,7 @@
 		rc = slot_update (&tmp_slot);
 		if (rc)
 			return 0;
-		if (SLOT_PRESENT (tmp_slot->status) && SLOT_POWER (tmp_slot->status))
+		if (SLOT_PRESENT (tmp_slot->status) && SLOT_PWRGD (tmp_slot->status))
 			return 0;
 		i++;
 	}
@@ -1036,13 +1104,18 @@
 
 /***********************************************************
  * If the HPC permits and the bus currently empty, tries to set the 
- * bus speed and mode at the maximum card capability
+ * bus speed and mode at the maximum card and bus capability
+ * Parameters: slot
+ * Returns: bus is set (0) or error code
  ***********************************************************/
 static int set_bus (struct slot * slot_cur)
 {
 	int rc;
 	u8 speed;
 	u8 cmd = 0x0;
+	const struct list_head *tmp;
+	struct pci_dev * dev;
+	int retval;
 
 	debug ("%s - entry slot # %d \n", __FUNCTION__, slot_cur->number);
 	if (SET_BUS_STATUS (slot_cur->ctrl) && is_bus_empty (slot_cur)) {
@@ -1056,30 +1129,118 @@
 			cmd = HPC_BUS_33CONVMODE;
 			break;
 		case HPC_SLOT_SPEED_66:
-			if (SLOT_PCIX (slot_cur->ext_status))
-				cmd = HPC_BUS_66PCIXMODE;
-			else
-				cmd = HPC_BUS_66CONVMODE;
+			if (SLOT_PCIX (slot_cur->ext_status)) {
+				if ((slot_cur->supported_speed >= BUS_SPEED_66) && (slot_cur->supported_bus_mode == BUS_MODE_PCIX))
+					cmd = HPC_BUS_66PCIXMODE;
+				else if (!SLOT_BUS_MODE (slot_cur->ext_status))
+					/* if max slot/bus capability is 66 pci
+					and there's no bus mode mismatch, then
+					the adapter supports 66 pci */ 
+					cmd = HPC_BUS_66CONVMODE;
+				else
+					cmd = HPC_BUS_33CONVMODE;
+			} else {
+				if (slot_cur->supported_speed >= BUS_SPEED_66)
+					cmd = HPC_BUS_66CONVMODE;
+				else
+					cmd = HPC_BUS_33CONVMODE;
+			}
 			break;
 		case HPC_SLOT_SPEED_133:
-			if (slot_cur->bus_on->slot_count > 1)
+			switch (slot_cur->supported_speed) {
+			case BUS_SPEED_33:
+				cmd = HPC_BUS_33CONVMODE;
+				break;
+			case BUS_SPEED_66:
+				if (slot_cur->supported_bus_mode == BUS_MODE_PCIX)
+					cmd = HPC_BUS_66PCIXMODE;
+				else
+					cmd = HPC_BUS_66CONVMODE;
+				break;
+			case BUS_SPEED_100:
 				cmd = HPC_BUS_100PCIXMODE;
-			else
+				break;
+			case BUS_SPEED_133:
+				/* This is to take care of the bug in CIOBX chip*/
+				list_for_each (tmp, &pci_devices) {
+					dev = (struct pci_dev *) pci_dev_g (tmp);
+					if (dev) {
+						if ((dev->vendor == 0x1166) && (dev->device == 0x0101))
+							ibmphp_hpc_writeslot (slot_cur, HPC_BUS_100PCIXMODE);
+					}
+				}
 				cmd = HPC_BUS_133PCIXMODE;
+				break;
+			default:
+				err ("Wrong bus speed \n");
+				return -ENODEV;
+			}
 			break;
 		default:
 			err ("wrong slot speed \n");
 			return -ENODEV;
 		}
 		debug ("setting bus speed for slot %d, cmd %x\n", slot_cur->number, cmd);
-		rc = ibmphp_hpc_writeslot (slot_cur, cmd);
-		if (rc)
-			return rc;
+		retval = ibmphp_hpc_writeslot (slot_cur, cmd);
+		if (retval) {
+			err ("setting bus speed failed\n");
+			return retval;
+		}
+		if (CTLR_RESULT (slot_cur->ctrl->status)) {
+			err ("command not completed successfully in set_bus \n");
+			return -EIO;
+		}
 	}
+	/* This is for x440, once Brandon fixes the firmware, 
+	will not need this delay */
+	long_delay (1 * HZ);
 	debug ("%s -Exit \n", __FUNCTION__);
 	return 0;
 }
 
+/* This routine checks the bus limitations that the slot is on from the BIOS.
+ * This is used in deciding whether or not to power up the slot.  
+ * (electrical/spec limitations. For example, >1 133 MHz or >2 66 PCI cards on
+ * same bus) 
+ * Parameters: slot
+ * Returns: 0 = no limitations, -EINVAL = exceeded limitations on the bus
+ */
+static int check_limitations (struct slot *slot_cur)
+{
+	u8 i;
+	struct slot * tmp_slot;
+	u8 count = 0;
+	u8 limitation = 0;
+
+	for (i = slot_cur->bus_on->slot_min; i <= slot_cur->bus_on->slot_max; i++) {
+		tmp_slot = ibmphp_get_slot_from_physical_num (i);
+		if ((SLOT_PWRGD (tmp_slot->status)) && !(SLOT_CONNECT (tmp_slot->status))) 
+			count++;
+	}
+	get_cur_bus_info (&slot_cur);
+	switch (slot_cur->bus_on->current_speed) {
+	case BUS_SPEED_33:
+		limitation = slot_cur->bus_on->slots_at_33_conv;
+		break;
+	case BUS_SPEED_66:
+		if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX)
+			limitation = slot_cur->bus_on->slots_at_66_pcix;
+		else
+			limitation = slot_cur->bus_on->slots_at_66_conv;
+		break;
+	case BUS_SPEED_100:
+		limitation = slot_cur->bus_on->slots_at_100_pcix;
+		break;
+	case BUS_SPEED_133:
+		limitation = slot_cur->bus_on->slots_at_133_pcix;
+		break;
+	}
+
+	if ((count + 1) > limitation)
+		return -EINVAL;
+	return 0;
+}
+
 static inline void print_card_capability (struct slot *slot_cur)
 {
 	info ("capability of the card is ");
@@ -1136,7 +1297,28 @@
 		ibmphp_unlock_operations ();
 		return -ENODEV;
 	}
-		
+
+	/*-----------------debugging------------------------------*/
+	get_cur_bus_info (&slot_cur);
+	debug ("the current bus speed right after set_bus = %x \n", slot_cur->bus_on->current_speed); 
+	/*----------------------------------------------------------*/
+
+	rc = check_limitations (slot_cur);
+	if (rc) {
+		err ("Adding this card exceeds the limitations of this bus. \n");
+		err ("(i.e., >1 133MHz cards running on same bus, or >2 66 PCI cards running on same bus \n. Try hot-adding into another bus \n");
+		attn_off (slot_cur);
+		attn_on (slot_cur);
+
+		if (slot_update (&slot_cur)) {
+			ibmphp_unlock_operations ();
+			return -ENODEV;
+		}
+		ibmphp_update_slot_info (slot_cur);
+		ibmphp_unlock_operations ();
+		return -EINVAL;
+	}
+
 	rc = power_on (slot_cur);
 
 	if (rc) {
@@ -1151,19 +1333,24 @@
 			return -ENODEV;
 		}
 		/* Check to see the error of why it failed */
-		if (!(SLOT_PWRGD (slot_cur->status)))
+		if ((SLOT_POWER (slot_cur->status)) && !(SLOT_PWRGD (slot_cur->status)))
 			err ("power fault occured trying to power up \n");
 		else if (SLOT_BUS_SPEED (slot_cur->status)) {
 			err ("bus speed mismatch occured.  please check current bus speed and card capability \n");
 			print_card_capability (slot_cur);
-		} else if (SLOT_BUS_MODE (slot_cur->ext_status)) 
+		} else if (SLOT_BUS_MODE (slot_cur->ext_status)) {
 			err ("bus mode mismatch occured.  please check current bus mode and card capability \n");
-
+			print_card_capability (slot_cur);
+		}
 		ibmphp_update_slot_info (slot_cur);
-		ibmphp_unlock_operations (); 
+		ibmphp_unlock_operations ();
 		return rc;
 	}
 	debug ("after power_on\n");
+	/*-----------------------debugging---------------------------*/
+	get_cur_bus_info (&slot_cur);
+	debug ("the current bus speed right after power_on = %x \n", slot_cur->bus_on->current_speed);
+	/*----------------------------------------------------------*/
 
 	rc = slot_update (&slot_cur);
 	if (rc) {
@@ -1180,7 +1367,7 @@
 	
 	if (SLOT_POWER (slot_cur->status) && !(SLOT_PWRGD (slot_cur->status))) {
 		faulted = 1;
-		err ("power fault occured trying to power up...\n");
+		err ("power fault occured trying to power up... \n");
 	} else if (SLOT_POWER (slot_cur->status) && (SLOT_BUS_SPEED (slot_cur->status))) {
 		faulted = 1;
 		err ("bus speed mismatch occured.  please check current bus speed and card capability \n");
@@ -1200,8 +1387,8 @@
 			return rcpr;
 		}
 			
-		if (slot_update (&slot_cur)) {
-			ibmphp_unlock_operations ();
+		if (slot_update (&slot_cur)) {                      
+			ibmphp_unlock_operations ();	
 			return -ENODEV;
 		}
 		ibmphp_update_slot_info (slot_cur);
@@ -1278,20 +1465,28 @@
 {
 	int rc;
 	struct slot *slot_cur = (struct slot *) hotplug_slot->private;
-	u8 flag = slot_cur->flag;
+	u8 flag;
+	int parm = 0;
 
-	slot_cur->flag = TRUE;
 	debug ("DISABLING SLOT... \n"); 
 		
-	ibmphp_lock_operations (); 
 	if (slot_cur == NULL) {
-		ibmphp_unlock_operations ();
+		ibmphp_unlock_operations (); 
 		return -ENODEV;
 	}
+	
 	if (slot_cur->ctrl == NULL) {
 		ibmphp_unlock_operations ();
 		return -ENODEV;
 	}
+	
+	flag = slot_cur->flag;	/* to see if got here from polling */
+	
+	if (flag)
+		ibmphp_lock_operations ();
+	
+	slot_cur->flag = TRUE;
+
 	if (flag == TRUE) {
 		rc = validate (slot_cur, DISABLE);	/* checking if powered off already & valid slot # */
 		if (rc) {
@@ -1333,10 +1528,21 @@
 		ibmphp_unlock_operations ();
 		return rc;
 	}
+        
+	/* If we got here from latch suddenly opening on operating card or 
+	a power fault, there's no power to the card, so cannot
+	read from it to determine what resources it occupied.  This operation
+	is forbidden anyhow.  The best we can do is remove it from kernel
+	lists at least */
 
-	rc = ibmphp_unconfigure_card (&slot_cur, 0);
+	if (!flag) {
+		attn_off (slot_cur);
+		return 0;
+	}
+
+	rc = ibmphp_unconfigure_card (&slot_cur, parm);
 	slot_cur->func = NULL;
-	debug ("in disable_slot. after unconfigure_card \n");
+	debug ("in disable_slot. after unconfigure_card\n");
 	if (rc) {
 		err ("could not unconfigure card.\n");
 		attn_off (slot_cur);	/* need to turn off if was blinking b4 */
@@ -1347,9 +1553,8 @@
 			return -EFAULT;
 		}
 
-		if (flag) 
+		if (flag)
 			ibmphp_update_slot_info (slot_cur);
-
 		ibmphp_unlock_operations ();
 		return -EFAULT;
 	}
@@ -1363,9 +1568,7 @@
 			return -EFAULT;
 		}
 
-		if (flag)
-			ibmphp_update_slot_info (slot_cur);
-
+		ibmphp_update_slot_info (slot_cur);
 		ibmphp_unlock_operations ();
 		return rc;
 	}
@@ -1375,30 +1578,26 @@
 		ibmphp_unlock_operations ();
 		return -EFAULT;
 	}
-	if (flag) 
-		rc = ibmphp_update_slot_info (slot_cur);
-	else
-		rc = 0;
-
+	rc = ibmphp_update_slot_info (slot_cur);
 	ibmphp_print_test ();
 	ibmphp_unlock_operations();
 	return rc;
 }
 
 struct hotplug_slot_ops ibmphp_hotplug_slot_ops = {
-	owner:				THIS_MODULE,
-	set_attention_status:		set_attention_status,
-	enable_slot:			enable_slot,
-	disable_slot:			ibmphp_disable_slot,
-	hardware_test:			NULL,
-	get_power_status:		get_power_status,
-	get_attention_status:		get_attention_status,
-	get_latch_status:		get_latch_status,
-	get_adapter_status:		get_adapter_present,
-/*	get_max_bus_speed_status:	get_max_bus_speed,
-	get_max_adapter_speed_status:	get_max_adapter_speed,
-	get_cur_bus_speed_status:	get_cur_bus_speed,
-	get_card_bus_names_status:	get_card_bus_names,
+	.owner =			THIS_MODULE,
+	.set_attention_status =		set_attention_status,
+	.enable_slot =			enable_slot,
+	.disable_slot =			ibmphp_disable_slot,
+	.hardware_test =		NULL,
+	.get_power_status =		get_power_status,
+	.get_attention_status =		get_attention_status,
+	.get_latch_status =		get_latch_status,
+	.get_adapter_status =		get_adapter_present,
+	.get_max_bus_speed =		get_max_bus_speed,
+	.get_cur_bus_speed =		get_cur_bus_speed,
+/*	.get_max_adapter_speed =	get_max_adapter_speed,
+	.get_bus_name_status =		get_bus_name,
 */
 };
 
@@ -1422,9 +1621,12 @@
 	int rc = 0;
 
 	init_flag = 1;
+
+	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
 	ibmphp_pci_root_ops = get_root_pci_ops ();
 	if (ibmphp_pci_root_ops == NULL) {
-		err ("cannot read bus operations... will not be able to read the cards.  Please check your system \n");
+		err ("cannot read bus operations... will not be able to read the cards.  Please check your system\n");
 		return -ENODEV;	
 	}
 
@@ -1439,15 +1641,20 @@
 		ibmphp_unload ();
 		return rc;
 	}
-	debug ("after ibmphp_access_ebda () \n");
+	debug ("after ibmphp_access_ebda ()\n");
 
 	if ((rc = ibmphp_rsrc_init ())) {
 		ibmphp_unload ();
 		return rc;
 	}
-	debug ("AFTER Resource & EBDA INITIALIZATIONS \n");
+	debug ("AFTER Resource & EBDA INITIALIZATIONS\n");
 
 	max_slots = get_max_slots ();
+	
+	if ((rc = ibmphp_register_pci ())) {
+		ibmphp_unload ();
+		return rc;
+	}
 
 	if (init_ops ()) {
 		ibmphp_unload ();
@@ -1459,21 +1666,18 @@
 		return -ENODEV;
 	}
 
-	/* lock ourselves into memory with a module count of -1 
-	 * so that no one can unload us. */
+	/* if no NVRAM module selected, lock ourselves into memory with a 
+	 * module count of -1 so that no one can unload us. */
 	MOD_DEC_USE_COUNT;
-
-	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
-
 	return 0;
 }
 
 static void __exit ibmphp_exit (void)
 {
 	ibmphp_hpc_stop_poll_thread ();
-	debug ("after polling \n");
+	debug ("after polling\n");
 	ibmphp_unload ();
-	debug ("done \n");
+	debug ("done\n");
 }
 
 module_init (ibmphp_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/ibmphp_ebda.c linux-2.4.20/drivers/hotplug/ibmphp_ebda.c
--- linux-2.4.19/drivers/hotplug/ibmphp_ebda.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/ibmphp_ebda.c	2002-10-29 11:18:35.000000000 +0000
@@ -34,6 +34,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/list.h>
+#include <linux/init.h>
 #include "ibmphp.h"
 
 /*
@@ -55,11 +56,17 @@
 /* Local variables */
 static struct ebda_hpc_list *hpc_list_ptr;
 static struct ebda_rsrc_list *rsrc_list_ptr;
-static struct rio_table_hdr *rio_table_ptr;
+static struct rio_table_hdr *rio_table_ptr = NULL;
 static LIST_HEAD (ebda_hpc_head);
 static LIST_HEAD (bus_info_head);
+static LIST_HEAD (rio_vg_head);
+static LIST_HEAD (rio_lo_head);
+static LIST_HEAD (opt_vg_head);
+static LIST_HEAD (opt_lo_head);
 static void *io_mem;
 
+char *chassis_str, *rxe_str, *str;
+
 /* Local functions */
 static int ebda_rsrc_controller (void);
 static int ebda_rsrc_rsrc (void);
@@ -76,7 +83,7 @@
 	return slot;
 }
 
-static struct ebda_hpc_list *alloc_ebda_hpc_list (void)
+static struct ebda_hpc_list * __init alloc_ebda_hpc_list (void)
 {
 	struct ebda_hpc_list *list;
 
@@ -124,10 +131,11 @@
 	controller->slots = NULL;
 	kfree (controller->buses);
 	controller->buses = NULL;
+	controller->ctrl_dev = NULL;
 	kfree (controller);
 }
 
-static struct ebda_rsrc_list *alloc_ebda_rsrc_list (void)
+static struct ebda_rsrc_list * __init alloc_ebda_rsrc_list (void)
 {
 	struct ebda_rsrc_list *list;
 
@@ -149,7 +157,7 @@
 	return resource;
 }
 
-static void print_bus_info (void)
+static void __init print_bus_info (void)
 {
 	struct bus_info *ptr;
 	struct list_head *ptr1;
@@ -161,25 +169,89 @@
 		debug ("%s - slot_count = %x\n", __FUNCTION__, ptr->slot_count);
 		debug ("%s - bus# = %x\n", __FUNCTION__, ptr->busno);
 		debug ("%s - current_speed = %x\n", __FUNCTION__, ptr->current_speed);
-		debug ("%s - supported_speed = %x\n", __FUNCTION__, ptr->supported_speed);
 		debug ("%s - controller_id = %x\n", __FUNCTION__, ptr->controller_id);
-		debug ("%s - bus_mode = %x\n", __FUNCTION__, ptr->supported_bus_mode);
+		
+		debug ("%s - slots_at_33_conv = %x\n", __FUNCTION__, ptr->slots_at_33_conv);
+		debug ("%s - slots_at_66_conv = %x\n", __FUNCTION__, ptr->slots_at_66_conv);
+		debug ("%s - slots_at_66_pcix = %x\n", __FUNCTION__, ptr->slots_at_66_pcix);
+		debug ("%s - slots_at_100_pcix = %x\n", __FUNCTION__, ptr->slots_at_100_pcix);
+		debug ("%s - slots_at_133_pcix = %x\n", __FUNCTION__, ptr->slots_at_133_pcix);
+
+	}
+}
+
+static void print_lo_info (void)
+{
+	struct rio_detail *ptr;
+	struct list_head *ptr1;
+	debug ("print_lo_info ---- \n");	
+	list_for_each (ptr1, &rio_lo_head) {
+		ptr = list_entry (ptr1, struct rio_detail, rio_detail_list);
+		debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id);
+		debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type);
+		debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id);
+		debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num);
+		debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex);
+		debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num);
+
+	}
+}
+
+static void print_vg_info (void)
+{
+	struct rio_detail *ptr;
+	struct list_head *ptr1;
+	debug ("%s --- \n", __FUNCTION__);
+	list_for_each (ptr1, &rio_vg_head) {
+		ptr = list_entry (ptr1, struct rio_detail, rio_detail_list);
+		debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id);
+		debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type);
+		debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id);
+		debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num);
+		debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex);
+		debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num);
+
 	}
 }
 
-static void print_ebda_pci_rsrc (void)
+static void __init print_ebda_pci_rsrc (void)
 {
 	struct ebda_pci_rsrc *ptr;
 	struct list_head *ptr1;
 
 	list_for_each (ptr1, &ibmphp_ebda_pci_rsrc_head) {
 		ptr = list_entry (ptr1, struct ebda_pci_rsrc, ebda_pci_rsrc_list);
-		debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %lx end addr: %lx\n", 
+		debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", 
 			__FUNCTION__, ptr->rsrc_type ,ptr->bus_num, ptr->dev_fun,ptr->start_addr, ptr->end_addr);
 	}
 }
 
-static void print_ebda_hpc (void)
+static void __init print_ibm_slot (void)
+{
+	struct slot *ptr;
+	struct list_head *ptr1;
+
+	list_for_each (ptr1, &ibmphp_slot_head) {
+		ptr = list_entry (ptr1, struct slot, ibm_slot_list);
+		debug ("%s - slot_number: %x \n", __FUNCTION__, ptr->number); 
+	}
+}
+
+static void __init print_opt_vg (void)
+{
+	struct opt_rio *ptr;
+	struct list_head *ptr1;
+	debug ("%s --- \n", __FUNCTION__);
+	list_for_each (ptr1, &opt_vg_head) {
+		ptr = list_entry (ptr1, struct opt_rio, opt_rio_list);
+		debug ("%s - rio_type %x \n", __FUNCTION__, ptr->rio_type); 
+		debug ("%s - chassis_num: %x \n", __FUNCTION__, ptr->chassis_num); 
+		debug ("%s - first_slot_num: %x \n", __FUNCTION__, ptr->first_slot_num); 
+		debug ("%s - middle_num: %x \n", __FUNCTION__, ptr->middle_num); 
+	}
+}
+
+static void __init print_ebda_hpc (void)
 {
 	struct controller *hpc_ptr;
 	struct list_head *ptr1;
@@ -215,6 +287,7 @@
 			break;
 
 		case 2:
+		case 4:
 			debug ("%s - wpegbbar: %lx\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.wpegbbar);
 			debug ("%s - i2c_addr: %x\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.i2c_addr);
 			debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq);
@@ -223,7 +296,7 @@
 	}
 }
 
-int ibmphp_access_ebda (void)
+int __init ibmphp_access_ebda (void)
 {
 	u8 format, num_ctlrs, rio_complete, hs_complete;
 	u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, rc, re, rc_id, re_id, base;
@@ -351,38 +424,389 @@
 
 			rio_complete = 1;
 		}
+	}
 
-		if (hs_complete && rio_complete) {
-			rc = ebda_rsrc_controller ();
-			if (rc) {
-				iounmap(io_mem);
-				return rc;
-			}
-			rc = ebda_rsrc_rsrc ();
-			if (rc) {
-				iounmap(io_mem);
-				return rc;
-			}
+	if (!hs_complete && !rio_complete) {
+		iounmap (io_mem);
+		return -ENODEV;
+	}
+
+	if (rio_table_ptr) {
+		if (rio_complete == 1 && rio_table_ptr->ver_num == 3) {
 			rc = ebda_rio_table ();
 			if (rc) {
-				iounmap(io_mem);
+				iounmap (io_mem);
 				return rc;
-			}	
-			iounmap (io_mem);
-			return 0;
+			}
 		}
 	}
+	rc = ebda_rsrc_controller ();
+	if (rc) {
+		iounmap (io_mem);
+		return rc;
+	}
+
+	rc = ebda_rsrc_rsrc ();
+	if (rc) {
+		iounmap (io_mem);
+		return rc;
+	}
+
 	iounmap (io_mem);
-	return -ENODEV;
+	return 0;
+}
+
+/*
+ * map info of scalability details and rio details from physical address
+ */
+static int __init ebda_rio_table (void)
+{
+	u16 offset;
+	u8 i;
+	struct rio_detail *rio_detail_ptr;
+
+	offset = rio_table_ptr->offset;
+	offset += 12 * rio_table_ptr->scal_count;
+
+	// we do concern about rio details
+	for (i = 0; i < rio_table_ptr->riodev_count; i++) {
+		rio_detail_ptr = kmalloc (sizeof (struct rio_detail), GFP_KERNEL);
+		if (!rio_detail_ptr)
+			return -ENOMEM;
+		memset (rio_detail_ptr, 0, sizeof (struct rio_detail));
+		rio_detail_ptr->rio_node_id = readb (io_mem + offset);
+		rio_detail_ptr->bbar = readl (io_mem + offset + 1);
+		rio_detail_ptr->rio_type = readb (io_mem + offset + 5);
+		rio_detail_ptr->owner_id = readb (io_mem + offset + 6);
+		rio_detail_ptr->port0_node_connect = readb (io_mem + offset + 7);
+		rio_detail_ptr->port0_port_connect = readb (io_mem + offset + 8);
+		rio_detail_ptr->port1_node_connect = readb (io_mem + offset + 9);
+		rio_detail_ptr->port1_port_connect = readb (io_mem + offset + 10);
+		rio_detail_ptr->first_slot_num = readb (io_mem + offset + 11);
+		rio_detail_ptr->status = readb (io_mem + offset + 12);
+		rio_detail_ptr->wpindex = readb (io_mem + offset + 13);
+		rio_detail_ptr->chassis_num = readb (io_mem + offset + 14);
+//		debug ("rio_node_id: %x\nbbar: %x\nrio_type: %x\nowner_id: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nfirst_slot_num: %x\nstatus: %x\n", rio_detail_ptr->rio_node_id, rio_detail_ptr->bbar, rio_detail_ptr->rio_type, rio_detail_ptr->owner_id, rio_detail_ptr->port0_node_connect, rio_detail_ptr->port0_port_connect, rio_detail_ptr->port1_node_connect, rio_detail_ptr->port1_port_connect, rio_detail_ptr->first_slot_num, rio_detail_ptr->status);
+		//create linked list of chassis
+		if (rio_detail_ptr->rio_type == 4 || rio_detail_ptr->rio_type == 5) 
+			list_add (&rio_detail_ptr->rio_detail_list, &rio_vg_head);
+		//create linked list of expansion box				
+		else if (rio_detail_ptr->rio_type == 6 || rio_detail_ptr->rio_type == 7) 
+			list_add (&rio_detail_ptr->rio_detail_list, &rio_lo_head);
+		else 
+			// not in my concern
+			kfree (rio_detail_ptr);
+		offset += 15;
+	}
+	print_lo_info ();
+	print_vg_info ();
+	return 0;
+}
+
+/*
+ * reorganizing linked list of chassis	 
+ */
+static struct opt_rio *search_opt_vg (u8 chassis_num)
+{
+	struct opt_rio *ptr;
+	struct list_head *ptr1;
+	list_for_each (ptr1, &opt_vg_head) {
+		ptr = list_entry (ptr1, struct opt_rio, opt_rio_list);
+		if (ptr->chassis_num == chassis_num)
+			return ptr;
+	}		
+	return NULL;
+}
+
+static int __init combine_wpg_for_chassis (void)
+{
+	struct opt_rio *opt_rio_ptr = NULL;
+	struct rio_detail *rio_detail_ptr = NULL;
+	struct list_head *list_head_ptr = NULL;
+	
+	list_for_each (list_head_ptr, &rio_vg_head) {
+		rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list);
+		opt_rio_ptr = search_opt_vg (rio_detail_ptr->chassis_num);
+		if (!opt_rio_ptr) {
+			opt_rio_ptr = (struct opt_rio *) kmalloc (sizeof (struct opt_rio), GFP_KERNEL);
+			if (!opt_rio_ptr)
+				return -ENOMEM;
+			memset (opt_rio_ptr, 0, sizeof (struct opt_rio));
+			opt_rio_ptr->rio_type = rio_detail_ptr->rio_type;
+			opt_rio_ptr->chassis_num = rio_detail_ptr->chassis_num;
+			opt_rio_ptr->first_slot_num = rio_detail_ptr->first_slot_num;
+			opt_rio_ptr->middle_num = rio_detail_ptr->first_slot_num;
+			list_add (&opt_rio_ptr->opt_rio_list, &opt_vg_head);
+		} else {	
+			opt_rio_ptr->first_slot_num = min (opt_rio_ptr->first_slot_num, rio_detail_ptr->first_slot_num);
+			opt_rio_ptr->middle_num = max (opt_rio_ptr->middle_num, rio_detail_ptr->first_slot_num);
+		}	
+	}
+	print_opt_vg ();
+	return 0;	
+}	
+
+/*
+ * reorgnizing linked list of expansion box	 
+ */
+static struct opt_rio_lo *search_opt_lo (u8 chassis_num)
+{
+	struct opt_rio_lo *ptr;
+	struct list_head *ptr1;
+	list_for_each (ptr1, &opt_lo_head) {
+		ptr = list_entry (ptr1, struct opt_rio_lo, opt_rio_lo_list);
+		if (ptr->chassis_num == chassis_num)
+			return ptr;
+	}		
+	return NULL;
+}
+
+static int combine_wpg_for_expansion (void)
+{
+	struct opt_rio_lo *opt_rio_lo_ptr = NULL;
+	struct rio_detail *rio_detail_ptr = NULL;
+	struct list_head *list_head_ptr = NULL;
+	
+	list_for_each (list_head_ptr, &rio_lo_head) {
+		rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list);
+		opt_rio_lo_ptr = search_opt_lo (rio_detail_ptr->chassis_num);
+		if (!opt_rio_lo_ptr) {
+			opt_rio_lo_ptr = (struct opt_rio_lo *) kmalloc (sizeof (struct opt_rio_lo), GFP_KERNEL);
+			if (!opt_rio_lo_ptr)
+				return -ENOMEM;
+			memset (opt_rio_lo_ptr, 0, sizeof (struct opt_rio_lo));
+			opt_rio_lo_ptr->rio_type = rio_detail_ptr->rio_type;
+			opt_rio_lo_ptr->chassis_num = rio_detail_ptr->chassis_num;
+			opt_rio_lo_ptr->first_slot_num = rio_detail_ptr->first_slot_num;
+			opt_rio_lo_ptr->middle_num = rio_detail_ptr->first_slot_num;
+			opt_rio_lo_ptr->pack_count = 1;
+			
+			list_add (&opt_rio_lo_ptr->opt_rio_lo_list, &opt_lo_head);
+		} else {	
+			opt_rio_lo_ptr->first_slot_num = min (opt_rio_lo_ptr->first_slot_num, rio_detail_ptr->first_slot_num);
+			opt_rio_lo_ptr->middle_num = max (opt_rio_lo_ptr->middle_num, rio_detail_ptr->first_slot_num);
+			opt_rio_lo_ptr->pack_count = 2;
+		}	
+	}
+	return 0;	
+}
+	
+static char *convert_2digits_to_char (int var)
+{
+	int bit;	
+	char *str1;
+
+	str = (char *) kmalloc (3, GFP_KERNEL);
+	memset (str, 0, 3);
+	str1 = (char *) kmalloc (2, GFP_KERNEL);
+	memset (str, 0, 3);
+	bit = (int)(var / 10);
+	switch (bit) {
+	case 0:
+		//one digit number
+		*str = (char)(var + 48);
+		return str;
+	default: 	
+		//2 digits number
+		*str1 = (char)(bit + 48);
+		strncpy (str, str1, 1);
+		memset (str1, 0, 3);
+		*str1 = (char)((var % 10) + 48);
+		strcat (str, str1);
+		return str;
+	}	
+	return NULL;	
+}
+
+/* Since we don't know the max slot number per each chassis, hence go
+ * through the list of all chassis to find out the range
+ * Arguments: slot_num, 1st slot number of the chassis we think we are on, 
+ * var (0 = chassis, 1 = expansion box) 
+ */
+static int first_slot_num (u8 slot_num, u8 first_slot, u8 var)
+{
+	struct opt_rio *opt_vg_ptr = NULL;
+	struct opt_rio_lo *opt_lo_ptr = NULL;
+	struct list_head *ptr = NULL;
+	int rc = 0;
+
+	if (!var) {
+		list_for_each (ptr, &opt_vg_head) {
+			opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list);
+			if ((first_slot < opt_vg_ptr->first_slot_num) && (slot_num >= opt_vg_ptr->first_slot_num)) { 
+				rc = -ENODEV;
+				break;
+			}
+		}
+	} else {
+		list_for_each (ptr, &opt_lo_head) {
+			opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list);
+			if ((first_slot < opt_lo_ptr->first_slot_num) && (slot_num >= opt_lo_ptr->first_slot_num)) {
+				rc = -ENODEV;
+				break;
+			}
+		}
+	}
+	return rc;
+}
+
+static struct opt_rio_lo * find_rxe_num (u8 slot_num)
+{
+	struct opt_rio_lo *opt_lo_ptr;
+	struct list_head *ptr;
+
+	list_for_each (ptr, &opt_lo_head) {
+		opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list);
+		//check to see if this slot_num belongs to expansion box
+		if ((slot_num >= opt_lo_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_lo_ptr->first_slot_num, 1))) 
+			return opt_lo_ptr;
+	}
+	return NULL;
+}
+
+static struct opt_rio * find_chassis_num (u8 slot_num)
+{
+	struct opt_rio *opt_vg_ptr;
+	struct list_head *ptr;
+
+	list_for_each (ptr, &opt_vg_head) {
+		opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list);
+		//check to see if this slot_num belongs to chassis 
+		if ((slot_num >= opt_vg_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_vg_ptr->first_slot_num, 0))) 
+			return opt_vg_ptr;
+	}
+	return NULL;
+}
+
+/* This routine will find out how many slots are in the chassis, so that
+ * the slot numbers for rxe100 would start from 1, and not from 7, or 6 etc
+ */
+static u8 calculate_first_slot (u8 slot_num)
+{
+	u8 first_slot = 1;
+	struct list_head * list;
+	struct slot * slot_cur;
+	
+	list_for_each (list, &ibmphp_slot_head) {
+		slot_cur = list_entry (list, struct slot, ibm_slot_list);
+		if (slot_cur->ctrl) {
+			if ((slot_cur->ctrl->ctlr_type != 4) && (slot_cur->ctrl->ending_slot_num > first_slot) && (slot_num > slot_cur->ctrl->ending_slot_num)) 
+				first_slot = slot_cur->ctrl->ending_slot_num;
+		}
+	}			
+	return first_slot + 1;
+
 }
+static char *create_file_name (struct slot * slot_cur)
+{
+	struct opt_rio *opt_vg_ptr = NULL;
+	struct opt_rio_lo *opt_lo_ptr = NULL;
+	char *ptr_chassis_num, *ptr_rxe_num, *ptr_slot_num;
+	int which = 0; /* rxe = 1, chassis = 0 */
+	u8 number = 1; /* either chassis or rxe # */
+	u8 first_slot = 1;
+	u8 slot_num;
+	u8 flag = 0;
 
+	if (!slot_cur) {
+		err ("Structure passed is empty \n");
+		return NULL;
+	}
+	
+	slot_num = slot_cur->number;
+
+	chassis_str = (char *) kmalloc (30, GFP_KERNEL);
+	memset (chassis_str, 0, 30);
+	rxe_str = (char *) kmalloc (30, GFP_KERNEL);
+	memset (rxe_str, 0, 30);
+	ptr_chassis_num = (char *) kmalloc (3, GFP_KERNEL);
+	memset (ptr_chassis_num, 0, 3);
+	ptr_rxe_num = (char *) kmalloc (3, GFP_KERNEL);
+	memset (ptr_rxe_num, 0, 3);
+	ptr_slot_num = (char *) kmalloc (3, GFP_KERNEL);
+	memset (ptr_slot_num, 0, 3);
+	
+	strcpy (chassis_str, "chassis");
+	strcpy (rxe_str, "rxe");
+	
+	if (rio_table_ptr) {
+		if (rio_table_ptr->ver_num == 3) {
+			opt_vg_ptr = find_chassis_num (slot_num);
+			opt_lo_ptr = find_rxe_num (slot_num);
+		}
+	}
+	if (opt_vg_ptr) {
+		if (opt_lo_ptr) {
+			if ((slot_num - opt_vg_ptr->first_slot_num) > (slot_num - opt_lo_ptr->first_slot_num)) {
+				number = opt_lo_ptr->chassis_num;
+				first_slot = opt_lo_ptr->first_slot_num;
+				which = 1; /* it is RXE */
+			} else {
+				first_slot = opt_vg_ptr->first_slot_num;
+				number = opt_vg_ptr->chassis_num;
+				which = 0;
+			}
+		} else {
+			first_slot = opt_vg_ptr->first_slot_num;
+			number = opt_vg_ptr->chassis_num;
+			which = 0;
+		}
+		++flag;
+	} else if (opt_lo_ptr) {
+		number = opt_lo_ptr->chassis_num;
+		first_slot = opt_lo_ptr->first_slot_num;
+		which = 1;
+		++flag;
+	} else if (rio_table_ptr) {
+		if (rio_table_ptr->ver_num == 3) {
+			/* if both NULL and we DO have correct RIO table in BIOS */
+			return NULL;
+		}
+	} 
+	if (!flag) {
+		if (slot_cur->ctrl->ctlr_type == 4) {
+			first_slot = calculate_first_slot (slot_num);
+			which = 1;
+		} else {
+			which = 0;
+		}
+	}
+
+	switch (which) {
+	case 0:
+		/* Chassis */
+		*ptr_chassis_num = (char)(number + 48);
+		strcat (chassis_str, ptr_chassis_num);
+		kfree (ptr_chassis_num);
+		strcat (chassis_str, "slot");
+		ptr_slot_num = convert_2digits_to_char (slot_num - first_slot + 1);
+		strcat (chassis_str, ptr_slot_num);
+		kfree (ptr_slot_num);
+		return chassis_str;
+		break;
+	case 1:
+		/* RXE */
+		*ptr_rxe_num = (char)(number + 48);
+		strcat (rxe_str, ptr_rxe_num);
+		kfree (ptr_rxe_num);
+		strcat (rxe_str, "slot");
+		ptr_slot_num = convert_2digits_to_char (slot_num - first_slot + 1);
+		strcat (rxe_str, ptr_slot_num);
+		kfree (ptr_slot_num);
+		return rxe_str;
+		break;
+	}	
+	return NULL;
+}
+
+static struct pci_driver ibmphp_driver;
 
 /*
  * map info (ctlr-id, slot count, slot#.. bus count, bus#, ctlr type...) of
  * each hpc from physical address to a list of hot plug controllers based on
  * hpc descriptors.
  */
-static int ebda_rsrc_controller (void)
+static int __init ebda_rsrc_controller (void)
 {
 	u16 addr, addr_slot, addr_bus;
 	u8 ctlr_id, temp, bus_index;
@@ -394,6 +818,9 @@
 	struct ebda_hpc_slot *slot_ptr;
 	struct bus_info *bus_info_ptr1, *bus_info_ptr2;
 	int rc;
+	int retval;
+	struct slot *slot_cur;
+	struct list_head *list;
 
 	addr = hpc_list_ptr->phys_addr;
 	for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) {
@@ -455,19 +882,9 @@
 				bus_info_ptr1->index = bus_index++;
 				bus_info_ptr1->current_speed = 0xff;
 				bus_info_ptr1->current_bus_mode = 0xff;
-				if ( ((slot_ptr->slot_cap) & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX )
-					bus_info_ptr1->supported_speed =  3;
-				else if ( ((slot_ptr->slot_cap) & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX )
-					bus_info_ptr1->supported_speed =  2;
-				else if ( ((slot_ptr->slot_cap) & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX )
-					bus_info_ptr1->supported_speed =  1;
+				
 				bus_info_ptr1->controller_id = hpc_ptr->ctlr_id;
-				if ( ((slot_ptr->slot_cap) & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP )
-					bus_info_ptr1->supported_bus_mode = 1;
-				else
-					bus_info_ptr1->supported_bus_mode =0;
-
-
+				
 				list_add_tail (&bus_info_ptr1->bus_info_list, &bus_info_head);
 
 			} else {
@@ -486,9 +903,25 @@
 		/* init bus structure */
 		bus_ptr = hpc_ptr->buses;
 		for (bus = 0; bus < bus_num; bus++) {
-			bus_ptr->bus_num = readb (io_mem + addr_bus);
+			bus_ptr->bus_num = readb (io_mem + addr_bus + bus);
+			bus_ptr->slots_at_33_conv = readb (io_mem + addr_bus + bus_num + 8 * bus);
+			bus_ptr->slots_at_66_conv = readb (io_mem + addr_bus + bus_num + 8 * bus + 1);
+
+			bus_ptr->slots_at_66_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 2);
+
+			bus_ptr->slots_at_100_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 3);
+
+			bus_ptr->slots_at_133_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 4);
+
+			bus_info_ptr2 = ibmphp_find_same_bus_num (bus_ptr->bus_num);
+			if (bus_info_ptr2) {
+				bus_info_ptr2->slots_at_33_conv = bus_ptr->slots_at_33_conv;
+				bus_info_ptr2->slots_at_66_conv = bus_ptr->slots_at_66_conv;
+				bus_info_ptr2->slots_at_66_pcix = bus_ptr->slots_at_66_pcix;
+				bus_info_ptr2->slots_at_100_pcix = bus_ptr->slots_at_100_pcix;
+				bus_info_ptr2->slots_at_133_pcix = bus_ptr->slots_at_133_pcix; 
+			}
 			bus_ptr++;
-			addr_bus += 1;
 		}
 
 		hpc_ptr->ctlr_type = temp;
@@ -498,27 +931,22 @@
 				hpc_ptr->u.pci_ctlr.bus = readb (io_mem + addr);
 				hpc_ptr->u.pci_ctlr.dev_fun = readb (io_mem + addr + 1);
 				hpc_ptr->irq = readb (io_mem + addr + 2);
-				addr += 3; 
+				addr += 3;
+				debug ("ctrl bus = %x, ctlr devfun = %x, irq = %x\n", hpc_ptr->u.pci_ctlr.bus, hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq);
 				break;
 
 			case 0:
 				hpc_ptr->u.isa_ctlr.io_start = readw (io_mem + addr);
 				hpc_ptr->u.isa_ctlr.io_end = readw (io_mem + addr + 2);
+				retval = check_region (hpc_ptr->u.isa_ctlr.io_start, (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1));
+				if (retval)
+					return -ENODEV;
+				request_region (hpc_ptr->u.isa_ctlr.io_start, (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1), "ibmphp");
 				hpc_ptr->irq = readb (io_mem + addr + 4);
 				addr += 5;
 				break;
 
 			case 2:
-				hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr);
-				hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4);
-				/* following 2 lines for testing purpose */
-				if (hpc_ptr->u.wpeg_ctlr.i2c_addr == 0) 
-					hpc_ptr->ctlr_type = 4;	
-				
-
-				hpc_ptr->irq = readb (io_mem + addr + 5);
-				addr += 6;
-				break;
 			case 4:
 				hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr);
 				hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4);
@@ -529,14 +957,14 @@
 				iounmap (io_mem);
 				return -ENODEV;
 		}
-		/* following 3 line: Now our driver only supports I2c ctlrType */
-		if ((hpc_ptr->ctlr_type != 2) && (hpc_ptr->ctlr_type != 4)) {
-			err ("Please run this driver on ibm xseries440\n ");
-			return -ENODEV;
-		}
 
+		//reorganize chassis' linked list
+		combine_wpg_for_chassis ();
+		combine_wpg_for_expansion ();
 		hpc_ptr->revision = 0xff;
 		hpc_ptr->options = 0xff;
+		hpc_ptr->starting_slot_num = hpc_ptr->slots[0].slot_num;
+		hpc_ptr->ending_slot_num = hpc_ptr->slots[slot_num-1].slot_num;
 
 		// register slots with hpc core as well as create linked list of ibm slot
 		for (index = 0; index < hpc_ptr->slot_count; index++) {
@@ -556,7 +984,7 @@
 			}
 			memset (hp_slot_ptr->info, 0, sizeof (struct hotplug_slot_info));
 
-			hp_slot_ptr->name = (char *) kmalloc (10, GFP_KERNEL);
+			hp_slot_ptr->name = (char *) kmalloc (30, GFP_KERNEL);
 			if (!hp_slot_ptr->name) {
 				iounmap (io_mem);
 				kfree (hp_slot_ptr->info);
@@ -574,9 +1002,21 @@
 			}
 
 			((struct slot *)hp_slot_ptr->private)->flag = TRUE;
-			snprintf (hp_slot_ptr->name, 10, "%d", hpc_ptr->slots[index].slot_num);
 
 			((struct slot *) hp_slot_ptr->private)->capabilities = hpc_ptr->slots[index].slot_cap;
+			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX)
+				((struct slot *) hp_slot_ptr->private)->supported_speed =  3;
+			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX)
+				((struct slot *) hp_slot_ptr->private)->supported_speed =  2;
+			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX)
+				((struct slot *) hp_slot_ptr->private)->supported_speed =  1;
+				
+			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP)
+				((struct slot *) hp_slot_ptr->private)->supported_bus_mode = 1;
+			else
+				((struct slot *) hp_slot_ptr->private)->supported_bus_mode = 0;
+
+
 			((struct slot *) hp_slot_ptr->private)->bus = hpc_ptr->slots[index].slot_bus_num;
 
 			bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num);
@@ -591,9 +1031,8 @@
 
 			((struct slot *) hp_slot_ptr->private)->ctlr_index = hpc_ptr->slots[index].ctl_index;
 			((struct slot *) hp_slot_ptr->private)->number = hpc_ptr->slots[index].slot_num;
-
+			
 			((struct slot *) hp_slot_ptr->private)->hotplug_slot = hp_slot_ptr;
-
 			rc = ibmphp_hpc_fillhpslotinfo (hp_slot_ptr);
 			if (rc) {
 				iounmap (io_mem);
@@ -607,8 +1046,6 @@
 			}
 			hp_slot_ptr->ops = &ibmphp_hotplug_slot_ops;
 
-			pci_hp_register (hp_slot_ptr);
-
 			// end of registering ibm slot with hotplug core
 
 			list_add (& ((struct slot *)(hp_slot_ptr->private))->ibm_slot_list, &ibmphp_slot_head);
@@ -618,7 +1055,20 @@
 		list_add (&hpc_ptr->ebda_hpc_list, &ebda_hpc_head );
 
 	}			/* each hpc  */
+
+	list_for_each (list, &ibmphp_slot_head) {
+		slot_cur = list_entry (list, struct slot, ibm_slot_list);
+
+		snprintf (slot_cur->hotplug_slot->name, 30, "%s", create_file_name (slot_cur));
+		if (chassis_str) 
+			kfree (chassis_str);
+		if (rxe_str)
+			kfree (rxe_str);
+		pci_hp_register (slot_cur->hotplug_slot);
+	}
+
 	print_ebda_hpc ();
+	print_ibm_slot ();
 	return 0;
 }
 
@@ -626,7 +1076,7 @@
  * map info (bus, devfun, start addr, end addr..) of i/o, memory,
  * pfm from the physical addr to a list of resource.
  */
-static int ebda_rsrc_rsrc (void)
+static int __init ebda_rsrc_rsrc (void)
 {
 	u16 addr;
 	short rsrc;
@@ -658,7 +1108,7 @@
 			addr += 6;
 
 			debug ("rsrc from io type ----\n");
-			debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %lx end addr: %lx\n",
+			debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
 				rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
 
 			list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
@@ -679,7 +1129,7 @@
 			addr += 10;
 
 			debug ("rsrc from mem or pfm ---\n");
-			debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %lx end addr: %lx\n", 
+			debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", 
 				rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
 
 			list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
@@ -691,56 +1141,6 @@
 	return 0;
 }
 
-/*
- * map info of scalability details and rio details from physical address
- */
-static int ebda_rio_table(void)
-{
-	u16 offset;
-	u8 i;
-	struct scal_detail *scal_detail_ptr;
-	struct rio_detail *rio_detail_ptr;
-
-	offset = rio_table_ptr->offset;
-	for (i = 0; i < rio_table_ptr->scal_count; i++) {
-		
-		scal_detail_ptr = kmalloc (sizeof (struct scal_detail), GFP_KERNEL );
-		if (!scal_detail_ptr )
-			return -ENOMEM;
-		memset (scal_detail_ptr, 0, sizeof (struct scal_detail) );
-		scal_detail_ptr->node_id = readb (io_mem + offset);
-		scal_detail_ptr->cbar = readl (io_mem+ offset + 1);
-		scal_detail_ptr->port0_node_connect = readb (io_mem + 5);
-		scal_detail_ptr->port0_port_connect = readb (io_mem + 6);
-		scal_detail_ptr->port1_node_connect = readb (io_mem + 7);
-		scal_detail_ptr->port1_port_connect = readb (io_mem + 8);
-		scal_detail_ptr->port2_node_connect = readb (io_mem + 9);
-		scal_detail_ptr->port2_port_connect = readb (io_mem + 10);
-		debug ("node_id: %x\ncbar: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nport2_node: %x\nport2_port: %x\n", scal_detail_ptr->node_id, scal_detail_ptr->cbar, scal_detail_ptr->port0_node_connect, scal_detail_ptr->port0_port_connect, scal_detail_ptr->port1_node_connect, scal_detail_ptr->port1_port_connect, scal_detail_ptr->port2_node_connect, scal_detail_ptr->port2_port_connect);
-//		list_add (&scal_detail_ptr->scal_detail_list, &scal_detail_head);
-		offset += 11;
-	}
-	for (i=0; i < rio_table_ptr->riodev_count; i++) {
-		rio_detail_ptr = kmalloc (sizeof (struct rio_detail), GFP_KERNEL );
-		if (!rio_detail_ptr )
-			return -ENOMEM;
-		memset (rio_detail_ptr, 0, sizeof (struct rio_detail) );
-		rio_detail_ptr->rio_node_id = readb (io_mem + offset );
-		rio_detail_ptr->bbar = readl (io_mem + offset + 1);
-		rio_detail_ptr->rio_type = readb (io_mem + offset + 5);
-		rio_detail_ptr->owner_id = readb (io_mem + offset + 6);
-		rio_detail_ptr->port0_node_connect = readb (io_mem + offset + 7);
-		rio_detail_ptr->port0_port_connect = readb (io_mem + offset + 8);
-		rio_detail_ptr->port1_node_connect = readb (io_mem + offset + 9);
-		rio_detail_ptr->port1_port_connect = readb (io_mem + offset + 10);
-		rio_detail_ptr->first_slot_num = readb (io_mem + offset + 11);
-		rio_detail_ptr->status = readb (io_mem + offset + 12);
-		debug ("rio_node_id: %x\nbbar: %x\nrio_type: %x\nowner_id: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nfirst_slot_num: %x\nstatus: %x\n", rio_detail_ptr->rio_node_id, rio_detail_ptr->bbar, rio_detail_ptr->rio_type, rio_detail_ptr->owner_id, rio_detail_ptr->port0_node_connect, rio_detail_ptr->port0_port_connect, rio_detail_ptr->port1_node_connect, rio_detail_ptr->port1_port_connect, rio_detail_ptr->first_slot_num, rio_detail_ptr->status);
-		offset += 13;
-	}
-	return 0;
-}
-
 u16 ibmphp_get_total_controllers (void)
 {
 	return hpc_list_ptr->num_ctlrs;
@@ -806,32 +1206,21 @@
 	}
 }
 
-/*
- * Calculate the total hot pluggable slots controlled by total hpcs
- */
-/*
-int ibmphp_get_total_hp_slots (void)
-{
-	struct ebda_hpc *ptr;
-	int slot_num = 0;
-
-	ptr = ebda_hpc_head;
-	while (ptr != NULL) {
-		slot_num += ptr->slot_count;
-		ptr = ptr->next;
-	}
-	return slot_num;
-}
-*/
-
 void ibmphp_free_ebda_hpc_queue (void)
 {
-	struct controller *controller;
+	struct controller *controller = NULL;
 	struct list_head *list;
 	struct list_head *next;
+	int pci_flag = 0;
 
 	list_for_each_safe (list, next, &ebda_hpc_head) {
 		controller = list_entry (list, struct controller, ebda_hpc_list);
+		if (controller->ctlr_type == 0)
+			release_region (controller->u.isa_ctlr.io_start, (controller->u.isa_ctlr.io_end - controller->u.isa_ctlr.io_start + 1));
+		else if ((controller->ctlr_type == 1) && (!pci_flag)) {
+			++pci_flag;
+			pci_unregister_driver (&ibmphp_driver);
+		}
 		free_ebda_hpc (controller);
 	}
 }
@@ -849,3 +1238,58 @@
 	}
 }
 
+static struct pci_device_id id_table[] __devinitdata = {
+	{
+		vendor:		PCI_VENDOR_ID_IBM,
+		device:		HPC_DEVICE_ID,
+		subvendor:	PCI_VENDOR_ID_IBM,
+		subdevice:	HPC_SUBSYSTEM_ID,
+		class:		((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00),
+	}, {}
+};		
+
+MODULE_DEVICE_TABLE(pci, id_table);
+
+static int ibmphp_probe (struct pci_dev *, const struct pci_device_id *);
+static struct pci_driver ibmphp_driver = {
+	name:		"ibmphp",
+	id_table:	id_table,
+	probe:		ibmphp_probe,
+};
+
+int ibmphp_register_pci (void)
+{
+	struct controller *ctrl;
+	struct list_head *tmp;
+	int rc = 0;
+
+	list_for_each (tmp, &ebda_hpc_head) {
+		ctrl = list_entry (tmp, struct controller, ebda_hpc_list);
+		if (ctrl->ctlr_type == 1) {
+			rc = pci_module_init (&ibmphp_driver);
+			break;
+		}
+	}
+	return rc;
+}
+static int ibmphp_probe (struct pci_dev * dev, const struct pci_device_id *ids)
+{
+	struct controller *ctrl;
+	struct list_head *tmp;
+
+	debug ("inside ibmphp_probe \n");
+	
+	list_for_each (tmp, &ebda_hpc_head) {
+		ctrl = list_entry (tmp, struct controller, ebda_hpc_list);
+		if (ctrl->ctlr_type == 1) {
+			if ((dev->devfn == ctrl->u.pci_ctlr.dev_fun) && (dev->bus->number == ctrl->u.pci_ctlr.bus)) {
+				ctrl->ctrl_dev = dev;
+				debug ("found device!!! \n");
+				debug ("dev->device = %x, dev->subsystem_device = %x\n", dev->device, dev->subsystem_device);
+				return 0;
+			}
+		}
+	}
+	return -ENODEV;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/ibmphp_hpc.c linux-2.4.20/drivers/hotplug/ibmphp_hpc.c
--- linux-2.4.19/drivers/hotplug/ibmphp_hpc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/ibmphp_hpc.c	2002-10-29 11:18:32.000000000 +0000
@@ -3,7 +3,7 @@
  *
  * Written By: Jyoti Shah, IBM Corporation
  *
- * Copyright (c) 2001,2001 IBM Corp.
+ * Copyright (c) 2001-2002 IBM Corp.
  *
  * All rights reserved.
  *
@@ -27,17 +27,14 @@
  *
  */
 
-//#include <linux/delay.h>
 #include <linux/wait.h>
 #include <linux/time.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/smp_lock.h>
+#include <linux/init.h>
 #include "ibmphp.h"
 
-#define POLL_NO		0x01
-#define POLL_YES	0x00
-
 static int to_debug = FALSE;
 #define debug_polling(fmt, arg...)	do { if (to_debug) debug (fmt, arg); } while (0)
 
@@ -83,10 +80,6 @@
 //
 //----------------------------------------------------------------------------
 #define WPG_I2C_IOREMAP_SIZE	0x2044	// size of linear address interval
-#define WPG_CTLR_MAX		0x01	// max controllers
-#define WPG_SLOT_MAX		0x06	// max slots
-#define WPG_CTLR_SLOT_MAX	0x06	// max slots per controller
-#define WPG_FIRST_CTLR		0x00	// index of the controller
 
 //----------------------------------------------------------------------------
 // command index
@@ -102,24 +95,20 @@
 // if bits 20,22,25,26,27,29,30 are OFF return TRUE
 #define HPC_I2CSTATUS_CHECK(s)	((u8)((s & 0x00000A76) ? FALSE : TRUE))
 
-// return code 0:poll slots, 1-POLL_LATCH_CNT:poll latch register
-#define INCREMENT_POLLCNT(i)	((i < POLL_LATCH_CNT) ? i++ : (i=0))
 //----------------------------------------------------------------------------
 // global variables
 //----------------------------------------------------------------------------
 static int ibmphp_shutdown;
 static int tid_poll;
-static int stop_polling;		// 2 values: poll, don't poll
 static struct semaphore sem_hpcaccess;	// lock access to HPC
 static struct semaphore semOperations;	// lock all operations and
 					// access to data structures
 static struct semaphore sem_exit;	// make sure polling thread goes away
-static struct semaphore sem_poll;	// make sure poll is idle 
 //----------------------------------------------------------------------------
 // local function prototypes
 //----------------------------------------------------------------------------
-static u8 ctrl_read (struct controller *, void *, u8);
-static u8 ctrl_write (struct controller *, void *, u8, u8);
+static u8 i2c_ctrl_read (struct controller *, void *, u8);
+static u8 i2c_ctrl_write (struct controller *, void *, u8, u8);
 static u8 hpc_writecmdtoindex (u8, u8);
 static u8 hpc_readcmdtoindex (u8, u8);
 static void get_hpc_access (void);
@@ -127,7 +116,7 @@
 static void poll_hpc (void);
 static int update_slot (struct slot *, u8);
 static int process_changeinstatus (struct slot *, struct slot *);
-static int process_changeinlatch (u8, u8);
+static int process_changeinlatch (u8, u8, struct controller *);
 static int hpc_poll_thread (void *);
 static int hpc_wait_ctlr_notworking (int, struct controller *, void *, u8 *);
 //----------------------------------------------------------------------------
@@ -138,15 +127,13 @@
 *
 * Action:  initialize semaphores and variables
 *---------------------------------------------------------------------*/
-void ibmphp_hpc_initvars (void)
+void __init ibmphp_hpc_initvars (void)
 {
 	debug ("%s - Entry\n", __FUNCTION__);
 
 	init_MUTEX (&sem_hpcaccess);
 	init_MUTEX (&semOperations);
 	init_MUTEX_LOCKED (&sem_exit);
-	init_MUTEX_LOCKED (&sem_poll);
-	stop_polling = POLL_YES;
 	to_debug = FALSE;
 	ibmphp_shutdown = FALSE;
 	tid_poll = 0;
@@ -155,12 +142,12 @@
 }
 
 /*----------------------------------------------------------------------
-* Name:    ctrl_read
+* Name:    i2c_ctrl_read
 *
 * Action:  read from HPC over I2C
 *
 *---------------------------------------------------------------------*/
-static u8 ctrl_read (struct controller *ctlr_ptr, void *WPGBbar, u8 index)
+static u8 i2c_ctrl_read (struct controller *ctlr_ptr, void *WPGBbar, u8 index)
 {
 	u8 status;
 	int i;
@@ -262,13 +249,13 @@
 }
 
 /*----------------------------------------------------------------------
-* Name:    ctrl_write
+* Name:    i2c_ctrl_write
 *
 * Action:  write to HPC over I2C
 *
 * Return   0 or error codes
 *---------------------------------------------------------------------*/
-static u8 ctrl_write (struct controller *ctlr_ptr, void *WPGBbar, u8 index, u8 cmd)
+static u8 i2c_ctrl_write (struct controller *ctlr_ptr, void *WPGBbar, u8 index, u8 cmd)
 {
 	u8 rc;
 	void *wpg_addr;		// base addr + offset
@@ -277,8 +264,7 @@
 	int i;
 
 
-	debug_polling ("%s - Entry WPGBbar[%lx] index[%x] cmd[%x]\n",
-		       __FUNCTION__, (ulong) WPGBbar, index, cmd);
+	debug_polling ("%s - Entry WPGBbar[%lx] index[%x] cmd[%x]\n", __FUNCTION__, (ulong) WPGBbar, index, cmd);
 
 	rc = 0;
 	//--------------------------------------------------------------------
@@ -365,6 +351,93 @@
 	return (rc);
 }
 
+//------------------------------------------------------------
+//  Read from ISA type HPC 
+//------------------------------------------------------------
+static u8 isa_ctrl_read (struct controller *ctlr_ptr, u8 offset)
+{
+	u16 start_address;
+	u16 end_address;
+	u8 data;
+
+	start_address = ctlr_ptr->u.isa_ctlr.io_start;
+	end_address = ctlr_ptr->u.isa_ctlr.io_end;
+	data = inb (start_address + offset);
+	return data;
+}
+
+//--------------------------------------------------------------
+// Write to ISA type HPC
+//--------------------------------------------------------------
+static void isa_ctrl_write (struct controller *ctlr_ptr, u8 offset, u8 data)
+{
+	u16 start_address;
+	u16 port_address;
+	
+	start_address = ctlr_ptr->u.isa_ctlr.io_start;
+	port_address = start_address + (u16) offset;
+	outb (data, port_address);
+}
+
+static u8 pci_ctrl_read (struct controller *ctrl, u8 offset)
+{
+	u8 data = 0x00;
+	debug ("inside pci_ctrl_read\n");
+	if (ctrl->ctrl_dev)
+		pci_read_config_byte (ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, &data);
+	return data;
+}
+
+static u8 pci_ctrl_write (struct controller *ctrl, u8 offset, u8 data)
+{
+	u8 rc = -ENODEV;
+	debug ("inside pci_ctrl_write\n");
+	if (ctrl->ctrl_dev) {
+		pci_write_config_byte (ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, data);
+		rc = 0;
+	}
+	return rc;
+}
+
+static u8 ctrl_read (struct controller *ctlr, void *base, u8 offset)
+{
+	u8 rc;
+	switch (ctlr->ctlr_type) {
+	case 0:
+		rc = isa_ctrl_read (ctlr, offset);
+		break;
+	case 1:
+		rc = pci_ctrl_read (ctlr, offset);
+		break;
+	case 2:
+	case 4:
+		rc = i2c_ctrl_read (ctlr, base, offset);
+		break;
+	default:
+		return -ENODEV;
+	}
+	return rc;
+}
+
+static u8 ctrl_write (struct controller *ctlr, void *base, u8 offset, u8 data)
+{
+	u8 rc = 0;
+	switch (ctlr->ctlr_type) {
+	case 0:
+		isa_ctrl_write(ctlr, offset, data);
+		break;
+	case 1:
+		rc = pci_ctrl_write (ctlr, offset, data);
+		break;
+	case 2:
+	case 4:
+		rc = i2c_ctrl_write(ctlr, base, offset, data);
+		break;
+	default:
+		return -ENODEV;
+	}
+	return rc;
+}
 /*----------------------------------------------------------------------
 * Name:    hpc_writecmdtoindex()
 *
@@ -463,15 +536,14 @@
 *---------------------------------------------------------------------*/
 int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus)
 {
-	void *wpg_bbar;
+	void *wpg_bbar = NULL;
 	struct controller *ctlr_ptr;
 	struct list_head *pslotlist;
 	u8 index, status;
 	int rc = 0;
 	int busindex;
 
-	debug_polling ("%s - Entry pslot[%lx] cmd[%x] pstatus[%lx]\n",
-		       __FUNCTION__, (ulong) pslot, cmd, (ulong) pstatus);
+	debug_polling ("%s - Entry pslot[%lx] cmd[%x] pstatus[%lx]\n", __FUNCTION__, (ulong) pslot, cmd, (ulong) pstatus);
 
 	if ((pslot == NULL)
 	    || ((pstatus == NULL) && (cmd != READ_ALLSTAT) && (cmd != READ_BUSSTATUS))) {
@@ -506,7 +578,8 @@
 	//--------------------------------------------------------------------
 	// map physical address to logical address
 	//--------------------------------------------------------------------
-	wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE);
+	if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4))
+		wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE);
 
 	//--------------------------------------------------------------------
 	// check controller status before reading
@@ -584,7 +657,11 @@
 	//--------------------------------------------------------------------
 	// cleanup
 	//--------------------------------------------------------------------
-	iounmap (wpg_bbar);	// remove physical to logical address mapping
+	
+	// remove physical to logical address mapping
+	if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4))
+		iounmap (wpg_bbar);	
+	
 	free_hpc_access ();
 
 	debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc);
@@ -598,7 +675,7 @@
 *---------------------------------------------------------------------*/
 int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd)
 {
-	void *wpg_bbar;
+	void *wpg_bbar = NULL;
 	struct controller *ctlr_ptr;
 	u8 index, status;
 	int busindex;
@@ -641,12 +718,13 @@
 	//--------------------------------------------------------------------
 	// map physical address to logical address
 	//--------------------------------------------------------------------
-	wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE);
+	if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) {
+		wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE);
 
-	debug ("%s - ctlr id[%x] physical[%lx] logical[%lx] i2c[%x]\n", __FUNCTION__,
+		debug ("%s - ctlr id[%x] physical[%lx] logical[%lx] i2c[%x]\n", __FUNCTION__,
 		ctlr_ptr->ctlr_id, (ulong) (ctlr_ptr->u.wpeg_ctlr.wpegbbar), (ulong) wpg_bbar,
 		ctlr_ptr->u.wpeg_ctlr.i2c_addr);
-
+	}
 	//--------------------------------------------------------------------
 	// check controller status before writing
 	//--------------------------------------------------------------------
@@ -683,7 +761,10 @@
 		ctlr_ptr->status = status;
 	}
 	// cleanup
-	iounmap (wpg_bbar);	// remove physical to logical address mapping
+
+	// remove physical to logical address mapping
+	if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4))
+		iounmap (wpg_bbar);	
 	free_hpc_access ();
 
 	debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc);
@@ -716,11 +797,7 @@
 void ibmphp_lock_operations (void)
 {
 	down (&semOperations);
-	stop_polling = POLL_NO;
 	to_debug = TRUE;
-
-	/* waiting for polling to actually stop */
-	down (&sem_poll);
 }
 
 /*----------------------------------------------------------------------
@@ -729,99 +806,114 @@
 void ibmphp_unlock_operations (void)
 {
 	debug ("%s - Entry\n", __FUNCTION__);
-	stop_polling = POLL_YES;
-	to_debug = FALSE;
 	up (&semOperations);
+	to_debug = FALSE;
 	debug ("%s - Exit\n", __FUNCTION__);
 }
 
 /*----------------------------------------------------------------------
 * Name:    poll_hpc()
 *---------------------------------------------------------------------*/
+#define POLL_LATCH_REGISTER	0
+#define POLL_SLOTS		1
+#define POLL_SLEEP		2
 static void poll_hpc (void)
 {
-	struct slot myslot, *pslot = NULL;
+	struct slot myslot;
+	struct slot *pslot = NULL;
 	struct list_head *pslotlist;
 	int rc;
+	int poll_state = POLL_LATCH_REGISTER;
 	u8 oldlatchlow = 0x00;
 	u8 curlatchlow = 0x00;
-	int pollcnt = 0;
+	int poll_count = 0;
 	u8 ctrl_count = 0x00;
 
-	debug ("poll_hpc - Entry\n");
+	debug ("%s - Entry\n", __FUNCTION__);
 
 	while (!ibmphp_shutdown) {
-		if (stop_polling) {
-			debug ("poll_hpc - stop_polling\n");
-			up (&sem_poll); 
-			/* to prevent deadlock */
-			if (ibmphp_shutdown)
-				break;
-			/* to make the thread sleep */
-			down (&semOperations);
-			up (&semOperations);
-			debug ("poll_hpc - after stop_polling sleep\n");
-		} else {
-			if (pollcnt) {
-				// only poll the latch register
-				oldlatchlow = curlatchlow;
-
-				ctrl_count = 0x00;
-				list_for_each (pslotlist, &ibmphp_slot_head) {
-					if (ctrl_count >= ibmphp_get_total_controllers())
-						break;
-					pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
-					if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
-						ctrl_count++;
-						if (READ_SLOT_LATCH (pslot->ctrl)) {
-							rc = ibmphp_hpc_readslot (pslot,
-										  READ_SLOTLATCHLOWREG,
-										  &curlatchlow);
-							if (oldlatchlow != curlatchlow)
-								process_changeinlatch (oldlatchlow,
-											curlatchlow);
-						}
+		if (ibmphp_shutdown) 
+			break;
+		
+		/* try to get the lock to do some kind of harware access */
+		down (&semOperations);
+
+		switch (poll_state) {
+		case POLL_LATCH_REGISTER: 
+			oldlatchlow = curlatchlow;
+			ctrl_count = 0x00;
+			list_for_each (pslotlist, &ibmphp_slot_head) {
+				if (ctrl_count >= ibmphp_get_total_controllers())
+					break;
+				pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
+				if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
+					ctrl_count++;
+					if (READ_SLOT_LATCH (pslot->ctrl)) {
+						rc = ibmphp_hpc_readslot (pslot,
+									  READ_SLOTLATCHLOWREG,
+									  &curlatchlow);
+						if (oldlatchlow != curlatchlow)
+							process_changeinlatch (oldlatchlow,
+									       curlatchlow,
+									       pslot->ctrl);
 					}
 				}
-			} else {
-				list_for_each (pslotlist, &ibmphp_slot_head) {
-					if (stop_polling)
-						break;
-					pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
-					// make a copy of the old status
-					memcpy ((void *) &myslot, (void *) pslot,
-						sizeof (struct slot));
-					rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL);
-					if ((myslot.status != pslot->status)
-					    || (myslot.ext_status != pslot->ext_status))
-						process_changeinstatus (pslot, &myslot);
-				}
-
-				if (!stop_polling) {
-					ctrl_count = 0x00;
-					list_for_each (pslotlist, &ibmphp_slot_head) {
-						if (ctrl_count >= ibmphp_get_total_controllers())
-							break;
-						pslot =
-						    list_entry (pslotlist, struct slot,
-								ibm_slot_list);
-						if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
-							ctrl_count++;
-							if (READ_SLOT_LATCH (pslot->ctrl))
-								rc = ibmphp_hpc_readslot (pslot,
-											  READ_SLOTLATCHLOWREG,
-											  &curlatchlow);
-						}
-					}
+			}
+			++poll_count;
+			poll_state = POLL_SLEEP;
+			break;
+		case POLL_SLOTS:
+			list_for_each (pslotlist, &ibmphp_slot_head) {
+				pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
+				// make a copy of the old status
+				memcpy ((void *) &myslot, (void *) pslot,
+					sizeof (struct slot));
+				rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL);
+				if ((myslot.status != pslot->status)
+				    || (myslot.ext_status != pslot->ext_status))
+					process_changeinstatus (pslot, &myslot);
+			}
+			ctrl_count = 0x00;
+			list_for_each (pslotlist, &ibmphp_slot_head) {
+				if (ctrl_count >= ibmphp_get_total_controllers())
+					break;
+				pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
+				if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
+					ctrl_count++;
+					if (READ_SLOT_LATCH (pslot->ctrl))
+						rc = ibmphp_hpc_readslot (pslot,
+									  READ_SLOTLATCHLOWREG,
+									  &curlatchlow);
 				}
 			}
-			INCREMENT_POLLCNT (pollcnt);
-			long_delay (POLL_INTERVAL_SEC * HZ);	// snooze
-		}
+			++poll_count;
+			poll_state = POLL_SLEEP;
+			break;
+		case POLL_SLEEP:
+			/* don't sleep with a lock on the hardware */
+			up (&semOperations);
+			long_delay (POLL_INTERVAL_SEC * HZ);
+
+			if (ibmphp_shutdown) 
+				break;
+			
+			down (&semOperations);
+			
+			if (poll_count >= POLL_LATCH_CNT) {
+				poll_count = 0;
+				poll_state = POLL_SLOTS;
+			} else
+				poll_state = POLL_LATCH_REGISTER;
+			break;
+		}	
+		/* give up the harware semaphore */
+		up (&semOperations);
+		/* sleep for a short time just for good measure */
+		set_current_state (TASK_INTERRUPTIBLE);
+		schedule_timeout (HZ/10);
 	}
-	up (&sem_poll);
 	up (&sem_exit);
-	debug ("poll_hpc - Exit\n");
+	debug ("%s - Exit\n", __FUNCTION__);
 }
 
 
@@ -917,7 +1009,6 @@
 
 	// bit 0 - HPC_SLOT_POWER
 	if ((pslot->status & 0x01) != (poldslot->status & 0x01))
-		/* ????????? DO WE NEED TO UPDATE BUS SPEED INFO HERE ??? */
 		update = TRUE;
 
 	// bit 1 - HPC_SLOT_CONNECT
@@ -936,7 +1027,7 @@
 	// bit 5 - HPC_SLOT_PWRGD
 	if ((pslot->status & 0x20) != (poldslot->status & 0x20))
 		// OFF -> ON: ignore, ON -> OFF: disable slot
-		if (poldslot->status & 0x20)
+		if ((poldslot->status & 0x20) && (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) 
 			disable = TRUE;
 
 	// bit 6 - HPC_SLOT_BUS_SPEED
@@ -947,20 +1038,20 @@
 		update = TRUE;
 		// OPEN -> CLOSE
 		if (pslot->status & 0x80) {
-			if (SLOT_POWER (pslot->status)) {
+			if (SLOT_PWRGD (pslot->status)) {
 				// power goes on and off after closing latch
 				// check again to make sure power is still ON
 				long_delay (1 * HZ);
 				rc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &status);
-				if (SLOT_POWER (status))
+				if (SLOT_PWRGD (status))
 					update = TRUE;
 				else	// overwrite power in pslot to OFF
 					pslot->status &= ~HPC_SLOT_POWER;
 			}
 		}
 		// CLOSE -> OPEN 
-		else if ((SLOT_POWER (poldslot->status) == HPC_SLOT_POWER_ON)
-			|| (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED)) {
+		else if ((SLOT_PWRGD (poldslot->status) == HPC_SLOT_PWRGD_GOOD)
+			&& (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) {
 			disable = TRUE;
 		}
 		// else - ignore
@@ -994,7 +1085,7 @@
 * Return   0 or error codes
 * Value:
 *---------------------------------------------------------------------*/
-static int process_changeinlatch (u8 old, u8 new)
+static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl)
 {
 	struct slot myslot, *pslot;
 	u8 i;
@@ -1004,7 +1095,7 @@
 	debug ("%s - Entry old[%x], new[%x]\n", __FUNCTION__, old, new);
 	// bit 0 reserved, 0 is LSB, check bit 1-6 for 6 slots
 
-	for (i = 1; i <= 6; i++) {
+	for (i = ctrl->starting_slot_num; i <= ctrl->ending_slot_num; i++) {
 		mask = 0x01 << i;
 		if ((mask & old) != (mask & new)) {
 			pslot = ibmphp_get_slot_from_physical_num (i);
@@ -1056,19 +1147,19 @@
 *
 * Action:  start polling thread
 *---------------------------------------------------------------------*/
-int ibmphp_hpc_start_poll_thread (void)
+int __init ibmphp_hpc_start_poll_thread (void)
 {
 	int rc = 0;
 
-	debug ("ibmphp_hpc_start_poll_thread - Entry\n");
+	debug ("%s - Entry\n", __FUNCTION__);
 
 	tid_poll = kernel_thread (hpc_poll_thread, 0, 0);
 	if (tid_poll < 0) {
-		err ("ibmphp_hpc_start_poll_thread - Error, thread not started\n");
+		err ("%s - Error, thread not started\n", __FUNCTION__);
 		rc = -1;
 	}
 
-	debug ("ibmphp_hpc_start_poll_thread - Exit tid_poll[%d] rc[%d]\n", tid_poll, rc);
+	debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc);
 	return rc;
 }
 
@@ -1077,23 +1168,30 @@
 *
 * Action:  stop polling thread and cleanup
 *---------------------------------------------------------------------*/
-void ibmphp_hpc_stop_poll_thread (void)
+void __exit ibmphp_hpc_stop_poll_thread (void)
 {
-	debug ("ibmphp_hpc_stop_poll_thread - Entry\n");
+	debug ("%s - Entry\n", __FUNCTION__);
 
 	ibmphp_shutdown = TRUE;
+	debug ("before locking operations \n");
 	ibmphp_lock_operations ();
-
+	debug ("after locking operations \n");
+	
 	// wait for poll thread to exit
+	debug ("before sem_exit down \n");
 	down (&sem_exit);
+	debug ("after sem_exit down \n");
 
 	// cleanup
+	debug ("before free_hpc_access \n");
 	free_hpc_access ();
+	debug ("after free_hpc_access \n");
 	ibmphp_unlock_operations ();
-	up (&sem_poll);
+	debug ("after unlock operations \n");
 	up (&sem_exit);
+	debug ("after sem exit up\n");
 
-	debug ("ibmphp_hpc_stop_poll_thread - Exit\n");
+	debug ("%s - Exit\n", __FUNCTION__);
 }
 
 /*----------------------------------------------------------------------
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/ibmphp_pci.c linux-2.4.20/drivers/hotplug/ibmphp_pci.c
--- linux-2.4.19/drivers/hotplug/ibmphp_pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/ibmphp_pci.c	2002-10-29 11:18:39.000000000 +0000
@@ -920,16 +920,30 @@
 	debug ("flag_io = %x, flag_mem = %x, flag_pfmem = %x\n", flag_io, flag_mem, flag_pfmem);
 
 	if (flag_io && flag_mem && flag_pfmem) {
-		bus = kmalloc (sizeof (struct bus_node), GFP_KERNEL);
+		/* If on bootup, there was a bridged card in this slot,
+		 * then card was removed and ibmphp got unloaded and loaded
+		 * back again, there's no way for us to remove the bus
+		 * struct, so no need to kmalloc, can use existing node
+		 */
+		bus = ibmphp_find_res_bus (sec_number);
 		if (!bus) {
-			err ("out of system memory \n");
-			retval = -ENOMEM;
+			bus = kmalloc (sizeof (struct bus_node), GFP_KERNEL);
+			if (!bus) {
+				err ("out of system memory \n");
+				retval = -ENOMEM;
+				goto error;
+			}
+			memset (bus, 0, sizeof (struct bus_node));
+			bus->busno = sec_number;
+			debug ("b4 adding new bus\n");
+			rc = add_new_bus (bus, io, mem, pfmem, func->busno);
+		} else if (!(bus->rangeIO) && !(bus->rangeMem) && !(bus->rangePFMem))
+			rc = add_new_bus (bus, io, mem, pfmem, 0xFF);
+		else {
+			err ("expected bus structure not empty? \n");
+			retval = -EIO;
 			goto error;
 		}
-		memset (bus, 0, sizeof (struct bus_node));
-		bus->busno = sec_number;
-		debug ("b4 adding new bus\n");
-		rc = add_new_bus (bus, io, mem, pfmem, func->busno);
 		if (rc) {
 			if (rc == -ENOMEM) {
 				ibmphp_remove_bus (bus, func->busno);
@@ -1579,7 +1593,6 @@
 	}
 
 	if (sl->func) {
-		debug ("do we come in here? \n");
 		cur_func = sl->func;
 		while (cur_func) {
 			/* TO DO: WILL MOST LIKELY NEED TO GET RID OF THE BUS STRUCTURE FROM RESOURCES AS WELL */
@@ -1619,6 +1632,7 @@
 
 	sl->func = NULL;
 	*slot_cur = sl;
+	debug ("%s - exit\n", __FUNCTION__);
 	return 0;
 }
 
@@ -1638,14 +1652,15 @@
 	struct bus_node *cur_bus = NULL;
 
 	/* Trying to find the parent bus number */
-	cur_bus	= ibmphp_find_res_bus (parent_busno);
-	if (!cur_bus) {
-		err ("strange, cannot find bus which is supposed to be at the system... something is terribly wrong...\n");
-		return -ENODEV;
+	if (parent_busno != 0xFF) {
+		cur_bus	= ibmphp_find_res_bus (parent_busno);
+		if (!cur_bus) {
+			err ("strange, cannot find bus which is supposed to be at the system... something is terribly wrong...\n");
+			return -ENODEV;
+		}
+	
+		list_add (&bus->bus_list, &cur_bus->bus_list);
 	}
-
-	list_add (&bus->bus_list, &cur_bus->bus_list);
-
 	if (io) {
 		io_range = kmalloc (sizeof (struct range_node), GFP_KERNEL);
 		if (!io_range) {
@@ -1698,6 +1713,7 @@
 	int min, max;
 	u8 busno;
 	struct bus_info *bus;
+	struct bus_node *bus_cur;
 
 	bus = ibmphp_find_same_bus_num (primary_busno);
 	if (!bus) {
@@ -1712,7 +1728,12 @@
 	}
 	busno = (u8) (slotno - (u8) min);
 	busno += primary_busno + 0x01;
-	if (!ibmphp_find_res_bus (busno))
+	bus_cur = ibmphp_find_res_bus (busno);
+	/* either there is no such bus number, or there are no ranges, which
+	 * can only happen if we removed the bridged device in previous load
+	 * of the driver, and now only have the skeleton bus struct
+	 */
+	if ((!bus_cur) || (!(bus_cur->rangeIO) && !(bus_cur->rangeMem) && !(bus_cur->rangePFMem)))
 		return busno;
 	return 0xff;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/ibmphp_res.c linux-2.4.20/drivers/hotplug/ibmphp_res.c
--- linux-2.4.19/drivers/hotplug/ibmphp_res.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/ibmphp_res.c	2002-10-29 11:18:50.000000000 +0000
@@ -31,6 +31,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/list.h>
+#include <linux/init.h>
 #include "ibmphp.h"
 
 static int flags = 0;		/* for testing */
@@ -44,11 +45,17 @@
 static inline struct bus_node *find_bus_wprev (u8, struct bus_node **, u8);
 
 static LIST_HEAD(gbuses);
+LIST_HEAD(ibmphp_res_head);
 
-static struct bus_node * alloc_error_bus (struct ebda_pci_rsrc * curr)
+static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr, u8 busno, int flag)
 {
 	struct bus_node * newbus;
 
+	if (!(curr) && !(flag)) {
+		err ("NULL pointer passed \n");
+		return NULL;
+	}
+
 	newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL);
 	if (!newbus) {
 		err ("out of system memory \n");
@@ -56,14 +63,24 @@
 	}
 
 	memset (newbus, 0, sizeof (struct bus_node));
-	newbus->busno = curr->bus_num;
+	if (flag)
+		newbus->busno = busno;
+	else
+		newbus->busno = curr->bus_num;
 	list_add_tail (&newbus->bus_list, &gbuses);
 	return newbus;
 }
 
-static struct resource_node * alloc_resources (struct ebda_pci_rsrc * curr)
+static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc * curr)
 {
-	struct resource_node *rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+	struct resource_node *rs;
+	
+	if (!curr) {
+		err ("NULL passed to allocate \n");
+		return NULL;
+	}
+
+	rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
 	if (!rs) {
 		err ("out of system memory \n");
 		return NULL;
@@ -77,7 +94,7 @@
 	return rs;
 }
 
-static int alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus)
+static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus)
 {
 	struct bus_node * newbus;
 	struct range_node *newrange;
@@ -184,7 +201,7 @@
  * Input: ptr to the head of the resource list from EBDA
  * Output: 0, -1 or error codes
  ***************************************************************************/
-int ibmphp_rsrc_init (void)
+int __init ibmphp_rsrc_init (void)
 {
 	struct ebda_pci_rsrc *curr;
 	struct range_node *newrange = NULL;
@@ -298,7 +315,7 @@
 				 * actually appears...
 				 */
 				if (ibmphp_add_resource (new_mem) < 0) {
-					newbus = alloc_error_bus (curr);
+					newbus = alloc_error_bus (curr, 0, 0);
 					if (!newbus)
 						return -ENOMEM;
 					newbus->firstMem = new_mem;
@@ -315,7 +332,7 @@
 				new_pfmem->type = PFMEM;
 				new_pfmem->fromMem = FALSE;
 				if (ibmphp_add_resource (new_pfmem) < 0) {
-					newbus = alloc_error_bus (curr);
+					newbus = alloc_error_bus (curr, 0, 0);
 					if (!newbus)
 						return -ENOMEM;
 					newbus->firstPFMem = new_pfmem;
@@ -339,7 +356,7 @@
 				 * range actually appears...
 				 */
 				if (ibmphp_add_resource (new_io) < 0) {
-					newbus = alloc_error_bus (curr);
+					newbus = alloc_error_bus (curr, 0, 0);
 					if (!newbus)
 						return -ENOMEM;
 					newbus->firstIO = new_io;
@@ -351,8 +368,6 @@
 		}
 	}
 
-	debug ("after the while loop in rsrc_init \n");
-
 	list_for_each (tmp, &gbuses) {
 		bus_cur = list_entry (tmp, struct bus_node, bus_list);
 		/* This is to get info about PPB resources, since EBDA doesn't put this info into the primary bus info */
@@ -360,11 +375,9 @@
 		if (rc)
 			return rc;
 	}
-	debug ("b4 once_over in rsrc_init \n");
 	rc = once_over ();  /* This is to align ranges (so no -1) */
 	if (rc)
 		return rc;
-	debug ("after once_over in rsrc_init \n");
 	return 0;
 }
 
@@ -579,7 +592,7 @@
  * based on their resource type and sorted by their starting addresses.  It assigns
  * the ptrs to next and nextRange if needed.
  *
- * Input: 3 diff. resources (nulled out if not needed)
+ * Input: resource ptr
  * Output: ptrs assigned (to the node)
  * 0 or -1
  *******************************************************************************/
@@ -592,12 +605,17 @@
 	struct resource_node *res_start = NULL;
 
 	debug ("%s - enter\n", __FUNCTION__);
+
+	if (!res) {
+		err ("NULL passed to add \n");
+		return -ENODEV;
+	}
 	
 	bus_cur = find_bus_wprev (res->busno, NULL, 0);
 	
 	if (!bus_cur) {
 		/* didn't find a bus, smth's wrong!!! */
-		err ("no bus in the system, either pci_dev's wrong or allocation failed\n");
+		debug ("no bus in the system, either pci_dev's wrong or allocation failed\n");
 		return -ENODEV;
 	}
 
@@ -768,6 +786,11 @@
 	struct resource_node *mem_cur;
 	char * type = "";
 
+	if (!res)  {
+		err ("resource to remove is NULL \n");
+		return -ENODEV;
+	}
+
 	bus_cur = find_bus_wprev (res->busno, NULL, 0);
 
 	if (!bus_cur) {
@@ -796,7 +819,6 @@
 	res_prev = NULL;
 
 	while (res_cur) {
-		/* ???????????DO WE _NEED_ TO BE CHECKING FOR END AS WELL?????????? */
 		if ((res_cur->start == res->start) && (res_cur->end == res->end))
 			break;
 		res_prev = res_cur;
@@ -980,7 +1002,7 @@
 
 	if (!bus_cur) {
 		/* didn't find a bus, smth's wrong!!! */
-		err ("no bus in the system, either pci_dev's wrong or allocation failed \n");
+		debug ("no bus in the system, either pci_dev's wrong or allocation failed \n");
 		return -EINVAL;
 	}
 
@@ -1339,7 +1361,7 @@
 	prev_bus = find_bus_wprev (parent_busno, NULL, 0);	
 
 	if (!prev_bus) {
-		err ("something terribly wrong. Cannot find parent bus to the one to remove\n");
+		debug ("something terribly wrong. Cannot find parent bus to the one to remove\n");
 		return -ENODEV;
 	}
 
@@ -1466,13 +1488,18 @@
 
 /*
  * find the resource node in the bus 
- * Input: Resource needed, start address of the resource, type or resource
+ * Input: Resource needed, start address of the resource, type of resource
  */
 int ibmphp_find_resource (struct bus_node *bus, u32 start_address, struct resource_node **res, int flag)
 {
 	struct resource_node *res_cur = NULL;
 	char * type = "";
 
+	if (!bus) {
+		err ("The bus passed in NULL to find resource \n");
+		return -ENODEV;
+	}
+
 	switch (flag) {
 		case IO:
 			res_cur = bus->firstIO;
@@ -1513,11 +1540,11 @@
 				res_cur = res_cur->next;
 			}
 			if (!res_cur) {
-				err ("SOS...cannot find %s resource in the bus. \n", type);
+				debug ("SOS...cannot find %s resource in the bus. \n", type);
 				return -EINVAL;
 			}
 		} else {
-			err ("SOS... cannot find %s resource in the bus. \n", type);
+			debug ("SOS... cannot find %s resource in the bus. \n", type);
 			return -EINVAL;
 		}
 	}
@@ -1650,7 +1677,7 @@
  * a new Mem node
  * This routine is called right after initialization
  *******************************************************************************/
-static int once_over (void)
+static int __init once_over (void)
 {
 	struct resource_node *pfmem_cur;
 	struct resource_node *pfmem_prev;
@@ -1755,6 +1782,8 @@
 	struct range_node *range;
 	struct resource_node *res;
 	struct list_head *tmp;
+	
+	debug_pci ("*****************START**********************\n");
 
 	if ((!list_empty(&gbuses)) && flags) {
 		err ("The GBUSES is not NULL?!?!?!?!?\n");
@@ -1763,50 +1792,50 @@
 
 	list_for_each (tmp, &gbuses) {
 		bus_cur = list_entry (tmp, struct bus_node, bus_list);
-		debug ("This is bus # %d.  There are \n", bus_cur->busno);
-		debug ("IORanges = %d\t", bus_cur->noIORanges);
-		debug ("MemRanges = %d\t", bus_cur->noMemRanges);
-		debug ("PFMemRanges = %d\n", bus_cur->noPFMemRanges);
-		debug ("The IO Ranges are as follows:\n");
+		debug_pci ("This is bus # %d.  There are \n", bus_cur->busno);
+		debug_pci ("IORanges = %d\t", bus_cur->noIORanges);
+		debug_pci ("MemRanges = %d\t", bus_cur->noMemRanges);
+		debug_pci ("PFMemRanges = %d\n", bus_cur->noPFMemRanges);
+		debug_pci ("The IO Ranges are as follows:\n");
 		if (bus_cur->rangeIO) {
 			range = bus_cur->rangeIO;
 			for (i = 0; i < bus_cur->noIORanges; i++) {
-				debug ("rangeno is %d\n", range->rangeno);
-				debug ("[%x - %x]\n", range->start, range->end);
+				debug_pci ("rangeno is %d\n", range->rangeno);
+				debug_pci ("[%x - %x]\n", range->start, range->end);
 				range = range->next;
 			}
 		}
 
-		debug ("The Mem Ranges are as follows:\n");
+		debug_pci ("The Mem Ranges are as follows:\n");
 		if (bus_cur->rangeMem) {
 			range = bus_cur->rangeMem;
 			for (i = 0; i < bus_cur->noMemRanges; i++) {
-				debug ("rangeno is %d\n", range->rangeno);
-				debug ("[%x - %x]\n", range->start, range->end);
+				debug_pci ("rangeno is %d\n", range->rangeno);
+				debug_pci ("[%x - %x]\n", range->start, range->end);
 				range = range->next;
 			}
 		}
 
-		debug ("The PFMem Ranges are as follows:\n");
+		debug_pci ("The PFMem Ranges are as follows:\n");
 
 		if (bus_cur->rangePFMem) {
 			range = bus_cur->rangePFMem;
 			for (i = 0; i < bus_cur->noPFMemRanges; i++) {
-				debug ("rangeno is %d\n", range->rangeno);
-				debug ("[%x - %x]\n", range->start, range->end);
+				debug_pci ("rangeno is %d\n", range->rangeno);
+				debug_pci ("[%x - %x]\n", range->start, range->end);
 				range = range->next;
 			}
 		}
 
-		debug ("The resources on this bus are as follows\n");
+		debug_pci ("The resources on this bus are as follows\n");
 
-		debug ("IO...\n");
+		debug_pci ("IO...\n");
 		if (bus_cur->firstIO) {
 			res = bus_cur->firstIO;
 			while (res) {
-				debug ("The range # is %d\n", res->rangeno);
-				debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
-				debug ("[%x - %x], len=%x\n", res->start, res->end, res->len);
+				debug_pci ("The range # is %d\n", res->rangeno);
+				debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
+				debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len);
 				if (res->next)
 					res = res->next;
 				else if (res->nextRange)
@@ -1815,13 +1844,13 @@
 					break;
 			}
 		}
-		debug ("Mem...\n");
+		debug_pci ("Mem...\n");
 		if (bus_cur->firstMem) {
 			res = bus_cur->firstMem;
 			while (res) {
-				debug ("The range # is %d\n", res->rangeno);
-				debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
-				debug ("[%x - %x], len=%x\n", res->start, res->end, res->len);
+				debug_pci ("The range # is %d\n", res->rangeno);
+				debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
+				debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len);
 				if (res->next)
 					res = res->next;
 				else if (res->nextRange)
@@ -1830,13 +1859,13 @@
 					break;
 			}
 		}
-		debug ("PFMem...\n");
+		debug_pci ("PFMem...\n");
 		if (bus_cur->firstPFMem) {
 			res = bus_cur->firstPFMem;
 			while (res) {
-				debug ("The range # is %d\n", res->rangeno);
-				debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
-				debug ("[%x - %x], len=%x\n", res->start, res->end, res->len);
+				debug_pci ("The range # is %d\n", res->rangeno);
+				debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
+				debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len);
 				if (res->next)
 					res = res->next;
 				else if (res->nextRange)
@@ -1846,23 +1875,53 @@
 			}
 		}
 
-		debug ("PFMemFromMem...\n");
+		debug_pci ("PFMemFromMem...\n");
 		if (bus_cur->firstPFMemFromMem) {
 			res = bus_cur->firstPFMemFromMem;
 			while (res) {
-				debug ("The range # is %d\n", res->rangeno);
-				debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
-				debug ("[%x - %x], len=%x\n", res->start, res->end, res->len);
+				debug_pci ("The range # is %d\n", res->rangeno);
+				debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
+				debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len);
 				res = res->next;
 			}
 		}
 	}
+	debug_pci ("***********************END***********************\n");
+}
+
+int static range_exists_already (struct range_node * range, struct bus_node * bus_cur, u8 type)
+{
+	struct range_node * range_cur = NULL;
+	switch (type) {
+		case IO:
+			range_cur = bus_cur->rangeIO;
+			break;
+		case MEM:
+			range_cur = bus_cur->rangeMem;
+			break;
+		case PFMEM:
+			range_cur = bus_cur->rangePFMem;
+			break;
+		default:
+			err ("wrong type passed to find out if range already exists \n");
+			return -ENODEV;
+	}
+
+	while (range_cur) {
+		if ((range_cur->start == range->start) && (range_cur->end == range->end))
+			return 1;
+		range_cur = range_cur->next;
+	}
+	
+	return 0;
 }
 
 /* This routine will read the windows for any PPB we have and update the
  * range info for the secondary bus, and will also input this info into
  * primary bus, since BIOS doesn't. This is for PPB that are in the system
- * on bootup
+ * on bootup.  For bridged cards that were added during previous load of the
+ * driver, only the ranges and the bus structure are added, the devices are
+ * added from NVRAM
  * Input: primary busno
  * Returns: none
  * Note: this function doesn't take into account IO restrictions etc,
@@ -1871,7 +1930,7 @@
  *	 behind them All these are TO DO.
  *	 Also need to add more error checkings... (from fnc returns etc)
  */
-static int update_bridge_ranges (struct bus_node **bus)
+static int __init update_bridge_ranges (struct bus_node **bus)
 {
 	u8 sec_busno, device, function, busno, hdr_type, start_io_address, end_io_address;
 	u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address;
@@ -1883,9 +1942,11 @@
 	struct resource_node *pfmem;
 	struct range_node *range;
 	bus_cur = *bus;
+	if (!bus_cur)
+		return -ENODEV;
 	busno = bus_cur->busno;
 
-	debug ("inside update_bridge_ranges \n");
+	debug ("inside %s \n", __FUNCTION__);
 	debug ("bus_cur->busno = %x\n", bus_cur->busno);
 
 	for (device = 0; device < 32; device++) {
@@ -1915,6 +1976,12 @@
 						 */
 						pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SECONDARY_BUS, &sec_busno);
 						bus_sec = find_bus_wprev (sec_busno, NULL, 0); 
+						/* this bus structure doesn't exist yet, PPB was configured during previous loading of ibmphp */
+						if (!bus_sec) {
+							bus_sec = alloc_error_bus (NULL, sec_busno, 1);
+							/* the rest will be populated during NVRAM call */
+							return 0;
+						}
 						pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_BASE, &start_io_address);
 						pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_LIMIT, &end_io_address);
 						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_BASE_UPPER16, &upper_io_start);
@@ -1925,9 +1992,7 @@
 						end_address |= (upper_io_end << 16);
 
 						if ((start_address) && (start_address <= end_address)) {
-
 							range = kmalloc (sizeof (struct range_node), GFP_KERNEL);
-
 							if (!range) {
 								err ("out of system memory \n");
 								return -ENOMEM;
@@ -1936,33 +2001,39 @@
 							range->start = start_address;
 							range->end = end_address + 0xfff;
 
-							if (bus_sec->noIORanges > 0) 
-								add_range (IO, range, bus_sec);
-							else {
+							if (bus_sec->noIORanges > 0) {
+								if (!range_exists_already (range, bus_sec, IO)) {
+									add_range (IO, range, bus_sec);
+									++bus_sec->noIORanges;
+								} else {
+									kfree (range);
+									range = NULL;
+								}
+							} else {
 								/* 1st IO Range on the bus */
 								range->rangeno = 1;
 								bus_sec->rangeIO = range;
+								++bus_sec->noIORanges;
 							}
-
-							++bus_sec->noIORanges;
 							fix_resources (bus_sec);
-						
-							io = kmalloc (sizeof (struct resource_node), GFP_KERNEL);							
-							if (!io) {
-								kfree (range);
-								err ("out of system memory \n");
-								return -ENOMEM;
-							}
-							memset (io, 0, sizeof (struct resource_node));
-							io->type = IO;
-							io->busno = bus_cur->busno;
-							io->devfunc = ((device << 3) | (function & 0x7));
-							io->start = start_address;
-							io->end = end_address + 0xfff;
-							io->len = io->end - io->start + 1;
 
-							ibmphp_add_resource (io);
-						}
+							if (ibmphp_find_resource (bus_cur, start_address, &io, IO)) {
+								io = kmalloc (sizeof (struct resource_node), GFP_KERNEL);							
+								if (!io) {
+									kfree (range);
+									err ("out of system memory \n");
+									return -ENOMEM;
+								}
+								memset (io, 0, sizeof (struct resource_node));
+								io->type = IO;
+								io->busno = bus_cur->busno;
+								io->devfunc = ((device << 3) | (function & 0x7));
+								io->start = start_address;
+								io->end = end_address + 0xfff;
+								io->len = io->end - io->start + 1;
+								ibmphp_add_resource (io);
+							}
+						}	
 
 						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_MEMORY_BASE, &start_mem_address);
 						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_MEMORY_LIMIT, &end_mem_address);
@@ -1981,31 +2052,39 @@
 							range->start = start_address;
 							range->end = end_address + 0xfffff;
 
-							if (bus_sec->noMemRanges > 0) 
-								add_range (MEM, range, bus_sec);
-							else {
+							if (bus_sec->noMemRanges > 0) {
+								if (!range_exists_already (range, bus_sec, MEM)) {
+									add_range (MEM, range, bus_sec);
+									++bus_sec->noMemRanges;
+								} else {
+									kfree (range);
+									range = NULL;
+								}
+							} else {
 								/* 1st Mem Range on the bus */
 								range->rangeno = 1;
 								bus_sec->rangeMem = range;
+								++bus_sec->noMemRanges;
 							}
 
-							++bus_sec->noMemRanges;
 							fix_resources (bus_sec);
 
-							mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
-							if (!mem) {
-								kfree (range);
-								err ("out of system memory \n");
-								return -ENOMEM;
+							if (ibmphp_find_resource (bus_cur, start_address, &mem, MEM)) {
+								mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+								if (!mem) {
+									kfree (range);
+									err ("out of system memory \n");
+									return -ENOMEM;
+								}
+								memset (mem, 0, sizeof (struct resource_node));
+								mem->type = MEM;
+								mem->busno = bus_cur->busno;
+								mem->devfunc = ((device << 3) | (function & 0x7));
+								mem->start = start_address;
+								mem->end = end_address + 0xfffff;
+								mem->len = mem->end - mem->start + 1;
+								ibmphp_add_resource (mem);
 							}
-							memset (mem, 0, sizeof (struct resource_node));
-							mem->type = MEM;
-							mem->busno = bus_cur->busno;
-							mem->devfunc = ((device << 3) | (function & 0x7));
-							mem->start = start_address;
-							mem->end = end_address + 0xfffff;
-							mem->len = mem->end - mem->start + 1;
-							ibmphp_add_resource (mem);
 						}
 						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_MEMORY_BASE, &start_mem_address);
 						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_MEMORY_LIMIT, &end_mem_address);
@@ -2029,32 +2108,40 @@
 							range->start = start_address;
 							range->end = end_address + 0xfffff;
 
-							if (bus_sec->noPFMemRanges > 0)
-								add_range (PFMEM, range, bus_sec);
-							else {
+							if (bus_sec->noPFMemRanges > 0) {
+								if (!range_exists_already (range, bus_sec, PFMEM)) {
+									add_range (PFMEM, range, bus_sec);
+									++bus_sec->noPFMemRanges;
+								} else {
+									kfree (range);
+									range = NULL;
+								}
+							} else {
 								/* 1st PFMem Range on the bus */
 								range->rangeno = 1;
 								bus_sec->rangePFMem = range;
+								++bus_sec->noPFMemRanges;
 							}
 
-							++bus_sec->noPFMemRanges;
 							fix_resources (bus_sec);
+							if (ibmphp_find_resource (bus_cur, start_address, &pfmem, PFMEM)) {
+								pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+								if (!pfmem) {
+									kfree (range);
+									err ("out of system memory \n");
+									return -ENOMEM;
+								}
+								memset (pfmem, 0, sizeof (struct resource_node));
+								pfmem->type = PFMEM;
+								pfmem->busno = bus_cur->busno;
+								pfmem->devfunc = ((device << 3) | (function & 0x7));
+								pfmem->start = start_address;
+								pfmem->end = end_address + 0xfffff;
+								pfmem->len = pfmem->end - pfmem->start + 1;
+								pfmem->fromMem = FALSE;
 
-							pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
-							if (!pfmem) {
-								kfree (range);
-								err ("out of system memory \n");
-								return -ENOMEM;
+								ibmphp_add_resource (pfmem);
 							}
-							memset (pfmem, 0, sizeof (struct resource_node));
-							pfmem->type = PFMEM;
-							pfmem->busno = bus_cur->busno;
-							pfmem->devfunc = ((device << 3) | (function & 0x7));
-							pfmem->start = start_address;
-							pfmem->end = end_address + 0xfffff;
-							pfmem->len = pfmem->end - pfmem->start + 1;
-							pfmem->fromMem = FALSE;
-							ibmphp_add_resource (pfmem);
 						}
 						break;
 				}	/* end of switch */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/pci_hotplug.h linux-2.4.20/drivers/hotplug/pci_hotplug.h
--- linux-2.4.19/drivers/hotplug/pci_hotplug.h	2001-11-09 22:01:22.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/pci_hotplug.h	2002-10-29 11:18:37.000000000 +0000
@@ -29,6 +29,22 @@
 #define _PCI_HOTPLUG_H
 
 
+/* These values come from the PCI Hotplug Spec */
+enum pci_bus_speed {
+	PCI_SPEED_33MHz			= 0x00,
+	PCI_SPEED_66MHz			= 0x01,
+	PCI_SPEED_66MHz_PCIX		= 0x02,
+	PCI_SPEED_100MHz_PCIX		= 0x03,
+	PCI_SPEED_133MHz_PCIX		= 0x04,
+	PCI_SPEED_66MHz_PCIX_266	= 0x09,
+	PCI_SPEED_100MHz_PCIX_266	= 0x0a,
+	PCI_SPEED_133MHz_PCIX_266	= 0x0b,
+	PCI_SPEED_66MHz_PCIX_533	= 0x11,
+	PCI_SPEED_100MHz_PCIX_533	= 0X12,
+	PCI_SPEED_133MHz_PCIX_533	= 0x13,
+	PCI_SPEED_UNKNOWN		= 0xff,
+};
+
 struct hotplug_slot;
 struct hotplug_slot_core;
 
@@ -50,7 +66,13 @@
  * @get_latch_status: Called to get the current latch status of a slot.
  *	If this field is NULL, the value passed in the struct hotplug_slot_info
  *	will be used when this value is requested by a user.
- * @get_adapter_present: Called to get see if an adapter is present in the slot or not.
+ * @get_adapter_status: Called to get see if an adapter is present in the slot or not.
+ *	If this field is NULL, the value passed in the struct hotplug_slot_info
+ *	will be used when this value is requested by a user.
+ * @get_max_bus_speed: Called to get the max bus speed for a slot.
+ *	If this field is NULL, the value passed in the struct hotplug_slot_info
+ *	will be used when this value is requested by a user.
+ * @get_cur_bus_speed: Called to get the current bus speed for a slot.
  *	If this field is NULL, the value passed in the struct hotplug_slot_info
  *	will be used when this value is requested by a user.
  *
@@ -69,6 +91,8 @@
 	int (*get_attention_status)	(struct hotplug_slot *slot, u8 *value);
 	int (*get_latch_status)		(struct hotplug_slot *slot, u8 *value);
 	int (*get_adapter_status)	(struct hotplug_slot *slot, u8 *value);
+	int (*get_max_bus_speed)	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+	int (*get_cur_bus_speed)	(struct hotplug_slot *slot, enum pci_bus_speed *value);
 };
 
 /**
@@ -85,6 +109,8 @@
 	u8	attention_status;
 	u8	latch_status;
 	u8	adapter_status;
+	enum pci_bus_speed	max_bus_speed;
+	enum pci_bus_speed	cur_bus_speed;
 };
 
 /**
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/pci_hotplug_core.c linux-2.4.20/drivers/hotplug/pci_hotplug_core.c
--- linux-2.4.19/drivers/hotplug/pci_hotplug_core.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/pci_hotplug_core.c	2002-10-29 11:18:35.000000000 +0000
@@ -37,6 +37,8 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/dnotify.h>
+#include <linux/proc_fs.h>
 #include <asm/uaccess.h>
 #include "pci_hotplug.h"
 
@@ -56,7 +58,7 @@
 /* local variables */
 static int debug;
 
-#define DRIVER_VERSION	"0.4"
+#define DRIVER_VERSION	"0.5"
 #define DRIVER_AUTHOR	"Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC	"PCI Hot Plug PCI Core"
 
@@ -73,10 +75,11 @@
 	struct dentry	*latch_dentry;
 	struct dentry	*adapter_dentry;
 	struct dentry	*test_dentry;
+	struct dentry	*max_bus_speed_dentry;
+	struct dentry	*cur_bus_speed_dentry;
 };
 
 static struct super_operations pcihpfs_ops;
-static struct file_operations pcihpfs_dir_operations;
 static struct file_operations default_file_operations;
 static struct inode_operations pcihpfs_dir_inode_operations;
 static struct vfsmount *pcihpfs_mount;	/* one of the mounts of our fs for reference counting */
@@ -86,6 +89,29 @@
 
 LIST_HEAD(pci_hotplug_slot_list);
 
+/* these strings match up with the values in pci_bus_speed */
+static char *pci_bus_speed_strings[] = {
+	"33 MHz PCI",		/* 0x00 */
+	"66 MHz PCI",		/* 0x01 */
+	"66 MHz PCIX", 		/* 0x02 */
+	"100 MHz PCIX",		/* 0x03 */
+	"133 MHz PCIX",		/* 0x04 */
+	NULL,			/* 0x05 */
+	NULL,			/* 0x06 */
+	NULL,			/* 0x07 */
+	NULL,			/* 0x08 */
+	"66 MHz PCIX 266",	/* 0x09 */
+	"100 MHz PCIX 266",	/* 0x0a */
+	"133 MHz PCIX 266",	/* 0x0b */
+	NULL,			/* 0x0c */
+	NULL,			/* 0x0d */
+	NULL,			/* 0x0e */
+	NULL,			/* 0x0f */
+	NULL,			/* 0x10 */
+	"66 MHz PCIX 533",	/* 0x11 */
+	"100 MHz PCIX 533",	/* 0x12 */
+	"133 MHz PCIX 533",	/* 0x13 */
+};
 
 static int pcihpfs_statfs (struct super_block *sb, struct statfs *buf)
 {
@@ -101,6 +127,12 @@
 	return NULL;
 }
 
+#ifdef CONFIG_PROC_FS		
+extern struct proc_dir_entry *proc_bus_pci_dir;
+static struct proc_dir_entry *slotdir = NULL;
+static const char *slotdir_name = "slots";
+#endif
+
 static struct inode *pcihpfs_get_inode (struct super_block *sb, int mode, int dev)
 {
 	struct inode *inode = new_inode(sb);
@@ -122,7 +154,7 @@
 			break;
 		case S_IFDIR:
 			inode->i_op = &pcihpfs_dir_inode_operations;
-			inode->i_fop = &pcihpfs_dir_operations;
+			inode->i_fop = &dcache_dir_ops;
 			break;
 		}
 	}
@@ -235,11 +267,6 @@
 	return 0;
 }
 
-static struct file_operations pcihpfs_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	dcache_readdir,
-};
-
 static struct file_operations default_file_operations = {
 	read:		default_read_file,
 	write:		default_write_file,
@@ -285,6 +312,24 @@
 	llseek:		default_file_lseek,
 };
 
+/* file ops for the "max bus speed" files */
+static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
+static struct file_operations max_bus_speed_file_operations = {
+	read:		max_bus_speed_read_file,
+	write:		default_write_file,
+	open:		default_open,
+	llseek:		default_file_lseek,
+};
+
+/* file ops for the "current bus speed" files */
+static ssize_t cur_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
+static struct file_operations cur_bus_speed_file_operations = {
+	read:		cur_bus_speed_read_file,
+	write:		default_write_file,
+	open:		default_open,
+	llseek:		default_file_lseek,
+};
+
 /* file ops for the "test" files */
 static ssize_t test_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos);
 static struct file_operations test_file_operations = {
@@ -501,26 +546,28 @@
 	up(&parent->d_inode->i_sem);
 }
 
-#define GET_STATUS(name)	\
-static int get_##name##_status (struct hotplug_slot *slot, u8 *value)	\
+#define GET_STATUS(name,type)	\
+static int get_##name (struct hotplug_slot *slot, type *value)		\
 {									\
 	struct hotplug_slot_ops *ops = slot->ops;			\
 	int retval = 0;							\
 	if (ops->owner)							\
 		__MOD_INC_USE_COUNT(ops->owner);			\
-	if (ops->get_##name##_status)					\
-		retval = ops->get_##name##_status (slot, value);	\
+	if (ops->get_##name)						\
+		retval = ops->get_##name (slot, value);			\
 	else								\
-		*value = slot->info->name##_status;			\
+		*value = slot->info->name;				\
 	if (ops->owner)							\
 		__MOD_DEC_USE_COUNT(ops->owner);			\
 	return retval;							\
 }
 
-GET_STATUS(power)
-GET_STATUS(attention)
-GET_STATUS(latch)
-GET_STATUS(adapter)
+GET_STATUS(power_status, u8)
+GET_STATUS(attention_status, u8)
+GET_STATUS(latch_status, u8)
+GET_STATUS(adapter_status, u8)
+GET_STATUS(max_bus_speed, enum pci_bus_speed)
+GET_STATUS(cur_bus_speed, enum pci_bus_speed)
 
 static ssize_t power_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
 {
@@ -534,7 +581,7 @@
 
 	if (*offset < 0)
 		return -EINVAL;
-	if (count <= 0)
+	if (count == 0 || count > 16384)
 		return 0;
 	if (*offset != 0)
 		return 0;
@@ -575,7 +622,7 @@
 
 	if (*offset < 0)
 		return -EINVAL;
-	if (count <= 0)
+	if (count == 0 || count > 16384)
 		return 0;
 	if (*offset != 0)
 		return 0;
@@ -645,7 +692,7 @@
 
 	if (*offset < 0)
 		return -EINVAL;
-	if (count <= 0)
+	if (count == 0 || count > 16384)
 		return 0;
 	if (*offset != 0)
 		return 0;
@@ -686,7 +733,7 @@
 
 	if (*offset < 0)
 		return -EINVAL;
-	if (count <= 0)
+	if (count == 0 || count > 16384)
 		return 0;
 	if (*offset != 0)
 		return 0;
@@ -769,7 +816,6 @@
 	return retval;
 }
 
-
 static ssize_t presence_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
 {
 	struct hotplug_slot *slot = file->private_data;
@@ -813,6 +859,108 @@
 	return retval;
 }
 
+static char *unknown_speed = "Unknown bus speed";
+
+static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
+{
+	struct hotplug_slot *slot = file->private_data;
+	unsigned char *page;
+	char *speed_string;
+	int retval;
+	int len = 0;
+	enum pci_bus_speed value;
+	
+	dbg ("count = %d, offset = %lld\n", count, *offset);
+
+	if (*offset < 0)
+		return -EINVAL;
+	if (count <= 0)
+		return 0;
+	if (*offset != 0)
+		return 0;
+
+	if (slot == NULL) {
+		dbg("slot == NULL???\n");
+		return -ENODEV;
+	}
+
+	page = (unsigned char *)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	retval = get_max_bus_speed (slot, &value);
+	if (retval)
+		goto exit;
+
+	if (value == PCI_SPEED_UNKNOWN)
+		speed_string = unknown_speed;
+	else
+		speed_string = pci_bus_speed_strings[value];
+	
+	len = sprintf (page, "%s\n", speed_string);
+
+	if (copy_to_user (buf, page, len)) {
+		retval = -EFAULT;
+		goto exit;
+	}
+	*offset += len;
+	retval = len;
+
+exit:
+	free_page((unsigned long)page);
+	return retval;
+}
+
+static ssize_t cur_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
+{
+	struct hotplug_slot *slot = file->private_data;
+	unsigned char *page;
+	char *speed_string;
+	int retval;
+	int len = 0;
+	enum pci_bus_speed value;
+
+	dbg ("count = %d, offset = %lld\n", count, *offset);
+
+	if (*offset < 0)
+		return -EINVAL;
+	if (count <= 0)
+		return 0;
+	if (*offset != 0)
+		return 0;
+
+	if (slot == NULL) {
+		dbg("slot == NULL???\n");
+		return -ENODEV;
+	}
+
+	page = (unsigned char *)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	retval = get_cur_bus_speed (slot, &value);
+	if (retval)
+		goto exit;
+
+	if (value == PCI_SPEED_UNKNOWN)
+		speed_string = unknown_speed;
+	else
+		speed_string = pci_bus_speed_strings[value];
+	
+	len = sprintf (page, "%s\n", speed_string);
+
+	if (copy_to_user (buf, page, len)) {
+		retval = -EFAULT;
+		goto exit;
+	}
+	*offset += len;
+	retval = len;
+
+exit:
+	free_page((unsigned long)page);
+	return retval;
+}
+
 static ssize_t test_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset)
 {
 	struct hotplug_slot *slot = file->private_data;
@@ -823,7 +971,7 @@
 
 	if (*offset < 0)
 		return -EINVAL;
-	if (count <= 0)
+	if (count == 0 || count > 16384)
 		return 0;
 	if (*offset != 0)
 		return 0;
@@ -876,30 +1024,57 @@
 					   S_IFDIR | S_IXUGO | S_IRUGO,
 					   NULL, NULL, NULL);
 	if (core->dir_dentry != NULL) {
-		core->power_dentry = fs_create_file ("power",
-						     S_IFREG | S_IRUGO | S_IWUSR,
-						     core->dir_dentry, slot,
-						     &power_file_operations);
-
-		core->attention_dentry = fs_create_file ("attention",
-							 S_IFREG | S_IRUGO | S_IWUSR,
-							 core->dir_dentry, slot,
-							 &attention_file_operations);
-
-		core->latch_dentry = fs_create_file ("latch",
-						     S_IFREG | S_IRUGO,
-						     core->dir_dentry, slot,
-						     &latch_file_operations);
-
-		core->adapter_dentry = fs_create_file ("adapter",
-						       S_IFREG | S_IRUGO,
-						       core->dir_dentry, slot,
-						       &presence_file_operations);
-
-		core->test_dentry = fs_create_file ("test",
-						    S_IFREG | S_IRUGO | S_IWUSR,
-						    core->dir_dentry, slot,
-						    &test_file_operations);
+		if ((slot->ops->enable_slot) ||
+		    (slot->ops->disable_slot) ||
+		    (slot->ops->get_power_status))
+			core->power_dentry = 
+				fs_create_file ("power",
+						S_IFREG | S_IRUGO | S_IWUSR,
+						core->dir_dentry, slot,
+						&power_file_operations);
+
+		if ((slot->ops->set_attention_status) ||
+		    (slot->ops->get_attention_status))
+			core->attention_dentry =
+				fs_create_file ("attention",
+						S_IFREG | S_IRUGO | S_IWUSR,
+						core->dir_dentry, slot,
+						&attention_file_operations);
+
+		if (slot->ops->get_latch_status)
+			core->latch_dentry = 
+				fs_create_file ("latch",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&latch_file_operations);
+
+		if (slot->ops->get_adapter_status)
+			core->adapter_dentry = 
+				fs_create_file ("adapter",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&presence_file_operations);
+
+		if (slot->ops->get_max_bus_speed)
+			core->max_bus_speed_dentry = 
+				fs_create_file ("max_bus_speed",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&max_bus_speed_file_operations);
+
+		if (slot->ops->get_cur_bus_speed)
+			core->cur_bus_speed_dentry =
+				fs_create_file ("cur_bus_speed",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&cur_bus_speed_file_operations);
+
+		if (slot->ops->hardware_test)
+			core->test_dentry =
+				fs_create_file ("test",
+						S_IFREG | S_IRUGO | S_IWUSR,
+						core->dir_dentry, slot,
+						&test_file_operations);
 	}
 	return 0;
 }
@@ -917,6 +1092,10 @@
 			fs_remove_file (core->latch_dentry);
 		if (core->adapter_dentry)
 			fs_remove_file (core->adapter_dentry);
+		if (core->max_bus_speed_dentry)
+			fs_remove_file (core->max_bus_speed_dentry);
+		if (core->cur_bus_speed_dentry)
+			fs_remove_file (core->cur_bus_speed_dentry);
 		if (core->test_dentry)
 			fs_remove_file (core->test_dentry);
 		fs_remove_file (core->dir_dentry);
@@ -966,9 +1145,10 @@
 	if (get_slot_from_name (slot->name) != NULL) {
 		spin_unlock (&list_lock);
 		kfree (core);
-		return -EINVAL;
+		return -EEXIST;
 	}
 
+	memset (core, 0, sizeof (struct hotplug_slot_core));
 	slot->core_priv = core;
 
 	list_add (&slot->slot_list, &pci_hotplug_slot_list);
@@ -1012,10 +1192,13 @@
 	return 0;
 }
 
-static inline void update_inode_time (struct inode *inode)
+static inline void update_dentry_inode_time (struct dentry *dentry)
 {
-	if (inode)
-		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	struct inode *inode = dentry->d_inode;
+	if (inode) {
+		inode->i_mtime = CURRENT_TIME;
+		dnotify_parent(dentry, DN_MODIFY);
+	}
 }
 
 /**
@@ -1050,16 +1233,19 @@
 	core = temp->core_priv;
 	if ((core->power_dentry) &&
 	    (temp->info->power_status != info->power_status))
-		update_inode_time (core->power_dentry->d_inode);
+		update_dentry_inode_time (core->power_dentry);
 	if ((core->attention_dentry) &&
 	    (temp->info->attention_status != info->attention_status))
-		update_inode_time (core->attention_dentry->d_inode);
+		update_dentry_inode_time (core->attention_dentry);
 	if ((core->latch_dentry) &&
 	    (temp->info->latch_status != info->latch_status))
-		update_inode_time (core->latch_dentry->d_inode);
+		update_dentry_inode_time (core->latch_dentry);
 	if ((core->adapter_dentry) &&
 	    (temp->info->adapter_status != info->adapter_status))
-		update_inode_time (core->adapter_dentry->d_inode);
+		update_dentry_inode_time (core->adapter_dentry);
+	if ((core->cur_bus_speed_dentry) &&
+	    (temp->info->cur_bus_speed != info->cur_bus_speed))
+		update_dentry_inode_time (core->cur_bus_speed_dentry);
 
 	memcpy (temp->info, info, sizeof (struct hotplug_slot_info));
 	spin_unlock (&list_lock);
@@ -1080,6 +1266,11 @@
 		goto exit;
 	}
 
+#ifdef CONFIG_PROC_FS
+	/* create mount point for pcihpfs */
+	slotdir = proc_mkdir(slotdir_name, proc_bus_pci_dir);
+#endif
+
 	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
 
 exit:
@@ -1089,6 +1280,11 @@
 static void __exit pci_hotplug_exit (void)
 {
 	unregister_filesystem(&pcihpfs_fs_type);
+
+#ifdef CONFIG_PROC_FS
+	if (slotdir)
+		remove_proc_entry(slotdir_name, proc_bus_pci_dir);
+#endif
 }
 
 module_init(pci_hotplug_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/pcihp_acpi.c linux-2.4.20/drivers/hotplug/pcihp_acpi.c
--- linux-2.4.19/drivers/hotplug/pcihp_acpi.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/pcihp_acpi.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,397 +0,0 @@
-/*
- * ACPI PCI Hot Plug Controller Driver
- *
- * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001-2002 IBM Corp.
- * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
- * Copyright (c) 2002 NEC Corporation
- *
- * All rights reserved.
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT.  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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Send feedback to <gregkh@us.ibm.com>,
- *                  <h-aono@ap.jp.nec.com>,
- *		    <t-kouchi@cq.jp.nec.com>
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include "pci_hotplug.h"
-#include "pcihp_acpi.h"
-
-static LIST_HEAD(slot_list);
-
-#if !defined(CONFIG_HOTPLUG_PCI_ACPI_MODULE)
-	#define MY_NAME	"pcihp_acpi"
-#else
-	#define MY_NAME	THIS_MODULE->name
-#endif
-
-/* local variables */
-static int debug = 1;			/* XXX */
-static int num_slots;
-
-#define DRIVER_VERSION	"0.2"
-#define DRIVER_AUTHOR	"Greg Kroah-Hartman <gregkh@us.ibm.com>"
-#define DRIVER_DESC	"ACPI Hot Plug PCI Controller Driver"
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
-
-static int enable_slot		(struct hotplug_slot *slot);
-static int disable_slot		(struct hotplug_slot *slot);
-static int set_attention_status (struct hotplug_slot *slot, u8 value);
-static int hardware_test	(struct hotplug_slot *slot, u32 value);
-static int get_power_status	(struct hotplug_slot *slot, u8 *value);
-static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
-static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
-static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
-
-static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
-	owner:			THIS_MODULE,
-	enable_slot:		enable_slot,
-	disable_slot:		disable_slot,
-	set_attention_status:	set_attention_status,
-	hardware_test:		hardware_test,
-	get_power_status:	get_power_status,
-	get_attention_status:	get_attention_status,
-	get_latch_status:	get_latch_status,
-	get_adapter_status:	get_adapter_status,
-};
-
-
-/* Inline functions to check the sanity of a pointer that is passed to us */
-static inline int slot_paranoia_check (struct slot *slot, const char *function)
-{
-	if (!slot) {
-		dbg("%s - slot == NULL", function);
-		return -1;
-	}
-	if (slot->magic != SLOT_MAGIC) {
-		dbg("%s - bad magic number for slot", function);
-		return -1;
-	}
-	if (!slot->hotplug_slot) {
-		dbg("%s - slot->hotplug_slot == NULL!", function);
-		return -1;
-	}
-	return 0;
-}
-
-static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
-{ 
-	struct slot *slot;
-
-	if (!hotplug_slot) {
-		dbg("%s - hotplug_slot == NULL", function);
-		return NULL;
-	}
-
-	slot = (struct slot *)hotplug_slot->private;
-	if (slot_paranoia_check (slot, function))
-                return NULL;
-	return slot;
-}
-
-
-static int enable_slot (struct hotplug_slot *hotplug_slot)
-{
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	int retval = 0;
-	
-	if (slot == NULL)
-		return -ENODEV;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
-
-	/* enable the specified slot */
-	retval = pcihp_acpi_enable_slot (slot->acpi_slot);
-
-	return retval;
-}
-
-static int disable_slot (struct hotplug_slot *hotplug_slot)
-{
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	int retval = 0;
-	
-	if (slot == NULL)
-		return -ENODEV;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
-
-	/* disable the specified slot */
-	retval = pcihp_acpi_disable_slot (slot->acpi_slot);
-
-	return retval;
-}
-
-static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
-{
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	int retval = 0;
-	
-	if (slot == NULL)
-		return -ENODEV;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
-
-	/* TBD
-	 * ACPI doesn't have known method to manipulate
-	 * attention status LED
-	 */
-	switch (status) {
-		case 0:
-			/* FIXME turn light off */
-			slot->attention_status = 0;
-			break;
-
-		case 1:
-		default:
-			/* FIXME turn light on */
-			slot->attention_status = 1;
-			break;
-	}
-
-	return retval;
-}
-
-static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
-{
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	int retval = 0;
-	
-	if (slot == NULL)
-		return -ENODEV;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
-
-	err ("No hardware tests are defined for this driver");
-	retval = -ENODEV;
-
-	return retval;
-}
-
-static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
-{
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	int retval = 0;
-	
-	if (slot == NULL)
-		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
-
-	*value = pcihp_acpi_get_power_status (slot->acpi_slot);
-
-	return retval;
-}
-
-static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
-{
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	int retval = 0;
-	
-	if (slot == NULL)
-		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
-
-	*value = slot->attention_status;
-
-	return retval;
-}
-
-static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
-{
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	int retval = 0;
-	
-	if (slot == NULL)
-		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
-
-	*value = pcihp_acpi_get_latch_status (slot->acpi_slot);
-
-	return retval;
-}
-
-static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
-{
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	int retval = 0;
-	
-	if (slot == NULL)
-		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
-
-	*value = pcihp_acpi_get_adapter_status (slot->acpi_slot);
-
-	return retval;
-}
-
-static int init_acpi (void)
-{
-	int retval;
-
-	dbg("init_acpi");		/* XXX */
-	/* initialize internal data structure etc. */
-	retval = pcihp_acpi_glue_init();
-
-	/* read initial number of slots */
-	if (!retval) {
-		num_slots = pcihp_acpi_get_num_slots();
-		if (num_slots == 0)
-			retval = -ENODEV;
-	}
-
-	return retval;
-}
-
-static void exit_acpi (void)
-{
-	/* deallocate internal data structures etc. */
-	pcihp_acpi_glue_exit();
-}
-
-#define SLOT_NAME_SIZE	10
-static void make_slot_name (struct slot *slot)
-{
-	/* FIXME - get this from the ACPI representation of the slot */
-	snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d", slot->number);
-}
-
-static int init_slots (void)
-{
-	struct slot *slot;
-	int retval = 0;
-	int i;
-
-	for (i = 0; i < num_slots; ++i) {
-		slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
-		if (!slot)
-			return -ENOMEM;
-		memset(slot, 0, sizeof(struct slot));
-
-		slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
-		if (!slot->hotplug_slot) {
-			kfree (slot);
-			return -ENOMEM;
-		}
-		memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
-
-		slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
-		if (!slot->hotplug_slot->info) {
-			kfree (slot->hotplug_slot);
-			kfree (slot);
-			return -ENOMEM;
-		}
-		memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
-
-		slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
-		if (!slot->hotplug_slot->name) {
-			kfree (slot->hotplug_slot->info);
-			kfree (slot->hotplug_slot);
-			kfree (slot);
-			return -ENOMEM;
-		}
-
-		slot->magic = SLOT_MAGIC;
-		slot->number = i;
-
-		slot->hotplug_slot->private = slot;
-		make_slot_name (slot);
-		slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
-		
-		slot->acpi_slot = get_slot_from_id (i);
-		slot->hotplug_slot->info->power_status = pcihp_acpi_get_power_status(slot->acpi_slot);
-		slot->hotplug_slot->info->attention_status = pcihp_acpi_get_attention_status(slot->acpi_slot);
-		slot->hotplug_slot->info->latch_status = pcihp_acpi_get_latch_status(slot->acpi_slot);
-		slot->hotplug_slot->info->adapter_status = pcihp_acpi_get_adapter_status(slot->acpi_slot);
-
-		dbg ("registering slot %d", i);
-		retval = pci_hp_register (slot->hotplug_slot);
-		if (retval) {
-			err ("pci_hp_register failed with error %d", retval);
-			kfree (slot->hotplug_slot->info);
-			kfree (slot->hotplug_slot->name);
-			kfree (slot->hotplug_slot);
-			kfree (slot);
-			return retval;
-		}
-
-		/* add slot to our internal list */
-		list_add (&slot->slot_list, &slot_list);
-	}
-
-	return retval;
-}
-		
-static void cleanup_slots (void)
-{
-	struct list_head *tmp;
-	struct slot *slot;
-
-	list_for_each (tmp, &slot_list) {
-		slot = list_entry (tmp, struct slot, slot_list);
-		list_del (&slot->slot_list);
-		pci_hp_deregister (slot->hotplug_slot);
-		kfree (slot->hotplug_slot->info);
-		kfree (slot->hotplug_slot->name);
-		kfree (slot->hotplug_slot);
-		kfree (slot);
-	}
-
-	return;
-}
-
-static int __init pcihp_acpi_init(void)
-{
-	int retval;
-
-	/* read all the ACPI info from the system */
-	retval = init_acpi();
-	if (retval)
-		return retval;
-
-	retval = init_slots();
-	if (retval)
-		return retval;
-
-	info (DRIVER_DESC " version: " DRIVER_VERSION);
-	return 0;
-}
-
-static void __exit pcihp_acpi_exit(void)
-{
-	cleanup_slots();
-	exit_acpi();
-}
-
-module_init(pcihp_acpi_init);
-module_exit(pcihp_acpi_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/pcihp_acpi.h linux-2.4.20/drivers/hotplug/pcihp_acpi.h
--- linux-2.4.19/drivers/hotplug/pcihp_acpi.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/pcihp_acpi.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,231 +0,0 @@
-/*
- * ACPI PCI Hot Plug Controller Driver
- *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001 IBM Corp.
- * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
- * Copyright (c) 2002 NEC Corporation
- *
- * All rights reserved.
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT.  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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Send feedback to <gregkh@us.ibm.com>,
- *		    <h-aono@ap.jp.nec.com>,
- *		    <t-kouchi@cq.jp.nec.com>
- *
- */
-
-#ifndef _PCIHP_ACPI_H
-#define _PCIHP_ACPI_H
-
-#include "include/acpi.h"
-
-#if ACPI_CA_VERSION < 0x20020201
-/* until we get a new version of the ACPI driver for both ia32 and ia64 ... */
-#define acpi_util_eval_error(h,p,s)
-
-static acpi_status
-acpi_evaluate_integer (
-	acpi_handle		handle,
-	acpi_string		pathname,
-	acpi_object_list	*arguments,
-	unsigned long		*data)
-{
-	acpi_status             status = AE_OK;
-	acpi_object             element;
-	acpi_buffer		buffer = {sizeof(acpi_object), &element};
-
-	if (!data)
-		return AE_BAD_PARAMETER;
-
-	status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
-	if (ACPI_FAILURE(status)) {
-		acpi_util_eval_error(handle, pathname, status);
-		return status;
-	}
-
-	if (element.type != ACPI_TYPE_INTEGER) {
-		acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
-		return AE_BAD_DATA;
-	}
-
-	*data = element.integer.value;
-
-	return AE_OK;
-}
-#else  /* ACPI_CA_VERSION < 0x20020201 */
-#include "acpi_bus.h"
-#endif /* ACPI_CA_VERSION < 0x20020201 */
-
-/* compatibility stuff */
-#ifndef ACPI_MEMORY_RANGE
-#define ACPI_MEMORY_RANGE MEMORY_RANGE
-#endif
-
-#ifndef ACPI_IO_RANGE
-#define ACPI_IO_RANGE IO_RANGE
-#endif
-
-#ifndef ACPI_BUS_NUMBER_RANGE
-#define ACPI_BUS_NUMBER_RANGE BUS_NUMBER_RANGE
-#endif
-
-#ifndef ACPI_PREFETCHABLE_MEMORY
-#define ACPI_PREFETCHABLE_MEMORY PREFETCHABLE_MEMORY
-#endif
-
-#ifndef ACPI_PRODUCER
-#define ACPI_PRODUCER PRODUCER
-#endif
-
-
-#define dbg(format, arg...)					\
-	do {							\
-		if (debug)					\
-			printk (KERN_DEBUG "%s: " format "\n",	\
-				MY_NAME , ## arg); 		\
-	} while (0)
-#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
-
-/*
- * types and constants
- */
-
-#define SLOT_MAGIC	0x67267322
-
-struct pcihp_acpi_bridge;
-struct pcihp_acpi_slot;
-
-/* slot information for each *physical* slot */
-
-struct slot {
-	u32 magic;
-	u8 number;
-	struct hotplug_slot	*hotplug_slot;
-	struct list_head	slot_list;
-
-	int			attention_status;
-
-	struct pci_resource	*mem_head;
-	struct pci_resource	*p_mem_head;
-	struct pci_resource	*io_head;
-	struct pci_resource	*bus_head;
-
-	/* if there are multiple corresponding slot objects,
-	   this point to one of them */
-	struct pcihp_acpi_slot	*acpi_slot;
-
-	struct pci_dev		*pci_dev;
-};
-
-#define RESOURCE_TYPE_IO	(1)
-#define RESOURCE_TYPE_MEM	(2)
-#define RESOURCE_TYPE_PREFETCH	(3)
-#define RESOURCE_TYPE_BUS	(4)
-
-/* TBD 64bit resource support */
-struct pci_resource {
-	struct pci_resource * next;
-	u32 base;
-	u32 length;
-};
-
-/* bridge information for each bridge device in ACPI namespace */
-
-struct pcihp_acpi_bridge {
-	struct list_head list;
-	acpi_handle handle;
-	struct pcihp_acpi_slot *slots;
-	int nr_slots;
-	u8 seg;
-	u8 bus;
-	u8 sub;
-	u32 status;
-	u32 flags;
-
-	/* resources on this bus (free resources) */
-	struct pci_resource *free_io;
-	struct pci_resource *free_mem;
-	struct pci_resource *free_prefetch;
-	struct pci_resource *free_bus;
-
-	/* used resources (embedded or owned resources) */
-	struct pci_resource *used_io;
-	struct pci_resource *used_mem;
-	struct pci_resource *used_prefetch;
-	struct pci_resource *used_bus;
-};
-
-/*
- * slot information for each slot object in ACPI namespace
- * usually 8 objects per slot (for each PCI function)
- */
-
-struct pcihp_acpi_slot {
-	struct pcihp_acpi_slot	*next;
-	struct pcihp_acpi_bridge *bridge; /* this slot located on */
-	struct list_head sibling;	/* one slot may have different
-					   objects (i.e. for each function) */
-	acpi_handle	handle;
-	u32		id;		/* slot id (this driver specific) */
-	u8		device;		/* pci device# */
-	u8		function;	/* pci function# */
-	u8		pin;		/* pci interrupt pin */
-	u32		sun;		/* _SUN */
-	u32		flags;		/* see below */
-	u32		status;		/* _STA */
-};
-
-/* PCI bus bridge HID */
-#define ACPI_PCI_ROOT_HID		"PNP0A03"
-
-/* ACPI _STA method value (ignore bit 4; battery present) */
-#define ACPI_STA_PRESENT		(0x00000001)
-#define ACPI_STA_ENABLED		(0x00000002)
-#define ACPI_STA_SHOW_IN_UI		(0x00000004)
-#define ACPI_STA_FUNCTIONAL		(0x00000008)
-#define ACPI_STA_ALL			(0x0000000f)
-
-/* bridge flags */
-#define BRIDGE_HAS_STA	(0x00000001)
-
-/* slot flags */
-
-#define SLOT_HAS_EJ0	(0x00000001)
-#define SLOT_HAS_PS0	(0x00000002)
-#define SLOT_HAS_PS3	(0x00000004)
-
-/* function prototypes */
-
-/* pcihp_acpi_glue.c */
-extern int pcihp_acpi_glue_init (void);
-extern void pcihp_acpi_glue_exit (void);
-extern int pcihp_acpi_get_num_slots (void);
-extern struct pcihp_acpi_slot *get_slot_from_id (int id);
-
-extern int pcihp_acpi_enable_slot (struct pcihp_acpi_slot *slot);
-extern int pcihp_acpi_disable_slot (struct pcihp_acpi_slot *slot);
-extern u8 pcihp_acpi_get_power_status (struct pcihp_acpi_slot *slot);
-extern u8 pcihp_acpi_get_attention_status (struct pcihp_acpi_slot *slot);
-extern u8 pcihp_acpi_get_latch_status (struct pcihp_acpi_slot *slot);
-extern u8 pcihp_acpi_get_adapter_status (struct pcihp_acpi_slot *slot);
-
-#endif /* _PCIHP_ACPI_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/pcihp_acpi_ctrl.c linux-2.4.20/drivers/hotplug/pcihp_acpi_ctrl.c
--- linux-2.4.19/drivers/hotplug/pcihp_acpi_ctrl.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/pcihp_acpi_ctrl.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,642 +0,0 @@
-/*
- * ACPI PCI HotPlug Utility functions
- *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001 IBM Corp.
- * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
- * Copyright (c) 2002 NEC Corporation
- *
- * All rights reserved.
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT.  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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Send feedback to <gregkh@us.ibm.com>,<h-aono@ap.jp.nec.com>
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/sysctl.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/spinlock.h>
-
-#include <linux/ioctl.h>
-#include <linux/fcntl.h>
-
-#include <linux/list.h>
-
-#include <asm/uaccess.h>
-
-#define _LINUX                          /* for acpi subcomponent */
-
-#include "include/acpi.h"
-
-#include "pci_hotplug.h"
-#include "pchihp_acpi.h"
-
-#if !defined(CONFIG_HOTPLUG_PCI_MODULE)
-	#define MY_NAME "pci_hotplug"
-#else
-	#define MY_NAME THIS_MODULE->name
-#endif
-
-#define dbg(fmt, arg...) do { if (debug) printk(KERN_WARNING "%s: "__FUNCTION__": " fmt , MY_NAME , ## arg); } while (0)
-#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)
-
-
-/* local variables */
-static int debug = 0;
-
-/*
- * sort_by_size
- *
- * Sorts nodes on the list by their length.
- * Smallest first.
- *
- */
-static int sort_by_size(struct pci_resource **head)
-{
-	struct pci_resource *current_res;
-	struct pci_resource *next_res;
-	int out_of_order = 1;
-
-	if (!(*head))
-		return(1);
-
-	if (!((*head)->next))
-		return(0);
-
-	while (out_of_order) {
-		out_of_order = 0;
-
-		// Special case for swapping list head
-		if (((*head)->next) &&
-		    ((*head)->length > (*head)->next->length)) {
-			out_of_order++;
-			current_res = *head;
-			*head = (*head)->next;
-			current_res->next = (*head)->next;
-			(*head)->next = current_res;
-		}
-
-		current_res = *head;
-
-		while (current_res->next && current_res->next->next) {
-			if (current_res->next->length > current_res->next->next->length) {
-				out_of_order++;
-				next_res = current_res->next;
-				current_res->next = current_res->next->next;
-				current_res = current_res->next;
-				next_res->next = current_res->next;
-				current_res->next = next_res;
-			} else
-				current_res = current_res->next;
-		}
-	}  // End of out_of_order loop
-
-	return(0);
-}
-
-
-/*
- * sort_by_max_size
- *
- * Sorts nodes on the list by their length.
- * Largest first.
- *
- */
-static int sort_by_max_size(struct pci_resource **head)
-{
-	struct pci_resource *current_res;
-	struct pci_resource *next_res;
-	int out_of_order = 1;
-
-	if (!(*head))
-		return(1);
-
-	if (!((*head)->next))
-		return(0);
-
-	while (out_of_order) {
-		out_of_order = 0;
-
-		// Special case for swapping list head
-		if (((*head)->next) &&
-		    ((*head)->length < (*head)->next->length)) {
-			out_of_order++;
-			current_res = *head;
-			*head = (*head)->next;
-			current_res->next = (*head)->next;
-			(*head)->next = current_res;
-		}
-
-		current_res = *head;
-
-		while (current_res->next && current_res->next->next) {
-			if (current_res->next->length < current_res->next->next->length) {
-				out_of_order++;
-				next_res = current_res->next;
-				current_res->next = current_res->next->next;
-				current_res = current_res->next;
-				next_res->next = current_res->next;
-				current_res->next = next_res;
-			} else
-				current_res = current_res->next;
-		}
-	}  // End of out_of_order loop
-
-	return(0);
-}
-
-/*
- * get_io_resource
- *
- * this function sorts the resource list by size and then
- * returns the first node of "size" length that is not in the
- * ISA aliasing window.  If it finds a node larger than "size"
- * it will split it up.
- *
- * size must be a power of two.
- */
-struct pci_resource *hotplug_get_io_resource (struct pci_resource **head, u32 size)
-{
-	struct pci_resource *prevnode;
-	struct pci_resource *node;
-	struct pci_resource *split_node;
-	u32 temp_dword;
-
-	if (!(*head))
-		return(NULL);
-
-	if ( hotplug_resource_sort_and_combine(head) )
-		return(NULL);
-
-	if ( sort_by_size(head) )
-		return(NULL);
-
-	for (node = *head; node; node = node->next) {
-		if (node->length < size)
-			continue;
-
-		if (node->base & (size - 1)) {
-			// this one isn't base aligned properly
-			// so we'll make a new entry and split it up
-			temp_dword = (node->base | (size-1)) + 1;
-
-			// Short circuit if adjusted size is too small
-			if ((node->length - (temp_dword - node->base)) < size)
-				continue;
-
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-			if (!split_node)
-				return(NULL);
-
-			split_node->base = node->base;
-			split_node->length = temp_dword - node->base;
-			node->base = temp_dword;
-			node->length -= split_node->length;
-
-			// Put it in the list
-			split_node->next = node->next;
-			node->next = split_node;
-		} // End of non-aligned base
-
-		// Don't need to check if too small since we already did
-		if (node->length > size) {
-			// this one is longer than we need
-			// so we'll make a new entry and split it up
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-			if (!split_node)
-				return(NULL);
-
-			split_node->base = node->base + size;
-			split_node->length = node->length - size;
-			node->length = size;
-
-			// Put it in the list
-			split_node->next = node->next;
-			node->next = split_node;
-		}  // End of too big on top end
-
-		// For IO make sure it's not in the ISA aliasing space
-		if (node->base & 0x300L)
-			continue;
-
-		// If we got here, then it is the right size
-		// Now take it out of the list
-		if (*head == node) {
-			*head = node->next;
-		} else {
-			prevnode = *head;
-			while (prevnode->next != node)
-				prevnode = prevnode->next;
-
-			prevnode->next = node->next;
-		}
-		node->next = NULL;
-		// Stop looping
-		break;
-	}
-
-	return(node);
-}
-
-
-/*
- * get_max_resource
- *
- * Gets the largest node that is at least "size" big from the
- * list pointed to by head.  It aligns the node on top and bottom
- * to "size" alignment before returning it.
- */
-struct pci_resource *hotplug_get_max_resource (struct pci_resource **head, u32 size)
-{
-	struct pci_resource *max;
-	struct pci_resource *temp;
-	struct pci_resource *split_node;
-	u32 temp_dword;
-
-	if (!(*head))
-		return(NULL);
-
-	if (hotplug_resource_sort_and_combine(head))
-		return(NULL);
-
-	if (sort_by_max_size(head))
-		return(NULL);
-
-	for (max = *head;max; max = max->next) {
-
-		// If not big enough we could probably just bail, 
-		// instead we'll continue to the next.
-		if (max->length < size)
-			continue;
-
-		if (max->base & (size - 1)) {
-			// this one isn't base aligned properly
-			// so we'll make a new entry and split it up
-			temp_dword = (max->base | (size-1)) + 1;
-
-			// Short circuit if adjusted size is too small
-			if ((max->length - (temp_dword - max->base)) < size)
-				continue;
-
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-			if (!split_node)
-				return(NULL);
-
-			split_node->base = max->base;
-			split_node->length = temp_dword - max->base;
-			max->base = temp_dword;
-			max->length -= split_node->length;
-
-			// Put it next in the list
-			split_node->next = max->next;
-			max->next = split_node;
-		}
-
-		if ((max->base + max->length) & (size - 1)) {
-			// this one isn't end aligned properly at the top
-			// so we'll make a new entry and split it up
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-			if (!split_node)
-				return(NULL);
-			temp_dword = ((max->base + max->length) & ~(size - 1));
-			split_node->base = temp_dword;
-			split_node->length = max->length + max->base
-					     - split_node->base;
-			max->length -= split_node->length;
-
-			// Put it in the list
-			split_node->next = max->next;
-			max->next = split_node;
-		}
-
-		// Make sure it didn't shrink too much when we aligned it
-		if (max->length < size)
-			continue;
-
-		// Now take it out of the list
-		temp = (struct pci_resource*) *head;
-		if (temp == max) {
-			*head = max->next;
-		} else {
-			while (temp && temp->next != max) {
-				temp = temp->next;
-			}
-
-			temp->next = max->next;
-		}
-
-		max->next = NULL;
-		return(max);
-	}
-
-	// If we get here, we couldn't find one
-	return(NULL);
-}
-
-
-/*
- * get_resource
- *
- * this function sorts the resource list by size and then
- * returns the first node of "size" length.  If it finds a node
- * larger than "size" it will split it up.
- *
- * size must be a power of two.
- */
-struct pci_resource *hotplug_get_resource (struct pci_resource **head, u32 size)
-{
-	struct pci_resource *prevnode;
-	struct pci_resource *node;
-	struct pci_resource *split_node;
-	u32 temp_dword;
-
-	if (!(*head))
-		return(NULL);
-
-	if ( hotplug_resource_sort_and_combine(head) )
-		return(NULL);
-
-	if ( sort_by_size(head) )
-		return(NULL);
-
-	for (node = *head; node; node = node->next) {
-		dbg(__FUNCTION__": req_size =%x node=%p, base=%x, length=%x\n",
-		    size, node, node->base, node->length);
-		if (node->length < size)
-			continue;
-
-		if (node->base & (size - 1)) {
-			dbg(__FUNCTION__": not aligned\n");
-			// this one isn't base aligned properly
-			// so we'll make a new entry and split it up
-			temp_dword = (node->base | (size-1)) + 1;
-
-			// Short circuit if adjusted size is too small
-			if ((node->length - (temp_dword - node->base)) < size)
-				continue;
-
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-			if (!split_node)
-				return(NULL);
-
-			split_node->base = node->base;
-			split_node->length = temp_dword - node->base;
-			node->base = temp_dword;
-			node->length -= split_node->length;
-
-			// Put it in the list
-			split_node->next = node->next;
-			node->next = split_node;
-		} // End of non-aligned base
-
-		// Don't need to check if too small since we already did
-		if (node->length > size) {
-			dbg(__FUNCTION__": too big\n");
-			// this one is longer than we need
-			// so we'll make a new entry and split it up
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-			if (!split_node)
-				return(NULL);
-
-			split_node->base = node->base + size;
-			split_node->length = node->length - size;
-			node->length = size;
-
-			// Put it in the list
-			split_node->next = node->next;
-			node->next = split_node;
-		}  // End of too big on top end
-
-		dbg(__FUNCTION__": got one!!!\n");
-		// If we got here, then it is the right size
-		// Now take it out of the list
-		if (*head == node) {
-			*head = node->next;
-		} else {
-			prevnode = *head;
-			while (prevnode->next != node)
-				prevnode = prevnode->next;
-
-			prevnode->next = node->next;
-		}
-		node->next = NULL;
-		// Stop looping
-		break;
-	}
-	return(node);
-}
-
-/*
- * get_resource_with_base
- *
- * this function 
- * returns the first node of "size" length located at specified base address.
- * If it finds a node larger than "size" it will split it up.
- *
- * size must be a power of two.
- */
-struct pci_resource *hotplug_get_resource_with_base (struct pci_resource **head, u32 base, u32 size)
-{
-	struct pci_resource *prevnode;
-	struct pci_resource *node;
-	struct pci_resource *split_node;
-	u32 temp_dword;
-
-	if (!(*head))
-		return(NULL);
-
-	if ( hotplug_resource_sort_and_combine(head) )
-		return(NULL);
-
-	for (node = *head; node; node = node->next) {
-		dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
-		    base, size, node, node->base, node->length);
-		if (node->base > base)
-			continue;
-
-		if ((node->base + node->length) < (base + size))
-			continue;
-
-		if (node->base < base) {
-			dbg(": split 1\n");
-			// this one isn't base aligned properly
-			// so we'll make a new entry and split it up
-			temp_dword = base;
-
-			// Short circuit if adjusted size is too small
-			if ((node->length - (temp_dword - node->base)) < size)
-				continue;
-
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-			if (!split_node)
-				return(NULL);
-
-			split_node->base = node->base;
-			split_node->length = temp_dword - node->base;
-			node->base = temp_dword;
-			node->length -= split_node->length;
-
-			// Put it in the list
-			split_node->next = node->next;
-			node->next = split_node;
-		}
-
-		dbg(": 2st req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
-		    base, size, node, node->base, node->length);
-
-		// Don't need to check if too small since we already did
-		if (node->length >= size) {
-			dbg(": split 2\n");
-			// this one is longer than we need
-			// so we'll make a new entry and split it up
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-			if (!split_node)
-				return(NULL);
-
-			split_node->base = node->base + size;
-			split_node->length = node->length - size;
-			node->length = size;
-
-			// Put it in the list
-			split_node->next = node->next;
-			node->next = split_node;
-		}  // End of too big on top end
-
-		dbg(": got one!!!\n");
-		// If we got here, then it is the right size
-		// Now take it out of the list
-		if (*head == node) {
-			*head = node->next;
-		} else {
-			prevnode = *head;
-			while (prevnode->next != node)
-				prevnode = prevnode->next;
-
-			prevnode->next = node->next;
-		}
-		node->next = NULL;
-		// Stop looping
-		break;
-	}
-	return(node);
-}
-
-/*
- * hotplug_resource_sort_and_combine
- *
- * Sorts all of the nodes in the list in ascending order by
- * their base addresses.  Also does garbage collection by
- * combining adjacent nodes.
- *
- * returns 0 if success
- */
-int hotplug_resource_sort_and_combine(struct pci_resource **head)
-{
-	struct pci_resource *node1;
-	struct pci_resource *node2;
-	int out_of_order = 1;
-
-	dbg(__FUNCTION__": head = %p, *head = %p\n", head, *head);
-
-	if (!(*head))
-		return(1);
-
-	dbg("*head->next = %p\n",(*head)->next);
-
-	if (!(*head)->next)
-		return(0);	/* only one item on the list, already sorted! */
-
-	dbg("*head->base = 0x%x\n",(*head)->base);
-	dbg("*head->next->base = 0x%x\n",(*head)->next->base);
-	while (out_of_order) {
-		out_of_order = 0;
-
-		// Special case for swapping list head
-		if (((*head)->next) &&
-		    ((*head)->base > (*head)->next->base)) {
-			node1 = *head;
-			(*head) = (*head)->next;
-			node1->next = (*head)->next;
-			(*head)->next = node1;
-			out_of_order++;
-		}
-
-		node1 = (*head);
-
-		while (node1->next && node1->next->next) {
-			if (node1->next->base > node1->next->next->base) {
-				out_of_order++;
-				node2 = node1->next;
-				node1->next = node1->next->next;
-				node1 = node1->next;
-				node2->next = node1->next;
-				node1->next = node2;
-			} else
-				node1 = node1->next;
-		}
-	}  // End of out_of_order loop
-
-	node1 = *head;
-
-	while (node1 && node1->next) {
-		if ((node1->base + node1->length) == node1->next->base) {
-			// Combine
-			dbg("8..\n");
-			node1->length += node1->next->length;
-			node2 = node1->next;
-			node1->next = node1->next->next;
-			kfree(node2);
-		} else
-			node1 = node1->next;
-	}
-
-	return(0);
-}
-
-/*
-EXPORT_SYMBOL(hotplug_get_io_resource);
-EXPORT_SYMBOL(hotplug_get_max_resource);
-EXPORT_SYMBOL(hotplug_get_resource);
-EXPORT_SYMBOL(hotplug_resource_sort_and_combine);
-*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/hotplug/pcihp_acpi_glue.c linux-2.4.20/drivers/hotplug/pcihp_acpi_glue.c
--- linux-2.4.19/drivers/hotplug/pcihp_acpi_glue.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/hotplug/pcihp_acpi_glue.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,757 +0,0 @@
-/*
- * ACPI PCI HotPlug glue functions to ACPI CA subsystem
- *
- * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
- * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (c) 2002 NEC Corporation
- *
- * All rights reserved.
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT.  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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Send feedback to <t-kouchi@cq.jp.nec.com>
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include "pcihp_acpi.h"
-
-/*
- * TODO:
- * resource management
- * irq related interface? (_PRT)
- * consider locking
- */
-
-static LIST_HEAD(bridge_list);
-
-static int debug = 1;			/* XXX set 0 after debug */
-#define MY_NAME "pcihp_acpi_glue"
-
-static void handle_hotplug_event (acpi_handle, u32, void *);
-
-/*
- * initialization & terminatation routines
- */
-
-/*
- * Ejectable slot satisfies at least these conditions:
- *  1. has _ADR method
- *  2. has _STA method
- *  3. has _EJ0 method
- *
- * optionally
- *  1. has _PS0 method
- *  2. has _PS3 method
- *  3. TBD...
- */
-
-/* callback routine to check the existence of ejectable slots */
-static acpi_status
-is_ejectable_slot (acpi_handle handle, u32 lvl,	void *context, void **rv)
-{
-	acpi_status status;
-	acpi_handle tmp;
-	int *count = (int *)context;
-
-	status = acpi_get_handle(handle, "_ADR", &tmp);
-
-	if (ACPI_FAILURE(status)) {
-		return AE_OK;
-	}
-
-	status = acpi_get_handle(handle, "_STA", &tmp);
-
-	if (ACPI_FAILURE(status)) {
-		return AE_OK;
-	}
-
-	status = acpi_get_handle(handle, "_EJ0", &tmp);
-
-	if (ACPI_FAILURE(status)) {
-		return AE_OK;
-	}
-
-	(*count)++;
-
-	/* only one ejectable slot is enough */
-	return AE_CTRL_TERMINATE;
-}
-
-
-/* callback routine to register each ACPI PCI slot object */
-static acpi_status
-register_slot (acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-	struct pcihp_acpi_bridge *bridge = (struct pcihp_acpi_bridge *)context;
-	struct pcihp_acpi_slot *slot, *newslot;
-	acpi_handle tmp;
-	acpi_status status = AE_OK;
-	static int num_slots = 0;	/* XXX */
-	unsigned long adr, sun, sta;
-
-	status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
-
-	if (ACPI_FAILURE(status)) {
-		return AE_OK;
-	}
-
-	status = acpi_get_handle(handle, "_EJ0", &tmp);
-
-	if (ACPI_FAILURE(status)) {
-		dbg("This slot doesn't have _EJ0");
-		//return AE_OK;
-	}
-
-	status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
-
-	if (ACPI_FAILURE(status)) {
-		dbg("This slot doesn't have _STA");
-		//return AE_OK;
-	}
-
-	newslot = kmalloc(sizeof(struct pcihp_acpi_slot), GFP_KERNEL);
-	if (!newslot) {
-		return AE_NO_MEMORY;
-	}
-
-	memset(newslot, 0, sizeof(struct pcihp_acpi_slot));
-
-	INIT_LIST_HEAD(&newslot->sibling);
-	newslot->bridge = bridge;
-	newslot->handle = handle;
-	newslot->device = (adr >> 16) & 0xffff;
-	newslot->function = adr & 0xffff;
-	newslot->status = sta;
-	newslot->sun = -1;
-	newslot->flags = SLOT_HAS_EJ0;
-	newslot->id = num_slots++;
-	bridge->nr_slots++;
-
-	dbg("new slot id=%d device=0x%d function=0x%x", newslot->id, newslot->device, newslot->function);
-
-	status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
-	if (ACPI_SUCCESS(status)) {
-		newslot->sun = sun;
-	}
-
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp))) {
-		newslot->flags |= SLOT_HAS_PS0;
-	}
-
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) {
-		newslot->flags |= SLOT_HAS_PS3;
-	}
-
-	/* search for objects that share the same slot */
-	for (slot = bridge->slots; slot; slot = slot->next)
-		if (slot->device == newslot->device) {
-			dbg("found a sibling slot!");
-			list_add(&slot->sibling, &newslot->sibling);
-			newslot->id = slot->id;
-			num_slots --;
-			bridge->nr_slots --;
-			break;
-		}
-
-	/* link myself to bridge's slot list */
-	newslot->next = bridge->slots;
-	bridge->slots = newslot;
-
-	return AE_OK;
-}
-
-/* see if it's worth managing this brige */
-static int
-detect_ejectable_slots (acpi_handle *root)
-{
-	acpi_status status;
-	int count;
-
-	count = 0;
-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, root, ACPI_UINT32_MAX,
-				     is_ejectable_slot, (void *)&count, NULL);
-
-	dbg("%s: count=%d", __FUNCTION__, count);
-	return count;
-}
-
-
-/*
- * push one resource to resource list
- *
- * TBD: use hotplug_resource_sort_and_combine
- * TBD: 64bit resource handling (is it really used?)
- */
-static void
-push_resource (u32 base, u32 length, struct pci_resource **resource)
-{
-	struct pci_resource *resp, *newres;
-	int coalesced = 0;
-
-	if (length == 0) {
-		dbg("zero sized resource. ignored.");
-		return;
-	}
-
-	for (resp = *resource; resp; resp = resp->next) {
-
-		/* coalesce contiguous region */
-
-		if (resp->base + resp->length == base) {
-			resp->length += length;
-			coalesced = 1;
-			break;
-		}
-	}
-
-	if (!coalesced) {
-		newres = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-		if (!newres) {
-			/* TBD panic? */
-			return;
-		}
-		newres->base = base;
-		newres->length = length;
-		newres->next = (*resource);
-		*resource = newres;
-	}
-}
-
-
-/* decode ACPI _CRS data and convert into our internal resource list */
-static void
-decode_acpi_resource (acpi_resource *resource, struct pcihp_acpi_bridge *bridge)
-{
-	acpi_resource_address16 *address16_data;
-	acpi_resource_address32 *address32_data;
-	//acpi_resource_address64 *address64_data;
-
-	u32 resource_type, producer_consumer, min_address_range, max_address_range, address_length;
-	u16 cache_attribute = 0;
-
-	int done = 0, found;
-
-	/* shut up gcc */
-	resource_type = producer_consumer = min_address_range = max_address_range = address_length = 0;
-
-	while (!done) {
-		found = 0;
-
-		switch (resource->id) {
-		case ACPI_RSTYPE_ADDRESS16:
-			address16_data = (acpi_resource_address16 *)&resource->data;
-			resource_type = address16_data->resource_type;
-			producer_consumer = address16_data->producer_consumer;
-			min_address_range = address16_data->min_address_range;
-			max_address_range = address16_data->max_address_range;
-			address_length = address16_data->address_length;
-			if (resource_type == ACPI_MEMORY_RANGE)
-				cache_attribute = address16_data->attribute.memory.cache_attribute;
-			found = 1;
-			break;
-
-		case ACPI_RSTYPE_ADDRESS32:
-			address32_data = (acpi_resource_address32 *)&resource->data;
-			resource_type = address32_data->resource_type;
-			producer_consumer = address32_data->producer_consumer;
-			min_address_range = address32_data->min_address_range;
-			max_address_range = address32_data->max_address_range;
-			address_length = address32_data->address_length;
-			if (resource_type == ACPI_MEMORY_RANGE)
-				cache_attribute = address32_data->attribute.memory.cache_attribute;
-			found = 1;
-			break;
-/*
-		case ACPI_RSTYPE_ADDRESS64:
-			address64_data = (acpi_resource_address64 *)&resource->data;
-			resource_type = address64_data->resource_type;
-			break;
-*/
-		case ACPI_RSTYPE_END_TAG:
-			done = 1;
-			break;
-
-		default:
-			/* ignore */
-			break;
-		}
-
-		resource = (acpi_resource *)((char*)resource + resource->length);
-		if (found && producer_consumer == ACPI_PRODUCER) {
-			switch (resource_type) {
-			case ACPI_MEMORY_RANGE:
-				if (cache_attribute == ACPI_PREFETCHABLE_MEMORY) {
-					dbg("resource type: prefetchable memory 0x%x - 0x%x", min_address_range, max_address_range);
-					push_resource(min_address_range,
-						      address_length,
-						      &bridge->free_prefetch);
-				} else {
-					dbg("resource type: memory 0x%x - 0x%x", min_address_range, max_address_range);
-					push_resource(min_address_range,
-						      address_length,
-						      &bridge->free_mem);
-				}
-				break;
-			case ACPI_IO_RANGE:
-				dbg("resource type: io 0x%x - 0x%x", min_address_range, max_address_range);
-				push_resource(min_address_range,
-					      address_length,
-					      &bridge->free_io);
-				break;
-			case ACPI_BUS_NUMBER_RANGE:
-				dbg("resource type: bus number %d - %d", min_address_range, max_address_range);
-				push_resource(min_address_range,
-					      address_length,
-					      &bridge->free_bus);
-				break;
-			default:
-				/* invalid type */
-				break;
-			}
-		}
-	}
-}
-
-
-/* allocate and initialize bridge data structure */
-static int add_bridge (acpi_handle *handle)
-{
-	struct pcihp_acpi_bridge *bridge;
- 	acpi_status status;
-	acpi_buffer buffer;
-	unsigned long tmp;
-	acpi_handle dummy_handle;
-	int sta = -1;
-
-	status = acpi_get_handle(handle, "_STA", &dummy_handle);
-	if (ACPI_SUCCESS(status)) {
-		status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
-		if (ACPI_FAILURE(status)) {
-			dbg("%s: _STA evaluation failure", __FUNCTION__);
-			return 0;
-		}
-		sta = tmp;
-	}
-
-	if (sta >= 0 && !(sta & ACPI_STA_PRESENT))
-		/* don't register this object */
-		return 0;
-
-	dbg("%s: _STA: 0x%x", __FUNCTION__, (unsigned int)sta);
-
-	/* check if this bridge has ejectable slots */
-
-	detect_ejectable_slots(handle);
-	//if (detect_ejectable_slots(handle) == 0)
-	//return 0;
-
-	/* allocate per-bridge data structure and fill in */
-
-	bridge = kmalloc(sizeof(struct pcihp_acpi_bridge), GFP_KERNEL);
-	if (bridge == NULL)
-		return -ENOMEM;
-
-	memset(bridge, 0, sizeof(struct pcihp_acpi_bridge));
-
-	if (sta >= 0)
-		bridge->flags |= BRIDGE_HAS_STA;
-
-	/* get PCI segment number */
-	status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp);
-
-	if (ACPI_SUCCESS(status)) {
-		bridge->seg = tmp;
-	} else {
-		bridge->seg = 0;
-	}
-
-	/* get PCI bus number */
-	status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp);
-
-	if (ACPI_SUCCESS(status)) {
-		bridge->bus = tmp;
-	} else {
-		bridge->bus = 0;
-	}
-
-	/* to be overridden when we decode _CRS	*/
-	bridge->sub = bridge->bus;
-
-	/* register all slot objects under this bridge */
-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX,
-				     register_slot, bridge, NULL);
-
-	/* decode resources */
-	buffer.length = 0;
-	buffer.pointer = NULL;
-
-	
-	/* TBD use new ACPI_ALLOCATE_BUFFER */
-	status = acpi_get_current_resources(handle, &buffer);
-	if (status != AE_BUFFER_OVERFLOW) {
-		return -1;
-	}
-
-	buffer.pointer = kmalloc(buffer.length, GFP_KERNEL);
-	if (!buffer.pointer) {
-		return -1;
-	}
-
-	status = acpi_get_current_resources(handle, &buffer);
-	if (ACPI_FAILURE(status)) {
-		return -1;
-	}
-
-	decode_acpi_resource(buffer.pointer, bridge);
-
-	/* TBD decode _HPP (hot plug parameters) */
-	// decode_hpp(bridge);
-
-	kfree(buffer.pointer);
-
-	/* check already allocated resources */
-	/* TBD */
-
-	/* install notify handler */
-	dbg("installing notify handler");
-	status = acpi_install_notify_handler(handle,
-					     ACPI_SYSTEM_NOTIFY,
-					     handle_hotplug_event, NULL);
-
-	if (ACPI_FAILURE(status)) {
-		err("failed to register interrupt notify handler");
-	}
-
-	list_add(&bridge->list, &bridge_list);
-
-	return 0;
-}
-
-
-/* callback routine to enumerate all the bridges in ACPI namespace */
-static acpi_status
-check_pci_bridge (acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-	acpi_status status;
-	acpi_device_info info;
-	char objname[5];
-	acpi_buffer buffer = { sizeof(objname), objname };
-
-	status = acpi_get_object_info(handle, &info);
-	if (ACPI_FAILURE(status)) {
-		dbg("%s: failed to get bridge information", __FUNCTION__);
-		return AE_OK;		/* continue */
-	}
-
-	info.hardware_id[sizeof(info.hardware_id)-1] = '\0';
-
-	if (strcmp(info.hardware_id, ACPI_PCI_ROOT_HID) == 0) {
-
-		acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
-		dbg("%s: found PCI root bridge[%s]", __FUNCTION__, objname);
-
-		add_bridge(handle);
-	}
-	return AE_OK;
-}
-
-
-/* interrupt handler */
-static void handle_hotplug_event (acpi_handle handle, u32 type, void *data)
-{
-	char objname[5];
-	acpi_buffer buffer = { sizeof(objname), objname };
-
-	acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
-
-	switch (type) {
-	case ACPI_NOTIFY_BUS_CHECK:
-		/* hot insertion/surprise removal */
-		/* TBD */
-		dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
-		break;
-
-	case ACPI_NOTIFY_DEVICE_CHECK:
-		/* TBD */
-		dbg("%s: Device check notify on %s", __FUNCTION__, objname);
-		break;
-
-	case ACPI_NOTIFY_EJECT_REQUEST:
-		/* eject button pushed */
-		/* TBD */
-		dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
-		break;
-
-	default:
-		warn("notify_handler: unknown event type 0x%x", type);
-		break;
-	}
-}
-
-
-/*
- * external interfaces
- */
-
-int pcihp_acpi_glue_init (void)
-{
-	acpi_status status;
-
-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
-				     ACPI_UINT32_MAX, check_pci_bridge,
-				     NULL, NULL);
-
-	if (ACPI_FAILURE(status)) {
-		dbg("%s: acpi_walk_namespace() failed", __FUNCTION__);
-	}
-
-	return 0;
-}
-
-static void free_all_resources (struct pcihp_acpi_bridge *bridge)
-{
-	struct pci_resource *res, *next;;
-
-	for (res = bridge->free_io; res; ) {
-		next = res->next;
-		kfree(res);
-		res = next;
-	}
-
-	for (res = bridge->free_mem; res; ) {
-		next = res->next;
-		kfree(res);
-		res = next;
-	}
-
-	for (res = bridge->free_prefetch; res; ) {
-		next = res->next;
-		kfree(res);
-		res = next;
-	}
-
-	for (res = bridge->free_bus; res; ) {
-		next = res->next;
-		kfree(res);
-		res = next;
-	}
-}
-
-
-void pcihp_acpi_glue_exit (void)
-{
-	struct list_head *node;
-	struct pcihp_acpi_bridge *bridge;
-	struct pcihp_acpi_slot *slot, *next;
-
-	list_for_each(node, &bridge_list) {
-		bridge = (struct pcihp_acpi_bridge *)node;
-		slot = bridge->slots;
-		while (slot) {
-			next = slot->next;
-			kfree(slot);
-			slot = next;
-		}
-		free_all_resources(bridge);
-		kfree(bridge);
-	}
-}
-
-
-int pcihp_acpi_get_num_slots (void)
-{
-	struct list_head *node;
-	struct pcihp_acpi_bridge *bridge;
-	int num_slots;
-
-	num_slots = 0;
-
-	list_for_each(node, &bridge_list) {
-		bridge = (struct pcihp_acpi_bridge *)node;
-		dbg("Bus:%d num_slots:%d", bridge->bus, bridge->nr_slots);
-		num_slots += bridge->nr_slots;
-	}
-
-	dbg("num_slots = %d", num_slots);
-	return num_slots;
-}
-
-
-/*  TBD: improve performance */
-struct pcihp_acpi_slot *get_slot_from_id (int id)
-{
-	struct list_head *node;
-	struct pcihp_acpi_bridge *bridge;
-	struct pcihp_acpi_slot *slot;
-
-	list_for_each(node, &bridge_list) {
-		bridge = (struct pcihp_acpi_bridge *)node;
-		for (slot = bridge->slots; slot; slot = slot->next)
-			if (slot->id == id)
-				return slot;
-	}
-
-	/* should never happen! */
-	dbg("%s: no object for id %d",__FUNCTION__, id);
-	return 0;
-}
-
-
-/* power on slot */
-int pcihp_acpi_enable_slot (struct pcihp_acpi_slot *slot)
-{
-	acpi_status status;
-
-	if (slot->flags & SLOT_HAS_PS0) {
-		dbg("%s: powering on bus%d/dev%d.", __FUNCTION__,
-		    slot->bridge->bus, slot->device);
-		status = acpi_evaluate_object(slot->handle, "_PS0", NULL, NULL);
-		if (ACPI_FAILURE(status)) {
-			warn("%s: powering on bus%d/dev%d failed",
-			     __FUNCTION__, slot->bridge->bus, slot->device);
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-
-/* power off slot */
-int pcihp_acpi_disable_slot (struct pcihp_acpi_slot *slot)
-{
-	acpi_status status;
-
-	if (slot->flags & SLOT_HAS_PS3) {
-		dbg("%s: powering off bus%d/dev%d.", __FUNCTION__,
-		    slot->bridge->bus, slot->device);
-		status = acpi_evaluate_object(slot->handle, "_PS3", NULL, NULL);
-		if (ACPI_FAILURE(status)) {
-			warn("%s: _PS3 on bus%d/dev%d failed",
-			     __FUNCTION__, slot->bridge->bus, slot->device);
-			return -1;
-		}
-	}
-
-	if (slot->flags & SLOT_HAS_EJ0) {
-		dbg("%s: eject bus%d/dev%d.", __FUNCTION__,
-		    slot->bridge->bus, slot->device);
-		status = acpi_evaluate_object(slot->handle, "_EJ0", NULL, NULL);
-		if (ACPI_FAILURE(status)) {
-			warn("%s: _EJ0 bus%d/dev%d failed",
-			     __FUNCTION__, slot->bridge->bus, slot->device);
-			return -1;
-		}
-	}
-
-	/* TBD
-	 * evaluate _STA to check if state is successfully changed
-	 * and update status
-	 */
-
-	return 0;
-}
-
-
-static unsigned int get_slot_status(struct pcihp_acpi_slot *slot)
-{
-	acpi_status status;
-	unsigned long sta;
-
-	status = acpi_evaluate_integer(slot->handle, "_STA", NULL, &sta);
-
-	if (ACPI_FAILURE(status)) {
-		err("%s: _STA evaluation failed", __FUNCTION__);
-		return 0;
-	}
-
-	return (int)sta;
-}
-
-
-/*
- * slot enabled:  1
- * slot disabled: 0
- */
-u8 pcihp_acpi_get_power_status (struct pcihp_acpi_slot *slot)
-{
-	unsigned int sta;
-
-	/* TBD
-	 * . guarantee check _STA on function# 0
-	 * . check configuration space before _STA?
-	 */
-
-	sta = get_slot_status(slot);
-
-	return (sta & ACPI_STA_ENABLED) ? 1 : 0;
-}
-
-
-/* XXX this function is not used */
-/* 
- * attention LED ON: 1
- *              OFF: 0
- */
-u8 pcihp_acpi_get_attention_status (struct pcihp_acpi_slot *slot)
-{
-	/* TBD
-	 * no direct attention led status information via ACPI
-	 */
-
-	return 0;
-}
-
-
-/*
- * latch closed:  1
- * latch   open:  0
- */
-u8 pcihp_acpi_get_latch_status (struct pcihp_acpi_slot *slot)
-{
-	unsigned int sta;
-
-	/* TBD
-	 * no direct latch information via ACPI
-	 */
-
-	sta = get_slot_status(slot);
-
-	return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0;
-}
-
-
-/*
- * adapter presence : 2
- *          absence : 0
- */
-u8 pcihp_acpi_get_adapter_status (struct pcihp_acpi_slot *slot)
-{
-	unsigned int sta;
-
-	/* TBD
-	 * is this information correct?
-	 */
-
-	sta = get_slot_status(slot);
-
-	return (sta == 0) ? 0 : 2;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/i2c/i2c-core.c linux-2.4.20/drivers/i2c/i2c-core.c
--- linux-2.4.19/drivers/i2c/i2c-core.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/i2c/i2c-core.c	2002-10-29 11:18:33.000000000 +0000
@@ -656,7 +656,8 @@
 	struct inode * inode = file->f_dentry->d_inode;
 	char *kbuf;
 	struct i2c_client *client;
-	int i,j,k,order_nr,len=0,len_total;
+	int i,j,k,order_nr,len=0;
+	size_t len_total;
 	int order[I2C_CLIENT_MAX];
 
 	if (count > 4000)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/i2c/i2c-dev.c linux-2.4.20/drivers/i2c/i2c-dev.c
--- linux-2.4.19/drivers/i2c/i2c-dev.c	2001-10-11 15:05:47.000000000 +0000
+++ linux-2.4.20/drivers/i2c/i2c-dev.c	2002-10-29 11:18:34.000000000 +0000
@@ -159,6 +159,9 @@
 
 	struct i2c_client *client = (struct i2c_client *)file->private_data;
 
+	if(count > 8192)
+		count = 8192;
+		
 	/* copy user space data to kernel space. */
 	tmp = kmalloc(count,GFP_KERNEL);
 	if (tmp==NULL)
@@ -187,6 +190,9 @@
 	struct inode *inode = file->f_dentry->d_inode;
 #endif /* DEBUG */
 
+	if(count > 8192)
+		count = 8192;
+		
 	/* copy user space data to kernel space. */
 	tmp = kmalloc(count,GFP_KERNEL);
 	if (tmp==NULL)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/i2c/i2c-keywest.c linux-2.4.20/drivers/i2c/i2c-keywest.c
--- linux-2.4.19/drivers/i2c/i2c-keywest.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/i2c/i2c-keywest.c	2002-10-29 11:18:48.000000000 +0000
@@ -65,8 +65,6 @@
 
 #include "i2c-keywest.h"
 
-#undef POLLED_MODE
-
 #define DBG(x...) do {\
 	if (debug > 0) \
 		printk(KERN_DEBUG "KW:" x); \
@@ -85,27 +83,6 @@
 
 static struct keywest_iface *ifaces = NULL;
 
-#ifdef POLLED_MODE
-/* This isn't fast, but will go once I implement interrupt with
- * proper timeout
- */
-static u8
-wait_interrupt(struct keywest_iface* iface)
-{
-	int i;
-	u8 isr;
-	
-	for (i = 0; i < POLL_TIMEOUT; i++) {
-		isr = read_reg(reg_isr) & KW_I2C_IRQ_MASK;
-		if (isr != 0)
-			return isr;
-		current->state = TASK_UNINTERRUPTIBLE;
-		schedule_timeout(1);
-	}
-	return isr;
-}
-#endif /* POLLED_MODE */
-
 
 static void
 do_stop(struct keywest_iface* iface, int result)
@@ -116,16 +93,17 @@
 }
 
 /* Main state machine for standard & standard sub mode */
-static void
+static int
 handle_interrupt(struct keywest_iface *iface, u8 isr)
 {
 	int ack;
+	int rearm_timer = 1;
 	
 	DBG("handle_interrupt(), got: %x, status: %x, state: %d\n",
 		isr, read_reg(reg_status), iface->state);
 	if (isr == 0 && iface->state != state_stop) {
 		do_stop(iface, -1);
-		return;
+		return rearm_timer;
 	}
 	if (isr & KW_I2C_IRQ_STOP && iface->state != state_stop) {
 		iface->result = -1;
@@ -196,20 +174,19 @@
 		if (!(isr & KW_I2C_IRQ_STOP) && (++iface->stopretry) < 10)
 			do_stop(iface, -1);
 		else {
+			rearm_timer = 0;
 			iface->state = state_idle;
 			write_reg(reg_control, 0x00);
 			write_reg(reg_ier, 0x00);
-#ifndef POLLED_MODE
 			complete(&iface->complete);
-#endif /* POLLED_MODE */			
 		}
 		break;
 	}
 	
 	write_reg(reg_isr, isr);
-}
 
-#ifndef POLLED_MODE
+	return rearm_timer;
+}
 
 /* Interrupt handler */
 static void
@@ -219,8 +196,7 @@
 
 	spin_lock(&iface->lock);
 	del_timer(&iface->timeout_timer);
-	handle_interrupt(iface, read_reg(reg_isr));
-	if (iface->state != state_idle) {
+	if (handle_interrupt(iface, read_reg(reg_isr))) {
 		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
 		add_timer(&iface->timeout_timer);
 	}
@@ -234,16 +210,13 @@
 
 	DBG("timeout !\n");
 	spin_lock_irq(&iface->lock);
-	handle_interrupt(iface, read_reg(reg_isr));
-	if (iface->state != state_idle) {
+	if (handle_interrupt(iface, read_reg(reg_isr))) {
 		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
 		add_timer(&iface->timeout_timer);
 	}
 	spin_unlock(&iface->lock);
 }
 
-#endif /* POLLED_MODE */
-
 /*
  * SMBUS-type transfer entrypoint
  */
@@ -337,17 +310,7 @@
 	write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR);
 	write_reg(reg_ier, KW_I2C_IRQ_MASK);
 
-#ifdef POLLED_MODE
-	DBG("using polled mode...\n");
-	/* State machine, to turn into an interrupt handler */
-	while(iface->state != state_idle) {
-		u8 isr = wait_interrupt(iface);
-		handle_interrupt(iface, isr);
-	}
-#else /* POLLED_MODE */
-	DBG("using interrupt mode...\n");
 	wait_for_completion(&iface->complete);	
-#endif /* POLLED_MODE */	
 
 	rc = iface->result;	
 	DBG("transfer done, result: %d\n", rc);
@@ -427,17 +390,7 @@
 		write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR);
 		write_reg(reg_ier, KW_I2C_IRQ_MASK);
 
-#ifdef POLLED_MODE
-		DBG("using polled mode...\n");
-		/* State machine, to turn into an interrupt handler */
-		while(iface->state != state_idle) {
-			u8 isr = wait_interrupt(iface);
-			handle_interrupt(iface, isr);
-		}
-#else /* POLLED_MODE */
-		DBG("using interrupt mode...\n");
 		wait_for_completion(&iface->complete);	
-#endif /* POLLED_MODE */	
 
 		rc = iface->result;
 		if (rc == 0)
@@ -551,8 +504,8 @@
 			*prate);
 	}
 	
-	/* Select standard sub mode */
-	iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
+	/* Select standard mode by default */
+	iface->cur_mode |= KW_I2C_MODE_STANDARD;
 	
 	/* Write mode */
 	write_reg(reg_mode, iface->cur_mode);
@@ -561,7 +514,6 @@
 	write_reg(reg_ier, 0x00);
 	write_reg(reg_isr, KW_I2C_IRQ_MASK);
 
-#ifndef POLLED_MODE
 	/* Request chip interrupt */	
 	rc = request_irq(iface->irq, keywest_irq, 0, "keywest i2c", iface);
 	if (rc) {
@@ -570,7 +522,6 @@
 		kfree(iface);
 		return -ENODEV;
 	}
-#endif /* POLLED_MODE */
 
 	for (i=0; i<nchan; i++) {
 		struct keywest_chan* chan = &iface->channels[i];
@@ -622,19 +573,16 @@
 
 	/* Make sure we stop all activity */
 	down(&iface->sem);
-#ifndef POLLED_MODE
 	spin_lock_irq(&iface->lock);
 	while (iface->state != state_idle) {
 		spin_unlock_irq(&iface->lock);
-		schedule();
+		set_task_state(current,TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/10);
 		spin_lock_irq(&iface->lock);
 	}
-#endif /* POLLED_MODE */
 	iface->state = state_dead;
-#ifndef POLLED_MODE
 	spin_unlock_irq(&iface->lock);
 	free_irq(iface->irq, iface);
-#endif /* POLLED_MODE */
 	up(&iface->sem);
 
 	/* Release all channels */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ide/Config.in linux-2.4.20/drivers/ide/Config.in
--- linux-2.4.19/drivers/ide/Config.in	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ide/Config.in	2002-10-29 11:18:50.000000000 +0000
@@ -65,14 +65,14 @@
 	    dep_mbool '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3
 	    dep_bool '    AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_mbool '      AMD Viper ATA-66 Override (WIP)' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX $CONFIG_IDEDMA_PCI_WIP
-	    dep_bool '    CMD64X chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '    CMD64X and CMD680 chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '    CMD680 chipset tuning support' CONFIG_BLK_DEV_CMD680 $CONFIG_BLK_DEV_CMD64X
 	    dep_bool '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '    Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
   	    dep_bool '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_mbool '      HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP
 	    dep_bool '    HPT366/368/370 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
-	    if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then
+	    if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" -o "$CONFIG_MIPS" = "y" ]; then
 	       dep_mbool '    Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
 	       dep_mbool '      PIIXn Tuning support' CONFIG_PIIX_TUNING $CONFIG_BLK_DEV_PIIX $CONFIG_IDEDMA_PCI_AUTO
 	    fi
@@ -108,7 +108,7 @@
 	 fi
       fi
       if [ "$CONFIG_SIBYTE_SWARM" = "y" ]; then
-	 bool '  SWARM onboard IDE support' CONFIG_BLK_DEV_IDE_SWARM
+	 bool '  Broadcom SiByte onboard IDE support' CONFIG_BLK_DEV_IDE_SIBYTE
       fi
       if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
 	 dep_bool '    ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE $CONFIG_ARCH_ACORN
@@ -144,7 +144,8 @@
 		 EXT_DIRECT	CONFIG_IDE_EXT_DIRECT"	8xx_PCCARD
       fi
 
-      bool '  Other IDE chipset support' CONFIG_IDE_CHIPSETS
+      # no isa -> no vlb
+      dep_bool '  Other IDE chipset support' CONFIG_IDE_CHIPSETS $CONFIG_ISA
       if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
 	 comment 'Note: most of these also require special kernel boot parameters'
 	 bool '    Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
@@ -209,8 +210,8 @@
    define_bool CONFIG_BLK_DEV_IDE_MODES n
 fi
 
-dep_tristate 'Support for IDE Raid controllers' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL
-dep_tristate '   Support Promise software RAID (Fasttrak(tm))' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
-dep_tristate '   Highpoint 370 software RAID' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
+dep_tristate 'Support for IDE Raid controllers (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL
+dep_tristate '   Support Promise software RAID (Fasttrak(tm)) (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
+dep_tristate '   Highpoint 370 software RAID (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
 
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ide/Makefile linux-2.4.20/drivers/ide/Makefile
--- linux-2.4.19/drivers/ide/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ide/Makefile	2002-10-29 11:18:48.000000000 +0000
@@ -49,7 +49,7 @@
 ide-obj-$(CONFIG_BLK_DEV_IDEPCI)	+= ide-pci.o
 ide-obj-$(CONFIG_BLK_DEV_ISAPNP)	+= ide-pnp.o
 ide-obj-$(CONFIG_BLK_DEV_IDE_PMAC)	+= ide-pmac.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_SWARM)	+= ide-swarm.o
+ide-obj-$(CONFIG_BLK_DEV_IDE_SIBYTE)	+= ide-sibyte.o
 ide-obj-$(CONFIG_BLK_DEV_MAC_IDE)	+= macide.o
 ide-obj-$(CONFIG_BLK_DEV_NS87415)	+= ns87415.o
 ide-obj-$(CONFIG_BLK_DEV_OPTI621)	+= opti621.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ide/ataraid.c linux-2.4.20/drivers/ide/ataraid.c
--- linux-2.4.19/drivers/ide/ataraid.c	2001-10-25 20:58:35.000000000 +0000
+++ linux-2.4.20/drivers/ide/ataraid.c	2002-10-29 11:18:40.000000000 +0000
@@ -121,11 +121,8 @@
 	void *ptr = NULL;
 	while (!ptr) {
 		ptr=kmalloc(sizeof(struct buffer_head),GFP_NOIO);
-		if (!ptr) {
-			__set_current_state(TASK_RUNNING);
-	                current->policy |= SCHED_YIELD;
-	                schedule();             
-		}
+		if (!ptr)
+			yield();
 	}
 	return ptr;
 }
@@ -137,11 +134,8 @@
 	void *ptr = NULL;
 	while (!ptr) {
 		ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO);
-		if (!ptr) {
-			__set_current_state(TASK_RUNNING);
-	                current->policy |= SCHED_YIELD;
-	                schedule();             
-		}
+		if (!ptr)
+			yield();
 	}
 	return ptr;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ide/ide-cd.c linux-2.4.20/drivers/ide/ide-cd.c
--- linux-2.4.19/drivers/ide/ide-cd.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ide/ide-cd.c	2002-10-29 11:18:39.000000000 +0000
@@ -2194,6 +2194,8 @@
 	   layer. the packet must be complete, as we do not
 	   touch it at all. */
 	memset(&pc, 0, sizeof(pc));
+	if (cgc->sense)
+		memset(cgc->sense, 0, sizeof(struct request_sense));
 	memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE);
 	pc.buffer = cgc->buffer;
 	pc.buflen = cgc->buflen;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ide/ide-cs.c linux-2.4.20/drivers/ide/ide-cs.c
--- linux-2.4.19/drivers/ide/ide-cs.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ide/ide-cs.c	2002-10-29 11:18:36.000000000 +0000
@@ -15,7 +15,7 @@
     rights and limitations under the License.
 
     The initial developer of the original code is David A. Hinds
-    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ide/ide-disk.c linux-2.4.20/drivers/ide/ide-disk.c
--- linux-2.4.19/drivers/ide/ide-disk.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ide/ide-disk.c	2002-10-29 11:18:31.000000000 +0000
@@ -29,6 +29,7 @@
  * Version 1.10		request queue changes, Ultra DMA 100
  * Version 1.11		added 48-bit lba
  * Version 1.12		adding taskfile io access method
+ *			Highmem I/O support, Jens Axboe <axboe@suse.de>
  */
 
 #define IDEDISK_VERSION	"1.12"
@@ -158,7 +159,9 @@
 	byte stat;
 	int i;
 	unsigned int msect, nsect;
+	unsigned long flags;
 	struct request *rq;
+	char *to;
 
 	/* new way for dealing with premature shared PCI interrupts */
 	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
@@ -169,8 +172,8 @@
 		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
 		return ide_started;
 	}
+
 	msect = drive->mult_count;
-	
 read_next:
 	rq = HWGROUP(drive)->rq;
 	if (msect) {
@@ -179,14 +182,15 @@
 		msect -= nsect;
 	} else
 		nsect = 1;
-	idedisk_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
+	to = ide_map_buffer(rq, &flags);
+	idedisk_input_data(drive, to, nsect * SECTOR_WORDS);
 #ifdef DEBUG
 	printk("%s:  read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
 		drive->name, rq->sector, rq->sector+nsect-1,
 		(unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
 #endif
+	ide_unmap_buffer(to, &flags);
 	rq->sector += nsect;
-	rq->buffer += nsect<<9;
 	rq->errors = 0;
 	i = (rq->nr_sectors -= nsect);
 	if (((long)(rq->current_nr_sectors -= nsect)) <= 0)
@@ -220,14 +224,16 @@
 #endif
 		if ((rq->nr_sectors == 1) ^ ((stat & DRQ_STAT) != 0)) {
 			rq->sector++;
-			rq->buffer += 512;
 			rq->errors = 0;
 			i = --rq->nr_sectors;
 			--rq->current_nr_sectors;
 			if (((long)rq->current_nr_sectors) <= 0)
 				ide_end_request(1, hwgroup);
 			if (i > 0) {
-				idedisk_output_data (drive, rq->buffer, SECTOR_WORDS);
+				unsigned long flags;
+				char *to = ide_map_buffer(rq, &flags);
+				idedisk_output_data (drive, to, SECTOR_WORDS);
+				ide_unmap_buffer(to, &flags);
 				ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
                                 return ide_started;
 			}
@@ -257,14 +263,14 @@
   	do {
   		char *buffer;
   		int nsect = rq->current_nr_sectors;
- 
+		unsigned long flags;
+
 		if (nsect > mcount)
 			nsect = mcount;
 		mcount -= nsect;
-		buffer = rq->buffer;
 
+		buffer = ide_map_buffer(rq, &flags);
 		rq->sector += nsect;
-		rq->buffer += nsect << 9;
 		rq->nr_sectors -= nsect;
 		rq->current_nr_sectors -= nsect;
 
@@ -278,7 +284,7 @@
 			} else {
 				rq->bh = bh;
 				rq->current_nr_sectors = bh->b_size >> 9;
-				rq->buffer             = bh->b_data;
+				rq->hard_cur_sectors = rq->current_nr_sectors;
 			}
 		}
 
@@ -287,6 +293,7 @@
 		 * re-entering us on the last transfer.
 		 */
 		idedisk_output_data(drive, buffer, nsect<<7);
+		ide_unmap_buffer(buffer, &flags);
 	} while (mcount);
 
         return 0;
@@ -695,8 +702,11 @@
 				return ide_stopped;
 			}
 		} else {
+			unsigned long flags;
+			char *buffer = ide_map_buffer(rq, &flags);
 			ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
-			idedisk_output_data(drive, rq->buffer, SECTOR_WORDS);
+			idedisk_output_data(drive, buffer, SECTOR_WORDS);
+			ide_unmap_buffer(buffer, &flags);
 		}
 		return ide_started;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ide/ide-dma.c linux-2.4.20/drivers/ide/ide-dma.c
--- linux-2.4.19/drivers/ide/ide-dma.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ide/ide-dma.c	2002-10-29 11:18:34.000000000 +0000
@@ -252,33 +252,53 @@
 {
 	struct buffer_head *bh;
 	struct scatterlist *sg = hwif->sg_table;
+	unsigned long lastdataend = ~0UL;
 	int nents = 0;
 
 	if (hwif->sg_dma_active)
 		BUG();
-		
+
 	if (rq->cmd == READ)
 		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
 	else
 		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+
 	bh = rq->bh;
 	do {
-		unsigned char *virt_addr = bh->b_data;
-		unsigned int size = bh->b_size;
+		struct scatterlist *sge;
 
+		/*
+		 * continue segment from before?
+		 */
+		if (bh_phys(bh) == lastdataend) {
+			sg[nents - 1].length += bh->b_size;
+			lastdataend += bh->b_size;
+			continue;
+		}
+
+		/*
+		 * start new segment
+		 */
 		if (nents >= PRD_ENTRIES)
 			return 0;
 
-		while ((bh = bh->b_reqnext) != NULL) {
-			if ((virt_addr + size) != (unsigned char *) bh->b_data)
-				break;
-			size += bh->b_size;
+		sge = &sg[nents];
+		memset(sge, 0, sizeof(*sge));
+
+		if (bh->b_page) {
+			sge->page = bh->b_page;
+			sge->offset = bh_offset(bh);
+		} else {
+			if (((unsigned long) bh->b_data) < PAGE_SIZE)
+				BUG();
+
+			sge->address = bh->b_data;
 		}
-		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].address = virt_addr;
-		sg[nents].length = size;
+
+		sge->length = bh->b_size;
+		lastdataend = bh_phys(bh) + bh->b_size;
 		nents++;
-	} while (bh != NULL);
+	} while ((bh = bh->b_reqnext) != NULL);
 
 	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
 }
@@ -340,7 +360,7 @@
 		return 0;
 
 	sg = HWIF(drive)->sg_table;
-	while (i && sg_dma_len(sg)) {
+	while (i) {
 		u32 cur_addr;
 		u32 cur_len;
 
@@ -354,36 +374,35 @@
 		 */
 
 		while (cur_len) {
-			if (count++ >= PRD_ENTRIES) {
-				printk("%s: DMA table too small\n", drive->name);
-				goto use_pio_instead;
-			} else {
-				u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
+			u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
+			
+			if (count++ >= PRD_ENTRIES)
+				BUG();
+
+			if (bcount > cur_len)
+				bcount = cur_len;
+			*table++ = cpu_to_le32(cur_addr);
+			xcount = bcount & 0xffff;
+			if (is_trm290_chipset)
+				xcount = ((xcount >> 2) - 1) << 16;
+			if (xcount == 0x0000) {
+				/* 
+				 * Most chipsets correctly interpret a length
+				 * of 0x0000 as 64KB, but at least one
+				 * (e.g. CS5530) misinterprets it as zero (!).
+				 * So here we break the 64KB entry into two
+				 * 32KB entries instead.
+				 */
+				if (count++ >= PRD_ENTRIES)
+					goto use_pio_instead;
 
-				if (bcount > cur_len)
-					bcount = cur_len;
-				*table++ = cpu_to_le32(cur_addr);
-				xcount = bcount & 0xffff;
-				if (is_trm290_chipset)
-					xcount = ((xcount >> 2) - 1) << 16;
-				if (xcount == 0x0000) {
-					/* 
-					 * Most chipsets correctly interpret a length of 0x0000 as 64KB,
-					 * but at least one (e.g. CS5530) misinterprets it as zero (!).
-					 * So here we break the 64KB entry into two 32KB entries instead.
-					 */
-					if (count++ >= PRD_ENTRIES) {
-						printk("%s: DMA table too small\n", drive->name);
-						goto use_pio_instead;
-					}
-					*table++ = cpu_to_le32(0x8000);
-					*table++ = cpu_to_le32(cur_addr + 0x8000);
-					xcount = 0x8000;
-				}
-				*table++ = cpu_to_le32(xcount);
-				cur_addr += bcount;
-				cur_len -= bcount;
+				*table++ = cpu_to_le32(0x8000);
+				*table++ = cpu_to_le32(cur_addr + 0x8000);
+				xcount = 0x8000;
 			}
+			*table++ = cpu_to_le32(xcount);
+			cur_addr += bcount;
+			cur_len -= bcount;
 		}
 
 		sg++;
@@ -584,6 +603,23 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
 
+static inline void ide_toggle_bounce(ide_drive_t *drive, int on)
+{
+	dma64_addr_t addr = BLK_BOUNCE_HIGH;
+
+	if (HWIF(drive)->no_highio || HWIF(drive)->pci_dev == NULL)
+		return;
+
+	if (on && drive->media == ide_disk) {
+		if (!PCI_DMA_BUS_IS_PHYS)
+			addr = BLK_BOUNCE_ANY;
+		else
+			addr = HWIF(drive)->pci_dev->dma_mask;
+	}
+
+	blk_queue_bounce_limit(&drive->queue, addr);
+}
+
 /*
  * ide_dmaproc() initiates/aborts DMA read/write operations on a drive.
  *
@@ -606,18 +642,20 @@
 	ide_hwif_t *hwif		= HWIF(drive);
 	unsigned long dma_base		= hwif->dma_base;
 	byte unit			= (drive->select.b.unit & 0x01);
-	unsigned int count, reading	= 0;
+	unsigned int count, reading = 0, set_high = 1;
 	byte dma_stat;
 
 	switch (func) {
 		case ide_dma_off:
 			printk("%s: DMA disabled\n", drive->name);
 		case ide_dma_off_quietly:
+			set_high = 0;
 			outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
 		case ide_dma_on:
 			drive->using_dma = (func == ide_dma_on);
 			if (drive->using_dma)
 				outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+			ide_toggle_bounce(drive, set_high);
 			return 0;
 		case ide_dma_check:
 			return config_drive_for_dma (drive);
@@ -759,8 +797,8 @@
 	request_region(dma_base, num_ports, hwif->name);
 	hwif->dma_base = dma_base;
 	hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
-						  PRD_ENTRIES * PRD_BYTES,
-						  &hwif->dmatable_dma);
+						    PRD_ENTRIES * PRD_BYTES,
+						    &hwif->dmatable_dma);
 	if (hwif->dmatable_cpu == NULL)
 		goto dma_alloc_failure;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ide/ide-geometry.c linux-2.4.20/drivers/ide/ide-geometry.c
--- linux-2.4.19/drivers/ide/ide-geometry.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ide/ide-geometry.c	2002-10-29 11:18:31.000000000 +0000
@@ -32,7 +32,7 @@
  * for us during initialization.  I have the necessary docs -- any takers?  -ml
  */
 /*
- * I did this, but it doesnt work - there is no reasonable way to find the
+ * I did this, but it doesn't work - there is no reasonable way to find the
  * correspondence between the BIOS numbering of the disks and the Linux
  * numbering. -aeb
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ide/ide-pci.c linux-2.4.20/drivers/ide/ide-pci.c
--- linux-2.4.19/drivers/ide/ide-pci.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ide/ide-pci.c	2002-10-29 11:18:49.000000000 +0000
@@ -405,7 +405,7 @@
 #ifndef CONFIG_PDC202XX_FORCE
         {DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
         {DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-        {DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	48 },
+        {DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
         {DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
 #else /* !CONFIG_PDC202XX_FORCE */
 	{DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
@@ -623,8 +623,12 @@
 	}
 
 	if (pci_enable_device(dev)) {
-		printk(KERN_WARNING "%s: (ide_setup_pci_device:) Could not enable device.\n", d->name);
-		return;
+		if(pci_enable_device_bars(dev, 1<<4))
+		{
+			printk(KERN_WARNING "%s: (ide_setup_pci_device:) Could not enable device.\n", d->name);
+			return;
+		}
+		printk(KERN_INFO "%s: BIOS setup was incomplete.\n", d->name);
 	}
 
 check_if_enabled:
@@ -669,18 +673,27 @@
 	 */
 	pciirq = dev->irq;
 	
-#ifdef CONFIG_PDC202XX_FORCE
-	if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID) {
-		/*
-		 * By rights we want to ignore Promise FastTrak and SuperTrak
-		 * series here, those use own driver.
+	if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID)
+	{
+	    /*  By rights we want to ignore these, but the Promise Fastrak
+		 *	people have some strange ideas about proprietary so we have
+		 *	to act otherwise on those. The supertrak however we need
+		 *	to skip 
 		 */
-		if (dev->vendor == PCI_VENDOR_ID_PROMISE) {
-			printk(KERN_INFO "ide: Skipping Promise RAID controller.\n");
-			return;
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265))
+		{
+			printk(KERN_INFO "ide: Found promise 20265 in RAID mode.\n");
+			if(dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_INTEL &&
+			   dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960)
+			{
+				printk(KERN_INFO "ide: Skipping Promise PDC20265 attached to I2O RAID controller.\n");
+				return;
+			}
 		}
+		/* Its attached to something else, just a random bridge.
+		   Suspect a fastrak and fall through */
 	}
-#endif /* CONFIG_PDC202XX_FORCE */
+
 	if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) {
 		printk("%s: not 100%% native mode: will probe irqs later\n", d->name);
 		/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ide/ide-pmac.c linux-2.4.20/drivers/ide/ide-pmac.c
--- linux-2.4.19/drivers/ide/ide-pmac.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ide/ide-pmac.c	2002-10-29 11:18:49.000000000 +0000
@@ -114,8 +114,7 @@
  *    well, despite a comment that would lead to think it has a
  *    min value of 45ns.
  * Apple also add 60ns to the write data setup (or cycle time ?) on
- * reads. I can't explain that, I tried it and it broke everything
- * here.
+ * reads.
  */
 #define TR_66_UDMA_MASK			0xfff00000
 #define TR_66_UDMA_EN			0x00100000 /* Enable Ultra mode for DMA */
@@ -401,7 +400,6 @@
 pmac_ide_do_setfeature(ide_drive_t *drive, byte command)
 {
 	int result = 1;
-	unsigned long flags;
 	ide_hwif_t *hwif = HWIF(drive);
 	
 	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
@@ -420,10 +418,7 @@
 	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
 	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
 	udelay(1);
-	__save_flags(flags);	/* local CPU only */
-	ide__sti();		/* local CPU only -- for jiffies */
 	result = wait_for_ready(drive);
-	__restore_flags(flags); /* local CPU only */
 	OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
 	if (result)
 		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
@@ -956,6 +951,8 @@
 		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay;
 		hwif->udma_four = (pmhw->kind == controller_kl_ata4_80);
 		hwif->pci_dev = pdev;
+		hwif->drives[0].unmask = 1;
+		hwif->drives[1].unmask = 1;
 #ifdef CONFIG_PMAC_PBOOK
 		if (in_bay && check_media_bay_by_base(base, MB_CD) == 0)
 			hwif->noprobe = 0;
@@ -1032,33 +1029,48 @@
 	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
 	struct buffer_head *bh;
 	struct scatterlist *sg = pmif->sg_table;
+	unsigned long lastdataend = ~0UL;
 	int nents = 0;
 
 	if (hwif->sg_dma_active)
 		BUG();
-		
+
 	if (rq->cmd == READ)
 		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
 	else
 		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
+
 	bh = rq->bh;
 	do {
-		unsigned char *virt_addr = bh->b_data;
+		struct scatterlist *sge;
 		unsigned int size = bh->b_size;
 
+		/* continue segment from before? */
+		if (bh_phys(bh) == lastdataend) {
+			sg[nents-1].length += size;
+			lastdataend += size;
+			continue;
+		}
+
+		/* start new segment */
 		if (nents >= MAX_DCMDS)
 			return 0;
 
-		while ((bh = bh->b_reqnext) != NULL) {
-			if ((virt_addr + size) != (unsigned char *) bh->b_data)
-				break;
-			size += bh->b_size;
+		sge = &sg[nents];
+		memset(sge, 0, sizeof(*sge));
+
+		if (bh->b_page) {
+			sge->page = bh->b_page;
+			sge->offset = bh_offset(bh);
+		} else {
+			if ((unsigned long)bh->b_data < PAGE_SIZE)
+				BUG();
+			sge->address = bh->b_data;
 		}
-		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].address = virt_addr;
-		sg[nents].length = size;
+		sge->length = size;
+		lastdataend = bh_phys(bh) + size;
 		nents++;
-	} while (bh != NULL);
+	} while ((bh = bh->b_reqnext) != NULL);
 
 	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
 }
@@ -1330,6 +1342,23 @@
 	return 0;
 }
 
+static inline void pmac_ide_toggle_bounce(ide_drive_t *drive, int on)
+{
+	dma64_addr_t addr = BLK_BOUNCE_HIGH;
+
+	if (HWIF(drive)->no_highio || HWIF(drive)->pci_dev == NULL)
+		return;
+
+	if (on && drive->media == ide_disk) {
+		if (!PCI_DMA_BUS_IS_PHYS)
+			addr = BLK_BOUNCE_ANY;
+		else
+			addr = HWIF(drive)->pci_dev->dma_mask;
+	}
+
+	blk_queue_bounce_limit(&drive->queue, addr);
+}
+
 static int __pmac
 pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 {
@@ -1354,10 +1383,13 @@
 		printk(KERN_INFO "%s: DMA disabled\n", drive->name);
 	case ide_dma_off_quietly:
 		drive->using_dma = 0;
+		pmac_ide_toggle_bounce(drive, 0);
 		break;
 	case ide_dma_on:
 	case ide_dma_check:
 		pmac_ide_check_dma(drive);
+		if (drive->using_dma)
+			pmac_ide_toggle_bounce(drive, 1);
 		break;
 	case ide_dma_read:
 		reading = 1;
@@ -1612,7 +1644,14 @@
 
 /* Note: We support only master drives for now. This will have to be
  * improved if we want to handle sleep on the iMacDV where the CD-ROM
- * is a slave
+ * is a slave.
+ * 
+ * Well, actually, that sorta works on the iBook2 when the CD-ROM is
+ * a slave, though it will fail to spin_wait_hwgroup for the slave
+ * device as it is marked busy by the master sleep code. Well, it's
+ * probably not worth fixing now as we don't have sleep code for
+ * ATAPI devices anyway. Future kernels will hopefully deal with
+ * IDE PM in a more generic way.
  */
 static int __pmac
 idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ide/ide-probe.c linux-2.4.20/drivers/ide/ide-probe.c
--- linux-2.4.19/drivers/ide/ide-probe.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ide/ide-probe.c	2002-10-29 11:18:31.000000000 +0000
@@ -785,6 +785,7 @@
 	gd        = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
 	if (!gd)
 		goto err_kmalloc_gd;
+	memset (gd, 0, sizeof(struct gendisk));
 	gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
 	if (!gd->sizes)
 		goto err_kmalloc_gd_sizes;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ide/ide-sibyte.c linux-2.4.20/drivers/ide/ide-sibyte.c
--- linux-2.4.19/drivers/ide/ide-sibyte.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/ide/ide-sibyte.c	2002-10-29 11:18:47.000000000 +0000
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2001 Broadcom Corporation
+ *
+ * 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.
+ */
+
+/*  Derived loosely from ide-pmac.c, so:
+ *  
+ *  Copyright (C) 1998 Paul Mackerras.
+ *  Copyright (C) 1995-1998 Mark Lord
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_int.h>
+#include <asm/sibyte/sb1250_genbus.h>
+#include <asm/sibyte/64bit.h>
+#include <asm/sibyte/board.h>
+
+/* Note: this should be general for any board using IDE on GenBus */
+
+extern struct ide_ops std_ide_ops;
+
+static ide_hwif_t *sb_ide_hwif = NULL;
+static unsigned long ide_base;
+
+#define SIBYTE_IDE_BASE        (KSEG1ADDR(ide_base)-mips_io_port_base)
+#define SIBYTE_IDE_REG(pcaddr) (SIBYTE_IDE_BASE + ((pcaddr)<<5))
+
+/*
+ * We are limiting the number of PCI-IDE devices to leave room for
+ * GenBus IDE (and possibly PCMCIA/CF?)
+ */
+static int sibyte_ide_default_irq(ide_ioreg_t base)
+{
+	return 0;
+}
+
+static ide_ioreg_t sibyte_ide_default_io_base(int index)
+{
+	return 0;
+}
+
+static void sibyte_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port,
+				       ide_ioreg_t ctrl_port, int *irq)
+{
+	std_ide_ops.ide_init_hwif_ports(hw, data_port, ctrl_port, irq);
+}
+
+static int sibyte_ide_request_irq(unsigned int irq,
+                                void (*handler)(int,void *, struct pt_regs *),
+                                unsigned long flags, const char *device,
+                                void *dev_id)
+{
+	return request_irq(irq, handler, flags, device, dev_id);
+}
+
+static void sibyte_ide_free_irq(unsigned int irq, void *dev_id)
+{
+	free_irq(irq, dev_id);
+}
+
+static inline int is_sibyte_ide(ide_ioreg_t from)
+{
+	return (sb_ide_hwif &&
+		((from == sb_ide_hwif->io_ports[IDE_DATA_OFFSET]) ||
+		 (from == sb_ide_hwif->io_ports[IDE_ERROR_OFFSET]) ||
+		 (from == sb_ide_hwif->io_ports[IDE_NSECTOR_OFFSET]) ||
+		 (from == sb_ide_hwif->io_ports[IDE_SECTOR_OFFSET]) ||
+		 (from == sb_ide_hwif->io_ports[IDE_LCYL_OFFSET]) ||
+		 (from == sb_ide_hwif->io_ports[IDE_HCYL_OFFSET]) ||
+		 (from == sb_ide_hwif->io_ports[IDE_SELECT_OFFSET]) ||
+		 (from == sb_ide_hwif->io_ports[IDE_STATUS_OFFSET]) ||
+		 (from == sb_ide_hwif->io_ports[IDE_CONTROL_OFFSET])));
+}
+
+static int sibyte_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+	/* Figure out if it's the SiByte IDE; if so, don't do anything
+           since our I/O space is in a weird place. */
+	if (is_sibyte_ide(from))
+		return 0;
+	else
+#ifdef CONFIG_BLK_DEV_IDE
+		return std_ide_ops.ide_check_region(from, extent);
+#else
+		return 0;
+#endif
+}
+
+static void sibyte_ide_request_region(ide_ioreg_t from, unsigned int extent,
+				     const char *name)
+{
+#ifdef CONFIG_BLK_DEV_IDE
+	if (!is_sibyte_ide(from))
+		std_ide_ops.ide_request_region(from, extent, name);
+#endif
+}
+
+static void sibyte_ide_release_region(ide_ioreg_t from, unsigned int extent)
+{
+#ifdef CONFIG_BLK_DEV_IDE
+	if (!is_sibyte_ide(from))
+		std_ide_ops.ide_release_region(from, extent);
+#endif
+}
+
+struct ide_ops sibyte_ide_ops = {
+	&sibyte_ide_default_irq,
+	&sibyte_ide_default_io_base,
+	&sibyte_ide_init_hwif_ports,
+	&sibyte_ide_request_irq,
+	&sibyte_ide_free_irq,
+	&sibyte_ide_check_region,
+	&sibyte_ide_request_region,
+	&sibyte_ide_release_region
+};
+
+/*
+ * I/O operations. The FPGA for SiByte generic bus IDE deals with
+ * byte-swapping for us, so we can't share the I/O macros with other
+ * IDE (e.g. PCI-IDE) devices.
+ */
+
+#define sibyte_outb(val,port)					\
+do {								\
+	*(volatile u8 *)(mips_io_port_base + (port)) = val;	\
+} while(0)
+
+#define sibyte_outw(val,port)					\
+do {								\
+	*(volatile u16 *)(mips_io_port_base + (port)) = val;	\
+} while(0)
+
+#define sibyte_outl(val,port)					\
+do {								\
+	*(volatile u32 *)(mips_io_port_base + (port)) = val;	\
+} while(0)
+
+static inline unsigned char sibyte_inb(unsigned long port)
+{
+	return (*(volatile u8 *)(mips_io_port_base + (port)));
+}
+
+static inline unsigned short sibyte_inw(unsigned long port)
+{
+	return (*(volatile u16 *)(mips_io_port_base + (port)));
+}
+
+static inline unsigned int sibyte_inl(unsigned long port)
+{
+	return (*(volatile u32 *)(mips_io_port_base + (port)));
+}
+
+
+static inline void sibyte_outsb(unsigned long port, void *addr, unsigned int count)
+{
+	while (count--) {
+		sibyte_outb(*(u8 *)addr, port);
+		addr++;
+	}
+}
+
+static inline void sibyte_insb(unsigned long port, void *addr, unsigned int count)
+{
+	while (count--) {
+		*(u8 *)addr = sibyte_inb(port);
+		addr++;
+	}
+}
+
+static inline void sibyte_outsw(unsigned long port, void *addr, unsigned int count)
+{
+	while (count--) {
+		sibyte_outw(*(u16 *)addr, port);
+		addr += 2;
+	}
+}
+
+static inline void sibyte_insw(unsigned long port, void *addr, unsigned int count)
+{
+	while (count--) {
+		*(u16 *)addr = sibyte_inw(port);
+		addr += 2;
+	}
+}
+
+static inline void sibyte_outsl(unsigned long port, void *addr, unsigned int count)
+{
+	while (count--) {
+		sibyte_outl(*(u32 *)addr, port);
+		addr += 4;
+	}
+}
+
+static inline void sibyte_insl(unsigned long port, void *addr, unsigned int count)
+{
+	while (count--) {
+		*(u32 *)addr = sibyte_inl(port);
+		addr += 4;
+	}
+}
+
+static void sibyte_ideproc(ide_ide_action_t action, ide_drive_t *drive,
+			   void *buffer, unsigned int count)
+{
+	/*  slow? vlb_sync? */
+	switch (action) {
+	case ideproc_ide_input_data:
+		if (drive->io_32bit) {
+			sibyte_insl(IDE_DATA_REG, buffer, count);
+		} else {
+			sibyte_insw(IDE_DATA_REG, buffer, count<<1);
+		}
+		break;
+	case ideproc_ide_output_data:
+		if (drive->io_32bit) {
+			sibyte_outsl(IDE_DATA_REG, buffer, count);
+		} else {
+			sibyte_outsw(IDE_DATA_REG, buffer, count<<1);
+		}
+		break;
+	case ideproc_atapi_input_bytes:
+		count++;
+		if (drive->io_32bit) {
+			sibyte_insl(IDE_DATA_REG, buffer, count>>2);
+		} else {
+			sibyte_insw(IDE_DATA_REG, buffer, count>>1);
+		}
+		if ((count & 3) >= 2)
+			sibyte_insw(IDE_DATA_REG, (char *)buffer + (count & ~3), 1);
+		break;
+	case ideproc_atapi_output_bytes:
+		count++;
+		if (drive->io_32bit) {
+			sibyte_outsl(IDE_DATA_REG, buffer, count>>2);
+		} else {
+			sibyte_outsw(IDE_DATA_REG, buffer, count>>1);
+		}
+		if ((count & 3) >= 2)
+			sibyte_outsw(IDE_DATA_REG, (char *)buffer + (count & ~3), 1);
+		break;
+	}
+}
+
+/*
+ * selectproc and intrproc aren't really necessary, since
+ * byte-swapping doesn't affect byte ops; they are included for
+ * consistency.
+ */
+static void sibyte_selectproc(ide_drive_t *drive)
+{
+	sibyte_outb(drive->select.all, IDE_SELECT_REG);
+}
+
+static void sibyte_intrproc(ide_drive_t *drive)
+{
+	sibyte_outb(drive->ctl|2, IDE_CONTROL_REG);
+}
+
+void __init sibyte_ide_probe(void)
+{
+	int i;
+	ide_hwif_t *hwif;
+	/* 
+	 * Find the first untaken slot in hwifs 
+	 */
+	for (i = 0; i < MAX_HWIFS; i++) {
+		if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) {
+			break;
+		}
+	}
+	if (i == MAX_HWIFS) {
+		printk("No space for SiByte onboard IDE driver in ide_hwifs[].  Not enabled.\n");
+		return;
+	}
+
+	/* Find memory base address */
+#ifdef __MIPSEL__
+	/* Pass1 workaround (bug 1624) */
+	if (sb1250_pass == K_SYS_REVISION_PASS1)
+		ide_base = G_IO_START_ADDR(csr_in32(4+(IO_SPACE_BASE|A_IO_EXT_REG(R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS))))) << S_IO_ADDRBASE;
+	else
+#endif
+		ide_base = G_IO_START_ADDR(csr_in32(IO_SPACE_BASE|A_IO_EXT_REG(R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS)))) << S_IO_ADDRBASE;
+
+	/*
+	 * Set up our stuff; we're a little odd because our io_ports
+	 * aren't in the usual place, and byte-swapping isn't
+	 * necessary.
+	 */
+	hwif = &ide_hwifs[i];
+	hwif->hw.io_ports[IDE_DATA_OFFSET]    = SIBYTE_IDE_REG(0x1f0);
+	hwif->hw.io_ports[IDE_ERROR_OFFSET]   = SIBYTE_IDE_REG(0x1f1);
+	hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SIBYTE_IDE_REG(0x1f2);
+	hwif->hw.io_ports[IDE_SECTOR_OFFSET]  = SIBYTE_IDE_REG(0x1f3);
+	hwif->hw.io_ports[IDE_LCYL_OFFSET]    = SIBYTE_IDE_REG(0x1f4);
+	hwif->hw.io_ports[IDE_HCYL_OFFSET]    = SIBYTE_IDE_REG(0x1f5);
+	hwif->hw.io_ports[IDE_SELECT_OFFSET]  = SIBYTE_IDE_REG(0x1f6);
+	hwif->hw.io_ports[IDE_STATUS_OFFSET]  = SIBYTE_IDE_REG(0x1f7);
+	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SIBYTE_IDE_REG(0x3f6);
+	hwif->hw.irq                          = K_INT_GB_IDE;
+	hwif->irq                             = K_INT_GB_IDE;
+	hwif->noprobe                         = 0;
+	/* Use our own non-byte-swapping routines */
+	hwif->ideproc                         = sibyte_ideproc;
+	hwif->selectproc                      = sibyte_selectproc;
+	hwif->intrproc                        = sibyte_intrproc;
+
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+	printk("SiByte onboard IDE configured as device %i\n", i);
+	sb_ide_hwif = hwif;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ide/ide-swarm.c linux-2.4.20/drivers/ide/ide-swarm.c
--- linux-2.4.19/drivers/ide/ide-swarm.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ide/ide-swarm.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2001 Broadcom Corporation
- *
- * 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.
- */
-
-/*  Derived loosely from ide-pmac.c, so:
- *  
- *  Copyright (C) 1998 Paul Mackerras.
- *  Copyright (C) 1995-1998 Mark Lord
- */
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/sibyte/sb1250_int.h>
-#include <asm/sibyte/swarm_ide.h>
-
-void __init swarm_ide_probe(void)
-{
-	int i;
-	ide_hwif_t *hwif;
-	/* 
-	 * Find the first untaken slot in hwifs 
-	 */
-	for (i = 0; i < MAX_HWIFS; i++) {
-		if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) {
-			break;
-		}
-	}
-	if (i == MAX_HWIFS) {
-		printk("No space for SWARM onboard IDE driver in ide_hwifs[].  Not enabled.\n");
-		return;
-	}
-
-	/* Set up our stuff */
-	hwif = &ide_hwifs[i];
-	hwif->hw.io_ports[IDE_DATA_OFFSET]    = SWARM_IDE_REG(0x1f0);
-	hwif->hw.io_ports[IDE_ERROR_OFFSET]   = SWARM_IDE_REG(0x1f1);
-	hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SWARM_IDE_REG(0x1f2);
-	hwif->hw.io_ports[IDE_SECTOR_OFFSET]  = SWARM_IDE_REG(0x1f3);
-	hwif->hw.io_ports[IDE_LCYL_OFFSET]    = SWARM_IDE_REG(0x1f4);
-	hwif->hw.io_ports[IDE_HCYL_OFFSET]    = SWARM_IDE_REG(0x1f5);
-	hwif->hw.io_ports[IDE_SELECT_OFFSET]  = SWARM_IDE_REG(0x1f6);
-	hwif->hw.io_ports[IDE_STATUS_OFFSET]  = SWARM_IDE_REG(0x1f7);
-	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SWARM_IDE_REG(0x3f6);
-	hwif->hw.io_ports[IDE_IRQ_OFFSET]     = SWARM_IDE_REG(0x3f7);
-//	hwif->hw->ack_intr                     = swarm_ide_ack_intr;
-	hwif->hw.irq                          = SWARM_IDE_INT;
-	hwif->ideproc                         = swarm_ideproc;
-
-	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-	hwif->irq = hwif->hw.irq;
-	printk("SWARM onboard IDE configured as device %i\n", i);
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ide/ide.c linux-2.4.20/drivers/ide/ide.c
--- linux-2.4.19/drivers/ide/ide.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ide/ide.c	2002-10-29 11:18:50.000000000 +0000
@@ -3418,7 +3418,7 @@
 		const char *ide_words[] = {
 			"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66",
 			"minus8", "minus9", "minus10",
-			"four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
+			"four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", "nohighio", NULL };
 		hw = s[3] - '0';
 		hwif = &ide_hwifs[hw];
 		i = match_parm(&s[4], ide_words, vals, 3);
@@ -3437,6 +3437,10 @@
 		}
 
 		switch (i) {
+			case -19: /* nohighio */
+				hwif->no_highio = 1;
+				printk("%s: disabled high i/o capability\n", hwif->name);
+				goto done;
 #ifdef CONFIG_BLK_DEV_PDC4030
 			case -18: /* "dc4030" */
 			{
@@ -3616,12 +3620,12 @@
 		pmac_ide_probe();
 	}
 #endif /* CONFIG_BLK_DEV_IDE_PMAC */
-#ifdef CONFIG_BLK_DEV_IDE_SWARM
+#ifdef CONFIG_BLK_DEV_IDE_SIBYTE
 	{
-		extern void swarm_ide_probe(void);
-		swarm_ide_probe();
+		extern void sibyte_ide_probe(void);
+		sibyte_ide_probe();
 	}
-#endif /* CONFIG_BLK_DEV_IDE_SWARM */
+#endif /* CONFIG_BLK_DEV_IDE_SIBYTE */
 #ifdef CONFIG_BLK_DEV_IDE_ICSIDE
 	{
 		extern void icside_init(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ide/q40ide.c linux-2.4.20/drivers/ide/q40ide.c
--- linux-2.4.19/drivers/ide/q40ide.c	2001-10-25 20:53:47.000000000 +0000
+++ linux-2.4.20/drivers/ide/q40ide.c	2002-10-29 11:18:48.000000000 +0000
@@ -82,8 +82,8 @@
     for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
 	hw_regs_t hw;
 
-	ide_setup_ports(&hw,(ide_ioreg_t) pcide_bases[i], (int *)pcide_offsets, 
-			pcide_bases[i]+0x206, 
+	ide_setup_ports(&hw, (ide_ioreg_t)pcide_bases[i], (int *)pcide_offsets,
+			(ide_ioreg_t)pcide_bases[i]+0x206,
 			0, NULL, q40ide_default_irq(pcide_bases[i]));
 	ide_register_hw(&hw, NULL);
     }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/amdtp.c linux-2.4.20/drivers/ieee1394/amdtp.c
--- linux-2.4.19/drivers/ieee1394/amdtp.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/amdtp.c	2002-10-29 11:18:49.000000000 +0000
@@ -46,8 +46,6 @@
  *
  * - Fix DMA stop after bus reset!
  *
- * - Implement poll.
- *
  * - Clean up iso context handling in ohci1394.
  *
  *
@@ -75,6 +73,7 @@
 #include <linux/wait.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
+#include <linux/poll.h>
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
 
@@ -121,17 +120,40 @@
 	dma_addr_t payload_bus;
 };
 
-#ifdef __BIG_ENDIAN_BITFIELD
+#include <asm/byteorder.h>
 
-#error Big endian bitfields not tested
+#if defined __BIG_ENDIAN_BITFIELD
 
-#else
+struct iso_packet {
+	/* First quadlet */
+	unsigned int dbs      : 8;
+	unsigned int eoh0     : 2;
+	unsigned int sid      : 6;
+
+	unsigned int dbc      : 8;
+	unsigned int fn       : 2;
+	unsigned int qpc      : 3;
+	unsigned int sph      : 1;
+	unsigned int reserved : 2;
+
+	/* Second quadlet */
+	unsigned int fdf      : 8;
+	unsigned int eoh1     : 2;
+	unsigned int fmt      : 6;
+
+	unsigned int syt      : 16;
+
+        quadlet_t data[0];
+};
+
+#elif defined __LITTLE_ENDIAN_BITFIELD
 
 struct iso_packet {
 	/* First quadlet */
 	unsigned int sid      : 6;
 	unsigned int eoh0     : 2;
 	unsigned int dbs      : 8;
+
 	unsigned int reserved : 2;
 	unsigned int sph      : 1;
 	unsigned int qpc      : 3;
@@ -142,11 +164,16 @@
 	unsigned int fmt      : 6;
 	unsigned int eoh1     : 2;
 	unsigned int fdf      : 8;
+
 	unsigned int syt      : 16;
 
 	quadlet_t data[0];
 };
 
+#else
+
+#error Unknown bitfield type
+
 #endif
 
 struct fraction {
@@ -169,7 +196,7 @@
 /* This implements a circular buffer for incoming samples. */
 
 struct buffer {
-	int head, tail, length, size;
+	size_t head, tail, length, size;
 	unsigned char data[0];
 };
 
@@ -224,7 +251,7 @@
 	struct list_head free_packet_lists;
         wait_queue_head_t packet_list_wait;
 	spinlock_t packet_list_lock;
-	int iso_context;
+	struct ohci1394_iso_tasklet iso_tasklet;
 	struct pci_pool *descriptor_pool, *packet_pool;
 
 	/* Streams at a host controller are chained through this field. */
@@ -252,23 +279,6 @@
 #define OHCI1394_CONTEXT_DEAD        0x00000800
 #define OHCI1394_CONTEXT_ACTIVE      0x00000400
 
-static inline int ohci1394_alloc_it_ctx(struct ti_ohci *ohci)
-{
-	int i;
-
-	for (i = 0; i < ohci->nb_iso_xmit_ctx; i++)
-		if (!test_and_set_bit(i, &ohci->it_ctx_usage))
-			return i;
-
-	return -EBUSY;
-}
-	
-static inline void ohci1394_free_it_ctx(struct ti_ohci *ohci, int ctx)
-{
-	clear_bit(ctx, &ohci->it_ctx_usage);
-}
-
-
 void ohci1394_start_it_ctx(struct ti_ohci *ohci, int ctx,
 			   dma_addr_t first_cmd, int z, int cycle_match)
 {
@@ -347,7 +357,7 @@
 	if ((start_cycle & 0x1fff) >= 8000)
 		start_cycle = start_cycle - 8000 + 0x2000;
 
-	ohci1394_start_it_ctx(s->host->ohci, s->iso_context,
+	ohci1394_start_it_ctx(s->host->ohci, s->iso_tasklet.context,
 			      pl->packets[0].db_bus, 3,
 			      start_cycle & 0x7fff);
 }
@@ -370,14 +380,16 @@
 	if (pl->link.prev != &s->dma_packet_lists) {
 		struct packet *last = &prev->packets[PACKET_LIST_SIZE - 1];
 		last->db->payload_desc.branch = pl->packets[0].db_bus | 3;
-		ohci1394_wake_it_ctx(s->host->ohci, s->iso_context);
+		last->db->header_desc.skip = pl->packets[0].db_bus | 3;
+		ohci1394_wake_it_ctx(s->host->ohci, s->iso_tasklet.context);
 	}
 	else
 		stream_start_dma(s, pl);
 }
 
-static void stream_shift_packet_lists(struct stream *s)
+static void stream_shift_packet_lists(unsigned long l)
 {
+	struct stream *s = (struct stream *) l;
 	struct packet_list *pl;
 	struct packet *last;
 	int diff;
@@ -511,25 +523,6 @@
 	return frac->integer + (frac->numerator > 0 ? 1 : 0);
 }
 
-static void amdtp_irq_handler(int card, quadlet_t isoRecvIntEvent,
-			      quadlet_t isoXmitIntEvent, void *data)
-{
-	struct amdtp_host *host = data;
-	struct list_head *lh;
-	struct stream *s = NULL;
-
-	spin_lock(&host->stream_list_lock);
-	list_for_each(lh, &host->stream_list) {
-		s = list_entry(lh, struct stream, link);
-		if (isoXmitIntEvent & (1 << s->iso_context))
-			break;
-	}
-	spin_unlock(&host->stream_list_lock);
-
-	if (s != NULL)
-		stream_shift_packet_lists(s);
-}
-
 void packet_initialize(struct packet *p, struct packet *next)
 {
 	/* Here we initialize the dma descriptor block for
@@ -541,18 +534,19 @@
 
 	p->db->header_desc.control =
 		DMA_CTL_OUTPUT_MORE | DMA_CTL_IMMEDIATE | 8;
-	p->db->header_desc.skip = 0;
 
 	if (next) {
 		p->db->payload_desc.control = 
 			DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH;
 		p->db->payload_desc.branch = next->db_bus | 3;
+		p->db->header_desc.skip = next->db_bus | 3;
 	}
 	else {
 		p->db->payload_desc.control = 
 			DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH |
 			DMA_CTL_UPDATE | DMA_CTL_IRQ;
 		p->db->payload_desc.branch = 0;
+		p->db->header_desc.skip = 0;
 	}
 	p->db->payload_desc.data_address = p->payload_bus;
 	p->db->payload_desc.status = 0;
@@ -629,9 +623,9 @@
 }
 
 static unsigned char *buffer_put_bytes(struct buffer *buffer,
-				       int max, int *actual)
+				       size_t max, size_t *actual)
 {
-	int length;
+	size_t length;
 	unsigned char *p;
 
 	p = &buffer->data[buffer->tail];
@@ -889,7 +883,7 @@
 		stream_start_dma(s, pl);
 	}
 	else {
-		ohci1394_stop_it_ctx(s->host->ohci, s->iso_context, 0);
+		ohci1394_stop_it_ctx(s->host->ohci, s->iso_tasklet.context, 0);
 	}
 }
 
@@ -1039,8 +1033,11 @@
         init_waitqueue_head(&s->packet_list_wait);
         spin_lock_init(&s->packet_list_lock);
 
-	s->iso_context = ohci1394_alloc_it_ctx(host->ohci);
-	if (s->iso_context < 0) {
+	ohci1394_init_iso_tasklet(&s->iso_tasklet, OHCI_ISO_TRANSMIT,
+				  stream_shift_packet_lists,
+				  (unsigned long) s);
+
+	if (ohci1394_register_iso_tasklet(host->ohci, &s->iso_tasklet) < 0) {
 		pci_pool_destroy(s->descriptor_pool);
 		kfree(s->input);
 		kfree(s);
@@ -1067,8 +1064,8 @@
 	wait_event_interruptible(s->packet_list_wait, 
 				 list_empty(&s->dma_packet_lists));
 
-	ohci1394_stop_it_ctx(s->host->ohci, s->iso_context, 1);
-	ohci1394_free_it_ctx(s->host->ohci, s->iso_context);
+	ohci1394_stop_it_ctx(s->host->ohci, s->iso_tasklet.context, 1);
+	ohci1394_unregister_iso_tasklet(s->host->ohci, &s->iso_tasklet);
 
 	if (s->opcr != NULL)
 		cmp_unregister_opcr(s->host->host, s->opcr);
@@ -1092,7 +1089,8 @@
 {
 	struct stream *s = file->private_data;
 	unsigned char *p;
-	int i, length;
+	int i;
+	size_t length;
 	
 	if (s->packet_pool == NULL)
 		return -EBADFD;
@@ -1116,8 +1114,13 @@
 		
 		stream_flush(s);
 		
-		if (s->current_packet_list == NULL &&
-		    wait_event_interruptible(s->packet_list_wait, 
+		if (s->current_packet_list != NULL)
+			continue;
+
+		if (file->f_flags & O_NONBLOCK)
+			return i + length > 0 ? i + length : -EAGAIN;
+
+		if (wait_event_interruptible(s->packet_list_wait, 
 					     !list_empty(&s->free_packet_lists)))
 			return -EINTR;
 	}
@@ -1130,7 +1133,6 @@
 {
 	struct stream *s = file->private_data;
 	struct amdtp_ioctl cfg;
-	int new;
 
 	switch(cmd)
 	{
@@ -1141,23 +1143,23 @@
 		else 
 			return stream_configure(s, cmd, &cfg);
 
-	case AMDTP_IOC_PING:
-		HPSB_INFO("ping: offsetting timpestamps %ld ticks", arg);
-		new = s->cycle_offset.integer + arg;
-		s->cycle_offset.integer = new % 3072;
-		atomic_add(new / 3072, &s->cycle_count);
-		return 0;
-
-	case AMDTP_IOC_ZAP:
-		while (MOD_IN_USE)
-			MOD_DEC_USE_COUNT;
-		return 0;
-
 	default:
 		return -EINVAL;
 	}
 }
 
+static unsigned int amdtp_poll(struct file *file, poll_table *pt)
+{
+	struct stream *s = file->private_data;
+
+	poll_wait(file, &s->packet_list_wait, pt);
+
+	if (!list_empty(&s->free_packet_lists))
+		return POLLOUT | POLLWRNORM;
+	else
+		return 0;
+}
+
 static int amdtp_open(struct inode *inode, struct file *file)
 {
 	struct amdtp_host *host;
@@ -1193,6 +1195,7 @@
 {
 	.owner =	THIS_MODULE,
 	.write =	amdtp_write,
+	.poll =		amdtp_poll,
 	.ioctl =	amdtp_ioctl,
 	.open =		amdtp_open,
 	.release =	amdtp_release
@@ -1204,7 +1207,8 @@
 {
 	struct amdtp_host *ah;
 
-	/* FIXME: check it's an ohci host. */
+	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME) != 0)
+		return;
 
 	ah = kmalloc(sizeof *ah, SLAB_KERNEL);
 	ah->host = host;
@@ -1215,8 +1219,6 @@
 	spin_lock_irq(&host_list_lock);
 	list_add_tail(&ah->link, &host_list);
 	spin_unlock_irq(&host_list_lock);
-
-	ohci1394_hook_irq(ah->ohci, amdtp_irq_handler, ah);
 }
 
 static void amdtp_remove_host(struct hpsb_host *host)
@@ -1235,7 +1237,6 @@
 	
 	if (lh != &host_list) {
 		ah = list_entry(lh, struct amdtp_host, link);
-		ohci1394_unhook_irq(ah->ohci, amdtp_irq_handler, ah);
 		kfree(ah);
 	}
 	else
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/csr.c linux-2.4.20/drivers/ieee1394/csr.c
--- linux-2.4.19/drivers/ieee1394/csr.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/csr.c	2002-10-29 11:18:34.000000000 +0000
@@ -70,7 +70,7 @@
 {
         host->csr.lock = SPIN_LOCK_UNLOCKED;
 
-        host->csr.rom_size = host->ops->get_rom(host, &host->csr.rom);
+        host->csr.rom_size = host->driver->get_rom(host, &host->csr.rom);
 
         host->csr.state                 = 0;
         host->csr.node_ids              = 0;
@@ -152,7 +152,7 @@
         case CSR_CYCLE_TIME:
                 oldcycle = host->csr.cycle_time;
                 host->csr.cycle_time =
-                        host->ops->devctl(host, GET_CYCLE_COUNTER, 0);
+                        host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
 
                 if (oldcycle > host->csr.cycle_time) {
                         /* cycle time wrapped around */
@@ -163,7 +163,7 @@
         case CSR_BUS_TIME:
                 oldcycle = host->csr.cycle_time;
                 host->csr.cycle_time =
-                        host->ops->devctl(host, GET_CYCLE_COUNTER, 0);
+                        host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
 
                 if (oldcycle > host->csr.cycle_time) {
                         /* cycle time wrapped around */
@@ -181,32 +181,32 @@
                 return RCODE_ADDRESS_ERROR;
 
         case CSR_BUS_MANAGER_ID:
-                if (host->ops->hw_csr_reg)
-                        ret = host->ops->hw_csr_reg(host, 0, 0, 0);
+                if (host->driver->hw_csr_reg)
+                        ret = host->driver->hw_csr_reg(host, 0, 0, 0);
                 else
                         ret = host->csr.bus_manager_id;
 
                 *(buf++) = cpu_to_be32(ret);
                 out;
         case CSR_BANDWIDTH_AVAILABLE:
-                if (host->ops->hw_csr_reg)
-                        ret = host->ops->hw_csr_reg(host, 1, 0, 0);
+                if (host->driver->hw_csr_reg)
+                        ret = host->driver->hw_csr_reg(host, 1, 0, 0);
                 else
                         ret = host->csr.bandwidth_available;
 
                 *(buf++) = cpu_to_be32(ret);
                 out;
         case CSR_CHANNELS_AVAILABLE_HI:
-                if (host->ops->hw_csr_reg)
-                        ret = host->ops->hw_csr_reg(host, 2, 0, 0);
+                if (host->driver->hw_csr_reg)
+                        ret = host->driver->hw_csr_reg(host, 2, 0, 0);
                 else
                         ret = host->csr.channels_available_hi;
 
                 *(buf++) = cpu_to_be32(ret);
                 out;
         case CSR_CHANNELS_AVAILABLE_LO:
-                if (host->ops->hw_csr_reg)
-                        ret = host->ops->hw_csr_reg(host, 3, 0, 0);
+                if (host->driver->hw_csr_reg)
+                        ret = host->driver->hw_csr_reg(host, 3, 0, 0);
                 else
                         ret = host->csr.channels_available_lo;
 
@@ -244,7 +244,7 @@
                 host->csr.node_ids &= NODE_MASK << 16;
                 host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16);
                 host->node_id = host->csr.node_ids >> 16;
-                host->ops->devctl(host, SET_BUS_ID, host->node_id >> 6);
+                host->driver->devctl(host, SET_BUS_ID, host->node_id >> 6);
                 out;
 
         case CSR_RESET_START:
@@ -269,7 +269,7 @@
         case CSR_CYCLE_TIME:
                 /* should only be set by cycle start packet, automatically */
                 host->csr.cycle_time = be32_to_cpu(*data);
-                host->ops->devctl(host, SET_CYCLE_COUNTER,
+                host->driver->devctl(host, SET_CYCLE_COUNTER,
                                        be32_to_cpu(*(data++)));
                 out;
         case CSR_BUS_TIME:
@@ -318,10 +318,10 @@
         data = be32_to_cpu(data);
         arg = be32_to_cpu(arg);
 
-        if (host->ops->hw_csr_reg) {
+        if (host->driver->hw_csr_reg) {
                 quadlet_t old;
 
-                old = host->ops->
+                old = host->driver->
                         hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
                                    data, arg);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/dv1394-private.h linux-2.4.20/drivers/ieee1394/dv1394-private.h
--- linux-2.4.19/drivers/ieee1394/dv1394-private.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/dv1394-private.h	2002-10-29 11:18:33.000000000 +0000
@@ -27,6 +27,7 @@
 #define _DV_1394_PRIVATE_H
 
 #include "ieee1394.h"
+#include "ohci1394.h"
 #include <linux/pci.h>
 #include <asm/scatterlist.h>
 
@@ -91,20 +92,20 @@
 					      unsigned char sync_tag,
 					      unsigned int  payload_size)
 {
-	omi->q[0] = 0x02000000 | 8 ; /* OUTPUT_MORE_IMMEDIATE; 8 is the size of the IT header */
+	omi->q[0] = cpu_to_le32(0x02000000 | 8); /* OUTPUT_MORE_IMMEDIATE; 8 is the size of the IT header */
 	omi->q[1] = 0;
 	omi->q[2] = 0;
 	omi->q[3] = 0;
 	
 	/* IT packet header */
-	omi->q[4] = (0x0 << 16)  /* DMA_SPEED_100 */
-			| (tag << 14)
-			| (channel << 8)
-			| (TCODE_ISO_DATA << 4) 
-			| (sync_tag);
+	omi->q[4] = cpu_to_le32(  (0x0 << 16)  /* DMA_SPEED_100 */
+				  | (tag << 14)
+				  | (channel << 8)
+				  | (TCODE_ISO_DATA << 4) 
+				  | (sync_tag) );
 
-	omi->q[5] = payload_size << 16;
-	omi->q[5] |= (0x7F << 8) | 0xA0; /* reserved field; mimic behavior of my Sony DSR-40 */
+	/* reserved field; mimic behavior of my Sony DSR-40 */
+	omi->q[5] = cpu_to_le32((payload_size << 16) | (0x7F << 8) | 0xA0);
 	
 	omi->q[6] = 0;
 	omi->q[7] = 0;
@@ -114,10 +115,8 @@
 				    unsigned int data_size,
 				    unsigned long data_phys_addr)
 {
-	om->q[0] = 0; /* OUTPUT_MORE */
-	om->q[0] |= data_size;
-
-	om->q[1] = data_phys_addr;
+	om->q[0] = cpu_to_le32(data_size);
+	om->q[1] = cpu_to_le32(data_phys_addr);
 	om->q[2] = 0;
 	om->q[3] = 0;
 }
@@ -128,19 +127,20 @@
 				    unsigned int data_size,
 				    unsigned long data_phys_addr)
 {
-	ol->q[0] = 0;
-	ol->q[0] |= 1 << 28; /* OUTPUT_LAST */
+	u32 temp = 0;
+	temp |= 1 << 28; /* OUTPUT_LAST */
 
 	if(want_timestamp) /* controller will update timestamp at DMA time */
-		ol->q[0] |= 1 << 27;
+		temp |= 1 << 27;
 
 	if(want_interrupt)
-		ol->q[0] |= 3 << 20;
+		temp |= 3 << 20;
 
-	ol->q[0] |= 3 << 18; /* must take branch */
-	ol->q[0] |= data_size;
-	
-	ol->q[1] = data_phys_addr;
+	temp |= 3 << 18; /* must take branch */
+	temp |= data_size;
+
+	ol->q[0] = cpu_to_le32(temp);
+	ol->q[1] = cpu_to_le32(data_phys_addr);
 	ol->q[2] = 0;
 	ol->q[3] = 0;
 }
@@ -152,15 +152,16 @@
 				   unsigned int data_size,
 				   unsigned long data_phys_addr)
 {
-	im->q[0] =  2 << 28; /* INPUT_MORE */
-	im->q[0] |= 8 << 24; /* s = 1, update xferStatus and resCount */
+	u32 temp =  2 << 28; /* INPUT_MORE */
+	temp |= 8 << 24; /* s = 1, update xferStatus and resCount */
 	if (want_interrupt)
-		im->q[0] |= 0 << 20; /* interrupts, i=0 in packet-per-buffer mode */
-	im->q[0] |= 0x0 << 16; /* disable branch to address for packet-per-buffer mode */
+		temp |= 0 << 20; /* interrupts, i=0 in packet-per-buffer mode */
+	temp |= 0x0 << 16; /* disable branch to address for packet-per-buffer mode */
 	                       /* disable wait on sync field, not used in DV :-( */
-       	im->q[0] |= data_size;
+       	temp |= data_size;
 
-	im->q[1] = data_phys_addr;
+	im->q[0] = cpu_to_le32(temp);
+	im->q[1] = cpu_to_le32(data_phys_addr);
 	im->q[2] = 0; /* branchAddress and Z not use in packet-per-buffer mode */
 	im->q[3] = 0; /* xferStatus & resCount, resCount must be initialize to data_size */
 }
@@ -169,16 +170,17 @@
 				    unsigned int data_size,
 				    unsigned long data_phys_addr)
 {
-	il->q[0] =  3 << 28; /* INPUT_LAST */
-	il->q[0] |= 8 << 24; /* s = 1, update xferStatus and resCount */
-	il->q[0] |= 3 << 20; /* enable interrupts */
-	il->q[0] |= 0xC << 16; /* enable branch to address */
+	u32 temp =  3 << 28; /* INPUT_LAST */
+	temp |= 8 << 24; /* s = 1, update xferStatus and resCount */
+	temp |= 3 << 20; /* enable interrupts */
+	temp |= 0xC << 16; /* enable branch to address */
 	                       /* disable wait on sync field, not used in DV :-( */
-	il->q[0] |= data_size;
+	temp |= data_size;
 
-	il->q[1] = data_phys_addr;
-	il->q[2] = 1; /* branchAddress (filled in later) and Z = 1 descriptor in next block */
-	il->q[3] = data_size; /* xferStatus & resCount, resCount must be initialize to data_size */
+	il->q[0] = cpu_to_le32(temp);
+	il->q[1] = cpu_to_le32(data_phys_addr);
+	il->q[2] = cpu_to_le32(1); /* branchAddress (filled in later) and Z = 1 descriptor in next block */
+	il->q[3] = cpu_to_le32(data_size); /* xferStatus & resCount, resCount must be initialize to data_size */
 }
 
 
@@ -299,7 +301,8 @@
 	unsigned long data; 
 
 	/* Max # of packets per frame */
-        #define MAX_PACKETS 320
+	/* 320 is enough for NTSC, need to check what PAL is */
+        #define MAX_PACKETS 500
 
 
 	/* a PAGE_SIZE memory pool for allocating CIP headers
@@ -434,6 +437,7 @@
 
 	/* OHCI card IT DMA context number, -1 if not in use */
 	int ohci_it_ctx;
+	struct ohci1394_iso_tasklet it_tasklet;
 
 	/* register offsets for current IT DMA context, 0 if not in use */
 	u32 ohci_IsoXmitContextControlSet;
@@ -441,6 +445,7 @@
 	u32 ohci_IsoXmitCommandPtr;
 	
 	/* OHCI card IR DMA context number, -1 if not in use */
+	struct ohci1394_iso_tasklet ir_tasklet;
 	int ohci_ir_ctx;
 
 	/* register offsets for current IR DMA context, 0 if not in use */
@@ -476,6 +481,9 @@
 	     immediately. This is safe because the interrupt handler will never
 	     advance active_frame onto a frame that is not READY (and the spinlock
 	     must be held while marking a frame READY).
+
+	     spinlock is also used to protect ohci_it_ctx and ohci_ir_ctx,
+	     which can be accessed from both process and interrupt context
 	 */
 	spinlock_t spinlock;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/dv1394.c linux-2.4.20/drivers/ieee1394/dv1394.c
--- linux-2.4.19/drivers/ieee1394/dv1394.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/dv1394.c	2002-10-29 11:18:34.000000000 +0000
@@ -159,9 +159,8 @@
 	reg_read(ohci, OHCI1394_IsochronousCycleTimer);
 }
 
-static void irq_handler(int card, quadlet_t isoRecvIntEvent, 
-			quadlet_t isoXmitIntEvent, void *data);
-
+static void it_tasklet_func(unsigned long data);
+static void ir_tasklet_func(unsigned long data);
 
 /* GLOBAL DATA */
 
@@ -188,42 +187,29 @@
 }
 
 
-/* Taken from bttv.c */
 /*******************************/
 /* Memory management functions */
 /*******************************/
 
+/* note: we no longer use mem_map_reserve, because it causes a memory
+   leak, and setting vma->vm_flags to VM_RESERVED should be sufficient
+   to pin the pages in memory anyway. */
+
 static void * rvmalloc(unsigned long size)
 {
 	void * mem;
-	unsigned long adr;
 
-	size = PAGE_ALIGN(size);
-	mem=vmalloc_32(size);
-	if (mem) {
+	mem = vmalloc_32(size);
+
+	if(mem)
 		memset(mem, 0, size); /* Clear the ram out, 
 					 no junk to the user */
-	        adr=(unsigned long) mem;
-		while (size > 0) {
-			mem_map_reserve(vmalloc_to_page((void *)adr));
-			adr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
-	}
 	return mem;
 }
 
 static void rvfree(void * mem, unsigned long size)
 {
-        unsigned long adr;
-
 	if (mem) {
-	        adr=(unsigned long) mem;
-		while (size > 0) {
-			mem_map_unreserve(vmalloc_to_page((void *)adr));
-			adr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
 		vfree(mem);
 	}
 }
@@ -594,7 +580,7 @@
 		/* note: we are not linked into the active DMA chain yet */
 
 		if(last_branch_address) {
-			*(last_branch_address) = block_dma | n_descriptors; 
+			*(last_branch_address) = cpu_to_le32(block_dma | n_descriptors);
 		}
 
 		last_branch_address = branch_address;
@@ -606,7 +592,7 @@
 
 	/* when we first assemble a new frame, set the final branch 
 	   to loop back up to the top */
-	*(f->frame_end_branch) = f->descriptor_pool_dma | f->first_n_descriptors;
+	*(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors);
 
 
 	/* make the latest version of the frame buffer visible to the PCI card */
@@ -643,15 +629,18 @@
 		/* if DMA is already active, we are almost done */
 		/* just link us onto the active DMA chain */
 		if(video->frames[last_frame]->frame_end_branch) {
+			u32 temp;
 
 			/* point the previous frame's tail to this frame's head */
-			*(video->frames[last_frame]->frame_end_branch) = f->descriptor_pool_dma | f->first_n_descriptors; 
+			*(video->frames[last_frame]->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors);
 
 			/* this write MUST precede the next one, or we could silently drop frames */
 			wmb();
 			
 			/* disable the want_status semaphore on the last packet */
-			*(video->frames[last_frame]->frame_end_branch - 2) &= 0xF7CFFFFF;
+			temp = le32_to_cpu(*(video->frames[last_frame]->frame_end_branch - 2));
+			temp &= 0xF7CFFFFF;
+			*(video->frames[last_frame]->frame_end_branch - 2) = cpu_to_le32(temp);
 
 			/* flush these writes to memory ASAP */
 			flush_pci_write(video->ohci);
@@ -914,14 +903,14 @@
 		last_branch_address = f->frame_end_branch;
 
 		if (last_branch_address)
-			*(last_branch_address) = block_dma | 1; /* set Z=1 */
+			*(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */
 
 		f->frame_end_branch = &(block->u.in.il.q[2]);
 	}
 	
 	/* loop tail to head */
 	if (f->frame_end_branch)
-		*(f->frame_end_branch) =  f->descriptor_pool_dma | 1; /* set Z=1 */
+		*(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | 1); /* set Z=1 */
 
 	spin_unlock_irqrestore(&video->spinlock, irq_flags);
 
@@ -992,6 +981,7 @@
 		do_dv1394_shutdown(video, 0);
 
 
+	
 	/* try to claim the ISO channel */
 	spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
 	if(video->ohci->ISO_channel_usage & chan_mask) {
@@ -1004,43 +994,75 @@
 
 	video->channel = init->channel;
 
+	/* initialize misc. fields of video */
+	video->n_frames = init->n_frames;
+	video->pal_or_ntsc = init->format;
 	
-	/* find and claim DMA contexts on the OHCI card */
+
+	video->cip_accum = 0;
+	video->continuity_counter = 0;
+
+	video->active_frame = -1;
+	video->first_clear_frame = 0;
+	video->n_clear_frames = video->n_frames;
+	video->dropped_frames = 0;
+
+	video->write_off = 0;
+
+	video->first_run = 1;
+	video->current_packet = -1;
+	video->first_frame = 0;
+
+
+	if(video->pal_or_ntsc == DV1394_NTSC) {
+		video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC;
+		video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC;
+		video->frame_size = DV1394_NTSC_FRAME_SIZE;
+	} else {
+		video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_PAL;
+		video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_PAL;
+		video->frame_size = DV1394_PAL_FRAME_SIZE;
+	}
+
+	video->syt_offset = init->syt_offset;
 	
-	if(video->ohci_it_ctx == -1) {
+	
+	/* find and claim DMA contexts on the OHCI card */
 
-		for(i = 0; i < video->ohci->nb_iso_xmit_ctx; i++) {
+	/* XXX this should be the last step of initialization, since the interrupt
+	   handler uses ohci_i*_ctx to indicate whether or not it is safe to touch
+	   frames. I'm not making this change quite yet, since it would be better
+	   to clean up the init/shutdown process first.*/
 
-			if(! test_and_set_bit(i, &video->ohci->it_ctx_usage)) {
-				video->ohci_it_ctx = i;
-				debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
-				break;
-			}
-		}
-				
-		if(i == video->ohci->nb_iso_xmit_ctx) {
+	if(video->ohci_it_ctx == -1) {
+		ohci1394_init_iso_tasklet(&video->it_tasklet, OHCI_ISO_TRANSMIT,
+					  it_tasklet_func, (unsigned long) video);
+
+		if (ohci1394_register_iso_tasklet(video->ohci, &video->it_tasklet) < 0) {	
 			printk(KERN_ERR "dv1394: could not find an available IT DMA context\n");
 			retval = -EBUSY;
 			goto err_ctx;
 		}
+		else {
+			video->ohci_it_ctx = video->it_tasklet.context;
+			debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
+		}
 	}
 	
 
 	if(video->ohci_ir_ctx == -1) {
-		for(i = 0; i < video->ohci->nb_iso_rcv_ctx; i++) {
+		ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE,
+					  ir_tasklet_func, (unsigned long) video);
 
-			if(! test_and_set_bit(i, &video->ohci->ir_ctx_usage)) {
-				video->ohci_ir_ctx = i;
-				debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
-				break;
-			}
-		}
-				
-		if(i == video->ohci->nb_iso_rcv_ctx) {
+		if (ohci1394_register_iso_tasklet(video->ohci, &video->ir_tasklet) < 0) {
 			printk(KERN_ERR "dv1394: could not find an available IR DMA context\n");
 			retval = -EBUSY;
 			goto err_ctx;
 		}
+		else {
+			video->ohci_ir_ctx = video->ir_tasklet.context;
+			debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
+		}
 	}
 
 	
@@ -1055,38 +1077,8 @@
 		}
 	}
 
-	/* initialize misc. fields of video */
-	video->n_frames = init->n_frames;
-	video->pal_or_ntsc = init->format;
 	
 
-	video->cip_accum = 0;
-	video->continuity_counter = 0;
-
-	video->active_frame = -1;
-	video->first_clear_frame = 0;
-	video->n_clear_frames = video->n_frames;
-	video->dropped_frames = 0;
-
-	video->write_off = 0;
-
-	video->first_run = 1;
-	video->current_packet = -1;
-	video->first_frame = 0;
-
-
-	if(video->pal_or_ntsc == DV1394_NTSC) {
-		video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC;
-		video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC;
-		video->frame_size = DV1394_NTSC_FRAME_SIZE;
-	} else {
-		video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_PAL;
-		video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_PAL;
-		video->frame_size = DV1394_PAL_FRAME_SIZE;
-	}
-
-	video->syt_offset = init->syt_offset;
-
 	if(video->user_buf == NULL) {
 		unsigned int i;
 		
@@ -1224,11 +1216,11 @@
 
  err_ctx:
 	if(video->ohci_it_ctx != -1) {
-		clear_bit(video->ohci_it_ctx, &video->ohci->it_ctx_usage);
+		ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet);
 		video->ohci_it_ctx = -1;
 	}
 	if(video->ohci_ir_ctx != -1) {
-		clear_bit(video->ohci_ir_ctx, &video->ohci->ir_ctx_usage);
+		ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet);
 		video->ohci_ir_ctx = -1;
 	}
 	
@@ -1313,25 +1305,14 @@
 static int do_dv1394_shutdown(struct video_card *video, int free_user_buf)
 {
 	int i;
-
+	unsigned long flags;
+	
 	debug_printk("dv1394: shutdown...\n");
 
 	/* stop DMA if in progress */
 	stop_dma(video);
 	
-	/* release the ISO channel */
-	if(video->channel != -1) {
-		u64 chan_mask;
-		unsigned long flags;
-		
-		chan_mask = (u64)1 << video->channel;
-		
-		spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
-		video->ohci->ISO_channel_usage &= ~(chan_mask);
-		spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
-		
-		video->channel = -1;
-	}
+	spin_lock_irqsave(&video->spinlock, flags);
 
 	/* release the DMA contexts */
 	if(video->ohci_it_ctx != -1) {
@@ -1361,6 +1342,22 @@
 		video->ohci_ir_ctx = -1;
 	}
 
+	spin_unlock_irqrestore(&video->spinlock, flags);
+	
+	/* release the ISO channel */
+	if(video->channel != -1) {
+		u64 chan_mask;
+		unsigned long flags;
+		
+		chan_mask = (u64)1 << video->channel;
+		
+		spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
+		video->ohci->ISO_channel_usage &= ~(chan_mask);
+		spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
+		
+		video->channel = -1;
+	}
+	
 	/* free the frame structs */
 	for(i = 0; i < DV1394_MAX_FRAMES; i++) {
 		if(video->frames[i])
@@ -2142,7 +2139,7 @@
 			const char *buffer, unsigned long count, void *data)
 {
 	int len = 0;
-	char new_value[64];
+	char new_value[65];
 	char *pos;
 	struct video_card *video = (struct video_card*) data;
 	
@@ -2154,11 +2151,12 @@
 	if (copy_from_user( new_value, buffer, len))
 		return -EFAULT;
 	
+	new_value[len] = 0;
 	pos = strchr(new_value, '=');
 	if (pos != NULL) {
 		int val_len = len - (pos-new_value) - 1;
-		char buf[64];
-		memset(buf, 0, 64);
+		char buf[65];
+		memset(buf, 0, 65);
 		strncpy(buf, pos+1, val_len);
 		if (buf[val_len-1] == '\n') buf[val_len-1] = 0;
 		
@@ -2315,12 +2313,13 @@
 
 /*** DEVICE DRIVER HANDLERS ************************************************/
 
-static void irq_handler(int card, quadlet_t isoRecvIntEvent, 
-			quadlet_t isoXmitIntEvent, void *data)
+static void it_tasklet_func(unsigned long data)
 {
 	int wake = 0;
 	struct video_card *video = (struct video_card*) data;
 
+	spin_lock(&video->spinlock);
+	
 	irq_printk("INTERRUPT! Video = %08lx Iso event Recv: %08x Xmit: %08x\n",
 		   (unsigned long) video, isoRecvIntEvent, isoXmitIntEvent);
 	irq_printk("ContextControl = %08x, CommandPtr = %08x\n", 
@@ -2330,13 +2329,12 @@
 
 	
 	if( (video->ohci_it_ctx != -1) &&
-	    (isoXmitIntEvent & (1 << video->ohci_it_ctx)) &&
 	    (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) {
 
 		struct frame *f;
 		unsigned int frame, i;
 
-		spin_lock(&video->spinlock);
+		
 		if(video->active_frame == -1)
 			frame = 0;
 		else
@@ -2392,13 +2390,15 @@
 			/* see if we need to set the timestamp for the next frame */
 			if( *(f->mid_frame_timestamp) ) {
 				struct frame *next_frame;
-				u32 ts_cyc, ts_off;
+				u32 begin_ts, ts_cyc, ts_off;
 
 				*(f->mid_frame_timestamp) = 0;
 
+				begin_ts = le32_to_cpu(*(f->frame_begin_timestamp));
+
 				irq_printk("  MIDDLE - first packet was sent at cycle %4u (%2u), assigned timestamp was (%2u) %4u\n",
-				       *(f->frame_begin_timestamp) & 0x1FFF, *(f->frame_begin_timestamp) & 0xF,
-				       f->assigned_timestamp >> 12,       f->assigned_timestamp & 0xFFF);
+					   begin_ts & 0x1FFF, begin_ts & 0xF,
+					   f->assigned_timestamp >> 12, f->assigned_timestamp & 0xFFF);
 
 				/* prepare next frame and assign timestamp */
 				next_frame = video->frames[ (frame+1) % video->n_frames ];
@@ -2412,7 +2412,7 @@
 
 				/* set the timestamp to the timestamp of the last frame sent,
 				   plus the length of the last frame sent, plus the syt latency */
-				ts_cyc = *(f->frame_begin_timestamp) & 0xF;
+				ts_cyc = begin_ts & 0xF;
 				/* advance one frame, plus syt latency (typically 2-3) */
 				ts_cyc += f->n_packets + video->syt_offset ; 
 
@@ -2446,30 +2446,41 @@
 
 		
 		} /* for(each frame) */
+	}
+
+	spin_unlock(&video->spinlock);
 
-		spin_unlock(&video->spinlock);
+	if(wake) {
+		kill_fasync(&video->fasync, SIGIO, POLL_OUT);
 		
-	} /* end XMIT portion */
+		/* wake readers/writers/ioctl'ers */
+		wake_up_interruptible(&video->waitq);
+	}
+}
 
-	/***** RECEIVE INTERRUPT and DMA ACTIVE *****/
+static void ir_tasklet_func(unsigned long data)
+{
+	int wake = 0;
+	struct video_card *video = (struct video_card*) data;
 
-	else if( (video->ohci_ir_ctx != -1) &&
-		 (isoRecvIntEvent & (1 << video->ohci_ir_ctx)) &&
-		 (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { 
+	if( (video->ohci_ir_ctx != -1) &&
+	    (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { 
 
 		int sof=0; /* start-of-frame flag */
 		struct frame *f;
+		u16 packet_length, packet_time;
 
-		spin_lock(&video->spinlock);
+		packet_length = le16_to_cpu(video->packet_buffer[video->current_packet].data_length);
+		packet_time   = le16_to_cpu(video->packet_buffer[video->current_packet].timestamp);
 
 		irq_printk("received packet %02d, timestamp=%04x, length=%04x, sof=%02x%02x\n", video->current_packet,
-			   video->packet_buffer[video->current_packet].timestamp, video->packet_buffer[video->current_packet].data_length, 
+			   packet_time, packet_length, 
 			   video->packet_buffer[video->current_packet].data[0], video->packet_buffer[video->current_packet].data[1]);
 		
 		f = video->frames[video->active_frame];
 
 		/* exclude empty packet */
-		if (video->packet_buffer[video->current_packet].data_length > 8) {
+		if (packet_length > 8) {
 		
 			/* check for start of frame */
 			sof = (video->packet_buffer[video->current_packet].data[0] == 0x1f &&
@@ -2524,22 +2535,15 @@
 		/* advance packet_buffer cursor */
 		video->current_packet = (video->current_packet + 1) % MAX_PACKET_BUFFER;
  
- 		spin_unlock(&video->spinlock);
-
 		wake = 1; /* why the hell not? */
 
 	} /* receive interrupt */
 
+	spin_unlock(&video->spinlock);
+	
 	if(wake) {
-		
-		/* send SIGIO */
-		
-		if(isoRecvIntEvent & (1))
-			kill_fasync(&video->fasync, SIGIO, POLL_IN);
-		
-		if(isoXmitIntEvent & (1))
-			kill_fasync(&video->fasync, SIGIO, POLL_OUT);
-		
+		kill_fasync(&video->fasync, SIGIO, POLL_IN);
+
 		/* wake readers/writers/ioctl'ers */
 		wake_up_interruptible(&video->waitq);
 	}
@@ -2572,12 +2576,15 @@
 		list_for_each(lh, &dv1394_devfs) {
 			p = list_entry(lh, struct dv1394_devfs_entry, list);
 			if(!strncmp(p->name, name, sizeof(p->name))) {
-				spin_unlock( &dv1394_devfs_lock);
-				return p;
+				goto found;
 			}
 		}
 	}
-	return NULL;
+	p = NULL;
+	
+found:
+	spin_unlock( &dv1394_devfs_lock);
+	return p;
 }
 
 static int dv1394_devfs_add_entry(struct video_card *video)
@@ -2704,12 +2711,6 @@
 	
 	memset(video, 0, sizeof(struct video_card));
 	
-	if (ohci1394_hook_irq(ohci, irq_handler, (void*) video) != 0) {
-		printk(KERN_ERR "dv1394: ohci1394_hook_irq() failed\n");
-		goto err_free;
-	}
-
-	
 	video->ohci = ohci;
 	/* lower 2 bits of id indicate which of four "plugs"
 	   per host */
@@ -2763,7 +2764,7 @@
 	if (format == DV1394_NTSC)
 		video->id |= mode;
 	else video->id |= 2 + mode;
-	
+
 #ifdef CONFIG_DEVFS_FS
 	if (dv1394_devfs_add_entry(video) < 0)
 			goto err_free;
@@ -2785,7 +2786,6 @@
 	
 	/* obviously nobody has the driver open at this point */
 	do_dv1394_shutdown(video, 1);
-	ohci1394_unhook_irq(video->ohci, irq_handler, (void*) video);
 	snprintf(buf, sizeof(buf), "dv/host%d/%s/%s", (video->id >> 2),
 		(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
 		(video->mode == MODE_RECEIVE ? "in" : "out")
@@ -2923,12 +2923,13 @@
 	if(!video)
 		return;
 
+	
+	spin_lock_irqsave(&video->spinlock, flags);
+
 	/* check IT context */
 	if(video->ohci_it_ctx != -1) {
 		u32 ctx;
 		
-		spin_lock_irqsave(&video->spinlock, flags);
-		
 		ctx = reg_read(video->ohci, video->ohci_IsoXmitContextControlSet);
 
 		/* if(RUN but not ACTIVE) */
@@ -2959,16 +2960,12 @@
 				   reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
 				   reg_read(video->ohci, video->ohci_IsoXmitCommandPtr));
 		}
-
-		spin_unlock_irqrestore(&video->spinlock, flags);
 	}
 	
 	/* check IR context */
 	if(video->ohci_ir_ctx != -1) {
 		u32 ctx;
 		
-		spin_lock_irqsave(&video->spinlock, flags);
-		
 		ctx = reg_read(video->ohci, video->ohci_IsoRcvContextControlSet);
 
 		/* if(RUN but not ACTIVE) */
@@ -3000,10 +2997,10 @@
 				   reg_read(video->ohci, video->ohci_IsoRcvContextControlSet),
 				   reg_read(video->ohci, video->ohci_IsoRcvCommandPtr));
 		}
-
-		spin_unlock_irqrestore(&video->spinlock, flags);
 	}
-
+	
+	spin_unlock_irqrestore(&video->spinlock, flags);
+	
 	/* wake readers/writers/ioctl'ers */
 	wake_up_interruptible(&video->waitq);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/eth1394.c linux-2.4.20/drivers/ieee1394/eth1394.c
--- linux-2.4.19/drivers/ieee1394/eth1394.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/eth1394.c	2002-10-29 11:18:35.000000000 +0000
@@ -77,7 +77,7 @@
 	printk(KERN_ERR fmt, ## args)
 
 static char version[] __devinitdata =
-	"eth1394.c:v0.50 15/Jul/01 Ben Collins <bcollins@debian.org>";
+	"$Rev: 546 $ Ben Collins <bcollins@debian.org>";
 
 /* Our ieee1394 highlevel driver */
 #define ETHER1394_DRIVER_NAME "ether1394"
@@ -99,6 +99,7 @@
 
 MODULE_AUTHOR("Ben Collins (bcollins@debian.org)");
 MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)");
+MODULE_LICENSE("GPL");
 
 /* Find our host_info struct for a given host pointer. Must be called
  * under spinlock.  */
@@ -276,7 +277,7 @@
 
 static void ether1394_reset_priv (struct net_device *dev, int set_mtu)
 {
-	int flags;
+	unsigned long flags;
 	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
 	int phy_id = priv->host->node_id & NODE_MASK;
 
@@ -477,7 +478,7 @@
 	 * use of some of the fields, since they tell us a little bit
 	 * about the sending machine.  */
 	if (hdr->uf.ether_type == __constant_htons (ETH_P_ARP)) {
-		int flags;
+		unsigned long flags;
 		u16 phy_id = srcid & NODE_MASK;
 		struct eth1394_priv *priv =
 			(struct eth1394_priv *)dev->priv;
@@ -525,7 +526,7 @@
 {
 	struct sk_buff *skb;
 	char *buf = (char *)data;
-	int flags;
+	unsigned long flags;
 	struct net_device *dev = ether1394_find_dev (host);
 	struct eth1394_priv *priv;
 
@@ -596,7 +597,7 @@
 	struct sk_buff *skb = ptask->skb;
 	struct net_device *dev = ptask->skb->dev;
 	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
-	int flags;
+        unsigned long flags;
 
 	/* Statistics */
 	spin_lock_irqsave (&priv->lock, flags);
@@ -627,7 +628,8 @@
 	int kmflags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL;
 	struct ethhdr *eth;
 	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
-	int proto, flags;
+	int proto;
+	unsigned long flags;
 	nodeid_t dest_node;
 	u64 addr;
 	struct packet_task *ptask = NULL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/eth1394.h linux-2.4.20/drivers/ieee1394/eth1394.h
--- linux-2.4.19/drivers/ieee1394/eth1394.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/eth1394.h	2002-10-29 11:18:33.000000000 +0000
@@ -51,7 +51,7 @@
 	struct net_device *dev;
 };
 
-/* This is our task struct. It's used for the complete_tq callback.  */
+/* This is our task struct. It's used for the packet complete callback.  */
 struct packet_task {
 	struct sk_buff *skb;	/* Socket buffer we are sending */
 	nodeid_t dest_node;	/* Destination of the packet */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/highlevel.c linux-2.4.20/drivers/ieee1394/highlevel.c
--- linux-2.4.19/drivers/ieee1394/highlevel.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/highlevel.c	2002-10-29 11:18:36.000000000 +0000
@@ -139,7 +139,7 @@
         }
 
         if (host->iso_listen_count[channel]++ == 0) {
-                host->ops->devctl(host, ISO_LISTEN_CHANNEL, channel);
+                host->driver->devctl(host, ISO_LISTEN_CHANNEL, channel);
         }
 }
 
@@ -152,7 +152,7 @@
         }
 
         if (--host->iso_listen_count[channel] == 0) {
-                host->ops->devctl(host, ISO_UNLISTEN_CHANNEL, channel);
+                host->driver->devctl(host, ISO_UNLISTEN_CHANNEL, channel);
         }
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/hosts.c linux-2.4.20/drivers/ieee1394/hosts.c
--- linux-2.4.19/drivers/ieee1394/hosts.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/hosts.c	2002-10-29 11:18:38.000000000 +0000
@@ -38,7 +38,7 @@
         return -1;
 }
 
-static struct hpsb_host_operations dummy_ops = {
+static struct hpsb_host_driver dummy_driver = {
         .transmit_packet = dummy_transmit_packet,
         .devctl =          dummy_devctl
 };
@@ -63,7 +63,7 @@
         spin_lock_irqsave(&hosts_lock, flags);
         list_for_each(lh, &hosts) {
                 if (host == list_entry(lh, struct hpsb_host, host_list)) {
-                        host->ops->devctl(host, MODIFY_USAGE, 1);
+                        host->driver->devctl(host, MODIFY_USAGE, 1);
 			host->refcount++;
                         retval = 1;
 			break;
@@ -87,7 +87,7 @@
 {
         unsigned long flags;
 
-        host->ops->devctl(host, MODIFY_USAGE, 0);
+        host->driver->devctl(host, MODIFY_USAGE, 0);
 
         spin_lock_irqsave(&hosts_lock, flags);
         host->refcount--;
@@ -128,7 +128,6 @@
 
 	h->hostdata = h + 1;
         h->driver = drv;
-        h->ops = drv->ops;
 	h->refcount = 1;
 
         INIT_LIST_HEAD(&h->pending_packets);
@@ -152,63 +151,26 @@
         unsigned long flags;
 
         spin_lock_irqsave(&hosts_lock, flags);
-        host->driver->number_of_hosts++;
-        list_add_tail(&host->driver_list, &host->driver->hosts);
         list_add_tail(&host->host_list, &hosts);
         spin_unlock_irqrestore(&hosts_lock, flags);
 
         highlevel_add_host(host);
-        host->ops->devctl(host, RESET_BUS, 0);
+        host->driver->devctl(host, RESET_BUS, 0);
 }
 
 void hpsb_remove_host(struct hpsb_host *host)
 {
-        struct hpsb_host_driver *drv = host->driver;
         unsigned long flags;
 
         host->is_shutdown = 1;
-        host->ops = &dummy_ops;
+        host->driver = &dummy_driver;
         highlevel_remove_host(host);
 
         spin_lock_irqsave(&hosts_lock, flags);
-        list_del(&host->driver_list);
         list_del(&host->host_list);
-        drv->number_of_hosts--;
         spin_unlock_irqrestore(&hosts_lock, flags);
 }
 
-
-struct hpsb_host_driver *hpsb_register_lowlevel(struct hpsb_host_operations *op,
-                                                const char *name)
-{
-        struct hpsb_host_driver *drv;
-
-        drv = kmalloc(sizeof(struct hpsb_host_driver), SLAB_KERNEL);
-        if (!drv) return NULL;
-
-        INIT_LIST_HEAD(&drv->list);
-        INIT_LIST_HEAD(&drv->hosts);
-        drv->number_of_hosts = 0;
-        drv->name = name;
-        drv->ops = op;
-
-        spin_lock(&host_drivers_lock);
-        list_add_tail(&drv->list, &host_drivers);
-        spin_unlock(&host_drivers_lock);
-
-        return drv;
-}
-
-void hpsb_unregister_lowlevel(struct hpsb_host_driver *drv)
-{
-        spin_lock(&host_drivers_lock);
-        list_del(&drv->list);
-        spin_unlock(&host_drivers_lock);
-
-        kfree(drv);
-}
-
-
 /*
  * This function calls the given function for every host currently registered.
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/hosts.h linux-2.4.20/drivers/ieee1394/hosts.h
--- linux-2.4.19/drivers/ieee1394/hosts.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/hosts.h	2002-10-29 11:18:34.000000000 +0000
@@ -15,7 +15,6 @@
 struct hpsb_host {
         struct list_head host_list;
 
-        struct hpsb_host_operations *ops;
         void *hostdata;
 
         atomic_t generation;
@@ -59,7 +58,6 @@
         struct csr_control csr;
 
         struct hpsb_host_driver *driver;
-        struct list_head driver_list;
 
 	struct pci_dev *pdev;
 };
@@ -113,7 +111,9 @@
         SHORT_RESET
 };
 
-struct hpsb_host_operations {
+struct hpsb_host_driver {
+	const char *name;
+
         /* This function must store a pointer to the configuration ROM into the
          * location referenced to by pointer and return the size of the ROM. It
          * may not fail.  If any allocation is required, it must be done
@@ -149,18 +149,6 @@
                                  quadlet_t data, quadlet_t compare);
 };
 
-struct hpsb_host_driver {
-        struct list_head list;
-
-        struct list_head hosts;
-
-        int number_of_hosts;
-        const char *name;
-
-        struct hpsb_host_operations *ops;
-};
-
-
 /* core internal use */
 void register_builtin_lowlevels(void);
 
@@ -184,8 +172,4 @@
 void hpsb_add_host(struct hpsb_host *host);
 void hpsb_remove_host(struct hpsb_host *h);
 
-struct hpsb_host_driver *hpsb_register_lowlevel(struct hpsb_host_operations *op,
-                                                const char *name);
-void hpsb_unregister_lowlevel(struct hpsb_host_driver *drv);
-
 #endif /* _IEEE1394_HOSTS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/ieee1394_core.c linux-2.4.20/drivers/ieee1394/ieee1394_core.c
--- linux-2.4.19/drivers/ieee1394/ieee1394_core.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/ieee1394_core.c	2002-10-29 11:18:34.000000000 +0000
@@ -19,10 +19,10 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
+#include <linux/tqueue.h>
 #include <asm/bitops.h>
 #include <asm/byteorder.h>
 #include <asm/semaphore.h>
-#include <asm/smplock.h>
 
 #include "ieee1394_types.h"
 #include "ieee1394.h"
@@ -67,6 +67,29 @@
         printk("\n");
 }
 
+static void process_complete_tasks(struct hpsb_packet *packet)
+{
+	struct list_head *lh, *next;
+
+	list_for_each_safe(lh, next, &packet->complete_tq) {
+		struct tq_struct *tq = list_entry(lh, struct tq_struct, list);
+		list_del(&tq->list);
+		schedule_task(tq);
+	}
+
+	return;
+}
+
+/**
+ * hpsb_add_packet_complete_task - add a new task for when a packet completes
+ * @packet: the packet whose completion we want the task added to
+ * @tq: the tq_struct describing the task to add
+ */
+void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq)
+{
+	list_add_tail(&tq->list, &packet->complete_tq);
+	return;
+}
 
 /**
  * alloc_hpsb_packet - allocate new packet structure
@@ -142,7 +165,7 @@
 int hpsb_reset_bus(struct hpsb_host *host, int type)
 {
         if (!host->in_bus_reset) {
-                host->ops->devctl(host, RESET_BUS, type);
+                host->driver->devctl(host, RESET_BUS, type);
                 return 0;
         } else {
                 return 1;
@@ -161,7 +184,10 @@
         abort_requests(host);
         host->in_bus_reset = 1;
         host->irm_id = -1;
+	host->is_irm = 0;
         host->busmgr_id = -1;
+	host->is_busmgr = 0;
+	host->is_cycmst = 0;
         host->node_count = 0;
         host->selfid_count = 0;
 
@@ -355,7 +381,10 @@
         }
 
         host->reset_retries = 0;
-        if (isroot) host->ops->devctl(host, ACT_CYCLE_MASTER, 1);
+        if (isroot) {
+		host->driver->devctl(host, ACT_CYCLE_MASTER, 1);
+		host->is_cycmst = 1;
+	}
 	atomic_inc(&host->generation);
 	host->in_bus_reset = 0;
         highlevel_host_reset(host);
@@ -379,7 +408,7 @@
                 packet->state = hpsb_complete;
                 up(&packet->state_change);
                 up(&packet->state_change);
-                run_task_queue(&packet->complete_tq);
+                process_complete_tasks(packet);
                 return;
         }
 
@@ -391,7 +420,7 @@
         spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
 
         up(&packet->state_change);
-        queue_task(&host->timeout_tq, &tq_timer);
+        schedule_task(&host->timeout_tq);
 }
 
 /**
@@ -441,7 +470,7 @@
         }
 #endif
 
-        return host->ops->transmit_packet(host, packet);
+        return host->driver->transmit_packet(host, packet);
 }
 
 static void send_packet_nocare(struct hpsb_packet *packet)
@@ -529,7 +558,7 @@
 
         packet->state = hpsb_complete;
         up(&packet->state_change);
-        run_task_queue(&packet->complete_tq);
+	process_complete_tasks(packet);
 }
 
 
@@ -737,7 +766,7 @@
         struct list_head *lh;
         LIST_HEAD(llist);
 
-        host->ops->devctl(host, CANCEL_REQUESTS, 0);
+        host->driver->devctl(host, CANCEL_REQUESTS, 0);
 
         spin_lock_irqsave(&host->pending_pkt_lock, flags);
         list_splice(&host->pending_packets, &llist);
@@ -749,7 +778,7 @@
                 packet->state = hpsb_complete;
                 packet->ack_code = ACKX_ABORTED;
                 up(&packet->state_change);
-                run_task_queue(&packet->complete_tq);
+		process_complete_tasks(packet);
         }
 }
 
@@ -781,9 +810,9 @@
                 }
         }
 
-        if (!list_empty(&host->pending_packets)) {
-                queue_task(&host->timeout_tq, &tq_timer);
-        }
+        if (!list_empty(&host->pending_packets))
+		schedule_task(&host->timeout_tq);
+
         spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
 
         list_for_each(lh, &expiredlist) {
@@ -791,7 +820,7 @@
                 packet->state = hpsb_complete;
                 packet->ack_code = ACKX_TIMEOUT;
                 up(&packet->state_change);
-                run_task_queue(&packet->complete_tq);
+		process_complete_tasks(packet);
         }
 }
 
@@ -862,19 +891,57 @@
 	write_unlock(&ieee1394_chardevs_lock);
 }
 
+/*
+  ieee1394_get_chardev() - look up and acquire a character device
+  driver that has previously registered using ieee1394_register_chardev()
+  
+  On success, returns 1 and sets module and file_ops to the driver.
+  The module will have an incremented reference count.
+   
+  On failure, returns 0.
+  The module will NOT have an incremented reference count.
+*/
+
+static int ieee1394_get_chardev(int blocknum,
+				struct module **module,
+				struct file_operations **file_ops)
+{
+	int ret = 0;
+       
+	if( (blocknum < 0) || (blocknum > 15) )
+		return ret;
+
+	read_lock(&ieee1394_chardevs_lock);
+
+	*module = ieee1394_chardevs[blocknum].module;
+	*file_ops = ieee1394_chardevs[blocknum].file_ops;
+
+	if(*file_ops == NULL)
+		goto out;
+
+	/* don't need try_inc_mod_count if the driver is non-modular */
+	if(*module && (try_inc_mod_count(*module) == 0))
+		goto out;
+
+	/* success! */
+	ret = 1;
+	
+out:
+	read_unlock(&ieee1394_chardevs_lock);
+	return ret;
+}
+
 /* the point of entry for open() on any ieee1394 character device */
 static int ieee1394_dispatch_open(struct inode *inode, struct file *file)
 {
 	struct file_operations *file_ops;
 	struct module *module;
 	int blocknum;
-	int retval = -ENODEV;
+	int retval;
 
 	/*
 	  Maintaining correct module reference counts is tricky here!
 
-	  For Linux v2.4 and later:
-	  
 	  The key thing to remember is that the VFS increments the
 	  reference count of ieee1394 before it calls
 	  ieee1394_dispatch_open().
@@ -887,16 +954,7 @@
 	  If the open() fails, then the VFS will drop the
 	  reference count of whatever module file->f_op->owner points
 	  to, immediately after this function returns.
-
-	  The comments below refer to the 2.4 case, since the 2.2
-	  case is trivial.
-	  
 	*/
-
-#define INCREF(mod_) do { struct module *mod = (struct module*) mod_; \
-                          if(mod != NULL) __MOD_INC_USE_COUNT(mod); } while(0)
-#define DECREF(mod_) do { struct module *mod = (struct module*) mod_; \
-                          if(mod != NULL) __MOD_DEC_USE_COUNT(mod); } while(0)
 	
         /* shift away lower four bits of the minor
 	   to get the index of the ieee1394_driver
@@ -904,20 +962,10 @@
 	
 	blocknum = (minor(inode->i_rdev) >> 4) & 0xF;
 
-	/* printk("ieee1394_dispatch_open(%d)", blocknum); */
+	/* look up the driver */
 
-	read_lock(&ieee1394_chardevs_lock);
-	module = ieee1394_chardevs[blocknum].module;
-	/* bump the reference count of the driver that
-	   will receive the open() */
-	INCREF(module);
-	file_ops = ieee1394_chardevs[blocknum].file_ops;
-	read_unlock(&ieee1394_chardevs_lock);
-
-	if(file_ops == NULL) {
-		DECREF(module);
-		goto out_fail;
-	}
+	if(ieee1394_get_chardev(blocknum, &module, &file_ops) == 0)
+		return -ENODEV;
 
 	/* redirect all subsequent requests to the driver's
 	   own file_operations */
@@ -929,42 +977,42 @@
 	/* follow through with the open() */
 	retval = file_ops->open(inode, file);
 
-	if(retval) {
+	if(retval == 0) {
 		
-		/* if the open() failed, then we need to drop the
-                   extra reference we gave to the task-specific
-                   driver */
+		/* If the open() succeeded, then ieee1394 will be left
+		   with an extra module reference, so we discard it here.
 
-		DECREF(module);
-		goto out_fail;
+		   The task-specific driver still has the extra
+		   reference given to it by ieee1394_get_chardev().
+		   This extra reference prevents the module from
+		   unloading while the file is open, and will be
+		   dropped by the VFS when the file is released.
+		*/
 		
-	} else {
-
-		/* if the open() succeeded, then ieee1394 will be left
-		   with an extra module reference, so we discard it here.*/
+		if(THIS_MODULE)
+			__MOD_DEC_USE_COUNT((struct module*) THIS_MODULE);
+		
+		/* note that if ieee1394 is compiled into the kernel,
+		   THIS_MODULE will be (void*) NULL, hence the if and
+		   the cast are necessary */
 
-		DECREF(THIS_MODULE);
+	} else {
 
-		/* the task-specific driver still has the extra
-		   reference we gave it. This extra reference prevents
-		   the module from unloading while the file is open,
-		   and will be dropped by the VFS when the file is
-		   released. */
+		/* if the open() failed, then we need to drop the
+		   extra reference we gave to the task-specific
+		   driver */
 		
-		return 0;
-	}
-	       
-out_fail:
-	/* point the file's f_ops back to ieee1394. The VFS will then
-	   decrement ieee1394's reference count immediately after this
-	   function returns. */
+		if(module)
+			__MOD_DEC_USE_COUNT(module);
 	
-	file->f_op = &ieee1394_chardev_ops;
-	return retval;
+		/* point the file's f_ops back to ieee1394. The VFS will then
+		   decrement ieee1394's reference count immediately after this
+		   function returns. */
+		
+		file->f_op = &ieee1394_chardev_ops;
+	}
 
-#undef INCREF
-#undef DECREF
-	     
+	return retval;
 }
 
 struct proc_dir_entry *ieee1394_procfs_entry;
@@ -1025,14 +1073,13 @@
 module_exit(ieee1394_cleanup);
 
 /* Exported symbols */
-EXPORT_SYMBOL(hpsb_register_lowlevel);
-EXPORT_SYMBOL(hpsb_unregister_lowlevel);
 EXPORT_SYMBOL(hpsb_alloc_host);
 EXPORT_SYMBOL(hpsb_add_host);
 EXPORT_SYMBOL(hpsb_remove_host);
 EXPORT_SYMBOL(hpsb_ref_host);
 EXPORT_SYMBOL(hpsb_unref_host);
 EXPORT_SYMBOL(hpsb_speedto_str);
+EXPORT_SYMBOL(hpsb_add_packet_complete_task);
 
 EXPORT_SYMBOL(alloc_hpsb_packet);
 EXPORT_SYMBOL(free_hpsb_packet);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/ieee1394_core.h linux-2.4.20/drivers/ieee1394/ieee1394_core.h
--- linux-2.4.19/drivers/ieee1394/ieee1394_core.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/ieee1394_core.h	2002-10-29 11:18:34.000000000 +0000
@@ -16,7 +16,7 @@
         struct list_head list;
 
         /* This can be used for host driver internal linking. */
-        struct hpsb_packet *xnext;
+	struct list_head driver_list;
 
         nodeid_t node_id;
 
@@ -69,7 +69,7 @@
         /* Very core internal, don't care. */
         struct semaphore state_change;
 
-        task_queue complete_tq;
+	struct list_head complete_tq;
 
         /* Store jiffies for implementing bus timeouts. */
         unsigned long sendtime;
@@ -77,6 +77,13 @@
         quadlet_t embedded_header[5];
 };
 
+/* add a new task for when a packet completes */
+void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq);
+
+static inline struct hpsb_packet *driver_packet(struct list_head *l)
+{
+	return list_entry(l, struct hpsb_packet, driver_list);
+}
 
 void abort_timedouts(struct hpsb_host *host);
 void abort_requests(struct hpsb_host *host);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/nodemgr.c linux-2.4.20/drivers/ieee1394/nodemgr.c
--- linux-2.4.19/drivers/ieee1394/nodemgr.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/nodemgr.c	2002-10-29 11:18:48.000000000 +0000
@@ -133,16 +133,24 @@
 		/* Now the unit directories */
 		list_for_each (l, &ne->unit_directories) {
 			struct unit_directory *ud = list_entry (l, struct unit_directory, node_list);
+			int printed = 0; // small hack
+
 			PUTF("  Unit Directory %d:\n", ud_count++);
-			if (ud->flags & UNIT_DIRECTORY_VENDOR_ID)
+			if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) {
 				PUTF("    Vendor/Model ID: %s [%06x]",
 				     ud->vendor_name ?: "Unknown", ud->vendor_id);
-			else if (ud->flags & UNIT_DIRECTORY_MODEL_ID) /* Have to put something */
-				PUTF("    Vendor/Model ID: %s [%06x]",
-				      ne->vendor_name ?: "Unknown", ne->vendor_id);
-			if (ud->flags & UNIT_DIRECTORY_MODEL_ID)
+				printed = 1;
+			}
+			if (ud->flags & UNIT_DIRECTORY_MODEL_ID) {
+				if (!printed)
+					PUTF("    Vendor/Model ID: %s [%06x]",
+					     ne->vendor_name ?: "Unknown", ne->vendor_id);
 				PUTF(" / %s [%06x]", ud->model_name ?: "Unknown", ud->model_id);
-			PUTF("\n");
+				printed = 1;
+			}
+			if (printed)
+				PUTF("\n");
+
 			if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)
 				PUTF("    Software Specifier ID: %06x\n", ud->specifier_id);
 			if (ud->flags & UNIT_DIRECTORY_VERSION)
@@ -187,6 +195,10 @@
 		ret = hpsb_read(host, nodeid, generation, address, quad, 4);
 		if (!ret)
 			break;
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (schedule_timeout (HZ/3))
+			return -1;
 	}
 	*quad = be32_to_cpu(*quad);
 
@@ -199,8 +211,10 @@
 {
 	quadlet_t quad;
 	int size = 0;
+
 	if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
 		return -1;
+
 	if (CONFIG_ROM_KEY(quad) == CONFIG_ROM_DESCRIPTOR_LEAF) {
 		/* This is the offset.  */
 		address += 4 * CONFIG_ROM_VALUE(quad); 
@@ -209,6 +223,7 @@
 		/* Now we got the size of the text descriptor leaf. */
 		size = CONFIG_ROM_LEAF_LENGTH(quad);
 	}
+
 	return size;
 }
 
@@ -220,7 +235,7 @@
 	int i, size, ret;
 
 	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad)
-	    && CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF)
+	    || CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF)
 		return -1;
 
 	/* This is the offset.  */
@@ -1299,12 +1314,12 @@
 		}
 	}
 
-	if (hi != NULL)
+	if (hi != NULL) {
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-	HPSB_DEBUG ("NodeMgr: Processing host reset for %s", host->driver->name);
+		HPSB_DEBUG ("NodeMgr: Processing host reset for %s", host->driver->name);
 #endif
 		up(&hi->reset_sem);
-	else
+	} else
 		HPSB_ERR ("NodeMgr: could not process reset of non-existent host");
 
 	spin_unlock_irqrestore (&host_info_lock, flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/ohci1394.c linux-2.4.20/drivers/ieee1394/ohci1394.c
--- linux-2.4.19/drivers/ieee1394/ohci1394.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/ohci1394.c	2002-10-29 11:18:36.000000000 +0000
@@ -154,7 +154,7 @@
 printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 530 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 578 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 MODULE_PARM(attempt_root,"i");
@@ -170,10 +170,6 @@
 
 static void ohci1394_pci_remove(struct pci_dev *pdev);
 
-static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci,
-					  quadlet_t isoRecvEvent, 
-					  quadlet_t isoXmitEvent);
-
 #ifndef __LITTLE_ENDIAN
 /* Swap a series of quads inplace. */
 static __inline__ void block_swab32(quadlet_t *data, size_t size) {
@@ -443,10 +439,8 @@
 	d->sent_ind = 0;
 	d->free_prgs = d->num_desc;
         d->branchAddrPtr = NULL;
-	d->fifo_first = NULL;
-	d->fifo_last = NULL;
-	d->pending_first = NULL;
-	d->pending_last = NULL;
+	INIT_LIST_HEAD(&d->fifo_list);
+	INIT_LIST_HEAD(&d->pending_list);
 
 	DBGMSG(ohci->id, "Transmit DMA ctx=%d initialized", d->ctx);
 }
@@ -477,34 +471,6 @@
 {
 	quadlet_t buf;
 
-	/* Start off with a soft reset, to clear everything to a sane
-	 * state. */
-	ohci_soft_reset(ohci);
-
-	/* Now enable LPS, which we need in order to start accessing
-	 * most of the registers.  In fact, on some cards (ALI M5251),
-	 * accessing registers in the SClk domain without LPS enabled
-	 * will lock up the machine.  Wait 50msec to make sure we have
-	 * full link enabled.  */
-	reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);
-	mdelay(50);
-
-	/* Determine the number of available IR and IT contexts. */
-	ohci->nb_iso_rcv_ctx =
-		get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
-	DBGMSG(ohci->id, "%d iso receive contexts available",
-	       ohci->nb_iso_rcv_ctx);
-
-	ohci->nb_iso_xmit_ctx = 
-		get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
-	DBGMSG(ohci->id, "%d iso transmit contexts available",
-	       ohci->nb_iso_xmit_ctx);
-
-	/* Set the usage bits for non-existent contexts so they can't
-	 * be allocated */
-	ohci->ir_ctx_usage |= ~0 << ohci->nb_iso_rcv_ctx;
-	ohci->it_ctx_usage |= ~0 << ohci->nb_iso_xmit_ctx;
-	
 	spin_lock_init(&ohci->phy_reg_lock);
 	spin_lock_init(&ohci->event_lock);
   
@@ -571,18 +537,18 @@
 	reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
 
 	/* Initialize AR dma */
-	initialize_dma_rcv_ctx(ohci->ar_req_context, 0);
-	initialize_dma_rcv_ctx(ohci->ar_resp_context, 0);
+	initialize_dma_rcv_ctx(&ohci->ar_req_context, 0);
+	initialize_dma_rcv_ctx(&ohci->ar_resp_context, 0);
 
 	/* Initialize AT dma */
-	initialize_dma_trm_ctx(ohci->at_req_context);
-	initialize_dma_trm_ctx(ohci->at_resp_context);
+	initialize_dma_trm_ctx(&ohci->at_req_context);
+	initialize_dma_trm_ctx(&ohci->at_resp_context);
 
 	/* Initialize IR dma */
-	initialize_dma_rcv_ctx(ohci->ir_context, 1);
+	initialize_dma_rcv_ctx(&ohci->ir_context, 1);
 
         /* Initialize IT dma */
-        initialize_dma_trm_ctx(ohci->it_context);
+        initialize_dma_trm_ctx(&ohci->it_context);
 
 	/* Set up isoRecvIntMask to generate interrupts for context 0
 	   (thanks to Michael Greger for seeing that I forgot this) */
@@ -629,7 +595,7 @@
 	      ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
 	      ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq,
 	      pci_resource_start(ohci->dev, 0),
-	      pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE,
+	      pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1,
 	      ohci->max_packet_size);
 }
 
@@ -789,13 +755,7 @@
 	d->free_prgs--;
 
 	/* queue the packet in the appropriate context queue */
-	if (d->fifo_last) {
-		d->fifo_last->xnext = packet;
-		d->fifo_last = packet;
-	} else {
-		d->fifo_first = packet;
-		d->fifo_last = packet;
-	}
+	list_add_tail(&packet->driver_list, &d->fifo_list);
 	d->prg_ind = (d->prg_ind+1)%d->num_desc;
 }
 
@@ -807,22 +767,24 @@
  */ 
 static int dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d)
 {
+	struct hpsb_packet *p;
 	int idx,z;
 
-	if (d->pending_first == NULL || d->free_prgs == 0) 
+	if (list_empty(&d->pending_list) || d->free_prgs == 0)
 		return 0;
 
+	p = driver_packet(d->pending_list.next);
 	idx = d->prg_ind;
-	z = (d->pending_first->data_size) ? 3 : 2;
+	z = (p->data_size) ? 3 : 2;
 
 	/* insert the packets into the at dma fifo */
-	while (d->free_prgs>0 && d->pending_first) {
-		insert_packet(ohci, d, d->pending_first);
-		d->pending_first = d->pending_first->xnext;
+	while (d->free_prgs > 0 && !list_empty(&d->pending_list)) {
+		struct hpsb_packet *p = driver_packet(d->pending_list.next);
+		list_del(&p->driver_list);
+		insert_packet(ohci, d, p);
 	}
-	if (d->pending_first == NULL) 
-		d->pending_last = NULL;
-	else
+
+	if (d->free_prgs == 0)
 		PRINT(KERN_INFO, ohci->id, 
 		      "Transmit DMA FIFO ctx=%d is full... waiting",d->ctx);
 
@@ -848,7 +810,6 @@
 {
 	struct ti_ohci *ohci = host->hostdata;
 	struct dma_trm_ctx *d;
-	unsigned char tcode;
 	unsigned long flags;
 
 	if (packet->data_size > ohci->max_packet_size) {
@@ -857,25 +818,20 @@
 		      packet->data_size);
 		return 0;
 	}
-	packet->xnext = NULL;
 
 	/* Decide wether we have an iso, a request, or a response packet */
-	tcode = (packet->header[0]>>4)&0xf;
-	if (tcode == TCODE_ISO_DATA) d = ohci->it_context;
-	else if (tcode & 0x02) d = ohci->at_resp_context;
-	else d = ohci->at_req_context;
+	if (packet->type == hpsb_raw)
+		d = &ohci->at_req_context;
+	else if (packet->tcode == TCODE_ISO_DATA)
+		d = &ohci->it_context;
+	else if (packet->tcode & 0x02)
+		d = &ohci->at_resp_context;
+	else 
+		d = &ohci->at_req_context;
 
 	spin_lock_irqsave(&d->lock,flags);
 
-	/* queue the packet for later insertion into the dma fifo */
-	if (d->pending_last) {
-		d->pending_last->xnext = packet;
-		d->pending_last = packet;
-	}
-	else {
-		d->pending_first = packet;
-		d->pending_last = packet;
-	}
+	list_add_tail(&packet->driver_list, &d->pending_list);
 	
 	dma_trm_flush(ohci, d);
 
@@ -929,8 +885,8 @@
 
 	case CANCEL_REQUESTS:
 		DBGMSG(ohci->id, "Cancel request received");
-		dma_trm_reset(ohci->at_req_context);
-		dma_trm_reset(ohci->at_resp_context);
+		dma_trm_reset(&ohci->at_req_context);
+		dma_trm_reset(&ohci->at_resp_context);
 		break;
 
 	case MODIFY_USAGE:
@@ -1033,46 +989,62 @@
 
 static void dma_trm_reset(struct dma_trm_ctx *d)
 {
-	struct ti_ohci *ohci;
 	unsigned long flags;
-        struct hpsb_packet *nextpacket;
+	LIST_HEAD(packet_list);
 
-	if (d==NULL) {
-		PRINT_G(KERN_ERR, "dma_trm_reset called with NULL arg");
-		return;
-	}
-	ohci = (struct ti_ohci *)(d->ohci);
-	ohci1394_stop_context(ohci, d->ctrlClear, NULL);
+	ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
 
-	spin_lock_irqsave(&d->lock,flags);
+	/* Lock the context, reset it and release it. Move the packets
+	 * that were pending in the context to packet_list and free
+	 * them after releasing the lock. */
 
-	/* Is there still any packet pending in the fifo ? */
-	while(d->fifo_first) {
-		PRINT(KERN_INFO, ohci->id, 
-		      "AT dma reset ctx=%d, aborting transmission", 
-		      d->ctx);
-                nextpacket = d->fifo_first->xnext;
-		hpsb_packet_sent(ohci->host, d->fifo_first, ACKX_ABORTED);
-		d->fifo_first = nextpacket;
-	}
-	d->fifo_first = d->fifo_last = NULL;
+	spin_lock_irqsave(&d->lock, flags);
 
-	/* is there still any packet pending ? */
-	while(d->pending_first) {
-		PRINT(KERN_INFO, ohci->id, 
-		      "AT dma reset ctx=%d, aborting transmission", 
-		      d->ctx);
-                nextpacket = d->pending_first->xnext;
-		hpsb_packet_sent(ohci->host, d->pending_first, 
-				 ACKX_ABORTED);
-		d->pending_first = nextpacket;
-	}
-	d->pending_first = d->pending_last = NULL;
-	
-	d->branchAddrPtr=NULL;
+	list_splice(&d->fifo_list, &packet_list);
+	list_splice(&d->pending_list, &packet_list);
+	INIT_LIST_HEAD(&d->fifo_list);
+	INIT_LIST_HEAD(&d->pending_list);
+
+	d->branchAddrPtr = NULL;
 	d->sent_ind = d->prg_ind;
 	d->free_prgs = d->num_desc;
-	spin_unlock_irqrestore(&d->lock,flags);
+
+	spin_unlock_irqrestore(&d->lock, flags);
+
+	/* Now process subsystem callbacks for the packets from the
+	 * context. */
+
+	while (!list_empty(&packet_list)) {
+		struct hpsb_packet *p = driver_packet(packet_list.next);
+		PRINT(KERN_INFO, d->ohci->id, 
+		      "AT dma reset ctx=%d, aborting transmission", d->ctx);
+		list_del(&p->driver_list);
+		hpsb_packet_sent(d->ohci->host, p, ACKX_ABORTED);
+	}
+}
+
+static void ohci_schedule_iso_tasklets(struct ti_ohci *ohci, 
+				       quadlet_t rx_event,
+				       quadlet_t tx_event)
+{
+	struct list_head *lh;
+	struct ohci1394_iso_tasklet *t;
+	unsigned long mask;
+
+	spin_lock(&ohci->iso_tasklet_list_lock);
+
+	list_for_each(lh, &ohci->iso_tasklet_list) {
+		t = list_entry(lh, struct ohci1394_iso_tasklet, link);
+		mask = 1 << t->context;
+
+		if (t->type == OHCI_ISO_TRANSMIT && tx_event & mask)
+			tasklet_schedule(&t->tasklet);
+		if (t->type == OHCI_ISO_RECEIVE && rx_event & mask)
+			tasklet_schedule(&t->tasklet);
+	}
+
+	spin_unlock(&ohci->iso_tasklet_list_lock);
+
 }
 
 static void ohci_irq_handler(int irq, void *dev_id,
@@ -1143,7 +1115,7 @@
 	 * we get sent acks before response packets. This sucks mainly
 	 * because it halts the interrupt handler.  */
 	if (event & OHCI1394_reqTxComplete) {
-		struct dma_trm_ctx *d = ohci->at_req_context;
+		struct dma_trm_ctx *d = &ohci->at_req_context;
 		DBGMSG(ohci->id, "Got reqTxComplete interrupt "
 		       "status=0x%08X", reg_read(ohci, d->ctrlSet));
 		if (reg_read(ohci, d->ctrlSet) & 0x800)
@@ -1154,7 +1126,7 @@
 		event &= ~OHCI1394_reqTxComplete;
 	}
 	if (event & OHCI1394_respTxComplete) {
-		struct dma_trm_ctx *d = ohci->at_resp_context;
+		struct dma_trm_ctx *d = &ohci->at_resp_context;
 		DBGMSG(ohci->id, "Got respTxComplete interrupt "
 		       "status=0x%08X", reg_read(ohci, d->ctrlSet));
 		if (reg_read(ohci, d->ctrlSet) & 0x800)
@@ -1165,7 +1137,7 @@
 		event &= ~OHCI1394_respTxComplete;
 	}
 	if (event & OHCI1394_RQPkt) {
-		struct dma_rcv_ctx *d = ohci->ar_req_context;
+		struct dma_rcv_ctx *d = &ohci->ar_req_context;
 		DBGMSG(ohci->id, "Got RQPkt interrupt status=0x%08X",
 		       reg_read(ohci, d->ctrlSet));
 		if (reg_read(ohci, d->ctrlSet) & 0x800)
@@ -1175,7 +1147,7 @@
 		event &= ~OHCI1394_RQPkt;
 	}
 	if (event & OHCI1394_RSPkt) {
-		struct dma_rcv_ctx *d = ohci->ar_resp_context;
+		struct dma_rcv_ctx *d = &ohci->ar_resp_context;
 		DBGMSG(ohci->id, "Got RSPkt interrupt status=0x%08X",
 		       reg_read(ohci, d->ctrlSet));
 		if (reg_read(ohci, d->ctrlSet) & 0x800)
@@ -1185,46 +1157,19 @@
 		event &= ~OHCI1394_RSPkt;
 	}
 	if (event & OHCI1394_isochRx) {
-		quadlet_t isoRecvIntEvent;
-		struct dma_rcv_ctx *d = ohci->ir_context;
-		isoRecvIntEvent = 
-			reg_read(ohci, OHCI1394_IsoRecvIntEventSet);
-		reg_write(ohci, OHCI1394_IsoRecvIntEventClear,
-			  isoRecvIntEvent);
-		DBGMSG(ohci->id, "Got isochRx interrupt "
-		       "status=0x%08X isoRecvIntEvent=%08x", 
-		       reg_read(ohci, d->ctrlSet), isoRecvIntEvent);
-		if (isoRecvIntEvent & 0x1) {
-			if (reg_read(ohci, d->ctrlSet) & 0x800)
-				ohci1394_stop_context(ohci, d->ctrlClear, 
-					     "isochRx");
-			else
-				tasklet_schedule(&d->task);
-		}
-
-		ohci1394_run_irq_hooks(ohci, isoRecvIntEvent, 0);
+		quadlet_t rx_event;
 
+		rx_event = reg_read(ohci, OHCI1394_IsoRecvIntEventSet);
+		reg_write(ohci, OHCI1394_IsoRecvIntEventClear, rx_event);
+		ohci_schedule_iso_tasklets(ohci, rx_event, 0);
 		event &= ~OHCI1394_isochRx;
 	}
 	if (event & OHCI1394_isochTx) {
-		quadlet_t isoXmitIntEvent;
-		struct dma_trm_ctx *d = ohci->it_context;
-		isoXmitIntEvent = 
-			reg_read(ohci, OHCI1394_IsoXmitIntEventSet);
-		reg_write(ohci, OHCI1394_IsoXmitIntEventClear,
-			  isoXmitIntEvent);
-                       DBGMSG(ohci->id, "Got isochTx interrupt "
-                               "status=0x%08x isoXmitIntEvent=%08x",
-                              reg_read(ohci, d->ctrlSet), isoXmitIntEvent);
+		quadlet_t tx_event;		
 
-		ohci1394_run_irq_hooks(ohci, 0, isoXmitIntEvent);
-		
-		if (isoXmitIntEvent & 0x1) {
-			if (reg_read(ohci, d->ctrlSet) & 0x800)
-				ohci1394_stop_context(ohci, d->ctrlClear, "isochTx");
-			else
-				tasklet_schedule(&d->task);
-		}
+		tx_event = reg_read(ohci, OHCI1394_IsoXmitIntEventSet);
+		reg_write(ohci, OHCI1394_IsoXmitIntEventClear, tx_event);
+		ohci_schedule_iso_tasklets(ohci, 0, tx_event);
 		event &= ~OHCI1394_isochTx;
 	}
 	if (event & OHCI1394_selfIDComplete) {
@@ -1507,25 +1452,16 @@
 {
 	struct dma_trm_ctx *d = (struct dma_trm_ctx*)data;
 	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
-	struct hpsb_packet *packet, *nextpacket;
+	struct hpsb_packet *packet;
 	unsigned long flags;
 	u32 ack;
         size_t datasize;
 
 	spin_lock_irqsave(&d->lock, flags);
 
-	if (d->fifo_first == NULL) {
-#if 0
-		ohci1394_stop_context(ohci, d->ctrlClear, 
-			     "Packet sent ack received but queue is empty");
-#endif
-		spin_unlock_irqrestore(&d->lock, flags);
-		return;
-	}
-
-	while (d->fifo_first) {
-		packet = d->fifo_first;
-                datasize = d->fifo_first->data_size;
+	while (!list_empty(&d->fifo_list)) {
+		packet = driver_packet(d->fifo_list.next);
+                datasize = packet->data_size;
 		if (datasize && packet->type != hpsb_raw)
 			ack = le32_to_cpu(
 				d->prg_cpu[d->sent_ind]->end.status) >> 16;
@@ -1576,7 +1512,7 @@
                                 d->ctx);
 #endif		
 
-                nextpacket = packet->xnext;
+                list_del(&packet->driver_list);
 		hpsb_packet_sent(ohci->host, packet, ack & 0xf);
 
 		if (datasize) {
@@ -1588,90 +1524,64 @@
 
 		d->sent_ind = (d->sent_ind+1)%d->num_desc;
 		d->free_prgs++;
-		d->fifo_first = nextpacket;
 	}
-	if (d->fifo_first == NULL)
-		d->fifo_last = NULL;
 
 	dma_trm_flush(ohci, d);
 
 	spin_unlock_irqrestore(&d->lock, flags);
 }
 
-static int free_dma_rcv_ctx(struct dma_rcv_ctx **d)
+static void free_dma_rcv_ctx(struct dma_rcv_ctx *d)
 {
 	int i;
-	struct ti_ohci *ohci;
 
-	if (*d==NULL) return -1;
-
-	ohci = (struct ti_ohci *)(*d)->ohci;
+	if (d->ohci == NULL)
+		return;
 
-	DBGMSG(ohci->id, "Freeing dma_rcv_ctx %d",(*d)->ctx);
+	DBGMSG(d->ohci->id, "Freeing dma_rcv_ctx %d", d->ctx);
 	
-	ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL);
+	ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
 
-	tasklet_kill(&(*d)->task);
+	if (d->type == DMA_CTX_ISO)
+		ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->ir_tasklet);
+	else
+		tasklet_kill(&d->task);
 
-	if ((*d)->buf_cpu) {
-		for (i=0; i<(*d)->num_desc; i++)
-			if ((*d)->buf_cpu[i] && (*d)->buf_bus[i]) {
+	if (d->buf_cpu) {
+		for (i=0; i<d->num_desc; i++)
+			if (d->buf_cpu[i] && d->buf_bus[i]) {
 				pci_free_consistent(
-					ohci->dev, (*d)->buf_size, 
-					(*d)->buf_cpu[i], (*d)->buf_bus[i]);
+					d->ohci->dev, d->buf_size, 
+					d->buf_cpu[i], d->buf_bus[i]);
 				OHCI_DMA_FREE("consistent dma_rcv buf[%d]", i);
 			}
-		kfree((*d)->buf_cpu);
-		kfree((*d)->buf_bus);
+		kfree(d->buf_cpu);
+		kfree(d->buf_bus);
 	}
-	if ((*d)->prg_cpu) {
-		for (i=0; i<(*d)->num_desc; i++) 
-			if ((*d)->prg_cpu[i] && (*d)->prg_bus[i]) {
+	if (d->prg_cpu) {
+		for (i=0; i<d->num_desc; i++) 
+			if (d->prg_cpu[i] && d->prg_bus[i]) {
 				pci_free_consistent(
-					ohci->dev, sizeof(struct dma_cmd), 
-					(*d)->prg_cpu[i], (*d)->prg_bus[i]);
+					d->ohci->dev, sizeof(struct dma_cmd), 
+					d->prg_cpu[i], d->prg_bus[i]);
 				OHCI_DMA_FREE("consistent dma_rcv prg[%d]", i);
 			}
-		kfree((*d)->prg_cpu);
-		kfree((*d)->prg_bus);
+		kfree(d->prg_cpu);
+		kfree(d->prg_bus);
 	}
-	if ((*d)->spb) kfree((*d)->spb);
+	if (d->spb) kfree(d->spb);
 
-	/* clear ISO context usage bit */
-	if ((*d)->type == DMA_CTX_ISO) {
-		clear_bit((*d)->ctx, &ohci->ir_ctx_usage);
-	}
-	       
-	kfree(*d);
-	*d = NULL;
-
-	return 0;
+	/* Mark this context as freed. */
+	d->ohci = NULL;
 }
 
-static struct dma_rcv_ctx *
-alloc_dma_rcv_ctx(struct ti_ohci *ohci, enum context_type type, int ctx, int num_desc,
+static int
+alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
+		  enum context_type type, int ctx, int num_desc,
 		  int buf_size, int split_buf_size, int context_base)
 {
-	struct dma_rcv_ctx *d;
 	int i;
 
-	if (type == DMA_CTX_ISO) {
-		/* try to claim the ISO context usage bit */
-		if (test_and_set_bit(ctx, &ohci->ir_ctx_usage)) {
-			PRINT(KERN_ERR, ohci->id, "IR DMA context %d is not available", ctx);
-			return NULL;
-		}
-	}
-	
-	d = kmalloc(sizeof(struct dma_rcv_ctx), GFP_KERNEL);
-
-	if (d == NULL) {
-		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_rcv_ctx");
-		return NULL;
-	}
-
-	memset (d, 0, sizeof (struct dma_rcv_ctx));
-
 	d->ohci = ohci;
 	d->type = type;
 	d->ctx = ctx;
@@ -1689,8 +1599,8 @@
 
 	if (d->buf_cpu == NULL || d->buf_bus == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer");
-		free_dma_rcv_ctx(&d);
-		return NULL;
+		free_dma_rcv_ctx(d);
+		return -ENOMEM;
 	}
 	memset(d->buf_cpu, 0, d->num_desc * sizeof(quadlet_t*));
 	memset(d->buf_bus, 0, d->num_desc * sizeof(dma_addr_t));
@@ -1701,8 +1611,8 @@
 
 	if (d->prg_cpu == NULL || d->prg_bus == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma prg");
-		free_dma_rcv_ctx(&d);
-		return NULL;
+		free_dma_rcv_ctx(d);
+		return -ENOMEM;
 	}
 	memset(d->prg_cpu, 0, d->num_desc * sizeof(struct dma_cmd*));
 	memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t));
@@ -1711,8 +1621,8 @@
 
 	if (d->spb == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate split buffer");
-		free_dma_rcv_ctx(&d);
-		return NULL;
+		free_dma_rcv_ctx(d);
+		return -ENOMEM;
 	}
 
 	for (i=0; i<d->num_desc; i++) {
@@ -1726,8 +1636,8 @@
 		} else {
 			PRINT(KERN_ERR, ohci->id, 
 			      "Failed to allocate dma buffer");
-			free_dma_rcv_ctx(&d);
-			return NULL;
+			free_dma_rcv_ctx(d);
+			return -ENOMEM;
 		}
 
 		
@@ -1741,80 +1651,68 @@
 		} else {
 			PRINT(KERN_ERR, ohci->id, 
 			      "Failed to allocate dma prg");
-			free_dma_rcv_ctx(&d);
-			return NULL;
+			free_dma_rcv_ctx(d);
+			return -ENOMEM;
 		}
 	}
 
         spin_lock_init(&d->lock);
 
-	/* initialize tasklet */
-	tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long)d);
+	if (type == DMA_CTX_ISO) {
+		ohci1394_init_iso_tasklet(&ohci->ir_tasklet, OHCI_ISO_RECEIVE,
+					  dma_rcv_tasklet, (unsigned long) d);
+		if (ohci1394_register_iso_tasklet(ohci,
+						  &ohci->ir_tasklet) < 0) {
+			PRINT(KERN_ERR, ohci->id, "No IR DMA context available");
+			free_dma_rcv_ctx(d);
+			return -EBUSY;
+		}
+	}
+	else
+		tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long) d);
 
-	return d;
+	return 0;
 }
 
-static int free_dma_trm_ctx(struct dma_trm_ctx **d)
+static void free_dma_trm_ctx(struct dma_trm_ctx *d)
 {
-	struct ti_ohci *ohci;
 	int i;
 
-	if (*d==NULL) return -1;
-
-	ohci = (struct ti_ohci *)(*d)->ohci;
+	if (d->ohci == NULL)
+		return;
 
-	DBGMSG(ohci->id, "Freeing dma_trm_ctx %d",(*d)->ctx);
+	DBGMSG(d->ohci->id, "Freeing dma_trm_ctx %d", d->ctx);
 
-	ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL);
+	ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
 
-	tasklet_kill(&(*d)->task);
+	if (d->type == DMA_CTX_ISO)
+		ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->it_tasklet);
+	else
+		tasklet_kill(&d->task);
 
-	if ((*d)->prg_cpu) {
-		for (i=0; i<(*d)->num_desc; i++) 
-			if ((*d)->prg_cpu[i] && (*d)->prg_bus[i]) {
+	if (d->prg_cpu) {
+		for (i=0; i<d->num_desc; i++) 
+			if (d->prg_cpu[i] && d->prg_bus[i]) {
 				pci_free_consistent(
-					ohci->dev, sizeof(struct at_dma_prg), 
-					(*d)->prg_cpu[i], (*d)->prg_bus[i]);
+					d->ohci->dev, sizeof(struct at_dma_prg), 
+					d->prg_cpu[i], d->prg_bus[i]);
 				OHCI_DMA_FREE("consistent dma_trm prg[%d]", i);
 			}
-		kfree((*d)->prg_cpu);
-		kfree((*d)->prg_bus);
+		kfree(d->prg_cpu);
+		kfree(d->prg_bus);
 	}
 
-	/* clear the ISO context usage bit */
-	if ((*d)->type == DMA_CTX_ISO) {
-		clear_bit((*d)->ctx, &ohci->it_ctx_usage);
-	}
-
-	kfree(*d);
-	*d = NULL;
-	return 0;
+	/* Mark this context as freed. */
+	d->ohci = NULL;
 }
 
-static struct dma_trm_ctx *
-alloc_dma_trm_ctx(struct ti_ohci *ohci, enum context_type type, int ctx, int num_desc,
+static int
+alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
+		  enum context_type type, int ctx, int num_desc,
 		  int context_base)
 {
-	struct dma_trm_ctx *d;
 	int i;
 
-	if (type == DMA_CTX_ISO) {
-		/* try to claim the ISO context usage bit */
-		if (test_and_set_bit(ctx, &ohci->it_ctx_usage)) {
-			PRINT(KERN_ERR, ohci->id, "IT DMA context %d is not available", ctx);
-			return NULL;
-		}
-	}
-	
-	d = kmalloc(sizeof(struct dma_trm_ctx), GFP_KERNEL);
-
-	if (d == NULL) {
-		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_trm_ctx");
-		return NULL;
-	}
-
-	memset (d, 0, sizeof (struct dma_trm_ctx));
-
 	d->ohci = ohci;
 	d->type = type;
 	d->ctx = ctx;
@@ -1829,8 +1727,8 @@
 
 	if (d->prg_cpu == NULL || d->prg_bus == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate at dma prg");
-		free_dma_trm_ctx(&d);
-		return NULL;
+		free_dma_trm_ctx(d);
+		return -ENOMEM;
 	}
 	memset(d->prg_cpu, 0, d->num_desc * sizeof(struct at_dma_prg*));
 	memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t));
@@ -1846,17 +1744,28 @@
 		} else {
 			PRINT(KERN_ERR, ohci->id, 
 			      "Failed to allocate at dma prg");
-			free_dma_trm_ctx(&d);
-			return NULL;
+			free_dma_trm_ctx(d);
+			return -ENOMEM;
 		}
 	}
 
         spin_lock_init(&d->lock);
 
-        /* initialize bottom handler */
-	tasklet_init (&d->task, dma_trm_tasklet, (unsigned long)d);
+	/* initialize tasklet */
+	if (type == DMA_CTX_ISO) {
+		ohci1394_init_iso_tasklet(&ohci->it_tasklet, OHCI_ISO_TRANSMIT,
+					  dma_rcv_tasklet, (unsigned long) d);
+		if (ohci1394_register_iso_tasklet(ohci,
+						  &ohci->it_tasklet) < 0) {
+			PRINT(KERN_ERR, ohci->id, "No IT DMA context available");
+			free_dma_trm_ctx(d);
+			return -EBUSY;
+		}
+	}
+	else
+		tasklet_init (&d->task, dma_trm_tasklet, (unsigned long)d);
 
-	return d;
+	return 0;
 }
 
 static u16 ohci_crc16 (u32 *ptr, int length)
@@ -2028,15 +1937,14 @@
 	return reg_read(ohci, OHCI1394_CSRData);
 }
 
-static struct hpsb_host_operations ohci1394_ops = {
+static struct hpsb_host_driver ohci1394_driver = {
+	.name =			OHCI1394_DRIVER_NAME,
 	.get_rom =		ohci_get_rom,
 	.transmit_packet =	ohci_transmit,
 	.devctl =		ohci_devctl,
 	.hw_csr_reg =		ohci_hw_csr_reg,
 };
 
-static struct hpsb_host_driver *ohci1394_driver;
-
 
 
 /***********************************
@@ -2059,7 +1967,6 @@
 	struct hpsb_host *host;
 	struct ti_ohci *ohci;	/* shortcut to currently handled device */
 	unsigned long ohci_base;
-	int i;
 	
 	if (version_printed++ == 0)
 		PRINT_G(KERN_INFO, "%s", version);
@@ -2069,7 +1976,7 @@
 		        card_id_counter++);
         pci_set_master(dev);
 
-	host = hpsb_alloc_host(ohci1394_driver, sizeof(struct ti_ohci));
+	host = hpsb_alloc_host(&ohci1394_driver, sizeof(struct ti_ohci));
 	if (!host) FAIL(-ENOMEM, "Failed to allocate host structure");
 
 	ohci = host->hostdata;
@@ -2151,68 +2058,78 @@
 
 	ohci->init_state = OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE;
 	/* AR DMA request context allocation */
-	ohci->ar_req_context = 
-		alloc_dma_rcv_ctx(ohci, DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC,
-				  AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE,
-				  OHCI1394_AsReqRcvContextBase);
-
-	if (ohci->ar_req_context == NULL)
+	if (alloc_dma_rcv_ctx(ohci, &ohci->ar_req_context,
+			      DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC,
+			      AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE,
+			      OHCI1394_AsReqRcvContextBase) < 0)
 		FAIL(-ENOMEM, "Failed to allocate AR Req context");
 
 	/* AR DMA response context allocation */
-	ohci->ar_resp_context = 
-		alloc_dma_rcv_ctx(ohci, DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC,
-				  AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE,
-				  OHCI1394_AsRspRcvContextBase);
-	
-	if (ohci->ar_resp_context == NULL)
+	if (alloc_dma_rcv_ctx(ohci, &ohci->ar_resp_context,
+			      DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC,
+			      AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE,
+			      OHCI1394_AsRspRcvContextBase) < 0)
 		FAIL(-ENOMEM, "Failed to allocate AR Resp context");
 
 	/* AT DMA request context */
-	ohci->at_req_context = 
-		alloc_dma_trm_ctx(ohci, DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC,
-				  OHCI1394_AsReqTrContextBase);
-	
-	if (ohci->at_req_context == NULL)
+	if (alloc_dma_trm_ctx(ohci, &ohci->at_req_context,
+			      DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC,
+			      OHCI1394_AsReqTrContextBase) < 0)
 		FAIL(-ENOMEM, "Failed to allocate AT Req context");
 
 	/* AT DMA response context */
-	ohci->at_resp_context = 
-		alloc_dma_trm_ctx(ohci, DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC,
-				  OHCI1394_AsRspTrContextBase);
-	
-	if (ohci->at_resp_context == NULL)
+	if (alloc_dma_trm_ctx(ohci, &ohci->at_resp_context,
+			      DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC,
+			      OHCI1394_AsRspTrContextBase) < 0)
 		FAIL(-ENOMEM, "Failed to allocate AT Resp context");
 
-	ohci->ir_ctx_usage = 0;
-	ohci->it_ctx_usage = 0;
-	
-	/* IR DMA context */
-	ohci->ir_context =
-		alloc_dma_rcv_ctx(ohci, DMA_CTX_ISO, 0, IR_NUM_DESC,
-				  IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
-				  OHCI1394_IsoRcvContextBase);
+	/* Start off with a soft reset, to clear everything to a sane
+	 * state. */
+	ohci_soft_reset(ohci);
 
-	if (ohci->ir_context == NULL)
-		FAIL(-ENOMEM, "Failed to allocate IR context");
+	/* Now enable LPS, which we need in order to start accessing
+	 * most of the registers.  In fact, on some cards (ALI M5251),
+	 * accessing registers in the SClk domain without LPS enabled
+	 * will lock up the machine.  Wait 50msec to make sure we have
+	 * full link enabled.  */
+	reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);
+	mdelay(50);
 
-	
-	/* IT DMA context allocation */
-	ohci->it_context =
-		alloc_dma_trm_ctx(ohci, DMA_CTX_ISO, 0, IT_NUM_DESC,
-				  OHCI1394_IsoXmitContextBase);
+	/* Determine the number of available IR and IT contexts. */
+	ohci->nb_iso_rcv_ctx =
+		get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
+	DBGMSG(ohci->id, "%d iso receive contexts available",
+	       ohci->nb_iso_rcv_ctx);
 
-	if (ohci->it_context == NULL)
-		FAIL(-ENOMEM, "Failed to allocate IT context");
+	ohci->nb_iso_xmit_ctx =
+		get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
+	DBGMSG(ohci->id, "%d iso transmit contexts available",
+	       ohci->nb_iso_xmit_ctx);
+
+	/* Set the usage bits for non-existent contexts so they can't
+	 * be allocated */
+	ohci->ir_ctx_usage = ~0 << ohci->nb_iso_rcv_ctx;
+	ohci->it_ctx_usage = ~0 << ohci->nb_iso_xmit_ctx;
 
+	INIT_LIST_HEAD(&ohci->iso_tasklet_list);
+	spin_lock_init(&ohci->iso_tasklet_list_lock);
 	ohci->ISO_channel_usage = 0;
         spin_lock_init(&ohci->IR_channel_lock);
 
-	for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) {
-		ohci->irq_hooks[i].irq_handler = NULL;
-		ohci->irq_hooks[i].data = NULL;
-	}
+	/* IR DMA context */
+	if (alloc_dma_rcv_ctx(ohci, &ohci->ir_context,
+			      DMA_CTX_ISO, 0, IR_NUM_DESC,
+			      IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
+			      OHCI1394_IsoRcvContextBase) < 0)
+		FAIL(-ENOMEM, "Failed to allocate IR context");
+
 	
+	/* IT DMA context allocation */
+	if (alloc_dma_trm_ctx(ohci, &ohci->it_context,
+			      DMA_CTX_ISO, 0, IT_NUM_DESC,
+			      OHCI1394_IsoXmitContextBase) < 0)
+		FAIL(-ENOMEM, "Failed to allocate IT context");
+
 	if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,
 			 OHCI1394_DRIVER_NAME, ohci))
 		FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq);
@@ -2355,65 +2272,69 @@
 	if (msg) PRINT(KERN_ERR, ohci->id, "%s: dma prg stopped", msg);
 }
 
-static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci,
-					  quadlet_t isoRecvEvent, 
-					  quadlet_t isoXmitEvent)
+void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, int type,
+			       void (*func)(unsigned long), unsigned long data)
 {
-	int i;
-	for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) {
-		if(ohci->irq_hooks[i].irq_handler != NULL) {
-			ohci->irq_hooks[i].irq_handler(ohci->id, isoRecvEvent, isoXmitEvent,
-						       ohci->irq_hooks[i].data);
-		}
-	}
+	tasklet_init(&tasklet->tasklet, func, data);
+	tasklet->type = type;
+	/* We init the tasklet->link field, so we can list_del() it
+	 * without worrying wether it was added to the list or not. */
+	INIT_LIST_HEAD(&tasklet->link);
 }
 
-int ohci1394_hook_irq(struct ti_ohci *ohci,
-		      void (*irq_handler) (int, quadlet_t, quadlet_t, void *),
-		      void *data)
+int ohci1394_register_iso_tasklet(struct ti_ohci *ohci,
+				  struct ohci1394_iso_tasklet *tasklet)
 {
-	int i;
-	
-	/* find a free slot */
-	for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) {
-		if(ohci->irq_hooks[i].irq_handler == NULL)
-			break;
+	unsigned long flags, *usage;
+	int n, i, r = -EBUSY;
+
+	if (tasklet->type == OHCI_ISO_TRANSMIT) {
+		n = ohci->nb_iso_xmit_ctx;
+		usage = &ohci->it_ctx_usage;
+	}
+	else {
+		n = ohci->nb_iso_rcv_ctx;
+		usage = &ohci->ir_ctx_usage;
 	}
 
-	if(i >= OHCI1394_MAX_IRQ_HOOKS)
-		return -EBUSY;
+	spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
 
-	ohci->irq_hooks[i].irq_handler = irq_handler;
-	ohci->irq_hooks[i].data = data;
+	for (i = 0; i < n; i++)
+		if (!test_and_set_bit(i, usage)) {
+			tasklet->context = i;
+			list_add_tail(&tasklet->link, &ohci->iso_tasklet_list);
+			r = 0;
+			break;
+		}
 
-	/* ohci1394 will never be unloaded while an IRQ hook is
-	   in use, because the user must reference this symbol */
+	spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
 	
-	return 0;
+	return r;
 }
 
-void ohci1394_unhook_irq(struct ti_ohci *ohci,
-			 void (*irq_handler) (int, quadlet_t, quadlet_t, void *),
-			 void *data)
+void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
+				     struct ohci1394_iso_tasklet *tasklet)
 {
-	int i;
-	
-	for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) {
-		if( (ohci->irq_hooks[i].irq_handler == irq_handler) &&
-		    (ohci->irq_hooks[i].data == data) )
-			break;
-	}
-	
-	if(i < OHCI1394_MAX_IRQ_HOOKS) {
-		ohci->irq_hooks[i].irq_handler = NULL;
-		ohci->irq_hooks[i].data = NULL;
-	}
+	unsigned long flags;
+
+	tasklet_kill(&tasklet->tasklet);
+
+	spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
+
+	if (tasklet->type == OHCI_ISO_TRANSMIT)
+		clear_bit(tasklet->context, &ohci->it_ctx_usage);
+	else
+		clear_bit(tasklet->context, &ohci->ir_ctx_usage);
+
+	list_del(&tasklet->link);
+
+	spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
 }
 
 EXPORT_SYMBOL(ohci1394_stop_context);
-EXPORT_SYMBOL(ohci1394_hook_irq);
-EXPORT_SYMBOL(ohci1394_unhook_irq);
-
+EXPORT_SYMBOL(ohci1394_init_iso_tasklet);
+EXPORT_SYMBOL(ohci1394_register_iso_tasklet);
+EXPORT_SYMBOL(ohci1394_unregister_iso_tasklet);
 
 
 /***********************************
@@ -2427,27 +2348,11 @@
 static void __exit ohci1394_cleanup (void)
 {
 	pci_unregister_driver(&ohci1394_pci_driver);
-	hpsb_unregister_lowlevel(ohci1394_driver);
 }
 
 static int __init ohci1394_init(void)
 {
-	int ret;
-
-	ohci1394_driver = hpsb_register_lowlevel(&ohci1394_ops,
-						 OHCI1394_DRIVER_NAME);
-	if (!ohci1394_driver) {
-		PRINT_G(KERN_ERR, "hpsb_register_lowlevel failed");
-		return -ENOMEM;
-	}
-
-	ret = pci_module_init(&ohci1394_pci_driver);
-	if (ret < 0) {
-		PRINT_G(KERN_ERR, "pci_module_init failed");
-		hpsb_unregister_lowlevel(ohci1394_driver);
-		return ret;
-	}
-	return ret;
+	return pci_module_init(&ohci1394_pci_driver);
 }
 
 module_init(ohci1394_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/ohci1394.h linux-2.4.20/drivers/ieee1394/ohci1394.h
--- linux-2.4.19/drivers/ieee1394/ohci1394.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/ohci1394.h	2002-10-29 11:18:33.000000000 +0000
@@ -127,12 +127,10 @@
         quadlet_t *branchAddrPtr;
 
 	/* list of packets inserted in the AT FIFO */
-        struct hpsb_packet *fifo_first;
-        struct hpsb_packet *fifo_last;
+	struct list_head fifo_list;
 
 	/* list of pending packets to be inserted in the AT FIFO */
-        struct hpsb_packet *pending_first;
-        struct hpsb_packet *pending_last;
+	struct list_head pending_list;
 
         spinlock_t lock;
         struct tasklet_struct task;
@@ -141,6 +139,13 @@
 	int cmdPtr;
 };
 
+struct ohci1394_iso_tasklet {
+	struct tasklet_struct tasklet;
+	struct list_head link;
+	int context;
+	enum { OHCI_ISO_TRANSMIT, OHCI_ISO_RECEIVE } type;
+};
+
 struct ti_ohci {
         int id; /* sequential card number */
 
@@ -172,21 +177,23 @@
 	unsigned int max_packet_size;
 
         /* async receive */
-	struct dma_rcv_ctx *ar_resp_context;
-	struct dma_rcv_ctx *ar_req_context;
+	struct dma_rcv_ctx ar_resp_context;
+	struct dma_rcv_ctx ar_req_context;
 
 	/* async transmit */
-	struct dma_trm_ctx *at_resp_context;
-	struct dma_trm_ctx *at_req_context;
+	struct dma_trm_ctx at_resp_context;
+	struct dma_trm_ctx at_req_context;
 
         /* iso receive */
-	struct dma_rcv_ctx *ir_context;
+	struct dma_rcv_ctx ir_context;
+	struct ohci1394_iso_tasklet ir_tasklet;
         spinlock_t IR_channel_lock;
 	int nb_iso_rcv_ctx;
 	unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */
 	
         /* iso transmit */
-	struct dma_trm_ctx *it_context;
+	struct dma_trm_ctx it_context;
+	struct ohci1394_iso_tasklet it_tasklet;
 	int nb_iso_xmit_ctx;
 	unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */
 	
@@ -202,16 +209,12 @@
 
 	int self_id_errors;
 
-	/* IRQ hooks, for video1394 and dv1394 */
+	/* Tasklets for iso receive and transmit, used by video1394,
+	 * amdtp and dv1394 */
 	
-#define OHCI1394_MAX_IRQ_HOOKS 16
+	struct list_head iso_tasklet_list;
+	spinlock_t iso_tasklet_list_lock;
 	
-	struct ohci1394_irq_hook {
-		void (*irq_handler) (int card, quadlet_t isoRecvEvent, 
-				     quadlet_t isoXmitEvent, void *data);
-		void *data;
-	} irq_hooks[OHCI1394_MAX_IRQ_HOOKS];
-
 	/* Swap the selfid buffer? */
 	unsigned int selfid_swap:1;
 	/* Some Apple chipset seem to swap incoming headers for us */
@@ -399,15 +402,17 @@
 
 #define OHCI1394_TCODE_PHY               0xE
 
-void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
+void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, 
+			       int type,
+			       void (*func)(unsigned long), 
+			       unsigned long data);
+int ohci1394_register_iso_tasklet(struct ti_ohci *ohci,
+				  struct ohci1394_iso_tasklet *tasklet);
+void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
+				     struct ohci1394_iso_tasklet *tasklet);
+
+void ohci1394_stop_context      (struct ti_ohci *ohci, int reg, char *msg);
 struct ti_ohci *ohci1394_get_struct(int card_num);
 
-int ohci1394_hook_irq(struct ti_ohci *ohci,
-		      void (*irq_handler) (int, quadlet_t, quadlet_t, void *),
-		      void *data);
-
-void ohci1394_unhook_irq(struct ti_ohci *ohci,
-			 void (*irq_handler) (int, quadlet_t, quadlet_t, void *),
-			 void *data);
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/pcilynx.c linux-2.4.20/drivers/ieee1394/pcilynx.c
--- linux-2.4.19/drivers/ieee1394/pcilynx.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/pcilynx.c	2002-10-29 11:18:37.000000000 +0000
@@ -65,7 +65,7 @@
 static int skip_eeprom = 0;
 
 
-static struct hpsb_host_driver *lynx_driver;
+static struct hpsb_host_driver lynx_driver;
 static unsigned int card_id;
 
 
@@ -466,7 +466,7 @@
         struct hpsb_packet *packet;
 
         d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async);
-        packet = d->queue;
+        packet = driver_packet(d->queue.next);
 
         d->header_dma = pci_map_single(lynx->dev, packet->header,
                                        packet->header_size, PCI_DMA_TODEVICE);
@@ -538,7 +538,6 @@
                 return 0;
         }
 
-        packet->xnext = NULL;
         if (packet->tcode == TCODE_WRITEQ
             || packet->tcode == TCODE_READQ_RESPONSE) {
                 cpu_to_be32s(&packet->header[3]);
@@ -546,14 +545,9 @@
 
         spin_lock_irqsave(&d->queue_lock, flags);
 
-        if (d->queue == NULL) {
-                d->queue = packet;
-                d->queue_last = packet;
+	list_add_tail(&packet->driver_list, &d->queue);
+	if (d->queue.next == &packet->driver_list)
                 send_next(lynx, packet->type);
-        } else {
-                d->queue_last->xnext = packet;
-                d->queue_last = packet;
-        }
 
         spin_unlock_irqrestore(&d->queue_lock, flags);
 
@@ -566,7 +560,8 @@
 {
         struct ti_lynx *lynx = host->hostdata;
         int retval = 0;
-        struct hpsb_packet *packet, *lastpacket;
+        struct hpsb_packet *packet;
+	LIST_HEAD(packet_list);
         unsigned long flags;
 
         switch (cmd) {
@@ -620,16 +615,16 @@
                 spin_lock_irqsave(&lynx->async.queue_lock, flags);
 
                 reg_write(lynx, DMA_CHAN_CTRL(CHANNEL_ASYNC_SEND), 0);
-                packet = lynx->async.queue;
-                lynx->async.queue = NULL;
+		list_splice(&lynx->async.queue, &packet_list);
+		INIT_LIST_HEAD(&lynx->async.queue);
 
                 spin_unlock_irqrestore(&lynx->async.queue_lock, flags);
 
-                while (packet != NULL) {
-                        lastpacket = packet;
-                        packet = packet->xnext;
-                        hpsb_packet_sent(host, lastpacket, ACKX_ABORTED);
-                }
+		while (!list_empty(&packet_list)) {
+			packet = driver_packet(packet_list.next);
+			list_del(&packet->driver_list);
+			hpsb_packet_sent(host, packet, ACKX_ABORTED);
+		}
 
                 break;
 
@@ -892,10 +887,17 @@
         struct memdata *md = (struct memdata *)file->private_data;
         ssize_t bcount;
         size_t alignfix;
-        int off = (int)*offset; /* avoid useless 64bit-arithmetic */
+	loff_t off = *offset; /* avoid useless 64bit-arithmetic */
         ssize_t retval;
         void *membase;
 
+	if (*offset != off)	/* Check for EOF before we trust wrap */
+		return 0;
+	
+	/* FIXME: Signed wrap is undefined in C - wants fixing up */
+	if (off + count > off)
+		return 0;
+		
         if ((off + count) > PCILYNX_MAX_MEMORY + 1) {
                 count = PCILYNX_MAX_MEMORY + 1 - off;
         }
@@ -1122,8 +1124,9 @@
                 spin_lock(&lynx->async.queue_lock);
 
                 ack = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_SEND));
-                packet = lynx->async.queue;
-                lynx->async.queue = packet->xnext;
+
+		packet = driver_packet(lynx->async.queue.next);
+		list_del(&packet->driver_list);
 
                 pci_unmap_single(lynx->dev, lynx->async.header_dma,
                                  packet->header_size, PCI_DMA_TODEVICE);
@@ -1132,7 +1135,7 @@
                                          packet->data_size, PCI_DMA_TODEVICE);
                 }
 
-                if (lynx->async.queue != NULL) {
+                if (!list_empty(&lynx->async.queue)) {
                         send_next(lynx, hpsb_async);
                 }
 
@@ -1154,8 +1157,8 @@
 
                 spin_lock(&lynx->iso_send.queue_lock);
 
-                packet = lynx->iso_send.queue;
-                lynx->iso_send.queue = packet->xnext;
+		packet = driver_packet(lynx->iso_send.queue.next);
+		list_del(&packet->driver_list);
 
                 pci_unmap_single(lynx->dev, lynx->iso_send.header_dma,
                                  packet->header_size, PCI_DMA_TODEVICE);
@@ -1164,7 +1167,7 @@
                                          packet->data_size, PCI_DMA_TODEVICE);
                 }
 
-                if (lynx->iso_send.queue != NULL) {
+                if (!list_empty(&lynx->iso_send.queue)) {
                         send_next(lynx, hpsb_iso);
                 }
 
@@ -1327,7 +1330,7 @@
 
         error = -ENOMEM;
 
-	host = hpsb_alloc_host(lynx_driver, sizeof(struct ti_lynx));
+	host = hpsb_alloc_host(&lynx_driver, sizeof(struct ti_lynx));
         if (!host) FAIL("failed to allocate control structure memory");
 
         lynx = host->hostdata;
@@ -1471,7 +1474,8 @@
         lynx->selfid_size = -1;
         lynx->phy_reg0 = -1;
 
-        lynx->async.queue = NULL;
+	INIT_LIST_HEAD(&lynx->async.queue);
+	INIT_LIST_HEAD(&lynx->iso_send.queue);
 
         pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
         put_pcl(lynx, lynx->rcv_pcl_start, &pcl);
@@ -1697,7 +1701,8 @@
         .remove =   __devexit_p(remove_card),
 };
 
-static struct hpsb_host_operations lynx_ops = {
+static struct hpsb_host_driver lynx_driver = {
+	.name =		   PCILYNX_DRIVER_NAME,
         .get_rom =         get_lynx_rom,
         .transmit_packet = lynx_transmit,
         .devctl =          lynx_devctl,
@@ -1721,22 +1726,14 @@
         }
 #endif
 
-        lynx_driver = hpsb_register_lowlevel(&lynx_ops, PCILYNX_DRIVER_NAME);
-        if (!lynx_driver) {
-                ret = -ENOMEM;
-                goto free_char_dev;
-        }
-
         ret = pci_module_init(&lynx_pci_driver);
         if (ret < 0) {
                 PRINT_G(KERN_ERR, "PCI module init failed");
-                goto unregister_lowlevel;
+                goto free_char_dev;
         }
 
         return 0;
 
- unregister_lowlevel:
-        hpsb_unregister_lowlevel(lynx_driver);
  free_char_dev:
 #ifdef CONFIG_IEEE1394_PCILYNX_PORTS
         unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
@@ -1748,7 +1745,6 @@
 static void __exit pcilynx_cleanup(void)
 {
         pci_unregister_driver(&lynx_pci_driver);
-        hpsb_unregister_lowlevel(lynx_driver);
 
 #ifdef CONFIG_IEEE1394_PCILYNX_PORTS
         unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/pcilynx.h linux-2.4.20/drivers/ieee1394/pcilynx.h
--- linux-2.4.19/drivers/ieee1394/pcilynx.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/pcilynx.h	2002-10-29 11:18:31.000000000 +0000
@@ -94,7 +94,7 @@
 
         struct lynx_send_data {
                 pcl_t pcl_start, pcl;
-                struct hpsb_packet *queue, *queue_last;
+                struct list_head queue;
                 spinlock_t queue_lock;
                 dma_addr_t header_dma, data_dma;
                 int channel;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/raw1394.c linux-2.4.20/drivers/ieee1394/raw1394.c
--- linux-2.4.19/drivers/ieee1394/raw1394.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/raw1394.c	2002-10-29 11:18:31.000000000 +0000
@@ -743,7 +743,7 @@
         }
 
         req->tq.data = req;
-        queue_task(&req->tq, &packet->complete_tq);
+        hpsb_add_packet_complete_task(packet, &req->tq);
 
         spin_lock_irq(&fi->reqlists_lock);
         list_add_tail(&req->list, &fi->req_pending);
@@ -786,7 +786,7 @@
         req->tq.data = req;
         req->tq.routine = (void (*)(void*))queue_complete_req;
         req->req.length = 0;
-        queue_task(&req->tq, &packet->complete_tq);
+	hpsb_add_packet_complete_task(packet, &req->tq);
 
         spin_lock_irq(&fi->reqlists_lock);
         list_add_tail(&req->list, &fi->req_pending);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/sbp2.c linux-2.4.20/drivers/ieee1394/sbp2.c
--- linux-2.4.19/drivers/ieee1394/sbp2.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/sbp2.c	2002-10-29 11:18:33.000000000 +0000
@@ -351,15 +351,15 @@
 #include "sbp2.h"
 
 static char version[] __devinitdata =
-	"$Rev: 530 $ James Goodwin <jamesg@filanet.com>";
+	"$Rev: 584 $ James Goodwin <jamesg@filanet.com>";
 
 /*
  * Module load parameter definitions
  */
 
 /*
- * Change sbp2_max_speed on module load if you have a bad IEEE-1394 controller
- * that has trouble running 2KB packets at 400mb.
+ * Change sbp2_max_speed on module load if you have a bad IEEE-1394
+ * controller that has trouble running 2KB packets at 400mb.
  *
  * NOTE: On certain OHCI parts I have seen short packets on async transmit
  * (probably due to PCI latency/throughput issues with the part). You can
@@ -375,48 +375,54 @@
 static int sbp2_max_speed = SPEED_400;
 
 /*
- * Set sbp2_serialize_io to 1 if you'd like only one scsi command sent down to
- * us at a time (debugging). This might be necessary for very badly behaved sbp2 devices.
+ * Set sbp2_serialize_io to 1 if you'd like only one scsi command sent
+ * down to us at a time (debugging). This might be necessary for very
+ * badly behaved sbp2 devices.
  */
 MODULE_PARM(sbp2_serialize_io,"i");
 MODULE_PARM_DESC(sbp2_serialize_io, "Serialize all I/O coming down from the scsi drivers (default = 0)");
 static int sbp2_serialize_io = 0;	/* serialize I/O - available for debugging purposes */
 
 /*
- * Bump up sbp2_max_sectors if you'd like to support very large sized transfers. Please note 
- * that some older sbp2 bridge chips are broken for transfers greater or equal to 128KB.
- * Default is a value of 255 sectors, or just under 128KB (at 512 byte sector size). I can note
- * that the Oxsemi sbp2 chipsets have no problems supporting very large transfer sizes.
+ * Bump up sbp2_max_sectors if you'd like to support very large sized
+ * transfers. Please note that some older sbp2 bridge chips are broken for
+ * transfers greater or equal to 128KB.  Default is a value of 255
+ * sectors, or just under 128KB (at 512 byte sector size). I can note that
+ * the Oxsemi sbp2 chipsets have no problems supporting very large
+ * transfer sizes.
  */
 MODULE_PARM(sbp2_max_sectors,"i");
 MODULE_PARM_DESC(sbp2_max_sectors, "Change max sectors per I/O supported (default = 255)");
 static int sbp2_max_sectors = SBP2_MAX_SECTORS;
 
 /*
- * Adjust sbp2_max_outstanding_cmds to tune performance if you have many sbp2 devices attached
- * (or if you need to do some debugging).
+ * Adjust sbp2_max_outstanding_cmds to tune performance if you have many
+ * sbp2 devices attached (or if you need to do some debugging).
  */
 MODULE_PARM(sbp2_max_outstanding_cmds,"i");
 MODULE_PARM_DESC(sbp2_max_outstanding_cmds, "Change max outstanding concurrent commands (default = 8)");
 static int sbp2_max_outstanding_cmds = SBP2SCSI_MAX_OUTSTANDING_CMDS;
 
 /*
- * Adjust sbp2_max_cmds_per_lun to tune performance. Enabling more than one concurrent/linked 
- * command per sbp2 device may allow some performance gains, but some older sbp2 devices have 
- * firmware bugs resulting in problems when linking commands... so, enable this with care. 
- * I can note that the Oxsemi OXFW911 sbp2 chipset works very well with large numbers of 
- * concurrent/linked commands.  =)
+ * Adjust sbp2_max_cmds_per_lun to tune performance. Enabling more than
+ * one concurrent/linked command per sbp2 device may allow some
+ * performance gains, but some older sbp2 devices have firmware bugs
+ * resulting in problems when linking commands... so, enable this with
+ * care.  I can note that the Oxsemi OXFW911 sbp2 chipset works very well
+ * with large numbers of concurrent/linked commands.  =)
  */
 MODULE_PARM(sbp2_max_cmds_per_lun,"i");
 MODULE_PARM_DESC(sbp2_max_cmds_per_lun, "Change max concurrent commands per sbp2 device (default = 1)");
 static int sbp2_max_cmds_per_lun = SBP2SCSI_MAX_CMDS_PER_LUN;
 
 /*
- * Exclusive login to sbp2 device? In most cases, the sbp2 driver should do an exclusive login, as it's
- * generally unsafe to have two hosts talking to a single sbp2 device at the same time (filesystem
- * coherency, etc.). If you're running an sbp2 device that supports multiple logins, and you're either
- * running read-only filesystems or some sort of special filesystem supporting multiple hosts, then
- * set sbp2_exclusive_login to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
+ * Exclusive login to sbp2 device? In most cases, the sbp2 driver should
+ * do an exclusive login, as it's generally unsafe to have two hosts
+ * talking to a single sbp2 device at the same time (filesystem coherency,
+ * etc.). If you're running an sbp2 device that supports multiple logins,
+ * and you're either running read-only filesystems or some sort of special
+ * filesystem supporting multiple hosts, then set sbp2_exclusive_login to
+ * zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
  * concurrent logins.
  */
 MODULE_PARM(sbp2_exclusive_login,"i");
@@ -424,9 +430,14 @@
 static int sbp2_exclusive_login = 1;
 
 /*
- * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on if your sbp2 device
- * is not properly handling the SCSI inquiry command. This hack makes the inquiry look more
- * like a typical MS Windows inquiry.
+ * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on
+ * if your sbp2 device is not properly handling the SCSI inquiry command.
+ * This hack makes the inquiry look more like a typical MS Windows
+ * inquiry.
+ * 
+ * If sbp2_force_inquiry_hack=1 is required for your device to work,
+ * please submit the logged sbp2_firmware_revision value of this device to
+ * the linux1394-devel mailing list.
  */
 MODULE_PARM(sbp2_force_inquiry_hack,"i");
 MODULE_PARM_DESC(sbp2_force_inquiry_hack, "Force SCSI inquiry hack (default = 0)");
@@ -551,13 +562,17 @@
 	.update = 	sbp2_update
 };
 
-/* List of device firmware's that require a forced 36 byte inquiry. Note
- * the final 0x0 needs to be there for denoting end of list.  */
+/* List of device firmware's that require a forced 36 byte inquiry.  */
 static u32 sbp2_broken_inquiry_list[] = {
 	0x00002800,	/* Stefan Richter <richtest@bauwesen.tu-cottbus.de> */
-	0x0
+			/* DViCO Momobay CX-1 */
+	0x00000200	/* Andreas Plesch <plesch@fas.harvard.edu> */
+			/* QPS Fire DVDBurner */
 };
 
+#define NUM_BROKEN_INQUIRY_DEVS \
+	(sizeof(sbp2_broken_inquiry_list)/sizeof(*sbp2_broken_inquiry_list))
+
 /**************************************
  * General utility functions
  **************************************/
@@ -788,7 +803,7 @@
 		request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet;
 		request_packet->tq.data = request_packet;
 		request_packet->hi_context = hi;
-		queue_task(&request_packet->tq, &packet->complete_tq);
+		hpsb_add_packet_complete_task(packet, &request_packet->tq);
 
 		/*
 		 * Now, put the packet on the in-use list.
@@ -1915,7 +1930,10 @@
 			/* Firmware revision */
 			scsi_id->sbp2_firmware_revision
 				= CONFIG_ROM_VALUE(ud->quadlets[i]);
-			SBP2_DEBUG("sbp2_firmware_revision = %x",
+			if (sbp2_force_inquiry_hack)
+				SBP2_INFO("sbp2_firmware_revision = %x",
+				   (unsigned int) scsi_id->sbp2_firmware_revision);
+			else	SBP2_DEBUG("sbp2_firmware_revision = %x",
 				   (unsigned int) scsi_id->sbp2_firmware_revision);
 			break;
 
@@ -1949,19 +1967,14 @@
 
 	/* Check for a blacklisted set of devices that require us to force
 	 * a 36 byte host inquiry. This can be overriden as a module param
-	 * (to force all hosts).
-	 *
-	 * XXX If this does not detect your firmware as being defective,
-	 * but using the sbp2_force_inquiry_hack allows your device to
-	 * work, please submit the value of your firmware revision to the
-	 * linux1394-devel mailing list.  */
-	for (i = 0; sbp2_broken_inquiry_list[i]; i++) {
+	 * (to force all hosts).  */
+	for (i = 0; i < NUM_BROKEN_INQUIRY_DEVS; i++) {
 		if ((scsi_id->sbp2_firmware_revision & 0xffff00) ==
 				sbp2_broken_inquiry_list[i]) {
 			SBP2_WARN("Node " NODE_BUS_FMT ": Using 36byte inquiry workaround",
 					NODE_BUS_ARGS(scsi_id->ne->nodeid));
 			scsi_id->workarounds |= SBP2_BREAKAGE_INQUIRY_HACK;
-			break; // No need to continue.
+			break; /* No need to continue. */
 		}
 	}
 }
@@ -3135,7 +3148,11 @@
 /*
  * Called by scsi stack to get bios parameters (used by fdisk, and at boot).
  */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28)
 static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]) 
+#else
+static int sbp2scsi_biosparam (Scsi_Disk *disk, struct block_device *dev, int geom[]) 
+#endif
 {
 	int heads, sectors, cylinders;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/sbp2.h linux-2.4.20/drivers/ieee1394/sbp2.h
--- linux-2.4.19/drivers/ieee1394/sbp2.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/sbp2.h	2002-10-29 11:18:34.000000000 +0000
@@ -549,7 +549,11 @@
 static int sbp2scsi_detect (Scsi_Host_Template *tpnt);
 static const char *sbp2scsi_info (struct Scsi_Host *host);
 void sbp2scsi_setup(char *str, int *ints);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28)
 static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]);
+#else
+static int sbp2scsi_biosparam (Scsi_Disk *disk, struct block_device *dev, int geom[]);
+#endif
 static int sbp2scsi_abort (Scsi_Cmnd *SCpnt); 
 static int sbp2scsi_reset (Scsi_Cmnd *SCpnt); 
 static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/ieee1394/video1394.c linux-2.4.20/drivers/ieee1394/video1394.c
--- linux-2.4.19/drivers/ieee1394/video1394.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/ieee1394/video1394.c	2002-10-29 11:18:33.000000000 +0000
@@ -56,8 +56,6 @@
 #include "ohci1394.h"
 
 #define ISO_CHANNELS 64
-#define ISO_RECEIVE 0
-#define ISO_TRANSMIT 1
 
 #ifndef virt_to_page
 #define virt_to_page(x) MAP_NR(x)
@@ -84,9 +82,10 @@
 
 struct dma_iso_ctx {
 	struct ti_ohci *ohci;
-	int type; /* ISO_TRANSMIT or ISO_RECEIVE */
-	int ctx;
+	int type; /* OHCI_ISO_TRANSMIT or OHCI_ISO_RECEIVE */
+	struct ohci1394_iso_tasklet iso_tasklet;
 	int channel;
+	int ctx;
 	int last_buffer;
 	int * next_buffer;  /* For ISO Transmit of video packets
 			       to write the correct SYT field
@@ -153,8 +152,8 @@
 #define PRINT(level, card, fmt, args...) \
 printk(level "video1394_%d: " fmt "\n" , card , ## args)
 
-static void irq_handler(int card, quadlet_t isoRecvIntEvent, 
-			quadlet_t isoXmitIntEvent, void *data);
+void wakeup_dma_ir_ctx(unsigned long l);
+void wakeup_dma_it_ctx(unsigned long l);
 
 static LIST_HEAD(video1394_cards);
 static spinlock_t video1394_cards_lock = SPIN_LOCK_UNLOCKED;
@@ -234,12 +233,12 @@
 static int free_dma_iso_ctx(struct dma_iso_ctx *d)
 {
 	int i;
-	unsigned long *usage;
 	
 	DBGMSG(d->ohci->id, "Freeing dma_iso_ctx %d", d->ctx);
 
 	ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
-	ohci1394_unhook_irq(d->ohci, irq_handler, d);
+	if (d->iso_tasklet.link.next != NULL)
+		ohci1394_unregister_iso_tasklet(d->ohci, &d->iso_tasklet);
 
 	if (d->buf)
 		rvfree((void *)d->buf, d->num_desc * d->buf_size);
@@ -265,11 +264,6 @@
 	if (d->next_buffer)
 		kfree(d->next_buffer);
 
-	usage = (d->type == ISO_RECEIVE) ? &d->ohci->ir_ctx_usage :
-		&d->ohci->it_ctx_usage;
-       
-	/* clear the ISO context usage bit */
-	clear_bit(d->ctx, usage);
 	list_del(&d->link);
 
 	kfree(d);
@@ -281,55 +275,28 @@
 alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc,
 		  int buf_size, int channel, unsigned int packet_size)
 {
-	struct dma_iso_ctx *d=NULL;
+	struct dma_iso_ctx *d;
 	int i;
 
-	unsigned long *usage = (type == ISO_RECEIVE) ? &ohci->ir_ctx_usage :
-		                                       &ohci->it_ctx_usage;
-
-	/* try to claim the ISO context usage bit */
-	for (i = 0; i < ohci->nb_iso_rcv_ctx; i++) {
-		if (!test_and_set_bit(i, usage)) {
-			PRINT(KERN_ERR, ohci->id, "Free iso ctx %d found", i);
-			break;
-		}
-	}
-
-	if (i == ohci->nb_iso_rcv_ctx) {
-		PRINT(KERN_ERR, ohci->id, "No DMA contexts available");
-		return NULL;
-	}
-	
-	d = (struct dma_iso_ctx *)kmalloc(sizeof(struct dma_iso_ctx), 
-					  GFP_KERNEL);
-	if (d==NULL) {
+	d = kmalloc(sizeof(struct dma_iso_ctx), GFP_KERNEL);
+	if (d == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_iso_ctx");
 		return NULL;
 	}
 
-	memset(d, 0, sizeof(struct dma_iso_ctx));
+	memset(d, 0, sizeof *d);
 
-	d->ohci = (void *)ohci;
+	d->ohci = ohci;
 	d->type = type;
-	d->ctx = i;
 	d->channel = channel;
 	d->num_desc = num_desc;
 	d->frame_size = buf_size;
-	if (buf_size%PAGE_SIZE) 
-		d->buf_size = buf_size + PAGE_SIZE - (buf_size%PAGE_SIZE);
-	else
-		d->buf_size = buf_size;
+	d->buf_size = PAGE_ALIGN(buf_size);
 	d->last_buffer = -1;
 	d->buf = NULL;
 	d->ir_prg = NULL;
 	init_waitqueue_head(&d->waitq);
 
-	if (ohci1394_hook_irq(ohci, irq_handler, d) != 0) {
-		PRINT(KERN_ERR, ohci->id, "ohci1394_hook_irq() failed");
-		free_dma_iso_ctx(d);
-		return NULL;
-	}
-
 	d->buf = rvmalloc(d->num_desc * d->buf_size);
 
 	if (d->buf == NULL) {
@@ -339,7 +306,24 @@
 	}
 	memset(d->buf, 0, d->num_desc * d->buf_size);
 
-	if (type == ISO_RECEIVE) {
+	if (type == OHCI_ISO_RECEIVE)
+		ohci1394_init_iso_tasklet(&d->iso_tasklet, type,
+					  wakeup_dma_ir_ctx,
+					  (unsigned long) d);
+	else
+		ohci1394_init_iso_tasklet(&d->iso_tasklet, type,
+					  wakeup_dma_it_ctx,
+					  (unsigned long) d);
+
+	if (ohci1394_register_iso_tasklet(ohci, &d->iso_tasklet) < 0) {
+		PRINT(KERN_ERR, ohci->id, "no free iso %s contexts",
+		      type == OHCI_ISO_RECEIVE ? "receive" : "transmit");
+		free_dma_iso_ctx(d);
+		return NULL;
+	}
+	d->ctx = d->iso_tasklet.context;
+
+	if (type == OHCI_ISO_RECEIVE) {
 		d->ctrlSet = OHCI1394_IsoRcvContextControlSet+32*d->ctx;
 		d->ctrlClear = OHCI1394_IsoRcvContextControlClear+32*d->ctx;
 		d->cmdPtr = OHCI1394_IsoRcvCommandPtr+32*d->ctx;
@@ -359,7 +343,7 @@
 		d->nb_cmd = d->buf_size / PAGE_SIZE + 1;
 		d->left_size = (d->frame_size % PAGE_SIZE) ?
 			d->frame_size % PAGE_SIZE : PAGE_SIZE;
-
+ 
 		for (i=0;i<d->num_desc;i++) {
 			d->ir_prg[i] = kmalloc(d->nb_cmd * 
 					       sizeof(struct dma_cmd), 
@@ -371,8 +355,9 @@
 				return NULL;
 			}
 		}
+
 	}
-	else {  /* ISO_TRANSMIT */
+	else {  /* OHCI_ISO_TRANSMIT */
 		d->ctrlSet = OHCI1394_IsoXmitContextControlSet+16*d->ctx;
 		d->ctrlClear = OHCI1394_IsoXmitContextControlClear+16*d->ctx;
 		d->cmdPtr = OHCI1394_IsoXmitCommandPtr+16*d->ctx;
@@ -458,7 +443,7 @@
 
 	PRINT(KERN_INFO, ohci->id, "Iso %s DMA: %d buffers "
 	      "of size %d allocated for a frame size %d, each with %d prgs",
-	      (type==ISO_RECEIVE) ? "receive" : "transmit",
+	      (type == OHCI_ISO_RECEIVE) ? "receive" : "transmit",
 	      d->num_desc, d->buf_size, d->frame_size, d->nb_cmd);
 
 	return d;
@@ -563,18 +548,14 @@
 	return NULL;
 }
 
-int wakeup_dma_ir_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d) 
+void wakeup_dma_ir_ctx(unsigned long l)
 {
+	struct dma_iso_ctx *d = (struct dma_iso_ctx *) l;
 	int i;
 
-	if (d==NULL) {
-		PRINT(KERN_ERR, ohci->id, "Iso receive event received but "
-		      "context not allocated");
-		return -EFAULT;
-	}
-
 	spin_lock(&d->lock);
-	for (i=0;i<d->num_desc;i++) {
+
+	for (i = 0; i < d->num_desc; i++) {
 		if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) {
 			reset_ir_status(d, i);
 			d->buffer_status[i] = VIDEO1394_BUFFER_READY;
@@ -585,9 +566,11 @@
 #endif
 		}
 	}
+
 	spin_unlock(&d->lock);
-	if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq);
-	return 0;
+
+	if (waitqueue_active(&d->waitq))
+		wake_up_interruptible(&d->waitq);
 }
 
 static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d,
@@ -642,29 +625,28 @@
 #endif	
 }
 
-int wakeup_dma_it_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d) 
+void wakeup_dma_it_ctx(unsigned long l)
 {
+	struct dma_iso_ctx *d = (struct dma_iso_ctx *) l;
+	struct ti_ohci *ohci = d->ohci;
 	int i;
 
-	if (d==NULL) {
-		PRINT(KERN_ERR, ohci->id, "Iso transmit event received but "
-		      "context not allocated");
-		return -EFAULT;
-	}
-
 	spin_lock(&d->lock);
-	for (i=0;i<d->num_desc;i++) {
-		if (d->it_prg[i][d->last_used_cmd[i]].end.status& 
-			cpu_to_le32(0xFFFF0000)) {
+
+	for (i = 0; i < d->num_desc; i++) {
+		if (d->it_prg[i][d->last_used_cmd[i]].end.status & 
+		    cpu_to_le32(0xFFFF0000)) {
 			int next = d->next_buffer[i];
 			put_timestamp(ohci, d, next);
 			d->it_prg[i][d->last_used_cmd[i]].end.status = 0;
 			d->buffer_status[i] = VIDEO1394_BUFFER_READY;
 		}
 	}
+
 	spin_unlock(&d->lock);
-	if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq);
-	return 0;
+
+	if (waitqueue_active(&d->waitq))
+		wake_up_interruptible(&d->waitq);
 }
 
 static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag)
@@ -871,13 +853,13 @@
 		}
 		ohci->ISO_channel_usage |= mask;
 
-		if (v.buf_size<=0) {
+		if (v.buf_size == 0 || v.buf_size > VIDEO1394_MAX_SIZE) {
 			PRINT(KERN_ERR, ohci->id,
 			      "Invalid %d length buffer requested",v.buf_size);
 			return -EFAULT;
 		}
 
-		if (v.nb_buffers<=0) {
+		if (v.nb_buffers == 0 || v.nb_buffers > VIDEO1394_MAX_SIZE) {
 			PRINT(KERN_ERR, ohci->id,
 			      "Invalid %d buffers requested",v.nb_buffers);
 			return -EFAULT;
@@ -891,7 +873,7 @@
 		}
 
 		if (cmd == VIDEO1394_LISTEN_CHANNEL) {
-			d = alloc_dma_iso_ctx(ohci, ISO_RECEIVE,
+			d = alloc_dma_iso_ctx(ohci, OHCI_ISO_RECEIVE,
 					      v.nb_buffers, v.buf_size, 
 					      v.channel, 0);
 
@@ -912,7 +894,7 @@
 			      d->ctx, v.channel);
 		}
 		else {
-			d = alloc_dma_iso_ctx(ohci, ISO_TRANSMIT,
+			d = alloc_dma_iso_ctx(ohci, OHCI_ISO_TRANSMIT,
 					      v.nb_buffers, v.buf_size, 
 					      v.channel, v.packet_size);
 
@@ -966,9 +948,9 @@
 		ohci->ISO_channel_usage &= ~mask;
 
 		if (cmd == VIDEO1394_UNLISTEN_CHANNEL)
-			d = find_ctx(&ctx->context_list, ISO_RECEIVE, channel);
+			d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, channel);
 		else
-			d = find_ctx(&ctx->context_list, ISO_TRANSMIT, channel);
+			d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, channel);
 
 		if (d == NULL) return -EFAULT;
 		PRINT(KERN_INFO, ohci->id, "Iso context %d "
@@ -985,7 +967,7 @@
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
 
-		d = find_ctx(&ctx->context_list, ISO_RECEIVE, v.channel);
+		d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);
 
 		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
 			PRINT(KERN_ERR, ohci->id, 
@@ -1047,7 +1029,7 @@
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
 
-		d = find_ctx(&ctx->context_list, ISO_RECEIVE, v.channel);
+		d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);
 
 		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
 			PRINT(KERN_ERR, ohci->id, 
@@ -1128,7 +1110,7 @@
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
 
-		d = find_ctx(&ctx->context_list, ISO_TRANSMIT, v.channel);
+		d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel);
 
 		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
 			PRINT(KERN_ERR, ohci->id, 
@@ -1217,7 +1199,7 @@
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
 
-		d = find_ctx(&ctx->context_list, ISO_TRANSMIT, v.channel);
+		d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel);
 
 		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
 			PRINT(KERN_ERR, ohci->id, 
@@ -1340,7 +1322,7 @@
 			ohci->ISO_channel_usage &= ~mask;
 		PRINT(KERN_INFO, ohci->id, "On release: Iso %s context "
 		      "%d stop listening on channel %d",
-		      d->type == ISO_RECEIVE ? "receive" : "transmit",
+		      d->type == OHCI_ISO_RECEIVE ? "receive" : "transmit",
 		      d->ctx, d->channel);
 		free_dma_iso_ctx(d);
 	}
@@ -1352,20 +1334,6 @@
 	return 0;
 }
 
-static void irq_handler(int card, quadlet_t isoRecvIntEvent, 
-			quadlet_t isoXmitIntEvent, void *data)
-{
-	struct dma_iso_ctx *d = (struct dma_iso_ctx *) data;
-
-	DBGMSG(card, "Iso event Recv: %08x Xmit: %08x",
-	       isoRecvIntEvent, isoXmitIntEvent);
-
-	if (d->type == ISO_RECEIVE && isoRecvIntEvent & (1 << d->ctx))
-		wakeup_dma_ir_ctx(d->ohci, d);
-	if (d->type == ISO_TRANSMIT && isoXmitIntEvent & (1 << d->ctx))
-		wakeup_dma_it_ctx(d->ohci, d);
-}
-
 static struct file_operations video1394_fops=
 {
 	.owner =	THIS_MODULE,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/Config.in linux-2.4.20/drivers/isdn/Config.in
--- linux-2.4.19/drivers/isdn/Config.in	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/isdn/Config.in	2002-10-29 11:18:31.000000000 +0000
@@ -46,27 +46,29 @@
    bool '  HiSax Support for US NI1' CONFIG_HISAX_NI1
    int  '  Maximum number of cards supported by HiSax' CONFIG_HISAX_MAX_CARDS 8
    comment '  HiSax supported cards'
-   bool '  Teles 16.0/8.0' CONFIG_HISAX_16_0
-   bool '  Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
+   if [ "$CONFIG_ISA" != "n" ]; then
+      bool '  Teles 16.0/8.0' CONFIG_HISAX_16_0
+      bool '  Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
+      bool '  AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
+      bool '  ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
+      bool '  ASUSCOM ISA cards' CONFIG_HISAX_ASUSCOM
+      bool '  TELEINT cards' CONFIG_HISAX_TELEINT
+      bool '  HFC-S based cards' CONFIG_HISAX_HFCS
+      bool '  USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
+      bool '  MIC card' CONFIG_HISAX_MIC
+      bool '  Siemens I-Surf card' CONFIG_HISAX_ISURF
+      bool '  HST Saphir card' CONFIG_HISAX_HSTSAPHIR
+   fi
    bool '  Teles PCI' CONFIG_HISAX_TELESPCI 
    bool '  Teles S0Box' CONFIG_HISAX_S0BOX 
-   bool '  AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
    bool '  AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
    bool '  AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
    bool '  Elsa cards' CONFIG_HISAX_ELSA
-   bool '  ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
    bool '  Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
-   bool '  ASUSCOM ISA cards' CONFIG_HISAX_ASUSCOM
-   bool '  TELEINT cards' CONFIG_HISAX_TELEINT
-   bool '  HFC-S based cards' CONFIG_HISAX_HFCS
    bool '  Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
-   bool '  USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
-   bool '  MIC card' CONFIG_HISAX_MIC
    bool '  NETjet card' CONFIG_HISAX_NETJET
    bool '  NETspider U card' CONFIG_HISAX_NETJET_U
    bool '  Niccy PnP/PCI card' CONFIG_HISAX_NICCY
-   bool '  Siemens I-Surf card' CONFIG_HISAX_ISURF
-   bool '  HST Saphir card' CONFIG_HISAX_HSTSAPHIR
    bool '  Telekom A4T card' CONFIG_HISAX_BKM_A4T
    bool '  Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
    bool '  Gazel cards' CONFIG_HISAX_GAZEL
@@ -75,6 +77,7 @@
    bool '  HFC-S+, HFC-SP, HFC-PCMCIA cards' CONFIG_HISAX_HFC_SX
    if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
 #      bool '  TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
+      bool '  Formula-n enter:now PCI card' CONFIG_HISAX_ENTERNOW_PCI
       if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
 	 bool '  Am7930' CONFIG_HISAX_AMD7930
       fi
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/avmb1/b1dma.c linux-2.4.20/drivers/isdn/avmb1/b1dma.c
--- linux-2.4.19/drivers/isdn/avmb1/b1dma.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/avmb1/b1dma.c	2002-10-29 11:18:49.000000000 +0000
@@ -28,10 +28,6 @@
 #include "capicmd.h"
 #include "capiutil.h"
 
-#if BITS_PER_LONG != 32
-#error FIXME: driver requires 32-bit platform
-#endif
-
 static char *revision = "$Revision: 1.1.4.1 $";
 
 /* ------------------------------------------------------------- */
@@ -855,7 +851,7 @@
 	__u8 flag;
 	int len = 0;
 	char *s;
-	__u32 txaddr, txlen, rxaddr, rxlen, csr;
+	u_long txaddr, txlen, rxaddr, rxlen, csr;
 
 	len += sprintf(page+len, "%-16s %s\n", "name", card->name);
 	len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
@@ -911,12 +907,12 @@
 	save_flags(flags);
 	cli();
 
-	txaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x2c));
-	txaddr -= (__u32)card->dma->sendbuf;
+	txaddr = (u_long)phys_to_virt(b1dmainmeml(card->mbase+0x2c));
+	txaddr -= (u_long)card->dma->sendbuf;
 	txlen  = b1dmainmeml(card->mbase+0x30);
 
-	rxaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x24));
-	rxaddr -= (__u32)card->dma->recvbuf;
+	rxaddr = (u_long)phys_to_virt(b1dmainmeml(card->mbase+0x24));
+	rxaddr -= (u_long)card->dma->recvbuf;
 	rxlen  = b1dmainmeml(card->mbase+0x28);
 
 	csr  = b1dmainmeml(card->mbase+AMCC_INTCSR);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/avmb1/kcapi.c linux-2.4.20/drivers/isdn/avmb1/kcapi.c
--- linux-2.4.19/drivers/isdn/avmb1/kcapi.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/isdn/avmb1/kcapi.c	2002-10-29 11:18:49.000000000 +0000
@@ -110,7 +110,7 @@
 
 #define VALID_CARD(c)	   ((c) > 0 && (c) <= CAPI_MAXCONTR)
 #define CARD(c)		   (&cards[(c)-1])
-#define CARDNR(cp)	   (((cp)-cards)+1)
+#define CARDNR(cp)	   ((((cp)-cards)+1) & 0xff)
 
 static struct capi_appl applications[CAPI_MAXAPPL];
 static struct capi_ctr cards[CAPI_MAXCONTR];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/Makefile linux-2.4.20/drivers/isdn/hisax/Makefile
--- linux-2.4.19/drivers/isdn/hisax/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/Makefile	2002-10-29 11:18:39.000000000 +0000
@@ -34,7 +34,7 @@
 hisax-objs-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o
 hisax-objs-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o
 hisax-objs-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o
-hisax-objs-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipacx.o
 hisax-objs-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o
 hisax-objs-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o
 hisax-objs-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o isar.o
@@ -52,6 +52,7 @@
 hisax-objs-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o
 hisax-objs-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o
 hisax-objs-$(CONFIG_HISAX_W6692) += w6692.o
+hisax-objs-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o
 #hisax-objs-$(CONFIG_HISAX_TESTEMU) += testemu.o
 
 hisax-objs += $(sort $(hisax-objs-y))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/amd7930_fn.c linux-2.4.20/drivers/isdn/hisax/amd7930_fn.c
--- linux-2.4.19/drivers/isdn/hisax/amd7930_fn.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/amd7930_fn.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,761 @@
+/* gerdes_amd7930.c,v 0.99 2001/10/02
+ *
+ * gerdes_amd7930.c     Amd 79C30A and 79C32A specific routines
+ *                      (based on HiSax driver by Karsten Keil)
+ *
+ * Author               Christoph Ersfeld <info@formula-n.de>
+ *                      Formula-n Europe AG (www.formula-n.com)
+ *                      previously Gerdes AG
+ *
+ *
+ *                      This file is (c) under GNU PUBLIC LICENSE
+ *
+ *
+ * Notes:
+ * Version 0.99 is the first release of this driver and there are
+ * certainly a few bugs.
+ *
+ * Please don't report any malfunction to me without sending
+ * (compressed) debug-logs.
+ * It would be nearly impossible to retrace it.
+ *
+ * Log D-channel-processing as follows:
+ *
+ * 1. Load hisax with card-specific parameters, this example ist for
+ *    Formula-n enter:now ISDN PCI and compatible
+ *    (f.e. Gerdes Power ISDN PCI)
+ *
+ *    modprobe hisax type=41 protocol=2 id=gerdes
+ *
+ *    if you chose an other value for id, you need to modify the
+ *    code below, too.
+ *
+ * 2. set debug-level
+ *
+ *    hisaxctrl gerdes 1 0x3ff
+ *    hisaxctrl gerdes 11 0x4f
+ *    cat /dev/isdnctrl >> ~/log &
+ *
+ * Please take also a look into /var/log/messages if there is
+ * anything importand concerning HISAX.
+ *
+ *
+ * Credits:
+ * Programming the driver for Formula-n enter:now ISDN PCI and
+ * neccessary this driver for the used Amd 7930 D-channel-controller
+ * was spnsored by Formula-n Europe AG.
+ * Thanks to Karsten Keil and Petr Novak, who gave me support in
+ * Hisax-specific questions.
+ * I want so say special thanks to Carl-Friedrich Braun, who had to
+ * answer a lot of questions about generally ISDN and about handling
+ * of the Amd-Chip.
+ *
+ */
+
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl1.h"
+#include "isac.h"
+#include "amd7930_fn.h"
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+static void Amd7930_new_ph(struct IsdnCardState *cs);
+
+
+void /* macro wWordAMD */
+WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val)
+{
+        wByteAMD(cs, 0x00, reg);
+        wByteAMD(cs, 0x01, LOBYTE(val));
+        wByteAMD(cs, 0x01, HIBYTE(val));
+}
+
+WORD /* macro rWordAMD */
+ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg)
+{
+        WORD res;
+        /* direct access register */
+        if(reg < 8) {
+        	res = rByteAMD(cs, reg);
+                res += 256*rByteAMD(cs, reg);
+        }
+        /* indirect access register */
+        else {
+                wByteAMD(cs, 0x00, reg);
+	        res = rByteAMD(cs, 0x01);
+                res += 256*rByteAMD(cs, 0x01);
+        }
+	return (res);
+}
+
+
+static void
+Amd7930_ph_command(struct IsdnCardState *cs, u_char command, char *s)
+{
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "AMD7930: %s: ph_command 0x%02X", s, command);
+
+        cs->dc.amd7930.lmr1 = command;
+        wByteAMD(cs, 0xA3, command);
+}
+
+
+
+static BYTE i430States[] = {
+// to   reset  F3    F4    F5    F6    F7    F8    AR     from
+        0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00,   // init
+        0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00,   // reset
+        0x01, 0x02, 0x00, 0x00, 0x00, 0x09, 0x05, 0x04,   // F3
+        0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,   // F4
+        0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,   // F5
+        0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x05, 0x00,   // F6
+        0x11, 0x13, 0x00, 0x00, 0x1B, 0x00, 0x15, 0x00,   // F7
+        0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,   // F8
+        0x01, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0A};  // AR
+
+
+/*                    Row     init    -   reset  F3    F4    F5    F6    F7    F8    AR */
+static BYTE stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
+
+
+
+
+static void
+Amd7930_get_state(struct IsdnCardState *cs) {
+        BYTE lsr = rByteAMD(cs, 0xA1);
+        cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
+        Amd7930_new_ph(cs);
+}
+
+
+
+static void
+Amd7930_new_ph(struct IsdnCardState *cs)
+{
+        u_char index = stateHelper[cs->dc.amd7930.old_state]*8 + stateHelper[cs->dc.amd7930.ph_state]-1;
+        u_char message = i430States[index];
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "AMD7930: new_ph %d, old_ph %d, message %d, index %d",
+                        cs->dc.amd7930.ph_state, cs->dc.amd7930.old_state, message & 0x0f, index);
+
+        cs->dc.amd7930.old_state = cs->dc.amd7930.ph_state;
+
+        /* abort transmit if nessesary */
+        if ((message & 0xf0) && (cs->tx_skb)) {
+                wByteAMD(cs, 0x21, 0xC2);
+                wByteAMD(cs, 0x21, 0x02);
+        }
+
+	switch (message & 0x0f) {
+
+                case (1):
+                        l1_msg(cs, HW_RESET | INDICATION, NULL);
+                        Amd7930_get_state(cs);
+                        break;
+                case (2): /* init, Card starts in F3 */
+                        l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
+                        break;
+                case (3):
+                        l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
+                        break;
+                case (4):
+                        l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+                        Amd7930_ph_command(cs, 0x50, "HW_ENABLE REQUEST");
+                        break;
+                case (5):
+			l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+                        break;
+                case (6):
+			l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+                        break;
+                case (7): /* init, Card starts in F7 */
+			l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+			l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+                        break;
+                case (8):
+                        l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+                        /* fall through */
+                case (9):
+                        Amd7930_ph_command(cs, 0x40, "HW_ENABLE REQ cleared if set");
+			l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+			l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+			l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+                        break;
+                case (10):
+                        Amd7930_ph_command(cs, 0x40, "T3 expired, HW_ENABLE REQ cleared");
+                        cs->dc.amd7930.old_state = 3;
+                        break;
+                case (11):
+			l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+                        break;
+		default:
+			break;
+	}
+}
+
+
+
+static void
+Amd7930_bh(struct IsdnCardState *cs)
+{
+
+        struct PStack *stptr;
+
+	if (!cs)
+		return;
+	if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
+                if (cs->debug)
+			debugl1(cs, "Amd7930: bh, D-Channel Busy cleared");
+		stptr = cs->stlist;
+		while (stptr != NULL) {
+			stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
+			stptr = stptr->next;
+		}
+	}
+	if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+	        if (cs->debug & L1_DEB_ISAC)
+		        debugl1(cs, "AMD7930: bh, D_L1STATECHANGE");
+                Amd7930_new_ph(cs);
+        }
+
+        if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) {
+	        if (cs->debug & L1_DEB_ISAC)
+		        debugl1(cs, "AMD7930: bh, D_RCVBUFREADY");
+                DChannel_proc_rcv(cs);
+        }
+
+        if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) {
+	        if (cs->debug & L1_DEB_ISAC)
+		        debugl1(cs, "AMD7930: bh, D_XMTBUFREADY");
+                DChannel_proc_xmt(cs);
+        }
+}
+
+
+void
+Amd7930_sched_event(struct IsdnCardState *cs, int event) // ok
+{
+
+	if (cs->debug & L1_DEB_ISAC) {
+		debugl1(cs, "AMD7930: sched_event 0x%X", event);
+        }
+
+        test_and_set_bit(event, &cs->event);
+	queue_task(&cs->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+static void
+Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag)
+{
+
+        BYTE stat, der;
+	BYTE *ptr;
+	struct sk_buff *skb;
+
+
+	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+		debugl1(cs, "Amd7930: empty_Dfifo");
+
+
+	ptr = cs->rcvbuf + cs->rcvidx;
+
+	/* AMD interrupts off */
+	AmdIrqOff(cs);
+
+	/* read D-Channel-Fifo*/
+	stat = rByteAMD(cs, 0x07); // DSR2
+
+		/* while Data in Fifo ... */
+		while ( (stat & 2) && ((ptr-cs->rcvbuf) < MAX_DFRAME_LEN_L1) ) {
+			*ptr = rByteAMD(cs, 0x04); // DCRB
+			ptr++;
+	                stat = rByteAMD(cs, 0x07); // DSR2
+			cs->rcvidx = ptr - cs->rcvbuf;
+
+                        /* Paket ready? */
+			if (stat & 1) {
+
+                                der = rWordAMD(cs, 0x03);
+
+                                /* no errors, packet ok */
+                                if(!der && !flag) {
+					rWordAMD(cs, 0x89); // clear DRCR
+
+                                        if ((cs->rcvidx) > 0) {
+                                                if (!(skb = alloc_skb(cs->rcvidx, GFP_ATOMIC)))
+							printk(KERN_WARNING "HiSax: Amd7930: empty_Dfifo, D receive out of memory!\n");
+						else {
+                                                        /* Debugging */
+                                                        if (cs->debug & L1_DEB_ISAC_FIFO) {
+								char *t = cs->dlog;
+
+								t += sprintf(t, "Amd7930: empty_Dfifo cnt: %d |", cs->rcvidx);
+								QuickHex(t, cs->rcvbuf, cs->rcvidx);
+								debugl1(cs, cs->dlog);
+							}
+                                                        /* moves recieved data in sk-buffer */
+							memcpy(skb_put(skb, cs->rcvidx), cs->rcvbuf, cs->rcvidx);
+							skb_queue_tail(&cs->rq, skb);
+						}
+					}
+
+				}
+                                /* throw damaged packets away, reset recieve-buffer, indicate RX */
+				ptr = cs->rcvbuf;
+				cs->rcvidx = 0;
+				Amd7930_sched_event(cs, D_RCVBUFREADY);
+			}
+                }
+		/* Packet to long, overflow */
+		if(cs->rcvidx >= MAX_DFRAME_LEN_L1) {
+			if (cs->debug & L1_DEB_WARN)
+			        debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun");
+			cs->rcvidx = 0;
+			return;
+		}
+	/* AMD interrupts on */
+	AmdIrqOn(cs);
+}
+
+
+static void
+Amd7930_fill_Dfifo(struct IsdnCardState *cs)
+{
+
+        WORD dtcrr, dtcrw, len, count;
+        BYTE txstat, dmr3;
+        BYTE *ptr, *deb_ptr;
+
+	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+		debugl1(cs, "Amd7930: fill_Dfifo");
+
+	if ((!cs->tx_skb) || (cs->tx_skb->len <= 0))
+		return;
+
+        dtcrw = 0;
+        if(!cs->dc.amd7930.tx_xmtlen)
+                /* new Frame */
+                len = dtcrw = cs->tx_skb->len;
+        /* continue frame */
+        else len = cs->dc.amd7930.tx_xmtlen;
+
+
+	/* AMD interrupts off */
+	AmdIrqOff(cs);
+
+        deb_ptr = ptr = cs->tx_skb->data;
+
+        /* while free place in tx-fifo available and data in sk-buffer */
+        txstat = 0x10;
+        while((txstat & 0x10) && (cs->tx_cnt < len)) {
+                wByteAMD(cs, 0x04, *ptr);
+                ptr++;
+                cs->tx_cnt++;
+                txstat= rByteAMD(cs, 0x07);
+        }
+        count = ptr - cs->tx_skb->data;
+	skb_pull(cs->tx_skb, count);
+
+
+        dtcrr = rWordAMD(cs, 0x85); // DTCR
+        dmr3  = rByteAMD(cs, 0x8E);
+
+	if (cs->debug & L1_DEB_ISAC) {
+		debugl1(cs, "Amd7930: fill_Dfifo, DMR3: 0x%02X, DTCR read: 0x%04X write: 0x%02X 0x%02X", dmr3, dtcrr, LOBYTE(dtcrw), HIBYTE(dtcrw));
+        }
+
+        /* writeing of dtcrw starts transmit */
+        if(!cs->dc.amd7930.tx_xmtlen) {
+                wWordAMD(cs, 0x85, dtcrw);
+                cs->dc.amd7930.tx_xmtlen = dtcrw;
+        }
+
+	if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+		debugl1(cs, "Amd7930: fill_Dfifo dbusytimer running");
+		del_timer(&cs->dbusytimer);
+	}
+	init_timer(&cs->dbusytimer);
+	cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);
+	add_timer(&cs->dbusytimer);
+
+	if (cs->debug & L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "Amd7930: fill_Dfifo cnt: %d |", count);
+		QuickHex(t, deb_ptr, count);
+		debugl1(cs, cs->dlog);
+	}
+	/* AMD interrupts on */
+        AmdIrqOn(cs);
+}
+
+
+void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags)
+{
+	BYTE dsr1, dsr2, lsr;
+        WORD der;
+
+ while (irflags)
+ {
+
+        dsr1 = rByteAMD(cs, 0x02);
+        der  = rWordAMD(cs, 0x03);
+        dsr2 = rByteAMD(cs, 0x07);
+        lsr  = rByteAMD(cs, 0xA1);
+
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: interrupt: flags: 0x%02X, DSR1: 0x%02X, DSR2: 0x%02X, LSR: 0x%02X, DER=0x%04X", irflags, dsr1, dsr2, lsr, der);
+
+        /* D error -> read DER and DSR2 bit 2 */
+	if (der || (dsr2 & 4)) {
+
+                if (cs->debug & L1_DEB_WARN)
+			debugl1(cs, "Amd7930: interrupt: D error DER=0x%04X", der);
+
+                /* RX, TX abort if collision detected */
+                if (der & 2) {
+                        wByteAMD(cs, 0x21, 0xC2);
+                        wByteAMD(cs, 0x21, 0x02);
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+				Amd7930_sched_event(cs, D_CLEARBUSY);
+                        /* restart frame */
+                        if (cs->tx_skb) {
+				skb_push(cs->tx_skb, cs->tx_cnt);
+				cs->tx_cnt = 0;
+                                cs->dc.amd7930.tx_xmtlen = 0;
+				Amd7930_fill_Dfifo(cs);
+			} else {
+				printk(KERN_WARNING "HiSax: Amd7930 D-Collision, no skb\n");
+				debugl1(cs, "Amd7930: interrupt: D-Collision, no skb");
+			}
+                }
+                /* remove damaged data from fifo */
+		Amd7930_empty_Dfifo(cs, 1);
+
+		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			Amd7930_sched_event(cs, D_CLEARBUSY);
+                /* restart TX-Frame */
+                if (cs->tx_skb) {
+			skb_push(cs->tx_skb, cs->tx_cnt);
+			cs->tx_cnt = 0;
+                        cs->dc.amd7930.tx_xmtlen = 0;
+			Amd7930_fill_Dfifo(cs);
+		}
+	}
+
+        /* D TX FIFO empty -> fill */
+	if (irflags & 1) {
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "Amd7930: interrupt: clear Timer and fill D-TX-FIFO if data");
+
+		/* AMD interrupts off */
+                AmdIrqOff(cs);
+
+                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			Amd7930_sched_event(cs, D_CLEARBUSY);
+		if (cs->tx_skb) {
+			if (cs->tx_skb->len)
+				Amd7930_fill_Dfifo(cs);
+		}
+		/* AMD interrupts on */
+                AmdIrqOn(cs);
+	}
+
+
+        /* D RX FIFO full or tiny packet in Fifo -> empty */
+	if ((irflags & 2) || (dsr1 & 2)) {
+                if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "Amd7930: interrupt: empty D-FIFO");
+                Amd7930_empty_Dfifo(cs, 0);
+	}
+
+
+        /* D-Frame transmit complete */
+	if (dsr1 & 64) {
+		if (cs->debug & L1_DEB_ISAC) {
+			debugl1(cs, "Amd7930: interrupt: transmit packet ready");
+        	}
+		/* AMD interrupts off */
+                AmdIrqOff(cs);
+
+                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			Amd7930_sched_event(cs, D_CLEARBUSY);
+
+                if (cs->tx_skb) {
+        		if (cs->debug & L1_DEB_ISAC)
+	        		debugl1(cs, "Amd7930: interrupt: TX-Packet ready, freeing skb");
+                        dev_kfree_skb_irq(cs->tx_skb);
+			cs->tx_cnt = 0;
+                        cs->dc.amd7930.tx_xmtlen=0;
+			cs->tx_skb = NULL;
+                }
+                if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+        		if (cs->debug & L1_DEB_ISAC)
+	        		debugl1(cs, "Amd7930: interrupt: TX-Packet ready, next packet dequeued");
+	        	cs->tx_cnt = 0;
+                        cs->dc.amd7930.tx_xmtlen=0;
+			Amd7930_fill_Dfifo(cs);
+		}
+                else
+			Amd7930_sched_event(cs, D_XMTBUFREADY);
+		/* AMD interrupts on */
+                AmdIrqOn(cs);
+        }
+
+	/* LIU status interrupt -> read LSR, check statechanges */
+	if (lsr & 0x38) {
+                /* AMD interrupts off */
+                AmdIrqOff(cs);
+
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "Amd: interrupt: LSR=0x%02X, LIU is in state %d", lsr, ((lsr & 0x7) +2));
+
+		cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
+
+		Amd7930_sched_event(cs, D_L1STATECHANGE);
+		/* AMD interrupts on */
+                AmdIrqOn(cs);
+	}
+
+        /* reads Interrupt-Register again. If there is a new interrupt-flag: restart handler */
+        irflags = rByteAMD(cs, 0x00);
+ }
+
+}
+
+static void
+Amd7930_l1hw(struct PStack *st, int pr, void *arg)
+{
+        struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+	struct sk_buff *skb = arg;
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr);
+
+	switch (pr) {
+		case (PH_DATA | REQUEST):
+                        if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			if (cs->tx_skb) {
+				skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA Queued", 0);
+#endif
+			} else {
+				cs->tx_skb = skb;
+				cs->tx_cnt = 0;
+                                cs->dc.amd7930.tx_xmtlen=0;
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA", 0);
+#endif
+				Amd7930_fill_Dfifo(cs);
+			}
+			break;
+		case (PH_PULL | INDICATION):
+			if (cs->tx_skb) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen");
+				skb_queue_tail(&cs->sq, skb);
+				break;
+			}
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			cs->tx_skb = skb;
+			cs->tx_cnt = 0;
+                        cs->dc.amd7930.tx_xmtlen=0;
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA_PULLED", 0);
+#endif
+			Amd7930_fill_Dfifo(cs);
+			break;
+		case (PH_PULL | REQUEST):
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				debugl1(cs, "Amd7930: l1hw: -> PH_REQUEST_PULL, skb: %s", (cs->tx_skb)? "yes":"no");
+#endif
+			if (!cs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+			break;
+		case (HW_RESET | REQUEST):
+
+                        if ((cs->dc.amd7930.ph_state == 8))
+                                /* b-channels off, PH-AR cleared
+                                 * change to F3 */
+                                Amd7930_ph_command(cs, 0x20, "HW_RESET REQEST"); //LMR1 bit 5
+			else {
+                                Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST");
+                                cs->dc.amd7930.ph_state = 2;
+                                Amd7930_new_ph(cs);
+                        }
+			break;
+		case (HW_ENABLE | REQUEST):
+                        cs->dc.amd7930.ph_state = 9;
+                        Amd7930_new_ph(cs);
+			break;
+		case (HW_INFO3 | REQUEST):
+			// automatic
+			break;
+		case (HW_TESTLOOP | REQUEST):
+			/* not implemented yet */
+			break;
+		case (HW_DEACTIVATE | RESPONSE):
+                        skb_queue_purge(&cs->rq);
+			skb_queue_purge(&cs->sq);
+			if (cs->tx_skb) {
+				dev_kfree_skb(cs->tx_skb);
+				cs->tx_skb = NULL;
+			}
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+				Amd7930_sched_event(cs, D_CLEARBUSY);
+			break;
+		default:
+			if (cs->debug & L1_DEB_WARN)
+				debugl1(cs, "Amd7930: l1hw: unknown %04x", pr);
+			break;
+	}
+}
+
+void
+setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs)
+{
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: setstack called");
+
+        st->l1.l1hw = Amd7930_l1hw;
+}
+
+
+void
+DC_Close_Amd7930(struct IsdnCardState *cs) {
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: DC_Close called");
+}
+
+
+static void
+dbusy_timer_handler(struct IsdnCardState *cs)
+{
+	struct PStack *stptr;
+        WORD dtcr, der;
+        BYTE dsr1, dsr2;
+
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: dbusy_timer expired!");
+
+	if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+                /* D Transmit Byte Count Register:
+                 * Counts down packet's number of Bytes, 0 if packet ready */
+                dtcr = rWordAMD(cs, 0x85);
+                dsr1 = rByteAMD(cs, 0x02);
+                dsr2 = rByteAMD(cs, 0x07);
+                der  = rWordAMD(cs, 0x03);
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: dbusy_timer_handler: DSR1=0x%02X, DSR2=0x%02X, DER=0x%04X, cs->tx_skb->len=%u, tx_stat=%u, dtcr=%u, cs->tx_cnt=%u", dsr1, dsr2, der, cs->tx_skb->len, cs->dc.amd7930.tx_xmtlen, dtcr, cs->tx_cnt);
+
+		if ((cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) {	/* D-Channel Busy */
+			test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
+			stptr = cs->stlist;
+			while (stptr != NULL) {
+				stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
+				stptr = stptr->next;
+			}
+
+		} else {
+			/* discard frame; reset transceiver */
+			test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
+			if (cs->tx_skb) {
+				dev_kfree_skb_any(cs->tx_skb);
+				cs->tx_cnt = 0;
+				cs->tx_skb = NULL;
+                                cs->dc.amd7930.tx_xmtlen = 0;
+			} else {
+				printk(KERN_WARNING "HiSax: Amd7930: D-Channel Busy no skb\n");
+				debugl1(cs, "Amd7930: D-Channel Busy no skb");
+
+			}
+			/* Transmitter reset, abort transmit */
+			wByteAMD(cs, 0x21, 0x82);
+			wByteAMD(cs, 0x21, 0x02);
+			cs->irq_func(cs->irq, cs, NULL);
+
+                        if (cs->debug & L1_DEB_ISAC)
+				debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset");
+		}
+	}
+}
+
+
+
+void __devinit
+Amd7930_init(struct IsdnCardState *cs)
+{
+    WORD *ptr;
+    BYTE cmd, cnt;
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: initamd called");
+
+        cs->dc.amd7930.tx_xmtlen = 0;
+        cs->dc.amd7930.old_state = 0;
+        cs->dc.amd7930.lmr1 = 0x40;
+        cs->dc.amd7930.ph_command = Amd7930_ph_command;
+        cs->tqueue.routine = (void *) (void *) Amd7930_bh;
+	cs->setstack_d = setstack_Amd7930;
+	cs->DC_Close = DC_Close_Amd7930;
+	cs->dbusytimer.function = (void *) dbusy_timer_handler;
+	cs->dbusytimer.data = (long) cs;
+	init_timer(&cs->dbusytimer);
+
+	/* AMD Initialisation */
+	for (ptr = initAMD; *ptr != 0xFFFF; ) {
+		cmd = LOBYTE(*ptr);
+
+                /* read */
+                if (*ptr++ >= 0x100) {
+			if (cmd < 8)
+                                /* setzt Register zurck */
+                                rByteAMD(cs, cmd);
+			else {
+				wByteAMD(cs, 0x00, cmd);
+				for (cnt = *ptr++; cnt > 0; cnt--)
+					rByteAMD(cs, 0x01);
+			}
+		}
+                /* write */
+                else if (cmd < 8)
+			wByteAMD(cs, cmd, LOBYTE(*ptr++));
+
+		else {
+			wByteAMD(cs, 0x00, cmd);
+			for (cnt = *ptr++; cnt > 0; cnt--)
+				wByteAMD(cs, 0x01, LOBYTE(*ptr++));
+		}
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/amd7930_fn.h linux-2.4.20/drivers/isdn/hisax/amd7930_fn.h
--- linux-2.4.19/drivers/isdn/hisax/amd7930_fn.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/amd7930_fn.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,69 @@
+/* 2001/10/02
+ *
+ * gerdes_amd7930.h     Header-file included by
+ *                      gerdes_amd7930.c
+ *
+ * Author               Christoph Ersfeld <info@formula-n.de>
+ *                      Formula-n Europe AG (www.formula-n.com)
+ *                      previously Gerdes AG
+ *
+ *
+ *                      This file is (c) under GNU PUBLIC LICENSE
+ */
+
+
+
+
+#define BYTE							unsigned char
+#define WORD							unsigned int
+#define rByteAMD(cs, reg)					cs->readisac(cs, reg)
+#define wByteAMD(cs, reg, val)					cs->writeisac(cs, reg, val)
+#define rWordAMD(cs, reg)					ReadWordAmd7930(cs, reg)
+#define wWordAMD(cs, reg, val)					WriteWordAmd7930(cs, reg, val)
+#define HIBYTE(w)						((unsigned char)((w & 0xff00) / 256))
+#define LOBYTE(w)						((unsigned char)(w & 0x00ff))
+
+#define AmdIrqOff(cs)						cs->dc.amd7930.setIrqMask(cs, 0)
+#define AmdIrqOn(cs)						cs->dc.amd7930.setIrqMask(cs, 1)
+
+#define AMD_CR		0x00
+#define AMD_DR		0x01
+
+
+#define DBUSY_TIMER_VALUE 80
+
+static WORD initAMD[] = {
+	0x0100,
+
+	0x00A5, 3, 0x01, 0x40, 0x58,				// LPR, LMR1, LMR2
+	0x0086, 1, 0x0B,					// DMR1 (D-Buffer TH-Interrupts on)
+	0x0087, 1, 0xFF,					// DMR2
+	0x0092, 1, 0x03,					// EFCR (extended mode d-channel-fifo on)
+	0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F,			// FRAR4, SRAR4, DMR3, DMR4 (address recognition )
+	0x0084, 2, 0x80, 0x00,					// DRLR
+	0x00C0, 1, 0x47,					// PPCR1
+	0x00C8, 1, 0x01,					// PPCR2
+
+	0x0102,
+	0x0107,
+	0x01A1, 1,
+	0x0121, 1,
+	0x0189, 2,
+
+	0x0045, 4, 0x61, 0x72, 0x00, 0x00,			// MCR1, MCR2, MCR3, MCR4
+	0x0063, 2, 0x08, 0x08,					// GX
+	0x0064, 2, 0x08, 0x08,					// GR
+	0x0065, 2, 0x99, 0x00,					// GER
+	0x0066, 2, 0x7C, 0x8B,					// STG
+	0x0067, 2, 0x00, 0x00,					// FTGR1, FTGR2
+	0x0068, 2, 0x20, 0x20,					// ATGR1, ATGR2
+	0x0069, 1, 0x4F,					// MMR1
+	0x006A, 1, 0x00,					// MMR2
+	0x006C, 1, 0x40,					// MMR3
+	0x0021, 1, 0x02,					// INIT
+	0x00A3, 1, 0x40,					// LMR1
+
+	0xFFFF};
+
+extern void Amd7930_interrupt(struct IsdnCardState *cs, unsigned char irflags);
+extern void Amd7930_init(struct IsdnCardState *cs);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/asuscom.c linux-2.4.20/drivers/isdn/hisax/asuscom.c
--- linux-2.4.19/drivers/isdn/hisax/asuscom.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/asuscom.c	2002-10-29 11:18:40.000000000 +0000
@@ -14,6 +14,7 @@
 
 #define __NO_VERSION__
 #include <linux/init.h>
+#include <linux/isapnp.h>
 #include "hisax.h"
 #include "isac.h"
 #include "ipac.h"
@@ -309,6 +310,27 @@
 	return(0);
 }
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id asus_ids[] __initdata = {
+	{ ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
+	  ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688), 
+	  (unsigned long) "Asus1688 PnP" },
+	{ ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
+	  ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690), 
+	  (unsigned long) "Asus1690 PnP" },
+	{ ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
+	  ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020), 
+	  (unsigned long) "Isurf2 PnP" },
+	{ ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
+	  ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000), 
+	  (unsigned long) "Iscas TE320" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *adev = &asus_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 int __init
 setup_asuscom(struct IsdnCard *card)
 {
@@ -321,7 +343,45 @@
 	printk(KERN_INFO "HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp));
 	if (cs->typ != ISDN_CTYPE_ASUSCOM)
 		return (0);
-
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		while(adev->card_vendor) {
+			if ((pb = isapnp_find_card(adev->card_vendor,
+				adev->card_device, pnp_c))) {
+				pnp_c = pb;
+				pd = NULL;
+				if ((pd = isapnp_find_dev(pnp_c,
+					adev->vendor, adev->function, pd))) {
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)adev->driver_data);
+					pd->prepare(pd);
+					pd->deactivate(pd);
+					pd->activate(pd);
+					card->para[1] = pd->resource[0].start;
+					card->para[0] = pd->irq_resource[0].start;
+					if (!card->para[0] || !card->para[1]) {
+						printk(KERN_ERR "AsusPnP:some resources are missing %ld/%lx\n",
+						card->para[0], card->para[1]);
+						pd->deactivate(pd);
+						return(0);
+					}
+					break;
+				} else {
+					printk(KERN_ERR "AsusPnP: PnP error card found, no device\n");
+				}
+			}
+			adev++;
+			pnp_c=NULL;
+		} 
+		if (!adev->card_vendor) {
+			printk(KERN_INFO "AsusPnP: no ISAPnP card found\n");
+			return(0);
+		}
+	}
+#endif
 	bytecnt = 8;
 	cs->hw.asus.cfg_reg = card->para[1];
 	cs->irq = card->para[0];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/avm_pci.c linux-2.4.20/drivers/isdn/hisax/avm_pci.c
--- linux-2.4.19/drivers/isdn/hisax/avm_pci.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/avm_pci.c	2002-10-29 11:18:36.000000000 +0000
@@ -19,6 +19,7 @@
 #include "isac.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isapnp.h>
 #include <linux/interrupt.h>
 
 extern const char *CardType[];
@@ -763,6 +764,10 @@
 }
 
 static struct pci_dev *dev_avm __initdata = NULL;
+#ifdef __ISAPNP__
+static struct pci_bus *bus_avm __initdata = NULL;
+static struct pci_dev *pnp_avm __initdata = NULL;
+#endif
 
 int __init
 setup_avm_pcipnp(struct IsdnCard *card)
@@ -776,10 +781,47 @@
 	if (cs->typ != ISDN_CTYPE_FRITZPCI)
 		return (0);
 	if (card->para[1]) {
+		/* old manual method */
 		cs->hw.avm.cfg_reg = card->para[1];
 		cs->irq = card->para[0];
 		cs->subtyp = AVM_FRITZ_PNP;
 	} else {
+#ifdef __ISAPNP__
+		if (isapnp_present()) {
+			struct pci_bus *ba;
+			if ((ba = isapnp_find_card(
+				ISAPNP_VENDOR('A', 'V', 'M'),
+				ISAPNP_FUNCTION(0x0900), bus_avm))) {
+				bus_avm = ba;
+				pnp_avm = NULL;
+				if ((pnp_avm = isapnp_find_dev(bus_avm,
+					ISAPNP_VENDOR('A', 'V', 'M'),
+					ISAPNP_FUNCTION(0x0900), pnp_avm))) {
+					pnp_avm->prepare(pnp_avm);
+					pnp_avm->deactivate(pnp_avm);
+					pnp_avm->activate(pnp_avm);
+					cs->hw.avm.cfg_reg =
+						pnp_avm->resource[0].start;
+					cs->irq = 
+						pnp_avm->irq_resource[0].start;
+					if (!cs->irq) {
+						printk(KERN_ERR "FritzPnP:No IRQ\n");
+						pnp_avm->deactivate(pnp_avm);
+						return(0);
+					}
+					if (!cs->hw.avm.cfg_reg) {
+						printk(KERN_ERR "FritzPnP:No IO address\n");
+						pnp_avm->deactivate(pnp_avm);
+						return(0);
+					}
+					cs->subtyp = AVM_FRITZ_PNP;
+					goto ready;
+				}
+			}
+		} else {
+			printk(KERN_INFO "FritzPnP: no ISA PnP present\n");
+		}
+#endif
 #if CONFIG_PCI
 		if (!pci_present()) {
 			printk(KERN_ERR "FritzPCI: no PCI bus present\n");
@@ -810,6 +852,7 @@
 		return (0);
 #endif /* CONFIG_PCI */
 	}
+ready:
 	cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
 	if (check_region((cs->hw.avm.cfg_reg), 32)) {
 		printk(KERN_WARNING
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/config.c linux-2.4.20/drivers/isdn/hisax/config.c
--- linux-2.4.19/drivers/isdn/hisax/config.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/config.c	2002-10-29 11:18:49.000000000 +0000
@@ -75,6 +75,8 @@
  *   37 HFC 2BDS0 S+/SP         p0=irq p1=iobase
  *   38 Travers Technologies NETspider-U PCI card
  *   39 HFC 2BDS0-SP PCMCIA     p0=irq p1=iobase
+ *   40 hotplug interface
+ *   41 Formula-n enter:now ISDN PCI a/b   none
  *
  * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
  *
@@ -93,6 +95,7 @@
 	"Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T",
 	"Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
 	"HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA",
+	"Hotplug", "Formula-n enter:now PCI a/b", 
 };
 
 void HiSax_closecard(int cardnr);
@@ -601,6 +604,10 @@
 extern int setup_netjet_u(struct IsdnCard *card);
 #endif
 
+#if CARD_FN_ENTERNOW_PCI
+extern int setup_enternow_pci(struct IsdnCard *card);
+#endif
+
 /*
  * Find card with given driverId
  */
@@ -1136,6 +1143,11 @@
 		ret = setup_netjet_u(card);
 		break;
 #endif
+#if CARD_FN_ENTERNOW_PCI
+	case ISDN_CTYPE_ENTERNOW:
+		ret = setup_enternow_pci(card);
+		break;
+#endif
 	case ISDN_CTYPE_DYNAMIC:
 		ret = 2;
 		break;
@@ -1249,9 +1261,12 @@
 			foundcards++;
 			i++;
 		} else {
-			printk(KERN_WARNING
-			       "HiSax: Card %s not installed !\n",
-			       CardType[cards[i].typ]);
+			/* make sure we don't oops the module */
+			if (cards[i].typ > 0 && cards[i].typ <= ISDN_CTYPE_COUNT) {
+				printk(KERN_WARNING
+			       		"HiSax: Card %s not installed !\n",
+			       		CardType[cards[i].typ]);
+			}
 			HiSax_shiftcards(i);
 			nrcards--;
 		}
@@ -1511,7 +1526,8 @@
 	       nrcards, (nrcards > 1) ? "s" : "");
 
 	/* Install only, if at least one card found */
-	HiSax_inithardware(NULL);
+	if (!HiSax_inithardware(NULL))
+		return -ENODEV;
 	return 0;
 
  out_tei:
@@ -1579,7 +1595,8 @@
 	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
 	       nrcards, (nrcards > 1) ? "s" : "");
 
-	HiSax_inithardware(busy_flag);
+	if (!HiSax_inithardware(busy_flag))
+		return -ENODEV;
 	printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
 	return 0;
@@ -1621,7 +1638,8 @@
 	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
 	       nrcards, (nrcards > 1) ? "s" : "");
 
-	HiSax_inithardware(busy_flag);
+	if (!HiSax_inithardware(busy_flag))
+		return -ENODEV;
 	printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
 	return 0;
@@ -1663,7 +1681,8 @@
 	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
 	       nrcards, (nrcards > 1) ? "s" : "");
 
-	HiSax_inithardware(busy_flag);
+	if (!HiSax_inithardware(busy_flag))
+		return -ENODEV;
 	printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
 	return 0;
@@ -1705,7 +1724,8 @@
 	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
 	       nrcards, (nrcards > 1) ? "s" : "");
 
-	HiSax_inithardware(busy_flag);
+	if (!HiSax_inithardware(busy_flag))
+		return -ENODEV;
 	printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
 	return 0;
@@ -2092,6 +2112,9 @@
 	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA20,     PCI_ANY_ID, PCI_ANY_ID},
 	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA20_U,   PCI_ANY_ID, PCI_ANY_ID},
 	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA201,    PCI_ANY_ID, PCI_ANY_ID},
+//#########################################################################################	
+	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA202,    PCI_ANY_ID, PCI_ANY_ID},
+//#########################################################################################	
 #endif
 #ifdef CONFIG_HISAX_ELSA
 	{PCI_VENDOR_ID_ELSA,     PCI_DEVICE_ID_ELSA_MICROLINK,   PCI_ANY_ID, PCI_ANY_ID},
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/diva.c linux-2.4.20/drivers/isdn/hisax/diva.c
--- linux-2.4.19/drivers/isdn/hisax/diva.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/diva.c	2002-10-29 11:18:38.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: diva.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
+/* $Id: diva.c,v 1.1.4.2 2002/08/30 11:21:00 keil Exp $
  *
  * low level stuff for Eicon.Diehl Diva Family ISDN cards
  *
@@ -22,12 +22,14 @@
 #include "isac.h"
 #include "hscx.h"
 #include "ipac.h"
+#include "ipacx.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isapnp.h>
 
 extern const char *CardType[];
 
-const char *Diva_revision = "$Revision: 1.1.4.1 $";
+const char *Diva_revision = "$Revision: 1.1.4.2 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -49,6 +51,7 @@
 #define DIVA_PCI	2
 #define DIVA_IPAC_ISA	3
 #define DIVA_IPAC_PCI	4
+#define DIVA_IPACX_PCI	5
 
 /* CTRL (Read) */
 #define DIVA_IRQ_STAT	0x01
@@ -68,10 +71,12 @@
 #define PITA_MISC_REG		0x1c
 #ifdef __BIG_ENDIAN
 #define PITA_PARA_SOFTRESET	0x00000001
+#define PITA_SER_SOFTRESET	0x00000002
 #define PITA_PARA_MPX_MODE	0x00000004
 #define PITA_INT0_ENABLE	0x00000200
 #else
 #define PITA_PARA_SOFTRESET	0x01000000
+#define PITA_SER_SOFTRESET	0x02000000
 #define PITA_PARA_MPX_MODE	0x04000000
 #define PITA_INT0_ENABLE	0x00020000
 #endif
@@ -239,6 +244,47 @@
 	memwritereg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0), value);
 }
 
+/* IO-Functions for IPACX type cards */
+static u_char
+MemReadISAC_IPACX(struct IsdnCardState *cs, u_char offset)
+{
+	return (memreadreg(cs->hw.diva.cfg_reg, offset));
+}
+
+static void
+MemWriteISAC_IPACX(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+	memwritereg(cs->hw.diva.cfg_reg, offset, value);
+}
+
+static void
+MemReadISACfifo_IPACX(struct IsdnCardState *cs, u_char * data, int size)
+{
+	while(size--)
+		*data++ = memreadreg(cs->hw.diva.cfg_reg, 0);
+}
+
+static void
+MemWriteISACfifo_IPACX(struct IsdnCardState *cs, u_char * data, int size)
+{
+	while(size--)
+		memwritereg(cs->hw.diva.cfg_reg, 0, *data++);
+}
+
+static u_char
+MemReadHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+	return(memreadreg(cs->hw.diva.cfg_reg, offset + 
+                    (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1)));
+}
+
+static void
+MemWriteHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+	memwritereg(cs->hw.diva.cfg_reg, offset + 
+              (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1), value);
+}
+
 /*
  * fast interrupt HSCX stuff goes here
  */
@@ -549,7 +595,7 @@
 	u_char exval;
 	struct BCState *bcs;
 
-	if (val & 0x01) {
+	if (val & 0x01) { // EXB
 		bcs = cs->bcs + 1;
 		exval = MemReadHSCX(cs, 1, HSCX_EXIR);
 		if (exval & 0x40) {
@@ -576,7 +622,7 @@
 			debugl1(cs, "HSCX B interrupt %x", val);
 		Memhscx_interrupt(cs, val, 1);
 	}
-	if (val & 0x02) {
+	if (val & 0x02) {	// EXA
 		bcs = cs->bcs;
 		exval = MemReadHSCX(cs, 0, HSCX_EXIR);
 		if (exval & 0x40) {
@@ -598,7 +644,7 @@
 		} else if (cs->debug & L1_DEB_HSCX)
 			debugl1(cs, "HSCX A EXIR %x", exval);
 	}
-	if (val & 0x04) {
+	if (val & 0x04) {	// ICA
 		exval = MemReadHSCX(cs, 0, HSCX_ISTA);
 		if (cs->debug & L1_DEB_HSCX)
 			debugl1(cs, "HSCX A interrupt %x", exval);
@@ -659,12 +705,31 @@
 	memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xC0);
 }
 
+static void
+diva_irq_ipacx_pci(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	u_char val;
+	u_char *cfg;
+
+	if (!cs) {
+		printk(KERN_WARNING "Diva: Spurious interrupt!\n");
+		return;
+	}
+	cfg = (u_char *) cs->hw.diva.pci_cfg;
+	val = *cfg;
+	if (!(val &PITA_INT0_STATUS)) return; // other shared IRQ
+  interrupt_ipacx(cs);      // handler for chip
+	*cfg = PITA_INT0_STATUS;  // Reset PLX interrupt
+}
+
 void
 release_io_diva(struct IsdnCardState *cs)
 {
 	int bytecnt;
 
-	if (cs->subtyp == DIVA_IPAC_PCI) {
+	if ((cs->subtyp == DIVA_IPAC_PCI) || 
+	    (cs->subtyp == DIVA_IPACX_PCI)   ) {
 		u_int *cfg = (unsigned int *)cs->hw.diva.pci_cfg;
 
 		*cfg = 0; /* disable INT0/1 */ 
@@ -711,6 +776,16 @@
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout((10*HZ)/1000);
 		memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0);
+	} else if (cs->subtyp == DIVA_IPACX_PCI) {
+		unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg +
+					PITA_MISC_REG);
+		*ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((10*HZ)/1000);
+		*ireg = PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((10*HZ)/1000);
+		MemWriteISAC_IPACX(cs, IPACX_MASK, 0xff); // Interrupts off
 	} else { /* DIVA 2.0 */
 		cs->hw.diva.ctrl_reg = 0;        /* Reset On */
 		byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
@@ -739,7 +814,9 @@
 {
 	int blink = 0;
 
-	if ((cs->subtyp == DIVA_IPAC_ISA) || (cs->subtyp == DIVA_IPAC_PCI))
+	if ((cs->subtyp == DIVA_IPAC_ISA) ||
+	    (cs->subtyp == DIVA_IPAC_PCI) ||
+	    (cs->subtyp == DIVA_IPACX_PCI)   )
 		return;
 	del_timer(&cs->hw.diva.tl);
 	if (cs->hw.diva.status & DIVA_ASSIGN)
@@ -782,6 +859,12 @@
 			release_io_diva(cs);
 			return(0);
 		case CARD_INIT:
+			if (cs->subtyp == DIVA_IPACX_PCI) {
+				ireg = (unsigned int *)cs->hw.diva.pci_cfg;
+				*ireg = PITA_INT0_ENABLE;
+			  init_ipacx(cs, 3); // init chip and enable interrupts
+        return (0);
+			}
 			if (cs->subtyp == DIVA_IPAC_PCI) {
 				ireg = (unsigned int *)cs->hw.diva.pci_cfg;
 				*ireg = PITA_INT0_ENABLE;
@@ -818,7 +901,9 @@
 			}
 			break;
 	}
-	if ((cs->subtyp != DIVA_IPAC_ISA) && (cs->subtyp != DIVA_IPAC_PCI))
+	if ((cs->subtyp != DIVA_IPAC_ISA) && 
+	    (cs->subtyp != DIVA_IPAC_PCI) &&
+	    (cs->subtyp != DIVA_IPACX_PCI)   )
 		diva_led_handler(cs);
 	return(0);
 }
@@ -826,11 +911,40 @@
 static struct pci_dev *dev_diva __initdata = NULL;
 static struct pci_dev *dev_diva_u __initdata = NULL;
 static struct pci_dev *dev_diva201 __initdata = NULL;
+static struct pci_dev *dev_diva202 __initdata = NULL;
+
+#ifdef __ISAPNP__
+static struct isapnp_device_id diva_ids[] __initdata = {
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), 
+	  (unsigned long) "Diva picola" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), 
+	  (unsigned long) "Diva picola" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), 
+	  (unsigned long) "Diva 2.0" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), 
+	  (unsigned long) "Diva 2.0" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), 
+	  (unsigned long) "Diva 2.01" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), 
+	  (unsigned long) "Diva 2.01" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *pdev = &diva_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 
 int __init
 setup_diva(struct IsdnCard *card)
 {
-	int bytecnt;
+	int bytecnt = 8;
 	u_char val;
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
@@ -863,8 +977,75 @@
 			cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
 		}
 		cs->irq = card->para[0];
-		bytecnt = 8;
 	} else {
+#ifdef __ISAPNP__
+		if (isapnp_present()) {
+			struct pci_bus *pb;
+			struct pci_dev *pd;
+
+			while(pdev->card_vendor) {
+				if ((pb = isapnp_find_card(pdev->card_vendor,
+					pdev->card_device, pnp_c))) {
+					pnp_c = pb;
+					pd = NULL;
+					if ((pd = isapnp_find_dev(pnp_c,
+						pdev->vendor, pdev->function, pd))) {
+						printk(KERN_INFO "HiSax: %s detected\n",
+							(char *)pdev->driver_data);
+						pd->prepare(pd);
+						pd->deactivate(pd);
+						pd->activate(pd);
+						card->para[1] =
+							pd->resource[0].start;
+						card->para[0] =
+							pd->irq_resource[0].start;
+						if (!card->para[0] || !card->para[1]) {
+							printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
+								card->para[0], card->para[1]);
+							pd->deactivate(pd);
+							return(0);
+						}
+						cs->hw.diva.cfg_reg  = card->para[1];
+						cs->irq = card->para[0];
+						if (pdev->function == ISAPNP_FUNCTION(0xA1)) {
+							cs->subtyp = DIVA_IPAC_ISA;
+							cs->hw.diva.ctrl = 0;
+							cs->hw.diva.isac =
+								card->para[1] + DIVA_IPAC_DATA;
+							cs->hw.diva.hscx =
+								card->para[1] + DIVA_IPAC_DATA;
+							cs->hw.diva.isac_adr =
+								card->para[1] + DIVA_IPAC_ADR;
+							cs->hw.diva.hscx_adr =
+								card->para[1] + DIVA_IPAC_ADR;
+							test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+						} else {
+							cs->subtyp = DIVA_ISA;
+							cs->hw.diva.ctrl =
+								card->para[1] + DIVA_ISA_CTRL;
+							cs->hw.diva.isac =
+								card->para[1] + DIVA_ISA_ISAC_DATA;
+							cs->hw.diva.hscx =
+								card->para[1] + DIVA_HSCX_DATA;
+							cs->hw.diva.isac_adr =
+								card->para[1] + DIVA_ISA_ISAC_ADR;
+							cs->hw.diva.hscx_adr =
+								card->para[1] + DIVA_HSCX_ADR;
+						}
+						goto ready;
+					} else {
+						printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
+						return(0);
+					}
+				}
+				pdev++;
+				pnp_c=NULL;
+			} 
+			if (!pdev->card_vendor) {
+				printk(KERN_INFO "Diva PnP: no ISAPnP card found\n");
+			}
+		}
+#endif
 #if CONFIG_PCI
 		if (!pci_present()) {
 			printk(KERN_ERR "Diva: no PCI bus present\n");
@@ -896,6 +1077,16 @@
 				(ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
 			cs->hw.diva.cfg_reg =
 				(ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
+		} else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
+			PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
+			if (pci_enable_device(dev_diva202))
+				return(0);
+			cs->subtyp = DIVA_IPACX_PCI;
+			cs->irq = dev_diva202->irq;
+			cs->hw.diva.pci_cfg =
+				(ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
+			cs->hw.diva.cfg_reg =
+				(ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
 		} else {
 			printk(KERN_WARNING "Diva: No PCI card found\n");
 			return(0);
@@ -916,7 +1107,8 @@
 		printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
 		return (0);
 #endif /* CONFIG_PCI */
-		if (cs->subtyp == DIVA_IPAC_PCI) {
+		if ((cs->subtyp == DIVA_IPAC_PCI) ||
+		    (cs->subtyp == DIVA_IPACX_PCI)   ) {
 			cs->hw.diva.ctrl = 0;
 			cs->hw.diva.isac = 0;
 			cs->hw.diva.hscx = 0;
@@ -933,18 +1125,23 @@
 			bytecnt = 32;
 		}
 	}
-
+ready:
 	printk(KERN_INFO
 		"Diva: %s card configured at %#lx IRQ %d\n",
 		(cs->subtyp == DIVA_PCI) ? "PCI" :
 		(cs->subtyp == DIVA_ISA) ? "ISA" : 
-		(cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" : "IPAC PCI",
+		(cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" :
+		(cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI",
 		cs->hw.diva.cfg_reg, cs->irq);
-	if ((cs->subtyp == DIVA_IPAC_PCI) || (cs->subtyp == DIVA_PCI))
-		printk(KERN_INFO "Diva: %s PCI space at %#lx\n",
-			(cs->subtyp == DIVA_PCI) ? "PCI" : "IPAC PCI",
+	if ((cs->subtyp == DIVA_IPAC_PCI)  || 
+	    (cs->subtyp == DIVA_IPACX_PCI) || 
+	    (cs->subtyp == DIVA_PCI)         )
+		printk(KERN_INFO "Diva: %s space at %#lx\n",
+			(cs->subtyp == DIVA_PCI) ? "PCI" :
+			(cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI",
 			cs->hw.diva.pci_cfg);
-	if (cs->subtyp != DIVA_IPAC_PCI) {
+	if ((cs->subtyp != DIVA_IPAC_PCI) &&
+	    (cs->subtyp != DIVA_IPACX_PCI)   ) {
 		if (check_region(cs->hw.diva.cfg_reg, bytecnt)) {
 			printk(KERN_WARNING
 			       "HiSax: %s config port %lx-%lx already in use\n",
@@ -980,6 +1177,17 @@
 		cs->irq_func = &diva_irq_ipac_pci;
 		val = memreadreg(cs->hw.diva.cfg_reg, IPAC_ID);
 		printk(KERN_INFO "Diva: IPAC version %x\n", val);
+	} else if (cs->subtyp == DIVA_IPACX_PCI) {
+		cs->readisac  = &MemReadISAC_IPACX;
+		cs->writeisac = &MemWriteISAC_IPACX;
+		cs->readisacfifo  = &MemReadISACfifo_IPACX;
+		cs->writeisacfifo = &MemWriteISACfifo_IPACX;
+		cs->BC_Read_Reg  = &MemReadHSCX_IPACX;
+		cs->BC_Write_Reg = &MemWriteHSCX_IPACX;
+		cs->BC_Send_Data = 0; // function located in ipacx module
+		cs->irq_func = &diva_irq_ipacx_pci;
+		printk(KERN_INFO "Diva: IPACX Design Id: %x\n", 
+            MemReadISAC_IPACX(cs, IPACX_ID) &0x3F);
 	} else { /* DIVA 2.0 */
 		cs->hw.diva.tl.function = (void *) diva_led_handler;
 		cs->hw.diva.tl.data = (long) cs;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/elsa.c linux-2.4.20/drivers/isdn/hisax/elsa.c
--- linux-2.4.19/drivers/isdn/hisax/elsa.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/elsa.c	2002-10-29 11:18:33.000000000 +0000
@@ -28,6 +28,7 @@
 #include "hscx.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isapnp.h>
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
 
@@ -863,6 +864,21 @@
 static 	struct pci_dev *dev_qs1000 __devinitdata = NULL;
 static 	struct pci_dev *dev_qs3000 __devinitdata = NULL;
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id elsa_ids[] __initdata = {
+	{ ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133),
+	  ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133), 
+	  (unsigned long) "Elsa QS1000" },
+	{ ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134),
+	  ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134), 
+	  (unsigned long) "Elsa QS3000" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *pdev = &elsa_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 int __devinit
 setup_elsa(struct IsdnCard *card)
 {
@@ -877,6 +893,7 @@
 	cs->hw.elsa.ctrl_reg = 0;
 	cs->hw.elsa.status = 0;
 	cs->hw.elsa.MFlag = 0;
+	cs->subtyp = 0;
 	if (cs->typ == ISDN_CTYPE_ELSA) {
 		cs->hw.elsa.base = card->para[0];
 		printk(KERN_INFO "Elsa: Microlink IO probing\n");
@@ -938,9 +955,60 @@
 			return (0);
 		}
 	} else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
-		cs->hw.elsa.base = card->para[1];
-		cs->irq = card->para[0];
-		cs->subtyp = ELSA_QS1000;
+#ifdef __ISAPNP__
+		if (!card->para[1] && isapnp_present()) {
+			struct pci_bus *pb;
+			struct pci_dev *pd;
+
+			while(pdev->card_vendor) {
+				if ((pb = isapnp_find_card(pdev->card_vendor,
+					pdev->card_device, pnp_c))) {
+					pnp_c = pb;
+					pd = NULL;
+					if ((pd = isapnp_find_dev(pnp_c,
+						pdev->vendor, pdev->function, pd))) {
+						printk(KERN_INFO "HiSax: %s detected\n",
+							(char *)pdev->driver_data);
+						pd->prepare(pd);
+						pd->deactivate(pd);
+						pd->activate(pd);
+						card->para[1] =
+							pd->resource[0].start;
+						card->para[0] =
+							pd->irq_resource[0].start;
+						if (!card->para[0] || !card->para[1]) {
+							printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
+								card->para[0], card->para[1]);
+							pd->deactivate(pd);
+							return(0);
+						}
+						if (pdev->function == ISAPNP_FUNCTION(0x133))
+							cs->subtyp = ELSA_QS1000;
+						else
+							cs->subtyp = ELSA_QS3000;
+						break;
+					} else {
+						printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
+						return(0);
+					}
+				}
+				pdev++;
+				pnp_c=NULL;
+			} 
+			if (!pdev->card_vendor) {
+				printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
+				return(0);
+			}
+		}
+#endif
+		if (card->para[1] && card->para[0]) { 
+			cs->hw.elsa.base = card->para[1];
+			cs->irq = card->para[0];
+			if (!cs->subtyp)
+				cs->subtyp = ELSA_QS1000;
+		} else {
+			printk(KERN_ERR "Elsa PnP: no parameter\n");
+		}
 		cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
 		cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
 		cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
@@ -1055,6 +1123,7 @@
 			break;
 		case ELSA_PCFPRO:
 		case ELSA_PCF:
+		case ELSA_QS3000:
 		case ELSA_QS3000PCI:
 			bytecnt = 16;
 			break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/enternow.h linux-2.4.20/drivers/isdn/hisax/enternow.h
--- linux-2.4.19/drivers/isdn/hisax/enternow.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/enternow.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,51 @@
+/* 2001/10/02
+ *
+ * enternow.h   Header-file included by
+ *              enternow_pci.c
+ *
+ * Author       Christoph Ersfeld <info@formula-n.de>
+ *              Formula-n Europe AG (www.formula-n.com)
+ *              previously Gerdes AG
+ *
+ *
+ *              This file is (c) under GNU PUBLIC LICENSE
+ */
+
+
+/* ***************************************************************************************** *
+ * ****************************** datatypes and macros ************************************* *
+ * ***************************************************************************************** */
+
+#define BYTE							unsigned char
+#define WORD							unsigned int
+#define HIBYTE(w)						((unsigned char)((w & 0xff00) / 256))
+#define LOBYTE(w)						((unsigned char)(w & 0x00ff))
+#define InByte(addr)						inb(addr)
+#define OutByte(addr,val)					outb(val,addr)
+
+
+
+/* ***************************************************************************************** *
+ * *********************************** card-specific *************************************** *
+ * ***************************************************************************************** */
+
+/* fr PowerISDN PCI */
+#define TJ_AMD_IRQ 						0x20
+#define TJ_LED1 						0x40
+#define TJ_LED2 						0x80
+
+
+/* Das Fenster zum AMD...
+ * Ab Adresse hw.njet.base + TJ_AMD_PORT werden vom AMD jeweils 8 Bit in
+ * den TigerJet i/o-Raum gemappt
+ * -> 0x01 des AMD bei hw.njet.base + 0C4 */
+#define TJ_AMD_PORT						0xC0
+
+
+
+/* ***************************************************************************************** *
+ * *************************************** Prototypen ************************************** *
+ * ***************************************************************************************** */
+
+BYTE ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset);
+void WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/enternow_pci.c linux-2.4.20/drivers/isdn/hisax/enternow_pci.c
--- linux-2.4.19/drivers/isdn/hisax/enternow_pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/enternow_pci.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,447 @@
+/* enternow_pci.c,v 0.99 2001/10/02
+ *
+ * enternow_pci.c       Card-specific routines for
+ *                      Formula-n enter:now ISDN PCI ab
+ *                      Gerdes AG Power ISDN PCI
+ *                      Woerltronic SA 16 PCI
+ *                      (based on HiSax driver by Karsten Keil)
+ *
+ * Author               Christoph Ersfeld <info@formula-n.de>
+ *                      Formula-n Europe AG (www.formula-n.com)
+ *                      previously Gerdes AG
+ *
+ *
+ *                      This file is (c) under GNU PUBLIC LICENSE
+ *
+ * Notes:
+ * This driver interfaces to netjet.c which performs B-channel
+ * processing.
+ *
+ * Version 0.99 is the first release of this driver and there are
+ * certainly a few bugs.
+ * It isn't testet on linux 2.4 yet, so consider this code to be
+ * beta.
+ *
+ * Please don't report me any malfunction without sending
+ * (compressed) debug-logs.
+ * It would be nearly impossible to retrace it.
+ *
+ * Log D-channel-processing as follows:
+ *
+ * 1. Load hisax with card-specific parameters, this example ist for
+ *    Formula-n enter:now ISDN PCI and compatible
+ *    (f.e. Gerdes Power ISDN PCI)
+ *
+ *    modprobe hisax type=41 protocol=2 id=gerdes
+ *
+ *    if you chose an other value for id, you need to modify the
+ *    code below, too.
+ *
+ * 2. set debug-level
+ *
+ *    hisaxctrl gerdes 1 0x3ff
+ *    hisaxctrl gerdes 11 0x4f
+ *    cat /dev/isdnctrl >> ~/log &
+ *
+ * Please take also a look into /var/log/messages if there is
+ * anything importand concerning HISAX.
+ *
+ *
+ * Credits:
+ * Programming the driver for Formula-n enter:now ISDN PCI and
+ * neccessary the driver for the used Amd 7930 D-channel-controller
+ * was spnsored by Formula-n Europe AG.
+ * Thanks to Karsten Keil and Petr Novak, who gave me support in
+ * Hisax-specific questions.
+ * I want so say special thanks to Carl-Friedrich Braun, who had to
+ * answer a lot of questions about generally ISDN and about handling
+ * of the Amd-Chip.
+ *
+ */
+
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "hisax.h"
+#include "isac.h"
+#include "isdnl1.h"
+#include "amd7930_fn.h"
+#include "enternow.h"
+#include <linux/interrupt.h>
+#include <linux/ppp_defs.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include "netjet.h"
+
+
+
+const char *enternow_pci_rev = "$Revision: 1.1.2.1 $";
+
+
+/* *************************** I/O-Interface functions ************************************* */
+
+
+/* cs->readisac, macro rByteAMD */
+BYTE
+ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset)
+{
+	/* direktes Register */
+	if(offset < 8)
+		return (InByte(cs->hw.njet.isac + 4*offset));
+
+	/* indirektes Register */
+	else {
+		OutByte(cs->hw.njet.isac + 4*AMD_CR, offset);
+		return(InByte(cs->hw.njet.isac + 4*AMD_DR));
+	}
+}
+
+/* cs->writeisac, macro wByteAMD */
+void
+WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value)
+{
+	/* direktes Register */
+	if(offset < 8)
+		OutByte(cs->hw.njet.isac + 4*offset, value);
+
+	/* indirektes Register */
+	else {
+		OutByte(cs->hw.njet.isac + 4*AMD_CR, offset);
+		OutByte(cs->hw.njet.isac + 4*AMD_DR, value);
+	}
+}
+
+
+void
+enpci_setIrqMask(struct IsdnCardState *cs, BYTE val) {
+        if (!val)
+	        OutByte(cs->hw.njet.base+NETJET_IRQMASK1, 0x00);
+        else
+	        OutByte(cs->hw.njet.base+NETJET_IRQMASK1, TJ_AMD_IRQ);
+}
+
+
+static BYTE dummyrr(struct IsdnCardState *cs, int chan, BYTE off)
+{
+        return(5);
+}
+
+static void dummywr(struct IsdnCardState *cs, int chan, BYTE off, BYTE value)
+{
+
+}
+
+
+/* ******************************************************************************** */
+
+
+static void
+reset_enpci(struct IsdnCardState *cs)
+{
+	long flags;
+
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "enter:now PCI: reset");
+
+	save_flags(flags);
+	sti();
+	/* Reset on, (also for AMD) */
+	cs->hw.njet.ctrl_reg = 0x07;
+	OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	/* 80 ms delay */
+	schedule_timeout((80*HZ)/1000);
+	/* Reset off */
+	cs->hw.njet.ctrl_reg = 0x70;
+	OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	/* 80ms delay */
+	schedule_timeout((80*HZ)/1000);
+	restore_flags(flags);
+	cs->hw.njet.auxd = 0;  // LED-status
+	cs->hw.njet.dmactrl = 0;
+	OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
+	OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
+	OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); // LED off
+
+}
+
+
+static int
+enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+        BYTE *chan;
+
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt);
+
+        switch (mt) {
+		case CARD_RESET:
+			reset_enpci(cs);
+                        Amd7930_init(cs);
+			break;
+		case CARD_RELEASE:
+			release_io_netjet(cs);
+			break;
+		case CARD_INIT:
+			inittiger(cs);
+			Amd7930_init(cs);
+			break;
+		case CARD_TEST:
+			break;
+                case MDL_ASSIGN:
+                        /* TEI assigned, LED1 on */
+                        cs->hw.njet.auxd = TJ_AMD_IRQ << 1;
+                        OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+                        break;
+                case MDL_REMOVE:
+                        /* TEI removed, LEDs off */
+	                cs->hw.njet.auxd = 0;
+                        OutByte(cs->hw.njet.base + NETJET_AUXDATA, 0x00);
+                        break;
+                case MDL_BC_ASSIGN:
+                        /* activate B-channel */
+                        chan = (BYTE *)arg;
+
+                        if (cs->debug & L1_DEB_ISAC)
+		                debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan);
+
+                        cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN");
+                        /* at least one b-channel in use, LED 2 on */
+                        cs->hw.njet.auxd |= TJ_AMD_IRQ << 2;
+                        OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+                        break;
+                case MDL_BC_RELEASE:
+                        /* deactivate B-channel */
+                        chan = (BYTE *)arg;
+
+                        if (cs->debug & L1_DEB_ISAC)
+		                debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan);
+
+                        cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 & ~(*chan + 1)), "MDL_BC_RELEASE");
+                        /* no b-channel active -> LED2 off */
+                        if (!(cs->dc.amd7930.lmr1 & 3)) {
+                                cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2);
+                                OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+                        }
+                        break;
+                default:
+                        break;
+
+	}
+	return(0);
+}
+
+
+static void
+enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	BYTE sval, ir;
+	long flags;
+
+
+	if (!cs) {
+		printk(KERN_WARNING "enter:now PCI: Spurious interrupt!\n");
+		return;
+	}
+
+	sval = InByte(cs->hw.njet.base + NETJET_IRQSTAT1);
+
+        /* AMD threw an interrupt */
+	if (!(sval & TJ_AMD_IRQ)) {
+                /* read and clear interrupt-register */
+		ir = ReadByteAmd7930(cs, 0x00);
+		Amd7930_interrupt(cs, ir);
+	}
+
+	/* DMA-Interrupt: B-channel-stuff */
+	/* set bits in sval to indicate which page is free */
+
+	save_flags(flags);
+	cli();
+	/* set bits in sval to indicate which page is free */
+	if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
+		inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
+		/* the 2nd write page is free */
+		sval = 0x08;
+	else	/* the 1st write page is free */
+		sval = 0x04;
+	if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
+		inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
+		/* the 2nd read page is free */
+		sval = sval | 0x02;
+	else	/* the 1st read page is free */
+		sval = sval | 0x01;
+	if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */
+	{
+		if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+			restore_flags(flags);
+			return;
+		}
+		cs->hw.njet.irqstat0 = sval;
+		restore_flags(flags);
+		if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
+			(cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
+			/* we have a read dma int */
+			read_tiger(cs);
+		if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) !=
+			(cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
+			/* we have a write dma int */
+			write_tiger(cs);
+		test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+	} else
+		restore_flags(flags);
+}
+
+
+static struct pci_dev *dev_netjet __initdata = NULL;
+
+/* called by config.c */
+int __init
+setup_enternow_pci(struct IsdnCard *card)
+{
+	int bytecnt;
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+	long flags;
+
+#if CONFIG_PCI
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
+        strcpy(tmp, enternow_pci_rev);
+	printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_ENTERNOW)
+		return(0);
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+
+	for ( ;; )
+	{
+		if (!pci_present()) {
+			printk(KERN_ERR "enter:now PCI: no PCI bus present\n");
+			return(0);
+		}
+		if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+			PCI_DEVICE_ID_TIGERJET_300,  dev_netjet))) {
+			if (pci_enable_device(dev_netjet))
+				return(0);
+			cs->irq = dev_netjet->irq;
+			if (!cs->irq) {
+				printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n");
+				return(0);
+			}
+			cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
+			if (!cs->hw.njet.base) {
+				printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n");
+				return(0);
+			}
+                        /* checks Sub-Vendor ID because system crashes with Traverse-Card */
+			if ((dev_netjet->subsystem_vendor != 0x55) ||
+				(dev_netjet->subsystem_device != 0x02)) {
+				printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n");
+                                printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n");
+                                return(0);
+                        }
+		} else {
+                        printk(KERN_WARNING "enter:now PCI: No PCI card found\n");
+			return(0);
+		}
+
+		cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+		cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD
+
+		save_flags(flags);
+		sti();
+
+		/* Reset an */
+		cs->hw.njet.ctrl_reg = 0x07;  // gendert von 0xff
+		OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		/* 50 ms Pause */
+		schedule_timeout((50*HZ)/1000);
+
+		cs->hw.njet.ctrl_reg = 0x30;  /* Reset Off and status read clear */
+		OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
+
+		restore_flags(flags);
+
+		cs->hw.njet.auxd = 0x00; // war 0xc0
+		cs->hw.njet.dmactrl = 0;
+
+		OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
+		OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
+		OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd);
+
+			   break;
+	}
+#else
+
+	printk(KERN_WARNING "enter:now PCI: NO_PCI_BIOS\n");
+	printk(KERN_WARNING "enter:now PCI: unable to config Formula-n enter:now ISDN PCI ab\n");
+	return (0);
+
+#endif /* CONFIG_PCI */
+
+	bytecnt = 256;
+
+	printk(KERN_INFO
+		"enter:now PCI: PCI card configured at 0x%lx IRQ %d\n",
+		cs->hw.njet.base, cs->irq);
+	if (check_region(cs->hw.njet.base, bytecnt)) {
+		printk(KERN_WARNING
+			   "HiSax: %s config port %lx-%lx already in use\n",
+			   CardType[card->typ],
+			   cs->hw.njet.base,
+			   cs->hw.njet.base + bytecnt);
+		return (0);
+	} else {
+		request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN");
+	}
+	reset_enpci(cs);
+	cs->hw.njet.last_is0 = 0;
+        /* macro rByteAMD */
+        cs->readisac = &ReadByteAmd7930;
+        /* macro wByteAMD */
+        cs->writeisac = &WriteByteAmd7930;
+        cs->dc.amd7930.setIrqMask = &enpci_setIrqMask;
+
+        cs->BC_Read_Reg  = &dummyrr;
+	cs->BC_Write_Reg = &dummywr;
+	cs->BC_Send_Data = &netjet_fill_dma;
+	cs->cardmsg = &enpci_card_msg;
+	cs->irq_func = &enpci_interrupt;
+	cs->irq_flags |= SA_SHIRQ;
+
+        return (1);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/hfc_sx.c linux-2.4.20/drivers/isdn/hisax/hfc_sx.c
--- linux-2.4.19/drivers/isdn/hisax/hfc_sx.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/hfc_sx.c	2002-10-29 11:18:32.000000000 +0000
@@ -17,6 +17,7 @@
 #include "hfc_sx.h"
 #include "isdnl1.h"
 #include <linux/interrupt.h>
+#include <linux/isapnp.h>
 
 extern const char *CardType[];
 
@@ -1460,7 +1461,17 @@
 	return (0);
 }
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id hfc_ids[] __initdata = {
+	{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620),
+	  ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620), 
+	  (unsigned long) "Teles 16.3c2" },
+	{ 0, }
+};
 
+static struct isapnp_device_id *hdev = &hfc_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
 
 int __devinit
 setup_hfcsx(struct IsdnCard *card)
@@ -1471,6 +1482,45 @@
 
 	strcpy(tmp, hfcsx_revision);
 	printk(KERN_INFO "HiSax: HFC-SX driver Rev. %s\n", HiSax_getrev(tmp));
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		while(hdev->card_vendor) {
+			if ((pb = isapnp_find_card(hdev->card_vendor,
+				hdev->card_device, pnp_c))) {
+				pnp_c = pb;
+				pd = NULL;
+				if ((pd = isapnp_find_dev(pnp_c,
+					hdev->vendor, hdev->function, pd))) {
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)hdev->driver_data);
+					pd->prepare(pd);
+					pd->deactivate(pd);
+					pd->activate(pd);
+					card->para[1] = pd->resource[0].start;
+					card->para[0] = pd->irq_resource[0].start;
+					if (!card->para[0] || !card->para[1]) {
+						printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n",
+						card->para[0], card->para[1]);
+						pd->deactivate(pd);
+						return(0);
+					}
+					break;
+				} else {
+					printk(KERN_ERR "HFC PnP: PnP error card found, no device\n");
+				}
+			}
+			hdev++;
+			pnp_c=NULL;
+		} 
+		if (!hdev->card_vendor) {
+			printk(KERN_INFO "HFC PnP: no ISAPnP card found\n");
+			return(0);
+		}
+	}
+#endif
 	cs->hw.hfcsx.base = card->para[1] & 0xfffe;
 	cs->irq = card->para[0];
 	cs->hw.hfcsx.int_s1 = 0;
@@ -1553,7 +1603,3 @@
 	cs->auxcmd = &hfcsx_auxcmd;
 	return (1);
 }
-
-
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/hfcscard.c linux-2.4.20/drivers/isdn/hisax/hfcscard.c
--- linux-2.4.19/drivers/isdn/hisax/hfcscard.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/hfcscard.c	2002-10-29 11:18:39.000000000 +0000
@@ -12,6 +12,7 @@
 
 #define __NO_VERSION__
 #include <linux/init.h>
+#include <linux/isapnp.h>
 #include "hisax.h"
 #include "hfc_2bds0.h"
 #include "isdnl1.h"
@@ -139,6 +140,36 @@
 	return(0);
 }
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id hfc_ids[] __initdata = {
+	{ ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
+	  ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114), 
+	  (unsigned long) "Acer P10" },
+	{ ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002),
+	  ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002), 
+	  (unsigned long) "Billion 2" },
+	{ ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001),
+	  ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001), 
+	  (unsigned long) "Billion 1" },
+	{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410),
+	  ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410), 
+	  (unsigned long) "IStar PnP" },
+	{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610),
+	  ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610), 
+	  (unsigned long) "Teles 16.3c" },
+	{ ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001),
+	  ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001), 
+	  (unsigned long) "Tornado Tipa C" },
+	{ ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001),
+	  ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001), 
+	  (unsigned long) "Genius Speed Surfer" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *hdev = &hfc_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 int __init
 setup_hfcs(struct IsdnCard *card)
 {
@@ -147,6 +178,46 @@
 
 	strcpy(tmp, hfcs_revision);
 	printk(KERN_INFO "HiSax: HFC-S driver Rev. %s\n", HiSax_getrev(tmp));
+
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		while(hdev->card_vendor) {
+			if ((pb = isapnp_find_card(hdev->card_vendor,
+				hdev->card_device, pnp_c))) {
+				pnp_c = pb;
+				pd = NULL;
+				if ((pd = isapnp_find_dev(pnp_c,
+					hdev->vendor, hdev->function, pd))) {
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)hdev->driver_data);
+					pd->prepare(pd);
+					pd->deactivate(pd);
+					pd->activate(pd);
+					card->para[1] = pd->resource[0].start;
+					card->para[0] = pd->irq_resource[0].start;
+					if (!card->para[0] || !card->para[1]) {
+						printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n",
+						card->para[0], card->para[1]);
+						pd->deactivate(pd);
+						return(0);
+					}
+					break;
+				} else {
+					printk(KERN_ERR "HFC PnP: PnP error card found, no device\n");
+				}
+			}
+			hdev++;
+			pnp_c=NULL;
+		} 
+		if (!hdev->card_vendor) {
+			printk(KERN_INFO "HFC PnP: no ISAPnP card found\n");
+			return(0);
+		}
+	}
+#endif
 	cs->hw.hfcD.addr = card->para[1] & 0xfffe;
 	cs->irq = card->para[0];
 	cs->hw.hfcD.cip = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/hisax.h linux-2.4.20/drivers/isdn/hisax/hisax.h
--- linux-2.4.19/drivers/isdn/hisax/hisax.h	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/hisax.h	2002-10-29 11:18:49.000000000 +0000
@@ -68,6 +68,9 @@
 #define DL_DATA		0x0220
 #define DL_FLUSH	0x0224
 #define DL_UNIT_DATA	0x0230
+
+#define MDL_BC_RELEASE  0x0278  // Formula-n enter:now
+#define MDL_BC_ASSIGN   0x027C  // Formula-n enter:now
 #define MDL_ASSIGN	0x0280
 #define MDL_REMOVE	0x0284
 #define MDL_ERROR	0x0288
@@ -833,6 +836,17 @@
 	int ph_state;
 };
 
+struct amd7930_chip {
+	u_char lmr1;
+	u_char ph_state;
+	u_char old_state;
+	u_char flg_t3;
+	unsigned int tx_xmtlen;
+	struct timer_list timer3;
+	void (*ph_command) (struct IsdnCardState *, u_char, char *);
+	void (*setIrqMask) (struct IsdnCardState *, u_char);
+};
+
 struct icc_chip {
 	int ph_state;
 	u_char *mon_tx;
@@ -929,6 +943,7 @@
 		struct hfcpci_chip hfcpci;
 		struct hfcsx_chip hfcsx;
 		struct w6692_chip w6692;
+		struct amd7930_chip amd7930;
 		struct icc_chip icc;
 	} dc;
 	u_char *rcvbuf;
@@ -990,7 +1005,8 @@
 #define  ISDN_CTYPE_NETJET_U	38
 #define  ISDN_CTYPE_HFC_SP_PCMCIA      39
 #define  ISDN_CTYPE_DYNAMIC     40
-#define  ISDN_CTYPE_COUNT	40
+#define  ISDN_CTYPE_ENTERNOW	41
+#define  ISDN_CTYPE_COUNT	41
 
 
 #ifdef ISDN_CHIP_ISAC
@@ -1249,6 +1265,10 @@
 #define CARD_NETJET_U 0
 #endif
 
+#ifdef CONFIG_HISAX_ENTERNOW_PCI
+#define CARD_FN_ENTERNOW_PCI 1
+#endif
+
 #define TEI_PER_CARD 1
 
 /* L1 Debug */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/hisax_debug.h linux-2.4.20/drivers/isdn/hisax/hisax_debug.h
--- linux-2.4.19/drivers/isdn/hisax/hisax_debug.h	2001-09-30 19:26:05.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/hisax_debug.h	2002-10-29 11:18:39.000000000 +0000
@@ -28,7 +28,7 @@
 
 #define DBG(level, format, arg...) do { \
 if (level & __debug_variable) \
-printk(KERN_DEBUG __FUNCTION__ ": " format "\n" , ## arg); \
+printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \
 } while (0)
 
 #define DBG_PACKET(level,data,count) \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/ipacx.c linux-2.4.20/drivers/isdn/hisax/ipacx.c
--- linux-2.4.19/drivers/isdn/hisax/ipacx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/ipacx.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,1029 @@
+/* 
+ *
+ * IPACX specific routines
+ *
+ * Author       Joerg Petersohn
+ * Derived from hisax_isac.c, isac.c, hscx.c and others
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+#define __NO_VERSION__
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include "hisax_if.h"
+#include "hisax.h"
+#include "isdnl1.h"
+#include "ipacx.h"
+
+#define DBUSY_TIMER_VALUE 80
+#define TIMER3_VALUE      7000
+#define MAX_DFRAME_LEN_L1 300
+#define B_FIFO_SIZE       64
+#define D_FIFO_SIZE       32
+
+
+// ipacx interrupt mask values    
+#define _MASK_IMASK     0x2E  // global mask
+#define _MASKB_IMASK    0x0B
+#define _MASKD_IMASK    0x03  // all on
+
+//----------------------------------------------------------
+// local function declarations
+//----------------------------------------------------------
+static void ph_command(struct IsdnCardState *cs, unsigned int command);
+static inline void cic_int(struct IsdnCardState *cs);
+static void dch_l2l1(struct PStack *st, int pr, void *arg);
+static void dbusy_timer_handler(struct IsdnCardState *cs);
+static void ipacx_new_ph(struct IsdnCardState *cs);
+static void dch_bh(struct IsdnCardState *cs);
+static void dch_sched_event(struct IsdnCardState *cs, int event);
+static void dch_empty_fifo(struct IsdnCardState *cs, int count);
+static void dch_fill_fifo(struct IsdnCardState *cs);
+static inline void dch_int(struct IsdnCardState *cs);
+static void __devinit dch_setstack(struct PStack *st, struct IsdnCardState *cs);
+static void __devinit dch_init(struct IsdnCardState *cs);
+static void bch_l2l1(struct PStack *st, int pr, void *arg);
+static void bch_sched_event(struct BCState *bcs, int event);
+static void bch_empty_fifo(struct BCState *bcs, int count);
+static void bch_fill_fifo(struct BCState *bcs);
+static void bch_int(struct IsdnCardState *cs, u_char hscx);
+static void bch_mode(struct BCState *bcs, int mode, int bc);
+static void bch_close_state(struct BCState *bcs);
+static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs);
+static int bch_setstack(struct PStack *st, struct BCState *bcs);
+static void __devinit bch_init(struct IsdnCardState *cs, int hscx);
+static void __init clear_pending_ints(struct IsdnCardState *cs);
+
+//----------------------------------------------------------
+// Issue Layer 1 command to chip
+//----------------------------------------------------------
+static void 
+ph_command(struct IsdnCardState *cs, unsigned int command)
+{
+	if (cs->debug &L1_DEB_ISAC)
+		debugl1(cs, "ph_command (%#x) in (%#x)", command,
+			cs->dc.isac.ph_state);
+//###################################  
+//	printk(KERN_INFO "ph_command (%#x)\n", command);
+//###################################  
+	cs->writeisac(cs, IPACX_CIX0, (command << 4) | 0x0E);
+}
+
+//----------------------------------------------------------
+// Transceiver interrupt handler
+//----------------------------------------------------------
+static inline void 
+cic_int(struct IsdnCardState *cs)
+{
+	u_char event;
+
+	event = cs->readisac(cs, IPACX_CIR0) >> 4;
+	if (cs->debug &L1_DEB_ISAC) debugl1(cs, "cic_int(event=%#x)", event);
+//#########################################  
+//	printk(KERN_INFO "cic_int(%x)\n", event);
+//#########################################  
+  cs->dc.isac.ph_state = event;
+  dch_sched_event(cs, D_L1STATECHANGE);
+}
+
+//==========================================================
+// D channel functions
+//==========================================================
+
+//----------------------------------------------------------
+// Command entry point
+//----------------------------------------------------------
+static void
+dch_l2l1(struct PStack *st, int pr, void *arg)
+{
+	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+	struct sk_buff *skb = arg;
+  u_char cda1_cr, cda2_cr;
+
+	switch (pr) {
+		case (PH_DATA |REQUEST):
+			if (cs->debug &DEB_DLOG_HEX)     LogFrame(cs, skb->data, skb->len);
+			if (cs->debug &DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
+			if (cs->tx_skb) {
+				skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG
+				if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+			} else {
+				cs->tx_skb = skb;
+				cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG
+				if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+				dch_fill_fifo(cs);
+			}
+			break;
+      
+		case (PH_PULL |INDICATION):
+			if (cs->tx_skb) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+				skb_queue_tail(&cs->sq, skb);
+				break;
+			}
+			if (cs->debug & DEB_DLOG_HEX)     LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
+			cs->tx_skb = skb;
+			cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG
+			if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+			dch_fill_fifo(cs);
+			break;
+      
+		case (PH_PULL | REQUEST):
+#ifdef L2FRAME_DEBUG
+			if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+			if (!cs->tx_skb) {
+				clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+			break;
+
+		case (HW_RESET | REQUEST):
+		case (HW_ENABLE | REQUEST):
+			ph_command(cs, IPACX_CMD_TIM);
+			break;
+
+		case (HW_INFO3 | REQUEST):
+			ph_command(cs, IPACX_CMD_AR8);
+			break;
+
+		case (HW_TESTLOOP | REQUEST):
+      cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1
+      cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1
+      cda1_cr = cs->readisac(cs, IPACX_CDA1_CR);
+      cda2_cr = cs->readisac(cs, IPACX_CDA2_CR);
+			if ((long)arg &1) { // loop B1
+        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x0a); 
+      }
+      else {  // B1 off
+        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x0a); 
+      }
+			if ((long)arg &2) { // loop B2
+        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x14); 
+      }
+      else {  // B2 off
+        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x14); 
+      }
+			break;
+
+		case (HW_DEACTIVATE | RESPONSE):
+			skb_queue_purge(&cs->rq);
+			skb_queue_purge(&cs->sq);
+			if (cs->tx_skb) {
+				dev_kfree_skb_any(cs->tx_skb);
+				cs->tx_skb = NULL;
+			}
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			break;
+
+		default:
+			if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_l2l1 unknown %04x", pr);
+			break;
+	}
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void
+dbusy_timer_handler(struct IsdnCardState *cs)
+{
+	struct PStack *st;
+	int	rbchd, stard;
+
+	if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+		rbchd = cs->readisac(cs, IPACX_RBCHD);
+		stard = cs->readisac(cs, IPACX_STARD);
+		if (cs->debug) 
+      debugl1(cs, "D-Channel Busy RBCHD %02x STARD %02x", rbchd, stard);
+		if (!(stard &0x40)) { // D-Channel Busy
+			set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
+      for (st = cs->stlist; st; st = st->next) {
+				st->l1.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on
+			}
+		} else {
+			// seems we lost an interrupt; reset transceiver */
+			clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
+			if (cs->tx_skb) {
+				dev_kfree_skb_any(cs->tx_skb);
+				cs->tx_cnt = 0;
+				cs->tx_skb = NULL;
+			} else {
+				printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
+				debugl1(cs, "D-Channel Busy no skb");
+			}
+			cs->writeisac(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR
+		}
+	}
+}
+
+//----------------------------------------------------------
+// L1 state machine intermediate layer to isdnl1 module
+//----------------------------------------------------------
+static void
+ipacx_new_ph(struct IsdnCardState *cs)
+{
+	switch (cs->dc.isac.ph_state) {
+		case (IPACX_IND_RES):
+			ph_command(cs, IPACX_CMD_DI);
+			l1_msg(cs, HW_RESET | INDICATION, NULL);
+			break;
+      
+		case (IPACX_IND_DC):
+			l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
+			break;
+      
+		case (IPACX_IND_DR):
+			l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
+			break;
+      
+		case (IPACX_IND_PU):
+			l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+			break;
+
+		case (IPACX_IND_RSY):
+			l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+			break;
+
+		case (IPACX_IND_AR):
+			l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+			break;
+      
+		case (IPACX_IND_AI8):
+			l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+			break;
+      
+		case (IPACX_IND_AI10):
+			l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);
+			break;
+      
+		default:
+			break;
+	}
+}
+
+//----------------------------------------------------------
+// bottom half handler for D channel
+//----------------------------------------------------------
+static void
+dch_bh(struct IsdnCardState *cs)
+{
+	struct PStack *st;
+	
+	if (!cs) return;
+  
+	if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
+		if (cs->debug) debugl1(cs, "D-Channel Busy cleared");
+		for (st = cs->stlist; st; st = st->next) {
+			st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL);
+		}
+	}
+  
+	if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) {
+		DChannel_proc_rcv(cs);
+  }  
+  
+	if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) {
+		DChannel_proc_xmt(cs);
+  }  
+  
+	if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+    ipacx_new_ph(cs);
+  }  
+}
+
+//----------------------------------------------------------
+// proceed with bottom half handler dch_bh()
+//----------------------------------------------------------
+static void
+dch_sched_event(struct IsdnCardState *cs, int event)
+{
+	set_bit(event, &cs->event);
+	queue_task(&cs->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+//----------------------------------------------------------
+// Fill buffer from receive FIFO
+//----------------------------------------------------------
+static void 
+dch_empty_fifo(struct IsdnCardState *cs, int count)
+{
+	long flags;
+	u_char *ptr;
+
+	if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO))
+		debugl1(cs, "dch_empty_fifo()");
+
+  // message too large, remove
+	if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
+		if (cs->debug &L1_DEB_WARN)
+			debugl1(cs, "dch_empty_fifo() incoming message too large");
+	  cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
+		cs->rcvidx = 0;
+		return;
+	}
+  
+	ptr = cs->rcvbuf + cs->rcvidx;
+	cs->rcvidx += count;
+  
+	save_flags(flags);
+	cli();
+	cs->readisacfifo(cs, ptr, count);
+	cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
+	restore_flags(flags);
+  
+	if (cs->debug &L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "dch_empty_fifo() cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, cs->dlog);
+	}
+}
+
+//----------------------------------------------------------
+// Fill transmit FIFO
+//----------------------------------------------------------
+static void 
+dch_fill_fifo(struct IsdnCardState *cs)
+{
+	long flags;
+	int count;
+	u_char cmd, *ptr;
+
+	if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO))
+		debugl1(cs, "dch_fill_fifo()");
+    
+	if (!cs->tx_skb) return;
+	count = cs->tx_skb->len;
+	if (count <= 0) return;
+
+	if (count > D_FIFO_SIZE) {
+		count = D_FIFO_SIZE;
+		cmd   = 0x08; // XTF
+	} else {
+		cmd   = 0x0A; // XTF | XME
+	}
+  
+	save_flags(flags);
+	cli();
+	ptr = cs->tx_skb->data;
+	skb_pull(cs->tx_skb, count);
+	cs->tx_cnt += count;
+	cs->writeisacfifo(cs, ptr, count);
+	cs->writeisac(cs, IPACX_CMDRD, cmd);
+  
+  // set timeout for transmission contol
+	if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+		debugl1(cs, "dch_fill_fifo dbusytimer running");
+		del_timer(&cs->dbusytimer);
+	}
+	init_timer(&cs->dbusytimer);
+	cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
+	add_timer(&cs->dbusytimer);
+	restore_flags(flags);
+  
+	if (cs->debug &L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "dch_fill_fifo() cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, cs->dlog);
+	}
+}
+
+//----------------------------------------------------------
+// D channel interrupt handler
+//----------------------------------------------------------
+static inline void 
+dch_int(struct IsdnCardState *cs)
+{
+	struct sk_buff *skb;
+	u_char istad, rstad;
+	long flags;
+	int count;
+
+	istad = cs->readisac(cs, IPACX_ISTAD);
+//##############################################  
+//	printk(KERN_WARNING "dch_int(istad=%02x)\n", istad);
+//##############################################  
+  
+	if (istad &0x80) {  // RME
+	  rstad = cs->readisac(cs, IPACX_RSTAD);
+		if ((rstad &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
+			if (!(rstad &0x80))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "dch_int(): invalid frame");
+			if ((rstad &0x40))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "dch_int(): RDO");
+			if (!(rstad &0x20))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "dch_int(): CRC error");
+	    cs->writeisac(cs, IPACX_CMDRD, 0x80);  // RMC
+		} else {  // received frame ok
+			count = cs->readisac(cs, IPACX_RBCLD);
+      if (count) count--; // RSTAB is last byte
+			count &= D_FIFO_SIZE-1;
+			if (count == 0) count = D_FIFO_SIZE;
+			dch_empty_fifo(cs, count);
+			save_flags(flags);
+			cli();
+			if ((count = cs->rcvidx) > 0) {
+	      cs->rcvidx = 0;
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "HiSax dch_int(): receive out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), cs->rcvbuf, count);
+					skb_queue_tail(&cs->rq, skb);
+				}
+			}
+			restore_flags(flags);
+    }
+	  cs->rcvidx = 0;
+		dch_sched_event(cs, D_RCVBUFREADY);
+	}
+
+	if (istad &0x40) {  // RPF
+		dch_empty_fifo(cs, D_FIFO_SIZE);
+	}
+
+	if (istad &0x20) {  // RFO
+		if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): RFO");
+	  cs->writeisac(cs, IPACX_CMDRD, 0x40); //RRES
+	}
+  
+  if (istad &0x10) {  // XPR
+		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			dch_sched_event(cs, D_CLEARBUSY);
+    if (cs->tx_skb) {
+      if (cs->tx_skb->len) {
+        dch_fill_fifo(cs);
+        goto afterXPR;
+      }
+      else {
+        dev_kfree_skb_irq(cs->tx_skb);
+        cs->tx_skb = NULL;
+        cs->tx_cnt = 0;
+      }
+    }
+    if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+      cs->tx_cnt = 0;
+      dch_fill_fifo(cs);
+    } 
+    else {
+      dch_sched_event(cs, D_XMTBUFREADY);
+    }  
+  }  
+  afterXPR:
+
+	if (istad &0x0C) {  // XDU or XMR
+		if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): XDU");
+	  if (cs->tx_skb) {
+	    skb_push(cs->tx_skb, cs->tx_cnt); // retransmit
+	    cs->tx_cnt = 0;
+			dch_fill_fifo(cs);
+		} else {
+			printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
+			debugl1(cs, "ISAC XDU no skb");
+		}
+  }
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void __devinit
+dch_setstack(struct PStack *st, struct IsdnCardState *cs)
+{
+	st->l1.l1hw = dch_l2l1;
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void __devinit
+dch_init(struct IsdnCardState *cs)
+{
+	printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n");
+
+	cs->tqueue.routine  = (void *)(void *) dch_bh;
+	cs->setstack_d      = dch_setstack;
+  
+	cs->dbusytimer.function = (void *) dbusy_timer_handler;
+	cs->dbusytimer.data = (long) cs;
+	init_timer(&cs->dbusytimer);
+
+  cs->writeisac(cs, IPACX_TR_CONF0, 0x00);  // clear LDD
+  cs->writeisac(cs, IPACX_TR_CONF2, 0x00);  // enable transmitter
+  cs->writeisac(cs, IPACX_MODED,    0xC9);  // transparent mode 0, RAC, stop/go
+  cs->writeisac(cs, IPACX_MON_CR,   0x00);  // disable monitor channel
+}
+
+
+//==========================================================
+// B channel functions
+//==========================================================
+
+//----------------------------------------------------------
+// Entry point for commands
+//----------------------------------------------------------
+static void
+bch_l2l1(struct PStack *st, int pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	long flags;
+
+	switch (pr) {
+		case (PH_DATA | REQUEST):
+			save_flags(flags);
+			cli();
+			if (st->l1.bcs->tx_skb) {
+				skb_queue_tail(&st->l1.bcs->squeue, skb);
+				restore_flags(flags);
+			} else {
+				st->l1.bcs->tx_skb = skb;
+				set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+				st->l1.bcs->hw.hscx.count = 0;
+				restore_flags(flags);
+        bch_fill_fifo(st->l1.bcs);
+			}
+			break;
+		case (PH_PULL | INDICATION):
+			if (st->l1.bcs->tx_skb) {
+				printk(KERN_WARNING "HiSax bch_l2l1(): this shouldn't happen\n");
+				break;
+			}
+			set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+			st->l1.bcs->tx_skb = skb;
+			st->l1.bcs->hw.hscx.count = 0;
+      bch_fill_fifo(st->l1.bcs);
+			break;
+		case (PH_PULL | REQUEST):
+			if (!st->l1.bcs->tx_skb) {
+				clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+			break;
+		case (PH_ACTIVATE | REQUEST):
+			set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+			bch_mode(st->l1.bcs, st->l1.mode, st->l1.bc);
+			l1_msg_b(st, pr, arg);
+			break;
+		case (PH_DEACTIVATE | REQUEST):
+			l1_msg_b(st, pr, arg);
+			break;
+		case (PH_DEACTIVATE | CONFIRM):
+			clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+			clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+			bch_mode(st->l1.bcs, 0, st->l1.bc);
+			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			break;
+	}
+}
+
+//----------------------------------------------------------
+// proceed with bottom half handler BChannel_bh()
+//----------------------------------------------------------
+static void
+bch_sched_event(struct BCState *bcs, int event)
+{
+	bcs->event |= 1 << event;
+	queue_task(&bcs->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+//----------------------------------------------------------
+// Read B channel fifo to receive buffer
+//----------------------------------------------------------
+static void
+bch_empty_fifo(struct BCState *bcs, int count)
+{
+	u_char *ptr, hscx;
+	struct IsdnCardState *cs;
+	long flags;
+	int cnt;
+
+	cs = bcs->cs;
+  hscx = bcs->hw.hscx.hscx;
+	if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO))
+		debugl1(cs, "bch_empty_fifo()");
+
+  // message too large, remove
+	if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
+		if (cs->debug &L1_DEB_WARN)
+			debugl1(cs, "bch_empty_fifo() incoming packet too large");
+	  cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
+		bcs->hw.hscx.rcvidx = 0;
+		return;
+	}
+  
+  // Read data uninterruptible
+	save_flags(flags);
+	cli();
+	ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+	cnt = count;
+	while (cnt--) *ptr++ = cs->BC_Read_Reg(cs, hscx, IPACX_RFIFOB); 
+	cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
+  
+	ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+	bcs->hw.hscx.rcvidx += count;
+	restore_flags(flags);
+  
+	if (cs->debug &L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		t += sprintf(t, "bch_empty_fifo() B-%d cnt %d", hscx, count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, bcs->blog);
+	}
+}
+
+//----------------------------------------------------------
+// Fill buffer to transmit FIFO
+//----------------------------------------------------------
+static void
+bch_fill_fifo(struct BCState *bcs)
+{
+	struct IsdnCardState *cs;
+	int more, count, cnt;
+	u_char *ptr, *p, hscx;
+	long flags;
+
+	cs = bcs->cs;
+	if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO))
+		debugl1(cs, "bch_fill_fifo()");
+
+	if (!bcs->tx_skb)           return;
+	if (bcs->tx_skb->len <= 0)  return;
+
+	hscx = bcs->hw.hscx.hscx;
+	more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
+	if (bcs->tx_skb->len > B_FIFO_SIZE) {
+		more  = 1;
+		count = B_FIFO_SIZE;
+	} else {
+		count = bcs->tx_skb->len;
+	}  
+	cnt = count;
+    
+	save_flags(flags);
+	cli();
+	p = ptr = bcs->tx_skb->data;
+	skb_pull(bcs->tx_skb, count);
+	bcs->tx_cnt -= count;
+	bcs->hw.hscx.count += count;
+	while (cnt--) cs->BC_Write_Reg(cs, hscx, IPACX_XFIFOB, *p++); 
+	cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, (more ? 0x08 : 0x0a));
+	restore_flags(flags);
+  
+	if (cs->debug &L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		t += sprintf(t, "chb_fill_fifo() B-%d cnt %d", hscx, count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, bcs->blog);
+	}
+}
+
+//----------------------------------------------------------
+// B channel interrupt handler
+//----------------------------------------------------------
+static void
+bch_int(struct IsdnCardState *cs, u_char hscx)
+{
+	u_char istab;
+	struct BCState *bcs;
+	struct sk_buff *skb;
+	int count;
+	u_char rstab;
+
+	bcs = cs->bcs + hscx;
+	istab = cs->BC_Read_Reg(cs, hscx, IPACX_ISTAB);
+//##############################################  
+//	printk(KERN_WARNING "bch_int(istab=%02x)\n", istab);
+//##############################################  
+	if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return;
+
+	if (istab &0x80) {	// RME
+		rstab = cs->BC_Read_Reg(cs, hscx, IPACX_RSTAB);
+		if ((rstab &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
+			if (!(rstab &0x80))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "bch_int() B-%d: invalid frame", hscx);
+			if ((rstab &0x40) && (bcs->mode != L1_MODE_NULL))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode);
+			if (!(rstab &0x20))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "bch_int() B-%d: CRC error", hscx);
+	    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
+		} 
+    else {  // received frame ok
+			count = cs->BC_Read_Reg(cs, hscx, IPACX_RBCLB) &(B_FIFO_SIZE-1);
+			if (count == 0) count = B_FIFO_SIZE;
+			bch_empty_fifo(bcs, count);
+			if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
+				if (cs->debug &L1_DEB_HSCX_FIFO)
+					debugl1(cs, "bch_int Frame %d", count);
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "HiSax bch_int(): receive frame out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
+					skb_queue_tail(&bcs->rqueue, skb);
+				}
+			}
+		}
+		bcs->hw.hscx.rcvidx = 0;
+		bch_sched_event(bcs, B_RCVBUFREADY);
+	}
+  
+	if (istab &0x40) {	// RPF
+		bch_empty_fifo(bcs, B_FIFO_SIZE);
+
+		if (bcs->mode == L1_MODE_TRANS) { // queue every chunk
+			// receive transparent audio data
+			if (!(skb = dev_alloc_skb(B_FIFO_SIZE)))
+				printk(KERN_WARNING "HiSax bch_int(): receive transparent out of memory\n");
+			else {
+				memcpy(skb_put(skb, B_FIFO_SIZE), bcs->hw.hscx.rcvbuf, B_FIFO_SIZE);
+				skb_queue_tail(&bcs->rqueue, skb);
+			}
+			bcs->hw.hscx.rcvidx = 0;
+			bch_sched_event(bcs, B_RCVBUFREADY);
+		}
+	}
+  
+	if (istab &0x20) {	// RFO
+		if (cs->debug &L1_DEB_WARN) 
+      debugl1(cs, "bch_int() B-%d: RFO error", hscx);
+	  cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40);  // RRES
+	}
+
+	if (istab &0x10) {	// XPR
+		if (bcs->tx_skb) {
+			if (bcs->tx_skb->len) {
+		    bch_fill_fifo(bcs);
+        goto afterXPR;
+      }
+      else {
+				if (bcs->st->lli.l1writewakeup &&
+					  (PACKET_NOACK != bcs->tx_skb->pkt_type)) {    
+					bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count);
+        }  
+			  dev_kfree_skb_irq(bcs->tx_skb);
+			  bcs->hw.hscx.count = 0; 
+			  bcs->tx_skb = NULL;
+      }
+    }    
+    if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+      bcs->hw.hscx.count = 0;
+      set_bit(BC_FLG_BUSY, &bcs->Flag);
+      bch_fill_fifo(bcs);
+    } else {
+      clear_bit(BC_FLG_BUSY, &bcs->Flag);
+      bch_sched_event(bcs, B_XMTBUFREADY);
+    }
+  }
+  afterXPR:
+
+	if (istab &0x04) {	// XDU
+    if (bcs->mode == L1_MODE_TRANS) {
+			bch_fill_fifo(bcs);
+    }  
+    else {
+      if (bcs->tx_skb) {  // restart transmitting the whole frame
+        skb_push(bcs->tx_skb, bcs->hw.hscx.count);
+        bcs->tx_cnt += bcs->hw.hscx.count;
+        bcs->hw.hscx.count = 0;
+      }
+	    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01);  // XRES
+      if (cs->debug &L1_DEB_WARN)
+        debugl1(cs, "bch_int() B-%d XDU error", hscx);
+    }
+	}
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void
+bch_mode(struct BCState *bcs, int mode, int bc)
+{
+	struct IsdnCardState *cs = bcs->cs;
+	int hscx = bcs->hw.hscx.hscx;
+
+        bc = bc ? 1 : 0;  // in case bc is greater than 1
+	if (cs->debug & L1_DEB_HSCX)
+		debugl1(cs, "mode_bch() switch B-% mode %d chan %d", hscx, mode, bc);
+	bcs->mode = mode;
+	bcs->channel = bc;
+  
+  // map controller to according timeslot
+  if (!hscx)
+  {
+    cs->writeisac(cs, IPACX_BCHA_TSDP_BC1, 0x80 | bc);
+    cs->writeisac(cs, IPACX_BCHA_CR,       0x88); 
+  }
+  else
+  {
+    cs->writeisac(cs, IPACX_BCHB_TSDP_BC1, 0x80 | bc);
+    cs->writeisac(cs, IPACX_BCHB_CR,       0x88); 
+  }
+
+	switch (mode) {
+		case (L1_MODE_NULL):
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC0);  // rec off
+		    cs->BC_Write_Reg(cs, hscx, IPACX_EXMB,  0x30);  // std adj.
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, 0xFF);  // ints off
+		    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41);  // validate adjustments
+		    break;
+		case (L1_MODE_TRANS):
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0x88);  // ext transp mode
+		    cs->BC_Write_Reg(cs, hscx, IPACX_EXMB,  0x00);  // xxx00000
+		    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41);  // validate adjustments
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
+		    break;
+		case (L1_MODE_HDLC):
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC8);  // transp mode 0
+		    cs->BC_Write_Reg(cs, hscx, IPACX_EXMB,  0x01);  // idle=hdlc flags crc enabled
+		    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41);  // validate adjustments
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
+		    break;
+	}
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void
+bch_close_state(struct BCState *bcs)
+{
+	bch_mode(bcs, 0, bcs->channel);
+	if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+		if (bcs->hw.hscx.rcvbuf) {
+			kfree(bcs->hw.hscx.rcvbuf);
+			bcs->hw.hscx.rcvbuf = NULL;
+		}
+		if (bcs->blog) {
+			kfree(bcs->blog);
+			bcs->blog = NULL;
+		}
+		skb_queue_purge(&bcs->rqueue);
+		skb_queue_purge(&bcs->squeue);
+		if (bcs->tx_skb) {
+			dev_kfree_skb_any(bcs->tx_skb);
+			bcs->tx_skb = NULL;
+			clear_bit(BC_FLG_BUSY, &bcs->Flag);
+		}
+	}
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static int
+bch_open_state(struct IsdnCardState *cs, struct BCState *bcs)
+{
+	if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+		if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+				"HiSax open_bchstate(): No memory for hscx.rcvbuf\n");
+			clear_bit(BC_FLG_INIT, &bcs->Flag);
+			return (1);
+		}
+		if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+				"HiSax open_bchstate: No memory for bcs->blog\n");
+			clear_bit(BC_FLG_INIT, &bcs->Flag);
+			kfree(bcs->hw.hscx.rcvbuf);
+			bcs->hw.hscx.rcvbuf = NULL;
+			return (2);
+		}
+		skb_queue_head_init(&bcs->rqueue);
+		skb_queue_head_init(&bcs->squeue);
+	}
+	bcs->tx_skb = NULL;
+	clear_bit(BC_FLG_BUSY, &bcs->Flag);
+	bcs->event = 0;
+	bcs->hw.hscx.rcvidx = 0;
+	bcs->tx_cnt = 0;
+	return (0);
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static int
+bch_setstack(struct PStack *st, struct BCState *bcs)
+{
+	bcs->channel = st->l1.bc;
+	if (bch_open_state(st->l1.hardware, bcs)) return (-1);
+	st->l1.bcs = bcs;
+	st->l2.l2l1 = bch_l2l1;
+	setstack_manager(st);
+	bcs->st = st;
+	setstack_l1_B(st);
+	return (0);
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void __devinit
+bch_init(struct IsdnCardState *cs, int hscx)
+{
+	cs->bcs[hscx].BC_SetStack   = bch_setstack;
+	cs->bcs[hscx].BC_Close      = bch_close_state;
+	cs->bcs[hscx].hw.hscx.hscx  = hscx;
+	cs->bcs[hscx].cs            = cs;
+	bch_mode(cs->bcs + hscx, 0, hscx);
+}
+
+
+//==========================================================
+// Shared functions
+//==========================================================
+
+//----------------------------------------------------------
+// Main interrupt handler
+//----------------------------------------------------------
+void 
+interrupt_ipacx(struct IsdnCardState *cs)
+{
+	u_char ista;
+  
+	while ((ista = cs->readisac(cs, IPACX_ISTA))) {
+//#################################################  
+//		printk(KERN_WARNING "interrupt_ipacx(ista=%02x)\n", ista);
+//#################################################  
+    if (ista &0x80) bch_int(cs, 0); // B channel interrupts
+    if (ista &0x40) bch_int(cs, 1);
+    
+    if (ista &0x01) dch_int(cs);    // D channel
+    if (ista &0x10) cic_int(cs);    // Layer 1 state
+  }  
+}
+
+//----------------------------------------------------------
+// Clears chip interrupt status
+//----------------------------------------------------------
+static void __init
+clear_pending_ints(struct IsdnCardState *cs)
+{
+	int ista;
+
+  // all interrupts off
+  cs->writeisac(cs, IPACX_MASK, 0xff);
+	cs->writeisac(cs, IPACX_MASKD, 0xff);
+	cs->BC_Write_Reg(cs, 0, IPACX_MASKB, 0xff);
+	cs->BC_Write_Reg(cs, 1, IPACX_MASKB, 0xff);
+  
+  ista = cs->readisac(cs, IPACX_ISTA); 
+  if (ista &0x80) cs->BC_Read_Reg(cs, 0, IPACX_ISTAB);
+  if (ista &0x40) cs->BC_Read_Reg(cs, 1, IPACX_ISTAB);
+  if (ista &0x10) cs->readisac(cs, IPACX_CIR0);
+  if (ista &0x01) cs->readisac(cs, IPACX_ISTAD); 
+}
+
+//----------------------------------------------------------
+// Does chip configuration work
+// Work to do depends on bit mask in part
+//----------------------------------------------------------
+void __init
+init_ipacx(struct IsdnCardState *cs, int part)
+{
+	if (part &1) {  // initialise chip
+//##################################################  
+//	printk(KERN_INFO "init_ipacx(%x)\n", part);
+//##################################################  
+		clear_pending_ints(cs);
+		bch_init(cs, 0);
+		bch_init(cs, 1);
+		dch_init(cs);
+	}
+	if (part &2) {  // reenable all interrupts and start chip
+		cs->BC_Write_Reg(cs, 0, IPACX_MASKB, _MASKB_IMASK);
+		cs->BC_Write_Reg(cs, 1, IPACX_MASKB, _MASKB_IMASK);
+		cs->writeisac(cs, IPACX_MASKD, _MASKD_IMASK);
+		cs->writeisac(cs, IPACX_MASK, _MASK_IMASK); // global mask register
+
+    // reset HDLC Transmitters/receivers
+		cs->writeisac(cs, IPACX_CMDRD, 0x41); 
+    cs->BC_Write_Reg(cs, 0, IPACX_CMDRB, 0x41);
+    cs->BC_Write_Reg(cs, 1, IPACX_CMDRB, 0x41);
+  	ph_command(cs, IPACX_CMD_RES);
+	}
+}
+
+//----------------- end of file -----------------------
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/ipacx.h linux-2.4.20/drivers/isdn/hisax/ipacx.h
--- linux-2.4.19/drivers/isdn/hisax/ipacx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/ipacx.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,161 @@
+/*
+ *
+ * IPACX specific defines
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+/* All Registers original Siemens Spec  */
+
+#ifndef INCLUDE_IPACX_H
+#define INCLUDE_IPACX_H
+
+/* D-channel registers   */
+#define IPACX_RFIFOD        0x00    /* RD       */
+#define IPACX_XFIFOD        0x00    /* WR       */
+#define IPACX_ISTAD         0x20    /* RD       */
+#define IPACX_MASKD         0x20    /* WR       */
+#define IPACX_STARD         0x21    /* RD       */
+#define IPACX_CMDRD         0x21    /* WR       */
+#define IPACX_MODED         0x22    /* RD/WR    */
+#define IPACX_EXMD1         0x23    /* RD/WR    */
+#define IPACX_TIMR1         0x24    /* RD/WR    */
+#define IPACX_SAP1          0x25    /* WR       */
+#define IPACX_SAP2          0x26    /* WR       */
+#define IPACX_RBCLD         0x26    /* RD       */
+#define IPACX_RBCHD         0x27    /* RD       */
+#define IPACX_TEI1          0x27    /* WR       */
+#define IPACX_TEI2          0x28    /* WR       */
+#define IPACX_RSTAD         0x28    /* RD       */
+#define IPACX_TMD           0x29    /* RD/WR    */
+#define IPACX_CIR0          0x2E    /* RD       */
+#define IPACX_CIX0          0x2E    /* WR       */
+#define IPACX_CIR1          0x2F    /* RD       */
+#define IPACX_CIX1          0x2F    /* WR       */
+
+/* Transceiver registers    */
+#define IPACX_TR_CONF0      0x30    /* RD/WR    */
+#define IPACX_TR_CONF1      0x31    /* RD/WR    */
+#define IPACX_TR_CONF2      0x32    /* RD/WR    */
+#define IPACX_TR_STA        0x33    /* RD       */
+#define IPACX_TR_CMD        0x34    /* RD/WR    */
+#define IPACX_SQRR1         0x35    /* RD       */
+#define IPACX_SQXR1         0x35    /* WR       */
+#define IPACX_SQRR2         0x36    /* RD       */
+#define IPACX_SQXR2         0x36    /* WR       */
+#define IPACX_SQRR3         0x37    /* RD       */
+#define IPACX_SQXR3         0x37    /* WR       */
+#define IPACX_ISTATR        0x38    /* RD       */
+#define IPACX_MASKTR        0x39    /* RD/WR    */
+#define IPACX_TR_MODE       0x3A    /* RD/WR    */
+#define IPACX_ACFG1         0x3C    /* RD/WR    */
+#define IPACX_ACFG2         0x3D    /* RD/WR    */
+#define IPACX_AOE           0x3E    /* RD/WR    */
+#define IPACX_ARX           0x3F    /* RD       */
+#define IPACX_ATX           0x3F    /* WR       */
+
+/* IOM: Timeslot, DPS, CDA  */
+#define IPACX_CDA10         0x40    /* RD/WR    */
+#define IPACX_CDA11         0x41    /* RD/WR    */
+#define IPACX_CDA20         0x42    /* RD/WR    */
+#define IPACX_CDA21         0x43    /* RD/WR    */
+#define IPACX_CDA_TSDP10    0x44    /* RD/WR    */
+#define IPACX_CDA_TSDP11    0x45    /* RD/WR    */
+#define IPACX_CDA_TSDP20    0x46    /* RD/WR    */
+#define IPACX_CDA_TSDP21    0x47    /* RD/WR    */
+#define IPACX_BCHA_TSDP_BC1 0x48    /* RD/WR    */
+#define IPACX_BCHA_TSDP_BC2 0x49    /* RD/WR    */
+#define IPACX_BCHB_TSDP_BC1 0x4A    /* RD/WR    */
+#define IPACX_BCHB_TSDP_BC2 0x4B    /* RD/WR    */
+#define IPACX_TR_TSDP_BC1   0x4C    /* RD/WR    */
+#define IPACX_TR_TSDP_BC2   0x4D    /* RD/WR    */
+#define IPACX_CDA1_CR       0x4E    /* RD/WR    */
+#define IPACX_CDA2_CR       0x4F    /* RD/WR    */
+
+/* IOM: Contol, Sync transfer, Monitor    */
+#define IPACX_TR_CR         0x50    /* RD/WR    */
+#define IPACX_TRC_CR        0x50    /* RD/WR    */
+#define IPACX_BCHA_CR       0x51    /* RD/WR    */
+#define IPACX_BCHB_CR       0x52    /* RD/WR    */
+#define IPACX_DCI_CR        0x53    /* RD/WR    */
+#define IPACX_DCIC_CR       0x53    /* RD/WR    */
+#define IPACX_MON_CR        0x54    /* RD/WR    */
+#define IPACX_SDS1_CR       0x55    /* RD/WR    */
+#define IPACX_SDS2_CR       0x56    /* RD/WR    */
+#define IPACX_IOM_CR        0x57    /* RD/WR    */
+#define IPACX_STI           0x58    /* RD       */
+#define IPACX_ASTI          0x58    /* WR       */
+#define IPACX_MSTI          0x59    /* RD/WR    */
+#define IPACX_SDS_CONF      0x5A    /* RD/WR    */
+#define IPACX_MCDA          0x5B    /* RD       */
+#define IPACX_MOR           0x5C    /* RD       */
+#define IPACX_MOX           0x5C    /* WR       */
+#define IPACX_MOSR          0x5D    /* RD       */
+#define IPACX_MOCR          0x5E    /* RD/WR    */
+#define IPACX_MSTA          0x5F    /* RD       */
+#define IPACX_MCONF         0x5F    /* WR       */
+
+/* Interrupt and general registers */
+#define IPACX_ISTA          0x60    /* RD       */
+#define IPACX_MASK          0x60    /* WR       */
+#define IPACX_AUXI          0x61    /* RD       */
+#define IPACX_AUXM          0x61    /* WR       */
+#define IPACX_MODE1         0x62    /* RD/WR    */
+#define IPACX_MODE2         0x63    /* RD/WR    */
+#define IPACX_ID            0x64    /* RD       */
+#define IPACX_SRES          0x64    /* WR       */
+#define IPACX_TIMR2         0x65    /* RD/WR    */
+
+/* B-channel registers */
+#define IPACX_OFF_B1        0x70
+#define IPACX_OFF_B2        0x80
+
+#define IPACX_ISTAB         0x00    /* RD       */
+#define IPACX_MASKB         0x00    /* WR       */
+#define IPACX_STARB         0x01    /* RD       */
+#define IPACX_CMDRB         0x01    /* WR       */
+#define IPACX_MODEB         0x02    /* RD/WR    */
+#define IPACX_EXMB          0x03    /* RD/WR    */
+#define IPACX_RAH1          0x05    /* WR       */
+#define IPACX_RAH2          0x06    /* WR       */
+#define IPACX_RBCLB         0x06    /* RD       */
+#define IPACX_RBCHB         0x07    /* RD       */
+#define IPACX_RAL1          0x07    /* WR       */
+#define IPACX_RAL2          0x08    /* WR       */
+#define IPACX_RSTAB         0x08    /* RD       */
+#define IPACX_TMB           0x09    /* RD/WR    */
+#define IPACX_RFIFOB        0x0A    /*- RD      */
+#define IPACX_XFIFOB        0x0A    /*- WR      */
+
+/* Layer 1 Commands */
+#define IPACX_CMD_TIM    0x0
+#define IPACX_CMD_RES    0x1
+#define IPACX_CMD_SSP    0x2
+#define IPACX_CMD_SCP    0x3
+#define IPACX_CMD_AR8    0x8
+#define IPACX_CMD_AR10   0x9
+#define IPACX_CMD_ARL    0xa
+#define IPACX_CMD_DI     0xf
+
+/* Layer 1 Indications */
+#define IPACX_IND_DR     0x0
+#define IPACX_IND_RES    0x1
+#define IPACX_IND_TMA    0x2
+#define IPACX_IND_SLD    0x3
+#define IPACX_IND_RSY    0x4
+#define IPACX_IND_DR6    0x5
+#define IPACX_IND_PU     0x7
+#define IPACX_IND_AR     0x8
+#define IPACX_IND_ARL    0xa
+#define IPACX_IND_CVR    0xb
+#define IPACX_IND_AI8    0xc
+#define IPACX_IND_AI10   0xd
+#define IPACX_IND_AIL    0xe
+#define IPACX_IND_DC     0xf
+
+extern void init_ipacx(struct IsdnCardState *cs, int part);
+extern void interrupt_ipacx(struct IsdnCardState *cs);
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/isurf.c linux-2.4.20/drivers/isdn/hisax/isurf.c
--- linux-2.4.19/drivers/isdn/hisax/isurf.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/isurf.c	2002-10-29 11:18:31.000000000 +0000
@@ -16,6 +16,7 @@
 #include "isac.h"
 #include "isar.h"
 #include "isdnl1.h"
+#include <linux/isapnp.h>
 
 extern const char *CardType[];
 
@@ -193,6 +194,10 @@
 	return(isar_auxcmd(cs, ic));
 }
 
+#ifdef __ISAPNP__
+static struct pci_bus *pnp_surf __devinitdata = NULL;
+#endif
+
 int __init
 setup_isurf(struct IsdnCard *card)
 {
@@ -210,9 +215,48 @@
 		cs->hw.isurf.phymem = card->para[2];
 		cs->irq = card->para[0];
 	} else {
+#ifdef __ISAPNP__
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		if (isapnp_present()) {
+			cs->subtyp = 0;
+			if ((pb = isapnp_find_card(
+				ISAPNP_VENDOR('S', 'I', 'E'),
+				ISAPNP_FUNCTION(0x0010), pnp_surf))) {
+				pnp_surf = pb;
+				pd = NULL;
+				if (!(pd = isapnp_find_dev(pnp_surf,
+					ISAPNP_VENDOR('S', 'I', 'E'),
+					ISAPNP_FUNCTION(0x0010), pd))) {
+					printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n");
+					return (0);
+				}
+				pd->prepare(pd);
+				pd->deactivate(pd);
+				pd->activate(pd);
+				cs->hw.isurf.reset = pd->resource[0].start;
+				cs->hw.isurf.phymem = pd->resource[1].start;
+				cs->irq = pd->irq_resource[0].start;
+				if (!cs->irq || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) {
+					printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n",
+						cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem);
+					pd->deactivate(pd);
+					return(0);
+				}
+			} else {
+				printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n");
+				return(0);
+			}
+		} else {
+			printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n");
+			return(0);
+		}
+#else
 		printk(KERN_WARNING "HiSax: %s port/mem not set\n",
 			CardType[card->typ]);
 		return (0);
+#endif
 	}
 	if (check_region(cs->hw.isurf.reset, 1)) {
 		printk(KERN_WARNING
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/ix1_micro.c linux-2.4.20/drivers/isdn/hisax/ix1_micro.c
--- linux-2.4.19/drivers/isdn/hisax/ix1_micro.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/ix1_micro.c	2002-10-29 11:18:50.000000000 +0000
@@ -19,6 +19,7 @@
 
 #define __NO_VERSION__
 #include <linux/init.h>
+#include <linux/isapnp.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -218,6 +219,21 @@
 	return(0);
 }
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id itk_ids[] __initdata = {
+	{ ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
+	  ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), 
+	  (unsigned long) "ITK micro 2" },
+	{ ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29),
+	  ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29), 
+	  (unsigned long) "ITK micro 2." },
+	{ 0, }
+};
+
+static struct isapnp_device_id *idev = &itk_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 
 int __init
 setup_ix1micro(struct IsdnCard *card)
@@ -230,6 +246,45 @@
 	if (cs->typ != ISDN_CTYPE_IX1MICROR2)
 		return (0);
 
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		while(idev->card_vendor) {
+			if ((pb = isapnp_find_card(idev->card_vendor,
+				idev->card_device, pnp_c))) {
+				pnp_c = pb;
+				pd = NULL;
+				if ((pd = isapnp_find_dev(pnp_c,
+					idev->vendor, idev->function, pd))) {
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)idev->driver_data);
+					pd->prepare(pd);
+					pd->deactivate(pd);
+					pd->activate(pd);
+					card->para[1] = pd->resource[0].start;
+					card->para[0] = pd->irq_resource[0].start;
+					if (!card->para[0] || !card->para[1]) {
+						printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n",
+						card->para[0], card->para[1]);
+						pd->deactivate(pd);
+						return(0);
+					}
+					break;
+				} else {
+					printk(KERN_ERR "ITK PnP: PnP error card found, no device\n");
+				}
+			}
+			idev++;
+			pnp_c=NULL;
+		} 
+		if (!idev->card_vendor) {
+			printk(KERN_INFO "ITK PnP: no ISAPnP card found\n");
+			return(0);
+		}
+	}
+#endif
 	/* IO-Ports */
 	cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET;
 	cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/md5sums.asc linux-2.4.20/drivers/isdn/hisax/md5sums.asc
--- linux-2.4.19/drivers/isdn/hisax/md5sums.asc	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/md5sums.asc	2002-10-29 11:18:37.000000000 +0000
@@ -4,9 +4,9 @@
 # This are valid md5sums for certificated HiSax driver.
 # The certification is valid only if the md5sums of all files match.
 # The certification is valid only for ELSA Microlink PCI,
-# Eicon Technology Diva 2.01 PCI, Sedlbauer SpeedFax+, 
-# HFC-S PCI A based cards and HFC-S USB based isdn tas 
-# in the moment.
+# Eicon Technology Diva 2.01 PCI, Sedlbauer SpeedFax+,
+# HFC-S PCI A based cards and HFC-S USB based ISDN
+# terminal adapters in the moment.
 # Read ../../../Documentation/isdn/HiSax.cert for more informations.
 # 
 cd4a9917e1147039d5dfc66440d42054  isac.c
@@ -18,16 +18,16 @@
 6abc55c77e0f3149ae9334f3257a1a1a  cert.c
 27bdb2800d4590e00da20eff241edc47  l3dss1.c
 df8bb877b854c4302d396b554e4e84ef  l3_1tr6.c
-3d22d2f2fe9af693eb3b471beecf596d  elsa.c
-fd6aedade5b5bbd73683a3de878b76d2  diva.c
-def8d69efd25186878dc123df73d9319  sedlbauer.c
+9d8b4bed15370063d1b16e47080f50e1  elsa.c
+210f4a3f1eebca70229d786b15cf3e90  diva.c
+4ddf21079dd77e892380f789bae250a7  sedlbauer.c
 8200d818771e3cbdef2a3c3e818d25ac  hfc_pci.c
 # end of md5sums
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.0.6 (GNU/Linux)
 Comment: For info see http://www.gnupg.org
 
-iD8DBQE86l0pDiY0VZsg4ukRAt5eAKCjKt86NE4seQTp88McDaifcz8O8gCguMp3
-56AcQOgPpMtw0OpcYCY+iS8=
-=tfsn
+iD8DBQE9rE91DiY0VZsg4ukRAkKfAJ4xWUfqjc0hW+V+JPue5yr7mrt+RwCdGdSf
+GIKgAEdRLzERmpt/bCCwAbY=
+=FaHw
 -----END PGP SIGNATURE-----
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/netjet.c linux-2.4.20/drivers/isdn/hisax/netjet.c
--- linux-2.4.19/drivers/isdn/hisax/netjet.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/netjet.c	2002-10-29 11:18:33.000000000 +0000
@@ -8,7 +8,9 @@
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
  *
- * Thanks to Traverse Technologie Australia for documents and information
+ * Thanks to Traverse Technologies Australia for documents and information
+ *
+ * 16-Apr-2002 - led code added - Guy Ellis (guy@traverse.com.au)
  *
  */
 
@@ -133,6 +135,7 @@
 mode_tiger(struct BCState *bcs, int mode, int bc)
 {
 	struct IsdnCardState *cs = bcs->cs;
+        u_char led;
 
 	if (cs->debug & L1_DEB_HSCX)
 		debugl1(cs, "Tiger mode %d bchan %d/%d",
@@ -154,6 +157,15 @@
 					cs->hw.njet.dmactrl);
 				byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
 			}
+                        if (cs->typ == ISDN_CTYPE_NETJET_S)
+                        {
+                                // led off
+                                led = bc & 0x01;
+                                led = 0x01 << (6 + led); // convert to mask
+                                led = ~led;
+                                cs->hw.njet.auxd &= led;
+                                byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+                        }
 			break;
 		case (L1_MODE_TRANS):
 			break;
@@ -179,6 +191,14 @@
 			bcs->hw.tiger.sendp = bcs->hw.tiger.send;
 			bcs->hw.tiger.free = NETJET_DMA_TXSIZE;
 			test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag);
+                        if (cs->typ == ISDN_CTYPE_NETJET_S)
+                        {
+                                // led on
+                                led = bc & 0x01;
+                                led = 0x01 << (6 + led); // convert to mask
+                                cs->hw.njet.auxd |= led;
+                                byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+                        }
 			break;
 	}
 	if (cs->debug & L1_DEB_HSCX)
@@ -854,9 +874,13 @@
 		case (PH_ACTIVATE | REQUEST):
 			test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
 			mode_tiger(st->l1.bcs, st->l1.mode, st->l1.bc);
+			/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
+			st->l1.bcs->cs->cardmsg(st->l1.bcs->cs, MDL_BC_ASSIGN, (void *)(&st->l1.bc));
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | REQUEST):
+			/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
+			st->l1.bcs->cs->cardmsg(st->l1.bcs->cs, MDL_BC_RELEASE, (void *)(&st->l1.bc));
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | CONFIRM):
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/niccy.c linux-2.4.20/drivers/isdn/hisax/niccy.c
--- linux-2.4.19/drivers/isdn/hisax/niccy.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/niccy.c	2002-10-29 11:18:38.000000000 +0000
@@ -22,6 +22,7 @@
 #include "hscx.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isapnp.h>
 
 extern const char *CardType[];
 const char *niccy_revision = "$Revision: 1.1.4.1 $";
@@ -238,6 +239,9 @@
 }
 
 static struct pci_dev *niccy_dev __initdata = NULL;
+#ifdef __ISAPNP__
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
 
 int __init
 setup_niccy(struct IsdnCard *card)
@@ -249,7 +253,39 @@
 	printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp));
 	if (cs->typ != ISDN_CTYPE_NICCY)
 		return (0);
-
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		if ((pb = isapnp_find_card(
+			ISAPNP_VENDOR('S', 'D', 'A'),
+			ISAPNP_FUNCTION(0x0150), pnp_c))) {
+			pnp_c = pb;
+			pd = NULL;
+			if (!(pd = isapnp_find_dev(pnp_c,
+				ISAPNP_VENDOR('S', 'D', 'A'),
+				ISAPNP_FUNCTION(0x0150), pd))) {
+				printk(KERN_ERR "NiccyPnP: PnP error card found, no device\n");
+				return (0);
+			}
+			pd->prepare(pd);
+			pd->deactivate(pd);
+			pd->activate(pd);
+			card->para[1] = pd->resource[0].start;
+			card->para[2] = pd->resource[1].start;
+			card->para[0] = pd->irq_resource[0].start;
+			if (!card->para[0] || !card->para[1] || !card->para[2]) {
+				printk(KERN_ERR "NiccyPnP:some resources are missing %ld/%lx/%lx\n",
+					card->para[0], card->para[1], card->para[2]);
+				pd->deactivate(pd);
+				return(0);
+			}
+		} else {
+			printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n");
+		}
+	}
+#endif
 	if (card->para[1]) {
 		cs->hw.niccy.isac = card->para[1] + ISAC_PNP;
 		cs->hw.niccy.hscx = card->para[1] + HSCX_PNP;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/nj_s.c linux-2.4.20/drivers/isdn/hisax/nj_s.c
--- linux-2.4.19/drivers/isdn/hisax/nj_s.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/nj_s.c	2002-10-29 11:18:35.000000000 +0000
@@ -184,6 +184,14 @@
 				printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n");
 				return(0);
 			}
+			/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */
+			if ((dev_netjet->subsystem_vendor == 0x55) &&
+				(dev_netjet->subsystem_device == 0x02)) {
+				printk(KERN_WARNING "Netjet: You tried to load this driver with an incompatible TigerJet-card\n");
+				printk(KERN_WARNING "Use type=41 for Formula-n enter:now ISDN PCI and compatible\n");
+				return(0);
+			}
+			/* end new code */
 		} else {
 			printk(KERN_WARNING "NETjet-S: No PCI card found\n");
 			return(0);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/sedlbauer.c linux-2.4.20/drivers/isdn/hisax/sedlbauer.c
--- linux-2.4.19/drivers/isdn/hisax/sedlbauer.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/sedlbauer.c	2002-10-29 11:18:40.000000000 +0000
@@ -48,6 +48,7 @@
 #include "isar.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isapnp.h>
 
 extern const char *CardType[];
 
@@ -530,6 +531,21 @@
 
 static struct pci_dev *dev_sedl __devinitdata = NULL;
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id sedl_ids[] __initdata = {
+	{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
+	  ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01), 
+	  (unsigned long) "Speed win" },
+	{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02),
+	  ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02), 
+	  (unsigned long) "Speed Fax+" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *pdev = &sedl_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 int __devinit
 setup_sedlbauer(struct IsdnCard *card)
 {
@@ -565,6 +581,57 @@
 			bytecnt = 16;
 		}
 	} else {
+#ifdef __ISAPNP__
+		if (isapnp_present()) {
+			struct pci_bus *pb;
+			struct pci_dev *pd;
+
+			while(pdev->card_vendor) {
+				if ((pb = isapnp_find_card(pdev->card_vendor,
+					pdev->card_device, pnp_c))) {
+					pnp_c = pb;
+					pd = NULL;
+					if ((pd = isapnp_find_dev(pnp_c,
+						pdev->vendor, pdev->function, pd))) {
+						printk(KERN_INFO "HiSax: %s detected\n",
+							(char *)pdev->driver_data);
+						pd->prepare(pd);
+						pd->deactivate(pd);
+						pd->activate(pd);
+						card->para[1] =
+							pd->resource[0].start;
+						card->para[0] =
+							pd->irq_resource[0].start;
+						if (!card->para[0] || !card->para[1]) {
+							printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
+								card->para[0], card->para[1]);
+							pd->deactivate(pd);
+							return(0);
+						}
+						cs->hw.sedl.cfg_reg = card->para[1];
+						cs->irq = card->para[0];
+						if (pdev->function == ISAPNP_FUNCTION(0x2)) {
+							cs->subtyp = SEDL_SPEED_FAX;
+							cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+							bytecnt = 16;
+						} else {
+							cs->subtyp = SEDL_SPEED_CARD_WIN;
+							cs->hw.sedl.chip = SEDL_CHIP_TEST;
+						}
+						goto ready;
+					} else {
+						printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
+						return(0);
+					}
+				}
+				pdev++;
+				pnp_c=NULL;
+			} 
+			if (!pdev->card_vendor) {
+				printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
+			}
+		}
+#endif
 /* Probe for Sedlbauer speed pci */
 #if CONFIG_PCI
 		if (!pci_present()) {
@@ -630,7 +697,7 @@
 		return (0);
 #endif /* CONFIG_PCI */
 	}	
-	
+ready:	
 	/* In case of the sedlbauer pcmcia card, this region is in use,
 	 * reserved for us by the card manager. So we do not check it
 	 * here, it would fail.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/st5481.h linux-2.4.20/drivers/isdn/hisax/st5481.h
--- linux-2.4.19/drivers/isdn/hisax/st5481.h	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/st5481.h	2002-10-29 11:18:49.000000000 +0000
@@ -309,7 +309,7 @@
 typedef void (*ctrl_complete_t)(void *);
 
 typedef struct ctrl_msg {
-	devrequest dr;
+	struct usb_ctrlrequest dr;
 	ctrl_complete_t complete;
 	void *context;
 } ctrl_msg; 
@@ -478,7 +478,7 @@
   if (level & __debug_variable) dump_iso_packet(__FUNCTION__,urb)
 
 static void __attribute__((unused))
-dump_iso_packet(const char *name,urb_t *urb)
+dump_iso_packet(const char *name,struct urb *urb)
 {
 	int i,j;
 	int len,ofs;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/st5481_d.c linux-2.4.20/drivers/isdn/hisax/st5481_d.c
--- linux-2.4.19/drivers/isdn/hisax/st5481_d.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/st5481_d.c	2002-10-29 11:18:40.000000000 +0000
@@ -297,7 +297,7 @@
 	unsigned int num_packets, packet_offset;
 	int len, buf_size, bytes_sent;
 	struct sk_buff *skb;
-	iso_packet_descriptor_t *desc;
+	struct iso_packet_descriptor *desc;
 
 	if (d_out->fsm.state != ST_DOUT_NORMAL)
 		return;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/st5481_usb.c linux-2.4.20/drivers/isdn/hisax/st5481_usb.c
--- linux-2.4.19/drivers/isdn/hisax/st5481_usb.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/st5481_usb.c	2002-10-29 11:18:48.000000000 +0000
@@ -41,9 +41,9 @@
 		(unsigned char *)&ctrl->msg_fifo.data[r_index];
 	
 	DBG(1,"request=0x%02x,value=0x%04x,index=%x",
-	    ((struct ctrl_msg *)urb->setup_packet)->dr.request,
-	    ((struct ctrl_msg *)urb->setup_packet)->dr.value,
-	    ((struct ctrl_msg *)urb->setup_packet)->dr.index);
+	    ((struct ctrl_msg *)urb->setup_packet)->dr.bRequest,
+	    ((struct ctrl_msg *)urb->setup_packet)->dr.wValue,
+	    ((struct ctrl_msg *)urb->setup_packet)->dr.wIndex);
 
 	// Prepare the URB
 	urb->dev = adapter->usb_dev;
@@ -69,11 +69,11 @@
 	}
 	ctrl_msg = &ctrl->msg_fifo.data[w_index]; 
    
-	ctrl_msg->dr.requesttype = requesttype;
-	ctrl_msg->dr.request = request;
-	ctrl_msg->dr.value = cpu_to_le16p(&value);
-	ctrl_msg->dr.index = cpu_to_le16p(&index);
-	ctrl_msg->dr.length = 0;
+	ctrl_msg->dr.bRequestType = requesttype;
+	ctrl_msg->dr.bRequest = request;
+	ctrl_msg->dr.wValue = cpu_to_le16p(&value);
+	ctrl_msg->dr.wIndex = cpu_to_le16p(&index);
+	ctrl_msg->dr.wLength = 0;
 	ctrl_msg->complete = complete;
 	ctrl_msg->context = context;
 
@@ -140,17 +140,17 @@
 
 	ctrl_msg = (struct ctrl_msg *)urb->setup_packet;
 	
-	if (ctrl_msg->dr.request == USB_REQ_CLEAR_FEATURE) {
+	if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) {
 	        /* Special case handling for pipe reset */
-		le16_to_cpus(&ctrl_msg->dr.index);
+		le16_to_cpus(&ctrl_msg->dr.wIndex);
 		usb_endpoint_running(adapter->usb_dev,
-				     ctrl_msg->dr.index & ~USB_DIR_IN, 
-				     (ctrl_msg->dr.index & USB_DIR_IN) == 0);
+				     ctrl_msg->dr.wIndex & ~USB_DIR_IN, 
+				     (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0);
 
 		/* toggle is reset on clear */
 		usb_settoggle(adapter->usb_dev, 
-			      ctrl_msg->dr.index & ~USB_DIR_IN, 
-			      (ctrl_msg->dr.index & USB_DIR_IN) == 0,
+			      ctrl_msg->dr.wIndex & ~USB_DIR_IN, 
+			      (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0,
 			      0);
 
 
@@ -235,7 +235,7 @@
 	struct usb_interface_descriptor *altsetting;
 	struct usb_endpoint_descriptor *endpoint;
 	int status;
-	urb_t *urb;
+	struct urb *urb;
 	u_char *buf;
 	
 	DBG(1,"");
@@ -560,7 +560,8 @@
  */
 int st5481_isoc_flatten(struct urb *urb)
 {
-	piso_packet_descriptor_t pipd,pend;
+	struct iso_packet_descriptor *pipd;
+	struct iso_packet_descriptor *pend;
 	unsigned char *src,*dst;
 	unsigned int len;
 	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/hisax/teles3.c linux-2.4.20/drivers/isdn/hisax/teles3.c
--- linux-2.4.19/drivers/isdn/hisax/teles3.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/hisax/teles3.c	2002-10-29 11:18:40.000000000 +0000
@@ -15,6 +15,7 @@
  */
 #define __NO_VERSION__
 #include <linux/init.h>
+#include <linux/isapnp.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -254,6 +255,24 @@
 	return(0);
 }
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id teles_ids[] __initdata = {
+	{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
+	  ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110), 
+	  (unsigned long) "Teles 16.3 PnP" },
+	{ ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0),
+	  ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0), 
+	  (unsigned long) "Creatix 16.3 PnP" },
+	{ ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002),
+	  ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002), 
+	  (unsigned long) "Compaq ISDN S0" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *tdev = &teles_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 int __devinit
 setup_teles3(struct IsdnCard *card)
 {
@@ -267,6 +286,47 @@
 	    && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA))
 		return (0);
 
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		while(tdev->card_vendor) {
+			if ((pb = isapnp_find_card(tdev->card_vendor,
+				tdev->card_device, pnp_c))) {
+				pnp_c = pb;
+				pd = NULL;
+				if ((pd = isapnp_find_dev(pnp_c,
+					tdev->vendor, tdev->function, pd))) {
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)tdev->driver_data);
+					pd->prepare(pd);
+					pd->deactivate(pd);
+					pd->activate(pd);
+					card->para[3] = pd->resource[2].start;
+					card->para[2] = pd->resource[1].start;
+					card->para[1] = pd->resource[0].start;
+					card->para[0] = pd->irq_resource[0].start;
+					if (!card->para[0] || !card->para[1] || !card->para[2]) {
+						printk(KERN_ERR "Teles PnP:some resources are missing %ld/%lx/%lx\n",
+						card->para[0], card->para[1], card->para[2]);
+						pd->deactivate(pd);
+						return(0);
+					}
+					break;
+				} else {
+					printk(KERN_ERR "Teles PnP: PnP error card found, no device\n");
+				}
+			}
+			tdev++;
+			pnp_c=NULL;
+		} 
+		if (!tdev->card_vendor) {
+			printk(KERN_INFO "Teles PnP: no ISAPnP card found\n");
+			return(0);
+		}
+	}
+#endif
 	if (cs->typ == ISDN_CTYPE_16_3) {
 		cs->hw.teles3.cfg_reg = card->para[1];
 		switch (cs->hw.teles3.cfg_reg) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/isdn_net.c linux-2.4.20/drivers/isdn/isdn_net.c
--- linux-2.4.19/drivers/isdn/isdn_net.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/isdn_net.c	2002-10-29 11:18:40.000000000 +0000
@@ -9,6 +9,14 @@
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
  *
+ * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02 
+ *                                       guy@traverse.com.au
+ * Outgoing calls - looks for a 'V' in first char of dialed number
+ * Incoming calls - checks first character of eaz as follows:
+ *   Numeric - accept DATA only - original functionality
+ *   'V'     - accept VOICE (DOV) only
+ *   'B'     - accept BOTH DATA and DOV types
+ *
  * Jan 2001: fix CISCO HDLC      Bjoern A. Zeeb <i4l@zabbadoz.net>
  *           for info on the protocol, see 
  *           http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
@@ -570,6 +578,7 @@
 	int i;
 	unsigned long flags;
 	isdn_ctrl cmd;
+        u_char *phone_number;
 
 	while (p) {
 		isdn_net_local *lp = p->local;
@@ -668,7 +677,20 @@
 							break;
 						}
 
-					sprintf(cmd.parm.setup.phone, "%s", lp->dial->num);
+					cmd.driver = lp->isdn_device;
+					cmd.command = ISDN_CMD_DIAL;
+					cmd.parm.setup.si2 = 0;
+
+                                        /* check for DOV */
+                                        phone_number = lp->dial->num;
+                                        if ((*phone_number == 'v') ||
+					    (*phone_number == 'V')) { /* DOV call */
+                                                cmd.parm.setup.si1 = 1;
+                                        } else { /* DATA call */
+                                                cmd.parm.setup.si1 = 7;
+					}
+
+					strcpy(cmd.parm.setup.phone, phone_number);
 					/*
 					 * Switch to next number or back to start if at end of list.
 					 */
@@ -688,10 +710,6 @@
 						}
 					}
 					restore_flags(flags);
-					cmd.driver = lp->isdn_device;
-					cmd.command = ISDN_CMD_DIAL;
-					cmd.parm.setup.si1 = 7;
-					cmd.parm.setup.si2 = 0;
 					sprintf(cmd.parm.setup.eazmsn, "%s",
 						isdn_map_eaz2msn(lp->msn, cmd.driver));
 					i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel);
@@ -700,8 +718,9 @@
 						dev->usage[i] |= ISDN_USAGE_OUTGOING;
 						isdn_info_update();
 					}
-					printk(KERN_INFO "%s: dialing %d %s...\n", lp->name,
-					       lp->dialretry, cmd.parm.setup.phone);
+					printk(KERN_INFO "%s: dialing %d %s... %s\n", lp->name,
+					       lp->dialretry, cmd.parm.setup.phone,
+					       (cmd.parm.setup.si1 == 1) ? "DOV" : "");
 					lp->dtimer = 0;
 #ifdef ISDN_DEBUG_NET_DIAL
 					printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device,
@@ -1747,10 +1766,6 @@
 	}
 
 	switch (type) {
-	case CISCO_TYPE_INET:
-		skb->protocol = htons(ETH_P_IP);
-		netif_rx(skb);
-		break;
 	case CISCO_TYPE_SLARP:
 		isdn_net_ciscohdlck_slarp_in(lp, skb);
 		goto out_free;
@@ -1760,11 +1775,11 @@
 				"\"no cdp enable\" on cisco.\n", lp->name);
 		goto out_free;
 	default:
-		printk(KERN_WARNING "%s: Unknown Cisco type 0x%04x\n",
-		       lp->name, type);
-		goto out_free;
+		/* no special cisco protocol */
+		skb->protocol = htons(type);
+		netif_rx(skb);
+		return;
 	}
-	return;
 
  out_free:
 	kfree_skb(skb);
@@ -2145,6 +2160,8 @@
 	isdn_net_phone *n;
 	ulong flags;
 	char nr[32];
+	char *my_eaz;
+
 	/* Search name in netdev-chain */
 	save_flags(flags);
 	cli();
@@ -2163,15 +2180,17 @@
 		eaz = setup->eazmsn;
 	if (dev->net_verbose > 1)
 		printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz);
-	/* Accept only calls with Si1 = 7 (Data-Transmission) */
-	if (si1 != 7) {
-		restore_flags(flags);
-		if (dev->net_verbose > 1)
-			printk(KERN_INFO "isdn_net: Service-Indicator not 7, ignored\n");
-		return 0;
-	}
-	n = (isdn_net_phone *) 0;
-	p = dev->netdev;
+        /* Accept DATA and VOICE calls at this stage
+        local eaz is checked later for allowed call types */
+        if ((si1 != 7) && (si1 != 1)) {
+                restore_flags(flags);
+                if (dev->net_verbose > 1)
+                        printk(KERN_INFO "isdn_net: Service-Indicator not 1 or 7, ignored\n");
+                return 0;
+        }
+
+n = (isdn_net_phone *) 0;
+p = dev->netdev;
 	ematch = wret = swapped = 0;
 #ifdef ISDN_DEBUG_NET_ICALL
 	printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx,
@@ -2191,8 +2210,25 @@
 				break;
 		}
 		swapped = 0;
-		if (!(matchret = isdn_msncmp(eaz, isdn_map_eaz2msn(lp->msn, di))))
-			ematch = 1;
+                /* check acceptable call types for DOV */
+                my_eaz = isdn_map_eaz2msn(lp->msn, di);
+                if (si1 == 1) { /* it's a DOV call, check if we allow it */
+                        if (*my_eaz == 'v' || *my_eaz == 'V' ||
+			    *my_eaz == 'b' || *my_eaz == 'B')
+                                my_eaz++; /* skip to allow a match */
+                        else
+                                my_eaz = 0; /* force non match */
+                } else { /* it's a DATA call, check if we allow it */
+                        if (*my_eaz == 'b' || *my_eaz == 'B')
+                                my_eaz++; /* skip to allow a match */
+                }
+                if (my_eaz)
+                        matchret = isdn_msncmp(eaz, my_eaz);
+                else
+                        matchret = 1;
+                if (!matchret)
+                        ematch = 1;
+
 		/* Remember if more numbers eventually can match */
 		if (matchret > wret)
 			wret = matchret;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/isdn_net.h linux-2.4.20/drivers/isdn/isdn_net.h
--- linux-2.4.19/drivers/isdn/isdn_net.h	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/isdn/isdn_net.h	2002-10-29 11:18:49.000000000 +0000
@@ -26,7 +26,6 @@
 #define CISCO_ADDR_BROADCAST  0x8f
 #define CISCO_CTRL            0x00
 #define CISCO_TYPE_CDP        0x2000
-#define CISCO_TYPE_INET       0x0800
 #define CISCO_TYPE_SLARP      0x8035
 #define CISCO_SLARP_REQUEST   0
 #define CISCO_SLARP_REPLY     1
@@ -107,6 +106,8 @@
 	spin_lock_irqsave(&nd->queue_lock, flags);
 
 	lp = nd->queue;
+//	printk(KERN_DEBUG __FUNCTION__": lp:%s(%p) nlp:%s(%p) last(%p)\n",
+//		lp->name, lp, nlp->name, nlp, lp->last); 
 	nlp->last = lp->last;
 	lp->last->next = nlp;
 	lp->last = nlp;
@@ -126,12 +127,20 @@
 	if (lp->master)
 		master_lp = (isdn_net_local *) lp->master->priv;
 
+//	printk(KERN_DEBUG __FUNCTION__": lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n",
+//		lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue); 
 	spin_lock_irqsave(&master_lp->netdev->queue_lock, flags);
 	lp->last->next = lp->next;
 	lp->next->last = lp->last;
-	if (master_lp->netdev->queue == lp)
+	if (master_lp->netdev->queue == lp) {
 		master_lp->netdev->queue = lp->next;
+		if (lp->next == lp) { /* last in queue */
+			master_lp->netdev->queue = master_lp->netdev->local;
+		}
+	}
 	lp->next = lp->last = lp;	/* (re)set own pointers */
+//	printk(KERN_DEBUG __FUNCTION__": mndq(%p)\n",
+//		master_lp->netdev->queue); 
 	spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/isdn_ppp.c linux-2.4.20/drivers/isdn/isdn_ppp.c
--- linux-2.4.19/drivers/isdn/isdn_ppp.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/isdn/isdn_ppp.c	2002-10-29 11:18:49.000000000 +0000
@@ -107,8 +107,11 @@
 	unsigned long flags;
 	struct ippp_struct *is;
 
-	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS)
+	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": ppp_slot(%d) out of range\n",
+			lp->ppp_slot);
 		return 0;
+	}
 
 	save_flags(flags);
 	cli();
@@ -124,7 +127,12 @@
 	lp->netdev->pb->ref_ct--;
 	spin_unlock(&lp->netdev->pb->lock);
 #endif /* CONFIG_ISDN_MPP */
-
+	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": ppp_slot(%d) now invalid\n",
+			lp->ppp_slot);
+		restore_flags(flags);
+		return 0;
+	}
 	is = ippp_table[lp->ppp_slot];
 	if ((is->state & IPPP_CONNECT))
 		isdn_ppp_closewait(lp->ppp_slot);	/* force wakeup on ippp device */
@@ -220,12 +228,13 @@
 void
 isdn_ppp_wakeup_daemon(isdn_net_local * lp)
 {
-	if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS)
+	if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": ppp_slot(%d) out of range\n",
+			lp->ppp_slot);
 		return;
-
+	}
 	ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
-
-		wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
+	wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
 }
 
 /*
@@ -238,13 +247,14 @@
 {
 	struct ippp_struct *is;
 
-	if (slot < 0 || slot >= ISDN_MAX_CHANNELS)
+	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": slot(%d) out of range\n",
+			slot);
 		return 0;
+	}
 	is = ippp_table[slot];
-
 	if (is->state)
 		wake_up_interruptible(&is->wq);
-
 	is->state = IPPP_CLOSEWAIT;
 	return 1;
 }
@@ -282,8 +292,9 @@
 		return -EBUSY;
 	}
 	is = file->private_data = ippp_table[slot];
-
-		printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state);
+	
+	printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n",
+	       slot, min, is->state);
 
 	/* compression stuff */
 	is->link_compressor   = is->compressor = NULL;
@@ -332,12 +343,20 @@
 		return;
 	is = file->private_data;
 
+	if (!is) {
+		printk(KERN_ERR __FUNCTION__": no file->private_data\n");
+		return;
+	}
 	if (is->debug & 0x1)
 		printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
 
 	if (is->lp) {           /* a lp address says: this link is still up */
 		isdn_net_dev *p = is->lp->netdev;
 
+		if (!p) {
+			printk(KERN_ERR __FUNCTION__": no lp->netdev\n");
+			return;
+		}
 		is->state &= ~IPPP_CONNECT;	/* -> effect: no call of wakeup */
 		/*
 		 * isdn_net_hangup() calls isdn_ppp_free()
@@ -474,7 +493,9 @@
 			if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
 				if (lp) {
 					/* OK .. we are ready to send buffers */
+					is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */
 					netif_wake_queue(&lp->netdev->dev);
+					break;
 				}
 			}
 			is->pppcfg = val;
@@ -629,7 +650,7 @@
 	struct ippp_struct *is;
 
 	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
-		printk(KERN_WARNING "ippp: illegal slot.\n");
+		printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot);
 		return 0;
 	}
 	is = ippp_table[slot];
@@ -906,7 +927,8 @@
 
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot %d\n", lp->ppp_slot);
+		printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n",
+			lp->ppp_slot);
 		kfree_skb(skb);
 		return;
 	}
@@ -959,7 +981,8 @@
 
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot %d\n", lp->ppp_slot);
+		printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n",
+			lp->ppp_slot);
 		goto drop_packet;
 	}
 	is = ippp_table[slot];
@@ -967,7 +990,8 @@
  	if (lp->master) { // FIXME?
  		slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
  		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
- 			printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot %d\n", lp->ppp_slot);
+ 			printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
+ 				lp->ppp_slot);
 			goto drop_packet;
  		}
  	}
@@ -1001,6 +1025,11 @@
 		case PPP_VJC_UNCOMP:
 			if (is->debug & 0x20)
 				printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
+			if (net_dev->local->ppp_slot < 0) {
+				printk(KERN_ERR __FUNCTION__": net_dev->local->ppp_slot(%d) out of range\n",
+					net_dev->local->ppp_slot);
+				goto drop_packet;
+			}
 			if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
 				printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
 				goto drop_packet;
@@ -1022,6 +1051,11 @@
 				}
 				skb_put(skb, skb_old->len + 128);
 				memcpy(skb->data, skb_old->data, skb_old->len);
+				if (net_dev->local->ppp_slot < 0) {
+					printk(KERN_ERR __FUNCTION__": net_dev->local->ppp_slot(%d) out of range\n",
+						net_dev->local->ppp_slot);
+					goto drop_packet;
+				}
 				pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
 						skb->data, skb_old->len);
 				kfree_skb(skb_old);
@@ -1110,7 +1144,8 @@
 
 	slot = mlp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot %d\n", mlp->ppp_slot);
+		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
+			mlp->ppp_slot);
 		kfree_skb(skb);
 		return 0;
 	}
@@ -1145,7 +1180,8 @@
 
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot %d\n", lp->ppp_slot);
+		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
+			lp->ppp_slot);
 		kfree_skb(skb);
 		return 0;
 	}
@@ -1350,8 +1386,15 @@
 
 static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
 {
-	struct ippp_struct * is = ippp_table[lp->ppp_slot];
-   
+	struct ippp_struct * is;
+
+	if (lp->ppp_slot < 0) {
+		printk(KERN_ERR __FUNCTION__": lp->ppp_slot(%d) out of range\n",
+			lp->ppp_slot);
+		return(-EINVAL);
+	}
+
+	is = ippp_table[lp->ppp_slot];
 	if (add_to) {
 		if( lp->netdev->pb )
 			lp->netdev->pb->ref_ct--;
@@ -1397,7 +1440,8 @@
         stats = &mp->stats;
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "isdn_ppp_mp_receive: lp->ppp_slot %d\n", lp->ppp_slot);
+		printk(KERN_ERR __FUNCTION__": lp->ppp_slot(%d)\n",
+			lp->ppp_slot);
 		stats->frame_drops++;
 		dev_kfree_skb(skb);
 		spin_unlock_irqrestore(&mp->lock, flags);
@@ -1433,7 +1477,8 @@
 	for (lpq = net_dev->queue;;) {
 		slot = lpq->ppp_slot;
 		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-			printk(KERN_ERR "isdn_ppp_mp_receive: lpq->ppp_slot %d\n", lpq->ppp_slot);
+			printk(KERN_ERR __FUNCTION__": lpq->ppp_slot(%d)\n",
+				lpq->ppp_slot);
 		} else {
 			u32 lls = ippp_table[slot]->last_link_seqno;
 			if (MP_LT(lls, minseq))
@@ -1665,9 +1710,14 @@
 	struct sk_buff * skb;
 	unsigned int tot_len;
 
+	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": lp->ppp_slot(%d) out of range\n",
+			lp->ppp_slot);
+		return;
+	}
 	if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {
 		if( ippp_table[lp->ppp_slot]->debug & 0x40 )
-			printk(KERN_DEBUG"isdn_mppp: reassembly: frame %d, "
+			printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
 					"len %d\n", MP_SEQ(from), from->len );
 		skb = from;
 		skb_pull(skb, MP_HEADER_LEN);
@@ -2230,7 +2280,7 @@
 				return;
 			}
 			rs->state = CCPResetSentReq;
-			/* We always expect an Ack if the decompressor doesnt
+			/* We always expect an Ack if the decompressor doesn't
 			   know	better */
 			rs->expra = 1;
 			rs->dlen = 0;
@@ -2429,18 +2479,31 @@
 static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
 	 struct sk_buff *skb,int proto)
 {
-	struct ippp_struct *is = ippp_table[lp->ppp_slot];
+	struct ippp_struct *is;
 	struct ippp_struct *mis;
 	int len;
 	struct isdn_ppp_resetparams rsparm;
 	unsigned char rsdata[IPPP_RESET_MAXDATABYTES];	
 
-	printk(KERN_DEBUG "Received CCP frame from peer\n");
+	printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
+		lp->ppp_slot);
+	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": lp->ppp_slot(%d) out of range\n",
+			lp->ppp_slot);
+		return;
+	}
+	is = ippp_table[lp->ppp_slot];
 	isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
 
-	if(lp->master)
-		mis = ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot];
-	else
+	if(lp->master) {
+		int slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+			printk(KERN_ERR __FUNCTION__": slot(%d) out of range\n",
+				slot);
+			return;
+		}	
+		mis = ippp_table[slot];
+	} else
 		mis = is;
 
 	switch(skb->data[0]) {
@@ -2592,13 +2655,18 @@
 
 static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
 {
-	struct ippp_struct *mis,*is = ippp_table[lp->ppp_slot];
-	int proto;
+	struct ippp_struct *mis,*is;
+	int proto, slot = lp->ppp_slot;
 	unsigned char *data;
 
 	if(!skb || skb->len < 3)
 		return;
-
+	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": lp->ppp_slot(%d) out of range\n",
+			slot);
+		return;
+	}	
+	is = ippp_table[slot];
 	/* Daemon may send with or without address and control field comp */
 	data = skb->data;
 	if(!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) {
@@ -2614,12 +2682,17 @@
 	printk(KERN_DEBUG "Received CCP frame from daemon:\n");
 	isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
 
-        if(lp->master)
-                mis = ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot];
-        else
-                mis = is;
-	
-	if(mis != is)
+	if (lp->master) {
+		slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+			printk(KERN_ERR __FUNCTION__": slot(%d) out of range\n",
+				slot);
+			return;
+		}	
+		mis = ippp_table[slot];
+	} else
+		mis = is;
+	if (mis != is)
 		printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");
 	
         switch(data[2]) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/isdn/pcbit/drv.c linux-2.4.20/drivers/isdn/pcbit/drv.c
--- linux-2.4.19/drivers/isdn/pcbit/drv.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.20/drivers/isdn/pcbit/drv.c	2002-10-29 11:18:34.000000000 +0000
@@ -430,7 +430,7 @@
 	switch(dev->l2_state) {
 	case L2_LWMODE:
 		/* check (size <= rdp_size); write buf into board */
-		if (len > BANK4 + 1)
+		if (len < 0 || len > BANK4 + 1)
 		{
 			printk("pcbit_writecmd: invalid length %d\n", len);
 			return -EINVAL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/macintosh/Makefile linux-2.4.20/drivers/macintosh/Makefile
--- linux-2.4.19/drivers/macintosh/Makefile	2002-02-25 19:37:58.000000000 +0000
+++ linux-2.4.20/drivers/macintosh/Makefile	2002-10-29 11:18:36.000000000 +0000
@@ -28,7 +28,9 @@
 
 obj-$(CONFIG_PMAC_PBOOK)	+= mediabay.o
 obj-$(CONFIG_MAC_SERIAL)	+= macserial.o
-obj-$(CONFIG_NVRAM)		+= nvram.o
+ifneq ($(CONFIG_MAC),y)
+  obj-$(CONFIG_NVRAM)		+= nvram.o
+endif
 obj-$(CONFIG_MAC_HID)		+= mac_hid.o
 obj-$(CONFIG_INPUT_ADBHID)	+= adbhid.o
 obj-$(CONFIG_PPC_RTC)		+= rtc.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/macintosh/adb.c linux-2.4.20/drivers/macintosh/adb.c
--- linux-2.4.19/drivers/macintosh/adb.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/macintosh/adb.c	2002-10-29 11:18:40.000000000 +0000
@@ -311,9 +311,11 @@
 #ifdef CONFIG_PMAC_PBOOK
 		pmu_register_sleep_notifier(&adb_sleep_notifier);
 #endif /* CONFIG_PMAC_PBOOK */
+#ifdef CONFIG_PPC
 		if (machine_is_compatible("AAPL,PowerBook1998") ||
 			machine_is_compatible("PowerBook1,1"))
 			sleepy_trackpad = 1;
+#endif /* CONFIG_PPC */
 		init_completion(&adb_probe_task_comp);
 		adbdev_init();
 		adb_reset_bus();
@@ -769,24 +771,24 @@
 
 	/* If a probe is in progress or we are sleeping, wait for it to complete */
 	down(&adb_probe_mutex);
-	up(&adb_probe_mutex);
 
 	/* Special case for ADB_BUSRESET request, all others are sent to
 	   the controller */
 	if ((req->data[0] == ADB_PACKET)&&(count > 1)
 		&&(req->data[1] == ADB_BUSRESET)) {
 		ret = do_adb_reset_bus();
+		up(&adb_probe_mutex);
 		atomic_dec(&state->n_pending);
 		if (ret == 0)
 			ret = count;
 		goto out;
 	} else {	
 		req->reply_expected = ((req->data[1] & 0xc) == 0xc);
-
 		if (adb_controller && adb_controller->send_request)
 			ret = adb_controller->send_request(req, 0);
 		else
 			ret = -ENXIO;
+		up(&adb_probe_mutex);
 	}
 
 	if (ret != 0) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/macintosh/apm_emu.c linux-2.4.20/drivers/macintosh/apm_emu.c
--- linux-2.4.19/drivers/macintosh/apm_emu.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/macintosh/apm_emu.c	2002-10-29 11:18:40.000000000 +0000
@@ -183,7 +183,7 @@
 static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos)
 {
 	struct apm_user *	as;
-	int			i;
+	size_t			i;
 	apm_event_t		event;
 	DECLARE_WAITQUEUE(wait, current);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/macintosh/macio-adb.c linux-2.4.20/drivers/macintosh/macio-adb.c
--- linux-2.4.19/drivers/macintosh/macio-adb.c	2000-09-17 16:48:05.000000000 +0000
+++ linux-2.4.20/drivers/macintosh/macio-adb.c	2002-10-29 11:18:40.000000000 +0000
@@ -7,6 +7,7 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
+#include <linux/spinlock.h>
 #include <asm/prom.h>
 #include <linux/adb.h>
 #include <asm/io.h>
@@ -57,7 +58,7 @@
 
 static volatile struct adb_regs *adb;
 static struct adb_request *current_req, *last_req;
-static unsigned char adb_rbuf[16];
+static spinlock_t macio_lock = SPIN_LOCK_UNLOCKED;
 
 static int macio_probe(void);
 static int macio_init(void);
@@ -66,7 +67,6 @@
 static int macio_adb_autopoll(int devs);
 static void macio_adb_poll(void);
 static int macio_adb_reset_bus(void);
-static void completed(void);
 
 struct adb_driver macio_adb_driver = {
 	"MACIO",
@@ -107,19 +107,19 @@
 	adb = (volatile struct adb_regs *)
 		ioremap(adbs->addrs->address, sizeof(struct adb_regs));
 
-	if (request_irq(adbs->intrs[0].line, macio_adb_interrupt,
-			0, "ADB", (void *)0)) {
-		printk(KERN_ERR "ADB: can't get irq %d\n",
-		       adbs->intrs[0].line);
-		return -EAGAIN;
-	}
-
 	out_8(&adb->ctrl.r, 0);
 	out_8(&adb->intr.r, 0);
 	out_8(&adb->error.r, 0);
 	out_8(&adb->active_hi.r, 0xff); /* for now, set all devices active */
 	out_8(&adb->active_lo.r, 0xff);
 	out_8(&adb->autopoll.r, APE);
+
+	if (request_irq(adbs->intrs[0].line, macio_adb_interrupt,
+			0, "ADB", (void *)0)) {
+		printk(KERN_ERR "ADB: can't get irq %d\n",
+		       adbs->intrs[0].line);
+		return -EAGAIN;
+	}
 	out_8(&adb->intr_enb.r, DFB | TAG);
 
 	printk("adb: mac-io driver 1.0 for unified ADB\n");
@@ -129,16 +129,27 @@
 
 static int macio_adb_autopoll(int devs)
 {
+	unsigned long flags;
+	
+	spin_lock_irqsave(&macio_lock, flags);
 	out_8(&adb->active_hi.r, devs >> 8);
 	out_8(&adb->active_lo.r, devs);
 	out_8(&adb->autopoll.r, devs? APE: 0);
+	spin_unlock_irqrestore(&macio_lock, flags);
 	return 0;
 }
 
 static int macio_adb_reset_bus(void)
 {
+	unsigned long flags;
 	int timeout = 1000000;
 
+	/* Hrm... we may want to not lock interrupts for so
+	 * long ... oh well, who uses that chip anyway ? :)
+	 * That function will be seldomly used during boot
+	 * on rare machines, so...
+	 */
+	spin_lock_irqsave(&macio_lock, flags);
 	out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | ADB_RST);
 	while ((in_8(&adb->ctrl.r) & ADB_RST) != 0) {
 		if (--timeout == 0) {
@@ -146,13 +157,14 @@
 			return -1;
 		}
 	}
+	spin_unlock_irqrestore(&macio_lock, flags);
 	return 0;
 }
 
 /* Send an ADB command */
 static int macio_send_request(struct adb_request *req, int sync)
 {
-	unsigned long mflags;
+	unsigned long flags;
 	int i;
 	
 	if (req->data[0] != ADB_PACKET)
@@ -167,8 +179,7 @@
 	req->complete = 0;
 	req->reply_len = 0;
 
-	save_flags(mflags);
-	cli();
+	spin_lock_irqsave(&macio_lock, flags);
 	if (current_req != 0) {
 		last_req->next = req;
 		last_req = req;
@@ -176,7 +187,7 @@
 		current_req = last_req = req;
 		out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
 	}
-	restore_flags(mflags);
+	spin_unlock_irqrestore(&macio_lock, flags);
 	
 	if (sync) {
 		while (!req->complete)
@@ -190,7 +201,12 @@
 {
 	int i, n, err;
 	struct adb_request *req;
-
+	unsigned char ibuf[16];
+	int ibuf_len = 0;
+	int complete = 0;
+	int autopoll = 0;
+	
+	spin_lock(&macio_lock);
 	if (in_8(&adb->intr.r) & TAG) {
 		if ((req = current_req) != 0) {
 			/* put the current request in */
@@ -202,7 +218,11 @@
 				out_8(&adb->ctrl.r, DTB + CRE);
 			} else {
 				out_8(&adb->ctrl.r, DTB);
-				completed();
+				req->complete = 1;
+				current_req = req->next;
+				complete = 1;
+				if (current_req)
+					out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
 			}
 		}
 		out_8(&adb->intr.r, 0);
@@ -218,39 +238,35 @@
 				for (i = 0; i < req->reply_len; ++i)
 					req->reply[i] = in_8(&adb->data[i].r);
 			}
-			completed();
+			req->complete = 1;
+			current_req = req->next;
+			complete = 1;
+			if (current_req)
+				out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
 		} else if (err == 0) {
 			/* autopoll data */
 			n = in_8(&adb->dcount.r) & HMB;
 			for (i = 0; i < n; ++i)
-				adb_rbuf[i] = in_8(&adb->data[i].r);
-			adb_input(adb_rbuf, n, regs,
-				  in_8(&adb->dcount.r) & APD);
+				ibuf[i] = in_8(&adb->data[i].r);
+			ibuf_len = n;
+			autopoll = (in_8(&adb->dcount.r) & APD) != 0;
 		}
 		out_8(&adb->error.r, 0);
 		out_8(&adb->intr.r, 0);
 	}
-}
-
-static void completed(void)
-{
-	struct adb_request *req = current_req;
-
-	req->complete = 1;
-	current_req = req->next;
-	if (current_req)
-		out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
-	if (req->done)
+	spin_unlock(&macio_lock);
+	if (complete && req && req->done)
 		(*req->done)(req);
+	if (ibuf_len)
+		adb_input(ibuf, ibuf_len, regs, autopoll);
 }
 
 static void macio_adb_poll(void)
 {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	local_irq_save(flags);
 	if (in_8(&adb->intr.r) != 0)
 		macio_adb_interrupt(0, 0, 0);
-	restore_flags(flags);
+	local_irq_restore(flags);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/macintosh/via-cuda.c linux-2.4.20/drivers/macintosh/via-cuda.c
--- linux-2.4.19/drivers/macintosh/via-cuda.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/macintosh/via-cuda.c	2002-10-29 11:18:33.000000000 +0000
@@ -17,6 +17,7 @@
 #include <linux/sched.h>
 #include <linux/adb.h>
 #include <linux/cuda.h>
+#include <linux/spinlock.h>
 #ifdef CONFIG_PPC
 #include <asm/prom.h>
 #include <asm/machdep.h>
@@ -31,6 +32,7 @@
 #include <linux/init.h>
 
 static volatile unsigned char *via;
+static spinlock_t cuda_lock = SPIN_LOCK_UNLOCKED;
 
 #ifdef CONFIG_MAC
 #define CUDA_IRQ IRQ_MAC_ADB
@@ -125,7 +127,7 @@
 #endif /* CONFIG_ADB */
 
 #ifdef CONFIG_PPC
-int
+int __init
 find_via_cuda(void)
 {
     int err;
@@ -186,12 +188,15 @@
 }
 #endif /* CONFIG_PPC */
 
-int via_cuda_start(void)
+int __init
+via_cuda_start(void)
 {
     if (via == NULL)
 	return -ENODEV;
 
+#ifdef CONFIG_PPC
     request_OF_resource(vias, 0, NULL);
+#endif
 
     if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
 	printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ);
@@ -219,7 +224,7 @@
     return 0;
 }
 
-static int
+static int __init
 cuda_init(void)
 {
 #ifdef CONFIG_PPC
@@ -382,8 +387,8 @@
     req->sent = 0;
     req->complete = 0;
     req->reply_len = 0;
-    save_flags(flags); cli();
 
+    spin_lock_irqsave(&cuda_lock, flags);
     if (current_req != 0) {
 	last_req->next = req;
 	last_req = req;
@@ -393,15 +398,14 @@
 	if (cuda_state == idle)
 	    cuda_start();
     }
+    spin_unlock_irqrestore(&cuda_lock, flags);
 
-    restore_flags(flags);
     return 0;
 }
 
 static void
 cuda_start()
 {
-    unsigned long flags;
     struct adb_request *req;
 
     /* assert cuda_state == idle */
@@ -409,41 +413,46 @@
     req = current_req;
     if (req == 0)
 	return;
-    save_flags(flags); cli();
-    if ((via[B] & TREQ) == 0) {
-	restore_flags(flags);
+    if ((via[B] & TREQ) == 0)
 	return;			/* a byte is coming in from the CUDA */
-    }
 
     /* set the shift register to shift out and send a byte */
     via[ACR] |= SR_OUT; eieio();
     via[SR] = req->data[0]; eieio();
     via[B] &= ~TIP;
     cuda_state = sent_first_byte;
-    restore_flags(flags);
 }
 
 void
 cuda_poll()
 {
-    unsigned long flags;
+    if (via[IFR] & SR_INT) {
+	unsigned long flags;
 
-    save_flags(flags);
-    cli();
-    if (via[IFR] & SR_INT)
+	/* cuda_interrupt only takes a normal lock, we disable
+	 * interrupts here to avoid re-entering and thus deadlocking.
+	 * An option would be to disable only the IRQ source with
+	 * disable_irq(), would that work on m68k ? --BenH
+	 */
+	local_irq_save(flags);
 	cuda_interrupt(0, 0, 0);
-    restore_flags(flags);
+	local_irq_restore(flags);
+    }
 }
 
 static void
 cuda_interrupt(int irq, void *arg, struct pt_regs *regs)
 {
     int x, status;
-    struct adb_request *req;
-
+    struct adb_request *req = NULL;
+    unsigned char ibuf[16];
+    int ibuf_len = 0;
+    int complete = 0;
+    
     if ((via[IFR] & SR_INT) == 0)
 	return;
 
+    spin_lock(&cuda_lock);
     status = (~via[B] & (TIP|TREQ)) | (via[ACR] & SR_OUT); eieio();
     /* printk("cuda_interrupt: state=%d status=%x\n", cuda_state, status); */
     switch (cuda_state) {
@@ -498,8 +507,7 @@
 		cuda_state = awaiting_reply;
 	    } else {
 		current_req = req->next;
-		if (req->done)
-		    (*req->done)(req);
+		complete = 1;
 		/* not sure about this */
 		cuda_state = idle;
 		cuda_start();
@@ -542,10 +550,17 @@
 	    }
 	    req->complete = 1;
 	    current_req = req->next;
-	    if (req->done)
-		(*req->done)(req);
+	    complete = 1;
 	} else {
-	    cuda_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs);
+	    /* This is tricky. We must break the spinlock to call
+	     * cuda_input. However, doing so means we might get
+	     * re-entered from another CPU getting an interrupt
+	     * or calling cuda_poll(). I ended up using the stack
+	     * (it's only for 16 bytes) and moving the actual
+	     * call to cuda_input to outside of the lock.
+	     */
+	    ibuf_len = reply_ptr - cuda_rbuf;
+	    memcpy(ibuf, cuda_rbuf, ibuf_len);
 	}
 	if (status == TREQ) {
 	    via[B] &= ~TIP; eieio();
@@ -561,6 +576,11 @@
     default:
 	printk("cuda_interrupt: unknown cuda_state %d?\n", cuda_state);
     }
+    spin_unlock(&cuda_lock);
+    if (complete && req && req->done)
+	(*req->done)(req);
+    if (ibuf_len)
+	cuda_input(ibuf, ibuf_len, regs);
 }
 
 static void
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/macintosh/via-maciisi.c linux-2.4.20/drivers/macintosh/via-maciisi.c
--- linux-2.4.19/drivers/macintosh/via-maciisi.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/macintosh/via-maciisi.c	2002-10-29 11:18:49.000000000 +0000
@@ -230,7 +230,6 @@
 maciisi_send_request(struct adb_request* req, int sync)
 {
 	int i;
-	int count;
 
 #ifdef DEBUG_MACIISI_ADB
 	static int dump_packet = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/macintosh/via-pmu.c linux-2.4.20/drivers/macintosh/via-pmu.c
--- linux-2.4.19/drivers/macintosh/via-pmu.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/macintosh/via-pmu.c	2002-10-29 11:18:37.000000000 +0000
@@ -9,11 +9,7 @@
  * and the RTC (real time clock) chip.
  *
  * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
- * Copyright (C) 2001 Benjamin Herrenschmidt
- * 
- * todo: - Cleanup synchro between VIA interrupt and GPIO-based PMU
- *         interrupt.
- *
+ * Copyright (C) 2001-2002 Benjamin Herrenschmidt
  *
  */
 #include <stdarg.h>
@@ -113,14 +109,24 @@
 	reading_intr,
 } pmu_state;
 
+static volatile enum int_data_state {
+	int_data_empty,
+	int_data_fill,
+	int_data_ready,
+	int_data_flush
+} int_data_state[2] = { int_data_empty, int_data_empty };
+
 static struct adb_request *current_req;
 static struct adb_request *last_req;
 static struct adb_request *req_awaiting_reply;
-static unsigned char interrupt_data[256]; /* Made bigger: I've been told that might happen */
+static unsigned char interrupt_data[2][32];
+static int interrupt_data_len[2];
+static int int_data_last;
 static unsigned char *reply_ptr;
 static int data_index;
 static int data_len;
 static volatile int adb_int_pending;
+static volatile int disable_poll;
 static struct adb_request bright_req_1, bright_req_2, bright_req_3;
 static struct device_node *vias;
 static int pmu_kind = PMU_UNKNOWN;
@@ -176,12 +182,6 @@
 static int pmu_queue_request(struct adb_request *req);
 static void pmu_start(void);
 static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
-static void send_byte(int x);
-static void recv_byte(void);
-static void pmu_sr_intr(struct pt_regs *regs);
-static void pmu_done(struct adb_request *req);
-static void pmu_handle_data(unsigned char *data, int len,
-			    struct pt_regs *regs);
 static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs);
 static int proc_get_info(char *page, char **start, off_t off,
 			  int count, int *eof, void *data);
@@ -219,9 +219,9 @@
 extern void enable_kernel_altivec(void);
 extern void enable_kernel_fp(void);
 
-#ifdef DEBUG_SLEEP
+#if defined(DEBUG_SLEEP) || defined(DEBUG_FREQ)
 int pmu_polled_request(struct adb_request *req);
-int pmu_wink(struct adb_request *req);
+void pmu_blink(int n);
 #endif
 
 #if defined(CONFIG_PMAC_PBOOK) && defined(CONFIG_PM)
@@ -349,6 +349,7 @@
 	if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
 		can_sleep = 1;
 #endif /* CONFIG_PMAC_PBOOK */
+
 	via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);
 
 	out_8(&via[IER], IER_CLR | 0x7f);	/* disable all intrs */
@@ -510,8 +511,8 @@
 
 	/* ack all pending interrupts */
 	timeout = 100000;
-	interrupt_data[0] = 1;
-	while (interrupt_data[0] || pmu_state != idle) {
+	interrupt_data[0][0] = 1;
+	while (interrupt_data[0][0] || pmu_state != idle) {
 		if (--timeout < 0) {
 			printk(KERN_ERR "init_pmu: timed out acking intrs\n");
 			return 0;
@@ -545,6 +546,16 @@
 	return pmu_kind;
 }
 
+static inline void wakeup_decrementer(void)
+{
+	set_dec(tb_ticks_per_jiffy);
+	/* No currently-supported powerbook has a 601,
+	 * so use get_tbl, not native
+	 */
+	last_jiffy_stamp(0) = tb_last_stamp = get_tbl();
+}
+
+
 #ifdef CONFIG_PMAC_PBOOK
 
 /* 
@@ -952,9 +963,10 @@
 	while(*val == ' ')
 		val++;
 #ifdef CONFIG_PMAC_PBOOK
-	if (pmu_kind == PMU_KEYLARGO_BASED && can_sleep)
+	if (pmu_kind == PMU_KEYLARGO_BASED && can_sleep) {
 		if (!strcmp(label, "lid_wakeup"))
 			option_lid_wakeup = ((*val) == '1');
+	}
 #endif /* CONFIG_PMAC_PBOOK */
 	return fcount;
 }
@@ -1165,7 +1177,7 @@
 	return 0;
 }
 
-static void __openfirmware
+static inline void
 wait_for_ack(void)
 {
 	/* Sightly increased the delay, I had one occurence of the message
@@ -1183,7 +1195,7 @@
 
 /* New PMU seems to be very sensitive to those timings, so we make sure
  * PCI is flushed immediately */
-static void __openfirmware
+static inline void
 send_byte(int x)
 {
 	volatile unsigned char *v = via;
@@ -1194,8 +1206,8 @@
 	(void)in_8(&v[B]);
 }
 
-static void __openfirmware
-recv_byte()
+static inline void
+recv_byte(void)
 {
 	volatile unsigned char *v = via;
 
@@ -1205,7 +1217,13 @@
 	(void)in_8(&v[B]);
 }
 
-static volatile int disable_poll;
+static inline void
+pmu_done(struct adb_request *req)
+{
+	req->complete = 1;
+	if (req->done)
+		(*req->done)(req);
+}
 
 static void __openfirmware
 pmu_start()
@@ -1270,9 +1288,9 @@
 	}
 
 	do {
-		spin_unlock(&pmu_lock);
+		spin_unlock_irqrestore(&pmu_lock, flags);
 		via_pmu_interrupt(0, 0, 0);
-		spin_lock(&pmu_lock);
+		spin_lock_irqsave(&pmu_lock, flags);
 		if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) {
 #ifdef SUSPEND_USES_PMU
 			pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0);
@@ -1319,61 +1337,83 @@
 #endif /* SUSPEND_USES_PMU */
 }
 
+/* Interrupt data could be the result data from an ADB cmd */
 static void __openfirmware
-via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
+pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
 {
-	unsigned long flags;
-	int intr;
-	int nloop = 0;
-
-	/* This is a bit brutal, we can probably do better */
-	spin_lock_irqsave(&pmu_lock, flags);
-	++disable_poll;
-		
-	for (;;) {
-		intr = in_8(&via[IFR]) & (SR_INT | CB1_INT);
-		if (intr == 0)
-			break;
-		if (++nloop > 1000) {
-			printk(KERN_DEBUG "PMU: stuck in intr loop, "
-			       "intr=%x, ier=%x pmu_state=%d\n",
-			       intr, in_8(&via[IER]), pmu_state);
-			break;
-		}
-		out_8(&via[IFR], intr);
-		if (intr & SR_INT)
-			pmu_sr_intr(regs);
-		if (intr & CB1_INT)
-			adb_int_pending = 1;
+	asleep = 0;
+	if (drop_interrupts || len < 1) {
+		adb_int_pending = 0;
+		return;
 	}
-
-	if (pmu_state == idle) {
-		if (adb_int_pending) {
-			pmu_state = intack;
-			/* Sounds safer to make sure ACK is high before writing.
-			 * This helped kill a problem with ADB and some iBooks
+	/* Note: for some reason, we get an interrupt with len=1,
+	 * data[0]==0 after each normal ADB interrupt, at least
+	 * on the Pismo. Still investigating...  --BenH
+	 */
+	if (data[0] & PMU_INT_ADB) {
+		if ((data[0] & PMU_INT_ADB_AUTO) == 0) {
+			struct adb_request *req = req_awaiting_reply;
+			if (req == 0) {
+				printk(KERN_ERR "PMU: extra ADB reply\n");
+				return;
+			}
+			req_awaiting_reply = 0;
+			if (len <= 2)
+				req->reply_len = 0;
+			else {
+				memcpy(req->reply, data + 1, len - 1);
+				req->reply_len = len - 1;
+			}
+			pmu_done(req);
+		} else {
+#ifdef CONFIG_XMON
+			if (len == 4 && data[1] == 0x2c) {
+				extern int xmon_wants_key, xmon_adb_keycode;
+				if (xmon_wants_key) {
+					xmon_adb_keycode = data[2];
+					return;
+				}
+			}
+#endif /* CONFIG_XMON */
+#ifdef CONFIG_ADB
+			/*
+			 * XXX On the [23]400 the PMU gives us an up
+			 * event for keycodes 0x74 or 0x75 when the PC
+			 * card eject buttons are released, so we
+			 * ignore those events.
 			 */
-			wait_for_ack();
-			send_byte(PMU_INT_ACK);
-			adb_int_pending = 0;
-		} else if (current_req)
-			pmu_start();
-	}
-	
-	--disable_poll;
-	spin_unlock_irqrestore(&pmu_lock, flags);
-}
-
-static void __openfirmware
-gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
-{
-	if ((in_8(gpio_reg + 0x9) & 0x02) == 0) {
-		adb_int_pending = 1;
-		via_pmu_interrupt(0, 0, 0);
+			if (!(pmu_kind == PMU_OHARE_BASED && len == 4
+			      && data[1] == 0x2c && data[3] == 0xff
+			      && (data[2] & ~1) == 0xf4))
+				adb_input(data+1, len-1, regs, 1);
+#endif /* CONFIG_ADB */		
+		}
+	} else {
+		/* Sound/brightness button pressed */
+		if ((data[0] & PMU_INT_SNDBRT) && len == 3) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+#ifdef CONFIG_INPUT_ADBHID
+			if (!disable_kernel_backlight)
+#endif /* CONFIG_INPUT_ADBHID */
+				set_backlight_level(data[1] >> 4);
+#endif /* CONFIG_PMAC_BACKLIGHT */
+		}
+#ifdef CONFIG_PMAC_PBOOK
+		/* Environement or tick interrupt, query batteries */
+		if (pmu_battery_count && (data[0] & PMU_INT_TICK)) {
+			if ((--query_batt_timer) == 0) {
+				query_battery_state();
+				query_batt_timer = BATTERY_POLLING_COUNT;
+			}
+		} else if (pmu_battery_count && (data[0] & PMU_INT_ENVIRONMENT))
+			query_battery_state();
+ 		if (data[0])
+			pmu_pass_intr(data, len);
+#endif /* CONFIG_PMAC_PBOOK */
 	}
 }
 
-static void __openfirmware
+static struct adb_request* __openfirmware
 pmu_sr_intr(struct pt_regs *regs)
 {
 	struct adb_request *req;
@@ -1382,7 +1422,7 @@
 	if (via[B] & TREQ) {
 		printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]);
 		out_8(&via[IFR], SR_INT);
-		return;
+		return NULL;
 	}
 	/* The ack may not yet be low when we get the interrupt */
 	while ((in_8(&via[B]) & TACK) != 0)
@@ -1415,11 +1455,8 @@
 			current_req = req->next;
 			if (req->reply_expected)
 				req_awaiting_reply = req;
-			else {
-				spin_unlock(&pmu_lock);
-				pmu_done(req);
-				spin_lock(&pmu_lock);
-			}
+			else
+				return req;
 		} else {
 			pmu_state = reading;
 			data_index = 0;
@@ -1432,7 +1469,7 @@
 		data_index = 0;
 		data_len = -1;
 		pmu_state = reading_intr;
-		reply_ptr = interrupt_data;
+		reply_ptr = interrupt_data[int_data_last];
 		recv_byte();
 		break;
 
@@ -1451,108 +1488,113 @@
 		}
 
 		if (pmu_state == reading_intr) {
-			spin_unlock(&pmu_lock);
-			pmu_handle_data(interrupt_data, data_index, regs);
-			spin_lock(&pmu_lock);
+			pmu_state = idle;
+			int_data_state[int_data_last] = int_data_ready;
+			interrupt_data_len[int_data_last] = data_len;
 		} else {
 			req = current_req;
 			current_req = req->next;
 			req->reply_len += data_index;
-			spin_unlock(&pmu_lock);
-			pmu_done(req);
-			spin_lock(&pmu_lock);
+			pmu_state = idle;
+			return req;
 		}
-		pmu_state = idle;
-
 		break;
 
 	default:
 		printk(KERN_ERR "via_pmu_interrupt: unknown state %d?\n",
 		       pmu_state);
 	}
+	return NULL;
 }
 
 static void __openfirmware
-pmu_done(struct adb_request *req)
+via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
 {
-	req->complete = 1;
-	if (req->done)
-		(*req->done)(req);
+	unsigned long flags;
+	int intr;
+	int nloop = 0;
+	int int_data = -1;
+	struct adb_request *req = NULL;
+	
+	/* This is a bit brutal, we can probably do better */
+	spin_lock_irqsave(&pmu_lock, flags);
+	++disable_poll;
+	
+	for (;;) {
+		intr = in_8(&via[IFR]) & (SR_INT | CB1_INT);
+		if (intr == 0)
+			break;
+		if (++nloop > 1000) {
+			printk(KERN_DEBUG "PMU: stuck in intr loop, "
+			       "intr=%x, ier=%x pmu_state=%d\n",
+			       intr, in_8(&via[IER]), pmu_state);
+			break;
+		}
+		out_8(&via[IFR], intr);
+		if (intr & CB1_INT)
+			adb_int_pending = 1;
+		if (intr & SR_INT) {
+			req = pmu_sr_intr(regs);
+			if (req)
+				break;
+		}
+	}
+
+recheck:
+	if (pmu_state == idle) {
+		if (adb_int_pending) {
+			if (int_data_state[0] == int_data_empty)
+				int_data_last = 0;
+			else if (int_data_state[1] == int_data_empty)
+				int_data_last = 1;
+			else
+				goto no_free_slot;
+			pmu_state = intack;
+			int_data_state[int_data_last] = int_data_fill;
+			/* Sounds safer to make sure ACK is high before writing.
+			 * This helped kill a problem with ADB and some iBooks
+			 */
+			wait_for_ack();
+			send_byte(PMU_INT_ACK);
+			adb_int_pending = 0;
+no_free_slot:			
+		} else if (current_req)
+			pmu_start();
+	}
+	/* Mark the oldest buffer for flushing */
+	if (int_data_state[!int_data_last] == int_data_ready) {
+		int_data_state[!int_data_last] = int_data_flush;
+		int_data = !int_data_last;
+	} else if (int_data_state[int_data_last] == int_data_ready) {
+		int_data_state[int_data_last] = int_data_flush;
+		int_data = int_data_last;
+	}
+	--disable_poll;
+	spin_unlock_irqrestore(&pmu_lock, flags);
+
+	/* Deal with completed PMU requests outside of the lock */
+	if (req) {
+		pmu_done(req);
+		req = NULL;
+	}
+		
+	/* Deal with interrupt datas outside of the lock */
+	if (int_data >= 0) {
+		pmu_handle_data(interrupt_data[int_data], interrupt_data_len[int_data], regs);
+		spin_lock_irqsave(&pmu_lock, flags);
+		++disable_poll;
+		int_data_state[int_data] = int_data_empty;
+		int_data = -1;
+		goto recheck;
+	}
 }
 
-/* Interrupt data could be the result data from an ADB cmd */
 static void __openfirmware
-pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
+gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
 {
-	asleep = 0;
-	if (drop_interrupts || len < 1) {
-		adb_int_pending = 0;
-		return;
-	}
-	/* Note: for some reason, we get an interrupt with len=1,
-	 * data[0]==0 after each normal ADB interrupt, at least
-	 * on the Pismo. Still investigating...  --BenH
-	 */
-	if (data[0] & PMU_INT_ADB) {
-		if ((data[0] & PMU_INT_ADB_AUTO) == 0) {
-			struct adb_request *req = req_awaiting_reply;
-			if (req == 0) {
-				printk(KERN_ERR "PMU: extra ADB reply\n");
-				return;
-			}
-			req_awaiting_reply = 0;
-			if (len <= 2)
-				req->reply_len = 0;
-			else {
-				memcpy(req->reply, data + 1, len - 1);
-				req->reply_len = len - 1;
-			}
-			pmu_done(req);
-		} else {
-#ifdef CONFIG_XMON
-			if (len == 4 && data[1] == 0x2c) {
-				extern int xmon_wants_key, xmon_adb_keycode;
-				if (xmon_wants_key) {
-					xmon_adb_keycode = data[2];
-					return;
-				}
-			}
-#endif /* CONFIG_XMON */
-#ifdef CONFIG_ADB
-			/*
-			 * XXX On the [23]400 the PMU gives us an up
-			 * event for keycodes 0x74 or 0x75 when the PC
-			 * card eject buttons are released, so we
-			 * ignore those events.
-			 */
-			if (!(pmu_kind == PMU_OHARE_BASED && len == 4
-			      && data[1] == 0x2c && data[3] == 0xff
-			      && (data[2] & ~1) == 0xf4))
-				adb_input(data+1, len-1, regs, 1);
-#endif /* CONFIG_ADB */		
-		}
-	} else {
-		/* Sound/brightness button pressed */
-		if ((data[0] & PMU_INT_SNDBRT) && len == 3) {
-#ifdef CONFIG_PMAC_BACKLIGHT
-#ifdef CONFIG_INPUT_ADBHID
-			if (!disable_kernel_backlight)
-#endif /* CONFIG_INPUT_ADBHID */
-				set_backlight_level(data[1] >> 4);
-#endif /* CONFIG_PMAC_BACKLIGHT */
-		}
-#ifdef CONFIG_PMAC_PBOOK
-		/* Environement or tick interrupt, query batteries */
-		if (pmu_battery_count && (data[0] & PMU_INT_TICK)) {
-			if ((--query_batt_timer) == 0) {
-				query_battery_state();
-				query_batt_timer = BATTERY_POLLING_COUNT;
-			}
-		} else if (pmu_battery_count && (data[0] & PMU_INT_ENVIRONMENT))
-			query_battery_state();
- 		if (data[0])
-			pmu_pass_intr(data, len);
-#endif /* CONFIG_PMAC_PBOOK */
+	if ((in_8(gpio_reg + 0x9) & 0x02) == 0) {
+		adb_int_pending = 1;
+		via_pmu_interrupt(0, 0, 0);
 	}
 }
 
@@ -1624,7 +1666,7 @@
 {
 	struct adb_request req;
 
-	cli();
+	local_irq_disable();
 
 	drop_interrupts = 1;
 	
@@ -1647,7 +1689,7 @@
 {
 	struct adb_request req;
 
-	cli();
+	local_irq_disable();
 
 	drop_interrupts = 1;
 
@@ -1672,6 +1714,43 @@
 	return via != 0;
 }
 
+#if defined(DEBUG_SLEEP) || defined(DEBUG_FREQ)
+/* N.B. This doesn't work on the 3400 */
+void
+pmu_blink(int n)
+{
+	struct adb_request req;
+
+	memset(&req, 0, sizeof(req));
+
+	for (; n > 0; --n) {
+		req.nbytes = 4;
+		req.done = NULL;
+		req.data[0] = 0xee;
+		req.data[1] = 4;
+		req.data[2] = 0;
+		req.data[3] = 1;
+		req.reply[0] = ADB_RET_OK;
+		req.reply_len = 1;
+		req.reply_expected = 0;
+		pmu_polled_request(&req);
+		mdelay(50);
+		req.nbytes = 4;
+		req.done = NULL;
+		req.data[0] = 0xee;
+		req.data[1] = 4;
+		req.data[2] = 0;
+		req.data[3] = 0;
+		req.reply[0] = ADB_RET_OK;
+		req.reply_len = 1;
+		req.reply_expected = 0;
+		pmu_polled_request(&req);
+		mdelay(50);
+	}
+	mdelay(50);
+}
+#endif /* defined(DEBUG_SLEEP) || defined(DEBUG_FREQ) */
+
 #ifdef CONFIG_PMAC_PBOOK
 
 static LIST_HEAD(sleep_notifiers);
@@ -1887,43 +1966,6 @@
 	}
 }
 
-#ifdef DEBUG_SLEEP
-/* N.B. This doesn't work on the 3400 */
-void
-pmu_blink(int n)
-{
-	struct adb_request req;
-
-	memset(&req, 0, sizeof(req));
-
-	for (; n > 0; --n) {
-		req.nbytes = 4;
-		req.done = NULL;
-		req.data[0] = 0xee;
-		req.data[1] = 4;
-		req.data[2] = 0;
-		req.data[3] = 1;
-		req.reply[0] = ADB_RET_OK;
-		req.reply_len = 1;
-		req.reply_expected = 0;
-		pmu_polled_request(&req);
-		mdelay(50);
-		req.nbytes = 4;
-		req.done = NULL;
-		req.data[0] = 0xee;
-		req.data[1] = 4;
-		req.data[2] = 0;
-		req.data[3] = 0;
-		req.reply[0] = ADB_RET_OK;
-		req.reply_len = 1;
-		req.reply_expected = 0;
-		pmu_polled_request(&req);
-		mdelay(50);
-	}
-	mdelay(50);
-}
-#endif
-
 /*
  * Put the powerbook to sleep.
  */
@@ -1955,15 +1997,6 @@
 	out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
 }
 
-static inline void wakeup_decrementer(void)
-{
-	set_dec(tb_ticks_per_jiffy);
-	/* No currently-supported powerbook has a 601,
-	 * so use get_tbl, not native
-	 */
-	last_jiffy_stamp(0) = tb_last_stamp = get_tbl();
-}
-
 #define	GRACKLE_PM	(1<<7)
 #define GRACKLE_DOZE	(1<<5)
 #define	GRACKLE_NAP	(1<<4)
@@ -1975,7 +2008,7 @@
 	unsigned long wait;
 	unsigned short pmcr1;
 	struct adb_request req;
-	int ret, timeout;
+	int ret;
 	struct pci_dev *grackle;
 
 	grackle = pci_find_slot(0, 0);
@@ -2036,17 +2069,16 @@
 	mb();
 	asm volatile("mtdec %0" : : "r" (0x7fffffff));
 	
-	/* Giveup the FPU */
-	if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0)
-		giveup_fpu(current);
-
 	/* We can now disable MSR_EE */
-	cli();
+	local_irq_disable();
+
+	/* Giveup the FPU */
+	enable_kernel_fp();
 
 	/* For 750, save backside cache setting and disable it */
-	save_l2cr = _get_L2CR();	/* (returns 0 if not 750) */
-	if (save_l2cr)
-		_set_L2CR(0);
+	save_l2cr = _get_L2CR();	/* (returns -1 if not available) */
+	if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
+		_set_L2CR(save_l2cr & 0x7fffffff);
 
 	/* Ask the PMU to put us to sleep */
 	pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
@@ -2077,7 +2109,7 @@
 	restore_via_state();
 	
 	/* Restore L2 cache */
-	if (save_l2cr)
+	if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
  		_set_L2CR(save_l2cr);
 	
 	/* Restore userland MMU context */
@@ -2096,18 +2128,6 @@
 	while (!req.complete)
 		pmu_poll();
 
-	/* ack all pending interrupts */
-	timeout = 100000;
-	interrupt_data[0] = 1;
-	while (interrupt_data[0] || pmu_state != idle) {
-		if (--timeout < 0)
-			break;
-		if (pmu_state == idle)
-			adb_int_pending = 1;
-		via_pmu_interrupt(0, 0, 0);
-		udelay(10);
-	}
-
 	/* reenable interrupt controller */
 	pmac_sleep_restore_intrs();
 
@@ -2116,7 +2136,13 @@
 
 	/* Restart jiffies & scheduling */
 	wakeup_decrementer();
-	sti();
+
+	/* Force a poll of ADB interrupts */
+	adb_int_pending = 1;
+	via_pmu_interrupt(0, 0, 0);
+
+	/* Re-enable local CPU interrupts */
+	local_irq_enable();
 
 	/* Notify drivers */
 	broadcast_wake();
@@ -2127,9 +2153,10 @@
 int __openfirmware powerbook_sleep_Core99(void)
 {
 	unsigned long save_l2cr;
+	unsigned long save_l3cr;
 	unsigned long wait;
 	struct adb_request req;
-	int ret, timeout;
+	int ret;
 	
 	if (!can_sleep) {
 		printk(KERN_ERR "Sleep mode not supported on this machine\n");
@@ -2192,6 +2219,9 @@
 	mb();
 	asm volatile("mtdec %0" : : "r" (0x7fffffff));
 
+	/* We can now disable MSR_EE */
+	local_irq_disable();
+
 	/* Giveup the FPU & vec */
 	enable_kernel_fp();
 
@@ -2200,12 +2230,12 @@
 		enable_kernel_altivec();
 #endif /* CONFIG_ALTIVEC */
 
-	/* We can now disable MSR_EE */
-	cli();
-
-	/* For 750, save backside cache setting and disable it */
-	save_l2cr = _get_L2CR();	/* (returns 0 if not 750) */
-	if (save_l2cr)
+	/* Save & disable L2 and L3 caches*/
+	save_l3cr = _get_L3CR();	/* (returns -1 if not available) */
+	save_l2cr = _get_L2CR();	/* (returns -1 if not available) */
+	if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0)
+		_set_L3CR(save_l3cr & 0x7fffffff);
+	if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
 		_set_L2CR(save_l2cr & 0x7fffffff);
 
 	/* Save the state of PCI config space for some slots */
@@ -2250,11 +2280,15 @@
 	/* Don't restore PCI for now, it crashes. Maybe unnecessary on pbook */
 	//pbook_pci_restore();
 
+#ifdef DEBUG_SLEEP
 	pmu_blink(2);
-		
+#endif		
 	/* Restore L2 cache */
-	if (save_l2cr)
+	if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
  		_set_L2CR(save_l2cr);
+	/* Restore L3 cache */
+	if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0)
+ 		_set_L3CR(save_l3cr);
 	
 	/* Restore userland MMU context */
 	set_context(current->active_mm->context, current->active_mm->pgd);
@@ -2267,18 +2301,6 @@
 	while (!req.complete)
 		pmu_poll();
 		
-	/* ack all pending interrupts */
-	timeout = 100000;
-	interrupt_data[0] = 1;
-	while (interrupt_data[0] || pmu_state != idle) {
-		if (--timeout < 0)
-			break;
-		if (pmu_state == idle)
-			adb_int_pending = 1;
-		via_pmu_interrupt(0, 0, 0);
-		udelay(10);
-	}
-
 	/* reenable interrupt controller */
 	openpic_sleep_restore_intrs();
 
@@ -2287,7 +2309,13 @@
 
 	/* Restart jiffies & scheduling */
 	wakeup_decrementer();
-	sti();
+
+	/* Force a poll of ADB interrupts */
+	adb_int_pending = 1;
+	via_pmu_interrupt(0, 0, 0);
+
+	/* Re-enable local CPU interrupts */
+	local_irq_enable();
 
 	/* Notify drivers */
 	broadcast_wake();
@@ -2411,7 +2439,9 @@
 
 	/* Restart jiffies & scheduling */
 	wakeup_decrementer();
-	sti();
+
+	/* Re-enable local CPU interrupts */
+	local_irq_enable();
 
 	/* Notify drivers */
 	broadcast_wake();
@@ -2686,8 +2716,9 @@
 }
 #endif /* CONFIG_PMAC_PBOOK */
 
-#ifdef DEBUG_SLEEP
-static inline void polled_handshake(volatile unsigned char *via)
+#if defined(DEBUG_SLEEP) || defined(DEBUG_FREQ)
+static inline void __pmac
+polled_handshake(volatile unsigned char *via)
 {
 	via[B] &= ~TREQ; eieio();
 	while ((via[B] & TACK) != 0)
@@ -2697,14 +2728,16 @@
 		;
 }
 
-static inline void polled_send_byte(volatile unsigned char *via, int x)
+static inline void __pmac
+polled_send_byte(volatile unsigned char *via, int x)
 {
 	via[ACR] |= SR_OUT | SR_EXT; eieio();
 	via[SR] = x; eieio();
 	polled_handshake(via);
 }
 
-static inline int polled_recv_byte(volatile unsigned char *via)
+static inline int __pmac
+polled_recv_byte(volatile unsigned char *via)
 {
 	int x;
 
@@ -2715,7 +2748,7 @@
 	return x;
 }
 
-int
+int __pmac
 pmu_polled_request(struct adb_request *req)
 {
 	unsigned long flags;
@@ -2728,7 +2761,7 @@
 	if (l >= 0 && req->nbytes != l + 1)
 		return -EINVAL;
 
-	save_flags(flags); cli();
+	local_irq_save(flags);
 	while (pmu_state != idle)
 		pmu_poll();
 
@@ -2751,10 +2784,11 @@
 	if (req->done)
 		(*req->done)(req);
 
-	restore_flags(flags);
+	local_irq_restore(flags);
 	return 0;
 }
-#endif /* DEBUG_SLEEP */
+#endif /* defined(DEBUG_SLEEP) || defined(DEBUG_FREQ) */
+
 
 EXPORT_SYMBOL(pmu_request);
 EXPORT_SYMBOL(pmu_poll);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/macintosh/via-pmu68k.c linux-2.4.20/drivers/macintosh/via-pmu68k.c
--- linux-2.4.19/drivers/macintosh/via-pmu68k.c	2001-02-09 19:30:23.000000000 +0000
+++ linux-2.4.20/drivers/macintosh/via-pmu68k.c	2002-10-29 11:18:33.000000000 +0000
@@ -120,6 +120,8 @@
 static void pmu_handle_data(unsigned char *data, int len,
 			    struct pt_regs *regs);
 static void set_volume(int level);
+static void pmu_enable_backlight(int on);
+static void pmu_set_brightness(int level);
 
 struct adb_driver via_pmu_driver = {
 	"68K PMU",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/md/lvm-fs.c linux-2.4.20/drivers/md/lvm-fs.c
--- linux-2.4.19/drivers/md/lvm-fs.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/md/lvm-fs.c	2002-10-29 11:18:32.000000000 +0000
@@ -1,9 +1,10 @@
 /*
  * kernel/lvm-fs.c
  *
- * Copyright (C) 2001 Sistina Software
+ * Copyright (C) 2001-2002 Sistina Software
  *
- * January-April 2001
+ * January-May,December 2001
+ * May 2002
  *
  * LVM driver is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -108,6 +109,9 @@
 void lvm_fs_create_vg(vg_t *vg_ptr) {
 	struct proc_dir_entry *pde;
 
+	if (!vg_ptr)
+		return;
+
 	vg_devfs_handle[vg_ptr->vg_number] =
 		devfs_mk_dir(0, vg_ptr->vg_name, NULL);
 
@@ -135,22 +139,24 @@
 void lvm_fs_remove_vg(vg_t *vg_ptr) {
 	int i;
 
+	if (!vg_ptr)
+		return;
+
 	devfs_unregister(ch_devfs_handle[vg_ptr->vg_number]);
 	ch_devfs_handle[vg_ptr->vg_number] = NULL;
 
-	/* remove pv's */
-	for(i = 0; i < vg_ptr->pv_max; i++)
-		if(vg_ptr->pv[i]) lvm_fs_remove_pv(vg_ptr, vg_ptr->pv[i]);
-
 	/* remove lv's */
 	for(i = 0; i < vg_ptr->lv_max; i++)
 		if(vg_ptr->lv[i]) lvm_fs_remove_lv(vg_ptr, vg_ptr->lv[i]);
 
-
 	/* must not remove directory before leaf nodes */
 	devfs_unregister(vg_devfs_handle[vg_ptr->vg_number]);
 	vg_devfs_handle[vg_ptr->vg_number] = NULL;
 
+	/* remove pv's */
+	for(i = 0; i < vg_ptr->pv_max; i++)
+		if(vg_ptr->pv[i]) lvm_fs_remove_pv(vg_ptr, vg_ptr->pv[i]);
+
 	if(vg_ptr->vg_dir_pde) {
 		remove_proc_entry(LVM_LV_SUBDIR, vg_ptr->vg_dir_pde);
 		vg_ptr->lv_subdir_pde = NULL;
@@ -174,7 +180,12 @@
 
 devfs_handle_t lvm_fs_create_lv(vg_t *vg_ptr, lv_t *lv) {
 	struct proc_dir_entry *pde;
-	const char *name = _basename(lv->lv_name);
+	const char *name;
+
+	if (!vg_ptr || !lv)
+		return NULL;
+
+	name = _basename(lv->lv_name);
 
 	lv_devfs_handle[MINOR(lv->lv_dev)] = devfs_register(
 		vg_devfs_handle[vg_ptr->vg_number], name,
@@ -191,6 +202,10 @@
 }
 
 void lvm_fs_remove_lv(vg_t *vg_ptr, lv_t *lv) {
+
+	if (!vg_ptr || !lv)
+		return;
+
 	devfs_unregister(lv_devfs_handle[MINOR(lv->lv_dev)]);
 	lv_devfs_handle[MINOR(lv->lv_dev)] = NULL;
 
@@ -219,6 +234,9 @@
 	struct proc_dir_entry *pde;
 	char name[NAME_LEN];
 
+	if (!vg_ptr || !pv)
+		return;
+
 	if(!vg_ptr->pv_subdir_pde)
 		return;
 
@@ -232,6 +250,9 @@
 void lvm_fs_remove_pv(vg_t *vg_ptr, pv_t *pv) {
 	char name[NAME_LEN];
 
+	if (!vg_ptr || !pv)
+		return;
+
 	if(!vg_ptr->pv_subdir_pde)
 		return;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/md/lvm-internal.h linux-2.4.20/drivers/md/lvm-internal.h
--- linux-2.4.19/drivers/md/lvm-internal.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/md/lvm-internal.h	2002-10-29 11:18:38.000000000 +0000
@@ -49,6 +49,10 @@
 extern vg_t *vg[];
 extern struct file_operations lvm_chr_fops;
 
+#ifndef	uchar
+typedef	unsigned char	uchar;
+#endif
+
 extern struct block_device_operations lvm_blk_dops;
 
 #define lvm_sectsize(dev) get_hardsect_size(dev)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/md/lvm-snap.c linux-2.4.20/drivers/md/lvm-snap.c
--- linux-2.4.19/drivers/md/lvm-snap.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/md/lvm-snap.c	2002-10-29 11:18:49.000000000 +0000
@@ -2,7 +2,7 @@
  * kernel/lvm-snap.c
  *
  * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
- *               2000 - 2001 Heinz Mauelshagen, Sistina Software
+ *               2000 - 2002 Heinz Mauelshagen, Sistina Software
  *
  * LVM snapshot driver is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -41,6 +41,7 @@
  *                 lvm_snapshot_fill_COW_table has a return value too.
  *    15/10/2001 - fix snapshot alignment problem [CM]
  *               - fix snapshot full oops (always check lv_block_exception) [CM]
+ *    26/06/2002 - support for new list_move macro [patch@luckynet.dynu.com]
  *
  */
 
@@ -125,8 +126,12 @@
 			if (i)
 			{
 				/* fun, isn't it? :) */
+#ifdef	list_move
+				list_move(next, hash_table);
+#else
 				list_del(next);
 				list_add(next, hash_table);
+#endif
 			}
 			ret = exception;
 			break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/md/lvm.c linux-2.4.20/drivers/md/lvm.c
--- linux-2.4.19/drivers/md/lvm.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/md/lvm.c	2002-10-29 11:18:32.000000000 +0000
@@ -1,13 +1,14 @@
 /*
  * kernel/lvm.c
  *
- * Copyright (C) 1997 - 2001  Heinz Mauelshagen, Sistina Software
+ * Copyright (C) 1997 - 2002  Heinz Mauelshagen, Sistina Software
  *
  * February-November 1997
  * April-May,July-August,November 1998
  * January-March,May,July,September,October 1999
  * January,February,July,September-November 2000
- * January-April 2001
+ * January-May,June,October 2001
+ * May-July 2002
  *
  *
  * LVM driver is free software; you can redistribute it and/or modify
@@ -214,6 +215,11 @@
  *                 in the LV each time.  [AED]
  *    12/10/2001 - Use add/del_gendisk() routines in 2.4.10+
  *    01/11/2001 - Backport read_ahead change from Linus kernel [AED]
+ *    24/05/2002 - fixed locking bug in lvm_do_le_remap() introduced with 1.0.4
+ *    13/06/2002 - use blk_ioctl() to support various standard block ioctls
+ *               - support HDIO_GETGEO_BIG ioctl
+ *    05/07/2002 - fixed OBO error on vg array access [benh@kernel.crashing.org]
+ *    22/07/2002 - streamlined blk_ioctl() call
  *
  */
 
@@ -277,14 +283,13 @@
 /*
  * External function prototypes
  */
-static int lvm_make_request_fn(request_queue_t *, int,
-			       struct buffer_head *);
+static int lvm_make_request_fn(request_queue_t*, int, struct buffer_head*);
 
 static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong);
 static int lvm_blk_open(struct inode *, struct file *);
 
 static int lvm_blk_close(struct inode *, struct file *);
-static int lvm_get_snapshot_use_rate(lv_t * lv_ptr, void *arg);
+static int lvm_get_snapshot_use_rate(lv_t *lv_ptr, void *arg);
 static int lvm_user_bmap(struct inode *, struct lv_bmap *);
 
 static int lvm_chr_open(struct inode *, struct file *);
@@ -314,13 +319,13 @@
 static int lvm_do_lv_extend_reduce(int, char *, lv_t *);
 static int lvm_do_lv_remove(int, char *, int);
 static int lvm_do_lv_rename(vg_t *, lv_req_t *, lv_t *);
-static int lvm_do_lv_status_byname(vg_t * r, void *);
+static int lvm_do_lv_status_byname(vg_t *r, void *);
 static int lvm_do_lv_status_byindex(vg_t *, void *);
 static int lvm_do_lv_status_bydev(vg_t *, void *);
 
-static int lvm_do_pe_lock_unlock(vg_t * r, void *);
+static int lvm_do_pe_lock_unlock(vg_t *r, void *);
 
-static int lvm_do_pv_change(vg_t *, void *);
+static int lvm_do_pv_change(vg_t*, void*);
 static int lvm_do_pv_status(vg_t *, void *);
 static int lvm_do_pv_flush(void *);
 
@@ -330,15 +335,15 @@
 static int lvm_do_vg_rename(vg_t *, void *);
 static int lvm_do_vg_remove(int);
 static void lvm_geninit(struct gendisk *);
-static void __update_hardsectsize(lv_t * lv);
+static void __update_hardsectsize(lv_t *lv);
 
 
 static void _queue_io(struct buffer_head *bh, int rw);
 static struct buffer_head *_dequeue_io(void);
 static void _flush_io(struct buffer_head *bh);
 
-static int _open_pv(pv_t * pv);
-static void _close_pv(pv_t * pv);
+static int _open_pv(pv_t *pv);
+static void _close_pv(pv_t *pv);
 
 static unsigned long _sectors_to_k(unsigned long sect);
 
@@ -349,22 +354,20 @@
 
 
 /* variables */
-char *lvm_version =
-    "LVM version " LVM_RELEASE_NAME "(" LVM_RELEASE_DATE ")";
+char *lvm_version = "LVM version "LVM_RELEASE_NAME"("LVM_RELEASE_DATE")";
 ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION;
 int loadtime = 0;
 const char *const lvm_name = LVM_NAME;
 
 
 /* volume group descriptor area pointers */
-vg_t *vg[ABS_MAX_VG];
+vg_t *vg[ABS_MAX_VG + 1];
 
 /* map from block minor number to VG and LV numbers */
-typedef struct {
+static struct {
 	int vg_number;
 	int lv_number;
-} vg_lv_map_t;
-static vg_lv_map_t vg_lv_map[ABS_MAX_LV];
+} vg_lv_map[ABS_MAX_LV];
 
 
 /* Request structures (lvm_chr_ioctl()) */
@@ -394,17 +397,19 @@
 
 
 struct file_operations lvm_chr_fops = {
-	open:lvm_chr_open,
-	release:lvm_chr_close,
-	ioctl:lvm_chr_ioctl,
+	owner:		THIS_MODULE,
+	open:		lvm_chr_open,
+	release:	lvm_chr_close,
+	ioctl:		lvm_chr_ioctl,
 };
 
 /* block device operations structure needed for 2.3.38? and above */
-struct block_device_operations lvm_blk_dops = {
-	owner:THIS_MODULE,
-	open:lvm_blk_open,
-	release:lvm_blk_close,
-	ioctl:lvm_blk_ioctl,
+struct block_device_operations lvm_blk_dops =
+{
+	owner:		THIS_MODULE,
+	open:		lvm_blk_open,
+	release:	lvm_blk_close,
+	ioctl:		lvm_blk_ioctl,
 };
 
 
@@ -414,14 +419,15 @@
 static int lvm_hardsectsizes[MAX_LV];
 static int lvm_size[MAX_LV];
 
-static struct gendisk lvm_gendisk = {
-	major:MAJOR_NR,
-	major_name:LVM_NAME,
-	minor_shift:0,
-	max_p:1,
-	part:lvm_hd_struct,
-	sizes:lvm_size,
-	nr_real:MAX_LV,
+static struct gendisk lvm_gendisk =
+{
+	major:		MAJOR_NR,
+	major_name:	LVM_NAME,
+	minor_shift:	0,
+	max_p:		1,
+	part:		lvm_hd_struct,
+	sizes:		lvm_size,
+	nr_real:	MAX_LV,
 };
 
 
@@ -458,8 +464,7 @@
 	lvm_hd_name_ptr = lvm_hd_name;
 #endif
 
-	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR),
-			       lvm_make_request_fn);
+	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn);
 
 
 	/* initialise the pe lock */
@@ -477,7 +482,7 @@
 #endif
 
 	return 0;
-}				/* lvm_init() */
+} /* lvm_init() */
 
 /*
  * cleanup...
@@ -510,12 +515,11 @@
 	lvm_fin_fs();
 
 #ifdef MODULE
-	printk(KERN_INFO "%s -- Module successfully deactivated\n",
-	       lvm_name);
+	printk(KERN_INFO "%s -- Module successfully deactivated\n", lvm_name);
 #endif
 
 	return;
-}				/* lvm_cleanup() */
+}	/* lvm_cleanup() */
 
 /*
  * support function to initialize lvm variables
@@ -534,7 +538,7 @@
 	pe_lock_req.data.pv_offset = 0;
 
 	/* Initialize VG pointers */
-	for (v = 0; v < ABS_MAX_VG; v++)
+	for (v = 0; v < ABS_MAX_VG + 1; v++)
 		vg[v] = NULL;
 
 	/* Initialize LV -> VG association */
@@ -545,7 +549,7 @@
 	}
 
 	return;
-}				/* lvm_init_vars() */
+} /* lvm_init_vars() */
 
 
 /********************************************************************
@@ -568,15 +572,13 @@
 	      minor, VG_CHR(minor), MODE_TO_STR(file->f_mode), lock);
 
 	/* super user validation */
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
+	if (!capable(CAP_SYS_ADMIN)) return -EACCES;
 
 	/* Group special file open */
-	if (VG_CHR(minor) > MAX_VG)
-		return -ENXIO;
+	if (VG_CHR(minor) > MAX_VG) return -ENXIO;
 
 	spin_lock(&lvm_lock);
-	if (lock == current->pid)
+	if(lock == current->pid)
 		_lock_open_count++;
 	spin_unlock(&lvm_lock);
 
@@ -585,7 +587,7 @@
 	MOD_INC_USE_COUNT;
 
 	return 0;
-}				/* lvm_chr_open() */
+} /* lvm_chr_open() */
 
 
 /*
@@ -602,19 +604,16 @@
 	uint extendable, l, v;
 	void *arg = (void *) a;
 	lv_t lv;
-	vg_t *vg_ptr = vg[VG_CHR(minor)];
+	vg_t* vg_ptr = vg[VG_CHR(minor)];
 
 	/* otherwise cc will complain about unused variables */
 	(void) lvm_lock;
 
-	P_IOCTL
-	    ("chr MINOR: %d  command: 0x%X  arg: %p  VG#: %d  mode: %s%s\n",
-	     minor, command, arg, VG_CHR(minor),
-	     MODE_TO_STR(file->f_mode));
+	P_IOCTL("chr MINOR: %d  command: 0x%X  arg: %p  VG#: %d  mode: %s%s\n",
+		minor, command, arg, VG_CHR(minor), MODE_TO_STR(file->f_mode));
 
 #ifdef LVM_TOTAL_RESET
-	if (lvm_reset_spindown > 0)
-		return -EACCES;
+	if (lvm_reset_spindown > 0) return -EACCES;
 #endif
 
 	/* Main command switch */
@@ -626,8 +625,8 @@
 	case LVM_GET_IOP_VERSION:
 		/* check lvm version to ensure driver/tools+lib
 		   interoperability */
-		if (copy_to_user(arg, &lvm_iop_version, sizeof(ushort)) !=
-		    0) return -EFAULT;
+		if (copy_to_user(arg, &lvm_iop_version, sizeof(ushort)) != 0)
+			return -EFAULT;
 		return 0;
 
 #ifdef LVM_TOTAL_RESET
@@ -635,8 +634,7 @@
 		/* lock reset function */
 		lvm_reset_spindown = 1;
 		for (v = 0; v < ABS_MAX_VG; v++) {
-			if (vg[v] != NULL)
-				lvm_do_vg_remove(v);
+			if (vg[v] != NULL) lvm_do_vg_remove(v);
 		}
 
 #ifdef MODULE
@@ -644,28 +642,28 @@
 			MOD_INC_USE_COUNT;
 		while (GET_USE_COUNT(&__this_module) > 1)
 			MOD_DEC_USE_COUNT;
-#endif				/* MODULE */
+#endif /* MODULE */
 		lock = 0;	/* release lock */
 		wake_up_interruptible(&lvm_wait);
 		return 0;
-#endif				/* LVM_TOTAL_RESET */
+#endif /* LVM_TOTAL_RESET */
 
 
 	case LE_REMAP:
 		/* remap a logical extent (after moving the physical extent) */
-		return lvm_do_le_remap(vg_ptr, arg);
+		return lvm_do_le_remap(vg_ptr,arg);
 
 	case PE_LOCK_UNLOCK:
 		/* lock/unlock i/o to a physical extent to move it to another
 		   physical volume (move's done in user space's pvmove) */
-		return lvm_do_pe_lock_unlock(vg_ptr, arg);
+		return lvm_do_pe_lock_unlock(vg_ptr,arg);
 
 	case VG_CREATE_OLD:
 		/* create a VGDA */
 		return lvm_do_vg_create(arg, minor);
 
 	case VG_CREATE:
-		/* create a VGDA, assume VG number is filled in */
+	        /* create a VGDA, assume VG number is filled in */
 		return lvm_do_vg_create(arg, -1);
 
 	case VG_EXTEND:
@@ -687,10 +685,9 @@
 
 	case VG_SET_EXTENDABLE:
 		/* set/clear extendability flag of volume group */
-		if (vg_ptr == NULL)
-			return -ENXIO;
-		if (copy_from_user(&extendable, arg, sizeof(extendable)) !=
-		    0) return -EFAULT;
+		if (vg_ptr == NULL) return -ENXIO;
+		if (copy_from_user(&extendable, arg, sizeof(extendable)) != 0)
+			return -EFAULT;
 
 		if (extendable == VG_EXTENDABLE ||
 		    extendable == ~VG_EXTENDABLE) {
@@ -698,15 +695,13 @@
 				vg_ptr->vg_status |= VG_EXTENDABLE;
 			else
 				vg_ptr->vg_status &= ~VG_EXTENDABLE;
-		} else
-			return -EINVAL;
+		} else return -EINVAL;
 		return 0;
 
 
 	case VG_STATUS:
 		/* get volume group data (only the vg_t struct) */
-		if (vg_ptr == NULL)
-			return -ENXIO;
+		if (vg_ptr == NULL) return -ENXIO;
 		if (copy_to_user(arg, vg_ptr, sizeof(vg_t)) != 0)
 			return -EFAULT;
 		return 0;
@@ -739,25 +734,21 @@
 	case LV_REMOVE:
 	case LV_RENAME:
 		/* create, extend, reduce, remove or rename a logical volume */
-		if (vg_ptr == NULL)
-			return -ENXIO;
+		if (vg_ptr == NULL) return -ENXIO;
 		if (copy_from_user(&lv_req, arg, sizeof(lv_req)) != 0)
 			return -EFAULT;
 
 		if (command != LV_REMOVE) {
-			if (copy_from_user(&lv, lv_req.lv, sizeof(lv_t)) !=
-			    0) return -EFAULT;
+			if (copy_from_user(&lv, lv_req.lv, sizeof(lv_t)) != 0)
+				return -EFAULT;
 		}
 		switch (command) {
 		case LV_CREATE:
-			return lvm_do_lv_create(minor, lv_req.lv_name,
-						&lv);
+			return lvm_do_lv_create(minor, lv_req.lv_name, &lv);
 
 		case LV_EXTEND:
 		case LV_REDUCE:
-			return lvm_do_lv_extend_reduce(minor,
-						       lv_req.lv_name,
-						       &lv);
+			return lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &lv);
 		case LV_REMOVE:
 			return lvm_do_lv_remove(minor, lv_req.lv_name, -1);
 
@@ -785,12 +776,12 @@
 
 	case PV_CHANGE:
 		/* change a physical volume */
-		return lvm_do_pv_change(vg_ptr, arg);
+		return lvm_do_pv_change(vg_ptr,arg);
 
 
 	case PV_STATUS:
 		/* get physical volume data (pv_t structure only) */
-		return lvm_do_pv_status(vg_ptr, arg);
+		return lvm_do_pv_status(vg_ptr,arg);
 
 
 	case PV_FLUSH:
@@ -802,11 +793,11 @@
 		printk(KERN_WARNING
 		       "%s -- lvm_chr_ioctl: unknown command 0x%x\n",
 		       lvm_name, command);
-		return -EINVAL;
+		return -ENOTTY;
 	}
 
 	return 0;
-}				/* lvm_chr_ioctl */
+} /* lvm_chr_ioctl */
 
 
 /*
@@ -824,14 +815,12 @@
 	}
 #endif
 
-	if (lvm_chr_open_count > 0)
-		lvm_chr_open_count--;
+	if (lvm_chr_open_count > 0) lvm_chr_open_count--;
 
 	spin_lock(&lvm_lock);
-	if (lock == current->pid) {
-		if (!_lock_open_count) {
-			P_DEV("chr_close: unlocking LVM for pid %d\n",
-			      lock);
+	if(lock == current->pid) {
+		if(!_lock_open_count) {
+			P_DEV("chr_close: unlocking LVM for pid %d\n", lock);
 			lock = 0;
 			wake_up_interruptible(&lvm_wait);
 		} else
@@ -842,7 +831,7 @@
 	MOD_DEC_USE_COUNT;
 
 	return 0;
-}				/* lvm_chr_close() */
+} /* lvm_chr_close() */
 
 
 
@@ -862,8 +851,7 @@
 	vg_t *vg_ptr = vg[VG_BLK(minor)];
 
 	P_DEV("blk_open MINOR: %d  VG#: %d  LV#: %d  mode: %s%s\n",
-	      minor, VG_BLK(minor), LV_BLK(minor),
-	      MODE_TO_STR(file->f_mode));
+	      minor, VG_BLK(minor), LV_BLK(minor), MODE_TO_STR(file->f_mode));
 
 #ifdef LVM_TOTAL_RESET
 	if (lvm_reset_spindown > 0)
@@ -873,25 +861,26 @@
 	if (vg_ptr != NULL &&
 	    (vg_ptr->vg_status & VG_ACTIVE) &&
 	    (lv_ptr = vg_ptr->lv[LV_BLK(minor)]) != NULL &&
-	    LV_BLK(minor) >= 0 && LV_BLK(minor) < vg_ptr->lv_max) {
+	    LV_BLK(minor) >= 0 &&
+	    LV_BLK(minor) < vg_ptr->lv_max) {
 
 		/* Check parallel LV spindown (LV remove) */
-		if (lv_ptr->lv_status & LV_SPINDOWN)
-			return -EPERM;
+		if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM;
 
 		/* Check inactive LV and open for read/write */
 		/* We need to be able to "read" an inactive LV
 		   to re-activate it again */
 		if ((file->f_mode & FMODE_WRITE) &&
-		    (!(lv_ptr->lv_status & LV_ACTIVE))) return -EPERM;
+		    (!(lv_ptr->lv_status & LV_ACTIVE)))
+		    return -EPERM;
 
 		if (!(lv_ptr->lv_access & LV_WRITE) &&
-		    (file->f_mode & FMODE_WRITE)) return -EACCES;
+		    (file->f_mode & FMODE_WRITE))
+			return -EACCES;
 
 
-		/* be sure to increment VG counter */
-		if (lv_ptr->lv_open == 0)
-			vg_ptr->lv_open++;
+                /* be sure to increment VG counter */
+		if (lv_ptr->lv_open == 0) vg_ptr->lv_open++;
 		lv_ptr->lv_open++;
 
 		MOD_INC_USE_COUNT;
@@ -901,157 +890,161 @@
 		return 0;
 	}
 	return -ENXIO;
-}				/* lvm_blk_open() */
-
+} /* lvm_blk_open() */
 
-/*
- * block device i/o-control routine
- */
-static int lvm_blk_ioctl(struct inode *inode, struct file *file,
-			 uint command, ulong a)
+/* Deliver "hard disk geometry" */
+static int _hdio_getgeo(ulong a, lv_t *lv_ptr, int what)
 {
-	int minor = MINOR(inode->i_rdev);
-	vg_t *vg_ptr = vg[VG_BLK(minor)];
-	lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)];
-	void *arg = (void *) a;
-	struct hd_geometry *hd = (struct hd_geometry *) a;
-
-	P_IOCTL("blk MINOR: %d  command: 0x%X  arg: %p  VG#: %d  LV#: %d  "
-		"mode: %s%s\n", minor, command, arg, VG_BLK(minor),
-		LV_BLK(minor), MODE_TO_STR(file->f_mode));
-
-	switch (command) {
-	case BLKSSZGET:
-		/* get block device sector size as needed e.g. by fdisk */
-		return put_user(lvm_sectsize(inode->i_rdev), (int *) arg);
-
-	case BLKGETSIZE:
-		/* return device size */
-		P_IOCTL("BLKGETSIZE: %u\n", lv_ptr->lv_size);
-		if (put_user(lv_ptr->lv_size, (unsigned long *) arg))
-			return -EFAULT;
-		break;
-
-#ifdef BLKGETSIZE64
-	case BLKGETSIZE64:
-		if (put_user((u64) lv_ptr->lv_size << 9, (u64 *) arg))
-			return -EFAULT;
-		break;
-#endif
-
-	case BLKFLSBUF:
-		/* flush buffer cache */
-		if (!capable(CAP_SYS_ADMIN))
-			return -EACCES;
-
-		P_IOCTL("BLKFLSBUF\n");
-
-		fsync_dev(inode->i_rdev);
-		invalidate_buffers(inode->i_rdev);
-		break;
-
-
-	case BLKRASET:
-		/* set read ahead for block device */
-		if (!capable(CAP_SYS_ADMIN))
-			return -EACCES;
-
-		P_IOCTL("BLKRASET: %ld sectors for %s\n",
-			(long) arg, kdevname(inode->i_rdev));
-
-		if ((long) arg < LVM_MIN_READ_AHEAD ||
-		    (long) arg > LVM_MAX_READ_AHEAD) return -EINVAL;
-		lv_ptr->lv_read_ahead = (long) arg;
-		LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead);
-		read_ahead[MAJOR_NR] = lv_ptr->lv_read_ahead;
-		break;
-
+	int ret = 0;
+	uchar heads = 128;
+	uchar sectors = 128;
+	ulong start = 0;
+	uint cylinders;
+
+	while ( heads * sectors > lv_ptr->lv_size) {
+		heads >>= 1;
+		sectors >>= 1;
+	}
+	cylinders = lv_ptr->lv_size / heads / sectors;
 
-	case BLKRAGET:
-		/* get current read ahead setting */
-		P_IOCTL("BLKRAGET %d\n", lv_ptr->lv_read_ahead);
-		if (put_user(lv_ptr->lv_read_ahead, (long *) arg))
-			return -EFAULT;
-		break;
+	switch (what) {
+		case 0:
+		{
+			struct hd_geometry *hd = (struct hd_geometry *) a;
 
+			if (put_user(heads, &hd->heads) ||
+	    		    put_user(sectors, &hd->sectors) ||
+	    		    put_user((ushort) cylinders, &hd->cylinders) ||
+			    put_user(start, &hd->start))
+				return -EFAULT;
+			break;
+		}
 
-	case HDIO_GETGEO:
-		/* get disk geometry */
-		P_IOCTL("%s -- lvm_blk_ioctl -- HDIO_GETGEO\n", lvm_name);
-		if (hd == NULL)
-			return -EINVAL;
+#ifdef HDIO_GETGEO_BIG
+		case 1:
 		{
-			unsigned char heads = 64;
-			unsigned char sectors = 32;
-			long start = 0;
-			short cylinders =
-			    lv_ptr->lv_size / heads / sectors;
-
-			if (copy_to_user((char *) &hd->heads, &heads,
-					 sizeof(heads)) != 0 ||
-			    copy_to_user((char *) &hd->sectors, &sectors,
-					 sizeof(sectors)) != 0 ||
-			    copy_to_user((short *) &hd->cylinders,
-					 &cylinders,
-					 sizeof(cylinders)) != 0
-			    || copy_to_user((long *) &hd->start, &start,
-					    sizeof(start)) != 0)
-				return -EFAULT;
+			struct hd_big_geometry *hd =
+				(struct hd_big_geometry *) a;
 
-			P_IOCTL("%s -- lvm_blk_ioctl -- cylinders: %d\n",
-				lvm_name, cylinders);
+			if (put_user(heads, &hd->heads) ||
+	    		    put_user(sectors, &hd->sectors) ||
+	    		    put_user(cylinders, &hd->cylinders) ||
+			    put_user(start, &hd->start))
+				return -EFAULT;
+			break;
 		}
-		break;
-
+#endif
 
-	case LV_SET_ACCESS:
-		/* set access flags of a logical volume */
-		if (!capable(CAP_SYS_ADMIN))
-			return -EACCES;
-		lv_ptr->lv_access = (ulong) arg;
-		if (lv_ptr->lv_access & LV_WRITE)
-			set_device_ro(lv_ptr->lv_dev, 0);
-		else
-			set_device_ro(lv_ptr->lv_dev, 1);
-		break;
+	}
 
+	P_IOCTL("%s -- lvm_blk_ioctl -- cylinders: %d\n",
+		lvm_name, cylinders);
+	return ret;
+}
 
-	case LV_SET_STATUS:
-		/* set status flags of a logical volume */
-		if (!capable(CAP_SYS_ADMIN))
-			return -EACCES;
-		if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1)
-			return -EPERM;
-		lv_ptr->lv_status = (ulong) arg;
-		break;
 
-	case LV_BMAP:
-		/* turn logical block into (dev_t, block). non privileged. */
-		/* don't bmap a snapshot, since the mapping can change */
-		if (lv_ptr->lv_access & LV_SNAPSHOT)
-			return -EPERM;
-
-		return lvm_user_bmap(inode, (struct lv_bmap *) arg);
-
-	case LV_SET_ALLOCATION:
-		/* set allocation flags of a logical volume */
-		if (!capable(CAP_SYS_ADMIN))
-			return -EACCES;
-		lv_ptr->lv_allocation = (ulong) arg;
-		break;
+/*
+ * block device i/o-control routine
+ */
+static int lvm_blk_ioctl(struct inode *inode, struct file *file,
+			 uint cmd, ulong a)
+{
+	kdev_t dev = inode->i_rdev;
+	int minor = MINOR(dev), ret;
+	vg_t *vg_ptr = vg[VG_BLK(minor)];
+	lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)];
+	void *arg = (void *) a;
 
-	case LV_SNAPSHOT_USE_RATE:
-		return lvm_get_snapshot_use_rate(lv_ptr, arg);
+	P_IOCTL("blk MINOR: %d  cmd: 0x%X  arg: %p  VG#: %d  LV#: %d  "
+		"mode: %s%s\n", minor, cmd, arg, VG_BLK(minor),
+		LV_BLK(minor), MODE_TO_STR(file->f_mode));
 
-	default:
-		printk(KERN_WARNING
-		       "%s -- lvm_blk_ioctl: unknown command 0x%x\n",
-		       lvm_name, command);
-		return -EINVAL;
+	switch (cmd) {
+		case BLKRASET:
+			/* set read ahead for block device */
+			ret = blk_ioctl(dev, cmd, a);
+			if (ret)
+				return ret;
+			lv_ptr->lv_read_ahead = (long) a;
+			LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead);
+			break;
+	
+		case HDIO_GETGEO:
+#ifdef HDIO_GETGEO_BIG
+		case HDIO_GETGEO_BIG:
+#endif
+			/* get disk geometry */
+			P_IOCTL("%s -- lvm_blk_ioctl -- HDIO_GETGEO\n",
+				lvm_name);
+			if (!a)
+				return -EINVAL;
+
+			switch (cmd) {
+				case HDIO_GETGEO:
+					return _hdio_getgeo(a, lv_ptr, 0);
+#ifdef HDIO_GETGEO_BIG
+				case HDIO_GETGEO_BIG:
+					return _hdio_getgeo(a, lv_ptr, 1);
+#endif
+			}
+	
+		case LV_BMAP:
+			/* turn logical block into (dev_t, block). non privileged. */
+			/* don't bmap a snapshot, since the mapping can change */
+			if (lv_ptr->lv_access & LV_SNAPSHOT)
+				return -EPERM;
+	
+			return lvm_user_bmap(inode, (struct lv_bmap *) arg);
+	
+		case LV_SET_ACCESS:
+			/* set access flags of a logical volume */
+			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+	
+			down_write(&lv_ptr->lv_lock);
+			lv_ptr->lv_access = (ulong) arg;
+			up_write(&lv_ptr->lv_lock);
+	
+			if ( lv_ptr->lv_access & LV_WRITE)
+				set_device_ro(lv_ptr->lv_dev, 0);
+			else
+				set_device_ro(lv_ptr->lv_dev, 1);
+			break;
+	
+	
+		case LV_SET_ALLOCATION:
+			/* set allocation flags of a logical volume */
+			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+			down_write(&lv_ptr->lv_lock);
+			lv_ptr->lv_allocation = (ulong) arg;
+			up_write(&lv_ptr->lv_lock);
+			break;
+	
+		case LV_SET_STATUS:
+			/* set status flags of a logical volume */
+			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+			if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1)
+				return -EPERM;
+			down_write(&lv_ptr->lv_lock);
+			lv_ptr->lv_status = (ulong) arg;
+			up_write(&lv_ptr->lv_lock);
+			break;
+	
+		case LV_SNAPSHOT_USE_RATE:
+			return lvm_get_snapshot_use_rate(lv_ptr, arg);
+	
+		default:
+			/* Handle rest here */
+			ret = blk_ioctl(dev, cmd, a);
+			if (ret)
+				printk(KERN_WARNING
+				       "%s -- lvm_blk_ioctl: unknown "
+				       "cmd 0x%x\n",
+				       lvm_name, cmd);
+			return ret;
 	}
 
 	return 0;
-}				/* lvm_blk_ioctl() */
+} /* lvm_blk_ioctl() */
 
 
 /*
@@ -1066,21 +1059,24 @@
 	P_DEV("blk_close MINOR: %d  VG#: %d  LV#: %d\n",
 	      minor, VG_BLK(minor), LV_BLK(minor));
 
-	if (lv_ptr->lv_open == 1)
-		vg_ptr->lv_open--;
+	if (lv_ptr->lv_open == 1) vg_ptr->lv_open--;
 	lv_ptr->lv_open--;
 
 	MOD_DEC_USE_COUNT;
 
 	return 0;
-}				/* lvm_blk_close() */
+} /* lvm_blk_close() */
 
-static int lvm_get_snapshot_use_rate(lv_t * lv, void *arg)
+static int lvm_get_snapshot_use_rate(lv_t *lv, void *arg)
 {
 	lv_snapshot_use_rate_req_t lv_rate_req;
 
-	if (!(lv->lv_access & LV_SNAPSHOT))
+	down_read(&lv->lv_lock);
+	if (!(lv->lv_access & LV_SNAPSHOT)) {
+		up_read(&lv->lv_lock);
 		return -EPERM;
+	}
+	up_read(&lv->lv_lock);
 
 	if (copy_from_user(&lv_rate_req, arg, sizeof(lv_rate_req)))
 		return -EFAULT;
@@ -1090,10 +1086,17 @@
 
 	switch (lv_rate_req.block) {
 	case 0:
+		down_write(&lv->lv_lock);
 		lv->lv_snapshot_use_rate = lv_rate_req.rate;
+		up_write(&lv->lv_lock);
+		down_read(&lv->lv_lock);
 		if (lv->lv_remap_ptr * 100 / lv->lv_remap_end <
-		    lv->lv_snapshot_use_rate)
-			    interruptible_sleep_on(&lv->lv_snapshot_wait);
+		    lv->lv_snapshot_use_rate) {
+			up_read(&lv->lv_lock);
+			interruptible_sleep_on(&lv->lv_snapshot_wait);
+			down_read(&lv->lv_lock);
+		}
+		up_read(&lv->lv_lock);
 		break;
 
 	case O_NONBLOCK:
@@ -1102,7 +1105,9 @@
 	default:
 		return -EINVAL;
 	}
+	down_read(&lv->lv_lock);
 	lv_rate_req.rate = lv->lv_remap_ptr * 100 / lv->lv_remap_end;
+	up_read(&lv->lv_lock);
 
 	return copy_to_user(arg, &lv_rate_req,
 			    sizeof(lv_rate_req)) ? -EFAULT : 0;
@@ -1117,20 +1122,20 @@
 	if (get_user(block, &user_result->lv_block))
 		return -EFAULT;
 
-	memset(&bh, 0, sizeof bh);
+	memset(&bh,0,sizeof bh);
 	bh.b_blocknr = block;
 	bh.b_dev = bh.b_rdev = inode->i_rdev;
 	bh.b_size = lvm_get_blksize(bh.b_dev);
 	bh.b_rsector = block * (bh.b_size >> 9);
 	bh.b_end_io = NULL;
-	if ((err = lvm_map(&bh, READ)) < 0) {
+	if ((err = lvm_map(&bh, READ)) < 0)  {
 		printk("lvm map failed: %d\n", err);
 		return -EINVAL;
 	}
 
 	return put_user(kdev_t_to_nr(bh.b_rdev), &user_result->lv_dev) ||
-	    put_user(bh.b_rsector / (bh.b_size >> 9),
-		     &user_result->lv_block) ? -EFAULT : 0;
+	       put_user(bh.b_rsector/(bh.b_size>>9), &user_result->lv_block) ?
+		-EFAULT : 0;
 }
 
 
@@ -1139,8 +1144,7 @@
  * (see init_module/lvm_init)
  */
 static void __remap_snapshot(kdev_t rdev, ulong rsector,
-			     ulong pe_start, lv_t * lv, vg_t * vg)
-{
+				    ulong pe_start, lv_t *lv, vg_t *vg) {
 
 	/* copy a chunk from the origin to a snapshot device */
 	down_write(&lv->lv_lock);
@@ -1155,8 +1159,7 @@
 }
 
 static inline void _remap_snapshot(kdev_t rdev, ulong rsector,
-				   ulong pe_start, lv_t * lv, vg_t * vg)
-{
+				   ulong pe_start, lv_t *lv, vg_t *vg) {
 	int r;
 
 	/* check to see if this chunk is already in the snapshot */
@@ -1173,8 +1176,7 @@
 /*
  * extents destined for a pe that is on the move should be deferred
  */
-static inline int _should_defer(kdev_t pv, ulong sector, uint32_t pe_size)
-{
+static inline int _should_defer(kdev_t pv, ulong sector, uint32_t pe_size) {
 	return ((pe_lock_req.lock == LOCK_PE) &&
 		(pv == pe_lock_req.data.pv_dev) &&
 		(sector >= pe_lock_req.data.pv_offset) &&
@@ -1221,32 +1223,34 @@
 		goto bad;
 	}
 
-	if ((rw == WRITE || rw == WRITEA) && !(lv->lv_access & LV_WRITE)) {
+	if ((rw == WRITE || rw == WRITEA) &&
+	    !(lv->lv_access & LV_WRITE)) {
 		printk(KERN_CRIT
 		       "%s - lvm_map: ll_rw_blk write for readonly LV %s\n",
 		       lvm_name, lv->lv_name);
 		goto bad;
 	}
 
-	P_MAP
-	    ("%s - lvm_map minor: %d  *rdev: %s  *rsector: %lu  size:%lu\n",
-	     lvm_name, minor, kdevname(bh->b_rdev), rsector_org, size);
+	P_MAP("%s - lvm_map minor: %d  *rdev: %s  *rsector: %lu  size:%lu\n",
+	      lvm_name, minor,
+	      kdevname(bh->b_rdev),
+	      rsector_org, size);
 
 	if (rsector_org + size > lv->lv_size) {
 		printk(KERN_ALERT
 		       "%s - lvm_map access beyond end of device; *rsector: "
-		       "%lu or size: %lu wrong for minor: %2d\n",
-		       lvm_name, rsector_org, size, minor);
+                       "%lu or size: %lu wrong for minor: %2d\n",
+                       lvm_name, rsector_org, size, minor);
 		goto bad;
 	}
 
 
-	if (lv->lv_stripes < 2) {	/* linear mapping */
+	if (lv->lv_stripes < 2) { /* linear mapping */
 		/* get the index */
 		index = rsector_org / vg_this->pe_size;
 		pe_start = lv->lv_current_pe[index].pe;
 		rsector_map = lv->lv_current_pe[index].pe +
-		    (rsector_org % vg_this->pe_size);
+			(rsector_org % vg_this->pe_size);
 		rdev_map = lv->lv_current_pe[index].dev;
 
 		P_MAP("lv_current_pe[%ld].pe: %d  rdev: %s  rsector:%ld\n",
@@ -1259,23 +1263,22 @@
 
 		stripe_length = vg_this->pe_size * lv->lv_stripes;
 		stripe_index = (rsector_org % stripe_length) /
-		    lv->lv_stripesize;
+			lv->lv_stripesize;
 		index = rsector_org / stripe_length +
-		    (stripe_index % lv->lv_stripes) *
-		    (lv->lv_allocated_le / lv->lv_stripes);
+			(stripe_index % lv->lv_stripes) *
+			(lv->lv_allocated_le / lv->lv_stripes);
 		pe_start = lv->lv_current_pe[index].pe;
 		rsector_map = lv->lv_current_pe[index].pe +
-		    (rsector_org % stripe_length) -
-		    (stripe_index % lv->lv_stripes) * lv->lv_stripesize -
-		    stripe_index / lv->lv_stripes *
-		    (lv->lv_stripes - 1) * lv->lv_stripesize;
+			(rsector_org % stripe_length) -
+			(stripe_index % lv->lv_stripes) * lv->lv_stripesize -
+			stripe_index / lv->lv_stripes *
+			(lv->lv_stripes - 1) * lv->lv_stripesize;
 		rdev_map = lv->lv_current_pe[index].dev;
 
 		P_MAP("lv_current_pe[%ld].pe: %d  rdev: %s  rsector:%ld\n"
 		      "stripe_length: %ld  stripe_index: %ld\n",
-		      index, lv->lv_current_pe[index].pe,
-		      kdevname(rdev_map), rsector_map, stripe_length,
-		      stripe_index);
+		      index, lv->lv_current_pe[index].pe, kdevname(rdev_map),
+		      rsector_map, stripe_length, stripe_index);
 	}
 
 	/*
@@ -1284,8 +1287,8 @@
 	 * we need to queue this request, because this is in the fast path.
 	 */
 	if (rw == WRITE || rw == WRITEA) {
-		if (_defer_extent(bh, rw, rdev_map,
-				  rsector_map, vg_this->pe_size)) {
+		if(_defer_extent(bh, rw, rdev_map,
+				 rsector_map, vg_this->pe_size)) {
 
 			up_read(&lv->lv_lock);
 			return 0;
@@ -1296,14 +1299,15 @@
 		lv->lv_current_pe[index].reads++;	/* statistic */
 
 	/* snapshot volume exception handling on physical device address base */
-	if (!(lv->lv_access & (LV_SNAPSHOT | LV_SNAPSHOT_ORG)))
+	if (!(lv->lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG)))
 		goto out;
 
-	if (lv->lv_access & LV_SNAPSHOT) {	/* remap snapshot */
-		if (lvm_snapshot_remap_block
-		    (&rdev_map, &rsector_map, pe_start, lv) < 0)
-				goto bad;
-	} else if (rw == WRITE || rw == WRITEA) {	/* snapshot origin */
+	if (lv->lv_access & LV_SNAPSHOT) { /* remap snapshot */
+		if (lvm_snapshot_remap_block(&rdev_map, &rsector_map,
+					     pe_start, lv) < 0)
+			goto bad;
+
+	} else if (rw == WRITE || rw == WRITEA) { /* snapshot origin */
 		lv_t *snap;
 
 		/* start with first snapshot and loop through all of
@@ -1317,21 +1321,22 @@
 			/* Serializes the COW with the accesses to the
 			   snapshot device */
 			_remap_snapshot(rdev_map, rsector_map,
-					pe_start, snap, vg_this);
+					 pe_start, snap, vg_this);
 		}
 	}
 
-      out:
+ out:
 	bh->b_rdev = rdev_map;
 	bh->b_rsector = rsector_map;
 	up_read(&lv->lv_lock);
 	return 1;
 
-      bad:
-	if (bh->b_end_io) buffer_IO_error(bh);
+ bad:
+	if (bh->b_end_io)
+	buffer_IO_error(bh);
 	up_read(&lv->lv_lock);
 	return -1;
-}				/* lvm_map() */
+} /* lvm_map() */
 
 
 /*
@@ -1363,8 +1368,9 @@
 /*
  * make request function
  */
-static int lvm_make_request_fn(request_queue_t * q,
-			       int rw, struct buffer_head *bh)
+static int lvm_make_request_fn(request_queue_t *q,
+			       int rw,
+			       struct buffer_head *bh)
 {
 	return (lvm_map(bh, rw) <= 0) ? 0 : 1;
 }
@@ -1380,7 +1386,7 @@
  */
 static int lvm_do_lock_lvm(void)
 {
-      lock_try_again:
+lock_try_again:
 	spin_lock(&lvm_lock);
 	if (lock != 0 && lock != current->pid) {
 		P_DEV("lvm_do_lock_lvm: locked by pid %d ...\n", lock);
@@ -1398,20 +1404,19 @@
 	P_DEV("lvm_do_lock_lvm: locking LVM for pid %d\n", lock);
 	spin_unlock(&lvm_lock);
 	return 0;
-}				/* lvm_do_lock_lvm */
+} /* lvm_do_lock_lvm */
 
 
 /*
  * character device support function lock/unlock physical extend
  */
-static int lvm_do_pe_lock_unlock(vg_t * vg_ptr, void *arg)
+static int lvm_do_pe_lock_unlock(vg_t *vg_ptr, void *arg)
 {
 	pe_lock_req_t new_lock;
 	struct buffer_head *bh;
 	uint p;
 
-	if (vg_ptr == NULL)
-		return -ENXIO;
+	if (vg_ptr == NULL) return -ENXIO;
 	if (copy_from_user(&new_lock, arg, sizeof(new_lock)) != 0)
 		return -EFAULT;
 
@@ -1422,8 +1427,7 @@
 			    new_lock.data.pv_dev == vg_ptr->pv[p]->pv_dev)
 				break;
 		}
-		if (p == vg_ptr->pv_max)
-			return -ENXIO;
+		if (p == vg_ptr->pv_max) return -ENXIO;
 
 		/*
 		 * this sync releaves memory pressure to lessen the
@@ -1474,20 +1478,24 @@
 /*
  * character device support function logical extend remap
  */
-static int lvm_do_le_remap(vg_t * vg_ptr, void *arg)
+static int lvm_do_le_remap(vg_t *vg_ptr, void *arg)
 {
 	uint l, le;
 	lv_t *lv_ptr;
 
-	if (vg_ptr == NULL)
-		return -ENXIO;
+	if (vg_ptr == NULL) return -ENXIO;
 	if (copy_from_user(&le_remap_req, arg,
-			   sizeof(le_remap_req_t)) != 0) return -EFAULT;
+			   sizeof(le_remap_req_t)) != 0)
+		return -EFAULT;
 
 	for (l = 0; l < vg_ptr->lv_max; l++) {
 		lv_ptr = vg_ptr->lv[l];
-		if (lv_ptr != NULL &&
-		    strcmp(lv_ptr->lv_name, le_remap_req.lv_name) == 0) {
+
+		if (!lv_ptr)
+			continue;
+
+		if (strcmp(lv_ptr->lv_name, le_remap_req.lv_name) == 0) {
+			down_write(&lv_ptr->lv_lock);
 			for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
 				if (lv_ptr->lv_current_pe[le].dev ==
 				    le_remap_req.old_dev &&
@@ -1497,16 +1505,17 @@
 					    le_remap_req.new_dev;
 					lv_ptr->lv_current_pe[le].pe =
 					    le_remap_req.new_pe;
-
 					__update_hardsectsize(lv_ptr);
+					up_write(&lv_ptr->lv_lock);
 					return 0;
 				}
 			}
+			up_write(&lv_ptr->lv_lock);
 			return -EINVAL;
 		}
 	}
 	return -ENXIO;
-}				/* lvm_do_le_remap() */
+} /* lvm_do_le_remap() */
 
 
 /*
@@ -1520,7 +1529,7 @@
 	vg_t *vg_ptr;
 	lv_t **snap_lv_ptr;
 
-	if ((vg_ptr = kmalloc(sizeof(vg_t), GFP_KERNEL)) == NULL) {
+	if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) {
 		printk(KERN_CRIT
 		       "%s -- VG_CREATE: kmalloc error VG at line %d\n",
 		       lvm_name, __LINE__);
@@ -1528,9 +1537,8 @@
 	}
 	/* get the volume group structure */
 	if (copy_from_user(vg_ptr, arg, sizeof(vg_t)) != 0) {
-		P_IOCTL
-		    ("lvm_do_vg_create ERROR: copy VG ptr %p (%d bytes)\n",
-		     arg, sizeof(vg_t));
+		P_IOCTL("lvm_do_vg_create ERROR: copy VG ptr %p (%d bytes)\n",
+			arg, sizeof(vg_t));
 		kfree(vg_ptr);
 		return -EFAULT;
 	}
@@ -1539,6 +1547,10 @@
 	if (minor == -1)
 		minor = vg_ptr->vg_number;
 
+	/* check limits */
+	if (minor >= ABS_MAX_VG)
+		return -EFAULT;
+
 	/* Validate it */
 	if (vg[VG_CHR(minor)] != NULL) {
 		P_IOCTL("lvm_do_vg_create ERROR: VG %d in use\n", minor);
@@ -1560,7 +1572,7 @@
 
 	if (vg_ptr->lv_max > ABS_MAX_LV) {
 		printk(KERN_WARNING
-		       "%s -- Can't activate VG: ABS_MAX_LV too small for %u\n",
+		"%s -- Can't activate VG: ABS_MAX_LV too small for %u\n",
 		       lvm_name, vg_ptr->lv_max);
 		kfree(vg_ptr);
 		return -EPERM;
@@ -1578,7 +1590,7 @@
 		/* user space address */
 		if ((pvp = vg_ptr->pv[p]) != NULL) {
 			ret = lvm_do_pv_create(pvp, vg_ptr, p);
-			if (ret != 0) {
+			if ( ret != 0) {
 				lvm_do_vg_remove(minor);
 				return ret;
 			}
@@ -1586,7 +1598,7 @@
 	}
 
 	size = vg_ptr->lv_max * sizeof(lv_t *);
-	if ((snap_lv_ptr = vmalloc(size)) == NULL) {
+	if ((snap_lv_ptr = vmalloc ( size)) == NULL) {
 		printk(KERN_CRIT
 		       "%s -- VG_CREATE: vmalloc error snapshot LVs at line %d\n",
 		       lvm_name, __LINE__);
@@ -1602,13 +1614,12 @@
 		/* user space address */
 		if ((lvp = vg_ptr->lv[l]) != NULL) {
 			if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) {
-				P_IOCTL
-				    ("ERROR: copying LV ptr %p (%d bytes)\n",
-				     lvp, sizeof(lv_t));
+				P_IOCTL("ERROR: copying LV ptr %p (%d bytes)\n",
+					lvp, sizeof(lv_t));
 				lvm_do_vg_remove(minor);
 				return -EFAULT;
 			}
-			if (lv.lv_access & LV_SNAPSHOT) {
+			if ( lv.lv_access & LV_SNAPSHOT) {
 				snap_lv_ptr[ls] = lvp;
 				vg_ptr->lv[l] = NULL;
 				ls++;
@@ -1648,26 +1659,24 @@
 	vg_ptr->vg_status |= VG_ACTIVE;
 
 	return 0;
-}				/* lvm_do_vg_create() */
+} /* lvm_do_vg_create() */
 
 
 /*
  * character device support function VGDA extend
  */
-static int lvm_do_vg_extend(vg_t * vg_ptr, void *arg)
+static int lvm_do_vg_extend(vg_t *vg_ptr, void *arg)
 {
 	int ret = 0;
 	uint p;
 	pv_t *pv_ptr;
 
-	if (vg_ptr == NULL)
-		return -ENXIO;
+	if (vg_ptr == NULL) return -ENXIO;
 	if (vg_ptr->pv_cur < vg_ptr->pv_max) {
 		for (p = 0; p < vg_ptr->pv_max; p++) {
-			if ((pv_ptr = vg_ptr->pv[p]) == NULL) {
+			if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) {
 				ret = lvm_do_pv_create(arg, vg_ptr, p);
-				if (ret != 0)
-					return ret;
+				if ( ret != 0) return ret;
 				pv_ptr = vg_ptr->pv[p];
 				vg_ptr->pe_total += pv_ptr->pe_total;
 				return 0;
@@ -1675,28 +1684,26 @@
 		}
 	}
 	return -EPERM;
-}				/* lvm_do_vg_extend() */
+} /* lvm_do_vg_extend() */
 
 
 /*
  * character device support function VGDA reduce
  */
-static int lvm_do_vg_reduce(vg_t * vg_ptr, void *arg)
-{
+static int lvm_do_vg_reduce(vg_t *vg_ptr, void *arg) {
 	uint p;
 	pv_t *pv_ptr;
 
-	if (vg_ptr == NULL)
-		return -ENXIO;
+	if (vg_ptr == NULL) return -ENXIO;
 	if (copy_from_user(pv_name, arg, sizeof(pv_name)) != 0)
 		return -EFAULT;
 
 	for (p = 0; p < vg_ptr->pv_max; p++) {
 		pv_ptr = vg_ptr->pv[p];
 		if (pv_ptr != NULL &&
-		    strcmp(pv_ptr->pv_name, pv_name) == 0) {
-			if (pv_ptr->lv_cur > 0)
-				return -EPERM;
+		    strcmp(pv_ptr->pv_name,
+			       pv_name) == 0) {
+			if (pv_ptr->lv_cur > 0) return -EPERM;
 			lvm_do_pv_remove(vg_ptr, p);
 			/* Make PV pointer array contiguous */
 			for (; p < vg_ptr->pv_max - 1; p++)
@@ -1706,55 +1713,74 @@
 		}
 	}
 	return -ENXIO;
-}				/* lvm_do_vg_reduce */
+} /* lvm_do_vg_reduce */
 
 
 /*
  * character device support function VG rename
  */
-static int lvm_do_vg_rename(vg_t * vg_ptr, void *arg)
+static int lvm_do_vg_rename(vg_t *vg_ptr, void *arg)
 {
 	int l = 0, p = 0, len = 0;
-	char vg_name[NAME_LEN] = { 0, };
-	char lv_name[NAME_LEN] = { 0, };
+	char vg_name[NAME_LEN] = { 0,};
+	char lv_name[NAME_LEN] = { 0,};
 	char *ptr = NULL;
 	lv_t *lv_ptr = NULL;
 	pv_t *pv_ptr = NULL;
 
 	/* If the VG doesn't exist in the kernel then just exit */
-	if (!vg_ptr)
-		return 0;
+	if (!vg_ptr) return 0;
 
 	if (copy_from_user(vg_name, arg, sizeof(vg_name)) != 0)
 		return -EFAULT;
 
 	lvm_fs_remove_vg(vg_ptr);
 
-	strncpy(vg_ptr->vg_name, vg_name, sizeof(vg_name) - 1);
-	for (l = 0; l < vg_ptr->lv_max; l++) {
-		if ((lv_ptr = vg_ptr->lv[l]) == NULL)
-			continue;
-		strncpy(lv_ptr->vg_name, vg_name, sizeof(vg_name));
+	strncpy ( vg_ptr->vg_name, vg_name, sizeof ( vg_name)-1);
+	for ( l = 0; l < vg_ptr->lv_max; l++)
+	{
+		if ((lv_ptr = vg_ptr->lv[l]) == NULL) continue;
+		memset (lv_ptr->vg_name, 0, sizeof (*vg_name));
+		strncpy(lv_ptr->vg_name, vg_name, sizeof ( vg_name));
 		ptr = strrchr(lv_ptr->lv_name, '/');
-		if (ptr == NULL)
-			ptr = lv_ptr->lv_name;
-		strncpy(lv_name, ptr, sizeof(lv_name));
+		ptr = ptr ? ptr + 1 : lv_ptr->lv_name;
+		strncpy(lv_name, ptr, sizeof ( lv_name));
 		len = sizeof(LVM_DIR_PREFIX);
 		strcpy(lv_ptr->lv_name, LVM_DIR_PREFIX);
 		strncat(lv_ptr->lv_name, vg_name, NAME_LEN - len);
-		len += strlen(vg_name);
+		strcat (lv_ptr->lv_name, "/");
+		len += strlen(vg_name) + 1;
 		strncat(lv_ptr->lv_name, lv_name, NAME_LEN - len);
 	}
-	for (p = 0; p < vg_ptr->pv_max; p++) {
-		if ((pv_ptr = vg_ptr->pv[p]) == NULL)
-			continue;
+	for ( p = 0; p < vg_ptr->pv_max; p++)
+	{
+		if ( (pv_ptr = vg_ptr->pv[p]) == NULL) continue;
 		strncpy(pv_ptr->vg_name, vg_name, NAME_LEN);
 	}
 
 	lvm_fs_create_vg(vg_ptr);
 
+	/* Need to add PV entries */
+	for ( p = 0; p < vg_ptr->pv_act; p++) {
+		pv_t *pv_ptr = vg_ptr->pv[p];
+
+		if (pv_ptr)
+			lvm_fs_create_pv(vg_ptr, pv_ptr);
+	}
+
+	/* Need to add LV entries */
+        for ( l = 0; l < vg_ptr->lv_max; l++) {
+		lv_t *lv_ptr = vg_ptr->lv[l];
+
+		if (!lv_ptr)
+			continue;
+
+		lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].de =
+	    		lvm_fs_create_lv(vg_ptr, lv_ptr);
+	}
+
 	return 0;
-}				/* lvm_do_vg_rename */
+} /* lvm_do_vg_rename */
 
 
 /*
@@ -1766,8 +1792,7 @@
 	vg_t *vg_ptr = vg[VG_CHR(minor)];
 	pv_t *pv_ptr;
 
-	if (vg_ptr == NULL)
-		return -ENXIO;
+	if (vg_ptr == NULL) return -ENXIO;
 
 #ifdef LVM_TOTAL_RESET
 	if (vg_ptr->lv_open > 0 && lvm_reset_spindown == 0)
@@ -1818,18 +1843,20 @@
 	MOD_DEC_USE_COUNT;
 
 	return 0;
-}				/* lvm_do_vg_remove() */
+} /* lvm_do_vg_remove() */
 
 
 /*
  * character device support function physical volume create
  */
-static int lvm_do_pv_create(pv_t * pvp, vg_t * vg_ptr, ulong p)
-{
+static int lvm_do_pv_create(pv_t *pvp, vg_t *vg_ptr, ulong p) {
 	pv_t *pv;
 	int err;
 
-	pv = kmalloc(sizeof(pv_t), GFP_KERNEL);
+	if (!vg_ptr)
+		return -ENXIO;
+
+	pv = kmalloc(sizeof(pv_t),GFP_KERNEL);
 	if (pv == NULL) {
 		printk(KERN_CRIT
 		       "%s -- PV_CREATE: kmalloc error PV at line %d\n",
@@ -1840,9 +1867,8 @@
 	memset(pv, 0, sizeof(*pv));
 
 	if (copy_from_user(pv, pvp, sizeof(pv_t)) != 0) {
-		P_IOCTL
-		    ("lvm_do_pv_create ERROR: copy PV ptr %p (%d bytes)\n",
-		     pvp, sizeof(pv_t));
+		P_IOCTL("lvm_do_pv_create ERROR: copy PV ptr %p (%d bytes)\n",
+			pvp, sizeof(pv_t));
 		kfree(pv);
 		return -EFAULT;
 	}
@@ -1863,14 +1889,13 @@
 
 	vg_ptr->pv[p] = pv;
 	return 0;
-}				/* lvm_do_pv_create() */
+} /* lvm_do_pv_create() */
 
 
 /*
  * character device support function physical volume remove
  */
-static int lvm_do_pv_remove(vg_t * vg_ptr, ulong p)
-{
+static int lvm_do_pv_remove(vg_t *vg_ptr, ulong p) {
 	pv_t *pv = vg_ptr->pv[p];
 
 	lvm_fs_remove_pv(vg_ptr, pv);
@@ -1888,7 +1913,7 @@
 }
 
 
-static void __update_hardsectsize(lv_t * lv)
+static void __update_hardsectsize(lv_t *lv)
 {
 	int max_hardsectsize = 0, hardsectsize = 0;
 	int p;
@@ -1900,10 +1925,9 @@
 			if (max_hardsectsize == 0)
 				max_hardsectsize = hardsectsize;
 			else if (hardsectsize != max_hardsectsize) {
-				P_DEV
-				    ("%s PV[%d] (%s) sector size %d, not %d\n",
-				     lv->lv_name, p, kdevname(pv->pv_dev),
-				     hardsectsize, max_hardsectsize);
+				P_DEV("%s PV[%d] (%s) sector size %d, not %d\n",
+				      lv->lv_name, p, kdevname(pv->pv_dev),
+				      hardsectsize, max_hardsectsize);
 				break;
 			}
 		}
@@ -1913,14 +1937,12 @@
 	if (hardsectsize != max_hardsectsize) {
 		int le;
 		for (le = 0; le < lv->lv_allocated_le; le++) {
-			hardsectsize =
-			    lvm_sectsize(lv->lv_current_pe[le].dev);
+			hardsectsize = lvm_sectsize(lv->lv_current_pe[le].dev);
 			if (hardsectsize > max_hardsectsize) {
-				P_DEV
-				    ("%s LE[%d] (%s) blocksize %d not %d\n",
-				     lv->lv_name, le,
-				     kdevname(lv->lv_current_pe[le].dev),
-				     hardsectsize, max_hardsectsize);
+				P_DEV("%s LE[%d] (%s) blocksize %d not %d\n",
+				      lv->lv_name, le,
+				      kdevname(lv->lv_current_pe[le].dev),
+				      hardsectsize, max_hardsectsize);
 				max_hardsectsize = hardsectsize;
 			}
 		}
@@ -1930,9 +1952,7 @@
 		    (lv->lv_status & LV_ACTIVE)) {
 			int e;
 			for (e = 0; e < lv->lv_remap_end; e++) {
-				hardsectsize =
-				    lvm_sectsize(lv->lv_block_exception[e].
-						 rdev_new);
+				hardsectsize = lvm_sectsize(lv->lv_block_exception[e].rdev_new);
 				if (hardsectsize > max_hardsectsize)
 					max_hardsectsize = hardsectsize;
 			}
@@ -1949,7 +1969,7 @@
 /*
  * character device support function logical volume create
  */
-static int lvm_do_lv_create(int minor, char *lv_name, lv_t * lv)
+static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv)
 {
 	int e, ret, l, le, l_new, p, size, activate = 1;
 	ulong lv_status_save;
@@ -1977,18 +1997,14 @@
 	else {
 		for (l = 0; l < vg_ptr->lv_max; l++) {
 			if (vg_ptr->lv[l] == NULL)
-				if (l_new == -1)
-					l_new = l;
+				if (l_new == -1) l_new = l;
 		}
 	}
-	if (l_new == -1)
-		return -EPERM;
-	else
-		l = l_new;
+	if (l_new == -1) return -EPERM;
+	else             l = l_new;
 
-	if ((lv_ptr = kmalloc(sizeof(lv_t), GFP_KERNEL)) == NULL) {;
-		printk(KERN_CRIT
-		       "%s -- LV_CREATE: kmalloc error LV at line %d\n",
+	if ((lv_ptr = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL) {;
+		printk(KERN_CRIT "%s -- LV_CREATE: kmalloc error LV at line %d\n",
 		       lvm_name, __LINE__);
 		return -ENOMEM;
 	}
@@ -2020,7 +2036,8 @@
 		if ((lv_ptr->lv_current_pe = vmalloc(size)) == NULL) {
 			printk(KERN_CRIT
 			       "%s -- LV_CREATE: vmalloc error LV_CURRENT_PE of %d Byte "
-			       "at line %d\n", lvm_name, size, __LINE__);
+			       "at line %d\n",
+			       lvm_name, size, __LINE__);
 			P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__);
 			kfree(lv_ptr);
 			vg_ptr->lv[l] = NULL;
@@ -2049,9 +2066,7 @@
 			lv_ptr->lv_snapshot_org =
 			    vg_ptr->lv[LV_BLK(lv_ptr->lv_snapshot_minor)];
 			if (lv_ptr->lv_snapshot_org != NULL) {
-				size =
-				    lv_ptr->lv_remap_end *
-				    sizeof(lv_block_exception_t);
+				size = lv_ptr->lv_remap_end * sizeof(lv_block_exception_t);
 
 				if (!size) {
 					printk(KERN_WARNING
@@ -2061,33 +2076,29 @@
 					return -EINVAL;
 				}
 
-				if (
-				    (lv_ptr->lv_block_exception =
-				     vmalloc(size)) == NULL) {
+				if ((lv_ptr->lv_block_exception = vmalloc(size)) == NULL) {
 					printk(KERN_CRIT
 					       "%s -- lvm_do_lv_create: vmalloc error LV_BLOCK_EXCEPTION "
 					       "of %d byte at line %d\n",
 					       lvm_name, size, __LINE__);
-					P_KFREE("%s -- kfree %d\n",
-						lvm_name, __LINE__);
+					P_KFREE("%s -- kfree %d\n", lvm_name,
+						__LINE__);
 					kfree(lv_ptr);
 					vg_ptr->lv[l] = NULL;
 					return -ENOMEM;
 				}
-				if (copy_from_user
-				    (lv_ptr->lv_block_exception, lvbe,
-				     size)) {
+				if (copy_from_user(lv_ptr->lv_block_exception, lvbe, size)) {
 					vfree(lv_ptr->lv_block_exception);
 					kfree(lv_ptr);
 					vg_ptr->lv[l] = NULL;
 					return -EFAULT;
 				}
 
-				if (lv_ptr->lv_block_exception[0].
-				    rsector_org ==
-				    LVM_SNAPSHOT_DROPPED_SECTOR) {
+				if(lv_ptr->lv_block_exception[0].rsector_org ==
+				   LVM_SNAPSHOT_DROPPED_SECTOR)
+				{
 					printk(KERN_WARNING
-					       "%s -- lvm_do_lv_create: snapshot has been dropped and will not be activated\n",
+   "%s -- lvm_do_lv_create: snapshot has been dropped and will not be activated\n",
 					       lvm_name);
 					activate = 0;
 				}
@@ -2101,54 +2112,36 @@
 				   which can be the original logical volume */
 				lv_ptr = vg_ptr->lv[l];
 				/* now lv_ptr points to our new last snapshot logical volume */
-				lv_ptr->lv_current_pe =
-				    lv_ptr->lv_snapshot_org->lv_current_pe;
-				lv_ptr->lv_allocated_snapshot_le =
-				    lv_ptr->lv_allocated_le;
-				lv_ptr->lv_allocated_le =
-				    lv_ptr->lv_snapshot_org->
-				    lv_allocated_le;
-				lv_ptr->lv_current_le =
-				    lv_ptr->lv_snapshot_org->lv_current_le;
-				lv_ptr->lv_size =
-				    lv_ptr->lv_snapshot_org->lv_size;
-				lv_ptr->lv_stripes =
-				    lv_ptr->lv_snapshot_org->lv_stripes;
-				lv_ptr->lv_stripesize =
-				    lv_ptr->lv_snapshot_org->lv_stripesize;
+				lv_ptr->lv_current_pe = lv_ptr->lv_snapshot_org->lv_current_pe;
+				lv_ptr->lv_allocated_snapshot_le = lv_ptr->lv_allocated_le;
+				lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le;
+				lv_ptr->lv_current_le = lv_ptr->lv_snapshot_org->lv_current_le;
+				lv_ptr->lv_size = lv_ptr->lv_snapshot_org->lv_size;
+				lv_ptr->lv_stripes = lv_ptr->lv_snapshot_org->lv_stripes;
+				lv_ptr->lv_stripesize = lv_ptr->lv_snapshot_org->lv_stripesize;
 
 				/* Update the VG PE(s) used by snapshot reserve space. */
-				vg_ptr->pe_allocated +=
-				    lv_ptr->lv_allocated_snapshot_le;
+				vg_ptr->pe_allocated += lv_ptr->lv_allocated_snapshot_le;
 
-				if ((ret = lvm_snapshot_alloc(lv_ptr)) !=
-				    0) {
+				if ((ret = lvm_snapshot_alloc(lv_ptr)) != 0)
+				{
 					vfree(lv_ptr->lv_block_exception);
 					kfree(lv_ptr);
 					vg_ptr->lv[l] = NULL;
 					return ret;
 				}
-				for (e = 0; e < lv_ptr->lv_remap_ptr; e++)
-					lvm_hash_link(lv_ptr->
-						      lv_block_exception +
-						      e,
-						      lv_ptr->
-						      lv_block_exception
-						      [e].rdev_org,
-						      lv_ptr->
-						      lv_block_exception
-						      [e].rsector_org,
-						      lv_ptr);
+				for ( e = 0; e < lv_ptr->lv_remap_ptr; e++)
+					lvm_hash_link (lv_ptr->lv_block_exception + e,
+						       lv_ptr->lv_block_exception[e].rdev_org,
+						       lv_ptr->lv_block_exception[e].rsector_org, lv_ptr);
 				/* need to fill the COW exception table data
 				   into the page for disk i/o */
-				if (lvm_snapshot_fill_COW_page
-				    (vg_ptr, lv_ptr)) {
+				if(lvm_snapshot_fill_COW_page(vg_ptr, lv_ptr)) {
 					kfree(lv_ptr);
 					vg_ptr->lv[l] = NULL;
 					return -EINVAL;
 				}
-				init_waitqueue_head(&lv_ptr->
-						    lv_snapshot_wait);
+				init_waitqueue_head(&lv_ptr->lv_snapshot_wait);
 			} else {
 				kfree(lv_ptr);
 				vg_ptr->lv[l] = NULL;
@@ -2159,7 +2152,7 @@
 			vg_ptr->lv[l] = NULL;
 			return -EINVAL;
 		}
-	}			/* if ( vg[VG_CHR(minor)]->lv[l]->lv_access & LV_SNAPSHOT) */
+	} /* if ( vg[VG_CHR(minor)]->lv[l]->lv_access & LV_SNAPSHOT) */
 
 	lv_ptr = vg_ptr->lv[l];
 	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0;
@@ -2187,24 +2180,23 @@
 
 		down_write(&org->lv_lock);
 		org->lv_access |= LV_SNAPSHOT_ORG;
-		lv_ptr->lv_access &= ~LV_SNAPSHOT_ORG;	/* this can only hide an userspace bug */
+		lv_ptr->lv_access &= ~LV_SNAPSHOT_ORG; /* this can only hide an userspace bug */
 
 
 		/* Link in the list of snapshot volumes */
-		for (last = org; last->lv_snapshot_next;
-		     last = last->lv_snapshot_next);
+		for (last = org; last->lv_snapshot_next; last = last->lv_snapshot_next);
 		lv_ptr->lv_snapshot_prev = last;
 		last->lv_snapshot_next = lv_ptr;
 		up_write(&org->lv_lock);
 	}
 
 	/* activate the logical volume */
-	if (activate)
+	if(activate)
 		lv_ptr->lv_status |= LV_ACTIVE;
 	else
 		lv_ptr->lv_status &= ~LV_ACTIVE;
 
-	if (lv_ptr->lv_access & LV_WRITE)
+	if ( lv_ptr->lv_access & LV_WRITE)
 		set_device_ro(lv_ptr->lv_dev, 0);
 	else
 		set_device_ro(lv_ptr->lv_dev, 1);
@@ -2218,7 +2210,7 @@
 	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].de =
 	    lvm_fs_create_lv(vg_ptr, lv_ptr);
 	return 0;
-}				/* lvm_do_lv_create() */
+} /* lvm_do_lv_create() */
 
 
 /*
@@ -2230,6 +2222,9 @@
 	vg_t *vg_ptr = vg[VG_CHR(minor)];
 	lv_t *lv_ptr;
 
+	if (!vg_ptr)
+		return -ENXIO;
+
 	if (l == -1) {
 		for (l = 0; l < vg_ptr->lv_max; l++) {
 			if (vg_ptr->lv[l] != NULL &&
@@ -2238,8 +2233,7 @@
 			}
 		}
 	}
-	if (l == vg_ptr->lv_max)
-		return -ENXIO;
+	if (l == vg_ptr->lv_max) return -ENXIO;
 
 	lv_ptr = vg_ptr->lv[l];
 #ifdef LVM_TOTAL_RESET
@@ -2262,12 +2256,11 @@
 		 * Atomically make the the snapshot invisible
 		 * to the original lv before playing with it.
 		 */
-		lv_t *org = lv_ptr->lv_snapshot_org;
+		lv_t * org = lv_ptr->lv_snapshot_org;
 		down_write(&org->lv_lock);
 
 		/* remove this snapshot logical volume from the chain */
-		lv_ptr->lv_snapshot_prev->lv_snapshot_next =
-		    lv_ptr->lv_snapshot_next;
+		lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr->lv_snapshot_next;
 		if (lv_ptr->lv_snapshot_next != NULL) {
 			lv_ptr->lv_snapshot_next->lv_snapshot_prev =
 			    lv_ptr->lv_snapshot_prev;
@@ -2306,7 +2299,7 @@
 	vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = -1;
 
 	/* correct the PE count in PVs if this is not a snapshot
-	   logical volume */
+           logical volume */
 	if (!(lv_ptr->lv_access & LV_SNAPSHOT)) {
 		/* only if this is no snapshot logical volume because
 		   we share the lv_current_pe[] structs with the
@@ -2327,15 +2320,13 @@
 	vg_ptr->lv[l] = NULL;
 	vg_ptr->lv_cur--;
 	return 0;
-}				/* lvm_do_lv_remove() */
+} /* lvm_do_lv_remove() */
 
 
 /*
  * logical volume extend / reduce
  */
-static int __extend_reduce_snapshot(vg_t * vg_ptr, lv_t * old_lv,
-				    lv_t * new_lv)
-{
+static int __extend_reduce_snapshot(vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) {
 	ulong size;
 	lv_block_exception_t *lvbe;
 
@@ -2366,8 +2357,7 @@
 	return 0;
 }
 
-static int __extend_reduce(vg_t * vg_ptr, lv_t * old_lv, lv_t * new_lv)
-{
+static int __extend_reduce(vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) {
 	ulong size, l, p, end;
 	pe_t *pe;
 
@@ -2383,7 +2373,7 @@
 
 	/* get the PE structures from user space */
 	if (copy_from_user(pe, new_lv->lv_current_pe, size)) {
-		if (old_lv->lv_access & LV_SNAPSHOT)
+		if(old_lv->lv_access & LV_SNAPSHOT)
 			vfree(new_lv->lv_snapshot_hash_table);
 		vfree(pe);
 		return -EFAULT;
@@ -2408,7 +2398,7 @@
 		vg_ptr->pe_allocated++;
 		for (p = 0; p < vg_ptr->pv_cur; p++) {
 			if (vg_ptr->pv[p]->pv_dev ==
-			    new_lv->lv_current_pe[l].dev) {
+                            new_lv->lv_current_pe[l].dev) {
 				vg_ptr->pv[p]->pe_allocated++;
 				break;
 			}
@@ -2420,30 +2410,25 @@
 		end = min(old_lv->lv_current_le, new_lv->lv_current_le);
 		for (l = 0; l < end; l++) {
 			new_lv->lv_current_pe[l].reads +=
-			    old_lv->lv_current_pe[l].reads;
+				old_lv->lv_current_pe[l].reads;
 
 			new_lv->lv_current_pe[l].writes +=
-			    old_lv->lv_current_pe[l].writes;
+				old_lv->lv_current_pe[l].writes;
 		}
 
 	} else {		/* striped logical volume */
-		uint i, j, source, dest, end, old_stripe_size,
-		    new_stripe_size;
+		uint i, j, source, dest, end, old_stripe_size, new_stripe_size;
 
-		old_stripe_size =
-		    old_lv->lv_allocated_le / old_lv->lv_stripes;
-		new_stripe_size =
-		    new_lv->lv_allocated_le / new_lv->lv_stripes;
+		old_stripe_size = old_lv->lv_allocated_le / old_lv->lv_stripes;
+		new_stripe_size = new_lv->lv_allocated_le / new_lv->lv_stripes;
 		end = min(old_stripe_size, new_stripe_size);
 
 		for (i = source = dest = 0; i < new_lv->lv_stripes; i++) {
 			for (j = 0; j < end; j++) {
 				new_lv->lv_current_pe[dest + j].reads +=
-				    old_lv->lv_current_pe[source +
-							  j].reads;
+				    old_lv->lv_current_pe[source + j].reads;
 				new_lv->lv_current_pe[dest + j].writes +=
-				    old_lv->lv_current_pe[source +
-							  j].writes;
+				    old_lv->lv_current_pe[source + j].writes;
 			}
 			source += old_stripe_size;
 			dest += new_stripe_size;
@@ -2453,7 +2438,7 @@
 	return 0;
 }
 
-static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t * new_lv)
+static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *new_lv)
 {
 	int r;
 	ulong l, e, size;
@@ -2461,12 +2446,15 @@
 	lv_t *old_lv;
 	pe_t *pe;
 
+	if (!vg_ptr)
+		return -ENXIO;
+
 	if ((pe = new_lv->lv_current_pe) == NULL)
 		return -EINVAL;
 
 	for (l = 0; l < vg_ptr->lv_max; l++)
-		if (vg_ptr->lv[l]
-		    && !strcmp(vg_ptr->lv[l]->lv_name, lv_name)) break;
+		if (vg_ptr->lv[l] && !strcmp(vg_ptr->lv[l]->lv_name, lv_name))
+			break;
 
 	if (l == vg_ptr->lv_max)
 		return -ENXIO;
@@ -2476,24 +2464,22 @@
 	if (old_lv->lv_access & LV_SNAPSHOT) {
 		/* only perform this operation on active snapshots */
 		if (old_lv->lv_status & LV_ACTIVE)
-			r =
-			    __extend_reduce_snapshot(vg_ptr, old_lv,
-						     new_lv);
+			r = __extend_reduce_snapshot(vg_ptr, old_lv, new_lv);
 		else
 			r = -EPERM;
 
 	} else
 		r = __extend_reduce(vg_ptr, old_lv, new_lv);
 
-	if (r)
+	if(r)
 		return r;
 
 	/* copy relevent fields */
 	down_write(&old_lv->lv_lock);
 
-	if (new_lv->lv_access & LV_SNAPSHOT) {
+	if(new_lv->lv_access & LV_SNAPSHOT) {
 		size = (new_lv->lv_remap_end > old_lv->lv_remap_end) ?
-		    old_lv->lv_remap_ptr : new_lv->lv_remap_end;
+			old_lv->lv_remap_ptr : new_lv->lv_remap_end;
 		size *= sizeof(lv_block_exception_t);
 		memcpy(new_lv->lv_block_exception,
 		       old_lv->lv_block_exception, size);
@@ -2501,18 +2487,17 @@
 		old_lv->lv_remap_end = new_lv->lv_remap_end;
 		old_lv->lv_block_exception = new_lv->lv_block_exception;
 		old_lv->lv_snapshot_hash_table =
-		    new_lv->lv_snapshot_hash_table;
+			new_lv->lv_snapshot_hash_table;
 		old_lv->lv_snapshot_hash_table_size =
-		    new_lv->lv_snapshot_hash_table_size;
+			new_lv->lv_snapshot_hash_table_size;
 		old_lv->lv_snapshot_hash_mask =
-		    new_lv->lv_snapshot_hash_mask;
+			new_lv->lv_snapshot_hash_mask;
 
 		for (e = 0; e < new_lv->lv_remap_ptr; e++)
 			lvm_hash_link(new_lv->lv_block_exception + e,
-				      new_lv->lv_block_exception[e].
-				      rdev_org,
-				      new_lv->lv_block_exception[e].
-				      rsector_org, new_lv);
+				      new_lv->lv_block_exception[e].rdev_org,
+				      new_lv->lv_block_exception[e].rsector_org,
+				      new_lv);
 
 	} else {
 
@@ -2524,26 +2509,24 @@
 		old_lv->lv_current_le = new_lv->lv_current_le;
 		old_lv->lv_current_pe = new_lv->lv_current_pe;
 		lvm_gendisk.part[MINOR(old_lv->lv_dev)].nr_sects =
-		    old_lv->lv_size;
+			old_lv->lv_size;
 		lvm_size[MINOR(old_lv->lv_dev)] = old_lv->lv_size >> 1;
 
 		if (old_lv->lv_access & LV_SNAPSHOT_ORG) {
 			lv_t *snap;
-			for (snap = old_lv->lv_snapshot_next; snap;
-			     snap = snap->lv_snapshot_next) {
+			for(snap = old_lv->lv_snapshot_next; snap;
+			    snap = snap->lv_snapshot_next) {
 				down_write(&snap->lv_lock);
-				snap->lv_current_pe =
-				    old_lv->lv_current_pe;
+				snap->lv_current_pe = old_lv->lv_current_pe;
 				snap->lv_allocated_le =
-				    old_lv->lv_allocated_le;
-				snap->lv_current_le =
-				    old_lv->lv_current_le;
+					old_lv->lv_allocated_le;
+				snap->lv_current_le = old_lv->lv_current_le;
 				snap->lv_size = old_lv->lv_size;
 
-				lvm_gendisk.part[MINOR(snap->lv_dev)].
-				    nr_sects = old_lv->lv_size;
+				lvm_gendisk.part[MINOR(snap->lv_dev)].nr_sects
+					= old_lv->lv_size;
 				lvm_size[MINOR(snap->lv_dev)] =
-				    old_lv->lv_size >> 1;
+					old_lv->lv_size >> 1;
 				__update_hardsectsize(snap);
 				up_write(&snap->lv_lock);
 			}
@@ -2554,13 +2537,13 @@
 	up_write(&old_lv->lv_lock);
 
 	return 0;
-}				/* lvm_do_lv_extend_reduce() */
+} /* lvm_do_lv_extend_reduce() */
 
 
 /*
  * character device support function logical volume status by name
  */
-static int lvm_do_lv_status_byname(vg_t * vg_ptr, void *arg)
+static int lvm_do_lv_status_byname(vg_t *vg_ptr, void *arg)
 {
 	uint l;
 	lv_status_byname_req_t lv_status_byname_req;
@@ -2568,206 +2551,181 @@
 	void *saved_ptr2;
 	lv_t *lv_ptr;
 
-	if (vg_ptr == NULL)
-		return -ENXIO;
+	if (vg_ptr == NULL) return -ENXIO;
 	if (copy_from_user(&lv_status_byname_req, arg,
 			   sizeof(lv_status_byname_req_t)) != 0)
 		return -EFAULT;
 
-	if (lv_status_byname_req.lv == NULL)
-		return -EINVAL;
+	if (lv_status_byname_req.lv == NULL) return -EINVAL;
 
 	for (l = 0; l < vg_ptr->lv_max; l++) {
 		if ((lv_ptr = vg_ptr->lv[l]) != NULL &&
 		    strcmp(lv_ptr->lv_name,
 			   lv_status_byname_req.lv_name) == 0) {
-			/* Save usermode pointers */
-			if (copy_from_user
-			    (&saved_ptr1,
-			     &lv_status_byname_req.lv->lv_current_pe,
-			     sizeof(void *)) != 0)
-				return -EFAULT;
-			if (copy_from_user
-			    (&saved_ptr2,
-			     &lv_status_byname_req.lv->lv_block_exception,
-			     sizeof(void *)) != 0)
+		        /* Save usermode pointers */
+		        if (copy_from_user(&saved_ptr1, &lv_status_byname_req.lv->lv_current_pe, sizeof(void*)) != 0)
 				return -EFAULT;
-			if (copy_to_user(lv_status_byname_req.lv,
-					 lv_ptr, sizeof(lv_t)) != 0)
+			if (copy_from_user(&saved_ptr2, &lv_status_byname_req.lv->lv_block_exception, sizeof(void*)) != 0)
+			        return -EFAULT;
+		        if (copy_to_user(lv_status_byname_req.lv,
+					 lv_ptr,
+					 sizeof(lv_t)) != 0)
 				return -EFAULT;
 			if (saved_ptr1 != NULL) {
 				if (copy_to_user(saved_ptr1,
 						 lv_ptr->lv_current_pe,
 						 lv_ptr->lv_allocated_le *
-						 sizeof(pe_t)) != 0)
+				       		 sizeof(pe_t)) != 0)
 					return -EFAULT;
 			}
 			/* Restore usermode pointers */
-			if (copy_to_user
-			    (&lv_status_byname_req.lv->lv_current_pe,
-			     &saved_ptr1, sizeof(void *)) != 0)
-				return -EFAULT;
+			if (copy_to_user(&lv_status_byname_req.lv->lv_current_pe, &saved_ptr1, sizeof(void*)) != 0)
+			        return -EFAULT;
 			return 0;
 		}
 	}
 	return -ENXIO;
-}				/* lvm_do_lv_status_byname() */
+} /* lvm_do_lv_status_byname() */
 
 
 /*
  * character device support function logical volume status by index
  */
-static int lvm_do_lv_status_byindex(vg_t * vg_ptr, void *arg)
+static int lvm_do_lv_status_byindex(vg_t *vg_ptr,void *arg)
 {
 	lv_status_byindex_req_t lv_status_byindex_req;
 	void *saved_ptr1;
 	void *saved_ptr2;
 	lv_t *lv_ptr;
 
-	if (vg_ptr == NULL)
-		return -ENXIO;
+	if (vg_ptr == NULL) return -ENXIO;
 	if (copy_from_user(&lv_status_byindex_req, arg,
 			   sizeof(lv_status_byindex_req)) != 0)
 		return -EFAULT;
 
 	if (lv_status_byindex_req.lv == NULL)
 		return -EINVAL;
-	if (lv_status_byindex_req.lv_index < 0 ||
-	    lv_status_byindex_req.lv_index >= MAX_LV)
-		return -EINVAL;
-	if ((lv_ptr = vg_ptr->lv[lv_status_byindex_req.lv_index]) == NULL)
+	if ( ( lv_ptr = vg_ptr->lv[lv_status_byindex_req.lv_index]) == NULL)
 		return -ENXIO;
 
 	/* Save usermode pointers */
-	if (copy_from_user
-	    (&saved_ptr1, &lv_status_byindex_req.lv->lv_current_pe,
-	     sizeof(void *)) != 0)
-		return -EFAULT;
-	if (copy_from_user
-	    (&saved_ptr2, &lv_status_byindex_req.lv->lv_block_exception,
-	     sizeof(void *)) != 0)
-		return -EFAULT;
+	if (copy_from_user(&saved_ptr1, &lv_status_byindex_req.lv->lv_current_pe, sizeof(void*)) != 0)
+	        return -EFAULT;
+	if (copy_from_user(&saved_ptr2, &lv_status_byindex_req.lv->lv_block_exception, sizeof(void*)) != 0)
+	        return -EFAULT;
 
-	if (copy_to_user(lv_status_byindex_req.lv, lv_ptr, sizeof(lv_t)) !=
-	    0) return -EFAULT;
+	if (copy_to_user(lv_status_byindex_req.lv, lv_ptr, sizeof(lv_t)) != 0)
+		return -EFAULT;
 	if (saved_ptr1 != NULL) {
 		if (copy_to_user(saved_ptr1,
 				 lv_ptr->lv_current_pe,
 				 lv_ptr->lv_allocated_le *
-				 sizeof(pe_t)) != 0) return -EFAULT;
+		       		 sizeof(pe_t)) != 0)
+			return -EFAULT;
 	}
 
 	/* Restore usermode pointers */
-	if (copy_to_user
-	    (&lv_status_byindex_req.lv->lv_current_pe, &saved_ptr1,
-	     sizeof(void *)) != 0)
-		return -EFAULT;
+	if (copy_to_user(&lv_status_byindex_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0)
+	        return -EFAULT;
 
 	return 0;
-}				/* lvm_do_lv_status_byindex() */
+} /* lvm_do_lv_status_byindex() */
 
 
 /*
  * character device support function logical volume status by device number
  */
-static int lvm_do_lv_status_bydev(vg_t * vg_ptr, void *arg)
-{
+static int lvm_do_lv_status_bydev(vg_t * vg_ptr, void * arg) {
 	int l;
 	lv_status_bydev_req_t lv_status_bydev_req;
 	void *saved_ptr1;
 	void *saved_ptr2;
 	lv_t *lv_ptr;
 
-	if (vg_ptr == NULL)
-		return -ENXIO;
+	if (vg_ptr == NULL) return -ENXIO;
 	if (copy_from_user(&lv_status_bydev_req, arg,
 			   sizeof(lv_status_bydev_req)) != 0)
 		return -EFAULT;
 
-	for (l = 0; l < vg_ptr->lv_max; l++) {
-		if (vg_ptr->lv[l] == NULL)
-			continue;
-		if (vg_ptr->lv[l]->lv_dev == lv_status_bydev_req.dev)
-			break;
+	for ( l = 0; l < vg_ptr->lv_max; l++) {
+		if ( vg_ptr->lv[l] == NULL) continue;
+		if ( vg_ptr->lv[l]->lv_dev == lv_status_bydev_req.dev) break;
 	}
 
-	if (l == vg_ptr->lv_max)
-		return -ENXIO;
+	if ( l == vg_ptr->lv_max) return -ENXIO;
 	lv_ptr = vg_ptr->lv[l];
 
 	/* Save usermode pointers */
-	if (copy_from_user
-	    (&saved_ptr1, &lv_status_bydev_req.lv->lv_current_pe,
-	     sizeof(void *)) != 0)
-		return -EFAULT;
-	if (copy_from_user
-	    (&saved_ptr2, &lv_status_bydev_req.lv->lv_block_exception,
-	     sizeof(void *)) != 0)
-		return -EFAULT;
+	if (copy_from_user(&saved_ptr1, &lv_status_bydev_req.lv->lv_current_pe, sizeof(void*)) != 0)
+	        return -EFAULT;
+	if (copy_from_user(&saved_ptr2, &lv_status_bydev_req.lv->lv_block_exception, sizeof(void*)) != 0)
+	        return -EFAULT;
 
-	if (copy_to_user(lv_status_bydev_req.lv, lv_ptr, sizeof(lv_t)) !=
-	    0) return -EFAULT;
+	if (copy_to_user(lv_status_bydev_req.lv, lv_ptr, sizeof(lv_t)) != 0)
+		return -EFAULT;
 	if (saved_ptr1 != NULL) {
 		if (copy_to_user(saved_ptr1,
 				 lv_ptr->lv_current_pe,
 				 lv_ptr->lv_allocated_le *
-				 sizeof(pe_t)) != 0) return -EFAULT;
+		       		 sizeof(pe_t)) != 0)
+			return -EFAULT;
 	}
 	/* Restore usermode pointers */
-	if (copy_to_user
-	    (&lv_status_bydev_req.lv->lv_current_pe, &saved_ptr1,
-	     sizeof(void *)) != 0)
-		return -EFAULT;
+	if (copy_to_user(&lv_status_bydev_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0)
+	        return -EFAULT;
 
 	return 0;
-}				/* lvm_do_lv_status_bydev() */
+} /* lvm_do_lv_status_bydev() */
 
 
 /*
  * character device support function rename a logical volume
  */
-static int lvm_do_lv_rename(vg_t * vg_ptr, lv_req_t * lv_req, lv_t * lv)
+static int lvm_do_lv_rename(vg_t *vg_ptr, lv_req_t *lv_req, lv_t *lv)
 {
 	int l = 0;
 	int ret = 0;
 	lv_t *lv_ptr = NULL;
 
-	for (l = 0; l < vg_ptr->lv_max; l++) {
-		if ((lv_ptr = vg_ptr->lv[l]) == NULL)
-			continue;
-		if (lv_ptr->lv_dev == lv->lv_dev) {
+	if (!vg_ptr)
+		return -ENXIO;
+
+	for (l = 0; l < vg_ptr->lv_max; l++)
+	{
+		if ( (lv_ptr = vg_ptr->lv[l]) == NULL) continue;
+		if (lv_ptr->lv_dev == lv->lv_dev)
+		{
 			lvm_fs_remove_lv(vg_ptr, lv_ptr);
-			strncpy(lv_ptr->lv_name, lv_req->lv_name,
-				NAME_LEN);
+			strncpy(lv_ptr->lv_name, lv_req->lv_name, NAME_LEN);
 			lvm_fs_create_lv(vg_ptr, lv_ptr);
 			break;
 		}
 	}
-	if (l == vg_ptr->lv_max)
-		ret = -ENODEV;
+	if (l == vg_ptr->lv_max) ret = -ENODEV;
 
 	return ret;
-}				/* lvm_do_lv_rename */
+} /* lvm_do_lv_rename */
 
 
 /*
  * character device support function physical volume change
  */
-static int lvm_do_pv_change(vg_t * vg_ptr, void *arg)
+static int lvm_do_pv_change(vg_t *vg_ptr, void *arg)
 {
 	uint p;
 	pv_t *pv_ptr;
 	struct block_device *bd;
 
-	if (vg_ptr == NULL)
-		return -ENXIO;
+	if (vg_ptr == NULL) return -ENXIO;
 	if (copy_from_user(&pv_change_req, arg,
-			   sizeof(pv_change_req)) != 0) return -EFAULT;
+			   sizeof(pv_change_req)) != 0)
+		return -EFAULT;
 
 	for (p = 0; p < vg_ptr->pv_max; p++) {
 		pv_ptr = vg_ptr->pv[p];
 		if (pv_ptr != NULL &&
-		    strcmp(pv_ptr->pv_name, pv_change_req.pv_name) == 0) {
+		    strcmp(pv_ptr->pv_name,
+			       pv_change_req.pv_name) == 0) {
 
 			bd = pv_ptr->bd;
 			if (copy_from_user(pv_ptr,
@@ -2783,33 +2741,35 @@
 		}
 	}
 	return -ENXIO;
-}				/* lvm_do_pv_change() */
+} /* lvm_do_pv_change() */
 
 /*
  * character device support function get physical volume status
  */
-static int lvm_do_pv_status(vg_t * vg_ptr, void *arg)
+static int lvm_do_pv_status(vg_t *vg_ptr, void *arg)
 {
 	uint p;
 	pv_t *pv_ptr;
 
-	if (vg_ptr == NULL)
-		return -ENXIO;
+	if (vg_ptr == NULL) return -ENXIO;
 	if (copy_from_user(&pv_status_req, arg,
-			   sizeof(pv_status_req)) != 0) return -EFAULT;
+			   sizeof(pv_status_req)) != 0)
+		return -EFAULT;
 
 	for (p = 0; p < vg_ptr->pv_max; p++) {
 		pv_ptr = vg_ptr->pv[p];
 		if (pv_ptr != NULL &&
-		    strcmp(pv_ptr->pv_name, pv_status_req.pv_name) == 0) {
+		    strcmp(pv_ptr->pv_name,
+			       pv_status_req.pv_name) == 0) {
 			if (copy_to_user(pv_status_req.pv,
-					 pv_ptr, sizeof(pv_t)) != 0)
+					 pv_ptr,
+				         sizeof(pv_t)) != 0)
 				return -EFAULT;
 			return 0;
 		}
 	}
 	return -ENXIO;
-}				/* lvm_do_pv_status() */
+} /* lvm_do_pv_status() */
 
 
 /*
@@ -2851,15 +2811,13 @@
 	hardsect_size[MAJOR_NR] = lvm_hardsectsizes;
 
 	return;
-}				/* lvm_gen_init() */
+} /* lvm_gen_init() */
 
 
 
 /* Must have down_write(_pe_lock) when we enqueue buffers */
-static void _queue_io(struct buffer_head *bh, int rw)
-{
-	if (bh->b_reqnext)
-		BUG();
+static void _queue_io(struct buffer_head *bh, int rw) {
+	if (bh->b_reqnext) BUG();
 	bh->b_reqnext = _pe_requests;
 	_pe_requests = bh;
 }
@@ -2897,15 +2855,14 @@
 /*
  * we must open the pv's before we use them
  */
-static int _open_pv(pv_t * pv)
-{
+static int _open_pv(pv_t *pv) {
 	int err;
 	struct block_device *bd;
 
 	if (!(bd = bdget(kdev_t_to_nr(pv->pv_dev))))
 		return -ENOMEM;
 
-	err = blkdev_get(bd, FMODE_READ | FMODE_WRITE, 0, BDEV_FILE);
+	err = blkdev_get(bd, FMODE_READ|FMODE_WRITE, 0, BDEV_FILE);
 	if (err)
 		return err;
 
@@ -2913,8 +2870,7 @@
 	return 0;
 }
 
-static void _close_pv(pv_t * pv)
-{
+static void _close_pv(pv_t *pv) {
 	if (pv) {
 		struct block_device *bdev = pv->bd;
 		pv->bd = NULL;
@@ -2926,7 +2882,7 @@
 
 static unsigned long _sectors_to_k(unsigned long sect)
 {
-	if (SECTOR_SIZE > 1024) {
+	if(SECTOR_SIZE > 1024) {
 		return sect * (SECTOR_SIZE / 1024);
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/md/md.c linux-2.4.20/drivers/md/md.c
--- linux-2.4.19/drivers/md/md.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/md/md.c	2002-10-29 11:18:35.000000000 +0000
@@ -724,9 +724,9 @@
 	 * Make sure nobody else is using this mddev
 	 * (careful, we rely on the global kernel lock here)
 	 */
-	while (md_atomic_read(&mddev->resync_sem.count) != 1)
+	while (sem_getcount(&mddev->resync_sem) != 1)
 		schedule();
-	while (md_atomic_read(&mddev->recovery_sem.count) != 1)
+	while (sem_getcount(&mddev->recovery_sem) != 1)
 		schedule();
 
 	del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev)));
@@ -3219,7 +3219,7 @@
 		if (mddev->curr_resync) {
 			sz += status_resync (page+sz, mddev);
 		} else {
-			if (md_atomic_read(&mddev->resync_sem.count) != 1)
+			if (sem_getcount(&mddev->resync_sem) != 1)
 				sz += sprintf(page + sz, "	resync=DELAYED");
 		}
 		sz += sprintf(page + sz, "\n");
@@ -3712,7 +3712,7 @@
  * Searches all registered partitions for autorun RAID arrays
  * at boot time.
  */
-static int detected_devices[128];
+static kdev_t detected_devices[128];
 static int dev_cnt;
 
 void md_autodetect_dev(kdev_t dev)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/md/raid1.c linux-2.4.20/drivers/md/raid1.c
--- linux-2.4.19/drivers/md/raid1.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/md/raid1.c	2002-10-29 11:18:31.000000000 +0000
@@ -23,6 +23,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/config.h>
 #include <linux/slab.h>
 #include <linux/raid/raid1.h>
 #include <asm/atomic.h>
@@ -522,6 +523,10 @@
 	if (conf->sect_count >= conf->mirrors[new_disk].sect_limit) {
 		conf->sect_count = 0;
 
+#if defined(CONFIG_SPARC64) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 92)
+		/* Work around a compiler bug in egcs-2.92.11 19980921 */
+		new_disk = *(volatile int *)&new_disk;
+#endif
 		do {
 			if (new_disk<=0)
 				new_disk = conf->raid_disks;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/radio/Config.in linux-2.4.20/drivers/media/radio/Config.in
--- linux-2.4.19/drivers/media/radio/Config.in	2001-11-09 22:01:22.000000000 +0000
+++ linux-2.4.20/drivers/media/radio/Config.in	2002-10-29 11:18:48.000000000 +0000
@@ -4,50 +4,53 @@
 mainmenu_option next_comment
 comment 'Radio Adapters'
 
-dep_tristate '  ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV
-dep_tristate '  AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV
-if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then
-   hex '  RadioTrack i/o port (0x20f or 0x30f)' CONFIG_RADIO_RTRACK_PORT 20f
-fi
-dep_tristate '  AIMSlab RadioTrack II support' CONFIG_RADIO_RTRACK2 $CONFIG_VIDEO_DEV
-if [ "$CONFIG_RADIO_RTRACK2" = "y" ]; then
-   hex '    RadioTrack II i/o port (0x20c or 0x30c)' CONFIG_RADIO_RTRACK2_PORT 30c
-fi
-dep_tristate '  Aztech/Packard Bell Radio' CONFIG_RADIO_AZTECH $CONFIG_VIDEO_DEV
-if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then
-   hex '    Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350
-fi
-dep_tristate '  GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV
-if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
-   hex '    GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
+if [ "$CONFIG_ISA" = "y" ]; then
+   dep_tristate '  ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV
+   dep_tristate '  AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then
+      hex '  RadioTrack i/o port (0x20f or 0x30f)' CONFIG_RADIO_RTRACK_PORT 20f
+   fi
+   dep_tristate '  AIMSlab RadioTrack II support' CONFIG_RADIO_RTRACK2 $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_RADIO_RTRACK2" = "y" ]; then
+      hex '    RadioTrack II i/o port (0x20c or 0x30c)' CONFIG_RADIO_RTRACK2_PORT 30c
+   fi
+   dep_tristate '  Aztech/Packard Bell Radio' CONFIG_RADIO_AZTECH $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then
+      hex '    Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350
+  fi
+   dep_tristate '  GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
+      hex '    GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
+   fi
 fi
 dep_tristate '  GemTek PCI Radio Card support' CONFIG_RADIO_GEMTEK_PCI $CONFIG_VIDEO_DEV $CONFIG_PCI
 dep_tristate '  Guillemot MAXI Radio FM 2000 radio' CONFIG_RADIO_MAXIRADIO $CONFIG_VIDEO_DEV
 dep_tristate '  Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV
 dep_tristate '  miroSOUND PCM20 radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV $CONFIG_SOUND_ACI_MIXER
-dep_tristate '    miroSOUND PCM20 radio RDS user interface (EXPERIMENTAL)' CONFIG_RADIO_MIROPCM20_RDS $CONFIG_RADIO_MIROPCM20 $CONFIG_EXPERIMENTAL
-dep_tristate '  SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
-dep_tristate '  TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV
-if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then
-   hex '    Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590
-fi
-dep_tristate '  Trust FM radio card' CONFIG_RADIO_TRUST $CONFIG_VIDEO_DEV
-if [ "$CONFIG_RADIO_TRUST" = "y" ]; then
-   hex '    Trust i/o port (usually 0x350 or 0x358)' CONFIG_RADIO_TRUST_PORT 350
-fi
-dep_tristate '  Typhoon Radio (a.k.a. EcoRadio)' CONFIG_RADIO_TYPHOON $CONFIG_VIDEO_DEV
-if [ "$CONFIG_PROC_FS" = "y" ]; then
-   if [ "$CONFIG_RADIO_TYPHOON" != "n" ]; then
-      bool '    Support for /proc/radio-typhoon' CONFIG_RADIO_TYPHOON_PROC_FS
+if [ "$CONFIG_ISA" = "y" ]; then
+   dep_tristate '    miroSOUND PCM20 radio RDS user interface (EXPERIMENTAL)' CONFIG_RADIO_MIROPCM20_RDS $CONFIG_RADIO_MIROPCM20 $CONFIG_EXPERIMENTAL
+   dep_tristate '  SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
+   dep_tristate '  TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then
+      hex '    Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590
+   fi
+   dep_tristate '  Trust FM radio card' CONFIG_RADIO_TRUST $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_RADIO_TRUST" = "y" ]; then
+      hex '    Trust i/o port (usually 0x350 or 0x358)' CONFIG_RADIO_TRUST_PORT 350
+   fi
+   dep_tristate '  Typhoon Radio (a.k.a. EcoRadio)' CONFIG_RADIO_TYPHOON $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_PROC_FS" = "y" ]; then
+      if [ "$CONFIG_RADIO_TYPHOON" != "n" ]; then
+         bool '    Support for /proc/radio-typhoon' CONFIG_RADIO_TYPHOON_PROC_FS
+      fi
+   fi
+   if [ "$CONFIG_RADIO_TYPHOON" = "y" ]; then
+      hex '  Typhoon I/O port (0x316 or 0x336)' CONFIG_RADIO_TYPHOON_PORT 316
+      int '  Typhoon frequency set when muting the device (kHz)' CONFIG_RADIO_TYPHOON_MUTEFREQ 87500
+   fi
+   dep_tristate '  Zoltrix Radio' CONFIG_RADIO_ZOLTRIX $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then
+      hex '    ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c
    fi
 fi
-if [ "$CONFIG_RADIO_TYPHOON" = "y" ]; then
-   hex '  Typhoon I/O port (0x316 or 0x336)' CONFIG_RADIO_TYPHOON_PORT 316
-   int '  Typhoon frequency set when muting the device (kHz)' CONFIG_RADIO_TYPHOON_MUTEFREQ 87500
-fi
-dep_tristate '  Zoltrix Radio' CONFIG_RADIO_ZOLTRIX $CONFIG_VIDEO_DEV
-if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then
-   hex '    ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c
-fi
-
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/radio/radio-gemtek.c linux-2.4.20/drivers/media/radio/radio-gemtek.c
--- linux-2.4.19/drivers/media/radio/radio-gemtek.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.20/drivers/media/radio/radio-gemtek.c	2002-10-29 11:18:30.000000000 +0000
@@ -281,14 +281,14 @@
 	printk(KERN_INFO "GemTek Radio Card driver.\n");
 
 	spin_lock_init(&lock);
- 	/* mute card - prevents noisy bootups */
-	outb(0x10, io);
-	udelay(5);
-	gemtek_unit.muted = 1;
 
 	/* this is _maybe_ unnecessary */
 	outb(0x01, io);
 
+ 	/* mute card - prevents noisy bootups */
+	gemtek_unit.muted = 0;
+	gemtek_mute(&gemtek_unit);
+
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/Makefile linux-2.4.20/drivers/media/video/Makefile
--- linux-2.4.19/drivers/media/video/Makefile	2001-11-09 22:01:22.000000000 +0000
+++ linux-2.4.20/drivers/media/video/Makefile	2002-10-29 11:18:37.000000000 +0000
@@ -1,5 +1,5 @@
 #
-# Makefile for the kernel character device drivers.
+# Makefile for the video capture/playback device drivers.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 # removes any old dependencies. DON'T put your own dependencies here
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/bttv-cards.c linux-2.4.20/drivers/media/video/bttv-cards.c
--- linux-2.4.19/drivers/media/video/bttv-cards.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/media/video/bttv-cards.c	2002-10-29 11:18:40.000000000 +0000
@@ -63,9 +63,9 @@
 static int triton1=0;
 static int vsfx=0;
 int no_overlay=-1;
-static unsigned int card[4]  = { -1, -1, -1, -1 };
-static unsigned int pll[4]   = { -1, -1, -1, -1 };
-static unsigned int tuner[4] = { -1, -1, -1, -1 };
+static unsigned int card[BTTV_MAX]  = { [ 0 ... (BTTV_MAX-1) ] = -1};
+static unsigned int pll[BTTV_MAX]   = { [ 0 ... (BTTV_MAX-1) ] = -1};
+static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = -1};
 #ifdef MODULE
 static unsigned int autoload = 1;
 #else
@@ -83,11 +83,11 @@
 MODULE_PARM_DESC(vsfx,"set VSFX pci config bit "
 		 "[yet another chipset flaw workaround]");
 MODULE_PARM(no_overlay,"i");
-MODULE_PARM(card,"1-4i");
+MODULE_PARM(card,"1-" __stringify(BTTV_MAX) "i");
 MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
-MODULE_PARM(pll,"1-4i");
+MODULE_PARM(pll,"1-" __stringify(BTTV_MAX) "i");
 MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
-MODULE_PARM(tuner,"1-4i");
+MODULE_PARM(tuner,"1-" __stringify(BTTV_MAX) "i");
 MODULE_PARM_DESC(tuner,"specify installed tuner type");
 MODULE_PARM(autoload,"i");
 MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)");
@@ -127,7 +127,7 @@
 } cards[] __devinitdata = {
 	{ 0x13eb0070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV" },
 	{ 0x39000070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV-D" },
-	{ 0x45000070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV/PVR" },
+	{ 0x45000070, BTTV_HAUPPAUGEPVR,  "Hauppauge WinTV/PVR" },
 	{ 0xff000070, BTTV_HAUPPAUGE878,  "Osprey-100" },
 	{ 0xff010070, BTTV_HAUPPAUGE878,  "Osprey-200" },
 
@@ -135,9 +135,10 @@
 	{ 0x00031002, BTTV_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
 
 	{ 0x6606107d, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
+	{ 0x6607107d, BTTV_WINFAST2000,   "Leadtek WinFast VC 100" },
 	{ 0x263610b4, BTTV_STB2,          "STB TV PCI FM, P/N 6000704" },
- 	{ 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCV3/PCI" },
-	{ 0x405010fc, BTTV_GVBCTV4PCI,    "I-O Data Co. GV-BCV4/PCI" },
+ 	{ 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCTV3/PCI" },
+	{ 0x405010fc, BTTV_GVBCTV4PCI,    "I-O Data Co. GV-BCTV4/PCI" },
 
 	{ 0x1200bd11, BTTV_PINNACLE,      "Pinnacle PCTV" },
 	{ 0x001211bd, BTTV_PINNACLE,      "Pinnacle PCTV" },
@@ -163,6 +164,8 @@
 	{ 0x111a153b, BTTV_TERRATVALUE,   "Terratec TValue" },
 	{ 0x1123153b, BTTV_TERRATVRADIO,  "Terratec TV Radio+" },
 	{ 0x1127153b, BTTV_TERRATV,       "Terratec TV+"    },
+	// clashes with FlyVideo
+	//{ 0x18521852, BTTV_TERRATV,     "Terratec TV+"    },
 	{ 0x1134153b, BTTV_TERRATVALUE,   "Terratec TValue" },
 	{ 0x1135153b, BTTV_TERRATVALUER,  "Terratec TValue Radio" },
 	{ 0x5018153b, BTTV_TERRATVALUE,   "Terratec TValue" },
@@ -174,13 +177,14 @@
 
     	{ 0x010115cb, BTTV_GMV1,          "AG GMV1" },
 	{ 0x010114c7, BTTV_MODTEC_205,    "Modular Technology MM205 PCTV" },
-	{ 0x18501851, BTTV_CHRONOS_VS2,   "Flyvideo 98 (LR50)/ Chronos Video Shuttle II" },
-	{ 0x18511851, BTTV_FLYVIDEO98EZ,  "Flyvideo 98EZ (LR51)/ CyberMail AV" },
-	{ 0x18521852, BTTV_TYPHOON_TVIEW, "Flyvideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
+	{ 0x18501851, BTTV_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
+	{ 0x18511851, BTTV_FLYVIDEO98EZ,  "FlyVideo 98EZ (LR51)/ CyberMail AV" },
+	{ 0x18521852, BTTV_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
 	{ 0x10b42636, BTTV_HAUPPAUGE878,  "STB ???" },
 	{ 0x217d6606, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
 	{ 0x03116000, BTTV_SENSORAY311,   "Sensoray 311" },
 	{ 0x00790e11, BTTV_WINDVR,        "Canopus WinDVR PCI" },
+	{ 0xa0fca1a0, BTTV_ZOLTRIX,       "Face to Face Tvmax" },
 
 	{ 0, -1, NULL }
 };
@@ -235,16 +239,16 @@
 },{
 
 /* ---- card 0x04 ---------------------------------- */
-	name:		"Intel",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		-1,
-	gpiomask:	7,
+	name:		"Intel Create and Share PCI/ Smart Video Recorder III",
+	video_inputs:	4,
+	audio_inputs:	0,
+	tuner:		-1,
+	svhs:		2,
+	gpiomask:	0,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 1, 2, 3, 4},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
+	audiomux:	{ 0 },
+	needs_tvaudio:	0,
+	tuner_type:	4,
 },{
 	name:		"Diamond DTV2000",
 	video_inputs:	4,
@@ -283,7 +287,7 @@
 },{
 
 /* ---- card 0x08 ---------------------------------- */
-	name:		"FlyVideo II (Bt848) LR26",
+	name:		"Lifeview FlyVideo II (Bt848) LR26",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -295,7 +299,7 @@
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"IXMicro TurboTV",
+	name:		"IMS/IXmicro TurboTV",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -303,8 +307,9 @@
 	gpiomask:	3,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 1, 1, 2, 3, 0},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
+	needs_tvaudio:	0,
+	pll:		PLL_28,
+	tuner_type:	TUNER_TEMIC_PAL,
 },{
 	name:		"Hauppauge (bt878)",
 	video_inputs:	4,
@@ -331,7 +336,7 @@
 },{
 
 /* ---- card 0x0c ---------------------------------- */
-	name:		"ADS Technologies Channel Surfer TV",
+	name:		"ADS Technologies Channel Surfer TV (bt848)",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -352,7 +357,7 @@
 	audiomux:	{ 13, 14, 11, 7, 0, 0},
 	needs_tvaudio:	1,
 	pll:		PLL_28,
-	tuner_type:	-1,
+	tuner_type:	TUNER_PHILIPS_PAL,
 },{
 	name:		"Aimslab Video Highway Xtreme (VHX)",
 	video_inputs:	3,
@@ -363,6 +368,7 @@
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */
 	needs_tvaudio:	1,
+	pll:		PLL_28,
 	tuner_type:	-1,
 },{
 	name:		"Zoltrix TV-Max",
@@ -378,7 +384,7 @@
 },{
 
 /* ---- card 0x10 ---------------------------------- */
-	name:		"Pixelview PlayTV (bt878)",
+	name:		"Prolink Pixelview PlayTV (bt878)",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -414,8 +420,8 @@
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
-	name:		"LifeView FlyKit w/o Tuner",
-	video_inputs:	3,
+	name:		"Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
+	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		-1,
 	svhs:		-1,
@@ -435,19 +441,18 @@
 	muxsel:		{2, 3, 1, 1},
 	tuner_type:	-1,
 },{
-	name:		"Lucky Star Image World ConferenceTV",
-	video_inputs:	3,
-	audio_inputs:	1,
+	name:		"Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
+	video_inputs:	4,
+	audio_inputs:	2,  // tuner, line in
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	0x00fffe07,
+	gpiomask:	0x1800,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 131072, 1, 1638400, 3, 4},
-	needs_tvaudio:	1,
+	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800},
 	pll:		PLL_28,
 	tuner_type:	TUNER_PHILIPS_PAL_I,
 },{
-	name:		"Phoebe Tv Master + FM (CPH050)",
+	name:		"Askey CPH050/ Phoebe Tv Master + FM",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -456,6 +461,7 @@
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{0, 1, 0x800, 0x400, 0xc00, 0},
 	needs_tvaudio:	1,
+	pll:		PLL_28,
 	tuner_type:	-1,
 },{
 	name:		"Modular Technology MM205 PCTV, bt878",
@@ -472,7 +478,7 @@
 },{
 
 /* ---- card 0x18 ---------------------------------- */
-	name:		"[many vendors] CPH05X/06X (bt878)",
+	name:		"Askey CPH05X/06X (bt878) [many vendors]",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -484,7 +490,7 @@
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"Terratec/Vobis TV-Boostar",
+	name:		"Terratec Terra TV+ Version 1.0 (Bt848)/Vobis TV-Boostar",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -495,7 +501,7 @@
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
-	name:		"Newer Hauppauge WinCam (bt878)",
+	name:		"Hauppauge WinCam newer (bt878)",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -506,15 +512,15 @@
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
-	name:		"MAXI TV Video PCI2",
-	video_inputs:	3,
-	audio_inputs:	1,
+	name:		"Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
+	video_inputs:	4,
+	audio_inputs:	2,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	0xffff,
+	gpiomask:	0x1800,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 1, 2, 3, 0xc00},
-	needs_tvaudio:	1,
+	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800},
+	pll:            PLL_28,
 	tuner_type:	TUNER_PHILIPS_SECAM,
 },{
 
@@ -543,18 +549,18 @@
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
-	name:		"FlyVideo 98",
-	video_inputs:	3,
+	name:		"Lifeview FlyVideo 98 LR50",
+	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
 	gpiomask:	0x1800,  //0x8dfe00
-	muxsel:		{2, 3, 1, 1},
+	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
-	needs_tvaudio:	1,
+	pll:            PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"iProTV",
+	name:		"Formac iProTV",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -566,16 +572,16 @@
 },{
 
 /* ---- card 0x20 ---------------------------------- */
-	name:		"Intel Create and Share PCI",
+	name:		"Intel Create and Share PCI/ Smart Video Recorder III",
 	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		0,
+	audio_inputs:	0,
+	tuner:		-1,
 	svhs:		2,
-	gpiomask:	7,
+	gpiomask:	0,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 4, 4, 4, 4, 4},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
+	audiomux:	{ 0 },
+	needs_tvaudio:	0,
+	tuner_type:	4,
 },{
 	name:		"Terratec TerraTValue",
 	video_inputs:	3,
@@ -589,47 +595,57 @@
 	pll:		PLL_28,
 	tuner_type:	TUNER_PHILIPS_PAL,
 },{
-	name:		"Leadtek WinFast 2000",
-	video_inputs:	3,
+	name:		"Leadtek WinFast 2000/ WinFast 2000 XP",
+	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
 	gpiomask:	0xc33000,
-	muxsel:		{ 2, 3, 1, 1,0},
-	audiomux:	{ 0x422000,0x001000,0x621100,0x620000,0x800000,0x620000},
+	muxsel:		{ 2, 3, 1, 1, 0}, // TV, CVid, SVid, CVid over SVid connector
+	audiomux:	{ 0x422000,0x1000,0x0000,0x620000,0x800000},
+	/* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
+		gpio23 -- hef4052:nEnable (0x800000)
+		gpio12 -- hef4052:A1
+	        gpio13 -- hef4052:A0
+	    0x0000: external audio
+	    0x1000: FM
+	    0x2000: TV
+	    0x3000: n.c.
+          Note: There exists another variant "Winfast 2000" with tv stereo !?
+	  Note: eeprom only contains FF and pci subsystem id 107d:6606
+	 */
 	needs_tvaudio:	0,
 	pll:		PLL_28,
-	tuner_type:	-1,
+	has_radio:	1,
+	tuner_type:	5, // default for now, gpio reads BFFF06 for Pal bg+dk
 	audio_hook:	winfast2000_audio,
 },{
-	name:		"Flyvideo 98 (LR50Q) / Chronos Video Shuttle II",
-	video_inputs:	3,
+	name:		"Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
+	video_inputs:	4,
 	audio_inputs:	3,
 	tuner:		0,
 	svhs:		2,
 	gpiomask:	0x1800,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800},
-	needs_tvaudio:	1,
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
 
 /* ---- card 0x24 ---------------------------------- */
-	name:		"Flyvideo 98FM (LR50Q) / Typhoon TView TV/FM Tuner",
-	video_inputs:	3,
+	name:		"Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
+	video_inputs:	4,
 	audio_inputs:	3,
 	tuner:		0,
 	svhs:		2,
 	gpiomask:	0x1800,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
-	needs_tvaudio:	1,
 	pll:		PLL_28,
 	tuner_type:	-1,
 	has_radio:	1,
 },{
-	name:		"PixelView PlayTV pro",
+	name:		"Prolink PixelView PlayTV pro",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -641,7 +657,7 @@
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"TView99 CPH06X",
+	name:		"Askey CPH06X TView99",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -684,7 +700,7 @@
 	audio_inputs:	4,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	12,
+	gpiomask:	15,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 13, 4, 11, 7, 0, 0},
 	needs_tvaudio:	1,
@@ -700,6 +716,7 @@
 	gpiomask:	0,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0, 0, 0, 0, 0},
+	needs_tvaudio:	1,
 	no_msp34xx:	1,
 	pll:		PLL_28,
 	tuner_type:	1,
@@ -758,9 +775,9 @@
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	0x1f0000,
+	gpiomask:	0x70000,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0xe2ffff, 0xebffff, 0, 0, 0xe0ffff, 0xe2ffff },
+	audiomux:	{ 0x20000, 0x30000, 0x10000, 0, 0x40000, 0x20000 },
 	needs_tvaudio:	1,
 	no_msp34xx:	1,
 	pll:		PLL_35,
@@ -769,7 +786,7 @@
 },{
 
 /* ---- card 0x30 ---------------------------------- */
-	name:		"Dynalink Magic TView ",
+	name:		"Askey CPH03x/ Dynalink Magic TView",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -781,7 +798,7 @@
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"GV-BCTV3",
+	name:		"IODATA GV-BCTV3/PCI",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -828,6 +845,15 @@
 	gpiomask:       0x03000F,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 1, 0x10001, 0, 0, 10},
+			/* sound path (5 sources):
+			   MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable)
+				0= ext. Audio IN
+				1= from MUX2
+				2= Mono TV sound from Tuner
+				3= not connected
+			   MUX2 (mask 0x30000):
+				0,2,3= from MSP34xx
+				1= FM stereo Radio from Tuner */
 	needs_tvaudio:  1,
 	pll:            PLL_28,
 	tuner_type:     -1,
@@ -852,7 +878,7 @@
 		options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
 		audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
 		options tuner type=5 */
-	name:		"Lifetec LT 9415 TV (LR90 Rev.F)",
+	name:		"Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -860,17 +886,16 @@
 	gpiomask:	0x18e0,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0x0000,0x0800,0x1000,0x1000,0x18e0 },
-		       /* 0x0000: Tuner normal stereo
+		       /* For cards with tda9820/tda9821:
+			  0x0000: Tuner normal stereo
 			  0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
 			  0x0880: Tuner A2 stereo */
 	pll:		PLL_28,
-	tuner_type:	TUNER_PHILIPS_PAL,
-	audio_hook:	lt9415_audio,
-	has_radio:	1,
+	tuner_type:	-1,
 },{
 	/* Miguel Angel Alvarez <maacruz@navegalia.com>
 	   old Easy TV BT848 version (model CPH031) */
-	name:           "BESTBUY Easy TV (CPH031)",
+	name:           "Askey CPH031/ BESTBUY Easy TV",
 	video_inputs:	4,
 	audio_inputs:   1,
 	tuner:          0,
@@ -885,15 +910,14 @@
 
 /* ---- card 0x38 ---------------------------------- */
 	/* Gordon Heydon <gjheydon@bigfoot.com ('98) */
-	name:           "FlyVideo '98/FM",
-	video_inputs:   3,
+	name:           "Lifeview FlyVideo 98FM LR50",
+	video_inputs:   4,
 	audio_inputs:   3,
 	tuner:          0,
 	svhs:           2,
 	gpiomask:       0x1800,
-	muxsel:         { 2, 3, 0, 1},
+	muxsel:         { 2, 3, 1, 1},
 	audiomux:       { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
-	needs_tvaudio:  1,
 	pll:            PLL_28,
 	tuner_type:     5,
 },{
@@ -914,7 +938,7 @@
 	tuner_type:     -1,
 },{
         /* Daniel Herrington <daniel.herrington@home.com> */
-        name:           "Phoebe TV Master Only (No FM) CPH060",
+        name:           "Askey CPH060/ Phoebe TV Master Only (No FM)",
         video_inputs:   3,
         audio_inputs:   1,
         tuner:          0,
@@ -923,11 +947,11 @@
         muxsel:         { 2, 3, 1, 1},
         audiomux:       { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
         needs_tvaudio:  1,
-        pll:            PLL_NONE,
+        pll:            PLL_28,
         tuner_type:     TUNER_TEMIC_4036FY5_NTSC,
 },{
 	/* Matti Mottus <mottus@physic.ut.ee> */
-	name:		"TV Capturer (CPH03X)",
+	name:		"Askey CPH03x TV Capturer",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -944,10 +968,12 @@
 	name:           "Modular Technology MM100PCTV",
 	video_inputs:   2,
 	audio_inputs:   2,
+	tuner:		0,
+	svhs:		-1,
 	gpiomask:       11,
 	muxsel:         { 2, 3, 1, 1},
 	audiomux:       { 2, 0, 0, 1, 8},
-	pll:            PLL_NONE,
+	pll:            PLL_35,
 	tuner_type:     TUNER_TEMIC_PAL,
 
 },{
@@ -968,7 +994,7 @@
 	/* Miguel Angel Alvarez <maacruz@navegalia.com>
 	   new Easy TV BT878 version (model CPH061) 
 	   special thanks to Informatica Mieres for providing the card */
-	name:           "BESTBUY Easy TV (bt878)",
+	name:           "Askey CPH061/ BESTBUY Easy TV (bt878)",
 	video_inputs:	3,
 	audio_inputs:   2,
 	tuner:          0,
@@ -1008,7 +1034,7 @@
 	tuner_type:	TUNER_TEMIC_4006FN5_MULTI_PAL,
 },{
 	/* DeeJay <deejay@westel900.net (2000S) */
-	name:           "FlyVideo 2000S",
+	name:           "Lifeview FlyVideo 2000S LR90",
 	video_inputs:   3,
 	audio_inputs:   3,
 	tuner:          0,
@@ -1016,7 +1042,7 @@
 	gpiomask:	0x18e0,
 	muxsel:		{ 2, 3, 0, 1},
 			/* Radio changed from 1e80 to 0x800 to make
-			   Flyvideo2000S in .hu happy (gm)*/
+			   FlyVideo2000S in .hu happy (gm)*/
 			/* -dk-???: set mute=0x1800 for tda9874h daughterboard */
 	audiomux:	{ 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 },
 	audio_hook:	fv2000s_audio,
@@ -1040,7 +1066,7 @@
 	has_radio:	1,
 },{
 	/* TANAKA Kei <peg00625@nifty.com> */
-	name:           "GV-BCTV4/PCI",
+	name:           "IODATA GV-BCTV4/PCI",
 	video_inputs:   3,
 	audio_inputs:   1,
 	tuner:          0,
@@ -1084,7 +1110,7 @@
 	gpiomask:       0
 },{
         /* Tomasz Pyra <hellfire@sedez.iq.pl> */
-        name:           "PV-BT878P+",
+        name:           "Prolink Pixelview PV-BT878P+ (Rev.4C)",
         video_inputs:   3,
         audio_inputs:   4,
         tuner:          0,
@@ -1096,7 +1122,7 @@
         pll:            PLL_28,
         tuner_type:     25,
 },{
-	name:		"Flyvideo 98EZ (capture only)",
+	name:		"Lifeview FlyVideo 98EZ (capture only) LR51",
 	video_inputs:	4,
 	audio_inputs:   0,
 	tuner:		-1,
@@ -1108,7 +1134,7 @@
 
 /* ---- card 0x48 ---------------------------------- */
 	/* Dariusz Kowalewski <darekk@automex.pl> */
-	name:		"Prolink PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
+	name:		"Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -1141,8 +1167,8 @@
 	name:           "RemoteVision MX (RV605)",
 	video_inputs:   16,
 	audio_inputs:   0,
-	tuner:          0,
-	svhs:           0,
+	tuner:          -1,
+	svhs:           -1,
 	gpiomask:       0x00,
 	gpiomask2:      0x07ff,
 	muxsel:         { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
@@ -1155,6 +1181,7 @@
         name:           "Powercolor MTV878/ MTV878R/ MTV878F",
         video_inputs:   3,
         audio_inputs:   2, 
+	tuner:		0,
         svhs:           2,
         gpiomask:       0x1C800F,  // Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset
         muxsel:         { 2, 1, 1, },
@@ -1191,15 +1218,57 @@
         pll:            PLL_28,
         tuner_type:     -1,
 },{
-	/* http://www.aopen.com/products/video/va1000.htm */
-	name:           "AOPEN VA1000",
-	video_inputs:   3, /* coax, AV, s-vid */
-	audio_inputs:   1,
-	tuner:          0,
-	tuner_type:     TUNER_LG_PAL, /* actually TP18PSB12P (PAL B/G) */
-	audiomux:       { 2, 0, 0, 0 },
-	muxsel:         { 2, 3, 1, 0 },
-	pll:            PLL_28,
+        name:           "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
+        video_inputs:   4,
+        audio_inputs:   3, 
+        tuner:          0,
+        svhs:           2,
+        gpiomask:       7,
+        muxsel:         { 2, 3, 1, 1 },   // Tuner, SVid, SVHS, SVid to SVHS connector
+        audiomux:       { 0 ,0 ,4, 4,4,4},// Yes, this tuner uses the same audio output for TV and FM radio!
+					  // This card lacks external Audio In, so we mute it on Ext. & Int.
+					  // The PCB can take a sbx1637/sbx1673, wiring unknown.
+					  // This card lacks PCI subsystem ID, sigh.
+					  // audiomux=1: lower volume, 2+3: mute
+					  // btwincap uses 0x80000/0x80003
+        needs_tvaudio:  0,
+        no_msp34xx:     1,
+        pll:            PLL_28,
+        tuner_type:     5, // Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
+			   // radio signal strength indicators work fine.
+	has_radio:		1,
+	/* GPIO Info:
+		GPIO0,1:   HEF4052 A0,A1
+		GPIO2:     HEF4052 nENABLE
+		GPIO3-7:   n.c.
+		GPIO8-13:  IRDC357 data0,5 (data6 n.c. ?) [chip not present on my card]
+		GPIO14,15: ??
+		GPIO16-21: n.c.
+		GPIO22,23: ??
+		??       : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/
+},{
+        /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
+        name:           "DSP Design TCVIDEO",
+        video_inputs:   4,
+        svhs:           -1,
+        muxsel:         { 2, 3, 1, 0},
+        pll:            PLL_28,
+        tuner_type:     -1,
+},{
+
+        /* ---- card 0x50 ---------------------------------- */
+	name:           "Hauppauge WinTV PVR",
+        video_inputs:   4,
+        audio_inputs:   1,
+        tuner:          0,
+        svhs:           2,
+        muxsel:         { 2, 0, 1, 1},
+        needs_tvaudio:  1,
+        pll:            PLL_28,
+        tuner_type:     -1,
+
+	gpiomask:       7,
+	audiomux:       {7},
 }};
 
 const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard));
@@ -1289,8 +1358,8 @@
  */
 
 static void flyvideo_gpio(struct bttv *btv)
-{
-	int gpio,outbits;
+{ 
+	int gpio,outbits,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
 	int tuner=-1,ttype;
 	
 	outbits = btread(BT848_GPIO_OUT_EN);
@@ -1299,29 +1368,56 @@
 	gpio=btread(BT848_GPIO_DATA);
 	btwrite(outbits, BT848_GPIO_OUT_EN);
 	// all cards provide GPIO info, some have an additional eeprom
+	// LR50: GPIO coding can be found lower right CP1 .. CP9
+	//       CP9=GPIO23 .. CP1=GPIO15; when OPEN, the corresponding GPIO reads 1.
+	//       GPIO14-12: n.c.
+	// LR90: GP9=GPIO23 .. GP1=GPIO15 (right above the bt878)
 	
 	// lowest 3 bytes are remote control codes (no handshake needed)
+        // xxxFFF: No remote control chip soldered
+        // xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered 
+	// Note: Some bits are Audio_Mask !
+
 	ttype=(gpio&0x0f0000)>>16;
 	switch(ttype) {
-	case 0: tuner=4; // None
+	case 0x0: tuner=4; // None
 		break;
-	case 4: tuner=5; // Philips PAL
+        case 0x2: tuner=39;// LG NTSC (newer TAPC series) TAPC-H701P
 		break;
-	case 6: tuner=37; // LG PAL (newer TAPC series)
+	case 0x4: tuner=5; // Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216
 		break;
-	case 0xC: tuner=3; // Philips SECAM(+PAL)
+	case 0x6: tuner=37; // LG PAL (newer TAPC series) TAPC-G702P
+		break;
+	case 0xC: tuner=3; // Philips SECAM(+PAL) FQ1216ME or FI1216MF
 		break;
 	default:
-		printk(KERN_INFO "bttv%d: flyvideo_gpio: unknown tuner type.\n", btv->nr);
+		printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->nr);
 	}
-	
-	printk(KERN_INFO "bttv%d: Flyvideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", 
-	       btv->nr,
-	       gpio&0x400000? "yes":"no",
-	       gpio&0x800000? "yes":"no", tuner, gpio);
-	
-	btv->tuner_type = tuner;
-	btv->has_radio = gpio&0x400000? 1:0; 
+
+	has_remote          =   gpio & 0x800000;
+	has_radio	    =   gpio & 0x400000;
+	//   unknown                   0x200000;
+	//   unknown2                  0x100000;
+        is_capture_only     = !(gpio & 0x008000); //GPIO15
+	has_tda9820_tda9821 = !(gpio & 0x004000);
+	is_lr90             = !(gpio & 0x002000); // else LR26/LR50 (LR38/LR51 f. capture only)
+        //		        gpio & 0x001000 // output bit for audio routing
+
+	printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", 
+	       btv->nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio); 
+	printk(KERN_INFO "bttv%d: FlyVideo  LR90=%s tda9821/tda9820=%s capture_only=%s\n",
+		btv->nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ", 
+		is_capture_only?"yes":"no ");
+
+	if(tuner!= -1) // only set if known tuner autodetected, else let insmod option through
+		btv->tuner_type = tuner;
+	btv->has_radio = has_radio;  
+
+	// LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
+        // LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
+	// Audio options: from tuner, from tda9821/tda9821(mono,stereo.sap), from tda9874, ext., mute
+	if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio;
+	//todo: if(has_tda9874) btv->audio_hook = fv2000s_audio;
 }
 
 int miro_tunermap[] = { 0,6,2,3,   4,5,6,0,  3,0,4,5,  5,2,16,1,
@@ -1329,86 +1425,98 @@
 int miro_fmtuner[]  = { 0,0,0,0,   0,0,0,0,  0,0,0,0,  0,0,0,1,
 			1,1,1,1,   1,1,1,0,  0,0,0,0,  0,0,0,0 };
 
+static void miro_pinnacle_gpio(struct bttv *btv)
+{
+	int id,msp;
+	
+	id  = ((btread(BT848_GPIO_DATA)>>10) & 31) -1;
+	msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
+	btv->tuner_type = miro_tunermap[id];
+	if (0 == (btread(BT848_GPIO_DATA) & 0x20)) {
+		btv->has_radio = 1;
+		if (!miro_fmtuner[id]) {
+			btv->has_matchbox = 1;
+			btv->mbox_we    = (1<<6);
+			btv->mbox_most  = (1<<7);
+			btv->mbox_clk   = (1<<8);
+			btv->mbox_data  = (1<<9);
+			btv->mbox_mask  = (1<<6)|(1<<7)|(1<<8)|(1<<9);
+		}
+	} else {
+		btv->has_radio = 0;
+	}
+	if (-1 != msp) {
+		if (btv->type == BTTV_MIRO)
+			btv->type = BTTV_MIROPRO;
+		if (btv->type == BTTV_PINNACLE)
+			btv->type = BTTV_PINNACLEPRO;
+	}
+	printk(KERN_INFO "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
+	       btv->nr, id+1, btv->tuner_type,
+	       !btv->has_radio ? "no" :
+	       (btv->has_matchbox ? "matchbox" : "fmtuner"),
+	       (-1 == msp) ? "no" : "yes");
+}
+
 /* initialization part one -- before registering i2c bus */
 void __devinit bttv_init_card1(struct bttv *btv)
 {
-        if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878)
+	switch (btv->type) {
+	case BTTV_HAUPPAUGE:
+	case BTTV_HAUPPAUGE878:
                 boot_msp34xx(btv,5);
-	if (btv->type == BTTV_VOODOOTV_FM)
-		boot_msp34xx(btv,20);
+		break;
+	case BTTV_VOODOOTV_FM:
+                boot_msp34xx(btv,20);
+		break;
+	case BTTV_HAUPPAUGEPVR:
+		pvr_boot(btv);
+		break;
+	}
 }
 
-/* initialization part one -- after registering i2c bus */
+/* initialization part two -- after registering i2c bus */
 void __devinit bttv_init_card2(struct bttv *btv)
 {
-	/* miro/pinnacle */
-        if (btv->type == BTTV_MIRO      ||
-	    btv->type == BTTV_MIROPRO   ||
-	    btv->type == BTTV_PINNACLE  ||
-	    btv->type == BTTV_PINNACLEPRO) {
-		int id,msp;
-		id  = ((btread(BT848_GPIO_DATA)>>10) & 31) -1;
-		msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
-		btv->tuner_type = miro_tunermap[id];
-		if (0 == (btread(BT848_GPIO_DATA) & 0x20)) {
-			btv->has_radio = 1;
-			if (!miro_fmtuner[id]) {
-				btv->has_matchbox = 1;
-				btv->mbox_we    = (1<<6);
-				btv->mbox_most  = (1<<7);
-				btv->mbox_clk   = (1<<8);
-				btv->mbox_data  = (1<<9);
-				btv->mbox_mask  = (1<<6)|(1<<7)|(1<<8)|(1<<9);
-			}
-		} else {
-			btv->has_radio = 0;
-		}
-		if (-1 != msp) {
-			if (btv->type == BTTV_MIRO)
-				btv->type = BTTV_MIROPRO;
-			if (btv->type == BTTV_PINNACLE)
-				btv->type = BTTV_PINNACLEPRO;
-		}
-		if (bttv_verbose)
-			printk(KERN_INFO "bttv%d: miro: id=%d tuner=%d "
-			       "radio=%s stereo=%s\n",
-			       btv->nr, id+1, btv->tuner_type,
-			       !btv->has_radio ? "no" :
-				   (btv->has_matchbox ? "matchbox" : "fmtuner"),
-			       (-1 == msp) ? "no" : "yes");
-#if 0
-		if (btv->has_matchbox) {
-			if (bttv_verbose)
-				printk(KERN_INFO "Initializing TEA5757...\n");
-			init_tea5757(btv);
-		}
-#endif
-	}
+        btv->tuner_type = -1;
 
-	if (btv->type == BTTV_FLYVIDEO_98    ||
-	    btv->type == BTTV_FLYVIDEO       ||
-	    btv->type == BTTV_TYPHOON_TVIEW  ||
-	    btv->type == BTTV_CHRONOS_VS2    ||
-	    btv->type == BTTV_FLYVIDEO_98FM  ||
-	    btv->type == BTTV_FLYVIDEO2000   ||
-	    btv->type == BTTV_FLYVIDEO98EZ)
+	switch (btv->type) {
+	case BTTV_MIRO:
+	case BTTV_MIROPRO:
+	case BTTV_PINNACLE:
+	case BTTV_PINNACLEPRO: 
+		/* miro/pinnacle */
+		miro_pinnacle_gpio(btv);
+		break;
+	case BTTV_FLYVIDEO_98:
+	case BTTV_MAXI:
+	case BTTV_LIFE_FLYKIT:
+	case BTTV_FLYVIDEO:
+	case BTTV_TYPHOON_TVIEW:
+	case BTTV_CHRONOS_VS2:
+	case BTTV_FLYVIDEO_98FM:
+	case BTTV_FLYVIDEO2000:
+	case BTTV_FLYVIDEO98EZ:
+	case BTTV_CONFERENCETV:
+	case BTTV_LIFETEC_9415:
 		flyvideo_gpio(btv);
-
-        if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) {
+		break;
+	case BTTV_HAUPPAUGE:
+	case BTTV_HAUPPAUGE878:
+	case BTTV_HAUPPAUGEPVR:
 		/* pick up some config infos from the eeprom */
 		bttv_readee(btv,eeprom_data,0xa0);
                 hauppauge_eeprom(btv);
-        }
-
-	if (btv->type == BTTV_AVERMEDIA98 || btv->type == BTTV_AVPHONE98) {
+		break;
+	case BTTV_AVERMEDIA98:
+	case BTTV_AVPHONE98:
 		bttv_readee(btv,eeprom_data,0xa0);
 		avermedia_eeprom(btv);
-	}
-
- 	if (btv->type == BTTV_PXC200)
+		break;
+	case BTTV_PXC200:
 		init_PXC200(btv);
-
-	if (btv->type == BTTV_VHX) {
+		break;
+	case BTTV_VHX:
 		btv->has_radio    = 1;
 		btv->has_matchbox = 1;
 		btv->mbox_we      = 0x20;
@@ -1416,20 +1524,13 @@
 		btv->mbox_clk     = 0x08;
 		btv->mbox_data    = 0x10;
 		btv->mbox_mask    = 0x38;
-	}
-
-	if (btv->type == BTTV_LIFETEC_9415) {
-		if (btread(BT848_GPIO_DATA) & 0x4000)
-			printk("bttv%d: lifetec: tv mono/fm stereo card\n", btv->nr);
-		else
-			printk("bttv%d: lifetec: stereo(TDA9821) card\n",btv->nr);
-	}
-
-	if (btv->type == BTTV_MAGICTVIEW061) {
-		if(btv->cardid == 0x4002144f) {
+		break;
+	case BTTV_MAGICTVIEW061:
+		if (btv->cardid == 0x4002144f) {
 			btv->has_radio=1;
 			printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->nr);
 		}
+		break;
 	}
 
 	/* pll configuration */
@@ -1465,17 +1566,22 @@
                 }
         }
 
-	/* tuner configuration (from card list / insmod option) */
+	/* tuner configuration (from card list / autodetect / insmod option) */
  	if (-1 != bttv_tvcards[btv->type].tuner_type)
-                btv->tuner_type = bttv_tvcards[btv->type].tuner_type;
+		if( -1 == btv->tuner_type) 
+                	btv->tuner_type = bttv_tvcards[btv->type].tuner_type;
 	if (-1 != tuner[btv->nr])
 		btv->tuner_type = tuner[btv->nr];
 	if (btv->tuner_type != -1)
 		bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
+	printk("bttv%d: using tuner=%d\n",btv->nr,btv->tuner_type);
 
 	if (bttv_tvcards[btv->type].has_radio)
 		btv->has_radio=1;
 
+	if (bttv_tvcards[btv->type].audio_hook)
+		btv->audio_hook=bttv_tvcards[btv->type].audio_hook;
+
 	/* try to detect audio/fader chips */
 	if (!bttv_tvcards[btv->type].no_msp34xx &&
 	    bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) {
@@ -1597,6 +1703,85 @@
 		       btv->tuner_type, radio ? "yes" : "no");
 }
 
+/* ----------------------------------------------------------------------- */
+
+/*
+ * minimal bootstrap for the WinTV/PVR -- upload altera firmware.
+ *
+ * The hcwamc.rbf firmware file is on the Hauppauge driver CD.  Have
+ * a look at Pvr/pvr45xxx.EXE (self-extracting zip archive, can be
+ * unpacked with unzip).
+ */
+static char *firm_altera = "/usr/lib/video4linux/hcwamc.rbf";
+MODULE_PARM(firm_altera,"s");
+MODULE_PARM_DESC(firm_altera,"WinTV/PVR firmware "
+		 "(driver CD => unzip pvr45xxx.exe => hcwamc.rbf)");
+
+/* drivers/sound/sound_firmware.c => soundcore.o */
+extern int mod_firmware_load(const char *fn, char **fp);
+
+#define PVR_GPIO_DELAY		10
+
+#define BTTV_ALT_DATA		0x000001
+#define BTTV_ALT_DCLK		0x100000
+#define BTTV_ALT_NCONFIG	0x800000
+
+static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen)
+{
+	u32 n;
+  	u8 bits;
+	int i;
+ 
+	btwrite(BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG,
+		BT848_GPIO_OUT_EN);
+	btwrite(0,BT848_GPIO_DATA);
+	udelay(PVR_GPIO_DELAY);
+	
+	btwrite(BTTV_ALT_NCONFIG,BT848_GPIO_DATA);
+	udelay(PVR_GPIO_DELAY);
+
+	for (n = 0; n < microlen; n++) {
+		bits = micro[n];
+		for ( i = 0 ; i < 8 ; i++ ) {
+			btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA);
+			if (bits & 0x01) 
+				btor(BTTV_ALT_DATA,BT848_GPIO_DATA);
+			else 
+				btand(~BTTV_ALT_DATA,BT848_GPIO_DATA);
+			btor(BTTV_ALT_DCLK,BT848_GPIO_DATA);
+			bits >>= 1;
+		}
+	}
+	btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA);
+	udelay(PVR_GPIO_DELAY);
+	
+	/* begin Altera init loop (Not necessary,but doesn't hurt) */
+	for (i = 0 ; i < 30 ; i++) {
+		btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA);
+		btor(BTTV_ALT_DCLK,BT848_GPIO_DATA);
+	}
+	btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA);
+	return 0;
+}
+
+int __devinit pvr_boot(struct bttv *btv)
+{
+	u32 microlen;
+	u8 *micro;
+	int result;
+
+	microlen = mod_firmware_load(firm_altera, (char**) &micro);
+	if (!microlen)
+		return -1;
+	
+	printk(KERN_INFO "bttv%d: uploading altera firmware [%s] ...\n",
+	       btv->nr, firm_altera);
+	result = pvr_altera_load(btv, micro, microlen);
+	printk(KERN_INFO "bttv%d: ... upload %s\n",
+	       btv->nr, (result < 0) ? "failed" : "ok");
+	vfree(micro);
+	return result;
+}
 
 /* ----------------------------------------------------------------------- */
 /* AVermedia specific stuff, from  bktr_card.c                             */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/bttv-driver.c linux-2.4.20/drivers/media/video/bttv-driver.c
--- linux-2.4.19/drivers/media/video/bttv-driver.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/media/video/bttv-driver.c	2002-10-29 11:18:49.000000000 +0000
@@ -43,6 +43,7 @@
 #include <linux/kmod.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
+#include <linux/pagemap.h>
 
 #include "bttvp.h"
 #include "tuner.h"
@@ -65,8 +66,10 @@
 static unsigned int radio[BTTV_MAX];
 static unsigned int fieldnr = 0;
 static unsigned int irq_debug = 0;
-static unsigned int gbuffers = 2;
+static unsigned int gbuffers = 4;
 static unsigned int gbufsize = BTTV_MAX_FBUF;
+static int latency = -1;
+
 static unsigned int combfilter = 0;
 static unsigned int lumafilter = 0;
 static unsigned int automute = 1;
@@ -80,7 +83,7 @@
 unsigned int bttv_gpio = 0;
 
 /* insmod options */
-MODULE_PARM(radio,"1-4i");
+MODULE_PARM(radio,"1-" __stringify(BTTV_MAX) "i");
 MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
 MODULE_PARM(bigendian,"i");
 MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
@@ -98,6 +101,8 @@
 MODULE_PARM_DESC(gbuffers,"number of capture buffers, default is 2 (64 max)");
 MODULE_PARM(gbufsize,"i");
 MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
+MODULE_PARM(latency,"i");
+MODULE_PARM_DESC(latency,"pci latency timer");
 
 MODULE_PARM(combfilter,"i");
 MODULE_PARM(lumafilter,"i");
@@ -137,64 +142,14 @@
 /* Memory management functions */
 /*******************************/
 
-#define MDEBUG(x)	do { } while(0)		/* Debug memory management */
-
-/* [DaveM] I've recoded most of this so that:
- * 1) It's easier to tell what is happening
- * 2) It's more portable, especially for translating things
- *    out of vmalloc mapped areas in the kernel.
- * 3) Less unnecessary translations happen.
- *
- * The code used to assume that the kernel vmalloc mappings
- * existed in the page tables of every process, this is simply
- * not guarenteed.  We now use pgd_offset_k which is the
- * defined way to get at the kernel page tables.
- */
-
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
-        unsigned long ret = 0UL;
-	pmd_t *pmd;
-	pte_t *ptep, pte;
-  
-	if (!pgd_none(*pgd)) {
-                pmd = pmd_offset(pgd, adr);
-                if (!pmd_none(*pmd)) {
-                        ptep = pte_offset(pmd, adr);
-                        pte = *ptep;
-                        if(pte_present(pte)) {
-				ret  = (unsigned long) page_address(pte_page(pte));
-				ret |= (adr & (PAGE_SIZE - 1));
-				
-			}
-                }
-        }
-        MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
-	return ret;
-}
-
-static inline unsigned long uvirt_to_bus(unsigned long adr) 
-{
-        unsigned long kva, ret;
-
-        kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
-	ret = virt_to_bus((void *)kva);
-        MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
-        return ret;
-}
 
 static inline unsigned long kvirt_to_bus(unsigned long adr) 
 {
-        unsigned long va, kva, ret;
+        unsigned long kva;
 
-        va = VMALLOC_VMADDR(adr);
-        kva = uvirt_to_kva(pgd_offset_k(va), va);
-	ret = virt_to_bus((void *)kva);
-        MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
-        return ret;
+	kva = (unsigned long)page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */   
+	return virt_to_bus((void *)kva);
 }
 
 /* Here we want the physical address of the memory.
@@ -203,19 +158,18 @@
  */
 static inline unsigned long kvirt_to_pa(unsigned long adr) 
 {
-        unsigned long va, kva, ret;
+        unsigned long kva;
 
-        va = VMALLOC_VMADDR(adr);
-        kva = uvirt_to_kva(pgd_offset_k(va), va);
-	ret = __pa(kva);
-        MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
-        return ret;
+	kva = (unsigned long)page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+	return __pa(kva);
 }
 
 static void * rvmalloc(signed long size)
 {
+	struct page *page;
 	void * mem;
-	unsigned long adr, page;
+	unsigned long adr;
 
 	mem=vmalloc_32(size);
 	if (NULL == mem)
@@ -224,10 +178,9 @@
 		/* Clear the ram out, no junk to the user */
 		memset(mem, 0, size);
 	        adr=(unsigned long) mem;
-		while (size > 0) 
-                {
-	                page = kvirt_to_pa(adr);
-			mem_map_reserve(virt_to_page(__va(page)));
+		while (size > 0) {
+			page = vmalloc_to_page((void *)adr);
+			mem_map_reserve(page);
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -237,15 +190,14 @@
 
 static void rvfree(void * mem, signed long size)
 {
-        unsigned long adr, page;
+	struct page *page;
+        unsigned long adr;
         
-	if (mem) 
-	{
+	if (mem) {
 	        adr=(unsigned long) mem;
-		while (size > 0) 
-                {
-	                page = kvirt_to_pa(adr);
-			mem_map_unreserve(virt_to_page(__va(page)));
+		while (size > 0) {
+			page = vmalloc_to_page((void *)adr);
+			mem_map_unreserve(page);
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -290,8 +242,10 @@
 
 static void audio(struct bttv *btv, int mode)
 {
-	btaor(bttv_tvcards[btv->type].gpiomask, ~bttv_tvcards[btv->type].gpiomask,
-              BT848_GPIO_OUT_EN);
+	if (bttv_tvcards[btv->type].gpiomask)
+		btaor(bttv_tvcards[btv->type].gpiomask,
+		      ~bttv_tvcards[btv->type].gpiomask,
+		      BT848_GPIO_OUT_EN);
 
 	switch (mode)
 	{
@@ -318,8 +272,10 @@
 	        mode=AUDIO_OFF;
         if ((mode == AUDIO_TUNER) && (btv->radio))
 		mode = AUDIO_RADIO;
-	btaor(bttv_tvcards[btv->type].audiomux[mode],
-              ~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
+	if (bttv_tvcards[btv->type].gpiomask)
+		btaor(bttv_tvcards[btv->type].audiomux[mode],
+		      ~bttv_tvcards[btv->type].gpiomask,
+		      BT848_GPIO_DATA);
 	if (bttv_gpio)
 		bttv_gpio_tracking(btv,audio_modes[mode]);
 	if (!in_interrupt())
@@ -435,8 +391,10 @@
 static void bt848_muxsel(struct bttv *btv, unsigned int input)
 {
         /* needed by RemoteVideo MX */
-	btaor(bttv_tvcards[btv->type].gpiomask2,~bttv_tvcards[btv->type].gpiomask2,
-              BT848_GPIO_OUT_EN);
+	if (bttv_tvcards[btv->type].gpiomask2)
+		btaor(bttv_tvcards[btv->type].gpiomask2,
+		      ~bttv_tvcards[btv->type].gpiomask2,
+		      BT848_GPIO_OUT_EN);
 
 	/* This seems to get rid of some synchronization problems */
 	btand(~(3<<5), BT848_IFORM);
@@ -458,12 +416,14 @@
 	audio(btv, (input!=bttv_tvcards[btv->type].tuner) ?
               AUDIO_EXTERN : AUDIO_TUNER);
 
-	btaor(bttv_tvcards[btv->type].muxsel[input]>>4,
-		~bttv_tvcards[btv->type].gpiomask2, BT848_GPIO_DATA);
+	if (bttv_tvcards[btv->type].gpiomask2)
+		btaor(bttv_tvcards[btv->type].muxsel[input]>>4,
+		      ~bttv_tvcards[btv->type].gpiomask2,
+		      BT848_GPIO_DATA);
 
 	/* card specific hook */
-	if( bttv_tvcards[btv->type].muxsel_hook )
-		bttv_tvcards[btv->type].muxsel_hook ( btv, input );
+	if (bttv_tvcards[btv->type].muxsel_hook)
+		bttv_tvcards[btv->type].muxsel_hook(btv, input);
 
 	if (bttv_gpio)
 		bttv_gpio_tracking(btv,"muxsel");
@@ -1255,7 +1215,8 @@
 static long bttv_read(struct video_device *v, char *buf, unsigned long count, int nonblock)
 {
 	struct bttv *btv= (struct bttv *)v;
-	int q,todo;
+	int q;
+	unsigned long todo;
 	DECLARE_WAITQUEUE(wait, current);
 
 	/* BROKEN: RETURNS VBI WHEN IT SHOULD RETURN GRABBED VIDEO FRAME */
@@ -1583,7 +1544,7 @@
 		bt848_muxsel(btv, v.channel);
 		btv->channel=v.channel;
 		if (btv->win.norm != v.norm) {
-			if(btv->type== BTTV_VOODOOTV_FM)
+			if (btv->type == BTTV_VOODOOTV_FM)
 				bttv_tda9880_setnorm(btv,v.norm);
 			btv->win.norm = v.norm;
 			make_vbitab(btv);
@@ -1874,8 +1835,8 @@
 		bttv_call_i2c_clients(btv,cmd,&v);
 
 		/* card specific hooks */
-		if (bttv_tvcards[btv->type].audio_hook)
-			bttv_tvcards[btv->type].audio_hook(btv,&v,0);
+		if (btv->audio_hook)
+			btv->audio_hook(btv,&v,0);
 
 		if(copy_to_user(arg,&v,sizeof(v)))
 			return -EFAULT;
@@ -1902,8 +1863,8 @@
 		bttv_call_i2c_clients(btv,cmd,&v);
 		
 		/* card specific hooks */
-		if (bttv_tvcards[btv->type].audio_hook)
-			bttv_tvcards[btv->type].audio_hook(btv,&v,1);
+		if (btv->audio_hook)
+			btv->audio_hook(btv,&v,1);
 
 		btv->audio_dev=v;
 		up(&btv->lock);
@@ -2483,27 +2444,22 @@
 		bt848_dma(btv, 0);
 }
 
-# define do_video_register(dev,type,nr) video_register_device(dev,type,nr)
-
 static int __devinit init_video_dev(struct bttv *btv)
 {
 	audio(btv, AUDIO_MUTE);
         
-	if(do_video_register(&btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
+	if (video_register_device(&btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
 		return -1;
 	printk(KERN_INFO "bttv%d: registered device video%d\n",
 	       btv->nr,btv->video_dev.minor & 0x1f);
-	if(do_video_register(&btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) 
-        {
+	if (video_register_device(&btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) {
 	        video_unregister_device(&btv->video_dev);
 		return -1;
 	}
 	printk(KERN_INFO "bttv%d: registered device vbi%d\n",
 	       btv->nr,btv->vbi_dev.minor & 0x1f);
-	if (btv->has_radio)
-	{
-		if(do_video_register(&btv->radio_dev, VFL_TYPE_RADIO, radio_nr)<0) 
-                {
+	if (btv->has_radio) {
+		if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO, radio_nr)<0) {
 		        video_unregister_device(&btv->vbi_dev);
 		        video_unregister_device(&btv->video_dev);
 			return -1;
@@ -2524,13 +2480,14 @@
 
 	/* dump current state of the gpio registers before changing them,
 	 * might help to make a new card work */
-	if (bttv_gpio)
+	if (bttv_gpio) {
+		bttv_gpio_tracking(btv,"init #1");
 		bttv_gpio_tracking(btv,"init #1");
+	}
 
 	/* reset the bt848 */
 	btwrite(0, BT848_SRESET);
-	DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%lx\n", btv->nr, (unsigned long) btv->bt848_mem));
-
+	
 	/* not registered yet */
 	btv->video_dev.minor = -1;
 	btv->radio_dev.minor = -1;
@@ -2973,12 +2930,17 @@
         else
                 btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA);
 
+	if (-1 != latency) {
+		printk(KERN_INFO "bttv%d: setting pci latency timer to %d\n",
+		       bttv_num,latency);
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
+	}
         pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
         pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
         printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %02x:%02x.%x, ",
                bttv_num,btv->id, btv->revision, dev->bus->number,
 	       PCI_SLOT(dev->devfn),PCI_FUNC(dev->devfn));
-        printk("irq: %d, latency: %d, memory: 0x%lx\n",
+        printk("irq: %d, latency: %d, mmio: 0x%lx\n",
 	       btv->dev->irq, lat, btv->bt848_adr);
 	
 	bttv_idcard(btv);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/bttv-if.c linux-2.4.20/drivers/media/video/bttv-if.c
--- linux-2.4.19/drivers/media/video/bttv-if.c	2001-10-17 21:19:20.000000000 +0000
+++ linux-2.4.20/drivers/media/video/bttv-if.c	2002-10-29 11:18:33.000000000 +0000
@@ -41,11 +41,13 @@
 static struct i2c_client bttv_i2c_client_template;
 
 EXPORT_SYMBOL(bttv_get_cardinfo);
+EXPORT_SYMBOL(bttv_get_pcidev);
 EXPORT_SYMBOL(bttv_get_id);
 EXPORT_SYMBOL(bttv_gpio_enable);
 EXPORT_SYMBOL(bttv_read_gpio);
 EXPORT_SYMBOL(bttv_write_gpio);
 EXPORT_SYMBOL(bttv_get_gpio_queue);
+EXPORT_SYMBOL(bttv_i2c_call);
 
 /* ----------------------------------------------------------------------- */
 /* Exported functions - for other modules which want to access the         */
@@ -62,6 +64,13 @@
 	return 0;
 }
 
+struct pci_dev* bttv_get_pcidev(unsigned int card)
+{
+	if (card >= bttv_num)
+		return NULL;
+	return bttvs[card].dev;
+}
+
 int bttv_get_id(unsigned int card)
 {
 	printk("bttv_get_id is obsolete, use bttv_get_cardinfo instead\n");
@@ -245,6 +254,13 @@
 	}
 }
 
+void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg)
+{
+	if (card >= bttv_num)
+		return;
+	bttv_call_i2c_clients(&bttvs[card], cmd, arg);
+}
+
 static struct i2c_algo_bit_data bttv_i2c_algo_template = {
 	setsda:  bttv_bit_setsda,
 	setscl:  bttv_bit_setscl,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/bttv.h linux-2.4.20/drivers/media/video/bttv.h
--- linux-2.4.19/drivers/media/video/bttv.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/media/video/bttv.h	2002-10-29 11:18:33.000000000 +0000
@@ -90,6 +90,7 @@
 #define BTTV_SENSORAY311    0x49
 #define BTTV_RV605          0x4a
 #define BTTV_WINDVR         0x4c
+#define BTTV_HAUPPAUGEPVR   0x50
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
@@ -174,6 +175,7 @@
    returns negative value if error occurred 
 */
 extern int bttv_get_cardinfo(unsigned int card, int *type, int *cardid);
+extern struct pci_dev* bttv_get_pcidev(unsigned int card);
 
 /* obsolete, use bttv_get_cardinfo instead */
 extern int bttv_get_id(unsigned int card);
@@ -208,6 +210,11 @@
 */
 extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card);
 
+/* call i2c clients
+*/
+extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg);
+
+
 /* i2c */
 #define I2C_CLIENTS_MAX 16
 extern void bttv_bit_setscl(void *data, int state);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/bttvp.h linux-2.4.20/drivers/media/video/bttvp.h
--- linux-2.4.19/drivers/media/video/bttvp.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/media/video/bttvp.h	2002-10-29 11:18:37.000000000 +0000
@@ -25,8 +25,7 @@
 #ifndef _BTTVP_H_
 #define _BTTVP_H_
 
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,91)
-
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,96)
 
 #include <linux/types.h>
 #include <linux/wait.h>
@@ -49,6 +48,7 @@
 extern unsigned int bttv_gpio;
 extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
 extern int init_bttv_i2c(struct bttv *btv);
+extern int pvr_boot(struct bttv *btv);
 
 #define dprintk		if (bttv_debug) printk
 
@@ -195,6 +195,7 @@
 
 	wait_queue_head_t gpioq;
 	int shutdown;
+        void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
 };
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/cpia.c linux-2.4.20/drivers/media/video/cpia.c
--- linux-2.4.19/drivers/media/video/cpia.c	2001-10-25 20:53:47.000000000 +0000
+++ linux-2.4.20/drivers/media/video/cpia.c	2002-10-29 11:18:49.000000000 +0000
@@ -56,7 +56,7 @@
 
 #ifdef MODULE
 MODULE_PARM(video_nr,"i");
-MODULE_AUTHOR("Scott J. Bertin <sbertin@mindspring.com> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <jerdfelt@valinux.com>");
+MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfeld.com>");
 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("video");
@@ -163,6 +163,7 @@
 #define COMMAND_SETAPCOR		0x1000
 #define COMMAND_SETFLICKERCTRL		0x2000
 #define COMMAND_SETVLOFFSET		0x4000
+#define COMMAND_SETLIGHTS		0x8000
 
 /* Developer's Guide Table 5 p 3-34
  * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
@@ -178,50 +179,17 @@
  *
  * Memory management
  *
- * This is a shameless copy from the USB-cpia driver (linux kernel
- * version 2.3.29 or so, I have no idea what this code actually does ;).
- * Actually it seems to be a copy of a shameless copy of the bttv-driver.
- * Or that is a copy of a shameless copy of ... (To the powers: is there
- * no generic kernel-function to do this sort of stuff?)
- *
- * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
- * there will be one, but apparentely not yet - jerdfelt
- *
  **********************************************************************/
 
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
-	unsigned long ret = 0UL;
-	pmd_t *pmd;
-	pte_t *ptep, pte;
-
-	if (!pgd_none(*pgd)) {
-		pmd = pmd_offset(pgd, adr);
-		if (!pmd_none(*pmd)) {
-			ptep = pte_offset(pmd, adr);
-			pte = *ptep;
-			if (pte_present(pte)) {
-				ret = (unsigned long) page_address(pte_page(pte));
-				ret |= (adr & (PAGE_SIZE-1));
-			}
-		}
-	}
-	return ret;
-}
-
 /* Here we want the physical address of the memory.
- * This is used when initializing the contents of the
- * area and marking the pages as reserved.
+ * This is used when initializing the contents of the area.
  */
 static inline unsigned long kvirt_to_pa(unsigned long adr)
 {
-	unsigned long va, kva, ret;
+	unsigned long kva, ret;
 
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
 	ret = __pa(kva);
 	return ret;
 }
@@ -229,12 +197,9 @@
 static void *rvmalloc(unsigned long size)
 {
 	void *mem;
-	unsigned long adr, page;
-
-	/* Round it off to PAGE_SIZE */
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
+	unsigned long adr;
 
+	size = PAGE_ALIGN(size);
 	mem = vmalloc_32(size);
 	if (!mem)
 		return NULL;
@@ -242,13 +207,9 @@
 	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
 	adr = (unsigned long) mem;
 	while (size > 0) {
-		page = kvirt_to_pa(adr);
-		mem_map_reserve(virt_to_page(__va(page)));
+		mem_map_reserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 
 	return mem;
@@ -256,23 +217,16 @@
 
 static void rvfree(void *mem, unsigned long size)
 {
-	unsigned long adr, page;
+	unsigned long adr;
 
 	if (!mem)
 		return;
 
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
-
 	adr = (unsigned long) mem;
-	while (size > 0) {
-		page = kvirt_to_pa(adr);
-		mem_map_unreserve(virt_to_page(__va(page)));
+	while ((long) size > 0) {
+		mem_map_unreserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 	vfree(mem);
 }
@@ -291,7 +245,7 @@
 	char *out = page;
 	int len, tmp;
 	struct cam_data *cam = data;
-	char tmpstr[20];
+	char tmpstr[29];
 
 	/* IMPORTANT: This output MUST be kept under PAGE_SIZE
 	 *            or we need to get more sophisticated. */
@@ -328,6 +282,13 @@
 	               cam->params.status.vpStatus);
 	out += sprintf(out, "error_code:               %#04x\n",
 	               cam->params.status.errorCode);
+	/* QX3 specific entries */
+	if (cam->params.qx3.qx3_detected) {
+		out += sprintf(out, "button:                   %4d\n",
+		               cam->params.qx3.button);
+		out += sprintf(out, "cradled:                  %4d\n",
+		               cam->params.qx3.cradled);
+	}
 	out += sprintf(out, "video_size:               %s\n",
 	               cam->params.format.videoSize == VIDEOSIZE_CIF ?
 		       "CIF " : "QCIF");
@@ -392,16 +353,17 @@
 	if (cam->params.version.firmwareVersion == 1 &&
 	   cam->params.version.firmwareRevision == 2)
 		/* 1-02 firmware limits gain to 2 */
-		sprintf(tmpstr, "%8d  %8d", 1, 2);
+		sprintf(tmpstr, "%8d  %8d  %8d", 1, 2, 2);
 	else
-		sprintf(tmpstr, "1,2,4,8");
+		sprintf(tmpstr, "%8d  %8d  %8d", 1, 8, 2);
 
 	if (cam->params.exposure.gainMode == 0)
-		out += sprintf(out, "max_gain:                unknown  %18s"
-		               "  %8d\n", tmpstr, 2); 
+		out += sprintf(out, "max_gain:                unknown  %28s"
+		               "  powers of 2\n", tmpstr); 
 	else
-		out += sprintf(out, "max_gain:               %8d  %18s  %8d\n", 
-		               1<<(cam->params.exposure.gainMode-1), tmpstr, 2);
+		out += sprintf(out, "max_gain:               %8d  %28s"
+			       "  1,2,4 or 8 \n",
+		               1<<(cam->params.exposure.gainMode-1), tmpstr);
 
 	switch(cam->params.exposure.expMode) {
 	case 1:
@@ -528,6 +490,15 @@
 	out += sprintf(out, "decimation_thresh_mod:  %8d  %8d  %8d  %8d\n",
 	               cam->params.compressionParams.decimationThreshMod,
 		       0, 255, 2);
+	/* QX3 specific entries */
+	if (cam->params.qx3.qx3_detected) {
+		out += sprintf(out, "toplight:               %8s  %8s  %8s  %8s\n", 
+		               cam->params.qx3.toplight ? "on" : "off",
+			       "off", "on", "off");
+		out += sprintf(out, "bottomlight:            %8s  %8s  %8s  %8s\n", 
+		               cam->params.qx3.bottomlight ? "on" : "off",
+			       "off", "on", "off");
+	}
 	
 	len = out - page;
 	len -= off;
@@ -541,18 +512,45 @@
 	return len;
 }
 
-static int cpia_write_proc(struct file *file, const char *buffer,
+static int cpia_write_proc(struct file *file, const char *buf,
                            unsigned long count, void *data)
 {
-	return -EINVAL;
-#if 0
 	struct cam_data *cam = data;
 	struct cam_params new_params;
+	char *page, *buffer;
 	int retval, find_colon;
 	int size = count;
-	unsigned long val;
+	unsigned long val = 0;
 	u32 command_flags = 0;
 	u8 new_mains;
+
+	/*
+	 * This code to copy from buf to page is shamelessly copied
+	 * from the comx driver
+	 */
+	if (count > PAGE_SIZE) {
+		printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
+		return -ENOSPC;
+	}
+
+	if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
+
+	if(copy_from_user(page, buf, count))
+	{
+		retval = -EFAULT;
+		goto out;
+	}
+
+	if (page[count-1] == '\n')
+		page[count-1] = '\0';
+	else if (count < PAGE_SIZE)
+		page[count] = '\0';
+	else if (page[count]) {
+		retval = -EINVAL;
+		goto out;
+	}
+	
+	buffer = page;
 	
 	if (down_interruptible(&cam->param_lock))
 		return -ERESTARTSYS;
@@ -1210,6 +1208,22 @@
 					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+		} else if (MATCH("toplight")) {
+		        if (!retval && MATCH("on"))
+				new_params.qx3.toplight = 1;
+			else if (!retval && MATCH("off"))
+				new_params.qx3.toplight = 0;
+			else 
+				retval = -EINVAL;
+			command_flags |= COMMAND_SETLIGHTS;
+		} else if (MATCH("bottomlight")) {
+		        if (!retval && MATCH("on"))
+				new_params.qx3.bottomlight = 1;
+			else if (!retval && MATCH("off"))  
+				new_params.qx3.bottomlight = 0;
+			else 
+				retval = -EINVAL;
+			command_flags |= COMMAND_SETLIGHTS;
 		} else {
 			DBG("No match found\n");
 			retval = -EINVAL;
@@ -1221,7 +1235,10 @@
 				++buffer;
 			}
 			if (count) {
-				if (*buffer != '\n' && *buffer != ';')
+				if (*buffer == '\0' && count != 1)
+					retval = -EINVAL;
+				else if (*buffer != '\n' && *buffer != ';' &&
+					 *buffer != '\0')
 					retval = -EINVAL;
 				else {
 					--count;
@@ -1255,8 +1272,9 @@
 	
 	up(&cam->param_lock);
 	
+out:
+	free_page((unsigned long)page);
 	return retval;
-#endif
 }
 
 static void create_proc_cpia_cam(struct cam_data *cam)
@@ -1276,7 +1294,12 @@
 	ent->data = cam;
 	ent->read_proc = cpia_read_proc;
 	ent->write_proc = cpia_write_proc;
-	ent->size = 3626;
+	/* 
+	   size of the proc entry is 3672 bytes for the standard webcam;
+ 	   the extra features of the QX3 microscope add 188 bytes.
+	   (we have not yet probed the camera to see which type it is).
+	*/
+	ent->size = 3672 + 188;
 	cam->proc_entry = ent;
 }
 
@@ -1570,6 +1593,10 @@
 		down(&cam->param_lock);
 		datasize=8;
 		break;
+	case CPIA_COMMAND_ReadMCPorts: 
+	case CPIA_COMMAND_ReadVCRegs:
+		datasize = 4;
+		break;
 	default:
 		datasize=0;
 		break;
@@ -1667,6 +1694,22 @@
 			  }
 			up(&cam->param_lock);
 			break;
+
+		case CPIA_COMMAND_ReadMCPorts: 
+			if (!cam->params.qx3.qx3_detected) 
+				break;
+			/* test button press */ 
+			cam->params.qx3.button = ((data[1] & 0x02) == 0);
+			if (cam->params.qx3.button) {
+				/* button pressed - unlock the latch */
+				do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
+				do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
+			}
+
+			/* test whether microscope is cradled */
+			cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
+			break;
+
 		default:
 			break;
 		}
@@ -1826,6 +1869,7 @@
 {
 	switch(fmt) {
 	case VIDEO_PALETTE_GREY:
+		return count;
 	case VIDEO_PALETTE_RGB555:
 	case VIDEO_PALETTE_RGB565:
 	case VIDEO_PALETTE_YUV422:
@@ -2106,6 +2150,13 @@
 	if (cam->cmd_queue & COMMAND_RESUME)
 		init_stream_cap(cam);
 
+	if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected) {
+		int p1 = (cam->params.qx3.bottomlight == 0) << 1;
+		int p2 = (cam->params.qx3.toplight == 0) << 3;
+		do_command(cam, CPIA_COMMAND_WriteVCReg,  0x90, 0x8F, 0x50, 0);
+		do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
+	}
+
 	up(&cam->param_lock);
 	cam->cmd_queue = COMMAND_NONE;
 	return;
@@ -2182,9 +2233,10 @@
 		/* camera idle now so dispatch queued commands */
 		dispatch_commands(cam);
 
-		/* Update our knowledge of the camera state - FIXME: necessary? */
+		/* Update our knowledge of the camera state */
 		do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
 		do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+		do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
 
 		/* decompress and convert image to by copying it from
 		 * raw_image to decompressed_frame
@@ -2396,7 +2448,11 @@
 	get_version_information(cam);
 	if (cam->params.version.firmwareVersion != 1)
 		return -ENODEV;
-	
+
+	/* set QX3 detected flag */
+	cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
+					cam->params.pnpID.product == 0x0001);
+
 	/* The fatal error checking should be done after
 	 * the camera powers up (developer's guide p 3-38) */
 
@@ -2526,7 +2582,7 @@
 		/* GotoLoPower */
 		goto_low_power(cam);
 
-		/* Update the camera ststus */
+		/* Update the camera status */
 		do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
 
 		/* cleanup internal state stuff */
@@ -2566,7 +2622,7 @@
 {
 	struct cam_data *cam = dev->priv;
 
-	/* make this _really_ smp and multithredi-safe */
+	/* make this _really_ smp and multithread-safe */
 	if (down_interruptible(&cam->busy_lock))
 		return -EINTR;
 
@@ -2793,7 +2849,6 @@
 			cam->cmd_queue |= COMMAND_SETFORMAT;
 		}
 
-		// FIXME needed??? memcpy(&cam->vw, &vw, sizeof(vw));
 		up(&cam->param_lock);
 
 		/* setformat ignored by camera during streaming,
@@ -2835,10 +2890,8 @@
 			retval = -EFAULT;
 			break;
 		}
-#if 1
 		DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
 		    vm.width, vm.height);
-#endif
 		if (vm.frame<0||vm.frame>=FRAME_NUM) {
 			retval = -EINVAL;
 			break;
@@ -2848,6 +2901,8 @@
 		cam->vp.palette = vm.format;
 		switch(vm.format) {
 		case VIDEO_PALETTE_GREY:
+			cam->vp.depth=8;
+			break;
 		case VIDEO_PALETTE_RGB555:
 		case VIDEO_PALETTE_RGB565:
 		case VIDEO_PALETTE_YUV422:
@@ -2880,10 +2935,6 @@
 			cam->cmd_queue |= COMMAND_SETFORMAT;
 			dispatch_commands(cam);
 		}
-#if 0
-		DBG("VIDIOCMCAPTURE: %d / %d/%d\n", cam->video_size,
-		    cam->vw.width, cam->vw.height);
-#endif
 		/* according to v4l-spec we must start streaming here */
 		cam->mmap_kludge = 1;
 		retval = capture_frame(cam, &vm);
@@ -3035,7 +3086,7 @@
 	owner:		THIS_MODULE,
 	name:		"CPiA Camera",
 	type:		VID_TYPE_CAPTURE,
-	hardware:	VID_HARDWARE_CPIA,      /* FIXME */
+	hardware:	VID_HARDWARE_CPIA,
 	open:		cpia_open,
 	close:		cpia_close,
 	read:		cpia_read,
@@ -3100,8 +3151,8 @@
 	cam->params.sensorFps.divisor = 1;
 	cam->params.sensorFps.baserate = 1;
 	
-	cam->params.yuvThreshold.yThreshold = 15; /* FIXME? */
-	cam->params.yuvThreshold.uvThreshold = 15; /* FIXME? */
+	cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
+	cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
 	
 	cam->params.format.subSample = SUBSAMPLE_422;
 	cam->params.format.yuvOrder = YUVORDER_YUYV;
@@ -3109,8 +3160,14 @@
 	cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
 	cam->params.compressionTarget.frTargeting =
 		CPIA_COMPRESSION_TARGET_QUALITY;
-	cam->params.compressionTarget.targetFR = 7; /* FIXME? */
-	cam->params.compressionTarget.targetQ = 10; /* FIXME? */
+	cam->params.compressionTarget.targetFR = 15; /* From windows driver */
+	cam->params.compressionTarget.targetQ = 5; /* From windows driver */
+
+	cam->params.qx3.qx3_detected = 0;
+	cam->params.qx3.toplight = 0;
+	cam->params.qx3.bottomlight = 0;
+	cam->params.qx3.button = 0;
+	cam->params.qx3.cradled = 0;
 
 	cam->video_size = VIDEOSIZE_CIF;
 	
@@ -3119,8 +3176,8 @@
 	cam->vp.brightness = 32768;  /* 50% */
 	cam->vp.contrast = 32768;    /* 50% */
 	cam->vp.whiteness = 0;       /* not used -> grayscale only */
-	cam->vp.depth = 0;           /* FIXME: to be set by user? */
-	cam->vp.palette = VIDEO_PALETTE_RGB24;         /* FIXME: to be set by user? */
+	cam->vp.depth = 24;          /* to be set by user */
+	cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
 
 	cam->vw.x = 0;
 	cam->vw.y = 0;
@@ -3209,12 +3266,6 @@
 	/* close cpia */
 	camera->ops->close(camera->lowlevel_data);
 
-/* Eh? Feeling happy? - jerdfelt */
-/*
-	camera->ops->open(camera->lowlevel_data);
-	camera->ops->close(camera->lowlevel_data);
-*/
-	
 	printk(KERN_INFO "  CPiA Version: %d.%02d (%d.%d)\n",
 	       camera->params.version.firmwareVersion,
 	       camera->params.version.firmwareRevision,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/cpia.h linux-2.4.20/drivers/media/video/cpia.h
--- linux-2.4.19/drivers/media/video/cpia.h	2001-10-25 20:53:47.000000000 +0000
+++ linux-2.4.20/drivers/media/video/cpia.h	2002-10-29 11:18:49.000000000 +0000
@@ -27,12 +27,12 @@
  */
 
 #define CPIA_MAJ_VER	0
-#define CPIA_MIN_VER    7
-#define CPIA_PATCH_VER	4
+#define CPIA_MIN_VER    8
+#define CPIA_PATCH_VER	1
 
 #define CPIA_PP_MAJ_VER       0
-#define CPIA_PP_MIN_VER       7
-#define CPIA_PP_PATCH_VER     4
+#define CPIA_PP_MIN_VER       8
+#define CPIA_PP_PATCH_VER     1
 
 #define CPIA_MAX_FRAME_SIZE_UNALIGNED	(352 * 288 * 4)   /* CIF at RGB32 */
 #define CPIA_MAX_FRAME_SIZE	((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */
@@ -204,6 +204,13 @@
 		u8 subSample;
 		u8 yuvOrder;
 	} format;
+        struct {                        /* Intel QX3 specific data */
+                u8 qx3_detected;        /* a QX3 is present */
+                u8 toplight;            /* top light lit , R/W */
+                u8 bottomlight;         /* bottom light lit, R/W */
+                u8 button;              /* snapshot button pressed (R/O) */
+                u8 cradled;             /* microscope is in cradle (R/O) */
+        } qx3;
 	struct {
 		u8 colStart;		/* skip first 8*colStart pixels */
 		u8 colEnd;		/* finish at 8*colEnd pixels */
@@ -393,29 +400,6 @@
       (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\
         (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
 
-#define ADD_TO_LIST(l, drv) \
-  {\
-    lock_kernel();\
-    (drv)->next = l;\
-    (drv)->previous = &(l);\
-    (l) = drv;\
-    unlock_kernel();\
-  } while(0)
-
-#define REMOVE_FROM_LIST(drv) \
-  {\
-    if ((drv)->previous != NULL) {\
-      lock_kernel();\
-      if ((drv)->next != NULL)\
-        (drv)->next->previous = (drv)->previous;\
-      *((drv)->previous) = (drv)->next;\
-      (drv)->previous = NULL;\
-      (drv)->next = NULL;\
-      unlock_kernel();\
-    }\
-  } while (0)
-
-
 static inline void cpia_add_to_list(struct cam_data* l, struct cam_data* drv)
 {
 	drv->next = l;
@@ -423,7 +407,6 @@
 	l = drv;
 }
 
-
 static inline void cpia_remove_from_list(struct cam_data* drv)
 {
 	if (drv->previous != NULL) {
@@ -435,7 +418,6 @@
 	}
 }
 
-
 #endif /* __KERNEL__ */
 
 #endif /* cpia_h */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/cpia_pp.c linux-2.4.20/drivers/media/video/cpia_pp.c
--- linux-2.4.19/drivers/media/video/cpia_pp.c	2001-10-25 20:53:47.000000000 +0000
+++ linux-2.4.20/drivers/media/video/cpia_pp.c	2002-10-29 11:18:31.000000000 +0000
@@ -4,7 +4,7 @@
  * Supports CPiA based parallel port Video Camera's.
  *
  * (C) Copyright 1999 Bas Huisman <bhuism@cs.utwente.nl>
- * (C) Copyright 1999-2000 Scott J. Bertin <sbertin@mindspring.com>,
+ * (C) Copyright 1999-2000 Scott J. Bertin <sbertin@securenym.net>,
  * (C) Copyright 1999-2000 Peter Pregler <Peter_Pregler@email.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -340,17 +340,6 @@
 	return 0;
 }
 
-static int cpia_pp_read(struct parport *port, u8 *buffer, int len)
-{
-	int bytes_read, new_bytes;
-	for(bytes_read=0; bytes_read<len; bytes_read += new_bytes) {
-		new_bytes = parport_read(port, buffer+bytes_read,
-			                 len-bytes_read);
-		if(new_bytes < 0) break;
-	}
-	return bytes_read;
-}
-
 /****************************************************************************
  *
  *  cpia_pp_streamRead
@@ -360,7 +349,7 @@
 {
 	struct pp_cam_entry *cam = privdata;
 	int read_bytes = 0;
-	int i, endseen, block_size, new_bytes;
+	int i, endseen;
 
 	if(cam == NULL) {
 		DBG("Internal driver error: cam is NULL\n");
@@ -389,34 +378,25 @@
 			return -EIO;
 		}
 	}
+	read_bytes = parport_read(cam->port, buffer, CPIA_MAX_IMAGE_SIZE );
+
+	EndTransferMode(cam);
+	DBG("read %d bytes\n", read_bytes);
+	if( read_bytes<0) return -EIO;
 	endseen = 0;
-	block_size = PARPORT_CHUNK_SIZE;
-	while( !cam->image_complete ) {
-		if(current->need_resched)  schedule();
-		
-		new_bytes = cpia_pp_read(cam->port, buffer, block_size );
-		if( new_bytes <= 0 ) {
-			break;
-		}
-		i=-1;
-		while(++i<new_bytes && endseen<4) {
-	        	if(*buffer==EOI) {
-	                	endseen++;
-	                } else {
-	                	endseen=0;
-	                }
-			buffer++;
-		}
-		read_bytes += i;
-		if( endseen==4 ) {
-			cam->image_complete=1;
-			break;
-		}
-		if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) {
-			block_size=CPIA_MAX_IMAGE_SIZE-read_bytes;
-		}
+	endseen = 0;
+	for( i=0; i<read_bytes && endseen<4; i++ ) {
+	  if( *buffer==EOI ) {
+	    endseen++;
+	  } else {
+	    endseen=0;
+	  }
+	  buffer++;
+	}
+	if( endseen>3 ) {
+	  cam->image_complete=1;
+	  DBG("endseen at %d bytes\n", i);
 	}
-	EndTransferMode(cam);
 	return cam->image_complete ? read_bytes : -EIO;
 }
 
@@ -716,15 +696,6 @@
 
 static int __init cpia_pp_setup(char *str)
 {
-#if 0
-	/* Is this only a 2.2ism? -jerdfelt */
-	if (!str) {
-		if (ints[0] == 0 || ints[1] == 0) {
-			/* disable driver on "cpia_pp=" or "cpia_pp=0" */
-			parport_nr[0] = PPCPIA_PARPORT_OFF;
-		}
-	} else
-#endif
 	if (!strncmp(str, "parport", 7)) {
 		int n = simple_strtoul(str + 7, NULL, 10);
 		if (parport_ptr < PARPORT_MAX) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/cpia_usb.c linux-2.4.20/drivers/media/video/cpia_usb.c
--- linux-2.4.19/drivers/media/video/cpia_usb.c	2001-10-25 20:53:47.000000000 +0000
+++ linux-2.4.20/drivers/media/video/cpia_usb.c	2002-10-29 11:18:31.000000000 +0000
@@ -46,7 +46,7 @@
 
 struct cpia_sbuf {
 	char *data;
-	urb_t *urb;
+	struct urb *urb;
 };
 
 #define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100)
@@ -168,7 +168,7 @@
 static int cpia_usb_open(void *privdata)
 {
 	struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
-	urb_t *urb;
+	struct urb *urb;
 	int ret, retval = 0, fx, err;
   
 	if (!ucpia)
@@ -266,14 +266,16 @@
 
 error_urb1:		/* free urb 1 */
 	usb_free_urb(ucpia->sbuf[1].urb);
-
+	ucpia->sbuf[1].urb = NULL;
 error_urb0:		/* free urb 0 */
 	usb_free_urb(ucpia->sbuf[0].urb);
-
+	ucpia->sbuf[0].urb = NULL;
 error_1:
 	kfree (ucpia->sbuf[1].data);
+	ucpia->sbuf[1].data = NULL;
 error_0:
 	kfree (ucpia->sbuf[0].data);
+	ucpia->sbuf[0].data = NULL;
 	
 	return retval;
 }
@@ -620,8 +622,10 @@
 		ucpia->buffers[0] = NULL;
 	}
 
-	if (!ucpia->open)
+	if (!ucpia->open) {
 		kfree(ucpia);
+		cam->lowlevel_data = NULL;
+	}
 }
 
 static int __init usb_cpia_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/meye.c linux-2.4.20/drivers/media/video/meye.c
--- linux-2.4.19/drivers/media/video/meye.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/media/video/meye.c	2002-10-29 11:18:32.000000000 +0000
@@ -861,7 +861,7 @@
 
 		mchip_free_frame();
 	}
-out:
+out: ;
 }
 
 /****************************************************************************/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/msp3400.c linux-2.4.20/drivers/media/video/msp3400.c
--- linux-2.4.19/drivers/media/video/msp3400.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/media/video/msp3400.c	2002-10-29 11:18:32.000000000 +0000
@@ -1266,6 +1266,7 @@
 
 	if (-1 == msp3400c_reset(c)) {
 		kfree(msp);
+		kfree(c);
 		dprintk("msp3400: no chip found\n");
 		return -1;
 	}
@@ -1275,6 +1276,7 @@
 		rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);
 	if ((-1 == rev1) || (0 == rev1 && 0 == rev2)) {
 		kfree(msp);
+		kfree(c);
 		printk("msp3400: error while reading chip version\n");
 		return -1;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/pms.c linux-2.4.20/drivers/media/video/pms.c
--- linux-2.4.19/drivers/media/video/pms.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/media/video/pms.c	2002-10-29 11:18:35.000000000 +0000
@@ -11,7 +11,7 @@
  *
  *	Most of this code is directly derived from his userspace driver.
  *	His driver works so send any reports to alan@redhat.com unless the
- *	userspace driver also doesnt work for you...
+ *	userspace driver also doesn't work for you...
  */
 
 #include <linux/module.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/tda7432.c linux-2.4.20/drivers/media/video/tda7432.c
--- linux-2.4.19/drivers/media/video/tda7432.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/media/video/tda7432.c	2002-10-29 11:18:49.000000000 +0000
@@ -18,8 +18,12 @@
  *
  * loudness - set between 0 and 15 for varying degrees of loudness effect
  *
+ * maxvol   - set maximium volume to +20db (1), default is 0db(0)
  *
  *
+ *  Revision: 0.7 - maxvol module parm to set maximium volume 0db or +20db
+ *  				store if muted so we can return it
+ *  				change balance only if flaged to
  *  Revision: 0.6 - added tone controls
  *  Revision: 0.5 - Fixed odd balance problem
  *  Revision: 0.4 - added muting
@@ -54,6 +58,9 @@
 
 MODULE_PARM(debug,"i");
 MODULE_PARM(loudness,"i");
+MODULE_PARM_DESC(maxvol,"Set maximium volume to +20db (0), default is 0db(1)");
+MODULE_PARM(maxvol,"i");
+static int maxvol = 0;
 static int loudness = 0; /* disable loudness by default */
 static int debug = 0;	 /* insmod parameter */
 
@@ -81,12 +88,12 @@
 	int addr;
 	int input;
 	int volume;
+	int muted;
 	int bass, treble;
 	int lf, lr, rf, rr;
 	int loud;
 	struct i2c_client c;
 };
-
 static struct i2c_driver driver;
 static struct i2c_client client_template;
 
@@ -291,9 +298,10 @@
 	t->input  = TDA7432_STEREO_IN |  /* Main (stereo) input   */
 		    TDA7432_BASS_SYM  |  /* Symmetric bass cut    */
 		    TDA7432_BASS_NORM;   /* Normal bass range     */ 
-	t->volume = TDA7432_VOL_0DB;	 /* 0dB Volume            */
+	t->volume =  0x3b ;				 /* -27dB Volume            */
 	if (loudness)			 /* Turn loudness on?     */
 		t->volume |= TDA7432_LD_ON;	
+	t->muted    = VIDEO_AUDIO_MUTE;
 	t->treble   = TDA7432_TREBLE_0DB; /* 0dB Treble            */
 	t->bass		= TDA7432_BASS_0DB; 	 /* 0dB Bass              */
 	t->lf     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
@@ -374,17 +382,24 @@
 
 		va->flags |= VIDEO_AUDIO_VOLUME |
 			VIDEO_AUDIO_BASS |
-			VIDEO_AUDIO_TREBLE;
+			VIDEO_AUDIO_TREBLE |
+			VIDEO_AUDIO_MUTABLE;
+		if (t->muted)
+			va->flags |= VIDEO_AUDIO_MUTE;
 		va->mode |= VIDEO_SOUND_STEREO;
 		/* Master volume control
 		 * V4L volume is min 0, max 65535
 		 * TDA7432 Volume: 
 		 * Min (-79dB) is 0x6f
-		 * Max (+20dB) is 0x07
+		 * Max (+20dB) is 0x07 (630)
+		 * Max (0dB) is 0x20 (829)
 		 * (Mask out bit 7 of vol - it's for the loudness setting)
 		 */
-
-		va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630;
+		if(!maxvol){  /* max +20db */
+			va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630;
+		} else {     /* max 0db   */
+			va->volume = (int )(( 0x6f - (t->volume & 0x7F) ) * 829.557);
+		}
 		
 		/* Balance depends on L,R attenuation
 		 * V4L balance is 0 to 65535, middle is 32768
@@ -401,15 +416,15 @@
 			/* left is attenuated, balance shifted right */
 			va->balance = (32768 + 1057*(t->lf));
 		
-		/* Bass/treble */	
+		/* Bass/treble 4 bits each */	
 		va->bass=t->bass;
 		if(va->bass >= 0x8)
-				va->bass = ~(va->bass - 0x8) & 0xf;
-		va->bass = va->bass << 12;
+			va->bass = ~(va->bass - 0x8) & 0xf;
+		va->bass = (va->bass << 12)+(va->bass << 8)+(va->bass << 4)+(va->bass);
 		va->treble=t->treble;
 		if(va->treble >= 0x8)
-				va->treble = ~(va->treble - 0x8) & 0xf;
-		va->treble = va->treble << 12;
+			va->treble = ~(va->treble - 0x8) & 0xf;
+		va->treble = (va->treble << 12)+(va->treble << 8)+(va->treble << 4)+(va->treble);
 								
 		break; /* VIDIOCGAUDIO case */
 	}
@@ -420,26 +435,36 @@
 		struct video_audio *va = arg;
 		dprintk("tda7432: VIDEOCSAUDIO\n");
 
-		t->volume = 0x6f - ( (va->volume)/630 );
+		if(va->flags & VIDEO_AUDIO_VOLUME){
+				
+			if(!maxvol){ /* max +20db */
+				t->volume = 0x6f - ( (va->volume)/630 );
+			} else {    /* max 0db   */
+				t->volume = 0x6f - ((int) (va->volume)/829.557 );
+			}
 		
 		if (loudness)		/* Turn on the loudness bit */
 			t->volume |= TDA7432_LD_ON;
 		
+			tda7432_write(client,TDA7432_VL, t->volume);
+		}
+		
 		if(va->flags & VIDEO_AUDIO_BASS)
 		{
 			t->bass = va->bass >> 12;
 			if(t->bass>= 0x8)
 					t->bass = (~t->bass & 0xf) + 0x8 ;
-			t->bass = t->bass | 0x10;
 		}
 		if(va->flags & VIDEO_AUDIO_TREBLE)
 		{
 			t->treble= va->treble >> 12;
 			if(t->treble>= 0x8)
 					t->treble = (~t->treble & 0xf) + 0x8 ;
-						
 		}
+		if(va->flags & (VIDEO_AUDIO_TREBLE| VIDEO_AUDIO_BASS))
+			tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
 		
+		if(va->flags & VIDEO_AUDIO_BALANCE)	{
 		if (va->balance < 32768) 
 		{
 			/* shifted to left, attenuate right */
@@ -464,20 +489,17 @@
 			t->lf = TDA7432_ATTEN_0DB;
 			t->lr = TDA7432_ATTEN_0DB;
 		}
+		}
 					
-		tda7432_write(client,TDA7432_TN, (t->bass << 4)| t->treble );		
-		tda7432_write(client,TDA7432_VL, t->volume);
-		
-		if (va->flags & VIDEO_AUDIO_MUTE)
+	 	t->muted=(va->flags & VIDEO_AUDIO_MUTE);	
+		if (t->muted)
 		{
 			/* Mute & update balance*/	
 			tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE);
 			tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE);
 			tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE);
 			tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE);
-		}
-		else
-		{	
+		} else {
 			tda7432_write(client,TDA7432_LF, t->lf);
 			tda7432_write(client,TDA7432_LR, t->lr);
 			tda7432_write(client,TDA7432_RF, t->rf);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/tda9875.c linux-2.4.20/drivers/media/video/tda9875.c
--- linux-2.4.19/drivers/media/video/tda9875.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/media/video/tda9875.c	2002-10-29 11:18:39.000000000 +0000
@@ -28,6 +28,7 @@
 #include <linux/videodev.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
 
 #include "bttv.h"
 #include "audiochip.h"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/tuner.c linux-2.4.20/drivers/media/video/tuner.c
--- linux-2.4.19/drivers/media/video/tuner.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/media/video/tuner.c	2002-10-29 11:18:35.000000000 +0000
@@ -101,10 +101,16 @@
 
 /* system switching for Philips FI1216MF MK2
    from datasheet "1996 Jul 09",
+    standard         BG     L      L'
+    picture carrier  38.90  38.90  33.95
+    colour	     34.47  34.37  38.38
+    sound 1          33.40  32.40  40.45
+    sound 2          33.16  -      -
+    NICAM            33.05  33.05  39.80
  */
 #define PHILIPS_MF_SET_BG	0x01 /* Bit 2 must be zero, Bit 3 is system output */
-#define PHILIPS_MF_SET_PAL_L	0x03
-#define PHILIPS_MF_SET_PAL_L2	0x02
+#define PHILIPS_MF_SET_PAL_L	0x03 // France
+#define PHILIPS_MF_SET_PAL_L2	0x02 // L'
 
 
 /* ---------------------------------------------------------------------- */
@@ -132,16 +138,16 @@
 static struct tunertype tuners[] = {
         { "Temic PAL (4002 FH5)", TEMIC, PAL,
 	  16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623},
-	{ "Philips PAL_I", Philips, PAL_I,
+	{ "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I,
 	  16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
-	{ "Philips NTSC", Philips, NTSC,
+	{ "Philips NTSC (FI1236 and compatibles)", Philips, NTSC,
 	  16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732},
-	{ "Philips SECAM", Philips, SECAM,
+	{ "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", Philips, SECAM,
 	  16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623},
 
 	{ "NoTuner", NoTuner, NOTUNER,
 	  0,0,0x00,0x00,0x00,0x00,0x00},
-	{ "Philips PAL", Philips, PAL,
+	{ "Philips PAL_BG (FI1216 and compatibles)", Philips, PAL,
 	  16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623},
 	{ "Temic NTSC (4032 FY5)", TEMIC, NTSC,
 	  16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732},
@@ -181,7 +187,7 @@
           16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
         { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL,
           16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
-        { "Philips PAL_DK", Philips, PAL,
+        { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL,
 	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
 
 	{ "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL,
@@ -200,7 +206,7 @@
 	{ "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL,
 	  16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
 	{ "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */
-	  16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940},
+	  16*137.25,16*317.25,0x01,0x02,0x08,0x8e,732 }, // Corrected to NTSC=732 (was:940)
 
 	{ "Samsung PAL TCPM9091PD27", Samsung, PAL,  /* from sourceforge v3tv */
           16*169,16*464,0xA0,0x90,0x30,0x8e,623},
@@ -215,7 +221,10 @@
           16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
         { "LG PAL (newer TAPC series)", LGINNOTEK, PAL,
           16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623},
-	
+	{ "Philips PAL/SECAM multi (FM1216ME MK3)", Philips, PAL,
+	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
+	{ "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC,
+          16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732},
 };
 #define TUNERS (sizeof(tuners)/sizeof(struct tunertype))
 
@@ -253,7 +262,7 @@
 	return (tuner_getstatus (c) & TUNER_STEREO);
 }
 
-
+#if 0 /* unused */
 static int tuner_islocked (struct i2c_client *c)
 {
         return (tuner_getstatus (c) & TUNER_FL);
@@ -264,12 +273,12 @@
         return (tuner_getstatus (c) & TUNER_AFC) - 2;
 }
 
-#if 0 /* unused */
 static int tuner_mode (struct i2c_client *c)
 {
         return (tuner_getstatus (c) & TUNER_MODE) >> 3;
 }
 #endif
+
 // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
 static int mt2032_init(struct i2c_client *c)
 {
@@ -620,7 +629,7 @@
 
 	/* tv norm specific stuff for multi-norm tuners */
 	switch (t->type) {
-	case TUNER_PHILIPS_SECAM:
+	case TUNER_PHILIPS_SECAM: // FI1216MF
 		/* 0x01 -> ??? no change ??? */
 		/* 0x02 -> PAL BDGHI / SECAM L */
 		/* 0x04 -> ??? PAL others / SECAM others ??? */
@@ -651,8 +660,9 @@
 		default:
 			config |= TEMIC_SET_PAL_BG;
 			break;
-		break;
 		}
+		break;
+
 	case TUNER_PHILIPS_FQ1216ME:
 		config &= ~0x0f;
 		switch (pal[0]) {
@@ -672,8 +682,8 @@
 		case 'G':
 			config |= PHILIPS_SET_PAL_BGDK;
 			break;
-		break;
 		}
+		break;
 	}
 
 	
@@ -703,6 +713,8 @@
 		buffer[2] = tun->config;
 		buffer[3] = config;
 	}
+	dprintk("tuner: tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
+		buffer[0],buffer[1],buffer[2],buffer[3]);
 
         if (4 != (rc = i2c_master_send(c,buffer,4)))
                 printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
@@ -720,12 +732,10 @@
 
 static void set_radio_freq(struct i2c_client *c, int freq)
 {
-	u8 config;
-	u16 div;
 	struct tunertype *tun;
 	struct tuner *t = (struct tuner*)c->data;
         unsigned char buffer[4];
-	int rc;
+	int rc,div;
 
 	if (freq < radio_range[0]*16 || freq > radio_range[1]*16) {
 		printk("tuner: radio freq (%d.%02d) out of range (%d-%d)\n",
@@ -744,35 +754,27 @@
 	}
 
 	tun=&tuners[t->type];
-	config = 0xa4 /* 0xa5 */; /* bit 0 is AFC (set) vs. RF-Signal (clear) */
-	div=freq + (int)(16*10.7);
-  	div&=0x7fff;
-
+	div = freq + (int)(16*10.7);
         buffer[0] = (div>>8) & 0x7f;
         buffer[1] = div      & 0xff;
-        buffer[2] = tun->config;
-        buffer[3] = config;
-        if (4 != (rc = i2c_master_send(c,buffer,4)))
-                printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
+	buffer[2] = tun->config;
+	switch (t->type) {
+	case TUNER_PHILIPS_FM1216ME_MK3:
+		buffer[3] = 0x19;
+		break;
+	default:
+		buffer[3] = 0xa4;
+		break;
+	}
 
-	if (debug) {
-		current->state   = TASK_INTERRUPTIBLE;
-		schedule_timeout(HZ/10);
-		
-		if (tuner_islocked (c))
-			printk ("tuner: PLL locked\n");
-		else
-			printk ("tuner: PLL not locked\n");
+	dprintk("tuner: radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
+		buffer[0],buffer[1],buffer[2],buffer[3]);
 
-		if (config & 1) {
-			printk ("tuner: AFC: %d\n", tuner_afcstatus(c));
-		} else {
-			printk ("tuner: Signal: %d\n", tuner_signal(c));
-		}
-	}
+        if (4 != (rc = i2c_master_send(c,buffer,4)))
+                printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
 }
-/* ---------------------------------------------------------------------- */
 
+/* ---------------------------------------------------------------------- */
 
 static int tuner_attach(struct i2c_adapter *adap, int addr,
 			unsigned short flags, int kind)
@@ -824,6 +826,7 @@
 	this_adap = 0;
 	switch (adap->id) {
 	case I2C_ALGO_BIT | I2C_HW_B_BT848:
+	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
 	case I2C_ALGO_SAA7134:
 		printk("tuner: probing %s i2c adapter [id=0x%x]\n",
 		       adap->name,adap->id);
@@ -988,7 +991,6 @@
 
 module_init(tuner_init_module);
 module_exit(tuner_cleanup_module);
-EXPORT_NO_SYMBOLS;
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/tuner.h linux-2.4.20/drivers/media/video/tuner.h
--- linux-2.4.19/drivers/media/video/tuner.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/media/video/tuner.h	2002-10-29 11:18:33.000000000 +0000
@@ -62,6 +62,9 @@
 #define TUNER_TEMIC_4012FY5	35	/* 4012 FY5 (3X 0971, 1099)*/
 #define TUNER_TEMIC_4136FY5	36	/* 4136 FY5 (3X 7708, 7746)*/
 #define TUNER_LG_PAL_NEW_TAPC   37
+#define TUNER_PHILIPS_FM1216ME_MK3  38
+#define TUNER_LG_NTSC_NEW_TAPC   39
+
 
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/tvaudio.c linux-2.4.20/drivers/media/video/tvaudio.c
--- linux-2.4.19/drivers/media/video/tvaudio.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/media/video/tvaudio.c	2002-10-29 11:18:36.000000000 +0000
@@ -1070,10 +1070,46 @@
 #define TDA8425_S1         0x08  /* switch functions */
                                  /* values for those registers: */
 #define TDA8425_S1_OFF     0xEE  /* audio off (mute on) */
-#define TDA8425_S1_ON      0xCE  /* audio on (mute off) - "linear stereo" mode */
+#define TDA8425_S1_CH1     0xCE  /* audio channel 1 (mute off) - "linear stereo" mode */
+#define TDA8425_S1_CH2     0xCF  /* audio channel 2 (mute off) - "linear stereo" mode */
+#define TDA8425_S1_MU      0x20  /* mute bit */
+#define TDA8425_S1_STEREO  0x18  /* stereo bits */
+#define TDA8425_S1_STEREO_SPATIAL 0x18 /* spatial stereo */
+#define TDA8425_S1_STEREO_LINEAR  0x08 /* linear stereo */
+#define TDA8425_S1_STEREO_PSEUDO  0x10 /* pseudo stereo */
+#define TDA8425_S1_STEREO_MONO    0x00 /* forced mono */
+#define TDA8425_S1_ML      0x06        /* language selector */
+#define TDA8425_S1_ML_SOUND_A 0x02     /* sound a */
+#define TDA8425_S1_ML_SOUND_B 0x04     /* sound b */
+#define TDA8425_S1_ML_STEREO  0x06     /* stereo */
+#define TDA8425_S1_IS      0x01        /* channel selector */
 
-static int tda8425_shift10(int val) { return val >> 10 | 0xc0; }
-static int tda8425_shift12(int val) { return val >> 12 | 0xf0; }
+
+static int tda8425_shift10(int val) { return (val >> 10) | 0xc0; }
+static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; }
+
+static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
+{
+	int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1;
+	
+	if (mode & VIDEO_SOUND_LANG1) {
+		s1 |= TDA8425_S1_ML_SOUND_A;
+		s1 |= TDA8425_S1_STEREO_PSEUDO;
+
+	} else if (mode & VIDEO_SOUND_LANG2) {
+		s1 |= TDA8425_S1_ML_SOUND_B;
+		s1 |= TDA8425_S1_STEREO_PSEUDO;
+		
+	} else {
+		s1 |= TDA8425_S1_ML_STEREO;
+		
+		if (mode & VIDEO_SOUND_MONO)
+			s1 |= TDA8425_S1_STEREO_MONO;
+		if (mode & VIDEO_SOUND_STEREO)
+			s1 |= TDA8425_S1_STEREO_SPATIAL;
+	}
+	chip_write(chip,TDA8425_S1,s1);
+}
 
 
 /* ---------------------------------------------------------------------- */
@@ -1190,8 +1226,8 @@
 		registers:  11,
 		flags:      CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
 
-		leftreg:    TDA9855_VR,
-		rightreg:   TDA9855_VL,
+		leftreg:    TDA9855_VL,
+		rightreg:   TDA9855_VR,
 		bassreg:    TDA9855_BA,
 		treblereg:  TDA9855_TR,
 		volfunc:    tda9855_volume,
@@ -1258,8 +1294,10 @@
 		treblefunc: tda8425_shift12,
 
 		inputreg:   TDA8425_S1,
-		inputmap:   { TDA8425_S1_ON, TDA8425_S1_ON, TDA8425_S1_ON },
+		inputmap:   { TDA8425_S1_CH1, TDA8425_S1_CH1, TDA8425_S1_CH1 },
 		inputmute:  TDA8425_S1_OFF,
+
+		setmode:    tda8425_setmode,
 	},
 	{
 		name:       "pic16c54 (PV951)",
@@ -1338,8 +1376,8 @@
 		chip_cmd(chip,"init",&desc->init);
 
 	if (desc->flags & CHIP_HAS_VOLUME) {
-		chip->left   = desc->leftinit   ? desc->leftinit   : 65536;
-		chip->right  = desc->rightinit  ? desc->rightinit  : 65536;
+		chip->left   = desc->leftinit   ? desc->leftinit   : 65535;
+		chip->right  = desc->rightinit  ? desc->rightinit  : 65535;
 		chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
 		chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
 	}
@@ -1367,9 +1405,14 @@
 
 static int chip_probe(struct i2c_adapter *adap)
 {
-	if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+	switch (adap->id) {
+	case I2C_ALGO_BIT | I2C_HW_B_BT848:
+	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
 		return i2c_probe(adap, &addr_data, chip_attach);
-	return 0;
+	default:
+		/* ignore this i2c bus */
+		return 0;
+	}
 }
 
 static int chip_detach(struct i2c_client *client)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/tvmixer.c linux-2.4.20/drivers/media/video/tvmixer.c
--- linux-2.4.19/drivers/media/video/tvmixer.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/media/video/tvmixer.c	2002-10-29 11:18:49.000000000 +0000
@@ -215,7 +215,6 @@
 	return 0;
 }
 
-
 static struct i2c_driver driver = {
 	name:            "tv card mixer driver",
         id:              I2C_DRIVERID_TVMIXER,
@@ -254,7 +253,13 @@
 	int i,minor;
 
 	/* TV card ??? */
-	if (client->adapter->id != (I2C_ALGO_BIT | I2C_HW_B_BT848)) {
+	switch (client->adapter->id) {
+	case I2C_ALGO_BIT | I2C_HW_B_BT848:
+	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
+		/* ok, have a look ... */
+		break;
+	default:
+		/* ignore that one */
 		if (debug)
 			printk("tvmixer: %s is not a tv card\n",
 			       client->adapter->name);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/zoran_procfs.c linux-2.4.20/drivers/media/video/zoran_procfs.c
--- linux-2.4.19/drivers/media/video/zoran_procfs.c	2001-07-04 21:41:33.000000000 +0000
+++ linux-2.4.20/drivers/media/video/zoran_procfs.c	2002-10-29 11:18:36.000000000 +0000
@@ -110,6 +110,9 @@
 	struct zoran *zr;
 
 	zr = (struct zoran *) data;
+	
+	if(count > 32768)		/* Stupidity filter */
+		count = 32768;
 
 	string = sp = vmalloc(count + 1);
 	if (!string) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/media/video/zr36067.c linux-2.4.20/drivers/media/video/zr36067.c
--- linux-2.4.19/drivers/media/video/zr36067.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/media/video/zr36067.c	2002-10-29 11:18:50.000000000 +0000
@@ -1417,7 +1417,7 @@
 		zr36060_sleep(zr, 0);
 		post_office_write(zr, 3, 0, 0);
 		udelay(2);
-	default:
+	default:;
 	}
 	return 0;
 }
@@ -3763,7 +3763,7 @@
 			 *   Write the overlay mask if clips are wanted.
 			 */
 			 
-			if (vw.clipcount > 2048)
+			if (vw.clipcount < 0 || vw.clipcount > 2048)
 				return -EINVAL;
 			if (vw.clipcount) {
 				vcp =
@@ -4163,7 +4163,6 @@
 		{
 			struct zoran_status bs;
 			int norm, input, status;
-			unsigned long timeout;
 
 			if (zr->codec_mode != BUZ_MODE_IDLE) {
 				DEBUG1(printk(KERN_ERR
@@ -4209,6 +4208,7 @@
 
 			/* sleep 1 second */
 
+			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout(HZ);
 
 			/* Get status of video decoder */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/message/fusion/Makefile linux-2.4.20/drivers/message/fusion/Makefile
--- linux-2.4.19/drivers/message/fusion/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/message/fusion/Makefile	2002-10-29 11:18:33.000000000 +0000
@@ -36,9 +36,9 @@
 #CFLAGS_mptbase.o += -DMPT_DEBUG_IRQ
 #
 #  For mptscsih:
-#CFLAGS_mptscsih.o += -DMPT_SCSI_USE_NEW_EH
 #CFLAGS_mptscsih.o += -DMPT_DEBUG_SCANDV
 #CFLAGS_mptscsih.o += -DMPT_DEBUG_RESET
+#CFLAGS_mptscsih.o += -DMPT_DEBUG_NEH
 #
 #  For mptctl:
 #CFLAGS_mptctl.o += -DMPT_DEBUG_IOCTL
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/message/fusion/linux_compat.h linux-2.4.20/drivers/message/fusion/linux_compat.h
--- linux-2.4.19/drivers/message/fusion/linux_compat.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/message/fusion/linux_compat.h	2002-10-29 11:18:36.000000000 +0000
@@ -15,6 +15,26 @@
 #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 #endif
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#define SET_NICE(current,x)	do {(current)->nice = (x);} while (0)
+#else
+#define SET_NICE(current,x)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+#define pci_enable_device(pdev)	(0)
+#define SCSI_DATA_UNKNOWN	0
+#define SCSI_DATA_WRITE		1
+#define SCSI_DATA_READ		2
+#define SCSI_DATA_NONE		3
+#endif
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
+#define pci_set_dma_mask(pdev, mask)	(0)
+#define scsi_set_pci_device(sh, pdev)	(0)
+#endif
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
 #	if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
 		typedef unsigned int dma_addr_t;
@@ -55,11 +75,11 @@
 typedef void (*__cleanup_module_func_t)(void);
 #define module_init(x) \
 	int init_module(void) __attribute__((alias(#x))); \
-	static inline __init_module_func_t __init_module_inline(void) \
+	extern inline __init_module_func_t __init_module_inline(void) \
 	{ return x; }
 #define module_exit(x) \
 	void cleanup_module(void) __attribute__((alias(#x))); \
-	static inline __cleanup_module_func_t __cleanup_module_inline(void) \
+	extern inline __cleanup_module_func_t __cleanup_module_inline(void) \
 	{ return x; }
 
 #else
@@ -210,6 +230,27 @@
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif /* PCI_DMA_BIDIRECTIONAL */
 
+/*
+ *  With the new command queuing code in the SCSI mid-layer we no longer have
+ *  to hold the io_request_lock spin lock when calling the scsi_done routine.
+ *  For now we only do this with the 2.5.1 kernel or newer.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
+        #define MPT_HOST_LOCK(flags)
+        #define MPT_HOST_UNLOCK(flags)
+#else
+        #define MPT_HOST_LOCK(flags) \
+                spin_lock_irqsave(&io_request_lock, flags)
+        #define MPT_HOST_UNLOCK(flags) \
+                spin_unlock_irqrestore(&io_request_lock, flags)
+#endif
+
+/*
+ *  We use our new error handling code if the kernel version is 2.5.1 or newer.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
+        #define MPT_SCSI_USE_NEW_EH
+#endif
 
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif /* _LINUX_COMPAT_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/message/fusion/mptbase.c linux-2.4.20/drivers/message/fusion/mptbase.c
--- linux-2.4.19/drivers/message/fusion/mptbase.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/message/fusion/mptbase.c	2002-10-29 11:18:34.000000000 +0000
@@ -49,7 +49,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptbase.c,v 1.110 2002/02/27 18:44:20 sralston Exp $
+ *  $Id: mptbase.c,v 1.121 2002/07/23 18:56:59 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -437,13 +437,14 @@
 			pa = 0;					/* No reply flush! */
 		}
 
+#ifdef MPT_DEBUG_IRQ
 		if ((int)ioc->chip_type > (int)FC929) {
-			/* Verify mf, mf are reasonable.
+			/* Verify mf, mr are reasonable.
 			 */
 			if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))
 				|| (mf < ioc->req_frames)) ) {
 				printk(MYIOC_s_WARN_FMT 
-					"mpt_interrupt: Invalid mf (%p) req_idx (%d)!\n", ioc->name, mf, req_idx);
+					"mpt_interrupt: Invalid mf (%p) req_idx (%d)!\n", ioc->name, (void *)mf, req_idx);
 				cb_idx = 0;
 				pa = 0;
 				freeme = 0;
@@ -451,7 +452,7 @@
 			if ((pa) && (mr) && ((mr >= MPT_INDEX_2_RFPTR(ioc, ioc->req_depth))
 				|| (mr < ioc->reply_frames)) ) {
 				printk(MYIOC_s_WARN_FMT 
-					"mpt_interrupt: Invalid rf (%p)!\n", ioc->name, mr);
+					"mpt_interrupt: Invalid rf (%p)!\n", ioc->name, (void *)mr);
 				cb_idx = 0;
 				pa = 0;
 				freeme = 0;
@@ -464,6 +465,7 @@
 				freeme = 0;
 			}
 		}
+#endif
 
 		/*  Check for (valid) IO callback!  */
 		if (cb_idx) {
@@ -525,7 +527,7 @@
 	if ((mf == NULL) ||
 	    (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
 		printk(MYIOC_s_ERR_FMT "NULL or BAD request frame ptr! (=%p)\n",
-				ioc->name, mf);
+				ioc->name, (void *)mf);
 		return 1;
 	}
 
@@ -938,6 +940,70 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
+ *	mpt_add_sge - Place a simple SGE at address pAddr.
+ *	@pAddr: virtual address for SGE
+ *	@flagslength: SGE flags and data transfer length
+ *	@dma_addr: Physical address 
+ *
+ *	This routine places a MPT request frame back on the MPT adapter's
+ *	FreeQ.
+ */
+void
+mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
+{
+	if (sizeof(dma_addr_t) == sizeof(u64)) {
+		SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+		u32 tmp = dma_addr & 0xFFFFFFFF;
+
+		pSge->FlagsLength = cpu_to_le32(flagslength);
+		pSge->Address.Low = cpu_to_le32(tmp);
+		tmp = (u32) ((u64)dma_addr >> 32);
+		pSge->Address.High = cpu_to_le32(tmp);
+
+	} else {
+		SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
+		pSge->FlagsLength = cpu_to_le32(flagslength);
+		pSge->Address = cpu_to_le32(dma_addr);
+	}
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_add_chain - Place a chain SGE at address pAddr.
+ *	@pAddr: virtual address for SGE
+ *	@next: nextChainOffset value (u32's)
+ *	@length: length of next SGL segment
+ *	@dma_addr: Physical address 
+ *
+ *	This routine places a MPT request frame back on the MPT adapter's
+ *	FreeQ.
+ */
+void
+mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
+{
+	if (sizeof(dma_addr_t) == sizeof(u64)) {
+		SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
+		u32 tmp = dma_addr & 0xFFFFFFFF;
+
+		pChain->Length = cpu_to_le16(length);
+		pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); 
+
+		pChain->NextChainOffset = next;
+
+		pChain->Address.Low = cpu_to_le32(tmp);
+		tmp = (u32) ((u64)dma_addr >> 32);
+		pChain->Address.High = cpu_to_le32(tmp);
+	} else {
+		SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
+		pChain->Length = cpu_to_le16(length);
+		pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
+		pChain->NextChainOffset = next;
+		pChain->Address = cpu_to_le32(dma_addr);
+	}
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
  *	mpt_send_handshake_request - Send MPT request via doorbell
  *	handshake method.
  *	@handle: Handle of registered MPT protocol driver
@@ -1023,7 +1089,7 @@
 			}
 		}
 
-		if ((r = WaitForDoorbellInt(iocp, 10, sleepFlag)) >= 0)
+		if (r >= 0 && WaitForDoorbellInt(iocp, 10, sleepFlag) >= 0)
 			r = 0;
 		else
 			r = -4;
@@ -1090,7 +1156,7 @@
 	dprintk((KERN_INFO MYNAM ": Checking for MPT adapters...\n"));
 
 	/*
-	 *  NOTE: The 929 and 1030 will appear as 2 separate PCI devices,
+	 *  NOTE: The 929, 929X and 1030 will appear as 2 separate PCI devices,
 	 *  one for each channel.
 	 */
 	pci_for_each_dev(pdev) {
@@ -1101,6 +1167,8 @@
 		if ((pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC909) &&
 		    (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929) &&
 		    (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919) &&
+		    (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929X) &&
+		    (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919X) &&
 		    (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) &&
 #if 0
 		    /* FIXME! C103x family */
@@ -1113,7 +1181,7 @@
 		}
 
 		/* GRRRRR
-		 * dual function devices (929, 1030) may be presented in Func 1,0 order,
+		 * dual function devices (929, 929X, 1030) may be presented in Func 1,0 order,
 		 * but we'd really really rather have them in Func 0,1 order.
 		 * Do some kind of look ahead here...
 		 */
@@ -1206,7 +1274,6 @@
 mpt_adapter_install(struct pci_dev *pdev)
 {
 	MPT_ADAPTER	*ioc;
-	char		*myname;
 	u8		*mem;
 	unsigned long	 mem_phys;
 	unsigned long	 port;
@@ -1214,9 +1281,20 @@
 	u32		 psize;
 	int		 ii;
 	int		 r = -ENODEV;
-	int		 len;
+	u64		 mask = 0xffffffffffffffff;
 
-	ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_KERNEL);
+	if (pci_enable_device(pdev))
+		return r;
+
+	if (!pci_set_dma_mask(pdev, mask)) {
+		dprintk((KERN_INFO MYNAM 
+			": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
+	} else if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) {
+		printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
+		return r;
+	}
+
+	ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
 	if (ioc == NULL) {
 		printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
 		return -ENOMEM;
@@ -1241,10 +1319,7 @@
 	ioc->mfcnt = 0;
 #endif
 
-	/* Initialize the FW and Data image pointers.
-	 */
-	ioc->FWImage = NULL;
-	ioc->FWImage_dma = 0;
+	ioc->cached_fw = NULL;
 
 	/* Initilize SCSI Config Data structure
 	 */
@@ -1338,6 +1413,14 @@
 		ioc->chip_type = FC919;
 		ioc->prod_name = "LSIFC919";
 	}
+	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
+		ioc->chip_type = FC929X;
+		ioc->prod_name = "LSIFC929X";
+	}
+	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
+		ioc->chip_type = FC919X;
+		ioc->prod_name = "LSIFC919X";
+	}
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
 		ioc->chip_type = C1030;
 		ioc->prod_name = "LSI53C1030";
@@ -1352,10 +1435,7 @@
 		}
 	}
 
-	myname = "iocN";
-	len = strlen(myname);
-	memcpy(ioc->name, myname, len+1);
-	ioc->name[len-1] = '0' + ioc->id;
+	sprintf(ioc->name, "ioc%d", ioc->id);
 
 	Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR);
 	spin_lock_init(&ioc->FreeQlock);
@@ -1400,9 +1480,9 @@
 	mpt_adapters[ioc->id] = ioc;
 
 	/* NEW!  20010220 -sralston
-	 * Check for "bound ports" (929, 1030) to reduce redundant resets.
+	 * Check for "bound ports" (929, 929X, 1030) to reduce redundant resets.
 	 */
-	if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030))
+	if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030) || (ioc->chip_type == FC929X))
 		mpt_detect_bound_ports(ioc, pdev);
 
 	if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) {
@@ -1523,15 +1603,15 @@
 	}
 
 	if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
-		if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
-			dprintk((MYIOC_s_INFO_FMT
+		if (ioc->upload_fw) {
+			ddlprintk((MYIOC_s_INFO_FMT
 				"firmware upload required!\n", ioc->name));
 
 			r = mpt_do_upload(ioc, sleepFlag);
 			if (r != 0)
 				printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
 			/* Handle the alt IOC too */
-			if (alt_ioc_ready){
+			if ((alt_ioc_ready) && (ioc->alt_ioc->upload_fw)){
 				r = mpt_do_upload(ioc->alt_ioc, sleepFlag);
 				if (r != 0)
 					printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
@@ -1645,8 +1725,8 @@
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *	mpt_detect_bound_ports - Search for PCI bus/dev_function
- *	which matches PCI bus/dev_function (+/-1) for newly discovered 929
- *	or 1030.
+ *	which matches PCI bus/dev_function (+/-1) for newly discovered 929,
+ *	929X or 1030.
  *	@ioc: Pointer to MPT adapter structure
  *	@pdev: Pointer to (struct pci_dev) structure
  *
@@ -1710,6 +1790,16 @@
 				(void) KickStart(this, 1, NO_SLEEP);
 		}
 
+		if (this->cached_fw != NULL) {
+			ddlprintk((KERN_INFO MYNAM ": Pushing FW onto adapter\n"));
+
+			if ((state = mpt_downloadboot(this, NO_SLEEP)) < 0) {
+				printk(KERN_WARNING MYNAM 
+					": firmware downloadboot failure (%d)!\n", state);
+			}
+		}
+
+
 		/* Disable adapter interrupts! */
 		CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
 		this->active = 0;
@@ -1753,11 +1843,26 @@
 			this->alloc_total -= sz;
 		}
 
-		if (freeup && this->FWImage != NULL) {
-			sz = this->facts.FWImageSize;
-			pci_free_consistent(this->pcidev, sz,
-					this->FWImage, this->FWImage_dma);
-			this->FWImage = NULL;
+		if (freeup && this->cached_fw != NULL) {
+			int ii = 0;
+
+			while ((ii < this->num_fw_frags) && (this->cached_fw[ii]!= NULL)) {
+				sz = this->cached_fw[ii]->size;
+				pci_free_consistent(this->pcidev, sz,
+					this->cached_fw[ii]->fw, this->cached_fw[ii]->fw_dma);
+				this->cached_fw[ii]->fw = NULL;
+				this->alloc_total -= sz;
+
+				kfree(this->cached_fw[ii]);
+				this->cached_fw[ii] = NULL;
+				this->alloc_total -= sizeof(fw_image_t);
+
+				ii++;
+			}
+
+			kfree(this->cached_fw);
+			this->cached_fw = NULL;
+			sz = this->num_fw_frags * sizeof(void *);
 			this->alloc_total -= sz;
 		}
 
@@ -2151,7 +2256,7 @@
 			 * and request & reply queue depths...
 			 */
 			ioc->req_sz = MIN(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
-			ioc->req_depth = MIN(MPT_DEFAULT_REQ_DEPTH, facts->GlobalCredits);
+			ioc->req_depth = MIN(MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
 			ioc->reply_sz = ioc->req_sz;
 			ioc->reply_depth = MIN(MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
 
@@ -2271,10 +2376,24 @@
 	ioc_init.Function = MPI_FUNCTION_IOC_INIT;
 /*	ioc_init.Flags = 0;				*/
 
+	/* If we are in a recovery mode and we uploaded the FW image,
+	 * then this pointer is not NULL. Skip the upload a second time.
+	 * Set this flag if cached_fw set for either IOC.
+	 */
+	ioc->upload_fw = 0;
+	ioc_init.Flags = 0;
+	if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
+		if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw))
+			ioc_init.Flags = MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE;
+		else 
+			ioc->upload_fw = 1;
+	}
+	ddlprintk((MYIOC_s_INFO_FMT "flags %d, upload_fw %d \n", 
+		   ioc->name, ioc_init.Flags, ioc->upload_fw));
+
 	if ((int)ioc->chip_type <= (int)FC929) {
 		ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
-	}
-	else {
+	} else {
 		ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
 	}
 	ioc_init.MaxBuses = MPT_MAX_BUS;
@@ -2283,17 +2402,17 @@
 /*	ioc_init.MsgContext = cpu_to_le32(0x00000000);	*/
 	ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz);	/* in BYTES */
 
-#ifdef __ia64__
-	/* Save the upper 32-bits of the request
-	 * (reply) and sense buffers.
-	 */
-	ioc_init.HostMfaHighAddr = cpu_to_le32((u32)(ioc->req_frames_dma >> 32));
-	ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)(ioc->sense_buf_pool_dma >> 32));
-#else
-	/* Force 32-bit addressing */
-	ioc_init.HostMfaHighAddr = cpu_to_le32(0);
-	ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
-#endif
+	if (sizeof(dma_addr_t) == sizeof(u64)) {
+		/* Save the upper 32-bits of the request
+		 * (reply) and sense buffers.
+		 */
+		ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32));
+		ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
+	} else {
+		/* Force 32-bit addressing */
+		ioc_init.HostMfaHighAddr = cpu_to_le32(0);
+		ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
+	}
 
 	dprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
 			ioc->name, &ioc_init));
@@ -2398,6 +2517,142 @@
 	return 0;
 }
 
+/*
+ * Inputs: size - total FW bytes
+ * Outputs: frags - number of fragments needed
+ * Return NULL if failed.
+ */
+void * 
+mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz) 
+{
+	fw_image_t	**cached_fw = NULL;
+	u8		*mem = NULL;
+	dma_addr_t	fw_dma;
+	int		alloc_total = 0;
+	int		bytes_left, bytes, num_frags;
+	int		sz, ii;
+
+	/* cached_fw 
+	 */
+	sz = ioc->num_fw_frags * sizeof(void *);
+	mem = kmalloc(sz, GFP_ATOMIC);
+	if (mem == NULL)
+		return NULL;
+
+	memset(mem, 0, sz);
+	cached_fw = (fw_image_t **)mem;
+	alloc_total += sz;
+
+	/* malloc fragment memory
+	 * fw_image_t struct and dma for fw data
+	 */
+	bytes_left = size;
+	ii = 0;
+	num_frags = 0;
+	bytes = bytes_left;
+	while((bytes_left) && (num_frags < ioc->num_fw_frags)) {
+		if (cached_fw[ii] == NULL) {
+			mem = kmalloc(sizeof(fw_image_t), GFP_ATOMIC);
+			if (mem == NULL)
+				break;
+
+			memset(mem, 0, sizeof(fw_image_t));
+			cached_fw[ii] = (fw_image_t *)mem;
+			alloc_total += sizeof(fw_image_t);
+		}
+
+		mem = pci_alloc_consistent(ioc->pcidev, bytes, &fw_dma);
+		if (mem == NULL) {
+			if (bytes > 0x10000)
+				bytes = 0x10000;
+			else if (bytes > 0x8000)
+				bytes = 0x8000;
+			else if (bytes > 0x4000)
+				bytes = 0x4000;
+			else if (bytes > 0x2000)
+				bytes = 0x2000;
+			else if (bytes > 0x1000)
+				bytes = 0x1000;
+			else
+				break;
+
+			continue;
+		}
+
+		cached_fw[ii]->fw = mem;
+		cached_fw[ii]->fw_dma = fw_dma;
+		cached_fw[ii]->size = bytes;
+		memset(mem, 0, bytes);
+		alloc_total += bytes;
+
+		bytes_left -= bytes;
+
+		num_frags++;
+		ii++;
+	}
+
+	if (bytes_left ) {
+		/* Major Failure.
+		 */
+		mpt_free_fw_memory(ioc, cached_fw);
+		return NULL;
+	}
+
+	*frags = num_frags;
+	*alloc_sz = alloc_total;
+
+	return (void *) cached_fw;
+}
+
+/*
+ * If alt_img is NULL, delete from ioc structure.
+ * Else, delete a secondary image in same format.
+ */
+void
+mpt_free_fw_memory(MPT_ADAPTER *ioc, fw_image_t **alt_img)
+{
+	fw_image_t **cached_fw;
+	int ii;
+	int sz;
+	int alloc_freed = 0;
+
+	if (alt_img != NULL)
+		cached_fw = alt_img;
+	else
+		cached_fw = ioc->cached_fw;
+
+	if (cached_fw == NULL)
+		return;
+
+	ii = 0;
+	while ((ii < ioc->num_fw_frags) && (cached_fw[ii]!= NULL)) {
+		sz = cached_fw[ii]->size;
+		if (sz > 0) {
+			pci_free_consistent(ioc->pcidev, sz,
+						cached_fw[ii]->fw, cached_fw[ii]->fw_dma);
+		}
+		cached_fw[ii]->fw = NULL;
+		alloc_freed += sz;
+
+		kfree(cached_fw[ii]);
+		cached_fw[ii] = NULL;
+		alloc_freed += sizeof(fw_image_t);
+
+		ii++;
+	}
+
+	kfree(cached_fw);
+	cached_fw = NULL;
+	sz = ioc->num_fw_frags * sizeof(void *);
+	alloc_freed += sz;
+
+	if (alt_img == NULL)
+		ioc->alloc_total -= alloc_freed;
+
+	return;
+}
+
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *	mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
@@ -2415,45 +2670,46 @@
 static int
 mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
 {
-	u8			 request[sizeof(FWUpload_t) +  24];
+	u8			 request[ioc->req_sz];
 	u8			 reply[sizeof(FWUploadReply_t)];
 	FWUpload_t		*prequest;
 	FWUploadReply_t		*preply;
 	FWUploadTCSGE_t		*ptcsge = NULL;
-	MptSge_t		*psge;
-	u8			*mem;
-	dma_addr_t		 dma_addr;
 	int			 sgeoffset;
-	int			 i, sz, req_sz, reply_sz;
+	int			 ii, sz, reply_sz;
 	int			 cmdStatus, freeMem = 0;
+	int			 num_frags, alloc_sz;
 
 	/* If the image size is 0 or if the pointer is
 	 * not NULL (error), we are done.
 	 */
-	if (((sz = ioc->facts.FWImageSize) == 0) || ioc->FWImage)
+	if (((sz = ioc->facts.FWImageSize) == 0) || ioc->cached_fw)
 		return 0;
 
-	/* Allocate memory
-	 */
-	mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->FWImage_dma);
-	if (mem == NULL)
-		return -1;
+	ioc->num_fw_frags = ioc->req_sz - sizeof(FWUpload_t) + sizeof(dma_addr_t) + sizeof(u32) -1;
+	ioc->num_fw_frags /= sizeof(dma_addr_t) + sizeof(u32);
 
-	memset(mem, 0, sz);
-	ioc->alloc_total += sz;
-	ioc->FWImage = mem;
-	dprintk((KERN_INFO MYNAM ": FW Image  @ %p[%p], sz=%d bytes\n",
-			mem, (void *)(ulong)ioc->FWImage_dma, sz));
+	ioc->cached_fw = (fw_image_t **) mpt_alloc_fw_memory(ioc, 
+			ioc->facts.FWImageSize, &num_frags, &alloc_sz); 
 
-	dma_addr = ioc->FWImage_dma;
+	if (ioc->cached_fw == NULL) {
+		/* Major Failure.
+		 */
+		mpt_free_fw_memory(ioc, NULL);
+		ioc->cached_fw = NULL;
+		
+		return -ENOMEM;
+	}
+	ioc->alloc_total += alloc_sz;
+
+	ddlprintk((KERN_INFO MYNAM ": FW Image  @ %p, sz=%d bytes\n",
+		 (void *)(ulong)ioc->cached_fw, ioc->facts.FWImageSize));
 
 	prequest = (FWUpload_t *)&request;
 	preply = (FWUploadReply_t *)&reply;
 
 	/*  Destination...  */
-	req_sz = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION)
-			+ sizeof(FWUploadTCSGE_t) + sizeof(MptSge_t);
-	memset(prequest, 0, req_sz);
+	memset(prequest, 0, ioc->req_sz);
 
 	reply_sz = sizeof(reply);
 	memset(preply, 0, reply_sz);
@@ -2472,19 +2728,29 @@
 	ptcsge->ImageSize = cpu_to_le32(sz);
 
 	sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
-	psge = (MptSge_t *) &request[sgeoffset];
-	psge->FlagsLength = cpu_to_le32(MPT_SGE_FLAGS_SSIMPLE_READ | (u32) sz);
 
-	cpu_to_leXX(dma_addr, psge->Address);
+	for (ii = 0; ii < (num_frags-1); ii++) {
+		mpt_add_sge(&request[sgeoffset], MPT_SGE_FLAGS_SIMPLE_ELEMENT |	
+			MPT_SGE_FLAGS_ADDRESSING | MPT_TRANSFER_IOC_TO_HOST |
+			(u32) ioc->cached_fw[ii]->size, ioc->cached_fw[ii]->fw_dma);
+
+		sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
+	}
+
+	mpt_add_sge(&request[sgeoffset], 
+			MPT_SGE_FLAGS_SSIMPLE_READ |(u32) ioc->cached_fw[ii]->size, 
+			ioc->cached_fw[ii]->fw_dma);
+
+	sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
 
-	dprintk((MYIOC_s_INFO_FMT "Sending FW Upload (req @ %p)\n",
-			ioc->name, prequest));
+	dprintk((MYIOC_s_INFO_FMT "Sending FW Upload (req @ %p) size %d \n",
+			ioc->name, prequest, sgeoffset));
 
-	i = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)prequest,
+	ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
 				reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
 
 	cmdStatus = -EFAULT;
-	if (i == 0) {
+	if (ii == 0) {
 		/* Handshake transfer was complete and successful.
 		 * Check the Reply Frame.
 		 */
@@ -2496,14 +2762,15 @@
 				cmdStatus = 0;
 		}
 	}
-	dprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n",
+	ddlprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n",
 			ioc->name, cmdStatus));
 
 	/* Check to see if we have a copy of this image in
 	 * host memory already.
 	 */
 	if (cmdStatus == 0) {
-		if (ioc->alt_ioc && ioc->alt_ioc->FWImage)
+		ioc->upload_fw = 0;
+		if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
 			freeMem = 1;
 	}
 
@@ -2512,13 +2779,11 @@
 	 * failed (i != 0) or the command did not complete successfully.
 	 */
 	if (cmdStatus || freeMem) {
-		dprintk((MYIOC_s_INFO_FMT ": do_upload freeing %s image \n",
-			ioc->name, cmdStatus ? "incomplete" : "duplicate"));
 
-		pci_free_consistent(ioc->pcidev, sz,
-					ioc->FWImage, ioc->FWImage_dma);
-		ioc->FWImage = NULL;
-		ioc->alloc_total -= sz;
+		ddlprintk((MYIOC_s_INFO_FMT ": do_upload freeing %s image \n",
+			ioc->name, cmdStatus ? "incomplete" : "duplicate"));
+		mpt_free_fw_memory(ioc, NULL);
+		ioc->cached_fw = NULL;
 	}
 
 	return cmdStatus;
@@ -2535,7 +2800,7 @@
  *
  *	Returns 0 for success
  *		-1 FW Image size is 0
- *		-2 No valid FWImage Pointer
+ *		-2 No valid cached_fw Pointer
  *		<0 for fw upload failure.
  */
 static int
@@ -2543,6 +2808,7 @@
 {
 	MpiFwHeader_t		*FwHdr = NULL;
 	MpiExtImageHeader_t 	*ExtHdr;
+	fw_image_t		**pCached = NULL;
 	int			 fw_sz;
 	u32			 diag0val;
 #ifdef MPT_DEBUG
@@ -2552,22 +2818,26 @@
 	u32			*ptru32 = NULL;
 	u32			 diagRwData;
 	u32			 nextImage;
+	u32			 ext_offset;
+	u32			 load_addr;
+	int			 max_idx, fw_idx, ext_idx;
+	int			 left_u32s;
 
-	dprintk((MYIOC_s_INFO_FMT "DbGb0: downloadboot entered.\n",
+	ddlprintk((MYIOC_s_INFO_FMT "DbGb0: downloadboot entered.\n",
 				ioc->name));
 #ifdef MPT_DEBUG
 	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
 	if (ioc->alt_ioc)
 		diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-	dprintk((MYIOC_s_INFO_FMT "DbGb1: diag0=%08x, diag1=%08x\n",
+	ddlprintk((MYIOC_s_INFO_FMT "DbGb1: diag0=%08x, diag1=%08x\n",
 				ioc->name, diag0val, diag1val));
 #endif
 
-	dprintk((MYIOC_s_INFO_FMT "fw size 0x%x, ioc FW Ptr %p\n",
-				ioc->name, ioc->facts.FWImageSize, ioc->FWImage));
+	ddlprintk((MYIOC_s_INFO_FMT "fw size 0x%x, ioc FW Ptr %p\n",
+				ioc->name, ioc->facts.FWImageSize, ioc->cached_fw));
 	if (ioc->alt_ioc)
-		dprintk((MYIOC_s_INFO_FMT "alt ioc FW Ptr %p\n",
-				ioc->name, ioc->alt_ioc->FWImage));
+		ddlprintk((MYIOC_s_INFO_FMT "alt ioc FW Ptr %p\n",
+				ioc->name, ioc->alt_ioc->cached_fw));
 
 	/* Get dma_addr and data transfer size.
 	 */
@@ -2575,15 +2845,14 @@
 		return -1;
 
 	/* Get the DMA from ioc or ioc->alt_ioc */
-	if (ioc->FWImage)
-		FwHdr = (MpiFwHeader_t *)ioc->FWImage;
-	else if (ioc->alt_ioc && ioc->alt_ioc->FWImage)
-		FwHdr = (MpiFwHeader_t *)ioc->alt_ioc->FWImage;
-
-	dprintk((MYIOC_s_INFO_FMT "DbGb2: FW Image @ %p\n",
-			ioc->name, FwHdr));
-
-	if (!FwHdr)
+	if (ioc->cached_fw != NULL)
+		pCached = (fw_image_t **)ioc->cached_fw;
+	else if (ioc->alt_ioc && (ioc->alt_ioc->cached_fw != NULL))
+		pCached = (fw_image_t **)ioc->alt_ioc->cached_fw;
+
+	ddlprintk((MYIOC_s_INFO_FMT "DbGb2: FW Image @ %p\n",
+			ioc->name, pCached));
+	if (!pCached)
 		return -2;
 
 	/* Write magic sequence to WriteSequence register
@@ -2617,10 +2886,10 @@
 #ifdef MPT_DEBUG
 		if (ioc->alt_ioc)
 			diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-		dprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n",
+		ddlprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n",
 				ioc->name, diag0val, diag1val));
 #endif
-		dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
+		ddlprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
 				ioc->name, diag0val));
 	}
 
@@ -2631,60 +2900,145 @@
 #ifdef MPT_DEBUG
 	if (ioc->alt_ioc)
 		diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-	dprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n",
+
+	ddlprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n",
 			ioc->name, diag0val, diag1val));
 #endif
 
+	/* max_idx = 1 + maximum valid buffer index
+	 */
+	max_idx = 0;
+	while (pCached[max_idx])
+		max_idx++;
+
+	fw_idx = 0;
+	FwHdr = (MpiFwHeader_t *) pCached[fw_idx]->fw;
+	ptru32 = (u32 *) FwHdr;
+	count = (FwHdr->ImageSize + 3)/4;
+	nextImage = FwHdr->NextImageHeaderOffset;
+
 	/* Write the LoadStartAddress to the DiagRw Address Register
 	 * using Programmed IO
 	 */
-
 	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->LoadStartAddress);
-	dprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
+	ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
 		ioc->name, FwHdr->LoadStartAddress));
 
-	nextImage = FwHdr->NextImageHeaderOffset;
-
-	/* round up count to a 32bit alignment */
-	ptru32 = (u32 *) FwHdr;
-	count = (FwHdr->ImageSize + 3)/4;
-
-	dprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x u32's @ %p\n",
+	ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x u32's @ %p\n",
 				ioc->name, count, ptru32));
-	while (count-- ) {
+	left_u32s = pCached[fw_idx]->size/4;
+	while (count--) {
+		if (left_u32s == 0) {
+			fw_idx++;
+			if (fw_idx >= max_idx) {
+				/* FIXME
+				ERROR CASE
+				*/
+				;
+			}
+			ptru32 = (u32 *) pCached[fw_idx]->fw;
+			left_u32s = pCached[fw_idx]->size / 4;
+		}
+		left_u32s--;
 		CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32);
 		ptru32++;
 	}
 
-	dprintk((MYIOC_s_INFO_FMT "FW Image done! \n", ioc->name));
-		
+	/* left_u32s, fw_idx and ptru32 are all valid
+	 */
 	while (nextImage) {
+		ext_idx = 0;
+		ext_offset = nextImage;
+		while (ext_offset > pCached[ext_idx]->size) {
+			ext_idx++;
+			if (ext_idx >= max_idx) {
+				/* FIXME
+				ERROR CASE
+				*/
+				;
+			}
+			ext_offset -= pCached[ext_idx]->size;
+		}
+		ptru32 = (u32 *) ((char *)pCached[ext_idx]->fw + ext_offset);
+		left_u32s = pCached[ext_idx]->size - ext_offset;
 
-		/* Set the pointer to the extended image
-		 */
-		ExtHdr = (MpiExtImageHeader_t *) ((char *) FwHdr + nextImage);
+		if ((left_u32s * 4) >= sizeof(MpiExtImageHeader_t)) {
+			ExtHdr = (MpiExtImageHeader_t *) ptru32;
+			count = (ExtHdr->ImageSize + 3 )/4;
+			nextImage = ExtHdr->NextImageHeaderOffset;
+			load_addr = ExtHdr->LoadStartAddress;
+		} else {
+			u32 * ptmp = (u32 *)pCached[ext_idx+1]->fw;
 
-		CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, ExtHdr->LoadStartAddress);
+			switch (left_u32s) {
+			case 5:
+				count = *(ptru32 + 2);
+				nextImage = *(ptru32 + 3);
+				load_addr = *(ptru32 + 4);
+				break;
+			case 4:
+				count = *(ptru32 + 2);
+				nextImage = *(ptru32 + 3);
+				load_addr = *ptmp;
+				break;
+			case 3:
+				count = *(ptru32 + 2);
+				nextImage = *ptmp;
+				load_addr = *(ptmp + 1);
+				break;
+			case 2:
+				count = *ptmp;
+				nextImage = *(ptmp + 1);
+				load_addr = *(ptmp + 2);
+				break;
 
-		count = (ExtHdr->ImageSize + 3 )/4;
+			case 1:
+				count = *(ptmp + 1);
+				nextImage = *(ptmp + 2);
+				load_addr = *(ptmp + 3);
+				break;
 
-		ptru32 = (u32 *) ExtHdr;
-		dprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x u32's @ %p\n",
-				ioc->name, count, ptru32));
-		while (count-- ) {
+			default:
+				count = 0;
+				nextImage = 0;
+				load_addr = 0;
+				/* FIXME
+				ERROR CASE
+				*/
+				;
+
+			}
+			count = (count +3)/4;
+		}
+
+		ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x u32's @ %p\n",
+						ioc->name, count, ptru32));
+		CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
+
+		while (count--) {
+			if (left_u32s == 0) {
+				fw_idx++;
+				if (fw_idx >= max_idx) {
+					/* FIXME
+					ERROR CASE
+					*/
+					;
+				}
+				ptru32 = (u32 *) pCached[fw_idx]->fw;
+				left_u32s = pCached[fw_idx]->size / 4;
+			}
+			left_u32s--;
 			CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32);
 			ptru32++;
 		}
-		nextImage = ExtHdr->NextImageHeaderOffset;
 	}
 
-
 	/* Write the IopResetVectorRegAddr */
-	dprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr! \n", ioc->name));
+	ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr! \n", ioc->name));
 	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->IopResetRegAddr);
 
 	/* Write the IopResetVectorValue */
-	dprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value! \n", ioc->name));
+	ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value! \n", ioc->name));
 	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, FwHdr->IopResetVectorValue);
 
 	/* Clear the internal flash bad bit - autoincrementing register,
@@ -3182,15 +3536,14 @@
 
 		ioc->req_frames_low_dma = (u32) (ioc->req_frames_dma & 0xFFFFFFFF);
 
-#ifdef __ia64__
-		/* Check: upper 32-bits of the request and reply frame
-		 * physical addresses must be the same.
-		 * ia64 check only
-		 */
-		if ((ioc->req_frames_dma >> 32) != (ioc->reply_frames_dma >> 32)){
-			goto out_fail;
+		if (sizeof(dma_addr_t) == sizeof(u64)) {
+			/* Check: upper 32-bits of the request and reply frame
+			 * physical addresses must be the same.
+			 */
+			if (((u64)ioc->req_frames_dma >> 32) != ((u64)ioc->reply_frames_dma >> 32)){
+				goto out_fail;
+			}
 		}
-#endif
 
 #if defined(CONFIG_MTRR) && 0
 		/*
@@ -3866,7 +4219,7 @@
 		int	 sz;
 		u8	*mem;
 		sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
-		mem = kmalloc(sz, GFP_KERNEL);
+		mem = kmalloc(sz, GFP_ATOMIC);
 		if (mem == NULL)
 			return -EFAULT;
 
@@ -4166,7 +4519,7 @@
 		cfg.physAddr = ioc3_dma;
 		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
 		if (mpt_config(ioc, &cfg) == 0) {
-			mem = kmalloc(iocpage3sz, GFP_KERNEL);
+			mem = kmalloc(iocpage3sz, GFP_ATOMIC);
 			if (mem) {
 				memcpy(mem, (u8 *)pIoc3, iocpage3sz);
 				ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem;
@@ -4271,7 +4624,6 @@
 {
 	Config_t	*pReq;
 	MPT_FRAME_HDR	*mf;
-	MptSge_t	*psge;
 	unsigned long	 flags;
 	int		 ii, rc;
 	int		 flagsLength;
@@ -4316,19 +4668,14 @@
 
 	/* Add a SGE to the config request.
 	 */
-	flagsLength = ((MPI_SGE_FLAGS_LAST_ELEMENT |
-			MPI_SGE_FLAGS_END_OF_BUFFER |
-			MPI_SGE_FLAGS_END_OF_LIST |
-			MPI_SGE_FLAGS_SIMPLE_ELEMENT |
-			MPT_SGE_ADDRESS_SIZE ) << MPI_SGE_FLAGS_SHIFT) |
-			pCfg->hdr->PageLength * 4;
-
 	if (pCfg->dir)
-		flagsLength |= (MPI_SGE_FLAGS_DIRECTION << MPI_SGE_FLAGS_SHIFT);
+		flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
+	else
+		flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
+
+	flagsLength |= pCfg->hdr->PageLength * 4;
 
-	psge = (MptSge_t *) &pReq->PageBufferSGE;
-	psge->FlagsLength = cpu_to_le32(flagsLength);
-	cpu_to_leXX(pCfg->physAddr, psge->Address);
+	mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
 
 	dprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
 		ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
@@ -4431,6 +4778,7 @@
 		/* Search the configQ for internal commands. 
 		 * Flush the Q, and wake up all suspended threads.
 		 */
+#if 1
 		spin_lock_irqsave(&ioc->FreeQlock, flags);
 		if (! Q_IS_EMPTY(&ioc->configQ)){
 			pCfg = (CONFIGPARMS *)ioc->configQ.head;
@@ -4447,6 +4795,23 @@
 			} while (pCfg != (CONFIGPARMS *)&ioc->configQ);
 		}
 		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+#else
+		while (1) {
+			spin_lock_irqsave(&ioc->FreeQlock, flags);
+			if (! Q_IS_EMPTY(&ioc->configQ)){
+				spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+				break;
+			}
+			pCfg = (CONFIGPARMS *)ioc->configQ.head;
+
+			Q_DEL_ITEM(&pCfg->linkage);
+			spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+			pCfg->status = MPT_CONFIG_ERROR;
+			pCfg->wait_done = 1;
+			wake_up(&mpt_waitq);
+		}
+#endif
 	}
 
 	return 1;		/* currently means nothing really */
@@ -4732,7 +5097,7 @@
 	len += sprintf(buf+len, "  MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
 
 	len += sprintf(buf+len, "  RequestFrames @ 0x%p (Dma @ 0x%p)\n",
-					ioc->req_alloc, (void *)(ulong)ioc->req_alloc_dma);
+					(void *)ioc->req_alloc, (void *)(ulong)ioc->req_alloc_dma);
 	/*
 	 *  Rounding UP to nearest 4-kB boundary here...
 	 */
@@ -4745,7 +5110,7 @@
 					ioc->facts.GlobalCredits);
 
 	len += sprintf(buf+len, "  ReplyFrames   @ 0x%p (Dma @ 0x%p)\n",
-					ioc->reply_alloc, (void *)(ulong)ioc->reply_alloc_dma);
+					(void *)ioc->reply_alloc, (void *)(ulong)ioc->reply_alloc_dma);
 	sz = (ioc->reply_sz * ioc->reply_depth) + 128;
 	len += sprintf(buf+len, "    {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
 					ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
@@ -5301,6 +5666,8 @@
 EXPORT_SYMBOL(mpt_get_msg_frame);
 EXPORT_SYMBOL(mpt_put_msg_frame);
 EXPORT_SYMBOL(mpt_free_msg_frame);
+EXPORT_SYMBOL(mpt_add_sge);
+EXPORT_SYMBOL(mpt_add_chain);
 EXPORT_SYMBOL(mpt_send_handshake_request);
 EXPORT_SYMBOL(mpt_handshake_req_reply_wait);
 EXPORT_SYMBOL(mpt_adapter_find_first);
@@ -5312,6 +5679,8 @@
 EXPORT_SYMBOL(mpt_stm_index);
 EXPORT_SYMBOL(mpt_HardResetHandler);
 EXPORT_SYMBOL(mpt_config);
+EXPORT_SYMBOL(mpt_alloc_fw_memory);
+EXPORT_SYMBOL(mpt_free_fw_memory);
 
 EXPORT_SYMBOL(mpt_register_ascqops_strings);
 EXPORT_SYMBOL(mpt_deregister_ascqops_strings);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/message/fusion/mptbase.h linux-2.4.20/drivers/message/fusion/mptbase.h
--- linux-2.4.19/drivers/message/fusion/mptbase.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/message/fusion/mptbase.h	2002-10-29 11:18:34.000000000 +0000
@@ -13,7 +13,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptbase.h,v 1.103 2002/02/27 20:24:38 pdelaney Exp $
+ *  $Id: mptbase.h,v 1.133 2002/09/05 22:30:09 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -80,8 +80,8 @@
 #define COPYRIGHT	"Copyright (c) 1999-2002 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"2.00.11"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-2.00.11"
+#define MPT_LINUX_VERSION_COMMON	"2.02.01"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-2.02.01"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -295,6 +295,8 @@
  */
 
 typedef enum {
+	FC919X = 0x0819,
+	FC929X = 0x0829,
 	FC909 = 0x0909,
 	FC919 = 0x0919,
 	FC929 = 0x0929,
@@ -375,9 +377,13 @@
 	u8			 minSyncFactor;	/* 0xFF is async */
 	u8			 maxOffset;	/* 0 if async */
 	u8			 maxWidth;	/* 0 if narrow, 1 if wide*/
-	u8			 negoFlags;	/* 0 if WDTR/SDTR allowed */
+	u8			 negoFlags;	/* bit field, 0 if WDTR/SDTR/QAS allowed */
 	u8			 raidVolume;	/* set, if RAID Volume */
-	u8			 rsvd;		/* alignment */
+#ifdef ABORT_FIX
+	u8			 numAborts;
+#else
+	u8			 rsvd;
+#endif
 	u16			 rsvd1raid;
 	int			 npaths;
 	u16			 fc_phys_lun;
@@ -396,11 +402,13 @@
 	u32			 luns;		/* Max LUNs is 32 */
 	u8			 inq_data[SCSI_STD_INQUIRY_BYTES];	/* 36 */
 	u8			 pad0[4];
-	u8			 uniq_prepad[8];
 	u8			 inq00_data[20];
 	u8			 pad1[4];
 		/* IEEE Registered Extended Identifier
 		   obtained via INQUIRY VPD page 0x83 */
+		/* NOTE: Do not separate uniq_prepad and uniq_data
+		   as they are treateed as a single entity in the code */
+	u8			 uniq_prepad[8];
 	u8			 uniq_data[20];
 	u8			 pad2[4];
 	u8			 inqC3_data[12];
@@ -421,6 +429,7 @@
 
 #define MPT_TARGET_NO_NEGO_WIDE		0x01
 #define MPT_TARGET_NO_NEGO_SYNC		0x02
+#define MPT_TARGET_NO_NEGO_QAS		0x04
 
 typedef struct _VirtDevTracker {
 	struct _VirtDevice	*head;
@@ -459,11 +468,15 @@
  *	IOCTL structure and associated defines
  */
 
-#define MPT_IOCTL_STATUS_DID_TIMEOUT	0x01	/* The current IOCTL timed out */
+#define MPT_IOCTL_STATUS_DID_IOCRESET	0x01	/* IOC Reset occurred on the current*/
 #define MPT_IOCTL_STATUS_RF_VALID	0x02	/* The Reply Frame is VALID */
 #define MPT_IOCTL_STATUS_TIMER_ACTIVE	0x04	/* The timer is running */
 #define MPT_IOCTL_STATUS_SENSE_VALID	0x08	/* Sense data is valid */
 #define MPT_IOCTL_STATUS_COMMAND_GOOD	0x10	/* Command Status GOOD */
+#define MPT_IOCTL_STATUS_TMTIMER_ACTIVE	0x20	/* The TM timer is running */
+#define MPT_IOCTL_STATUS_TM_FAILED	0x40	/* User TM request failed */
+
+#define MPTCTL_RESET_OK			0x01	/* Issue Bus Reset */
 
 typedef struct _MPT_IOCTL {
 	struct _MPT_ADAPTER	*ioc;
@@ -471,9 +484,12 @@
 	u8			 ReplyFrame[MPT_DEFAULT_FRAME_SIZE];	/* reply frame data */
 	u8			 sense[MPT_SENSE_BUFFER_ALLOC];
 	int			 wait_done;	/* wake-up value for this ioc */
-	u8			 cmd;		/* current command */
+	u8			 rsvd;
 	u8			 status;	/* current command status */
-	u8			 pad[2];
+	u8			 reset;		/* 1 if bus reset allowed */
+	u8			 target;	/* target for reset */
+	void 			*tmPtr;
+	struct timer_list	 TMtimer;	/* timer function for this adapter */
 } MPT_IOCTL;
 
 /*
@@ -495,18 +511,23 @@
 /*
  *	Substructure to store SCSI specific configuration page data
  */
+						/* dvStatus defines: */
 #define MPT_SCSICFG_NEGOTIATE		0x01	/* Negotiate on next IO */
 #define MPT_SCSICFG_NEED_DV		0x02	/* Schedule DV */
 #define MPT_SCSICFG_DV_PENDING		0x04	/* DV on this physical id pending */
-#define MPT_SCSICFG_DV_DONE		0x08	/* DV on this physical id complete */
+#define MPT_SCSICFG_DV_NOT_DONE		0x08	/* DV has not been performed */
+#define MPT_SCSICFG_BLK_NEGO		0x10	/* WriteSDP1 with WDTR and SDTR disabled */
 
+						/* Args passed to writeSDP1: */
 #define MPT_SCSICFG_USE_NVRAM		0x01	/* WriteSDP1 using NVRAM */
 #define MPT_SCSICFG_ALL_IDS		0x02	/* WriteSDP1 to all IDS */
+/* #define MPT_SCSICFG_BLK_NEGO		0x10	   WriteSDP1 with WDTR and SDTR disabled */
 
 typedef	struct _ScsiCfgData {
 	int		*nvram;			/* table of device NVRAM values */
 	IOCPage3_t	*pIocPg3;		/* table of physical disks */
 	u8		 dvStatus[MPT_MAX_SCSI_DEVICES];
+	u8		 iocntr[MPT_MAX_SCSI_DEVICES];
 	int		 isRaid;		/* bit field, 1 if RAID */
 	u8		 minSyncFactor;		/* 0xFF if async */
 	u8		 maxSyncOffset;		/* 0 if async */
@@ -518,9 +539,17 @@
 	u8		 sdp0length;		/* SDP0 length  */
 	u8		 dvScheduled;		/* 1 if scheduled */
 	u8		 forceDv;		/* 1 to force DV scheduling */
+	u8		 noQas;			/* Disable QAS for this adapter */
 	u8		 rsvd[2];
 } ScsiCfgData;
 
+typedef struct _fw_image {
+	char		*fw;
+	dma_addr_t	 fw_dma;
+	u32		 size;
+	u32		 rsvd;
+} fw_image_t;
+
 /*
  *  Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
  */
@@ -580,9 +609,9 @@
 	int			 eventContext;	/* Next event context */
 	int			 eventLogSize;	/* Max number of cached events */
 	struct _mpt_ioctl_events *events;	/* pointer to event log */
-	u8			*FWImage;	/* Pointer to FW */
-	dma_addr_t		 FWImage_dma;
+	fw_image_t		**cached_fw;	/* Pointer to FW SG List */
 	Q_TRACKER		 configQ;	/* linked list of config. requests */
+	int			 num_fw_frags;	/* Number of SGE in FW SG List */
 	int			 hs_reply_idx;
 #ifndef MFCNT
 	u32			 pad0;
@@ -597,7 +626,8 @@
 	LANPage0_t		 lan_cnfg_page0;
 	LANPage1_t		 lan_cnfg_page1;
 	u8			 FirstWhoInit;
-	u8			 pad1[7];
+	u8			 upload_fw;	/* If set, do a fw upload */
+	u8			 pad1[6];
 } MPT_ADAPTER;
 
 
@@ -631,46 +661,21 @@
 #define MPT_HOSTEVENT_IOC_BRINGUP	0x91
 #define MPT_HOSTEVENT_IOC_RECOVER	0x92
 
-/* 32 vs 64 bit SGL code.
- *
+/* Define the generic types based on the size
+ * of the dma_addr_t type.
  */
-#if defined(__ia64__)
-typedef SGESimple64_t	MptSge_t;
-typedef SGEChain64_t	MptChain_t;
-
-#define cpu_to_leXX(y, p) { \
-	u32 low = (u32) (y & 0xFFFFFFFF); \
-	u32 high = (u32) (y >> 32); \
-	p.Low = cpu_to_le32(low); \
-	p.High = cpu_to_le32(high); \
-}
-
-#define leXX_to_cpu(y, p) { \
-	y = (dma_addr_t) le32_to_cpu(p.High); \
-	y = (y << 32); \
-	y |= le32_to_cpu(p.Low); \
-}
-
-#define MPT_SGE_ADDRESS_SIZE		MPI_SGE_FLAGS_64_BIT_ADDRESSING
-#define MPT_SCSIIO_MSG_FLAGS		MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64
-
-
-#else
-
-typedef SGESimple32_t	MptSge_t;
-typedef SGEChain32_t	MptChain_t;
-#define cpu_to_leXX(y,p) { \
-	p = cpu_to_le32(y); \
-}
-
-#define leXX_to_cpu(y,p) { \
-	y = le32_to_cpu(p); \
-}
-
-#define MPT_SGE_ADDRESS_SIZE		MPI_SGE_FLAGS_32_BIT_ADDRESSING
-#define MPT_SCSIIO_MSG_FLAGS		MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32
-
-#endif
+typedef struct _mpt_sge {
+	u32		FlagsLength;
+	dma_addr_t	Address;
+} MptSge_t;
+
+#define mpt_addr_size() \
+	((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SGE_FLAGS_64_BIT_ADDRESSING : \
+		MPI_SGE_FLAGS_32_BIT_ADDRESSING)
+
+#define mpt_msg_flags() \
+	((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \
+		MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -707,6 +712,13 @@
 #define dsgprintk(x)
 #endif
 
+#if defined(MPT_DEBUG_DL) || defined(MPT_DEBUG)
+#define ddlprintk(x)  printk x
+#else
+#define ddlprintk(x)
+#endif
+
+
 #ifdef MPT_DEBUG_DV
 #define ddvprintk(x)  printk x
 #else
@@ -731,6 +743,12 @@
 #define dtmprintk(x)
 #endif
 
+#ifdef MPT_DEBUG_NEH
+#define nehprintk(x) printk x
+#else
+#define nehprintk(x)
+#endif
+
 #define MPT_INDEX_2_MFPTR(ioc,idx) \
 	(MPT_FRAME_HDR*)( (u8*)(ioc)->req_frames + (ioc)->req_sz * (idx) )
 
@@ -831,6 +849,15 @@
 #define MPT_NVRAM_WIDE_DISABLE		(0x00100000)
 #define MPT_NVRAM_BOOT_CHOICE		(0x00200000)
 
+#ifdef MPT_SCSI_USE_NEW_EH
+/* The TM_STATE variable is used to provide strict single threading of TM
+ * requests as well as communicate TM error conditions.
+ */
+#define TM_STATE_NONE          (0)
+#define	TM_STATE_IN_PROGRESS   (1)
+#define	TM_STATE_ERROR	       (2)
+#endif
+
 typedef struct _MPT_SCSI_HOST {
 	MPT_ADAPTER		 *ioc;
 	int			  port;
@@ -868,7 +895,12 @@
 	u8			  is_spi;		/* Parallel SCSI i/f */
 	u8			  negoNvram;		/* DV disabled, nego NVRAM */
 	u8			  is_multipath;		/* Multi-path compatible */
+#ifdef MPT_SCSI_USE_NEW_EH
+	u8                        tmState;
+	u8			  rsvd[1];
+#else
 	u8			  rsvd[2];
+#endif
 	MPT_FRAME_HDR		 *tmPtr;		/* Ptr to TM request*/
 	MPT_FRAME_HDR		 *cmdPtr;		/* Ptr to nonOS request */
 	struct scsi_cmnd	 *abortSCpnt;
@@ -950,6 +982,9 @@
 extern MPT_FRAME_HDR	*mpt_get_msg_frame(int handle, int iocid);
 extern void	 mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf);
 extern void	 mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf);
+extern void	 mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr);
+extern void	 mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr);
+
 extern int	 mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req, int sleepFlag);
 extern int	 mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait, int sleepFlag);
 extern int	 mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
@@ -959,6 +994,8 @@
 extern void	 mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
 extern int	 mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
 extern int	 mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
+extern void	*mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz);
+extern void	 mpt_free_fw_memory(MPT_ADAPTER *ioc, fw_image_t **alt_img);
 
 /*
  *  Public data decl's...
@@ -1016,7 +1053,7 @@
 #define MPT_SGE_FLAGS_END_OF_BUFFER		(0x40000000)
 #define MPT_SGE_FLAGS_LOCAL_ADDRESS		(0x08000000)
 #define MPT_SGE_FLAGS_DIRECTION			(0x04000000)
-#define MPT_SGE_FLAGS_ADDRESSING		(MPT_SGE_ADDRESS_SIZE << MPI_SGE_FLAGS_SHIFT)
+#define MPT_SGE_FLAGS_ADDRESSING		(mpt_addr_size() << MPI_SGE_FLAGS_SHIFT)
 #define MPT_SGE_FLAGS_END_OF_LIST		(0x01000000)
 
 #define MPT_SGE_FLAGS_TRANSACTION_ELEMENT	(0x00000000)
@@ -1029,14 +1066,14 @@
 	 MPT_SGE_FLAGS_END_OF_BUFFER |	\
 	 MPT_SGE_FLAGS_END_OF_LIST |	\
 	 MPT_SGE_FLAGS_SIMPLE_ELEMENT |	\
-	 MPT_SGE_FLAGS_ADDRESSING |	\
+	 MPT_SGE_FLAGS_ADDRESSING | \
 	 MPT_TRANSFER_IOC_TO_HOST)
 #define MPT_SGE_FLAGS_SSIMPLE_WRITE \
 	(MPT_SGE_FLAGS_LAST_ELEMENT |	\
 	 MPT_SGE_FLAGS_END_OF_BUFFER |	\
 	 MPT_SGE_FLAGS_END_OF_LIST |	\
 	 MPT_SGE_FLAGS_SIMPLE_ELEMENT |	\
-	 MPT_SGE_FLAGS_ADDRESSING |	\
+	 MPT_SGE_FLAGS_ADDRESSING | \
 	 MPT_TRANSFER_HOST_TO_IOC)
 
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/message/fusion/mptctl.c linux-2.4.20/drivers/message/fusion/mptctl.c
--- linux-2.4.19/drivers/message/fusion/mptctl.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/message/fusion/mptctl.c	2002-10-29 11:18:32.000000000 +0000
@@ -34,7 +34,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptctl.c,v 1.52 2002/02/27 18:44:24 sralston Exp $
+ *  $Id: mptctl.c,v 1.59 2002/09/05 22:30:10 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -126,7 +126,7 @@
  * arg contents specific to function.
  */
 static int mptctl_fw_download(unsigned long arg);
-static int mptctl_getiocinfo (unsigned long arg);
+static int mptctl_getiocinfo (unsigned long arg, unsigned int cmd);
 static int mptctl_gettargetinfo (unsigned long arg);
 static int mptctl_readtest (unsigned long arg);
 static int mptctl_mpt_command (unsigned long arg);
@@ -155,6 +155,9 @@
 static void kfree_sgl( MptSge_t *sgl, dma_addr_t sgl_dma,
 		struct buflist *buflist, MPT_ADAPTER *ioc);
 static void mptctl_timer_expired (unsigned long data);
+static int  mptctl_bus_reset(MPT_IOCTL *ioctl);
+static int mptctl_set_tm_flags(MPT_SCSI_HOST *hd);
+static void mptctl_free_tm_flags(MPT_ADAPTER *ioc);
 
 /*
  * Reset Handler cleanup function
@@ -188,23 +191,6 @@
 static pMPIDefaultReply_t ReplyMsg = NULL;
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*	Function to return 0 if the sge Address member is 0 and
- *	non-zero else.  Used in the mpt_do_fw_download routines.
- */
-static inline int
-mptctl_test_address(MptSge_t *sge)
-{
-#ifdef __ia64__
-	if ((sge->Address.Low) || (sge->Address.High))
-		return 1;
-	else
-		return 0;
-#else
-	return sge->Address;
-#endif
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *	mptctl_syscall_down - Down the MPT adapter syscall semaphore.
  *	@ioc: Pointer to MPT adapter
@@ -221,6 +207,11 @@
 	int rc = 0;
 	dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock));
 
+	if (ioc->ioctl->tmPtr != NULL) {
+		dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down BUSY\n"));
+		return -EBUSY;
+	}
+
 #if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
 	if (!nonblock) {
 		if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id]))
@@ -268,7 +259,29 @@
 		 * queues.
 		 * Main callback will free message and reply frames.
 		 */
-		if (ioc->ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE) {
+		if (reply && (cmd == MPI_FUNCTION_SCSI_TASK_MGMT) &&
+		    (ioc->ioctl->status & MPT_IOCTL_STATUS_TMTIMER_ACTIVE)) {
+			/* This is internally generated TM
+			 */
+			del_timer (&ioc->ioctl->TMtimer);
+			ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TMTIMER_ACTIVE;
+
+			mptctl_free_tm_flags(ioc);
+
+			/* If TM failed, reset the timer on the existing command,
+			 * will trigger an adapter reset.
+			 */
+			iocStatus = reply->u.reply.IOCStatus & MPI_IOCSTATUS_MASK;
+			if (iocStatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED) {
+				if (ioc->ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE) {
+					del_timer (&ioc->ioctl->timer);
+					ioc->ioctl->timer.expires = jiffies + HZ;
+					add_timer(&ioc->ioctl->timer);
+				}
+			}
+			ioc->ioctl->tmPtr = NULL;
+
+		} else if (ioc->ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE) {
 			/* Delete this timer
 			 */
 			del_timer (&ioc->ioctl->timer);
@@ -294,10 +307,12 @@
 				if (iocStatus  == MPI_IOCSTATUS_SUCCESS)
 					ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
 
-				if ((iocStatus  == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) || 
-						(iocStatus  == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) {
-					if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
-						(cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+				if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+					(cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+					ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
+
+					if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) ||
+						(iocStatus == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) {
 						ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
 					}
 				}
@@ -313,9 +328,15 @@
 					memcpy(ioc->ioctl->sense, sense_data, sz);
 					ioc->ioctl->status |= MPT_IOCTL_STATUS_SENSE_VALID;
 				}
+
+				if (cmd == MPI_FUNCTION_SCSI_TASK_MGMT)
+					mptctl_free_tm_flags(ioc);
+
+
 			} else if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
 					(cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
 				ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
+				ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
 			}
 
 			/* We are done, issue wake up
@@ -343,17 +364,157 @@
 static void mptctl_timer_expired (unsigned long data)
 {
 	MPT_IOCTL *ioctl = (MPT_IOCTL *) data;
+	int rc = 1;
 
 	dctlprintk((KERN_NOTICE MYNAM ": Timer Expired! Host %d\n",
 				ioctl->ioc->id));
+	if (ioctl == NULL)
+		return;
+
+	if (ioctl->reset & MPTCTL_RESET_OK)
+		rc = mptctl_bus_reset(ioctl);
+
+	if (rc) {
+		/* Issue a reset for this device.
+		 * The IOC is not responding.
+		 */
+		mpt_HardResetHandler(ioctl->ioc, NO_SLEEP);
+	}
+	return;
+
+}
+
+/* mptctl_bus_reset
+ *
+ * Bus reset code.
+ *
+ */
+static int mptctl_bus_reset(MPT_IOCTL *ioctl)
+{
+	MPT_FRAME_HDR	*mf;
+	SCSITaskMgmt_t	*pScsiTm;
+	MPT_SCSI_HOST	*hd;
+	int		 ii;
+	int		 retval;
+
+
+	ioctl->reset &= ~MPTCTL_RESET_OK;
+
+	if (ioctl->ioc->sh == NULL)
+		return -EPERM;
+	
+	hd = (MPT_SCSI_HOST *) ioctl->ioc->sh->hostdata;
+	if (hd == NULL)
+		return -EPERM;
+
+	/* Single threading ....
+	 */
+	if (mptctl_set_tm_flags(hd) != 0)
+		return -EPERM;
 
-	/* Issue a reset for this device.
-	 * The IOC is not responding.
+	/* Send request
 	 */
-	mpt_HardResetHandler(ioctl->ioc, NO_SLEEP);
+	if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc->id)) == NULL) {
+		dtmprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n",
+				ioctl->ioc->name));
+
+		mptctl_free_tm_flags(ioctl->ioc);
+		return -ENOMEM;
+	}
+
+	dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
+			ioctl->ioc->name, mf));
+
+	pScsiTm = (SCSITaskMgmt_t *) mf;
+	pScsiTm->TargetID = ioctl->target;
+	pScsiTm->Bus = hd->port;	/* 0 */
+	pScsiTm->ChainOffset = 0;
+	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+	pScsiTm->Reserved = 0;
+	pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+	pScsiTm->Reserved1 = 0;
+	pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
+
+	for (ii= 0; ii < 8; ii++)
+		pScsiTm->LUN[ii] = 0;
+
+	for (ii=0; ii < 7; ii++)
+		pScsiTm->Reserved2[ii] = 0;
+
+	pScsiTm->TaskMsgContext = 0;
+	dtmprintk((MYIOC_s_INFO_FMT "mptctl_bus_reset: issued.\n", ioctl->ioc->name));
+
+	ioctl->tmPtr = mf;
+	ioctl->TMtimer.expires = jiffies + HZ * 20;	/* 20 seconds */
+	ioctl->status |= MPT_IOCTL_STATUS_TMTIMER_ACTIVE;
+	add_timer(&ioctl->TMtimer);
+
+	retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc->id,
+			sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, NO_SLEEP);
+
+	if (retval != 0) {
+		dtmprintk((MYIOC_s_WARN_FMT "_send_handshake FAILED!"
+			" (hd %p, ioc %p, mf %p) \n", ioctl->ioc->name, hd, hd->ioc, mf));
+
+		mptctl_free_tm_flags(ioctl->ioc);
+		del_timer(&ioctl->TMtimer);
+		mpt_free_msg_frame(mptctl_id, ioctl->ioc->id, mf);
+		ioctl->tmPtr = NULL;
+	}
+
+	return retval;
+}
+
+static int
+mptctl_set_tm_flags(MPT_SCSI_HOST *hd) {
+	unsigned long flags;
+
+	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+#ifdef MPT_SCSI_USE_NEW_EH
+	if (hd->tmState == TM_STATE_NONE) {
+		hd->tmState = TM_STATE_IN_PROGRESS;
+		hd->tmPending = 1;
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+	} else {
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+		return -EBUSY;
+	}
+#else
+	if (hd->tmPending) {
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+		return -EBUSY;
+	} else {
+		hd->tmPending = 1;
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+	}
+#endif
+	return 0;
+}
+
+static void
+mptctl_free_tm_flags(MPT_ADAPTER *ioc)
+{
+	MPT_SCSI_HOST * hd;
+	unsigned long flags;
+
+	hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+	if (hd == NULL)
+		return;
+
+	spin_lock_irqsave(&ioc->FreeQlock, flags);
+#ifdef MPT_SCSI_USE_NEW_EH
+	hd->tmState = TM_STATE_ERROR;
+	hd->tmPending = 0;
+	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+#else
+	hd->tmPending = 0;
+	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+#endif
+
 	return;
 }
 
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /* mptctl_ioc_reset
  *
@@ -372,14 +533,17 @@
 
 		/* Someone has called the reset handler to
 		 * do a hard reset. No more replies from the FW.
-		 * Delete the timer.
+		 * Delete the timer. TM flags cleaned up by SCSI driver.
+		 * Do not need to free msg frame, as re-initialized
 		 */
 		if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE)){
-
-			/* Delete this timer
-			 */
 			del_timer(&ioctl->timer);
 		}
+		if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TMTIMER_ACTIVE)){
+			ioctl->status &= ~MPT_IOCTL_STATUS_TMTIMER_ACTIVE;
+			del_timer(&ioctl->TMtimer);
+			mpt_free_msg_frame(mptctl_id, ioc->id, ioctl->tmPtr);
+		}
 
 	} else {
 		/* Set the status and continue IOCTL
@@ -388,7 +552,7 @@
 		 * called.
 		 */
 		if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE)){
-			ioctl->status = MPT_IOCTL_STATUS_DID_TIMEOUT;
+			ioctl->status = MPT_IOCTL_STATUS_DID_IOCRESET;
 
 			/* Wake up the calling process
 			 */
@@ -459,6 +623,7 @@
 	}
 	ret = -ENXIO;				/* (-6) No such device or address */
 
+
 	/* Test for Compaq-specific IOCTL's.
 	 */
 	if ((cmd == CPQFCTS_GETPCIINFO) || (cmd == CPQFCTS_CTLR_STATUS) ||
@@ -472,18 +637,20 @@
 	iocnumX = khdr.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		printk(KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnumX);
+		dtmprintk((KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnumX));
 		return -ENODEV;
 	}
 
+
+
 	/* Handle those commands that are just returning
 	 * information stored in the driver.
 	 * These commands should never time out and are unaffected
 	 * by TM and FW reloads.
 	 */
-	if (cmd == MPTIOCINFO) {
-		return mptctl_getiocinfo(arg);
+	if ((cmd & ~IOCSIZE_MASK) == (MPTIOCINFO & ~IOCSIZE_MASK)) {
+		return mptctl_getiocinfo(arg, _IOC_SIZE(cmd));
 	} else if (cmd == MPTTARGETINFO) {
 		return mptctl_gettargetinfo(arg);
 	} else if (cmd == MPTTEST) {
@@ -541,9 +708,9 @@
 	}
 
 	if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
-		printk(KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n",
-				__FILE__, __LINE__, krinfo.hdr.iocnum);
-		return -ENXIO; /* (-6) No such device or address */
+		dtmprintk((KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n",
+				__FILE__, __LINE__, krinfo.hdr.iocnum));
+		return -ENODEV; /* (-6) No such device or address */
 	}
 
 	if (mpt_HardResetHandler(iocp, NO_SLEEP) != 0) {
@@ -625,8 +792,8 @@
 	MPT_FRAME_HDR		*mf;
 	MPT_ADAPTER		*iocp;
 	FWDownloadTCSGE_t	*ptsge;
-	MptSge_t		*sgl;
-	MptSge_t		*sgOut, *sgIn;
+	MptSge_t		*sgl, *sgIn;
+	char			*sgOut;
 	struct buflist		*buflist;
 	struct buflist		*bl;
 	dma_addr_t		 sgl_dma;
@@ -649,9 +816,9 @@
 	dctlprintk((KERN_INFO "DbG: kfwdl.ioc   = %04xh\n", ioc));
 
 	if ((ioc = mpt_verify_adapter(ioc, &iocp)) < 0) {
-		printk("%s@%d::_ioctl_fwdl - ioc%d not found!\n",
-				__FILE__, __LINE__, ioc);
-		return -ENXIO; /* (-6) No such device or address */
+		dtmprintk(("%s@%d::_ioctl_fwdl - ioc%d not found!\n",
+				__FILE__, __LINE__, ioc));
+		return -ENODEV; /* (-6) No such device or address */
 	}
 
 	/*  Valid device. Get a message frame and construct the FW download message.
@@ -660,7 +827,7 @@
 		return -EAGAIN;
 	dlmsg = (FWDownload_t*) mf;
 	ptsge = (FWDownloadTCSGE_t *) &dlmsg->SGL;
-	sgOut = (MptSge_t *) (ptsge + 1);
+	sgOut = (char *) (ptsge + 1);
 
 	/*
 	 * Construct f/w download request
@@ -715,7 +882,8 @@
 	 *	96		8
 	 *	64		4
 	 */
-	maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) / sizeof(MptSge_t);
+	maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) 
+			/ (sizeof(dma_addr_t) + sizeof(u32));
 	if (numfrags > maxfrags) {
 		ret = -EMLINK;
 		goto fwdl_out;
@@ -738,11 +906,11 @@
 		 * Note: we should not have anything but Simple as
 		 *	Chain SGE are illegal.
 		 */
-		nib = (le32_to_cpu(sgIn->FlagsLength) & 0x30000000) >> 28;
+		nib = (sgIn->FlagsLength & 0x30000000) >> 28;
 		if (nib == 0 || nib == 3) {
 			;
-		} else if (mptctl_test_address(sgIn)) {
-			*sgOut = *sgIn;
+		} else if (sgIn->Address) {
+			mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
 			n++;
 			if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
 				printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
@@ -754,7 +922,7 @@
 		}
 		sgIn++;
 		bl++;
-		sgOut++;
+		sgOut += (sizeof(dma_addr_t) + sizeof(u32));
 	}
 
 #ifdef MPT_DEBUG
@@ -840,22 +1008,19 @@
 kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
 		 struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc)
 {
-	MptSge_t	*sglbuf = NULL;		/* pointer to array of SGE
-						 * and chain buffers */
+	MptSge_t	*sglbuf = NULL;		/* pointer to array of SGE */
+						/* and chain buffers */
 	struct buflist	*buflist = NULL;	/* kernel routine */
 	MptSge_t	*sgl;
-	MptChain_t	*last_chain = NULL;
 	int		 numfrags = 0;
 	int		 fragcnt = 0;
 	int		 alloc_sz = MIN(bytes,MAX_KMALLOC_SZ);	// avoid kernel warning msg!
 	int		 bytes_allocd = 0;
 	int		 this_alloc;
 	dma_addr_t	 pa;					// phys addr
-	int		 chaincnt = 0;
 	int		 i, buflist_ent;
 	int		 sg_spill = MAX_FRAGS_SPILL1;
 	int		 dir;
-
 	/* initialization */
 	*frags = 0;
 	*blp = NULL;
@@ -892,7 +1057,7 @@
 	 *
 	 */
 	sgl = sglbuf;
-	sg_spill = ((ioc->req_sz  - sge_offset)/ sizeof(MptSge_t)) - 1;
+	sg_spill = ((ioc->req_sz - sge_offset)/(sizeof(dma_addr_t) + sizeof(u32))) - 1;
 	while (bytes_allocd < bytes) {
 		this_alloc = MIN(alloc_sz, bytes-bytes_allocd);
 		buflist[buflist_ent].len = this_alloc;
@@ -913,11 +1078,9 @@
 			dma_addr_t dma_addr;
 
 			bytes_allocd += this_alloc;
-
-			/* Write one SIMPLE sge */
-			sgl->FlagsLength = cpu_to_le32(0x10000000|sgdir|this_alloc);
+			sgl->FlagsLength = (0x10000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|this_alloc);
 			dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir);
-			cpu_to_leXX(dma_addr, sgl->Address);
+			sgl->Address = dma_addr;
 
 			fragcnt++;
 			numfrags++;
@@ -930,52 +1093,13 @@
 
 		/* Need to chain? */
 		if (fragcnt == sg_spill) {
-			dma_addr_t chain_link;
-
-			/* If there is a chain element, set the offset
-			 * (in 32 bit words) to the next chain element.
-			 * fragcnt = # sge = 8 bytes = 2 words
-			 *
-			 * Set the length of the chain element (bytes)
-			 * This includes the size of the next chain element.
-			 *
-			 * We are now done with last_chain and the previous
-			 * buffer.
-			 */
-			if (last_chain != NULL) {
-				last_chain->NextChainOffset = fragcnt * 2;
-				last_chain->Length = cpu_to_le16((fragcnt+1) * 8);
-			}
-
-			/* Finish the current buffer:
-			 * - add the LE bit to last sge
-			 * - add the chain element
-			*/
-			sgl[-1].FlagsLength |= cpu_to_le32(0x80000000);
-
-			chain_link = (*sglbuf_dma) +
-				((u8 *)(sgl+1) - (u8 *)sglbuf);
-
-			/* Write one CHAIN sge */
-//			sgl->FlagsLength = cpu_to_le32(0x30000080);
-			sgl->FlagsLength = cpu_to_le32(0x30000000);
-			cpu_to_leXX(chain_link, sgl->Address);
-
-			/* Reset everything for the next SGE series,
-			 * save a ptr to the chain element in last_chain
-			 */
-			fragcnt = 0;
-//			sg_spill = MAX_FRAGS_SPILL2;
-			sg_spill = (ioc->req_sz / sizeof(MptSge_t)) - 1;
-
-			last_chain = (MptChain_t*)sgl;
-			chaincnt++;
-			numfrags++;
-			sgl++;
+			printk(KERN_WARNING MYNAM "-SG: No can do - " "Chain required!   :-(\n");
+			printk(KERN_WARNING MYNAM "(freeing %d frags)\n", numfrags);
+			goto free_and_fail;
 		}
 
 		/* overflow check... */
-		if (numfrags*8 > MAX_SGL_BYTES) {
+		if (numfrags*8 > MAX_SGL_BYTES){
 			/* GRRRRR... */
 			printk(KERN_WARNING MYNAM "-SG: No can do - "
 					    "too many SG frags!   :-(\n");
@@ -986,19 +1110,14 @@
 	}
 
 	/* Last sge fixup: set LE+eol+eob bits */
-	sgl[-1].FlagsLength |= cpu_to_le32(0xC1000000);
-
-	/* Chain fixup needed? */	/* SteveR CHECKME!!! */
-//	if (last_chain != NULL && fragcnt < 16)
-	if (last_chain != NULL)
-		last_chain->Length = cpu_to_le16(fragcnt * 8);
+	sgl[-1].FlagsLength |= 0xC1000000;
 
 	*frags = numfrags;
 	*blp = buflist;
 
 	dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
-			   "%d SG frags generated!  (%d CHAIN%s)\n",
-			   numfrags, chaincnt, chaincnt>1?"s":""));
+			   "%d SG frags generated!\n",
+			   numfrags));
 
 	dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
 			   "last (big) alloc_sz=%d\n",
@@ -1015,10 +1134,10 @@
 			u8 *kptr;
 			int len;
 
-			if ((le32_to_cpu(sglbuf[i].FlagsLength) >> 24) == 0x30)
+			if ((sglbuf[i].FlagsLength >> 24) == 0x30)
 				continue;
 
-			leXX_to_cpu(dma_addr, sglbuf[i].Address);
+			dma_addr = sglbuf[i].Address;
 			kptr = buflist[i].kptr;
 			len = buflist[i].len;
 
@@ -1043,22 +1162,22 @@
 	int		 dir;
 	int		 n = 0;
 
-	if ((le32_to_cpu(sg->FlagsLength) & 0x04000000))
+	if (sg->FlagsLength & 0x04000000)
 		dir = PCI_DMA_TODEVICE;
 	else
 		dir = PCI_DMA_FROMDEVICE;
 
-	nib = (le32_to_cpu(sg->FlagsLength) & 0xF0000000) >> 28;
+	nib = (sg->FlagsLength & 0xF0000000) >> 28;
 	while (! (nib & 0x4)) { /* eob */
 		/* skip ignore/chain. */
 		if (nib == 0 || nib == 3) {
 			;
-		} else if (mptctl_test_address(sg)) {
+		} else if (sg->Address) {
 			dma_addr_t dma_addr;
 			void *kptr;
 			int len;
 
-			leXX_to_cpu(dma_addr, sg->Address);
+			dma_addr = sg->Address;
 			kptr = bl->kptr;
 			len = bl->len;
 			pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
@@ -1071,12 +1190,12 @@
 	}
 
 	/* we're at eob! */
-	if (mptctl_test_address(sg)) {
+	if (sg->Address) {
 		dma_addr_t dma_addr;
 		void *kptr;
 		int len;
 
-		leXX_to_cpu(dma_addr, sg->Address);
+		dma_addr = sg->Address;
 		kptr = bl->kptr;
 		len = bl->len;
 		pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
@@ -1100,7 +1219,7 @@
  *		-ENODEV  if no such device/adapter
  */
 static int
-mptctl_getiocinfo (unsigned long arg)
+mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
 {
 	struct mpt_ioctl_iocinfo *uarg = (struct mpt_ioctl_iocinfo *) arg;
 	struct mpt_ioctl_iocinfo karg;
@@ -1113,10 +1232,18 @@
 	unsigned int		max_id;
 	int			ii;
 	int			port;
+	int			cim_rev;
 	u8			revision;
 
 	dctlprintk((": mptctl_getiocinfo called.\n"));
-	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_iocinfo))) {
+	if (data_size == sizeof(struct mpt_ioctl_iocinfo))
+		cim_rev = 1;
+	else if (data_size == (sizeof(struct mpt_ioctl_iocinfo) - sizeof(struct mpt_ioctl_pci_info)))
+		cim_rev = 0;
+	else
+		return -EFAULT;
+
+	if (copy_from_user(&karg, uarg, data_size)) {
 		printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
 			"Unable to read in mpt_ioctl_iocinfo struct @ %p\n",
 				__FILE__, __LINE__, (void*)uarg);
@@ -1125,15 +1252,15 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
 	/* Verify the data transfer size is correct.
 	 * Ignore the port setting.
 	 */
-	if (karg.hdr.maxDataSize != sizeof(struct mpt_ioctl_iocinfo)) {
+	if (karg.hdr.maxDataSize != data_size) {
 		printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
 			"Structure size mismatch. Command not completed.\n",
 				__FILE__, __LINE__);
@@ -1161,10 +1288,17 @@
 	karg.subSystemVendor = pdev->subsystem_vendor;
 #endif
 
+	if (cim_rev == 1) {
+		/* Get the PCI bus, device, and function numbers for the IOC
+		 */
+		karg.pciInfo.u.bits.busNumber = pdev->bus->number;
+		karg.pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn );
+		karg.pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn );
+	}
+
 	/* Get number of devices
          */
-	if ( (sh = ioc->sh) != NULL) {
-
+	if ((sh = ioc->sh) != NULL) {
 		 /* sh->max_id = maximum target ID + 1
 		 */
 		max_id = sh->max_id - 1;
@@ -1197,8 +1331,7 @@
 
 	/* Copy the data from kernel memory to user memory
 	 */
-	if (copy_to_user((char *)arg, &karg,
-				sizeof(struct mpt_ioctl_iocinfo))) {
+	if (copy_to_user((char *)arg, &karg, data_size)) {
 		printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
 			"Unable to write out mpt_ioctl_iocinfo struct @ %p\n",
 				__FILE__, __LINE__, (void*)uarg);
@@ -1246,8 +1379,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -1377,8 +1510,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -1435,8 +1568,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -1473,8 +1606,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -1521,8 +1654,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -1558,10 +1691,12 @@
 	struct mpt_ioctl_replace_fw	*uarg = (struct mpt_ioctl_replace_fw *) arg;
 	struct mpt_ioctl_replace_fw	 karg;
 	MPT_ADAPTER		 *ioc;
+	fw_image_t		 **fwmem = NULL;
 	int			 iocnum;
-	u8			 *mem = NULL;
-	dma_addr_t		 mem_dma;
-	int			 oldFwSize, newFwSize;
+	int			 newFwSize;
+	int			 num_frags, alloc_sz;
+	int			 ii;
+	u32			 offset;
 
 	dctlprintk(("mptctl_replace_fw called.\n"));
 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) {
@@ -1573,52 +1708,49 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
 	/* If not caching FW, return 0
 	 */
-	if ((ioc->FWImage == NULL) && (ioc->alt_ioc) && (ioc->alt_ioc->FWImage == NULL)) {
+	if ((ioc->cached_fw == NULL) && (ioc->alt_ioc) && (ioc->alt_ioc->cached_fw == NULL))
 		return 0;
-	}
-
 
 	/* Allocate memory for the new FW image
 	 */
 	newFwSize = karg.newImageSize;
-	mem = pci_alloc_consistent(ioc->pcidev, newFwSize, &mem_dma);
-	if (mem == NULL)
+	fwmem = mpt_alloc_fw_memory(ioc, newFwSize, &num_frags, &alloc_sz); 
+	if (fwmem == NULL)
 		return -ENOMEM;
 
-	ioc->alloc_total += newFwSize;	
+	offset = 0;
+	for (ii = 0; ii < num_frags; ii++) {
+		/* Copy the data from user memory to kernel space
+		 */
+		if (copy_from_user(fwmem[ii]->fw, uarg->newImage + offset, fwmem[ii]->size)) {
+			printk(KERN_ERR "%s@%d::mptctl_replace_fw - "
+				"Unable to read in mpt_ioctl_replace_fw image @ %p\n",
+					__FILE__, __LINE__, (void*)uarg);
 
-	/* Copy the data from user memory to kernel space
-	 */
-	if (copy_from_user(mem, uarg->newImage, newFwSize)) {
-		printk(KERN_ERR "%s@%d::mptctl_replace_fw - "
-			"Unable to read in mpt_ioctl_replace_fw image @ %p\n",
-				__FILE__, __LINE__, (void*)uarg);
-		pci_free_consistent(ioc->pcidev, newFwSize, mem, mem_dma);
-		ioc->alloc_total -= newFwSize;	
-		return -EFAULT;
+			mpt_free_fw_memory(ioc, fwmem);
+			return -EFAULT;
+		}
+		offset += fwmem[ii]->size;
 	}
 
+
 	/* Free the old FW image 
 	 */
-	oldFwSize = ioc->facts.FWImageSize;
-	if (ioc->FWImage) {
-		pci_free_consistent(ioc->pcidev, oldFwSize, ioc->FWImage, ioc->FWImage_dma);
-		ioc->alloc_total -= oldFwSize;	
-		ioc->FWImage = mem;
-		ioc->FWImage_dma = mem_dma;
-		
-	} else if ((ioc->alt_ioc) && (ioc->alt_ioc->FWImage)) {
-		pci_free_consistent(ioc->pcidev, oldFwSize, ioc->alt_ioc->FWImage, ioc->alt_ioc->FWImage_dma);
-		ioc->alloc_total -= oldFwSize;	
-		ioc->alt_ioc->FWImage = mem;
-		ioc->alt_ioc->FWImage_dma = mem_dma;
+	if (ioc->cached_fw) {
+		mpt_free_fw_memory(ioc, 0);
+		ioc->cached_fw = fwmem;
+		ioc->alloc_total += alloc_sz;
+	} else if ((ioc->alt_ioc) && (ioc->alt_ioc->cached_fw)) {
+		mpt_free_fw_memory(ioc->alt_ioc, 0);
+		ioc->alt_ioc->cached_fw = fwmem;
+		ioc->alt_ioc->alloc_total += alloc_sz;
 	}
 
 	/* Update IOCFactsReply
@@ -1662,8 +1794,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -1682,6 +1814,7 @@
  *		-ENODEV if no such device/adapter
  *		-ETIME	if timer expires
  *		-ENOMEM if memory allocation error
+ *		-EPERM if SCSI I/O and target is untagged
  */
 static int
 mptctl_do_mpt_command (struct mpt_ioctl_command karg, char *mfPtr, int local)
@@ -1689,7 +1822,7 @@
 	MPT_ADAPTER	*ioc;
 	MPT_FRAME_HDR	*mf = NULL;
 	MPIHeader_t	*hdr;
-	MptSge_t	*psge;
+	char		*psge;
 	MptSge_t	*this_sge = NULL;
 	MptSge_t	*sglbuf = NULL;
 	struct buflist	bufIn;	/* data In buffer */
@@ -1699,17 +1832,18 @@
 	int		dir;	/* PCI data direction */
 	int		sgSize = 0;	/* Num SG elements */
 	int		this_alloc;
-	int iocnum, flagsLength;
-	int sz, rc = 0;
-	int msgContext;
+	int		 iocnum, flagsLength;
+	int		 sz, rc = 0;
+	int		 msgContext;
+	int		tm_flags_set = 0;
 	u16		req_idx;
 
 	dctlprintk(("mptctl_do_mpt_command called.\n"));
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 	if (!ioc->ioctl) {
@@ -1717,7 +1851,7 @@
 			"No memory available during driver init.\n",
 				__FILE__, __LINE__);
 		return -ENOMEM;
-	} else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_TIMEOUT) {
+	} else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) {
 		printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
 			"Busy with IOC Reset \n", __FILE__, __LINE__);
 		return -EBUSY;
@@ -1727,9 +1861,9 @@
 	 */
 	sz = karg.dataSgeOffset * 4;
 	if (karg.dataInSize > 0)
-		sz += sizeof (MptSge_t);
+		sz += sizeof(dma_addr_t) + sizeof(u32);
 	if (karg.dataOutSize > 0)
-		sz += sizeof (MptSge_t);
+		sz += sizeof(dma_addr_t) + sizeof(u32);
 
 	if ( sz > ioc->req_sz) {
 		printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
@@ -1792,7 +1926,7 @@
 			int target = (int) pScsiReq->TargetID;
 			int dataSize;
 
-			pScsiReq->MsgFlags = MPT_SCSIIO_MSG_FLAGS;
+			pScsiReq->MsgFlags = mpt_msg_flags();
 
 			/* verify that app has not requested
 			 *	more sense data than driver
@@ -1830,6 +1964,9 @@
 			pScsiReq->Control = cpu_to_le32(scsidir | qtag);
 			pScsiReq->DataLength = cpu_to_le32(dataSize);
 
+			ioc->ioctl->reset = MPTCTL_RESET_OK;
+			ioc->ioctl->target = target;
+
 		} else {
 			printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
 				"SCSI driver is not loaded. \n",
@@ -1851,7 +1988,7 @@
 			int scsidir = MPI_SCSIIO_CONTROL_READ;
 			int dataSize;
 
-			pScsiReq->MsgFlags = MPT_SCSIIO_MSG_FLAGS;
+			pScsiReq->MsgFlags = mpt_msg_flags();
 
 			/* verify that app has not requested
 			 *	more sense data than driver
@@ -1884,6 +2021,8 @@
 			pScsiReq->Control = cpu_to_le32(scsidir | qtag);
 			pScsiReq->DataLength = cpu_to_le32(dataSize);
 
+			ioc->ioctl->reset = MPTCTL_RESET_OK;
+			ioc->ioctl->target = pScsiReq->TargetID;
 		} else {
 			printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
 				"SCSI driver is not loaded. \n",
@@ -1893,6 +2032,23 @@
 		}
 		break;
 
+	case MPI_FUNCTION_SCSI_TASK_MGMT:
+		{ 
+			MPT_SCSI_HOST *hd = NULL;
+			if ((ioc->sh == NULL) || ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) {
+				printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+					"SCSI driver not loaded or SCSI host not found. \n",
+					__FILE__, __LINE__);
+				rc = -EFAULT;
+				goto done_free_mem;
+			}  else if (mptctl_set_tm_flags(hd) != 0) {
+				rc = -EPERM;
+				goto done_free_mem;
+			}
+			tm_flags_set = 1;
+		}
+		break;
+
 	default:
 		/*
 		 * MPI_FUNCTION_IOC_INIT
@@ -1908,7 +2064,6 @@
 		 * MPI_FUNCTION_EVENT_NOTIFICATION
 		 *  (driver handles event notification)
 		 * MPI_FUNCTION_EVENT_ACK
-		 * MPI_FUNCTION_SCSI_TASK_MGMT
 		 */
 
 		/*  What to do with these???  CHECK ME!!!
@@ -1933,7 +2088,7 @@
 	 * preceede the data in (read) SGE. psgList is used to free the
 	 * allocated memory.
 	 */
-	psge = (MptSge_t *) ( ((int *) mf) + karg.dataSgeOffset);
+	psge = (char *) ( ((int *) mf) + karg.dataSgeOffset);
 	flagsLength = 0;
 
 	/* bufIn and bufOut are used for user to kernel space transfers
@@ -1967,7 +2122,7 @@
 			if (karg.dataInSize > 0 ) {
 				flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
 						MPI_SGE_FLAGS_DIRECTION |
-						MPT_SGE_ADDRESS_SIZE )
+						mpt_addr_size() )
 						<< MPI_SGE_FLAGS_SHIFT;
 			} else {
 				flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
@@ -2001,13 +2156,11 @@
 				/* Set up this SGE.
 				 * Copy to MF and to sglbuf
 				 */
+				mpt_add_sge(psge, flagsLength, dma_addr);
+				psge += (sizeof(u32) + sizeof(dma_addr_t));
 
-				psge->FlagsLength = cpu_to_le32 (flagsLength);
-				cpu_to_leXX(dma_addr, psge->Address);
-				psge++;
-
-				this_sge->FlagsLength=cpu_to_le32(flagsLength);
-				cpu_to_leXX(dma_addr, this_sge->Address);
+				this_sge->FlagsLength = flagsLength;
+				this_sge->Address = dma_addr;
 				this_sge++;
 			}
 		}
@@ -2028,20 +2181,17 @@
 				/* Set up this SGE
 				 * Copy to MF and to sglbuf
 				 */
-				psge->FlagsLength = cpu_to_le32 (flagsLength);
-				cpu_to_leXX(dma_addr, psge->Address);
+				mpt_add_sge(psge, flagsLength, dma_addr);
 
-				this_sge->FlagsLength=cpu_to_le32(flagsLength);
-				cpu_to_leXX(dma_addr, this_sge->Address);
+				this_sge->FlagsLength = flagsLength;
+				this_sge->Address = dma_addr;
 				this_sge++;
 			}
 		}
 	} else  {
 		/* Add a NULL SGE
 		 */
-		flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
-		psge->FlagsLength = cpu_to_le32 (flagsLength);
-		cpu_to_leXX( (dma_addr_t) -1, psge->Address);
+		mpt_add_sge(psge, flagsLength, (dma_addr_t) -1);
 	}
 
 	/* The request is complete. Set the timer parameters
@@ -2057,8 +2207,22 @@
 	ioc->ioctl->status |= MPT_IOCTL_STATUS_TIMER_ACTIVE;
 	add_timer(&ioc->ioctl->timer);
 
-	mpt_put_msg_frame(mptctl_id, ioc->id, mf);
-	wait_event(mptctl_wait, ioc->ioctl->wait_done);
+	if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
+		rc = mpt_send_handshake_request(mptctl_id, ioc->id,
+				sizeof(SCSITaskMgmt_t), (u32*)mf, NO_SLEEP);
+		if (rc == 0) {
+			wait_event(mptctl_wait, ioc->ioctl->wait_done);
+		} else {
+			mptctl_free_tm_flags(ioc);
+			tm_flags_set= 0;
+			del_timer(&ioc->ioctl->timer);
+			ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TIMER_ACTIVE;
+			ioc->ioctl->status = MPT_IOCTL_STATUS_TM_FAILED;
+		}
+	} else {
+		mpt_put_msg_frame(mptctl_id, ioc->id, mf);
+		wait_event(mptctl_wait, ioc->ioctl->wait_done);
+	}
 
 	/* The command is complete.  * Return data to the user.
 	 *
@@ -2068,7 +2232,7 @@
 	 * If timeout, a recovery  mechanism has been called.
 	 * Need to free the mf.
 	 */
-	if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_TIMEOUT) {
+	if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) {
 
 		/* A timeout - there is no data to return to the
 		 * the user other than an error.
@@ -2076,13 +2240,17 @@
 		 * timer and reset the adapter queues.
 		 */
 		printk(KERN_WARNING "%s@%d::mptctl_do_mpt_command - "
-			"Timeout Occurred on IOCTL! Resetting IOC.\n", __FILE__, __LINE__);
+			"Timeout Occurred on IOCTL! Reset IOC.\n", __FILE__, __LINE__);
+		tm_flags_set= 0;
 		rc = -ETIME;
 
 		/* Free memory and return to the calling function
 		 */
 		goto done_free_mem;
-
+	} else if (ioc->ioctl->status & MPT_IOCTL_STATUS_TM_FAILED) {
+		/* User TM request failed!
+		 */
+		rc = -ENODATA;
 	} else {
 		/* Callback freed request frame.
 		 */
@@ -2149,27 +2317,28 @@
 	 */
 	ioc->ioctl->status = 0;
 
+	if (tm_flags_set)
+		mptctl_free_tm_flags(ioc);
+
 	if (sglbuf) {
 		this_sge = sglbuf;
 
 		/* Free the allocated memory.
 		 */
 		 if (bufOut.kptr != NULL ) {
-
-			leXX_to_cpu (dma_addr, this_sge->Address);
-
+			dma_addr = this_sge->Address;
 			this_sge++;	/* go to next structure */
 			this_alloc = bufOut.len;
 			pci_free_consistent(ioc->pcidev,
-				this_alloc, (void *) &bufOut, dma_addr);
+				this_alloc, (void *)bufOut.kptr, dma_addr);
 		}
 
 		if (bufIn.kptr != NULL ) {
-			leXX_to_cpu (dma_addr, this_sge->Address);
+			dma_addr = this_sge->Address;
 			this_alloc = bufIn.len;
 
 			pci_free_consistent(ioc->pcidev,
-					this_alloc, (void *) &bufIn, dma_addr);
+					this_alloc, (void *)bufIn.kptr, dma_addr);
 		}
 
 		this_alloc = sgSize * sizeof(MptSge_t);
@@ -2220,8 +2389,8 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		printk(KERN_ERR "%s::mptctl_compaq_ioctl() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnumX);
+		dtmprintk((KERN_ERR "%s::mptctl_compaq_ioctl() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnumX));
 		return -ENODEV;
 	}
 
@@ -2288,13 +2457,13 @@
 		printk(KERN_ERR "%s@%d::mptctl_cpq_pciinfo - "
 			"Unable to read in cpqfc_pci_info_struct @ %p\n",
 				__FILE__, __LINE__, (void*)uarg);
-		return -EFAULT;
+		return -EINVAL;
 	}
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_pciinfo() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_pciinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -2394,8 +2563,8 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_cpq_getdriver() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_cpq_getdriver() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -2458,8 +2627,8 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_cpq_ctlr_status() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_cpq_ctlr_status() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -2514,8 +2683,8 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_cpq_target_address() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_cpq_target_address() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -2617,8 +2786,8 @@
 	iocnumX = karg.lc & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_cpq_passthru() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_cpq_passthru() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -2747,12 +2916,12 @@
 
 static struct file_operations mptctl_fops = {
 	owner_THIS_MODULE
-	llseek:		no_llseek,
-	read:		mptctl_read,
-	write:		mptctl_write,
-	ioctl:		mptctl_ioctl,
-	open:		mptctl_open,
-	release:	mptctl_release,
+	.llseek =	no_llseek,
+	.read =		mptctl_read,
+	.write =	mptctl_write,
+	.ioctl =	mptctl_ioctl,
+	.open =		mptctl_open,
+	.release =	mptctl_release,
 };
 
 static struct miscdevice mptctl_miscdev = {
@@ -2802,8 +2971,8 @@
 	iocnumX = kfw32.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		printk(KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n",
-				__LINE__, iocnumX);
+		dtmprintk((KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n",
+				__LINE__, iocnumX));
 		return -ENODEV;
 	}
 
@@ -2842,8 +3011,8 @@
 	iocnumX = karg32.hdr.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		printk(KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
-				__LINE__, iocnumX);
+		dtmprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
+				__LINE__, iocnumX));
 		return -ENODEV;
 	}
 
@@ -2899,8 +3068,8 @@
 	iocnumX = karg32.lc & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
-				__LINE__, iocnumX);
+		dtmprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
+				__LINE__, iocnumX));
 		return -ENODEV;
 	}
 
@@ -2980,6 +3149,9 @@
 			init_timer (&ioc->ioctl->timer);
 			ioc->ioctl->timer.data = (unsigned long) ioc->ioctl;
 			ioc->ioctl->timer.function = mptctl_timer_expired;
+			init_timer (&ioc->ioctl->TMtimer);
+			ioc->ioctl->TMtimer.data = (unsigned long) ioc->ioctl;
+			ioc->ioctl->TMtimer.function = mptctl_timer_expired;
 		}
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/message/fusion/mptctl.h linux-2.4.20/drivers/message/fusion/mptctl.h
--- linux-2.4.19/drivers/message/fusion/mptctl.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/message/fusion/mptctl.h	2002-10-29 11:18:33.000000000 +0000
@@ -20,7 +20,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptctl.h,v 1.9 2002/02/27 18:44:26 sralston Exp $
+ *  $Id: mptctl.h,v 1.10 2002/05/28 15:57:16 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -122,7 +122,6 @@
 };
 #endif	/*}*/
 
-
 /*
  *  IOCTL header structure.
  *  iocnum - must be defined.
@@ -150,6 +149,20 @@
 
 
 /*
+ *  PCI bus/device/function information structure.
+ */
+struct mpt_ioctl_pci_info {
+	union {
+		struct {
+			unsigned long  deviceNumber   :  5;
+			unsigned long  functionNumber :  3;
+			unsigned long  busNumber      : 24;
+		} bits;
+		unsigned long  asUlong;
+	} u;
+};
+
+/*
  *  Adapter Information Page
  *  Read only.
  *  Data starts at offset 0xC
@@ -173,6 +186,7 @@
 	char		 busChangeEvent;
 	char		 hostId;
 	char		 rsvd[2];
+	struct mpt_ioctl_pci_info  pciInfo; /* Added Rev 1 */
 };
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/message/fusion/mptlan.c linux-2.4.20/drivers/message/fusion/mptlan.c
--- linux-2.4.19/drivers/message/fusion/mptlan.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/message/fusion/mptlan.c	2002-10-29 11:18:47.000000000 +0000
@@ -26,7 +26,7 @@
  *  Copyright (c) 2000-2002 LSI Logic Corporation
  *  Originally By: Noah Romer
  *
- *  $Id: mptlan.c,v 1.51 2002/02/11 14:40:55 sralston Exp $
+ *  $Id: mptlan.c,v 1.52 2002/05/06 13:45:07 sshirron Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -669,7 +669,7 @@
 
 	/* Add check for Loginfo Flag in IOCStatus */
 
-	switch (le16_to_cpu(pSendRep->IOCStatus)) {
+	switch (le16_to_cpu(pSendRep->IOCStatus) & MPI_IOCSTATUS_MASK) {
 	case MPI_IOCSTATUS_SUCCESS:
 		priv->stats.tx_packets += count;
 		break;
@@ -1045,7 +1045,8 @@
 	dioprintk((KERN_INFO MYNAM ": receive_post_reply: IOCStatus: %04x\n",
 		 le16_to_cpu(pRecvRep->IOCStatus)));
 
-	if (le16_to_cpu(pRecvRep->IOCStatus) & MPI_IOCSTATUS_LAN_CANCELED)
+	if ((le16_to_cpu(pRecvRep->IOCStatus) & MPI_IOCSTATUS_MASK) ==
+						MPI_IOCSTATUS_LAN_CANCELED)
 		return mpt_lan_receive_post_free(dev, pRecvRep);
 
 	len = le32_to_cpu(pRecvRep->PacketLength);
@@ -1436,7 +1437,7 @@
 {
 	struct net_device *dev;
 	MPT_ADAPTER *curadapter;
-	int i = 0, j;
+	int i, j;
 
 	show_mptmod_ver(LANAME, LANVER);
 
@@ -1468,7 +1469,6 @@
 	for (j = 0; j < MPT_MAX_ADAPTERS; j++) {
 		mpt_landev[j] = NULL;
 	}
-	j = 0;
 
 	curadapter = mpt_adapter_find_first();
 	while (curadapter != NULL) {
@@ -1492,11 +1492,11 @@
 //					printk (KERN_INFO MYNAM ": %s/%s: Max_TX_outstanding = %d\n",
 //							IOC_AND_NETDEV_NAMES_s_s(dev),
 //							NETDEV_TO_LANPRIV_PTR(dev)->tx_max_out);
+					j = curadapter->id;
 					mpt_landev[j] = dev;
 					dlprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n",
 							dev, j,  mpt_landev[j]));
 
-					j++;
 				} else {
 					printk (KERN_ERR MYNAM ": %s: Unable to register port%d as a LAN device\n",
 							curadapter->name,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/message/fusion/mptscsih.c linux-2.4.20/drivers/message/fusion/mptscsih.c
--- linux-2.4.19/drivers/message/fusion/mptscsih.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/message/fusion/mptscsih.c	2002-10-29 11:18:39.000000000 +0000
@@ -26,7 +26,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptscsih.c,v 1.80 2002/02/27 18:44:27 sralston Exp $
+ *  $Id: mptscsih.c,v 1.101 2002/09/05 22:30:11 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -158,9 +158,8 @@
 static int	mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
 static int	mptscsih_io_direction(Scsi_Cmnd *cmd);
 
-static int	mptscsih_Add32BitSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
+static int	mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
 				 SCSIIORequest_t *pReq, int req_idx);
-static void	mptscsih_AddNullSGE(SCSIIORequest_t *pReq);
 static int	mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex);
 static void	mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx);
 static int	mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init);
@@ -168,6 +167,8 @@
 static void	copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
 #ifndef MPT_SCSI_USE_NEW_EH
 static void	search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd);
+#else
+static int	mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
 #endif
 static u32	SCPNT_TO_LOOKUP_IDX(Scsi_Cmnd *sc);
 static MPT_FRAME_HDR *mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx);
@@ -180,10 +181,11 @@
 static int	mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
 
 static VirtDevice	*mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen);
-void		mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target);
+void		mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56);
 static void	clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
-static void	mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq, char *data);
+static void	mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
 static void	mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
+static void	mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id);
 static int	mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags);
 static int	mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
 static void	mptscsih_timer_expired(unsigned long data);
@@ -194,6 +196,8 @@
 #ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
 static int	mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);
 static void	mptscsih_domainValidation(void *hd);
+static int	mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);
+static void	mptscsih_qas_check(MPT_SCSI_HOST *hd);
 static void	mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int target);
 static void	mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
 static void	mptscsih_fillbuf(char *buffer, int size, int index, int width);
@@ -222,11 +226,11 @@
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28)
 static struct proc_dir_entry proc_mpt_scsihost =
 {
-	low_ino:	PROC_SCSI_MPT,
-	namelen:	8,
-	name:		"mptscsih",
-	mode:		S_IFDIR | S_IRUGO | S_IXUGO,
-	nlink:		2,
+	.low_ino =	PROC_SCSI_MPT,
+	.namelen =	8,
+	.name =		"mptscsih",
+	.mode =		S_IFDIR | S_IRUGO | S_IXUGO,
+	.nlink =	2,
 };
 #endif
 
@@ -286,7 +290,9 @@
 	MPT_SCSI_HOST	*hd;
 	SCSIIORequest_t	*pScsiReq;
 	SCSIIOReply_t	*pScsiReply;
+#ifndef MPT_SCSI_USE_NEW_EH
 	unsigned long	 flags;
+#endif
 	u16		 req_idx;
 
 	hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
@@ -294,7 +300,7 @@
 	if ((mf == NULL) ||
 	    (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
 		printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n",
-				ioc->name, mf?"BAD":"NULL", mf);
+				ioc->name, mf?"BAD":"NULL", (void *) mf);
 		/* return 1; CHECKME SteveR. Don't free. */
 		return 0;
 	}
@@ -317,8 +323,8 @@
 		return 1;
 	}
 
-	dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p)\n",
-			ioc->name, mf, mr, sc));
+	dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
+			ioc->name, mf, mr, sc, req_idx));
 
 	atomic_dec(&queue_depth);
 
@@ -326,6 +332,14 @@
 	pScsiReq = (SCSIIORequest_t *) mf;
 	pScsiReply = (SCSIIOReply_t *) mr;
 
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+	if (hd->is_spi) {
+		u32 qtag = le32_to_cpu(pScsiReq->Control);
+		if (qtag & MPI_SCSIIO_CONTROL_UNTAGGED)
+			hd->ioc->spi_data.iocntr[sc->target]--;
+	}
+#endif
+
 	if (pScsiReply == NULL) {
 		/* special context reply handling */
 
@@ -345,9 +359,6 @@
 			}
 		}
 		clear_sense_flag(hd, pScsiReq);
-
-		if (hd->is_spi)
-			mptscsih_set_dvflags(hd, pScsiReq, sc->buffer);
 	} else {
 		u32	 xfer_cnt;
 		u16	 status;
@@ -403,6 +414,10 @@
 			 * than an unsolicited DID_ABORT.
 			 */
 			sc->result = DID_RESET << 16;
+
+			/* GEM Workaround. */ 
+			if (hd->is_spi)
+				mptscsih_no_negotiate(hd, sc->target);
 			break;
 
 		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
@@ -411,6 +426,10 @@
 			search_taskQ_for_cmd(sc, hd);
 #endif
 			sc->result = DID_RESET << 16;
+
+			/* GEM Workaround. */ 
+			if (hd->is_spi)
+				mptscsih_no_negotiate(hd, sc->target);
 			break;
 
 		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */
@@ -470,9 +489,6 @@
 						sc->buffer,
 						xfer_cnt);
 			}
-
-			if (hd->is_spi)
-				mptscsih_set_dvflags(hd, pScsiReq, sc->buffer);
 			break;
 
 		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
@@ -554,9 +570,6 @@
 						sc->buffer,
 						xfer_cnt);
 			}
-
-			if (hd->is_spi)
-				mptscsih_set_dvflags(hd, pScsiReq, sc->buffer);
 			break;
 
 		case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */
@@ -606,9 +619,9 @@
 
 	sc->host_scribble = NULL;	/* CHECKME! - Do we need to clear this??? */
 
-	spin_lock_irqsave(&io_request_lock, flags);
+        MPT_HOST_LOCK(flags);
 	sc->scsi_done(sc);		/* Issue the command callback */
-	spin_unlock_irqrestore(&io_request_lock, flags);
+        MPT_HOST_UNLOCK(flags);
 
 	/* Free Chain buffers */
 	mptscsih_freeChainBuffers(hd, req_idx);
@@ -700,6 +713,7 @@
 	unsigned long flags;
 
 	dprintk((KERN_INFO MYNAM ": clean_taskQ called\n"));
+
 	spin_lock_irqsave(&ioc->FreeQlock, flags);
 	if (! Q_IS_EMPTY(&hd->taskQ)) {
 		mf = hd->taskQ.head;
@@ -812,9 +826,9 @@
 
 		/* Do the OS callback.
 		 */
-		spin_lock_irqsave(&io_request_lock, flags);
+                MPT_HOST_LOCK(flags);
 		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&io_request_lock, flags);
+                MPT_HOST_UNLOCK(flags);
 	}
 
 	return;
@@ -871,7 +885,10 @@
 	MPT_FRAME_HDR	*mf = NULL;
 	int		 ii;
 	int		 max = hd->ioc->req_depth;
+
+#ifndef MPT_SCSI_USE_NEW_EH
 	unsigned long	 flags;
+#endif
 
 	dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
 	for (ii= 0; ii < max; ii++) {
@@ -901,16 +918,26 @@
 			dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
 					mf, SCpnt));
 
-			/* Set status
+			/* Set status, free OS resources (SG DMA buffers)
 			 * Do OS callback
-			 * Free chain buffers
-			 * Free message frame
+			 * Free driver resources (chain, msg buffers)
 			 */
+			if (SCpnt->use_sg) {
+				pci_unmap_sg(hd->ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer,
+					    SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+			} else if (SCpnt->request_bufflen) {
+				scPrivate	*my_priv;
+		
+				my_priv = (scPrivate *) &SCpnt->SCp;
+				pci_unmap_single(hd->ioc->pcidev, (dma_addr_t)(ulong)my_priv->p1,
+					   SCpnt->request_bufflen,
+					   scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+			}
 			SCpnt->result = DID_RESET << 16;
 			SCpnt->host_scribble = NULL;
-			spin_lock_irqsave(&io_request_lock, flags);
+                        MPT_HOST_LOCK(flags);
 			SCpnt->scsi_done(SCpnt);	/* Issue the command callback */
-			spin_unlock_irqrestore(&io_request_lock, flags);
+                        MPT_HOST_UNLOCK(flags);
 
 			/* Free Chain buffers */
 			mptscsih_freeChainBuffers(hd, ii);
@@ -919,9 +946,82 @@
 			mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
 		}
 	}
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+	/* Clear untagged counting array */
+	for (ii= 0; ii < MPT_MAX_SCSI_DEVICES; ii++)
+		hd->ioc->spi_data.iocntr[ii] = 0;
+#endif
+
 	return;
 }
 
+#ifdef DROP_TEST
+/* 	mptscsih_flush_drop_test - Free resources and do callback if
+ *		DROP_TEST enabled.
+ *
+ *	@hd: Pointer to a SCSI HOST structure
+ *
+ *	Returns: None.
+ *
+ *	Must be called while new I/Os are being queued.
+ */
+static void
+mptscsih_flush_drop_test (MPT_SCSI_HOST *hd)
+{
+	Scsi_Cmnd	*sc;
+	unsigned long	 flags;
+	u16		 req_idx;
+
+	/* Free resources for the drop test MF
+	 * and chain buffers.
+	 */
+	if (dropMfPtr) {
+		req_idx = le16_to_cpu(dropMfPtr->u.frame.hwhdr.msgctxu.fld.req_idx);
+		sc = hd->ScsiLookup[req_idx];
+		if (sc == NULL) {
+			printk(MYIOC_s_ERR_FMT "Drop Test: NULL ScsiCmd ptr!\n",
+					ioc->name);
+		} else {
+			/* unmap OS resources, set status, do callback
+			 * free driver resources
+			 */
+			if (sc->use_sg) {
+				pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
+					    sc->use_sg, scsi_to_pci_dma_dir(sc->sc_data_direction));
+			} else if (sc->request_bufflen) {
+				scPrivate	*my_priv;
+
+				my_priv = (scPrivate *) &sc->SCp;
+				pci_unmap_single(ioc->pcidev, (dma_addr_t)(ulong)my_priv->p1,
+					   sc->request_bufflen,
+					   scsi_to_pci_dma_dir(sc->sc_data_direction));
+			}
+
+			sc->host_scribble = NULL;
+			sc->result = DID_RESET << 16;
+			hd->ScsiLookup[req_idx] = NULL;
+			atomic_dec(&queue_depth);
+			MPT_HOST_LOCK(flags);
+			sc->scsi_done(sc);	/* Issue callback */
+			MPT_HOST_UNLOCK(flags);
+		}
+
+		mptscsih_freeChainBuffers(hd, req_idx);
+		mpt_free_msg_frame(ScsiDoneCtx, ioc->id, dropMfPtr);
+		printk(MYIOC_s_INFO_FMT "Free'd Dropped cmd (%p)\n",
+					hd->ioc->name, sc);
+		printk(MYIOC_s_INFO_FMT "mf (%p) reqidx (%4x)\n",
+					hd->ioc->name, dropMfPtr, req_idx);
+		printk(MYIOC_s_INFO_FMT "Num Tot (%d) Good (%d) Bad (%d) \n",
+				hd->ioc->name, dropTestNum,
+				dropTestOK, dropTestBad);
+	}
+	dropMfPtr = NULL;
+
+	return;
+}
+#endif
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *	mptscsih_initChainBuffers - Allocate memory for and initialize
@@ -951,7 +1051,7 @@
 	sz = numChain * sizeof(int);
 
 	if (hd->ReqToChain == NULL) {
-		mem = kmalloc(sz, GFP_KERNEL);
+		mem = kmalloc(sz, GFP_ATOMIC);
 		if (mem == NULL)
 			return -1;
 
@@ -962,7 +1062,7 @@
 	memset(mem, 0xFF, sz);
 
 	if (hd->ChainToChain == NULL) {
-		mem = kmalloc(sz, GFP_KERNEL);
+		mem = kmalloc(sz, GFP_ATOMIC);
 		if (mem == NULL)
 			return -1;
 
@@ -1038,7 +1138,7 @@
 	if (time - last_queue_full > 10 * HZ) {
 		char *ioc_str = "ioc?";
 
-		if (sc->host && sc->host->hostdata)
+		if (sc->host != NULL && sc->host->hostdata != NULL)
 			ioc_str = ((MPT_SCSI_HOST *)sc->host->hostdata)->ioc->name;
 		printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
 				ioc_str, 0, sc->target, sc->lun);
@@ -1175,21 +1275,21 @@
 
 				/* Verify that we won't exceed the maximum
 				 * number of chain buffers
-				 * We can optimize:  ZZ = req_sz/sizeof(MptSge_t)
+				 * We can optimize:  ZZ = req_sz/sizeof(SGE)
 				 * For 32bit SGE's:
 				 *  numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
-				 *               + (req_sz - 64)/sizeof(MptSge_t)
+				 *               + (req_sz - 64)/sizeof(SGE)
 				 * A slightly different algorithm is required for
 				 * 64bit SGEs.
 				 */
-				scale = this->req_sz/sizeof(MptSge_t);
-				if (sizeof(MptSge_t) == sizeof(SGESimple32_t)) {
-					numSGE = 1 + (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
-						(this->req_sz - 64) / (sizeof(MptSge_t));
-				} else if (sizeof(MptSge_t) == sizeof(SGESimple64_t)) {
+				scale = this->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+				if (sizeof(dma_addr_t) == sizeof(u64)) {
 					numSGE = (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
-						(this->req_sz - 60) / (sizeof(MptSge_t));
-				}
+						(this->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
+				} else {
+					numSGE = 1 + (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
+						(this->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
+				} 
 
 				if (numSGE < sh->sg_tablesize) {
 					/* Reset this value */
@@ -1199,6 +1299,10 @@
 					sh->sg_tablesize = numSGE;
 				}
 
+				/* Set the pci device pointer in Scsi_Host structure.
+				 */
+				scsi_set_pci_device(sh, this->pcidev);
+
 				restore_flags(flags);
 
 				hd = (MPT_SCSI_HOST *) sh->hostdata;
@@ -1217,7 +1321,7 @@
 				 * (with size equal to req_depth*PtrSz!)
 				 */
 				sz = hd->ioc->req_depth * sizeof(void *);
-				mem = kmalloc(sz, GFP_KERNEL);
+				mem = kmalloc(sz, GFP_ATOMIC);
 				if (mem == NULL)
 					goto done;
 
@@ -1233,7 +1337,7 @@
 				/* Allocate memory for free and doneQ's
 				 */
 				sz = sh->can_queue * sizeof(MPT_DONE_Q);
-				mem = kmalloc(sz, GFP_KERNEL);
+				mem = kmalloc(sz, GFP_ATOMIC);
 				if (mem == NULL)
 					goto done;
 
@@ -1266,7 +1370,7 @@
 				 * max_id = 1 + maximum id (hosts.h)
 				 */
 				sz = sh->max_id * sizeof(void *);
-				mem = kmalloc(sz, GFP_KERNEL);
+				mem = kmalloc(sz, GFP_ATOMIC);
 				if (mem == NULL)
 					goto done;
 
@@ -1279,6 +1383,9 @@
 				/* Clear the TM flags
 				 */
 				hd->tmPending = 0;
+#ifdef MPT_SCSI_USE_NEW_EH
+				hd->tmState = TM_STATE_NONE;
+#endif
 				hd->resetPending = 0;
 				hd->abortSCpnt = NULL;
 				hd->tmPtr = NULL;
@@ -1333,7 +1440,11 @@
 					hd->ioc->spi_data.forceDv = 0;
 					for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
 						hd->ioc->spi_data.dvStatus[ii] = MPT_SCSICFG_NEGOTIATE;
-
+	
+					if (hd->negoNvram == 0) {
+						for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
+							hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_NOT_DONE;
+					}
 
 					ddvprintk((MYIOC_s_INFO_FMT
 						"dv %x width %x factor %x \n",
@@ -1387,10 +1498,9 @@
 	spin_unlock_irqrestore(&dvtaskQ_lock, flags);
 #endif
 
+	count = 10 * HZ;
 	spin_lock_irqsave(&mytaskQ_lock, flags);
 	if (mytaskQ_bh_active) {
-		count = 10 * HZ;
-
 		spin_unlock_irqrestore(&mytaskQ_lock, flags);
 		dprintk((KERN_INFO MYNAM ": Info: Zapping TaskMgmt thread!\n"));
 		clean_taskQ(hd);
@@ -1399,23 +1509,27 @@
 			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(1);
 		}
-		if (!count)
-			printk(KERN_ERR MYNAM ": ERROR - TaskMgmt thread still active!\n");
+	} else {
+		spin_unlock_irqrestore(&mytaskQ_lock, flags);
 	}
-	spin_unlock_irqrestore(&mytaskQ_lock, flags);
+	if (!count)
+		printk(KERN_ERR MYNAM ": ERROR - TaskMgmt thread still active!\n");
+
 #endif
 
 #ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
 	/* Check DV thread active */
 	count = 10 * HZ;
 	spin_lock_irqsave(&dvtaskQ_lock, flags);
-	while(dvtaskQ_active && --count) {
+	if (dvtaskQ_active) {
+		spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+		while(dvtaskQ_active && --count) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(1);
+		}
+	} else {
 		spin_unlock_irqrestore(&dvtaskQ_lock, flags);
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(1);
-		spin_lock_irqsave(&dvtaskQ_lock, flags);
 	}
-	spin_unlock_irqrestore(&dvtaskQ_lock, flags);
 	if (!count)
 		printk(KERN_ERR MYNAM ": ERROR - DV thread still active!\n");
 #if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
@@ -1428,6 +1542,8 @@
 
 	if (hd != NULL) {
 		int sz1, sz2, sz3, sztarget=0;
+		int szr2chain = 0;
+		int szc2chain = 0;
 		int szchain = 0;
 		int szQ = 0;
 		int scale;
@@ -1452,20 +1568,20 @@
 		}
 
 		if (hd->ReqToChain != NULL) {
-			szchain += scale * hd->ioc->req_depth * sizeof(int);
+			szr2chain = scale * hd->ioc->req_depth * sizeof(int);
 			kfree(hd->ReqToChain);
 			hd->ReqToChain = NULL;
 		}
 
 		if (hd->ChainToChain != NULL) {
-			szchain += scale * hd->ioc->req_depth * sizeof(int);
+			szc2chain = scale * hd->ioc->req_depth * sizeof(int);
 			kfree(hd->ChainToChain);
 			hd->ChainToChain = NULL;
 		}
 
 		if (hd->ChainBuffer != NULL) {
 			sz2 = scale * hd->ioc->req_depth * hd->ioc->req_sz;
-			szchain += sz2;
+			szchain = szr2chain + szc2chain + sz2;
 
 			pci_free_consistent(hd->ioc->pcidev, sz2,
 				    hd->ChainBuffer, hd->ChainBufferDMA);
@@ -1772,10 +1888,10 @@
 	 *    will be no data transfer!  GRRRRR...
 	 */
 	datadir = mptscsih_io_direction(SCpnt);
-	if (datadir < 0) {
+	if (datadir == SCSI_DATA_READ) {
 		datalen = SCpnt->request_bufflen;
 		scsidir = MPI_SCSIIO_CONTROL_READ;	/* DATA IN  (host<--ioc<--dev) */
-	} else if (datadir > 0) {
+	} else if (datadir == SCSI_DATA_WRITE) {
 		datalen = SCpnt->request_bufflen;
 		scsidir = MPI_SCSIIO_CONTROL_WRITE;	/* DATA OUT (host-->ioc-->dev) */
 	} else {
@@ -1812,7 +1928,7 @@
 	pScsiReq->CDBLength = SCpnt->cmd_len;
 	pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
 	pScsiReq->Reserved = 0;
-	pScsiReq->MsgFlags = MPT_SCSIIO_MSG_FLAGS;
+	pScsiReq->MsgFlags = mpt_msg_flags();
 	pScsiReq->LUN[0] = 0;
 	pScsiReq->LUN[1] = lun;
 	pScsiReq->LUN[2] = 0;
@@ -1845,10 +1961,11 @@
 	rc = SUCCESS;
 	if (datalen == 0) {
 		/* Add a NULL SGE */
-		mptscsih_AddNullSGE(pScsiReq);
+		mpt_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
+			(dma_addr_t) -1);
 	} else {
 		/* Add a 32 or 64 bit SGE */
-		rc = mptscsih_Add32BitSGE(hd, SCpnt, pScsiReq, my_idx);
+		rc = mptscsih_AddSGE(hd, SCpnt, pScsiReq, my_idx);
 	}
 
 
@@ -1896,11 +2013,15 @@
 
 			if (dvStatus || hd->ioc->spi_data.forceDv) {
 
-				/* Write SDP1 on 1st I/O to this target */
+				/* Write SDP1 on this I/O to this target */
 				if (dvStatus & MPT_SCSICFG_NEGOTIATE) {
 					mptscsih_writeSDP1(hd, 0, target, hd->negoNvram);
 					dvStatus &= ~MPT_SCSICFG_NEGOTIATE;
 					hd->ioc->spi_data.dvStatus[target] =  dvStatus;
+				} else if (dvStatus & MPT_SCSICFG_BLK_NEGO) {
+					mptscsih_writeSDP1(hd, 0, target, MPT_SCSICFG_BLK_NEGO);
+					dvStatus &= ~MPT_SCSICFG_BLK_NEGO;
+					hd->ioc->spi_data.dvStatus[target] =  dvStatus;
 				}
 
 #ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
@@ -1910,14 +2031,16 @@
 					spin_lock_irqsave(&dvtaskQ_lock, lflags);
 					if (!dvtaskQ_active) {
 						dvtaskQ_active = 1;
+						spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
 						mptscsih_dvTask.sync = 0;
 						mptscsih_dvTask.routine = mptscsih_domainValidation;
 						mptscsih_dvTask.data = (void *) hd;
 
 						SCHEDULE_TASK(&mptscsih_dvTask);
+					} else {
+						spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
 					}
 					hd->ioc->spi_data.forceDv = 0;
-					spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
 				}
 
 				/* Trying to do DV to this target, extend timeout.
@@ -1927,17 +2050,25 @@
 					mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
 					issueCmd = 0;
 				}
+
+				if (qtag == MPI_SCSIIO_CONTROL_UNTAGGED)
+					hd->ioc->spi_data.iocntr[target]++;
+
+				/* Set the DV flags.
+				 */
+				if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
+					mptscsih_set_dvflags(hd, pScsiReq);
 #endif
 			}
 		}
 
 		if (issueCmd) {
 			mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
-			dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p)\n",
-					hd->ioc->name, SCpnt));
+			dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
+					hd->ioc->name, SCpnt, mf, my_idx));
 		} else {
-			ddvtprintk((MYIOC_s_INFO_FMT "Pending SCSI cmd (%p)\n",
-					hd->ioc->name, SCpnt));
+			ddvtprintk((MYIOC_s_INFO_FMT "Pending cmd=%p idx %d\n",
+					hd->ioc->name, SCpnt, my_idx));
 			/* Place this command on the pendingQ if possible */
 			spin_lock_irqsave(&hd->freedoneQlock, flags);
 			if (!Q_IS_EMPTY(&hd->freeQ)) {
@@ -1995,7 +2126,7 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	mptscsih_Add32BitSGE - Add a 32Bit SGE (plus chain buffers) to the
+ *	mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
  *	SCSIIORequest_t Message Frame.
  *	@hd: Pointer to MPT_SCSI_HOST structure
  *	@SCpnt: Pointer to Scsi_Cmnd structure
@@ -2004,19 +2135,19 @@
  *	Returns ...
  */
 static int
-mptscsih_Add32BitSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
+mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
 				 SCSIIORequest_t *pReq, int req_idx)
 {
-	MptSge_t *psge;
-	MptChain_t  *chainSge;
+	char 	*psge;
+	char	*chainSge;
 	struct scatterlist *sg;
 	int	 frm_sz;
 	int	 sges_left, sg_done;
 	int	 chain_idx = MPT_HOST_NO_CHAIN;
 	int	 sgeOffset;
 	int	 numSgeSlots, numSgeThisFrame;
-	u32	 sgflags, sgdir, len, thisxfer = 0;
-	int	 offset;
+	u32	 sgflags, sgdir, thisxfer = 0;
+	int	 chain_dma_off = 0;
 	int	 newIndex;
 	int	 ii;
 	dma_addr_t v2;
@@ -2028,7 +2159,7 @@
 		sgdir = MPT_TRANSFER_IOC_TO_HOST;
 	}
 
-	psge = (MptSge_t *) &pReq->SGL;
+	psge = (char *) &pReq->SGL;
 	frm_sz = hd->ioc->req_sz;
 
 	/* Map the data portion, if any.
@@ -2056,10 +2187,9 @@
 		dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
 				hd->ioc->name, SCpnt, SCpnt->request_bufflen));
 
-		/* 0xD1000000 = LAST | EOB | SIMPLE | EOL */
-		psge->FlagsLength = cpu_to_le32(
-				0xD1000000|sgdir|SCpnt->request_bufflen);
-		cpu_to_leXX(buf_dma_addr, psge->Address);
+		mpt_add_sge((char *) &pReq->SGL,
+			0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
+			buf_dma_addr);
 
 		return SUCCESS;
 	}
@@ -2078,7 +2208,7 @@
 	 */
 
 nextSGEset:
-	numSgeSlots = ((frm_sz - sgeOffset) / sizeof(MptSge_t));
+	numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
 	numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
 
 	sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
@@ -2095,14 +2225,12 @@
 			continue;
 		}
 
-		len += thisxfer;
-		psge->FlagsLength = cpu_to_le32( sgflags | thisxfer );
 		v2 = sg_dma_address(sg);
-		cpu_to_leXX(v2, psge->Address);
+		mpt_add_sge(psge, sgflags | thisxfer, v2);
 
 		sg++;		/* Get next SG element from the OS */
-		psge++;		/* Point to next SG location in this MF */
-		sgeOffset += sizeof(MptSge_t);
+		psge += (sizeof(u32) + sizeof(dma_addr_t));
+		sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
 		sg_done++;
 	}
 
@@ -2111,19 +2239,20 @@
 		 */
 		sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
 				MPT_SGE_FLAGS_END_OF_BUFFER |
-				MPT_SGE_FLAGS_ADDRESSING |
 				MPT_SGE_FLAGS_END_OF_LIST;
 
 		/* Add last SGE and set termination flags.
 		 * Note: Last SGE may have a length of 0 - which should be ok.
 		 */
 		thisxfer = sg_dma_len(sg);
-		len += thisxfer;
 
-		psge->FlagsLength = cpu_to_le32( sgflags | thisxfer );
 		v2 = sg_dma_address(sg);
-		cpu_to_leXX(v2, psge->Address);
-
+		mpt_add_sge(psge, sgflags | thisxfer, v2);
+		/*
+		sg++;
+		psge += (sizeof(u32) + sizeof(dma_addr_t));
+		*/
+		sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
 		sg_done++;
 
 		if (chainSge) {
@@ -2132,9 +2261,7 @@
 			 * Update the chain element
 			 * Offset and Length fields.
 			 */
-			chainSge->NextChainOffset = 0;
-			sgeOffset += sizeof(MptSge_t);
-			chainSge->Length = cpu_to_le16(sgeOffset);
+			mpt_add_chain((char *)chainSge, 0, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
 		} else {
 			/* The current buffer is the original MF
 			 * and there is no Chain buffer.
@@ -2163,11 +2290,10 @@
 		 * set properly).
 		 */
 		if (sg_done) {
-			psge--;
-			sgflags = le32_to_cpu (psge->FlagsLength);
+			u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
+			sgflags = le32_to_cpu(*ptmp);
 			sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
-			psge->FlagsLength = cpu_to_le32( sgflags );
-			psge++;
+			*ptmp = cpu_to_le32(sgflags);
 		}
 
 		if (chainSge) {
@@ -2177,9 +2303,9 @@
 			 * include chain element size) fields.
 			 * Old chain element is now complete.
 			 */
-			chainSge->NextChainOffset = (u8) (sgeOffset >> 2);
-			sgeOffset += sizeof(MptSge_t);
-			chainSge->Length = cpu_to_le16(sgeOffset);
+			u8 nextChain = (u8) (sgeOffset >> 2);
+			sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+			mpt_add_chain((char *)chainSge, nextChain, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
 		} else {
 			/* The original MF buffer requires a chain buffer -
 			 * set the offset.
@@ -2206,22 +2332,19 @@
 			hd->ReqToChain[req_idx] = newIndex;
 		}
 		chain_idx = newIndex;
-		offset = hd->ioc->req_sz * chain_idx;
+		chain_dma_off = hd->ioc->req_sz * chain_idx;
 
 		/* Populate the chainSGE for the current buffer.
 		 * - Set chain buffer pointer to psge and fill
 		 *   out the Address and Flags fields.
 		 */
-		chainSge = (MptChain_t *) psge;
-		chainSge->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
-		cpu_to_leXX ((hd->ChainBufferDMA + offset), chainSge->Address);
-
+		chainSge = (char *) psge;
 		dsgprintk((KERN_INFO "  Current buff @ %p (index 0x%x)",
 				psge, req_idx));
 
 		/* Start the SGE for the next buffer
 		 */
-		psge = (MptSge_t *) (hd->ChainBuffer + offset);
+		psge = (char *) (hd->ChainBuffer + chain_dma_off);
 		sgeOffset = 0;
 		sg_done = 0;
 
@@ -2239,25 +2362,6 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	mptscsih_AddNullSGE - Add a NULL SGE to the SCSIIORequest_t
- *	Message Frame.
- *	@pReq: Pointer to SCSIIORequest_t structure
- */
-static void
-mptscsih_AddNullSGE(SCSIIORequest_t *pReq)
-{
-	MptSge_t *psge;
-
-	psge = (MptSge_t *) &pReq->SGL;
-	psge->FlagsLength = cpu_to_le32(MPT_SGE_FLAGS_SSIMPLE_READ | 0);
-
-	cpu_to_leXX( (dma_addr_t) -1, psge->Address);
-
-	return;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
  *	mptscsih_getFreeChainBuffes - Function to get a free chain
  *	from the MPT_SCSI_HOST FreeChainQ.
  *	@hd: Pointer to the MPT_SCSI_HOST instance
@@ -2333,11 +2437,9 @@
 
 		chain = (MPT_FRAME_HDR *) (hd->ChainBuffer
 					+ (chain_idx * hd->ioc->req_sz));
-		//spin_lock_irqsave(&hd->FreeChainQlock, flags);
 		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
 		Q_ADD_TAIL(&hd->FreeChainQ.head,
 					&chain->u.frame.linkage, MPT_FRAME_HDR);
-		//spin_unlock_irqrestore(&hd->FreeChainQlock, flags);
 		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
 		dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
@@ -2386,7 +2488,7 @@
 	/* If FW is being reloaded currently, return success to
 	 * the calling function.
 	 */
-	if (!hd)
+	if (hd == NULL)
 		return 0;
 
 	ioc = hd->ioc;
@@ -2431,6 +2533,9 @@
 		 */
 		rc = mptscsih_IssueTaskMgmt(hd, type, target, lun, ctx2abort, sleepFlag);
 		if (rc) {
+#ifdef MPT_SCSI_USE_NEW_EH
+			hd->tmState = TM_STATE_ERROR;
+#endif
 			printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
 		} else {
 			printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name);
@@ -2484,7 +2589,7 @@
 	MPT_FRAME_HDR	*mf;
 	SCSITaskMgmt_t	*pScsiTm;
 	int		 ii;
-	int		 retval = 0;
+	int		 retval;
 
 	/* Return Fail to calling function if no message frames available.
 	 */
@@ -2508,7 +2613,8 @@
 	pScsiTm->Reserved = 0;
 	pScsiTm->TaskType = type;
 	pScsiTm->Reserved1 = 0;
-	pScsiTm->MsgFlags = 0;
+	pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
+	                    ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
 
 	for (ii= 0; ii < 8; ii++) {
 		pScsiTm->LUN[ii] = 0;
@@ -2540,7 +2646,6 @@
 		hd->tmPtr = NULL;
 		del_timer(&hd->TMtimer);
 		mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
-		return ii;
 	}
 
 	return retval;
@@ -2564,41 +2669,62 @@
 	unsigned long	 flags;
 	u32		 ctx2abort;
 	int		 scpnt_idx;
-	u8		 type;
-
-	printk(KERN_WARNING MYNAM ": Attempting ABORT SCSI IO (=%p)\n", SCpnt);
-	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
 
+	/* If we can't locate our host adapter structure, return FAILED status.
+	 */
 	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
 		SCpnt->result = DID_RESET << 16;
-		spin_lock_irqsave(&io_request_lock, flags);
 		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return SUCCESS;
+		nehprintk((KERN_WARNING MYNAM ": mptscsih_abort: "
+			   "Can't locate host! (sc=%p)\n",
+			   SCpnt));
+		return FAILED;
 	}
 
+	printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p)\n",
+	       hd->ioc->name, SCpnt);
+	printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
+	       hd->ioc->name, atomic_read(&queue_depth));
+
 	/* Find this command
 	 */
 	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
-		/* Cmd not found in ScsiLookup. If found in 
+		/* Cmd not found in ScsiLookup. If found in
 		 * doneQ, delete from Q. Do OS callback.
 		 */
 		search_doneQ_for_cmd(hd, SCpnt);
 
 		SCpnt->result = DID_RESET << 16;
-		spin_lock_irqsave(&io_request_lock, flags);
 		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&io_request_lock, flags);
+		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
+			   "Command not in the active list! (sc=%p)\n",
+			   hd->ioc->name, SCpnt));
 		return SUCCESS;
 	}
 
+	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
+	 *  If we time out, then we return a FAILED status to the caller.  This
+	 *  call to mptscsih_tm_pending_wait() will set the pending flag if we are
+	 *  successful.
+	 */
+	if (mptscsih_tm_pending_wait(hd) == FAILED){
+		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
+			   "Timed out waiting for previous TM to complete! "
+			   "(sc = %p)\n",
+			   hd->ioc->name, SCpnt));
+		return FAILED;
+	}
+
 	/* If this command is pended, then timeout/hang occurred
-	 * during DV. Post command and flush pending Q 
+	 * during DV. Post command and flush pending Q
 	 * and then following up with the reset request.
 	 */
 	if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
 		mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
 		post_pendingQ_commands(hd);
+		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
+			   "Found command in pending queue! (sc=%p)\n",
+			   hd->ioc->name, SCpnt));
 	}
 
 	/* Most important!  Set TaskMsgContext to SCpnt's MsgContext!
@@ -2611,61 +2737,62 @@
 	mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
 	ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
 
-	/* This thread will not exit until tmPending is cleared
-	 * FIXME - must ensure single threaded....DV conflict possible
-	 */
-	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
-	hd->tmPending = 1;
-	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-
-	if (hd->is_spi)
-		type = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
-	else {
-		type = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
-		hd->abortSCpnt = SCpnt;
-		printk(KERN_WARNING MYNAM ": Attempting ABORT SCSI IO! (sc=%p)\n", SCpnt);
-	}
+	hd->abortSCpnt = SCpnt;
 
-	if (mptscsih_TMHandler(hd, type,
-			SCpnt->target, SCpnt->lun, ctx2abort, CAN_SLEEP) < 0) {
+	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
+	                       SCpnt->target, SCpnt->lun, ctx2abort, CAN_SLEEP) 
+		< 0
+	    || hd->tmState == TM_STATE_ERROR) {
 
 		/* The TM request failed and the subsequent FW-reload failed!
 		 * Fatal error case.
 		 */
-		printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n",
-				hd->ioc->name, SCpnt);
+		printk(MYIOC_s_WARN_FMT "Error issuing abort task! (sc=%p)\n",
+		       hd->ioc->name, SCpnt);
 
 		/* If command not found, do not do callback,
-		 *  just return failed.  CHECKME 
+		 *  just return failed.  CHECKME
 		 */
 		if (hd->ScsiLookup[scpnt_idx] != NULL) {
-			//atomic_dec(&queue_depth);
 			SCpnt->result = STS_BUSY;
-			spin_lock_irqsave(&io_request_lock, flags);
 			SCpnt->scsi_done(SCpnt);
-			spin_unlock_irqrestore(&io_request_lock, flags);
 		}
 
-		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+		/* We must clear our pending flag before clearing our state.
+		 */
 		hd->tmPending = 0;
-		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-	}
+		hd->tmState = TM_STATE_NONE;
 
+		return FAILED;
+	}
 
-	/* Spin on tmPending until we get the interrupt for this TM request.
+	/* Our task management request will either complete or time out.  So we
+	 * spin until tmPending is != 1. If tmState is set to TM_STATE_ERROR, 
+	 * we encountered an error executing the task management request.
 	 */
-	while (1) {
-		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
-		if (!hd->tmPending) {
-			spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-			break;
-		}
-		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+	while (hd->tmPending == 1){
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ/4);
 	}
+	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+	if (hd->tmState == TM_STATE_ERROR){
+		hd->tmState = TM_STATE_NONE;
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
+			   "TM timeout error! (sc=%p)\n",
+			   hd->ioc->name,
+			   SCpnt));
+		return FAILED;
+	}
+	hd->tmState = TM_STATE_NONE;
+	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+	nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
+		   "Abort was successful! (sc=%p)\n",
+		   hd->ioc->name,
+		   SCpnt));
 
-	return FAILED;
+	return SUCCESS;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2681,98 +2808,75 @@
 mptscsih_dev_reset(Scsi_Cmnd * SCpnt)
 {
 	MPT_SCSI_HOST	*hd;
-	MPT_FRAME_HDR	*mf;
 	unsigned long	 flags;
-	int		 scpnt_idx;
-	u8		 type;
-
-	printk(KERN_WARNING MYNAM ": Attempting _TARGET_RESET (%p)\n", SCpnt);
-	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
-
-	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
-		SCpnt->result = DID_RESET << 16;
-		spin_lock_irqsave(&io_request_lock, flags);
-		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return SUCCESS;
-	}
-
-	/* Find this command
-	 */
-	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
-		/* Cmd not found in ScsiLookup. If found in 
-		 * doneQ, delete from Q. Do OS callback.
-		 */
-		search_doneQ_for_cmd(hd, SCpnt);
-
-		SCpnt->result = DID_RESET << 16;
-		spin_lock_irqsave(&io_request_lock, flags);
-		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return SUCCESS;
-	}
 
-	/* If this command is pended, then timeout/hang occurred
-	 * during DV. Force bus reset by posting command to F/W
-	 * and then following up with the reset request.
+	/* If we can't locate our host adapter structure, return FAILED status.
 	 */
-	if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
-		mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
-		post_pendingQ_commands(hd);
+	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL){
+		nehprintk((KERN_WARNING MYNAM ": mptscsih_dev_reset: "
+			   "Can't locate host! (sc=%p)\n",
+			   SCpnt));
+		return FAILED;
 	}
 
-	/* This thread will not exit until tmPending is cleared
-	 */
-	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
-	hd->tmPending = 1;
-	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-
-	if (hd->is_spi)
-		type = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
-	else {
-		type = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
-		printk(KERN_WARNING MYNAM ": Attempting Target Reset! (sc=%p)\n", SCpnt);
+	printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p)\n",
+	       hd->ioc->name, SCpnt);
+	printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
+	       hd->ioc->name, atomic_read(&queue_depth));
+
+	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
+	 *  If we time out, then we return a FAILED status to the caller.  This
+	 *  call to mptscsih_tm_pending_wait() will set the pending flag if we are
+	 *  successful.
+	 */
+	if (mptscsih_tm_pending_wait(hd) == FAILED) {
+		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_dev_reset: "
+			   "Timed out waiting for previous TM to complete! "
+			   "(sc = %p)\n",
+			   hd->ioc->name, SCpnt));
+		return FAILED;
 	}
 
 	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
-				SCpnt->target, 0, 0, CAN_SLEEP) < 0) {
+	                       SCpnt->target, 0, 0, CAN_SLEEP) 
+		< 0){
 		/* The TM request failed and the subsequent FW-reload failed!
 		 * Fatal error case.
 		 */
 		printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n",
 		 		hd->ioc->name, SCpnt);
-
-		/* If command not found, do not do callback,
-		 * just returned failed. CHECKME.
-		 */
-		if (hd->ScsiLookup[scpnt_idx] != NULL) {
-			//atomic_dec(&queue_depth);
-			SCpnt->result = STS_BUSY;
-			spin_lock_irqsave(&io_request_lock, flags);
-			SCpnt->scsi_done(SCpnt);
-			spin_unlock_irqrestore(&io_request_lock, flags);
-		}
-
-		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
 		hd->tmPending = 0;
-		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+		hd->tmState = TM_STATE_NONE;
+		return FAILED;
 	}
 
-	/* Spin on tmPending until we get the interrupt for this TM request.
+	/* Our task management request will either complete or time out.  So we
+	 * spin until tmPending is != 1. If tmState is set to TM_STATE_ERROR, 
+	 * we encountered an error executing the task management request.
 	 */
-	while (1) {
-		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
-		if (!hd->tmPending) {
-			spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-			break;
-		}
-		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+	while (hd->tmPending == 1){
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ/4);
 	}
+	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+	if (hd->tmState == TM_STATE_ERROR){
+		hd->tmState = TM_STATE_NONE;
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_dev_reset: "
+			   "TM timeout error! (sc=%p)\n",
+			   hd->ioc->name,
+			   SCpnt));
+		return FAILED;
+	}
+	hd->tmState = TM_STATE_NONE;
+	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+	nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_dev_reset: "
+		   "Device reset was successful! (sc=%p)\n",
+		   hd->ioc->name,
+		   SCpnt));
 
-	//return SUCCESS;
-	return FAILED;
+	return SUCCESS;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2788,95 +2892,80 @@
 mptscsih_bus_reset(Scsi_Cmnd * SCpnt)
 {
 	MPT_SCSI_HOST	*hd;
-	MPT_FRAME_HDR	*mf;
 	unsigned long	 flags;
-	int		 scpnt_idx;
 
-	printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET (%p)\n", SCpnt);
-	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
-
-	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
-		SCpnt->result = DID_RESET << 16;
-		spin_lock_irqsave(&io_request_lock, flags);
-		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return SUCCESS;
-	}
-
-	/* Find this command
+	/* If we can't locate our host adapter structure, return FAILED status.
 	 */
-	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
-		/* Cmd not found in ScsiLookup. If found in 
-		 * doneQ, delete from Q. Do OS callback.
-		 */
-		search_doneQ_for_cmd(hd, SCpnt);
-
-		SCpnt->result = DID_RESET << 16;
-		spin_lock_irqsave(&io_request_lock, flags);
-		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return SUCCESS;
+	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL){
+		nehprintk((KERN_WARNING MYNAM ": mptscsih_bus_reset: "
+			   "Can't locate host! (sc=%p)\n",
+			   SCpnt ) );
+		return FAILED;
 	}
 
-	/* If this command is pended, then timeout/hang occurred
-	 * during DV. Force bus reset by posting command to F/W
-	 * and then following up with the reset request.
-	 */
-	if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
-		mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
-		post_pendingQ_commands(hd);
+	printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p)\n",
+	       hd->ioc->name, SCpnt);
+	printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
+	       hd->ioc->name, atomic_read(&queue_depth));
+
+	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
+	 *  If we time out, then we return a FAILED status to the caller.  This
+	 *  call to mptscsih_tm_pending_wait() will set the pending flag if we are
+	 *  successful.
+	 */
+	if (mptscsih_tm_pending_wait(hd) == FAILED) {
+		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_bus_reset: "
+			   "Timed out waiting for previous TM to complete! "
+			   "(sc = %p)\n",
+			   hd->ioc->name, SCpnt ) );
+		return FAILED;
 	}
 
-	/* This thread will not exit until tmPending is cleared
-	 */
-	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
-	hd->tmPending = 1;
-	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-
+	/* We are now ready to execute the task management request. */
 	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
-						0, 0, 0, CAN_SLEEP) < 0) {
+	                       0, 0, 0, CAN_SLEEP) 
+	    < 0){
 
 		/* The TM request failed and the subsequent FW-reload failed!
 		 * Fatal error case.
 		 */
-		printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n",
-		 		hd->ioc->name, SCpnt);
-
-		/* If command not found, do not do callback,
-		 * just returned failed. CHECKME.
-		 */
-		if (hd->ScsiLookup[scpnt_idx] != NULL) {
-			//atomic_dec(&queue_depth);
-			SCpnt->result = STS_BUSY;
-			spin_lock_irqsave(&io_request_lock, flags);
-			SCpnt->scsi_done(SCpnt);
-			spin_unlock_irqrestore(&io_request_lock, flags);
-		}
-
-		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+		printk(MYIOC_s_WARN_FMT 
+		       "Error processing TaskMgmt request (sc=%p)\n",
+		       hd->ioc->name, SCpnt);
 		hd->tmPending = 0;
-		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-
+		hd->tmState = TM_STATE_NONE;
 		return FAILED;
 	}
 
-	/* Spin on tmPending until we get the interrupt for this TM request.
+	/* Our task management request will either complete or time out.  So we
+	 * spin until tmPending is != 1. If tmState is set to TM_STATE_ERROR, 
+	 * we encountered an error executing the task management request.
 	 */
-	while (1) {
-		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
-		if (!hd->tmPending) {
-			spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-			break;
-		}
-		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+	while (hd->tmPending == 1){
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ/4);
 	}
+	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+	if (hd->tmState == TM_STATE_ERROR){
+		hd->tmState = TM_STATE_NONE;
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_bus_reset: "
+			   "TM timeout error! (sc=%p)\n",
+			   hd->ioc->name,
+			   SCpnt));
+		return FAILED;
+	}
+	hd->tmState = TM_STATE_NONE;
+	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+	nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_bus_reset: "
+		   "Bus reset was successful! (sc=%p)\n",
+		   hd->ioc->name,
+		   SCpnt));
 
 	return SUCCESS;
 }
 
-#if 0
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *	mptscsih_host_reset - Perform a SCSI host adapter RESET!
@@ -2890,59 +2979,75 @@
 int
 mptscsih_host_reset(Scsi_Cmnd *SCpnt)
 {
-	MPT_SCSI_HOST	*hd;
-	MPT_FRAME_HDR	*mf;
-
-	printk(KERN_WARNING MYNAM ": Attempting HOST_RESET (%p)\n", SCpnt);
-	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+	MPT_SCSI_HOST *  hd;
+	int              status = SUCCESS;
 
-	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
-		SCpnt->result = DID_RESET << 16;
-		spin_lock_irqsave(&io_request_lock, flags);
-		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return SUCCESS;
+	/*  If we can't locate the host to reset, then we failed. */
+	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL){
+		nehprintk( ( KERN_WARNING MYNAM ": mptscsih_host_reset: "
+			     "Can't locate host! (sc=%p)\n",
+			     SCpnt ) );
+		return FAILED;
 	}
 
-	/* If this command is pended, then timeout/hang occurred
-	 * during DV. Force bus reset by posting command to F/W
-	 * and then following up with the reset request.
+	printk(KERN_WARNING MYNAM ": %s: >> Attempting host reset! (sc=%p)\n",
+	       hd->ioc->name, SCpnt);
+	printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
+	       hd->ioc->name, atomic_read(&queue_depth));
+
+	/*  If our attempts to reset the host failed, then return a failed
+	 *  status.  The host will be taken off line by the SCSI mid-layer.
 	 */
-	if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
-		mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
-		post_pendingQ_commands(hd);
+	if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
+		status = FAILED;
+	} else {
+		/*  Make sure TM pending is cleared and TM state is set to 
+		 *  NONE. 
+		 */
+		hd->tmPending = 0;
+		hd->tmState = TM_STATE_NONE;
 	}
 
-	/* This thread will not exit until tmPending is cleared
-	 */
-	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
-	hd->tmPending = 1;
-	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
-	if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) {
-		SCpnt->result = STS_BUSY;
-		spin_lock_irqsave(&io_request_lock, flags);		// sjr-added
-		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&io_request_lock, flags);	// sjr-added
-		return FAILED;
-	}
+	nehprintk( ( KERN_WARNING MYNAM ": mptscsih_host_reset: "
+		     "Status = %s\n",
+		     (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
 
-	/* Spin on tmPending until we get the interrupt for this TM request.
-	 */
-	while (1) {
+	return status;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_tm_pending_wait - wait for pending task management request to 
+ *		complete.
+ *	@hd: Pointer to MPT host structure.
+ *
+ *	Returns {SUCCESS,FAILED}.
+ */
+static int
+mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
+{
+	unsigned long  flags;
+	int            loop_count = 60 * 4;  /* Wait 60 seconds */
+	int            status = FAILED;
+
+	do {
 		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
-		if (!hd->tmPending) {
+		if (hd->tmState == TM_STATE_NONE) {
+			hd->tmState = TM_STATE_IN_PROGRESS;
+			hd->tmPending = 1;
 			spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+			status = SUCCESS;
 			break;
 		}
 		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ/4);
-	}
 
-	return SUCCESS;
+	} while (--loop_count);
+
+	return status;
 }
-#endif
 
 #else		/* MPT_SCSI old EH stuff... */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2963,7 +3068,7 @@
 	unsigned long		 flags;
 	int			 scpnt_idx;
 
-	printk(KERN_WARNING MYNAM ": OldAbort scheduling ABORT SCSI IO (sc=%p)\n", SCpnt);
+	printk(KERN_WARNING MYNAM ": OldAbort scheduling ABORT SCSI IO (sc=%p)\n", (void *) SCpnt);
 	printk(KERN_WARNING "  IOs outstanding = %d\n", atomic_read(&queue_depth));
 
 	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
@@ -3061,6 +3166,8 @@
 
 	if (! mytaskQ_bh_active) {
 		mytaskQ_bh_active = 1;
+		spin_unlock_irqrestore(&mytaskQ_lock, flags);
+
 		/*
 		 *  Oh how cute, no alloc/free/mgmt needed if we use
 		 *  (bottom/unused portion of) MPT request frame.
@@ -3071,8 +3178,9 @@
 		ptaskfoo->data = SCpnt;
 
 		SCHEDULE_TASK(ptaskfoo);
+	} else  {
+		spin_unlock_irqrestore(&mytaskQ_lock, flags);
 	}
-	spin_unlock_irqrestore(&mytaskQ_lock, flags);
 
 	return SCSI_ABORT_PENDING;
 }
@@ -3096,7 +3204,7 @@
 	unsigned long		 flags;
 	int			 scpnt_idx;
 
-	printk(KERN_WARNING MYNAM ": OldReset scheduling BUS_RESET (sc=%p)\n", SCpnt);
+	printk(KERN_WARNING MYNAM ": OldReset scheduling BUS_RESET (sc=%p)\n", (void *) SCpnt);
 	printk(KERN_WARNING "  IOs outstanding = %d\n", atomic_read(&queue_depth));
 
 	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
@@ -3174,8 +3282,11 @@
 	atomic_inc(&mpt_taskQdepth);
 	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
-	spin_lock_irqsave(&mytaskQ_lock, flags);
 
+	dtmprintk((MYIOC_s_INFO_FMT "OldReset: _bh_handler state (%d) taskQ count (%d)\n",
+		hd->ioc->name, mytaskQ_bh_active, hd->taskQcnt));
+
+	spin_lock_irqsave(&mytaskQ_lock, flags);
 	/* Save the original SCpnt mf pointer
 	 */
 	SCpnt->host_scribble = (u8 *) MPT_INDEX_2_MFPTR (hd->ioc, scpnt_idx);
@@ -3184,11 +3295,9 @@
 	mf->u.frame.linkage.argp1 = SCpnt;
 	mf->u.frame.linkage.argp2 = (void *) hd;
 
-	dtmprintk((MYIOC_s_INFO_FMT "OldReset: _bh_handler state (%d) taskQ count (%d)\n",
-		hd->ioc->name, mytaskQ_bh_active, hd->taskQcnt));
-
 	if (! mytaskQ_bh_active) {
 		mytaskQ_bh_active = 1;
+		spin_unlock_irqrestore(&mytaskQ_lock, flags);
 		/*
 		 *  Oh how cute, no alloc/free/mgmt needed if we use
 		 *  (bottom/unused portion of) MPT request frame.
@@ -3199,8 +3308,9 @@
 		ptaskfoo->data = SCpnt;
 
 		SCHEDULE_TASK(ptaskfoo);
+	} else  {
+		spin_unlock_irqrestore(&mytaskQ_lock, flags);
 	}
-	spin_unlock_irqrestore(&mytaskQ_lock, flags);
 	return SCSI_RESET_PENDING;
 }
 
@@ -3243,7 +3353,7 @@
 					printk(KERN_ERR MYNAM
 							": ERROR - TaskMgmt NULL SCSI Host!"
 							"(ioc=%p, sh=%p hd=%p)\n",
-							ioc, ioc->sh, hd);
+							(void *) ioc, (void *) ioc->sh, (void *) hd);
 					continue;
 				}
 
@@ -3276,7 +3386,7 @@
 				SCpnt = (Scsi_Cmnd*)mf->u.frame.linkage.argp1;
 				if (SCpnt == NULL) {
 					printk(KERN_ERR MYNAM ": ERROR - TaskMgmt has NULL SCpnt! (mf=%p:sc=%p)\n",
-							mf, SCpnt);
+							(void *) mf, (void *) SCpnt);
 					mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
 					spin_lock_irqsave(&ioc->FreeQlock, flags);
 					hd->tmPending = 0;
@@ -3330,7 +3440,7 @@
 
 					hd->abortSCpnt = SCpnt;
 					printk(KERN_WARNING MYNAM ": Attempting ABORT SCSI IO! (mf=%p:sc=%p)\n",
-							mf, SCpnt);
+							(void *) mf, (void *) SCpnt);
 				}
 
 				/* The TM handler will allocate a new mf,
@@ -3345,14 +3455,14 @@
 					 * Fatal error case.
 					 */
 					printk(KERN_WARNING MYNAM
-						": WARNING[1] - IOC error processing TaskMgmt request (sc=%p)\n", SCpnt);
+						": WARNING[1] - IOC error processing TaskMgmt request (sc=%p)\n", (void *) SCpnt);
 
 					if (hd->ScsiLookup[scpnt_idx] != NULL) {
 						atomic_dec(&queue_depth);
 						SCpnt->result = DID_SOFT_ERROR << 16;
-						spin_lock_irqsave(&io_request_lock, flags);
+                                                MPT_HOST_LOCK(flags);
 						SCpnt->scsi_done(SCpnt);
-						spin_unlock_irqrestore(&io_request_lock, flags);
+                                                MPT_HOST_UNLOCK(flags);
 						mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
 					}
 					spin_lock_irqsave(&ioc->FreeQlock, flags);
@@ -3462,6 +3572,9 @@
 					}
 				}
 			}
+#ifdef MPT_SCSI_USE_NEW_EH
+			hd->tmState = TM_STATE_ERROR;
+#endif
 		} else {
 			dtmprintk((KERN_INFO "  SCSI TaskMgmt SUCCESS!\n"));
 
@@ -3483,58 +3596,14 @@
 			flush_doneQ(hd);
 
 #ifdef	DROP_TEST
-			if (dropMfPtr)
-				dropTestOK++;
-#endif
-		}
-	}
-
-#ifdef	DROP_TEST
-	{
-		Scsi_Cmnd	*sc;
-		unsigned long	 flags;
-		u16		 req_idx;
-
-		/* Free resources for the drop test MF and chain buffers.
-		 */
-		if (dropMfPtr) {
-			req_idx = le16_to_cpu(dropMfPtr->u.frame.hwhdr.msgctxu.fld.req_idx);
-			sc = hd->ScsiLookup[req_idx];
-			if (sc == NULL) {
-				printk(MYIOC_s_ERR_FMT
-					"Drop Test: NULL ScsiCmd ptr!\n",
-					ioc->name);
-			} else {
-				sc->host_scribble = NULL;
-				if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
-					sc->result = DID_RESET << 16;
-				else
-					sc->result = DID_ABORT << 16;
-
-				hd->ScsiLookup[req_idx] = NULL;
-				atomic_dec(&queue_depth);
-				spin_lock_irqsave(&io_request_lock, flags);
-				sc->scsi_done(sc);	/* Issue callback */
-				spin_unlock_irqrestore(&io_request_lock, flags);
-
-				mptscsih_freeChainBuffers(hd, req_idx);
-				mpt_free_msg_frame(ScsiDoneCtx, ioc->id, dropMfPtr);
-
-				printk(MYIOC_s_INFO_FMT
-						"Free'd Dropped cmd (%p)\n",
-						hd->ioc->name, sc);
-				printk(MYIOC_s_INFO_FMT
-						"mf (%p) reqidx (%4x)\n",
-						hd->ioc->name, dropMfPtr,
-						req_idx);
-				printk(MYIOC_s_INFO_FMT
-					"Num Tot (%d) Good (%d) Bad (%d) \n",
-					hd->ioc->name, dropTestNum,
-					dropTestOK, dropTestBad);
-			}
-			dropMfPtr = NULL;
+			if (dropMfPtr)
+				dropTestOK++;
+#endif
 		}
 	}
+
+#ifdef	DROP_TEST
+	mptscsih_flush_drop_test(hd);
 #endif
 
 #ifndef MPT_SCSI_USE_NEW_EH
@@ -3588,16 +3657,16 @@
 	MPT_SCSI_HOST		*hd;
 	int			 ii, max;
 
-	for (device = sdList; device; device = device->next) {
+	for (device = sdList; device != NULL; device = device->next) {
 
 		if (device->host != sh)
 			continue;
 
 		hd = (MPT_SCSI_HOST *) sh->hostdata;
-		if (!hd)
+		if (hd == NULL)
 			continue;
 
-		if (hd->Targets) {
+		if (hd->Targets != NULL) {
 			if (hd->is_spi)
 				max = MPT_MAX_SCSI_DEVICES;
 			else
@@ -3623,11 +3692,38 @@
  *     1 = _DATA_OUT
  *     0 = _DIR_NONE
  *    -1 = _DATA_IN
+ *
+ * Changed: 3-20-2002 pdelaney to use the default data
+ * direction and the defines set up in the
+ * 2.4 kernel series
+ *     1 = _DATA_OUT	changed to SCSI_DATA_WRITE (1)
+ *     0 = _DIR_NONE	changed to SCSI_DATA_NONE (3)
+ *    -1 = _DATA_IN	changed to SCSI_DATA_READ (2)
+ * If the direction is unknown, fall through to original code.
+ *
+ * Mid-layer bug fix(): sg interface generates the wrong data 
+ * direction in some cases. Set the direction the hard way for 
+ * the most common commands.
  */
 static int
 mptscsih_io_direction(Scsi_Cmnd *cmd)
 {
 	switch (cmd->cmnd[0]) {
+	case WRITE_6:		
+	case WRITE_10:		
+		return SCSI_DATA_WRITE;
+		break;
+	case READ_6:		
+	case READ_10:		
+		return SCSI_DATA_READ;
+		break;
+	}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	if (cmd->sc_data_direction != SCSI_DATA_UNKNOWN)
+		return cmd->sc_data_direction;
+#endif
+	switch (cmd->cmnd[0]) {
 	/*  _DATA_OUT commands	*/
 	case WRITE_6:		case WRITE_10:		case WRITE_12:
 	case WRITE_LONG:	case WRITE_SAME:	case WRITE_BUFFER:
@@ -3642,7 +3738,7 @@
 	case PERSISTENT_RESERVE_OUT:
 	case 0xea:
 	case 0xa3:
-		return 1;
+		return SCSI_DATA_WRITE;
 
 	/*  No data transfer commands  */
 	case SEEK_6:		case SEEK_10:
@@ -3650,26 +3746,26 @@
 	case TEST_UNIT_READY:
 	case START_STOP:
 	case ALLOW_MEDIUM_REMOVAL:
-		return 0;
+		return SCSI_DATA_NONE;
 
 	/*  Conditional data transfer commands	*/
 	case FORMAT_UNIT:
 		if (cmd->cmnd[1] & 0x10)	/* FmtData (data out phase)? */
-			return 1;
+			return SCSI_DATA_WRITE;
 		else
-			return 0;
+			return SCSI_DATA_NONE;
 
 	case VERIFY:
 		if (cmd->cmnd[1] & 0x02)	/* VERIFY:BYTCHK (data out phase)? */
-			return 1;
+			return SCSI_DATA_WRITE;
 		else
-			return 0;
+			return SCSI_DATA_NONE;
 
 	case RESERVE_10:
 		if (cmd->cmnd[1] & 0x03)	/* RESERVE:{LongID|Extent} (data out phase)? */
-			return 1;
+			return SCSI_DATA_WRITE;
 		else
-			return 0;
+			return SCSI_DATA_NONE;
 
 #if 0
 	case REZERO_UNIT:	/* (or REWIND) */
@@ -3681,7 +3777,7 @@
 
 	/*  Must be data _IN!  */
 	default:
-		return -1;
+		return SCSI_DATA_READ;
 	}
 }
 
@@ -3727,6 +3823,20 @@
 				sz =  SCSI_STD_SENSE_BYTES;
 			memcpy(target->sense, sense_data, sz);
 			target->tflags |= MPT_TARGET_FLAGS_VALID_SENSE;
+
+#ifdef ABORT_FIX
+			if (sz >= SCSI_STD_SENSE_BYTES) {
+				if ((sense_data[02] == ABORTED_COMMAND) && 
+					(sense_data[12] == 0x47) && (sense_data[13] == 0x00)){
+					target->numAborts++;
+					if ((target->raidVolume == 0) && (target->numAborts > 5)) {
+						target->numAborts = 0;
+						target->minSyncFactor++;
+						hd->ioc->spi_data.dvStatus[index] |= MPT_SCSICFG_NEGOTIATE;
+					}
+				}
+			}
+#endif
 		}
 
 		/* Log SMART data (asc = 0x5D, non-IM case only) if required.
@@ -3820,7 +3930,7 @@
 	MPT_FRAME_HDR	*mf = NULL;
 	MPT_FRAME_HDR	*cmdMfPtr = NULL;
 
-	ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ called...", hd->ioc->name));
+	ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ ...", hd->ioc->name));
 	cmdMfPtr = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
 	spin_lock_irqsave(&hd->freedoneQlock, flags);
 	if (!Q_IS_EMPTY(&hd->pendingQ)) {
@@ -3860,7 +3970,7 @@
 
 	/* Flush the pendingQ.
 	 */
-	ddvtprintk((MYIOC_s_INFO_FMT ": post_pendingQ_commands called\n", hd->ioc->name));
+	ddvtprintk((MYIOC_s_INFO_FMT ": post_pendingQ_commands\n", hd->ioc->name));
 	while (1) {
 		spin_lock_irqsave(&hd->freedoneQlock, flags);
 		if (Q_IS_EMPTY(&hd->pendingQ)) {
@@ -3874,23 +3984,29 @@
 		Q_DEL_ITEM(buffer);
 
 		mf = (MPT_FRAME_HDR *) buffer->argp;
+		buffer->argp = NULL;
+
+		/* Add to the freeQ
+		 */
+		Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
+		spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+
 		if (!mf) {
 			/* This should never happen */
-			printk(MYIOC_s_WARN_FMT "post_pendingQ_commands: mf %p\n", hd->ioc->name, mf);
-			spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+			printk(MYIOC_s_WARN_FMT "post_pendingQ_commands: mf %p\n", hd->ioc->name, (void *) mf);
 			continue;
 		}
 
 		mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
-		ddvtprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (mf=%p)\n",
-				hd->ioc->name, mf));
 
-		buffer->argp = NULL;
-
-		/* Add to the freeQ
-		 */
-		Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
-		spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
+		{
+			u16		 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+			Scsi_Cmnd	*sc = hd->ScsiLookup[req_idx];
+			printk(MYIOC_s_INFO_FMT "Issued SCSI cmd (sc=%p) idx=%d (mf=%p)\n",
+					hd->ioc->name, sc, req_idx, mf);
+		}
+#endif
 	}
 
 	return;
@@ -3935,40 +4051,7 @@
 		/* 2a. Drop Test Command.
 		 */
 #ifdef	DROP_TEST
-		{
-			Scsi_Cmnd	*sc;
-			unsigned long	 flags;
-			u16		 req_idx;
-
-			/* Free resources for the drop test MF
-			 * and chain buffers.
-			 */
-			if (dropMfPtr) {
-				req_idx = le16_to_cpu(dropMfPtr->u.frame.hwhdr.msgctxu.fld.req_idx);
-				sc = hd->ScsiLookup[req_idx];
-				if (sc == NULL) {
-					printk(MYIOC_s_ERR_FMT
-					"Drop Test: NULL ScsiCmd ptr!\n",
-					ioc->name);
-				} else {
-					sc->host_scribble = NULL;
-					sc->result = DID_RESET << 16;
-					hd->ScsiLookup[req_idx] = NULL;
-					atomic_dec(&queue_depth);
-					spin_lock_irqsave(&io_request_lock, flags);
-					sc->scsi_done(sc);	/* Issue callback */
-					spin_unlock_irqrestore(&io_request_lock, flags);
-				}
-
-				mptscsih_freeChainBuffers(hd, req_idx);
-				mpt_free_msg_frame(ScsiDoneCtx, ioc->id, dropMfPtr);
-				printk(MYIOC_s_INFO_FMT
-						"Free'd: mf (%p) reqidx (%4x)\n",
-						hd->ioc->name, dropMfPtr,
-						req_idx);
-			}
-			dropMfPtr = NULL;
-		}
+		mptscsih_flush_drop_test(hd);
 #endif
 
 		/* 2b. Reply to OS all known outstanding I/O commands.
@@ -4102,14 +4185,18 @@
 		/*
 		 *  CHECKME!  Falling thru...
 		 */
+		break;
 
 	case MPI_EVENT_INTEGRATED_RAID:			/* 0B */
 #ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
 		/* negoNvram set to 0 if DV enabled and to USE_NVRAM if 
-		 * if DV disabled
+		 * if DV disabled. Need to check for target mode.
 		 */
-		hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
-		if (hd->negoNvram == 0) {
+		hd = NULL;
+		if (ioc->sh)
+			hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+
+		if (hd && (hd->is_spi) && (hd->negoNvram == 0)) {
 			ScsiCfgData	*pSpi;
 			Ioc3PhysDisk_t	*pPDisk;
 			int		 numPDisk;
@@ -4129,7 +4216,7 @@
 
 					while (numPDisk) {
 						if (physDiskNum == pPDisk->PhysDiskNum) {
-							pSpi->dvStatus[pPDisk->PhysDiskID] = MPT_SCSICFG_NEED_DV;
+							pSpi->dvStatus[pPDisk->PhysDiskID] = (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE);
 							pSpi->forceDv = MPT_SCSICFG_NEED_DV;
 							ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
 							break;
@@ -4556,7 +4643,7 @@
 		return 0;
 	}
 	if (	(sk==SK_UNIT_ATTENTION	&& asc==0x29 && (ascq==0x00 || ascq==0x01))
-	     || (sk==SK_NOT_READY	&& asc==0x04 && ascq==0x01)
+	     || (sk==SK_NOT_READY	&& asc==0x04 && (ascq==0x01 || ascq==0x02))
 	     || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00)
 	   )
 	{
@@ -4564,6 +4651,26 @@
 		return 0;
 	}
 
+	/* Prevent the system from continually writing to the log
+	 * if a medium is not found: 02 3A 00
+	 * Changer issues: TUR, Read Capacity, Table of Contents continually
+	 */
+	if (sk==SK_NOT_READY && asc==0x3A) {
+		if (ioop->cdbPtr == NULL) {
+			return 0;
+		} else if ((ioop->cdbPtr[0] == CMD_TestUnitReady) ||
+			(ioop->cdbPtr[0] == CMD_ReadCapacity) || 
+			(ioop->cdbPtr[0] == 0x43)) {
+			return 0;
+		}
+	}
+	if (sk==SK_UNIT_ATTENTION) {
+		if (ioop->cdbPtr == NULL)
+			return 0;
+		else if (ioop->cdbPtr[0] == CMD_TestUnitReady)
+			return 0;
+	}
+
 	/*
 	 *  Protect ourselves...
 	 */
@@ -4675,6 +4782,13 @@
 		}
 	}
 
+	if (vdev) {
+		if (hd->ioc->spi_data.isRaid & (1 << target_id))
+			vdev->raidVolume = 1;
+		else
+			vdev->raidVolume = 0;
+	}
+
 	if (vdev && data) {
 		if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
 
@@ -4687,7 +4801,18 @@
 
 			/* Update the target capabilities
 			 */
-			mptscsih_setTargetNegoParms(hd, vdev);
+			if (dlen > 56)
+				mptscsih_setTargetNegoParms(hd, vdev, data[56]);
+			else
+				mptscsih_setTargetNegoParms(hd, vdev, 0);
+
+			/* If LUN 0, tape and have not done DV, set the DV flag.
+			 */
+			if ((lun == 0) && ((data[0] & 0x1F) == 0x01)) {
+				ScsiCfgData *pSpi = &hd->ioc->spi_data;
+				if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE)
+					pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV;
+			}
 		}
 
 		/* Is LUN supported? If so, upper 3 bits will be 0
@@ -4697,12 +4822,6 @@
 			vdev->luns |= (1 << lun);
 	}
 
-	if (vdev) {
-		if (hd->ioc->spi_data.isRaid & (1 << target_id))
-			vdev->raidVolume = 1;
-		else
-			vdev->raidVolume = 0;
-	}
 
 	dprintk((KERN_INFO "  target = %p\n", vdev));
 	return vdev;
@@ -4714,8 +4833,9 @@
  *  the Inquiry data, adapter capabilities, and NVRAM settings.
  *
  */
-void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target)
+void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56)
 {
+	ScsiCfgData *pspi_data = &hd->ioc->spi_data;
 	int  id = (int) target->target_id;
 	int  nvram;
 	char canQ = 0;
@@ -4723,12 +4843,12 @@
 	u8 factor = MPT_ASYNC;
 	u8 offset = 0;
 	u8 version, nfactor;
-	ScsiCfgData *pspi_data = &hd->ioc->spi_data;
+	u8 noQas = 1;
 
 	/* Set flags based on Inquiry data
 	 */
 	if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
-		version = target->inq_data[2] & 0x03;
+		version = target->inq_data[2] & 0x07;
 		if (version < 2) {
 			width = 0;
 			factor = MPT_ULTRA2;
@@ -4739,11 +4859,18 @@
 			}
 
 			if (target->inq_data[7] & 0x10) {
-				if (version == 2)
+				/* bits 2 & 3 show DT support
+				 */
+				if ((byte56 & 0x04) == 0)
 					factor = MPT_ULTRA2;
 				else
 					factor = MPT_ULTRA320;
 
+				/* bit 1 QAS support, non-raid only
+				 */
+				if ((target->raidVolume == 0) && (byte56 & 0x02) != 0)
+					noQas = 0;
+
 				offset = pspi_data->maxSyncOffset;
 			} else {
 				factor = MPT_ASYNC;
@@ -4801,15 +4928,39 @@
 
 		target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
 
-		/* Disable all wide (sync) extended messages
-		 * if device is narrow (async).
+		/* Disable unused features.
 		 */
-		target->negoFlags = 0;
+		target->negoFlags = pspi_data->noQas;
 		if (!width)
 			target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
 
 		if (!offset)
 			target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+
+		if (noQas)
+			target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+
+		/* GEM, processor WORKAROUND
+		 */
+		if (((target->inq_data[0] & 0x1F) == 0x03) || ((target->inq_data[0] & 0x1F) > 0x08)){
+			target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
+			pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
+		}
+
+		/* Disable QAS if mixed configuration case
+		 */
+		if ((noQas) && (!pspi_data->noQas) && ((target->inq_data[0] & 0x1F) == 0x00)){
+			VirtDevice	*vdev;
+			int ii;
+
+			pspi_data->noQas = MPT_TARGET_NO_NEGO_QAS;
+			for (ii = 0; ii < id; ii++) {
+				vdev = hd->Targets[id];
+				if (vdev != NULL)
+					vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+			}
+		}
+
 	}
 
 	return;
@@ -4831,48 +4982,58 @@
 	return;
 }
 
-/* 
- * If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
+/* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
  * Else set the NEED_DV flag after Read Capacity Issued (disks) 
- * or Mode Sense (cdroms). Tapes, key off of Inquiry command.
+ * or Mode Sense (cdroms). 
+ *
+ * Tapes, initTarget will set this flag on completion of Inquiry command.
+ * Called only if DV_NOT_DONE flag is set
  */
-static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq, char *data)
+static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
 {
-	u8 cmd = pReq->CDB[0];
+	u8 cmd;
 	
-	if (pReq->LUN[1] != 0)
+	if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0))
 		return;
 
-	if (hd->negoNvram != 0)
-		return;
+	cmd = pReq->CDB[0];
+
+	if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) {
+		ScsiCfgData *pSpi = &hd->ioc->spi_data;
+		if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) {
+			/* Set NEED_DV for all hidden disks
+			 */
+			Ioc3PhysDisk_t *pPDisk =  pSpi->pIocPg3->PhysDisk;
+			int		numPDisk = pSpi->pIocPg3->NumPhysDisks;
 
-	if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE) || 
-		((cmd == INQUIRY) && ((data[0] & 0x1F) == 0x01))) {
-		u8 dvStatus = hd->ioc->spi_data.dvStatus[pReq->TargetID];
-		if (!(dvStatus & MPT_SCSICFG_DV_DONE)) {
-			ScsiCfgData *pSpi = &hd->ioc->spi_data;
-			if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) {
-				/* Set NEED_DV for all hidden disks
-				 */
-				Ioc3PhysDisk_t *pPDisk =  pSpi->pIocPg3->PhysDisk;
-				int		numPDisk = pSpi->pIocPg3->NumPhysDisks;
-				
-				while (numPDisk) {
-					pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
-					ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
-					pPDisk++;
-					numPDisk--;
-				}
-			}
-			pSpi->dvStatus[pReq->TargetID] |= MPT_SCSICFG_NEED_DV;
-			ddvtprintk(("NEED_DV set for visible disk id %d\n", 
-					pReq->TargetID));
-		};
+			while (numPDisk) {
+				pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
+				ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
+				pPDisk++;
+				numPDisk--;
+			}
+		}
+		pSpi->dvStatus[pReq->TargetID] |= MPT_SCSICFG_NEED_DV;
+		ddvtprintk(("NEED_DV set for visible disk id %d\n", pReq->TargetID));
 	}
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
+ * If no Target, bus reset on 1st I/O. Set the flag to 
+ * prevent any future negotiations to this device.
+ */
+static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id)
+{
+
+	if ((hd->Targets) && (hd->Targets[target_id] == NULL))
+		hd->ioc->spi_data.dvStatus[target_id] |= MPT_SCSICFG_BLK_NEGO;
+
+	return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
  *  SCSI Config Page functionality ...
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -4901,8 +5062,9 @@
 
 	if (width && offset && !nowide && !nosync) {
 		if (factor < MPT_ULTRA160) {
-			*requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT +
-						MPI_SCSIDEVPAGE1_RP_QAS);
+			*requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT);
+			if ((flags & MPT_TARGET_NO_NEGO_QAS) == 0)
+				*requestedPtr |= MPI_SCSIDEVPAGE1_RP_QAS;
 		} else if (factor < MPT_ULTRA2) {
 			*requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT;
 		}
@@ -4922,7 +5084,7 @@
  *	@hd: Pointer to a SCSI Host Strucutre
  *	@portnum: IOC port number
  *	@target_id: writeSDP1 for single ID
- *	@flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM
+ *	@flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM, MPT_SCSICFG_BLK_NEGO
  *
  *	Return: -EFAULT if read of config page header fails
  *		or 0 if success.
@@ -4942,7 +5104,6 @@
 	SCSIDevicePage1_t	*pData = NULL;
 	VirtDevice		*pTarget = NULL;
 	MPT_FRAME_HDR		*mf;
-	MptSge_t		*psge;
 	dma_addr_t		 dataDma;
 	u16			 req_idx;
 	u32			 frameOffset;
@@ -4954,6 +5115,7 @@
 	u8			 offset;
 	u8			 bus = 0;
 	u8			 negoFlags;
+	u8			 maxwidth, maxoffset, maxfactor;
 
 	if (ioc->spi_data.sdp1length == 0)
 		return 0;
@@ -4967,48 +5129,54 @@
 	}
 
 	for (; id <= maxid; id++) {
+
 		if (id == ioc->pfacts[portnum].PortSCSIID)
 			continue;
 
-		if (flags & MPT_SCSICFG_USE_NVRAM) {
-			/* Use NVRAM, adapter maximums and target settings.
-			 * Data over-riden by target structure information, if present
-			 */
-			width = ioc->spi_data.maxBusWidth;
-			offset = ioc->spi_data.maxSyncOffset;
-			factor = ioc->spi_data.minSyncFactor;
-			if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
-				nvram = ioc->spi_data.nvram[id];
-
-				if (width)
-					width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
-
-				if (offset > 0) {
-					factor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
-					if (factor == 0) {
-						/* Key for async */
-						factor = MPT_ASYNC;
-						offset = 0;
-					} else if (factor < ioc->spi_data.minSyncFactor) {
-						factor = ioc->spi_data.minSyncFactor;
-					}
-				} else
-					factor = MPT_ASYNC;
-			}
+		/* Use NVRAM to get adapter and target maximums
+		 * Data over-riden by target structure information, if present
+		 */
+		maxwidth = ioc->spi_data.maxBusWidth;
+		maxoffset = ioc->spi_data.maxSyncOffset;
+		maxfactor = ioc->spi_data.minSyncFactor;
+		if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+			nvram = ioc->spi_data.nvram[id];
+
+			if (maxwidth)
+				maxwidth = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
+
+			if (maxoffset > 0) {
+				maxfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
+				if (maxfactor == 0) {
+					/* Key for async */
+					maxfactor = MPT_ASYNC;
+					maxoffset = 0;
+				} else if (maxfactor < ioc->spi_data.minSyncFactor) {
+					maxfactor = ioc->spi_data.minSyncFactor;
+				}
+			} else
+				maxfactor = MPT_ASYNC;
+		}
 
-			/* Set the negotiation flags.
-			 */
-			negoFlags = 0;
-			if (!width)
-				negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
-	
-			if (!offset)
-				negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+		/* Set the negotiation flags.
+		 */
+		negoFlags = ioc->spi_data.noQas;
+		if (!maxwidth)
+			negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
+
+		if (!maxoffset)
+			negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+
+		if (flags & MPT_SCSICFG_USE_NVRAM) {
+			width = maxwidth;
+			factor = maxfactor;
+			offset = maxoffset;
 		} else {
 			width = 0;
 			factor = MPT_ASYNC;
 			offset = 0;
-			negoFlags = MPT_TARGET_NO_NEGO_SYNC;
+			//negoFlags = 0;
+			//negoFlags = MPT_TARGET_NO_NEGO_SYNC;
 		}
 
 		/* If id is not a raid volume, get the updated
@@ -5021,12 +5189,12 @@
 			negoFlags = pTarget->negoFlags;
 			pTarget = NULL;
 		}
-		mptscsih_setDevicePage1Flags(width, factor, offset,
-					&requested, &configuration, negoFlags);
 
+		if (flags & MPT_SCSICFG_BLK_NEGO)
+			negoFlags = MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC;
 
-		if (negoFlags == (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC))
-			continue;
+		mptscsih_setDevicePage1Flags(width, factor, offset,
+					&requested, &configuration, negoFlags);
 
 		/* Get a MF for this command.
 		 */
@@ -5036,6 +5204,10 @@
 			return -EAGAIN;
 		}
 
+		ddvprintk((MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n",
+			hd->ioc->name, mf, id, requested, configuration));
+
+
 		/* Set the request and the data pointers.
 		 * Request takes: 36 bytes (32 bit SGE)
 		 * SCSI Device Page 1 requires 16 bytes
@@ -5074,9 +5246,7 @@
 		 */
 		flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | ioc->spi_data.sdp1length * 4;
 
-		psge = (MptSge_t *) &pReq->PageBufferSGE;
-		psge->FlagsLength = cpu_to_le32(flagsLength);
-		cpu_to_leXX(dataDma, psge->Address);
+		mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
 
 		/* Set up the common data portion
 		 */
@@ -5109,19 +5279,39 @@
 {
 	MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
 
-	dprintk((MYIOC_s_WARN_FMT "TM request timed out!\n", hd->ioc->name));
+	dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_taskmgmt_timeout: "
+		   "TM request timed out!\n", hd->ioc->name));
+
 	/* Delete the timer that triggered this callback.
 	 * Remark: del_timer checks to make sure timer is active
 	 * before deleting.
 	 */
 	del_timer(&hd->TMtimer);
 
+#ifdef MPT_SCSI_USE_NEW_EH
+	/* Set the error flag to 1 so that the function that started the
+	 * task management request knows it timed out.
+	 */
+	hd->tmState = TM_STATE_ERROR;
+#endif
+
 	/* Call the reset handler. Already had a TM request
 	 * timeout - so issue a diagnostic reset
 	 */
 	if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
 		printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
 	}
+#ifdef MPT_SCSI_USE_NEW_EH
+	else {
+		/* Because we have reset the IOC, no TM requests can be
+		 * pending.  So let's make sure the tmPending flag is reset.
+		 */
+		nehprintk((KERN_WARNING MYNAM 
+			   ": %s: mptscsih_taskmgmt_timeout\n", 
+			   hd->ioc->name));
+		hd->tmPending = 0;
+	}
+#endif
 
 	return;
 }
@@ -5163,7 +5353,7 @@
 	    (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
 		printk(MYIOC_s_ERR_FMT
 			"ScanDvComplete, %s req frame ptr! (=%p)\n",
-				ioc->name, mf?"BAD":"NULL", mf);
+				ioc->name, mf?"BAD":"NULL", (void *) mf);
 		goto wakeup;
 	}
 
@@ -5174,13 +5364,13 @@
 	pReq = (SCSIIORequest_t *) mf;
 
 	if (mf != hd->cmdPtr) {
-		printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p)\n",
-				hd->ioc->name, mf, hd->cmdPtr);
+		printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
+				hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
 	}
 	hd->cmdPtr = NULL;
 
-	ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p)\n",
-			hd->ioc->name, mf, mr));
+	ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
+			hd->ioc->name, mf, mr, req_idx));
 
 	atomic_dec(&queue_depth);
 
@@ -5392,8 +5582,6 @@
 {
 	MpiRaidActionRequest_t	*pReq;
 	MPT_FRAME_HDR		*mf;
-	MptSge_t		*psge;
-	int			flagsLength;
 	int			in_isr;
 
 	in_isr = in_interrupt();
@@ -5423,14 +5611,8 @@
 	pReq->ActionDataWord = 0; /* Reserved for this action */
 	//pReq->ActionDataSGE = 0;
 
-	psge = (MptSge_t *) &pReq->ActionDataSGE;
-
-	/* Add a SGE to the config request.
-	 */
-	flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | 0;
-
-	psge->FlagsLength = cpu_to_le32(flagsLength);
-	cpu_to_leXX( (dma_addr_t) -1, psge->Address);
+	mpt_add_sge((char *)&pReq->ActionDataSGE, 
+		MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
 
 	ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
 			hd->ioc->name, action, io->id));
@@ -5479,7 +5661,6 @@
 mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
 {
 	MPT_FRAME_HDR	*mf;
-	MptSge_t	*mpisge;
 	SCSIIORequest_t	*pScsiReq;
 	SCSIIORequest_t	 ReqCopy;
 	int		 my_idx, ii, dir;
@@ -5614,7 +5795,7 @@
 
 	pScsiReq->Reserved = 0;
 
-	pScsiReq->MsgFlags = MPT_SCSIIO_MSG_FLAGS;
+	pScsiReq->MsgFlags = mpt_msg_flags();
 	/* MsgContext set in mpt_get_msg_fram call  */
 
 	for (ii=0; ii < 8; ii++)
@@ -5636,21 +5817,16 @@
 	ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
 			hd->ioc->name, cmd, io->bus, io->id, io->lun));
 
-	/* 32 bit SG only */
-	mpisge = (MptSge_t *) &pScsiReq->SGL;
-
 	if (dir == MPI_SCSIIO_CONTROL_READ) {
-		mpisge->FlagsLength = cpu_to_le32(
-			MPT_SGE_FLAGS_SSIMPLE_READ | io->size);
+		mpt_add_sge((char *) &pScsiReq->SGL,
+			MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
+			io->data_dma);
 	} else {
-		mpisge->FlagsLength = cpu_to_le32(
-			MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size);
+		mpt_add_sge((char *) &pScsiReq->SGL,
+			MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
+			io->data_dma);
 	}
 
-	/* data_dma defaults to -1
-	 */
-	cpu_to_leXX(io->data_dma, mpisge->Address);
-
 	/* The ISR will free the request frame, but we need
 	 * the information to initialize the target. Duplicate.
 	 */
@@ -5786,7 +5962,7 @@
 			if (pTarget && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
 				flags = pTarget->negoFlags;
 			} else {
-				flags = 0;
+				flags = hd->ioc->spi_data.noQas;
 				if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
 					data = hd->ioc->spi_data.nvram[id];
 	
@@ -5917,8 +6093,25 @@
 				dvStatus = hd->ioc->spi_data.dvStatus[id];
 
 				if (dvStatus & MPT_SCSICFG_NEED_DV) {
+					VirtDevice *pTarget = hd->Targets[id];
+					did++;
+					if (pTarget && ((pTarget->tflags & MPT_TARGET_FLAGS_Q_YES) == 0)){
+						if (hd->ioc->spi_data.iocntr[id] == 0) {
+							hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
+						} else {
+							/* Wait until not busy
+							 */
+							ddvtprintk((MYIOC_s_NOTE_FMT 
+							" DV Wait: %d untagged and busy. cntr %d\n",
+							ioc->name, id, 
+							hd->ioc->spi_data.iocntr[id]));
+							continue;
+						}
+					} else {
+						hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
+					}
+
 
-					hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
 					hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
 
 					set_current_state(TASK_INTERRUPTIBLE);
@@ -5928,24 +6121,7 @@
 					 *	raid volumes
 					 * else, process normally
 					 */
-					isPhysDisk = 0;
-					if (ioc->spi_data.pIocPg3) {
-						/* Search IOC page 3 to determine if
-						 * this is hidden physical disk
-						 */
-						Ioc3PhysDisk_t *pPDisk =  ioc->spi_data.pIocPg3->PhysDisk;
-						int		numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
-						
-						while (numPDisk) {
-							if (pPDisk->PhysDiskID == id) {
-								isPhysDisk = 1;
-								break;
-							}
-							pPDisk++;
-							numPDisk--;
-						}
-					}
-
+					isPhysDisk = mptscsih_is_phys_disk(ioc, id);
 					if (isPhysDisk) {
 						for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
 							if (hd->ioc->spi_data.isRaid & (1 << ii)) {
@@ -5955,9 +6131,8 @@
 					}
 
 					mptscsih_doDv(hd, 0, id);
-					did++;
-					hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_DONE;
-					hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
+
+					hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
 
 					if (isPhysDisk) {
 						for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
@@ -5971,6 +6146,9 @@
 					 * DV running.
 					 */
 					post_pendingQ_commands(hd);
+
+					if (hd->ioc->spi_data.noQas)
+						mptscsih_qas_check(hd);
 				}
 			}
 		}
@@ -5983,6 +6161,55 @@
 	return;
 }
 
+/* Search IOC page 3 to determine if this is hidden physical disk
+ */
+static int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
+{
+	if (ioc->spi_data.pIocPg3) {
+		Ioc3PhysDisk_t *pPDisk =  ioc->spi_data.pIocPg3->PhysDisk;
+		int		numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
+
+		while (numPDisk) {
+			if (pPDisk->PhysDiskID == id) {
+				return 1;
+			}
+			pPDisk++;
+			numPDisk--;
+		}
+	}
+	return 0;
+}
+
+/* Write SDP1 if no QAS has been enabled
+ */
+static void mptscsih_qas_check(MPT_SCSI_HOST *hd)
+{
+	VirtDevice *pTarget = NULL;
+	int ii;
+
+	if (hd->Targets == NULL)
+		return;
+
+	for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+		if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
+			continue;
+
+		pTarget = hd->Targets[ii];
+
+		if ((pTarget != NULL) && (!pTarget->raidVolume)) {
+			if ((pTarget->negoFlags & hd->ioc->spi_data.noQas) == 0) {
+				pTarget->negoFlags |= hd->ioc->spi_data.noQas;
+				mptscsih_writeSDP1(hd, 0, ii, 0);
+			}
+		} else {
+			if (mptscsih_is_phys_disk(hd->ioc, ii) == 1)
+				mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM);
+		}
+	}
+	return;
+}
+
+
 
 #define MPT_GET_NVRAM_VALS	0x01
 #define MPT_UPDATE_MAX		0x02
@@ -6009,19 +6236,22 @@
 {
 	MPT_ADAPTER		*ioc = hd->ioc;
 	VirtDevice		*pTarget = NULL;
+	SCSIDevicePage1_t	*pcfg1Data = NULL;
+	SCSIDevicePage0_t	*pcfg0Data = NULL;
 	u8			*pbuf1 = NULL;
 	u8			*pbuf2 = NULL;
+	u8			*pDvBuf = NULL;
+	dma_addr_t		 dvbuf_dma = -1;
 	dma_addr_t		 buf1_dma = -1;
 	dma_addr_t		 buf2_dma = -1;
-	ConfigPageHeader_t	 header1;
-	SCSIDevicePage1_t	*pcfg1Data = NULL;
 	dma_addr_t		 cfg1_dma_addr = -1;
-	ConfigPageHeader_t	 header0;
-	SCSIDevicePage0_t	*pcfg0Data = NULL;
 	dma_addr_t		 cfg0_dma_addr = -1;
+	ConfigPageHeader_t	 header1;
+	ConfigPageHeader_t	 header0;
 	DVPARAMETERS		 dv;
 	INTERNAL_CMD		 iocmd;
 	CONFIGPARMS		 cfg;
+	int			 dv_alloc = 0;
 	int			 rc, sz = 0;
 	int			 bufsize = 0;
 	int			 dataBufSize = 0;
@@ -6033,6 +6263,7 @@
 	char			 doFallback = 0;
 	char			 readPage0;
 	char			 bus, lun;
+	char			 inq0 = 0;
 
 	if (ioc->spi_data.sdp1length == 0)
 		return;
@@ -6078,6 +6309,16 @@
 	if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
 		iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
 
+	if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
+		/* Another GEM workaround. Check peripheral device type,
+		 * if PROCESSOR, quit DV.
+		 */
+		if (((pTarget->inq_data[0] & 0x1F) == 0x03) || ((pTarget->inq_data[0] & 0x1F) > 0x08)) {
+			pTarget->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
+			return;
+		}
+	}
+
 	/* Prep cfg structure
 	 */
 	cfg.pageAddr = (bus<<8) | id;
@@ -6089,10 +6330,6 @@
 	header0.PageLength = ioc->spi_data.sdp0length;
 	header0.PageNumber = 0;
 	header0.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
-	pcfg0Data = (SCSIDevicePage0_t *)pci_alloc_consistent(ioc->pcidev,
-				 header0.PageLength * 4, &cfg0_dma_addr);
-	if (!pcfg0Data)
-		return;
 
 	/* Prep SDP1 header
 	 */
@@ -6100,10 +6337,36 @@
 	header1.PageLength = ioc->spi_data.sdp1length;
 	header1.PageNumber = 1;
 	header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
-	pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
-				 header1.PageLength * 4, &cfg1_dma_addr);
-	if (!pcfg1Data)
-		goto target_done;
+
+	if (header0.PageLength & 1)
+		dv_alloc = (header0.PageLength * 4) + 4;
+
+	dv_alloc +=  (2048 + (header1.PageLength * 4));
+
+	pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
+	if (pDvBuf == NULL)
+		return;
+
+	sz = 0;
+	pbuf1 = (u8 *)pDvBuf;
+	buf1_dma = dvbuf_dma;
+	sz +=1024;
+
+	pbuf2 = (u8 *) (pDvBuf + sz);
+	buf2_dma = dvbuf_dma + sz;
+	sz +=1024;
+
+	pcfg0Data = (SCSIDevicePage0_t *) (pDvBuf + sz);
+	cfg0_dma_addr = dvbuf_dma + sz;
+	sz += header0.PageLength * 4;
+
+	/* 8-byte alignment
+	 */
+	if (header0.PageLength & 1)
+		sz += 4;
+
+	pcfg1Data = (SCSIDevicePage1_t *) (pDvBuf + sz);
+	cfg1_dma_addr = dvbuf_dma + sz;
 
 	/* Skip this ID? Set cfg.hdr to force config page write
 	 */
@@ -6164,11 +6427,6 @@
 	hd->pLocal = NULL;
 	readPage0 = 0;
 	sz = SCSI_STD_INQUIRY_BYTES;
-	pbuf1 = pci_alloc_consistent(ioc->pcidev, sz, &buf1_dma);
-	pbuf2 = pci_alloc_consistent(ioc->pcidev, sz, &buf2_dma);
-	if (!pbuf1 || !pbuf2)
-		goto target_done;
-
 	while (1) {
 		ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test.\n", ioc->name));
 		dv.cmd = MPT_SET_MIN;
@@ -6234,6 +6492,7 @@
 					cfg.physAddr = cfg0_dma_addr;
 					cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
 					cfg.dir = 0;
+
 					if (mpt_config(hd->ioc, &cfg) != 0)
 						goto target_done;
 
@@ -6277,12 +6536,13 @@
 			firstPass = 0;
 		}
 	}
-	/* Free pbuf2, but use pbuf1 for
-	 * acquiring the (echo) buffer size.
-	 */
-	pci_free_consistent(ioc->pcidev, sz, pbuf2, buf2_dma);
-	pbuf2 = NULL;
 	ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test completed OK.\n", ioc->name));
+	inq0 = (*pbuf1) & 0x1F;
+
+	/* Continue only for disks
+	 */
+	if (inq0 != 0)
+		goto target_done;
 
 	/* Start the Enhanced Test.
 	 * 0) issue TUR to clear out check conditions
@@ -6418,8 +6678,6 @@
 		else
 			dataBufSize = bufsize;
 	}
-	pci_free_consistent(ioc->pcidev, sz, pbuf1, buf1_dma);
-	pbuf1 = NULL;
 	sz = 0;
 	iocmd.flags &= ~MPT_ICFLAG_BUF_CAP;
 
@@ -6438,13 +6696,9 @@
 	ddvprintk((MYIOC_s_INFO_FMT "%s Buffer Capacity %d\n", ioc->name,
 		(iocmd.flags & MPT_ICFLAG_ECHO) ? "Echo" : " ", bufsize));
 
-	/* Allocate data buffers for write-read-compare test.
+	/* Data buffers for write-read-compare test max 1K.
 	 */
 	sz = MIN(bufsize, 1024);
-	pbuf1 = pci_alloc_consistent(ioc->pcidev, sz, &buf1_dma);
-	pbuf2 = pci_alloc_consistent(ioc->pcidev, sz, &buf2_dma);
-	if (!pbuf1 || !pbuf2)
-		goto target_done;
 
 	/* --- loop ----
 	 * On first pass, always issue a reserve.
@@ -6698,6 +6952,12 @@
 	/* Set if cfg1_dma_addr contents is valid
 	 */
 	if (cfg.hdr != NULL) {
+
+		/* If disk, not U320, disable QAS
+		 */
+		if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320))
+			hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
+
 		dv.cmd = MPT_SAVE;
 		mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
 
@@ -6720,25 +6980,8 @@
 
 	/* Done with the DV scan of the current target
 	 */
-	if (pcfg0Data) {
-		pci_free_consistent(ioc->pcidev, header0.PageLength * 4,
-						pcfg0Data, cfg0_dma_addr);
-	}
-
-	if (pcfg1Data) {
-		pci_free_consistent(ioc->pcidev, header1.PageLength * 4,
-						pcfg1Data, cfg1_dma_addr);
-	}
-
-	if (pbuf1) {
-		pci_free_consistent(ioc->pcidev, sz, pbuf1, buf1_dma);
-		pbuf1 = NULL;
-	}
-
-	if (pbuf2) {
-		pci_free_consistent(ioc->pcidev, sz, pbuf2, buf2_dma);
-		pbuf2 = NULL;
-	}
+	if (pDvBuf)
+		pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma);
 
 	ddvtprintk((MYIOC_s_INFO_FMT "DV Done. IOs outstanding = %d\n",
 			ioc->name, atomic_read(&queue_depth)));
@@ -6800,7 +7043,7 @@
 			}
 
 			/* Set the negotiation flags */
-			negoFlags = 0;
+			negoFlags = hd->ioc->spi_data.noQas;
 			if (!width)
 				negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
 
@@ -6947,6 +7190,7 @@
 			width = MPT_NARROW;
 			factor = MPT_ASYNC;
 		}
+		dv->max.flags |= MPT_TARGET_NO_NEGO_QAS;
 
 		dv->now.width = width;
 		dv->now.offset = offset;
@@ -6981,24 +7225,27 @@
 			pTarget->maxWidth = dv->now.width;
 			pTarget->maxOffset = dv->now.offset;
 			pTarget->minSyncFactor = dv->now.factor;
+			pTarget->negoFlags = dv->now.flags;
 		} else {
 			/* Preserv all flags, use
 			 * read-modify-write algorithm
 			 */
-			data = hd->ioc->spi_data.nvram[id];
+			if (hd->ioc->spi_data.nvram) {
+				data = hd->ioc->spi_data.nvram[id];
 
-			if (dv->now.width)
-				data &= ~MPT_NVRAM_WIDE_DISABLE;
-			else
-				data |= MPT_NVRAM_WIDE_DISABLE;
+				if (dv->now.width)
+					data &= ~MPT_NVRAM_WIDE_DISABLE;
+				else
+					data |= MPT_NVRAM_WIDE_DISABLE;
 
-			if (!dv->now.offset)
-				factor = MPT_ASYNC;
+				if (!dv->now.offset)
+					factor = MPT_ASYNC;
 
-			data &= ~MPT_NVRAM_SYNC_MASK;
-			data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK;
+				data &= ~MPT_NVRAM_SYNC_MASK;
+				data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK;
 
-			hd->ioc->spi_data.nvram[id] = data;
+				hd->ioc->spi_data.nvram[id] = data;
+			}
 		}
 		break;
 	}
@@ -7186,8 +7433,6 @@
 	unsigned long val;
 	int  c;
 
-	printk("KERN_WARNING: mptscsih_setup arg %s\n", str);
-
 	while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
 		char *pe;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/message/fusion/mptscsih.h linux-2.4.20/drivers/message/fusion/mptscsih.h
--- linux-2.4.19/drivers/message/fusion/mptscsih.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/message/fusion/mptscsih.h	2002-10-29 11:18:51.000000000 +0000
@@ -20,7 +20,7 @@
  *  (mailto:netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptscsih.h,v 1.16 2002/02/27 18:44:30 sralston Exp $
+ *  $Id: mptscsih.h,v 1.18 2002/06/06 15:32:52 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -73,7 +73,8 @@
  *	Try to keep these at 2^N-1
  */
 #define MPT_FC_CAN_QUEUE	63
-#define MPT_SCSI_CAN_QUEUE	31
+//#define MPT_SCSI_CAN_QUEUE	31
+#define MPT_SCSI_CAN_QUEUE	MPT_FC_CAN_QUEUE
 #define MPT_SCSI_CMD_PER_LUN	 7
 
 #define MPT_SCSI_SG_DEPTH	40
@@ -195,7 +196,7 @@
 extern	int		 x_scsi_abort(Scsi_Cmnd *);
 extern	int		 x_scsi_bus_reset(Scsi_Cmnd *);
 extern	int		 x_scsi_dev_reset(Scsi_Cmnd *);
-/*extern	int		 x_scsi_host_reset(Scsi_Cmnd *);*/
+extern	int		 x_scsi_host_reset(Scsi_Cmnd *);
 #else
 extern	int		 x_scsi_old_abort(Scsi_Cmnd *);
 extern	int		 x_scsi_old_reset(Scsi_Cmnd *, unsigned int);
@@ -212,6 +213,33 @@
 
 #ifdef MPT_SCSI_USE_NEW_EH
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
+
+#define MPT_SCSIHOST {						\
+	next:				NULL,			\
+	PROC_SCSI_DECL						\
+	name:				"MPT SCSI Host",	\
+	detect:				x_scsi_detect,		\
+	release:			x_scsi_release,		\
+	info:				x_scsi_info,		\
+	command:			NULL,			\
+	queuecommand:			x_scsi_queuecommand,	\
+	eh_strategy_handler:		NULL,			\
+	eh_abort_handler:		x_scsi_abort,		\
+	eh_device_reset_handler:	x_scsi_dev_reset,	\
+	eh_bus_reset_handler:		x_scsi_bus_reset,	\
+	eh_host_reset_handler:		x_scsi_host_reset,	\
+	bios_param:			x_scsi_bios_param,	\
+	can_queue:			MPT_SCSI_CAN_QUEUE,	\
+	this_id:			-1,			\
+	sg_tablesize:			MPT_SCSI_SG_DEPTH,	\
+	cmd_per_lun:			MPT_SCSI_CMD_PER_LUN,	\
+	unchecked_isa_dma:		0,			\
+	use_clustering:			ENABLE_CLUSTERING,	\
+}
+
+#else  /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) */
+
 #define MPT_SCSIHOST {						\
 	next:				NULL,			\
 	PROC_SCSI_DECL						\
@@ -236,7 +264,9 @@
 	use_new_eh_code:		1			\
 }
 
-#else
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) */
+
+#else /* MPT_SCSI_USE_NEW_EH */
 
 #define MPT_SCSIHOST {						\
 	next:				NULL,			\
@@ -257,7 +287,7 @@
 	unchecked_isa_dma:		0,			\
 	use_clustering:			ENABLE_CLUSTERING	\
 }
-#endif
+#endif  /* MPT_SCSI_USE_NEW_EH */
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/message/i2o/README.ioctl linux-2.4.20/drivers/message/i2o/README.ioctl
--- linux-2.4.19/drivers/message/i2o/README.ioctl	2000-06-19 20:30:55.000000000 +0000
+++ linux-2.4.20/drivers/message/i2o/README.ioctl	2002-10-29 11:18:48.000000000 +0000
@@ -318,7 +318,7 @@
    DESCRIPTION
 
    This function posts an ExecConfigValidate message to the controller
-   identified by iop. This message indicates that the the current
+   identified by iop. This message indicates that the current
    configuration is accepted. The iop changes the status of suspect drivers 
    to valid and may delete old drivers from its store.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/message/i2o/i2o_core.c linux-2.4.20/drivers/message/i2o/i2o_core.c
--- linux-2.4.19/drivers/message/i2o/i2o_core.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/message/i2o/i2o_core.c	2002-10-29 11:18:48.000000000 +0000
@@ -3390,8 +3390,9 @@
 	{
 		if(i2o_quiesce_controller(c))
 		{
-			printk(KERN_WARNING "i2o: Could not quiesce %s."  "
-				Verify setup on next system power up.\n", c->name);
+			printk(KERN_WARNING "i2o: Could not quiesce %s.\n"
+			       "Verify setup on next system power up.\n",
+			       c->name);
 		}
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/message/i2o/i2o_pci.c linux-2.4.20/drivers/message/i2o/i2o_pci.c
--- linux-2.4.19/drivers/message/i2o/i2o_pci.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/message/i2o/i2o_pci.c	2002-10-29 11:18:33.000000000 +0000
@@ -35,6 +35,7 @@
 
 static int dpt = 0;
 
+extern void i2o_sys_init(void);
 
 /**
  *	i2o_pci_dispose		-	Free bus specific resources
@@ -334,6 +335,11 @@
 			continue;
 		printk(KERN_INFO "i2o: I2O controller on bus %d at %d.\n",
 			dev->bus->number, dev->devfn);
+		if(pci_set_dma_mask(dev, 0xffffffff))
+		{
+			printk(KERN_WARNING "I2O controller on bus %d at %d : No suitable DMA available\n", dev->bus->number, dev->devfn);
+		 	continue;
+		}
 		pci_set_master(dev);
 		if(i2o_pci_install(dev)==0)
 			count++;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/mtd/devices/Config.in linux-2.4.20/drivers/mtd/devices/Config.in
--- linux-2.4.19/drivers/mtd/devices/Config.in	2001-10-04 22:13:18.000000000 +0000
+++ linux-2.4.20/drivers/mtd/devices/Config.in	2002-10-29 11:18:39.000000000 +0000
@@ -10,6 +10,9 @@
    bool '    PMC551 256M DRAM Bugfix' CONFIG_MTD_PMC551_BUGFIX
    bool '    PMC551 Debugging' CONFIG_MTD_PMC551_DEBUG
 fi
+if [ "$CONFIG_DECSTATION" = "y" ]; then
+   dep_tristate '  DEC MS02-NV NVRAM module support' CONFIG_MTD_MS02NV $CONFIG_MTD $CONFIG_DECSTATION
+fi
 dep_tristate '  Uncached system RAM' CONFIG_MTD_SLRAM $CONFIG_MTD
 if [ "$CONFIG_SA1100_LART" = "y" ]; then
   dep_tristate '  28F160xx flash driver for LART' CONFIG_MTD_LART $CONFIG_MTD
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/mtd/devices/Makefile linux-2.4.20/drivers/mtd/devices/Makefile
--- linux-2.4.19/drivers/mtd/devices/Makefile	2001-10-04 22:13:18.000000000 +0000
+++ linux-2.4.20/drivers/mtd/devices/Makefile	2002-10-29 11:18:31.000000000 +0000
@@ -18,6 +18,7 @@
 obj-$(CONFIG_MTD_DOCPROBE)	+= docprobe.o docecc.o
 obj-$(CONFIG_MTD_SLRAM)		+= slram.o
 obj-$(CONFIG_MTD_PMC551)	+= pmc551.o
+obj-$(CONFIG_MTD_MS02NV)	+= ms02-nv.o
 obj-$(CONFIG_MTD_MTDRAM)	+= mtdram.o
 obj-$(CONFIG_MTD_LART)		+= lart.o
 obj-$(CONFIG_MTD_BLKMTD)	+= blkmtd.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/mtd/devices/blkmtd.c linux-2.4.20/drivers/mtd/devices/blkmtd.c
--- linux-2.4.19/drivers/mtd/devices/blkmtd.c	2002-02-25 19:37:58.000000000 +0000
+++ linux-2.4.20/drivers/mtd/devices/blkmtd.c	2002-10-29 11:18:32.000000000 +0000
@@ -225,7 +225,7 @@
     return err;
   }
 
-  /* Pre 2.4.4 doesnt have space for the block list in the kiobuf */ 
+  /* Pre 2.4.4 doesn't have space for the block list in the kiobuf */ 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
   blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long));
   if(blocks == NULL) {
@@ -320,7 +320,7 @@
     return 0;
   }
 
-  /* Pre 2.4.4 doesnt have space for the block list in the kiobuf */ 
+  /* Pre 2.4.4 doesn't have space for the block list in the kiobuf */ 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
   blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long));
   if(blocks == NULL) {
@@ -360,7 +360,7 @@
       int max_sectors = KIO_MAX_SECTORS >> (item->rawdevice->sector_bits - 9);
       kdev_t dev = to_kdev_t(item->rawdevice->binding->bd_dev);
 
-      /* If we are writing to the last page on the device and it doesnt end
+      /* If we are writing to the last page on the device and it doesn't end
        * on a page boundary, subtract the number of sectors that dont exist.
        */
       if(item->rawdevice->partial_last_page && 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/mtd/devices/ms02-nv.c linux-2.4.20/drivers/mtd/devices/ms02-nv.c
--- linux-2.4.19/drivers/mtd/devices/ms02-nv.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/mtd/devices/ms02-nv.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,323 @@
+/*
+ *      Copyright (c) 2001 Maciej W. Rozycki
+ *
+ *      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.
+ */
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+#include <asm/dec/ioasic_addrs.h>
+#include <asm/dec/kn02.h>
+#include <asm/dec/kn03.h>
+#include <asm/io.h>
+#include <asm/paccess.h>
+
+#include "ms02-nv.h"
+
+
+static char version[] __initdata =
+        "ms02-nv.c: v.1.0.0  13 Aug 2001  Maciej W. Rozycki.\n";
+
+MODULE_AUTHOR("Maciej W. Rozycki <macro@ds2.pg.gda.pl>");
+MODULE_DESCRIPTION("DEC MS02-NV NVRAM module driver");
+MODULE_LICENSE("GPL");
+
+
+/*
+ * Addresses we probe for an MS02-NV at.  Modules may be located
+ * at any 8MB boundary within a 0MB up to 112MB range or at any 32MB
+ * boundary within a 0MB up to 448MB range.  We don't support a module
+ * at 0MB, though.
+ */
+static ulong ms02nv_addrs[] __initdata = {
+	0x07000000, 0x06800000, 0x06000000, 0x05800000, 0x05000000,
+	0x04800000, 0x04000000, 0x03800000, 0x03000000, 0x02800000,
+	0x02000000, 0x01800000, 0x01000000, 0x00800000
+};
+
+static const char ms02nv_name[] = "DEC MS02-NV NVRAM";
+static const char ms02nv_res_diag_ram[] = "Diagnostic RAM";
+static const char ms02nv_res_user_ram[] = "General-purpose RAM";
+static const char ms02nv_res_csr[] = "Control and status register";
+
+static struct mtd_info *root_ms02nv_mtd;
+
+
+static int ms02nv_read(struct mtd_info *mtd, loff_t from,
+			size_t len, size_t *retlen, u_char *buf)
+{
+	struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv;
+
+	if (from + len > mtd->size)
+		return -EINVAL;
+
+	memcpy(buf, mp->uaddr + from, len);
+	*retlen = len;
+
+	return 0;
+}
+
+static int ms02nv_write(struct mtd_info *mtd, loff_t to,
+			size_t len, size_t *retlen, const u_char *buf)
+{
+	struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv;
+
+	if (to + len > mtd->size)
+		return -EINVAL;
+
+	memcpy(mp->uaddr + to, buf, len);
+	*retlen = len;
+
+	return 0;
+}
+
+
+static inline uint ms02nv_probe_one(ulong addr)
+{
+	ms02nv_uint *ms02nv_diagp;
+	ms02nv_uint *ms02nv_magicp;
+	uint ms02nv_diag;
+	uint ms02nv_magic;
+	size_t size;
+
+	int err;
+
+	/*
+	 * The firmware writes MS02NV_ID at MS02NV_MAGIC and also
+	 * a diagnostic status at MS02NV_DIAG.
+	 */
+	ms02nv_diagp = (ms02nv_uint *)(KSEG1ADDR(addr + MS02NV_DIAG));
+	ms02nv_magicp = (ms02nv_uint *)(KSEG1ADDR(addr + MS02NV_MAGIC));
+	err = get_dbe(ms02nv_magic, ms02nv_magicp);
+	if (err)
+		return 0;
+	if (ms02nv_magic != MS02NV_ID)
+		return 0;
+
+	ms02nv_diag = *ms02nv_diagp;
+	size = (ms02nv_diag & MS02NV_DIAG_SIZE_MASK) << MS02NV_DIAG_SIZE_SHIFT;
+	if (size > MS02NV_CSR)
+		size = MS02NV_CSR;
+
+	return size;
+}
+
+static int __init ms02nv_init_one(ulong addr)
+{
+	struct mtd_info *mtd;
+	struct ms02nv_private *mp;
+	struct resource *mod_res;
+	struct resource *diag_res;
+	struct resource *user_res;
+	struct resource *csr_res;
+	ulong fixaddr;
+	size_t size, fixsize;
+
+	static int version_printed;
+
+	int ret = -ENODEV;
+
+	/* The module decodes 8MB of address space. */
+	mod_res = kmalloc(sizeof(*mod_res), GFP_KERNEL);
+	if (!mod_res)
+		return -ENOMEM;
+
+	memset(mod_res, 0, sizeof(*mod_res));
+	mod_res->name = ms02nv_name;
+	mod_res->start = addr;
+	mod_res->end = addr + MS02NV_SLOT_SIZE - 1;
+	mod_res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+	if (request_resource(&iomem_resource, mod_res) < 0)
+		goto err_out_mod_res;
+
+	size = ms02nv_probe_one(addr);
+	if (!size)
+		goto err_out_mod_res_rel;
+
+	if (!version_printed) {
+		printk(KERN_INFO "%s", version);
+		version_printed = 1;
+	}
+
+	ret = -ENOMEM;
+	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+	if (!mtd)
+		goto err_out_mod_res_rel;
+	memset(mtd, 0, sizeof(*mtd));
+	mp = kmalloc(sizeof(*mp), GFP_KERNEL);
+	if (!mp)
+		goto err_out_mtd;
+	memset(mp, 0, sizeof(*mp));
+
+	mtd->priv = mp;
+	mp->resource.module = mod_res;
+
+	/* Firmware's diagnostic NVRAM area. */
+	diag_res = kmalloc(sizeof(*diag_res), GFP_KERNEL);
+	if (!diag_res)
+		goto err_out_mp;
+
+	memset(diag_res, 0, sizeof(*diag_res));
+	diag_res->name = ms02nv_res_diag_ram;
+	diag_res->start = addr;
+	diag_res->end = addr + MS02NV_RAM - 1;
+	diag_res->flags = IORESOURCE_BUSY;
+	request_resource(mod_res, diag_res);
+
+	mp->resource.diag_ram = diag_res;
+
+	/* User-available general-purpose NVRAM area. */
+	user_res = kmalloc(sizeof(*user_res), GFP_KERNEL);
+	if (!user_res)
+		goto err_out_diag_res;
+
+	memset(user_res, 0, sizeof(*user_res));
+	user_res->name = ms02nv_res_user_ram;
+	user_res->start = addr + MS02NV_RAM;
+	user_res->end = addr + size - 1;
+	user_res->flags = IORESOURCE_BUSY;
+	request_resource(mod_res, user_res);
+
+	mp->resource.user_ram = user_res;
+
+	/* Control and status register. */
+	csr_res = kmalloc(sizeof(*csr_res), GFP_KERNEL);
+	if (!csr_res)
+		goto err_out_user_res;
+
+	memset(csr_res, 0, sizeof(*csr_res));
+	csr_res->name = ms02nv_res_csr;
+	csr_res->start = addr + MS02NV_CSR;
+	csr_res->end = addr + MS02NV_CSR + 3;
+	csr_res->flags = IORESOURCE_BUSY;
+	request_resource(mod_res, csr_res);
+
+	mp->resource.csr = csr_res;
+
+	mp->addr = phys_to_virt(addr);
+	mp->size = size;
+
+	/*
+	 * Hide the firmware's diagnostic area.  It may get destroyed
+	 * upon a reboot.  Take paging into account for mapping support.
+	 */
+	fixaddr = (addr + MS02NV_RAM + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+	fixsize = (size - (fixaddr - addr)) & ~(PAGE_SIZE - 1);
+	mp->uaddr = phys_to_virt(fixaddr);
+
+	mtd->type = MTD_RAM;
+	mtd->flags = MTD_CAP_RAM | MTD_XIP;
+	mtd->size = fixsize;
+	mtd->name = (char *)ms02nv_name;
+	mtd->module = THIS_MODULE;
+	mtd->read = ms02nv_read;
+	mtd->write = ms02nv_write;
+
+	ret = -EIO;
+	if (add_mtd_device(mtd)) {
+		printk(KERN_ERR
+			"ms02-nv: Unable to register MTD device, aborting!\n");
+		goto err_out_csr_res;
+	}
+
+	printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMB.\n",
+		mtd->index, ms02nv_name, addr, size >> 20);
+
+	mp->next = root_ms02nv_mtd;
+	root_ms02nv_mtd = mtd;
+
+	return 0;
+
+
+err_out_csr_res:
+	release_resource(csr_res);
+	kfree(csr_res);
+err_out_user_res:
+	release_resource(user_res);
+	kfree(user_res);
+err_out_diag_res:
+	release_resource(diag_res);
+	kfree(diag_res);
+err_out_mp:
+	kfree(mp);
+err_out_mtd:
+	kfree(mtd);
+err_out_mod_res_rel:
+	release_resource(mod_res);
+err_out_mod_res:
+	kfree(mod_res);
+	return ret;
+}
+
+static void __exit ms02nv_remove_one(void)
+{
+	struct mtd_info *mtd = root_ms02nv_mtd;
+	struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv;
+
+	root_ms02nv_mtd = mp->next;
+
+	del_mtd_device(mtd);
+
+	release_resource(mp->resource.csr);
+	kfree(mp->resource.csr);
+	release_resource(mp->resource.user_ram);
+	kfree(mp->resource.user_ram);
+	release_resource(mp->resource.diag_ram);
+	kfree(mp->resource.diag_ram);
+	release_resource(mp->resource.module);
+	kfree(mp->resource.module);
+	kfree(mp);
+	kfree(mtd);
+}
+
+
+static int __init ms02nv_init(void)
+{
+	volatile u32 *csr;
+	uint stride = 0;
+	int count = 0;
+	int i;
+
+	switch (mips_machtype) {
+	case MACH_DS5000_200:
+		csr = (volatile u32 *)KN02_CSR_ADDR;
+		if (*csr & KN02_CSR_BNK32M)
+			stride = 2;
+		break;
+	case MACH_DS5000_2X0:
+		csr = (volatile u32 *)KN03_MCR_BASE;
+		if (*csr & KN03_MCR_BNK32M)
+			stride = 2;
+		break;
+	default:
+		return -ENODEV;
+		break;
+	}
+
+	for (i = 0; i < (sizeof(ms02nv_addrs) / sizeof(*ms02nv_addrs)); i++)
+		if (!ms02nv_init_one(ms02nv_addrs[i] << stride))
+			count++;
+
+	return (count > 0) ? 0 : -ENODEV;
+}
+
+static void __exit ms02nv_cleanup(void)
+{
+	while (root_ms02nv_mtd)
+		ms02nv_remove_one();
+}
+
+
+module_init(ms02nv_init);
+module_exit(ms02nv_cleanup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/mtd/devices/ms02-nv.h linux-2.4.20/drivers/mtd/devices/ms02-nv.h
--- linux-2.4.19/drivers/mtd/devices/ms02-nv.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/mtd/devices/ms02-nv.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,43 @@
+/*
+ *      Copyright (c) 2001 Maciej W. Rozycki
+ *
+ *      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.
+ */
+
+#include <linux/ioport.h>
+#include <linux/mtd/mtd.h>
+
+/* MS02-NV iomem register offsets. */
+#define MS02NV_CSR		0x400000	/* control & status register */
+
+/* MS02-NV memory offsets. */
+#define MS02NV_DIAG		0x0003f8	/* diagnostic status */
+#define MS02NV_MAGIC		0x0003fc	/* MS02-NV magic ID */
+#define MS02NV_RAM		0x000400	/* general-purpose RAM start */
+
+/* MS02-NV diagnostic status constants. */
+#define MS02NV_DIAG_SIZE_MASK	0xf0		/* RAM size mask */
+#define MS02NV_DIAG_SIZE_SHIFT	0x10		/* RAM size shift (left) */
+
+/* MS02-NV general constants. */
+#define MS02NV_ID		0x03021966	/* MS02-NV magic ID value */
+#define MS02NV_SLOT_SIZE	0x800000	/* size of the address space
+						   decoded by the module */
+
+typedef volatile u32 ms02nv_uint;
+
+struct ms02nv_private {
+	struct mtd_info *next;
+	struct {
+		struct resource *module;
+		struct resource *diag_ram;
+		struct resource *user_ram;
+		struct resource *csr;
+	} resource;
+	u_char *addr;
+	size_t size;
+	u_char *uaddr;
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/mtd/ftl.c linux-2.4.20/drivers/mtd/ftl.c
--- linux-2.4.19/drivers/mtd/ftl.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/mtd/ftl.c	2002-10-29 11:18:35.000000000 +0000
@@ -26,7 +26,7 @@
     rights and limitations under the License.
 
     The initial developer of the original code is David A. Hinds
-    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
@@ -1455,5 +1455,5 @@
 
 
 MODULE_LICENSE("Dual MPL/GPL");
-MODULE_AUTHOR("David Hinds <dhinds@sonic.net>");
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
 MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices and M-Systems DiskOnChip 1000");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/mtd/maps/Config.in linux-2.4.20/drivers/mtd/maps/Config.in
--- linux-2.4.19/drivers/mtd/maps/Config.in	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/mtd/maps/Config.in	2002-10-29 11:18:48.000000000 +0000
@@ -46,9 +46,11 @@
 if [ "$CONFIG_MIPS" = "y" ]; then
    dep_tristate '  Pb1000 boot flash device' CONFIG_MTD_PB1000 $CONFIG_MIPS_PB1000
    dep_tristate '  Pb1500 MTD support' CONFIG_MTD_PB1500 $CONFIG_MIPS_PB1500
-   if [ "$CONFIG_MTD_PB1500" = "y" -o "$CONFIG_MTD_PB1500" = "m" ]; then
-      bool '  Pb1500 boot flash device' CONFIG_MTD_PB1500_BOOT 
-      bool '  Pb1500 user flash device (2nd 32MB bank)' CONFIG_MTD_PB1500_USER
+   dep_tristate '  Pb1100 MTD support' CONFIG_MTD_PB1100 $CONFIG_MIPS_PB1100
+   if [ "$CONFIG_MTD_PB1500" = "y" -o "$CONFIG_MTD_PB1500" = "m" \
+	-o "$CONFIG_MTD_PB1100" = "y" -o "$CONFIG_MTD_PB1100" = "m" ]; then
+      bool '  Pb1[015]00 boot flash device' CONFIG_MTD_PB1500_BOOT 
+      bool '  Pb1[015]00 user flash device (2nd 32MB bank)' CONFIG_MTD_PB1500_USER
    fi
    dep_tristate '  Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board' CONFIG_MTD_CSTM_MIPS_IXX $CONFIG_MTD_CFI $CONFIG_MTD_JEDEC $CONFIG_MTD_PARTITIONS 
    if [ "$CONFIG_MTD_CSTM_MIPS_IXX" = "y" -o "$CONFIG_MTD_CSTM_MIPS_IXX" = "m" ]; then
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/mtd/maps/Makefile linux-2.4.20/drivers/mtd/maps/Makefile
--- linux-2.4.19/drivers/mtd/maps/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/mtd/maps/Makefile	2002-10-29 11:18:30.000000000 +0000
@@ -37,7 +37,8 @@
 obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
 obj-$(CONFIG_MTD_PCI)		+= pci.o
 obj-$(CONFIG_MTD_PB1000)        += pb1xxx-flash.o
+obj-$(CONFIG_MTD_PB1100)        += pb1xxx-flash.o
 obj-$(CONFIG_MTD_PB1500)        += pb1xxx-flash.o
-obj-$(CONFIG_MTD_AUTCPU12)      += autcpu12-nvram.o
+obj-$(CONFIG_MTD_AUTCPU12)	+= autcpu12-nvram.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/mtd/maps/pb1xxx-flash.c linux-2.4.20/drivers/mtd/maps/pb1xxx-flash.c
--- linux-2.4.19/drivers/mtd/maps/pb1xxx-flash.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/mtd/maps/pb1xxx-flash.c	2002-10-29 11:18:35.000000000 +0000
@@ -3,7 +3,7 @@
  * 
  * (C) 2001 Pete Popov <ppopov@mvista.com>
  * 
- * $Id: pb1xxx-flash.c,v 1.2 2002/02/14 19:36:45 ppopov Exp $
+ * $Id: pb1xxx-flash.c,v 1.5 2002/02/01 23:08:50 ppopov Exp $
  */
 
 #include <linux/config.h>
@@ -127,7 +127,7 @@
         }
 };
 
-#elif defined(CONFIG_MIPS_PB1500)
+#elif defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
 
 static unsigned char flash_buswidth = 4;
 #if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/3c503.c linux-2.4.20/drivers/net/3c503.c
--- linux-2.4.19/drivers/net/3c503.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/3c503.c	2002-10-29 11:18:49.000000000 +0000
@@ -512,6 +512,7 @@
 
     if (dev->mem_start) {       /* Use the shared memory. */
 	isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+	hdr->count = le16_to_cpu(hdr->count);
 	return;
     }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/3c505.c linux-2.4.20/drivers/net/3c505.c
--- linux-2.4.19/drivers/net/3c505.c	2002-02-25 19:37:58.000000000 +0000
+++ linux-2.4.20/drivers/net/3c505.c	2002-10-29 11:18:40.000000000 +0000
@@ -1397,7 +1397,7 @@
 	int timeout;
 	int addr = dev->base_addr;
 	const char *name = dev->name;
-	long flags;
+	unsigned long flags;
 	byte orig_HSR;
 
 	if (!request_region(addr, ELP_IO_EXTENT, "3c505"))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/3c509.c linux-2.4.20/drivers/net/3c509.c
--- linux-2.4.19/drivers/net/3c509.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/3c509.c	2002-10-29 11:18:32.000000000 +0000
@@ -49,11 +49,13 @@
 			- Power Management support
                 v1.18c 1Mar2002 David Ruggiero <jdr@farfalle.com>
                         - Full duplex support
-*/
+		v1.19  16Oct2002 Zwane Mwaikambo <zwane@linuxpower.ca>
+			- Additional ethtool features
+  */
 
 #define DRV_NAME	"3c509"
-#define DRV_VERSION	"1.18c"
-#define DRV_RELDATE	"1Mar2002"
+#define DRV_VERSION	"1.19"
+#define DRV_RELDATE	"16Oct2002"
 
 /* A few values that may be tweaked. */
 
@@ -140,9 +142,11 @@
 #define TX_STATUS 	0x0B
 #define TX_FREE		0x0C		/* Remaining free bytes in Tx buffer. */
 
+#define WN0_CONF_CTRL	0x04		/* Window 0: Configuration control register */
+#define WN0_ADDR_CONF	0x06		/* Window 0: Address configuration register */
 #define WN0_IRQ		0x08		/* Window 0: Set IRQ line in bits 12-15. */
 #define WN4_MEDIA	0x0A		/* Window 4: Various transcvr/media bits. */
-#define  MEDIA_TP	0x00C0		/* Enable link beat and jabber for 10baseT. */
+#define	MEDIA_TP	0x00C0		/* Enable link beat and jabber for 10baseT. */
 #define WN4_NETDIAG	0x06		/* Window 4: Net diagnostic */
 #define FD_ENABLE	0x8000		/* Enable full-duplex ("external loopback") */  
 
@@ -230,12 +234,10 @@
 };
 
 MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);
-MODULE_LICENSE("GPL");
-
 
 static u16 el3_isapnp_phys_addr[8][3];
-#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */
 static int nopnp;
+#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */
 
 int __init el3_probe(struct net_device *dev, int card_idx)
 {
@@ -696,7 +698,7 @@
 	outw(0x00, ioaddr + TX_FIFO);
 	/* ... and the packet rounded to a doubleword. */
 #ifdef  __powerpc__
-	outsl_unswapped(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+	outsl_ns(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
 #else
 	outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
 #endif
@@ -907,7 +909,7 @@
 
 				/* 'skb->data' points to the start of sk_buff data area. */
 #ifdef  __powerpc__
-				insl_unswapped(ioaddr+RX_FIFO, skb_put(skb,pkt_len),
+				insl_ns(ioaddr+RX_FIFO, skb_put(skb,pkt_len),
 							   (pkt_len + 3) >> 2);
 #else
 				insl(ioaddr + RX_FIFO, skb_put(skb,pkt_len),
@@ -985,6 +987,119 @@
 	return 0;
 }
 
+static int 
+el3_link_ok(struct net_device *dev)
+{
+	int ioaddr = dev->base_addr;
+	u16 tmp;
+
+	EL3WINDOW(4);
+	tmp = inw(ioaddr + WN4_MEDIA);
+	EL3WINDOW(1);
+	return tmp & (1<<11);
+}
+
+static int
+el3_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	u16 tmp;
+	int ioaddr = dev->base_addr;
+	
+	EL3WINDOW(0);
+	/* obtain current tranceiver via WN4_MEDIA? */	
+	tmp = inw(ioaddr + WN0_ADDR_CONF);
+	ecmd->transceiver = XCVR_INTERNAL;
+	switch (tmp >> 14) {
+	case 0:
+		ecmd->port = PORT_TP;
+		break;
+	case 1:
+		ecmd->port = PORT_AUI;
+		ecmd->transceiver = XCVR_EXTERNAL;
+		break;
+	case 3:
+		ecmd->port = PORT_BNC;
+	default:
+		break;
+	}
+
+	ecmd->duplex = DUPLEX_HALF;
+	ecmd->supported = 0;
+	tmp = inw(ioaddr + WN0_CONF_CTRL);
+	if (tmp & (1<<13))
+		ecmd->supported |= SUPPORTED_AUI;
+	if (tmp & (1<<12))
+		ecmd->supported |= SUPPORTED_BNC;
+	if (tmp & (1<<9)) {
+		ecmd->supported |= SUPPORTED_TP | SUPPORTED_10baseT_Half |
+				SUPPORTED_10baseT_Full;	/* hmm... */
+		EL3WINDOW(4);
+		tmp = inw(ioaddr + WN4_NETDIAG);
+		if (tmp & FD_ENABLE)
+			ecmd->duplex = DUPLEX_FULL;
+	}
+
+	ecmd->speed = SPEED_10;
+	EL3WINDOW(1);
+	return 0;
+}
+
+static int
+el3_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	u16 tmp;
+	int ioaddr = dev->base_addr;
+
+	if (ecmd->speed != SPEED_10)
+		return -EINVAL;
+	if ((ecmd->duplex != DUPLEX_HALF) && (ecmd->duplex != DUPLEX_FULL))
+		return -EINVAL;
+	if ((ecmd->transceiver != XCVR_INTERNAL) && (ecmd->transceiver != XCVR_EXTERNAL))
+		return -EINVAL;
+
+	/* change XCVR type */
+	EL3WINDOW(0);
+	tmp = inw(ioaddr + WN0_ADDR_CONF);
+	switch (ecmd->port) {
+	case PORT_TP:
+		tmp &= ~(3<<14);
+		dev->if_port = 0;
+		break;
+	case PORT_AUI:
+		tmp |= (1<<14);
+		dev->if_port = 1;
+		break;
+	case PORT_BNC:
+		tmp |= (3<<14);
+		dev->if_port = 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	outw(tmp, ioaddr + WN0_ADDR_CONF);
+	if (dev->if_port == 3) {
+		/* fire up the DC-DC convertor if BNC gets enabled */
+		tmp = inw(ioaddr + WN0_ADDR_CONF);
+		if (tmp & (3 << 14)) {
+			outw(StartCoax, ioaddr + EL3_CMD);
+			udelay(800);
+		} else
+			return -EIO;
+	}
+
+	EL3WINDOW(4);
+	tmp = inw(ioaddr + WN4_NETDIAG);
+	if (ecmd->duplex == DUPLEX_FULL)
+		tmp |= FD_ENABLE;
+	else
+		tmp &= ~FD_ENABLE;
+	outw(tmp, ioaddr + WN4_NETDIAG);
+	EL3WINDOW(1);
+
+	return 0;
+}
+
 /**
  * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
  * @dev: network interface on which out-of-band action is to be performed
@@ -993,9 +1108,11 @@
  * Process the various commands of the SIOCETHTOOL interface.
  */
 
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static int
+netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
 {
 	u32 ethcmd;
+	struct el3_private *lp = dev->priv;
 
 	/* dev_ioctl() in ../../net/core/dev.c has already checked
 	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
@@ -1014,6 +1131,41 @@
 		return 0;
 	}
 
+	/* get settings */
+	case ETHTOOL_GSET: {
+		int ret;
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&lp->lock);
+		ret = el3_netdev_get_ecmd(dev, &ecmd);
+		spin_unlock_irq(&lp->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return ret;
+	}
+
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int ret;
+		struct ethtool_cmd ecmd;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&lp->lock);
+		ret = el3_netdev_set_ecmd(dev, &ecmd);
+		spin_unlock_irq(&lp->lock);
+		return ret;
+	}
+
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = { ETHTOOL_GLINK };
+		spin_lock_irq(&lp->lock);
+		edata.data = el3_link_ok(dev);
+		spin_unlock_irq(&lp->lock);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
 	/* get message-level */
 	case ETHTOOL_GMSGLVL: {
 		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
@@ -1047,7 +1199,8 @@
  * Process the various out-of-band ioctls passed to this driver.
  */
 
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+static int
+netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	int rc = 0;
 
@@ -1064,7 +1217,8 @@
 	return rc;
 }
 
-static void el3_down(struct net_device *dev)
+static void
+el3_down(struct net_device *dev)
 {
 	int ioaddr = dev->base_addr;
 
@@ -1081,7 +1235,7 @@
 		/* Turn off thinnet power.  Green! */
 		outw(StopCoax, ioaddr + EL3_CMD);
 	else if (dev->if_port == 0) {
-		/* Disable link beat and jabber, if_port may change ere next open(). */
+		/* Disable link beat and jabber, if_port may change here next open(). */
 		EL3WINDOW(4);
 		outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA);
 	}
@@ -1091,7 +1245,8 @@
 	update_stats(dev);
 }
 
-static void el3_up(struct net_device *dev)
+static void
+el3_up(struct net_device *dev)
 {
 	int i, sw_info, net_diag;
 	int ioaddr = dev->base_addr;
@@ -1180,7 +1335,8 @@
 /* Power Management support functions */
 #ifdef CONFIG_PM
 
-static int el3_suspend(struct pm_dev *pdev)
+static int
+el3_suspend(struct pm_dev *pdev)
 {
 	unsigned long flags;
 	struct net_device *dev;
@@ -1206,7 +1362,8 @@
 	return 0;
 }
 
-static int el3_resume(struct pm_dev *pdev)
+static int
+el3_resume(struct pm_dev *pdev)
 {
 	unsigned long flags;
 	struct net_device *dev;
@@ -1232,7 +1389,8 @@
 	return 0;
 }
 
-static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data)
+static int
+el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data)
 {
 	switch (rqst) {
 		case PM_SUSPEND:
@@ -1265,6 +1423,7 @@
 MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)");
 #endif	/* CONFIG_ISAPNP */
 MODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B) ISA/PnP ethernet driver");
+MODULE_LICENSE("GPL");
 
 int
 init_module(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/3c59x.c linux-2.4.20/drivers/net/3c59x.c
--- linux-2.4.19/drivers/net/3c59x.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/net/3c59x.c	2002-10-29 11:18:31.000000000 +0000
@@ -1444,11 +1444,14 @@
 		/* Read BMSR (reg1) only to clear old status. */
 		mii_reg1 = mdio_read(dev, vp->phys[0], 1);
 		mii_reg5 = mdio_read(dev, vp->phys[0], 5);
-		if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000)
-			;					/* No MII device or no link partner report */
-		else if ((mii_reg5 & 0x0100) != 0	/* 100baseTx-FD */
+		if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000) {
+			netif_carrier_off(dev); /* No MII device or no link partner report */
+		} else {
+			if ((mii_reg5 & 0x0100) != 0	/* 100baseTx-FD */
 				 || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */
-			vp->full_duplex = 1;
+				vp->full_duplex = 1;
+			netif_carrier_on(dev);
+		}
 		vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0);
 		if (vortex_debug > 1)
 			printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x,"
@@ -1651,13 +1654,16 @@
 	switch (dev->if_port) {
 	case XCVR_10baseT:  case XCVR_100baseTx:  case XCVR_100baseFx:
 		if (media_status & Media_LnkBeat) {
+			netif_carrier_on(dev);
 			ok = 1;
 			if (vortex_debug > 1)
 				printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n",
 					   dev->name, media_tbl[dev->if_port].name, media_status);
-		} else if (vortex_debug > 1)
+		} else if (vortex_debug > 1) {
+			netif_carrier_off(dev);
 			printk(KERN_DEBUG "%s: Media %s has no link beat, %x.\n",
 				   dev->name, media_tbl[dev->if_port].name, media_status);
+		}
 		break;
 	case XCVR_MII: case XCVR_NWAY:
 		{
@@ -1666,7 +1672,7 @@
 			if (vortex_debug > 2)
 				printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
 					dev->name, mii_status);
-			if (mii_status & 0x0004) {
+			if (mii_status & BMSR_LSTATUS) {
 				int mii_reg5 = mdio_read(dev, vp->phys[0], 5);
 				if (! vp->force_fd  &&  mii_reg5 != 0xffff) {
 					int duplex = (mii_reg5&0x0100) ||
@@ -1688,6 +1694,9 @@
 						/* AKPM: bug: should reset Tx and Rx after setting Duplex.  Page 180 */
 					}
 				}
+				netif_carrier_on(dev);
+			} else {
+				netif_carrier_off(dev);
 			}
 		}
 		break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/7990.c linux-2.4.20/drivers/net/7990.c
--- linux-2.4.19/drivers/net/7990.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/7990.c	2002-10-29 11:18:49.000000000 +0000
@@ -569,7 +569,7 @@
         volatile u16 *mcast_table = (u16 *)&ib->filter;
         struct dev_mc_list *dmi=dev->mc_list;
         char *addrs;
-        int i, j, bit, byte;
+        int i;
         u32 crc;
         
         /* set all multicast bits */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/8139cp.c linux-2.4.20/drivers/net/8139cp.c
--- linux-2.4.19/drivers/net/8139cp.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/8139cp.c	2002-10-29 11:18:40.000000000 +0000
@@ -18,21 +18,21 @@
 
 	See the file COPYING in this distribution for more information.
 
+	Contributors:
+	
+		Wake-on-LAN support - Felipe Damasio <felipewd@terra.com.br>
+		PCI suspend/resume  - Felipe Damasio <felipewd@terra.com.br>
+		LinkChg interrupt   - Felipe Damasio <felipewd@terra.com.br>
+			
 	TODO, in rough priority order:
+	* Test Tx checksumming thoroughly
 	* dev->tx_timeout
-	* LinkChg interrupt
-	* Support forcing media type with a module parameter,
-	  like dl2k.c/sundance.c
-	* Implement PCI suspend/resume
 	* Constants (module parms?) for Rx work limit
-	* support 64-bit PCI DMA
 	* Complete reset on PciErr
 	* Consider Rx interrupt mitigation using TimerIntr
 	* Implement 8139C+ statistics dump; maybe not...
 	  h/w stats can be reset only by software reset
-	* Tx checksumming
 	* Handle netif_rx return value
-	* ETHTOOL_GREGS, ETHTOOL_[GS]WOL,
 	* Investigate using skb->priority with h/w VLAN priority
 	* Investigate using High Priority Tx Queue with skb->priority
 	* Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error
@@ -41,12 +41,14 @@
 	  Tx descriptor bit
 	* The real minimum of CP_MIN_MTU is 4 bytes.  However,
 	  for this to be supported, one must(?) turn on packet padding.
+	* Support 8169 GMII
+	* Support external MII transceivers
 
  */
 
 #define DRV_NAME		"8139cp"
-#define DRV_VERSION		"0.0.7"
-#define DRV_RELDATE		"Feb 27, 2002"
+#define DRV_VERSION		"0.3.0"
+#define DRV_RELDATE		"Sep 29, 2002"
 
 
 #include <linux/config.h>
@@ -62,9 +64,17 @@
 #include <linux/mii.h>
 #include <linux/if_vlan.h>
 #include <linux/crc32.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
+/* experimental TX checksumming feature enable/disable */
+#undef CP_TX_CHECKSUM
+
+/* VLAN tagging feature enable/disable */
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #define CP_VLAN_TAG_USED 1
 #define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \
@@ -77,7 +87,7 @@
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
-KERN_INFO DRV_NAME " 10/100 PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n";
+KERN_INFO DRV_NAME ": 10/100 PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n";
 
 MODULE_AUTHOR("Jeff Garzik <jgarzik@mandrakesoft.com>");
 MODULE_DESCRIPTION("RealTek RTL-8139C+ series 10/100 PCI Ethernet driver");
@@ -85,25 +95,34 @@
 
 static int debug = -1;
 MODULE_PARM (debug, "i");
-MODULE_PARM_DESC (debug, "8139cp bitmapped message enable number");
+MODULE_PARM_DESC (debug, "8139cp: bitmapped message enable number");
 
 /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
    The RTL chips use a 64 element hash table based on the Ethernet CRC.  */
 static int multicast_filter_limit = 32;
 MODULE_PARM (multicast_filter_limit, "i");
-MODULE_PARM_DESC (multicast_filter_limit, "8139cp maximum number of filtered multicast addresses");
+MODULE_PARM_DESC (multicast_filter_limit, "8139cp: maximum number of filtered multicast addresses");
 
 #define PFX			DRV_NAME ": "
 
+#ifndef TRUE
+#define FALSE 0
+#define TRUE (!FALSE)
+#endif
+
 #define CP_DEF_MSG_ENABLE	(NETIF_MSG_DRV		| \
 				 NETIF_MSG_PROBE 	| \
 				 NETIF_MSG_LINK)
+#define CP_NUM_STATS		14	/* struct cp_dma_stats, plus one */
+#define CP_STATS_SIZE		64	/* size in bytes of DMA stats block */
 #define CP_REGS_SIZE		(0xff + 1)
+#define CP_REGS_VER		1		/* version 1 */
 #define CP_RX_RING_SIZE		64
 #define CP_TX_RING_SIZE		64
 #define CP_RING_BYTES		\
 		((sizeof(struct cp_desc) * CP_RX_RING_SIZE) +	\
-		(sizeof(struct cp_desc) * CP_TX_RING_SIZE))
+		 (sizeof(struct cp_desc) * CP_TX_RING_SIZE) +	\
+		 CP_STATS_SIZE)
 #define NEXT_TX(N)		(((N) + 1) & (CP_TX_RING_SIZE - 1))
 #define NEXT_RX(N)		(((N) + 1) & (CP_RX_RING_SIZE - 1))
 #define TX_BUFFS_AVAIL(CP)					\
@@ -132,6 +151,7 @@
 	/* NIC register offsets */
 	MAC0		= 0x00,	/* Ethernet hardware address. */
 	MAR0		= 0x08,	/* Multicast filter. */
+	StatsAddr	= 0x10,	/* 64-bit start addr of 64-byte DMA stats blk */
 	TxRingAddr	= 0x20, /* 64-bit start addr of Tx ring */
 	HiTxRingAddr	= 0x28, /* 64-bit start addr of high priority Tx ring */
 	Cmd		= 0x37, /* Command register */
@@ -152,7 +172,9 @@
 	NWayExpansion	= 0x6A, /* MII Expansion */
 	Config5		= 0xD8,	/* Config5 */
 	TxPoll		= 0xD9,	/* Tell chip to check Tx descriptors for work */
+	RxMaxSize	= 0xDA, /* Max size of an Rx packet (8169 only) */
 	CpCmd		= 0xE0, /* C+ Command register (C+ mode only) */
+	IntrMitigate	= 0xE2,	/* rx/tx interrupt mitigation control */
 	RxRingAddr	= 0xE4, /* 64-bit start addr of Rx ring */
 	TxThresh	= 0xEC, /* Early Tx threshold */
 	OldRxBufAddr	= 0x30, /* DMA address of Rx ring buffer (C mode) */
@@ -176,8 +198,8 @@
 	NormalTxPoll	= (1 << 6),  /* One or more normal Tx packets to send */
 	PID1		= (1 << 17), /* 2 protocol id bits:  0==non-IP, */
 	PID0		= (1 << 16), /* 1==UDP/IP, 2==TCP/IP, 3==IP */
-	RxProtoTCP	= 2,
-	RxProtoUDP	= 1,
+	RxProtoTCP	= 1,
+	RxProtoUDP	= 2,
 	RxProtoIP	= 3,
 	TxFIFOUnder	= (1 << 25), /* Tx FIFO underrun */
 	TxOWC		= (1 << 22), /* Tx Out-of-window collision */
@@ -192,6 +214,9 @@
 	RxErrLong	= (1 << 21), /* Rx error, packet > 4096 bytes */
 	RxErrFIFO	= (1 << 22), /* Rx error, FIFO overflowed, pkt bad */
 
+	/* StatsAddr register */
+	DumpStats	= (1 << 3),  /* Begin stats dump */
+
 	/* RxConfig register */
 	RxCfgFIFOShift	= 13,	     /* Shift, to get Rx FIFO thresh value */
 	RxCfgDMAShift	= 8,	     /* Shift, to get Rx Max DMA value */
@@ -230,6 +255,7 @@
 	/* C+ mode command register */
 	RxVlanOn	= (1 << 6),  /* Rx VLAN de-tagging enable */
 	RxChkSum	= (1 << 5),  /* Rx checksum offload enable */
+	PCIDAC		= (1 << 4),  /* PCI Dual Address Cycle (64-bit PCI) */
 	PCIMulRW	= (1 << 3),  /* Enable PCI read/write multiple */
 	CpRxOn		= (1 << 1),  /* Rx mode enable */
 	CpTxOn		= (1 << 0),  /* Tx mode enable */
@@ -248,12 +274,23 @@
 
 	/* Config1 register */
 	DriverLoaded	= (1 << 5),  /* Software marker, driver is loaded */
+	LWACT           = (1 << 4),  /* LWAKE active mode */
 	PMEnable	= (1 << 0),  /* Enable various PM features of chip */
 
 	/* Config3 register */
 	PARMEnable	= (1 << 6),  /* Enable auto-loading of PHY parms */
+	MagicPacket     = (1 << 5),  /* Wake up when receives a Magic Packet */
+	LinkUp          = (1 << 4),  /* Wake up when the cable connection is re-established */
+
+	/* Config4 register */
+	LWPTN           = (1 << 1),  /* LWAKE Pattern */
+	LWPME           = (1 << 4),  /* LANWAKE vs PMEB */
 
 	/* Config5 register */
+	BWF             = (1 << 6),  /* Accept Broadcast wakeup frame */
+	MWF             = (1 << 5),  /* Accept Multicast wakeup frame */
+	UWF             = (1 << 4),  /* Accept Unicast wakeup frame */
+	LANWake         = (1 << 1),  /* Enable LANWake signal */
 	PMEStatus	= (1 << 0),  /* PME status can be reset by PCI RST# */
 };
 
@@ -269,8 +306,7 @@
 struct cp_desc {
 	u32		opts1;
 	u32		opts2;
-	u32		addr_lo;
-	u32		addr_hi;
+	u64		addr;
 };
 
 struct ring_info {
@@ -279,6 +315,22 @@
 	unsigned		frag;
 };
 
+struct cp_dma_stats {
+	u64			tx_ok;
+	u64			rx_ok;
+	u64			tx_err;
+	u32			rx_err;
+	u16			rx_fifo;
+	u16			frame_align;
+	u32			tx_ok_1col;
+	u32			tx_ok_mcol;
+	u64			rx_ok_phys;
+	u64			rx_ok_bcast;
+	u32			rx_ok_mcast;
+	u16			tx_abort;
+	u16			tx_underrun;
+} __attribute__((packed));
+
 struct cp_extra_stats {
 	unsigned long		rx_frags;
 };
@@ -307,12 +359,19 @@
 
 	struct net_device_stats net_stats;
 	struct cp_extra_stats	cp_stats;
+	struct cp_dma_stats	*nic_stats;
+	dma_addr_t		nic_stats_dma;
 
 	struct pci_dev		*pdev;
 	u32			rx_config;
 
 	struct sk_buff		*frag_skb;
 	unsigned		dropping_frag : 1;
+	unsigned		pci_using_dac : 1;
+	unsigned int		board_type;
+
+	unsigned int		wol_enabled : 1; /* Is Wake-on-LAN enabled? */
+	u32			power_state[16];
 
 	struct mii_if_info	mii_if;
 };
@@ -341,14 +400,52 @@
 static void cp_tx (struct cp_private *cp);
 static void cp_clean_rings (struct cp_private *cp);
 
+enum board_type {
+	RTL8139Cp,
+	RTL8169,
+};
+
+static struct cp_board_info {
+	const char *name;
+} cp_board_tbl[] __devinitdata = {
+	/* RTL8139Cp */
+	{ "RTL-8139C+" },
+
+	/* RTL8169 */
+	{ "RTL-8169" },
+};
 
 static struct pci_device_id cp_pci_tbl[] __devinitdata = {
 	{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139Cp },
+#if 0
+	{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8169,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8169 },
+#endif
 	{ },
 };
 MODULE_DEVICE_TABLE(pci, cp_pci_tbl);
 
+static struct {
+	const char str[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+	{ "tx_ok" },
+	{ "rx_ok" },
+	{ "tx_err" },
+	{ "rx_err" },
+	{ "rx_fifo" },
+	{ "frame_align" },
+	{ "tx_ok_1col" },
+	{ "tx_ok_mcol" },
+	{ "rx_ok_phys" },
+	{ "rx_ok_bcast" },
+	{ "rx_ok_mcast" },
+	{ "tx_abort" },
+	{ "tx_underrun" },
+	{ "rx_frags" },
+};
+
+
 static inline void cp_set_rxbufsize (struct cp_private *cp)
 {
 	unsigned int mtu = cp->dev->mtu;
@@ -545,13 +642,13 @@
 		cp_rx_skb(cp, skb, desc);
 
 rx_next:
+		cp->rx_ring[rx_tail].opts2 = 0;
+		cp->rx_ring[rx_tail].addr = cpu_to_le64(mapping);
 		if (rx_tail == (CP_RX_RING_SIZE - 1))
 			desc->opts1 = cpu_to_le32(DescOwn | RingEnd |
 						  cp->rx_buf_sz);
 		else
 			desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz);
-		cp->rx_ring[rx_tail].opts2 = 0;
-		cp->rx_ring[rx_tail].addr_lo = cpu_to_le32(mapping);
 		rx_tail = NEXT_RX(rx_tail);
 	}
 
@@ -575,14 +672,16 @@
 		printk(KERN_DEBUG "%s: intr, status %04x cmd %02x cpcmd %04x\n",
 		        dev->name, status, cpr8(Cmd), cpr16(CpCmd));
 
+	cpw16_f(IntrStatus, status);
+
 	spin_lock(&cp->lock);
 
 	if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
 		cp_rx(cp);
 	if (status & (TxOK | TxErr | TxEmpty | SWInt))
 		cp_tx(cp);
-
-	cpw16_f(IntrStatus, status);
+	if (status & LinkChg)
+		mii_check_media(&cp->mii_if, netif_msg_link(cp), FALSE);
 
 	if (status & PciErr) {
 		u16 pci_status;
@@ -682,22 +781,32 @@
 	eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
 	if (skb_shinfo(skb)->nr_frags == 0) {
 		struct cp_desc *txd = &cp->tx_ring[entry];
-		u32 mapping, len;
+		u32 len;
+		dma_addr_t mapping;
 
 		len = skb->len;
 		mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE);
-		eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
 		CP_VLAN_TX_TAG(txd, vlan_tag);
-		txd->addr_lo = cpu_to_le32(mapping);
+		txd->addr = cpu_to_le64(mapping);
 		wmb();
 
 #ifdef CP_TX_CHECKSUM
-		txd->opts1 = cpu_to_le32(eor | len | DescOwn | FirstFrag |
-			LastFrag | IPCS | UDPCS | TCPCS);
-#else
-		txd->opts1 = cpu_to_le32(eor | len | DescOwn | FirstFrag |
-			LastFrag);
+		if (skb->ip_summed == CHECKSUM_HW) {
+			const struct iphdr *ip = skb->nh.iph;
+			if (ip->protocol == IPPROTO_TCP)
+				txd->opts1 = cpu_to_le32(eor | len | DescOwn |
+							 FirstFrag | LastFrag |
+							 IPCS | TCPCS);
+			else if (ip->protocol == IPPROTO_UDP)
+				txd->opts1 = cpu_to_le32(eor | len | DescOwn |
+							 FirstFrag | LastFrag |
+							 IPCS | UDPCS);
+			else
+				BUG();
+		} else
 #endif
+			txd->opts1 = cpu_to_le32(eor | len | DescOwn |
+						 FirstFrag | LastFrag);
 		wmb();
 
 		cp->tx_skb[entry].skb = skb;
@@ -706,12 +815,17 @@
 		entry = NEXT_TX(entry);
 	} else {
 		struct cp_desc *txd;
-		u32 first_len, first_mapping;
+		u32 first_len, first_eor;
+		dma_addr_t first_mapping;
 		int frag, first_entry = entry;
+#ifdef CP_TX_CHECKSUM
+		const struct iphdr *ip = skb->nh.iph;
+#endif
 
 		/* We must give this initial chunk to the device last.
 		 * Otherwise we could race with the device.
 		 */
+		first_eor = eor;
 		first_len = skb->len - skb->data_len;
 		first_mapping = pci_map_single(cp->pdev, skb->data,
 					       first_len, PCI_DMA_TODEVICE);
@@ -722,8 +836,9 @@
 
 		for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
 			skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
-			u32 len, mapping;
+			u32 len;
 			u32 ctrl;
+			dma_addr_t mapping;
 
 			len = this_frag->size;
 			mapping = pci_map_single(cp->pdev,
@@ -732,16 +847,24 @@
 						 len, PCI_DMA_TODEVICE);
 			eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
 #ifdef CP_TX_CHECKSUM
-			ctrl = eor | len | DescOwn | IPCS | UDPCS | TCPCS;
-#else
-			ctrl = eor | len | DescOwn;
+			if (skb->ip_summed == CHECKSUM_HW) {
+				ctrl = eor | len | DescOwn | IPCS;
+				if (ip->protocol == IPPROTO_TCP)
+					ctrl |= TCPCS;
+				else if (ip->protocol == IPPROTO_UDP)
+					ctrl |= UDPCS;
+				else
+					BUG();
+			} else
 #endif
+				ctrl = eor | len | DescOwn;
+
 			if (frag == skb_shinfo(skb)->nr_frags - 1)
 				ctrl |= LastFrag;
 
 			txd = &cp->tx_ring[entry];
 			CP_VLAN_TX_TAG(txd, vlan_tag);
-			txd->addr_lo = cpu_to_le32(mapping);
+			txd->addr = cpu_to_le64(mapping);
 			wmb();
 
 			txd->opts1 = cpu_to_le32(ctrl);
@@ -755,14 +878,25 @@
 
 		txd = &cp->tx_ring[first_entry];
 		CP_VLAN_TX_TAG(txd, vlan_tag);
-		txd->addr_lo = cpu_to_le32(first_mapping);
+		txd->addr = cpu_to_le64(first_mapping);
 		wmb();
 
 #ifdef CP_TX_CHECKSUM
-		txd->opts1 = cpu_to_le32(first_len | FirstFrag | DescOwn | IPCS | UDPCS | TCPCS);
-#else
-		txd->opts1 = cpu_to_le32(first_len | FirstFrag | DescOwn);
+		if (skb->ip_summed == CHECKSUM_HW) {
+			if (ip->protocol == IPPROTO_TCP)
+				txd->opts1 = cpu_to_le32(first_eor | first_len |
+							 FirstFrag | DescOwn |
+							 IPCS | TCPCS);
+			else if (ip->protocol == IPPROTO_UDP)
+				txd->opts1 = cpu_to_le32(first_eor | first_len |
+							 FirstFrag | DescOwn |
+							 IPCS | UDPCS);
+			else
+				BUG();
+		} else
 #endif
+			txd->opts1 = cpu_to_le32(first_eor | first_len |
+						 FirstFrag | DescOwn);
 		wmb();
 	}
 	cp->tx_head = entry;
@@ -889,8 +1023,12 @@
 
 static inline void cp_start_hw (struct cp_private *cp)
 {
+	u16 pci_dac = cp->pci_using_dac ? PCIDAC : 0;
+	if (cp->board_type == RTL8169)
+		cpw16(CpCmd, pci_dac | PCIMulRW | RxChkSum);
+	else
+		cpw16(CpCmd, pci_dac | PCIMulRW | RxChkSum | CpRxOn | CpTxOn);
 	cpw8(Cmd, RxOn | TxOn);
-	cpw16(CpCmd, PCIMulRW | RxChkSum | CpRxOn | CpTxOn);
 }
 
 static void cp_init_hw (struct cp_private *cp)
@@ -912,27 +1050,28 @@
 	cpw32_f (TxConfig, IFG | (TX_DMA_BURST << TxDMAShift));
 
 	cpw8(Config1, cpr8(Config1) | DriverLoaded | PMEnable);
-	cpw8(Config3, PARMEnable); /* disables magic packet and WOL */
-	cpw8(Config5, cpr8(Config5) & PMEStatus); /* disables more WOL stuff */
+	/* Disable Wake-on-LAN. Can be turned on with ETHTOOL_SWOL */
+	if (cp->board_type == RTL8139Cp) {
+		cpw8(Config3, PARMEnable);
+		cp->wol_enabled = 0;
+	}
+	cpw8(Config5, cpr8(Config5) & PMEStatus); 
+	if (cp->board_type == RTL8169)
+		cpw16(RxMaxSize, cp->rx_buf_sz);
 
 	cpw32_f(HiTxRingAddr, 0);
 	cpw32_f(HiTxRingAddr + 4, 0);
-	cpw32_f(OldRxBufAddr, 0);
-	cpw32_f(OldTSD0, 0);
-	cpw32_f(OldTSD0 + 4, 0);
-	cpw32_f(OldTSD0 + 8, 0);
-	cpw32_f(OldTSD0 + 12, 0);
 
 	cpw32_f(RxRingAddr, cp->ring_dma);
-	cpw32_f(RxRingAddr + 4, 0);
+	cpw32_f(RxRingAddr + 4, 0);		/* FIXME: 64-bit PCI */
 	cpw32_f(TxRingAddr, cp->ring_dma + (sizeof(struct cp_desc) * CP_RX_RING_SIZE));
-	cpw32_f(TxRingAddr + 4, 0);
+	cpw32_f(TxRingAddr + 4, 0);		/* FIXME: 64-bit PCI */
 
 	cpw16(MultiIntr, 0);
 
-	cpw16(IntrMask, cp_intr_mask);
+	cpw16_f(IntrMask, cp_intr_mask);
 
-	cpw8_f (Cfg9346, Cfg9346_Lock);
+	cpw8_f(Cfg9346, Cfg9346_Lock);
 }
 
 static int cp_refill_rx (struct cp_private *cp)
@@ -954,15 +1093,14 @@
 		cp->rx_skb[i].skb = skb;
 		cp->rx_skb[i].frag = 0;
 
+		cp->rx_ring[i].opts2 = 0;
+		cp->rx_ring[i].addr = cpu_to_le64(cp->rx_skb[i].mapping);
 		if (i == (CP_RX_RING_SIZE - 1))
 			cp->rx_ring[i].opts1 =
 				cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz);
 		else
 			cp->rx_ring[i].opts1 =
 				cpu_to_le32(DescOwn | cp->rx_buf_sz);
-		cp->rx_ring[i].opts2 = 0;
-		cp->rx_ring[i].addr_lo = cpu_to_le32(cp->rx_skb[i].mapping);
-		cp->rx_ring[i].addr_hi = 0;
 	}
 
 	return 0;
@@ -985,10 +1123,19 @@
 
 static int cp_alloc_rings (struct cp_private *cp)
 {
-	cp->rx_ring = pci_alloc_consistent(cp->pdev, CP_RING_BYTES, &cp->ring_dma);
-	if (!cp->rx_ring)
+	void *mem;
+
+	mem = pci_alloc_consistent(cp->pdev, CP_RING_BYTES, &cp->ring_dma);
+	if (!mem)
 		return -ENOMEM;
+
+	cp->rx_ring = mem;
 	cp->tx_ring = &cp->rx_ring[CP_RX_RING_SIZE];
+
+	mem += (CP_RING_BYTES - CP_STATS_SIZE);
+	cp->nic_stats = mem;
+	cp->nic_stats_dma = cp->ring_dma + (CP_RING_BYTES - CP_STATS_SIZE);
+
 	return cp_init_rings(cp);
 }
 
@@ -1027,6 +1174,7 @@
 	pci_free_consistent(cp->pdev, CP_RING_BYTES, cp->rx_ring, cp->ring_dma);
 	cp->rx_ring = NULL;
 	cp->tx_ring = NULL;
+	cp->nic_stats = NULL;
 }
 
 static int cp_open (struct net_device *dev)
@@ -1047,6 +1195,8 @@
 	if (rc)
 		goto err_out_hw;
 
+	netif_carrier_off(dev);
+	mii_check_media(&cp->mii_if, netif_msg_link(cp), TRUE);
 	netif_start_queue(dev);
 
 	return 0;
@@ -1065,12 +1215,18 @@
 		printk(KERN_DEBUG "%s: disabling interface\n", dev->name);
 
 	netif_stop_queue(dev);
+	netif_carrier_off(dev);
+
+	spin_lock_irq(&cp->lock);
 	cp_stop_hw(cp);
+	spin_unlock_irq(&cp->lock);
+
 	free_irq(dev->irq, dev);
 	cp_free_rings(cp);
 	return 0;
 }
 
+#ifdef BROKEN
 static int cp_change_mtu(struct net_device *dev, int new_mtu)
 {
 	struct cp_private *cp = dev->priv;
@@ -1094,6 +1250,8 @@
 
 	dev->mtu = new_mtu;
 	cp_set_rxbufsize(cp);		/* set new rx buf size */
+	if (cp->board_type == RTL8169)
+		cpw16(RxMaxSize, cp->rx_buf_sz);
 
 	rc = cp_init_rings(cp);		/* realloc and restart h/w */
 	cp_start_hw(cp);
@@ -1102,6 +1260,7 @@
 
 	return rc;
 }
+#endif /* BROKEN */
 
 static char mii_2_8139_map[8] = {
 	BasicModeCtrl,
@@ -1136,6 +1295,60 @@
 		cpw16(mii_2_8139_map[location], value);
 }
 
+/* Set the ethtool Wake-on-LAN settings */
+static void netdev_set_wol (struct cp_private *cp,
+                     const struct ethtool_wolinfo *wol)
+{
+	u8 options;
+
+	options = cpr8 (Config3) & ~(LinkUp | MagicPacket);
+	/* If WOL is being disabled, no need for complexity */
+	if (wol->wolopts) {
+		if (wol->wolopts & WAKE_PHY)	options |= LinkUp;
+		if (wol->wolopts & WAKE_MAGIC)	options |= MagicPacket;
+	}
+
+	cpw8 (Cfg9346, Cfg9346_Unlock);
+	cpw8 (Config3, options);
+	cpw8 (Cfg9346, Cfg9346_Lock);
+
+	options = 0; /* Paranoia setting */
+	options = cpr8 (Config5) & ~(UWF | MWF | BWF);
+	/* If WOL is being disabled, no need for complexity */
+	if (wol->wolopts) {
+		if (wol->wolopts & WAKE_UCAST)  options |= UWF;
+		if (wol->wolopts & WAKE_BCAST)	options |= BWF;
+		if (wol->wolopts & WAKE_MCAST)	options |= MWF;
+	}
+
+	cpw8 (Config5, options);
+
+	cp->wol_enabled = (wol->wolopts) ? 1 : 0;
+}
+
+/* Get the ethtool Wake-on-LAN settings */
+static void netdev_get_wol (struct cp_private *cp,
+	             struct ethtool_wolinfo *wol)
+{
+	u8 options;
+
+	wol->wolopts   = 0; /* Start from scratch */
+	wol->supported = WAKE_PHY   | WAKE_BCAST | WAKE_MAGIC |
+		         WAKE_MCAST | WAKE_UCAST;
+	/* We don't need to go on if WOL is disabled */
+	if (!cp->wol_enabled) return;
+	
+	options        = cpr8 (Config3);
+	if (options & LinkUp)        wol->wolopts |= WAKE_PHY;
+	if (options & MagicPacket)   wol->wolopts |= WAKE_MAGIC;
+
+	options        = 0; /* Paranoia setting */
+	options        = cpr8 (Config5);
+	if (options & UWF)           wol->wolopts |= WAKE_UCAST;
+	if (options & BWF)           wol->wolopts |= WAKE_BCAST;
+	if (options & MWF)           wol->wolopts |= WAKE_MCAST;
+}
+
 static int cp_ethtool_ioctl (struct cp_private *cp, void *useraddr)
 {
 	u32 ethcmd;
@@ -1153,6 +1366,8 @@
 		strcpy (info.driver, DRV_NAME);
 		strcpy (info.version, DRV_VERSION);
 		strcpy (info.bus_info, cp->pdev->slot_name);
+		info.regdump_len = CP_REGS_SIZE;
+		info.n_stats = CP_NUM_STATS;
 		if (copy_to_user (useraddr, &info, sizeof (info)))
 			return -EFAULT;
 		return 0;
@@ -1209,6 +1424,226 @@
 		return 0;
 	}
 
+	/* NIC register dump */
+	case ETHTOOL_GREGS: {
+                struct ethtool_regs regs;
+                u8 *regbuf = kmalloc(CP_REGS_SIZE, GFP_KERNEL);
+                int rc;
+
+		if (!regbuf)
+			return -ENOMEM;
+		memset(regbuf, 0, CP_REGS_SIZE);
+
+                rc = copy_from_user(&regs, useraddr, sizeof(regs));
+		if (rc) {
+			rc = -EFAULT;
+			goto err_out_gregs;
+		}
+                
+                if (regs.len > CP_REGS_SIZE)
+                        regs.len = CP_REGS_SIZE;
+                if (regs.len < CP_REGS_SIZE) {
+			rc = -EINVAL;
+			goto err_out_gregs;
+		}
+
+                regs.version = CP_REGS_VER;
+                rc = copy_to_user(useraddr, &regs, sizeof(regs));
+		if (rc) {
+			rc = -EFAULT;
+			goto err_out_gregs;
+		}
+
+                useraddr += offsetof(struct ethtool_regs, data);
+
+                spin_lock_irq(&cp->lock);
+                memcpy_fromio(regbuf, cp->regs, CP_REGS_SIZE);
+                spin_unlock_irq(&cp->lock);
+
+                if (copy_to_user(useraddr, regbuf, regs.len))
+                        rc = -EFAULT;
+
+err_out_gregs:
+		kfree(regbuf);
+		return rc;
+	}
+
+	/* get/set RX checksumming */
+	case ETHTOOL_GRXCSUM: {
+		struct ethtool_value edata = { ETHTOOL_GRXCSUM };
+		u16 cmd = cpr16(CpCmd) & RxChkSum;
+
+		edata.data = cmd ? 1 : 0;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SRXCSUM: {
+		struct ethtool_value edata;
+		u16 cmd = cpr16(CpCmd), newcmd;
+
+		newcmd = cmd;
+
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+
+		if (edata.data)
+			newcmd |= RxChkSum;
+		else
+			newcmd &= ~RxChkSum;
+
+		if (newcmd == cmd)
+			return 0;
+
+		spin_lock_irq(&cp->lock);
+		cpw16_f(CpCmd, newcmd);
+		spin_unlock_irq(&cp->lock);
+	}
+
+	/* get/set TX checksumming */
+	case ETHTOOL_GTXCSUM: {
+		struct ethtool_value edata = { ETHTOOL_GTXCSUM };
+
+		edata.data = (cp->dev->features & NETIF_F_IP_CSUM) != 0;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_STXCSUM: {
+		struct ethtool_value edata;
+
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+
+		if (edata.data)
+			cp->dev->features |= NETIF_F_IP_CSUM;
+		else
+			cp->dev->features &= ~NETIF_F_IP_CSUM;
+
+		return 0;
+	}
+
+	/* get/set scatter-gather */
+	case ETHTOOL_GSG: {
+		struct ethtool_value edata = { ETHTOOL_GSG };
+
+		edata.data = (cp->dev->features & NETIF_F_SG) != 0;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SSG: {
+		struct ethtool_value edata;
+
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+
+		if (edata.data)
+			cp->dev->features |= NETIF_F_SG;
+		else
+			cp->dev->features &= ~NETIF_F_SG;
+
+		return 0;
+	}
+
+	/* get string list(s) */
+	case ETHTOOL_GSTRINGS: {
+		struct ethtool_gstrings estr = { ETHTOOL_GSTRINGS };
+
+		if (copy_from_user(&estr, useraddr, sizeof(estr)))
+			return -EFAULT;
+		if (estr.string_set != ETH_SS_STATS)
+			return -EINVAL;
+
+		estr.len = CP_NUM_STATS;
+		if (copy_to_user(useraddr, &estr, sizeof(estr)))
+			return -EFAULT;
+		if (copy_to_user(useraddr + sizeof(estr),
+				 &ethtool_stats_keys,
+				 sizeof(ethtool_stats_keys)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get NIC-specific statistics */
+	case ETHTOOL_GSTATS: {
+		struct ethtool_stats estats = { ETHTOOL_GSTATS };
+		u64 *tmp_stats;
+		unsigned int work = 100;
+		const unsigned int sz = sizeof(u64) * CP_NUM_STATS;
+		int i;
+
+		/* begin NIC statistics dump */
+		cpw32(StatsAddr + 4, 0); /* FIXME: 64-bit PCI */
+		cpw32(StatsAddr, cp->nic_stats_dma | DumpStats);
+		cpr32(StatsAddr);
+
+		estats.n_stats = CP_NUM_STATS;
+		if (copy_to_user(useraddr, &estats, sizeof(estats)))
+			return -EFAULT;
+
+		while (work-- > 0) {
+			if ((cpr32(StatsAddr) & DumpStats) == 0)
+				break;
+			cpu_relax();
+		}
+
+		if (cpr32(StatsAddr) & DumpStats)
+			return -EIO;
+
+		tmp_stats = kmalloc(sz, GFP_KERNEL);
+		if (!tmp_stats)
+			return -ENOMEM;
+		memset(tmp_stats, 0, sz);
+
+		i = 0;
+		tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_ok);
+		tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok);
+		tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_err);
+		tmp_stats[i++] = le32_to_cpu(cp->nic_stats->rx_err);
+		tmp_stats[i++] = le16_to_cpu(cp->nic_stats->rx_fifo);
+		tmp_stats[i++] = le16_to_cpu(cp->nic_stats->frame_align);
+		tmp_stats[i++] = le32_to_cpu(cp->nic_stats->tx_ok_1col);
+		tmp_stats[i++] = le32_to_cpu(cp->nic_stats->tx_ok_mcol);
+		tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok_phys);
+		tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok_bcast);
+		tmp_stats[i++] = le32_to_cpu(cp->nic_stats->rx_ok_mcast);
+		tmp_stats[i++] = le16_to_cpu(cp->nic_stats->tx_abort);
+		tmp_stats[i++] = le16_to_cpu(cp->nic_stats->tx_underrun);
+		tmp_stats[i++] = cp->cp_stats.rx_frags;
+		if (i != CP_NUM_STATS)
+			BUG();
+
+		i = copy_to_user(useraddr + sizeof(estats),
+				 tmp_stats, sz);
+		kfree(tmp_stats);
+
+		if (i)
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get/set Wake-on-LAN settings */
+	case ETHTOOL_GWOL: {
+		struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
+		
+		spin_lock_irq (&cp->lock);
+		netdev_get_wol (cp, &wol);
+		spin_unlock_irq (&cp->lock);
+		return ((copy_to_user (useraddr, &wol, sizeof (wol)))? -EFAULT : 0);
+	}
+	
+	case ETHTOOL_SWOL: {
+		struct ethtool_wolinfo wol;
+
+		if (copy_from_user (&wol, useraddr, sizeof (wol)))
+			return -EFAULT;
+		spin_lock_irq (&cp->lock);
+		netdev_set_wol (cp, &wol);
+		spin_unlock_irq (&cp->lock);
+		return 0;
+	}
+
 	default:
 		break;
 	}
@@ -1220,20 +1655,18 @@
 static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct cp_private *cp = dev->priv;
-	int rc = 0;
+	struct mii_ioctl_data *mii = (struct mii_ioctl_data *) &rq->ifr_data;
+	int rc;
 
 	if (!netif_running(dev))
 		return -EINVAL;
 
-	switch (cmd) {
-	case SIOCETHTOOL:
+	if (cmd == SIOCETHTOOL)
 		return cp_ethtool_ioctl(cp, (void *) rq->ifr_data);
 
-	default:
-		rc = -EOPNOTSUPP;
-		break;
-	}
-
+	spin_lock_irq(&cp->lock);
+	rc = generic_mii_ioctl(&cp->mii_if, mii, cmd, NULL);
+	spin_unlock_irq(&cp->lock);
 	return rc;
 }
 
@@ -1321,6 +1754,13 @@
 	return retval;
 }
 
+/* Put the board into D3cold state and wait for WakeUp signal */
+static void cp_set_d3_state (struct cp_private *cp)
+{
+	pci_enable_wake (cp->pdev, 0, 1); /* Enable PME# generation */
+	pci_set_power_state (cp->pdev, 3);
+}
+
 static int __devinit cp_init_one (struct pci_dev *pdev,
 				  const struct pci_device_id *ent)
 {
@@ -1329,9 +1769,10 @@
 	int rc;
 	void *regs;
 	long pciaddr;
-	unsigned addr_len, i;
+	unsigned int addr_len, i;
 	u8 pci_rev, cache_size;
 	u16 pci_command;
+	unsigned int board_type = (unsigned int) ent->driver_data;
 
 #ifndef MODULE
 	static int version_printed;
@@ -1355,6 +1796,7 @@
 	SET_MODULE_OWNER(dev);
 	cp = dev->priv;
 	cp->pdev = pdev;
+	cp->board_type = board_type;
 	cp->dev = dev;
 	cp->msg_enable = (debug < 0 ? CP_DEF_MSG_ENABLE : debug);
 	spin_lock_init (&cp->lock);
@@ -1362,6 +1804,8 @@
 	cp->mii_if.mdio_read = mdio_read;
 	cp->mii_if.mdio_write = mdio_write;
 	cp->mii_if.phy_id = CP_INTERNAL_PHY;
+	cp->mii_if.phy_id_mask = 0x1f;
+	cp->mii_if.reg_num_mask = 0x1f;
 	cp_set_rxbufsize(cp);
 
 	rc = pci_enable_device(pdev);
@@ -1392,6 +1836,19 @@
 		goto err_out_res;
 	}
 
+	/* Configure DMA attributes. */
+	if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) {
+		cp->pci_using_dac = 1;
+	} else {
+		rc = pci_set_dma_mask(pdev, (u64) 0xffffffff);
+		if (rc) {
+			printk(KERN_ERR PFX "No usable DMA configuration, "
+			       "aborting.\n");
+			goto err_out_res;
+		}
+		cp->pci_using_dac = 0;
+	}
+
 	regs = ioremap_nocache(pciaddr, CP_REGS_SIZE);
 	if (!regs) {
 		rc = -EIO;
@@ -1416,7 +1873,9 @@
 	dev->hard_start_xmit = cp_start_xmit;
 	dev->get_stats = cp_get_stats;
 	dev->do_ioctl = cp_ioctl;
+#ifdef BROKEN
 	dev->change_mtu = cp_change_mtu;
+#endif
 #if 0
 	dev->tx_timeout = cp_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
@@ -1440,7 +1899,7 @@
 		"%02x:%02x:%02x:%02x:%02x:%02x, "
 		"IRQ %d\n",
 		dev->name,
-		"RTL-8139C+",
+		cp_board_tbl[board_type].name,
 		dev->base_addr,
 		dev->dev_addr[0], dev->dev_addr[1],
 		dev->dev_addr[2], dev->dev_addr[3],
@@ -1477,6 +1936,8 @@
 	}
 	pci_set_master(pdev);
 
+	if (cp->wol_enabled) cp_set_d3_state (cp);
+
 	return 0;
 
 err_out_iomap:
@@ -1499,17 +1960,75 @@
 		BUG();
 	unregister_netdev(dev);
 	iounmap(cp->regs);
+	if (cp->wol_enabled) pci_set_power_state (pdev, 0);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 	kfree(dev);
 }
 
+#ifdef CONFIG_PM
+static int cp_suspend (struct pci_dev *pdev, u32 state)
+{
+	struct net_device *dev;
+	struct cp_private *cp;
+	unsigned long flags;
+
+	dev = pci_get_drvdata (pdev);
+	cp  = dev->priv;
+
+	if (!dev || !netif_running (dev)) return 0;
+
+	netif_device_detach (dev);
+	netif_stop_queue (dev);
+
+	spin_lock_irqsave (&cp->lock, flags);
+
+	/* Disable Rx and Tx */
+	cpw16 (IntrMask, 0);
+	cpw8  (Cmd, cpr8 (Cmd) & (~RxOn | ~TxOn));
+
+	spin_unlock_irqrestore (&cp->lock, flags);
+
+	if (cp->pdev && cp->wol_enabled) {
+		pci_save_state (cp->pdev, cp->power_state);
+		cp_set_d3_state (cp);
+	}
+
+	return 0;
+}
+
+static int cp_resume (struct pci_dev *pdev)
+{
+	struct net_device *dev;
+	struct cp_private *cp;
+
+	dev = pci_get_drvdata (pdev);
+	cp  = dev->priv;
+
+	netif_device_attach (dev);
+	
+	if (cp->pdev && cp->wol_enabled) {
+		pci_set_power_state (cp->pdev, 0);
+		pci_restore_state (cp->pdev, cp->power_state);
+	}
+	
+	cp_init_hw (cp);
+	netif_start_queue (dev);
+	
+	return 0;
+}
+#endif /* CONFIG_PM */
+
 static struct pci_driver cp_driver = {
-	name:		DRV_NAME,
-	id_table:	cp_pci_tbl,
-	probe:		cp_init_one,
-	remove:		__devexit_p(cp_remove_one),
+	.name         = DRV_NAME,
+	.id_table     = cp_pci_tbl,
+	.probe        =	cp_init_one,
+	.remove       = __devexit_p(cp_remove_one),
+#ifdef CONFIG_PM
+	.resume       = cp_resume,
+	.suspend      = cp_suspend,
+#endif
 };
 
 static int __init cp_init (void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/8139too.c linux-2.4.20/drivers/net/8139too.c
--- linux-2.4.19/drivers/net/8139too.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/8139too.c	2002-10-29 11:18:30.000000000 +0000
@@ -92,7 +92,7 @@
 */
 
 #define DRV_NAME	"8139too"
-#define DRV_VERSION	"0.9.25"
+#define DRV_VERSION	"0.9.26"
 
 
 #include <linux/config.h>
@@ -201,6 +201,8 @@
 	HAS_LNK_CHNG = 0x040000,
 };
 
+#define RTL_NUM_STATS 4		/* number of ETHTOOL_GSTATS u64's */
+#define RTL_REGS_VER 1		/* version of reg. data in ETHTOOL_GREGS */
 #define RTL_MIN_IO_SIZE 0x80
 #define RTL8139B_IO_SIZE 256
 
@@ -219,6 +221,8 @@
 	FE2000VX,
 	ALLIED8139,
 	RTL8129,
+	FNW3603TX,
+	FNW3800TX,
 } board_t;
 
 
@@ -238,6 +242,8 @@
 	{ "AboCom FE2000VX (RealTek RTL8139)", RTL8139_CAPS },
 	{ "Allied Telesyn 8139 CardBus", RTL8139_CAPS },
 	{ "RealTek RTL8129", RTL8129_CAPS },
+	{ "Planex FNW-3603-TX 10/100 CardBus", RTL8139_CAPS },
+	{ "Planex FNW-3800-TX 10/100 CardBus", RTL8139_CAPS },
 };
 
 
@@ -252,6 +258,8 @@
 	{0x1186, 0x1340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE690TXD },
 	{0x13d1, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FE2000VX },
 	{0x1259, 0xa117, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALLIED8139 },
+	{0x14ea, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FNW3603TX },
+	{0x14ea, 0xab07, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FNW3800TX },
 
 #ifdef CONFIG_8139TOO_8129
 	{0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 },
@@ -269,6 +277,14 @@
 };
 MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl);
 
+static struct {
+	const char str[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+	{ "early_rx" },
+	{ "tx_buf_mapped" },
+	{ "tx_timeouts" },
+	{ "rx_lost_in_ring" },
+};
 
 /* The rest of these values should never change. */
 
@@ -446,7 +462,7 @@
 
 
 /* Twister tuning parameters from RealTek.
-   Completely undocumented, but required to tune bad links. */
+   Completely undocumented, but required to tune bad links on some boards. */
 enum CSCRBits {
 	CSCR_LinkOKBit = 0x0400,
 	CSCR_LinkChangeBit = 0x0800,
@@ -461,10 +477,14 @@
 	Cfg9346_Unlock = 0xC0,
 };
 
+#ifdef CONFIG_8139TOO_TUNE_TWISTER
+
+enum TwisterParamVals {
+	PARA78_default	= 0x78fa8388,
+	PARA7c_default	= 0xcb38de43,	/* param[0][3] */
+	PARA7c_xxx	= 0xcb38de43,
+};
 
-#define PARA78_default	0x78fa8388
-#define PARA7c_default	0xcb38de43	/* param[0][3] */
-#define PARA7c_xxx		0xcb38de43
 static const unsigned long param[4][4] = {
 	{0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43},
 	{0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
@@ -472,6 +492,8 @@
 	{0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83}
 };
 
+#endif /* CONFIG_8139TOO_TUNE_TWISTER */
+
 typedef enum {
 	CH_8139 = 0,
 	CH_8139_K,
@@ -556,7 +578,6 @@
 	signed char phys[4];		/* MII device addresses. */
 	char twistie, twist_row, twist_col;	/* Twister tune state. */
 	unsigned int default_port:4;	/* Last dev->if_port value. */
-	unsigned int medialock:1;	/* Don't sense media type. */
 	spinlock_t lock;
 	chip_t chipset;
 	pid_t thr_pid;
@@ -566,6 +587,7 @@
 	struct rtl_extra_stats xstats;
 	int time_to_die;
 	struct mii_if_info mii;
+	unsigned int regs_len;
 };
 
 MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
@@ -807,6 +829,7 @@
 	ioaddr = (void *) pio_start;
 	dev->base_addr = pio_start;
 	tp->mmio_addr = ioaddr;
+	tp->regs_len = pio_len;
 #else
 	/* ioremap MMIO region */
 	ioaddr = ioremap (mmio_start, mmio_len);
@@ -817,6 +840,7 @@
 	}
 	dev->base_addr = (long) ioaddr;
 	tp->mmio_addr = ioaddr;
+	tp->regs_len = mmio_len;
 #endif /* USE_IO_OPS */
 
 	/* Bring old chips out of low-power mode. */
@@ -961,6 +985,8 @@
 	tp->mii.dev = dev;
 	tp->mii.mdio_read = mdio_read;
 	tp->mii.mdio_write = mdio_write;
+	tp->mii.phy_id_mask = 0x3f;
+	tp->mii.reg_num_mask = 0x1f;
 
 	/* dev is fully set up and ready to use now */
 	DPRINTK("about to register device named %s (%p)...\n", dev->name, dev);
@@ -1016,7 +1042,7 @@
 		tp->mii.full_duplex = (option & 0x210) ? 1 : 0;
 		tp->default_port = option & 0xFF;
 		if (tp->default_port)
-			tp->medialock = 1;
+			tp->mii.force_media = 1;
 	}
 	if (board_idx < MAX_UNITS  &&  full_duplex[board_idx] > 0)
 		tp->mii.full_duplex = full_duplex[board_idx];
@@ -1024,7 +1050,7 @@
 		printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
 		/* Changing the MII-advertised media because might prevent
 		   re-connection. */
-		tp->mii.duplex_lock = 1;
+		tp->mii.force_media = 1;
 	}
 	if (tp->default_port) {
 		printk(KERN_INFO "  Forcing %dMbps %s-duplex operation.\n",
@@ -1281,9 +1307,9 @@
 
 	}
 
-	tp->mii.full_duplex = tp->mii.duplex_lock;
+	tp->mii.full_duplex = tp->mii.force_media;
 	tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
-	tp->twistie = 1;
+	tp->twistie = (tp->chipset == CH_8139_K) ? 1 : 0;
 	tp->time_to_die = 0;
 
 	rtl8139_init_ring (dev);
@@ -1512,7 +1538,7 @@
 
 	mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA);
 
-	if (!tp->mii.duplex_lock && mii_lpa != 0xffff) {
+	if (!tp->mii.force_media && mii_lpa != 0xffff) {
 		int duplex = (mii_lpa & LPA_100FULL)
 		    || (mii_lpa & 0x01C0) == 0x0040;
 		if (tp->mii.full_duplex != duplex) {
@@ -1722,10 +1748,6 @@
 				tp->stats.tx_carrier_errors++;
 			if (txstatus & TxOutOfWindow)
 				tp->stats.tx_window_errors++;
-#ifdef ETHER_STATS
-			if ((txstatus & 0x0f000000) == 0x0f000000)
-				tp->stats.collisions16++;
-#endif
 		} else {
 			if (txstatus & TxUnderrun) {
 				/* Add 64 to the Tx FIFO threshold. */
@@ -1765,7 +1787,7 @@
 			    struct rtl8139_private *tp, void *ioaddr)
 {
 	u8 tmp8;
-#ifndef CONFIG_8139_NEW_RX_RESET
+#ifdef CONFIG_8139_OLD_RX_RESET
 	int tmp_work;
 #endif
 
@@ -1788,7 +1810,7 @@
 		tp->xstats.rx_lost_in_ring++;
 	}
 
-#ifdef CONFIG_8139_NEW_RX_RESET
+#ifndef CONFIG_8139_OLD_RX_RESET
 	tmp8 = RTL_R8 (ChipCmd);
 	RTL_W8 (ChipCmd, tmp8 & ~CmdRxEnb);
 	RTL_W8 (ChipCmd, tmp8);
@@ -1975,7 +1997,7 @@
 		/* Really link-change on new chips. */
 		int lpar = RTL_R16 (NWayLPAR);
 		int duplex = (lpar & LPA_100FULL) || (lpar & 0x01C0) == 0x0040
-				|| tp->mii.duplex_lock;
+				|| tp->mii.force_media;
 		if (tp->mii.full_duplex != duplex) {
 			tp->mii.full_duplex = duplex;
 #if 0
@@ -2231,6 +2253,7 @@
 		strcpy (info.driver, DRV_NAME);
 		strcpy (info.version, DRV_VERSION);
 		strcpy (info.bus_info, np->pci_dev->slot_name);
+		info.regdump_len = np->regs_len;
 		if (copy_to_user (useraddr, &info, sizeof (info)))
 			return -EFAULT;
 		return 0;
@@ -2310,6 +2333,104 @@
 			return rc;
 		}
 
+/* TODO: we are too slack to do reg dumping for pio, for now */
+#ifndef CONFIG_8139TOO_PIO
+	/* NIC register dump */
+	case ETHTOOL_GREGS: {
+                struct ethtool_regs regs;
+		unsigned int regs_len = np->regs_len;
+                u8 *regbuf = kmalloc(regs_len, GFP_KERNEL);
+                int rc;
+
+		if (!regbuf)
+			return -ENOMEM;
+		memset(regbuf, 0, regs_len);
+
+                rc = copy_from_user(&regs, useraddr, sizeof(regs));
+		if (rc) {
+			rc = -EFAULT;
+			goto err_out_gregs;
+		}
+                
+                if (regs.len > regs_len)
+                        regs.len = regs_len;
+                if (regs.len < regs_len) {
+			rc = -EINVAL;
+			goto err_out_gregs;
+		}
+
+                regs.version = RTL_REGS_VER;
+                rc = copy_to_user(useraddr, &regs, sizeof(regs));
+		if (rc) {
+			rc = -EFAULT;
+			goto err_out_gregs;
+		}
+
+                useraddr += offsetof(struct ethtool_regs, data);
+
+                spin_lock_irq(&np->lock);
+                memcpy_fromio(regbuf, np->mmio_addr, regs_len);
+                spin_unlock_irq(&np->lock);
+
+                if (copy_to_user(useraddr, regbuf, regs_len))
+                        rc = -EFAULT;
+
+err_out_gregs:
+		kfree(regbuf);
+		return rc;
+	}
+#endif /* CONFIG_8139TOO_PIO */
+
+	/* get string list(s) */
+	case ETHTOOL_GSTRINGS: {
+		struct ethtool_gstrings estr = { ETHTOOL_GSTRINGS };
+
+		if (copy_from_user(&estr, useraddr, sizeof(estr)))
+			return -EFAULT;
+		if (estr.string_set != ETH_SS_STATS)
+			return -EINVAL;
+
+		estr.len = RTL_NUM_STATS;
+		if (copy_to_user(useraddr, &estr, sizeof(estr)))
+			return -EFAULT;
+		if (copy_to_user(useraddr + sizeof(estr),
+				 &ethtool_stats_keys,
+				 sizeof(ethtool_stats_keys)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get NIC-specific statistics */
+	case ETHTOOL_GSTATS: {
+		struct ethtool_stats estats = { ETHTOOL_GSTATS };
+		u64 *tmp_stats;
+		const unsigned int sz = sizeof(u64) * RTL_NUM_STATS;
+		int i;
+
+		estats.n_stats = RTL_NUM_STATS;
+		if (copy_to_user(useraddr, &estats, sizeof(estats)))
+			return -EFAULT;
+
+		tmp_stats = kmalloc(sz, GFP_KERNEL);
+		if (!tmp_stats)
+			return -ENOMEM;
+		memset(tmp_stats, 0, sz);
+
+		i = 0;
+		tmp_stats[i++] = np->xstats.early_rx;
+		tmp_stats[i++] = np->xstats.tx_buf_mapped;
+		tmp_stats[i++] = np->xstats.tx_timeouts;
+		tmp_stats[i++] = np->xstats.rx_lost_in_ring;
+		if (i != RTL_NUM_STATS)
+			BUG();
+
+		i = copy_to_user(useraddr + sizeof(estats), tmp_stats, sz);
+		kfree(tmp_stats);
+
+		if (i)
+			return -EFAULT;
+		return 0;
+	}
 	default:
 		break;
 	}
@@ -2318,61 +2439,22 @@
 }
 
 
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct rtl8139_private *tp = dev->priv;
-	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
-	int rc = 0;
-	int phy = tp->phys[0] & 0x3f;
+	struct rtl8139_private *np = dev->priv;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+	int rc;
 
 	if (!netif_running(dev))
 		return -EINVAL;
 
-	if (cmd != SIOCETHTOOL) {
-		/* With SIOCETHTOOL, this would corrupt the pointer.  */
-		data->phy_id &= 0x3f;
-		data->reg_num &= 0x1f;
-	}
-
-	switch (cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
-	case SIOCGMIIPHY:	/* Get the address of the PHY in use. */
-	case SIOCDEVPRIVATE:	/* binary compat, remove in 2.5 */
-		data->phy_id = phy;
-		/* Fall Through */
-
-	case SIOCGMIIREG:	/* Read the specified MII register. */
-	case SIOCDEVPRIVATE+1:	/* binary compat, remove in 2.5 */
-		data->val_out = mdio_read (dev, data->phy_id, data->reg_num);
-		break;
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 
-	case SIOCSMIIREG:	/* Write the specified MII register */
-	case SIOCDEVPRIVATE+2:	/* binary compat, remove in 2.5 */
-		if (!capable (CAP_NET_ADMIN)) {
-			rc = -EPERM;
-			break;
-		}
-
-		if (data->phy_id == phy) {
-			u16 value = data->val_in;
-			switch (data->reg_num) {
-			case 0:
-				/* Check for autonegotiation on or reset. */
-				tp->medialock = (value & 0x9000) ? 0 : 1;
-				if (tp->medialock)
-					tp->mii.full_duplex = (value & 0x0100) ? 1 : 0;
-				break;
-			case 4: tp->mii.advertising = value; break;
-			}
-		}
-		mdio_write(dev, data->phy_id, data->reg_num, data->val_in);
-		break;
-
-	default:
-		rc = -EOPNOTSUPP;
-		break;
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
 	}
 
 	return rc;
@@ -2500,13 +2582,13 @@
 
 
 static struct pci_driver rtl8139_pci_driver = {
-	name:		DRV_NAME,
-	id_table:	rtl8139_pci_tbl,
-	probe:		rtl8139_init_one,
-	remove:		__devexit_p(rtl8139_remove_one),
+	.name		= DRV_NAME,
+	.id_table	= rtl8139_pci_tbl,
+	.probe		= rtl8139_init_one,
+	.remove		= __devexit_p(rtl8139_remove_one),
 #ifdef CONFIG_PM
-	suspend:	rtl8139_suspend,
-	resume:		rtl8139_resume,
+	.suspend	= rtl8139_suspend,
+	.resume		= rtl8139_resume,
 #endif /* CONFIG_PM */
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/Config.in linux-2.4.20/drivers/net/Config.in
--- linux-2.4.19/drivers/net/Config.in	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/Config.in	2002-10-29 11:18:32.000000000 +0000
@@ -36,7 +36,7 @@
 	 bool '    Use AAUI port instead of TP by default' CONFIG_MACE_AAUI_PORT
       fi
       dep_tristate '  BMAC (G3 ethernet) support' CONFIG_BMAC $CONFIG_ALL_PPC
-      dep_tristate '  GMAC (G4/iBook ethernet) support' CONFIG_GMAC $CONFIG_ALL_PPC
+      dep_tristate '  GMAC (G4/iBook ethernet) support (OBSOLETE, use Sun GEM)' CONFIG_GMAC $CONFIG_ALL_PPC
       if [ "$CONFIG_4xx" = "y" ]; then
          if [ "$CONFIG_STB03xxx" = "y" -o "$CONFIG_403GCX" = "y" ]; then
 	    tristate '  National DP83902AV (Oak ethernet) support' CONFIG_OAKNET
@@ -67,6 +67,9 @@
    if [ "$CONFIG_SGI_IP27" = "y" ]; then
       bool '  SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH
    fi
+   if [ "$CONFIG_SGI_IP32" = "y" ]; then
+      tristate '  SGI O2 MACE Fast Ethernet support' CONFIG_SGI_O2MACE_ETH
+   fi
    if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then
       bool '  SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH
    fi
@@ -79,7 +82,7 @@
    fi
    dep_tristate '  Sun BigMAC 10/100baseT support (EXPERIMENTAL)' CONFIG_SUNBMAC $CONFIG_SBUS $CONFIG_EXPERIMENTAL
    dep_tristate '  Sun QuadEthernet support' CONFIG_SUNQE $CONFIG_SBUS
-   dep_tristate '  Sun GEM support' CONFIG_SUNGEM $CONFIG_PCI
+   dep_tristate '  Sun GEM & Apple GMAC support' CONFIG_SUNGEM $CONFIG_PCI
    bool '  3COM cards' CONFIG_NET_VENDOR_3COM
    if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
       dep_tristate '    3c501 "EtherLink" support' CONFIG_EL1 $CONFIG_ISA
@@ -129,7 +132,7 @@
       tristate '    EtherExpress 16 support' CONFIG_EEXPRESS
       tristate '    EtherExpressPro support/EtherExpress 10 (i82595) support' CONFIG_EEXPRESS_PRO
       if [ "$CONFIG_OBSOLETE" = "y" ]; then
-         tristate '    FMV-181/182/183/184 support' CONFIG_FMV18X
+         tristate '    FMV-181/182/183/184 support (OBSOLETE)' CONFIG_FMV18X
       fi
       tristate '    HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
       tristate '    HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
@@ -149,9 +152,9 @@
       tristate '  IBM LAN Adapter/A support' CONFIG_IBMLANA
    fi
    if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
-     bool '  EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
+      bool '  EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
    else
-     define_bool CONFIG_NET_PCI n
+      define_bool CONFIG_NET_PCI n
    fi
    if [ "$CONFIG_NET_PCI" = "y" ]; then
       dep_tristate '    AMD PCnet32 PCI support' CONFIG_PCNET32 $CONFIG_PCI
@@ -163,7 +166,6 @@
       dep_tristate '    Apricot Xen-II on board Ethernet' CONFIG_APRICOT $CONFIG_ISA
       dep_tristate '    CS89x0 support' CONFIG_CS89x0 $CONFIG_ISA
       dep_tristate '    DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP $CONFIG_PCI
-      dep_tristate '    TOSHIBA TC35815 Ethernet support' CONFIG_TC35815 $CONFIG_PCI
       if [ "$CONFIG_TULIP" = "y" -o "$CONFIG_TULIP" = "m" ]; then
          dep_bool '      New bus configuration (EXPERIMENTAL)' CONFIG_TULIP_MWI $CONFIG_EXPERIMENTAL
          bool '      Use PCI shared mem for NIC registers' CONFIG_TULIP_MMIO
@@ -173,33 +175,33 @@
          tristate '    Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
       fi
       dep_tristate '    Davicom DM910x/DM980x support' CONFIG_DM9102 $CONFIG_PCI
-      dep_tristate '    EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI
+      dep_tristate '    EtherExpressPro/100 support (eepro100, original Becker driver)' CONFIG_EEPRO100 $CONFIG_PCI
+      dep_tristate '    EtherExpressPro/100 support (e100, Alternate Intel driver)' CONFIG_E100 $CONFIG_PCI
       dep_tristate '    Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    Myson MTD-8xx PCI Ethernet support' CONFIG_FEALNX $CONFIG_PCI
       dep_tristate '    National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI
-      if [ "$CONFIG_NATSEMI" = "y" -o "$CONFIG_NATSEMI" = "m" ]; then
-        bool       '      NatSemi workaround for high errors' CONFIG_NATSEMI_CABLE_MAGIC
-      fi
       dep_tristate '    PCI NE2000 and clones support (see help)' CONFIG_NE2K_PCI $CONFIG_PCI
       dep_tristate '    Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_8139CP $CONFIG_PCI $CONFIG_EXPERIMENTAL
       dep_tristate '    RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO $CONFIG_PCI
       dep_mbool '      Use PIO instead of MMIO' CONFIG_8139TOO_PIO $CONFIG_8139TOO
-      dep_mbool '      Support for automatic channel equalization (EXPERIMENTAL)' CONFIG_8139TOO_TUNE_TWISTER $CONFIG_8139TOO $CONFIG_EXPERIMENTAL
+      dep_mbool '      Support for uncommon RTL-8139 rev. K (automatic channel equalization)' CONFIG_8139TOO_TUNE_TWISTER $CONFIG_8139TOO
       dep_mbool '      Support for older RTL-8129/8130 boards' CONFIG_8139TOO_8129 $CONFIG_8139TOO
-      dep_mbool '      Experiment for better RX reset (EXPERIMENTAL)' CONFIG_8139_NEW_RX_RESET $CONFIG_8139TOO $CONFIG_EXPERIMENTAL
+      dep_mbool '      Use older RX-reset method' CONFIG_8139_OLD_RX_RESET $CONFIG_8139TOO
       dep_tristate '    SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 $CONFIG_PCI
       dep_tristate '    SMC EtherPower II' CONFIG_EPIC100 $CONFIG_PCI
       dep_tristate '    Sundance Alta support' CONFIG_SUNDANCE $CONFIG_PCI
+      dep_mbool '      Use MMIO instead of PIO' CONFIG_SUNDANCE_MMIO $CONFIG_SUNDANCE
       if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
          tristate '    TI ThunderLAN support' CONFIG_TLAN
       fi
+      dep_tristate '    TOSHIBA TC35815 Ethernet support' CONFIG_TC35815 $CONFIG_PCI
       dep_tristate '    VIA Rhine support' CONFIG_VIA_RHINE $CONFIG_PCI
       dep_mbool '      Use MMIO instead of PIO (EXPERIMENTAL)' CONFIG_VIA_RHINE_MMIO $CONFIG_VIA_RHINE $CONFIG_EXPERIMENTAL
       dep_tristate '    Winbond W89c840 Ethernet support' CONFIG_WINBOND_840 $CONFIG_PCI
       if [ "$CONFIG_OBSOLETE" = "y" ]; then
-	 dep_bool '    Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET $CONFIG_ISA
+	 dep_bool '    Zenith Z-Note support (OBSOLETE)' CONFIG_ZNET $CONFIG_ISA
       fi
       if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_MIPS" = "y" ]; then
 	 bool '    Philips SAA9730 Ethernet support (EXPERIMENTAL)' CONFIG_LAN_SAA9730
@@ -241,8 +243,9 @@
    bool '  Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I
 fi
 dep_tristate 'D-Link DL2000-based Gigabit Ethernet support' CONFIG_DL2K $CONFIG_PCI
+dep_tristate 'Intel(R) PRO/1000 Gigabit Ethernet support' CONFIG_E1000 $CONFIG_PCI
 dep_tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS $CONFIG_SBUS
-dep_tristate 'National Semiconduct DP83820 support' CONFIG_NS83820 $CONFIG_PCI
+dep_tristate 'National Semiconductor DP83820 support' CONFIG_NS83820 $CONFIG_PCI
 dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI
 dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN $CONFIG_PCI
@@ -266,9 +269,9 @@
    if [ "$CONFIG_INET" = "y" ]; then
       bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
       if [ "$CONFIG_HIPPI" = "y" -a "$CONFIG_PCI" = "y" ]; then
-         dep_tristate '  Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER $CONFIG_PCI
+         dep_tristate '  Essential RoadRunner HIPPI PCI adapter support (EXPERIMENTAL)' CONFIG_ROADRUNNER $CONFIG_PCI
          if [ "$CONFIG_ROADRUNNER" != "n" ]; then
-   	    bool '    Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS
+   	    bool '    Use large TX/RX rings (EXPERIMENTAL)' CONFIG_ROADRUNNER_LARGE_RINGS
          fi
       fi
    fi
@@ -306,7 +309,9 @@
 if [ "$CONFIG_NET_RADIO" = "y" ]; then
    dep_tristate '  STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET
    tristate '  AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
-   tristate '  Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN
+   if [ "$CONFIG_X86_64" != "y" ]; then
+      tristate '  Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN
+   fi
    tristate '  Aironet 4500/4800 series adapters' CONFIG_AIRONET4500
    dep_tristate '   Aironet 4500/4800 ISA/PCI/PNP/365 support ' CONFIG_AIRONET4500_NONCS $CONFIG_AIRONET4500
    if [ "$CONFIG_AIRONET4500" != "n" -a "$CONFIG_AIRONET4500_NONCS" != "n" ]; then
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/Makefile linux-2.4.20/drivers/net/Makefile
--- linux-2.4.19/drivers/net/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/Makefile	2002-10-29 11:18:35.000000000 +0000
@@ -25,6 +25,10 @@
   obj-y += tulip/tulip.o
 endif
 
+ifeq ($(CONFIG_E1000),y)
+  obj-y += e1000/e1000.o
+endif
+
 ifeq ($(CONFIG_ISDN_PPP),y)
   obj-$(CONFIG_ISDN) += slhc.o
 endif
@@ -40,6 +44,8 @@
 subdir-$(CONFIG_DEV_APPLETALK) += appletalk
 subdir-$(CONFIG_SK98LIN) += sk98lin
 subdir-$(CONFIG_SKFP) += skfp
+subdir-$(CONFIG_E100) += e100
+subdir-$(CONFIG_E1000) += e1000
 
 #
 # link order important here
@@ -81,6 +87,10 @@
 obj-$(CONFIG_TC35815) += tc35815.o
 obj-$(CONFIG_TIGON3) += tg3.o
 
+ifeq ($(CONFIG_E100),y)
+  obj-y += e100/e100.o
+endif
+
 ifeq ($(CONFIG_SK98LIN),y)
 obj-y += sk98lin/sk98lin.o
 endif
@@ -103,7 +113,7 @@
 obj-$(CONFIG_AIRONET4500_CS)	+= aironet4500_proc.o
 
 obj-$(CONFIG_WINBOND_840) += winbond-840.o mii.o
-obj-$(CONFIG_SUNDANCE) += sundance.o
+obj-$(CONFIG_SUNDANCE) += sundance.o mii.o
 obj-$(CONFIG_HAMACHI) += hamachi.o
 obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o
 obj-$(CONFIG_SEEQ8005) += seeq8005.o
@@ -156,6 +166,7 @@
 obj-$(CONFIG_SUN3LANCE) += sun3lance.o
 obj-$(CONFIG_DEFXX) += defxx.o
 obj-$(CONFIG_SGISEEQ) += sgiseeq.o
+obj-$(CONFIG_SGI_O2MACE_ETH) += meth.o
 obj-$(CONFIG_AT1700) += at1700.o
 obj-$(CONFIG_FMV18X) += fmv18x.o
 obj-$(CONFIG_EL1) += 3c501.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/acenic.c linux-2.4.20/drivers/net/acenic.c
--- linux-2.4.19/drivers/net/acenic.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/acenic.c	2002-10-29 11:18:40.000000000 +0000
@@ -47,6 +47,7 @@
  *                                       flushing the Jumbo ring.
  *   Hans Grobler <grobh@sun.ac.za>:     Memory leak fixes in the
  *                                       driver init path.
+ *   Grant Grundler <grundler@cup.hp.com>: PCI write posting fixes.
  */
 
 #include <linux/config.h>
@@ -123,7 +124,6 @@
 #ifndef PCI_DEVICE_ID_FARALLON_PN9100T
 #define PCI_DEVICE_ID_FARALLON_PN9100T  0xfa
 #endif
-
 #ifndef PCI_VENDOR_ID_SGI
 #define PCI_VENDOR_ID_SGI		0x10a9
 #endif
@@ -144,13 +144,13 @@
 	{ PCI_VENDOR_ID_NETGEAR, PCI_DEVICE_ID_NETGEAR_GA620T,
 	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
 	/*
-	 * Farallon used the DEC vendor ID on their cards incorrectly.
+	 * Farallon used the DEC vendor ID on their cards incorrectly,
+	 * then later Alteon's ID.
 	 */
 	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_FARALLON_PN9000SX,
 	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
 	{ PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_FARALLON_PN9100T,
 	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
-
 	{ PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_ACENIC,
 	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
 	{ }
@@ -180,15 +180,21 @@
 #endif
 
 #ifndef SET_MODULE_OWNER
-#define SET_MODULE_OWNER(dev)		{do{} while(0);}
+#define SET_MODULE_OWNER(dev)		do{} while(0)
 #define ACE_MOD_INC_USE_COUNT		MOD_INC_USE_COUNT
 #define ACE_MOD_DEC_USE_COUNT		MOD_DEC_USE_COUNT
 #else
-#define ACE_MOD_INC_USE_COUNT		{do{} while(0);}
-#define ACE_MOD_DEC_USE_COUNT		{do{} while(0);}
+#define ACE_MOD_INC_USE_COUNT		do{} while(0)
+#define ACE_MOD_DEC_USE_COUNT		do{} while(0)
 #endif
 
 
+#if LINUX_VERSION_CODE >= 0x2051c
+#define ace_sync_irq(irq)	synchronize_irq(irq)
+#else
+#define ace_sync_irq(irq)	synchronize_irq()
+#endif
+
 #if (LINUX_VERSION_CODE < 0x02030d)
 #define pci_resource_start(dev, bar)	dev->base_address[bar]
 #elif (LINUX_VERSION_CODE < 0x02032c)
@@ -199,6 +205,7 @@
 #define net_device device
 #endif
 
+
 #if (LINUX_VERSION_CODE < 0x02032a)
 typedef u32 dma_addr_t;
 
@@ -222,8 +229,6 @@
 	(((u64)(mask) & 0xffffffff00000000) == 0 ? 0 : -EIO)
 #define pci_dma_supported(dev, mask)		\
 	(((u64)(mask) & 0xffffffff00000000) == 0 ? 1 : 0)
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
 
 #elif (LINUX_VERSION_CODE < 0x02040d)
 
@@ -247,8 +252,15 @@
 }
 #define pci_unmap_page(cookie, dma_addr, size, dir)	\
 	pci_unmap_single(cookie, dma_addr, size, dir)
+#endif
+
+#if (LINUX_VERSION_CODE < 0x020412)
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)		0
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do{} while(0)
+#define pci_unmap_len(PTR, LEN_NAME)		0
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do{} while(0)
 #endif
 
 
@@ -266,7 +278,7 @@
 #define dev_kfree_skb_irq(a)			dev_kfree_skb(a)
 #define netif_wake_queue(dev)			clear_bit(0, &dev->tbusy)
 #define netif_stop_queue(dev)			set_bit(0, &dev->tbusy)
-#define late_stop_netif_stop_queue(dev)		{do{} while(0);}
+#define late_stop_netif_stop_queue(dev)		do{} while(0)
 #define early_stop_netif_stop_queue(dev)	test_and_set_bit(0,&dev->tbusy)
 #define early_stop_netif_wake_queue(dev)	netif_wake_queue(dev)
 
@@ -280,7 +292,7 @@
 #define ace_mark_net_bh()			mark_bh(NET_BH)
 #define netif_queue_stopped(dev)		dev->tbusy
 #define netif_running(dev)			dev->start
-#define ace_if_down(dev)			{do{dev->start = 0;} while(0);}
+#define ace_if_down(dev)			do{dev->start = 0;} while(0)
 
 #define tasklet_struct				tq_struct
 static inline void tasklet_schedule(struct tasklet_struct *tasklet)
@@ -298,13 +310,13 @@
 	tasklet->routine = (void (*)(void *))func;
 	tasklet->data = (void *)data;
 }
-#define tasklet_kill(tasklet)			{do{} while(0);}
+#define tasklet_kill(tasklet)			do{} while(0)
 #else
 #define late_stop_netif_stop_queue(dev)		netif_stop_queue(dev)
 #define early_stop_netif_stop_queue(dev)	0
-#define early_stop_netif_wake_queue(dev)	{do{} while(0);}
-#define ace_mark_net_bh()			{do{} while(0);}
-#define ace_if_down(dev)			{do{} while(0);}
+#define early_stop_netif_wake_queue(dev)	do{} while(0)
+#define ace_mark_net_bh()			do{} while(0)
+#define ace_if_down(dev)			do{} while(0)
 #endif
 
 #if (LINUX_VERSION_CODE >= 0x02031b)
@@ -320,7 +332,7 @@
 
 #ifndef ARCH_HAS_PREFETCHW
 #ifndef prefetchw
-#define prefetchw(x)				{do{} while(0);}
+#define prefetchw(x)				do{} while(0)
 #endif
 #endif
 
@@ -575,7 +587,7 @@
 static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
 
 static char version[] __initdata = 
-  "acenic.c: v0.89 03/15/2002  Jes Sorensen, linux-acenic@SunSITE.dk\n"
+  "acenic.c: v0.92 08/05/2002  Jes Sorensen, linux-acenic@SunSITE.dk\n"
   "                            http://home.cern.ch/~jes/gige/acenic.html\n";
 
 static struct net_device *root_dev;
@@ -673,6 +685,11 @@
 			printk(version);
 		}
 
+		if (pci_enable_device(pdev)) {
+			kfree(dev);
+			continue;
+		}
+
 		/*
 		 * Enable master mode before we start playing with the
 		 * pci_command word since pci_set_master() will modify
@@ -722,11 +739,12 @@
 					"Gigabit Ethernet", sizeof (ap->name));
 				printk(KERN_INFO "%s: Farallon PN9100-T ",
 				       dev->name);
-				break;
+			} else {
+				strncpy(ap->name, "AceNIC Gigabit Ethernet",
+					sizeof (ap->name));
+				printk(KERN_INFO "%s: Alteon AceNIC ",
+				       dev->name);
 			}
-			strncpy(ap->name, "AceNIC Gigabit Ethernet",
-				sizeof (ap->name));
-			printk(KERN_INFO "%s: Alteon AceNIC ", dev->name);
 			break;
 		case PCI_VENDOR_ID_3COM:
 			strncpy(ap->name, "3Com 3C985 Gigabit Ethernet",
@@ -862,6 +880,7 @@
 		 * This clears any pending interrupts
 		 */
 		writel(1, &regs->Mb0Lo);
+		readl(&regs->CpuCtrl);	/* flush */
 
 		/*
 		 * Make sure no other CPUs are processing interrupts
@@ -872,7 +891,7 @@
 		 * Then release the RX buffers - jumbo buffers were
 		 * already released in ace_close().
 		 */
-		synchronize_irq();
+		ace_sync_irq(root_dev->irq);
 
 		for (i = 0; i < RX_STD_RING_ENTRIES; i++) {
 			struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb;
@@ -1154,34 +1173,30 @@
 	 * to any crashes involving the NIC
 	 */
 	writel(HW_RESET | (HW_RESET << 24), &regs->HostCtrl);
-	wmb();
+	readl(&regs->HostCtrl);		/* PCI write posting */
+	udelay(5);
 
 	/*
-	 * Don't access any other registes before this point!
+	 * Don't access any other registers before this point!
 	 */
 #ifdef __BIG_ENDIAN
 	/*
 	 * This will most likely need BYTE_SWAP once we switch
 	 * to using __raw_writel()
 	 */
-#ifdef __parisc__
-	writel((WORD_SWAP | BYTE_SWAP | CLR_INT |
-		((WORD_SWAP | BYTE_SWAP | CLR_INT) << 24)),
-	       &regs->HostCtrl);
-#else
 	writel((WORD_SWAP | CLR_INT | ((WORD_SWAP | CLR_INT) << 24)),
 	       &regs->HostCtrl);
-#endif
 #else
 	writel((CLR_INT | WORD_SWAP | ((CLR_INT | WORD_SWAP) << 24)),
 	       &regs->HostCtrl);
 #endif
-	mb();
+	readl(&regs->HostCtrl);		/* PCI write posting */
 
 	/*
 	 * Stop the NIC CPU and clear pending interrupts
 	 */
 	writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
+	readl(&regs->CpuCtrl);		/* PCI write posting */
 	writel(0, &regs->Mb0Lo);
 
 	tig_ver = readl(&regs->HostCtrl) >> 28;
@@ -1202,6 +1217,7 @@
 		       tig_ver, tigon2FwReleaseMajor, tigon2FwReleaseMinor,
 		       tigon2FwReleaseFix);
 		writel(readl(&regs->CpuBCtrl) | CPU_HALT, &regs->CpuBCtrl);
+		readl(&regs->CpuBCtrl);		/* PCI write posting */
 		/*
 		 * The SRAM bank size does _not_ indicate the amount
 		 * of memory on the card, it controls the _bank_ size!
@@ -1233,7 +1249,7 @@
 	writel(ACE_BYTE_SWAP_DMA | ACE_WARN | ACE_FATAL |
 	       ACE_WORD_SWAP_BD | ACE_NO_JUMBO_FRAG, &regs->ModeStat);
 #endif
-	mb();
+	readl(&regs->ModeStat);		/* PCI write posting */
 
 	mac1 = 0;
 	for(i = 0; i < 4; i++) {
@@ -1371,7 +1387,7 @@
 	tmp &= ~DMA_READ_WRITE_MASK;
 	tmp |= DMA_READ_MAX_128;
 	/*
-	 * All the docs sy MUST NOT. Well, I did.
+	 * All the docs say MUST NOT. Well, I did.
 	 * Nothing terrible happens, if we load wrong size.
 	 * Bit w&i still works better!
 	 */
@@ -1381,6 +1397,13 @@
 
 #if 0
 	/*
+	 * The Host PCI bus controller driver has to set FBB.
+	 * If all devices on that PCI bus support FBB, then the controller
+	 * can enable FBB support in the Host PCI Bus controller (or on
+	 * the PCI-PCI bridge if that applies).
+	 * -ggg
+	 */
+	/*
 	 * I have received reports from people having problems when this
 	 * bit is enabled.
 	 */
@@ -1461,9 +1484,9 @@
 	set_aceaddr(&info->evt_ctrl.rngptr, ap->evt_ring_dma);
 	info->evt_ctrl.flags = 0;
 
-	set_aceaddr(&info->evt_prd_ptr, ap->evt_prd_dma);
 	*(ap->evt_prd) = 0;
 	wmb();
+	set_aceaddr(&info->evt_prd_ptr, ap->evt_prd_dma);
 	writel(0, &regs->EvtCsm);
 
 	set_aceaddr(&info->cmd_ctrl.rngptr, 0x100);
@@ -1595,7 +1618,13 @@
 
 	writel(0, &regs->MaskInt);
 	writel(1, &regs->IfIdx);
+#if 0
+	/*
+	 * McKinley boxes do not like us fiddling with AssistState
+	 * this early
+	 */
 	writel(1, &regs->AssistState);
+#endif
 
 	writel(DEF_STAT, &regs->TuneStatTicks);
 	writel(DEF_TRACE, &regs->TuneTrace);
@@ -1705,10 +1734,19 @@
 	 */
 	memset(&ap->stats, 0, sizeof(ap->stats));
 
+       /*
+	* Enable DMA engine now.
+	* If we do this sooner, Mckinley box pukes.
+	* I assume it's because Tigon II DMA engine wants to check
+	* *something* even before the CPU is started.
+	*/
+       writel(1, &regs->AssistState);  /* enable DMA */
+
 	/*
 	 * Start the NIC CPU
 	 */
 	writel(readl(&regs->CpuCtrl) & ~(CPU_HALT|CPU_TRACE), &regs->CpuCtrl);
+	readl(&regs->CpuCtrl);
 
 	/*
 	 * Wait for the firmware to spin up - max 3 seconds.
@@ -1721,6 +1759,7 @@
 
 		ace_dump_trace(ap);
 		writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
+		readl(&regs->CpuCtrl);
 
 		/* aman@sgi.com - account for badly behaving firmware/NIC:
 		 * - have observed that the NIC may continue to generate
@@ -1735,6 +1774,7 @@
 			writel(readl(&regs->CpuBCtrl) | CPU_HALT,
 			       &regs->CpuBCtrl);
 		writel(0, &regs->Mb0Lo);
+		readl(&regs->Mb0Lo);
 
 		ecode = -EBUSY;
 		goto init_error;
@@ -2409,6 +2449,7 @@
 	 * threads and it is wrong even for that case.
 	 */
 	writel(0, &regs->Mb0Lo);
+	readl(&regs->Mb0Lo);
 
 	/*
 	 * There is no conflict between transmit handling in
@@ -2512,12 +2553,13 @@
 	struct ace_private *ap = dev->priv;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	local_irq_save(flags);
+	ace_mask_irq(dev);
 
 	ap->vlgrp = grp;
 
-	restore_flags(flags);
+	ace_unmask_irq(dev);
+	local_irq_restore(flags);
 }
 
 
@@ -2526,13 +2568,14 @@
 	struct ace_private *ap = dev->priv;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	local_irq_save(flags);
+	ace_mask_irq(dev);
 
 	if (ap->vlgrp)
 		ap->vlgrp->vlan_devices[vid] = NULL;
 
-	restore_flags(flags);
+	ace_unmask_irq(dev);
+	local_irq_restore(flags);
 }
 #endif /* ACENIC_DO_VLAN */
 
@@ -2636,8 +2679,9 @@
 	 * Make sure one CPU is not processing packets while
 	 * buffers are being released by another.
 	 */
-	save_flags(flags);
-	cli();
+
+	local_irq_save(flags);
+	ace_mask_irq(dev);
 
 	for (i = 0; i < ACE_TX_RING_ENTRIES(ap); i++) {
 		struct sk_buff *skb;
@@ -2674,7 +2718,8 @@
 		ace_issue_cmd(regs, &cmd);
 	}
 
-	restore_flags(flags);
+	ace_unmask_irq(dev);
+	local_irq_restore(flags);
 
 	ACE_MOD_DEC_USE_COUNT;
 	return 0;
@@ -2893,7 +2938,7 @@
 		}
 	} else {
 		while (test_and_set_bit(0, &ap->jumbo_refill_busy));
-		synchronize_irq();
+		ace_sync_irq(dev->irq);
 		ace_set_rxtx_parms(dev, 0);
 		if (ap->jumbo) {
 			struct cmd cmd;
@@ -3275,22 +3320,27 @@
 {
 	u32 local;
 
+	readl(&regs->LocalCtrl);
 	udelay(ACE_SHORT_DELAY);
 	local = readl(&regs->LocalCtrl);
 	local |= EEPROM_DATA_OUT | EEPROM_WRITE_ENABLE;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	local |= EEPROM_CLK_OUT;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	local &= ~EEPROM_DATA_OUT;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	local &= ~EEPROM_CLK_OUT;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 }
 
@@ -3305,6 +3355,7 @@
 	local &= ~EEPROM_DATA_OUT;
 	local |= EEPROM_WRITE_ENABLE;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 
 	for (i = 0; i < 8; i++, magic <<= 1) {
@@ -3314,15 +3365,18 @@
 		else
 			local &= ~EEPROM_DATA_OUT;
 		writel(local, &regs->LocalCtrl);
+		readl(&regs->LocalCtrl);
 		mb();
 
 		udelay(ACE_SHORT_DELAY);
 		local |= EEPROM_CLK_OUT;
 		writel(local, &regs->LocalCtrl);
+		readl(&regs->LocalCtrl);
 		mb();
 		udelay(ACE_SHORT_DELAY);
 		local &= ~(EEPROM_CLK_OUT | EEPROM_DATA_OUT);
 		writel(local, &regs->LocalCtrl);
+		readl(&regs->LocalCtrl);
 		mb();
 	}
 }
@@ -3336,10 +3390,12 @@
 	local = readl(&regs->LocalCtrl);
 	local &= ~EEPROM_WRITE_ENABLE;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_LONG_DELAY);
 	local |= EEPROM_CLK_OUT;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	/* sample data in middle of high clk */
@@ -3347,6 +3403,7 @@
 	udelay(ACE_SHORT_DELAY);
 	mb();
 	writel(readl(&regs->LocalCtrl) & ~EEPROM_CLK_OUT, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 
 	return state;
@@ -3361,18 +3418,22 @@
 	local = readl(&regs->LocalCtrl);
 	local |= EEPROM_WRITE_ENABLE;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	local &= ~EEPROM_DATA_OUT;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	local |= EEPROM_CLK_OUT;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	local |= EEPROM_DATA_OUT;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_LONG_DELAY);
 	local &= ~EEPROM_CLK_OUT;
@@ -3405,14 +3466,13 @@
 	 * Don't take interrupts on this CPU will bit banging
 	 * the %#%#@$ I2C device
 	 */
-	__save_flags(flags);
-	__cli();
+	local_irq_save(flags);
 
 	eeprom_start(regs);
 
 	eeprom_prep(regs, EEPROM_WRITE_SELECT);
 	if (eeprom_check_ack(regs)) {
-		__restore_flags(flags);
+		local_irq_restore(flags);
 		printk(KERN_ERR "%s: Unable to sync eeprom\n", dev->name);
 		result = -EIO;
 		goto eeprom_read_error;
@@ -3420,7 +3480,7 @@
 
 	eeprom_prep(regs, (offset >> 8) & 0xff);
 	if (eeprom_check_ack(regs)) {
-		__restore_flags(flags);
+		local_irq_restore(flags);
 		printk(KERN_ERR "%s: Unable to set address byte 0\n",
 		       dev->name);
 		result = -EIO;
@@ -3429,7 +3489,7 @@
 
 	eeprom_prep(regs, offset & 0xff);
 	if (eeprom_check_ack(regs)) {
-		__restore_flags(flags);
+		local_irq_restore(flags);
 		printk(KERN_ERR "%s: Unable to set address byte 1\n",
 		       dev->name);
 		result = -EIO;
@@ -3439,7 +3499,7 @@
 	eeprom_start(regs);
 	eeprom_prep(regs, EEPROM_READ_SELECT);
 	if (eeprom_check_ack(regs)) {
-		__restore_flags(flags);
+		local_irq_restore(flags);
 		printk(KERN_ERR "%s: Unable to set READ_SELECT\n",
 		       dev->name);
 		result = -EIO;
@@ -3450,10 +3510,12 @@
 		local = readl(&regs->LocalCtrl);
 		local &= ~EEPROM_WRITE_ENABLE;
 		writel(local, &regs->LocalCtrl);
+		readl(&regs->LocalCtrl);
 		udelay(ACE_LONG_DELAY);
 		mb();
 		local |= EEPROM_CLK_OUT;
 		writel(local, &regs->LocalCtrl);
+		readl(&regs->LocalCtrl);
 		mb();
 		udelay(ACE_SHORT_DELAY);
 		/* sample data mid high clk */
@@ -3464,11 +3526,13 @@
 		local = readl(&regs->LocalCtrl);
 		local &= ~EEPROM_CLK_OUT;
 		writel(local, &regs->LocalCtrl);
+		readl(&regs->LocalCtrl);
 		udelay(ACE_SHORT_DELAY);
 		mb();
 		if (i == 7) {
 			local |= EEPROM_WRITE_ENABLE;
 			writel(local, &regs->LocalCtrl);
+			readl(&regs->LocalCtrl);
 			mb();
 			udelay(ACE_SHORT_DELAY);
 		}
@@ -3476,16 +3540,19 @@
 
 	local |= EEPROM_DATA_OUT;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	writel(readl(&regs->LocalCtrl) | EEPROM_CLK_OUT, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	udelay(ACE_LONG_DELAY);
 	writel(readl(&regs->LocalCtrl) & ~EEPROM_CLK_OUT, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	eeprom_stop(regs);
 
-	__restore_flags(flags);
+	local_irq_restore(flags);
  out:
 	return result;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/acenic.h linux-2.4.20/drivers/net/acenic.h
--- linux-2.4.19/drivers/net/acenic.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/acenic.h	2002-10-29 11:18:40.000000000 +0000
@@ -748,6 +748,32 @@
 }
 
 
+static inline void ace_mask_irq(struct net_device *dev)
+{
+	struct ace_private *ap = dev->priv;
+	struct ace_regs *regs = ap->regs;
+
+	if (ACE_IS_TIGON_I(ap))
+		writel(1, &regs->MaskInt);
+	else
+		writel(readl(&regs->HostCtrl) | MASK_INTS, &regs->HostCtrl);
+
+	ace_sync_irq(dev->irq);
+}
+
+
+static inline void ace_unmask_irq(struct net_device *dev)
+{
+	struct ace_private *ap = dev->priv;
+	struct ace_regs *regs = ap->regs;
+ 
+	if (ACE_IS_TIGON_I(ap))
+		writel(0, &regs->MaskInt);
+	else
+		writel(readl(&regs->HostCtrl) & ~MASK_INTS, &regs->HostCtrl);
+}
+
+
 /*
  * Prototypes
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/aironet4500_rid.c linux-2.4.20/drivers/net/aironet4500_rid.c
--- linux-2.4.19/drivers/net/aironet4500_rid.c	2000-03-10 17:43:04.000000000 +0000
+++ linux-2.4.20/drivers/net/aironet4500_rid.c	2002-10-29 11:18:36.000000000 +0000
@@ -20,7 +20,7 @@
 #define awc_RID_gen_RidLen 				{(const struct aironet4500_rid_selector *)&aironet4500_RID_Select_General_Config,0x0000, 8,1,1,1,0, 0xffffffff,0x0000, "Length of RID" }
 #define awc_RID_gen_OperatingMode_adhoc 		{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0000,"Opmode IBSS Adhoc operation" } // Without AP
 #define awc_RID_gen_OperatingMode_Infrastructure 	{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0001,"Opmode Infrastructure Station operation" }// With AP
-#define awc_RID_gen_OperatingMode_AP			{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0002,"Opmode Access Point" } // Aironet doesnt release info on use 
+#define awc_RID_gen_OperatingMode_AP			{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0002,"Opmode Access Point" } // Aironet doesn't release info on use 
 #define awc_RID_gen_OperatingMode_AP_and_repeater 	{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0003,"Opmode Access Point and Repeater" } // no info
 #define awc_RID_gen_OperatingMode_No_payload_modify	{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000100,0x0100,"Opmode Payload without modify" } 
 #define awc_RID_gen_OperatingMode_LLC_802_3_convert	{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000100,0x0000,"Opmode LLC -> 802.3 convert" }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/appletalk/Config.in linux-2.4.20/drivers/net/appletalk/Config.in
--- linux-2.4.19/drivers/net/appletalk/Config.in	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/appletalk/Config.in	2002-10-29 11:18:31.000000000 +0000
@@ -6,8 +6,10 @@
 comment 'Appletalk devices'
 dep_mbool 'Appletalk interfaces support' CONFIG_DEV_APPLETALK $CONFIG_ATALK
 if [ "$CONFIG_DEV_APPLETALK" = "y" ]; then
-   tristate '  Apple/Farallon LocalTalk PC support' CONFIG_LTPC
-   tristate '  COPS LocalTalk PC support' CONFIG_COPS
+   if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" ]; then
+      tristate '  Apple/Farallon LocalTalk PC support' CONFIG_LTPC
+      tristate '  COPS LocalTalk PC support' CONFIG_COPS
+   fi
    if [ "$CONFIG_COPS" != "n" ]; then
       bool '    Dayna firmware support' CONFIG_COPS_DAYNA
       bool '    Tangent firmware support' CONFIG_COPS_TANGENT
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/arcnet/arcnet.c linux-2.4.20/drivers/net/arcnet/arcnet.c
--- linux-2.4.19/drivers/net/arcnet/arcnet.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/arcnet/arcnet.c	2002-10-29 11:18:49.000000000 +0000
@@ -186,7 +186,7 @@
 void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc)
 {
 	int i;
-	long flags;
+	unsigned long flags;
 
 	save_flags(flags);
 	cli();
@@ -212,7 +212,7 @@
 {
 	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
 	int i, length;
-	long flags;
+	unsigned long flags;
 	static uint8_t buf[512];
 
 	save_flags(flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/at1700.c linux-2.4.20/drivers/net/at1700.c
--- linux-2.4.19/drivers/net/at1700.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/at1700.c	2002-10-29 11:18:38.000000000 +0000
@@ -811,7 +811,7 @@
 	int ioaddr = dev->base_addr;
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned char mc_filter[8];		 /* Multicast hash filter */
-	long flags;
+	unsigned long flags;
 	int i;
 
 	if (dev->flags & IFF_PROMISC) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/atarilance.c linux-2.4.20/drivers/net/atarilance.c
--- linux-2.4.19/drivers/net/atarilance.c	2001-10-17 04:56:29.000000000 +0000
+++ linux-2.4.20/drivers/net/atarilance.c	2002-10-29 11:18:34.000000000 +0000
@@ -920,7 +920,7 @@
 #ifndef final_version
 			if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
 				DPRINTK( 0, ( "out-of-sync dirty pointer,"
-							  " %d vs. %d, full=%d.\n",
+							  " %d vs. %d, full=%ld.\n",
 							  dirty_tx, lp->cur_tx, lp->tx_full ));
 				dirty_tx += TX_RING_SIZE;
 			}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/au1000_eth.c linux-2.4.20/drivers/net/au1000_eth.c
--- linux-2.4.19/drivers/net/au1000_eth.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/au1000_eth.c	2002-10-29 11:18:31.000000000 +0000
@@ -114,9 +114,12 @@
   au1500_iflist[NUM_INTERFACES] = {
 		{AU1500_ETH0_BASE, AU1000_ETH0_IRQ}, 
 		{AU1500_ETH1_BASE, AU1000_ETH1_IRQ}
+	},
+  au1100_iflist[NUM_INTERFACES] = {
+		{AU1000_ETH0_BASE, AU1000_ETH0_IRQ}, 
+		{NULL, NULL}
 	};
 
-
 static char version[] __devinitdata =
     "au1000eth.c:1.0 ppopov@mvista.com\n";
 
@@ -168,6 +171,11 @@
 	data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;
 	mdio_write(dev, phy_addr, MII_CONTROL, data);
 
+	/* Enable TX LED instead of FDX */
+	data = mdio_read(dev, phy_addr, MII_INT);
+	data &= ~MII_FDX_LED;
+	mdio_write(dev, phy_addr, MII_INT, data);
+
 	if (au1000_debug > 4) dump_mii(dev, phy_addr);
 	return 0;
 }
@@ -241,6 +249,8 @@
 	/* restart auto-negotiation */
 	mdio_write(dev, phy_addr, 0, 0x3200);
 
+	mdelay(1);
+
 	/* set up LEDs to correct display */
 	mdio_write(dev, phy_addr, 17, 0xffc0);
 
@@ -359,6 +369,7 @@
 	{"Broadcom BCM5201 10/100 BaseT PHY",  0x0040, 0x6212, &bcm_5201_ops },
 	{"AMD 79C901 HomePNA PHY",  0x0000, 0x35c8, &am79c901_ops },
 	{"LSI 80227 10/100 BaseT PHY", 0x0016, 0xf840, &lsi_80227_ops },
+	{"Broadcom BCM5221 10/100 BaseT PHY",  0x0040, 0x61e4, &bcm_5201_ops },
 	{0,},
 };
 
@@ -629,14 +640,20 @@
 		} else if ( (prid & 0xffff0000) == 0x01030000 ) {
 			base_addr = au1500_iflist[i].port;
 			irq = au1500_iflist[i].irq;
+		} else if ( (prid & 0xffff0000) == 0x02030000 ) {
+			base_addr = au1100_iflist[i].port;
+			irq = au1100_iflist[i].irq;
 		} else {
 			printk(KERN_ERR "au1000 eth: unknown Processor ID\n");
 			return -ENODEV;
 		}
+		// check for valid entries, au1100 only has one entry
+		if (base_addr && irq) {
 		if (au1000_probe1(NULL, base_addr, irq, i) != 0) {
 			return -ENODEV;
 		}
 	}
+	}
 	return 0;
 }
 
@@ -811,9 +828,9 @@
 				MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS));
 	if (dev->priv != NULL)
 		kfree(dev->priv);
-	kfree(dev);
 	printk(KERN_ERR "%s: au1000_probe1 failed.  Returns %d\n",
 	       dev->name, retval);
+	kfree(dev);
 	return retval;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/au1000_eth.h linux-2.4.20/drivers/net/au1000_eth.h
--- linux-2.4.19/drivers/net/au1000_eth.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/au1000_eth.h	2002-10-29 11:18:36.000000000 +0000
@@ -33,7 +33,7 @@
 #define ETH_TX_TIMEOUT HZ/4
 #define MAC_MIN_PKT_SIZE 64
 
-#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1500)
+#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
 #define PHY_ADDRESS              0
 #define PHY_CONTROL_DEFAULT 0x3000
 #define PHY_CONTROL_REG_ADDR     0
@@ -57,6 +57,7 @@
 #define MII_LSI_CONFIG 0x0011
 #define MII_LSI_STAT   0x0012
 #define MII_AUX_CNTRL  0x0018
+#define MII_INT        0x001A
 
 /* mii registers specific to AMD 79C901 */
 #define	MII_STATUS_SUMMARY = 0x0018
@@ -122,14 +123,15 @@
 
 /* lsi status register */
 
-#define MII_LSI_STAT_FDX	0x0008
-#define MII_LSI_STAT_SPD	0x0010
+#define MII_LSI_STAT_FDX	0x0040
+#define MII_LSI_STAT_SPD	0x0080
 
 /* Auxilliary Control/Status Register */
 #define MII_AUX_FDX      0x0001
 #define MII_AUX_100      0x0002
 #define MII_AUX_F100     0x0004
 #define MII_AUX_ANEG     0x0008
+#define MII_FDX_LED	 0x8000
 
 typedef struct mii_phy {
 	struct mii_phy * next;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/bonding.c linux-2.4.20/drivers/net/bonding.c
--- linux-2.4.19/drivers/net/bonding.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/bonding.c	2002-10-29 11:18:38.000000000 +0000
@@ -176,6 +176,21 @@
  *              Steve Mead <steve.mead at comdev dot cc>
  *     - Port Gleb Natapov's multicast support patchs from 2.4.12
  *       to 2.4.18 adding support for multicast.
+ *
+ * 2002/06/17 - Tony Cureington <tony.cureington * hp_com>
+ *     - corrected uninitialized pointer (ifr.ifr_data) in bond_check_dev_link;
+ *       actually changed function to use ETHTOOL, then MIIPHY, and finally
+ *       MIIREG to determine the link status
+ *     - fixed bad ifr_data pointer assignments in bond_ioctl
+ *     - corrected mode 1 being reported as active-backup in bond_get_info;
+ *       also added text to distinguish type of load balancing (rr or xor)
+ *     - change arp_ip_target module param from "1-12s" (array of 12 ptrs)
+ *       to "s" (a single ptr)
+ *
+ * 2002/09/18 - Jay Vosburgh <fubar at us dot ibm dot com>
+ *     - Fixed up bond_check_dev_link() (and callers): removed some magic
+ *	 numbers, banished local MII_ defines, wrapped ioctl calls to
+ *	 prevent EFAULT errors
  */
 
 #include <linux/config.h>
@@ -210,21 +225,15 @@
 #include <linux/smp.h>
 #include <linux/if_ether.h>
 #include <linux/if_arp.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+
 
 /* monitor all links that often (in milliseconds). <=0 disables monitoring */
 #ifndef BOND_LINK_MON_INTERV
 #define BOND_LINK_MON_INTERV	0
 #endif
 
-#undef  MII_LINK_UP
-#define MII_LINK_UP	0x04
-
-#undef  MII_ENDOF_NWAY
-#define MII_ENDOF_NWAY	0x20
-
-#undef  MII_LINK_READY
-#define MII_LINK_READY	(MII_LINK_UP)
-
 #ifndef BOND_LINK_ARP_INTERV
 #define BOND_LINK_ARP_INTERV	0
 #endif
@@ -253,7 +262,7 @@
 MODULE_PARM(mode, "i");
 MODULE_PARM(arp_interval, "i");
 MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
-MODULE_PARM(arp_ip_target, "1-12s");
+MODULE_PARM(arp_ip_target, "s");
 MODULE_PARM_DESC(arp_ip_target, "arp target in n.n.n.n form");
 MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor");
 MODULE_PARM(updelay, "i");
@@ -374,33 +383,75 @@
 	return slave;
 }
 
+/*
+ * Less bad way to call ioctl from within the kernel; this needs to be
+ * done some other way to get the call out of interrupt context.
+ * Needs "ioctl" variable to be supplied by calling context.
+ */
+#define IOCTL(dev, arg, cmd) ({		\
+	int ret;			\
+	mm_segment_t fs = get_fs();	\
+	set_fs(get_ds());		\
+	ret = ioctl(dev, arg, cmd);	\
+	set_fs(fs);			\
+	ret; })
+
 /* 
- * if <dev> supports MII link status reporting, check its link
- * and report it as a bit field in a short int :
- *   - 0x04 means link is up,
- *   - 0x20 means end of autonegociation
- * If the device doesn't support MII, then we only report 0x24,
- * meaning that the link is up and running since we can't check it.
+ * if <dev> supports MII link status reporting, check its link status.
+ *
+ * Return either BMSR_LSTATUS, meaning that the link is up (or we
+ * can't tell and just pretend it is), or 0, meaning that the link is
+ * down.
  */
 static u16 bond_check_dev_link(struct net_device *dev)
 {
 	static int (* ioctl)(struct net_device *, struct ifreq *, int);
 	struct ifreq ifr;
-	u16 *data = (u16 *)&ifr.ifr_data;
-		
-	/* data[0] automagically filled by the ioctl */
-	data[1] = 1; /* MII location 1 reports Link Status */
+	struct mii_ioctl_data *mii;
+	struct ethtool_value etool;
+
+	ioctl = dev->do_ioctl;
+	if (ioctl) {
+		/* TODO: set pointer to correct ioctl on a per team member */
+		/*       bases to make this more efficient. that is, once  */
+		/*       we determine the correct ioctl, we will always    */
+		/*       call it and not the others for that team          */
+		/*       member.                                           */
+
+		/* try SOICETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */
+		/* for a period of time; we need to encourage link status  */
+		/* be reported by network drivers in real time; if the     */
+		/* value is cached, the mmimon module parm may have no     */
+		/* effect...                                               */
+	        etool.cmd = ETHTOOL_GLINK;
+	        ifr.ifr_data = (char*)&etool;
+		if (IOCTL(dev, &ifr, SIOCETHTOOL) == 0) {
+			if (etool.data == 1) {
+				return BMSR_LSTATUS;
+			} 
+			else { 
+				return(0);
+			} 
+		}
+
+		/*
+		 * We cannot assume that SIOCGMIIPHY will also read a
+		 * register; not all network drivers support that.
+		 */
+
+		/* Yes, the mii is overlaid on the ifreq.ifr_ifru */
+		mii = (struct mii_ioctl_data *)&ifr.ifr_data;
+		if (IOCTL(dev, &ifr, SIOCGMIIPHY) != 0) {
+			return BMSR_LSTATUS;	 /* can't tell */
+		}
+
+		mii->reg_num = MII_BMSR;
+		if (IOCTL(dev, &ifr, SIOCGMIIREG) == 0) {
+			return mii->val_out & BMSR_LSTATUS;
+		}
 
-	if (((ioctl = dev->do_ioctl) != NULL) &&  /* ioctl to access MII */
-	    (ioctl(dev, &ifr, SIOCGMIIPHY) == 0)) {
-		/* now, data[3] contains info about link status :
-		   - data[3] & 0x04 means link up
-		   - data[3] & 0x20 means end of auto-negociation
-		*/
-		return data[3];
-	} else {
-		return MII_LINK_READY;  /* spoof link up ( we can't check it) */
 	}
+	return BMSR_LSTATUS;  /* spoof link up ( we can't check it) */
 }
 
 static u16 bond_check_mii_link(bonding_t *bond)
@@ -414,7 +465,7 @@
 	read_unlock(&bond->ptrlock);
 	read_unlock_irqrestore(&bond->lock, flags);
 
-	return (has_active_interface ? MII_LINK_READY : 0);
+	return (has_active_interface ? BMSR_LSTATUS : 0);
 }
 
 static int bond_open(struct net_device *dev)
@@ -598,12 +649,6 @@
 	 */
 	write_lock_irqsave(&bond->lock, flags);
 
-	/*
-	 * Lock the master device so that noone trys to transmit
-	 * while we're changing things
-	 */
-	spin_lock_bh(&master->xmit_lock);
-
 	/* set promiscuity flag to slaves */
 	if ( (master->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC) )
 		bond_set_promiscuity(bond, 1); 
@@ -637,7 +682,6 @@
 	bond_mc_list_destroy (bond);
 	bond_mc_list_copy (master->mc_list, bond, GFP_KERNEL);
 
-	spin_unlock_bh(&master->xmit_lock);
 	write_unlock_irqrestore(&bond->lock, flags);
 }
 
@@ -759,8 +803,8 @@
 	new_slave->link_failure_count = 0;
 
 	/* check for initial state */
-	if ((miimon <= 0) || ((bond_check_dev_link(slave_dev) & MII_LINK_READY)
-		 == MII_LINK_READY)) {
+	if ((miimon <= 0) ||
+	    (bond_check_dev_link(slave_dev) == BMSR_LSTATUS)) {
 #ifdef BONDING_DEBUG
 		printk(KERN_CRIT "Initial state of slave_dev is BOND_LINK_UP\n");
 #endif
@@ -1182,7 +1226,7 @@
 
 		switch (slave->link) {
 		case BOND_LINK_UP:	/* the link was up */
-			if ((link_state & MII_LINK_UP) == MII_LINK_UP) {
+			if (link_state == BMSR_LSTATUS) {
 				/* link stays up, tell that this one
 				   is immediately available */
 				if (IS_UP(dev) && (mindelay > -2)) {
@@ -1218,7 +1262,7 @@
 			   ensure proper action to be taken
 			*/
 		case BOND_LINK_FAIL:	/* the link has just gone down */
-			if ((link_state & MII_LINK_UP) == 0) {
+			if (link_state != BMSR_LSTATUS) {
 				/* link stays down */
 				if (slave->delay <= 0) {
 					/* link down for too long time */
@@ -1247,7 +1291,7 @@
 				} else {
 					slave->delay--;
 				}
-			} else if ((link_state & MII_LINK_READY) == MII_LINK_READY) {
+			} else {
 				/* link up again */
 				slave->link  = BOND_LINK_UP;
 				printk(KERN_INFO
@@ -1266,7 +1310,7 @@
 			}
 			break;
 		case BOND_LINK_DOWN:	/* the link was down */
-			if ((link_state & MII_LINK_READY) != MII_LINK_READY) {
+			if (link_state != BMSR_LSTATUS) {
 				/* the link stays down, nothing more to do */
 				break;
 			} else {	/* link going up */
@@ -1288,7 +1332,7 @@
 			   case there's something to do.
 			*/
 		case BOND_LINK_BACK:	/* the link has just come back */
-			if ((link_state & MII_LINK_UP) == 0) {
+			if (link_state != BMSR_LSTATUS) {
 				/* link down again */
 				slave->link  = BOND_LINK_DOWN;
 				printk(KERN_INFO
@@ -1297,8 +1341,7 @@
 					master->name,
 					(updelay - slave->delay) * miimon,
 					dev->name);
-			}
-			else if ((link_state & MII_LINK_READY) == MII_LINK_READY) {
+			} else {
 				/* link stays up */
 				if (slave->delay == 0) {
 					/* now the link has been up for long time enough */
@@ -1707,7 +1750,7 @@
 
 	switch (cmd) {
 	case SIOCGMIIPHY:
-		data = (u16 *)&ifr->ifr_data;
+		data = (u16 *)ifr->ifr_data;
 		if (data == NULL) {
 			return -EINVAL;
 		}
@@ -1718,7 +1761,7 @@
 		 * We do this again just in case we were called by SIOCGMIIREG
 		 * instead of SIOCGMIIPHY.
 		 */
-		data = (u16 *)&ifr->ifr_data;
+		data = (u16 *)ifr->ifr_data;
 		if (data == NULL) {
 			return -EINVAL;
 		}
@@ -2035,7 +2078,28 @@
 		link = bond_check_mii_link(bond);
 
 		len += sprintf(buf + len, "Bonding Mode: ");
-		len += sprintf(buf + len, "%s\n", mode ? "active-backup" : "load balancing");
+
+		switch (mode) {
+			case BOND_MODE_ACTIVEBACKUP:
+				len += sprintf(buf + len, "%s\n", 
+						"active-backup");
+			break;
+
+			case BOND_MODE_ROUNDROBIN:
+				len += sprintf(buf + len, "%s\n", 
+						"load balancing (round-robin)");
+			break;
+
+			case BOND_MODE_XOR:
+				len += sprintf(buf + len, "%s\n", 
+						"load balancing (xor)");
+			break;
+
+			default:
+				len += sprintf(buf + len, "%s\n", 
+						"unknown");
+			break;
+		}
 
 		if (mode == BOND_MODE_ACTIVEBACKUP) {
 			read_lock_irqsave(&bond->lock, flags);
@@ -2051,7 +2115,7 @@
 
 		len += sprintf(buf + len, "MII Status: ");
 		len += sprintf(buf + len, 
-				link == MII_LINK_READY ? "up\n" : "down\n");
+				link == BMSR_LSTATUS ? "up\n" : "down\n");
 		len += sprintf(buf + len, "MII Polling Interval (ms): %d\n", 
 				miimon);
 		len += sprintf(buf + len, "Up Delay (ms): %d\n", updelay);
@@ -2282,7 +2346,32 @@
 	}
 	memset(dev_bonds, 0, max_bonds*sizeof(struct net_device));
 
+	if (updelay < 0) {
+		printk(KERN_WARNING 
+		       "bonding_init(): updelay module parameter (%d), "
+		       "not in range 0-%d, so it was reset to 0\n",
+		       updelay, INT_MAX);
+		updelay = 0;
+	}
+
+	if (downdelay < 0) {
+		printk(KERN_WARNING 
+		       "bonding_init(): downdelay module parameter (%d), "
+		       "not in range 0-%d, so it was reset to 0\n",
+		       downdelay, INT_MAX);
+		downdelay = 0;
+	}
+
+	if (arp_interval < 0) {
+		printk(KERN_WARNING 
+		       "bonding_init(): arp_interval module parameter (%d), "
+		       "not in range 0-%d, so it was reset to %d\n",
+		       arp_interval, INT_MAX, BOND_LINK_ARP_INTERV);
+		arp_interval = BOND_LINK_ARP_INTERV;
+	}
+
 	if (arp_ip_target) {
+		/* TODO: check and log bad ip address */
 		if (my_inet_aton(arp_ip_target, &arp_target) == 0)  {
 			arp_interval = 0;
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/cs89x0.h linux-2.4.20/drivers/net/cs89x0.h
--- linux-2.4.19/drivers/net/cs89x0.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/cs89x0.h	2002-10-29 11:18:33.000000000 +0000
@@ -385,11 +385,11 @@
 #define A_CNF_10B_T 0x0001
 #define A_CNF_AUI 0x0002
 #define A_CNF_10B_2 0x0004
-#define A_CNF_MEDIA_TYPE 0x0060
-#define A_CNF_MEDIA_AUTO 0x0000
+#define A_CNF_MEDIA_TYPE 0x0070
+#define A_CNF_MEDIA_AUTO 0x0070
 #define A_CNF_MEDIA_10B_T 0x0020
 #define A_CNF_MEDIA_AUI 0x0040
-#define A_CNF_MEDIA_10B_2 0x0060
+#define A_CNF_MEDIA_10B_2 0x0010
 #define A_CNF_DC_DC_POLARITY 0x0080
 #define A_CNF_NO_AUTO_POLARITY 0x2000
 #define A_CNF_LOW_RX_SQUELCH 0x4000
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/de600.c linux-2.4.20/drivers/net/de600.c
--- linux-2.4.19/drivers/net/de600.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.20/drivers/net/de600.c	2002-10-29 11:18:39.000000000 +0000
@@ -718,7 +718,7 @@
 adapter_init(struct net_device *dev)
 {
 	int	i;
-	long flags;
+	unsigned long flags;
 
 	save_flags(flags);
 	cli();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/declance.c linux-2.4.20/drivers/net/declance.c
--- linux-2.4.19/drivers/net/declance.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/declance.c	2002-10-29 11:18:32.000000000 +0000
@@ -43,8 +43,10 @@
  */
 
 #include <linux/config.h>
+#include <linux/crc32.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
+#include <linux/if_ether.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -60,7 +62,7 @@
 #include <asm/dec/kn01.h>
 #include <asm/dec/machtype.h>
 #include <asm/dec/tc.h>
-#include <asm/wbflush.h>
+#include <asm/system.h>
 
 static char version[] __devinitdata =
 "declance.c: v0.009 by Linux MIPS DECstation task force\n";
@@ -81,9 +83,6 @@
 unsigned long dmaptr;
 #endif
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL	/* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL	/* Ethernet CRC, little endian */
-
 #define LE_CSR0 0
 #define LE_CSR1 1
 #define LE_CSR2 2
@@ -290,7 +289,7 @@
 static inline void writereg(volatile unsigned short *regptr, short value)
 {
 	*regptr = value;
-	wbflush();
+	iob();
 }
 
 /* Load the CSR registers */
@@ -370,7 +369,7 @@
 		}
 	}
 
-	wbflush();
+	iob();
 }
 
 void cp_from_buf(const int type, void *to, const void *from, int len)
@@ -498,7 +497,7 @@
 		if (i < 3 && ZERO)
 			printk("%d: 0x%8.8x(0x%8.8x)\n", i, leptr, (int) lp->rx_buf_ptr_cpu[i]);
 	}
-	wbflush();
+	iob();
 }
 
 static int init_restart_lance(struct lance_private *lp)
@@ -795,7 +794,7 @@
 			return -EAGAIN;
 		}
 		/* Enable I/O ASIC LANCE DMA.  */
-		wbflush();
+		fast_wmb();
 		ioasic_write(SSR, ioasic_read(SSR) | LANCE_DMA_EN);
 	}
 
@@ -824,7 +823,7 @@
 	if (lp->dma_irq >= 0) {
 		/* Disable I/O ASIC LANCE DMA.  */
 		ioasic_write(SSR, ioasic_read(SSR) & ~LANCE_DMA_EN);
-		wbflush();
+		fast_iob();
 		free_irq(lp->dma_irq, dev);
 	}
 	free_irq(dev->irq, dev);
@@ -921,7 +920,7 @@
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
 	int i, j, bit, byte;
-	u32 crc, poly = CRC_POLYNOMIAL_LE;
+	u32 crc;
 
 	/* set all multicast bits */
 	if (dev->flags & IFF_ALLMULTI) {
@@ -946,19 +945,7 @@
 		if (!(*addrs & 1))
 			continue;
 
-		crc = 0xffffffff;
-		for (byte = 0; byte < 6; byte++)
-			for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-				int test;
-
-				test = ((bit ^ crc) & 0x01);
-				crc >>= 1;
-
-				if (test) {
-					crc = crc ^ poly;
-				}
-			}
-
+		crc = ether_crc_le(ETH_ALEN, addrs);
 		crc = crc >> 26;
 		mcast_table[2 * (crc >> 4)] |= 1 << (crc & 0xf);
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/depca.c linux-2.4.20/drivers/net/depca.c
--- linux-2.4.19/drivers/net/depca.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/depca.c	2002-10-29 11:18:48.000000000 +0000
@@ -268,8 +268,7 @@
 
 #include "depca.h"
 
-static char version[] __initdata =
-	"depca.c:v0.53 2001/1/12 davies@maniac.ultranet.com\n";
+static char version[] __initdata = "depca.c:v0.53 2001/1/12 davies@maniac.ultranet.com\n";
 
 #ifdef DEPCA_DEBUG
 static int depca_debug = DEPCA_DEBUG;
@@ -277,7 +276,7 @@
 static int depca_debug = 1;
 #endif
 
-#define DEPCA_NDA 0xffe0            /* No Device Address */
+#define DEPCA_NDA 0xffe0	/* No Device Address */
 
 #define TX_TIMEOUT (1*HZ)
 
@@ -294,15 +293,15 @@
 **
 ** total_memory = NUM_RX_DESC*(8+RX_BUFF_SZ) + NUM_TX_DESC*(8+TX_BUFF_SZ)
 */
-#define NUM_RX_DESC     8               /* Number of RX descriptors */
-#define NUM_TX_DESC     8               /* Number of TX descriptors */
-#define RX_BUFF_SZ	1536            /* Buffer size for each Rx buffer */
-#define TX_BUFF_SZ	1536            /* Buffer size for each Tx buffer */
+#define NUM_RX_DESC     8	/* Number of RX descriptors */
+#define NUM_TX_DESC     8	/* Number of TX descriptors */
+#define RX_BUFF_SZ	1536	/* Buffer size for each Rx buffer */
+#define TX_BUFF_SZ	1536	/* Buffer size for each Tx buffer */
 
 /*
 ** EISA bus defines
 */
-#define DEPCA_EISA_IO_PORTS 0x0c00       /* I/O port base address, slot 0 */
+#define DEPCA_EISA_IO_PORTS 0x0c00	/* I/O port base address, slot 0 */
 #define MAX_EISA_SLOTS 16
 #define EISA_SLOT_INC 0x1000
 
@@ -329,7 +328,7 @@
                          "DE422",\
                          ""}
 static enum {
-  DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown
+	DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown
 } adapter;
 
 /*
@@ -344,78 +343,78 @@
 ** DESC_ALIGN. ALIGN aligns the start address of the private memory area
 ** and hence the RX descriptor ring's first entry. 
 */
-#define ALIGN4      ((u_long)4 - 1)       /* 1 longword align */
-#define ALIGN8      ((u_long)8 - 1)       /* 2 longword (quadword) align */
-#define ALIGN         ALIGN8              /* Keep the LANCE happy... */
+#define ALIGN4      ((u_long)4 - 1)	/* 1 longword align */
+#define ALIGN8      ((u_long)8 - 1)	/* 2 longword (quadword) align */
+#define ALIGN         ALIGN8	/* Keep the LANCE happy... */
 
 /*
 ** The DEPCA Rx and Tx ring descriptors. 
 */
 struct depca_rx_desc {
-    volatile s32 base;
-    s16 buf_length;		/* This length is negative 2's complement! */
-    s16 msg_length;		/* This length is "normal". */
+	volatile s32 base;
+	s16 buf_length;		/* This length is negative 2's complement! */
+	s16 msg_length;		/* This length is "normal". */
 };
 
 struct depca_tx_desc {
-    volatile s32 base;
-    s16 length;		        /* This length is negative 2's complement! */
-    s16 misc;                   /* Errors and TDR info */
+	volatile s32 base;
+	s16 length;		/* This length is negative 2's complement! */
+	s16 misc;		/* Errors and TDR info */
 };
 
-#define LA_MASK 0x0000ffff      /* LANCE address mask for mapping network RAM
+#define LA_MASK 0x0000ffff	/* LANCE address mask for mapping network RAM
 				   to LANCE memory address space */
 
 /*
 ** The Lance initialization block, described in databook, in common memory.
 */
 struct depca_init {
-    u16 mode;	                /* Mode register */
-    u8  phys_addr[ETH_ALEN];	/* Physical ethernet address */
-    u8  mcast_table[8];	        /* Multicast Hash Table. */
-    u32 rx_ring;     	        /* Rx ring base pointer & ring length */
-    u32 tx_ring;	        /* Tx ring base pointer & ring length */
+	u16 mode;		/* Mode register */
+	u8 phys_addr[ETH_ALEN];	/* Physical ethernet address */
+	u8 mcast_table[8];	/* Multicast Hash Table. */
+	u32 rx_ring;		/* Rx ring base pointer & ring length */
+	u32 tx_ring;		/* Tx ring base pointer & ring length */
 };
 
 #define DEPCA_PKT_STAT_SZ 16
-#define DEPCA_PKT_BIN_SZ  128                /* Should be >=100 unless you
-                                                increase DEPCA_PKT_STAT_SZ */
+#define DEPCA_PKT_BIN_SZ  128	/* Should be >=100 unless you
+				   increase DEPCA_PKT_STAT_SZ */
 struct depca_private {
-    char devname[DEPCA_STRLEN];    /* Device Product String                  */
-    char adapter_name[DEPCA_STRLEN];/* /proc/ioports string                  */
-    char adapter;                  /* Adapter type                           */
-    char mca_slot;                 /* MCA slot, if MCA else -1               */
-    struct depca_init	init_block;/* Shadow Initialization block            */
+	char devname[DEPCA_STRLEN];	/* Device Product String                  */
+	char adapter_name[DEPCA_STRLEN];	/* /proc/ioports string                  */
+	char adapter;		/* Adapter type                           */
+	char mca_slot;		/* MCA slot, if MCA else -1               */
+	struct depca_init init_block;	/* Shadow Initialization block            */
 /* CPU address space fields */
-    struct depca_rx_desc *rx_ring; /* Pointer to start of RX descriptor ring */
-    struct depca_tx_desc *tx_ring; /* Pointer to start of TX descriptor ring */
-    void *rx_buff[NUM_RX_DESC];    /* CPU virt address of sh'd memory buffs  */
-    void *tx_buff[NUM_TX_DESC];    /* CPU virt address of sh'd memory buffs  */
-    void *sh_mem;                  /* CPU mapped virt address of device RAM  */
+	struct depca_rx_desc *rx_ring;	/* Pointer to start of RX descriptor ring */
+	struct depca_tx_desc *tx_ring;	/* Pointer to start of TX descriptor ring */
+	void *rx_buff[NUM_RX_DESC];	/* CPU virt address of sh'd memory buffs  */
+	void *tx_buff[NUM_TX_DESC];	/* CPU virt address of sh'd memory buffs  */
+	void *sh_mem;		/* CPU mapped virt address of device RAM  */
 /* Device address space fields */
-    u_long device_ram_start;       /* Start of RAM in device addr space      */
+	u_long device_ram_start;	/* Start of RAM in device addr space      */
 /* Offsets used in both address spaces */
-    u_long rx_ring_offset;         /* Offset from start of RAM to rx_ring    */
-    u_long tx_ring_offset;         /* Offset from start of RAM to tx_ring    */
-    u_long buffs_offset;	   /* LANCE Rx and Tx buffers start address. */
+	u_long rx_ring_offset;	/* Offset from start of RAM to rx_ring    */
+	u_long tx_ring_offset;	/* Offset from start of RAM to tx_ring    */
+	u_long buffs_offset;	/* LANCE Rx and Tx buffers start address. */
 /* Kernel-only (not device) fields */
-    int	rx_new, tx_new;		   /* The next free ring entry               */
-    int rx_old, tx_old;	           /* The ring entries to be free()ed.       */
-    struct net_device_stats stats;
-    spinlock_t lock;
-    struct {                       /* Private stats counters                 */
-	u32 bins[DEPCA_PKT_STAT_SZ];
-	u32 unicast;
-	u32 multicast;
-	u32 broadcast;
-	u32 excessive_collisions;
-	u32 tx_underruns;
-	u32 excessive_underruns;
-    } pktStats;
-    int txRingMask;                /* TX ring mask                           */
-    int rxRingMask;                /* RX ring mask                           */
-    s32 rx_rlen;                   /* log2(rxRingMask+1) for the descriptors */
-    s32 tx_rlen;                   /* log2(txRingMask+1) for the descriptors */
+	int rx_new, tx_new;	/* The next free ring entry               */
+	int rx_old, tx_old;	/* The ring entries to be free()ed.       */
+	struct net_device_stats stats;
+	spinlock_t lock;
+	struct {		/* Private stats counters                 */
+		u32 bins[DEPCA_PKT_STAT_SZ];
+		u32 unicast;
+		u32 multicast;
+		u32 broadcast;
+		u32 excessive_collisions;
+		u32 tx_underruns;
+		u32 excessive_underruns;
+	} pktStats;
+	int txRingMask;		/* TX ring mask                           */
+	int rxRingMask;		/* RX ring mask                           */
+	s32 rx_rlen;		/* log2(rxRingMask+1) for the descriptors */
+	s32 tx_rlen;		/* log2(txRingMask+1) for the descriptors */
 };
 
 /*
@@ -432,61 +431,61 @@
 /*
 ** Public Functions
 */
-static int    depca_open(struct net_device *dev);
-static int    depca_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void   depca_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int    depca_close(struct net_device *dev);
-static int    depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void   depca_tx_timeout (struct net_device *dev);
+static int depca_open(struct net_device *dev);
+static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void depca_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int depca_close(struct net_device *dev);
+static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void depca_tx_timeout(struct net_device *dev);
 static struct net_device_stats *depca_get_stats(struct net_device *dev);
-static void   set_multicast_list(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
 
 /*
 ** Private functions
 */
-static int    depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot);
-static void   depca_init_ring(struct net_device *dev);
-static int    depca_rx(struct net_device *dev);
-static int    depca_tx(struct net_device *dev);
-
-static void   LoadCSRs(struct net_device *dev);
-static int    InitRestartDepca(struct net_device *dev);
-static void   DepcaSignature(char *name, u_long paddr);
-static int    DevicePresent(u_long ioaddr);
-static int    get_hw_addr(struct net_device *dev);
-static int    EISA_signature(char *name, s32 eisa_id);
-static void   SetMulticastFilter(struct net_device *dev);
-static void   isa_probe(struct net_device *dev, u_long iobase);
-static void   eisa_probe(struct net_device *dev, u_long iobase);
-#ifdef CONFIG_MCA      
-static void   mca_probe(struct net_device *dev, u_long iobase);
+static int depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot);
+static void depca_init_ring(struct net_device *dev);
+static int depca_rx(struct net_device *dev);
+static int depca_tx(struct net_device *dev);
+
+static void LoadCSRs(struct net_device *dev);
+static int InitRestartDepca(struct net_device *dev);
+static void DepcaSignature(char *name, u_long paddr);
+static int DevicePresent(u_long ioaddr);
+static int get_hw_addr(struct net_device *dev);
+static int EISA_signature(char *name, s32 eisa_id);
+static void SetMulticastFilter(struct net_device *dev);
+static void isa_probe(struct net_device *dev, u_long iobase);
+static void eisa_probe(struct net_device *dev, u_long iobase);
+#ifdef CONFIG_MCA
+static void mca_probe(struct net_device *dev, u_long iobase);
 #endif
 static struct net_device *alloc_device(struct net_device *dev, u_long iobase);
-static int    depca_dev_index(char *s);
-static struct net_device *insert_device(struct net_device *dev, u_long iobase, int (*init)(struct net_device *));
-static int    load_packet(struct net_device *dev, struct sk_buff *skb);
-static void   depca_dbg_open(struct net_device *dev);
+static int depca_dev_index(char *s);
+static struct net_device *insert_device(struct net_device *dev, u_long iobase, int (*init) (struct net_device *));
+static int load_packet(struct net_device *dev, struct sk_buff *skb);
+static void depca_dbg_open(struct net_device *dev);
 
 #ifdef MODULE
-int           init_module(void);
-void          cleanup_module(void);
-static int    autoprobed = 1, loading_module = 1;
+int init_module(void);
+void cleanup_module(void);
+static int autoprobed = 1, loading_module = 1;
 # else
-static u_char de1xx_irq[] __initdata = {2,3,4,5,7,9,0};
-static u_char de2xx_irq[] __initdata = {5,9,10,11,15,0};
-static u_char de422_irq[] __initdata = {5,9,10,11,0};
+static u_char de1xx_irq[] __initdata = { 2, 3, 4, 5, 7, 9, 0 };
+static u_char de2xx_irq[] __initdata = { 5, 9, 10, 11, 15, 0 };
+static u_char de422_irq[] __initdata = { 5, 9, 10, 11, 0 };
 static u_char *depca_irq;
-static int    autoprobed, loading_module;
-#endif /* MODULE */
+static int autoprobed, loading_module;
+#endif				/* MODULE */
 
-static char   name[DEPCA_STRLEN];
-static int    num_depcas, num_eth;
-static int    mem;                       /* For loadable module assignment
-                                              use insmod mem=0x????? .... */
-static char   *adapter_name; /* = '\0';     If no PROM when loadable module
-					      use insmod adapter_name=DE??? ...
-					      bss initializes this to zero
-					   */
+static char name[DEPCA_STRLEN];
+static int num_depcas, num_eth;
+static int mem;			/* For loadable module assignment
+				   use insmod mem=0x????? .... */
+static char *adapter_name;	/* = '\0';     If no PROM when loadable module
+				   use insmod adapter_name=DE??? ...
+				   bss initializes this to zero
+				 */
 /*
 ** Miscellaneous defines...
 */
@@ -494,49 +493,48 @@
     outw(CSR0, DEPCA_ADDR);\
     outw(STOP, DEPCA_DATA)
 
-int __init 
-depca_probe(struct net_device *dev)
+int __init depca_probe(struct net_device *dev)
 {
-  int tmp = num_depcas, status = -ENODEV;
-  u_long iobase = dev->base_addr;
+	int tmp = num_depcas, status = -ENODEV;
+	u_long iobase = dev->base_addr;
 
-  SET_MODULE_OWNER(dev);
+	SET_MODULE_OWNER(dev);
 
-  if ((iobase == 0) && loading_module){
-    printk("Autoprobing is not supported when loading a module based driver.\n");
-    status = -EIO;
-  } else {
-#ifdef CONFIG_MCA      
-    mca_probe(dev, iobase);
+	if ((iobase == 0) && loading_module) {
+		printk("Autoprobing is not supported when loading a module based driver.\n");
+		status = -EIO;
+	} else {
+#ifdef CONFIG_MCA
+		mca_probe(dev, iobase);
 #endif
-    isa_probe(dev, iobase);
-    eisa_probe(dev, iobase);
+		isa_probe(dev, iobase);
+		eisa_probe(dev, iobase);
 
-    if ((tmp == num_depcas) && (iobase != 0) && loading_module) {
-      printk("%s: depca_probe() cannot find device at 0x%04lx.\n", dev->name, 
-	                                                               iobase);
-    }
-
-    /*
-    ** Walk the device list to check that at least one device
-    ** initialised OK
-    */
-    for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next);
+		if ((tmp == num_depcas) && (iobase != 0) && loading_module) {
+			printk("%s: depca_probe() cannot find device at 0x%04lx.\n", dev->name, iobase);
+		}
 
-    if (dev->priv) status = 0;
-    if (iobase == 0) autoprobed = 1;
-  }
+		/*
+		   ** Walk the device list to check that at least one device
+		   ** initialised OK
+		 */
+		for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next);
+
+		if (dev->priv)
+			status = 0;
+		if (iobase == 0)
+			autoprobed = 1;
+	}
 
-  return status;
+	return status;
 }
 
-static int __init 
-depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot)
+static int __init depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot)
 {
 	struct depca_private *lp;
-	int i, j, offset, netRAM, mem_len, status=0;
+	int i, j, offset, netRAM, mem_len, status = 0;
 	s16 nicsr;
-	u_long mem_start=0, mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
+	u_long mem_start = 0, mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
 
 	STOP_DEPCA;
 
@@ -554,19 +552,17 @@
 		DepcaSignature(name, mem_start);
 	} while (!mem && mem_base[mem_chkd] && (adapter == unknown));
 
-	if ((adapter == unknown) || !mem_start) { /* DEPCA device not found */
+	if ((adapter == unknown) || !mem_start) {	/* DEPCA device not found */
 		return -ENXIO;
 	}
 
 	dev->base_addr = ioaddr;
 
 	if (mca_slot != -1) {
-		printk("%s: %s at 0x%04lx (MCA slot %d)", dev->name, name, 
-		                                          ioaddr, mca_slot);
-	} else if ((ioaddr & 0x0fff) == DEPCA_EISA_IO_PORTS) { /* EISA slot address */
-		printk("%s: %s at 0x%04lx (EISA slot %d)", 
-		       dev->name, name, ioaddr, (int)((ioaddr>>12)&0x0f));
-	} else {                             /* ISA port address */
+		printk("%s: %s at 0x%04lx (MCA slot %d)", dev->name, name, ioaddr, mca_slot);
+	} else if ((ioaddr & 0x0fff) == DEPCA_EISA_IO_PORTS) {	/* EISA slot address */
+		printk("%s: %s at 0x%04lx (EISA slot %d)", dev->name, name, ioaddr, (int) ((ioaddr >> 12) & 0x0f));
+	} else {		/* ISA port address */
 		printk("%s: %s at 0x%04lx", dev->name, name, ioaddr);
 	}
 
@@ -576,7 +572,7 @@
 		printk("      which has an Ethernet PROM CRC error.\n");
 		return -ENXIO;
 	}
-	for (i=0; i<ETH_ALEN - 1; i++) { /* get the ethernet address */
+	for (i = 0; i < ETH_ALEN - 1; i++) {	/* get the ethernet address */
 		printk("%2.2x:", dev->dev_addr[i]);
 	}
 	printk("%2.2x", dev->dev_addr[i]);
@@ -587,19 +583,16 @@
 		netRAM = 128;
 	offset = 0x0000;
 
-	/* Shared Memory Base Address */ 
+	/* Shared Memory Base Address */
 	if (nicsr & BUF) {
-		offset = 0x8000;        /* 32kbyte RAM offset*/
-		nicsr &= ~BS;           /* DEPCA RAM in top 32k */
+		offset = 0x8000;	/* 32kbyte RAM offset */
+		nicsr &= ~BS;	/* DEPCA RAM in top 32k */
 		netRAM -= 32;
 	}
-	mem_start += offset;            /* (E)ISA start address */
-	if ((mem_len = (NUM_RX_DESC*(sizeof(struct depca_rx_desc)+RX_BUFF_SZ) +
-			NUM_TX_DESC*(sizeof(struct depca_tx_desc)+TX_BUFF_SZ) +
-			sizeof(struct depca_init)))
-	    > (netRAM<<10)) {
-		printk(",\n       requests %dkB RAM: only %dkB is available!\n",
-		        (mem_len >> 10), netRAM);
+	mem_start += offset;	/* (E)ISA start address */
+	if ((mem_len = (NUM_RX_DESC * (sizeof(struct depca_rx_desc) + RX_BUFF_SZ) + NUM_TX_DESC * (sizeof(struct depca_tx_desc) + TX_BUFF_SZ) + sizeof(struct depca_init)))
+	    > (netRAM << 10)) {
+		printk(",\n       requests %dkB RAM: only %dkB is available!\n", (mem_len >> 10), netRAM);
 		return -ENXIO;
 	}
 
@@ -610,21 +603,20 @@
 		nicsr |= SHE;
 		outb(nicsr, DEPCA_NICSR);
 	}
- 
+
 	/* Define the device private memory */
 	dev->priv = (void *) kmalloc(sizeof(struct depca_private), GFP_KERNEL);
 	if (dev->priv == NULL)
 		return -ENOMEM;
-	lp = (struct depca_private *)dev->priv;
-	memset((char *)dev->priv, 0, sizeof(struct depca_private));
+	lp = (struct depca_private *) dev->priv;
+	memset((char *) dev->priv, 0, sizeof(struct depca_private));
 	lp->adapter = adapter;
 	lp->mca_slot = mca_slot;
 	lp->lock = SPIN_LOCK_UNLOCKED;
- 	sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
+	sprintf(lp->adapter_name, "%s (%s)", name, dev->name);
 	status = -EBUSY;
 	if (!request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name)) {
-		printk(KERN_ERR "depca: I/O resource 0x%x @ 0x%lx busy\n",
-		       DEPCA_TOTAL_SIZE, ioaddr);
+		printk(KERN_ERR "depca: I/O resource 0x%x @ 0x%lx busy\n", DEPCA_TOTAL_SIZE, ioaddr);
 		goto out_priv;
 	}
 
@@ -636,17 +628,17 @@
 		goto out_region;
 	}
 	lp->device_ram_start = mem_start & LA_MASK;
-	
+
 	offset = 0;
 	offset += sizeof(struct depca_init);
 
 	/* Tx & Rx descriptors (aligned to a quadword boundary) */
 	offset = (offset + ALIGN) & ~ALIGN;
-	lp->rx_ring = (struct depca_rx_desc *)(lp->sh_mem + offset);
+	lp->rx_ring = (struct depca_rx_desc *) (lp->sh_mem + offset);
 	lp->rx_ring_offset = offset;
 
 	offset += (sizeof(struct depca_rx_desc) * NUM_RX_DESC);
-	lp->tx_ring = (struct depca_tx_desc *)(lp->sh_mem + offset);
+	lp->tx_ring = (struct depca_tx_desc *) (lp->sh_mem + offset);
 	lp->tx_ring_offset = offset;
 
 	offset += (sizeof(struct depca_tx_desc) * NUM_TX_DESC);
@@ -658,14 +650,14 @@
 	lp->txRingMask = NUM_TX_DESC - 1;
 
 	/* Calculate Tx/Rx RLEN size for the descriptors. */
-	for (i=0, j = lp->rxRingMask; j>0; i++) {
+	for (i = 0, j = lp->rxRingMask; j > 0; i++) {
 		j >>= 1;
 	}
-	lp->rx_rlen = (s32)(i << 29);
-	for (i=0, j = lp->txRingMask; j>0; i++) {
+	lp->rx_rlen = (s32) (i << 29);
+	for (i = 0, j = lp->txRingMask; j > 0; i++) {
 		j >>= 1;
 	}
-	lp->tx_rlen = (s32)(i << 29);
+	lp->tx_rlen = (s32) (i << 29);
 
 	/* Load the initialisation block */
 	depca_init_ring(dev);
@@ -674,7 +666,7 @@
 	LoadCSRs(dev);
 
 	/* Enable DEPCA board interrupts for autoprobing */
-	nicsr = ((nicsr & ~IM)|IEN);
+	nicsr = ((nicsr & ~IM) | IEN);
 	outb(nicsr, DEPCA_NICSR);
 
 	/* To auto-IRQ we enable the initialization-done and DMA err,
@@ -705,26 +697,26 @@
 
 		/* Trigger an initialization just for the interrupt. */
 		outw(INEA | INIT, DEPCA_DATA);
-	  
+
 		irqnum = autoirq_report(1);
 		status = -ENXIO;
 		if (!irqnum) {
 			printk(" and failed to detect IRQ line.\n");
 			goto out_region;
 		} else {
-			for (dev->irq=0,i=0; (depca_irq[i]) && (!dev->irq); i++)
+			for (dev->irq = 0, i = 0; (depca_irq[i]) && (!dev->irq); i++)
 				if (irqnum == depca_irq[i]) {
 					dev->irq = irqnum;
 					printk(" and uses IRQ%d.\n", dev->irq);
 				}
-	      
+
 			status = -ENXIO;
 			if (!dev->irq) {
 				printk(" but incorrect IRQ line detected.\n");
 				goto out_region;
 			}
 		}
-#endif /* MODULE */
+#endif				/* MODULE */
 	} else {
 		printk(" and assigned IRQ%d.\n", dev->irq);
 	}
@@ -748,65 +740,63 @@
 	/* Fill in the generic field of the device structure. */
 	ether_setup(dev);
 	return 0;
-out_region:
+      out_region:
 	release_region(ioaddr, DEPCA_TOTAL_SIZE);
-out_priv:
+      out_priv:
 	kfree(dev->priv);
 	dev->priv = NULL;
 	return status;
 }
-
 
-static int
-depca_open(struct net_device *dev)
+
+static int depca_open(struct net_device *dev)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  u_long ioaddr = dev->base_addr;
-  s16 nicsr;
-  int status = 0;
-
-  STOP_DEPCA;
-  nicsr = inb(DEPCA_NICSR);
-
-  /* Make sure the shadow RAM is enabled */
-  if (lp->adapter != DEPCA) {
-    nicsr |= SHE;
-    outb(nicsr, DEPCA_NICSR);
-  }
-
-  /* Re-initialize the DEPCA... */
-  depca_init_ring(dev);
-  LoadCSRs(dev);
-
-  depca_dbg_open(dev);
-
-  if (request_irq(dev->irq, &depca_interrupt, 0, lp->adapter_name, dev)) {
-    printk("depca_open(): Requested IRQ%d is busy\n",dev->irq);
-    status = -EAGAIN;
-  } else {
-
-    /* Enable DEPCA board interrupts and turn off LED */
-    nicsr = ((nicsr & ~IM & ~LED)|IEN);
-    outb(nicsr, DEPCA_NICSR);
-    outw(CSR0,DEPCA_ADDR);
-    
-    netif_start_queue(dev);
-    
-    status = InitRestartDepca(dev);
-
-    if (depca_debug > 1){
-      printk("CSR0: 0x%4.4x\n",inw(DEPCA_DATA));
-      printk("nicsr: 0x%02x\n",inb(DEPCA_NICSR));
-    }
-  }
-  return status;
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	u_long ioaddr = dev->base_addr;
+	s16 nicsr;
+	int status = 0;
+
+	STOP_DEPCA;
+	nicsr = inb(DEPCA_NICSR);
+
+	/* Make sure the shadow RAM is enabled */
+	if (lp->adapter != DEPCA) {
+		nicsr |= SHE;
+		outb(nicsr, DEPCA_NICSR);
+	}
+
+	/* Re-initialize the DEPCA... */
+	depca_init_ring(dev);
+	LoadCSRs(dev);
+
+	depca_dbg_open(dev);
+
+	if (request_irq(dev->irq, &depca_interrupt, 0, lp->adapter_name, dev)) {
+		printk("depca_open(): Requested IRQ%d is busy\n", dev->irq);
+		status = -EAGAIN;
+	} else {
+
+		/* Enable DEPCA board interrupts and turn off LED */
+		nicsr = ((nicsr & ~IM & ~LED) | IEN);
+		outb(nicsr, DEPCA_NICSR);
+		outw(CSR0, DEPCA_ADDR);
+
+		netif_start_queue(dev);
+
+		status = InitRestartDepca(dev);
+
+		if (depca_debug > 1) {
+			printk("CSR0: 0x%4.4x\n", inw(DEPCA_DATA));
+			printk("nicsr: 0x%02x\n", inb(DEPCA_NICSR));
+		}
+	}
+	return status;
 }
 
 /* Initialize the lance Rx and Tx descriptor rings. */
-static void
-depca_init_ring(struct net_device *dev)
+static void depca_init_ring(struct net_device *dev)
 {
-	struct depca_private *lp = (struct depca_private *)dev->priv;
+	struct depca_private *lp = (struct depca_private *) dev->priv;
 	u_int i;
 	u_long offset;
 
@@ -818,17 +808,15 @@
 
 	/* Initialize the base address and length of each buffer in the ring */
 	for (i = 0; i <= lp->rxRingMask; i++) {
-		offset = lp->buffs_offset + i*RX_BUFF_SZ;
-		writel((lp->device_ram_start + offset) | R_OWN,
-		       &lp->rx_ring[i].base);
+		offset = lp->buffs_offset + i * RX_BUFF_SZ;
+		writel((lp->device_ram_start + offset) | R_OWN, &lp->rx_ring[i].base);
 		writew(-RX_BUFF_SZ, &lp->rx_ring[i].buf_length);
 		lp->rx_buff[i] = lp->sh_mem + offset;
 	}
 
 	for (i = 0; i <= lp->txRingMask; i++) {
-		offset = lp->buffs_offset + (i + lp->rxRingMask+1)*TX_BUFF_SZ;
-		writel((lp->device_ram_start + offset) & 0x00ffffff,
-	               &lp->tx_ring[i].base);
+		offset = lp->buffs_offset + (i + lp->rxRingMask + 1) * TX_BUFF_SZ;
+		writel((lp->device_ram_start + offset) & 0x00ffffff, &lp->tx_ring[i].base);
 		lp->tx_buff[i] = lp->sh_mem + offset;
 	}
 
@@ -842,30 +830,29 @@
 		lp->init_block.phys_addr[i] = dev->dev_addr[i];
 	}
 
-	lp->init_block.mode = 0x0000;            /* Enable the Tx and Rx */
+	lp->init_block.mode = 0x0000;	/* Enable the Tx and Rx */
 }
 
 
-static void depca_tx_timeout (struct net_device *dev)
+static void depca_tx_timeout(struct net_device *dev)
 {
 	u_long ioaddr = dev->base_addr;
 
-	printk ("%s: transmit timed out, status %04x, resetting.\n",
-		dev->name, inw (DEPCA_DATA));
+	printk("%s: transmit timed out, status %04x, resetting.\n", dev->name, inw(DEPCA_DATA));
 
 	STOP_DEPCA;
-	depca_init_ring (dev);
-	LoadCSRs (dev);
+	depca_init_ring(dev);
+	LoadCSRs(dev);
 	dev->trans_start = jiffies;
-	netif_wake_queue (dev);
-	InitRestartDepca (dev);
+	netif_wake_queue(dev);
+	InitRestartDepca(dev);
 }
 
 
 /* 
 ** Writes a socket buffer to TX descriptor ring and starts transmission 
 */
-static int depca_start_xmit (struct sk_buff *skb, struct net_device *dev)
+static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct depca_private *lp = (struct depca_private *) dev->priv;
 	u_long ioaddr = dev->base_addr;
@@ -875,32 +862,32 @@
 	if (skb->len < 1)
 		goto out;
 
-	netif_stop_queue (dev);
+	netif_stop_queue(dev);
 
 	if (TX_BUFFS_AVAIL) {	/* Fill in a Tx ring entry */
-		status = load_packet (dev, skb);
+		status = load_packet(dev, skb);
 
 		if (!status) {
 			/* Trigger an immediate send demand. */
-			outw (CSR0, DEPCA_ADDR);
-			outw (INEA | TDMD, DEPCA_DATA);
+			outw(CSR0, DEPCA_ADDR);
+			outw(INEA | TDMD, DEPCA_DATA);
 
 			dev->trans_start = jiffies;
-			dev_kfree_skb (skb);
+			dev_kfree_skb(skb);
 		}
 		if (TX_BUFFS_AVAIL)
-			netif_start_queue (dev);
+			netif_start_queue(dev);
 	} else
 		status = -1;
 
-out:
+      out:
 	return status;
 }
 
 /*
 ** The DEPCA interrupt handler. 
 */
-static void depca_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+static void depca_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
 	struct depca_private *lp;
@@ -908,308 +895,301 @@
 	u_long ioaddr;
 
 	if (dev == NULL) {
-		printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
+		printk("depca_interrupt(): irq %d for unknown device.\n", irq);
 		return;
 	}
 
 	lp = (struct depca_private *) dev->priv;
 	ioaddr = dev->base_addr;
 
-	spin_lock (&lp->lock);
+	spin_lock(&lp->lock);
 
 	/* mask the DEPCA board interrupts and turn on the LED */
-	nicsr = inb (DEPCA_NICSR);
+	nicsr = inb(DEPCA_NICSR);
 	nicsr |= (IM | LED);
-	outb (nicsr, DEPCA_NICSR);
+	outb(nicsr, DEPCA_NICSR);
 
-	outw (CSR0, DEPCA_ADDR);
-	csr0 = inw (DEPCA_DATA);
+	outw(CSR0, DEPCA_ADDR);
+	csr0 = inw(DEPCA_DATA);
 
 	/* Acknowledge all of the current interrupt sources ASAP. */
-	outw (csr0 & INTE, DEPCA_DATA);
+	outw(csr0 & INTE, DEPCA_DATA);
 
 	if (csr0 & RINT)	/* Rx interrupt (packet arrived) */
-		depca_rx (dev);
+		depca_rx(dev);
 
 	if (csr0 & TINT)	/* Tx interrupt (packet sent) */
-		depca_tx (dev);
+		depca_tx(dev);
 
 	/* Any resources available? */
 	if ((TX_BUFFS_AVAIL >= 0) && netif_queue_stopped(dev)) {
-		netif_wake_queue (dev);
+		netif_wake_queue(dev);
 	}
 
 	/* Unmask the DEPCA board interrupts and turn off the LED */
 	nicsr = (nicsr & ~IM & ~LED);
-	outb (nicsr, DEPCA_NICSR);
+	outb(nicsr, DEPCA_NICSR);
 
-	spin_unlock (&lp->lock);
+	spin_unlock(&lp->lock);
 }
 
 
-static int
-depca_rx(struct net_device *dev)
+static int depca_rx(struct net_device *dev)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  int i, entry;
-  s32 status;
-
-  for (entry=lp->rx_new; 
-       !(readl(&lp->rx_ring[entry].base) & R_OWN);
-       entry=lp->rx_new){
-    status = readl(&lp->rx_ring[entry].base) >> 16 ;
-    if (status & R_STP) {                      /* Remember start of frame */
-      lp->rx_old = entry;
-    }
-    if (status & R_ENP) {                      /* Valid frame status */
-      if (status & R_ERR) {	               /* There was an error. */
-	lp->stats.rx_errors++;                 /* Update the error stats. */
-	if (status & R_FRAM) lp->stats.rx_frame_errors++;
-	if (status & R_OFLO) lp->stats.rx_over_errors++;
-	if (status & R_CRC)  lp->stats.rx_crc_errors++;
-	if (status & R_BUFF) lp->stats.rx_fifo_errors++;
-      } else {	
-	short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4;
-	struct sk_buff *skb;
-
-	skb = dev_alloc_skb(pkt_len+2);
-	if (skb != NULL) {
-	  unsigned char *buf;
-	  skb_reserve(skb,2);               /* 16 byte align the IP header */
-	  buf = skb_put(skb,pkt_len);
-	  skb->dev = dev;
-	  if (entry < lp->rx_old) {         /* Wrapped buffer */
-	    len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ;
-	    memcpy_fromio(buf, lp->rx_buff[lp->rx_old], len);
-	    memcpy_fromio(buf + len, lp->rx_buff[0], pkt_len-len);
-	  } else {                          /* Linear buffer */
-	    memcpy_fromio(buf, lp->rx_buff[lp->rx_old], pkt_len);
-	  }
-
-	  /* 
-	  ** Notify the upper protocol layers that there is another 
-	  ** packet to handle
-	  */
-	  skb->protocol=eth_type_trans(skb,dev);
-	  netif_rx(skb);
-
-	  /*
-	  ** Update stats
-	  */
-	  dev->last_rx = jiffies;
-	  lp->stats.rx_packets++;
-	  lp->stats.rx_bytes += pkt_len;
-	  for (i=1; i<DEPCA_PKT_STAT_SZ-1; i++) {
-	    if (pkt_len < (i*DEPCA_PKT_BIN_SZ)) {
-	      lp->pktStats.bins[i]++;
-	      i = DEPCA_PKT_STAT_SZ;
-	    }
-	  }
-	  if (buf[0] & 0x01) {              /* Multicast/Broadcast */
-	    if ((*(s16 *)&buf[0] == -1) &&
-		(*(s16 *)&buf[2] == -1) &&
-		(*(s16 *)&buf[4] == -1)) {
-	      lp->pktStats.broadcast++;
-	    } else {
-	      lp->pktStats.multicast++;
-	    }
-	  } else if ((*(s16 *)&buf[0] == *(s16 *)&dev->dev_addr[0]) &&
-		     (*(s16 *)&buf[2] == *(s16 *)&dev->dev_addr[2]) &&
-		     (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) {
-	    lp->pktStats.unicast++;
-	  }
-	  
-	  lp->pktStats.bins[0]++;           /* Duplicates stats.rx_packets */
-	  if (lp->pktStats.bins[0] == 0) {  /* Reset counters */
-	    memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats));
-	  }
-	} else {
-	  printk("%s: Memory squeeze, deferring packet.\n", dev->name);
-	  lp->stats.rx_dropped++;	/* Really, deferred. */
-	  break;
-	}
-      }
-      /* Change buffer ownership for this last frame, back to the adapter */
-      for (; lp->rx_old!=entry; lp->rx_old=(++lp->rx_old)&lp->rxRingMask) {
-	writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN, 
-	                                        &lp->rx_ring[lp->rx_old].base);
-      }
-      writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base);
-    }
-
-    /*
-    ** Update entry information
-    */
-    lp->rx_new = (++lp->rx_new) & lp->rxRingMask;
-    }
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	int i, entry;
+	s32 status;
 
-    return 0;
+	for (entry = lp->rx_new; !(readl(&lp->rx_ring[entry].base) & R_OWN); entry = lp->rx_new) {
+		status = readl(&lp->rx_ring[entry].base) >> 16;
+		if (status & R_STP) {	/* Remember start of frame */
+			lp->rx_old = entry;
+		}
+		if (status & R_ENP) {	/* Valid frame status */
+			if (status & R_ERR) {	/* There was an error. */
+				lp->stats.rx_errors++;	/* Update the error stats. */
+				if (status & R_FRAM)
+					lp->stats.rx_frame_errors++;
+				if (status & R_OFLO)
+					lp->stats.rx_over_errors++;
+				if (status & R_CRC)
+					lp->stats.rx_crc_errors++;
+				if (status & R_BUFF)
+					lp->stats.rx_fifo_errors++;
+			} else {
+				short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4;
+				struct sk_buff *skb;
+
+				skb = dev_alloc_skb(pkt_len + 2);
+				if (skb != NULL) {
+					unsigned char *buf;
+					skb_reserve(skb, 2);	/* 16 byte align the IP header */
+					buf = skb_put(skb, pkt_len);
+					skb->dev = dev;
+					if (entry < lp->rx_old) {	/* Wrapped buffer */
+						len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ;
+						memcpy_fromio(buf, lp->rx_buff[lp->rx_old], len);
+						memcpy_fromio(buf + len, lp->rx_buff[0], pkt_len - len);
+					} else {	/* Linear buffer */
+						memcpy_fromio(buf, lp->rx_buff[lp->rx_old], pkt_len);
+					}
+
+					/* 
+					   ** Notify the upper protocol layers that there is another 
+					   ** packet to handle
+					 */
+					skb->protocol = eth_type_trans(skb, dev);
+					netif_rx(skb);
+
+					/*
+					   ** Update stats
+					 */
+					dev->last_rx = jiffies;
+					lp->stats.rx_packets++;
+					lp->stats.rx_bytes += pkt_len;
+					for (i = 1; i < DEPCA_PKT_STAT_SZ - 1; i++) {
+						if (pkt_len < (i * DEPCA_PKT_BIN_SZ)) {
+							lp->pktStats.bins[i]++;
+							i = DEPCA_PKT_STAT_SZ;
+						}
+					}
+					if (buf[0] & 0x01) {	/* Multicast/Broadcast */
+						if ((*(s16 *) & buf[0] == -1) && (*(s16 *) & buf[2] == -1) && (*(s16 *) & buf[4] == -1)) {
+							lp->pktStats.broadcast++;
+						} else {
+							lp->pktStats.multicast++;
+						}
+					} else if ((*(s16 *) & buf[0] == *(s16 *) & dev->dev_addr[0]) && (*(s16 *) & buf[2] == *(s16 *) & dev->dev_addr[2]) && (*(s16 *) & buf[4] == *(s16 *) & dev->dev_addr[4])) {
+						lp->pktStats.unicast++;
+					}
+
+					lp->pktStats.bins[0]++;	/* Duplicates stats.rx_packets */
+					if (lp->pktStats.bins[0] == 0) {	/* Reset counters */
+						memset((char *) &lp->pktStats, 0, sizeof(lp->pktStats));
+					}
+				} else {
+					printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+					lp->stats.rx_dropped++;	/* Really, deferred. */
+					break;
+				}
+			}
+			/* Change buffer ownership for this last frame, back to the adapter */
+			for (; lp->rx_old != entry; lp->rx_old = (++lp->rx_old) & lp->rxRingMask) {
+				writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN, &lp->rx_ring[lp->rx_old].base);
+			}
+			writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base);
+		}
+
+		/*
+		   ** Update entry information
+		 */
+		lp->rx_new = (++lp->rx_new) & lp->rxRingMask;
+	}
+
+	return 0;
 }
 
 /*
 ** Buffer sent - check for buffer errors.
 */
-static int
-depca_tx(struct net_device *dev)
+static int depca_tx(struct net_device *dev)
+{
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	int entry;
+	s32 status;
+	u_long ioaddr = dev->base_addr;
+
+	for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
+		status = readl(&lp->tx_ring[entry].base) >> 16;
+
+		if (status < 0) {	/* Packet not yet sent! */
+			break;
+		} else if (status & T_ERR) {	/* An error occurred. */
+			status = readl(&lp->tx_ring[entry].misc);
+			lp->stats.tx_errors++;
+			if (status & TMD3_RTRY)
+				lp->stats.tx_aborted_errors++;
+			if (status & TMD3_LCAR)
+				lp->stats.tx_carrier_errors++;
+			if (status & TMD3_LCOL)
+				lp->stats.tx_window_errors++;
+			if (status & TMD3_UFLO)
+				lp->stats.tx_fifo_errors++;
+			if (status & (TMD3_BUFF | TMD3_UFLO)) {
+				/* Trigger an immediate send demand. */
+				outw(CSR0, DEPCA_ADDR);
+				outw(INEA | TDMD, DEPCA_DATA);
+			}
+		} else if (status & (T_MORE | T_ONE)) {
+			lp->stats.collisions++;
+		} else {
+			lp->stats.tx_packets++;
+		}
+
+		/* Update all the pointers */
+		lp->tx_old = (++lp->tx_old) & lp->txRingMask;
+	}
+
+	return 0;
+}
+
+static int depca_close(struct net_device *dev)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  int entry;
-  s32 status;
-  u_long ioaddr = dev->base_addr;
-
-  for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
-    status = readl(&lp->tx_ring[entry].base) >> 16 ;
-
-    if (status < 0) {                          /* Packet not yet sent! */
-      break;
-    } else if (status & T_ERR) {               /* An error occurred. */
-      status = readl(&lp->tx_ring[entry].misc);
-      lp->stats.tx_errors++;
-      if (status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
-      if (status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
-      if (status & TMD3_LCOL) lp->stats.tx_window_errors++;
-      if (status & TMD3_UFLO) lp->stats.tx_fifo_errors++;
-      if (status & (TMD3_BUFF | TMD3_UFLO)) {
-	/* Trigger an immediate send demand. */
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	s16 nicsr;
+	u_long ioaddr = dev->base_addr;
+
+	netif_stop_queue(dev);
+
 	outw(CSR0, DEPCA_ADDR);
-	outw(INEA | TDMD, DEPCA_DATA);
-      }
-    } else if (status & (T_MORE | T_ONE)) {
-      lp->stats.collisions++;
-    } else {
-      lp->stats.tx_packets++;
-    }
-
-    /* Update all the pointers */
-    lp->tx_old = (++lp->tx_old) & lp->txRingMask;
-  }
-
-  return 0;
-}
-
-static int
-depca_close(struct net_device *dev)
-{
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  s16 nicsr;
-  u_long ioaddr = dev->base_addr;
-
-  netif_stop_queue(dev);
-
-  outw(CSR0, DEPCA_ADDR);
-
-  if (depca_debug > 1) {
-    printk("%s: Shutting down ethercard, status was %2.2x.\n",
-	   dev->name, inw(DEPCA_DATA));
-  }
-
-  /* 
-  ** We stop the DEPCA here -- it occasionally polls
-  ** memory if we don't. 
-  */
-  outw(STOP, DEPCA_DATA);
-
-  /*
-  ** Give back the ROM in case the user wants to go to DOS
-  */
-  if (lp->adapter != DEPCA) {
-    nicsr = inb(DEPCA_NICSR);
-    nicsr &= ~SHE;
-    outb(nicsr, DEPCA_NICSR);
-  }
-
-  /*
-  ** Free the associated irq
-  */
-  free_irq(dev->irq, dev);
-  return 0;
+
+	if (depca_debug > 1) {
+		printk("%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inw(DEPCA_DATA));
+	}
+
+	/* 
+	   ** We stop the DEPCA here -- it occasionally polls
+	   ** memory if we don't. 
+	 */
+	outw(STOP, DEPCA_DATA);
+
+	/*
+	   ** Give back the ROM in case the user wants to go to DOS
+	 */
+	if (lp->adapter != DEPCA) {
+		nicsr = inb(DEPCA_NICSR);
+		nicsr &= ~SHE;
+		outb(nicsr, DEPCA_NICSR);
+	}
+
+	/*
+	   ** Free the associated irq
+	 */
+	free_irq(dev->irq, dev);
+	return 0;
 }
 
 static void LoadCSRs(struct net_device *dev)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  u_long ioaddr = dev->base_addr;
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	u_long ioaddr = dev->base_addr;
 
-  outw(CSR1, DEPCA_ADDR);                /* initialisation block address LSW */
-  outw((u16)lp->device_ram_start, DEPCA_DATA);
-  outw(CSR2, DEPCA_ADDR);                /* initialisation block address MSW */
-  outw((u16)(lp->device_ram_start >> 16), DEPCA_DATA);
-  outw(CSR3, DEPCA_ADDR);                /* ALE control */
-  outw(ACON, DEPCA_DATA);
+	outw(CSR1, DEPCA_ADDR);	/* initialisation block address LSW */
+	outw((u16) lp->device_ram_start, DEPCA_DATA);
+	outw(CSR2, DEPCA_ADDR);	/* initialisation block address MSW */
+	outw((u16) (lp->device_ram_start >> 16), DEPCA_DATA);
+	outw(CSR3, DEPCA_ADDR);	/* ALE control */
+	outw(ACON, DEPCA_DATA);
 
-  outw(CSR0, DEPCA_ADDR);                /* Point back to CSR0 */
+	outw(CSR0, DEPCA_ADDR);	/* Point back to CSR0 */
 
-  return;
+	return;
 }
 
 static int InitRestartDepca(struct net_device *dev)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  u_long ioaddr = dev->base_addr;
-  int i, status=0;
-
-  /* Copy the shadow init_block to shared memory */
-  memcpy_toio(lp->sh_mem, &lp->init_block, sizeof(struct depca_init));
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	u_long ioaddr = dev->base_addr;
+	int i, status = 0;
 
-  outw(CSR0, DEPCA_ADDR);                /* point back to CSR0 */
-  outw(INIT, DEPCA_DATA);                /* initialize DEPCA */
+	/* Copy the shadow init_block to shared memory */
+	memcpy_toio(lp->sh_mem, &lp->init_block, sizeof(struct depca_init));
 
-  /* wait for lance to complete initialisation */
-  for (i=0;(i<100) && !(inw(DEPCA_DATA) & IDON); i++); 
+	outw(CSR0, DEPCA_ADDR);	/* point back to CSR0 */
+	outw(INIT, DEPCA_DATA);	/* initialize DEPCA */
 
-  if (i!=100) {
-    /* clear IDON by writing a "1", enable interrupts and start lance */
-    outw(IDON | INEA | STRT, DEPCA_DATA);
-    if (depca_debug > 2) {
-      printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n",
-	     dev->name, i, virt_to_phys(lp->sh_mem), inw(DEPCA_DATA));
-    }
-  } else {
-    printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n",
-	     dev->name, i, virt_to_phys(lp->sh_mem), inw(DEPCA_DATA));
-    status = -1;
-  }
+	/* wait for lance to complete initialisation */
+	for (i = 0; (i < 100) && !(inw(DEPCA_DATA) & IDON); i++);
+
+	if (i != 100) {
+		/* clear IDON by writing a "1", enable interrupts and start lance */
+		outw(IDON | INEA | STRT, DEPCA_DATA);
+		if (depca_debug > 2) {
+			printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, virt_to_phys(lp->sh_mem), inw(DEPCA_DATA));
+		}
+	} else {
+		printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, virt_to_phys(lp->sh_mem), inw(DEPCA_DATA));
+		status = -1;
+	}
 
-  return status;
+	return status;
 }
 
-static struct net_device_stats *
-depca_get_stats(struct net_device *dev)
+static struct net_device_stats *depca_get_stats(struct net_device *dev)
 {
-    struct depca_private *lp = (struct depca_private *)dev->priv;
+	struct depca_private *lp = (struct depca_private *) dev->priv;
 
-    /* Null body since there is no framing error counter */
+	/* Null body since there is no framing error counter */
 
-    return &lp->stats;
+	return &lp->stats;
 }
 
 /*
 ** Set or clear the multicast filter for this adaptor.
 */
-static void
-set_multicast_list(struct net_device *dev)
+static void set_multicast_list(struct net_device *dev)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  u_long ioaddr = dev->base_addr;
-  
-  if (dev) {
-    netif_stop_queue(dev);
-    while(lp->tx_old != lp->tx_new);  /* Wait for the ring to empty */
-
-    STOP_DEPCA;                       /* Temporarily stop the depca.  */
-    depca_init_ring(dev);             /* Initialize the descriptor rings */
-
-    if (dev->flags & IFF_PROMISC) {   /* Set promiscuous mode */
-      lp->init_block.mode |= PROM;
-    } else {
-      SetMulticastFilter(dev);
-      lp->init_block.mode &= ~PROM;   /* Unset promiscuous mode */
-    }
-
-    LoadCSRs(dev);                    /* Reload CSR3 */
-    InitRestartDepca(dev);            /* Resume normal operation. */
-    netif_start_queue(dev);           /* Unlock the TX ring */
-  }
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	u_long ioaddr = dev->base_addr;
+
+	if (dev) {
+		netif_stop_queue(dev);
+		while (lp->tx_old != lp->tx_new);	/* Wait for the ring to empty */
+
+		STOP_DEPCA;	/* Temporarily stop the depca.  */
+		depca_init_ring(dev);	/* Initialize the descriptor rings */
+
+		if (dev->flags & IFF_PROMISC) {	/* Set promiscuous mode */
+			lp->init_block.mode |= PROM;
+		} else {
+			SetMulticastFilter(dev);
+			lp->init_block.mode &= ~PROM;	/* Unset promiscuous mode */
+		}
+
+		LoadCSRs(dev);	/* Reload CSR3 */
+		InitRestartDepca(dev);	/* Resume normal operation. */
+		netif_start_queue(dev);	/* Unlock the TX ring */
+	}
 }
 
 /*
@@ -1220,274 +1200,277 @@
 */
 static void SetMulticastFilter(struct net_device *dev)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  struct dev_mc_list *dmi=dev->mc_list;
-  char *addrs;
-  int i, j, bit, byte;
-  u16 hashcode;
-  u32 crc;
-
-  if (dev->flags & IFF_ALLMULTI) {         /* Set all multicast bits */
-    for (i=0; i<(HASH_TABLE_LEN>>3); i++) {
-      lp->init_block.mcast_table[i] = (char)0xff;
-    }
-  } else {
-    for (i=0; i<(HASH_TABLE_LEN>>3); i++){ /* Clear the multicast table */
-      lp->init_block.mcast_table[i]=0;
-    }
-                                           /* Add multicast addresses */
-    for (i=0;i<dev->mc_count;i++) {        /* for each address in the list */
-      addrs=dmi->dmi_addr;
-      dmi=dmi->next;
-      if ((*addrs & 0x01) == 1) {          /* multicast address? */ 
-        crc = ether_crc(ETH_ALEN, addrs);
-	hashcode = (crc & 1);              /* hashcode is 6 LSb of CRC ... */
-	for (j=0;j<5;j++) {                /* ... in reverse order. */
-	  hashcode = (hashcode << 1) | ((crc>>=1) & 1);
-	}                                      
-	
-	
-	byte = hashcode >> 3;              /* bit[3-5] -> byte in filter */
-	bit = 1 << (hashcode & 0x07);      /* bit[0-2] -> bit in byte */
-	lp->init_block.mcast_table[byte] |= bit;
-      }
-    }
-  }
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct dev_mc_list *dmi = dev->mc_list;
+	char *addrs;
+	int i, j, bit, byte;
+	u16 hashcode;
+	u32 crc;
+
+	if (dev->flags & IFF_ALLMULTI) {	/* Set all multicast bits */
+		for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
+			lp->init_block.mcast_table[i] = (char) 0xff;
+		}
+	} else {
+		for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {	/* Clear the multicast table */
+			lp->init_block.mcast_table[i] = 0;
+		}
+		/* Add multicast addresses */
+		for (i = 0; i < dev->mc_count; i++) {	/* for each address in the list */
+			addrs = dmi->dmi_addr;
+			dmi = dmi->next;
+			if ((*addrs & 0x01) == 1) {	/* multicast address? */
+				crc = ether_crc(ETH_ALEN, addrs);
+				hashcode = (crc & 1);	/* hashcode is 6 LSb of CRC ... */
+				for (j = 0; j < 5; j++) {	/* ... in reverse order. */
+					hashcode = (hashcode << 1) | ((crc >>= 1) & 1);
+				}
+
 
-  return;
+				byte = hashcode >> 3;	/* bit[3-5] -> byte in filter */
+				bit = 1 << (hashcode & 0x07);	/* bit[0-2] -> bit in byte */
+				lp->init_block.mcast_table[byte] |= bit;
+			}
+		}
+	}
+
+	return;
 }
 
 #ifdef CONFIG_MCA
 /*
 ** Microchannel bus I/O device probe
 */
-static void __init 
-mca_probe(struct net_device *dev, u_long ioaddr)
+static void __init mca_probe(struct net_device *dev, u_long ioaddr)
 {
-    unsigned char pos[2];
-    unsigned char where;
-    unsigned long iobase;
-    int irq;
-    int slot = 0;
-
-    /*
-    ** See if we've been here before.
-    */
-    if ((!ioaddr && autoprobed) || (ioaddr && !loading_module)) return;   
+	unsigned char pos[2];
+	unsigned char where;
+	unsigned long iobase;
+	int irq;
+	int slot = 0;
 
-    if (MCA_bus) {
 	/*
-	** Search for the adapter.  If an address has been given, search 
-	** specifically for the card at that address.  Otherwise find the
-	** first card in the system.
-	*/
-	while ((dev!=NULL) && 
-	       ((slot=mca_find_adapter(DE212_ID, slot)) != MCA_NOTFOUND)) {
-	    pos[0] = mca_read_stored_pos(slot, 2);
-	    pos[1] = mca_read_stored_pos(slot, 3);
-
-	    /*
-	    ** IO of card is handled by bits 1 and 2 of pos0.    
-	    **
-	    **    bit2 bit1    IO
-	    **       0    0    0x2c00
-	    **       0    1    0x2c10
-	    **       1    0    0x2c20
-	    **       1    1    0x2c30
-	    */
-	    where = (pos[0] & 6) >> 1;
-	    iobase = 0x2c00 + (0x10 * where);
-	       
-	    if ((ioaddr) && (ioaddr != iobase)) {
-		/*
-		** Card was found, but not at the right IO location. Continue 
-		** scanning from the next MCA slot up for another card.
-		*/
-		slot++;
-		continue;
-	    }
-
-	    /*
-	    ** Found the adapter we were looking for. Now start setting it up.
-	    ** 
-	    ** First work on decoding the IRQ.  It's stored in the lower 4 bits
-	    ** of pos1.  Bits are as follows (from the ADF file):
-	    **
-	    **      Bits           
-	    **   3   2   1   0    IRQ 
-	    **   --------------------
-	    **   0   0   1   0     5
-	    **   0   0   0   1     9
-	    **   0   1   0   0    10
-	    **   1   0   0   0    11
-	    **/
-	    where = pos[1] & 0x0f;
-	    switch(where) {       
-	    case 1:
-		irq = 9;
-		break;
-	    case 2:
-		irq = 5;
-		break;
-	    case 4:
-		irq = 10;
-		break;
-	    case 8:
-		irq = 11;
-		break;
-	    default:
-		printk("%s: mca_probe IRQ error.  You should never get here (%d).\n", dev->name, where);
+	   ** See if we've been here before.
+	 */
+	if ((!ioaddr && autoprobed) || (ioaddr && !loading_module))
 		return;
-	    }  
- 
-	    /*
-	    ** Shared memory address of adapter is stored in bits 3-5 of pos0.
-	    ** They are mapped as follows:
-	    **
-	    **    Bit
-	    **   5  4  3       Memory Addresses
-	    **   0  0  0       C0000-CFFFF (64K)
-	    **   1  0  0       C8000-CFFFF (32K)
-	    **   0  0  1       D0000-DFFFF (64K)
-	    **   1  0  1       D8000-DFFFF (32K)
-	    **   0  1  0       E0000-EFFFF (64K)
-	    **   1  1  0       E8000-EFFFF (32K)
-	    */ 
-	    where = (pos[0] & 0x18) >> 3; 
-	    mem = 0xc0000 + (where * 0x10000);
-	    if (pos[0] & 0x20) {
-		mem += 0x8000;
-	    }
-       
-	    /*
-	    ** Get everything allocated and initialized...  (almost just
-	    ** like the ISA and EISA probes)
-	    */
-	    if (DevicePresent(iobase) != 0) {
+
+	if (MCA_bus) {
 		/*
-		** If the MCA configuration says the card should be here,
-		** it really should be here.
-		*/
-		printk(KERN_ERR "%s: MCA reports card at 0x%lx but it is not
-responding.\n", dev->name, iobase);
-	    }
-       
-	    if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
-		if ((dev = alloc_device(dev, iobase)) != NULL) {
-		    dev->irq = irq;
-		    if (depca_hw_init(dev, iobase, slot) == 0) {       
+		   ** Search for the adapter.  If an address has been given, search 
+		   ** specifically for the card at that address.  Otherwise find the
+		   ** first card in the system.
+		 */
+		while ((dev != NULL) && ((slot = mca_find_adapter(DE212_ID, slot)) != MCA_NOTFOUND)) {
+			pos[0] = mca_read_stored_pos(slot, 2);
+			pos[1] = mca_read_stored_pos(slot, 3);
+
+			/*
+			   ** IO of card is handled by bits 1 and 2 of pos0.    
+			   **
+			   **    bit2 bit1    IO
+			   **       0    0    0x2c00
+			   **       0    1    0x2c10
+			   **       1    0    0x2c20
+			   **       1    1    0x2c30
+			 */
+			where = (pos[0] & 6) >> 1;
+			iobase = 0x2c00 + (0x10 * where);
+
+			if ((ioaddr) && (ioaddr != iobase)) {
+				/*
+				   ** Card was found, but not at the right IO location. Continue 
+				   ** scanning from the next MCA slot up for another card.
+				 */
+				slot++;
+				continue;
+			}
+
 			/*
-			** Adapter initialized correctly:  Name it in
-			** /proc/mca.
-			*/
-			mca_set_adapter_name(slot, "DE210/212 Ethernet Adapter");
-			mca_mark_as_used(slot);
-			num_depcas++;
-		    }
-		    num_eth++;
-		}
-	    } else if (autoprobed) {
-		printk(KERN_WARNING "%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
-	    }
-       
-	    /*
-	    ** If this is a probe by a module, return after setting up the
-	    ** given card.
-	    */
-	    if (ioaddr) return;
-       
-	    /*
-	    ** Set up to check the next slot and loop.
-	    */
-	    slot++;
+			   ** Found the adapter we were looking for. Now start setting it up.
+			   ** 
+			   ** First work on decoding the IRQ.  It's stored in the lower 4 bits
+			   ** of pos1.  Bits are as follows (from the ADF file):
+			   **
+			   **      Bits           
+			   **   3   2   1   0    IRQ 
+			   **   --------------------
+			   **   0   0   1   0     5
+			   **   0   0   0   1     9
+			   **   0   1   0   0    10
+			   **   1   0   0   0    11
+			   * */
+			where = pos[1] & 0x0f;
+			switch (where) {
+			case 1:
+				irq = 9;
+				break;
+			case 2:
+				irq = 5;
+				break;
+			case 4:
+				irq = 10;
+				break;
+			case 8:
+				irq = 11;
+				break;
+			default:
+				printk("%s: mca_probe IRQ error.  You should never get here (%d).\n", dev->name, where);
+				return;
+			}
+
+			/*
+			   ** Shared memory address of adapter is stored in bits 3-5 of pos0.
+			   ** They are mapped as follows:
+			   **
+			   **    Bit
+			   **   5  4  3       Memory Addresses
+			   **   0  0  0       C0000-CFFFF (64K)
+			   **   1  0  0       C8000-CFFFF (32K)
+			   **   0  0  1       D0000-DFFFF (64K)
+			   **   1  0  1       D8000-DFFFF (32K)
+			   **   0  1  0       E0000-EFFFF (64K)
+			   **   1  1  0       E8000-EFFFF (32K)
+			 */
+			where = (pos[0] & 0x18) >> 3;
+			mem = 0xc0000 + (where * 0x10000);
+			if (pos[0] & 0x20) {
+				mem += 0x8000;
+			}
+
+			/*
+			   ** Get everything allocated and initialized...  (almost just
+			   ** like the ISA and EISA probes)
+			 */
+			if (DevicePresent(iobase) != 0) {
+				/*
+				   ** If the MCA configuration says the card should be here,
+				   ** it really should be here.
+				 */
+				printk(KERN_ERR "%s: MCA reports card at 0x%lx but it is not responding.\n", dev->name, iobase);
+			}
+
+			if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
+				if ((dev = alloc_device(dev, iobase)) != NULL) {
+					dev->irq = irq;
+					if (depca_hw_init(dev, iobase, slot) == 0) {
+						/*
+						   ** Adapter initialized correctly:  Name it in
+						   ** /proc/mca.
+						 */
+						mca_set_adapter_name(slot, "DE210/212 Ethernet Adapter");
+						mca_mark_as_used(slot);
+						num_depcas++;
+					}
+					num_eth++;
+				}
+			} else if (autoprobed) {
+				printk(KERN_WARNING "%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
+			}
+
+			/*
+			   ** If this is a probe by a module, return after setting up the
+			   ** given card.
+			 */
+			if (ioaddr)
+				return;
+
+			/*
+			   ** Set up to check the next slot and loop.
+			 */
+			slot++;
+		}
 	}
-    }
 
-    return;
+	return;
 }
 #endif
 
 /*
 ** ISA bus I/O device probe
 */
-static void __init 
-isa_probe(struct net_device *dev, u_long ioaddr)
+static void __init isa_probe(struct net_device *dev, u_long ioaddr)
 {
-  int i = num_depcas, maxSlots;
-  s32 ports[] = DEPCA_IO_PORTS;
+	int i = num_depcas, maxSlots;
+	s32 ports[] = DEPCA_IO_PORTS;
 
-  if (!ioaddr && autoprobed) return ;          /* Been here before ! */
-  if (ioaddr > 0x400) return;                  /* EISA Address */
-  if (i >= MAX_NUM_DEPCAS) return;             /* Too many ISA adapters */
-
-  if (ioaddr == 0) {                           /* Autoprobing */
-    maxSlots = MAX_NUM_DEPCAS;
-  } else {                                     /* Probe a specific location */
-    ports[i] = ioaddr;
-    maxSlots = i + 1;
-  }
-
-  for (; (i<maxSlots) && (dev!=NULL) && ports[i]; i++) {
-    if (check_region(ports[i], DEPCA_TOTAL_SIZE) == 0) {
-      if (DevicePresent(ports[i]) == 0) { 
-	if ((dev = alloc_device(dev, ports[i])) != NULL) {
-	  if (depca_hw_init(dev, ports[i], -1) == 0) {
-	    num_depcas++;
-	  }
-	  num_eth++;
-	}
-      }
-    } else if (autoprobed) {
-      printk("%s: region already allocated at 0x%04x.\n", dev->name, ports[i]);
-    }
-  }
+	if (!ioaddr && autoprobed)
+		return;		/* Been here before ! */
+	if (ioaddr > 0x400)
+		return;		/* EISA Address */
+	if (i >= MAX_NUM_DEPCAS)
+		return;		/* Too many ISA adapters */
+
+	if (ioaddr == 0) {	/* Autoprobing */
+		maxSlots = MAX_NUM_DEPCAS;
+	} else {		/* Probe a specific location */
+		ports[i] = ioaddr;
+		maxSlots = i + 1;
+	}
+
+	for (; (i < maxSlots) && (dev != NULL) && ports[i]; i++) {
+		if (check_region(ports[i], DEPCA_TOTAL_SIZE) == 0) {
+			if (DevicePresent(ports[i]) == 0) {
+				if ((dev = alloc_device(dev, ports[i])) != NULL) {
+					if (depca_hw_init(dev, ports[i], -1) == 0) {
+						num_depcas++;
+					}
+					num_eth++;
+				}
+			}
+		} else if (autoprobed) {
+			printk("%s: region already allocated at 0x%04x.\n", dev->name, ports[i]);
+		}
+	}
 
-  return;
+	return;
 }
 
 /*
 ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
 ** the motherboard. Upto 15 EISA devices are supported.
 */
-static void __init 
-eisa_probe(struct net_device *dev, u_long ioaddr)
+static void __init eisa_probe(struct net_device *dev, u_long ioaddr)
 {
-  int i, maxSlots;
-  u_long iobase;
-  char name[DEPCA_STRLEN];
-
-  if (!ioaddr && autoprobed) return ;            /* Been here before ! */
-  if ((ioaddr < 0x400) && (ioaddr > 0)) return;  /* ISA Address */
-
-  if (ioaddr == 0) {                           /* Autoprobing */
-    iobase = EISA_SLOT_INC;                    /* Get the first slot address */
-    i = 1;
-    maxSlots = MAX_EISA_SLOTS;
-  } else {                                     /* Probe a specific location */
-    iobase = ioaddr;
-    i = (ioaddr >> 12);
-    maxSlots = i + 1;
-  }
-  if ((iobase & 0x0fff) == 0) iobase += DEPCA_EISA_IO_PORTS;
-
-  for (; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
-    if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
-      if (EISA_signature(name, EISA_ID)) {
-	if (DevicePresent(iobase) == 0) { 
-	  if ((dev = alloc_device(dev, iobase)) != NULL) {
-	    if (depca_hw_init(dev, iobase, -1) == 0) {
-	      num_depcas++;
-	    }
-	    num_eth++;
-	  }
-	}
-      }
-    } else if (autoprobed) {
-      printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
-    }
-  }
+	int i, maxSlots;
+	u_long iobase;
+	char name[DEPCA_STRLEN];
+
+	if (!ioaddr && autoprobed)
+		return;		/* Been here before ! */
+	if ((ioaddr < 0x400) && (ioaddr > 0))
+		return;		/* ISA Address */
+
+	if (ioaddr == 0) {	/* Autoprobing */
+		iobase = EISA_SLOT_INC;	/* Get the first slot address */
+		i = 1;
+		maxSlots = MAX_EISA_SLOTS;
+	} else {		/* Probe a specific location */
+		iobase = ioaddr;
+		i = (ioaddr >> 12);
+		maxSlots = i + 1;
+	}
+	if ((iobase & 0x0fff) == 0)
+		iobase += DEPCA_EISA_IO_PORTS;
+
+	for (; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) {
+		if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
+			if (EISA_signature(name, EISA_ID)) {
+				if (DevicePresent(iobase) == 0) {
+					if ((dev = alloc_device(dev, iobase)) != NULL) {
+						if (depca_hw_init(dev, iobase, -1) == 0) {
+							num_depcas++;
+						}
+						num_eth++;
+					}
+				}
+			}
+		} else if (autoprobed) {
+			printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
+		}
+	}
 
-  return;
+	return;
 }
 
 /*
@@ -1496,89 +1479,87 @@
 ** are not available then insert a new device structure at the end of
 ** the current list.
 */
-static struct net_device * __init 
-alloc_device(struct net_device *dev, u_long iobase)
+static struct net_device *__init alloc_device(struct net_device *dev, u_long iobase)
 {
-    struct net_device *adev = NULL;
-    int fixed = 0, new_dev = 0;
+	struct net_device *adev = NULL;
+	int fixed = 0, new_dev = 0;
 
-    num_eth = depca_dev_index(dev->name);
-    if (loading_module) return dev;
-    
-    while (1) {
-	if (((dev->base_addr == DEPCA_NDA) || (dev->base_addr==0)) && !adev) {
-	    adev=dev;
-	} else if ((dev->priv == NULL) && (dev->base_addr==iobase)) {
-	    fixed = 1;
-	} else {
-	    if (dev->next == NULL) {
-		new_dev = 1;
-	    } else if (strncmp(dev->next->name, "eth", 3) != 0) {
-		new_dev = 1;
-	    }
-	}
-	if ((dev->next == NULL) || new_dev || fixed) break;
-	dev = dev->next;
-	num_eth++;
-    }
-    if (adev && !fixed) {
-	dev = adev;
 	num_eth = depca_dev_index(dev->name);
-	new_dev = 0;
-    }
+	if (loading_module)
+		return dev;
 
-    if (((dev->next == NULL) &&  
-	((dev->base_addr != DEPCA_NDA) && (dev->base_addr != 0)) && !fixed) ||
-	new_dev) {
-	num_eth++;                         /* New device */
-	dev = insert_device(dev, iobase, depca_probe);
-    }
-    
-    return dev;
+	while (1) {
+		if (((dev->base_addr == DEPCA_NDA) || (dev->base_addr == 0)) && !adev) {
+			adev = dev;
+		} else if ((dev->priv == NULL) && (dev->base_addr == iobase)) {
+			fixed = 1;
+		} else {
+			if (dev->next == NULL) {
+				new_dev = 1;
+			} else if (strncmp(dev->next->name, "eth", 3) != 0) {
+				new_dev = 1;
+			}
+		}
+		if ((dev->next == NULL) || new_dev || fixed)
+			break;
+		dev = dev->next;
+		num_eth++;
+	}
+	if (adev && !fixed) {
+		dev = adev;
+		num_eth = depca_dev_index(dev->name);
+		new_dev = 0;
+	}
+
+	if (((dev->next == NULL) && ((dev->base_addr != DEPCA_NDA) && (dev->base_addr != 0)) && !fixed) || new_dev) {
+		num_eth++;	/* New device */
+		dev = insert_device(dev, iobase, depca_probe);
+	}
+
+	return dev;
 }
 
 /*
 ** If at end of eth device list and can't use current entry, malloc
 ** one up. If memory could not be allocated, print an error message.
 */
-static struct net_device * __init 
-insert_device(struct net_device *dev, u_long iobase, int (*init)(struct net_device *))
+static struct net_device *__init insert_device(struct net_device *dev, u_long iobase, int (*init) (struct net_device *))
 {
-    struct net_device *new;
+	struct net_device *new;
 
-    new = (struct net_device *)kmalloc(sizeof(struct net_device), GFP_KERNEL);
-    if (new == NULL) {
-	printk("eth%d: Device not initialised, insufficient memory\n",num_eth);
-	return NULL;
-    } else {
-	new->next = dev->next;
-	dev->next = new;
-	dev = dev->next;               /* point to the new device */
-	if (num_eth > 9999) {
-	    sprintf(dev->name,"eth????");/* New device name */
+	new = (struct net_device *) kmalloc(sizeof(struct net_device), GFP_KERNEL);
+	if (new == NULL) {
+		printk("eth%d: Device not initialised, insufficient memory\n", num_eth);
+		return NULL;
 	} else {
-	    sprintf(dev->name,"eth%d", num_eth);/* New device name */
+		new->next = dev->next;
+		dev->next = new;
+		dev = dev->next;	/* point to the new device */
+		if (num_eth > 9999) {
+			sprintf(dev->name, "eth????");	/* New device name */
+		} else {
+			sprintf(dev->name, "eth%d", num_eth);	/* New device name */
+		}
+		dev->base_addr = iobase;	/* assign the io address */
+		dev->init = init;	/* initialisation routine */
 	}
-	dev->base_addr = iobase;       /* assign the io address */
-	dev->init = init;              /* initialisation routine */
-    }
 
-    return dev;
+	return dev;
 }
 
-static int __init 
-depca_dev_index(char *s)
+static int __init depca_dev_index(char *s)
 {
-    int i=0, j=0;
+	int i = 0, j = 0;
 
-    for (;*s; s++) {
-	if (isdigit(*s)) {
-	    j=1;
-	    i = (i * 10) + (*s - '0');
-	} else if (j) break;
-    }
+	for (; *s; s++) {
+		if (isdigit(*s)) {
+			j = 1;
+			i = (i * 10) + (*s - '0');
+		} else if (j)
+			break;
+	}
 
-    return i;
+	return i;
 }
 
 /*
@@ -1586,50 +1567,51 @@
 ** and Boot (readb) ROM. This will also give us a clue to the network RAM
 ** base address.
 */
-static void __init 
-DepcaSignature(char *name, u_long paddr)
+static void __init DepcaSignature(char *name, u_long paddr)
 {
-  u_int i,j,k;
-  const char *signatures[] = DEPCA_SIGNATURE;
-  void *ptr;
-  char tmpstr[16];
-
-  /* Copy the first 16 bytes of ROM */
-  ptr = ioremap(paddr + 0xc000, 16);
-  if (ptr == NULL) {
-	  printk(KERN_ERR "depca: I/O remap failed at %lx\n", paddr+0xc000);
-	  adapter = unknown;
-	  return;
-  }
-  for (i=0;i<16;i++) {
-    tmpstr[i] = readb(ptr + i);
-  }
-  iounmap(ptr);
-
-  /* Check if PROM contains a valid string */
-  for (i=0;*signatures[i]!='\0';i++) {
-    for (j=0,k=0;j<16 && k<strlen(signatures[i]);j++) {
-      if (signatures[i][k] == tmpstr[j]) {              /* track signature */
-	k++;
-      } else {                     /* lost signature; begin search again */
-	k=0;
-      }
-    }
-    if (k == strlen(signatures[i])) break;
-  }
-
-  /* Check if name string is valid, provided there's no PROM */
-  if (*name && (i == unknown)) {
-    for (i=0;*signatures[i]!='\0';i++) {
-      if (strcmp(name,signatures[i]) == 0) break;
-    }
-  }
-
-  /* Update search results */
-  strcpy(name,signatures[i]);
-  adapter = i;
+	u_int i, j, k;
+	const char *signatures[] = DEPCA_SIGNATURE;
+	void *ptr;
+	char tmpstr[16];
+
+	/* Copy the first 16 bytes of ROM */
+	ptr = ioremap(paddr + 0xc000, 16);
+	if (ptr == NULL) {
+		printk(KERN_ERR "depca: I/O remap failed at %lx\n", paddr + 0xc000);
+		adapter = unknown;
+		return;
+	}
+	for (i = 0; i < 16; i++) {
+		tmpstr[i] = readb(ptr + i);
+	}
+	iounmap(ptr);
+
+	/* Check if PROM contains a valid string */
+	for (i = 0; *signatures[i] != '\0'; i++) {
+		for (j = 0, k = 0; j < 16 && k < strlen(signatures[i]); j++) {
+			if (signatures[i][k] == tmpstr[j]) {	/* track signature */
+				k++;
+			} else {	/* lost signature; begin search again */
+				k = 0;
+			}
+		}
+		if (k == strlen(signatures[i]))
+			break;
+	}
 
-  return;
+	/* Check if name string is valid, provided there's no PROM */
+	if (*name && (i == unknown)) {
+		for (i = 0; *signatures[i] != '\0'; i++) {
+			if (strcmp(name, signatures[i]) == 0)
+				break;
+		}
+	}
+
+	/* Update search results */
+	strcpy(name, signatures[i]);
+	adapter = i;
+
+	return;
 }
 
 /*
@@ -1647,52 +1629,52 @@
 ** PROM address counter is correctly positioned at the start of the
 ** ethernet address for later read out.
 */
-static int __init 
-DevicePresent(u_long ioaddr)
+static int __init DevicePresent(u_long ioaddr)
 {
-  union {
-    struct {
-      u32 a;
-      u32 b;
-    } llsig;
-    char Sig[sizeof(u32) << 1];
-  } dev;
-  short sigLength=0;
-  s8 data;
-  s16 nicsr;
-  int i, j, status = 0;
-
-  data = inb(DEPCA_PROM);                /* clear counter on DEPCA */
-  data = inb(DEPCA_PROM);                /* read data */
-
-  if (data == 0x08) {                    /* Enable counter on DEPCA */
-    nicsr = inb(DEPCA_NICSR);
-    nicsr |= AAC;
-    outb(nicsr, DEPCA_NICSR);
-  }
-  
-  dev.llsig.a = ETH_PROM_SIG;
-  dev.llsig.b = ETH_PROM_SIG;
-  sigLength = sizeof(u32) << 1;
-
-  for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
-    data = inb(DEPCA_PROM);
-    if (dev.Sig[j] == data) {    /* track signature */
-      j++;
-    } else {                     /* lost signature; begin search again */
-      if (data == dev.Sig[0]) {  /* rare case.... */
-	j=1;
-      } else {
-	j=0;
-      }
-    }
-  }
-
-  if (j!=sigLength) {
-    status = -ENODEV;           /* search failed */
-  }
+	union {
+		struct {
+			u32 a;
+			u32 b;
+		} llsig;
+		char Sig[sizeof(u32) << 1];
+	}
+	dev;
+	short sigLength = 0;
+	s8 data;
+	s16 nicsr;
+	int i, j, status = 0;
+
+	data = inb(DEPCA_PROM);	/* clear counter on DEPCA */
+	data = inb(DEPCA_PROM);	/* read data */
 
-  return status;
+	if (data == 0x08) {	/* Enable counter on DEPCA */
+		nicsr = inb(DEPCA_NICSR);
+		nicsr |= AAC;
+		outb(nicsr, DEPCA_NICSR);
+	}
+
+	dev.llsig.a = ETH_PROM_SIG;
+	dev.llsig.b = ETH_PROM_SIG;
+	sigLength = sizeof(u32) << 1;
+
+	for (i = 0, j = 0; j < sigLength && i < PROBE_LENGTH + sigLength - 1; i++) {
+		data = inb(DEPCA_PROM);
+		if (dev.Sig[j] == data) {	/* track signature */
+			j++;
+		} else {	/* lost signature; begin search again */
+			if (data == dev.Sig[0]) {	/* rare case.... */
+				j = 1;
+			} else {
+				j = 0;
+			}
+		}
+	}
+
+	if (j != sigLength) {
+		status = -ENODEV;	/* search failed */
+	}
+
+	return status;
 }
 
 /*
@@ -1700,33 +1682,36 @@
 ** reason: access the upper half of the PROM with x=0; access the lower half
 ** with x=1.
 */
-static int __init 
-get_hw_addr(struct net_device *dev)
+static int __init get_hw_addr(struct net_device *dev)
 {
-  u_long ioaddr = dev->base_addr;
-  int i, k, tmp, status = 0;
-  u_short j, x, chksum;
-
-  x = (((adapter == de100) || (adapter == de101)) ? 1 : 0);
-
-  for (i=0,k=0,j=0;j<3;j++) {
-    k <<= 1 ;
-    if (k > 0xffff) k-=0xffff;
-
-    k += (u_char) (tmp = inb(DEPCA_PROM + x));
-    dev->dev_addr[i++] = (u_char) tmp;
-    k += (u_short) ((tmp = inb(DEPCA_PROM + x)) << 8);
-    dev->dev_addr[i++] = (u_char) tmp;
+	u_long ioaddr = dev->base_addr;
+	int i, k, tmp, status = 0;
+	u_short j, x, chksum;
 
-    if (k > 0xffff) k-=0xffff;
-  }
-  if (k == 0xffff) k=0;
+	x = (((adapter == de100) || (adapter == de101)) ? 1 : 0);
 
-  chksum = (u_char) inb(DEPCA_PROM + x);
-  chksum |= (u_short) (inb(DEPCA_PROM + x) << 8);
-  if (k != chksum) status = -1;
+	for (i = 0, k = 0, j = 0; j < 3; j++) {
+		k <<= 1;
+		if (k > 0xffff)
+			k -= 0xffff;
+
+		k += (u_char) (tmp = inb(DEPCA_PROM + x));
+		dev->dev_addr[i++] = (u_char) tmp;
+		k += (u_short) ((tmp = inb(DEPCA_PROM + x)) << 8);
+		dev->dev_addr[i++] = (u_char) tmp;
+
+		if (k > 0xffff)
+			k -= 0xffff;
+	}
+	if (k == 0xffff)
+		k = 0;
+
+	chksum = (u_char) inb(DEPCA_PROM + x);
+	chksum |= (u_short) (inb(DEPCA_PROM + x) << 8);
+	if (k != chksum)
+		status = -1;
 
-  return status;
+	return status;
 }
 
 /*
@@ -1734,165 +1719,161 @@
 */
 static int load_packet(struct net_device *dev, struct sk_buff *skb)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  int i, entry, end, len, status = 0;
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	int i, entry, end, len, status = 0;
 
-  entry = lp->tx_new;  		               /* Ring around buffer number. */
-  end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
-  if (!(readl(&lp->tx_ring[end].base) & T_OWN)) {/* Enough room? */
-    /* 
-    ** Caution: the write order is important here... don't set up the
-    ** ownership rights until all the other information is in place.
-    */
-    if (end < entry) {                         /* wrapped buffer */
-      len = (lp->txRingMask - entry + 1) * TX_BUFF_SZ;
-      memcpy_toio(lp->tx_buff[entry], skb->data, len);
-      memcpy_toio(lp->tx_buff[0], skb->data + len, skb->len - len);
-    } else {                                   /* linear buffer */
-      memcpy_toio(lp->tx_buff[entry], skb->data, skb->len);
-    }
-
-    /* set up the buffer descriptors */
-    len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
-    for (i = entry; i != end; i = (++i) & lp->txRingMask) {
-                                               /* clean out flags */
-      writel(readl(&lp->tx_ring[i].base) & ~T_FLAGS, &lp->tx_ring[i].base);
-      writew(0x0000, &lp->tx_ring[i].misc);    /* clears other error flags */
-      writew(-TX_BUFF_SZ, &lp->tx_ring[i].length);/* packet length in buffer */
-      len -= TX_BUFF_SZ;
-    }
-                                               /* clean out flags */
-    writel(readl(&lp->tx_ring[end].base) & ~T_FLAGS, &lp->tx_ring[end].base);
-    writew(0x0000, &lp->tx_ring[end].misc);    /* clears other error flags */
-    writew(-len, &lp->tx_ring[end].length);    /* packet length in last buff */
-
-                                               /* start of packet */
-    writel(readl(&lp->tx_ring[entry].base) | T_STP, &lp->tx_ring[entry].base);
-                                               /* end of packet */
-    writel(readl(&lp->tx_ring[end].base) | T_ENP, &lp->tx_ring[end].base);
-
-    for (i=end; i!=entry; --i) {
-                                               /* ownership of packet */
-      writel(readl(&lp->tx_ring[i].base) | T_OWN, &lp->tx_ring[i].base);
-      if (i == 0) i=lp->txRingMask+1;
-    }   
-    writel(readl(&lp->tx_ring[entry].base) | T_OWN, &lp->tx_ring[entry].base);
- 
-    lp->tx_new = (++end) & lp->txRingMask;     /* update current pointers */
-  } else {
-    status = -1;
-  }
+	entry = lp->tx_new;	/* Ring around buffer number. */
+	end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
+	if (!(readl(&lp->tx_ring[end].base) & T_OWN)) {	/* Enough room? */
+		/* 
+		   ** Caution: the write order is important here... don't set up the
+		   ** ownership rights until all the other information is in place.
+		 */
+		if (end < entry) {	/* wrapped buffer */
+			len = (lp->txRingMask - entry + 1) * TX_BUFF_SZ;
+			memcpy_toio(lp->tx_buff[entry], skb->data, len);
+			memcpy_toio(lp->tx_buff[0], skb->data + len, skb->len - len);
+		} else {	/* linear buffer */
+			memcpy_toio(lp->tx_buff[entry], skb->data, skb->len);
+		}
 
-  return status;
+		/* set up the buffer descriptors */
+		len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
+		for (i = entry; i != end; i = (++i) & lp->txRingMask) {
+			/* clean out flags */
+			writel(readl(&lp->tx_ring[i].base) & ~T_FLAGS, &lp->tx_ring[i].base);
+			writew(0x0000, &lp->tx_ring[i].misc);	/* clears other error flags */
+			writew(-TX_BUFF_SZ, &lp->tx_ring[i].length);	/* packet length in buffer */
+			len -= TX_BUFF_SZ;
+		}
+		/* clean out flags */
+		writel(readl(&lp->tx_ring[end].base) & ~T_FLAGS, &lp->tx_ring[end].base);
+		writew(0x0000, &lp->tx_ring[end].misc);	/* clears other error flags */
+		writew(-len, &lp->tx_ring[end].length);	/* packet length in last buff */
+
+		/* start of packet */
+		writel(readl(&lp->tx_ring[entry].base) | T_STP, &lp->tx_ring[entry].base);
+		/* end of packet */
+		writel(readl(&lp->tx_ring[end].base) | T_ENP, &lp->tx_ring[end].base);
+
+		for (i = end; i != entry; --i) {
+			/* ownership of packet */
+			writel(readl(&lp->tx_ring[i].base) | T_OWN, &lp->tx_ring[i].base);
+			if (i == 0)
+				i = lp->txRingMask + 1;
+		}
+		writel(readl(&lp->tx_ring[entry].base) | T_OWN, &lp->tx_ring[entry].base);
+
+		lp->tx_new = (++end) & lp->txRingMask;	/* update current pointers */
+	} else {
+		status = -1;
+	}
+
+	return status;
 }
 
 /*
 ** Look for a particular board name in the EISA configuration space
 */
-static int __init 
-EISA_signature(char *name, s32 eisa_id)
+static int __init EISA_signature(char *name, s32 eisa_id)
 {
-  u_int i;
-  const char *signatures[] = DEPCA_SIGNATURE;
-  char ManCode[DEPCA_STRLEN];
-  union {
-    s32 ID;
-    char Id[4];
-  } Eisa;
-  int status = 0;
-
-  *name = '\0';
-  Eisa.ID = inl(eisa_id);
-
-  ManCode[0]=(((Eisa.Id[0]>>2)&0x1f)+0x40);
-  ManCode[1]=(((Eisa.Id[1]&0xe0)>>5)+((Eisa.Id[0]&0x03)<<3)+0x40);
-  ManCode[2]=(((Eisa.Id[2]>>4)&0x0f)+0x30);
-  ManCode[3]=(( Eisa.Id[2]&0x0f)+0x30);
-  ManCode[4]=(((Eisa.Id[3]>>4)&0x0f)+0x30);
-  ManCode[5]='\0';
-
-  for (i=0;(*signatures[i] != '\0') && (*name == '\0');i++) {
-    if (strstr(ManCode, signatures[i]) != NULL) {
-      strcpy(name,ManCode);
-      status = 1;
-    }
-  }
+	u_int i;
+	const char *signatures[] = DEPCA_SIGNATURE;
+	char ManCode[DEPCA_STRLEN];
+	union {
+		s32 ID;
+		char Id[4];
+	} Eisa;
+	int status = 0;
+
+	*name = '\0';
+	Eisa.ID = inl(eisa_id);
+
+	ManCode[0] = (((Eisa.Id[0] >> 2) & 0x1f) + 0x40);
+	ManCode[1] = (((Eisa.Id[1] & 0xe0) >> 5) + ((Eisa.Id[0] & 0x03) << 3) + 0x40);
+	ManCode[2] = (((Eisa.Id[2] >> 4) & 0x0f) + 0x30);
+	ManCode[3] = ((Eisa.Id[2] & 0x0f) + 0x30);
+	ManCode[4] = (((Eisa.Id[3] >> 4) & 0x0f) + 0x30);
+	ManCode[5] = '\0';
+
+	for (i = 0; (*signatures[i] != '\0') && (*name == '\0'); i++) {
+		if (strstr(ManCode, signatures[i]) != NULL) {
+			strcpy(name, ManCode);
+			status = 1;
+		}
+	}
 
-  return status;
+	return status;
 }
 
 static void depca_dbg_open(struct net_device *dev)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  u_long ioaddr = dev->base_addr;
-  struct depca_init *p = &lp->init_block;
-  int i; 
-
-  if (depca_debug > 1){
-    /* Do not copy the shadow init block into shared memory */
-    /* Debugging should not affect normal operation! */
-    /* The shadow init block will get copied across during InitRestartDepca */
-    printk("%s: depca open with irq %d\n",dev->name,dev->irq);
-    printk("Descriptor head addresses (CPU):\n");
-    printk("        0x%lx  0x%lx\n",(u_long)lp->rx_ring, (u_long)lp->tx_ring);
-    printk("Descriptor addresses (CPU):\nRX: ");
-    for (i=0;i<lp->rxRingMask;i++){
-      if (i < 3) {
-	printk("0x%8.8lx ", (long) &lp->rx_ring[i].base);
-      }
-    }
-    printk("...0x%8.8lx\n", (long) &lp->rx_ring[i].base);
-    printk("TX: ");
-    for (i=0;i<lp->txRingMask;i++){
-      if (i < 3) {
-	printk("0x%8.8lx ", (long) &lp->tx_ring[i].base);
-      }
-    }
-    printk("...0x%8.8lx\n", (long) &lp->tx_ring[i].base);
-    printk("\nDescriptor buffers (Device):\nRX: ");
-    for (i=0;i<lp->rxRingMask;i++){
-      if (i < 3) {
-	printk("0x%8.8x  ", readl(&lp->rx_ring[i].base));
-      }
-    }
-    printk("...0x%8.8x\n", readl(&lp->rx_ring[i].base));
-    printk("TX: ");
-    for (i=0;i<lp->txRingMask;i++){
-      if (i < 3) {
-	printk("0x%8.8x  ", readl(&lp->tx_ring[i].base));
-      }
-    }
-    printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
-    printk("Initialisation block at 0x%8.8lx(Phys)\n",virt_to_phys(lp->sh_mem));
-    printk("        mode: 0x%4.4x\n",p->mode);
-    printk("        physical address: ");
-    for (i=0;i<ETH_ALEN-1;i++){
-      printk("%2.2x:", p->phys_addr[i]);
-    }
-    printk("%2.2x\n", p->phys_addr[i]);
-    printk("        multicast hash table: ");
-    for (i=0;i<(HASH_TABLE_LEN >> 3)-1;i++){
-      printk("%2.2x:", p->mcast_table[i]);
-    }
-    printk("%2.2x\n", p->mcast_table[i]);
-    printk("        rx_ring at: 0x%8.8x\n", p->rx_ring);
-    printk("        tx_ring at: 0x%8.8x\n", p->tx_ring);
-    printk("buffers (Phys): 0x%8.8lx\n",virt_to_phys(lp->sh_mem)+lp->buffs_offset);
-    printk("Ring size:\nRX: %d  Log2(rxRingMask): 0x%8.8x\n", 
-	   (int)lp->rxRingMask + 1, 
-	   lp->rx_rlen);
-    printk("TX: %d  Log2(txRingMask): 0x%8.8x\n", 
-	   (int)lp->txRingMask + 1, 
-	   lp->tx_rlen);
-    outw(CSR2,DEPCA_ADDR);
-    printk("CSR2&1: 0x%4.4x",inw(DEPCA_DATA));
-    outw(CSR1,DEPCA_ADDR);
-    printk("%4.4x\n",inw(DEPCA_DATA));
-    outw(CSR3,DEPCA_ADDR);
-    printk("CSR3: 0x%4.4x\n",inw(DEPCA_DATA));
-  }
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	u_long ioaddr = dev->base_addr;
+	struct depca_init *p = &lp->init_block;
+	int i;
 
-  return;
+	if (depca_debug > 1) {
+		/* Do not copy the shadow init block into shared memory */
+		/* Debugging should not affect normal operation! */
+		/* The shadow init block will get copied across during InitRestartDepca */
+		printk("%s: depca open with irq %d\n", dev->name, dev->irq);
+		printk("Descriptor head addresses (CPU):\n");
+		printk("        0x%lx  0x%lx\n", (u_long) lp->rx_ring, (u_long) lp->tx_ring);
+		printk("Descriptor addresses (CPU):\nRX: ");
+		for (i = 0; i < lp->rxRingMask; i++) {
+			if (i < 3) {
+				printk("0x%8.8lx ", (long) &lp->rx_ring[i].base);
+			}
+		}
+		printk("...0x%8.8lx\n", (long) &lp->rx_ring[i].base);
+		printk("TX: ");
+		for (i = 0; i < lp->txRingMask; i++) {
+			if (i < 3) {
+				printk("0x%8.8lx ", (long) &lp->tx_ring[i].base);
+			}
+		}
+		printk("...0x%8.8lx\n", (long) &lp->tx_ring[i].base);
+		printk("\nDescriptor buffers (Device):\nRX: ");
+		for (i = 0; i < lp->rxRingMask; i++) {
+			if (i < 3) {
+				printk("0x%8.8x  ", readl(&lp->rx_ring[i].base));
+			}
+		}
+		printk("...0x%8.8x\n", readl(&lp->rx_ring[i].base));
+		printk("TX: ");
+		for (i = 0; i < lp->txRingMask; i++) {
+			if (i < 3) {
+				printk("0x%8.8x  ", readl(&lp->tx_ring[i].base));
+			}
+		}
+		printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
+		printk("Initialisation block at 0x%8.8lx(Phys)\n", virt_to_phys(lp->sh_mem));
+		printk("        mode: 0x%4.4x\n", p->mode);
+		printk("        physical address: ");
+		for (i = 0; i < ETH_ALEN - 1; i++) {
+			printk("%2.2x:", p->phys_addr[i]);
+		}
+		printk("%2.2x\n", p->phys_addr[i]);
+		printk("        multicast hash table: ");
+		for (i = 0; i < (HASH_TABLE_LEN >> 3) - 1; i++) {
+			printk("%2.2x:", p->mcast_table[i]);
+		}
+		printk("%2.2x\n", p->mcast_table[i]);
+		printk("        rx_ring at: 0x%8.8x\n", p->rx_ring);
+		printk("        tx_ring at: 0x%8.8x\n", p->tx_ring);
+		printk("buffers (Phys): 0x%8.8lx\n", virt_to_phys(lp->sh_mem) + lp->buffs_offset);
+		printk("Ring size:\nRX: %d  Log2(rxRingMask): 0x%8.8x\n", (int) lp->rxRingMask + 1, lp->rx_rlen);
+		printk("TX: %d  Log2(txRingMask): 0x%8.8x\n", (int) lp->txRingMask + 1, lp->tx_rlen);
+		outw(CSR2, DEPCA_ADDR);
+		printk("CSR2&1: 0x%4.4x", inw(DEPCA_DATA));
+		outw(CSR1, DEPCA_ADDR);
+		printk("%4.4x\n", inw(DEPCA_DATA));
+		outw(CSR3, DEPCA_ADDR);
+		printk("CSR3: 0x%4.4x\n", inw(DEPCA_DATA));
+	}
+
+	return;
 }
 
 /*
@@ -1902,177 +1883,189 @@
 */
 static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_data;
-  int i, status = 0;
-  u_long ioaddr = dev->base_addr;
-  union {
-    u8  addr[(HASH_TABLE_LEN * ETH_ALEN)];
-    u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
-    u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
-  } tmp;
-
-  switch(ioc->cmd) {
-  case DEPCA_GET_HWADDR:             /* Get the hardware address */
-    for (i=0; i<ETH_ALEN; i++) {
-      tmp.addr[i] = dev->dev_addr[i];
-    }
-    ioc->len = ETH_ALEN;
-    if (copy_to_user(ioc->data, tmp.addr, ioc->len))
-      return -EFAULT;
-    break;
-
-  case DEPCA_SET_HWADDR:             /* Set the hardware address */
-    if (!capable(CAP_NET_ADMIN)) return -EPERM;
-    if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN))
-      return -EFAULT;
-    for (i=0; i<ETH_ALEN; i++) {
-      dev->dev_addr[i] = tmp.addr[i];
-    }
-    netif_stop_queue(dev);
-    while(lp->tx_old != lp->tx_new);    /* Wait for the ring to empty */
-
-    STOP_DEPCA;                         /* Temporarily stop the depca.  */
-    depca_init_ring(dev);               /* Initialize the descriptor rings */
-    LoadCSRs(dev);                      /* Reload CSR3 */
-    InitRestartDepca(dev);              /* Resume normal operation. */
-    netif_start_queue(dev);             /* Unlock the TX ring */
-    break;
-
-  case DEPCA_SET_PROM:               /* Set Promiscuous Mode */
-    if (!capable(CAP_NET_ADMIN)) return -EPERM;
-    netif_stop_queue(dev);
-    while(lp->tx_old != lp->tx_new);    /* Wait for the ring to empty */
-
-    STOP_DEPCA;                         /* Temporarily stop the depca.  */
-    depca_init_ring(dev);               /* Initialize the descriptor rings */
-    lp->init_block.mode |= PROM;        /* Set promiscuous mode */
-
-    LoadCSRs(dev);                      /* Reload CSR3 */
-    InitRestartDepca(dev);              /* Resume normal operation. */
-    netif_start_queue(dev);             /* Unlock the TX ring */
-    break;
-
-  case DEPCA_CLR_PROM:               /* Clear Promiscuous Mode */
-    if (!capable(CAP_NET_ADMIN)) return -EPERM;
-    netif_stop_queue(dev);
-    while(lp->tx_old != lp->tx_new);    /* Wait for the ring to empty */
-
-    STOP_DEPCA;                         /* Temporarily stop the depca.  */
-    depca_init_ring(dev);               /* Initialize the descriptor rings */
-    lp->init_block.mode &= ~PROM;       /* Clear promiscuous mode */
-
-    LoadCSRs(dev);                      /* Reload CSR3 */
-    InitRestartDepca(dev);              /* Resume normal operation. */
-    netif_start_queue(dev);             /* Unlock the TX ring */
-    break;
-
-  case DEPCA_SAY_BOO:                /* Say "Boo!" to the kernel log file */
-    printk("%s: Boo!\n", dev->name);
-    break;
-
-  case DEPCA_GET_MCA:                /* Get the multicast address table */
-    ioc->len = (HASH_TABLE_LEN >> 3);
-    if (copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len))
-      return -EFAULT;
-    break;
-
-  case DEPCA_SET_MCA:                /* Set a multicast address */
-    if (!capable(CAP_NET_ADMIN)) return -EPERM;
-    if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len))
-      return -EFAULT;
-    set_multicast_list(dev);
-    break;
-
-  case DEPCA_CLR_MCA:                /* Clear all multicast addresses */
-    if (!capable(CAP_NET_ADMIN)) return -EPERM;
-    set_multicast_list(dev);
-    break;
-
-  case DEPCA_MCA_EN:                 /* Enable pass all multicast addressing */
-    if (!capable(CAP_NET_ADMIN)) return -EPERM;
-      set_multicast_list(dev);
-    break;
-
-  case DEPCA_GET_STATS:              /* Get the driver statistics */
-    cli();
-    ioc->len = sizeof(lp->pktStats);
-    if (copy_to_user(ioc->data, &lp->pktStats, ioc->len))
-      status = -EFAULT;
-    sti();
-    break;
-
-  case DEPCA_CLR_STATS:              /* Zero out the driver statistics */
-    if (!capable(CAP_NET_ADMIN)) return -EPERM;
-    cli();
-    memset(&lp->pktStats, 0, sizeof(lp->pktStats));
-    sti();
-    break;
-
-  case DEPCA_GET_REG:                /* Get the DEPCA Registers */
-    i=0;
-    tmp.sval[i++] = inw(DEPCA_NICSR);
-    outw(CSR0, DEPCA_ADDR);              /* status register */
-    tmp.sval[i++] = inw(DEPCA_DATA);
-    memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init));
-    ioc->len = i+sizeof(struct depca_init);
-    if (copy_to_user(ioc->data, tmp.addr, ioc->len))
-      return -EFAULT;
-    break;
-
-  default:
-    return -EOPNOTSUPP;
-  }
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_data;
+	int i, status = 0;
+	u_long ioaddr = dev->base_addr;
+	union {
+		u8 addr[(HASH_TABLE_LEN * ETH_ALEN)];
+		u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
+		u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
+	} tmp;
+
+	switch (ioc->cmd) {
+	case DEPCA_GET_HWADDR:	/* Get the hardware address */
+		for (i = 0; i < ETH_ALEN; i++) {
+			tmp.addr[i] = dev->dev_addr[i];
+		}
+		ioc->len = ETH_ALEN;
+		if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+			return -EFAULT;
+		break;
 
-  return status;
+	case DEPCA_SET_HWADDR:	/* Set the hardware address */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN))
+			return -EFAULT;
+		for (i = 0; i < ETH_ALEN; i++) {
+			dev->dev_addr[i] = tmp.addr[i];
+		}
+		netif_stop_queue(dev);
+		while (lp->tx_old != lp->tx_new)
+			cpu_relax();	/* Wait for the ring to empty */
+
+		STOP_DEPCA;	/* Temporarily stop the depca.  */
+		depca_init_ring(dev);	/* Initialize the descriptor rings */
+		LoadCSRs(dev);	/* Reload CSR3 */
+		InitRestartDepca(dev);	/* Resume normal operation. */
+		netif_start_queue(dev);	/* Unlock the TX ring */
+		break;
+
+	case DEPCA_SET_PROM:	/* Set Promiscuous Mode */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		netif_stop_queue(dev);
+		while (lp->tx_old != lp->tx_new)
+			cpu_relax();	/* Wait for the ring to empty */
+
+		STOP_DEPCA;	/* Temporarily stop the depca.  */
+		depca_init_ring(dev);	/* Initialize the descriptor rings */
+		lp->init_block.mode |= PROM;	/* Set promiscuous mode */
+
+		LoadCSRs(dev);	/* Reload CSR3 */
+		InitRestartDepca(dev);	/* Resume normal operation. */
+		netif_start_queue(dev);	/* Unlock the TX ring */
+		break;
+
+	case DEPCA_CLR_PROM:	/* Clear Promiscuous Mode */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		netif_stop_queue(dev);
+		while (lp->tx_old != lp->tx_new)
+			cpu_relax();	/* Wait for the ring to empty */
+
+		STOP_DEPCA;	/* Temporarily stop the depca.  */
+		depca_init_ring(dev);	/* Initialize the descriptor rings */
+		lp->init_block.mode &= ~PROM;	/* Clear promiscuous mode */
+
+		LoadCSRs(dev);	/* Reload CSR3 */
+		InitRestartDepca(dev);	/* Resume normal operation. */
+		netif_start_queue(dev);	/* Unlock the TX ring */
+		break;
+
+	case DEPCA_SAY_BOO:	/* Say "Boo!" to the kernel log file */
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		printk("%s: Boo!\n", dev->name);
+		break;
+
+	case DEPCA_GET_MCA:	/* Get the multicast address table */
+		ioc->len = (HASH_TABLE_LEN >> 3);
+		if (copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len))
+			return -EFAULT;
+		break;
+
+	case DEPCA_SET_MCA:	/* Set a multicast address */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (ioc->len >= HASH_TABLE_LEN)
+			return -EINVAL;
+		if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len))
+			return -EFAULT;
+		set_multicast_list(dev);
+		break;
+
+	case DEPCA_CLR_MCA:	/* Clear all multicast addresses */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		set_multicast_list(dev);
+		break;
+
+	case DEPCA_MCA_EN:	/* Enable pass all multicast addressing */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		set_multicast_list(dev);
+		break;
+
+	case DEPCA_GET_STATS:	/* Get the driver statistics */
+		cli();
+		ioc->len = sizeof(lp->pktStats);
+		if (copy_to_user(ioc->data, &lp->pktStats, ioc->len))
+			status = -EFAULT;
+		sti();
+		break;
+
+	case DEPCA_CLR_STATS:	/* Zero out the driver statistics */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		cli();
+		memset(&lp->pktStats, 0, sizeof(lp->pktStats));
+		sti();
+		break;
+
+	case DEPCA_GET_REG:	/* Get the DEPCA Registers */
+		i = 0;
+		tmp.sval[i++] = inw(DEPCA_NICSR);
+		outw(CSR0, DEPCA_ADDR);	/* status register */
+		tmp.sval[i++] = inw(DEPCA_DATA);
+		memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init));
+		ioc->len = i + sizeof(struct depca_init);
+		if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+			return -EFAULT;
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return status;
 }
 
 #ifdef MODULE
 static struct net_device thisDepca;
-static int irq=7;	/* EDIT THESE LINE FOR YOUR CONFIGURATION */
-static int io=0x200;    /* Or use the irq= io= options to insmod */
+static int irq = 7;		/* EDIT THESE LINE FOR YOUR CONFIGURATION */
+static int io = 0x200;		/* Or use the irq= io= options to insmod */
 MODULE_PARM(irq, "i");
 MODULE_PARM(io, "i");
 MODULE_PARM_DESC(irq, "DEPCA IRQ number");
 MODULE_PARM_DESC(io, "DEPCA I/O base address");
 
-/* See depca_probe() for autoprobe messages when a module */	
-int
-init_module(void)
+/* See depca_probe() for autoprobe messages when a module */
+int init_module(void)
 {
-  thisDepca.irq=irq;
-  thisDepca.base_addr=io;
-  thisDepca.init = depca_probe;
+	thisDepca.irq = irq;
+	thisDepca.base_addr = io;
+	thisDepca.init = depca_probe;
 
-  if (register_netdev(&thisDepca) != 0)
-    return -EIO;
+	if (register_netdev(&thisDepca) != 0)
+		return -EIO;
 
-  return 0;
+	return 0;
 }
 
-void
-cleanup_module(void)
+void cleanup_module(void)
 {
-  struct depca_private *lp = thisDepca.priv;
+	struct depca_private *lp = thisDepca.priv;
 
-  unregister_netdev(&thisDepca);
-  if (lp) {
-    iounmap(lp->sh_mem);
-#ifdef CONFIG_MCA      
-    if(lp->mca_slot != -1)
-      mca_mark_as_unused(lp->mca_slot);
-#endif                 
-    kfree(lp);
-    thisDepca.priv = NULL;
-  }
-  thisDepca.irq=0;
+	unregister_netdev(&thisDepca);
+	if (lp) {
+		iounmap(lp->sh_mem);
+#ifdef CONFIG_MCA
+		if (lp->mca_slot != -1)
+			mca_mark_as_unused(lp->mca_slot);
+#endif
+		kfree(lp);
+		thisDepca.priv = NULL;
+	}
+	thisDepca.irq = 0;
 
-  release_region(thisDepca.base_addr, DEPCA_TOTAL_SIZE);
+	release_region(thisDepca.base_addr, DEPCA_TOTAL_SIZE);
 }
-#endif /* MODULE */
+#endif				/* MODULE */
 MODULE_LICENSE("GPL");
-
 
+
 /*
  * Local variables:
  *  compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c depca.c"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/dl2k.c linux-2.4.20/drivers/net/dl2k.c
--- linux-2.4.19/drivers/net/dl2k.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/dl2k.c	2002-10-29 11:18:39.000000000 +0000
@@ -1,6 +1,6 @@
 /*  D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
 /*
-    Copyright (c) 2001,2002 by D-Link Corporation
+    Copyright (c) 2001, 2002 by D-Link Corporation
     Written by Edward Peng.<edward_peng@dlink.com.tw>
     Created 03-May-2001, base on Linux' sundance.c.
 
@@ -33,12 +33,13 @@
     1.11	2002/05/23	Added ISR schedule scheme.
     				Fixed miscount of rx frame error for DGE-550SX.
     				Fixed VLAN bug.
+    1.12	2002/06/13	Lock tx_coalesce=1 on 10/100Mbps mode.
  */
 
 #include "dl2k.h"
 
 static char version[] __devinitdata =
-    KERN_INFO "D-Link DL2000-based linux driver v1.11 2002/05/23\n";
+    KERN_INFO "D-Link DL2000-based linux driver v1.12 2002/06/13\n";
 
 #define MAX_UNITS 8
 static int mtu[MAX_UNITS];
@@ -138,15 +139,15 @@
 	}
 	SET_MODULE_OWNER (dev);
 
-#ifdef USE_IO_OPS
-	ioaddr = pci_resource_start (pdev, 0);
-#else
+#ifdef MEM_MAPPING
 	ioaddr = pci_resource_start (pdev, 1);
 	ioaddr = (long) ioremap (ioaddr, RIO_IO_SIZE);
 	if (!ioaddr) {
 		err = -ENOMEM;
 		goto err_out_dev;
 	}
+#else
+	ioaddr = pci_resource_start (pdev, 0);
 #endif
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
@@ -158,6 +159,7 @@
 
 	/* Parse manual configuration */
 	np->an_enable = 1;
+	np->tx_coalesce = 1;
 	if (card_idx < MAX_UNITS) {
 		if (media[card_idx] != NULL) {
 			np->an_enable = 0;
@@ -213,7 +215,7 @@
 
 		if (tx_coalesce < 1)
 			tx_coalesce = 1;
-		if (tx_coalesce > TX_RING_SIZE-1)
+		else if (tx_coalesce > TX_RING_SIZE-1)
 			tx_coalesce = TX_RING_SIZE - 1;
 	}
 	dev->open = &rio_open;
@@ -303,7 +305,7 @@
       err_out_unmap_tx:
 	pci_free_consistent (pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma);
       err_out_iounmap:
-#ifndef USE_IO_OPS
+#ifdef MEM_MAPPING
 	iounmap ((void *) ioaddr);
 
       err_out_dev:
@@ -361,7 +363,7 @@
 	}
 
 	/* Check CRC */
-	crc = ~ether_crc_le(256 - 4, sromdata);
+	crc = ~ether_crc_le (256 - 4, sromdata);
 	if (psrom->crc != crc) {
 		printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
 		return -1;
@@ -636,7 +638,7 @@
 
 	/* DL2K bug: DMA fails to get next descriptor ptr in 10Mbps mode
 	 * Work around: Always use 1 descriptor in 10Mbps mode */
-	if (entry % tx_coalesce == 0 || np->speed == 10)
+	if (entry % np->tx_coalesce == 0 || np->speed == 10)
 		txdesc->status = cpu_to_le64 (entry | tfc_vlan_tag |
 					      WordAlignDisable | 
 					      TxDMAIndicate |
@@ -807,13 +809,8 @@
 		/* Let TxStartThresh stay default value */
 	}
 	/* Maximum Collisions */
-#ifdef ETHER_STATS	
-	if (tx_status & 0x08) 
-		np->stats.collisions16++;
-#else
 	if (tx_status & 0x08) 
 		np->stats.collisions++;
-#endif
 	/* Restart the Tx */
 	writel (readw (dev->base_addr + MACCtrl) | TxEnable, ioaddr + MACCtrl);
 }
@@ -936,6 +933,10 @@
 				mii_get_media_pcs (dev);
 			else
 				mii_get_media (dev);
+			if (np->speed == 1000)
+				np->tx_coalesce = tx_coalesce;
+			else 
+				np->tx_coalesce = 1;
 			macctrl = 0;
 			macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
 			macctrl |= (np->full_duplex) ? DuplexSelect : 0;
@@ -1102,7 +1103,6 @@
 	u16 rx_mode = 0;
 	int i;
 	int bit;
-	int index, crc;
 	struct dev_mc_list *mclist;
 	struct netdev_private *np = dev->priv;
 	
@@ -1124,13 +1124,14 @@
 		for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count; 
 			i++, mclist=mclist->next) {
 
-			crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
+			int index = 0;
+			int crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
 
 			/* The inverted high significant 6 bits of CRC are
 			   used as an index to hashtable */
-			for (index = 0, bit = 0; bit < 6; bit++)
-				if (test_bit(31 - bit, &crc))
-					set_bit(bit, &index);
+			for (bit = 0; bit < 6; bit++)
+				if (crc & (1 << (31 - bit)))
+					index |= (1 << bit);
 
 			hash_table[index / 32] |= (1 << (index % 32));
 		}
@@ -1671,7 +1672,7 @@
 				     np->rx_ring_dma);
 		pci_free_consistent (pdev, TX_TOTAL_SIZE, np->tx_ring,
 				     np->tx_ring_dma);
-#ifndef USE_IO_OPS
+#ifdef MEM_MAPPING
 		iounmap ((char *) (dev->base_addr));
 #endif
 		kfree (dev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/dl2k.h linux-2.4.20/drivers/net/dl2k.h
--- linux-2.4.19/drivers/net/dl2k.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/dl2k.h	2002-10-29 11:18:37.000000000 +0000
@@ -33,15 +33,15 @@
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/time.h>
-#define TX_RING_SIZE	128
-#define TX_QUEUE_LEN	120	/* Limit ring entries actually used.  */
-#define RX_RING_SIZE 	128
+#define TX_RING_SIZE	256
+#define TX_QUEUE_LEN	(TX_RING_SIZE - 1) /* Limit ring entries actually used.*/
+#define RX_RING_SIZE 	256
 #define TX_TOTAL_SIZE	TX_RING_SIZE*sizeof(struct netdev_desc)
 #define RX_TOTAL_SIZE	RX_RING_SIZE*sizeof(struct netdev_desc)
 
 /* This driver was written to use PCI memory space, however x86-oriented
    hardware often uses I/O space accesses. */
-#ifdef USE_IO_OPS
+#ifndef MEM_MAPPING
 #undef readb
 #undef readw
 #undef readl
@@ -658,6 +658,7 @@
 	unsigned int chip_id;		/* PCI table chip id */
 	unsigned int rx_coalesce; 	/* Maximum frames each RxDMAComplete intr */
 	unsigned int rx_timeout; 	/* Wait time between RxDMAComplete intr */
+	unsigned int tx_coalesce;	/* Maximum frames each tx interrupt */
 	unsigned int full_duplex:1;	/* Full-duplex operation requested. */
 	unsigned int an_enable:2;	/* Auto-Negotiated Enable */
 	unsigned int jumbo:1;		/* Jumbo frame enable */
@@ -681,10 +682,10 @@
 };
 
 /* The station address location in the EEPROM. */
-#ifdef USE_IO_OPS
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO  | PCI_ADDR0)
-#else
+#ifdef MEM_MAPPING
 #define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
+#else
+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO  | PCI_ADDR0)
 #endif
 /* The struct pci_device_id consist of:
         vendor, device          Vendor and device ID to match (or PCI_ANY_ID)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e100/LICENSE linux-2.4.20/drivers/net/e100/LICENSE
--- linux-2.4.19/drivers/net/e100/LICENSE	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e100/LICENSE	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,339 @@
+
+"This software program is licensed subject to the GNU General Public License 
+(GPL). Version 2, June 1991, available at 
+<http://www.fsf.org/copyleft/gpl.html>"
+
+GNU General Public License 
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.  
+59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to 
+share and change it. By contrast, the GNU General Public License is intended
+to guarantee your freedom to share and change free software--to make sure 
+the software is free for all its users. This General Public License applies 
+to most of the Free Software Foundation's software and to any other program 
+whose authors commit to using it. (Some other Free Software Foundation 
+software is covered by the GNU Library General Public License instead.) You 
+can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the freedom 
+to distribute copies of free software (and charge for this service if you 
+wish), that you receive source code or can get it if you want it, that you 
+can change the software or use pieces of it in new free programs; and that 
+you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to 
+deny you these rights or to ask you to surrender the rights. These 
+restrictions translate to certain responsibilities for you if you distribute
+copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or 
+for a fee, you must give the recipients all the rights that you have. You 
+must make sure that they, too, receive or can get the source code. And you 
+must show them these terms so they know their rights.
+ 
+We protect your rights with two steps: (1) copyright the software, and (2) 
+offer you this license which gives you legal permission to copy, distribute 
+and/or modify the software. 
+
+Also, for each author's protection and ours, we want to make certain that 
+everyone understands that there is no warranty for this free software. If 
+the software is modified by someone else and passed on, we want its 
+recipients to know that what they have is not the original, so that any 
+problems introduced by others will not reflect on the original authors' 
+reputations. 
+
+Finally, any free program is threatened constantly by software patents. We 
+wish to avoid the danger that redistributors of a free program will 
+individually obtain patent licenses, in effect making the program 
+proprietary. To prevent this, we have made it clear that any patent must be 
+licensed for everyone's free use or not licensed at all. 
+
+The precise terms and conditions for copying, distribution and modification 
+follow. 
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice
+   placed by the copyright holder saying it may be distributed under the 
+   terms of this General Public License. The "Program", below, refers to any
+   such program or work, and a "work based on the Program" means either the 
+   Program or any derivative work under copyright law: that is to say, a 
+   work containing the Program or a portion of it, either verbatim or with 
+   modifications and/or translated into another language. (Hereinafter, 
+   translation is included without limitation in the term "modification".) 
+   Each licensee is addressed as "you". 
+
+   Activities other than copying, distribution and modification are not 
+   covered by this License; they are outside its scope. The act of running 
+   the Program is not restricted, and the output from the Program is covered 
+   only if its contents constitute a work based on the Program (independent 
+   of having been made by running the Program). Whether that is true depends
+   on what the Program does. 
+
+1. You may copy and distribute verbatim copies of the Program's source code 
+   as you receive it, in any medium, provided that you conspicuously and 
+   appropriately publish on each copy an appropriate copyright notice and 
+   disclaimer of warranty; keep intact all the notices that refer to this 
+   License and to the absence of any warranty; and give any other recipients 
+   of the Program a copy of this License along with the Program. 
+
+   You may charge a fee for the physical act of transferring a copy, and you 
+   may at your option offer warranty protection in exchange for a fee. 
+
+2. You may modify your copy or copies of the Program or any portion of it, 
+   thus forming a work based on the Program, and copy and distribute such 
+   modifications or work under the terms of Section 1 above, provided that 
+   you also meet all of these conditions: 
+
+   * a) You must cause the modified files to carry prominent notices stating 
+        that you changed the files and the date of any change. 
+
+   * b) You must cause any work that you distribute or publish, that in 
+        whole or in part contains or is derived from the Program or any part 
+        thereof, to be licensed as a whole at no charge to all third parties
+        under the terms of this License. 
+
+   * c) If the modified program normally reads commands interactively when 
+        run, you must cause it, when started running for such interactive 
+        use in the most ordinary way, to print or display an announcement 
+        including an appropriate copyright notice and a notice that there is
+        no warranty (or else, saying that you provide a warranty) and that 
+        users may redistribute the program under these conditions, and 
+        telling the user how to view a copy of this License. (Exception: if 
+        the Program itself is interactive but does not normally print such 
+        an announcement, your work based on the Program is not required to 
+        print an announcement.) 
+
+   These requirements apply to the modified work as a whole. If identifiable 
+   sections of that work are not derived from the Program, and can be 
+   reasonably considered independent and separate works in themselves, then 
+   this License, and its terms, do not apply to those sections when you 
+   distribute them as separate works. But when you distribute the same 
+   sections as part of a whole which is a work based on the Program, the 
+   distribution of the whole must be on the terms of this License, whose 
+   permissions for other licensees extend to the entire whole, and thus to 
+   each and every part regardless of who wrote it. 
+
+   Thus, it is not the intent of this section to claim rights or contest 
+   your rights to work written entirely by you; rather, the intent is to 
+   exercise the right to control the distribution of derivative or 
+   collective works based on the Program. 
+
+   In addition, mere aggregation of another work not based on the Program 
+   with the Program (or with a work based on the Program) on a volume of a 
+   storage or distribution medium does not bring the other work under the 
+   scope of this License. 
+
+3. You may copy and distribute the Program (or a work based on it, under 
+   Section 2) in object code or executable form under the terms of Sections 
+   1 and 2 above provided that you also do one of the following: 
+
+   * a) Accompany it with the complete corresponding machine-readable source 
+        code, which must be distributed under the terms of Sections 1 and 2 
+        above on a medium customarily used for software interchange; or, 
+
+   * b) Accompany it with a written offer, valid for at least three years, 
+        to give any third party, for a charge no more than your cost of 
+        physically performing source distribution, a complete machine-
+        readable copy of the corresponding source code, to be distributed 
+        under the terms of Sections 1 and 2 above on a medium customarily 
+        used for software interchange; or, 
+
+   * c) Accompany it with the information you received as to the offer to 
+        distribute corresponding source code. (This alternative is allowed 
+        only for noncommercial distribution and only if you received the 
+        program in object code or executable form with such an offer, in 
+        accord with Subsection b above.) 
+
+   The source code for a work means the preferred form of the work for 
+   making modifications to it. For an executable work, complete source code 
+   means all the source code for all modules it contains, plus any 
+   associated interface definition files, plus the scripts used to control 
+   compilation and installation of the executable. However, as a special 
+   exception, the source code distributed need not include anything that is 
+   normally distributed (in either source or binary form) with the major 
+   components (compiler, kernel, and so on) of the operating system on which
+   the executable runs, unless that component itself accompanies the 
+   executable. 
+
+   If distribution of executable or object code is made by offering access 
+   to copy from a designated place, then offering equivalent access to copy 
+   the source code from the same place counts as distribution of the source 
+   code, even though third parties are not compelled to copy the source 
+   along with the object code. 
+
+4. You may not copy, modify, sublicense, or distribute the Program except as
+   expressly provided under this License. Any attempt otherwise to copy, 
+   modify, sublicense or distribute the Program is void, and will 
+   automatically terminate your rights under this License. However, parties 
+   who have received copies, or rights, from you under this License will not
+   have their licenses terminated so long as such parties remain in full 
+   compliance. 
+
+5. You are not required to accept this License, since you have not signed 
+   it. However, nothing else grants you permission to modify or distribute 
+   the Program or its derivative works. These actions are prohibited by law 
+   if you do not accept this License. Therefore, by modifying or 
+   distributing the Program (or any work based on the Program), you 
+   indicate your acceptance of this License to do so, and all its terms and
+   conditions for copying, distributing or modifying the Program or works 
+   based on it. 
+
+6. Each time you redistribute the Program (or any work based on the 
+   Program), the recipient automatically receives a license from the 
+   original licensor to copy, distribute or modify the Program subject to 
+   these terms and conditions. You may not impose any further restrictions 
+   on the recipients' exercise of the rights granted herein. You are not 
+   responsible for enforcing compliance by third parties to this License. 
+
+7. If, as a consequence of a court judgment or allegation of patent 
+   infringement or for any other reason (not limited to patent issues), 
+   conditions are imposed on you (whether by court order, agreement or 
+   otherwise) that contradict the conditions of this License, they do not 
+   excuse you from the conditions of this License. If you cannot distribute 
+   so as to satisfy simultaneously your obligations under this License and 
+   any other pertinent obligations, then as a consequence you may not 
+   distribute the Program at all. For example, if a patent license would 
+   not permit royalty-free redistribution of the Program by all those who 
+   receive copies directly or indirectly through you, then the only way you 
+   could satisfy both it and this License would be to refrain entirely from 
+   distribution of the Program. 
+
+   If any portion of this section is held invalid or unenforceable under any
+   particular circumstance, the balance of the section is intended to apply
+   and the section as a whole is intended to apply in other circumstances. 
+
+   It is not the purpose of this section to induce you to infringe any 
+   patents or other property right claims or to contest validity of any 
+   such claims; this section has the sole purpose of protecting the 
+   integrity of the free software distribution system, which is implemented 
+   by public license practices. Many people have made generous contributions
+   to the wide range of software distributed through that system in 
+   reliance on consistent application of that system; it is up to the 
+   author/donor to decide if he or she is willing to distribute software 
+   through any other system and a licensee cannot impose that choice. 
+
+   This section is intended to make thoroughly clear what is believed to be 
+   a consequence of the rest of this License. 
+
+8. If the distribution and/or use of the Program is restricted in certain 
+   countries either by patents or by copyrighted interfaces, the original 
+   copyright holder who places the Program under this License may add an 
+   explicit geographical distribution limitation excluding those countries, 
+   so that distribution is permitted only in or among countries not thus 
+   excluded. In such case, this License incorporates the limitation as if 
+   written in the body of this License. 
+
+9. The Free Software Foundation may publish revised and/or new versions of 
+   the General Public License from time to time. Such new versions will be 
+   similar in spirit to the present version, but may differ in detail to 
+   address new problems or concerns. 
+
+   Each version is given a distinguishing version number. If the Program 
+   specifies a version number of this License which applies to it and "any 
+   later version", you have the option of following the terms and 
+   conditions either of that version or of any later version published by 
+   the Free Software Foundation. If the Program does not specify a version 
+   number of this License, you may choose any version ever published by the 
+   Free Software Foundation. 
+
+10. If you wish to incorporate parts of the Program into other free programs
+    whose distribution conditions are different, write to the author to ask 
+    for permission. For software which is copyrighted by the Free Software 
+    Foundation, write to the Free Software Foundation; we sometimes make 
+    exceptions for this. Our decision will be guided by the two goals of 
+    preserving the free status of all derivatives of our free software and 
+    of promoting the sharing and reuse of software generally. 
+
+   NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 
+    FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 
+    OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 
+    PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
+    EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE 
+    ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH 
+    YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL 
+    NECESSARY SERVICING, REPAIR OR CORRECTION. 
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 
+    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 
+    REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR 
+    DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL 
+    DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM 
+    (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED 
+    INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF 
+    THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR 
+    OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest 
+possible use to the public, the best way to achieve this is to make it free 
+software which everyone can redistribute and change under these terms. 
+
+To do so, attach the following notices to the program. It is safest to 
+attach them to the start of each source file to most effectively convey the
+exclusion of warranty; and each file should have at least the "copyright" 
+line and a pointer to where the full notice is found. 
+
+one line to give the program's name and an idea of what it does.
+Copyright (C) yyyy  name of author
+
+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.
+
+Also add information on how to contact you by electronic and paper mail. 
+
+If the program is interactive, make it output a short notice like this when 
+it starts in an interactive mode: 
+
+Gnomovision version 69, Copyright (C) year name of author Gnomovision comes 
+with ABSOLUTELY NO WARRANTY; for details type 'show w'.  This is free 
+software, and you are welcome to redistribute it under certain conditions; 
+type 'show c' for details.
+
+The hypothetical commands 'show w' and 'show c' should show the appropriate 
+parts of the General Public License. Of course, the commands you use may be 
+called something other than 'show w' and 'show c'; they could even be 
+mouse-clicks or menu items--whatever suits your program. 
+
+You should also get your employer (if you work as a programmer) or your 
+school, if any, to sign a "copyright disclaimer" for the program, if 
+necessary. Here is a sample; alter the names: 
+
+Yoyodyne, Inc., hereby disclaims all copyright interest in the program 
+'Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+signature of Ty Coon, 1 April 1989
+Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into 
+proprietary programs. If your program is a subroutine library, you may 
+consider it more useful to permit linking proprietary applications with the 
+library. If this is what you want to do, use the GNU Library General Public 
+License instead of this License.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e100/Makefile linux-2.4.20/drivers/net/e100/Makefile
--- linux-2.4.19/drivers/net/e100/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e100/Makefile	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,11 @@
+#
+# Makefile for the Intel's E100 ethernet driver
+#
+
+O_TARGET := e100.o
+
+obj-y	 :=	e100_main.o e100_config.o e100_proc.o e100_phy.o \
+		e100_eeprom.o e100_test.o
+obj-m	 := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e100/e100.h linux-2.4.20/drivers/net/e100/e100.h
--- linux-2.4.19/drivers/net/e100/e100.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e100/e100.h	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,1001 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+*******************************************************************************/
+
+#ifndef _E100_INC_
+#define _E100_INC_
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <linux/reboot.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <asm/processor.h>
+#include <linux/ethtool.h>
+#include <linux/inetdevice.h>
+#include <linux/bitops.h>
+
+#include <linux/if.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+#include <linux/ip.h>
+
+#define E100_REGS_LEN 1
+/*
+ *  Configure parameters for buffers per controller.
+ *  If the machine this is being used on is a faster machine (i.e. > 150MHz)
+ *  and running on a 10MBS network then more queueing of data occurs. This
+ *  may indicate the some of the numbers below should be adjusted.  Here are
+ *  some typical numbers:
+ *                             MAX_TCB 64
+ *                             MAX_RFD 64
+ *  The default numbers give work well on most systems tests so no real
+ *  adjustments really need to take place.  Also, if the machine is connected
+ *  to a 100MBS network the numbers described above can be lowered from the
+ *  defaults as considerably less data will be queued.
+ */
+
+#define TX_FRAME_CNT   8	/* consecutive transmit frames per interrupt */
+/* TX_FRAME_CNT must be less than MAX_TCB    */
+
+#define E100_DEFAULT_TCB   64
+#define E100_MIN_TCB       2*TX_FRAME_CNT + 3	/* make room for at least 2 interrupts */
+#define E100_MAX_TCB       1024
+
+#define E100_DEFAULT_RFD   64
+#define E100_MIN_RFD       8
+#define E100_MAX_RFD       1024
+
+#define E100_DEFAULT_XSUM         true
+#define E100_DEFAULT_BER          ZLOCK_MAX_ERRORS
+#define E100_DEFAULT_SPEED_DUPLEX 0
+#define E100_DEFAULT_FC           0
+#define E100_DEFAULT_IFS          true
+#define E100_DEFAULT_UCODE        true
+
+#define TX_THRSHLD     8
+
+/* IFS parameters */
+#define MIN_NUMBER_OF_TRANSMITS_100 1000
+#define MIN_NUMBER_OF_TRANSMITS_10  100
+
+#define E100_MAX_NIC 16
+
+#define E100_MAX_SCB_WAIT	100	/* Max udelays in wait_scb */
+#define E100_MAX_CU_IDLE_WAIT	50	/* Max udelays in wait_cus_idle */
+
+/* HWI feature related constant */
+#define HWI_MAX_LOOP                    100
+#define MAX_SAME_RESULTS		3
+#define HWI_REGISTER_GRANULARITY        80	/* register granularity = 80 Cm */
+#define HWI_NEAR_END_BOUNDARY           1000	/* Near end is defined as < 10 meters */
+
+/* CPUSAVER_BUNDLE_MAX: Sets the maximum number of frames that will be bundled.
+ * In some situations, such as the TCP windowing algorithm, it may be
+ * better to limit the growth of the bundle size than let it go as
+ * high as it can, because that could cause too much added latency.
+ * The default is six, because this is the number of packets in the
+ * default TCP window size.  A value of 1 would make CPUSaver indicate
+ * an interrupt for every frame received.  If you do not want to put
+ * a limit on the bundle size, set this value to xFFFF.
+ */
+#define E100_DEFAULT_CPUSAVER_BUNDLE_MAX	6
+#define E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY	0x600
+#define E100_DEFAULT_BUNDLE_SMALL_FR		false
+
+/* end of configurables */
+
+/* ====================================================================== */
+/*                                hw                                      */
+/* ====================================================================== */
+
+/* timeout for command completion */
+#define E100_CMD_WAIT   100	/* iterations */
+
+struct driver_stats {
+	struct net_device_stats net_stats;
+
+	unsigned long tx_late_col;
+	unsigned long tx_ok_defrd;
+	unsigned long tx_one_retry;
+	unsigned long tx_mt_one_retry;
+	unsigned long rcv_cdt_frames;
+	unsigned long xmt_fc_pkts;
+	unsigned long rcv_fc_pkts;
+	unsigned long rcv_fc_unsupported;
+	unsigned long xmt_tco_pkts;
+	unsigned long rcv_tco_pkts;
+	unsigned long rx_intr_pkts;
+};
+
+/* TODO: kill me when we can do C99 */
+#define false		(0)
+#define true		(1)
+
+/* Changed for 82558 and 82559 enhancements */
+/* defines for 82558/9 flow control CSR values */
+#define DFLT_FC_THLD       0x00	/* Rx FIFO threshold of 0.5KB free  */
+#define DFLT_FC_CMD        0x00	/* FC Command in CSR */
+
+/* ====================================================================== */
+/*                              equates                                   */
+/* ====================================================================== */
+
+/*
+ * These are general purpose defines 
+ */
+
+/* Bit Mask definitions */
+#define BIT_0       0x0001
+#define BIT_1       0x0002
+#define BIT_2       0x0004
+#define BIT_3       0x0008
+#define BIT_4       0x0010
+#define BIT_5       0x0020
+#define BIT_6       0x0040
+#define BIT_7       0x0080
+#define BIT_8       0x0100
+#define BIT_9       0x0200
+#define BIT_10      0x0400
+#define BIT_11      0x0800
+#define BIT_12      0x1000
+#define BIT_13      0x2000
+#define BIT_14      0x4000
+#define BIT_15      0x8000
+#define BIT_28      0x10000000
+
+#define BIT_0_2     0x0007
+#define BIT_0_3     0x000F
+#define BIT_0_4     0x001F
+#define BIT_0_5     0x003F
+#define BIT_0_6     0x007F
+#define BIT_0_7     0x00FF
+#define BIT_0_8     0x01FF
+#define BIT_0_13    0x3FFF
+#define BIT_0_15    0xFFFF
+#define BIT_1_2     0x0006
+#define BIT_1_3     0x000E
+#define BIT_2_5     0x003C
+#define BIT_3_4     0x0018
+#define BIT_4_5     0x0030
+#define BIT_4_6     0x0070
+#define BIT_4_7     0x00F0
+#define BIT_5_7     0x00E0
+#define BIT_5_12    0x1FE0
+#define BIT_5_15    0xFFE0
+#define BIT_6_7     0x00c0
+#define BIT_7_11    0x0F80
+#define BIT_8_10    0x0700
+#define BIT_9_13    0x3E00
+#define BIT_12_15   0xF000
+#define BIT_8_15    0xFF00
+
+#define BIT_16_20   0x001F0000
+#define BIT_21_25   0x03E00000
+#define BIT_26_27   0x0C000000
+
+/* Transmit Threshold related constants */
+#define DEFAULT_TX_PER_UNDERRUN         20000
+
+#define MAX_MULTICAST_ADDRS             64
+#define MAX_FILTER                      16
+
+#define FULL_DUPLEX      2
+#define HALF_DUPLEX      1
+
+/*
+ * These defines are specific to the 82557 
+ */
+
+/* E100 PORT functions -- lower 4 bits */
+#define PORT_SOFTWARE_RESET         0
+#define PORT_SELFTEST               1
+#define PORT_SELECTIVE_RESET        2
+#define PORT_DUMP                   3
+
+/* SCB Status Word bit definitions */
+/* Interrupt status/ack fields */
+/* ER and FCP interrupts for 82558 masks  */
+#define SCB_STATUS_ACK_MASK        BIT_8_15	/* Status Mask */
+#define SCB_STATUS_ACK_CX          BIT_15	/* CU Completed Action Cmd */
+#define SCB_STATUS_ACK_FR          BIT_14	/* RU Received A Frame */
+#define SCB_STATUS_ACK_CNA         BIT_13	/* CU Became Inactive (IDLE) */
+#define SCB_STATUS_ACK_RNR         BIT_12	/* RU Became Not Ready */
+#define SCB_STATUS_ACK_MDI         BIT_11	/* MDI read or write done */
+#define SCB_STATUS_ACK_SWI         BIT_10	/* S/W generated interrupt */
+#define SCB_STATUS_ACK_ER          BIT_9	/* Early Receive */
+#define SCB_STATUS_ACK_FCP         BIT_8	/* Flow Control Pause */
+
+/*- CUS Fields */
+#define SCB_CUS_MASK            (BIT_6 | BIT_7)	/* CUS 2-bit Mask */
+#define SCB_CUS_IDLE            0	/* CU Idle */
+#define SCB_CUS_SUSPEND         BIT_6	/* CU Suspended */
+#define SCB_CUS_ACTIVE          BIT_7	/* CU Active */
+
+/*- RUS Fields */
+#define SCB_RUS_IDLE            0	/* RU Idle */
+#define SCB_RUS_MASK            BIT_2_5	/* RUS 3-bit Mask */
+#define SCB_RUS_SUSPEND         BIT_2	/* RU Suspended */
+#define SCB_RUS_NO_RESOURCES    BIT_3	/* RU Out Of Resources */
+#define SCB_RUS_READY           BIT_4	/* RU Ready */
+#define SCB_RUS_SUSP_NO_RBDS    (BIT_2 | BIT_5)	/* RU No More RBDs */
+#define SCB_RUS_NO_RBDS         (BIT_3 | BIT_5)	/* RU No More RBDs */
+#define SCB_RUS_READY_NO_RBDS   (BIT_4 | BIT_5)	/* RU Ready, No RBDs */
+
+/* SCB Command Word bit definitions */
+/*- CUC fields */
+/* Changing mask to 4 bits */
+#define SCB_CUC_MASK            BIT_4_7	/* CUC 4-bit Mask */
+#define SCB_CUC_NOOP            0
+#define SCB_CUC_START           BIT_4	/* CU Start */
+#define SCB_CUC_RESUME          BIT_5	/* CU Resume */
+/* Changed for 82558 enhancements */
+#define SCB_CUC_STATIC_RESUME   (BIT_5 | BIT_7)	/* 82558/9 Static Resume */
+#define SCB_CUC_DUMP_ADDR       BIT_6	/* CU Dump Counters Address */
+#define SCB_CUC_DUMP_STAT       (BIT_4 | BIT_6)	/* CU Dump stat. counters */
+#define SCB_CUC_LOAD_BASE       (BIT_5 | BIT_6)	/* Load the CU base */
+/* Below was defined as BIT_4_7 */
+#define SCB_CUC_DUMP_RST_STAT   BIT_4_6	/* CU Dump & reset statistics cntrs */
+
+/*- RUC fields */
+#define SCB_RUC_MASK            BIT_0_2	/* RUC 3-bit Mask */
+#define SCB_RUC_START           BIT_0	/* RU Start */
+#define SCB_RUC_RESUME          BIT_1	/* RU Resume */
+#define SCB_RUC_ABORT           BIT_2	/* RU Abort */
+#define SCB_RUC_LOAD_HDS        (BIT_0 | BIT_2)	/* Load RFD Header Data Size */
+#define SCB_RUC_LOAD_BASE       (BIT_1 | BIT_2)	/* Load the RU base */
+#define SCB_RUC_RBD_RESUME      BIT_0_2	/* RBD resume */
+
+/* Interrupt fields (assuming byte addressing) */
+#define SCB_INT_MASK            BIT_0	/* Mask interrupts */
+#define SCB_SOFT_INT            BIT_1	/* Generate a S/W interrupt */
+/*  Specific Interrupt Mask Bits (upper byte of SCB Command word) */
+#define SCB_FCP_INT_MASK        BIT_2	/* Flow Control Pause */
+#define SCB_ER_INT_MASK         BIT_3	/* Early Receive */
+#define SCB_RNR_INT_MASK        BIT_4	/* RU Not Ready */
+#define SCB_CNA_INT_MASK        BIT_5	/* CU Not Active */
+#define SCB_FR_INT_MASK         BIT_6	/* Frame Received */
+#define SCB_CX_INT_MASK         BIT_7	/* CU eXecution w/ I-bit done */
+#define SCB_BACHELOR_INT_MASK   BIT_2_7	/* 82558 interrupt mask bits */
+
+#define SCB_GCR2_EEPROM_ACCESS_SEMAPHORE BIT_7
+
+/* EEPROM bit definitions */
+/*- EEPROM control register bits */
+#define EN_TRNF          0x10	/* Enable turnoff */
+#define EEDO             0x08	/* EEPROM data out */
+#define EEDI             0x04	/* EEPROM data in (set for writing data) */
+#define EECS             0x02	/* EEPROM chip select (1=hi, 0=lo) */
+#define EESK             0x01	/* EEPROM shift clock (1=hi, 0=lo) */
+
+/*- EEPROM opcodes */
+#define EEPROM_READ_OPCODE          06
+#define EEPROM_WRITE_OPCODE         05
+#define EEPROM_ERASE_OPCODE         07
+#define EEPROM_EWEN_OPCODE          19	/* Erase/write enable */
+#define EEPROM_EWDS_OPCODE          16	/* Erase/write disable */
+
+/*- EEPROM data locations */
+#define EEPROM_NODE_ADDRESS_BYTE_0      0
+#define EEPROM_COMPATIBILITY_WORD       3
+#define EEPROM_PWA_NO                   8
+#define EEPROM_ID_WORD			0x0A
+
+#define EEPROM_SUM                      0xbaba
+
+// Zero Locking Algorithm definitions:
+#define ZLOCK_ZERO_MASK		0x00F0
+#define ZLOCK_MAX_READS		50	
+#define ZLOCK_SET_ZERO		0x2010
+#define ZLOCK_MAX_SLEEP		300 * HZ	
+#define ZLOCK_MAX_ERRORS	300
+
+/* E100 Action Commands */
+#define CB_IA_ADDRESS           1
+#define CB_CONFIGURE            2
+#define CB_MULTICAST            3
+#define CB_TRANSMIT             4
+#define CB_LOAD_MICROCODE       5
+#define CB_LOAD_FILTER		8
+#define CB_MAX_NONTX_CMD        9
+#define CB_IPCB_TRANSMIT        9
+
+/* Pre-defined Filter Bits */
+#define CB_FILTER_EL            0x80000000
+#define CB_FILTER_FIX           0x40000000
+#define CB_FILTER_ARP           0x08000000
+#define CB_FILTER_IA_MATCH      0x02000000
+
+/* Command Block (CB) Field Definitions */
+/*- CB Command Word */
+#define CB_EL_BIT           BIT_15	/* CB EL Bit */
+#define CB_S_BIT            BIT_14	/* CB Suspend Bit */
+#define CB_I_BIT            BIT_13	/* CB Interrupt Bit */
+#define CB_TX_SF_BIT        BIT_3	/* TX CB Flexible Mode */
+#define CB_CMD_MASK         BIT_0_3	/* CB 4-bit CMD Mask */
+#define CB_CID_DEFAULT      (0x1f << 8)	/* CB 5-bit CID (max value) */
+
+/*- CB Status Word */
+#define CB_STATUS_MASK          BIT_12_15	/* CB Status Mask (4-bits) */
+#define CB_STATUS_COMPLETE      BIT_15	/* CB Complete Bit */
+#define CB_STATUS_OK            BIT_13	/* CB OK Bit */
+#define CB_STATUS_UNDERRUN      BIT_12	/* CB A Bit */
+#define CB_STATUS_FAIL          BIT_11	/* CB Fail (F) Bit */
+
+/*misc command bits */
+#define CB_TX_EOF_BIT           BIT_15	/* TX CB/TBD EOF Bit */
+
+/* Config params */
+#define CB_CFIG_BYTE_COUNT          22	/* 22 config bytes */
+#define CB_CFIG_D102_BYTE_COUNT    10
+
+/* Receive Frame Descriptor Fields */
+
+/*- RFD Status Bits */
+#define RFD_RECEIVE_COLLISION   BIT_0	/* Collision detected on Receive */
+#define RFD_IA_MATCH            BIT_1	/* Indv Address Match Bit */
+#define RFD_RX_ERR              BIT_4	/* RX_ERR pin on Phy was set */
+#define RFD_FRAME_TOO_SHORT     BIT_7	/* Receive Frame Short */
+#define RFD_DMA_OVERRUN         BIT_8	/* Receive DMA Overrun */
+#define RFD_NO_RESOURCES        BIT_9	/* No Buffer Space */
+#define RFD_ALIGNMENT_ERROR     BIT_10	/* Alignment Error */
+#define RFD_CRC_ERROR           BIT_11	/* CRC Error */
+#define RFD_STATUS_OK           BIT_13	/* RFD OK Bit */
+#define RFD_STATUS_COMPLETE     BIT_15	/* RFD Complete Bit */
+
+/*- RFD Command Bits*/
+#define RFD_EL_BIT      BIT_15	/* RFD EL Bit */
+#define RFD_S_BIT       BIT_14	/* RFD Suspend Bit */
+#define RFD_H_BIT       BIT_4	/* Header RFD Bit */
+#define RFD_SF_BIT      BIT_3	/* RFD Flexible Mode */
+
+/*- RFD misc bits*/
+#define RFD_EOF_BIT         BIT_15	/* RFD End-Of-Frame Bit */
+#define RFD_F_BIT           BIT_14	/* RFD Buffer Fetch Bit */
+#define RFD_ACT_COUNT_MASK  BIT_0_13	/* RFD Actual Count Mask */
+
+/* Receive Buffer Descriptor Fields*/
+#define RBD_EOF_BIT             BIT_15	/* RBD End-Of-Frame Bit */
+#define RBD_F_BIT               BIT_14	/* RBD Buffer Fetch Bit */
+#define RBD_ACT_COUNT_MASK      BIT_0_13	/* RBD Actual Count Mask */
+
+#define SIZE_FIELD_MASK     BIT_0_13	/* Size of the associated buffer */
+#define RBD_EL_BIT          BIT_15	/* RBD EL Bit */
+
+/* Self Test Results*/
+#define CB_SELFTEST_FAIL_BIT        BIT_12
+#define CB_SELFTEST_DIAG_BIT        BIT_5
+#define CB_SELFTEST_REGISTER_BIT    BIT_3
+#define CB_SELFTEST_ROM_BIT         BIT_2
+
+#define CB_SELFTEST_ERROR_MASK ( \
+                CB_SELFTEST_FAIL_BIT | CB_SELFTEST_DIAG_BIT | \
+                CB_SELFTEST_REGISTER_BIT | CB_SELFTEST_ROM_BIT)
+
+/* adapter vendor & device ids */
+#define PCI_OHIO_BOARD   0x10f0	/* subdevice ID, Ohio dual port nic */
+
+/* Values for PCI_REV_ID_REGISTER values */
+#define D101A4_REV_ID      4	/* 82558 A4 stepping */
+#define D101B0_REV_ID      5	/* 82558 B0 stepping */
+#define D101MA_REV_ID      8	/* 82559 A0 stepping */
+#define D101S_REV_ID      9	/* 82559S A-step */
+#define D102_REV_ID      12
+#define D102C_REV_ID     13	/* 82550 step C */
+#define D102E_REV_ID     15
+
+/* ############Start of 82555 specific defines################## */
+
+#define PHY_82555_LED_SWITCH_CONTROL    	0x1b	/* 82555 led switch control register */
+
+/* 82555 led switch control reg. opcodes */
+#define PHY_82555_LED_NORMAL_CONTROL    0	// control back to the 8255X
+#define PHY_82555_LED_DRIVER_CONTROL    BIT_2	// the driver is in control
+#define PHY_82555_LED_OFF               BIT_2	// activity LED is off
+#define PHY_82555_LED_ON_559           (BIT_0 | BIT_2)	// activity LED is on for 559 and later
+#define PHY_82555_LED_ON_PRE_559       (BIT_0 | BIT_1 | BIT_2)	// activity LED is on for 558 and before
+
+// Describe the state of the phy led.
+// needed for the function : 'e100_blink_timer'
+enum led_state_e {
+	LED_OFF = 0,
+	LED_ON,
+};
+
+/* ############End of 82555 specific defines##################### */
+
+#define RFD_PARSE_BIT			BIT_3
+#define RFD_TCP_PACKET			0x00
+#define RFD_UDP_PACKET			0x01
+#define TCPUDP_CHECKSUM_BIT_VALID	BIT_4
+#define TCPUDP_CHECKSUM_VALID		BIT_5
+#define CHECKSUM_PROTOCOL_MASK		0x03
+
+#define VLAN_SIZE   4
+#define CHKSUM_SIZE 2
+#define RFD_DATA_SIZE (ETH_FRAME_LEN + CHKSUM_SIZE + VLAN_SIZE)
+
+/* Bits for bdp->flags */
+#define DF_LINK_FC_CAP     0x00000001	/* Link is flow control capable */
+#define DF_CSUM_OFFLOAD    0x00000002
+#define DF_UCODE_LOADED    0x00000004
+#define USE_IPCB           0x00000008	/* set if using ipcb for transmits */
+#define IS_BACHELOR        0x00000010	/* set if 82558 or newer board */
+#define IS_ICH             0x00000020
+#define DF_SPEED_FORCED    0x00000040	/* set if speed is forced */
+#define LED_IS_ON	   0x00000080	/* LED is turned ON by the driver */
+#define DF_LINK_FC_TX_ONLY 0x00000100	/* Received PAUSE frames are honored*/
+
+typedef struct net_device_stats net_dev_stats_t;
+
+/* needed macros */
+/* These macros use the bdp pointer. If you use them it better be defined */
+#define PREV_TCB_USED(X)  ((X).tail ? (X).tail - 1 : bdp->params.TxDescriptors - 1)
+#define NEXT_TCB_TOUSE(X) ((((X) + 1) >= bdp->params.TxDescriptors) ? 0 : (X) + 1)
+#define TCB_TO_USE(X)     ((X).tail)
+#define TCBS_AVAIL(X)     (NEXT_TCB_TOUSE( NEXT_TCB_TOUSE((X).tail)) != (X).head)
+
+#define RFD_POINTER(skb,bdp)      ((rfd_t *) (((unsigned char *)((skb)->data))-((bdp)->rfd_size)))
+#define SKB_RFD_STATUS(skb,bdp)   ((RFD_POINTER((skb),(bdp)))->rfd_header.cb_status)
+
+/* ====================================================================== */
+/*                              82557                                     */
+/* ====================================================================== */
+
+/* Changed for 82558 enhancement */
+typedef struct _d101_scb_ext_t {
+	u32 scb_rx_dma_cnt;	/* Rx DMA byte count */
+	u8 scb_early_rx_int;	/* Early Rx DMA byte count */
+	u8 scb_fc_thld;	/* Flow Control threshold */
+	u8 scb_fc_xon_xoff;	/* Flow Control XON/XOFF values */
+	u8 scb_pmdr;	/* Power Mgmt. Driver Reg */
+} d101_scb_ext __attribute__ ((__packed__));
+
+/* Changed for 82559 enhancement */
+typedef struct _d101m_scb_ext_t {
+	u32 scb_rx_dma_cnt;	/* Rx DMA byte count */
+	u8 scb_early_rx_int;	/* Early Rx DMA byte count */
+	u8 scb_fc_thld;	/* Flow Control threshold */
+	u8 scb_fc_xon_xoff;	/* Flow Control XON/XOFF values */
+	u8 scb_pmdr;	/* Power Mgmt. Driver Reg */
+	u8 scb_gen_ctrl;	/* General Control */
+	u8 scb_gen_stat;	/* General Status */
+	u16 scb_reserved;	/* Reserved */
+	u32 scb_function_event;	/* Cardbus Function Event */
+	u32 scb_function_event_mask;	/* Cardbus Function Mask */
+	u32 scb_function_present_state;	/* Cardbus Function state */
+	u32 scb_force_event;	/* Cardbus Force Event */
+} d101m_scb_ext __attribute__ ((__packed__));
+
+/* Changed for 82550 enhancement */
+typedef struct _d102_scb_ext_t {
+	u32 scb_rx_dma_cnt;	/* Rx DMA byte count */
+	u8 scb_early_rx_int;	/* Early Rx DMA byte count */
+	u8 scb_fc_thld;	/* Flow Control threshold */
+	u8 scb_fc_xon_xoff;	/* Flow Control XON/XOFF values */
+	u8 scb_pmdr;	/* Power Mgmt. Driver Reg */
+	u8 scb_gen_ctrl;	/* General Control */
+	u8 scb_gen_stat;	/* General Status */
+	u8 scb_gen_ctrl2;
+	u8 scb_reserved;	/* Reserved */
+	u32 scb_scheduling_reg;
+	u32 scb_reserved2;
+	u32 scb_function_event;	/* Cardbus Function Event */
+	u32 scb_function_event_mask;	/* Cardbus Function Mask */
+	u32 scb_function_present_state;	/* Cardbus Function state */
+	u32 scb_force_event;	/* Cardbus Force Event */
+} d102_scb_ext __attribute__ ((__packed__));
+
+/*
+ * 82557 status control block. this will be memory mapped & will hang of the
+ * the bdp, which hangs of the bdp. This is the brain of it.
+ */
+typedef struct _scb_t {
+	u16 scb_status;	/* SCB Status register */
+	u8 scb_cmd_low;	/* SCB Command register (low byte) */
+	u8 scb_cmd_hi;	/* SCB Command register (high byte) */
+	u32 scb_gen_ptr;	/* SCB General pointer */
+	u32 scb_port;	/* PORT register */
+	u16 scb_flsh_cntrl;	/* Flash Control register */
+	u16 scb_eprm_cntrl;	/* EEPROM control register */
+	u32 scb_mdi_cntrl;	/* MDI Control Register */
+	/* Changed for 82558 enhancement */
+	union {
+		u32 scb_rx_dma_cnt;	/* Rx DMA byte count */
+		d101_scb_ext d101_scb;	/* 82558/9 specific fields */
+		d101m_scb_ext d101m_scb;	/* 82559 specific fields */
+		d102_scb_ext d102_scb;
+	} scb_ext;
+} scb_t __attribute__ ((__packed__));
+
+/* Self test
+ * This is used to dump results of the self test 
+ */
+typedef struct _self_test_t {
+	u32 st_sign;	/* Self Test Signature */
+	u32 st_result;	/* Self Test Results */
+} self_test_t __attribute__ ((__packed__));
+
+/* 
+ *  Statistical Counters 
+ */
+/* 82557 counters */
+typedef struct _basic_cntr_t {
+	u32 xmt_gd_frames;	/* Good frames transmitted */
+	u32 xmt_max_coll;	/* Fatal frames -- had max collisions */
+	u32 xmt_late_coll;	/* Fatal frames -- had a late coll. */
+	u32 xmt_uruns;	/* Xmit underruns (fatal or re-transmit) */
+	u32 xmt_lost_crs;	/* Frames transmitted without CRS */
+	u32 xmt_deferred;	/* Deferred transmits */
+	u32 xmt_sngl_coll;	/* Transmits that had 1 and only 1 coll. */
+	u32 xmt_mlt_coll;	/* Transmits that had multiple coll. */
+	u32 xmt_ttl_coll;	/* Transmits that had 1+ collisions. */
+	u32 rcv_gd_frames;	/* Good frames received */
+	u32 rcv_crc_errs;	/* Aligned frames that had a CRC error */
+	u32 rcv_algn_errs;	/* Receives that had alignment errors */
+	u32 rcv_rsrc_err;	/* Good frame dropped cuz no resources */
+	u32 rcv_oruns;	/* Overrun errors - bus was busy */
+	u32 rcv_err_coll;	/* Received frms. that encountered coll. */
+	u32 rcv_shrt_frames;	/* Received frames that were to short */
+} basic_cntr_t;
+
+/* 82558 extended statistic counters */
+typedef struct _ext_cntr_t {
+	u32 xmt_fc_frames;
+	u32 rcv_fc_frames;
+	u32 rcv_fc_unsupported;
+} ext_cntr_t;
+
+/* 82559 TCO statistic counters */
+typedef struct _tco_cntr_t {
+	u16 xmt_tco_frames;
+	u16 rcv_tco_frames;
+} tco_cntr_t;
+
+/* Structures to access thet physical dump area */
+/* Use one of these types, according to the statisitcal counters mode,
+   to cast the pointer to the physical dump area and access the cmd_complete
+   DWORD. */
+
+/* 557-mode : only basic counters + cmd_complete */
+typedef struct _err_cntr_557_t {
+	basic_cntr_t basic_stats;
+	u32 cmd_complete;
+} err_cntr_557_t;
+
+/* 558-mode : basic + extended counters + cmd_complete */
+typedef struct _err_cntr_558_t {
+	basic_cntr_t basic_stats;
+	ext_cntr_t extended_stats;
+	u32 cmd_complete;
+} err_cntr_558_t;
+
+/* 559-mode : basic + extended + TCO counters + cmd_complete */
+typedef struct _err_cntr_559_t {
+	basic_cntr_t basic_stats;
+	ext_cntr_t extended_stats;
+	tco_cntr_t tco_stats;
+	u32 cmd_complete;
+} err_cntr_559_t;
+
+/* This typedef defines the struct needed to hold the largest number of counters */
+typedef err_cntr_559_t max_counters_t;
+
+/* Different statistical-counters mode the controller may be in */
+typedef enum _stat_mode_t {
+	E100_BASIC_STATS = 0,	/* 82557 stats : 16 counters / 16 dw */
+	E100_EXTENDED_STATS,	/* 82558 stats : 19 counters / 19 dw */
+	E100_TCO_STATS		/* 82559 stats : 21 counters / 20 dw */
+} stat_mode_t;
+
+/* dump statistical counters complete codes */
+#define DUMP_STAT_COMPLETED	0xA005
+#define DUMP_RST_STAT_COMPLETED	0xA007
+
+/* Command Block (CB) Generic Header Structure*/
+typedef struct _cb_header_t {
+	u16 cb_status;	/* Command Block Status */
+	u16 cb_cmd;	/* Command Block Command */
+	u32 cb_lnk_ptr;	/* Link To Next CB */
+} cb_header_t __attribute__ ((__packed__));
+
+//* Individual Address Command Block (IA_CB)*/
+typedef struct _ia_cb_t {
+	cb_header_t ia_cb_hdr;
+	u8 ia_addr[ETH_ALEN];
+} ia_cb_t __attribute__ ((__packed__));
+
+/* Configure Command Block (CONFIG_CB)*/
+typedef struct _config_cb_t {
+	cb_header_t cfg_cbhdr;
+	u8 cfg_byte[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT];
+} config_cb_t __attribute__ ((__packed__));
+
+/* MultiCast Command Block (MULTICAST_CB)*/
+typedef struct _multicast_cb_t {
+	cb_header_t mc_cbhdr;
+	u16 mc_count;	/* Number of multicast addresses */
+	u8 mc_addr[(ETH_ALEN * MAX_MULTICAST_ADDRS)];
+} mltcst_cb_t __attribute__ ((__packed__));
+
+#define UCODE_MAX_DWORDS	134
+/* Load Microcode Command Block (LOAD_UCODE_CB)*/
+typedef struct _load_ucode_cb_t {
+	cb_header_t load_ucode_cbhdr;
+	u32 ucode_dword[UCODE_MAX_DWORDS];
+} load_ucode_cb_t __attribute__ ((__packed__));
+
+/* Load Programmable Filter Data*/
+typedef struct _filter_cb_t {
+	cb_header_t filter_cb_hdr;
+	u32 filter_data[MAX_FILTER];
+} filter_cb_t __attribute__ ((__packed__));
+
+/* NON_TRANSMIT_CB -- Generic Non-Transmit Command Block 
+ */
+typedef struct _nxmit_cb_t {
+	union {
+		config_cb_t config;
+		ia_cb_t setup;
+		load_ucode_cb_t load_ucode;
+		mltcst_cb_t multicast;
+		filter_cb_t filter;
+	} ntcb;
+} nxmit_cb_t __attribute__ ((__packed__));
+
+/*Block for queuing for postponed execution of the non-transmit commands*/
+typedef struct _nxmit_cb_entry_t {
+	struct list_head list_elem;
+	nxmit_cb_t *non_tx_cmd;
+	dma_addr_t dma_addr;
+	unsigned long expiration_time;
+} nxmit_cb_entry_t;
+
+/* States for postponed non tx commands execution */
+typedef enum _non_tx_cmd_state_t {
+	E100_NON_TX_IDLE = 0,	/* No queued NON-TX commands */
+	E100_WAIT_TX_FINISH,	/* Wait for completion of the TX activities */
+	E100_WAIT_NON_TX_FINISH	/* Wait for completion of the non TX command */
+} non_tx_cmd_state_t;
+
+/* some defines for the ipcb */
+#define IPCB_IP_CHECKSUM_ENABLE 	BIT_4
+#define IPCB_TCPUDP_CHECKSUM_ENABLE	BIT_5
+#define IPCB_TCP_PACKET 		BIT_6
+#define IPCB_LARGESEND_ENABLE 		BIT_7
+#define IPCB_HARDWAREPARSING_ENABLE	BIT_0
+#define IPCB_INSERTVLAN_ENABLE 		BIT_1
+#define IPCB_IP_ACTIVATION_DEFAULT      IPCB_HARDWAREPARSING_ENABLE
+
+#define FOLD_CSUM(_XSUM)  ((((_XSUM << 16) | (_XSUM >> 16)) + _XSUM) >> 16)
+
+/* Transmit Buffer Descriptor (TBD)*/
+typedef struct _tbd_t {
+	u32 tbd_buf_addr;	/* Physical Transmit Buffer Address */
+	u16 tbd_buf_cnt;	/* Actual Count Of Bytes */
+	u16 padd;
+} tbd_t __attribute__ ((__packed__));
+
+/* d102 specific fields */
+typedef struct _tcb_ipcb_t {
+	u16 schedule_low;
+	u8 ip_schedule;
+	u8 ip_activation_high;
+	u16 vlan;
+	u8 ip_header_offset;
+	u8 tcp_header_offset;
+	union {
+		u32 sec_rec_phys_addr;
+		u32 tbd_zero_address;
+	} tbd_sec_addr;
+	union {
+		u16 sec_rec_size;
+		u16 tbd_zero_size;
+	} tbd_sec_size;
+	u16 total_tcp_payload;
+} tcb_ipcb_t __attribute__ ((__packed__));
+
+#define E100_TBD_ARRAY_SIZE (2+MAX_SKB_FRAGS)
+
+/* Transmit Command Block (TCB)*/
+struct _tcb_t {
+	cb_header_t tcb_hdr;
+	u32 tcb_tbd_ptr;	/* TBD address */
+	u16 tcb_cnt;	/* Data Bytes In TCB past header */
+	u8 tcb_thrshld;	/* TX Threshold for FIFO Extender */
+	u8 tcb_tbd_num;
+
+	union {
+		tcb_ipcb_t ipcb;	/* d102 ipcb fields */
+		tbd_t tbd_array[E100_TBD_ARRAY_SIZE];
+	} tcbu;
+
+	/* From here onward we can dump anything we want as long as the
+	 * size of the total structure is a multiple of a paragraph
+	 * boundary ( i.e. -16 bit aligned ).
+	 */
+	tbd_t *tbd_ptr;
+
+	u32 tcb_tbd_dflt_ptr;	/* TBD address for non-segmented packet */
+	u32 tcb_tbd_expand_ptr;	/* TBD address for segmented packet */
+
+	struct sk_buff *tcb_skb;	/* the associated socket buffer */
+	dma_addr_t tcb_phys;	/* phys addr of the TCB */
+} __attribute__ ((__packed__));
+
+#define _TCB_T_
+typedef struct _tcb_t tcb_t;
+
+/* Receive Frame Descriptor (RFD) - will be using the simple model*/
+struct _rfd_t {
+	/* 8255x */
+	cb_header_t rfd_header;
+	u32 rfd_rbd_ptr;	/* Receive Buffer Descriptor Addr */
+	u16 rfd_act_cnt;	/* Number Of Bytes Received */
+	u16 rfd_sz;	/* Number Of Bytes In RFD */
+	/* D102 aka Gamla */
+	u16 vlanid;
+	u8 rcvparserstatus;
+	u8 reserved;
+	u16 securitystatus;
+	u8 checksumstatus;
+	u8 zerocopystatus;
+	u8 pad[8];	/* data should be 16 byte aligned */
+	u8 data[RFD_DATA_SIZE];
+
+} __attribute__ ((__packed__));
+
+#define _RFD_T_
+typedef struct _rfd_t rfd_t;
+
+/* Receive Buffer Descriptor (RBD)*/
+typedef struct _rbd_t {
+	u16 rbd_act_cnt;	/* Number Of Bytes Received */
+	u16 rbd_filler;
+	u32 rbd_lnk_addr;	/* Link To Next RBD */
+	u32 rbd_rcb_addr;	/* Receive Buffer Address */
+	u16 rbd_sz;	/* Receive Buffer Size */
+	u16 rbd_filler1;
+} rbd_t __attribute__ ((__packed__));
+
+/*
+ * This structure is used to maintain a FIFO access to a resource that is 
+ * maintained as a circular queue. The resource to be maintained is pointed
+ * to by the "data" field in the structure below. In this driver the TCBs', 
+ * TBDs' & RFDs' are maintained  as a circular queue & are managed thru this
+ * structure.
+ */
+typedef struct _buf_pool_t {
+	unsigned int head;	/* index to first used resource */
+	unsigned int tail;	/* index to last used resource */
+	void *data;		/* points to resource pool */
+} buf_pool_t;
+
+/*Rx skb holding structure*/
+struct rx_list_elem {
+	struct list_head list_elem;
+	dma_addr_t dma_addr;
+	struct sk_buff *skb;
+};
+
+enum next_cu_cmd_e { RESUME_NO_WAIT = 0, RESUME_WAIT, START_WAIT };
+enum zlock_state_e { ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING };
+enum tx_queue_stop_type { LONG_STOP = 0, SHORT_STOP };
+
+/* 64 bit aligned size */
+#define E100_SIZE_64A(X) ((sizeof(X) + 7) & ~0x7)
+
+typedef struct _bd_dma_able_t {
+	char selftest[E100_SIZE_64A(self_test_t)];
+	char stats_counters[E100_SIZE_64A(max_counters_t)];
+} bd_dma_able_t;
+
+/* bit masks for bool parameters */
+#define PRM_XSUMRX       0x00000001
+#define PRM_UCODE        0x00000002
+#define PRM_FC           0x00000004
+#define PRM_IFS          0x00000008
+#define PRM_BUNDLE_SMALL 0x00000010
+
+struct cfg_params {
+	int e100_speed_duplex;
+	int RxDescriptors;
+	int TxDescriptors;
+	int IntDelay;
+	int BundleMax;
+	int ber;
+	u32 b_params;
+};
+struct ethtool_lpbk_data{
+        dma_addr_t dma_handle;
+        tcb_t *tcb;
+        rfd_t *rfd;
+
+};
+
+struct e100_private {
+	u32 flags;		/* board management flags */
+	u32 tx_per_underrun;	/* number of good tx frames per underrun */
+	unsigned int tx_count;	/* count of tx frames, so we can request an interrupt */
+	u8 tx_thld;		/* stores transmit threshold */
+	u16 eeprom_size;
+	u32 pwa_no;		/* PWA: xxxxxx-0xx */
+	u8 perm_node_address[ETH_ALEN];
+	struct list_head active_rx_list;	/* list of rx buffers */
+	struct list_head rx_struct_pool;	/* pool of rx buffer struct headers */
+	u16 rfd_size;			/* size of the adapter's RFD struct */
+	int skb_req;			/* number of skbs neede by the adapter */
+	u8 intr_mask;			/* mask for interrupt status */
+
+	void *dma_able;			/* dma allocated structs */
+	dma_addr_t dma_able_phys;
+	self_test_t *selftest;		/* pointer to self test area */
+	dma_addr_t selftest_phys;	/* phys addr of selftest */
+	max_counters_t *stats_counters;	/* pointer to stats table */
+	dma_addr_t stat_cnt_phys;	/* phys addr of stat counter area */
+
+	stat_mode_t stat_mode;	/* statistics mode: extended, TCO, basic */
+	scb_t *scb;		/* memory mapped ptr to 82557 scb */
+
+	tcb_t *last_tcb;	/* pointer to last tcb sent */
+	buf_pool_t tcb_pool;	/* adapter's TCB array */
+	dma_addr_t tcb_phys;	/* phys addr of start of TCBs */
+
+	u16 cur_line_speed;
+	u16 cur_dplx_mode;
+
+	struct net_device *device;
+	struct pci_dev *pdev;
+	struct driver_stats drv_stats;
+
+	u8 rev_id;		/* adapter PCI revision ID */
+	unsigned long device_type;	/* device type from e100_vendor.h */
+
+	unsigned int phy_addr;	/* address of PHY component */
+	unsigned int PhyId;	/* ID of PHY component */
+	unsigned int PhyState;	/* state for the fix squelch algorithm */
+	unsigned int PhyDelay;	/* delay for the fix squelch algorithm */
+
+	/* Lock defintions for the driver */
+	spinlock_t bd_lock;		/* board lock */
+	spinlock_t bd_non_tx_lock;	/* Non transmit command lock  */
+	spinlock_t config_lock;		/* config block lock */
+	spinlock_t mdi_access_lock;	/* mdi lock */
+
+	struct timer_list watchdog_timer;	/* watchdog timer id */
+
+	/* non-tx commands parameters */
+	struct timer_list nontx_timer_id;	/* non-tx timer id */
+	struct list_head non_tx_cmd_list;
+	non_tx_cmd_state_t non_tx_command_state;
+	nxmit_cb_entry_t *same_cmd_entry[CB_MAX_NONTX_CMD];
+
+	enum next_cu_cmd_e next_cu_cmd;
+
+	/* Zero Locking Algorithm data members */
+	enum zlock_state_e zlock_state;
+	u8 zlock_read_data[16];	/* number of times each value 0-15 was read */
+	u16 zlock_read_cnt;	/* counts number of reads */
+	ulong zlock_sleep_cnt;	/* keeps track of "sleep" time */
+
+	u8 config[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT];
+
+	/* IFS params */
+	u8 ifs_state;
+	u8 ifs_value;
+
+	struct cfg_params params;	/* adapter's command line parameters */
+
+	struct proc_dir_entry *proc_parent;
+
+	rwlock_t isolate_lock;
+	int driver_isolated;
+	char *id_string;
+	char *cable_status;
+	char *mdix_status;
+
+	/* Variables for HWI */
+	int saved_open_circut;
+	int saved_short_circut;
+	int saved_distance;
+	int saved_i;
+	int saved_same;
+	unsigned char hwi_started;
+	struct timer_list hwi_timer;	/* hwi timer id */
+
+	u32 speed_duplex_caps;	/* adapter's speed/duplex capabilities */
+
+	/* WOL params for ethtool */
+	u32 wolsupported;
+	u32 wolopts;
+	u16 ip_lbytes;
+	struct ethtool_lpbk_data loopback;
+	struct timer_list blink_timer;	/* led blink timer id */
+
+#ifdef CONFIG_PM
+	u32 pci_state[16];
+#endif
+	char ifname[IFNAMSIZ];
+};
+
+#define E100_AUTONEG        0
+#define E100_SPEED_10_HALF  1
+#define E100_SPEED_10_FULL  2
+#define E100_SPEED_100_HALF 3
+#define E100_SPEED_100_FULL 4
+
+/********* function prototypes *************/
+extern void e100_isolate_driver(struct e100_private *bdp);
+extern void e100_sw_reset(struct e100_private *bdp, u32 reset_cmd);
+extern void e100_start_cu(struct e100_private *bdp, tcb_t *tcb);
+extern void e100_free_non_tx_cmd(struct e100_private *bdp,
+				 nxmit_cb_entry_t *non_tx_cmd);
+extern nxmit_cb_entry_t *e100_alloc_non_tx_cmd(struct e100_private *bdp);
+extern unsigned char e100_exec_non_cu_cmd(struct e100_private *bdp,
+					  nxmit_cb_entry_t *cmd);
+extern unsigned char e100_selftest(struct e100_private *bdp, u32 *st_timeout,
+				   u32 *st_result);
+extern unsigned char e100_get_link_state(struct e100_private *bdp);
+extern unsigned char e100_wait_scb(struct e100_private *bdp);
+
+extern void e100_deisolate_driver(struct e100_private *bdp,
+				  u8 recover, u8 full_reset);
+extern unsigned char e100_hw_reset_recover(struct e100_private *bdp,
+					   u32 reset_cmd);
+
+#define ROM_TEST_FAIL		0x01
+#define REGISTER_TEST_FAIL	0x02
+#define SELF_TEST_FAIL		0x04
+#define TEST_TIMEOUT		0x08
+
+enum test_offsets {
+	E100_EEPROM_TEST_FAIL = 0,
+	E100_CHIP_TIMEOUT,
+	E100_ROM_TEST_FAIL,
+	E100_REG_TEST_FAIL,
+	E100_MAC_TEST_FAIL,
+	E100_LPBK_MAC_FAIL,
+	E100_LPBK_PHY_FAIL,
+	E100_MAX_TEST_RES
+};
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e100/e100_config.c linux-2.4.20/drivers/net/e100/e100_config.c
--- linux-2.4.19/drivers/net/e100/e100_config.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e100/e100_config.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,614 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+*******************************************************************************/
+
+/**********************************************************************
+*                                                                     *
+* INTEL CORPORATION                                                   *
+*                                                                     *
+* This software is supplied under the terms of the license included   *
+* above.  All use of this driver must be in accordance with the terms *
+* of that license.                                                    *
+*                                                                     *
+* Module Name:  e100_config.c                                         *
+*                                                                     *
+* Abstract:     Functions for configuring the network adapter.        *
+*                                                                     *
+* Environment:  This file is intended to be specific to the Linux     *
+*               operating system.                                     *
+*                                                                     *
+**********************************************************************/
+#include "e100_config.h"
+
+static void e100_config_long_rx(struct e100_private *bdp, unsigned char enable);
+
+static const u8 def_config[] = {
+	CB_CFIG_BYTE_COUNT,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x32, 0x07, 0x01,
+	0x00, 0x2e, 0x00, 0x60, 0x00, 0xf2, 0xc8, 0x00,
+	0x40, 0xf2, 0x80, 0x3f, 0x05
+};
+
+/**
+ * e100_config_init_82557 - config the 82557 adapter
+ * @bdp: atapter's private data struct
+ *
+ * This routine will initialize the 82557 configure block.
+ * All other init functions will only set values that are
+ * different from the 82557 default.
+ */
+static void __devinit
+e100_config_init_82557(struct e100_private *bdp)
+{
+	/* initialize config block */
+	memcpy(bdp->config, def_config, sizeof (def_config));
+	bdp->config[0] = CB_CFIG_BYTE_COUNT;	/* just in case */
+
+	e100_config_ifs(bdp);
+
+	/*
+	 * Enable extended statistical counters (82558 and up) and TCO counters
+	 * (82559 and up) and set the statistical counters' mode in bdp 
+	 *  
+	 *  stat. mode      |    TCO stat. bit (2)  |  Extended stat. bit (5)
+	 * ------------------------------------------------------------------
+	 *  Basic (557)     |       0               |         1
+	 * ------------------------------------------------------------------
+	 *  Extended (558)  |       0               |         0
+	 * ------------------------------------------------------------------
+	 *  TCO (559)       |       1               |         1
+	 * ------------------------------------------------------------------
+	 *  Reserved        |       1               |         0
+	 * ------------------------------------------------------------------
+	 */
+	bdp->config[6] &= ~CB_CFIG_TCO_STAT;
+	bdp->config[6] |= CB_CFIG_EXT_STAT_DIS;
+	bdp->stat_mode = E100_BASIC_STATS;
+
+	/* Setup for MII or 503 operation.  The CRS+CDT bit should only be set */
+	/* when operating in 503 mode. */
+	if (bdp->phy_addr == 32) {
+		bdp->config[8] &= ~CB_CFIG_503_MII;
+		bdp->config[15] |= CB_CFIG_CRS_OR_CDT;
+	} else {
+		bdp->config[8] |= CB_CFIG_503_MII;
+		bdp->config[15] &= ~CB_CFIG_CRS_OR_CDT;
+	}
+
+	e100_config_fc(bdp);
+	e100_config_force_dplx(bdp);
+	e100_config_promisc(bdp, false);
+	e100_config_mulcast_enbl(bdp, false);
+}
+
+static void __devinit
+e100_config_init_82558(struct e100_private *bdp)
+{
+	/* MWI enable. This should be turned on only if the adapter is a 82558/9
+	 * and if the PCI command reg. has enabled the MWI bit. */
+	bdp->config[3] |= CB_CFIG_MWI_EN;
+
+	bdp->config[6] &= ~CB_CFIG_EXT_TCB_DIS;
+
+	if (bdp->rev_id >= D101MA_REV_ID) {
+		/* this is 82559 and up - enable TCO counters */
+		bdp->config[6] |= CB_CFIG_TCO_STAT;
+		bdp->config[6] |= CB_CFIG_EXT_STAT_DIS;
+		bdp->stat_mode = E100_TCO_STATS;
+
+		if ((bdp->rev_id < D102_REV_ID) &&
+		    (bdp->params.b_params & PRM_XSUMRX) &&
+		    (bdp->pdev->device != 0x1209)) {
+
+			bdp->flags |= DF_CSUM_OFFLOAD;
+			bdp->config[9] |= 1;
+		}
+	} else {
+		/* this is 82558 */
+		bdp->config[6] &= ~CB_CFIG_TCO_STAT;
+		bdp->config[6] &= ~CB_CFIG_EXT_STAT_DIS;
+		bdp->stat_mode = E100_EXTENDED_STATS;
+	}
+
+	e100_config_long_rx(bdp, true);
+}
+
+static void __devinit
+e100_config_init_82550(struct e100_private *bdp)
+{
+	/* The D102 chip allows for 32 config bytes.  This value is
+	 * supposed to be in Byte 0.  Just add the extra bytes to
+	 * what was already setup in the block. */
+	bdp->config[0] += CB_CFIG_D102_BYTE_COUNT;
+
+	/* now we need to enable the extended RFD.  When this is
+	 * enabled, the immediated receive data buffer starts at offset
+	 * 32 from the RFD base address, instead of at offset 16. */
+	bdp->config[7] |= CB_CFIG_EXTENDED_RFD;
+
+	/* put the chip into D102 receive mode.  This is neccessary
+	 * for any parsing and offloading features. */
+	bdp->config[22] = CB_CFIG_RECEIVE_GAMLA_MODE;
+
+	/* set the flag if checksum offloading was enabled */
+	if (bdp->params.b_params & PRM_XSUMRX) {
+		bdp->flags |= DF_CSUM_OFFLOAD;
+	}
+}
+
+/* Initialize the adapter's configure block */
+void __devinit
+e100_config_init(struct e100_private *bdp)
+{
+	e100_config_init_82557(bdp);
+
+	if (bdp->flags & IS_BACHELOR)
+		e100_config_init_82558(bdp);
+
+	if (bdp->rev_id >= D102_REV_ID)
+		e100_config_init_82550(bdp);
+}
+
+/**
+ * e100_force_config - force a configure command
+ * @bdp: atapter's private data struct
+ *
+ * This routine will force a configure command to the adapter.
+ * The command will be executed in polled mode as interrupts
+ * are _disabled_ at this time.
+ *
+ * Returns:
+ *      true: if the configure command was successfully issued and completed
+ *      false: otherwise
+ */
+unsigned char
+e100_force_config(struct e100_private *bdp)
+{
+	spin_lock_bh(&(bdp->config_lock));
+
+	bdp->config[0] = CB_CFIG_BYTE_COUNT;
+	if (bdp->rev_id >= D102_REV_ID) {
+		/* The D102 chip allows for 32 config bytes.  This value is
+		   supposed to be in Byte 0.  Just add the extra bytes to
+		   what was already setup in the block. */
+		bdp->config[0] += CB_CFIG_D102_BYTE_COUNT;
+	}
+
+	spin_unlock_bh(&(bdp->config_lock));
+
+	// although we call config outside the lock, there is no
+	// race condition because config byte count has maximum value
+	return e100_config(bdp);
+}
+
+/**
+ * e100_config - issue a configure command
+ * @bdp: atapter's private data struct
+ *
+ * This routine will issue a configure command to the 82557.
+ * This command will be executed in polled mode as interrupts
+ * are _disabled_ at this time.
+ *
+ * Returns:
+ *      true: if the configure command was successfully issued and completed
+ *      false: otherwise
+ */
+unsigned char
+e100_config(struct e100_private *bdp)
+{
+	cb_header_t *pntcb_hdr;
+	unsigned char res = true;
+	nxmit_cb_entry_t *cmd;
+
+	if (bdp->config[0] == 0) {
+		goto exit;
+	}
+
+	if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) {
+		res = false;
+		goto exit;
+	}
+
+	pntcb_hdr = (cb_header_t *) cmd->non_tx_cmd;
+	pntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_CONFIGURE);
+
+	spin_lock_bh(&bdp->config_lock);
+
+	if (bdp->config[0] < CB_CFIG_MIN_PARAMS) {
+		bdp->config[0] = CB_CFIG_MIN_PARAMS;
+	}
+
+	/* Copy the device's config block to the device's memory */
+	memcpy(cmd->non_tx_cmd->ntcb.config.cfg_byte, bdp->config,
+	       bdp->config[0]);
+	/* reset number of bytes to config next time */
+	bdp->config[0] = 0;
+
+	spin_unlock_bh(&bdp->config_lock);
+
+	res = e100_exec_non_cu_cmd(bdp, cmd);
+
+exit:
+	if (netif_running(bdp->device))
+		netif_wake_queue(bdp->device);
+	return res;
+}
+
+/**
+ * e100_config_fc - config flow-control state
+ * @bdp: adapter's private data struct
+ *
+ * This routine will enable or disable flow control support in the adapter's
+ * config block. Flow control will be enable only if requested using the command
+ * line option, and if the link is flow-contorl capable (both us and the link
+ * partner). But, if link partner is capable of autoneg, but not capable of
+ * flow control, received PAUSE	frames are still honored.
+ */
+void
+e100_config_fc(struct e100_private *bdp)
+{
+	unsigned char enable = false;
+	/* 82557 doesn't support fc. Don't touch this option */
+	if (!(bdp->flags & IS_BACHELOR))
+		return;
+
+	/* Enable fc if requested and if the link supports it */
+	if ((bdp->params.b_params & PRM_FC) && (bdp->flags & 
+		(DF_LINK_FC_CAP | DF_LINK_FC_TX_ONLY))) {
+		enable = true;
+	}
+
+	spin_lock_bh(&(bdp->config_lock));
+
+	if (enable) {
+		if (bdp->flags & DF_LINK_FC_TX_ONLY) {
+			/* If link partner is capable of autoneg, but  */
+			/* not capable of flow control, Received PAUSE */
+			/* frames are still honored, i.e.,             */
+			/* transmitted frames would be paused by       */
+			/* incoming PAUSE frames                       */
+			bdp->config[16] = DFLT_NO_FC_DELAY_LSB;
+			bdp->config[17] = DFLT_NO_FC_DELAY_MSB;
+			bdp->config[19] &= ~(CB_CFIG_FC_RESTOP | CB_CFIG_FC_RESTART);
+			bdp->config[19] |= CB_CFIG_FC_REJECT;
+			bdp->config[19] &= ~CB_CFIG_TX_FC_DIS;
+		} else {
+			bdp->config[16] = DFLT_FC_DELAY_LSB;
+			bdp->config[17] = DFLT_FC_DELAY_MSB;
+			bdp->config[19] |= CB_CFIG_FC_OPTS;
+			bdp->config[19] &= ~CB_CFIG_TX_FC_DIS;
+		}
+	} else {
+		bdp->config[16] = DFLT_NO_FC_DELAY_LSB;
+		bdp->config[17] = DFLT_NO_FC_DELAY_MSB;
+		bdp->config[19] &= ~CB_CFIG_FC_OPTS;
+		bdp->config[19] |= CB_CFIG_TX_FC_DIS;
+	}
+	E100_CONFIG(bdp, 19);
+	spin_unlock_bh(&(bdp->config_lock));
+
+	return;
+}
+
+/**
+ * e100_config_promisc - configure promiscuous mode
+ * @bdp: atapter's private data struct
+ * @enable: should we enable this option or not
+ *
+ * This routine will enable or disable promiscuous mode
+ * in the adapter's config block.
+ */
+void
+e100_config_promisc(struct e100_private *bdp, unsigned char enable)
+{
+	spin_lock_bh(&(bdp->config_lock));
+
+	/* if in promiscuous mode, save bad frames */
+	if (enable) {
+
+		if (!(bdp->config[6] & CB_CFIG_SAVE_BAD_FRAMES)) {
+			bdp->config[6] |= CB_CFIG_SAVE_BAD_FRAMES;
+			E100_CONFIG(bdp, 6);
+		}
+
+		if (bdp->config[7] & (u8) BIT_0) {
+			bdp->config[7] &= (u8) (~BIT_0);
+			E100_CONFIG(bdp, 7);
+		}
+
+		if (!(bdp->config[15] & CB_CFIG_PROMISCUOUS)) {
+			bdp->config[15] |= CB_CFIG_PROMISCUOUS;
+			E100_CONFIG(bdp, 15);
+		}
+
+	} else {		/* not in promiscuous mode */
+
+		if (bdp->config[6] & CB_CFIG_SAVE_BAD_FRAMES) {
+			bdp->config[6] &= ~CB_CFIG_SAVE_BAD_FRAMES;
+			E100_CONFIG(bdp, 6);
+		}
+
+		if (!(bdp->config[7] & (u8) BIT_0)) {
+			bdp->config[7] |= (u8) (BIT_0);
+			E100_CONFIG(bdp, 7);
+		}
+
+		if (bdp->config[15] & CB_CFIG_PROMISCUOUS) {
+			bdp->config[15] &= ~CB_CFIG_PROMISCUOUS;
+			E100_CONFIG(bdp, 15);
+		}
+	}
+
+	spin_unlock_bh(&(bdp->config_lock));
+}
+
+/**
+ * e100_config_mulcast_enbl - configure allmulti mode
+ * @bdp: atapter's private data struct
+ * @enable: should we enable this option or not
+ *
+ * This routine will enable or disable reception of all multicast packets
+ * in the adapter's config block.
+ */
+void
+e100_config_mulcast_enbl(struct e100_private *bdp, unsigned char enable)
+{
+	spin_lock_bh(&(bdp->config_lock));
+
+	/* this flag is used to enable receiving all multicast packet */
+	if (enable) {
+		if (!(bdp->config[21] & CB_CFIG_MULTICAST_ALL)) {
+			bdp->config[21] |= CB_CFIG_MULTICAST_ALL;
+			E100_CONFIG(bdp, 21);
+		}
+
+	} else {
+		if (bdp->config[21] & CB_CFIG_MULTICAST_ALL) {
+			bdp->config[21] &= ~CB_CFIG_MULTICAST_ALL;
+			E100_CONFIG(bdp, 21);
+		}
+	}
+
+	spin_unlock_bh(&(bdp->config_lock));
+}
+
+/**
+ * e100_config_ifs - configure the IFS parameter
+ * @bdp: atapter's private data struct
+ *
+ * This routine will configure the adaptive IFS value
+ * in the adapter's config block. IFS values are only
+ * relevant in half duplex, so set to 0 in full duplex.
+ */
+void
+e100_config_ifs(struct e100_private *bdp)
+{
+	u8 value = 0;
+
+	spin_lock_bh(&(bdp->config_lock));
+
+	/* IFS value is only needed to be specified at half-duplex mode */
+	if (bdp->cur_dplx_mode == HALF_DUPLEX) {
+		value = (u8) bdp->ifs_value;
+	}
+
+	if (bdp->config[2] != value) {
+		bdp->config[2] = value;
+		E100_CONFIG(bdp, 2);
+	}
+
+	spin_unlock_bh(&(bdp->config_lock));
+}
+
+/**
+ * e100_config_force_dplx - configure the forced full duplex mode
+ * @bdp: atapter's private data struct
+ *
+ * This routine will enable or disable force full duplex
+ * in the adapter's config block. If the PHY is 503, and
+ * the duplex is full, consider the adapter forced.
+ */
+void
+e100_config_force_dplx(struct e100_private *bdp)
+{
+	spin_lock_bh(&(bdp->config_lock));
+
+	/* We must force full duplex on if we are using PHY 0, and we are */
+	/* supposed to run in FDX mode. We do this because the e100 has only */
+	/* one FDX# input pin, and that pin will be connected to PHY 1. */
+	/* Changed the 'if' condition below to fix performance problem * at 10
+	 * full. The Phy was getting forced to full duplex while the MAC * was
+	 * not, because the cur_dplx_mode was not being set to 2 by SetupPhy. *
+	 * This is how the condition was, initially. * This has been changed so
+	 * that the MAC gets forced to full duplex * simply if the user has
+	 * forced full duplex. * * if (( bdp->phy_addr == 0 ) && (
+	 * bdp->cur_dplx_mode == 2 )) */
+	/* The rest of the fix is in the PhyDetect code. */
+	if ((bdp->params.e100_speed_duplex == E100_SPEED_10_FULL) ||
+	    (bdp->params.e100_speed_duplex == E100_SPEED_100_FULL) ||
+	    ((bdp->phy_addr == 32) && (bdp->cur_dplx_mode == FULL_DUPLEX))) {
+		if (!(bdp->config[19] & (u8) CB_CFIG_FORCE_FDX)) {
+			bdp->config[19] |= (u8) CB_CFIG_FORCE_FDX;
+			E100_CONFIG(bdp, 19);
+		}
+
+	} else {
+		if (bdp->config[19] & (u8) CB_CFIG_FORCE_FDX) {
+			bdp->config[19] &= (u8) (~CB_CFIG_FORCE_FDX);
+			E100_CONFIG(bdp, 19);
+		}
+	}
+
+	spin_unlock_bh(&(bdp->config_lock));
+}
+
+/**
+ * e100_config_long_rx
+ * @bdp: atapter's private data struct
+ * @enable: should we enable this option or not
+ *
+ * This routine will enable or disable reception of larger packets.
+ * This is needed by VLAN implementations.
+ */
+static void
+e100_config_long_rx(struct e100_private *bdp, unsigned char enable)
+{
+	if (enable) {
+		if (!(bdp->config[18] & CB_CFIG_LONG_RX_OK)) {
+			bdp->config[18] |= CB_CFIG_LONG_RX_OK;
+			E100_CONFIG(bdp, 18);
+		}
+
+	} else {
+		if ((bdp->config[18] & CB_CFIG_LONG_RX_OK)) {
+			bdp->config[18] &= ~CB_CFIG_LONG_RX_OK;
+			E100_CONFIG(bdp, 18);
+		}
+	}
+}
+
+/**
+ * e100_config_wol
+ * @bdp: atapter's private data struct
+ *
+ * This sets configuration options for Wake On LAN functionality (WOL) in the
+ * config record. WOL options are retrieved from wolinfo_wolopts in @bdp
+ */
+void
+e100_config_wol(struct e100_private *bdp)
+{
+	spin_lock_bh(&(bdp->config_lock));
+
+	if (bdp->wolopts & WAKE_PHY) {
+		bdp->config[9] |= CB_LINK_STATUS_WOL;
+		E100_CONFIG(bdp, 9);
+	}
+
+	if (!(bdp->wolopts & WAKE_MAGIC)) {
+		bdp->config[19] |= CB_DISABLE_MAGPAK_WAKE;
+		E100_CONFIG(bdp, 19);
+	}
+
+	spin_unlock_bh(&(bdp->config_lock));
+}
+
+/**
+ * e100_config_loopback_mode
+ * @bdp: atapter's private data struct
+ * @mode: loopback mode(phy/mac/none)
+ *
+ */
+unsigned char
+e100_config_loopback_mode(struct e100_private *bdp, u8 mode)
+{
+	unsigned char bc_changed = false;
+	u8 config_byte;
+
+	spin_lock_bh(&(bdp->config_lock));
+
+	switch (mode) {
+	case NO_LOOPBACK:
+		config_byte = CB_CFIG_LOOPBACK_NORMAL;
+		break;
+	case MAC_LOOPBACK:
+		config_byte = CB_CFIG_LOOPBACK_INTERNAL;
+		break;
+	case PHY_LOOPBACK:
+		config_byte = CB_CFIG_LOOPBACK_EXTERNAL;
+		break;
+	default:
+		printk(KERN_NOTICE "e100: e100_config_loopback_mode: "
+		       "Invalid argument 'mode': %d\n", mode);
+		goto exit;
+	}
+
+	if ((bdp->config[10] & CB_CFIG_LOOPBACK_MODE) != config_byte) {
+
+		bdp->config[10] &= (~CB_CFIG_LOOPBACK_MODE);
+		bdp->config[10] |= config_byte;
+		E100_CONFIG(bdp, 10);
+		bc_changed = true;
+	}
+
+exit:
+	spin_unlock_bh(&(bdp->config_lock));
+	return bc_changed;
+}
+unsigned char
+e100_config_tcb_ext_enable(struct e100_private *bdp, unsigned char enable)
+{
+        unsigned char bc_changed = false;
+ 
+        spin_lock_bh(&(bdp->config_lock));
+ 
+        if (enable) {
+                if (bdp->config[6] & CB_CFIG_EXT_TCB_DIS) {
+ 
+                        bdp->config[6] &= (~CB_CFIG_EXT_TCB_DIS);
+                        E100_CONFIG(bdp, 6);
+                        bc_changed = true;
+                }
+ 
+        } else {
+                if (!(bdp->config[6] & CB_CFIG_EXT_TCB_DIS)) {
+ 
+                        bdp->config[6] |= CB_CFIG_EXT_TCB_DIS;
+                        E100_CONFIG(bdp, 6);
+                        bc_changed = true;
+                }
+        }
+        spin_unlock_bh(&(bdp->config_lock));
+ 
+        return bc_changed;
+}
+unsigned char
+e100_config_dynamic_tbd(struct e100_private *bdp, unsigned char enable)
+{
+        unsigned char bc_changed = false;
+ 
+        spin_lock_bh(&(bdp->config_lock));
+ 
+        if (enable) {
+                if (!(bdp->config[7] & CB_CFIG_DYNTBD_EN)) {
+ 
+                        bdp->config[7] |= CB_CFIG_DYNTBD_EN;
+                        E100_CONFIG(bdp, 7);
+                        bc_changed = true;
+                }
+ 
+        } else {
+                if (bdp->config[7] & CB_CFIG_DYNTBD_EN) {
+ 
+                        bdp->config[7] &= (~CB_CFIG_DYNTBD_EN);
+                        E100_CONFIG(bdp, 7);
+                        bc_changed = true;
+                }
+        }
+        spin_unlock_bh(&(bdp->config_lock));
+ 
+        return bc_changed;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e100/e100_config.h linux-2.4.20/drivers/net/e100/e100_config.h
--- linux-2.4.19/drivers/net/e100/e100_config.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e100/e100_config.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,167 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+*******************************************************************************/
+
+#ifndef _E100_CONFIG_INC_
+#define _E100_CONFIG_INC_
+
+#include "e100.h"
+
+#define E100_CONFIG(bdp, X) ((bdp)->config[0] = max_t(u8, (bdp)->config[0], (X)+1))
+
+#define CB_CFIG_MIN_PARAMS         8
+
+/* byte 0 bit definitions*/
+#define CB_CFIG_BYTE_COUNT_MASK     BIT_0_5	/* Byte count occupies bit 5-0 */
+
+/* byte 1 bit definitions*/
+#define CB_CFIG_RXFIFO_LIMIT_MASK   BIT_0_4	/* RxFifo limit mask */
+#define CB_CFIG_TXFIFO_LIMIT_MASK   BIT_4_7	/* TxFifo limit mask */
+
+/* byte 2 bit definitions -- ADAPTIVE_IFS*/
+
+/* word 3 bit definitions -- RESERVED*/
+/* Changed for 82558 enhancements */
+/* byte 3 bit definitions */
+#define CB_CFIG_MWI_EN      BIT_0	/* Enable MWI on PCI bus */
+#define CB_CFIG_TYPE_EN     BIT_1	/* Type Enable */
+#define CB_CFIG_READAL_EN   BIT_2	/* Enable Read Align */
+#define CB_CFIG_TERMCL_EN   BIT_3	/* Cache line write  */
+
+/* byte 4 bit definitions*/
+#define CB_CFIG_RX_MIN_DMA_MASK     BIT_0_6	/* Rx minimum DMA count mask */
+
+/* byte 5 bit definitions*/
+#define CB_CFIG_TX_MIN_DMA_MASK BIT_0_6	/* Tx minimum DMA count mask */
+#define CB_CFIG_DMBC_EN         BIT_7	/* Enable Tx/Rx min. DMA counts */
+
+/* Changed for 82558 enhancements */
+/* byte 6 bit definitions*/
+#define CB_CFIG_LATE_SCB           BIT_0	/* Update SCB After New Tx Start */
+#define CB_CFIG_DIRECT_DMA_DIS     BIT_1	/* Direct DMA mode */
+#define CB_CFIG_TNO_INT            BIT_2	/* Tx Not OK Interrupt */
+#define CB_CFIG_TCO_STAT           BIT_2	/* TCO statistics in 559 and above */
+#define CB_CFIG_CI_INT             BIT_3	/* Command Complete Interrupt */
+#define CB_CFIG_EXT_TCB_DIS        BIT_4	/* Extended TCB */
+#define CB_CFIG_EXT_STAT_DIS       BIT_5	/* Extended Stats */
+#define CB_CFIG_SAVE_BAD_FRAMES    BIT_7	/* Save Bad Frames Enabled */
+
+/* byte 7 bit definitions*/
+#define CB_CFIG_DISC_SHORT_FRAMES   BIT_0	/* Discard Short Frames */
+#define CB_CFIG_DYNTBD_EN           BIT_7	/* Enable dynamic TBD */
+/* Enable extended RFD's on D102 */
+#define CB_CFIG_EXTENDED_RFD        BIT_5
+
+/* byte 8 bit definitions*/
+#define CB_CFIG_503_MII             BIT_0	/* 503 vs. MII mode */
+
+/* byte 9 bit definitions -- pre-defined all zeros*/
+#define CB_LINK_STATUS_WOL	BIT_5
+
+/* byte 10 bit definitions*/
+#define CB_CFIG_NO_SRCADR       BIT_3	/* No Source Address Insertion */
+#define CB_CFIG_PREAMBLE_LEN    BIT_4_5	/* Preamble Length */
+#define CB_CFIG_LOOPBACK_MODE   BIT_6_7	/* Loopback Mode */
+#define CB_CFIG_LOOPBACK_NORMAL 0
+#define CB_CFIG_LOOPBACK_INTERNAL BIT_6
+#define CB_CFIG_LOOPBACK_EXTERNAL BIT_6_7
+
+/* byte 11 bit definitions*/
+#define CB_CFIG_LINEAR_PRIORITY     BIT_0_2	/* Linear Priority */
+
+/* byte 12 bit definitions*/
+#define CB_CFIG_LINEAR_PRI_MODE     BIT_0	/* Linear Priority mode */
+#define CB_CFIG_IFS_MASK            BIT_4_7	/* Interframe Spacing mask */
+
+/* byte 13 bit definitions -- pre-defined all zeros*/
+
+/* byte 14 bit definitions -- pre-defined 0xf2*/
+
+/* byte 15 bit definitions*/
+#define CB_CFIG_PROMISCUOUS         BIT_0	/* Promiscuous Mode Enable */
+#define CB_CFIG_BROADCAST_DIS       BIT_1	/* Broadcast Mode Disable */
+#define CB_CFIG_CRS_OR_CDT          BIT_7	/* CRS Or CDT */
+
+/* byte 16 bit definitions -- pre-defined all zeros*/
+#define DFLT_FC_DELAY_LSB  0x1f	/* Delay for outgoing Pause frames */
+#define DFLT_NO_FC_DELAY_LSB  0x00	/* no flow control default value */
+
+/* byte 17 bit definitions -- pre-defined 0x40*/
+#define DFLT_FC_DELAY_MSB  0x01	/* Delay for outgoing Pause frames */
+#define DFLT_NO_FC_DELAY_MSB  0x40	/* no flow control default value */
+
+/* byte 18 bit definitions*/
+#define CB_CFIG_STRIPPING           BIT_0	/* Padding Disabled */
+#define CB_CFIG_PADDING             BIT_1	/* Padding Disabled */
+#define CB_CFIG_CRC_IN_MEM          BIT_2	/* Transfer CRC To Memory */
+
+/* byte 19 bit definitions*/
+#define CB_CFIG_TX_ADDR_WAKE        BIT_0	/* Address Wakeup */
+#define CB_DISABLE_MAGPAK_WAKE      BIT_1	/* Magic Packet Wakeup disable */
+/* Changed TX_FC_EN to TX_FC_DIS because 0 enables, 1 disables. Jul 8, 1999 */
+#define CB_CFIG_TX_FC_DIS           BIT_2	/* Tx Flow Control Disable */
+#define CB_CFIG_FC_RESTOP           BIT_3	/* Rx Flow Control Restop */
+#define CB_CFIG_FC_RESTART          BIT_4	/* Rx Flow Control Restart */
+#define CB_CFIG_FC_REJECT           BIT_5	/* Rx Flow Control Restart */
+#define CB_CFIG_FC_OPTS (CB_CFIG_FC_RESTOP | CB_CFIG_FC_RESTART | CB_CFIG_FC_REJECT)
+
+/* end 82558/9 specifics */
+
+#define CB_CFIG_FORCE_FDX           BIT_6	/* Force Full Duplex */
+#define CB_CFIG_FDX_ENABLE          BIT_7	/* Full Duplex Enabled */
+
+/* byte 20 bit definitions*/
+#define CB_CFIG_MULTI_IA            BIT_6	/* Multiple IA Addr */
+
+/* byte 21 bit definitions*/
+#define CB_CFIG_MULTICAST_ALL       BIT_3	/* Multicast All */
+
+/* byte 22 bit defines */
+#define CB_CFIG_RECEIVE_GAMLA_MODE  BIT_0	/* D102 receive mode */
+#define CB_CFIG_VLAN_DROP_ENABLE    BIT_1	/* vlan stripping */
+
+#define CB_CFIG_LONG_RX_OK	    BIT_3
+
+#define NO_LOOPBACK	0	
+#define MAC_LOOPBACK	0x01
+#define PHY_LOOPBACK	0x02
+
+/* function prototypes */
+extern void e100_config_init(struct e100_private *bdp);
+extern unsigned char e100_force_config(struct e100_private *bdp);
+extern unsigned char e100_config(struct e100_private *bdp);
+extern void e100_config_fc(struct e100_private *bdp);
+extern void e100_config_promisc(struct e100_private *bdp, unsigned char enable);
+extern void e100_config_brdcast_dsbl(struct e100_private *bdp);
+extern void e100_config_mulcast_enbl(struct e100_private *bdp,
+				     unsigned char enable);
+extern void e100_config_ifs(struct e100_private *bdp);
+extern void e100_config_force_dplx(struct e100_private *bdp);
+extern u8 e100_config_loopback_mode(struct e100_private *bdp, u8 mode);
+extern u8 e100_config_dynamic_tbd(struct e100_private *bdp, u8 enable);
+extern u8 e100_config_tcb_ext_enable(struct e100_private *bdp, u8 enable);
+
+#endif /* _E100_CONFIG_INC_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e100/e100_eeprom.c linux-2.4.20/drivers/net/e100/e100_eeprom.c
--- linux-2.4.19/drivers/net/e100/e100_eeprom.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e100/e100_eeprom.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,565 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+*******************************************************************************/
+
+/**********************************************************************
+*                                                                     *
+* INTEL CORPORATION                                                   *
+*                                                                     *
+* This software is supplied under the terms of the license included   *
+* above.  All use of this driver must be in accordance with the terms *
+* of that license.                                                    *
+*                                                                     *
+* Module Name:  e100_eeprom.c                                         *
+*                                                                     *
+* Abstract:     This module contains routines to read and write to a  *
+*               serial EEPROM                                         *
+*                                                                     *
+* Environment:  This file is intended to be specific to the Linux     *
+*               operating system.                                     *
+*                                                                     *
+**********************************************************************/
+#include "e100.h"
+
+#define CSR_EEPROM_CONTROL_FIELD(bdp) ((bdp)->scb->scb_eprm_cntrl)
+
+#define CSR_GENERAL_CONTROL2_FIELD(bdp) \
+	           ((bdp)->scb->scb_ext.d102_scb.scb_gen_ctrl2)
+
+#define EEPROM_STALL_TIME	4
+#define EEPROM_CHECKSUM		((u16) 0xBABA)
+#define EEPROM_MAX_WORD_SIZE	256
+
+void e100_eeprom_cleanup(struct e100_private *adapter);
+u16 e100_eeprom_calculate_chksum(struct e100_private *adapter);
+static void e100_eeprom_write_word(struct e100_private *adapter, u16 reg,
+				   u16 data);
+void e100_eeprom_write_block(struct e100_private *adapter, u16 start, u16 *data,
+			     u16 size);
+u16 e100_eeprom_size(struct e100_private *adapter);
+u16 e100_eeprom_read(struct e100_private *adapter, u16 reg);
+
+static void shift_out_bits(struct e100_private *adapter, u16 data, u16 count);
+static u16 shift_in_bits(struct e100_private *adapter);
+static void raise_clock(struct e100_private *adapter, u16 *x);
+static void lower_clock(struct e100_private *adapter, u16 *x);
+static u16 eeprom_wait_cmd_done(struct e100_private *adapter);
+static void eeprom_stand_by(struct e100_private *adapter);
+
+//----------------------------------------------------------------------------------------
+// Procedure:   eeprom_set_semaphore
+//
+// Description: This function set (write 1) Gamla EEPROM semaphore bit (bit 23 word 0x1C in the CSR).
+//
+// Arguments:
+//      Adapter                 - Adapter context
+//
+// Returns:  true if success
+//           else return false 
+//
+//----------------------------------------------------------------------------------------
+
+inline u8
+eeprom_set_semaphore(struct e100_private *adapter)
+{
+	u16 data = 0;
+	unsigned long expiration_time = jiffies + HZ / 100 + 1;
+
+	do {
+		// Get current value of General Control 2
+		data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter));
+
+		// Set bit 23 word 0x1C in the CSR.
+		data |= SCB_GCR2_EEPROM_ACCESS_SEMAPHORE;
+		writeb(data, &CSR_GENERAL_CONTROL2_FIELD(adapter));
+
+		// Check to see if this bit set or not.
+		data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter));
+
+		if (data & SCB_GCR2_EEPROM_ACCESS_SEMAPHORE) {
+			return true;
+		}
+
+		if (time_before(jiffies, expiration_time))
+			yield();
+		else
+			return false;
+
+	} while (true);
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   eeprom_reset_semaphore
+//
+// Description: This function reset (write 0) Gamla EEPROM semaphore bit 
+//              (bit 23 word 0x1C in the CSR).
+//
+// Arguments:  struct e100_private * adapter - Adapter context
+//----------------------------------------------------------------------------------------
+
+inline void
+eeprom_reset_semaphore(struct e100_private *adapter)
+{
+	u16 data = 0;
+
+	data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter));
+	data &= ~(SCB_GCR2_EEPROM_ACCESS_SEMAPHORE);
+	writeb(data, &CSR_GENERAL_CONTROL2_FIELD(adapter));
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   e100_eeprom_size
+//
+// Description: This routine determines the size of the EEPROM.  This value should be
+//              checked for validity - ie. is it too big or too small.  The size returned
+//              is then passed to the read/write functions.
+//
+// Returns:
+//      Size of the eeprom, or zero if an error occured
+//----------------------------------------------------------------------------------------
+u16
+e100_eeprom_size(struct e100_private *adapter)
+{
+	u16 x, size = 1;	// must be one to accumulate a product
+
+	// if we've already stored this data, read from memory
+	if (adapter->eeprom_size) {
+		return adapter->eeprom_size;
+	}
+	// otherwise, read from the eeprom
+	// Set EEPROM semaphore.
+	if (adapter->rev_id >= D102_REV_ID) {
+		if (!eeprom_set_semaphore(adapter))
+			return 0;
+	}
+	// enable the eeprom by setting EECS.
+	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+	x &= ~(EEDI | EEDO | EESK);
+	x |= EECS;
+	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+
+	// write the read opcode
+	shift_out_bits(adapter, EEPROM_READ_OPCODE, 3);
+
+	// experiment to discover the size of the eeprom.  request register zero
+	// and wait for the eeprom to tell us it has accepted the entire address.
+	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+	do {
+		size *= 2;	// each bit of address doubles eeprom size
+		x |= EEDO;	// set bit to detect "dummy zero"
+		x &= ~EEDI;	// address consists of all zeros
+
+		writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+		readw(&(adapter->scb->scb_status));
+		udelay(EEPROM_STALL_TIME);
+		raise_clock(adapter, &x);
+		lower_clock(adapter, &x);
+
+		// check for "dummy zero"
+		x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+		if (size > EEPROM_MAX_WORD_SIZE) {
+			size = 0;
+			break;
+		}
+	} while (x & EEDO);
+
+	// read in the value requested
+	(void) shift_in_bits(adapter);
+	e100_eeprom_cleanup(adapter);
+
+	// Clear EEPROM Semaphore.
+	if (adapter->rev_id >= D102_REV_ID) {
+		eeprom_reset_semaphore(adapter);
+	}
+
+	return size;
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   eeprom_address_size
+//
+// Description: determines the number of bits in an address for the eeprom acceptable
+//              values are 64, 128, and 256
+// Arguments: size of the eeprom
+// Returns: bits in an address for that size eeprom
+//----------------------------------------------------------------------------------------
+
+static inline int
+eeprom_address_size(u16 size)
+{
+	int isize = size;
+	
+	return (ffs(isize) - 1);
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   e100_eeprom_read
+//
+// Description: This routine serially reads one word out of the EEPROM.
+//
+// Arguments:
+//      adapter - our adapter context
+//      reg - EEPROM word to read.
+//
+// Returns:
+//      Contents of EEPROM word (reg).
+//----------------------------------------------------------------------------------------
+
+u16
+e100_eeprom_read(struct e100_private *adapter, u16 reg)
+{
+	u16 x, data, bits;
+
+	// Set EEPROM semaphore.
+	if (adapter->rev_id >= D102_REV_ID) {
+		if (!eeprom_set_semaphore(adapter))
+			return 0;
+	}
+	// eeprom size is initialized to zero
+	if (!adapter->eeprom_size)
+		adapter->eeprom_size = e100_eeprom_size(adapter);
+
+	bits = eeprom_address_size(adapter->eeprom_size);
+
+	// select EEPROM, reset bits, set EECS
+	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+
+	x &= ~(EEDI | EEDO | EESK);
+	x |= EECS;
+	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+
+	// write the read opcode and register number in that order
+	// The opcode is 3bits in length, reg is 'bits' bits long
+	shift_out_bits(adapter, EEPROM_READ_OPCODE, 3);
+	shift_out_bits(adapter, reg, bits);
+
+	// Now read the data (16 bits) in from the selected EEPROM word
+	data = shift_in_bits(adapter);
+
+	e100_eeprom_cleanup(adapter);
+
+	// Clear EEPROM Semaphore.
+	if (adapter->rev_id >= D102_REV_ID) {
+		eeprom_reset_semaphore(adapter);
+	}
+
+	return data;
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   shift_out_bits
+//
+// Description: This routine shifts data bits out to the EEPROM.
+//
+// Arguments:
+//      data - data to send to the EEPROM.
+//      count - number of data bits to shift out.
+//
+// Returns: (none)
+//----------------------------------------------------------------------------------------
+
+static void
+shift_out_bits(struct e100_private *adapter, u16 data, u16 count)
+{
+	u16 x, mask;
+
+	mask = 1 << (count - 1);
+	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+	x &= ~(EEDO | EEDI);
+
+	do {
+		x &= ~EEDI;
+		if (data & mask)
+			x |= EEDI;
+
+		writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+		readw(&(adapter->scb->scb_status)); /* flush command to card */
+		udelay(EEPROM_STALL_TIME);
+		raise_clock(adapter, &x);
+		lower_clock(adapter, &x);
+		mask = mask >> 1;
+	} while (mask);
+
+	x &= ~EEDI;
+	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   raise_clock
+//
+// Description: This routine raises the EEPROM's clock input (EESK)
+//
+// Arguments:
+//      x - Ptr to the EEPROM control register's current value
+//
+// Returns: (none)
+//----------------------------------------------------------------------------------------
+
+void
+raise_clock(struct e100_private *adapter, u16 *x)
+{
+	*x = *x | EESK;
+	writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+	readw(&(adapter->scb->scb_status)); /* flush command to card */
+	udelay(EEPROM_STALL_TIME);
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   lower_clock
+//
+// Description: This routine lower's the EEPROM's clock input (EESK)
+//
+// Arguments:
+//      x - Ptr to the EEPROM control register's current value
+//
+// Returns: (none)
+//----------------------------------------------------------------------------------------
+
+void
+lower_clock(struct e100_private *adapter, u16 *x)
+{
+	*x = *x & ~EESK;
+	writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+	readw(&(adapter->scb->scb_status)); /* flush command to card */
+	udelay(EEPROM_STALL_TIME);
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   shift_in_bits
+//
+// Description: This routine shifts data bits in from the EEPROM.
+//
+// Arguments:
+//
+// Returns:
+//      The contents of that particular EEPROM word
+//----------------------------------------------------------------------------------------
+
+static u16
+shift_in_bits(struct e100_private *adapter)
+{
+	u16 x, d, i;
+
+	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+	x &= ~(EEDO | EEDI);
+	d = 0;
+
+	for (i = 0; i < 16; i++) {
+		d <<= 1;
+		raise_clock(adapter, &x);
+
+		x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+
+		x &= ~EEDI;
+		if (x & EEDO)
+			d |= 1;
+
+		lower_clock(adapter, &x);
+	}
+
+	return d;
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   e100_eeprom_cleanup
+//
+// Description: This routine returns the EEPROM to an idle state
+//----------------------------------------------------------------------------------------
+
+void
+e100_eeprom_cleanup(struct e100_private *adapter)
+{
+	u16 x;
+
+	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+
+	x &= ~(EECS | EEDI);
+	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+
+	raise_clock(adapter, &x);
+	lower_clock(adapter, &x);
+}
+
+//**********************************************************************************
+// Procedure:   e100_eeprom_update_chksum
+//
+// Description: Calculates the checksum and writes it to the EEProm. 
+//              It calculates the checksum accroding to the formula: 
+//                              Checksum = 0xBABA - (sum of first 63 words).
+//
+//-----------------------------------------------------------------------------------
+u16
+e100_eeprom_calculate_chksum(struct e100_private *adapter)
+{
+	u16 idx, xsum_index, checksum = 0;
+
+	// eeprom size is initialized to zero
+	if (!adapter->eeprom_size)
+		adapter->eeprom_size = e100_eeprom_size(adapter);
+
+	xsum_index = adapter->eeprom_size - 1;
+	for (idx = 0; idx < xsum_index; idx++)
+		checksum += e100_eeprom_read(adapter, idx);
+
+	checksum = EEPROM_CHECKSUM - checksum;
+	return checksum;
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   e100_eeprom_write_word
+//
+// Description: This routine writes a word to a specific EEPROM location without.
+//              taking EEPROM semaphore and updating checksum. 
+//              Use e100_eeprom_write_block for the EEPROM update
+// Arguments: reg - The EEPROM word that we are going to write to.
+//            data - The data (word) that we are going to write to the EEPROM.
+//----------------------------------------------------------------------------------------
+static void
+e100_eeprom_write_word(struct e100_private *adapter, u16 reg, u16 data)
+{
+	u16 x;
+	u16 bits;
+
+	bits = eeprom_address_size(adapter->eeprom_size);
+
+	/* select EEPROM, mask off ASIC and reset bits, set EECS */
+	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+	x &= ~(EEDI | EEDO | EESK);
+	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+	readw(&(adapter->scb->scb_status)); /* flush command to card */
+	udelay(EEPROM_STALL_TIME);
+	x |= EECS;
+	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+
+	shift_out_bits(adapter, EEPROM_EWEN_OPCODE, 5);
+	shift_out_bits(adapter, reg, (u16) (bits - 2));
+	if (!eeprom_wait_cmd_done(adapter))
+		return;
+
+	/* write the new word to the EEPROM & send the write opcode the EEPORM */
+	shift_out_bits(adapter, EEPROM_WRITE_OPCODE, 3);
+
+	/* select which word in the EEPROM that we are writing to */
+	shift_out_bits(adapter, reg, bits);
+
+	/* write the data to the selected EEPROM word */
+	shift_out_bits(adapter, data, 16);
+	if (!eeprom_wait_cmd_done(adapter))
+		return;
+
+	shift_out_bits(adapter, EEPROM_EWDS_OPCODE, 5);
+	shift_out_bits(adapter, reg, (u16) (bits - 2));
+	if (!eeprom_wait_cmd_done(adapter))
+		return;
+
+	e100_eeprom_cleanup(adapter);
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   e100_eeprom_write_block
+//
+// Description: This routine writes a block of words starting from specified EEPROM 
+//              location and updates checksum
+// Arguments: reg - The EEPROM word that we are going to write to.
+//            data - The data (word) that we are going to write to the EEPROM.
+//----------------------------------------------------------------------------------------
+void
+e100_eeprom_write_block(struct e100_private *adapter, u16 start, u16 *data,
+			u16 size)
+{
+	u16 checksum;
+	u16 i;
+
+	if (!adapter->eeprom_size)
+		adapter->eeprom_size = e100_eeprom_size(adapter);
+
+	// Set EEPROM semaphore.
+	if (adapter->rev_id >= D102_REV_ID) {
+		if (!eeprom_set_semaphore(adapter))
+			return;
+	}
+
+	for (i = 0; i < size; i++) {
+		e100_eeprom_write_word(adapter, start + i, data[i]);
+	}
+	//Update checksum
+	checksum = e100_eeprom_calculate_chksum(adapter);
+	e100_eeprom_write_word(adapter, (adapter->eeprom_size - 1), checksum);
+
+	// Clear EEPROM Semaphore.
+	if (adapter->rev_id >= D102_REV_ID) {
+		eeprom_reset_semaphore(adapter);
+	}
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   eeprom_wait_cmd_done
+//
+// Description: This routine waits for the the EEPROM to finish its command.  
+//                              Specifically, it waits for EEDO (data out) to go high.
+// Returns:     true - If the command finished
+//              false - If the command never finished (EEDO stayed low)
+//----------------------------------------------------------------------------------------
+static u16
+eeprom_wait_cmd_done(struct e100_private *adapter)
+{
+	u16 x;
+	unsigned long expiration_time = jiffies + HZ / 100 + 1;
+
+	eeprom_stand_by(adapter);
+
+	do {
+		rmb();
+		x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+		if (x & EEDO)
+			return true;
+		if (time_before(jiffies, expiration_time))
+			yield();
+		else
+			return false;
+	} while (true);
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   eeprom_stand_by
+//
+// Description: This routine lowers the EEPROM chip select (EECS) for a few microseconds.
+//----------------------------------------------------------------------------------------
+static void
+eeprom_stand_by(struct e100_private *adapter)
+{
+	u16 x;
+
+	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+	x &= ~(EECS | EESK);
+	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+	readw(&(adapter->scb->scb_status)); /* flush command to card */
+	udelay(EEPROM_STALL_TIME);
+	x |= EECS;
+	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+	readw(&(adapter->scb->scb_status)); /* flush command to card */
+	udelay(EEPROM_STALL_TIME);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e100/e100_main.c linux-2.4.20/drivers/net/e100/e100_main.c
--- linux-2.4.19/drivers/net/e100/e100_main.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e100/e100_main.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,4309 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+*******************************************************************************/
+
+/**********************************************************************
+*                                                                     *
+* INTEL CORPORATION                                                   *
+*                                                                     *
+* This software is supplied under the terms of the license included   *
+* above.  All use of this driver must be in accordance with the terms *
+* of that license.                                                    *
+*                                                                     *
+* Module Name:  e100_main.c                                           *
+*                                                                     *
+* Abstract:     Functions for the driver entry points like load,      *
+*               unload, open and close. All board specific calls made *
+*               by the network interface section of the driver.       *
+*                                                                     *
+* Environment:  This file is intended to be specific to the Linux     *
+*               operating system.                                     *
+*                                                                     *
+**********************************************************************/
+
+/* Change Log
+ *
+ * 2.1.24       10/7/02
+ *   o Bug fix: Wrong files under /proc/net/PRO_LAN_Adapters/ when interface
+ *     name is changed
+ *   o Bug fix: Rx skb corruption when Rx polling code and Rx interrupt code
+ *     are executing during stress traffic at shared interrupt system. 
+ *     Removed Rx polling code
+ *   o Added detailed printk if selftest failed when insmod
+ *   o Removed misleading printks
+ *
+ * 2.1.12       8/2/02
+ *   o Feature: ethtool register dump
+ *   o Bug fix: Driver passes wrong name to /proc/interrupts
+ *   o Bug fix: Ethernet bridging not working 
+ *   o Bug fix: Promiscuous mode is not working
+ *   o Bug fix: Checked return value from copy_from_user (William Stinson,
+ *     wstinson@infonie.fr)
+ *   o Bug fix: ARP wake on LAN fails
+ *   o Bug fix: mii-diag does not update driver level's speed, duplex and
+ *     re-configure flow control
+ *   o Bug fix: Ethtool shows wrong speed/duplex when not connected
+ *   o Bug fix: Ethtool shows wrong speed/duplex when reconnected if forced 
+ *     speed/duplex
+ *   o Bug fix: PHY loopback diagnostic fails
+ *
+ * 2.1.6        7/5/02
+ */
+ 
+#include <linux/config.h>
+#include <net/checksum.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include "e100.h"
+#include "e100_ucode.h"
+#include "e100_config.h"
+#include "e100_phy.h"
+#include "e100_vendor.h"
+
+#ifdef CONFIG_PROC_FS
+extern int e100_create_proc_subdir(struct e100_private *, char *);
+extern void e100_remove_proc_subdir(struct e100_private *, char *);
+#else
+#define e100_create_proc_subdir(X) 0
+#define e100_remove_proc_subdir(X) do {} while(0)
+#endif
+
+static int e100_do_ethtool_ioctl(struct net_device *, struct ifreq *);
+static void e100_get_speed_duplex_caps(struct e100_private *);
+static int e100_ethtool_get_settings(struct net_device *, struct ifreq *);
+static int e100_ethtool_set_settings(struct net_device *, struct ifreq *);
+
+static int e100_ethtool_get_drvinfo(struct net_device *, struct ifreq *);
+static int e100_ethtool_eeprom(struct net_device *, struct ifreq *);
+
+#define E100_EEPROM_MAGIC 0x1234
+static int e100_ethtool_glink(struct net_device *, struct ifreq *);
+static int e100_ethtool_gregs(struct net_device *, struct ifreq *);
+static int e100_ethtool_nway_rst(struct net_device *, struct ifreq *);
+static int e100_ethtool_wol(struct net_device *, struct ifreq *);
+#ifdef CONFIG_PM
+static unsigned char e100_setup_filter(struct e100_private *bdp);
+static void e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp);
+#endif
+static u16 e100_get_ip_lbytes(struct net_device *dev);
+extern void e100_config_wol(struct e100_private *bdp);
+extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags);
+static int e100_ethtool_test(struct net_device *, struct ifreq *);
+static int e100_ethtool_gstrings(struct net_device *, struct ifreq *);
+static char *test_strings[] = {
+	"E100_EEPROM_TEST_FAIL",
+	"E100_CHIP_TIMEOUT",
+	"E100_ROM_TEST_FAIL",
+	"E100_REG_TEST_FAIL",
+	"E100_MAC_TEST_FAIL",
+	"E100_LPBK_MAC_FAIL",
+	"E100_LPBK_PHY_FAIL"
+};
+
+static int e100_ethtool_led_blink(struct net_device *, struct ifreq *);
+
+#include <linux/mii.h>
+static int e100_mii_ioctl(struct net_device *, struct ifreq *, int);
+
+static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *,
+						  nxmit_cb_entry_t *);
+static void e100_free_nontx_list(struct e100_private *);
+static void e100_non_tx_background(unsigned long);
+
+/* Global Data structures and variables */
+char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
+char e100_driver_version[]="2.1.24-k1";
+const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
+char e100_short_driver_name[] = "e100";
+static int e100nics = 0;
+
+#ifdef CONFIG_PM
+static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
+static int e100_suspend(struct pci_dev *pcid, u32 state);
+static int e100_resume(struct pci_dev *pcid);
+struct notifier_block e100_notifier_reboot = {
+        notifier_call:  e100_notify_reboot,
+        next:           NULL,
+        priority:       0
+};
+#endif
+static int e100_notify_netdev(struct notifier_block *, unsigned long event, void *ptr);
+ 
+struct notifier_block e100_notifier_netdev = {
+	notifier_call:  e100_notify_netdev,
+	next:           NULL,
+	priority:       0
+};
+
+static void e100_get_mdix_status(struct e100_private *bdp);
+
+/*********************************************************************/
+/*! This is a GCC extension to ANSI C.
+ *  See the item "Labeled Elements in Initializers" in the section
+ *  "Extensions to the C Language Family" of the GCC documentation.
+ *********************************************************************/
+#define E100_PARAM_INIT { [0 ... E100_MAX_NIC] = -1 }
+
+/* All parameters are treated the same, as an integer array of values.
+ * This macro just reduces the need to repeat the same declaration code
+ * over and over (plus this helps to avoid typo bugs).
+ */
+#define E100_PARAM(X, S)                                        \
+        static const int X[E100_MAX_NIC + 1] = E100_PARAM_INIT; \
+        MODULE_PARM(X, "1-" __MODULE_STRING(E100_MAX_NIC) "i"); \
+        MODULE_PARM_DESC(X, S);
+
+/* ====================================================================== */
+static u8 e100_D101M_checksum(struct e100_private *, struct sk_buff *);
+static u8 e100_D102_check_checksum(rfd_t *);
+static int e100_ioctl(struct net_device *, struct ifreq *, int);
+static int e100_open(struct net_device *);
+static int e100_close(struct net_device *);
+static int e100_change_mtu(struct net_device *, int);
+static int e100_xmit_frame(struct sk_buff *, struct net_device *);
+static unsigned char e100_init(struct e100_private *);
+static int e100_set_mac(struct net_device *, void *);
+struct net_device_stats *e100_get_stats(struct net_device *);
+
+static void e100intr(int, void *, struct pt_regs *);
+static void e100_print_brd_conf(struct e100_private *);
+static void e100_set_multi(struct net_device *);
+void e100_set_speed_duplex(struct e100_private *);
+
+char *e100_get_brand_msg(struct e100_private *);
+static u8 e100_pci_setup(struct pci_dev *, struct e100_private *);
+static u8 e100_sw_init(struct e100_private *);
+static unsigned char e100_alloc_space(struct e100_private *);
+static void e100_dealloc_space(struct e100_private *);
+static int e100_alloc_tcb_pool(struct e100_private *);
+static void e100_setup_tcb_pool(tcb_t *, unsigned int, struct e100_private *);
+static void e100_free_tcb_pool(struct e100_private *);
+static int e100_alloc_rfd_pool(struct e100_private *);
+static void e100_free_rfd_pool(struct e100_private *);
+
+static void e100_rd_eaddr(struct e100_private *);
+static void e100_rd_pwa_no(struct e100_private *);
+extern u16 e100_eeprom_read(struct e100_private *, u16);
+extern void e100_eeprom_write_block(struct e100_private *, u16, u16 *, u16);
+extern u16 e100_eeprom_size(struct e100_private *);
+u16 e100_eeprom_calculate_chksum(struct e100_private *adapter);
+
+static unsigned char e100_clr_cntrs(struct e100_private *);
+static unsigned char e100_load_microcode(struct e100_private *);
+static unsigned char e100_hw_init(struct e100_private *, u32);
+static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *);
+static unsigned char e100_update_stats(struct e100_private *bdp);
+
+static void e100_start_ru(struct e100_private *);
+static void e100_dump_stats_cntrs(struct e100_private *);
+
+static void e100_check_options(int board, struct e100_private *bdp);
+static void e100_set_int_option(int *, int, int, int, int, char *);
+static void e100_set_bool_option(struct e100_private *bdp, int, u32, int,
+				 char *);
+unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8);
+void e100_exec_cmplx(struct e100_private *, u32, u8);
+
+/**
+ * e100_get_rx_struct - retrieve cell to hold skb buff from the pool
+ * @bdp: atapter's private data struct
+ *
+ * Returns the new cell to hold sk_buff or %NULL.
+ */
+static inline struct rx_list_elem *
+e100_get_rx_struct(struct e100_private *bdp)
+{
+	struct rx_list_elem *rx_struct = NULL;
+
+	if (!list_empty(&(bdp->rx_struct_pool))) {
+		rx_struct = list_entry(bdp->rx_struct_pool.next,
+				       struct rx_list_elem, list_elem);
+		list_del(&(rx_struct->list_elem));
+	}
+
+	return rx_struct;
+}
+
+/**
+ * e100_alloc_skb - allocate an skb for the adapter
+ * @bdp: atapter's private data struct
+ *
+ * Allocates skb with enough room for rfd, and data, and reserve non-data space.
+ * Returns the new cell with sk_buff or %NULL.
+ */
+static inline struct rx_list_elem *
+e100_alloc_skb(struct e100_private *bdp)
+{
+	struct sk_buff *new_skb;
+	u32 skb_size = sizeof (rfd_t);
+	struct rx_list_elem *rx_struct;
+
+	new_skb = (struct sk_buff *) dev_alloc_skb(skb_size);
+	if (new_skb) {
+		/* The IP data should be 
+		   DWORD aligned. since the ethernet header is 14 bytes long, 
+		   we need to reserve 2 extra bytes so that the TCP/IP headers
+		   will be DWORD aligned. */
+		skb_reserve(new_skb, 2);
+		if ((rx_struct = e100_get_rx_struct(bdp)) == NULL)
+			goto err;
+		rx_struct->skb = new_skb;
+		rx_struct->dma_addr = pci_map_single(bdp->pdev, new_skb->data,
+						     sizeof (rfd_t),
+						     PCI_DMA_FROMDEVICE);
+		if (!rx_struct->dma_addr)
+			goto err;
+		skb_reserve(new_skb, bdp->rfd_size);
+		return rx_struct;
+	} else {
+		return NULL;
+	}
+
+err:
+	dev_kfree_skb_irq(new_skb);
+	return NULL;
+}
+
+/**
+ * e100_add_skb_to_end - add an skb to the end of our rfd list
+ * @bdp: atapter's private data struct
+ * @rx_struct: rx_list_elem with the new skb
+ *
+ * Adds a newly allocated skb to the end of our rfd list.
+ */
+inline void
+e100_add_skb_to_end(struct e100_private *bdp, struct rx_list_elem *rx_struct)
+{
+	rfd_t *rfdn;		/* The new rfd */
+	rfd_t *rfd;		/* The old rfd */
+	struct rx_list_elem *rx_struct_last;
+
+	(rx_struct->skb)->dev = bdp->device;
+	rfdn = RFD_POINTER(rx_struct->skb, bdp);
+	rfdn->rfd_header.cb_status = 0;
+	rfdn->rfd_header.cb_cmd = __constant_cpu_to_le16(RFD_EL_BIT);
+	rfdn->rfd_act_cnt = 0;
+	rfdn->rfd_sz = __constant_cpu_to_le16(RFD_DATA_SIZE);
+
+	pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, bdp->rfd_size,
+			    PCI_DMA_TODEVICE);
+
+	if (!list_empty(&(bdp->active_rx_list))) {
+		rx_struct_last = list_entry(bdp->active_rx_list.prev,
+					    struct rx_list_elem, list_elem);
+		rfd = RFD_POINTER(rx_struct_last->skb, bdp);
+		pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr,
+				    4, PCI_DMA_FROMDEVICE);
+		put_unaligned(cpu_to_le32(rx_struct->dma_addr),
+			      ((u32 *) (&(rfd->rfd_header.cb_lnk_ptr))));
+
+		pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr,
+				    8, PCI_DMA_TODEVICE);
+		rfd->rfd_header.cb_cmd &=
+			__constant_cpu_to_le16((u16) ~RFD_EL_BIT);
+
+		pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr,
+				    4, PCI_DMA_TODEVICE);
+	}
+
+	list_add_tail(&(rx_struct->list_elem), &(bdp->active_rx_list));
+}
+
+static inline void
+e100_alloc_skbs(struct e100_private *bdp)
+{
+	for (; bdp->skb_req > 0; bdp->skb_req--) {
+		struct rx_list_elem *rx_struct;
+
+		if ((rx_struct = e100_alloc_skb(bdp)) == NULL)
+			return;
+
+		e100_add_skb_to_end(bdp, rx_struct);
+	}
+}
+
+void e100_tx_srv(struct e100_private *);
+u32 e100_rx_srv(struct e100_private *);
+
+void e100_watchdog(struct net_device *);
+static void e100_do_hwi(struct net_device *);
+static void e100_hwi_restore(struct e100_private *);
+void e100_refresh_txthld(struct e100_private *);
+void e100_manage_adaptive_ifs(struct e100_private *);
+void e100_clear_pools(struct e100_private *);
+static void e100_clear_structs(struct net_device *);
+static inline tcb_t *e100_prepare_xmit_buff(struct e100_private *,
+					    struct sk_buff *);
+static void e100_set_multi_exec(struct net_device *dev);
+
+MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
+MODULE_DESCRIPTION("Intel(R) PRO/100 Network Driver");
+MODULE_LICENSE("GPL");
+
+E100_PARAM(TxDescriptors, "Number of transmit descriptors");
+E100_PARAM(RxDescriptors, "Number of receive descriptors");
+E100_PARAM(XsumRX, "Disable or enable Receive Checksum offload");
+E100_PARAM(e100_speed_duplex, "Speed and Duplex settings");
+E100_PARAM(ucode, "Disable or enable microcode loading");
+E100_PARAM(ber, "Value for the BER correction algorithm");
+E100_PARAM(flow_control, "Disable or enable Ethernet PAUSE frames processing");
+E100_PARAM(IntDelay, "Value for CPU saver's interrupt delay");
+E100_PARAM(BundleSmallFr, "Disable or enable interrupt bundling of small frames");
+E100_PARAM(BundleMax, "Maximum number for CPU saver's packet bundling");
+E100_PARAM(IFS, "Disable or enable the adaptive IFS algorithm");
+
+/**
+ * e100_exec_cmd - issue a comand
+ * @bdp: atapter's private data struct
+ * @scb_cmd_low: the command that is to be issued
+ *
+ * This general routine will issue a command to the e100.
+ */
+static inline void
+e100_exec_cmd(struct e100_private *bdp, u8 cmd_low)
+{
+	writeb(cmd_low, &(bdp->scb->scb_cmd_low));
+	readw(&(bdp->scb->scb_status));	/* flushes last write, read-safe */
+}
+
+/**
+ * e100_wait_scb - wait for SCB to clear
+ * @bdp: atapter's private data struct
+ *
+ * This routine checks to see if the e100 has accepted a command.
+ * It does so by checking the command field in the SCB, which will
+ * be zeroed by the e100 upon accepting a command.  The loop waits
+ * for up to 1 millisecond for command acceptance.
+ *
+ * Returns:
+ *      true if the SCB cleared within 1 millisecond.
+ *      false if it didn't clear within 1 millisecond
+ */
+unsigned char
+e100_wait_scb(struct e100_private *bdp)
+{
+	int i;
+
+	/* loop on the scb for a few times */
+	for (i = 0; i < 100; i++) {
+		if (!readb(&bdp->scb->scb_cmd_low))
+			return true;
+		cpu_relax();
+	}
+
+	/* it didn't work. do it the slow way using udelay()s */
+	for (i = 0; i < E100_MAX_SCB_WAIT; i++) {
+		if (!readb(&bdp->scb->scb_cmd_low))
+			return true;
+		cpu_relax();
+		udelay(1);
+	}
+
+	return false;
+}
+
+/**
+ * e100_wait_exec_simple - issue a command
+ * @bdp: atapter's private data struct
+ * @scb_cmd_low: the command that is to be issued
+ *
+ * This general routine will issue a command to the e100 after waiting for
+ * the previous command to finish.
+ *
+ * Returns:
+ *      true if the command was issued to the chip successfully
+ *      false if the command was not issued to the chip
+ */
+inline unsigned char
+e100_wait_exec_simple(struct e100_private *bdp, u8 scb_cmd_low)
+{
+	if (!e100_wait_scb(bdp)) {
+		printk(KERN_DEBUG "e100: %s: e100_wait_exec_simple: failed\n",
+		       bdp->device->name);
+		return false;
+	}
+	e100_exec_cmd(bdp, scb_cmd_low);
+	return true;
+}
+
+void
+e100_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd)
+{
+	writel(phys_addr, &(bdp->scb->scb_gen_ptr));
+	readw(&(bdp->scb->scb_status));	/* flushes last write, read-safe */
+	e100_exec_cmd(bdp, cmd);
+}
+
+unsigned char
+e100_wait_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd)
+{
+	if (!e100_wait_scb(bdp)) {
+		return false;
+	}
+	e100_exec_cmplx(bdp, phys_addr, cmd);
+	return true;
+}
+
+inline u8
+e100_wait_cus_idle(struct e100_private *bdp)
+{
+	int i;
+
+	/* loop on the scb for a few times */
+	for (i = 0; i < 100; i++) {
+		if (((readw(&(bdp->scb->scb_status)) & SCB_CUS_MASK) !=
+		     SCB_CUS_ACTIVE)) {
+			return true;
+		}
+		cpu_relax();
+	}
+
+	for (i = 0; i < E100_MAX_CU_IDLE_WAIT; i++) {
+		if (((readw(&(bdp->scb->scb_status)) & SCB_CUS_MASK) !=
+		     SCB_CUS_ACTIVE)) {
+			return true;
+		}
+		cpu_relax();
+		udelay(1);
+	}
+
+	return false;
+}
+
+/**
+ * e100_dis_intr - disable interrupts
+ * @bdp: atapter's private data struct
+ *
+ * This routine disables interrupts at the hardware, by setting
+ * the M (mask) bit in the adapter's CSR SCB command word.
+ */
+static inline void
+e100_dis_intr(struct e100_private *bdp)
+{
+	/* Disable interrupts on our PCI board by setting the mask bit */
+	writeb(SCB_INT_MASK, &bdp->scb->scb_cmd_hi);
+	readw(&(bdp->scb->scb_status));	/* flushes last write, read-safe */
+}
+
+/**
+ * e100_set_intr_mask - set interrupts
+ * @bdp: atapter's private data struct
+ *
+ * This routine sets interrupts at the hardware, by resetting
+ * the M (mask) bit in the adapter's CSR SCB command word
+ */
+static inline void
+e100_set_intr_mask(struct e100_private *bdp)
+{
+	writeb(bdp->intr_mask, &bdp->scb->scb_cmd_hi);
+	readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */
+}
+
+static inline void
+e100_trigger_SWI(struct e100_private *bdp)
+{
+	/* Trigger interrupt on our PCI board by asserting SWI bit */
+	writeb(SCB_SOFT_INT, &bdp->scb->scb_cmd_hi);
+	readw(&(bdp->scb->scb_status));	/* flushes last write, read-safe */
+}
+
+static int __devinit
+e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
+{
+	static int first_time = true;
+	struct net_device *dev = NULL;
+	struct e100_private *bdp = NULL;
+	int rc = 0;
+	u16 cal_checksum, read_checksum;
+
+	dev = alloc_etherdev(sizeof (struct e100_private));
+	if (dev == NULL) {
+		printk(KERN_ERR "e100: Not able to alloc etherdev struct\n");
+		rc = -ENODEV;
+		goto out;
+	}
+
+	SET_MODULE_OWNER(dev);
+
+	if (first_time) {
+		first_time = false;
+        	printk(KERN_NOTICE "%s - version %s\n",
+	               e100_full_driver_name, e100_driver_version);
+		printk(KERN_NOTICE "%s\n", e100_copyright);
+		printk(KERN_NOTICE "\n");
+	}
+
+	bdp = dev->priv;
+	bdp->pdev = pcid;
+	bdp->device = dev;
+
+	pci_set_drvdata(pcid, dev);
+
+	if ((rc = e100_alloc_space(bdp)) != 0) {
+		goto err_dev;
+	}
+
+	bdp->flags = 0;
+	bdp->ifs_state = 0;
+	bdp->ifs_value = 0;
+	bdp->scb = 0;
+
+	init_timer(&bdp->nontx_timer_id);
+	bdp->nontx_timer_id.data = (unsigned long) bdp;
+	bdp->nontx_timer_id.function = (void *) &e100_non_tx_background;
+	INIT_LIST_HEAD(&(bdp->non_tx_cmd_list));
+	bdp->non_tx_command_state = E100_NON_TX_IDLE;
+
+	init_timer(&bdp->watchdog_timer);
+	bdp->watchdog_timer.data = (unsigned long) dev;
+	bdp->watchdog_timer.function = (void *) &e100_watchdog;
+
+	init_timer(&bdp->hwi_timer);
+	bdp->hwi_timer.data = (unsigned long) dev;
+	bdp->hwi_timer.function = (void *) &e100_do_hwi;
+
+	if ((rc = e100_pci_setup(pcid, bdp)) != 0) {
+		goto err_dealloc;
+	}
+
+	if (((bdp->pdev->device > 0x1030)
+	     && (bdp->pdev->device < 0x103F))
+	    || (bdp->pdev->device == 0x2449)
+	    || (bdp->pdev->device == 0x2459)
+	    || (bdp->pdev->device == 0x245D)) {
+		bdp->rev_id = D101MA_REV_ID;	/* workaround for ICH3 */
+		bdp->flags |= IS_ICH;
+	}
+
+	if (bdp->rev_id == 0xff)
+		bdp->rev_id = 1;
+
+	if ((u8) bdp->rev_id >= D101A4_REV_ID)
+		bdp->flags |= IS_BACHELOR;
+
+	if ((u8) bdp->rev_id >= D102_REV_ID) {
+		bdp->flags |= USE_IPCB;
+		bdp->rfd_size = 32;
+	} else {
+		bdp->rfd_size = 16;
+	}
+	e100_check_options(e100nics, bdp);
+
+	if (!e100_init(bdp)) {
+		printk(KERN_ERR "e100: Failed to initialize, instance #%d\n",
+		       e100nics);
+		rc = -ENODEV;
+		goto err_pci;
+	}
+
+	/* Check if checksum is valid */
+	cal_checksum = e100_eeprom_calculate_chksum(bdp);
+	read_checksum = e100_eeprom_read(bdp, (bdp->eeprom_size - 1));
+	if (cal_checksum != read_checksum) {
+                printk(KERN_ERR "e100: Corrupted EERPROM on instance #%d\n",
+		       e100nics);
+                rc = -ENODEV;
+                goto err_pci;
+	}
+	
+	dev->irq = pcid->irq;
+	dev->open = &e100_open;
+	dev->hard_start_xmit = &e100_xmit_frame;
+	dev->stop = &e100_close;
+	dev->change_mtu = &e100_change_mtu;
+	dev->get_stats = &e100_get_stats;
+	dev->set_multicast_list = &e100_set_multi;
+	dev->set_mac_address = &e100_set_mac;
+	dev->do_ioctl = &e100_ioctl;
+	if (bdp->flags & USE_IPCB) {
+		dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+	}
+	e100nics++;
+
+	e100_get_speed_duplex_caps(bdp);
+
+	if ((rc = register_netdev(dev)) != 0) {
+		goto err_pci;
+	}
+        memcpy(bdp->ifname, dev->name, IFNAMSIZ);
+        bdp->ifname[IFNAMSIZ-1] = 0;	
+
+	bdp->device_type = ent->driver_data;
+	printk(KERN_NOTICE
+	       "e100: %s: %s\n", 
+	       bdp->device->name, e100_get_brand_msg(bdp));
+	e100_print_brd_conf(bdp);
+	bdp->id_string = e100_get_brand_msg(bdp);
+	e100_get_mdix_status(bdp);
+
+	if (netif_carrier_ok(bdp->device)) 
+		bdp->cable_status = "Cable OK";
+	else {
+		if (bdp->rev_id < D102_REV_ID) 
+			bdp->cable_status = "Not supported";
+		else
+			bdp->cable_status = "Not available";
+	}
+
+	if (e100_create_proc_subdir(bdp, bdp->ifname) < 0) {
+		printk(KERN_ERR "e100: Failed to create proc dir for %s\n",
+		       bdp->device->name);
+	}
+
+	/* Disabling all WOLs as initialization */
+	bdp->wolsupported = bdp->wolopts = 0;
+	if (bdp->rev_id >= D101A4_REV_ID) {
+		bdp->wolsupported = WAKE_PHY | WAKE_MAGIC;
+		if (bdp->rev_id >= D101MA_REV_ID)
+			bdp->wolsupported |= WAKE_UCAST | WAKE_ARP;
+		bdp->wolopts = WAKE_MAGIC;
+	}
+
+	printk(KERN_NOTICE "\n");
+
+	goto out;
+
+err_pci:
+	iounmap(bdp->scb);
+	pci_release_regions(pcid);
+	pci_disable_device(pcid);
+err_dealloc:
+	e100_dealloc_space(bdp);
+err_dev:
+	pci_set_drvdata(pcid, NULL);
+	kfree(dev);
+out:
+	return rc;
+}
+
+/**
+ * e100_clear_structs - free resources
+ * @dev: adapter's net_device struct
+ *
+ * Free all device specific structs, unmap i/o address, etc.
+ */
+static void __devexit
+e100_clear_structs(struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+
+	iounmap(bdp->scb);
+	pci_release_regions(bdp->pdev);
+	pci_disable_device(bdp->pdev);
+
+	e100_dealloc_space(bdp);
+	pci_set_drvdata(bdp->pdev, NULL);
+	kfree(dev);
+}
+
+static void __devexit
+e100_remove1(struct pci_dev *pcid)
+{
+	struct net_device *dev;
+	struct e100_private *bdp;
+
+	if (!(dev = (struct net_device *) pci_get_drvdata(pcid)))
+		return;
+
+	bdp = dev->priv;
+
+	unregister_netdev(dev);
+
+	e100_remove_proc_subdir(bdp, bdp->ifname);
+
+	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
+
+	if (bdp->non_tx_command_state != E100_NON_TX_IDLE) {
+		del_timer_sync(&bdp->nontx_timer_id);
+		e100_free_nontx_list(bdp);
+		bdp->non_tx_command_state = E100_NON_TX_IDLE;
+	}
+
+	e100_clear_structs(dev);
+
+	--e100nics;
+}
+
+MODULE_DEVICE_TABLE(pci, e100_id_table);
+
+static struct pci_driver e100_driver = {
+	.name         = "e100",
+	.id_table     = e100_id_table,
+	.probe        = e100_found1,
+	.remove       = __devexit_p(e100_remove1),
+#ifdef CONFIG_PM
+	.suspend      = e100_suspend,
+	.resume       = e100_resume,
+#endif
+};
+
+static int __init
+e100_init_module(void)
+{
+	int ret;
+        ret = pci_module_init(&e100_driver);
+
+	if(ret >= 0) {
+#ifdef CONFIG_PM
+		register_reboot_notifier(&e100_notifier_reboot);
+#endif 
+		register_netdevice_notifier(&e100_notifier_netdev);
+	}
+
+	return ret;
+}
+
+static void __exit
+e100_cleanup_module(void)
+{
+#ifdef CONFIG_PM	
+	unregister_reboot_notifier(&e100_notifier_reboot);
+#endif 
+	unregister_netdevice_notifier(&e100_notifier_netdev);
+
+	pci_unregister_driver(&e100_driver);
+}
+
+module_init(e100_init_module);
+module_exit(e100_cleanup_module);
+
+/**
+ * e100_check_options - check command line options
+ * @board: board number
+ * @bdp: atapter's private data struct
+ *
+ * This routine does range checking on command-line options
+ */
+void __devinit
+e100_check_options(int board, struct e100_private *bdp)
+{
+	if (board >= E100_MAX_NIC) {
+		printk(KERN_NOTICE 
+		       "e100: No configuration available for board #%d\n",
+		       board);
+		printk(KERN_NOTICE "e100: Using defaults for all values\n");
+		board = E100_MAX_NIC;
+	}
+
+	e100_set_int_option(&(bdp->params.TxDescriptors), TxDescriptors[board],
+			    E100_MIN_TCB, E100_MAX_TCB, E100_DEFAULT_TCB,
+			    "TxDescriptor count");
+
+	e100_set_int_option(&(bdp->params.RxDescriptors), RxDescriptors[board],
+			    E100_MIN_RFD, E100_MAX_RFD, E100_DEFAULT_RFD,
+			    "RxDescriptor count");
+
+	e100_set_int_option(&(bdp->params.e100_speed_duplex),
+			    e100_speed_duplex[board], 0, 4,
+			    E100_DEFAULT_SPEED_DUPLEX, "speed/duplex mode");
+
+	e100_set_int_option(&(bdp->params.ber), ber[board], 0, ZLOCK_MAX_ERRORS,
+			    E100_DEFAULT_BER, "Bit Error Rate count");
+
+	e100_set_bool_option(bdp, XsumRX[board], PRM_XSUMRX, E100_DEFAULT_XSUM,
+			     "XsumRX value");
+
+	/* Default ucode value depended on controller revision */
+	if (bdp->rev_id >= D101MA_REV_ID) {
+		e100_set_bool_option(bdp, ucode[board], PRM_UCODE,
+				     E100_DEFAULT_UCODE, "ucode value");
+	} else {
+		e100_set_bool_option(bdp, ucode[board], PRM_UCODE, false,
+				     "ucode value");
+	}
+
+	e100_set_bool_option(bdp, flow_control[board], PRM_FC, E100_DEFAULT_FC,
+			     "flow control value");
+
+	e100_set_bool_option(bdp, IFS[board], PRM_IFS, E100_DEFAULT_IFS,
+			     "IFS value");
+
+	e100_set_bool_option(bdp, BundleSmallFr[board], PRM_BUNDLE_SMALL,
+			     E100_DEFAULT_BUNDLE_SMALL_FR,
+			     "CPU saver bundle small frames value");
+
+	e100_set_int_option(&(bdp->params.IntDelay), IntDelay[board], 0x0,
+			    0xFFFF, E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY,
+			    "CPU saver interrupt delay value");
+
+	e100_set_int_option(&(bdp->params.BundleMax), BundleMax[board], 0x1,
+			    0xFFFF, E100_DEFAULT_CPUSAVER_BUNDLE_MAX,
+			    "CPU saver bundle max value");
+
+}
+
+/**
+ * e100_set_int_option - check and set an integer option
+ * @option: a pointer to the relevant option field
+ * @val: the value specified
+ * @min: the minimum valid value
+ * @max: the maximum valid value
+ * @default_val: the default value
+ * @name: the name of the option
+ *
+ * This routine does range checking on a command-line option.
+ * If the option's value is '-1' use the specified default.
+ * Otherwise, if the value is invalid, change it to the default.
+ */
+void __devinit
+e100_set_int_option(int *option, int val, int min, int max, int default_val,
+		    char *name)
+{
+	if (val == -1) {	/* no value specified. use default */
+		*option = default_val;
+
+	} else if ((val < min) || (val > max)) {
+		printk(KERN_NOTICE
+		       "e100: Invalid %s specified (%i). "
+		       "Valid range is %i-%i\n",
+		       name, val, min, max);
+		printk(KERN_NOTICE "e100: Using default %s of %i\n", name,
+		       default_val);
+		*option = default_val;
+	} else {
+		printk(KERN_INFO "e100: Using specified %s of %i\n", name, val);
+		*option = val;
+	}
+}
+
+/**
+ * e100_set_bool_option - check and set a boolean option
+ * @bdp: atapter's private data struct
+ * @val: the value specified
+ * @mask: the mask for the relevant option
+ * @default_val: the default value
+ * @name: the name of the option
+ *
+ * This routine checks a boolean command-line option.
+ * If the option's value is '-1' use the specified default.
+ * Otherwise, if the value is invalid (not 0 or 1), 
+ * change it to the default.
+ */
+void __devinit
+e100_set_bool_option(struct e100_private *bdp, int val, u32 mask,
+		     int default_val, char *name)
+{
+	if (val == -1) {
+		if (default_val)
+			bdp->params.b_params |= mask;
+
+	} else if ((val != true) && (val != false)) {
+		printk(KERN_NOTICE
+		       "e100: Invalid %s specified (%i). "
+		       "Valid values are %i/%i\n",
+		       name, val, false, true);
+		printk(KERN_NOTICE "e100: Using default %s of %i\n", name,
+		       default_val);
+
+		if (default_val)
+			bdp->params.b_params |= mask;
+	} else {
+		printk(KERN_INFO "e100: Using specified %s of %i\n", name, val);
+		if (val)
+			bdp->params.b_params |= mask;
+	}
+}
+
+static int
+e100_open(struct net_device *dev)
+{
+	struct e100_private *bdp;
+	int rc = 0;
+
+	bdp = dev->priv;
+
+	read_lock(&(bdp->isolate_lock));
+
+	if (bdp->driver_isolated) {
+		rc = -EBUSY;
+		goto exit;
+	}
+
+	/* setup the tcb pool */
+	if (!e100_alloc_tcb_pool(bdp)) {
+		rc = -ENOMEM;
+		goto err_exit;
+	}
+	bdp->last_tcb = NULL;
+
+	bdp->tcb_pool.head = 0;
+	bdp->tcb_pool.tail = 1;	
+
+	e100_setup_tcb_pool((tcb_t *) bdp->tcb_pool.data,
+			    bdp->params.TxDescriptors, bdp);
+
+	if (!e100_alloc_rfd_pool(bdp)) {
+		rc = -ENOMEM;
+		goto err_exit;
+	}
+
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE)) {
+		rc = -EAGAIN;
+		goto err_exit;
+	}
+
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE)) {
+		rc = -EAGAIN;
+		goto err_exit;
+	}
+
+	mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ));
+
+	netif_start_queue(dev);
+
+	e100_start_ru(bdp);
+	if ((rc = request_irq(dev->irq, &e100intr, SA_SHIRQ,
+			      dev->name, dev)) != 0) {
+		del_timer_sync(&bdp->watchdog_timer);
+		goto err_exit;
+	}
+	bdp->intr_mask = 0;
+	e100_set_intr_mask(bdp);
+
+	e100_force_config(bdp);
+
+	goto exit;
+
+err_exit:
+	e100_clear_pools(bdp);
+exit:
+	read_unlock(&(bdp->isolate_lock));
+	return rc;
+}
+
+static int
+e100_close(struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+
+	bdp->intr_mask = SCB_INT_MASK;
+	e100_isolate_driver(bdp);
+
+	netif_carrier_off(bdp->device);
+	bdp->cur_line_speed = 0;
+	bdp->cur_dplx_mode = 0;
+	free_irq(dev->irq, dev);
+	e100_clear_pools(bdp);
+
+	/* set the isolate flag to false, so e100_open can be called */
+	bdp->driver_isolated = false;
+
+	return 0;
+}
+
+static int
+e100_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > (ETH_DATA_LEN + VLAN_SIZE)))
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+static int
+e100_xmit_frame(struct sk_buff *skb, struct net_device *dev)
+{
+	int rc = 0;
+	int notify_stop = false;
+	struct e100_private *bdp = dev->priv;
+
+	read_lock(&(bdp->isolate_lock));
+
+	if (bdp->driver_isolated) {
+		rc = -EBUSY;
+		goto exit2;
+	}
+
+	if (!spin_trylock(&bdp->bd_non_tx_lock)) {
+		notify_stop = true;
+		rc = 1;
+		goto exit2;
+	}
+
+	if (!TCBS_AVAIL(bdp->tcb_pool) ||
+	    (bdp->non_tx_command_state != E100_NON_TX_IDLE)) {
+		notify_stop = true;
+		rc = 1;
+		goto exit1;
+	}
+
+	e100_prepare_xmit_buff(bdp, skb);
+
+	bdp->drv_stats.net_stats.tx_bytes += skb->len;
+
+	dev->trans_start = jiffies;
+
+exit1:
+	spin_unlock(&bdp->bd_non_tx_lock);
+exit2:
+	read_unlock(&(bdp->isolate_lock));
+	if (notify_stop) {
+		netif_stop_queue(dev);
+	}
+
+	return rc;
+}
+
+/**
+ * e100_get_stats - get driver statistics
+ * @dev: adapter's net_device struct
+ *
+ * This routine is called when the OS wants the adapter's stats returned.
+ * It returns the address of the net_device_stats stucture for the device.
+ * If the statistics are currently being updated, then they might be incorrect
+ * for a short while. However, since this cannot actually cause damage, no
+ * locking is used.
+ */
+struct net_device_stats *
+e100_get_stats(struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+
+	bdp->drv_stats.net_stats.tx_errors =
+		bdp->drv_stats.net_stats.tx_carrier_errors +
+		bdp->drv_stats.net_stats.tx_aborted_errors;
+
+	bdp->drv_stats.net_stats.rx_errors =
+		bdp->drv_stats.net_stats.rx_crc_errors +
+		bdp->drv_stats.net_stats.rx_frame_errors +
+		bdp->drv_stats.net_stats.rx_length_errors +
+		bdp->drv_stats.rcv_cdt_frames;
+
+	return &(bdp->drv_stats.net_stats);
+}
+
+/**
+ * e100_set_mac - set the MAC address
+ * @dev: adapter's net_device struct
+ * @addr: the new address
+ *
+ * This routine sets the ethernet address of the board
+ * Returns:
+ * 0  - if successful
+ * -1 - otherwise
+ */
+static int
+e100_set_mac(struct net_device *dev, void *addr)
+{
+	struct e100_private *bdp;
+	int rc = -1;
+	struct sockaddr *p_sockaddr = (struct sockaddr *) addr;
+
+	bdp = dev->priv;
+
+	read_lock(&(bdp->isolate_lock));
+
+	if (bdp->driver_isolated) {
+		goto exit;
+	}
+	if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) {
+		memcpy(&(dev->dev_addr[0]), p_sockaddr->sa_data, ETH_ALEN);
+		rc = 0;
+	}
+
+exit:
+	read_unlock(&(bdp->isolate_lock));
+	return rc;
+}
+
+static void
+e100_set_multi_exec(struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+	mltcst_cb_t *mcast_buff;
+	cb_header_t *cb_hdr;
+	struct dev_mc_list *mc_list;
+	unsigned int i;
+	nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp);
+
+	if (cmd != NULL) {
+		mcast_buff = &((cmd->non_tx_cmd)->ntcb.multicast);
+		cb_hdr = &((cmd->non_tx_cmd)->ntcb.multicast.mc_cbhdr);
+	} else {
+		return;
+	}
+
+	/* initialize the multi cast command */
+	cb_hdr->cb_cmd = __constant_cpu_to_le16(CB_MULTICAST);
+
+	/* now fill in the rest of the multicast command */
+	*(u16 *) (&(mcast_buff->mc_count)) = cpu_to_le16(dev->mc_count * 6);
+	for (i = 0, mc_list = dev->mc_list;
+	     (i < dev->mc_count) && (i < MAX_MULTICAST_ADDRS);
+	     i++, mc_list = mc_list->next) {
+		/* copy into the command */
+		memcpy(&(mcast_buff->mc_addr[i * ETH_ALEN]),
+		       (u8 *) &(mc_list->dmi_addr), ETH_ALEN);
+	}
+
+	if (!e100_exec_non_cu_cmd(bdp, cmd)) {
+		printk(KERN_WARNING "e100: %s: Multicast setup failed\n", 
+		       dev->name);
+	}
+}
+
+/**
+ * e100_set_multi - set multicast status
+ * @dev: adapter's net_device struct
+ *
+ * This routine is called to add or remove multicast addresses, and/or to
+ * change the adapter's promiscuous state.
+ */
+static void
+e100_set_multi(struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+	unsigned char promisc_enbl;
+	unsigned char mulcast_enbl;
+
+	read_lock(&(bdp->isolate_lock));
+	if (bdp->driver_isolated) {
+		goto exit;
+	}
+	promisc_enbl = ((dev->flags & IFF_PROMISC) == IFF_PROMISC);
+	mulcast_enbl = ((dev->flags & IFF_ALLMULTI) ||
+			(dev->mc_count > MAX_MULTICAST_ADDRS));
+
+	e100_config_promisc(bdp, promisc_enbl);
+	e100_config_mulcast_enbl(bdp, mulcast_enbl);
+
+	/* reconfigure the chip if something has changed in its config space */
+	e100_config(bdp);
+
+	if (promisc_enbl || mulcast_enbl) {
+		goto exit;	/* no need for Multicast Cmd */
+	}
+
+	/* get the multicast CB */
+	e100_set_multi_exec(dev);
+
+exit:
+	read_unlock(&(bdp->isolate_lock));
+}
+
+static int
+e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+
+	switch (cmd) {
+
+	case SIOCETHTOOL:
+		return e100_do_ethtool_ioctl(dev, ifr);
+		break;
+
+	case SIOCGMIIPHY:	/* Get address of MII PHY in use. */
+	case SIOCGMIIREG:	/* Read MII PHY register. */
+	case SIOCSMIIREG:	/* Write to MII PHY register. */
+		return e100_mii_ioctl(dev, ifr, cmd);
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+
+}
+
+/**
+ * e100init - initialize the adapter
+ * @bdp: atapter's private data struct
+ *
+ * This routine is called when this driver is loaded. This is the initialization
+ * routine which allocates memory, configures the adapter and determines the
+ * system resources.
+ *
+ * Returns:
+ *      true: if successful
+ *      false: otherwise
+ */
+static unsigned char __devinit
+e100_init(struct e100_private *bdp)
+{
+	u32 st_timeout = 0;
+	u32 st_result = 0;
+	e100_sw_init(bdp);
+
+	if (!e100_selftest(bdp, &st_timeout, &st_result)) {
+        	if (st_timeout) {
+			printk(KERN_ERR "e100: selftest timeout\n");
+		} else {
+			printk(KERN_ERR "e100: selftest failed. Results: %x\n",
+					st_result);
+		}
+		return false;
+	}
+	else
+		printk(KERN_DEBUG "e100: selftest OK.\n");
+
+	/* read the MAC address from the eprom */
+	e100_rd_eaddr(bdp);
+	/* read NIC's part number */
+	e100_rd_pwa_no(bdp);
+
+	if (!e100_hw_init(bdp, PORT_SOFTWARE_RESET)) {
+		printk(KERN_ERR "e100: hw init failed\n");
+		return false;
+	}
+	e100_dis_intr(bdp);
+
+	return true;
+}
+
+/**
+ * e100_sw_init - initialize software structs
+ * @bdp: atapter's private data struct
+ * 
+ * This routine initializes all software structures. Sets up the
+ * circular structures for the RFD's & TCB's. Allocates the per board
+ * structure for storing adapter information. The CSR is also memory 
+ * mapped in this routine.
+ *
+ * Returns :
+ *      true: if S/W was successfully initialized
+ *      false: otherwise
+ */
+static unsigned char __devinit
+e100_sw_init(struct e100_private *bdp)
+{
+	bdp->next_cu_cmd = START_WAIT;	// init the next cu state
+
+	/* 
+	 * Set the value for # of good xmits per underrun. the value assigned
+	 * here is an intelligent  suggested default. Nothing magical about it.
+	 */
+	bdp->tx_per_underrun = DEFAULT_TX_PER_UNDERRUN;
+
+	/* get the default transmit threshold value */
+	bdp->tx_thld = TX_THRSHLD;
+
+	/* get the EPROM size */
+	bdp->eeprom_size = e100_eeprom_size(bdp);
+
+	/* Initialize our spinlocks */
+	spin_lock_init(&(bdp->bd_lock));
+	spin_lock_init(&(bdp->bd_non_tx_lock));
+	spin_lock_init(&(bdp->config_lock));
+	spin_lock_init(&(bdp->mdi_access_lock));
+	bdp->isolate_lock = RW_LOCK_UNLOCKED;
+	bdp->driver_isolated = false;
+
+	return 1;
+}
+
+/**
+ * e100_hw_init - initialized tthe hardware
+ * @bdp: atapter's private data struct
+ * @reset_cmd: s/w reset or selective reset
+ *
+ * This routine performs a reset on the adapter, and configures the adapter.
+ * This includes configuring the 82557 LAN controller, validating and setting
+ * the node address, detecting and configuring the Phy chip on the adapter,
+ * and initializing all of the on chip counters.
+ *
+ * Returns:
+ *      true - If the adapter was initialized
+ *      false - If the adapter failed initialization
+ */
+unsigned char __devinit
+e100_hw_init(struct e100_private *bdp, u32 reset_cmd)
+{
+	if (!e100_phy_init(bdp))
+		return false;
+
+	/* Issue a software reset to the e100 */
+	e100_sw_reset(bdp, reset_cmd);
+
+	/* Load the CU BASE (set to 0, because we use linear mode) */
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE))
+		return false;
+
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE))
+		return false;
+
+	/* Load interrupt microcode  */
+	if (e100_load_microcode(bdp)) {
+		bdp->flags |= DF_UCODE_LOADED;
+	}
+
+	e100_config_init(bdp);
+	if (!e100_config(bdp)) {
+		return false;
+	}
+
+	if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr))
+		return false;
+
+	/* Clear the internal counters */
+	if (!e100_clr_cntrs(bdp))
+		return false;
+
+	/* Change for 82558 enhancement */
+	/* If 82558/9 and if the user has enabled flow control, set up the
+	 * Flow Control Reg. in the CSR */
+	if ((bdp->flags & IS_BACHELOR)
+	    && (bdp->params.b_params & PRM_FC)) {
+		writeb(DFLT_FC_THLD, &bdp->scb->scb_ext.d101_scb.scb_fc_thld);
+		writeb(DFLT_FC_CMD,
+		       &bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff);
+	}
+
+	return true;
+}
+
+/**
+ * e100_setup_tcb_pool - setup TCB circular list
+ * @head: Pointer to head of the allocated TCBs
+ * @qlen: Number of elements in the queue
+ * @bdp: atapter's private data struct
+ * 
+ * This routine arranges the contigiously allocated TCB's in a circular list.
+ * Also does the one time initialization of the TCBs.
+ */
+static void
+e100_setup_tcb_pool(tcb_t *head, unsigned int qlen, struct e100_private *bdp)
+{
+	int ele_no;
+	tcb_t *pcurr_tcb;	/* point to current tcb */
+	u32 next_phys;		/* the next phys addr */
+	u16 txcommand = CB_S_BIT | CB_TX_SF_BIT;
+
+	if (bdp->flags & USE_IPCB) {
+		txcommand |= CB_IPCB_TRANSMIT | CB_CID_DEFAULT;
+	} else if (bdp->flags & IS_BACHELOR) {
+		txcommand |= CB_TRANSMIT | CB_CID_DEFAULT;
+	} else {
+		txcommand |= CB_TRANSMIT;
+	}
+
+	for (ele_no = 0, next_phys = bdp->tcb_phys, pcurr_tcb = head;
+	     ele_no < qlen; ele_no++, pcurr_tcb++) {
+
+		/* set the phys addr for this TCB, next_phys has not incr. yet */
+		pcurr_tcb->tcb_phys = next_phys;
+		next_phys += sizeof (tcb_t);
+
+		/* set the link to next tcb */
+		if (ele_no == (qlen - 1))
+			pcurr_tcb->tcb_hdr.cb_lnk_ptr =
+				cpu_to_le32(bdp->tcb_phys);
+		else
+			pcurr_tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(next_phys);
+
+		pcurr_tcb->tcb_hdr.cb_status = 0;
+		pcurr_tcb->tcb_hdr.cb_cmd = cpu_to_le16(txcommand);
+		pcurr_tcb->tcb_cnt = 0;	
+		pcurr_tcb->tcb_thrshld = bdp->tx_thld;	
+		if (ele_no < 2) {
+			pcurr_tcb->tcb_hdr.cb_status =
+				cpu_to_le16(CB_STATUS_COMPLETE);
+		}
+		pcurr_tcb->tcb_tbd_num = 1;
+
+		if (bdp->flags & IS_BACHELOR) {
+			pcurr_tcb->tcb_tbd_ptr =
+				__constant_cpu_to_le32(0xFFFFFFFF);
+		} else {
+			pcurr_tcb->tcb_tbd_ptr =
+				cpu_to_le32(pcurr_tcb->tcb_phys + 0x10);
+		}
+
+		if (bdp->flags & IS_BACHELOR) {
+			pcurr_tcb->tcb_tbd_expand_ptr =
+				cpu_to_le32(pcurr_tcb->tcb_phys + 0x20);
+		} else {
+			pcurr_tcb->tcb_tbd_expand_ptr =
+				cpu_to_le32(pcurr_tcb->tcb_phys + 0x10);
+		}
+		pcurr_tcb->tcb_tbd_dflt_ptr = pcurr_tcb->tcb_tbd_ptr;
+
+		if (bdp->flags & USE_IPCB) {
+			pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[1]);
+			pcurr_tcb->tcbu.ipcb.ip_activation_high =
+				IPCB_IP_ACTIVATION_DEFAULT;
+			pcurr_tcb->tcbu.ipcb.vlan = 0;
+		} else {
+			pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[0]);
+		}
+
+		pcurr_tcb->tcb_skb = NULL;
+	}
+
+	wmb();
+}
+
+/***************************************************************************/
+/***************************************************************************/
+/*       Memory Management Routines                                        */
+/***************************************************************************/
+
+/**
+ * e100_alloc_space - allocate private driver data
+ * @bdp: atapter's private data struct
+ *
+ * This routine allocates memory for the driver. Memory allocated is for the
+ * selftest and statistics structures.
+ *
+ * Returns:
+ *      0: if the operation was successful
+ *      %-ENOMEM: if memory allocation failed
+ */
+unsigned char __devinit
+e100_alloc_space(struct e100_private *bdp)
+{
+	unsigned long off;
+
+	/* allocate all the dma-able structures in one call:
+	 * selftest results, adapter stats, and non-tx cb commands */
+	if (!(bdp->dma_able =
+	      pci_alloc_consistent(bdp->pdev, sizeof (bd_dma_able_t),
+				   &(bdp->dma_able_phys)))) {
+		goto err;
+	}
+
+	/* now assign the various pointers into the struct we've just allocated */
+	off = offsetof(bd_dma_able_t, selftest);
+
+	bdp->selftest = (self_test_t *) (bdp->dma_able + off);
+	bdp->selftest_phys = bdp->dma_able_phys + off;
+
+	off = offsetof(bd_dma_able_t, stats_counters);
+
+	bdp->stats_counters = (max_counters_t *) (bdp->dma_able + off);
+	bdp->stat_cnt_phys = bdp->dma_able_phys + off;
+
+	return 0;
+
+err:
+	printk(KERN_ERR
+	       "e100: Failed to allocate memory\n");
+	return -ENOMEM;
+}
+
+/**
+ * e100_alloc_tcb_pool - allocate TCB circular list
+ * @bdp: atapter's private data struct
+ *
+ * This routine allocates memory for the circular list of transmit descriptors.
+ *
+ * Returns:
+ *       0: if allocation has failed.
+ *       1: Otherwise. 
+ */
+int
+e100_alloc_tcb_pool(struct e100_private *bdp)
+{
+	int stcb = sizeof (tcb_t) * bdp->params.TxDescriptors;
+
+	/* allocate space for the TCBs */
+	if (!(bdp->tcb_pool.data =
+	      pci_alloc_consistent(bdp->pdev, stcb, &bdp->tcb_phys)))
+		return 0;
+
+	memset(bdp->tcb_pool.data, 0x00, stcb);
+
+	return 1;
+}
+
+void
+e100_free_tcb_pool(struct e100_private *bdp)
+{
+	pci_free_consistent(bdp->pdev,
+			    sizeof (tcb_t) * bdp->params.TxDescriptors,
+			    bdp->tcb_pool.data, bdp->tcb_phys);
+	bdp->tcb_phys = 0;
+}
+
+static void
+e100_dealloc_space(struct e100_private *bdp)
+{
+	if (bdp->dma_able) {
+		pci_free_consistent(bdp->pdev, sizeof (bd_dma_able_t),
+				    bdp->dma_able, bdp->dma_able_phys);
+	}
+
+	bdp->selftest_phys = 0;
+	bdp->stat_cnt_phys = 0;
+	bdp->dma_able_phys = 0;
+	bdp->dma_able = 0;
+}
+
+static void
+e100_free_rfd_pool(struct e100_private *bdp)
+{
+	struct rx_list_elem *rx_struct;
+
+	while (!list_empty(&(bdp->active_rx_list))) {
+
+		rx_struct = list_entry(bdp->active_rx_list.next,
+				       struct rx_list_elem, list_elem);
+		list_del(&(rx_struct->list_elem));
+		pci_unmap_single(bdp->pdev, rx_struct->dma_addr,
+				 sizeof (rfd_t), PCI_DMA_TODEVICE);
+		dev_kfree_skb(rx_struct->skb);
+		kfree(rx_struct);
+	}
+
+	while (!list_empty(&(bdp->rx_struct_pool))) {
+		rx_struct = list_entry(bdp->rx_struct_pool.next,
+				       struct rx_list_elem, list_elem);
+		list_del(&(rx_struct->list_elem));
+		kfree(rx_struct);
+	}
+}
+
+/**
+ * e100_alloc_rfd_pool - allocate RFDs
+ * @bdp: atapter's private data struct
+ *
+ * Allocates initial pool of skb which holds both rfd and data,
+ * and return a pointer to the head of the list
+ */
+static int
+e100_alloc_rfd_pool(struct e100_private *bdp)
+{
+	struct rx_list_elem *rx_struct;
+	int i;
+
+	INIT_LIST_HEAD(&(bdp->active_rx_list));
+	INIT_LIST_HEAD(&(bdp->rx_struct_pool));
+	bdp->skb_req = bdp->params.RxDescriptors;
+	for (i = 0; i < bdp->skb_req; i++) {
+		rx_struct = kmalloc(sizeof (struct rx_list_elem), GFP_ATOMIC);
+		list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool));
+	}
+	e100_alloc_skbs(bdp);
+	return !list_empty(&(bdp->active_rx_list));
+
+}
+
+void
+e100_clear_pools(struct e100_private *bdp)
+{
+	bdp->last_tcb = NULL;
+	e100_free_rfd_pool(bdp);
+	e100_free_tcb_pool(bdp);
+}
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*      Run Time Functions                                                   */
+/*****************************************************************************/
+
+/**
+ * e100_watchdog
+ * @dev: adapter's net_device struct
+ *
+ * This routine runs every 2 seconds and updates our statitics and link state,
+ * and refreshs txthld value.
+ */
+void
+e100_watchdog(struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+
+	read_lock(&(bdp->isolate_lock));
+	if (bdp->driver_isolated) {
+		goto exit;
+	}
+	if (!netif_running(dev)) {
+		goto exit;
+	}
+	e100_get_mdix_status(bdp);
+
+	/* check if link state has changed */
+	if (e100_phy_check(bdp)) {
+		if (netif_carrier_ok(dev)) {
+			printk(KERN_ERR
+			       "e100: %s NIC Link is Up %d Mbps %s duplex\n",
+			       bdp->device->name, bdp->cur_line_speed,
+			       (bdp->cur_dplx_mode == HALF_DUPLEX) ?
+			       "Half" : "Full");
+
+			e100_config_fc(bdp);
+			e100_config(bdp);  
+			bdp->cable_status = "Cable OK";
+
+		} else {
+			printk(KERN_ERR "e100: %s NIC Link is Down\n",
+			       bdp->device->name);
+                	if (bdp->rev_id < D102_REV_ID)
+				bdp->cable_status = "Not supported";
+		        else {				
+				/* Initiate hwi, ie, cable diagnostic */
+				bdp->saved_open_circut = 0xffff;
+				bdp->saved_short_circut = 0xffff;
+				bdp->saved_distance = 0xffff;
+				bdp->saved_i = 0;
+				bdp->saved_same = 0;
+				bdp->hwi_started = 1;
+				
+				/* Disable MDI/MDI-X auto switching */
+                		e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
+		                	MDI_MDIX_RESET_ALL_MASK);
+
+				/* Set to 100 Full as required by hwi test */
+				e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
+				       BMCR_SPEED100 | BMCR_FULLDPLX);
+
+				/* Enable and execute HWI test */
+				e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,
+					(HWI_TEST_ENABLE | HWI_TEST_EXECUTE));
+
+				/* Launch hwi timer in 1 msec */
+				mod_timer(&(bdp->hwi_timer), jiffies + (HZ / 1000) );
+			}
+		}
+	}
+
+	// toggle the tx queue according to link status
+	// this also resolves a race condition between tx & non-cu cmd flows
+	if (netif_carrier_ok(dev)) {
+		if (netif_running(dev))
+			netif_wake_queue(dev);
+	} else {
+		netif_stop_queue(dev);
+	}
+
+	rmb();
+
+	if (e100_update_stats(bdp)) {
+
+		/* Check if a change in the IFS parameter is needed,
+		   and configure the device accordingly */
+		if (bdp->params.b_params & PRM_IFS)
+			e100_manage_adaptive_ifs(bdp);
+
+		/* Now adjust our dynamic tx threshold value */
+		e100_refresh_txthld(bdp);
+
+		/* Now if we are on a 557 and we havn't received any frames then we
+		 * should issue a multicast command to reset the RU */
+		if (bdp->rev_id < D101A4_REV_ID) {
+			if (!(bdp->stats_counters->basic_stats.rcv_gd_frames)) {
+				e100_set_multi(dev);
+			}
+		}
+
+		/* Update the statistics needed by the upper interface */
+		/* This should be the last statistic related command
+		 * as it's async. now */
+		e100_dump_stats_cntrs(bdp);
+	}
+
+	wmb();
+
+	/* relaunch watchdog timer in 2 sec */
+	mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ));
+
+	if (list_empty(&bdp->active_rx_list))
+		e100_trigger_SWI(bdp);
+
+exit:
+	read_unlock(&(bdp->isolate_lock));
+}
+
+/**
+ * e100_manage_adaptive_ifs
+ * @bdp: atapter's private data struct
+ *
+ * This routine manages the adaptive Inter-Frame Spacing algorithm
+ * using a state machine.
+ */
+void
+e100_manage_adaptive_ifs(struct e100_private *bdp)
+{
+	static u16 state_table[9][4] = {	// rows are states
+		{2, 0, 0, 0},	// state0   // column0: next state if increasing
+		{2, 0, 5, 30},	// state1   // column1: next state if decreasing
+		{5, 1, 5, 30},	// state2   // column2: IFS value for 100 mbit
+		{5, 3, 0, 0},	// state3   // column3: IFS value for 10 mbit
+		{5, 3, 10, 60},	// state4
+		{8, 4, 10, 60},	// state5
+		{8, 6, 0, 0},	// state6
+		{8, 6, 20, 60},	// state7
+		{8, 7, 20, 60}	// state8
+	};
+
+	u32 transmits =
+		le32_to_cpu(bdp->stats_counters->basic_stats.xmt_gd_frames);
+	u32 collisions =
+		le32_to_cpu(bdp->stats_counters->basic_stats.xmt_ttl_coll);
+	u32 state = bdp->ifs_state;
+	u32 old_value = bdp->ifs_value;
+	int next_col;
+	u32 min_transmits;
+
+	if (bdp->cur_dplx_mode == FULL_DUPLEX) {
+		bdp->ifs_state = 0;
+		bdp->ifs_value = 0;
+
+	} else {		/* Half Duplex */
+		/* Set speed specific parameters */
+		if (bdp->cur_line_speed == 100) {
+			next_col = 2;
+			min_transmits = MIN_NUMBER_OF_TRANSMITS_100;
+
+		} else {	/* 10 Mbps */
+			next_col = 3;
+			min_transmits = MIN_NUMBER_OF_TRANSMITS_10;
+		}
+
+		if ((transmits / 32 < collisions)
+		    && (transmits > min_transmits)) {
+			state = state_table[state][0];	/* increment */
+
+		} else if (transmits < min_transmits) {
+			state = state_table[state][1];	/* decrement */
+		}
+
+		bdp->ifs_value = state_table[state][next_col];
+		bdp->ifs_state = state;
+	}
+
+	/* If the IFS value has changed, configure the device */
+	if (bdp->ifs_value != old_value) {
+		e100_config_ifs(bdp);
+		e100_config(bdp);
+	}
+}
+
+/**
+ * e100intr - interrupt handler
+ * @irq: the IRQ number
+ * @dev_inst: the net_device struct
+ * @regs: registers (unused)
+ *
+ * This routine is the ISR for the e100 board. It services
+ * the RX & TX queues & starts the RU if it has stopped due
+ * to no resources.
+ */
+void
+e100intr(int irq, void *dev_inst, struct pt_regs *regs)
+{
+	struct net_device *dev;
+	struct e100_private *bdp;
+	u16 intr_status;
+
+	dev = dev_inst;
+	bdp = dev->priv;
+
+	intr_status = readw(&bdp->scb->scb_status);
+	if (!intr_status || (intr_status == 0xffff)) {
+		return;
+	}
+
+	/* disable intr before we ack & after identifying the intr as ours */
+	e100_dis_intr(bdp);
+
+	writew(intr_status, &bdp->scb->scb_status);	/* ack intrs */
+	readw(&bdp->scb->scb_status);
+
+	/* the device is closed, don't continue or else bad things may happen. */
+	if (!netif_running(dev)) {
+		e100_set_intr_mask(bdp);
+		return;
+	}
+
+	read_lock(&(bdp->isolate_lock));
+	if (bdp->driver_isolated) {
+		goto exit;
+	}
+
+	/* SWI intr (triggered by watchdog) is signal to allocate new skb buffers */
+	if (intr_status & SCB_STATUS_ACK_SWI) {
+		e100_alloc_skbs(bdp);
+	}
+
+	/* do recv work if any */
+	if (intr_status &
+	    (SCB_STATUS_ACK_FR | SCB_STATUS_ACK_RNR | SCB_STATUS_ACK_SWI)) 
+		bdp->drv_stats.rx_intr_pkts += e100_rx_srv(bdp);
+
+	/* clean up after tx'ed packets */
+	if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX)) {
+		bdp->tx_count = 0;	/* restart tx interrupt batch count */
+		e100_tx_srv(bdp);
+	}
+
+exit:
+	e100_set_intr_mask(bdp);
+	read_unlock(&(bdp->isolate_lock));
+}
+
+/**
+ * e100_tx_skb_free - free TX skbs resources
+ * @bdp: atapter's private data struct
+ * @tcb: associated tcb of the freed skb
+ *
+ * This routine frees resources of TX skbs.
+ */
+static void inline
+e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb)
+{
+	if (tcb->tcb_skb) {
+		int i;
+		tbd_t *tbd_arr = tcb->tbd_ptr;
+		int frags = skb_shinfo(tcb->tcb_skb)->nr_frags;
+
+		for (i = 0; i <= frags; i++, tbd_arr++) {
+			pci_unmap_single(bdp->pdev,
+					 le32_to_cpu(tbd_arr->tbd_buf_addr),
+					 le16_to_cpu(tbd_arr->tbd_buf_cnt),
+					 PCI_DMA_TODEVICE);
+		}
+		dev_kfree_skb_irq(tcb->tcb_skb);
+		tcb->tcb_skb = NULL;
+	}
+}
+
+/**
+ * e100_tx_srv - service TX queues
+ * @bdp: atapter's private data struct
+ *
+ * This routine services the TX queues. It reclaims the TCB's & TBD's & other
+ * resources used during the transmit of this buffer. It is called from the ISR.
+ * We don't need a tx_lock since we always access buffers which were already
+ * prepared.
+ */
+void
+e100_tx_srv(struct e100_private *bdp)
+{
+	tcb_t *tcb;
+	int i;
+
+	/* go over at most TxDescriptors buffers */
+	for (i = 0; i < bdp->params.TxDescriptors; i++) {
+		tcb = bdp->tcb_pool.data;
+		tcb += bdp->tcb_pool.head;
+
+		rmb();
+
+		/* if the buffer at 'head' is not complete, break */
+		if (!(tcb->tcb_hdr.cb_status &
+		      __constant_cpu_to_le16(CB_STATUS_COMPLETE)))
+			break;
+
+		/* service next buffer, clear the out of resource condition */
+		e100_tx_skb_free(bdp, tcb);
+
+		if (netif_running(bdp->device))
+			netif_wake_queue(bdp->device);
+
+		/* if we've caught up with 'tail', break */
+		if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail) {
+			break;
+		}
+
+		bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head);
+	}
+}
+
+/**
+ * e100_rx_srv - service RX queue
+ * @bdp: atapter's private data struct
+ * @max_number_of_rfds: max number of RFDs to process
+ * @rx_congestion: flag pointer, to inform the calling function of congestion.
+ *
+ * This routine processes the RX interrupt & services the RX queues.
+ * For each successful RFD, it allocates a new msg block, links that
+ * into the RFD list, and sends the old msg upstream.
+ * The new RFD is then put at the end of the free list of RFD's.
+ * It returns the number of serviced RFDs.
+ */
+u32
+e100_rx_srv(struct e100_private *bdp)
+{
+	rfd_t *rfd;		/* new rfd, received rfd */
+	int i;
+	u16 rfd_status;
+	struct sk_buff *skb;
+	struct net_device *dev;
+	unsigned int data_sz;
+	struct rx_list_elem *rx_struct;
+	u32 rfd_cnt = 0;
+
+	dev = bdp->device;
+
+	/* current design of rx is as following:
+	 * 1. socket buffer (skb) used to pass network packet to upper layer
+	 * 2. all HW host memory structures (like RFDs, RBDs and data buffers)
+	 *    are placed in a skb's data room
+	 * 3. when rx process is complete, we change skb internal pointers to exclude
+	 *    from data area all unrelated things (RFD, RDB) and to leave
+	 *    just rx'ed packet netto
+	 * 4. for each skb passed to upper layer, new one is allocated instead.
+	 * 5. if no skb left, in 2 sec another atempt to allocate skbs will be made
+	 *    (watchdog trigger SWI intr and isr should allocate new skbs)
+	 */
+	for (i = 0; i < bdp->params.RxDescriptors; i++) {
+		if (list_empty(&(bdp->active_rx_list))) {
+			break;
+		}
+
+		rx_struct = list_entry(bdp->active_rx_list.next,
+				       struct rx_list_elem, list_elem);
+		skb = rx_struct->skb;
+
+		rfd = RFD_POINTER(skb, bdp);	/* locate RFD within skb */
+
+		// sync only the RFD header
+		pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr,
+				    bdp->rfd_size, PCI_DMA_FROMDEVICE);
+		rfd_status = le16_to_cpu(rfd->rfd_header.cb_status);	/* get RFD's status */
+		if (!(rfd_status & RFD_STATUS_COMPLETE))	/* does not contains data yet - exit */
+			break;
+
+		/* to allow manipulation with current skb we need to unlink it */
+		list_del(&(rx_struct->list_elem));
+
+		/* do not free & unmap badly recieved packet.
+		 * move it to the end of skb list for reuse */
+		if (!(rfd_status & RFD_STATUS_OK)) {
+			e100_add_skb_to_end(bdp, rx_struct);
+			continue;
+		}
+
+		data_sz = min_t(u16, (le16_to_cpu(rfd->rfd_act_cnt) & 0x3fff),
+				(sizeof (rfd_t) - bdp->rfd_size));
+
+		/* now sync all the data */
+		pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr,
+				    (data_sz + bdp->rfd_size),
+				    PCI_DMA_FROMDEVICE);
+
+		pci_unmap_single(bdp->pdev, rx_struct->dma_addr,
+				 sizeof (rfd_t), PCI_DMA_FROMDEVICE);
+
+		list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool));
+
+		/* end of dma access to rfd */
+		bdp->skb_req++;	/* incr number of requested skbs */
+		e100_alloc_skbs(bdp);	/* and get them */
+
+		/* set packet size, excluding checksum (2 last bytes) if it is present */
+		if ((bdp->flags & DF_CSUM_OFFLOAD)
+		    && (bdp->rev_id < D102_REV_ID))
+			skb_put(skb, (int) data_sz - 2);
+		else
+			skb_put(skb, (int) data_sz);
+
+		/* set the protocol */
+		skb->protocol = eth_type_trans(skb, dev);
+
+		/* set the checksum info */
+		if (bdp->flags & DF_CSUM_OFFLOAD) {
+			if (bdp->rev_id >= D102_REV_ID) {
+				skb->ip_summed = e100_D102_check_checksum(rfd);
+			} else {
+				skb->ip_summed = e100_D101M_checksum(bdp, skb);
+			}
+		} else {
+			skb->ip_summed = CHECKSUM_NONE;
+		}
+		switch (netif_rx(skb)) {
+		case NET_RX_BAD:
+		case NET_RX_DROP:
+		case NET_RX_CN_MOD:
+		case NET_RX_CN_HIGH:
+			break;
+		default:
+			bdp->drv_stats.net_stats.rx_bytes += skb->len;
+			break;
+		}
+
+		rfd_cnt++;
+	}			/* end of rfd loop */
+
+	/* restart the RU if it has stopped */
+	if ((readw(&bdp->scb->scb_status) & SCB_RUS_MASK) != SCB_RUS_READY) {
+		e100_start_ru(bdp);
+	}
+
+	return rfd_cnt;
+}
+
+void
+e100_refresh_txthld(struct e100_private *bdp)
+{
+	basic_cntr_t *pstat = &(bdp->stats_counters->basic_stats);
+
+	/* as long as tx_per_underrun is not 0, we can go about dynamically *
+	 * adjusting the xmit threshold. we stop doing that & resort to defaults
+	 * * once the adjustments become meaningless. the value is adjusted by *
+	 * dumping the error counters & checking the # of xmit underrun errors *
+	 * we've had. */
+	if (bdp->tx_per_underrun) {
+		/* We are going to last values dumped from the dump statistics
+		 * command */
+		if (le32_to_cpu(pstat->xmt_gd_frames)) {
+			if (le32_to_cpu(pstat->xmt_uruns)) {
+				/* 
+				 * if we have had more than one underrun per "DEFAULT #
+				 * OF XMITS ALLOWED PER UNDERRUN" good xmits, raise the
+				 * THRESHOLD.
+				 */
+				if ((le32_to_cpu(pstat->xmt_gd_frames) /
+				     le32_to_cpu(pstat->xmt_uruns)) <
+				    bdp->tx_per_underrun) {
+					bdp->tx_thld += 3;
+				}
+			}
+
+			/* 
+			 * if we've had less than one underrun per the DEFAULT number of
+			 * of good xmits allowed, lower the THOLD but not less than 0 
+			 */
+			if (le32_to_cpu(pstat->xmt_gd_frames) >
+			    bdp->tx_per_underrun) {
+				bdp->tx_thld--;
+
+				if (bdp->tx_thld < 6)
+					bdp->tx_thld = 6;
+
+			}
+		}
+
+		/* end good xmits */
+		/* 
+		 * * if our adjustments are becoming unresonable, stop adjusting &
+		 * resort * to defaults & pray. A THOLD value > 190 means that the
+		 * adapter will * wait for 190*8=1520 bytes in TX FIFO before it
+		 * starts xmit. Since * MTU is 1514, it doesn't make any sense for
+		 * further increase. */
+		if (bdp->tx_thld >= 190) {
+			bdp->tx_per_underrun = 0;
+			bdp->tx_thld = 189;
+		}
+	}			/* end underrun check */
+}
+
+/**
+ * e100_pseudo_hdr_csum - compute IP pseudo-header checksum
+ * @ip: points to the header of the IP packet
+ *
+ * Return the 16 bit checksum of the IP pseudo-header.,which is computed
+ * on the fields: IP src, IP dst, next protocol, payload length.
+ * The checksum vaule is returned in network byte order.
+ */
+static inline u16
+e100_pseudo_hdr_csum(const struct iphdr *ip)
+{
+	u32 pseudo = 0;
+	u32 payload_len = 0;
+
+	payload_len = ntohs(ip->tot_len) - (ip->ihl * 4);
+
+	pseudo += htons(payload_len);
+	pseudo += (ip->protocol << 8);
+	pseudo += ip->saddr & 0x0000ffff;
+	pseudo += (ip->saddr & 0xffff0000) >> 16;
+	pseudo += ip->daddr & 0x0000ffff;
+	pseudo += (ip->daddr & 0xffff0000) >> 16;
+
+	return FOLD_CSUM(pseudo);
+}
+
+/**
+ * e100_prepare_xmit_buff - prepare a buffer for transmission
+ * @bdp: atapter's private data struct
+ * @skb: skb to send
+ *
+ * This routine prepare a buffer for transmission. It checks
+ * the message length for the appropiate size. It picks up a
+ * free tcb from the TCB pool and sets up the corresponding
+ * TBD's. If the number of fragments are more than the number
+ * of TBD/TCB it copies all the fragments in a coalesce buffer.
+ * It returns a pointer to the prepared TCB.
+ */
+static inline tcb_t *
+e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb)
+{
+	tcb_t *tcb, *prev_tcb;
+
+	tcb = bdp->tcb_pool.data;
+	tcb += TCB_TO_USE(bdp->tcb_pool);
+
+	if (bdp->flags & USE_IPCB) {
+		tcb->tcbu.ipcb.ip_activation_high = IPCB_IP_ACTIVATION_DEFAULT;
+		tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCP_PACKET;
+		tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCPUDP_CHECKSUM_ENABLE;
+	}
+
+	tcb->tcb_hdr.cb_status = 0;
+	tcb->tcb_thrshld = bdp->tx_thld;
+	tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT);
+
+	/* set the I bit on the modulo tcbs, so we will get an interrupt * to
+	 * clean things up */
+	if (!(++bdp->tx_count % TX_FRAME_CNT)) {
+		tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_I_BIT);
+	}
+
+	tcb->tcb_skb = skb;
+
+	if (skb->ip_summed == CHECKSUM_HW) {
+		const struct iphdr *ip = skb->nh.iph;
+
+		if ((ip->protocol == IPPROTO_TCP) ||
+		    (ip->protocol == IPPROTO_UDP)) {
+			u16 *chksum;
+
+			tcb->tcbu.ipcb.ip_activation_high =
+				IPCB_HARDWAREPARSING_ENABLE;
+			tcb->tcbu.ipcb.ip_schedule |=
+				IPCB_TCPUDP_CHECKSUM_ENABLE;
+
+			if (ip->protocol == IPPROTO_TCP) {
+				struct tcphdr *tcp;
+
+				tcp = (struct tcphdr *) ((u32 *) ip + ip->ihl);
+				chksum = &(tcp->check);
+				tcb->tcbu.ipcb.ip_schedule |= IPCB_TCP_PACKET;
+			} else {
+				struct udphdr *udp;
+
+				udp = (struct udphdr *) ((u32 *) ip + ip->ihl);
+				chksum = &(udp->check);
+			}
+
+			*chksum = e100_pseudo_hdr_csum(ip);
+		}
+	}
+
+	if (!skb_shinfo(skb)->nr_frags) {
+		(tcb->tbd_ptr)->tbd_buf_addr =
+			cpu_to_le32(pci_map_single(bdp->pdev, skb->data,
+						   skb->len, PCI_DMA_TODEVICE));
+		(tcb->tbd_ptr)->tbd_buf_cnt = cpu_to_le16(skb->len);
+		tcb->tcb_tbd_num = 1;
+		tcb->tcb_tbd_ptr = tcb->tcb_tbd_dflt_ptr;
+	} else {
+		int i;
+		void *addr;
+		tbd_t *tbd_arr_ptr = &(tcb->tbd_ptr[1]);
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[0];
+
+		(tcb->tbd_ptr)->tbd_buf_addr =
+			cpu_to_le32(pci_map_single(bdp->pdev, skb->data,
+						   (skb->len - skb->data_len),
+						   PCI_DMA_TODEVICE));
+		(tcb->tbd_ptr)->tbd_buf_cnt =
+			cpu_to_le16(skb->len - skb->data_len);
+
+		for (i = 0; i < skb_shinfo(skb)->nr_frags;
+		     i++, tbd_arr_ptr++, frag++) {
+
+			addr = ((void *) page_address(frag->page) +
+				frag->page_offset);
+
+			tbd_arr_ptr->tbd_buf_addr =
+				cpu_to_le32(pci_map_single(bdp->pdev,
+							   addr, frag->size,
+							   PCI_DMA_TODEVICE));
+			tbd_arr_ptr->tbd_buf_cnt = cpu_to_le16(frag->size);
+		}
+		tcb->tcb_tbd_num = skb_shinfo(skb)->nr_frags + 1;
+		tcb->tcb_tbd_ptr = tcb->tcb_tbd_expand_ptr;
+	}
+
+	/* clear the S-BIT on the previous tcb */
+	prev_tcb = bdp->tcb_pool.data;
+	prev_tcb += PREV_TCB_USED(bdp->tcb_pool);
+	prev_tcb->tcb_hdr.cb_cmd &= __constant_cpu_to_le16((u16) ~CB_S_BIT);
+
+	bdp->tcb_pool.tail = NEXT_TCB_TOUSE(bdp->tcb_pool.tail);
+
+	wmb();
+
+	e100_start_cu(bdp, tcb);
+
+	return tcb;
+}
+
+/* Changed for 82558 enhancement */
+/**
+ * e100_start_cu - start the adapter's CU
+ * @bdp: atapter's private data struct
+ * @tcb: TCB to be transmitted
+ *
+ * This routine issues a CU Start or CU Resume command to the 82558/9.
+ * This routine was added because the prepare_ext_xmit_buff takes advantage
+ * of the 82558/9's Dynamic TBD chaining feature and has to start the CU as
+ * soon as the first TBD is ready. 
+ *
+ * e100_start_cu must be called while holding the tx_lock ! 
+ */
+void
+e100_start_cu(struct e100_private *bdp, tcb_t *tcb)
+{
+	unsigned long lock_flag;
+
+	spin_lock_irqsave(&(bdp->bd_lock), lock_flag);
+	switch (bdp->next_cu_cmd) {
+	case RESUME_NO_WAIT:
+		/*last cu command was a CU_RESMUE if this is a 558 or newer we dont need to
+		 * wait for command word to clear, we reach here only if we are bachlor
+		 */
+		e100_exec_cmd(bdp, SCB_CUC_RESUME);
+		break;
+
+	case RESUME_WAIT:
+		if ((bdp->flags & IS_ICH) &&
+		    (bdp->cur_line_speed == 10) &&
+		    (bdp->cur_dplx_mode == HALF_DUPLEX)) {
+			e100_wait_exec_simple(bdp, SCB_CUC_NOOP);
+			udelay(1);
+		}
+		if ((e100_wait_exec_simple(bdp, SCB_CUC_RESUME)) &&
+		    (bdp->flags & IS_BACHELOR) && (!(bdp->flags & IS_ICH))) {
+			bdp->next_cu_cmd = RESUME_NO_WAIT;
+		}
+		break;
+
+	case START_WAIT:
+		// The last command was a non_tx CU command
+		if (!e100_wait_cus_idle(bdp))
+			printk(KERN_DEBUG
+			       "e100: %s: cu_start: timeout waiting for cu\n",
+			       bdp->device->name);
+		if (!e100_wait_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
+					  SCB_CUC_START)) {
+			printk(KERN_DEBUG
+			       "e100: %s: cu_start: timeout waiting for scb\n",
+			       bdp->device->name);
+			e100_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
+					SCB_CUC_START);
+		}
+
+		bdp->next_cu_cmd = RESUME_WAIT;
+
+		break;
+	}
+
+	/* save the last tcb */
+	bdp->last_tcb = tcb;
+
+	spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
+}
+
+/* ====================================================================== */
+/* hw                                                                     */
+/* ====================================================================== */
+
+/**
+ * e100_selftest - perform H/W self test
+ * @bdp: atapter's private data struct
+ * @st_timeout: address to return timeout value, if fails
+ * @st_result: address to return selftest result, if fails
+ *
+ * This routine will issue PORT Self-test command to test the e100.
+ * The self-test will fail if the adapter's master-enable bit is not
+ * set in the PCI Command Register, or if the adapter is not seated
+ * in a PCI master-enabled slot. we also disable interrupts when the
+ * command is completed.
+ *
+ * Returns:
+ *      true: if adapter passes self_test
+ *      false: otherwise
+ */
+unsigned char
+e100_selftest(struct e100_private *bdp, u32 *st_timeout, u32 *st_result)
+{
+	u32 selftest_cmd;
+
+	/* initialize the nic state before running test */
+	e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
+	/* Setup the address of the self_test area */
+	selftest_cmd = bdp->selftest_phys;
+
+	/* Setup SELF TEST Command Code in D3 - D0 */
+	selftest_cmd |= PORT_SELFTEST;
+
+	/* Initialize the self-test signature and results DWORDS */
+	bdp->selftest->st_sign = 0;
+	bdp->selftest->st_result = 0xffffffff;
+
+	/* Do the port command */
+	writel(selftest_cmd, &bdp->scb->scb_port);
+	readw(&(bdp->scb->scb_status));	/* flushes last write, read-safe */
+
+	/* Wait at least 10 milliseconds for the self-test to complete */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ / 100 + 1);
+
+	/* disable interrupts since the're now enabled */
+	e100_dis_intr(bdp);
+
+	/* if The First Self Test DWORD Still Zero, We've timed out. If the
+	 * second DWORD is not zero then we have an error. */
+	if ((bdp->selftest->st_sign == 0) || (bdp->selftest->st_result != 0)) {
+
+		if (st_timeout)
+			*st_timeout = !(le32_to_cpu(bdp->selftest->st_sign));
+
+		if (st_result)
+			*st_result = le32_to_cpu(bdp->selftest->st_result);
+
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * e100_setup_iaaddr - issue IA setup sommand
+ * @bdp: atapter's private data struct
+ * @eaddr: new ethernet address
+ *
+ * This routine will issue the IA setup command. This command
+ * will notify the 82557 (e100) of what its individual (node)
+ * address is. This command will be executed in polled mode.
+ *
+ * Returns:
+ *      true: if the IA setup command was successfully issued and completed
+ *      false: otherwise
+ */
+unsigned char
+e100_setup_iaaddr(struct e100_private *bdp, u8 *eaddr)
+{
+	unsigned int i;
+	cb_header_t *ntcb_hdr;
+	unsigned char res;
+	nxmit_cb_entry_t *cmd;
+
+	if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) {
+		res = false;
+		goto exit;
+	}
+
+	ntcb_hdr = (cb_header_t *) cmd->non_tx_cmd;
+	ntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_IA_ADDRESS);
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		(cmd->non_tx_cmd)->ntcb.setup.ia_addr[i] = eaddr[i];
+	}
+
+	res = e100_exec_non_cu_cmd(bdp, cmd);
+	if (!res)
+		printk(KERN_WARNING "e100: %s: IA setup failed\n", 
+		       bdp->device->name);
+
+exit:
+	return res;
+}
+
+/**
+ * e100_start_ru - start the RU if needed
+ * @bdp: atapter's private data struct
+ *
+ * This routine checks the status of the 82557's receive unit(RU),
+ * and starts the RU if it was not already active.  However,
+ * before restarting the RU, the driver gives the RU the buffers
+ * it freed up during the servicing of the ISR. If there are
+ * no free buffers to give to the RU, (i.e. we have reached a
+ * no resource condition) the RU will not be started till the
+ * next ISR.
+ */
+void
+e100_start_ru(struct e100_private *bdp)
+{
+	struct rx_list_elem *rx_struct = NULL;
+	int buffer_found = 0;
+	struct list_head *entry_ptr;
+
+	list_for_each(entry_ptr, &(bdp->active_rx_list)) {
+		rx_struct =
+			list_entry(entry_ptr, struct rx_list_elem, list_elem);
+		pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr,
+				    bdp->rfd_size, PCI_DMA_FROMDEVICE);
+		if (!((SKB_RFD_STATUS(rx_struct->skb, bdp) &
+		       __constant_cpu_to_le16(RFD_STATUS_COMPLETE)))) {
+			buffer_found = 1;
+			break;
+		}
+	}
+
+	/* No available buffers */
+	if (!buffer_found) {
+		return;
+	}
+
+	spin_lock(&bdp->bd_lock);
+
+	if (!e100_wait_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START)) {
+		printk(KERN_DEBUG
+		       "e100: %s: start_ru: wait_scb failed\n", 
+		       bdp->device->name);
+		e100_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START);
+	}
+	if (bdp->next_cu_cmd == RESUME_NO_WAIT) {
+		bdp->next_cu_cmd = RESUME_WAIT;
+	}
+	spin_unlock(&bdp->bd_lock);
+}
+
+/**
+ * e100_cmd_complete_location
+ * @bdp: atapter's private data struct
+ *
+ * This routine returns a pointer to the location of the command-complete
+ * DWord in the dump statistical counters area, according to the statistical
+ * counters mode (557 - basic, 558 - extended, or 559 - TCO mode).
+ * See e100_config_init() for the setting of the statistical counters mode.
+ */
+static u32 *
+e100_cmd_complete_location(struct e100_private *bdp)
+{
+	u32 *cmd_complete;
+	max_counters_t *stats = bdp->stats_counters;
+
+	switch (bdp->stat_mode) {
+	case E100_EXTENDED_STATS:
+		cmd_complete =
+			(u32 *) &(((err_cntr_558_t *) (stats))->cmd_complete);
+		break;
+
+	case E100_TCO_STATS:
+		cmd_complete =
+			(u32 *) &(((err_cntr_559_t *) (stats))->cmd_complete);
+		break;
+
+	case E100_BASIC_STATS:
+	default:		
+		cmd_complete =
+			(u32 *) &(((err_cntr_557_t *) (stats))->cmd_complete);
+		break;
+	}
+
+	return cmd_complete;
+}
+
+/**
+ * e100_clr_cntrs - clear statistics counters
+ * @bdp: atapter's private data struct
+ *
+ * This routine will clear the adapter error statistic counters.
+ *
+ * Returns:
+ *      true: if successfully cleared stat counters
+ *      false: otherwise
+ */
+static unsigned char __devinit
+e100_clr_cntrs(struct e100_private *bdp)
+{
+	volatile u32 *pcmd_complete;
+
+	/* clear the dump counter complete word */
+	pcmd_complete = e100_cmd_complete_location(bdp);
+	*pcmd_complete = 0;
+	wmb();
+
+	if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR))
+		return false;
+
+	/* wait 10 microseconds for the command to complete */
+	udelay(10);
+
+	if (!e100_wait_exec_simple(bdp, SCB_CUC_DUMP_RST_STAT))
+		return false;
+
+	if (bdp->next_cu_cmd == RESUME_NO_WAIT) {
+		bdp->next_cu_cmd = RESUME_WAIT;
+	}
+
+	return true;
+}
+
+static unsigned char
+e100_update_stats(struct e100_private *bdp)
+{
+	u32 *pcmd_complete;
+	basic_cntr_t *pstat = &(bdp->stats_counters->basic_stats);
+
+	// check if last dump command completed
+	pcmd_complete = e100_cmd_complete_location(bdp);
+	if (*pcmd_complete != le32_to_cpu(DUMP_RST_STAT_COMPLETED) &&
+	    *pcmd_complete != le32_to_cpu(DUMP_STAT_COMPLETED)) {
+		return false;
+	}
+
+	/* increment the statistics */
+	bdp->drv_stats.net_stats.rx_packets +=
+		le32_to_cpu(pstat->rcv_gd_frames);
+	bdp->drv_stats.net_stats.tx_packets +=
+		le32_to_cpu(pstat->xmt_gd_frames);
+	bdp->drv_stats.net_stats.rx_dropped += le32_to_cpu(pstat->rcv_rsrc_err);
+	bdp->drv_stats.net_stats.collisions += le32_to_cpu(pstat->xmt_ttl_coll);
+	bdp->drv_stats.net_stats.rx_length_errors +=
+		le32_to_cpu(pstat->rcv_shrt_frames);
+	bdp->drv_stats.net_stats.rx_over_errors +=
+		le32_to_cpu(pstat->rcv_rsrc_err);
+	bdp->drv_stats.net_stats.rx_crc_errors +=
+		le32_to_cpu(pstat->rcv_crc_errs);
+	bdp->drv_stats.net_stats.rx_frame_errors +=
+		le32_to_cpu(pstat->rcv_algn_errs);
+	bdp->drv_stats.net_stats.rx_fifo_errors +=
+		le32_to_cpu(pstat->rcv_oruns);
+	bdp->drv_stats.net_stats.tx_aborted_errors +=
+		le32_to_cpu(pstat->xmt_max_coll);
+	bdp->drv_stats.net_stats.tx_carrier_errors +=
+		le32_to_cpu(pstat->xmt_lost_crs);
+	bdp->drv_stats.net_stats.tx_fifo_errors +=
+		le32_to_cpu(pstat->xmt_uruns);
+
+	bdp->drv_stats.tx_late_col += le32_to_cpu(pstat->xmt_late_coll);
+	bdp->drv_stats.tx_ok_defrd += le32_to_cpu(pstat->xmt_deferred);
+	bdp->drv_stats.tx_one_retry += le32_to_cpu(pstat->xmt_sngl_coll);
+	bdp->drv_stats.tx_mt_one_retry += le32_to_cpu(pstat->xmt_mlt_coll);
+	bdp->drv_stats.rcv_cdt_frames += le32_to_cpu(pstat->rcv_err_coll);
+
+	if (bdp->stat_mode != E100_BASIC_STATS) {
+		ext_cntr_t *pex_stat = &bdp->stats_counters->extended_stats;
+
+		bdp->drv_stats.xmt_fc_pkts +=
+			le32_to_cpu(pex_stat->xmt_fc_frames);
+		bdp->drv_stats.rcv_fc_pkts +=
+			le32_to_cpu(pex_stat->rcv_fc_frames);
+		bdp->drv_stats.rcv_fc_unsupported +=
+			le32_to_cpu(pex_stat->rcv_fc_unsupported);
+	}
+
+	if (bdp->stat_mode == E100_TCO_STATS) {
+		tco_cntr_t *ptco_stat = &bdp->stats_counters->tco_stats;
+
+		bdp->drv_stats.xmt_tco_pkts +=
+			le16_to_cpu(ptco_stat->xmt_tco_frames);
+		bdp->drv_stats.rcv_tco_pkts +=
+			le16_to_cpu(ptco_stat->rcv_tco_frames);
+	}
+
+	*pcmd_complete = 0;
+	return true;
+}
+
+/**
+ * e100_dump_stat_cntrs
+ * @bdp: atapter's private data struct
+ *
+ * This routine will dump the board statistical counters without waiting
+ * for stat_dump to complete. Any access to this stats should verify the completion
+ * of the command
+ */
+void
+e100_dump_stats_cntrs(struct e100_private *bdp)
+{
+	unsigned long lock_flag_bd;
+
+	spin_lock_irqsave(&(bdp->bd_lock), lock_flag_bd);
+
+	/* dump h/w stats counters */
+	if (e100_wait_exec_simple(bdp, SCB_CUC_DUMP_RST_STAT)) {
+		if (bdp->next_cu_cmd == RESUME_NO_WAIT) {
+			bdp->next_cu_cmd = RESUME_WAIT;
+		}
+	}
+
+	spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag_bd);
+}
+
+/**
+ * e100_exec_non_cu_cmd
+ * @bdp: atapter's private data struct
+ * @command: the non-cu command to execute
+ *
+ * This routine will submit a command block to be executed,
+ */
+unsigned char
+e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command)
+{
+	cb_header_t *ntcb_hdr;
+	unsigned long lock_flag;
+	unsigned long expiration_time;
+	unsigned char rc = true;
+
+	ntcb_hdr = (cb_header_t *) command->non_tx_cmd;	/* get hdr of non tcb cmd */
+
+	/* Set the Command Block to be the last command block */
+	ntcb_hdr->cb_cmd |= __constant_cpu_to_le16(CB_EL_BIT);
+	ntcb_hdr->cb_status = 0;
+	ntcb_hdr->cb_lnk_ptr = 0;
+
+	wmb();
+	if (in_interrupt())
+		return e100_delayed_exec_non_cu_cmd(bdp, command);
+
+	if (netif_running(bdp->device) && (!bdp->driver_isolated))
+		return e100_delayed_exec_non_cu_cmd(bdp, command);
+
+	spin_lock_bh(&(bdp->bd_non_tx_lock));
+
+	if (bdp->non_tx_command_state != E100_NON_TX_IDLE) {
+		goto delayed_exec;
+	}
+
+	if (bdp->last_tcb) {
+		rmb();
+		if ((bdp->last_tcb->tcb_hdr.cb_status &
+		     __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0)
+			goto delayed_exec;
+	}
+
+	if ((readw(&bdp->scb->scb_status) & SCB_CUS_MASK) == SCB_CUS_ACTIVE) {
+		goto delayed_exec;
+	}
+
+	spin_lock_irqsave(&bdp->bd_lock, lock_flag);
+
+	if (!e100_wait_exec_cmplx(bdp, command->dma_addr, SCB_CUC_START)) {
+		spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
+		rc = false;
+		goto exit;
+	}
+
+	bdp->next_cu_cmd = START_WAIT;
+	spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
+
+	/* now wait for completion of non-cu CB up to 20 msec */
+	expiration_time = jiffies + HZ / 50 + 1;
+	rmb();
+	while (!(ntcb_hdr->cb_status &
+		     __constant_cpu_to_le16(CB_STATUS_COMPLETE))) {
+
+		if (time_before(jiffies, expiration_time)) {
+			spin_unlock_bh(&(bdp->bd_non_tx_lock));
+			yield();
+			spin_lock_bh(&(bdp->bd_non_tx_lock));
+		} else {
+			rc = false;
+			goto exit;
+		}
+		rmb();
+	}
+
+exit:
+	e100_free_non_tx_cmd(bdp, command);
+
+	if (netif_running(bdp->device))
+		netif_wake_queue(bdp->device);
+
+	spin_unlock_bh(&(bdp->bd_non_tx_lock));
+	return rc;
+
+delayed_exec:
+	spin_unlock_bh(&(bdp->bd_non_tx_lock));
+	return e100_delayed_exec_non_cu_cmd(bdp, command);
+}
+
+/**
+ * e100_sw_reset
+ * @bdp: atapter's private data struct
+ * @reset_cmd: s/w reset or selective reset
+ *
+ * This routine will issue a software reset to the adapter. It 
+ * will also disable interrupts, as the are enabled after reset.
+ */
+void
+e100_sw_reset(struct e100_private *bdp, u32 reset_cmd)
+{
+	/* Do  a selective reset first to avoid a potential PCI hang */
+	writel(PORT_SELECTIVE_RESET, &bdp->scb->scb_port);
+	readw(&(bdp->scb->scb_status));	/* flushes last write, read-safe */
+
+	/* wait for the reset to take effect */
+	udelay(20);
+	if (reset_cmd == PORT_SOFTWARE_RESET) {
+		writel(PORT_SOFTWARE_RESET, &bdp->scb->scb_port);
+
+		/* wait 20 micro seconds for the reset to take effect */
+		udelay(20);
+	}
+
+	/* Mask off our interrupt line -- its unmasked after reset */
+	e100_dis_intr(bdp);
+}
+
+/**
+ * e100_load_microcode - Download microsocde to controller.
+ * @bdp: atapter's private data struct
+ *
+ * This routine downloads microcode on to the controller. This
+ * microcode is available for the 82558/9, 82550. Currently the
+ * microcode handles interrupt bundling and TCO workaround.
+ *
+ * Returns:
+ *      true: if successfull
+ *      false: otherwise
+ */
+static unsigned char
+e100_load_microcode(struct e100_private *bdp)
+{
+	static struct {
+		u8 rev_id;
+		u32 ucode[UCODE_MAX_DWORDS + 1];
+		int timer_dword;
+		int bundle_dword;
+		int min_size_dword;
+	} ucode_opts[] = {
+		{ D101A4_REV_ID,
+		  D101_A_RCVBUNDLE_UCODE,
+		  D101_CPUSAVER_TIMER_DWORD,
+		  D101_CPUSAVER_BUNDLE_DWORD,
+		  D101_CPUSAVER_MIN_SIZE_DWORD },
+		{ D101B0_REV_ID,
+		  D101_B0_RCVBUNDLE_UCODE,
+		  D101_CPUSAVER_TIMER_DWORD,
+		  D101_CPUSAVER_BUNDLE_DWORD,
+		  D101_CPUSAVER_MIN_SIZE_DWORD },
+		{ D101MA_REV_ID,
+		  D101M_B_RCVBUNDLE_UCODE,
+		  D101M_CPUSAVER_TIMER_DWORD,
+		  D101M_CPUSAVER_BUNDLE_DWORD,
+		  D101M_CPUSAVER_MIN_SIZE_DWORD },
+		{ D101S_REV_ID,
+		  D101S_RCVBUNDLE_UCODE,
+		  D101S_CPUSAVER_TIMER_DWORD,
+		  D101S_CPUSAVER_BUNDLE_DWORD,
+		  D101S_CPUSAVER_MIN_SIZE_DWORD },
+		{ D102_REV_ID,
+		  D102_B_RCVBUNDLE_UCODE,
+		  D102_B_CPUSAVER_TIMER_DWORD,
+		  D102_B_CPUSAVER_BUNDLE_DWORD,
+		  D102_B_CPUSAVER_MIN_SIZE_DWORD },
+		{ D102C_REV_ID,
+		  D102_C_RCVBUNDLE_UCODE,
+		  D102_C_CPUSAVER_TIMER_DWORD,
+		  D102_C_CPUSAVER_BUNDLE_DWORD,
+		  D102_C_CPUSAVER_MIN_SIZE_DWORD },
+		{ D102E_REV_ID,
+		  D102_E_RCVBUNDLE_UCODE,
+		  D102_E_CPUSAVER_TIMER_DWORD,
+		  D102_E_CPUSAVER_BUNDLE_DWORD,
+		  D102_E_CPUSAVER_MIN_SIZE_DWORD },
+		{ 0, {0}, 0, 0, 0}
+	}, *opts;
+
+	opts = ucode_opts;
+
+	/* User turned ucode loading off */
+	if (!(bdp->params.b_params & PRM_UCODE))
+		return false;
+
+	/* These controllers do not need ucode */
+	if (bdp->flags & IS_ICH)
+		return false;
+
+	/* Search for ucode match against h/w rev_id */
+	while (opts->rev_id) {
+		if (bdp->rev_id == opts->rev_id) {
+			int i;
+			u32 *ucode_dword;
+			load_ucode_cb_t *ucode_cmd_ptr;
+			nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp);
+
+			if (cmd != NULL) {
+				ucode_cmd_ptr =
+					(load_ucode_cb_t *) cmd->non_tx_cmd;
+				ucode_dword = ucode_cmd_ptr->ucode_dword;
+			} else {
+				return false;
+			}
+
+			memcpy(ucode_dword, opts->ucode, sizeof (opts->ucode));
+
+			/* Insert user-tunable settings */
+			ucode_dword[opts->timer_dword] &= 0xFFFF0000;
+			ucode_dword[opts->timer_dword] |=
+				(u16) bdp->params.IntDelay;
+			ucode_dword[opts->bundle_dword] &= 0xFFFF0000;
+			ucode_dword[opts->bundle_dword] |=
+				(u16) bdp->params.BundleMax;
+			ucode_dword[opts->min_size_dword] &= 0xFFFF0000;
+			ucode_dword[opts->min_size_dword] |=
+				(bdp->params.b_params & PRM_BUNDLE_SMALL) ?
+				0xFFFF : 0xFF80;
+
+			for (i = 0; i < UCODE_MAX_DWORDS; i++)
+				cpu_to_le32s(&(ucode_dword[i]));
+
+			ucode_cmd_ptr->load_ucode_cbhdr.cb_cmd =
+				__constant_cpu_to_le16(CB_LOAD_MICROCODE);
+
+			return e100_exec_non_cu_cmd(bdp, cmd);
+		}
+		opts++;
+	}
+
+	return false;
+}
+
+/***************************************************************************/
+/***************************************************************************/
+/*       EEPROM  Functions                                                 */
+/***************************************************************************/
+
+/* Read PWA (printed wired assembly) number */
+void __devinit
+e100_rd_pwa_no(struct e100_private *bdp)
+{
+	bdp->pwa_no = e100_eeprom_read(bdp, EEPROM_PWA_NO);
+	bdp->pwa_no <<= 16;
+	bdp->pwa_no |= e100_eeprom_read(bdp, EEPROM_PWA_NO + 1);
+}
+
+/* Read the permanent ethernet address from the eprom. */
+void __devinit
+e100_rd_eaddr(struct e100_private *bdp)
+{
+	int i;
+	u16 eeprom_word;
+
+	for (i = 0; i < 6; i += 2) {
+		eeprom_word =
+			e100_eeprom_read(bdp,
+					 EEPROM_NODE_ADDRESS_BYTE_0 + (i / 2));
+
+		bdp->device->dev_addr[i] =
+			bdp->perm_node_address[i] = (u8) eeprom_word;
+		bdp->device->dev_addr[i + 1] =
+			bdp->perm_node_address[i + 1] = (u8) (eeprom_word >> 8);
+	}
+}
+
+/* Check the D102 RFD flags to see if the checksum passed */
+static unsigned char
+e100_D102_check_checksum(rfd_t *rfd)
+{
+	if (((le16_to_cpu(rfd->rfd_header.cb_status)) & RFD_PARSE_BIT)
+	    && (((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) ==
+		 RFD_TCP_PACKET)
+		|| ((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) ==
+		    RFD_UDP_PACKET))
+	    && (rfd->checksumstatus & TCPUDP_CHECKSUM_BIT_VALID)
+	    && (rfd->checksumstatus & TCPUDP_CHECKSUM_VALID)) {
+		return CHECKSUM_UNNECESSARY;
+	}
+	return CHECKSUM_NONE;
+}
+
+/**
+ * e100_D101M_checksum
+ * @bdp: atapter's private data struct
+ * @skb: skb received
+ *
+ * Sets the skb->csum value from D101 csum found at the end of the Rx frame. The
+ * D101M sums all words in frame excluding the ethernet II header (14 bytes) so
+ * in case the packet is ethernet II and the protocol is IP, all is need is to
+ * assign this value to skb->csum.
+ */
+static unsigned char
+e100_D101M_checksum(struct e100_private *bdp, struct sk_buff *skb)
+{
+	unsigned short proto = (skb->protocol);
+
+	if (proto == __constant_htons(ETH_P_IP)) {
+
+		skb->csum = get_unaligned((u16 *) (skb->tail));
+		return CHECKSUM_HW;
+	}
+	return CHECKSUM_NONE;
+}
+
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+/*       Auxilary Functions                                                */
+/***************************************************************************/
+
+/* Print the board's configuration */
+void __devinit
+e100_print_brd_conf(struct e100_private *bdp)
+{
+	if (netif_carrier_ok(bdp->device)) {
+		printk(KERN_NOTICE
+		       "  Mem:0x%08lx  IRQ:%d  Speed:%d Mbps  Dx:%s\n",
+		       (unsigned long) bdp->device->mem_start,
+		       bdp->device->irq, bdp->cur_line_speed,
+		       (bdp->cur_dplx_mode == FULL_DUPLEX) ? "Full" : "Half");
+	} else {
+		printk(KERN_NOTICE
+		       "  Mem:0x%08lx  IRQ:%d  Speed:%d Mbps  Dx:%s\n",
+		       (unsigned long) bdp->device->mem_start,
+		       bdp->device->irq, 0, "N/A");
+	}
+
+	/* Print the string if checksum Offloading was enabled */
+	if (bdp->flags & DF_CSUM_OFFLOAD)
+		printk(KERN_NOTICE "  Hardware receive checksums enabled\n");
+	else {
+		if (bdp->rev_id >= D101MA_REV_ID) 
+			printk(KERN_NOTICE "  Hardware receive checksums disabled\n");
+	}
+
+	if ((bdp->flags & DF_UCODE_LOADED))
+		printk(KERN_NOTICE "  cpu cycle saver enabled\n");
+}
+
+/**
+ * e100_get_brand_msg
+ * @bdp: atapter's private data struct
+ *
+ * This routine checks if there is specified branding message for a given board
+ * type and returns a pointer to the string containing the branding message.
+ */
+char *
+e100_get_brand_msg(struct e100_private *bdp)
+{
+	int i;
+
+	for (i = 0; e100_vendor_info_array[i].idstr != NULL; i++) {
+		if (e100_vendor_info_array[i].device_type == bdp->device_type) {
+			return e100_vendor_info_array[i].idstr;
+		}
+	}
+
+	return e100_vendor_info_array[E100_ALL_BOARDS].idstr;
+}
+
+/**
+ * e100_pci_setup - setup the adapter's PCI information
+ * @pcid: adapter's pci_dev struct
+ * @bdp: atapter's private data struct
+ *
+ * This routine sets up all PCI information for the adapter. It enables the bus
+ * master bit (some BIOS don't do this), requests memory ans I/O regions, and
+ * calls ioremap() on the adapter's memory region.
+ *
+ * Returns:
+ *      true: if successfull
+ *      false: otherwise
+ */
+static unsigned char __devinit
+e100_pci_setup(struct pci_dev *pcid, struct e100_private *bdp)
+{
+	struct net_device *dev = bdp->device;
+	int rc = 0;
+
+	if ((rc = pci_enable_device(pcid)) != 0) {
+		goto err;
+	}
+
+	/* dev and ven ID have already been checked so it is our device */
+	pci_read_config_byte(pcid, PCI_REVISION_ID, (u8 *) &(bdp->rev_id));
+
+	/* address #0 is a memory region */
+	dev->mem_start = pci_resource_start(pcid, 0);
+	dev->mem_end = dev->mem_start + sizeof (scb_t);
+
+	/* address #1 is a IO region */
+	dev->base_addr = pci_resource_start(pcid, 1);
+
+	if ((rc = pci_request_regions(pcid, e100_short_driver_name)) != 0) {
+		goto err_disable;
+	}
+
+	pci_enable_wake(pcid, 0, 0);
+
+	/* if Bus Mastering is off, turn it on! */
+	pci_set_master(pcid);
+
+	/* address #0 is a memory mapping */
+	bdp->scb = (scb_t *) ioremap_nocache(dev->mem_start, sizeof (scb_t));
+
+	if (!bdp->scb) {
+		printk(KERN_ERR "e100: %s: Failed to map PCI address 0x%lX\n",
+		       dev->name, pci_resource_start(pcid, 0));
+		rc = -ENOMEM;
+		goto err_region;
+	}
+
+	return 0;
+
+err_region:
+	pci_release_regions(pcid);
+err_disable:
+	pci_disable_device(pcid);
+err:
+	return rc;
+}
+
+void
+e100_isolate_driver(struct e100_private *bdp)
+{
+	write_lock_irq(&(bdp->isolate_lock));
+	bdp->driver_isolated = true;
+	write_unlock_irq(&(bdp->isolate_lock));
+
+	del_timer_sync(&bdp->watchdog_timer);
+
+	del_timer_sync(&bdp->hwi_timer);
+	/* If in middle of cable diag, */
+	if (bdp->hwi_started) {
+		bdp->hwi_started = 0;
+		e100_hwi_restore(bdp);
+	}
+
+	if (netif_running(bdp->device))
+		netif_stop_queue(bdp->device);
+
+	bdp->last_tcb = NULL;
+
+	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
+}
+
+void
+e100_set_speed_duplex(struct e100_private *bdp)
+{
+	e100_phy_set_speed_duplex(bdp, true);
+	e100_config_fc(bdp);	/* re-config flow-control if necessary */
+	e100_config(bdp);	
+}
+
+static void
+e100_tcb_add_C_bit(struct e100_private *bdp)
+{
+	tcb_t *tcb = (tcb_t *) bdp->tcb_pool.data;
+	int i;
+
+	for (i = 0; i < bdp->params.TxDescriptors; i++, tcb++) {
+		tcb->tcb_hdr.cb_status |= cpu_to_le16(CB_STATUS_COMPLETE);
+	}
+}
+
+/* 
+ * Procedure:   e100_hw_reset_recover
+ *
+ * Description: This routine will recover the hw after reset.
+ *
+ * Arguments:
+ *      bdp - Ptr to this card's e100_bdconfig structure
+ *        reset_cmd - s/w reset or selective reset. 
+ *
+ * Returns:
+ *        true upon success
+ *        false upon failure
+ */
+unsigned char
+e100_hw_reset_recover(struct e100_private *bdp, u32 reset_cmd)
+{
+	bdp->last_tcb = NULL;
+	if (reset_cmd == PORT_SOFTWARE_RESET) {
+
+		/*load CU & RU base */
+		if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE)) {
+			return false;
+		}
+
+		if (e100_load_microcode(bdp)) {
+			bdp->flags |= DF_UCODE_LOADED;
+		}
+
+		if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE)) {
+			return false;
+		}
+
+		/* Issue the load dump counters address command */
+		if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys,
+					  SCB_CUC_DUMP_ADDR)) {
+			return false;
+		}
+
+		if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) {
+			printk(KERN_ERR
+			       "e100: e100_hw_reset_recover: "
+			       "setup iaaddr failed\n");
+			return false;
+		}
+
+		e100_set_multi_exec(bdp->device);
+
+		/* Change for 82558 enhancement */
+		/* If 82558/9 and if the user has enabled flow control, set up * the
+		 * Flow Control Reg. in the CSR */
+		if ((bdp->flags & IS_BACHELOR)
+		    && (bdp->params.b_params & PRM_FC)) {
+			writeb(DFLT_FC_THLD,
+			       &bdp->scb->scb_ext.d101_scb.scb_fc_thld);
+			writeb(DFLT_FC_CMD,
+			       &bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff);
+		}
+
+	}
+
+	e100_force_config(bdp);
+
+	return true;
+}
+
+void
+e100_deisolate_driver(struct e100_private *bdp, u8 recover, u8 full_init)
+{
+	if (full_init) {
+		e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
+		if (!e100_hw_reset_recover(bdp, PORT_SOFTWARE_RESET))
+			printk(KERN_ERR "e100: e100_deisolate_driver:"
+			       " HW SOFTWARE reset recover failed\n");
+	}
+
+	if (recover) {
+
+		bdp->next_cu_cmd = START_WAIT;
+		bdp->last_tcb = NULL;
+
+		/* lets reset the chip */
+		if (!full_init) {
+			e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
+
+			if (!e100_hw_reset_recover(bdp, PORT_SELECTIVE_RESET)) {
+				printk(KERN_ERR "e100: e100_deisolate_driver:"
+				       " HW reset recover failed\n");
+			}
+		}
+		e100_start_ru(bdp);
+
+		/* relaunch watchdog timer in 2 sec */
+		mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ));
+
+		// we must clear tcbs since we may have lost Tx intrrupt
+		// or have unsent frames on the tcb chain
+		e100_tcb_add_C_bit(bdp);
+		e100_tx_srv(bdp);
+
+		e100_set_intr_mask(bdp);
+
+		if (netif_running(bdp->device))
+			netif_wake_queue(bdp->device);
+	}
+
+	bdp->driver_isolated = false;
+}
+
+static int
+e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+	struct ethtool_cmd ecmd;
+	int rc = -EOPNOTSUPP;
+
+	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd.cmd)))
+		return -EFAULT;
+
+	switch (ecmd.cmd) {
+	case ETHTOOL_GSET:
+		rc = e100_ethtool_get_settings(dev, ifr);
+		break;
+	case ETHTOOL_SSET:
+		rc = e100_ethtool_set_settings(dev, ifr);
+		break;
+	case ETHTOOL_GDRVINFO:
+		rc = e100_ethtool_get_drvinfo(dev, ifr);
+		break;
+	case ETHTOOL_GREGS:
+		rc = e100_ethtool_gregs(dev, ifr);
+		break;
+	case ETHTOOL_NWAY_RST:
+		rc = e100_ethtool_nway_rst(dev, ifr);
+		break;
+	case ETHTOOL_GLINK:
+		rc = e100_ethtool_glink(dev, ifr);
+		break;
+	case ETHTOOL_GEEPROM:
+	case ETHTOOL_SEEPROM:
+		rc = e100_ethtool_eeprom(dev, ifr);
+		break;
+	case ETHTOOL_GWOL:
+	case ETHTOOL_SWOL:
+		rc = e100_ethtool_wol(dev, ifr);
+		break;
+	case ETHTOOL_TEST:
+		rc = e100_ethtool_test(dev, ifr);
+		break;
+	case ETHTOOL_GSTRINGS:
+		rc = e100_ethtool_gstrings(dev,ifr);
+		break;
+	case ETHTOOL_PHYS_ID:
+		rc = e100_ethtool_led_blink(dev,ifr);
+		break;
+	default:
+		break;
+	}			//switch
+	return rc;
+}
+
+static int
+e100_ethtool_get_settings(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+	struct ethtool_cmd ecmd;
+	u16 advert = 0;
+
+	memset((void *) &ecmd, 0, sizeof (ecmd));
+
+	bdp = dev->priv;
+
+	ecmd.supported = bdp->speed_duplex_caps;
+
+	ecmd.port =
+		(bdp->speed_duplex_caps & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
+	ecmd.transceiver = XCVR_INTERNAL;
+	ecmd.phy_address = bdp->phy_addr;
+
+	if (netif_carrier_ok(bdp->device)) {
+		ecmd.speed = bdp->cur_line_speed;
+		ecmd.duplex =
+			(bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL;
+	}
+	else {
+		ecmd.speed = -1;
+		ecmd.duplex = -1;
+	}
+
+	ecmd.advertising = ADVERTISED_TP;
+
+	if (bdp->params.e100_speed_duplex == E100_AUTONEG) {
+		ecmd.autoneg = AUTONEG_ENABLE;
+		ecmd.advertising |= ADVERTISED_Autoneg;
+	} else {
+		ecmd.autoneg = AUTONEG_DISABLE;
+	}
+
+	if (bdp->speed_duplex_caps & SUPPORTED_MII) {
+		e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &advert);
+
+		if (advert & ADVERTISE_10HALF)
+			ecmd.advertising |= ADVERTISED_10baseT_Half;
+		if (advert & ADVERTISE_10FULL)
+			ecmd.advertising |= ADVERTISED_10baseT_Full;
+		if (advert & ADVERTISE_100HALF)
+			ecmd.advertising |= ADVERTISED_100baseT_Half;
+		if (advert & ADVERTISE_100FULL)
+			ecmd.advertising |= ADVERTISED_100baseT_Full;
+	} else {
+		ecmd.autoneg = AUTONEG_DISABLE;
+		ecmd.advertising &= ~ADVERTISED_Autoneg;
+	}
+
+	if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int
+e100_ethtool_set_settings(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+	int current_duplex;
+	int e100_new_speed_duplex;
+	int ethtool_new_speed_duplex;
+	int speed_duplex_change_required;
+	struct ethtool_cmd ecmd;
+
+	if (!capable(CAP_NET_ADMIN)) {
+		return -EPERM;
+	}
+
+	bdp = dev->priv;
+	if (netif_running(dev)) {
+		return -EBUSY;
+	}
+	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) {
+		return -EFAULT;
+	}
+	current_duplex =
+		(bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL;
+	speed_duplex_change_required = (ecmd.speed != bdp->cur_line_speed)
+		|| (ecmd.duplex != current_duplex);
+
+	if ((ecmd.autoneg == AUTONEG_ENABLE) && speed_duplex_change_required) {
+		return -EINVAL;
+	}
+
+	if ((ecmd.autoneg == AUTONEG_ENABLE)
+	    && (bdp->speed_duplex_caps & SUPPORTED_Autoneg)) {
+		bdp->params.e100_speed_duplex = E100_AUTONEG;
+		e100_set_speed_duplex(bdp);
+	} else {
+		if (speed_duplex_change_required) {
+			if (ecmd.speed == SPEED_10) {
+				if (ecmd.duplex == DUPLEX_HALF) {
+					e100_new_speed_duplex =
+						E100_SPEED_10_HALF;
+					ethtool_new_speed_duplex =
+						SUPPORTED_10baseT_Half;
+
+				} else {
+					e100_new_speed_duplex =
+						E100_SPEED_10_FULL;
+					ethtool_new_speed_duplex =
+						SUPPORTED_10baseT_Full;
+				}
+
+			} else {
+				if (ecmd.duplex == DUPLEX_HALF) {
+					e100_new_speed_duplex =
+						E100_SPEED_100_HALF;
+					ethtool_new_speed_duplex =
+						SUPPORTED_100baseT_Half;
+
+				} else {
+					e100_new_speed_duplex =
+						E100_SPEED_100_FULL;
+					ethtool_new_speed_duplex =
+						SUPPORTED_100baseT_Full;
+				}
+			}
+
+			if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) {
+				bdp->params.e100_speed_duplex =
+					e100_new_speed_duplex;
+				e100_set_speed_duplex(bdp);
+			} else {
+				return -EOPNOTSUPP;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int
+e100_ethtool_glink(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+	struct ethtool_value info;
+
+	memset((void *) &info, 0, sizeof (info));
+
+	bdp = dev->priv;
+	info.cmd = ETHTOOL_GLINK;
+
+	/* Consider both PHY link and netif_running */
+	info.data = e100_update_link_state(bdp);
+
+	if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int
+e100_ethtool_test(struct net_device *dev, struct ifreq *ifr)
+{
+	struct ethtool_test *info;
+	int rc = -EFAULT;
+
+	info = kmalloc(sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64),
+		       GFP_ATOMIC);
+
+	if (!info)
+		return -ENOMEM;
+
+	memset((void *) info, 0, sizeof(*info) +
+				 E100_MAX_TEST_RES * sizeof(u64));
+
+	if (copy_from_user(info, ifr->ifr_data, sizeof(*info)))
+		goto exit;
+
+	info->flags = e100_run_diag(dev, info->data, info->flags);
+
+	if (!copy_to_user(ifr->ifr_data, info,
+			 sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64)))
+		rc = 0;
+exit:
+	kfree(info);
+	return rc;
+}
+
+static int
+e100_ethtool_gregs(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+	u32 regs_buff[E100_REGS_LEN];
+	struct ethtool_regs regs = {ETHTOOL_GREGS};
+	void *addr = ifr->ifr_data;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+	bdp = dev->priv;
+
+	if(copy_from_user(&regs, addr, sizeof(regs)))
+		return -EFAULT;
+
+	regs.version = (1 << 24) | bdp->rev_id;
+	regs_buff[0] = readb(&(bdp->scb->scb_cmd_hi)) << 24 |
+		readb(&(bdp->scb->scb_cmd_low)) << 16 |
+		readw(&(bdp->scb->scb_status));
+
+	if(copy_to_user(addr, &regs, sizeof(regs)))
+		return -EFAULT;
+
+	addr += offsetof(struct ethtool_regs, data);
+	if(copy_to_user(addr, regs_buff, regs.len))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int
+e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	bdp = dev->priv;
+
+	if ((bdp->speed_duplex_caps & SUPPORTED_Autoneg) &&
+	    (bdp->params.e100_speed_duplex == E100_AUTONEG)) {
+		e100_set_speed_duplex(bdp);
+	} else {
+		return -EFAULT;
+	}
+	return 0;
+}
+
+static int
+e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+	struct ethtool_drvinfo info;
+
+	memset((void *) &info, 0, sizeof (info));
+
+	bdp = dev->priv;
+
+	strncpy(info.driver, e100_short_driver_name, sizeof (info.driver) - 1);
+	strncpy(info.version, e100_driver_version, sizeof (info.version) - 1);
+	strncpy(info.fw_version, "N/A",
+		sizeof (info.fw_version) - 1);
+	strncpy(info.bus_info, bdp->pdev->slot_name,
+		sizeof (info.bus_info) - 1);
+	info.regdump_len  = E100_REGS_LEN * sizeof(u32);
+	info.eedump_len = (bdp->eeprom_size << 1);	
+	info.testinfo_len = E100_MAX_TEST_RES;
+	if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int
+e100_ethtool_eeprom(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+	struct ethtool_eeprom ecmd;
+	u16 eeprom_data[256];
+	u16 *usr_eeprom_ptr;
+	u16 first_word, last_word;
+	int i, max_len;
+	void *ptr;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	bdp = dev->priv;
+
+	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
+		return -EFAULT;
+
+	usr_eeprom_ptr =
+		(u16 *) (ifr->ifr_data + offsetof(struct ethtool_eeprom, data));
+
+        max_len = bdp->eeprom_size * 2;
+        
+        if (ecmd.offset > ecmd.offset + ecmd.len)
+        	return -EINVAL;
+        	
+	if ((ecmd.offset + ecmd.len) > max_len)
+		ecmd.len = (max_len - ecmd.offset);
+
+	first_word = ecmd.offset >> 1;
+	last_word = (ecmd.offset + ecmd.len - 1) >> 1;
+		
+	if (first_word >= bdp->eeprom_size)
+		return -EFAULT;
+
+	if (ecmd.cmd == ETHTOOL_GEEPROM) {
+        	for(i = 0; i <= (last_word - first_word); i++)
+			eeprom_data[i] = e100_eeprom_read(bdp, first_word + i);
+
+		ecmd.magic = E100_EEPROM_MAGIC;
+
+		if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
+			return -EFAULT;
+
+		if (copy_to_user(usr_eeprom_ptr, eeprom_data, ecmd.len))
+			return -EFAULT;
+	} else {
+		if (ecmd.magic != E100_EEPROM_MAGIC)
+			return -EFAULT;
+
+		ptr = (void *)eeprom_data;
+        	if(ecmd.offset & 1) {
+                	/* need modification of first changed EEPROM word */
+                	/* only the second byte of the word is being modified */
+			eeprom_data[0] = e100_eeprom_read(bdp, first_word);
+                	ptr++;
+        	}
+        	if((ecmd.offset + ecmd.len) & 1) {
+	                /* need modification of last changed EEPROM word */
+	                /* only the first byte of the word is being modified */
+			eeprom_data[last_word - first_word] = 
+				e100_eeprom_read(bdp, last_word);
+		}
+        	if(copy_from_user(ptr, usr_eeprom_ptr, ecmd.len))
+	                return -EFAULT;
+
+		e100_eeprom_write_block(bdp, first_word, eeprom_data,
+					last_word - first_word + 1);
+
+		if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+#define E100_BLINK_INTERVAL	(HZ/4)
+/**
+ * e100_led_control
+ * @bdp: atapter's private data struct
+ * @led_mdi_op: led operation
+ *
+ * Software control over adapter's led. The possible operations are:
+ * TURN LED OFF, TURN LED ON and RETURN LED CONTROL TO HARDWARE.
+ */
+static void
+e100_led_control(struct e100_private *bdp, u16 led_mdi_op)
+{
+	e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
+		       bdp->phy_addr, led_mdi_op);
+
+}
+/**
+ * e100_led_blink_callback
+ * @data: pointer to atapter's private data struct
+ *
+ * Blink timer callback function. Toggles ON/OFF led status bit and calls
+ * led hardware access function. 
+ */
+static void
+e100_led_blink_callback(unsigned long data)
+{
+	struct e100_private *bdp = (struct e100_private *) data;
+
+	if(bdp->flags & LED_IS_ON) {
+		bdp->flags &= ~LED_IS_ON;
+		e100_led_control(bdp, PHY_82555_LED_OFF);
+	} else {
+		bdp->flags |= LED_IS_ON;
+		if (bdp->rev_id >= D101MA_REV_ID)
+			e100_led_control(bdp, PHY_82555_LED_ON_559);
+		else
+			e100_led_control(bdp, PHY_82555_LED_ON_PRE_559);
+	}
+
+	mod_timer(&bdp->blink_timer, jiffies + E100_BLINK_INTERVAL);
+}
+/**
+ * e100_ethtool_led_blink
+ * @dev: pointer to atapter's net_device struct
+ * @ifr: pointer to ioctl request structure
+ *
+ * Blink led ioctl handler. Initialtes blink timer and sleeps until
+ * blink period expires. Than it kills timer and returns. The led control
+ * is returned back to hardware when blink timer is killed.
+ */
+static int
+e100_ethtool_led_blink(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+	struct ethtool_value ecmd;
+
+	bdp = dev->priv;
+
+	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
+		return -EFAULT;
+
+	if(!bdp->blink_timer.function) {
+		init_timer(&bdp->blink_timer);
+		bdp->blink_timer.function = e100_led_blink_callback;
+		bdp->blink_timer.data = (unsigned long) bdp;
+	}
+
+	mod_timer(&bdp->blink_timer, jiffies);
+
+	set_current_state(TASK_INTERRUPTIBLE);
+
+	if ((!ecmd.data) || (ecmd.data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)))
+		ecmd.data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
+
+	schedule_timeout(ecmd.data * HZ);
+
+	del_timer_sync(&bdp->blink_timer);
+
+	e100_led_control(bdp, PHY_82555_LED_NORMAL_CONTROL);
+
+	return 0;
+}
+
+static inline int __devinit
+e100_10BaseT_adapter(struct e100_private *bdp)
+{
+	return ((bdp->pdev->device == 0x1229) &&
+		(bdp->pdev->subsystem_vendor == 0x8086) &&
+		(bdp->pdev->subsystem_device == 0x0003));
+}
+
+static void __devinit
+e100_get_speed_duplex_caps(struct e100_private *bdp)
+{
+	u16 status;
+
+	e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status);
+
+	bdp->speed_duplex_caps = 0;
+
+	bdp->speed_duplex_caps |=
+		(status & BMSR_ANEGCAPABLE) ? SUPPORTED_Autoneg : 0;
+
+	bdp->speed_duplex_caps |=
+		(status & BMSR_10HALF) ? SUPPORTED_10baseT_Half : 0;
+
+	bdp->speed_duplex_caps |=
+		(status & BMSR_10FULL) ? SUPPORTED_10baseT_Full : 0;
+
+	bdp->speed_duplex_caps |=
+		(status & BMSR_100HALF) ? SUPPORTED_100baseT_Half : 0;
+
+	bdp->speed_duplex_caps |=
+		(status & BMSR_100FULL) ? SUPPORTED_100baseT_Full : 0;
+
+	if (IS_NC3133(bdp))
+		bdp->speed_duplex_caps =
+			(SUPPORTED_FIBRE | SUPPORTED_100baseT_Full);
+	else
+		bdp->speed_duplex_caps |= SUPPORTED_TP;
+
+	if ((status == 0xFFFF) && e100_10BaseT_adapter(bdp)) {
+		bdp->speed_duplex_caps =
+			(SUPPORTED_10baseT_Half | SUPPORTED_TP);
+	} else {
+		bdp->speed_duplex_caps |= SUPPORTED_MII;
+	}
+
+}
+
+#ifdef CONFIG_PM
+static unsigned char
+e100_setup_filter(struct e100_private *bdp)
+{
+	cb_header_t *ntcb_hdr;
+	unsigned char res = false;
+	nxmit_cb_entry_t *cmd;
+
+	if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) {
+		goto exit;
+	}
+
+	ntcb_hdr = (cb_header_t *) cmd->non_tx_cmd;
+	ntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_LOAD_FILTER);
+
+	/* Set EL and FIX bit */
+	(cmd->non_tx_cmd)->ntcb.filter.filter_data[0] =
+		__constant_cpu_to_le32(CB_FILTER_EL | CB_FILTER_FIX);
+
+	if (bdp->wolopts & WAKE_UCAST) {
+		(cmd->non_tx_cmd)->ntcb.filter.filter_data[0] |=
+			__constant_cpu_to_le32(CB_FILTER_IA_MATCH);
+	}
+
+	if (bdp->wolopts & WAKE_ARP) {
+		/* Setup ARP bit and lower IP parts */
+		/* bdp->ip_lbytes contains 2 lower bytes of IP address in network byte order */
+		(cmd->non_tx_cmd)->ntcb.filter.filter_data[0] |=
+			cpu_to_le32(CB_FILTER_ARP | bdp->ip_lbytes);
+	}
+
+	res = e100_exec_non_cu_cmd(bdp, cmd);
+	if (!res)
+		printk(KERN_WARNING "e100: %s: Filter setup failed\n",
+		       bdp->device->name);
+
+exit:
+	return res;
+
+}
+
+static void
+e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp)
+{
+	e100_config_wol(bdp);
+
+	if (e100_config(bdp)) {
+		if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP))
+			if (!e100_setup_filter(bdp))
+				printk(KERN_ERR
+				       "e100: WOL options failed\n");
+	} else {
+		printk(KERN_ERR "e100: config WOL failed\n");
+	}
+}
+#endif
+
+static u16
+e100_get_ip_lbytes(struct net_device *dev)
+{
+	struct in_ifaddr *ifa;
+	struct in_device *in_dev;
+	u32 res = 0;
+
+	in_dev = (struct in_device *) dev->ip_ptr;
+	/* Check if any in_device bound to interface */
+	if (in_dev) {
+		/* Check if any IP address is bound to interface */
+		if ((ifa = in_dev->ifa_list) != NULL) {
+			res = __constant_ntohl(ifa->ifa_address);
+			res = __constant_htons(res & 0x0000ffff);
+		}
+	}
+	return res;
+}
+
+static int
+e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+	struct ethtool_wolinfo wolinfo;
+	int res = 0;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	bdp = dev->priv;
+
+	if (copy_from_user(&wolinfo, ifr->ifr_data, sizeof (wolinfo))) {
+		return -EFAULT;
+	}
+
+	switch (wolinfo.cmd) {
+	case ETHTOOL_GWOL:
+		wolinfo.supported = bdp->wolsupported;
+		wolinfo.wolopts = bdp->wolopts;
+		if (copy_to_user(ifr->ifr_data, &wolinfo, sizeof (wolinfo)))
+			res = -EFAULT;
+		break;
+	case ETHTOOL_SWOL:
+		/* If ALL requests are supported or request is DISABLE wol */
+		if (((wolinfo.wolopts & bdp->wolsupported) == wolinfo.wolopts)
+		    || (wolinfo.wolopts == 0)) {
+			bdp->wolopts = wolinfo.wolopts;
+		} else {
+			res = -EOPNOTSUPP;
+		}
+		if (wolinfo.wolopts & WAKE_ARP)
+			bdp->ip_lbytes = e100_get_ip_lbytes(dev);
+		break;
+	default:
+		break;
+	}
+	return res;
+}
+
+static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr)
+{
+	struct ethtool_gstrings info;
+	char *strings = NULL;
+	char *usr_strings;
+	int i;
+
+	memset((void *) &info, 0, sizeof(info));
+
+	usr_strings = (u8 *) (ifr->ifr_data + 
+			      offsetof(struct ethtool_gstrings, data));
+
+	if (copy_from_user(&info, ifr->ifr_data, sizeof (info)))
+		return -EFAULT;
+
+	switch (info.string_set) {
+	case ETH_SS_TEST:
+		if (info.len > E100_MAX_TEST_RES)
+			info.len = E100_MAX_TEST_RES;
+		strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC);
+		if (!strings)
+			return -ENOMEM;
+		memset(strings, 0, info.len * ETH_GSTRING_LEN);
+
+		for (i = 0; i < info.len; i++) {
+			sprintf(strings + i * ETH_GSTRING_LEN, "%-31s",
+				test_strings[i]);
+		}
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+		return -EFAULT;
+
+	if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN))
+		return -EFAULT;
+
+	kfree(strings);
+	return 0;
+}
+
+static int
+e100_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct e100_private *bdp;
+	struct mii_ioctl_data *data_ptr =
+		(struct mii_ioctl_data *) &(ifr->ifr_data);
+
+	bdp = dev->priv;
+
+	switch (cmd) {
+	case SIOCGMIIPHY:
+		data_ptr->phy_id = bdp->phy_addr & 0x1f;
+		break;
+
+	case SIOCGMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		e100_mdi_read(bdp, data_ptr->reg_num & 0x1f, bdp->phy_addr,
+			      &(data_ptr->val_out));
+		break;
+
+	case SIOCSMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (netif_running(dev)) {
+			return -EBUSY;
+		}
+		/* If reg = 0 && change speed/duplex */
+		if (data_ptr->reg_num == 0 && 
+			(data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) /* restart cmd */
+			|| data_ptr->val_in == (BMCR_RESET) /* reset cmd */ 
+			|| data_ptr->val_in & (BMCR_SPEED100 | BMCR_FULLDPLX) 
+			|| data_ptr->val_in == 0)) {
+				if (data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART)
+					|| data_ptr->val_in == (BMCR_RESET))
+					bdp->params.e100_speed_duplex = E100_AUTONEG;
+				else if (data_ptr->val_in == (BMCR_SPEED100 | BMCR_FULLDPLX))
+					bdp->params.e100_speed_duplex = E100_SPEED_100_FULL;
+				else if (data_ptr->val_in == (BMCR_SPEED100))
+					bdp->params.e100_speed_duplex = E100_SPEED_100_HALF;
+				else if (data_ptr->val_in == (BMCR_FULLDPLX))
+					bdp->params.e100_speed_duplex = E100_SPEED_10_FULL;
+				else
+					bdp->params.e100_speed_duplex = E100_SPEED_10_HALF;
+				e100_set_speed_duplex(bdp);
+		}
+		else {
+			e100_mdi_write(bdp, data_ptr->reg_num, bdp->phy_addr,
+			       data_ptr->val_in);
+		}
+		
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+nxmit_cb_entry_t *
+e100_alloc_non_tx_cmd(struct e100_private *bdp)
+{
+	nxmit_cb_entry_t *non_tx_cmd_elem;
+
+	if (!(non_tx_cmd_elem = (nxmit_cb_entry_t *)
+	      kmalloc(sizeof (nxmit_cb_entry_t), GFP_ATOMIC))) {
+		return NULL;
+	}
+	non_tx_cmd_elem->non_tx_cmd =
+		pci_alloc_consistent(bdp->pdev, sizeof (nxmit_cb_t),
+				     &(non_tx_cmd_elem->dma_addr));
+	if (non_tx_cmd_elem->non_tx_cmd == NULL) {
+		kfree(non_tx_cmd_elem);
+		return NULL;
+	}
+	return non_tx_cmd_elem;
+}
+
+void
+e100_free_non_tx_cmd(struct e100_private *bdp,
+		     nxmit_cb_entry_t *non_tx_cmd_elem)
+{
+	pci_free_consistent(bdp->pdev, sizeof (nxmit_cb_t),
+			    non_tx_cmd_elem->non_tx_cmd,
+			    non_tx_cmd_elem->dma_addr);
+	kfree(non_tx_cmd_elem);
+}
+
+static void
+e100_free_nontx_list(struct e100_private *bdp)
+{
+	nxmit_cb_entry_t *command;
+	int i;
+
+	while (!list_empty(&bdp->non_tx_cmd_list)) {
+		command = list_entry(bdp->non_tx_cmd_list.next,
+				     nxmit_cb_entry_t, list_elem);
+		list_del(&(command->list_elem));
+		e100_free_non_tx_cmd(bdp, command);
+	}
+
+	for (i = 0; i < CB_MAX_NONTX_CMD; i++) {
+		bdp->same_cmd_entry[i] = NULL;
+	}
+}
+
+static unsigned char
+e100_delayed_exec_non_cu_cmd(struct e100_private *bdp,
+			     nxmit_cb_entry_t *command)
+{
+	nxmit_cb_entry_t *same_command;
+	cb_header_t *ntcb_hdr;
+	u16 cmd;
+
+	ntcb_hdr = (cb_header_t *) command->non_tx_cmd;
+
+	cmd = CB_CMD_MASK & le16_to_cpu(ntcb_hdr->cb_cmd);
+
+	spin_lock_bh(&(bdp->bd_non_tx_lock));
+
+	same_command = bdp->same_cmd_entry[cmd];
+
+	if (same_command != NULL) {
+		memcpy((void *) (same_command->non_tx_cmd),
+		       (void *) (command->non_tx_cmd), sizeof (nxmit_cb_t));
+		e100_free_non_tx_cmd(bdp, command);
+	} else {
+		list_add_tail(&(command->list_elem), &(bdp->non_tx_cmd_list));
+		bdp->same_cmd_entry[cmd] = command;
+	}
+
+	if (bdp->non_tx_command_state == E100_NON_TX_IDLE) {
+		bdp->non_tx_command_state = E100_WAIT_TX_FINISH;
+		mod_timer(&(bdp->nontx_timer_id), jiffies + 1);
+	}
+
+	spin_unlock_bh(&(bdp->bd_non_tx_lock));
+	return true;
+}
+
+static void
+e100_non_tx_background(unsigned long ptr)
+{
+	struct e100_private *bdp = (struct e100_private *) ptr;
+	nxmit_cb_entry_t *active_command;
+	int restart = true;
+
+	spin_lock_bh(&(bdp->bd_non_tx_lock));
+
+	switch (bdp->non_tx_command_state) {
+	case E100_WAIT_TX_FINISH:
+		if (bdp->last_tcb != NULL) {
+			rmb();
+			if ((bdp->last_tcb->tcb_hdr.cb_status &
+			     __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0)
+				goto exit;
+		}
+		if ((readw(&bdp->scb->scb_status) & SCB_CUS_MASK) ==
+		    SCB_CUS_ACTIVE) {
+			goto exit;
+		}
+		break;
+
+	case E100_WAIT_NON_TX_FINISH:
+		active_command = list_entry(bdp->non_tx_cmd_list.next,
+					    nxmit_cb_entry_t, list_elem);
+		rmb();
+
+		if (((((cb_header_t *) (active_command->non_tx_cmd))->cb_status
+		      & __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0)
+		    && time_before(jiffies, active_command->expiration_time)) {
+			goto exit;
+		} else {
+			list_del(&(active_command->list_elem));
+			e100_free_non_tx_cmd(bdp, active_command);
+		}
+		break;
+
+	default:
+		break;
+	}			//switch
+
+	if (list_empty(&bdp->non_tx_cmd_list)) {
+		bdp->non_tx_command_state = E100_NON_TX_IDLE;
+		spin_lock_irq(&(bdp->bd_lock));
+		bdp->next_cu_cmd = START_WAIT;
+		spin_unlock_irq(&(bdp->bd_lock));
+		restart = false;
+		goto exit;
+	} else {
+		u16 cmd_type;
+
+		bdp->non_tx_command_state = E100_WAIT_NON_TX_FINISH;
+		active_command = list_entry(bdp->non_tx_cmd_list.next,
+					    nxmit_cb_entry_t, list_elem);
+		spin_lock_irq(&(bdp->bd_lock));
+		e100_wait_exec_cmplx(bdp, active_command->dma_addr,
+				     SCB_CUC_START);
+		spin_unlock_irq(&(bdp->bd_lock));
+		active_command->expiration_time = jiffies + HZ;
+		cmd_type = CB_CMD_MASK &
+			le16_to_cpu(((cb_header_t *)
+				     (active_command->non_tx_cmd))->cb_cmd);
+		bdp->same_cmd_entry[cmd_type] = NULL;
+	}
+
+exit:
+	if (restart) {
+		mod_timer(&(bdp->nontx_timer_id), jiffies + 1);
+	} else {
+		if (netif_running(bdp->device))
+			netif_wake_queue(bdp->device);
+	}
+	spin_unlock_bh(&(bdp->bd_non_tx_lock));
+}
+
+int e100_notify_netdev(struct notifier_block *nb, unsigned long event, void *p)
+{
+	struct e100_private *bdp;
+	struct net_device *netdev = p;
+	
+	if(netdev == NULL)
+		return NOTIFY_DONE;
+	
+	switch(event) {
+	case NETDEV_CHANGENAME:
+		if(netdev->open == e100_open) {
+			bdp = netdev->priv;
+			/* rename the proc nodes the easy way */
+			e100_remove_proc_subdir(bdp, bdp->ifname);
+			memcpy(bdp->ifname, netdev->name, IFNAMSIZ);
+			bdp->ifname[IFNAMSIZ-1] = 0;
+			e100_create_proc_subdir(bdp, bdp->ifname);
+		}
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+#ifdef CONFIG_PM
+static int
+e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
+{
+        struct pci_dev *pdev;
+	
+        switch(event) {
+        case SYS_DOWN:
+        case SYS_HALT:
+        case SYS_POWER_OFF:
+                pci_for_each_dev(pdev) {
+                        if(pci_dev_driver(pdev) == &e100_driver) {
+				/* If net_device struct is allocated? */
+                                if (pci_get_drvdata(pdev))
+					e100_suspend(pdev, 3);
+
+			}
+		}
+        }
+        return NOTIFY_DONE;
+}
+
+static int
+e100_suspend(struct pci_dev *pcid, u32 state)
+{
+	struct net_device *netdev = pci_get_drvdata(pcid);
+	struct e100_private *bdp = netdev->priv;
+
+	e100_isolate_driver(bdp);
+	pci_save_state(pcid, bdp->pci_state);
+
+	/* If wol is enabled */
+	if (bdp->wolopts) {
+		e100_do_wol(pcid, bdp);
+		pci_enable_wake(pcid, 3, 1);	/* Enable PME for power state D3 */
+		pci_set_power_state(pcid, 3);	/* Set power state to D3.        */
+	} else {
+		/* Disable bus mastering */
+		pci_disable_device(pcid);
+		pci_set_power_state(pcid, state);
+	}
+	return 0;
+}
+
+static int
+e100_resume(struct pci_dev *pcid)
+{
+	struct net_device *netdev = pci_get_drvdata(pcid);
+	struct e100_private *bdp = netdev->priv;
+	u8 recover = false;
+	u8 full_init = false;
+
+	pci_set_power_state(pcid, 0);
+	pci_enable_wake(pcid, 0, 0);	/* Clear PME status and disable PME */
+	pci_restore_state(pcid, bdp->pci_state);
+
+	if (netif_running(netdev)) {
+		recover = true;
+	}
+
+	if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP)) {
+		full_init = true;
+	}
+
+	e100_deisolate_driver(bdp, recover, full_init);
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static void
+e100_get_mdix_status(struct e100_private *bdp)
+{	
+	if (bdp->rev_id < D102_REV_ID) {
+		if (netif_carrier_ok(bdp->device))
+			bdp->mdix_status = "MDI";				
+		else			
+			bdp->mdix_status = "None";
+	} else {	
+		u16 ctrl_reg;
+		/* Read the MDIX control register */
+		e100_mdi_read(bdp, MII_NCONFIG, bdp->phy_addr, &ctrl_reg);
+		if (ctrl_reg & MDI_MDIX_CONFIG_IS_OK) {
+			if (ctrl_reg & MDI_MDIX_STATUS)
+				bdp->mdix_status = "MDI-X";
+			else
+				bdp->mdix_status = "MDI";
+		} else
+			bdp->mdix_status = "None";
+	}
+}
+
+static void
+e100_do_hwi(struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+	u16 ctrl_reg;
+	int distance, open_circut, short_circut;
+
+	e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg);
+
+	distance = ctrl_reg & HWI_TEST_DISTANCE;
+	open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM;
+	short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM;
+
+	if ((distance == bdp->saved_distance) &&
+	    (open_circut == bdp->saved_open_circut) &&
+	    (short_circut == bdp->saved_short_circut)) 
+		bdp->saved_same++;
+	else {
+		bdp->saved_same = 0;
+		bdp->saved_distance = distance;
+		bdp->saved_open_circut = open_circut;
+		bdp->saved_short_circut = short_circut;
+	}
+		
+	if (bdp->saved_same == MAX_SAME_RESULTS) {
+		if ((open_circut && !(short_circut)) ||
+		    (!(open_circut) && short_circut)) {
+
+			u8 near_end = ((distance * HWI_REGISTER_GRANULARITY) <
+				       HWI_NEAR_END_BOUNDARY);
+			if (open_circut) {
+				if (near_end) 
+					bdp->cable_status = "Open Circut Near End";
+				else 
+					bdp->cable_status = "Open Circut Far End";
+			} else {
+				if (near_end) 
+					bdp->cable_status = "Short Circut Near End";
+				else 
+					bdp->cable_status = "Short Circut Far End";
+			}
+			goto done;
+		}
+	}
+	else if (bdp->saved_i == HWI_MAX_LOOP) {
+		bdp->cable_status = "Test failed";
+		goto done;
+	}
+		
+	/* Do another hwi test */
+	e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,
+		       (HWI_TEST_ENABLE | HWI_TEST_EXECUTE));
+	bdp->saved_i++;
+	/* relaunch hwi timer in 1 msec */
+	mod_timer(&(bdp->hwi_timer), jiffies + (HZ / 1000) );
+	return;
+
+done:
+	e100_hwi_restore(bdp);
+	bdp->hwi_started = 0;
+	return;
+}
+
+static void e100_hwi_restore(struct e100_private *bdp)
+{
+	u16 control = 0;
+
+	/* Restore speed, duplex and autoneg before */
+	/* hwi test, i.e., cable diagnostic         */
+	
+	/* Reset hwi test */
+        e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,					       HWI_RESET_ALL_MASK);
+				
+	if ((bdp->params.e100_speed_duplex == E100_AUTONEG) &&
+        	(bdp->rev_id >= D102_REV_ID)) 
+		/* Enable MDI/MDI-X auto switching */
+                e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
+			MDI_MDIX_AUTO_SWITCH_ENABLE);
+
+	switch (bdp->params.e100_speed_duplex) {
+	case E100_SPEED_10_HALF:
+		break;
+	case E100_SPEED_10_FULL:
+		control = BMCR_FULLDPLX;
+		break;
+	case E100_SPEED_100_HALF:
+		control = BMCR_SPEED100;
+		break;
+	case E100_SPEED_100_FULL:
+		control = BMCR_SPEED100 | BMCR_FULLDPLX;
+		break;
+	case E100_AUTONEG:
+		control = BMCR_ANENABLE | BMCR_ANRESTART;
+		break;
+	}
+	/* Restore original speed/duplex */
+	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control);
+	return;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e100/e100_phy.c linux-2.4.20/drivers/net/e100/e100_phy.c
--- linux-2.4.19/drivers/net/e100/e100_phy.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e100/e100_phy.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,1126 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+*******************************************************************************/
+
+#include "e100_phy.h"
+
+void e100_handle_zlock(struct e100_private *bdp);
+
+/* 
+ * Procedure:	e100_mdi_write
+ *
+ * Description: This routine will write a value to the specified MII register
+ *		of an external MDI compliant device (e.g. PHY 100).  The
+ *		command will execute in polled mode.
+ *
+ * Arguments:
+ *	bdp - Ptr to this card's e100_bdconfig structure
+ *	reg_addr - The MII register that we are writing to
+ *	phy_addr - The MDI address of the Phy component.
+ *	data - The value that we are writing to the MII register.
+ *
+ * Returns:
+ *	NOTHING
+ */
+int
+e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data)
+{
+	int e100_retry;
+	u32 temp_val;
+	unsigned int mdi_cntrl;
+
+	spin_lock_bh(&bdp->mdi_access_lock);
+	temp_val = (((u32) data) | (reg_addr << 16) |
+		    (phy_addr << 21) | (MDI_WRITE << 26));
+	writel(temp_val, &bdp->scb->scb_mdi_cntrl);
+	readw(&bdp->scb->scb_status);
+
+	/* wait 20usec before checking status */
+	udelay(20);
+
+	/* poll for the mdi write to complete */
+	e100_retry = E100_CMD_WAIT;
+	while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) {
+
+		udelay(20);
+		e100_retry--;
+	}
+	spin_unlock_bh(&bdp->mdi_access_lock);
+	if (mdi_cntrl & MDI_PHY_READY) 
+		return 0;
+	else {
+		printk(KERN_ERR "e100: MDI write timeout\n");
+		return 1;
+	}
+}
+
+/* 
+ * Procedure:	e100_mdi_read
+ *
+ * Description: This routine will read a value from the specified MII register
+ *		of an external MDI compliant device (e.g. PHY 100), and return
+ *		it to the calling routine.  The command will execute in polled
+ *		mode.
+ *
+ * Arguments:
+ *	bdp - Ptr to this card's e100_bdconfig structure
+ *	reg_addr - The MII register that we are reading from
+ *	phy_addr - The MDI address of the Phy component.
+ *
+ * Results:
+ *	data - The value that we read from the MII register.
+ *
+ * Returns:
+ *	NOTHING
+ */
+int
+e100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data)
+{
+	int e100_retry;
+	u32 temp_val;
+	unsigned int mdi_cntrl;
+
+	spin_lock_bh(&bdp->mdi_access_lock);
+	/* Issue the read command to the MDI control register. */
+	temp_val = ((reg_addr << 16) | (phy_addr << 21) | (MDI_READ << 26));
+	writel(temp_val, &bdp->scb->scb_mdi_cntrl);
+	readw(&bdp->scb->scb_status);
+
+	/* wait 20usec before checking status */
+	udelay(20);
+
+	/* poll for the mdi read to complete */
+	e100_retry = E100_CMD_WAIT;
+	while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) {
+
+		udelay(20);
+		e100_retry--;
+	}
+
+	spin_unlock_bh(&bdp->mdi_access_lock);
+	if (mdi_cntrl & MDI_PHY_READY) {
+		/* return the lower word */
+		*data = (u16) mdi_cntrl;
+		return 0;
+	}
+	else {
+		printk(KERN_ERR "e100: MDI read timeout\n");
+		return 1;
+	}
+}
+
+static unsigned char __devinit
+e100_phy_valid(struct e100_private *bdp, unsigned int phy_address)
+{
+	u16 ctrl_reg, stat_reg;
+
+	/* Read the MDI control register */
+	e100_mdi_read(bdp, MII_BMCR, phy_address, &ctrl_reg);
+
+	/* Read the status register twice, bacause of sticky bits */
+	e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg);
+	e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg);
+
+	if ((ctrl_reg == 0xffff) || ((stat_reg == 0) && (ctrl_reg == 0)))
+		return false;
+
+	return true;
+}
+
+static void __devinit
+e100_phy_address_detect(struct e100_private *bdp)
+{
+	unsigned int addr;
+	unsigned char valid_phy_found = false;
+
+	if (IS_NC3133(bdp)) {
+		bdp->phy_addr = 0;
+		return;
+	}
+
+	if (e100_phy_valid(bdp, PHY_DEFAULT_ADDRESS)) {
+		bdp->phy_addr = PHY_DEFAULT_ADDRESS;
+		valid_phy_found = true;
+
+	} else {
+		for (addr = MIN_PHY_ADDR; addr <= MAX_PHY_ADDR; addr++) {
+			if (e100_phy_valid(bdp, addr)) {
+				bdp->phy_addr = addr;
+				valid_phy_found = true;
+				break;
+			}
+		}
+	}
+
+	if (!valid_phy_found) {
+		bdp->phy_addr = PHY_ADDRESS_503;
+	}
+}
+
+static void __devinit
+e100_phy_id_detect(struct e100_private *bdp)
+{
+	u16 low_id_reg, high_id_reg;
+
+	if (bdp->phy_addr == PHY_ADDRESS_503) {
+		bdp->PhyId = PHY_503;
+		return;
+	}
+	if (!(bdp->flags & IS_ICH)) {
+		if (bdp->rev_id >= D102_REV_ID) {
+			bdp->PhyId = PHY_82562ET;
+			return;
+		}
+	}
+
+	/* Read phy id from the MII register */
+	e100_mdi_read(bdp, MII_PHYSID1, bdp->phy_addr, &low_id_reg);
+	e100_mdi_read(bdp, MII_PHYSID2, bdp->phy_addr, &high_id_reg);
+
+	bdp->PhyId = ((unsigned int) low_id_reg |
+		      ((unsigned int) high_id_reg << 16));
+}
+
+static void __devinit
+e100_phy_isolate(struct e100_private *bdp)
+{
+	unsigned int phy_address;
+	u16 ctrl_reg;
+
+	/* Go over all phy addresses. Deisolate the selected one, and isolate
+	 * all the rest */
+	for (phy_address = 0; phy_address <= MAX_PHY_ADDR; phy_address++) {
+		if (phy_address != bdp->phy_addr) {
+			e100_mdi_write(bdp, MII_BMCR, phy_address,
+				       BMCR_ISOLATE);
+
+		} else {
+			e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &ctrl_reg);
+			ctrl_reg &= ~BMCR_ISOLATE;
+			e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
+		}
+
+		udelay(100);
+	}
+}
+
+static unsigned char __devinit
+e100_phy_specific_setup(struct e100_private *bdp)
+{
+	u16 misc_reg;
+
+	if (bdp->phy_addr == PHY_ADDRESS_503) {
+		switch (bdp->params.e100_speed_duplex) {
+		case E100_AUTONEG:
+			/* The adapter can't autoneg. so set to 10/HALF */
+			printk(KERN_INFO
+			       "e100: 503 serial component detected which "
+			       "cannot autonegotiate\n");
+			printk(KERN_INFO
+			       "e100: speed/duplex forced to "
+			       "10Mbps / Half duplex\n");
+			bdp->params.e100_speed_duplex = E100_SPEED_10_HALF;
+			break;
+
+		case E100_SPEED_100_HALF:
+		case E100_SPEED_100_FULL:
+			printk(KERN_ERR
+			       "e100: 503 serial component detected "
+			       "which does not support 100Mbps\n");
+			printk(KERN_ERR
+			       "e100: Change the forced speed/duplex "
+			       "to a supported setting\n");
+			return false;
+		}
+
+		return true;
+	}
+
+	if (IS_NC3133(bdp)) {
+		u16 int_reg;
+
+		/* enable 100BASE fiber interface */
+		e100_mdi_write(bdp, MDI_NC3133_CONFIG_REG, bdp->phy_addr,
+			       MDI_NC3133_100FX_ENABLE);
+
+		if ((bdp->params.e100_speed_duplex != E100_AUTONEG) &&
+		    (bdp->params.e100_speed_duplex != E100_SPEED_100_FULL)) {
+			/* just inform user about 100 full */
+			printk(KERN_ERR "e100: NC3133 NIC can only run "
+			       "at 100Mbps full duplex\n");
+		}
+
+		bdp->params.e100_speed_duplex = E100_SPEED_100_FULL;
+
+		/* enable interrupts */
+		e100_mdi_read(bdp, MDI_NC3133_INT_ENABLE_REG,
+			      bdp->phy_addr, &int_reg);
+		int_reg |= MDI_NC3133_INT_ENABLE;
+		e100_mdi_write(bdp, MDI_NC3133_INT_ENABLE_REG,
+			       bdp->phy_addr, int_reg);
+	}
+
+	/* Handle the National TX */
+	if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_NSC_TX) {
+		e100_mdi_read(bdp, NSC_CONG_CONTROL_REG,
+			      bdp->phy_addr, &misc_reg);
+
+		misc_reg |= NSC_TX_CONG_TXREADY;
+
+		/* disable the congestion control bit in the National Phy */
+		misc_reg &= ~NSC_TX_CONG_ENABLE;
+
+		e100_mdi_write(bdp, NSC_CONG_CONTROL_REG,
+			       bdp->phy_addr, misc_reg);
+	}
+
+	return true;
+}
+
+/* 
+ * Procedure:	e100_phy_fix_squelch
+ *
+ * Description:
+ *	Help find link on certain rare scenarios.
+ *	NOTE: This routine must be called once per watchdog,
+ *	      and *after* setting the current link state.
+ *
+ * Arguments:
+ *	bdp - Ptr to this card's e100_bdconfig structure
+ *
+ * Returns:
+ *	NOTHING
+ */
+static void
+e100_phy_fix_squelch(struct e100_private *bdp)
+{
+	if ((bdp->PhyId != PHY_82555_TX) || (bdp->flags & DF_SPEED_FORCED))
+		return;
+
+	if (netif_carrier_ok(bdp->device)) {
+		switch (bdp->PhyState) {
+		case 0:
+			break;
+		case 1:
+			e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
+				       bdp->phy_addr, 0x0000);
+			break;
+		case 2:
+			e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+				       bdp->phy_addr, 0x3000);
+			break;
+		}
+		bdp->PhyState = 0;
+		bdp->PhyDelay = 0;
+
+	} else if (!bdp->PhyDelay--) {
+		switch (bdp->PhyState) {
+		case 0:
+			e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
+				       bdp->phy_addr, EXTENDED_SQUELCH_BIT);
+			bdp->PhyState = 1;
+			break;
+		case 1:
+			e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
+				       bdp->phy_addr, 0x0000);
+			e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+				       bdp->phy_addr, 0x2010);
+			bdp->PhyState = 2;
+			break;
+		case 2:
+			e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+				       bdp->phy_addr, 0x3000);
+			bdp->PhyState = 0;
+			break;
+		}
+
+		e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
+			       BMCR_ANENABLE | BMCR_ANRESTART);
+		bdp->PhyDelay = 3;
+	}
+}
+
+/* 
+ * Procedure:	e100_fix_polarity
+ *
+ * Description:
+ *	Fix for 82555 auto-polarity toggle problem. With a short cable 
+ *	connecting an 82555 with an 840A link partner, if the medium is noisy,
+ *	the 82555 sometime thinks that the polarity might be wrong and so 
+ *	toggles polarity. This happens repeatedly and results in a high bit 
+ *	error rate.
+ *	NOTE: This happens only at 10 Mbps
+ *
+ * Arguments:
+ *	bdp - Ptr to this card's e100_bdconfig structure
+ *
+ * Returns:
+ *	NOTHING
+ */
+static void __devinit
+e100_fix_polarity(struct e100_private *bdp)
+{
+	u16 status;
+	u16 errors;
+	u16 misc_reg;
+	int speed;
+
+	if ((bdp->PhyId != PHY_82555_TX) && (bdp->PhyId != PHY_82562ET) &&
+	    (bdp->PhyId != PHY_82562EM))
+		return;
+
+	/* If the user wants auto-polarity disabled, do only that and nothing *
+	 * else. * e100_autopolarity == 0 means disable --- we do just the
+	 * disabling * e100_autopolarity == 1 means enable  --- we do nothing at
+	 * all * e100_autopolarity >= 2 means we do the workaround code. */
+	/* Change for 82558 enhancement */
+	switch (E100_AUTOPOLARITY) {
+	case 0:
+		e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,
+			      bdp->phy_addr, &misc_reg);
+		e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr,
+			       (u16) (misc_reg | DISABLE_AUTO_POLARITY));
+		break;
+
+	case 1:
+		e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,
+			      bdp->phy_addr, &misc_reg);
+		e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr,
+			       (u16) (misc_reg & ~DISABLE_AUTO_POLARITY));
+		break;
+
+	case 2:
+		/* we do this only if link is up */
+		if (!netif_carrier_ok(bdp->device)) {
+			break;
+		}
+
+		e100_mdi_read(bdp, PHY_82555_CSR, bdp->phy_addr, &status);
+		speed = (status & PHY_82555_SPEED_BIT) ? 100 : 10;
+
+		/* we need to do this only if speed is 10 */
+		if (speed != 10) {
+			break;
+		}
+
+		/* see if we have any end of frame errors */
+		e100_mdi_read(bdp, PHY_82555_EOF_COUNTER,
+			      bdp->phy_addr, &errors);
+
+		/* if non-zero, wait for 100 ms before reading again */
+		if (errors) {
+			udelay(200);
+			e100_mdi_read(bdp, PHY_82555_EOF_COUNTER,
+				      bdp->phy_addr, &errors);
+
+			/* if non-zero again, we disable polarity */
+			if (errors) {
+				e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,
+					      bdp->phy_addr, &misc_reg);
+				e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
+					       bdp->phy_addr,
+					       (u16) (misc_reg |
+						      DISABLE_AUTO_POLARITY));
+			}
+		}
+
+		if (!errors) {
+			/* it is safe to read the polarity now */
+			e100_mdi_read(bdp, PHY_82555_CSR,
+				      bdp->phy_addr, &status);
+
+			/* if polarity is normal, disable polarity */
+			if (!(status & PHY_82555_POLARITY_BIT)) {
+				e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,
+					      bdp->phy_addr, &misc_reg);
+				e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
+					       bdp->phy_addr,
+					       (u16) (misc_reg |
+						      DISABLE_AUTO_POLARITY));
+			}
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+/* 
+ * Procedure:	e100_find_speed_duplex
+ *
+ * Description: This routine will figure out what line speed and duplex mode
+ *		the PHY is currently using.
+ *
+ * Arguments:
+ *	bdp - Ptr to this card's e100_bdconfig structure
+ *
+ * Returns:
+ *	NOTHING
+ */
+static void
+e100_find_speed_duplex(struct e100_private *bdp)
+{
+	unsigned int PhyId;
+	u16 stat_reg, misc_reg;
+	u16 ad_reg, lp_ad_reg;
+
+	PhyId = bdp->PhyId & PHY_MODEL_REV_ID_MASK;
+
+	/* First we should check to see if we have link */
+	/* If we don't have a link no reason to print a speed and duplex */
+	if (!e100_update_link_state(bdp)) {
+		bdp->cur_line_speed = 0;
+		bdp->cur_dplx_mode = 0;
+		return;
+	}
+
+	/* On the 82559 and later controllers, speed/duplex is part of the *
+	 * SCB. So, we save an mdi_read and get these from the SCB. * */
+	if (bdp->rev_id >= D101MA_REV_ID) {
+		/* Read speed */
+		if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_1)
+			bdp->cur_line_speed = 100;
+		else
+			bdp->cur_line_speed = 10;
+
+		/* Read duplex */
+		if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_2)
+			bdp->cur_dplx_mode = FULL_DUPLEX;
+		else
+			bdp->cur_dplx_mode = HALF_DUPLEX;
+
+		return;
+	}
+
+	/* If this is a Phy 100, then read bits 1 and 0 of extended register 0,
+	 * to get the current speed and duplex settings. */
+	if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) ||
+	    (PhyId == PHY_82555_TX)) {
+
+		/* Read Phy 100 extended register 0 */
+		e100_mdi_read(bdp, EXTENDED_REG_0, bdp->phy_addr, &misc_reg);
+
+		/* Get current speed setting */
+		if (misc_reg & PHY_100_ER0_SPEED_INDIC)
+			bdp->cur_line_speed = 100;
+		else
+			bdp->cur_line_speed = 10;
+
+		/* Get current duplex setting -- FDX enabled if bit is set */
+		if (misc_reg & PHY_100_ER0_FDX_INDIC)
+			bdp->cur_dplx_mode = FULL_DUPLEX;
+		else
+			bdp->cur_dplx_mode = HALF_DUPLEX;
+
+		return;
+	}
+
+	/* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */
+	e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &misc_reg);
+
+	/* See if Auto-Negotiation was complete (bit 5, reg 1) */
+	e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
+
+	/* If a True NWAY connection was made, then we can detect speed/dplx
+	 * by ANDing our adapter's advertised abilities with our link partner's
+	 * advertised ablilities, and then assuming that the highest common
+	 * denominator was chosed by NWAY. */
+	if ((misc_reg & EXPANSION_NWAY) && (stat_reg & BMSR_ANEGCOMPLETE)) {
+
+		/* Read our advertisement register */
+		e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg);
+
+		/* Read our link partner's advertisement register */
+		e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg);
+
+		/* AND the two advertisement registers together, and get rid
+		 * of any extraneous bits. */
+		ad_reg &= (lp_ad_reg & NWAY_LP_ABILITY);
+
+		/* Get speed setting */
+		if (ad_reg &
+		    (ADVERTISE_100HALF | ADVERTISE_100FULL |
+		     ADVERTISE_100BASE4))
+
+			bdp->cur_line_speed = 100;
+		else
+			bdp->cur_line_speed = 10;
+
+		/* Get duplex setting -- use priority resolution algorithm */
+		if (ad_reg & ADVERTISE_100BASE4) {
+			bdp->cur_dplx_mode = HALF_DUPLEX;
+		} else if (ad_reg & ADVERTISE_100FULL) {
+			bdp->cur_dplx_mode = FULL_DUPLEX;
+		} else if (ad_reg & ADVERTISE_100HALF) {
+			bdp->cur_dplx_mode = HALF_DUPLEX;
+		} else if (ad_reg & ADVERTISE_10FULL) {
+			bdp->cur_dplx_mode = FULL_DUPLEX;
+		} else {
+			bdp->cur_dplx_mode = HALF_DUPLEX;
+		}
+
+		return;
+	}
+
+	/* If we are connected to a dumb (non-NWAY) repeater or hub, and the
+	 * line speed was determined automatically by parallel detection, then
+	 * we have no way of knowing exactly what speed the PHY is set to
+	 * unless that PHY has a propietary register which indicates speed in
+	 * this situation. The NSC TX PHY does have such a register. Also,
+	 * since NWAY didn't establish the connection, the duplex setting
+	 * should HALF duplex. */
+	bdp->cur_dplx_mode = HALF_DUPLEX;
+
+	if (PhyId == PHY_NSC_TX) {
+		/* Read register 25 to get the SPEED_10 bit */
+		e100_mdi_read(bdp, NSC_SPEED_IND_REG, bdp->phy_addr, &misc_reg);
+
+		/* If bit 6 was set then we're at 10Mbps */
+		if (misc_reg & NSC_TX_SPD_INDC_SPEED)
+			bdp->cur_line_speed = 10;
+		else
+			bdp->cur_line_speed = 100;
+
+	} else {
+		/* If we don't know the line speed, default to 10Mbps */
+		bdp->cur_line_speed = 10;
+	}
+}
+
+/* 
+ * Procedure: e100_force_speed_duplex
+ *
+ * Description: This routine forces line speed and duplex mode of the
+ * adapter based on the values the user has set in e100.c.
+ *
+ * Arguments:  bdp - Pointer to the e100_private structure for the board
+ *
+ * Returns: void
+ *
+ */
+void
+e100_force_speed_duplex(struct e100_private *bdp)
+{
+	u16 control;
+	unsigned long expires;
+
+	e100_phy_reset(bdp);
+
+	bdp->flags |= DF_SPEED_FORCED;
+
+	e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control);
+	control &= ~BMCR_ANENABLE;
+	control &= ~BMCR_LOOPBACK;
+
+	/* Check e100.c values */
+	switch (bdp->params.e100_speed_duplex) {
+	case E100_SPEED_10_HALF:
+		control &= ~BMCR_SPEED100;
+		control &= ~BMCR_FULLDPLX;
+		bdp->cur_line_speed = 10;
+		bdp->cur_dplx_mode = HALF_DUPLEX;
+		break;
+
+	case E100_SPEED_10_FULL:
+		control &= ~BMCR_SPEED100;
+		control |= BMCR_FULLDPLX;
+		bdp->cur_line_speed = 10;
+		bdp->cur_dplx_mode = FULL_DUPLEX;
+		break;
+
+	case E100_SPEED_100_HALF:
+		control |= BMCR_SPEED100;
+		control &= ~BMCR_FULLDPLX;
+		bdp->cur_line_speed = 100;
+		bdp->cur_dplx_mode = HALF_DUPLEX;
+		break;
+
+	case E100_SPEED_100_FULL:
+		control |= BMCR_SPEED100;
+		control |= BMCR_FULLDPLX;
+		bdp->cur_line_speed = 100;
+		bdp->cur_dplx_mode = FULL_DUPLEX;
+		break;
+	}
+
+	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control);
+
+	/* loop must run at least once */
+	expires = jiffies + 2 * HZ;
+	do {
+		if (e100_update_link_state(bdp) || 
+		    time_after(jiffies, expires)) {
+			break;
+		} else {
+			yield();
+		}
+
+	} while (true);
+}
+
+/* 
+ * Procedure: e100_set_fc
+ *
+ * Description: Checks the link's capability for flow control.
+ * 
+ * Arguments:  bdp - Pointer to the e100_private structure for the board
+ *		    
+ * Returns: void
+ *
+ */
+static void
+e100_set_fc(struct e100_private *bdp)
+{
+	u16 ad_reg;
+	u16 lp_ad_reg;
+	u16 exp_reg;
+
+	/* no flow control for 82557, forced links or half duplex */
+	if (!netif_carrier_ok(bdp->device) || (bdp->flags & DF_SPEED_FORCED) ||
+	    (bdp->cur_dplx_mode == HALF_DUPLEX) ||
+	    !(bdp->flags & IS_BACHELOR)) {
+
+		bdp->flags &= ~DF_LINK_FC_CAP;
+		return;
+	}
+
+	/* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */
+	e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &exp_reg);
+
+	if (exp_reg & EXPANSION_NWAY) {
+		/* Read our advertisement register */
+		e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg);
+
+		/* Read our link partner's advertisement register */
+		e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg);
+
+		ad_reg &= lp_ad_reg;	/* AND the 2 ad registers */
+
+		if (ad_reg & NWAY_AD_FC_SUPPORTED)
+			bdp->flags |= DF_LINK_FC_CAP;
+		else
+			/* If link partner is capable of autoneg, but  */
+			/* not capable of flow control, Received PAUSE */
+			/* frames are still honored, i.e.,             */
+		        /* transmitted frames would be paused */
+			/* by incoming PAUSE frames           */
+			bdp->flags |= DF_LINK_FC_TX_ONLY;
+
+	} else {
+		bdp->flags &= ~DF_LINK_FC_CAP;
+	}
+}
+
+/* 
+ * Procedure: e100_phy_check
+ * 
+ * Arguments:  bdp - Pointer to the e100_private structure for the board
+ *
+ * Returns: true if link state was changed
+ *	   false otherwise
+ *
+ */
+unsigned char
+e100_phy_check(struct e100_private *bdp)
+{
+	unsigned char old_link;
+	unsigned char changed = false;
+
+	old_link = netif_carrier_ok(bdp->device) ? 1 : 0;
+	e100_find_speed_duplex(bdp);
+
+	if (!old_link && netif_carrier_ok(bdp->device)) {
+		e100_set_fc(bdp);
+		changed = true;
+	}
+
+	if (old_link && !netif_carrier_ok(bdp->device)) {
+		/* reset the zero lock state */
+		bdp->zlock_state = ZLOCK_INITIAL;
+
+		// set auto lock for phy auto-negotiation on link up
+		if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_82555_TX)
+			e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+				       bdp->phy_addr, 0);
+		changed = true;
+	}
+
+	e100_phy_fix_squelch(bdp);
+	e100_handle_zlock(bdp);
+
+	return changed;
+}
+
+/* 
+ * Procedure:	e100_auto_neg
+ *
+ * Description: This routine will start autonegotiation and wait
+ *		     for it to complete
+ *
+ * Arguments:
+ *	bdp		- pointer to this card's e100_bdconfig structure
+ *	force_restart	- defines if autoneg should be restarted even if it
+ *			has been completed before
+ * Returns:
+ *	NOTHING
+ */
+static void
+e100_auto_neg(struct e100_private *bdp, unsigned char force_restart)
+{
+	u16 stat_reg;
+	unsigned long expires;
+
+	bdp->flags &= ~DF_SPEED_FORCED;
+
+	e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
+	e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
+
+	/* if we are capable of performing autoneg then we restart if needed */
+	if ((stat_reg != 0xFFFF) && (stat_reg & BMSR_ANEGCAPABLE)) {
+
+		if ((!force_restart) &&
+		    (stat_reg & BMSR_ANEGCOMPLETE)) {
+			goto exit;
+		}
+
+		e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
+			       BMCR_ANENABLE | BMCR_ANRESTART);
+
+		/* wait for autoneg to complete (up to 3 seconds) */
+		expires = jiffies + HZ * 3;
+		do {
+			/* now re-read the value. Sticky so read twice */
+			e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
+			e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
+
+			if ((stat_reg & BMSR_ANEGCOMPLETE) ||
+			    time_after(jiffies, expires) ) {
+				goto exit;
+			} else {
+				yield();
+			}
+		} while (true);
+	}
+
+exit:
+	e100_find_speed_duplex(bdp);
+}
+
+void
+e100_phy_set_speed_duplex(struct e100_private *bdp, unsigned char force_restart)
+{
+	if (bdp->params.e100_speed_duplex == E100_AUTONEG) {
+        	if (bdp->rev_id >= D102_REV_ID) 
+			/* Enable MDI/MDI-X auto switching */
+                	e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
+		                       MDI_MDIX_AUTO_SWITCH_ENABLE);
+		e100_auto_neg(bdp, force_restart);
+
+	} else {
+        	if (bdp->rev_id >= D102_REV_ID) 
+			/* Disable MDI/MDI-X auto switching */
+                	e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
+		                       MDI_MDIX_RESET_ALL_MASK);
+		e100_force_speed_duplex(bdp);
+	}
+
+	e100_set_fc(bdp);
+}
+
+void
+e100_phy_autoneg(struct e100_private *bdp)
+{
+	u16 ctrl_reg;
+
+	ctrl_reg = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET;
+
+	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
+
+	udelay(100);
+}
+
+void
+e100_phy_set_loopback(struct e100_private *bdp)
+{
+	u16 ctrl_reg;
+	ctrl_reg = BMCR_LOOPBACK;
+	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
+		udelay(100);
+}
+	
+void
+e100_phy_reset(struct e100_private *bdp)
+{
+	u16 ctrl_reg;
+	ctrl_reg = BMCR_RESET;
+	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
+}
+
+unsigned char __devinit
+e100_phy_init(struct e100_private *bdp)
+{
+	e100_phy_address_detect(bdp);
+	e100_phy_isolate(bdp);
+	e100_phy_id_detect(bdp);
+
+	if (!e100_phy_specific_setup(bdp))
+		return false;
+
+	bdp->PhyState = 0;
+	bdp->PhyDelay = 0;
+	bdp->zlock_state = ZLOCK_INITIAL;
+
+	e100_phy_set_speed_duplex(bdp, false);
+	e100_fix_polarity(bdp);
+
+	return true;
+}
+
+/* 
+ * Procedure: e100_get_link_state
+ * 
+ * Description: This routine checks the link status of the adapter
+ *
+ * Arguments:  bdp - Pointer to the e100_private structure for the board
+ *		    
+ *
+ * Returns: true - If a link is found
+ *		false - If there is no link
+ *
+ */
+unsigned char
+e100_get_link_state(struct e100_private *bdp)
+{
+	unsigned char link = false;
+	u16 status;
+
+	/* Check link status */
+	/* If the controller is a 82559 or later one, link status is available
+	 * from the CSR. This avoids the mdi_read. */
+	if (bdp->rev_id >= D101MA_REV_ID) {
+		if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_0) {
+			link = true;
+		} else {
+			link = false;
+		}
+
+	} else {
+		/* Read the status register twice because of sticky bits */
+		e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status);
+		e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status);
+
+		if (status & BMSR_LSTATUS) {
+			link = true;
+		} else {
+			link = false;
+		}
+	}
+
+	return link;
+}
+
+/* 
+ * Procedure: e100_update_link_state
+ * 
+ * Description: This routine updates the link status of the adapter,
+ * 		also considering netif_running
+ *
+ * Arguments:  bdp - Pointer to the e100_private structure for the board
+ *		    
+ *
+ * Returns: true - If a link is found
+ *		false - If there is no link
+ *
+ */
+unsigned char
+e100_update_link_state(struct e100_private *bdp)
+{
+	unsigned char link;
+
+	/* Logical AND PHY link & netif_running */
+	link = e100_get_link_state(bdp) && netif_running(bdp->device);
+
+	if (link) {
+		if (!netif_carrier_ok(bdp->device))
+			netif_carrier_on(bdp->device);
+	} else {
+		if (netif_carrier_ok(bdp->device))
+			netif_carrier_off(bdp->device);
+	}
+
+	return link;
+}
+
+/**************************************************************************\
+ **
+ ** PROC NAME:     e100_handle_zlock
+ **    This function manages a state machine that controls
+ **    the driver's zero locking algorithm.
+ **    This function is called by e100_watchdog() every ~2 second.
+ ** States:
+ **    The current link handling state is stored in 
+ **    bdp->zlock_state, and is one of:
+ **    ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING
+ **    Detailed description of the states and the transitions
+ **    between states is found below.
+ **    Note that any time the link is down / there is a reset
+ **    state will be changed outside this function to ZLOCK_INITIAL
+ ** Algorithm:
+ **    1. If link is up & 100 Mbps continue else stay in #1:
+ **    2. Set 'auto lock'
+ **    3. Read & Store 100 times 'Zero' locked in 1 sec interval
+ **    4. If max zero read >= 0xB continue else goto 1
+ **    5. Set most popular 'Zero' read in #3
+ **    6. Sleep 5 minutes
+ **    7. Read number of errors, if it is > 300 goto 2 else goto 6
+ ** Data Structures (in DRIVER_DATA):
+ **    zlock_state           - current state of the algorithm
+ **    zlock_read_cnt        - counts number of reads (up to 100)
+ **    zlock_read_data[i]    - counts number of times 'Zero' read was i, 0 <= i <= 15
+ **    zlock_sleep_cnt       - keeps track of "sleep" time (up to 300 secs = 5 minutes)
+ **                                
+ ** Parameters:    DRIVER_DATA    *bdp
+ **
+ **                bdp  - Pointer to HSM's adapter data space
+ **
+ ** Return Value:  NONE
+ **
+ ** See Also:      e100_watchdog()
+ **
+ \**************************************************************************/
+void
+e100_handle_zlock(struct e100_private *bdp)
+{
+	u16 pos;
+	u16 eq_reg;
+	u16 err_cnt;
+	u8 mpz;			/* Most Popular Zero */
+
+	switch (bdp->zlock_state) {
+	case ZLOCK_INITIAL:
+
+		if (((u8) bdp->rev_id <= D102_REV_ID) ||
+		    !(bdp->cur_line_speed == 100) ||
+		    !netif_carrier_ok(bdp->device)) {
+			break;
+		}
+
+		/* initialize hw and sw and start reading */
+		e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+			       bdp->phy_addr, 0);
+		/* reset read counters: */
+		bdp->zlock_read_cnt = 0;
+		for (pos = 0; pos < 16; pos++)
+			bdp->zlock_read_data[pos] = 0;
+		/* start reading in the next call back: */
+		bdp->zlock_state = ZLOCK_READING;
+
+		/* FALL THROUGH !! */
+
+	case ZLOCK_READING:
+		/* state: reading (100 times) zero locked in 1 sec interval
+		 * prev states: ZLOCK_INITIAL
+		 * next states: ZLOCK_INITIAL, ZLOCK_SLEEPING */
+
+		e100_mdi_read(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+			      bdp->phy_addr, &eq_reg);
+		pos = (eq_reg & ZLOCK_ZERO_MASK) >> 4;
+		bdp->zlock_read_data[pos]++;
+		bdp->zlock_read_cnt++;
+
+		if (bdp->zlock_read_cnt == ZLOCK_MAX_READS) {
+			/* check if we read a 'Zero' value of 0xB or greater */
+			if ((bdp->zlock_read_data[0xB]) ||
+			    (bdp->zlock_read_data[0xC]) ||
+			    (bdp->zlock_read_data[0xD]) ||
+			    (bdp->zlock_read_data[0xE]) ||
+			    (bdp->zlock_read_data[0xF])) {
+
+				/* we've read 'Zero' value of 0xB or greater,
+				 * find most popular 'Zero' value and lock it */
+				mpz = 0;
+				/* this loop finds the most popular 'Zero': */
+				for (pos = 1; pos < 16; pos++) {
+					if (bdp->zlock_read_data[pos] >
+					    bdp->zlock_read_data[mpz])
+
+						mpz = pos;
+				}
+				/* now lock the most popular 'Zero': */
+				eq_reg = (ZLOCK_SET_ZERO | mpz);
+				e100_mdi_write(bdp,
+					       PHY_82555_MDI_EQUALIZER_CSR,
+					       bdp->phy_addr, eq_reg);
+
+				/* sleep for 5 minutes: */
+				bdp->zlock_sleep_cnt = jiffies;
+				bdp->zlock_state = ZLOCK_SLEEPING;
+				/* we will be reading the # of errors after 5
+				 * minutes, so we need to reset the error
+				 * counters - these registers are self clearing
+				 * on read, so read them */
+				e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR,
+					      bdp->phy_addr, &err_cnt);
+
+			} else {
+				/* we did not read a 'Zero' value of 0xB or
+				 * above. go back to the start */
+				bdp->zlock_state = ZLOCK_INITIAL;
+			}
+
+		}
+		break;
+
+	case ZLOCK_SLEEPING:
+		/* state: sleeping for 5 minutes
+		 * prev states: ZLOCK_READING
+		 * next states: ZLOCK_READING, ZLOCK_SLEEPING */
+
+		/* if 5 minutes have passed: */
+		if ((jiffies - bdp->zlock_sleep_cnt) >= ZLOCK_MAX_SLEEP) {
+			/* read and sum up the number of errors:  */
+			e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR,
+				      bdp->phy_addr, &err_cnt);
+			/* if we've more than 300 errors (this number was
+			 * calculated according to the spec max allowed errors
+			 * (80 errors per 1 million frames) for 5 minutes in
+			 * 100 Mbps (or the user specified max BER number) */
+			if (err_cnt > bdp->params.ber) {
+				/* start again in the next callback: */
+				bdp->zlock_state = ZLOCK_INITIAL;
+			} else {
+				/* we don't have more errors than allowed,
+				 * sleep for 5 minutes */
+				bdp->zlock_sleep_cnt = jiffies;
+			}
+		}
+		break;
+
+	default:
+		break;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e100/e100_phy.h linux-2.4.20/drivers/net/e100/e100_phy.h
--- linux-2.4.19/drivers/net/e100/e100_phy.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e100/e100_phy.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,160 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+*******************************************************************************/
+
+#ifndef _E100_PHY_INC_
+#define _E100_PHY_INC_
+
+#include "e100.h"
+
+#include <linux/mii.h>
+
+/*
+ * Auto-polarity enable/disable
+ * e100_autopolarity = 0 => disable auto-polarity
+ * e100_autopolarity = 1 => enable auto-polarity
+ * e100_autopolarity = 2 => let software determine
+ */
+#define E100_AUTOPOLARITY 2
+
+#define IS_NC3133(bdp) (((bdp)->pdev->subsystem_vendor == 0x0E11) && \
+                        ((bdp)->pdev->subsystem_device == 0xB0E1))
+
+#define PHY_503                 0
+#define PHY_100_A               0x000003E0
+#define PHY_100_C               0x035002A8
+#define PHY_NSC_TX              0x5c002000
+#define PHY_82562ET             0x033002A8
+#define PHY_82562EM             0x032002A8
+#define PHY_82562EH             0x017002A8
+#define PHY_82555_TX            0x015002a8	/* added this for 82555 */
+#define PHY_OTHER               0xFFFF
+#define MAX_PHY_ADDR            31
+#define MIN_PHY_ADDR            0
+
+#define PHY_MODEL_REV_ID_MASK   0xFFF0FFFF
+
+#define PHY_DEFAULT_ADDRESS 1
+#define PHY_ADDRESS_503 32
+
+/* MDI Control register bit definitions */
+#define MDI_PHY_READY	    BIT_28	/* PHY is ready for next MDI cycle */
+
+#define MDI_NC3133_CONFIG_REG           0x19
+#define MDI_NC3133_100FX_ENABLE         BIT_2
+#define MDI_NC3133_INT_ENABLE_REG       0x17
+#define MDI_NC3133_INT_ENABLE           BIT_1
+
+/* MDI Control register opcode definitions */
+#define MDI_WRITE 1		/* Phy Write */
+#define MDI_READ  2		/* Phy read */
+
+/* MDI register set*/
+#define AUTO_NEG_NEXT_PAGE_REG	    0x07	/* Auto-negotiation next page xmit */
+#define EXTENDED_REG_0		    0x10	/* Extended reg 0 (Phy 100 modes) */
+#define EXTENDED_REG_1		    0x14	/* Extended reg 1 (Phy 100 error indications) */
+#define NSC_CONG_CONTROL_REG	    0x17	/* National (TX) congestion control */
+#define NSC_SPEED_IND_REG	    0x19	/* National (TX) speed indication */
+
+#define HWI_CONTROL_REG             0x1D	/* HWI Control register */
+/* MDI/MDI-X Control Register bit definitions */
+#define MDI_MDIX_RES_TIMER          BIT_0_3	/* minimum slot time for resolution timer */
+#define MDI_MDIX_CONFIG_IS_OK       BIT_4	/* 1 = resolution algorithm completes OK */
+#define MDI_MDIX_STATUS             BIT_5	/* 1 = MDIX (croos over), 0 = MDI (straight through) */
+#define MDI_MDIX_SWITCH             BIT_6	/* 1 = Forces to MDIX, 0 = Forces to MDI */
+#define MDI_MDIX_AUTO_SWITCH_ENABLE BIT_7	/* 1 = MDI/MDI-X feature enabled */
+#define MDI_MDIX_CONCT_CONFIG       BIT_8	/* Sets the MDI/MDI-X connectivity configuration (test prupose only) */
+#define MDI_MDIX_CONCT_TEST_ENABLE  BIT_9	/* 1 = Enables connectivity testing */
+#define MDI_MDIX_RESET_ALL_MASK     0x0000
+
+/* HWI Control Register bit definitions */
+#define HWI_TEST_DISTANCE           BIT_0_8	/* distance to cable problem */
+#define HWI_TEST_HIGHZ_PROBLEM      BIT_9	/* 1 = Open Circuit */
+#define HWI_TEST_LOWZ_PROBLEM       BIT_10	/* 1 = Short Circuit */
+#define HWI_TEST_RESERVED           (BIT_11 | BIT_12)	/* reserved */
+#define HWI_TEST_EXECUTE            BIT_13	/* 1 = Execute the HWI test on the PHY */
+#define HWI_TEST_ABILITY            BIT_14	/* 1 = test passed */
+#define HWI_TEST_ENABLE             BIT_15	/* 1 = Enables the HWI feature */
+#define HWI_RESET_ALL_MASK          0x0000
+
+/* ############Start of 82555 specific defines################## */
+
+/* Intel 82555 specific registers */
+#define PHY_82555_CSR		    0x10	/* 82555 CSR */
+#define PHY_82555_SPECIAL_CONTROL   0x11	/* 82555 special control register */
+
+#define PHY_82555_RCV_ERR	    0x15	/* 82555 100BaseTx Receive Error
+						 * Frame Counter */
+#define PHY_82555_SYMBOL_ERR	    0x16	/* 82555 RCV Symbol Error Counter */
+#define PHY_82555_PREM_EOF_ERR	    0x17	/* 82555 100BaseTx RCV Premature End
+						 * of Frame Error Counter */
+#define PHY_82555_EOF_COUNTER	    0x18	/* 82555 end of frame error counter */
+#define PHY_82555_MDI_EQUALIZER_CSR 0x1a	/* 82555 specific equalizer reg. */
+
+/* 82555 CSR bits */
+#define PHY_82555_SPEED_BIT    BIT_1
+#define PHY_82555_POLARITY_BIT BIT_8
+
+/* 82555 equalizer reg. opcodes */
+#define ENABLE_ZERO_FORCING  0x2010	/* write to ASD conf. reg. 0 */
+#define DISABLE_ZERO_FORCING 0x2000	/* write to ASD conf. reg. 0 */
+
+/* 82555 special control reg. opcodes */
+#define DISABLE_AUTO_POLARITY 0x0010
+#define EXTENDED_SQUELCH_BIT  BIT_2
+
+/* ############End of 82555 specific defines##################### */
+
+/* Auto-Negotiation advertisement register bit definitions*/
+#define NWAY_AD_FC_SUPPORTED    0x0400	/* Flow Control supported */
+
+/* Auto-Negotiation link partner ability register bit definitions*/
+#define NWAY_LP_ABILITY	        0x07e0	/* technologies supported */
+
+/* PHY 100 Extended Register 0 bit definitions*/
+#define PHY_100_ER0_FDX_INDIC	BIT_0	/* 1 = FDX, 0 = half duplex */
+#define PHY_100_ER0_SPEED_INDIC BIT_1	/* 1 = 100Mbps, 0= 10Mbps */
+
+/* National Semiconductor TX phy congestion control register bit definitions*/
+#define NSC_TX_CONG_TXREADY  BIT_10	/* Makes TxReady an input */
+#define NSC_TX_CONG_ENABLE   BIT_8	/* Enables congestion control */
+
+/* National Semiconductor TX phy speed indication register bit definitions*/
+#define NSC_TX_SPD_INDC_SPEED BIT_6	/* 0 = 100Mbps, 1=10Mbps */
+
+/************* function prototypes ************/
+extern unsigned char e100_phy_init(struct e100_private *bdp);
+extern unsigned char e100_update_link_state(struct e100_private *bdp);
+extern unsigned char e100_phy_check(struct e100_private *bdp);
+extern void e100_phy_set_speed_duplex(struct e100_private *bdp,
+				      unsigned char force_restart);
+extern void e100_phy_autoneg(struct e100_private *bdp);
+extern void e100_phy_reset(struct e100_private *bdp);
+extern void e100_phy_set_loopback(struct e100_private *bdp);
+extern int e100_mdi_write(struct e100_private *, u32, u32, u16);
+extern int e100_mdi_read(struct e100_private *, u32, u32, u16 *);
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e100/e100_proc.c linux-2.4.20/drivers/net/e100/e100_proc.c
--- linux-2.4.19/drivers/net/e100/e100_proc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e100/e100_proc.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,474 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+*******************************************************************************/
+
+/**********************************************************************
+*                                                                       *
+* INTEL CORPORATION                                                     *
+*                                                                       *
+* This software is supplied under the terms of the license included     *
+* above.  All use of this driver must be in accordance with the terms   *
+* of that license.                                                      *
+*                                                                       *
+* Module Name:  e100_proc.c                                             *
+*                                                                       *
+* Abstract:     Functions to handle the proc file system.               *
+*               Create the proc directories and files and run read and  *
+*               write requests from the user                            *
+*                                                                       *
+* Environment:  This file is intended to be specific to the Linux       *
+*               operating system.                                       *
+*                                                                       *
+**********************************************************************/
+
+#include <linux/config.h>
+
+#ifdef CONFIG_PROC_FS
+#include "e100.h"
+/* MDI sleep time is at least 50 ms, in jiffies */
+#define MDI_SLEEP_TIME ((HZ / 20) + 1)
+/***************************************************************************/
+/*       /proc File System Interaface Support Functions                    */
+/***************************************************************************/
+
+static struct proc_dir_entry *adapters_proc_dir = 0;
+
+/* externs from e100_main.c */
+extern char e100_short_driver_name[];
+extern char e100_driver_version[];
+extern struct net_device_stats *e100_get_stats(struct net_device *dev);
+extern char *e100_get_brand_msg(struct e100_private *bdp);
+extern int e100_mdi_write(struct e100_private *, u32, u32, u16);
+
+static void e100_proc_cleanup(void);
+static unsigned char e100_init_proc_dir(void);
+
+#define ADAPTERS_PROC_DIR "PRO_LAN_Adapters"
+#define WRITE_BUF_MAX_LEN 20	
+#define READ_BUF_MAX_LEN  256
+#define E100_PE_LEN       25
+
+#define bdp_drv_off(off) (unsigned long)(offsetof(struct e100_private, drv_stats.off))
+#define bdp_prm_off(off) (unsigned long)(offsetof(struct e100_private, params.off))
+
+typedef struct _e100_proc_entry {
+	char *name;
+	read_proc_t *read_proc;
+	write_proc_t *write_proc;
+	unsigned long offset;	/* offset into bdp. ~0 means no value, pass NULL. */
+} e100_proc_entry;
+
+static int
+generic_read(char *page, char **start, off_t off, int count, int *eof, int len)
+{
+	if (len <= off + count)
+		*eof = 1;
+
+	*start = page + off;
+	len -= off;
+	if (len > count)
+		len = count;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+
+static int
+read_ulong(char *page, char **start, off_t off,
+	   int count, int *eof, unsigned long l)
+{
+	int len;
+
+	len = sprintf(page, "%lu\n", l);
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_gen_ulong(char *page, char **start, off_t off,
+	       int count, int *eof, void *data)
+{
+	unsigned long val = 0;
+
+	if (data)
+		val = *((unsigned long *) data);
+
+	return read_ulong(page, start, off, count, eof, val);
+}
+
+static int
+read_hwaddr(char *page, char **start, off_t off,
+	    int count, int *eof, unsigned char *hwaddr)
+{
+	int len;
+
+	len = sprintf(page, "%02X:%02X:%02X:%02X:%02X:%02X\n",
+		      hwaddr[0], hwaddr[1], hwaddr[2],
+		      hwaddr[3], hwaddr[4], hwaddr[5]);
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_descr(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct e100_private *bdp = data;
+	int len;
+
+	len = sprintf(page, "%s\n", bdp->id_string);
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_permanent_hwaddr(char *page, char **start, off_t off,
+		      int count, int *eof, void *data)
+{
+	struct e100_private *bdp = data;
+	unsigned char *hwaddr = bdp->perm_node_address;
+
+	return read_hwaddr(page, start, off, count, eof, hwaddr);
+}
+
+static int
+read_part_number(char *page, char **start, off_t off,
+		 int count, int *eof, void *data)
+{
+	struct e100_private *bdp = data;
+	int len;
+
+	len = sprintf(page, "%06lx-%03x\n",
+		      (unsigned long) (bdp->pwa_no >> 8),
+		      (unsigned int) (bdp->pwa_no & 0xFF));
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static void
+set_led(struct e100_private *bdp, u16 led_mdi_op)
+{
+	e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
+		       bdp->phy_addr, led_mdi_op);
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(MDI_SLEEP_TIME);
+
+	/* turn led ownership to the chip */
+	e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
+		       bdp->phy_addr, PHY_82555_LED_NORMAL_CONTROL);
+}
+
+static int
+write_blink_led_timer(struct file *file, const char *buffer,
+		      unsigned long count, void *data)
+{
+	struct e100_private *bdp = data;
+	char s_blink_op[WRITE_BUF_MAX_LEN + 1];
+	char *res;
+	unsigned long i_blink_op;
+
+	if (!buffer)
+		return -EINVAL;
+
+	if (count > WRITE_BUF_MAX_LEN) {
+		count = WRITE_BUF_MAX_LEN;
+	}
+	if (copy_from_user(s_blink_op, buffer, count))
+		return -EFAULT;
+	s_blink_op[count] = '\0';
+	i_blink_op = simple_strtoul(s_blink_op, &res, 0);
+	if (res == s_blink_op) {
+		return -EINVAL;
+	}
+
+	switch (i_blink_op) {
+
+	case LED_OFF:
+		set_led(bdp, PHY_82555_LED_OFF);
+		break;
+	case LED_ON:
+		if (bdp->rev_id >= D101MA_REV_ID)
+			set_led(bdp, PHY_82555_LED_ON_559);
+		else
+			set_led(bdp, PHY_82555_LED_ON_PRE_559);
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static e100_proc_entry e100_proc_list[] = {
+	{"Description",           read_descr,            0, 0},
+	{"Permanent_HWaddr",      read_permanent_hwaddr, 0, 0},
+	{"Part_Number",           read_part_number,      0, 0},
+	{"\n",},
+	{"Rx_TCP_Checksum_Good",  read_gen_ulong, 0, ~0},
+	{"Rx_TCP_Checksum_Bad",   read_gen_ulong, 0, ~0},
+	{"Tx_TCP_Checksum_Good",  read_gen_ulong, 0, ~0},
+	{"Tx_TCP_Checksum_Bad",   read_gen_ulong, 0, ~0},
+	{"\n",},
+	{"Tx_Abort_Late_Coll",    read_gen_ulong, 0, bdp_drv_off(tx_late_col)},
+	{"Tx_Deferred_Ok",        read_gen_ulong, 0, bdp_drv_off(tx_ok_defrd)},
+	{"Tx_Single_Coll_Ok",     read_gen_ulong, 0, bdp_drv_off(tx_one_retry)},
+	{"Tx_Multi_Coll_Ok",      read_gen_ulong, 0, bdp_drv_off(tx_mt_one_retry)},
+	{"Rx_Long_Length_Errors", read_gen_ulong, 0, ~0},
+	{"\n",},
+	{"Tx_Flow_Control_Pause", read_gen_ulong, 0, bdp_drv_off(xmt_fc_pkts)},
+	{"Rx_Flow_Control_Pause", read_gen_ulong, 0, bdp_drv_off(rcv_fc_pkts)},
+	{"Rx_Flow_Control_Unsup", read_gen_ulong, 0, bdp_drv_off(rcv_fc_unsupported)},
+	{"\n",},
+	{"Tx_TCO_Packets",        read_gen_ulong, 0, bdp_drv_off(xmt_tco_pkts)},
+	{"Rx_TCO_Packets",        read_gen_ulong, 0, bdp_drv_off(rcv_tco_pkts)},
+	{"\n",},
+	{"Rx_Interrupt_Packets",  read_gen_ulong, 0, bdp_drv_off(rx_intr_pkts)},
+	{"Identify_Adapter", 0, write_blink_led_timer, 0},
+	{"", 0, 0, 0}
+};
+
+static int
+read_info(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct e100_private *bdp = data;
+	e100_proc_entry *pe;
+	int tmp;
+	void *val;
+	int len = 0;
+
+	for (pe = e100_proc_list; pe->name[0]; pe++) {
+		if (pe->name[0] == '\n') {
+			len += sprintf(page + len, "\n");
+			continue;
+		}
+
+		if (pe->read_proc) {
+			if ((len + READ_BUF_MAX_LEN + E100_PE_LEN + 1) >=
+			    PAGE_SIZE)
+				break;
+
+			if (pe->offset != ~0)
+				val = ((char *) bdp) + pe->offset;
+			else
+				val = NULL;
+
+			len += sprintf(page + len, "%-"
+				       __MODULE_STRING(E100_PE_LEN)
+				       "s ", pe->name);
+			len += pe->read_proc(page + len, start, 0,
+					     READ_BUF_MAX_LEN + 1, &tmp, val);
+		}
+	}
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static struct proc_dir_entry *
+create_proc_rw(char *name, void *data, struct proc_dir_entry *parent,
+	       read_proc_t * read_proc, write_proc_t * write_proc)
+{
+	struct proc_dir_entry *pdep;
+	mode_t mode = S_IFREG;
+
+	if (write_proc) {
+		mode |= S_IWUSR;
+		if (read_proc) {
+			mode |= S_IRUSR;
+		}
+
+	} else if (read_proc) {
+		mode |= S_IRUGO;
+	}
+
+	if (!(pdep = create_proc_entry(name, mode, parent)))
+		return NULL;
+
+	pdep->read_proc = read_proc;
+	pdep->write_proc = write_proc;
+	pdep->data = data;
+	return pdep;
+}
+
+void
+e100_remove_proc_subdir(struct e100_private *bdp, char *name)
+{
+	e100_proc_entry *pe;
+	char info[256];
+	int len;
+
+	/* If our root /proc dir was not created, there is nothing to remove */
+	if (adapters_proc_dir == NULL) {
+		return;
+	}
+
+	len = strlen(bdp->ifname);
+	strncpy(info, bdp->ifname, sizeof (info));
+	strncat(info + len, ".info", sizeof (info) - len);
+
+	if (bdp->proc_parent) {
+		for (pe = e100_proc_list; pe->name[0]; pe++) {
+			if (pe->name[0] == '\n')
+				continue;
+
+			remove_proc_entry(pe->name, bdp->proc_parent);
+		}
+
+		remove_proc_entry(bdp->ifname, adapters_proc_dir);
+		bdp->proc_parent = NULL;
+	}
+
+	remove_proc_entry(info, adapters_proc_dir);
+
+	/* try to remove the main /proc dir, if it's empty */
+	e100_proc_cleanup();
+}
+
+int
+e100_create_proc_subdir(struct e100_private *bdp)
+{
+	struct proc_dir_entry *dev_dir;
+	e100_proc_entry *pe;
+	char info[256];
+	int len;
+	void *data;
+
+	/* create the main /proc dir if needed */
+	if (!adapters_proc_dir) {
+		if (!e100_init_proc_dir())
+			return -ENOMEM;
+	}
+
+	strncpy(info, bdp->ifname, sizeof (info));
+	len = strlen(info);
+	strncat(info + len, ".info", sizeof (info) - len);
+
+	/* info */
+	if (!(create_proc_rw(info, bdp, adapters_proc_dir, read_info, 0))) {
+		e100_proc_cleanup();
+		return -ENOMEM;
+	}
+
+	dev_dir = create_proc_entry(bdp->ifname, S_IFDIR,
+				    adapters_proc_dir);
+	bdp->proc_parent = dev_dir;
+
+	if (!dev_dir) {
+		e100_remove_proc_subdir(bdp, bdp->ifname);
+		return -ENOMEM;
+	}
+
+	for (pe = e100_proc_list; pe->name[0]; pe++) {
+		if (pe->name[0] == '\n')
+			continue;
+
+		if (pe->offset != ~0)
+			data = ((char *) bdp) + pe->offset;
+		else
+			data = NULL;
+
+		if (!(create_proc_rw(pe->name, data, dev_dir,
+				     pe->read_proc, pe->write_proc))) {
+			e100_remove_proc_subdir(bdp, bdp->ifname);
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ * Name:          e100_init_proc_dir
+ *
+ * Description:   This routine creates the top-level /proc directory for the
+ *                driver in /proc/net
+ *
+ * Arguments:     none
+ *
+ * Returns:       true on success, false on fail
+ *
+ ***************************************************************************/
+static unsigned char
+e100_init_proc_dir(void)
+{
+	int len;
+
+	/* first check if adapters_proc_dir already exists */
+	len = strlen(ADAPTERS_PROC_DIR);
+	for (adapters_proc_dir = proc_net->subdir;
+	     adapters_proc_dir; adapters_proc_dir = adapters_proc_dir->next) {
+
+		if ((adapters_proc_dir->namelen == len) &&
+		    (!memcmp(adapters_proc_dir->name, ADAPTERS_PROC_DIR, len)))
+			break;
+	}
+
+	if (!adapters_proc_dir)
+		adapters_proc_dir =
+			create_proc_entry(ADAPTERS_PROC_DIR, S_IFDIR, proc_net);
+
+	if (!adapters_proc_dir)
+		return false;
+
+	return true;
+}
+
+/****************************************************************************
+ * Name:          e100_proc_cleanup
+ *
+ * Description:   This routine clears the top-level /proc directory, if empty.
+ *
+ * Arguments:     none
+ *
+ * Returns:       none
+ *
+ ***************************************************************************/
+static void
+e100_proc_cleanup(void)
+{
+	struct proc_dir_entry *de;
+
+	if (adapters_proc_dir == NULL) {
+		return;
+	}
+
+	/* check if subdir list is empty before removing adapters_proc_dir */
+	for (de = adapters_proc_dir->subdir; de; de = de->next) {
+		/* ignore . and .. */
+		if (*(de->name) != '.')
+			break;
+	}
+
+	if (de)
+		return;
+
+	remove_proc_entry(ADAPTERS_PROC_DIR, proc_net);
+	adapters_proc_dir = NULL;
+}
+
+#endif /* CONFIG_PROC_FS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e100/e100_test.c linux-2.4.20/drivers/net/e100/e100_test.c
--- linux-2.4.19/drivers/net/e100/e100_test.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e100/e100_test.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,432 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+*******************************************************************************/
+
+#include "e100.h"
+#include "e100_config.h"
+
+extern u16 e100_eeprom_read(struct e100_private *, u16);
+extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8);
+extern void e100_phy_reset(struct e100_private *bdp);
+extern void e100_phy_autoneg(struct e100_private *bdp);
+extern void e100_phy_set_loopback(struct e100_private *bdp);
+extern void e100_force_speed_duplex(struct e100_private *bdp);
+
+static u8 e100_diag_selftest(struct net_device *);
+static u8 e100_diag_eeprom(struct net_device *);
+static u8 e100_diag_loopback(struct net_device *);
+
+static u8 e100_diag_one_loopback (struct net_device *, u8);
+static u8 e100_diag_rcv_loopback_pkt(struct e100_private *);
+static void e100_diag_config_loopback(struct e100_private *, u8, u8, u8 *,u8 *);
+static u8 e100_diag_loopback_alloc(struct e100_private *);
+static void e100_diag_loopback_cu_ru_exec(struct e100_private *);
+static u8 e100_diag_check_pkt(u8 *);
+static void e100_diag_loopback_free(struct e100_private *);
+
+#define LB_PACKET_SIZE 1500
+
+/**
+ * e100_run_diag - main test execution handler - checks mask of requests and calls the diag routines  
+ * @dev: atapter's net device data struct
+ * @test_info: array with test request mask also used to store test results
+ *
+ * RETURNS: updated flags field of struct ethtool_test
+ */
+u32
+e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags)
+{
+	struct e100_private* bdp = dev->priv;
+	u8 test_result = true;
+
+	e100_isolate_driver(bdp);
+
+	if (flags & ETH_TEST_FL_OFFLINE) {
+		u8 fail_mask;
+		
+		fail_mask = e100_diag_selftest(dev);
+		if (fail_mask) {
+			test_result = false;
+			if (fail_mask & REGISTER_TEST_FAIL)
+				test_info [E100_REG_TEST_FAIL] = true;
+			if (fail_mask & ROM_TEST_FAIL)
+				test_info [E100_ROM_TEST_FAIL] = true;
+			if (fail_mask & SELF_TEST_FAIL)
+				test_info [E100_MAC_TEST_FAIL] = true;
+			if (fail_mask & TEST_TIMEOUT)
+				test_info [E100_CHIP_TIMEOUT] = true;
+		}
+
+		fail_mask = e100_diag_loopback(dev);
+		if (fail_mask) {
+			test_result = false;
+			if (fail_mask & PHY_LOOPBACK)
+				test_info [E100_LPBK_PHY_FAIL] = true;
+			if (fail_mask & MAC_LOOPBACK)
+				test_info [E100_LPBK_MAC_FAIL] = true;
+		}
+	}
+
+	if (!e100_diag_eeprom(dev)) {
+		test_result = false;
+		test_info [E100_EEPROM_TEST_FAIL] = true;
+	}
+
+	/* fully recover only if the device is open*/
+	if (netif_running(dev))  {
+		e100_deisolate_driver(bdp, true, false);
+	} else {
+    		e100_deisolate_driver(bdp, false, false);
+	}
+	/*Let card recover from the test*/
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ * 2);
+
+	return flags | (test_result ? 0 : ETH_TEST_FL_FAILED);
+}
+
+/**
+ * e100_diag_selftest - run hardware selftest 
+ * @dev: atapter's net device data struct
+ */
+static u8
+e100_diag_selftest(struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+	u32 st_timeout, st_result;
+	u8 retval = 0;
+
+	if (!e100_selftest(bdp, &st_timeout, &st_result)) {
+		if (!st_timeout) {
+			if (st_result & CB_SELFTEST_REGISTER_BIT)
+				retval |= REGISTER_TEST_FAIL;
+			if (st_result & CB_SELFTEST_DIAG_BIT)
+				retval |= SELF_TEST_FAIL;
+			if (st_result & CB_SELFTEST_ROM_BIT)
+				retval |= ROM_TEST_FAIL;
+		} else {
+            		retval = TEST_TIMEOUT;
+		}
+	}
+
+	e100_hw_reset_recover(bdp,PORT_SOFTWARE_RESET);
+
+	return retval;
+}
+
+/**
+ * e100_diag_eeprom - validate eeprom checksum correctness
+ * @dev: atapter's net device data struct
+ *
+ */
+static u8
+e100_diag_eeprom (struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+	u16 i, eeprom_sum, eeprom_actual_csm;
+
+	for (i = 0, eeprom_sum = 0; i < (bdp->eeprom_size - 1); i++) {
+		eeprom_sum += e100_eeprom_read(bdp, i);
+	}
+
+	eeprom_actual_csm = e100_eeprom_read(bdp, bdp->eeprom_size - 1);
+
+	if (eeprom_actual_csm == (u16)(EEPROM_SUM - eeprom_sum)) {
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * e100_diag_loopback - performs loopback test  
+ * @dev: atapter's net device data struct
+ */
+static u8
+e100_diag_loopback (struct net_device *dev)
+{
+	u8 rc = 0;
+
+	if (!e100_diag_one_loopback(dev, PHY_LOOPBACK)) {
+		rc |= PHY_LOOPBACK;
+	}
+
+	if (!e100_diag_one_loopback(dev, MAC_LOOPBACK)) {
+		rc |= MAC_LOOPBACK;
+	}
+
+	return rc;
+}
+
+/**
+ * e100_diag_loopback - performs loopback test  
+ * @dev: atapter's net device data struct
+ * @mode: lopback test type
+ */
+static u8
+e100_diag_one_loopback (struct net_device *dev, u8 mode)
+{
+        struct e100_private *bdp = dev->priv;
+        u8 res = false;
+   	u8 saved_dynamic_tbd = false;
+   	u8 saved_extended_tcb = false;
+
+	if (!e100_diag_loopback_alloc(bdp))
+		return false;
+
+	/* change the config block to standard tcb and the correct loopback */
+        e100_diag_config_loopback(bdp, true, mode,
+				  &saved_extended_tcb, &saved_dynamic_tbd);
+
+	e100_diag_loopback_cu_ru_exec(bdp);
+
+        if (e100_diag_rcv_loopback_pkt(bdp)) {
+		res = true;
+	}
+
+        e100_diag_loopback_free(bdp);
+
+        /* change the config block to previous tcb mode and the no loopback */
+        e100_diag_config_loopback(bdp, false, mode,
+				  &saved_extended_tcb, &saved_dynamic_tbd);
+	return res;
+}
+
+/**
+ * e100_diag_config_loopback - setup/clear loopback before/after lpbk test
+ * @bdp: atapter's private data struct
+ * @set_loopback: true if the function is called to set lb
+ * @loopback_mode: the loopback mode(MAC or PHY)
+ * @tcb_extended: true if need to set extended tcb mode after clean loopback
+ * @dynamic_tbd: true if needed to set dynamic tbd mode after clean loopback
+ *
+ */
+void
+e100_diag_config_loopback(struct e100_private* bdp,
+			  u8 set_loopback,
+			  u8 loopback_mode,
+			  u8* tcb_extended,
+			  u8* dynamic_tbd)
+{
+	/* if set_loopback == true - we want to clear tcb_extended/dynamic_tbd.
+	 * the previous values are saved in the params tcb_extended/dynamic_tbd
+	 * if set_loopback == false - we want to restore previous value.
+	 */
+	if (set_loopback || (*tcb_extended))
+		  *tcb_extended = e100_config_tcb_ext_enable(bdp,*tcb_extended);
+
+	if (set_loopback || (*dynamic_tbd))
+		 *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd);
+
+	if (set_loopback) {
+		/* Configure loopback on MAC */
+		e100_config_loopback_mode(bdp,loopback_mode);
+	} else {
+		e100_config_loopback_mode(bdp,NO_LOOPBACK);
+	}
+
+	e100_config(bdp);
+
+	if (loopback_mode == PHY_LOOPBACK) {
+		if (set_loopback)
+                        /* Set PHY loopback mode */
+                        e100_phy_set_loopback(bdp);
+                else {	/* Back to normal speed and duplex */
+                	if (bdp->params.e100_speed_duplex == E100_AUTONEG)
+				/* Reset PHY and do autoneg */
+                        	e100_phy_autoneg(bdp);
+			else    
+				/* Reset PHY and force speed and duplex */
+				e100_force_speed_duplex(bdp);
+		}
+                /* Wait for PHY state change */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+                schedule_timeout(HZ);
+	} else { /* For MAC loopback wait 500 msec to take effect */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ / 2);
+	}
+}
+  
+/**
+ * e100_diag_loopback_alloc - alloc & initate tcb and rfd for the loopback
+ * @bdp: atapter's private data struct
+ *
+ */
+static u8
+e100_diag_loopback_alloc(struct e100_private *bdp)
+{
+	dma_addr_t dma_handle;
+	tcb_t *tcb;
+	rfd_t *rfd;
+	tbd_t *tbd;
+
+	/* tcb, tbd and transmit buffer are allocated */
+	tcb = pci_alloc_consistent(bdp->pdev,
+				   (sizeof (tcb_t) + sizeof (tbd_t) +
+				    LB_PACKET_SIZE),
+				   &dma_handle);
+        if (tcb == NULL)
+		return false;
+
+	memset(tcb, 0x00, sizeof (tcb_t) + sizeof (tbd_t) + LB_PACKET_SIZE);
+	tcb->tcb_phys = dma_handle;
+	tcb->tcb_hdr.cb_status = 0;
+	tcb->tcb_hdr.cb_cmd =
+		cpu_to_le16(CB_EL_BIT | CB_TRANSMIT | CB_TX_SF_BIT);
+	/* Next command is null */
+	tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(0xffffffff);
+	tcb->tcb_cnt = 0;
+	tcb->tcb_thrshld = bdp->tx_thld;
+	tcb->tcb_tbd_num = 1;
+	/* Set up tcb tbd pointer */
+	tcb->tcb_tbd_ptr = cpu_to_le32(tcb->tcb_phys + sizeof (tcb_t));
+	tbd = (tbd_t *) ((u8 *) tcb + sizeof (tcb_t));
+	/* Set up tbd transmit buffer */
+	tbd->tbd_buf_addr =
+		cpu_to_le32(le32_to_cpu(tcb->tcb_tbd_ptr) + sizeof (tbd_t));
+	tbd->tbd_buf_cnt = __constant_cpu_to_le16(1024);
+	/* The value of first 512 bytes is FF */
+	memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 512);
+	/* The value of second 512 bytes is BA */
+	memset((void *) ((u8 *) tbd + sizeof (tbd_t) + 512), 0xBA, 512);
+	wmb();
+	rfd = pci_alloc_consistent(bdp->pdev, sizeof (rfd_t), &dma_handle);
+
+	if (rfd == NULL) {
+		pci_free_consistent(bdp->pdev,
+				    sizeof (tcb_t) + sizeof (tbd_t) +
+				    LB_PACKET_SIZE, tcb, tcb->tcb_phys);
+		return false;
+	}
+
+	memset(rfd, 0x00, sizeof (rfd_t));
+
+	/* init all fields in rfd */
+	rfd->rfd_header.cb_cmd = cpu_to_le16(RFD_EL_BIT);
+	rfd->rfd_sz = cpu_to_le16(ETH_FRAME_LEN + CHKSUM_SIZE);
+	/* dma_handle is physical address of rfd */
+	bdp->loopback.dma_handle = dma_handle;
+	bdp->loopback.tcb = tcb;
+	bdp->loopback.rfd = rfd;
+	wmb();
+	return true;
+}
+
+/**
+ * e100_diag_loopback_cu_ru_exec - activates cu and ru to send & receive the pkt
+ * @bdp: atapter's private data struct
+ *
+ */
+static void
+e100_diag_loopback_cu_ru_exec(struct e100_private *bdp)
+{
+	/*load CU & RU base */ 
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE))
+		printk("e100: SCB_CUC_LOAD_BASE failed\n");
+	if(!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE))
+		printk("e100: SCB_RUC_LOAD_BASE failed!\n");
+	if(!e100_wait_exec_cmplx(bdp, bdp->loopback.dma_handle, SCB_RUC_START))
+		printk("e100: SCB_RUC_START failed!\n");
+
+	bdp->next_cu_cmd = START_WAIT;
+	e100_start_cu(bdp, bdp->loopback.tcb);
+	bdp->last_tcb = NULL;
+	rmb();
+}
+/**
+ * e100_diag_check_pkt - checks if a given packet is a loopback packet
+ * @bdp: atapter's private data struct
+ *
+ * Returns true if OK false otherwise.
+ */
+static u8
+e100_diag_check_pkt(u8 *datap)
+{
+	int i;
+	for (i = 0; i<512; i++) {
+		if( !((*datap)==0xFF && (*(datap + 512) == 0xBA)) ) {
+			printk (KERN_ERR "e100: check loopback packet failed at: %x\n", i);
+			return false;
+			}
+	}
+	printk (KERN_DEBUG "e100: Check received loopback packet OK\n");
+	return true;
+}
+
+/**
+ * e100_diag_rcv_loopback_pkt - waits for receive and checks lpbk packet
+ * @bdp: atapter's private data struct
+ *
+ * Returns true if OK false otherwise.
+ */
+static u8
+e100_diag_rcv_loopback_pkt(struct e100_private* bdp) 
+{    
+	rfd_t *rfdp;
+	u16 rfd_status;
+	unsigned long expires = jiffies + HZ * 2;
+
+        rfdp =bdp->loopback.rfd;
+
+        rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status);
+
+        while (!(rfd_status & RFD_STATUS_COMPLETE)) { 
+		if (time_before(jiffies, expires)) {
+			yield();
+			rmb();
+			rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status);
+		} else {
+			break;
+		}
+        }
+
+        if (rfd_status & RFD_STATUS_COMPLETE) {
+		printk(KERN_DEBUG "e100: Loopback packet received\n");
+                return e100_diag_check_pkt(((u8 *)rfdp+bdp->rfd_size));
+	}
+	else {
+		printk(KERN_ERR "e100: Loopback packet not received\n");
+		return false;
+	}
+}
+
+/**
+ * e100_diag_loopback_free - free data allocated for loopback pkt send/receive
+ * @bdp: atapter's private data struct
+ *
+ */
+static void
+e100_diag_loopback_free (struct e100_private *bdp)
+{
+        pci_free_consistent(bdp->pdev,
+			    sizeof(tcb_t) + sizeof(tbd_t) + LB_PACKET_SIZE,
+			    bdp->loopback.tcb, bdp->loopback.tcb->tcb_phys);
+
+        pci_free_consistent(bdp->pdev, sizeof(rfd_t), bdp->loopback.rfd,
+			    bdp->loopback.dma_handle);
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e100/e100_ucode.h linux-2.4.20/drivers/net/e100/e100_ucode.h
--- linux-2.4.19/drivers/net/e100/e100_ucode.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e100/e100_ucode.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,365 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+*******************************************************************************/
+
+#ifndef _E100_UCODE_H_
+#define _E100_UCODE_H_
+
+/*
+e100_ucode.h
+
+This file contains the loadable micro code arrays to implement receive 
+bundling on the D101 A-step, D101 B-step, D101M (B-step only), D101S, 
+D102 B-step, D102 B-step with TCO work around and D102 C-step.
+
+Each controller has its own specific micro code array.  The array for one 
+controller is totally incompatible with any other controller, and if used 
+will most likely cause the controller to lock up and stop responding to 
+the driver.  Each micro code array has its own parameter offsets (described 
+below), and they each have their own version number.
+*/
+
+/*************************************************************************
+*  CPUSaver parameters
+*
+*  All CPUSaver parameters are 16-bit literals that are part of a
+*  "move immediate value" instruction.  By changing the value of
+*  the literal in the instruction before the code is loaded, the
+*  driver can change algorithm.
+*
+*  CPUSAVER_DWORD - This is the location of the instruction that loads
+*    the dead-man timer with its inital value.  By writing a 16-bit
+*    value to the low word of this instruction, the driver can change
+*    the timer value.  The current default is either x600 or x800;
+*    experiments show that the value probably should stay within the
+*    range of x200 - x1000.
+*
+*  CPUSAVER_BUNDLE_MAX_DWORD - This is the location of the instruction
+*    that sets the maximum number of frames that will be bundled.  In
+*    some situations, such as the TCP windowing algorithm, it may be
+*    better to limit the growth of the bundle size than let it go as
+*    high as it can, because that could cause too much added latency.
+*    The default is six, because this is the number of packets in the
+*    default TCP window size.  A value of 1 would make CPUSaver indicate
+*    an interrupt for every frame received.  If you do not want to put
+*    a limit on the bundle size, set this value to xFFFF.
+*
+*  CPUSAVER_MIN_SIZE_DWORD - This is the location of the instruction
+*    that contains a bit-mask describing the minimum size frame that
+*    will be bundled.  The default masks the lower 7 bits, which means
+*    that any frame less than 128 bytes in length will not be bundled,
+*    but will instead immediately generate an interrupt.  This does
+*    not affect the current bundle in any way.  Any frame that is 128
+*    bytes or large will be bundled normally.  This feature is meant
+*    to provide immediate indication of ACK frames in a TCP environment.
+*    Customers were seeing poor performance when a machine with CPUSaver
+*    enabled was sending but not receiving.  The delay introduced when
+*    the ACKs were received was enough to reduce total throughput, because
+*    the sender would sit idle until the ACK was finally seen.
+*
+*    The current default is 0xFF80, which masks out the lower 7 bits.
+*    This means that any frame which is x7F (127) bytes or smaller
+*    will cause an immediate interrupt.  Because this value must be a 
+*    bit mask, there are only a few valid values that can be used.  To
+*    turn this feature off, the driver can write the value xFFFF to the
+*    lower word of this instruction (in the same way that the other
+*    parameters are used).  Likewise, a value of 0xF800 (2047) would
+*    cause an interrupt to be generated for every frame, because all
+*    standard Ethernet frames are <= 2047 bytes in length.
+*************************************************************************/
+
+#ifndef UCODE_MAX_DWORDS
+#define UCODE_MAX_DWORDS	134
+#endif
+
+/********************************************************/
+/*  CPUSaver micro code for the D101A                   */
+/********************************************************/
+
+/*  Version 2.0  */
+
+/*  This value is the same for both A and B step of 558.  */
+
+#define D101_CPUSAVER_TIMER_DWORD		72
+#define D101_CPUSAVER_BUNDLE_DWORD		UCODE_MAX_DWORDS
+#define D101_CPUSAVER_MIN_SIZE_DWORD		UCODE_MAX_DWORDS
+
+#define     D101_A_RCVBUNDLE_UCODE \
+{\
+0x03B301BB, 0x0046FFFF, 0xFFFFFFFF, 0x051DFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \
+0x000C0001, 0x00101212, 0x000C0008, 0x003801BC, \
+0x00000000, 0x00124818, 0x000C1000, 0x00220809, \
+0x00010200, 0x00124818, 0x000CFFFC, 0x003803B5, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x0024B81D, 0x00130836, 0x000C0001, \
+0x0026081C, 0x0020C81B, 0x00130824, 0x00222819, \
+0x00101213, 0x00041000, 0x003A03B3, 0x00010200, \
+0x00101B13, 0x00238081, 0x00213049, 0x0038003B, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x0024B83E, 0x00130826, 0x000C0001, \
+0x0026083B, 0x00010200, 0x00134824, 0x000C0001, \
+0x00101213, 0x00041000, 0x0038051E, 0x00101313, \
+0x00010400, 0x00380521, 0x00050600, 0x00100824, \
+0x00101310, 0x00041000, 0x00080600, 0x00101B10, \
+0x0038051E, 0x00000000, 0x00000000, 0x00000000  \
+}
+
+/********************************************************/
+/*  CPUSaver micro code for the D101B                   */
+/********************************************************/
+
+/*  Version 2.0  */
+
+#define     D101_B0_RCVBUNDLE_UCODE \
+{\
+0x03B401BC, 0x0047FFFF, 0xFFFFFFFF, 0x051EFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \
+0x000C0001, 0x00101B92, 0x000C0008, 0x003801BD, \
+0x00000000, 0x00124818, 0x000C1000, 0x00220809, \
+0x00010200, 0x00124818, 0x000CFFFC, 0x003803B6, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x0024B81D, 0x0013082F, 0x000C0001, \
+0x0026081C, 0x0020C81B, 0x00130837, 0x00222819, \
+0x00101B93, 0x00041000, 0x003A03B4, 0x00010200, \
+0x00101793, 0x00238082, 0x0021304A, 0x0038003C, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x0024B83E, 0x00130826, 0x000C0001, \
+0x0026083B, 0x00010200, 0x00134837, 0x000C0001, \
+0x00101B93, 0x00041000, 0x0038051F, 0x00101313, \
+0x00010400, 0x00380522, 0x00050600, 0x00100837, \
+0x00101310, 0x00041000, 0x00080600, 0x00101790, \
+0x0038051F, 0x00000000, 0x00000000, 0x00000000  \
+}
+
+/********************************************************/
+/*  CPUSaver micro code for the D101M (B-step only)     */
+/********************************************************/
+
+/*  Version 2.10.1  */
+
+/*  Parameter values for the D101M B-step  */
+#define D101M_CPUSAVER_TIMER_DWORD		78
+#define D101M_CPUSAVER_BUNDLE_DWORD		65
+#define D101M_CPUSAVER_MIN_SIZE_DWORD		126
+
+#define D101M_B_RCVBUNDLE_UCODE \
+{\
+0x00550215, 0xFFFF0437, 0xFFFFFFFF, 0x06A70789, 0xFFFFFFFF, 0x0558FFFF, \
+0x000C0001, 0x00101312, 0x000C0008, 0x00380216, \
+0x0010009C, 0x00204056, 0x002380CC, 0x00380056, \
+0x0010009C, 0x00244C0B, 0x00000800, 0x00124818, \
+0x00380438, 0x00000000, 0x00140000, 0x00380555, \
+0x00308000, 0x00100662, 0x00100561, 0x000E0408, \
+0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
+0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
+0x000C007E, 0x00222C21, 0x000C0002, 0x00103093, \
+0x00380C7A, 0x00080000, 0x00103090, 0x00380C7A, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x00244C2D, 0x00010004, 0x00041000, \
+0x003A0437, 0x00044010, 0x0038078A, 0x00000000, \
+0x00100099, 0x00206C7A, 0x0010009C, 0x00244C48, \
+0x00130824, 0x000C0001, 0x00101213, 0x00260C75, \
+0x00041000, 0x00010004, 0x00130826, 0x000C0006, \
+0x002206A8, 0x0013C926, 0x00101313, 0x003806A8, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
+0x00101210, 0x00380C34, 0x00000000, 0x00000000, \
+0x0021155B, 0x00100099, 0x00206559, 0x0010009C, \
+0x00244559, 0x00130836, 0x000C0000, 0x00220C62, \
+0x000C0001, 0x00101B13, 0x00229C0E, 0x00210C0E, \
+0x00226C0E, 0x00216C0E, 0x0022FC0E, 0x00215C0E, \
+0x00214C0E, 0x00380555, 0x00010004, 0x00041000, \
+0x00278C67, 0x00040800, 0x00018100, 0x003A0437, \
+0x00130826, 0x000C0001, 0x00220559, 0x00101313, \
+0x00380559, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00130831, 0x0010090B, 0x00124813, \
+0x000CFF80, 0x002606AB, 0x00041000, 0x00010004, \
+0x003806A8, 0x00000000, 0x00000000, 0x00000000, \
+}
+
+/********************************************************/
+/*  CPUSaver micro code for the D101S                   */
+/********************************************************/
+
+/*  Version 1.20.1  */
+
+/*  Parameter values for the D101S  */
+#define D101S_CPUSAVER_TIMER_DWORD		78
+#define D101S_CPUSAVER_BUNDLE_DWORD		67
+#define D101S_CPUSAVER_MIN_SIZE_DWORD		128
+
+#define D101S_RCVBUNDLE_UCODE \
+{\
+0x00550242, 0xFFFF047E, 0xFFFFFFFF, 0x06FF0818, 0xFFFFFFFF, 0x05A6FFFF, \
+0x000C0001, 0x00101312, 0x000C0008, 0x00380243, \
+0x0010009C, 0x00204056, 0x002380D0, 0x00380056, \
+0x0010009C, 0x00244F8B, 0x00000800, 0x00124818, \
+0x0038047F, 0x00000000, 0x00140000, 0x003805A3, \
+0x00308000, 0x00100610, 0x00100561, 0x000E0408, \
+0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
+0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
+0x000C007E, 0x00222FA1, 0x000C0002, 0x00103093, \
+0x00380F90, 0x00080000, 0x00103090, 0x00380F90, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x00244FAD, 0x00010004, 0x00041000, \
+0x003A047E, 0x00044010, 0x00380819, 0x00000000, \
+0x00100099, 0x00206FFD, 0x0010009A, 0x0020AFFD, \
+0x0010009C, 0x00244FC8, 0x00130824, 0x000C0001, \
+0x00101213, 0x00260FF7, 0x00041000, 0x00010004, \
+0x00130826, 0x000C0006, 0x00220700, 0x0013C926, \
+0x00101313, 0x00380700, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
+0x00101210, 0x00380FB6, 0x00000000, 0x00000000, \
+0x002115A9, 0x00100099, 0x002065A7, 0x0010009A, \
+0x0020A5A7, 0x0010009C, 0x002445A7, 0x00130836, \
+0x000C0000, 0x00220FE4, 0x000C0001, 0x00101B13, \
+0x00229F8E, 0x00210F8E, 0x00226F8E, 0x00216F8E, \
+0x0022FF8E, 0x00215F8E, 0x00214F8E, 0x003805A3, \
+0x00010004, 0x00041000, 0x00278FE9, 0x00040800, \
+0x00018100, 0x003A047E, 0x00130826, 0x000C0001, \
+0x002205A7, 0x00101313, 0x003805A7, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00130831, \
+0x0010090B, 0x00124813, 0x000CFF80, 0x00260703, \
+0x00041000, 0x00010004, 0x00380700  \
+}
+
+/********************************************************/
+/*  CPUSaver micro code for the D102 B-step             */
+/********************************************************/
+
+/*  Version 2.0  */
+/*  Parameter values for the D102 B-step  */
+#define D102_B_CPUSAVER_TIMER_DWORD		82
+#define D102_B_CPUSAVER_BUNDLE_DWORD		106
+#define D102_B_CPUSAVER_MIN_SIZE_DWORD		70
+
+#define     D102_B_RCVBUNDLE_UCODE \
+{\
+0x006F0276, 0x0EF71FFF, 0x0ED30F86, 0x0D250ED9, 0x1FFF1FFF, 0x1FFF04D2, \
+0x00300001, 0x0140D871, 0x00300008, 0x00E00277, \
+0x01406C57, 0x00816073, 0x008700FA, 0x00E00070, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x01406CBA, 0x00807F9A, 0x00901F9A, 0x0024FFFF, \
+0x014B6F6F, 0x0030FFFE, 0x01407172, 0x01496FBA, \
+0x014B6F72, 0x00308000, 0x01406C52, 0x00912EFC, \
+0x00E00EF8, 0x00000000, 0x00000000, 0x00000000, \
+0x00906F8C, 0x00900F8C, 0x00E00F87, 0x00000000, \
+0x00906ED8, 0x01406C55, 0x00E00ED4, 0x00000000, \
+0x01406C51, 0x0080DFC2, 0x01406C52, 0x00815FC2, \
+0x01406C57, 0x00917FCC, 0x00E01FDD, 0x00000000, \
+0x00822D30, 0x01406C51, 0x0080CD26, 0x01406C52, \
+0x00814D26, 0x01406C57, 0x00916D26, 0x014C6FD7, \
+0x00300000, 0x00841FD2, 0x00300001, 0x0140D772, \
+0x00E012B3, 0x014C6F91, 0x0150710B, 0x01496F72, \
+0x0030FF80, 0x00940EDD, 0x00102000, 0x00038400, \
+0x00E00EDA, 0x00000000, 0x00000000, 0x00000000, \
+0x01406C57, 0x00917FE9, 0x00001000, 0x00E01FE9, \
+0x00200600, 0x0140D76F, 0x00138400, 0x01406FD8, \
+0x0140D96F, 0x00E01FDD, 0x00038400, 0x00102000, \
+0x00971FD7, 0x00101000, 0x00050200, 0x00E804D2, \
+0x014C6FD8, 0x00300001, 0x00840D26, 0x0140D872, \
+0x00E00D26, 0x014C6FD9, 0x00300001, 0x0140D972, \
+0x00941FBD, 0x00102000, 0x00038400, 0x014C6FD8, \
+0x00300006, 0x00840EDA, 0x014F71D8, 0x0140D872, \
+0x00E00EDA, 0x01496F50, 0x00E004D3, 0x00000000, \
+}
+
+/********************************************************/
+/*  Micro code for the D102 C-step                      */
+/********************************************************/
+
+/*  Parameter values for the D102 C-step  */
+#define D102_C_CPUSAVER_TIMER_DWORD		46
+#define D102_C_CPUSAVER_BUNDLE_DWORD		74
+#define D102_C_CPUSAVER_MIN_SIZE_DWORD		54
+
+#define     D102_C_RCVBUNDLE_UCODE \
+{ \
+0x00700279, 0x0E6604E2, 0x02BF0CAE, 0x1508150C, 0x15190E5B, 0x0E840F13, \
+0x00E014D8, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014DC, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014F4, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014E0, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014E7, 0x00000000, 0x00000000, 0x00000000, \
+0x00141000, 0x015D6F0D, 0x00E002C0, 0x00000000, \
+0x00200600, 0x00E0150D, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0030FF80, 0x00940E6A, 0x00038200, 0x00102000, \
+0x00E00E67, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00906E65, 0x00800E60, 0x00E00E5D, 0x00000000, \
+0x00300006, 0x00E0151A, 0x00000000, 0x00000000, \
+0x00906F19, 0x00900F19, 0x00E00F14, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x01406CBA, 0x00807FDA, 0x00901FDA, 0x0024FFFF, \
+0x014B6F6F, 0x0030FFFE, 0x01407172, 0x01496FBA, \
+0x014B6F72, 0x00308000, 0x01406C52, 0x00912E89, \
+0x00E00E85, 0x00000000, 0x00000000, 0x00000000  \
+}
+
+/********************************************************/
+/*  Micro code for the D102 E-step                      */
+/********************************************************/
+
+/*  Parameter values for the D102 E-step  */
+#define D102_E_CPUSAVER_TIMER_DWORD		42
+#define D102_E_CPUSAVER_BUNDLE_DWORD		54
+#define D102_E_CPUSAVER_MIN_SIZE_DWORD		46
+
+#define     D102_E_RCVBUNDLE_UCODE \
+{\
+0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x1FFF1FFF, 0x1FFF1FFF, \
+0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014C1, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014C8, 0x00000000, 0x00000000, 0x00000000, \
+0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \
+0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \
+0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \
+0x00300006, 0x00E014FB, 0x00000000, 0x00000000  \
+}
+
+#endif /* _E100_UCODE_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e100/e100_vendor.h linux-2.4.20/drivers/net/e100/e100_vendor.h
--- linux-2.4.19/drivers/net/e100/e100_vendor.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e100/e100_vendor.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,311 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+*******************************************************************************/
+
+#ifndef E100_VENDOR_ID_INFO
+#define E100_VENDOR_ID_INFO
+/* ====================================================================== */
+/*                              vendor_info                               */
+/* ====================================================================== */
+
+struct e100_vendor_info {
+	unsigned long device_type;
+	char *idstr;
+};
+
+enum e100_device_type {
+	E100_BRD_100TX = 1,
+	E100_BRD_100T4,
+	E100_BRD_10T,
+	E100_BRD_100WFM,
+	E100_BRD_82557,
+	E100_BRD_82557_WOL,
+	E100_BRD_82558,
+	E100_BRD_82558_WOL,
+	E100_BRD_100,
+	E100_BRD_100M,
+	E100_BRD_AOL2,
+	E100_BRD_AOL,
+	E100_PROS_M,
+	E100_PROS_AM,
+	E100_PROS_AM_AOL,
+	E100_PROS_DT,
+	E100_PRO_DT,
+	E100_PROM_DT,
+	E100_PRO_SRV,
+	E100_PRO_SRVP,
+	E100_PROS_SRV,
+	E100_PRO_DUAL,
+	E100_PROS_DUAL,
+	E100_PROP_DUAL,
+	E100_PROP_WOL,
+	E100_PROS_MOB,
+	E100_PRO_CB,
+	E100_PRO_CB_M,
+	E100_PROSR_MOB,
+	E100_PROS_MC,
+	E100_PROSR_MC,
+	E100_PROP_MC,
+	E100_PROSP_MC,
+	E100_PROP_MOB,
+	E100_PROSP_MOB,
+	E100_PRO_MINI,
+	E100_PRO_NET,
+	E100_PROS_NET,
+	E100_PROVM_NET,
+	E100_PROVE_D,
+	E100_82559_LOM,
+	E100_82559_LOM_AOL,
+	E100_82559_LOM_AOL2,
+	E100_82559_LOM_DELL,
+	E100_IBM_MDS,
+	E100_CMPQ_S,
+	E100_PROVE_DA,
+	E100_PROVM_DA,
+	E100_PROVE_LOM,
+	E100_PROVE_NET,
+	E100_82562,
+	E100_82551QM,
+	E100_ALL_BOARDS
+};
+
+struct e100_vendor_info e100_vendor_info_array[] = {
+	{ E100_BRD_100TX, "Intel(R) PRO/100B PCI Adapter (TX)"},
+	{ E100_BRD_100T4, "Intel(R) PRO/100B PCI Adapter (T4)"},
+	{ E100_BRD_10T, "Intel(R) PRO/10+ PCI Adapter"},
+	{ E100_BRD_100WFM, "Intel(R) PRO/100 WfM PCI Adapter"},
+	{ E100_BRD_82557, "Intel(R) 82557-based Integrated Ethernet PCI (10/100)"},
+	{ E100_BRD_82557_WOL, "Intel(R) 82557-based Integrated Ethernet with Wake on LAN*"},
+	{ E100_BRD_82558, "Intel(R) 82558-based Integrated Ethernet"},
+	{ E100_BRD_82558_WOL, "Intel(R) 82558-based Integrated Ethernet with Wake on LAN*"},
+	{ E100_BRD_100, "Intel(R) PRO/100+ PCI Adapter"},
+	{ E100_BRD_100M, "Intel(R) PRO/100+ Management Adapter"},
+	{ E100_BRD_AOL2, "Intel(R) PRO/100+ Alert on LAN* 2 Management Adapter"},
+	{ E100_82559_LOM_DELL, "Intel(R) 8255x Based Network Connection"},
+	{ E100_BRD_AOL, "Intel(R) PRO/100+ Alert on LAN* Management Adapter"},
+	{ E100_PROS_M, "Intel(R) PRO/100 S Management Adapter"},
+	{ E100_PROS_AM, "Intel(R) PRO/100 S Advanced Management Adapter"},
+	{ E100_PROS_AM_AOL, "Intel(R) PRO/100+ Management Adapter with Alert On LAN* GC"},
+	{ E100_PROS_DT, "Intel(R) PRO/100 S Desktop Adapter"},
+	{ E100_PRO_DT, "Intel(R) PRO/100 Desktop Adapter"},
+	{ E100_PROM_DT, "Intel(R) PRO/100 M Desktop Adapter"},
+	{ E100_PRO_SRV, "Intel(R) PRO/100+ Server Adapter"},
+	{ E100_PRO_SRVP, "Intel(R) PRO/100+ Server Adapter (PILA8470B)"},
+	{ E100_PROS_SRV, "Intel(R) PRO/100 S Server Adapter"},
+	{ E100_PRO_DUAL, "Intel(R) PRO/100 Dual Port Server Adapter"},
+	{ E100_PROS_DUAL, "Intel(R) PRO/100 S Dual Port Server Adapter"},
+	{ E100_PROP_DUAL, "Intel(R) PRO/100+ Dual Port Server Adapter"},
+	{ E100_PROP_WOL, "Intel(R) PRO/100+ Management Adapter with Alert On LAN* G Server"},
+	{ E100_PROS_MOB, "Intel(R) PRO/100 S Mobile Adapter"},
+	{ E100_PRO_CB, "Intel(R) PRO/100 CardBus II"},
+	{ E100_PRO_CB_M, "Intel(R) PRO/100 LAN+Modem56 CardBus II"},
+	{ E100_PROSR_MOB, "Intel(R) PRO/100 SR Mobile Adapter"},
+	{ E100_PROS_MC, "Intel(R) PRO/100 S Mobile Combo Adapter"},
+	{ E100_PROSR_MC, "Intel(R) PRO/100 SR Mobile Combo Adapter"},
+	{ E100_PROP_MC, "Intel(R) PRO/100 P Mobile Combo Adapter"},
+	{ E100_PROSP_MC, "Intel(R) PRO/100 SP Mobile Combo Adapter"},
+	{ E100_PROP_MOB, "Intel(R) PRO/100 P Mobile Adapter"},
+	{ E100_PROSP_MOB, "Intel(R) PRO/100 SP Mobile Adapter"},
+	{ E100_PRO_MINI, "Intel(R) PRO/100+ Mini PCI"},
+	{ E100_PRO_NET, "Intel(R) PRO/100 Network Connection" },
+	{ E100_PROS_NET, "Intel(R) PRO/100 S Network Connection" },
+	{ E100_PROVM_NET, "Intel(R) PRO/100 VM Network Connection"},
+	{ E100_PROVE_D, "Intel(R) PRO/100 VE Desktop Connection"},
+	{ E100_82559_LOM, "Intel(R) 82559 Fast Ethernet LAN on Motherboard"},
+	{ E100_82559_LOM_AOL, "Intel(R) 82559 Fast Ethernet LOM with Alert on LAN*" },
+	{ E100_82559_LOM_AOL2, "Intel(R) 82559 Fast Ethernet LOM with Alert on LAN* 2" },
+	{ E100_IBM_MDS, "IBM Mobile, Desktop & Server Adapters"},
+	{ E100_CMPQ_S, "Compaq Fast Ethernet Server Adapter" },
+	{ E100_PROVE_DA, "Intel(R) PRO/100 VE Desktop Adapter"},
+	{ E100_PROVM_DA, "Intel(R) PRO/100 VM Desktop Adapter"},
+	{ E100_PROVE_LOM, "Intel(R) PRO/100 VE Network ConnectionPLC LOM" },
+	{ E100_PROVE_NET, "Intel(R) PRO/100 VE Network Connection"},
+	{ E100_82562, "Intel(R)82562 based Fast Ethernet Connection"},
+	{ E100_82551QM, "Intel(R) PRO/100 M Mobile Connection"},
+	{ E100_ALL_BOARDS, "Intel(R) 8255x-based Ethernet Adapter"},
+	{0,NULL}
+};
+
+static struct pci_device_id e100_id_table[] __devinitdata = {
+	{0x8086, 0x1229, 0x8086, 0x0001, 0, 0, E100_BRD_100TX},
+	{0x8086, 0x1229, 0x8086, 0x0002, 0, 0, E100_BRD_100T4},
+	{0x8086, 0x1229, 0x8086, 0x0003, 0, 0, E100_BRD_10T},
+	{0x8086, 0x1229, 0x8086, 0x0004, 0, 0, E100_BRD_100WFM},
+	{0x8086, 0x1229, 0x8086, 0x0005, 0, 0, E100_BRD_82557},
+	{0x8086, 0x1229, 0x8086, 0x0006, 0, 0, E100_BRD_82557_WOL},
+	{0x8086, 0x1229, 0x8086, 0x0002, 0, 0, E100_BRD_100T4},
+	{0x8086, 0x1229, 0x8086, 0x0003, 0, 0, E100_BRD_10T},
+	{0x8086, 0x1229, 0x8086, 0x0004, 0, 0, E100_BRD_100WFM},
+	{0x8086, 0x1229, 0x8086, 0x0005, 0, 0, E100_BRD_82557},
+	{0x8086, 0x1229, 0x8086, 0x0006, 0, 0, E100_BRD_82557_WOL},
+	{0x8086, 0x1229, 0x8086, 0x0007, 0, 0, E100_BRD_82558},
+	{0x8086, 0x1229, 0x8086, 0x0008, 0, 0, E100_BRD_82558_WOL},
+	{0x8086, 0x1229, 0x8086, 0x0009, 0, 0, E100_BRD_100},
+	{0x8086, 0x1229, 0x8086, 0x000A, 0, 0, E100_BRD_100M},
+	{0x8086, 0x1229, 0x8086, 0x000B, 0, 0, E100_BRD_100},
+	{0x8086, 0x1229, 0x8086, 0x000C, 0, 0, E100_BRD_100M},
+	{0x8086, 0x1229, 0x8086, 0x000D, 0, 0, E100_BRD_AOL2},
+	{0x8086, 0x1229, 0x8086, 0x000E, 0, 0, E100_BRD_AOL},
+	{0x8086, 0x1229, 0x8086, 0x0010, 0, 0, E100_PROS_M},
+	{0x8086, 0x1229, 0x8086, 0x0011, 0, 0, E100_PROS_M},
+	{0x8086, 0x1229, 0x8086, 0x0012, 0, 0, E100_PROS_AM},
+	{0x8086, 0x1229, 0x8086, 0x0013, 0, 0, E100_PROS_AM},
+	{0x8086, 0x1229, 0x8086, 0x0030, 0, 0, E100_PROS_AM_AOL},
+	{0x8086, 0x1229, 0x8086, 0x0040, 0, 0, E100_PROS_DT},
+	{0x8086, 0x1229, 0x8086, 0x0041, 0, 0, E100_PROS_DT},
+	{0x8086, 0x1229, 0x8086, 0x0042, 0, 0, E100_PRO_DT},
+	{0x8086, 0x1229, 0x8086, 0x0050, 0, 0, E100_PROS_DT},
+	{0x8086, 0x1229, 0x8086, 0x0070, 0, 0, E100_PROM_DT},
+	{0x8086, 0x1229, 0x8086, 0x1009, 0, 0, E100_PRO_SRV},
+	{0x8086, 0x1229, 0x8086, 0x100C, 0, 0, E100_PRO_SRVP},
+	{0x8086, 0x1229, 0x8086, 0x1012, 0, 0, E100_PROS_SRV},
+	{0x8086, 0x1229, 0x8086, 0x1013, 0, 0, E100_PROS_SRV},
+	{0x8086, 0x1229, 0x8086, 0x1014, 0, 0, E100_PRO_DUAL},
+	{0x8086, 0x1229, 0x8086, 0x1015, 0, 0, E100_PROS_DUAL},
+	{0x8086, 0x1229, 0x8086, 0x1016, 0, 0, E100_PROS_DUAL},
+	{0x8086, 0x1229, 0x8086, 0x1017, 0, 0, E100_PROP_DUAL},
+	{0x8086, 0x1229, 0x8086, 0x1030, 0, 0, E100_PROP_WOL},
+	{0x8086, 0x1229, 0x8086, 0x1040, 0, 0, E100_PROS_SRV},
+	{0x8086, 0x1229, 0x8086, 0x1041, 0, 0, E100_PROS_SRV},
+	{0x8086, 0x1229, 0x8086, 0x1042, 0, 0, E100_PRO_SRV},
+	{0x8086, 0x1229, 0x8086, 0x1050, 0, 0, E100_PROS_SRV},
+	{0x8086, 0x1229, 0x8086, 0x10F0, 0, 0, E100_PROP_DUAL}, 
+	{0x8086, 0x1229, 0x8086, 0x10F0, 0, 0, E100_PROP_DUAL}, 
+	{0x8086, 0x1229, 0x8086, 0x2009, 0, 0, E100_PROS_MOB},
+	{0x8086, 0x1229, 0x8086, 0x200D, 0, 0, E100_PRO_CB},
+	{0x8086, 0x1229, 0x8086, 0x200E, 0, 0, E100_PRO_CB_M},
+	{0x8086, 0x1229, 0x8086, 0x200F, 0, 0, E100_PROSR_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2010, 0, 0, E100_PROS_MC},
+	{0x8086, 0x1229, 0x8086, 0x2013, 0, 0, E100_PROSR_MC},
+	{0x8086, 0x1229, 0x8086, 0x2016, 0, 0, E100_PROS_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2017, 0, 0, E100_PROS_MC},
+	{0x8086, 0x1229, 0x8086, 0x2018, 0, 0, E100_PROSR_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2019, 0, 0, E100_PROSR_MC},
+	{0x8086, 0x1229, 0x8086, 0x2101, 0, 0, E100_PROP_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2102, 0, 0, E100_PROSP_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2103, 0, 0, E100_PROSP_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2104, 0, 0, E100_PROSP_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2105, 0, 0, E100_PROSP_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2106, 0, 0, E100_PROP_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2107, 0, 0, E100_PRO_NET},
+	{0x8086, 0x1229, 0x8086, 0x2108, 0, 0, E100_PRO_NET},
+	{0x8086, 0x1229, 0x8086, 0x2200, 0, 0, E100_PROP_MC},
+	{0x8086, 0x1229, 0x8086, 0x2201, 0, 0, E100_PROP_MC},
+	{0x8086, 0x1229, 0x8086, 0x2202, 0, 0, E100_PROSP_MC},
+	{0x8086, 0x1229, 0x8086, 0x2203, 0, 0, E100_PRO_MINI},
+	{0x8086, 0x1229, 0x8086, 0x2204, 0, 0, E100_PRO_MINI},
+	{0x8086, 0x1229, 0x8086, 0x2205, 0, 0, E100_PROSP_MC},
+	{0x8086, 0x1229, 0x8086, 0x2206, 0, 0, E100_PROSP_MC},
+	{0x8086, 0x1229, 0x8086, 0x2207, 0, 0, E100_PROSP_MC},
+	{0x8086, 0x1229, 0x8086, 0x2208, 0, 0, E100_PROP_MC},
+	{0x8086, 0x1229, 0x8086, 0x2408, 0, 0, E100_PRO_MINI},
+	{0x8086, 0x1229, 0x8086, 0x240F, 0, 0, E100_PRO_MINI},
+	{0x8086, 0x1229, 0x8086, 0x2411, 0, 0, E100_PRO_MINI},
+	{0x8086, 0x1229, 0x8086, 0x3400, 0, 0, E100_82559_LOM},
+	{0x8086, 0x1229, 0x8086, 0x3000, 0, 0, E100_82559_LOM},
+	{0x8086, 0x1229, 0x8086, 0x3001, 0, 0, E100_82559_LOM_AOL},
+	{0x8086, 0x1229, 0x8086, 0x3002, 0, 0, E100_82559_LOM_AOL2},
+	{0x8086, 0x1229, 0x8086, 0x3006, 0, 0, E100_PROS_NET},
+	{0x8086, 0x1229, 0x8086, 0x3007, 0, 0, E100_PROS_NET},
+	{0x8086, 0x1229, 0x8086, 0x3008, 0, 0, E100_PRO_NET},
+	{0x8086, 0x1229, 0x8086, 0x3010, 0, 0, E100_PROS_NET},
+	{0x8086, 0x1229, 0x8086, 0x3011, 0, 0, E100_PROS_NET},
+	{0x8086, 0x1229, 0x8086, 0x3012, 0, 0, E100_PRO_NET},
+	{0x8086, 0x1229, 0x1014, 0x005C, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x305C, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x405C, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x605C, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x505C, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x105C, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x805C, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x705C, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x01F1, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x0232, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x0207, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x1014, 0x023F, 0, 0, E100_PRO_NET},   
+	{0x8086, 0x1229, 0x1014, 0x01BC, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x1014, 0x01CE, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x1014, 0x01DC, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x1014, 0x01EB, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x1014, 0x01EC, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x1014, 0x0202, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x1014, 0x0205, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x1014, 0x0217, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x0E11, 0xB01E, 0, 0, E100_CMPQ_S},         
+	{0x8086, 0x1229, 0x0E11, 0xB02F, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB04A, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB0C6, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB0C7, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB0D7, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB0DD, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB0DE, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB0E1, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB134, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB13C, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB144, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB163, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB164, 0, 0, E100_CMPQ_S},
+	{0x8086, 0x1229, 0x1028, PCI_ANY_ID, 0, 0, E100_82559_LOM_DELL},
+	{0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
+
+	{0x8086, 0x2449, 0x1014, 0x0265, 0, 0, E100_PROVE_D},
+	{0x8086, 0x2449, 0x1014, 0x0267, 0, 0, E100_PROVE_D},
+	{0x8086, 0x2449, 0x1014, 0x026A, 0, 0, E100_PROVE_D},
+	{0x8086, 0x2449, 0x8086, 0x3010, 0, 0, E100_PROVE_DA},
+	{0x8086, 0x2449, 0x8086, 0x3011, 0, 0, E100_PROVM_DA},
+	{0x8086, 0x2449, 0x8086, 0x3013, 0, 0, E100_PROVE_NET},
+	{0x8086, 0x2449, 0x8086, 0x3014, 0, 0, E100_PROVM_NET},
+	{0x8086, 0x2449, 0x8086, 0x3016, 0, 0, E100_PROP_MC},
+	{0x8086, 0x2449, 0x8086, 0x3017, 0, 0, E100_PROP_MOB},
+	{0x8086, 0x2449, 0x8086, 0x3018, 0, 0, E100_PRO_NET},
+	{0x8086, 0x2449, 0x0E11, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+	{0x8086, 0x2449, 0x1014, PCI_ANY_ID, 0, 0, E100_PROVE_D},	
+	{0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
+	
+	{0x8086, 0x1059, 0x1179, 0x0005, 0, 0, E100_82551QM},
+	{0x8086, 0x1059, 0x1033, 0x8191, 0, 0, E100_82551QM},
+	{0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82551QM},
+	
+	{0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
+  	{0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
+	{0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},	
+	{0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET}, 
+	{0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
+	{0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET}, 
+	{0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET}, 
+	{0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+	{0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
+	{0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
+	{0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+	{0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+	{0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
+	{0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+	{0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82562},
+	{0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82562},
+	{0,} /* This has to be the last entry*/
+};
+
+#endif /* E100_VENDOR_ID_INFO */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e1000/LICENSE linux-2.4.20/drivers/net/e1000/LICENSE
--- linux-2.4.19/drivers/net/e1000/LICENSE	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e1000/LICENSE	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,339 @@
+
+"This software program is licensed subject to the GNU General Public License 
+(GPL). Version 2, June 1991, available at 
+<http://www.fsf.org/copyleft/gpl.html>"
+
+GNU General Public License 
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.  
+59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to 
+share and change it. By contrast, the GNU General Public License is intended
+to guarantee your freedom to share and change free software--to make sure 
+the software is free for all its users. This General Public License applies 
+to most of the Free Software Foundation's software and to any other program 
+whose authors commit to using it. (Some other Free Software Foundation 
+software is covered by the GNU Library General Public License instead.) You 
+can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the freedom 
+to distribute copies of free software (and charge for this service if you 
+wish), that you receive source code or can get it if you want it, that you 
+can change the software or use pieces of it in new free programs; and that 
+you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to 
+deny you these rights or to ask you to surrender the rights. These 
+restrictions translate to certain responsibilities for you if you distribute
+copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or 
+for a fee, you must give the recipients all the rights that you have. You 
+must make sure that they, too, receive or can get the source code. And you 
+must show them these terms so they know their rights.
+ 
+We protect your rights with two steps: (1) copyright the software, and (2) 
+offer you this license which gives you legal permission to copy, distribute 
+and/or modify the software. 
+
+Also, for each author's protection and ours, we want to make certain that 
+everyone understands that there is no warranty for this free software. If 
+the software is modified by someone else and passed on, we want its 
+recipients to know that what they have is not the original, so that any 
+problems introduced by others will not reflect on the original authors' 
+reputations. 
+
+Finally, any free program is threatened constantly by software patents. We 
+wish to avoid the danger that redistributors of a free program will 
+individually obtain patent licenses, in effect making the program 
+proprietary. To prevent this, we have made it clear that any patent must be 
+licensed for everyone's free use or not licensed at all. 
+
+The precise terms and conditions for copying, distribution and modification 
+follow. 
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice
+   placed by the copyright holder saying it may be distributed under the 
+   terms of this General Public License. The "Program", below, refers to any
+   such program or work, and a "work based on the Program" means either the 
+   Program or any derivative work under copyright law: that is to say, a 
+   work containing the Program or a portion of it, either verbatim or with 
+   modifications and/or translated into another language. (Hereinafter, 
+   translation is included without limitation in the term "modification".) 
+   Each licensee is addressed as "you". 
+
+   Activities other than copying, distribution and modification are not 
+   covered by this License; they are outside its scope. The act of running 
+   the Program is not restricted, and the output from the Program is covered 
+   only if its contents constitute a work based on the Program (independent 
+   of having been made by running the Program). Whether that is true depends
+   on what the Program does. 
+
+1. You may copy and distribute verbatim copies of the Program's source code 
+   as you receive it, in any medium, provided that you conspicuously and 
+   appropriately publish on each copy an appropriate copyright notice and 
+   disclaimer of warranty; keep intact all the notices that refer to this 
+   License and to the absence of any warranty; and give any other recipients 
+   of the Program a copy of this License along with the Program. 
+
+   You may charge a fee for the physical act of transferring a copy, and you 
+   may at your option offer warranty protection in exchange for a fee. 
+
+2. You may modify your copy or copies of the Program or any portion of it, 
+   thus forming a work based on the Program, and copy and distribute such 
+   modifications or work under the terms of Section 1 above, provided that 
+   you also meet all of these conditions: 
+
+   * a) You must cause the modified files to carry prominent notices stating 
+        that you changed the files and the date of any change. 
+
+   * b) You must cause any work that you distribute or publish, that in 
+        whole or in part contains or is derived from the Program or any part 
+        thereof, to be licensed as a whole at no charge to all third parties
+        under the terms of this License. 
+
+   * c) If the modified program normally reads commands interactively when 
+        run, you must cause it, when started running for such interactive 
+        use in the most ordinary way, to print or display an announcement 
+        including an appropriate copyright notice and a notice that there is
+        no warranty (or else, saying that you provide a warranty) and that 
+        users may redistribute the program under these conditions, and 
+        telling the user how to view a copy of this License. (Exception: if 
+        the Program itself is interactive but does not normally print such 
+        an announcement, your work based on the Program is not required to 
+        print an announcement.) 
+
+   These requirements apply to the modified work as a whole. If identifiable 
+   sections of that work are not derived from the Program, and can be 
+   reasonably considered independent and separate works in themselves, then 
+   this License, and its terms, do not apply to those sections when you 
+   distribute them as separate works. But when you distribute the same 
+   sections as part of a whole which is a work based on the Program, the 
+   distribution of the whole must be on the terms of this License, whose 
+   permissions for other licensees extend to the entire whole, and thus to 
+   each and every part regardless of who wrote it. 
+
+   Thus, it is not the intent of this section to claim rights or contest 
+   your rights to work written entirely by you; rather, the intent is to 
+   exercise the right to control the distribution of derivative or 
+   collective works based on the Program. 
+
+   In addition, mere aggregation of another work not based on the Program 
+   with the Program (or with a work based on the Program) on a volume of a 
+   storage or distribution medium does not bring the other work under the 
+   scope of this License. 
+
+3. You may copy and distribute the Program (or a work based on it, under 
+   Section 2) in object code or executable form under the terms of Sections 
+   1 and 2 above provided that you also do one of the following: 
+
+   * a) Accompany it with the complete corresponding machine-readable source 
+        code, which must be distributed under the terms of Sections 1 and 2 
+        above on a medium customarily used for software interchange; or, 
+
+   * b) Accompany it with a written offer, valid for at least three years, 
+        to give any third party, for a charge no more than your cost of 
+        physically performing source distribution, a complete machine-
+        readable copy of the corresponding source code, to be distributed 
+        under the terms of Sections 1 and 2 above on a medium customarily 
+        used for software interchange; or, 
+
+   * c) Accompany it with the information you received as to the offer to 
+        distribute corresponding source code. (This alternative is allowed 
+        only for noncommercial distribution and only if you received the 
+        program in object code or executable form with such an offer, in 
+        accord with Subsection b above.) 
+
+   The source code for a work means the preferred form of the work for 
+   making modifications to it. For an executable work, complete source code 
+   means all the source code for all modules it contains, plus any 
+   associated interface definition files, plus the scripts used to control 
+   compilation and installation of the executable. However, as a special 
+   exception, the source code distributed need not include anything that is 
+   normally distributed (in either source or binary form) with the major 
+   components (compiler, kernel, and so on) of the operating system on which
+   the executable runs, unless that component itself accompanies the 
+   executable. 
+
+   If distribution of executable or object code is made by offering access 
+   to copy from a designated place, then offering equivalent access to copy 
+   the source code from the same place counts as distribution of the source 
+   code, even though third parties are not compelled to copy the source 
+   along with the object code. 
+
+4. You may not copy, modify, sublicense, or distribute the Program except as
+   expressly provided under this License. Any attempt otherwise to copy, 
+   modify, sublicense or distribute the Program is void, and will 
+   automatically terminate your rights under this License. However, parties 
+   who have received copies, or rights, from you under this License will not
+   have their licenses terminated so long as such parties remain in full 
+   compliance. 
+
+5. You are not required to accept this License, since you have not signed 
+   it. However, nothing else grants you permission to modify or distribute 
+   the Program or its derivative works. These actions are prohibited by law 
+   if you do not accept this License. Therefore, by modifying or 
+   distributing the Program (or any work based on the Program), you 
+   indicate your acceptance of this License to do so, and all its terms and
+   conditions for copying, distributing or modifying the Program or works 
+   based on it. 
+
+6. Each time you redistribute the Program (or any work based on the 
+   Program), the recipient automatically receives a license from the 
+   original licensor to copy, distribute or modify the Program subject to 
+   these terms and conditions. You may not impose any further restrictions 
+   on the recipients' exercise of the rights granted herein. You are not 
+   responsible for enforcing compliance by third parties to this License. 
+
+7. If, as a consequence of a court judgment or allegation of patent 
+   infringement or for any other reason (not limited to patent issues), 
+   conditions are imposed on you (whether by court order, agreement or 
+   otherwise) that contradict the conditions of this License, they do not 
+   excuse you from the conditions of this License. If you cannot distribute 
+   so as to satisfy simultaneously your obligations under this License and 
+   any other pertinent obligations, then as a consequence you may not 
+   distribute the Program at all. For example, if a patent license would 
+   not permit royalty-free redistribution of the Program by all those who 
+   receive copies directly or indirectly through you, then the only way you 
+   could satisfy both it and this License would be to refrain entirely from 
+   distribution of the Program. 
+
+   If any portion of this section is held invalid or unenforceable under any
+   particular circumstance, the balance of the section is intended to apply
+   and the section as a whole is intended to apply in other circumstances. 
+
+   It is not the purpose of this section to induce you to infringe any 
+   patents or other property right claims or to contest validity of any 
+   such claims; this section has the sole purpose of protecting the 
+   integrity of the free software distribution system, which is implemented 
+   by public license practices. Many people have made generous contributions
+   to the wide range of software distributed through that system in 
+   reliance on consistent application of that system; it is up to the 
+   author/donor to decide if he or she is willing to distribute software 
+   through any other system and a licensee cannot impose that choice. 
+
+   This section is intended to make thoroughly clear what is believed to be 
+   a consequence of the rest of this License. 
+
+8. If the distribution and/or use of the Program is restricted in certain 
+   countries either by patents or by copyrighted interfaces, the original 
+   copyright holder who places the Program under this License may add an 
+   explicit geographical distribution limitation excluding those countries, 
+   so that distribution is permitted only in or among countries not thus 
+   excluded. In such case, this License incorporates the limitation as if 
+   written in the body of this License. 
+
+9. The Free Software Foundation may publish revised and/or new versions of 
+   the General Public License from time to time. Such new versions will be 
+   similar in spirit to the present version, but may differ in detail to 
+   address new problems or concerns. 
+
+   Each version is given a distinguishing version number. If the Program 
+   specifies a version number of this License which applies to it and "any 
+   later version", you have the option of following the terms and 
+   conditions either of that version or of any later version published by 
+   the Free Software Foundation. If the Program does not specify a version 
+   number of this License, you may choose any version ever published by the 
+   Free Software Foundation. 
+
+10. If you wish to incorporate parts of the Program into other free programs
+    whose distribution conditions are different, write to the author to ask 
+    for permission. For software which is copyrighted by the Free Software 
+    Foundation, write to the Free Software Foundation; we sometimes make 
+    exceptions for this. Our decision will be guided by the two goals of 
+    preserving the free status of all derivatives of our free software and 
+    of promoting the sharing and reuse of software generally. 
+
+   NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 
+    FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 
+    OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 
+    PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
+    EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE 
+    ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH 
+    YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL 
+    NECESSARY SERVICING, REPAIR OR CORRECTION. 
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 
+    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 
+    REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR 
+    DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL 
+    DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM 
+    (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED 
+    INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF 
+    THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR 
+    OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest 
+possible use to the public, the best way to achieve this is to make it free 
+software which everyone can redistribute and change under these terms. 
+
+To do so, attach the following notices to the program. It is safest to 
+attach them to the start of each source file to most effectively convey the
+exclusion of warranty; and each file should have at least the "copyright" 
+line and a pointer to where the full notice is found. 
+
+one line to give the program's name and an idea of what it does.
+Copyright (C) yyyy  name of author
+
+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.
+
+Also add information on how to contact you by electronic and paper mail. 
+
+If the program is interactive, make it output a short notice like this when 
+it starts in an interactive mode: 
+
+Gnomovision version 69, Copyright (C) year name of author Gnomovision comes 
+with ABSOLUTELY NO WARRANTY; for details type 'show w'.  This is free 
+software, and you are welcome to redistribute it under certain conditions; 
+type 'show c' for details.
+
+The hypothetical commands 'show w' and 'show c' should show the appropriate 
+parts of the General Public License. Of course, the commands you use may be 
+called something other than 'show w' and 'show c'; they could even be 
+mouse-clicks or menu items--whatever suits your program. 
+
+You should also get your employer (if you work as a programmer) or your 
+school, if any, to sign a "copyright disclaimer" for the program, if 
+necessary. Here is a sample; alter the names: 
+
+Yoyodyne, Inc., hereby disclaims all copyright interest in the program 
+'Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+signature of Ty Coon, 1 April 1989
+Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into 
+proprietary programs. If your program is a subroutine library, you may 
+consider it more useful to permit linking proprietary applications with the 
+library. If this is what you want to do, use the GNU Library General Public 
+License instead of this License.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e1000/Makefile linux-2.4.20/drivers/net/e1000/Makefile
--- linux-2.4.19/drivers/net/e1000/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e1000/Makefile	2002-10-29 11:18:51.000000000 +0000
@@ -0,0 +1,39 @@
+################################################################################
+#
+# 
+# Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+# 
+# 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.
+# 
+# The full GNU General Public License is included in this distribution in the
+# file called LICENSE.
+# 
+# Contact Information:
+# Linux NICS <linux.nics@intel.com>
+# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+#
+################################################################################
+
+#
+# Makefile for the Intel(R) PRO/1000 ethernet driver
+#
+
+O_TARGET := e1000.o
+
+obj-y	:= e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o \
+	   e1000_proc.o
+obj-m	:= $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e1000/e1000.h linux-2.4.20/drivers/net/e1000/e1000.h
--- linux-2.4.19/drivers/net/e1000/e1000.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e1000/e1000.h	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,207 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+
+/* Linux PRO/1000 Ethernet Driver main header file */
+
+#ifndef _E1000_H_
+#define _E1000_H_
+
+#include <linux/stddef.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/pagemap.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/capability.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <net/pkt_sched.h>
+#include <linux/list.h>
+#include <linux/reboot.h>
+#include <linux/tqueue.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+
+#define BAR_0		0
+#define BAR_1		1
+#define BAR_5		5
+#define PCI_DMA_64BIT	0xffffffffffffffffULL
+#define PCI_DMA_32BIT	0x00000000ffffffffULL
+
+
+struct e1000_adapter;
+
+#include "e1000_hw.h"
+
+#if DBG
+#define E1000_DBG(args...) printk(KERN_DEBUG "e1000: " args)
+#else
+#define E1000_DBG(args...)
+#endif
+
+#define E1000_ERR(args...) printk(KERN_ERR "e1000: " args)
+
+#define E1000_MAX_INTR 10
+
+/* Supported Rx Buffer Sizes */
+#define E1000_RXBUFFER_2048  2048
+#define E1000_RXBUFFER_4096  4096
+#define E1000_RXBUFFER_8192  8192
+#define E1000_RXBUFFER_16384 16384
+
+/* Flow Control High-Watermark: 43464 bytes */
+#define E1000_FC_HIGH_THRESH 0xA9C8
+
+/* Flow Control Low-Watermark: 43456 bytes */
+#define E1000_FC_LOW_THRESH 0xA9C0
+
+/* Flow Control Pause Time: 858 usec */
+#define E1000_FC_PAUSE_TIME 0x0680
+
+/* How many Tx Descriptors do we need to call netif_wake_queue ? */
+#define E1000_TX_QUEUE_WAKE	16
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define E1000_RX_BUFFER_WRITE	16
+
+#define E1000_JUMBO_PBA      0x00000028
+#define E1000_DEFAULT_PBA    0x00000030
+
+#define AUTO_ALL_MODES       0
+
+/* only works for sizes that are powers of 2 */
+#define E1000_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1)))
+
+/* wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer */
+struct e1000_buffer {
+	struct sk_buff *skb;
+	uint64_t dma;
+	unsigned long length;
+	unsigned long time_stamp;
+};
+
+struct e1000_desc_ring {
+	/* pointer to the descriptor ring memory */
+	void *desc;
+	/* physical address of the descriptor ring */
+	dma_addr_t dma;
+	/* length of descriptor ring in bytes */
+	unsigned int size;
+	/* number of descriptors in the ring */
+	unsigned int count;
+	/* next descriptor to associate a buffer with */
+	unsigned int next_to_use;
+	/* next descriptor to check for DD status bit */
+	unsigned int next_to_clean;
+	/* array of buffer information structs */
+	struct e1000_buffer *buffer_info;
+};
+
+#define E1000_DESC_UNUSED(R) \
+((((R)->next_to_clean + (R)->count) - ((R)->next_to_use + 1)) % ((R)->count))
+
+#define E1000_GET_DESC(R, i, type)	(&(((struct type *)((R).desc))[i]))
+#define E1000_RX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_rx_desc)
+#define E1000_TX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_tx_desc)
+#define E1000_CONTEXT_DESC(R, i)	E1000_GET_DESC(R, i, e1000_context_desc)
+
+/* board specific private data structure */
+
+struct e1000_adapter {
+	struct timer_list watchdog_timer;
+	struct timer_list phy_info_timer;
+#ifdef CONFIG_PROC_FS
+	struct list_head proc_list_head;
+#endif
+	struct vlan_group *vlgrp;
+	char *id_string;
+	uint32_t bd_number;
+	uint32_t rx_buffer_len;
+	uint32_t part_num;
+	uint32_t wol;
+	uint16_t link_speed;
+	uint16_t link_duplex;
+	spinlock_t stats_lock;
+	atomic_t irq_sem;
+	struct tq_struct tx_timeout_task;
+
+	struct timer_list blink_timer;
+	unsigned long led_status;
+
+	/* TX */
+	struct e1000_desc_ring tx_ring;
+	uint32_t txd_cmd;
+	uint32_t tx_int_delay;
+	uint32_t tx_abs_int_delay;
+	int max_data_per_txd;
+
+	/* RX */
+	struct e1000_desc_ring rx_ring;
+	uint64_t hw_csum_err;
+	uint64_t hw_csum_good;
+	uint32_t rx_int_delay;
+	uint32_t rx_abs_int_delay;
+	boolean_t rx_csum;
+
+	/* OS defined structs */
+	struct net_device *netdev;
+	struct pci_dev *pdev;
+	struct net_device_stats net_stats;
+
+	/* structs defined in e1000_hw.h */
+	struct e1000_hw hw;
+	struct e1000_hw_stats stats;
+	struct e1000_phy_info phy_info;
+	struct e1000_phy_stats phy_stats;
+
+
+
+	uint32_t pci_state[16];
+	char ifname[IFNAMSIZ];
+};
+#endif /* _E1000_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e1000/e1000_ethtool.c linux-2.4.20/drivers/net/e1000/e1000_ethtool.c
--- linux-2.4.19/drivers/net/e1000/e1000_ethtool.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e1000/e1000_ethtool.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,538 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* ethtool support for e1000 */
+
+#include "e1000.h"
+
+#include <asm/uaccess.h>
+
+extern char e1000_driver_name[];
+extern char e1000_driver_version[];
+
+extern int e1000_up(struct e1000_adapter *adapter);
+extern void e1000_down(struct e1000_adapter *adapter);
+extern void e1000_reset(struct e1000_adapter *adapter);
+
+static void
+e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	if(hw->media_type == e1000_media_type_copper) {
+
+		ecmd->supported = (SUPPORTED_10baseT_Half |
+		                   SUPPORTED_10baseT_Full |
+		                   SUPPORTED_100baseT_Half |
+		                   SUPPORTED_100baseT_Full |
+		                   SUPPORTED_1000baseT_Full|
+		                   SUPPORTED_Autoneg |
+		                   SUPPORTED_TP);
+
+		ecmd->advertising = ADVERTISED_TP;
+
+		if(hw->autoneg == 1) {
+			ecmd->advertising |= ADVERTISED_Autoneg;
+
+			/* the e1000 autoneg seems to match ethtool nicely */
+
+			ecmd->advertising |= hw->autoneg_advertised;
+		}
+
+		ecmd->port = PORT_TP;
+		ecmd->phy_address = hw->phy_addr;
+
+		if(hw->mac_type == e1000_82543)
+			ecmd->transceiver = XCVR_EXTERNAL;
+		else
+			ecmd->transceiver = XCVR_INTERNAL;
+
+	} else {
+		ecmd->supported   = (SUPPORTED_1000baseT_Full |
+				     SUPPORTED_FIBRE |
+				     SUPPORTED_Autoneg);
+
+		ecmd->advertising = (SUPPORTED_1000baseT_Full |
+				     SUPPORTED_FIBRE |
+				     SUPPORTED_Autoneg);
+
+		ecmd->port = PORT_FIBRE;
+
+		if(hw->mac_type >= e1000_82545)
+			ecmd->transceiver = XCVR_INTERNAL;
+		else
+			ecmd->transceiver = XCVR_EXTERNAL;
+	}
+
+	if(netif_carrier_ok(adapter->netdev)) {
+
+		e1000_get_speed_and_duplex(hw, &adapter->link_speed,
+		                                   &adapter->link_duplex);
+		ecmd->speed = adapter->link_speed;
+
+		/* unfortunatly FULL_DUPLEX != DUPLEX_FULL
+		 *          and HALF_DUPLEX != DUPLEX_HALF */
+
+		if(adapter->link_duplex == FULL_DUPLEX)
+			ecmd->duplex = DUPLEX_FULL;
+		else
+			ecmd->duplex = DUPLEX_HALF;
+	} else {
+		ecmd->speed = -1;
+		ecmd->duplex = -1;
+	}
+
+	ecmd->autoneg = (hw->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
+}
+
+static int
+e1000_ethtool_sset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	if(ecmd->autoneg == AUTONEG_ENABLE) {
+		hw->autoneg = 1;
+		hw->autoneg_advertised = 0x002F;
+		ecmd->advertising = 0x002F;
+	} else {
+		hw->autoneg = 0;
+		switch(ecmd->speed + ecmd->duplex) {
+		case SPEED_10 + DUPLEX_HALF:
+			hw->forced_speed_duplex = e1000_10_half;
+			break;
+		case SPEED_10 + DUPLEX_FULL:
+			hw->forced_speed_duplex = e1000_10_full;
+			break;
+		case SPEED_100 + DUPLEX_HALF:
+			hw->forced_speed_duplex = e1000_100_half;
+			break;
+		case SPEED_100 + DUPLEX_FULL:
+			hw->forced_speed_duplex = e1000_100_full;
+			break;
+		case SPEED_1000 + DUPLEX_FULL:
+			hw->autoneg = 1;
+			hw->autoneg_advertised = ADVERTISE_1000_FULL;
+			break;
+		case SPEED_1000 + DUPLEX_HALF: /* not supported */
+		default:
+			return -EINVAL;
+		}
+	}
+
+	/* reset the link */
+
+	if(netif_running(adapter->netdev)) {
+		e1000_down(adapter);
+		e1000_up(adapter);
+	} else
+		e1000_reset(adapter);
+
+	return 0;
+}
+
+static inline int
+e1000_eeprom_size(struct e1000_hw *hw)
+{
+	if((hw->mac_type > e1000_82544) &&
+	   (E1000_READ_REG(hw, EECD) & E1000_EECD_SIZE))
+		return 512;
+	else
+		return 128;
+}
+
+static void
+e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter,
+                       struct ethtool_drvinfo *drvinfo)
+{
+	strncpy(drvinfo->driver,  e1000_driver_name, 32);
+	strncpy(drvinfo->version, e1000_driver_version, 32);
+	strncpy(drvinfo->fw_version, "N/A", 32);
+	strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32);
+#define E1000_REGS_LEN 32
+	drvinfo->regdump_len  = E1000_REGS_LEN * sizeof(uint32_t);
+	drvinfo->eedump_len  = e1000_eeprom_size(&adapter->hw);
+}
+
+static void
+e1000_ethtool_gregs(struct e1000_adapter *adapter,
+                    struct ethtool_regs *regs, uint32_t *regs_buff)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id;
+
+	regs_buff[0]  = E1000_READ_REG(hw, CTRL);
+	regs_buff[1]  = E1000_READ_REG(hw, STATUS);
+
+	regs_buff[2]  = E1000_READ_REG(hw, RCTL);
+	regs_buff[3]  = E1000_READ_REG(hw, RDLEN);
+	regs_buff[4]  = E1000_READ_REG(hw, RDH);
+	regs_buff[5]  = E1000_READ_REG(hw, RDT);
+	regs_buff[6]  = E1000_READ_REG(hw, RDTR);
+	
+	regs_buff[7]  = E1000_READ_REG(hw, TCTL);
+	regs_buff[8]  = E1000_READ_REG(hw, TDLEN);
+	regs_buff[9]  = E1000_READ_REG(hw, TDH);
+	regs_buff[10] = E1000_READ_REG(hw, TDT);
+	regs_buff[11] = E1000_READ_REG(hw, TIDV);
+
+	return;
+}
+
+static int
+e1000_ethtool_geeprom(struct e1000_adapter *adapter,
+                      struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	int i, max_len, first_word, last_word;
+
+	if(eeprom->len == 0)
+		return -EINVAL;
+
+	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	max_len = e1000_eeprom_size(hw);
+
+	if(eeprom->offset > eeprom->offset + eeprom->len)
+		return -EINVAL;
+	
+	if((eeprom->offset + eeprom->len) > max_len)
+		eeprom->len = (max_len - eeprom->offset);
+
+	first_word = eeprom->offset >> 1;
+	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+
+	for(i = 0; i <= (last_word - first_word); i++)
+		e1000_read_eeprom(hw, first_word + i, &eeprom_buff[i]);
+
+	return 0;
+}
+
+static int 
+e1000_ethtool_seeprom(struct e1000_adapter *adapter,
+                      struct ethtool_eeprom *eeprom, void *user_data)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	uint16_t eeprom_buff[256];
+	int i, max_len, first_word, last_word;
+	void *ptr;
+
+	if(eeprom->len == 0)
+		return -EOPNOTSUPP;
+
+	if(eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
+		return -EFAULT;
+
+	max_len = e1000_eeprom_size(hw);
+
+	if((eeprom->offset + eeprom->len) > max_len)
+		eeprom->len = (max_len - eeprom->offset);
+
+	first_word = eeprom->offset >> 1;
+	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+	ptr = (void *)eeprom_buff;
+
+	if(eeprom->offset & 1) {
+		/* need read/modify/write of first changed EEPROM word */
+		/* only the second byte of the word is being modified */
+		e1000_read_eeprom(hw, first_word, &eeprom_buff[0]);
+		ptr++;
+	}
+	if((eeprom->offset + eeprom->len) & 1) {
+		/* need read/modify/write of last changed EEPROM word */
+		/* only the first byte of the word is being modified */
+		e1000_read_eeprom(hw, last_word,
+		                  &eeprom_buff[last_word - first_word]);
+	}
+	if(copy_from_user(ptr, user_data, eeprom->len))
+		return -EFAULT;
+
+	for(i = 0; i <= (last_word - first_word); i++)
+		e1000_write_eeprom(hw, first_word + i, eeprom_buff[i]);
+
+	/* Update the checksum over the first part of the EEPROM if needed */
+	if(first_word <= EEPROM_CHECKSUM_REG)
+		e1000_update_eeprom_checksum(hw);
+
+	return 0;
+}
+
+static void
+e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	switch(adapter->hw.device_id) {
+	case E1000_DEV_ID_82542:
+	case E1000_DEV_ID_82543GC_FIBER:
+	case E1000_DEV_ID_82543GC_COPPER:
+	case E1000_DEV_ID_82544EI_FIBER:
+		wol->supported = 0;
+		wol->wolopts   = 0;
+		return;
+
+	case E1000_DEV_ID_82546EB_FIBER:
+		/* Wake events only supported on port A for dual fiber */
+		if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) {
+			wol->supported = 0;
+			wol->wolopts   = 0;
+			return;
+		}
+		/* Fall Through */
+
+	default:
+		wol->supported = WAKE_PHY | WAKE_UCAST | 
+				 WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
+		
+		wol->wolopts = 0;
+		if(adapter->wol & E1000_WUFC_LNKC)
+			wol->wolopts |= WAKE_PHY;
+		if(adapter->wol & E1000_WUFC_EX)
+			wol->wolopts |= WAKE_UCAST;
+		if(adapter->wol & E1000_WUFC_MC)
+			wol->wolopts |= WAKE_MCAST;
+		if(adapter->wol & E1000_WUFC_BC)
+			wol->wolopts |= WAKE_BCAST;
+		if(adapter->wol & E1000_WUFC_MAG)
+			wol->wolopts |= WAKE_MAGIC;
+		return;
+	}
+}
+
+static int
+e1000_ethtool_swol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	switch(adapter->hw.device_id) {
+	case E1000_DEV_ID_82542:
+	case E1000_DEV_ID_82543GC_FIBER:
+	case E1000_DEV_ID_82543GC_COPPER:
+	case E1000_DEV_ID_82544EI_FIBER:
+		return wol->wolopts ? -EOPNOTSUPP : 0;
+
+	case E1000_DEV_ID_82546EB_FIBER:
+		/* Wake events only supported on port A for dual fiber */
+		if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
+			return wol->wolopts ? -EOPNOTSUPP : 0;
+		/* Fall Through */
+
+	default:
+		if(wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE))
+			return -EOPNOTSUPP;
+
+		adapter->wol = 0;
+
+		if(wol->wolopts & WAKE_PHY)
+			adapter->wol |= E1000_WUFC_LNKC;
+		if(wol->wolopts & WAKE_UCAST)
+			adapter->wol |= E1000_WUFC_EX;
+		if(wol->wolopts & WAKE_MCAST)
+			adapter->wol |= E1000_WUFC_MC;
+		if(wol->wolopts & WAKE_BCAST)
+			adapter->wol |= E1000_WUFC_BC;
+		if(wol->wolopts & WAKE_MAGIC)
+			adapter->wol |= E1000_WUFC_MAG;
+	}
+
+	return 0;
+}
+
+
+/* toggle LED 4 times per second = 2 "blinks" per second */
+#define E1000_ID_INTERVAL	(HZ/4)
+
+/* bit defines for adapter->led_status */
+#define E1000_LED_ON		0
+
+static void
+e1000_led_blink_callback(unsigned long data)
+{
+	struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+	
+	if(test_and_change_bit(E1000_LED_ON, &adapter->led_status))
+		e1000_led_off(&adapter->hw);
+	else
+		e1000_led_on(&adapter->hw);
+
+	mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL);
+}
+
+static int
+e1000_ethtool_led_blink(struct e1000_adapter *adapter, struct ethtool_value *id)
+{
+	if(!adapter->blink_timer.function) {
+		init_timer(&adapter->blink_timer);
+		adapter->blink_timer.function = e1000_led_blink_callback;
+		adapter->blink_timer.data = (unsigned long) adapter;
+	}
+
+	e1000_setup_led(&adapter->hw);
+	mod_timer(&adapter->blink_timer, jiffies);
+	
+	set_current_state(TASK_INTERRUPTIBLE);
+	if(id->data)
+		schedule_timeout(id->data * HZ);
+	else
+		schedule_timeout(MAX_SCHEDULE_TIMEOUT);
+	
+	del_timer_sync(&adapter->blink_timer);
+	e1000_led_off(&adapter->hw);
+	clear_bit(E1000_LED_ON, &adapter->led_status);
+	e1000_cleanup_led(&adapter->hw);
+
+	return 0;
+}
+
+int
+e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+	void *addr = ifr->ifr_data;
+	uint32_t cmd;
+
+	if(get_user(cmd, (uint32_t *) addr))
+		return -EFAULT;
+
+	switch(cmd) {
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = {ETHTOOL_GSET};
+		e1000_ethtool_gset(adapter, &ecmd);
+		if(copy_to_user(addr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SSET: {
+		struct ethtool_cmd ecmd;
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if(copy_from_user(&ecmd, addr, sizeof(ecmd)))
+			return -EFAULT;
+		return e1000_ethtool_sset(adapter, &ecmd);
+	}
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo drvinfo = {ETHTOOL_GDRVINFO};
+		e1000_ethtool_gdrvinfo(adapter, &drvinfo);
+		if(copy_to_user(addr, &drvinfo, sizeof(drvinfo)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_GREGS: {
+		struct ethtool_regs regs = {ETHTOOL_GREGS};
+		uint32_t regs_buff[E1000_REGS_LEN];
+
+		if(copy_from_user(&regs, addr, sizeof(regs)))
+			return -EFAULT;
+		e1000_ethtool_gregs(adapter, &regs, regs_buff);
+		if(copy_to_user(addr, &regs, sizeof(regs)))
+			return -EFAULT;
+
+		addr += offsetof(struct ethtool_regs, data);
+		if(copy_to_user(addr, regs_buff, regs.len))
+			return -EFAULT;
+
+		return 0;
+	}
+	case ETHTOOL_NWAY_RST: {
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if(netif_running(netdev)) {
+			e1000_down(adapter);
+			e1000_up(adapter);
+		}
+		return 0;
+	}
+	case ETHTOOL_PHYS_ID: {
+		struct ethtool_value id;
+		if(copy_from_user(&id, addr, sizeof(id)))
+			return -EFAULT;
+		return e1000_ethtool_led_blink(adapter, &id);
+	}
+	case ETHTOOL_GLINK: {
+		struct ethtool_value link = {ETHTOOL_GLINK};
+		link.data = netif_carrier_ok(netdev);
+		if(copy_to_user(addr, &link, sizeof(link)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_GWOL: {
+		struct ethtool_wolinfo wol = {ETHTOOL_GWOL};
+		e1000_ethtool_gwol(adapter, &wol);
+		if(copy_to_user(addr, &wol, sizeof(wol)) != 0)
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SWOL: {
+		struct ethtool_wolinfo wol;
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if(copy_from_user(&wol, addr, sizeof(wol)) != 0)
+			return -EFAULT;
+		return e1000_ethtool_swol(adapter, &wol);
+	}
+	case ETHTOOL_GEEPROM: {
+		struct ethtool_eeprom eeprom = {ETHTOOL_GEEPROM};
+		uint16_t eeprom_buff[256];
+		void *ptr;
+		int err;
+
+		if(copy_from_user(&eeprom, addr, sizeof(eeprom)))
+			return -EFAULT;
+
+		if((err = e1000_ethtool_geeprom(adapter, 
+			&eeprom, eeprom_buff)))
+			return err;
+
+		if(copy_to_user(addr, &eeprom, sizeof(eeprom)))
+			return -EFAULT;
+
+		addr += offsetof(struct ethtool_eeprom, data);
+		ptr = ((void *)eeprom_buff) + (eeprom.offset & 1);
+
+		if(copy_to_user(addr, ptr, eeprom.len))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SEEPROM: {
+		struct ethtool_eeprom eeprom;
+
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if(copy_from_user(&eeprom, addr, sizeof(eeprom)))
+			return -EFAULT;
+
+		addr += offsetof(struct ethtool_eeprom, data);
+		return e1000_ethtool_seeprom(adapter, &eeprom, addr);
+	}
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e1000/e1000_hw.c linux-2.4.20/drivers/net/e1000/e1000_hw.c
--- linux-2.4.19/drivers/net/e1000/e1000_hw.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e1000/e1000_hw.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,3610 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* e1000_hw.c
+ * Shared functions for accessing and configuring the MAC
+ */
+
+#include "e1000_hw.h"
+
+static int32_t e1000_setup_fiber_link(struct e1000_hw *hw);
+static int32_t e1000_setup_copper_link(struct e1000_hw *hw);
+static int32_t e1000_phy_force_speed_duplex(struct e1000_hw *hw);
+static int32_t e1000_config_mac_to_phy(struct e1000_hw *hw);
+static int32_t e1000_force_mac_fc(struct e1000_hw *hw);
+static void e1000_raise_mdi_clk(struct e1000_hw *hw, uint32_t *ctrl);
+static void e1000_lower_mdi_clk(struct e1000_hw *hw, uint32_t *ctrl);
+static void e1000_shift_out_mdi_bits(struct e1000_hw *hw, uint32_t data, uint16_t count);
+static uint16_t e1000_shift_in_mdi_bits(struct e1000_hw *hw);
+static int32_t e1000_phy_reset_dsp(struct e1000_hw *hw);
+static void e1000_raise_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
+static void e1000_lower_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
+static void e1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data, uint16_t count);
+static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw);
+static void e1000_setup_eeprom(struct e1000_hw *hw);
+static void e1000_clock_eeprom(struct e1000_hw *hw);
+static void e1000_cleanup_eeprom(struct e1000_hw *hw);
+static void e1000_standby_eeprom(struct e1000_hw *hw);
+static int32_t e1000_id_led_init(struct e1000_hw * hw);
+
+/******************************************************************************
+ * Set the mac type member in the hw struct.
+ * 
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_set_mac_type(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_set_mac_type");
+
+    switch (hw->device_id) {
+    case E1000_DEV_ID_82542:
+        switch (hw->revision_id) {
+        case E1000_82542_2_0_REV_ID:
+            hw->mac_type = e1000_82542_rev2_0;
+            break;
+        case E1000_82542_2_1_REV_ID:
+            hw->mac_type = e1000_82542_rev2_1;
+            break;
+        default:
+            /* Invalid 82542 revision ID */
+            return -E1000_ERR_MAC_TYPE;
+        }
+        break;
+    case E1000_DEV_ID_82543GC_FIBER:
+    case E1000_DEV_ID_82543GC_COPPER:
+        hw->mac_type = e1000_82543;
+        break;
+    case E1000_DEV_ID_82544EI_COPPER:
+    case E1000_DEV_ID_82544EI_FIBER:
+    case E1000_DEV_ID_82544GC_COPPER:
+    case E1000_DEV_ID_82544GC_LOM:
+        hw->mac_type = e1000_82544;
+        break;
+    case E1000_DEV_ID_82540EM:
+    case E1000_DEV_ID_82540EM_LOM:
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
+        hw->mac_type = e1000_82540;
+        break;
+    case E1000_DEV_ID_82545EM_COPPER:
+    case E1000_DEV_ID_82545EM_FIBER:
+        hw->mac_type = e1000_82545;
+        break;
+    case E1000_DEV_ID_82546EB_COPPER:
+    case E1000_DEV_ID_82546EB_FIBER:
+        hw->mac_type = e1000_82546;
+        break;
+    default:
+        /* Should never have loaded on this device */
+        return -E1000_ERR_MAC_TYPE;
+    }
+    return E1000_SUCCESS;
+}
+/******************************************************************************
+ * Reset the transmit and receive units; mask and clear all interrupts.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_reset_hw(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint32_t ctrl_ext;
+    uint32_t icr;
+    uint32_t manc;
+
+    DEBUGFUNC("e1000_reset_hw");
+    
+    /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
+    if(hw->mac_type == e1000_82542_rev2_0) {
+        DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+        e1000_pci_clear_mwi(hw);
+    }
+
+    /* Clear interrupt mask to stop board from generating interrupts */
+    DEBUGOUT("Masking off all interrupts\n");
+    E1000_WRITE_REG(hw, IMC, 0xffffffff);
+
+    /* Disable the Transmit and Receive units.  Then delay to allow
+     * any pending transactions to complete before we hit the MAC with
+     * the global reset.
+     */
+    E1000_WRITE_REG(hw, RCTL, 0);
+    E1000_WRITE_REG(hw, TCTL, E1000_TCTL_PSP);
+    E1000_WRITE_FLUSH(hw);
+
+    /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */
+    hw->tbi_compatibility_on = FALSE;
+
+    /* Delay to allow any outstanding PCI transactions to complete before
+     * resetting the device
+     */ 
+    msec_delay(10);
+
+    /* Issue a global reset to the MAC.  This will reset the chip's
+     * transmit, receive, DMA, and link units.  It will not effect
+     * the current PCI configuration.  The global reset bit is self-
+     * clearing, and should clear within a microsecond.
+     */
+    DEBUGOUT("Issuing a global reset to MAC\n");
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    if(hw->mac_type > e1000_82543)
+        E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST));
+    else
+        E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+
+    /* Force a reload from the EEPROM if necessary */
+    if(hw->mac_type < e1000_82540) {
+        /* Wait for reset to complete */
+        udelay(10);
+        ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+        ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+        E1000_WRITE_FLUSH(hw);
+        /* Wait for EEPROM reload */
+        msec_delay(2);
+    } else {
+        /* Wait for EEPROM reload (it happens automatically) */
+        msec_delay(4);
+        /* Dissable HW ARPs on ASF enabled adapters */
+        manc = E1000_READ_REG(hw, MANC);
+        manc &= ~(E1000_MANC_ARP_EN);
+        E1000_WRITE_REG(hw, MANC, manc);
+    }
+    
+    /* Clear interrupt mask to stop board from generating interrupts */
+    DEBUGOUT("Masking off all interrupts\n");
+    E1000_WRITE_REG(hw, IMC, 0xffffffff);
+
+    /* Clear any pending interrupt events. */
+    icr = E1000_READ_REG(hw, ICR);
+
+    /* If MWI was previously enabled, reenable it. */
+    if(hw->mac_type == e1000_82542_rev2_0) {
+        if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+            e1000_pci_set_mwi(hw);
+    }
+}
+
+/******************************************************************************
+ * Performs basic configuration of the adapter.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * 
+ * Assumes that the controller has previously been reset and is in a 
+ * post-reset uninitialized state. Initializes the receive address registers,
+ * multicast table, and VLAN filter table. Calls routines to setup link
+ * configuration and flow control settings. Clears all on-chip counters. Leaves
+ * the transmit and receive units disabled and uninitialized.
+ *****************************************************************************/
+int32_t
+e1000_init_hw(struct e1000_hw *hw)
+{
+    uint32_t ctrl, status;
+    uint32_t i;
+    int32_t ret_val;
+    uint16_t pcix_cmd_word;
+    uint16_t pcix_stat_hi_word;
+    uint16_t cmd_mmrbc;
+    uint16_t stat_mmrbc;
+
+    DEBUGFUNC("e1000_init_hw");
+
+    /* Initialize Identification LED */
+    ret_val = e1000_id_led_init(hw);
+    if(ret_val < 0) {
+        DEBUGOUT("Error Initializing Identification LED\n");
+        return ret_val;
+    }
+    
+    /* Set the Media Type and exit with error if it is not valid. */
+    if(hw->mac_type != e1000_82543) {
+        /* tbi_compatibility is only valid on 82543 */
+        hw->tbi_compatibility_en = FALSE;
+    }
+
+    if(hw->mac_type >= e1000_82543) {
+        status = E1000_READ_REG(hw, STATUS);
+        if(status & E1000_STATUS_TBIMODE) {
+            hw->media_type = e1000_media_type_fiber;
+            /* tbi_compatibility not valid on fiber */
+            hw->tbi_compatibility_en = FALSE;
+        } else {
+            hw->media_type = e1000_media_type_copper;
+        }
+    } else {
+        /* This is an 82542 (fiber only) */
+        hw->media_type = e1000_media_type_fiber;
+    }
+
+    /* Disabling VLAN filtering. */
+    DEBUGOUT("Initializing the IEEE VLAN\n");
+    E1000_WRITE_REG(hw, VET, 0);
+
+    e1000_clear_vfta(hw);
+
+    /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
+    if(hw->mac_type == e1000_82542_rev2_0) {
+        DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+        e1000_pci_clear_mwi(hw);
+        E1000_WRITE_REG(hw, RCTL, E1000_RCTL_RST);
+        E1000_WRITE_FLUSH(hw);
+        msec_delay(5);
+    }
+
+    /* Setup the receive address. This involves initializing all of the Receive
+     * Address Registers (RARs 0 - 15).
+     */
+    e1000_init_rx_addrs(hw);
+
+    /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
+    if(hw->mac_type == e1000_82542_rev2_0) {
+        E1000_WRITE_REG(hw, RCTL, 0);
+        E1000_WRITE_FLUSH(hw);
+        msec_delay(1);
+        if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+            e1000_pci_set_mwi(hw);
+    }
+
+    /* Zero out the Multicast HASH table */
+    DEBUGOUT("Zeroing the MTA\n");
+    for(i = 0; i < E1000_MC_TBL_SIZE; i++)
+        E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+
+    /* Set the PCI priority bit correctly in the CTRL register.  This
+     * determines if the adapter gives priority to receives, or if it
+     * gives equal priority to transmits and receives.
+     */
+    if(hw->dma_fairness) {
+        ctrl = E1000_READ_REG(hw, CTRL);
+        E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
+    }
+
+    /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
+    if(hw->bus_type == e1000_bus_type_pcix) {
+        e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word);
+        e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI, &pcix_stat_hi_word);
+        cmd_mmrbc = (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >>
+            PCIX_COMMAND_MMRBC_SHIFT;
+        stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
+            PCIX_STATUS_HI_MMRBC_SHIFT;
+        if(stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
+            stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
+        if(cmd_mmrbc > stat_mmrbc) {
+            pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
+            pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
+            e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word);
+        }
+    }
+
+    /* Call a subroutine to configure the link and setup flow control. */
+    ret_val = e1000_setup_link(hw);
+
+    /* Set the transmit descriptor write-back policy */
+    if(hw->mac_type > e1000_82544) {
+        ctrl = E1000_READ_REG(hw, TXDCTL);
+        ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
+        E1000_WRITE_REG(hw, TXDCTL, ctrl);
+    }
+
+    /* Clear all of the statistics registers (clear on read).  It is
+     * important that we do this after we have tried to establish link
+     * because the symbol error count will increment wildly if there
+     * is no link.
+     */
+    e1000_clear_hw_cntrs(hw);
+
+    return ret_val;
+}
+
+/******************************************************************************
+ * Configures flow control and link settings.
+ * 
+ * hw - Struct containing variables accessed by shared code
+ * 
+ * Determines which flow control settings to use. Calls the apropriate media-
+ * specific link configuration function. Configures the flow control settings.
+ * Assuming the adapter has a valid link partner, a valid link should be
+ * established. Assumes the hardware has previously been reset and the 
+ * transmitter and receiver are not enabled.
+ *****************************************************************************/
+int32_t
+e1000_setup_link(struct e1000_hw *hw)
+{
+    uint32_t ctrl_ext;
+    int32_t ret_val;
+    uint16_t eeprom_data;
+
+    DEBUGFUNC("e1000_setup_link");
+
+    /* Read and store word 0x0F of the EEPROM. This word contains bits
+     * that determine the hardware's default PAUSE (flow control) mode,
+     * a bit that determines whether the HW defaults to enabling or
+     * disabling auto-negotiation, and the direction of the
+     * SW defined pins. If there is no SW over-ride of the flow
+     * control setting, then the variable hw->fc will
+     * be initialized based on a value in the EEPROM.
+     */
+    if(e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data) < 0) {
+        DEBUGOUT("EEPROM Read Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+
+    if(hw->fc == e1000_fc_default) {
+        if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
+            hw->fc = e1000_fc_none;
+        else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 
+                EEPROM_WORD0F_ASM_DIR)
+            hw->fc = e1000_fc_tx_pause;
+        else
+            hw->fc = e1000_fc_full;
+    }
+
+    /* We want to save off the original Flow Control configuration just
+     * in case we get disconnected and then reconnected into a different
+     * hub or switch with different Flow Control capabilities.
+     */
+    if(hw->mac_type == e1000_82542_rev2_0)
+        hw->fc &= (~e1000_fc_tx_pause);
+
+    if((hw->mac_type < e1000_82543) && (hw->report_tx_early == 1))
+        hw->fc &= (~e1000_fc_rx_pause);
+
+    hw->original_fc = hw->fc;
+
+    DEBUGOUT1("After fix-ups FlowControl is now = %x\n", hw->fc);
+
+    /* Take the 4 bits from EEPROM word 0x0F that determine the initial
+     * polarity value for the SW controlled pins, and setup the
+     * Extended Device Control reg with that info.
+     * This is needed because one of the SW controlled pins is used for
+     * signal detection.  So this should be done before e1000_setup_pcs_link()
+     * or e1000_phy_setup() is called.
+     */
+    if(hw->mac_type == e1000_82543) {
+        ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) << 
+                    SWDPIO__EXT_SHIFT);
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+    }
+
+    /* Call the necessary subroutine to configure the link. */
+    ret_val = (hw->media_type == e1000_media_type_fiber) ?
+              e1000_setup_fiber_link(hw) :
+              e1000_setup_copper_link(hw);
+
+    /* Initialize the flow control address, type, and PAUSE timer
+     * registers to their default values.  This is done even if flow
+     * control is disabled, because it does not hurt anything to
+     * initialize these registers.
+     */
+    DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
+
+    E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
+    E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+    E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+    E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
+
+    /* Set the flow control receive threshold registers.  Normally,
+     * these registers will be set to a default threshold that may be
+     * adjusted later by the driver's runtime code.  However, if the
+     * ability to transmit pause frames in not enabled, then these
+     * registers will be set to 0. 
+     */
+    if(!(hw->fc & e1000_fc_tx_pause)) {
+        E1000_WRITE_REG(hw, FCRTL, 0);
+        E1000_WRITE_REG(hw, FCRTH, 0);
+    } else {
+        /* We need to set up the Receive Threshold high and low water marks
+         * as well as (optionally) enabling the transmission of XON frames.
+         */
+        if(hw->fc_send_xon) {
+            E1000_WRITE_REG(hw, FCRTL, (hw->fc_low_water | E1000_FCRTL_XONE));
+            E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+        } else {
+            E1000_WRITE_REG(hw, FCRTL, hw->fc_low_water);
+            E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+        }
+    }
+    return ret_val;
+}
+
+/******************************************************************************
+ * Sets up link for a fiber based adapter
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Manipulates Physical Coding Sublayer functions in order to configure
+ * link. Assumes the hardware has been previously reset and the transmitter
+ * and receiver are not enabled.
+ *****************************************************************************/
+static int32_t 
+e1000_setup_fiber_link(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint32_t status;
+    uint32_t txcw = 0;
+    uint32_t i;
+    uint32_t signal;
+    int32_t ret_val;
+
+    DEBUGFUNC("e1000_setup_fiber_link");
+
+    /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be 
+     * set when the optics detect a signal. On older adapters, it will be 
+     * cleared when there is a signal
+     */
+    ctrl = E1000_READ_REG(hw, CTRL);
+    if(hw->mac_type > e1000_82544) signal = E1000_CTRL_SWDPIN1;
+    else signal = 0;
+   
+    /* Take the link out of reset */
+    ctrl &= ~(E1000_CTRL_LRST);
+    
+    e1000_config_collision_dist(hw);
+
+    /* Check for a software override of the flow control settings, and setup
+     * the device accordingly.  If auto-negotiation is enabled, then software
+     * will have to set the "PAUSE" bits to the correct value in the Tranmsit
+     * Config Word Register (TXCW) and re-start auto-negotiation.  However, if
+     * auto-negotiation is disabled, then software will have to manually 
+     * configure the two flow control enable bits in the CTRL register.
+     *
+     * The possible values of the "fc" parameter are:
+     *      0:  Flow control is completely disabled
+     *      1:  Rx flow control is enabled (we can receive pause frames, but 
+     *          not send pause frames).
+     *      2:  Tx flow control is enabled (we can send pause frames but we do
+     *          not support receiving pause frames).
+     *      3:  Both Rx and TX flow control (symmetric) are enabled.
+     */
+    switch (hw->fc) {
+    case e1000_fc_none:
+        /* Flow control is completely disabled by a software over-ride. */
+        txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+        break;
+    case e1000_fc_rx_pause:
+        /* RX Flow control is enabled and TX Flow control is disabled by a 
+         * software over-ride. Since there really isn't a way to advertise 
+         * that we are capable of RX Pause ONLY, we will advertise that we
+         * support both symmetric and asymmetric RX PAUSE. Later, we will
+         *  disable the adapter's ability to send PAUSE frames.
+         */
+        txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+        break;
+    case e1000_fc_tx_pause:
+        /* TX Flow control is enabled, and RX Flow control is disabled, by a 
+         * software over-ride.
+         */
+        txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+        break;
+    case e1000_fc_full:
+        /* Flow control (both RX and TX) is enabled by a software over-ride. */
+        txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+        break;
+    default:
+        DEBUGOUT("Flow control param set incorrectly\n");
+        return -E1000_ERR_CONFIG;
+        break;
+    }
+
+    /* Since auto-negotiation is enabled, take the link out of reset (the link
+     * will be in reset, because we previously reset the chip). This will
+     * restart auto-negotiation.  If auto-neogtiation is successful then the
+     * link-up status bit will be set and the flow control enable bits (RFCE
+     * and TFCE) will be set according to their negotiated value.
+     */
+    DEBUGOUT("Auto-negotiation enabled\n");
+
+    E1000_WRITE_REG(hw, TXCW, txcw);
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+    E1000_WRITE_FLUSH(hw);
+
+    hw->txcw = txcw;
+    msec_delay(1);
+
+    /* If we have a signal (the cable is plugged in) then poll for a "Link-Up"
+     * indication in the Device Status Register.  Time-out if a link isn't 
+     * seen in 500 milliseconds seconds (Auto-negotiation should complete in 
+     * less than 500 milliseconds even if the other end is doing it in SW).
+     */
+    if((E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) {
+        DEBUGOUT("Looking for Link\n");
+        for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
+            msec_delay(10);
+            status = E1000_READ_REG(hw, STATUS);
+            if(status & E1000_STATUS_LU) break;
+        }
+        if(i == (LINK_UP_TIMEOUT / 10)) {
+            /* AutoNeg failed to achieve a link, so we'll call 
+             * e1000_check_for_link. This routine will force the link up if we
+             * detect a signal. This will allow us to communicate with
+             * non-autonegotiating link partners.
+             */
+            DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+            hw->autoneg_failed = 1;
+            ret_val = e1000_check_for_link(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error while checking for link\n");
+                return ret_val;
+            }
+            hw->autoneg_failed = 0;
+        } else {
+            hw->autoneg_failed = 0;
+            DEBUGOUT("Valid Link Found\n");
+        }
+    } else {
+        DEBUGOUT("No Signal Detected\n");
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Detects which PHY is present and the speed and duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t 
+e1000_setup_copper_link(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    int32_t ret_val;
+    uint16_t i;
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_setup_copper_link");
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+    /* With 82543, we need to force speed and duplex on the MAC equal to what
+     * the PHY speed and duplex configuration is. In addition, we need to
+     * perform a hardware reset on the PHY to take it out of reset.
+     */
+    if(hw->mac_type > e1000_82543) {
+        ctrl |= E1000_CTRL_SLU;
+        ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+    } else {
+        ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        e1000_phy_hw_reset(hw);
+    }
+
+    /* Make sure we have a valid PHY */
+    ret_val = e1000_detect_gig_phy(hw);
+    if(ret_val < 0) {
+        DEBUGOUT("Error, did not detect valid phy.\n");
+        return ret_val;
+    }
+    DEBUGOUT1("Phy ID = %x \n", hw->phy_id);
+
+    /* Enable CRS on TX. This must be set for half-duplex operation. */
+    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+    /* Options:
+     *   MDI/MDI-X = 0 (default)
+     *   0 - Auto for all speeds
+     *   1 - MDI mode
+     *   2 - MDI-X mode
+     *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+     */
+    phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+    switch (hw->mdix) {
+    case 1:
+        phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+        break;
+    case 2:
+        phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+        break;
+    case 3:
+        phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+        break;
+    case 0:
+    default:
+        phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+        break;
+    }
+
+    /* Options:
+     *   disable_polarity_correction = 0 (default)
+     *       Automatic Correction for Reversed Cable Polarity
+     *   0 - Disabled
+     *   1 - Enabled
+     */
+    phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+    if(hw->disable_polarity_correction == 1)
+        phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+    if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* Force TX_CLK in the Extended PHY Specific Control Register
+     * to 25MHz clock.
+     */
+    if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+    if (hw->phy_revision < M88E1011_I_REV_4) {
+        /* Configure Master and Slave downshift values */
+        phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+                      M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+        phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+                     M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+        if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
+    }
+
+    /* SW Reset the PHY so all changes take effect */
+    ret_val = e1000_phy_reset(hw);
+    if(ret_val < 0) {
+        DEBUGOUT("Error Resetting the PHY\n");
+        return ret_val;
+    }
+    
+    /* Options:
+     *   autoneg = 1 (default)
+     *      PHY will advertise value(s) parsed from
+     *      autoneg_advertised and fc
+     *   autoneg = 0
+     *      PHY will be set to 10H, 10F, 100H, or 100F
+     *      depending on value parsed from forced_speed_duplex.
+     */
+
+    /* Is autoneg enabled?  This is enabled by default or by software override.
+     * If so, call e1000_phy_setup_autoneg routine to parse the
+     * autoneg_advertised and fc options. If autoneg is NOT enabled, then the
+     * user should have provided a speed/duplex override.  If so, then call
+     * e1000_phy_force_speed_duplex to parse and set this up.
+     */
+    if(hw->autoneg) {
+        /* Perform some bounds checking on the hw->autoneg_advertised
+         * parameter.  If this variable is zero, then set it to the default.
+         */
+        hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+        /* If autoneg_advertised is zero, we assume it was not defaulted
+         * by the calling code so we set to advertise full capability.
+         */
+        if(hw->autoneg_advertised == 0)
+            hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+        DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+        ret_val = e1000_phy_setup_autoneg(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error Setting up Auto-Negotiation\n");
+            return ret_val;
+        }
+        DEBUGOUT("Restarting Auto-Neg\n");
+
+        /* Restart auto-negotiation by setting the Auto Neg Enable bit and
+         * the Auto Neg Restart bit in the PHY control register.
+         */
+        if(e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+        if(e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
+
+        /* Does the user want to wait for Auto-Neg to complete here, or
+         * check at a later time (for example, callback routine).
+         */
+        if(hw->wait_autoneg_complete) {
+            ret_val = e1000_wait_autoneg(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error while waiting for autoneg to complete\n");
+                return ret_val;
+            }
+        }
+    } else {
+        DEBUGOUT("Forcing speed and duplex\n");
+        ret_val = e1000_phy_force_speed_duplex(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error Forcing Speed and Duplex\n");
+            return ret_val;
+        }
+    }
+
+    /* Check link status. Wait up to 100 microseconds for link to become
+     * valid.
+     */
+    for(i = 0; i < 10; i++) {
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(phy_data & MII_SR_LINK_STATUS) {
+            /* We have link, so we need to finish the config process:
+             *   1) Set up the MAC to the current PHY speed/duplex
+             *      if we are on 82543.  If we
+             *      are on newer silicon, we only need to configure
+             *      collision distance in the Transmit Control Register.
+             *   2) Set up flow control on the MAC to that established with
+             *      the link partner.
+             */
+            if(hw->mac_type >= e1000_82544) {
+                e1000_config_collision_dist(hw);
+            } else {
+                ret_val = e1000_config_mac_to_phy(hw);
+                if(ret_val < 0) {
+                    DEBUGOUT("Error configuring MAC to PHY settings\n");
+                    return ret_val;
+                  }
+            }
+            ret_val = e1000_config_fc_after_link_up(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error Configuring Flow Control\n");
+                return ret_val;
+            }
+            DEBUGOUT("Valid link established!!!\n");
+            return 0;
+        }
+        udelay(10);
+    }
+
+    DEBUGOUT("Unable to establish link!!!\n");
+    return 0;
+}
+
+/******************************************************************************
+* Configures PHY autoneg and flow control advertisement settings
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_phy_setup_autoneg(struct e1000_hw *hw)
+{
+    uint16_t mii_autoneg_adv_reg;
+    uint16_t mii_1000t_ctrl_reg;
+
+    DEBUGFUNC("e1000_phy_setup_autoneg");
+
+    /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+    if(e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* Read the MII 1000Base-T Control Register (Address 9). */
+    if(e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* Need to parse both autoneg_advertised and fc and set up
+     * the appropriate PHY registers.  First we will parse for
+     * autoneg_advertised software override.  Since we can advertise
+     * a plethora of combinations, we need to check each bit
+     * individually.
+     */
+
+    /* First we clear all the 10/100 mb speed bits in the Auto-Neg
+     * Advertisement Register (Address 4) and the 1000 mb speed bits in
+     * the  1000Base-T Control Register (Address 9).
+     */
+    mii_autoneg_adv_reg &= ~REG4_SPEED_MASK;
+    mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
+
+    DEBUGOUT1("autoneg_advertised %x\n", hw->autoneg_advertised);
+
+    /* Do we want to advertise 10 Mb Half Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_10_HALF) {
+        DEBUGOUT("Advertise 10mb Half duplex\n");
+        mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+    }
+
+    /* Do we want to advertise 10 Mb Full Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_10_FULL) {
+        DEBUGOUT("Advertise 10mb Full duplex\n");
+        mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+    }
+
+    /* Do we want to advertise 100 Mb Half Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_100_HALF) {
+        DEBUGOUT("Advertise 100mb Half duplex\n");
+        mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+    }
+
+    /* Do we want to advertise 100 Mb Full Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_100_FULL) {
+        DEBUGOUT("Advertise 100mb Full duplex\n");
+        mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+    }
+
+    /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+    if(hw->autoneg_advertised & ADVERTISE_1000_HALF) {
+        DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n");
+    }
+
+    /* Do we want to advertise 1000 Mb Full Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_1000_FULL) {
+        DEBUGOUT("Advertise 1000mb Full duplex\n");
+        mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+    }
+
+    /* Check for a software override of the flow control settings, and
+     * setup the PHY advertisement registers accordingly.  If
+     * auto-negotiation is enabled, then software will have to set the
+     * "PAUSE" bits to the correct value in the Auto-Negotiation
+     * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation.
+     *
+     * The possible values of the "fc" parameter are:
+     *      0:  Flow control is completely disabled
+     *      1:  Rx flow control is enabled (we can receive pause frames
+     *          but not send pause frames).
+     *      2:  Tx flow control is enabled (we can send pause frames
+     *          but we do not support receiving pause frames).
+     *      3:  Both Rx and TX flow control (symmetric) are enabled.
+     *  other:  No software override.  The flow control configuration
+     *          in the EEPROM is used.
+     */
+    switch (hw->fc) {
+    case e1000_fc_none: /* 0 */
+        /* Flow control (RX & TX) is completely disabled by a
+         * software over-ride.
+         */
+        mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+        break;
+    case e1000_fc_rx_pause: /* 1 */
+        /* RX Flow control is enabled, and TX Flow control is
+         * disabled, by a software over-ride.
+         */
+        /* Since there really isn't a way to advertise that we are
+         * capable of RX Pause ONLY, we will advertise that we
+         * support both symmetric and asymmetric RX PAUSE.  Later
+         * (in e1000_config_fc_after_link_up) we will disable the
+         *hw's ability to send PAUSE frames.
+         */
+        mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+        break;
+    case e1000_fc_tx_pause: /* 2 */
+        /* TX Flow control is enabled, and RX Flow control is
+         * disabled, by a software over-ride.
+         */
+        mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+        mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+        break;
+    case e1000_fc_full: /* 3 */
+        /* Flow control (both RX and TX) is enabled by a software
+         * over-ride.
+         */
+        mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+        break;
+    default:
+        DEBUGOUT("Flow control param set incorrectly\n");
+        return -E1000_ERR_CONFIG;
+    }
+
+    if(e1000_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+    if(e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Force PHY speed and duplex settings to hw->forced_speed_duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_phy_force_speed_duplex(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    int32_t ret_val;
+    uint16_t mii_ctrl_reg;
+    uint16_t mii_status_reg;
+    uint16_t phy_data;
+    uint16_t i;
+
+    DEBUGFUNC("e1000_phy_force_speed_duplex");
+
+    /* Turn off Flow control if we are forcing speed and duplex. */
+    hw->fc = e1000_fc_none;
+
+    DEBUGOUT1("hw->fc = %d\n", hw->fc);
+
+    /* Read the Device Control Register. */
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */
+    ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+    ctrl &= ~(DEVICE_SPEED_MASK);
+
+    /* Clear the Auto Speed Detect Enable bit. */
+    ctrl &= ~E1000_CTRL_ASDE;
+
+    /* Read the MII Control Register. */
+    if(e1000_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* We need to disable autoneg in order to force link and duplex. */
+
+    mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN;
+
+    /* Are we forcing Full or Half Duplex? */
+    if(hw->forced_speed_duplex == e1000_100_full ||
+       hw->forced_speed_duplex == e1000_10_full) {
+        /* We want to force full duplex so we SET the full duplex bits in the
+         * Device and MII Control Registers.
+         */
+        ctrl |= E1000_CTRL_FD;
+        mii_ctrl_reg |= MII_CR_FULL_DUPLEX;
+        DEBUGOUT("Full Duplex\n");
+    } else {
+        /* We want to force half duplex so we CLEAR the full duplex bits in
+         * the Device and MII Control Registers.
+         */
+        ctrl &= ~E1000_CTRL_FD;
+        mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX;
+        DEBUGOUT("Half Duplex\n");
+    }
+
+    /* Are we forcing 100Mbps??? */
+    if(hw->forced_speed_duplex == e1000_100_full ||
+       hw->forced_speed_duplex == e1000_100_half) {
+        /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */
+        ctrl |= E1000_CTRL_SPD_100;
+        mii_ctrl_reg |= MII_CR_SPEED_100;
+        mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+        DEBUGOUT("Forcing 100mb ");
+    } else {
+        /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */
+        ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+        mii_ctrl_reg |= MII_CR_SPEED_10;
+        mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+        DEBUGOUT("Forcing 10mb ");
+    }
+
+    e1000_config_collision_dist(hw);
+
+    /* Write the configured values back to the Device Control Reg. */
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+
+    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+     * forced whenever speed are duplex are forced.
+     */
+    phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+    if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+    DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
+
+    /* Need to reset the PHY or these changes will be ignored */
+    mii_ctrl_reg |= MII_CR_RESET;
+
+    /* Write back the modified PHY MII control register. */
+    if(e1000_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+    udelay(1);
+
+    /* The wait_autoneg_complete flag may be a little misleading here.
+     * Since we are forcing speed and duplex, Auto-Neg is not enabled.
+     * But we do want to delay for a period while forcing only so we
+     * don't generate false No Link messages.  So we will wait here
+     * only if the user has set wait_autoneg_complete to 1, which is
+     * the default.
+     */
+    if(hw->wait_autoneg_complete) {
+        /* We will wait for autoneg to complete. */
+        DEBUGOUT("Waiting for forced speed/duplex link.\n");
+        mii_status_reg = 0;
+
+        /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+        for(i = PHY_FORCE_TIME; i > 0; i--) {
+            /* Read the MII Status Register and wait for Auto-Neg Complete bit
+             * to be set.
+             */
+            if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            if(mii_status_reg & MII_SR_LINK_STATUS) break;
+            msec_delay(100);
+        }
+        if(i == 0) { /* We didn't get link */
+            /* Reset the DSP and wait again for link. */
+            
+            ret_val = e1000_phy_reset_dsp(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error Resetting PHY DSP\n");
+                return ret_val;
+            }
+        }
+        /* This loop will early-out if the link condition has been met.  */
+        for(i = PHY_FORCE_TIME; i > 0; i--) {
+            if(mii_status_reg & MII_SR_LINK_STATUS) break;
+            msec_delay(100);
+            /* Read the MII Status Register and wait for Auto-Neg Complete bit
+             * to be set.
+             */
+            if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+        }
+    }
+    
+    /* Because we reset the PHY above, we need to re-force TX_CLK in the
+     * Extended PHY Specific Control Register to 25MHz clock.  This value
+     * defaults back to a 2.5MHz clock when the PHY is reset.
+     */
+    if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    phy_data |= M88E1000_EPSCR_TX_CLK_25;
+    if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* In addition, because of the s/w reset above, we need to enable CRS on
+     * TX.  This must be set for both full and half duplex operation.
+     */
+    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+    if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Sets the collision distance in the Transmit Control register
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Link should have been established previously. Reads the speed and duplex
+* information from the Device Status register.
+******************************************************************************/
+void
+e1000_config_collision_dist(struct e1000_hw *hw)
+{
+    uint32_t tctl;
+
+    tctl = E1000_READ_REG(hw, TCTL);
+
+    tctl &= ~E1000_TCTL_COLD;
+    tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+    E1000_WRITE_REG(hw, TCTL, tctl);
+    E1000_WRITE_FLUSH(hw);
+}
+
+/******************************************************************************
+* Sets MAC speed and duplex settings to reflect the those in the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* mii_reg - data to write to the MII control register
+*
+* The contents of the PHY register containing the needed information need to
+* be passed in.
+******************************************************************************/
+static int32_t
+e1000_config_mac_to_phy(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_config_mac_to_phy");
+
+    /* Read the Device Control Register and set the bits to Force Speed
+     * and Duplex.
+     */
+    ctrl = E1000_READ_REG(hw, CTRL);
+    ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+    ctrl &= ~(E1000_CTRL_SPD_SEL | E1000_CTRL_ILOS);
+
+    /* Set up duplex in the Device Control and Transmit Control
+     * registers depending on negotiated values.
+     */
+    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD;
+    else ctrl &= ~E1000_CTRL_FD;
+
+    e1000_config_collision_dist(hw);
+
+    /* Set up speed in the Device Control register depending on
+     * negotiated values.
+     */
+    if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
+        ctrl |= E1000_CTRL_SPD_1000;
+    else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
+        ctrl |= E1000_CTRL_SPD_100;
+    /* Write the configured values back to the Device Control Reg. */
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+    return 0;
+}
+
+/******************************************************************************
+ * Forces the MAC's flow control settings.
+ * 
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sets the TFCE and RFCE bits in the device control register to reflect
+ * the adapter settings. TFCE and RFCE need to be explicitly set by
+ * software when a Copper PHY is used because autonegotiation is managed
+ * by the PHY rather than the MAC. Software must also configure these
+ * bits when link is forced on a fiber connection.
+ *****************************************************************************/
+static int32_t
+e1000_force_mac_fc(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+
+    DEBUGFUNC("e1000_force_mac_fc");
+
+    /* Get the current configuration of the Device Control Register */
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    /* Because we didn't get link via the internal auto-negotiation
+     * mechanism (we either forced link or we got link via PHY
+     * auto-neg), we have to manually enable/disable transmit an
+     * receive flow control.
+     *
+     * The "Case" statement below enables/disable flow control
+     * according to the "hw->fc" parameter.
+     *
+     * The possible values of the "fc" parameter are:
+     *      0:  Flow control is completely disabled
+     *      1:  Rx flow control is enabled (we can receive pause
+     *          frames but not send pause frames).
+     *      2:  Tx flow control is enabled (we can send pause frames
+     *          frames but we do not receive pause frames).
+     *      3:  Both Rx and TX flow control (symmetric) is enabled.
+     *  other:  No other values should be possible at this point.
+     */
+
+    switch (hw->fc) {
+    case e1000_fc_none:
+        ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+        break;
+    case e1000_fc_rx_pause:
+        ctrl &= (~E1000_CTRL_TFCE);
+        ctrl |= E1000_CTRL_RFCE;
+        break;
+    case e1000_fc_tx_pause:
+        ctrl &= (~E1000_CTRL_RFCE);
+        ctrl |= E1000_CTRL_TFCE;
+        break;
+    case e1000_fc_full:
+        ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+        break;
+    default:
+        DEBUGOUT("Flow control param set incorrectly\n");
+        return -E1000_ERR_CONFIG;
+    }
+
+    /* Disable TX Flow Control for 82542 (rev 2.0) */
+    if(hw->mac_type == e1000_82542_rev2_0)
+        ctrl &= (~E1000_CTRL_TFCE);
+
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+    return 0;
+}
+
+/******************************************************************************
+ * Configures flow control settings after link is established
+ * 
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Should be called immediately after a valid link has been established.
+ * Forces MAC flow control settings if link was forced. When in MII/GMII mode
+ * and autonegotiation is enabled, the MAC flow control settings will be set
+ * based on the flow control negotiated by the PHY. In TBI mode, the TFCE
+ * and RFCE bits will be automaticaly set to the negotiated flow control mode.
+ *****************************************************************************/
+int32_t
+e1000_config_fc_after_link_up(struct e1000_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t mii_status_reg;
+    uint16_t mii_nway_adv_reg;
+    uint16_t mii_nway_lp_ability_reg;
+    uint16_t speed;
+    uint16_t duplex;
+
+    DEBUGFUNC("e1000_config_fc_after_link_up");
+
+    /* Check for the case where we have fiber media and auto-neg failed
+     * so we had to force link.  In this case, we need to force the
+     * configuration of the MAC to match the "fc" parameter.
+     */
+    if(((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed)) ||
+       ((hw->media_type == e1000_media_type_copper) && (!hw->autoneg))) {
+        ret_val = e1000_force_mac_fc(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error forcing flow control settings\n");
+            return ret_val;
+        }
+    }
+
+    /* Check for the case where we have copper media and auto-neg is
+     * enabled.  In this case, we need to check and see if Auto-Neg
+     * has completed, and if so, how the PHY and link partner has
+     * flow control configured.
+     */
+    if((hw->media_type == e1000_media_type_copper) && hw->autoneg) {
+        /* Read the MII Status Register and check to see if AutoNeg
+         * has completed.  We read this twice because this reg has
+         * some "sticky" (latched) bits.
+         */
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+            DEBUGOUT("PHY Read Error \n");
+            return -E1000_ERR_PHY;
+        }
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+            DEBUGOUT("PHY Read Error \n");
+            return -E1000_ERR_PHY;
+        }
+
+        if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
+            /* The AutoNeg process has completed, so we now need to
+             * read both the Auto Negotiation Advertisement Register
+             * (Address 4) and the Auto_Negotiation Base Page Ability
+             * Register (Address 5) to determine how flow control was
+             * negotiated.
+             */
+            if(e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            if(e1000_read_phy_reg(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+
+            /* Two bits in the Auto Negotiation Advertisement Register
+             * (Address 4) and two bits in the Auto Negotiation Base
+             * Page Ability Register (Address 5) determine flow control
+             * for both the PHY and the link partner.  The following
+             * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+             * 1999, describes these PAUSE resolution bits and how flow
+             * control is determined based upon these settings.
+             * NOTE:  DC = Don't Care
+             *
+             *   LOCAL DEVICE  |   LINK PARTNER
+             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+             *-------|---------|-------|---------|--------------------
+             *   0   |    0    |  DC   |   DC    | e1000_fc_none
+             *   0   |    1    |   0   |   DC    | e1000_fc_none
+             *   0   |    1    |   1   |    0    | e1000_fc_none
+             *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+             *   1   |    0    |   0   |   DC    | e1000_fc_none
+             *   1   |   DC    |   1   |   DC    | e1000_fc_full
+             *   1   |    1    |   0   |    0    | e1000_fc_none
+             *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+             *
+             */
+            /* Are both PAUSE bits set to 1?  If so, this implies
+             * Symmetric Flow Control is enabled at both ends.  The
+             * ASM_DIR bits are irrelevant per the spec.
+             *
+             * For Symmetric Flow Control:
+             *
+             *   LOCAL DEVICE  |   LINK PARTNER
+             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+             *-------|---------|-------|---------|--------------------
+             *   1   |   DC    |   1   |   DC    | e1000_fc_full
+             *
+             */
+            if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+               (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+                /* Now we need to check if the user selected RX ONLY
+                 * of pause frames.  In this case, we had to advertise
+                 * FULL flow control because we could not advertise RX
+                 * ONLY. Hence, we must now check to see if we need to
+                 * turn OFF  the TRANSMISSION of PAUSE frames.
+                 */
+                if(hw->original_fc == e1000_fc_full) {
+                    hw->fc = e1000_fc_full;
+                    DEBUGOUT("Flow Control = FULL.\r\n");
+                } else {
+                    hw->fc = e1000_fc_rx_pause;
+                    DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+                }
+            }
+            /* For receiving PAUSE frames ONLY.
+             *
+             *   LOCAL DEVICE  |   LINK PARTNER
+             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+             *-------|---------|-------|---------|--------------------
+             *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+             *
+             */
+            else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+                    (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+                    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+                    (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+                hw->fc = e1000_fc_tx_pause;
+                DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n");
+            }
+            /* For transmitting PAUSE frames ONLY.
+             *
+             *   LOCAL DEVICE  |   LINK PARTNER
+             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+             *-------|---------|-------|---------|--------------------
+             *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+             *
+             */
+            else if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+                    (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+                    !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+                    (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+                hw->fc = e1000_fc_rx_pause;
+                DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+            }
+            /* Per the IEEE spec, at this point flow control should be
+             * disabled.  However, we want to consider that we could
+             * be connected to a legacy switch that doesn't advertise
+             * desired flow control, but can be forced on the link
+             * partner.  So if we advertised no flow control, that is
+             * what we will resolve to.  If we advertised some kind of
+             * receive capability (Rx Pause Only or Full Flow Control)
+             * and the link partner advertised none, we will configure
+             * ourselves to enable Rx Flow Control only.  We can do
+             * this safely for two reasons:  If the link partner really
+             * didn't want flow control enabled, and we enable Rx, no
+             * harm done since we won't be receiving any PAUSE frames
+             * anyway.  If the intent on the link partner was to have
+             * flow control enabled, then by us enabling RX only, we
+             * can at least receive pause frames and process them.
+             * This is a good idea because in most cases, since we are
+             * predominantly a server NIC, more times than not we will
+             * be asked to delay transmission of packets than asking
+             * our link partner to pause transmission of frames.
+             */
+            else if(hw->original_fc == e1000_fc_none ||
+                    hw->original_fc == e1000_fc_tx_pause) {
+                hw->fc = e1000_fc_none;
+                DEBUGOUT("Flow Control = NONE.\r\n");
+            } else {
+                hw->fc = e1000_fc_rx_pause;
+                DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+            }
+
+            /* Now we need to do one last check...  If we auto-
+             * negotiated to HALF DUPLEX, flow control should not be
+             * enabled per IEEE 802.3 spec.
+             */
+            e1000_get_speed_and_duplex(hw, &speed, &duplex);
+
+            if(duplex == HALF_DUPLEX)
+                hw->fc = e1000_fc_none;
+
+            /* Now we call a subroutine to actually force the MAC
+             * controller to use the correct flow control settings.
+             */
+            ret_val = e1000_force_mac_fc(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error forcing flow control settings\n");
+                return ret_val;
+             }
+        } else {
+            DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n");
+        }
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Checks to see if the link status of the hardware has changed.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Called by any function that needs to check the link status of the adapter.
+ *****************************************************************************/
+int32_t
+e1000_check_for_link(struct e1000_hw *hw)
+{
+    uint32_t rxcw;
+    uint32_t ctrl;
+    uint32_t status;
+    uint32_t rctl;
+    uint32_t signal;
+    int32_t ret_val;
+    uint16_t phy_data;
+    uint16_t lp_capability;
+
+    DEBUGFUNC("e1000_check_for_link");
+    
+    /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be 
+     * set when the optics detect a signal. On older adapters, it will be 
+     * cleared when there is a signal
+     */
+    if(hw->mac_type > e1000_82544) signal = E1000_CTRL_SWDPIN1;
+    else signal = 0;
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+    status = E1000_READ_REG(hw, STATUS);
+    rxcw = E1000_READ_REG(hw, RXCW);
+
+    /* If we have a copper PHY then we only want to go out to the PHY
+     * registers to see if Auto-Neg has completed and/or if our link
+     * status has changed.  The get_link_status flag will be set if we
+     * receive a Link Status Change interrupt or we have Rx Sequence
+     * Errors.
+     */
+    if((hw->media_type == e1000_media_type_copper) && hw->get_link_status) {
+        /* First we want to see if the MII Status Register reports
+         * link.  If so, then we want to get the current speed/duplex
+         * of the PHY.
+         * Read the register twice since the link bit is sticky.
+         */
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+
+        if(phy_data & MII_SR_LINK_STATUS) {
+            hw->get_link_status = FALSE;
+        } else {
+            /* No link detected */
+            return 0;
+        }
+
+        /* If we are forcing speed/duplex, then we simply return since
+         * we have already determined whether we have link or not.
+         */
+        if(!hw->autoneg) return -E1000_ERR_CONFIG;
+
+        /* We have a M88E1000 PHY and Auto-Neg is enabled.  If we
+         * have Si on board that is 82544 or newer, Auto
+         * Speed Detection takes care of MAC speed/duplex
+         * configuration.  So we only need to configure Collision
+         * Distance in the MAC.  Otherwise, we need to force
+         * speed/duplex on the MAC to the current PHY speed/duplex
+         * settings.
+         */
+        if(hw->mac_type >= e1000_82544)
+            e1000_config_collision_dist(hw);
+        else {
+            ret_val = e1000_config_mac_to_phy(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error configuring MAC to PHY settings\n");
+                return ret_val;
+            }
+        }
+
+        /* Configure Flow Control now that Auto-Neg has completed. First, we 
+         * need to restore the desired flow control settings because we may
+         * have had to re-autoneg with a different link partner.
+         */
+        ret_val = e1000_config_fc_after_link_up(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error configuring flow control\n");
+            return ret_val;
+        }
+
+        /* At this point we know that we are on copper and we have
+         * auto-negotiated link.  These are conditions for checking the link
+         * parter capability register.  We use the link partner capability to
+         * determine if TBI Compatibility needs to be turned on or off.  If
+         * the link partner advertises any speed in addition to Gigabit, then
+         * we assume that they are GMII-based, and TBI compatibility is not
+         * needed. If no other speeds are advertised, we assume the link
+         * partner is TBI-based, and we turn on TBI Compatibility.
+         */
+        if(hw->tbi_compatibility_en) {
+            if(e1000_read_phy_reg(hw, PHY_LP_ABILITY, &lp_capability) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            if(lp_capability & (NWAY_LPAR_10T_HD_CAPS |
+                                NWAY_LPAR_10T_FD_CAPS |
+                                NWAY_LPAR_100TX_HD_CAPS |
+                                NWAY_LPAR_100TX_FD_CAPS |
+                                NWAY_LPAR_100T4_CAPS)) {
+                /* If our link partner advertises anything in addition to 
+                 * gigabit, we do not need to enable TBI compatibility.
+                 */
+                if(hw->tbi_compatibility_on) {
+                    /* If we previously were in the mode, turn it off. */
+                    rctl = E1000_READ_REG(hw, RCTL);
+                    rctl &= ~E1000_RCTL_SBP;
+                    E1000_WRITE_REG(hw, RCTL, rctl);
+                    hw->tbi_compatibility_on = FALSE;
+                }
+            } else {
+                /* If TBI compatibility is was previously off, turn it on. For
+                 * compatibility with a TBI link partner, we will store bad
+                 * packets. Some frames have an additional byte on the end and
+                 * will look like CRC errors to to the hardware.
+                 */
+                if(!hw->tbi_compatibility_on) {
+                    hw->tbi_compatibility_on = TRUE;
+                    rctl = E1000_READ_REG(hw, RCTL);
+                    rctl |= E1000_RCTL_SBP;
+                    E1000_WRITE_REG(hw, RCTL, rctl);
+                }
+            }
+        }
+    }
+    /* If we don't have link (auto-negotiation failed or link partner cannot
+     * auto-negotiate), the cable is plugged in (we have signal), and our
+     * link partner is not trying to auto-negotiate with us (we are receiving
+     * idles or data), we need to force link up. We also need to give
+     * auto-negotiation time to complete, in case the cable was just plugged
+     * in. The autoneg_failed flag does this.
+     */
+    else if((hw->media_type == e1000_media_type_fiber) &&
+            (!(status & E1000_STATUS_LU)) &&
+            ((ctrl & E1000_CTRL_SWDPIN1) == signal) &&
+            (!(rxcw & E1000_RXCW_C))) {
+        if(hw->autoneg_failed == 0) {
+            hw->autoneg_failed = 1;
+            return 0;
+        }
+        DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n");
+
+        /* Disable auto-negotiation in the TXCW register */
+        E1000_WRITE_REG(hw, TXCW, (hw->txcw & ~E1000_TXCW_ANE));
+
+        /* Force link-up and also force full-duplex. */
+        ctrl = E1000_READ_REG(hw, CTRL);
+        ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+
+        /* Configure Flow Control after forcing link up. */
+        ret_val = e1000_config_fc_after_link_up(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error configuring flow control\n");
+            return ret_val;
+        }
+    }
+    /* If we are forcing link and we are receiving /C/ ordered sets, re-enable
+     * auto-negotiation in the TXCW register and disable forced link in the
+     * Device Control register in an attempt to auto-negotiate with our link
+     * partner.
+     */
+    else if((hw->media_type == e1000_media_type_fiber) &&
+              (ctrl & E1000_CTRL_SLU) &&
+              (rxcw & E1000_RXCW_C)) {
+        DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n");
+        E1000_WRITE_REG(hw, TXCW, hw->txcw);
+        E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU));
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Detects the current speed and duplex settings of the hardware.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ *****************************************************************************/
+void
+e1000_get_speed_and_duplex(struct e1000_hw *hw,
+                           uint16_t *speed,
+                           uint16_t *duplex)
+{
+    uint32_t status;
+
+    DEBUGFUNC("e1000_get_speed_and_duplex");
+
+    if(hw->mac_type >= e1000_82543) {
+        status = E1000_READ_REG(hw, STATUS);
+        if(status & E1000_STATUS_SPEED_1000) {
+            *speed = SPEED_1000;
+            DEBUGOUT("1000 Mbs, ");
+        } else if(status & E1000_STATUS_SPEED_100) {
+            *speed = SPEED_100;
+            DEBUGOUT("100 Mbs, ");
+        } else {
+            *speed = SPEED_10;
+            DEBUGOUT("10 Mbs, ");
+        }
+
+        if(status & E1000_STATUS_FD) {
+            *duplex = FULL_DUPLEX;
+            DEBUGOUT("Full Duplex\r\n");
+        } else {
+            *duplex = HALF_DUPLEX;
+            DEBUGOUT(" Half Duplex\r\n");
+        }
+    } else {
+        DEBUGOUT("1000 Mbs, Full Duplex\r\n");
+        *speed = SPEED_1000;
+        *duplex = FULL_DUPLEX;
+    }
+}
+
+/******************************************************************************
+* Blocks until autoneg completes or times out (~4.5 seconds)
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_wait_autoneg(struct e1000_hw *hw)
+{
+    uint16_t i;
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_wait_autoneg");
+    DEBUGOUT("Waiting for Auto-Neg to complete.\n");
+
+    /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+    for(i = PHY_AUTO_NEG_TIME; i > 0; i--) {
+        /* Read the MII Status Register and wait for Auto-Neg
+         * Complete bit to be set.
+         */
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(phy_data & MII_SR_AUTONEG_COMPLETE) {
+            return 0;
+        }
+        msec_delay(100);
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Raises the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+e1000_raise_mdi_clk(struct e1000_hw *hw,
+                    uint32_t *ctrl)
+{
+    /* Raise the clock input to the Management Data Clock (by setting the MDC
+     * bit), and then delay 2 microseconds.
+     */
+    E1000_WRITE_REG(hw, CTRL, (*ctrl | E1000_CTRL_MDC));
+    E1000_WRITE_FLUSH(hw);
+    udelay(2);
+}
+
+/******************************************************************************
+* Lowers the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+e1000_lower_mdi_clk(struct e1000_hw *hw,
+                    uint32_t *ctrl)
+{
+    /* Lower the clock input to the Management Data Clock (by clearing the MDC
+     * bit), and then delay 2 microseconds.
+     */
+    E1000_WRITE_REG(hw, CTRL, (*ctrl & ~E1000_CTRL_MDC));
+    E1000_WRITE_FLUSH(hw);
+    udelay(2);
+}
+
+/******************************************************************************
+* Shifts data bits out to the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* data - Data to send out to the PHY
+* count - Number of bits to shift out
+*
+* Bits are shifted out in MSB to LSB order.
+******************************************************************************/
+static void
+e1000_shift_out_mdi_bits(struct e1000_hw *hw,
+                         uint32_t data,
+                         uint16_t count)
+{
+    uint32_t ctrl;
+    uint32_t mask;
+
+    /* We need to shift "count" number of bits out to the PHY. So, the value
+     * in the "data" parameter will be shifted out to the PHY one bit at a 
+     * time. In order to do this, "data" must be broken down into bits.
+     */
+    mask = 0x01;
+    mask <<= (count - 1);
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    /* Set MDIO_DIR and MDC_DIR direction bits to be used as output pins. */
+    ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
+
+    while(mask) {
+        /* A "1" is shifted out to the PHY by setting the MDIO bit to "1" and
+         * then raising and lowering the Management Data Clock. A "0" is
+         * shifted out to the PHY by setting the MDIO bit to "0" and then
+         * raising and lowering the clock.
+         */
+        if(data & mask) ctrl |= E1000_CTRL_MDIO;
+        else ctrl &= ~E1000_CTRL_MDIO;
+
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        E1000_WRITE_FLUSH(hw);
+
+        udelay(2);
+
+        e1000_raise_mdi_clk(hw, &ctrl);
+        e1000_lower_mdi_clk(hw, &ctrl);
+
+        mask = mask >> 1;
+    }
+}
+
+/******************************************************************************
+* Shifts data bits in from the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Bits are shifted in in MSB to LSB order. 
+******************************************************************************/
+static uint16_t
+e1000_shift_in_mdi_bits(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint16_t data = 0;
+    uint8_t i;
+
+    /* In order to read a register from the PHY, we need to shift in a total
+     * of 18 bits from the PHY. The first two bit (turnaround) times are used
+     * to avoid contention on the MDIO pin when a read operation is performed.
+     * These two bits are ignored by us and thrown away. Bits are "shifted in"
+     * by raising the input to the Management Data Clock (setting the MDC bit),
+     * and then reading the value of the MDIO bit.
+     */ 
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as input. */
+    ctrl &= ~E1000_CTRL_MDIO_DIR;
+    ctrl &= ~E1000_CTRL_MDIO;
+
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+    E1000_WRITE_FLUSH(hw);
+
+    /* Raise and Lower the clock before reading in the data. This accounts for
+     * the turnaround bits. The first clock occurred when we clocked out the
+     * last bit of the Register Address.
+     */
+    e1000_raise_mdi_clk(hw, &ctrl);
+    e1000_lower_mdi_clk(hw, &ctrl);
+
+    for(data = 0, i = 0; i < 16; i++) {
+        data = data << 1;
+        e1000_raise_mdi_clk(hw, &ctrl);
+        ctrl = E1000_READ_REG(hw, CTRL);
+        /* Check to see if we shifted in a "1". */
+        if(ctrl & E1000_CTRL_MDIO) data |= 1;
+        e1000_lower_mdi_clk(hw, &ctrl);
+    }
+
+    e1000_raise_mdi_clk(hw, &ctrl);
+    e1000_lower_mdi_clk(hw, &ctrl);
+
+    return data;
+}
+
+/*****************************************************************************
+* Reads the value from a PHY register
+*
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to read
+******************************************************************************/
+int32_t
+e1000_read_phy_reg(struct e1000_hw *hw,
+                   uint32_t reg_addr,
+                   uint16_t *phy_data)
+{
+    uint32_t i;
+    uint32_t mdic = 0;
+    const uint32_t phy_addr = 1;
+
+    DEBUGFUNC("e1000_read_phy_reg");
+
+    if(reg_addr > MAX_PHY_REG_ADDRESS) {
+        DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+        return -E1000_ERR_PARAM;
+    }
+
+    if(hw->mac_type > e1000_82543) {
+        /* Set up Op-code, Phy Address, and register address in the MDI
+         * Control register.  The MAC will take care of interfacing with the
+         * PHY to retrieve the desired data.
+         */
+        mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
+                (phy_addr << E1000_MDIC_PHY_SHIFT) | 
+                (E1000_MDIC_OP_READ));
+
+        E1000_WRITE_REG(hw, MDIC, mdic);
+
+        /* Poll the ready bit to see if the MDI read completed */
+        for(i = 0; i < 64; i++) {
+            udelay(10);
+            mdic = E1000_READ_REG(hw, MDIC);
+            if(mdic & E1000_MDIC_READY) break;
+        }
+        if(!(mdic & E1000_MDIC_READY)) {
+            DEBUGOUT("MDI Read did not complete\n");
+            return -E1000_ERR_PHY;
+        }
+        if(mdic & E1000_MDIC_ERROR) {
+            DEBUGOUT("MDI Error\n");
+            return -E1000_ERR_PHY;
+        }
+        *phy_data = (uint16_t) mdic;
+    } else {
+        /* We must first send a preamble through the MDIO pin to signal the
+         * beginning of an MII instruction.  This is done by sending 32
+         * consecutive "1" bits.
+         */
+        e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+        /* Now combine the next few fields that are required for a read
+         * operation.  We use this method instead of calling the
+         * e1000_shift_out_mdi_bits routine five different times. The format of
+         * a MII read instruction consists of a shift out of 14 bits and is
+         * defined as follows:
+         *    <Preamble><SOF><Op Code><Phy Addr><Reg Addr>
+         * followed by a shift in of 18 bits.  This first two bits shifted in
+         * are TurnAround bits used to avoid contention on the MDIO pin when a
+         * READ operation is performed.  These two bits are thrown away
+         * followed by a shift in of 16 bits which contains the desired data.
+         */
+        mdic = ((reg_addr) | (phy_addr << 5) | 
+                (PHY_OP_READ << 10) | (PHY_SOF << 12));
+
+        e1000_shift_out_mdi_bits(hw, mdic, 14);
+
+        /* Now that we've shifted out the read command to the MII, we need to
+         * "shift in" the 16-bit value (18 total bits) of the requested PHY
+         * register address.
+         */
+        *phy_data = e1000_shift_in_mdi_bits(hw);
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Writes a value to a PHY register
+*
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to write
+* data - data to write to the PHY
+******************************************************************************/
+int32_t
+e1000_write_phy_reg(struct e1000_hw *hw,
+                    uint32_t reg_addr,
+                    uint16_t phy_data)
+{
+    uint32_t i;
+    uint32_t mdic = 0;
+    const uint32_t phy_addr = 1;
+
+    DEBUGFUNC("e1000_write_phy_reg");
+
+    if(reg_addr > MAX_PHY_REG_ADDRESS) {
+        DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+        return -E1000_ERR_PARAM;
+    }
+
+    if(hw->mac_type > e1000_82543) {
+        /* Set up Op-code, Phy Address, register address, and data intended
+         * for the PHY register in the MDI Control register.  The MAC will take
+         * care of interfacing with the PHY to send the desired data.
+         */
+        mdic = (((uint32_t) phy_data) |
+                (reg_addr << E1000_MDIC_REG_SHIFT) |
+                (phy_addr << E1000_MDIC_PHY_SHIFT) | 
+                (E1000_MDIC_OP_WRITE));
+
+        E1000_WRITE_REG(hw, MDIC, mdic);
+
+        /* Poll the ready bit to see if the MDI read completed */
+        for(i = 0; i < 64; i++) {
+            udelay(10);
+            mdic = E1000_READ_REG(hw, MDIC);
+            if(mdic & E1000_MDIC_READY) break;
+        }
+        if(!(mdic & E1000_MDIC_READY)) {
+            DEBUGOUT("MDI Write did not complete\n");
+            return -E1000_ERR_PHY;
+        }
+    } else {
+        /* We'll need to use the SW defined pins to shift the write command
+         * out to the PHY. We first send a preamble to the PHY to signal the
+         * beginning of the MII instruction.  This is done by sending 32 
+         * consecutive "1" bits.
+         */
+        e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+        /* Now combine the remaining required fields that will indicate a 
+         * write operation. We use this method instead of calling the
+         * e1000_shift_out_mdi_bits routine for each field in the command. The
+         * format of a MII write instruction is as follows:
+         * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>.
+         */
+        mdic = ((PHY_TURNAROUND) | (reg_addr << 2) | (phy_addr << 7) |
+                (PHY_OP_WRITE << 12) | (PHY_SOF << 14));
+        mdic <<= 16;
+        mdic |= (uint32_t) phy_data;
+
+        e1000_shift_out_mdi_bits(hw, mdic, 32);
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Returns the PHY to the power-on reset state
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+void
+e1000_phy_hw_reset(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint32_t ctrl_ext;
+
+    DEBUGFUNC("e1000_phy_hw_reset");
+
+    DEBUGOUT("Resetting Phy...\n");
+
+    if(hw->mac_type > e1000_82543) {
+        /* Read the device control register and assert the E1000_CTRL_PHY_RST
+         * bit. Then, take it out of reset.
+         */
+        ctrl = E1000_READ_REG(hw, CTRL);
+        E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST);
+        E1000_WRITE_FLUSH(hw);
+        msec_delay(10);
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        E1000_WRITE_FLUSH(hw);
+    } else {
+        /* Read the Extended Device Control Register, assert the PHY_RESET_DIR
+         * bit to put the PHY into reset. Then, take it out of reset.
+         */
+        ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+        ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
+        ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+        E1000_WRITE_FLUSH(hw);
+        msec_delay(10);
+        ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+        E1000_WRITE_FLUSH(hw);
+    }
+    udelay(150);
+}
+
+/******************************************************************************
+* Resets the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Sets bit 15 of the MII Control regiser
+******************************************************************************/
+int32_t
+e1000_phy_reset(struct e1000_hw *hw)
+{
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_phy_reset");
+
+    if(e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    phy_data |= MII_CR_RESET;
+    if(e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+    udelay(1);
+    return 0;
+}
+
+/******************************************************************************
+* Probes the expected PHY address for known PHY IDs
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_detect_gig_phy(struct e1000_hw *hw)
+{
+    uint16_t phy_id_high, phy_id_low;
+    boolean_t match = FALSE;
+
+    DEBUGFUNC("e1000_detect_gig_phy");
+
+    /* Read the PHY ID Registers to identify which PHY is onboard. */
+    if(e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    hw->phy_id = (uint32_t) (phy_id_high << 16);
+    udelay(2);
+    if(e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
+    hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK;
+
+    switch(hw->mac_type) {
+    case e1000_82543:
+        if(hw->phy_id == M88E1000_E_PHY_ID) match = TRUE;
+        break;
+    case e1000_82544:
+        if(hw->phy_id == M88E1000_I_PHY_ID) match = TRUE;
+        break;
+    case e1000_82540:
+    case e1000_82545:
+    case e1000_82546:
+        if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE;
+        break;
+    default:
+        DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
+        return -E1000_ERR_CONFIG;
+    }
+    if(match) {
+        DEBUGOUT1("PHY ID 0x%X detected\n", hw->phy_id);
+        return 0;
+    }
+    DEBUGOUT1("Invalid PHY ID 0x%X\n", hw->phy_id);
+    return -E1000_ERR_PHY;
+}
+
+/******************************************************************************
+* Resets the PHY's DSP
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_phy_reset_dsp(struct e1000_hw *hw)
+{
+    int32_t ret_val = -E1000_ERR_PHY;
+    DEBUGFUNC("e1000_phy_reset_dsp");
+    
+    do {
+        if(e1000_write_phy_reg(hw, 29, 0x001d) < 0) break;
+        if(e1000_write_phy_reg(hw, 30, 0x00c1) < 0) break;
+        if(e1000_write_phy_reg(hw, 30, 0x0000) < 0) break;
+        ret_val = 0;
+    } while(0);
+
+    if(ret_val < 0) DEBUGOUT("PHY Write Error\n");
+    return ret_val;
+}
+
+/******************************************************************************
+* Get PHY information from various PHY registers
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+e1000_phy_get_info(struct e1000_hw *hw,
+                   struct e1000_phy_info *phy_info)
+{
+    int32_t ret_val = -E1000_ERR_PHY;
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_phy_get_info");
+
+    phy_info->cable_length = e1000_cable_length_undefined;
+    phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_undefined;
+    phy_info->cable_polarity = e1000_rev_polarity_undefined;
+    phy_info->polarity_correction = e1000_polarity_reversal_undefined;
+    phy_info->mdix_mode = e1000_auto_x_mode_undefined;
+    phy_info->local_rx = e1000_1000t_rx_status_undefined;
+    phy_info->remote_rx = e1000_1000t_rx_status_undefined;
+
+    if(hw->media_type != e1000_media_type_copper) {
+        DEBUGOUT("PHY info is only valid for copper media\n");
+        return -E1000_ERR_CONFIG;
+    }
+
+    do {
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break;
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break;
+        if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
+            DEBUGOUT("PHY info is only valid if link is up\n");
+            return -E1000_ERR_CONFIG;
+        }
+
+        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0)
+            break;
+        phy_info->extended_10bt_distance =
+            (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
+            M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
+        phy_info->polarity_correction =
+            (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >>
+            M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
+
+        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
+            break;
+        phy_info->cable_polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
+            M88E1000_PSSR_REV_POLARITY_SHIFT;
+        phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
+            M88E1000_PSSR_MDIX_SHIFT;
+        if(phy_data & M88E1000_PSSR_1000MBS) {
+            /* Cable Length Estimation and Local/Remote Receiver Informatoion
+             * are only valid at 1000 Mbps
+             */
+            phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+                                      M88E1000_PSSR_CABLE_LENGTH_SHIFT);
+            if(e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0) 
+                break;
+            phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+                SR_1000T_LOCAL_RX_STATUS_SHIFT;
+            phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+                SR_1000T_REMOTE_RX_STATUS_SHIFT;
+        }
+        ret_val = 0;
+    } while(0);
+
+    if(ret_val < 0) DEBUGOUT("PHY Read Error\n");
+    return ret_val;
+}
+
+int32_t
+e1000_validate_mdi_setting(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_validate_mdi_settings");
+
+    if(!hw->autoneg && (hw->mdix == 0 || hw->mdix == 3)) {
+        DEBUGOUT("Invalid MDI setting detected\n");
+        hw->mdix = 1;
+        return -E1000_ERR_CONFIG;
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Raises the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+e1000_raise_ee_clk(struct e1000_hw *hw,
+                   uint32_t *eecd)
+{
+    /* Raise the clock input to the EEPROM (by setting the SK bit), and then
+     * wait <delay> microseconds.
+     */
+    *eecd = *eecd | E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, *eecd);
+    E1000_WRITE_FLUSH(hw);
+    udelay(50);
+}
+
+/******************************************************************************
+ * Lowers the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code 
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+e1000_lower_ee_clk(struct e1000_hw *hw,
+                   uint32_t *eecd)
+{
+    /* Lower the clock input to the EEPROM (by clearing the SK bit), and then 
+     * wait 50 microseconds. 
+     */
+    *eecd = *eecd & ~E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, *eecd);
+    E1000_WRITE_FLUSH(hw);
+    udelay(50);
+}
+
+/******************************************************************************
+ * Shift data bits out to the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * data - data to send to the EEPROM
+ * count - number of bits to shift out
+ *****************************************************************************/
+static void
+e1000_shift_out_ee_bits(struct e1000_hw *hw,
+                        uint16_t data,
+                        uint16_t count)
+{
+    uint32_t eecd;
+    uint32_t mask;
+
+    /* We need to shift "count" bits out to the EEPROM. So, value in the
+     * "data" parameter will be shifted out to the EEPROM one bit at a time.
+     * In order to do this, "data" must be broken down into bits. 
+     */
+    mask = 0x01 << (count - 1);
+    eecd = E1000_READ_REG(hw, EECD);
+    eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+    do {
+        /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
+         * and then raising and then lowering the clock (the SK bit controls
+         * the clock input to the EEPROM).  A "0" is shifted out to the EEPROM
+         * by setting "DI" to "0" and then raising and then lowering the clock.
+         */
+        eecd &= ~E1000_EECD_DI;
+
+        if(data & mask)
+            eecd |= E1000_EECD_DI;
+
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+
+        udelay(50);
+
+        e1000_raise_ee_clk(hw, &eecd);
+        e1000_lower_ee_clk(hw, &eecd);
+
+        mask = mask >> 1;
+
+    } while(mask);
+
+    /* We leave the "DI" bit set to "0" when we leave this routine. */
+    eecd &= ~E1000_EECD_DI;
+    E1000_WRITE_REG(hw, EECD, eecd);
+}
+
+/******************************************************************************
+ * Shift data bits in from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static uint16_t
+e1000_shift_in_ee_bits(struct e1000_hw *hw)
+{
+    uint32_t eecd;
+    uint32_t i;
+    uint16_t data;
+
+    /* In order to read a register from the EEPROM, we need to shift 'count'
+     * bits in from the EEPROM. Bits are "shifted in" by raising the clock
+     * input to the EEPROM (setting the SK bit), and then reading the value of
+     * the "DO" bit.  During this "shifting in" process the "DI" bit should
+     * always be clear.
+     */
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+    data = 0;
+
+    for(i = 0; i < 16; i++) {
+        data = data << 1;
+        e1000_raise_ee_clk(hw, &eecd);
+
+        eecd = E1000_READ_REG(hw, EECD);
+
+        eecd &= ~(E1000_EECD_DI);
+        if(eecd & E1000_EECD_DO)
+            data |= 1;
+
+        e1000_lower_ee_clk(hw, &eecd);
+    }
+
+    return data;
+}
+
+/******************************************************************************
+ * Prepares EEPROM for access
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This 
+ * function should be called before issuing a command to the EEPROM.
+ *****************************************************************************/
+static void
+e1000_setup_eeprom(struct e1000_hw *hw)
+{
+    uint32_t eecd;
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    /* Clear SK and DI */
+    eecd &= ~(E1000_EECD_SK | E1000_EECD_DI);
+    E1000_WRITE_REG(hw, EECD, eecd);
+
+    /* Set CS */
+    eecd |= E1000_EECD_CS;
+    E1000_WRITE_REG(hw, EECD, eecd);
+}
+
+/******************************************************************************
+ * Returns EEPROM to a "standby" state
+ * 
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_standby_eeprom(struct e1000_hw *hw)
+{
+    uint32_t eecd;
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    /* Deselct EEPROM */
+    eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+    E1000_WRITE_REG(hw, EECD, eecd);
+    E1000_WRITE_FLUSH(hw);
+    udelay(50);
+
+    /* Clock high */
+    eecd |= E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, eecd);
+    E1000_WRITE_FLUSH(hw);
+    udelay(50);
+
+    /* Select EEPROM */
+    eecd |= E1000_EECD_CS;
+    E1000_WRITE_REG(hw, EECD, eecd);
+    E1000_WRITE_FLUSH(hw);
+    udelay(50);
+
+    /* Clock low */
+    eecd &= ~E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, eecd);
+    E1000_WRITE_FLUSH(hw);
+    udelay(50);
+}
+
+/******************************************************************************
+ * Raises then lowers the EEPROM's clock pin
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_clock_eeprom(struct e1000_hw *hw)
+{
+    uint32_t eecd;
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    /* Rising edge of clock */
+    eecd |= E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, eecd);
+    E1000_WRITE_FLUSH(hw);
+    udelay(50);
+
+    /* Falling edge of clock */
+    eecd &= ~E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, eecd);
+    E1000_WRITE_FLUSH(hw);
+    udelay(50);
+}
+
+/******************************************************************************
+ * Terminates a command by lowering the EEPROM's chip select pin
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_cleanup_eeprom(struct e1000_hw *hw)
+{
+    uint32_t eecd;
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+
+    E1000_WRITE_REG(hw, EECD, eecd);
+
+    e1000_clock_eeprom(hw);
+}
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM 
+ *****************************************************************************/
+int32_t
+e1000_read_eeprom(struct e1000_hw *hw,
+                  uint16_t offset,
+                  uint16_t *data)
+{
+    uint32_t eecd;
+    uint32_t i = 0;
+    boolean_t large_eeprom = FALSE;
+
+    DEBUGFUNC("e1000_read_eeprom");
+
+    /* Request EEPROM Access */
+    if(hw->mac_type > e1000_82544) {
+        eecd = E1000_READ_REG(hw, EECD);
+        if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE;
+        eecd |= E1000_EECD_REQ;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        eecd = E1000_READ_REG(hw, EECD);
+        while((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
+            i++;
+            udelay(5);
+            eecd = E1000_READ_REG(hw, EECD);
+        }
+        if(!(eecd & E1000_EECD_GNT)) {
+            eecd &= ~E1000_EECD_REQ;
+            E1000_WRITE_REG(hw, EECD, eecd);
+            DEBUGOUT("Could not acquire EEPROM grant\n");
+            return -E1000_ERR_EEPROM;
+        }
+    }
+
+    /*  Prepare the EEPROM for reading  */
+    e1000_setup_eeprom(hw);
+
+    /*  Send the READ command (opcode + addr)  */
+    e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE, 3);
+    if(large_eeprom) {
+        /* If we have a 256 word EEPROM, there are 8 address bits */
+        e1000_shift_out_ee_bits(hw, offset, 8);
+    } else {
+        /* If we have a 64 word EEPROM, there are 6 address bits */
+        e1000_shift_out_ee_bits(hw, offset, 6);
+    }
+
+    /* Read the data */
+    *data = e1000_shift_in_ee_bits(hw);
+
+    /* End this read operation */
+    e1000_standby_eeprom(hw);
+
+    /* Stop requesting EEPROM access */
+    if(hw->mac_type > e1000_82544) {
+        eecd = E1000_READ_REG(hw, EECD);
+        eecd &= ~E1000_EECD_REQ;
+        E1000_WRITE_REG(hw, EECD, eecd);
+    }
+
+    return 0;
+}
+
+/******************************************************************************
+ * Verifies that the EEPROM has a valid checksum
+ * 
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Reads the first 64 16 bit words of the EEPROM and sums the values read.
+ * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
+ * valid.
+ *****************************************************************************/
+int32_t
+e1000_validate_eeprom_checksum(struct e1000_hw *hw)
+{
+    uint16_t checksum = 0;
+    uint16_t i, eeprom_data;
+
+    DEBUGFUNC("e1000_validate_eeprom_checksum");
+
+    for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
+        if(e1000_read_eeprom(hw, i, &eeprom_data) < 0) {
+            DEBUGOUT("EEPROM Read Error\n");
+            return -E1000_ERR_EEPROM;
+        }
+        checksum += eeprom_data;
+    }
+
+    if(checksum == (uint16_t) EEPROM_SUM) {
+        return 0;
+    } else {
+        DEBUGOUT("EEPROM Checksum Invalid\n");    
+        return -E1000_ERR_EEPROM;
+    }
+}
+
+/******************************************************************************
+ * Calculates the EEPROM checksum and writes it to the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sums the first 63 16 bit words of the EEPROM. Subtracts the sum from 0xBABA.
+ * Writes the difference to word offset 63 of the EEPROM.
+ *****************************************************************************/
+int32_t
+e1000_update_eeprom_checksum(struct e1000_hw *hw)
+{
+    uint16_t checksum = 0;
+    uint16_t i, eeprom_data;
+
+    DEBUGFUNC("e1000_update_eeprom_checksum");
+
+    for(i = 0; i < EEPROM_CHECKSUM_REG; i++) {
+        if(e1000_read_eeprom(hw, i, &eeprom_data) < 0) {
+            DEBUGOUT("EEPROM Read Error\n");
+            return -E1000_ERR_EEPROM;
+        }
+        checksum += eeprom_data;
+    }
+    checksum = (uint16_t) EEPROM_SUM - checksum;
+    if(e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, checksum) < 0) {
+        DEBUGOUT("EEPROM Write Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word to a given offset in the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset within the EEPROM to be written to
+ * data - 16 bit word to be writen to the EEPROM
+ *
+ * If e1000_update_eeprom_checksum is not called after this function, the 
+ * EEPROM will most likely contain an invalid checksum.
+ *****************************************************************************/
+int32_t
+e1000_write_eeprom(struct e1000_hw *hw,
+                   uint16_t offset,
+                   uint16_t data)
+{
+    uint32_t eecd;
+    uint32_t i = 0;
+    int32_t status = 0;
+    boolean_t large_eeprom = FALSE;
+
+    DEBUGFUNC("e1000_write_eeprom");
+
+    /* Request EEPROM Access */
+    if(hw->mac_type > e1000_82544) {
+        eecd = E1000_READ_REG(hw, EECD);
+        if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE;
+        eecd |= E1000_EECD_REQ;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        eecd = E1000_READ_REG(hw, EECD);
+        while((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
+            i++;
+            udelay(5);
+            eecd = E1000_READ_REG(hw, EECD);
+        }
+        if(!(eecd & E1000_EECD_GNT)) {
+            eecd &= ~E1000_EECD_REQ;
+            E1000_WRITE_REG(hw, EECD, eecd);
+            DEBUGOUT("Could not acquire EEPROM grant\n");
+            return -E1000_ERR_EEPROM;
+        }
+    }
+
+    /* Prepare the EEPROM for writing  */
+    e1000_setup_eeprom(hw);
+
+    /* Send the 9-bit (or 11-bit on large EEPROM) EWEN (write enable) command
+     * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This puts the EEPROM
+     * into write/erase mode. 
+     */
+    e1000_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE, 5);
+    if(large_eeprom) 
+        e1000_shift_out_ee_bits(hw, 0, 6);
+    else
+        e1000_shift_out_ee_bits(hw, 0, 4);
+
+    /* Prepare the EEPROM */
+    e1000_standby_eeprom(hw);
+
+    /* Send the Write command (3-bit opcode + addr) */
+    e1000_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE, 3);
+    if(large_eeprom) 
+        /* If we have a 256 word EEPROM, there are 8 address bits */
+        e1000_shift_out_ee_bits(hw, offset, 8);
+    else
+        /* If we have a 64 word EEPROM, there are 6 address bits */
+        e1000_shift_out_ee_bits(hw, offset, 6);
+
+    /* Send the data */
+    e1000_shift_out_ee_bits(hw, data, 16);
+
+    /* Toggle the CS line.  This in effect tells to EEPROM to actually execute 
+     * the command in question.
+     */
+    e1000_standby_eeprom(hw);
+
+    /* Now read DO repeatedly until is high (equal to '1').  The EEEPROM will
+     * signal that the command has been completed by raising the DO signal.
+     * If DO does not go high in 10 milliseconds, then error out.
+     */
+    for(i = 0; i < 200; i++) {
+        eecd = E1000_READ_REG(hw, EECD);
+        if(eecd & E1000_EECD_DO) break;
+        udelay(50);
+    }
+    if(i == 200) {
+        DEBUGOUT("EEPROM Write did not complete\n");
+        status = -E1000_ERR_EEPROM;
+    }
+
+    /* Recover from write */
+    e1000_standby_eeprom(hw);
+
+    /* Send the 9-bit (or 11-bit on large EEPROM) EWDS (write disable) command
+     * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This takes the EEPROM
+     * out of write/erase mode.
+     */
+    e1000_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE, 5);
+    if(large_eeprom) 
+        e1000_shift_out_ee_bits(hw, 0, 6);
+    else
+        e1000_shift_out_ee_bits(hw, 0, 4);
+
+    /* Done with writing */
+    e1000_cleanup_eeprom(hw);
+
+    /* Stop requesting EEPROM access */
+    if(hw->mac_type > e1000_82544) {
+        eecd = E1000_READ_REG(hw, EECD);
+        eecd &= ~E1000_EECD_REQ;
+        E1000_WRITE_REG(hw, EECD, eecd);
+    }
+
+    return status;
+}
+
+/******************************************************************************
+ * Reads the adapter's part number from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ * part_num - Adapter's part number
+ *****************************************************************************/
+int32_t
+e1000_read_part_num(struct e1000_hw *hw,
+                    uint32_t *part_num)
+{
+    uint16_t offset = EEPROM_PBA_BYTE_1;
+    uint16_t eeprom_data;
+
+    DEBUGFUNC("e1000_read_part_num");
+
+    /* Get word 0 from EEPROM */
+    if(e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
+        DEBUGOUT("EEPROM Read Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+    /* Save word 0 in upper half of part_num */
+    *part_num = (uint32_t) (eeprom_data << 16);
+
+    /* Get word 1 from EEPROM */
+    if(e1000_read_eeprom(hw, ++offset, &eeprom_data) < 0) {
+        DEBUGOUT("EEPROM Read Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+    /* Save word 1 in lower half of part_num */
+    *part_num |= eeprom_data;
+
+    return 0;
+}
+
+/******************************************************************************
+ * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
+ * second function of dual function devices
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_read_mac_addr(struct e1000_hw * hw)
+{
+    uint16_t offset;
+    uint16_t eeprom_data, i;
+
+    DEBUGFUNC("e1000_read_mac_addr");
+
+    for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
+        offset = i >> 1;
+        if(e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
+            DEBUGOUT("EEPROM Read Error\n");
+            return -E1000_ERR_EEPROM;
+        }
+        hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF);
+        hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8);
+    }
+    if((hw->mac_type == e1000_82546) &&
+       (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
+        if(hw->perm_mac_addr[5] & 0x01)
+            hw->perm_mac_addr[5] &= ~(0x01);
+        else
+            hw->perm_mac_addr[5] |= 0x01;
+    }
+    for(i = 0; i < NODE_ADDRESS_SIZE; i++)
+        hw->mac_addr[i] = hw->perm_mac_addr[i];
+    return 0;
+}
+
+/******************************************************************************
+ * Initializes receive address filters.
+ *
+ * hw - Struct containing variables accessed by shared code 
+ *
+ * Places the MAC address in receive address register 0 and clears the rest
+ * of the receive addresss registers. Clears the multicast table. Assumes
+ * the receiver is in reset when the routine is called.
+ *****************************************************************************/
+void
+e1000_init_rx_addrs(struct e1000_hw *hw)
+{
+    uint32_t i;
+    uint32_t addr_low;
+    uint32_t addr_high;
+
+    DEBUGFUNC("e1000_init_rx_addrs");
+
+    /* Setup the receive address. */
+    DEBUGOUT("Programming MAC Address into RAR[0]\n");
+    addr_low = (hw->mac_addr[0] |
+                (hw->mac_addr[1] << 8) |
+                (hw->mac_addr[2] << 16) | (hw->mac_addr[3] << 24));
+
+    addr_high = (hw->mac_addr[4] |
+                 (hw->mac_addr[5] << 8) | E1000_RAH_AV);
+
+    E1000_WRITE_REG_ARRAY(hw, RA, 0, addr_low);
+    E1000_WRITE_REG_ARRAY(hw, RA, 1, addr_high);
+
+    /* Zero out the other 15 receive addresses. */
+    DEBUGOUT("Clearing RAR[1-15]\n");
+    for(i = 1; i < E1000_RAR_ENTRIES; i++) {
+        E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+        E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+    }
+}
+
+/******************************************************************************
+ * Updates the MAC's list of multicast addresses.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr_list - the list of new multicast addresses
+ * mc_addr_count - number of addresses
+ * pad - number of bytes between addresses in the list
+ *
+ * The given list replaces any existing list. Clears the last 15 receive
+ * address registers and the multicast table. Uses receive address registers
+ * for the first 15 multicast addresses, and hashes the rest into the 
+ * multicast table.
+ *****************************************************************************/
+void
+e1000_mc_addr_list_update(struct e1000_hw *hw,
+                          uint8_t *mc_addr_list,
+                          uint32_t mc_addr_count,
+                          uint32_t pad)
+{
+    uint32_t hash_value;
+    uint32_t i;
+    uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */
+
+    DEBUGFUNC("e1000_mc_addr_list_update");
+
+    /* Set the new number of MC addresses that we are being requested to use. */
+    hw->num_mc_addrs = mc_addr_count;
+
+    /* Clear RAR[1-15] */
+    DEBUGOUT(" Clearing RAR[1-15]\n");
+    for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) {
+        E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+        E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+    }
+
+    /* Clear the MTA */
+    DEBUGOUT(" Clearing MTA\n");
+    for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) {
+        E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+    }
+
+    /* Add the new addresses */
+    for(i = 0; i < mc_addr_count; i++) {
+        DEBUGOUT(" Adding the multicast addresses:\n");
+        DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i,
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]);
+
+        hash_value = e1000_hash_mc_addr(hw,
+                                        mc_addr_list +
+                                        (i * (ETH_LENGTH_OF_ADDRESS + pad)));
+
+        DEBUGOUT1(" Hash value = 0x%03X\n", hash_value);
+
+        /* Place this multicast address in the RAR if there is room, *
+         * else put it in the MTA            
+         */
+        if(rar_used_count < E1000_RAR_ENTRIES) {
+            e1000_rar_set(hw,
+                          mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)),
+                          rar_used_count);
+            rar_used_count++;
+        } else {
+            e1000_mta_set(hw, hash_value);
+        }
+    }
+    DEBUGOUT("MC Update Complete\n");
+}
+
+/******************************************************************************
+ * Hashes an address to determine its location in the multicast table
+ *
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr - the multicast address to hash 
+ *****************************************************************************/
+uint32_t
+e1000_hash_mc_addr(struct e1000_hw *hw,
+                   uint8_t *mc_addr)
+{
+    uint32_t hash_value = 0;
+
+    /* The portion of the address that is used for the hash table is
+     * determined by the mc_filter_type setting.  
+     */
+    switch (hw->mc_filter_type) {
+    /* [0] [1] [2] [3] [4] [5]
+     * 01  AA  00  12  34  56
+     * LSB                 MSB
+     */
+    case 0:
+        /* [47:36] i.e. 0x563 for above example address */
+        hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
+        break;
+    case 1:
+        /* [46:35] i.e. 0xAC6 for above example address */
+        hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5));
+        break;
+    case 2:
+        /* [45:34] i.e. 0x5D8 for above example address */
+        hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
+        break;
+    case 3:
+        /* [43:32] i.e. 0x634 for above example address */
+        hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8));
+        break;
+    }
+
+    hash_value &= 0xFFF;
+    return hash_value;
+}
+
+/******************************************************************************
+ * Sets the bit in the multicast table corresponding to the hash value.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * hash_value - Multicast address hash value
+ *****************************************************************************/
+void
+e1000_mta_set(struct e1000_hw *hw,
+              uint32_t hash_value)
+{
+    uint32_t hash_bit, hash_reg;
+    uint32_t mta;
+    uint32_t temp;
+
+    /* The MTA is a register array of 128 32-bit registers.  
+     * It is treated like an array of 4096 bits.  We want to set 
+     * bit BitArray[hash_value]. So we figure out what register
+     * the bit is in, read it, OR in the new bit, then write
+     * back the new value.  The register is determined by the 
+     * upper 7 bits of the hash value and the bit within that 
+     * register are determined by the lower 5 bits of the value.
+     */
+    hash_reg = (hash_value >> 5) & 0x7F;
+    hash_bit = hash_value & 0x1F;
+
+    mta = E1000_READ_REG_ARRAY(hw, MTA, hash_reg);
+
+    mta |= (1 << hash_bit);
+
+    /* If we are on an 82544 and we are trying to write an odd offset
+     * in the MTA, save off the previous entry before writing and
+     * restore the old value after writing.
+     */
+    if((hw->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) {
+        temp = E1000_READ_REG_ARRAY(hw, MTA, (hash_reg - 1));
+        E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+        E1000_WRITE_REG_ARRAY(hw, MTA, (hash_reg - 1), temp);
+    } else {
+        E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+    }
+}
+
+/******************************************************************************
+ * Puts an ethernet address into a receive address register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * addr - Address to put into receive address register
+ * index - Receive address register to write
+ *****************************************************************************/
+void
+e1000_rar_set(struct e1000_hw *hw,
+              uint8_t *addr,
+              uint32_t index)
+{
+    uint32_t rar_low, rar_high;
+
+    /* HW expects these in little endian so we reverse the byte order
+     * from network order (big endian) to little endian              
+     */
+    rar_low = ((uint32_t) addr[0] |
+               ((uint32_t) addr[1] << 8) |
+               ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24));
+
+    rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV);
+
+    E1000_WRITE_REG_ARRAY(hw, RA, (index << 1), rar_low);
+    E1000_WRITE_REG_ARRAY(hw, RA, ((index << 1) + 1), rar_high);
+}
+
+/******************************************************************************
+ * Writes a value to the specified offset in the VLAN filter table.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - Offset in VLAN filer table to write
+ * value - Value to write into VLAN filter table
+ *****************************************************************************/
+void
+e1000_write_vfta(struct e1000_hw *hw,
+                 uint32_t offset,
+                 uint32_t value)
+{
+    uint32_t temp;
+
+    if((hw->mac_type == e1000_82544) && ((offset & 0x1) == 1)) {
+        temp = E1000_READ_REG_ARRAY(hw, VFTA, (offset - 1));
+        E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+        E1000_WRITE_REG_ARRAY(hw, VFTA, (offset - 1), temp);
+    } else {
+        E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+    }
+}
+
+/******************************************************************************
+ * Clears the VLAN filer table
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_clear_vfta(struct e1000_hw *hw)
+{
+    uint32_t offset;
+
+    for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++)
+        E1000_WRITE_REG_ARRAY(hw, VFTA, offset, 0);
+}
+
+static int32_t
+e1000_id_led_init(struct e1000_hw * hw)
+{
+    uint32_t ledctl;
+    const uint32_t ledctl_mask = 0x000000FF;
+    const uint32_t ledctl_on = E1000_LEDCTL_MODE_LED_ON;
+    const uint32_t ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
+    uint16_t eeprom_data, i, temp;
+    const uint16_t led_mask = 0x0F;
+        
+    DEBUGFUNC("e1000_id_led_init");
+    
+    if(hw->mac_type < e1000_82540) {
+        /* Nothing to do */
+        return 0;
+    }
+    
+    ledctl = E1000_READ_REG(hw, LEDCTL);
+    hw->ledctl_default = ledctl;
+    hw->ledctl_mode1 = hw->ledctl_default;
+    hw->ledctl_mode2 = hw->ledctl_default;
+        
+    if(e1000_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, &eeprom_data) < 0) {
+        DEBUGOUT("EEPROM Read Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+    if((eeprom_data== ID_LED_RESERVED_0000) || 
+       (eeprom_data == ID_LED_RESERVED_FFFF)) eeprom_data = ID_LED_DEFAULT;
+    for(i = 0; i < 4; i++) {
+        temp = (eeprom_data >> (i << 2)) & led_mask;
+        switch(temp) {
+        case ID_LED_ON1_DEF2:
+        case ID_LED_ON1_ON2:
+        case ID_LED_ON1_OFF2:
+            hw->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+            hw->ledctl_mode1 |= ledctl_on << (i << 3);
+            break;
+        case ID_LED_OFF1_DEF2:
+        case ID_LED_OFF1_ON2:
+        case ID_LED_OFF1_OFF2:
+            hw->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+            hw->ledctl_mode1 |= ledctl_off << (i << 3);
+            break;
+        default:
+            /* Do nothing */
+            break;
+        }
+        switch(temp) {
+        case ID_LED_DEF1_ON2:
+        case ID_LED_ON1_ON2:
+        case ID_LED_OFF1_ON2:
+            hw->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+            hw->ledctl_mode2 |= ledctl_on << (i << 3);
+            break;
+        case ID_LED_DEF1_OFF2:
+        case ID_LED_ON1_OFF2:
+        case ID_LED_OFF1_OFF2:
+            hw->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+            hw->ledctl_mode2 |= ledctl_off << (i << 3);
+            break;
+        default:
+            /* Do nothing */
+            break;
+        }
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Prepares SW controlable LED for use and saves the current state of the LED.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_setup_led(struct e1000_hw *hw)
+{
+    uint32_t ledctl;
+ 
+    DEBUGFUNC("e1000_setup_led");
+   
+    switch(hw->device_id) {
+    case E1000_DEV_ID_82542:
+    case E1000_DEV_ID_82543GC_FIBER:
+    case E1000_DEV_ID_82543GC_COPPER:
+    case E1000_DEV_ID_82544EI_COPPER:
+    case E1000_DEV_ID_82544EI_FIBER:
+    case E1000_DEV_ID_82544GC_COPPER:
+    case E1000_DEV_ID_82544GC_LOM:
+        /* No setup necessary */
+        break;
+    case E1000_DEV_ID_82545EM_FIBER:
+    case E1000_DEV_ID_82546EB_FIBER:
+        ledctl = E1000_READ_REG(hw, LEDCTL);
+        /* Save current LEDCTL settings */
+        hw->ledctl_default = ledctl;
+        /* Turn off LED0 */
+        ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
+                    E1000_LEDCTL_LED0_BLINK | 
+                    E1000_LEDCTL_LED0_MODE_MASK);
+        ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT);
+        E1000_WRITE_REG(hw, LEDCTL, ledctl);
+        break;
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
+    case E1000_DEV_ID_82540EM:
+    case E1000_DEV_ID_82540EM_LOM:
+    case E1000_DEV_ID_82545EM_COPPER:
+    case E1000_DEV_ID_82546EB_COPPER:
+        E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
+        break;
+    default:
+        DEBUGOUT("Invalid device ID\n");
+        return -E1000_ERR_CONFIG;
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Restores the saved state of the SW controlable LED.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_cleanup_led(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_cleanup_led");
+
+    switch(hw->device_id) {
+    case E1000_DEV_ID_82542:
+    case E1000_DEV_ID_82543GC_FIBER:
+    case E1000_DEV_ID_82543GC_COPPER:
+    case E1000_DEV_ID_82544EI_COPPER:
+    case E1000_DEV_ID_82544EI_FIBER:
+    case E1000_DEV_ID_82544GC_COPPER:
+    case E1000_DEV_ID_82544GC_LOM:
+        /* No cleanup necessary */
+        break;
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
+    case E1000_DEV_ID_82540EM:
+    case E1000_DEV_ID_82540EM_LOM:
+    case E1000_DEV_ID_82545EM_COPPER:
+    case E1000_DEV_ID_82545EM_FIBER:
+    case E1000_DEV_ID_82546EB_COPPER:
+    case E1000_DEV_ID_82546EB_FIBER:
+        /* Restore LEDCTL settings */
+        E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default);
+        break;
+    default:
+        DEBUGOUT("Invalid device ID\n");
+        return -E1000_ERR_CONFIG;
+    }
+    return 0;
+}
+    
+/******************************************************************************
+ * Turns on the software controllable LED
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_led_on(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+
+    DEBUGFUNC("e1000_led_on");
+
+    switch(hw->device_id) {
+    case E1000_DEV_ID_82542:
+    case E1000_DEV_ID_82543GC_FIBER:
+    case E1000_DEV_ID_82543GC_COPPER:
+    case E1000_DEV_ID_82544EI_FIBER:
+        ctrl = E1000_READ_REG(hw, CTRL);
+        /* Set SW Defineable Pin 0 to turn on the LED */
+        ctrl |= E1000_CTRL_SWDPIN0;
+        ctrl |= E1000_CTRL_SWDPIO0;
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        break;
+    case E1000_DEV_ID_82544EI_COPPER:
+    case E1000_DEV_ID_82544GC_COPPER:
+    case E1000_DEV_ID_82544GC_LOM:
+    case E1000_DEV_ID_82545EM_FIBER:
+    case E1000_DEV_ID_82546EB_FIBER:
+        ctrl = E1000_READ_REG(hw, CTRL);
+        /* Clear SW Defineable Pin 0 to turn on the LED */
+        ctrl &= ~E1000_CTRL_SWDPIN0;
+        ctrl |= E1000_CTRL_SWDPIO0;
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        break;
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
+    case E1000_DEV_ID_82540EM:
+    case E1000_DEV_ID_82540EM_LOM:
+    case E1000_DEV_ID_82545EM_COPPER:
+    case E1000_DEV_ID_82546EB_COPPER:
+        E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2);
+        break;
+    default:
+        DEBUGOUT("Invalid device ID\n");
+        return -E1000_ERR_CONFIG;
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Turns off the software controllable LED
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_led_off(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+
+    DEBUGFUNC("e1000_led_off");
+
+    switch(hw->device_id) {
+    case E1000_DEV_ID_82542:
+    case E1000_DEV_ID_82543GC_FIBER:
+    case E1000_DEV_ID_82543GC_COPPER:
+    case E1000_DEV_ID_82544EI_FIBER:
+        ctrl = E1000_READ_REG(hw, CTRL);
+        /* Clear SW Defineable Pin 0 to turn off the LED */
+        ctrl &= ~E1000_CTRL_SWDPIN0;
+        ctrl |= E1000_CTRL_SWDPIO0;
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        break;
+    case E1000_DEV_ID_82544EI_COPPER:
+    case E1000_DEV_ID_82544GC_COPPER:
+    case E1000_DEV_ID_82544GC_LOM:
+    case E1000_DEV_ID_82545EM_FIBER:
+    case E1000_DEV_ID_82546EB_FIBER:
+        ctrl = E1000_READ_REG(hw, CTRL);
+        /* Set SW Defineable Pin 0 to turn off the LED */
+        ctrl |= E1000_CTRL_SWDPIN0;
+        ctrl |= E1000_CTRL_SWDPIO0;
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        break;
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
+    case E1000_DEV_ID_82540EM:
+    case E1000_DEV_ID_82540EM_LOM:
+    case E1000_DEV_ID_82545EM_COPPER:
+    case E1000_DEV_ID_82546EB_COPPER:
+        E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
+        break;
+    default:
+        DEBUGOUT("Invalid device ID\n");
+        return -E1000_ERR_CONFIG;
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Clears all hardware statistics counters. 
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_clear_hw_cntrs(struct e1000_hw *hw)
+{
+    volatile uint32_t temp;
+
+    temp = E1000_READ_REG(hw, CRCERRS);
+    temp = E1000_READ_REG(hw, SYMERRS);
+    temp = E1000_READ_REG(hw, MPC);
+    temp = E1000_READ_REG(hw, SCC);
+    temp = E1000_READ_REG(hw, ECOL);
+    temp = E1000_READ_REG(hw, MCC);
+    temp = E1000_READ_REG(hw, LATECOL);
+    temp = E1000_READ_REG(hw, COLC);
+    temp = E1000_READ_REG(hw, DC);
+    temp = E1000_READ_REG(hw, SEC);
+    temp = E1000_READ_REG(hw, RLEC);
+    temp = E1000_READ_REG(hw, XONRXC);
+    temp = E1000_READ_REG(hw, XONTXC);
+    temp = E1000_READ_REG(hw, XOFFRXC);
+    temp = E1000_READ_REG(hw, XOFFTXC);
+    temp = E1000_READ_REG(hw, FCRUC);
+    temp = E1000_READ_REG(hw, PRC64);
+    temp = E1000_READ_REG(hw, PRC127);
+    temp = E1000_READ_REG(hw, PRC255);
+    temp = E1000_READ_REG(hw, PRC511);
+    temp = E1000_READ_REG(hw, PRC1023);
+    temp = E1000_READ_REG(hw, PRC1522);
+    temp = E1000_READ_REG(hw, GPRC);
+    temp = E1000_READ_REG(hw, BPRC);
+    temp = E1000_READ_REG(hw, MPRC);
+    temp = E1000_READ_REG(hw, GPTC);
+    temp = E1000_READ_REG(hw, GORCL);
+    temp = E1000_READ_REG(hw, GORCH);
+    temp = E1000_READ_REG(hw, GOTCL);
+    temp = E1000_READ_REG(hw, GOTCH);
+    temp = E1000_READ_REG(hw, RNBC);
+    temp = E1000_READ_REG(hw, RUC);
+    temp = E1000_READ_REG(hw, RFC);
+    temp = E1000_READ_REG(hw, ROC);
+    temp = E1000_READ_REG(hw, RJC);
+    temp = E1000_READ_REG(hw, TORL);
+    temp = E1000_READ_REG(hw, TORH);
+    temp = E1000_READ_REG(hw, TOTL);
+    temp = E1000_READ_REG(hw, TOTH);
+    temp = E1000_READ_REG(hw, TPR);
+    temp = E1000_READ_REG(hw, TPT);
+    temp = E1000_READ_REG(hw, PTC64);
+    temp = E1000_READ_REG(hw, PTC127);
+    temp = E1000_READ_REG(hw, PTC255);
+    temp = E1000_READ_REG(hw, PTC511);
+    temp = E1000_READ_REG(hw, PTC1023);
+    temp = E1000_READ_REG(hw, PTC1522);
+    temp = E1000_READ_REG(hw, MPTC);
+    temp = E1000_READ_REG(hw, BPTC);
+
+    if(hw->mac_type < e1000_82543) return;
+
+    temp = E1000_READ_REG(hw, ALGNERRC);
+    temp = E1000_READ_REG(hw, RXERRC);
+    temp = E1000_READ_REG(hw, TNCRS);
+    temp = E1000_READ_REG(hw, CEXTERR);
+    temp = E1000_READ_REG(hw, TSCTC);
+    temp = E1000_READ_REG(hw, TSCTFC);
+
+    if(hw->mac_type <= e1000_82544) return;
+
+    temp = E1000_READ_REG(hw, MGTPRC);
+    temp = E1000_READ_REG(hw, MGTPDC);
+    temp = E1000_READ_REG(hw, MGTPTC);
+}
+
+/******************************************************************************
+ * Resets Adaptive IFS to its default state.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Call this after e1000_init_hw. You may override the IFS defaults by setting
+ * hw->ifs_params_forced to TRUE. However, you must initialize hw->
+ * current_ifs_val, ifs_min_val, ifs_max_val, ifs_step_size, and ifs_ratio
+ * before calling this function.
+ *****************************************************************************/
+void
+e1000_reset_adaptive(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_reset_adaptive");
+
+    if(hw->adaptive_ifs) {
+        if(!hw->ifs_params_forced) {
+            hw->current_ifs_val = 0;
+            hw->ifs_min_val = IFS_MIN;
+            hw->ifs_max_val = IFS_MAX;
+            hw->ifs_step_size = IFS_STEP;
+            hw->ifs_ratio = IFS_RATIO;
+        }
+        hw->in_ifs_mode = FALSE;
+        E1000_WRITE_REG(hw, AIT, 0);
+    } else {
+        DEBUGOUT("Not in Adaptive IFS mode!\n");
+    }
+}
+
+/******************************************************************************
+ * Called during the callback/watchdog routine to update IFS value based on
+ * the ratio of transmits to collisions.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * tx_packets - Number of transmits since last callback
+ * total_collisions - Number of collisions since last callback
+ *****************************************************************************/
+void
+e1000_update_adaptive(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_update_adaptive");
+
+    if(hw->adaptive_ifs) {
+        if((hw->collision_delta * hw->ifs_ratio) > 
+           hw->tx_packet_delta) {
+            if(hw->tx_packet_delta > MIN_NUM_XMITS) {
+                hw->in_ifs_mode = TRUE;
+                if(hw->current_ifs_val < hw->ifs_max_val) {
+                    if(hw->current_ifs_val == 0)
+                        hw->current_ifs_val = hw->ifs_min_val;
+                    else
+                        hw->current_ifs_val += hw->ifs_step_size;
+                    E1000_WRITE_REG(hw, AIT, hw->current_ifs_val);
+                }
+            }
+        } else {
+            if((hw->in_ifs_mode == TRUE) && 
+               (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
+                hw->current_ifs_val = 0;
+                hw->in_ifs_mode = FALSE;
+                E1000_WRITE_REG(hw, AIT, 0);
+            }
+        }
+    } else {
+        DEBUGOUT("Not in Adaptive IFS mode!\n");
+    }
+}
+
+/******************************************************************************
+ * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
+ * 
+ * hw - Struct containing variables accessed by shared code
+ * frame_len - The length of the frame in question
+ * mac_addr - The Ethernet destination address of the frame in question
+ *****************************************************************************/
+void
+e1000_tbi_adjust_stats(struct e1000_hw *hw,
+                       struct e1000_hw_stats *stats,
+                       uint32_t frame_len,
+                       uint8_t *mac_addr)
+{
+    uint64_t carry_bit;
+
+    /* First adjust the frame length. */
+    frame_len--;
+    /* We need to adjust the statistics counters, since the hardware
+     * counters overcount this packet as a CRC error and undercount
+     * the packet as a good packet
+     */
+    /* This packet should not be counted as a CRC error.    */
+    stats->crcerrs--;
+    /* This packet does count as a Good Packet Received.    */
+    stats->gprc++;
+
+    /* Adjust the Good Octets received counters             */
+    carry_bit = 0x80000000 & stats->gorcl;
+    stats->gorcl += frame_len;
+    /* If the high bit of Gorcl (the low 32 bits of the Good Octets
+     * Received Count) was one before the addition, 
+     * AND it is zero after, then we lost the carry out, 
+     * need to add one to Gorch (Good Octets Received Count High).
+     * This could be simplified if all environments supported 
+     * 64-bit integers.
+     */
+    if(carry_bit && ((stats->gorcl & 0x80000000) == 0))
+        stats->gorch++;
+    /* Is this a broadcast or multicast?  Check broadcast first,
+     * since the test for a multicast frame will test positive on 
+     * a broadcast frame.
+     */
+    if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
+        /* Broadcast packet */
+        stats->bprc++;
+    else if(*mac_addr & 0x01)
+        /* Multicast packet */
+        stats->mprc++;
+
+    if(frame_len == hw->max_frame_size) {
+        /* In this case, the hardware has overcounted the number of
+         * oversize frames.
+         */
+        if(stats->roc > 0)
+            stats->roc--;
+    }
+
+    /* Adjust the bin counters when the extra byte put the frame in the
+     * wrong bin. Remember that the frame_len was adjusted above.
+     */
+    if(frame_len == 64) {
+        stats->prc64++;
+        stats->prc127--;
+    } else if(frame_len == 127) {
+        stats->prc127++;
+        stats->prc255--;
+    } else if(frame_len == 255) {
+        stats->prc255++;
+        stats->prc511--;
+    } else if(frame_len == 511) {
+        stats->prc511++;
+        stats->prc1023--;
+    } else if(frame_len == 1023) {
+        stats->prc1023++;
+        stats->prc1522--;
+    } else if(frame_len == 1522) {
+        stats->prc1522++;
+    }
+}
+
+/******************************************************************************
+ * Gets the current PCI bus type, speed, and width of the hardware
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_get_bus_info(struct e1000_hw *hw)
+{
+    uint32_t status;
+
+    if(hw->mac_type < e1000_82543) {
+        hw->bus_type = e1000_bus_type_unknown;
+        hw->bus_speed = e1000_bus_speed_unknown;
+        hw->bus_width = e1000_bus_width_unknown;
+        return;
+    }
+
+    status = E1000_READ_REG(hw, STATUS);
+    hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
+                   e1000_bus_type_pcix : e1000_bus_type_pci;
+    if(hw->bus_type == e1000_bus_type_pci) {
+        hw->bus_speed = (status & E1000_STATUS_PCI66) ?
+                        e1000_bus_speed_66 : e1000_bus_speed_33;
+    } else {
+        switch (status & E1000_STATUS_PCIX_SPEED) {
+        case E1000_STATUS_PCIX_SPEED_66:
+            hw->bus_speed = e1000_bus_speed_66;
+            break;
+        case E1000_STATUS_PCIX_SPEED_100:
+            hw->bus_speed = e1000_bus_speed_100;
+            break;
+        case E1000_STATUS_PCIX_SPEED_133:
+            hw->bus_speed = e1000_bus_speed_133;
+            break;
+        default:
+            hw->bus_speed = e1000_bus_speed_reserved;
+            break;
+        }
+    }
+    hw->bus_width = (status & E1000_STATUS_BUS64) ?
+                    e1000_bus_width_64 : e1000_bus_width_32;
+}
+/******************************************************************************
+ * Reads a value from one of the devices registers using port I/O (as opposed
+ * memory mapped I/O). Only 82544 and newer devices support port I/O.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset to read from
+ *****************************************************************************/
+uint32_t
+e1000_read_reg_io(struct e1000_hw *hw,
+                  uint32_t offset)
+{
+    uint32_t io_addr = hw->io_base;
+    uint32_t io_data = hw->io_base + 4;
+
+    e1000_io_write(hw, io_addr, offset);
+    return e1000_io_read(hw, io_data);
+}
+
+/******************************************************************************
+ * Writes a value to one of the devices registers using port I/O (as opposed to
+ * memory mapped I/O). Only 82544 and newer devices support port I/O.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset to write to
+ * value - value to write
+ *****************************************************************************/
+void
+e1000_write_reg_io(struct e1000_hw *hw,
+                   uint32_t offset,
+                   uint32_t value)
+{
+    uint32_t io_addr = hw->io_base;
+    uint32_t io_data = hw->io_base + 4;
+
+    e1000_io_write(hw, io_addr, offset);
+    e1000_io_write(hw, io_data, value);
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e1000/e1000_hw.h linux-2.4.20/drivers/net/e1000/e1000_hw.h
--- linux-2.4.19/drivers/net/e1000/e1000_hw.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e1000/e1000_hw.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,1789 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* e1000_hw.h
+ * Structures, enums, and macros for the MAC
+ */
+
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
+
+#include "e1000_osdep.h"
+
+/* Forward declarations of structures used by the shared code */
+struct e1000_hw;
+struct e1000_hw_stats;
+
+/* Enumerated types specific to the e1000 hardware */
+/* Media Access Controlers */
+typedef enum {
+    e1000_undefined = 0,
+    e1000_82542_rev2_0,
+    e1000_82542_rev2_1,
+    e1000_82543,
+    e1000_82544,
+    e1000_82540,
+    e1000_82545,
+    e1000_82546,
+    e1000_num_macs
+} e1000_mac_type;
+
+/* Media Types */
+typedef enum {
+    e1000_media_type_copper = 0,
+    e1000_media_type_fiber = 1,
+    e1000_num_media_types
+} e1000_media_type;
+
+typedef enum {
+    e1000_10_half = 0,
+    e1000_10_full = 1,
+    e1000_100_half = 2,
+    e1000_100_full = 3
+} e1000_speed_duplex_type;
+
+/* Flow Control Settings */
+typedef enum {
+    e1000_fc_none = 0,
+    e1000_fc_rx_pause = 1,
+    e1000_fc_tx_pause = 2,
+    e1000_fc_full = 3,
+    e1000_fc_default = 0xFF
+} e1000_fc_type;
+
+/* PCI bus types */
+typedef enum {
+    e1000_bus_type_unknown = 0,
+    e1000_bus_type_pci,
+    e1000_bus_type_pcix
+} e1000_bus_type;
+
+/* PCI bus speeds */
+typedef enum {
+    e1000_bus_speed_unknown = 0,
+    e1000_bus_speed_33,
+    e1000_bus_speed_66,
+    e1000_bus_speed_100,
+    e1000_bus_speed_133,
+    e1000_bus_speed_reserved
+} e1000_bus_speed;
+
+/* PCI bus widths */
+typedef enum {
+    e1000_bus_width_unknown = 0,
+    e1000_bus_width_32,
+    e1000_bus_width_64
+} e1000_bus_width;
+
+/* PHY status info structure and supporting enums */
+typedef enum {
+    e1000_cable_length_50 = 0,
+    e1000_cable_length_50_80,
+    e1000_cable_length_80_110,
+    e1000_cable_length_110_140,
+    e1000_cable_length_140,
+    e1000_cable_length_undefined = 0xFF
+} e1000_cable_length;
+
+typedef enum {
+    e1000_10bt_ext_dist_enable_normal = 0,
+    e1000_10bt_ext_dist_enable_lower,
+    e1000_10bt_ext_dist_enable_undefined = 0xFF
+} e1000_10bt_ext_dist_enable;
+
+typedef enum {
+    e1000_rev_polarity_normal = 0,
+    e1000_rev_polarity_reversed,
+    e1000_rev_polarity_undefined = 0xFF
+} e1000_rev_polarity;
+
+typedef enum {
+    e1000_polarity_reversal_enabled = 0,
+    e1000_polarity_reversal_disabled,
+    e1000_polarity_reversal_undefined = 0xFF
+} e1000_polarity_reversal;
+
+typedef enum {
+    e1000_auto_x_mode_manual_mdi = 0,
+    e1000_auto_x_mode_manual_mdix,
+    e1000_auto_x_mode_auto1,
+    e1000_auto_x_mode_auto2,
+    e1000_auto_x_mode_undefined = 0xFF
+} e1000_auto_x_mode;
+
+typedef enum {
+    e1000_1000t_rx_status_not_ok = 0,
+    e1000_1000t_rx_status_ok,
+    e1000_1000t_rx_status_undefined = 0xFF
+} e1000_1000t_rx_status;
+
+struct e1000_phy_info {
+    e1000_cable_length cable_length;
+    e1000_10bt_ext_dist_enable extended_10bt_distance;
+    e1000_rev_polarity cable_polarity;
+    e1000_polarity_reversal polarity_correction;
+    e1000_auto_x_mode mdix_mode;
+    e1000_1000t_rx_status local_rx;
+    e1000_1000t_rx_status remote_rx;
+};
+
+struct e1000_phy_stats {
+    uint32_t idle_errors;
+    uint32_t receive_errors;
+};
+
+
+
+/* Error Codes */
+#define E1000_SUCCESS      0
+#define E1000_ERR_EEPROM   1
+#define E1000_ERR_PHY      2
+#define E1000_ERR_CONFIG   3
+#define E1000_ERR_PARAM    4
+#define E1000_ERR_MAC_TYPE 5
+
+/* Function prototypes */
+/* Initialization */
+void e1000_reset_hw(struct e1000_hw *hw);
+int32_t e1000_init_hw(struct e1000_hw *hw);
+int32_t e1000_set_mac_type(struct e1000_hw *hw);
+
+/* Link Configuration */
+int32_t e1000_setup_link(struct e1000_hw *hw);
+int32_t e1000_phy_setup_autoneg(struct e1000_hw *hw);
+void e1000_config_collision_dist(struct e1000_hw *hw);
+int32_t e1000_config_fc_after_link_up(struct e1000_hw *hw);
+int32_t e1000_check_for_link(struct e1000_hw *hw);
+void e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t * speed, uint16_t * duplex);
+int32_t e1000_wait_autoneg(struct e1000_hw *hw);
+
+/* PHY */
+int32_t e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *phy_data);
+int32_t e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data);
+void e1000_phy_hw_reset(struct e1000_hw *hw);
+int32_t e1000_phy_reset(struct e1000_hw *hw);
+int32_t e1000_detect_gig_phy(struct e1000_hw *hw);
+int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
+int32_t e1000_validate_mdi_setting(struct e1000_hw *hw);
+
+/* EEPROM Functions */
+int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t *data);
+int32_t e1000_validate_eeprom_checksum(struct e1000_hw *hw);
+int32_t e1000_update_eeprom_checksum(struct e1000_hw *hw);
+int32_t e1000_write_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t data);
+int32_t e1000_read_part_num(struct e1000_hw *hw, uint32_t * part_num);
+int32_t e1000_read_mac_addr(struct e1000_hw * hw);
+
+/* Filters (multicast, vlan, receive) */
+void e1000_init_rx_addrs(struct e1000_hw *hw);
+void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad);
+uint32_t e1000_hash_mc_addr(struct e1000_hw *hw, uint8_t * mc_addr);
+void e1000_mta_set(struct e1000_hw *hw, uint32_t hash_value);
+void e1000_rar_set(struct e1000_hw *hw, uint8_t * mc_addr, uint32_t rar_index);
+void e1000_write_vfta(struct e1000_hw *hw, uint32_t offset, uint32_t value);
+void e1000_clear_vfta(struct e1000_hw *hw);
+
+/* LED functions */
+int32_t e1000_setup_led(struct e1000_hw *hw);
+int32_t e1000_cleanup_led(struct e1000_hw *hw);
+int32_t e1000_led_on(struct e1000_hw *hw);
+int32_t e1000_led_off(struct e1000_hw *hw);
+
+/* Adaptive IFS Functions */
+
+/* Everything else */
+void e1000_clear_hw_cntrs(struct e1000_hw *hw);
+void e1000_reset_adaptive(struct e1000_hw *hw);
+void e1000_update_adaptive(struct e1000_hw *hw);
+void e1000_tbi_adjust_stats(struct e1000_hw *hw, struct e1000_hw_stats *stats, uint32_t frame_len, uint8_t * mac_addr);
+void e1000_get_bus_info(struct e1000_hw *hw);
+void e1000_pci_set_mwi(struct e1000_hw *hw);
+void e1000_pci_clear_mwi(struct e1000_hw *hw);
+void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
+void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
+/* Port I/O is only supported on 82544 and newer */
+uint32_t e1000_io_read(struct e1000_hw *hw, uint32_t port);
+uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset);
+void e1000_io_write(struct e1000_hw *hw, uint32_t port, uint32_t value);
+void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value);
+#define E1000_READ_REG_IO(a, reg) \
+    e1000_read_reg_io((a), E1000_##reg)
+#define E1000_WRITE_REG_IO(a, reg, val) \
+    e1000_write_reg_io((a), E1000_##reg, val)
+
+/* PCI Device IDs */
+#define E1000_DEV_ID_82542               0x1000
+#define E1000_DEV_ID_82543GC_FIBER       0x1001
+#define E1000_DEV_ID_82543GC_COPPER      0x1004
+#define E1000_DEV_ID_82544EI_COPPER      0x1008
+#define E1000_DEV_ID_82544EI_FIBER       0x1009
+#define E1000_DEV_ID_82544GC_COPPER      0x100C
+#define E1000_DEV_ID_82544GC_LOM         0x100D
+#define E1000_DEV_ID_82540EM             0x100E
+#define E1000_DEV_ID_82540EM_LOM         0x1015
+#define E1000_DEV_ID_82540EP_LOM         0x1016
+#define E1000_DEV_ID_82540EP             0x1017
+#define E1000_DEV_ID_82540EP_LP          0x101E
+#define E1000_DEV_ID_82545EM_COPPER      0x100F
+#define E1000_DEV_ID_82545EM_FIBER       0x1011
+#define E1000_DEV_ID_82546EB_COPPER      0x1010
+#define E1000_DEV_ID_82546EB_FIBER       0x1012
+#define NUM_DEV_IDS 16
+
+#define NODE_ADDRESS_SIZE 6
+#define ETH_LENGTH_OF_ADDRESS 6
+
+/* MAC decode size is 128K - This is the size of BAR0 */
+#define MAC_DECODE_SIZE (128 * 1024)
+
+#define E1000_82542_2_0_REV_ID 2
+#define E1000_82542_2_1_REV_ID 3
+
+#define SPEED_10    10
+#define SPEED_100   100
+#define SPEED_1000  1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+/* The sizes (in bytes) of a ethernet packet */
+#define ENET_HEADER_SIZE             14
+#define MAXIMUM_ETHERNET_FRAME_SIZE  1518 /* With FCS */
+#define MINIMUM_ETHERNET_FRAME_SIZE  64   /* With FCS */
+#define ETHERNET_FCS_SIZE            4
+#define MAXIMUM_ETHERNET_PACKET_SIZE \
+    (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define MINIMUM_ETHERNET_PACKET_SIZE \
+    (MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define CRC_LENGTH                   ETHERNET_FCS_SIZE
+#define MAX_JUMBO_FRAME_SIZE         0x3F00
+
+
+/* 802.1q VLAN Packet Sizes */
+#define VLAN_TAG_SIZE                     4     /* 802.3ac tag (not DMAed) */
+
+/* Ethertype field values */
+#define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
+#define ETHERNET_IP_TYPE        0x0800  /* IP packets */
+#define ETHERNET_ARP_TYPE       0x0806  /* Address Resolution Protocol (ARP) */
+
+/* Packet Header defines */
+#define IP_PROTOCOL_TCP    6
+#define IP_PROTOCOL_UDP    0x11
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error 
+ */
+#define POLL_IMS_ENABLE_MASK ( \
+    E1000_IMS_RXDMT0 |         \
+    E1000_IMS_RXSEQ)
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXT0   = Receiver Timer Interrupt (ring 0)
+ *   o TXDW   = Transmit Descriptor Written Back
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ *   o LSC    = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+    E1000_IMS_RXT0   |    \
+    E1000_IMS_TXDW   |    \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ  |    \
+    E1000_IMS_LSC)
+
+/* The number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor. We
+ * reserve one of these spots for our directed address, allowing us room for
+ * E1000_RAR_ENTRIES - 1 multicast addresses. 
+ */
+#define E1000_RAR_ENTRIES 16
+
+#define MIN_NUMBER_OF_DESCRIPTORS 8
+#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+    uint64_t buffer_addr; /* Address of the descriptor's data buffer */
+    uint16_t length;     /* Length of data DMAed into data buffer */
+    uint16_t csum;       /* Packet checksum */
+    uint8_t status;      /* Descriptor status */
+    uint8_t errors;      /* Descriptor Errors */
+    uint16_t special;
+};
+
+/* Receive Decriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
+#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
+#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
+#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
+#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
+#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
+#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 0x000D  /* Priority is in upper 3 of 16 */
+#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 0x000C  /* CFI is bit 12 */
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+    E1000_RXD_ERR_CE  |                \
+    E1000_RXD_ERR_SE  |                \
+    E1000_RXD_ERR_SEQ |                \
+    E1000_RXD_ERR_CXE |                \
+    E1000_RXD_ERR_RXE)
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+    uint64_t buffer_addr;       /* Address of the descriptor's data buffer */
+    union {
+        uint32_t data;
+        struct {
+            uint16_t length;    /* Data buffer length */
+            uint8_t cso;        /* Checksum offset */
+            uint8_t cmd;        /* Descriptor control */
+        } flags;
+    } lower;
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t css;        /* Checksum start */
+            uint16_t special;
+        } fields;
+    } upper;
+};
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
+#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
+#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+    union {
+        uint32_t ip_config;
+        struct {
+            uint8_t ipcss;      /* IP checksum start */
+            uint8_t ipcso;      /* IP checksum offset */
+            uint16_t ipcse;     /* IP checksum end */
+        } ip_fields;
+    } lower_setup;
+    union {
+        uint32_t tcp_config;
+        struct {
+            uint8_t tucss;      /* TCP checksum start */
+            uint8_t tucso;      /* TCP checksum offset */
+            uint16_t tucse;     /* TCP checksum end */
+        } tcp_fields;
+    } upper_setup;
+    uint32_t cmd_and_length;    /* */
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t hdr_len;    /* Header length */
+            uint16_t mss;       /* Maximum segment size */
+        } fields;
+    } tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+    uint64_t buffer_addr;       /* Address of the descriptor's buffer address */
+    union {
+        uint32_t data;
+        struct {
+            uint16_t length;    /* Data buffer length */
+            uint8_t typ_len_ext;        /* */
+            uint8_t cmd;        /* */
+        } flags;
+    } lower;
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t popts;      /* Packet Options */
+            uint16_t special;   /* */
+        } fields;
+    } upper;
+};
+
+/* Filters */
+#define E1000_NUM_UNICAST          16   /* Unicast filter entries */
+#define E1000_MC_TBL_SIZE          128  /* Multicast Filter Table (4096 bits) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
+
+
+/* Receive Address Register */
+struct e1000_rar {
+    volatile uint32_t low;      /* receive address low */
+    volatile uint32_t high;     /* receive address high */
+};
+
+/* The number of entries in the Multicast Table Array (MTA). */
+#define E1000_NUM_MTA_REGISTERS 128
+
+/* IPv4 Address Table Entry */
+struct e1000_ipv4_at_entry {
+    volatile uint32_t ipv4_addr;        /* IP Address (RW) */
+    volatile uint32_t reserved;
+};
+
+/* Four wakeup IP addresses are supported */
+#define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4
+#define E1000_IP4AT_SIZE                  E1000_WAKEUP_IP_ADDRESS_COUNT_MAX
+#define E1000_IP6AT_SIZE                  1
+
+/* IPv6 Address Table Entry */
+struct e1000_ipv6_at_entry {
+    volatile uint8_t ipv6_addr[16];
+};
+
+/* Flexible Filter Length Table Entry */
+struct e1000_fflt_entry {
+    volatile uint32_t length;   /* Flexible Filter Length (RW) */
+    volatile uint32_t reserved;
+};
+
+/* Flexible Filter Mask Table Entry */
+struct e1000_ffmt_entry {
+    volatile uint32_t mask;     /* Flexible Filter Mask (RW) */
+    volatile uint32_t reserved;
+};
+
+/* Flexible Filter Value Table Entry */
+struct e1000_ffvt_entry {
+    volatile uint32_t value;    /* Flexible Filter Value (RW) */
+    volatile uint32_t reserved;
+};
+
+/* Four Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define E1000_FLEXIBLE_FILTER_SIZE_MAX  128
+
+#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
+#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+
+/* Register Set. (82543, 82544)
+ *
+ * Registers are defined to be 32 bits and  should be accessed as 32 bit values.
+ * These registers are physically located on the NIC, but are mapped into the 
+ * host memory address space.
+ *
+ * RW - register is both readable and writable
+ * RO - register is read only
+ * WO - register is write only
+ * R/clr - register is read only and is cleared when read
+ * A - register array
+ */
+#define E1000_CTRL     0x00000  /* Device Control - RW */
+#define E1000_STATUS   0x00008  /* Device Status - RO */
+#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
+#define E1000_EERD     0x00014  /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
+#define E1000_MDIC     0x00020  /* MDI Control - RW */
+#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
+#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
+#define E1000_FCT      0x00030  /* Flow Control Type - RW */
+#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
+#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
+#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
+#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
+#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
+#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
+#define E1000_RCTL     0x00100  /* RX Control - RW */
+#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW     0x00178  /* TX Configuration Word - RW */
+#define E1000_RXCW     0x00180  /* RX Configuration Word - RO */
+#define E1000_TCTL     0x00400  /* TX Control - RW */
+#define E1000_TIPG     0x00410  /* TX Inter-packet gap -RW */
+#define E1000_TBT      0x00448  /* TX Burst Timer - RW */
+#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
+#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
+#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
+#define E1000_RDBAL    0x02800  /* RX Descriptor Base Address Low - RW */
+#define E1000_RDBAH    0x02804  /* RX Descriptor Base Address High - RW */
+#define E1000_RDLEN    0x02808  /* RX Descriptor Length - RW */
+#define E1000_RDH      0x02810  /* RX Descriptor Head - RW */
+#define E1000_RDT      0x02818  /* RX Descriptor Tail - RW */
+#define E1000_RDTR     0x02820  /* RX Delay Timer - RW */
+#define E1000_RXDCTL   0x02828  /* RX Descriptor Control - RW */
+#define E1000_RADV     0x0282C  /* RX Interrupt Absolute Delay Timer - RW */
+#define E1000_RSRPD    0x02C00  /* RX Small Packet Detect - RW */
+#define E1000_TXDMAC   0x03000  /* TX DMA Control - RW */
+#define E1000_TDBAL    0x03800  /* TX Descriptor Base Address Low - RW */
+#define E1000_TDBAH    0x03804  /* TX Descriptor Base Address High - RW */
+#define E1000_TDLEN    0x03808  /* TX Descriptor Length - RW */
+#define E1000_TDH      0x03810  /* TX Descriptor Head - RW */
+#define E1000_TDT      0x03818  /* TX Descripotr Tail - RW */
+#define E1000_TIDV     0x03820  /* TX Interrupt Delay Value - RW */
+#define E1000_TXDCTL   0x03828  /* TX Descriptor Control - RW */
+#define E1000_TADV     0x0382C  /* TX Interrupt Absolute Delay Val - RW */
+#define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
+#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
+#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
+#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
+#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
+#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
+#define E1000_COLC     0x04028  /* Collision Count - R/clr */
+#define E1000_DC       0x04030  /* Defer Count - R/clr */
+#define E1000_TNCRS    0x04034  /* TX-No CRS - R/clr */
+#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC   0x04048  /* XON RX Count - R/clr */
+#define E1000_XONTXC   0x0404C  /* XON TX Count - R/clr */
+#define E1000_XOFFRXC  0x04050  /* XOFF RX Count - R/clr */
+#define E1000_XOFFTXC  0x04054  /* XOFF TX Count - R/clr */
+#define E1000_FCRUC    0x04058  /* Flow Control RX Unsupported Count- R/clr */
+#define E1000_PRC64    0x0405C  /* Packets RX (64 bytes) - R/clr */
+#define E1000_PRC127   0x04060  /* Packets RX (65-127 bytes) - R/clr */
+#define E1000_PRC255   0x04064  /* Packets RX (128-255 bytes) - R/clr */
+#define E1000_PRC511   0x04068  /* Packets RX (255-511 bytes) - R/clr */
+#define E1000_PRC1023  0x0406C  /* Packets RX (512-1023 bytes) - R/clr */
+#define E1000_PRC1522  0x04070  /* Packets RX (1024-1522 bytes) - R/clr */
+#define E1000_GPRC     0x04074  /* Good Packets RX Count - R/clr */
+#define E1000_BPRC     0x04078  /* Broadcast Packets RX Count - R/clr */
+#define E1000_MPRC     0x0407C  /* Multicast Packets RX Count - R/clr */
+#define E1000_GPTC     0x04080  /* Good Packets TX Count - R/clr */
+#define E1000_GORCL    0x04088  /* Good Octets RX Count Low - R/clr */
+#define E1000_GORCH    0x0408C  /* Good Octets RX Count High - R/clr */
+#define E1000_GOTCL    0x04090  /* Good Octets TX Count Low - R/clr */
+#define E1000_GOTCH    0x04094  /* Good Octets TX Count High - R/clr */
+#define E1000_RNBC     0x040A0  /* RX No Buffers Count - R/clr */
+#define E1000_RUC      0x040A4  /* RX Undersize Count - R/clr */
+#define E1000_RFC      0x040A8  /* RX Fragment Count - R/clr */
+#define E1000_ROC      0x040AC  /* RX Oversize Count - R/clr */
+#define E1000_RJC      0x040B0  /* RX Jabber Count - R/clr */
+#define E1000_MGTPRC   0x040B4  /* Management Packets RX Count - R/clr */
+#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC   0x040BC  /* Management Packets TX Count - R/clr */
+#define E1000_TORL     0x040C0  /* Total Octets RX Low - R/clr */
+#define E1000_TORH     0x040C4  /* Total Octets RX High - R/clr */
+#define E1000_TOTL     0x040C8  /* Total Octets TX Low - R/clr */
+#define E1000_TOTH     0x040CC  /* Total Octets TX High - R/clr */
+#define E1000_TPR      0x040D0  /* Total Packets RX - R/clr */
+#define E1000_TPT      0x040D4  /* Total Packets TX - R/clr */
+#define E1000_PTC64    0x040D8  /* Packets TX (64 bytes) - R/clr */
+#define E1000_PTC127   0x040DC  /* Packets TX (65-127 bytes) - R/clr */
+#define E1000_PTC255   0x040E0  /* Packets TX (128-255 bytes) - R/clr */
+#define E1000_PTC511   0x040E4  /* Packets TX (256-511 bytes) - R/clr */
+#define E1000_PTC1023  0x040E8  /* Packets TX (512-1023 bytes) - R/clr */
+#define E1000_PTC1522  0x040EC  /* Packets TX (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC     0x040F0  /* Multicast Packets TX Count - R/clr */
+#define E1000_BPTC     0x040F4  /* Broadcast Packets TX Count - R/clr */
+#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context TX - R/clr */
+#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context TX Fail - R/clr */
+#define E1000_RXCSUM   0x05000  /* RX Checksum Control - RW */
+#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
+#define E1000_RA       0x05400  /* Receive Address - RW Array */
+#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
+#define E1000_WUC      0x05800  /* Wakeup Control - RW */
+#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
+#define E1000_WUS      0x05810  /* Wakeup Status - RO */
+#define E1000_MANC     0x05820  /* Management Control - RW */
+#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
+#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
+#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
+#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
+#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
+#define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
+#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
+#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
+
+/* Register Set (82542)
+ *
+ * Some of the 82542 registers are located at different offsets than they are
+ * in more current versions of the 8254x. Despite the difference in location,
+ * the registers function in the same manner.
+ */
+#define E1000_82542_CTRL     E1000_CTRL
+#define E1000_82542_STATUS   E1000_STATUS
+#define E1000_82542_EECD     E1000_EECD
+#define E1000_82542_EERD     E1000_EERD
+#define E1000_82542_CTRL_EXT E1000_CTRL_EXT
+#define E1000_82542_MDIC     E1000_MDIC
+#define E1000_82542_FCAL     E1000_FCAL
+#define E1000_82542_FCAH     E1000_FCAH
+#define E1000_82542_FCT      E1000_FCT
+#define E1000_82542_VET      E1000_VET
+#define E1000_82542_RA       0x00040
+#define E1000_82542_ICR      E1000_ICR
+#define E1000_82542_ITR      E1000_ITR
+#define E1000_82542_ICS      E1000_ICS
+#define E1000_82542_IMS      E1000_IMS
+#define E1000_82542_IMC      E1000_IMC
+#define E1000_82542_RCTL     E1000_RCTL
+#define E1000_82542_RDTR     0x00108
+#define E1000_82542_RDBAL    0x00110
+#define E1000_82542_RDBAH    0x00114
+#define E1000_82542_RDLEN    0x00118
+#define E1000_82542_RDH      0x00120
+#define E1000_82542_RDT      0x00128
+#define E1000_82542_FCRTH    0x00160
+#define E1000_82542_FCRTL    0x00168
+#define E1000_82542_FCTTV    E1000_FCTTV
+#define E1000_82542_TXCW     E1000_TXCW
+#define E1000_82542_RXCW     E1000_RXCW
+#define E1000_82542_MTA      0x00200
+#define E1000_82542_TCTL     E1000_TCTL
+#define E1000_82542_TIPG     E1000_TIPG
+#define E1000_82542_TDBAL    0x00420
+#define E1000_82542_TDBAH    0x00424
+#define E1000_82542_TDLEN    0x00428
+#define E1000_82542_TDH      0x00430
+#define E1000_82542_TDT      0x00438
+#define E1000_82542_TIDV     0x00440
+#define E1000_82542_TBT      E1000_TBT
+#define E1000_82542_AIT      E1000_AIT
+#define E1000_82542_VFTA     0x00600
+#define E1000_82542_LEDCTL   E1000_LEDCTL
+#define E1000_82542_PBA      E1000_PBA
+#define E1000_82542_RXDCTL   E1000_RXDCTL
+#define E1000_82542_RADV     E1000_RADV
+#define E1000_82542_RSRPD    E1000_RSRPD
+#define E1000_82542_TXDMAC   E1000_TXDMAC
+#define E1000_82542_TXDCTL   E1000_TXDCTL
+#define E1000_82542_TADV     E1000_TADV
+#define E1000_82542_TSPMT    E1000_TSPMT
+#define E1000_82542_CRCERRS  E1000_CRCERRS
+#define E1000_82542_ALGNERRC E1000_ALGNERRC
+#define E1000_82542_SYMERRS  E1000_SYMERRS
+#define E1000_82542_RXERRC   E1000_RXERRC
+#define E1000_82542_MPC      E1000_MPC
+#define E1000_82542_SCC      E1000_SCC
+#define E1000_82542_ECOL     E1000_ECOL
+#define E1000_82542_MCC      E1000_MCC
+#define E1000_82542_LATECOL  E1000_LATECOL
+#define E1000_82542_COLC     E1000_COLC
+#define E1000_82542_DC       E1000_DC
+#define E1000_82542_TNCRS    E1000_TNCRS
+#define E1000_82542_SEC      E1000_SEC
+#define E1000_82542_CEXTERR  E1000_CEXTERR
+#define E1000_82542_RLEC     E1000_RLEC
+#define E1000_82542_XONRXC   E1000_XONRXC
+#define E1000_82542_XONTXC   E1000_XONTXC
+#define E1000_82542_XOFFRXC  E1000_XOFFRXC
+#define E1000_82542_XOFFTXC  E1000_XOFFTXC
+#define E1000_82542_FCRUC    E1000_FCRUC
+#define E1000_82542_PRC64    E1000_PRC64
+#define E1000_82542_PRC127   E1000_PRC127
+#define E1000_82542_PRC255   E1000_PRC255
+#define E1000_82542_PRC511   E1000_PRC511
+#define E1000_82542_PRC1023  E1000_PRC1023
+#define E1000_82542_PRC1522  E1000_PRC1522
+#define E1000_82542_GPRC     E1000_GPRC
+#define E1000_82542_BPRC     E1000_BPRC
+#define E1000_82542_MPRC     E1000_MPRC
+#define E1000_82542_GPTC     E1000_GPTC
+#define E1000_82542_GORCL    E1000_GORCL
+#define E1000_82542_GORCH    E1000_GORCH
+#define E1000_82542_GOTCL    E1000_GOTCL
+#define E1000_82542_GOTCH    E1000_GOTCH
+#define E1000_82542_RNBC     E1000_RNBC
+#define E1000_82542_RUC      E1000_RUC
+#define E1000_82542_RFC      E1000_RFC
+#define E1000_82542_ROC      E1000_ROC
+#define E1000_82542_RJC      E1000_RJC
+#define E1000_82542_MGTPRC   E1000_MGTPRC
+#define E1000_82542_MGTPDC   E1000_MGTPDC
+#define E1000_82542_MGTPTC   E1000_MGTPTC
+#define E1000_82542_TORL     E1000_TORL
+#define E1000_82542_TORH     E1000_TORH
+#define E1000_82542_TOTL     E1000_TOTL
+#define E1000_82542_TOTH     E1000_TOTH
+#define E1000_82542_TPR      E1000_TPR
+#define E1000_82542_TPT      E1000_TPT
+#define E1000_82542_PTC64    E1000_PTC64
+#define E1000_82542_PTC127   E1000_PTC127
+#define E1000_82542_PTC255   E1000_PTC255
+#define E1000_82542_PTC511   E1000_PTC511
+#define E1000_82542_PTC1023  E1000_PTC1023
+#define E1000_82542_PTC1522  E1000_PTC1522
+#define E1000_82542_MPTC     E1000_MPTC
+#define E1000_82542_BPTC     E1000_BPTC
+#define E1000_82542_TSCTC    E1000_TSCTC
+#define E1000_82542_TSCTFC   E1000_TSCTFC
+#define E1000_82542_RXCSUM   E1000_RXCSUM
+#define E1000_82542_WUC      E1000_WUC
+#define E1000_82542_WUFC     E1000_WUFC
+#define E1000_82542_WUS      E1000_WUS
+#define E1000_82542_MANC     E1000_MANC
+#define E1000_82542_IPAV     E1000_IPAV
+#define E1000_82542_IP4AT    E1000_IP4AT
+#define E1000_82542_IP6AT    E1000_IP6AT
+#define E1000_82542_WUPL     E1000_WUPL
+#define E1000_82542_WUPM     E1000_WUPM
+#define E1000_82542_FFLT     E1000_FFLT
+#define E1000_82542_FFMT     E1000_FFMT
+#define E1000_82542_FFVT     E1000_FFVT
+
+/* Statistics counters collected by the MAC */
+struct e1000_hw_stats {
+    uint64_t crcerrs;
+    uint64_t algnerrc;
+    uint64_t symerrs;
+    uint64_t rxerrc;
+    uint64_t mpc;
+    uint64_t scc;
+    uint64_t ecol;
+    uint64_t mcc;
+    uint64_t latecol;
+    uint64_t colc;
+    uint64_t dc;
+    uint64_t tncrs;
+    uint64_t sec;
+    uint64_t cexterr;
+    uint64_t rlec;
+    uint64_t xonrxc;
+    uint64_t xontxc;
+    uint64_t xoffrxc;
+    uint64_t xofftxc;
+    uint64_t fcruc;
+    uint64_t prc64;
+    uint64_t prc127;
+    uint64_t prc255;
+    uint64_t prc511;
+    uint64_t prc1023;
+    uint64_t prc1522;
+    uint64_t gprc;
+    uint64_t bprc;
+    uint64_t mprc;
+    uint64_t gptc;
+    uint64_t gorcl;
+    uint64_t gorch;
+    uint64_t gotcl;
+    uint64_t gotch;
+    uint64_t rnbc;
+    uint64_t ruc;
+    uint64_t rfc;
+    uint64_t roc;
+    uint64_t rjc;
+    uint64_t mgprc;
+    uint64_t mgpdc;
+    uint64_t mgptc;
+    uint64_t torl;
+    uint64_t torh;
+    uint64_t totl;
+    uint64_t toth;
+    uint64_t tpr;
+    uint64_t tpt;
+    uint64_t ptc64;
+    uint64_t ptc127;
+    uint64_t ptc255;
+    uint64_t ptc511;
+    uint64_t ptc1023;
+    uint64_t ptc1522;
+    uint64_t mptc;
+    uint64_t bptc;
+    uint64_t tsctc;
+    uint64_t tsctfc;
+};
+
+/* Structure containing variables used by the shared code (e1000_hw.c) */
+struct e1000_hw {
+    uint8_t *hw_addr;
+    e1000_mac_type mac_type;
+    e1000_media_type media_type;
+    void *back;
+    e1000_fc_type fc;
+    e1000_bus_speed bus_speed;
+    e1000_bus_width bus_width;
+    e1000_bus_type bus_type;
+    uint32_t io_base;
+    uint32_t phy_id;
+    uint32_t phy_revision;
+    uint32_t phy_addr;
+    uint32_t original_fc;
+    uint32_t txcw;
+    uint32_t autoneg_failed;
+    uint32_t max_frame_size;
+    uint32_t min_frame_size;
+    uint32_t mc_filter_type;
+    uint32_t num_mc_addrs;
+    uint32_t collision_delta;
+    uint32_t tx_packet_delta;
+    uint32_t ledctl_default;
+    uint32_t ledctl_mode1;
+    uint32_t ledctl_mode2;
+    uint16_t autoneg_advertised;
+    uint16_t pci_cmd_word;
+    uint16_t fc_high_water;
+    uint16_t fc_low_water;
+    uint16_t fc_pause_time;
+    uint16_t current_ifs_val;
+    uint16_t ifs_min_val;
+    uint16_t ifs_max_val;
+    uint16_t ifs_step_size;
+    uint16_t ifs_ratio;
+    uint16_t device_id;
+    uint16_t vendor_id;
+    uint16_t subsystem_id;
+    uint16_t subsystem_vendor_id;
+    uint8_t revision_id;
+    uint8_t autoneg;
+    uint8_t mdix;
+    uint8_t forced_speed_duplex;
+    uint8_t wait_autoneg_complete;
+    uint8_t dma_fairness;
+    uint8_t mac_addr[NODE_ADDRESS_SIZE];
+    uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
+    boolean_t disable_polarity_correction;
+    boolean_t get_link_status;
+    boolean_t tbi_compatibility_en;
+    boolean_t tbi_compatibility_on;
+    boolean_t fc_send_xon;
+    boolean_t report_tx_early;
+    boolean_t adaptive_ifs;
+    boolean_t ifs_params_forced;
+    boolean_t in_ifs_mode;
+};
+
+
+#define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
+#define E1000_EEPROM_LED_LOGIC 0x0020   /* Led Logic Word */
+
+/* Register Bit Masks */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
+#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
+#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
+#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
+#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
+
+/* Constants used to intrepret the masked PCI-X bus speed. */
+#define E1000_STATUS_PCIX_SPEED_66  0x00000000 /* PCI-X bus speed  50-66 MHz */
+#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed  66-100 MHz */
+#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */
+
+/* EEPROM/Flash Control */
+#define E1000_EECD_SK        0x00000001 /* EEPROM Clock */
+#define E1000_EECD_CS        0x00000002 /* EEPROM Chip Select */
+#define E1000_EECD_DI        0x00000004 /* EEPROM Data In */
+#define E1000_EECD_DO        0x00000008 /* EEPROM Data Out */
+#define E1000_EECD_FWE_MASK  0x00000030 
+#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
+#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_SIZE      0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
+#define E1000_EECD_REQ       0x00000040 /* EEPROM Access Request */
+#define E1000_EECD_GNT       0x00000080 /* EEPROM Access Grant */
+#define E1000_EECD_PRES      0x00000100 /* EEPROM Present */
+
+/* EEPROM Read */
+#define E1000_EERD_START      0x00000001 /* Start Read */
+#define E1000_EERD_DONE       0x00000010 /* Read Done */
+#define E1000_EERD_ADDR_SHIFT 8
+#define E1000_EERD_ADDR_MASK  0x0000FF00 /* Read Address */
+#define E1000_EERD_DATA_SHIFT 16
+#define E1000_EERD_DATA_MASK  0xFFFF0000 /* Read Data */
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */ 
+#define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
+#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
+#define E1000_CTRL_EXT_GPI2_EN   0x00000004 /* Maps SDP6 to GPI2 */
+#define E1000_CTRL_EXT_GPI3_EN   0x00000008 /* Maps SDP7 to GPI3 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable Pin 5 */
+#define E1000_CTRL_EXT_PHY_INT   E1000_CTRL_EXT_SDP5_DATA
+#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Defineable Pin 6 */
+#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
+#define E1000_CTRL_EXT_SDP4_DIR  0x00000100 /* Direction of SDP4 0=in 1=out */
+#define E1000_CTRL_EXT_SDP5_DIR  0x00000200 /* Direction of SDP5 0=in 1=out */
+#define E1000_CTRL_EXT_SDP6_DIR  0x00000400 /* Direction of SDP6 0=in 1=out */
+#define E1000_CTRL_EXT_SDP7_DIR  0x00000800 /* Direction of SDP7 0=in 1=out */
+#define E1000_CTRL_EXT_ASDCHK    0x00001000 /* Initiate an ASD sequence */
+#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_IPS       0x00004000 /* Invert Power State */
+#define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_TBI  0x00C00000
+#define E1000_CTRL_EXT_WR_WMARK_MASK  0x03000000
+#define E1000_CTRL_EXT_WR_WMARK_256   0x00000000
+#define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
+#define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
+#define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK  0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK  0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE  0x04000000
+#define E1000_MDIC_OP_READ   0x08000000
+#define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_INT_EN    0x20000000
+#define E1000_MDIC_ERROR     0x40000000
+
+/* LED Control */
+#define E1000_LEDCTL_LED0_MODE_MASK  0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT 0
+#define E1000_LEDCTL_LED0_IVRT       0x00000040
+#define E1000_LEDCTL_LED0_BLINK      0x00000080
+#define E1000_LEDCTL_LED1_MODE_MASK  0x00000F00
+#define E1000_LEDCTL_LED1_MODE_SHIFT 8
+#define E1000_LEDCTL_LED1_IVRT       0x00004000
+#define E1000_LEDCTL_LED1_BLINK      0x00008000
+#define E1000_LEDCTL_LED2_MODE_MASK  0x000F0000
+#define E1000_LEDCTL_LED2_MODE_SHIFT 16
+#define E1000_LEDCTL_LED2_IVRT       0x00400000
+#define E1000_LEDCTL_LED2_BLINK      0x00800000
+#define E1000_LEDCTL_LED3_MODE_MASK  0x0F000000
+#define E1000_LEDCTL_LED3_MODE_SHIFT 24
+#define E1000_LEDCTL_LED3_IVRT       0x40000000
+#define E1000_LEDCTL_LED3_BLINK      0x80000000
+
+#define E1000_LEDCTL_MODE_LINK_10_1000  0x0
+#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
+#define E1000_LEDCTL_MODE_LINK_UP       0x2
+#define E1000_LEDCTL_MODE_ACTIVITY      0x3
+#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
+#define E1000_LEDCTL_MODE_LINK_10       0x5
+#define E1000_LEDCTL_MODE_LINK_100      0x6
+#define E1000_LEDCTL_MODE_LINK_1000     0x7
+#define E1000_LEDCTL_MODE_PCIX_MODE     0x8
+#define E1000_LEDCTL_MODE_FULL_DUPLEX   0x9
+#define E1000_LEDCTL_MODE_COLLISION     0xA
+#define E1000_LEDCTL_MODE_BUS_SPEED     0xB
+#define E1000_LEDCTL_MODE_BUS_SIZE      0xC
+#define E1000_LEDCTL_MODE_PAUSED        0xD
+#define E1000_LEDCTL_MODE_LED_ON        0xE
+#define E1000_LEDCTL_MODE_LED_OFF       0xF
+
+/* Receive Address */
+#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW    0x00000001    /* Transmit desc written back */
+#define E1000_ICR_TXQE    0x00000002    /* Transmit Queue empty */
+#define E1000_ICR_LSC     0x00000004    /* Link Status Change */
+#define E1000_ICR_RXSEQ   0x00000008    /* rx sequence error */
+#define E1000_ICR_RXDMT0  0x00000010    /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO     0x00000040    /* rx overrun */
+#define E1000_ICR_RXT0    0x00000080    /* rx timer intr (ring 0) */
+#define E1000_ICR_MDAC    0x00000200    /* MDIO access complete */
+#define E1000_ICR_RXCFG   0x00000400    /* RX /c/ ordered set */
+#define E1000_ICR_GPI_EN0 0x00000800    /* GP Int 0 */
+#define E1000_ICR_GPI_EN1 0x00001000    /* GP Int 1 */
+#define E1000_ICR_GPI_EN2 0x00002000    /* GP Int 2 */
+#define E1000_ICR_GPI_EN3 0x00004000    /* GP Int 3 */
+#define E1000_ICR_TXD_LOW 0x00008000
+#define E1000_ICR_SRPD    0x00010000
+
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW    E1000_ICR_TXDW        /* Transmit desc written back */
+#define E1000_ICS_TXQE    E1000_ICR_TXQE        /* Transmit Queue empty */
+#define E1000_ICS_LSC     E1000_ICR_LSC         /* Link Status Change */
+#define E1000_ICS_RXSEQ   E1000_ICR_RXSEQ       /* rx sequence error */
+#define E1000_ICS_RXDMT0  E1000_ICR_RXDMT0      /* rx desc min. threshold */
+#define E1000_ICS_RXO     E1000_ICR_RXO         /* rx overrun */
+#define E1000_ICS_RXT0    E1000_ICR_RXT0        /* rx timer intr */
+#define E1000_ICS_MDAC    E1000_ICR_MDAC        /* MDIO access complete */
+#define E1000_ICS_RXCFG   E1000_ICR_RXCFG       /* RX /c/ ordered set */
+#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0     /* GP Int 0 */
+#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1     /* GP Int 1 */
+#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2     /* GP Int 2 */
+#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3     /* GP Int 3 */
+#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD    E1000_ICR_SRPD
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW    E1000_ICR_TXDW        /* Transmit desc written back */
+#define E1000_IMS_TXQE    E1000_ICR_TXQE        /* Transmit Queue empty */
+#define E1000_IMS_LSC     E1000_ICR_LSC         /* Link Status Change */
+#define E1000_IMS_RXSEQ   E1000_ICR_RXSEQ       /* rx sequence error */
+#define E1000_IMS_RXDMT0  E1000_ICR_RXDMT0      /* rx desc min. threshold */
+#define E1000_IMS_RXO     E1000_ICR_RXO         /* rx overrun */
+#define E1000_IMS_RXT0    E1000_ICR_RXT0        /* rx timer intr */
+#define E1000_IMS_MDAC    E1000_ICR_MDAC        /* MDIO access complete */
+#define E1000_IMS_RXCFG   E1000_ICR_RXCFG       /* RX /c/ ordered set */
+#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0     /* GP Int 0 */
+#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1     /* GP Int 1 */
+#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2     /* GP Int 2 */
+#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3     /* GP Int 3 */
+#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD    E1000_ICR_SRPD
+
+/* Interrupt Mask Clear */
+#define E1000_IMC_TXDW    E1000_ICR_TXDW        /* Transmit desc written back */
+#define E1000_IMC_TXQE    E1000_ICR_TXQE        /* Transmit Queue empty */
+#define E1000_IMC_LSC     E1000_ICR_LSC         /* Link Status Change */
+#define E1000_IMC_RXSEQ   E1000_ICR_RXSEQ       /* rx sequence error */
+#define E1000_IMC_RXDMT0  E1000_ICR_RXDMT0      /* rx desc min. threshold */
+#define E1000_IMC_RXO     E1000_ICR_RXO         /* rx overrun */
+#define E1000_IMC_RXT0    E1000_ICR_RXT0        /* rx timer intr */
+#define E1000_IMC_MDAC    E1000_ICR_MDAC        /* MDIO access complete */
+#define E1000_IMC_RXCFG   E1000_ICR_RXCFG       /* RX /c/ ordered set */
+#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0     /* GP Int 0 */
+#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1     /* GP Int 1 */
+#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2     /* GP Int 2 */
+#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3     /* GP Int 3 */
+#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_IMC_SRPD    E1000_ICR_SRPD
+
+/* Receive Control */
+#define E1000_RCTL_RST          0x00000001      /* Software reset */
+#define E1000_RCTL_EN           0x00000002      /* enable */
+#define E1000_RCTL_SBP          0x00000004      /* store bad packet */
+#define E1000_RCTL_UPE          0x00000008      /* unicast promiscuous enable */
+#define E1000_RCTL_MPE          0x00000010      /* multicast promiscuous enab */
+#define E1000_RCTL_LPE          0x00000020      /* long packet enable */
+#define E1000_RCTL_LBM_NO       0x00000000      /* no loopback mode */
+#define E1000_RCTL_LBM_MAC      0x00000040      /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP      0x00000080      /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR     0x000000C0      /* tcvr loopback mode */
+#define E1000_RCTL_RDMTS_HALF   0x00000000      /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_QUAT   0x00000100      /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_EIGTH  0x00000200      /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT     12              /* multicast offset shift */
+#define E1000_RCTL_MO_0         0x00000000      /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1         0x00001000      /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2         0x00002000      /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3         0x00003000      /* multicast offset 15:4 */
+#define E1000_RCTL_MDR          0x00004000      /* multicast desc ring 0 */
+#define E1000_RCTL_BAM          0x00008000      /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048      0x00000000      /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024      0x00010000      /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512       0x00020000      /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256       0x00030000      /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384     0x00010000      /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192      0x00020000      /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096      0x00030000      /* rx buffer size 4096 */
+#define E1000_RCTL_VFE          0x00040000      /* vlan filter enable */
+#define E1000_RCTL_CFIEN        0x00080000      /* canonical form enable */
+#define E1000_RCTL_CFI          0x00100000      /* canonical form indicator */
+#define E1000_RCTL_DPF          0x00400000      /* discard pause frames */
+#define E1000_RCTL_PMCF         0x00800000      /* pass MAC control frames */
+#define E1000_RCTL_BSEX         0x02000000      /* Buffer size extension */
+
+/* Receive Descriptor */
+#define E1000_RDT_DELAY 0x0000ffff      /* Delay timer (1=1024us) */
+#define E1000_RDT_FPDB  0x80000000      /* Flush descriptor block */
+#define E1000_RDLEN_LEN 0x0007ff80      /* descriptor length */
+#define E1000_RDH_RDH   0x0000ffff      /* receive descriptor head */
+#define E1000_RDT_RDT   0x0000ffff      /* receive descriptor tail */
+
+/* Flow Control */
+#define E1000_FCRTH_RTH  0x0000FFF8     /* Mask Bits[15:3] for RTH */
+#define E1000_FCRTH_XFCE 0x80000000     /* External Flow Control Enable */
+#define E1000_FCRTL_RTL  0x0000FFF8     /* Mask Bits[15:3] for RTL */
+#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
+
+/* Receive Descriptor Control */
+#define E1000_RXDCTL_PTHRESH 0x0000003F /* RXDCTL Prefetch Threshold */
+#define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */
+#define E1000_RXDCTL_WTHRESH 0x003F0000 /* RXDCTL Writeback Threshold */
+#define E1000_RXDCTL_GRAN    0x01000000 /* RXDCTL Granularity */
+
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x000000FF /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_HTHRESH 0x0000FF00 /* TXDCTL Host Threshold */
+#define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_GRAN    0x01000000 /* TXDCTL Granularity */
+#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
+#define E1000_TXCW_HD         0x00000040        /* TXCW half duplex */
+#define E1000_TXCW_PAUSE      0x00000080        /* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR    0x00000100        /* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180        /* TXCW pause request mask */
+#define E1000_TXCW_RF         0x00003000        /* TXCW remote fault */
+#define E1000_TXCW_NP         0x00008000        /* TXCW next page */
+#define E1000_TXCW_CW         0x0000ffff        /* TxConfigWord mask */
+#define E1000_TXCW_TXC        0x40000000        /* Transmit Config control */
+#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_CW    0x0000ffff     /* RxConfigWord mask */
+#define E1000_RXCW_NC    0x04000000     /* Receive config no carrier */
+#define E1000_RXCW_IV    0x08000000     /* Receive config invalid */
+#define E1000_RXCW_CC    0x10000000     /* Receive config change */
+#define E1000_RXCW_C     0x20000000     /* Receive config */
+#define E1000_RXCW_SYNCH 0x40000000     /* Receive config synch */
+#define E1000_RXCW_ANC   0x80000000     /* Auto-neg complete */
+
+/* Transmit Control */
+#define E1000_TCTL_RST    0x00000001    /* software reset */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
+#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_PCSS_MASK 0x000000FF   /* Packet Checksum Start */
+#define E1000_RXCSUM_IPOFL     0x00000100   /* IPv4 checksum offload */
+#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPV6OFL   0x00000400   /* IPv6 checksum offload */
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME       0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
+#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
+#define E1000_WUC_APMPME     0x00000008 /* Assert PME on APM Wakeup */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
+#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
+#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */
+#define E1000_WUFC_FLX_OFFSET 16       /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */
+
+/* Wake Up Status */
+#define E1000_WUS_LNKC 0x00000001 /* Link Status Changed */
+#define E1000_WUS_MAG  0x00000002 /* Magic Packet Received */
+#define E1000_WUS_EX   0x00000004 /* Directed Exact Received */
+#define E1000_WUS_MC   0x00000008 /* Directed Multicast Received */
+#define E1000_WUS_BC   0x00000010 /* Broadcast Received */
+#define E1000_WUS_ARP  0x00000020 /* ARP Request Packet Received */
+#define E1000_WUS_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Received */
+#define E1000_WUS_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Received */
+#define E1000_WUS_FLX0 0x00010000 /* Flexible Filter 0 Match */
+#define E1000_WUS_FLX1 0x00020000 /* Flexible Filter 1 Match */
+#define E1000_WUS_FLX2 0x00040000 /* Flexible Filter 2 Match */
+#define E1000_WUS_FLX3 0x00080000 /* Flexible Filter 3 Match */
+#define E1000_WUS_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
+#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
+#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
+#define E1000_MANC_NEIGHBOR_EN   0x00004000 /* Enable Neighbor Discovery 
+                                             * Filtering */
+#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
+#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
+
+/* Wake Up Packet Length */
+#define E1000_WUPL_LENGTH_MASK 0x0FFF   /* Only the lower 12 bits are valid */
+
+#define E1000_MDALIGN          4096
+
+/* EEPROM Commands */
+#define EEPROM_READ_OPCODE  0x6  /* EERPOM read opcode */
+#define EEPROM_WRITE_OPCODE 0x5  /* EERPOM write opcode */
+#define EEPROM_ERASE_OPCODE 0x7  /* EERPOM erase opcode */
+#define EEPROM_EWEN_OPCODE  0x13 /* EERPOM erase/write enable */
+#define EEPROM_EWDS_OPCODE  0x10 /* EERPOM erast/write disable */
+
+/* EEPROM Word Offsets */
+#define EEPROM_COMPAT              0x0003
+#define EEPROM_ID_LED_SETTINGS     0x0004
+#define EEPROM_INIT_CONTROL1_REG   0x000A
+#define EEPROM_INIT_CONTROL2_REG   0x000F
+#define EEPROM_FLASH_VERSION       0x0032
+#define EEPROM_CHECKSUM_REG        0x003F
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2 << 12) | \
+                              (ID_LED_OFF1_OFF2 << 8) | \
+                              (ID_LED_DEF1_DEF2 << 4) | \
+                              (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2     0x1
+#define ID_LED_DEF1_ON2      0x2
+#define ID_LED_DEF1_OFF2     0x3
+#define ID_LED_ON1_DEF2      0x4
+#define ID_LED_ON1_ON2       0x5
+#define ID_LED_ON1_OFF2      0x6
+#define ID_LED_OFF1_DEF2     0x7
+#define ID_LED_OFF1_ON2      0x8
+#define ID_LED_OFF1_OFF2     0x9
+
+/* Mask bits for fields in Word 0x03 of the EEPROM */
+#define EEPROM_COMPAT_SERVER 0x0400
+#define EEPROM_COMPAT_CLIENT 0x0200
+
+/* Mask bits for fields in Word 0x0a of the EEPROM */
+#define EEPROM_WORD0A_ILOS   0x0010
+#define EEPROM_WORD0A_SWDPIO 0x01E0
+#define EEPROM_WORD0A_LRST   0x0200
+#define EEPROM_WORD0A_FD     0x0400
+#define EEPROM_WORD0A_66MHZ  0x0800
+
+/* Mask bits for fields in Word 0x0f of the EEPROM */
+#define EEPROM_WORD0F_PAUSE_MASK 0x3000
+#define EEPROM_WORD0F_PAUSE      0x1000
+#define EEPROM_WORD0F_ASM_DIR    0x2000
+#define EEPROM_WORD0F_ANE        0x0800
+#define EEPROM_WORD0F_SWPDIO_EXT 0x00F0
+
+/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
+#define EEPROM_SUM 0xBABA
+
+/* EEPROM Map defines (WORD OFFSETS)*/
+#define EEPROM_NODE_ADDRESS_BYTE_0 0
+#define EEPROM_PBA_BYTE_1          8
+
+/* EEPROM Map Sizes (Byte Counts) */
+#define PBA_SIZE 4
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD       16
+#define E1000_CT_SHIFT                  4
+#define E1000_COLLISION_DISTANCE        64
+#define E1000_FDX_COLLISION_DISTANCE    E1000_COLLISION_DISTANCE
+#define E1000_HDX_COLLISION_DISTANCE    E1000_COLLISION_DISTANCE
+#define E1000_GB_HDX_COLLISION_DISTANCE 512
+#define E1000_COLD_SHIFT                12
+
+/* The number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE  8
+#define REQ_RX_DESCRIPTOR_MULTIPLE  8
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82542_TIPG_IPGT        10
+#define DEFAULT_82543_TIPG_IPGT_FIBER  9
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK  0x000003FF
+#define E1000_TIPG_IPGR1_MASK 0x000FFC00
+#define E1000_TIPG_IPGR2_MASK 0x3FF00000
+
+#define DEFAULT_82542_TIPG_IPGR1 2
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT  10
+
+#define DEFAULT_82542_TIPG_IPGR2 10
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define E1000_TIPG_IPGR2_SHIFT  20
+
+#define E1000_TXDMAC_DPP 0x00000001
+
+/* Adaptive IFS defines */
+#define TX_THRESHOLD_START     8
+#define TX_THRESHOLD_INCREMENT 10
+#define TX_THRESHOLD_DECREMENT 1
+#define TX_THRESHOLD_STOP      190
+#define TX_THRESHOLD_DISABLE   0
+#define TX_THRESHOLD_TIMER_MS  10000
+#define MIN_NUM_XMITS          1000
+#define IFS_MAX                80
+#define IFS_STEP               10
+#define IFS_MIN                40
+#define IFS_RATIO              4
+
+/* PBA constants */
+#define E1000_PBA_16K 0x0010    /* 16KB, default TX allocation */
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_40K 0x0028
+#define E1000_PBA_48K 0x0030    /* 48KB, default RX allocation */
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE         0x8808
+
+/* The historical defaults for the flow control values are given below. */
+#define FC_DEFAULT_HI_THRESH        (0x8000)    /* 32KB */
+#define FC_DEFAULT_LO_THRESH        (0x4000)    /* 16KB */
+#define FC_DEFAULT_TX_TIMER         (0x100)     /* ~130 us */
+
+/* PCIX Config space */
+#define PCIX_COMMAND_REGISTER    0xE6
+#define PCIX_STATUS_REGISTER_LO  0xE8
+#define PCIX_STATUS_REGISTER_HI  0xEA
+
+#define PCIX_COMMAND_MMRBC_MASK      0x000C
+#define PCIX_COMMAND_MMRBC_SHIFT     0x2
+#define PCIX_STATUS_HI_MMRBC_MASK    0x0060
+#define PCIX_STATUS_HI_MMRBC_SHIFT   0x5
+#define PCIX_STATUS_HI_MMRBC_4K      0x3
+#define PCIX_STATUS_HI_MMRBC_2K      0x2
+
+
+/* The number of bits that we need to shift right to move the "pause"
+ * bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field
+ * in the TXCW register 
+ */
+#define PAUSE_SHIFT 5
+
+/* The number of bits that we need to shift left to move the "SWDPIO"
+ * bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field
+ * in the CTRL register 
+ */
+#define SWDPIO_SHIFT 17
+
+/* The number of bits that we need to shift left to move the "SWDPIO_EXT"
+ * bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The
+ * Extended CTRL register.
+ * in the CTRL register 
+ */
+#define SWDPIO__EXT_SHIFT 4
+
+/* The number of bits that we need to shift left to move the "ILOS"
+ * bit from the EEPROM (bit 4) to the "ILOS" (bit 7) field
+ * in the CTRL register 
+ */
+#define ILOS_SHIFT  3
+
+
+#define RECEIVE_BUFFER_ALIGN_SIZE  (256)
+
+/* The number of milliseconds we wait for auto-negotiation to complete */
+#define LINK_UP_TIMEOUT             500
+
+#define E1000_TX_BUFFER_SIZE ((uint32_t)1514)
+
+/* The carrier extension symbol, as received by the NIC. */
+#define CARRIER_EXTENSION   0x0F
+
+/* TBI_ACCEPT macro definition:
+ *
+ * This macro requires:
+ *      adapter = a pointer to struct e1000_hw 
+ *      status = the 8 bit status field of the RX descriptor with EOP set
+ *      error = the 8 bit error field of the RX descriptor with EOP set
+ *      length = the sum of all the length fields of the RX descriptors that
+ *               make up the current frame
+ *      last_byte = the last byte of the frame DMAed by the hardware
+ *      max_frame_length = the maximum frame length we want to accept.
+ *      min_frame_length = the minimum frame length we want to accept.
+ *
+ * This macro is a conditional that should be used in the interrupt 
+ * handler's Rx processing routine when RxErrors have been detected.
+ *
+ * Typical use:
+ *  ...
+ *  if (TBI_ACCEPT) {
+ *      accept_frame = TRUE;
+ *      e1000_tbi_adjust_stats(adapter, MacAddress);
+ *      frame_length--;
+ *  } else {
+ *      accept_frame = FALSE;
+ *  }
+ *  ...
+ */
+
+#define TBI_ACCEPT(adapter, status, errors, length, last_byte) \
+    ((adapter)->tbi_compatibility_on && \
+     (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \
+     ((last_byte) == CARRIER_EXTENSION) && \
+     (((status) & E1000_RXD_STAT_VP) ? \
+          (((length) > ((adapter)->min_frame_size - VLAN_TAG_SIZE)) && \
+           ((length) <= ((adapter)->max_frame_size + 1))) : \
+          (((length) > (adapter)->min_frame_size) && \
+           ((length) <= ((adapter)->max_frame_size + VLAN_TAG_SIZE + 1)))))
+
+
+/* Structures, enums, and macros for the PHY */
+
+/* Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+#define E1000_CTRL_PHY_RESET_DIR  E1000_CTRL_SWDPIO0
+#define E1000_CTRL_PHY_RESET      E1000_CTRL_SWDPIN0
+#define E1000_CTRL_MDIO_DIR       E1000_CTRL_SWDPIO2
+#define E1000_CTRL_MDIO           E1000_CTRL_SWDPIN2
+#define E1000_CTRL_MDC_DIR        E1000_CTRL_SWDPIO3
+#define E1000_CTRL_MDC            E1000_CTRL_SWDPIN3
+#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
+#define E1000_CTRL_PHY_RESET4     E1000_CTRL_EXT_SDP4_DATA
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CTRL         0x00 /* Control Register */
+#define PHY_STATUS       0x01 /* Status Regiser */
+#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE        0x12  /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS        0x13  /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
+
+#define MAX_PHY_REG_ADDRESS 0x1F        /* 5 bit address bus (0-0x1F) */
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */
+#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
+#define MII_CR_ISOLATE          0x0400  /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN       0x0800  /* Power down */
+#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS     0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT     0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS      0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT      0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS   0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS     0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS     0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS       0x0800 /* 10T   Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS       0x1000 /* 10T   Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS      0x2000 /* 100X  Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS      0x4000 /* 100X  Full Duplex Capable */
+#define MII_SR_100T4_CAPS        0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_SELECTOR_FIELD 0x0001   /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS    0x0020   /* 10T   Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS    0x0040   /* 10T   Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS  0x0080   /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS  0x0100   /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS     0x0200   /* 100T4 Capable */
+#define NWAY_AR_PAUSE          0x0400   /* Pause operation desired */
+#define NWAY_AR_ASM_DIR        0x0800   /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT   0x2000   /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE      0x8000   /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS    0x0020 /* LP is 10T   Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS    0x0040 /* LP is 10T   Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS  0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS     0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT   0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE    0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE      0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS      0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT  0x0100 /* LP is 100TX Full Duplex Capable */
+
+/* Next Page TX Register */
+#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define NPTX_TOGGLE         0x0800 /* Toggles between exchanges
+                                    * of different NP
+                                    */
+#define NPTX_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg
+                                    * 0 = cannot comply with msg
+                                    */
+#define NPTX_MSG_PAGE       0x2000 /* formatted(1)/unformatted(0) pg */
+#define NPTX_NEXT_PAGE      0x8000 /* 1 = addition NP will follow 
+                                    * 0 = sending last NP
+                                    */
+
+/* Link Partner Next Page Register */
+#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define LP_RNPR_TOGGLE         0x0800 /* Toggles between exchanges
+                                       * of different NP
+                                       */
+#define LP_RNPR_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg 
+                                       * 0 = cannot comply with msg
+                                       */
+#define LP_RNPR_MSG_PAGE       0x2000  /* formatted(1)/unformatted(0) pg */
+#define LP_RNPR_ACKNOWLDGE     0x4000  /* 1 = ACK / 0 = NO ACK */
+#define LP_RNPR_NEXT_PAGE      0x8000  /* 1 = addition NP will follow
+                                        * 0 = sending last NP 
+                                        */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_ASYM_PAUSE      0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
+#define CR_1000T_REPEATER_DTE    0x0400 /* 1=Repeater/switch device port */
+                                        /* 0=DTE device */
+#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
+                                        /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE       0x1000 /* 1=Master/Slave manual config value */
+                                        /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1     0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2     0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3     0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4     0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_IDLE_ERROR_CNT   0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR   0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS       0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS       0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES    0x4000 /* 1=Local TX is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT  0x8000 /* Master/Slave config fault */
+#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12
+#define SR_1000T_LOCAL_RX_STATUS_SHIFT  13
+
+/* Extended Status Register */
+#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */
+#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */
+#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */
+#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */
+
+#define PHY_TX_POLARITY_MASK   0x0100 /* register 10h bit 8 (polarity bit) */
+#define PHY_TX_NORMAL_POLARITY 0      /* register 10h bit 8 (normal polarity) */
+
+#define AUTO_POLARITY_DISABLE  0x0010 /* register 11h bit 4 */
+                                      /* (0=enable, 1=disable) */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_JABBER_DISABLE    0x0001 /* 1=Jabber Function disabled */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+#define M88E1000_PSCR_SQE_TEST          0x0004 /* 1=SQE Test enabled */
+#define M88E1000_PSCR_CLK125_DISABLE    0x0010 /* 1=CLK125 low, 
+                                                * 0=CLK125 toggling
+                                                */
+#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000  /* MDI Crossover Mode bits 6:5 */
+                                               /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
+#define M88E1000_PSCR_AUTO_X_1000T     0x0040  /* 1000BASE-T: Auto crossover,
+                                                *  100BASE-TX/10BASE-T: 
+                                                *  MDI Mode
+                                                */
+#define M88E1000_PSCR_AUTO_X_MODE      0x0060  /* Auto crossover enabled 
+                                                * all speeds. 
+                                                */
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080 
+                                        /* 1=Enable Extended 10BASE-T distance
+                                         * (Lower 10BASE-T RX Threshold)
+                                         * 0=Normal 10BASE-T RX Threshold */
+#define M88E1000_PSCR_MII_5BIT_ENABLE      0x0100
+                                        /* 1=5-Bit interface in 100BASE-TX
+                                         * 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_SCRAMBLER_DISABLE    0x0200 /* 1=Scrambler disable */
+#define M88E1000_PSCR_FORCE_LINK_GOOD      0x0400 /* 1=Force link good */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Transmit */
+
+#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT    1
+#define M88E1000_PSCR_AUTO_X_MODE_SHIFT          5
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_JABBER             0x0001 /* 1=Jabber */
+#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
+#define M88E1000_PSSR_CABLE_LENGTH       0x0380 /* 0=<50M;1=50-80M;2=80-110M;
+                                            * 3=110-140M;4=>140M */
+#define M88E1000_PSSR_LINK               0x0400 /* 1=Link up, 0=Link down */
+#define M88E1000_PSSR_SPD_DPLX_RESOLVED  0x0800 /* 1=Speed & Duplex resolved */
+#define M88E1000_PSSR_PAGE_RCVD          0x1000 /* 1=Page received */
+#define M88E1000_PSSR_DPLX               0x2000 /* 1=Duplex 0=Half Duplex */
+#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_10MBS              0x0000 /* 00=10Mbs */
+#define M88E1000_PSSR_100MBS             0x4000 /* 01=100Mbs */
+#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_REV_POLARITY_SHIFT 1
+#define M88E1000_PSSR_MDIX_SHIFT         6
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
+#define M88E1000_EPSCR_DOWN_NO_IDLE   0x8000 /* 1=Lost lock detect enabled.
+                                              * Will assert lost lock and bring
+                                              * link down if idle not seen
+                                              * within 1ms in 1000BASE-T 
+                                              */
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000    
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X   0x0400
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X   0x0800
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X   0x0C00
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS   0x0000
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X    0x0200
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X    0x0300
+#define M88E1000_EPSCR_TX_CLK_2_5     0x0060 /* 2.5 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_0       0x0000 /* NO  TX_CLK */
+
+/* Bit definitions for valid PHY IDs. */
+#define M88E1000_E_PHY_ID  0x01410C50
+#define M88E1000_I_PHY_ID  0x01410C30
+#define M88E1011_I_PHY_ID  0x01410C20
+#define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
+#define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
+#define M88E1011_I_REV_4   0x04
+
+/* Miscellaneous PHY bit definitions. */
+#define PHY_PREAMBLE        0xFFFFFFFF
+#define PHY_SOF             0x01
+#define PHY_OP_READ         0x02
+#define PHY_OP_WRITE        0x01
+#define PHY_TURNAROUND      0x02
+#define PHY_PREAMBLE_SIZE   32
+#define MII_CR_SPEED_1000   0x0040
+#define MII_CR_SPEED_100    0x2000
+#define MII_CR_SPEED_10     0x0000
+#define E1000_PHY_ADDRESS   0x01
+#define PHY_AUTO_NEG_TIME   45  /* 4.5 Seconds */
+#define PHY_FORCE_TIME      20  /* 2.0 Seconds */
+#define PHY_REVISION_MASK   0xFFFFFFF0
+#define DEVICE_SPEED_MASK   0x00000300  /* Device Ctrl Reg Speed Mask */
+#define REG4_SPEED_MASK     0x01E0
+#define REG9_SPEED_MASK     0x0300
+#define ADVERTISE_10_HALF   0x0001
+#define ADVERTISE_10_FULL   0x0002
+#define ADVERTISE_100_HALF  0x0004
+#define ADVERTISE_100_FULL  0x0008
+#define ADVERTISE_1000_HALF 0x0010
+#define ADVERTISE_1000_FULL 0x0020
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F  /* Everything but 1000-Half */
+
+#endif /* _E1000_HW_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e1000/e1000_main.c linux-2.4.20/drivers/net/e1000/e1000_main.c
--- linux-2.4.19/drivers/net/e1000/e1000_main.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e1000/e1000_main.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,2287 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#define __E1000_MAIN__
+#include "e1000.h"
+
+/* Change Log
+ *
+ * 4.4.12       10/15/02
+ *   o Clean up: use members of pci_device rather than direct calls to
+ *     pci_read_config_word.
+ *   o Bug fix: changed default flow control settings.
+ *   o Clean up: ethtool file now has an inclusive list for adapters in the
+ *     Wake-On-LAN capabilities instead of an exclusive list.
+ *   o Bug fix: miscellaneous WoL bug fixes.
+ *   o Added software interrupt for clearing rx ring
+ *   o Bug fix: easier to undo "forcing" of 1000/fd using ethtool.
+ *   o Now setting netdev->mem_end in e1000_probe.
+ *   o Clean up: Moved tx_timeout from interrupt context to process context
+ *     using schedule_task.
+ *
+ * 4.3.15      8/9/02
+ *   o Converted from Dual BSD/GPL license to GPL license.
+ *   o Clean up: use pci_[clear|set]_mwi rather than direct calls to
+ *     pci_write_config_word.
+ *   o Bug fix: added read-behind-write calls to post writes before delays.
+ *   o Bug fix: removed mdelay busy-waits in interrupt context.
+ *   o Clean up: direct clear of descriptor bits rather than using memset.
+ *   o Bug fix: added wmb() for ia-64 between descritor writes and advancing
+ *     descriptor tail.
+ *   o Feature: added locking mechanism for asf functionality.
+ *   o Feature: exposed two Tx and one Rx interrupt delay knobs for finer
+ *     control over interurpt rate tuning.
+ *   o Misc ethtool bug fixes.
+ *
+ * 4.3.2       7/5/02
+ */
+ 
+char e1000_driver_name[] = "e1000";
+char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
+char e1000_driver_version[] = "4.4.12-k1";
+char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation.";
+
+/* e1000_pci_tbl - PCI Device ID Table
+ *
+ * Private driver_data field (last one) stores an index into e1000_strings
+ * Wildcard entries (PCI_ANY_ID) should come last
+ * Last entry must be all 0s
+ *
+ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
+ *   Class, Class Mask, String Index }
+ */
+static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
+	/* Intel(R) PRO/1000 Network Connection */
+	{0x8086, 0x1000, 0x8086, 0x1000, 0, 0, 0},
+	{0x8086, 0x1001, 0x8086, 0x1003, 0, 0, 0},
+	{0x8086, 0x1004, 0x8086, 0x1004, 0, 0, 0},
+	{0x8086, 0x1008, 0x8086, 0x1107, 0, 0, 0},
+	{0x8086, 0x1009, 0x8086, 0x1109, 0, 0, 0},
+	{0x8086, 0x100C, 0x8086, 0x1112, 0, 0, 0},
+	{0x8086, 0x100E, 0x8086, 0x001E, 0, 0, 0},
+	/* Compaq Gigabit Ethernet Server Adapter */
+	{0x8086, 0x1000, 0x0E11, PCI_ANY_ID, 0, 0, 1},
+	{0x8086, 0x1001, 0x0E11, PCI_ANY_ID, 0, 0, 1},
+	{0x8086, 0x1004, 0x0E11, PCI_ANY_ID, 0, 0, 1},
+	/* IBM Mobile, Desktop & Server Adapters */
+	{0x8086, 0x1000, 0x1014, PCI_ANY_ID, 0, 0, 2},
+	{0x8086, 0x1001, 0x1014, PCI_ANY_ID, 0, 0, 2},
+	{0x8086, 0x1004, 0x1014, PCI_ANY_ID, 0, 0, 2},
+	/* Generic */
+	{0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	/* required last entry */
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
+
+static char *e1000_strings[] = {
+	"Intel(R) PRO/1000 Network Connection",
+	"Compaq Gigabit Ethernet Server Adapter",
+	"IBM Mobile, Desktop & Server Adapters"
+};
+
+/* Local Function Prototypes */
+
+int e1000_up(struct e1000_adapter *adapter);
+void e1000_down(struct e1000_adapter *adapter);
+void e1000_reset(struct e1000_adapter *adapter);
+
+static int e1000_init_module(void);
+static void e1000_exit_module(void);
+static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void e1000_remove(struct pci_dev *pdev);
+static int e1000_sw_init(struct e1000_adapter *adapter);
+static int e1000_open(struct net_device *netdev);
+static int e1000_close(struct net_device *netdev);
+static int e1000_setup_tx_resources(struct e1000_adapter *adapter);
+static int e1000_setup_rx_resources(struct e1000_adapter *adapter);
+static void e1000_configure_tx(struct e1000_adapter *adapter);
+static void e1000_configure_rx(struct e1000_adapter *adapter);
+static void e1000_setup_rctl(struct e1000_adapter *adapter);
+static void e1000_clean_tx_ring(struct e1000_adapter *adapter);
+static void e1000_clean_rx_ring(struct e1000_adapter *adapter);
+static void e1000_free_tx_resources(struct e1000_adapter *adapter);
+static void e1000_free_rx_resources(struct e1000_adapter *adapter);
+static void e1000_set_multi(struct net_device *netdev);
+static void e1000_update_phy_info(unsigned long data);
+static void e1000_watchdog(unsigned long data);
+static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
+static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
+static int e1000_change_mtu(struct net_device *netdev, int new_mtu);
+static int e1000_set_mac(struct net_device *netdev, void *p);
+static void e1000_update_stats(struct e1000_adapter *adapter);
+static inline void e1000_irq_disable(struct e1000_adapter *adapter);
+static inline void e1000_irq_enable(struct e1000_adapter *adapter);
+static void e1000_intr(int irq, void *data, struct pt_regs *regs);
+static void e1000_clean_tx_irq(struct e1000_adapter *adapter);
+static void e1000_clean_rx_irq(struct e1000_adapter *adapter);
+static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter);
+static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
+static void e1000_enter_82542_rst(struct e1000_adapter *adapter);
+static void e1000_leave_82542_rst(struct e1000_adapter *adapter);
+static inline void e1000_rx_checksum(struct e1000_adapter *adapter,
+                                     struct e1000_rx_desc *rx_desc,
+                                     struct sk_buff *skb);
+static void e1000_tx_timeout(struct net_device *dev);
+static void e1000_tx_timeout_task(struct net_device *dev);
+
+static void e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp);
+static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
+static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
+
+static int e1000_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
+static int e1000_notify_netdev(struct notifier_block *, unsigned long event, void *ptr);
+static int e1000_suspend(struct pci_dev *pdev, uint32_t state);
+#ifdef CONFIG_PM
+static int e1000_resume(struct pci_dev *pdev);
+#endif
+
+struct notifier_block e1000_notifier_reboot = {
+	.notifier_call	= e1000_notify_reboot,
+	.next		= NULL,
+	.priority	= 0
+};
+
+struct notifier_block e1000_notifier_netdev = {
+	.notifier_call	= e1000_notify_netdev,
+	.next		= NULL,
+	.priority	= 0
+};
+
+/* Exported from other modules */
+
+extern void e1000_check_options(struct e1000_adapter *adapter);
+extern void e1000_proc_dev_setup(struct e1000_adapter *adapter);
+extern void e1000_proc_dev_free(struct e1000_adapter *adapter);
+extern int e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr);
+
+static struct pci_driver e1000_driver = {
+	.name     = e1000_driver_name,
+	.id_table = e1000_pci_tbl,
+	.probe    = e1000_probe,
+	.remove   = __devexit_p(e1000_remove),
+	/* Power Managment Hooks */
+#ifdef CONFIG_PM
+	.suspend  = e1000_suspend,
+	.resume   = e1000_resume
+#endif
+};
+
+MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
+MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver");
+MODULE_LICENSE("GPL");
+
+/**
+ * e1000_init_module - Driver Registration Routine
+ *
+ * e1000_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ **/
+
+static int __init
+e1000_init_module(void)
+{
+	int ret;
+	printk(KERN_INFO "%s - version %s\n",
+	       e1000_driver_string, e1000_driver_version);
+
+	printk(KERN_INFO "%s\n", e1000_copyright);
+
+	ret = pci_module_init(&e1000_driver);
+	if(ret >= 0) {
+		register_reboot_notifier(&e1000_notifier_reboot);
+		register_netdevice_notifier(&e1000_notifier_netdev);
+	}
+	return ret;
+}
+
+module_init(e1000_init_module);
+
+/**
+ * e1000_exit_module - Driver Exit Cleanup Routine
+ *
+ * e1000_exit_module is called just before the driver is removed
+ * from memory.
+ **/
+
+static void __exit
+e1000_exit_module(void)
+{
+	unregister_reboot_notifier(&e1000_notifier_reboot);
+	unregister_netdevice_notifier(&e1000_notifier_netdev);
+	pci_unregister_driver(&e1000_driver);
+}
+
+module_exit(e1000_exit_module);
+
+
+int
+e1000_up(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	if(request_irq(netdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM,
+	               netdev->name, netdev))
+		return -1;
+
+	/* hardware has been reset, we need to reload some things */
+
+	e1000_set_multi(netdev);
+
+	e1000_configure_tx(adapter);
+	e1000_setup_rctl(adapter);
+	e1000_configure_rx(adapter);
+	e1000_alloc_rx_buffers(adapter);
+
+	mod_timer(&adapter->watchdog_timer, jiffies);
+	e1000_irq_enable(adapter);
+
+	return 0;
+}
+
+void
+e1000_down(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	e1000_irq_disable(adapter);
+	free_irq(netdev->irq, netdev);
+	del_timer_sync(&adapter->watchdog_timer);
+	del_timer_sync(&adapter->phy_info_timer);
+	adapter->link_speed = 0;
+	adapter->link_duplex = 0;
+	netif_carrier_off(netdev);
+	netif_stop_queue(netdev);
+
+	e1000_reset(adapter);
+	e1000_clean_tx_ring(adapter);
+	e1000_clean_rx_ring(adapter);
+}
+
+void
+e1000_reset(struct e1000_adapter *adapter)
+{
+	/* Repartition Pba for greater than 9k mtu
+	 * To take effect CTRL.RST is required.
+	 */
+
+	if(adapter->rx_buffer_len > E1000_RXBUFFER_8192)
+		E1000_WRITE_REG(&adapter->hw, PBA, E1000_JUMBO_PBA);
+	else
+		E1000_WRITE_REG(&adapter->hw, PBA, E1000_DEFAULT_PBA);
+
+	adapter->hw.fc = adapter->hw.original_fc;
+	e1000_reset_hw(&adapter->hw);
+	if(adapter->hw.mac_type >= e1000_82544)
+		E1000_WRITE_REG(&adapter->hw, WUC, 0);
+	e1000_init_hw(&adapter->hw);
+	e1000_reset_adaptive(&adapter->hw);
+	e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
+}
+
+/**
+ * e1000_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in e1000_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * e1000_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+
+static int __devinit
+e1000_probe(struct pci_dev *pdev,
+            const struct pci_device_id *ent)
+{
+	struct net_device *netdev;
+	struct e1000_adapter *adapter;
+	static int cards_found = 0;
+	unsigned long mmio_start;
+	int mmio_len;
+	int pci_using_dac;
+	int i;
+
+	if((i = pci_enable_device(pdev)))
+		return i;
+
+	if(!(i = pci_set_dma_mask(pdev, PCI_DMA_64BIT))) {
+		pci_using_dac = 1;
+	} else {
+		if((i = pci_set_dma_mask(pdev, PCI_DMA_32BIT))) {
+			E1000_ERR("No usable DMA configuration, aborting\n");
+			return i;
+		}
+		pci_using_dac = 0;
+	}
+
+	if((i = pci_request_regions(pdev, e1000_driver_name)))
+		return i;
+
+	pci_set_master(pdev);
+
+	netdev = alloc_etherdev(sizeof(struct e1000_adapter));
+	if(!netdev)
+		goto err_alloc_etherdev;
+
+	SET_MODULE_OWNER(netdev);
+
+	pci_set_drvdata(pdev, netdev);
+	adapter = netdev->priv;
+	adapter->netdev = netdev;
+	adapter->pdev = pdev;
+	adapter->hw.back = adapter;
+
+	mmio_start = pci_resource_start(pdev, BAR_0);
+	mmio_len = pci_resource_len(pdev, BAR_0);
+
+	adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
+	if(!adapter->hw.hw_addr)
+		goto err_ioremap;
+
+	for(i = BAR_1; i <= BAR_5; i++) {
+		if(pci_resource_len(pdev, i) == 0)
+			continue;
+		if(pci_resource_flags(pdev, i) & IORESOURCE_IO) {
+			adapter->hw.io_base = pci_resource_start(pdev, i);
+			break;
+		}
+	}
+
+	netdev->open = &e1000_open;
+	netdev->stop = &e1000_close;
+	netdev->hard_start_xmit = &e1000_xmit_frame;
+	netdev->get_stats = &e1000_get_stats;
+	netdev->set_multicast_list = &e1000_set_multi;
+	netdev->set_mac_address = &e1000_set_mac;
+	netdev->change_mtu = &e1000_change_mtu;
+	netdev->do_ioctl = &e1000_ioctl;
+	netdev->tx_timeout = &e1000_tx_timeout;
+	netdev->watchdog_timeo = HZ;
+	netdev->vlan_rx_register = e1000_vlan_rx_register;
+	netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid;
+	netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid;
+
+	netdev->irq = pdev->irq;
+	netdev->mem_start = mmio_start;
+	netdev->mem_end = mmio_start + mmio_len;
+	netdev->base_addr = adapter->hw.io_base;
+
+	adapter->bd_number = cards_found;
+	adapter->id_string = e1000_strings[ent->driver_data];
+
+	/* setup the private structure */
+
+	if(e1000_sw_init(adapter))
+		goto err_sw_init;
+
+	if(adapter->hw.mac_type >= e1000_82543) {
+		netdev->features = NETIF_F_SG |
+			           NETIF_F_HW_CSUM |
+		       	           NETIF_F_HW_VLAN_TX |
+		                   NETIF_F_HW_VLAN_RX |
+				   NETIF_F_HW_VLAN_FILTER;
+	} else {
+		netdev->features = NETIF_F_SG;
+	}
+
+	if(pci_using_dac)
+		netdev->features |= NETIF_F_HIGHDMA;
+
+	/* make sure the EEPROM is good */
+
+	if(e1000_validate_eeprom_checksum(&adapter->hw) < 0) {
+		printk(KERN_ERR "The EEPROM Checksum Is Not Valid\n");
+		goto err_eeprom;
+	}
+
+	/* copy the MAC address out of the EEPROM */
+
+	e1000_read_mac_addr(&adapter->hw);
+	memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
+
+	if(!is_valid_ether_addr(netdev->dev_addr))
+		goto err_eeprom;
+
+	e1000_read_part_num(&adapter->hw, &(adapter->part_num));
+
+	e1000_get_bus_info(&adapter->hw);
+
+	if((adapter->hw.mac_type == e1000_82544) &&
+	   (adapter->hw.bus_type == e1000_bus_type_pcix))
+
+		adapter->max_data_per_txd = 4096;
+	else
+		adapter->max_data_per_txd = MAX_JUMBO_FRAME_SIZE;
+
+
+	init_timer(&adapter->watchdog_timer);
+	adapter->watchdog_timer.function = &e1000_watchdog;
+	adapter->watchdog_timer.data = (unsigned long) adapter;
+
+	init_timer(&adapter->phy_info_timer);
+	adapter->phy_info_timer.function = &e1000_update_phy_info;
+	adapter->phy_info_timer.data = (unsigned long) adapter;
+
+	INIT_TQUEUE(&adapter->tx_timeout_task, 
+		(void (*)(void *))e1000_tx_timeout_task, netdev);
+
+	register_netdev(netdev);
+	memcpy(adapter->ifname, netdev->name, IFNAMSIZ);
+	adapter->ifname[IFNAMSIZ-1] = 0;
+
+	/* we're going to reset, so assume we have no link for now */
+
+	netif_carrier_off(netdev);
+	netif_stop_queue(netdev);
+
+	printk(KERN_INFO "%s: %s\n", netdev->name, adapter->id_string);
+	e1000_check_options(adapter);
+	e1000_proc_dev_setup(adapter);
+
+	/* Initial Wake on LAN setting
+	 * If APM wake is enabled in the EEPROM,
+	 * enable the ACPI Magic Packet filter
+	 */
+
+	if((adapter->hw.mac_type >= e1000_82544) &&
+	   (E1000_READ_REG(&adapter->hw, WUC) & E1000_WUC_APME))
+		adapter->wol |= E1000_WUFC_MAG;
+
+	/* reset the hardware with the new settings */
+
+	e1000_reset(adapter);
+
+	cards_found++;
+	return 0;
+
+err_sw_init:
+err_eeprom:
+	iounmap(adapter->hw.hw_addr);
+err_ioremap:
+	pci_release_regions(pdev);
+	kfree(netdev);
+err_alloc_etherdev:
+	return -ENOMEM;
+}
+
+/**
+ * e1000_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * e1000_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+
+static void __devexit
+e1000_remove(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct e1000_adapter *adapter = netdev->priv;
+	uint32_t manc;
+
+	if(adapter->hw.mac_type >= e1000_82540) {
+		manc = E1000_READ_REG(&adapter->hw, MANC);
+		if(manc & E1000_MANC_SMBUS_EN) {
+			manc |= E1000_MANC_ARP_EN;
+			E1000_WRITE_REG(&adapter->hw, MANC, manc);
+		}
+	}
+
+	unregister_netdev(netdev);
+
+	e1000_phy_hw_reset(&adapter->hw);
+
+	e1000_proc_dev_free(adapter);
+
+	iounmap(adapter->hw.hw_addr);
+	pci_release_regions(pdev);
+
+	kfree(netdev);
+}
+
+/**
+ * e1000_sw_init - Initialize general software structures (struct e1000_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * e1000_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+
+static int __devinit
+e1000_sw_init(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+
+	/* PCI config space info */
+
+	hw->vendor_id = pdev->vendor;
+	hw->device_id = pdev->device;
+	hw->subsystem_vendor_id = pdev->subsystem_vendor;
+	hw->subsystem_id = pdev->subsystem_device;
+
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
+	pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
+
+	adapter->rx_buffer_len = E1000_RXBUFFER_2048;
+	hw->max_frame_size = netdev->mtu +
+	                         ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+	hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
+
+	/* identify the MAC */
+
+	if (e1000_set_mac_type(hw)) {
+		E1000_ERR("Unknown MAC Type\n");
+		return -1;
+	}
+
+	/* flow control settings */
+
+	hw->fc_high_water = E1000_FC_HIGH_THRESH;
+	hw->fc_low_water = E1000_FC_LOW_THRESH;
+	hw->fc_pause_time = E1000_FC_PAUSE_TIME;
+	hw->fc_send_xon = 1;
+
+	/* Media type - copper or fiber */
+
+	if(hw->mac_type >= e1000_82543) {
+		uint32_t status = E1000_READ_REG(hw, STATUS);
+
+		if(status & E1000_STATUS_TBIMODE)
+			hw->media_type = e1000_media_type_fiber;
+		else
+			hw->media_type = e1000_media_type_copper;
+	} else {
+		hw->media_type = e1000_media_type_fiber;
+	}
+
+	if(hw->mac_type < e1000_82543)
+		hw->report_tx_early = 0;
+	else
+		hw->report_tx_early = 1;
+
+	hw->wait_autoneg_complete = FALSE;
+	hw->tbi_compatibility_en = TRUE;
+	hw->adaptive_ifs = TRUE;
+
+	/* Copper options */
+	
+	if(hw->media_type == e1000_media_type_copper) {
+		hw->mdix = AUTO_ALL_MODES;
+		hw->disable_polarity_correction = FALSE;
+	}
+
+	atomic_set(&adapter->irq_sem, 1);
+	spin_lock_init(&adapter->stats_lock);
+
+	return 0;
+}
+
+/**
+ * e1000_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+
+static int
+e1000_open(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+
+	/* allocate transmit descriptors */
+
+	if(e1000_setup_tx_resources(adapter))
+		goto err_setup_tx;
+
+	/* allocate receive descriptors */
+
+	if(e1000_setup_rx_resources(adapter))
+		goto err_setup_rx;
+
+	if(e1000_up(adapter))
+		goto err_up;
+
+	return 0;
+
+err_up:
+	e1000_free_rx_resources(adapter);
+err_setup_rx:
+	e1000_free_tx_resources(adapter);
+err_setup_tx:
+	e1000_reset(adapter);
+
+	return -EBUSY;
+}
+
+/**
+ * e1000_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+
+static int
+e1000_close(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+
+	e1000_down(adapter);
+
+	e1000_free_tx_resources(adapter);
+	e1000_free_rx_resources(adapter);
+
+	return 0;
+}
+
+/**
+ * e1000_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ **/
+
+static int
+e1000_setup_tx_resources(struct e1000_adapter *adapter)
+{
+	struct e1000_desc_ring *txdr = &adapter->tx_ring;
+	struct pci_dev *pdev = adapter->pdev;
+	int size;
+
+	size = sizeof(struct e1000_buffer) * txdr->count;
+	txdr->buffer_info = kmalloc(size, GFP_KERNEL);
+	if(!txdr->buffer_info) {
+		return -ENOMEM;
+	}
+	memset(txdr->buffer_info, 0, size);
+
+	/* round up to nearest 4K */
+
+	txdr->size = txdr->count * sizeof(struct e1000_tx_desc);
+	E1000_ROUNDUP(txdr->size, 4096);
+
+	txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
+	if(!txdr->desc) {
+		kfree(txdr->buffer_info);
+		return -ENOMEM;
+	}
+	memset(txdr->desc, 0, txdr->size);
+
+	txdr->next_to_use = 0;
+	txdr->next_to_clean = 0;
+
+	return 0;
+}
+
+/**
+ * e1000_configure_tx - Configure 8254x Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+
+static void
+e1000_configure_tx(struct e1000_adapter *adapter)
+{
+	uint64_t tdba = adapter->tx_ring.dma;
+	uint32_t tdlen = adapter->tx_ring.count * sizeof(struct e1000_tx_desc);
+	uint32_t tctl, tipg;
+
+	E1000_WRITE_REG(&adapter->hw, TDBAL, (tdba & 0x00000000ffffffffULL));
+	E1000_WRITE_REG(&adapter->hw, TDBAH, (tdba >> 32));
+
+	E1000_WRITE_REG(&adapter->hw, TDLEN, tdlen);
+
+	/* Setup the HW Tx Head and Tail descriptor pointers */
+
+	E1000_WRITE_REG(&adapter->hw, TDH, 0);
+	E1000_WRITE_REG(&adapter->hw, TDT, 0);
+
+	/* Set the default values for the Tx Inter Packet Gap timer */
+
+	switch (adapter->hw.mac_type) {
+	case e1000_82542_rev2_0:
+	case e1000_82542_rev2_1:
+		tipg = DEFAULT_82542_TIPG_IPGT;
+		tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
+		tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
+		break;
+	default:
+		if(adapter->hw.media_type == e1000_media_type_fiber)
+			tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
+		else
+			tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
+		tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
+		tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
+	}
+	E1000_WRITE_REG(&adapter->hw, TIPG, tipg);
+
+	/* Set the Tx Interrupt Delay register */
+
+	E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay);
+	if(adapter->hw.mac_type >= e1000_82540)
+		E1000_WRITE_REG(&adapter->hw, TADV, adapter->tx_abs_int_delay);
+
+	/* Program the Transmit Control Register */
+
+	tctl = E1000_READ_REG(&adapter->hw, TCTL);
+
+	tctl &= ~E1000_TCTL_CT;
+	tctl |= E1000_TCTL_EN | E1000_TCTL_PSP |
+	       (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+
+	E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
+
+	e1000_config_collision_dist(&adapter->hw);
+
+	/* Setup Transmit Descriptor Settings for this adapter */
+	adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_IDE;
+
+	if(adapter->hw.report_tx_early == 1)
+		adapter->txd_cmd |= E1000_TXD_CMD_RS;
+	else
+		adapter->txd_cmd |= E1000_TXD_CMD_RPS;
+}
+
+/**
+ * e1000_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @adapter: board private structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+
+static int
+e1000_setup_rx_resources(struct e1000_adapter *adapter)
+{
+	struct e1000_desc_ring *rxdr = &adapter->rx_ring;
+	struct pci_dev *pdev = adapter->pdev;
+	int size;
+
+	size = sizeof(struct e1000_buffer) * rxdr->count;
+	rxdr->buffer_info = kmalloc(size, GFP_KERNEL);
+	if(!rxdr->buffer_info) {
+		return -ENOMEM;
+	}
+	memset(rxdr->buffer_info, 0, size);
+
+	/* Round up to nearest 4K */
+
+	rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc);
+	E1000_ROUNDUP(rxdr->size, 4096);
+
+	rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
+
+	if(!rxdr->desc) {
+		kfree(rxdr->buffer_info);
+		return -ENOMEM;
+	}
+	memset(rxdr->desc, 0, rxdr->size);
+
+	rxdr->next_to_clean = 0;
+	rxdr->next_to_use = 0;
+
+	return 0;
+}
+
+/**
+ * e1000_setup_rctl - configure the receive control register
+ * @adapter: Board private structure
+ **/
+
+static void
+e1000_setup_rctl(struct e1000_adapter *adapter)
+{
+	uint32_t rctl;
+
+	rctl = E1000_READ_REG(&adapter->hw, RCTL);
+
+	rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
+
+	rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
+	        E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+	        (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
+
+	if(adapter->hw.tbi_compatibility_on == 1)
+		rctl |= E1000_RCTL_SBP;
+	else
+		rctl &= ~E1000_RCTL_SBP;
+
+	rctl &= ~(E1000_RCTL_SZ_4096);
+	switch (adapter->rx_buffer_len) {
+	case E1000_RXBUFFER_2048:
+	default:
+		rctl |= E1000_RCTL_SZ_2048;
+		rctl &= ~(E1000_RCTL_BSEX | E1000_RCTL_LPE);
+		break;
+	case E1000_RXBUFFER_4096:
+		rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
+		break;
+	case E1000_RXBUFFER_8192:
+		rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
+		break;
+	case E1000_RXBUFFER_16384:
+		rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
+		break;
+	}
+
+	E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+}
+
+/**
+ * e1000_configure_rx - Configure 8254x Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+
+static void
+e1000_configure_rx(struct e1000_adapter *adapter)
+{
+	uint64_t rdba = adapter->rx_ring.dma;
+	uint32_t rdlen = adapter->rx_ring.count * sizeof(struct e1000_rx_desc);
+	uint32_t rctl;
+	uint32_t rxcsum;
+
+	/* make sure receives are disabled while setting up the descriptors */
+
+	rctl = E1000_READ_REG(&adapter->hw, RCTL);
+	E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN);
+
+	/* set the Receive Delay Timer Register */
+
+	E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay);
+
+	if(adapter->hw.mac_type >= e1000_82540) {
+		E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay);
+
+		/* Set the interrupt throttling rate.  Value is calculated
+		 * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
+#define MAX_INTS_PER_SEC        8000
+#define DEFAULT_ITR             1000000000/(MAX_INTS_PER_SEC * 256)
+		E1000_WRITE_REG(&adapter->hw, ITR, DEFAULT_ITR);
+	}
+
+	/* Setup the Base and Length of the Rx Descriptor Ring */
+
+	E1000_WRITE_REG(&adapter->hw, RDBAL, (rdba & 0x00000000ffffffffULL));
+	E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32));
+
+	E1000_WRITE_REG(&adapter->hw, RDLEN, rdlen);
+
+	/* Setup the HW Rx Head and Tail Descriptor Pointers */
+	E1000_WRITE_REG(&adapter->hw, RDH, 0);
+	E1000_WRITE_REG(&adapter->hw, RDT, 0);
+
+	/* Enable 82543 Receive Checksum Offload for TCP and UDP */
+	if((adapter->hw.mac_type >= e1000_82543) &&
+	   (adapter->rx_csum == TRUE)) {
+		rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM);
+		rxcsum |= E1000_RXCSUM_TUOFL;
+		E1000_WRITE_REG(&adapter->hw, RXCSUM, rxcsum);
+	}
+
+	/* Enable Receives */
+
+	E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+}
+
+/**
+ * e1000_free_tx_resources - Free Tx Resources
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+
+static void
+e1000_free_tx_resources(struct e1000_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+
+	e1000_clean_tx_ring(adapter);
+
+	kfree(adapter->tx_ring.buffer_info);
+	adapter->tx_ring.buffer_info = NULL;
+
+	pci_free_consistent(pdev, adapter->tx_ring.size,
+	                    adapter->tx_ring.desc, adapter->tx_ring.dma);
+
+	adapter->tx_ring.desc = NULL;
+}
+
+/**
+ * e1000_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ **/
+
+static void
+e1000_clean_tx_ring(struct e1000_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	unsigned long size;
+	int i;
+
+	/* Free all the Tx ring sk_buffs */
+
+	for(i = 0; i < adapter->tx_ring.count; i++) {
+		if(adapter->tx_ring.buffer_info[i].skb) {
+
+			pci_unmap_page(pdev,
+			               adapter->tx_ring.buffer_info[i].dma,
+			               adapter->tx_ring.buffer_info[i].length,
+			               PCI_DMA_TODEVICE);
+
+			dev_kfree_skb(adapter->tx_ring.buffer_info[i].skb);
+
+			adapter->tx_ring.buffer_info[i].skb = NULL;
+		}
+	}
+
+	size = sizeof(struct e1000_buffer) * adapter->tx_ring.count;
+	memset(adapter->tx_ring.buffer_info, 0, size);
+
+	/* Zero out the descriptor ring */
+
+	memset(adapter->tx_ring.desc, 0, adapter->tx_ring.size);
+
+	adapter->tx_ring.next_to_use = 0;
+	adapter->tx_ring.next_to_clean = 0;
+
+	E1000_WRITE_REG(&adapter->hw, TDH, 0);
+	E1000_WRITE_REG(&adapter->hw, TDT, 0);
+}
+
+/**
+ * e1000_free_rx_resources - Free Rx Resources
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+
+static void
+e1000_free_rx_resources(struct e1000_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+
+	e1000_clean_rx_ring(adapter);
+
+	kfree(adapter->rx_ring.buffer_info);
+	adapter->rx_ring.buffer_info = NULL;
+
+	pci_free_consistent(pdev, adapter->rx_ring.size,
+	                    adapter->rx_ring.desc, adapter->rx_ring.dma);
+
+	adapter->rx_ring.desc = NULL;
+}
+
+/**
+ * e1000_clean_rx_ring - Free Rx Buffers
+ * @adapter: board private structure
+ **/
+
+static void
+e1000_clean_rx_ring(struct e1000_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	unsigned long size;
+	int i;
+
+	/* Free all the Rx ring sk_buffs */
+
+	for(i = 0; i < adapter->rx_ring.count; i++) {
+		if(adapter->rx_ring.buffer_info[i].skb) {
+
+			pci_unmap_single(pdev,
+			                 adapter->rx_ring.buffer_info[i].dma,
+			                 adapter->rx_ring.buffer_info[i].length,
+			                 PCI_DMA_FROMDEVICE);
+
+			dev_kfree_skb(adapter->rx_ring.buffer_info[i].skb);
+
+			adapter->rx_ring.buffer_info[i].skb = NULL;
+		}
+	}
+
+	size = sizeof(struct e1000_buffer) * adapter->rx_ring.count;
+	memset(adapter->rx_ring.buffer_info, 0, size);
+
+	/* Zero out the descriptor ring */
+
+	memset(adapter->rx_ring.desc, 0, adapter->rx_ring.size);
+
+	adapter->rx_ring.next_to_clean = 0;
+	adapter->rx_ring.next_to_use = 0;
+
+	E1000_WRITE_REG(&adapter->hw, RDH, 0);
+	E1000_WRITE_REG(&adapter->hw, RDT, 0);
+}
+
+/* The 82542 2.0 (revision 2) needs to have the receive unit in reset
+ * and memory write and invalidate disabled for certain operations
+ */
+static void
+e1000_enter_82542_rst(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	uint32_t rctl;
+
+	e1000_pci_clear_mwi(&adapter->hw);
+
+	rctl = E1000_READ_REG(&adapter->hw, RCTL);
+	rctl |= E1000_RCTL_RST;
+	E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+	E1000_WRITE_FLUSH(&adapter->hw);
+	mdelay(5);
+
+	if(netif_running(netdev))
+		e1000_clean_rx_ring(adapter);
+}
+
+static void
+e1000_leave_82542_rst(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	uint32_t rctl;
+
+	rctl = E1000_READ_REG(&adapter->hw, RCTL);
+	rctl &= ~E1000_RCTL_RST;
+	E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+	E1000_WRITE_FLUSH(&adapter->hw);
+	mdelay(5);
+
+	if(adapter->hw.pci_cmd_word & PCI_COMMAND_INVALIDATE)
+		e1000_pci_set_mwi(&adapter->hw);
+
+	if(netif_running(netdev)) {
+		e1000_configure_rx(adapter);
+		e1000_alloc_rx_buffers(adapter);
+	}
+}
+
+/**
+ * e1000_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+
+static int
+e1000_set_mac(struct net_device *netdev, void *p)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+	struct sockaddr *addr = p;
+
+	/* 82542 2.0 needs to be in reset to write receive address registers */
+
+	if(adapter->hw.mac_type == e1000_82542_rev2_0)
+		e1000_enter_82542_rst(adapter);
+
+	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+	memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
+
+	e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0);
+
+	if(adapter->hw.mac_type == e1000_82542_rev2_0)
+		e1000_leave_82542_rst(adapter);
+
+	return 0;
+}
+
+/**
+ * e1000_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated.  This routine is
+ * resposible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ **/
+
+static void
+e1000_set_multi(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_hw *hw = &adapter->hw;
+	struct dev_mc_list *mc_ptr;
+	uint32_t rctl;
+	uint32_t hash_value;
+	int i;
+
+	/* Check for Promiscuous and All Multicast modes */
+
+	rctl = E1000_READ_REG(hw, RCTL);
+
+	if(netdev->flags & IFF_PROMISC) {
+		rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
+	} else if(netdev->flags & IFF_ALLMULTI) {
+		rctl |= E1000_RCTL_MPE;
+		rctl &= ~E1000_RCTL_UPE;
+	} else {
+		rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
+	}
+
+	E1000_WRITE_REG(hw, RCTL, rctl);
+
+	/* 82542 2.0 needs to be in reset to write receive address registers */
+
+	if(hw->mac_type == e1000_82542_rev2_0)
+		e1000_enter_82542_rst(adapter);
+
+	/* load the first 15 multicast address into the exact filters 1-15
+	 * RAR 0 is used for the station MAC adddress
+	 * if there are not 15 addresses, go ahead and clear the filters
+	 */
+	mc_ptr = netdev->mc_list;
+
+	for(i = 1; i < E1000_RAR_ENTRIES; i++) {
+		if(mc_ptr) {
+			e1000_rar_set(hw, mc_ptr->dmi_addr, i);
+			mc_ptr = mc_ptr->next;
+		} else {
+			E1000_WRITE_REG_ARRAY(hw, RA, i << 1, 0);
+			E1000_WRITE_REG_ARRAY(hw, RA, (i << 1) + 1, 0);
+		}
+	}
+
+	/* clear the old settings from the multicast hash table */
+
+	for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++)
+		E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+
+	/* load any remaining addresses into the hash table */
+
+	for(; mc_ptr; mc_ptr = mc_ptr->next) {
+		hash_value = e1000_hash_mc_addr(hw, mc_ptr->dmi_addr);
+		e1000_mta_set(hw, hash_value);
+	}
+
+	if(hw->mac_type == e1000_82542_rev2_0)
+		e1000_leave_82542_rst(adapter);
+}
+
+
+/* need to wait a few seconds after link up to get diagnostic information from the phy */
+
+static void
+e1000_update_phy_info(unsigned long data)
+{
+	struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+	e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
+}
+
+/**
+ * e1000_watchdog - Timer Call-back
+ * @data: pointer to netdev cast into an unsigned long
+ **/
+
+static void
+e1000_watchdog(unsigned long data)
+{
+	struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+	struct net_device *netdev = adapter->netdev;
+	struct e1000_desc_ring *txdr = &adapter->tx_ring;
+	int i;
+
+	e1000_check_for_link(&adapter->hw);
+
+	if(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
+		if(!netif_carrier_ok(netdev)) {
+			e1000_get_speed_and_duplex(&adapter->hw,
+			                           &adapter->link_speed,
+			                           &adapter->link_duplex);
+
+			printk(KERN_INFO
+			       "e1000: %s NIC Link is Up %d Mbps %s\n",
+			       netdev->name, adapter->link_speed,
+			       adapter->link_duplex == FULL_DUPLEX ?
+			       "Full Duplex" : "Half Duplex");
+
+			netif_carrier_on(netdev);
+			netif_wake_queue(netdev);
+			mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
+		}
+	} else {
+		if(netif_carrier_ok(netdev)) {
+			adapter->link_speed = 0;
+			adapter->link_duplex = 0;
+			printk(KERN_INFO
+			       "e1000: %s NIC Link is Down\n",
+			       netdev->name);
+			netif_carrier_off(netdev);
+			netif_stop_queue(netdev);
+			mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
+		}
+	}
+
+	e1000_update_stats(adapter);
+	e1000_update_adaptive(&adapter->hw);
+
+
+	/* Cause software interrupt to ensure rx ring is cleaned */
+	E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_RXDMT0);
+
+	/* Early detection of hung controller */
+	i = txdr->next_to_clean;
+	if(txdr->buffer_info[i].dma &&
+	   time_after(jiffies, txdr->buffer_info[i].time_stamp + HZ) &&
+	   !(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF))
+		netif_stop_queue(netdev);
+
+	/* Reset the timer */
+	mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+}
+
+#define E1000_TX_FLAGS_CSUM		0x00000001
+#define E1000_TX_FLAGS_VLAN		0x00000002
+#define E1000_TX_FLAGS_VLAN_MASK	0xffff0000
+#define E1000_TX_FLAGS_VLAN_SHIFT	16
+
+static inline boolean_t
+e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
+{
+	struct e1000_context_desc *context_desc;
+	int i;
+	uint8_t css, cso;
+
+	if(skb->ip_summed == CHECKSUM_HW) {
+		css = skb->h.raw - skb->data;
+		cso = (skb->h.raw + skb->csum) - skb->data;
+
+		i = adapter->tx_ring.next_to_use;
+		context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
+
+		context_desc->upper_setup.tcp_fields.tucss = css;
+		context_desc->upper_setup.tcp_fields.tucso = cso;
+		context_desc->upper_setup.tcp_fields.tucse = 0;
+		context_desc->tcp_seg_setup.data = 0;
+		context_desc->cmd_and_length =
+			cpu_to_le32(adapter->txd_cmd | E1000_TXD_CMD_DEXT);
+
+		i = (i + 1) % adapter->tx_ring.count;
+		adapter->tx_ring.next_to_use = i;
+
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static inline int
+e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
+{
+	struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
+	int len, offset, size, count, i;
+
+	int f;
+	len = skb->len - skb->data_len;
+
+	i = (tx_ring->next_to_use + tx_ring->count - 1) % tx_ring->count;
+	count = 0;
+
+	offset = 0;
+
+	while(len) {
+		i = (i + 1) % tx_ring->count;
+		size = min(len, adapter->max_data_per_txd);
+		tx_ring->buffer_info[i].length = size;
+		tx_ring->buffer_info[i].dma =
+			pci_map_single(adapter->pdev,
+				skb->data + offset,
+				size,
+				PCI_DMA_TODEVICE);
+		tx_ring->buffer_info[i].time_stamp = jiffies;
+
+		len -= size;
+		offset += size;
+		count++;
+	}
+
+	for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
+		struct skb_frag_struct *frag;
+
+		frag = &skb_shinfo(skb)->frags[f];
+		len = frag->size;
+		offset = 0;
+
+		while(len) {
+			i = (i + 1) % tx_ring->count;
+			size = min(len, adapter->max_data_per_txd);
+			tx_ring->buffer_info[i].length = size;
+			tx_ring->buffer_info[i].dma =
+				pci_map_page(adapter->pdev,
+					frag->page,
+					frag->page_offset + offset,
+					size,
+					PCI_DMA_TODEVICE);
+
+			len -= size;
+			offset += size;
+			count++;
+		}
+	}
+	tx_ring->buffer_info[i].skb = skb;
+
+	return count;
+}
+
+static inline void
+e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
+{
+	struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
+	struct e1000_tx_desc *tx_desc = NULL;
+	uint32_t txd_upper, txd_lower;
+	int i;
+
+	txd_upper = 0;
+	txd_lower = adapter->txd_cmd;
+
+	if(tx_flags & E1000_TX_FLAGS_CSUM) {
+		txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
+		txd_upper |= E1000_TXD_POPTS_TXSM << 8;
+	}
+
+	if(tx_flags & E1000_TX_FLAGS_VLAN) {
+		txd_lower |= E1000_TXD_CMD_VLE;
+		txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK);
+	}
+
+	i = tx_ring->next_to_use;
+
+	while(count--) {
+		tx_desc = E1000_TX_DESC(*tx_ring, i);
+		tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma);
+		tx_desc->lower.data =
+			cpu_to_le32(txd_lower | tx_ring->buffer_info[i].length);
+		tx_desc->upper.data = cpu_to_le32(txd_upper);
+		i = (i + 1) % tx_ring->count;
+	}
+
+	tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP);
+
+	/* Force memory writes to complete before letting h/w
+	 * know there are new descriptors to fetch.  (Only
+	 * applicable for weak-ordered memory model archs,
+	 * such as IA-64). */
+	wmb();
+
+	tx_ring->next_to_use = i;
+	E1000_WRITE_REG(&adapter->hw, TDT, i);
+}
+
+#define TXD_USE_COUNT(S, X) (((S) / (X)) + (((S) % (X)) ? 1 : 0))
+
+static int
+e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+	int tx_flags = 0, count;
+
+	int f;
+
+	count = TXD_USE_COUNT(skb->len - skb->data_len,
+	                      adapter->max_data_per_txd);
+	for(f = 0; f < skb_shinfo(skb)->nr_frags; f++)
+		count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size,
+		                       adapter->max_data_per_txd);
+
+	if(skb->ip_summed == CHECKSUM_HW)
+		count++;
+
+	if(E1000_DESC_UNUSED(&adapter->tx_ring) < count) {
+		netif_stop_queue(netdev);
+		return 1;
+	}
+
+	if(e1000_tx_csum(adapter, skb))
+		tx_flags |= E1000_TX_FLAGS_CSUM;
+
+	if(adapter->vlgrp && vlan_tx_tag_present(skb)) {
+		tx_flags |= E1000_TX_FLAGS_VLAN;
+		tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
+	}
+
+	count = e1000_tx_map(adapter, skb);
+
+	e1000_tx_queue(adapter, count, tx_flags);
+
+	netdev->trans_start = jiffies;
+
+	return 0;
+}
+
+/**
+ * e1000_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ **/
+
+static void
+e1000_tx_timeout(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+
+	/* Do the reset outside of interrupt context */
+	schedule_task(&adapter->tx_timeout_task);
+}
+
+static void
+e1000_tx_timeout_task(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+
+	netif_device_detach(netdev);
+	e1000_down(adapter);
+	e1000_up(adapter);
+	netif_device_attach(netdev);
+}
+
+/**
+ * e1000_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ **/
+
+static struct net_device_stats *
+e1000_get_stats(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+
+	return &adapter->net_stats;
+}
+
+/**
+ * e1000_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+
+static int
+e1000_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+	int old_mtu = adapter->rx_buffer_len;
+	int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+
+	if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
+	   (max_frame > MAX_JUMBO_FRAME_SIZE)) {
+		E1000_ERR("Invalid MTU setting\n");
+		return -EINVAL;
+	}
+
+	if(max_frame <= MAXIMUM_ETHERNET_FRAME_SIZE) {
+		adapter->rx_buffer_len = E1000_RXBUFFER_2048;
+
+	} else if(adapter->hw.mac_type < e1000_82543) {
+		E1000_ERR("Jumbo Frames not supported on 82542\n");
+		return -EINVAL;
+
+	} else if(max_frame <= E1000_RXBUFFER_4096) {
+		adapter->rx_buffer_len = E1000_RXBUFFER_4096;
+
+	} else if(max_frame <= E1000_RXBUFFER_8192) {
+		adapter->rx_buffer_len = E1000_RXBUFFER_8192;
+
+	} else {
+		adapter->rx_buffer_len = E1000_RXBUFFER_16384;
+	}
+
+	if(old_mtu != adapter->rx_buffer_len && netif_running(netdev)) {
+
+		e1000_down(adapter);
+		e1000_up(adapter);
+	}
+
+	netdev->mtu = new_mtu;
+	adapter->hw.max_frame_size = max_frame;
+
+	return 0;
+}
+
+/**
+ * e1000_update_stats - Update the board statistics counters
+ * @adapter: board private structure
+ **/
+
+static void
+e1000_update_stats(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	unsigned long flags;
+	uint16_t phy_tmp;
+
+#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
+
+	spin_lock_irqsave(&adapter->stats_lock, flags);
+
+	/* these counters are modified from e1000_adjust_tbi_stats,
+	 * called from the interrupt context, so they must only
+	 * be written while holding adapter->stats_lock
+	 */
+
+	adapter->stats.crcerrs += E1000_READ_REG(hw, CRCERRS);
+	adapter->stats.gprc += E1000_READ_REG(hw, GPRC);
+	adapter->stats.gorcl += E1000_READ_REG(hw, GORCL);
+	adapter->stats.gorch += E1000_READ_REG(hw, GORCH);
+	adapter->stats.bprc += E1000_READ_REG(hw, BPRC);
+	adapter->stats.mprc += E1000_READ_REG(hw, MPRC);
+	adapter->stats.roc += E1000_READ_REG(hw, ROC);
+	adapter->stats.prc64 += E1000_READ_REG(hw, PRC64);
+	adapter->stats.prc127 += E1000_READ_REG(hw, PRC127);
+	adapter->stats.prc255 += E1000_READ_REG(hw, PRC255);
+	adapter->stats.prc511 += E1000_READ_REG(hw, PRC511);
+	adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023);
+	adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522);
+
+	spin_unlock_irqrestore(&adapter->stats_lock, flags);
+
+	/* the rest of the counters are only modified here */
+
+	adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS);
+	adapter->stats.mpc += E1000_READ_REG(hw, MPC);
+	adapter->stats.scc += E1000_READ_REG(hw, SCC);
+	adapter->stats.ecol += E1000_READ_REG(hw, ECOL);
+	adapter->stats.mcc += E1000_READ_REG(hw, MCC);
+	adapter->stats.latecol += E1000_READ_REG(hw, LATECOL);
+	adapter->stats.dc += E1000_READ_REG(hw, DC);
+	adapter->stats.sec += E1000_READ_REG(hw, SEC);
+	adapter->stats.rlec += E1000_READ_REG(hw, RLEC);
+	adapter->stats.xonrxc += E1000_READ_REG(hw, XONRXC);
+	adapter->stats.xontxc += E1000_READ_REG(hw, XONTXC);
+	adapter->stats.xoffrxc += E1000_READ_REG(hw, XOFFRXC);
+	adapter->stats.xofftxc += E1000_READ_REG(hw, XOFFTXC);
+	adapter->stats.fcruc += E1000_READ_REG(hw, FCRUC);
+	adapter->stats.gptc += E1000_READ_REG(hw, GPTC);
+	adapter->stats.gotcl += E1000_READ_REG(hw, GOTCL);
+	adapter->stats.gotch += E1000_READ_REG(hw, GOTCH);
+	adapter->stats.rnbc += E1000_READ_REG(hw, RNBC);
+	adapter->stats.ruc += E1000_READ_REG(hw, RUC);
+	adapter->stats.rfc += E1000_READ_REG(hw, RFC);
+	adapter->stats.rjc += E1000_READ_REG(hw, RJC);
+	adapter->stats.torl += E1000_READ_REG(hw, TORL);
+	adapter->stats.torh += E1000_READ_REG(hw, TORH);
+	adapter->stats.totl += E1000_READ_REG(hw, TOTL);
+	adapter->stats.toth += E1000_READ_REG(hw, TOTH);
+	adapter->stats.tpr += E1000_READ_REG(hw, TPR);
+	adapter->stats.ptc64 += E1000_READ_REG(hw, PTC64);
+	adapter->stats.ptc127 += E1000_READ_REG(hw, PTC127);
+	adapter->stats.ptc255 += E1000_READ_REG(hw, PTC255);
+	adapter->stats.ptc511 += E1000_READ_REG(hw, PTC511);
+	adapter->stats.ptc1023 += E1000_READ_REG(hw, PTC1023);
+	adapter->stats.ptc1522 += E1000_READ_REG(hw, PTC1522);
+	adapter->stats.mptc += E1000_READ_REG(hw, MPTC);
+	adapter->stats.bptc += E1000_READ_REG(hw, BPTC);
+
+	/* used for adaptive IFS */
+
+	hw->tx_packet_delta = E1000_READ_REG(hw, TPT);
+	adapter->stats.tpt += hw->tx_packet_delta;
+	hw->collision_delta = E1000_READ_REG(hw, COLC);
+	adapter->stats.colc += hw->collision_delta;
+
+	if(hw->mac_type >= e1000_82543) {
+		adapter->stats.algnerrc += E1000_READ_REG(hw, ALGNERRC);
+		adapter->stats.rxerrc += E1000_READ_REG(hw, RXERRC);
+		adapter->stats.tncrs += E1000_READ_REG(hw, TNCRS);
+		adapter->stats.cexterr += E1000_READ_REG(hw, CEXTERR);
+		adapter->stats.tsctc += E1000_READ_REG(hw, TSCTC);
+		adapter->stats.tsctfc += E1000_READ_REG(hw, TSCTFC);
+	}
+
+	/* Fill out the OS statistics structure */
+
+	adapter->net_stats.rx_packets = adapter->stats.gprc;
+	adapter->net_stats.tx_packets = adapter->stats.gptc;
+	adapter->net_stats.rx_bytes = adapter->stats.gorcl;
+	adapter->net_stats.tx_bytes = adapter->stats.gotcl;
+	adapter->net_stats.multicast = adapter->stats.mprc;
+	adapter->net_stats.collisions = adapter->stats.colc;
+
+	/* Rx Errors */
+
+	adapter->net_stats.rx_errors = adapter->stats.rxerrc +
+		adapter->stats.crcerrs + adapter->stats.algnerrc +
+		adapter->stats.rlec + adapter->stats.rnbc +
+		adapter->stats.mpc + adapter->stats.cexterr;
+	adapter->net_stats.rx_dropped = adapter->stats.rnbc;
+	adapter->net_stats.rx_length_errors = adapter->stats.rlec;
+	adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
+	adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc;
+	adapter->net_stats.rx_fifo_errors = adapter->stats.mpc;
+	adapter->net_stats.rx_missed_errors = adapter->stats.mpc;
+
+	/* Tx Errors */
+
+	adapter->net_stats.tx_errors = adapter->stats.ecol +
+	                               adapter->stats.latecol;
+	adapter->net_stats.tx_aborted_errors = adapter->stats.ecol;
+	adapter->net_stats.tx_window_errors = adapter->stats.latecol;
+	adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs;
+
+	/* Tx Dropped needs to be maintained elsewhere */
+
+	/* Phy Stats */
+
+	if(hw->media_type == e1000_media_type_copper) {
+		if((adapter->link_speed == SPEED_1000) &&
+		   (!e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) {
+			phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
+			adapter->phy_stats.idle_errors += phy_tmp;
+		}
+
+		if((hw->mac_type <= e1000_82546) &&
+		   !e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp))
+			adapter->phy_stats.receive_errors += phy_tmp;
+	}
+}
+
+/**
+ * e1000_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+
+static inline void
+e1000_irq_disable(struct e1000_adapter *adapter)
+{
+	atomic_inc(&adapter->irq_sem);
+	E1000_WRITE_REG(&adapter->hw, IMC, ~0);
+	E1000_WRITE_FLUSH(&adapter->hw);
+	synchronize_irq();
+}
+
+/**
+ * e1000_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+
+static inline void
+e1000_irq_enable(struct e1000_adapter *adapter)
+{
+	if(atomic_dec_and_test(&adapter->irq_sem)) {
+		E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK);
+		E1000_WRITE_FLUSH(&adapter->hw);
+	}
+}
+
+/**
+ * e1000_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ * @pt_regs: CPU registers structure
+ **/
+
+static void
+e1000_intr(int irq, void *data, struct pt_regs *regs)
+{
+	struct net_device *netdev = data;
+	struct e1000_adapter *adapter = netdev->priv;
+	uint32_t icr;
+	int i = E1000_MAX_INTR;
+
+	while(i && (icr = E1000_READ_REG(&adapter->hw, ICR))) {
+
+		if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+			adapter->hw.get_link_status = 1;
+			mod_timer(&adapter->watchdog_timer, jiffies);
+		}
+
+		e1000_clean_rx_irq(adapter);
+		e1000_clean_tx_irq(adapter);
+		i--;
+
+	}
+}
+
+/**
+ * e1000_clean_tx_irq - Reclaim resources after transmit completes
+ * @adapter: board private structure
+ **/
+
+static void
+e1000_clean_tx_irq(struct e1000_adapter *adapter)
+{
+	struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_tx_desc *tx_desc;
+	int i;
+
+	i = tx_ring->next_to_clean;
+	tx_desc = E1000_TX_DESC(*tx_ring, i);
+
+	while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
+
+		if(tx_ring->buffer_info[i].dma) {
+
+			pci_unmap_page(pdev,
+			               tx_ring->buffer_info[i].dma,
+			               tx_ring->buffer_info[i].length,
+			               PCI_DMA_TODEVICE);
+
+			tx_ring->buffer_info[i].dma = 0;
+		}
+
+		if(tx_ring->buffer_info[i].skb) {
+
+			dev_kfree_skb_any(tx_ring->buffer_info[i].skb);
+
+			tx_ring->buffer_info[i].skb = NULL;
+		}
+
+		tx_desc->upper.data = 0;
+
+		i = (i + 1) % tx_ring->count;
+		tx_desc = E1000_TX_DESC(*tx_ring, i);
+	}
+
+	tx_ring->next_to_clean = i;
+
+	if(netif_queue_stopped(netdev) && netif_carrier_ok(netdev) &&
+	   (E1000_DESC_UNUSED(tx_ring) > E1000_TX_QUEUE_WAKE)) {
+
+		netif_wake_queue(netdev);
+	}
+}
+
+/**
+ * e1000_clean_rx_irq - Send received data up the network stack,
+ * @adapter: board private structure
+ **/
+
+static void
+e1000_clean_rx_irq(struct e1000_adapter *adapter)
+{
+	struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_rx_desc *rx_desc;
+	struct sk_buff *skb;
+	unsigned long flags;
+	uint32_t length;
+	uint8_t last_byte;
+	int i;
+
+	i = rx_ring->next_to_clean;
+	rx_desc = E1000_RX_DESC(*rx_ring, i);
+
+	while(rx_desc->status & E1000_RXD_STAT_DD) {
+
+		pci_unmap_single(pdev,
+		                 rx_ring->buffer_info[i].dma,
+		                 rx_ring->buffer_info[i].length,
+		                 PCI_DMA_FROMDEVICE);
+
+		skb = rx_ring->buffer_info[i].skb;
+		length = le16_to_cpu(rx_desc->length);
+
+		if(!(rx_desc->status & E1000_RXD_STAT_EOP)) {
+
+			/* All receives must fit into a single buffer */
+
+			E1000_DBG("Receive packet consumed multiple buffers\n");
+
+			dev_kfree_skb_irq(skb);
+			rx_desc->status = 0;
+			rx_ring->buffer_info[i].skb = NULL;
+
+			i = (i + 1) % rx_ring->count;
+
+			rx_desc = E1000_RX_DESC(*rx_ring, i);
+			continue;
+		}
+
+		if(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
+
+			last_byte = *(skb->data + length - 1);
+
+			if(TBI_ACCEPT(&adapter->hw, rx_desc->status,
+			              rx_desc->errors, length, last_byte)) {
+
+				spin_lock_irqsave(&adapter->stats_lock, flags);
+
+				e1000_tbi_adjust_stats(&adapter->hw,
+				                       &adapter->stats,
+				                       length, skb->data);
+
+				spin_unlock_irqrestore(&adapter->stats_lock,
+				                       flags);
+				length--;
+			} else {
+
+				dev_kfree_skb_irq(skb);
+				rx_desc->status = 0;
+				rx_ring->buffer_info[i].skb = NULL;
+
+				i = (i + 1) % rx_ring->count;
+
+				rx_desc = E1000_RX_DESC(*rx_ring, i);
+				continue;
+			}
+		}
+
+		/* Good Receive */
+		skb_put(skb, length - ETHERNET_FCS_SIZE);
+
+		/* Receive Checksum Offload */
+		e1000_rx_checksum(adapter, rx_desc, skb);
+
+		skb->protocol = eth_type_trans(skb, netdev);
+		if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) {
+			vlan_hwaccel_rx(skb, adapter->vlgrp,
+				(rx_desc->special & E1000_RXD_SPC_VLAN_MASK));
+		} else {
+			netif_rx(skb);
+		}
+		netdev->last_rx = jiffies;
+
+		rx_desc->status = 0;
+		rx_ring->buffer_info[i].skb = NULL;
+
+		i = (i + 1) % rx_ring->count;
+
+		rx_desc = E1000_RX_DESC(*rx_ring, i);
+	}
+
+	rx_ring->next_to_clean = i;
+
+	e1000_alloc_rx_buffers(adapter);
+}
+
+/**
+ * e1000_alloc_rx_buffers - Replace used receive buffers
+ * @data: address of board private structure
+ **/
+
+static void
+e1000_alloc_rx_buffers(struct e1000_adapter *adapter)
+{
+	struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_rx_desc *rx_desc;
+	struct sk_buff *skb;
+	int reserve_len;
+	int i;
+
+	reserve_len = 2;
+
+	i = rx_ring->next_to_use;
+
+	while(!rx_ring->buffer_info[i].skb) {
+		rx_desc = E1000_RX_DESC(*rx_ring, i);
+
+		skb = dev_alloc_skb(adapter->rx_buffer_len + reserve_len);
+
+		if(!skb) {
+			/* Better luck next round */
+			break;
+		}
+
+		/* Make buffer alignment 2 beyond a 16 byte boundary
+		 * this will result in a 16 byte aligned IP header after
+		 * the 14 byte MAC header is removed
+		 */
+		skb_reserve(skb, reserve_len);
+
+		skb->dev = netdev;
+
+		rx_ring->buffer_info[i].skb = skb;
+		rx_ring->buffer_info[i].length = adapter->rx_buffer_len;
+		rx_ring->buffer_info[i].dma =
+			pci_map_single(pdev,
+			               skb->data,
+			               adapter->rx_buffer_len,
+			               PCI_DMA_FROMDEVICE);
+
+		rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma);
+
+		if(!(i % E1000_RX_BUFFER_WRITE)) {
+			/* Force memory writes to complete before letting h/w
+			 * know there are new descriptors to fetch.  (Only
+			 * applicable for weak-ordered memory model archs,
+			 * such as IA-64). */
+			wmb();
+
+			E1000_WRITE_REG(&adapter->hw, RDT, i);
+		}
+
+		i = (i + 1) % rx_ring->count;
+	}
+
+	rx_ring->next_to_use = i;
+}
+
+/**
+ * e1000_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ **/
+
+static int
+e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	switch (cmd) {
+	case SIOCETHTOOL:
+		return e1000_ethtool_ioctl(netdev, ifr);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+/**
+ * e1000_rx_checksum - Receive Checksum Offload for 82543
+ * @adapter: board private structure
+ * @rx_desc: receive descriptor
+ * @sk_buff: socket buffer with received data
+ **/
+
+static inline void
+e1000_rx_checksum(struct e1000_adapter *adapter,
+                  struct e1000_rx_desc *rx_desc,
+                  struct sk_buff *skb)
+{
+	/* 82543 or newer only */
+	if((adapter->hw.mac_type < e1000_82543) ||
+	/* Ignore Checksum bit is set */
+	(rx_desc->status & E1000_RXD_STAT_IXSM) ||
+	/* TCP Checksum has not been calculated */
+	(!(rx_desc->status & E1000_RXD_STAT_TCPCS))) {
+		skb->ip_summed = CHECKSUM_NONE;
+		return;
+	}
+
+	/* At this point we know the hardware did the TCP checksum */
+	/* now look at the TCP checksum error bit */
+	if(rx_desc->errors & E1000_RXD_ERR_TCPE) {
+		/* let the stack verify checksum errors */
+		skb->ip_summed = CHECKSUM_NONE;
+		adapter->hw_csum_err++;
+	} else {
+	/* TCP checksum is good */
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		adapter->hw_csum_good++;
+	}
+}
+
+void
+e1000_pci_set_mwi(struct e1000_hw *hw)
+{
+	struct e1000_adapter *adapter = hw->back;
+
+	pci_set_mwi(adapter->pdev);
+}
+
+void
+e1000_pci_clear_mwi(struct e1000_hw *hw)
+{
+	struct e1000_adapter *adapter = hw->back;
+
+	pci_clear_mwi(adapter->pdev);
+}
+
+void
+e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
+{
+	struct e1000_adapter *adapter = hw->back;
+
+	pci_read_config_word(adapter->pdev, reg, value);
+}
+
+void
+e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
+{
+	struct e1000_adapter *adapter = hw->back;
+
+	pci_write_config_word(adapter->pdev, reg, *value);
+}
+
+uint32_t
+e1000_io_read(struct e1000_hw *hw, uint32_t port)
+{
+	return inl(port);
+}
+
+void
+e1000_io_write(struct e1000_hw *hw, uint32_t port, uint32_t value)
+{
+	outl(value, port);
+}
+
+static void
+e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+	uint32_t ctrl, rctl;
+
+	e1000_irq_disable(adapter);
+	adapter->vlgrp = grp;
+
+	if(grp) {
+		/* enable VLAN tag insert/strip */
+
+		E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE);
+
+		ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+		ctrl |= E1000_CTRL_VME;
+		E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+
+		/* enable VLAN receive filtering */
+
+		rctl = E1000_READ_REG(&adapter->hw, RCTL);
+		rctl |= E1000_RCTL_VFE;
+		rctl &= ~E1000_RCTL_CFIEN;
+		E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+	} else {
+		/* disable VLAN tag insert/strip */
+
+		ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+		ctrl &= ~E1000_CTRL_VME;
+		E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+
+		/* disable VLAN filtering */
+
+		rctl = E1000_READ_REG(&adapter->hw, RCTL);
+		rctl &= ~E1000_RCTL_VFE;
+		E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+	}
+
+	e1000_irq_enable(adapter);
+}
+
+static void
+e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+	uint32_t vfta, index;
+
+	/* add VID to filter table */
+
+	index = (vid >> 5) & 0x7F;
+	vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index);
+	vfta |= (1 << (vid & 0x1F));
+	e1000_write_vfta(&adapter->hw, index, vfta);
+}
+
+static void
+e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+	uint32_t vfta, index;
+
+	e1000_irq_disable(adapter);
+
+	if(adapter->vlgrp)
+		adapter->vlgrp->vlan_devices[vid] = NULL;
+
+	e1000_irq_enable(adapter);
+
+	/* remove VID from filter table*/
+
+	index = (vid >> 5) & 0x7F;
+	vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index);
+	vfta &= ~(1 << (vid & 0x1F));
+	e1000_write_vfta(&adapter->hw, index, vfta);
+}
+
+static int
+e1000_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
+{
+	struct pci_dev *pdev = NULL;
+
+	switch(event) {
+	case SYS_DOWN:
+	case SYS_HALT:
+	case SYS_POWER_OFF:
+		pci_for_each_dev(pdev) {
+			if(pci_dev_driver(pdev) == &e1000_driver)
+				e1000_suspend(pdev, 3);
+		}
+	}
+	return NOTIFY_DONE;
+}
+
+static int
+e1000_notify_netdev(struct notifier_block *nb, unsigned long event, void *p)
+{
+	struct e1000_adapter *adapter;
+	struct net_device *netdev = p;
+	if(netdev == NULL)
+		return NOTIFY_DONE;
+
+	switch(event) {
+	case NETDEV_CHANGENAME:
+		if(netdev->open == e1000_open) {
+			adapter = netdev->priv;
+			/* rename the proc nodes the easy way */
+			e1000_proc_dev_free(adapter);
+			memcpy(adapter->ifname, netdev->name, IFNAMSIZ);
+			adapter->ifname[IFNAMSIZ-1] = 0;
+			e1000_proc_dev_setup(adapter);
+		}
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static int
+e1000_suspend(struct pci_dev *pdev, uint32_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct e1000_adapter *adapter = netdev->priv;
+	uint32_t ctrl, ctrl_ext, rctl, manc;
+
+	netif_device_detach(netdev);
+
+	if(netif_running(netdev))
+		e1000_down(adapter);
+
+	if(adapter->wol) {
+		e1000_setup_rctl(adapter);
+		e1000_set_multi(netdev);
+
+		/* turn on all-multi mode if wake on multicast is enabled */
+		if(adapter->wol & E1000_WUFC_MC) {
+			rctl = E1000_READ_REG(&adapter->hw, RCTL);
+			rctl |= E1000_RCTL_MPE;
+			E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+		}
+
+		if(adapter->hw.mac_type >= e1000_82540) {
+			ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+			/* advertise wake from D3Cold */
+			#define E1000_CTRL_ADVD3WUC 0x00100000
+			/* phy power management enable */
+			#define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000
+			ctrl |= E1000_CTRL_ADVD3WUC |
+				E1000_CTRL_EN_PHY_PWR_MGMT;
+			E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+		}
+
+		if(adapter->hw.media_type == e1000_media_type_fiber) {
+			/* keep the laser running in D3 */
+			ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
+			ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA;
+			E1000_WRITE_REG(&adapter->hw, CTRL_EXT, ctrl_ext);
+		}
+
+		E1000_WRITE_REG(&adapter->hw, WUC, E1000_WUC_PME_EN);
+		E1000_WRITE_REG(&adapter->hw, WUFC, adapter->wol);
+		pci_enable_wake(pdev, 3, 1);
+		pci_enable_wake(pdev, 4, 1); /* 4 == D3 cold */
+	} else {
+		E1000_WRITE_REG(&adapter->hw, WUC, 0);
+		E1000_WRITE_REG(&adapter->hw, WUFC, 0);
+		pci_enable_wake(pdev, 3, 0);
+		pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */
+	}
+
+	pci_save_state(pdev, adapter->pci_state);
+
+	if(adapter->hw.mac_type >= e1000_82540) {
+		manc = E1000_READ_REG(&adapter->hw, MANC);
+		if(manc & E1000_MANC_SMBUS_EN) {
+			manc |= E1000_MANC_ARP_EN;
+			E1000_WRITE_REG(&adapter->hw, MANC, manc);
+			state = 0;
+		}
+	}
+
+	state = (state > 0) ? 3 : 0;
+	pci_set_power_state(pdev, state);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int
+e1000_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct e1000_adapter *adapter = netdev->priv;
+	uint32_t manc;
+
+	pci_set_power_state(pdev, 0);
+	pci_restore_state(pdev, adapter->pci_state);
+
+	pci_enable_wake(pdev, 3, 0);
+	pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */
+
+	e1000_reset(adapter);
+	E1000_WRITE_REG(&adapter->hw, WUS, ~0);
+
+	if(netif_running(netdev))
+		e1000_up(adapter);
+
+	netif_device_attach(netdev);
+
+	if(adapter->hw.mac_type >= e1000_82540) {
+		manc = E1000_READ_REG(&adapter->hw, MANC);
+		manc &= ~(E1000_MANC_ARP_EN);
+		E1000_WRITE_REG(&adapter->hw, MANC, manc);
+	}
+
+	return 0;
+}
+#endif
+
+/* e1000_main.c */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e1000/e1000_osdep.h linux-2.4.20/drivers/net/e1000/e1000_osdep.h
--- linux-2.4.19/drivers/net/e1000/e1000_osdep.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e1000/e1000_osdep.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,101 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+
+/* glue for the OS independant part of e1000 
+ * includes register access macros
+ */
+
+#ifndef _E1000_OSDEP_H_
+#define _E1000_OSDEP_H_
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+
+#ifndef msec_delay
+#define msec_delay(x)	do { if(in_interrupt()) { \
+				/* Don't mdelay in interrupt context! */ \
+	                	BUG(); \
+			} else { \
+				set_current_state(TASK_UNINTERRUPTIBLE); \
+				schedule_timeout((x * HZ)/1000); \
+			} } while(0)
+#endif
+
+#define PCI_COMMAND_REGISTER   PCI_COMMAND
+#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
+
+typedef enum {
+    FALSE = 0,
+    TRUE = 1
+} boolean_t;
+
+#define ASSERT(x)	if(!(x)) BUG()
+#define MSGOUT(S, A, B)	printk(KERN_DEBUG S "\n", A, B)
+
+#if DBG
+#define DEBUGOUT(S)		printk(KERN_DEBUG S "\n")
+#define DEBUGOUT1(S, A...)	printk(KERN_DEBUG S "\n", A)
+#else
+#define DEBUGOUT(S)
+#define DEBUGOUT1(S, A...)
+#endif
+
+#define DEBUGFUNC(F) DEBUGOUT(F)
+#define DEBUGOUT2 DEBUGOUT1
+#define DEBUGOUT3 DEBUGOUT2
+#define DEBUGOUT7 DEBUGOUT3
+
+
+#define E1000_WRITE_REG(a, reg, value) ( \
+    ((a)->mac_type >= e1000_82543) ? \
+        (writel((value), ((a)->hw_addr + E1000_##reg))) : \
+        (writel((value), ((a)->hw_addr + E1000_82542_##reg))))
+
+#define E1000_READ_REG(a, reg) ( \
+    ((a)->mac_type >= e1000_82543) ? \
+        readl((a)->hw_addr + E1000_##reg) : \
+        readl((a)->hw_addr + E1000_82542_##reg))
+
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \
+    ((a)->mac_type >= e1000_82543) ? \
+        writel((value), ((a)->hw_addr + E1000_##reg + ((offset) << 2))) : \
+        writel((value), ((a)->hw_addr + E1000_82542_##reg + ((offset) << 2))))
+
+#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
+    ((a)->mac_type >= e1000_82543) ? \
+        readl((a)->hw_addr + E1000_##reg + ((offset) << 2)) : \
+        readl((a)->hw_addr + E1000_82542_##reg + ((offset) << 2)))
+
+#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS)
+
+#endif /* _E1000_OSDEP_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e1000/e1000_param.c linux-2.4.20/drivers/net/e1000/e1000_param.c
--- linux-2.4.19/drivers/net/e1000/e1000_param.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e1000/e1000_param.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,654 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "e1000.h"
+
+/* This is the only thing that needs to be changed to adjust the
+ * maximum number of ports that the driver can manage.
+ */
+
+#define E1000_MAX_NIC 32
+
+#define OPTION_UNSET    -1
+#define OPTION_DISABLED 0
+#define OPTION_ENABLED  1
+
+/* Module Parameters are always initialized to -1, so that the driver
+ * can tell the difference between no user specified value or the
+ * user asking for the default value.
+ * The true default values are loaded in when e1000_check_options is called.
+ *
+ * This is a GCC extension to ANSI C.
+ * See the item "Labeled Elements in Initializers" in the section
+ * "Extensions to the C Language Family" of the GCC documentation.
+ */
+
+#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
+
+/* All parameters are treated the same, as an integer array of values.
+ * This macro just reduces the need to repeat the same declaration code
+ * over and over (plus this helps to avoid typo bugs).
+ */
+
+#define E1000_PARAM(X, S) \
+static const int __devinitdata X[E1000_MAX_NIC + 1] = E1000_PARAM_INIT; \
+MODULE_PARM(X, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); \
+MODULE_PARM_DESC(X, S);
+
+/* Transmit Descriptor Count
+ *
+ * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
+ * Valid Range: 80-4096 for 82544
+ *
+ * Default Value: 256
+ */
+
+E1000_PARAM(TxDescriptors, "Number of transmit descriptors");
+
+/* Receive Descriptor Count
+ *
+ * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
+ * Valid Range: 80-4096 for 82544
+ *
+ * Default Value: 80
+ */
+
+E1000_PARAM(RxDescriptors, "Number of receive descriptors");
+
+/* User Specified Speed Override
+ *
+ * Valid Range: 0, 10, 100, 1000
+ *  - 0    - auto-negotiate at all supported speeds
+ *  - 10   - only link at 10 Mbps
+ *  - 100  - only link at 100 Mbps
+ *  - 1000 - only link at 1000 Mbps
+ *
+ * Default Value: 0
+ */
+
+E1000_PARAM(Speed, "Speed setting");
+
+/* User Specified Duplex Override
+ *
+ * Valid Range: 0-2
+ *  - 0 - auto-negotiate for duplex
+ *  - 1 - only link at half duplex
+ *  - 2 - only link at full duplex
+ *
+ * Default Value: 0
+ */
+
+E1000_PARAM(Duplex, "Duplex setting");
+
+/* Auto-negotiation Advertisement Override
+ *
+ * Valid Range: 0x01-0x0F, 0x20-0x2F
+ *
+ * The AutoNeg value is a bit mask describing which speed and duplex
+ * combinations should be advertised during auto-negotiation.
+ * The supported speed and duplex modes are listed below
+ *
+ * Bit           7     6     5      4      3     2     1      0
+ * Speed (Mbps)  N/A   N/A   1000   N/A    100   100   10     10
+ * Duplex                    Full          Full  Half  Full   Half
+ *
+ * Default Value: 0x2F
+ */
+
+E1000_PARAM(AutoNeg, "Advertised auto-negotiation setting");
+
+/* User Specified Flow Control Override
+ *
+ * Valid Range: 0-3
+ *  - 0 - No Flow Control
+ *  - 1 - Rx only, respond to PAUSE frames but do not generate them
+ *  - 2 - Tx only, generate PAUSE frames but ignore them on receive
+ *  - 3 - Full Flow Control Support
+ *
+ * Default Value: Read flow control settings from the EEPROM
+ */
+
+E1000_PARAM(FlowControl, "Flow Control setting");
+
+/* XsumRX - Receive Checksum Offload Enable/Disable
+ *
+ * Valid Range: 0, 1
+ *  - 0 - disables all checksum offload
+ *  - 1 - enables receive IP/TCP/UDP checksum offload
+ *        on 82543 based NICs
+ *
+ * Default Value: 1
+ */
+
+E1000_PARAM(XsumRX, "Disable or enable Receive Checksum offload");
+
+/* Transmit Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ *
+ * Default Value: 64
+ */
+
+E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay");
+
+/* Transmit Absolute Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ *
+ * Default Value: 0
+ */
+
+E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay");
+
+/* Receive Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ *
+ * Default Value: 0/128
+ */
+
+E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
+
+/* Receive Absolute Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ *
+ * Default Value: 128
+ */
+
+E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
+
+#define AUTONEG_ADV_DEFAULT  0x2F
+#define AUTONEG_ADV_MASK     0x2F
+#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
+
+#define DEFAULT_TXD                  256
+#define MAX_TXD                      256
+#define MIN_TXD                       80
+#define MAX_82544_TXD               4096
+
+#define DEFAULT_RXD                   80
+#define MAX_RXD                      256
+#define MIN_RXD                       80
+#define MAX_82544_RXD               4096
+
+#define DEFAULT_RDTR                   0
+#define MAX_RXDELAY               0xFFFF
+#define MIN_RXDELAY                    0
+
+#define DEFAULT_RADV                 128
+#define MAX_RXABSDELAY            0xFFFF
+#define MIN_RXABSDELAY                 0
+
+#define DEFAULT_TIDV                  64
+#define MAX_TXDELAY               0xFFFF
+#define MIN_TXDELAY                    0
+
+#define DEFAULT_TADV                  64
+#define MAX_TXABSDELAY            0xFFFF
+#define MIN_TXABSDELAY                 0
+
+struct e1000_option {
+	enum { enable_option, range_option, list_option } type;
+	char *name;
+	char *err;
+	int  def;
+	union {
+		struct { /* range_option info */
+			int min;
+			int max;
+		} r;
+		struct { /* list_option info */
+			int nr;
+			struct e1000_opt_list { int i; char *str; } *p;
+		} l;
+	} arg;
+};
+
+
+static int __devinit
+e1000_validate_option(int *value, struct e1000_option *opt)
+{
+	if(*value == OPTION_UNSET) {
+		*value = opt->def;
+		return 0;
+	}
+
+	switch (opt->type) {
+	case enable_option:
+		switch (*value) {
+		case OPTION_ENABLED:
+			printk(KERN_INFO "%s Enabled\n", opt->name);
+			return 0;
+		case OPTION_DISABLED:
+			printk(KERN_INFO "%s Disabled\n", opt->name);
+			return 0;
+		}
+		break;
+	case range_option:
+		if(*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
+			printk(KERN_INFO "%s set to %i\n", opt->name, *value);
+			return 0;
+		}
+		break;
+	case list_option: {
+		int i;
+		struct e1000_opt_list *ent;
+
+		for(i = 0; i < opt->arg.l.nr; i++) {
+			ent = &opt->arg.l.p[i];
+			if(*value == ent->i) {
+				if(ent->str[0] != '\0')
+					printk(KERN_INFO "%s\n", ent->str);
+				return 0;
+			}
+		}
+	}
+		break;
+	default:
+		BUG();
+	}
+		
+	printk(KERN_INFO "Invalid %s specified (%i) %s\n",
+	       opt->name, *value, opt->err);
+	*value = opt->def;
+	return -1;
+}
+
+static void e1000_check_fiber_options(struct e1000_adapter *adapter);
+static void e1000_check_copper_options(struct e1000_adapter *adapter);
+
+/**
+ * e1000_check_options - Range Checking for Command Line Parameters
+ * @adapter: board private structure
+ *
+ * This routine checks all command line paramters for valid user
+ * input.  If an invalid value is given, or if no user specified
+ * value exists, a default value is used.  The final value is stored
+ * in a variable in the adapter structure.
+ **/
+
+void __devinit
+e1000_check_options(struct e1000_adapter *adapter)
+{
+	int bd = adapter->bd_number;
+	if(bd >= E1000_MAX_NIC) {
+		printk(KERN_NOTICE 
+		       "Warning: no configuration for board #%i\n", bd);
+		printk(KERN_NOTICE "Using defaults for all values\n");
+		bd = E1000_MAX_NIC;
+	}
+
+	{ /* Transmit Descriptor Count */
+		struct e1000_option opt = {
+			.type = range_option,
+			.name = "Transmit Descriptors",
+			.err  = "using default of " __MODULE_STRING(DEFAULT_TXD),
+			.def  = DEFAULT_TXD,
+			.arg  = { r: { min: MIN_TXD }}
+		};
+		struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
+		e1000_mac_type mac_type = adapter->hw.mac_type;
+		opt.arg.r.max = mac_type < e1000_82544 ? 
+			MAX_TXD : MAX_82544_TXD;
+
+		tx_ring->count = TxDescriptors[bd];
+		e1000_validate_option(&tx_ring->count, &opt);
+		E1000_ROUNDUP(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE);
+	}
+	{ /* Receive Descriptor Count */
+		struct e1000_option opt = {
+			.type = range_option,
+			.name = "Receive Descriptors",
+			.err  = "using default of " __MODULE_STRING(DEFAULT_RXD),
+			.def  = DEFAULT_RXD,
+			.arg  = { r: { min: MIN_RXD }}
+		};
+		struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
+		e1000_mac_type mac_type = adapter->hw.mac_type;
+		opt.arg.r.max = mac_type < e1000_82544 ? MAX_RXD : MAX_82544_RXD;
+
+		rx_ring->count = RxDescriptors[bd];
+		e1000_validate_option(&rx_ring->count, &opt);
+		E1000_ROUNDUP(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE);
+	}
+	{ /* Checksum Offload Enable/Disable */
+		struct e1000_option opt = {
+			.type = enable_option,
+			.name = "Checksum Offload",
+			.err  = "defaulting to Enabled",
+			.def  = OPTION_ENABLED
+		};
+		
+		int rx_csum = XsumRX[bd];
+		e1000_validate_option(&rx_csum, &opt);
+		adapter->rx_csum = rx_csum;
+	}
+	{ /* Flow Control */
+		
+		struct e1000_opt_list fc_list[] =
+			{{ e1000_fc_none,    "Flow Control Disabled" },
+			 { e1000_fc_rx_pause,"Flow Control Receive Only" },
+			 { e1000_fc_tx_pause,"Flow Control Transmit Only" },
+			 { e1000_fc_full,    "Flow Control Enabled" },
+			 { e1000_fc_default, "Flow Control Hardware Default" }};
+
+		struct e1000_option opt = {
+			.type = list_option,
+			.name = "Flow Control",
+			.err  = "reading default settings from EEPROM",
+			.def  = e1000_fc_default,
+			.arg  = { l: { nr: ARRAY_SIZE(fc_list), p: fc_list }}
+		};
+
+		int fc = FlowControl[bd];
+		e1000_validate_option(&fc, &opt);
+		adapter->hw.fc = adapter->hw.original_fc = fc;
+	}
+	{ /* Transmit Interrupt Delay */
+		char *tidv = "using default of " __MODULE_STRING(DEFAULT_TIDV);
+		struct e1000_option opt = {
+			.type = range_option,
+			.name = "Transmit Interrupt Delay",
+			.arg  = { r: { min: MIN_TXDELAY, max: MAX_TXDELAY }}
+		};
+		opt.def = DEFAULT_TIDV;
+		opt.err = tidv;
+
+		adapter->tx_int_delay = TxIntDelay[bd];
+		e1000_validate_option(&adapter->tx_int_delay, &opt);
+	}
+	{ /* Transmit Absolute Interrupt Delay */
+		char *tadv = "using default of " __MODULE_STRING(DEFAULT_TADV);
+		struct e1000_option opt = {
+			.type = range_option,
+			.name = "Transmit Absolute Interrupt Delay",
+			.arg  = { r: { min: MIN_TXABSDELAY, max: MAX_TXABSDELAY }}
+		};
+		opt.def = DEFAULT_TADV;
+		opt.err = tadv;
+
+		adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
+		e1000_validate_option(&adapter->tx_abs_int_delay, &opt);
+	}
+	{ /* Receive Interrupt Delay */
+		char *rdtr = "using default of " __MODULE_STRING(DEFAULT_RDTR);
+		struct e1000_option opt = {
+			.type = range_option,
+			.name = "Receive Interrupt Delay",
+			.arg  = { r: { min: MIN_RXDELAY, max: MAX_RXDELAY }}
+		};
+		opt.def = DEFAULT_RDTR;
+		opt.err = rdtr;
+
+		adapter->rx_int_delay = RxIntDelay[bd];
+		e1000_validate_option(&adapter->rx_int_delay, &opt);
+	}
+	{ /* Receive Absolute Interrupt Delay */
+		char *radv = "using default of " __MODULE_STRING(DEFAULT_RADV);
+		struct e1000_option opt = {
+			.type = range_option,
+			.name = "Receive Absolute Interrupt Delay",
+			.arg  = { r: { min: MIN_RXABSDELAY, max: MAX_RXABSDELAY }}
+		};
+		opt.def = DEFAULT_RADV;
+		opt.err = radv;
+
+		adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
+		e1000_validate_option(&adapter->rx_abs_int_delay, &opt);
+	}
+	
+	switch(adapter->hw.media_type) {
+	case e1000_media_type_fiber:
+		e1000_check_fiber_options(adapter);
+		break;
+	case e1000_media_type_copper:
+		e1000_check_copper_options(adapter);
+		break;
+	default:
+		BUG();
+	}
+}
+
+/**
+ * e1000_check_fiber_options - Range Checking for Link Options, Fiber Version
+ * @adapter: board private structure
+ *
+ * Handles speed and duplex options on fiber adapters
+ **/
+
+static void __devinit
+e1000_check_fiber_options(struct e1000_adapter *adapter)
+{
+	int bd = adapter->bd_number;
+	bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd;
+
+	if((Speed[bd] != OPTION_UNSET)) {
+		printk(KERN_INFO "Speed not valid for fiber adapters, "
+		       "parameter ignored\n");
+	}
+	if((Duplex[bd] != OPTION_UNSET)) {
+		printk(KERN_INFO "Duplex not valid for fiber adapters, "
+		       "parameter ignored\n");
+	}
+	if((AutoNeg[bd] != OPTION_UNSET)) {
+		printk(KERN_INFO "AutoNeg not valid for fiber adapters, "
+		       "parameter ignored\n");
+	}
+}
+
+/**
+ * e1000_check_copper_options - Range Checking for Link Options, Copper Version
+ * @adapter: board private structure
+ *
+ * Handles speed and duplex options on copper adapters
+ **/
+
+static void __devinit
+e1000_check_copper_options(struct e1000_adapter *adapter)
+{
+	int speed, dplx;
+	int bd = adapter->bd_number;
+	bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd;
+
+	{ /* Speed */
+		struct e1000_opt_list speed_list[] = {{          0, "" },
+		                                      {   SPEED_10, "" },
+		                                      {  SPEED_100, "" },
+		                                      { SPEED_1000, "" }};
+		struct e1000_option opt = {
+			.type = list_option,
+			.name = "Speed",
+			.err  = "parameter ignored",
+			.def  = 0,
+			.arg  = { l: { nr: ARRAY_SIZE(speed_list), p: speed_list }}
+		};
+
+		speed = Speed[bd];
+		e1000_validate_option(&speed, &opt);
+	}
+	{ /* Duplex */
+		struct e1000_opt_list dplx_list[] = {{           0, "" },
+		                                     { HALF_DUPLEX, "" },
+		                                     { FULL_DUPLEX, "" }};
+		struct e1000_option opt = {
+			.type = list_option,
+			.name = "Duplex",
+			.err  = "parameter ignored",
+			.def  = 0,
+			.arg  = { l: { nr: ARRAY_SIZE(dplx_list), p: dplx_list }}
+		};
+
+		dplx = Duplex[bd];
+		e1000_validate_option(&dplx, &opt);
+	}
+
+	if(AutoNeg[bd] != OPTION_UNSET && (speed != 0 || dplx != 0)) {
+		printk(KERN_INFO
+		       "AutoNeg specified along with Speed or Duplex, "
+		       "parameter ignored\n");
+		adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
+	} else { /* Autoneg */
+		struct e1000_opt_list an_list[] =
+			#define AA "AutoNeg advertising "
+			{{ 0x01, AA "10/HD" },
+			 { 0x02, AA "10/FD" },
+			 { 0x03, AA "10/FD, 10/HD" },
+			 { 0x04, AA "100/HD" },
+			 { 0x05, AA "100/HD, 10/HD" },
+			 { 0x06, AA "100/HD, 10/FD" },
+			 { 0x07, AA "100/HD, 10/FD, 10/HD" },
+			 { 0x08, AA "100/FD" },
+			 { 0x09, AA "100/FD, 10/HD" },
+			 { 0x0a, AA "100/FD, 10/FD" },
+			 { 0x0b, AA "100/FD, 10/FD, 10/HD" },
+			 { 0x0c, AA "100/FD, 100/HD" },
+			 { 0x0d, AA "100/FD, 100/HD, 10/HD" },
+			 { 0x0e, AA "100/FD, 100/HD, 10/FD" },
+			 { 0x0f, AA "100/FD, 100/HD, 10/FD, 10/HD" },
+			 { 0x20, AA "1000/FD" },
+			 { 0x21, AA "1000/FD, 10/HD" },
+			 { 0x22, AA "1000/FD, 10/FD" },
+			 { 0x23, AA "1000/FD, 10/FD, 10/HD" },
+			 { 0x24, AA "1000/FD, 100/HD" },
+			 { 0x25, AA "1000/FD, 100/HD, 10/HD" },
+			 { 0x26, AA "1000/FD, 100/HD, 10/FD" },
+			 { 0x27, AA "1000/FD, 100/HD, 10/FD, 10/HD" },
+			 { 0x28, AA "1000/FD, 100/FD" },
+			 { 0x29, AA "1000/FD, 100/FD, 10/HD" },
+			 { 0x2a, AA "1000/FD, 100/FD, 10/FD" },
+			 { 0x2b, AA "1000/FD, 100/FD, 10/FD, 10/HD" },
+			 { 0x2c, AA "1000/FD, 100/FD, 100/HD" },
+			 { 0x2d, AA "1000/FD, 100/FD, 100/HD, 10/HD" },
+			 { 0x2e, AA "1000/FD, 100/FD, 100/HD, 10/FD" },
+			 { 0x2f, AA "1000/FD, 100/FD, 100/HD, 10/FD, 10/HD" }};
+
+		struct e1000_option opt = {
+			.type = list_option,
+			.name = "AutoNeg",
+			.err  = "parameter ignored",
+			.def  = AUTONEG_ADV_DEFAULT,
+			.arg  = { l: { nr: ARRAY_SIZE(an_list), p: an_list }}
+		};
+
+		int an = AutoNeg[bd];
+		e1000_validate_option(&an, &opt);
+		adapter->hw.autoneg_advertised = an;
+	}
+
+	switch (speed + dplx) {
+	case 0:
+		adapter->hw.autoneg = 1;
+		if(Speed[bd] != OPTION_UNSET || Duplex[bd] != OPTION_UNSET)
+			printk(KERN_INFO
+			       "Speed and duplex autonegotiation enabled\n");
+		break;
+	case HALF_DUPLEX:
+		printk(KERN_INFO "Half Duplex specified without Speed\n");
+		printk(KERN_INFO "Using Autonegotiation at Half Duplex only\n");
+		adapter->hw.autoneg = 1;
+		adapter->hw.autoneg_advertised = ADVERTISE_10_HALF | 
+		                                 ADVERTISE_100_HALF;
+		break;
+	case FULL_DUPLEX:
+		printk(KERN_INFO "Full Duplex specified without Speed\n");
+		printk(KERN_INFO "Using Autonegotiation at Full Duplex only\n");
+		adapter->hw.autoneg = 1;
+		adapter->hw.autoneg_advertised = ADVERTISE_10_FULL |
+		                                 ADVERTISE_100_FULL |
+		                                 ADVERTISE_1000_FULL;
+		break;
+	case SPEED_10:
+		printk(KERN_INFO "10 Mbps Speed specified without Duplex\n");
+		printk(KERN_INFO "Using Autonegotiation at 10 Mbps only\n");
+		adapter->hw.autoneg = 1;
+		adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
+		                                 ADVERTISE_10_FULL;
+		break;
+	case SPEED_10 + HALF_DUPLEX:
+		printk(KERN_INFO "Forcing to 10 Mbps Half Duplex\n");
+		adapter->hw.autoneg = 0;
+		adapter->hw.forced_speed_duplex = e1000_10_half;
+		adapter->hw.autoneg_advertised = 0;
+		break;
+	case SPEED_10 + FULL_DUPLEX:
+		printk(KERN_INFO "Forcing to 10 Mbps Full Duplex\n");
+		adapter->hw.autoneg = 0;
+		adapter->hw.forced_speed_duplex = e1000_10_full;
+		adapter->hw.autoneg_advertised = 0;
+		break;
+	case SPEED_100:
+		printk(KERN_INFO "100 Mbps Speed specified without Duplex\n");
+		printk(KERN_INFO "Using Autonegotiation at 100 Mbps only\n");
+		adapter->hw.autoneg = 1;
+		adapter->hw.autoneg_advertised = ADVERTISE_100_HALF |
+		                                 ADVERTISE_100_FULL;
+		break;
+	case SPEED_100 + HALF_DUPLEX:
+		printk(KERN_INFO "Forcing to 100 Mbps Half Duplex\n");
+		adapter->hw.autoneg = 0;
+		adapter->hw.forced_speed_duplex = e1000_100_half;
+		adapter->hw.autoneg_advertised = 0;
+		break;
+	case SPEED_100 + FULL_DUPLEX:
+		printk(KERN_INFO "Forcing to 100 Mbps Full Duplex\n");
+		adapter->hw.autoneg = 0;
+		adapter->hw.forced_speed_duplex = e1000_100_full;
+		adapter->hw.autoneg_advertised = 0;
+		break;
+	case SPEED_1000:
+		printk(KERN_INFO "1000 Mbps Speed specified without Duplex\n");
+		printk(KERN_INFO
+		       "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
+		adapter->hw.autoneg = 1;
+		adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
+		break;
+	case SPEED_1000 + HALF_DUPLEX:
+		printk(KERN_INFO "Half Duplex is not supported at 1000 Mbps\n");
+		printk(KERN_INFO
+		       "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
+		adapter->hw.autoneg = 1;
+		adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
+		break;
+	case SPEED_1000 + FULL_DUPLEX:
+		printk(KERN_INFO
+		       "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
+		adapter->hw.autoneg = 1;
+		adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
+		break;
+	default:
+		BUG();
+	}
+
+	/* Speed, AutoNeg and MDI/MDI-X must all play nice */
+	if (e1000_validate_mdi_setting(&(adapter->hw)) < 0) {
+		printk(KERN_INFO "Speed, AutoNeg and MDI-X specifications are "
+		       "incompatible. Setting MDI-X to a compatible value.\n");
+	}
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e1000/e1000_proc.c linux-2.4.20/drivers/net/e1000/e1000_proc.c
--- linux-2.4.19/drivers/net/e1000/e1000_proc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/e1000/e1000_proc.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,699 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  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.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/*
+ * Proc fs support.
+ *
+ * Read-only files created by driver (if CONFIG_PROC_FS):
+ *
+ * /proc/net/PRO_LAN_Adapters/<ethx>.info
+ * /proc/net/PRO_LAN_Adapters/<ethx>/<attribute>
+ *
+ * where <ethx>      is the system device name, i.e eth0.
+ *       <attribute> is the driver attribute name.
+ *
+ * There is one file for each driver attribute, where the contents
+ * of the file is the attribute value.  The ethx.info file contains
+ * a list of all driver attributes in one file.
+ *
+ */
+
+#include "e1000.h"
+
+#ifdef CONFIG_PROC_FS
+
+#include <linux/proc_fs.h>
+
+#define ADAPTERS_PROC_DIR           "PRO_LAN_Adapters"
+#define TAG_MAX_LENGTH              32
+#define LINE_MAX_LENGTH             80
+#define FIELD_MAX_LENGTH            LINE_MAX_LENGTH - TAG_MAX_LENGTH - 3
+
+extern char e1000_driver_name[];
+extern char e1000_driver_version[];
+
+/*
+ * The list of driver proc attributes is stored in a proc_list link
+ * list.  The list is build with proc_list_setup and is used to
+ * build the proc fs nodes.  The private data for each node is the
+ * corresponding link in the link list.
+ */
+
+struct proc_list {
+	struct list_head list;                  /* link list */
+	char tag[TAG_MAX_LENGTH + 1];           /* attribute name */
+	void *data;                             /* attribute data */
+	size_t len;				/* sizeof data */
+	char *(*func)(void *, size_t, char *);  /* format data func */
+};
+
+static int
+e1000_proc_read(char *page, char **start, off_t off, int count, int *eof)
+{
+	int len = strlen(page);
+
+	page[len++] = '\n';
+
+	if(len <= off + count)
+		*eof = 1;
+	*start = page + off;
+	len -= off;
+	if(len > count)
+		len = count;
+	if(len < 0)
+		len = 0;
+
+	return len;
+}
+
+static int
+e1000_proc_info_read(char *page, char **start, off_t off,
+                     int count, int *eof, void *data)
+{
+	struct list_head *proc_list_head = data, *curr;
+	struct proc_list *elem;
+	char *p = page;
+	char buf[FIELD_MAX_LENGTH + 1];
+
+	list_for_each(curr, proc_list_head) {
+		elem = list_entry(curr, struct proc_list, list);
+
+		if (p - page + LINE_MAX_LENGTH >= PAGE_SIZE)
+			break;
+
+		if(!strlen(elem->tag))
+			p += sprintf(p, "\n");
+		else
+			p += sprintf(p, "%-*.*s %.*s\n", 
+				TAG_MAX_LENGTH, TAG_MAX_LENGTH,
+				elem->tag, FIELD_MAX_LENGTH,
+				elem->func(elem->data, elem->len, buf));
+	}
+
+	*p = '\0';
+
+	return e1000_proc_read(page, start, off, count, eof);
+}
+
+static int
+e1000_proc_single_read(char *page, char **start, off_t off,
+                       int count, int *eof, void *data)
+{
+	struct proc_list *elem = data;
+
+	sprintf(page, "%.*s", FIELD_MAX_LENGTH, elem->func(elem->data, 
+	        elem->len, page));
+
+	return e1000_proc_read(page, start, off, count, eof);
+}
+
+static void
+e1000_proc_dirs_free(char *name, struct list_head *proc_list_head)
+{
+	struct proc_dir_entry *intel_proc_dir, *proc_dir;
+	char info_name[strlen(name) + strlen(".info")];
+
+	for(intel_proc_dir = proc_net->subdir; intel_proc_dir;
+		intel_proc_dir = intel_proc_dir->next) {
+		if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) &&
+		   !memcmp(intel_proc_dir->name, ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)))
+			break;
+	}
+
+	if(!intel_proc_dir)
+		return;
+
+	for(proc_dir = intel_proc_dir->subdir; proc_dir;
+		proc_dir = proc_dir->next) {
+		if ((proc_dir->namelen == strlen(name)) &&
+		    !memcmp(proc_dir->name, name, strlen(name)))
+			break;
+	}
+
+	if(proc_dir) {
+		struct list_head *curr;
+		struct proc_list *elem;
+
+		list_for_each(curr, proc_list_head) {
+			elem = list_entry(curr, struct proc_list, list);
+			remove_proc_entry(elem->tag, proc_dir);
+		}
+
+		strcpy(info_name, name);
+		strcat(info_name, ".info");
+
+		remove_proc_entry(info_name, intel_proc_dir);
+		remove_proc_entry(name, intel_proc_dir);
+	}
+
+	/* If the intel dir is empty, remove it */
+
+	for(proc_dir = intel_proc_dir->subdir; proc_dir;
+		proc_dir = proc_dir->next) {
+
+		/* ignore . and .. */
+
+		if(*(proc_dir->name) == '.')
+			continue;
+		break;
+	}
+
+	if(!proc_dir)
+		remove_proc_entry(ADAPTERS_PROC_DIR, proc_net);
+}
+
+
+static int
+e1000_proc_singles_create(struct proc_dir_entry *parent,
+                          struct list_head *proc_list_head)
+{
+	struct list_head *curr;
+	struct proc_list *elem;
+
+	list_for_each(curr, proc_list_head) {
+		struct proc_dir_entry *proc_entry;
+
+		elem = list_entry(curr, struct proc_list, list);
+
+		if(!strlen(elem->tag))
+			continue;
+
+		if(!(proc_entry =
+			create_proc_entry(elem->tag, S_IFREG, parent)))
+			return 0;
+
+		proc_entry->read_proc = e1000_proc_single_read;
+		proc_entry->data = elem;
+		SET_MODULE_OWNER(proc_entry);
+	}
+
+	return 1;
+}
+
+static void
+e1000_proc_dirs_create(void *data, char *name, 
+                       struct list_head *proc_list_head)
+{
+	struct proc_dir_entry *intel_proc_dir, *proc_dir, *info_entry;
+	char info_name[strlen(name) + strlen(".info")];
+
+	for(intel_proc_dir = proc_net->subdir; intel_proc_dir;
+		intel_proc_dir = intel_proc_dir->next) {
+		if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) &&
+		   !memcmp(intel_proc_dir->name, ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)))
+			break;
+	}
+
+	if(!intel_proc_dir)
+		if(!(intel_proc_dir =
+			create_proc_entry(ADAPTERS_PROC_DIR,
+				S_IFDIR, proc_net)))
+			return;
+
+	if(!(proc_dir =
+		create_proc_entry(name, S_IFDIR, intel_proc_dir)))
+		return;
+	SET_MODULE_OWNER(proc_dir);
+
+	if(!e1000_proc_singles_create(proc_dir, proc_list_head))
+		return;
+
+	strcpy(info_name, name);
+	strcat(info_name, ".info");
+
+	if(!(info_entry =
+		create_proc_entry(info_name, S_IFREG, intel_proc_dir)))
+		return;
+	SET_MODULE_OWNER(info_entry);
+
+	info_entry->read_proc = e1000_proc_info_read;
+	info_entry->data = proc_list_head;
+}
+
+static void
+e1000_proc_list_add(struct list_head *proc_list_head, char *tag,
+                    void *data, size_t len, 
+		    char *(*func)(void *, size_t, char *))
+{
+	struct proc_list *new = (struct proc_list *)
+		kmalloc(sizeof(struct proc_list), GFP_KERNEL);
+
+	if(!new)
+		return;
+
+	strncpy(new->tag, tag, TAG_MAX_LENGTH);
+	new->data = data;
+	new->len  = len;
+	new->func = func;
+
+	list_add_tail(&new->list, proc_list_head);
+}
+
+static void
+e1000_proc_list_free(struct list_head *proc_list_head)
+{
+	struct proc_list *elem;
+
+	while(!list_empty(proc_list_head)) {
+		elem = list_entry(proc_list_head->next, struct proc_list, list);
+		list_del(&elem->list);
+		kfree(elem);
+	}
+}
+
+/*
+ * General purpose formating functions
+ */
+
+static char *
+e1000_proc_str(void *data, size_t len, char *buf)
+{
+	sprintf(buf, "%s", (char *)data);
+	return buf;
+}
+
+static char *
+e1000_proc_hex(void *data, size_t len, char *buf)
+{
+	switch(len) {
+	case sizeof(uint8_t):
+		sprintf(buf, "0x%02x", *(uint8_t *)data);
+		break;
+	case sizeof(uint16_t):
+		sprintf(buf, "0x%04x", *(uint16_t *)data);
+		break;
+	case sizeof(uint32_t):
+		sprintf(buf, "0x%08x", *(uint32_t *)data);
+		break;
+	case sizeof(uint64_t):
+		sprintf(buf, "0x%08Lx", (unsigned long long)*(uint64_t *)data);
+		break;
+	}
+	return buf;
+}
+
+static char *
+e1000_proc_unsigned(void *data, size_t len, char *buf)
+{
+	switch(len) {
+	case sizeof(uint8_t):
+		sprintf(buf, "%u", *(uint8_t *)data);
+		break;
+	case sizeof(uint16_t):
+		sprintf(buf, "%u", *(uint16_t *)data);
+		break;
+	case sizeof(uint32_t):
+		sprintf(buf, "%u", *(uint32_t *)data);
+		break;
+	case sizeof(uint64_t):
+		sprintf(buf, "%Lu", (unsigned long long)*(uint64_t *)data);
+		break;
+	}
+	return buf;
+}
+
+/*
+ * Specific formating functions
+ */
+
+static char *
+e1000_proc_part_number(void *data, size_t len, char *buf)
+{
+	sprintf(buf, "%06x-%03x", *(uint32_t *)data >> 8,
+	        *(uint32_t *)data & 0x000000FF);
+	return buf;
+}
+
+static char *
+e1000_proc_slot(void *data, size_t len, char *buf)
+{
+	struct e1000_adapter *adapter = data;
+	sprintf(buf, "%u", PCI_SLOT(adapter->pdev->devfn));
+	return buf;
+}
+
+static char *
+e1000_proc_bus_type(void *data, size_t len, char *buf)
+{
+	e1000_bus_type bus_type = *(e1000_bus_type *)data;
+	sprintf(buf,
+		bus_type == e1000_bus_type_pci  ? "PCI"   :
+		bus_type == e1000_bus_type_pcix ? "PCI-X" :
+		"UNKNOWN");
+	return buf;
+}
+
+static char *
+e1000_proc_bus_speed(void *data, size_t len, char *buf)
+{
+	e1000_bus_speed bus_speed = *(e1000_bus_speed *)data;
+	sprintf(buf,
+		bus_speed == e1000_bus_speed_33  ? "33MHz"  :
+		bus_speed == e1000_bus_speed_66  ? "66MHz"  :
+		bus_speed == e1000_bus_speed_100 ? "100MHz" :
+		bus_speed == e1000_bus_speed_133 ? "133MHz" :
+		"UNKNOWN");
+	return buf;
+}
+
+static char *
+e1000_proc_bus_width(void *data, size_t len, char *buf)
+{
+	e1000_bus_width bus_width = *(e1000_bus_width *)data;
+	sprintf(buf,
+		bus_width == e1000_bus_width_32 ? "32-bit"   :
+		bus_width == e1000_bus_width_64 ? "64-bit" :
+		"UNKNOWN");
+	return buf;
+}
+
+static char *
+e1000_proc_hwaddr(void *data, size_t len, char *buf)
+{
+	unsigned char *hwaddr = data;
+	sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
+		hwaddr[0], hwaddr[1], hwaddr[2],
+		hwaddr[3], hwaddr[4], hwaddr[5]);
+	return buf;
+}
+
+static char *
+e1000_proc_link(void *data, size_t len, char *buf)
+{
+	struct e1000_adapter *adapter = data;
+	sprintf(buf, netif_running(adapter->netdev) ?
+		netif_carrier_ok(adapter->netdev) ?
+		"up" : "down" : "N/A");
+	return buf;
+}
+
+static char *
+e1000_proc_link_speed(void *data, size_t len, char *buf)
+{
+	uint16_t link_speed = *(uint16_t *)data;
+	sprintf(buf, link_speed ? "%u" : "N/A", link_speed);
+	return buf;
+}
+
+static char *
+e1000_proc_link_duplex(void *data, size_t len, char *buf)
+{
+	uint16_t link_duplex = *(uint16_t *)data;
+	sprintf(buf,
+		link_duplex == FULL_DUPLEX ? "Full" :
+		link_duplex == HALF_DUPLEX ? "Half" :
+		"N/A");
+	return buf;
+}
+
+static char *
+e1000_proc_state(void *data, size_t len, char *buf)
+{
+	struct e1000_adapter *adapter = data;
+	sprintf(buf, adapter->netdev->flags & IFF_UP ? "up" : "down");
+	return buf;
+}
+
+static char *
+e1000_proc_media_type(void *data, size_t len, char *buf)
+{
+	struct e1000_adapter *adapter = data;
+	sprintf(buf,
+		adapter->hw.media_type == e1000_media_type_copper ?
+		"Copper" : "Fiber");
+	return buf;
+}
+
+static char *
+e1000_proc_cable_length(void *data, size_t len, char *buf)
+{
+	struct e1000_adapter *adapter = data;
+	e1000_cable_length cable_length = adapter->phy_info.cable_length;
+	sprintf(buf, "%s%s",
+		cable_length == e1000_cable_length_50      ? "0-50"    :
+		cable_length == e1000_cable_length_50_80   ? "50-80"   :
+		cable_length == e1000_cable_length_80_110  ? "80-110"  :
+		cable_length == e1000_cable_length_110_140 ? "110-140" :
+		cable_length == e1000_cable_length_140     ? "> 140"   :
+		"Unknown",
+		cable_length != e1000_cable_length_undefined ?
+		" Meters (+/- 20 Meters)" : "");
+	return buf;
+}
+
+static char *
+e1000_proc_extended(void *data, size_t len, char *buf)
+{
+	struct e1000_adapter *adapter = data;
+	e1000_10bt_ext_dist_enable dist_enable =
+		adapter->phy_info.extended_10bt_distance;
+	sprintf(buf,
+		dist_enable == e1000_10bt_ext_dist_enable_normal ? "Disabled" :
+		dist_enable == e1000_10bt_ext_dist_enable_lower  ? "Enabled"  :
+		"Unknown");
+	return buf;
+}
+
+static char *
+e1000_proc_cable_polarity(void *data, size_t len, char *buf)
+{
+	struct e1000_adapter *adapter = data;
+	e1000_rev_polarity polarity = adapter->phy_info.cable_polarity;
+	sprintf(buf,
+		polarity == e1000_rev_polarity_normal   ? "Normal"   :
+		polarity == e1000_rev_polarity_reversed ? "Reversed" :
+		"Unknown");
+	return buf;
+}
+
+static char *
+e1000_proc_polarity_correction(void *data, size_t len, char *buf)
+{
+	struct e1000_adapter *adapter = data;
+	e1000_polarity_reversal correction =
+		adapter->phy_info.polarity_correction;
+	sprintf(buf,
+		correction == e1000_polarity_reversal_enabled  ? "Disabled" :
+		correction == e1000_polarity_reversal_disabled ? "Enabled"  :
+		"Unknown");
+	return buf;
+}
+
+static char *
+e1000_proc_mdi_x_enabled(void *data, size_t len, char *buf)
+{
+	struct e1000_adapter *adapter = data;
+	e1000_auto_x_mode mdix_mode = adapter->phy_info.mdix_mode;
+	sprintf(buf, 
+		mdix_mode == e1000_auto_x_mode_manual_mdi  ? "MDI"   : 
+		mdix_mode == e1000_auto_x_mode_manual_mdix ? "MDI-X" :
+		"Unknown");
+	return buf;
+}
+
+static char *
+e1000_proc_rx_status(void *data, size_t len, char *buf)
+{
+	e1000_1000t_rx_status rx_status = *(e1000_1000t_rx_status *)data;
+	sprintf(buf,
+		rx_status == e1000_1000t_rx_status_not_ok ? "NOT_OK" :
+		rx_status == e1000_1000t_rx_status_ok     ? "OK"     :
+		"Unknown");
+	return buf;
+}
+
+/*
+ * e1000_proc_list_setup - build link list of proc praramters
+ * @adapter: board private structure
+ *
+ * Order matters - ethx.info entries are ordered in the order links 
+ * are added to list.
+ */
+
+#define LIST_ADD_F(T,D,F) \
+	e1000_proc_list_add(proc_list_head, (T), (D), sizeof(*(D)), (F))
+#define LIST_ADD_BLANK() LIST_ADD_F("", NULL, NULL)
+#define LIST_ADD_S(T,D) LIST_ADD_F((T), (D), e1000_proc_str)
+#define LIST_ADD_H(T,D) LIST_ADD_F((T), (D), e1000_proc_hex)
+#define LIST_ADD_U(T,D) LIST_ADD_F((T), (D), e1000_proc_unsigned)
+
+static void
+e1000_proc_list_setup(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct list_head *proc_list_head = &adapter->proc_list_head;
+
+	INIT_LIST_HEAD(proc_list_head);
+
+	LIST_ADD_S("Description", adapter->id_string);
+	LIST_ADD_F("Part_Number", &adapter->part_num, e1000_proc_part_number);
+	LIST_ADD_S("Driver_Name", e1000_driver_name);
+	LIST_ADD_S("Driver_Version", e1000_driver_version);
+	LIST_ADD_H("PCI_Vendor", &hw->vendor_id);
+	LIST_ADD_H("PCI_Device_ID", &hw->device_id);
+	LIST_ADD_H("PCI_Subsystem_Vendor", &hw->subsystem_vendor_id);
+	LIST_ADD_H("PCI_Subsystem_ID", &hw->subsystem_id);
+	LIST_ADD_H("PCI_Revision_ID", &hw->revision_id);
+	LIST_ADD_U("PCI_Bus", &adapter->pdev->bus->number);
+	LIST_ADD_F("PCI_Slot", adapter, e1000_proc_slot);
+
+	if(adapter->hw.mac_type >= e1000_82543) {
+		LIST_ADD_F("PCI_Bus_Type",
+		           &hw->bus_type, e1000_proc_bus_type);
+		LIST_ADD_F("PCI_Bus_Speed",
+		           &hw->bus_speed, e1000_proc_bus_speed);
+		LIST_ADD_F("PCI_Bus_Width",
+		           &hw->bus_width, e1000_proc_bus_width);
+	}
+
+	LIST_ADD_U("IRQ", &adapter->pdev->irq);
+	LIST_ADD_S("System_Device_Name", adapter->ifname);
+	LIST_ADD_F("Current_HWaddr",
+	            adapter->netdev->dev_addr, e1000_proc_hwaddr);
+	LIST_ADD_F("Permanent_HWaddr",
+	            adapter->hw.perm_mac_addr, e1000_proc_hwaddr);
+
+	LIST_ADD_BLANK();
+
+	LIST_ADD_F("Link", adapter, e1000_proc_link);
+	LIST_ADD_F("Speed", &adapter->link_speed, e1000_proc_link_speed);
+	LIST_ADD_F("Duplex", &adapter->link_duplex, e1000_proc_link_duplex);
+	LIST_ADD_F("State", adapter, e1000_proc_state);
+
+	LIST_ADD_BLANK();
+
+	/* Standard net device stats */
+	LIST_ADD_U("Rx_Packets", &adapter->net_stats.rx_packets);
+	LIST_ADD_U("Tx_Packets", &adapter->net_stats.tx_packets);
+	LIST_ADD_U("Rx_Bytes", &adapter->net_stats.rx_bytes);
+	LIST_ADD_U("Tx_Bytes", &adapter->net_stats.tx_bytes);
+	LIST_ADD_U("Rx_Errors", &adapter->net_stats.rx_errors);
+	LIST_ADD_U("Tx_Errors", &adapter->net_stats.tx_errors);
+	LIST_ADD_U("Rx_Dropped", &adapter->net_stats.rx_dropped);
+	LIST_ADD_U("Tx_Dropped", &adapter->net_stats.tx_dropped);
+
+	LIST_ADD_U("Multicast", &adapter->net_stats.multicast);
+	LIST_ADD_U("Collisions", &adapter->net_stats.collisions);
+
+	LIST_ADD_U("Rx_Length_Errors", &adapter->net_stats.rx_length_errors);
+	LIST_ADD_U("Rx_Over_Errors", &adapter->net_stats.rx_over_errors);
+	LIST_ADD_U("Rx_CRC_Errors", &adapter->net_stats.rx_crc_errors);
+	LIST_ADD_U("Rx_Frame_Errors", &adapter->net_stats.rx_frame_errors);
+	LIST_ADD_U("Rx_FIFO_Errors", &adapter->net_stats.rx_fifo_errors);
+	LIST_ADD_U("Rx_Missed_Errors", &adapter->net_stats.rx_missed_errors);
+
+	LIST_ADD_U("Tx_Aborted_Errors", &adapter->net_stats.tx_aborted_errors);
+	LIST_ADD_U("Tx_Carrier_Errors", &adapter->net_stats.tx_carrier_errors);
+	LIST_ADD_U("Tx_FIFO_Errors", &adapter->net_stats.tx_fifo_errors);
+	LIST_ADD_U("Tx_Heartbeat_Errors", 
+	           &adapter->net_stats.tx_heartbeat_errors);
+	LIST_ADD_U("Tx_Window_Errors", &adapter->net_stats.tx_window_errors);
+
+	/* 8254x-specific stats */
+	LIST_ADD_U("Tx_Abort_Late_Coll", &adapter->stats.latecol);
+	LIST_ADD_U("Tx_Deferred_Ok", &adapter->stats.dc);
+	LIST_ADD_U("Tx_Single_Coll_Ok", &adapter->stats.scc);
+	LIST_ADD_U("Tx_Multi_Coll_Ok", &adapter->stats.mcc);
+	LIST_ADD_U("Rx_Long_Length_Errors", &adapter->stats.roc);
+	LIST_ADD_U("Rx_Short_Length_Errors", &adapter->stats.ruc);
+
+	/* The 82542 does not have an alignment error count register */
+	if(adapter->hw.mac_type >= e1000_82543)
+		LIST_ADD_U("Rx_Align_Errors", &adapter->stats.algnerrc);
+
+	LIST_ADD_U("Rx_Flow_Control_XON", &adapter->stats.xonrxc);
+	LIST_ADD_U("Rx_Flow_Control_XOFF", &adapter->stats.xoffrxc);
+	LIST_ADD_U("Tx_Flow_Control_XON", &adapter->stats.xontxc);
+	LIST_ADD_U("Tx_Flow_Control_XOFF", &adapter->stats.xofftxc);
+	LIST_ADD_U("Rx_CSum_Offload_Good", &adapter->hw_csum_good);
+	LIST_ADD_U("Rx_CSum_Offload_Errors", &adapter->hw_csum_err);
+
+	LIST_ADD_BLANK();
+
+	/* Cable diags */
+	LIST_ADD_F("PHY_Media_Type", adapter, e1000_proc_media_type);
+	if(adapter->hw.media_type == e1000_media_type_copper) {
+		LIST_ADD_F("PHY_Cable_Length",
+		           adapter, e1000_proc_cable_length);
+		LIST_ADD_F("PHY_Extended_10Base_T_Distance",
+		           adapter, e1000_proc_extended);
+		LIST_ADD_F("PHY_Cable_Polarity",
+		           adapter, e1000_proc_cable_polarity);
+		LIST_ADD_F("PHY_Disable_Polarity_Correction",
+		           adapter, e1000_proc_polarity_correction);
+		LIST_ADD_U("PHY_Idle_Errors", 
+		           &adapter->phy_stats.idle_errors);
+		LIST_ADD_U("PHY_Receive_Errors",
+		           &adapter->phy_stats.receive_errors);
+		LIST_ADD_F("PHY_MDI_X_Enabled",
+		           adapter, e1000_proc_mdi_x_enabled);
+		LIST_ADD_F("PHY_Local_Receiver_Status",
+		           &adapter->phy_info.local_rx, 
+			   e1000_proc_rx_status);
+		LIST_ADD_F("PHY_Remote_Receiver_Status",
+		           &adapter->phy_info.remote_rx, 
+			   e1000_proc_rx_status);
+	}
+
+}
+
+/*
+ * e1000_proc_dev_setup - create proc fs nodes and link list
+ * @adapter: board private structure
+ */
+
+void
+e1000_proc_dev_setup(struct e1000_adapter *adapter)
+{
+	e1000_proc_list_setup(adapter);
+
+	e1000_proc_dirs_create(adapter, 
+	                       adapter->ifname,
+	                       &adapter->proc_list_head);
+}
+
+/*
+ * e1000_proc_dev_free - free proc fs nodes and link list
+ * @adapter: board private structure
+ */
+
+void
+e1000_proc_dev_free(struct e1000_adapter *adapter)
+{
+	e1000_proc_dirs_free(adapter->ifname, &adapter->proc_list_head);
+
+	e1000_proc_list_free(&adapter->proc_list_head);
+}
+
+#else /* CONFIG_PROC_FS */
+
+void e1000_proc_dev_setup(struct e1000_adapter *adapter) {}
+void e1000_proc_dev_free(struct e1000_adapter *adapter) {}
+
+#endif /* CONFIG_PROC_FS */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/e2100.c linux-2.4.20/drivers/net/e2100.c
--- linux-2.4.19/drivers/net/e2100.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/e2100.c	2002-10-29 11:18:50.000000000 +0000
@@ -72,7 +72,7 @@
 #define E21_SAPROM		0x10	/* Offset to station address data. */
 #define E21_IO_EXTENT	 0x20
 
-extern inline void mem_on(short port, volatile char *mem_base,
+static inline void mem_on(short port, volatile char *mem_base,
 						  unsigned char start_page )
 {
 	/* This is a little weird: set the shared memory window by doing a
@@ -82,7 +82,7 @@
 	outb(E21_MEM_ON, port + E21_MEM_ENABLE + E21_MEM_ON);
 }
 
-extern inline void mem_off(short port)
+static inline void mem_off(short port)
 {
 	inb(port + E21_MEM_ENABLE);
 	outb(0x00, port + E21_MEM_ENABLE);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/eepro.c linux-2.4.20/drivers/net/eepro.c
--- linux-2.4.19/drivers/net/eepro.c	2001-11-19 23:19:42.000000000 +0000
+++ linux-2.4.20/drivers/net/eepro.c	2002-10-29 11:18:49.000000000 +0000
@@ -23,6 +23,8 @@
 	This is a compatibility hardware problem.
 
 	Versions:
+	0.13a   in memory shortage, drop packets also in board
+		(Michael Westermann <mw@microdata-pos.de>, 07/30/2002)
 	0.13    irq sharing, rewrote probe function, fixed a nasty bug in
 		hardware_send_packet and a major cleanup (aris, 11/08/2001)
 	0.12d	fixing a problem with single card detected as eight eth devices
@@ -665,37 +667,37 @@
 
 	i = inb(dev->base_addr + ID_REG);
 	printk(KERN_DEBUG " id: %#x ",i);
-	printk(KERN_DEBUG " io: %#x ", (unsigned)dev->base_addr);
+	printk(" io: %#x ", (unsigned)dev->base_addr);
 
 	switch (lp->eepro) {
 		case LAN595FX_10ISA:
-			printk(KERN_INFO "%s: Intel EtherExpress 10 ISA\n at %#x,",
+			printk("%s: Intel EtherExpress 10 ISA\n at %#x,",
 					dev->name, (unsigned)dev->base_addr);
 			break;
 		case LAN595FX:
-			printk(KERN_INFO "%s: Intel EtherExpress Pro/10+ ISA\n at %#x,", 
+			printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,", 
 					dev->name, (unsigned)dev->base_addr);
 			break;
 		case LAN595TX:
-			printk(KERN_INFO "%s: Intel EtherExpress Pro/10 ISA at %#x,",
+			printk("%s: Intel EtherExpress Pro/10 ISA at %#x,",
 					dev->name, (unsigned)dev->base_addr);
 			break;
 		case LAN595:
-			printk(KERN_INFO "%s: Intel 82595-based lan card at %#x,", 
+			printk("%s: Intel 82595-based lan card at %#x,", 
 					dev->name, (unsigned)dev->base_addr);
 	}
 
 	for (i=0; i < 6; i++)
-		printk(KERN_INFO "%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
+		printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
 
 	if (net_debug > 3)
 		printk(KERN_DEBUG ", %dK RCV buffer",
 				(int)(lp->rcv_ram)/1024);
 
 	if (dev->irq > 2)
-		printk(KERN_INFO ", IRQ %d, %s.\n", dev->irq, ifmap[dev->if_port]);
+		printk(", IRQ %d, %s.\n", dev->irq, ifmap[dev->if_port]);
 	else 
-		printk(KERN_INFO ", %s.\n", ifmap[dev->if_port]);
+		printk(", %s.\n", ifmap[dev->if_port]);
 
 	if (net_debug > 3) {
 		i = read_eeprom(dev->base_addr, 5, dev);
@@ -730,27 +732,27 @@
 		goto exit;
 	}
 
-		/* We seem to have the 82595 signature, let's
-		   play with its counter (last 2 bits of
-		   register 2 of bank 0) to be sure. */
+	/* We seem to have the 82595 signature, let's
+	   play with its counter (last 2 bits of
+	   register 2 of bank 0) to be sure. */
 
-		counter = (id & R_ROBIN_BITS);
+	counter = (id & R_ROBIN_BITS);
 
 	if (((id=inb(ioaddr+ID_REG)) & R_ROBIN_BITS)!=(counter + 0x40)) {
 		retval = -ENODEV;
 		goto exit;
 	}
 
-			/* Initialize the device structure */
-			dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL);
+	/* Initialize the device structure */
+	dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL);
 	if (!dev->priv) {
 		retval = -ENOMEM;
 		goto exit;
 	}
 
-			memset(dev->priv, 0, sizeof(struct eepro_local));
+	memset(dev->priv, 0, sizeof(struct eepro_local));
 
-			lp = (struct eepro_local *)dev->priv;
+	lp = (struct eepro_local *)dev->priv;
 
 	/* default values */
 	lp->eepro = 0;
@@ -759,37 +761,37 @@
 	lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO;
 	lp->eeprom_reg = EEPROM_REG_PRO;
 
-			/* Now, get the ethernet hardware address from
-			   the EEPROM */
-			station_addr[0] = read_eeprom(ioaddr, 2, dev);
-
-			/* FIXME - find another way to know that we've found
-			 * an Etherexpress 10
-			 */
-			if (station_addr[0] == 0x0000 ||
-			    station_addr[0] == 0xffff) {
-				lp->eepro = LAN595FX_10ISA;
+	/* Now, get the ethernet hardware address from
+	   the EEPROM */
+	station_addr[0] = read_eeprom(ioaddr, 2, dev);
+
+	/* FIXME - find another way to know that we've found
+	 * an Etherexpress 10
+	 */
+	if (station_addr[0] == 0x0000 ||
+	    station_addr[0] == 0xffff) {
+		lp->eepro = LAN595FX_10ISA;
 		lp->eeprom_reg = EEPROM_REG_10;
 		lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10;
 		lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10;
 		lp->xmt_bar = XMT_BAR_10;
 				station_addr[0] = read_eeprom(ioaddr, 2, dev);
-			}
-			station_addr[1] = read_eeprom(ioaddr, 3, dev);
-			station_addr[2] = read_eeprom(ioaddr, 4, dev);
+	}
+	station_addr[1] = read_eeprom(ioaddr, 3, dev);
+	station_addr[2] = read_eeprom(ioaddr, 4, dev);
 
 	if (!lp->eepro) {
 		if (read_eeprom(ioaddr,7,dev)== ee_FX_INT2IRQ)
 			lp->eepro = 2;
 		else if (station_addr[2] == SA_ADDR1)
 			lp->eepro = 1;
-			}
+	}
 
-			/* Fill in the 'dev' fields. */
-			dev->base_addr = ioaddr;
+	/* Fill in the 'dev' fields. */
+	dev->base_addr = ioaddr;
 
 	for (i=0; i < 6; i++)
-				dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
+		dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
 
 	/* RX buffer must be more than 3K and less than 29K */
 	if (dev->mem_end < 3072 || dev->mem_end > 29696)
@@ -798,57 +800,58 @@
 	/* calculate {xmt,rcv}_{lower,upper}_limit */
 	eepro_recalc(dev);
 
-
-			if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE))
-				dev->if_port = BNC;
+	if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE))
+		dev->if_port = BNC;
 	else
 		dev->if_port = TPE;
 
 	if ((dev->irq < 2) && (lp->eepro!=0)) {
-				i = read_eeprom(ioaddr, 1, dev);
-				irqMask = read_eeprom(ioaddr, 7, dev);
-				i &= 0x07; /* Mask off INT number */
-
-				for (j=0; ((j<16) && (i>=0)); j++) {
-					if ((irqMask & (1<<j))!=0) {
-						if (i==0) {
-							dev->irq = j;
-							break; /* found bit corresponding to irq */
-						}
-						i--; /* count bits set in irqMask */
-					}
+		i = read_eeprom(ioaddr, 1, dev);
+		irqMask = read_eeprom(ioaddr, 7, dev);
+		i &= 0x07; /* Mask off INT number */
+
+		for (j=0; ((j<16) && (i>=0)); j++) {
+			if ((irqMask & (1<<j))!=0) {
+				if (i==0) {
+					dev->irq = j;
+					break; /* found bit corresponding to irq */
 				}
-				if (dev->irq < 2) {
+				i--; /* count bits set in irqMask */
+			}
+		}
+		if (dev->irq < 2) {
 			printk(KERN_ERR " Duh! illegal interrupt vector stored in EEPROM.\n");
-					kfree(dev->priv);
+			kfree(dev->priv);
 			retval = -ENODEV;
 			goto freeall;
-				} else
-			if (dev->irq==2) dev->irq = 9;
-			}
-
-			/* Grab the region so we can find another board if autoIRQ fails. */
-			request_region(ioaddr, EEPRO_IO_EXTENT, dev->name);
-
-			((struct eepro_local *)dev->priv)->lock = SPIN_LOCK_UNLOCKED;
+		} 
+		else if (dev->irq==2) dev->irq = 9;
+	}
 
-			dev->open               = eepro_open;
-			dev->stop               = eepro_close;
-			dev->hard_start_xmit    = eepro_send_packet;
-			dev->get_stats          = eepro_get_stats;
-			dev->set_multicast_list = &set_multicast_list;
-			dev->tx_timeout		= eepro_tx_timeout;
-			dev->watchdog_timeo	= TX_TIMEOUT;
-
-			/* Fill in the fields of the device structure with
-			   ethernet generic values */
-			ether_setup(dev);
+	/* Grab the region so we can find another board if autoIRQ fails. */
+	if (!request_region(ioaddr, EEPRO_IO_EXTENT, dev->name)) { 
+		printk(KERN_WARNING "EEPRO: io-port 0x%04x in use \n", ioaddr);
+		goto freeall;
+	}
+	((struct eepro_local *)dev->priv)->lock = SPIN_LOCK_UNLOCKED;
+
+	dev->open               = eepro_open;
+	dev->stop               = eepro_close;
+	dev->hard_start_xmit    = eepro_send_packet;
+	dev->get_stats          = eepro_get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+	dev->tx_timeout		= eepro_tx_timeout;
+	dev->watchdog_timeo	= TX_TIMEOUT;
+
+	/* Fill in the fields of the device structure with
+	ethernet generic values */
+	ether_setup(dev);
 
 	/* print boot time info */
 	eepro_print_info(dev);
 
 	/* reset 82595 */
-			eepro_reset(ioaddr);
+	eepro_reset(ioaddr);
 
 exit:
 	return retval;
@@ -1578,6 +1581,10 @@
 			if (skb == NULL) {
 				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
 				lp->stats.rx_dropped++;
+				rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
+				lp->rx_start = rcv_next_frame;
+				outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
+
 				break;
 			}
 			skb->dev = dev;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/eepro100.c linux-2.4.20/drivers/net/eepro100.c
--- linux-2.4.19/drivers/net/eepro100.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/eepro100.c	2002-10-29 11:18:49.000000000 +0000
@@ -1,7 +1,5 @@
 /* drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux. */
 /*
-   NOTICE: For use with late 2.3 kernels only.
-   May not compile for kernels 2.3.43-47.
 	Written 1996-1999 by Donald Becker.
 
 	The driver also contains updates by different kernel developers
@@ -25,6 +23,8 @@
 		Disabled FC and ER, to avoid lockups when when we get FCP interrupts.
 	2000 Jul 17 Goutham Rao <goutham.rao@intel.com>
 		PCI DMA API fixes, adding pci_dma_sync_single calls where neccesary
+	2000 Aug 31 David Mosberger <davidm@hpl.hp.com>
+		rx_align support: enables rx DMA without causing unaligned accesses.
 */
 
 static const char *version =
@@ -41,14 +41,19 @@
 static int txdmacount = 128;
 static int rxdmacount /* = 0 */;
 
+#if defined(__ia64__) || defined(__alpha__) || defined(__sparc__) || defined(__mips__) || \
+	defined(__arm__)
+  /* align rx buffers to 2 bytes so that IP header is aligned */
+# define rx_align(skb)		skb_reserve((skb), 2)
+# define RxFD_ALIGNMENT		__attribute__ ((aligned (2), packed))
+#else
+# define rx_align(skb)
+# define RxFD_ALIGNMENT
+#endif
+
 /* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
    Lower values use more memory, but are faster. */
-#if defined(__alpha__) || defined(__sparc__) || defined(__mips__) || \
-    defined(__arm__)
-static int rx_copybreak = 1518;
-#else
 static int rx_copybreak = 200;
-#endif
 
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 20;
@@ -60,7 +65,6 @@
    e.g. "options=16" for FD, "options=32" for 100mbps-only. */
 static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
 static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int debug = -1;			/* The debug level */
 
 /* A few values that may be tweaked. */
 /* The ring sizes should be a power of two for efficiency. */
@@ -114,6 +118,15 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
+#include <linux/mii.h>
+
+static int debug = -1;
+#define DEBUG_DEFAULT		(NETIF_MSG_DRV		| \
+				 NETIF_MSG_HW		| \
+				 NETIF_MSG_RX_ERR	| \
+				 NETIF_MSG_TX_ERR)
+#define DEBUG			((debug >= 0) ? (1<<debug)-1 : DEBUG_DEFAULT)
+
 
 MODULE_AUTHOR("Maintainer: Andrey V. Savochkin <saw@saw.sw.com.sg>");
 MODULE_DESCRIPTION("Intel i82557/i82558/i82559 PCI EtherExpressPro driver");
@@ -162,7 +175,6 @@
 								} while(0)
 
 
-static int speedo_debug = 1;
 
 /*
 				Theory of Operation
@@ -311,23 +323,11 @@
 #define outl writel
 #endif
 
-/* How to wait for the command unit to accept a command.
-   Typically this takes 0 ticks. */
-static inline void wait_for_cmd_done(long cmd_ioaddr)
-{
-	int wait = 1000;
-	do  udelay(1) ;
-	while(inb(cmd_ioaddr) && --wait >= 0);
-#ifndef final_version
-	if (wait < 0)
-		printk(KERN_ALERT "eepro100: wait_for_cmd_done timeout!\n");
-#endif
-}
-
 /* Offsets to the various registers.
    All accesses need not be longword aligned. */
 enum speedo_offsets {
 	SCBStatus = 0, SCBCmd = 2,	/* Rx/Command Unit command and status. */
+	SCBIntmask = 3,
 	SCBPointer = 4,				/* General purpose pointer. */
 	SCBPort = 8,				/* Misc. commands and operands.  */
 	SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */
@@ -377,18 +377,18 @@
 
 /* The Speedo3 Rx and Tx frame/buffer descriptors. */
 struct descriptor {			    /* A generic descriptor. */
-	s32 cmd_status;				/* All command and status fields. */
+	volatile s32 cmd_status;	/* All command and status fields. */
 	u32 link;				    /* struct descriptor *  */
 	unsigned char params[0];
 };
 
 /* The Speedo3 Rx and Tx buffer descriptors. */
 struct RxFD {					/* Receive frame descriptor. */
-	s32 status;
+	volatile s32 status;
 	u32 link;					/* struct RxFD * */
 	u32 rx_buf_addr;			/* void * */
 	u32 count;
-};
+} RxFD_ALIGNMENT;
 
 /* Selected elements of the Tx/RxFD.status word. */
 enum RxFD_bits {
@@ -454,8 +454,8 @@
    Unfortunately, all the positions have been shifted since there.
    A new re-alignment is required.  2000/03/06  SAW */
 struct speedo_private {
-	struct TxFD	*tx_ring;				/* Commands (usually CmdTxPacket). */
-	struct RxFD *rx_ringp[RX_RING_SIZE];/* Rx descriptor, used as ring. */
+	struct TxFD	*tx_ring;		/* Commands (usually CmdTxPacket). */
+	struct RxFD *rx_ringp[RX_RING_SIZE];	/* Rx descriptor, used as ring. */
 	/* The addresses of a Tx/Rx-in-place packets/buffers. */
 	struct sk_buff *tx_skbuff[TX_RING_SIZE];
 	struct sk_buff *rx_skbuff[RX_RING_SIZE];
@@ -465,9 +465,9 @@
 	dma_addr_t rx_ring_dma[RX_RING_SIZE];
 	struct descriptor *last_cmd;		/* Last command sent. */
 	unsigned int cur_tx, dirty_tx;		/* The ring entries to be free()ed. */
-	spinlock_t lock;					/* Group with Tx control cache line. */
-	u32 tx_threshold;					/* The value for txdesc.count. */
-	struct RxFD *last_rxf;				/* Last filled RX buffer. */
+	spinlock_t lock;			/* Group with Tx control cache line. */
+	u32 tx_threshold;			/* The value for txdesc.count. */
+	struct RxFD *last_rxf;			/* Last filled RX buffer. */
 	dma_addr_t last_rxf_dma;
 	unsigned int cur_rx, dirty_rx;		/* The next free ring entry */
 	long last_rx_time;			/* Last Rx, in jiffies, to handle Rx hang. */
@@ -476,21 +476,21 @@
 	dma_addr_t lstats_dma;
 	int chip_id;
 	struct pci_dev *pdev;
-	struct timer_list timer;			/* Media selection timer. */
-	struct speedo_mc_block *mc_setup_head;/* Multicast setup frame list head. */
-	struct speedo_mc_block *mc_setup_tail;/* Multicast setup frame list tail. */
-	long in_interrupt;					/* Word-aligned dev->interrupt */
+	struct timer_list timer;		/* Media selection timer. */
+	struct speedo_mc_block *mc_setup_head;	/* Multicast setup frame list head. */
+	struct speedo_mc_block *mc_setup_tail;	/* Multicast setup frame list tail. */
+	long in_interrupt;			/* Word-aligned dev->interrupt */
 	unsigned char acpi_pwr;
-	signed char rx_mode;					/* Current PROMISC/ALLMULTI setting. */
-	unsigned int tx_full:1;				/* The Tx queue is full. */
-	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
-	unsigned int flow_ctrl:1;			/* Use 802.3x flow control. */
-	unsigned int rx_bug:1;				/* Work around receiver hang errata. */
+	signed char rx_mode;			/* Current PROMISC/ALLMULTI setting. */
+	unsigned int tx_full:1;			/* The Tx queue is full. */
+	unsigned int flow_ctrl:1;		/* Use 802.3x flow control. */
+	unsigned int rx_bug:1;			/* Work around receiver hang errata. */
 	unsigned char default_port:8;		/* Last dev->if_port value. */
 	unsigned char rx_ring_state;		/* RX ring status flags. */
-	unsigned short phy[2];				/* PHY media interfaces available. */
-	unsigned short advertising;			/* Current PHY advertised caps. */
-	unsigned short partner;				/* Link partner caps. */
+	unsigned short phy[2];			/* PHY media interfaces available. */
+	unsigned short partner;			/* Link partner caps. */
+	struct mii_if_info mii_if;		/* MII API hooks, info */
+	u32 msg_enable;				/* debug message level */
 #ifdef CONFIG_PM
 	u32 pm_state[16];
 #endif
@@ -524,12 +524,10 @@
 static int eepro100_init_one(struct pci_dev *pdev,
 		const struct pci_device_id *ent);
 static void eepro100_remove_one (struct pci_dev *pdev);
-static int eepro100_suspend (struct pci_dev *pdev, u32 state);
-static int eepro100_resume (struct pci_dev *pdev);
 
 static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len);
-static int mdio_read(long ioaddr, int phy_id, int location);
-static int mdio_write(long ioaddr, int phy_id, int location, int value);
+static int mdio_read(struct net_device *dev, int phy_id, int location);
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
 static int speedo_open(struct net_device *dev);
 static void speedo_resume(struct net_device *dev);
 static void speedo_timer(unsigned long data);
@@ -555,6 +553,24 @@
 						   0x2000, 0x2100, 0x0400, 0x3100};
 #endif
 
+/* How to wait for the command unit to accept a command.
+   Typically this takes 0 ticks. */
+static inline unsigned char wait_for_cmd_done(struct net_device *dev)
+{
+	int wait = 1000;
+	long cmd_ioaddr = dev->base_addr + SCBCmd;
+	unsigned char r;
+
+	do  {
+		udelay(1);
+		r = inb(cmd_ioaddr);
+	} while(r && --wait >= 0);
+
+	if (wait < 0)
+		printk(KERN_ALERT "%s: wait_for_cmd_done timeout!\n", dev->name);
+	return r;
+}
+
 static int __devinit eepro100_init_one (struct pci_dev *pdev,
 		const struct pci_device_id *ent)
 {
@@ -563,9 +579,12 @@
 	int acpi_idle_state = 0, pm;
 	static int cards_found /* = 0 */;
 
-	static int did_version /* = 0 */;		/* Already printed version info. */
-	if (speedo_debug > 0  &&  did_version++ == 0)
+#ifndef MODULE
+	/* when built-in, we only print version if device is found */
+	static int did_version;
+	if (did_version++ == 0)
 		printk(version);
+#endif
 
 	/* save power state before pci_enable_device overwrites it */
 	pm = pci_find_capability(pdev, PCI_CAP_ID_PM);
@@ -594,7 +613,7 @@
 	irq = pdev->irq;
 #ifdef USE_IO
 	ioaddr = pci_resource_start(pdev, 1);
-	if (speedo_debug > 2)
+	if (DEBUG & NETIF_MSG_PROBE)
 		printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
 			   ioaddr, irq);
 #else
@@ -605,7 +624,7 @@
 				pci_resource_len(pdev, 0), pci_resource_start(pdev, 0));
 		goto err_out_free_mmio_region;
 	}
-	if (speedo_debug > 2)
+	if (DEBUG & NETIF_MSG_PROBE)
 		printk("Found Intel i82557 PCI Speedo, MMIO at %#lx, IRQ %d.\n",
 			   pci_resource_start(pdev, 0), irq);
 #endif
@@ -654,6 +673,8 @@
 		return -1;
 	}
 
+	SET_MODULE_OWNER(dev);
+
 	if (dev->mem_start > 0)
 		option = dev->mem_start;
 	else if (card_idx >= 0  &&  options[card_idx] >= 0)
@@ -724,6 +745,9 @@
 #endif
 	printk("IRQ %d.\n", pdev->irq);
 
+	/* we must initialize base_addr early, for mdio_{read,write} */
+	dev->base_addr = ioaddr;
+
 #if 1 || defined(kernel_bloat)
 	/* OK, this is pure kernel bloat.  I don't like it when other drivers
 	   waste non-pageable kernel space to emit similar messages, but I need
@@ -749,18 +773,18 @@
 				   phys[(eeprom[7]>>8)&7]);
 		if (((eeprom[6]>>8) & 0x3f) == DP83840
 			||  ((eeprom[6]>>8) & 0x3f) == DP83840A) {
-			int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422;
+			int mdi_reg23 = mdio_read(dev, eeprom[6] & 0x1f, 23) | 0x0422;
 			if (congenb)
 			  mdi_reg23 |= 0x0100;
 			printk(KERN_INFO"  DP83840 specific setup, setting register 23 to %4.4x.\n",
 				   mdi_reg23);
-			mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23);
+			mdio_write(dev, eeprom[6] & 0x1f, 23, mdi_reg23);
 		}
 		if ((option >= 0) && (option & 0x70)) {
 			printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",
 				   (option & 0x20 ? 100 : 10),
 				   (option & 0x10 ? "full" : "half"));
-			mdio_write(ioaddr, eeprom[6] & 0x1f, 0,
+			mdio_write(dev, eeprom[6] & 0x1f, MII_BMCR,
 					   ((option & 0x20) ? 0x2000 : 0) | 	/* 100mbps? */
 					   ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
 		}
@@ -802,11 +826,11 @@
 
 	pci_set_drvdata (pdev, dev);
 
-	dev->base_addr = ioaddr;
 	dev->irq = pdev->irq;
 
 	sp = dev->priv;
 	sp->pdev = pdev;
+	sp->msg_enable = DEBUG;
 	sp->acpi_pwr = acpi_idle_state;
 	sp->tx_ring = tx_ring_space;
 	sp->tx_ring_dma = tx_ring_dma;
@@ -814,15 +838,23 @@
 	sp->lstats_dma = TX_RING_ELEM_DMA(sp, TX_RING_SIZE);
 	init_timer(&sp->timer); /* used in ioctl() */
 
-	sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
+	sp->mii_if.full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
 	if (card_idx >= 0) {
 		if (full_duplex[card_idx] >= 0)
-			sp->full_duplex = full_duplex[card_idx];
+			sp->mii_if.full_duplex = full_duplex[card_idx];
 	}
 	sp->default_port = option >= 0 ? (option & 0x0f) : 0;
 
 	sp->phy[0] = eeprom[6];
 	sp->phy[1] = eeprom[7];
+
+	sp->mii_if.phy_id = eeprom[6] & 0x1f;
+	sp->mii_if.phy_id_mask = 0x1f;
+	sp->mii_if.reg_num_mask = 0x1f;
+	sp->mii_if.dev = dev;
+	sp->mii_if.mdio_read = mdio_read;
+	sp->mii_if.mdio_write = mdio_write;
+	
 	sp->rx_bug = (eeprom[3] & 0x03) == 3 ? 0 : 1;
 	if (((pdev->device > 0x1030 && (pdev->device < 0x103F))) 
 	    || (pdev->device == 0x2449) || (pdev->device == 0x2459) 
@@ -844,7 +876,30 @@
 
 	return 0;
 }
-
+
+static void do_slow_command(struct net_device *dev, int cmd)
+{
+	long cmd_ioaddr = dev->base_addr + SCBCmd;
+	int wait = 0;
+	do
+		if (inb(cmd_ioaddr) == 0) break;
+	while(++wait <= 200);
+	if (wait > 100)
+		printk(KERN_ERR "Command %4.4x never accepted (%d polls)!\n",
+		       inb(cmd_ioaddr), wait);
+
+	outb(cmd, cmd_ioaddr);
+
+	for (wait = 0; wait <= 100; wait++)
+		if (inb(cmd_ioaddr) == 0) return;
+	for (; wait <= 20000; wait++)
+		if (inb(cmd_ioaddr) == 0) return;
+		else udelay(1);
+	printk(KERN_ERR "Command %4.4x was not accepted after %d polls!"
+	       "  Current status %8.8x.\n",
+	       cmd, wait, inl(dev->base_addr + SCBStatus));
+}
+
 /* Serial EEPROM section.
    A "bit" grungy, but we work our way through bit-by-bit :->. */
 /*  EEPROM_Ctrl bits. */
@@ -886,8 +941,9 @@
 	return retval;
 }
 
-static int mdio_read(long ioaddr, int phy_id, int location)
+static int mdio_read(struct net_device *dev, int phy_id, int location)
 {
+	long ioaddr = dev->base_addr;
 	int val, boguscnt = 64*10;		/* <64 usec. to complete, typ 27 ticks */
 	outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI);
 	do {
@@ -900,8 +956,9 @@
 	return val & 0xffff;
 }
 
-static int mdio_write(long ioaddr, int phy_id, int location, int value)
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
 {
+	long ioaddr = dev->base_addr;
 	int val, boguscnt = 64*10;		/* <64 usec. to complete, typ 27 ticks */
 	outl(0x04000000 | (location<<16) | (phy_id<<21) | value,
 		 ioaddr + SCBCtrlMDI);
@@ -912,10 +969,8 @@
 			break;
 		}
 	} while (! (val & 0x10000000));
-	return val & 0xffff;
 }
 
-
 static int
 speedo_open(struct net_device *dev)
 {
@@ -923,11 +978,9 @@
 	long ioaddr = dev->base_addr;
 	int retval;
 
-	if (speedo_debug > 1)
+	if (netif_msg_ifup(sp))
 		printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
 
-	MOD_INC_USE_COUNT;
-
 	pci_set_power_state(sp->pdev, 0);
 
 	/* Set up the Tx queue early.. */
@@ -941,7 +994,6 @@
 	/* .. we can safely take handler calls during init. */
 	retval = request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev);
 	if (retval) {
-		MOD_DEC_USE_COUNT;
 		return retval;
 	}
 
@@ -958,9 +1010,9 @@
 		   0x2100 100-FD
 		*/
 #ifdef honor_default_port
-		mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
+		mdio_write(dev, phy_addr, MII_BMCR, mii_ctrl[dev->default_port & 7]);
 #else
-		mdio_write(ioaddr, phy_addr, 0, 0x3300);
+		mdio_write(dev, phy_addr, MII_BMCR, 0x3300);
 #endif
 	}
 #endif
@@ -981,14 +1033,11 @@
 	sp->rx_mode = -1;			/* Invalid -> always reset the mode. */
 	set_rx_mode(dev);
 	if ((sp->phy[0] & 0x8000) == 0)
-		sp->advertising = mdio_read(ioaddr, sp->phy[0] & 0x1f, 4);
+		sp->mii_if.advertising = mdio_read(dev, sp->phy[0] & 0x1f, MII_ADVERTISE);
 
-	if (mdio_read(ioaddr, sp->phy[0] & 0x1f, MII_BMSR) & BMSR_LSTATUS)
-		netif_carrier_on(dev);
-	else
-		netif_carrier_off(dev);
+	mii_check_link(&sp->mii_if);
 
-	if (speedo_debug > 2) {
+	if (netif_msg_ifup(sp)) {
 		printk(KERN_DEBUG "%s: Done speedo_open(), status %8.8x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 	}
@@ -1005,7 +1054,7 @@
 
 	/* No need to wait for the command unit to accept here. */
 	if ((sp->phy[0] & 0x8000) == 0)
-		mdio_read(ioaddr, sp->phy[0] & 0x1f, 0);
+		mdio_read(dev, sp->phy[0] & 0x1f, MII_BMCR);
 
 	return 0;
 }
@@ -1013,42 +1062,47 @@
 /* Start the chip hardware after a full reset. */
 static void speedo_resume(struct net_device *dev)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = dev->priv;
 	long ioaddr = dev->base_addr;
 
 	/* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */
 	sp->tx_threshold = 0x01208000;
 
 	/* Set the segment registers to '0'. */
-	wait_for_cmd_done(ioaddr + SCBCmd);
-	outl(0, ioaddr + SCBPointer);
-	/* impose a delay to avoid a bug */
-	inl(ioaddr + SCBPointer);
-	udelay(10);
-	outb(RxAddrLoad, ioaddr + SCBCmd);
-	wait_for_cmd_done(ioaddr + SCBCmd);
-	outb(CUCmdBase, ioaddr + SCBCmd);
+	if (wait_for_cmd_done(dev) != 0) {
+		outl(PortPartialReset, ioaddr + SCBPort);
+		udelay(10);
+	}
+
+        outl(0, ioaddr + SCBPointer);
+        inl(ioaddr + SCBPointer);			/* Flush to PCI. */
+        udelay(10);			/* Bogus, but it avoids the bug. */
+
+        /* Note: these next two operations can take a while. */
+        do_slow_command(dev, RxAddrLoad);
+        do_slow_command(dev, CUCmdBase);
 
 	/* Load the statistics block and rx ring addresses. */
-	wait_for_cmd_done(ioaddr + SCBCmd);
 	outl(sp->lstats_dma, ioaddr + SCBPointer);
+	inl(ioaddr + SCBPointer);			/* Flush to PCI */
+
 	outb(CUStatsAddr, ioaddr + SCBCmd);
 	sp->lstats->done_marker = 0;
+	wait_for_cmd_done(dev);
 
 	if (sp->rx_ringp[sp->cur_rx % RX_RING_SIZE] == NULL) {
-		if (speedo_debug > 2)
+		if (netif_msg_rx_err(sp))
 			printk(KERN_DEBUG "%s: NULL cur_rx in speedo_resume().\n",
 					dev->name);
 	} else {
-		wait_for_cmd_done(ioaddr + SCBCmd);
 		outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
 			 ioaddr + SCBPointer);
-		outb(RxStart, ioaddr + SCBCmd);
+		inl(ioaddr + SCBPointer);		/* Flush to PCI */
 	}
 
-	wait_for_cmd_done(ioaddr + SCBCmd);
-	outb(CUDumpStats, ioaddr + SCBCmd);
-	udelay(30);
+	/* Note: RxStart should complete instantly. */
+	do_slow_command(dev, RxStart);
+	do_slow_command(dev, CUDumpStats);
 
 	/* Fill the first command with our physical address. */
 	{
@@ -1061,11 +1115,12 @@
 		ias_cmd->link =
 			cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE));
 		memcpy(ias_cmd->params, dev->dev_addr, 6);
+		if (sp->last_cmd)
+			clear_suspend(sp->last_cmd);
 		sp->last_cmd = ias_cmd;
 	}
 
 	/* Start the chip's Tx process and unmask interrupts. */
-	wait_for_cmd_done(ioaddr + SCBCmd);
 	outl(TX_RING_ELEM_DMA(sp, sp->dirty_tx % TX_RING_SIZE),
 		 ioaddr + SCBPointer);
 	/* We are not ACK-ing FCP and ER in the interrupt handler yet so they should
@@ -1092,8 +1147,7 @@
 	long ioaddr;
 
 	ioaddr = dev->base_addr;
-	wait_for_cmd_done(ioaddr + SCBCmd);
-	if (inb(ioaddr + SCBCmd) != 0) {
+	if (wait_for_cmd_done(dev) != 0) {
 		printk("%s: previous command stalled\n", dev->name);
 		return;
 	}
@@ -1106,9 +1160,7 @@
 
 	rfd->rx_buf_addr = 0xffffffff;
 
-	wait_for_cmd_done(ioaddr + SCBCmd);
-
-	if (inb(ioaddr + SCBCmd) != 0) {
+	if (wait_for_cmd_done(dev) != 0) {
 		printk("%s: RxAbort command stalled\n", dev->name);
 		return;
 	}
@@ -1128,29 +1180,23 @@
 
 	/* We have MII and lost link beat. */
 	if ((sp->phy[0] & 0x8000) == 0) {
-		int partner = mdio_read(ioaddr, phy_num, 5);
+		int partner = mdio_read(dev, phy_num, MII_LPA);
 		if (partner != sp->partner) {
-			int flow_ctrl = sp->advertising & partner & 0x0400 ? 1 : 0;
-			if (speedo_debug > 2) {
+			int flow_ctrl = sp->mii_if.advertising & partner & 0x0400 ? 1 : 0;
+			if (netif_msg_link(sp)) {
 				printk(KERN_DEBUG "%s: Link status change.\n", dev->name);
 				printk(KERN_DEBUG "%s: Old partner %x, new %x, adv %x.\n",
-					   dev->name, sp->partner, partner, sp->advertising);
+					   dev->name, sp->partner, partner, sp->mii_if.advertising);
 			}
 			sp->partner = partner;
 			if (flow_ctrl != sp->flow_ctrl) {
 				sp->flow_ctrl = flow_ctrl;
 				sp->rx_mode = -1;	/* Trigger a reload. */
 			}
-			/* Clear sticky bit. */
-			mdio_read(ioaddr, phy_num, 1);
-			/* If link beat has returned... */
-			if (mdio_read(ioaddr, phy_num, 1) & 0x0004)
-				netif_carrier_on(dev);
-			else
-				netif_carrier_off(dev);
 		}
 	}
-	if (speedo_debug > 3) {
+	mii_check_link(&sp->mii_if);
+	if (netif_msg_timer(sp)) {
 		printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 	}
@@ -1159,7 +1205,7 @@
 		/* We haven't received a packet in a Long Time.  We might have been
 		   bitten by the receiver hang bug.  This can be cleared by sending
 		   a set multicast list command. */
-		if (speedo_debug > 3)
+		if (netif_msg_timer(sp))
 			printk(KERN_DEBUG "%s: Sending a multicast list set command"
 				   " from a timer routine,"
 				   " m=%d, j=%ld, l=%ld.\n",
@@ -1179,28 +1225,26 @@
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	int i;
 
-	/* Print a few items for debugging. */
-	if (speedo_debug > 0) {
-		int i;
-		printk(KERN_DEBUG "%s: Tx ring dump,  Tx queue %u / %u:\n", dev->name,
-			   sp->cur_tx, sp->dirty_tx);
+	if (netif_msg_pktdata(sp)) {
+		printk(KERN_DEBUG "%s: Tx ring dump,  Tx queue %u / %u:\n", 
+		    dev->name, sp->cur_tx, sp->dirty_tx);
 		for (i = 0; i < TX_RING_SIZE; i++)
 			printk(KERN_DEBUG "%s:  %c%c%2d %8.8x.\n", dev->name,
-				   i == sp->dirty_tx % TX_RING_SIZE ? '*' : ' ',
-				   i == sp->cur_tx % TX_RING_SIZE ? '=' : ' ',
-				   i, sp->tx_ring[i].status);
-	}
-	printk(KERN_DEBUG "%s: Printing Rx ring"
-		   " (next to receive into %u, dirty index %u).\n",
-		   dev->name, sp->cur_rx, sp->dirty_rx);
-
-	for (i = 0; i < RX_RING_SIZE; i++)
-		printk(KERN_DEBUG "%s: %c%c%c%2d %8.8x.\n", dev->name,
-			   sp->rx_ringp[i] == sp->last_rxf ? 'l' : ' ',
-			   i == sp->dirty_rx % RX_RING_SIZE ? '*' : ' ',
-			   i == sp->cur_rx % RX_RING_SIZE ? '=' : ' ',
-			   i, (sp->rx_ringp[i] != NULL) ?
-					   (unsigned)sp->rx_ringp[i]->status : 0);
+			    i == sp->dirty_tx % TX_RING_SIZE ? '*' : ' ',
+			    i == sp->cur_tx % TX_RING_SIZE ? '=' : ' ',
+			    i, sp->tx_ring[i].status);
+
+		printk(KERN_DEBUG "%s: Printing Rx ring"
+		    " (next to receive into %u, dirty index %u).\n",
+		    dev->name, sp->cur_rx, sp->dirty_rx);
+		for (i = 0; i < RX_RING_SIZE; i++)
+			printk(KERN_DEBUG "%s: %c%c%c%2d %8.8x.\n", dev->name,
+			    sp->rx_ringp[i] == sp->last_rxf ? 'l' : ' ',
+			    i == sp->dirty_rx % RX_RING_SIZE ? '*' : ' ',
+			    i == sp->cur_rx % RX_RING_SIZE ? '=' : ' ',
+			    i, (sp->rx_ringp[i] != NULL) ?
+			    (unsigned)sp->rx_ringp[i]->status : 0);
+	}
 
 #if 0
 	{
@@ -1210,7 +1254,7 @@
 			/* FIXME: what does it mean?  --SAW */
 			if (i == 6) i = 21;
 			printk(KERN_DEBUG "%s:  PHY index %d register %d is %4.4x.\n",
-				   dev->name, phy_num, i, mdio_read(ioaddr, phy_num, i));
+				   dev->name, phy_num, i, mdio_read(dev, phy_num, i));
 		}
 	}
 #endif
@@ -1231,6 +1275,8 @@
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		struct sk_buff *skb;
 		skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
+		/* XXX: do we really want to call this before the NULL check? --hch */
+		rx_align(skb);			/* Align IP on 16 byte boundary */
 		sp->rx_skbuff[i] = skb;
 		if (skb == NULL)
 			break;			/* OK.  Just initially short of Rx bufs. */
@@ -1284,7 +1330,7 @@
 	}
 	while (sp->mc_setup_head != NULL) {
 		struct speedo_mc_block *t;
-		if (speedo_debug > 1)
+		if (netif_msg_tx_err(sp))
 			printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name);
 		pci_unmap_single(sp->pdev, sp->mc_setup_head->frame_dma,
 				sp->mc_setup_head->len, PCI_DMA_TODEVICE);
@@ -1300,22 +1346,22 @@
 static void reset_mii(struct net_device *dev)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
-	long ioaddr = dev->base_addr;
+
 	/* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
 	if ((sp->phy[0] & 0x8000) == 0) {
 		int phy_addr = sp->phy[0] & 0x1f;
-		int advertising = mdio_read(ioaddr, phy_addr, 4);
-		int mii_bmcr = mdio_read(ioaddr, phy_addr, 0);
-		mdio_write(ioaddr, phy_addr, 0, 0x0400);
-		mdio_write(ioaddr, phy_addr, 1, 0x0000);
-		mdio_write(ioaddr, phy_addr, 4, 0x0000);
-		mdio_write(ioaddr, phy_addr, 0, 0x8000);
+		int advertising = mdio_read(dev, phy_addr, MII_ADVERTISE);
+		int mii_bmcr = mdio_read(dev, phy_addr, MII_BMCR);
+		mdio_write(dev, phy_addr, MII_BMCR, 0x0400);
+		mdio_write(dev, phy_addr, MII_BMSR, 0x0000);
+		mdio_write(dev, phy_addr, MII_ADVERTISE, 0x0000);
+		mdio_write(dev, phy_addr, MII_BMCR, 0x8000);
 #ifdef honor_default_port
-		mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
+		mdio_write(dev, phy_addr, MII_BMCR, mii_ctrl[dev->default_port & 7]);
 #else
-		mdio_read(ioaddr, phy_addr, 0);
-		mdio_write(ioaddr, phy_addr, 0, mii_bmcr);
-		mdio_write(ioaddr, phy_addr, 4, advertising);
+		mdio_read(dev, phy_addr, MII_BMCR);
+		mdio_write(dev, phy_addr, MII_BMCR, mii_bmcr);
+		mdio_write(dev, phy_addr, MII_ADVERTISE, advertising);
 #endif
 	}
 }
@@ -1327,12 +1373,14 @@
 	int status = inw(ioaddr + SCBStatus);
 	unsigned long flags;
 
-	printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
+	if (netif_msg_tx_err(sp)) {
+		printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
 		   " %4.4x at %d/%d command %8.8x.\n",
 		   dev->name, status, inw(ioaddr + SCBCmd),
 		   sp->dirty_tx, sp->cur_tx,
 		   sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status);
 
+	}
 	speedo_show_state(dev);
 #if 0
 	if ((status & 0x00C0) != 0x0080
@@ -1422,13 +1470,13 @@
 	/* workaround for hardware bug on 10 mbit half duplex */
 
 	if ((sp->partner == 0) && (sp->chip_id == 1)) {
-		wait_for_cmd_done(ioaddr + SCBCmd);
+		wait_for_cmd_done(dev);
 		outb(0 , ioaddr + SCBCmd);
 		udelay(1);
 	}
 
 	/* Trigger the command unit resume. */
-	wait_for_cmd_done(ioaddr + SCBCmd);
+	wait_for_cmd_done(dev);
 	clear_suspend(sp->last_cmd);
 	/* We want the time window between clearing suspend flag on the previous
 	   command and resuming CU to be as small as possible.
@@ -1460,14 +1508,14 @@
 		int entry = dirty_tx % TX_RING_SIZE;
 		int status = le32_to_cpu(sp->tx_ring[entry].status);
 
-		if (speedo_debug > 5)
+		if (netif_msg_tx_done(sp))
 			printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n",
 				   entry, status);
 		if ((status & StatusComplete) == 0)
 			break;			/* It still hasn't been processed. */
 		if (status & TxUnderrun)
 			if (sp->tx_threshold < 0x01e08000) {
-				if (speedo_debug > 2)
+				if (netif_msg_tx_err(sp))
 					printk(KERN_DEBUG "%s: TX underrun, threshold adjusted.\n",
 						   dev->name);
 				sp->tx_threshold += 0x00040000;
@@ -1485,7 +1533,7 @@
 		dirty_tx++;
 	}
 
-	if (speedo_debug && (int)(sp->cur_tx - dirty_tx) > TX_RING_SIZE) {
+	if (netif_msg_tx_err(sp) && (int)(sp->cur_tx - dirty_tx) > TX_RING_SIZE) {
 		printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d,"
 			   " full=%d.\n",
 			   dirty_tx, sp->cur_tx, sp->tx_full);
@@ -1495,7 +1543,7 @@
 	while (sp->mc_setup_head != NULL
 		   && (int)(dirty_tx - sp->mc_setup_head->tx - 1) > 0) {
 		struct speedo_mc_block *t;
-		if (speedo_debug > 1)
+		if (netif_msg_tx_err(sp))
 			printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name);
 		pci_unmap_single(sp->pdev, sp->mc_setup_head->frame_dma,
 				sp->mc_setup_head->len, PCI_DMA_TODEVICE);
@@ -1518,13 +1566,6 @@
 	long ioaddr, boguscnt = max_interrupt_work;
 	unsigned short status;
 
-#ifndef final_version
-	if (dev == NULL) {
-		printk(KERN_ERR "speedo_interrupt(): irq %d for unknown device.\n", irq);
-		return;
-	}
-#endif
-
 	ioaddr = dev->base_addr;
 	sp = (struct speedo_private *)dev->priv;
 
@@ -1545,7 +1586,7 @@
 		   FCP and ER interrupts --Dragan */
 		outw(status & 0xfc00, ioaddr + SCBStatus);
 
-		if (speedo_debug > 4)
+		if (netif_msg_intr(sp))
 			printk(KERN_DEBUG "%s: interrupt  status=%#4.4x.\n",
 				   dev->name, status);
 
@@ -1607,7 +1648,7 @@
 		}
 	} while (1);
 
-	if (speedo_debug > 3)
+	if (netif_msg_intr(sp))
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 
@@ -1622,6 +1663,8 @@
 	struct sk_buff *skb;
 	/* Get a fresh skbuff to replace the consumed one. */
 	skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
+	/* XXX: do we really want to call this before the NULL check? --hch */
+	rx_align(skb);				/* Align IP on 16 byte boundary */
 	sp->rx_skbuff[entry] = skb;
 	if (skb == NULL) {
 		sp->rx_ringp[entry] = NULL;
@@ -1666,12 +1709,12 @@
 		if (rxf == NULL) {
 			unsigned int forw;
 			int forw_entry;
-			if (speedo_debug > 2 || !(sp->rx_ring_state & RrOOMReported)) {
+			if (netif_msg_rx_err(sp) || !(sp->rx_ring_state & RrOOMReported)) {
 				printk(KERN_WARNING "%s: can't fill rx buffer (force %d)!\n",
 						dev->name, force);
-				speedo_show_state(dev);
 				sp->rx_ring_state |= RrOOMReported;
 			}
+			speedo_show_state(dev);
 			if (!force)
 				return -1;	/* Better luck next time!  */
 			/* Borrow an skb from one of next entries. */
@@ -1712,8 +1755,9 @@
 	int entry = sp->cur_rx % RX_RING_SIZE;
 	int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx;
 	int alloc_ok = 1;
+	int npkts = 0;
 
-	if (speedo_debug > 4)
+	if (netif_msg_intr(sp))
 		printk(KERN_DEBUG " In speedo_rx().\n");
 	/* If we own the next entry, it's a new packet. Send it up. */
 	while (sp->rx_ringp[entry] != NULL) {
@@ -1736,14 +1780,14 @@
 		if (sp->last_rxf == sp->rx_ringp[entry]) {
 			/* Postpone the packet.  It'll be reaped at an interrupt when this
 			   packet is no longer the last packet in the ring. */
-			if (speedo_debug > 2)
+			if (netif_msg_rx_err(sp))
 				printk(KERN_DEBUG "%s: RX packet postponed!\n",
 					   dev->name);
 			sp->rx_ring_state |= RrPostponed;
 			break;
 		}
 
-		if (speedo_debug > 4)
+		if (netif_msg_rx_status(sp))
 			printk(KERN_DEBUG "  speedo_rx() status %8.8x len %d.\n", status,
 				   pkt_len);
 		if ((status & (RxErrTooBig|RxOK|0x0f90)) != RxOK) {
@@ -1778,6 +1822,7 @@
 				memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->tail,
 					   pkt_len);
 #endif
+				npkts++;
 			} else {
 				/* Pass up the already-filled skbuff. */
 				skb = sp->rx_skbuff[entry];
@@ -1788,6 +1833,7 @@
 				}
 				sp->rx_skbuff[entry] = NULL;
 				skb_put(skb, pkt_len);
+				npkts++;
 				sp->rx_ringp[entry] = NULL;
 				pci_unmap_single(sp->pdev, sp->rx_ring_dma[entry],
 						PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
@@ -1808,7 +1854,8 @@
 	/* Try hard to refill the recently taken buffers. */
 	speedo_refill_rx_buffers(dev, 1);
 
-	sp->last_rx_time = jiffies;
+	if (npkts)
+		sp->last_rx_time = jiffies;
 
 	return 0;
 }
@@ -1823,21 +1870,25 @@
 	netdevice_stop(dev);
 	netif_stop_queue(dev);
 
-	if (speedo_debug > 1)
+	if (netif_msg_ifdown(sp))
 		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 
 	/* Shut off the media monitoring timer. */
 	del_timer_sync(&sp->timer);
 
+	outw(SCBMaskAll, ioaddr + SCBCmd);
+
 	/* Shutting down the chip nicely fails to disable flow control. So.. */
 	outl(PortPartialReset, ioaddr + SCBPort);
+	inl(ioaddr + SCBPort); /* flush posted write */
+	/*
+	 * The chip requires a 10 microsecond quiet period.  Wait here!
+	 */
+	udelay(10);
 
 	free_irq(dev->irq, dev);
-
-	/* Print a few items for debugging. */
-	if (speedo_debug > 3)
-		speedo_show_state(dev);
+	speedo_show_state(dev);
 
     /* Free all the skbuffs in the Rx and Tx queues. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
@@ -1872,13 +1923,11 @@
 		sp->mc_setup_head = t;
 	}
 	sp->mc_setup_tail = NULL;
-	if (speedo_debug > 0)
+	if (netif_msg_ifdown(sp))
 		printk(KERN_DEBUG "%s: %d multicast blocks dropped.\n", dev->name, i);
 
 	pci_set_power_state(sp->pdev, 2);
 
-	MOD_DEC_USE_COUNT;
-
 	return 0;
 }
 
@@ -1915,7 +1964,7 @@
 			/* Take a spinlock to make wait_for_cmd_done and sending the
 			   command atomic.  --SAW */
 			spin_lock_irqsave(&sp->lock, flags);
-			wait_for_cmd_done(ioaddr + SCBCmd);
+			wait_for_cmd_done(dev);
 			outb(CUDumpStats, ioaddr + SCBCmd);
 			spin_unlock_irqrestore(&sp->lock, flags);
 		}
@@ -1932,6 +1981,7 @@
 		return -EFAULT;
 	
         switch (ethcmd) {
+	/* get driver-specific version/etc. info */
 	case ETHTOOL_GDRVINFO: {
 		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
 		strncpy(info.driver, "eepro100", sizeof(info.driver)-1);
@@ -1943,19 +1993,64 @@
 		return 0;
 	}
 	
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&sp->lock);
+		mii_ethtool_gset(&sp->mii_if, &ecmd);
+		spin_unlock_irq(&sp->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int r;
+		struct ethtool_cmd ecmd;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&sp->lock);
+		r = mii_ethtool_sset(&sp->mii_if, &ecmd);
+		spin_unlock_irq(&sp->lock);
+		return r;
+	}
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST: {
+		return mii_nway_restart(&sp->mii_if);
+	}
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		edata.data = mii_link_ok(&sp->mii_if);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = sp->msg_enable;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		sp->msg_enable = edata.data;
+		return 0;
+	}
+
         }
 	
 	return -EOPNOTSUPP;
 }
 
-
-
-
-
 static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
-	long ioaddr = dev->base_addr;
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
 	int phy = sp->phy[0] & 0x1f;
 	int saved_acpi;
@@ -1974,7 +2069,7 @@
 		   timer routine.  2000/05/09 SAW */
 		saved_acpi = pci_set_power_state(sp->pdev, 0);
 		t = del_timer_sync(&sp->timer);
-		data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f);
+		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
 		if (t)
 			add_timer(&sp->timer); /* may be set to the past  --SAW */
 		pci_set_power_state(sp->pdev, saved_acpi);
@@ -1986,7 +2081,7 @@
 			return -EPERM;
 		saved_acpi = pci_set_power_state(sp->pdev, 0);
 		t = del_timer_sync(&sp->timer);
-		mdio_write(ioaddr, data->phy_id, data->reg_num, data->val_in);
+		mdio_write(dev, data->phy_id, data->reg_num, data->val_in);
 		if (t)
 			add_timer(&sp->timer); /* may be set to the past  --SAW */
 		pci_set_power_state(sp->pdev, saved_acpi);
@@ -2024,7 +2119,7 @@
 	} else
 		new_rx_mode = 0;
 
-	if (speedo_debug > 3)
+	if (netif_msg_rx_status(sp))
 		printk(KERN_DEBUG "%s: set_rx_mode %d -> %d\n", dev->name,
 				sp->rx_mode, new_rx_mode);
 
@@ -2058,14 +2153,14 @@
 		   Disable Flow control since we are not ACK-ing any FC interrupts
 		   for now. --Dragan */
 		config_cmd_data[19] = 0x84;
-		config_cmd_data[19] |= sp->full_duplex ? 0x40 : 0;
+		config_cmd_data[19] |= sp->mii_if.full_duplex ? 0x40 : 0;
 		config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
 		if (sp->phy[0] & 0x8000) {			/* Use the AUI port instead. */
 			config_cmd_data[15] |= 0x80;
 			config_cmd_data[8] = 0;
 		}
 		/* Trigger the command unit resume. */
-		wait_for_cmd_done(ioaddr + SCBCmd);
+		wait_for_cmd_done(dev);
 		clear_suspend(last_cmd);
 		outb(CUResume, ioaddr + SCBCmd);
 		if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
@@ -2102,7 +2197,7 @@
 			*setup_params++ = *eaddrs++;
 		}
 
-		wait_for_cmd_done(ioaddr + SCBCmd);
+		wait_for_cmd_done(dev);
 		clear_suspend(last_cmd);
 		/* Immediately trigger the command unit resume. */
 		outb(CUResume, ioaddr + SCBCmd);
@@ -2135,7 +2230,7 @@
 		mc_setup_frm = &mc_blk->frame;
 
 		/* Fill the setup frame. */
-		if (speedo_debug > 1)
+		if (netif_msg_ifup(sp))
 			printk(KERN_DEBUG "%s: Constructing a setup frame at %p.\n",
 				   dev->name, mc_setup_frm);
 		mc_setup_frm->cmd_status =
@@ -2178,7 +2273,7 @@
 		pci_dma_sync_single(sp->pdev, mc_blk->frame_dma,
 				mc_blk->len, PCI_DMA_TODEVICE);
 
-		wait_for_cmd_done(ioaddr + SCBCmd);
+		wait_for_cmd_done(dev);
 		clear_suspend(last_cmd);
 		/* Immediately trigger the command unit resume. */
 		outb(CUResume, ioaddr + SCBCmd);
@@ -2189,7 +2284,7 @@
 		}
 		spin_unlock_irqrestore(&sp->lock, flags);
 
-		if (speedo_debug > 5)
+		if (netif_msg_rx_status(sp))
 			printk(" CmdMCSetup frame length %d in entry %d.\n",
 				   dev->mc_count, entry);
 	}
@@ -2332,11 +2427,9 @@
 
 static int __init eepro100_init_module(void)
 {
-	if (debug >= 0 && speedo_debug != debug)
-		printk(KERN_INFO "eepro100.c: Debug level is %d.\n", debug);
-	if (debug >= 0)
-		speedo_debug = debug;
-
+#ifdef MODULE
+	printk(version);
+#endif
 	return pci_module_init(&eepro100_driver);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/eexpress.c linux-2.4.20/drivers/net/eexpress.c
--- linux-2.4.19/drivers/net/eexpress.c	2002-02-25 19:37:59.000000000 +0000
+++ linux-2.4.20/drivers/net/eexpress.c	2002-10-29 11:18:31.000000000 +0000
@@ -341,7 +341,7 @@
 int __init express_probe(struct net_device *dev)
 {
 	unsigned short *port;
-	static unsigned short ports[] = { 0x300,0x310,0x270,0x320,0x340,0 };
+	static unsigned short ports[] = { 0x240,0x300,0x310,0x270,0x320,0x340,0 };
 	unsigned short ioaddr = dev->base_addr;
 
 	SET_MODULE_OWNER(dev);
@@ -436,10 +436,26 @@
 	ret = request_irq(dev->irq,&eexp_irq,0,dev->name,dev);
 	if (ret) return ret;
 
-	request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress");
-	request_region(ioaddr+0x4000, 16, "EtherExpress shadow");
-	request_region(ioaddr+0x8000, 16, "EtherExpress shadow");
-	request_region(ioaddr+0xc000, 16, "EtherExpress shadow");
+	if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) {
+		printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
+			, ioaddr);
+		goto err_out1;
+	}
+	if (!request_region(ioaddr+0x4000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
+		printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
+			, ioaddr+0x4000);
+		goto err_out2;
+	}
+	if (!request_region(ioaddr+0x8000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
+		printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
+			, ioaddr+0x8000);
+		goto err_out3;
+	}
+	if (!request_region(ioaddr+0xc000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
+		printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
+			, ioaddr+0xc000);
+		goto err_out4;
+	}
 	
 	if (lp->width) {
 		printk("%s: forcing ASIC to 8-bit mode\n", dev->name);
@@ -452,6 +468,16 @@
 	printk(KERN_DEBUG "%s: leaving eexp_open()\n", dev->name);
 #endif
 	return 0;
+
+	err_out4:
+		release_region(ioaddr+0x8000, EEXP_IO_EXTENT);
+	err_out3:
+		release_region(ioaddr+0x4000, EEXP_IO_EXTENT);
+	err_out2:
+		release_region(ioaddr, EEXP_IO_EXTENT);
+	err_out1:
+		free_irq(dev->irq, dev);
+		return -EBUSY;
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/epic100.c linux-2.4.20/drivers/net/epic100.c
--- linux-2.4.19/drivers/net/epic100.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/epic100.c	2002-10-29 11:18:40.000000000 +0000
@@ -63,11 +63,15 @@
 	LK1.1.13:
 	* revert version 1.1.12, power-up sequence "fix"
 
+	LK1.1.14 (Kryzsztof Halasa):
+	* fix spurious bad initializations
+	* pound phy a la SMSC's app note on the subject
+
 */
 
 #define DRV_NAME	"epic100"
-#define DRV_VERSION	"1.11+LK1.1.13"
-#define DRV_RELDATE	"Mar 20, 2002"
+#define DRV_VERSION	"1.11+LK1.1.14"
+#define DRV_RELDATE	"Aug 4, 2002"
 
 
 /* The user-configurable values.
@@ -426,6 +430,8 @@
 	ep->mii.dev = dev;
 	ep->mii.mdio_read = mdio_read;
 	ep->mii.mdio_write = mdio_write;
+	ep->mii.phy_id_mask = 0x1f;
+	ep->mii.reg_num_mask = 0x1f;
 
 	ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
 	if (!ring_space)
@@ -457,7 +463,9 @@
 	/* Bring the chip out of low-power mode. */
 	outl(0x4200, ioaddr + GENCTL);
 	/* Magic?!  If we don't set this bit the MII interface won't work. */
-	outl(0x0008, ioaddr + TEST1);
+	/* This magic is documented in SMSC app note 7.15 */
+	for (i = 16; i > 0; i--)
+		outl(0x0008, ioaddr + TEST1);
 
 	/* Turn on the MII transceiver. */
 	outl(0x12, ioaddr + MIICfg);
@@ -518,7 +526,7 @@
 
 	/* The lower four bits are the media type. */
 	if (duplex) {
-		ep->mii.duplex_lock = ep->mii.full_duplex = 1;
+		ep->mii.force_media = ep->mii.full_duplex = 1;
 		printk(KERN_INFO DRV_NAME "(%s):  Forced full duplex operation requested.\n",
 		       pdev->slot_name);
 	}
@@ -674,7 +682,8 @@
 
 	outl(0x4000, ioaddr + GENCTL);
 	/* This magic is documented in SMSC app note 7.15 */
-	outl(0x0008, ioaddr + TEST1);
+	for (i = 16; i > 0; i--)
+		outl(0x0008, ioaddr + TEST1);
 
 	/* Pull the chip out of low-power mode, enable interrupts, and set for
 	   PCI read multiple.  The MIIcfg setting and strange write order are
@@ -697,6 +706,8 @@
 	outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
 #endif
 
+	udelay(20); /* Looks like EPII needs that if you want reliable RX init. FIXME: pci posting bug? */
+	
 	for (i = 0; i < 3; i++)
 		outl(cpu_to_le16(((u16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4);
 
@@ -846,7 +857,7 @@
 	int negotiated = mii_lpa & ep->mii.advertising;
 	int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
 
-	if (ep->mii.duplex_lock)
+	if (ep->mii.force_media)
 		return;
 	if (mii_lpa == 0xffff)		/* Bogus read */
 		return;
@@ -1064,13 +1075,7 @@
 					if (txstatus & 0x0008) ep->stats.tx_carrier_errors++;
 					if (txstatus & 0x0040) ep->stats.tx_window_errors++;
 					if (txstatus & 0x0010) ep->stats.tx_fifo_errors++;
-#ifdef ETHER_STATS
-					if (txstatus & 0x1000) ep->stats.collisions16++;
-#endif
 				} else {
-#ifdef ETHER_STATS
-					if ((txstatus & 0x0002) != 0) ep->stats.tx_deferred++;
-#endif
 					ep->stats.collisions += (txstatus >> 8) & 15;
 					ep->stats.tx_packets++;
 					ep->stats.tx_bytes += ep->tx_skbuff[entry]->len;
@@ -1424,66 +1429,34 @@
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct epic_private *ep = dev->priv;
+	struct epic_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
+	int rc;
 
-	switch(cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
-		data->phy_id = ep->phys[0] & 0x1f;
-		/* Fall Through */
-
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
-		if (! netif_running(dev)) {
-			outl(0x0200, ioaddr + GENCTL);
-			outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
-		}
-		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
-#if 0					/* Just leave on if the ioctl() is ever used. */
-		if (! netif_running(dev)) {
-			outl(0x0008, ioaddr + GENCTL);
-			outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
-		}
-#endif
-		return 0;
+	/* power-up, if interface is down */
+	if (! netif_running(dev)) {
+		outl(0x0200, ioaddr + GENCTL);
+		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
+	}
 
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		if (! netif_running(dev)) {
-			outl(0x0200, ioaddr + GENCTL);
-			outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
-		}
-		if (data->phy_id == ep->phys[0]) {
-			u16 value = data->val_in;
-			switch (data->reg_num) {
-			case 0:
-				/* Check for autonegotiation on or reset. */
-				ep->mii.duplex_lock = (value & 0x9000) ? 0 : 1;
-				if (ep->mii.duplex_lock)
-					ep->mii.full_duplex = (value & 0x0100) ? 1 : 0;
-				break;
-			case 4: ep->mii.advertising = value; break;
-			}
-			/* Perhaps check_duplex(dev), depending on chip semantics. */
-		}
-		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-#if 0					/* Leave on if the ioctl() is used. */
-		if (! netif_running(dev)) {
-			outl(0x0008, ioaddr + GENCTL);
-			outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
-		}
-#endif
-		return 0;
-	default:
-		return -EOPNOTSUPP;
+	/* ethtool commands */
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	/* all other ioctls (the SIOC[GS]MIIxxx ioctls) */
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
+	}
+
+	/* power-down, if interface is down */
+	if (! netif_running(dev)) {
+		outl(0x0008, ioaddr + GENCTL);
+		outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
 	}
+	return rc;
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/ewrk3.c linux-2.4.20/drivers/net/ewrk3.c
--- linux-2.4.19/drivers/net/ewrk3.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/ewrk3.c	2002-10-29 11:18:39.000000000 +0000
@@ -76,6 +76,7 @@
    kernel with the ewrk3 configuration turned off and reboot.
    5) insmod ewrk3.o
    [Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y]
+   [Adam Kropelin: now accepts irq=x1,x2 io=y1,y2 for multiple cards]
    6) run the net startup bits for your new eth?? interface manually
    (usually /etc/rc.inet[12] at boot time).
    7) enjoy!
@@ -130,9 +131,14 @@
    Add new multicasting code.
    0.41    20-Jan-96   Fix IRQ set up problem reported by
    <kenneth@bbs.sas.ntu.ac.sg>.
-   0.42    22-Apr-96      Fix alloc_device() bug <jari@markkus2.fimr.fi>
-   0.43    16-Aug-96      Update alloc_device() to conform to de4x5.c
-   0.44    08-Nov-01      use library crc32 functions <Matt_Domsch@dell.com>
+   0.42    22-Apr-96   Fix alloc_device() bug <jari@markkus2.fimr.fi>
+   0.43    16-Aug-96   Update alloc_device() to conform to de4x5.c
+   0.44    08-Nov-01   use library crc32 functions <Matt_Domsch@dell.com>
+   0.45    19-Jul-02   fix unaligned access on alpha <martin@bruli.net>
+   0.46    10-Oct-02   Multiple NIC support when module <akropel1@rochester.rr.com>
+   0.47    18-Oct-02   ethtool support <akropel1@rochester.rr.com>
+   0.48    18-Oct-02   cli/sti removal for 2.5 <vda@port.imtp.ilyichevsk.odessa.ua>
+   ioctl locking, signature search cleanup <akropel1@rochester.rr.com>
 
    =========================================================================
  */
@@ -142,7 +148,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
@@ -158,6 +163,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/ethtool.h>
 
 #include <linux/time.h>
 #include <linux/types.h>
@@ -166,8 +172,11 @@
 
 #include "ewrk3.h"
 
+#define DRV_NAME	"ewrk3"
+#define DRV_VERSION	"0.48"
+
 static char version[] __initdata =
-"ewrk3.c:v0.43a 2001/02/04 davies@maniac.ultranet.com\n";
+DRV_NAME ":v" DRV_VERSION " 2002/10/18 davies@maniac.ultranet.com\n";
 
 #ifdef EWRK3_DEBUG
 static int ewrk3_debug = EWRK3_DEBUG;
@@ -196,6 +205,7 @@
 #define EWRK3_IOP_INC 0x20	/* I/O address increment */
 #define EWRK3_TOTAL_SIZE 0x20	/* required I/O address length */
 
+/* If you change this, remember to also change MODULE_PARM array limits */
 #ifndef MAX_NUM_EWRK3S
 #define MAX_NUM_EWRK3S 21
 #endif
@@ -254,26 +264,29 @@
 #define EWRK3_PKT_BIN_SZ  128	/* Should be >=100 unless you
 				   increase EWRK3_PKT_STAT_SZ */
 
+struct ewrk3_stats {
+	u32 bins[EWRK3_PKT_STAT_SZ];
+	u32 unicast;
+	u32 multicast;
+	u32 broadcast;
+	u32 excessive_collisions;
+	u32 tx_underruns;
+	u32 excessive_underruns;
+};
+
 struct ewrk3_private {
 	char adapter_name[80];	/* Name exported to /proc/ioports */
 	u_long shmem_base;	/* Shared memory start address */
 	u_long shmem_length;	/* Shared memory window length */
 	struct net_device_stats stats;	/* Public stats */
-	struct {
-		u32 bins[EWRK3_PKT_STAT_SZ];	/* Private stats counters */
-		u32 unicast;
-		u32 multicast;
-		u32 broadcast;
-		u32 excessive_collisions;
-		u32 tx_underruns;
-		u32 excessive_underruns;
-	} pktStats;
+	struct ewrk3_stats pktStats; /* Private stats counters */
 	u_char irq_mask;	/* Adapter IRQ mask bits */
 	u_char mPage;		/* Maximum 2kB Page number */
 	u_char lemac;		/* Chip rev. level */
 	u_char hard_strapped;	/* Don't allow a full open */
 	u_char txc;		/* Transmit cut through */
 	u_char *mctbl;		/* Pointer to the multicast table */
+	u_char led_mask;	/* Used to reserve LED access for ethtool */
 	spinlock_t hw_lock;
 };
 
@@ -529,6 +542,7 @@
 							lp->shmem_length = shmem_length;
 							lp->lemac = lemac;
 							lp->hard_strapped = hard_strapped;
+							lp->led_mask = CR_LED;
 							spin_lock_init(&lp->hw_lock);
 
 							lp->mPage = 64;
@@ -555,8 +569,10 @@
 								if (dev->irq < 2) {
 #ifndef MODULE
 									u_char irqnum;
+									unsigned long irq_mask, delay;
+			
 
-									autoirq_setup(0);
+									irq_mask = probe_irq_on();
 
 									/*
 									   ** Trigger a TNE interrupt.
@@ -567,7 +583,9 @@
 
 									irqnum = irq[((icr & IRQ_SEL) >> 4)];
 
-									dev->irq = autoirq_report(1);
+									delay = jiffies + HZ/50;
+									while (time_before(jiffies, delay)) ;
+									dev->irq = probe_irq_off(irq_mask);
 									if ((dev->irq) && (irqnum == dev->irq)) {
 										printk(" and uses IRQ%d.\n", dev->irq);
 									} else {
@@ -895,7 +913,7 @@
 	DISABLE_IRQs;
 
 	cr = inb(EWRK3_CR);
-	cr |= CR_LED;
+	cr |= lp->led_mask;
 	outb(cr, EWRK3_CR);
 
 	if (csr & CSR_RNE)	/* Rx interrupt (packet[s] arrived) */
@@ -920,12 +938,13 @@
 	}
 
 	/* Unmask the EWRK3 board interrupts and turn off the LED */
-	cr &= ~CR_LED;
+	cr &= ~(lp->led_mask);
 	outb(cr, EWRK3_CR);
 	ENABLE_IRQs;
 	spin_unlock(&lp->hw_lock);
 }
 
+/* Called with lp->hw_lock held */
 static int ewrk3_rx(struct net_device *dev)
 {
 	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
@@ -1004,12 +1023,13 @@
 						}
 						p = skb->data;	/* Look at the dest addr */
 						if (p[0] & 0x01) {	/* Multicast/Broadcast */
-							if ((*(s32 *) & p[0] == -1) && (*(s16 *) & p[4] == -1)) {
+							if ((*(s16 *) & p[0] == -1) && (*(s16 *) & p[2] == -1) && (*(s16 *) & p[4] == -1)) {
 								lp->pktStats.broadcast++;
 							} else {
 								lp->pktStats.multicast++;
 							}
-						} else if ((*(s32 *) & p[0] == *(s32 *) & dev->dev_addr[0]) &&
+						} else if ((*(s16 *) & p[0] == *(s16 *) & dev->dev_addr[0]) &&
+							   (*(s16 *) & p[2] == *(s16 *) & dev->dev_addr[2]) &&
 							   (*(s16 *) & p[4] == *(s16 *) & dev->dev_addr[4])) {
 							lp->pktStats.unicast++;
 						}
@@ -1050,8 +1070,9 @@
 }
 
 /*
-   ** Buffer sent - check for TX buffer errors.
- */
+** Buffer sent - check for TX buffer errors.
+** Called with lp->hw_lock held
+*/
 static int ewrk3_tx(struct net_device *dev)
 {
 	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
@@ -1459,27 +1480,20 @@
  */
 static void __init EthwrkSignature(char *name, char *eeprom_image)
 {
-	u_long i, j, k;
+	int i;
 	char *signatures[] = EWRK3_SIGNATURE;
 
-	strcpy(name, "");
-	for (i = 0; *signatures[i] != '\0' && *name == '\0'; i++) {
-		for (j = EEPROM_PNAME7, k = 0; j <= EEPROM_PNAME0 && k < strlen(signatures[i]); j++) {
-			if (signatures[i][k] == eeprom_image[j]) {	/* track signature */
-				k++;
-			} else {	/* lost signature; begin search again */
-				k = 0;
-			}
-		}
-		if (k == strlen(signatures[i])) {
-			for (k = 0; k < EWRK3_STRLEN; k++) {
-				name[k] = eeprom_image[EEPROM_PNAME7 + k];
-				name[EWRK3_STRLEN] = '\0';
-			}
-		}
-	}
+	for (i=0; *signatures[i] != '\0'; i++)
+		if( !strncmp(eeprom_image+EEPROM_PNAME7, signatures[i], strlen(signatures[i])) )
+			break;
 
-	return;			/* return the device name string */
+	if (*signatures[i] != '\0') {
+		memcpy(name, eeprom_image+EEPROM_PNAME7, EWRK3_STRLEN);
+		name[EWRK3_STRLEN] = '\0';
+	} else
+		name[0] = '\0';
+
+	return;
 }
 
 /*
@@ -1615,6 +1629,197 @@
 	return status;		/* return the device name string */
 }
 
+static int ewrk3_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+	u_long iobase = dev->base_addr;
+	u32 ethcmd;
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	/* Get driver info */
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		int fwrev = Read_EEPROM(dev->base_addr, EEPROM_REVLVL);
+
+		strcpy(info.driver, DRV_NAME);
+		strcpy(info.version, DRV_VERSION);
+		sprintf(info.fw_version, "%d", fwrev);
+		strcpy(info.bus_info, "N/A");
+		info.eedump_len = EEPROM_MAX;
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* Get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		u_char cr = inb(EWRK3_CR);
+
+		switch (lp->adapter_name[4]) {
+		case '3': /* DE203 */
+			ecmd.supported = SUPPORTED_BNC;
+			ecmd.port = PORT_BNC;
+			break;
+
+		case '4': /* DE204 */
+			ecmd.supported = SUPPORTED_TP;
+			ecmd.port = PORT_TP;
+			break;
+
+		case '5': /* DE205 */
+			ecmd.supported = SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_AUI;
+			ecmd.autoneg = !(cr & CR_APD);
+			/*
+			** Port is only valid if autoneg is disabled
+			** and even then we don't know if AUI is jumpered.
+			*/
+			if (!ecmd.autoneg)
+				ecmd.port = (cr & CR_PSEL) ? PORT_BNC : PORT_TP;
+			break;
+		}
+
+		ecmd.supported |= SUPPORTED_10baseT_Half;
+		ecmd.speed = SPEED_10;
+		ecmd.duplex = DUPLEX_HALF;
+
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* Set settings */
+	case ETHTOOL_SSET: {
+		struct ethtool_cmd ecmd;
+		u_char cr;
+		u_long flags;
+
+		/* DE205 is the only card with anything to set */
+		if (lp->adapter_name[4] != '5')
+			return -EOPNOTSUPP;
+
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+
+		/* Sanity-check parameters */
+		if (ecmd.speed != SPEED_10)
+			return -EINVAL;
+		if (ecmd.port != PORT_TP && ecmd.port != PORT_BNC)
+			return -EINVAL; /* AUI is not software-selectable */
+		if (ecmd.transceiver != XCVR_INTERNAL)
+			return -EINVAL;
+		if (ecmd.duplex != DUPLEX_HALF)
+			return -EINVAL;
+		if (ecmd.phy_address != 0)
+			return -EINVAL;
+
+		spin_lock_irqsave(&lp->hw_lock, flags);
+		cr = inb(EWRK3_CR);
+
+		/* If Autoneg is set, change to Auto Port mode */
+		/* Otherwise, disable Auto Port and set port explicitly */
+		if (ecmd.autoneg) {
+			cr &= ~CR_APD;
+		} else {
+			cr |= CR_APD;
+			if (ecmd.port == PORT_TP)
+				cr &= ~CR_PSEL;		/* Force TP */
+			else
+				cr |= CR_PSEL;		/* Force BNC */
+		}
+
+		/* Commit the changes */
+		outb(cr, EWRK3_CR);
+
+		spin_unlock_irqrestore(&lp->hw_lock, flags);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* Get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = { ETHTOOL_GLINK };
+		u_char cmr = inb(EWRK3_CMR);
+
+		/* DE203 has BNC only and link status does not apply */
+		if (lp->adapter_name[4] == '3')
+			return -EOPNOTSUPP;
+
+		/* On DE204 this is always valid since TP is the only port. */
+		/* On DE205 this reflects TP status even if BNC or AUI is selected. */
+		edata.data = !(cmr & CMR_LINK);
+
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+#ifdef BROKEN
+	/* Blink LED for identification */
+	case ETHTOOL_PHYS_ID: {
+		struct ethtool_value edata;
+		u_long flags;
+		long delay, ret;
+		u_char cr;
+		int count;
+		wait_queue_head_t wait;
+
+		init_waitqueue_head(&wait);
+
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+
+		/* Toggle LED 4x per second */
+		delay = HZ >> 2;
+		count = edata.data << 2;
+
+		spin_lock_irqsave(&lp->hw_lock, flags);
+
+		/* Bail if a PHYS_ID is already in progress */
+		if (lp->led_mask == 0) {
+			spin_unlock_irqrestore(&lp->hw_lock, flags);
+			return -EBUSY;
+		}
+
+		/* Prevent ISR from twiddling the LED */
+		lp->led_mask = 0;
+
+		while (count--) {
+			/* Toggle the LED */
+			cr = inb(EWRK3_CR);
+			outb(cr ^ CR_LED, EWRK3_CR);
+
+			/* Wait a little while */
+			spin_unlock_irqrestore(&lp->hw_lock, flags);
+			ret = delay;
+			__wait_event_interruptible_timeout(wait, 0, ret);
+			spin_lock_irqsave(&lp->hw_lock, flags);
+
+			/* Exit if we got a signal */
+			if (ret == -ERESTARTSYS)
+				goto out;
+		}
+
+		ret = 0;
+out:
+		lp->led_mask = CR_LED;
+		cr = inb(EWRK3_CR);
+		outb(cr & ~CR_LED, EWRK3_CR);
+		spin_unlock_irqrestore(&lp->hw_lock, flags);
+		return ret;
+	}
+#endif /* BROKEN */
+
+	}
+
+	return -EOPNOTSUPP;
+}
+
 /*
    ** Perform IOCTL call functions here. Some are privileged operations and the
    ** effective uid is checked in those cases.
@@ -1626,6 +1831,7 @@
 	u_long iobase = dev->base_addr;
 	int i, j, status = 0;
 	u_char csr;
+	unsigned long flags;
 	union ewrk3_addr {
 		u_char addr[HASH_TABLE_LEN * ETH_ALEN];
 		u_short val[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
@@ -1633,6 +1839,14 @@
 	
 	union ewrk3_addr *tmp;
 
+	/* ethtool IOCTLs are handled elsewhere */
+	if (cmd == SIOCETHTOOL)
+		return ewrk3_ethtool_ioctl(dev, (void *)rq->ifr_data);
+
+	/* Other than ethtool, all we handle are private IOCTLs */
+	if (cmd != EWRK3IOCTL)
+		return -EOPNOTSUPP;
+
 	tmp = kmalloc(sizeof(union ewrk3_addr), GFP_KERNEL);
 	if(tmp==NULL)
 		return -ENOMEM;
@@ -1649,21 +1863,26 @@
 		
 	case EWRK3_SET_HWADDR:	/* Set the hardware address */
 		if (capable(CAP_NET_ADMIN)) {
+			spin_lock_irqsave(&lp->hw_lock, flags);
 			csr = inb(EWRK3_CSR);
 			csr |= (CSR_TXD | CSR_RXD);
 			outb(csr, EWRK3_CSR);	/* Disable the TX and RX */
+			spin_unlock_irqrestore(&lp->hw_lock, flags);
 
 			if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN)) {
 				status = -EFAULT;
 				break;
 			}
+			spin_lock_irqsave(&lp->hw_lock, flags);
 			for (i = 0; i < ETH_ALEN; i++) {
 				dev->dev_addr[i] = tmp->addr[i];
 				outb(tmp->addr[i], EWRK3_PAR0 + i);
 			}
 
+			csr = inb(EWRK3_CSR);
 			csr &= ~(CSR_TXD | CSR_RXD);	/* Enable the TX and RX */
 			outb(csr, EWRK3_CSR);
+			spin_unlock_irqrestore(&lp->hw_lock, flags);
 		} else {
 			status = -EPERM;
 		}
@@ -1671,10 +1890,12 @@
 		break;
 	case EWRK3_SET_PROM:	/* Set Promiscuous Mode */
 		if (capable(CAP_NET_ADMIN)) {
+			spin_lock_irqsave(&lp->hw_lock, flags);
 			csr = inb(EWRK3_CSR);
 			csr |= CSR_PME;
 			csr &= ~CSR_MCE;
 			outb(csr, EWRK3_CSR);
+			spin_unlock_irqrestore(&lp->hw_lock, flags);
 		} else {
 			status = -EPERM;
 		}
@@ -1682,16 +1903,18 @@
 		break;
 	case EWRK3_CLR_PROM:	/* Clear Promiscuous Mode */
 		if (capable(CAP_NET_ADMIN)) {
+			spin_lock_irqsave(&lp->hw_lock, flags);
 			csr = inb(EWRK3_CSR);
 			csr &= ~CSR_PME;
 			outb(csr, EWRK3_CSR);
+			spin_unlock_irqrestore(&lp->hw_lock, flags);
 		} else {
 			status = -EPERM;
 		}
 
 		break;
 	case EWRK3_GET_MCA:	/* Get the multicast address table */
-		spin_lock_irq(&lp->hw_lock);
+		spin_lock_irqsave(&lp->hw_lock, flags);
 		if (lp->shmem_length == IO_ONLY) {
 			outb(0, EWRK3_IOPR);
 			outw(PAGE0_HTE, EWRK3_PIR1);
@@ -1702,7 +1925,7 @@
 			outb(0, EWRK3_MPR);
 			isa_memcpy_fromio(tmp->addr, lp->shmem_base + PAGE0_HTE, (HASH_TABLE_LEN >> 3));
 		}
-		spin_unlock_irq(&lp->hw_lock);
+		spin_unlock_irqrestore(&lp->hw_lock, flags);
 
 		ioc->len = (HASH_TABLE_LEN >> 3);
 		if (copy_to_user(ioc->data, tmp->addr, ioc->len))
@@ -1736,28 +1959,37 @@
 		break;
 	case EWRK3_MCA_EN:	/* Enable multicast addressing */
 		if (capable(CAP_NET_ADMIN)) {
+			spin_lock_irqsave(&lp->hw_lock, flags);
 			csr = inb(EWRK3_CSR);
 			csr |= CSR_MCE;
 			csr &= ~CSR_PME;
 			outb(csr, EWRK3_CSR);
+			spin_unlock_irqrestore(&lp->hw_lock, flags);
 		} else {
 			status = -EPERM;
 		}
 
 		break;
-	case EWRK3_GET_STATS:	/* Get the driver statistics */
-		cli();
-		ioc->len = sizeof(lp->pktStats);
-		if (copy_to_user(ioc->data, &lp->pktStats, ioc->len))
-			status = -EFAULT;
-		sti();
+	case EWRK3_GET_STATS: { /* Get the driver statistics */
+		struct ewrk3_stats *tmp_stats =
+        		kmalloc(sizeof(lp->pktStats), GFP_KERNEL);
+		if (!tmp_stats) return -ENOMEM;
+
+		spin_lock_irqsave(&lp->hw_lock, flags);
+		memcpy(tmp_stats, &lp->pktStats, sizeof(lp->pktStats));
+		spin_unlock_irqrestore(&lp->hw_lock, flags);
 
+		ioc->len = sizeof(lp->pktStats);
+		if (copy_to_user(ioc->data, tmp_stats, sizeof(lp->pktStats)))
+    			status = -EFAULT;
+		kfree(tmp_stats);
 		break;
+	}
 	case EWRK3_CLR_STATS:	/* Zero out the driver statistics */
 		if (capable(CAP_NET_ADMIN)) {
-			cli();
+			spin_lock_irqsave(&lp->hw_lock, flags);
 			memset(&lp->pktStats, 0, sizeof(lp->pktStats));
-			sti();
+			spin_unlock_irqrestore(&lp->hw_lock,flags);
 		} else {
 			status = -EPERM;
 		}
@@ -1843,35 +2075,61 @@
 }
 
 #ifdef MODULE
-static struct net_device thisEthwrk;
-static int io = 0x300;		/* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
-static int irq = 5;		/* or use the insmod io= irq= options           */
-
-MODULE_PARM(io, "i");
-MODULE_PARM(irq, "i");
-MODULE_PARM_DESC(io, "EtherWORKS 3 I/O base address");
-MODULE_PARM_DESC(irq, "EtherWORKS 3 IRQ number");
+static struct net_device *ewrk3_devs[MAX_NUM_EWRK3S];
+static int ndevs;
+static int io[MAX_NUM_EWRK3S+1] = { 0x300, 0, };	/* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
+static int irq[MAX_NUM_EWRK3S+1] = { 5, 0, };		/* or use the insmod io= irq= options           */
+
+/* '21' below should really be 'MAX_NUM_EWRK3S' */
+MODULE_PARM(io, "0-21i");
+MODULE_PARM(irq, "0-21i");
+MODULE_PARM_DESC(io, "EtherWORKS 3 I/O base address(es)");
+MODULE_PARM_DESC(irq, "EtherWORKS 3 IRQ number(s)");
 
 int init_module(void)
 {
-	thisEthwrk.base_addr = io;
-	thisEthwrk.irq = irq;
-	thisEthwrk.init = ewrk3_probe;
-	if (register_netdev(&thisEthwrk) != 0)
-		return -EIO;
-	return 0;
+	int i=0;
+
+	while( io[i] && irq[i] ) {
+		ewrk3_devs[ndevs] = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+		if (!ewrk3_devs[ndevs])
+			goto error; 
+		memset(ewrk3_devs[ndevs], 0, sizeof(struct net_device));
+		ewrk3_devs[ndevs]->base_addr = io[i];
+		ewrk3_devs[ndevs]->irq = irq[i];
+		ewrk3_devs[ndevs]->init = ewrk3_probe;
+
+		if (register_netdev(ewrk3_devs[ndevs]) == 0)
+			ndevs++;
+		else
+			kfree(ewrk3_devs[ndevs]);
+
+		i++;
+	}
+
+	return ndevs ? 0 : -EIO;
+
+error:
+	cleanup_module();
+	return -ENOMEM;
 }
 
 void cleanup_module(void)
 {
-	unregister_netdev(&thisEthwrk);
-	if (thisEthwrk.priv) {
-		kfree(thisEthwrk.priv);
-		thisEthwrk.priv = NULL;
-	}
-	thisEthwrk.irq = 0;
+	int i;
 
-	release_region(thisEthwrk.base_addr, EWRK3_TOTAL_SIZE);
+	for( i=0; i<ndevs; i++ ) {
+		unregister_netdev(ewrk3_devs[i]);
+		if (ewrk3_devs[i]->priv) {
+			kfree(ewrk3_devs[i]->priv);
+			ewrk3_devs[i]->priv = NULL;
+		}
+		ewrk3_devs[i]->irq = 0;
+
+		release_region(ewrk3_devs[i]->base_addr, EWRK3_TOTAL_SIZE);
+		kfree(ewrk3_devs[i]);
+		ewrk3_devs[i] = NULL;
+	}
 }
 #endif				/* MODULE */
 MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/fealnx.c linux-2.4.20/drivers/net/fealnx.c
--- linux-2.4.19/drivers/net/fealnx.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/fealnx.c	2002-10-29 11:18:49.000000000 +0000
@@ -559,6 +559,8 @@
 	np->mii.dev = dev;
 	np->mii.mdio_read = mdio_read;
 	np->mii.mdio_write = mdio_write;
+	np->mii.phy_id_mask = 0x1f;
+	np->mii.reg_num_mask = 0x1f;
 
 	ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);
 	if (!ring_space) {
@@ -654,7 +656,7 @@
 			mdio_write(dev, np->phys[0], MII_ADVERTISE, ADVERTISE_FULL);
 		else
 			writel(ADVERTISE_FULL, dev->base_addr + ANARANLPAR);
-		np->mii.duplex_lock = 1;
+		np->mii.force_media = 1;
 	}
 
 	/* The chip-specific entries in the device structure. */
@@ -956,7 +958,7 @@
 // 89/9/1 modify,
 //   np->crvalue = 0x00e40001;    /* tx store and forward, tx/rx enable */
 	np->crvalue |= 0x00e40001;	/* tx store and forward, tx/rx enable */
-	np->mii.full_duplex = np->mii.duplex_lock;
+	np->mii.full_duplex = np->mii.force_media;
 	getlinkstatus(dev);
 	if (np->linkok)
 		getlinktype(dev);
@@ -1493,16 +1495,7 @@
 					if ((tx_status & HF) && np->mii.full_duplex == 0)
 						np->stats.tx_heartbeat_errors++;
 
-#ifdef ETHER_STATS
-					if (tx_status & EC)
-						np->stats.collisions16++;
-#endif
 				} else {
-#ifdef ETHER_STATS
-					if (tx_status & DFR)
-						np->stats.tx_deferred++;
-#endif
-
 					np->stats.tx_bytes +=
 					    ((tx_control & PKTSMask) >> PKTSShift);
 
@@ -1544,9 +1537,6 @@
 			np->stats.tx_errors += (data & 0xff000000) >> 24;
 			np->stats.tx_aborted_errors += (data & 0xff000000) >> 24;
 			np->stats.tx_window_errors += (data & 0x00ff0000) >> 16;
-#ifdef ETHER_STATS
-			np->stats.collisions16 += (data & 0xff000000) >> 24;
-#endif
 			np->stats.collisions += (data & 0x0000ffff);
 		}
 
@@ -1845,31 +1835,23 @@
 
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
+	struct netdev_private *np = dev->priv;
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+	int rc;
 
-	switch (cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
-		data->phy_id = ((struct netdev_private *) dev->priv)->phys[0] & 0x1f;
-		/* Fall Through */
-
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
-		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
-		return 0;
+	if (!netif_running(dev))
+		return -EINVAL;
 
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-		return 0;
-	default:
-		return -EOPNOTSUPP;
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
 	}
+
+	return rc;
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/gmac.c linux-2.4.20/drivers/net/gmac.c
--- linux-2.4.19/drivers/net/gmac.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/gmac.c	2002-10-29 11:18:35.000000000 +0000
@@ -246,6 +246,7 @@
 #endif
 		    	full_duplex = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_DUPLEX) != 0);
 		    	link_100 = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_SPEED) != 0);
+			netif_carrier_on(gm->dev);
 		        break;
 		      case PHY_B5400:
 		      case PHY_B5401:
@@ -260,6 +261,7 @@
 		    	full_duplex = phy_BCM5400_link_table[link][0];
 		    	link_100 = phy_BCM5400_link_table[link][1];
 		    	gigabit = phy_BCM5400_link_table[link][2];
+			netif_carrier_on(gm->dev);
 		    	break;
 		      case PHY_LXT971:
 		    	aux_stat = mii_read(gm, gm->phy_addr, MII_LXT971_STATUS2);
@@ -269,6 +271,7 @@
 #endif
 		    	full_duplex = ((aux_stat & MII_LXT971_STATUS2_FULLDUPLEX) != 0);
 		    	link_100 = ((aux_stat & MII_LXT971_STATUS2_SPEED) != 0);
+			netif_carrier_on(gm->dev);
 		    	break;
 		      default:
 		    	full_duplex = (lpar_ability & MII_ANLPA_FDAM) != 0;
@@ -296,6 +299,7 @@
 #ifdef DEBUG_PHY
 		    printk(KERN_INFO "%s:    Link down !\n", gm->dev->name);
 #endif
+			netif_carrier_off(gm->dev);
 		}
 	}
 }
@@ -1101,7 +1105,10 @@
 	
 	/* Initialize the multicast tables & promisc mode if any */
 	gmac_set_multicast(dev);
-	
+
+	/* Initialize the carrier status */
+	netif_carrier_off(dev);
+
 	/*
 	 * Check out PHY status and start auto-poll
 	 * 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/gt96100eth.c linux-2.4.20/drivers/net/gt96100eth.c
--- linux-2.4.19/drivers/net/gt96100eth.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/gt96100eth.c	2002-10-29 11:18:49.000000000 +0000
@@ -256,7 +256,7 @@
 		gt96100_delay(1);
 
 		if (--timedout == 0) {
-			printk(KERN_ERR __FUNCTION__ ": busy timeout!!\n");
+			printk(KERN_ERR "%s: busy timeout!!\n", __FUNCTION__);
 			return -ENODEV;
 		}
 	}
@@ -270,7 +270,7 @@
 		gt96100_delay(1);
 	
 		if (--timedout == 0) {
-			printk(KERN_ERR __FUNCTION__ ": timeout!!\n");
+			printk(KERN_ERR "%s: timeout!!\n", __FUNCTION__);
 			return -ENODEV;
 		}
 	}
@@ -322,7 +322,7 @@
 		gt96100_delay(1);
 	
 		if (--timedout == 0) {
-			printk(KERN_ERR __FUNCTION__ ": busy timeout!!\n");
+			printk(KERN_ERR "%s: busy timeout!!\n", __FUNCTION__);
 			return -1;
 		}
 	}
@@ -339,7 +339,7 @@
 	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
 	int i;
 
-	dbg(0, __FUNCTION__ ": txno/txni/cnt=%d/%d/%d\n",
+	dbg(0, "%s: txno/txni/cnt=%d/%d/%d\n", __FUNCTION__,
 	    gp->tx_next_out, gp->tx_next_in, gp->tx_count);
 
 	for (i=0; i<TX_RING_SIZE; i++)
@@ -352,7 +352,7 @@
 	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
 	int i;
 
-	dbg(0, __FUNCTION__ ": rxno=%d\n", gp->rx_next_out);
+	dbg(0, "%s: rxno=%d\n", __FUNCTION__, gp->rx_next_out);
 
 	for (i=0; i<RX_RING_SIZE; i++)
 		dump_rx_desc(0, dev, i);
@@ -403,9 +403,8 @@
 	unsigned char* skbdata;
     
 	if (dbg_lvl <= GT96100_DEBUG) {
-		dbg(dbg_lvl, __FUNCTION__
-		    ": skb=%p, skb->data=%p, skb->len=%d\n",
-		    skb, skb->data, skb->len);
+		dbg(dbg_lvl, "%s: skb=%p, skb->data=%p, skb->len=%d\n",
+		    __FUNCTION__, skb, skb->data, skb->len);
 
 		skbdata = (unsigned char*)KSEG1ADDR(skb->data);
     
@@ -435,11 +434,11 @@
 	tblEntry1 |= (u32)addr[4] << 11;
 	tblEntry1 |= (u32)addr[3] << 19;
 	tblEntry1 |= ((u32)addr[2] & 0x1f) << 27;
-	dbg(3, __FUNCTION__ ": tblEntry1=%x\n", tblEntry1);
+	dbg(3, "%s: tblEntry1=%x\n", __FUNCTION__, tblEntry1);
 	tblEntry0 = ((u32)addr[2] >> 5) & 0x07;
 	tblEntry0 |= (u32)addr[1] << 3;
 	tblEntry0 |= (u32)addr[0] << 11;
-	dbg(3, __FUNCTION__ ": tblEntry0=%x\n", tblEntry0);
+	dbg(3, "%s: tblEntry0=%x\n", __FUNCTION__, tblEntry0);
 
 #if 0
 
@@ -453,7 +452,7 @@
 			((ctmp&0x20)<<1) | ((ctmp&0x40)>>1);
 	}
 
-	dump_hw_addr(3, dev, __FUNCTION__ ": nib swap/invt addr=", hash_ea);
+	dump_hw_addr(3, dev, "%s: nib swap/invt addr=", __FUNCTION__, hash_ea);
     
 	if (gp->hash_mode == 0) {
 		hashResult = ((u16)hash_ea[0] & 0xfc) << 7;
@@ -467,19 +466,19 @@
 		return -1; // don't support hash mode 1
 	}
 
-	dbg(3, __FUNCTION__ ": hashResult=%x\n", hashResult);
+	dbg(3, "%s: hashResult=%x\n", __FUNCTION__, hashResult);
 
 	tblEntryAddr =
 		(u32 *)(&gp->hash_table[((u32)hashResult & 0x7ff) << 3]);
     
-	dbg(3, __FUNCTION__ ": tblEntryAddr=%p\n", tblEntryAddr);
+	dbg(3, "%s: tblEntryAddr=%p\n", tblEntryAddr, __FUNCTION__);
 
 	for (i=0; i<HASH_HOP_NUMBER; i++) {
 		if ((*tblEntryAddr & hteValid) &&
 		    !(*tblEntryAddr & hteSkip)) {
 			// This entry is already occupied, go to next entry
 			tblEntryAddr += 2;
-			dbg(3, __FUNCTION__ ": skipping to %p\n",
+			dbg(3, "%s: skipping to %p\n", __FUNCTION__, 
 			    tblEntryAddr);
 		} else {
 			memset(tblEntryAddr, 0, 8);
@@ -490,7 +489,7 @@
 	}
 
 	if (i >= HASH_HOP_NUMBER) {
-		err(__FUNCTION__ ": expired!\n");
+		err("%s: expired!\n", __FUNCTION__);
 		return -1; // Couldn't find an unused entry
 	}
 
@@ -552,7 +551,7 @@
 	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
 	int timedout = 100; // wait up to 100 msec for hard stop to complete
 
-	dbg(3, __FUNCTION__ "\n");
+	dbg(3, "%s\n", __FUNCTION__);
 
 	// Return if neither Rx or Tx abort bits are set
 	if (!(abort_bits & (sdcmrAR | sdcmrAT)))
@@ -566,7 +565,7 @@
 	// abort any Rx/Tx DMA immediately
 	GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, abort_bits);
 
-	dbg(3, __FUNCTION__ ": SDMA comm = %x\n",
+	dbg(3, "%s: SDMA comm = %x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM));
 
 	// wait for abort to complete
@@ -575,7 +574,7 @@
 		gt96100_delay(1);
 	
 		if (--timedout == 0) {
-			err(__FUNCTION__ ": timeout!!\n");
+			err("%s: timeout!!\n", __FUNCTION__);
 			break;
 		}
 	}
@@ -589,7 +588,7 @@
 {
 	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
 
-	dbg(3, __FUNCTION__ "\n");
+	dbg(3, "%s\n", __FUNCTION__);
 
 	disable_ether_irq(dev);
 
@@ -701,8 +700,7 @@
 	struct net_device *dev = NULL;
     
 	if (gtif->irq < 0) {
-		printk(KERN_ERR __FUNCTION__
-		       ": irq unknown - probing not supported\n");
+		printk(KERN_ERR "%s: irq unknown - probing not supported\n", __FUNCTION_);
 		return -ENODEV;
 	}
     
@@ -726,13 +724,12 @@
 	// probe for the external PHY
 	if ((phy_id1 = read_MII(phy_addr, 2)) <= 0 ||
 	    (phy_id2 = read_MII(phy_addr, 3)) <= 0) {
-		printk(KERN_ERR __FUNCTION__
-		       ": no PHY found on MII%d\n", port_num);
+		printk(KERN_ERR "%s: no PHY found on MII%d\n", __FUNCTION__, port_num);
 		return -ENODEV;
 	}
 	
 	if (!request_region(gtif->iobase, GT96100_ETH_IO_SIZE, "GT96100ETH")) {
-		printk(KERN_ERR __FUNCTION__ ": request_region failed\n");
+		printk(KERN_ERR "%s: request_region failed\n", __FUNCTION__);
 		return -EBUSY;
 	}
 
@@ -745,7 +742,7 @@
 	dev->irq = gtif->irq;
 
 	if ((retval = parse_mac_addr(dev, gtif->mac_str))) {
-		err(__FUNCTION__ ": MAC address parse failed\n");
+		err("%s: MAC address parse failed\n", __FUNCTION__);
 		retval = -EINVAL;
 		goto free_region;
 	}
@@ -809,7 +806,7 @@
 		}
 	}
     
-	dbg(3, __FUNCTION__ ": rx_ring=%p, tx_ring=%p\n",
+	dbg(3, "%s: rx_ring=%p, tx_ring=%p\n", __FUNCTION__,
 	    gp->rx_ring, gp->tx_ring);
 
 	// Allocate Rx Hash Table
@@ -826,7 +823,7 @@
 		}
 	}
     
-	dbg(3, __FUNCTION__ ": hash=%p\n", gp->hash_table);
+	dbg(3, "%s: hash=%p\n", __FUNCTION__, gp->hash_table);
 
 	spin_lock_init(&gp->lock);
     
@@ -849,7 +846,7 @@
 	if (dev->priv != NULL)
 		kfree (dev->priv);
 	kfree (dev);
-	err(__FUNCTION__ " failed.  Returns %d\n", retval);
+	err("%s failed.  Returns %d\n", __FUNCTION__, retval);
 	return retval;
 }
 
@@ -956,10 +953,10 @@
 	u32 tmp;
 	u16 mii_reg;
     
-	dbg(3, __FUNCTION__ ": dev=%p\n", dev);
-	dbg(3, __FUNCTION__ ": scs10_lo=%4x, scs10_hi=%4x\n",
+	dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);
+	dbg(3, "%s: scs10_lo=%4x, scs10_hi=%4x\n", __FUNCTION__, 
 	    GT96100_READ(0x8), GT96100_READ(0x10));
-	dbg(3, __FUNCTION__ ": scs32_lo=%4x, scs32_hi=%4x\n",
+	dbg(3, "%s: scs32_lo=%4x, scs32_hi=%4x\n", __FUNCTION__,
 	    GT96100_READ(0x18), GT96100_READ(0x20));
     
 	// Stop and disable Port
@@ -974,7 +971,7 @@
 	tmp |= (1<<31);
 #endif
 	GT96100_WRITE(GT96100_CIU_ARBITER_CONFIG, tmp);
-	dbg(3, __FUNCTION__ ": CIU Config=%x/%x\n",
+	dbg(3, "%s: CIU Config=%x/%x\n", __FUNCTION__, 
 	    tmp, GT96100_READ(GT96100_CIU_ARBITER_CONFIG));
 
 	// Set routing.
@@ -999,19 +996,19 @@
 	gt96100_add_hash_entry(dev, dev->dev_addr);
 	// Set-up DMA ptr to hash table
 	GT96100ETH_WRITE(gp, GT96100_ETH_HASH_TBL_PTR, gp->hash_table_dma);
-	dbg(3, __FUNCTION__ ": Hash Tbl Ptr=%x\n",
+	dbg(3, "%s: Hash Tbl Ptr=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_HASH_TBL_PTR));
 
 	// Setup Tx
 	reset_tx(dev);
 
-	dbg(3, __FUNCTION__ ": Curr Tx Desc Ptr0=%x\n",
+	dbg(3, "%s: Curr Tx Desc Ptr0=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0));
 
 	// Setup Rx
 	reset_rx(dev);
 
-	dbg(3, __FUNCTION__ ": 1st/Curr Rx Desc Ptr0=%x/%x\n",
+	dbg(3, "%s: 1st/Curr Rx Desc Ptr0=%x/%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_1ST_RX_DESC_PTR0),
 	    GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0));
 
@@ -1023,7 +1020,7 @@
 	mii_reg |= 2;  /* enable mii interrupt */
 	write_MII(gp->phy_addr, 0x11, mii_reg);
 	
-	dbg(3, __FUNCTION__ ": PhyAD=%x\n",
+	dbg(3, "%s: PhyAD=%x\n", __FUNCTION__,
 	    GT96100_READ(GT96100_ETH_PHY_ADDR_REG));
 
 	// setup DMA
@@ -1038,17 +1035,17 @@
 			 sdcrBLMR | sdcrBLMT |
 			 (0xf<<sdcrRCBit) | sdcrRIFB | (3<<sdcrBSZBit));
 #endif
-	dbg(3, __FUNCTION__ ": SDMA Config=%x\n",
+	dbg(3, "%s: SDMA Config=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_SDMA_CONFIG));
 
 	// start Rx DMA
 	GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD);
-	dbg(3, __FUNCTION__ ": SDMA Comm=%x\n",
+	dbg(3, "%s: SDMA Comm=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM));
     
 	// enable this port (set hash size to 1/2K)
 	GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS);
-	dbg(3, __FUNCTION__ ": Port Config=%x\n",
+	dbg(3, "%s: Port Config=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG));
     
 	/*
@@ -1068,7 +1065,7 @@
 			 pcxrFCTL | pcxrFCTLen | pcxrFLP |
 			 pcxrPRIOrxOverride | pcxrMIBclrMode);
     
-	dbg(3, __FUNCTION__ ": Port Config Ext=%x\n",
+	dbg(3, "%s: Port Config Ext=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG_EXT));
 
 	netif_start_queue(dev);
@@ -1090,7 +1087,7 @@
     
 	MOD_INC_USE_COUNT;
 
-	dbg(2, __FUNCTION__ ": dev=%p\n", dev);
+	dbg(2, "%s: dev=%p\n", __FUNCTION__, dev);
 
 	// Initialize and startup the GT-96100 ethernet port
 	if ((retval = gt96100_init(dev))) {
@@ -1107,7 +1104,7 @@
 		return retval;
 	}
 	
-	dbg(2, __FUNCTION__ ": Initialization done.\n");
+	dbg(2, "%s: Initialization done.\n", __FUNCTION__);
 
 	return 0;
 }
@@ -1115,7 +1112,7 @@
 static int
 gt96100_close(struct net_device *dev)
 {
-	dbg(3, __FUNCTION__ ": dev=%p\n", dev);
+	dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);
 
 	// stop the device
 	if (netif_device_present(dev)) {
@@ -1141,7 +1138,7 @@
 
 	nextIn = gp->tx_next_in;
 
-	dbg(3, __FUNCTION__ ": nextIn=%d\n", nextIn);
+	dbg(3, "%s: nextIn=%d\n", __FUNCTION__, nextIn);
     
 	if (gp->tx_count >= TX_RING_SIZE) {
 		warn("Tx Ring full, pkt dropped.\n");
@@ -1151,14 +1148,14 @@
 	}
     
 	if (!(gp->last_psr & psrLink)) {
-		err(__FUNCTION__ ": Link down, pkt dropped.\n");
+		err("%s: Link down, pkt dropped.\n", __FUNCTION__);
 		gp->stats.tx_dropped++;
 		spin_unlock_irqrestore(&gp->lock, flags);
 		return 1;
 	}
     
 	if (dma32_to_cpu(gp->tx_ring[nextIn].cmdstat) & txOwn) {
-		err(__FUNCTION__ ": device owns descriptor, pkt dropped.\n");
+		err("%s: device owns descriptor, pkt dropped.\n", __FUNCTION__);
 		gp->stats.tx_dropped++;
 		// stop the queue, so Tx timeout can fix it
 		netif_stop_queue(dev);
@@ -1211,7 +1208,7 @@
 	gt96100_rd_t *rd;
 	u32 cmdstat;
     
-	dbg(3, __FUNCTION__ ": dev=%p, status=%x\n", dev, status);
+	dbg(3, "%s: dev=%p, status=%x\n", __FUNCTION__, dev, status);
 
 	cdp = (GT96100ETH_READ(gp, GT96100_ETH_1ST_RX_DESC_PTR0)
 	       - gp->rx_ring_dma) / sizeof(gt96100_rd_t);
@@ -1226,7 +1223,7 @@
 		rd = &gp->rx_ring[nextOut];
 		cmdstat = dma32_to_cpu(rd->cmdstat);
 	
-		dbg(4, __FUNCTION__ ": Rx desc cmdstat=%x, nextOut=%d\n",
+		dbg(4, "%s: Rx desc cmdstat=%x, nextOut=%d\n", __FUNCTION__,
 		    cmdstat, nextOut);
 
 		if (cmdstat & (u32)rxOwn) {
@@ -1268,8 +1265,7 @@
 				 * the deal with this packet? Good question,
 				 * let's dump it out.
 				 */
-				err(__FUNCTION__
-				    ": desc not first and last!\n");
+				err("%s: desc not first and last!\n", __FUNCTION__);
 				dump_rx_desc(0, dev, nextOut);
 			}
 			cmdstat |= (u32)rxOwn;
@@ -1283,8 +1279,7 @@
 		/* Create new skb. */
 		skb = dev_alloc_skb(pkt_len+2);
 		if (skb == NULL) {
-			err(__FUNCTION__
-			    ": Memory squeeze, dropping packet.\n");
+			err("%s: Memory squeeze, dropping packet.\n", __FUNCTION__);
 			gp->stats.rx_dropped++;
 			cmdstat |= (u32)rxOwn;
 			rd->cmdstat = cpu_to_dma32(cmdstat);
@@ -1306,7 +1301,7 @@
 	}
     
 	if (nextOut == gp->rx_next_out)
-		dbg(3, __FUNCTION__ ": RxCDP did not increment?\n");
+		dbg(3, "%s: RxCDP did not increment?\n", __FUNCTION__);
 
 	gp->rx_next_out = nextOut;
 	return 0;
@@ -1334,7 +1329,7 @@
 		td = &gp->tx_ring[nextOut];
 		cmdstat = dma32_to_cpu(td->cmdstat);
 	
-		dbg(3, __FUNCTION__ ": Tx desc cmdstat=%x, nextOut=%d\n",
+		dbg(3, "%s: Tx desc cmdstat=%x, nextOut=%d\n", __FUNCTION__,
 		    cmdstat, nextOut);
 	
 		if (cmdstat & (u32)txOwn) {
@@ -1347,7 +1342,7 @@
 	
 		// increment Tx error stats
 		if (cmdstat & (u32)txErrorSummary) {
-			dbg(2, __FUNCTION__ ": Tx error, cmdstat = %x\n",
+			dbg(2, "%s: Tx error, cmdstat = %x\n", __FUNCTION__,
 			    cmdstat);
 			gp->stats.tx_errors++;
 			if (cmdstat & (u32)txReTxLimit)
@@ -1368,8 +1363,7 @@
 			gp->tx_full = 0;
 			if (gp->last_psr & psrLink) {
 				netif_wake_queue(dev);
-				dbg(2, __FUNCTION__
-				    ": Tx Ring was full, queue waked\n");
+				dbg(2, "%s: Tx Ring was full, queue waked\n", __FUNCTION_);
 			}
 		}
 	
@@ -1378,24 +1372,24 @@
 	
 		// free the skb
 		if (gp->tx_skbuff[nextOut]) {
-			dbg(3, __FUNCTION__ ": good Tx, skb=%p\n",
+			dbg(3, "%s: good Tx, skb=%p\n", __FUNCTION__,
 			    gp->tx_skbuff[nextOut]);
 			dev_kfree_skb_irq(gp->tx_skbuff[nextOut]);
 			gp->tx_skbuff[nextOut] = NULL;
 		} else {
-			err(__FUNCTION__ ": no skb!\n");
+			err("%s: no skb!\n", __FUNCTION__);
 		}
 	}
 
 	gp->tx_next_out = nextOut;
 
 	if (gt96100_check_tx_consistent(gp)) {
-		err(__FUNCTION__ ": Tx queue inconsistent!\n");
+		err("%s: Tx queue inconsistent!\n", __FUNCTION__);
 	}
     
 	if ((status & icrTxEndLow) && gp->tx_count != 0) {
 		// we must restart the DMA
-		dbg(3, __FUNCTION__ ": Restarting Tx DMA\n");
+		dbg(3, "%s: Restarting Tx DMA\n", __FUNCTION__);
 		GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM,
 				 sdcmrERD | sdcmrTXDL);
 	}
@@ -1410,11 +1404,11 @@
 	u32 status;
     
 	if (dev == NULL) {
-		err(__FUNCTION__ ": null dev ptr\n");
+		err("%s: null dev ptr\n", __FUNCTION__);
 		return;
 	}
 
-	dbg(3, __FUNCTION__ ": entry, icr=%x\n",
+	dbg(3, "%s: entry, icr=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE));
 
 	spin_lock(&gp->lock);
@@ -1449,13 +1443,13 @@
 		
 				if ((psr & psrLink) && !gp->tx_full &&
 				    netif_queue_stopped(dev)) {
-					dbg(0, __FUNCTION__
-					    ": Link up, waking queue.\n");
+					dbg(0, ": Link up, waking queue.\n",
+					    __FUNCTION_);
 					netif_wake_queue(dev);
 				} else if (!(psr & psrLink) &&
 					   !netif_queue_stopped(dev)) {
-					dbg(0, __FUNCTION__
-					    "Link down, stopping queue.\n");
+					dbg(0, "Link down, stopping queue.\n",
+					    __FUNCTION__);
 					netif_stop_queue(dev);
 				}
 
@@ -1475,13 +1469,13 @@
 	
 		// Now check TX errors (RX errors were handled in gt96100_rx)
 		if (status & icrTxErrorLow) {
-			err(__FUNCTION__ ": Tx resource error\n");
+			err("%s: Tx resource error\n", __FUNCTION__);
 			if (--gp->intr_work_done == 0)
 				break;
 		}
 	
 		if (status & icrTxUdr) {
-			err(__FUNCTION__ ": Tx underrun error\n");
+			err("%s: Tx underrun error\n", __FUNCTION__);
 			if (--gp->intr_work_done == 0)
 				break;
 		}
@@ -1490,10 +1484,10 @@
 	if (gp->intr_work_done == 0) {
 		// ACK any remaining pending interrupts
 		GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, 0);
-		dbg(3, __FUNCTION__ ": hit max work\n");
+		dbg(3, "%s: hit max work\n", __FUNCTION__);
 	}
     
-	dbg(3, __FUNCTION__ ": exit, icr=%x\n",
+	dbg(3, "%s: exit, icr=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE));
 
 	spin_unlock(&gp->lock);
@@ -1532,7 +1526,7 @@
 	unsigned long flags;
 	//struct dev_mc_list *mcptr;
     
-	dbg(3, __FUNCTION__ ": dev=%p, flags=%x\n", dev, dev->flags);
+	dbg(3, "%s: dev=%p, flags=%x\n", __FUNCTION__, dev, dev->flags);
 
 	// stop the Receiver DMA
 	abort(dev, sdcmrAR);
@@ -1575,7 +1569,7 @@
 	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
 	unsigned long flags;
 
-	dbg(3, __FUNCTION__ ": dev=%p\n", dev);
+	dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);
 
 	if (netif_device_present(dev)) {
 		spin_lock_irqsave (&gp->lock, flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/hamachi.c linux-2.4.20/drivers/net/hamachi.c
--- linux-2.4.19/drivers/net/hamachi.c	2002-02-25 19:37:59.000000000 +0000
+++ linux-2.4.20/drivers/net/hamachi.c	2002-10-29 11:18:40.000000000 +0000
@@ -210,8 +210,10 @@
 /* Condensed bus+endian portability operations. */
 #if ADDRLEN == 64
 #define cpu_to_leXX(addr)	cpu_to_le64(addr)
+#define desc_to_virt(addr) bus_to_virt(le64_to_cpu(addr))
 #else 
 #define cpu_to_leXX(addr)	cpu_to_le32(addr)
+#define desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
 #endif   
 
 
@@ -1544,7 +1546,7 @@
 			break;
 		pci_dma_sync_single(hmp->pci_dev, desc->addr, hmp->rx_buf_sz, 
 			PCI_DMA_FROMDEVICE);
-		buf_addr = (u8 *)hmp->rx_ring + entry*sizeof(*desc);
+		buf_addr = desc_to_virt(desc->addr);
 		frame_status = le32_to_cpu(get_unaligned((s32*)&(buf_addr[data_size - 12])));
 		if (hamachi_debug > 4)
 			printk(KERN_DEBUG "  hamachi_rx() status was %8.8x.\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/hamradio/Config.in linux-2.4.20/drivers/net/hamradio/Config.in
--- linux-2.4.19/drivers/net/hamradio/Config.in	1999-10-02 14:38:27.000000000 +0000
+++ linux-2.4.20/drivers/net/hamradio/Config.in	2002-10-29 11:18:30.000000000 +0000
@@ -4,8 +4,10 @@
 dep_tristate 'Serial port 6PACK driver' CONFIG_6PACK $CONFIG_AX25
 dep_tristate 'BPQ Ethernet driver' CONFIG_BPQETHER $CONFIG_AX25
     
+if [ "$CONFIG_ISA" = "y" ]; then
 dep_tristate 'High-speed (DMA) SCC driver for AX.25' CONFIG_DMASCC $CONFIG_AX25
 dep_tristate 'Z8530 SCC driver' CONFIG_SCC $CONFIG_AX25
+fi
 if [ "$CONFIG_SCC" != "n" ]; then
    bool '  additional delay for PA0HZP OptoSCC compatible boards' CONFIG_SCC_DELAY
    bool '  support for TRX that feedback the tx signal to rx' CONFIG_SCC_TRXECHO
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/hamradio/baycom_epp.c linux-2.4.20/drivers/net/hamradio/baycom_epp.c
--- linux-2.4.19/drivers/net/hamradio/baycom_epp.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/hamradio/baycom_epp.c	2002-10-29 11:18:51.000000000 +0000
@@ -481,7 +481,7 @@
 ({                                             \
         if (!(notbitstream & (0x1f0 << j)))    \
                 goto stuff##j;                 \
-  encodeend##j:                                \
+  encodeend##j: ;                              \
 })
 
 #define ENCODEITERB(j)                                          \
@@ -715,7 +715,7 @@
                 goto flgabrt##j;                                              \
         if ((bitstream & (0x1f8 << j)) == (0xf8 << j))   /* stuffed bit */    \
                 goto stuff##j;                                                \
-  enditer##j:                                                                 \
+  enditer##j: ;                                                               \
 })
 
 #define DECODEITERB(j)                                                                 \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/hamradio/scc.c linux-2.4.20/drivers/net/hamradio/scc.c
--- linux-2.4.19/drivers/net/hamradio/scc.c	2002-02-25 19:37:59.000000000 +0000
+++ linux-2.4.20/drivers/net/hamradio/scc.c	2002-10-29 11:18:36.000000000 +0000
@@ -2128,7 +2128,7 @@
 
 static void __exit scc_cleanup_driver(void)
 {
-	long flags;
+	unsigned long flags;
 	io_port ctrl;
 	int k;
 	struct scc_channel *scc;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/hamradio/soundmodem/sm_sbc.c linux-2.4.20/drivers/net/hamradio/soundmodem/sm_sbc.c
--- linux-2.4.19/drivers/net/hamradio/soundmodem/sm_sbc.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/hamradio/soundmodem/sm_sbc.c	2002-10-29 11:18:33.000000000 +0000
@@ -47,36 +47,7 @@
  */
 #include <linux/version.h>
 
-#if LINUX_VERSION_CODE >= 0x20100
 #include <asm/uaccess.h>
-#else
-#include <asm/segment.h>
-#include <linux/mm.h>
-
-#undef put_user
-#undef get_user
-
-#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
-#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-
-static inline int copy_from_user(void *to, const void *from, unsigned long n)
-{
-        int i = verify_area(VERIFY_READ, from, n);
-        if (i)
-                return i;
-        memcpy_fromfs(to, from, n);
-        return 0;
-}
-
-static inline int copy_to_user(void *to, const void *from, unsigned long n)
-{
-        int i = verify_area(VERIFY_WRITE, to, n);
-        if (i)
-                return i;
-        memcpy_tofs(to, from, n);
-        return 0;
-}
-#endif
 
 /* --------------------------------------------------------------------- */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/hamradio/soundmodem/sm_wss.c linux-2.4.20/drivers/net/hamradio/soundmodem/sm_wss.c
--- linux-2.4.19/drivers/net/hamradio/soundmodem/sm_wss.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/hamradio/soundmodem/sm_wss.c	2002-10-29 11:18:39.000000000 +0000
@@ -45,37 +45,7 @@
  * This will go in 2.2
  */
 #include <linux/version.h>
-
-#if LINUX_VERSION_CODE >= 0x20100
 #include <asm/uaccess.h>
-#else
-#include <asm/segment.h>
-#include <linux/mm.h>
-
-#undef put_user
-#undef get_user
-
-#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
-#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-
-static inline int copy_from_user(void *to, const void *from, unsigned long n)
-{
-        int i = verify_area(VERIFY_READ, from, n);
-        if (i)
-                return i;
-        memcpy_fromfs(to, from, n);
-        return 0;
-}
-
-static inline int copy_to_user(void *to, const void *from, unsigned long n)
-{
-        int i = verify_area(VERIFY_WRITE, to, n);
-        if (i)
-                return i;
-        memcpy_tofs(to, from, n);
-        return 0;
-}
-#endif
 
 /* --------------------------------------------------------------------- */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/hamradio/yam.c linux-2.4.20/drivers/net/hamradio/yam.c
--- linux-2.4.19/drivers/net/hamradio/yam.c	2002-02-25 19:37:59.000000000 +0000
+++ linux-2.4.20/drivers/net/hamradio/yam.c	2002-10-29 11:18:49.000000000 +0000
@@ -840,6 +840,7 @@
 	struct yam_port *yp = (struct yam_port *) dev->priv;
 	enum uart u;
 	int i;
+	int ret=0;
 
 	printk(KERN_INFO "Trying %s at iobase 0x%lx irq %u\n", dev->name, dev->base_addr, dev->irq);
 
@@ -849,24 +850,27 @@
 		dev->irq < 2 || dev->irq > 15) {
 		return -ENXIO;
 	}
-	if (check_region(dev->base_addr, YAM_EXTENT)) {
+	if (!request_region(dev->base_addr, YAM_EXTENT, dev->name))
+	{
 		printk(KERN_ERR "%s: cannot 0x%lx busy\n", dev->name, dev->base_addr);
 		return -EACCES;
 	}
 	if ((u = yam_check_uart(dev->base_addr)) == c_uart_unknown) {
 		printk(KERN_ERR "%s: cannot find uart type\n", dev->name);
-		return -EIO;
+		ret = -EIO;
+		goto out_release_base;
 	}
 	if (fpga_download(dev->base_addr, yp->bitrate)) {
 		printk(KERN_ERR "%s: cannot init FPGA\n", dev->name);
-		return -EIO;
+		ret = -EIO;
+		goto out_release_base;
 	}
 	outb(0, IER(dev->base_addr));
 	if (request_irq(dev->irq, yam_interrupt, SA_INTERRUPT | SA_SHIRQ, dev->name, dev)) {
 		printk(KERN_ERR "%s: irq %d busy\n", dev->name, dev->irq);
-		return -EBUSY;
+		ret = -EBUSY;
+		goto out_release_base;
 	}
-	request_region(dev->base_addr, YAM_EXTENT, dev->name);
 
 	yam_set_uart(dev);
 
@@ -883,6 +887,10 @@
 	printk(KERN_INFO "%s at iobase 0x%lx irq %u uart %s\n", dev->name, dev->base_addr, dev->irq,
 		   uart_str[u]);
 	return 0;
+
+out_release_base:
+	release_region(dev->base_addr, YAM_EXTENT);
+	return ret;
 }
 
 /* --------------------------------------------------------------------- */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/hp-plus.c linux-2.4.20/drivers/net/hp-plus.c
--- linux-2.4.19/drivers/net/hp-plus.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/hp-plus.c	2002-10-29 11:18:32.000000000 +0000
@@ -351,7 +351,7 @@
 	outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
 	isa_memcpy_fromio(hdr, dev->mem_start, sizeof(struct e8390_pkt_hdr));
 	outw(option_reg, ioaddr + HPP_OPTION);
-	hdr->count = (hdr->count + 3) & ~3;	/* Round up allocation. */
+	hdr->count = (le16_to_cpu(hdr->count) + 3) & ~3;	/* Round up allocation. */
 }
 
 static void
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/hp100.c linux-2.4.20/drivers/net/hp100.c
--- linux-2.4.19/drivers/net/hp100.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/hp100.c	2002-10-29 11:18:37.000000000 +0000
@@ -237,6 +237,9 @@
 	/* 10/100 ISA card with Cascade chip */
 	{0x5019F022, "HP J2573", HP100_BUS_ISA},
 
+	/* 10/100 EISA card with AT&T chip */
+	{0x9019f022, "HP J2577", HP100_BUS_EISA },
+
 	/* 10/100 PCI card - old J2585A */
 	{0x1030103c, "HP J2585A", HP100_BUS_PCI},
 
@@ -1880,7 +1883,7 @@
 #endif
 
 		/* Now we allocate the skb and transfer the data into it. */
-		skb = dev_alloc_skb(pkt_len);
+		skb = dev_alloc_skb(pkt_len+2);
 		if (skb == NULL) {	/* Not enough memory->drop packet */
 #ifdef HP100_DEBUG
 			printk("hp100: %s: rx: couldn't allocate a sk_buff of size %d\n",
@@ -1891,10 +1894,12 @@
 
 			u_char *ptr;
 
+			skb_reserve(skb,2);
 			skb->dev = dev;
 
 			/* ptr to start of the sk_buff data area */
-			ptr = (u_char *) skb_put(skb, pkt_len);
+			skb_put(skb, pkt_len);
+			ptr = skb->data;
 
 			/* Now transfer the data from the card into that area */
 			if (lp->mode == 2) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/hplance.c linux-2.4.20/drivers/net/hplance.c
--- linux-2.4.19/drivers/net/hplance.c	2001-10-17 04:56:29.000000000 +0000
+++ linux-2.4.20/drivers/net/hplance.c	2002-10-29 11:18:40.000000000 +0000
@@ -58,9 +58,9 @@
 static int hplance_init(struct net_device *dev, int scode);
 static int hplance_open(struct net_device *dev);
 static int hplance_close(struct net_device *dev);
-static void hplance_writerap(struct hplance_private *lp, unsigned short value);
-static void hplance_writerdp(struct hplance_private *lp, unsigned short value);
-static unsigned short hplance_readrdp(struct hplance_private *lp);
+static void hplance_writerap(void *priv, unsigned short value);
+static void hplance_writerdp(void *priv, unsigned short value);
+static unsigned short hplance_readrdp(void *priv);
 
 #ifdef MODULE
 static struct hplance_private *root_hplance_dev;
@@ -100,8 +100,7 @@
 /* Initialise a single lance board at the given select code */
 static int __init hplance_init(struct net_device *dev, int scode)
 {
-        /* const char *name = dio_scodetoname(scode); */
-        static const char name[] = "HP LANCE";
+        const char *name = dio_scodetoname(scode);
         void *va = dio_scodetoviraddr(scode);
         struct hplance_private *lp;
         int i;
@@ -118,10 +117,10 @@
 #endif
 	SET_MODULE_OWNER(dev);
 
-        printk("%s: HP LANCE; select code %d, addr", dev->name, scode);
+        printk("%s: %s; select code %d, addr", dev->name, name, scode);
 
         /* reset the board */
-        writeb(0xff,va+DIO_IDOFF);
+        out_8(va+DIO_IDOFF, 0xff);
         udelay(100);                              /* ariba! ariba! udelay! udelay! */
 
         /* Fill the dev fields */
@@ -138,8 +137,8 @@
                 /* The NVRAM holds our ethernet address, one nibble per byte,
                  * at bytes NVRAMOFF+1,3,5,7,9...
                  */
-                dev->dev_addr[i] = ((readb(va + HPLANCE_NVRAMOFF + i*4 + 1) & 0xF) << 4)
-                        | (readb(va + HPLANCE_NVRAMOFF + i*4 + 3) & 0xF);
+                dev->dev_addr[i] = ((in_8(va + HPLANCE_NVRAMOFF + i*4 + 1) & 0xF) << 4)
+                        | (in_8(va + HPLANCE_NVRAMOFF + i*4 + 3) & 0xF);
                 printk("%c%2.2x", i == 0 ? ' ' : ':', dev->dev_addr[i]);
         }
         
@@ -175,25 +174,28 @@
 /* This is disgusting. We have to check the DIO status register for ack every
  * time we read or write the LANCE registers.
  */
-static void hplance_writerap(struct hplance_private *lp, unsigned short value)
+static void hplance_writerap(void *priv, unsigned short value)
 {
+	struct hplance_private *lp = (struct hplance_private *)priv;
         struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
         do {
                 lp->lance.ll->rap = value;
         } while ((hpregs->status & LE_ACK) == 0);
 }
 
-static void hplance_writerdp(struct hplance_private *lp, unsigned short value)
+static void hplance_writerdp(void *priv, unsigned short value)
 {
+	struct hplance_private *lp = (struct hplance_private *)priv;
         struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
         do {
                 lp->lance.ll->rdp = value;
         } while ((hpregs->status & LE_ACK) == 0);
 }
 
-static unsigned short hplance_readrdp(struct hplance_private *lp)
+static unsigned short hplance_readrdp(void *priv)
 {
         unsigned short val;
+	struct hplance_private *lp = (struct hplance_private *)priv;
         struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
         do {
                 val = lp->lance.ll->rdp;
@@ -211,7 +213,7 @@
         if (status)
                 return status;
         /* enable interrupts at board level. */
-        writeb(LE_IE, &(hpregs->status));
+        out_8(&(hpregs->status), LE_IE);
 
         return 0;
 }
@@ -220,7 +222,7 @@
 {
         struct hplance_private *lp = (struct hplance_private *)dev->priv;
         struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
-        writeb(0,&(hpregs->status));              /* disable interrupts at boardlevel */
+        out_8(&(hpregs->status), 8);              /* disable interrupts at boardlevel */
         lance_close(dev);
         return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/irda/Config.in linux-2.4.20/drivers/net/irda/Config.in
--- linux-2.4.19/drivers/net/irda/Config.in	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/irda/Config.in	2002-10-29 11:18:35.000000000 +0000
@@ -13,10 +13,15 @@
    dep_tristate '  Tekram IrMate 210B dongle' CONFIG_TEKRAM_DONGLE $CONFIG_IRDA
    dep_tristate '  Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRDA
    dep_tristate '  Parallax LiteLink dongle' CONFIG_LITELINK_DONGLE $CONFIG_IRDA
+   dep_tristate '  Microchip MCP2120' CONFIG_MCP2120_DONGLE $CONFIG_IRDA
    dep_tristate '  Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA   
    if [ "$CONFIG_ARCH_EP7211" = "y" ]; then
       dep_tristate '  EP7211 I/R support' CONFIG_EP7211_IR $CONFIG_IRDA
    fi
+   if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+      dep_tristate '  ACTiSYS IR-200L dongle (Experimental)' CONFIG_ACT200L_DONGLE $CONFIG_IRDA
+      dep_tristate '  Mobile Action MA600 dongle (Experimental)' CONFIG_MA600_DONGLE $CONFIG_IRDA
+   fi
 fi
 
 comment 'FIR device drivers'
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/irda/Makefile linux-2.4.20/drivers/net/irda/Makefile
--- linux-2.4.19/drivers/net/irda/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/irda/Makefile	2002-10-29 11:18:40.000000000 +0000
@@ -29,5 +29,8 @@
 obj-$(CONFIG_OLD_BELKIN_DONGLE)	+= old_belkin.o
 obj-$(CONFIG_EP7211_IR)		+= ep7211_ir.o
 obj-$(CONFIG_AU1000_FIR)	+= au1k_ir.o
+obj-$(CONFIG_MCP2120_DONGLE)	+= mcp2120.o
+obj-$(CONFIG_ACT200L_DONGLE)	+= act200l.o
+obj-$(CONFIG_MA600_DONGLE)	+= ma600.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/irda/act200l.c linux-2.4.20/drivers/net/irda/act200l.c
--- linux-2.4.19/drivers/net/irda/act200l.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/irda/act200l.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,299 @@
+/*********************************************************************
+ *
+ * Filename:      act200l.c
+ * Version:       0.8
+ * Description:   Implementation for the ACTiSYS ACT-IR200L dongle
+ * Status:        Experimental.
+ * Author:        SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>
+ * Created at:    Fri Aug  3 17:35:42 2001
+ * Modified at:   Fri Aug 17 10:22:40 2001
+ * Modified by:   SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>
+ *
+ *     Copyright (c) 2001 SHIMIZU Takuya, All Rights Reserved.
+ *
+ *     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.
+ *
+ ********************************************************************/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irda_device.h>
+#include <net/irda/irtty.h>
+
+static int  act200l_reset(struct irda_task *task);
+static void act200l_open(dongle_t *self, struct qos_info *qos);
+static void act200l_close(dongle_t *self);
+static int  act200l_change_speed(struct irda_task *task);
+
+/* Regsiter 0: Control register #1 */
+#define ACT200L_REG0    0x00
+#define ACT200L_TXEN    0x01 /* Enable transmitter */
+#define ACT200L_RXEN    0x02 /* Enable receiver */
+
+/* Register 1: Control register #2 */
+#define ACT200L_REG1    0x10
+#define ACT200L_LODB    0x01 /* Load new baud rate count value */
+#define ACT200L_WIDE    0x04 /* Expand the maximum allowable pulse */
+
+/* Register 4: Output Power register */
+#define ACT200L_REG4    0x40
+#define ACT200L_OP0     0x01 /* Enable LED1C output */
+#define ACT200L_OP1     0x02 /* Enable LED2C output */
+#define ACT200L_BLKR    0x04
+
+/* Register 5: Receive Mode register */
+#define ACT200L_REG5    0x50
+#define ACT200L_RWIDL   0x01 /* fixed 1.6us pulse mode */
+
+/* Register 6: Receive Sensitivity register #1 */
+#define ACT200L_REG6    0x60
+#define ACT200L_RS0     0x01 /* receive threshold bit 0 */
+#define ACT200L_RS1     0x02 /* receive threshold bit 1 */
+
+/* Register 7: Receive Sensitivity register #2 */
+#define ACT200L_REG7    0x70
+#define ACT200L_ENPOS   0x04 /* Ignore the falling edge */
+
+/* Register 8,9: Baud Rate Dvider register #1,#2 */
+#define ACT200L_REG8    0x80
+#define ACT200L_REG9    0x90
+
+#define ACT200L_2400    0x5f
+#define ACT200L_9600    0x17
+#define ACT200L_19200   0x0b
+#define ACT200L_38400   0x05
+#define ACT200L_57600   0x03
+#define ACT200L_115200  0x01
+
+/* Register 13: Control register #3 */
+#define ACT200L_REG13   0xd0
+#define ACT200L_SHDW    0x01 /* Enable access to shadow registers */
+
+/* Register 15: Status register */
+#define ACT200L_REG15   0xf0
+
+/* Register 21: Control register #4 */
+#define ACT200L_REG21   0x50
+#define ACT200L_EXCK    0x02 /* Disable clock output driver */
+#define ACT200L_OSCL    0x04 /* oscillator in low power, medium accuracy mode */
+
+static struct dongle_reg dongle = {
+	Q_NULL,
+	IRDA_ACT200L_DONGLE,
+	act200l_open,
+	act200l_close,
+	act200l_reset,
+	act200l_change_speed,
+};
+
+int __init act200l_init(void)
+{
+	return irda_device_register_dongle(&dongle);
+}
+
+void __exit act200l_cleanup(void)
+{
+	irda_device_unregister_dongle(&dongle);
+}
+
+static void act200l_open(dongle_t *self, struct qos_info *qos)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	/* Power on the dongle */
+	self->set_dtr_rts(self->dev, TRUE, TRUE);
+
+	/* Set the speeds we can accept */
+	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+	qos->min_turn_time.bits = 0x03;
+
+	MOD_INC_USE_COUNT;
+}
+
+static void act200l_close(dongle_t *self)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	/* Power off the dongle */
+	self->set_dtr_rts(self->dev, FALSE, FALSE);
+
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * Function act200l_change_speed (dev, speed)
+ *
+ *    Set the speed for the ACTiSYS ACT-IR200L type dongle.
+ *
+ */
+static int act200l_change_speed(struct irda_task *task)
+{
+	dongle_t *self = (dongle_t *) task->instance;
+	__u32 speed = (__u32) task->param;
+	__u8 control[3];
+	int ret = 0;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	self->speed_task = task;
+
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+		if (irda_task_execute(self, act200l_reset, NULL, task,
+				(void *) speed))
+		{
+			/* Dongle need more time to reset */
+			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
+
+			/* Give reset 1 sec to finish */
+			ret = MSECS_TO_JIFFIES(1000);
+		}
+		break;
+	case IRDA_TASK_CHILD_WAIT:
+		WARNING(__FUNCTION__ "(), resetting dongle timed out!\n");
+		ret = -1;
+		break;
+	case IRDA_TASK_CHILD_DONE:
+		/* Clear DTR and set RTS to enter command mode */
+		self->set_dtr_rts(self->dev, FALSE, TRUE);
+
+		switch (speed) {
+		case 9600:
+		default:
+			control[0] = ACT200L_REG8 |  (ACT200L_9600       & 0x0f);
+			control[1] = ACT200L_REG9 | ((ACT200L_9600 >> 4) & 0x0f);
+			break;
+		case 19200:
+			control[0] = ACT200L_REG8 |  (ACT200L_19200       & 0x0f);
+			control[1] = ACT200L_REG9 | ((ACT200L_19200 >> 4) & 0x0f);
+			break;
+		case 38400:
+			control[0] = ACT200L_REG8 |  (ACT200L_38400       & 0x0f);
+			control[1] = ACT200L_REG9 | ((ACT200L_38400 >> 4) & 0x0f);
+			break;
+		case 57600:
+			control[0] = ACT200L_REG8 |  (ACT200L_57600       & 0x0f);
+			control[1] = ACT200L_REG9 | ((ACT200L_57600 >> 4) & 0x0f);
+			break;
+		case 115200:
+			control[0] = ACT200L_REG8 |  (ACT200L_115200       & 0x0f);
+			control[1] = ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f);
+			break;
+		}
+		control[2] = ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE;
+
+		/* Write control bytes */
+		self->write(self->dev, control, 3);
+		irda_task_next_state(task, IRDA_TASK_WAIT);
+		ret = MSECS_TO_JIFFIES(5);
+		break;
+	case IRDA_TASK_WAIT:
+		/* Go back to normal mode */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+		ret = -1;
+		break;
+	}
+	return ret;
+}
+
+/*
+ * Function act200l_reset (driver)
+ *
+ *    Reset the ACTiSYS ACT-IR200L type dongle.
+ */
+static int act200l_reset(struct irda_task *task)
+{
+	dongle_t *self = (dongle_t *) task->instance;
+	__u8 control[9] = {
+		ACT200L_REG15,
+		ACT200L_REG13 | ACT200L_SHDW,
+		ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL,
+		ACT200L_REG13,
+		ACT200L_REG7  | ACT200L_ENPOS,
+		ACT200L_REG6  | ACT200L_RS0  | ACT200L_RS1,
+		ACT200L_REG5  | ACT200L_RWIDL,
+		ACT200L_REG4  | ACT200L_OP0  | ACT200L_OP1 | ACT200L_BLKR,
+		ACT200L_REG0  | ACT200L_TXEN | ACT200L_RXEN
+	};
+	int ret = 0;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	self->reset_task = task;
+
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+		/* Power on the dongle */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+
+		irda_task_next_state(task, IRDA_TASK_WAIT1);
+		ret = MSECS_TO_JIFFIES(50);
+		break;
+	case IRDA_TASK_WAIT1:
+		/* Reset the dongle : set RTS low for 25 ms */
+		self->set_dtr_rts(self->dev, TRUE, FALSE);
+
+		irda_task_next_state(task, IRDA_TASK_WAIT2);
+		ret = MSECS_TO_JIFFIES(50);
+		break;
+	case IRDA_TASK_WAIT2:
+		/* Clear DTR and set RTS to enter command mode */
+		self->set_dtr_rts(self->dev, FALSE, TRUE);
+
+		/* Write control bytes */
+		self->write(self->dev, control, 9);
+		irda_task_next_state(task, IRDA_TASK_WAIT3);
+		ret = MSECS_TO_JIFFIES(15);
+		break;
+	case IRDA_TASK_WAIT3:
+		/* Go back to normal mode */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		ret = -1;
+		break;
+	}
+	return ret;
+}
+
+MODULE_AUTHOR("SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>");
+MODULE_DESCRIPTION("ACTiSYS ACT-IR200L dongle driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Function init_module (void)
+ *
+ *    Initialize ACTiSYS ACT-IR200L module
+ *
+ */
+module_init(act200l_init);
+
+/*
+ * Function cleanup_module (void)
+ *
+ *    Cleanup ACTiSYS ACT-IR200L module
+ *
+ */
+module_exit(act200l_cleanup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/irda/actisys.c linux-2.4.20/drivers/net/irda/actisys.c
--- linux-2.4.19/drivers/net/irda/actisys.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.20/drivers/net/irda/actisys.c	2002-10-29 11:18:48.000000000 +0000
@@ -166,8 +166,8 @@
 	int ret = 0;
 	int i = 0;
 
-        IRDA_DEBUG(4, __FUNCTION__ "(), speed=%d (was %d)\n", speed, 
-		   self->speed);
+        IRDA_DEBUG(4, "%s(), speed=%d (was %d)\n", __FUNCTION__,
+        	speed, self->speed);
 
 	/* Go to a known state by reseting the dongle */
 
@@ -260,7 +260,7 @@
 		self->speed = 9600;	/* That's the default */
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->reset_task = NULL;
 		ret = -1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/irda/ali-ircc.c linux-2.4.20/drivers/net/irda/ali-ircc.c
--- linux-2.4.19/drivers/net/irda/ali-ircc.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/irda/ali-ircc.c	2002-10-29 11:18:39.000000000 +0000
@@ -59,7 +59,6 @@
 static unsigned int irq[] = { 0, 0, 0, 0 };
 static unsigned int dma[] = { 0, 0, 0, 0 };
 
-static int  ali_ircc_probe_43(ali_chip_t *chip, chipio_t *info);
 static int  ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info);
 static int  ali_ircc_init_43(ali_chip_t *chip, chipio_t *info);
 static int  ali_ircc_init_53(ali_chip_t *chip, chipio_t *info);
@@ -146,12 +145,12 @@
 	int reg, revision;
 	int i = 0;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	/* Probe for all the ALi chipsets we know about */
 	for (chip= chips; chip->name; chip++, i++) 
 	{
-		IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", chip->name);
+		IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__, chip->name);
 				
 		/* Try all config registers for this chip */
 		for (cfg=0; cfg<2; cfg++)
@@ -181,14 +180,12 @@
 				
 			if (reg == chip->cid_value)
 			{
-				IRDA_DEBUG(2, __FUNCTION__
-					"(), Chip found at 0x%03x\n", cfg_base);
+				IRDA_DEBUG(2, "%s(), Chip found at 0x%03x\n", __FUNCTION__,  cfg_base);
 					   
 				outb(0x1F, cfg_base);
 				revision = inb(cfg_base+1);
-				IRDA_DEBUG(2, __FUNCTION__ 
-					   "(), Found %s chip, revision=%d\n",
-					   chip->name, revision);					
+				IRDA_DEBUG(2, "%s(), Found %s chip, revision=%d\n",
+					__FUNCTION__, chip->name, revision);					
 				
 				/* 
 				 * If the user supplies the base address, then
@@ -210,15 +207,14 @@
 			}
 			else
 			{
-				IRDA_DEBUG(2, __FUNCTION__ 
-					   "(), No %s chip at 0x%03x\n", chip->name, cfg_base);
+				IRDA_DEBUG(2, "%s(), No %s chip at 0x%03x\n", __FUNCTION__, chip->name, cfg_base);
 			}
 			/* Exit configuration */
 			outb(0xbb, cfg_base);
 		}
 	}		
 		
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n");					   		
+	IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);
 	return ret;
 }
 
@@ -233,7 +229,7 @@
 {
 	int i;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");	
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);	
 	
 	pm_unregister_all(ali_ircc_pmproc);
 
@@ -242,7 +238,7 @@
 			ali_ircc_close(dev_self[i]);
 	}
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n");
+	IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);
 }
 #endif /* MODULE */
 
@@ -258,10 +254,9 @@
 	struct ali_ircc_cb *self;
 	struct pm_dev *pmdev;
 	int dongle_id;
-	int ret;
 	int err;
 			
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");	
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);	
 	
 	/* Set FIR FIFO and DMA Threshold */
 	if ((ali_ircc_setup(info)) == -1)
@@ -271,7 +266,7 @@
 	self = kmalloc(sizeof(struct ali_ircc_cb), GFP_KERNEL);
 	if (self == NULL) 
 	{
-		ERROR(__FUNCTION__ "(), can't allocate memory for control block!\n");
+		ERROR("%s(), can't allocate memory for control block!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 	memset(self, 0, sizeof(struct ali_ircc_cb));
@@ -292,8 +287,8 @@
 	
 	/* Reserve the ioports that we need */
 	if (!request_region(self->io.fir_base, self->io.fir_ext, driver_name)) {
-		WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n",
-			self->io.fir_base);
+		WARNING("%s(), can't get iobase of 0x%03x\n",
+			__FUNCTION__, self->io.fir_base);
 		dev_self[i] = NULL;
 		kfree(self);
 		return -ENODEV;
@@ -345,7 +340,7 @@
 	self->tx_fifo.tail = self->tx_buff.head;
 
 	if (!(dev = dev_alloc("irda%d", &err))) {
-		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 
@@ -364,14 +359,14 @@
 	err = register_netdevice(dev);
 	rtnl_unlock();
 	if (err) {
-		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
 		return -1;
 	}
 	MESSAGE("IrDA: Registered device %s\n", dev->name);
 
 	/* Check dongle id */
 	dongle_id = ali_ircc_read_dongle_id(i, info);
-	MESSAGE(__FUNCTION__ "(), %s, Found dongle: %s\n", driver_name, dongle_types[dongle_id]);
+	MESSAGE("%s(), %s, Found dongle: %s\n", __FUNCTION__, driver_name, dongle_types[dongle_id]);
 		
 	self->io.dongle_id = dongle_id;
 	
@@ -379,7 +374,7 @@
         if (pmdev)
                 pmdev->data = self;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n");
+	IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);
 	
 	return 0;
 }
@@ -396,7 +391,7 @@
 {
 	int iobase;
 
-	IRDA_DEBUG(4, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(4, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return -1;);
 
@@ -410,7 +405,7 @@
 	}
 
 	/* Release the PORT that this driver is using */
-	IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", self->io.fir_base);
+	IRDA_DEBUG(4, "%s(), Releasing Region %03x\n", __FUNCTION__, self->io.fir_base);
 	release_region(self->io.fir_base, self->io.fir_ext);
 
 	if (self->tx_buff.head)
@@ -422,7 +417,7 @@
 	dev_self[self->index] = NULL;
 	kfree(self);
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n");
+	IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);
 	
 	return 0;
 }
@@ -457,16 +452,6 @@
 }
 
 /*
- * Function ali_ircc_probe_43 (chip, info)
- *    	
- *	Probes for the ALi M1543
- */
-static int ali_ircc_probe_43(ali_chip_t *chip, chipio_t *info)
-{
-	return 0;	
-}
-
-/*
  * Function ali_ircc_probe_53 (chip, info)
  *    	
  *	Probes for the ALi M1535D or M1535
@@ -476,7 +461,7 @@
 	int cfg_base = info->cfg_base;
 	int hi, low, reg;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	/* Enter Configuration */
 	outb(chip->entr1, cfg_base);
@@ -495,13 +480,13 @@
 	
 	info->sir_base = info->fir_base;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), probing fir_base=0x%03x\n", info->fir_base);
+	IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", __FUNCTION__, info->fir_base);
 		
 	/* Read IRQ control register */
 	outb(0x70, cfg_base);
 	reg = inb(cfg_base+1);
 	info->irq = reg & 0x0f;
-	IRDA_DEBUG(2, __FUNCTION__ "(), probing irq=%d\n", info->irq);
+	IRDA_DEBUG(2, "%s(), probing irq=%d\n", __FUNCTION__, info->irq);
 	
 	/* Read DMA channel */
 	outb(0x74, cfg_base);
@@ -509,26 +494,26 @@
 	info->dma = reg & 0x07;
 	
 	if(info->dma == 0x04)
-		WARNING(__FUNCTION__ "(), No DMA channel assigned !\n");
+		WARNING("%s(), No DMA channel assigned !\n", __FUNCTION__);
 	else
-		IRDA_DEBUG(2, __FUNCTION__ "(), probing dma=%d\n", info->dma);
+		IRDA_DEBUG(2, "%s(), probing dma=%d\n", __FUNCTION__, info->dma);
 	
 	/* Read Enabled Status */
 	outb(0x30, cfg_base);
 	reg = inb(cfg_base+1);
 	info->enabled = (reg & 0x80) && (reg & 0x01);
-	IRDA_DEBUG(2, __FUNCTION__ "(), probing enabled=%d\n", info->enabled);
+	IRDA_DEBUG(2, "%s(), probing enabled=%d\n", __FUNCTION__, info->enabled);
 	
 	/* Read Power Status */
 	outb(0x22, cfg_base);
 	reg = inb(cfg_base+1);
 	info->suspended = (reg & 0x20);
-	IRDA_DEBUG(2, __FUNCTION__ "(), probing suspended=%d\n", info->suspended);
+	IRDA_DEBUG(2, "%s(), probing suspended=%d\n", __FUNCTION__, info->suspended);
 	
 	/* Exit configuration */
 	outb(0xbb, cfg_base);
 		
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);	
 	
 	return 0;	
 }
@@ -546,7 +531,7 @@
 	int version;
 	int iobase = info->fir_base;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	/* Switch to FIR space */
 	SIR2FIR(iobase);
@@ -602,7 +587,7 @@
 	// outb(UART_IER_RDI, iobase+UART_IER); //benjamin 2000/11/23 01:25PM
 	// Turn on the interrupts in ali_ircc_net_open
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	
 	return 0;
 }
@@ -619,7 +604,7 @@
 	int dongle_id, reg;
 	int cfg_base = info->cfg_base;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 		
 	/* Enter Configuration */
 	outb(chips[i].entr1, cfg_base);
@@ -633,13 +618,13 @@
 	outb(0xf0, cfg_base);
 	reg = inb(cfg_base+1);	
 	dongle_id = ((reg>>6)&0x02) | ((reg>>5)&0x01);
-	IRDA_DEBUG(2, __FUNCTION__ "(), probing dongle_id=%d, dongle_types=%s\n", 
-		dongle_id, dongle_types[dongle_id]);
+	IRDA_DEBUG(2, "%s(), probing dongle_id=%d, dongle_types=%s\n", 
+		__FUNCTION__, dongle_id, dongle_types[dongle_id]);
 	
 	/* Exit configuration */
 	outb(0xbb, cfg_base);
 			
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);
 	
 	return dongle_id;
 }
@@ -655,7 +640,7 @@
 	struct net_device *dev = (struct net_device *) dev_id;
 	struct ali_ircc_cb *self;
 		
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 		
  	if (!dev) {
 		WARNING("%s: irq %d for unknown device.\n", driver_name, irq);
@@ -674,7 +659,7 @@
 		
 	spin_unlock(&self->lock);
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");		
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);		
 }
 /*
  * Function ali_ircc_fir_interrupt(irq, struct ali_ircc_cb *self, regs)
@@ -687,7 +672,7 @@
 	__u8 eir, OldMessageCount;
 	int iobase, tmp;
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	iobase = self->io.fir_base;
 	
@@ -700,10 +685,10 @@
 	//self->ier = inb(iobase+FIR_IER); 		2000/12/1 04:32PM
 	eir = self->InterruptID & self->ier; /* Mask out the interesting ones */ 
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), self->InterruptID = %x\n",self->InterruptID);
-	IRDA_DEBUG(1, __FUNCTION__ "(), self->LineStatus = %x\n",self->LineStatus);
-	IRDA_DEBUG(1, __FUNCTION__ "(), self->ier = %x\n",self->ier);
-	IRDA_DEBUG(1, __FUNCTION__ "(), eir = %x\n",eir);
+	IRDA_DEBUG(1, "%s(), self->InterruptID = %x\n", __FUNCTION__,self->InterruptID);
+	IRDA_DEBUG(1, "%s(), self->LineStatus = %x\n",__FUNCTION__, self->LineStatus);
+	IRDA_DEBUG(1, "%s(), self->ier = %x\n",__FUNCTION__, self->ier);
+	IRDA_DEBUG(1, "%s(), eir = %x\n",__FUNCTION__, eir);
 	
 	/* Disable interrupts */
 	 SetCOMInterrupts(self, FALSE);
@@ -714,7 +699,7 @@
 	{		
 		if (self->io.direction == IO_XMIT) /* TX */
 		{
-			IRDA_DEBUG(1, __FUNCTION__ "(), ******* IIR_EOM (Tx) *******\n");
+			IRDA_DEBUG(1, "%s(), ******* IIR_EOM (Tx) *******\n", __FUNCTION__);
 			
 			if(ali_ircc_dma_xmit_complete(self))
 			{
@@ -733,23 +718,23 @@
 		}	
 		else /* RX */
 		{
-			IRDA_DEBUG(1, __FUNCTION__ "(), ******* IIR_EOM (Rx) *******\n");
+			IRDA_DEBUG(1, "%s(), ******* IIR_EOM (Rx) *******\n", __FUNCTION__);
 			
 			if(OldMessageCount > ((self->LineStatus+1) & 0x07))
 			{
 				self->rcvFramesOverflow = TRUE;	
-				IRDA_DEBUG(1, __FUNCTION__ "(), ******* self->rcvFramesOverflow = TRUE ******** \n");
+				IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE ******** \n", __FUNCTION__);
 			}
 						
 			if (ali_ircc_dma_receive_complete(self))
 			{
-				IRDA_DEBUG(1, __FUNCTION__ "(), ******* receive complete ******** \n");
+				IRDA_DEBUG(1, "%s(), ******* receive complete ******** \n", __FUNCTION__);
 				
 				self->ier = IER_EOM;				
 			}
 			else
 			{
-				IRDA_DEBUG(1, __FUNCTION__ "(), ******* Not receive complete ******** \n");
+				IRDA_DEBUG(1, "%s(), ******* Not receive complete ******** \n", __FUNCTION__);
 				
 				self->ier = IER_EOM | IER_TIMER;								
 			}	
@@ -762,7 +747,7 @@
 		if(OldMessageCount > ((self->LineStatus+1) & 0x07))
 		{
 			self->rcvFramesOverflow = TRUE;	
-			IRDA_DEBUG(1, __FUNCTION__ "(), ******* self->rcvFramesOverflow = TRUE ******* \n");
+			IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE ******* \n", __FUNCTION__);
 		}
 		/* Disable Timer */
 		switch_bank(iobase, BANK1);
@@ -794,7 +779,7 @@
 	/* Restore Interrupt */	
 	SetCOMInterrupts(self, TRUE);	
 		
-	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ---------------\n");
+	IRDA_DEBUG(1, "%s(), ----------------- End ---------------\n", __FUNCTION__);
 }
 
 /*
@@ -808,7 +793,7 @@
 	int iobase;
 	int iir, lsr;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	iobase = self->io.sir_base;
 
@@ -817,14 +802,13 @@
 		/* Clear interrupt */
 		lsr = inb(iobase+UART_LSR);
 
-		IRDA_DEBUG(4, __FUNCTION__ 
-			   "(), iir=%02x, lsr=%02x, iobase=%#x\n", 
-			   iir, lsr, iobase);
+		IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", 
+			__FUNCTION__, iir, lsr, iobase);
 
 		switch (iir) 
 		{
 			case UART_IIR_RLSI:
-				IRDA_DEBUG(2, __FUNCTION__ "(), RLSI\n");
+				IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__);
 				break;
 			case UART_IIR_RDI:
 				/* Receive interrupt */
@@ -838,14 +822,14 @@
 				}				
 				break;
 			default:
-				IRDA_DEBUG(0, __FUNCTION__ "(), unhandled IIR=%#x\n", iir);
+				IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n", __FUNCTION__, iir);
 				break;
 		} 
 		
 	}
 	
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 }
 
 
@@ -860,7 +844,7 @@
 	int boguscount = 0;
 	int iobase;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	ASSERT(self != NULL, return;);
 
 	iobase = self->io.sir_base;
@@ -875,12 +859,12 @@
 
 		/* Make sure we don't stay here to long */
 		if (boguscount++ > 32) {
-			IRDA_DEBUG(2,__FUNCTION__ "(), breaking!\n");
+			IRDA_DEBUG(2, "%s(), breaking!\n", __FUNCTION__);
 			break;
 		}
 	} while (inb(iobase+UART_LSR) & UART_LSR_DR);	
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 }
 
 /*
@@ -897,7 +881,7 @@
 
 	ASSERT(self != NULL, return;);
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	iobase = self->io.sir_base;
 
@@ -916,16 +900,16 @@
 		{
 			/* We must wait until all data are gone */
 			while(!(inb(iobase+UART_LSR) & UART_LSR_TEMT))
-				IRDA_DEBUG(1, __FUNCTION__ "(), UART_LSR_THRE\n");
+				IRDA_DEBUG(1, "%s(), UART_LSR_THRE\n", __FUNCTION__);
 			
-			IRDA_DEBUG(1, __FUNCTION__ "(), Changing speed! self->new_speed = %d\n", self->new_speed);
+			IRDA_DEBUG(1, "%s(), Changing speed! self->new_speed = %d\n", __FUNCTION__, self->new_speed);
 			ali_ircc_change_speed(self, self->new_speed);
 			self->new_speed = 0;			
 			
 			// benjamin 2000/11/10 06:32PM
 			if (self->io.speed > 115200)
 			{
-				IRDA_DEBUG(2, __FUNCTION__ "(), ali_ircc_change_speed from UART_LSR_TEMT \n");				
+				IRDA_DEBUG(2,  "%s(), ali_ircc_change_speed from UART_LSR_TEMT \n", __FUNCTION__);
 					
 				self->ier = IER_EOM;
 				// SetCOMInterrupts(self, TRUE);							
@@ -943,7 +927,7 @@
 		outb(UART_IER_RDI, iobase+UART_IER);
 	}
 		
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 }
 
 static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud)
@@ -951,9 +935,9 @@
 	struct net_device *dev = self->netdev;
 	int iobase;
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), setting speed = %d \n", baud);
+	IRDA_DEBUG(2, "%s(), setting speed = %d \n", __FUNCTION__, baud);
 	
 	iobase = self->io.fir_base;
 	
@@ -989,7 +973,7 @@
 		
 	netif_wake_queue(self->netdev);	
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 }
 
 static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 baud)
@@ -999,14 +983,14 @@
 	struct ali_ircc_cb *self = (struct ali_ircc_cb *) priv;
 	struct net_device *dev;
 
-	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 		
 	ASSERT(self != NULL, return;);
 
 	dev = self->netdev;
 	iobase = self->io.fir_base;
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), self->io.speed = %d, change to speed = %d\n",self->io.speed,baud);
+	IRDA_DEBUG(1, "%s(), self->io.speed = %d, change to speed = %d\n", __FUNCTION__,self->io.speed,baud);
 	
 	/* Come from SIR speed */
 	if(self->io.speed <=115200)
@@ -1020,7 +1004,7 @@
 	// Set Dongle Speed mode
 	ali_ircc_change_dongle_speed(self, baud);
 		
-	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 }
 
 /*
@@ -1038,9 +1022,9 @@
 	int lcr;    /* Line control reg */
 	int divisor;
 
-	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), Setting speed to: %d\n", speed);
+	IRDA_DEBUG(1, "%s(), Setting speed to: %d\n", __FUNCTION__, speed);
 
 	ASSERT(self != NULL, return;);
 
@@ -1094,7 +1078,7 @@
 	
 	spin_unlock_irqrestore(&self->lock, flags);
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 }
 
 static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed)
@@ -1105,7 +1089,7 @@
 	unsigned long flags;
 	int tmp = 0;
 			
-	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");	
+	IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__);	
 	
 	iobase = self->io.fir_base; 	/* or iobase = self->io.sir_base; */
 	dongle_id = self->io.dongle_id;
@@ -1113,7 +1097,7 @@
 	save_flags(flags);
 	cli();
 		
-	IRDA_DEBUG(1, __FUNCTION__ "(), Set Speed for %s , Speed = %d\n", dongle_types[dongle_id], speed);		
+	IRDA_DEBUG(1, "%s(), Set Speed for %s , Speed = %d\n", __FUNCTION__, dongle_types[dongle_id], speed);		
 	
 	switch_bank(iobase, BANK2);
 	tmp = inb(iobase+FIR_IRDA_CR);
@@ -1279,7 +1263,7 @@
 	
 	restore_flags(flags);
 		
-	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");		
+	IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__);		
 }
 
 /*
@@ -1292,11 +1276,11 @@
 {
 	int actual = 0;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 		
 	/* Tx FIFO should be empty! */
 	if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), failed, fifo not empty!\n");
+		IRDA_DEBUG(0, "%s(), failed, fifo not empty!\n", __FUNCTION__);
 		return 0;
 	}
         
@@ -1308,7 +1292,7 @@
 		actual++;
 	}
 	
-        IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+        IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	return actual;
 }
 
@@ -1320,14 +1304,14 @@
  */
 static int ali_ircc_net_init(struct net_device *dev)
 {
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	/* Setup to be a normal IrDA network device driver */
 	irda_device_setup(dev);
 
 	/* Insert overrides below this line! */
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	
 	return 0;
 }
@@ -1344,7 +1328,7 @@
 	int iobase;
 	char hwname[32];
 		
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	ASSERT(dev != NULL, return -1;);
 	
@@ -1390,7 +1374,7 @@
 		
 	MOD_INC_USE_COUNT;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	
 	return 0;
 }
@@ -1407,7 +1391,7 @@
 	struct ali_ircc_cb *self;
 	//int iobase;
 			
-	IRDA_DEBUG(4, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(4, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 		
 	ASSERT(dev != NULL, return -1;);
 
@@ -1432,7 +1416,7 @@
 
 	MOD_DEC_USE_COUNT;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	
 	return 0;
 }
@@ -1451,7 +1435,7 @@
 	__u32 speed;
 	int mtt, diff;
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start -----------------\n");	
+	IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __FUNCTION__);
 	
 	self = (struct ali_ircc_cb *) dev->priv;
 	iobase = self->io.fir_base;
@@ -1499,7 +1483,7 @@
 			diff = self->now.tv_usec - self->stamp.tv_usec;
 			/* self->stamp is set from ali_ircc_dma_receive_complete() */
 							
-			IRDA_DEBUG(1, __FUNCTION__ "(), ******* diff = %d ******* \n", diff);	
+			IRDA_DEBUG(1, "%s(), ******* diff = %d ******* \n", __FUNCTION__, diff);
 			
 			if (diff < 0) 
 				diff += 1000000;
@@ -1521,7 +1505,7 @@
 					/* Adjust for timer resolution */
 					mtt = (mtt+250) / 500; 	/* 4 discard, 5 get advanced, Let's round off */
 					
-					IRDA_DEBUG(1, __FUNCTION__ "(), ************** mtt = %d ***********\n", mtt);	
+					IRDA_DEBUG(1, "%s(), ************** mtt = %d ***********\n", __FUNCTION__, mtt);
 					
 					/* Setup timer */
 					if (mtt == 1) /* 500 us */
@@ -1577,7 +1561,7 @@
 	spin_unlock_irqrestore(&self->lock, flags);
 	dev_kfree_skb(skb);
 
-	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	return 0;	
 }
 
@@ -1588,7 +1572,7 @@
 	unsigned char FIFO_OPTI, Hi, Lo;
 	
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start -----------------\n");	
+	IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __FUNCTION__);	
 	
 	iobase = self->io.fir_base;
 	
@@ -1638,7 +1622,7 @@
 	tmp = inb(iobase+FIR_LCR_B);
 	tmp &= ~0x20; // Disable SIP
 	outb(((unsigned char)(tmp & 0x3f) | LCR_B_TX_MODE) & ~LCR_B_BW, iobase+FIR_LCR_B);
-	IRDA_DEBUG(1, __FUNCTION__ "(), ******* Change to TX mode: FIR_LCR_B = 0x%x ******* \n", inb(iobase+FIR_LCR_B));
+	IRDA_DEBUG(1, "%s(), ******* Change to TX mode: FIR_LCR_B = 0x%x ******* \n", __FUNCTION__, inb(iobase+FIR_LCR_B));
 	
 	outb(0, iobase+FIR_LSR);
 			
@@ -1648,7 +1632,7 @@
 	
 	switch_bank(iobase, BANK0); 
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");
+	IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__);
 }
 
 static int  ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self)
@@ -1656,7 +1640,7 @@
 	int iobase;
 	int ret = TRUE;
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start -----------------\n");	
+	IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __FUNCTION__);
 	
 	iobase = self->io.fir_base;
 	
@@ -1669,7 +1653,7 @@
 	if((inb(iobase+FIR_LSR) & LSR_FRAME_ABORT) == LSR_FRAME_ABORT)
 	
 	{
-		ERROR(__FUNCTION__ "(), ********* LSR_FRAME_ABORT *********\n");	
+		ERROR("%s(), ********* LSR_FRAME_ABORT *********\n", __FUNCTION__);
 		self->stats.tx_errors++;
 		self->stats.tx_fifo_errors++;		
 	}
@@ -1712,7 +1696,7 @@
 		
 	switch_bank(iobase, BANK0); 
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	return ret;
 }
 
@@ -1727,7 +1711,7 @@
 {
 	int iobase, tmp;
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start -----------------\n");	
+	IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __FUNCTION__);
 	
 	iobase = self->io.fir_base;
 	
@@ -1765,7 +1749,7 @@
 	//switch_bank(iobase, BANK0);
 	tmp = inb(iobase+FIR_LCR_B);
 	outb((unsigned char)(tmp &0x3f) | LCR_B_RX_MODE | LCR_B_BW , iobase + FIR_LCR_B); // 2000/12/1 05:16PM
-	IRDA_DEBUG(1, __FUNCTION__ "(), *** Change To RX mode: FIR_LCR_B = 0x%x *** \n", inb(iobase+FIR_LCR_B));
+	IRDA_DEBUG(1, "%s(), *** Change To RX mode: FIR_LCR_B = 0x%x *** \n", __FUNCTION__, inb(iobase+FIR_LCR_B));
 			
 	/* Set Rx Threshold */
 	switch_bank(iobase, BANK1);
@@ -1777,7 +1761,7 @@
 	outb(CR_DMA_EN | CR_DMA_BURST, iobase+FIR_CR);
 				
 	switch_bank(iobase, BANK0); 
-	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	return 0;
 }
 
@@ -1788,7 +1772,7 @@
 	__u8 status, MessageCount;
 	int len, i, iobase, val;	
 
-	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start -----------------\n");	
+	IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __FUNCTION__);
 
 	st_fifo = &self->st_fifo;		
 	iobase = self->io.fir_base;	
@@ -1797,7 +1781,7 @@
 	MessageCount = inb(iobase+ FIR_LSR)&0x07;
 	
 	if (MessageCount > 0)	
-		IRDA_DEBUG(0, __FUNCTION__ "(), Messsage count = %d,\n", MessageCount);	
+		IRDA_DEBUG(0, "%s(), Messsage count = %d,\n", __FUNCTION__, MessageCount);	
 		
 	for (i=0; i<=MessageCount; i++)
 	{
@@ -1810,11 +1794,11 @@
 		len = len << 8; 
 		len |= inb(iobase+FIR_RX_DSR_LO);
 		
-		IRDA_DEBUG(1, __FUNCTION__ "(), RX Length = 0x%.2x,\n", len);	
-		IRDA_DEBUG(1, __FUNCTION__ "(), RX Status = 0x%.2x,\n", status);
+		IRDA_DEBUG(1, "%s(), RX Length = 0x%.2x,\n", __FUNCTION__, len);	
+		IRDA_DEBUG(1, "%s(), RX Status = 0x%.2x,\n", __FUNCTION__, status);
 		
 		if (st_fifo->tail >= MAX_RX_WINDOW) {
-			IRDA_DEBUG(0, __FUNCTION__ "(), window is full!\n");
+			IRDA_DEBUG(0, "%s(), window is full!\n", __FUNCTION__);
 			continue;
 		}
 			
@@ -1837,7 +1821,7 @@
 		/* Check for errors */
 		if ((status & 0xd8) || self->rcvFramesOverflow || (len==0)) 		
 		{
-			IRDA_DEBUG(0,__FUNCTION__ "(), ************* RX Errors ************ \n");	
+			IRDA_DEBUG(0,  "%s(), ************* RX Errors ************ \n", __FUNCTION__);
 			
 			/* Skip frame */
 			self->stats.rx_errors++;
@@ -1847,29 +1831,29 @@
 			if (status & LSR_FIFO_UR) 
 			{
 				self->stats.rx_frame_errors++;
-				IRDA_DEBUG(0,__FUNCTION__ "(), ************* FIFO Errors ************ \n");
+				IRDA_DEBUG(0, "%s(), ************* FIFO Errors ************ \n", __FUNCTION__);
 			}	
 			if (status & LSR_FRAME_ERROR)
 			{
 				self->stats.rx_frame_errors++;
-				IRDA_DEBUG(0,__FUNCTION__ "(), ************* FRAME Errors ************ \n");
+				IRDA_DEBUG(0, "%s(), ************* FRAME Errors ************ \n", __FUNCTION__);
 			}
 							
 			if (status & LSR_CRC_ERROR) 
 			{
 				self->stats.rx_crc_errors++;
-				IRDA_DEBUG(0,__FUNCTION__ "(), ************* CRC Errors ************ \n");
+				IRDA_DEBUG(0, "%s(), ************* CRC Errors ************ \n", __FUNCTION__);
 			}
 			
 			if(self->rcvFramesOverflow)
 			{
 				self->stats.rx_frame_errors++;
-				IRDA_DEBUG(0,__FUNCTION__ "(), ************* Overran DMA buffer ************ \n");								
+				IRDA_DEBUG(0, "%s(), ************* Overran DMA buffer ************ \n", __FUNCTION__);								
 			}
 			if(len == 0)
 			{
 				self->stats.rx_frame_errors++;
-				IRDA_DEBUG(0,__FUNCTION__ "(), ********** Receive Frame Size = 0 ********* \n");
+				IRDA_DEBUG(0, "%s(), ********** Receive Frame Size = 0 ********* \n", __FUNCTION__);
 			}
 		}	 
 		else 
@@ -1881,7 +1865,7 @@
 				val = inb(iobase+FIR_BSR);	
 				if ((val& BSR_FIFO_NOT_EMPTY)== 0x80) 
 				{
-					IRDA_DEBUG(0, __FUNCTION__ "(), ************* BSR_FIFO_NOT_EMPTY ************ \n");
+					IRDA_DEBUG(0, "%s(), ************* BSR_FIFO_NOT_EMPTY ************ \n", __FUNCTION__);
 					
 					/* Put this entry back in fifo */
 					st_fifo->head--;
@@ -1916,8 +1900,8 @@
 			skb = dev_alloc_skb(len+1);
 			if (skb == NULL)  
 			{
-				WARNING(__FUNCTION__ "(), memory squeeze, "
-					"dropping frame.\n");
+				WARNING("%s(), memory squeeze, "
+					"dropping frame.\n", __FUNCTION__);
 				self->stats.rx_dropped++;
 
 				return FALSE;
@@ -1944,7 +1928,7 @@
 	
 	switch_bank(iobase, BANK0);	
 		
-	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	return TRUE;
 }
 
@@ -1963,7 +1947,7 @@
 	int iobase;
 	__u32 speed;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	ASSERT(dev != NULL, return 0;);
 	
@@ -2004,7 +1988,7 @@
 
 	dev_kfree_skb(skb);
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	
 	return 0;	
 }
@@ -2023,7 +2007,7 @@
 	unsigned long flags;
 	int ret = 0;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	ASSERT(dev != NULL, return -1;);
 
@@ -2031,7 +2015,7 @@
 
 	ASSERT(self != NULL, return -1;);
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 	
 	/* Disable interrupts & save flags */
 	save_flags(flags);
@@ -2039,7 +2023,7 @@
 	
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
-		IRDA_DEBUG(1, __FUNCTION__ "(), SIOCSBANDWIDTH\n");
+		IRDA_DEBUG(1, "%s(), SIOCSBANDWIDTH\n", __FUNCTION__);
 		/*
 		 * This function will also be used by IrLAP to change the
 		 * speed, so we still must allow for speed change within
@@ -2051,13 +2035,13 @@
 		ali_ircc_change_speed(self, irq->ifr_baudrate);		
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
-		IRDA_DEBUG(1, __FUNCTION__ "(), SIOCSMEDIABUSY\n");
+		IRDA_DEBUG(1, "%s(), SIOCSMEDIABUSY\n", __FUNCTION__);
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		irda_device_set_media_busy(self->netdev, TRUE);
 		break;
 	case SIOCGRECEIVING: /* Check if we are receiving right now */
-		IRDA_DEBUG(2, __FUNCTION__ "(), SIOCGRECEIVING\n");
+		IRDA_DEBUG(2, "%s(), SIOCGRECEIVING\n", __FUNCTION__);
 		irq->ifr_receiving = ali_ircc_is_receiving(self);
 		break;
 	default:
@@ -2066,7 +2050,7 @@
 	
 	restore_flags(flags);
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	
 	return ret;
 }
@@ -2083,7 +2067,7 @@
 	int status = FALSE;
 	int iobase;		
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start -----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start -----------------\n", __FUNCTION__);
 	
 	ASSERT(self != NULL, return FALSE;);
 
@@ -2097,7 +2081,7 @@
 		if((inb(iobase+FIR_FIFO_FR) & 0x3f) != 0) 		
 		{
 			/* We are receiving something */
-			IRDA_DEBUG(1, __FUNCTION__ "(), We are receiving something\n");
+			IRDA_DEBUG(1, "%s(), We are receiving something\n", __FUNCTION__);
 			status = TRUE;
 		}
 		switch_bank(iobase, BANK0);		
@@ -2109,7 +2093,7 @@
 	
 	spin_unlock_irqrestore(&self->lock, flags);
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);
 	
 	return status;
 }
@@ -2118,16 +2102,16 @@
 {
 	struct ali_ircc_cb *self = (struct ali_ircc_cb *) dev->priv;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 		
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	
 	return &self->stats;
 }
 
 static void ali_ircc_suspend(struct ali_ircc_cb *self)
 {
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	MESSAGE("%s, Suspending\n", driver_name);
 
@@ -2138,12 +2122,12 @@
 
 	self->io.suspended = 1;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 }
 
 static void ali_ircc_wakeup(struct ali_ircc_cb *self)
 {
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	if (!self->io.suspended)
 		return;
@@ -2154,14 +2138,14 @@
 
 	self->io.suspended = 0;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 }
 
 static int ali_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
 {
         struct ali_ircc_cb *self = (struct ali_ircc_cb*) dev->data;
         
-        IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+        IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
         if (self) {
                 switch (rqst) {
@@ -2174,7 +2158,7 @@
                 }
         }
         
-        IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+        IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
         
 	return 0;
 }
@@ -2189,7 +2173,7 @@
 	
 	int iobase = self->io.fir_base; /* or sir_base */
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), -------- Start -------- ( Enable = %d )\n", enable);	
+	IRDA_DEBUG(2, "%s(), -------- Start -------- ( Enable = %d )\n", __FUNCTION__, enable);	
 	
 	/* Enable the interrupt which we wish to */
 	if (enable){
@@ -2230,7 +2214,7 @@
 	else
 		outb(newMask, iobase+UART_IER);
 		
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 }
 
 static void SIR2FIR(int iobase)
@@ -2238,7 +2222,7 @@
 	//unsigned char tmp;
 	unsigned long flags;
 		
-	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	save_flags(flags);
 	cli();
@@ -2256,7 +2240,7 @@
 	//tmp |= 0x20;
 	//outb(tmp, iobase+FIR_LCR_B);	
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 }
 
 static void FIR2SIR(int iobase)
@@ -2264,7 +2248,7 @@
 	unsigned char val;
 	unsigned long flags;
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	save_flags(flags);
 	cli();
@@ -2282,7 +2266,7 @@
 	
 	restore_flags(flags);
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");
+	IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__);
 }
 
 #ifdef MODULE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/irda/girbil.c linux-2.4.20/drivers/net/irda/girbil.c
--- linux-2.4.19/drivers/net/irda/girbil.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.20/drivers/net/irda/girbil.c	2002-10-29 11:18:31.000000000 +0000
@@ -130,7 +130,7 @@
 		}
 		break;
 	case IRDA_TASK_CHILD_WAIT:
-		WARNING(__FUNCTION__ "(), resetting dongle timed out!\n");
+		WARNING("%s(), resetting dongle timed out!\n", __FUNCTION__);
 		ret = -1;
 		break;
 	case IRDA_TASK_CHILD_DONE:
@@ -169,7 +169,7 @@
 		self->speed_task = NULL;
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->speed_task = NULL;
 		ret = -1;
@@ -222,7 +222,7 @@
 		self->reset_task = NULL;
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->reset_task = NULL;
 		ret = -1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/irda/irda-usb.c linux-2.4.20/drivers/net/irda/irda-usb.c
--- linux-2.4.19/drivers/net/irda/irda-usb.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/irda/irda-usb.c	2002-10-29 11:18:48.000000000 +0000
@@ -45,6 +45,8 @@
  * Amongst the reasons :
  *	o uhci doesn't implement USB_ZERO_PACKET
  *	o uhci non-compliant use of urb->timeout
+ * The final fix for USB_ZERO_PACKET in uhci is likely to be in 2.4.19 and
+ * 2.5.8. With this fix, the driver will work properly. More on that later.
  *
  * Jean II
  */
@@ -112,9 +114,9 @@
 static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev);
 static int irda_usb_open(struct irda_usb_cb *self);
 static int irda_usb_close(struct irda_usb_cb *self);
-static void speed_bulk_callback(purb_t purb);
-static void write_bulk_callback(purb_t purb);
-static void irda_usb_receive(purb_t purb);
+static void speed_bulk_callback(struct urb *urb);
+static void write_bulk_callback(struct urb *urb);
+static void irda_usb_receive(struct urb *urb);
 static int irda_usb_net_init(struct net_device *dev);
 static int irda_usb_net_open(struct net_device *dev);
 static int irda_usb_net_close(struct net_device *dev);
@@ -158,12 +160,12 @@
 		    (!force) && (self->speed != -1)) {
 			/* No speed and xbofs change here
 			 * (we'll do it later in the write callback) */
-			IRDA_DEBUG(2, __FUNCTION__ "(), not changing speed yet\n");
+			IRDA_DEBUG(2, "%s(), not changing speed yet\n", __FUNCTION__);
 			*header = 0;
 			return;
 		}
 
-		IRDA_DEBUG(2, __FUNCTION__ "(), changing speed to %d\n", self->new_speed);
+		IRDA_DEBUG(2, "%s(), changing speed to %d\n", __FUNCTION__, self->new_speed);
 		self->speed = self->new_speed;
 		self->new_speed = -1;
 
@@ -204,7 +206,7 @@
 	
 	/* Set the negotiated additional XBOFS */
 	if (self->new_xbofs != -1) {
-		IRDA_DEBUG(2, __FUNCTION__ "(), changing xbofs to %d\n", self->new_xbofs);
+		IRDA_DEBUG(2, "%s(), changing xbofs to %d\n", __FUNCTION__, self->new_xbofs);
 		self->xbofs = self->new_xbofs;
 		self->new_xbofs = -1;
 
@@ -243,26 +245,24 @@
 /*------------------------------------------------------------------*/
 /*
  * Send a command to change the speed of the dongle
+ * Need to be called with spinlock on.
  */
 static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
 {
-	unsigned long flags;
 	__u8 *frame;
-	purb_t purb;
 	int ret;
+	struct urb *purb;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n",
-		   self->new_speed, self->new_xbofs);
+	IRDA_DEBUG(2, "%s(), speed=%d, xbofs=%d\n",
+		__FUNCTION__, self->new_speed, self->new_xbofs);
 
 	/* Grab the speed URB */
 	purb = &self->speed_urb;
 	if (purb->status != USB_ST_NOERROR) {
-		WARNING(__FUNCTION__ "(), URB still in use!\n");
+		WARNING("%s(), URB still in use!\n", __FUNCTION__);
 		return;
 	}
 
-	spin_lock_irqsave(&self->lock, flags);
-
 	/* Allocate the fake frame */
 	frame = self->speed_buff;
 
@@ -279,31 +279,30 @@
 	purb->timeout = MSECS_TO_JIFFIES(100);
 
 	if ((ret = usb_submit_urb(purb))) {
-		WARNING(__FUNCTION__ "(), failed Speed URB\n");
+		WARNING("%s(), failed Speed URB\n", __FUNCTION__);
 	}
-	spin_unlock_irqrestore(&self->lock, flags);
 }
 
 /*------------------------------------------------------------------*/
 /*
  * Note : this function will be called with both speed_urb and empty_urb...
  */
-static void speed_bulk_callback(purb_t purb)
+static void speed_bulk_callback(struct urb *purb)
 {
 	struct irda_usb_cb *self = purb->context;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	/* We should always have a context */
 	if (self == NULL) {
-		WARNING(__FUNCTION__ "(), Bug : self == NULL\n");
+		WARNING("%s(), Bug : self == NULL\n", __FUNCTION__);
 		return;
 	}
 
 	/* Check for timeout and other USB nasties */
 	if(purb->status != USB_ST_NOERROR) {
 		/* I get a lot of -ECONNABORTED = -103 here - Jean II */
-		IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags);
+		IRDA_DEBUG(0, "%s(), URB complete status %d, transfer_flags 0x%04X\n", __FUNCTION__, purb->status, purb->transfer_flags);
 
 		/* Don't do anything here, that might confuse the USB layer.
 		 * Instead, we will wait for irda_usb_net_timeout(), the
@@ -329,20 +328,26 @@
 static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct irda_usb_cb *self = netdev->priv;
-	purb_t purb = &self->tx_urb;
+	struct urb *purb = &self->tx_urb;
 	unsigned long flags;
 	s32 speed;
 	s16 xbofs;
 	int res, mtt;
 
-	/* Check if the device is still there */
+	netif_stop_queue(netdev);
+
+	/* Protect us from USB callbacks, net watchdog and else. */
+	spin_lock_irqsave(&self->lock, flags);
+
+	/* Check if the device is still there.
+	 * We need to check self->present under the spinlock because
+	 * of irda_usb_disconnect() is synchronous - Jean II */
 	if ((!self) || (!self->present)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), Device is gone...\n");
+		IRDA_DEBUG(0, "%s(), Device is gone...\n", __FUNCTION__);
+		spin_unlock_irqrestore(&self->lock, flags);
 		return 1;	/* Failed */
 	}
 
-	netif_stop_queue(netdev);
-
 	/* Check if we need to change the number of xbofs */
         xbofs = irda_get_next_xbofs(skb);
         if ((xbofs != self->xbofs) && (xbofs != -1)) {
@@ -366,16 +371,14 @@
 			 * Jean II */
 			irda_usb_change_speed_xbofs(self);
 			netdev->trans_start = jiffies;
-			dev_kfree_skb(skb);
 			/* Will netif_wake_queue() in callback */
-			return 0;
+			goto drop;
 		}
 	}
 
 	if (purb->status != USB_ST_NOERROR) {
-		WARNING(__FUNCTION__ "(), URB still in use!\n");
-		dev_kfree_skb(skb);
-		return 0;
+		WARNING("%s(), URB still in use!\n", __FUNCTION__);
+		goto drop;
 	}
 
 	/* Make sure there is room for IrDA-USB header. The actual
@@ -383,16 +386,13 @@
 	 * Also, we don't use directly skb_cow(), because it require
 	 * headroom >= 16, which force unnecessary copies - Jean II */
 	if (skb_headroom(skb) < USB_IRDA_HEADER) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), Insuficient skb headroom.\n");
+		IRDA_DEBUG(0, "%s(), Insuficient skb headroom.\n", __FUNCTION__);
 		if (skb_cow(skb, USB_IRDA_HEADER)) {
-			WARNING(__FUNCTION__ "(), failed skb_cow() !!!\n");
-			dev_kfree_skb(skb);
-			return 0;
+			WARNING("%s(), failed skb_cow() !!!\n", __FUNCTION__);
+			goto drop;
 		}
 	}
 
-	spin_lock_irqsave(&self->lock, flags);
-
 	/* Change setting for next frame */
 	irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0);
 
@@ -459,7 +459,7 @@
 	
 	/* Ask USB to send the packet */
 	if ((res = usb_submit_urb(purb))) {
-		WARNING(__FUNCTION__ "(), failed Tx URB\n");
+		WARNING("%s(), failed Tx URB\n", __FUNCTION__);
 		self->stats.tx_errors++;
 		/* Let USB recover : We will catch that in the watchdog */
 		/*netif_start_queue(netdev);*/
@@ -473,22 +473,29 @@
 	spin_unlock_irqrestore(&self->lock, flags);
 	
 	return 0;
+
+drop:
+	/* Drop silently the skb and exit */
+	dev_kfree_skb(skb);
+	spin_unlock_irqrestore(&self->lock, flags);
+	return 0;
 }
 
 /*------------------------------------------------------------------*/
 /*
  * Note : this function will be called only for tx_urb...
  */
-static void write_bulk_callback(purb_t purb)
+static void write_bulk_callback(struct urb *purb)
 {
+	unsigned long flags;
 	struct sk_buff *skb = purb->context;
 	struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	/* We should always have a context */
 	if (self == NULL) {
-		WARNING(__FUNCTION__ "(), Bug : self == NULL\n");
+		WARNING("%s(), Bug : self == NULL\n", __FUNCTION__);
 		return;
 	}
 
@@ -499,7 +506,7 @@
 	/* Check for timeout and other USB nasties */
 	if(purb->status != USB_ST_NOERROR) {
 		/* I get a lot of -ECONNABORTED = -103 here - Jean II */
-		IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags);
+		IRDA_DEBUG(0, "%s(), URB complete status %d, transfer_flags 0x%04X\n", __FUNCTION__, purb->status, purb->transfer_flags);
 
 		/* Don't do anything here, that might confuse the USB layer,
 		 * and we could go in recursion and blow the kernel stack...
@@ -511,22 +518,27 @@
 	}
 
 	/* urb is now available */
-	purb->status = USB_ST_NOERROR;
+	//purb->status = USB_ST_NOERROR; -> tested above
+
+	/* Make sure we read self->present properly */
+	spin_lock_irqsave(&self->lock, flags);
 
 	/* If the network is closed, stop everything */
 	if ((!self->netopen) || (!self->present)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone...\n");
+		IRDA_DEBUG(0, "%s(), Network is gone...\n", __FUNCTION__);
+		spin_unlock_irqrestore(&self->lock, flags);
 		return;
 	}
 
 	/* If we need to change the speed or xbofs, do it now */
 	if ((self->new_speed != -1) || (self->new_xbofs != -1)) {
-		IRDA_DEBUG(1, __FUNCTION__ "(), Changing speed now...\n");
+		IRDA_DEBUG(1, "%s(), Changing speed now...\n", __FUNCTION__);
 		irda_usb_change_speed_xbofs(self);
 	} else {
 		/* Otherwise, allow the stack to send more packets */
 		netif_wake_queue(self->netdev);
 	}
+	spin_unlock_irqrestore(&self->lock, flags);
 }
 
 /*------------------------------------------------------------------*/
@@ -540,15 +552,20 @@
  */
 static void irda_usb_net_timeout(struct net_device *netdev)
 {
+	unsigned long flags;
 	struct irda_usb_cb *self = netdev->priv;
-	purb_t purb;
+	struct urb *purb;
 	int	done = 0;	/* If we have made any progress */
 
-	IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n");
+	IRDA_DEBUG(0, "%s(), Network layer thinks we timed out!\n", __FUNCTION__);
+
+	/* Protect us from USB callbacks, net Tx and else. */
+	spin_lock_irqsave(&self->lock, flags);
 
 	if ((!self) || (!self->present)) {
-		WARNING(__FUNCTION__ "(), device not present!\n");
+		WARNING("%s(), device not present!\n", __FUNCTION__);
 		netif_stop_queue(netdev);
+		spin_unlock_irqrestore(&self->lock, flags);
 		return;
 	}
 
@@ -623,6 +640,7 @@
 			break;
 		}
 	}
+	spin_unlock_irqrestore(&self->lock, flags);
 
 	/* Maybe we need a reset */
 	/* Note : Some drivers seem to use a usb_set_interface() when they
@@ -692,16 +710,16 @@
  *
  * Jean II
  */
-static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_t purb)
+static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struct urb *purb)
 {
 	struct irda_skb_cb *cb;
 	int ret;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	/* Check that we have an urb */
 	if (!purb) {
-		WARNING(__FUNCTION__ "(), Bug : purb == NULL\n");
+		WARNING("%s(), Bug : purb == NULL\n", __FUNCTION__);
 		return;
 	}
 
@@ -711,7 +729,7 @@
 		if (!skb) {
 			/* If this ever happen, we are in deep s***.
 			 * Basically, the Rx path will stop... */
-			WARNING(__FUNCTION__ "(), Failed to allocate Rx skb\n");
+			WARNING("%s(), Failed to allocate Rx skb\n", __FUNCTION__);
 			return;
 		}
 	} else  {
@@ -741,7 +759,7 @@
 	if (ret) {
 		/* If this ever happen, we are in deep s***.
 		 * Basically, the Rx path will stop... */
-		WARNING(__FUNCTION__ "(), Failed to submit Rx URB %d\n", ret);
+		WARNING("%s(), Failed to submit Rx URB %d\n", __FUNCTION__, ret);
 	}
 }
 
@@ -752,14 +770,14 @@
  *     Called by the USB subsystem when a frame has been received
  *
  */
-static void irda_usb_receive(purb_t purb) 
+static void irda_usb_receive(struct urb *purb) 
 {
 	struct sk_buff *skb = (struct sk_buff *) purb->context;
 	struct irda_usb_cb *self; 
 	struct irda_skb_cb *cb;
 	struct sk_buff *new;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), len=%d\n", purb->actual_length);
+	IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, purb->actual_length);
 	
 	/* Find ourselves */
 	cb = (struct irda_skb_cb *) skb->cb;
@@ -769,7 +787,7 @@
 
 	/* If the network is closed or the device gone, stop everything */
 	if ((!self->netopen) || (!self->present)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone!\n");
+		IRDA_DEBUG(0, "%s(), Network is gone!\n", __FUNCTION__);
 		/* Don't re-submit the URB : will stall the Rx path */
 		return;
 	}
@@ -782,13 +800,13 @@
 			self->stats.rx_crc_errors++;	
 			break;
 		case -ECONNRESET:		/* -104 */
-			IRDA_DEBUG(0, __FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", purb->transfer_flags);
+			IRDA_DEBUG(0, "%s(), Connection Reset (-104), transfer_flags 0x%04X \n", __FUNCTION__, purb->transfer_flags);
 			/* uhci_cleanup_unlink() is going to kill the Rx
 			 * URB just after we return. No problem, at this
 			 * point the URB will be idle ;-) - Jean II */
 			break;
 		default:
-			IRDA_DEBUG(0, __FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", purb->status, purb->transfer_flags);
+			IRDA_DEBUG(0, "%s(), RX status %d,transfer_flags 0x%04X \n", __FUNCTION__, purb->status, purb->transfer_flags);
 			break;
 		}
 		goto done;
@@ -796,7 +814,7 @@
 	
 	/* Check for empty frames */
 	if (purb->actual_length <= USB_IRDA_HEADER) {
-		WARNING(__FUNCTION__ "(), empty frame!\n");
+		WARNING("%s(), empty frame!\n", __FUNCTION__);
 		goto done;
 	}
 
@@ -900,7 +918,7 @@
  */
 static int irda_usb_net_init(struct net_device *dev)
 {
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 	
 	/* Set up to be a normal IrDA network device driver */
 	irda_device_setup(dev);
@@ -924,7 +942,7 @@
 	char	hwname[16];
 	int i;
 	
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
 	ASSERT(netdev != NULL, return -1;);
 	self = (struct irda_usb_cb *) netdev->priv;
@@ -932,7 +950,7 @@
 
 	/* Can only open the device if it's there */
 	if(!self->present) {
-		WARNING(__FUNCTION__ "(), device not present!\n");
+		WARNING("%s(), device not present!\n", __FUNCTION__);
 		return -1;
 	}
 
@@ -988,7 +1006,7 @@
 	struct irda_usb_cb *self;
 	int	i;
 
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
 	ASSERT(netdev != NULL, return -1;);
 	self = (struct irda_usb_cb *) netdev->priv;
@@ -1003,7 +1021,7 @@
 
 	/* Deallocate all the Rx path buffers (URBs and skb) */
 	for (i = 0; i < IU_MAX_RX_URBS; i++) {
-		purb_t purb = &(self->rx_urb[i]);
+		struct urb *purb = &(self->rx_urb[i]);
 		struct sk_buff *skb = (struct sk_buff *) purb->context;
 		/* Cancel the receive command */
 		usb_unlink_urb(purb);
@@ -1013,8 +1031,10 @@
 			purb->context = NULL;
 		}
 	}
-	/* Cancel Tx and speed URB */
+	/* Cancel Tx and speed URB - need to be synchronous to avoid races */
+	self->tx_urb.transfer_flags &= ~USB_ASYNC_UNLINK;
 	usb_unlink_urb(&(self->tx_urb));
+	self->speed_urb.transfer_flags &= ~USB_ASYNC_UNLINK;
 	usb_unlink_urb(&(self->speed_urb));
 
 	/* Stop and remove instance of IrLAP */
@@ -1033,6 +1053,7 @@
  */
 static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
+	unsigned long flags;
 	struct if_irda_req *irq = (struct if_irda_req *) rq;
 	struct irda_usb_cb *self;
 	int ret = 0;
@@ -1041,25 +1062,28 @@
 	self = dev->priv;
 	ASSERT(self != NULL, return -1;);
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
-
-	/* Check if the device is still there */
-	if(!self->present)
-		return -EFAULT;
+	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
-		/* Set the desired speed */
-		self->new_speed = irq->ifr_baudrate;
-		irda_usb_change_speed_xbofs(self);
-		/* Note : will spinlock in above function */
+		/* Protect us from USB callbacks, net watchdog and else. */
+		spin_lock_irqsave(&self->lock, flags);
+		/* Check if the device is still there */
+		if(self->present) {
+			/* Set the desired speed */
+			self->new_speed = irq->ifr_baudrate;
+			irda_usb_change_speed_xbofs(self);
+		}
+		spin_unlock_irqrestore(&self->lock, flags);
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
-		irda_device_set_media_busy(self->netdev, TRUE);
+		/* Check if the IrDA stack is still there */
+		if(self->netopen)
+			irda_device_set_media_busy(self->netdev, TRUE);
 		break;
 	case SIOCGRECEIVING: /* Check if we are receiving right now */
 		irq->ifr_receiving = irda_usb_is_receiving(self);
@@ -1096,7 +1120,7 @@
 {
 	struct irda_class_desc *desc;
 
-	IRDA_DEBUG(3, __FUNCTION__ "()\n");
+	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 	
 	desc = self->irda_desc;
 	
@@ -1109,7 +1133,8 @@
 	self->qos.window_size.bits     = desc->bmWindowSize;
 	self->qos.data_size.bits       = desc->bmDataSize;
 
-	IRDA_DEBUG(0, __FUNCTION__ "(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", self->qos.baud_rate.bits, self->qos.data_size.bits, self->qos.window_size.bits, self->qos.additional_bofs.bits, self->qos.min_turn_time.bits);
+	IRDA_DEBUG(0, "%s(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", 
+		__FUNCTION__, self->qos.baud_rate.bits, self->qos.data_size.bits, self->qos.window_size.bits, self->qos.additional_bofs.bits, self->qos.min_turn_time.bits);
 
 	/* Don't always trust what the dongle tell us */
 	if(self->capability & IUC_SIR_ONLY)
@@ -1153,7 +1178,7 @@
 	struct net_device *netdev;
 	int err;
 
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
 	spin_lock_init(&self->lock);
 
@@ -1173,7 +1198,7 @@
 
 	/* Create a network device for us */
 	if (!(netdev = dev_alloc("irda%d", &err))) {
-		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
 		return -1;
 	}
 	self->netdev = netdev;
@@ -1193,7 +1218,7 @@
 	err = register_netdevice(netdev);
 	rtnl_unlock();
 	if (err) {
-		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
 		return -1;
 	}
 	MESSAGE("IrDA: Registered device %s\n", netdev->name);
@@ -1208,7 +1233,7 @@
  */
 static inline int irda_usb_close(struct irda_usb_cb *self)
 {
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return -1;);
 
@@ -1290,12 +1315,13 @@
 				/* This is our interrupt endpoint */
 				self->bulk_int_ep = ep;
 			} else {
-				ERROR(__FUNCTION__ "(), Unrecognised endpoint %02X.\n", ep);
+				ERROR("%s(), Unrecognised endpoint %02X.\n", __FUNCTION__, ep);
 			}
 		}
 	}
 
-	IRDA_DEBUG(0, __FUNCTION__ "(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n", self->bulk_in_ep, self->bulk_out_ep, self->bulk_out_mtu, self->bulk_int_ep);
+	IRDA_DEBUG(0, "%s(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n",
+		__FUNCTION__, self->bulk_in_ep, self->bulk_out_ep, self->bulk_out_mtu, self->bulk_int_ep);
 	/* Should be 8, 16, 32 or 64 bytes */
 	ASSERT(self->bulk_out_mtu == 64, ;);
 
@@ -1357,7 +1383,7 @@
 		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 		0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500));
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), ret=%d\n", ret);
+	IRDA_DEBUG(1, "%s(), ret=%d\n", __FUNCTION__, ret);
 	if (ret < sizeof(*desc)) {
 		WARNING("usb-irda: class_descriptor read %s (%d)\n",
 			(ret<0) ? "failed" : "too short", ret);
@@ -1409,15 +1435,14 @@
 		dev->descriptor.idProduct);
 
 	/* Try to cleanup all instance that have a pending disconnect
-	 * Instance will be in this state is the disconnect() occurs
-	 * before the net_close().
+	 * In theory, it can't happen any longer.
 	 * Jean II */
 	for (i = 0; i < NIRUSB; i++) {
 		struct irda_usb_cb *irda = &irda_instance[i];
 		if((irda->usbdev != NULL) &&
 		   (irda->present == 0) &&
 		   (irda->netopen == 0)) {
-			IRDA_DEBUG(0, __FUNCTION__ "(), found a zombie instance !!!\n");
+			IRDA_DEBUG(0, "%s(), found a zombie instance !!!\n", __FUNCTION__);
 			irda_usb_disconnect(irda->usbdev, (void *) irda);
 		}
 	}
@@ -1457,10 +1482,10 @@
 			break;
 		case USB_ST_STALL:		/* -EPIPE = -32 */
 			usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
-			IRDA_DEBUG(0, __FUNCTION__ "(), Clearing stall on control interface\n" );
+			IRDA_DEBUG(0, "%s(), Clearing stall on control interface\n", __FUNCTION__);
 			break;
 		default:
-			IRDA_DEBUG(0, __FUNCTION__ "(), Unknown error %d\n", ret);
+			IRDA_DEBUG(0, "%s(), Unknown error %d\n", __FUNCTION__, ret);
 			return NULL;
 			break;
 	}
@@ -1469,7 +1494,7 @@
 	interface = &dev->actconfig->interface[ifnum].altsetting[0];
 	if(!irda_usb_parse_endpoints(self, interface->endpoint,
 				     interface->bNumEndpoints)) {
-		ERROR(__FUNCTION__ "(), Bogus endpoints...\n");
+		ERROR("%s(), Bogus endpoints...\n", __FUNCTION__);
 		return NULL;
 	}
 
@@ -1494,40 +1519,54 @@
 /*
  * The current irda-usb device is removed, the USB layer tell us
  * to shut it down...
+ * One of the constraints is that when we exit this function,
+ * we cannot use the usb_device no more. Gone. Destroyed. kfree().
+ * Most other subsystem allow you to destroy the instance at a time
+ * when it's convenient to you, to postpone it to a later date, but
+ * not the USB subsystem.
+ * So, we must make bloody sure that everything gets deactivated.
+ * Jean II
  */
 static void irda_usb_disconnect(struct usb_device *dev, void *ptr)
 {
+	unsigned long flags;
 	struct irda_usb_cb *self = (struct irda_usb_cb *) ptr;
 	int i;
 
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+
+	/* Make sure that the Tx path is not executing. - Jean II */
+	spin_lock_irqsave(&self->lock, flags);
 
-	/* Oups ! We are not there any more */
+	/* Oups ! We are not there any more.
+	 * This will stop/desactivate the Tx path. - Jean II */
 	self->present = 0;
 
-	/* Hum... Check if networking is still active */
-	if (self->netopen) {
+	/* We need to have irq enabled to unlink the URBs. That's OK,
+	 * at this point the Tx path is gone - Jean II */
+	spin_unlock_irqrestore(&self->lock, flags);
+
+	/* Hum... Check if networking is still active (avoid races) */
+	if((self->netopen) || (self->irlap)) {
 		/* Accept no more transmissions */
 		/*netif_device_detach(self->netdev);*/
 		netif_stop_queue(self->netdev);
 		/* Stop all the receive URBs */
 		for (i = 0; i < IU_MAX_RX_URBS; i++)
 			usb_unlink_urb(&(self->rx_urb[i]));
-		/* Cancel Tx and speed URB */
+		/* Cancel Tx and speed URB.
+		 * Toggle flags to make sure it's synchronous. */
+		self->tx_urb.transfer_flags &= ~USB_ASYNC_UNLINK;
 		usb_unlink_urb(&(self->tx_urb));
+		self->speed_urb.transfer_flags &= ~USB_ASYNC_UNLINK;
 		usb_unlink_urb(&(self->speed_urb));
-
-		IRDA_DEBUG(0, __FUNCTION__ "(), postponing disconnect, network is still active...\n");
-		/* better not do anything just yet, usb_irda_cleanup()
-		 * will do whats needed */
-		return;
 	}
 
 	/* Cleanup the device stuff */
 	irda_usb_close(self);
 	/* No longer attached to USB bus */
 	self->usbdev = NULL;
-	IRDA_DEBUG(0, __FUNCTION__ "(), USB IrDA Disconnected\n");
+	IRDA_DEBUG(0, "%s(), USB IrDA Disconnected\n", __FUNCTION__);
 }
 
 /*------------------------------------------------------------------*/
@@ -1570,12 +1609,13 @@
 	struct irda_usb_cb *irda = NULL;
 	int	i;
 
-	/* Find zombie instances and kill them... */
+	/* Find zombie instances and kill them...
+	 * In theory, it can't happen any longer. Jean II */
 	for (i = 0; i < NIRUSB; i++) {
 		irda = &irda_instance[i];
 		/* If the Device is zombie */
 		if((irda->usbdev != NULL) && (irda->present == 0)) {
-			IRDA_DEBUG(0, __FUNCTION__ "(), disconnect zombie now !\n");
+			IRDA_DEBUG(0, "%s(), disconnect zombie now !\n", __FUNCTION__);
 			irda_usb_disconnect(irda->usbdev, (void *) irda);
 		}
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/irda/irport.c linux-2.4.20/drivers/net/irda/irport.c
--- linux-2.4.19/drivers/net/irda/irport.c	2002-02-25 19:37:59.000000000 +0000
+++ linux-2.4.20/drivers/net/irda/irport.c	2002-10-29 11:18:33.000000000 +0000
@@ -126,7 +126,7 @@
 {
  	int i;
 
-        IRDA_DEBUG( 4, __FUNCTION__ "()\n");
+        IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
 
 	for (i=0; i < 4; i++) {
  		if (dev_self[i])
@@ -143,15 +143,15 @@
 	void *ret;
 	int err;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	/*
 	 *  Allocate new instance of the driver
 	 */
 	self = kmalloc(sizeof(struct irport_cb), GFP_KERNEL);
 	if (!self) {
-		ERROR(__FUNCTION__ "(), can't allocate memory for "
-		      "control block!\n");
+		ERROR("%s(), can't allocate memory for "
+		      "control block!\n", __FUNCTION__);
 		return NULL;
 	}
 	memset(self, 0, sizeof(struct irport_cb));
@@ -171,8 +171,8 @@
 	/* Lock the port that we need */
 	ret = request_region(self->io.sir_base, self->io.sir_ext, driver_name);
 	if (!ret) { 
-		IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
-			   self->io.sir_base);
+		IRDA_DEBUG(0, "%s(), can't get iobase of 0x%03x\n",
+			__FUNCTION__, self->io.sir_base);
 		return NULL;
 	}
 
@@ -215,7 +215,7 @@
 	self->mode = IRDA_IRLAP;
 
 	if (!(dev = dev_alloc("irda%d", &err))) {
-		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
 		return NULL;
 	}
 	self->netdev = dev;
@@ -243,7 +243,7 @@
 	err = register_netdevice(dev);
 	rtnl_unlock();
 	if (err) {
-		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
 		return NULL;
 	}
 	MESSAGE("IrDA: Registered device %s\n", dev->name);
@@ -268,8 +268,8 @@
 	}
 
 	/* Release the IO-port that this driver is using */
-	IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", 
-		   self->io.sir_base);
+	IRDA_DEBUG(0 , "%s(), Releasing Region %03x\n", 
+		__FUNCTION__, self->io.sir_base);
 	release_region(self->io.sir_base, self->io.sir_ext);
 
 	if (self->tx_buff.head)
@@ -332,7 +332,7 @@
  */
 int irport_probe(int iobase)
 {
-	IRDA_DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase);
+	IRDA_DEBUG(4, "%s(), iobase=%#x\n", __FUNCTION__, iobase);
 
 	return 0;
 }
@@ -352,7 +352,8 @@
 	int lcr;    /* Line control reg */
 	int divisor;
 
-	IRDA_DEBUG(0, __FUNCTION__ "(), Setting speed to: %d\n", speed);
+	IRDA_DEBUG(0, "%s(), Setting speed to: %d\n",
+		__FUNCTION__, speed);
 
 	ASSERT(self != NULL, return;);
 
@@ -407,7 +408,7 @@
 	__u32 speed = (__u32) task->param;
 	int ret = 0;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), <%ld>\n", jiffies); 
+	IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies); 
 
 	self = (struct irport_cb *) task->instance;
 
@@ -449,8 +450,7 @@
 			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
 		break;
 	case IRDA_TASK_CHILD_WAIT:
-		WARNING(__FUNCTION__ 
-			"(), changing speed of dongle timed out!\n");
+		WARNING("%s(), changing speed of dongle timed out!\n",  __FUNCTION__);
 		ret = -1;		
 		break;
 	case IRDA_TASK_CHILD_DONE:
@@ -460,7 +460,7 @@
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n",  __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		ret = -1;
 		break;
@@ -483,7 +483,7 @@
 
 	ASSERT(self != NULL, return;);
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	iobase = self->io.sir_base;
 
@@ -501,7 +501,7 @@
 		 *  if we need to change the speed of the hardware
 		 */
 		if (self->new_speed) {
-			IRDA_DEBUG(5, __FUNCTION__ "(), Changing speed!\n");
+			IRDA_DEBUG(5, "%s(), Changing speed!\n",  __FUNCTION__);
 			irda_task_execute(self, __irport_change_speed, 
 					  irport_change_speed_complete, 
 					  NULL, (void *) self->new_speed);
@@ -541,7 +541,7 @@
 
 	/* Tx FIFO should be empty! */
 	if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), failed, fifo not empty!\n");
+		IRDA_DEBUG(0, "%s(), failed, fifo not empty!\n",  __FUNCTION__);
 		return 0;
 	}
         
@@ -566,7 +566,7 @@
 {
 	struct irport_cb *self;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	self = (struct irport_cb *) task->instance;
 
@@ -617,7 +617,7 @@
 	int iobase;
 	s32 speed;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	ASSERT(dev != NULL, return 0;);
 	
@@ -688,7 +688,7 @@
 
 		/* Make sure we don't stay here to long */
 		if (boguscount++ > 32) {
-			IRDA_DEBUG(2,__FUNCTION__ "(), breaking!\n");
+			IRDA_DEBUG(2, "%s(), breaking!\n",  __FUNCTION__);
 			break;
 		}
 	} while (inb(iobase+UART_LSR) & UART_LSR_DR);	
@@ -708,7 +708,7 @@
 	int iir, lsr;
 
 	if (!dev) {
-		WARNING(__FUNCTION__ "() irq %d for unknown device.\n", irq);
+		WARNING("%s() irq %d for unknown device.\n",  __FUNCTION__, irq);
 		return;
 	}
 	self = (struct irport_cb *) dev->priv;
@@ -722,13 +722,12 @@
 		/* Clear interrupt */
 		lsr = inb(iobase+UART_LSR);
 
-		IRDA_DEBUG(4, __FUNCTION__ 
-			   "(), iir=%02x, lsr=%02x, iobase=%#x\n", 
-			   iir, lsr, iobase);
+		IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", 
+			 __FUNCTION__, iir, lsr, iobase);
 
 		switch (iir) {
 		case UART_IIR_RLSI:
-			IRDA_DEBUG(2, __FUNCTION__ "(), RLSI\n");
+			IRDA_DEBUG(2, "%s(), RLSI\n",  __FUNCTION__);
 			break;
 		case UART_IIR_RDI:
 			/* Receive interrupt */
@@ -740,7 +739,7 @@
 				irport_write_wakeup(self);
 			break;
 		default:
-			IRDA_DEBUG(0, __FUNCTION__ "(), unhandled IIR=%#x\n", iir);
+			IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n",  __FUNCTION__, iir);
 			break;
 		} 
 		
@@ -775,7 +774,7 @@
 	int iobase;
 	char hwname[16];
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 	
 	ASSERT(dev != NULL, return -1;);
 	self = (struct irport_cb *) dev->priv;
@@ -784,8 +783,8 @@
 
 	if (request_irq(self->io.irq, self->interrupt, 0, dev->name, 
 			(void *) dev)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), unable to allocate irq=%d\n",
-			   self->io.irq);
+		IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n",
+			 __FUNCTION__, self->io.irq);
 		return -EAGAIN;
 	}
 
@@ -822,7 +821,7 @@
 	struct irport_cb *self;
 	int iobase;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(dev != NULL, return -1;);
 	self = (struct irport_cb *) dev->priv;
@@ -863,7 +862,7 @@
 
 	/* Wait until Tx FIFO is empty */
 	while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
-		IRDA_DEBUG(2, __FUNCTION__ "(), waiting!\n");
+		IRDA_DEBUG(2, "%s(), waiting!\n",  __FUNCTION__);
 		current->state = TASK_INTERRUPTIBLE;
 		schedule_timeout(MSECS_TO_JIFFIES(60));
 	}
@@ -918,7 +917,7 @@
 
 	/* Tx FIFO should be empty! */
 	if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
-		IRDA_DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n");
+		IRDA_DEBUG( 0, "%s(), failed, fifo not empty!\n",  __FUNCTION__);
 		return -1;
 	}
         
@@ -952,7 +951,7 @@
 
 	ASSERT(self != NULL, return -1;);
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 	
 	/* Disable interrupts & save flags */
 	save_flags(flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/irda/irtty.c linux-2.4.20/drivers/net/irda/irtty.c
--- linux-2.4.19/drivers/net/irda/irtty.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.20/drivers/net/irda/irtty.c	2002-10-29 11:18:35.000000000 +0000
@@ -121,9 +121,8 @@
 	
 	/* Unregister tty line-discipline */
 	if ((ret = tty_register_ldisc(N_IRDA, NULL))) {
-		ERROR(__FUNCTION__ 
-		      "(), can't unregister line discipline (err = %d)\n",
-		      ret);
+		ERROR("%s(), can't unregister line discipline (err = %d)\n",
+			__FUNCTION__, ret);
 	}
 
 	/*
@@ -230,7 +229,7 @@
 	self->rx_buff.data = self->rx_buff.head;
 	
 	if (!(dev = dev_alloc("irda%d", &err))) {
-		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 
@@ -249,7 +248,7 @@
 	err = register_netdevice(dev);
 	rtnl_unlock();
 	if (err) {
-		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
 		return -1;
 	}
 
@@ -352,7 +351,7 @@
 
 	cflag &= ~CBAUD;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), Setting speed to %d\n", speed);
+	IRDA_DEBUG(2, "%s(), Setting speed to %d\n", __FUNCTION__, speed);
 
 	switch (speed) {
 	case 1200:
@@ -400,14 +399,14 @@
 	__u32 speed = (__u32) task->param;
 	int ret = 0;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), <%ld>\n", jiffies); 
+	IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies); 
 
 	self = (struct irtty_cb *) task->instance;
 	ASSERT(self != NULL, return -1;);
 
 	/* Check if busy */
 	if (self->task && self->task != task) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n");
+		IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__);
 		return MSECS_TO_JIFFIES(10);
 	} else
 		self->task = task;
@@ -455,8 +454,7 @@
 			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
 		break;
 	case IRDA_TASK_CHILD_WAIT:
-		WARNING(__FUNCTION__ 
-			"(), changing speed of dongle timed out!\n");
+		WARNING("%s(), changing speed of dongle timed out!\n", __FUNCTION__);
 		ret = -1;		
 		break;
 	case IRDA_TASK_CHILD_DONE:
@@ -467,7 +465,7 @@
 		self->task = NULL;
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->task = NULL;
 		ret = -1;
@@ -559,7 +557,7 @@
 	struct irtty_cb *self = (struct irtty_cb *) tty->disc_data;
 
 	if (!self || !self->netdev) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), not ready yet!\n");
+		IRDA_DEBUG(0, "%s(), not ready yet!\n", __FUNCTION__);
 		return;
 	}
 
@@ -605,7 +603,7 @@
 {
 	struct irtty_cb *self;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	self = (struct irtty_cb *) task->instance;
 
@@ -684,7 +682,7 @@
 */
 static int irtty_receive_room(struct tty_struct *tty) 
 {
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 	return 65536;  /* We can handle an infinite amount of data. :-) */
 }
 
@@ -714,19 +712,19 @@
 
 		self->tx_buff.data += actual;
 		self->tx_buff.len  -= actual;
-
-		self->stats.tx_packets++;		      
 	} else {		
 		/* 
 		 *  Now serial buffer is almost free & we can start 
 		 *  transmission of another packet 
 		 */
-		IRDA_DEBUG(5, __FUNCTION__ "(), finished with frame!\n");
+		IRDA_DEBUG(5, "%s(), finished with frame!\n", __FUNCTION__);
 		
+		self->stats.tx_packets++;		      
+
 		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 
 		if (self->new_speed) {
-			IRDA_DEBUG(5, __FUNCTION__ "(), Changing speed!\n");
+			IRDA_DEBUG(5, "%s(), Changing speed!\n", __FUNCTION__);
 			irda_task_execute(self, irtty_change_speed, 
 					  irtty_change_speed_complete, 
 					  NULL, (void *) self->new_speed);
@@ -760,14 +758,11 @@
 	struct irtty_cb *self;
 	struct tty_struct *tty;
 	mm_segment_t fs;
-	int arg = 0;
+	int arg = TIOCM_MODEM_BITS;
 
 	self = (struct irtty_cb *) dev->priv;
 	tty = self->tty;
 
-#ifdef TIOCM_OUT2 /* Not defined for ARM */
-	arg = TIOCM_OUT2;
-#endif
 	if (rts)
 		arg |= TIOCM_RTS;
 	if (dtr)
@@ -785,7 +780,7 @@
 	set_fs(get_ds());
 	
 	if (tty->driver.ioctl(tty, NULL, TIOCMSET, (unsigned long) &arg)) { 
-		IRDA_DEBUG(2, __FUNCTION__ "(), error doing ioctl!\n");
+		IRDA_DEBUG(2, "%s(), error doing ioctl!\n", __FUNCTION__);
 	}
 	set_fs(fs);
 
@@ -808,7 +803,7 @@
 
 	ASSERT(self != NULL, return -1;);
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), mode=%s\n", infrared_mode[mode]);
+	IRDA_DEBUG(2, "%s(), mode=%s\n", __FUNCTION__, infrared_mode[mode]);
 	
 	/* save status for driver */
 	self->mode = mode;
@@ -901,7 +896,7 @@
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRTTY_MAGIC, return -1;);
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 	
 	/* Ready to play! */
 	netif_start_queue(dev);
@@ -969,7 +964,7 @@
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRTTY_MAGIC, return -1;);
 
-	IRDA_DEBUG(3, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+	IRDA_DEBUG(3, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 	
 	/* Disable interrupts & save flags */
 	save_flags(flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/irda/ma600.c linux-2.4.20/drivers/net/irda/ma600.c
--- linux-2.4.19/drivers/net/irda/ma600.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/irda/ma600.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,356 @@
+/*********************************************************************
+ *                
+ * Filename:      ma600.c
+ * Version:       0.1
+ * Description:   Implementation of the MA600 dongle
+ * Status:        Experimental.
+ * Author:        Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95
+ * Created at:    Sat Jun 10 20:02:35 2000
+ * Modified at:   
+ * Modified by:   
+ *
+ * Note: very thanks to Mr. Maru Wang <maru@mobileaction.com.tw> for providing 
+ *       information on the MA600 dongle
+ * 
+ *     Copyright (c) 2000 Leung, All Rights Reserved.
+ *      
+ *     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
+ *     
+ ********************************************************************/
+
+/* define this macro for release version */
+//#define NDEBUG
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irda_device.h>
+#include <net/irda/irtty.h>
+
+#ifndef NDEBUG
+	#undef IRDA_DEBUG
+	#define IRDA_DEBUG(n, args...) (printk(KERN_DEBUG args))
+
+	#undef ASSERT(expr, func)
+	#define ASSERT(expr, func) \
+	if(!(expr)) { \
+	        printk( "Assertion failed! %s,%s,%s,line=%d\n",\
+        	#expr,__FILE__,__FUNCTION__,__LINE__); \
+	        ##func}
+#endif
+
+/* convert hex value to ascii hex */
+static const char hexTbl[] = "0123456789ABCDEF";
+
+
+static void ma600_open(dongle_t *self, struct qos_info *qos);
+static void ma600_close(dongle_t *self);
+static int  ma600_change_speed(struct irda_task *task);
+static int  ma600_reset(struct irda_task *task);
+
+/* control byte for MA600 */
+#define MA600_9600	0x00
+#define MA600_19200	0x01
+#define MA600_38400	0x02
+#define MA600_57600	0x03
+#define MA600_115200	0x04
+#define MA600_DEV_ID1	0x05
+#define MA600_DEV_ID2	0x06
+#define MA600_2400	0x08
+
+static struct dongle_reg dongle = {
+	Q_NULL,
+	IRDA_MA600_DONGLE,
+	ma600_open,
+	ma600_close,
+	ma600_reset,
+	ma600_change_speed,
+};
+
+int __init ma600_init(void)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	return irda_device_register_dongle(&dongle);
+}
+
+void __exit ma600_cleanup(void)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	irda_device_unregister_dongle(&dongle);
+}
+
+/*
+	Power on:
+		(0) Clear RTS and DTR for 1 second
+		(1) Set RTS and DTR for 1 second
+		(2) 9600 bps now
+	Note: assume RTS, DTR are clear before
+*/
+static void ma600_open(dongle_t *self, struct qos_info *qos)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400
+				|IR_57600|IR_115200;
+	qos->min_turn_time.bits = 0x01;		/* Needs at least 1 ms */	
+	irda_qos_bits_to_value(qos);
+
+	//self->set_dtr_rts(self->dev, FALSE, FALSE);
+	// should wait 1 second
+
+	self->set_dtr_rts(self->dev, TRUE, TRUE);
+	// should wait 1 second
+
+	MOD_INC_USE_COUNT;
+}
+
+static void ma600_close(dongle_t *self)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	/* Power off dongle */
+	self->set_dtr_rts(self->dev, FALSE, FALSE);
+
+	MOD_DEC_USE_COUNT;
+}
+
+static __u8 get_control_byte(__u32 speed)
+{
+	__u8 byte;
+
+	switch (speed) {
+	default:
+	case 115200:
+		byte = MA600_115200;
+		break;
+	case 57600:
+		byte = MA600_57600;
+		break;
+	case 38400:
+		byte = MA600_38400;
+		break;
+	case 19200:
+		byte = MA600_19200;
+		break;
+	case 9600:
+		byte = MA600_9600;
+		break;
+	case 2400:
+		byte = MA600_2400;
+		break;
+	}
+
+	return byte;
+}
+
+/*
+ * Function ma600_change_speed (dev, state, speed)
+ *
+ *    Set the speed for the MA600 type dongle. Warning, this 
+ *    function must be called with a process context!
+ *
+ *    Algorithm
+ *    1. Reset
+ *    2. clear RTS, set DTR and wait for 1ms
+ *    3. send Control Byte to the MA600 through TXD to set new baud rate
+ *       wait until the stop bit of Control Byte is sent (for 9600 baud rate, 
+ *       it takes about 10 msec)
+ *    4. set RTS, set DTR (return to NORMAL Operation)
+ *    5. wait at least 10 ms, new setting (baud rate, etc) takes effect here 
+ *       after
+ */
+static int ma600_change_speed(struct irda_task *task)
+{
+	dongle_t *self = (dongle_t *) task->instance;
+	__u32 speed = (__u32) task->param;
+	static __u8 byte;
+	__u8 byte_echo;
+	int ret = 0;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(task != NULL, return -1;);
+
+	if (self->speed_task && self->speed_task != task) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n");
+		return MSECS_TO_JIFFIES(10);
+	} else {
+		self->speed_task = task;
+	}
+
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+	case IRDA_TASK_CHILD_INIT:
+		/* 
+		 * Need to reset the dongle and go to 9600 bps before
+                 * programming 
+		 */
+		if (irda_task_execute(self, ma600_reset, NULL, task, 
+				      (void *) speed)) {
+			/* Dongle need more time to reset */
+			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
+	
+			/* give 1 second to finish */
+			ret = MSECS_TO_JIFFIES(1000);
+		} else {
+			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
+		}
+		break;
+
+	case IRDA_TASK_CHILD_WAIT:
+		WARNING(__FUNCTION__ "(), resetting dongle timed out!\n");
+		ret = -1;
+		break;
+
+	case IRDA_TASK_CHILD_DONE:
+		/* Set DTR, Clear RTS */
+		self->set_dtr_rts(self->dev, TRUE, FALSE);
+	
+		ret = MSECS_TO_JIFFIES(1);		/* Sleep 1 ms */
+		irda_task_next_state(task, IRDA_TASK_WAIT);
+		break;
+
+	case IRDA_TASK_WAIT:
+		speed = (__u32) task->param;
+		byte = get_control_byte(speed);
+
+		/* Write control byte */
+		self->write(self->dev, &byte, sizeof(byte));
+		
+		irda_task_next_state(task, IRDA_TASK_WAIT1);
+
+		/* Wait at least 10 ms */
+		ret = MSECS_TO_JIFFIES(15);
+		break;
+
+	case IRDA_TASK_WAIT1:
+		/* Read control byte echo */
+		self->read(self->dev, &byte_echo, sizeof(byte_echo));
+
+		if(byte != byte_echo) {
+			/* if control byte != echo, I don't know what to do */
+			printk(KERN_WARNING __FUNCTION__ "() control byte written != read!\n");
+			printk(KERN_WARNING "control byte = 0x%c%c\n", 
+			       hexTbl[(byte>>4)&0x0f], hexTbl[byte&0x0f]);
+			printk(KERN_WARNING "byte echo = 0x%c%c\n", 
+			       hexTbl[(byte_echo>>4) & 0x0f], 
+			       hexTbl[byte_echo & 0x0f]);
+		#ifndef NDEBUG
+		} else {
+			IRDA_DEBUG(2, __FUNCTION__ "() control byte write read OK\n");
+		#endif
+		}
+
+		/* Set DTR, Set RTS */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+
+		irda_task_next_state(task, IRDA_TASK_WAIT2);
+
+		/* Wait at least 10 ms */
+		ret = MSECS_TO_JIFFIES(10);
+		break;
+
+	case IRDA_TASK_WAIT2:
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+		break;
+
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+		ret = -1;
+		break;
+	}
+	return ret;
+}
+
+/*
+ * Function ma600_reset (driver)
+ *
+ *      This function resets the ma600 dongle. Warning, this function 
+ *      must be called with a process context!! 
+ *
+ *      Algorithm:
+ *    	  0. DTR=0, RTS=1 and wait 10 ms
+ *    	  1. DTR=1, RTS=1 and wait 10 ms
+ *        2. 9600 bps now
+ */
+int ma600_reset(struct irda_task *task)
+{
+	dongle_t *self = (dongle_t *) task->instance;
+	int ret = 0;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(task != NULL, return -1;);
+
+	if (self->reset_task && self->reset_task != task) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n");
+		return MSECS_TO_JIFFIES(10);
+	} else
+		self->reset_task = task;
+	
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+		/* Clear DTR and Set RTS */
+		self->set_dtr_rts(self->dev, FALSE, TRUE);
+		irda_task_next_state(task, IRDA_TASK_WAIT1);
+		ret = MSECS_TO_JIFFIES(10);		/* Sleep 10 ms */
+		break;
+	case IRDA_TASK_WAIT1:
+		/* Set DTR and RTS */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+		irda_task_next_state(task, IRDA_TASK_WAIT2);
+		ret = MSECS_TO_JIFFIES(10);		/* Sleep 10 ms */
+		break;
+	case IRDA_TASK_WAIT2:
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);		
+		self->reset_task = NULL;
+		ret = -1;
+	}
+	return ret;
+}
+
+MODULE_AUTHOR("Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95");
+MODULE_DESCRIPTION("MA600 dongle driver version 0.1");
+MODULE_LICENSE("GPL");
+		
+/*
+ * Function init_module (void)
+ *
+ *    Initialize MA600 module
+ *
+ */
+module_init(ma600_init);
+
+/*
+ * Function cleanup_module (void)
+ *
+ *    Cleanup MA600 module
+ *
+ */
+module_exit(ma600_cleanup);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/irda/mcp2120.c linux-2.4.20/drivers/net/irda/mcp2120.c
--- linux-2.4.19/drivers/net/irda/mcp2120.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/irda/mcp2120.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,252 @@
+/*********************************************************************
+ *            
+ *    
+ * Filename:      mcp2120.c
+ * Version:       1.0
+ * Description:   Implementation for the MCP2120 (Microchip)
+ * Status:        Experimental.
+ * Author:        Felix Tang (tangf@eyetap.org)
+ * Created at:    Sun Mar 31 19:32:12 EST 2002
+ * Based on code by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 2002 Felix Tang, All Rights Reserved.
+ *      
+ *     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.
+ *  
+ ********************************************************************/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/irda_device.h>
+#include <net/irda/irtty.h>
+
+static int  mcp2120_reset(struct irda_task *task);
+static void mcp2120_open(dongle_t *self, struct qos_info *qos);
+static void mcp2120_close(dongle_t *self);
+static int  mcp2120_change_speed(struct irda_task *task);
+
+#define MCP2120_9600    0x87
+#define MCP2120_19200   0x8B
+#define MCP2120_38400   0x85
+#define MCP2120_57600   0x83
+#define MCP2120_115200  0x81
+
+#define MCP2120_COMMIT  0x11
+
+static struct dongle_reg dongle = {
+	Q_NULL,
+	IRDA_MCP2120_DONGLE,
+	mcp2120_open,
+	mcp2120_close,
+	mcp2120_reset,
+	mcp2120_change_speed,
+};
+
+int __init mcp2120_init(void)
+{
+	return irda_device_register_dongle(&dongle);
+}
+
+void mcp2120_cleanup(void)
+{
+	irda_device_unregister_dongle(&dongle);
+}
+
+static void mcp2120_open(dongle_t *self, struct qos_info *qos)
+{
+	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+	qos->min_turn_time.bits = 0x01;
+
+	MOD_INC_USE_COUNT;
+}
+
+static void mcp2120_close(dongle_t *self)
+{
+	/* Power off dongle */
+        /* reset and inhibit mcp2120 */
+	self->set_dtr_rts(self->dev, TRUE, TRUE);
+	//self->set_dtr_rts(self->dev, FALSE, FALSE);
+
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * Function mcp2120_change_speed (dev, speed)
+ *
+ *    Set the speed for the MCP2120.
+ *
+ */
+static int mcp2120_change_speed(struct irda_task *task)
+{
+	dongle_t *self = (dongle_t *) task->instance;
+	__u32 speed = (__u32) task->param;
+	__u8 control[2];
+	int ret = 0;
+
+	self->speed_task = task;
+
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+		/* Need to reset the dongle and go to 9600 bps before
+                   programming */
+                //printk("Dmcp2120_change_speed irda_task_init\n");
+		if (irda_task_execute(self, mcp2120_reset, NULL, task, 
+				      (void *) speed))
+		{
+			/* Dongle need more time to reset */
+			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
+
+			/* Give reset 1 sec to finish */
+			ret = MSECS_TO_JIFFIES(1000);
+		}
+		break;
+	case IRDA_TASK_CHILD_WAIT:
+		WARNING(__FUNCTION__ "(), resetting dongle timed out!\n");
+		ret = -1;
+		break;
+	case IRDA_TASK_CHILD_DONE:
+		/* Set DTR to enter command mode */
+		self->set_dtr_rts(self->dev, TRUE, FALSE);
+                udelay(500);
+
+		switch (speed) {
+		case 9600:
+		default:
+			control[0] = MCP2120_9600;
+                        //printk("mcp2120 9600\n");
+			break;
+		case 19200:
+			control[0] = MCP2120_19200;
+                        //printk("mcp2120 19200\n");
+			break;
+		case 34800:
+			control[0] = MCP2120_38400;
+                        //printk("mcp2120 38400\n");
+			break;
+		case 57600:
+			control[0] = MCP2120_57600;
+                        //printk("mcp2120 57600\n");
+			break;
+		case 115200:
+                        control[0] = MCP2120_115200;
+                        //printk("mcp2120 115200\n");
+			break;
+		}
+	        control[1] = MCP2120_COMMIT;
+	
+		/* Write control bytes */
+                self->write(self->dev, control, 2);
+ 
+                irda_task_next_state(task, IRDA_TASK_WAIT);
+		ret = MSECS_TO_JIFFIES(100);
+                //printk("mcp2120_change_speed irda_child_done\n");
+		break;
+	case IRDA_TASK_WAIT:
+		/* Go back to normal mode */
+		self->set_dtr_rts(self->dev, FALSE, FALSE);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+                //printk("mcp2120_change_speed irda_task_wait\n");
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+		ret = -1;
+		break;
+	}
+	return ret;
+}
+
+/*
+ * Function mcp2120_reset (driver)
+ *
+ *      This function resets the mcp2120 dongle.
+ *      
+ *      Info: -set RTS to reset mcp2120
+ *            -set DTR to set mcp2120 software command mode
+ *            -mcp2120 defaults to 9600 baud after reset
+ *
+ *      Algorithm:
+ *      0. Set RTS to reset mcp2120.
+ *      1. Clear RTS and wait for device reset timer of 30 ms (max).
+ *      
+ */
+
+
+static int mcp2120_reset(struct irda_task *task)
+{
+	dongle_t *self = (dongle_t *) task->instance;
+	int ret = 0;
+
+	self->reset_task = task;
+
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+                //printk("mcp2120_reset irda_task_init\n");
+		/* Reset dongle by setting RTS*/
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+		irda_task_next_state(task, IRDA_TASK_WAIT1);
+		ret = MSECS_TO_JIFFIES(50);
+		break;
+	case IRDA_TASK_WAIT1:
+                //printk("mcp2120_reset irda_task_wait1\n");
+                /* clear RTS and wait for at least 30 ms. */
+		self->set_dtr_rts(self->dev, FALSE, FALSE);
+		irda_task_next_state(task, IRDA_TASK_WAIT2);
+		ret = MSECS_TO_JIFFIES(50);
+		break;
+	case IRDA_TASK_WAIT2:
+                //printk("mcp2120_reset irda_task_wait2\n");
+		/* Go back to normal mode */
+		self->set_dtr_rts(self->dev, FALSE, FALSE);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		ret = -1;
+		break;
+	}
+	return ret;
+}
+
+#ifdef MODULE
+MODULE_AUTHOR("Felix Tang <tangf@eyetap.org>");
+MODULE_DESCRIPTION("Microchip MCP2120");
+MODULE_LICENSE("GPL");
+
+	
+/*
+ * Function init_module (void)
+ *
+ *    Initialize MCP2120 module
+ *
+ */
+int init_module(void)
+{
+	return mcp2120_init();
+}
+
+/*
+ * Function cleanup_module (void)
+ *
+ *    Cleanup MCP2120 module
+ *
+ */
+void cleanup_module(void)
+{
+        mcp2120_cleanup();
+}
+#endif /* MODULE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/irda/nsc-ircc.c linux-2.4.20/drivers/net/irda/nsc-ircc.c
--- linux-2.4.19/drivers/net/irda/nsc-ircc.c	2002-02-25 19:37:59.000000000 +0000
+++ linux-2.4.20/drivers/net/irda/nsc-ircc.c	2002-10-29 11:18:31.000000000 +0000
@@ -88,10 +88,14 @@
 
 /* These are the known NSC chips */
 static nsc_chip_t chips[] = {
+/*  Name, {cfg registers}, chip id index reg, chip id expected value, revision mask */
 	{ "PC87108", { 0x150, 0x398, 0xea }, 0x05, 0x10, 0xf0, 
 	  nsc_ircc_probe_108, nsc_ircc_init_108 },
 	{ "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf8, 
 	  nsc_ircc_probe_338, nsc_ircc_init_338 },
+	/* Contributed by Kevin Thayer - OmniBook 6100 */
+	{ "PC87338?", { 0x2e, 0x15c, 0x398 }, 0x08, 0x00, 0xf8, 
+	  nsc_ircc_probe_338, nsc_ircc_init_338 },
 	{ NULL }
 };
 
@@ -161,8 +165,8 @@
 
 	/* Probe for all the NSC chipsets we know about */
 	for (chip=chips; chip->name ; chip++) {
-		IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", 
-			   chip->name);
+		IRDA_DEBUG(2, "%s(), Probing for %s ...\n", 
+			__FUNCTION__, chip->name);
 		
 		/* Try all config registers for this chip */
 		for (cfg=0; cfg<3; cfg++) {
@@ -179,8 +183,8 @@
 			/* Read index register */
 			reg = inb(cfg_base);
 			if (reg == 0xff) {
-				IRDA_DEBUG(2, __FUNCTION__ 
-					   "() no chip at 0x%03x\n", cfg_base);
+				IRDA_DEBUG(2, "%s() no chip at 0x%03x\n", 
+					__FUNCTION__, cfg_base);
 				continue;
 			}
 			
@@ -188,9 +192,8 @@
 			outb(chip->cid_index, cfg_base);
 			id = inb(cfg_base+1);
 			if ((id & chip->cid_mask) == chip->cid_value) {
-				IRDA_DEBUG(2, __FUNCTION__ 
-					   "() Found %s chip, revision=%d\n",
-					   chip->name, id & ~chip->cid_mask);
+				IRDA_DEBUG(2, "%s() Found %s chip, revision=%d\n",
+					__FUNCTION__, chip->name, id & ~chip->cid_mask);
 				/* 
 				 * If the user supplies the base address, then
 				 * we init the chip, if not we probe the values
@@ -205,8 +208,7 @@
 					ret = 0;
 				i++;
 			} else {
-				IRDA_DEBUG(2, __FUNCTION__ 
-					   "(), Wrong chip id=0x%02x\n", id);
+				IRDA_DEBUG(2, "%s(), Wrong chip id=0x%02x\n", __FUNCTION__, id);
 			}
 		} 
 		
@@ -249,7 +251,7 @@
 	void *ret;
 	int err;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	MESSAGE("%s, Found chip at base=0x%03x\n", driver_name,
 		info->cfg_base);
@@ -262,8 +264,8 @@
 	/* Allocate new instance of the driver */
 	self = kmalloc(sizeof(struct nsc_ircc_cb), GFP_KERNEL);
 	if (self == NULL) {
-		ERROR(__FUNCTION__ "(), can't allocate memory for "
-		       "control block!\n");
+		ERROR("%s(), can't allocate memory for "
+		       "control block!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 	memset(self, 0, sizeof(struct nsc_ircc_cb));
@@ -284,8 +286,8 @@
 	/* Reserve the ioports that we need */
 	ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name);
 	if (!ret) {
-		WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n",
-			self->io.fir_base);
+		WARNING("%s(), can't get iobase of 0x%03x\n",
+			__FUNCTION__, self->io.fir_base);
 		dev_self[i] = NULL;
 		kfree(self);
 		return -ENODEV;
@@ -335,7 +337,7 @@
 	self->tx_fifo.tail = self->tx_buff.head;
 
 	if (!(dev = dev_alloc("irda%d", &err))) {
-		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 
@@ -354,7 +356,7 @@
 	err = register_netdevice(dev);
 	rtnl_unlock();
 	if (err) {
-		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
 		return -1;
 	}
 	MESSAGE("IrDA: Registered device %s\n", dev->name);
@@ -391,7 +393,7 @@
 {
 	int iobase;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return -1;);
 
@@ -405,8 +407,8 @@
 	}
 
 	/* Release the PORT that this driver is using */
-	IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", 
-		   self->io.fir_base);
+	IRDA_DEBUG(4, "%s(), Releasing Region %03x\n", 
+		__FUNCTION__, self->io.fir_base);
 	release_region(self->io.fir_base, self->io.fir_ext);
 
 	if (self->tx_buff.head)
@@ -443,7 +445,7 @@
 	case 0x2e8: outb(0x15, cfg_base+1); break;
 	case 0x3f8: outb(0x16, cfg_base+1); break;
 	case 0x2f8: outb(0x17, cfg_base+1); break;
-	default: ERROR(__FUNCTION__ "(), invalid base_address");
+	default: ERROR("%s(), invalid base_address", __FUNCTION__);
 	}
 	
 	/* Control Signal Routing Register (CSRT) */
@@ -455,7 +457,7 @@
 	case 9:  temp = 0x05; break;
 	case 11: temp = 0x06; break;
 	case 15: temp = 0x07; break;
-	default: ERROR(__FUNCTION__ "(), invalid irq");
+	default: ERROR("%s(), invalid irq", __FUNCTION__);
 	}
 	outb(1, cfg_base);
 	
@@ -463,7 +465,7 @@
 	case 0: outb(0x08+temp, cfg_base+1); break;
 	case 1: outb(0x10+temp, cfg_base+1); break;
 	case 3: outb(0x18+temp, cfg_base+1); break;
-	default: ERROR(__FUNCTION__ "(), invalid dma");
+	default: ERROR("%s(), invalid dma", __FUNCTION__);
 	}
 	
 	outb(2, cfg_base);      /* Mode Control Register (MCTL) */
@@ -502,8 +504,8 @@
 		break;
 	}
 	info->sir_base = info->fir_base;
-	IRDA_DEBUG(2, __FUNCTION__ "(), probing fir_base=0x%03x\n", 
-		   info->fir_base);
+	IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", 
+		__FUNCTION__, info->fir_base);
 
 	/* Read control signals routing register (CSRT) */
 	outb(CFG_CSRT, cfg_base);
@@ -535,7 +537,7 @@
 		info->irq = 15;
 		break;
 	}
-	IRDA_DEBUG(2, __FUNCTION__ "(), probing irq=%d\n", info->irq);
+	IRDA_DEBUG(2, "%s(), probing irq=%d\n", __FUNCTION__, info->irq);
 
 	/* Currently we only read Rx DMA but it will also be used for Tx */
 	switch ((reg >> 3) & 0x03) {
@@ -552,7 +554,7 @@
 		info->dma = 3;
 		break;
 	}
-	IRDA_DEBUG(2, __FUNCTION__ "(), probing dma=%d\n", info->dma);
+	IRDA_DEBUG(2, "%s(), probing dma=%d\n", __FUNCTION__, info->dma);
 
 	/* Read mode control register (MCTL) */
 	outb(CFG_MCTL, cfg_base);
@@ -698,6 +700,9 @@
 	switch_bank(iobase, BANK3);
 	version = inb(iobase+MID);
 
+	IRDA_DEBUG(2, __FUNCTION__  "() Driver %s Found chip version %02x\n",
+		   driver_name, version);
+
 	/* Should be 0x2? */
 	if (0x20 != (version & 0xf0)) {
 		ERROR("%s, Wrong chip version %02x\n", driver_name, version);
@@ -798,39 +803,39 @@
 	switch (dongle_id) {
 	case 0x00: /* same as */
 	case 0x01: /* Differential serial interface */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			__FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x02: /* same as */
 	case 0x03: /* Reserved */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			__FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x04: /* Sharp RY5HD01 */
 		break;
 	case 0x05: /* Reserved, but this is what the Thinkpad reports */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			__FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x06: /* Single-ended serial interface */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			__FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x07: /* Consumer-IR only */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n",
+			__FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s\n",
-			   dongle_types[dongle_id]);
+		IRDA_DEBUG(0, "%s(), %s\n",
+			__FUNCTION__, dongle_types[dongle_id]);
 		break;
 	case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
 		outb(0x28, iobase+7); /* Set irsl[0-2] as output */
 		break;
 	case 0x0A: /* same as */
 	case 0x0B: /* Reserved */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			__FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x0C: /* same as */
 	case 0x0D: /* HP HSDL-1100/HSDL-2100 */
@@ -844,15 +849,15 @@
 		outb(0x28, iobase+7); /* Set irsl[0-2] as output */
 		break;
 	case 0x0F: /* No dongle connected */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s\n",
+			__FUNCTION__, dongle_types[dongle_id]); 
 
 		switch_bank(iobase, BANK0);
 		outb(0x62, iobase+MCR);
 		break;
 	default: 
-		IRDA_DEBUG(0, __FUNCTION__ "(), invalid dongle_id %#x", 
-			   dongle_id);
+		IRDA_DEBUG(0, "%s(), invalid dongle_id %#x", 
+			__FUNCTION__, dongle_id);
 	}
 	
 	/* IRCFG1: IRSL1 and 2 are set to IrDA mode */
@@ -884,31 +889,31 @@
 	switch (dongle_id) {
 	case 0x00: /* same as */
 	case 0x01: /* Differential serial interface */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			__FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x02: /* same as */
 	case 0x03: /* Reserved */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			__FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x04: /* Sharp RY5HD01 */
 		break;
 	case 0x05: /* Reserved */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			__FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x06: /* Single-ended serial interface */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			__FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x07: /* Consumer-IR only */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n",
+			__FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", 
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s\n", 
+			__FUNCTION__, dongle_types[dongle_id]); 
 		outb(0x00, iobase+4);
 		if (speed > 115200)
 			outb(0x01, iobase+4);
@@ -927,8 +932,8 @@
 		break;
 	case 0x0A: /* same as */
 	case 0x0B: /* Reserved */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			__FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x0C: /* same as */
 	case 0x0D: /* HP HSDL-1100/HSDL-2100 */
@@ -936,14 +941,14 @@
 	case 0x0E: /* Supports SIR Mode only */
 		break;
 	case 0x0F: /* No dongle connected */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
-			   dongle_types[dongle_id]);
+		IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n",
+			__FUNCTION__, dongle_types[dongle_id]);
 
 		switch_bank(iobase, BANK0); 
 		outb(0x62, iobase+MCR);
 		break;
 	default: 
-		IRDA_DEBUG(0, __FUNCTION__ "(), invalid data_rate\n");
+		IRDA_DEBUG(0, "%s(), invalid data_rate\n", __FUNCTION__);
 	}
 	/* Restore bank register */
 	outb(bank, iobase+BSR);
@@ -962,7 +967,7 @@
 	int iobase; 
 	__u8 bank;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d\n", speed);
+	IRDA_DEBUG(2, "%s(), speed=%d\n", __FUNCTION__, speed);
 
 	ASSERT(self != NULL, return;);
 
@@ -995,20 +1000,20 @@
 		outb(inb(iobase+4) | 0x04, iobase+4);
 	       
 		mcr = MCR_MIR;
-		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n");
+		IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __FUNCTION__);
 		break;
 	case 1152000:
 		mcr = MCR_MIR;
-		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
+		IRDA_DEBUG(0, "%s(), handling baud of 1152000\n", __FUNCTION__);
 		break;
 	case 4000000:
 		mcr = MCR_FIR;
-		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
+		IRDA_DEBUG(0, "%s(), handling baud of 4000000\n", __FUNCTION__);
 		break;
 	default:
 		mcr = MCR_FIR;
-		IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", 
-			   speed);
+		IRDA_DEBUG(0, "%s(), unknown baud rate of %d\n", 
+			__FUNCTION__, speed);
 		break;
 	}
 
@@ -1271,15 +1276,14 @@
 	int actual = 0;
 	__u8 bank;
 	
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	/* Save current bank */
 	bank = inb(iobase+BSR);
 
 	switch_bank(iobase, BANK0);
 	if (!(inb_p(iobase+LSR) & LSR_TXEMP)) {
-		IRDA_DEBUG(4, __FUNCTION__ 
-			   "(), warning, FIFO not empty yet!\n");
+		IRDA_DEBUG(4, "%s(), warning, FIFO not empty yet!\n", __FUNCTION__);
 
 		/* FIFO may still be filled to the Tx interrupt threshold */
 		fifo_size -= 17;
@@ -1291,8 +1295,8 @@
 		outb(buf[actual++], iobase+TXD);
 	}
         
-	IRDA_DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
-		   fifo_size, actual, len);
+	IRDA_DEBUG(4, "%s(), fifo_size %d ; %d sent of %d\n", 
+		__FUNCTION__, fifo_size, actual, len);
 	
 	/* Restore bank */
 	outb(bank, iobase+BSR);
@@ -1313,7 +1317,7 @@
 	__u8 bank;
 	int ret = TRUE;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	iobase = self->io.fir_base;
 
@@ -1449,7 +1453,7 @@
 		len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8);
 
 		if (st_fifo->tail >= MAX_RX_WINDOW) {
-			IRDA_DEBUG(0, __FUNCTION__ "(), window is full!\n");
+			IRDA_DEBUG(0, "%s(), window is full!\n", __FUNCTION__);
 			continue;
 		}
 			
@@ -1539,8 +1543,8 @@
 
 			skb = dev_alloc_skb(len+1);
 			if (skb == NULL)  {
-				WARNING(__FUNCTION__ "(), memory squeeze, "
-					"dropping frame.\n");
+				WARNING("%s(), memory squeeze, "
+					"dropping frame.\n", __FUNCTION__);
 				self->stats.rx_dropped++;
 
 				/* Restore bank register */
@@ -1636,7 +1640,7 @@
 	if (eir & EIR_TXEMP_EV) {
 		/* Check if we need to change the speed? */
 		if (self->new_speed) {
-			IRDA_DEBUG(2, __FUNCTION__ "(), Changing speed!\n");
+			IRDA_DEBUG(2, "%s(), Changing speed!\n", __FUNCTION__);
 			nsc_ircc_change_speed(self, self->new_speed);
 			self->new_speed = 0;
 
@@ -1815,7 +1819,7 @@
  */
 static int nsc_ircc_net_init(struct net_device *dev)
 {
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	/* Setup to be a normal IrDA network device driver */
 	irda_device_setup(dev);
@@ -1838,7 +1842,7 @@
 	char hwname[32];
 	__u8 bank;
 	
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 	
 	ASSERT(dev != NULL, return -1;);
 	self = (struct nsc_ircc_cb *) dev->priv;
@@ -1902,7 +1906,7 @@
 	int iobase;
 	__u8 bank;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 	
 	ASSERT(dev != NULL, return -1;);
 
@@ -1958,7 +1962,7 @@
 
 	ASSERT(self != NULL, return -1;);
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 	
 	/* Disable interrupts & save flags */
 	save_flags(flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/irda/smc-ircc.c linux-2.4.20/drivers/net/irda/smc-ircc.c
--- linux-2.4.19/drivers/net/irda/smc-ircc.c	2001-10-05 01:41:09.000000000 +0000
+++ linux-2.4.20/drivers/net/irda/smc-ircc.c	2002-10-29 11:18:31.000000000 +0000
@@ -170,7 +170,7 @@
 
 static int __init smc_access(unsigned short cfg_base,unsigned char reg)
 {
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	outb(reg, cfg_base);
 
@@ -184,7 +184,7 @@
 {
 	u8 devid,xdevid,rev; 
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	/* Leave configuration */
 
@@ -263,7 +263,7 @@
 	u8 mode;
 	int ret = -ENODEV;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	if (smc_probe(cfg_base,0xD,chips,type)==NULL)
 		return ret;
@@ -307,7 +307,7 @@
 	unsigned short sir_io;
 	int ret = -ENODEV;
 	
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	if (smc_probe(cfg_base,0x20,chips,type)==NULL)
 		return ret;
@@ -343,8 +343,8 @@
 static int __init smc_superio_fdc(unsigned short cfg_base)
 {
 	if (check_region(cfg_base, 2) < 0) {
-		IRDA_DEBUG(0, __FUNCTION__ ": can't get cfg_base of 0x%03x\n",
-			   cfg_base);
+		IRDA_DEBUG(0, "%s: can't get cfg_base of 0x%03x\n",
+			__FUNCTION__, cfg_base);
 		return -1;
 	}
 
@@ -358,8 +358,8 @@
 {
 #if 0
 	if (check_region(cfg_base, 2) < 0) {
-		IRDA_DEBUG(0, __FUNCTION__ ": can't get cfg_base of 0x%03x\n",
-			   cfg_base);
+		IRDA_DEBUG(0, "%s: can't get cfg_base of 0x%03x\n",
+			__FUNCTION__, cfg_base);
 		return -1;
 	}
 #endif
@@ -380,7 +380,7 @@
 {
 	int ret=-ENODEV;
 
-	IRDA_DEBUG(0, __FUNCTION__ "\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	dev_count=0;
 
@@ -403,8 +403,7 @@
 
 	/* Trys to open for all the SMC chipsets we know about */
 
-	IRDA_DEBUG(0, __FUNCTION__ 
-	" Try to open all known SMC chipsets\n");
+	IRDA_DEBUG(0, "%s Try to open all known SMC chipsets\n", __FUNCTION__);
 
 	if (!smc_superio_fdc(0x3f0))
 		ret=0;
@@ -433,17 +432,17 @@
 	unsigned char low, high, chip, config, dma, irq, version;
 
 
-	IRDA_DEBUG(0, __FUNCTION__ "\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	if (check_region(fir_base, CHIP_IO_EXTENT) < 0) {
-		IRDA_DEBUG(0, __FUNCTION__ ": can't get fir_base of 0x%03x\n",
-			   fir_base);
+		IRDA_DEBUG(0, "%s: can't get fir_base of 0x%03x\n",
+			__FUNCTION__, fir_base);
 		return -ENODEV;
 	}
 #if POSSIBLE_USED_BY_SERIAL_DRIVER
 	if (check_region(sir_base, CHIP_IO_EXTENT) < 0) {
-		IRDA_DEBUG(0, __FUNCTION__ ": can't get sir_base of 0x%03x\n",
-			   sir_base);
+		IRDA_DEBUG(0, "%s: can't get sir_base of 0x%03x\n",
+			__FUNCTION__, sir_base);
 		return -ENODEV;
 	}
 #endif
@@ -460,8 +459,8 @@
 	dma     = config & 0x0f;
 
         if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) { 
-	        IRDA_DEBUG(0, __FUNCTION__ 
-			   "(), addr 0x%04x - no device found!\n", fir_base);
+	        IRDA_DEBUG(0, "%s(), addr 0x%04x - no device found!\n", 
+	        	__FUNCTION__, fir_base);
 		return -ENODEV;
 	}
 	MESSAGE("SMC IrDA Controller found\n IrCC version %d.%d, "
@@ -469,8 +468,7 @@
 		chip & 0x0f, version, fir_base, sir_base, dma, irq);
 
 	if (dev_count>DIM(dev_self)) {
-	        IRDA_DEBUG(0, __FUNCTION__ 
-			   "(), to many devices!\n");
+	        IRDA_DEBUG(0, "%s(), to many devices!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 
@@ -605,7 +603,7 @@
 	struct ircc_cb *self = (struct ircc_cb *) priv;
 	struct net_device *dev;
 
-	IRDA_DEBUG(0, __FUNCTION__ "\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 
@@ -620,8 +618,8 @@
 
 	switch (speed) {
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", 
-			   speed);
+		IRDA_DEBUG(0, "%s(), unknown baud rate of %d\n", 
+			__FUNCTION__, speed);
 		/* FALLTHROUGH */
 	case 9600:
 	case 19200:
@@ -636,19 +634,19 @@
 		ir_mode = IRCC_CFGA_IRDA_HDLC;
 		ctrl = IRCC_CRC;
 		fast = 0;
-		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n");
+		IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __FUNCTION__);
 		break;
 	case 1152000:
 		ir_mode = IRCC_CFGA_IRDA_HDLC;
 		ctrl = IRCC_1152 | IRCC_CRC;
 		fast = 0;
-		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
+		IRDA_DEBUG(0, "%s(), handling baud of 1152000\n", __FUNCTION__);
 		break;
 	case 4000000:
 		ir_mode = IRCC_CFGA_IRDA_4PPM;
 		ctrl = IRCC_CRC;
 		fast = IRCC_LCR_A_FAST;
-		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
+		IRDA_DEBUG(0, "%s(), handling baud of 4000000\n", __FUNCTION__);
 		break;
 	}
 	
@@ -676,8 +674,7 @@
 		dev->hard_start_xmit = &irport_hard_xmit;
 		irport_start(self->irport);
 		
-	        IRDA_DEBUG(0, __FUNCTION__ 
-			   "(), using irport to change speed to %d\n", speed);
+	        IRDA_DEBUG(0, "%s(), using irport to change speed to %d\n", __FUNCTION__, speed);
 		irport_change_speed(self->irport, speed);
 	}	
 
@@ -779,7 +776,7 @@
 {
 	u8 ctrl;
 
-	IRDA_DEBUG(2, __FUNCTION__ "\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 #if 0	
 	/* Disable Rx */
 	register_bank(iobase, 0);
@@ -829,7 +826,7 @@
  */
 static void ircc_dma_xmit_complete(struct ircc_cb *self, int iobase)
 {
-	IRDA_DEBUG(2, __FUNCTION__ "\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 #if 0
 	/* Disable Tx */
 	register_bank(iobase, 0);
@@ -915,7 +912,7 @@
 	struct sk_buff *skb;
 	int len, msgcnt;
 
-	IRDA_DEBUG(2, __FUNCTION__ "\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 #if 0
 	/* Disable Rx */
 	register_bank(iobase, 0);
@@ -924,8 +921,8 @@
 	register_bank(iobase, 0);
 	msgcnt = inb(iobase+IRCC_LCR_B) & 0x08;
 
-	IRDA_DEBUG(2, __FUNCTION__ ": dma count = %d\n",
-		   get_dma_residue(self->io->dma));
+	IRDA_DEBUG(2, "%s: dma count = %d\n",
+		__FUNCTION__, get_dma_residue(self->io->dma));
 
 	len = self->rx_buff.truesize - get_dma_residue(self->io->dma);
 	
@@ -936,14 +933,14 @@
 		len -= 4;
 
 	if ((len < 2) || (len > 2050)) {
-		WARNING(__FUNCTION__ "(), bogus len=%d\n", len);
+		WARNING("%s(), bogus len=%d\n", __FUNCTION__, len);
 		return;
 	}
-	IRDA_DEBUG(2, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len);
+	IRDA_DEBUG(2, "%s: msgcnt = %d, len=%d\n", __FUNCTION__, msgcnt, len);
 
 	skb = dev_alloc_skb(len+1);
 	if (!skb)  {
-		WARNING(__FUNCTION__ "(), memory squeeze, dropping frame.\n");
+		WARNING("%s(), memory squeeze, dropping frame.\n", __FUNCTION__);
 		return;
 	}			
 	/* Make sure IP header gets aligned */
@@ -997,7 +994,7 @@
 	/* Disable interrupts */
 	outb(0, iobase+IRCC_IER);
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), iir = 0x%02x\n", iir);
+	IRDA_DEBUG(2, "%s(), iir = 0x%02x\n", __FUNCTION__, iir);
 
 	if (iir & IRCC_IIR_EOM) {
 		if (self->io->direction == IO_RECV)
@@ -1027,12 +1024,12 @@
 	int status = FALSE;
 	/* int iobase; */
 
-	IRDA_DEBUG(0, __FUNCTION__ "\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return FALSE;);
 
-	IRDA_DEBUG(0, __FUNCTION__ ": dma count = %d\n",
-		   get_dma_residue(self->io->dma));
+	IRDA_DEBUG(0, "%s: dma count = %d\n",
+		__FUNCTION__, get_dma_residue(self->io->dma));
 
 	status = (self->rx_buff.state != OUTSIDE_FRAME);
 	
@@ -1052,7 +1049,7 @@
 	struct ircc_cb *self;
 	int iobase;
 
-	IRDA_DEBUG(0, __FUNCTION__ "\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 	
 	ASSERT(dev != NULL, return -1;);
 	irport = (struct irport_cb *) dev->priv;
@@ -1071,7 +1068,7 @@
 	if (request_dma(self->io->dma, dev->name)) {
 		irport_net_close(dev);
 
-		WARNING(__FUNCTION__ "(), unable to allocate DMA=%d\n", self->io->dma);
+		WARNING("%s(), unable to allocate DMA=%d\n", __FUNCTION__, self->io->dma);
 		return -EAGAIN;
 	}
 	
@@ -1092,7 +1089,7 @@
 	struct ircc_cb *self;
 	int iobase;
 
-	IRDA_DEBUG(0, __FUNCTION__ "\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 	
 	ASSERT(dev != NULL, return -1;);
 	irport = (struct irport_cb *) dev->priv;
@@ -1170,7 +1167,7 @@
 {
 	int iobase;
 
-	IRDA_DEBUG(0, __FUNCTION__ "\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return -1;);
 
@@ -1190,8 +1187,8 @@
         outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);
 #endif
 	/* Release the PORT that this driver is using */
-	IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n", 
-		   self->io->fir_base);
+	IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", 
+		__FUNCTION__, self->io->fir_base);
 
 	release_region(self->io->fir_base, self->io->fir_ext);
 
@@ -1207,7 +1204,7 @@
 }
 #endif /* MODULE */
 
-int __init smc_init(void)
+static int __init smc_init(void)
 {
 	return ircc_init();
 }
@@ -1216,7 +1213,7 @@
 {
 	int i;
 
-	IRDA_DEBUG(0, __FUNCTION__ "\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	for (i=0; i < 2; i++) {
 		if (dev_self[i])
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/irda/tekram.c linux-2.4.20/drivers/net/irda/tekram.c
--- linux-2.4.19/drivers/net/irda/tekram.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.20/drivers/net/irda/tekram.c	2002-10-29 11:18:48.000000000 +0000
@@ -67,7 +67,7 @@
 
 static void tekram_open(dongle_t *self, struct qos_info *qos)
 {
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
 	qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */	
@@ -78,7 +78,7 @@
 
 static void tekram_close(dongle_t *self)
 {
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	/* Power off dongle */
 	self->set_dtr_rts(self->dev, FALSE, FALSE);
@@ -114,12 +114,12 @@
 	__u8 byte;
 	int ret = 0;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	ASSERT(task != NULL, return -1;);
 
 	if (self->speed_task && self->speed_task != task) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n");
+		IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__);
 		return MSECS_TO_JIFFIES(10);
 	} else
 		self->speed_task = task;
@@ -162,7 +162,7 @@
 			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
 		break;
 	case IRDA_TASK_CHILD_WAIT:
-		WARNING(__FUNCTION__ "(), resetting dongle timed out!\n");
+		WARNING("%s(), resetting dongle timed out!\n", __FUNCTION__);
 		ret = -1;
 		break;
 	case IRDA_TASK_CHILD_DONE:
@@ -188,7 +188,7 @@
 		self->speed_task = NULL;
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->speed_task = NULL;
 		ret = -1;
@@ -215,12 +215,12 @@
 	dongle_t *self = (dongle_t *) task->instance;
 	int ret = 0;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	ASSERT(task != NULL, return -1;);
 
 	if (self->reset_task && self->reset_task != task) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n");
+		IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__);
 		return MSECS_TO_JIFFIES(10);
 	} else
 		self->reset_task = task;
@@ -256,7 +256,7 @@
 		self->reset_task = NULL;
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);		
 		self->reset_task = NULL;
 		ret = -1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/irda/toshoboe.c linux-2.4.20/drivers/net/irda/toshoboe.c
--- linux-2.4.19/drivers/net/irda/toshoboe.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.20/drivers/net/irda/toshoboe.c	2002-10-29 11:18:31.000000000 +0000
@@ -94,7 +94,7 @@
 static void
 toshoboe_stopchip (struct toshoboe_cb *self)
 {
-  IRDA_DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
 
   outb_p (0x0e, OBOE_REG_11);
 
@@ -115,7 +115,7 @@
 toshoboe_setbaud (struct toshoboe_cb *self, int baud)
 {
   unsigned long flags;
-  IRDA_DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
 
   printk (KERN_WARNING "ToshOboe: setting baud to %d\n", baud);
 
@@ -185,7 +185,7 @@
 {
   __u32 physaddr;
 
-  IRDA_DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
 
 
   outb_p (0, OBOE_LOCK);
@@ -214,7 +214,7 @@
 static void
 toshoboe_enablebm (struct toshoboe_cb *self)
 {
-  IRDA_DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
   pci_set_master (self->pdev);
 }
 
@@ -223,7 +223,7 @@
 toshoboe_disablebm (struct toshoboe_cb *self)
 {
   __u8 command;
-  IRDA_DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
 
   pci_read_config_byte (self->pdev, PCI_COMMAND, &command);
   command &= ~PCI_COMMAND_MASTER;
@@ -238,7 +238,7 @@
   int i;
   unsigned long flags;
 
-  IRDA_DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
 
   save_flags (flags);
   cli ();
@@ -365,7 +365,7 @@
       return;
     }
 
-  IRDA_DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
 
   irqstat = inb_p (OBOE_ISR);
 
@@ -423,8 +423,7 @@
             }
           else
             {
-              printk (KERN_INFO __FUNCTION__
-                      "(), memory squeeze, dropping frame.\n");
+              printk (KERN_INFO "%s(), memory squeeze, dropping frame.\n", __FUNCTION__);
             }
 
           self->taskfile->recv[self->rxs].control = 0x83;
@@ -463,7 +462,7 @@
 static int
 toshoboe_net_init (struct net_device *dev)
 {
-  IRDA_DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
 
   /* Setup to be a normal IrDA network device driver */
   irda_device_setup (dev);
@@ -512,7 +511,7 @@
   struct toshoboe_cb *self;
   char hwname[32];
 
-  IRDA_DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
 
   ASSERT (dev != NULL, return -1;
     );
@@ -559,7 +558,7 @@
 {
   struct toshoboe_cb *self;
 
-  IRDA_DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
 
   ASSERT (dev != NULL, return -1;
     );
@@ -608,7 +607,7 @@
 
 	ASSERT(self != NULL, return -1;);
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 	
 	/* Disable interrupts & save flags */
 	save_flags(flags);
@@ -654,7 +653,7 @@
   int i;
   struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev);
 
-  IRDA_DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
 
   ASSERT (self != NULL, return;
     );
@@ -704,7 +703,7 @@
   int ok = 0;
   int err;
 
-  IRDA_DEBUG (4, __FUNCTION__ "()\n");
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
 
   if ((err=pci_enable_device(pci_dev)))
 	  return err;
@@ -733,8 +732,8 @@
   /* Lock the port that we need */
   if (NULL==request_region (self->io.sir_base, self->io.sir_ext, driver_name))
     {
-      IRDA_DEBUG (0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
-             self->io.sir_base);
+      IRDA_DEBUG (0, "%s(), can't get iobase of 0x%03x\n",
+      	__FUNCTION__, self->io.sir_base);
 
       err = -EBUSY;
       goto freeself;
@@ -824,7 +823,7 @@
 
 
   if (!(dev = dev_alloc("irda%d", &err))) {
-      ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+      ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
       err = -ENOMEM;
       goto freebufs;
   }
@@ -843,7 +842,7 @@
   err = register_netdevice(dev);
   rtnl_unlock();
   if (err) {
-	  ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+	  ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
 	  /* XXX there is not freeing for dev? */
           goto freebufs;
   }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/irda/w83977af_ir.c linux-2.4.20/drivers/net/irda/w83977af_ir.c
--- linux-2.4.19/drivers/net/irda/w83977af_ir.c	2002-02-25 19:37:59.000000000 +0000
+++ linux-2.4.20/drivers/net/irda/w83977af_ir.c	2002-10-29 11:18:37.000000000 +0000
@@ -117,7 +117,7 @@
 {
         int i;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s\n", __FUNCTION__);
 
 	for (i=0; (io[i] < 2000) && (i < 4); i++) { 
 		int ioaddr = io[i];
@@ -140,7 +140,7 @@
 {
 	int i;
 
-        IRDA_DEBUG(4, __FUNCTION__ "()\n");
+        IRDA_DEBUG(4, "%s\n", __FUNCTION__);
 
 	for (i=0; i < 4; i++) {
 		if (dev_self[i])
@@ -163,7 +163,7 @@
 	void *ret;
 	int err;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s\n", __FUNCTION__);
 
 	if (w83977af_probe(iobase, irq, dma) == -1)
 		return -1;
@@ -192,8 +192,8 @@
 	/* Lock the port that we need */
 	ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name);
 	if (!ret) { 
-		IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
-		      self->io.fir_base);
+		IRDA_DEBUG(0, "%s(), can't get iobase of 0x%03x\n",
+			__FUNCTION__, self->io.fir_base);
 		/* w83977af_cleanup( self);  */
 		return -ENODEV;
 	}
@@ -239,7 +239,7 @@
 	self->rx_buff.data = self->rx_buff.head;
 	
 	if (!(dev = dev_alloc("irda%d", &err))) {
-		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 	dev->priv = (void *) self;
@@ -257,7 +257,7 @@
 	err = register_netdevice(dev);
 	rtnl_unlock();
 	if (err) {
-		ERROR(__FUNCTION__ "(), register_netdevice() failed!\n");
+		ERROR("%s(), register_netdevice() failed!\n", __FUNCTION__);
 		return -1;
 	}
 	MESSAGE("IrDA: Registered device %s\n", dev->name);
@@ -275,7 +275,7 @@
 {
 	int iobase;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s\n", __FUNCTION__);
 
         iobase = self->io.fir_base;
 
@@ -299,8 +299,8 @@
 	}
 
 	/* Release the PORT that this driver is using */
-	IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", 
-	      self->io.fir_base);
+	IRDA_DEBUG(0 , "%s(), Releasing Region %03x\n", 
+		__FUNCTION__, self->io.fir_base);
 	release_region(self->io.fir_base, self->io.fir_ext);
 
 	if (self->tx_buff.head)
@@ -320,7 +320,7 @@
 	int i;
   	
  	for (i=0; i < 2; i++) {
- 		IRDA_DEBUG( 0, __FUNCTION__ "()\n");
+ 		IRDA_DEBUG( 0, "%s\n", __FUNCTION__);
 #ifdef CONFIG_USE_W977_PNP
  		/* Enter PnP configuration mode */
 		w977_efm_enter(efbase[i]);
@@ -407,7 +407,7 @@
 			return 0;
 		} else {
 			/* Try next extented function register address */
-			IRDA_DEBUG( 0, __FUNCTION__ "(), Wrong chip version");
+			IRDA_DEBUG( 0, "%s(), Wrong chip version", __FUNCTION__);
 		}
   	}   	
 	return -1;
@@ -443,19 +443,19 @@
 	case 115200: outb(0x01, iobase+ABLL); break;
 	case 576000:
 		ir_mode = HCR_MIR_576;
-		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n");
+		IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __FUNCTION__);
 		break;
 	case 1152000:
 		ir_mode = HCR_MIR_1152;
-		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
+		IRDA_DEBUG(0, "%s(), handling baud of 1152000\n", __FUNCTION__);
 		break;
 	case 4000000:
 		ir_mode = HCR_FIR;
-		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
+		IRDA_DEBUG(0, "%s(), handling baud of 4000000\n", __FUNCTION__);
 		break;
 	default:
 		ir_mode = HCR_FIR;
-		IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", speed);
+		IRDA_DEBUG(0, "%s(), unknown baud rate of %d\n", __FUNCTION__, speed);
 		break;
 	}
 
@@ -505,7 +505,7 @@
 
 	iobase = self->io.fir_base;
 
-	IRDA_DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, 
+	IRDA_DEBUG(4, "%s(%ld), skb->len=%d\n", __FUNCTION__, jiffies, 
 		   (int) skb->len);
 	
 	/* Lock transmit buffer */
@@ -552,7 +552,7 @@
 			outb(ICR_ETMRI, iobase+ICR);
 		} else {
 #endif
-			IRDA_DEBUG(4,__FUNCTION__ "(%ld), mtt=%d\n", jiffies, mtt);
+			IRDA_DEBUG(4, "%s(%ld), mtt=%d\n", __FUNCTION__, jiffies, mtt);
 			if (mtt)
 				udelay(mtt);
 
@@ -593,7 +593,7 @@
 	unsigned long flags;
 	__u8 hcr;
 #endif
-        IRDA_DEBUG(4, __FUNCTION__ "(), len=%d\n", self->tx_buff.len);
+        IRDA_DEBUG(4, "%s(), len=%d\n", __FUNCTION__, self->tx_buff.len);
 
 	/* Save current set */
 	set = inb(iobase+SSR);
@@ -646,19 +646,18 @@
 	int actual = 0;
 	__u8 set;
 	
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s\n", __FUNCTION__);
 
 	/* Save current bank */
 	set = inb(iobase+SSR);
 
 	switch_bank(iobase, SET0);
 	if (!(inb_p(iobase+USR) & USR_TSRE)) {
-		IRDA_DEBUG(4, __FUNCTION__ 
-			   "(), warning, FIFO not empty yet!\n");
+		IRDA_DEBUG(4, "%s(), warning, FIFO not empty yet!\n", __FUNCTION__);
 
 		fifo_size -= 17;
-		IRDA_DEBUG(4, __FUNCTION__ "%d bytes left in tx fifo\n", 
-			   fifo_size);
+		IRDA_DEBUG(4, "%s(), %d bytes left in tx fifo\n", 
+			__FUNCTION__, fifo_size);
 	}
 
 	/* Fill FIFO with current frame */
@@ -667,8 +666,8 @@
 		outb(buf[actual++], iobase+TBR);
 	}
         
-	IRDA_DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
-		   fifo_size, actual, len);
+	IRDA_DEBUG(4, "%s(), fifo_size %d ; %d sent of %d\n", 
+		__FUNCTION__, fifo_size, actual, len);
 
 	/* Restore bank */
 	outb(set, iobase+SSR);
@@ -688,7 +687,7 @@
 	int iobase;
 	__u8 set;
 
-	IRDA_DEBUG(4, __FUNCTION__ "(%ld)\n", jiffies);
+	IRDA_DEBUG(4, "%s(%ld)\n", __FUNCTION__, jiffies);
 
 	ASSERT(self != NULL, return;);
 
@@ -703,7 +702,7 @@
 	
 	/* Check for underrrun! */
 	if (inb(iobase+AUDR) & AUDR_UNDR) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), Transmit underrun!\n");
+		IRDA_DEBUG(0, "%s(), Transmit underrun!\n", __FUNCTION__);
 		
 		self->stats.tx_errors++;
 		self->stats.tx_fifo_errors++;
@@ -744,7 +743,7 @@
 #endif
 	ASSERT(self != NULL, return -1;);
 
-	IRDA_DEBUG(4, __FUNCTION__ "\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	iobase= self->io.fir_base;
 
@@ -816,7 +815,7 @@
 	__u8 set;
 	__u8 status;
 
-	IRDA_DEBUG(4, __FUNCTION__ "\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	st_fifo = &self->st_fifo;
 
@@ -895,8 +894,7 @@
 						
 			skb = dev_alloc_skb(len+1);
 			if (skb == NULL)  {
-				printk(KERN_INFO __FUNCTION__ 
-				       "(), memory squeeze, dropping frame.\n");
+				printk(KERN_INFO "%s(), memory squeeze, dropping frame.\n", __FUNCTION__);
 				/* Restore set register */
 				outb(set, iobase+SSR);
 
@@ -942,7 +940,7 @@
 	__u8 byte = 0x00;
 	int iobase;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	
@@ -969,7 +967,7 @@
 	__u8 set;
 	int iobase;
 
-	IRDA_DEBUG(4, __FUNCTION__ "(), isr=%#x\n", isr);
+	IRDA_DEBUG(4, "%s(), isr=%#x\n", __FUNCTION__, isr);
 	
 	iobase = self->io.fir_base;
 	/* Transmit FIFO low on data */
@@ -1005,8 +1003,7 @@
 	if (isr & ISR_TXEMP_I) {		
 		/* Check if we need to change the speed? */
 		if (self->new_speed) {
-			IRDA_DEBUG(2, __FUNCTION__ 
-				   "(), Changing speed!\n");
+			IRDA_DEBUG(2, "%s(), Changing speed!\n", __FUNCTION__);
 			w83977af_change_speed(self, self->new_speed);
 			self->new_speed = 0;
 		}
@@ -1188,7 +1185,7 @@
  */
 static int w83977af_net_init(struct net_device *dev)
 {
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s\n", __FUNCTION__);
 
 	/* Set up to be a normal IrDA network device driver */
 	irda_device_setup(dev);
@@ -1212,7 +1209,7 @@
 	char hwname[32];
 	__u8 set;
 	
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s\n", __FUNCTION__);
 	
 	ASSERT(dev != NULL, return -1;);
 	self = (struct w83977af_ir *) dev->priv;
@@ -1277,7 +1274,7 @@
 	int iobase;
 	__u8 set;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s\n", __FUNCTION__);
 
 	ASSERT(dev != NULL, return -1;);
 	
@@ -1334,7 +1331,7 @@
 
 	ASSERT(self != NULL, return -1;);
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 	
 	/* Disable interrupts & save flags */
 	save_flags(flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/lasi_82596.c linux-2.4.20/drivers/net/lasi_82596.c
--- linux-2.4.19/drivers/net/lasi_82596.c	2001-10-17 04:56:29.000000000 +0000
+++ linux-2.4.20/drivers/net/lasi_82596.c	2002-10-29 11:18:33.000000000 +0000
@@ -84,6 +84,7 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/types.h>
 
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -95,8 +96,8 @@
 #include <asm/gsc.h>
 #include <asm/cache.h>
 
-static char version[] __initdata =
-	"82596.c $Revision: 1.20 $\n";
+static char version[] __devinitdata =
+	"82596.c $Revision: 1.29 $\n";
 
 /* DEBUG flags
  */
@@ -120,7 +121,7 @@
 #define DEB_ANY		0xffff
 
 
-#define DEB(x,y)	if (i596_debug & (x)) y
+#define DEB(x,y)	if (i596_debug & (x)) { y; }
 
 
 #define  CHECK_WBACK(addr,len) \
@@ -144,13 +145,13 @@
  */
 
 #ifdef __BIG_ENDIAN
-#define WSWAPrfd(x)  ((struct i596_rfd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPrbd(x)  ((struct i596_rbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPiscp(x) ((struct i596_iscp *)(((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPscb(x)  ((struct i596_scb *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPcmd(x)  ((struct i596_cmd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPtbd(x)  ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPchar(x) ((char *)            (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPrfd(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPrbd(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPiscp(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPscb(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPcmd(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPtbd(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPchar(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
 #define ISCP_BUSY	0x00010000
 #define MACH_IS_APRICOT	0
 #else
@@ -183,18 +184,19 @@
 MODULE_LICENSE("GPL");
 MODULE_PARM(i596_debug, "i");
 MODULE_PARM_DESC(i596_debug, "lasi_82596 debug mask");
+EXPORT_NO_SYMBOLS;
 
 /* Copy frames shorter than rx_copybreak, otherwise pass on up in
  * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
  */
 static int rx_copybreak = 100;
 
+#define MAX_DRIVERS	4	/* max count of drivers */
+
 #define PKT_BUF_SZ	1536
 #define MAX_MC_CNT	64
 
-#define I596_TOTAL_SIZE 17
-
-#define I596_NULL ((void *)0xffffffff)
+#define I596_NULL ((u32)0xffffffff)
 
 #define CMD_EOL		0x8000	/* The last command of the list, stop. */
 #define CMD_SUSP	0x4000	/* Suspend after doing cmd. */
@@ -229,7 +231,7 @@
 struct i596_reg {
 	unsigned short porthi;
 	unsigned short portlo;
-	unsigned long ca;
+	u32            ca;
 };
 
 #define EOF		0x8000
@@ -238,9 +240,9 @@
 struct i596_tbd {
 	unsigned short size;
 	unsigned short pad;
-	struct i596_tbd *next;
-	char *data;
-	long cache_pad[5];		/* Total 32 bytes... */
+	dma_addr_t     next;
+	dma_addr_t     data;
+	u32 cache_pad[5];		/* Total 32 bytes... */
 };
 
 /* The command structure has two 'next' pointers; v_next is the address of
@@ -257,17 +259,21 @@
 	struct i596_cmd *v_next;	/* Address from CPUs viewpoint */
 	unsigned short status;
 	unsigned short command;
-	struct i596_cmd *b_next;	/* Address from i596 viewpoint */
+	dma_addr_t     b_next;	/* Address from i596 viewpoint */
 };
 
 struct tx_cmd {
 	struct i596_cmd cmd;
-	struct i596_tbd *tbd;
+	dma_addr_t     tbd;
 	unsigned short size;
 	unsigned short pad;
 	struct sk_buff *skb;		/* So we can free it after tx */
 	dma_addr_t dma_addr;
-	long cache_pad[1];		/* Total 32 bytes... */
+#ifdef __LP64__
+	u32 cache_pad[6];		/* Total 64 bytes... */
+#else    
+	u32 cache_pad[1];		/* Total 32 bytes... */
+#endif    
 };
 
 struct tdr_cmd {
@@ -295,27 +301,34 @@
 struct i596_rfd {
 	unsigned short stat;
 	unsigned short cmd;
-	struct i596_rfd *b_next;	/* Address from i596 viewpoint */
-	struct i596_rbd *rbd;
+	dma_addr_t     b_next;	/* Address from i596 viewpoint */
+	dma_addr_t     rbd;
 	unsigned short count;
 	unsigned short size;
 	struct i596_rfd *v_next;	/* Address from CPUs viewpoint */
 	struct i596_rfd *v_prev;
-	long cache_pad[2];		/* Total 32 bytes... */
+#ifndef __LP64__    
+	u32 cache_pad[2];		/* Total 32 bytes... */
+#endif    
 };
 
 struct i596_rbd {
+    /* hardware data */
     unsigned short count;
     unsigned short zero1;
-    struct i596_rbd *b_next;
-    unsigned char *b_data;		/* Address from i596 viewpoint */
+    dma_addr_t     b_next;
+    dma_addr_t     b_data;		/* Address from i596 viewpoint */
     unsigned short size;
     unsigned short zero2;
+    /* driver data */
     struct sk_buff *skb;
     struct i596_rbd *v_next;
-    struct i596_rbd *b_addr;		/* This rbd addr from i596 view */
+    dma_addr_t     b_addr;		/* This rbd addr from i596 view */
     unsigned char *v_data;		/* Address from CPUs viewpoint */
 					/* Total 32 bytes... */
+#ifdef __LP64__
+    u32 cache_pad[4];
+#endif    
 };
 
 /* These values as chosen so struct i596_private fits in one page... */
@@ -326,27 +339,27 @@
 struct i596_scb {
 	unsigned short status;
 	unsigned short command;
-	struct i596_cmd *cmd;
-	struct i596_rfd *rfd;
-	unsigned long crc_err;
-	unsigned long align_err;
-	unsigned long resource_err;
-	unsigned long over_err;
-	unsigned long rcvdt_err;
-	unsigned long short_err;
+	dma_addr_t    cmd;
+	dma_addr_t    rfd;
+	u32           crc_err;
+	u32           align_err;
+	u32           resource_err;
+	u32           over_err;
+	u32           rcvdt_err;
+	u32           short_err;
 	unsigned short t_on;
 	unsigned short t_off;
 };
 
 struct i596_iscp {
-	unsigned long stat;
-	struct i596_scb *scb;
+	u32           stat;
+	dma_addr_t    scb;
 };
 
 struct i596_scp {
-	unsigned long sysbus;
-	unsigned long pad;
-	struct i596_iscp *iscp;
+	u32           sysbus;
+	u32            pad;
+	dma_addr_t    iscp;
 };
 
 struct i596_private {
@@ -361,14 +374,14 @@
 	struct i596_rbd rbds[RX_RING_SIZE]	__attribute__((aligned(32)));
 	struct tx_cmd tx_cmds[TX_RING_SIZE]	__attribute__((aligned(32)));
 	struct i596_tbd tbds[TX_RING_SIZE]	__attribute__((aligned(32)));
-	unsigned long stat;
+	u32    stat;
 	int last_restart;
 	struct i596_rfd *rfd_head;
 	struct i596_rbd *rbd_head;
 	struct i596_cmd *cmd_tail;
 	struct i596_cmd *cmd_head;
 	int cmd_backlog;
-	unsigned long last_cmd;
+	u32    last_cmd;
 	struct net_device_stats stats;
 	int next_tx_cmd;
 	int options;
@@ -393,6 +406,8 @@
 	0x00,
 	0x7f /*  *multi IA */ };
 
+static struct pci_dev *fake_pci_dev; /* The fake pci_dev needed for 
+					pci_* functions under ccio. */
 static int dma_consistent = 1;	/* Zero if pci_alloc_consistent() fails */
 
 static int i596_open(struct net_device *dev);
@@ -412,22 +427,28 @@
 
 static inline void CA(struct net_device *dev)
 {
-	gsc_writel(0, (void*)(dev->base_addr + PA_CHANNEL_ATTENTION));
+	gsc_writel(0, dev->base_addr + PA_CHANNEL_ATTENTION);
 }
 
 
-static inline void MPU_PORT(struct net_device *dev, int c, volatile void *x)
+static inline void MPU_PORT(struct net_device *dev, int c, dma_addr_t x)
 {
 	struct i596_private *lp = (struct i596_private *) dev->priv;
 
 	u32 v = (u32) (c) | (u32) (x);
+	u16 a, b;
 
-	if (lp->options & OPT_SWAP_PORT)
-		v = ((u32) (v) << 16) | ((u32) (v) >> 16);
+	if (lp->options & OPT_SWAP_PORT) {
+		a = v >> 16;
+		b = v & 0xffff;
+	} else {
+		a = v & 0xffff;
+		b = v >> 16;
+	}
 
-	gsc_writel(v & 0xffff, (void*)(dev->base_addr + PA_CPU_PORT_L_ACCESS));
+	gsc_writel(a, dev->base_addr + PA_CPU_PORT_L_ACCESS);
 	udelay(1);
-	gsc_writel(v >> 16,    (void*)(dev->base_addr + PA_CPU_PORT_L_ACCESS));
+	gsc_writel(b, dev->base_addr + PA_CPU_PORT_L_ACCESS);
 }
 
 
@@ -439,7 +460,7 @@
 		CHECK_INV(&(lp->iscp), sizeof(struct i596_iscp));
 	}
 	if (!delcnt) {
-		printk("%s: %s, iscp.stat %04lx, didn't clear\n",
+		printk("%s: %s, iscp.stat %04x, didn't clear\n",
 		     dev->name, str, lp->iscp.stat);
 		return -1;
 	}
@@ -472,28 +493,28 @@
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
 
-	printk("lp and scp at %p, .sysbus = %08lx, .iscp = %p\n",
+	printk("lp and scp at %p, .sysbus = %08x, .iscp = %08x\n",
 	       &lp->scp, lp->scp.sysbus, lp->scp.iscp);
-	printk("iscp at %p, iscp.stat = %08lx, .scb = %p\n",
+	printk("iscp at %p, iscp.stat = %08x, .scb = %08x\n",
 	       &lp->iscp, lp->iscp.stat, lp->iscp.scb);
 	printk("scb at %p, scb.status = %04x, .command = %04x,"
-		" .cmd = %p, .rfd = %p\n",
+		" .cmd = %08x, .rfd = %08x\n",
 	       &lp->scb, lp->scb.status, lp->scb.command,
 		lp->scb.cmd, lp->scb.rfd);
-	printk("   errors: crc %lx, align %lx, resource %lx,"
-               " over %lx, rcvdt %lx, short %lx\n",
+	printk("   errors: crc %x, align %x, resource %x,"
+               " over %x, rcvdt %x, short %x\n",
 		lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err,
 		lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err);
 	cmd = lp->cmd_head;
-	while (cmd != I596_NULL) {
-		printk("cmd at %p, .status = %04x, .command = %04x, .b_next = %p\n",
+	while (cmd != NULL) {
+		printk("cmd at %p, .status = %04x, .command = %04x, .b_next = %08x\n",
 		  cmd, cmd->status, cmd->command, cmd->b_next);
 		cmd = cmd->v_next;
 	}
 	rfd = lp->rfd_head;
 	printk("rfd_head = %p\n", rfd);
 	do {
-		printk ("   %p .stat %04x, .cmd %04x, b_next %p, rbd %p,"
+		printk ("   %p .stat %04x, .cmd %04x, b_next %08x, rbd %08x,"
                         " count %04x\n",
 			rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd,
 			rfd->count);
@@ -502,7 +523,7 @@
 	rbd = lp->rbd_head;
 	printk("rbd_head = %p\n", rbd);
 	do {
-		printk("   %p .count %04x, b_next %p, b_data %p, size %04x\n",
+		printk("   %p .count %04x, b_next %08x, b_data %08x, size %04x\n",
 			rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size);
 		rbd = rbd->v_next;
 	} while (rbd != lp->rbd_head);
@@ -523,7 +544,7 @@
 }
 #endif
 
-#define virt_to_dma(lp,v) ((char *)(v)-(char *)(lp)+(char *)((lp)->dma_addr))
+#define virt_to_dma(lp,v) ((lp)->dma_addr + (dma_addr_t)((unsigned long)(v)-(unsigned long)(lp)))
 
 static inline void init_rx_bufs(struct net_device *dev)
 {
@@ -541,7 +562,7 @@
 		if (skb == NULL)
 			panic("82596: alloc_skb() failed");
 		skb_reserve(skb, 2);
-		dma_addr = pci_map_single(NULL, skb->tail,PKT_BUF_SZ,
+		dma_addr = pci_map_single(fake_pci_dev, skb->tail,PKT_BUF_SZ,
 					PCI_DMA_FROMDEVICE);
 		skb->dev = dev;
 		rbd->v_next = rbd+1;
@@ -569,7 +590,7 @@
 	lp->rfd_head = lp->rfds;
 	lp->scb.rfd = WSWAPrfd(virt_to_dma(lp,lp->rfds));
 	rfd = lp->rfds;
-	rfd->rbd = lp->rbd_head;
+	rfd->rbd = WSWAPrbd(virt_to_dma(lp,lp->rbd_head));
 	rfd->v_prev = lp->rfds + rx_ring_size - 1;
 	rfd = lp->rfds + rx_ring_size - 1;
 	rfd->v_next = lp->rfds;
@@ -588,7 +609,9 @@
 	for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
 		if (rbd->skb == NULL)
 			break;
-		pci_unmap_single(NULL,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+		pci_unmap_single(fake_pci_dev,
+				 (dma_addr_t)WSWAPchar(rbd->b_data), 
+				 PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 		dev_kfree_skb(rbd->skb);
 	}
 }
@@ -640,14 +663,15 @@
 	lp->iscp.stat = ISCP_BUSY;
 	lp->cmd_backlog = 0;
 
-	lp->cmd_head = lp->scb.cmd = I596_NULL;
+	lp->cmd_head = NULL;
+        lp->scb.cmd = I596_NULL;
 
 	DEB(DEB_INIT,printk("%s: starting i82596.\n", dev->name));
 
 	CHECK_WBACK(&(lp->scp), sizeof(struct i596_scp));
 	CHECK_WBACK(&(lp->iscp), sizeof(struct i596_iscp));
 
-	MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_dma(lp,&lp->scp));	
+	MPU_PORT(dev, PORT_ALTSCP, virt_to_dma(lp,&lp->scp));	
 
 	CA(dev);
 
@@ -724,7 +748,7 @@
 	CHECK_INV(rfd, sizeof(struct i596_rfd));
 	while ((rfd->stat) & STAT_C) {	/* Loop while complete frames */
 		if (rfd->rbd == I596_NULL)
-			rbd = I596_NULL;
+			rbd = NULL;
 		else if (rfd->rbd == lp->rbd_head->b_addr) {
 			rbd = lp->rbd_head;
 			CHECK_INV(rbd, sizeof(struct i596_rbd));
@@ -732,12 +756,12 @@
 		else {
 			printk("%s: rbd chain broken!\n", dev->name);
 			/* XXX Now what? */
-			rbd = I596_NULL;
+			rbd = NULL;
 		}
-		DEB(DEB_RXFRAME, printk("  rfd %p, rfd.rbd %p, rfd.stat %04x\n",
+		DEB(DEB_RXFRAME, printk("  rfd %p, rfd.rbd %08x, rfd.stat %04x\n",
 			rfd, rfd->rbd, rfd->stat));
 		
-		if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) {
+		if (rbd != NULL && ((rfd->stat) & STAT_OK)) {
 			/* a good frame */
 			int pkt_len = rbd->count & 0x3fff;
 			struct sk_buff *skb = rbd->skb;
@@ -754,7 +778,7 @@
 				struct sk_buff *newskb;
 				dma_addr_t dma_addr;
 
-				pci_unmap_single(NULL,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+				pci_unmap_single(fake_pci_dev,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 				/* Get fresh skbuff to replace filled one. */
 				newskb = dev_alloc_skb(PKT_BUF_SZ + 4);
 				if (newskb == NULL) {
@@ -768,7 +792,7 @@
 				rx_in_place = 1;
 				rbd->skb = newskb;
 				newskb->dev = dev;
-				dma_addr = pci_map_single(NULL, newskb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+				dma_addr = pci_map_single(fake_pci_dev, newskb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 				rbd->v_data = newskb->tail;
 				rbd->b_data = WSWAPchar(dma_addr);
 				CHECK_WBACK_INV(rbd, sizeof(struct i596_rbd));
@@ -785,7 +809,7 @@
 				skb->dev = dev;
 				if (!rx_in_place) {
 					/* 16 byte align the data fields */
-					pci_dma_sync_single(NULL, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+					pci_dma_sync_single(fake_pci_dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 					skb_reserve(skb, 2);
 					memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len);
 				}
@@ -819,7 +843,7 @@
 
 		/* Clear the buffer descriptor count and EOF + F flags */
 
-		if (rbd != I596_NULL && (rbd->count & 0x4000)) {
+		if (rbd != NULL && (rbd->count & 0x4000)) {
 			rbd->count = 0;
 			lp->rbd_head = rbd->v_next;
 			CHECK_WBACK_INV(rbd, sizeof(struct i596_rbd));
@@ -856,7 +880,7 @@
 {
 	struct i596_cmd *ptr;
 
-	while (lp->cmd_head != I596_NULL) {
+	while (lp->cmd_head != NULL) {
 		ptr = lp->cmd_head;
 		lp->cmd_head = ptr->v_next;
 		lp->cmd_backlog--;
@@ -866,19 +890,21 @@
 			{
 				struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
 				struct sk_buff *skb = tx_cmd->skb;
-				pci_unmap_single(NULL, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE);
+				pci_unmap_single(fake_pci_dev, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE);
 
 				dev_kfree_skb(skb);
 
 				lp->stats.tx_errors++;
 				lp->stats.tx_aborted_errors++;
 
-				ptr->v_next = ptr->b_next = I596_NULL;
+				ptr->v_next = NULL;
+				ptr->b_next = I596_NULL;
 				tx_cmd->cmd.command = 0;  /* Mark as free */
 				break;
 			}
 		default:
-			ptr->v_next = ptr->b_next = I596_NULL;
+			ptr->v_next = NULL;
+			ptr->b_next = I596_NULL;
 		}
 		CHECK_WBACK_INV(ptr, sizeof(struct i596_cmd));
 	}
@@ -889,7 +915,7 @@
 }
 
 
-static inline void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr)
+static inline void i596_reset(struct net_device *dev, struct i596_private *lp)
 {
 	unsigned long flags;
 
@@ -921,19 +947,19 @@
 static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
 {
 	struct i596_private *lp = (struct i596_private *) dev->priv;
-	int ioaddr = dev->base_addr;
 	unsigned long flags;
 
 	DEB(DEB_ADDCMD,printk("i596_add_cmd cmd_head %p\n", lp->cmd_head));
 
 	cmd->status = 0;
 	cmd->command |= (CMD_EOL | CMD_INTR);
-	cmd->v_next = cmd->b_next = I596_NULL;
+	cmd->v_next = NULL;
+	cmd->b_next = I596_NULL;
 	CHECK_WBACK(cmd, sizeof(struct i596_cmd));
 
 	spin_lock_irqsave (&lp->lock, flags);
 
-	if (lp->cmd_head != I596_NULL) {
+	if (lp->cmd_head != NULL) {
 		lp->cmd_tail->v_next = cmd;
 		lp->cmd_tail->b_next = WSWAPcmd(virt_to_dma(lp,&cmd->status));
 		CHECK_WBACK(lp->cmd_tail, sizeof(struct i596_cmd));
@@ -958,7 +984,7 @@
 
 		printk("%s: command unit timed out, status resetting.\n", dev->name);
 #if 1
-		i596_reset(dev, lp, ioaddr);
+		i596_reset(dev, lp);
 #endif
 	}
 }
@@ -1011,8 +1037,6 @@
 		goto out_remove_rx_bufs;
 	}
 
-	request_mem_region(dev->base_addr, I596_TOTAL_SIZE, "i82596");
-
 	netif_start_queue(dev);
 
 	return 0;
@@ -1029,7 +1053,6 @@
 static void i596_tx_timeout (struct net_device *dev)
 {
 	struct i596_private *lp = (struct i596_private *) dev->priv;
-	int ioaddr = dev->base_addr;
 
 	/* Transmitter timeout, serious problems. */
 	DEB(DEB_ERRORS,printk("%s: transmit timed out, status resetting.\n",
@@ -1041,7 +1064,7 @@
 	if (lp->last_restart == lp->stats.tx_packets) {
 		DEB(DEB_ERRORS,printk ("Resetting board.\n"));
 		/* Shutdown and restart */
-		i596_reset (dev, lp, ioaddr);
+		i596_reset (dev, lp);
 	} else {
 		/* Issue a channel attention signal */
 		DEB(DEB_ERRORS,printk ("Kicking board.\n"));
@@ -1064,8 +1087,8 @@
 	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 	dev->trans_start = jiffies;
 
-	DEB(DEB_STARTTX,printk("%s: i596_start_xmit(%x,%x) called\n", dev->name,
-				skb->len, (unsigned int)skb->data));
+	DEB(DEB_STARTTX,printk("%s: i596_start_xmit(%x,%p) called\n", dev->name,
+				skb->len, skb->data));
 
 	netif_stop_queue(dev);
 
@@ -1092,7 +1115,7 @@
 		tbd->pad = 0;
 		tbd->size = EOF | length;
 
-		tx_cmd->dma_addr = pci_map_single(NULL, skb->data, skb->len, 
+		tx_cmd->dma_addr = pci_map_single(fake_pci_dev, skb->data, skb->len, 
 				PCI_DMA_TODEVICE);
 		tbd->data = WSWAPchar(tx_cmd->dma_addr);
 
@@ -1126,7 +1149,7 @@
 
 #define LAN_PROM_ADDR	0xF0810000
 
-static int __init i82596_probe(struct net_device *dev, int options)
+static int __devinit i82596_probe(struct net_device *dev)
 {
 	int i;
 	struct i596_private *lp;
@@ -1139,12 +1162,12 @@
 			    sizeof(struct i596_rfd));
 	    return -ENODEV;
 	}
-	if (sizeof(struct i596_rbd) != 32) {
+	if ((sizeof(struct i596_rbd) % 32) != 0) {
 	    printk("82596: sizeof(struct i596_rbd) = %d\n",
 			    sizeof(struct i596_rbd));
 	    return -ENODEV;
 	}
-	if (sizeof(struct tx_cmd) != 32) {
+	if ((sizeof(struct tx_cmd) % 32) != 0) {
 	    printk("82596: sizeof(struct tx_cmd) = %d\n",
 			    sizeof(struct tx_cmd));
 	    return -ENODEV;
@@ -1154,27 +1177,25 @@
 			    sizeof(struct i596_tbd));
 	    return -ENODEV;
 	}
+#ifndef __LP64__
 	if (sizeof(struct i596_private) > 4096) {
 	    printk("82596: sizeof(struct i596_private) = %d\n",
 			    sizeof(struct i596_private));
 	    return -ENODEV;
 	}
-
-	/* FIXME:
-	    Currently this works only, if set-up from lasi.c.
-	    This should be changed to use probing too !
-	*/
+#endif
 
 	if (!dev->base_addr || !dev->irq)
-	    return -ENODEV;
+		return -ENODEV;
 
-	if (pdc_lan_station_id( (char*)&eth_addr, (void*)dev->base_addr)) {
-	    for(i=0;i<6;i++)
-		eth_addr[i] = gsc_readb(LAN_PROM_ADDR+i);
-	    printk("82596.c: MAC of HP700 LAN blindely read from the prom!\n");
+	if (pdc_lan_station_id(eth_addr, dev->base_addr)) {
+		for (i=0; i < 6; i++) {
+			eth_addr[i] = gsc_readb(LAN_PROM_ADDR + i);
+		}
+		printk("82596.c: MAC of HP700 LAN read from EEPROM\n");
 	}
 
-	dev->mem_start = (int)pci_alloc_consistent( NULL, 
+	dev->mem_start = (unsigned long) pci_alloc_consistent(fake_pci_dev, 
 		sizeof(struct i596_private), &dma_addr);
 	if (!dev->mem_start) {
 		printk("%s: Couldn't get consistent shared memory\n", dev->name);
@@ -1210,11 +1231,10 @@
 
 	lp = (struct i596_private *) dev->priv;
 	DEB(DEB_INIT,printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n",
-			dev->name, (unsigned long)lp,
-			sizeof(struct i596_private), (unsigned long)&lp->scb));
-	memset((void *) lp, 0, sizeof(struct i596_private));
+		dev->name, (unsigned long)lp,
+		sizeof(struct i596_private), (unsigned long)&lp->scb));
+	memset(lp, 0, sizeof(struct i596_private));
 
-	lp->options = options;
 	lp->scb.command = 0;
 	lp->scb.cmd = I596_NULL;
 	lp->scb.rfd = I596_NULL;
@@ -1227,18 +1247,6 @@
 }
 
 
-int __init lasi_i82596_probe(struct net_device *dev)
-{
-	return i82596_probe(dev, 0);
-}
-
-
-int __init asp_i82596_probe(struct net_device *dev)
-{
-	return i82596_probe(dev, OPT_SWAP_PORT);
-}
-
-
 static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
@@ -1276,7 +1284,7 @@
 		if ((status & 0x2000))
 			DEB(DEB_INTS,printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700));
 
-		while (lp->cmd_head != I596_NULL) {
+		while (lp->cmd_head != NULL) {
 			CHECK_INV(lp->cmd_head, sizeof(struct i596_cmd));
 			if (!(lp->cmd_head->status & STAT_C))
 				break;
@@ -1309,7 +1317,7 @@
 					if ((ptr->status) & 0x1000)
 						lp->stats.tx_aborted_errors++;
 				}
-				pci_unmap_single(NULL, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE);
+				pci_unmap_single(fake_pci_dev, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE);
 				dev_kfree_skb_irq(skb);
 
 				tx_cmd->cmd.command = 0; /* Mark free */
@@ -1338,7 +1346,8 @@
 				ptr->command = 0;
 				break;
 			}
-			ptr->v_next = ptr->b_next = I596_NULL;
+			ptr->v_next = NULL;
+		        ptr->b_next = I596_NULL;
 			CHECK_WBACK(ptr, sizeof(struct i596_cmd));
 			lp->last_cmd = jiffies;
 		}
@@ -1348,7 +1357,7 @@
 		 * only add to the cmd queue when the CU is stopped.
 		 */
 		ptr = lp->cmd_head;
-		while ((ptr != I596_NULL) && (ptr != lp->cmd_tail)) {
+		while ((ptr != NULL) && (ptr != lp->cmd_tail)) {
 			struct i596_cmd *prev = ptr;
 
 			ptr->command &= 0x1fff;
@@ -1356,7 +1365,7 @@
 			CHECK_WBACK_INV(prev, sizeof(struct i596_cmd));
 		}
 
-		if ((lp->cmd_head != I596_NULL))
+		if ((lp->cmd_head != NULL))
 			ack_cmd |= CUC_START;
 		lp->scb.cmd = WSWAPcmd(virt_to_dma(lp,&lp->cmd_head->status));
 		CHECK_WBACK_INV(&lp->scb, sizeof(struct i596_scb));
@@ -1422,8 +1431,6 @@
 	free_irq(dev->irq, dev);
 	remove_rx_bufs(dev);
 
-	release_mem_region(dev->base_addr, I596_TOTAL_SIZE);
-
 	MOD_DEC_USE_COUNT;
 
 	return 0;
@@ -1503,48 +1510,106 @@
 	}
 }
 
-#ifdef HAVE_DEVLIST
-static unsigned int i596_portlist[] __initdata =
-{0x300, 0};
-struct netdev_entry i596_drv =
-{"lasi_i82596", lasi_i82596_probe, I596_TOTAL_SIZE, i596_portlist};
-#endif
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "lasi_82596 debug mask");
+static int debug = -1;
+
+static int num_drivers;
+static struct net_device *netdevs[MAX_DRIVERS];
 
-#ifdef MODULE
-static char devicename[9] =
-{0,};
-static struct net_device dev_82596 =
+static int __devinit
+lan_init_chip(struct parisc_device *dev)
 {
-	name: devicename,	/* device name inserted by drivers/net/net_init.c */
-	init: lasi_i82596_probe,
+	struct	net_device *netdevice;
+	int	retval;
+
+	if (num_drivers >= MAX_DRIVERS) {
+		/* max count of possible i82596 drivers reached */
+		return -ENODEV;
+	}
+	
+	fake_pci_dev = ccio_get_fake(dev);
+
+	if (!dev->irq) {
+		printk(KERN_ERR __FILE__ ": IRQ not found for i82596 at 0x%lx\n", dev->hpa);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n", dev->hpa, dev->irq);
+
+	netdevice = alloc_etherdev(0);
+	if (!netdevice)
+		return -ENOMEM;
+
+	netdevice->base_addr = dev->hpa;
+	netdevice->irq = dev->irq;
+	netdevice->init = i82596_probe;
+
+	retval = register_netdev(netdevice);
+	if (retval) {
+		printk(KERN_WARNING __FILE__ ": register_netdevice ret'd %d\n", retval);
+		kfree(netdevice);
+		return -ENODEV;
+	};
+	if (dev->id.sversion == 0x72) {
+		((struct i596_private *)netdevice->priv)->options = OPT_SWAP_PORT;
+	}
+
+	netdevs[num_drivers++] = netdevice;
+
+	return retval;
+}
+
+
+static struct parisc_device_id lan_tbl[] = {
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008a },
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00072 },
+	{ 0, }
 };
 
+MODULE_DEVICE_TABLE(parisc, lan_tbl);
 
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "lasi_82596 debug mask");
-static int debug = -1;
+static struct parisc_driver lan_driver = {
+	name:		"Apricot",
+	id_table:	lan_tbl,
+	probe:		lan_init_chip,
+};
 
-int init_module(void)
+static int __devinit lasi_82596_init(void)
 {
 	if (debug >= 0)
 		i596_debug = debug;
-	if (register_netdev(&dev_82596) != 0)
-		return -EIO;
-	return 0;
+	return register_parisc_driver(&lan_driver);
 }
 
-void cleanup_module(void)
+module_init(lasi_82596_init);
+
+static void __exit lasi_82596_exit(void)
 {
-	unregister_netdev(&dev_82596);
-	lp = (struct i596_private *) dev_82596.priv;
+	int i;
 
-	if (dma_consistent)
-		pci_free_consistent( NULL, sizeof( struct i596_private), 
-			dev_82596.mem_start, lp->dma_addr);
-	else
-		free_page ((u32)(dev_82596.mem_start));
+	for (i=0; i<MAX_DRIVERS; i++) {
+		struct i596_private *lp;
+		struct net_device *netdevice;
+		
+		netdevice = netdevs[i];
+		if (!netdevice) 
+			continue;
+		
+		unregister_netdev(netdevice);
+
+		lp = (struct i596_private *) netdevice->priv;
+		if (dma_consistent)
+			pci_free_consistent(fake_pci_dev, 
+					    sizeof(struct i596_private), 
+				(void *)netdevice->mem_start, lp->dma_addr);
+		else
+			free_page(netdevice->mem_start);
+
+		netdevice->priv = NULL;
+	}
 
-	dev_82596.priv = NULL;
+	unregister_parisc_driver(&lan_driver);
 }
 
-#endif				/* MODULE */
+module_exit(lasi_82596_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/mac89x0.c linux-2.4.20/drivers/net/mac89x0.c
--- linux-2.4.19/drivers/net/mac89x0.c	2001-10-17 04:56:29.000000000 +0000
+++ linux-2.4.20/drivers/net/mac89x0.c	2002-10-29 11:18:48.000000000 +0000
@@ -144,28 +144,28 @@
 static int inline
 readreg_io(struct net_device *dev, int portno)
 {
-	writew(swab16(portno), dev->base_addr + ADD_PORT);
-	return swab16(readw(dev->base_addr + DATA_PORT));
+	nubus_writew(swab16(portno), dev->base_addr + ADD_PORT);
+	return swab16(nubus_readw(dev->base_addr + DATA_PORT));
 }
 
 static void inline
 writereg_io(struct net_device *dev, int portno, int value)
 {
-	writew(swab16(portno), dev->base_addr + ADD_PORT);
-	writew(swab16(value), dev->base_addr + DATA_PORT);
+	nubus_writew(swab16(portno), dev->base_addr + ADD_PORT);
+	nubus_writew(swab16(value), dev->base_addr + DATA_PORT);
 }
 
 /* These are for reading/writing registers in shared memory */
 static int inline
 readreg(struct net_device *dev, int portno)
 {
-	return swab16(readw(dev->mem_start + portno));
+	return swab16(nubus_readw(dev->mem_start + portno));
 }
 
 static void inline
 writereg(struct net_device *dev, int portno, int value)
 {
-	writew(swab16(value), dev->mem_start + portno);
+	nubus_writew(swab16(value), dev->mem_start + portno);
 }
 
 /* Probe for the CS8900 card in slot E.  We won't bother looking
@@ -210,8 +210,8 @@
 			return -ENODEV;
 	}
 
-	writew(0, ioaddr + ADD_PORT);
-	sig = readw(ioaddr + DATA_PORT);
+	nubus_writew(0, ioaddr + ADD_PORT);
+	sig = nubus_readw(ioaddr + DATA_PORT);
 	if (sig != swab16(CHIP_EISA_ID_SIG))
 		return -ENODEV;
 
@@ -450,7 +450,7 @@
            course, if you're on a slow machine, and packets are arriving
            faster than you can read them off, you're screwed.  Hasta la
            vista, baby!  */
-	while ((status = swab16(readw(dev->base_addr + ISQ_PORT)))) {
+	while ((status = swab16(nubus_readw(dev->base_addr + ISQ_PORT)))) {
 		if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status);
 		switch(status & ISQ_EVENT_MASK) {
 		case ISQ_RECEIVER_EVENT:
@@ -655,7 +655,7 @@
 
 #endif
 #ifdef MODULE
-	writew(0, dev_cs89x0.base_addr + ADD_PORT);
+	nubus_writew(0, dev_cs89x0.base_addr + ADD_PORT);
 #endif
 #ifdef MODULE
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/macmace.c linux-2.4.20/drivers/net/macmace.c
--- linux-2.4.19/drivers/net/macmace.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/macmace.c	2002-10-29 11:18:37.000000000 +0000
@@ -16,6 +16,7 @@
 
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
@@ -182,7 +183,6 @@
 int mace_probe(struct net_device *unused)
 {
 	int j;
-	static int once;
 	struct mace_data *mp;
 	unsigned char *addr;
 	struct net_device *dev;
@@ -447,7 +447,7 @@
 {
 	struct mace_data *mp = (struct mace_data *) dev->priv;
 	volatile struct mace *mb = mp->mace;
-	int i, j, k, b;
+	int i, j;
 	u32 crc;
 	u8 maccc;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/macsonic.c linux-2.4.20/drivers/net/macsonic.c
--- linux-2.4.19/drivers/net/macsonic.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/macsonic.c	2002-10-29 11:18:33.000000000 +0000
@@ -63,9 +63,21 @@
 
 #include "sonic.h"
 
+#define SONIC_READ(reg) \
+	nubus_readl(base_addr+(reg))
+#define SONIC_WRITE(reg,val) \
+	nubus_writel((val), base_addr+(reg))
+#define sonic_read(dev, reg) \
+	nubus_readl((dev)->base_addr+(reg))
+#define sonic_write(dev, reg, val) \
+	nubus_writel((val), (dev)->base_addr+(reg))
+
+
 static int sonic_debug;
 static int sonic_version_printed;
 
+static int reg_offset;
+
 extern int macsonic_probe(struct net_device* dev);
 extern int mac_onboard_sonic_probe(struct net_device* dev);
 extern int mac_nubus_sonic_probe(struct net_device* dev);
@@ -100,7 +112,7 @@
    resource directories */
 #define DAYNA_SONIC_MAC_ADDR	0xffe004
 
-#define SONIC_READ_PROM(addr) readb(prom_addr+addr)
+#define SONIC_READ_PROM(addr) nubus_readb(prom_addr+addr)
 
 int __init macsonic_probe(struct net_device* dev)
 {
@@ -187,8 +199,6 @@
 	if ((lp->rba = (char *)
 	     kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL | GFP_DMA)) == NULL) {
 		printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name);
-		kfree(lp->sonic_desc);
-		lp->sonic_desc = NULL;
 		return -ENOMEM;
 	}
 
@@ -297,7 +307,6 @@
 {
 	/* Bwahahaha */
 	static int once_is_more_than_enough;
-	struct sonic_local* lp;
 	int i;
 	int dma_bitmode;
 	
@@ -339,7 +348,7 @@
 
 	printk("yes\n");	
 
-	if (dev) 
+	if (dev) {
 		dev = init_etherdev(dev, sizeof(struct sonic_local));
 		if (!dev)
 			return -ENOMEM;
@@ -351,6 +360,7 @@
 		}
 	} else {
 		dev = init_etherdev(NULL, sizeof(struct sonic_local));
+	}
 
 	if (dev == NULL)
 		return -ENOMEM;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/meth.c linux-2.4.20/drivers/net/meth.c
--- linux-2.4.19/drivers/net/meth.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/meth.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,863 @@
+/*
+ * meth.c -- O2 Builtin 10/100 Ethernet driver
+ *
+ * Copyright (C) 2001 Ilya Volynets
+ *
+ *	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.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h> /* printk() */
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/errno.h>  /* error codes */
+#include <linux/types.h>  /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+#include <linux/pci.h>
+
+#include <linux/in.h>
+#include <linux/netdevice.h>   /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h>          /* struct iphdr */
+#include <linux/tcp.h>         /* struct tcphdr */
+#include <linux/skbuff.h>
+#include <linux/mii.h> /*MII definitions */
+
+#include <asm/ip32/crime.h>
+#include <asm/ip32/mace.h>
+#include <asm/ip32/ip32_ints.h>
+
+#include "meth.h"
+
+#include <linux/in6.h>
+#include <asm/checksum.h>
+
+#ifndef MFE_DEBUG
+#define MFE_DEBUG 0
+#endif
+
+#if MFE_DEBUG>=1
+#define DPRINTK(str,args...) printk (KERN_DEBUG "meth(%ld): %s: " str, jiffies, __FUNCTION__ , ## args)
+#define MFE_RX_DEBUG 2
+#else
+#define DPRINTK(str,args...)
+#define MFE_RX_DEBUG 0
+#endif
+
+
+static const char *version="meth.c: Ilya Volynets (ilya@theIlya.com)";
+static const char *meth_str="SGI O2 Fast Ethernet";
+MODULE_AUTHOR("Ilya Volynets");
+MODULE_DESCRIPTION("SGI O2 Builtin Fast Ethernet driver");
+
+/* This is a load-time options */
+/*static int eth = 0;
+MODULE_PARM(eth, "i");*/
+
+#define HAVE_TX_TIMEOUT
+/* The maximum time waited (in jiffies) before assuming a Tx failed. (400ms) */
+#define TX_TIMEOUT (400*HZ/1000)
+
+#ifdef HAVE_TX_TIMEOUT
+static int timeout = TX_TIMEOUT;
+MODULE_PARM(timeout, "i");
+#endif
+
+int meth_eth;
+
+
+/*
+ * This structure is private to each device. It is used to pass
+ * packets in and out, so there is place for a packet
+ */
+
+typedef struct meth_private {
+    struct net_device_stats stats;
+	volatile struct meth_regs *regs;
+	u64 mode; /* in-memory copy of MAC control register */
+	int  phy_addr; /* address of phy, used by mdio_* functions, initialized in mdio_probe*/
+	tx_packet *tx_ring;
+	dma_addr_t tx_ring_dma;
+	int free_space;
+	struct sk_buff *tx_skbs[TX_RING_ENTRIES];
+	dma_addr_t      tx_skb_dmas[TX_RING_ENTRIES];
+	int tx_read,tx_write;
+	int tx_count;
+
+	rx_packet *rx_ring[RX_RING_ENTRIES];
+	dma_addr_t rx_ring_dmas[RX_RING_ENTRIES];
+	int rx_write;
+
+    spinlock_t meth_lock;
+} meth_private;
+
+extern struct net_device meth_devs[];
+void meth_tx_timeout (struct net_device *dev);
+void meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs);
+        
+/* global, initialized in ip32-setup.c */
+char o2meth_eaddr[8]={0,0,0,0,0,0,0,0};
+
+static inline void load_eaddr(struct net_device *dev,
+			      volatile struct meth_regs *regs)
+{
+	int i;
+	DPRINTK("Loading MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+		(int)o2meth_eaddr[0]&0xFF,(int)o2meth_eaddr[1]&0xFF,(int)o2meth_eaddr[2]&0xFF,
+		(int)o2meth_eaddr[3]&0xFF,(int)o2meth_eaddr[4]&0xFF,(int)o2meth_eaddr[5]&0xFF);
+	//memcpy(dev->dev_addr,o2meth_eaddr+2,6);
+	for (i=0; i<6; i++)
+		dev->dev_addr[i]=o2meth_eaddr[i];
+	regs->mac_addr= //dev->dev_addr[0]|(dev->dev_addr[1]<<8)|
+					//dev->dev_addr[2]<<16|(dev->dev_addr[3]<<24)|
+					//dev->dev_addr[4]<<32|(dev->dev_addr[5]<<40);
+	(*(u64*)o2meth_eaddr)>>16;
+	DPRINTK("MAC, finally is %0lx\n",regs->mac_addr);
+}
+
+/*
+ *Waits for BUSY status of mdio bus to clear
+ */
+#define WAIT_FOR_PHY(___regs, ___rval)			\
+	while((___rval=___regs->phy_data)&MDIO_BUSY){	\
+		udelay(25);								\
+	}
+/*read phy register, return value read */
+static int mdio_read(meth_private *priv,int phyreg)
+{
+	volatile meth_regs* regs=priv->regs;
+	volatile u32 rval;
+	WAIT_FOR_PHY(regs,rval)
+	regs->phy_registers=(priv->phy_addr<<5)|(phyreg&0x1f);
+	udelay(25);
+	regs->phy_trans_go=1;
+	udelay(25);
+	WAIT_FOR_PHY(regs,rval)
+	return rval&MDIO_DATA_MASK;
+}
+
+/*write phy register */
+static void mdio_write(meth_private* priv,int pfyreg,int val)
+{
+	volatile meth_regs* regs=priv->regs;
+	int rval;
+///	DPRINTK("Trying to write value %i to reguster %i\n",val, pfyreg);
+	spin_lock_irq(&priv->meth_lock);
+	WAIT_FOR_PHY(regs,rval)
+	regs->phy_registers=(priv->phy_addr<<5)|(pfyreg&0x1f);
+	regs->phy_data=val;
+	udelay(25);
+	WAIT_FOR_PHY(regs,rval)
+	spin_unlock_irq(&priv->meth_lock);
+}
+
+/* Modify phy register using given mask and value */
+static void mdio_update(meth_private* priv,int phyreg, int val, int mask)
+{
+	int rval;
+	DPRINTK("RMW value %i to PHY register %i with mask %i\n",val,phyreg,mask);
+	rval=mdio_read(priv,phyreg);
+	rval=(rval&~mask)|(val&mask);
+	mdio_write(priv,phyreg,rval);
+}
+
+/* handle errata data on MDIO bus */
+//static void mdio_errata(meth_private *priv)
+//{
+	/* Hmmm... what the hell is phyerrata? does it come from sys init parameters in IRIX */
+//}
+static int mdio_probe(meth_private *priv)
+{
+	int i, p2, p3;
+	DPRINTK("Detecting PHY kind\n");
+	/* check if phy is detected already */
+	if(priv->phy_addr>=0&&priv->phy_addr<32)
+		return 0;
+	spin_lock_irq(&priv->meth_lock);
+	for (i=0;i<32;++i){
+		priv->phy_addr=(char)i;
+		p2=mdio_read(priv,2);
+#ifdef MFE_DEBUG
+		p3=mdio_read(priv,3);
+		switch ((p2<<12)|(p3>>4)){
+			case PHY_QS6612X:
+				DPRINTK("PHY is QS6612X\n");
+				break;
+			case PHY_ICS1889:
+				DPRINTK("PHY is ICS1889\n");
+				break;
+			case PHY_ICS1890:
+				DPRINTK("PHY is ICS1890\n");
+				break;
+			case PHY_DP83840:
+				DPRINTK("PHY is DP83840\n");
+				break;
+		}
+#endif
+		if(p2!=0xffff&&p2!=0x0000){
+			DPRINTK("PHY code: %x\n",(p2<<12)|(p3>>4));
+			break;
+		}
+	}
+	spin_unlock_irq(&priv->meth_lock);
+	if(priv->phy_addr<32) {
+		return 0;
+	}
+	DPRINTK("Oopsie! PHY is not known!\n");
+	priv->phy_addr=-1;
+	return -ENODEV;
+}
+
+static void meth_check_link(struct net_device *dev)
+{
+	struct meth_private *priv = (struct meth_private *) dev->priv;
+	int mii_partner = mdio_read(priv, 5);
+	int mii_advertising = mdio_read(priv, 4);
+	int negotiated = mii_advertising & mii_partner;
+	int duplex, speed;
+
+	if (mii_partner == 0xffff)
+		return;
+
+	duplex = ((negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040)?METH_PHY_FDX:0;
+	speed = (negotiated & 0x0380)?METH_100MBIT:0;
+
+	if ((priv->mode & METH_PHY_FDX) ^ duplex)
+	{
+		DPRINTK("Setting %s-duplex\n", duplex ? "full" : "half");
+		if (duplex)
+			priv->mode |= METH_PHY_FDX;
+		else
+			priv->mode &= ~METH_PHY_FDX;
+		priv->regs->mac_ctrl = priv->mode;
+	}
+
+	if ((priv->mode & METH_100MBIT) ^ speed)
+	{
+		DPRINTK("Setting %dMbs mode\n", speed ? 100 : 10);
+		if (duplex)
+			priv->mode |= METH_100MBIT;
+		else
+			priv->mode &= ~METH_100MBIT;
+		priv->regs->mac_ctrl = priv->mode;
+	}
+}
+
+
+static int meth_init_tx_ring(meth_private *priv)
+{
+	/* Init TX ring */
+	DPRINTK("Initializing TX ring\n");
+	priv->tx_ring = (tx_packet *) pci_alloc_consistent(NULL,TX_RING_BUFFER_SIZE,&(priv->tx_ring_dma));
+	if(!priv->tx_ring)
+		return -ENOMEM;
+	memset(priv->tx_ring, 0, TX_RING_BUFFER_SIZE);
+	priv->tx_count = priv->tx_read = priv->tx_write = 0;
+	priv->regs->tx_ring_base = priv->tx_ring_dma;
+	priv->free_space = TX_RING_ENTRIES;
+	/* Now init skb save area */
+	memset(priv->tx_skbs,0,sizeof(priv->tx_skbs));
+	memset(priv->tx_skb_dmas,0,sizeof(priv->tx_skb_dmas));
+	DPRINTK("Done with TX ring init\n");
+	return 0;
+}
+
+static int meth_init_rx_ring(meth_private *priv)
+{
+	int i;
+	DPRINTK("Initializing RX ring\n");
+	for(i=0;i<RX_RING_ENTRIES;i++){
+		DPRINTK("\t1:\t%i\t",i);
+		/*if(!(priv->rx_ring[i]=get_free_page(GFP_KERNEL)))
+			return -ENOMEM;
+		DPRINTK("\t2:\t%i\n",i);*/
+		priv->rx_ring[i]=(rx_packet*)pci_alloc_consistent(NULL,METH_RX_BUFF_SIZE,&(priv->rx_ring_dmas[i]));
+		/* I'll need to re-sync it after each RX */
+		DPRINTK("\t%p\n",priv->rx_ring[i]);
+		priv->regs->rx_fifo=priv->rx_ring_dmas[i];
+	}
+	priv->rx_write = 0;
+	DPRINTK("Done with RX ring\n");
+	return 0;
+}
+static void meth_free_tx_ring(meth_private *priv)
+{
+	int i;
+
+	/* Remove any pending skb */
+	for (i = 0; i < TX_RING_ENTRIES; i++) {
+	  if (priv->tx_skbs[i])
+		dev_kfree_skb(priv->tx_skbs[i]);
+		priv->tx_skbs[i] = NULL;
+	}
+	pci_free_consistent(NULL,
+			    TX_RING_BUFFER_SIZE,
+			    priv->tx_ring,
+			    priv->tx_ring_dma);
+}
+static void meth_free_rx_ring(meth_private *priv)
+{
+	int i;
+
+	for(i=0;i<RX_RING_ENTRIES;i++)
+		pci_free_consistent(NULL,
+				    METH_RX_BUFF_SIZE,
+				    priv->rx_ring[i],
+				    priv->rx_ring_dmas[i]);
+}
+
+int meth_reset(struct net_device *dev)
+{
+	struct meth_private *priv = (struct meth_private *) dev->priv;
+
+	/* Reset card */
+	priv->regs->mac_ctrl = SGI_MAC_RESET;
+	priv->regs->mac_ctrl = 0;
+	udelay(25);
+	DPRINTK("MAC control after reset: %016lx\n", priv->regs->mac_ctrl);
+
+	/* Load ethernet address */
+	load_eaddr(dev, priv->regs);
+	/* Should load some "errata", but later */
+	
+	/* Check for device */
+	if(mdio_probe(priv) < 0) {
+		DPRINTK("Unable to find PHY\n");
+		return -ENODEV;
+	}
+
+	/* Initial mode -- 10|Half-duplex|Accept normal packets */
+	priv->mode=METH_ACCEPT_MCAST|METH_DEFAULT_IPG;
+	if(dev->flags | IFF_PROMISC)
+		priv->mode |= METH_PROMISC;
+	priv->regs->mac_ctrl = priv->mode;
+
+	/* Autonegociate speed and duplex mode */
+	meth_check_link(dev);
+
+	/* Now set dma control, but don't enable DMA, yet */
+	priv->regs->dma_ctrl= (4 << METH_RX_OFFSET_SHIFT) |
+		              (RX_RING_ENTRIES << METH_RX_DEPTH_SHIFT);
+
+	return(0);
+}
+
+/*============End Helper Routines=====================*/
+
+/*
+ * Open and close
+ */
+
+int meth_open(struct net_device *dev)
+{
+	meth_private *priv=dev->priv;
+	volatile meth_regs *regs=priv->regs;
+
+	MOD_INC_USE_COUNT;
+
+	/* Start DMA */
+	regs->dma_ctrl|=
+	        METH_DMA_TX_EN|/*METH_DMA_TX_INT_EN|*/
+		METH_DMA_RX_EN|METH_DMA_RX_INT_EN;
+
+	if(request_irq(dev->irq,meth_interrupt,SA_SHIRQ,meth_str,dev)){
+		printk(KERN_ERR "%s: Can't get irq %d\n", dev->name, dev->irq);
+		return -EAGAIN;
+	}
+	netif_start_queue(dev);
+	DPRINTK("Opened... DMA control=0x%08lx\n", regs->dma_ctrl);
+	return 0;
+}
+
+int meth_release(struct net_device *dev)
+{
+    netif_stop_queue(dev); /* can't transmit any more */
+	/* shut down dma */
+	((meth_private*)(dev->priv))->regs->dma_ctrl&=
+		~(METH_DMA_TX_EN|METH_DMA_TX_INT_EN|
+		METH_DMA_RX_EN|METH_DMA_RX_INT_EN);
+	free_irq(dev->irq, dev);
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+/*
+ * Configuration changes (passed on by ifconfig)
+ */
+int meth_config(struct net_device *dev, struct ifmap *map)
+{
+    if (dev->flags & IFF_UP) /* can't act on a running interface */
+        return -EBUSY;
+
+    /* Don't allow changing the I/O address */
+    if (map->base_addr != dev->base_addr) {
+        printk(KERN_WARNING "meth: Can't change I/O address\n");
+        return -EOPNOTSUPP;
+    }
+
+    /* Allow changing the IRQ */
+    if (map->irq != dev->irq) {
+        printk(KERN_WARNING "meth: Can't change IRQ\n");
+        return -EOPNOTSUPP;
+    }
+	DPRINTK("Configured\n");
+
+    /* ignore other fields */
+    return 0;
+}
+
+/*
+ * Receive a packet: retrieve, encapsulate and pass over to upper levels
+ */
+void meth_rx(struct net_device* dev)
+{
+    struct sk_buff *skb;
+    struct meth_private *priv = (struct meth_private *) dev->priv;
+	rx_packet *rxb;
+	DPRINTK("RX...\n");
+	// TEMP	while((rxb=priv->rx_ring[priv->rx_write])->status.raw&0x8000000000000000){
+	while((rxb=priv->rx_ring[priv->rx_write])->status.raw&0x8000000000000000){
+	        int len=rxb->status.parsed.rx_len - 4; /* omit CRC */
+		DPRINTK("(%i)\n",priv->rx_write);
+		/* length sanity check */
+		if(len < 60 || len > 1518) {
+		  printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x.\n",
+			 dev->name, priv->rx_write, rxb->status.raw);
+		  priv->stats.rx_errors++;
+		  priv->stats.rx_length_errors++;
+		}
+		if(!(rxb->status.raw&METH_RX_STATUS_ERRORS)){
+			skb=alloc_skb(len+2,GFP_ATOMIC);/* Should be atomic -- we are in interrupt */
+			if(!skb){
+				/* Ouch! No memory! Drop packet on the floor */
+				DPRINTK("!!!>>>Ouch! Not enough Memory for RX buffer!\n");
+				priv->stats.rx_dropped++;
+			} else {
+				skb_reserve(skb, 2); /* align IP on 16B boundary */  
+    			memcpy(skb_put(skb, len), rxb->buf, len);
+			    /* Write metadata, and then pass to the receive level */
+			    skb->dev = dev;
+			    skb->protocol = eth_type_trans(skb, dev);
+				//skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
+			   
+				DPRINTK("passing packet\n");
+				DPRINTK("len = %d rxb->status = %x\n",
+					len, rxb->status.raw);
+				netif_rx(skb);
+				dev->last_rx = jiffies;
+				priv->stats.rx_packets++;
+				priv->stats.rx_bytes+=len;
+				DPRINTK("There we go... Whew...\n");
+			}
+		}
+		priv->regs->rx_fifo=priv->rx_ring_dmas[priv->rx_write];
+		rxb->status.raw=0;		
+		priv->rx_write=(priv->rx_write+1)&(RX_RING_ENTRIES-1);
+	}
+}
+
+static int meth_tx_full(struct net_device *dev)
+{
+	struct meth_private *priv = (struct meth_private *) dev->priv;
+
+	return(priv->tx_count >= TX_RING_ENTRIES-1);
+}
+
+void meth_tx_cleanup(struct net_device* dev, int rptr)
+{
+	meth_private *priv=dev->priv;
+	tx_packet* status;
+	struct sk_buff *skb;
+
+	spin_lock(&priv->meth_lock);
+
+	/* Stop DMA */
+	priv->regs->dma_ctrl &= ~(METH_DMA_TX_INT_EN);
+
+	while(priv->tx_read != rptr){
+		skb = priv->tx_skbs[priv->tx_read];
+		status = &priv->tx_ring[priv->tx_read];
+		if(!status->header.res.sent)
+			break;
+		if(status->header.raw & METH_TX_STATUS_DONE) {
+			priv->stats.tx_packets++;
+			priv->stats.tx_bytes += skb->len;
+		}
+		dev_kfree_skb_irq(skb);
+		priv->tx_skbs[priv->tx_read] = NULL;
+		status->header.raw = 0;
+		priv->tx_read = (priv->tx_read+1)&(TX_RING_ENTRIES-1);
+		priv->tx_count --;
+	}
+
+	/* wake up queue if it was stopped */
+	if (netif_queue_stopped(dev) && ! meth_tx_full(dev)) {
+		netif_wake_queue(dev);
+	}
+
+	spin_unlock(priv->meth_lock);
+}
+
+/*
+ * The typical interrupt entry point
+ */
+void meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs)
+{
+	struct meth_private *priv;
+	union {
+		u32	reg; /*Whole status register */
+		struct {
+			u32			:	2,
+				rx_seq	:	5,
+				tx_read	:	9,
+				
+				rx_read	:	8,
+				int_mask:	8;
+		} parsed;
+	} status;
+	/*
+	 * As usual, check the "device" pointer for shared handlers.
+	 * Then assign "struct device *dev"
+	 */
+	struct net_device *dev = (struct net_device *)dev_id;
+	/* ... and check with hw if it's really ours */
+
+	if (!dev /*paranoid*/ ) return;
+
+	/* Lock the device */
+	priv = (struct meth_private *) dev->priv;
+
+	status.reg = priv->regs->int_flags;
+    
+	DPRINTK("Interrupt, status %08x...\n",status.reg);
+	if (status.parsed.int_mask & METH_INT_RX_THRESHOLD) {
+		/* send it to meth_rx for handling */
+		meth_rx(dev);
+	}
+
+	if (status.parsed.int_mask & (METH_INT_TX_EMPTY|METH_INT_TX_PKT)) {
+		/* a transmission is over: free the skb */
+		meth_tx_cleanup(dev, status.parsed.tx_read);
+	}
+	/* check for errors too... */
+	if (status.parsed.int_mask & (METH_INT_TX_LINK_FAIL))
+		printk(KERN_WARNING "meth: link failure\n");
+	if (status.parsed.int_mask & (METH_INT_MEM_ERROR))
+		printk(KERN_WARNING "meth: memory error\n");
+	if (status.parsed.int_mask & (METH_INT_TX_ABORT))
+		printk(KERN_WARNING "meth: aborted\n");
+	DPRINTK("Interrupt handling done...\n");
+	
+	priv->regs->int_flags=status.reg&0xff; /* clear interrupts */
+}
+
+/*
+ * Transmits packets that fit into TX descriptor (are <=120B)
+ */
+static void meth_tx_short_prepare(meth_private* priv, struct sk_buff* skb)
+{
+	tx_packet *desc=&priv->tx_ring[priv->tx_write];
+	int len = (skb->len<ETH_ZLEN)?ETH_ZLEN:skb->len;
+
+	DPRINTK("preparing short packet\n");
+	/* maybe I should set whole thing to 0 first... */
+	memcpy(desc->data.dt+(120-len),skb->data,skb->len);
+	if(skb->len < len)
+		memset(desc->data.dt+120-len+skb->len,0,len-skb->len);
+	desc->header.raw=METH_TX_CMD_INT_EN|(len-1)|((128-len)<<16);
+	DPRINTK("desc=%016lx\n",desc->header.raw);
+}
+#define TX_CATBUF1 BIT(25)
+static void meth_tx_1page_prepare(meth_private* priv, struct sk_buff* skb)
+{
+	tx_packet *desc=&priv->tx_ring[priv->tx_write];
+	void *buffer_data = (void *)(((u64)skb->data + 7ULL) & (~7ULL));
+	int unaligned_len = (int)((u64)buffer_data - (u64)skb->data);
+	int buffer_len = skb->len - unaligned_len;
+	dma_addr_t catbuf;
+
+	DPRINTK("preparing 1 page...\n");
+	DPRINTK("length=%d data=%p\n", skb->len, skb->data);
+	DPRINTK("unaligned_len=%d\n", unaligned_len);
+	DPRINTK("buffer_data=%p buffer_len=%d\n",
+	       buffer_data,
+	       buffer_len);
+
+	desc->header.raw=METH_TX_CMD_INT_EN|TX_CATBUF1|(skb->len-1);
+
+	/* unaligned part */
+	if(unaligned_len){
+		memcpy(desc->data.dt+(120-unaligned_len),
+		       skb->data, unaligned_len);
+		desc->header.raw |= (128-unaligned_len) << 16;
+	}
+
+	/* first page */
+	catbuf = pci_map_single(NULL,
+				buffer_data,
+				buffer_len,
+				PCI_DMA_TODEVICE);
+	DPRINTK("catbuf=%x\n", catbuf);
+	desc->data.cat_buf[0].form.start_addr = catbuf >> 3;
+	desc->data.cat_buf[0].form.len = buffer_len-1;
+	DPRINTK("desc=%016lx\n",desc->header.raw);
+	DPRINTK("cat_buf[0].raw=%016lx\n",desc->data.cat_buf[0].raw);
+}
+#define TX_CATBUF2 BIT(26)
+static void meth_tx_2page_prepare(meth_private* priv, struct sk_buff* skb)
+{
+	tx_packet *desc=&priv->tx_ring[priv->tx_write];
+	void *buffer1_data = (void *)(((u64)skb->data + 7ULL) & (~7ULL));
+	void *buffer2_data = (void *)PAGE_ALIGN((u64)skb->data);
+	int unaligned_len = (int)((u64)buffer1_data - (u64)skb->data);
+	int buffer1_len = (int)((u64)buffer2_data - (u64)buffer1_data);
+	int buffer2_len = skb->len - buffer1_len - unaligned_len;
+	dma_addr_t catbuf1, catbuf2;
+
+	DPRINTK("preparing 2 pages... \n");
+	DPRINTK("length=%d data=%p\n", skb->len, skb->data);
+	DPRINTK("unaligned_len=%d\n", unaligned_len);
+	DPRINTK("buffer1_data=%p buffer1_len=%d\n",
+	       buffer1_data,
+	       buffer1_len);
+	DPRINTK("buffer2_data=%p buffer2_len=%d\n",
+	       buffer2_data,
+	       buffer2_len);
+
+	desc->header.raw=METH_TX_CMD_INT_EN|TX_CATBUF1|TX_CATBUF2|(skb->len-1);
+	/* unaligned part */
+	if(unaligned_len){
+		memcpy(desc->data.dt+(120-unaligned_len),
+		       skb->data, unaligned_len);
+		desc->header.raw |= (128-unaligned_len) << 16;
+	}
+
+	/* first page */
+	catbuf1 = pci_map_single(NULL,
+				 buffer1_data,
+				 buffer1_len,
+				 PCI_DMA_TODEVICE);
+	DPRINTK("catbuf1=%x\n", catbuf1);
+	desc->data.cat_buf[0].form.start_addr = catbuf1 >> 3;
+	desc->data.cat_buf[0].form.len = buffer1_len-1;
+	/* second page */
+	catbuf2 = pci_map_single(NULL,
+				 buffer2_data,
+				 buffer2_len,
+				 PCI_DMA_TODEVICE);
+	DPRINTK("catbuf2=%x\n", catbuf2);
+	desc->data.cat_buf[1].form.start_addr = catbuf2 >> 3;
+	desc->data.cat_buf[1].form.len = buffer2_len-1;
+	DPRINTK("desc=%016lx\n",desc->header.raw);
+	DPRINTK("cat_buf[0].raw=%016lx\n",desc->data.cat_buf[0].raw);
+	DPRINTK("cat_buf[1].raw=%016lx\n",desc->data.cat_buf[1].raw);
+}
+
+
+void meth_add_to_tx_ring(meth_private *priv, struct sk_buff* skb)
+{
+	DPRINTK("Transmitting data...\n");
+	if(skb->len <= 120) {
+		/* Whole packet fits into descriptor */
+		meth_tx_short_prepare(priv,skb);
+	} else if(PAGE_ALIGN((u64)skb->data) !=
+		  PAGE_ALIGN((u64)skb->data+skb->len-1)) {
+		/* Packet crosses page boundary */
+		meth_tx_2page_prepare(priv,skb);
+	} else {
+		/* Packet is in one page */
+		meth_tx_1page_prepare(priv,skb);
+	}
+
+	/* Remember the skb, so we can free it at interrupt time */
+	priv->tx_skbs[priv->tx_write] = skb;
+	priv->tx_write = (priv->tx_write+1) & (TX_RING_ENTRIES-1);
+	priv->regs->tx_info.wptr = priv->tx_write;
+	priv->tx_count ++;
+	/* Enable DMA transfer */
+	priv->regs->dma_ctrl |= METH_DMA_TX_INT_EN;
+}
+
+/*
+ * Transmit a packet (called by the kernel)
+ */
+int meth_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct meth_private *priv = (struct meth_private *) dev->priv;
+
+	spin_lock_irq(&priv->meth_lock);
+
+	meth_add_to_tx_ring(priv, skb);
+	dev->trans_start = jiffies; /* save the timestamp */
+
+	/* If TX ring is full, tell the upper layer to stop sending packets */
+	if (meth_tx_full(dev)) {
+	        DPRINTK("TX full: stopping\n");
+		netif_stop_queue(dev);
+	}
+
+	spin_unlock_irq(&priv->meth_lock);
+
+	return 0;
+}
+
+/*
+ * Deal with a transmit timeout.
+ */
+
+void meth_tx_timeout (struct net_device *dev)
+{
+	struct meth_private *priv = (struct meth_private *) dev->priv;
+	
+	printk(KERN_WARNING "%s: transmit timed out\n", dev->name);
+
+	/* Protect against concurrent rx interrupts */
+	spin_lock_irq(&priv->meth_lock);
+
+	/* Try to reset the adaptor. */
+	meth_reset(dev);
+
+	priv->stats.tx_errors++;
+
+	/* Clear all rings */
+	meth_free_tx_ring(priv);
+	meth_free_rx_ring(priv);
+	meth_init_tx_ring(priv);
+	meth_init_rx_ring(priv);
+
+	/* Restart dma */
+	priv->regs->dma_ctrl|=METH_DMA_TX_EN|METH_DMA_RX_EN|METH_DMA_RX_INT_EN;
+
+	/* Enable interrupt */
+	spin_unlock_irq(&priv->meth_lock);
+
+	dev->trans_start = jiffies;
+	netif_wake_queue(dev);
+
+	return;
+}
+
+/*
+ * Ioctl commands 
+ */
+int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ 
+    DPRINTK("ioctl\n");
+    return 0;
+}
+
+/*
+ * Return statistics to the caller
+ */
+struct net_device_stats *meth_stats(struct net_device *dev)
+{
+    struct meth_private *priv = (struct meth_private *) dev->priv;
+    return &priv->stats;
+}
+
+/*
+ * The init function (sometimes called probe).
+ * It is invoked by register_netdev()
+ */
+int meth_init(struct net_device *dev)
+{
+	meth_private *priv;
+	int ret;
+	/* 
+	 * Then, assign other fields in dev, using ether_setup() and some
+	 * hand assignments
+	 */
+	ether_setup(dev); /* assign some of the fields */
+
+	dev->open            = meth_open;
+	dev->stop            = meth_release;
+	dev->set_config      = meth_config;
+	dev->hard_start_xmit = meth_tx;
+	dev->do_ioctl        = meth_ioctl;
+	dev->get_stats       = meth_stats;
+#ifdef HAVE_TX_TIMEOUT
+	dev->tx_timeout      = meth_tx_timeout;
+	dev->watchdog_timeo  = timeout;
+#endif
+	dev->irq		 = MACE_ETHERNET_IRQ;
+	SET_MODULE_OWNER(dev);
+
+	/*
+	 * Then, allocate the priv field. This encloses the statistics
+	 * and a few private fields.
+	 */
+	priv = kmalloc(sizeof(struct meth_private), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+	dev->priv=priv;
+	memset(priv, 0, sizeof(struct meth_private));
+	spin_lock_init(&((struct meth_private *) dev->priv)->meth_lock);
+	/*
+	 * Make the usual checks: check_region(), probe irq, ...  -ENODEV
+	 * should be returned if no device found.  No resource should be
+	 * grabbed: this is done on open(). 
+	 */
+	priv->regs=(meth_regs*)SGI_MFE;
+	dev->base_addr=SGI_MFE;
+	priv->phy_addr = -1; /* No phy is known yet... */
+
+	/* Initialize the hardware */
+	if((ret=meth_reset(dev)) < 0)
+	        return ret;
+
+	/* Allocate the ring buffers */
+	if((ret=meth_init_tx_ring(priv))<0||(ret=meth_init_rx_ring(priv))<0){
+		meth_free_tx_ring(priv);
+		meth_free_rx_ring(priv);
+		return ret;
+	}
+
+	printk("SGI O2 Fast Ethernet rev. %ld\n", priv->regs->mac_ctrl >> 29);
+
+    return 0;
+}
+
+/*
+ * The devices
+ */
+
+struct net_device meth_devs[1] = {
+    { init: meth_init, }  /* init, nothing more */
+};
+
+/*
+ * Finally, the module stuff
+ */
+
+int meth_init_module(void)
+{
+	int result, device_present = 0;
+
+	strcpy(meth_devs[0].name, "eth%d");
+
+	if ( (result = register_netdev(meth_devs)) )
+		printk("meth: error %i registering device \"%s\"\n",
+		       result, meth_devs->name);
+	else device_present++;
+#ifndef METH_DEBUG
+	EXPORT_NO_SYMBOLS;
+#endif
+	
+	return device_present ? 0 : -ENODEV;
+}
+
+void meth_cleanup(void)
+{
+    kfree(meth_devs->priv);
+    unregister_netdev(meth_devs);
+    return;
+}
+
+module_init(meth_init_module);
+module_exit(meth_cleanup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/meth.h linux-2.4.20/drivers/net/meth.h
--- linux-2.4.19/drivers/net/meth.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/net/meth.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,273 @@
+
+/*
+ * snull.h -- definitions for the network module
+ *
+ * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
+ * Copyright (C) 2001 O'Reilly & Associates
+ *
+ * The source code in this file can be freely used, adapted,
+ * and redistributed in source or binary form, so long as an
+ * acknowledgment appears in derived source files.  The citation
+ * should list that the code comes from the book "Linux Device
+ * Drivers" by Alessandro Rubini and Jonathan Corbet, published
+ * by O'Reilly & Associates.   No warranty is attached;
+ * we cannot take responsibility for errors or fitness for use.
+ */
+
+/* version dependencies have been confined to a separate file */
+
+#define SGI_MFE		(MACE_BASE+MACE_ENET)
+/*		(0xBF280000)*/
+
+/* Tunable parameters */
+#define TX_RING_ENTRIES 64	/* 64-512?*/
+
+#define RX_RING_ENTRIES 16 /* Do not change */
+/* Internal constants */
+#define TX_RING_BUFFER_SIZE	(TX_RING_ENTRIES*sizeof(tx_packet))
+#define RX_BUFFER_SIZE 1546 /* ethenet packet size */
+#define METH_RX_BUFF_SIZE 4096
+#define RX_BUFFER_OFFSET (sizeof(rx_status_vector)+2) /* staus vector + 2 bytes of padding */
+#define RX_BUCKET_SIZE 256
+
+
+
+/* For more detailed explanations of what each field menas,
+   see Nick's great comments to #defines below (or docs, if
+   you are lucky enough toget hold of them :)*/
+
+/* tx status vector is written over tx command header upon
+   dma completion. */
+
+typedef struct tx_status_vector {
+	u64		sent:1; /* always set to 1...*/
+	u64		pad0:34;/* always set to 0 */
+	u64		flags:9;			/*I'm too lazy to specify each one separately at the moment*/
+	u64		col_retry_cnt:4;	/*collision retry count*/
+	u64		len:16;				/*Transmit length in bytes*/
+} tx_status_vector;
+
+/*
+ * Each packet is 128 bytes long.
+ * It consists of header, 0-3 concatination
+ * buffer pointers and up to 120 data bytes.
+ */
+typedef struct tx_packet_hdr {
+	u64		pad1:36; /*should be filled with 0 */
+	u64		cat_ptr3_valid:1,	/*Concatination pointer valid flags*/
+			cat_ptr2_valid:1,
+			cat_ptr1_valid:1;
+	u64		tx_int_flag:1;		/*Generate TX intrrupt when packet has been sent*/
+	u64		term_dma_flag:1;	/*Terminate transmit DMA on transmit abort conditions*/
+	u64		data_offset:7;		/*Starting byte offset in ring data block*/
+	u64		data_len:16;		/*Length of valid data in bytes-1*/
+} tx_packet_hdr;
+typedef union tx_cat_ptr {
+	struct {
+		u64		pad2:16; /* should be 0 */
+		u64		len:16;				/*length of buffer data - 1*/
+		u64		start_addr:29;		/*Physical starting address*/
+		u64		pad1:3; /* should be zero */
+	} form;
+	u64 raw;
+} tx_cat_ptr;
+
+typedef struct tx_packet {
+	union {
+		tx_packet_hdr header;
+		tx_status_vector res;
+		u64 raw;
+	}header;
+	union {
+		tx_cat_ptr cat_buf[3];
+		char dt[120];
+	} data;
+} tx_packet;
+
+typedef union rx_status_vector {
+	struct {
+		u64		pad1:1;/*fill it with ones*/
+		u64		pad2:15;/*fill with 0*/
+		u64		ip_chk_sum:16;
+		u64		seq_num:5;
+		u64		mac_addr_match:1;
+		u64		mcast_addr_match:1;
+		u64		carrier_event_seen:1;
+		u64		bad_packet:1;
+		u64		long_event_seen:1;
+		u64		invalid_preamble:1;
+		u64		broadcast:1;
+		u64		multicast:1;
+		u64		crc_error:1;
+		u64		huh:1;/*???*/
+		u64		rx_code_violation:1;
+		u64		rx_len:16;
+	} parsed;
+	u64 raw;
+} rx_status_vector;
+
+typedef struct rx_packet {
+	rx_status_vector status;
+        u64 pad[3]; /* For whatever reason, there needs to be 4 double-word offset */
+        u16 pad2;
+	char buf[METH_RX_BUFF_SIZE-sizeof(rx_status_vector)-3*sizeof(u64)-sizeof(u16)];/* data */
+} rx_packet;
+
+typedef struct meth_regs {
+	u64		mac_ctrl;		/*0x00,rw,31:0*/
+	u64		int_flags;		/*0x08,rw,30:0*/
+	u64		dma_ctrl;		/*0x10,rw,15:0*/
+	u64		timer;			/*0x18,rw,5:0*/
+	u64		int_tx;			/*0x20,wo,0:0*/
+	u64		int_rx;			/*0x28,wo,9:4*/
+	struct {
+		u32 tx_info_pad;
+		u32 rptr:16,wptr:16;
+	}		tx_info;		/*0x30,rw,31:0*/
+	u64		tx_info_al;		/*0x38,rw,31:0*/
+	struct {
+		u32	rx_buff_pad1;
+		u32	rx_buff_pad2:8,
+			wptr:8,
+			rptr:8,
+			depth:8;
+	}		rx_buff;		/*0x40,ro,23:0*/
+	u64		rx_buff_al1;	/*0x48,ro,23:0*/
+	u64		rx_buff_al2;	/*0x50,ro,23:0*/
+	u64		int_update;		/*0x58,wo,31:0*/
+	u32		phy_data_pad;
+	u32		phy_data;		/*0x60,rw,16:0*/
+	u32		phy_reg_pad;
+	u32		phy_registers;	/*0x68,rw,9:0*/
+	u64		phy_trans_go;	/*0x70,wo,0:0*/
+	u64		backoff_seed;	/*0x78,wo,10:0*/
+	u64		imq_reserved[4];/*0x80,ro,64:0(x4)*/
+	/*===================================*/
+	u64		mac_addr;		/*0xA0,rw,47:0, I think it's MAC address, but I'm not sure*/
+	u64		mcast_addr;		/*0xA8,rw,47:0, This seems like secondary MAC address*/
+	u64		mcast_filter;	/*0xB0,rw,63:0*/
+	u64		tx_ring_base;	/*0xB8,rw,31:13*/
+	/* Following are read-only debugging info register */
+	u64		tx_pkt1_hdr;	/*0xC0,ro,63:0*/
+	u64		tx_pkt1_ptr[3];	/*0xC8,ro,63:0(x3)*/
+	u64		tx_pkt2_hdr;	/*0xE0,ro,63:0*/
+	u64		tx_pkt2_ptr[3];	/*0xE8,ro,63:0(x3)*/
+	/*===================================*/
+	u32		rx_pad;
+	u32		rx_fifo;
+	u64		reserved[31];
+}meth_regs;
+
+	/* Bits in METH_MAC */
+
+#define SGI_MAC_RESET		BIT(0)	/* 0: MAC110 active in run mode, 1: Global reset signal to MAC110 core is active */
+#define METH_PHY_FDX		BIT(1) /* 0: Disable full duplex, 1: Enable full duplex */
+#define METH_PHY_LOOP	BIT(2) /* 0: Normal operation, follows 10/100mbit and M10T/MII select, 1: loops internal MII bus */
+				       /*    selects ignored */
+#define METH_100MBIT		BIT(3) /* 0: 10meg mode, 1: 100meg mode */
+#define METH_PHY_MII		BIT(4) /* 0: MII selected, 1: SIA selected */
+				       /*   Note: when loopback is set this bit becomes collision control.  Setting this bit will */
+				       /*         cause a collision to be reported. */
+
+				       /* Bits 5 and 6 are used to determine the the Destination address filter mode */
+#define METH_ACCEPT_MY 0			/* 00: Accept PHY address only */
+#define METH_ACCEPT_MCAST 0x20	/* 01: Accept physical, broadcast, and multicast filter matches only */
+#define METH_ACCEPT_AMCAST 0x40	/* 10: Accept physical, broadcast, and all multicast packets */
+#define METH_PROMISC 0x60		/* 11: Promiscious mode */
+
+#define METH_PHY_LINK_FAIL	BIT(7) /* 0: Link failure detection disabled, 1: Hardware scans for link failure in PHY */
+
+#define METH_MAC_IPG	0x1ffff00
+
+#define METH_DEFAULT_IPG ((17<<15) | (11<<22) | (21<<8))
+						/* 0x172e5c00 */ /* 23, 23, 23 */ /*0x54A9500 *//*21,21,21*/
+				       /* Bits 8 through 14 are used to determine Inter-Packet Gap between "Back to Back" packets */
+				       /* The gap depends on the clock speed of the link, 80ns per increment for 100baseT, 800ns  */
+				       /* per increment for 10BaseT */
+
+				       /* Bits 15 through 21 are used to determine IPGR1 */
+
+				       /* Bits 22 through 28 are used to determine IPGR2 */
+
+#define METH_REV_SHIFT 29       /* Bits 29 through 31 are used to determine the revision */
+				       /* 000: Inital revision */
+				       /* 001: First revision, Improved TX concatenation */
+
+
+/* DMA control bits */
+#define METH_RX_OFFSET_SHIFT 12 /* Bits 12:14 of DMA control register indicate starting offset of packet data for RX operation */
+#define METH_RX_DEPTH_SHIFT 4 /* Bits 8:4 define RX fifo depth -- when # of RX fifo entries != depth, interrupt is generted */
+
+#define METH_DMA_TX_EN BIT(1) /* enable TX DMA */
+#define METH_DMA_TX_INT_EN BIT(0) /* enable TX Buffer Empty interrupt */
+#define METH_DMA_RX_EN BIT(15) /* Enable RX */
+#define METH_DMA_RX_INT_EN BIT(9) /* Enable interrupt on RX packet */
+
+
+/* RX status bits */
+
+#define METH_RX_ST_RCV_CODE_VIOLATION BIT(16)
+#define METH_RX_ST_DRBL_NBL BIT(17)
+#define METH_RX_ST_CRC_ERR BIT(18)
+#define METH_RX_ST_MCAST_PKT BIT(19)
+#define METH_RX_ST_BCAST_PKT BIT(20)
+#define METH_RX_ST_INV_PREAMBLE_CTX BIT(21)
+#define METH_RX_ST_LONG_EVT_SEEN BIT(22)
+#define METH_RX_ST_BAD_PACKET BIT(23)
+#define METH_RX_ST_CARRIER_EVT_SEEN BIT(24)
+#define METH_RX_ST_MCAST_FILTER_MATCH BIT(25)
+#define METH_RX_ST_PHYS_ADDR_MATCH BIT(26)
+
+#define METH_RX_STATUS_ERRORS \
+	( \
+	METH_RX_ST_RCV_CODE_VIOLATION| \
+	METH_RX_ST_CRC_ERR| \
+	METH_RX_ST_INV_PREAMBLE_CTX| \
+	METH_RX_ST_LONG_EVT_SEEN| \
+	METH_RX_ST_BAD_PACKET| \
+	METH_RX_ST_CARRIER_EVT_SEEN \
+	)
+	/* Bits in METH_INT */
+	/* Write _1_ to corresponding bit to clear */
+#define METH_INT_TX_EMPTY	BIT(0)	/* 0: No interrupt pending, 1: The TX ring buffer is empty */
+#define METH_INT_TX_PKT		BIT(1)	/* 0: No interrupt pending */
+					      	/* 1: A TX message had the INT request bit set, the packet has been sent. */
+#define METH_INT_TX_LINK_FAIL	BIT(2)	/* 0: No interrupt pending, 1: PHY has reported a link failure */
+#define METH_INT_MEM_ERROR	BIT(3)	/* 0: No interrupt pending */
+						/* 1: A memory error occurred durring DMA, DMA stopped, Fatal */
+#define METH_INT_TX_ABORT		BIT(4)	/* 0: No interrupt pending, 1: The TX aborted operation, DMA stopped, FATAL */
+#define METH_INT_RX_THRESHOLD	BIT(5)	/* 0: No interrupt pending, 1: Selected receive threshold condition Valid */
+#define METH_INT_RX_UNDERFLOW	BIT(6)	/* 0: No interrupt pending, 1: FIFO was empty, packet could not be queued */
+#define METH_INT_RX_OVERFLOW		BIT(7)	/* 0: No interrupt pending, 1: DMA FIFO Overflow, DMA stopped, FATAL */
+
+#define METH_INT_RX_RPTR_MASK 0x0001F00		/* Bits 8 through 12 alias of RX read-pointer */
+
+						/* Bits 13 through 15 are always 0. */
+
+#define METH_INT_TX_RPTR_MASK 0x1FF0000	        /* Bits 16 through 24 alias of TX read-pointer */
+
+#define METH_INT_SEQ_MASK    0x2E000000	        /* Bits 25 through 29 are the starting seq number for the message at the */
+						/* top of the queue */
+
+#define METH_ERRORS ( \
+	METH_INT_RX_OVERFLOW|	\
+	METH_INT_RX_UNDERFLOW|	\
+	METH_INT_MEM_ERROR|			\
+	METH_INT_TX_ABORT)
+
+#define METH_INT_MCAST_HASH		BIT(30) /* If RX DMA is enabled the hash select logic output is latched here */
+
+/* TX status bits */
+#define METH_TX_STATUS_DONE BIT(23) /* Packet was transmitted successfully */
+
+/* Tx command header bits */
+#define METH_TX_CMD_INT_EN BIT(24) /* Generate TX interrupt when packet is sent */
+
+/* Phy MDIO interface busy flag */
+#define MDIO_BUSY    BIT(16)
+#define MDIO_DATA_MASK 0xFFFF
+/* PHY defines */
+#define PHY_QS6612X    0x0181441    /* Quality TX */
+#define PHY_ICS1889    0x0015F41    /* ICS FX */
+#define PHY_ICS1890    0x0015F42    /* ICS TX */
+#define PHY_DP83840    0x20005C0    /* National TX */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/mii.c linux-2.4.20/drivers/net/mii.c
--- linux-2.4.19/drivers/net/mii.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/mii.c	2002-10-29 11:18:36.000000000 +0000
@@ -3,7 +3,27 @@
 	mii.c: MII interface library
 
 	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
-	Copyright 2001 Jeff Garzik
+	Copyright 2001,2002 Jeff Garzik
+
+	Various code came from myson803.c and other files by
+	Donald Becker.  Copyright:
+
+		Written 1998-2002 by Donald Becker.
+
+		This software may be used and distributed according
+		to the terms of the GNU General Public License (GPL),
+		incorporated herein by reference.  Drivers based on
+		or derived from this code fall under the GPL and must
+		retain the authorship, copyright and license notice.
+		This file is not a complete program and may only be
+		used when the entire operating system is licensed
+		under the GPL.
+
+		The author may be reached as becker@scyld.com, or C/O
+		Scyld Computing Corporation
+		410 Severn Ave., Suite 210
+		Annapolis MD 21403
+
 
  */
 
@@ -122,7 +142,7 @@
 		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
 		mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
 
-		mii->duplex_lock = 0;
+		mii->force_media = 0;
 	} else {
 		u32 bmcr, tmp;
 
@@ -130,16 +150,16 @@
 		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
 		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
 		if (ecmd->speed == SPEED_100)
-			bmcr |= BMCR_SPEED100;
+			tmp |= BMCR_SPEED100;
 		if (ecmd->duplex == DUPLEX_FULL) {
-			bmcr |= BMCR_FULLDPLX;
+			tmp |= BMCR_FULLDPLX;
 			mii->full_duplex = 1;
 		} else
 			mii->full_duplex = 0;
 		if (bmcr != tmp)
-			mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
+			mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
 
-		mii->duplex_lock = 1;
+		mii->force_media = 1;
 	}
 	return 0;
 }
@@ -170,6 +190,155 @@
 	return r;
 }
 
+void mii_check_link (struct mii_if_info *mii)
+{
+	int cur_link = mii_link_ok(mii);
+	int prev_link = netif_carrier_ok(mii->dev);
+
+	if (cur_link && !prev_link)
+		netif_carrier_on(mii->dev);
+	else if (prev_link && !cur_link)
+		netif_carrier_off(mii->dev);
+}
+
+unsigned int mii_check_media (struct mii_if_info *mii,
+			      unsigned int ok_to_print,
+			      unsigned int init_media)
+{
+	unsigned int old_carrier, new_carrier;
+	int advertise, lpa, media, duplex;
+
+	/* if forced media, go no further */
+	if (mii->force_media)
+		return 0; /* duplex did not change */
+
+	/* check current and old link status */
+	old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
+	new_carrier = (unsigned int) mii_link_ok(mii);
+
+	/* if carrier state did not change, this is a "bounce",
+	 * just exit as everything is already set correctly
+	 */
+	if ((!init_media) && (old_carrier == new_carrier))
+		return 0; /* duplex did not change */
+
+	/* no carrier, nothing much to do */
+	if (!new_carrier) {
+		netif_carrier_off(mii->dev);
+		if (ok_to_print)
+			printk(KERN_INFO "%s: link down\n", mii->dev->name);
+		return 0; /* duplex did not change */
+	}
+
+	/*
+	 * we have carrier, see who's on the other end
+	 */
+	netif_carrier_on(mii->dev);
+
+	/* get MII advertise and LPA values */
+	if ((!init_media) && (mii->advertising))
+		advertise = mii->advertising;
+	else {
+		advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
+		mii->advertising = advertise;
+	}
+	lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
+
+	/* figure out media and duplex from advertise and LPA values */
+	media = mii_nway_result(lpa & advertise);
+	duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+
+	if (ok_to_print)
+		printk(KERN_INFO "%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n",
+		       mii->dev->name,
+		       media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ?
+		       		"100" : "10",
+		       duplex ? "full" : "half",
+		       lpa);
+
+	if ((init_media) || (mii->full_duplex != duplex)) {
+		mii->full_duplex = duplex;
+		return 1; /* duplex changed */
+	}
+
+	return 0; /* duplex did not change */
+}
+
+int generic_mii_ioctl(struct mii_if_info *mii_if,
+		      struct mii_ioctl_data *mii_data, int cmd,
+		      unsigned int *duplex_chg_out)
+{
+	int rc = 0;
+	unsigned int duplex_changed = 0;
+
+	if (duplex_chg_out)
+		*duplex_chg_out = 0;
+
+	mii_data->phy_id &= mii_if->phy_id_mask;
+	mii_data->reg_num &= mii_if->reg_num_mask;
+
+	switch(cmd) {
+	case SIOCDEVPRIVATE:	/* binary compat, remove in 2.5 */
+	case SIOCGMIIPHY:
+		mii_data->phy_id = mii_if->phy_id;
+		/* fall through */
+
+	case SIOCDEVPRIVATE + 1:/* binary compat, remove in 2.5 */
+	case SIOCGMIIREG:
+		mii_data->val_out =
+			mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
+					  mii_data->reg_num);
+		break;
+
+	case SIOCDEVPRIVATE + 2:/* binary compat, remove in 2.5 */
+	case SIOCSMIIREG: {
+		u16 val = mii_data->val_in;
+
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if (mii_data->phy_id == mii_if->phy_id) {
+			switch(mii_data->reg_num) {
+			case MII_BMCR: {
+				unsigned int new_duplex = 0;
+				if (val & (BMCR_RESET|BMCR_ANENABLE))
+					mii_if->force_media = 0;
+				else
+					mii_if->force_media = 1;
+				if (mii_if->force_media &&
+				    (val & BMCR_FULLDPLX))
+					new_duplex = 1;
+				if (mii_if->full_duplex != new_duplex) {
+					duplex_changed = 1;
+					mii_if->full_duplex = new_duplex;
+				}
+				break;
+			}
+			case MII_ADVERTISE:
+				mii_if->advertising = val;
+				break;
+			default:
+				/* do nothing */
+				break;
+			}
+		}
+
+		mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
+				   mii_data->reg_num, val);
+		break;
+	}
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
+		*duplex_chg_out = 1;
+
+	return rc;
+}
+
 MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
 MODULE_DESCRIPTION ("MII hardware support library");
 MODULE_LICENSE("GPL");
@@ -178,3 +347,7 @@
 EXPORT_SYMBOL(mii_nway_restart);
 EXPORT_SYMBOL(mii_ethtool_gset);
 EXPORT_SYMBOL(mii_ethtool_sset);
+EXPORT_SYMBOL(mii_check_link);
+EXPORT_SYMBOL(mii_check_media);
+EXPORT_SYMBOL(generic_mii_ioctl);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/natsemi.c linux-2.4.20/drivers/net/natsemi.c
--- linux-2.4.19/drivers/net/natsemi.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/natsemi.c	2002-10-29 11:18:32.000000000 +0000
@@ -1,7 +1,8 @@
 /* natsemi.c: A Linux PCI Ethernet driver for the NatSemi DP8381x series. */
 /*
 	Written/copyright 1999-2001 by Donald Becker.
-	Portions copyright (c) 2001 Sun Microsystems (thockin@sun.com)
+	Portions copyright (c) 2001,2002 Sun Microsystems (thockin@sun.com)
+	Portions copyright 2001,2002 Manfred Spraul (manfred@colorfullife.com)
 
 	This software may be used and distributed according to the terms of
 	the GNU General Public License (GPL), incorporated herein by reference.
@@ -86,7 +87,7 @@
 		* use long for ee_addr (various)
 		* print pointers properly (DaveM)
 		* include asm/irq.h (?)
-	
+
 	version 1.0.11:
 		* check and reset if PHY errors appear (Adrian Sun)
 		* WoL cleanup (Tim Hockin)
@@ -100,18 +101,42 @@
 		* ETHTOOL_* further support (Tim Hockin)
 
 	version 1.0.13:
-		* ETHTOOL_GEEPROM support (Tim Hockin)
+		* ETHTOOL_[G]EEPROM support (Tim Hockin)
+
+	version 1.0.13:
+		* crc cleanup (Matt Domsch <Matt_Domsch@dell.com>)
 
 	version 1.0.14:
 		* Cleanup some messages and autoneg in ethtool (Tim Hockin)
 
-	version 1.0.13:
-		* crc cleanup (Matt Domsch <Matt_Domsch@dell.com>)
+	version 1.0.15:
+		* Get rid of cable_magic flag
+		* use new (National provided) solution for cable magic issue
+
+	version 1.0.16:
+		* call netdev_rx() for RxErrors (Manfred Spraul)
+		* formatting and cleanups
+		* change options and full_duplex arrays to be zero
+		  initialized
+		* enable only the WoL and PHY interrupts in wol mode
+
+	version 1.0.17:
+		* only do cable_magic on 83815 and early 83816 (Tim Hockin)
+		* create a function for rx refill (Manfred Spraul)
+		* combine drain_ring and init_ring (Manfred Spraul)
+		* oom handling (Manfred Spraul)
+		* hands_off instead of playing with netif_device_{de,a}ttach
+		  (Manfred Spraul)
+		* be sure to write the MAC back to the chip (Manfred Spraul)
+		* lengthen EEPROM timeout, and always warn about timeouts
+		  (Manfred Spraul)
+		* comments update (Manfred)
+		* do the right thing on a phy-reset (Manfred and Tim)
 
 	TODO:
 	* big endian support with CFG:BEM instead of cpu_to_le32
 	* support for an external PHY
-	* flow control
+	* NAPI
 */
 
 #if !defined(__OPTIMIZE__)
@@ -146,23 +171,11 @@
 #include <asm/uaccess.h>
 
 #define DRV_NAME	"natsemi"
-#define DRV_VERSION	"1.07+LK1.0.14"
-#define DRV_RELDATE	"Nov 27, 2001"
+#define DRV_VERSION	"1.07+LK1.0.17"
+#define DRV_RELDATE	"Sep 27, 2002"
 
 /* Updated to recommendations in pci-skeleton v2.03. */
 
-/* Automatically extracted configuration info:
-probe-func: natsemi_probe
-config-in: tristate 'National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI
-
-c-help-name: National Semiconductor DP8381x series PCI Ethernet support
-c-help-symbol: CONFIG_NATSEMI
-c-help: This driver is for the National Semiconductor DP8381x series,
-c-help: including the 8381[56] chips.
-c-help: More specific information and updates are available from 
-c-help: http://www.scyld.com/network/natsemi.html
-*/
-
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
@@ -171,7 +184,7 @@
 				 NETIF_MSG_WOL		| \
 				 NETIF_MSG_RX_ERR	| \
 				 NETIF_MSG_TX_ERR)
-static int debug = NATSEMI_DEF_MSG;
+static int debug = -1;
 
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 20;
@@ -191,8 +204,8 @@
    The media type is usually passed in 'options[]'.
 */
 #define MAX_UNITS 8		/* More are supported, limit only on options */
-static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int options[MAX_UNITS];
+static int full_duplex[MAX_UNITS];
 
 /* Operational parameters that are set at compile time. */
 
@@ -203,7 +216,7 @@
    There are no ill effects from too-large receive rings. */
 #define TX_RING_SIZE	16
 #define TX_QUEUE_LEN	10 /* Limit ring entries actually used, min 4. */
-#define RX_RING_SIZE	64
+#define RX_RING_SIZE	32
 
 /* Operational parameters that usually are not changed. */
 /* Time in jiffies before concluding the transmitter is hung. */
@@ -224,9 +237,11 @@
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
-KERN_INFO DRV_NAME ".c:v1.07 1/9/2001  Written by Donald Becker <becker@scyld.com>\n"
-KERN_INFO "  http://www.scyld.com/network/natsemi.html\n"
-KERN_INFO "  (unofficial 2.4.x kernel port, version " DRV_VERSION ", " DRV_RELDATE "  Jeff Garzik, Tjeerd Mulder)\n";
+  KERN_INFO DRV_NAME " dp8381x driver, version "
+      DRV_VERSION ", " DRV_RELDATE "\n"
+  KERN_INFO "  originally by Donald Becker <becker@scyld.com>\n"
+  KERN_INFO "  http://www.scyld.com/network/natsemi.html\n"
+  KERN_INFO "  2.4.x kernel port by Jeff Garzik, Tjeerd Mulder\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("National Semiconductor DP8381x series PCI Ethernet driver");
@@ -238,11 +253,14 @@
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM_DESC(max_interrupt_work, "DP8381x maximum events handled per interrupt");
+MODULE_PARM_DESC(max_interrupt_work, 
+	"DP8381x maximum events handled per interrupt");
 MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)");
-MODULE_PARM_DESC(debug, "DP8381x debug bitmask");
-MODULE_PARM_DESC(rx_copybreak, "DP8381x copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(options, "DP8381x: Bits 0-3: media type, bit 17: full duplex");
+MODULE_PARM_DESC(debug, "DP8381x default debug level");
+MODULE_PARM_DESC(rx_copybreak, 
+	"DP8381x copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(options, 
+	"DP8381x: Bits 0-3: media type, bit 17: full duplex");
 MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)");
 
 /*
@@ -256,7 +274,7 @@
 II. Board-specific settings
 
 This driver requires the PCI interrupt line to be valid.
-It honors the EEPROM-set values. 
+It honors the EEPROM-set values.
 
 III. Driver operation
 
@@ -266,7 +284,7 @@
 formed into rings by a branch from the final descriptor to the beginning of
 the list.  The ring sizes are set at compile time by RX/TX_RING_SIZE.
 The NatSemi design uses a 'next descriptor' pointer that the driver forms
-into a list. 
+into a list.
 
 IIIb/c. Transmit/Receive Structure
 
@@ -295,20 +313,19 @@
 
 IIId. Synchronization
 
-The driver runs as two independent, single-threaded flows of control.  One
-is the send-packet routine, which enforces single-threaded use by the
-dev->tbusy flag.  The other thread is the interrupt handler, which is single
-threaded by the hardware and interrupt handling software.
-
-The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-the 'lp->tx_full' flag.
-
-The interrupt handler has exclusive control over the Rx ring and records stats
-from the Tx ring.  After reaping the stats, it marks the Tx queue entry as
-empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
-clears both the tx_full and tbusy flags.
+Most operations are synchronized on the np->lock irq spinlock, except the
+performance critical codepaths:
+
+The rx process only runs in the interrupt handler. Access from outside
+the interrupt handler is only permitted after disable_irq().
+
+The rx process usually runs under the dev->xmit_lock. If np->intr_tx_reap
+is set, then access is permitted under spin_lock_irq(&np->lock).
+
+Thus configuration functions that want to access everything must call
+	disable_irq(dev->irq);
+	spin_lock_bh(dev->xmit_lock);
+	spin_lock_irq(&np->lock);
 
 IV. Notes
 
@@ -326,7 +343,7 @@
 None characterised.
 */
 
-
+
 
 enum pcistuff {
 	PCI_USES_IO = 0x01,
@@ -367,6 +384,7 @@
 	IntrStatus		= 0x10,
 	IntrMask		= 0x14,
 	IntrEnable		= 0x18,
+	IntrHoldoff		= 0x16, /* DP83816 only */
 	TxRingPtr		= 0x20,
 	TxConfig		= 0x24,
 	RxRingPtr		= 0x30,
@@ -402,14 +420,12 @@
 	SDCFG			= 0xF8
 };
 /* the values for the 'magic' registers above (PGSEL=1) */
-#ifdef CONFIG_NATSEMI_CABLE_MAGIC
-#define PMDCSR_VAL	0x1898
-#else
-#define PMDCSR_VAL	0x189C
-#endif
+#define PMDCSR_VAL	0x189c	/* enable preferred adaptation circuitry */
 #define TSTDAT_VAL	0x0
 #define DSPCFG_VAL	0x5040
-#define SDCFG_VAL	0x008c
+#define SDCFG_VAL	0x008c	/* set voltage thresholds for Signal Detect */
+#define DSPCFG_LOCK	0x20	/* coefficient lock bit in DSPCFG */
+#define TSTDAT_FIXED	0xe8	/* magic number for bad coefficients */
 
 /* misc PCI space registers */
 enum pci_register_offsets {
@@ -477,11 +493,11 @@
 
 /*
  * Default Interrupts:
- * Rx OK, Rx Packet Error, Rx Overrun, 
- * Tx OK, Tx Packet Error, Tx Underrun, 
+ * Rx OK, Rx Packet Error, Rx Overrun,
+ * Tx OK, Tx Packet Error, Tx Underrun,
  * MIB Service, Phy Interrupt, High Bits,
  * Rx Status FIFO overrun,
- * Received Target Abort, Received Master Abort, 
+ * Received Target Abort, Received Master Abort,
  * Signalled System Error, Received Parity Error
  */
 #define DEFAULT_INTR 0x00f1cd65
@@ -578,8 +594,11 @@
 	PhyAddrMask		= 0xf,
 };
 
-#define SRR_REV_C	0x0302
-#define SRR_REV_D	0x0403
+/* values we might find in the silicon revision register */
+#define SRR_DP83815_C	0x0302
+#define SRR_DP83815_D	0x0403
+#define SRR_DP83816_A4	0x0504
+#define SRR_DP83816_A5	0x0505
 
 /* The Rx and Tx buffer descriptors. */
 /* Note that using only 32 bit fields simplifies conversion to big-endian
@@ -594,14 +613,14 @@
 /* Bits in network_desc.status */
 enum desc_status_bits {
 	DescOwn=0x80000000, DescMore=0x40000000, DescIntr=0x20000000,
-	DescNoCRC=0x10000000, DescPktOK=0x08000000, 
+	DescNoCRC=0x10000000, DescPktOK=0x08000000,
 	DescSizeMask=0xfff,
 
-	DescTxAbort=0x04000000, DescTxFIFO=0x02000000, 
+	DescTxAbort=0x04000000, DescTxFIFO=0x02000000,
 	DescTxCarrier=0x01000000, DescTxDefer=0x00800000,
 	DescTxExcDefer=0x00400000, DescTxOOWCol=0x00200000,
 	DescTxExcColl=0x00100000, DescTxCollCount=0x000f0000,
-	
+
 	DescRxAbort=0x04000000, DescRxOver=0x02000000,
 	DescRxDest=0x01800000, DescRxLong=0x00400000,
 	DescRxRunt=0x00200000, DescRxInvalid=0x00100000,
@@ -610,37 +629,45 @@
 };
 
 struct netdev_private {
-	/* Descriptor rings first for alignment. */
+	/* Descriptor rings first for alignment */
 	dma_addr_t ring_dma;
-	struct netdev_desc* rx_ring;
-	struct netdev_desc* tx_ring;
-	/* The addresses of receive-in-place skbuffs. */
-	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+	struct netdev_desc *rx_ring;
+	struct netdev_desc *tx_ring;
+	/* The addresses of receive-in-place skbuffs */
+	struct sk_buff *rx_skbuff[RX_RING_SIZE];
 	dma_addr_t rx_dma[RX_RING_SIZE];
-	/* The saved address of a sent-in-place packet/buffer, for later free(). */
-	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+	/* address of a sent-in-place packet/buffer, for later free() */
+	struct sk_buff *tx_skbuff[TX_RING_SIZE];
 	dma_addr_t tx_dma[TX_RING_SIZE];
 	struct net_device_stats stats;
-	struct timer_list timer;	/* Media monitoring timer. */
-	/* Frequently used values: keep some adjacent for cache effect. */
+	/* Media monitoring timer */
+	struct timer_list timer;
+	/* Frequently used values: keep some adjacent for cache effect */
 	struct pci_dev *pci_dev;
 	struct netdev_desc *rx_head_desc;
-	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
+	/* Producer/consumer ring indices */
+	unsigned int cur_rx, dirty_rx;
 	unsigned int cur_tx, dirty_tx;
-	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
-	/* These values are keep track of the transceiver/media in use. */
+	/* Based on MTU+slack. */
+	unsigned int rx_buf_sz;
+	int oom;
+	/* Do not touch the nic registers */
+	int hands_off;
+	/* These values are keep track of the transceiver/media in use */
 	unsigned int full_duplex;
-	/* Rx filter. */
+	/* Rx filter */
 	u32 cur_rx_mode;
 	u32 rx_filter[16];
-	/* FIFO and PCI burst thresholds. */
+	/* FIFO and PCI burst thresholds */
 	u32 tx_config, rx_config;
 	/* original contents of ClkRun register */
 	u32 SavedClkRun;
 	/* silicon revision */
 	u32 srr;
-	/* MII transceiver section. */
-	u16 advertising; /* NWay media advertisement */
+	/* expected DSPCFG value */
+	u16 dspcfg;
+	/* MII transceiver section */
+	u16 advertising;
 	unsigned int iosize;
 	spinlock_t lock;
 	u32 msg_enable;
@@ -653,13 +680,19 @@
 static void natsemi_reload_eeprom(struct net_device *dev);
 static void natsemi_stop_rxtx(struct net_device *dev);
 static int netdev_open(struct net_device *dev);
+static void do_cable_magic(struct net_device *dev);
+static void undo_cable_magic(struct net_device *dev);
 static void check_link(struct net_device *dev);
 static void netdev_timer(unsigned long data);
+static void dump_ring(struct net_device *dev);
 static void tx_timeout(struct net_device *dev);
 static int alloc_ring(struct net_device *dev);
+static void refill_rx(struct net_device *dev);
 static void init_ring(struct net_device *dev);
+static void drain_tx(struct net_device *dev);
 static void drain_ring(struct net_device *dev);
 static void free_ring(struct net_device *dev);
+static void reinit_ring(struct net_device *dev);
 static void init_registers(struct net_device *dev);
 static int start_tx(struct sk_buff *skb, struct net_device *dev);
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
@@ -682,9 +715,9 @@
 static int netdev_get_regs(struct net_device *dev, u8 *buf);
 static int netdev_get_eeprom(struct net_device *dev, u8 *buf);
 
-
+
 static int __devinit natsemi_probe1 (struct pci_dev *pdev,
-				     const struct pci_device_id *ent)
+	const struct pci_device_id *ent)
 {
 	struct net_device *dev;
 	struct netdev_private *np;
@@ -763,7 +796,8 @@
 	pci_set_drvdata(pdev, dev);
 	np->iosize = iosize;
 	spin_lock_init(&np->lock);
-	np->msg_enable = debug;
+	np->msg_enable = (debug >= 0) ? (1<<debug)-1 : NATSEMI_DEF_MSG;
+	np->hands_off = 0;
 
 	/* Reset the chip to erase previous misconfiguration. */
 	natsemi_reload_eeprom(dev);
@@ -774,15 +808,15 @@
 		option = dev->mem_start;
 
 	/* The lower four bits are the media type. */
-	if (option > 0) {
+	if (option) {
 		if (option & 0x200)
 			np->full_duplex = 1;
 		if (option & 15)
-			printk(KERN_INFO 
+			printk(KERN_INFO
 				"%s: ignoring user supplied media type %d",
 				dev->name, option & 15);
 	}
-	if (find_cnt < MAX_UNITS  &&  full_duplex[find_cnt] > 0)
+	if (find_cnt < MAX_UNITS  &&  full_duplex[find_cnt])
 		np->full_duplex = 1;
 
 	/* The chip-specific entries in the device structure. */
@@ -810,27 +844,28 @@
 
 	if (netif_msg_drv(np)) {
 		printk(KERN_INFO "%s: %s at %#08lx, ",
-			   dev->name, natsemi_pci_info[chip_idx].name, ioaddr);
+			dev->name, natsemi_pci_info[chip_idx].name, ioaddr);
 		for (i = 0; i < ETH_ALEN-1; i++)
 				printk("%02x:", dev->dev_addr[i]);
 		printk("%02x, IRQ %d.\n", dev->dev_addr[i], irq);
 	}
 
 	np->advertising = mdio_read(dev, 1, MII_ADVERTISE);
-	if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000 
+	if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000
 	 && netif_msg_probe(np)) {
 		u32 chip_config = readl(ioaddr + ChipConfig);
 		printk(KERN_INFO "%s: Transceiver default autonegotiation %s "
-			   "10%s %s duplex.\n",
-			   dev->name,
-			   chip_config & CfgAnegEnable ? "enabled, advertise" : "disabled, force",
-			   chip_config & CfgAneg100 ? "0" : "",
-			   chip_config & CfgAnegFull ? "full" : "half");
+			"10%s %s duplex.\n",
+			dev->name,
+			chip_config & CfgAnegEnable ?
+			  "enabled, advertise" : "disabled, force",
+			chip_config & CfgAneg100 ? "0" : "",
+			chip_config & CfgAnegFull ? "full" : "half");
 	}
 	if (netif_msg_probe(np))
-		printk(KERN_INFO 
+		printk(KERN_INFO
 			"%s: Transceiver status %#04x advertising %#04x.\n",
-			dev->name, mdio_read(dev, 1, MII_BMSR), 
+			dev->name, mdio_read(dev, 1, MII_BMSR),
 			np->advertising);
 
 	/* save the silicon revision for later querying */
@@ -843,7 +878,7 @@
 	return 0;
 }
 
-
+
 /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.
    The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses. */
 
@@ -897,9 +932,9 @@
 	return retval;
 }
 
-/*  MII transceiver control section.
-	The 83815 series has an internal transceiver, and we present the
-	management registers as if they were MII connected. */
+/* MII transceiver control section.
+ * The 83815 series has an internal transceiver, and we present the
+ * management registers as if they were MII connected. */
 
 static int mdio_read(struct net_device *dev, int phy_id, int reg)
 {
@@ -937,11 +972,11 @@
 	u16 sopass[3];
 	struct netdev_private *np = dev->priv;
 
-	/* 
+	/*
 	 * Resetting the chip causes some registers to be lost.
 	 * Natsemi suggests NOT reloading the EEPROM while live, so instead
 	 * we save the state that would have been loaded from EEPROM
-	 * on a normal power-up (see the spec EEPROM map).  This assumes 
+	 * on a normal power-up (see the spec EEPROM map).  This assumes
 	 * whoever calls this will follow up with init_registers() eventually.
 	 */
 
@@ -969,12 +1004,12 @@
 			break;
 		udelay(5);
 	}
-	if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) {
-		printk(KERN_INFO "%s: reset did not complete in %d usec.\n",
-		   dev->name, i*5);
+	if (i==NATSEMI_HW_TIMEOUT) {
+		printk(KERN_WARNING "%s: reset did not complete in %d usec.\n",
+			dev->name, i*5);
 	} else if (netif_msg_hw(np)) {
 		printk(KERN_DEBUG "%s: reset completed in %d usec.\n",
-		   dev->name, i*5);
+			dev->name, i*5);
 	}
 
 	/* restore CFG */
@@ -985,7 +1020,7 @@
 	writel(wcsr, dev->base_addr + WOLCmd);
 	/* read RFCR */
 	rfcr |= readl(dev->base_addr + RxFilterAddr) & ~RFCR_RESET_SAVE;
-	/* restore PMATCH */ 
+	/* restore PMATCH */
 	for (i = 0; i < 3; i++) {
 		writel(i*2, dev->base_addr + RxFilterAddr);
 		writew(pmatch[i], dev->base_addr + RxFilterData);
@@ -996,7 +1031,6 @@
 	}
 	/* restore RFCR */
 	writel(rfcr, dev->base_addr + RxFilterAddr);
-	
 }
 
 static void natsemi_reload_eeprom(struct net_device *dev)
@@ -1006,16 +1040,16 @@
 
 	writel(EepromReload, dev->base_addr + PCIBusCfg);
 	for (i=0;i<NATSEMI_HW_TIMEOUT;i++) {
+		udelay(50);
 		if (!(readl(dev->base_addr + PCIBusCfg) & EepromReload))
 			break;
-		udelay(5);
 	}
-	if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) {
-		printk(KERN_INFO "%s: EEPROM did not reload in %d usec.\n",
-		   dev->name, i*5);
+	if (i==NATSEMI_HW_TIMEOUT) {
+		printk(KERN_WARNING "%s: EEPROM did not reload in %d usec.\n",
+			dev->name, i*50);
 	} else if (netif_msg_hw(np)) {
 		printk(KERN_DEBUG "%s: EEPROM reloaded in %d usec.\n",
-		   dev->name, i*5);
+			dev->name, i*50);
 	}
 }
 
@@ -1031,12 +1065,12 @@
 			break;
 		udelay(5);
 	}
-	if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) {
-		printk(KERN_INFO "%s: Tx/Rx process did not stop in %d usec.\n",
-				dev->name, i*5);
+	if (i==NATSEMI_HW_TIMEOUT) {
+		printk(KERN_WARNING "%s: Tx/Rx process did not stop in %d usec.\n",
+			dev->name, i*5);
 	} else if (netif_msg_hw(np)) {
 		printk(KERN_DEBUG "%s: Tx/Rx process stopped in %d usec.\n",
-				dev->name, i*5);
+			dev->name, i*5);
 	}
 }
 
@@ -1054,7 +1088,7 @@
 
 	if (netif_msg_ifup(np))
 		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
-			   dev->name, dev->irq);
+			dev->name, dev->irq);
 	i = alloc_ring(dev);
 	if (i < 0) {
 		free_irq(dev->irq, dev);
@@ -1063,13 +1097,21 @@
 	init_ring(dev);
 	spin_lock_irq(&np->lock);
 	init_registers(dev);
+	/* now set the MAC address according to dev->dev_addr */
+	for (i = 0; i < 3; i++) {
+		u16 mac = (dev->dev_addr[2*i+1]<<8) + dev->dev_addr[2*i];
+
+		writel(i*2, ioaddr + RxFilterAddr);
+		writew(mac, ioaddr + RxFilterData);
+	}
+	writel(np->cur_rx_mode, ioaddr + RxFilterAddr);
 	spin_unlock_irq(&np->lock);
 
 	netif_start_queue(dev);
 
 	if (netif_msg_ifup(np))
 		printk(KERN_DEBUG "%s: Done netdev_open(), status: %#08x.\n",
-			   dev->name, (int)readl(ioaddr + ChipCmd));
+			dev->name, (int)readl(ioaddr + ChipCmd));
 
 	/* Set the timer to check for link beat. */
 	init_timer(&np->timer);
@@ -1081,6 +1123,62 @@
 	return 0;
 }
 
+static void do_cable_magic(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+
+	if (np->srr >= SRR_DP83816_A5)
+		return;
+
+	/*
+	 * 100 MBit links with short cables can trip an issue with the chip.
+	 * The problem manifests as lots of CRC errors and/or flickering
+	 * activity LED while idle.  This process is based on instructions
+	 * from engineers at National.
+	 */
+	if (readl(dev->base_addr + ChipConfig) & CfgSpeed100) {
+		u16 data;
+
+		writew(1, dev->base_addr + PGSEL);
+		/*
+		 * coefficient visibility should already be enabled via
+		 * DSPCFG | 0x1000
+		 */
+		data = readw(dev->base_addr + TSTDAT) & 0xff;
+		/*
+		 * the value must be negative, and within certain values
+		 * (these values all come from National)
+		 */
+		if (!(data & 0x80) || ((data >= 0xd8) && (data <= 0xff))) {
+			struct netdev_private *np = dev->priv;
+
+			/* the bug has been triggered - fix the coefficient */
+			writew(TSTDAT_FIXED, dev->base_addr + TSTDAT);
+			/* lock the value */
+			data = readw(dev->base_addr + DSPCFG);
+			np->dspcfg = data | DSPCFG_LOCK;
+			writew(np->dspcfg, dev->base_addr + DSPCFG);
+		}
+		writew(0, dev->base_addr + PGSEL);
+	}
+}
+
+static void undo_cable_magic(struct net_device *dev)
+{
+	u16 data;
+	struct netdev_private *np = dev->priv;
+
+	if (np->srr >= SRR_DP83816_A5)
+		return;
+
+	writew(1, dev->base_addr + PGSEL);
+	/* make sure the lock bit is clear */
+	data = readw(dev->base_addr + DSPCFG);
+	np->dspcfg = data & ~DSPCFG_LOCK;
+	writew(np->dspcfg, dev->base_addr + DSPCFG);
+	writew(0, dev->base_addr + PGSEL);
+}
+
 static void check_link(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
@@ -1091,9 +1189,10 @@
 	if (!(chipcfg & CfgLink)) {
 		if (netif_carrier_ok(dev)) {
 			if (netif_msg_link(np))
-				printk(KERN_NOTICE "%s: link down.\n", 
+				printk(KERN_NOTICE "%s: link down.\n",
 					dev->name);
 			netif_carrier_off(dev);
+			undo_cable_magic(dev);
 		}
 		return;
 	}
@@ -1101,6 +1200,7 @@
 		if (netif_msg_link(np))
 			printk(KERN_NOTICE "%s: link up.\n", dev->name);
 		netif_carrier_on(dev);
+		do_cable_magic(dev);
 	}
 
 	duplex = np->full_duplex || (chipcfg & CfgFullDuplex ? 1 : 0);
@@ -1108,7 +1208,7 @@
 	/* if duplex is set then bit 28 must be set, too */
 	if (duplex ^ !!(np->rx_config & RxAcceptTx)) {
 		if (netif_msg_link(np))
-			printk(KERN_INFO 
+			printk(KERN_INFO
 				"%s: Setting %s-duplex based on negotiated "
 				"link capability.\n", dev->name,
 				duplex ? "full" : "half");
@@ -1136,16 +1236,16 @@
 		udelay(10);
 	}
 	if (i==NATSEMI_HW_TIMEOUT && netif_msg_link(np)) {
-		printk(KERN_INFO 
+		printk(KERN_INFO
 			"%s: autonegotiation did not complete in %d usec.\n",
 			dev->name, i*10);
 	}
 
 	/* On page 78 of the spec, they recommend some settings for "optimum
 	   performance" to be done in sequence.  These settings optimize some
-	   of the 100Mbit autodetection circuitry.  They say we only want to 
-	   do this for rev C of the chip, but engineers at NSC (Bradley 
-	   Kennedy) recommends always setting them.  If you don't, you get 
+	   of the 100Mbit autodetection circuitry.  They say we only want to
+	   do this for rev C of the chip, but engineers at NSC (Bradley
+	   Kennedy) recommends always setting them.  If you don't, you get
 	   errors on some autonegotiations that make the device unusable.
 	*/
 	writew(1, ioaddr + PGSEL);
@@ -1154,6 +1254,7 @@
 	writew(DSPCFG_VAL, ioaddr + DSPCFG);
 	writew(SDCFG_VAL, ioaddr + SDCFG);
 	writew(0, ioaddr + PGSEL);
+	np->dspcfg = DSPCFG_VAL;
 
 	/* Enable PHY Specific event based interrupts.  Link state change
 	   and Auto-Negotiation Completion are among the affected.
@@ -1166,14 +1267,14 @@
 	readl(ioaddr + IntrStatus);
 
 	writel(np->ring_dma, ioaddr + RxRingPtr);
-	writel(np->ring_dma + RX_RING_SIZE * sizeof(struct netdev_desc), 
+	writel(np->ring_dma + RX_RING_SIZE * sizeof(struct netdev_desc),
 		ioaddr + TxRingPtr);
 
 	/* Initialize other registers.
 	 * Configure the PCI bus bursts and FIFO thresholds.
 	 * Configure for standard, in-spec Ethernet.
 	 * Start with half-duplex. check_link will update
-	 * to the correct settings. 
+	 * to the correct settings.
 	 */
 
 	/* DRTH: 2: start tx if 64 bytes are in the fifo
@@ -1195,13 +1296,13 @@
 	/* Disable PME:
 	 * The PME bit is initialized from the EEPROM contents.
 	 * PCI cards probably have PME disabled, but motherboard
-	 * implementations may have PME set to enable WakeOnLan. 
+	 * implementations may have PME set to enable WakeOnLan.
 	 * With PME set the chip will scan incoming packets but
 	 * nothing will be written to memory. */
 	np->SavedClkRun = readl(ioaddr + ClkRun);
 	writel(np->SavedClkRun & ~PMEEnable, ioaddr + ClkRun);
 	if (np->SavedClkRun & PMEStatus && netif_msg_wol(np)) {
-		printk(KERN_NOTICE "%s: Wake-up event %#08x\n", 
+		printk(KERN_NOTICE "%s: Wake-up event %#08x\n",
 			dev->name, readl(ioaddr + WOLCmd));
 	}
 
@@ -1216,12 +1317,17 @@
 	writel(StatsClear, ioaddr + StatsCtrl); /* Clear Stats */
 }
 
-/* 
- * The frequency on this has been increased because of a nasty little problem.
- * It seems that a reference set for this chip went out with incorrect info,
- * and there exist boards that aren't quite right.  An unexpected voltage drop
- * can cause the PHY to get itself in a weird state (basically reset..).
- * NOTE: this only seems to affect revC chips.
+/*
+ * netdev_timer:
+ * Purpose:
+ * 1) check for link changes. Usually they are handled by the MII interrupt
+ *    but it doesn't hurt to check twice.
+ * 2) check for sudden death of the NIC:
+ *    It seems that a reference set for this chip went out with incorrect info,
+ *    and there exist boards that aren't quite right.  An unexpected voltage
+ *    drop can cause the PHY to get itself in a weird state (basically reset).
+ *    NOTE: this only seems to affect revC chips.
+ * 3) check of death of the RX path due to OOM
  */
 static void netdev_timer(unsigned long data)
 {
@@ -1232,37 +1338,54 @@
 	u16 dspcfg;
 
 	if (netif_msg_timer(np)) {
-		/* DO NOT read the IntrStatus register, 
+		/* DO NOT read the IntrStatus register,
 		 * a read clears any pending interrupts.
 		 */
 		printk(KERN_DEBUG "%s: Media selection timer tick.\n",
-			   dev->name);
+			dev->name);
 	}
 
+	spin_lock_irq(&np->lock);
+
 	/* check for a nasty random phy-reset - use dspcfg as a flag */
 	writew(1, ioaddr+PGSEL);
 	dspcfg = readw(ioaddr+DSPCFG);
 	writew(0, ioaddr+PGSEL);
-	if (dspcfg != DSPCFG_VAL) {
+	if (dspcfg != np->dspcfg) {
 		if (!netif_queue_stopped(dev)) {
+			spin_unlock_irq(&np->lock);
 			if (netif_msg_hw(np))
 				printk(KERN_NOTICE "%s: possible phy reset: "
 					"re-initializing\n", dev->name);
 			disable_irq(dev->irq);
 			spin_lock_irq(&np->lock);
+			natsemi_stop_rxtx(dev);
+			dump_ring(dev);
+			reinit_ring(dev);
 			init_registers(dev);
 			spin_unlock_irq(&np->lock);
 			enable_irq(dev->irq);
 		} else {
 			/* hurry back */
 			next_tick = HZ;
+			spin_unlock_irq(&np->lock);
 		}
 	} else {
 		/* init_registers() calls check_link() for the above case */
-		spin_lock_irq(&np->lock);
 		check_link(dev);
 		spin_unlock_irq(&np->lock);
 	}
+	if (np->oom) {
+		disable_irq(dev->irq);
+		np->oom = 0;
+		refill_rx(dev);
+		enable_irq(dev->irq);
+		if (!np->oom) {
+			writel(RxOn, dev->base_addr + ChipCmd);
+		} else {
+			next_tick = 1;
+		}
+	}
 	mod_timer(&np->timer, jiffies + next_tick);
 }
 
@@ -1275,16 +1398,16 @@
 		printk(KERN_DEBUG "  Tx ring at %p:\n", np->tx_ring);
 		for (i = 0; i < TX_RING_SIZE; i++) {
 			printk(KERN_DEBUG " #%d desc. %#08x %#08x %#08x.\n",
-				   i, np->tx_ring[i].next_desc,
-				   np->tx_ring[i].cmd_status, 
-				   np->tx_ring[i].addr);
+				i, np->tx_ring[i].next_desc,
+				np->tx_ring[i].cmd_status,
+				np->tx_ring[i].addr);
 		}
 		printk(KERN_DEBUG "  Rx ring %p:\n", np->rx_ring);
 		for (i = 0; i < RX_RING_SIZE; i++) {
 			printk(KERN_DEBUG " #%d desc. %#08x %#08x %#08x.\n",
-				   i, np->rx_ring[i].next_desc,
-				   np->rx_ring[i].cmd_status, 
-				   np->rx_ring[i].addr);
+				i, np->rx_ring[i].next_desc,
+				np->rx_ring[i].cmd_status,
+				np->rx_ring[i].addr);
 		}
 	}
 }
@@ -1296,22 +1419,21 @@
 
 	disable_irq(dev->irq);
 	spin_lock_irq(&np->lock);
-	if (netif_device_present(dev)) {
+	if (!np->hands_off) {
 		if (netif_msg_tx_err(np))
-			printk(KERN_WARNING 
+			printk(KERN_WARNING
 				"%s: Transmit timed out, status %#08x,"
-				" resetting...\n", 
+				" resetting...\n",
 				dev->name, readl(ioaddr + IntrStatus));
 		dump_ring(dev);
 
 		natsemi_reset(dev);
-		drain_ring(dev);
-		init_ring(dev);
+		reinit_ring(dev);
 		init_registers(dev);
 	} else {
-		printk(KERN_WARNING 
-			"%s: tx_timeout while in suspended state?\n",
-		   	dev->name);
+		printk(KERN_WARNING
+			"%s: tx_timeout while in hands_off state?\n",
+			dev->name);
 	}
 	spin_unlock_irq(&np->lock);
 	enable_irq(dev->irq);
@@ -1325,24 +1447,62 @@
 {
 	struct netdev_private *np = dev->priv;
 	np->rx_ring = pci_alloc_consistent(np->pci_dev,
-				sizeof(struct netdev_desc) * (RX_RING_SIZE+TX_RING_SIZE),
-				&np->ring_dma);
+		sizeof(struct netdev_desc) * (RX_RING_SIZE+TX_RING_SIZE),
+		&np->ring_dma);
 	if (!np->rx_ring)
 		return -ENOMEM;
 	np->tx_ring = &np->rx_ring[RX_RING_SIZE];
 	return 0;
 }
 
+static void refill_rx(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+
+	/* Refill the Rx ring buffers. */
+	for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
+		struct sk_buff *skb;
+		int entry = np->dirty_rx % RX_RING_SIZE;
+		if (np->rx_skbuff[entry] == NULL) {
+			skb = dev_alloc_skb(np->rx_buf_sz);
+			np->rx_skbuff[entry] = skb;
+			if (skb == NULL)
+				break; /* Better luck next round. */
+			skb->dev = dev; /* Mark as being used by this device. */
+			np->rx_dma[entry] = pci_map_single(np->pci_dev,
+				skb->data, skb->len, PCI_DMA_FROMDEVICE);
+			np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]);
+		}
+		np->rx_ring[entry].cmd_status = cpu_to_le32(np->rx_buf_sz);
+	}
+	if (np->cur_rx - np->dirty_rx == RX_RING_SIZE) {
+		if (netif_msg_rx_err(np))
+			printk(KERN_WARNING "%s: going OOM.\n", dev->name);
+		np->oom = 1;
+	}
+}
+
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void init_ring(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
 	int i;
 
-	np->cur_rx = np->cur_tx = 0;
-	np->dirty_rx = np->dirty_tx = 0;
+	/* 1) TX ring */
+	np->dirty_tx = np->cur_tx = 0;
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		np->tx_skbuff[i] = NULL;
+		np->tx_ring[i].next_desc = cpu_to_le32(np->ring_dma
+			+sizeof(struct netdev_desc)
+			*((i+1)%TX_RING_SIZE+RX_RING_SIZE));
+		np->tx_ring[i].cmd_status = 0;
+	}
 
+	/* 2) RX ring */
+	np->dirty_rx = 0;
+	np->cur_rx = RX_RING_SIZE;
 	np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
+	np->oom = 0;
 	np->rx_head_desc = &np->rx_ring[0];
 
 	/* Please be carefull before changing this loop - at least gcc-2.95.1
@@ -1356,29 +1516,25 @@
 		np->rx_ring[i].cmd_status = cpu_to_le32(DescOwn);
 		np->rx_skbuff[i] = NULL;
 	}
+	refill_rx(dev);
+	dump_ring(dev);
+}
 
-	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
-		np->rx_skbuff[i] = skb;
-		if (skb == NULL)
-			break;
-		skb->dev = dev;			/* Mark as being used by this device. */
-		np->rx_dma[i] = pci_map_single(np->pci_dev,
-						skb->data, skb->len, PCI_DMA_FROMDEVICE);
-		np->rx_ring[i].addr = cpu_to_le32(np->rx_dma[i]);
-		np->rx_ring[i].cmd_status = cpu_to_le32(np->rx_buf_sz);
-	}
-	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+static void drain_tx(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	int i;
 
 	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (np->tx_skbuff[i]) {
+			pci_unmap_single(np->pci_dev,
+				np->rx_dma[i], np->rx_skbuff[i]->len,
+				PCI_DMA_TODEVICE);
+			dev_kfree_skb(np->tx_skbuff[i]);
+			np->stats.tx_dropped++;
+		}
 		np->tx_skbuff[i] = NULL;
-		np->tx_ring[i].next_desc = cpu_to_le32(np->ring_dma
-					+sizeof(struct netdev_desc)
-					 *((i+1)%TX_RING_SIZE+RX_RING_SIZE));
-		np->tx_ring[i].cmd_status = 0;
 	}
-	dump_ring(dev);
 }
 
 static void drain_ring(struct net_device *dev)
@@ -1392,31 +1548,43 @@
 		np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
 		if (np->rx_skbuff[i]) {
 			pci_unmap_single(np->pci_dev,
-						np->rx_dma[i],
-						np->rx_skbuff[i]->len,
-						PCI_DMA_FROMDEVICE);
+				np->rx_dma[i], np->rx_skbuff[i]->len,
+				PCI_DMA_FROMDEVICE);
 			dev_kfree_skb(np->rx_skbuff[i]);
 		}
 		np->rx_skbuff[i] = NULL;
 	}
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		if (np->tx_skbuff[i]) {
-			pci_unmap_single(np->pci_dev,
-						np->rx_dma[i],
-						np->rx_skbuff[i]->len,
-						PCI_DMA_TODEVICE);
-			dev_kfree_skb(np->tx_skbuff[i]);
-		}
-		np->tx_skbuff[i] = NULL;
-	}
+	drain_tx(dev);
 }
 
 static void free_ring(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
 	pci_free_consistent(np->pci_dev,
-				sizeof(struct netdev_desc) * (RX_RING_SIZE+TX_RING_SIZE),
-				np->rx_ring, np->ring_dma);
+		sizeof(struct netdev_desc) * (RX_RING_SIZE+TX_RING_SIZE),
+		np->rx_ring, np->ring_dma);
+}
+
+static void reinit_ring(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	int i;
+
+	/* drain TX ring */
+	drain_tx(dev);
+	np->dirty_tx = np->cur_tx = 0;
+	for (i=0;i<TX_RING_SIZE;i++)
+		np->tx_ring[i].cmd_status = 0;
+
+	/* RX Ring */
+	np->dirty_rx = 0;
+	np->cur_rx = RX_RING_SIZE;
+	np->rx_head_desc = &np->rx_ring[0];
+	/* Initialize all Rx descriptors. */
+	for (i = 0; i < RX_RING_SIZE; i++)
+		np->rx_ring[i].cmd_status = cpu_to_le32(DescOwn);
+
+	refill_rx(dev);
 }
 
 static int start_tx(struct sk_buff *skb, struct net_device *dev)
@@ -1437,10 +1605,10 @@
 	np->tx_ring[entry].addr = cpu_to_le32(np->tx_dma[entry]);
 
 	spin_lock_irq(&np->lock);
-	
-	if (netif_device_present(dev)) {
+
+	if (!np->hands_off) {
 		np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len);
-		/* StrongARM: Explicitly cache flush np->tx_ring and 
+		/* StrongARM: Explicitly cache flush np->tx_ring and
 		 * skb->data,skb->len. */
 		wmb();
 		np->cur_tx++;
@@ -1461,7 +1629,7 @@
 
 	if (netif_msg_tx_queued(np)) {
 		printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
-			   dev->name, np->cur_tx, entry);
+			dev->name, np->cur_tx, entry);
 	}
 	return 0;
 }
@@ -1475,7 +1643,7 @@
 		if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn))
 			break;
 		if (netif_msg_tx_done(np))
-			printk(KERN_DEBUG 
+			printk(KERN_DEBUG
 				"%s: tx frame #%d finished, status %#08x.\n",
 					dev->name, np->dirty_tx,
 					le32_to_cpu(np->tx_ring[entry].cmd_status));
@@ -1483,14 +1651,15 @@
 			np->stats.tx_packets++;
 			np->stats.tx_bytes += np->tx_skbuff[entry]->len;
 		} else { /* Various Tx errors */
-			int tx_status = le32_to_cpu(np->tx_ring[entry].cmd_status);
-			if (tx_status & (DescTxAbort|DescTxExcColl)) 
+			int tx_status =
+				le32_to_cpu(np->tx_ring[entry].cmd_status);
+			if (tx_status & (DescTxAbort|DescTxExcColl))
 				np->stats.tx_aborted_errors++;
-			if (tx_status & DescTxFIFO) 
+			if (tx_status & DescTxFIFO)
 				np->stats.tx_fifo_errors++;
-			if (tx_status & DescTxCarrier) 
+			if (tx_status & DescTxCarrier)
 				np->stats.tx_carrier_errors++;
-			if (tx_status & DescTxOOWCol) 
+			if (tx_status & DescTxOOWCol)
 				np->stats.tx_window_errors++;
 			np->stats.tx_errors++;
 		}
@@ -1517,23 +1686,29 @@
 	long ioaddr = dev->base_addr;
 	int boguscnt = max_interrupt_work;
 
-	if (!netif_device_present(dev))
+	if (np->hands_off)
 		return;
 	do {
 		/* Reading automatically acknowledges all int sources. */
 		u32 intr_status = readl(ioaddr + IntrStatus);
 
 		if (netif_msg_intr(np))
-			printk(KERN_DEBUG "%s: Interrupt, status %#08x.\n",
-				   dev->name, intr_status);
+			printk(KERN_DEBUG
+				"%s: Interrupt, status %#08x, mask %#08x.\n",
+				dev->name, intr_status,
+				readl(ioaddr + IntrMask));
 
 		if (intr_status == 0)
 			break;
 
-		if (intr_status & (IntrRxDone | IntrRxIntr))
+		if (intr_status &
+		   (IntrRxDone | IntrRxIntr | RxStatusFIFOOver |
+		    IntrRxErr | IntrRxOverrun)) {
 			netdev_rx(dev);
+		}
 
-		if (intr_status & (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr) ) {
+		if (intr_status &
+		   (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) {
 			spin_lock(&np->lock);
 			netdev_tx_done(dev);
 			spin_unlock(&np->lock);
@@ -1544,16 +1719,17 @@
 			netdev_error(dev, intr_status);
 
 		if (--boguscnt < 0) {
-			printk(KERN_WARNING "%s: Too much work at interrupt, "
-				   "status=%#08x.\n",
-				   dev->name, intr_status);
+			if (netif_msg_intr(np))
+				printk(KERN_WARNING
+					"%s: Too much work at interrupt, "
+					"status=%#08x.\n",
+					dev->name, intr_status);
 			break;
 		}
 	} while (1);
 
 	if (netif_msg_intr(np))
-		printk(KERN_DEBUG "%s: exiting interrupt.\n",
-			   dev->name);
+		printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name);
 }
 
 /* This routine is logically part of the interrupt handler, but separated
@@ -1566,9 +1742,9 @@
 	s32 desc_status = le32_to_cpu(np->rx_head_desc->cmd_status);
 
 	/* If the driver owns the next entry it's a new packet. Send it up. */
-	while (desc_status < 0) {        /* e.g. & DescOwn */
+	while (desc_status < 0) { /* e.g. & DescOwn */
 		if (netif_msg_rx_status(np))
-			printk(KERN_DEBUG 
+			printk(KERN_DEBUG
 				"  netdev_rx() entry %d status was %#08x.\n",
 				entry, desc_status);
 		if (--boguscnt < 0)
@@ -1576,54 +1752,56 @@
 		if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){
 			if (desc_status & DescMore) {
 				if (netif_msg_rx_err(np))
-					printk(KERN_WARNING 
+					printk(KERN_WARNING
 						"%s: Oversized(?) Ethernet "
 						"frame spanned multiple "
 						"buffers, entry %#08x "
-						"status %#08x.\n", dev->name, 
+						"status %#08x.\n", dev->name,
 						np->cur_rx, desc_status);
 				np->stats.rx_length_errors++;
 			} else {
 				/* There was an error. */
 				np->stats.rx_errors++;
-				if (desc_status & (DescRxAbort|DescRxOver)) 
+				if (desc_status & (DescRxAbort|DescRxOver))
 					np->stats.rx_over_errors++;
-				if (desc_status & (DescRxLong|DescRxRunt)) 
+				if (desc_status & (DescRxLong|DescRxRunt))
 					np->stats.rx_length_errors++;
-				if (desc_status & (DescRxInvalid|DescRxAlign)) 
+				if (desc_status & (DescRxInvalid|DescRxAlign))
 					np->stats.rx_frame_errors++;
-				if (desc_status & DescRxCRC) 
+				if (desc_status & DescRxCRC)
 					np->stats.rx_crc_errors++;
 			}
 		} else {
 			struct sk_buff *skb;
 			/* Omit CRC size. */
 			int pkt_len = (desc_status & DescSizeMask) - 4;
-			/* Check if the packet is long enough to accept 
+			/* Check if the packet is long enough to accept
 			 * without copying to a minimally-sized skbuff. */
 			if (pkt_len < rx_copybreak
-				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+			    && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb->dev = dev;
-				skb_reserve(skb, 2);	/* 16 byte align the IP header */
-				pci_dma_sync_single(np->pci_dev, np->rx_dma[entry],
-							np->rx_skbuff[entry]->len,
-							PCI_DMA_FROMDEVICE);
+				/* 16 byte align the IP header */
+				skb_reserve(skb, 2);
+				pci_dma_sync_single(np->pci_dev,
+					np->rx_dma[entry],
+					np->rx_skbuff[entry]->len,
+					PCI_DMA_FROMDEVICE);
 #if HAS_IP_COPYSUM
-				eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
+				eth_copy_and_sum(skb,
+					np->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
 #else
-				memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
-					   pkt_len);
+				memcpy(skb_put(skb, pkt_len),
+					np->rx_skbuff[entry]->tail, pkt_len);
 #endif
 			} else {
 				pci_unmap_single(np->pci_dev, np->rx_dma[entry],
-							np->rx_skbuff[entry]->len,
-							PCI_DMA_FROMDEVICE);
+					np->rx_skbuff[entry]->len,
+					PCI_DMA_FROMDEVICE);
 				skb_put(skb = np->rx_skbuff[entry], pkt_len);
 				np->rx_skbuff[entry] = NULL;
 			}
 			skb->protocol = eth_type_trans(skb, dev);
-			/* W/ hardware checksum: skb->ip_summed = CHECKSUM_UNNECESSARY; */
 			netif_rx(skb);
 			dev->last_rx = jiffies;
 			np->stats.rx_packets++;
@@ -1633,27 +1811,13 @@
 		np->rx_head_desc = &np->rx_ring[entry];
 		desc_status = le32_to_cpu(np->rx_head_desc->cmd_status);
 	}
-
-	/* Refill the Rx ring buffers. */
-	for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
-		struct sk_buff *skb;
-		entry = np->dirty_rx % RX_RING_SIZE;
-		if (np->rx_skbuff[entry] == NULL) {
-			skb = dev_alloc_skb(np->rx_buf_sz);
-			np->rx_skbuff[entry] = skb;
-			if (skb == NULL)
-				break;				/* Better luck next round. */
-			skb->dev = dev;			/* Mark as being used by this device. */
-			np->rx_dma[entry] = pci_map_single(np->pci_dev,
-							skb->data, skb->len, PCI_DMA_FROMDEVICE);
-			np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]);
-		}
-		np->rx_ring[entry].cmd_status =
-			cpu_to_le32(np->rx_buf_sz);
-	}
+	refill_rx(dev);
 
 	/* Restart Rx engine if stopped. */
-	writel(RxOn, dev->base_addr + ChipCmd);
+	if (np->oom)
+		mod_timer(&np->timer, jiffies + 1);
+	else
+		writel(RxOn, dev->base_addr + ChipCmd);
 }
 
 static void netdev_error(struct net_device *dev, int intr_status)
@@ -1665,9 +1829,9 @@
 	if (intr_status & LinkChange) {
 		u16 adv = mdio_read(dev, 1, MII_ADVERTISE);
 		u16 lpa = mdio_read(dev, 1, MII_LPA);
-		if (mdio_read(dev, 1, MII_BMCR) & BMCR_ANENABLE 
+		if (mdio_read(dev, 1, MII_BMCR) & BMCR_ANENABLE
 		 && netif_msg_link(np)) {
-			printk(KERN_INFO 
+			printk(KERN_INFO
 				"%s: Autonegotiation advertising"
 				" %#04x  partner %#04x.\n", dev->name,
 				adv, lpa);
@@ -1684,19 +1848,19 @@
 		if ((np->tx_config & TxDrthMask) < 62)
 			np->tx_config += 2;
 		if (netif_msg_tx_err(np))
-			printk(KERN_NOTICE 
-				"%s: increased Tx theshold, txcfg %#08x.\n",
+			printk(KERN_NOTICE
+				"%s: increased Tx threshold, txcfg %#08x.\n",
 				dev->name, np->tx_config);
 		writel(np->tx_config, ioaddr + TxConfig);
 	}
 	if (intr_status & WOLPkt && netif_msg_wol(np)) {
 		int wol_status = readl(ioaddr + WOLCmd);
 		printk(KERN_NOTICE "%s: Link wake-up event %#08x\n",
-			   dev->name, wol_status);
+			dev->name, wol_status);
 	}
 	if (intr_status & RxStatusFIFOOver) {
 		if (netif_msg_rx_err(np) && netif_msg_intr(np)) {
-			printk(KERN_NOTICE "%s: Rx status FIFO overrun\n", 
+			printk(KERN_NOTICE "%s: Rx status FIFO overrun\n",
 				dev->name);
 		}
 		np->stats.rx_fifo_errors++;
@@ -1727,8 +1891,8 @@
 
 	/* The chip only need report frame silently dropped. */
 	spin_lock_irq(&np->lock);
- 	if (netif_running(dev) && netif_device_present(dev))
- 		__get_stats(dev);
+	if (netif_running(dev) && !np->hands_off)
+		__get_stats(dev);
 	spin_unlock_irq(&np->lock);
 
 	return &np->stats;
@@ -1744,27 +1908,27 @@
 #define DP_POLYNOMIAL			0x04C11DB7
 static unsigned dp83815_crc(int length, unsigned char *data)
 {
-    u32 crc;
-    u8 cur_byte;
-    u8 msb;
-    u8 byte, bit;
-
-    crc = ~0;
-    for (byte=0; byte<length; byte++) {
-        cur_byte = *data++;
-        for (bit=0; bit<8; bit++) {
-            msb = crc >> 31;
-            crc <<= 1;
-            if (msb ^ (cur_byte & 1)) {
-                crc ^= DP_POLYNOMIAL;
-                crc |= 1;
-            }
-            cur_byte >>= 1;
-        }
-    }
-    crc >>= 23;
+	u32 crc;
+	u8 cur_byte;
+	u8 msb;
+	u8 byte, bit;
+
+	crc = ~0;
+	for (byte=0; byte<length; byte++) {
+		cur_byte = *data++;
+		for (bit=0; bit<8; bit++) {
+			msb = crc >> 31;
+			crc <<= 1;
+			if (msb ^ (cur_byte & 1)) {
+				crc ^= DP_POLYNOMIAL;
+				crc |= 1;
+			}
+			cur_byte >>= 1;
+		}
+	}
+	crc >>= 23;
 
-    return (crc);
+	return (crc);
 }
 
 
@@ -1777,18 +1941,18 @@
 {
 	long ioaddr = dev->base_addr;
 	struct netdev_private *np = dev->priv;
-	u8 mc_filter[64];			/* Multicast hash filter */
+	u8 mc_filter[64]; /* Multicast hash filter */
 	u32 rx_mode;
 
-	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
+	if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
 		/* Unconditionally log net taps. */
-		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", 
+		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
 			dev->name);
-		rx_mode = RxFilterEnable | AcceptBroadcast 
+		rx_mode = RxFilterEnable | AcceptBroadcast
 			| AcceptAllMulticast | AcceptAllPhys | AcceptMyPhys;
 	} else if ((dev->mc_count > multicast_filter_limit)
-			   ||  (dev->flags & IFF_ALLMULTI)) {
-		rx_mode = RxFilterEnable | AcceptBroadcast 
+	  || (dev->flags & IFF_ALLMULTI)) {
+		rx_mode = RxFilterEnable | AcceptBroadcast
 			| AcceptAllMulticast | AcceptMyPhys;
 	} else {
 		struct dev_mc_list *mclist;
@@ -1796,14 +1960,15 @@
 		memset(mc_filter, 0, sizeof(mc_filter));
 		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
 			 i++, mclist = mclist->next) {
-			set_bit_le(dp83815_crc(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
-					mc_filter);
+			set_bit_le(
+				dp83815_crc(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
+				mc_filter);
 		}
-		rx_mode = RxFilterEnable | AcceptBroadcast 
+		rx_mode = RxFilterEnable | AcceptBroadcast
 			| AcceptMulticast | AcceptMyPhys;
 		for (i = 0; i < 64; i += 2) {
 			writew(HASH_TABLE + i, ioaddr + RxFilterAddr);
-			writew((mc_filter[i+1]<<8) + mc_filter[i], 
+			writew((mc_filter[i+1]<<8) + mc_filter[i],
 				ioaddr + RxFilterData);
 		}
 	}
@@ -1815,7 +1980,7 @@
 {
 	struct netdev_private *np = dev->priv;
 	spin_lock_irq(&np->lock);
-	if (netif_device_present(dev))
+	if (!np->hands_off)
 		__set_rx_mode(dev);
 	spin_unlock_irq(&np->lock);
 }
@@ -1824,18 +1989,18 @@
 {
 	struct netdev_private *np = dev->priv;
 	u32 cmd;
-	
+
 	if (get_user(cmd, (u32 *)useraddr))
 		return -EFAULT;
 
-        switch (cmd) {
+	switch (cmd) {
 	/* get driver info */
-        case ETHTOOL_GDRVINFO: {
+	case ETHTOOL_GDRVINFO: {
 		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
 		strncpy(info.driver, DRV_NAME, ETHTOOL_BUSINFO_LEN);
 		strncpy(info.version, DRV_VERSION, ETHTOOL_BUSINFO_LEN);
 		info.fw_version[0] = '\0';
-		strncpy(info.bus_info, np->pci_dev->slot_name, 
+		strncpy(info.bus_info, np->pci_dev->slot_name,
 			ETHTOOL_BUSINFO_LEN);
 		info.eedump_len = NATSEMI_EEPROM_SIZE;
 		info.regdump_len = NATSEMI_REGS_SIZE;
@@ -1895,7 +2060,7 @@
 
 		if (copy_from_user(&regs, useraddr, sizeof(regs)))
 			return -EFAULT;
-		
+
 		if (regs.len > NATSEMI_REGS_SIZE) {
 			regs.len = NATSEMI_REGS_SIZE;
 		}
@@ -1962,10 +2127,10 @@
 
 		if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
 			return -EFAULT;
-		
+
 		if (eeprom.offset > eeprom.offset+eeprom.len)
 			return -EINVAL;
-			
+
 		if ((eeprom.offset+eeprom.len) > NATSEMI_EEPROM_SIZE) {
 			eeprom.len = NATSEMI_EEPROM_SIZE-eeprom.offset;
 		}
@@ -1986,8 +2151,8 @@
 		return 0;
 	}
 
-        }
-	
+	}
+
 	return -EOPNOTSUPP;
 }
 
@@ -2009,7 +2174,7 @@
 		data |= WakeArp;
 	if (newval & WAKE_MAGIC)
 		data |= WakeMagic;
-	if (np->srr >= SRR_REV_D) {
+	if (np->srr >= SRR_DP83815_D) {
 		if (newval & WAKE_MAGICSECURE) {
 			data |= WakeMagicSecure;
 		}
@@ -2025,10 +2190,10 @@
 	struct netdev_private *np = dev->priv;
 	u32 regval = readl(dev->base_addr + WOLCmd);
 
-	*supported = (WAKE_PHY | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST 
+	*supported = (WAKE_PHY | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST
 			| WAKE_ARP | WAKE_MAGIC);
-	
-	if (np->srr >= SRR_REV_D) {
+
+	if (np->srr >= SRR_DP83815_D) {
 		/* SOPASS works on revD and higher */
 		*supported |= WAKE_MAGICSECURE;
 	}
@@ -2060,8 +2225,8 @@
 	struct netdev_private *np = dev->priv;
 	u16 *sval = (u16 *)newval;
 	u32 addr;
-	
-	if (np->srr < SRR_REV_D) {
+
+	if (np->srr < SRR_DP83815_D) {
 		return 0;
 	}
 
@@ -2076,10 +2241,10 @@
 
 	writel(addr | 0xc, dev->base_addr + RxFilterAddr);
 	writew(sval[1], dev->base_addr + RxFilterData);
-	
+
 	writel(addr | 0xe, dev->base_addr + RxFilterAddr);
 	writew(sval[2], dev->base_addr + RxFilterData);
-	
+
 	/* re-enable the RX filter */
 	writel(addr | RxFilterEnable, dev->base_addr + RxFilterAddr);
 
@@ -2092,7 +2257,7 @@
 	u16 *sval = (u16 *)data;
 	u32 addr;
 
-	if (np->srr < SRR_REV_D) {
+	if (np->srr < SRR_DP83815_D) {
 		sval[0] = sval[1] = sval[2] = 0;
 		return 0;
 	}
@@ -2105,10 +2270,10 @@
 
 	writel(addr | 0xc, dev->base_addr + RxFilterAddr);
 	sval[1] = readw(dev->base_addr + RxFilterData);
-	
+
 	writel(addr | 0xe, dev->base_addr + RxFilterAddr);
 	sval[2] = readw(dev->base_addr + RxFilterData);
-	
+
 	writel(addr, dev->base_addr + RxFilterAddr);
 
 	return 0;
@@ -2118,11 +2283,11 @@
 {
 	u32 tmp;
 
-	ecmd->supported = 
+	ecmd->supported =
 		(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
 		SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
 		SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
-	
+
 	/* only supports twisted-pair or MII */
 	tmp = readl(dev->base_addr + ChipConfig);
 	if (tmp & CfgExtPhy)
@@ -2161,7 +2326,7 @@
 	} else {
 		ecmd->speed = SPEED_10;
 	}
-		
+
 	if (tmp & CfgFullDuplex) {
 		ecmd->duplex = DUPLEX_FULL;
 	} else {
@@ -2189,9 +2354,9 @@
 	if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
 		return -EINVAL;
 	/* ignore phy_address, maxtxpkt, maxrxpkt for now */
-	
+
 	/* WHEW! now lets bang some bits */
-	
+
 	tmp = mdio_read(dev, 1, MII_BMCR);
 	if (ecmd->autoneg == AUTONEG_ENABLE) {
 		/* turn on autonegotiation */
@@ -2217,7 +2382,7 @@
 	int j;
 	u32 rfcr;
 	u32 *rbuf = (u32 *)buf;
-	
+
 	/* read all of page 0 of registers */
 	for (i = 0; i < NATSEMI_PG0_NREGS; i++) {
 		rbuf[i] = readl(dev->base_addr + i*4);
@@ -2241,8 +2406,8 @@
 
 	/* the interrupt status is clear-on-read - see if we missed any */
 	if (rbuf[4] & rbuf[5]) {
-		printk(KERN_WARNING 
-			"%s: shoot, we dropped an interrupt (%#08x)\n", 
+		printk(KERN_WARNING
+			"%s: shoot, we dropped an interrupt (%#08x)\n",
 			dev->name, rbuf[4] & rbuf[5]);
 	}
 
@@ -2266,7 +2431,7 @@
 	/* eeprom_read reads 16 bits, and indexes by 16 bits */
 	for (i = 0; i < NATSEMI_EEPROM_SIZE/2; i++) {
 		ebuf[i] = eeprom_read(dev->base_addr, i);
-		/* The EEPROM itself stores data bit-swapped, but eeprom_read 
+		/* The EEPROM itself stores data bit-swapped, but eeprom_read
 		 * reads it back "sanely". So we swap it back here in order to
 		 * present it to userland as it is stored. */
 		ebuf[i] = SWAP_BITS(ebuf[i]);
@@ -2288,7 +2453,7 @@
 
 	case SIOCGMIIREG:		/* Read MII PHY register. */
 	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
-		data->val_out = mdio_read(dev, data->phy_id & 0x1f, 
+		data->val_out = mdio_read(dev, data->phy_id & 0x1f,
 			data->reg_num & 0x1f);
 		return 0;
 
@@ -2296,7 +2461,7 @@
 	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
-		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, 
+		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f,
 			data->val_in);
 		return 0;
 	default:
@@ -2310,7 +2475,7 @@
 	struct netdev_private *np = dev->priv;
 
 	if (netif_msg_wol(np))
-		printk(KERN_INFO "%s: remaining active for wake-on-lan\n", 
+		printk(KERN_INFO "%s: remaining active for wake-on-lan\n",
 			dev->name);
 
 	/* For WOL we must restart the rx process in silent mode.
@@ -2332,7 +2497,8 @@
 		/* enable the WOL interrupt.
 		 * Could be used to send a netlink message.
 		 */
-		writel(readl(ioaddr + IntrMask) | WOLPkt, ioaddr + IntrMask);
+		writel(WOLPkt | LinkChange, ioaddr + IntrMask);
+		writel(1, ioaddr + IntrEnable);
 	}
 }
 
@@ -2341,57 +2507,62 @@
 	long ioaddr = dev->base_addr;
 	struct netdev_private *np = dev->priv;
 
-	netif_stop_queue(dev);
-	netif_carrier_off(dev);
-
 	if (netif_msg_ifdown(np))
-		printk(KERN_DEBUG 
+		printk(KERN_DEBUG
 			"%s: Shutting down ethercard, status was %#04x.\n",
 			dev->name, (int)readl(ioaddr + ChipCmd));
 	if (netif_msg_pktdata(np))
-		printk(KERN_DEBUG 
+		printk(KERN_DEBUG
 			"%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
-			dev->name, np->cur_tx, np->dirty_tx, 
+			dev->name, np->cur_tx, np->dirty_tx,
 			np->cur_rx, np->dirty_rx);
 
-	del_timer_sync(&np->timer);
+	/*
+	 * FIXME: what if someone tries to close a device
+	 * that is suspended?
+	 * Should we reenable the nic to switch to
+	 * the final WOL settings?
+	 */
 
+	del_timer_sync(&np->timer);
 	disable_irq(dev->irq);
 	spin_lock_irq(&np->lock);
-
-	/* Disable and clear interrupts */
+	/* Disable interrupts, and flush posted writes */
 	writel(0, ioaddr + IntrEnable);
+	readl(ioaddr + IntrEnable);
+	np->hands_off = 1;
+	spin_unlock_irq(&np->lock);
+	enable_irq(dev->irq);
+
+	free_irq(dev->irq, dev);
+
+	/* Interrupt disabled, interrupt handler released,
+	 * queue stopped, timer deleted, rtnl_lock held
+	 * All async codepaths that access the driver are disabled.
+	 */
+	spin_lock_irq(&np->lock);
+	np->hands_off = 0;
 	readl(ioaddr + IntrMask);
 	readw(ioaddr + MIntrStatus);
 
- 	/* Freeze Stats */
+	/* Freeze Stats */
 	writel(StatsFreeze, ioaddr + StatsCtrl);
-	    
+
 	/* Stop the chip's Tx and Rx processes. */
 	natsemi_stop_rxtx(dev);
 
 	__get_stats(dev);
 	spin_unlock_irq(&np->lock);
 
-	/* race: shared irq and as most nics the DP83815
-	 * reports _all_ interrupt conditions in IntrStatus, even
-	 * disabled ones.
-	 * packet received after disable_irq, but before stop_rxtx
-	 * --> race. intr_handler would restart the rx process.
-	 * netif_device_{de,a}tach around {enable,free}_irq.
-	 */
-	netif_device_detach(dev);
-	enable_irq(dev->irq);
-	free_irq(dev->irq, dev);
-	netif_device_attach(dev);
 	/* clear the carrier last - an interrupt could reenable it otherwise */
 	netif_carrier_off(dev);
+	netif_stop_queue(dev);
 
 	dump_ring(dev);
 	drain_ring(dev);
 	free_ring(dev);
 
-	 {
+	{
 		u32 wol = readl(ioaddr + WOLCmd) & WakeOptsSummary;
 		if (wol) {
 			/* restart the NIC in WOL mode.
@@ -2406,7 +2577,7 @@
 	return 0;
 }
 
-
+
 static void __devexit natsemi_remove1 (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
@@ -2421,23 +2592,26 @@
 #ifdef CONFIG_PM
 
 /*
+ * The ns83815 chip doesn't have explicit RxStop bits.
+ * Kicking the Rx or Tx process for a new packet reenables the Rx process
+ * of the nic, thus this function must be very careful:
+ *
  * suspend/resume synchronization:
  * entry points:
  *   netdev_open, netdev_close, netdev_ioctl, set_rx_mode, intr_handler,
  *   start_tx, tx_timeout
- * Reading from some registers can restart the nic!
- * No function accesses the hardware without checking netif_device_present().
- * 	the check occurs under spin_lock_irq(&np->lock);
+ *
+ * No function accesses the hardware without checking np->hands_off.
+ *	the check occurs under spin_lock_irq(&np->lock);
  * exceptions:
- * 	* netdev_ioctl, netdev_open.
- * 		net/core checks netif_device_present() before calling them.
- * 	* netdev_close: doesn't hurt.
+ *	* netdev_ioctl: noncritical access.
+ *	* netdev_open: cannot happen due to the device_detach
+ *	* netdev_close: doesn't hurt.
  *	* netdev_timer: timer stopped by natsemi_suspend.
  *	* intr_handler: doesn't acquire the spinlock. suspend calls
  *		disable_irq() to enforce synchronization.
  *
- * netif_device_detach must occur under spin_unlock_irq(), interrupts from a
- * detached device would cause an irq storm.
+ * Interrupts must be disabled, otherwise hands_off can cause irq storms.
  */
 
 static int natsemi_suspend (struct pci_dev *pdev, u32 state)
@@ -2454,13 +2628,13 @@
 		spin_lock_irq(&np->lock);
 
 		writel(0, ioaddr + IntrEnable);
+		np->hands_off = 1;
 		natsemi_stop_rxtx(dev);
 		netif_stop_queue(dev);
-		netif_device_detach(dev);
 
 		spin_unlock_irq(&np->lock);
 		enable_irq(dev->irq);
-		
+
 		/* Update the error counts. */
 		__get_stats(dev);
 
@@ -2472,7 +2646,7 @@
 			if (wol) {
 				/* restart the NIC in WOL mode.
 				 * The nic must be stopped for this.
-				 * FIXME: use the WOL interupt 
+				 * FIXME: use the WOL interupt
 				 */
 				enable_wol_mode(dev, 0);
 			} else {
@@ -2480,9 +2654,8 @@
 				writel(np->SavedClkRun, ioaddr + ClkRun);
 			}
 		}
-	} else {
-		netif_device_detach(dev);
 	}
+	netif_device_detach(dev);
 	rtnl_unlock();
 	return 0;
 }
@@ -2497,20 +2670,23 @@
 	if (netif_device_present(dev))
 		goto out;
 	if (netif_running(dev)) {
+		BUG_ON(!np->hands_off);
 		pci_enable_device(pdev);
 	/*	pci_power_on(pdev); */
-		
+
 		natsemi_reset(dev);
 		init_ring(dev);
+		disable_irq(dev->irq);
 		spin_lock_irq(&np->lock);
+		np->hands_off = 0;
 		init_registers(dev);
 		netif_device_attach(dev);
 		spin_unlock_irq(&np->lock);
+		enable_irq(dev->irq);
 
 		mod_timer(&np->timer, jiffies + 1*HZ);
-	} else {
-		netif_device_attach(dev);
 	}
+	netif_device_attach(dev);
 out:
 	rtnl_unlock();
 	return 0;
@@ -2519,13 +2695,13 @@
 #endif /* CONFIG_PM */
 
 static struct pci_driver natsemi_driver = {
-	name:		DRV_NAME,
-	id_table:	natsemi_pci_tbl,
-	probe:		natsemi_probe1,
-	remove:		__devexit_p(natsemi_remove1),
+	.name		= DRV_NAME,
+	.id_table	= natsemi_pci_tbl,
+	.probe		= natsemi_probe1,
+	.remove		= __devexit_p(natsemi_remove1),
 #ifdef CONFIG_PM
-	suspend:	natsemi_suspend,
-	resume:		natsemi_resume,
+	.suspend	= natsemi_suspend,
+	.resume		= natsemi_resume,
 #endif
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/ni65.c linux-2.4.20/drivers/net/ni65.c
--- linux-2.4.19/drivers/net/ni65.c	2001-09-30 19:26:07.000000000 +0000
+++ linux-2.4.20/drivers/net/ni65.c	2002-10-29 11:18:35.000000000 +0000
@@ -353,18 +353,21 @@
 	unsigned long flags;
 
 	for(i=0;i<NUM_CARDS;i++) {
-		if(check_region(ioaddr, cards[i].total_size))
+		if(!request_region(ioaddr, cards[i].total_size, cards[i].cardname))
 			continue;
 		if(cards[i].id_offset >= 0) {
 			if(inb(ioaddr+cards[i].id_offset+0) != cards[i].id0 ||
 				 inb(ioaddr+cards[i].id_offset+1) != cards[i].id1) {
+				 release_region(ioaddr, cards[i].total_size);
 				 continue;
 			}
 		}
 		if(cards[i].vendor_id) {
 			for(j=0;j<3;j++)
-				if(inb(ioaddr+cards[i].addr_offset+j) != cards[i].vendor_id[j])
+				if(inb(ioaddr+cards[i].addr_offset+j) != cards[i].vendor_id[j]) {
+					release_region(ioaddr, cards[i].total_size);
 					continue;
+			  }
 		}
 		break;
 	}
@@ -374,8 +377,10 @@
 	for(j=0;j<6;j++)
 		dev->dev_addr[j] = inb(ioaddr+cards[i].addr_offset+j);
 
-	if( (j=ni65_alloc_buffer(dev)) < 0)
+	if( (j=ni65_alloc_buffer(dev)) < 0) {
+		release_region(ioaddr, cards[i].total_size);
 		return j;
+	}
 	p = (struct priv *) dev->priv;
 	p->cmdr_addr = ioaddr + cards[i].cmd_offset;
 	p->cardno = i;
@@ -386,6 +391,7 @@
 	if( (j=readreg(CSR0)) != 0x4) {
 		 printk(KERN_ERR "can't RESET card: %04x\n",j);
 		 ni65_free_buffer(p);
+		 release_region(ioaddr, cards[p->cardno].total_size);
 		 return -EAGAIN;
 	}
 
@@ -437,6 +443,7 @@
 			if(i == 5) {
 				printk("Can't detect DMA channel!\n");
 				ni65_free_buffer(p);
+				release_region(ioaddr, cards[p->cardno].total_size);
 				return -EAGAIN;
 			}
 			dev->dma = dmatab[i];
@@ -455,6 +462,7 @@
 			{
 				printk("Failed to detect IRQ line!\n");
 				ni65_free_buffer(p);
+				release_region(ioaddr, cards[p->cardno].total_size);
 				return -EAGAIN;
 			}
 			printk("IRQ %d (autodetected).\n",dev->irq);
@@ -467,14 +475,10 @@
 	{
 		printk("%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma);
 		ni65_free_buffer(p);
+		release_region(ioaddr, cards[p->cardno].total_size);
 		return -EAGAIN;
 	}
 
-	/*
-	 * Grab the region so we can find another board.
-	 */
-	request_region(ioaddr,cards[p->cardno].total_size,cards[p->cardno].cardname);
-
 	dev->base_addr = ioaddr;
 
 	dev->open		= ni65_open;
@@ -1101,7 +1105,7 @@
 	{
 		short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 		struct tmd *tmdp;
-		long flags;
+		unsigned long flags;
 
 #ifdef XMT_VIA_SKB
 		if( (unsigned long) (skb->data + skb->len) > 0x1000000) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/ns83820.c linux-2.4.20/drivers/net/ns83820.c
--- linux-2.4.19/drivers/net/ns83820.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/ns83820.c	2002-10-29 11:18:50.000000000 +0000
@@ -1,9 +1,9 @@
-#define _VERSION "0.18"
+#define _VERSION "0.20"
 /* ns83820.c by Benjamin LaHaise with contributions.
  *
  * Questions/comments/discussion to linux-ns83820@kvack.org.
  *
- * $Revision: 1.34.2.16 $
+ * $Revision: 1.34.2.23 $
  *
  * Copyright 2001 Benjamin LaHaise.
  * Copyright 2001, 2002 Red Hat.
@@ -57,6 +57,12 @@
  *	20020310	0.17	speedups
  *	20020610	0.18 -	actually use the pci dma api for highmem
  *			     -	remove pci latency register fiddling
+ *			0.19 -	better bist support
+ *			     -	add ihr and reset_phy parameters
+ *			     -	gmii bus probing
+ *			     -	fix missed txok introduced during performance
+ *				tuning
+ *			0.20 -	fix stupid RFEN thinko.  i am such a smurf.
  *
  * Driver Overview
  * ===============
@@ -101,10 +107,16 @@
 #include <linux/compiler.h>
 #include <linux/prefetch.h>
 #include <linux/ethtool.h>
+#include <linux/timer.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
+/* Global parameters.  See MODULE_PARM near the bottom. */
+static int ihr = 2;
+static int reset_phy = 0;
+static int lnksts = 0;		/* CFG_LNKSTS bit polarity */
+
 /* Dprintk is used for more interesting debug events */
 #undef Dprintk
 #define	Dprintk			dprintk
@@ -126,7 +138,7 @@
 
 /* Must not exceed ~65000. */
 #define NR_RX_DESC	64
-#define NR_TX_DESC	64
+#define NR_TX_DESC	128
 
 /* not tunable */
 #define REAL_RX_BUF_SIZE (RX_BUF_SIZE + 14)	/* rx/tx mac addr + type */
@@ -138,6 +150,9 @@
 
 #define CR_TXE		0x00000001
 #define CR_TXD		0x00000002
+/* Ramit : Here's a tip, don't do a RXD immediately followed by an RXE
+ * The Receive engine skips one descriptor and moves
+ * onto the next one!! */
 #define CR_RXE		0x00000004
 #define CR_RXD		0x00000008
 #define CR_TXR		0x00000010
@@ -145,8 +160,21 @@
 #define CR_SWI		0x00000080
 #define CR_RST		0x00000100
 
-#define PTSCR_EEBIST_EN	0x00000002
-#define PTSCR_EELOAD_EN	0x00000004
+#define PTSCR_EEBIST_FAIL       0x00000001
+#define PTSCR_EEBIST_EN         0x00000002
+#define PTSCR_EELOAD_EN         0x00000004
+#define PTSCR_RBIST_FAIL        0x000001b8
+#define PTSCR_RBIST_DONE        0x00000200
+#define PTSCR_RBIST_EN          0x00000400
+#define PTSCR_RBIST_RST         0x00002000
+
+#define MEAR_EEDI		0x00000001
+#define MEAR_EEDO		0x00000002
+#define MEAR_EECLK		0x00000004
+#define MEAR_EESEL		0x00000008
+#define MEAR_MDIO		0x00000010
+#define MEAR_MDDIR		0x00000020
+#define MEAR_MDC		0x00000040
 
 #define ISR_TXDESC3	0x40000000
 #define ISR_TXDESC2	0x20000000
@@ -202,6 +230,8 @@
 #define CFG_DUPSTS	0x10000000
 #define CFG_TBI_EN	0x01000000
 #define CFG_MODE_1000	0x00400000
+/* Ramit : Dont' ever use AUTO_1000, it never works and is buggy.
+ * Read the Phy response and then configure the MAC accordingly */
 #define CFG_AUTO_1000	0x00200000
 #define CFG_PINT_CTL	0x001c0000
 #define CFG_PINT_DUPSTS	0x00100000
@@ -230,22 +260,29 @@
 #define EXTSTS_TCPPKT	0x00080000
 #define EXTSTS_IPPKT	0x00020000
 
-#define SPDSTS_POLARITY	(CFG_SPDSTS1 | CFG_SPDSTS0 | CFG_DUPSTS)
+#define SPDSTS_POLARITY	(CFG_SPDSTS1 | CFG_SPDSTS0 | CFG_DUPSTS | (lnksts ? CFG_LNKSTS : 0))
 
 #define MIBC_MIBS	0x00000008
 #define MIBC_ACLR	0x00000004
 #define MIBC_FRZ	0x00000002
 #define MIBC_WRN	0x00000001
 
+#define PCR_PSEN	(1 << 31)
+#define PCR_PS_MCAST	(1 << 30)
+#define PCR_PS_DA	(1 << 29)
+#define PCR_STHI_8	(3 << 23)
+#define PCR_STLO_4	(1 << 23)
+#define PCR_FFHI_8K	(3 << 21)
+#define PCR_FFLO_4K	(1 << 21)
+#define PCR_PAUSE_CNT	0xFFFE
+
 #define RXCFG_AEP	0x80000000
 #define RXCFG_ARP	0x40000000
 #define RXCFG_STRIPCRC	0x20000000
 #define RXCFG_RX_FD	0x10000000
 #define RXCFG_ALP	0x08000000
 #define RXCFG_AIRL	0x04000000
-#define RXCFG_MXDMA	0x00700000
-#define RXCFG_MXDMA0	0x00100000
-#define RXCFG_MXDMA64	0x00600000
+#define RXCFG_MXDMA512	0x00700000
 #define RXCFG_DRTH	0x0000003e
 #define RXCFG_DRTH0	0x00000002
 
@@ -354,23 +391,22 @@
 #define desc_addr_set(desc, addr)				\
 	do {							\
 		u64 __addr = (addr);				\
-		desc[BUFPTR] = cpu_to_le32(__addr);		\
-		desc[BUFPTR+1] = cpu_to_le32(__addr >> 32);	\
+		(desc)[0] = cpu_to_le32(__addr);		\
+		(desc)[1] = cpu_to_le32(__addr >> 32);		\
 	} while(0)
 #define desc_addr_get(desc)					\
-		(((u64)le32_to_cpu(desc[BUFPTR+1]) << 32)	\
-		     | le32_to_cpu(desc[BUFPTR]))
+		(((u64)le32_to_cpu((desc)[1]) << 32)		\
+		     | le32_to_cpu((desc)[0]))
 #else
 #define HW_ADDR_LEN	4
-#define desc_addr_set(desc, addr)	(desc[BUFPTR] = cpu_to_le32(addr))
-#define desc_addr_get(desc)		(le32_to_cpu(desc[BUFPTR]))
+#define desc_addr_set(desc, addr)	((desc)[0] = cpu_to_le32(addr))
+#define desc_addr_get(desc)		(le32_to_cpu((desc)[0]))
 #endif
 
-#define LINK		0
-#define BUFPTR		(LINK + HW_ADDR_LEN/4)
-#define CMDSTS		(BUFPTR + HW_ADDR_LEN/4)
-#define EXTSTS		(CMDSTS + 4/4)
-#define DRV_NEXT	(EXTSTS + 4/4)
+#define DESC_LINK		0
+#define DESC_BUFPTR		(DESC_LINK + HW_ADDR_LEN/4)
+#define DESC_CMDSTS		(DESC_BUFPTR + HW_ADDR_LEN/4)
+#define DESC_EXTSTS		(DESC_CMDSTS + 4/4)
 
 #define CMDSTS_OWN	0x80000000
 #define CMDSTS_MORE	0x40000000
@@ -426,18 +462,19 @@
 
 	spinlock_t	tx_lock;
 
-	long		tx_idle;
-
 	u16		tx_done_idx;
 	u16		tx_idx;
 	volatile u16	tx_free_idx;	/* idx of free desc chain */
 	u16		tx_intr_idx;
 
+	atomic_t	nr_tx_skbs;
 	struct sk_buff	*tx_skbs[NR_TX_DESC];
 
 	char		pad[16] __attribute__((aligned(16)));
 	u32		*tx_descs;
 	dma_addr_t	tx_phy_descs;
+
+	struct timer_list	tx_watchdog;
 };
 
 //free = (tx_done_idx + NR_TX_DESC-2 - free_idx) % NR_TX_DESC
@@ -458,33 +495,15 @@
  * conditions, still route realtime traffic with as low jitter as
  * possible.
  */
-#ifdef USE_64BIT_ADDR
-static inline void build_rx_desc64(struct ns83820 *dev, u32 *desc, u64 link, u64 buf, u32 cmdsts, u32 extsts)
-{
-	desc[0] = link;
-	desc[1] = link >> 32;
-	desc[2] = buf;
-	desc[3] = buf >> 32;
-	desc[5] = extsts;
-	mb();
-	desc[4] = cmdsts;
-}
-
-#define build_rx_desc	build_rx_desc64
-#else
-
-static inline void build_rx_desc32(struct ns83820 *dev, u32 *desc, u32 link, u32 buf, u32 cmdsts, u32 extsts)
+static inline void build_rx_desc(struct ns83820 *dev, u32 *desc, dma_addr_t link, dma_addr_t buf, u32 cmdsts, u32 extsts)
 {
-	desc[0] = cpu_to_le32(link);
-	desc[1] = cpu_to_le32(buf);
-	desc[3] = cpu_to_le32(extsts);
+	desc_addr_set(desc + DESC_LINK, link);
+	desc_addr_set(desc + DESC_BUFPTR, buf);
+	desc[DESC_EXTSTS] = extsts;
 	mb();
-	desc[2] = cpu_to_le32(cmdsts);
+	desc[DESC_CMDSTS] = cmdsts;
 }
 
-#define build_rx_desc	build_rx_desc32
-#endif
-
 #define nr_rx_empty(dev) ((NR_RX_DESC-2 + dev->rx_info.next_rx - dev->rx_info.next_empty) % NR_RX_DESC)
 static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb)
 {
@@ -717,7 +736,7 @@
 		phy_intr(dev);
 
 		/* Okay, let it rip */
-		spin_lock(&dev->misc_lock);
+		spin_lock_irq(&dev->misc_lock);
 		dev->IMR_cache |= ISR_PHY;
 		dev->IMR_cache |= ISR_RXRCMP;
 		//dev->IMR_cache |= ISR_RXERR;
@@ -731,7 +750,7 @@
 
 		writel(dev->IMR_cache, dev->base + IMR);
 		writel(1, dev->base + IER);
-		spin_unlock(&dev->misc_lock);
+		spin_unlock_irq(&dev->misc_lock);
 
 		kick_rx(dev);
 
@@ -788,7 +807,7 @@
 	else
 		kick_rx(dev);
 	if (dev->rx_info.idle)
-		Dprintk("BAD\n");
+		printk(KERN_DEBUG "%s: BAD\n", dev->net_dev.name);
 }
 
 /* rx_irq
@@ -820,14 +839,14 @@
 	dprintk("walking descs\n");
 	next_rx = info->next_rx;
 	desc = info->next_rx_desc;
-	while ((CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[CMDSTS]))) &&
+	while ((CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[DESC_CMDSTS]))) &&
 	       (cmdsts != CMDSTS_OWN)) {
 		struct sk_buff *skb;
-		u32 extsts = le32_to_cpu(desc[EXTSTS]);
-		dma_addr_t bufptr = desc_addr_get(desc);
+		u32 extsts = le32_to_cpu(desc[DESC_EXTSTS]);
+		dma_addr_t bufptr = desc_addr_get(desc + DESC_BUFPTR);
 
 		dprintk("cmdsts: %08x\n", cmdsts);
-		dprintk("link: %08x\n", cpu_to_le32(desc[LINK]));
+		dprintk("link: %08x\n", cpu_to_le32(desc[DESC_LINK]));
 		dprintk("extsts: %08x\n", extsts);
 
 		skb = info->skbs[next_rx];
@@ -881,8 +900,13 @@
 {
 	struct ns83820 *dev = (void *)_dev;
 	rx_irq(dev);
-	writel(0x002, dev->base + IHR);
-	writel(dev->IMR_cache | ISR_RXDESC, dev->base + IMR);
+	writel(ihr, dev->base + IHR);
+
+	spin_lock_irq(&dev->misc_lock);
+	dev->IMR_cache |= ISR_RXDESC;
+	writel(dev->IMR_cache, dev->base + IMR);
+	spin_unlock_irq(&dev->misc_lock);
+
 	rx_irq(dev);
 	ns83820_rx_kick(dev);
 }
@@ -891,8 +915,8 @@
  */
 static inline void kick_tx(struct ns83820 *dev)
 {
-	dprintk("kick_tx(%p): tx_idle=%ld, tx_idx=%d free_idx=%d\n",
-		dev, dev->tx_idle, dev->tx_idx, dev->tx_free_idx);
+	dprintk("kick_tx(%p): tx_idx=%d free_idx=%d\n",
+		dev, dev->tx_idx, dev->tx_free_idx);
 	writel(CR_TXE, dev->base + CR);
 }
 
@@ -903,14 +927,16 @@
 {
 	u32 cmdsts, tx_done_idx, *desc;
 
+	spin_lock_irq(&dev->tx_lock);
+
 	dprintk("do_tx_done(%p)\n", dev);
 	tx_done_idx = dev->tx_done_idx;
 	desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
 
 	dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
-		tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[CMDSTS]));
+		tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS]));
 	while ((tx_done_idx != dev->tx_free_idx) &&
-	       !(CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[CMDSTS]))) ) {
+	       !(CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[DESC_CMDSTS]))) ) {
 		struct sk_buff *skb;
 		unsigned len;
 		dma_addr_t addr;
@@ -929,13 +955,14 @@
 		dprintk("done(%p)\n", skb);
 
 		len = cmdsts & CMDSTS_LEN_MASK;
-		addr = desc_addr_get(desc);
+		addr = desc_addr_get(desc + DESC_BUFPTR);
 		if (skb) {
 			pci_unmap_single(dev->pci_dev,
 					addr,
 					len,
 					PCI_DMA_TODEVICE);
 			dev_kfree_skb_irq(skb);
+			atomic_dec(&dev->nr_tx_skbs);
 		} else
 			pci_unmap_page(dev->pci_dev, 
 					addr,
@@ -944,7 +971,7 @@
 
 		tx_done_idx = (tx_done_idx + 1) % NR_TX_DESC;
 		dev->tx_done_idx = tx_done_idx;
-		desc[CMDSTS] = cpu_to_le32(0);
+		desc[DESC_CMDSTS] = cpu_to_le32(0);
 		mb();
 		desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
 	}
@@ -957,6 +984,7 @@
 		netif_start_queue(&dev->net_dev);
 		netif_wake_queue(&dev->net_dev);
 	}
+	spin_unlock_irq(&dev->tx_lock);
 }
 
 static void ns83820_cleanup_tx(struct ns83820 *dev)
@@ -966,12 +994,18 @@
 	for (i=0; i<NR_TX_DESC; i++) {
 		struct sk_buff *skb = dev->tx_skbs[i];
 		dev->tx_skbs[i] = NULL;
-		if (skb)
-			dev_kfree_skb(skb);
+		if (skb) {
+			u32 *desc = dev->tx_descs + (i * DESC_SIZE);
+			pci_unmap_single(dev->pci_dev,
+					desc_addr_get(desc + DESC_BUFPTR),
+					le32_to_cpu(desc[DESC_CMDSTS]) & CMDSTS_LEN_MASK,
+					PCI_DMA_TODEVICE);
+			dev_kfree_skb_irq(skb);
+			atomic_dec(&dev->nr_tx_skbs);
+		}
 	}
 
 	memset(dev->tx_descs, 0, NR_TX_DESC * DESC_SIZE * 4);
-	set_bit(0, &dev->tx_idle);
 }
 
 /* transmit routine.  This code relies on the network layer serializing
@@ -985,7 +1019,7 @@
 	struct ns83820 *dev = (struct ns83820 *)_dev;
 	u32 free_idx, cmdsts, extsts;
 	int nr_free, nr_frags;
-	unsigned tx_done_idx;
+	unsigned tx_done_idx, last_idx;
 	dma_addr_t buf;
 	unsigned len;
 	skb_frag_t *frag;
@@ -1004,7 +1038,7 @@
 		netif_start_queue(&dev->net_dev);
 	}
 
-	free_idx = dev->tx_free_idx;
+	last_idx = free_idx = dev->tx_free_idx;
 	tx_done_idx = dev->tx_done_idx;
 	nr_free = (tx_done_idx + NR_TX_DESC-2 - free_idx) % NR_TX_DESC;
 	nr_free -= 1;
@@ -1058,15 +1092,16 @@
 
 		dprintk("frag[%3u]: %4u @ 0x%08Lx\n", free_idx, len,
 			(unsigned long long)buf);
+		last_idx = free_idx;
 		free_idx = (free_idx + 1) % NR_TX_DESC;
-		desc[LINK] = cpu_to_le32(dev->tx_phy_descs + (free_idx * DESC_SIZE * 4));
-		desc_addr_set(desc, buf);
-		desc[EXTSTS] = cpu_to_le32(extsts);
+		desc[DESC_LINK] = cpu_to_le32(dev->tx_phy_descs + (free_idx * DESC_SIZE * 4));
+		desc_addr_set(desc + DESC_BUFPTR, buf);
+		desc[DESC_EXTSTS] = cpu_to_le32(extsts);
 
 		cmdsts = ((nr_frags|residue) ? CMDSTS_MORE : do_intr ? CMDSTS_INTR : 0);
 		cmdsts |= (desc == first_desc) ? 0 : CMDSTS_OWN;
 		cmdsts |= len;
-		desc[CMDSTS] = cpu_to_le32(cmdsts);
+		desc[DESC_CMDSTS] = cpu_to_le32(cmdsts);
 
 		if (residue) {
 			buf += len;
@@ -1088,15 +1123,22 @@
 		nr_frags--;
 	}
 	dprintk("done pkt\n");
-	dev->tx_skbs[free_idx] = skb;
-	first_desc[CMDSTS] |= cpu_to_le32(CMDSTS_OWN);
+
+	spin_lock_irq(&dev->tx_lock);
+	dev->tx_skbs[last_idx] = skb;
+	first_desc[DESC_CMDSTS] |= cpu_to_le32(CMDSTS_OWN);
 	dev->tx_free_idx = free_idx;
+	atomic_inc(&dev->nr_tx_skbs);
+	spin_unlock_irq(&dev->tx_lock);
+
 	kick_tx(dev);
 
 	/* Check again: we may have raced with a tx done irq */
 	if (stopped && (dev->tx_done_idx != tx_done_idx) && start_tx_okay(dev))
 		netif_start_queue(&dev->net_dev);
 
+	/* set the transmit start time to catch transmit timeouts */
+	dev->net_dev.trans_start = jiffies;
 	return 0;
 }
 
@@ -1190,6 +1232,7 @@
 	spin_unlock(&dev->misc_lock);
 }
 
+static void ns83820_do_isr(struct ns83820 *dev, u32 isr);
 static void ns83820_irq(int foo, void *data, struct pt_regs *regs)
 {
 	struct ns83820 *dev = data;
@@ -1200,7 +1243,11 @@
 
 	isr = readl(dev->base + ISR);
 	dprintk("irq: %08x\n", isr);
+	ns83820_do_isr(dev, isr);
+}
 
+static void ns83820_do_isr(struct ns83820 *dev, u32 isr)
+{
 #ifdef DEBUG
 	if (isr & ~(ISR_PHY | ISR_RXDESC | ISR_RXEARLY | ISR_RXOK | ISR_RXERR | ISR_TXIDLE | ISR_TXOK | ISR_TXDESC))
 		Dprintk("odd isr? 0x%08x\n", isr);
@@ -1214,7 +1261,12 @@
 
 	if ((ISR_RXDESC | ISR_RXOK) & isr) {
 		prefetch(dev->rx_info.next_rx_desc);
-		writel(dev->IMR_cache & ~(ISR_RXDESC | ISR_RXOK), dev->base + IMR);
+
+		spin_lock_irq(&dev->misc_lock);
+		dev->IMR_cache &= ~(ISR_RXDESC | ISR_RXOK);
+		writel(dev->IMR_cache, dev->base + IMR);
+		spin_unlock_irq(&dev->misc_lock);
+
 		tasklet_schedule(&dev->rx_tasklet);
 		//rx_irq(dev);
 		//writel(4, dev->base + IHR);
@@ -1246,12 +1298,11 @@
 			printk(KERN_ALERT "%s: BUG -- txdp out of range\n", dev->net_dev.name);
 			dev->tx_idx = 0;
 		}
-		if (dev->tx_idx != dev->tx_free_idx)
-			writel(CR_TXE, dev->base + CR);
-			//kick_tx(dev);
-		else
-			dev->tx_idle = 1;
-		mb();
+		/* The may have been a race between a pci originated read
+		 * and the descriptor update from the cpu.  Just in case, 
+		 * kick the transmitter if the hardware thinks it is on a 
+		 * different descriptor than we are.
+		 */
 		if (dev->tx_idx != dev->tx_free_idx)
 			kick_tx(dev);
 	}
@@ -1259,12 +1310,38 @@
 	/* Defer tx ring processing until more than a minimum amount of
 	 * work has accumulated
 	 */
-	if ((ISR_TXDESC | ISR_TXIDLE) & isr)
+	if ((ISR_TXDESC | ISR_TXIDLE | ISR_TXOK | ISR_TXERR) & isr) {
 		do_tx_done(dev);
 
+		/* Disable TxOk if there are no outstanding tx packets.
+		 */
+		if ((dev->tx_done_idx == dev->tx_free_idx) &&
+		    (dev->IMR_cache & ISR_TXOK)) {
+			spin_lock_irq(&dev->misc_lock);
+			dev->IMR_cache &= ~ISR_TXOK;
+			writel(dev->IMR_cache, dev->base + IMR);
+			spin_unlock_irq(&dev->misc_lock);
+		}
+	}
+
+	/* The TxIdle interrupt can come in before the transmit has
+	 * completed.  Normally we reap packets off of the combination
+	 * of TxDesc and TxIdle and leave TxOk disabled (since it 
+	 * occurs on every packet), but when no further irqs of this 
+	 * nature are expected, we must enable TxOk.
+	 */
+	if ((ISR_TXIDLE & isr) && (dev->tx_done_idx != dev->tx_free_idx)) {
+		spin_lock_irq(&dev->misc_lock);
+		dev->IMR_cache |= ISR_TXOK;
+		writel(dev->IMR_cache, dev->base + IMR);
+		spin_unlock_irq(&dev->misc_lock);
+	}
+
+	/* MIB interrupt: one of the statistics counters is about to overflow */
 	if (unlikely(ISR_MIB & isr))
 		ns83820_mib_isr(dev);
 
+	/* PHY: Link up/down/negotiation state change */
 	if (unlikely(ISR_PHY & isr))
 		phy_intr(dev);
 
@@ -1289,6 +1366,7 @@
 	struct ns83820 *dev = (struct ns83820 *)_dev;
 
 	/* FIXME: protect against interrupt handler? */
+	del_timer_sync(&dev->tx_watchdog);
 
 	/* disable interrupts */
 	writel(0, dev->base + IMR);
@@ -1302,13 +1380,76 @@
 
 	synchronize_irq();
 
+	spin_lock_irq(&dev->misc_lock);
 	dev->IMR_cache &= ~(ISR_TXURN | ISR_TXIDLE | ISR_TXERR | ISR_TXDESC | ISR_TXOK);
+	spin_unlock_irq(&dev->misc_lock);
+
 	ns83820_cleanup_rx(dev);
 	ns83820_cleanup_tx(dev);
 
 	return 0;
 }
 
+static void ns83820_do_isr(struct ns83820 *dev, u32 isr);
+static void ns83820_tx_timeout(struct net_device *_dev)
+{
+	struct ns83820 *dev = (struct ns83820 *)_dev;
+        u32 tx_done_idx, *desc;
+	long flags;
+
+	__save_flags(flags);
+	__cli();
+
+	tx_done_idx = dev->tx_done_idx;
+	desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
+
+	printk(KERN_INFO "%s: tx_timeout: tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
+		dev->net_dev.name,
+		tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS]));
+
+#if defined(DEBUG)
+	{
+		u32 isr;
+		isr = readl(dev->base + ISR);
+		printk("irq: %08x imr: %08x\n", isr, dev->IMR_cache);
+		ns83820_do_isr(dev, isr);
+	}
+#endif
+
+	do_tx_done(dev);
+
+	tx_done_idx = dev->tx_done_idx;
+	desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
+
+	printk(KERN_INFO "%s: after: tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
+		dev->net_dev.name,
+		tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS]));
+
+	__restore_flags(flags);
+}
+
+static void ns83820_tx_watch(unsigned long data)
+{
+	struct ns83820 *dev = (void *)data;
+
+#if defined(DEBUG)
+	printk("ns83820_tx_watch: %u %u %d\n",
+		dev->tx_done_idx, dev->tx_free_idx, atomic_read(&dev->nr_tx_skbs)
+		);
+#endif
+
+	if (time_after(jiffies, dev->net_dev.trans_start + 1*HZ) &&
+	    dev->tx_done_idx != dev->tx_free_idx) {
+		printk(KERN_DEBUG "%s: ns83820_tx_watch: %u %u %d\n",
+			dev->net_dev.name,
+			dev->tx_done_idx, dev->tx_free_idx,
+			atomic_read(&dev->nr_tx_skbs));
+		ns83820_tx_timeout(&dev->net_dev);
+	}
+
+	mod_timer(&dev->tx_watchdog, jiffies + 2*HZ);
+}
+
 static int ns83820_open(struct net_device *_dev)
 {
 	struct ns83820 *dev = (struct ns83820 *)_dev;
@@ -1326,7 +1467,7 @@
 
 	memset(dev->tx_descs, 0, 4 * NR_TX_DESC * DESC_SIZE);
 	for (i=0; i<NR_TX_DESC; i++) {
-		dev->tx_descs[(i * DESC_SIZE) + LINK]
+		dev->tx_descs[(i * DESC_SIZE) + DESC_LINK]
 				= cpu_to_le32(
 				  dev->tx_phy_descs
 				  + ((i+1) % NR_TX_DESC) * DESC_SIZE * 4);
@@ -1338,9 +1479,11 @@
 	writel(0, dev->base + TXDP_HI);
 	writel(desc, dev->base + TXDP);
 
-//printk("IMR: %08x / %08x\n", readl(dev->base + IMR), dev->IMR_cache);
+	init_timer(&dev->tx_watchdog);
+	dev->tx_watchdog.data = (unsigned long)dev;
+	dev->tx_watchdog.function = ns83820_tx_watch;
+	mod_timer(&dev->tx_watchdog, jiffies + 2*HZ);
 
-	set_bit(0, &dev->tx_idle);
 	netif_start_queue(&dev->net_dev);	/* FIXME: wait for phy to come up */
 
 	return 0;
@@ -1350,15 +1493,6 @@
 	return ret;
 }
 
-#if 0	/* FIXME: implement this! */
-static void ns83820_tx_timeout(struct net_device *_dev)
-{
-	struct ns83820 *dev = (struct ns83820 *)_dev;
-
-	printk("ns83820_tx_timeout\n");
-}
-#endif
-
 static void ns83820_getmac(struct ns83820 *dev, u8 *mac)
 {
 	unsigned i;
@@ -1392,6 +1526,7 @@
 	u8 *rfcr = dev->base + RFCR;
 	u32 and_mask = 0xffffffff;
 	u32 or_mask = 0;
+	u32 val;
 
 	if (dev->net_dev.flags & IFF_PROMISC)
 		or_mask |= RFCR_AAU | RFCR_AAM;
@@ -1404,10 +1539,225 @@
 		and_mask &= ~RFCR_AAM;
 
 	spin_lock_irq(&dev->misc_lock);
-	writel((readl(rfcr) & and_mask) | or_mask, rfcr);
+	val = (readl(rfcr) & and_mask) | or_mask;
+	/* Ramit : RFCR Write Fix doc says RFEN must be 0 modify other bits */
+	writel(val & ~RFCR_RFEN, rfcr);
+	writel(val, rfcr);
 	spin_unlock_irq(&dev->misc_lock);
 }
 
+static void ns83820_run_bist(struct ns83820 *dev, const char *name, u32 enable, u32 done, u32 fail)
+{
+	int timed_out = 0;
+	long start;
+	u32 status;
+	int loops = 0;
+
+	dprintk("%s: start %s\n", dev->net_dev.name, name);
+
+	start = jiffies;
+
+	writel(enable, dev->base + PTSCR);
+	for (;;) {
+		loops++;
+		status = readl(dev->base + PTSCR);
+		if (!(status & enable))
+			break;
+		if (status & done)
+			break;
+		if (status & fail)
+			break;
+		if ((jiffies - start) >= HZ) {
+			timed_out = 1;
+			break;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+
+	if (status & fail)
+		printk(KERN_INFO "%s: %s failed! (0x%08x & 0x%08x)\n",
+			dev->net_dev.name, name, status, fail);
+	else if (timed_out)
+		printk(KERN_INFO "%s: run_bist %s timed out! (%08x)\n",
+			dev->net_dev.name, name, status);
+
+	dprintk("%s: done %s in %d loops\n", dev->net_dev.name, name, loops);
+}
+
+static void ns83820_mii_write_bit(struct ns83820 *dev, int bit)
+{
+	/* drive MDC low */
+	dev->MEAR_cache &= ~MEAR_MDC;
+	writel(dev->MEAR_cache, dev->base + MEAR);
+	readl(dev->base + MEAR);
+
+	/* enable output, set bit */
+	dev->MEAR_cache |= MEAR_MDDIR;
+	if (bit)
+		dev->MEAR_cache |= MEAR_MDIO;
+	else
+		dev->MEAR_cache &= ~MEAR_MDIO;
+
+	/* set the output bit */
+	writel(dev->MEAR_cache, dev->base + MEAR);
+	readl(dev->base + MEAR);
+
+	/* Wait.  Max clock rate is 2.5MHz, this way we come in under 1MHz */
+	udelay(1);
+
+	/* drive MDC high causing the data bit to be latched */
+	dev->MEAR_cache |= MEAR_MDC;
+	writel(dev->MEAR_cache, dev->base + MEAR);
+	readl(dev->base + MEAR);
+
+	/* Wait again... */
+	udelay(1);
+}
+
+static int ns83820_mii_read_bit(struct ns83820 *dev)
+{
+	int bit;
+
+	/* drive MDC low, disable output */
+	dev->MEAR_cache &= ~MEAR_MDC;
+	dev->MEAR_cache &= ~MEAR_MDDIR;
+	writel(dev->MEAR_cache, dev->base + MEAR);
+	readl(dev->base + MEAR);
+
+	/* Wait.  Max clock rate is 2.5MHz, this way we come in under 1MHz */
+	udelay(1);
+
+	/* drive MDC high causing the data bit to be latched */
+	bit = (readl(dev->base + MEAR) & MEAR_MDIO) ? 1 : 0;
+	dev->MEAR_cache |= MEAR_MDC;
+	writel(dev->MEAR_cache, dev->base + MEAR);
+
+	/* Wait again... */
+	udelay(1);
+
+	return bit;
+}
+
+static unsigned ns83820_mii_read_reg(struct ns83820 *dev, unsigned phy, unsigned reg)
+{
+	unsigned data = 0;
+	int i;
+
+	/* read some garbage so that we eventually sync up */
+	for (i=0; i<64; i++)
+		ns83820_mii_read_bit(dev);
+
+	ns83820_mii_write_bit(dev, 0);	/* start */
+	ns83820_mii_write_bit(dev, 1);
+	ns83820_mii_write_bit(dev, 1);	/* opcode read */
+	ns83820_mii_write_bit(dev, 0);
+
+	/* write out the phy address: 5 bits, msb first */
+	for (i=0; i<5; i++)
+		ns83820_mii_write_bit(dev, phy & (0x10 >> i));
+
+	/* write out the register address, 5 bits, msb first */
+	for (i=0; i<5; i++)
+		ns83820_mii_write_bit(dev, reg & (0x10 >> i));
+
+	ns83820_mii_read_bit(dev);	/* turn around cycles */
+	ns83820_mii_read_bit(dev);
+
+	/* read in the register data, 16 bits msb first */
+	for (i=0; i<16; i++) {
+		data <<= 1;
+		data |= ns83820_mii_read_bit(dev);
+	}
+
+	return data;
+}
+
+static unsigned ns83820_mii_write_reg(struct ns83820 *dev, unsigned phy, unsigned reg, unsigned data)
+{
+	int i;
+
+	/* read some garbage so that we eventually sync up */
+	for (i=0; i<64; i++)
+		ns83820_mii_read_bit(dev);
+
+	ns83820_mii_write_bit(dev, 0);	/* start */
+	ns83820_mii_write_bit(dev, 1);
+	ns83820_mii_write_bit(dev, 0);	/* opcode read */
+	ns83820_mii_write_bit(dev, 1);
+
+	/* write out the phy address: 5 bits, msb first */
+	for (i=0; i<5; i++)
+		ns83820_mii_write_bit(dev, phy & (0x10 >> i));
+
+	/* write out the register address, 5 bits, msb first */
+	for (i=0; i<5; i++)
+		ns83820_mii_write_bit(dev, reg & (0x10 >> i));
+
+	ns83820_mii_read_bit(dev);	/* turn around cycles */
+	ns83820_mii_read_bit(dev);
+
+	/* read in the register data, 16 bits msb first */
+	for (i=0; i<16; i++)
+		ns83820_mii_write_bit(dev, (data >> (15 - i)) & 1);
+
+	return data;
+}
+
+static void ns83820_probe_phy(struct ns83820 *dev)
+{
+	static int first;
+	int i;
+#define MII_PHYIDR1	0x02
+#define MII_PHYIDR2	0x03
+
+#if 0
+	if (!first) {
+		unsigned tmp;
+		ns83820_mii_read_reg(dev, 1, 0x09);
+		ns83820_mii_write_reg(dev, 1, 0x10, 0x0d3e);
+
+		tmp = ns83820_mii_read_reg(dev, 1, 0x00);
+		ns83820_mii_write_reg(dev, 1, 0x00, tmp | 0x8000);
+		udelay(1300);
+		ns83820_mii_read_reg(dev, 1, 0x09);
+	}
+#endif
+	first = 1;
+
+	for (i=1; i<2; i++) {
+		int j;
+		unsigned a, b;
+		a = ns83820_mii_read_reg(dev, i, MII_PHYIDR1);
+		b = ns83820_mii_read_reg(dev, i, MII_PHYIDR2);
+
+		//printk("%s: phy %d: 0x%04x 0x%04x\n",
+		//	dev->net_dev.name, i, a, b);
+
+		for (j=0; j<0x16; j+=4) {
+			dprintk("%s: [0x%02x] %04x %04x %04x %04x\n",
+				dev->net_dev.name, j,
+				ns83820_mii_read_reg(dev, i, 0 + j),
+				ns83820_mii_read_reg(dev, i, 1 + j),
+				ns83820_mii_read_reg(dev, i, 2 + j),
+				ns83820_mii_read_reg(dev, i, 3 + j)
+				);
+		}
+	}
+	{
+		unsigned a, b;
+		/* read firmware version: memory addr is 0x8402 and 0x8403 */
+		ns83820_mii_write_reg(dev, 1, 0x16, 0x000d);
+		ns83820_mii_write_reg(dev, 1, 0x1e, 0x810e);
+		a = ns83820_mii_read_reg(dev, 1, 0x1d);
+
+		ns83820_mii_write_reg(dev, 1, 0x16, 0x000d);
+		ns83820_mii_write_reg(dev, 1, 0x1e, 0x810e);
+		b = ns83820_mii_read_reg(dev, 1, 0x1d);
+		dprintk("version: 0x%04x 0x%04x\n", a, b);
+	}
+}
+
 static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_device_id *id)
 {
 	struct ns83820 *dev;
@@ -1415,6 +1765,7 @@
 	int err;
 	int using_dac = 0;
 
+	/* See if we can set the dma mask early on; failure is fatal. */
 	if (TRY_DAC && !pci_set_dma_mask(pci_dev, 0xffffffffffffffff)) {
 		using_dac = 1;
 	} else if (!pci_set_dma_mask(pci_dev, 0xffffffff)) {
@@ -1443,7 +1794,7 @@
 
 	err = pci_enable_device(pci_dev);
 	if (err) {
-		printk(KERN_INFO "ns83820: pci_enable_dev: %d\n", err);
+		printk(KERN_INFO "ns83820: pci_enable_dev failed: %d\n", err);
 		goto out_free;
 	}
 
@@ -1461,6 +1812,7 @@
 	dprintk("%p: %08lx  %p: %08lx\n",
 		dev->tx_descs, (long)dev->tx_phy_descs,
 		dev->rx_info.descs, (long)dev->rx_info.phy_descs);
+
 	/* disable interrupts */
 	writel(0, dev->base + IMR);
 	writel(0, dev->base + IER);
@@ -1479,45 +1831,47 @@
 		goto out_unmap;
 	}
 
-	if(register_netdev(&dev->net_dev)) goto out_unmap;
+	err = register_netdev(&dev->net_dev);
+	if (err) {
+		printk(KERN_INFO "ns83820: unable to register netdev: %d\n", err);
+		goto out_unmap;
+	}
+
+	printk("%s: ns83820.c: 0x22c: %08x, subsystem: %04x:%04x\n",
+		dev->net_dev.name, le32_to_cpu(readl(dev->base + 0x22c)),
+		pci_dev->subsystem_vendor, pci_dev->subsystem_device);
 
 	dev->net_dev.open = ns83820_open;
 	dev->net_dev.stop = ns83820_stop;
 	dev->net_dev.hard_start_xmit = ns83820_hard_start_xmit;
-	dev->net_dev.change_mtu = ns83820_change_mtu;
 	dev->net_dev.get_stats = ns83820_get_stats;
 	dev->net_dev.change_mtu = ns83820_change_mtu;
 	dev->net_dev.set_multicast_list = ns83820_set_multicast;
 	dev->net_dev.do_ioctl = ns83820_ioctl;
-	//FIXME: dev->net_dev.tx_timeout = ns83820_tx_timeout;
+	dev->net_dev.tx_timeout = ns83820_tx_timeout;
+	dev->net_dev.watchdog_timeo = 5 * HZ;
 
 	pci_set_drvdata(pci_dev, dev);
 
 	ns83820_do_reset(dev, CR_RST);
 
-	dprintk("start bist\n");
-	writel(PTSCR_EEBIST_EN, dev->base + PTSCR);
-	do {
-		schedule();
-	} while (readl(dev->base + PTSCR) & PTSCR_EEBIST_EN);
-	dprintk("done bist\n");
-
-	dprintk("start eeload\n");
-	writel(PTSCR_EELOAD_EN, dev->base + PTSCR);
-	do {
-		schedule();
-	} while (readl(dev->base + PTSCR) & PTSCR_EELOAD_EN);
-	dprintk("done eeload\n");
+	/* Must reset the ram bist before running it */
+	writel(PTSCR_RBIST_RST, dev->base + PTSCR);
+	ns83820_run_bist(dev, "sram bist",   PTSCR_RBIST_EN,
+			 PTSCR_RBIST_DONE, PTSCR_RBIST_FAIL);
+	ns83820_run_bist(dev, "eeprom bist", PTSCR_EEBIST_EN, 0,
+			 PTSCR_EEBIST_FAIL);
+	ns83820_run_bist(dev, "eeprom load", PTSCR_EELOAD_EN, 0, 0);
 
 	/* I love config registers */
 	dev->CFG_cache = readl(dev->base + CFG);
 
 	if ((dev->CFG_cache & CFG_PCI64_DET)) {
-		printk("%s: detected 64 bit PCI data bus.\n",
+		printk(KERN_INFO "%s: detected 64 bit PCI data bus.\n",
 			dev->net_dev.name);
 		/*dev->CFG_cache |= CFG_DATA64_EN;*/
 		if (!(dev->CFG_cache & CFG_DATA64_EN))
-			printk("%s: EEPROM did not enable 64 bit bus.  Disabled.\n",
+			printk(KERN_INFO "%s: EEPROM did not enable 64 bit bus.  Disabled.\n",
 				dev->net_dev.name);
 	} else
 		dev->CFG_cache &= ~(CFG_DATA64_EN);
@@ -1529,6 +1883,11 @@
 			  CFG_EXTSTS_EN   | CFG_EXD         | CFG_PESEL;
 	dev->CFG_cache |= CFG_REQALG;
 	dev->CFG_cache |= CFG_POW;
+	dev->CFG_cache |= CFG_TMRTEST;
+
+	/* When compiled with 64 bit addressing, we must always enable
+	 * the 64 bit descriptor format.
+	 */
 #ifdef USE_64BIT_ADDR
 	dev->CFG_cache |= CFG_M64ADDR;
 #endif
@@ -1540,7 +1899,8 @@
 
 	/* setup optical transceiver if we have one */
 	if (dev->CFG_cache & CFG_TBI_EN) {
-		printk("%s: enabling optical transceiver\n", dev->net_dev.name);
+		printk(KERN_INFO "%s: enabling optical transceiver\n",
+			dev->net_dev.name);
 		writel(readl(dev->base + GPIOR) | 0x3e8, dev->base + GPIOR);
 
 		/* setup auto negotiation feature advertisement */
@@ -1560,6 +1920,14 @@
 	writel(dev->CFG_cache, dev->base + CFG);
 	dprintk("CFG: %08x\n", dev->CFG_cache);
 
+	if (reset_phy) {
+		printk(KERN_INFO "%s: resetting phy\n", dev->net_dev.name);
+		writel(dev->CFG_cache | CFG_PHY_RST, dev->base + CFG);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((HZ+99)/100);
+		writel(dev->CFG_cache, dev->base + CFG);
+	}
+
 #if 0	/* Huh?  This sets the PCI latency register.  Should be done via 
 	 * the PCI layer.  FIXME.
 	 */
@@ -1572,7 +1940,9 @@
 	 * can be transmitted is 8192 - FLTH - burst size.
 	 * If only the transmit fifo was larger...
 	 */
-	writel(TXCFG_CSI | TXCFG_HBI | TXCFG_ATP | TXCFG_MXDMA1024
+	/* Ramit : 1024 DMA is not a good idea, it ends up banging 
+	 * some DELL and COMPAQ SMP systems */
+	writel(TXCFG_CSI | TXCFG_HBI | TXCFG_ATP | TXCFG_MXDMA512
 		| ((1600 / 32) * 0x100),
 		dev->base + TXCFG);
 
@@ -1582,12 +1952,15 @@
 	writel(0x000, dev->base + IHR);
 
 	/* Set Rx to full duplex, don't accept runt, errored, long or length
-	 * range errored packets.  Set MXDMA to 0 => 1024 word burst
+	 * range errored packets.  Use 512 byte DMA.
 	 */
+	/* Ramit : 1024 DMA is not a good idea, it ends up banging 
+	 * some DELL and COMPAQ SMP systems 
+	 * Turn on ALP, only we are accpeting Jumbo Packets */
 	writel(RXCFG_AEP | RXCFG_ARP | RXCFG_AIRL | RXCFG_RX_FD
 		| RXCFG_STRIPCRC
-		| RXCFG_ALP
-		| (RXCFG_MXDMA0 * 0) | 0, dev->base + RXCFG);
+		//| RXCFG_ALP
+		| (RXCFG_MXDMA512) | 0, dev->base + RXCFG);
 
 	/* Disable priority queueing */
 	writel(0, dev->base + PQCR);
@@ -1597,13 +1970,23 @@
 	 * revision of the chip does not properly accept IP fragments
 	 * at least for UDP.
 	 */
+	/* Ramit : Be sure to turn on RXCFG_ARP if VLAN's are enabled, since
+	 * the MAC it calculates the packetsize AFTER stripping the VLAN
+	 * header, and if a VLAN Tagged packet of 64 bytes is received (like
+	 * a ping with a VLAN header) then the card, strips the 4 byte VLAN
+	 * tag and then checks the packet size, so if RXCFG_ARP is not enabled,
+	 * it discrards it!.  These guys......
+	 */
 	writel(VRCR_IPEN | VRCR_VTDEN, dev->base + VRCR);
 
 	/* Enable per-packet TCP/UDP/IP checksumming */
 	writel(VTCR_PPCHK, dev->base + VTCR);
 
-	/* Disable Pause frames */
-	writel(0, dev->base + PCR);
+	/* Ramit : Enable async and sync pause frames */
+	/* writel(0, dev->base + PCR); */
+	writel((PCR_PS_MCAST | PCR_PS_DA | PCR_PSEN | PCR_FFLO_4K |
+		PCR_FFHI_8K | PCR_STLO_4 | PCR_STHI_8 | PCR_PAUSE_CNT),
+		dev->base + PCR);
 
 	/* Disable Wake On Lan */
 	writel(0, dev->base + WCSR);
@@ -1631,6 +2014,10 @@
 		(dev->net_dev.features & NETIF_F_HIGHDMA) ? "h,sg" : "sg"
 		);
 
+#ifdef PHY_CODE_IS_FINISHED
+	ns83820_probe_phy(dev);
+#endif
+
 	return 0;
 
 out_unmap:
@@ -1670,7 +2057,7 @@
 }
 
 static struct pci_device_id ns83820_pci_tbl[] __devinitdata = {
-	{ 0x100b, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{ 0x100b, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, .driver_data = 0, },
 	{ 0, },
 };
 
@@ -1703,5 +2090,14 @@
 
 MODULE_DEVICE_TABLE(pci, ns83820_pci_tbl);
 
+MODULE_PARM(lnksts, "i");
+MODULE_PARM_DESC(lnksts, "Polarity of LNKSTS bit");
+
+MODULE_PARM(ihr, "i");
+MODULE_PARM_DESC(ihr, "Time in 100 us increments to delay interrupts (range 0-127)");
+
+MODULE_PARM(reset_phy, "i");
+MODULE_PARM_DESC(reset_phy, "Set to 1 to reset the PHY on startup");
+
 module_init(ns83820_init);
 module_exit(ns83820_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pci-skeleton.c linux-2.4.20/drivers/net/pci-skeleton.c
--- linux-2.4.19/drivers/net/pci-skeleton.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/pci-skeleton.c	2002-10-29 11:18:31.000000000 +0000
@@ -1411,10 +1411,6 @@
 				tp->stats.tx_carrier_errors++;
 			if (txstatus & TxOutOfWindow)
 				tp->stats.tx_window_errors++;
-#ifdef ETHER_STATS
-			if ((txstatus & 0x0f000000) == 0x0f000000)
-				tp->stats.collisions16++;
-#endif
 		} else {
 			if (txstatus & TxUnderrun) {
 				/* Add 64 to the Tx FIFO threshold. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pcmcia/3c574_cs.c linux-2.4.20/drivers/net/pcmcia/3c574_cs.c
--- linux-2.4.19/drivers/net/pcmcia/3c574_cs.c	2001-11-13 17:02:30.000000000 +0000
+++ linux-2.4.20/drivers/net/pcmcia/3c574_cs.c	2002-10-29 11:18:34.000000000 +0000
@@ -86,6 +86,8 @@
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/ioport.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -1189,6 +1191,26 @@
 	return worklimit;
 }
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "3c574_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
 /* Provide ioctl() calls to examine the MII xcvr state. */
 static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
@@ -1202,12 +1224,14 @@
 		  data[0], data[1], data[2], data[3]);
 
     switch(cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *)rq->ifr_data);
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 		data[0] = phy;
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
 		{
 			int saved_window;
-			long flags;
+			unsigned long flags;
 
 			save_flags(flags);
 			cli();
@@ -1221,7 +1245,7 @@
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
 		{
 			int saved_window;
-			long flags;
+			unsigned long flags;
 
 			if (!capable(CAP_NET_ADMIN))
 				return -EPERM;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pcmcia/aironet4500_cs.c linux-2.4.20/drivers/net/pcmcia/aironet4500_cs.c
--- linux-2.4.19/drivers/net/pcmcia/aironet4500_cs.c	2002-02-25 19:37:59.000000000 +0000
+++ linux-2.4.20/drivers/net/pcmcia/aironet4500_cs.c	2002-10-29 11:18:32.000000000 +0000
@@ -347,7 +347,7 @@
 static void awc_detach(dev_link_t *link)
 {
 	dev_link_t **linkp;
-	long flags;
+	unsigned long flags;
 	int i=0;
 
 	DEBUG(0, "awc_detach(0x%p)\n", link);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pcmcia/axnet_cs.c linux-2.4.20/drivers/net/pcmcia/axnet_cs.c
--- linux-2.4.19/drivers/net/pcmcia/axnet_cs.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.20/drivers/net/pcmcia/axnet_cs.c	2002-10-29 11:18:31.000000000 +0000
@@ -11,8 +11,8 @@
 
     Copyright (C) 2001 David A. Hinds -- dahinds@users.sourceforge.net
 
-    axnet_cs.c 1.24 2001/11/18 02:46:51
-    
+    axnet_cs.c 1.28 2002/06/29 06:27:37
+
     The network driver code is based on Donald Becker's NE2000 code:
 
     Written 1992,1993 by Donald Becker.
@@ -34,9 +34,11 @@
 #include <linux/timer.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
+#include <linux/ethtool.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
+#include <asm/uaccess.h>
 
 #include <linux/netdevice.h>
 #include "../8390.h"
@@ -53,12 +55,17 @@
 #define AXNET_DATAPORT	0x10	/* NatSemi-defined port window offset. */
 #define AXNET_RESET	0x1f	/* Issue a read to reset, a write to clear. */
 #define AXNET_MII_EEP	0x14	/* Offset of MII access port */
+#define AXNET_TEST	0x15	/* Offset of TEST Register port */
+#define AXNET_GPIO	0x17	/* Offset of General Purpose Register Port */
 
 #define AXNET_START_PG	0x40	/* First page of TX buffer */
 #define AXNET_STOP_PG	0x80	/* Last page +1 of RX ring */
 
 #define AXNET_RDC_TIMEOUT 0x02	/* Max wait in jiffies for Tx RDC */
 
+#define IS_AX88190	0x0001
+#define IS_AX88790	0x0002
+
 /*====================================================================*/
 
 /* Module parameters */
@@ -78,7 +85,7 @@
 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"axnet_cs.c 1.24 2001/11/18 02:46:51 (David Hinds)";
+"axnet_cs.c 1.28 2002/06/29 06:27:37 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -115,6 +122,7 @@
 static int axdev_init(struct net_device *dev);
 static void AX88190_init(struct net_device *dev, int startp);
 static int ax_open(struct net_device *dev);
+static int ax_close(struct net_device *dev);
 static void ax_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
 /*====================================================================*/
@@ -129,6 +137,7 @@
     u_short		link_status;
     u_char		duplex_flag;
     int			phy_id;
+    int			flags;
 } axnet_dev_t;
 
 /*======================================================================
@@ -473,17 +482,37 @@
 
     strcpy(info->node.dev_name, dev->name);
     link->dev = &info->node;
-    link->state &= ~DEV_CONFIG_PENDING;
 
-    printk(KERN_INFO "%s: Asix AX88190: io %#3lx, irq %d, hw_addr ",
-	   dev->name, dev->base_addr, dev->irq);
+    if (inb(dev->base_addr + AXNET_TEST) != 0)
+	info->flags |= IS_AX88790;
+    else
+	info->flags |= IS_AX88190;
+
+    printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, hw_addr ",
+	   dev->name, ((info->flags & IS_AX88790) ? 7 : 1),
+	   dev->base_addr, dev->irq);
     for (i = 0; i < 6; i++)
 	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
 
+    if (info->flags & IS_AX88790)
+	outb(0x10, dev->base_addr + AXNET_GPIO);  /* select Internal PHY */
+
     for (i = 0; i < 32; i++) {
 	j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
 	if ((j != 0) && (j != 0xffff)) break;
     }
+
+    /* Maybe PHY is in power down mode. (PPD_SET = 1) 
+       Bit 2 of CCSR is active low. */ 
+    if (i == 32) {
+	conf_reg_t reg = { 0, CS_WRITE, CISREG_CCSR, 0x04 };
+ 	CardServices(AccessConfigurationRegister, link->handle, &reg);
+	for (i = 0; i < 32; i++) {
+	    j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
+	    if ((j != 0) && (j != 0xffff)) break;
+	}
+    }
+
     info->phy_id = (i < 32) ? i : -1;
     if (i < 32) {
 	DEBUG(0, "  MII transceiver at index %d, status %x.\n", i, j);
@@ -491,12 +520,14 @@
 	printk(KERN_NOTICE "  No MII transceivers found!\n");
     }
 
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
 
 cs_failed:
     cs_error(link->handle, last_fn, last_ret);
 failed:
     axnet_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
 } /* axnet_config */
 
@@ -555,7 +586,7 @@
 	}
 	break;
     case CS_EVENT_CARD_INSERTION:
-	link->state |= DEV_PRESENT;
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
 	axnet_config(link);
 	break;
     case CS_EVENT_PM_SUSPEND:
@@ -678,6 +709,7 @@
 
     DEBUG(2, "axnet_close('%s')\n", dev->name);
 
+    ax_close(dev);
     free_irq(dev->irq, dev);
     
     link->open--;
@@ -790,6 +822,26 @@
     add_timer(&info->watchdog);
 }
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "axnet_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
 /*====================================================================*/
 
 static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -798,6 +850,8 @@
     u16 *data = (u16 *)&rq->ifr_data;
     ioaddr_t mii_addr = dev->base_addr + AXNET_MII_EEP;
     switch (cmd) {
+    case SIOCETHTOOL:
+        return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
     case SIOCDEVPRIVATE:
 	data[0] = info->phy_id;
     case SIOCDEVPRIVATE+1:
@@ -888,7 +942,7 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "axnet_cs: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &axnet_attach, &axnet_detach);
     return 0;
@@ -1079,6 +1133,29 @@
 	return 0;
 }
 
+#define dev_lock(dev) (((struct ei_device *)(dev)->priv)->page_lock)
+
+/**
+ * ax_close - shut down network device
+ * @dev: network device to close
+ *
+ * Opposite of ax_open(). Only used when "ifconfig <devname> down" is done.
+ */
+int ax_close(struct net_device *dev)
+{
+	unsigned long flags;
+
+	/*
+	 *      Hold the page lock during close
+	 */
+
+	spin_lock_irqsave(&dev_lock(dev), flags);
+	AX88190_init(dev, 0);
+	spin_unlock_irqrestore(&dev_lock(dev), flags);
+	netif_stop_queue(dev);
+	return 0;
+}
+
 /**
  * ei_tx_timeout - handle transmit time out condition
  * @dev: network device which has apparently fallen asleep
@@ -1734,8 +1811,6 @@
  *	not called too often. Must protect against both bh and irq users
  */
 
-#define dev_lock(dev) (((struct ei_device *)(dev)->priv)->page_lock)
-
 static void set_multicast_list(struct net_device *dev)
 {
 	unsigned long flags;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pcmcia/fmvj18x_cs.c linux-2.4.20/drivers/net/pcmcia/fmvj18x_cs.c
--- linux-2.4.19/drivers/net/pcmcia/fmvj18x_cs.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/pcmcia/fmvj18x_cs.c	2002-10-29 11:18:33.000000000 +0000
@@ -362,7 +362,7 @@
     if (*linkp == NULL)
 	return;
 
-    del_timer(&link->release);
+    del_timer_sync(&link->release);
     if (link->state & DEV_CONFIG) {
 	fmvj18x_release((u_long)link);
 	if (link->state & DEV_STALE_CONFIG) {
@@ -571,8 +571,7 @@
     case XXX10304:
 	/* Read MACID from Buggy CIS */
 	if (fmvj18x_get_hwinfo(link, tuple.TupleData) == -1) {
-	    printk(KERN_NOTICE "fmvj18x_cs: unable to read hardware net 
-		address.");
+	    printk(KERN_NOTICE "fmvj18x_cs: unable to read hardware net address.\n");
 	    unregister_netdev(dev);
 	    goto failed;
 	}
@@ -1254,7 +1253,7 @@
     ioaddr_t ioaddr = dev->base_addr;
     struct local_info_t *lp = (struct local_info_t *)dev->priv;
     unsigned char mc_filter[8];		 /* Multicast hash filter */
-    long flags;
+    unsigned long flags;
     int i;
     
     if (dev->flags & IFF_PROMISC) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pcmcia/ibmtr_cs.c linux-2.4.20/drivers/net/pcmcia/ibmtr_cs.c
--- linux-2.4.19/drivers/net/pcmcia/ibmtr_cs.c	2001-09-30 19:26:07.000000000 +0000
+++ linux-2.4.20/drivers/net/pcmcia/ibmtr_cs.c	2002-10-29 11:18:48.000000000 +0000
@@ -53,6 +53,8 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/module.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
 
@@ -164,6 +166,37 @@
     CardServices(ReportError, handle, &err);
 }
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "ibmtr_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
+static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+
+       switch(cmd) {
+       case SIOCETHTOOL:
+	       return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+	default:
+	    return -EOPNOTSUPP;
+	}
+}
+
 /*======================================================================
 
     ibmtr_attach() creates an "instance" of the driver, allocating
@@ -216,6 +249,7 @@
     link->irq.Instance = info->dev = dev;
     
     dev->init = &ibmtr_probe;
+    dev->do_ioctl = &private_ioctl;
 
     /* Register with Card Services */
     link->next = dev_list;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pcmcia/nmclan_cs.c linux-2.4.20/drivers/net/pcmcia/nmclan_cs.c
--- linux-2.4.19/drivers/net/pcmcia/nmclan_cs.c	2002-02-25 19:37:59.000000000 +0000
+++ linux-2.4.20/drivers/net/pcmcia/nmclan_cs.c	2002-10-29 11:18:33.000000000 +0000
@@ -437,8 +437,8 @@
 static struct net_device_stats *mace_get_stats(struct net_device *dev);
 static int mace_rx(struct net_device *dev, unsigned char RxCnt);
 static void restore_multicast_list(struct net_device *dev);
-
 static void set_multicast_list(struct net_device *dev);
+static int mace_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 
 static dev_link_t *nmclan_attach(void);
 static void nmclan_detach(dev_link_t *);
@@ -520,6 +520,7 @@
     dev->set_config = &mace_config;
     dev->get_stats = &mace_get_stats;
     dev->set_multicast_list = &set_multicast_list;
+    dev->do_ioctl = &mace_ioctl;
     ether_setup(dev);
     dev->open = &mace_open;
     dev->stop = &mace_close;
@@ -1057,7 +1058,7 @@
 	return -EOPNOTSUPP;
 }
 
-static int smc91c92_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int mace_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	switch (cmd) {
 	case SIOCETHTOOL:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pcmcia/pcnet_cs.c linux-2.4.20/drivers/net/pcmcia/pcnet_cs.c
--- linux-2.4.19/drivers/net/pcmcia/pcnet_cs.c	2001-11-13 17:02:30.000000000 +0000
+++ linux-2.4.20/drivers/net/pcmcia/pcnet_cs.c	2002-10-29 11:18:35.000000000 +0000
@@ -11,7 +11,7 @@
 
     Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
 
-    pcnet_cs.c 1.144 2001/11/07 04:06:56
+    pcnet_cs.c 1.149 2002/06/29 06:27:37
     
     The network driver code is based on Donald Becker's NE2000 code:
 
@@ -37,9 +37,11 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/delay.h>
+#include <linux/ethtool.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
+#include <asm/uaccess.h>
 
 #include <linux/netdevice.h>
 #include <../drivers/net/8390.h>
@@ -64,7 +66,7 @@
 #define SOCKET_START_PG	0x01
 #define SOCKET_STOP_PG	0xff
 
-#define PCNET_RDC_TIMEOUT 0x02	/* Max wait in jiffies for Tx RDC */
+#define PCNET_RDC_TIMEOUT (2*HZ/100)	/* Max wait in jiffies for Tx RDC */
 
 static char *if_names[] = { "auto", "10baseT", "10base2"};
 
@@ -73,7 +75,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"pcnet_cs.c 1.144 2001/11/07 04:06:56 (David Hinds)";
+"pcnet_cs.c 1.149 2002/06/29 06:27:37 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -115,6 +117,7 @@
 static int pcnet_open(struct net_device *dev);
 static int pcnet_close(struct net_device *dev);
 static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int do_ioctl_light(struct net_device *dev, struct ifreq *rq, int cmd);
 static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs);
 static void ei_watchdog(u_long arg);
 static void pcnet_reset_8390(struct net_device *dev);
@@ -762,18 +765,21 @@
 
     strcpy(info->node.dev_name, dev->name);
     link->dev = &info->node;
-    link->state &= ~DEV_CONFIG_PENDING;
 
     if (info->flags & (IS_DL10019|IS_DL10022)) {
 	u_char id = inb(dev->base_addr + 0x1a);
 	dev->do_ioctl = &ei_ioctl;
 	mii_phy_probe(dev);
+	if ((id == 0x30) && !info->pna_phy && (info->eth_phy == 4))
+	    info->eth_phy = 0;
 	printk(KERN_INFO "%s: NE2000 (DL100%d rev %02x): ",
 	       dev->name, ((info->flags & IS_DL10022) ? 22 : 19), id);
 	if (info->pna_phy)
 	    printk("PNA, ");
-    } else
+    } else {
 	printk(KERN_INFO "%s: NE2000 Compatible: ", dev->name);
+ 	dev->do_ioctl = &do_ioctl_light;	
+    }
     printk("io %#3lx, irq %d,", dev->base_addr, dev->irq);
     if (info->flags & USE_SHMEM)
 	printk (" mem %#5lx,", dev->mem_start);
@@ -782,12 +788,14 @@
     printk(" hw_addr ");
     for (i = 0; i < 6; i++)
 	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
 
 cs_failed:
     cs_error(link->handle, last_fn, last_ret);
 failed:
     pcnet_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
 } /* pcnet_config */
 
@@ -851,7 +859,7 @@
 	}
 	break;
     case CS_EVENT_CARD_INSERTION:
-	link->state |= DEV_PRESENT;
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
 	pcnet_config(link);
 	break;
     case CS_EVENT_PM_SUSPEND:
@@ -1046,6 +1054,7 @@
 
     DEBUG(2, "pcnet_close('%s')\n", dev->name);
 
+    ei_close(dev);
     free_irq(dev->irq, dev);
     
     link->open--;
@@ -1183,7 +1192,7 @@
 	}
 	info->link_status = link;
     }
-    if (info->pna_phy && (jiffies - info->mii_reset > 6*HZ)) {
+    if (info->pna_phy && time_after(jiffies, info->mii_reset + 6*HZ)) {
 	link = mdio_read(mii_addr, info->eth_phy, 1) & 0x0004;
 	if (((info->phy_id == info->pna_phy) && link) ||
 	    ((info->phy_id != info->pna_phy) && !link)) {
@@ -1206,12 +1215,37 @@
 
 /*====================================================================*/
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+	
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "pcnet_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
+/*====================================================================*/
+
+
 static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
     pcnet_dev_t *info = (pcnet_dev_t *)dev;
     u16 *data = (u16 *)&rq->ifr_data;
     ioaddr_t mii_addr = dev->base_addr + DLINK_GPIO;
     switch (cmd) {
+    case SIOCETHTOOL:
+        return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
     case SIOCDEVPRIVATE:
 	data[0] = info->phy_id;
     case SIOCDEVPRIVATE+1:
@@ -1228,6 +1262,17 @@
 
 /*====================================================================*/
 
+static int do_ioctl_light(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+    switch (cmd) {
+        case SIOCETHTOOL:
+            return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+    }	    
+    return -EOPNOTSUPP;    
+}
+
+/*====================================================================*/
+
 static void dma_get_8390_hdr(struct net_device *dev,
 			     struct e8390_pkt_hdr *hdr,
 			     int ring_page)
@@ -1385,7 +1430,7 @@
 #endif
 
     while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
-	if (jiffies - dma_start > PCNET_RDC_TIMEOUT) {
+	if (time_after(jiffies, dma_start + PCNET_RDC_TIMEOUT)) {
 	    printk(KERN_NOTICE "%s: timeout waiting for Tx RDC.\n",
 		   dev->name);
 	    pcnet_reset_8390(dev);
@@ -1579,7 +1624,7 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "pcnet_cs: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &pcnet_attach, &pcnet_detach);
     return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pcmcia/ray_cs.c linux-2.4.20/drivers/net/pcmcia/ray_cs.c
--- linux-2.4.19/drivers/net/pcmcia/ray_cs.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/pcmcia/ray_cs.c	2002-10-29 11:18:38.000000000 +0000
@@ -2,7 +2,7 @@
  *
  * A  PCMCIA client driver for the Raylink wireless LAN card.
  * The starting point for this module was the skeleton.c in the
- * PCMCIA 2.9.12 package written by David Hinds, dhinds@allegro.stanford.edu
+ * PCMCIA 2.9.12 package written by David Hinds, dahinds@users.sourceforge.net
  *
  *
  * Copyright (c) 1998  Corey Thomas (corey@world.std.com)
@@ -48,6 +48,8 @@
 #include <linux/if_arp.h>
 #include <linux/ioport.h>
 #include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -1224,7 +1226,32 @@
         }
     }
 } /* end encapsulate_frame */
+
+
 /*===========================================================================*/
+
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "ray_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
+/*====================================================================*/
+
 static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
     ray_dev_t *local = (ray_dev_t *)dev->priv;
@@ -1242,6 +1269,10 @@
     /* Validate the command */
     switch (cmd)
     {
+    case SIOCETHTOOL:
+      err = netdev_ethtool_ioctl(dev, (void *) ifr->ifr_data);
+      break;
+
 #if WIRELESS_EXT > 7
       /* --------------- WIRELESS EXTENSIONS --------------- */
       /* Get name */
@@ -1316,9 +1347,12 @@
 		    err = -E2BIG;
 		    break;
 		}
-		copy_from_user(card_essid,
-			       wrq->u.data.pointer,
-			       wrq->u.data.length);
+		if (copy_from_user(card_essid,
+				   wrq->u.data.pointer,
+				   wrq->u.data.length)) {
+			err = -EFAULT;
+			break;
+		}
 		card_essid[IW_ESSID_MAX_SIZE] = '\0';
 
 		/* Set the ESSID in the card */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pcmcia/smc91c92_cs.c linux-2.4.20/drivers/net/pcmcia/smc91c92_cs.c
--- linux-2.4.19/drivers/net/pcmcia/smc91c92_cs.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/pcmcia/smc91c92_cs.c	2002-10-29 11:18:33.000000000 +0000
@@ -8,7 +8,7 @@
 
     Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
 
-    smc91c92_cs.c 1.113 2001/10/13 00:08:53
+    smc91c92_cs.c 1.2 2002/09/28 15:00:00
     
     This driver contains code written by Donald Becker
     (becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au),
@@ -37,12 +37,15 @@
 #include <linux/crc32.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/uaccess.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/ioport.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -88,6 +91,9 @@
 #define DEBUG(n, args...)
 #endif
 
+#define DRV_NAME	"smc91c92_cs"
+#define DRV_VERSION	"1.2"
+
 /*====================================================================*/
 
 /* Operational parameter that usually are not changed. */
@@ -109,6 +115,7 @@
 struct smc_private {
     dev_link_t			link;
     struct net_device		dev;
+    spinlock_t			lock;
     u_short			manfid;
     u_short			cardid;
     struct net_device_stats	stats;
@@ -122,7 +129,7 @@
     u_short			media_status;
     u_short			fast_poll;
     u_short			link_status;
-    int				phy_id;
+    struct mii_if_info		mii_if;
 };
 
 /* Special definitions for Megahertz multifunction cards */
@@ -292,9 +299,11 @@
 static void smc_set_xcvr(struct net_device *dev, int if_port);
 static void smc_reset(struct net_device *dev);
 static void media_check(u_long arg);
-static void mdio_sync(ioaddr_t addr);
-static int mdio_read(ioaddr_t addr, int phy_id, int loc);
-static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value);
+static void smc_mdio_sync(ioaddr_t addr);
+static int smc_mdio_read(struct net_device *dev, int phy_id, int loc);
+static void smc_mdio_write(struct net_device *dev, int phy_id, int loc, int value);
+static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int smc_link_ok(struct net_device *dev);
 
 /*======================================================================
 
@@ -346,7 +355,7 @@
     if (!smc) return NULL;
     memset(smc, 0, sizeof(struct smc_private));
     link = &smc->link; dev = &smc->dev;
-
+    spin_lock_init(&smc->lock);
     link->release.function = &smc91c92_release;
     link->release.data = (u_long)link;
     link->io.NumPorts1 = 16;
@@ -369,6 +378,7 @@
     dev->get_stats = &smc91c92_get_stats;
     dev->set_config = &s9k_config;
     dev->set_multicast_list = &set_rx_mode;
+    dev->do_ioctl = &smc_ioctl;
     ether_setup(dev);
     dev->open = &smc91c92_open;
     dev->stop = &smc91c92_close;
@@ -377,6 +387,12 @@
     dev->watchdog_timeo = TX_TIMEOUT;
 #endif
     dev->priv = link->priv = link->irq.Instance = smc;
+   
+    smc->mii_if.dev = dev;
+    smc->mii_if.mdio_read = smc_mdio_read;
+    smc->mii_if.mdio_write = smc_mdio_write;
+    smc->mii_if.phy_id_mask = 0x1f;
+    smc->mii_if.reg_num_mask = 0x1f;
     
     /* Register with Card Services */
     link->next = dev_list;
@@ -1044,10 +1060,10 @@
 	SMC_SELECT_BANK(3);
 
 	for (i = 0; i < 32; i++) {
-	    j = mdio_read(dev->base_addr + MGMT, i, 1);
+	    j = smc_mdio_read(dev, i, 1);
 	    if ((j != 0) && (j != 0xffff)) break;
 	}
-	smc->phy_id = (i < 32) ? i : -1;
+	smc->mii_if.phy_id = (i < 32) ? i : -1;
 	if (i < 32) {
 	    DEBUG(0, "  MII transceiver at index %d, status %x.\n", i, j);
 	} else {
@@ -1190,7 +1206,7 @@
 #define MDIO_DATA_WRITE1	(MDIO_DIR_WRITE | MDIO_DATA_OUT)
 #define MDIO_DATA_READ		0x02
 
-static void mdio_sync(ioaddr_t addr)
+static void smc_mdio_sync(ioaddr_t addr)
 {
     int bits;
     for (bits = 0; bits < 32; bits++) {
@@ -1199,12 +1215,13 @@
     }
 }
 
-static int mdio_read(ioaddr_t addr, int phy_id, int loc)
+static int smc_mdio_read(struct net_device *dev, int phy_id, int loc)
 {
+    ioaddr_t addr = dev->base_addr + MGMT;
     u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
     int i, retval = 0;
 
-    mdio_sync(addr);
+    smc_mdio_sync(addr);
     for (i = 13; i >= 0; i--) {
 	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
 	outb(dat, addr);
@@ -1218,12 +1235,13 @@
     return (retval>>1) & 0xffff;
 }
 
-static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value)
+static void smc_mdio_write(struct net_device *dev, int phy_id, int loc, int value)
 {
+    ioaddr_t addr = dev->base_addr + MGMT;
     u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
     int i;
 
-    mdio_sync(addr);
+    smc_mdio_sync(addr);
     for (i = 31; i >= 0; i--) {
 	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
 	outb(dat, addr);
@@ -1777,8 +1795,9 @@
 static void set_rx_mode(struct net_device *dev)
 {
     ioaddr_t ioaddr = dev->base_addr;
+    struct smc_private *smc = dev->priv;
     u_int multicast_table[ 2 ] = { 0, };
-    long flags;
+    unsigned long flags;
     u_short rx_cfg_setting;
     
     if (dev->flags & IFF_PROMISC) {
@@ -1795,16 +1814,15 @@
     }
     
     /* Load MC table and Rx setting into the chip without interrupts. */
-    save_flags(flags);
-    cli();
+    spin_lock_irqsave(&smc->lock, flags);
     SMC_SELECT_BANK(3);
     outl(multicast_table[0], ioaddr + MULTICAST0);
     outl(multicast_table[1], ioaddr + MULTICAST4);
     SMC_SELECT_BANK(0);
     outw(rx_cfg_setting, ioaddr + RCR);
     SMC_SELECT_BANK(2);
-    restore_flags(flags);
-    
+    spin_unlock_irqrestore(&smc->lock, flags);
+ 
     return;
 }
 
@@ -1917,11 +1935,11 @@
 	SMC_SELECT_BANK(3);
 
 	/* Reset MII */
-	mdio_write(ioaddr + MGMT, smc->phy_id, 0, 0x8000);
+	smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000);
 
 	/* Restart MII autonegotiation */
-	mdio_write(ioaddr + MGMT, smc->phy_id, 0, 0x0000);
-	mdio_write(ioaddr + MGMT, smc->phy_id, 0, 0x1200);
+	smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000);
+	smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200);
     }
 
     /* Enable interrupts. */
@@ -1942,7 +1960,6 @@
     struct net_device *dev = &smc->dev;
     ioaddr_t ioaddr = dev->base_addr;
     u_short i, media, saved_bank;
-    ioaddr_t mii_addr = dev->base_addr + MGMT;
     u_short link;
 
     saved_bank = inw(ioaddr + BANK_SELECT);
@@ -1974,20 +1991,20 @@
     }
 
     if (smc->cfg & CFG_MII_SELECT) {
-	if (smc->phy_id < 0)
+	if (smc->mii_if.phy_id < 0)
 	    goto reschedule;
 
 	SMC_SELECT_BANK(3);
-	link = mdio_read(mii_addr, smc->phy_id, 1);
+	link = smc_mdio_read(dev, smc->mii_if.phy_id, 1);
 	if (!link || (link == 0xffff)) {
   	    printk(KERN_INFO "%s: MII is missing!\n", dev->name);
-	    smc->phy_id = -1;
+	    smc->mii_if.phy_id = -1;
 	    goto reschedule;
 	}
 
 	link &= 0x0004;
 	if (link != smc->link_status) {
-	    u_short p = mdio_read(mii_addr, smc->phy_id, 5);
+	    u_short p = smc_mdio_read(dev, smc->mii_if.phy_id, 5);
 	    printk(KERN_INFO "%s: %s link beat\n", dev->name,
 		(link) ? "found" : "lost");
 	    if (link) {
@@ -2043,6 +2060,191 @@
     SMC_SELECT_BANK(saved_bank);
 }
 
+static int smc_link_ok(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    struct smc_private *smc = dev->priv;
+
+    if (smc->cfg & CFG_MII_SELECT) {
+	return mii_link_ok(&smc->mii_if);
+    } else {
+        SMC_SELECT_BANK(0);
+	return inw(ioaddr + EPH) & EPH_LINK_OK;
+    }
+}
+
+static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+    u16 tmp;
+    ioaddr_t ioaddr = dev->base_addr;
+
+    ecmd->supported = (SUPPORTED_TP | SUPPORTED_AUI |
+	SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full);
+		
+    SMC_SELECT_BANK(1);
+    tmp = inw(ioaddr + CONFIG);
+    ecmd->port = (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP;
+    ecmd->transceiver = XCVR_INTERNAL;
+    ecmd->speed = SPEED_10;
+    ecmd->phy_address = ioaddr + MGMT;
+
+    SMC_SELECT_BANK(0);
+    tmp = inw(ioaddr + TCR);
+    ecmd->duplex = (tmp & TCR_FDUPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+
+    return 0;
+}
+
+static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+    u16 tmp;
+    ioaddr_t ioaddr = dev->base_addr;
+
+    if (ecmd->speed != SPEED_10)
+    	return -EINVAL;
+    if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
+    	return -EINVAL;
+    if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI)
+	return -EINVAL;
+    if (ecmd->transceiver != XCVR_INTERNAL)
+    	return -EINVAL;
+
+    if (ecmd->port == PORT_AUI)
+	smc_set_xcvr(dev, 1);
+    else
+	smc_set_xcvr(dev, 0);
+
+    SMC_SELECT_BANK(0);
+    tmp = inw(ioaddr + TCR);
+    if (ecmd->duplex == DUPLEX_FULL)
+	tmp |= TCR_FDUPLX;
+    else
+	tmp &= ~TCR_FDUPLX;
+    outw(ioaddr + TCR, tmp);
+	
+    return 0;
+}
+
+static int smc_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+    u32 ethcmd;
+    struct smc_private *smc = dev->priv;
+
+    if (get_user(ethcmd, (u32 *)useraddr))
+	return -EFAULT;
+
+    switch (ethcmd) {
+
+    case ETHTOOL_GDRVINFO: {
+	struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+	strcpy(info.driver, DRV_NAME);
+	strcpy(info.version, DRV_VERSION);
+	if (copy_to_user(useraddr, &info, sizeof(info)))
+	    return -EFAULT;
+	return 0;
+    }
+
+    /* get settings */
+    case ETHTOOL_GSET: {
+	int ret;
+	struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+	spin_lock_irq(&smc->lock);
+	if (smc->cfg & CFG_MII_SELECT)
+	    ret = mii_ethtool_gset(&smc->mii_if, &ecmd);
+	else
+	    ret = smc_netdev_get_ecmd(dev, &ecmd);
+	spin_unlock_irq(&smc->lock);
+	if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+	    return -EFAULT;
+	return ret;
+    }
+
+    /* set settings */
+    case ETHTOOL_SSET: {
+	int ret;
+	struct ethtool_cmd ecmd;
+	if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+	    return -EFAULT;
+	spin_lock_irq(&smc->lock);
+	if (smc->cfg & CFG_MII_SELECT)
+	    ret = mii_ethtool_sset(&smc->mii_if, &ecmd);    
+	else
+	    ret = smc_netdev_set_ecmd(dev, &ecmd);
+	spin_unlock_irq(&smc->lock);
+	return ret;
+    }
+
+    /* get link status */
+    case ETHTOOL_GLINK: {
+	struct ethtool_value edata = { ETHTOOL_GLINK };
+	spin_lock_irq(&smc->lock);
+	edata.data = smc_link_ok(dev);
+	spin_unlock_irq(&smc->lock);
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+	    return -EFAULT;
+	return 0;
+    }
+
+#ifdef PCMCIA_DEBUG
+    /* get message-level */
+    case ETHTOOL_GMSGLVL: {
+	struct ethtool_value edata = { ETHTOOL_GMSGLVL };
+	edata.data = pc_debug;
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+	    return -EFAULT;
+	return 0;
+    }
+    
+    /* set message-level */
+    case ETHTOOL_SMSGLVL: {
+	struct ethtool_value edata;
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+	    return -EFAULT;
+	pc_debug = edata.data;
+	return 0;
+    }
+#endif
+    /* restart autonegotiation */
+    case ETHTOOL_NWAY_RST: {
+	if (smc->cfg & CFG_MII_SELECT)
+	    return mii_nway_restart(&smc->mii_if);
+	else
+	    return -EOPNOTSUPP;
+    }
+    
+    default:
+	break;
+    }
+
+    return -EOPNOTSUPP;
+}
+
+static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+    struct smc_private *smc = dev->priv;
+    struct mii_ioctl_data *mii;
+    int rc = 0;
+
+    mii = (struct mii_ioctl_data *) &rq->ifr_data;
+    if (!netif_running(dev))
+    	return -EINVAL;
+
+    switch (cmd) {
+    case SIOCETHTOOL:
+	rc = smc_ethtool_ioctl(dev, (void *) rq->ifr_data);
+	break;
+    
+    default:
+	spin_lock_irq(&smc->lock);
+	rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);
+	spin_unlock_irq(&smc->lock);
+	break;
+    }
+
+    return rc;
+}
+
+
 /*====================================================================*/
 
 static int __init init_smc91c92_cs(void)
@@ -2069,3 +2271,4 @@
 
 module_init(init_smc91c92_cs);
 module_exit(exit_smc91c92_cs);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pcmcia/wavelan.h linux-2.4.20/drivers/net/pcmcia/wavelan.h
--- linux-2.4.19/drivers/net/pcmcia/wavelan.h	2001-03-02 19:02:15.000000000 +0000
+++ linux-2.4.20/drivers/net/pcmcia/wavelan.h	2002-10-29 11:18:48.000000000 +0000
@@ -88,6 +88,7 @@
  */
 const int	fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 };
 
+
 /*************************** PC INTERFACE ****************************/
 
 /* WaveLAN host interface definitions */
@@ -316,6 +317,7 @@
 /* Calculate offset of a field in the above structure */
 #define	mmwoff(p,f) 	(unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0)
 
+
 /*
  * Modem Management Controller (MMC) read structure.
  */
@@ -373,6 +375,7 @@
 /* Calculate offset of a field in the above structure */
 #define	mmroff(p,f) 	(unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0)
 
+
 /* Make the two above structures one */
 typedef union mm_t
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pcmcia/wavelan_cs.c linux-2.4.20/drivers/net/pcmcia/wavelan_cs.c
--- linux-2.4.19/drivers/net/pcmcia/wavelan_cs.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/pcmcia/wavelan_cs.c	2002-10-29 11:18:48.000000000 +0000
@@ -41,7 +41,8 @@
  * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
  * - reorganize kmallocs in wavelan_attach, checking all for failure
  *   and releasing the previous allocations if one fails
- *
+ * <No longer true, we reverted to the version in the Pcmcia package
+ *  which was correct in the first place - Jean II>
  *
  ****************************************************************************
  *   Copyright 1995
@@ -62,6 +63,7 @@
  *
  */
 
+/* Do *NOT* add other headers here, you are guaranteed to be wrong - Jean II */
 #include "wavelan_cs.h"		/* Private header */
 
 /************************* MISC SUBROUTINES **************************/
@@ -72,6 +74,34 @@
 
 /*------------------------------------------------------------------*/
 /*
+ * Wrapper for disabling interrupts.
+ * (note : inline, so optimised away)
+ */
+static inline void
+wv_splhi(net_local *		lp,
+	 unsigned long *	pflags)
+{
+  spin_lock_irqsave(&lp->spinlock, *pflags);
+  /* Note : above does the cli(); itself */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for re-enabling interrupts.
+ */
+static inline void
+wv_splx(net_local *		lp,
+	unsigned long *		pflags)
+{
+  spin_unlock_irqrestore(&lp->spinlock, *pflags);
+
+  /* Note : enabling interrupts on the hardware is done in wv_ru_start()
+   * via : outb(OP1_INT_ENABLE, LCCR(base));
+   */
+}
+
+/*------------------------------------------------------------------*/
+/*
  * Wrapper for reporting error to cardservices
  */
 static void cs_error(client_handle_t handle, int func, int ret)
@@ -103,7 +133,7 @@
 
 /******************* MODEM MANAGEMENT SUBROUTINES *******************/
 /*
- * Usefull subroutines to manage the modem of the wavelan
+ * Useful subroutines to manage the modem of the wavelan
  */
 
 /*------------------------------------------------------------------*/
@@ -138,7 +168,7 @@
 {
   hacr_write(base, hacr);
   /* delay might only be needed sometimes */
-  mdelay(1L);
+  mdelay(1);
 } /* hacr_write_slow */
 
 /*------------------------------------------------------------------*/
@@ -529,7 +559,7 @@
   lp->curr_point=NULL;                        /* No default WavePoint */
   lp->cell_search=0;
   
-  lp->cell_timer.data=(int)lp;                /* Start cell expiry timer */
+  lp->cell_timer.data=(unsigned long)lp;                /* Start cell expiry timer */
   lp->cell_timer.function=wl_cell_expiry;
   lp->cell_timer.expires=jiffies+CELL_TIMEOUT;
   add_timer(&lp->cell_timer);
@@ -569,18 +599,18 @@
 #endif
   
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
   
   m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00;
   mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1);
   
-  /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
-  
   if(mode==NWID_PROMISC)
     lp->cell_search=1;
   else
-	lp->cell_search=0;
+    lp->cell_search=0;
+
+  /* ReEnable interrupts & restore flags */
+  wv_splx(lp, &flags);
 }
 
 /* Find a record in the WavePoint table matching a given NWID */
@@ -737,7 +767,7 @@
   ioaddr_t              base = lp->dev->base_addr;  
   mm_t                  m;
   unsigned long         flags;
-  
+
   if(wavepoint==lp->curr_point)          /* Sanity check... */
     {
       wv_nwid_filter(!NWID_PROMISC,lp);
@@ -749,16 +779,16 @@
 #endif
  	
   /* Disable interrupts & save flags */
-  spin_lock_irqsave(&lp->lock, flags);
-  
+  wv_splhi(lp, &flags);
+
   m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF;
   m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8;
   
   mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2);
   
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
-  
+  wv_splx(lp, &flags);
+
   wv_nwid_filter(!NWID_PROMISC,lp);
   lp->curr_point=wavepoint;
 }
@@ -775,6 +805,11 @@
   wavepoint_history *wavepoint=NULL;                /* WavePoint table entry */
   net_local *lp=(net_local *)dev->priv;              /* Device info */
 
+#ifdef I_NEED_THIS_FEATURE
+  /* Some people don't need this, some other may need it */
+  nwid=nwid^ntohs(beacon->domain_id);
+#endif
+
 #if WAVELAN_ROAMING_DEBUG > 1
   printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name);
   printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual);
@@ -832,7 +867,9 @@
 /*------------------------------------------------------------------*/
 /*
  * Routine to synchronously send a command to the i82593 chip. 
- * Should be called with interrupts enabled.
+ * Should be called with interrupts disabled.
+ * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(),
+ *  wv_82593_config() & wv_diag())
  */
 static int
 wv_82593_cmd(device *	dev,
@@ -841,74 +878,98 @@
 	     int	result)
 {
   ioaddr_t	base = dev->base_addr;
-  net_local *	lp = (net_local *)dev->priv;
   int		status;
+  int		wait_completed;
   long		spin;
-  u_long	flags;
 
   /* Spin until the chip finishes executing its current command (if any) */
+  spin = 1000;
   do
     {
-      spin_lock_irqsave (&lp->lock, flags);
+      /* Time calibration of the loop */
+      udelay(10);
+
+      /* Read the interrupt register */
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE);
+  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
 
-  /* We are waiting for command completion */
-  wv_wait_completed = TRUE;
+  /* If the interrupt hasn't be posted */
+  if(spin <= 0)
+    {
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n",
+	     str, status);
+#endif
+      return(FALSE);
+    }
 
   /* Issue the command to the controller */
   outb(cmd, LCCR(base));
 
-  /* If we don't have to check the result of the command */
+  /* If we don't have to check the result of the command
+   * Note : this mean that the irq handler will deal with that */
   if(result == SR0_NO_RESULT)
-    {
-      wv_wait_completed = FALSE;
-      return(TRUE);
-    }
+    return(TRUE);
 
-  /* Busy wait while the LAN controller executes the command.
-   * Note : wv_wait_completed should be volatile */
-  spin = 0;
-  while(wv_wait_completed && (spin++ < 1000))
-    udelay(10);
+  /* We are waiting for command completion */
+  wait_completed = TRUE;
 
-  /* If the interrupt handler hasn't be called */
-  if(wv_wait_completed)
+  /* Busy wait while the LAN controller executes the command. */
+  spin = 1000;
+  do
     {
-      outb(OP0_NOP, LCCR(base));
+      /* Time calibration of the loop */
+      udelay(10);
+
+      /* Read the interrupt register */
+      outb(CR0_STATUS_0 | OP0_NOP, LCCR(base));
       status = inb(LCSR(base));
-      if(status & SR0_INTERRUPT)
+
+      /* Check if there was an interrupt posted */
+      if((status & SR0_INTERRUPT))
 	{
-	  /* There was an interrupt : call the interrupt handler */
-#ifdef DEBUG_INTERRUPT_ERROR
-	  printk(KERN_WARNING "wv_82593_cmd: interrupt handler not installed or interrupt disabled\n");
-#endif
+	  /* Acknowledge the interrupt */
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
 
-	  wavelan_interrupt(dev->irq, (void *) dev,
-			    (struct pt_regs *) NULL);
+	  /* Check if interrupt is a command completion */
+	  if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) &&
+	     ((status & SR0_BOTH_RX_TX) != 0x0) &&
+	     !(status & SR0_RECEPTION))
+	    {
+	      /* Signal command completion */
+	      wait_completed = FALSE;
+	    }
+	  else
+	    {
+	      /* Note : Rx interrupts will be handled later, because we can
+	       * handle multiple Rx packets at once */
+#ifdef DEBUG_INTERRUPT_INFO
+	      printk(KERN_INFO "wv_82593_cmd: not our interrupt\n");
+#endif
+	    }
 	}
-      else
-	{
-	  wv_wait_completed = 0; /* XXX */
+    }
+  while(wait_completed && (spin-- > 0));
+
+  /* If the interrupt hasn't be posted */
+  if(wait_completed)
+    {
 #ifdef DEBUG_INTERRUPT_ERROR
-	  printk(KERN_INFO "wv_82593_cmd: %s timeout, status0 0x%02x\n",
-		 str, status);
+      printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n",
+	     str, status);
 #endif
-	  /* We probably should reset the controller here */
-	  return(FALSE);
-	}
+      return(FALSE);
     }
 
-  /* Check the return code provided by the interrupt handler against
+  /* Check the return code returned by the card (see above) against
    * the expected return code provided by the caller */
-  if((lp->status & SR0_EVENT_MASK) != result)
+  if((status & SR0_EVENT_MASK) != result)
     {
 #ifdef DEBUG_INTERRUPT_ERROR
-      printk(KERN_INFO "wv_82593_cmd: %s failed, status0 = 0x%x\n",
-	     str, lp->status);
+      printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n",
+	     str, status);
 #endif
       return(FALSE);
     }
@@ -924,14 +985,16 @@
 static inline int
 wv_diag(device *	dev)
 {
+  int		ret = FALSE;
+
   if(wv_82593_cmd(dev, "wv_diag(): diagnose",
 		  OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED))
-    return(TRUE);
+    ret = TRUE;
 
 #ifdef DEBUG_CONFIG_ERROR
   printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n");
 #endif
-  return(FALSE);
+  return(ret);
 } /* wv_diag */
 
 /*------------------------------------------------------------------*/
@@ -951,15 +1014,6 @@
   int		chunk_len;
   char *	buf_ptr = buf;
 
-#ifdef OLDIES
-  /* After having check skb_put (net/core/skbuff.c) in the kernel, it seem
-   * quite safe to remove this... */
-
-  /* If buf is NULL, just increment the ring buffer pointer */
-  if(buf == NULL)
-    return((ring_ptr - RX_BASE + len) % RX_SIZE + RX_BASE);
-#endif
-
   /* Get all the buffer */
   while(len > 0)
     {
@@ -990,70 +1044,32 @@
  * wavelan_interrupt is not an option...), so you may experience
  * some delay sometime...
  */
-static inline void wv_82593_reconfig (device * dev)
+static inline void
+wv_82593_reconfig(device *	dev)
 {
-	net_local *lp = (net_local *) dev->priv;
-	dev_link_t *link = ((net_local *) dev->priv)->link;
+  net_local *		lp = (net_local *)dev->priv;
+  dev_link_t *		link = ((net_local *) dev->priv)->link;
+  unsigned long		flags;
 
-	/* Check if we can do it now ! */
-	if (!(link->open)) {
-		lp->reconfig_82593 = TRUE;
+  /* Arm the flag, will be cleard in wv_82593_config() */
+  lp->reconfig_82593 = TRUE;
+
+  /* Check if we can do it now ! */
+  if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev)))
+    {
+      wv_splhi(lp, &flags);	/* Disable interrupts */
+      wv_82593_config(dev);
+      wv_splx(lp, &flags);	/* Re-enable interrupts */
+    }
+  else
+    {
 #ifdef DEBUG_IOCTL_INFO
-		printk (KERN_DEBUG "%s: wv_82593_reconfig(): delayed (link = %d)\n",
-			dev->name, link->open);
+      printk(KERN_DEBUG
+	     "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n",
+	     dev->name, dev->state, link->open);
 #endif
-	} else {
-		netif_stop_queue (dev);
-
-		lp->reconfig_82593 = FALSE;
-		wv_82593_config (dev);
-		netif_wake_queue (dev);
-	}
-}
-
-#ifdef OLDIES
-/*------------------------------------------------------------------*/
-/*
- * Dumps the current i82593 receive buffer to the console.
- */
-static void wavelan_dump(device *dev)
-{
-  ioaddr_t base = dev->base_addr;
-  int i, c;
-
-  /* disable receiver so we can use channel 1 */
-  outb(OP0_RCV_DISABLE, LCCR(base));
-
-  /* reset receive DMA pointer */
-  hacr_write_slow(base, HACR_PWR_STAT | HACR_RX_DMA_RESET);
-  hacr_write(base, HACR_DEFAULT);
-
-  /* dump into receive buffer */
-  wv_82593_cmd(dev, "wavelan_dump(): dump", CR0_CHNL|OP0_DUMP, SR0_DUMP_DONE);
-
-  /* set read pointer to start of receive buffer */
-  outb(0, PIORL(base));
-  outb(0, PIORH(base));
-
-  printk(KERN_DEBUG "wavelan_cs: dump:\n");
-  printk(KERN_DEBUG "     00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
-  for(i = 0; i < 73; i++){
-    if((i % 16) == 0) {
-      printk("\n0x%02x:", i);
-      if (!i) {
-	printk("   ");
-	continue;
-      }
     }
-    c = inb(PIOP(base));
-    printk("%02x ", c);
-  }
-  printk("\n");
-
-  /* enable the receiver again */
-  wv_ru_start(dev);
 }
-#endif
 
 /********************* DEBUG & INFO SUBROUTINES *********************/
 /*
@@ -1171,6 +1187,8 @@
       return;
     }
 
+  wv_splhi(lp, &flags);
+
   /* Read the mmc */
   mmc_out(base, mmwoff(0, mmw_freeze), 1);
   mmc_read(base, 0, (u_char *)&m, sizeof(m));
@@ -1181,6 +1199,8 @@
   lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
 #endif	/* WIRELESS_EXT */
 
+  wv_splx(lp, &flags);
+
   printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
 #ifdef DEBUG_SHOW_UNUSED
   printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
@@ -1265,6 +1285,7 @@
 wv_dev_show(device *	dev)
 {
   printk(KERN_DEBUG "dev:");
+  printk(" state=%lX,", dev->state);
   printk(" trans_start=%ld,", dev->trans_start);
   printk(" flags=0x%x,", dev->flags);
   printk("\n");
@@ -1869,6 +1890,26 @@
 }
 #endif	/* HISTOGRAM */
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "wavelan_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
 /*------------------------------------------------------------------*/
 /*
  * Perform ioctl : config & info stuff
@@ -1891,8 +1932,11 @@
   printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
 #endif
 
+  if (cmd == SIOCETHTOOL)
+    return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   /* Look what is the request */
   switch(cmd)
@@ -1968,7 +2012,7 @@
 
     case SIOCGIWFREQ:
       /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-       * (does it work for everybody XXX - especially old cards...) */
+       * (does it work for everybody ? - especially old cards...) */
       if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
 	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
 	{
@@ -2239,15 +2283,17 @@
 	{
 	  struct iw_range	range;
 
-	  /* Set the length (very important for backward compatibility) */
-	  wrq->u.data.length = sizeof(struct iw_range);
+	   /* Set the length (very important for backward compatibility) */
+	   wrq->u.data.length = sizeof(struct iw_range);
 
-	  /* Set all the info we don't care or don't know about to zero */
-	  memset(&range, 0, sizeof(range));
+	   /* Set all the info we don't care or don't know about to zero */
+	   memset(&range, 0, sizeof(range));
 
-	  /* Set the Wireless Extension versions */
-	  range.we_version_compiled = WIRELESS_EXT;
-	  range.we_version_source = 9;	/* Nothing for us in v10 and v11 */
+#if WIRELESS_EXT > 10
+	   /* Set the Wireless Extension versions */
+	   range.we_version_compiled = WIRELESS_EXT;
+	   range.we_version_source = 9;	/* Nothing for us in v10 and v11 */
+#endif /* WIRELESS_EXT > 10 */
 
 	  /* Set information in the range struct */
 	  range.throughput = 1.4 * 1000 * 1000;	/* don't argue on this ! */
@@ -2517,7 +2563,7 @@
     }
 
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
@@ -2543,11 +2589,8 @@
   printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
 #endif
 
-  if (lp == NULL) /* XXX will this ever occur? */
-    return NULL;
-
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   wstats = &lp->wstats;
 
@@ -2573,7 +2616,7 @@
   wstats->discard.misc = 0L;
 
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
@@ -2692,12 +2735,6 @@
   skb->protocol = eth_type_trans(skb, dev);
 
 #ifdef DEBUG_RX_INFO
-  /* Another glitch : Due to the way the GET_PACKET macro is written,
-   * we are not sure to have the same thing in skb->data. On the other
-   * hand, skb->mac.raw is not defined everywhere...
-   * For versions between 1.2.13 and those where skb->mac.raw appear,
-   * I don't have a clue...
-   */
   wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
 #endif	/* DEBUG_RX_INFO */
      
@@ -2731,9 +2768,7 @@
 	  wl_roam_gather(dev, skb->data, stats);
 #endif	/* WAVELAN_ROAMING */
 	  
-      /* Spying stuff */
 #ifdef WIRELESS_SPY
-      /* Same as above */
       wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats);
 #endif	/* WIRELESS_SPY */
 #ifdef HISTOGRAM
@@ -2766,6 +2801,7 @@
  * called to do the actual transfer of the card's data including the
  * ethernet header into a packet consisting of an sk_buff chain.
  * (called by wavelan_interrupt())
+ * Note : the spinlock is already grabbed for us and irq are disabled.
  */
 static inline void
 wv_packet_rcv(device *	dev)
@@ -2916,7 +2952,7 @@
   printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
 #endif
 
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   /* Check if we need some padding */
   if(clen < ETH_ZLEN)
@@ -2943,18 +2979,13 @@
   wv_82593_cmd(dev, "wv_packet_write(): transmit",
 	       OP0_TRANSMIT, SR0_NO_RESULT);
 
+  /* Make sure the watchdog will keep quiet for a while */
+  dev->trans_start = jiffies;
+
   /* Keep stats up to date */
   lp->stats.tx_bytes += length;
 
-  /* If watchdog not already active, activate it... */
-  if (!timer_pending(&lp->watchdog))
-    {
-      /* set timer to expire in WATCHDOG_JIFFIES */
-      lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
-      add_timer(&lp->watchdog);
-    }
-
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_TX_INFO
   wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
@@ -2963,56 +2994,57 @@
 #ifdef DEBUG_TX_TRACE
   printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
 #endif
-
-  netif_start_queue (dev);
 }
 
 /*------------------------------------------------------------------*/
 /*
  * This routine is called when we want to send a packet (NET3 callback)
- * In this routine, we check if the hardware is ready to accept
+ * In this routine, we check if the harware is ready to accept
  * the packet. We also prevent reentrance. Then, we call the function
  * to send the packet...
  */
-static int wavelan_packet_xmit (struct sk_buff *skb,
-				device * dev)
+static int
+wavelan_packet_xmit(struct sk_buff *	skb,
+		    device *		dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+  net_local *		lp = (net_local *)dev->priv;
+  unsigned long		flags;
 
 #ifdef DEBUG_TX_TRACE
-	printk (KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
-		(unsigned) skb);
+  printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
+	 (unsigned) skb);
 #endif
 
-	/*
-	 * For ethernet, fill in the header.
-	 */
+  /*
+   * Block a timer-based transmit from overlapping a previous transmit.
+   * In other words, prevent reentering this routine.
+   */
+  netif_stop_queue(dev);
 
-	netif_stop_queue (dev);
+  /* If somebody has asked to reconfigure the controller,
+   * we can do it now */
+  if(lp->reconfig_82593)
+    {
+      wv_splhi(lp, &flags);	/* Disable interrupts */
+      wv_82593_config(dev);
+      wv_splx(lp, &flags);	/* Re-enable interrupts */
+      /* Note : the configure procedure was totally synchronous,
+       * so the Tx buffer is now free */
+    }
 
-	/*
-	 * Block a timer-based transmit from overlapping a previous transmit.
-	 * In other words, prevent reentering this routine.
-	 */
-	if (1) {
-		/* If somebody has asked to reconfigure the controller, we can do it now */
-		if (lp->reconfig_82593) {
-			lp->reconfig_82593 = FALSE;
-			wv_82593_config (dev);
-		}
 #ifdef DEBUG_TX_ERROR
-		if (skb->next)
-			printk (KERN_INFO "skb has next\n");
+	if (skb->next)
+		printk(KERN_INFO "skb has next\n");
 #endif
 
-		wv_packet_write (dev, skb->data, skb->len);
-	}
-	dev_kfree_skb (skb);
+  wv_packet_write(dev, skb->data, skb->len);
+
+  dev_kfree_skb(skb);
 
 #ifdef DEBUG_TX_TRACE
-	printk (KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
+  printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
 #endif
-	return (0);
+  return(0);
 }
 
 /********************** HARDWARE CONFIGURATION **********************/
@@ -3165,7 +3197,7 @@
    */
 
   /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-   * (does it work for everybody XXX - especially old cards...) */
+   * (does it work for everybody ? - especially old cards...) */
   /* Note : WFREQSEL verify that it is able to read from EEprom
    * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
    * is 0xA (Xilinx version) or 0xB (Ariadne version).
@@ -3223,7 +3255,7 @@
 wv_ru_stop(device *	dev)
 {
   ioaddr_t	base = dev->base_addr;
-  net_local *lp = (net_local *) dev->priv;
+  net_local *	lp = (net_local *) dev->priv;
   unsigned long	flags;
   int		status;
   int		spin;
@@ -3232,35 +3264,35 @@
   printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name);
 #endif
 
+  wv_splhi(lp, &flags);
+
   /* First, send the LAN controller a stop receive command */
   wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv",
 	       OP0_STOP_RCV, SR0_NO_RESULT);
 
   /* Then, spin until the receive unit goes idle */
-  spin = 0;
+  spin = 300;
   do
     {
       udelay(10);
-      spin_lock_irqsave (&lp->lock, flags);
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin++ < 300));
+  while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0));
 
   /* Now, spin until the chip finishes executing its current command */
   do
     {
       udelay(10);
-      spin_lock_irqsave (&lp->lock, flags);
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin++ < 300));
+  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
+
+  wv_splx(lp, &flags);
 
   /* If there was a problem */
-  if(spin > 300)
+  if(spin <= 0)
     {
 #ifdef DEBUG_CONFIG_ERROR
       printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n",
@@ -3287,6 +3319,7 @@
 {
   ioaddr_t	base = dev->base_addr;
   net_local *	lp = (net_local *) dev->priv;
+  unsigned long	flags;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
@@ -3300,6 +3333,8 @@
   if(!wv_ru_stop(dev))
     return FALSE;
 
+  wv_splhi(lp, &flags);
+
   /* Now we know that no command is being executed. */
 
   /* Set the receive frame pointer and stop pointer */
@@ -3309,8 +3344,17 @@
   /* Reset ring management.  This sets the receive frame pointer to 1 */
   outb(OP1_RESET_RING_MNGMT, LCCR(base));
 
+#if 0
+  /* XXX the i82593 manual page 6-4 seems to indicate that the stop register
+     should be set as below */
+  /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/
+#elif 0
+  /* but I set it 0 instead */
+  lp->stop = 0;
+#else
   /* but I set it to 3 bytes per packet less than 8K */
   lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
+#endif
   outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base));
   outb(OP1_INT_ENABLE, LCCR(base));
   outb(OP1_SWIT_TO_PORT_0, LCCR(base));
@@ -3326,17 +3370,15 @@
 #ifdef DEBUG_I82593_SHOW
   {
     int	status;
-    unsigned long flags;
-    int	i = 0;
+    int	opri;
+    int	spin = 10000;
 
     /* spin until the chip starts receiving */
     do
       {
-	spin_lock_irqsave (&lp->lock, flags);
 	outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
 	status = inb(LCSR(base));
-	spin_unlock_irqrestore (&lp->lock, flags);
-	if(i++ > 10000)
+	if(spin-- <= 0)
 	  break;
       }
     while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) &&
@@ -3345,6 +3387,9 @@
 	   (status & SR3_RCV_STATE_MASK), i);
   }
 #endif
+
+  wv_splx(lp, &flags);
+
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
 #endif
@@ -3363,6 +3408,7 @@
   ioaddr_t			base = dev->base_addr;
   net_local *			lp = (net_local *) dev->priv;
   struct i82593_conf_block	cfblk;
+  int				ret = TRUE;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name);
@@ -3457,7 +3503,7 @@
   hacr_write(base, HACR_DEFAULT);
   if(!wv_82593_cmd(dev, "wv_82593_config(): configure",
 		   OP0_CONFIGURE, SR0_CONFIGURE_DONE))
-    return(FALSE);
+    ret = FALSE;
 
   /* Initialize adapter's ethernet MAC address */
   outb(TX_BASE & 0xff, PIORL(base));
@@ -3471,7 +3517,7 @@
   hacr_write(base, HACR_DEFAULT);
   if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup",
 		   OP0_IA_SETUP, SR0_IA_SETUP_DONE))
-    return(FALSE);
+    ret = FALSE;
 
 #ifdef WAVELAN_ROAMING
     /* If roaming is enabled, join the "Beacon Request" multicast group... */
@@ -3508,14 +3554,17 @@
       hacr_write(base, HACR_DEFAULT);
       if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup",
 		       OP0_MC_SETUP, SR0_MC_SETUP_DONE))
-	return(FALSE);
+	ret = FALSE;
       lp->mc_count = dev->mc_count;	/* remember to avoid repeated reset */
     }
 
+  /* Job done, clear the flag */
+  lp->reconfig_82593 = FALSE;
+
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name);
 #endif
-  return(TRUE);
+  return(ret);
 }
 
 /*------------------------------------------------------------------*/
@@ -3594,6 +3643,8 @@
 {
   net_local *		lp = (net_local *) dev->priv;
   ioaddr_t		base = dev->base_addr;
+  unsigned long		flags;
+  int			ret = FALSE;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name);
@@ -3612,50 +3663,78 @@
   if(wv_pcmcia_reset(dev) == FALSE)
     return FALSE;
 
-  /* Power UP the module + reset the modem + reset host adapter
-   * (in fact, reset DMA channels) */
-  hacr_write_slow(base, HACR_RESET);
-  hacr_write(base, HACR_DEFAULT);
+  /* Disable interrupts */
+  wv_splhi(lp, &flags);
 
-  /* Check if the module has been powered up... */
-  if(hasr_read(base) & HASR_NO_CLK)
+  /* Disguised goto ;-) */
+  do
     {
+      /* Power UP the module + reset the modem + reset host adapter
+       * (in fact, reset DMA channels) */
+      hacr_write_slow(base, HACR_RESET);
+      hacr_write(base, HACR_DEFAULT);
+
+      /* Check if the module has been powered up... */
+      if(hasr_read(base) & HASR_NO_CLK)
+	{
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
-	     dev->name);
+	  printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
+		 dev->name);
 #endif
-      return FALSE;
-    }
+	  break;
+	}
 
-  /* initialize the modem */
-  if(wv_mmc_init(dev) == FALSE)
-    return FALSE;
+      /* initialize the modem */
+      if(wv_mmc_init(dev) == FALSE)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_WARNING "%s: wv_hw_config(): Can't configure the modem\n",
+		 dev->name);
+#endif
+	  break;
+	}
 
-  /* reset the LAN controller (i82593) */
-  outb(OP0_RESET, LCCR(base));
-  mdelay(1);	/* A bit crude ! */
-
-  /* Initialize the LAN controller */
-  if((wv_82593_config(dev) == FALSE) ||
-     (wv_diag(dev) == FALSE))
-    {
+      /* reset the LAN controller (i82593) */
+      outb(OP0_RESET, LCCR(base));
+      mdelay(1);	/* A bit crude ! */
+
+      /* Initialize the LAN controller */
+      if(wv_82593_config(dev) == FALSE)
+	{
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", dev->name);
+	  printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n",
+		 dev->name);
 #endif
-      return FALSE;
-    }
+	  break;
+	}
 
-  /* 
-   * insert code for loopback test here
-   */
+      /* Diagnostic */
+      if(wv_diag(dev) == FALSE)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_INFO "%s: wv_hw_config(): i82593 diagnostic failed\n",
+		 dev->name);
+#endif
+	  break;
+	}
 
-  /* The device is now configured */
-  lp->configured = 1;
+      /* 
+       * insert code for loopback test here
+       */
+
+      /* The device is now configured */
+      lp->configured = 1;
+      ret = TRUE;
+    }
+  while(0);
+
+  /* Re-enable interrupts */
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name);
 #endif
-  return TRUE;
+  return(ret);
 }
 
 /*------------------------------------------------------------------*/
@@ -3675,10 +3754,6 @@
   printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name);
 #endif
 
-  /* If watchdog was activated, kill it ! */
-  if (timer_pending(&lp->watchdog))
-    del_timer(&lp->watchdog);
-
   lp->nresets++;
   lp->configured = 0;
   
@@ -3786,13 +3861,13 @@
 	}
 
       /*
-       * Allocate a 4K memory window.  Note that the dev_link_t
+       * Allocate a small memory window.  Note that the dev_link_t
        * structure provides space for one window handle -- if your
        * device needs several windows, you'll need to keep track of
        * the handles in your private data structure, link->priv.
        */
       req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-      req.Base = 0; req.Size = 0x1000;
+      req.Base = req.Size = 0;
       req.AccessSpeed = mem_speed;
       link->win = (window_handle_t)link->handle;
       i = CardServices(RequestWindow, &link->win, &req);
@@ -3803,7 +3878,7 @@
 	}
 
       dev->rmem_start = dev->mem_start =
-	  (u_long)ioremap(req.Base, 0x1000);
+	  (u_long)ioremap(req.Base, req.Size);
       dev->rmem_end = dev->mem_end = dev->mem_start + req.Size;
 
       mem.CardOffset = 0; mem.Page = 0;
@@ -3817,7 +3892,7 @@
       /* Feed device with this info... */
       dev->irq = link->irq.AssignedIRQ;
       dev->base_addr = link->io.BasePort1;
-      netif_start_queue (dev);
+      netif_start_queue(dev);
 
 #ifdef DEBUG_CONFIG_INFO
       printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n",
@@ -3843,7 +3918,7 @@
       return FALSE;
     }
 
-  /* XXX Could you explain me this, Dave ? */
+  strcpy(((net_local *) dev->priv)->node.dev_name, dev->name);
   link->dev = &((net_local *) dev->priv)->node;
 
 #ifdef DEBUG_CONFIG_TRACE
@@ -3887,7 +3962,7 @@
   CardServices(ReleaseIO, link->handle, &link->io);
   CardServices(ReleaseIRQ, link->handle, &link->irq);
 
-  link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING | DEV_STALE_CONFIG);
+  link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG);
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name);
@@ -3896,7 +3971,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Sometimes, netwave_detach can't be performed following a call from
+ * Sometimes, wavelan_detach can't be performed following a call from
  * cardmgr (device still open, pcmcia_release not done) and the device
  * is put in a STALE_LINK state and remains in memory.
  *
@@ -3970,7 +4045,19 @@
   lp = (net_local *) dev->priv;
   base = dev->base_addr;
 
-  spin_lock (&lp->lock);
+#ifdef DEBUG_INTERRUPT_INFO
+  /* Check state of our spinlock (it should be cleared) */
+  if(spin_is_locked(&lp->spinlock))
+    printk(KERN_DEBUG
+	   "%s: wavelan_interrupt(): spinlock is already locked !!!\n",
+	   dev->name);
+#endif
+
+  /* Prevent reentrancy. We need to do that because we may have
+   * multiple interrupt handler running concurently.
+   * It is safe because wv_splhi() disable interrupts before aquiring
+   * the spinlock. */
+  spin_lock(&lp->spinlock);
 
   /* Treat all pending interrupts */
   while(1)
@@ -4015,8 +4102,6 @@
 	  break;
 	}
 
-      lp->status = status0;	/* Save current status (for commands) */
-
       /* ----------------- RECEIVING PACKET ----------------- */
       /*
        * When the wavelan signal the reception of a new packet,
@@ -4054,22 +4139,6 @@
        * Most likely : transmission done
        */
 
-      /* If we are already waiting elsewhere for the command to complete */
-      if(wv_wait_completed)
-	{
-#ifdef DEBUG_INTERRUPT_INFO
-	  printk(KERN_DEBUG "%s: wv_interrupt(): command completed\n",
-		 dev->name);
-#endif
-
-	  /* Signal command completion */
-	  wv_wait_completed = 0;
-
-	  /* Acknowledge the interrupt */
-	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
-	  continue;
-    	}
-
       /* If a transmission has been done */
       if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
 	 (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
@@ -4081,10 +4150,6 @@
 		   dev->name);
 #endif
 
-	  /* If watchdog was activated, kill it ! */
-	  if(timer_pending(&lp->watchdog))
-	    del_timer(&lp->watchdog);
-
 	  /* Get transmission status */
 	  tx_status = inb(LCSR(base));
 	  tx_status |= (inb(LCSR(base)) << 8);
@@ -4174,7 +4239,7 @@
 	  lp->stats.collisions += (tx_status & TX_NCOL_MASK);
 	  lp->stats.tx_packets++;
 
-	  netif_wake_queue (dev);
+	  netif_wake_queue(dev);
 	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
     	} 
       else	/* if interrupt = transmit done or retransmit done */
@@ -4185,9 +4250,9 @@
 #endif
 	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
     	}
-    }
+    }	/* while(1) */
 
-  spin_unlock_irq (&lp->lock);
+  spin_unlock(&lp->spinlock);
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
@@ -4196,30 +4261,23 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Watchdog : when we start a transmission, we set a timer in the
- * kernel.  If the transmission complete, this timer is disabled. If
- * it expire, it try to unlock the hardware.
+ * Watchdog: when we start a transmission, a timer is set for us in the
+ * kernel.  If the transmission completes, this timer is disabled. If
+ * the timer expires, we are called and we try to unlock the hardware.
  *
- * Note : this watchdog doesn't work on the same principle as the
- * watchdog in the ISA driver. I make it this way because the overhead
- * of add_timer() and del_timer() is nothing and that it avoid calling
- * the watchdog, saving some CPU... If you want to apply the same
- * watchdog to the ISA driver, you should be a bit carefull, because
- * of the many transmit buffers...
- * This watchdog is also move clever, it try to abort the current
- * command before reseting everything...
+ * Note : This watchdog is move clever than the one in the ISA driver,
+ * because it try to abort the current command before reseting
+ * everything...
+ * On the other hand, it's a bit simpler, because we don't have to
+ * deal with the multiple Tx buffers...
  */
 static void
-wavelan_watchdog(u_long		a)
+wavelan_watchdog(device *	dev)
 {
-  device *		dev;
-  net_local *		lp;
-  ioaddr_t		base;
-  int			spin;
-
-  dev = (device *) a;
-  base = dev->base_addr;
-  lp = (net_local *) dev->priv;
+  net_local *		lp = (net_local *) dev->priv;
+  ioaddr_t		base = dev->base_addr;
+  unsigned long		flags;
+  int			aborted = FALSE;
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
@@ -4230,21 +4288,21 @@
 	 dev->name);
 #endif
 
-  /* We are waiting for command completion */
-  wv_wait_completed = TRUE;
+  wv_splhi(lp, &flags);
 
   /* Ask to abort the current command */
   outb(OP0_ABORT, LCCR(base));
 
-  /* Busy wait while the LAN controller executes the command.
-   * Note : wv_wait_completed should be volatile */
-  spin = 0;
-  while(wv_wait_completed && (spin++ < 250))
-    udelay(10);
-
-  /* If the interrupt handler hasn't be called or invalid status */
-  if((wv_wait_completed) ||
-     ((lp->status & SR0_EVENT_MASK) != SR0_EXECUTION_ABORTED))
+  /* Wait for the end of the command (a bit hackish) */
+  if(wv_82593_cmd(dev, "wavelan_watchdog(): abort",
+		  OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED))
+    aborted = TRUE;
+
+  /* Release spinlock here so that wv_hw_reset() can grab it */
+  wv_splx(lp, &flags);
+
+  /* Check if we were successful in aborting it */
+  if(!aborted)
     {
       /* It seem that it wasn't enough */
 #ifdef DEBUG_INTERRUPT_ERROR
@@ -4269,7 +4327,7 @@
 #endif
 
   /* We are no more waiting for something... */
-  netif_start_queue (dev);
+  netif_wake_queue(dev);
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
@@ -4322,7 +4380,7 @@
     return FALSE;
   if(!wv_ru_start(dev))
     wv_hw_reset(dev);		/* If problem : reset */
-  netif_start_queue (dev);
+  netif_start_queue(dev);
 
   /* Mark the device as used */
   link->open++;
@@ -4348,7 +4406,6 @@
 wavelan_close(device *	dev)
 {
   dev_link_t *	link = ((net_local *) dev->priv)->link;
-  net_local *	lp = (net_local *)dev->priv;
   ioaddr_t	base = dev->base_addr;
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4356,8 +4413,6 @@
 	 (unsigned int) dev);
 #endif
 
-  netif_stop_queue (dev);
-
   /* If the device isn't open, then nothing to do */
   if(!link->open)
     {
@@ -4373,17 +4428,13 @@
     wv_roam_cleanup(dev);
 #endif	/* WAVELAN_ROAMING */
 
-  /* If watchdog was activated, kill it ! */
-  if(timer_pending(&lp->watchdog))
-    del_timer(&lp->watchdog);
-
   link->open--;
   MOD_DEC_USE_COUNT;
 
   /* If the card is still present */
-  if (netif_device_present(dev))
+  if(netif_running(dev))
     {
-      netif_stop_queue (dev);
+      netif_stop_queue(dev);
 
       /* Stop receiving new messages and wait end of transmission */
       wv_ru_stop(dev);
@@ -4404,21 +4455,6 @@
 
 /*------------------------------------------------------------------*/
 /*
- * We never need to do anything when a wavelan device is "initialized"
- * by the net software, because we only register already-found cards.
- */
-static int
-wavelan_init(device *	dev)
-{
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "<>wavelan_init()\n");
-#endif
-
-  return(0);
-}
-
-/*------------------------------------------------------------------*/
-/*
  * wavelan_attach() creates an "instance" of the driver, allocating
  * local data structures for one device (one interface).  The device
  * is registered with Card Services.
@@ -4445,24 +4481,8 @@
 
   /* Initialize the dev_link_t structure */
   link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-  if (!link)
-	  return NULL;
-  
-  /* Allocate the generic data structure */
-  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
-  if (!dev)
-	  goto fail_alloc_dev;
-  
-  /* Allocate the wavelan-specific data structure. */
-  lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
-  if (!lp)
-	  goto fail_alloc_dev_priv;
-  
-  memset(lp, 0, sizeof(net_local));
+  if (!link) return NULL;
   memset(link, 0, sizeof(struct dev_link_t));
-  memset(dev, 0, sizeof(struct net_device));
-
-  dev->priv = lp;
 
   /* Unused for the Wavelan */
   link->release.function = &wv_pcmcia_release;
@@ -4492,18 +4512,35 @@
   link->next = dev_list;
   dev_list = link;
 
+  /* Allocate the generic data structure */
+  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+  if (!dev) {
+      kfree(link);
+      return NULL;
+  }
+  memset(dev, 0x00, sizeof(struct net_device));
   link->priv = link->irq.Instance = dev;
 
+  /* Allocate the wavelan-specific data structure. */
+  dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
+  if (!lp) {
+      kfree(link);
+      kfree(dev);
+      return NULL;
+  }
+  memset(lp, 0x00, sizeof(net_local));
+
   /* Init specific data */
-  wv_wait_completed = 0;
-  lp->status = FALSE;
   lp->configured = 0;
   lp->reconfig_82593 = FALSE;
   lp->nresets = 0;
+  /* Multicast stuff */
+  lp->promiscuous = 0;
+  lp->allmulticast = 0;
+  lp->mc_count = 0;
 
-  /* Set the watchdog timer */
-  lp->watchdog.function = wavelan_watchdog;
-  lp->watchdog.data = (unsigned long) dev;
+  /* Init spinlock */
+  spin_lock_init(&lp->spinlock);
 
   /* back links */
   lp->link = link;
@@ -4513,7 +4550,6 @@
   ether_setup(dev);
 
   /* wavelan NET3 callbacks */
-  dev->init = &wavelan_init;
   dev->open = &wavelan_open;
   dev->stop = &wavelan_close;
   dev->hard_start_xmit = &wavelan_packet_xmit;
@@ -4523,14 +4559,16 @@
   dev->set_mac_address = &wavelan_set_mac_address;
 #endif	/* SET_MAC_ADDRESS */
 
+  /* Set the watchdog timer */
+  dev->tx_timeout	= &wavelan_watchdog;
+  dev->watchdog_timeo	= WATCHDOG_JIFFIES;
+
 #ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
   dev->do_ioctl = wavelan_ioctl;	/* wireless extensions */
   dev->get_wireless_stats = wavelan_get_wireless_stats;
 #endif
 
   /* Other specific data */
-  strcpy(dev->name, ((net_local *)dev->priv)->node.dev_name);
-  netif_start_queue (dev);
   dev->mtu = WAVELAN_MTU;
 
   /* Register with Card Services */
@@ -4562,12 +4600,6 @@
 #endif
 
   return link;
-
-fail_alloc_dev_priv:
-  kfree(dev);
-fail_alloc_dev:
-  kfree(link);
-  return NULL;
 }
 
 /*------------------------------------------------------------------*/
@@ -4698,7 +4730,7 @@
 	if(link->state & DEV_CONFIG)
 	  {
 	    /* Accept no more transmissions */
-      	    netif_device_detach(dev);
+	    netif_device_detach(dev);
 
 	    /* Release the card */
 	    wv_pcmcia_release((u_long) link);
@@ -4720,7 +4752,7 @@
 	 * obliged to close nicely the wavelan here. David, could you
 	 * close the device before suspending them ? And, by the way,
 	 * could you, on resume, add a "route add -net ..." after the
-	 * ifconfig up XXX Thanks... */
+	 * ifconfig up ? Thanks... */
 
 	/* Stop receiving new messages and wait end of transmission */
 	wv_ru_stop(dev);
@@ -4735,8 +4767,7 @@
     	if(link->state & DEV_CONFIG)
 	  {
       	    if(link->open)
-	      	netif_device_detach(dev);
-
+	      netif_device_detach(dev);
       	    CardServices(ReleaseConfiguration, link->handle);
 	  }
 	break;
@@ -4748,7 +4779,7 @@
 	if(link->state & DEV_CONFIG)
 	  {
       	    CardServices(RequestConfiguration, link->handle, &link->conf);
-      	    if(link->open)	/* If RESET -> True, If RESUME -> False XXX */
+      	    if(link->open)	/* If RESET -> True, If RESUME -> False ? */
 	      {
 		wv_hw_reset(dev);
 		netif_device_attach(dev);
@@ -4838,4 +4869,5 @@
 
 module_init(init_wavelan_cs);
 module_exit(exit_wavelan_cs);
-MODULE_LICENSE("Dual BSD/GPL");
+
+/* Note : Modules parameters are in wavelan_cs.h - Jean II */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pcmcia/wavelan_cs.h linux-2.4.20/drivers/net/pcmcia/wavelan_cs.h
--- linux-2.4.19/drivers/net/pcmcia/wavelan_cs.h	2001-10-12 21:21:18.000000000 +0000
+++ linux-2.4.20/drivers/net/pcmcia/wavelan_cs.h	2002-10-29 11:18:49.000000000 +0000
@@ -34,6 +34,25 @@
  *	I try to maintain a web page with the Wireless LAN Howto at :
  *	    http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
  *
+ * SMP
+ * ---
+ *	We now are SMP compliant (I eventually fixed the remaining bugs).
+ *	The driver has been tested on a dual P6-150 and survived my usual
+ *	set of torture tests.
+ *	Anyway, I spent enough time chasing interrupt re-entrancy during
+ *	errors or reconfigure, and I designed the locked/unlocked sections
+ *	of the driver with great care, and with the recent addition of
+ *	the spinlock (thanks to the new API), we should be quite close to
+ *	the truth.
+ *	The SMP/IRQ locking is quite coarse and conservative (i.e. not fast),
+ *	but better safe than sorry (especially at 2 Mb/s ;-).
+ *
+ *	I have also looked into disabling only our interrupt on the card
+ *	(via HACR) instead of all interrupts in the processor (via cli),
+ *	so that other driver are not impacted, and it look like it's
+ *	possible, but it's very tricky to do right (full of races). As
+ *	the gain would be mostly for SMP systems, it can wait...
+ *
  * Debugging and options
  * ---------------------
  *	You will find below a set of '#define" allowing a very fine control
@@ -122,7 +141,7 @@
  * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work.
  * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
  * correctly 2.00 cards (2.4 GHz with frequency selection).
- * David Hinds <dhinds@pcmcia.sourceforge.org> integrated the whole in his
+ * David Hinds <dahinds@users.sourceforge.net> integrated the whole in his
  * Pcmcia package (+ bug corrections).
  *
  * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
@@ -158,8 +177,8 @@
  *
  *    This software was originally developed under Linux 1.2.3
  *	(Slackware 2.0 distribution).
- *    And then under Linux 2.0.x (Debian 1.1 - pcmcia 2.8.18-23) with
- *	HP OmniBook 4000 & 5500.
+ *    And then under Linux 2.0.x (Debian 1.1 -> 2.2 - pcmcia 2.8.18+)
+ *	with an HP OmniBook 4000 and then a 5500.
  *
  *    It is based on other device drivers and information either written
  *    or supplied by:
@@ -174,7 +193,7 @@
  *	Matthew Geier (matthew@cs.su.oz.au),
  *	Remo di Giovanni (remo@cs.su.oz.au),
  *	Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
- *	David Hinds <dhinds@pcmcia.sourceforge.org>,
+ *	David Hinds <dahinds@users.sourceforge.net>,
  *	Jan Hoogendoorn (c/o marteijn@lucent.com),
  *      Bruce Janson <bruce@cs.usyd.edu.au>,
  *	Anthony D. Joseph <adj@lcs.mit.edu>,
@@ -349,6 +368,37 @@
  *	- Fix check for root permission (break instead of exit)
  *	- New nwid & encoding setting (Wireless Extension 9)
  *
+ * Changes made for release in 3.1.12 :
+ * ----------------------------------
+ *	- reworked wv_82593_cmd to avoid using the IRQ handler and doing
+ *	  ugly things with interrupts.
+ *	- Add IRQ protection in 82593_config/ru_start/ru_stop/watchdog
+ *	- Update to new network API (softnet - 2.3.43) :
+ *		o replace dev->tbusy (David + me)
+ *		o replace dev->tstart (David + me)
+ *		o remove dev->interrupt (David)
+ *		o add SMP locking via spinlock in splxx (me)
+ *		o add spinlock in interrupt handler (me)
+ *		o use kernel watchdog instead of ours (me)
+ *		o verify that all the changes make sense and work (me)
+ *	- Re-sync kernel/pcmcia versions (not much actually)
+ *	- A few other cleanups (David & me)...
+ *
+ * Changes made for release in 3.1.22 :
+ * ----------------------------------
+ *	- Check that SMP works, remove annoying log message
+ *
+ * Changes made for release in 3.1.24 :
+ * ----------------------------------
+ *	- Fix unfrequent card lockup when watchdog was reseting the hardware :
+ *		o control first busy loop in wv_82593_cmd()
+ *		o Extend spinlock protection in wv_hw_config()
+ *
+ * Changes made for release in 3.2.1 :
+ * ---------------------------------
+ *	- Set dev->trans_start to avoid filling the logs
+ *		(and generating useless abort commands)
+ *
  * Wishes & dreams:
  * ----------------
  *	- Cleanup and integrate the roaming code
@@ -368,6 +418,7 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
+#include <linux/spinlock.h>
 #include <linux/in.h>
 #include <linux/delay.h>
 #include <asm/uaccess.h>
@@ -381,10 +432,11 @@
 #include <linux/if_arp.h>
 #include <linux/ioport.h>
 #include <linux/fcntl.h>
+#include <linux/ethtool.h>
 
 #ifdef CONFIG_NET_PCMCIA_RADIO
 #include <linux/wireless.h>		/* Wireless extensions */
-#endif	/* CONFIG_NET_PCMCIA_RADIO */
+#endif
 
 /* Pcmcia headers that we need */
 #include <pcmcia/cs_types.h>
@@ -437,7 +489,7 @@
 #undef DEBUG_RX_INFO		/* Header of the transmitted packet */
 #undef DEBUG_RX_FAIL		/* Normal failure conditions */
 #define DEBUG_RX_ERROR		/* Unexpected conditions */
-#undef DEBUG_PACKET_DUMP	/* Dump packet on the screen */
+#undef DEBUG_PACKET_DUMP	32	/* Dump packet on the screen */
 #undef DEBUG_IOCTL_TRACE	/* Misc call by Linux */
 #undef DEBUG_IOCTL_INFO		/* Various debug info */
 #define DEBUG_IOCTL_ERROR	/* What's going wrong */
@@ -452,7 +504,7 @@
 /************************ CONSTANTS & MACROS ************************/
 
 #ifdef DEBUG_VERSION_SHOW
-static const char *version = "wavelan_cs.c : v21 (wireless extensions) 18/10/99\n";
+static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/12/00\n";
 #endif
 
 /* Watchdog temporisation */
@@ -557,9 +609,9 @@
  */
 struct net_local
 {
-  spinlock_t	lock;
   dev_node_t 	node;		/* ???? What is this stuff ???? */
   device *	dev;		/* Reverse link... */
+  spinlock_t	spinlock;	/* Serialize access to the hardware (SMP) */
   dev_link_t *	link;		/* pcmcia structure */
   en_stats	stats;		/* Ethernet interface statistics */
   int		nresets;	/* Number of hw resets */
@@ -568,9 +620,7 @@
   u_char	promiscuous;	/* Promiscuous mode */
   u_char	allmulticast;	/* All Multicast mode */
   int		mc_count;	/* Number of multicast addresses */
-  timer_list	watchdog;	/* To avoid blocking state */
 
-  u_char        status;		/* Current i82593 status */
   int   	stop;		/* Current i82593 Stop Hit Register */
   int   	rfp;		/* Last DMA machine receive pointer */
   int		overrunning;	/* Receiver overrun flag */
@@ -617,8 +667,14 @@
 #endif	/* WAVELAN_ROAMING */
 
 /* ----------------------- MISC SUBROUTINES ------------------------ */
+static inline void
+	wv_splhi(net_local *,		/* Disable interrupts */
+		 unsigned long *);	/* flags */
+static inline void
+	wv_splx(net_local *,		/* ReEnable interrupts */
+		unsigned long *);	/* flags */
 static void
-	cs_error(client_handle_t, /* Report error to cardmgr */
+	cs_error(client_handle_t,	/* Report error to cardmgr */
 		 int,
 		 int);
 /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
@@ -722,16 +778,15 @@
 	wv_flush_stale_links(void);	/* "detach" all possible devices */
 /* ---------------------- INTERRUPT HANDLING ---------------------- */
 static void
-wavelan_interrupt(int,	/* Interrupt handler */
-		  void *,
-		  struct pt_regs *);
+	wavelan_interrupt(int,	/* Interrupt handler */
+			  void *,
+			  struct pt_regs *);
 static void
-	wavelan_watchdog(u_long);	/* Transmission watchdog */
+	wavelan_watchdog(device *);	/* Transmission watchdog */
 /* ------------------- CONFIGURATION CALLBACKS ------------------- */
 static int
 	wavelan_open(device *),		/* Open the device */
-	wavelan_close(device *),	/* Close the device */
-	wavelan_init(device *);		/* Do nothing */
+	wavelan_close(device *);	/* Close the device */
 static dev_link_t *
 	wavelan_attach(void);		/* Create a new device */
 static void
@@ -744,11 +799,7 @@
 /**************************** VARIABLES ****************************/
 
 static dev_info_t dev_info = "wavelan_cs";
-static dev_link_t *dev_list;		/* Linked list of devices */
-
-/* WARNING : the following variable MUST be volatile
- * It is used by wv_82593_cmd to syncronise with wavelan_interrupt */ 
-static volatile int	wv_wait_completed;
+static dev_link_t *dev_list = NULL;	/* Linked list of devices */
 
 /*
  * Parameters that can be set with 'insmod'
@@ -761,7 +812,7 @@
 static int 	irq_list[4] = { -1 };
 
 /* Shared memory speed, in ns */
-static int	mem_speed;
+static int	mem_speed = 0;
 
 /* New module interface */
 MODULE_PARM(irq_mask, "i");
@@ -770,9 +821,12 @@
 
 #ifdef WAVELAN_ROAMING		/* Conditional compile, see above in options */
 /* Enable roaming mode ? No ! Please keep this to 0 */
-static int	do_roaming;
+static int	do_roaming = 0;
 MODULE_PARM(do_roaming, "i");
 #endif	/* WAVELAN_ROAMING */
 
+/* My modifications and rewrite were GPL only - Jean II */
+MODULE_LICENSE("GPL");
+
 #endif	/* WAVELAN_CS_H */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pcmcia/xirc2ps_cs.c linux-2.4.20/drivers/net/pcmcia/xirc2ps_cs.c
--- linux-2.4.19/drivers/net/pcmcia/xirc2ps_cs.c	2001-11-13 17:02:30.000000000 +0000
+++ linux-2.4.20/drivers/net/pcmcia/xirc2ps_cs.c	2002-10-29 11:18:38.000000000 +0000
@@ -74,9 +74,11 @@
 #include <linux/interrupt.h>
 #include <linux/in.h>
 #include <linux/delay.h>
+#include <linux/ethtool.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
+#include <asm/uaccess.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -1715,6 +1717,26 @@
     return 0;
 }
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "xirc2ps_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
 static int
 do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
@@ -1730,6 +1752,8 @@
 	return -EOPNOTSUPP;
 
     switch(cmd) {
+      case SIOCETHTOOL:
+        return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
       case SIOCDEVPRIVATE:	/* Get the address of the PHY in use. */
 	data[0] = 0;		/* we have only this address */
 	/* fall trough */
@@ -2096,7 +2120,7 @@
 	MAYBE_SET(irq_list[1], 7);
 	MAYBE_SET(irq_list[2], 8);
 	MAYBE_SET(irq_list[3], 9);
-#undef  MAYBE_SET(X,Y)
+#undef  MAYBE_SET
 
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pcmcia/xircom_cb.c linux-2.4.20/drivers/net/pcmcia/xircom_cb.c
--- linux-2.4.19/drivers/net/pcmcia/xircom_cb.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/pcmcia/xircom_cb.c	2002-10-29 11:18:34.000000000 +0000
@@ -29,6 +29,8 @@
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 
@@ -174,6 +176,37 @@
 }
 #endif
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "xircom_cb", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
+static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+
+       switch(cmd) {
+       case SIOCETHTOOL:
+	       return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 /* xircom_probe is the code that gets called on device insertion.
    it sets up the hardware and registers the device to the networklayer.
    
@@ -263,6 +296,7 @@
 	dev->stop = &xircom_close;
 	dev->get_stats = &xircom_get_stats;
 	dev->priv = private;
+	dev->do_ioctl = &private_ioctl;
 	pdev->driver_data = dev;
 
 	
@@ -1008,7 +1042,7 @@
 
 
 /* 
-link_status() checks the the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what.
+link_status() checks the link's status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what.
 
 Must be called in locked state with interrupts disabled
 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pcmcia/xircom_tulip_cb.c linux-2.4.20/drivers/net/pcmcia/xircom_tulip_cb.c
--- linux-2.4.19/drivers/net/pcmcia/xircom_tulip_cb.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/pcmcia/xircom_tulip_cb.c	2002-10-29 11:18:33.000000000 +0000
@@ -355,7 +355,7 @@
 	const int strict_bits =
 		TxThresh10 | TxStoreForw | TxThreshMask | EnableTxRx | FullDuplexBit;
     int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200;
-    long flags;
+    unsigned long flags;
     save_flags(flags);
     cli();
 	/* mask out the reserved bits that always read 0 on the Xircom cards */
@@ -1105,9 +1105,6 @@
 					tp->stats.tx_errors++;
 					if (status & Tx0ManyColl) {
 						tp->stats.tx_aborted_errors++;
-#ifdef ETHER_STATS
-						tp->stats.collisions16++;
-#endif
 					}
 					if (status & Tx0NoCarrier) tp->stats.tx_carrier_errors++;
 					if (status & Tx0LateColl) tp->stats.tx_window_errors++;
@@ -1464,7 +1461,7 @@
 	struct xircom_private *tp = dev->priv;
 	u16 *data = (u16 *)&rq->ifr_data;
 	int phy = tp->phys[0] & 0x1f;
-	long flags;
+	unsigned long flags;
 
 	switch(cmd) {
 	case SIOCETHTOOL:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/pcnet32.c linux-2.4.20/drivers/net/pcnet32.c
--- linux-2.4.19/drivers/net/pcnet32.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/pcnet32.c	2002-10-29 11:18:35.000000000 +0000
@@ -22,8 +22,8 @@
  *************************************************************************/
 
 #define DRV_NAME	"pcnet32"
-#define DRV_VERSION	"1.27a"
-#define DRV_RELDATE	"10.02.2002"
+#define DRV_VERSION	"1.27b"
+#define DRV_RELDATE	"01.10.2002"
 #define PFX		DRV_NAME ": "
 
 static const char *version =
@@ -97,6 +97,8 @@
 
 #define PCNET32_DMA_MASK 0xffffffff
 
+#define PCNET32_WATCHDOG_TIMEOUT (jiffies + (2 * HZ))
+
 /*
  * table to translate option values from tulip
  * to internal options
@@ -212,6 +214,8 @@
  *	   fix pci probe not increment cards_found
  *	   FD auto negotiate error workaround for xSeries250
  *	   clean up and using new mii module
+ * v1.27b  Sep 30 2002 Kent Yoder <yoder1@us.ibm.com>
+ * 	   Added timer for cable connection state changes.
  */
 
 
@@ -319,6 +323,7 @@
 	mii:1;				/* mii port available */
     struct net_device	*next;
     struct mii_if_info mii_if;
+    struct timer_list	watchdog_timer;
 };
 
 static void pcnet32_probe_vlbus(void);
@@ -334,6 +339,7 @@
 static struct net_device_stats *pcnet32_get_stats(struct net_device *);
 static void pcnet32_set_multicast_list(struct net_device *);
 static int  pcnet32_ioctl(struct net_device *, struct ifreq *, int);
+static void pcnet32_watchdog(struct net_device *);
 static int mdio_read(struct net_device *dev, int phy_id, int reg_num);
 static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val);
 
@@ -778,6 +784,13 @@
 	}
     }
 
+    /* Set the mii phy_id so that we can query the link state */
+    if (lp->mii)
+	lp->mii_if.phy_id = ((lp->a.read_bcr (ioaddr, 33)) >> 5) & 0x1f;
+
+    init_timer (&lp->watchdog_timer);
+    lp->watchdog_timer.data = (unsigned long) dev;
+    lp->watchdog_timer.function = (void *) &pcnet32_watchdog;
     
     /* The PCNET32-specific entries in the device structure. */
     dev->open = &pcnet32_open;
@@ -902,6 +915,12 @@
 
     netif_start_queue(dev);
 
+    /* If we have mii, print the link status and start the watchdog */
+    if (lp->mii) {
+	mii_check_media (&lp->mii_if, 1, 1);
+	mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
+    }
+    
     i = 0;
     while (i++ < 100)
 	if (lp->a.read_csr (ioaddr, 0) & 0x0100)
@@ -1372,6 +1391,8 @@
     struct pcnet32_private *lp = dev->priv;
     int i;
 
+    del_timer_sync(&lp->watchdog_timer);
+
     netif_stop_queue(dev);
 
     lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);
@@ -1652,6 +1673,17 @@
     return -EOPNOTSUPP;
 }
 
+static void pcnet32_watchdog(struct net_device *dev)
+{
+    struct pcnet32_private *lp = dev->priv;
+
+    /* Print the link status if it has changed */
+    if (lp->mii)
+	mii_check_media (&lp->mii_if, 1, 0);
+
+    mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
+}
+
 static struct pci_driver pcnet32_driver = {
     name:	DRV_NAME,
     probe:	pcnet32_probe_pci,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/ppp_deflate.c linux-2.4.20/drivers/net/ppp_deflate.c
--- linux-2.4.19/drivers/net/ppp_deflate.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/ppp_deflate.c	2002-10-29 11:18:37.000000000 +0000
@@ -39,7 +39,7 @@
 #include <linux/ppp_defs.h>
 #include <linux/ppp-comp.h>
 
-#include "zlib.c"
+#include <linux/zlib.h>
 
 /*
  * State for a Deflate (de)compressor.
@@ -56,10 +56,6 @@
 
 #define DEFLATE_OVHD	2		/* Deflate overhead/packet */
 
-static void	*zalloc __P((void *, unsigned int items, unsigned int size));
-static void	*zalloc_init __P((void *, unsigned int items,
-				  unsigned int size));
-static void	zfree __P((void *, void *ptr));
 static void	*z_comp_alloc __P((unsigned char *options, int opt_len));
 static void	*z_decomp_alloc __P((unsigned char *options, int opt_len));
 static void	z_comp_free __P((void *state));
@@ -80,72 +76,6 @@
 static void	z_decomp_reset __P((void *state));
 static void	z_comp_stats __P((void *state, struct compstat *stats));
 
-struct chunk_header {
-	int valloced;		/* allocated with valloc, not kmalloc */
-	int guard;		/* check for overwritten header */
-};
-
-#define GUARD_MAGIC	0x77a8011a
-#define MIN_VMALLOC	2048	/* use kmalloc for blocks < this */
-
-/*
- * Space allocation and freeing routines for use by zlib routines.
- */
-void
-zfree(arg, ptr)
-    void *arg;
-    void *ptr;
-{
-	struct chunk_header *hdr = ((struct chunk_header *)ptr) - 1;
-
-	if (hdr->guard != GUARD_MAGIC) {
-		printk(KERN_WARNING "zfree: header corrupted (%x %x) at %p\n",
-		       hdr->valloced, hdr->guard, hdr);
-		return;
-	}
-	if (hdr->valloced)
-		vfree(hdr);
-	else
-		kfree(hdr);
-}
-
-void *
-zalloc(arg, items, size)
-    void *arg;
-    unsigned int items, size;
-{
-	struct chunk_header *hdr;
-	unsigned nbytes;
-
-	nbytes = items * size + sizeof(*hdr);
-	hdr = kmalloc(nbytes, GFP_ATOMIC);
-	if (hdr == 0)
-		return 0;
-	hdr->valloced = 0;
-	hdr->guard = GUARD_MAGIC;
-	return (void *) (hdr + 1);
-}
-
-void *
-zalloc_init(arg, items, size)
-    void *arg;
-    unsigned int items, size;
-{
-	struct chunk_header *hdr;
-	unsigned nbytes;
-
-	nbytes = items * size + sizeof(*hdr);
-	if (nbytes >= MIN_VMALLOC)
-		hdr = vmalloc(nbytes);
-	else
-		hdr = kmalloc(nbytes, GFP_KERNEL);
-	if (hdr == 0)
-		return 0;
-	hdr->valloced = nbytes >= MIN_VMALLOC;
-	hdr->guard = GUARD_MAGIC;
-	return (void *) (hdr + 1);
-}
-
 static void
 z_comp_free(arg)
     void *arg;
@@ -153,7 +83,9 @@
 	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
 
 	if (state) {
-		deflateEnd(&state->strm);
+		zlib_deflateEnd(&state->strm);
+		if (state->strm.workspace)
+			vfree(state->strm.workspace);
 		kfree(state);
 		MOD_DEC_USE_COUNT;
 	}
@@ -180,27 +112,27 @@
 	if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
 		return NULL;
 
-	state = (struct ppp_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL);
+	state = (struct ppp_deflate_state *) kmalloc(sizeof(*state),
+						     GFP_KERNEL);
 	if (state == NULL)
 		return NULL;
 
 	MOD_INC_USE_COUNT;
 	memset (state, 0, sizeof (struct ppp_deflate_state));
-	state->strm.next_in = NULL;
-	state->strm.zalloc  = zalloc_init;
-	state->strm.zfree   = zfree;
-	state->w_size       = w_size;
+	state->strm.next_in   = NULL;
+	state->w_size         = w_size;
+	state->strm.workspace = vmalloc(zlib_deflate_workspacesize());
+	if (state->strm.workspace == NULL)
+		goto out_free;
 
-	if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,
+	if (zlib_deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,
 			 DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY)
 	    != Z_OK)
 		goto out_free;
-	state->strm.zalloc = zalloc;
 	return (void *) state;
 
 out_free:
 	z_comp_free(state);
-	MOD_DEC_USE_COUNT;
 	return NULL;
 }
 
@@ -224,7 +156,7 @@
 	state->unit  = unit;
 	state->debug = debug;
 
-	deflateReset(&state->strm);
+	zlib_deflateReset(&state->strm);
 
 	return 1;
 }
@@ -236,7 +168,7 @@
 	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
 
 	state->seqno = 0;
-	deflateReset(&state->strm);
+	zlib_deflateReset(&state->strm);
 }
 
 int
@@ -286,7 +218,7 @@
 	state->strm.avail_in = (isize - off);
 
 	for (;;) {
-		r = deflate(&state->strm, Z_PACKET_FLUSH);
+		r = zlib_deflate(&state->strm, Z_PACKET_FLUSH);
 		if (r != Z_OK) {
 			if (state->debug)
 				printk(KERN_ERR
@@ -337,7 +269,9 @@
 	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
 
 	if (state) {
-		inflateEnd(&state->strm);
+		zlib_inflateEnd(&state->strm);
+		if (state->strm.workspace)
+			kfree(state->strm.workspace);
 		kfree(state);
 		MOD_DEC_USE_COUNT;
 	}
@@ -370,19 +304,19 @@
 
 	MOD_INC_USE_COUNT;
 	memset (state, 0, sizeof (struct ppp_deflate_state));
-	state->w_size        = w_size;
-	state->strm.next_out = NULL;
-	state->strm.zalloc   = zalloc_init;
-	state->strm.zfree    = zfree;
+	state->w_size         = w_size;
+	state->strm.next_out  = NULL;
+	state->strm.workspace = kmalloc(zlib_inflate_workspacesize(),
+					GFP_KERNEL);
+	if (state->strm.workspace == NULL)
+		goto out_free;
 
-	if (inflateInit2(&state->strm, -w_size) != Z_OK)
+	if (zlib_inflateInit2(&state->strm, -w_size) != Z_OK)
 		goto out_free;
-	state->strm.zalloc = zalloc;
 	return (void *) state;
 
 out_free:
 	z_decomp_free(state);
-	MOD_DEC_USE_COUNT;
 	return NULL;
 }
 
@@ -407,7 +341,7 @@
 	state->debug = debug;
 	state->mru   = mru;
 
-	inflateReset(&state->strm);
+	zlib_inflateReset(&state->strm);
 
 	return 1;
 }
@@ -419,7 +353,7 @@
 	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
 
 	state->seqno = 0;
-	inflateReset(&state->strm);
+	zlib_inflateReset(&state->strm);
 }
 
 /*
@@ -492,7 +426,7 @@
 	 * Call inflate, supplying more input or output as needed.
 	 */
 	for (;;) {
-		r = inflate(&state->strm, Z_PACKET_FLUSH);
+		r = zlib_inflate(&state->strm, Z_PACKET_FLUSH);
 		if (r != Z_OK) {
 			if (state->debug)
 				printk(KERN_DEBUG "z_decompress%d: inflate returned %d (%s)\n",
@@ -575,7 +509,7 @@
 		++state->strm.avail_in;
 	}
 
-	r = inflateIncomp(&state->strm);
+	r = zlib_inflateIncomp(&state->strm);
 	if (r != Z_OK) {
 		/* gak! */
 		if (state->debug) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/ppp_generic.c linux-2.4.20/drivers/net/ppp_generic.c
--- linux-2.4.19/drivers/net/ppp_generic.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/ppp_generic.c	2002-10-29 11:18:38.000000000 +0000
@@ -378,7 +378,7 @@
 {
 	struct ppp_file *pf = file->private_data;
 	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
+	ssize_t ret = 0;
 	struct sk_buff *skb = 0;
 
 	if (pf == 0)
@@ -404,19 +404,19 @@
 	remove_wait_queue(&pf->rwait, &wait);
 
 	if (skb == 0)
-		goto out;
+		goto err1;
 
 	ret = -EOVERFLOW;
 	if (skb->len > count)
-		goto outf;
+		goto err2;
 	ret = -EFAULT;
 	if (copy_to_user(buf, skb->data, skb->len))
-		goto outf;
+		goto err2;
 	ret = skb->len;
 
- outf:
+ err2:
 	kfree_skb(skb);
- out:
+ err1:
 	return ret;
 }
 
@@ -432,12 +432,12 @@
 	ret = -ENOMEM;
 	skb = alloc_skb(count + pf->hdrlen, GFP_KERNEL);
 	if (skb == 0)
-		goto out;
+		goto err1;
 	skb_reserve(skb, pf->hdrlen);
 	ret = -EFAULT;
 	if (copy_from_user(skb_put(skb, count), buf, count)) {
 		kfree_skb(skb);
-		goto out;
+		goto err1;
 	}
 
 	skb_queue_tail(&pf->xq, skb);
@@ -453,7 +453,7 @@
 
 	ret = count;
 
- out:
+ err1:
 	return ret;
 }
 
@@ -806,7 +806,7 @@
 
 	npi = ethertype_to_npindex(ntohs(skb->protocol));
 	if (npi < 0)
-		goto outf;
+		goto err1;
 
 	/* Drop, accept or reject the packet */
 	switch (ppp->npmode[npi]) {
@@ -815,10 +815,10 @@
 	case NPMODE_QUEUE:
 		/* it would be nice to have a way to tell the network
 		   system to queue this one up for later. */
-		goto outf;
+		goto err1;
 	case NPMODE_DROP:
 	case NPMODE_ERROR:
-		goto outf;
+		goto err1;
 	}
 
 	/* Put the 2-byte PPP protocol number on the front,
@@ -828,7 +828,7 @@
 
 		ns = alloc_skb(skb->len + dev->hard_header_len, GFP_ATOMIC);
 		if (ns == 0)
-			goto outf;
+			goto err1;
 		skb_reserve(ns, dev->hard_header_len);
 		memcpy(skb_put(ns, skb->len), skb->data, skb->len);
 		kfree_skb(skb);
@@ -844,7 +844,7 @@
 	ppp_xmit_process(ppp);
 	return 0;
 
- outf:
+ err1:
 	kfree_skb(skb);
 	++ppp->stats.tx_dropped;
 	return 0;
@@ -1945,11 +1945,11 @@
 	if (copy_from_user(&data, (void *) arg, sizeof(data))
 	    || (data.length <= CCP_MAX_OPTION_LENGTH
 		&& copy_from_user(ccp_option, data.ptr, data.length)))
-		goto out;
+		goto err1;
 	err = -EINVAL;
 	if (data.length > CCP_MAX_OPTION_LENGTH
 	    || ccp_option[1] < 2 || ccp_option[1] > data.length)
-		goto out;
+		goto err1;
 
 	cp = find_compressor(ccp_option[0]);
 #ifdef CONFIG_KMOD
@@ -1960,7 +1960,7 @@
 	}
 #endif /* CONFIG_KMOD */
 	if (cp == 0)
-		goto out;
+		goto err1;
 	/*
 	 * XXX race: the compressor module could get unloaded between
 	 * here and when we do the comp_alloc or decomp_alloc call below.
@@ -1998,7 +1998,7 @@
 		}
 	}
 
- out:
+ err1:
 	return err;
 }
 
@@ -2144,15 +2144,15 @@
 	spin_lock(&compressor_list_lock);
 	ret = -EEXIST;
 	if (find_comp_entry(cp->compress_proto) != 0)
-		goto out;
+		goto err1;
 	ret = -ENOMEM;
 	ce = kmalloc(sizeof(struct compressor_entry), GFP_ATOMIC);
 	if (ce == 0)
-		goto out;
+		goto err1;
 	ret = 0;
 	ce->comp = cp;
 	list_add(&ce->list, &compressor_list);
- out:
+ err1:
 	spin_unlock(&compressor_list_lock);
 	return ret;
 }
@@ -2431,11 +2431,12 @@
 	down(&all_ppp_sem);
 	ppp = ppp_find_unit(unit);
 	if (ppp == 0)
-		goto out;
+		goto err1;
+
 	write_lock_bh(&pch->upl);
 	ret = -EINVAL;
 	if (pch->ppp != 0)
-		goto outl;
+		goto err2;
 
 	ppp_lock(ppp);
 	if (pch->file.hdrlen > ppp->file.hdrlen)
@@ -2450,9 +2451,9 @@
 	ppp_unlock(ppp);
 	ret = 0;
 
- outl:
+ err2:
 	write_unlock_bh(&pch->upl);
- out:
+ err1:
 	up(&all_ppp_sem);
 	return ret;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/rcpci45.c linux-2.4.20/drivers/net/rcpci45.c
--- linux-2.4.19/drivers/net/rcpci45.c	2002-02-25 19:37:59.000000000 +0000
+++ linux-2.4.20/drivers/net/rcpci45.c	2002-10-29 11:18:35.000000000 +0000
@@ -102,8 +102,6 @@
 
 static void rc_timer (unsigned long);
 
-static int RCinit (struct net_device *);
-
 static int RCopen (struct net_device *);
 static int RC_xmit_packet (struct sk_buff *, struct net_device *);
 static void RCinterrupt (int, void *, struct pt_regs *);
@@ -167,7 +165,7 @@
 	 * API private area, which requires a minimum of 16KB.  The top 
 	 * of the allocated area will be assigned to struct net_device; 
 	 * the next chunk will be assigned to DPA; and finally, the rest 
-	 * will be assigned to the the LAN API layer.
+	 * will be assigned to the LAN API layer.
 	 */
 
 	dev = init_etherdev (NULL, sizeof (*pDpa));
@@ -188,7 +186,7 @@
 	error = -ENOMEM;
 	pci_start = pci_resource_start (pdev, 0);
 	pci_len = pci_resource_len (pdev, 0);
-	printk("pci_start %x pci_len %x\n", pci_start, pci_len);
+	printk("pci_start %lx pci_len %lx\n", pci_start, pci_len);
 
 	pci_set_drvdata (pdev, dev);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/sb1000.c linux-2.4.20/drivers/net/sb1000.c
--- linux-2.4.19/drivers/net/sb1000.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/sb1000.c	2002-10-29 11:18:32.000000000 +0000
@@ -276,7 +276,7 @@
  * SB1000 hardware routines to be used during open/configuration phases
  */
 
-const int TimeOutJiffies = (int)(8.75 * HZ);
+const int TimeOutJiffies = (875 * HZ) / 100;
 
 static inline void nicedelay(unsigned long usecs)
 {
@@ -299,7 +299,7 @@
 		current->state = TASK_INTERRUPTIBLE;
 		schedule_timeout(0);
 		a = inb(ioaddr[0] + 7);
-		if (jiffies >= timeout) {
+		if (time_after_eq(jiffies, timeout)) {
 			printk(KERN_WARNING "%s: card_wait_for_busy_clear timeout\n",
 				name);
 			return -ETIME;
@@ -323,7 +323,7 @@
 		current->state = TASK_INTERRUPTIBLE;
 		schedule_timeout(0);
 		a = inb(ioaddr[1] + 6);
-		if (jiffies >= timeout) {
+		if (time_after_eq(jiffies, timeout)) {
 			printk(KERN_WARNING "%s: card_wait_for_ready timeout\n",
 				name);
 			return -ETIME;
@@ -397,7 +397,7 @@
 
 	timeout = jiffies + Sb1000TimeOutJiffies;
 	while (inb(ioaddr[1] + 6) & 0x80) {
-		if (jiffies >= timeout) {
+		if (time_after_eq(jiffies, timeout)) {
 			printk(KERN_WARNING "%s: sb1000_wait_for_ready timeout\n",
 				name);
 			return -ETIME;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/sb1250-mac.c linux-2.4.20/drivers/net/sb1250-mac.c
--- linux-2.4.19/drivers/net/sb1250-mac.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/sb1250-mac.c	2002-10-29 11:18:32.000000000 +0000
@@ -24,6 +24,9 @@
 */
 
 
+
+#define CONFIG_SBMAC_COALESCE
+
 /* A few user-configurable values.
    These may be modified when a driver module is loaded. */
 
@@ -41,6 +44,8 @@
 static int full_duplex[MAX_UNITS] = {-1, -1, -1};
 #endif
 
+static int int_pktcnt = 0;
+static int int_timeout = 0;
 
 /* Operational parameters that usually are not changed. */
 
@@ -53,21 +58,20 @@
 #error  You must compile this driver with "-O".
 #endif
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
+#include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/compiler.h>
-#include <asm/processor.h>
+#include <linux/config.h>
+#include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/sibyte/sb1250.h>
@@ -75,7 +79,7 @@
 
 /* This is only here until the firmware is ready.  In that case,
    the firmware leaves the ethernet address in the register for us. */
-#ifdef CONFIG_SWARM_STANDALONE
+#ifdef CONFIG_SIBYTE_STANDALONE
 #define SBMAC_ETH0_HWADDR "40:00:00:00:01:00"
 #define SBMAC_ETH1_HWADDR "40:00:00:00:01:01"
 #define SBMAC_ETH2_HWADDR "40:00:00:00:01:02"
@@ -96,12 +100,15 @@
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 
+MODULE_PARM(int_pktcnt, "i");
+MODULE_PARM(int_timeout, "i");
 
 #include <asm/sibyte/sb1250_defs.h>
 #include <asm/sibyte/sb1250_regs.h>
 #include <asm/sibyte/sb1250_mac.h>
 #include <asm/sibyte/sb1250_dma.h>
 #include <asm/sibyte/sb1250_int.h>
+#include <asm/sibyte/sb1250_scd.h>		/* Only to check SOC part number. */
 
 
 /**********************************************************************
@@ -152,7 +159,8 @@
 
 #define ETHER_ALIGN	2
 #define ETHER_ADDR_LEN	6
-#define ENET_PACKET_SIZE	1518
+#define ENET_PACKET_SIZE	1518 
+/*#define ENET_PACKET_SIZE	9216 */ 
 
 /**********************************************************************
  *  DMA Descriptor structure
@@ -179,8 +187,13 @@
 	
 	struct sbmac_softc *sbdma_eth;	        /* back pointer to associated MAC */
 	int              sbdma_channel;	/* channel number */
-	int		     sbdma_txdir;       /* direction (1=transmit) */
-	int		     sbdma_maxdescr;	/* total # of descriptors in ring */
+	int		 sbdma_txdir;       /* direction (1=transmit) */
+	int		 sbdma_maxdescr;	/* total # of descriptors in ring */
+#ifdef CONFIG_SBMAC_COALESCE
+        int              sbdma_int_pktcnt;  /* # descriptors rx before interrupt*/
+        int              sbdma_int_timeout; /* # usec rx interrupt */
+#endif
+
 	sbmac_port_t     sbdma_config0;	/* DMA config register 0 */
 	sbmac_port_t     sbdma_config1;	/* DMA config register 1 */
 	sbmac_port_t     sbdma_dscrbase;	/* Descriptor base address */
@@ -208,11 +221,13 @@
  ********************************************************************* */
 
 struct sbmac_softc {
+	
 	/*
 	 * Linux-specific things
 	 */
-	struct net_device *sbm_dev;
-	spinlock_t sbm_lock;
+	
+	struct net_device *sbm_dev;		/* pointer to linux device */
+	spinlock_t sbm_lock;		/* spin lock */
 	struct timer_list sbm_timer;     	/* for monitoring MII */
 	struct net_device_stats sbm_stats; 
 	int sbm_devflags;			/* current device flags */
@@ -222,15 +237,16 @@
         int	     sbm_phy_oldk1stsr;
         int          sbm_phy_oldlinkstat;
 	int sbm_buffersize;
-
+	
 	unsigned char sbm_phys[2];
-
+	
 	/*
 	 * Controller-specific things
 	 */
+	
 	sbmac_port_t     sbm_base;          /* MAC's base address */
 	sbmac_state_t    sbm_state;         /* current state */
-
+	
 	sbmac_port_t     sbm_macenable;	/* MAC Enable Register */
 	sbmac_port_t     sbm_maccfg;	/* MAC Configuration Register */
 	sbmac_port_t     sbm_fifocfg;	/* FIFO configuration register */
@@ -239,15 +255,18 @@
 	sbmac_port_t     sbm_isr;		/* Interrupt status register */
 	sbmac_port_t     sbm_imr;		/* Interrupt mask register */
 	sbmac_port_t     sbm_mdio;		/* MDIO register */
-
+	
 	sbmac_speed_t    sbm_speed;		/* current speed */
 	sbmac_duplex_t   sbm_duplex;	/* current duplex */
 	sbmac_fc_t       sbm_fc;		/* current flow control setting */
 	
 	u_char           sbm_hwaddr[ETHER_ADDR_LEN];
-
+	
 	sbmacdma_t       sbm_txdma;		/* for now, only use channel 0 */
 	sbmacdma_t       sbm_rxdma;
+	int              rx_hw_checksum;
+	int 		 sbe_idx;
+	
 };
 
 
@@ -264,7 +283,7 @@
 			  int chan,
 			  int txrx,
 			  int maxdescr);
-static void sbdma_channel_start(sbmacdma_t *d);
+static void sbdma_channel_start(sbmacdma_t *d, int rxtx);
 static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *m);
 static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m);
 static void sbdma_emptyring(sbmacdma_t *d);
@@ -305,6 +324,9 @@
  *  Globals
  ********************************************************************* */
 
+static uint64_t sbmac_orig_hwaddr[MAX_UNITS];
+static uint64_t chip_revision;
+
 
 /**********************************************************************
  *  MDIO constants
@@ -325,7 +347,7 @@
 #define BMCR_DUPLEX    0x0100
 #define BMCR_COLTEST   0x0080
 #define BMCR_SPEED1    0x0040
-#define BMCR_SPEED1000 (BMCR_SPEED1|BMCR_SPEED0)
+#define BMCR_SPEED1000 (BMCR_SPEED1)
 #define BMCR_SPEED100  (BMCR_SPEED0)
 #define BMCR_SPEED10 	0
 
@@ -434,8 +456,10 @@
 
 #define M_MAC_MDIO_DIR_OUTPUT	0		/* for clarity */
 
+#define ENABLE 		1
+#define DISABLE		0
 
-/*
+/**********************************************************************
  *  SBMAC_MII_SYNC(s)
  *  
  *  Synchronize with the MII - send a pattern of bits to the MII
@@ -446,7 +470,8 @@
  *  	   
  *  Return value:
  *  	   nothing
- */
+ ********************************************************************* */
+
 static void sbmac_mii_sync(struct sbmac_softc *s)
 {
 	int cnt;
@@ -462,7 +487,7 @@
 	}
 }
 
-/*
+/**********************************************************************
  *  SBMAC_MII_SENDDATA(s,data,bitcnt)
  *  
  *  Send some bits to the MII.  The bits to be sent are right-
@@ -472,7 +497,8 @@
  *  	   s - sbmac structure
  *  	   data - data to send
  *  	   bitcnt - number of bits to send
- */
+ ********************************************************************* */
+
 static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt)
 {
 	int i;
@@ -494,7 +520,9 @@
 	}
 }
 
-/*
+
+
+/**********************************************************************
  *  SBMAC_MII_READ(s,phyaddr,regidx)
  *  
  *  Read a PHY register.
@@ -506,7 +534,8 @@
  *  	   
  *  Return value:
  *  	   value read, or 0 if an error occured.
- */
+ ********************************************************************* */
+
 static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
 {
 	int idx;
@@ -578,7 +607,7 @@
 }
 
 
-/*
+/**********************************************************************
  *  SBMAC_MII_WRITE(s,phyaddr,regidx,regval)
  *  
  *  Write a value to a PHY register.
@@ -591,7 +620,8 @@
  *  	   
  *  Return value:
  *  	   nothing
- */
+ ********************************************************************* */
+
 static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
 			    unsigned int regval)
 {
@@ -610,7 +640,7 @@
 
 
 
-/*
+/**********************************************************************
  *  SBDMA_INITCTX(d,s,chan,txrx,maxdescr)
  *  
  *  Initialize a DMA channel context.  Since there are potentially
@@ -626,7 +656,8 @@
  *  	   
  *  Return value:
  *  	   nothing
- */
+ ********************************************************************* */
+
 static void sbdma_initctx(sbmacdma_t *d,
 			  struct sbmac_softc *s,
 			  int chan,
@@ -641,6 +672,52 @@
 	d->sbdma_channel   = chan;
 	d->sbdma_txdir     = txrx;
 	
+	/* RMON clearing */
+	s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING;
+
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR)), 0);
+	SBMAC_WRITECSR(PKSEG1(
+        A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR)), 0);
+
 	/* 
 	 * initialize register pointers 
 	 */
@@ -648,7 +725,7 @@
 	d->sbdma_config0 = 
 		PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0));
 	d->sbdma_config1 = 
-		PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0));
+		PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG1));
 	d->sbdma_dscrbase = 
 		PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_BASE));
 	d->sbdma_dscrcnt = 
@@ -680,42 +757,120 @@
 	
 	memset(d->sbdma_ctxtable,0,d->sbdma_maxdescr*sizeof(struct sk_buff *));
 	
+#ifdef CONFIG_SBMAC_COALESCE
+        /*
+         * Setup Rx DMA coalescing defaults
+         */
+
+        if ( txrx == DMA_RX ) {
+		if ( int_pktcnt ) {
+                	d->sbdma_int_pktcnt = int_pktcnt;
+		        }
+		else {
+                	d->sbdma_int_pktcnt = 1;
+		        }
+
+		if ( int_timeout ) {
+		        d->sbdma_int_timeout = int_timeout;
+		        }
+		else {
+		        d->sbdma_int_timeout = 0;
+		    }
+	        }
+        else {
+                d->sbdma_int_pktcnt = 0;
+                d->sbdma_int_timeout = 0;
+	        }
+#endif
+
 }
 
-/*
+/**********************************************************************
  *  SBDMA_CHANNEL_START(d)
  *  
  *  Initialize the hardware registers for a DMA channel.
  *  
  *  Input parameters: 
  *  	   d - DMA channel to init (context must be previously init'd
+ *         rxtx - DMA_RX or DMA_TX depending on what type of channel
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
+
+static void sbdma_channel_start(sbmacdma_t *d, int rxtx )
+{
+    /*
+     * Turn on the DMA channel
+     */
+	
+#ifdef CONFIG_SBMAC_COALESCE
+    if (rxtx == DMA_RX) {
+        SBMAC_WRITECSR(d->sbdma_config1,
+		       V_DMA_INT_TIMEOUT(d->sbdma_int_timeout) |
+		       0);
+        SBMAC_WRITECSR(d->sbdma_config0,
+                       M_DMA_EOP_INT_EN |
+                       V_DMA_RINGSZ(d->sbdma_maxdescr) |
+                       V_DMA_INT_PKTCNT(d->sbdma_int_pktcnt) |
+                       0);
+	}
+    else {
+	SBMAC_WRITECSR(d->sbdma_config1,0);
+	SBMAC_WRITECSR(d->sbdma_config0,
+		       V_DMA_RINGSZ(d->sbdma_maxdescr) |
+		       0);
+	}
+#else
+    SBMAC_WRITECSR(d->sbdma_config1,0);
+    SBMAC_WRITECSR(d->sbdma_config0,
+		   V_DMA_RINGSZ(d->sbdma_maxdescr) |
+		   0);
+#endif
+
+	
+    SBMAC_WRITECSR(d->sbdma_dscrbase,d->sbdma_dscrtable_phys);
+	
+    /*
+     * Initialize ring pointers
+     */
+	
+    d->sbdma_addptr = d->sbdma_dscrtable;
+    d->sbdma_remptr = d->sbdma_dscrtable;
+}
+
+/**********************************************************************
+ *  SBDMA_CHANNEL_STOP(d)
+ *  
+ *  Initialize the hardware registers for a DMA channel.
+ *  
+ *  Input parameters: 
+ *  	   d - DMA channel to init (context must be previously init'd
  *  	   
  *  Return value:
  *  	   nothing
- */
-static void sbdma_channel_start(sbmacdma_t *d)
+ ********************************************************************* */
+
+static void sbdma_channel_stop(sbmacdma_t *d)
 {
 	/*
-	 * Turn on the DMA channel
+	 * Turn off the DMA channel
 	 */
 	
 	SBMAC_WRITECSR(d->sbdma_config1,0);
 	
-	SBMAC_WRITECSR(d->sbdma_dscrbase,d->sbdma_dscrtable_phys);
+	SBMAC_WRITECSR(d->sbdma_dscrbase,0);
 	
-	SBMAC_WRITECSR(d->sbdma_config0,
-		       V_DMA_RINGSZ(d->sbdma_maxdescr) |
-		       0);
+	SBMAC_WRITECSR(d->sbdma_config0,0);
 	
 	/*
-	 * Initialize ring pointers
+	 * Zero ring pointers
 	 */
 	
-	d->sbdma_addptr = d->sbdma_dscrtable;
-	d->sbdma_remptr = d->sbdma_dscrtable;
+	d->sbdma_addptr = 0;
+	d->sbdma_remptr = 0;
 }
 
-
 static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset)
 {
 	unsigned long addr;
@@ -728,7 +883,8 @@
 	skb_reserve(skb,newaddr-addr+offset);
 }
 
-/*
+
+/**********************************************************************
  *  SBDMA_ADD_RCVBUFFER(d,sb)
  *  
  *  Add a buffer to the specified DMA channel.   For receive channels,
@@ -741,7 +897,9 @@
  *  Return value:
  *  	   0 if buffer could not be added (ring is full)
  *  	   1 if buffer added successfully
- */
+ ********************************************************************* */
+
+
 static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
 {
 	sbdmadscr_t *dsc;
@@ -774,7 +932,7 @@
 	 *
 	 *    1. the data does not start in the middle of a cache line.
 	 *    2. The data does not end in the middle of a cache line
-	 * 	  3. The buffer can be aligned such that the IP addresses are 
+	 *    3. The buffer can be aligned such that the IP addresses are 
 	 *       naturally aligned.
 	 *
 	 *  Remember, the SB1250's MAC writes whole cache lines at a time,
@@ -808,9 +966,18 @@
 	 * fill in the descriptor 
 	 */
 	
+#ifdef CONFIG_SBMAC_COALESCE
+        /*
+         * Do not interrupt per DMA transfer.
+         */
+        dsc->dscr_a = KVTOPHYS(sb_new->tail) |
+                V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
+                0;
+#else
 	dsc->dscr_a = KVTOPHYS(sb_new->tail) |
 		V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
 		M_DMA_DSCRA_INTERRUPT;
+#endif
 	
 	/* receiving: no options */
 	dsc->dscr_b = 0;
@@ -836,7 +1003,7 @@
 	return 0;					/* we did it */
 }
 
-/*
+/**********************************************************************
  *  SBDMA_ADD_TXBUFFER(d,sb)
  *  
  *  Add a transmit buffer to the specified DMA channel, causing a
@@ -849,7 +1016,9 @@
  *  Return value:
  *  	   0 transmit queued successfully
  *  	   otherwise error code
- */
+ ********************************************************************* */
+
+
 static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb)
 {
 	sbdmadscr_t *dsc;
@@ -922,6 +1091,9 @@
 	return 0;					/* we did it */
 }
 
+
+
+
 /**********************************************************************
  *  SBDMA_EMPTYRING(d)
  *  
@@ -960,17 +1132,19 @@
  *  	   
  *  Return value:
  *  	   nothing
- */
+ ********************************************************************* */
+
 static void sbdma_fillring(sbmacdma_t *d)
 {
 	int idx;
 	
-	for (idx = 0; idx < SBMAC_MAX_RXDESCR-1; idx++)
-		if (sbdma_add_rcvbuffer(d, NULL) != 0)
-			break;
+	for (idx = 0; idx < SBMAC_MAX_RXDESCR-1; idx++) {
+		if (sbdma_add_rcvbuffer(d,NULL) != 0) break;
+	}
 }
 
-/*
+
+/**********************************************************************
  *  SBDMA_RX_PROCESS(sc,d)
  *  
  *  Process "completed" receive buffers on the specified DMA channel.  
@@ -984,7 +1158,8 @@
  *  	   
  *  Return value:
  *  	   nothing
- */
+ ********************************************************************* */
+
 static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
 {
 	int curidx;
@@ -1004,72 +1179,97 @@
 		 * just compare the low-order bits of the virtual address
 		 * (sbdma_remptr) and the physical address (sbdma_curdscr CSR)
 		 */
+		
 		curidx = d->sbdma_remptr - d->sbdma_dscrtable;
 		hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
 				d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
-
+		
 		/*
 		 * If they're the same, that means we've processed all
 		 * of the descriptors up to (but not including) the one that
 		 * the hardware is working on right now.
 		 */
-		if (curidx == hwidx)
-			break;
-
+		
+		if (curidx == hwidx) break;
+		
 		/*
 		 * Otherwise, get the packet's sk_buff ptr back
 		 */
-		dsc = d->sbdma_dscrtable + curidx;
+		
+		dsc = &(d->sbdma_dscrtable[curidx]);
 		sb = d->sbdma_ctxtable[curidx];
 		d->sbdma_ctxtable[curidx] = NULL;
-
+		
 		len = (int)G_DMA_DSCRB_PKT_SIZE(dsc->dscr_b) - 4;
-
+		
 		/*
 		 * Check packet status.  If good, process it.
 		 * If not, silently drop it and put it back on the
 		 * receive ring.
 		 */
+		
 		if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) {
+			
 			/*
 			 * Set length into the packet
 			 */
 			skb_put(sb,len);
-
+			
        			/*
 			 * Add a new buffer to replace the old one.  If we fail
 			 * to allocate a buffer, we're going to drop this
 			 * packet and put it right back on the receive ring.
 			 */
-			if (sbdma_add_rcvbuffer(d, NULL) == -ENOBUFS) {
-				sbdma_add_rcvbuffer(d,sb);	/* re-add old buffer */
-			} else {
-				/*
-				 * Buffer has been replaced on the receive ring.
-				 * Pass the buffer to the kernel
-				 */
-				sc->sbm_stats.rx_bytes += len;
-				sc->sbm_stats.rx_packets++;
-				sb->protocol = eth_type_trans(sb,
-							d->sbdma_eth->sbm_dev);
-				netif_rx(sb);
-			}
-		} else {
+			
+			if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) {
+			    sbdma_add_rcvbuffer(d,sb);	/* re-add old buffer */
+			    }
+			else {
+			    /*
+			     * Buffer has been replaced on the receive ring.
+			     * Pass the buffer to the kernel
+			     */
+			    sc->sbm_stats.rx_bytes += len;
+			    sc->sbm_stats.rx_packets++;
+			    sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev);
+                            if (sc->rx_hw_checksum == ENABLE) {
+			    /* if the ip checksum is good indicate in skb.
+		                else set CHECKSUM_NONE as device failed to
+					checksum the packet */
+
+			       if (((dsc->dscr_b) |M_DMA_ETHRX_BADTCPCS) ||
+			     	  ((dsc->dscr_a)| M_DMA_ETHRX_BADIP4CS)){
+				  sb->ip_summed = CHECKSUM_NONE;
+			       } else {
+				 printk(KERN_DEBUG "hw checksum fail .\n");
+				 sb->ip_summed = CHECKSUM_UNNECESSARY;
+			       }
+			    } /*rx_hw_checksum */
+
+			    netif_rx(sb);
+			    }
+		}
+		else {
 			/*
 			 * Packet was mangled somehow.  Just drop it and
 			 * put it back on the receive ring.
 			 */
 			sbdma_add_rcvbuffer(d,sb);
 		}
-
+		
+		
 		/* 
 		 * .. and advance to the next buffer.
 		 */
+		
 		d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+		
 	}
 }
 
-/*
+
+
+/**********************************************************************
  *  SBDMA_TX_PROCESS(sc,d)
  *  
  *  Process "completed" transmit buffers on the specified DMA channel.  
@@ -1084,7 +1284,8 @@
  *  	   
  *  Return value:
  *  	   nothing
- */
+ ********************************************************************* */
+
 static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
 {
 	int curidx;
@@ -1093,8 +1294,8 @@
 	struct sk_buff *sb;
 	unsigned long flags;
 
-	spin_lock_irqsave(&sc->sbm_lock, flags);
-
+	spin_lock_irqsave(&(sc->sbm_lock), flags);
+	
 	for (;;) {
 		/* 
 		 * figure out where we are (as an index) and where
@@ -1125,59 +1326,64 @@
 			*/
 			  
 			uint64_t tmp = SBMAC_READCSR(d->sbdma_curdscr);
-			if (!tmp)
+			if (!tmp) {
 				break;
-
+			}
 			hwidx = (int) (((tmp & M_DMA_CURDSCR_ADDR) -
 					d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
 		}
-
 		/*
 		 * If they're the same, that means we've processed all
 		 * of the descriptors up to (but not including) the one that
 		 * the hardware is working on right now.
 		 */
-		if (curidx == hwidx)
-			break;
+		
+		if (curidx == hwidx) break;
 		
 		/*
 		 * Otherwise, get the packet's sk_buff ptr back
 		 */
-		dsc = d->sbdma_dscrtable + curidx;
+		
+		dsc = &(d->sbdma_dscrtable[curidx]);
 		sb = d->sbdma_ctxtable[curidx];
 		d->sbdma_ctxtable[curidx] = NULL;
-
+		
 		/*
 		 * Stats
 		 */
+		
 		sc->sbm_stats.tx_bytes += sb->len;
 		sc->sbm_stats.tx_packets++;
-
+		
 		/*
 		 * for transmits, we just free buffers.
 		 */
+		
 		dev_kfree_skb_irq(sb);
-
+		
 		/* 
 		 * .. and advance to the next buffer.
 		 */
+
 		d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
 		
 	}
-
+	
 	/*
 	 * Decide if we should wake up the protocol or not.
 	 * Other drivers seem to do this when we reach a low
 	 * watermark on the transmit queue.
 	 */
+	
 	netif_wake_queue(d->sbdma_eth->sbm_dev);
-
-	spin_unlock_irqrestore(&sc->sbm_lock, flags);
+	
+	spin_unlock_irqrestore(&(sc->sbm_lock), flags);
+	
 }
 
 
 
-/*
+/**********************************************************************
  *  SBMAC_INITCTX(s)
  *  
  *  Initialize an Ethernet context structure - this is called
@@ -1190,7 +1396,8 @@
  *  	   
  *  Return value:
  *  	   0
- */
+ ********************************************************************* */
+
 static int sbmac_initctx(struct sbmac_softc *s)
 {
 	
@@ -1220,8 +1427,8 @@
 	 * Note: Only do this _once_, as it allocates memory from the kernel!
 	 */
 	
-	sbdma_initctx(&s->sbm_txdma, s, 0, DMA_TX,SBMAC_MAX_TXDESCR);
-	sbdma_initctx(&s->sbm_rxdma, s, 0, DMA_RX,SBMAC_MAX_RXDESCR);
+	sbdma_initctx(&(s->sbm_txdma),s,0,DMA_TX,SBMAC_MAX_TXDESCR);
+	sbdma_initctx(&(s->sbm_rxdma),s,0,DMA_RX,SBMAC_MAX_RXDESCR);
 	
 	/*
 	 * initial state is OFF
@@ -1240,6 +1447,7 @@
 	return 0;
 }
 
+
 static void sbdma_uninitctx(struct sbmacdma_s *d)
 {
 	if (d->sbdma_dscrtable) {
@@ -1256,11 +1464,12 @@
 
 static void sbmac_uninitctx(struct sbmac_softc *sc)
 {
-	sbdma_uninitctx(&sc->sbm_txdma);
-	sbdma_uninitctx(&sc->sbm_rxdma);
+	sbdma_uninitctx(&(sc->sbm_txdma));
+	sbdma_uninitctx(&(sc->sbm_rxdma));
 }
 
-/*
+
+/**********************************************************************
  *  SBMAC_CHANNEL_START(s)
  *  
  *  Start packet processing on this MAC.
@@ -1270,7 +1479,8 @@
  *  	   
  *  Return value:
  *  	   nothing
- */
+ ********************************************************************* */
+
 static void sbmac_channel_start(struct sbmac_softc *s)
 {
 	uint64_t reg;
@@ -1308,8 +1518,14 @@
 		M_MAC_SS_EN |
 		0;
 	
+	/* 
+	 * Be sure that RD_THRSH+WR_THRSH <= 32
+	 * Use a larger RD_THRSH for gigabit
+	 */
+
 	fifo = V_MAC_TX_WR_THRSH(4) |	/* Must be '4' or '8' */
-		V_MAC_TX_RD_THRSH(4) |
+		((s->sbm_speed == sbmac_speed_1000)
+		 ? V_MAC_TX_RD_THRSH(28) : V_MAC_TX_RD_THRSH(4)) |
 		V_MAC_TX_RL_THRSH(4) |
 		V_MAC_RX_PL_THRSH(4) |
 		V_MAC_RX_RD_THRSH(4) |	/* Must be '4' */
@@ -1395,59 +1611,82 @@
 	/*
 	 * Initialize DMA channels (rings should be ok now)
 	 */
-	sbdma_channel_start(&s->sbm_rxdma);
-	sbdma_channel_start(&s->sbm_txdma);
-
+	
+	sbdma_channel_start(&(s->sbm_rxdma), DMA_RX);
+	sbdma_channel_start(&(s->sbm_txdma), DMA_TX);
+	
 	/*
 	 * Configure the speed, duplex, and flow control
 	 */
+
 	sbmac_set_speed(s,s->sbm_speed);
 	sbmac_set_duplex(s,s->sbm_duplex,s->sbm_fc);
 	
 	/*
 	 * Fill the receive ring
 	 */
-	sbdma_fillring(&s->sbm_rxdma);
-
+	
+	sbdma_fillring(&(s->sbm_rxdma));
+	
 	/* 
 	 * Turn on the rest of the bits in the enable register
 	 */      
+	
 	SBMAC_WRITECSR(s->sbm_macenable,
 		       M_MAC_RXDMA_EN0 |
 		       M_MAC_TXDMA_EN0 |
 		       M_MAC_RX_ENABLE |
 		       M_MAC_TX_ENABLE);
+	
+	
 
+
+#ifdef CONFIG_SBMAC_COALESCE
+	/*
+	 * Accept any TX interrupt and EOP count/timer RX interrupts on ch 0
+	 */
+	SBMAC_WRITECSR(s->sbm_imr,
+		       (M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
+		       ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0));
+#else
 	/*
 	 * Accept any kind of interrupt on TX and RX DMA channel 0
 	 */
 	SBMAC_WRITECSR(s->sbm_imr,
 		       (M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
 		       (M_MAC_INT_CHANNEL << S_MAC_RX_CH0));
-
+#endif
+	
 	/* 
 	 * Enable receiving unicasts and broadcasts 
 	 */
+	
 	SBMAC_WRITECSR(s->sbm_rxfilter,M_MAC_UCAST_EN | M_MAC_BCAST_EN);
-
+	
 	/*
 	 * we're running now. 
 	 */
+	
 	s->sbm_state = sbmac_state_on;
-
+	
 	/* 
 	 * Program multicast addresses 
 	 */
+	
 	sbmac_setmulti(s);
-
+	
 	/* 
 	 * If channel was in promiscuous mode before, turn that on 
 	 */
-	if (s->sbm_devflags & IFF_PROMISC)
+	
+	if (s->sbm_devflags & IFF_PROMISC) {
 		sbmac_promiscuous_mode(s,1);
+	}
+	
 }
 
-/*
+
+/**********************************************************************
  *  SBMAC_CHANNEL_STOP(s)
  *  
  *  Stop packet processing on this MAC.
@@ -1457,11 +1696,10 @@
  *  	   
  *  Return value:
  *  	   nothing
- */
+ ********************************************************************* */
+
 static void sbmac_channel_stop(struct sbmac_softc *s)
 {
-	uint64_t ctl;
-	
 	/* don't do this if already stopped */
 	
 	if (s->sbm_state == sbmac_state_off) return;
@@ -1477,22 +1715,27 @@
 	
 	/* turn off receiver and transmitter */
 	
-	ctl = SBMAC_READCSR(s->sbm_macenable);
-	ctl &= ~(M_MAC_RXDMA_EN0 | M_MAC_TXDMA_EN0);
-	SBMAC_WRITECSR(s->sbm_macenable,ctl);
+	SBMAC_WRITECSR(s->sbm_macenable,0);
 	
 	/* We're stopped now. */
 	
 	s->sbm_state = sbmac_state_off;
 	
+	/*
+	 * Stop DMA channels (rings should be ok now)
+	 */
+	
+	sbdma_channel_stop(&(s->sbm_rxdma));
+	sbdma_channel_stop(&(s->sbm_txdma));
 	
 	/* Empty the receive and transmit rings */
 	
-	sbdma_emptyring(&s->sbm_rxdma);
-	sbdma_emptyring(&s->sbm_txdma);
+	sbdma_emptyring(&(s->sbm_rxdma));
+	sbdma_emptyring(&(s->sbm_txdma));
+	
 }
 
-/*
+/**********************************************************************
  *  SBMAC_SET_CHANNEL_STATE(state)
  *  
  *  Set the channel's state ON or OFF
@@ -1502,7 +1745,7 @@
  *  	   
  *  Return value:
  *  	   old state
- */
+ ********************************************************************* */
 static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc,
 					     sbmac_state_t state)
 {
@@ -1535,7 +1778,7 @@
 }
 
 
-/*
+/**********************************************************************
  *  SBMAC_PROMISCUOUS_MODE(sc,onoff)
  *  
  *  Turn on or off promiscuous mode
@@ -1546,7 +1789,8 @@
  *  	   
  *  Return value:
  *  	   nothing
- */
+ ********************************************************************* */
+
 static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff)
 {
 	uint64_t reg;
@@ -1565,6 +1809,36 @@
 	}
 }
 
+/**********************************************************************
+ *  SBMAC_SETIPHDR_OFFSET(sc,onoff)
+ *  
+ *  Set the iphdr offset as 15 assuming ethernet encapsulation
+ *  
+ *  Input parameters: 
+ *  	   sc - softc
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
+
+static void sbmac_set_iphdr_offset(struct sbmac_softc *sc)
+{
+	uint64_t reg;
+	
+	reg = SBMAC_READCSR(sc->sbm_rxfilter);
+	reg &= ~M_MAC_IPHDR_OFFSET;
+	/* Hard code the off set to 15 for now */
+	reg |= 15 << S_MAC_IPHDR_OFFSET;
+	SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+	
+	/* read system identification to determine revision */
+	if (sb1250_pass >= K_SYS_REVISION_PASS2) {
+		printk(KERN_INFO "pass2 - enabling Rx rcv tcp checksum\n");
+		sc->rx_hw_checksum = ENABLE;
+	} else {
+		sc->rx_hw_checksum = DISABLE;
+	}
+}
 
 
 #if 0
@@ -1582,15 +1856,17 @@
 static void sbmac_init_and_start(struct sbmac_softc *sc)
 {
 	unsigned long flags;
-
-	spin_lock_irqsave(&sc->sbm_lock, flags);
-	sbmac_set_channel_state(sc, sbmac_state_on);
-	spin_unlock_irqrestore(&sc->sbm_lock, flags);
+	
+	spin_lock_irqsave(&(sc->sbm_lock),flags);
+	
+	sbmac_set_channel_state(sc,sbmac_state_on);
+	
+	spin_unlock_irqrestore(&(sc->sbm_lock),flags);
 }
 #endif
 
 
-/*
+/**********************************************************************
  *  SBMAC_ADDR2REG(ptr)
  *  
  *  Convert six bytes into the 64-bit register value that
@@ -1601,13 +1877,14 @@
  *  	   
  *  Return value:
  *  	   register value
- */
+ ********************************************************************* */
+
 static uint64_t sbmac_addr2reg(unsigned char *ptr)
 {
 	uint64_t reg = 0;
-
+	
 	ptr += 6;
-
+	
 	reg |= (uint64_t) *(--ptr); 
 	reg <<= 8;
 	reg |= (uint64_t) *(--ptr); 
@@ -1619,12 +1896,12 @@
 	reg |= (uint64_t) *(--ptr); 
 	reg <<= 8;
 	reg |= (uint64_t) *(--ptr); 
-
+	
 	return reg;
 }
 
 
-/*
+/**********************************************************************
  *  SBMAC_SET_SPEED(s,speed)
  *  
  *  Configure LAN speed for the specified MAC.
@@ -1637,7 +1914,8 @@
  *  Return value:
  *  	   1 if successful
  *      0 indicates invalid parameters
- */
+ ********************************************************************* */
+
 static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
 {
 	uint64_t cfg;
@@ -1728,8 +2006,7 @@
  *  	   0 if an invalid parameter combination was specified
  ********************************************************************* */
 
-static int sbmac_set_duplex(struct sbmac_softc *s, sbmac_duplex_t duplex,
-                            sbmac_fc_t fc)
+static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc)
 {
 	uint64_t cfg;
 	
@@ -1810,37 +2087,75 @@
 	return 1;
 }
 
+
+
+
+/**********************************************************************
+ *  SBMAC_INTR()
+ *  
+ *  Interrupt handler for MAC interrupts
+ *  
+ *  Input parameters: 
+ *  	   MAC structure
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
 static void sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs)
 {
 	struct net_device *dev = (struct net_device *) dev_instance;
-	struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv;
+	struct sbmac_softc *sc = (struct sbmac_softc *) (dev->priv);
 	uint64_t isr;
-
+	
 	for (;;) {
+		
 		/*
-		 * Read the ISR (this clears the bits in the real register)
+		 * Read the ISR (this clears the bits in the real
+		 * register, except for counter addr)
 		 */
-		isr = SBMAC_READCSR(sc->sbm_isr);
-
-		if (isr == 0)
-			break;
-
+		
+		isr = SBMAC_READCSR(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR;
+		
+		if (isr == 0) break;
+		
 		/*
 		 * Transmits on channel 0
 		 */
-		if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0))
-			sbdma_tx_process(sc, &sc->sbm_txdma);
-
+		
+		if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
+			sbdma_tx_process(sc,&(sc->sbm_txdma));
+		}
+		
 		/*
 		 * Receives on channel 0
 		 */
-		if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0))
-			sbdma_rx_process(sc, &sc->sbm_rxdma);
+
+		/*
+		 * It's important to test all the bits (or at least the
+		 * EOP_SEEN bit) when deciding to do the RX process
+		 * particularly when coalescing, to make sure we
+		 * take care of the following:
+		 *
+		 * If you have some packets waiting (have been received
+		 * but no interrupt) and get a TX interrupt before
+		 * the RX timer or counter expires, reading the ISR
+		 * above will clear the timer and counter, and you
+		 * won't get another interrupt until a packet shows
+		 * up to start the timer again.  Testing
+		 * EOP_SEEN here takes care of this case.
+		 * (EOP_SEEN is part of M_MAC_INT_CHANNEL << S_MAC_RX_CH0)
+		 */
+		 
+		
+		if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
+			sbdma_rx_process(sc,&(sc->sbm_rxdma));
+		}
 	}
+	
 }
 
 
-/*
+/**********************************************************************
  *  SBMAC_START_TX(skb,dev)
  *  
  *  Start output on the specified interface.  Basically, we 
@@ -1852,29 +2167,31 @@
  *  	   
  *  Return value:
  *  	   nothing
- */
+ ********************************************************************* */
 static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
 {
 	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
-
+	
 	/* lock eth irq */
-	spin_lock_irq(&sc->sbm_lock);
-
+	spin_lock_irq (&sc->sbm_lock);
+	
 	/*
 	 * Put the buffer on the transmit ring.  If we 
 	 * don't have room, stop the queue.
 	 */
-	if (unlikely(sbdma_add_txbuffer(&sc->sbm_txdma, skb))) {
+	
+	if (sbdma_add_txbuffer(&(sc->sbm_txdma),skb)) {
+		/* XXX save skb that we could not send */
 		netif_stop_queue(dev);
 		spin_unlock_irq(&sc->sbm_lock);
 
 		return 1;
 	}
-
+	
 	dev->trans_start = jiffies;
-
-	spin_unlock_irq(&sc->sbm_lock);
-
+	
+	spin_unlock_irq (&sc->sbm_lock);
+	
 	return 0;
 }
 
@@ -1968,6 +2285,8 @@
 	}
 }
 
+
+
 #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR)
 /**********************************************************************
  *  SBMAC_PARSE_XDIGIT(str)
@@ -1993,6 +2312,20 @@
 	return digit;
 }
 
+/**********************************************************************
+ *  SBMAC_PARSE_HWADDR(str,hwaddr)
+ *  
+ *  Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte
+ *  Ethernet address.
+ *  
+ *  Input parameters: 
+ *  	   str - string
+ *  	   hwaddr - pointer to hardware address
+ *  	   
+ *  Return value:
+ *  	   0 if ok, else -1
+ ********************************************************************* */
+
 static int sbmac_parse_hwaddr(char *str,u_char *hwaddr)
 {
 	int digit1,digit2;
@@ -2024,6 +2357,27 @@
 }
 #endif
 
+static int sb1250_change_mtu(struct net_device *_dev, int new_mtu)
+{
+        if (new_mtu >  ENET_PACKET_SIZE)
+                return -EINVAL;
+        _dev->mtu = new_mtu;
+	printk(KERN_INFO "changing the mtu to %d\n", new_mtu);
+        return 0;
+}
+
+/**********************************************************************
+ *  SBMAC_INIT(dev)
+ *  
+ *  Attach routine - init hardware and hook ourselves into linux
+ *  
+ *  Input parameters: 
+ *  	   dev - net_device structure
+ *  	   
+ *  Return value:
+ *  	   status
+ ********************************************************************* */
+
 static int sbmac_init(struct net_device *dev)
 {
 	struct sbmac_softc *sc;
@@ -2086,7 +2440,7 @@
 	 * Set up Linux device callins
 	 */
 	
-	spin_lock_init(&sc->sbm_lock);
+	spin_lock_init(&(sc->sbm_lock));
 	
 	ether_setup(dev);
 	dev->open               = sbmac_open;
@@ -2097,11 +2451,22 @@
 	dev->do_ioctl           = sbmac_mii_ioctl;
 	dev->tx_timeout         = sbmac_tx_timeout;
 	dev->watchdog_timeo     = TX_TIMEOUT;
+
+	dev->change_mtu         = sb1250_change_mtu;
+
+	if (sb1250_pass >= K_SYS_REVISION_PASS3) {
+		/* In pass3 we do dumb checksum in TX */
+		dev->features |= NETIF_F_IP_CSUM;
+	}
+
+        /* This is needed for PASS2 for Rx H/W checksum feature */
+	sbmac_set_iphdr_offset( sc);
 	
 	return 0;
 	
 }
 
+
 static int sbmac_open(struct net_device *dev)
 {
 	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
@@ -2154,101 +2519,116 @@
 	return 0;
 }
 
+
+
 static int sbmac_mii_poll(struct sbmac_softc *s,int noisy)
 {
-	int bmsr,bmcr,k1stsr,anlpar;
-	int chg;
-	char buffer[100];
-	char *p = buffer;
-
-	/* Read the mode status and mode control registers. */
-	bmsr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMSR);
-	bmcr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMCR);
-
-	/* get the link partner status */
-	anlpar = sbmac_mii_read(s,s->sbm_phys[0],MII_ANLPAR);
-
-	/* if supported, read the 1000baseT register */
-	if (bmsr & BMSR_1000BT_XSR) {
-		k1stsr = sbmac_mii_read(s,s->sbm_phys[0],MII_K1STSR);
-	} else {
-		k1stsr = 0;
+    int bmsr,bmcr,k1stsr,anlpar;
+    int chg;
+    char buffer[100];
+    char *p = buffer;
+
+    /* Read the mode status and mode control registers. */
+    bmsr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMSR);
+    bmcr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMCR);
+
+    /* get the link partner status */
+    anlpar = sbmac_mii_read(s,s->sbm_phys[0],MII_ANLPAR);
+
+    /* if supported, read the 1000baseT register */
+    if (bmsr & BMSR_1000BT_XSR) {
+	k1stsr = sbmac_mii_read(s,s->sbm_phys[0],MII_K1STSR);
+	}
+    else {
+	k1stsr = 0;
 	}
 
-	chg = 0;
+    chg = 0;
 
-	if ((bmsr & BMSR_LINKSTAT) == 0) {
-		/*
-		 * If link status is down, clear out old info so that when
-		 * it comes back up it will force us to reconfigure speed
-		 */
-		s->sbm_phy_oldbmsr = 0;
-		s->sbm_phy_oldanlpar = 0;
-		s->sbm_phy_oldk1stsr = 0;
-		return 0;
+    if ((bmsr & BMSR_LINKSTAT) == 0) {
+	/*
+	 * If link status is down, clear out old info so that when
+	 * it comes back up it will force us to reconfigure speed
+	 */
+	s->sbm_phy_oldbmsr = 0;
+	s->sbm_phy_oldanlpar = 0;
+	s->sbm_phy_oldk1stsr = 0;
+	return 0;
 	}
 
-	if ((s->sbm_phy_oldbmsr != bmsr) ||
-	    (s->sbm_phy_oldanlpar != anlpar) ||
-	    (s->sbm_phy_oldk1stsr != k1stsr)) {
-		if (debug > 1)
-			printk(KERN_DEBUG
-			       "%s: bmsr:%x/%x anlpar:%x/%x  k1stsr:%x/%x\n",
-			       s->sbm_dev->name,
-			       s->sbm_phy_oldbmsr,bmsr,
-			       s->sbm_phy_oldanlpar,anlpar,
-			       s->sbm_phy_oldk1stsr,k1stsr);
-		s->sbm_phy_oldbmsr = bmsr;
-		s->sbm_phy_oldanlpar = anlpar;
-		s->sbm_phy_oldk1stsr = k1stsr;
-		chg = 1;
+    if ((s->sbm_phy_oldbmsr != bmsr) ||
+	(s->sbm_phy_oldanlpar != anlpar) ||
+	(s->sbm_phy_oldk1stsr != k1stsr)) {
+	if (debug > 1) {
+	    printk(KERN_DEBUG "%s: bmsr:%x/%x anlpar:%x/%x  k1stsr:%x/%x\n",
+	       s->sbm_dev->name,
+	       s->sbm_phy_oldbmsr,bmsr,
+	       s->sbm_phy_oldanlpar,anlpar,
+	       s->sbm_phy_oldk1stsr,k1stsr);
+	    }
+	s->sbm_phy_oldbmsr = bmsr;
+	s->sbm_phy_oldanlpar = anlpar;
+	s->sbm_phy_oldk1stsr = k1stsr;
+	chg = 1;
 	}
 
-	if (chg == 0)
-		return 0;
+    if (chg == 0) return 0;
 
-	p += sprintf(p,"Link speed: ");
+    p += sprintf(p,"Link speed: ");
 
-	if (k1stsr & K1STSR_LP1KFD) {
-		s->sbm_speed = sbmac_speed_1000;
-		s->sbm_duplex = sbmac_duplex_full;
-		s->sbm_fc = sbmac_fc_frame;
-		p += sprintf(p,"1000BaseT FDX");
-	} else if (k1stsr & K1STSR_LP1KHD) {
-		s->sbm_speed = sbmac_speed_1000;
-		s->sbm_duplex = sbmac_duplex_half;
-		s->sbm_fc = sbmac_fc_disabled;
-		p += sprintf(p,"1000BaseT HDX");
-	} else if (anlpar & ANLPAR_TXFD) {
-		s->sbm_speed = sbmac_speed_100;
-		s->sbm_duplex = sbmac_duplex_full;
-		s->sbm_fc = (anlpar & ANLPAR_PAUSE) ? sbmac_fc_frame
-		                                    : sbmac_fc_disabled;
-		p += sprintf(p,"100BaseT FDX");
-	} else if (anlpar & ANLPAR_TXHD) {
-		s->sbm_speed = sbmac_speed_100;
-		s->sbm_duplex = sbmac_duplex_half;
-		s->sbm_fc = sbmac_fc_disabled;
-		p += sprintf(p,"100BaseT HDX");
-	} else if (anlpar & ANLPAR_10FD) {
-		s->sbm_speed = sbmac_speed_10;
-		s->sbm_duplex = sbmac_duplex_full;
-		s->sbm_fc = sbmac_fc_frame;
-		p += sprintf(p,"10BaseT FDX");
-	} else if (anlpar & ANLPAR_10HD) {
-		s->sbm_speed = sbmac_speed_10;
-		s->sbm_duplex = sbmac_duplex_half;
-		s->sbm_fc = sbmac_fc_collision;
-		p += sprintf(p,"10BaseT HDX");
-	} else
-		p += sprintf(p,"Unknown");
+    if (k1stsr & K1STSR_LP1KFD) {
+	s->sbm_speed = sbmac_speed_1000;
+	s->sbm_duplex = sbmac_duplex_full;
+	s->sbm_fc = sbmac_fc_frame;
+	p += sprintf(p,"1000BaseT FDX");
+	}
+    else if (k1stsr & K1STSR_LP1KHD) {
+	s->sbm_speed = sbmac_speed_1000;
+	s->sbm_duplex = sbmac_duplex_half;
+	s->sbm_fc = sbmac_fc_disabled;
+	p += sprintf(p,"1000BaseT HDX");
+	}
+    else if (anlpar & ANLPAR_TXFD) {
+	s->sbm_speed = sbmac_speed_100;
+	s->sbm_duplex = sbmac_duplex_full;
+	s->sbm_fc = (anlpar & ANLPAR_PAUSE) ? sbmac_fc_frame : sbmac_fc_disabled;
+	p += sprintf(p,"100BaseT FDX");
+	}
+    else if (anlpar & ANLPAR_TXHD) {
+	s->sbm_speed = sbmac_speed_100;
+	s->sbm_duplex = sbmac_duplex_half;
+	s->sbm_fc = sbmac_fc_disabled;
+	p += sprintf(p,"100BaseT HDX");
+	}
+    else if (anlpar & ANLPAR_10FD) {
+	s->sbm_speed = sbmac_speed_10;
+	s->sbm_duplex = sbmac_duplex_full;
+	s->sbm_fc = sbmac_fc_frame;
+	p += sprintf(p,"10BaseT FDX");
+	}
+    else if (anlpar & ANLPAR_10HD) {
+	s->sbm_speed = sbmac_speed_10;
+	s->sbm_duplex = sbmac_duplex_half;
+	s->sbm_fc = sbmac_fc_collision;
+	p += sprintf(p,"10BaseT HDX");
+	}
+    else {
+	p += sprintf(p,"Unknown");
+	}
 
-	if (noisy)
-		printk(KERN_INFO "%s: %s\n",s->sbm_dev->name,buffer);
+#ifdef CONFIG_NET_SB1250_MAC_QUIET
+    noisy = 0;
+#endif
+    if (noisy) {
+	    printk(KERN_INFO "%s: %s\n",s->sbm_dev->name,buffer);
+	    }
 
-		return 1;
+    return 1;
 }
 
+
+
+
 static void sbmac_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
@@ -2295,6 +2675,7 @@
 	add_timer(&sc->sbm_timer);
 }
 
+
 static void sbmac_tx_timeout (struct net_device *dev)
 {
 	struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv;
@@ -2310,6 +2691,9 @@
 	printk (KERN_WARNING "%s: Transmit timed out\n",dev->name);
 }
 
+
+
+
 static struct net_device_stats *sbmac_get_stats(struct net_device *dev)
 {
 	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
@@ -2324,6 +2708,8 @@
 	return &sc->sbm_stats;
 }
 
+
+
 static void sbmac_set_rx_mode(struct net_device *dev)
 {
 	unsigned long flags;
@@ -2355,6 +2741,7 @@
 	/*
 	 * Program the multicasts.  Do this every time.
 	 */
+	
 	sbmac_setmulti(sc);
 	
 }
@@ -2399,33 +2786,36 @@
 {
 	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
 	unsigned long flags;
-
+	
 	sbmac_set_channel_state(sc,sbmac_state_off);
-
+	
 	del_timer_sync(&sc->sbm_timer);
-
+	
 	spin_lock_irqsave(&sc->sbm_lock, flags);
-
+	
 	netif_stop_queue(dev);
-
-	if (debug > 1)
+	
+	if (debug > 1) {
 		printk(KERN_DEBUG "%s: Shutting down ethercard\n",dev->name);
-
+	}
+	
 	spin_unlock_irqrestore(&sc->sbm_lock, flags);
-
+	
 	/* Make sure there is no irq-handler running on a different CPU. */
 	synchronize_irq();
-
+	
 	free_irq(dev->irq, dev);
-
-	sbdma_emptyring(&sc->sbm_txdma);
-	sbdma_emptyring(&sc->sbm_rxdma);
-
+	
+	sbdma_emptyring(&(sc->sbm_txdma));
+	sbdma_emptyring(&(sc->sbm_rxdma));
+	
 	MOD_DEC_USE_COUNT;
-
+	
 	return 0;
 }
 
+
+
 #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR)
 static void
 sbmac_setup_hwaddr(int chan,char *addr)
@@ -2451,6 +2841,7 @@
 	int macidx = 0;
 	struct net_device *dev;
 	sbmac_port_t port;
+	int chip_max_units;
 	
 	/*
 	 * For bringup when not using the firmware, we can pre-fill
@@ -2471,8 +2862,25 @@
 	 * Walk through the Ethernet controllers and find
 	 * those who have their MAC addresses set.
 	 */
-	
-	for (idx = 0; idx < MAX_UNITS; idx++) {
+	chip_revision = SBMAC_READCSR(PKSEG1(A_SCD_SYSTEM_REVISION));
+	switch ((int)G_SYS_PART(chip_revision)) {
+	case 0x1150:
+	case 0x1250:
+		chip_max_units = 3;
+		break;
+	case 0x1120:
+	case 0x1125:
+	case 0x1126:
+		chip_max_units = 2;
+		break;
+	default:
+		chip_max_units = 0;
+		break;
+	}
+	if (chip_max_units > MAX_UNITS)
+		chip_max_units = MAX_UNITS;
+
+	for (idx = 0; idx < chip_max_units; idx++) {
 
 	        /*
 	         * This is the base address of the MAC.
@@ -2486,16 +2894,20 @@
 		 * If we find a zero, skip this MAC.
 		 */
 
-		if (SBMAC_READCSR(PKSEG1(port+R_MAC_ETHERNET_ADDR)) == 0) {
+		sbmac_orig_hwaddr[idx] = SBMAC_READCSR(PKSEG1(port+R_MAC_ETHERNET_ADDR));
+		if (sbmac_orig_hwaddr[idx] == 0) {
+		    printk( KERN_DEBUG "sbmac: not configuring MAC at %x\n",(uint32_t)port);
 		    continue;
-		    }
+		}
 
 		/*
 		 * Okay, cool.  Initialize this MAC.
 		 */
 
 		dev = init_etherdev(NULL,sizeof(struct sbmac_softc));
-		if (!dev) break;			/* problems, get out now. */
+		if (!dev) 
+		  return -ENOMEM;	/* return ENOMEM */
+
 		dev->irq = K_INT_MAC_0 + idx;
 		dev->base_addr = port;
 		dev->mem_end = 0;
@@ -2520,6 +2932,7 @@
 {
 	int idx;
 	struct net_device *dev;
+	sbmac_port_t port;
 	for (idx = 0; idx < MAX_UNITS; idx++) {
 		dev = dev_sbmac[idx];
 		if (dev == NULL) continue;
@@ -2530,8 +2943,10 @@
 			
 			sbmac_uninitctx(sc);
 			
-			KFREE(sc);
 		}
+
+	        port = A_MAC_CHANNEL_BASE(idx);
+		SBMAC_WRITECSR(PKSEG1(port+R_MAC_ETHERNET_ADDR), sbmac_orig_hwaddr[idx] );
 		KFREE(dev);
 		dev_sbmac[idx] = NULL;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/sgiseeq.h linux-2.4.20/drivers/net/sgiseeq.h
--- linux-2.4.19/drivers/net/sgiseeq.h	2000-05-13 15:29:40.000000000 +0000
+++ linux-2.4.20/drivers/net/sgiseeq.h	2002-10-29 11:18:40.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: sgiseeq.h,v 1.4 1999/10/09 00:01:24 ralf Exp $
+/*
  * sgiseeq.h: Defines for the Seeq8003 ethernet controller.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/sis900.c linux-2.4.20/drivers/net/sis900.c
--- linux-2.4.19/drivers/net/sis900.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/sis900.c	2002-10-29 11:18:39.000000000 +0000
@@ -1,6 +1,6 @@
 /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
    Copyright 1999 Silicon Integrated System Corporation 
-   Revision:	1.08.04	Apr. 25 2002
+   Revision:	1.08.06 Sep. 24 2002
    
    Modified from the driver which is originally written by Donald Becker.
    
@@ -18,6 +18,8 @@
    preliminary Rev. 1.0 Jan. 18, 1998
    http://www.sis.com.tw/support/databook.htm
 
+   Rev 1.08.06 Sep. 24 2002 Mufasa Yang bug fix for Tx timeout & add SiS963 support
+   Rev 1.08.05 Jun. 6 2002 Mufasa Yang bug fix for read_eeprom & Tx descriptor over-boundary 
    Rev 1.08.04 Apr. 25 2002 Mufasa Yang <mufasa@sis.com.tw> added SiS962 support
    Rev 1.08.03 Feb. 1 2002 Matt Domsch <Matt_Domsch@dell.com> update to use library crc32 function
    Rev 1.08.02 Nov. 30 2001 Hui-Fen Hsu workaround for EDB & bug fix for dhcp problem
@@ -72,7 +74,7 @@
 #include "sis900.h"
 
 #define SIS900_MODULE_NAME "sis900"
-#define SIS900_DRV_VERSION "v1.08.04 4/25/2002"
+#define SIS900_DRV_VERSION "v1.08.06 9/24/2002"
 
 static char version[] __devinitdata =
 KERN_INFO "sis900.c: " SIS900_DRV_VERSION "\n";
@@ -309,31 +311,38 @@
 }
 
 /**
- *	sis962_get_mac_addr: - Get MAC address for SiS962 model
+ *	sis96x_get_mac_addr: - Get MAC address for SiS962 or SiS963 model
  *	@pci_dev: the sis900 pci device
  *	@net_dev: the net device to get address for 
  *
- *	SiS962 model, use EEPROM to store MAC address. And EEPROM is shared by
+ *	SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM 
+ *	is shared by
  *	LAN and 1394. When access EEPROM, send EEREQ signal to hardware first 
  *	and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access 
  *	by LAN, otherwise is not. After MAC address is read from EEPROM, send
  *	EEDONE signal to refuse EEPROM access by LAN. 
+ *	The EEPROM map of SiS962 or SiS963 is different to SiS900. 
+ *	The signature field in SiS962 or SiS963 spec is meaningless. 
  *	MAC address is read into @net_dev->dev_addr.
  */
 
-static int __devinit sis962_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev)
+static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev)
 {
 	long ioaddr = net_dev->base_addr;
 	long ee_addr = ioaddr + mear;
 	u32 waittime = 0;
-	int ret = 0;
+	int i;
 	
 	outl(EEREQ, ee_addr);
 	while(waittime < 2000) {
 		if(inl(ee_addr) & EEGNT) {
-			ret = sis900_get_mac_addr(pci_dev, net_dev);
+
+			/* get MAC address from EEPROM */
+			for (i = 0; i < 3; i++)
+			        ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr);
+
 			outl(EEDONE, ee_addr);
-			return(ret);
+			return 1;
 		} else {
 			udelay(1);	
 			waittime ++;
@@ -443,8 +452,8 @@
 		ret = sis630e_get_mac_addr(pci_dev, net_dev);
 	else if ((revision > 0x81) && (revision <= 0x90) )
 		ret = sis635_get_mac_addr(pci_dev, net_dev);
-	else if (revision == SIS962_900_REV)
-		ret = sis962_get_mac_addr(pci_dev, net_dev);
+	else if (revision == SIS96x_900_REV)
+		ret = sis96x_get_mac_addr(pci_dev, net_dev);
 	else
 		ret = sis900_get_mac_addr(pci_dev, net_dev);
 
@@ -702,7 +711,7 @@
 
 	outl(0, ee_addr);
 	eeprom_delay();
-	outl(EECLK, ee_addr);
+	outl(EECS, ee_addr);
 	eeprom_delay();
 
 	/* Shift the read command (9) bits out. */
@@ -713,7 +722,7 @@
 		outl(dataval | EECLK, ee_addr);
 		eeprom_delay();
 	}
-	outb(EECS, ee_addr);
+	outl(EECS, ee_addr);
 	eeprom_delay();
 
 	/* read the 16-bits data in */
@@ -729,7 +738,6 @@
 	/* Terminate the EEPROM access. */
 	outl(0, ee_addr);
 	eeprom_delay();
-	outl(EECLK, ee_addr);
 
 	return (retval);
 }
@@ -1432,8 +1440,8 @@
 
 	net_dev->trans_start = jiffies;
 
-	/* FIXME: Should we restart the transmission thread here  ?? */
-	outl(TxENA | inl(ioaddr + cr), ioaddr + cr);
+	/* load Transmit Descriptor Register */
+	outl(sis_priv->tx_ring_dma, ioaddr + txdp);
 
 	/* Enable all known interrupts by setting the interrupt mask. */
 	outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
@@ -1457,6 +1465,8 @@
 	long ioaddr = net_dev->base_addr;
 	unsigned int  entry;
 	unsigned long flags;
+	unsigned int  index_cur_tx, index_dirty_tx;
+	unsigned int  count_dirty_tx;
 
 	/* Don't transmit data before the complete of auto-negotiation */
 	if(!sis_priv->autong_complete){
@@ -1476,7 +1486,18 @@
 	sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len);
 	outl(TxENA | inl(ioaddr + cr), ioaddr + cr);
 
-	if (++sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC) {
+	sis_priv->cur_tx ++;
+	index_cur_tx = sis_priv->cur_tx;
+	index_dirty_tx = sis_priv->dirty_tx;
+
+	for (count_dirty_tx = 0; index_cur_tx != index_dirty_tx; index_dirty_tx++)
+		count_dirty_tx ++;
+
+	if (index_cur_tx == index_dirty_tx) {
+		/* dirty_tx is met in the cycle of cur_tx, buffer full */
+		sis_priv->tx_full = 1;
+		netif_stop_queue(net_dev);
+	} else if (count_dirty_tx < NUM_TX_DESC) { 
 		/* Typical path, tell upper layer that more transmission is possible */
 		netif_start_queue(net_dev);
 	} else {
@@ -1709,7 +1730,7 @@
 {
 	struct sis900_private *sis_priv = net_dev->priv;
 
-	for (; sis_priv->dirty_tx < sis_priv->cur_tx; sis_priv->dirty_tx++) {
+	for (; sis_priv->dirty_tx != sis_priv->cur_tx; sis_priv->dirty_tx++) {
 		struct sk_buff *skb;
 		unsigned int entry;
 		u32 tx_status;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/sis900.h linux-2.4.20/drivers/net/sis900.h
--- linux-2.4.19/drivers/net/sis900.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/sis900.h	2002-10-29 11:18:33.000000000 +0000
@@ -135,8 +135,8 @@
 	EEaddrMask = 0x013F, EEcmdShift = 16
 };
 
-/* For SiS962, request the eeprom software access */
-enum sis962_eeprom_command {
+/* For SiS962 or SiS963, request the eeprom software access */
+enum sis96x_eeprom_command {
 	EEREQ = 0x00000400, EEDONE = 0x00000200, EEGNT = 0x00000100
 };
 
@@ -245,7 +245,7 @@
 	SIS630A_900_REV = 0x80,		SIS630E_900_REV = 0x81,
 	SIS630S_900_REV = 0x82,		SIS630EA1_900_REV = 0x83,
 	SIS630ET_900_REV = 0x84,	SIS635A_900_REV = 0x90,
-	SIS962_900_REV = 0X91,		SIS900B_900_REV = 0x03
+	SIS96x_900_REV = 0X91,		SIS900B_900_REV = 0x03
 };
 
 enum sis630_revision_id {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/sk98lin/skge.c linux-2.4.20/drivers/net/sk98lin/skge.c
--- linux-2.4.19/drivers/net/sk98lin/skge.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/sk98lin/skge.c	2002-10-29 11:18:33.000000000 +0000
@@ -404,6 +404,7 @@
  */
 static int __init skge_probe (void)
 {
+	int			proc_root_initialized = 0;
 	int 		boards_found = 0;
 	int			version_disp = 0;
 	SK_AC		*pAC;
@@ -429,11 +430,6 @@
 	if (!pci_present())		/* is PCI support present? */
 		return -ENODEV;
 
-        pSkRootDir = create_proc_entry("sk98lin",
-                S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, proc_net); 
-
-	pSkRootDir->owner = THIS_MODULE;
-
 	while((pdev = pci_find_device(PCI_VENDOR_ID_SYSKONNECT,
 				      PCI_DEVICE_ID_SYSKONNECT_GE, pdev)) != NULL) {
 
@@ -485,6 +481,14 @@
 		dev->do_ioctl =		&SkGeIoctl;
 		dev->change_mtu =	&SkGeChangeMtu;
 
+		if(!proc_root_initialized) {
+			pSkRootDir = create_proc_entry("sk98lin",
+				S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, proc_net);
+			pSkRootDir->owner = THIS_MODULE;
+
+			proc_root_initialized = 1;
+		}
+
 		pProcFile = create_proc_entry(dev->name, 
 			S_IFREG | 0444, pSkRootDir);
 		pProcFile->read_proc = proc_read;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/slip.c linux-2.4.20/drivers/net/slip.c
--- linux-2.4.19/drivers/net/slip.c	2002-02-25 19:37:59.000000000 +0000
+++ linux-2.4.20/drivers/net/slip.c	2002-10-29 11:18:48.000000000 +0000
@@ -1393,10 +1393,8 @@
 		/* First of all: check for active disciplines and hangup them.
 		 */
 		do {
-			if (busy) {
-				current->counter = 0;
-				schedule();
-			}
+			if (busy)
+				yield();
 
 			busy = 0;
 			local_bh_disable();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/smc-ultra.c linux-2.4.20/drivers/net/smc-ultra.c
--- linux-2.4.19/drivers/net/smc-ultra.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/smc-ultra.c	2002-10-29 11:18:33.000000000 +0000
@@ -383,9 +383,11 @@
 	unsigned long hdr_start = dev->mem_start + ((ring_page - START_PG)<<8);
 
 	outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET);	/* shmem on */
-#ifdef notdef
+#ifdef __BIG_ENDIAN
 	/* Officially this is what we are doing, but the readl() is faster */
+	/* unfortunately it isn't endian aware of the struct               */
 	isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+	hdr->count = le16_to_cpu(hdr->count);
 #else
 	((unsigned int*)hdr)[0] = isa_readl(hdr_start);
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/smc-ultra32.c linux-2.4.20/drivers/net/smc-ultra32.c
--- linux-2.4.19/drivers/net/smc-ultra32.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/smc-ultra32.c	2002-10-29 11:18:36.000000000 +0000
@@ -320,9 +320,11 @@
 	/* Select correct 8KB Window. */
 	outb(ei_status.reg0 | ((ring_page & 0x60) >> 5), RamReg);
 
-#ifdef notdef
+#ifdef __BIG_ENDIAN
 	/* Officially this is what we are doing, but the readl() is faster */
+	/* unfortunately it isn't endian aware of the struct               */
 	isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+	hdr->count = le16_to_cpu(hdr->count);
 #else
 	((unsigned int*)hdr)[0] = isa_readl(hdr_start);
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/sun3lance.c linux-2.4.20/drivers/net/sun3lance.c
--- linux-2.4.19/drivers/net/sun3lance.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/sun3lance.c	2002-10-29 11:18:36.000000000 +0000
@@ -280,16 +280,17 @@
 
 static int __init lance_probe( struct net_device *dev)
 {	
-	unsigned long ioaddr, iopte;
-	
+	unsigned long ioaddr;
 	struct lance_private	*lp;
 	int 			i;
 	static int 		did_version;
-	int found = 0;
 	volatile unsigned short *ioaddr_probe;
 	unsigned short tmp1, tmp2;
 
 #ifdef CONFIG_SUN3
+	unsigned long iopte;
+	int found = 0;
+
 	/* LANCE_OBIO can be found within the IO pmeg with some effort */
 	for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 +
 	    SUN3_PMEG_SIZE); ioaddr += SUN3_PTE_SIZE) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/sundance.c linux-2.4.20/drivers/net/sundance.c
--- linux-2.4.19/drivers/net/sundance.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/sundance.c	2002-10-29 11:18:32.000000000 +0000
@@ -18,26 +18,66 @@
 	http://www.scyld.com/network/sundance.html
 
 
-	Version 1.01a (jgarzik):
+	Version LK1.01a (jgarzik):
 	- Replace some MII-related magic numbers with constants
 
-	Version 1.01b (D-Link):
+	Version LK1.02 (D-Link):
 	- Add new board to PCI ID list
-	
+	- Fix multicast bug
+
+	Version LK1.03 (D-Link):
+	- New Rx scheme, reduce Rx congestion
+	- Option to disable flow control
+
+	Version LK1.04 (D-Link):
+	- Tx timeout recovery
+	- More support for ethtool.
+
+	Version LK1.04a:
+	- Remove unused/constant members from struct pci_id_info
+	(which then allows removal of 'drv_flags' from private struct)
+	(jgarzik)
+	- If no phy is found, fail to load that board (jgarzik)
+	- Always start phy id scan at id 1 to avoid problems (Donald Becker)
+	- Autodetect where mii_preable_required is needed,
+	default to not needed.  (Donald Becker)
+
+	Version LK1.04b:
+	- Remove mii_preamble_required module parameter (Donald Becker)
+	- Add per-interface mii_preamble_required (setting is autodetected)
+	  (Donald Becker)
+	- Remove unnecessary cast from void pointer (jgarzik)
+	- Re-align comments in private struct (jgarzik)
+
+	Version LK1.04c (jgarzik):
+	- Support bitmapped message levels (NETIF_MSG_xxx), and the
+	  two ethtool ioctls that get/set them
+	- Don't hand-code MII ethtool support, use standard API/lib
+
+	Version LK1.04d:
+	- Merge from Donald Becker's sundance.c: (Jason Lunz)
+		* proper support for variably-sized MTUs
+		* default to PIO, to fix chip bugs
+	- Add missing unregister_netdev (Jason Lunz)
+	- Add CONFIG_SUNDANCE_MMIO config option (jgarzik)
+	- Better rx buf size calculation (Donald Becker)
+
+	Version LK1.05 (D-Link):
+	- fix DFE-580TX packet drop issue
+	- fix reset_tx logic
 
 */
 
 #define DRV_NAME	"sundance"
-#define DRV_VERSION	"1.01b"
-#define DRV_RELDATE	"17-Jan-2002"
+#define DRV_VERSION	"1.01+LK1.05"
+#define DRV_RELDATE	"28-Sep-2002"
 
 
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 30;
-static int mtu;
+static int max_interrupt_work = 0;
 /* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
    Typical is a 64 element hash table based on the Ethernet CRC.  */
 static int multicast_filter_limit = 32;
@@ -47,6 +87,8 @@
    This chip can receive into offset buffers, so the Alpha does not
    need a copy-align. */
 static int rx_copybreak;
+static int tx_coalesce=1;
+static int flowctrl=1;
 
 /* media[] specifies the media type the NIC operates at.
 		 autosense	Autosensing active media.
@@ -60,8 +102,10 @@
 		 3	 	100Mbps half duplex.
 		 4	 	100Mbps full duplex.
 */
-#define MAX_UNITS 8	
+#define MAX_UNITS 8
 static char *media[MAX_UNITS];
+
+
 /* Operational parameters that are set at compile time. */
 
 /* Keep the ring sizes a power of two for compile efficiency.
@@ -70,9 +114,10 @@
    bonding and packet priority, and more than 128 requires modifying the
    Tx error recovery.
    Large receive rings merely waste memory. */
-#define TX_RING_SIZE	16
-#define TX_QUEUE_LEN	10		/* Limit ring entries actually used.  */
-#define RX_RING_SIZE	32
+#define TX_RING_SIZE	64
+#define TX_QUEUE_LEN	(TX_RING_SIZE - 1) /* Limit ring entries actually used.  */
+#define RX_RING_SIZE	64
+#define RX_BUDGET	32
 #define TX_TOTAL_SIZE	TX_RING_SIZE*sizeof(struct netdev_desc)
 #define RX_TOTAL_SIZE	RX_RING_SIZE*sizeof(struct netdev_desc)
 
@@ -105,15 +150,22 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/init.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/crc32.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
+#ifndef _COMPAT_WITH_OLD_KERNEL
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#else
+#include "crc32.h"
+#include "ethtool.h"
+#include "mii.h"
+#include "compat.h"
+#endif
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
@@ -125,14 +177,15 @@
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(mtu, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "s");
+MODULE_PARM(flowctrl, "i");
 MODULE_PARM_DESC(max_interrupt_work, "Sundance Alta maximum events handled per interrupt");
-MODULE_PARM_DESC(mtu, "Sundance Alta MTU (all boards)");
 MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)");
 MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(flowctrl, "Sundance Alta flow control [0|1]");
+
 /*
 				Theory of Operation
 
@@ -207,20 +260,9 @@
 
 */
 
-
-
-enum pci_id_flags_bits {
-        /* Set PCI command register bits before calling probe1(). */
-        PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-        /* Read and map the single following PCI BAR. */
-        PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
-        PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
-};
-enum chip_capability_flags {CanHaveMII=1, };
-#ifdef USE_IO_OPS
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO  | PCI_ADDR0)
-#else
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
+/* Work-around for Kendin chip bugs. */
+#ifndef CONFIG_SUNDANCE_MMIO
+#define USE_IO_OPS 1
 #endif
 
 static struct pci_device_id sundance_pci_tbl[] __devinitdata = {
@@ -234,31 +276,20 @@
 };
 MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
 
+enum {
+	netdev_io_size = 128
+};
+
 struct pci_id_info {
         const char *name;
-        struct match_info {
-                int     pci, pci_mask, subsystem, subsystem_mask;
-                int revision, revision_mask;                            /* Only 8 bits. */
-        } id;
-        enum pci_id_flags_bits pci_flags;
-        int io_size;                            /* Needed for I/O region check or ioremap(). */
-        int drv_flags;                          /* Driver use, intended as capability flags. */
 };
 static struct pci_id_info pci_id_tbl[] = {
-	{"D-Link DFE-550TX FAST Ethernet Adapter", {0x10021186, 0xffffffff,},
-	 PCI_IOTYPE, 128, CanHaveMII},
-	{"D-Link DFE-550FX 100Mbps Fiber-optics Adapter",
-	 {0x10031186, 0xffffffff,},
-	 PCI_IOTYPE, 128, CanHaveMII},
-	{"D-Link DFE-580TX 4 port Server Adapter", {0x10121186, 0xffffffff,},
-	 PCI_IOTYPE, 128, CanHaveMII},
-	{"D-Link DFE-530TXS FAST Ethernet Adapter", {0x10021186, 0xffffffff,},
-	 PCI_IOTYPE, 128, CanHaveMII},
-	{"D-Link DL10050-based FAST Ethernet Adapter",
-	 {0x10021186, 0xffffffff,},
-	 PCI_IOTYPE, 128, CanHaveMII},
-	{"Sundance Technology Alta", {0x020113F0, 0xffffffff,},
-	 PCI_IOTYPE, 128, CanHaveMII},
+	{"D-Link DFE-550TX FAST Ethernet Adapter"},
+	{"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"},
+	{"D-Link DFE-580TX 4 port Server Adapter"},
+	{"D-Link DFE-530TXS FAST Ethernet Adapter"},
+	{"D-Link DL10050-based FAST Ethernet Adapter"},
+	{"Sundance Technology Alta"},
 	{0,},			/* 0 terminated list. */
 };
 
@@ -290,20 +321,26 @@
 enum alta_offsets {
 	DMACtrl = 0x00,
 	TxListPtr = 0x04,
-	TxDMACtrl = 0x08,
-	TxDescPoll = 0x0a,
+	TxDMABurstThresh = 0x08,
+	TxDMAUrgentThresh = 0x09,
+	TxDMAPollPeriod = 0x0a,
 	RxDMAStatus = 0x0c,
 	RxListPtr = 0x10,
-	RxDMACtrl = 0x14,
-	RxDescPoll = 0x16,
+	DebugCtrl0 = 0x1a,
+	DebugCtrl1 = 0x1c,
+	RxDMABurstThresh = 0x14,
+	RxDMAUrgentThresh = 0x15,
+	RxDMAPollPeriod = 0x16,
 	LEDCtrl = 0x1a,
 	ASICCtrl = 0x30,
 	EEData = 0x34,
 	EECtrl = 0x36,
-	TxThreshold = 0x3c,
+	TxStartThresh = 0x3c,
+	RxEarlyThresh = 0x3e,
 	FlashAddr = 0x40,
 	FlashData = 0x44,
 	TxStatus = 0x46,
+	TxFrameId = 0x47,
 	DownCounter = 0x18,
 	IntrClear = 0x4a,
 	IntrEnable = 0x4c,
@@ -311,7 +348,7 @@
 	MACCtrl0 = 0x50,
 	MACCtrl1 = 0x52,
 	StationAddr = 0x54,
-	MaxTxSize = 0x5A,
+	MaxFrameSize = 0x5A,
 	RxMode = 0x5c,
 	MIICtrl = 0x5e,
 	MulticastFilter0 = 0x60,
@@ -337,6 +374,16 @@
 	/* Aliased and bogus values! */
 	RxStatus = 0x0c,
 };
+enum ASICCtrl_HiWord_bit {
+	GlobalReset = 0x0001,
+	RxReset = 0x0002,
+	TxReset = 0x0004,
+	DMAReset = 0x0008,
+	FIFOReset = 0x0010,
+	NetworkReset = 0x0020,
+	HostReset = 0x0040,
+	ResetBusy = 0x0400,
+};
 
 /* Bits in the interrupt status/mask registers. */
 enum intr_status_bits {
@@ -396,35 +443,40 @@
         dma_addr_t tx_ring_dma;
         dma_addr_t rx_ring_dma;
 	struct net_device_stats stats;
-	struct timer_list timer;	/* Media monitoring timer. */
+	struct timer_list timer;		/* Media monitoring timer. */
 	/* Frequently used values: keep some adjacent for cache effect. */
 	spinlock_t lock;
-	int chip_id, drv_flags;
+	spinlock_t rx_lock;			/* Group with Tx control cache line. */
+	int msg_enable;
+	int chip_id;
 	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
-	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
-	spinlock_t txlock;					/* Group with Tx control cache line. */
+	unsigned int rx_buf_sz;			/* Based on MTU+slack. */
 	struct netdev_desc *last_tx;		/* Last Tx descriptor used. */
 	unsigned int cur_tx, dirty_tx;
-	unsigned int tx_full:1;				/* The Tx queue is full. */
 	/* These values are keep track of the transceiver/media in use. */
-	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
-	unsigned int medialock:1;			/* Do not sense media. */
+	unsigned int flowctrl:1;
 	unsigned int default_port:4;		/* Last dev->if_port value. */
 	unsigned int an_enable:1;
 	unsigned int speed;
+	struct tasklet_struct rx_tasklet;
+	int budget;
 	/* Multicast and receive mode. */
-	spinlock_t mcastlock;				/* SMP lock multicast updates. */
+	spinlock_t mcastlock;			/* SMP lock multicast updates. */
 	u16 mcast_filter[4];
 	/* MII transceiver section. */
-	int mii_cnt;						/* MII device addresses. */
-	u16 advertising;					/* NWay media advertisement */
+	struct mii_if_info mii_if;
+	int mii_preamble_required;
 	unsigned char phys[MII_CNT];		/* MII device addresses, only first one used. */
 	struct pci_dev *pci_dev;
 };
 
 /* The station address location in the EEPROM. */
 #define EEPROM_SA_OFFSET	0x10
+#define DEFAULT_INTR (IntrRxDMADone | IntrPCIErr | \
+			IntrDrvRqst | IntrTxDone | StatsMax | \
+			LinkChange)
 
+static int  change_mtu(struct net_device *dev, int new_mtu);
 static int  eeprom_read(long ioaddr, int location);
 static int  mdio_read(struct net_device *dev, int phy_id, int location);
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
@@ -434,16 +486,18 @@
 static void tx_timeout(struct net_device *dev);
 static void init_ring(struct net_device *dev);
 static int  start_tx(struct sk_buff *skb, struct net_device *dev);
+static int reset_tx (struct net_device *dev);
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
+static void rx_poll(unsigned long data);
+static void refill_rx (struct net_device *dev);
 static void netdev_error(struct net_device *dev, int intr_status);
-static int  netdev_rx(struct net_device *dev);
 static void netdev_error(struct net_device *dev, int intr_status);
 static void set_rx_mode(struct net_device *dev);
 static struct net_device_stats *get_stats(struct net_device *dev);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int  netdev_close(struct net_device *dev);
 
-
+
 
 static int __devinit sundance_probe1 (struct pci_dev *pdev,
 				      const struct pci_device_id *ent)
@@ -485,7 +539,7 @@
 	ioaddr = pci_resource_start(pdev, 0);
 #else
 	ioaddr = pci_resource_start(pdev, 1);
-	ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size);
+	ioaddr = (long) ioremap (ioaddr, netdev_io_size);
 	if (!ioaddr)
 		goto err_out_res;
 #endif
@@ -498,10 +552,11 @@
 	dev->irq = irq;
 
 	np = dev->priv;
-	np->chip_id = chip_idx;
-	np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
 	np->pci_dev = pdev;
+	np->chip_id = chip_idx;
+	np->msg_enable = (1 << debug) - 1;
 	spin_lock_init(&np->lock);
+	tasklet_init(&np->rx_tasklet, rx_poll, (unsigned long)dev);
 
 	ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
 	if (!ring_space)
@@ -515,6 +570,12 @@
 	np->rx_ring = (struct netdev_desc *)ring_space;
 	np->rx_ring_dma = ring_dma;
 
+	np->mii_if.dev = dev;
+	np->mii_if.mdio_read = mdio_read;
+	np->mii_if.mdio_write = mdio_write;
+	np->mii_if.phy_id_mask = 0x1f;
+	np->mii_if.reg_num_mask = 0x1f;
+
 	/* The chip-specific entries in the device structure. */
 	dev->open = &netdev_open;
 	dev->hard_start_xmit = &start_tx;
@@ -524,11 +585,9 @@
 	dev->do_ioctl = &netdev_ioctl;
 	dev->tx_timeout = &tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->change_mtu = &change_mtu;
 	pci_set_drvdata(pdev, dev);
 
-	if (mtu)
-		dev->mtu = mtu;
-
 	i = register_netdev(dev);
 	if (i)
 		goto err_out_unmap_rx;
@@ -542,21 +601,30 @@
 	if (1) {
 		int phy, phy_idx = 0;
 		np->phys[0] = 1;		/* Default setting */
-		for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) {
-			int mii_status = mdio_read(dev, phy, 1);
+		np->mii_preamble_required++;
+		for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) {
+			int mii_status = mdio_read(dev, phy, MII_BMSR);
 			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
 				np->phys[phy_idx++] = phy;
-				np->advertising = mdio_read(dev, phy, 4);
+				np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
+				if ((mii_status & 0x0040) == 0)
+					np->mii_preamble_required++;
 				printk(KERN_INFO "%s: MII PHY found at address %d, status "
 					   "0x%4.4x advertising %4.4x.\n",
-					   dev->name, phy, mii_status, np->advertising);
+					   dev->name, phy, mii_status, np->mii_if.advertising);
 			}
 		}
-		np->mii_cnt = phy_idx;
-		if (phy_idx == 0)
-			printk(KERN_INFO "%s: No MII transceiver found!, ASIC status %x\n",
+		np->mii_preamble_required--;
+
+		if (phy_idx == 0) {
+			printk(KERN_INFO "%s: No MII transceiver found, aborting.  ASIC status %x\n",
 				   dev->name, readl(ioaddr + ASICCtrl));
+			goto err_out_unregister;
+		}
+
+		np->mii_if.phy_id = np->phys[0];
 	}
+
 	/* Parse override configuration */
 	np->an_enable = 1;
 	if (card_idx < MAX_UNITS) {
@@ -565,23 +633,29 @@
 			if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
 			    strcmp (media[card_idx], "4") == 0) {
 				np->speed = 100;
-				np->full_duplex = 1;
+				np->mii_if.full_duplex = 1;
 			} else if (strcmp (media[card_idx], "100mbps_hd") == 0
 				   || strcmp (media[card_idx], "3") == 0) {
 				np->speed = 100;
-				np->full_duplex = 0;
+				np->mii_if.full_duplex = 0;
 			} else if (strcmp (media[card_idx], "10mbps_fd") == 0 ||
 				   strcmp (media[card_idx], "2") == 0) {
 				np->speed = 10;
-				np->full_duplex = 1;
+				np->mii_if.full_duplex = 1;
 			} else if (strcmp (media[card_idx], "10mbps_hd") == 0 ||
 				   strcmp (media[card_idx], "1") == 0) {
 				np->speed = 10;
-				np->full_duplex = 0;
+				np->mii_if.full_duplex = 0;
 			} else {
 				np->an_enable = 1;
 			}
 		}
+		if (tx_coalesce < 1)
+			tx_coalesce = 1;
+		else if (tx_coalesce > TX_QUEUE_LEN - 1)
+			tx_coalesce = TX_QUEUE_LEN - 1;
+		if (flowctrl == 0)
+			np->flowctrl = 0;
 	}
 
 	/* Fibre PHY? */
@@ -589,7 +663,7 @@
 		/* Default 100Mbps Full */
 		if (np->an_enable) {
 			np->speed = 100;
-			np->full_duplex = 1;
+			np->mii_if.full_duplex = 1;
 			np->an_enable = 0;
 		}
 	}
@@ -601,24 +675,26 @@
 	if (!np->an_enable) {
 		mii_ctl = 0;
 		mii_ctl |= (np->speed == 100) ? BMCR_SPEED100 : 0;
-		mii_ctl |= (np->full_duplex) ? BMCR_FULLDPLX : 0;
+		mii_ctl |= (np->mii_if.full_duplex) ? BMCR_FULLDPLX : 0;
 		mdio_write (dev, np->phys[0], MII_BMCR, mii_ctl);
 		printk (KERN_INFO "Override speed=%d, %s duplex\n",
-			np->speed, np->full_duplex ? "Full" : "Half");
+			np->speed, np->mii_if.full_duplex ? "Full" : "Half");
 
 	}
 
 	/* Perhaps move the reset here? */
 	/* Reset the chip to erase previous misconfiguration. */
-	if (debug > 1)
+	if (netif_msg_hw(np))
 		printk("ASIC Control is %x.\n", readl(ioaddr + ASICCtrl));
 	writew(0x007f, ioaddr + ASICCtrl + 2);
-	if (debug > 1)
+	if (netif_msg_hw(np))
 		printk("ASIC Control is now %x.\n", readl(ioaddr + ASICCtrl));
 
 	card_idx++;
 	return 0;
 
+err_out_unregister:
+	unregister_netdev(dev);
 err_out_unmap_rx:
         pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);
 err_out_unmap_tx:
@@ -635,7 +711,16 @@
 	return -ENODEV;
 }
 
-
+static int change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > 8191)) /* Set by RxDMAFrameLen */
+		return -EINVAL;
+	if (netif_running(dev))
+		return -EBUSY;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
 /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */
 static int __devinit eeprom_read(long ioaddr, int location)
 {
@@ -658,11 +743,6 @@
 	met by back-to-back 33Mhz PCI cycles. */
 #define mdio_delay() readb(mdio_addr)
 
-/* Set iff a MII transceiver on any interface requires mdio preamble.
-   This only set with older tranceivers, so the extra
-   code size of a per-interface flag is not worthwhile. */
-static const char mii_preamble_required = 1;
-
 enum mii_reg_bits {
 	MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004,
 };
@@ -687,11 +767,12 @@
 
 static int mdio_read(struct net_device *dev, int phy_id, int location)
 {
+	struct netdev_private *np = dev->priv;
 	long mdio_addr = dev->base_addr + MIICtrl;
 	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
 	int i, retval = 0;
 
-	if (mii_preamble_required)
+	if (np->mii_preamble_required)
 		mdio_sync(mdio_addr);
 
 	/* Shift the read command bits out. */
@@ -716,11 +797,12 @@
 
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
 {
+	struct netdev_private *np = dev->priv;
 	long mdio_addr = dev->base_addr + MIICtrl;
 	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
 	int i;
 
-	if (mii_preamble_required)
+	if (np->mii_preamble_required)
 		mdio_sync(mdio_addr);
 
 	/* Shift the command bits out. */
@@ -742,7 +824,6 @@
 	return;
 }
 
-
 static int netdev_open(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
@@ -755,7 +836,7 @@
 	if (i)
 		return i;
 
-	if (debug > 1)
+	if (netif_msg_ifup(np))
 		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
 			   dev->name, dev->irq);
 
@@ -768,6 +849,10 @@
 		writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
 
 	/* Initialize other registers. */
+	writew(dev->mtu + 14, ioaddr + MaxFrameSize);
+	if (dev->mtu > 2047)
+		writel(readl(ioaddr + ASICCtrl) | 0x0C, ioaddr + ASICCtrl);
+
 	/* Configure the PCI bus bursts and FIFO thresholds. */
 
 	if (dev->if_port == 0)
@@ -779,17 +864,15 @@
 	writew(0, ioaddr + IntrEnable);
 	writew(0, ioaddr + DownCounter);
 	/* Set the chip to poll every N*320nsec. */
-	writeb(100, ioaddr + RxDescPoll);
-	writeb(127, ioaddr + TxDescPoll);
+	writeb(100, ioaddr + RxDMAPollPeriod);
+	writeb(127, ioaddr + TxDMAPollPeriod);
+	/* Fix DFE-580TX packet drop issue */
+	writeb(0x01, ioaddr + DebugCtrl1);
 	netif_start_queue(dev);
 
-	/* Enable interrupts by setting the interrupt mask. */
-	writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst | IntrTxDone
-		   | StatsMax | LinkChange, ioaddr + IntrEnable);
-
 	writew(StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
 
-	if (debug > 2)
+	if (netif_msg_ifup(np))
 		printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x "
 			   "MAC Control %x, %4.4x %4.4x.\n",
 			   dev->name, readl(ioaddr + RxStatus), readb(ioaddr + TxStatus),
@@ -803,6 +886,9 @@
 	np->timer.function = &netdev_timer;				/* timer handler */
 	add_timer(&np->timer);
 
+	/* Enable interrupts by setting the interrupt mask. */
+	writew(DEFAULT_INTR, ioaddr + IntrEnable);
+
 	return 0;
 }
 
@@ -811,21 +897,22 @@
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA);
-	int negotiated = mii_lpa & np->advertising;
+	int negotiated = mii_lpa & np->mii_if.advertising;
 	int duplex;
-	
+
 	/* Force media */
 	if (!np->an_enable || mii_lpa == 0xffff) {
-		if (np->full_duplex)
+		if (np->mii_if.full_duplex)
 			writew (readw (ioaddr + MACCtrl0) | EnbFullDuplex,
 				ioaddr + MACCtrl0);
 		return;
 	}
+
 	/* Autonegotiation */
 	duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
-	if (np->full_duplex != duplex) {
-		np->full_duplex = duplex;
-		if (debug)
+	if (np->mii_if.full_duplex != duplex) {
+		np->mii_if.full_duplex = duplex;
+		if (netif_msg_link(np))
 			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d "
 				   "negotiated capability %4.4x.\n", dev->name,
 				   duplex ? "full" : "half", np->phys[0], negotiated);
@@ -840,7 +927,7 @@
 	long ioaddr = dev->base_addr;
 	int next_tick = 10*HZ;
 
-	if (debug > 3) {
+	if (netif_msg_timer(np)) {
 		printk(KERN_DEBUG "%s: Media selection timer tick, intr status %4.4x, "
 			   "Tx %x Rx %x.\n",
 			   dev->name, readw(ioaddr + IntrEnable),
@@ -855,9 +942,13 @@
 {
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
+	long flag;
 
-	printk(KERN_WARNING "%s: Transmit timed out, status %2.2x,"
-		   " resetting...\n", dev->name, readb(ioaddr + TxStatus));
+	writew(0, ioaddr + IntrEnable);
+	printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x "
+		   "TxFrameId %2.2x,"
+		   " resetting...\n", dev->name, readb(ioaddr + TxStatus),
+		   readb(ioaddr + TxFrameId));
 
 	{
 		int i;
@@ -866,22 +957,25 @@
 			printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
 		printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
 		for (i = 0; i < TX_RING_SIZE; i++)
-			printk(" %4.4x", np->tx_ring[i].status);
+			printk(" %8.8x", np->tx_ring[i].status);
 		printk("\n");
+		printk(KERN_DEBUG "cur_tx=%d dirty_tx=%d\n", np->cur_tx, np->dirty_tx);
+		printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
 	}
+	spin_lock_irqsave(&np->lock, flag);
+	reset_tx(dev);
+	spin_unlock_irqrestore(&np->lock, flag);
 
 	/* Perhaps we should reinitialize the hardware here. */
 	dev->if_port = 0;
 	/* Stop and restart the chip's Tx processes . */
 
 	/* Trigger an immediate transmit demand. */
-	writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst | IntrTxDone
-		   | StatsMax | LinkChange, ioaddr + IntrEnable);
+	writew(DEFAULT_INTR, ioaddr + IntrEnable);
 
 	dev->trans_start = jiffies;
 	np->stats.tx_errors++;
-
-	if (!np->tx_full)
+	if (!netif_queue_stopped(dev))
 		netif_wake_queue(dev);
 }
 
@@ -892,15 +986,14 @@
 	struct netdev_private *np = dev->priv;
 	int i;
 
-	np->tx_full = 0;
 	np->cur_rx = np->cur_tx = 0;
 	np->dirty_rx = np->dirty_tx = 0;
 
-	np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
+	np->rx_buf_sz = (dev->mtu <= 1520 ? PKT_BUF_SZ : dev->mtu + 16);
 
 	/* Initialize all Rx descriptors. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		np->rx_ring[i].next_desc = cpu_to_le32(np->rx_ring_dma + 
+		np->rx_ring[i].next_desc = cpu_to_le32(np->rx_ring_dma +
 			((i+1)%RX_RING_SIZE)*sizeof(*np->rx_ring));
 		np->rx_ring[i].status = 0;
 		np->rx_ring[i].frag[0].length = 0;
@@ -916,7 +1009,7 @@
 		skb->dev = dev;		/* Mark as being used by this device. */
 		skb_reserve(skb, 2);	/* 16 byte align the IP header. */
 		np->rx_ring[i].frag[0].addr = cpu_to_le32(
-			pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, 
+			pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz,
 				PCI_DMA_FROMDEVICE));
 		np->rx_ring[i].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag);
 	}
@@ -929,15 +1022,16 @@
 	return;
 }
 
-static int start_tx(struct sk_buff *skb, struct net_device *dev)
+static int
+start_tx (struct sk_buff *skb, struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
 	struct netdev_desc *txdesc;
 	unsigned entry;
+	long ioaddr = dev->base_addr;
 
 	/* Note: Ordering is important here, set the field with the
 	   "ownership" bit last, and only then increment cur_tx. */
-
 	/* Calculate the next Tx descriptor entry. */
 	entry = np->cur_tx % TX_RING_SIZE;
 	np->tx_skbuff[entry] = skb;
@@ -945,11 +1039,17 @@
 
 	txdesc->next_desc = 0;
 	/* Note: disable the interrupt generation here before releasing. */
-	txdesc->status =
-		cpu_to_le32((entry<<2) | DescIntrOnDMADone | DescIntrOnTx | DisableAlign);
-	txdesc->frag[0].addr = cpu_to_le32(pci_map_single(np->pci_dev, 
-		skb->data, skb->len, PCI_DMA_TODEVICE));
-	txdesc->frag[0].length = cpu_to_le32(skb->len | LastFrag);
+	if (entry % tx_coalesce == 0) {
+		txdesc->status = cpu_to_le32 ((entry << 2) |
+				 DescIntrOnTx | DisableAlign);
+
+	} else {
+		txdesc->status = cpu_to_le32 ((entry << 2) | DisableAlign);
+	}
+	txdesc->frag[0].addr = cpu_to_le32 (pci_map_single (np->pci_dev, skb->data,
+							skb->len,
+							PCI_DMA_TODEVICE));
+	txdesc->frag[0].length = cpu_to_le32 (skb->len | LastFrag);
 	if (np->last_tx)
 		np->last_tx->next_desc = cpu_to_le32(np->tx_ring_dma +
 			entry*sizeof(struct netdev_desc));
@@ -957,24 +1057,63 @@
 	np->cur_tx++;
 
 	/* On some architectures: explicitly flush cache lines here. */
-
-	if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1) {
+	if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1
+			&& !netif_queue_stopped(dev)) {
 		/* do nothing */
 	} else {
-		np->tx_full = 1;
-		netif_stop_queue(dev);
+		netif_stop_queue (dev);
 	}
 	/* Side effect: The read wakes the potentially-idle transmit channel. */
-	if (readl(dev->base_addr + TxListPtr) == 0)
-		writel(np->tx_ring_dma + entry*sizeof(*np->tx_ring),
+	if (readl (dev->base_addr + TxListPtr) == 0)
+		writel (np->tx_ring_dma + entry*sizeof(*np->tx_ring),
 			dev->base_addr + TxListPtr);
 
 	dev->trans_start = jiffies;
 
-	if (debug > 4) {
-		printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
-			   dev->name, np->cur_tx, entry);
+	if (netif_msg_tx_queued(np)) {
+		printk (KERN_DEBUG
+			"%s: Transmit frame #%d queued in slot %d.\n",
+			dev->name, np->cur_tx, entry);
+	}
+	if (tx_coalesce > 1)
+		writel (1000, ioaddr + DownCounter);
+	return 0;
+}
+/* Reset hardware tx and reset TxListPtr to TxFrameId */
+static int
+reset_tx (struct net_device *dev)
+{
+	struct netdev_private *np = (struct netdev_private*) dev->priv;
+	long ioaddr = dev->base_addr;
+	struct sk_buff *skb;
+	int i;
+	int irq = in_interrupt();
+	
+	/* reset tx logic */
+	writel (0, dev->base_addr + TxListPtr);
+	writew (TxReset | DMAReset | FIFOReset | NetworkReset,
+			ioaddr + ASICCtrl + 2);
+	for (i=50; i > 0; i--) {
+		if ((readw(ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
+			break;
+		mdelay(1);
+	}
+	/* free all tx skbuff */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		skb = np->tx_skbuff[i];
+		if (skb) {
+			pci_unmap_single(np->pci_dev, 
+				np->tx_ring[i].frag[0].addr, skb->len,
+				PCI_DMA_TODEVICE);
+			if (irq)
+				dev_kfree_skb_irq (skb);
+			else
+				dev_kfree_skb (skb);
+			np->tx_skbuff[i] = 0;
+			np->stats.tx_dropped++;
+		}
 	}
+	np->cur_tx = np->dirty_tx = 0;
 	return 0;
 }
 
@@ -986,142 +1125,139 @@
 	struct netdev_private *np;
 	long ioaddr;
 	int boguscnt = max_interrupt_work;
+	int hw_frame_id;
 
 	ioaddr = dev->base_addr;
 	np = dev->priv;
-	spin_lock(&np->lock);
 
 	do {
 		int intr_status = readw(ioaddr + IntrStatus);
-		writew(intr_status & (IntrRxDone | IntrRxDMADone | IntrPCIErr |
-			IntrDrvRqst | IntrTxDone | IntrTxDMADone | StatsMax | 
-			LinkChange), ioaddr + IntrStatus);
+		writew(intr_status, ioaddr + IntrStatus);
 
-		if (debug > 4)
+		if (netif_msg_intr(np))
 			printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
 				   dev->name, intr_status);
 
-		if (intr_status == 0)
+		if (!(intr_status & DEFAULT_INTR))
 			break;
 
-		if (intr_status & (IntrRxDone|IntrRxDMADone))
-			netdev_rx(dev);
+		if (intr_status & (IntrRxDMADone)) {
+			writew(DEFAULT_INTR & ~(IntrRxDone|IntrRxDMADone),
+					ioaddr + IntrEnable);
+			if (np->budget < 0)
+				np->budget = RX_BUDGET;
+			tasklet_schedule(&np->rx_tasklet);
+		}
 
-		if (intr_status & IntrTxDone) {
+		if (intr_status & (IntrTxDone | IntrDrvRqst)) {
 			int boguscnt = 32;
-			int tx_status = readw(ioaddr + TxStatus);
+			int tx_status = readw (ioaddr + TxStatus);
 			while (tx_status & 0x80) {
-				if (debug > 4)
-					printk("%s: Transmit status is %2.2x.\n",
-						   dev->name, tx_status);
+				if (netif_msg_tx_done(np))
+					printk
+					    ("%s: Transmit status is %2.2x.\n",
+					     dev->name, tx_status);
 				if (tx_status & 0x1e) {
 					np->stats.tx_errors++;
-					if (tx_status & 0x10)  np->stats.tx_fifo_errors++;
-#ifdef ETHER_STATS
-					if (tx_status & 0x08)  np->stats.collisions16++;
-#else
-					if (tx_status & 0x08)  np->stats.collisions++;
-#endif
-					if (tx_status & 0x04)  np->stats.tx_fifo_errors++;
-					if (tx_status & 0x02)  np->stats.tx_window_errors++;
+					if (tx_status & 0x10)
+						np->stats.tx_fifo_errors++;
+					if (tx_status & 0x08)
+						np->stats.collisions++;
+					if (tx_status & 0x02)
+						np->stats.tx_window_errors++;
 					/* This reset has not been verified!. */
-					if (tx_status & 0x10) {			/* Reset the Tx. */
-						writew(0x001c, ioaddr + ASICCtrl + 2);
-#if 0					/* Do we need to reset the Tx pointer here? */
-						writel(np->tx_ring_dma
-							+ np->dirty_tx*sizeof(*np->tx_ring),
-							dev->base_addr + TxListPtr);
-#endif
+					if (tx_status & 0x10) {	/* Reset the Tx. */
+						np->stats.tx_fifo_errors++;
+						spin_lock(&np->lock);
+						reset_tx(dev);
+						spin_unlock(&np->lock);
 					}
-					if (tx_status & 0x1e) 		/* Restart the Tx. */
-						writew(TxEnable, ioaddr + MACCtrl1);
+					if (tx_status & 0x1e)	/* Restart the Tx. */
+						writew (TxEnable,
+							ioaddr + MACCtrl1);
 				}
 				/* Yup, this is a documentation bug.  It cost me *hours*. */
-				writew(0, ioaddr + TxStatus);
-				tx_status = readb(ioaddr + TxStatus);
+				writew (0, ioaddr + TxStatus);
+				tx_status = readw (ioaddr + TxStatus);
 				if (--boguscnt < 0)
 					break;
 			}
 		}
+		spin_lock(&np->lock);
+		hw_frame_id = readb(ioaddr + TxFrameId);
 		for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
 			int entry = np->dirty_tx % TX_RING_SIZE;
 			struct sk_buff *skb;
-
-			if ( ! (np->tx_ring[entry].status & 0x00010000))
+			int sw_frame_id;
+			sw_frame_id = (np->tx_ring[entry].status >> 2) & 0xff;
+			
+			if (sw_frame_id == hw_frame_id)
 				break;
 			skb = np->tx_skbuff[entry];
 			/* Free the original skb. */
-			pci_unmap_single(np->pci_dev, 
-				np->tx_ring[entry].frag[0].addr, 
+			pci_unmap_single(np->pci_dev,
+				np->tx_ring[entry].frag[0].addr,
 				skb->len, PCI_DMA_TODEVICE);
-			dev_kfree_skb_irq(skb);
+			dev_kfree_skb_irq (np->tx_skbuff[entry]);
 			np->tx_skbuff[entry] = 0;
 		}
-		if (np->tx_full
-			&& np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
+		spin_unlock(&np->lock);
+		if (netif_queue_stopped(dev) &&
+			np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
 			/* The ring is no longer full, clear tbusy. */
-			np->tx_full = 0;
-			netif_wake_queue(dev);
+			netif_wake_queue (dev);
 		}
 
 		/* Abnormal error summary/uncommon events handlers. */
-		if (intr_status & (IntrDrvRqst | IntrPCIErr | LinkChange | StatsMax))
+		if (intr_status & (IntrPCIErr | LinkChange | StatsMax))
 			netdev_error(dev, intr_status);
 		if (--boguscnt < 0) {
 			get_stats(dev);
-			if (debug > 1) 
+			if (netif_msg_hw(np))
 				printk(KERN_WARNING "%s: Too much work at interrupt, "
 				   "status=0x%4.4x / 0x%4.4x.\n",
 				   dev->name, intr_status, readw(ioaddr + IntrClear));
-			/* Re-enable us in 3.2msec. */
-			writew(0, ioaddr + IntrEnable);
-			writew(1000, ioaddr + DownCounter);
-			writew(IntrDrvRqst, ioaddr + IntrEnable);
 			break;
 		}
 	} while (1);
-
-	if (debug > 3)
+	if (netif_msg_intr(np))
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
 			   dev->name, readw(ioaddr + IntrStatus));
+	if (np->cur_tx - np->dirty_tx > 0 && tx_coalesce > 1)
+		writel(100, ioaddr + DownCounter);
 
-	spin_unlock(&np->lock);
 }
 
-/* This routine is logically part of the interrupt handler, but separated
-   for clarity and better register allocation. */
-static int netdev_rx(struct net_device *dev)
+static void rx_poll(unsigned long data)
 {
+	struct net_device *dev = (struct net_device *)data;
 	struct netdev_private *np = dev->priv;
 	int entry = np->cur_rx % RX_RING_SIZE;
-	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
-
-	if (debug > 4) {
-		printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",
-			   entry, np->rx_ring[entry].status);
-	}
+	int boguscnt = np->budget;
+	long ioaddr = dev->base_addr;
+	int received = 0;
 
 	/* If EOP is set on the next entry, it's a new packet. Send it up. */
 	while (1) {
 		struct netdev_desc *desc = &(np->rx_ring[entry]);
-		u32 frame_status;
+		u32 frame_status = le32_to_cpu(desc->status);
 		int pkt_len;
 
+		if (--boguscnt < 0) {
+			goto not_done;
+		}
 		if (!(desc->status & DescOwn))
 			break;
-		frame_status = le32_to_cpu(desc->status);
 		pkt_len = frame_status & 0x1fff;	/* Chip omits the CRC. */
-		if (debug > 4)
+		if (netif_msg_rx_status(np))
 			printk(KERN_DEBUG "  netdev_rx() status was %8.8x.\n",
 				   frame_status);
-		if (--boguscnt < 0)
-			break;
 		pci_dma_sync_single(np->pci_dev, desc->frag[0].addr,
 			np->rx_buf_sz, PCI_DMA_FROMDEVICE);
-		
+
 		if (frame_status & 0x001f4000) {
 			/* There was a error. */
-			if (debug > 2)
+			if (netif_msg_rx_err(np))
 				printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",
 					   frame_status);
 			np->stats.rx_errors++;
@@ -1136,9 +1272,8 @@
 			}
 		} else {
 			struct sk_buff *skb;
-
 #ifndef final_version
-			if (debug > 4)
+			if (netif_msg_rx_status(np))
 				printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d"
 					   ", bogus_cnt %d.\n",
 					   pkt_len, boguscnt);
@@ -1152,9 +1287,9 @@
 				eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
 			} else {
-				pci_unmap_single(np->pci_dev, 
+				pci_unmap_single(np->pci_dev,
 					desc->frag[0].addr,
-					np->rx_buf_sz, 
+					np->rx_buf_sz,
 					PCI_DMA_FROMDEVICE);
 				skb_put(skb = np->rx_skbuff[entry], pkt_len);
 				np->rx_skbuff[entry] = NULL;
@@ -1164,11 +1299,36 @@
 			netif_rx(skb);
 			dev->last_rx = jiffies;
 		}
-		entry = (++np->cur_rx) % RX_RING_SIZE;
+		entry = (entry + 1) % RX_RING_SIZE;
+		received++;
 	}
+	np->cur_rx = entry;
+	refill_rx (dev);
+	np->budget -= received;
+	writew(DEFAULT_INTR, ioaddr + IntrEnable);
+	return;
+
+not_done:
+	np->cur_rx = entry;
+	refill_rx (dev);
+	if (!received)
+		received = 1;
+	np->budget -= received;
+	if (np->budget <= 0)
+		np->budget = RX_BUDGET;
+	tasklet_schedule(&np->rx_tasklet);
+	return;
+}
+
+static void refill_rx (struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	int entry;
+	int cnt = 0;
 
 	/* Refill the Rx ring buffers. */
-	for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
+	for (;(np->cur_rx - np->dirty_rx + RX_RING_SIZE) % RX_RING_SIZE > 0;
+		np->dirty_rx = (np->dirty_rx + 1) % RX_RING_SIZE) {
 		struct sk_buff *skb;
 		entry = np->dirty_rx % RX_RING_SIZE;
 		if (np->rx_skbuff[entry] == NULL) {
@@ -1179,19 +1339,17 @@
 			skb->dev = dev;		/* Mark as being used by this device. */
 			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 			np->rx_ring[entry].frag[0].addr = cpu_to_le32(
-				pci_map_single(np->pci_dev, skb->tail, 
+				pci_map_single(np->pci_dev, skb->tail,
 					np->rx_buf_sz, PCI_DMA_FROMDEVICE));
 		}
 		/* Perhaps we need not reset this field. */
 		np->rx_ring[entry].frag[0].length =
 			cpu_to_le32(np->rx_buf_sz | LastFrag);
 		np->rx_ring[entry].status = 0;
+		cnt++;
 	}
-
-	/* No need to restart Rx engine, it will poll. */
-	return 0;
+	return;
 }
-
 static void netdev_error(struct net_device *dev, int intr_status)
 {
 	long ioaddr = dev->base_addr;
@@ -1199,43 +1357,40 @@
 	u16 mii_ctl, mii_advertise, mii_lpa;
 	int speed;
 
-	if (intr_status & IntrDrvRqst) {
-		/* Stop the down counter and turn interrupts back on. */
-		if (debug > 1)
-			printk("%s: Turning interrupts back on.\n", dev->name);
-		writew(0, ioaddr + IntrEnable);
-		writew(0, ioaddr + DownCounter);
-		writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst |
-			   IntrTxDone | StatsMax | LinkChange, ioaddr + IntrEnable);
-		/* Ack buggy InRequest */
-		writew (IntrDrvRqst, ioaddr + IntrStatus);
-	}
 	if (intr_status & LinkChange) {
 		if (np->an_enable) {
 			mii_advertise = mdio_read (dev, np->phys[0], MII_ADVERTISE);
 			mii_lpa= mdio_read (dev, np->phys[0], MII_LPA);
 			mii_advertise &= mii_lpa;
 			printk (KERN_INFO "%s: Link changed: ", dev->name);
-			if (mii_advertise & ADVERTISE_100FULL)
+			if (mii_advertise & ADVERTISE_100FULL) {
+				np->speed = 100;
 				printk ("100Mbps, full duplex\n");
-			else if (mii_advertise & ADVERTISE_100HALF)
+			} else if (mii_advertise & ADVERTISE_100HALF) {
+				np->speed = 100;
 				printk ("100Mbps, half duplex\n");
-			else if (mii_advertise & ADVERTISE_10FULL)
+			} else if (mii_advertise & ADVERTISE_10FULL) {
+				np->speed = 10;
 				printk ("10Mbps, full duplex\n");
-			else if (mii_advertise & ADVERTISE_10HALF)
+			} else if (mii_advertise & ADVERTISE_10HALF) {
+				np->speed = 10;
 				printk ("10Mbps, half duplex\n");
-			else
+			} else
 				printk ("\n");
 
 		} else {
 			mii_ctl = mdio_read (dev, np->phys[0], MII_BMCR);
 			speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10;
+			np->speed = speed;
 			printk (KERN_INFO "%s: Link changed: %dMbps ,",
 				dev->name, speed);
 			printk ("%s duplex.\n", (mii_ctl & BMCR_FULLDPLX) ?
 				"full" : "half");
 		}
 		check_duplex (dev);
+		if (np->flowctrl == 0)
+			writew(readw(ioaddr + MACCtrl0) & ~EnbFlowCtrl,
+				ioaddr + MACCtrl0);
 	}
 	if (intr_status & StatsMax) {
 		get_stats(dev);
@@ -1294,11 +1449,16 @@
 		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
 	} else if (dev->mc_count) {
 		struct dev_mc_list *mclist;
-		memset(mc_filter, 0, sizeof(mc_filter));
+		int bit;
+		int index;
+		int crc;
+		memset (mc_filter, 0, sizeof (mc_filter));
 		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-			 i++, mclist = mclist->next) {
-			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
-					mc_filter);
+		     i++, mclist = mclist->next) {
+			crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
+			for (index=0, bit=0; bit < 6; bit++, crc <<= 1)
+				if (crc & 0x80000000) index |= 1 << bit;
+			mc_filter[index/16] |= (1 << (index % 16));
 		}
 		rx_mode = AcceptBroadcast | AcceptMultiHash | AcceptMyPhys;
 	} else {
@@ -1314,52 +1474,101 @@
 {
 	struct netdev_private *np = dev->priv;
 	u32 ethcmd;
-		
+
 	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
 		return -EFAULT;
 
         switch (ethcmd) {
-        case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strcpy(info.driver, DRV_NAME);
-		strcpy(info.version, DRV_VERSION);
-		strcpy(info.bus_info, np->pci_dev->slot_name);
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
+		/* get constant driver settings/info */
+        	case ETHTOOL_GDRVINFO: {
+			struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+			strcpy(info.driver, DRV_NAME);
+			strcpy(info.version, DRV_VERSION);
+			strcpy(info.bus_info, np->pci_dev->slot_name);
+			memset(&info.fw_version, 0, sizeof(info.fw_version));
+			if (copy_to_user(useraddr, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+		}
+
+		/* get media settings */
+		case ETHTOOL_GSET: {
+			struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+			spin_lock_irq(&np->lock);
+			mii_ethtool_gset(&np->mii_if, &ecmd);
+			spin_unlock_irq(&np->lock);
+			if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+				return -EFAULT;
+			return 0;
+		}
+		/* set media settings */
+		case ETHTOOL_SSET: {
+			int r;
+			struct ethtool_cmd ecmd;
+			if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+				return -EFAULT;
+			spin_lock_irq(&np->lock);
+			r = mii_ethtool_sset(&np->mii_if, &ecmd);
+			spin_unlock_irq(&np->lock);
+			return r;
+		}
+
+		/* restart autonegotiation */
+		case ETHTOOL_NWAY_RST: {
+			return mii_nway_restart(&np->mii_if);
+		}
+
+		/* get link status */
+		case ETHTOOL_GLINK: {
+			struct ethtool_value edata = {ETHTOOL_GLINK};
+			edata.data = mii_link_ok(&np->mii_if);
+			if (copy_to_user(useraddr, &edata, sizeof(edata)))
+				return -EFAULT;
+			return 0;
+		}
+
+		/* get message-level */
+		case ETHTOOL_GMSGLVL: {
+			struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+			edata.data = np->msg_enable;
+			if (copy_to_user(useraddr, &edata, sizeof(edata)))
+				return -EFAULT;
+			return 0;
+		}
+		/* set message-level */
+		case ETHTOOL_SMSGLVL: {
+			struct ethtool_value edata;
+			if (copy_from_user(&edata, useraddr, sizeof(edata)))
+				return -EFAULT;
+			np->msg_enable = edata.data;
+			return 0;
+		}
+
+		default:
+		return -EOPNOTSUPP;
 
         }
-	
-	return -EOPNOTSUPP;
 }
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
+	struct netdev_private *np = dev->priv;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+	int rc;
 
-	switch(cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
-		data->phy_id = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f;
-		/* Fall Through */
-
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
-		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
-		return 0;
-
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-		return 0;
-	default:
-		return -EOPNOTSUPP;
+	if (!netif_running(dev))
+		return -EINVAL;
+
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
 	}
+
+	return rc;
 }
 
 static int netdev_close(struct net_device *dev)
@@ -1371,7 +1580,7 @@
 
 	netif_stop_queue(dev);
 
-	if (debug > 1) {
+	if (netif_msg_ifdown(np)) {
 		printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %2.2x "
 			   "Rx %4.4x Int %2.2x.\n",
 			   dev->name, readb(ioaddr + TxStatus),
@@ -1387,7 +1596,7 @@
 	writew(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1);
 
 #ifdef __i386__
-	if (debug > 2) {
+	if (netif_msg_hw(np)) {
 		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
 			   (int)(np->tx_ring_dma));
 		for (i = 0; i < TX_RING_SIZE; i++)
@@ -1414,8 +1623,8 @@
 		np->rx_ring[i].frag[0].addr = 0xBADF00D0; /* An invalid address. */
 		skb = np->rx_skbuff[i];
 		if (skb) {
-			pci_unmap_single(np->pci_dev, 
-				np->rx_ring[i].frag[0].addr, np->rx_buf_sz, 
+			pci_unmap_single(np->pci_dev,
+				np->rx_ring[i].frag[0].addr, np->rx_buf_sz,
 				PCI_DMA_FROMDEVICE);
 			dev_kfree_skb(skb);
 			np->rx_skbuff[i] = 0;
@@ -1424,7 +1633,7 @@
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		skb = np->tx_skbuff[i];
 		if (skb) {
-			pci_unmap_single(np->pci_dev, 
+			pci_unmap_single(np->pci_dev,
 				np->tx_ring[i].frag[0].addr, skb->len,
 				PCI_DMA_TODEVICE);
 			dev_kfree_skb(skb);
@@ -1438,15 +1647,15 @@
 static void __devexit sundance_remove1 (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	
+
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	if (dev) {
 		struct netdev_private *np = dev->priv;
 
 		unregister_netdev(dev);
-        	pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, 
+        	pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring,
 			np->rx_ring_dma);
-	        pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, 
+	        pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring,
 			np->tx_ring_dma);
 		pci_release_regions(pdev);
 #ifndef USE_IO_OPS
@@ -1480,3 +1689,5 @@
 
 module_init(sundance_init);
 module_exit(sundance_exit);
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/sunhme.c linux-2.4.20/drivers/net/sunhme.c
--- linux-2.4.19/drivers/net/sunhme.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/sunhme.c	2002-10-29 11:18:36.000000000 +0000
@@ -76,6 +76,7 @@
 /* accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */
 MODULE_PARM(macaddr, "6i");
 MODULE_PARM_DESC(macaddr, "Happy Meal MAC address to set");
+MODULE_LICENSE("GPL");
 
 static struct happy_meal *root_happy_dev;
 
@@ -192,7 +193,6 @@
 };
 
 MODULE_DEVICE_TABLE(pci, happymeal_pci_ids);
-MODULE_LICENSE("GPL");
 
 #endif
 
@@ -2201,7 +2201,7 @@
 	 */
 	if ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO) {
 		if (request_irq(dev->irq, &happy_meal_interrupt,
-				SA_SHIRQ, "HAPPY MEAL", (void *)dev)) {
+				SA_SHIRQ, dev->name, (void *)dev)) {
 			HMD(("EAGAIN\n"));
 #ifdef __sparc__
 			printk(KERN_ERR "happy_meal(SBUS): Can't order irq %s to go.\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/tg3.c linux-2.4.20/drivers/net/tg3.c
--- linux-2.4.19/drivers/net/tg3.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/tg3.c	2002-10-29 11:18:39.000000000 +0000
@@ -48,12 +48,19 @@
 #define TG3_VLAN_TAG_USED 0
 #endif
 
+#ifdef NETIF_F_TSO
+/* XXX some bug in tso firmware hangs tx cpu, disabled until fixed */
+#define TG3_DO_TSO	0
+#else
+#define TG3_DO_TSO	0
+#endif
+
 #include "tg3.h"
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"0.99"
-#define DRV_MODULE_RELDATE	"Jun 11, 2002"
+#define DRV_MODULE_VERSION	"1.1"
+#define DRV_MODULE_RELDATE	"Aug 30, 2002"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -142,6 +149,8 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702FE,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702X,
@@ -212,6 +221,7 @@
 	tw32(TG3PCI_MISC_HOST_CTRL,
 	     (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
 	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
+	tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
 }
 
 static void tg3_enable_ints(struct tg3 *tp)
@@ -220,9 +230,44 @@
 	     (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
 	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000);
 
-	if (tp->hw_status->status & SD_STATUS_UPDATED)
+	if (tp->hw_status->status & SD_STATUS_UPDATED) {
+		tw32(GRC_LOCAL_CTRL,
+		     tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
+	}
+	tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+}
+
+static inline void tg3_mask_ints(struct tg3 *tp)
+{
+	tw32(TG3PCI_MISC_HOST_CTRL,
+	     (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
+}
+
+static inline void tg3_unmask_ints(struct tg3 *tp)
+{
+	tw32(TG3PCI_MISC_HOST_CTRL,
+	     (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
+	if (tp->hw_status->status & SD_STATUS_UPDATED) {
 		tw32(GRC_LOCAL_CTRL,
 		     tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
+	}
+}
+
+static void tg3_switch_clocks(struct tg3 *tp)
+{
+	if (tr32(TG3PCI_CLOCK_CTRL) & CLOCK_CTRL_44MHZ_CORE) {
+		tw32(TG3PCI_CLOCK_CTRL,
+		     (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK));
+		tr32(TG3PCI_CLOCK_CTRL);
+		udelay(40);
+		tw32(TG3PCI_CLOCK_CTRL,
+		     (CLOCK_CTRL_ALTCLK));
+		tr32(TG3PCI_CLOCK_CTRL);
+		udelay(40);
+	}
+	tw32(TG3PCI_CLOCK_CTRL, 0);
+	tr32(TG3PCI_CLOCK_CTRL);
+	udelay(40);
 }
 
 #define PHY_BUSY_LOOPS	5000
@@ -235,6 +280,7 @@
 	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
 		tw32(MAC_MI_MODE,
 		     (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL));
+		tr32(MAC_MI_MODE);
 		udelay(40);
 	}
 
@@ -247,9 +293,11 @@
 	frame_val |= (MI_COM_CMD_READ | MI_COM_START);
 	
 	tw32(MAC_MI_COM, frame_val);
+	tr32(MAC_MI_COM);
 
 	loops = PHY_BUSY_LOOPS;
 	while (loops-- > 0) {
+		udelay(10);
 		frame_val = tr32(MAC_MI_COM);
 
 		if ((frame_val & MI_COM_BUSY) == 0) {
@@ -257,7 +305,6 @@
 			frame_val = tr32(MAC_MI_COM);
 			break;
 		}
-		udelay(10);
 	}
 
 	ret = -EBUSY;
@@ -268,6 +315,7 @@
 
 	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
 		tw32(MAC_MI_MODE, tp->mi_mode);
+		tr32(MAC_MI_MODE);
 		udelay(40);
 	}
 
@@ -282,6 +330,7 @@
 	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
 		tw32(MAC_MI_MODE,
 		     (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL));
+		tr32(MAC_MI_MODE);
 		udelay(40);
 	}
 
@@ -293,16 +342,17 @@
 	frame_val |= (MI_COM_CMD_WRITE | MI_COM_START);
 	
 	tw32(MAC_MI_COM, frame_val);
+	tr32(MAC_MI_COM);
 
 	loops = PHY_BUSY_LOOPS;
 	while (loops-- > 0) {
+		udelay(10);
 		frame_val = tr32(MAC_MI_COM);
 		if ((frame_val & MI_COM_BUSY) == 0) {
 			udelay(5);
 			frame_val = tr32(MAC_MI_COM);
 			break;
 		}
-		udelay(10);
 	}
 
 	ret = -EBUSY;
@@ -311,6 +361,7 @@
 
 	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
 		tw32(MAC_MI_MODE, tp->mi_mode);
+		tr32(MAC_MI_MODE);
 		udelay(40);
 	}
 
@@ -388,7 +439,9 @@
 				      pm + PCI_PM_CTRL,
 				      power_control);
 		tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
-		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02);
+		tr32(GRC_LOCAL_CTRL);
+		udelay(100);
+
 		return 0;
 
 	case 1:
@@ -404,7 +457,8 @@
 		break;
 
 	default:
-		printk(KERN_WARNING "%s: Invalid power state (%d) requested.\n",
+		printk(KERN_WARNING PFX "%s: Invalid power state (%d) "
+		       "requested.\n",
 		       tp->dev->name, state);
 		return -EINVAL;
 	};
@@ -422,9 +476,12 @@
 		tp->link_config.orig_autoneg = tp->link_config.autoneg;
 	}
 
-	tp->link_config.speed = SPEED_10;
-	tp->link_config.autoneg = AUTONEG_ENABLE;
-	tg3_setup_phy(tp);
+	if (tp->phy_id != PHY_ID_SERDES) {
+		tp->link_config.speed = SPEED_10;
+		tp->link_config.duplex = DUPLEX_HALF;
+		tp->link_config.autoneg = AUTONEG_ENABLE;
+		tg3_setup_phy(tp);
+	}
 
 	tg3_halt(tp);
 
@@ -433,52 +490,114 @@
 	if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) {
 		u32 mac_mode;
 
-		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
+		if (tp->phy_id != PHY_ID_SERDES) {
+			tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
+			udelay(40);
+
+			mac_mode = MAC_MODE_PORT_MODE_MII;
+
+			if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 ||
+			    !(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB))
+				mac_mode |= MAC_MODE_LINK_POLARITY;
+		} else {
+			mac_mode = MAC_MODE_PORT_MODE_TBI;
+		}
 
-		mac_mode = MAC_MODE_PORT_MODE_MII |
-			MAC_MODE_LINK_POLARITY;
 
 		if (((power_caps & PCI_PM_CAP_PME_D3cold) &&
 		     (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)))
 			mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE;
 
 		tw32(MAC_MODE, mac_mode);
+		tr32(MAC_MODE);
+		udelay(100);
+
 		tw32(MAC_RX_MODE, RX_MODE_ENABLE);
+		tr32(MAC_RX_MODE);
+		udelay(10);
 	}
 
 	if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) {
-		tw32(TG3PCI_CLOCK_CTRL,
-		     (CLOCK_CTRL_RXCLK_DISABLE |
-		      CLOCK_CTRL_TXCLK_DISABLE |
-		      CLOCK_CTRL_ALTCLK));
-		tw32(TG3PCI_CLOCK_CTRL,
-		     (CLOCK_CTRL_RXCLK_DISABLE |
-		      CLOCK_CTRL_TXCLK_DISABLE |
-		      CLOCK_CTRL_44MHZ_CORE));
-		tw32(TG3PCI_CLOCK_CTRL,
-		     (CLOCK_CTRL_RXCLK_DISABLE |
-		      CLOCK_CTRL_TXCLK_DISABLE |
-		      CLOCK_CTRL_ALTCLK |
-		      CLOCK_CTRL_44MHZ_CORE));
+		u32 base_val;
+
+		base_val = 0;
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)
+			base_val |= (CLOCK_CTRL_RXCLK_DISABLE |
+				     CLOCK_CTRL_TXCLK_DISABLE);
+
+		tw32(TG3PCI_CLOCK_CTRL, base_val |
+		     CLOCK_CTRL_ALTCLK);
+		tr32(TG3PCI_CLOCK_CTRL);
+		udelay(40);
+
+		tw32(TG3PCI_CLOCK_CTRL, base_val |
+		     CLOCK_CTRL_ALTCLK |
+		     CLOCK_CTRL_44MHZ_CORE);
+		tr32(TG3PCI_CLOCK_CTRL);
+		udelay(40);
+
+		tw32(TG3PCI_CLOCK_CTRL, base_val |
+		     CLOCK_CTRL_44MHZ_CORE);
+		tr32(TG3PCI_CLOCK_CTRL);
+		udelay(40);
 	} else {
-		tw32(TG3PCI_CLOCK_CTRL,
-		     (CLOCK_CTRL_RXCLK_DISABLE |
-		      CLOCK_CTRL_TXCLK_DISABLE |
-		      CLOCK_CTRL_ALTCLK |
-		      CLOCK_CTRL_PWRDOWN_PLL133));
-	}
+		u32 base_val;
 
-	udelay(40);
+		base_val = 0;
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)
+			base_val |= (CLOCK_CTRL_RXCLK_DISABLE |
+				     CLOCK_CTRL_TXCLK_DISABLE);
+
+		tw32(TG3PCI_CLOCK_CTRL, base_val |
+		     CLOCK_CTRL_ALTCLK |
+		     CLOCK_CTRL_PWRDOWN_PLL133);
+		tr32(TG3PCI_CLOCK_CTRL);
+		udelay(40);
+	}
 
-	if ((power_caps & PCI_PM_CAP_PME_D3cold) &&
+	if (!(tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) &&
 	    (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) {
-		/* Move to auxilliary power. */
-		tw32(GRC_LOCAL_CTRL,
-		     (GRC_LCLCTRL_GPIO_OE0 |
-		      GRC_LCLCTRL_GPIO_OE1 |
-		      GRC_LCLCTRL_GPIO_OE2 |
-		      GRC_LCLCTRL_GPIO_OUTPUT0 |
-		      GRC_LCLCTRL_GPIO_OUTPUT1));
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+			tw32(GRC_LOCAL_CTRL,
+			     (GRC_LCLCTRL_GPIO_OE0 |
+			      GRC_LCLCTRL_GPIO_OE1 |
+			      GRC_LCLCTRL_GPIO_OE2 |
+			      GRC_LCLCTRL_GPIO_OUTPUT0 |
+			      GRC_LCLCTRL_GPIO_OUTPUT1));
+			tr32(GRC_LOCAL_CTRL);
+			udelay(100);
+		} else {
+			tw32(GRC_LOCAL_CTRL,
+			     (GRC_LCLCTRL_GPIO_OE0 |
+			      GRC_LCLCTRL_GPIO_OE1 |
+			      GRC_LCLCTRL_GPIO_OE2 |
+			      GRC_LCLCTRL_GPIO_OUTPUT1 |
+			      GRC_LCLCTRL_GPIO_OUTPUT2));
+			tr32(GRC_LOCAL_CTRL);
+			udelay(100);
+
+			tw32(GRC_LOCAL_CTRL,
+			     (GRC_LCLCTRL_GPIO_OE0 |
+			      GRC_LCLCTRL_GPIO_OE1 |
+			      GRC_LCLCTRL_GPIO_OE2 |
+			      GRC_LCLCTRL_GPIO_OUTPUT0 |
+			      GRC_LCLCTRL_GPIO_OUTPUT1 |
+			      GRC_LCLCTRL_GPIO_OUTPUT2));
+			tr32(GRC_LOCAL_CTRL);
+			udelay(100);
+
+			tw32(GRC_LOCAL_CTRL,
+			     (GRC_LCLCTRL_GPIO_OE0 |
+			      GRC_LCLCTRL_GPIO_OE1 |
+			      GRC_LCLCTRL_GPIO_OE2 |
+			      GRC_LCLCTRL_GPIO_OUTPUT0 |
+			      GRC_LCLCTRL_GPIO_OUTPUT1));
+			tr32(GRC_LOCAL_CTRL);
+			udelay(100);
+		}
 	}
 
 	/* Finally, set the new power state. */
@@ -490,9 +609,9 @@
 static void tg3_link_report(struct tg3 *tp)
 {
 	if (!netif_carrier_ok(tp->dev)) {
-		printk("%s: Link is down.\n", tp->dev->name);
+		printk(KERN_INFO PFX "%s: Link is down.\n", tp->dev->name);
 	} else {
-		printk("%s: Link is up at %d Mbps, %s duplex.\n",
+		printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n",
 		       tp->dev->name,
 		       (tp->link_config.active_speed == SPEED_1000 ?
 			1000 :
@@ -501,7 +620,8 @@
 		       (tp->link_config.active_duplex == DUPLEX_FULL ?
 			"full" : "half"));
 
-		printk("%s: Flow control is %s for TX and %s for RX.\n",
+		printk(KERN_INFO PFX "%s: Flow control is %s for TX and "
+		       "%s for RX.\n",
 		       tp->dev->name,
 		       (tp->tg3_flags & TG3_FLAG_TX_PAUSE) ? "on" : "off",
 		       (tp->tg3_flags & TG3_FLAG_RX_PAUSE) ? "on" : "off");
@@ -634,8 +754,9 @@
 				new_adv |= MII_TG3_CTRL_ADV_1000_HALF;
 			if (tp->link_config.advertising & ADVERTISED_1000baseT_Full)
 				new_adv |= MII_TG3_CTRL_ADV_1000_FULL;
-			if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
-			    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
+			if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY) &&
+			    (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
+			     tp->pci_chip_rev_id == CHIPREV_ID_5701_B0))
 				new_adv |= (MII_TG3_CTRL_AS_MASTER |
 					    MII_TG3_CTRL_ENABLE_AS_MASTER);
 			tg3_writephy(tp, MII_TG3_CTRL, new_adv);
@@ -785,11 +906,16 @@
 	tw32(MAC_STATUS,
 	     (MAC_STATUS_SYNC_CHANGED |
 	      MAC_STATUS_CFG_CHANGED));
+	tr32(MAC_STATUS);
+	udelay(40);
 
 	tp->mi_mode = MAC_MI_MODE_BASE;
 	tw32(MAC_MI_MODE, tp->mi_mode);
+	tr32(MAC_MI_MODE);
 	udelay(40);
 
+	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02);
+
 	if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
 		tg3_readphy(tp, MII_BMSR, &bmsr);
 		tg3_readphy(tp, MII_BMSR, &bmsr);
@@ -947,16 +1073,15 @@
 		tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
 
 	tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
-		if (current_link_up == 1)
-			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
-		tw32(MAC_LED_CTRL, LED_CTRL_PHY_MODE_1);
-	} else {
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
 		if ((tp->led_mode == led_mode_link10) ||
 		    (current_link_up == 1 &&
 		     tp->link_config.active_speed == SPEED_10))
 			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
+	} else {
+		if (current_link_up == 1)
+			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
+		tw32(MAC_LED_CTRL, LED_CTRL_PHY_MODE_1);
 	}
 
 	/* ??? Without this setting Netgear GA302T PHY does not
@@ -966,10 +1091,13 @@
 	    tp->pci_chip_rev_id == CHIPREV_ID_5700_ALTIMA) {
 		tp->mi_mode |= MAC_MI_MODE_AUTO_POLL;
 		tw32(MAC_MI_MODE, tp->mi_mode);
+		tr32(MAC_MI_MODE);
 		udelay(40);
 	}
 
 	tw32(MAC_MODE, tp->mac_mode);
+	tr32(MAC_MODE);
+	udelay(40);
 
 	if (tp->tg3_flags &
 	    (TG3_FLAG_USE_LINKCHG_REG |
@@ -979,6 +1107,8 @@
 	} else {
 		tw32(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
 	}
+	tr32(MAC_EVENT);
+	udelay(40);
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 &&
 	    current_link_up == 1 &&
@@ -989,6 +1119,8 @@
 		tw32(MAC_STATUS,
 		     (MAC_STATUS_SYNC_CHANGED |
 		      MAC_STATUS_CFG_CHANGED));
+		tr32(MAC_STATUS);
+		udelay(40);
 		tg3_write_mem(tp,
 			      NIC_SRAM_FIRMWARE_MBOX,
 			      NIC_SRAM_FIRMWARE_MBOX_MAGIC2);
@@ -1150,6 +1282,9 @@
 		tw32(MAC_TX_AUTO_NEG, 0);
 		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
 		tw32(MAC_MODE, tp->mac_mode);
+		tr32(MAC_MODE);
+		udelay(40);
+
 		ret = ANEG_TIMER_ENAB;
 		ap->state = ANEG_STATE_RESTART;
 
@@ -1173,6 +1308,8 @@
 		tw32(MAC_TX_AUTO_NEG, ap->txconfig);
 		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
 		tw32(MAC_MODE, tp->mac_mode);
+		tr32(MAC_MODE);
+		udelay(40);
 
 		ap->state = ANEG_STATE_ABILITY_DETECT;
 		break;
@@ -1188,6 +1325,8 @@
 		tw32(MAC_TX_AUTO_NEG, ap->txconfig);
 		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
 		tw32(MAC_MODE, tp->mac_mode);
+		tr32(MAC_MODE);
+		udelay(40);
 
 		ap->state = ANEG_STATE_ACK_DETECT;
 
@@ -1273,6 +1412,8 @@
 		ap->link_time = ap->cur_time;
 		tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
 		tw32(MAC_MODE, tp->mac_mode);
+		tr32(MAC_MODE);
+		udelay(40);
 
 		ap->state = ANEG_STATE_IDLE_DETECT;
 		ret = ANEG_TIMER_ENAB;
@@ -1329,6 +1470,7 @@
 	tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX);
 	tp->mac_mode |= MAC_MODE_PORT_MODE_TBI;
 	tw32(MAC_MODE, tp->mac_mode);
+	tr32(MAC_MODE);
 	udelay(40);
 
 	/* Reset when initting first time or we have a link. */
@@ -1379,6 +1521,8 @@
 		tw32(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
 	else
 		tw32(MAC_EVENT, 0);
+	tr32(MAC_EVENT);
+	udelay(40);
 
 	current_link_up = 0;
 	if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) {
@@ -1396,9 +1540,12 @@
 
 			tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK;
 			tw32(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII);
-			udelay(20);
+			tr32(MAC_MODE);
+			udelay(40);
 
 			tw32(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS);
+			tr32(MAC_MODE);
+			udelay(40);
 
 			aninfo.state = ANEG_STATE_UNKNOWN;
 			aninfo.cur_time = 0;
@@ -1414,6 +1561,8 @@
 
 			tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
 			tw32(MAC_MODE, tp->mac_mode);
+			tr32(MAC_MODE);
+			udelay(40);
 
 			if (status == ANEG_DONE &&
 			    (aninfo.flags &
@@ -1439,8 +1588,8 @@
 				tw32(MAC_STATUS,
 				     (MAC_STATUS_SYNC_CHANGED |
 				      MAC_STATUS_CFG_CHANGED));
-
-				udelay(20);
+				tr32(MAC_STATUS);
+				udelay(40);
 				if ((tr32(MAC_STATUS) &
 				     (MAC_STATUS_SYNC_CHANGED |
 				      MAC_STATUS_CFG_CHANGED)) == 0)
@@ -1458,6 +1607,8 @@
 
 	tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
 	tw32(MAC_MODE, tp->mac_mode);
+	tr32(MAC_MODE);
+	udelay(40);
 
 	tp->hw_status->status =
 		(SD_STATUS_UPDATED |
@@ -1468,8 +1619,8 @@
 		tw32(MAC_STATUS,
 		     (MAC_STATUS_SYNC_CHANGED |
 		      MAC_STATUS_CFG_CHANGED));
-
-		udelay(20);
+		tr32(MAC_STATUS);
+		udelay(40);
 		if ((tr32(MAC_STATUS) &
 		     (MAC_STATUS_SYNC_CHANGED |
 		      MAC_STATUS_CFG_CHANGED)) == 0)
@@ -1505,9 +1656,12 @@
 
 	if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) {
 		tw32(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY);
+		tr32(MAC_MODE);
+		udelay(40);
 		if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) {
-			udelay(1);
 			tw32(MAC_MODE, tp->mac_mode);
+			tr32(MAC_MODE);
+			udelay(40);
 		}
 	}
 
@@ -1549,7 +1703,7 @@
 	u32 sw_idx = tp->tx_cons;
 
 	while (sw_idx != hw_idx) {
-		struct ring_info *ri = &tp->tx_buffers[sw_idx];
+		struct tx_ring_info *ri = &tp->tx_buffers[sw_idx];
 		struct sk_buff *skb = ri->skb;
 		int i;
 
@@ -1725,7 +1879,7 @@
 #if TG3_VLAN_TAG_USED
 static int tg3_vlan_rx(struct tg3 *tp, struct sk_buff *skb, u16 vlan_tag)
 {
-	return vlan_hwaccel_rx(skb, tp->vlgrp, vlan_tag);
+	return vlan_hwaccel_receive_skb(skb, tp->vlgrp, vlan_tag);
 }
 #endif
 
@@ -1753,16 +1907,18 @@
  * If both the host and chip were to write into the same ring, cache line
  * eviction could occur since both entities want it in an exclusive state.
  */
-static void tg3_rx(struct tg3 *tp)
+static int tg3_rx(struct tg3 *tp, int budget)
 {
 	u32 work_mask;
 	u32 rx_rcb_ptr = tp->rx_rcb_ptr;
 	u16 hw_idx, sw_idx;
+	int received;
 
 	hw_idx = tp->hw_status->idx[0].rx_producer;
 	sw_idx = rx_rcb_ptr % TG3_RX_RCB_RING_SIZE;
 	work_mask = 0;
-	while (sw_idx != hw_idx) {
+	received = 0;
+	while (sw_idx != hw_idx && budget > 0) {
 		struct tg3_rx_buffer_desc *desc = &tp->rx_rcb[sw_idx];
 		unsigned int len;
 		struct sk_buff *skb;
@@ -1860,9 +2016,11 @@
 				    desc->err_vlan & RXD_VLAN_MASK);
 		} else
 #endif
-			netif_rx(skb);
+			netif_receive_skb(skb);
 
 		tp->dev->last_rx = jiffies;
+		received++;
+		budget--;
 
 next_pkt:
 		(*post_ptr)++;
@@ -1875,129 +2033,44 @@
 	tp->rx_rcb_ptr = rx_rcb_ptr;
 	tw32_mailbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW,
 		     (rx_rcb_ptr % TG3_RX_RCB_RING_SIZE));
+	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+		tr32(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW);
 
 	/* Refill RX ring(s). */
 	if (work_mask & RXD_OPAQUE_RING_STD) {
 		sw_idx = tp->rx_std_ptr % TG3_RX_RING_SIZE;
 		tw32_mailbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW,
 			     sw_idx);
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW);
 	}
 	if (work_mask & RXD_OPAQUE_RING_JUMBO) {
 		sw_idx = tp->rx_jumbo_ptr % TG3_RX_JUMBO_RING_SIZE;
 		tw32_mailbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW,
 			     sw_idx);
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW);
 	}
 #if TG3_MINI_RING_WORKS
 	if (work_mask & RXD_OPAQUE_RING_MINI) {
 		sw_idx = tp->rx_mini_ptr % TG3_RX_MINI_RING_SIZE;
 		tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW,
 			     sw_idx);
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW);
 	}
 #endif
-}
-
-#define PKT_RATE_LOW		22000
-#define PKT_RATE_HIGH		61000
-
-static void tg3_rate_sample(struct tg3 *tp, unsigned long ticks)
-{
-	u32 delta, rx_now, tx_now;
-	int new_vals, do_tx, do_rx;
 
-	rx_now = tp->hw_stats->rx_ucast_packets.low;
-	tx_now = tp->hw_stats->COS_out_packets[0].low;
-
-	delta  = (rx_now - tp->last_rx_count);
-	delta += (tx_now - tp->last_tx_count);
-	delta /= (ticks / tp->coalesce_config.rate_sample_jiffies);
-
-	tp->last_rx_count = rx_now;
-	tp->last_tx_count = tx_now;
-
-	new_vals = 0;
-	do_tx = (tp->tg3_flags & TG3_FLAG_ADAPTIVE_TX) != 0;
-	do_rx = (tp->tg3_flags & TG3_FLAG_ADAPTIVE_RX) != 0;
-	if (delta < tp->coalesce_config.pkt_rate_low) {
-		if (do_rx &&
-		    tp->coalesce_config.rx_max_coalesced_frames !=
-		    tp->coalesce_config.rx_max_coalesced_frames_low) {
-			tp->coalesce_config.rx_max_coalesced_frames =
-				LOW_RXMAX_FRAMES;
-			tp->coalesce_config.rx_coalesce_ticks =
-				LOW_RXCOL_TICKS;
-			new_vals = 1;
-		}
-		if (do_tx &&
-		    tp->coalesce_config.tx_max_coalesced_frames !=
-		    tp->coalesce_config.tx_max_coalesced_frames_low) {
-			tp->coalesce_config.tx_max_coalesced_frames =
-				tp->coalesce_config.tx_max_coalesced_frames_low;
-			tp->coalesce_config.tx_coalesce_ticks =
-				tp->coalesce_config.tx_coalesce_ticks_low;
-			new_vals = 1;
-		}
-	} else if (delta < tp->coalesce_config.pkt_rate_high) {
-		if (do_rx &&
-		    tp->coalesce_config.rx_max_coalesced_frames !=
-		    tp->coalesce_config.rx_max_coalesced_frames_def) {
-			tp->coalesce_config.rx_max_coalesced_frames =
-				tp->coalesce_config.rx_max_coalesced_frames_def;
-			tp->coalesce_config.rx_coalesce_ticks =
-				tp->coalesce_config.rx_coalesce_ticks_def;
-			new_vals = 1;
-		}
-		if (do_tx &&
-		    tp->coalesce_config.tx_max_coalesced_frames !=
-		    tp->coalesce_config.tx_max_coalesced_frames_def) {
-			tp->coalesce_config.tx_max_coalesced_frames =
-				tp->coalesce_config.tx_max_coalesced_frames_def;
-			tp->coalesce_config.tx_coalesce_ticks =
-				tp->coalesce_config.tx_coalesce_ticks_def;
-			new_vals = 1;
-		}
-	} else {
-		if (do_rx &&
-		    tp->coalesce_config.rx_max_coalesced_frames !=
-		    tp->coalesce_config.rx_max_coalesced_frames_high) {
-			tp->coalesce_config.rx_max_coalesced_frames =
-				tp->coalesce_config.rx_max_coalesced_frames_high;
-			tp->coalesce_config.rx_coalesce_ticks =
-				tp->coalesce_config.rx_coalesce_ticks_high;
-			new_vals = 1;
-		}
-		if (do_tx &&
-		    tp->coalesce_config.tx_max_coalesced_frames !=
-		    tp->coalesce_config.tx_max_coalesced_frames_high) {
-			tp->coalesce_config.tx_max_coalesced_frames =
-				tp->coalesce_config.tx_max_coalesced_frames_high;
-			tp->coalesce_config.tx_coalesce_ticks =
-				tp->coalesce_config.tx_coalesce_ticks_high;
-			new_vals = 1;
-		}
-	}
-
-	if (new_vals) {
-		if (do_rx) {
-			tw32(HOSTCC_RXCOL_TICKS,
-			     tp->coalesce_config.rx_coalesce_ticks);
-			tw32(HOSTCC_RXMAX_FRAMES,
-			     tp->coalesce_config.rx_max_coalesced_frames);
-		}
-		if (do_tx) {
-			tw32(HOSTCC_TXCOL_TICKS,
-			     tp->coalesce_config.tx_coalesce_ticks);
-			tw32(HOSTCC_TXMAX_FRAMES,
-			     tp->coalesce_config.tx_max_coalesced_frames);
-		}
-	}
-
-	tp->last_rate_sample = jiffies;
+	return received;
 }
 
-static void tg3_interrupt_main_work(struct tg3 *tp)
+static int tg3_poll(struct net_device *netdev, int *budget)
 {
+	struct tg3 *tp = netdev->priv;
 	struct tg3_hw_status *sblk = tp->hw_status;
-	int did_pkts;
+	int done;
+
+	spin_lock_irq(&tp->lock);
 
 	if (!(tp->tg3_flags &
 	      (TG3_FLAG_USE_LINKCHG_REG |
@@ -2009,84 +2082,91 @@
 		}
 	}
 
-	did_pkts = 0;
-	if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) {
-		tg3_rx(tp);
-		did_pkts = 1;
-	}
-
 	if (sblk->idx[0].tx_consumer != tp->tx_cons) {
+		spin_lock(&tp->tx_lock);
 		tg3_tx(tp);
-		did_pkts = 1;
+		spin_unlock(&tp->tx_lock);
 	}
 
-	if (did_pkts &&
-	    (tp->tg3_flags & (TG3_FLAG_ADAPTIVE_RX | TG3_FLAG_ADAPTIVE_TX))) {
-		unsigned long ticks = jiffies - tp->last_rate_sample;
+	done = 1;
+	if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) {
+		int orig_budget = *budget;
+		int work_done;
+
+		if (orig_budget > netdev->quota)
+			orig_budget = netdev->quota;
+
+		work_done = tg3_rx(tp, orig_budget);
+
+		*budget -= work_done;
+		netdev->quota -= work_done;
+
+		if (work_done >= orig_budget)
+			done = 0;
+	}
 
-		if (ticks >= tp->coalesce_config.rate_sample_jiffies)
-			tg3_rate_sample(tp, ticks);
+	if (done) {
+		netif_rx_complete(netdev);
+		tg3_unmask_ints(tp);
 	}
+
+	spin_unlock_irq(&tp->lock);
+
+	return (done ? 0 : 1);
 }
 
-static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static __inline__ void tg3_interrupt_main_work(struct net_device *dev, struct tg3 *tp)
 {
-	struct net_device *dev = dev_id;
-	struct tg3 *tp = dev->priv;
 	struct tg3_hw_status *sblk = tp->hw_status;
+	int work_exists = 0;
 
-	spin_lock(&tp->lock);
-
-	while (sblk->status & SD_STATUS_UPDATED) {
-		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
-			     0x00000001);
-		sblk->status &= ~SD_STATUS_UPDATED;
+	if (!(tp->tg3_flags &
+	      (TG3_FLAG_USE_LINKCHG_REG |
+	       TG3_FLAG_POLL_SERDES))) {
+		if (sblk->status & SD_STATUS_LINK_CHG)
+			work_exists = 1;
+	}
+	if (sblk->idx[0].tx_consumer != tp->tx_cons ||
+	    sblk->idx[0].rx_producer != tp->rx_rcb_ptr)
+		work_exists = 1;
 
-		tg3_interrupt_main_work(tp);
+	if (!work_exists)
+		return;
 
-		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
-			     0x00000000);
-		tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+	if (netif_rx_schedule_prep(dev)) {
+		/* NOTE: These writes are posted by the readback of
+		 *       the mailbox register done by our caller.
+		 */
+		tg3_mask_ints(tp);
+		__netif_rx_schedule(dev);
+	} else {
+		printk(KERN_ERR PFX "%s: Error, poll already scheduled\n",
+		       dev->name);
 	}
-
-	spin_unlock(&tp->lock);
 }
 
-static void tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *regs)
+static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
 	struct tg3 *tp = dev->priv;
 	struct tg3_hw_status *sblk = tp->hw_status;
+	unsigned long flags;
 
-	spin_lock(&tp->lock);
+	spin_lock_irqsave(&tp->lock, flags);
 
 	if (sblk->status & SD_STATUS_UPDATED) {
-		u32 oldtag;
-
 		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
 			     0x00000001);
-		oldtag = sblk->status_tag;
-
-		while (1) {
-			u32 newtag;
-
-			sblk->status &= ~SD_STATUS_UPDATED;
-			barrier();
+		sblk->status &= ~SD_STATUS_UPDATED;
 
-			tg3_interrupt_main_work(tp);
+		tg3_interrupt_main_work(dev, tp);
 
-			newtag = sblk->status_tag;
-			if (newtag == oldtag) {
-				tw32_mailbox(MAILBOX_INTERRUPT_0 +
-					     TG3_64BIT_REG_LOW,
-					     newtag << 24);
-				break;
-			}
-			oldtag = newtag;
-		}
+		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+			     0x00000000);
+		tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
 	}
 
-	spin_unlock(&tp->lock);
+	spin_unlock_irqrestore(&tp->lock, flags);
 }
 
 static void tg3_init_rings(struct tg3 *);
@@ -2096,15 +2176,17 @@
 {
 	struct tg3 *tp = dev->priv;
 
-	printk(KERN_ERR "%s: transmit timed out, resetting\n",
+	printk(KERN_ERR PFX "%s: transmit timed out, resetting\n",
 	       dev->name);
 
 	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
 
 	tg3_halt(tp);
 	tg3_init_rings(tp);
 	tg3_init_hw(tp);
 
+	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
 	netif_wake_queue(dev);
@@ -2136,11 +2218,11 @@
 }
 #endif
 
-static void tg3_set_txd(struct tg3 *, int, dma_addr_t, int, u32, int);
+static void tg3_set_txd(struct tg3 *, int, dma_addr_t, int, u32, u32);
 
 static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
 				       u32 guilty_entry, int guilty_len,
-				       u32 last_plus_one, u32 *start)
+				       u32 last_plus_one, u32 *start, u32 mss)
 {
 	dma_addr_t new_addr;
 	u32 entry = *start;
@@ -2193,7 +2275,7 @@
 				  PCI_DMA_TODEVICE);
 	tg3_set_txd(tp, entry, new_addr, new_skb->len,
 		    (skb->ip_summed == CHECKSUM_HW) ?
-		    TXD_FLAG_TCPUDP_CSUM : 0, 1);
+		    TXD_FLAG_TCPUDP_CSUM : 0, 1 | (mss << 1));
 	*start = NEXT_TX(entry);
 
 	/* Now clean up the sw ring entries. */
@@ -2225,30 +2307,28 @@
 
 static void tg3_set_txd(struct tg3 *tp, int entry,
 			dma_addr_t mapping, int len, u32 flags,
-			int is_end)
+			u32 mss_and_is_end)
 {
-#if TG3_VLAN_TAG_USED
-	u16 vlan_tag = 0;
-#endif
+	int is_end = (mss_and_is_end & 0x1);
+	u32 mss = (mss_and_is_end >> 1);
+	u32 vlan_tag = 0;
 
 	if (is_end)
 		flags |= TXD_FLAG_END;
-#if TG3_VLAN_TAG_USED
 	if (flags & TXD_FLAG_VLAN) {
 		vlan_tag = flags >> 16;
 		flags &= 0xffff;
 	}
-#endif
+	vlan_tag |= (mss << TXD_MSS_SHIFT);
 	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
 		struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry];
 
 		txd->addr_hi = ((u64) mapping >> 32);
 		txd->addr_lo = ((u64) mapping & 0xffffffff);
 		txd->len_flags = (len << TXD_LEN_SHIFT) | flags;
-#if TG3_VLAN_TAG_USED
 		txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT;
-#endif
 	} else {
+		struct tx_ring_info *txr = &tp->tx_buffers[entry];
 		unsigned long txd;
 
 		txd = (tp->regs +
@@ -2264,9 +2344,10 @@
 		writel(((u64) mapping & 0xffffffff),
 		       txd + TXD_ADDR + TG3_64BIT_REG_LOW);
 		writel(len << TXD_LEN_SHIFT | flags, txd + TXD_LEN_FLAGS);
-#if TG3_VLAN_TAG_USED
-		writel(vlan_tag << TXD_VLAN_TAG_SHIFT, txd + TXD_VLAN_TAG);
-#endif
+		if (txr->prev_vlan_tag != vlan_tag) {
+			writel(vlan_tag << TXD_VLAN_TAG_SHIFT, txd + TXD_VLAN_TAG);
+			txr->prev_vlan_tag = vlan_tag;
+		}
 	}
 }
 
@@ -2284,17 +2365,21 @@
 	struct tg3 *tp = dev->priv;
 	dma_addr_t mapping;
 	unsigned int i;
-	u32 len, entry, base_flags;
+	u32 len, entry, base_flags, mss;
 	int would_hit_hwbug;
 
 	len = (skb->len - skb->data_len);
 
-	spin_lock_irq(&tp->lock);
+	/* No BH disabling for tx_lock here.  We are running in BH disabled
+	 * context and TX reclaim runs via tp->poll inside of a software
+	 * interrupt.  Rejoice!
+	 */
+	spin_lock(&tp->tx_lock);
 
 	/* This is a hard error, log it. */
 	if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
 		netif_stop_queue(dev);
-		spin_unlock_irq(&tp->lock);
+		spin_unlock(&tp->tx_lock);
 		printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
 		       dev->name);
 		return 1;
@@ -2304,6 +2389,13 @@
 	base_flags = 0;
 	if (skb->ip_summed == CHECKSUM_HW)
 		base_flags |= TXD_FLAG_TCPUDP_CSUM;
+#if TG3_DO_TSO != 0
+	if ((mss = skb_shinfo(skb)->tso_size) != 0)
+		base_flags |= (TXD_FLAG_CPU_PRE_DMA |
+			       TXD_FLAG_CPU_POST_DMA);
+#else
+	mss = 0;
+#endif
 #if TG3_VLAN_TAG_USED
 	if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
 		base_flags |= (TXD_FLAG_VLAN |
@@ -2322,7 +2414,7 @@
 		would_hit_hwbug = entry + 1;
 
 	tg3_set_txd(tp, entry, mapping, len, base_flags,
-		    (skb_shinfo(skb)->nr_frags == 0));
+		    (skb_shinfo(skb)->nr_frags == 0) | (mss << 1));
 
 	entry = NEXT_TX(entry);
 
@@ -2351,7 +2443,7 @@
 			}
 
 			tg3_set_txd(tp, entry, mapping, len,
-				    base_flags, (i == last));
+				    base_flags, (i == last) | (mss << 1));
 
 			entry = NEXT_TX(entry);
 		}
@@ -2387,7 +2479,7 @@
 		if (tigon3_4gb_hwbug_workaround(tp, skb,
 						entry, len,
 						last_plus_one,
-						&start))
+						&start, mss))
 			goto out_unlock;
 
 		entry = start;
@@ -2400,12 +2492,27 @@
 		if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG)
 			tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 +
 				      TG3_64BIT_REG_LOW), entry);
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_SNDHOST_PROD_IDX_0 +
+			     TG3_64BIT_REG_LOW);
 	} else {
+		/* First, make sure tg3 sees last descriptor fully
+		 * in SRAM.
+		 */
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_SNDNIC_PROD_IDX_0 +
+			     TG3_64BIT_REG_LOW);
+
 		tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 +
 			      TG3_64BIT_REG_LOW), entry);
 		if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG)
 			tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 +
 				      TG3_64BIT_REG_LOW), entry);
+
+		/* Now post the mailbox write itself.  */
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_SNDNIC_PROD_IDX_0 +
+			     TG3_64BIT_REG_LOW);
 	}
 
 	tp->tx_prod = entry;
@@ -2413,7 +2520,7 @@
 		netif_stop_queue(dev);
 
 out_unlock:
-	spin_unlock_irq(&tp->lock);
+	spin_unlock(&tp->tx_lock);
 
 	dev->trans_start = jiffies;
 
@@ -2424,16 +2531,20 @@
 {
 	struct tg3 *tp = dev->priv;
 	dma_addr_t mapping;
-	u32 len, entry, base_flags;
+	u32 len, entry, base_flags, mss;
 
 	len = (skb->len - skb->data_len);
 
-	spin_lock_irq(&tp->lock);
+	/* No BH disabling for tx_lock here.  We are running in BH disabled
+	 * context and TX reclaim runs via tp->poll inside of a software
+	 * interrupt.  Rejoice!
+	 */
+	spin_lock(&tp->tx_lock);
 
 	/* This is a hard error, log it. */
 	if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
 		netif_stop_queue(dev);
-		spin_unlock_irq(&tp->lock);
+		spin_unlock(&tp->tx_lock);
 		printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
 		       dev->name);
 		return 1;
@@ -2443,6 +2554,13 @@
 	base_flags = 0;
 	if (skb->ip_summed == CHECKSUM_HW)
 		base_flags |= TXD_FLAG_TCPUDP_CSUM;
+#if TG3_DO_TSO != 0
+	if ((mss = skb_shinfo(skb)->tso_size) != 0)
+		base_flags |= (TXD_FLAG_CPU_PRE_DMA |
+			       TXD_FLAG_CPU_POST_DMA);
+#else
+	mss = 0;
+#endif
 #if TG3_VLAN_TAG_USED
 	if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
 		base_flags |= (TXD_FLAG_VLAN |
@@ -2456,7 +2574,7 @@
 	pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 	tg3_set_txd(tp, entry, mapping, len, base_flags,
-		    (skb_shinfo(skb)->nr_frags == 0));
+		    (skb_shinfo(skb)->nr_frags == 0) | (mss << 1));
 
 	entry = NEXT_TX(entry);
 
@@ -2479,7 +2597,7 @@
 			pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 			tg3_set_txd(tp, entry, mapping, len,
-				    base_flags, (i == last));
+				    base_flags, (i == last) | (mss << 1));
 
 			entry = NEXT_TX(entry);
 		}
@@ -2493,16 +2611,31 @@
 	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
 		tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 +
 			      TG3_64BIT_REG_LOW), entry);
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_SNDHOST_PROD_IDX_0 +
+			     TG3_64BIT_REG_LOW);
 	} else {
+		/* First, make sure tg3 sees last descriptor fully
+		 * in SRAM.
+		 */
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_SNDNIC_PROD_IDX_0 +
+			     TG3_64BIT_REG_LOW);
+
 		tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 +
 			      TG3_64BIT_REG_LOW), entry);
+
+		/* Now post the mailbox write itself.  */
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_SNDNIC_PROD_IDX_0 +
+			     TG3_64BIT_REG_LOW);
 	}
 
 	tp->tx_prod = entry;
 	if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1))
 		netif_stop_queue(dev);
 
-	spin_unlock_irq(&tp->lock);
+	spin_unlock(&tp->tx_lock);
 
 	dev->trans_start = jiffies;
 
@@ -2525,6 +2658,7 @@
 	}
 
 	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
 
 	tg3_halt(tp);
 
@@ -2538,6 +2672,7 @@
 	tg3_init_rings(tp);
 	tg3_init_hw(tp);
 
+	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
 	return 0;
@@ -2547,7 +2682,7 @@
  *
  * The chip has been shut down and the driver detached from
  * the networking, so no interrupts or new tx packets will
- * end up in the driver.  tp->lock is not held and we are not
+ * end up in the driver.  tp->{tx,}lock is not held and we are not
  * in an interrupt context and thus may sleep.
  */
 static void tg3_free_rings(struct tg3 *tp)
@@ -2595,7 +2730,7 @@
 	}
 
 	for (i = 0; i < TG3_TX_RING_SIZE; ) {
-		struct ring_info *txp;
+		struct tx_ring_info *txp;
 		struct sk_buff *skb;
 		int j;
 
@@ -2632,7 +2767,7 @@
  *
  * The chip has been shut down and the driver detached from
  * the networking, so no interrupts or new tx packets will
- * end up in the driver.  tp->lock is not held and we are not
+ * end up in the driver.  tp->{tx,}lock is not held and we are not
  * in an interrupt context and thus may sleep.
  */
 static void tg3_init_rings(struct tg3 *tp)
@@ -2662,6 +2797,8 @@
 			writel(0, start);
 			start += 4;
 		}
+		for (i = 0; i < TG3_TX_RING_SIZE; i++)
+			tp->tx_buffers[i].prev_vlan_tag = 0;
 	}
 
 	/* Initialize invariants of the rings, we only set this
@@ -2784,12 +2921,13 @@
  */
 static int tg3_alloc_consistent(struct tg3 *tp)
 {
-	tp->rx_std_buffers = kmalloc(sizeof(struct ring_info) *
-				     (TG3_RX_RING_SIZE +
+	tp->rx_std_buffers = kmalloc((sizeof(struct ring_info) *
+				      (TG3_RX_RING_SIZE +
 #if TG3_MINI_RING_WORKS
-				      TG3_RX_MINI_RING_SIZE +
+				       TG3_RX_MINI_RING_SIZE +
 #endif
-				      TG3_RX_JUMBO_RING_SIZE +
+				       TG3_RX_JUMBO_RING_SIZE)) +
+				     (sizeof(struct tx_ring_info) *
 				      TG3_TX_RING_SIZE),
 				     GFP_KERNEL);
 	if (!tp->rx_std_buffers)
@@ -2800,14 +2938,16 @@
 	       (sizeof(struct ring_info) *
 		(TG3_RX_RING_SIZE +
 		 TG3_RX_MINI_RING_SIZE +
-		 TG3_RX_JUMBO_RING_SIZE +
-		 TG3_TX_RING_SIZE)));
+		 TG3_RX_JUMBO_RING_SIZE)) +
+	       (sizeof(struct tx_ring_info) *
+		TG3_TX_RING_SIZE));
 #else
 	memset(tp->rx_std_buffers, 0,
 	       (sizeof(struct ring_info) *
 		(TG3_RX_RING_SIZE +
-		 TG3_RX_JUMBO_RING_SIZE +
-		 TG3_TX_RING_SIZE)));
+		 TG3_RX_JUMBO_RING_SIZE)) +
+	       (sizeof(struct tx_ring_info) *
+		TG3_TX_RING_SIZE));
 #endif
 
 #if TG3_MINI_RING_WORKS
@@ -2816,7 +2956,8 @@
 #else
 	tp->rx_jumbo_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE];
 #endif
-	tp->tx_buffers = &tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE];
+	tp->tx_buffers = (struct tx_ring_info *)
+		&tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE];
 
 	tp->rx_std = pci_alloc_consistent(tp->pdev, TG3_RX_RING_BYTES,
 					  &tp->rx_std_mapping);
@@ -2874,7 +3015,7 @@
 	return -ENOMEM;
 }
 
-#define MAX_WAIT_CNT 10000
+#define MAX_WAIT_CNT 1000
 
 /* To stop a block, clear the enable bit and poll till it
  * clears.  tp->lock is held.
@@ -2887,13 +3028,13 @@
 	val = tr32(ofs);
 	val &= ~enable_bit;
 	tw32(ofs, val);
+	tr32(ofs);
 
 	for (i = 0; i < MAX_WAIT_CNT; i++) {
+		udelay(100);
 		val = tr32(ofs);
-
 		if ((val & enable_bit) == 0)
 			break;
-		udelay(100);
 	}
 
 	if (i == MAX_WAIT_CNT) {
@@ -2915,6 +3056,8 @@
 
 	tp->rx_mode &= ~RX_MODE_ENABLE;
 	tw32(MAC_RX_MODE, tp->rx_mode);
+	tr32(MAC_RX_MODE);
+	udelay(10);
 
 	err  = tg3_stop_block(tp, RCVBDI_MODE, RCVBDI_MODE_ENABLE);
 	err |= tg3_stop_block(tp, RCVLPC_MODE, RCVLPC_MODE_ENABLE);
@@ -2934,9 +3077,13 @@
 
 	tp->mac_mode &= ~MAC_MODE_TDE_ENABLE;
 	tw32(MAC_MODE, tp->mac_mode);
+	tr32(MAC_MODE);
+	udelay(40);
 
 	tp->tx_mode &= ~TX_MODE_ENABLE;
 	tw32(MAC_TX_MODE, tp->tx_mode);
+	tr32(MAC_TX_MODE);
+
 	for (i = 0; i < MAX_WAIT_CNT; i++) {
 		udelay(100);
 		if (!(tr32(MAC_TX_MODE) & TX_MODE_ENABLE))
@@ -2988,6 +3135,14 @@
 	}
 
 	tw32(GRC_MISC_CFG, GRC_MISC_CFG_CORECLK_RESET);
+
+	/* Flush PCI posted writes.  The normal MMIO registers
+	 * are inaccessible at this time so this is the only
+	 * way to make this reliably.  I tried to use indirect
+	 * register read/write but this upset some 5701 variants.
+	 */
+	pci_read_config_dword(tp->pdev, PCI_COMMAND, &val);
+
 	udelay(40);
 	udelay(40);
 	udelay(40);
@@ -2997,9 +3152,11 @@
 			       tp->misc_host_ctrl);
 
 	/* Set MAX PCI retry to zero. */
-	pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE,
-			       (PCISTATE_ROM_ENABLE |
-				PCISTATE_ROM_RETRY_ENABLE));
+	val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
+	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
+		val |= PCISTATE_RETRY_SAME_DMA;
+	pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
 
 	pci_restore_state(tp->pdev, tp->pci_cfg_state);
 
@@ -3014,11 +3171,33 @@
 }
 
 /* tp->lock is held. */
+static void tg3_stop_fw(struct tg3 *tp)
+{
+	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+		u32 val;
+		int i;
+
+		tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_PAUSE_FW);
+		val = tr32(GRC_RX_CPU_EVENT);
+		val |= (1 << 14);
+		tw32(GRC_RX_CPU_EVENT, val);
+
+		/* Wait for RX cpu to ACK the event.  */
+		for (i = 0; i < 100; i++) {
+			if (!(tr32(GRC_RX_CPU_EVENT) & (1 << 14)))
+				break;
+			udelay(1);
+		}
+	}
+}
+
+/* tp->lock is held. */
 static int tg3_halt(struct tg3 *tp)
 {
 	u32 val;
 	int i;
 
+	tg3_stop_fw(tp);
 	tg3_abort_hw(tp);
 	tg3_chip_reset(tp);
 	tg3_write_mem(tp,
@@ -3038,6 +3217,17 @@
 		return -ENODEV;
 	}
 
+	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+		if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)
+			tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+				      DRV_STATE_WOL);
+		else
+			tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+				      DRV_STATE_UNLOAD);
+	} else
+		tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+			      DRV_STATE_SUSPEND);
+
 	return 0;
 }
 
@@ -3056,7 +3246,7 @@
 #define TG3_FW_BSS_ADDR		0x08000a70
 #define TG3_FW_BSS_LEN		0x10
 
-static u32 t3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = {
+static u32 tg3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = {
 	0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c1d0800,
 	0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100000, 0x0e000018, 0x00000000,
 	0x0000000d, 0x3c1d0800, 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100034,
@@ -3150,7 +3340,7 @@
 	0x27bd0008, 0x03e00008, 0x00000000, 0x00000000, 0x00000000
 };
 
-static u32 t3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = {
+static u32 tg3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = {
 	0x35373031, 0x726c7341, 0x00000000, 0x00000000, 0x53774576, 0x656e7430,
 	0x00000000, 0x726c7045, 0x76656e74, 0x31000000, 0x556e6b6e, 0x45766e74,
 	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x66617461, 0x6c457272,
@@ -3159,7 +3349,7 @@
 };
 
 #if 0 /* All zeros, dont eat up space with it. */
-u32 t3FwData[(TG3_FW_DATA_LEN / sizeof(u32)) + 1] = {
+u32 tg3FwData[(TG3_FW_DATA_LEN / sizeof(u32)) + 1] = {
 	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
 	0x00000000, 0x00000000, 0x00000000, 0x00000000
 };
@@ -3183,6 +3373,7 @@
 				break;
 		tw32(offset + CPU_STATE, 0xffffffff);
 		tw32(offset + CPU_MODE,  CPU_MODE_RESET);
+		tr32(offset + CPU_MODE);
 		udelay(10);
 	} else {
 		for (i = 0; i < 10000; i++) {
@@ -3190,6 +3381,7 @@
 				break;
 			tw32(offset + CPU_STATE, 0xffffffff);
 			tw32(offset + CPU_MODE,  CPU_MODE_RESET);
+			tr32(offset + CPU_MODE);
 			udelay(10);
 		}
 	}
@@ -3204,51 +3396,89 @@
 	return 0;
 }
 
+struct fw_info {
+	unsigned int text_base;
+	unsigned int text_len;
+	u32 *text_data;
+	unsigned int rodata_base;
+	unsigned int rodata_len;
+	u32 *rodata_data;
+	unsigned int data_base;
+	unsigned int data_len;
+	u32 *data_data;
+};
+
 /* tp->lock is held. */
 static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_base,
-				 int cpu_scratch_size)
+				 int cpu_scratch_size, struct fw_info *info)
 {
 	int err, i;
+	u32 orig_tg3_flags = tp->tg3_flags;
+
+	/* Force use of PCI config space for indirect register
+	 * write calls.
+	 */
+	tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
 
 	err = tg3_reset_cpu(tp, cpu_base);
 	if (err)
-		return err;
+		goto out;
 
 	for (i = 0; i < cpu_scratch_size; i += sizeof(u32))
 		tg3_write_indirect_reg32(tp, cpu_scratch_base + i, 0);
 	tw32(cpu_base + CPU_STATE, 0xffffffff);
 	tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT);
-	for (i = 0; i < (TG3_FW_TEXT_LEN / sizeof(u32)); i++)
+	for (i = 0; i < (info->text_len / sizeof(u32)); i++)
 		tg3_write_indirect_reg32(tp, (cpu_scratch_base +
-					      (TG3_FW_TEXT_ADDR & 0xffff) +
+					      (info->text_base & 0xffff) +
 					      (i * sizeof(u32))),
-					 t3FwText[i]);
-	for (i = 0; i < (TG3_FW_RODATA_LEN / sizeof(u32)); i++)
+					 (info->text_data ?
+					  info->text_data[i] : 0));
+	for (i = 0; i < (info->rodata_len / sizeof(u32)); i++)
 		tg3_write_indirect_reg32(tp, (cpu_scratch_base +
-					      (TG3_FW_RODATA_ADDR & 0xffff) +
+					      (info->rodata_base & 0xffff) +
 					      (i * sizeof(u32))),
-					 t3FwRodata[i]);
-	for (i = 0; i < (TG3_FW_DATA_LEN / sizeof(u32)); i++)
+					 (info->rodata_data ?
+					  info->rodata_data[i] : 0));
+	for (i = 0; i < (info->data_len / sizeof(u32)); i++)
 		tg3_write_indirect_reg32(tp, (cpu_scratch_base +
-					      (TG3_FW_DATA_ADDR & 0xffff) +
+					      (info->data_base & 0xffff) +
 					      (i * sizeof(u32))),
-					 0);
+					 (info->data_data ?
+					  info->data_data[i] : 0));
 
-	return 0;
+	err = 0;
+
+out:
+	tp->tg3_flags = orig_tg3_flags;
+	return err;
 }
 
 /* tp->lock is held. */
 static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
 {
+	struct fw_info info;
 	int err, i;
 
+	info.text_base = TG3_FW_TEXT_ADDR;
+	info.text_len = TG3_FW_TEXT_LEN;
+	info.text_data = &tg3FwText[0];
+	info.rodata_base = TG3_FW_RODATA_ADDR;
+	info.rodata_len = TG3_FW_RODATA_LEN;
+	info.rodata_data = &tg3FwRodata[0];
+	info.data_base = TG3_FW_DATA_ADDR;
+	info.data_len = TG3_FW_DATA_LEN;
+	info.data_data = NULL;
+
 	err = tg3_load_firmware_cpu(tp, RX_CPU_BASE,
-				    RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE);
+				    RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE,
+				    &info);
 	if (err)
 		return err;
 
 	err = tg3_load_firmware_cpu(tp, TX_CPU_BASE,
-				    TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE);
+				    TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE,
+				    &info);
 	if (err)
 		return err;
 
@@ -3286,6 +3516,336 @@
 	return 0;
 }
 
+#if TG3_DO_TSO != 0
+
+#define TG3_TSO_FW_RELEASE_MAJOR	0x1
+#define TG3_TSO_FW_RELASE_MINOR		0x8
+#define TG3_TSO_FW_RELEASE_FIX		0x0
+#define TG3_TSO_FW_START_ADDR		0x08000000
+#define TG3_TSO_FW_TEXT_ADDR		0x08000000
+#define TG3_TSO_FW_TEXT_LEN		0x1650
+#define TG3_TSO_FW_RODATA_ADDR		0x08001650
+#define TG3_TSO_FW_RODATA_LEN		0x30
+#define TG3_TSO_FW_DATA_ADDR		0x080016a0
+#define TG3_TSO_FW_DATA_LEN		0x20
+#define TG3_TSO_FW_SBSS_ADDR		0x080016c0
+#define TG3_TSO_FW_SBSS_LEN		0x14
+#define TG3_TSO_FW_BSS_ADDR		0x080016e0
+#define TG3_TSO_FW_BSS_LEN		0x8fc
+
+static u32 tg3TsoFwText[] = {
+	0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c1d0800,
+	0x37bd4000, 0x03a0f021, 0x3c100800, 0x26100000, 0x0e000010, 0x00000000,
+	0x0000000d, 0x00000000, 0x00000000, 0x00000000, 0x27bdffe0, 0x3c1bc000,
+	0xafbf0018, 0x0e000058, 0xaf60680c, 0x3c040800, 0x24841650, 0x03602821,
+	0x24060001, 0x24070004, 0xafa00010, 0x0e00006c, 0xafa00014, 0x8f625c50,
+	0x34420001, 0xaf625c50, 0x8f625c90, 0x34420001, 0xaf625c90, 0x2402ffff,
+	0x0e000098, 0xaf625404, 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x00000000,
+	0x00000000, 0x00000000, 0x24030b60, 0x24050fff, 0xac000b50, 0x00002021,
+	0xac640000, 0x24630004, 0x0065102b, 0x1440fffc, 0x24840001, 0x24030b60,
+	0x0065102b, 0x10400011, 0x00002021, 0x24090b54, 0x3c06dead, 0x34c6beef,
+	0x24080b58, 0x24070b5c, 0x8c620000, 0x50440006, 0x24630004, 0xad260000,
+	0x8c620000, 0xace40000, 0xad020000, 0x24630004, 0x0065102b, 0x1440fff6,
+	0x24840001, 0x03e00008, 0x00000000, 0x27bdfff8, 0x18800009, 0x00002821,
+	0x8f63680c, 0x8f62680c, 0x1043fffe, 0x00000000, 0x24a50001, 0x00a4102a,
+	0x1440fff9, 0x00000000, 0x03e00008, 0x27bd0008, 0x3c020800, 0x34423000,
+	0x3c030800, 0x34633000, 0x3c040800, 0x348437ff, 0x3c010800, 0xac2216c4,
+	0x24020040, 0x3c010800, 0xac2216c8, 0x3c010800, 0xac2016c0, 0xac600000,
+	0x24630004, 0x0083102b, 0x5040fffd, 0xac600000, 0x03e00008, 0x00000000,
+	0x00804821, 0x8faa0010, 0x3c020800, 0x8c4216c0, 0x3c040800, 0x8c8416c8,
+	0x8fab0014, 0x24430001, 0x0044102b, 0x3c010800, 0xac2316c0, 0x14400003,
+	0x00004021, 0x3c010800, 0xac2016c0, 0x3c020800, 0x8c4216c0, 0x3c030800,
+	0x8c6316c4, 0x91240000, 0x00021140, 0x00431021, 0x00481021, 0x25080001,
+	0xa0440000, 0x29020008, 0x1440fff4, 0x25290001, 0x3c020800, 0x8c4216c0,
+	0x3c030800, 0x8c6316c4, 0x8f64680c, 0x00021140, 0x00431021, 0xac440008,
+	0xac45000c, 0xac460010, 0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c,
+	0x00000000, 0x00000000, 0x27bdffe0, 0xafbf0018, 0xafb10014, 0x0e0000b6,
+	0xafb00010, 0x24110001, 0x8f706820, 0x32020100, 0x10400003, 0x00000000,
+	0x0e000127, 0x00000000, 0x8f706820, 0x32022000, 0x10400004, 0x32020001,
+	0x0e00025a, 0x24040001, 0x32020001, 0x10400003, 0x00000000, 0x0e0000e6,
+	0x00000000, 0x0a00009e, 0xaf715028, 0x8fbf0018, 0x8fb10014, 0x8fb00010,
+	0x03e00008, 0x27bd0020, 0x27bdffe0, 0x3c040800, 0x24841660, 0x00002821,
+	0x00003021, 0x00003821, 0xafbf0018, 0xafa00010, 0x0e00006c, 0xafa00014,
+	0x3c010800, 0xa4201fb8, 0x3c010800, 0xa02016f8, 0x3c010800, 0xac2016fc,
+	0x3c010800, 0xac201700, 0x3c010800, 0xac201704, 0x3c010800, 0xac20170c,
+	0x3c010800, 0xac201718, 0x3c010800, 0xac20171c, 0x8f624434, 0x3c010800,
+	0xac2216e8, 0x8f624438, 0x3c010800, 0xac2216ec, 0x8f624410, 0x3c010800,
+	0xac2016e0, 0x3c010800, 0xac2016e4, 0x3c010800, 0xac201fc0, 0x3c010800,
+	0xac201f68, 0x3c010800, 0xac201f6c, 0x3c010800, 0xac2216f0, 0x8fbf0018,
+	0x03e00008, 0x27bd0020, 0x27bdffe0, 0x3c040800, 0x2484166c, 0x00002821,
+	0x00003021, 0x00003821, 0xafbf0018, 0xafa00010, 0x0e00006c, 0xafa00014,
+	0x3c040800, 0x24841660, 0x00002821, 0x00003021, 0x00003821, 0xafa00010,
+	0x0e00006c, 0xafa00014, 0x3c010800, 0xa4201fb8, 0x3c010800, 0xa02016f8,
+	0x3c010800, 0xac2016fc, 0x3c010800, 0xac201700, 0x3c010800, 0xac201704,
+	0x3c010800, 0xac20170c, 0x3c010800, 0xac201718, 0x3c010800, 0xac20171c,
+	0x8f624434, 0x3c010800, 0xac2216e8, 0x8f624438, 0x3c010800, 0xac2216ec,
+	0x8f624410, 0x3c010800, 0xac2016e0, 0x3c010800, 0xac2016e4, 0x3c010800,
+	0xac201fc0, 0x3c010800, 0xac201f68, 0x3c010800, 0xac201f6c, 0x3c010800,
+	0xac2216f0, 0x0e000120, 0x00002021, 0x8fbf0018, 0x03e00008, 0x27bd0020,
+	0x24020001, 0x8f636820, 0x00821004, 0x00021027, 0x00621824, 0x03e00008,
+	0xaf636820, 0x27bdffd0, 0x3c0300ff, 0xafbf002c, 0xafb60028, 0xafb50024,
+	0xafb40020, 0xafb3001c, 0xafb20018, 0xafb10014, 0xafb00010, 0x8f665c5c,
+	0x3c040800, 0x2484171c, 0x8c820000, 0x3463fff8, 0x14460005, 0x00c38824,
+	0x3c020800, 0x904216f8, 0x14400115, 0x00000000, 0x00111902, 0x306300ff,
+	0x30c20003, 0x000211c0, 0x00623825, 0x00e02821, 0x00061602, 0xac860000,
+	0x3c030800, 0x906316f8, 0x3044000f, 0x1460002b, 0x00804021, 0x24020001,
+	0x3c010800, 0xa02216f8, 0x00071100, 0x00821025, 0x3c010800, 0xac2016fc,
+	0x3c010800, 0xac201700, 0x3c010800, 0xac201704, 0x3c010800, 0xac20170c,
+	0x3c010800, 0xac201718, 0x3c010800, 0xac201710, 0x3c010800, 0xac201714,
+	0x3c010800, 0xa4221fb8, 0x9623000c, 0x30628000, 0x10400008, 0x30627fff,
+	0x2442003e, 0x3c010800, 0xa42216f6, 0x24020001, 0x3c010800, 0x0a00016e,
+	0xac221fd4, 0x24620036, 0x3c010800, 0xa42216f6, 0x3c010800, 0xac201fd4,
+	0x3c010800, 0xac201fd0, 0x3c010800, 0x0a000176, 0xac201fd8, 0x9622000c,
+	0x3c010800, 0xa4221fcc, 0x3c040800, 0x248416fc, 0x8c820000, 0x00021100,
+	0x3c010800, 0x00220821, 0xac311728, 0x8c820000, 0x00021100, 0x3c010800,
+	0x00220821, 0xac26172c, 0x8c820000, 0x24a30001, 0x306701ff, 0x00021100,
+	0x3c010800, 0x00220821, 0xac271730, 0x8c820000, 0x00021100, 0x3c010800,
+	0x00220821, 0xac281734, 0x96230008, 0x3c020800, 0x8c42170c, 0x00432821,
+	0x3c010800, 0xac25170c, 0x9622000a, 0x30420004, 0x14400019, 0x00071100,
+	0x3c02c000, 0x00c21825, 0xaf635c5c, 0x8f625c50, 0x30420002, 0x1440fffc,
+	0x00000000, 0x8f630c14, 0x3063000f, 0x2c620002, 0x1440001e, 0x00000000,
+	0x8f630c14, 0x3c020800, 0x8c4216b4, 0x3063000f, 0x24420001, 0x3c010800,
+	0xac2216b4, 0x2c620002, 0x1040fff7, 0x00000000, 0x0a0001c1, 0x00000000,
+	0x3c030800, 0x8c6316e0, 0x3c040800, 0x948416f4, 0x01021025, 0x3c010800,
+	0xa4221fba, 0x24020001, 0x3c010800, 0xac221718, 0x24630001, 0x0085202a,
+	0x3c010800, 0x10800003, 0xac2316e0, 0x3c010800, 0xa42516f4, 0x3c030800,
+	0x246316fc, 0x8c620000, 0x24420001, 0xac620000, 0x28420080, 0x14400005,
+	0x24020001, 0x0e0002df, 0x24040002, 0x0a000250, 0x00000000, 0x3c030800,
+	0x906316f8, 0x1462007c, 0x24020003, 0x3c160800, 0x96d616f6, 0x3c050800,
+	0x8ca5170c, 0x32c4ffff, 0x00a4102a, 0x14400078, 0x00000000, 0x3c020800,
+	0x8c421718, 0x10400005, 0x32c2ffff, 0x14a40003, 0x00000000, 0x3c010800,
+	0xac231fd0, 0x10400062, 0x00009021, 0x0040a021, 0x3c150800, 0x26b51700,
+	0x26b30010, 0x8ea20000, 0x00028100, 0x3c110800, 0x02308821, 0x0e0002e1,
+	0x8e311728, 0x00403021, 0x10c00059, 0x00000000, 0x9628000a, 0x31020040,
+	0x10400004, 0x2407180c, 0x8e22000c, 0x2407188c, 0xacc20018, 0x31021000,
+	0x10400004, 0x34e32000, 0x00081040, 0x3042c000, 0x00623825, 0x3c030800,
+	0x00701821, 0x8c631730, 0x3c020800, 0x00501021, 0x8c421734, 0x00031d00,
+	0x00021400, 0x00621825, 0xacc30014, 0x8ea30004, 0x96220008, 0x00432023,
+	0x3242ffff, 0x3083ffff, 0x00431021, 0x0282102a, 0x14400002, 0x02d22823,
+	0x00802821, 0x8e620000, 0x30a4ffff, 0x00441021, 0xae620000, 0x8e220000,
+	0xacc20000, 0x8e220004, 0x8e63fff4, 0x00431021, 0xacc20004, 0xa4c5000e,
+	0x8e62fff4, 0x00441021, 0xae62fff4, 0x96230008, 0x0043102a, 0x14400005,
+	0x02459021, 0x8e62fff0, 0xae60fff4, 0x24420001, 0xae62fff0, 0xacc00008,
+	0x3242ffff, 0x14540008, 0x24020305, 0x31020080, 0x54400001, 0x34e70010,
+	0x24020905, 0xa4c2000c, 0x0a000233, 0x34e70020, 0xa4c2000c, 0x30e2ffff,
+	0xacc20010, 0x3c020800, 0x8c421fd0, 0x10400003, 0x3c024b65, 0x0a00023d,
+	0x34427654, 0x3c02b49a, 0x344289ab, 0xacc2001c, 0x0e000560, 0x00c02021,
+	0x3242ffff, 0x0054102b, 0x1440ffa4, 0x00000000, 0x24020002, 0x3c010800,
+	0x0a000250, 0xa02216f8, 0x8ea208bc, 0x24420001, 0x0a000250, 0xaea208bc,
+	0x14620003, 0x00000000, 0x0e000450, 0x00000000, 0x8fbf002c, 0x8fb60028,
+	0x8fb50024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
+	0x03e00008, 0x27bd0030, 0x27bdffd8, 0xafb3001c, 0x00809821, 0xafbf0020,
+	0xafb20018, 0xafb10014, 0xafb00010, 0x8f725c9c, 0x3c0200ff, 0x3442fff8,
+	0x3c040800, 0x24841714, 0x02428824, 0x9623000e, 0x8c820000, 0x00431021,
+	0xac820000, 0x8e220010, 0x30420020, 0x14400011, 0x00000000, 0x0e0002f7,
+	0x02202021, 0x3c02c000, 0x02421825, 0xaf635c9c, 0x8f625c90, 0x30420002,
+	0x10400061, 0x00000000, 0xaf635c9c, 0x8f625c90, 0x30420002, 0x1040005c,
+	0x00000000, 0x0a000278, 0x00000000, 0x8e220008, 0x00021c02, 0x000321c0,
+	0x3042ffff, 0x3c030800, 0x906316f8, 0x000229c0, 0x24020002, 0x14620003,
+	0x3c034b65, 0x0a000290, 0x00008021, 0x8e22001c, 0x34637654, 0x10430002,
+	0x24100002, 0x24100001, 0x0e000300, 0x02003021, 0x24020003, 0x3c010800,
+	0xa02216f8, 0x24020002, 0x1202000a, 0x24020001, 0x3c030800, 0x8c631fd0,
+	0x10620006, 0x00000000, 0x3c020800, 0x94421fb8, 0x00021400, 0x0a0002cd,
+	0xae220014, 0x3c040800, 0x24841fba, 0x94820000, 0x00021400, 0xae220014,
+	0x3c020800, 0x8c42171c, 0x3c03c000, 0x3c010800, 0xa02016f8, 0x00431025,
+	0xaf625c5c, 0x8f625c50, 0x30420002, 0x10400009, 0x00000000, 0x2484f762,
+	0x8c820000, 0x00431025, 0xaf625c5c, 0x8f625c50, 0x30420002, 0x1440fffa,
+	0x00000000, 0x3c020800, 0x244216e4, 0x8c430000, 0x24630001, 0xac430000,
+	0x8f630c14, 0x3063000f, 0x2c620002, 0x1440000b, 0x00009821, 0x8f630c14,
+	0x3c020800, 0x8c4216b4, 0x3063000f, 0x24420001, 0x3c010800, 0xac2216b4,
+	0x2c620002, 0x1040fff7, 0x00009821, 0x3c024000, 0x02421825, 0xaf635c9c,
+	0x8f625c90, 0x30420002, 0x1440fffc, 0x00000000, 0x12600003, 0x00000000,
+	0x0e000450, 0x00000000, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
+	0x8fb00010, 0x03e00008, 0x27bd0028, 0x0a0002df, 0x00000000, 0x8f634450,
+	0x3c040800, 0x248416e8, 0x8c820000, 0x00031c02, 0x0043102b, 0x14400007,
+	0x3c038000, 0x8c840004, 0x8f624450, 0x00021c02, 0x0083102b, 0x1040fffc,
+	0x3c038000, 0xaf634444, 0x8f624444, 0x00431024, 0x1440fffd, 0x00000000,
+	0x8f624448, 0x03e00008, 0x3042ffff, 0x3c024000, 0x00822025, 0xaf645c38,
+	0x8f625c30, 0x30420002, 0x1440fffc, 0x00000000, 0x03e00008, 0x00000000,
+	0x27bdffe0, 0x00805021, 0x14c00017, 0x254c0008, 0x3c020800, 0x8c421fd4,
+	0x1040000a, 0x2402003e, 0x3c010800, 0xa4221fb0, 0x24020016, 0x3c010800,
+	0xa4221fb2, 0x2402002a, 0x3c010800, 0x0a00031a, 0xa4221fb4, 0x95420014,
+	0x3c010800, 0xa4221fb0, 0x8d430010, 0x00031402, 0x3c010800, 0xa4221fb2,
+	0x3c010800, 0xa4231fb4, 0x3c040800, 0x94841fb4, 0x3c030800, 0x94631fb2,
+	0x958d0006, 0x3c020800, 0x94421fb0, 0x00832023, 0x01a27023, 0x3065ffff,
+	0x24a20028, 0x01824021, 0x3082ffff, 0x14c0001a, 0x01025821, 0x9562000c,
+	0x3042003f, 0x3c010800, 0xa4221fb6, 0x95620004, 0x95630006, 0x3c010800,
+	0xac201fc4, 0x3c010800, 0xac201fc8, 0x00021400, 0x00431025, 0x3c010800,
+	0xac221720, 0x95020004, 0x3c010800, 0xa4221724, 0x95030002, 0x01a51023,
+	0x0043102a, 0x10400010, 0x24020001, 0x3c010800, 0x0a00034e, 0xac221fd8,
+	0x3c030800, 0x8c631fc8, 0x3c020800, 0x94421724, 0x00431021, 0xa5020004,
+	0x3c020800, 0x94421720, 0xa5620004, 0x3c020800, 0x8c421720, 0xa5620006,
+	0x3c020800, 0x8c421fd0, 0x3c070800, 0x8ce71fc4, 0x3c050800, 0x144000c7,
+	0x8ca51fc8, 0x3c020800, 0x94421724, 0x00451821, 0x3063ffff, 0x0062182b,
+	0x24020002, 0x10c2000d, 0x00a32823, 0x3c020800, 0x94421fb6, 0x30420009,
+	0x10400008, 0x00000000, 0x9562000c, 0x3042fff6, 0xa562000c, 0x3c020800,
+	0x94421fb6, 0x30420009, 0x00e23823, 0x3c020800, 0x8c421fd8, 0x1040004b,
+	0x24020002, 0x01003021, 0x3c020800, 0x94421fb2, 0x00003821, 0xa500000a,
+	0x01a21023, 0xa5020002, 0x3082ffff, 0x00021042, 0x18400008, 0x00002821,
+	0x00401821, 0x94c20000, 0x24e70001, 0x00a22821, 0x00e3102a, 0x1440fffb,
+	0x24c60002, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402, 0x00a22821,
+	0x00a04821, 0x00051027, 0xa502000a, 0x00002821, 0x2506000c, 0x00003821,
+	0x94c20000, 0x24e70001, 0x00a22821, 0x2ce20004, 0x1440fffb, 0x24c60002,
+	0x95020002, 0x00003821, 0x91030009, 0x00442023, 0x01603021, 0x3082ffff,
+	0xa4c00010, 0x00621821, 0x00021042, 0x18400010, 0x00a32821, 0x00404021,
+	0x94c20000, 0x24c60002, 0x00a22821, 0x30c2007f, 0x14400006, 0x24e70001,
+	0x8d430000, 0x3c02007f, 0x3442ff80, 0x00625024, 0x25460008, 0x00e8102a,
+	0x1440fff3, 0x00000000, 0x30820001, 0x10400005, 0x00051c02, 0xa0c00001,
+	0x94c20000, 0x00a22821, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402,
+	0x00a22821, 0x0a000415, 0x30a5ffff, 0x14c20063, 0x00000000, 0x3c090800,
+	0x95291fb2, 0x95030002, 0x01a91023, 0x1062005d, 0x01003021, 0x00003821,
+	0x00002821, 0x01a91023, 0xa5020002, 0x3082ffff, 0x00021042, 0x18400008,
+	0xa500000a, 0x00401821, 0x94c20000, 0x24e70001, 0x00a22821, 0x00e3102a,
+	0x1440fffb, 0x24c60002, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402,
+	0x00a22821, 0x00a04821, 0x00051027, 0xa502000a, 0x00002821, 0x2506000c,
+	0x00003821, 0x94c20000, 0x24e70001, 0x00a22821, 0x2ce20004, 0x1440fffb,
+	0x24c60002, 0x95020002, 0x00003821, 0x91030009, 0x00442023, 0x01603021,
+	0x3082ffff, 0xa4c00010, 0x3c040800, 0x94841fb4, 0x00621821, 0x00a32821,
+	0x00051c02, 0x30a2ffff, 0x00622821, 0x00051c02, 0x3c020800, 0x94421fb0,
+	0x00a34021, 0x00441023, 0x00021fc2, 0x00431021, 0x00021043, 0x18400010,
+	0x00002821, 0x00402021, 0x94c20000, 0x24c60002, 0x00a22821, 0x30c2007f,
+	0x14400006, 0x24e70001, 0x8d430000, 0x3c02007f, 0x3442ff80, 0x00625024,
+	0x25460008, 0x00e4102a, 0x1440fff3, 0x00000000, 0x3c020800, 0x94421fcc,
+	0x00a22821, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402, 0x00a22821,
+	0x3102ffff, 0x00a22821, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402,
+	0x00a22821, 0x00a02021, 0x00051027, 0xa5620010, 0xad800014, 0x0a000435,
+	0xad800000, 0x8d830010, 0x00602021, 0x10a00007, 0x00034c02, 0x01252821,
+	0x00051402, 0x30a3ffff, 0x00432821, 0x00051402, 0x00a24821, 0x00091027,
+	0xa502000a, 0x3c030800, 0x94631fb4, 0x3082ffff, 0x01a21021, 0x00432823,
+	0x00a72821, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402, 0x00a22821,
+	0x00a02021, 0x00051027, 0xa5620010, 0x3082ffff, 0x00091c00, 0x00431025,
+	0xad820010, 0x3c020800, 0x8c421fd4, 0x10400002, 0x25a2fff2, 0xa5820034,
+	0x3c020800, 0x8c421fc8, 0x3c030800, 0x8c631720, 0x24420001, 0x3c010800,
+	0xac221fc8, 0x3c020800, 0x8c421fc4, 0x31c4ffff, 0x00641821, 0x3c010800,
+	0xac231720, 0x00441021, 0x3c010800, 0xac221fc4, 0x03e00008, 0x27bd0020,
+	0x27bdffc8, 0x3c040800, 0x248416f8, 0xafbf0034, 0xafbe0030, 0xafb7002c,
+	0xafb60028, 0xafb50024, 0xafb40020, 0xafb3001c, 0xafb20018, 0xafb10014,
+	0xafb00010, 0x90830000, 0x24020003, 0x146200f4, 0x00000000, 0x3c020800,
+	0x8c421710, 0x3c030800, 0x8c63170c, 0x3c1e0800, 0x97de16f6, 0x0043102a,
+	0x104000eb, 0x3c168000, 0x249708c4, 0x33d5ffff, 0x24920018, 0x3c020800,
+	0x8c421718, 0x104000e4, 0x00000000, 0x3c140800, 0x96941fb0, 0x3282ffff,
+	0x104000d6, 0x00008021, 0x00409821, 0x00008821, 0x8f634450, 0x3c020800,
+	0x8c4216e8, 0x00031c02, 0x0043102b, 0x14400008, 0x00000000, 0x3c040800,
+	0x8c8416ec, 0x8f624450, 0x00021c02, 0x0083102b, 0x1040fffc, 0x00000000,
+	0xaf764444, 0x8f624444, 0x00561024, 0x10400006, 0x00000000, 0x3c038000,
+	0x8f624444, 0x00431024, 0x1440fffd, 0x00000000, 0x8f624448, 0x3046ffff,
+	0x10c0005f, 0x00000000, 0x3c090800, 0x01314821, 0x8d291728, 0x9528000a,
+	0x31020040, 0x10400004, 0x2407180c, 0x8d22000c, 0x2407188c, 0xacc20018,
+	0x31021000, 0x10400004, 0x34e32000, 0x00081040, 0x3042c000, 0x00623825,
+	0x31020080, 0x54400001, 0x34e70010, 0x3c020800, 0x00511021, 0x8c421730,
+	0x3c030800, 0x00711821, 0x8c631734, 0x00021500, 0x00031c00, 0x00431025,
+	0xacc20014, 0x95240008, 0x3202ffff, 0x00821021, 0x0262102a, 0x14400002,
+	0x02902823, 0x00802821, 0x8d220000, 0x02058021, 0xacc20000, 0x8d220004,
+	0x00c02021, 0x26310010, 0xac820004, 0x30e2ffff, 0xac800008, 0xa485000e,
+	0xac820010, 0x24020305, 0x0e000560, 0xa482000c, 0x3202ffff, 0x0053102b,
+	0x1440ffaf, 0x3202ffff, 0x0a00054c, 0x00000000, 0x8e420000, 0x8e43fffc,
+	0x0043102a, 0x10400084, 0x00000000, 0x8e45fff0, 0x8f644450, 0x3c030800,
+	0x8c6316e8, 0x00051100, 0x3c090800, 0x01224821, 0x8d291728, 0x00041402,
+	0x0062182b, 0x14600008, 0x00000000, 0x3c030800, 0x8c6316ec, 0x8f624450,
+	0x00021402, 0x0062102b, 0x1040fffc, 0x00000000, 0xaf764444, 0x8f624444,
+	0x00561024, 0x10400006, 0x00000000, 0x3c038000, 0x8f624444, 0x00431024,
+	0x1440fffd, 0x00000000, 0x8f624448, 0x3046ffff, 0x14c00005, 0x00000000,
+	0x8ee20000, 0x24420001, 0x0a000554, 0xaee20000, 0x9528000a, 0x31020040,
+	0x10400004, 0x2407180c, 0x8d22000c, 0x2407188c, 0xacc20018, 0x31021000,
+	0x10400004, 0x34e32000, 0x00081040, 0x3042c000, 0x00623825, 0x00051900,
+	0x3c020800, 0x00431021, 0x8c421730, 0x3c010800, 0x00230821, 0x8c231734,
+	0x00021500, 0x00031c00, 0x00431025, 0xacc20014, 0x3c030800, 0x8c631704,
+	0x95220008, 0x00432023, 0x3202ffff, 0x3083ffff, 0x00431021, 0x02a2102a,
+	0x14400002, 0x03d02823, 0x00802821, 0x8e420000, 0x30a4ffff, 0x00441021,
+	0xae420000, 0xa4c5000e, 0x8d220000, 0xacc20000, 0x8d220004, 0x8e43fff4,
+	0x00431021, 0xacc20004, 0x8e43fff4, 0x95220008, 0x00641821, 0x0062102a,
+	0x14400006, 0x02058021, 0x8e42fff0, 0xae40fff4, 0x24420001, 0x0a000530,
+	0xae42fff0, 0xae43fff4, 0xacc00008, 0x3202ffff, 0x10550003, 0x31020004,
+	0x10400006, 0x24020305, 0x31020080, 0x54400001, 0x34e70010, 0x34e70020,
+	0x24020905, 0xa4c2000c, 0x30e2ffff, 0xacc20010, 0x3c030800, 0x8c63170c,
+	0x3c020800, 0x8c421710, 0x54620004, 0x3c02b49a, 0x3c024b65, 0x0a000548,
+	0x34427654, 0x344289ab, 0xacc2001c, 0x0e000560, 0x00c02021, 0x3202ffff,
+	0x0055102b, 0x1440ff7e, 0x00000000, 0x8e420000, 0x8e43fffc, 0x0043102a,
+	0x1440ff1a, 0x00000000, 0x8fbf0034, 0x8fbe0030, 0x8fb7002c, 0x8fb60028,
+	0x8fb50024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
+	0x03e00008, 0x27bd0038, 0x27bdffe8, 0xafbf0014, 0xafb00010, 0x8f624450,
+	0x8f634410, 0x0a00056f, 0x00808021, 0x8f626820, 0x30422000, 0x10400003,
+	0x00000000, 0x0e00025a, 0x00002021, 0x8f624450, 0x8f634410, 0x3042ffff,
+	0x0043102b, 0x1440fff5, 0x00000000, 0x8f630c14, 0x3063000f, 0x2c620002,
+	0x1440000b, 0x00000000, 0x8f630c14, 0x3c020800, 0x8c4216b4, 0x3063000f,
+	0x24420001, 0x3c010800, 0xac2216b4, 0x2c620002, 0x1040fff7, 0x00000000,
+	0xaf705c18, 0x8f625c10, 0x30420002, 0x10400009, 0x00000000, 0x8f626820,
+	0x30422000, 0x1040fff8, 0x00000000, 0x0e00025a, 0x00002021, 0x0a000582,
+	0x00000000, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x00000000,
+	0x00000000
+};
+
+u32 tg3TsoFwRodata[] = {
+	0x4d61696e, 0x43707542, 0x00000000, 0x00000000, 0x74637073, 0x6567496e,
+	0x00000000, 0x53774576, 0x656e7430, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000
+};
+
+#if 0 /* All zeros, dont eat up space with it. */
+u32 tg3TsoFwData[] = {
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000
+};
+#endif
+
+/* tp->lock is held. */
+static int tg3_load_tso_firmware(struct tg3 *tp)
+{
+	struct fw_info info;
+	int err, i;
+
+	info.text_base = TG3_TSO_FW_TEXT_ADDR;
+	info.text_len = TG3_TSO_FW_TEXT_LEN;
+	info.text_data = &tg3TsoFwText[0];
+	info.rodata_base = TG3_TSO_FW_RODATA_ADDR;
+	info.rodata_len = TG3_TSO_FW_RODATA_LEN;
+	info.rodata_data = &tg3TsoFwRodata[0];
+	info.data_base = TG3_TSO_FW_DATA_ADDR;
+	info.data_len = TG3_TSO_FW_DATA_LEN;
+	info.data_data = NULL;
+
+	err = tg3_load_firmware_cpu(tp, TX_CPU_BASE,
+				    TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE,
+				    &info);
+	if (err)
+		return err;
+
+	/* Now startup only the TX cpu. */
+	tw32(TX_CPU_BASE + CPU_STATE, 0xffffffff);
+	tw32(TX_CPU_BASE + CPU_PC,    TG3_TSO_FW_TEXT_ADDR);
+
+	/* Flush posted writes. */
+	tr32(TX_CPU_BASE + CPU_PC);
+	for (i = 0; i < 5; i++) {
+		if (tr32(TX_CPU_BASE + CPU_PC) == TG3_TSO_FW_TEXT_ADDR)
+			break;
+		tw32(TX_CPU_BASE + CPU_STATE, 0xffffffff);
+		tw32(TX_CPU_BASE + CPU_MODE,  CPU_MODE_HALT);
+		tw32(TX_CPU_BASE + CPU_PC,    TG3_TSO_FW_TEXT_ADDR);
+
+		/* Flush posted writes. */
+		tr32(TX_CPU_BASE + CPU_PC);
+
+		udelay(1000);
+	}
+	if (i >= 5) {
+		printk(KERN_ERR PFX "tg3_load_tso_firmware fails for %s "
+		       "to set TX CPU PC, is %08x should be %08x\n",
+		       tp->dev->name, tr32(TX_CPU_BASE + CPU_PC),
+		       TG3_TSO_FW_TEXT_ADDR);
+		return -ENODEV;
+	}
+	tw32(TX_CPU_BASE + CPU_STATE, 0xffffffff);
+	tw32(TX_CPU_BASE + CPU_MODE,  0x00000000);
+
+	/* Flush posted writes. */
+	tr32(TX_CPU_BASE + CPU_MODE);
+
+	return 0;
+}
+
+#endif /* TG3_DO_TSO != 0 */
+
 /* tp->lock is held. */
 static void __tg3_set_mac_addr(struct tg3 *tp)
 {
@@ -3365,6 +3925,8 @@
 
 	tg3_disable_ints(tp);
 
+	tg3_stop_fw(tp);
+
 	if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) {
 		err = tg3_abort_hw(tp);
 		if (err)
@@ -3382,6 +3944,8 @@
 		tw32(MAC_MODE, tp->mac_mode);
 	} else
 		tw32(MAC_MODE, 0);
+	tr32(MAC_MODE);
+	udelay(40);
 
 	/* Wait for firmware initialization to complete. */
 	for (i = 0; i < 100000; i++) {
@@ -3397,6 +3961,13 @@
 		return -ENODEV;
 	}
 
+	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF)
+		tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+			      DRV_STATE_START);
+	else
+		tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+			      DRV_STATE_SUSPEND);
+
 	/* This works around an issue with Athlon chipsets on
 	 * B3 tigon3 silicon.  This bit has no effect on any
 	 * other revision.
@@ -3404,12 +3975,22 @@
 	val = tr32(TG3PCI_CLOCK_CTRL);
 	val |= CLOCK_CTRL_DELAY_PCI_GRANT;
 	tw32(TG3PCI_CLOCK_CTRL, val);
+	tr32(TG3PCI_CLOCK_CTRL);
+
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
+	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) {
+		val = tr32(TG3PCI_PCISTATE);
+		val |= PCISTATE_RETRY_SAME_DMA;
+		tw32(TG3PCI_PCISTATE, val);
+	}
 
 	/* Clear statistics/status block in chip, and status block in ram. */
 	for (i = NIC_SRAM_STATS_BLK;
 	     i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE;
-	     i += sizeof(u32))
+	     i += sizeof(u32)) {
 		tg3_write_mem(tp, i, 0);
+		udelay(40);
+	}
 	memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
 
 	/* This value is determined during the probe time DMA
@@ -3440,7 +4021,10 @@
 
 	/* Initialize MBUF/DESC pool. */
 	tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE);
-	tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+		tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE64);
+	else
+		tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE96);
 	tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE);
 	tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE);
 
@@ -3560,6 +4144,8 @@
 	tp->tx_cons = 0;
 	tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
 	tw32_mailbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
+	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+		tr32(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW);
 
 	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
 		tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB,
@@ -3581,6 +4167,8 @@
 
 	tp->rx_rcb_ptr = 0;
 	tw32_mailbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, 0);
+	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+		tr32(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW);
 
 	tg3_set_bdinfo(tp, NIC_SRAM_RCV_RET_RCB,
 		       tp->rx_rcb_mapping,
@@ -3591,10 +4179,14 @@
 	tp->rx_std_ptr = tp->rx_pending;
 	tw32_mailbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW,
 		     tp->rx_std_ptr);
+	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+		tr32(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW);
 #if TG3_MINI_RING_WORKS
 	tp->rx_mini_ptr = tp->rx_mini_pending;
 	tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW,
 		     tp->rx_mini_ptr);
+	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+		tr32(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW);
 #endif
 
 	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE)
@@ -3603,6 +4195,8 @@
 		tp->rx_jumbo_ptr = 0;
 	tw32_mailbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW,
 		     tp->rx_jumbo_ptr);
+	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+		tr32(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW);
 
 	/* Initialize MAC address and backoff seed. */
 	__tg3_set_mac_addr(tp);
@@ -3638,24 +4232,16 @@
 		udelay(10);
 	}
 
-	tw32(HOSTCC_RXCOL_TICKS,
-	     tp->coalesce_config.rx_coalesce_ticks);
-	tw32(HOSTCC_RXMAX_FRAMES,
-	     tp->coalesce_config.rx_max_coalesced_frames);
-	tw32(HOSTCC_RXCOAL_TICK_INT,
-	     tp->coalesce_config.rx_coalesce_ticks_during_int);
-	tw32(HOSTCC_RXCOAL_MAXF_INT,
-	     tp->coalesce_config.rx_max_coalesced_frames_during_int);
-	tw32(HOSTCC_TXCOL_TICKS,
-	     tp->coalesce_config.tx_coalesce_ticks);
-	tw32(HOSTCC_TXMAX_FRAMES,
-	     tp->coalesce_config.tx_max_coalesced_frames);
-	tw32(HOSTCC_TXCOAL_TICK_INT,
-	     tp->coalesce_config.tx_coalesce_ticks_during_int);
-	tw32(HOSTCC_TXCOAL_MAXF_INT,
-	     tp->coalesce_config.tx_max_coalesced_frames_during_int);
+	tw32(HOSTCC_RXCOL_TICKS, 0);
+	tw32(HOSTCC_RXMAX_FRAMES, 1);
+	tw32(HOSTCC_RXCOAL_TICK_INT, 0);
+	tw32(HOSTCC_RXCOAL_MAXF_INT, 1);
+	tw32(HOSTCC_TXCOL_TICKS, LOW_TXCOL_TICKS);
+	tw32(HOSTCC_TXMAX_FRAMES, LOW_RXMAX_FRAMES);
+	tw32(HOSTCC_TXCOAL_TICK_INT, 0);
+	tw32(HOSTCC_TXCOAL_MAXF_INT, 0);
 	tw32(HOSTCC_STAT_COAL_TICKS,
-	     tp->coalesce_config.stats_coalesce_ticks);
+	     DEFAULT_STAT_COAL_TICKS);
 
 	/* Status/statistics block address. */
 	tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH,
@@ -3678,25 +4264,53 @@
 	tp->mac_mode = MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
 		MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE;
 	tw32(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR);
+	tr32(MAC_MODE);
+	udelay(40);
 
-	tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_GPIO_OE1 |
-		GRC_LCLCTRL_GPIO_OUTPUT1 | GRC_LCLCTRL_AUTO_SEEPROM;
+	tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_AUTO_SEEPROM;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
+		tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 |
+				       GRC_LCLCTRL_GPIO_OUTPUT1);
 	tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
+	tr32(GRC_LOCAL_CTRL);
+	udelay(100);
 
 	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0);
+	tr32(MAILBOX_INTERRUPT_0);
 
 	tw32(DMAC_MODE, DMAC_MODE_ENABLE);
+	tr32(DMAC_MODE);
+	udelay(40);
 
 	tw32(WDMAC_MODE, (WDMAC_MODE_ENABLE | WDMAC_MODE_TGTABORT_ENAB |
 			  WDMAC_MODE_MSTABORT_ENAB | WDMAC_MODE_PARITYERR_ENAB |
 			  WDMAC_MODE_ADDROFLOW_ENAB | WDMAC_MODE_FIFOOFLOW_ENAB |
 			  WDMAC_MODE_FIFOURUN_ENAB | WDMAC_MODE_FIFOOREAD_ENAB |
 			  WDMAC_MODE_LNGREAD_ENAB));
-	tw32(RDMAC_MODE, (RDMAC_MODE_ENABLE | RDMAC_MODE_TGTABORT_ENAB |
-			  RDMAC_MODE_MSTABORT_ENAB | RDMAC_MODE_PARITYERR_ENAB |
-			  RDMAC_MODE_ADDROFLOW_ENAB | RDMAC_MODE_FIFOOFLOW_ENAB |
-			  RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
-			  RDMAC_MODE_LNGREAD_ENAB));
+	tr32(WDMAC_MODE);
+	udelay(40);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
+	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) {
+		val = tr32(TG3PCI_X_CAPS);
+		val &= ~(PCIX_CAPS_SPLIT_MASK | PCIX_CAPS_BURST_MASK);
+		val |= (PCIX_CAPS_MAX_BURST_5704 << PCIX_CAPS_BURST_SHIFT);
+		if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE)
+			val |= (tp->split_mode_max_reqs <<
+				PCIX_CAPS_SPLIT_SHIFT);
+		tw32(TG3PCI_X_CAPS, val);
+	}
+
+	val = (RDMAC_MODE_ENABLE | RDMAC_MODE_TGTABORT_ENAB |
+	       RDMAC_MODE_MSTABORT_ENAB | RDMAC_MODE_PARITYERR_ENAB |
+	       RDMAC_MODE_ADDROFLOW_ENAB | RDMAC_MODE_FIFOOFLOW_ENAB |
+	       RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
+	       RDMAC_MODE_LNGREAD_ENAB);
+	if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE)
+		val |= RDMAC_MODE_SPLIT_ENABLE;
+	tw32(RDMAC_MODE, val);
+	tr32(RDMAC_MODE);
+	udelay(40);
 
 	tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE);
 	tw32(MBFREE_MODE, MBFREE_MODE_ENABLE);
@@ -3714,10 +4328,21 @@
 			return err;
 	}
 
+#if TG3_DO_TSO != 0
+	err = tg3_load_tso_firmware(tp);
+	if (err)
+		return err;
+#endif
+
 	tp->tx_mode = TX_MODE_ENABLE;
 	tw32(MAC_TX_MODE, tp->tx_mode);
+	tr32(MAC_TX_MODE);
+	udelay(100);
+
 	tp->rx_mode = RX_MODE_ENABLE;
 	tw32(MAC_RX_MODE, tp->rx_mode);
+	tr32(MAC_RX_MODE);
+	udelay(10);
 
 	if (tp->link_config.phy_is_low_power) {
 		tp->link_config.phy_is_low_power = 0;
@@ -3728,11 +4353,17 @@
 
 	tp->mi_mode = MAC_MI_MODE_BASE;
 	tw32(MAC_MI_MODE, tp->mi_mode);
+	tr32(MAC_MI_MODE);
+	udelay(40);
+
 	tw32(MAC_LED_CTRL, 0);
 	tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
 	tw32(MAC_RX_MODE, RX_MODE_RESET);
+	tr32(MAC_RX_MODE);
 	udelay(10);
 	tw32(MAC_RX_MODE, tp->rx_mode);
+	tr32(MAC_RX_MODE);
+	udelay(10);
 
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1)
 		tw32(MAC_SERDES_CFG, 0x616000);
@@ -3792,6 +4423,8 @@
 	if (err)
 		goto out;
 
+	tg3_switch_clocks(tp);
+
 	tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
 
 	err = tg3_reset_hw(tp);
@@ -3805,25 +4438,24 @@
 	struct tg3 *tp = (struct tg3 *) __opaque;
 
 	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
 
-	if (!(tp->tg3_flags & TG3_FLAG_TAGGED_IRQ_STATUS)) {
-		/* All of this garbage is because on the 5700 the
-		 * mailbox/status_block protocol the chip uses with
-		 * the cpu is race prone.
-		 */
-		if (tp->hw_status->status & SD_STATUS_UPDATED) {
-			tw32(GRC_LOCAL_CTRL,
-			     tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
-		} else {
-			tw32(HOSTCC_MODE,
-			     (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW));
-		}
+	/* All of this garbage is because when using non-tagged
+	 * IRQ status the mailbox/status_block protocol the chip
+	 * uses with the cpu is race prone.
+	 */
+	if (tp->hw_status->status & SD_STATUS_UPDATED) {
+		tw32(GRC_LOCAL_CTRL,
+		     tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
+	} else {
+		tw32(HOSTCC_MODE, tp->coalesce_mode |
+		     (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW));
+	}
 
-		if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
-			tg3_halt(tp);
-			tg3_init_rings(tp);
-			tg3_init_hw(tp);
-		}
+	if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
+		tg3_halt(tp);
+		tg3_init_rings(tp);
+		tg3_init_hw(tp);
 	}
 
 	/* This part only runs once per second. */
@@ -3859,8 +4491,11 @@
 				tw32(MAC_MODE,
 				     (tp->mac_mode &
 				      ~MAC_MODE_PORT_MODE_MASK));
+				tr32(MAC_MODE);
 				udelay(40);
 				tw32(MAC_MODE, tp->mac_mode);
+				tr32(MAC_MODE);
+				udelay(40);
 				tg3_setup_phy(tp);
 			}
 		}
@@ -3868,6 +4503,22 @@
 		tp->timer_counter = tp->timer_multiplier;
 	}
 
+	/* Heartbeat is only sent once every 120 seconds.  */
+	if (!--tp->asf_counter) {
+		if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+			u32 val;
+
+			tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_ALIVE);
+			tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
+			tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 3);
+			val = tr32(GRC_RX_CPU_EVENT);
+			val |= (1 << 14);
+			tw32(GRC_RX_CPU_EVENT, val);
+		}
+		tp->asf_counter = tp->asf_multiplier;
+	}
+
+	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
 	tp->timer.expires = jiffies + tp->timer_offset;
@@ -3880,10 +4531,12 @@
 	int err;
 
 	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
 
 	tg3_disable_ints(tp);
 	tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
 
+	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
 	/* If you move this call, make sure TG3_FLAG_HOST_TXDS in
@@ -3893,12 +4546,8 @@
 	if (err)
 		return err;
 
-	if (tp->tg3_flags & TG3_FLAG_TAGGED_IRQ_STATUS)
-		err = request_irq(dev->irq, tg3_interrupt_tagged,
-				  SA_SHIRQ, dev->name, dev);
-	else
-		err = request_irq(dev->irq, tg3_interrupt,
-				  SA_SHIRQ, dev->name, dev);
+	err = request_irq(dev->irq, tg3_interrupt,
+			  SA_SHIRQ, dev->name, dev);
 
 	if (err) {
 		tg3_free_consistent(tp);
@@ -3906,6 +4555,7 @@
 	}
 
 	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
 
 	tg3_init_rings(tp);
 
@@ -3914,13 +4564,9 @@
 		tg3_halt(tp);
 		tg3_free_rings(tp);
 	} else {
-		if (tp->tg3_flags & TG3_FLAG_TAGGED_IRQ_STATUS) {
-			tp->timer_offset = HZ;
-			tp->timer_counter = tp->timer_multiplier = 1;
-		} else {
-			tp->timer_offset = HZ / 10;
-			tp->timer_counter = tp->timer_multiplier = 10;
-		}
+		tp->timer_offset = HZ / 10;
+		tp->timer_counter = tp->timer_multiplier = 10;
+		tp->asf_counter = tp->asf_multiplier = (10 * 120);
 
 		init_timer(&tp->timer);
 		tp->timer.expires = jiffies + tp->timer_offset;
@@ -3928,13 +4574,10 @@
 		tp->timer.function = tg3_timer;
 		add_timer(&tp->timer);
 
-		tp->last_rate_sample = jiffies;
-		tp->last_rx_count = 0;
-		tp->last_tx_count = 0;
-
 		tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
 	}
 
+	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
 	if (err) {
@@ -3946,9 +4589,11 @@
 	netif_start_queue(dev);
 
 	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
 
 	tg3_enable_ints(tp);
 
+	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
 	return 0;
@@ -4210,6 +4855,7 @@
 	del_timer_sync(&tp->timer);
 
 	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
 #if 0
 	tg3_dump_state(tp);
 #endif
@@ -4223,6 +4869,7 @@
 		  TG3_FLAG_GOT_SERDES_FLOWCTL);
 	netif_carrier_off(tp->dev);
 
+	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
 	free_irq(dev->irq, dev);
@@ -4240,10 +4887,7 @@
 	unsigned long ret;
 
 #if (BITS_PER_LONG == 32)
-	if (val->high != 0)
-		ret = ~0UL;
-	else
-		ret = val->low;
+	ret = val->low;
 #else
 	ret = ((u64)val->high << 32) | ((u64)val->low);
 #endif
@@ -4357,10 +5001,10 @@
 static void tg3_set_multi(struct tg3 *tp, unsigned int accept_all)
 {
 	/* accept or reject all multicast frames */
-	tw32 (MAC_HASH_REG_0, accept_all ? 0xffffffff : 0);
-	tw32 (MAC_HASH_REG_1, accept_all ? 0xffffffff : 0);
-	tw32 (MAC_HASH_REG_2, accept_all ? 0xffffffff : 0);
-	tw32 (MAC_HASH_REG_3, accept_all ? 0xffffffff : 0);
+	tw32(MAC_HASH_REG_0, accept_all ? 0xffffffff : 0);
+	tw32(MAC_HASH_REG_1, accept_all ? 0xffffffff : 0);
+	tw32(MAC_HASH_REG_2, accept_all ? 0xffffffff : 0);
+	tw32(MAC_HASH_REG_3, accept_all ? 0xffffffff : 0);
 }
 
 static void __tg3_set_rx_mode(struct net_device *dev)
@@ -4368,7 +5012,17 @@
 	struct tg3 *tp = dev->priv;
 	u32 rx_mode;
 
-	rx_mode = tp->rx_mode & ~RX_MODE_PROMISC;
+	rx_mode = tp->rx_mode & ~(RX_MODE_PROMISC |
+				  RX_MODE_KEEP_VLAN_TAG);
+#if TG3_VLAN_TAG_USED
+	if (!tp->vlgrp)
+		rx_mode |= RX_MODE_KEEP_VLAN_TAG;
+#else
+	/* By definition, VLAN is disabled always in this
+	 * case.
+	 */
+	rx_mode |= RX_MODE_KEEP_VLAN_TAG;
+#endif
 
 	if (dev->flags & IFF_PROMISC) {
 		/* Promiscuous mode. */
@@ -4398,15 +5052,17 @@
 			mc_filter[regidx] |= (1 << bit);
 		}
 
-		tw32 (MAC_HASH_REG_0, mc_filter[0]);
-		tw32 (MAC_HASH_REG_1, mc_filter[1]);
-		tw32 (MAC_HASH_REG_2, mc_filter[2]);
-		tw32 (MAC_HASH_REG_3, mc_filter[3]);
+		tw32(MAC_HASH_REG_0, mc_filter[0]);
+		tw32(MAC_HASH_REG_1, mc_filter[1]);
+		tw32(MAC_HASH_REG_2, mc_filter[2]);
+		tw32(MAC_HASH_REG_3, mc_filter[3]);
 	}
 
 	if (rx_mode != tp->rx_mode) {
 		tp->rx_mode = rx_mode;
-		tw32 (MAC_RX_MODE, rx_mode);
+		tw32(MAC_RX_MODE, rx_mode);
+		tr32(MAC_RX_MODE);
+		udelay(10);
 	}
 }
 
@@ -4433,6 +5089,7 @@
 	memset(orig_p, 0, TG3_REGDUMP_LEN);
 
 	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
 
 #define __GET_REG32(reg)	(*((u32 *)(p))++ = tr32(reg))
 #define GET_REG32_LOOP(base,len)		\
@@ -4481,182 +5138,12 @@
 #undef GET_REG32_LOOP
 #undef GET_REG32_1
 
+	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
 	return orig_p;
 }
 
-static void tg3_to_ethtool_coal(struct tg3 *tp,
-				struct ethtool_coalesce *ecoal)
-{
-	ecoal->rx_coalesce_usecs =
-		tp->coalesce_config.rx_coalesce_ticks_def;
-	ecoal->rx_max_coalesced_frames =
-		tp->coalesce_config.rx_max_coalesced_frames_def;
-	ecoal->rx_coalesce_usecs_irq =
-		tp->coalesce_config.rx_coalesce_ticks_during_int_def;
-	ecoal->rx_max_coalesced_frames_irq =
-		tp->coalesce_config.rx_max_coalesced_frames_during_int_def;
-
-	ecoal->tx_coalesce_usecs =
-		tp->coalesce_config.tx_coalesce_ticks_def;
-	ecoal->tx_max_coalesced_frames =
-		tp->coalesce_config.tx_max_coalesced_frames_def;
-	ecoal->tx_coalesce_usecs_irq =
-		tp->coalesce_config.tx_coalesce_ticks_during_int_def;
-	ecoal->tx_max_coalesced_frames_irq =
-		tp->coalesce_config.tx_max_coalesced_frames_during_int_def;
-
-	ecoal->stats_block_coalesce_usecs =
-		tp->coalesce_config.stats_coalesce_ticks_def;
-
-	ecoal->use_adaptive_rx_coalesce =
-		(tp->tg3_flags & TG3_FLAG_ADAPTIVE_RX) != 0;
-	ecoal->use_adaptive_tx_coalesce =
-		(tp->tg3_flags & TG3_FLAG_ADAPTIVE_TX) != 0;
-
-	ecoal->pkt_rate_low =
-		tp->coalesce_config.pkt_rate_low;
-	ecoal->rx_coalesce_usecs_low =
-		tp->coalesce_config.rx_coalesce_ticks_low;
-	ecoal->rx_max_coalesced_frames_low =
-		tp->coalesce_config.rx_max_coalesced_frames_low;
-	ecoal->tx_coalesce_usecs_low =
-		tp->coalesce_config.tx_coalesce_ticks_low;
-	ecoal->tx_max_coalesced_frames_low =
-		tp->coalesce_config.tx_max_coalesced_frames_low;
-
-	ecoal->pkt_rate_high =
-		tp->coalesce_config.pkt_rate_high;
-	ecoal->rx_coalesce_usecs_high =
-		tp->coalesce_config.rx_coalesce_ticks_high;
-	ecoal->rx_max_coalesced_frames_high =
-		tp->coalesce_config.rx_max_coalesced_frames_high;
-	ecoal->tx_coalesce_usecs_high =
-		tp->coalesce_config.tx_coalesce_ticks_high;
-	ecoal->tx_max_coalesced_frames_high =
-		tp->coalesce_config.tx_max_coalesced_frames_high;
-
-	ecoal->rate_sample_interval =
-		tp->coalesce_config.rate_sample_jiffies / HZ;
-}
-
-static int tg3_from_ethtool_coal(struct tg3 *tp,
-				 struct ethtool_coalesce *ecoal)
-{
-	/* Make sure we are not getting garbage. */
-	if ((ecoal->rx_coalesce_usecs == 0 &&
-	     ecoal->rx_max_coalesced_frames == 0) ||
-	    (ecoal->tx_coalesce_usecs == 0 &&
-	     ecoal->tx_max_coalesced_frames == 0) ||
-	    ecoal->stats_block_coalesce_usecs == 0)
-		return -EINVAL;
-	if (ecoal->use_adaptive_rx_coalesce ||
-	    ecoal->use_adaptive_tx_coalesce) {
-		if (ecoal->pkt_rate_low > ecoal->pkt_rate_high)
-			return -EINVAL;
-		if (ecoal->rate_sample_interval == 0)
-			return -EINVAL;
-		if (ecoal->use_adaptive_rx_coalesce &&
-		    ((ecoal->rx_coalesce_usecs_low == 0 &&
-		      ecoal->rx_max_coalesced_frames_low == 0) ||
-		     (ecoal->rx_coalesce_usecs_high == 0 &&
-		      ecoal->rx_max_coalesced_frames_high == 0)))
-			return -EINVAL;
-		if (ecoal->use_adaptive_tx_coalesce &&
-		    ((ecoal->tx_coalesce_usecs_low == 0 &&
-		      ecoal->tx_max_coalesced_frames_low == 0) ||
-		     (ecoal->tx_coalesce_usecs_high == 0 &&
-		      ecoal->tx_max_coalesced_frames_high == 0)))
-			return -EINVAL;
-	}
-
-	/* Looks good, let it rip. */
-	spin_lock_irq(&tp->lock);
-	tp->coalesce_config.rx_coalesce_ticks =
-		tp->coalesce_config.rx_coalesce_ticks_def =
-		ecoal->rx_coalesce_usecs;
-	tp->coalesce_config.rx_max_coalesced_frames =
-		tp->coalesce_config.rx_max_coalesced_frames_def =
-		ecoal->rx_max_coalesced_frames;
-	tp->coalesce_config.rx_coalesce_ticks_during_int =
-		tp->coalesce_config.rx_coalesce_ticks_during_int_def =
-		ecoal->rx_coalesce_usecs_irq;
-	tp->coalesce_config.rx_max_coalesced_frames_during_int =
-		tp->coalesce_config.rx_max_coalesced_frames_during_int_def =
-		ecoal->rx_max_coalesced_frames_irq;
-	tp->coalesce_config.tx_coalesce_ticks =
-		tp->coalesce_config.tx_coalesce_ticks_def =
-		ecoal->tx_coalesce_usecs;
-	tp->coalesce_config.tx_max_coalesced_frames =
-		tp->coalesce_config.tx_max_coalesced_frames_def =
-		ecoal->tx_max_coalesced_frames;
-	tp->coalesce_config.tx_coalesce_ticks_during_int =
-		tp->coalesce_config.tx_coalesce_ticks_during_int_def =
-		ecoal->tx_coalesce_usecs_irq;
-	tp->coalesce_config.tx_max_coalesced_frames_during_int =
-		tp->coalesce_config.tx_max_coalesced_frames_during_int_def =
-		ecoal->tx_max_coalesced_frames_irq;
-	tp->coalesce_config.stats_coalesce_ticks =
-		tp->coalesce_config.stats_coalesce_ticks_def =
-		ecoal->stats_block_coalesce_usecs;
-
-	if (ecoal->use_adaptive_rx_coalesce)
-		tp->tg3_flags |= TG3_FLAG_ADAPTIVE_RX;
-	else
-		tp->tg3_flags &= ~TG3_FLAG_ADAPTIVE_RX;
-	if (ecoal->use_adaptive_tx_coalesce)
-		tp->tg3_flags |= TG3_FLAG_ADAPTIVE_TX;
-	else
-		tp->tg3_flags &= ~TG3_FLAG_ADAPTIVE_TX;
-
-	tp->coalesce_config.pkt_rate_low = ecoal->pkt_rate_low;
-	tp->coalesce_config.pkt_rate_high = ecoal->pkt_rate_high;
-	tp->coalesce_config.rate_sample_jiffies =
-		ecoal->rate_sample_interval * HZ;
-
-	tp->coalesce_config.rx_coalesce_ticks_low =
-		ecoal->rx_coalesce_usecs_low;
-	tp->coalesce_config.rx_max_coalesced_frames_low =
-		ecoal->rx_max_coalesced_frames_low;
-	tp->coalesce_config.tx_coalesce_ticks_low =
-		ecoal->tx_coalesce_usecs_low;
-	tp->coalesce_config.tx_max_coalesced_frames_low =
-		ecoal->tx_max_coalesced_frames_low;
-
-	tp->coalesce_config.rx_coalesce_ticks_high =
-		ecoal->rx_coalesce_usecs_high;
-	tp->coalesce_config.rx_max_coalesced_frames_high =
-		ecoal->rx_max_coalesced_frames_high;
-	tp->coalesce_config.tx_coalesce_ticks_high =
-		ecoal->tx_coalesce_usecs_high;
-	tp->coalesce_config.tx_max_coalesced_frames_high =
-		ecoal->tx_max_coalesced_frames_high;
-
-	tw32(HOSTCC_RXCOL_TICKS,
-	     tp->coalesce_config.rx_coalesce_ticks_def);
-	tw32(HOSTCC_RXMAX_FRAMES,
-	     tp->coalesce_config.rx_max_coalesced_frames_def);
-	tw32(HOSTCC_RXCOAL_TICK_INT,
-	     tp->coalesce_config.rx_coalesce_ticks_during_int_def);
-	tw32(HOSTCC_RXCOAL_MAXF_INT,
-	     tp->coalesce_config.rx_max_coalesced_frames_during_int_def);
-	tw32(HOSTCC_TXCOL_TICKS,
-	     tp->coalesce_config.tx_coalesce_ticks_def);
-	tw32(HOSTCC_TXMAX_FRAMES,
-	     tp->coalesce_config.tx_max_coalesced_frames_def);
-	tw32(HOSTCC_TXCOAL_TICK_INT,
-	     tp->coalesce_config.tx_coalesce_ticks_during_int_def);
-	tw32(HOSTCC_TXCOAL_MAXF_INT,
-	     tp->coalesce_config.tx_max_coalesced_frames_during_int_def);
-	tw32(HOSTCC_STAT_COAL_TICKS,
-	     tp->coalesce_config.stats_coalesce_ticks_def);
-
-	spin_unlock_irq(&tp->lock);
-
-	return 0;
-}
-
 static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
 {
 	struct tg3 *tp = dev->priv;
@@ -4708,8 +5195,8 @@
 		cmd.phy_address = PHY_ADDR;
 		cmd.transceiver = 0;
 		cmd.autoneg = tp->link_config.autoneg;
-		cmd.maxtxpkt = tp->coalesce_config.tx_max_coalesced_frames_def;
-		cmd.maxrxpkt = tp->coalesce_config.rx_max_coalesced_frames_def;
+		cmd.maxtxpkt = 0;
+		cmd.maxrxpkt = 0;
 		if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
 			return -EFAULT;
 		return 0;
@@ -4750,6 +5237,7 @@
 		}
 
 		spin_lock_irq(&tp->lock);
+		spin_lock(&tp->tx_lock);
 
 		tp->link_config.autoneg = cmd.autoneg;
 		if (cmd.autoneg == AUTONEG_ENABLE) {
@@ -4761,23 +5249,8 @@
 			tp->link_config.duplex = cmd.duplex;
 		}
 
-		if (cmd.maxtxpkt || cmd.maxrxpkt) {
-			tp->coalesce_config.tx_max_coalesced_frames_def =
-				tp->coalesce_config.tx_max_coalesced_frames =
-				cmd.maxtxpkt;
-			tp->coalesce_config.rx_max_coalesced_frames_def =
-				tp->coalesce_config.rx_max_coalesced_frames =
-				cmd.maxrxpkt;
-
-			/* Coalescing config bits can be updated without
-			 * a full chip reset.
-			 */
-			tw32(HOSTCC_TXMAX_FRAMES,
-			     tp->coalesce_config.tx_max_coalesced_frames);
-			tw32(HOSTCC_RXMAX_FRAMES,
-			     tp->coalesce_config.rx_max_coalesced_frames);
-		}
 		tg3_setup_phy(tp);
+		spin_unlock(&tp->tx_lock);
 		spin_unlock_irq(&tp->lock);
 
 		return 0;
@@ -4826,6 +5299,11 @@
 			return -EFAULT;
 		if (wol.wolopts & ~WAKE_MAGIC)
 			return -EINVAL;
+		if ((wol.wolopts & WAKE_MAGIC) &&
+		    tp->phy_id == PHY_ID_SERDES &&
+		    !(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP))
+			return -EINVAL;
+
 		spin_lock_irq(&tp->lock);
 		if (wol.wolopts & WAKE_MAGIC)
 			tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
@@ -4873,22 +5351,6 @@
 			return -EFAULT;
 		return 0;
 	}
-	case ETHTOOL_GCOALESCE: {
-		struct ethtool_coalesce ecoal = { ETHTOOL_GCOALESCE };
-
-		tg3_to_ethtool_coal(tp, &ecoal);
-		if (copy_to_user(useraddr, &ecoal, sizeof(ecoal)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SCOALESCE: {
-		struct ethtool_coalesce ecoal;
-
-		if (copy_from_user(&ecoal, useraddr, sizeof(ecoal)))
-			return -EINVAL;
-
-		return tg3_from_ethtool_coal(tp, &ecoal);
-	}
 	case ETHTOOL_GRINGPARAM: {
 		struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM };
 
@@ -4928,6 +5390,7 @@
 			return -EINVAL;
 
 		spin_lock_irq(&tp->lock);
+		spin_lock(&tp->tx_lock);
 
 		tp->rx_pending = ering.rx_pending;
 #if TG3_MINI_RING_WORKS
@@ -4940,6 +5403,7 @@
 		tg3_init_rings(tp);
 		tg3_init_hw(tp);
 		netif_wake_queue(tp->dev);
+		spin_unlock(&tp->tx_lock);
 		spin_unlock_irq(&tp->lock);
 
 		return 0;
@@ -4964,6 +5428,7 @@
 			return -EFAULT;
 
 		spin_lock_irq(&tp->lock);
+		spin_lock(&tp->tx_lock);
 		if (epause.autoneg)
 			tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
 		else
@@ -4979,6 +5444,7 @@
 		tg3_halt(tp);
 		tg3_init_rings(tp);
 		tg3_init_hw(tp);
+		spin_unlock(&tp->tx_lock);
 		spin_unlock_irq(&tp->lock);
 
 		return 0;
@@ -5116,7 +5582,14 @@
 	struct tg3 *tp = dev->priv;
 
 	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
+
 	tp->vlgrp = grp;
+
+	/* Update RX_MODE_KEEP_VLAN_TAG bit in RX_MODE register. */
+	__tg3_set_rx_mode(dev);
+
+	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 }
 
@@ -5125,8 +5598,10 @@
 	struct tg3 *tp = dev->priv;
 
 	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
 	if (tp->vlgrp)
 		tp->vlgrp->vlan_devices[vid] = NULL;
+	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 }
 #endif
@@ -5148,6 +5623,7 @@
 	/* Enable seeprom accesses. */
 	tw32(GRC_LOCAL_CTRL,
 	     tr32(GRC_LOCAL_CTRL) | GRC_LCLCTRL_AUTO_SEEPROM);
+	tr32(GRC_LOCAL_CTRL);
 	udelay(100);
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
@@ -5355,12 +5831,17 @@
 			eeprom_led_mode = led_mode_auto;
 			break;
 		};
+		if ((tp->pci_chip_rev_id == CHIPREV_ID_5703_A1 ||
+		     tp->pci_chip_rev_id == CHIPREV_ID_5703_A2) &&
+		    (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP))
+			tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
+
+		if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE)
+			tp->tg3_flags |= TG3_FLAG_ENABLE_ASF;
+		if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)
+			tp->tg3_flags |= TG3_FLAG_SERDES_WOL_CAP;
 	}
 
-	err = tg3_phy_reset(tp, 0);
-	if (err)
-		return err;
-
 	/* Now read the physical PHY_ID from the chip and verify
 	 * that it is sane.  If it doesn't look good, we fall back
 	 * to either the hard-coded table based PHY_ID and failing
@@ -5390,30 +5871,24 @@
 		}
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
-		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
-		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
-		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa);
-	}
+	err = tg3_phy_reset(tp, 1);
+	if (err)
+		return err;
 
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
-	    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
-		tp->tg3_flags |= TG3_FLAG_PHY_RESET_ON_INIT;
-
-	if (tp->tg3_flags & TG3_FLAG_PHY_RESET_ON_INIT) {
+	    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) {
 		u32 mii_tg3_ctrl;
-
-		err = tg3_phy_reset(tp, 1);
-		if (err)
-			return err;
-
-		/* These chips, when reset, only advertise 10Mb capabilities.
-		 * Fix that.
+		
+		/* These chips, when reset, only advertise 10Mb
+		 * capabilities.  Fix that.
 		 */
 		err  = tg3_writephy(tp, MII_ADVERTISE,
 				    (ADVERTISE_CSMA |
-				     ADVERTISE_10HALF | ADVERTISE_10FULL |
-				     ADVERTISE_100HALF | ADVERTISE_100FULL));
+				     ADVERTISE_PAUSE_CAP |
+				     ADVERTISE_10HALF |
+				     ADVERTISE_10FULL |
+				     ADVERTISE_100HALF |
+				     ADVERTISE_100FULL));
 		mii_tg3_ctrl = (MII_TG3_CTRL_ADV_1000_HALF |
 				MII_TG3_CTRL_ADV_1000_FULL |
 				MII_TG3_CTRL_AS_MASTER |
@@ -5426,6 +5901,22 @@
 				    (BMCR_ANRESTART | BMCR_ANENABLE));
 	}
 
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
+		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
+		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa);
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+		tg3_writephy(tp, 0x1c, 0x8d68);
+		tg3_writephy(tp, 0x1c, 0x8d68);
+	}
+
+	/* Enable Ethernet@WireSpeed */
+	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007);
+	tg3_readphy(tp, MII_TG3_AUX_CTRL, &val);
+	tg3_writephy(tp, MII_TG3_AUX_CTRL, (val | (1 << 15) | (1 << 4)));
+
 	if (!err && ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)) {
 		err = tg3_init_5401phy_dsp(tp);
 	}
@@ -5523,6 +6014,20 @@
 	u16 pci_cmd;
 	int err;
 
+	/* If we have an AMD 762 or Intel ICH/ICH0 chipset, write
+	 * reordering to the mailbox registers done by the host
+	 * controller can cause major troubles.  We read back from
+	 * every mailbox register write to force the writes to be
+	 * posted to the chip in order.
+	 */
+	if (pci_find_device(PCI_VENDOR_ID_INTEL,
+			    PCI_DEVICE_ID_INTEL_82801AA_8, NULL) ||
+	    pci_find_device(PCI_VENDOR_ID_INTEL,
+			    PCI_DEVICE_ID_INTEL_82801AB_8, NULL) ||
+	    pci_find_device(PCI_VENDOR_ID_AMD,
+			    PCI_DEVICE_ID_AMD_FE_GATE_700C, NULL))
+		tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER;
+
 	/* Force memory write invalidate off.  If we leave it on,
 	 * then on 5700_BX chips we have to enable a workaround.
 	 * The workaround is to set the TG3PCI_DMA_RW_CTRL boundry
@@ -5534,12 +6039,24 @@
 	pci_cmd &= ~PCI_COMMAND_INVALIDATE;
 	pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
 
+	/* It is absolutely critical that TG3PCI_MISC_HOST_CTRL
+	 * has the register indirect write enable bit set before
+	 * we try to access any of the MMIO registers.  It is also
+	 * critical that the PCI-X hw workaround situation is decided
+	 * before that as well.
+	 */
 	pci_read_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
 			      &misc_ctrl_reg);
 
 	tp->pci_chip_rev_id = (misc_ctrl_reg >>
 			       MISC_HOST_CTRL_CHIPREV_SHIFT);
 
+	/* Initialize misc host control in PCI block. */
+	tp->misc_host_ctrl |= (misc_ctrl_reg &
+			       MISC_HOST_CTRL_CHIPREV);
+	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+			       tp->misc_host_ctrl);
+
 	pci_read_config_dword(tp->pdev, TG3PCI_CACHELINESZ,
 			      &cacheline_sz_reg);
 
@@ -5641,62 +6158,29 @@
 		tp->tg3_flags |= TG3_FLAG_WOL_SPEED_100MB;
 	}
 
-	/* Only 5701 and later support tagged irq status mode. */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) {
-		tp->tg3_flags |= TG3_FLAG_TAGGED_IRQ_STATUS;
-		tp->misc_host_ctrl |= MISC_HOST_CTRL_TAGGED_STATUS;
-
-		/* ??? Due to a glitch Broadcom's driver ALWAYS sets
-		 * ??? these bits in coalesce_mode.  Because MM_GetConfig
-		 * ??? always sets pDevice->UseTaggedStatus correctly
-		 * ??? the following test at tigon3.c:LM_GetAdapterInfo()
-		 * ???
-		 * ???   pDevice->UseTaggedStatus &&
-		 * ???   (pDevice->ChipRevId == T3_CHIP_ID_5700_C0 ||
-		 * ???    T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5700_AX ||
-		 * ???    T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5700_BX)
-		 * ???
-		 * ??? will never pass and thus pDevice->CoalesceMode will never
-		 * ??? get set to zero.  For now I'll mirror what I believe is
-		 * ??? the intention of their driver.
-		 * ???
-		 * ??? Update: This is fixed in Broadcom's 2.2.3 and later
-		 * ???         drivers.  All the current 2.0.x drivers still
-		 * ???         have the bug.
-		 */
-		tp->coalesce_mode = (HOSTCC_MODE_CLRTICK_RXBD |
-				     HOSTCC_MODE_CLRTICK_TXBD);
-	} else {
-		tp->coalesce_mode = 0;
-
-		/* If not using tagged status, set the *_during_int
-		 * coalesce default config values to zero.
-		 */
-		tp->coalesce_config.rx_coalesce_ticks_during_int_def = 0;
-		tp->coalesce_config.rx_max_coalesced_frames_during_int_def = 0;
-		tp->coalesce_config.tx_coalesce_ticks_during_int_def = 0;
-		tp->coalesce_config.tx_max_coalesced_frames_during_int_def = 0;
-	}
+	/* Only 5701 and later support tagged irq status mode.
+	 *
+	 * However, since we are using NAPI avoid tagged irq status
+	 * because the interrupt condition is more difficult to
+	 * fully clear in that mode.
+	 */
+	tp->coalesce_mode = 0;
 
 	if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_AX &&
 	    GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX)
 		tp->coalesce_mode |= HOSTCC_MODE_32BYTE;
 
-	/* Initialize misc host control in PCI block. */
-	tp->misc_host_ctrl |= (misc_ctrl_reg &
-			       MISC_HOST_CTRL_CHIPREV);
-	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
-			       tp->misc_host_ctrl);
-
 	/* Initialize MAC MI mode, polling disabled. */
 	tw32(MAC_MI_MODE, tp->mi_mode);
+	tr32(MAC_MI_MODE);
 	udelay(40);
 
 	/* Initialize data/descriptor byte/word swapping. */
 	tw32(GRC_MODE, tp->grc_mode);
 
-	/* Clear these out for sanity. */
-	tw32(TG3PCI_CLOCK_CTRL, 0);
+	tg3_switch_clocks(tp);
+
+	/* Clear this out for sanity. */
 	tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
 
 	pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
@@ -5744,9 +6228,16 @@
 	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5702FE &&
 	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703 &&
 	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703S &&
+	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5704 &&
 	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_AC91002A1)
 		return -ENODEV;
 
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
+	    grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5704CIOBE) {
+		tp->tg3_flags |= TG3_FLAG_SPLIT_MODE;
+		tp->split_mode_max_reqs = SPLIT_MODE_5704_MAX_REQ;
+	}
+
 	/* ROFL, you should see Broadcom's driver code implementing
 	 * this, stuff like "if (a || b)" where a and b are always
 	 * mutually exclusive.  DaveM finds like 6 bugs today, hello!
@@ -5825,13 +6316,23 @@
 	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0)
 		tp->rx_offset = 0;
 
+	/* By default, disable wake-on-lan.  User can change this
+	 * using ETHTOOL_SWOL.
+	 */
+	tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
+
 	return err;
 }
 
 static int __devinit tg3_get_device_address(struct tg3 *tp)
 {
 	struct net_device *dev = tp->dev;
-	u32 hi, lo;
+	u32 hi, lo, mac_offset;
+
+	if (PCI_FUNC(tp->pdev->devfn) == 0)
+		mac_offset = 0x7c;
+	else
+		mac_offset = 0xcc;
 
 	/* First try to get it from MAC address mailbox. */
 	tg3_read_mem(tp, NIC_SRAM_MAC_ADDR_HIGH_MBOX, &hi);
@@ -5846,8 +6347,8 @@
 		dev->dev_addr[5] = (lo >>  0) & 0xff;
 	}
 	/* Next, try NVRAM. */
-	else if (!tg3_nvram_read(tp, 0x7c, &hi) &&
-		 !tg3_nvram_read(tp, 0x80, &lo)) {
+	else if (!tg3_nvram_read(tp, mac_offset + 0, &hi) &&
+		 !tg3_nvram_read(tp, mac_offset + 4, &lo)) {
 		dev->dev_addr[0] = ((hi >> 16) & 0xff);
 		dev->dev_addr[1] = ((hi >> 24) & 0xff);
 		dev->dev_addr[2] = ((lo >>  0) & 0xff);
@@ -5898,11 +6399,21 @@
 	if (to_device) {
 		test_desc.cqid_sqid = (13 << 8) | 2;
 		tw32(RDMAC_MODE, RDMAC_MODE_RESET);
+		tr32(RDMAC_MODE);
+		udelay(40);
+
 		tw32(RDMAC_MODE, RDMAC_MODE_ENABLE);
+		tr32(RDMAC_MODE);
+		udelay(40);
 	} else {
 		test_desc.cqid_sqid = (16 << 8) | 7;
 		tw32(WDMAC_MODE, WDMAC_MODE_RESET);
+		tr32(WDMAC_MODE);
+		udelay(40);
+
 		tw32(WDMAC_MODE, WDMAC_MODE_ENABLE);
+		tr32(WDMAC_MODE);
+		udelay(40);
 	}
 	test_desc.flags = 0x00000004;
 
@@ -5965,16 +6476,26 @@
 			(0x7 << DMA_RWCTRL_READ_WATER_SHIFT) |
 			(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
 	} else {
-		tp->dma_rwctrl =
-			(0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
-			(0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
-			(0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
-			(0x3 << DMA_RWCTRL_READ_WATER_SHIFT) |
-			(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+			tp->dma_rwctrl =
+				(0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
+				(0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
+				(0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
+				(0x7 << DMA_RWCTRL_READ_WATER_SHIFT) |
+				(0x00 << DMA_RWCTRL_MIN_DMA_SHIFT);
+		else
+			tp->dma_rwctrl =
+				(0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
+				(0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
+				(0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
+				(0x3 << DMA_RWCTRL_READ_WATER_SHIFT) |
+				(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
 
 		/* Wheee, some more chip bugs... */
 		if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1 ||
-		    tp->pci_chip_rev_id == CHIPREV_ID_5703_A2)
+		    tp->pci_chip_rev_id == CHIPREV_ID_5703_A2 ||
+		    tp->pci_chip_rev_id == CHIPREV_ID_5703_A3 ||
+		    tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
 			tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
 	}
 
@@ -6121,61 +6642,6 @@
 	tp->link_config.orig_autoneg = AUTONEG_INVALID;
 }
 
-static void __devinit tg3_init_coalesce_config(struct tg3 *tp)
-{
-	tp->coalesce_config.rx_coalesce_ticks_def = DEFAULT_RXCOL_TICKS;
-	tp->coalesce_config.rx_max_coalesced_frames_def = DEFAULT_RXMAX_FRAMES;
-	tp->coalesce_config.rx_coalesce_ticks_during_int_def =
-		DEFAULT_RXCOAL_TICK_INT;
-	tp->coalesce_config.rx_max_coalesced_frames_during_int_def =
-		DEFAULT_RXCOAL_MAXF_INT;
-	tp->coalesce_config.tx_coalesce_ticks_def = DEFAULT_TXCOL_TICKS;
-	tp->coalesce_config.tx_max_coalesced_frames_def = DEFAULT_TXMAX_FRAMES;
-	tp->coalesce_config.tx_coalesce_ticks_during_int_def =
-		DEFAULT_TXCOAL_TICK_INT;
-	tp->coalesce_config.tx_max_coalesced_frames_during_int_def =
-		DEFAULT_TXCOAL_MAXF_INT;
-	tp->coalesce_config.stats_coalesce_ticks_def =
-		DEFAULT_STAT_COAL_TICKS;
-
-	tp->coalesce_config.rx_coalesce_ticks_low =
-		LOW_RXCOL_TICKS;
-	tp->coalesce_config.rx_max_coalesced_frames_low =
-		LOW_RXMAX_FRAMES;
-	tp->coalesce_config.tx_coalesce_ticks_low =
-		LOW_TXCOL_TICKS;
-	tp->coalesce_config.tx_max_coalesced_frames_low =
-		LOW_TXMAX_FRAMES;
-
-	tp->coalesce_config.rx_coalesce_ticks_high =
-		HIGH_RXCOL_TICKS;
-	tp->coalesce_config.rx_max_coalesced_frames_high =
-		HIGH_RXMAX_FRAMES;
-	tp->coalesce_config.tx_coalesce_ticks_high =
-		HIGH_TXCOL_TICKS;
-	tp->coalesce_config.tx_max_coalesced_frames_high =
-		HIGH_TXMAX_FRAMES;
-
-	/* Active == default */
-	tp->coalesce_config.rx_coalesce_ticks =
-		tp->coalesce_config.rx_coalesce_ticks_def;
-	tp->coalesce_config.rx_max_coalesced_frames =
-		tp->coalesce_config.rx_max_coalesced_frames_def;
-	tp->coalesce_config.tx_coalesce_ticks =
-		tp->coalesce_config.tx_coalesce_ticks_def;
-	tp->coalesce_config.tx_max_coalesced_frames =
-		tp->coalesce_config.tx_max_coalesced_frames_def;
-	tp->coalesce_config.stats_coalesce_ticks =
-		tp->coalesce_config.stats_coalesce_ticks_def;
-
-	tp->coalesce_config.rate_sample_jiffies = (1 * HZ);
-	tp->coalesce_config.pkt_rate_low = 22000;
-	tp->coalesce_config.pkt_rate_high = 61000;
-
-	tp->tg3_flags |= TG3_FLAG_ADAPTIVE_RX;
-	tp->tg3_flags &= ~(TG3_FLAG_ADAPTIVE_TX);
-}
-
 static void __devinit tg3_init_bufmgr_config(struct tg3 *tp)
 {
 	tp->bufmgr_config.mbuf_read_dma_low_water =
@@ -6204,6 +6670,7 @@
 	case PHY_ID_BCM5411:	return "5411";
 	case PHY_ID_BCM5701:	return "5701";
 	case PHY_ID_BCM5703:	return "5703";
+	case PHY_ID_BCM5704:	return "5704";
 	case PHY_ID_BCM8002:	return "8002";
 	case PHY_ID_SERDES:	return "serdes";
 	default:		return "unknown";
@@ -6285,6 +6752,9 @@
 	dev->vlan_rx_register = tg3_vlan_rx_register;
 	dev->vlan_rx_kill_vid = tg3_vlan_rx_kill_vid;
 #endif
+#if TG3_DO_TSO != 0
+	dev->features |= NETIF_F_TSO;
+#endif
 
 	tp = dev->priv;
 	tp->pdev = pdev;
@@ -6321,6 +6791,7 @@
 	tp->grc_mode |= GRC_MODE_BSWAP_NONFRM_DATA;
 #endif
 	spin_lock_init(&tp->lock);
+	spin_lock_init(&tp->tx_lock);
 	spin_lock_init(&tp->indirect_lock);
 
 	tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len);
@@ -6333,8 +6804,6 @@
 
 	tg3_init_link_config(tp);
 
-	tg3_init_coalesce_config(tp);
-
 	tg3_init_bufmgr_config(tp);
 
 	tp->rx_pending = TG3_DEF_RX_RING_PENDING;
@@ -6351,6 +6820,8 @@
 	dev->set_mac_address = tg3_set_mac_addr;
 	dev->do_ioctl = tg3_ioctl;
 	dev->tx_timeout = tg3_tx_timeout;
+	dev->poll = tg3_poll;
+	dev->weight = 64;
 	dev->watchdog_timeo = TG3_TX_TIMEOUT;
 	dev->change_mtu = tg3_change_mtu;
 	dev->irq = pdev->irq;
@@ -6456,22 +6927,28 @@
 		return 0;
 
 	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
 	tg3_disable_ints(tp);
+	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
 	netif_device_detach(dev);
 
 	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
 	tg3_halt(tp);
+	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
 	err = tg3_set_power_state(tp, state);
 	if (err) {
 		spin_lock_irq(&tp->lock);
+		spin_lock(&tp->tx_lock);
 
 		tg3_init_rings(tp);
 		tg3_init_hw(tp);
 
+		spin_unlock(&tp->tx_lock);
 		spin_unlock_irq(&tp->lock);
 
 		netif_device_attach(dev);
@@ -6496,23 +6973,25 @@
 	netif_device_attach(dev);
 
 	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
 
 	tg3_init_rings(tp);
 	tg3_init_hw(tp);
 	tg3_enable_ints(tp);
 
+	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
 	return 0;
 }
 
 static struct pci_driver tg3_driver = {
-	name:		DRV_MODULE_NAME,
-	id_table:	tg3_pci_tbl,
-	probe:		tg3_init_one,
-	remove:		__devexit_p(tg3_remove_one),
-	suspend:	tg3_suspend,
-	resume:		tg3_resume
+	.name		= DRV_MODULE_NAME,
+	.id_table	= tg3_pci_tbl,
+	.probe		= tg3_init_one,
+	.remove		= __devexit_p(tg3_remove_one),
+	.suspend	= tg3_suspend,
+	.resume		= tg3_resume
 };
 
 static int __init tg3_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/tg3.h linux-2.4.20/drivers/net/tg3.h
--- linux-2.4.19/drivers/net/tg3.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/tg3.h	2002-10-29 11:18:48.000000000 +0000
@@ -58,6 +58,11 @@
 #define TG3PCI_MAX_LAT			0x0000003f
 #define TG3PCI_X_CAPS			0x00000040
 #define  PCIX_CAPS_RELAXED_ORDERING	 0x00020000
+#define  PCIX_CAPS_SPLIT_MASK		 0x00700000
+#define  PCIX_CAPS_SPLIT_SHIFT		 20
+#define  PCIX_CAPS_BURST_MASK		 0x000c0000
+#define  PCIX_CAPS_BURST_SHIFT		 18
+#define  PCIX_CAPS_MAX_BURST_5704	 2
 #define TG3PCI_PM_CAP_PTR		0x00000041
 #define TG3PCI_X_COMMAND		0x00000042
 #define TG3PCI_X_STATUS			0x00000044
@@ -109,10 +114,13 @@
 #define  CHIPREV_ID_5703_A0		 0x1000
 #define  CHIPREV_ID_5703_A1		 0x1001
 #define  CHIPREV_ID_5703_A2		 0x1002
+#define  CHIPREV_ID_5703_A3		 0x1003
+#define  CHIPREV_ID_5704_A0		 0x2000
 #define  GET_ASIC_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 12)
 #define   ASIC_REV_5700			 0x07
 #define   ASIC_REV_5701			 0x00
 #define   ASIC_REV_5703			 0x01
+#define   ASIC_REV_5704			 0x02
 #define  GET_CHIP_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 8)
 #define   CHIPREV_5700_AX		 0x70
 #define   CHIPREV_5700_BX		 0x71
@@ -165,6 +173,7 @@
 #define  PCISTATE_ROM_ENABLE		 0x00000020
 #define  PCISTATE_ROM_RETRY_ENABLE	 0x00000040
 #define  PCISTATE_FLAT_VIEW		 0x00000100
+#define  PCISTATE_RETRY_SAME_DMA	 0x00002000
 #define TG3PCI_CLOCK_CTRL		0x00000074
 #define  CLOCK_CTRL_CORECLK_DISABLE	 0x00000200
 #define  CLOCK_CTRL_RXCLK_DISABLE	 0x00000400
@@ -843,6 +852,8 @@
 #define  RDMAC_MODE_FIFOURUN_ENAB	 0x00000080
 #define  RDMAC_MODE_FIFOOREAD_ENAB	 0x00000100
 #define  RDMAC_MODE_LNGREAD_ENAB	 0x00000200
+#define  RDMAC_MODE_SPLIT_ENABLE	 0x00000800
+#define  RDMAC_MODE_SPLIT_RESET		 0x00001000
 #define RDMAC_STATUS			0x00004804
 #define  RDMAC_STATUS_TGTABORT		 0x00000004
 #define  RDMAC_STATUS_MSTABORT		 0x00000008
@@ -1126,6 +1137,8 @@
 #define  GRC_MISC_CFG_BOARD_ID_5702FE	0x00004000
 #define  GRC_MISC_CFG_BOARD_ID_5703	0x00000000
 #define  GRC_MISC_CFG_BOARD_ID_5703S	0x00002000
+#define  GRC_MISC_CFG_BOARD_ID_5704	0x00000000
+#define  GRC_MISC_CFG_BOARD_ID_5704CIOBE 0x00004000
 #define  GRC_MISC_CFG_BOARD_ID_AC91002A1 0x00018000
 #define GRC_LOCAL_CTRL			0x00006808
 #define  GRC_LCLCTRL_INT_ACTIVE		0x00000001
@@ -1248,14 +1261,20 @@
 #define  NIC_SRAM_DATA_SIG_MAGIC	 0x4b657654 /* ascii for 'KevT' */
 
 #define NIC_SRAM_DATA_CFG			0x00000b58
-#define  NIC_SRAM_DATA_CFG_PHY_TYPE_MASK	 0x0000000c
-#define  NIC_SRAM_DATA_CFG_PHY_TYPE_UNKNOWN	 0x00000000
-#define  NIC_SRAM_DATA_CFG_PHY_TYPE_COPPER	 0x00000004
-#define  NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER	 0x00000008
-#define  NIC_SRAM_DATA_CFG_LED_MODE_MASK	 0x00000030
+#define  NIC_SRAM_DATA_CFG_LED_MODE_MASK	 0x0000000c
 #define  NIC_SRAM_DATA_CFG_LED_MODE_UNKNOWN	 0x00000000
-#define  NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD	 0x00000010
-#define  NIC_SRAM_DATA_CFG_LED_LINK_SPD		 0x00000020
+#define  NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD	 0x00000004
+#define  NIC_SRAM_DATA_CFG_LED_OPEN_DRAIN	 0x00000004
+#define  NIC_SRAM_DATA_CFG_LED_LINK_SPD		 0x00000008
+#define  NIC_SRAM_DATA_CFG_LED_OUTPUT		 0x00000008
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_MASK	 0x00000030
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_UNKNOWN	 0x00000000
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_COPPER	 0x00000010
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER	 0x00000020
+#define  NIC_SRAM_DATA_CFG_WOL_ENABLE		 0x00000040
+#define  NIC_SRAM_DATA_CFG_ASF_ENABLE		 0x00000080
+#define  NIC_SRAM_DATA_CFG_EEPROM_WP		 0x00000100
+#define  NIC_SRAM_DATA_CFG_FIBER_WOL		 0x00004000
 
 #define NIC_SRAM_DATA_PHY_ID		0x00000b74
 #define  NIC_SRAM_DATA_PHY_ID1_MASK	 0xffff0000
@@ -1292,7 +1311,8 @@
 #define NIC_SRAM_RX_BUFFER_DESC		0x00006000 /* 256 entries */
 #define NIC_SRAM_RX_JUMBO_BUFFER_DESC	0x00007000 /* 256 entries */
 #define NIC_SRAM_MBUF_POOL_BASE		0x00008000
-#define  NIC_SRAM_MBUF_POOL_SIZE	 0x00018000
+#define  NIC_SRAM_MBUF_POOL_SIZE96	 0x00018000
+#define  NIC_SRAM_MBUF_POOL_SIZE64	 0x00010000
 
 /* Currently this is fixed. */
 #define PHY_ADDR		0x01
@@ -1410,6 +1430,7 @@
 
 	u32				vlan_tag;
 #define TXD_VLAN_TAG_SHIFT		0
+#define TXD_MSS_SHIFT			16
 };
 
 #define TXD_ADDR			0x00UL /* 64-bit */
@@ -1660,6 +1681,12 @@
 	DECLARE_PCI_UNMAP_ADDR(mapping)
 };
 
+struct tx_ring_info {
+	struct sk_buff			*skb;
+	DECLARE_PCI_UNMAP_ADDR(mapping)
+	u32				prev_vlan_tag;
+};
+
 struct tg3_config_info {
 	u32				flags;
 };
@@ -1687,45 +1714,6 @@
 	u8				orig_autoneg;
 };
 
-struct tg3_coalesce_config {
-	/* Current settings. */
-	u32		rx_coalesce_ticks;
-	u32		rx_max_coalesced_frames;
-	u32		rx_coalesce_ticks_during_int;
-	u32		rx_max_coalesced_frames_during_int;
-	u32		tx_coalesce_ticks;
-	u32		tx_max_coalesced_frames;
-	u32		tx_coalesce_ticks_during_int;
-	u32		tx_max_coalesced_frames_during_int;
-	u32		stats_coalesce_ticks;
-
-	/* Default settings. */
-	u32		rx_coalesce_ticks_def;
-	u32		rx_max_coalesced_frames_def;
-	u32		rx_coalesce_ticks_during_int_def;
-	u32		rx_max_coalesced_frames_during_int_def;
-	u32		tx_coalesce_ticks_def;
-	u32		tx_max_coalesced_frames_def;
-	u32		tx_coalesce_ticks_during_int_def;
-	u32		tx_max_coalesced_frames_during_int_def;
-	u32		stats_coalesce_ticks_def;
-
-	/* Adaptive RX/TX coalescing parameters. */
-	u32		rate_sample_jiffies;
-	u32		pkt_rate_low;
-	u32		pkt_rate_high;
-
-	u32		rx_coalesce_ticks_low;
-	u32		rx_max_coalesced_frames_low;
-	u32		tx_coalesce_ticks_low;
-	u32		tx_max_coalesced_frames_low;
-
-	u32		rx_coalesce_ticks_high;
-	u32		rx_max_coalesced_frames_high;
-	u32		tx_coalesce_ticks_high;
-	u32		tx_max_coalesced_frames_high;
-};
-
 struct tg3_bufmgr_config {
 	u32		mbuf_read_dma_low_water;
 	u32		mbuf_mac_rx_low_water;
@@ -1740,7 +1728,21 @@
 };
 
 struct tg3 {
+	/* SMP locking strategy:
+	 *
+	 * lock: Held during all operations except TX packet
+	 *       processing.
+	 *
+	 * tx_lock: Held during tg3_start_xmit{,_4gbug} and tg3_tx
+	 *
+	 * If you want to shut up all asynchronous processing you must
+	 * acquire both locks, 'lock' taken before 'tx_lock'.  IRQs must
+	 * be disabled to take 'lock' but only softirq disabling is
+	 * necessary for acquisition of 'tx_lock'.
+	 */
 	spinlock_t			lock;
+	spinlock_t			tx_lock;
+
 	u32				tx_prod;
 	u32				tx_cons;
 	u32				rx_rcb_ptr;
@@ -1755,11 +1757,6 @@
 	struct net_device_stats		net_stats_prev;
 	unsigned long			phy_crc_errors;
 
-	/* Adaptive coalescing engine. */
-	unsigned long			last_rate_sample;
-	u32				last_rx_count;
-	u32				last_tx_count;
-
 	u32				rx_offset;
 	u32				tg3_flags;
 #define TG3_FLAG_HOST_TXDS		0x00000001
@@ -1767,14 +1764,13 @@
 #define TG3_FLAG_RX_CHECKSUMS		0x00000004
 #define TG3_FLAG_USE_LINKCHG_REG	0x00000008
 #define TG3_FLAG_USE_MI_INTERRUPT	0x00000010
-#define TG3_FLAG_ADAPTIVE_RX		0x00000020
-#define TG3_FLAG_ADAPTIVE_TX		0x00000040
+#define TG3_FLAG_ENABLE_ASF		0x00000020
 #define TG3_FLAG_POLL_SERDES		0x00000080
-#define TG3_FLAG_PHY_RESET_ON_INIT	0x00000100
+#define TG3_FLAG_MBOX_WRITE_REORDER	0x00000100
 #define TG3_FLAG_PCIX_TARGET_HWBUG	0x00000200
-#define TG3_FLAG_TAGGED_IRQ_STATUS	0x00000400
-#define TG3_FLAG_WOL_SPEED_100MB	0x00000800
-#define TG3_FLAG_WOL_ENABLE		0x00001000
+#define TG3_FLAG_WOL_SPEED_100MB	0x00000400
+#define TG3_FLAG_WOL_ENABLE		0x00000800
+#define TG3_FLAG_EEPROM_WRITE_PROT	0x00001000
 #define TG3_FLAG_NVRAM			0x00002000
 #define TG3_FLAG_NVRAM_BUFFERED		0x00004000
 #define TG3_FLAG_RX_PAUSE		0x00008000
@@ -1784,7 +1780,7 @@
 #define TG3_FLAG_PCI_32BIT		0x00080000
 #define TG3_FLAG_NO_TX_PSEUDO_CSUM	0x00100000
 #define TG3_FLAG_NO_RX_PSEUDO_CSUM	0x00200000
-#define TG3_FLAG_AUTONEG_DISABLE	0x00400000
+#define TG3_FLAG_SERDES_WOL_CAP		0x00400000
 #define TG3_FLAG_JUMBO_ENABLE		0x00800000
 #define TG3_FLAG_10_100_ONLY		0x01000000
 #define TG3_FLAG_PAUSE_AUTONEG		0x02000000
@@ -1792,17 +1788,22 @@
 #define TG3_FLAG_PAUSE_TX		0x08000000
 #define TG3_FLAG_BROKEN_CHECKSUMS	0x10000000
 #define TG3_FLAG_GOT_SERDES_FLOWCTL	0x20000000
+#define TG3_FLAG_SPLIT_MODE		0x40000000
 #define TG3_FLAG_INIT_COMPLETE		0x80000000
 
 	u32				msg_enable;
 
+	u32				split_mode_max_reqs;
+#define SPLIT_MODE_5704_MAX_REQ		3
+
 	struct timer_list		timer;
 	u16				timer_counter;
 	u16				timer_multiplier;
 	u32				timer_offset;
+	u16				asf_counter;
+	u16				asf_multiplier;
 
 	struct tg3_link_config		link_config;
-	struct tg3_coalesce_config	coalesce_config;
 	struct tg3_bufmgr_config	bufmgr_config;
 
 	u32				rx_pending;
@@ -1841,6 +1842,7 @@
 #define PHY_ID_BCM5411			0x60008070
 #define PHY_ID_BCM5701			0x60008110
 #define PHY_ID_BCM5703			0x60008160
+#define PHY_ID_BCM5704			0x60008190
 #define PHY_ID_BCM8002			0x60010140
 #define PHY_ID_SERDES			0xfeedbee0
 #define PHY_ID_INVALID			0xffffffff
@@ -1860,7 +1862,7 @@
 #define KNOWN_PHY_ID(X)		\
 	((X) == PHY_ID_BCM5400 || (X) == PHY_ID_BCM5401 || \
 	 (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \
-	 (X) == PHY_ID_BCM5703 ||			   \
+	 (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \
 	 (X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES)
 
 	unsigned long			regs;
@@ -1887,7 +1889,7 @@
 
 	/* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */
 	struct tg3_tx_buffer_desc	*tx_ring;
-	struct ring_info		*tx_buffers;
+	struct tx_ring_info		*tx_buffers;
 	dma_addr_t			tx_desc_mapping;
 
 	struct tg3_hw_status		*hw_status;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/tokenring/3c359.c linux-2.4.20/drivers/net/tokenring/3c359.c
--- linux-2.4.19/drivers/net/tokenring/3c359.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/tokenring/3c359.c	2002-10-29 11:18:48.000000000 +0000
@@ -51,7 +51,6 @@
 #include <linux/timer.h>
 #include <linux/in.h>
 #include <linux/ioport.h>
-#include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/proc_fs.h>
 #include <linux/ptrace.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/tokenring/lanstreamer.c linux-2.4.20/drivers/net/tokenring/lanstreamer.c
--- linux-2.4.19/drivers/net/tokenring/lanstreamer.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/tokenring/lanstreamer.c	2002-10-29 11:18:40.000000000 +0000
@@ -65,6 +65,7 @@
  *  11/05/01 - Restructured the interrupt function, added delays, reduced the 
  *             the number of TX descriptors to 1, which together can prevent 
  *             the card from locking up the box - <yoder1@us.ibm.com>
+ *  09/27/02 - New PCI interface + bug fix. - <yoder1@us.ibm.com>
  *  
  *  To Do:
  *
@@ -136,7 +137,7 @@
  */
 
 static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan\n"
-                        "              v0.5.1 03/04/02 - Kent Yoder";
+                        "              v0.5.2 09/30/02 - Kent Yoder";
 
 static struct pci_device_id streamer_pci_tbl[] __initdata = {
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,},
@@ -250,6 +251,12 @@
   dev_streamer=streamer_priv;
 #endif
 #endif
+ 
+  if(pci_set_dma_mask(pdev, 0xFFFFFFFF)) {
+    printk(KERN_ERR "%s: No suitable PCI mapping available.\n", dev->name);
+    rc = -ENODEV;
+    goto err_out;
+  }
   
   if (pci_enable_device(pdev)) {
     printk(KERN_ERR "lanstreamer: unable to enable pci device\n");
@@ -481,9 +488,11 @@
 		data=((u8 *)skb->data)+sizeof(struct streamer_rx_desc);
 		rx_ring->forward=0;
 		rx_ring->status=0;
-		rx_ring->buffer=virt_to_bus(data);
+		rx_ring->buffer=cpu_to_le32(pci_map_single(streamer_priv->pci_dev, data, 
+							512, PCI_DMA_FROMDEVICE));
 		rx_ring->framelen_buflen=512; 
-		writel(virt_to_bus(rx_ring),streamer_mmio+RXBDA);
+		writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, rx_ring, 512, PCI_DMA_FROMDEVICE)),
+			streamer_mmio+RXBDA);
 	}
 
 #if STREAMER_DEBUG
@@ -499,6 +508,8 @@
 			printk(KERN_ERR
 			       "IBM PCI tokenring card not responding\n");
 			release_region(dev->base_addr, STREAMER_IO_SPACE);
+			if (skb)
+				dev_kfree_skb(skb);
 			return -1;
 		}
 	}
@@ -773,14 +784,19 @@
 
 		skb->dev = dev;
 
-		streamer_priv->streamer_rx_ring[i].forward = virt_to_bus(&streamer_priv->streamer_rx_ring[i + 1]);
+		streamer_priv->streamer_rx_ring[i].forward = 
+			cpu_to_le32(pci_map_single(streamer_priv->pci_dev, &streamer_priv->streamer_rx_ring[i + 1],
+					sizeof(struct streamer_rx_desc), PCI_DMA_FROMDEVICE));
 		streamer_priv->streamer_rx_ring[i].status = 0;
-		streamer_priv->streamer_rx_ring[i].buffer = virt_to_bus(skb->data);
+		streamer_priv->streamer_rx_ring[i].buffer = 
+			cpu_to_le32(pci_map_single(streamer_priv->pci_dev, skb->data,
+					      streamer_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE));
 		streamer_priv->streamer_rx_ring[i].framelen_buflen = streamer_priv->pkt_buf_sz;
 		streamer_priv->rx_ring_skb[i] = skb;
 	}
 	streamer_priv->streamer_rx_ring[STREAMER_RX_RING_SIZE - 1].forward =
-				virt_to_bus(&streamer_priv->streamer_rx_ring[0]);
+				cpu_to_le32(pci_map_single(streamer_priv->pci_dev, &streamer_priv->streamer_rx_ring[0],
+						sizeof(struct streamer_rx_desc), PCI_DMA_FROMDEVICE));
 
 	if (i == 0) {
 		printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled\n", dev->name);
@@ -790,8 +806,12 @@
 
 	streamer_priv->rx_ring_last_received = STREAMER_RX_RING_SIZE - 1;	/* last processed rx status */
 
-	writel(virt_to_bus(&streamer_priv->streamer_rx_ring[0]), streamer_mmio + RXBDA);
-	writel(virt_to_bus(&streamer_priv->streamer_rx_ring[STREAMER_RX_RING_SIZE - 1]), streamer_mmio + RXLBDA);
+	writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, &streamer_priv->streamer_rx_ring[0],
+				sizeof(struct streamer_rx_desc), PCI_DMA_TODEVICE)), 
+		streamer_mmio + RXBDA);
+	writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, &streamer_priv->streamer_rx_ring[STREAMER_RX_RING_SIZE - 1],
+				sizeof(struct streamer_rx_desc), PCI_DMA_TODEVICE)), 
+		streamer_mmio + RXLBDA);
 
 	/* set bus master interrupt event mask */
 	writew(MISR_RX_NOBUF | MISR_RX_EOF, streamer_mmio + MISR_MASK);
@@ -807,7 +827,10 @@
 
 	writew(~BMCTL_TX2_DIS, streamer_mmio + BMCTL_RUM);	/* Enables TX channel 2 */
 	for (i = 0; i < STREAMER_TX_RING_SIZE; i++) {
-		streamer_priv->streamer_tx_ring[i].forward = virt_to_bus(&streamer_priv->streamer_tx_ring[i + 1]);
+		streamer_priv->streamer_tx_ring[i].forward = cpu_to_le32(pci_map_single(streamer_priv->pci_dev, 
+										&streamer_priv->streamer_tx_ring[i + 1],
+										sizeof(struct streamer_tx_desc),
+										PCI_DMA_TODEVICE));
 		streamer_priv->streamer_tx_ring[i].status = 0;
 		streamer_priv->streamer_tx_ring[i].bufcnt_framelen = 0;
 		streamer_priv->streamer_tx_ring[i].buffer = 0;
@@ -817,7 +840,8 @@
 		streamer_priv->streamer_tx_ring[i].rsvd3 = 0;
 	}
 	streamer_priv->streamer_tx_ring[STREAMER_TX_RING_SIZE - 1].forward =
-					virt_to_bus(&streamer_priv->streamer_tx_ring[0]);
+					cpu_to_le32(pci_map_single(streamer_priv->pci_dev, &streamer_priv->streamer_tx_ring[0],
+							sizeof(struct streamer_tx_desc), PCI_DMA_TODEVICE));
 
 	streamer_priv->free_tx_ring_entries = STREAMER_TX_RING_SIZE;
 	streamer_priv->tx_ring_free = 0;	/* next entry in tx ring to use */
@@ -915,6 +939,11 @@
 				skb->dev = dev;
 
 				if (buffer_cnt == 1) {
+					/* release the DMA mapping */
+					pci_unmap_single(streamer_priv->pci_dev, 
+						le32_to_cpu(streamer_priv->streamer_rx_ring[rx_ring_last_received].buffer),
+						streamer_priv->pkt_buf_sz, 
+						PCI_DMA_FROMDEVICE);
 					skb2 = streamer_priv->rx_ring_skb[rx_ring_last_received];
 #if STREAMER_DEBUG_PACKETS
 					{
@@ -934,20 +963,29 @@
 					/* recycle this descriptor */
 					streamer_priv->streamer_rx_ring[rx_ring_last_received].status = 0;
 					streamer_priv->streamer_rx_ring[rx_ring_last_received].framelen_buflen = streamer_priv->pkt_buf_sz;
-					streamer_priv->streamer_rx_ring[rx_ring_last_received].buffer = virt_to_bus(skb->data);
-					streamer_priv-> rx_ring_skb[rx_ring_last_received] = skb;
+					streamer_priv->streamer_rx_ring[rx_ring_last_received].buffer = 
+						cpu_to_le32(pci_map_single(streamer_priv->pci_dev, skb->data, streamer_priv->pkt_buf_sz,
+								PCI_DMA_FROMDEVICE));
+					streamer_priv->rx_ring_skb[rx_ring_last_received] = skb;
 					/* place recycled descriptor back on the adapter */
-					writel(virt_to_bus(&streamer_priv->streamer_rx_ring[rx_ring_last_received]),streamer_mmio + RXLBDA);
+					writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, 
+									&streamer_priv->streamer_rx_ring[rx_ring_last_received],
+									sizeof(struct streamer_rx_desc), PCI_DMA_FROMDEVICE)),
+						streamer_mmio + RXLBDA);
 					/* pass the received skb up to the protocol */
 					netif_rx(skb2);
 				} else {
 					do {	/* Walk the buffers */
-						memcpy(skb_put(skb, length),bus_to_virt(rx_desc->buffer), length);	/* copy this fragment */
+						pci_unmap_single(streamer_priv->pci_dev, le32_to_cpu(rx_desc->buffer), length, PCI_DMA_FROMDEVICE), 
+						memcpy(skb_put(skb, length), (void *)rx_desc->buffer, length);	/* copy this fragment */
 						streamer_priv->streamer_rx_ring[rx_ring_last_received].status = 0;
 						streamer_priv->streamer_rx_ring[rx_ring_last_received].framelen_buflen = streamer_priv->pkt_buf_sz;
 						
 						/* give descriptor back to the adapter */
-						writel(virt_to_bus(&streamer_priv->streamer_rx_ring[rx_ring_last_received]), streamer_mmio + RXLBDA);
+						writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, 
+									&streamer_priv->streamer_rx_ring[rx_ring_last_received],
+									length, PCI_DMA_FROMDEVICE)), 
+							streamer_mmio + RXLBDA);
 
 						if (rx_desc->status & 0x80000000)
 							break;	/* this descriptor completes the frame */
@@ -1114,7 +1152,8 @@
 	if (streamer_priv->free_tx_ring_entries) {
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].status = 0;
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00020000 | skb->len;
-		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buffer = virt_to_bus(skb->data);
+		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buffer = 
+			cpu_to_le32(pci_map_single(streamer_priv->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE));
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd1 = skb->len;
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd2 = 0;
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd3 = 0;
@@ -1135,7 +1174,10 @@
 		}
 #endif
 
-		writel(virt_to_bus (&streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free]),streamer_mmio + TX2LFDA);
+		writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, 
+					&streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free],
+					sizeof(struct streamer_tx_desc), PCI_DMA_TODEVICE)),
+			streamer_mmio + TX2LFDA);
 		(void)readl(streamer_mmio + TX2LFDA);
 
 		streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/tokenring/olympic.c linux-2.4.20/drivers/net/tokenring/olympic.c
--- linux-2.4.19/drivers/net/tokenring/olympic.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/tokenring/olympic.c	2002-10-29 11:18:34.000000000 +0000
@@ -56,8 +56,15 @@
  * 07/19/01 - Improve bad LAA reporting, strip out freemem
  *	      into a separate function, its called from 3 
  *	      different places now. 
- * 02/09/01 - Replaced sleep_on. 
- *
+ * 02/09/02 - Replaced sleep_on. 
+ * 03/01/02 - Replace access to several registers from 32 bit to 
+ * 	      16 bit. Fixes alignment errors on PPC 64 bit machines.
+ * 	      Thanks to Al Trautman for this one.
+ * 03/10/02 - Fix BUG in arb_cmd. Bug was there all along but was
+ * 	      silently ignored until the error checking code 
+ * 	      went into version 1.0.0 
+ * 06/04/02 - Add correct start up sequence for the cardbus adapters.
+ * 	      Required for strict compliance with pci power mgmt specs.
  *  To Do:
  *
  *	     Wake on lan	
@@ -111,7 +118,7 @@
  */
 
 static char version[] __devinitdata = 
-"Olympic.c v1.0.0 2/9/02  - Peter De Schrijver & Mike Phillips" ; 
+"Olympic.c v1.0.5 6/04/02 - Peter De Schrijver & Mike Phillips" ; 
 
 static char *open_maj_error[]  = {"No error", "Lobe Media Test", "Physical Insertion",
 				   "Address Verification", "Neighbor Notification (Ring Poll)",
@@ -128,7 +135,7 @@
 /* Module paramters */
 
 MODULE_AUTHOR("Mike Phillips <mikep@linuxtr.net>") ; 
-MODULE_DESCRIPTION("Olympic PCI/Cardbus Chipset Driver \n") ; 
+MODULE_DESCRIPTION("Olympic PCI/Cardbus Chipset Driver") ; 
 
 /* Ring Speed 0,4,16,100 
  * 0 = Autosense         
@@ -296,9 +303,10 @@
 	spin_lock_init(&olympic_priv->olympic_lock) ; 
 
 	/* Needed for cardbus */
-	if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR))
+	if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR)) {
 		writel(readl(olympic_priv->olympic_mmio+FERMASK)|FERMASK_INT_BIT, olympic_mmio+FERMASK);
-
+	}
+	
 #if OLYMPIC_DEBUG
 	printk("BCTL: %x\n",readl(olympic_mmio+BCTL));
 	printk("GPR: %x\n",readw(olympic_mmio+GPR));
@@ -311,24 +319,42 @@
 	writel(readl(olympic_mmio+BCTL)|BCTL_MIMREB,olympic_mmio+BCTL);
 	
 	if (olympic_priv->olympic_ring_speed  == 0) { /* Autosense */
-		writel(readl(olympic_mmio+GPR)|GPR_AUTOSENSE,olympic_mmio+GPR);
+		writew(readw(olympic_mmio+GPR)|GPR_AUTOSENSE,olympic_mmio+GPR);
 		if (olympic_priv->olympic_message_level) 
 			printk(KERN_INFO "%s: Ringspeed autosense mode on\n",olympic_priv->olympic_card_name);
 	} else if (olympic_priv->olympic_ring_speed == 16) {
 		if (olympic_priv->olympic_message_level) 
 			printk(KERN_INFO "%s: Trying to open at 16 Mbps as requested\n", olympic_priv->olympic_card_name);
-		writel(GPR_16MBPS, olympic_mmio+GPR);
+		writew(GPR_16MBPS, olympic_mmio+GPR);
 	} else if (olympic_priv->olympic_ring_speed == 4) {
 		if (olympic_priv->olympic_message_level) 
 			printk(KERN_INFO "%s: Trying to open at 4 Mbps as requested\n", olympic_priv->olympic_card_name) ; 
-		writel(0, olympic_mmio+GPR);
+		writew(0, olympic_mmio+GPR);
 	} 
 	
-	writel(readl(olympic_mmio+GPR)|GPR_NEPTUNE_BF,olympic_mmio+GPR);
+	writew(readw(olympic_mmio+GPR)|GPR_NEPTUNE_BF,olympic_mmio+GPR);
 
 #if OLYMPIC_DEBUG
 	printk("GPR = %x\n",readw(olympic_mmio + GPR) ) ; 
 #endif
+	/* Solo has been paused to meet the Cardbus power
+	 * specs if the adapter is cardbus. Check to 
+	 * see its been paused and then restart solo. The
+	 * adapter should set the pause bit within 1 second.
+	 */
+
+	if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR)) { 
+		t=jiffies;
+		while (!readl(olympic_mmio+CLKCTL) & CLKCTL_PAUSE) { 
+			schedule() ; 
+			if(jiffies-t > 2*HZ) { 
+				printk(KERN_ERR "IBM Cardbus tokenring adapter not responsing.\n") ; 
+				return -ENODEV;
+			}
+		}
+		writel(readl(olympic_mmio+CLKCTL) & ~CLKCTL_PAUSE, olympic_mmio+CLKCTL) ; 
+	}
+	
 	/* start solo init */
 	writel((1<<15),olympic_mmio+SISR_MASK_SUM);
 
@@ -341,13 +367,13 @@
 		}
 	}
 	
-	writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
+	writel(readw(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
 
 #if OLYMPIC_DEBUG
 	printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
 #endif
 
-	init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800));
+	init_srb=olympic_priv->olympic_lap + ((readw(olympic_mmio+LAPWWO)) & (~0xf800));
 
 #if OLYMPIC_DEBUG		
 {
@@ -422,11 +448,11 @@
 
 	/* adapter is closed, so SRB is pointed to by LAPWWO */
 
-	writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
-	init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800));
+	writel(readw(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
+	init_srb=olympic_priv->olympic_lap + ((readw(olympic_mmio+LAPWWO)) & (~0xf800));
 	
 #if OLYMPIC_DEBUG
-	printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
+	printk("LAPWWO: %x, LAPA: %x\n",readw(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
 	printk("SISR Mask = %04x\n", readl(olympic_mmio+SISR_MASK));
 	printk("Before the open command \n");
 #endif	
@@ -486,7 +512,7 @@
             			olympic_priv->srb_queued=0;
             			break;
         		}
-			if ((jiffies-t) > 60*HZ) { 
+			if ((jiffies-t) > 10*HZ) { 
 				printk(KERN_WARNING "%s: SRB timed out. \n",dev->name) ; 
 				olympic_priv->srb_queued=0;
 				break ; 
@@ -495,7 +521,7 @@
     		}
 		remove_wait_queue(&olympic_priv->srb_wait,&wait) ; 
 		set_current_state(TASK_RUNNING) ; 
-
+		olympic_priv->srb_queued = 0 ; 
 #if OLYMPIC_DEBUG
 		printk("init_srb(%p): ",init_srb);
 		for(i=0;i<20;i++)
@@ -629,7 +655,8 @@
 	printk(" stat_ring[7]: %p\n", &(olympic_priv->olympic_rx_status_ring[7])  );
 
 	printk("RXCDA: %x, rx_ring[0]: %p\n",readl(olympic_mmio+RXCDA),&olympic_priv->olympic_rx_ring[0]);
-	printk("Rx_ring_dma_addr = %08x, rx_status_dma_addr = %08x\n",olympic_priv->rx_ring_dma_addr,olympic_priv->rx_status_ring_dma_addr) ; 
+	printk("Rx_ring_dma_addr = %08x, rx_status_dma_addr =
+%08x\n",olympic_priv->rx_ring_dma_addr,olympic_priv->rx_status_ring_dma_addr) ; 
 #endif
 
 	writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | i,olympic_mmio+RXENQ);
@@ -790,7 +817,7 @@
 			   	   	   first. Ideally all frames would be in a single buffer, this can be tuned by
                                	   	   altering the buffer size. If the length of the packet is less than
 					   1500 bytes we're going to copy it over anyway to stop packets getting
-					   dropped from sockets with buffers small than our pkt_buf_sz. */
+					   dropped from sockets with buffers smaller than our pkt_buf_sz. */
 				
  					if (buffer_cnt==1) {
 						olympic_priv->rx_ring_last_received++ ; 
@@ -1097,10 +1124,13 @@
 	writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL);
 
 #if OLYMPIC_DEBUG
+	{
+	int i ; 
 	printk("srb(%p): ",srb);
 	for(i=0;i<4;i++)
 		printk("%x ",readb(srb+i));
 	printk("\n");
+	}
 #endif
 	free_irq(dev->irq,dev);
 
@@ -1369,8 +1399,7 @@
 	arb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; 
 	asb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; 
 	srb = (u8 *)(olympic_priv->olympic_lap + olympic_priv->srb) ; 
-	writel(readl(olympic_mmio+LAPA),olympic_mmio+LAPWWO);
-
+	
 	if (readb(arb_block+0) == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */
 
 		header_len = readb(arb_block+8) ; /* 802.5 Token-Ring Header Length */	
@@ -1423,7 +1452,7 @@
 		/* Now tell the card we have dealt with the received frame */
 
 		/* Set LISR Bit 1 */
-		writel(LISR_ARB_FREE,olympic_priv->olympic_lap + LISR_SUM);
+		writel(LISR_ARB_FREE,olympic_priv->olympic_mmio + LISR_SUM);
 
 		/* Is the ASB free ? */ 	
 		
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/tokenring/olympic.h linux-2.4.20/drivers/net/tokenring/olympic.h
--- linux-2.4.19/drivers/net/tokenring/olympic.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/tokenring/olympic.h	2002-10-29 11:18:40.000000000 +0000
@@ -91,6 +91,7 @@
 #define TIMER 0x50
 
 #define CLKCTL 0x74
+#define CLKCTL_PAUSE (1<<15) 
 
 #define PM_CON 0x4
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/tulip/ChangeLog linux-2.4.20/drivers/net/tulip/ChangeLog
--- linux-2.4.19/drivers/net/tulip/ChangeLog	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/tulip/ChangeLog	2002-10-29 11:18:34.000000000 +0000
@@ -1,3 +1,14 @@
+2002-09-18  Ryan Bradetich  <rbradetich@uswest.net>
+
+	tulip hppa support:
+	* eeprom.c (tulip_build_fake_mediatable): new function
+	(tulip_parse_eeprom): call it, when no media table
+	* interrupt.c (phy_interrupt): new function
+	(tulip_interrupt): call it, before checking for no-irq-work
+	* tulip.c: add HAS_PHY_IRQ chip feature flag.
+	add csr12_shadow to tulip_private struct, only for hppa currently.
+	* tulip_core (tulip_init_one): support hppa wonky eeproms
+
 2002-05-11  Juan Quintela  <quintela@mandrakesoft.com>
 
 	* 21142.c (t21142_lnk_change): Revert earlier patch
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/tulip/eeprom.c linux-2.4.20/drivers/net/tulip/eeprom.c
--- linux-2.4.19/drivers/net/tulip/eeprom.c	2001-10-02 16:00:58.000000000 +0000
+++ linux-2.4.20/drivers/net/tulip/eeprom.c	2002-10-29 11:18:38.000000000 +0000
@@ -75,6 +75,61 @@
 };
 
 
+/**
+ * tulip_build_fake_mediatable - Build a fake mediatable entry.
+ * @tp: Ptr to the tulip private data.
+ *
+ * Some cards like the 3x5 HSC cards (J3514A) do not have a standard 
+ * srom and can not be handled under the fixup routine.  These cards
+ * still need a valid mediatable entry for correct csr12 setup and 
+ * mii handling.
+ * 
+ * Since this is currently a parisc-linux specific function, the
+ * #ifdef __hppa__ should completely optimize this function away for
+ * non-parisc hardware.
+ */
+static void __devinit tulip_build_fake_mediatable(struct tulip_private *tp)
+{
+#ifdef __hppa__
+	unsigned char *ee_data = tp->eeprom;
+
+	if (ee_data[0] == 0x3c && ee_data[1] == 0x10 && 
+		(ee_data[2] == 0x63 || ee_data[2] == 0x61) && ee_data[3] == 0x10) {
+
+		static unsigned char leafdata[] =
+			{ 0x01,       /* phy number */
+			  0x02,       /* gpr setup sequence length */
+			  0x02, 0x00, /* gpr setup sequence */
+			  0x02,       /* phy reset sequence length */
+			  0x01, 0x00, /* phy reset sequence */
+			  0x00, 0x78, /* media capabilities */
+			  0x00, 0xe0, /* nway advertisment */
+			  0x00, 0x05, /* fdx bit map */
+			  0x00, 0x06  /* ttm bit map */
+			};
+
+		tp->mtable = (struct mediatable *)
+			kmalloc(sizeof(struct mediatable) + sizeof(struct medialeaf), GFP_KERNEL);
+
+		if (tp->mtable == NULL)
+			return; /* Horrible, impossible failure. */
+
+		tp->mtable->defaultmedia = 0x800;
+		tp->mtable->leafcount = 1;
+		tp->mtable->csr12dir = 0x3f; /* inputs on bit7 for hsc-pci, bit6 for pci-fx */
+		tp->mtable->has_nonmii = 0;
+		tp->mtable->has_reset = 0;
+		tp->mtable->has_mii = 1;
+		tp->mtable->csr15dir = tp->mtable->csr15val = 0;
+		tp->mtable->mleaf[0].type = 1;
+		tp->mtable->mleaf[0].media = 11;
+		tp->mtable->mleaf[0].leafdata = &leafdata[0];
+		tp->flags |= HAS_PHY_IRQ;
+		tp->csr12_shadow = -1;
+	}
+#endif 
+}
+
 void __devinit tulip_parse_eeprom(struct net_device *dev)
 {
 	/* The last media info list parsed, for multiport boards.  */
@@ -136,6 +191,7 @@
 subsequent_board:
 
 	if (ee_data[27] == 0) {		/* No valid media table. */
+		tulip_build_fake_mediatable(tp);
 	} else if (tp->chip_id == DC21041) {
 		unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3];
 		int media = get_u16(p);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/tulip/interrupt.c linux-2.4.20/drivers/net/tulip/interrupt.c
--- linux-2.4.19/drivers/net/tulip/interrupt.c	2001-11-09 21:45:35.000000000 +0000
+++ linux-2.4.20/drivers/net/tulip/interrupt.c	2002-10-29 11:18:35.000000000 +0000
@@ -291,6 +291,25 @@
 #endif
 }
 
+static inline void phy_interrupt (struct net_device *dev)
+{
+#ifdef __hppa__
+	int csr12 = inl(dev->base_addr + CSR12) & 0xff;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+	if (csr12 != tp->csr12_shadow) {
+		/* ack interrupt */
+		outl(csr12 | 0x02, dev->base_addr + CSR12);
+		tp->csr12_shadow = csr12;
+		/* do link change stuff */
+		spin_lock(&tp->lock);
+		tulip_check_duplex(dev);
+		spin_unlock(&tp->lock);
+		/* clear irq ack bit */
+		outl(csr12 & ~0x02, dev->base_addr + CSR12);
+	}
+#endif
+}
 
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
@@ -313,6 +332,9 @@
 	/* Let's see whether the interrupt really is for us */
 	csr5 = inl(ioaddr + CSR5);
 
+        if (tp->flags & HAS_PHY_IRQ)
+	        phy_interrupt (dev);
+    
 	if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
 		return;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/tulip/tulip.h linux-2.4.20/drivers/net/tulip/tulip.h
--- linux-2.4.19/drivers/net/tulip/tulip.h	2001-11-09 21:45:35.000000000 +0000
+++ linux-2.4.20/drivers/net/tulip/tulip.h	2002-10-29 11:18:38.000000000 +0000
@@ -63,6 +63,7 @@
 	HAS_8023X		= 0x0400,
 	COMET_MAC_ADDR		= 0x0800,
 	HAS_PCI_MWI		= 0x1000,
+	HAS_PHY_IRQ		= 0x2000,
 };
 
 
@@ -84,6 +85,7 @@
 	COMPEX9881,
 	I21145,
 	DM910X,
+	CONEXANT,
 };
 
 
@@ -387,7 +389,8 @@
 	int susp_rx;
 	unsigned long nir;
 	unsigned long base_addr;
-	int pad0, pad1;		/* Used for 8-byte alignment */
+	int csr12_shadow;
+	int pad0;		/* Used for 8-byte alignment */
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/tulip/tulip_core.c linux-2.4.20/drivers/net/tulip/tulip_core.c
--- linux-2.4.19/drivers/net/tulip/tulip_core.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/tulip/tulip_core.c	2002-10-29 11:18:48.000000000 +0000
@@ -15,8 +15,8 @@
 */
 
 #define DRV_NAME	"tulip"
-#define DRV_VERSION	"0.9.15-pre11"
-#define DRV_RELDATE	"May 11, 2002"
+#define DRV_VERSION	"0.9.15-pre12"
+#define DRV_RELDATE	"Aug 9, 2002"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -191,6 +191,10 @@
   { "Davicom DM9102/DM9102A", 128, 0x0001ebef,
 	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI,
 	tulip_timer },
+
+  /* CONEXANT */
+  {	"Conexant LANfinity", 256, 0x0001ebef,
+	HAS_MII, tulip_timer },
 };
 
 
@@ -214,6 +218,7 @@
 	{ 0x13D1, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x104A, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x104A, 0x2774, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+	{ 0x1259, 0xa120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 },
 	{ 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 },
 	{ 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X },
@@ -221,6 +226,10 @@
 	{ 0x1113, 0x1216, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
 	{ 0x1113, 0x9511, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+	{ 0x1186, 0x1561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+	{ 0x1626, 0x8410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+	{ 0x1737, 0xAB09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+	{ 0x14f1, 0x1803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CONEXANT },
 	{ } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
@@ -453,7 +462,7 @@
 		tp->csr6 = 0x01a80200;
 		outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
 		outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0);
-	} else if (tp->chip_id == COMET) {
+	} else if (tp->chip_id == COMET || tp->chip_id == CONEXANT) {
 		/* Enable automatic Tx underrun recovery. */
 		outl(inl(ioaddr + 0x88) | 1, ioaddr + 0x88);
 		dev->if_port = tp->mii_cnt ? 11 : 0;
@@ -1474,7 +1483,6 @@
 	tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
 
 	dev->base_addr = ioaddr;
-	dev->irq = irq;
 
 #ifdef CONFIG_TULIP_MWI
 	if (!force_csr0 && (tp->flags & HAS_PCI_MWI))
@@ -1548,7 +1556,13 @@
 		for (i = 0; i < 8; i ++)
 			if (ee_data[i] != ee_data[16+i])
 				sa_offset = 20;
-		if (ee_data[0] == 0xff  &&  ee_data[1] == 0xff &&  ee_data[2] == 0) {
+		if (chip_idx == CONEXANT) {
+		    /* Check that the tuple type and length is correct. */
+			if (ee_data[0x198] == 0x04  &&  ee_data[0x199] == 6)
+			    sa_offset = 0x19A;
+		}
+		if (ee_data[0] == 0xff && ee_data[1] == 0xff &&
+		    ee_data[2] == 0) {
 			sa_offset = 2;		/* Grrr, damn Matrox boards. */
 			multiport_cnt = 4;
 		}
@@ -1578,6 +1592,25 @@
                        tp->flags &= ~HAS_MEDIA_TABLE;
                }
 #endif
+#ifdef __hppa__
+		/* 3x5 HSC (J3514A) has a broken srom */
+		if(ee_data[0] == 0x61 && ee_data[1] == 0x10) {
+			/* pci_vendor_id and subsystem_id are swapped */
+			ee_data[0] = ee_data[2];
+			ee_data[1] = ee_data[3];
+			ee_data[2] = 0x61;
+			ee_data[3] = 0x10;
+
+			/* srom need to be byte-swaped and shifted up 1 word.  
+			 * This shift needs to happen at the end of the MAC
+			 * first because of the 2 byte overlap.
+			 */
+			for(i = 4; i >= 0; i -= 2) {
+				ee_data[17 + i + 3] = ee_data[17 + i];
+				ee_data[16 + i + 5] = ee_data[16 + i];
+			}
+		}
+#endif
 		for (i = 0; i < 6; i ++) {
 			dev->dev_addr[i] = ee_data[i + sa_offset];
 			sum += ee_data[i + sa_offset];
@@ -1622,6 +1655,7 @@
 	for (i = 0; i < 6; i++)
 		last_phys_addr[i] = dev->dev_addr[i];
 	last_irq = irq;
+	dev->irq = irq;
 
 	/* The lower four bits are the media type. */
 	if (board_idx >= 0  &&  board_idx < MAX_UNITS) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/via-rhine.c linux-2.4.20/drivers/net/via-rhine.c
--- linux-2.4.19/drivers/net/via-rhine.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/via-rhine.c	2002-10-29 11:18:40.000000000 +0000
@@ -93,6 +93,10 @@
 	- transmit frame queue message is off by one - fixed
 	- adds IntrNormalSummary to "Something Wicked" exclusion list
 	  so normal interrupts will not trigger the message (src: Donald Becker)
+ 	(Roger Luethi)
+ 	- show confused chip where to continue after Tx error
+ 	- location of collision counter is chip specific
+ 	- allow selecting backoff algorithm (module parameter)
 
 */
 
@@ -111,6 +115,9 @@
    Setting to > 1518 effectively disables this feature. */
 static int rx_copybreak;
 
+/* Select a backoff algorithm (Ethernet capture effect) */
+static int backoff;
+
 /* Used to pass the media type, etc.
    Both 'options[]' and 'full_duplex[]' should exist for driver
    interoperability.
@@ -213,11 +220,13 @@
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(backoff, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt");
 MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)");
 MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(backoff, "VIA Rhine: Bits 0-3: backoff algorithm");
 MODULE_PARM_DESC(options, "VIA Rhine: Bits 0-3: media type, bit 17: full duplex");
 MODULE_PARM_DESC(full_duplex, "VIA Rhine full duplex setting(s) (1)");
 
@@ -234,7 +243,8 @@
 Boards with this chip are functional only in a bus-master PCI slot.
 
 Many operational settings are loaded from the EEPROM to the Config word at
-offset 0x78.  This driver assumes that they are correct.
+offset 0x78. For most of these settings, this driver assumes that they are
+correct.
 If this driver is compiled to use PCI memory space operations the EEPROM
 must be configured to enable memory ops.
 
@@ -386,9 +396,10 @@
 	StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC,
 };
 
-/* Bits in ConfigD (select backoff algorithm (Ethernet capture effect)) */
+/* Bits in ConfigD */
 enum backoff_bits {
-	BackOpt=0x01, BackAMD=0x02, BackDEC=0x04, BackRandom=0x08
+	BackOptional=0x01, BackModify=0x02,
+	BackCaptureEffect=0x04, BackRandom=0x08
 };
 
 #ifdef USE_MEM
@@ -402,7 +413,7 @@
 /* Bits in the interrupt status/mask registers. */
 enum intr_status_bits {
 	IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020,
-	IntrTxDone=0x0002, IntrTxAbort=0x0008, IntrTxUnderrun=0x0010,
+	IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0010,
 	IntrPCIErr=0x0040,
 	IntrStatsMax=0x0080, IntrRxEarly=0x0100, IntrMIIChange=0x0200,
 	IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000,
@@ -428,24 +439,27 @@
 /* The Rx and Tx buffer descriptors. */
 struct rx_desc {
 	s32 rx_status;
-	u32 desc_length;
+	u32 desc_length; /* Chain flag, Buffer/frame length */
 	u32 addr;
 	u32 next_desc;
 };
 struct tx_desc {
 	s32 tx_status;
-	u32 desc_length;
+	u32 desc_length; /* Chain flag, Tx Config, Frame length */
 	u32 addr;
 	u32 next_desc;
 };
 
+/* Initial value for tx_desc.desc_length, Buffer size goes to bits 0-10 */
+#define TXDESC 0x00e08000
+
 enum rx_status_bits {
 	RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F
 };
 
-/* Bits in *_desc.status */
+/* Bits in *_desc.*_status */
 enum desc_status_bits {
-	DescOwn=0x80000000, DescEndPacket=0x4000, DescIntr=0x1000,
+	DescOwn=0x80000000
 };
 
 /* Bits in ChipCmd. */
@@ -514,9 +528,10 @@
 static void via_rhine_error(struct net_device *dev, int intr_status);
 static void via_rhine_set_rx_mode(struct net_device *dev);
 static struct net_device_stats *via_rhine_get_stats(struct net_device *dev);
-static int via_rhine_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int  via_rhine_close(struct net_device *dev);
 static inline void clear_tally_counters(long ioaddr);
+static inline void via_restart_tx(struct net_device *dev);
 
 static void wait_for_reset(struct net_device *dev, int chip_id, char *name)
 {
@@ -703,6 +718,11 @@
 		writeb(readb(ioaddr + ConfigA) & 0xFE, ioaddr + ConfigA);
 	}
 
+	/* Select backoff algorithm */
+	if (backoff)
+		writeb(readb(ioaddr + ConfigD) & (0xF0 | backoff),
+			ioaddr + ConfigD);
+
 	dev->irq = pdev->irq;
 
 	np = dev->priv;
@@ -713,6 +733,8 @@
 	np->mii_if.dev = dev;
 	np->mii_if.mdio_read = mdio_read;
 	np->mii_if.mdio_write = mdio_write;
+	np->mii_if.phy_id_mask = 0x1f;
+	np->mii_if.reg_num_mask = 0x1f;
 
 	if (dev->mem_start)
 		option = dev->mem_start;
@@ -729,7 +751,7 @@
 	if (np->mii_if.full_duplex) {
 		printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
 			   " disabled.\n", dev->name);
-		np->mii_if.duplex_lock = 1;
+		np->mii_if.force_media = 1;
 	}
 
 	/* The chip-specific entries in the device structure. */
@@ -738,7 +760,7 @@
 	dev->stop = via_rhine_close;
 	dev->get_stats = via_rhine_get_stats;
 	dev->set_multicast_list = via_rhine_set_rx_mode;
-	dev->do_ioctl = via_rhine_ioctl;
+	dev->do_ioctl = netdev_ioctl;
 	dev->tx_timeout = via_rhine_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	if (np->drv_flags & ReqTxAlign)
@@ -937,7 +959,7 @@
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		np->tx_skbuff[i] = 0;
 		np->tx_ring[i].tx_status = 0;
-		np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
+		np->tx_ring[i].desc_length = cpu_to_le32(TXDESC);
 		next += sizeof(struct tx_desc);
 		np->tx_ring[i].next_desc = cpu_to_le32(next);
 		np->tx_buf[i] = &np->tx_bufs[i * PKT_BUF_SZ];
@@ -953,7 +975,7 @@
 
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		np->tx_ring[i].tx_status = 0;
-		np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
+		np->tx_ring[i].desc_length = cpu_to_le32(TXDESC);
 		np->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
 		if (np->tx_skbuff[i]) {
 			if (np->tx_skbuff_dma[i]) {
@@ -978,7 +1000,7 @@
 		writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
 
 	/* Initialize other registers. */
-	writew(0x0006, ioaddr + PCIBusConfig);	/* Store & forward */
+	writew(0x0006, ioaddr + PCIBusConfig);	/* Tune configuration??? */
 	/* Configure initial FIFO thresholds. */
 	writeb(0x20, ioaddr + TxConfig);
 	np->tx_thresh = 0x20;
@@ -993,13 +1015,14 @@
 	via_rhine_set_rx_mode(dev);
 
 	/* Enable interrupts by setting the interrupt mask. */
-	writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped|
-		   IntrTxDone | IntrTxAbort | IntrTxUnderrun |
+	writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
+		   IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
+		   IntrTxDone | IntrTxError | IntrTxUnderrun |
 		   IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange,
 		   ioaddr + IntrEnable);
 
 	np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;
-	if (np->mii_if.duplex_lock)
+	if (np->mii_if.force_media)
 		np->chip_cmd |= CmdFDuplex;
 	writew(np->chip_cmd, ioaddr + ChipCmd);
 
@@ -1041,7 +1064,7 @@
 		switch (regnum) {
 		case MII_BMCR:					/* Is user forcing speed/duplex? */
 			if (value & 0x9000)			/* Autonegotiation. */
-				np->mii_if.duplex_lock = 0;
+				np->mii_if.force_media = 0;
 			else
 				np->mii_if.full_duplex = (value & 0x0100) ? 1 : 0;
 			break;
@@ -1112,7 +1135,7 @@
 	int negotiated = mii_lpa & np->mii_if.advertising;
 	int duplex;
 
-	if (np->mii_if.duplex_lock  ||  mii_lpa == 0xffff)
+	if (np->mii_if.force_media  ||  mii_lpa == 0xffff)
 		return;
 	duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
 	if (np->mii_if.full_duplex != duplex) {
@@ -1237,7 +1260,7 @@
 	}
 
 	np->tx_ring[entry].desc_length = 
-		cpu_to_le32(0x00E08000 | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
+		cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
 
 	/* lock eth irq */
 	spin_lock_irq (&np->lock);
@@ -1289,13 +1312,14 @@
 						   IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf))
 			via_rhine_rx(dev);
 
-		if (intr_status & (IntrTxDone | IntrTxAbort | IntrTxUnderrun |
+		if (intr_status & (IntrTxDone | IntrTxError | IntrTxUnderrun |
 						   IntrTxAborted))
 			via_rhine_tx(dev);
 
 		/* Abnormal error summary/uncommon events handlers. */
 		if (intr_status & (IntrPCIErr | IntrLinkChange | IntrMIIChange |
-						   IntrStatsMax | IntrTxAbort | IntrTxUnderrun))
+				   IntrStatsMax | IntrTxError | IntrTxAborted |
+				   IntrTxUnderrun))
 			via_rhine_error(dev, intr_status);
 
 		if (--boguscnt < 0) {
@@ -1307,7 +1331,7 @@
 	}
 
 	if (debug > 3)
-		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
+		printk(KERN_DEBUG "%s: exiting interrupt, status=%4.4x.\n",
 			   dev->name, readw(ioaddr + IntrStatus));
 }
 
@@ -1323,11 +1347,11 @@
 	/* find and cleanup dirty tx descriptors */
 	while (np->dirty_tx != np->cur_tx) {
 		txstatus = le32_to_cpu(np->tx_ring[entry].tx_status);
-		if (txstatus & DescOwn)
-			break;
 		if (debug > 6)
 			printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n",
 				   entry, txstatus);
+		if (txstatus & DescOwn)
+			break;
 		if (txstatus & 0x8000) {
 			if (debug > 1)
 				printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
@@ -1337,10 +1361,22 @@
 			if (txstatus & 0x0200) np->stats.tx_window_errors++;
 			if (txstatus & 0x0100) np->stats.tx_aborted_errors++;
 			if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++;
-			if (txstatus & 0x0002) np->stats.tx_fifo_errors++;
+			if (((np->chip_id == VT86C100A) && txstatus & 0x0002) ||
+				(txstatus & 0x0800) || (txstatus & 0x1000)) {
+				np->stats.tx_fifo_errors++;
+				np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
+				break; /* Keep the skb - we try again */
+			}
 			/* Transmitter restarted in 'abnormal' handler. */
 		} else {
-			np->stats.collisions += (txstatus >> 3) & 15;
+			if (np->chip_id == VT86C100A)
+				np->stats.collisions += (txstatus >> 3) & 0x0F;
+			else
+				np->stats.collisions += txstatus & 0x0F;
+			if (debug > 6)
+				printk(KERN_DEBUG "collisions: %1.1x:%1.1x\n",
+					(txstatus >> 3) & 0xF,
+					txstatus & 0xF);
 			np->stats.tx_bytes += np->tx_skbuff[entry]->len;
 			np->stats.tx_packets++;
 		}
@@ -1476,6 +1512,17 @@
 	writew(CmdRxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
 }
 
+static inline void via_restart_tx(struct net_device *dev) {
+	struct netdev_private *np = dev->priv;
+	int entry = np->dirty_tx % TX_RING_SIZE;
+
+	/* We know better than the chip where it should continue */
+	writel(np->tx_ring_dma + entry * sizeof(struct tx_desc),
+		   dev->base_addr + TxRingPtr);
+
+	writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
+}
+
 static void via_rhine_error(struct net_device *dev, int intr_status)
 {
 	struct netdev_private *np = dev->priv;
@@ -1501,19 +1548,23 @@
 		np->stats.rx_missed_errors	+= readw(ioaddr + RxMissed);
 		clear_tally_counters(ioaddr);
 	}
-	if (intr_status & IntrTxAbort) {
-		/* Stats counted in Tx-done handler, just restart Tx. */
-		writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
+	if (intr_status & IntrTxError) {
+		if (debug > 1)
+			printk(KERN_INFO "%s: Abort %4.4x, frame dropped.\n",
+				   dev->name, intr_status);
+		via_restart_tx(dev);
 	}
 	if (intr_status & IntrTxUnderrun) {
 		if (np->tx_thresh < 0xE0)
 			writeb(np->tx_thresh += 0x20, ioaddr + TxConfig);
 		if (debug > 1)
-			printk(KERN_INFO "%s: Transmitter underrun, increasing Tx "
-				   "threshold setting to %2.2x.\n", dev->name, np->tx_thresh);
+			printk(KERN_INFO "%s: Transmitter underrun, Tx "
+				   "threshold now %2.2x.\n",
+				   dev->name, np->tx_thresh);
+		via_restart_tx(dev);
 	}
 	if (intr_status & ~( IntrLinkChange | IntrStatsMax |
- 						 IntrTxAbort | IntrTxAborted | IntrNormalSummary)) {
+ 						 IntrTxError | IntrTxAborted | IntrNormalSummary)) {
 		if (debug > 1)
 			printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
 			   dev->name, intr_status);
@@ -1584,7 +1635,7 @@
 	writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig);
 }
 
-static int via_rhine_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
 {
 	struct netdev_private *np = dev->priv;
 	u32 ethcmd;
@@ -1667,44 +1718,26 @@
 
 	return -EOPNOTSUPP;
 }
-static int via_rhine_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct netdev_private *np = dev->priv;
-	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
-	unsigned long flags;
-	int retval;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+	int rc;
 
-	if (cmd == SIOCETHTOOL)
-		return via_rhine_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
-	spin_lock_irqsave(&np->lock, flags);
-	retval = 0;
+	if (!netif_running(dev))
+		return -EINVAL;
 
-	switch(cmd) {
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
-		data->phy_id = np->phys[0] & 0x1f;
-		/* Fall Through */
-
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
-		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
-		break;
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
-		if (!capable(CAP_NET_ADMIN)) {
-			retval = -EPERM;
-			break;
-		}
-		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-		break;
-	default:
-		retval = -EOPNOTSUPP;
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
 	}
 
-	spin_unlock_irqrestore(&np->lock, flags);
-	return retval;
+	return rc;
 }
 
 static int via_rhine_close(struct net_device *dev)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wan/8253x/crc32.c linux-2.4.20/drivers/net/wan/8253x/crc32.c
--- linux-2.4.19/drivers/net/wan/8253x/crc32.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/wan/8253x/crc32.c	2002-10-29 11:18:31.000000000 +0000
@@ -46,13 +46,13 @@
 
 #if defined(AMD29K)
 pragma Data (Export,"fastbss");
-#endif defined(AMD29K)
+#endif // defined(AMD29K)
 
 unsigned int gg_a_crc_table[k_crc_table_size];
 
 #if defined(AMD29K)
 pragma Data;
-#endif defined(AMD29K)
+#endif // defined(AMD29K)
 
 
 /****************************************************/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wan/Config.in linux-2.4.20/drivers/net/wan/Config.in
--- linux-2.4.19/drivers/net/wan/Config.in	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/wan/Config.in	2002-10-29 11:18:33.000000000 +0000
@@ -9,12 +9,16 @@
 if [ "$CONFIG_WAN" = "y" ]; then
 # There is no way to detect a comtrol sv11 - force it modular for now.
 
+if [ "$CONFIG_ISA" = "y" ]; then
+
    dep_tristate '  Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m
 
 # The COSA/SRP driver has not been tested as non-modular yet.
 
    dep_tristate '  COSA/SRP sync serial boards support' CONFIG_COSA m
 
+fi
+
 #
 # COMX drivers
 #
@@ -95,9 +99,9 @@
 	    bool '      WANPIPE Multi-Port PPP support' CONFIG_WANPIPE_MULTPPP
 	 fi
 	 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-	    dep_tristate '    Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS
+	    dep_tristate '    Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS $CONFIG_ISA
 	    if [ "$CONFIG_CYCLADES_SYNC" != "n" ]; then
-	       bool '      Cyclom 2X X.25 support' CONFIG_CYCLOMX_X25
+	       bool '      Cyclom 2X X.25 support (EXPERIMENTAL)' CONFIG_CYCLOMX_X25
 	    fi
 	 fi
       fi
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wan/comx-hw-comx.c linux-2.4.20/drivers/net/wan/comx-hw-comx.c
--- linux-2.4.19/drivers/net/wan/comx-hw-comx.c	2001-09-13 23:04:43.000000000 +0000
+++ linux-2.4.20/drivers/net/wan/comx-hw-comx.c	2002-10-29 11:18:33.000000000 +0000
@@ -466,16 +466,16 @@
 	}
 
 	if (!twin_open) {
-		if (check_region(dev->base_addr, hw->io_extent)) {
+		if (!request_region(dev->base_addr, hw->io_extent, dev->name)) {
 			return -EAGAIN;
 		}
 		if (request_irq(dev->irq, COMX_interrupt, 0, dev->name, 
 		   (void *)dev)) {
 			printk(KERN_ERR "comx-hw-comx: unable to obtain irq %d\n", dev->irq);
+			release_region(dev->base_addr, hw->io_extent);
 			return -EAGAIN;
 		}
 		ch->init_status |= IRQ_ALLOCATED;
-		request_region(dev->base_addr, hw->io_extent, dev->name);
 		if (!ch->HW_load_board || ch->HW_load_board(dev)) {
 			ch->init_status &= ~IRQ_ALLOCATED;
 			retval=-ENODEV;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wan/comx-hw-munich.c linux-2.4.20/drivers/net/wan/comx-hw-munich.c
--- linux-2.4.19/drivers/net/wan/comx-hw-munich.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/wan/comx-hw-munich.c	2002-10-29 11:18:40.000000000 +0000
@@ -41,6 +41,7 @@
 #include <asm/io.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
+#include <linux/init.h>
 
 #define COMX_NEW
 
@@ -54,11 +55,9 @@
 #include "falc-lh.h"
 #endif
 
-MODULE_AUTHOR
-    ("Bartok Istvan <bartoki@itc.hu>, Gergely Madarasz <gorgo@itc.hu>, Szilard Pasztor <don@itc.hu>");
-MODULE_DESCRIPTION
-    ("Hardware-level driver for the SliceCOM and PciCOM (WelCOM) adapters");
-
+MODULE_AUTHOR("Bartok Istvan <bartoki@itc.hu>, Gergely Madarasz <gorgo@itc.hu>, Szilard Pasztor <don@itc.hu>");
+MODULE_DESCRIPTION("Hardware-level driver for the SliceCOM and PciCOM (WelCOM) adapters");
+MODULE_LICENSE("GPL");
 /*
  *	TODO: az ilyenek a comxhw.h -ban szoktak lenni, idovel menjenek majd oda:
  */
@@ -1252,8 +1251,6 @@
 	/* jon interrupt, de nincs mit feldolgozni, akkor torlom a STAT-ot.     */
 	/* 'needs a rewrite', de elso megoldasnak jo lesz                       */
 //              {
-
-udelay(10000);
 	int_info = board->tiq[board->tiq_ptr];
 	if (int_info.all & 0xF0000000)	/* ha ez nem 0, akkor itt interrupt_info van    */
 	{
@@ -1857,7 +1854,7 @@
 
     if (board->isx21)
     {
-	board->modemline_timer.data = (unsigned int)board;
+	board->modemline_timer.data = (unsigned long)board;
 	board->modemline_timer.function = pcicom_modemline;
 	board->modemline_timer.expires = jiffies + HZ;
 	add_timer((struct timer_list *)&board->modemline_timer);
@@ -2008,7 +2005,8 @@
 	if (board->tiq) kfree((void *)board->tiq);
 	if (board->riq) kfree((void *)board->riq);
 	if (board->piq) kfree((void *)board->piq);
-	board->ccb = board->tiq = board->riq = board->piq = NULL;
+	board->ccb = NULL;
+	board->tiq = board->riq = board->piq = NULL;
     }
 
     /* Enable setting of hw parameters */
@@ -2777,8 +2775,6 @@
 static int BOARD_exit(struct net_device *dev)
 {
     struct comx_channel *ch = (struct comx_channel *)dev->priv;
-    struct slicecom_privdata *hw = ch->HW_privdata;
-//    munich_board_t *board;
 
     /* Free private data area */
 //    board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wan/cosa.c linux-2.4.20/drivers/net/wan/cosa.c
--- linux-2.4.19/drivers/net/wan/cosa.c	2002-02-25 19:38:02.000000000 +0000
+++ linux-2.4.20/drivers/net/wan/cosa.c	2002-10-29 11:18:31.000000000 +0000
@@ -611,7 +611,8 @@
 static int cosa_sppp_open(struct net_device *d)
 {
 	struct channel_data *chan = d->priv;
-	int err, flags;
+	int err;
+	unsigned long flags;
 
 	if (!(chan->cosa->firmware_status & COSA_FW_START)) {
 		printk(KERN_NOTICE "%s: start the firmware first (status %d)\n",
@@ -682,7 +683,7 @@
 static int cosa_sppp_close(struct net_device *d)
 {
 	struct channel_data *chan = d->priv;
-	int flags;
+	unsigned long flags;
 
 	netif_stop_queue(d);
 	sppp_close(d);
@@ -779,7 +780,7 @@
 	char *buf, size_t count, loff_t *ppos)
 {
 	DECLARE_WAITQUEUE(wait, current);
-	int flags;
+	unsigned long flags;
 	struct channel_data *chan = (struct channel_data *)file->private_data;
 	struct cosa_data *cosa = chan->cosa;
 	char *kbuf;
@@ -856,7 +857,7 @@
 	DECLARE_WAITQUEUE(wait, current);
 	struct channel_data *chan = (struct channel_data *)file->private_data;
 	struct cosa_data *cosa = chan->cosa;
-	unsigned int flags;
+	unsigned long flags;
 	char *kbuf;
 
 	if (!(cosa->firmware_status & COSA_FW_START)) {
@@ -1245,7 +1246,7 @@
 static int cosa_start_tx(struct channel_data *chan, char *buf, int len)
 {
 	struct cosa_data *cosa = chan->cosa;
-	int flags;
+	unsigned long flags;
 #ifdef DEBUG_DATA
 	int i;
 
@@ -1271,7 +1272,7 @@
 
 static void put_driver_status(struct cosa_data *cosa)
 {
-	unsigned flags=0;
+	unsigned long flags;
 	int status;
 
 	spin_lock_irqsave(&cosa->lock, flags);
@@ -1339,7 +1340,7 @@
  */
 static void cosa_kick(struct cosa_data *cosa)
 {
-	unsigned flags, flags1;
+	unsigned long flags, flags1;
 	char *s = "(probably) IRQ";
 
 	if (test_bit(RXBIT, &cosa->rxtx))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wan/cycx_drv.c linux-2.4.20/drivers/net/wan/cycx_drv.c
--- linux-2.4.19/drivers/net/wan/cycx_drv.c	2001-09-30 19:26:07.000000000 +0000
+++ linux-2.4.20/drivers/net/wan/cycx_drv.c	2002-10-29 11:18:32.000000000 +0000
@@ -423,9 +423,9 @@
 
 	/* Verify firmware module format version */
 	if (cfm->version != CFM_VERSION) {
-		printk(KERN_ERR "%s:" __FUNCTION__ ": firmware format %u rejected! "
+		printk(KERN_ERR "%s:%s: firmware format %u rejected! "
 				"Expecting %u.\n",
-				modname, cfm->version, CFM_VERSION);
+				modname, __FUNCTION__, cfm->version, CFM_VERSION);
 		return -EINVAL;
 	}
 
@@ -437,8 +437,8 @@
 	if (((len - sizeof(cfm_t) - 1) != cfm->info.codesize) ||
 */
 	if (cksum != cfm->checksum) {
-		printk(KERN_ERR "%s:" __FUNCTION__ ": firmware corrupted!\n",
-				modname);
+		printk(KERN_ERR "%s:%s: firmware corrupted!\n",
+				modname, __FUNCTION__);
 		printk(KERN_ERR " cdsize = 0x%x (expected 0x%lx)\n",
 				len - sizeof(cfm_t) - 1, cfm->info.codesize);
                 printk(KERN_ERR " chksum = 0x%x (expected 0x%x)\n",
@@ -450,7 +450,7 @@
 
 	img_hdr = (cycx_header_t*)(((u8*)cfm) + sizeof(cfm_t) - 1);
 #ifdef FIRMWARE_DEBUG
-	printk(KERN_INFO "%s:" __FUNCTION__ ": image sizes\n", modname);
+	printk(KERN_INFO "%s:%s: image sizes\n", __FUNCTION__, modname);
 	printk(KERN_INFO " reset=%lu\n", img_hdr->reset_size);
 	printk(KERN_INFO "  data=%lu\n", img_hdr->data_size);
 	printk(KERN_INFO "  code=%lu\n", img_hdr->code_size);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wan/cycx_x25.c linux-2.4.20/drivers/net/wan/cycx_x25.c
--- linux-2.4.19/drivers/net/wan/cycx_x25.c	2001-09-14 21:39:59.000000000 +0000
+++ linux-2.4.20/drivers/net/wan/cycx_x25.c	2002-10-29 11:18:34.000000000 +0000
@@ -1446,7 +1446,7 @@
         unsigned char *ptr;
 
         if ((skb = dev_alloc_skb(1)) == NULL) {
-                printk(KERN_ERR __FUNCTION__ ": out of memory\n");
+                printk(KERN_ERR "%s: out of memory\n", __FUNCTION__);
                 return;
         }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wan/sbni.c linux-2.4.20/drivers/net/wan/sbni.c
--- linux-2.4.19/drivers/net/wan/sbni.c	2001-09-14 21:40:00.000000000 +0000
+++ linux-2.4.20/drivers/net/wan/sbni.c	2002-10-29 11:18:37.000000000 +0000
@@ -64,11 +64,6 @@
 #include <net/arp.h>
 #include <linux/pci.h>
 
-
-#ifndef MODULE
-#include <linux/string.h>
-#endif
-
 #include <linux/config.h>
 #include "sbni.h"
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wan/sdla.c linux-2.4.20/drivers/net/wan/sdla.c
--- linux-2.4.19/drivers/net/wan/sdla.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/wan/sdla.c	2002-10-29 11:18:40.000000000 +0000
@@ -695,7 +695,7 @@
 					save_flags(flags); 
 					cli();
 					SDLA_WINDOW(dev, addr);
-					pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK));
+					pbuf = (void *)(((unsigned long) dev->mem_start) + (addr & SDLA_ADDR_MASK));
 						sdla_write(dev, pbuf->buf_addr, skb->data, skb->len);
 						SDLA_WINDOW(dev, addr);
 					pbuf->opp_flag = 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wan/sdla_chdlc.c linux-2.4.20/drivers/net/wan/sdla_chdlc.c
--- linux-2.4.19/drivers/net/wan/sdla_chdlc.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/wan/sdla_chdlc.c	2002-10-29 11:18:40.000000000 +0000
@@ -2852,7 +2852,7 @@
 #endif
 		if(err) {
 			printk(KERN_INFO
-				"%s: Remove route %s failed, (err %d)\n",
+				"%s: Remove route %u.%u.%u.%u failed, (err %d)\n",
 					card->devname, NIPQUAD(remote_IP_addr),
 					err);
 		} else {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wan/sdla_ft1.c linux-2.4.20/drivers/net/wan/sdla_ft1.c
--- linux-2.4.19/drivers/net/wan/sdla_ft1.c	2001-09-13 23:04:43.000000000 +0000
+++ linux-2.4.20/drivers/net/wan/sdla_ft1.c	2002-10-29 11:18:33.000000000 +0000
@@ -23,7 +23,6 @@
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
-#include <linux/module.h>
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
 #include <linux/string.h>	/* inline memset(), etc. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wan/sdlamain.c linux-2.4.20/drivers/net/wan/sdlamain.c
--- linux-2.4.19/drivers/net/wan/sdlamain.c	2001-09-13 23:04:43.000000000 +0000
+++ linux-2.4.20/drivers/net/wan/sdlamain.c	2002-10-29 11:18:49.000000000 +0000
@@ -604,7 +604,13 @@
 
   	/* Reserve I/O region and schedule background task */
         if(card->hw.type != SDLA_S514 && !card->wandev.piggyback)
-                request_region(card->hw.port, card->hw.io_range, wandev->name);
+		if (!request_region(card->hw.port, card->hw.io_range, 
+				wandev->name)) {
+			printk(KERN_WARNING "port 0x%04x busy\n", card->hw.port);
+			release_hw(card);
+			wandev->state = WAN_UNCONFIGURED;
+			return -EBUSY;
+	  }
 
 	/* Only use the polling routine for the X25 protocol */
 	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wan/syncppp.c linux-2.4.20/drivers/net/wan/syncppp.c
--- linux-2.4.19/drivers/net/wan/syncppp.c	2001-09-13 23:04:43.000000000 +0000
+++ linux-2.4.20/drivers/net/wan/syncppp.c	2002-10-29 11:18:35.000000000 +0000
@@ -796,7 +796,7 @@
 		printk (">\n");
 	}
 	sp->obytes += skb->len;
-	/* Control is high priority so it doesnt get queued behind data */
+	/* Control is high priority so it doesn't get queued behind data */
 	skb->priority=TC_PRIO_CONTROL;
 	skb->dev = dev;
 	dev_queue_xmit(skb);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wavelan.c linux-2.4.20/drivers/net/wavelan.c
--- linux-2.4.19/drivers/net/wavelan.c	2002-02-25 19:38:03.000000000 +0000
+++ linux-2.4.20/drivers/net/wavelan.c	2002-10-29 11:18:37.000000000 +0000
@@ -2782,6 +2782,9 @@
 		    (unsigned char *) &nop.nop_h.ac_link,
 		    sizeof(nop.nop_h.ac_link));
 
+	/* Make sure the watchdog will keep quiet for a while */
+	dev->trans_start = jiffies;
+
 	/* Keep stats up to date. */
 	lp->stats.tx_bytes += length;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wavelan.p.h linux-2.4.20/drivers/net/wavelan.p.h
--- linux-2.4.19/drivers/net/wavelan.p.h	2001-10-12 21:21:18.000000000 +0000
+++ linux-2.4.20/drivers/net/wavelan.p.h	2002-10-29 11:18:49.000000000 +0000
@@ -143,7 +143,7 @@
  * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished this work.
  * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
  * 2.00 cards correctly (2.4 GHz with frequency selection).
- * David Hinds <dhinds@hyper.stanford.edu> integrated the whole in his
+ * David Hinds <dahinds@users.sourceforge.net> integrated the whole in his
  * PCMCIA package (and bug corrections).
  *
  * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
@@ -345,6 +345,10 @@
  *	- Fix spinlock stupid bugs that I left in. The driver is now SMP
  *		compliant and doesn't lockup at startup.
  *
+ * Changes made for release in 2.4.20 :
+ * ----------------------------------
+ *	- Set dev->trans_start to avoid filling the logs
+ *
  * Wishes & dreams:
  * ----------------
  *	- roaming (see Pcmcia driver)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wd.c linux-2.4.20/drivers/net/wd.c
--- linux-2.4.19/drivers/net/wd.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/wd.c	2002-10-29 11:18:32.000000000 +0000
@@ -365,9 +365,11 @@
 	if (ei_status.word16)
 		outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 
-#ifdef notdef
+#ifdef __BIG_ENDIAN
 	/* Officially this is what we are doing, but the readl() is faster */
+	/* unfortunately it isn't endian aware of the struct               */
 	isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+	hdr->count = le16_to_cpu(hdr->count);
 #else
 	((unsigned int*)hdr)[0] = isa_readl(hdr_start);
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/winbond-840.c linux-2.4.20/drivers/net/winbond-840.c
--- linux-2.4.19/drivers/net/winbond-840.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/winbond-840.c	2002-10-29 11:18:34.000000000 +0000
@@ -473,7 +473,7 @@
 		np->mii_if.full_duplex = 1;
 
 	if (np->mii_if.full_duplex)
-		np->mii_if.duplex_lock = 1;
+		np->mii_if.force_media = 1;
 
 	/* The chip-specific entries in the device structure. */
 	dev->open = &netdev_open;
@@ -773,7 +773,7 @@
 		duplex = (negotiated & LPA_100FULL) || ((negotiated & 0x02C0) == LPA_10FULL);
 		fasteth = negotiated & 0x380;
 	}
-	duplex |= np->mii_if.duplex_lock;
+	duplex |= np->mii_if.force_media;
 	/* remove fastether and fullduplex */
 	result = np->csr6 & ~0x20000200;
 	if (duplex)
@@ -1078,7 +1078,7 @@
 		np->tx_ring[entry].length |= DescEndRing;
 
 	/* Now acquire the irq spinlock.
-	 * The difficult race is the the ordering between
+	 * The difficult race is the ordering between
 	 * increasing np->cur_tx and setting DescOwn:
 	 * - if np->cur_tx is increased first the interrupt
 	 *   handler could consider the packet as transmitted
@@ -1136,13 +1136,7 @@
 			if (tx_status & 0x0002) np->stats.tx_fifo_errors++;
 			if ((tx_status & 0x0080) && np->mii_if.full_duplex == 0)
 				np->stats.tx_heartbeat_errors++;
-#ifdef ETHER_STATS
-			if (tx_status & 0x0100) np->stats.collisions16++;
-#endif
 		} else {
-#ifdef ETHER_STATS
-			if (tx_status & 0x0001) np->stats.tx_deferred++;
-#endif
 #ifndef final_version
 			if (debug > 3)
 				printk(KERN_DEBUG "%s: Transmit slot %d ok, Tx status %8.8x.\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wireless/Config.in linux-2.4.20/drivers/net/wireless/Config.in
--- linux-2.4.19/drivers/net/wireless/Config.in	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/wireless/Config.in	2002-10-29 11:18:35.000000000 +0000
@@ -13,8 +13,8 @@
 fi
 
 if [ "$CONFIG_PCI" = "y" ]; then
-   dep_tristate '    Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)' CONFIG_PLX_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL
-   dep_tristate '    Prism 2.5 PCI 802.11b adaptor support' CONFIG_PCI_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL
+   dep_tristate '    Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.) (EXPERIMENTAL)' CONFIG_PLX_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL
+   dep_tristate '    Prism 2.5 PCI 802.11b adaptor support (EXPERIMENTAL)' CONFIG_PCI_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL
 fi
 
 # If Pcmcia is compiled in, offer Pcmcia cards...
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wireless/airo.c linux-2.4.20/drivers/net/wireless/airo.c
--- linux-2.4.19/drivers/net/wireless/airo.c	2002-02-25 19:38:03.000000000 +0000
+++ linux-2.4.20/drivers/net/wireless/airo.c	2002-10-29 11:18:33.000000000 +0000
@@ -12,14 +12,13 @@
     (C) 1999 Benjamin Reed.  All Rights Reserved.  Permission to use
     code in the Developer's manual was granted for this driver by
     Aironet.  Major code contributions were received from Javier Achirica
-    and Jean Tourrilhes <jt@hpl.hp.com>.  Code was also integrated from
-    the Cisco Aironet driver for Linux.
+    <achirica@users.sourceforge.net> and Jean Tourrilhes <jt@hpl.hp.com>.
+    Code was also integrated from the Cisco Aironet driver for Linux.
 
 ======================================================================*/
 
 #include <linux/config.h>
 #include <linux/version.h>
-#include <asm/segment.h>
 #include <linux/init.h>
 
 #include <linux/kernel.h>
@@ -33,6 +32,7 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/in.h>
+#include <linux/tqueue.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -71,17 +71,26 @@
 /* Include Wireless Extension definition and check version - Jean II */
 #include <linux/wireless.h>
 #define WIRELESS_SPY		// enable iwspy support
-#if WIRELESS_EXT < 9
-#warning "Wireless extension v9 or newer required - please upgrade your kernel"
-#undef WIRELESS_EXT
-#undef WIRELESS_SPY
-#endif
-#define CISCO_EXT		// enable Cisco extensions
+#if WIRELESS_EXT > 12
+#include <net/iw_handler.h>	// New driver API
+#endif	/* WIRELESS_EXT > 12 */
 
+#define CISCO_EXT		// enable Cisco extensions
 #ifdef CISCO_EXT
 #include <linux/delay.h>
 #endif
 
+/* Support Cisco MIC feature */
+/* As this feature requires the AES encryption algorithm, it is not included
+   in the kernel tree. If you want to enable it, you need to download the
+   aes.h, aestab.h and mic.h files from the CVS at
+   http://sf.net/projects/airo-linux/ Put the files in the same directory
+   as airo.c and compile normally */
+#undef MICSUPPORT
+
+/* Hack to do some power saving */
+#define POWER_ON_DOWN
+
 /* As you can see this list is HUGH!
    I really don't know what a lot of these counts are about, but they
    are all here for completeness.  If the IGNLABEL macro is put in
@@ -194,6 +203,12 @@
 #ifndef RUN_AT
 #define RUN_AT(x) (jiffies+(x))
 #endif
+#if LINUX_VERSION_CODE < 0x020500
+static inline struct proc_dir_entry *PDE(const struct inode *inode)
+{
+	return inode->u.generic_ip;
+}
+#endif
 
 
 /* These variables are for insmod, since it seems that the rates
@@ -216,6 +231,8 @@
 		    the bap, needed on some older cards and buses. */
 static int adhoc;
 
+static int probe = 1;
+
 static int proc_uid /* = 0 */;
 
 static int proc_gid /* = 0 */;
@@ -250,6 +267,8 @@
 Older cards used to be limited to 2mbs (4).");
 MODULE_PARM(adhoc, "i");
 MODULE_PARM_DESC(adhoc, "If non-zero, the card will start in adhoc mode.");
+MODULE_PARM(probe, "i");
+MODULE_PARM_DESC(probe, "If zero, the driver won't start the card.");
 
 MODULE_PARM(proc_uid, "i");
 MODULE_PARM_DESC(proc_uid, "The uid that the /proc files will belong to.");
@@ -260,11 +279,9 @@
 MODULE_PARM(proc_perm, "i");
 MODULE_PARM_DESC(proc_perm, "The permission bits of the files in /proc");
 
-#include <asm/uaccess.h>
-
 /* This is a kind of sloppy hack to get this information to OUT4500 and
    IN4500.  I would be extremely interested in the situation where this
-   doesnt work though!!! */
+   doesn't work though!!! */
 static int do8bitIO = 0;
 
 /* Return codes */
@@ -273,18 +290,75 @@
 #define NO_PACKET -2
 
 /* Commands */
-#define NOP 0x0010
-#define MAC_ENABLE 0x0001
-#define MAC_DISABLE 0x0002
-#define CMD_LOSE_SYNC 0x0003 /* Not sure what this does... */
-#define CMD_ACCESS 0x0021
-#define CMD_ALLOCATETX 0x000a
-#define CMD_TRANSMIT 0x000b
-#define HOSTSLEEP 0x85
-#define CMD_SETMODE 0x0009
-#define CMD_ENABLEAUX 0x0111
-#define CMD_SOFTRESET 0x0004
-#define CMD_LISTBSS 0x0103
+#define NOP2		0x0000
+#define MAC_ENABLE	0x0001
+#define MAC_DISABLE	0x0002
+#define CMD_LOSE_SYNC	0x0003 /* Not sure what this does... */
+#define CMD_SOFTRESET	0x0004
+#define HOSTSLEEP	0x0005
+#define CMD_MAGIC_PKT	0x0006
+#define CMD_SETWAKEMASK	0x0007
+#define CMD_READCFG	0x0008
+#define CMD_SETMODE	0x0009
+#define CMD_ALLOCATETX	0x000a
+#define CMD_TRANSMIT	0x000b
+#define CMD_DEALLOCATETX 0x000c
+#define NOP		0x0010
+#define CMD_WORKAROUND	0x0011
+#define CMD_ACCESS	0x0021
+#define CMD_PCIBAP	0x0022
+#define CMD_PCIAUX	0x0023
+#define CMD_ALLOCBUF	0x0028
+#define CMD_GETTLV	0x0029
+#define CMD_PUTTLV	0x002a
+#define CMD_DELTLV	0x002b
+#define CMD_FINDNEXTTLV	0x002c
+#define CMD_PSPNODES	0x0030
+#define CMD_SETCW	0x0031    
+#define CMD_SETPCF	0x0032    
+#define CMD_SETPHYREG	0x003e
+#define CMD_TXTEST	0x003f
+#define MAC_ENABLETX	0x0101
+#define CMD_LISTBSS	0x0103
+#define CMD_SAVECFG	0x0108
+#define CMD_ENABLEAUX	0x0111
+#define CMD_WRITERID	0x0121
+#define CMD_USEPSPNODES	0x0130
+#define MAC_ENABLERX	0x0201
+
+/* Command errors */
+#define ERROR_QUALIF 0x00
+#define ERROR_ILLCMD 0x01
+#define ERROR_ILLFMT 0x02
+#define ERROR_INVFID 0x03
+#define ERROR_INVRID 0x04
+#define ERROR_LARGE 0x05
+#define ERROR_NDISABL 0x06
+#define ERROR_ALLOCBSY 0x07
+#define ERROR_NORD 0x0B
+#define ERROR_NOWR 0x0C
+#define ERROR_INVFIDTX 0x0D
+#define ERROR_TESTACT 0x0E
+#define ERROR_TAGNFND 0x12
+#define ERROR_DECODE 0x20
+#define ERROR_DESCUNAV 0x21
+#define ERROR_BADLEN 0x22
+#define ERROR_MODE 0x80
+#define ERROR_HOP 0x81
+#define ERROR_BINTER 0x82
+#define ERROR_RXMODE 0x83
+#define ERROR_MACADDR 0x84
+#define ERROR_RATES 0x85
+#define ERROR_ORDER 0x86
+#define ERROR_SCAN 0x87
+#define ERROR_AUTH 0x88
+#define ERROR_PSMODE 0x89
+#define ERROR_RTYPE 0x8A
+#define ERROR_DIVER 0x8B
+#define ERROR_SSID 0x8C
+#define ERROR_APLIST 0x8D
+#define ERROR_AUTOWAKE 0x8E
+#define ERROR_LEAP 0x8F
 
 /* Registers */
 #define COMMAND 0x00
@@ -336,8 +410,14 @@
 #define EV_LINK 0x80
 #define EV_AWAKE 0x100
 #define EV_UNKNOWN 0x800
-#define STATUS_INTS ( EV_AWAKE | EV_LINK | EV_TXEXC | EV_TX | EV_RX)
+#define EV_MIC 0x1000 /* Message Integrity Check Interrupt */
+#define STATUS_INTS ( EV_AWAKE | EV_LINK | EV_TXEXC | EV_TX | EV_RX | EV_MIC )
+
+#ifdef CHECK_UNKNOWN_INTS
 #define IGNORE_INTS ( EV_CMD | EV_UNKNOWN)
+#else
+#define IGNORE_INTS (~STATUS_INTS)
+#endif
 
 /* The RIDs */
 #define RID_CAPABILITIES 0xFF00
@@ -360,18 +440,21 @@
 #define RID_LEAPUSERNAME 0xFF23
 #define RID_LEAPPASSWORD 0xFF24
 #define RID_STATUS     0xFF50
-#define RID_UNKNOWN52  0xFF52
+#define RID_BEACON_HST 0xFF51
+#define RID_BUSY_HST   0xFF52
+#define RID_RETRIES_HST 0xFF53
 #define RID_UNKNOWN54  0xFF54
 #define RID_UNKNOWN55  0xFF55
 #define RID_UNKNOWN56  0xFF56
+#define RID_MIC        0xFF57
 #define RID_STATS16    0xFF60
 #define RID_STATS16DELTA 0xFF61
 #define RID_STATS16DELTACLEAR 0xFF62
 #define RID_STATS      0xFF68
 #define RID_STATSDELTA 0xFF69
 #define RID_STATSDELTACLEAR 0xFF6A
-#define RID_UNKNOWN70  0xFF70
-#define RID_UNKNOWN71  0xFF71
+#define RID_ECHOTEST_RID 0xFF70
+#define RID_ECHOTEST_RESULTS 0xFF71
 #define RID_BSSLISTFIRST 0xFF72
 #define RID_BSSLISTNEXT  0xFF73
 
@@ -403,7 +486,7 @@
 typedef struct {
 	u16 len;
 	u16 kindex;
-	u8 mac[6];
+	u8 mac[ETH_ALEN];
 	u16 klen;
 	u8 key[16];
 } WepKeyRid;
@@ -442,6 +525,7 @@
 #define MODE_ETHER_LLC (1<<12) /* enable ethernet LLC */
 #define MODE_LEAF_NODE (1<<13) /* enable leaf node bridge */
 #define MODE_CF_POLLABLE (1<<14) /* enable CF pollable */
+#define MODE_MIC (1<<15) /* enable MIC */
 	u16 rmode; /* receive mode */
 #define RXMODE_BC_MC_ADDR 0
 #define RXMODE_BC_ADDR 1 /* ignore multicasts */
@@ -453,7 +537,7 @@
 #define RXMODE_NORMALIZED_RSSI (1<<9) /* return normalized RSSI */
 	u16 fragThresh;
 	u16 rtsThres;
-	u8 macAddr[6];
+	u8 macAddr[ETH_ALEN];
 	u8 rates[8];
 	u16 shortRetryLimit;
 	u16 longRetryLimit;
@@ -548,14 +632,14 @@
 
 typedef struct {
 	u16 len;
-	u8 mac[6];
+	u8 mac[ETH_ALEN];
 	u16 mode;
 	u16 errorCode;
 	u16 sigQuality;
 	u16 SSIDlen;
 	char SSID[32];
 	char apName[16];
-	char bssid[4][6];
+	char bssid[4][ETH_ALEN];
 	u16 beaconPeriod;
 	u16 dimPeriod;
 	u16 atimDuration;
@@ -570,7 +654,9 @@
 	u16 currentXmitRate;
 	u16 apDevExtensions;
 	u16 normalizedSignalStrength;
-	u16 _reserved[10];
+	u16 _reserved1;
+	u8 apIP[4];
+	u16 _reserved[7];
 } StatusRid;
 
 typedef struct {
@@ -582,7 +668,7 @@
 
 typedef struct {
 	u16 len;
-	u8 ap[4][6];
+	u8 ap[4][ETH_ALEN];
 } APListRid;
 
 typedef struct {
@@ -593,11 +679,11 @@
 	char manName[32];
 	char prodName[16];
 	char prodVer[8];
-	char factoryAddr[6];
-	char aironetAddr[6];
+	char factoryAddr[ETH_ALEN];
+	char aironetAddr[ETH_ALEN];
 	u16 radioType;
 	u16 country;
-	char callid[6];
+	char callid[ETH_ALEN];
 	char supportedRates[8];
 	char rxDiversity;
 	char txDiversity;
@@ -611,6 +697,7 @@
 	u16 softCap;
 	u16 bootBlockVer;
 	u16 requiredHard;
+	u16 extSoftCap;
 } CapabilityRid;
 
 typedef struct {
@@ -620,7 +707,7 @@
 #define RADIO_DS 2 /* Direct sequence radio type */
 #define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */
   u16 radioType;
-  u8 bssid[6]; /* Mac address of the BSS */
+  u8 bssid[ETH_ALEN]; /* Mac address of the BSS */
   u8 zero;
   u8 ssidLen;
   u8 ssid[32];
@@ -653,6 +740,37 @@
   tdsRssiEntry x[256];
 } tdsRssiRid;
 
+typedef struct {
+	u16 len;
+	u16 state;
+	u16 multicastValid;
+	u8  multicast[16];
+	u16 unicastValid;
+	u8  unicast[16];
+} MICRid;
+
+typedef struct {
+	u16 typelen;
+
+	union {
+	    u8 snap[8];
+	    struct {
+		u8 dsap;
+		u8 ssap;
+		u8 control;
+		u8 orgcode[3];
+		u8 fieldtype[2];
+	    } llc;
+	} u;
+	u32 mic;
+	u32 seq;
+} MICBuffer;
+
+typedef struct {
+	u8 da[ETH_ALEN];
+	u8 sa[ETH_ALEN];
+} etherHead;
+
 #pragma pack()
 
 #define TXCTL_TXOK (1<<1) /* report if tx is ok */
@@ -677,6 +795,10 @@
 #else /* SIOCIWFIRSTPRIV */
 #define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
 #endif /* SIOCIWFIRSTPRIV */
+/* This may be wrong. When using the new SIOCIWFIRSTPRIV range, we probably
+ * should use only "GET" ioctls (last bit set to 1). "SET" ioctls are root
+ * only and don't return the modified struct ifreq to the application which
+ * is usually a problem. - Jean II */
 #define AIROIOCTL	SIOCIWFIRSTPRIV
 #define AIROIDIFC 	AIROIOCTL + 1
 
@@ -693,6 +815,9 @@
 #define AIROGSTAT		8
 #define AIROGSTATSC32		9
 #define AIROGSTATSD32		10
+#define AIROGMICRID		11
+#define AIROGMICSTATS		12
+#define AIROGFLAGS		13
 
 /* Leave gap of 40 commands after AIROGSTATSD32 for future */
 
@@ -728,6 +853,45 @@
 } aironet_ioctl;
 #endif /* CISCO_EXT */
 
+#define NUM_MODULES       2
+#define MIC_MSGLEN_MAX    2400
+#define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX
+
+typedef struct {
+	u32   size;            // size
+	u8    enabled;         // MIC enabled or not
+	u32   rxSuccess;       // successful packets received
+	u32   rxIncorrectMIC;  // pkts dropped due to incorrect MIC comparison
+	u32   rxNotMICed;      // pkts dropped due to not being MIC'd
+	u32   rxMICPlummed;    // pkts dropped due to not having a MIC plummed
+	u32   rxWrongSequence; // pkts dropped due to sequence number violation
+	u32   reserve[32];
+} mic_statistics;
+
+typedef struct {
+	u32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2];
+	u64 accum;	// accumulated mic, reduced to u32 in final()
+	int position;	// current position (byte offset) in message
+	union {
+		u8  d8[4];
+		u32 d32;
+	} part;	// saves partial message word across update() calls
+} emmh32_context;
+
+typedef struct {
+	emmh32_context seed;	    // Context - the seed
+	u32		 rx;	    // Received sequence number
+	u32		 tx;	    // Tx sequence number
+	u32		 window;    // Start of window
+	u8		 valid;	    // Flag to say if context is valid or not
+	u8		 key[16];
+} miccntx;
+
+typedef struct {
+	miccntx mCtx;		// Multicast context
+	miccntx uCtx;		// Unicast context
+} mic_module;
+
 #ifdef WIRELESS_EXT
 // Frequency list (map channels to frequencies)
 const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
@@ -740,20 +904,38 @@
 	u16	len;
 	u8	key[16];	/* 40-bit and 104-bit keys */
 } wep_key_t;
+
+/* Backward compatibility */
+#ifndef IW_ENCODE_NOKEY
+#define IW_ENCODE_NOKEY         0x0800  /* Key is write only, so not present */
+#define IW_ENCODE_MODE  (IW_ENCODE_DISABLED | IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)
+#endif /* IW_ENCODE_NOKEY */
+
+#if WIRELESS_EXT > 12
+/* List of Wireless Handlers (new API) */
+static const struct iw_handler_def	airo_handler_def;
+#else	/* WIRELESS_EXT > 12 */
+/* More Wireless Extensions backward compatibility */
+/* Part of iw_handler prototype we need (apart that we don't need it) */
+struct iw_request_info {};
+#endif	/* WIRELESS_EXT > 12 */
 #endif /* WIRELESS_EXT */
 
-static const char version[] = "airo.c 0.3 (Ben Reed & Javier Achirica)";
+static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)";
 
 struct airo_info;
 
 static int get_dec_u16( char *buffer, int *start, int limit );
 static void OUT4500( struct airo_info *, u16 register, u16 value );
 static unsigned short IN4500( struct airo_info *, u16 register );
-static u16 setup_card(struct airo_info*, u8 *mac, ConfigRid *);
+static u16 setup_card(struct airo_info*, u8 *mac);
+static int enable_MAC( struct airo_info *ai, Resp *rsp );
+static void disable_MAC(struct airo_info *ai);
 static void enable_interrupts(struct airo_info*);
 static void disable_interrupts(struct airo_info*);
-static u16 lock_issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
 static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
+static u16 sendcommand(struct airo_info *ai, Cmd *pCmd);
+static void completecommand(struct airo_info *ai, Resp *pRsp);
 static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap);
 static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
 			int whichbap);
@@ -767,9 +949,9 @@
 			   *pBuf, int len);
 static int do_writerid( struct airo_info*, u16 rid, const void *rid_data,
 			int len );
-static u16 transmit_allocate(struct airo_info*, int lenPayload);
-static int transmit_802_3_packet(struct airo_info*, u16 TxFid, char
-				 *pPacket, int len);
+static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw);
+static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket);
+static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket);
 
 static void airo_interrupt( int irq, void* dev_id, struct pt_regs
 			    *regs);
@@ -782,6 +964,12 @@
 static int writerids(struct net_device *dev, aironet_ioctl *comp);
 int flashcard(struct net_device *dev, aironet_ioctl *comp);
 #endif /* CISCO_EXT */
+#ifdef MICSUPPORT
+static void micinit(struct airo_info *ai, MICRid *micr);
+static void micsetup(struct airo_info *ai);
+static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len);
+static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen);
+#endif
 
 struct airo_info {
 	struct net_device_stats	stats;
@@ -793,31 +981,51 @@
 	int                           fids[MAX_FIDS];
 	int registered;
 	ConfigRid config;
-	u16 authtype; // Used with auto_wep
+	int need_commit;	// Need to set config
 	char keyindex; // Used with auto wep
 	char defindex; // Used with auto wep
 	struct timer_list timer;
 	struct proc_dir_entry *proc_entry;
 	struct airo_info *next;
         spinlock_t aux_lock;
-        spinlock_t main_lock;
-        int flags;
-#define FLAG_PROMISC   IFF_PROMISC
-#define FLAG_RADIO_OFF 0x02
+        unsigned long flags;
+#define FLAG_PROMISC   IFF_PROMISC	/* 0x100 - include/linux/if.h */
+#define FLAG_RADIO_OFF 0x02		/* User disabling of MAC */
+#define FLAG_RADIO_DOWN 0x08		/* ifup/ifdown disabling of MAC */
+#define FLAG_LOCKED    2		/* 0x04 - use as a bit offset */
+#define FLAG_FLASHING  0x10
+#define FLAG_ADHOC        0x01 /* Needed by MIC */
+#define FLAG_MIC_CAPABLE  0x20
+#define FLAG_UPDATE_MULTI 0x40
+#define FLAG_UPDATE_UNI   0x80
+#define FLAG_802_11    0x200
 	int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
 			int whichbap);
-	int (*header_parse)(struct sk_buff*, unsigned char *);
 	unsigned short *flash;
 	tdsRssiEntry *rssi;
+	struct semaphore sem;
+	struct task_struct *task;
+	struct tq_struct promisc_task;
+	struct {
+		struct sk_buff *skb;
+		int fid;
+		struct tq_struct task;
+	} xmit, xmit11;
+	struct net_device *wifidev;
 #ifdef WIRELESS_EXT
-	int			need_commit;	// Need to set config
 	struct iw_statistics	wstats;		// wireless stats
+	unsigned long		scan_timestamp;	/* Time started to scan */
+	struct tq_struct	event_task;
 #ifdef WIRELESS_SPY
 	int			spy_number;
-	u_char			spy_address[IW_MAX_SPY][6];
+	u_char			spy_address[IW_MAX_SPY][ETH_ALEN];
 	struct iw_quality	spy_stat[IW_MAX_SPY];
 #endif /* WIRELESS_SPY */
 #endif /* WIRELESS_EXT */
+	/* MIC stuff */
+	mic_module		mod[2];
+	mic_statistics		micstats;
+	struct tq_struct 	mic_task;
 };
 
 static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
@@ -830,6 +1038,10 @@
 static int takedown_proc_entry( struct net_device *dev,
 				struct airo_info *apriv );
 
+#ifdef MICSUPPORT
+#include "mic.h"
+#endif
+
 static int readBSSListRid(struct airo_info *ai, int first,
 		      BSSListRid *list) {
 	int rc;
@@ -839,13 +1051,17 @@
 	if (first == 1) {
 			memset(&cmd, 0, sizeof(cmd));
 			cmd.cmd=CMD_LISTBSS;
-			lock_issuecommand(ai, &cmd, &rsp);
+			if (down_interruptible(&ai->sem))
+				return -ERESTARTSYS;
+			issuecommand(ai, &cmd, &rsp);
+			up(&ai->sem);
 			/* Let the command take effect */
 			set_current_state (TASK_INTERRUPTIBLE);
+			ai->task = current;
 			schedule_timeout (3*HZ);
+			ai->task = NULL;
 		}
-	rc = PC4500_readrid(ai,
-		            first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT,
+	rc = PC4500_readrid(ai, first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT,
 			    list, sizeof(*list));
 
 	list->len = le16_to_cpu(list->len);
@@ -877,10 +1093,10 @@
 	wkr.len = cpu_to_le16(wkr.len);
 	wkr.kindex = cpu_to_le16(wkr.kindex);
 	wkr.klen = cpu_to_le16(wkr.klen);
-	rc = do_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr));
+	rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr));
 	if (rc!=SUCCESS) printk(KERN_ERR "airo:  WEP_TEMP set %x\n", rc);
 	if (perm) {
-		rc = do_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr));
+		rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr));
 		if (rc!=SUCCESS) {
 			printk(KERN_ERR "airo:  WEP_PERM set %x\n", rc);
 		}
@@ -907,29 +1123,61 @@
 	for(i = 0; i < 3; i++) {
 		ssidr.ssids[i].len = cpu_to_le16(ssidr.ssids[i].len);
 	}
-	rc = do_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr));
+	rc = PC4500_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr));
 	return rc;
 }
-static int readConfigRid(struct airo_info*ai, ConfigRid *cfgr) {
-	int rc = PC4500_readrid(ai, RID_ACTUALCONFIG, cfgr, sizeof(*cfgr));
+static int readConfigRid(struct airo_info*ai) {
+	int rc;
 	u16 *s;
+	ConfigRid cfg;
 
-	for(s = &cfgr->len; s <= &cfgr->rtsThres; s++) *s = le16_to_cpu(*s);
+	if (ai->config.len)
+		return SUCCESS;
 
-	for(s = &cfgr->shortRetryLimit; s <= &cfgr->radioType; s++)
+	rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg));
+	if (rc != SUCCESS)
+		return rc;
+
+	for(s = &cfg.len; s <= &cfg.rtsThres; s++) *s = le16_to_cpu(*s);
+
+	for(s = &cfg.shortRetryLimit; s <= &cfg.radioType; s++)
 		*s = le16_to_cpu(*s);
 
-	for(s = &cfgr->txPower; s <= &cfgr->radioSpecific; s++)
+	for(s = &cfg.txPower; s <= &cfg.radioSpecific; s++)
 		*s = le16_to_cpu(*s);
 
-	for(s = &cfgr->arlThreshold; s <= &cfgr->autoWake; s++)
+	for(s = &cfg.arlThreshold; s <= &cfg.autoWake; s++)
 		*s = le16_to_cpu(*s);
 
-	return rc;
+	ai->config = cfg;
+	return SUCCESS;
 }
-static int writeConfigRid(struct airo_info*ai, ConfigRid *pcfgr) {
+static inline void checkThrottle(struct airo_info *ai) {
+	int i;
+/* Old hardware had a limit on encryption speed */
+	if (ai->config.authType != AUTH_OPEN && maxencrypt) {
+		for(i=0; i<8; i++) {
+			if (ai->config.rates[i] > maxencrypt) {
+				ai->config.rates[i] = 0;
+			}
+		}
+	}
+}
+static int writeConfigRid(struct airo_info*ai) {
 	u16 *s;
-	ConfigRid cfgr = *pcfgr;
+	ConfigRid cfgr;
+
+	if (!ai->need_commit)
+		return SUCCESS;
+
+	ai->need_commit = 0;
+	checkThrottle(ai);
+	if ((cfgr.opmode & 0xFF) == MODE_STA_IBSS)
+		ai->flags |= FLAG_ADHOC;
+	else
+		ai->flags &= ~FLAG_ADHOC;
+
+	cfgr = ai->config;
 
 	for(s = &cfgr.len; s <= &cfgr.rtsThres; s++) *s = cpu_to_le16(*s);
 
@@ -942,7 +1190,7 @@
 	for(s = &cfgr.arlThreshold; s <= &cfgr.autoWake; s++)
 		*s = cpu_to_le16(*s);
 
-	return do_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr));
+	return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr));
 }
 static int readStatusRid(struct airo_info*ai, StatusRid *statr) {
 	int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr));
@@ -964,7 +1212,7 @@
 static int writeAPListRid(struct airo_info*ai, APListRid *aplr) {
 	int rc;
 	aplr->len = cpu_to_le16(aplr->len);
-	rc = do_writerid(ai, RID_APLIST, aplr, sizeof(*aplr));
+	rc = PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr));
 	return rc;
 }
 static int readCapabilityRid(struct airo_info*ai, CapabilityRid *capr) {
@@ -990,19 +1238,117 @@
 
 static int airo_open(struct net_device *dev) {
 	struct airo_info *info = dev->priv;
+	Resp rsp;
+
+	if (info->flags & FLAG_FLASHING)
+		return -EIO;
+
+	/* Make sure the card is configured.
+	 * Wireless Extensions may postpone config changes until the card
+	 * is open (to pipeline changes and speed-up card setup). If
+	 * those changes are not yet commited, do it now - Jean II */
+	if(info->need_commit) {
+		disable_MAC(info);
+		writeConfigRid(info);
+	}
 
-	enable_interrupts(info);
+	if (info->wifidev != dev) {
+		/* Power on the MAC controller (which may have been disabled) */
+		info->flags &= ~FLAG_RADIO_DOWN;
+		enable_interrupts(info);
+	}
+	enable_MAC(info, &rsp);
 
 	netif_start_queue(dev);
 	return 0;
 }
 
+static void get_tx_error(struct airo_info *ai, u32 fid)
+{
+	u16 status;
+
+	if (bap_setup(ai, ai->fids[fid] & 0xffff, 4, BAP0) == SUCCESS) {
+		bap_read(ai, &status, 2, BAP0);
+		if (le16_to_cpu(status) & 2) /* Too many retries */
+			ai->stats.tx_aborted_errors++;
+		if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */
+			ai->stats.tx_heartbeat_errors++;
+		if (le16_to_cpu(status) & 8) /* Aid fail */
+			{ }
+		if (le16_to_cpu(status) & 0x10) /* MAC disabled */
+			ai->stats.tx_carrier_errors++;
+		if (le16_to_cpu(status) & 0x20) /* Association lost */
+			{ }
+#if WIRELESS_EXT > 13
+		/* We produce a TXDROP event only for retry or lifetime
+		 * exceeded, because that's the only status that really mean
+		 * that this particular node went away.
+		 * Other errors means that *we* screwed up. - Jean II */
+		if ((le16_to_cpu(status) & 2) ||
+		     (le16_to_cpu(status) & 4)) {
+			union iwreq_data	wrqu;
+			char junk[0x18];
+
+			/* Faster to skip over useless data than to do
+			 * another bap_setup(). We are at offset 0x6 and
+			 * need to go to 0x18 and read 6 bytes - Jean II */
+			bap_read(ai, (u16 *) junk, 0x18, BAP0);
+
+			/* Copy 802.11 dest address.
+			 * We use the 802.11 header because the frame may
+			 * not be 802.3 or may be mangled...
+			 * In Ad-Hoc mode, it will be the node address.
+			 * In managed mode, it will be most likely the AP addr
+			 * User space will figure out how to convert it to
+			 * whatever it needs (IP address or else).
+			 * - Jean II */
+			memcpy(wrqu.addr.sa_data, junk + 0x12, ETH_ALEN);
+			wrqu.addr.sa_family = ARPHRD_ETHER;
+
+			/* Send event to user space */
+			wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL);
+		}
+#endif /* WIRELESS_EXT > 13 */
+	}
+}
+
+static void airo_do_xmit(struct net_device *dev) {
+	u16 status;
+	int i;
+	struct airo_info *priv = dev->priv;
+	struct sk_buff *skb = priv->xmit.skb;
+	int fid = priv->xmit.fid;
+	u32 *fids = priv->fids;
+
+	if (down_trylock(&priv->sem) != 0) {
+		netif_stop_queue(dev);
+		priv->xmit.task.routine = (void (*)(void *))airo_do_xmit;
+		priv->xmit.task.data = (void *)dev;
+		schedule_task(&priv->xmit.task);
+		return;
+	}
+	status = transmit_802_3_packet (priv, fids[fid], skb->data);
+	up(&priv->sem);
+
+	i = 0;
+	if ( status == SUCCESS ) {
+		dev->trans_start = jiffies;
+		for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++);
+	} else {
+		priv->fids[fid] &= 0xffff;
+		priv->stats.tx_window_errors++;
+	}
+	if (i < MAX_FIDS / 2)
+		netif_wake_queue(dev);
+	else
+		netif_stop_queue(dev);
+	dev_kfree_skb(skb);
+}
+
 static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
 	s16 len;
-	u16 status;
-	u32 flags;
-	int i,j;
-	struct airo_info *priv = (struct airo_info*)dev->priv;
+	int i;
+	struct airo_info *priv = dev->priv;
 	u32 *fids = priv->fids;
 
 	if ( skb == NULL ) {
@@ -1011,38 +1357,88 @@
 	}
 
 	/* Find a vacant FID */
-	spin_lock_irqsave(&priv->main_lock, flags);
-	for( j = 0, i = -1; j < MAX_FIDS; j++ ) {
-		if ( !( fids[j] & 0xffff0000 ) ) {
-			if ( i == -1 ) i = j;
-			else break;
-		}
-	}
-	if ( j == MAX_FIDS ) netif_stop_queue(dev);
-	if ( i == -1 ) {
+	for( i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++ );
+
+	if ( i == MAX_FIDS / 2 ) {
 		priv->stats.tx_fifo_errors++;
-		goto tx_done;
+		dev_kfree_skb(skb);
+	} else {
+		/* check min length*/
+		len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	        /* Mark fid as used & save length for later */
+		fids[i] |= (len << 16);
+		priv->xmit.skb = skb;
+		priv->xmit.fid = i;
+		airo_do_xmit(dev);
 	}
+	return 0;
+}
+
+static void airo_do_xmit11(struct net_device *dev) {
+	u16 status;
+	int i;
+	struct airo_info *priv = dev->priv;
+	struct sk_buff *skb = priv->xmit11.skb;
+	int fid = priv->xmit11.fid;
+	u32 *fids = priv->fids;
 
-	len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; /* check min length*/
-	status = transmit_802_3_packet( priv, fids[i], skb->data, len );
+	if (down_trylock(&priv->sem) != 0) {
+		netif_stop_queue(dev);
+		priv->xmit11.task.routine = (void (*)(void *))airo_do_xmit11;
+		priv->xmit11.task.data = (void *)dev;
+		schedule_task(&priv->xmit11.task);
+		return;
+	}
+	status = transmit_802_11_packet (priv, fids[fid], skb->data);
+	up(&priv->sem);
 
+	i = MAX_FIDS / 2;
 	if ( status == SUCCESS ) {
-                /* Mark fid as used & save length for later */
-		fids[i] |= (len << 16);
 		dev->trans_start = jiffies;
+		for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++);
 	} else {
+		priv->fids[fid] &= 0xffff;
 		priv->stats.tx_window_errors++;
 	}
- tx_done:
-	spin_unlock_irqrestore(&priv->main_lock, flags);
+	if (i < MAX_FIDS)
+		netif_wake_queue(dev);
+	else
+		netif_stop_queue(dev);
 	dev_kfree_skb(skb);
+}
+
+static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
+	s16 len;
+	int i;
+	struct airo_info *priv = dev->priv;
+	u32 *fids = priv->fids;
+
+	if ( skb == NULL ) {
+		printk( KERN_ERR "airo:  skb == NULL!!!\n" );
+		return 0;
+	}
+
+	/* Find a vacant FID */
+	for( i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++ );
+
+	if ( i == MAX_FIDS ) {
+		priv->stats.tx_fifo_errors++;
+		dev_kfree_skb(skb);
+	} else {
+		/* check min length*/
+		len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	        /* Mark fid as used & save length for later */
+		fids[i] |= (len << 16);
+		priv->xmit11.skb = skb;
+		priv->xmit11.fid = i;
+		airo_do_xmit11(dev);
+	}
 	return 0;
 }
 
 struct net_device_stats *airo_get_stats(struct net_device *dev)
 {
-	struct airo_info *local = (struct airo_info*) dev->priv;
+	struct airo_info *local =  dev->priv;
 	StatsRid stats_rid;
 	u32 *vals = stats_rid.vals;
 
@@ -1064,27 +1460,44 @@
 	local->stats.rx_frame_errors = vals[2];
 	local->stats.rx_fifo_errors = vals[0];
 
-	return (&local->stats);
+	return &local->stats;
 }
 
-static int enable_MAC( struct airo_info *ai, Resp *rsp );
-static void disable_MAC(struct airo_info *ai);
+static void airo_end_promisc(struct airo_info *ai) {
+	Resp rsp;
 
-static void airo_set_multicast_list(struct net_device *dev) {
-	struct airo_info *ai = (struct airo_info*)dev->priv;
+	if ((IN4500(ai, EVSTAT) & EV_CMD) != 0) {
+		completecommand(ai, &rsp);
+		up(&ai->sem);
+	} else {
+		ai->promisc_task.routine = (void (*)(void *))airo_end_promisc;
+		ai->promisc_task.data = (void *)ai;
+		schedule_task(&ai->promisc_task);
+	}
+}
+
+static void airo_set_promisc(struct airo_info *ai) {
 	Cmd cmd;
-	Resp rsp;
 
-	/* For some reason this command takes a lot of time (~20 ms) and it's
-	 * run in an interrupt handler, so we'd better be sure we needed it
-	 * before executing it.
-	 */
-	if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
+	if (down_trylock(&ai->sem) == 0) {
 		memset(&cmd, 0, sizeof(cmd));
 		cmd.cmd=CMD_SETMODE;
-		cmd.parm0=(dev->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
-		lock_issuecommand(ai, &cmd, &rsp);
-		ai->flags^=IFF_PROMISC;
+		cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
+		sendcommand(ai, &cmd);
+		airo_end_promisc(ai);
+	} else {
+		ai->promisc_task.routine = (void (*)(void *))airo_set_promisc;
+		ai->promisc_task.data = (void *)ai;
+		schedule_task(&ai->promisc_task);
+	}
+}
+
+static void airo_set_multicast_list(struct net_device *dev) {
+	struct airo_info *ai = dev->priv;
+
+	if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
+		ai->flags ^= IFF_PROMISC;
+		airo_set_promisc(ai);
 	}
 
 	if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) {
@@ -1094,14 +1507,18 @@
 
 static int airo_set_mac_address(struct net_device *dev, void *p)
 {
-	struct airo_info *ai = (struct airo_info*)dev->priv;
+	struct airo_info *ai = dev->priv;
 	struct sockaddr *addr = p;
-	ConfigRid cfg;
+	Resp rsp;
 
-	readConfigRid (ai, &cfg);
-	memcpy (cfg.macAddr, addr->sa_data, dev->addr_len);
-	writeConfigRid (ai, &cfg);
-	memcpy (dev->dev_addr, addr->sa_data, dev->addr_len);
+	memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len);
+	ai->need_commit = 1;
+	disable_MAC(ai);
+	writeConfigRid (ai);
+	enable_MAC(ai, &rsp);
+	memcpy (ai->dev->dev_addr, addr->sa_data, dev->addr_len);
+	if (ai->wifidev)
+		memcpy (ai->wifidev->dev_addr, addr->sa_data, dev->addr_len);
 	return 0;
 }
 
@@ -1115,10 +1532,22 @@
 
 
 static int airo_close(struct net_device *dev) {
-	struct airo_info *ai = (struct airo_info*)dev->priv;
+	struct airo_info *ai = dev->priv;
 
 	netif_stop_queue(dev);
-	disable_interrupts( ai );
+
+	if (ai->wifidev != dev) {
+#ifdef POWER_ON_DOWN
+		/* Shut power to the card. The idea is that the user can save
+		 * power when he doesn't need the card with "ifconfig down".
+		 * That's the method that is most friendly towards the network
+		 * stack (i.e. the network stack won't try to broadcast
+		 * anything on the interface and routes are gone. Jean II */
+		ai->flags |= FLAG_RADIO_DOWN;
+		disable_MAC(ai);
+#endif
+		disable_interrupts( ai );
+	}
 	return 0;
 }
 
@@ -1126,7 +1555,8 @@
 
 void stop_airo_card( struct net_device *dev, int freeres )
 {
-	struct airo_info *ai = (struct airo_info*)dev->priv;
+	struct airo_info *ai = dev->priv;
+	flush_scheduled_tasks();
 	if (ai->flash)
 		kfree(ai->flash);
 	if (ai->rssi)
@@ -1134,6 +1564,11 @@
 	takedown_proc_entry( dev, ai );
 	if (ai->registered) {
 		unregister_netdev( dev );
+		if (ai->wifidev) {
+			unregister_netdev(ai->wifidev);
+			kfree(ai->wifidev);
+			ai->wifidev = 0;
+		}
 		ai->registered = 0;
 	}
 	disable_interrupts(ai);
@@ -1147,8 +1582,73 @@
 	kfree( dev );
 }
 
+EXPORT_SYMBOL(stop_airo_card);
+
 static int add_airo_dev( struct net_device *dev );
 
+int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
+{
+	memcpy(haddr, skb->mac.raw + 10, ETH_ALEN);
+	return ETH_ALEN;
+}
+
+static void wifi_setup(struct net_device *dev, struct net_device *ethdev)
+{
+	struct airo_info *ai = ethdev->priv;
+	dev->priv = ai;
+	dev->hard_header        = 0;
+	dev->rebuild_header     = 0;
+	dev->hard_header_cache  = 0;
+	dev->header_cache_update= 0;
+
+	dev->hard_header_parse  = wll_header_parse;
+	dev->hard_start_xmit = &airo_start_xmit11;
+	dev->get_stats = &airo_get_stats;
+	dev->set_mac_address = &airo_set_mac_address;
+	dev->do_ioctl = &airo_ioctl;
+#ifdef WIRELESS_EXT
+	dev->get_wireless_stats = airo_get_wireless_stats;
+#if WIRELESS_EXT > 12
+	dev->wireless_handlers = (struct iw_handler_def *)&airo_handler_def;
+#endif /* WIRELESS_EXT > 12 */
+#endif /* WIRELESS_EXT */
+	dev->change_mtu = &airo_change_mtu;
+	dev->open = &airo_open;
+	dev->stop = &airo_close;
+	dev->irq = ethdev->irq;
+	dev->base_addr = ethdev->base_addr;
+
+	dev->type               = ARPHRD_IEEE80211;
+	dev->hard_header_len    = ETH_HLEN;
+	dev->mtu                = 2312;
+	dev->addr_len           = ETH_ALEN;
+	memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len);
+	dev->tx_queue_len       = 100; 
+
+	memset(dev->broadcast,0xFF, ETH_ALEN);
+
+	dev->flags              = IFF_BROADCAST|IFF_MULTICAST;
+}
+
+static struct net_device *init_wifidev(struct airo_info *ai,
+					struct net_device *ethdev)
+{
+	int err;
+	struct net_device *dev = (struct net_device*)kmalloc(sizeof *dev,GFP_KERNEL);
+	if (!dev) return 0;
+	memset(dev, 0, sizeof(*dev));
+
+	strcpy(dev->name, "wifi%d");
+	dev->priv = ai;
+	wifi_setup(dev, ethdev);
+	err = register_netdev(dev);
+	if (err<0) {
+		kfree(dev);
+		return 0;
+	}
+	return dev;
+}
+
 struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
 {
 	struct net_device *dev;
@@ -1167,11 +1667,13 @@
 	}
 
 	ai = dev->priv;
+	ai->wifidev = 0;
 	ai->registered = 0;
         ai->dev = dev;
 	ai->aux_lock = SPIN_LOCK_UNLOCKED;
-	ai->main_lock = SPIN_LOCK_UNLOCKED;
-	ai->header_parse = dev->hard_header_parse;
+	sema_init(&ai->sem, 1);
+	ai->need_commit = 0;
+	ai->config.len = 0;
 	rc = add_airo_dev( dev );
 	if (rc)
 		goto err_out_free;
@@ -1184,6 +1686,9 @@
 	dev->do_ioctl = &airo_ioctl;
 #ifdef WIRELESS_EXT
 	dev->get_wireless_stats = airo_get_wireless_stats;
+#if WIRELESS_EXT > 12
+	dev->wireless_handlers = (struct iw_handler_def *)&airo_handler_def;
+#endif /* WIRELESS_EXT > 12 */
 #endif /* WIRELESS_EXT */
 	dev->change_mtu = &airo_change_mtu;
 	dev->open = &airo_open;
@@ -1203,15 +1708,21 @@
 		}
 	}
 
-	if ( setup_card( ai, dev->dev_addr, &ai->config) != SUCCESS ) {
-		printk( KERN_ERR "airo: MAC could not be enabled\n" );
-		rc = -EIO;
-		goto err_out_res;
+	if (probe) {
+		if ( setup_card( ai, dev->dev_addr ) != SUCCESS ) {
+			printk( KERN_ERR "airo: MAC could not be enabled\n" );
+			rc = -EIO;
+			goto err_out_res;
+		}
+	} else {
+		ai->bap_read = fast_bap_read;
+		ai->flags |= FLAG_FLASHING;
 	}
 
 	rc = register_netdev(dev);
 	if (rc)
 		goto err_out_res;
+	ai->wifidev = init_wifidev(ai, dev);
 
 	ai->registered = 1;
 	printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n",
@@ -1220,8 +1731,9 @@
 		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
 
 	/* Allocate the transmit buffers */
-	for( i = 0; i < MAX_FIDS; i++ )
-		ai->fids[i] = transmit_allocate( ai, 2312 );
+	if (probe)
+		for( i = 0; i < MAX_FIDS; i++ )
+			ai->fids[i] = transmit_allocate(ai,2312,i>=MAX_FIDS/2);
 
 	setup_proc_entry( dev, dev->priv ); /* XXX check for failure */
 	netif_start_queue(dev);
@@ -1240,7 +1752,9 @@
 	return NULL;
 }
 
-int waitbusy (struct airo_info *ai) {
+EXPORT_SYMBOL(init_airo_card);
+
+static int waitbusy (struct airo_info *ai) {
 	int delay = 0;
 	while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) & (delay < 10000)) {
 		udelay (10);
@@ -1252,9 +1766,8 @@
 
 int reset_airo_card( struct net_device *dev ) {
 	int i;
-	struct airo_info *ai = (struct airo_info*)dev->priv;
+	struct airo_info *ai = dev->priv;
 
-	disable_MAC(ai);
 	waitbusy (ai);
 	OUT4500(ai,COMMAND,CMD_SOFTRESET);
 	set_current_state (TASK_UNINTERRUPTIBLE);
@@ -1262,7 +1775,7 @@
 	waitbusy (ai);
 	set_current_state (TASK_UNINTERRUPTIBLE);
 	schedule_timeout (HZ/5);
-	if ( setup_card(ai, dev->dev_addr, &(ai)->config) != SUCCESS ) {
+	if ( setup_card(ai, dev->dev_addr ) != SUCCESS ) {
 		printk( KERN_ERR "airo: MAC could not be enabled\n" );
 		return -1;
 	} else {
@@ -1277,24 +1790,64 @@
 			);
 		/* Allocate the transmit buffers */
 		for( i = 0; i < MAX_FIDS; i++ )
-			ai->fids[i] = transmit_allocate( ai, 2312 );
+			ai->fids[i] = transmit_allocate(ai,2312,i>=MAX_FIDS/2);
 	}
 	enable_interrupts( ai );
 	netif_wake_queue(dev);
 	return 0;
 }
 
-int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
-{
-	memcpy(haddr, skb->mac.raw + 10, ETH_ALEN);
-	return ETH_ALEN;
+EXPORT_SYMBOL(reset_airo_card);
+
+#if WIRELESS_EXT > 13
+static void airo_send_event(struct net_device *dev) {
+	struct airo_info *ai = dev->priv;
+	union iwreq_data wrqu;
+	StatusRid status_rid;
+
+	if (down_trylock(&ai->sem) == 0) {
+		__set_bit(FLAG_LOCKED, &ai->flags);
+		PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid));
+		clear_bit(FLAG_LOCKED, &ai->flags);
+		up(&ai->sem);
+		wrqu.data.length = 0;
+		wrqu.data.flags = 0;
+		memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN);
+		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+		/* Send event to user space */
+		wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+	} else {
+		ai->event_task.routine = (void (*)(void *))airo_send_event;
+		ai->event_task.data = (void *)dev;
+		schedule_task(&ai->event_task);
+	}
+}
+#endif
+
+static void airo_read_mic(struct airo_info *ai) {
+	MICRid mic_rid;
+
+	if (down_trylock(&ai->sem) == 0) {
+		__set_bit(FLAG_LOCKED, &ai->flags);
+		PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid));
+		clear_bit(FLAG_LOCKED, &ai->flags);
+		up(&ai->sem);
+#ifdef MICSUPPORT
+		micinit (ai, &mic_rid);
+#endif
+	} else {
+		ai->mic_task.routine = (void (*)(void *))airo_read_mic;
+		ai->mic_task.data = (void *)ai;
+		schedule_task(&ai->mic_task);
+	}
 }
 
 static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
 	struct net_device *dev = (struct net_device *)dev_id;
 	u16 status;
 	u16 fid;
-	struct airo_info *apriv = (struct airo_info *)dev->priv;
+	struct airo_info *apriv = dev->priv;
 	u16 savedInterrupts = 0;
 
 	if (!netif_device_present(dev))
@@ -1302,7 +1855,7 @@
 
 	for (;;) {
 		status = IN4500( apriv, EVSTAT );
-		if ( !status || status == 0xffff ) break;
+		if ( !(status & STATUS_INTS) || status == 0xffff ) break;
 
 		if ( status & EV_AWAKE ) {
 			OUT4500( apriv, EVACK, EV_AWAKE );
@@ -1314,7 +1867,14 @@
 			OUT4500( apriv, EVINTEN, 0 );
 		}
 
+		if ( status & EV_MIC ) {
+			OUT4500( apriv, EVACK, EV_MIC );
+			airo_read_mic( apriv );
+		}
 		if ( status & EV_LINK ) {
+#if WIRELESS_EXT > 13
+			union iwreq_data	wrqu;
+#endif /* WIRELESS_EXT > 13 */
 			/* The link status has changed, if you want to put a
 			   monitor hook in, do it here.  (Remember that
 			   interrupts are still disabled!)
@@ -1355,30 +1915,73 @@
 					apriv->timer.expires = RUN_AT(HZ*3);
 		      			add_timer(&apriv->timer);
 				}
+			} else {
+				struct task_struct *task = apriv->task;
+				if (task)
+					wake_up_process (task);
+				apriv->flags|=FLAG_UPDATE_UNI|FLAG_UPDATE_MULTI;
+			}
+#if WIRELESS_EXT > 13
+			/* Question : is ASSOCIATED the only status
+			 * that is valid ? We want to catch handover
+			 * and reassociations as valid status
+			 * Jean II */
+			if(newStatus == ASSOCIATED) {
+				if (apriv->scan_timestamp) {
+					/* Send an empty event to user space.
+					 * We don't send the received data on
+					 * the event because it would require
+					 * us to do complex transcoding, and
+					 * we want to minimise the work done in
+					 * the irq handler. Use a request to
+					 * extract the data - Jean II */
+					wrqu.data.length = 0;
+					wrqu.data.flags = 0;
+					wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+					apriv->scan_timestamp = 0;
+				}
+				airo_send_event(dev);
+			} else {
+				memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN);
+				wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+				/* Send event to user space */
+				wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL);
 			}
+#endif /* WIRELESS_EXT > 13 */
 		}
 
 		/* Check to see if there is something to receive */
 		if ( status & EV_RX  ) {
 			struct sk_buff *skb = NULL;
 			u16 fc, len, hdrlen = 0;
+#pragma pack(1)
 			struct {
 				u16 status, len;
 				u8 rssi[2];
+				u8 rate;
+				u8 freq;
+				u16 tmp[4];
 			} hdr;
+#pragma pack()
+			u16 gap;
+			u16 tmpbuf[4];
+			u16 *buffer;
 
 			fid = IN4500( apriv, RXFID );
 
 			/* Get the packet length */
-			if (dev->type == ARPHRD_IEEE80211) {
+			if (apriv->flags & FLAG_802_11) {
 				bap_setup (apriv, fid, 4, BAP0);
 				bap_read (apriv, (u16*)&hdr, sizeof(hdr), BAP0);
 				/* Bad CRC. Ignore packet */
 				if (le16_to_cpu(hdr.status) & 2)
 					hdr.len = 0;
+				if (apriv->wifidev == NULL)
+					hdr.len = 0;
 			} else {
-				bap_setup (apriv, fid, 6, BAP0);
-				bap_read (apriv, (u16*)&hdr.len, 4, BAP0);
+				bap_setup (apriv, fid, 0x36, BAP0);
+				bap_read (apriv, (u16*)&hdr.len, 2, BAP0);
 			}
 			len = le16_to_cpu(hdr.len);
 
@@ -1387,15 +1990,26 @@
 				len = 0;
 			}
 			if (len) {
-				if (dev->type == ARPHRD_IEEE80211) {
-					bap_setup (apriv, fid, 0x14, BAP0);
+				if (apriv->flags & FLAG_802_11) {
 					bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0);
-					if ((le16_to_cpu(fc) & 0x300) == 0x300)
-						hdrlen = 30;
-					else
-						hdrlen = 24;
+					fc = le16_to_cpu(fc);
+					switch (fc & 0xc) {
+						case 4:
+							if ((fc & 0xe0) == 0xc0)
+								hdrlen = 10;
+							else
+								hdrlen = 16;
+							break;
+						case 8:
+							if ((fc&0x300)==0x300){
+								hdrlen = 30;
+								break;
+							}
+						default:
+							hdrlen = 24;
+					}
 				} else
-					hdrlen = 12;
+					hdrlen = ETH_ALEN * 2;
 
 				skb = dev_alloc_skb( len + hdrlen + 2 );
 				if ( !skb ) {
@@ -1404,10 +2018,8 @@
 				}
 			}
 			if (len) {
-				u16 *buffer;
 				buffer = (u16*)skb_put (skb, len + hdrlen);
-				if (dev->type == ARPHRD_IEEE80211) {
-					u16 gap, tmpbuf[4];
+				if (apriv->flags & FLAG_802_11) {
 					buffer[0] = fc;
 					bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
 					if (hdrlen == 24)
@@ -1415,25 +2027,53 @@
 
 					bap_read (apriv, &gap, sizeof(gap), BAP0);
 					gap = le16_to_cpu(gap);
-					if (gap && gap <= 8)
-						bap_read (apriv, tmpbuf, gap, BAP0);
+					if (gap) {
+						if (gap <= 8)
+							bap_read (apriv, tmpbuf, gap, BAP0);
+						else
+							printk(KERN_ERR "airo: gaplen too big. Problems will follow...\n");
+					}
+
 
 					bap_read (apriv, buffer + hdrlen/2, len, BAP0);
 				} else {
-			                bap_setup (apriv, fid, 0x38, BAP0);
-					bap_read (apriv, buffer,len + hdrlen,BAP0);
+					MICBuffer micbuf;
+					bap_read (apriv, buffer, ETH_ALEN*2, BAP0);
+					if (apriv->micstats.enabled) {
+						bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0);
+						if (ntohs(micbuf.typelen) > 0x05DC)
+							bap_setup (apriv, fid, 0x44, BAP0);
+						else {
+							len -= sizeof(micbuf);
+							if (len < 48)
+								len = 48;
+							skb_trim (skb, len + hdrlen);
+						}
+					}
+					bap_read(apriv,buffer+ETH_ALEN,len,BAP0);
+#ifdef MICSUPPORT
+					if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) {
+						dev_kfree_skb_irq (skb);
+						len = 0;
+					}
+#endif
 				}
-				OUT4500( apriv, EVACK, EV_RX);
+			}
+			if (len) {
 #ifdef WIRELESS_SPY
 				if (apriv->spy_number > 0) {
 					int i;
 					char *sa;
 
-					sa = (char*)buffer + ((dev->type == ARPHRD_IEEE80211) ? 10 : 6);
+					sa = (char*)buffer + ((apriv->flags & FLAG_802_11) ? 10 : 6);
 
 					for (i=0; i<apriv->spy_number; i++)
-						if (!memcmp(sa,apriv->spy_address[i],6))
+						if (!memcmp(sa,apriv->spy_address[i],ETH_ALEN))
 						{
+							if (!(apriv->flags & FLAG_802_11)) {
+								bap_setup (apriv, fid, 8, BAP0);
+								bap_read (apriv, (u16*)hdr.rssi, 2, BAP0);
+							}
 							apriv->spy_stat[i].qual = hdr.rssi[0];
 							if (apriv->rssi)
 								apriv->spy_stat[i].level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
@@ -1445,16 +2085,19 @@
 						}
 				}
 #endif /* WIRELESS_SPY  */
-				dev->last_rx = jiffies;
-				skb->dev = dev;
-				skb->ip_summed = CHECKSUM_NONE;
-				if (dev->type == ARPHRD_IEEE80211) {
+				OUT4500( apriv, EVACK, EV_RX);
+
+				if (apriv->flags & FLAG_802_11) {
 					skb->mac.raw = skb->data;
-					skb_pull (skb, hdrlen);
 					skb->pkt_type = PACKET_OTHERHOST;
+					skb->dev = apriv->wifidev;
 					skb->protocol = htons(ETH_P_802_2);
-				} else
+				} else {
+					skb->dev = dev;
 					skb->protocol = eth_type_trans(skb,dev);
+				}
+				skb->dev->last_rx = jiffies;
+				skb->ip_summed = CHECKSUM_NONE;
 
 				netif_rx( skb );
 			} else
@@ -1477,27 +2120,16 @@
 					apriv->fids[i] &= 0xffff;
 				}
 			}
-			if (index != -1) netif_wake_queue(dev);
-			if ((status & EV_TXEXC) &&
-				(bap_setup(apriv, fid, 4, BAP1) == SUCCESS)) {
-
-				u16 status;
-				bap_read(apriv, &status, 2, BAP1);
-				if (le16_to_cpu(status) & 2)
-					apriv->stats.tx_aborted_errors++;
-				if (le16_to_cpu(status) & 4)
-					apriv->stats.tx_heartbeat_errors++;
-				if (le16_to_cpu(status) & 0x10)
-					apriv->stats.tx_carrier_errors++;
+			if (index != -1) {
+				netif_wake_queue(dev);
+				if (status & EV_TXEXC)
+					get_tx_error(apriv, index);
 			}
 			OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC));
 			if (index==-1) {
 				printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" );
 			}
 		}
-		if ( status & ~STATUS_INTS )
-			OUT4500( apriv, EVACK, status & ~STATUS_INTS);
-
 		if ( status & ~STATUS_INTS & ~IGNORE_INTS )
 			printk( KERN_WARNING "airo: Got weird status %x\n",
 				status & ~STATUS_INTS & ~IGNORE_INTS );
@@ -1541,12 +2173,26 @@
 }
 
 static int enable_MAC( struct airo_info *ai, Resp *rsp ) {
+	int rc;
         Cmd cmd;
 
-        if (ai->flags&FLAG_RADIO_OFF) return SUCCESS;
+	/* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions
+	 * FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down"
+	 * Note : we could try to use !netif_running(dev) in enable_MAC()
+	 * instead of this flag, but I don't trust it *within* the
+	 * open/close functions, and testing both flags together is
+	 * "cheaper" - Jean II */
+	if (ai->flags & (FLAG_RADIO_OFF|FLAG_RADIO_DOWN)) return SUCCESS;
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.cmd = MAC_ENABLE;
-	return lock_issuecommand(ai, &cmd, rsp);
+	if (test_bit(FLAG_LOCKED, &ai->flags) != 0)
+		return issuecommand(ai, &cmd, rsp);
+
+	if (down_interruptible(&ai->sem))
+		return -ERESTARTSYS;
+	rc = issuecommand(ai, &cmd, rsp);
+	up(&ai->sem);
+	return rc;
 }
 
 static void disable_MAC( struct airo_info *ai ) {
@@ -1555,7 +2201,15 @@
 
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.cmd = MAC_DISABLE; // disable in case already enabled
-	lock_issuecommand(ai, &cmd, &rsp);
+	if (test_bit(FLAG_LOCKED, &ai->flags) != 0) {
+		issuecommand(ai, &cmd, &rsp);
+		return;
+	}
+
+	if (down_interruptible(&ai->sem))
+		return;
+	issuecommand(ai, &cmd, &rsp);
+	up(&ai->sem);
 }
 
 static void enable_interrupts( struct airo_info *ai ) {
@@ -1572,12 +2226,10 @@
 	OUT4500( ai, EVINTEN, 0 );
 }
 
-static u16 setup_card(struct airo_info *ai, u8 *mac,
-		      ConfigRid *config)
+static u16 setup_card(struct airo_info *ai, u8 *mac)
 {
 	Cmd cmd;
 	Resp rsp;
-	ConfigRid cfg;
 	int status;
 	int i;
 	SsidRid mySsid;
@@ -1594,18 +2246,23 @@
 	/* The NOP is the first step in getting the card going */
 	cmd.cmd = NOP;
 	cmd.parm0 = cmd.parm1 = cmd.parm2 = 0;
-	if ( lock_issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
+	if (down_interruptible(&ai->sem))
+		return ERROR;
+	if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
+		up(&ai->sem);
 		return ERROR;
 	}
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.cmd = MAC_DISABLE; // disable in case already enabled
-	if ( lock_issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
+	if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
+		up(&ai->sem);
 		return ERROR;
 	}
 
 	// Let's figure out if we need to use the AUX port
 	cmd.cmd = CMD_ENABLEAUX;
-	if (lock_issuecommand(ai, &cmd, &rsp) != SUCCESS) {
+	if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
+		up(&ai->sem);
 		printk(KERN_ERR "airo: Error checking for AUX port\n");
 		return ERROR;
 	}
@@ -1616,13 +2273,16 @@
 		ai->bap_read = aux_bap_read;
 		printk(KERN_DEBUG "airo: Doing AUX bap_reads\n");
 	}
-	if ( config->len ) {
-		cfg = *config;
-	} else {
+	up(&ai->sem);
+	if (ai->config.len == 0) {
 		tdsRssiRid rssi_rid;
+		CapabilityRid cap_rid;
 
 		// general configuration (read/modify/write)
-		status = readConfigRid(ai, &cfg);
+		status = readConfigRid(ai);
+		if ( status != SUCCESS ) return ERROR;
+
+		status = readCapabilityRid(ai, &cap_rid);
 		if ( status != SUCCESS ) return ERROR;
 
 		status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid));
@@ -1631,67 +2291,77 @@
 				memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512);
 		}
 		else {
-			CapabilityRid cap_rid;
 			if (ai->rssi) {
 				kfree(ai->rssi);
 				ai->rssi = NULL;
 			}
-			status = readCapabilityRid(ai, &cap_rid);
-			if ((status == SUCCESS) && (cap_rid.softCap & 8))
-				cfg.rmode |= RXMODE_NORMALIZED_RSSI;
+			if (cap_rid.softCap & 8)
+				ai->config.rmode |= RXMODE_NORMALIZED_RSSI;
 			else
 				printk(KERN_WARNING "airo: unknown received signal level scale\n");
 		}
-		cfg.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
+		ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
+
+#ifdef MICSUPPORT
+		if ((cap_rid.len==sizeof(cap_rid)) && (cap_rid.extSoftCap&1)) {
+			ai->config.opmode |= MODE_MIC;
+			ai->flags |= FLAG_MIC_CAPABLE;
+			micsetup(ai);
+		}
+#endif
 
 		/* Save off the MAC */
-		for( i = 0; i < 6; i++ ) {
-			mac[i] = cfg.macAddr[i];
+		for( i = 0; i < ETH_ALEN; i++ ) {
+			mac[i] = ai->config.macAddr[i];
 		}
 
 		/* Check to see if there are any insmod configured
 		   rates to add */
 		if ( rates ) {
 			int i = 0;
-			if ( rates[0] ) memset(cfg.rates,0,sizeof(cfg.rates));
+			if ( rates[0] ) memset(ai->config.rates,0,sizeof(ai->config.rates));
 			for( i = 0; i < 8 && rates[i]; i++ ) {
-				cfg.rates[i] = rates[i];
+				ai->config.rates[i] = rates[i];
 			}
 		}
 		if ( basic_rate > 0 ) {
 			int i;
 			for( i = 0; i < 8; i++ ) {
-				if ( cfg.rates[i] == basic_rate ||
-				     !cfg.rates ) {
-					cfg.rates[i] = basic_rate | 0x80;
+				if ( ai->config.rates[i] == basic_rate ||
+				     !ai->config.rates ) {
+					ai->config.rates[i] = basic_rate | 0x80;
 					break;
 				}
 			}
 		}
-		cfg.authType = ai->authtype;
-		*config = cfg;
+		ai->need_commit = 1;
 	}
 
 	/* Setup the SSIDs if present */
 	if ( ssids[0] ) {
-		int i = 0;
+		int i;
 		for( i = 0; i < 3 && ssids[i]; i++ ) {
 			mySsid.ssids[i].len = strlen(ssids[i]);
 			if ( mySsid.ssids[i].len > 32 )
 				mySsid.ssids[i].len = 32;
 			memcpy(mySsid.ssids[i].ssid, ssids[i],
 			       mySsid.ssids[i].len);
-			mySsid.ssids[i].len = mySsid.ssids[i].len;
 		}
 	}
 
-	status = writeConfigRid(ai, &cfg);
+	status = writeConfigRid(ai);
 	if ( status != SUCCESS ) return ERROR;
 
 	/* Set up the SSID list */
 	status = writeSsidRid(ai, &mySsid);
 	if ( status != SUCCESS ) return ERROR;
 
+	status = enable_MAC(ai, &rsp);
+	if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) {
+		printk( KERN_ERR "airo: Bad MAC enable reason = %x, rid = %x, offset = %d\n", rsp.rsp0, rsp.rsp1, rsp.rsp2 );
+		return ERROR;
+	}
+
 	/* Grab the initial wep key, we gotta save it for auto_wep */
 	rc = readWepKeyRid(ai, &wkr, 1);
 	if (rc == SUCCESS) do {
@@ -1709,36 +2379,49 @@
 	return SUCCESS;
 }
 
-static u16 lock_issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
-	int rc;
-	long flags;
-
-	spin_lock_irqsave(&ai->main_lock, flags);
-	rc = issuecommand(ai, pCmd, pRsp);
-	spin_unlock_irqrestore(&ai->main_lock, flags);
-	return rc;
-}
-
 static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
         // Im really paranoid about letting it run forever!
 	int max_tries = 600000;
 
-	OUT4500(ai, PARAM0, pCmd->parm0);
-	OUT4500(ai, PARAM1, pCmd->parm1);
-	OUT4500(ai, PARAM2, pCmd->parm2);
-	OUT4500(ai, COMMAND, pCmd->cmd);
-	while ( max_tries-- &&
-		(IN4500(ai, EVSTAT) & EV_CMD) == 0) {
-		if ( IN4500(ai, COMMAND) == pCmd->cmd) {
-			// PC4500 didn't notice command, try again
-			OUT4500(ai, COMMAND, pCmd->cmd);
-		}
+	if (sendcommand(ai, pCmd) == (u16)ERROR)
+		return ERROR;
+
+	while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) {
+		if (!in_interrupt() && (max_tries & 255) == 0)
+			schedule();
+	}
+	if ( max_tries == -1 ) {
+		printk( KERN_ERR
+			"airo: Max tries exceeded waiting for command\n" );
+                return ERROR;
 	}
+	completecommand(ai, pRsp);
+	return SUCCESS;
+}
+
+static u16 sendcommand(struct airo_info *ai, Cmd *pCmd) {
+        // Im really paranoid about letting it run forever!
+	int max_tries = 600000;
+	u16 cmd;
+
+	OUT4500(ai, PARAM0, pCmd->parm0);
+	OUT4500(ai, PARAM1, pCmd->parm1);
+	OUT4500(ai, PARAM2, pCmd->parm2);
+	OUT4500(ai, COMMAND, pCmd->cmd);
+	while ( max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0 &&
+		(cmd = IN4500(ai, COMMAND)) != 0 )
+			if (cmd == pCmd->cmd)
+				// PC4500 didn't notice command, try again
+				OUT4500(ai, COMMAND, pCmd->cmd);
 	if ( max_tries == -1 ) {
 		printk( KERN_ERR
 			"airo: Max tries exceeded when issueing command\n" );
                 return ERROR;
 	}
+	return SUCCESS;
+}
+
+static void completecommand(struct airo_info *ai, Resp *pRsp) {
 	// command completed
 	pRsp->status = IN4500(ai, STATUS);
 	pRsp->rsp0 = IN4500(ai, RESP0);
@@ -1751,7 +2434,6 @@
 	}
 	// acknowledge processing the status/response
 	OUT4500(ai, EVACK, EV_CMD);
-	return SUCCESS;
 }
 
 /* Sets up the bap to start exchange data.  whichbap should
@@ -1891,11 +2573,14 @@
  *  we must get a lock. */
 static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len)
 {
-	u16 status;
-        long flags;
+	u16 status, dolock = 0;
         int rc = SUCCESS;
 
-	spin_lock_irqsave(&ai->main_lock, flags);
+	if (test_bit(FLAG_LOCKED, &ai->flags) == 0) {
+		dolock = 1;
+		if (down_interruptible(&ai->sem))
+			return ERROR;
+	}
 	if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != SUCCESS) {
                 rc = status;
                 goto done;
@@ -1919,8 +2604,9 @@
 	}
 	// read remainder of the rid
 	rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
- done:
-	spin_unlock_irqrestore(&ai->main_lock, flags);
+done:
+	if (dolock)
+		up(&ai->sem);
 	return rc;
 }
 
@@ -1929,11 +2615,14 @@
 static int PC4500_writerid(struct airo_info *ai, u16 rid,
 			   const void *pBuf, int len)
 {
-	u16 status;
-        long flags;
+	u16 status, dolock = 0;
 	int rc = SUCCESS;
 
-	spin_lock_irqsave(&ai->main_lock, flags);
+	if (test_bit(FLAG_LOCKED, &ai->flags) == 0) {
+		dolock = 1;
+		if (down_interruptible(&ai->sem))
+			return ERROR;
+	}
 	// --- first access so that we can write the rid data
 	if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
                 rc = status;
@@ -1948,24 +2637,32 @@
 	// ---now commit the rid data
 	rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
  done:
-	spin_unlock_irqrestore(&ai->main_lock, flags);
+	if (dolock)
+		up(&ai->sem);
         return rc;
 }
 
 /* Allocates a FID to be used for transmitting packets.  We only use
    one for now. */
-static u16 transmit_allocate(struct airo_info *ai, int lenPayload)
+static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw)
 {
 	Cmd cmd;
 	Resp rsp;
 	u16 txFid;
 	u16 txControl;
-        long flags;
 
 	cmd.cmd = CMD_ALLOCATETX;
 	cmd.parm0 = lenPayload;
-	if (lock_issuecommand(ai, &cmd, &rsp) != SUCCESS) return 0;
-	if ( (rsp.status & 0xFF00) != 0) return 0;
+	if (down_interruptible(&ai->sem))
+		return ERROR;
+	if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
+		txFid = 0;
+		goto done;
+	}
+	if ( (rsp.status & 0xFF00) != 0) {
+		txFid = 0;
+		goto done;
+	}
 	/* wait for the allocate event/indication
 	 * It makes me kind of nervous that this can just sit here and spin,
 	 * but in practice it only loops like four times. */
@@ -1979,15 +2676,19 @@
 	 *  will be using the same one over and over again. */
 	/*  We only have to setup the control once since we are not
 	 *  releasing the fid. */
-	txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3
-		| TXCTL_ETHERNET | TXCTL_NORELEASE);
-	spin_lock_irqsave(&ai->main_lock, flags);
-	if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS) {
-		spin_unlock_irqrestore(&ai->main_lock, flags);
-		return ERROR;
-	}
-	bap_write(ai, &txControl, sizeof(txControl), BAP1);
-	spin_unlock_irqrestore(&ai->main_lock, flags);
+	if (raw)
+		txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_11
+			| TXCTL_ETHERNET | TXCTL_NORELEASE);
+	else
+		txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3
+			| TXCTL_ETHERNET | TXCTL_NORELEASE);
+	if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS)
+		txFid = ERROR;
+	else
+		bap_write(ai, &txControl, sizeof(txControl), BAP1);
+
+done:
+	up(&ai->sem);
 
 	return txFid;
 }
@@ -1995,26 +2696,102 @@
 /* In general BAP1 is dedicated to transmiting packets.  However,
    since we need a BAP when accessing RIDs, we also use BAP1 for that.
    Make sure the BAP1 spinlock is held when this is called. */
-static int transmit_802_3_packet(struct airo_info *ai, u16 txFid,
-				 char *pPacket, int len)
+static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
 {
 	u16 payloadLen;
 	Cmd cmd;
 	Resp rsp;
+	int miclen = 0;
+	u16 txFid = len;
+	MICBuffer pMic;
+
+	len >>= 16;
 
-	if (len < 12) {
+	if (len < ETH_ALEN * 2) {
 		printk( KERN_WARNING "Short packet %d\n", len );
 		return ERROR;
 	}
+	len -= ETH_ALEN * 2;
+
+#ifdef MICSUPPORT
+	if ((ai->flags & FLAG_MIC_CAPABLE) && ai->micstats.enabled && 
+	    (ntohs(((u16 *)pPacket)[6]) != 0x888E)) {
+		if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS)
+			return ERROR;
+		miclen = sizeof(pMic);
+	}
+#endif
 
 	// packet is destination[6], source[6], payload[len-12]
 	// write the payload length and dst/src/payload
 	if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR;
 	/* The hardware addresses aren't counted as part of the payload, so
 	 * we have to subtract the 12 bytes for the addresses off */
-	payloadLen = cpu_to_le16(len-12);
+	payloadLen = cpu_to_le16(len + miclen);
+	bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
+	bap_write(ai, (const u16*)pPacket, sizeof(etherHead), BAP1);
+	if (miclen)
+		bap_write(ai, (const u16*)&pMic, miclen, BAP1);
+	bap_write(ai, (const u16*)(pPacket + sizeof(etherHead)), len, BAP1);
+	// issue the transmit command
+	memset( &cmd, 0, sizeof( cmd ) );
+	cmd.cmd = CMD_TRANSMIT;
+	cmd.parm0 = txFid;
+	if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
+	if ( (rsp.status & 0xFF00) != 0) return ERROR;
+	return SUCCESS;
+}
+
+static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket)
+{
+	u16 fc, payloadLen;
+	Cmd cmd;
+	Resp rsp;
+	int hdrlen;
+	struct {
+		u8 addr4[ETH_ALEN];
+		u16 gaplen;
+		u8 gap[6];
+	} gap;
+	u16 txFid = len;
+	len >>= 16;
+	gap.gaplen = 6;
+
+	fc = le16_to_cpu(*(const u16*)pPacket);
+	switch (fc & 0xc) {
+		case 4:
+			if ((fc & 0xe0) == 0xc0)
+				hdrlen = 10;
+			else
+				hdrlen = 16;
+			break;
+		case 8:
+			if ((fc&0x300)==0x300){
+				hdrlen = 30;
+				break;
+			}
+		default:
+			hdrlen = 24;
+	}
+
+	if (len < hdrlen) {
+		printk( KERN_WARNING "Short packet %d\n", len );
+		return ERROR;
+	}
+
+	/* packet is 802.11 header +  payload
+	 * write the payload length and dst/src/payload */
+	if (bap_setup(ai, txFid, 6, BAP1) != SUCCESS) return ERROR;
+	/* The 802.11 header aren't counted as part of the payload, so
+	 * we have to subtract the header bytes off */
+	payloadLen = cpu_to_le16(len-hdrlen);
 	bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
-	bap_write(ai, (const u16*)pPacket, len, BAP1);
+	if (bap_setup(ai, txFid, 0x0014, BAP1) != SUCCESS) return ERROR;
+	bap_write(ai, (const u16*)pPacket, hdrlen, BAP1);
+	bap_write(ai, hdrlen == 30 ?
+		(const u16*)&gap.gaplen : (const u16*)&gap, 38 - hdrlen, BAP1);
+
+	bap_write(ai, (const u16*)(pPacket + hdrlen), len - hdrlen, BAP1);
 	// issue the transmit command
 	memset( &cmd, 0, sizeof( cmd ) );
 	cmd.cmd = CMD_TRANSMIT;
@@ -2281,17 +3058,15 @@
 
 static int proc_status_open( struct inode *inode, struct file *file ) {
 	struct proc_data *data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *apriv = (struct airo_info *)dev->priv;
+	struct airo_info *apriv = dev->priv;
 	CapabilityRid cap_rid;
 	StatusRid status_rid;
 	int i;
 
 	MOD_INC_USE_COUNT;
 
-	dp = inode->u.generic_ip;
-
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2365,17 +3140,15 @@
 				struct file *file,
 				u16 rid ) {
 	struct proc_data *data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *apriv = (struct airo_info *)dev->priv;
+	struct airo_info *apriv = dev->priv;
 	StatsRid stats;
 	int i, j;
 	int *vals = stats.vals;
 	MOD_INC_USE_COUNT;
 
 
-	dp = inode->u.generic_ip;
-
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2420,57 +3193,43 @@
 	return value;
 }
 
-static void checkThrottle(ConfigRid *config) {
-	int i;
-/* Old hardware had a limit on encryption speed */
-	if (config->authType != AUTH_OPEN && maxencrypt) {
-		for(i=0; i<8; i++) {
-			if (config->rates[i] > maxencrypt) {
-				config->rates[i] = 0;
-			}
-		}
-	}
-}
-
 static void proc_config_on_close( struct inode *inode, struct file *file ) {
 	struct proc_data *data = file->private_data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = (struct airo_info*)dev->priv;
-	ConfigRid config;
+	struct airo_info *ai = dev->priv;
 	Resp rsp;
 	char *line;
 	int need_reset = 0;
 
 	if ( !data->writelen ) return;
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
 
-	disable_MAC(ai);
-	readConfigRid(ai, &config);
+	readConfigRid(ai);
 
 	line = data->wbuffer;
 	while( line[0] ) {
 /*** Mode processing */
 		if ( !strncmp( line, "Mode: ", 6 ) ) {
 			line += 6;
-			config.rmode &= 0xfe00;
+			if ((ai->config.rmode & 0xff) >= RXMODE_RFMON)
+					need_reset = 1;
+			ai->config.rmode &= 0xfe00;
+			ai->flags &= ~FLAG_802_11;
+			ai->config.opmode &= 0xFF00;
 			if ( line[0] == 'a' ) {
-				config.opmode = 0;
+				ai->config.opmode |= 0;
 			} else {
-				config.opmode = 1;
-				if ( line[0] == 'r' )
-					config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
-				else if ( line[0] == 'y' )
-					config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER;
-			}
-			if (config.rmode & RXMODE_DISABLE_802_3_HEADER) {
-				dev->type = ARPHRD_IEEE80211;
-				dev->hard_header_parse = wll_header_parse;
-			} else if (dev->type == ARPHRD_IEEE80211) {
-				dev->type = ARPHRD_ETHER;
-				dev->hard_header_parse = ai->header_parse;
-				need_reset = 1;
+				ai->config.opmode |= 1;
+				if ( line[0] == 'r' ) {
+					ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
+					ai->flags |= FLAG_802_11;
+				} else if ( line[0] == 'y' ) {
+					ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER;
+					ai->flags |= FLAG_802_11;
+				} else if ( line[0] == 'l' )
+					ai->config.rmode |= RXMODE_LANMON;
 			}
+			ai->need_commit = 1;
 		}
 
 /*** Radio status */
@@ -2487,22 +3246,26 @@
 			int j;
 
 			line += 10;
-			memset( config.nodeName, 0, 16 );
+			memset( ai->config.nodeName, 0, 16 );
 /* Do the name, assume a space between the mode and node name */
 			for( j = 0; j < 16 && line[j] != '\n'; j++ ) {
-				config.nodeName[j] = line[j];
+				ai->config.nodeName[j] = line[j];
 			}
+			ai->need_commit = 1;
 		}
 
 /*** PowerMode processing */
 		else if ( !strncmp( line, "PowerMode: ", 11 ) ) {
 			line += 11;
 			if ( !strncmp( line, "PSPCAM", 6 ) ) {
-				config.powerSaveMode = POWERSAVE_PSPCAM;
+				ai->config.powerSaveMode = POWERSAVE_PSPCAM;
+				ai->need_commit = 1;
 			} else if ( !strncmp( line, "PSP", 3 ) ) {
-				config.powerSaveMode = POWERSAVE_PSP;
+				ai->config.powerSaveMode = POWERSAVE_PSP;
+				ai->need_commit = 1;
 			} else {
-				config.powerSaveMode = POWERSAVE_CAM;
+				ai->config.powerSaveMode = POWERSAVE_CAM;
+				ai->need_commit = 1;
 			}
 		} else if ( !strncmp( line, "DataRates: ", 11 ) ) {
 			int v, i = 0, k = 0; /* i is index into line,
@@ -2510,77 +3273,91 @@
 
 			line += 11;
 			while((v = get_dec_u16(line, &i, 3))!=-1) {
-				config.rates[k++] = (u8)v;
+				ai->config.rates[k++] = (u8)v;
 				line += i + 1;
 				i = 0;
 			}
+			ai->need_commit = 1;
 		} else if ( !strncmp( line, "Channel: ", 9 ) ) {
 			int v, i = 0;
 			line += 9;
 			v = get_dec_u16(line, &i, i+3);
-			if ( v != -1 )
-				config.channelSet = (u16)v;
+			if ( v != -1 ) {
+				ai->config.channelSet = (u16)v;
+				ai->need_commit = 1;
+			}
 		} else if ( !strncmp( line, "XmitPower: ", 11 ) ) {
 			int v, i = 0;
 			line += 11;
 			v = get_dec_u16(line, &i, i+3);
-			if ( v != -1 ) config.txPower = (u16)v;
+			if ( v != -1 ) {
+				ai->config.txPower = (u16)v;
+				ai->need_commit = 1;
+			}
 		} else if ( !strncmp( line, "WEP: ", 5 ) ) {
 			line += 5;
 			switch( line[0] ) {
 			case 's':
-				config.authType = (u16)AUTH_SHAREDKEY;
+				ai->config.authType = (u16)AUTH_SHAREDKEY;
 				break;
 			case 'e':
-				config.authType = (u16)AUTH_ENCRYPT;
+				ai->config.authType = (u16)AUTH_ENCRYPT;
 				break;
 			default:
-				config.authType = (u16)AUTH_OPEN;
+				ai->config.authType = (u16)AUTH_OPEN;
 				break;
 			}
+			ai->need_commit = 1;
 		} else if ( !strncmp( line, "LongRetryLimit: ", 16 ) ) {
 			int v, i = 0;
 
 			line += 16;
 			v = get_dec_u16(line, &i, 3);
 			v = (v<0) ? 0 : ((v>255) ? 255 : v);
-			config.longRetryLimit = (u16)v;
+			ai->config.longRetryLimit = (u16)v;
+			ai->need_commit = 1;
 		} else if ( !strncmp( line, "ShortRetryLimit: ", 17 ) ) {
 			int v, i = 0;
 
 			line += 17;
 			v = get_dec_u16(line, &i, 3);
 			v = (v<0) ? 0 : ((v>255) ? 255 : v);
-			config.shortRetryLimit = (u16)v;
+			ai->config.shortRetryLimit = (u16)v;
+			ai->need_commit = 1;
 		} else if ( !strncmp( line, "RTSThreshold: ", 14 ) ) {
 			int v, i = 0;
 
 			line += 14;
 			v = get_dec_u16(line, &i, 4);
 			v = (v<0) ? 0 : ((v>2312) ? 2312 : v);
-			config.rtsThres = (u16)v;
+			ai->config.rtsThres = (u16)v;
+			ai->need_commit = 1;
 		} else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) {
 			int v, i = 0;
 
 			line += 16;
 			v = get_dec_u16(line, &i, 5);
 			v = (v<0) ? 0 : v;
-			config.txLifetime = (u16)v;
+			ai->config.txLifetime = (u16)v;
+			ai->need_commit = 1;
 		} else if ( !strncmp( line, "RXMSDULifetime: ", 16 ) ) {
 			int v, i = 0;
 
 			line += 16;
 			v = get_dec_u16(line, &i, 5);
 			v = (v<0) ? 0 : v;
-			config.rxLifetime = (u16)v;
+			ai->config.rxLifetime = (u16)v;
+			ai->need_commit = 1;
 		} else if ( !strncmp( line, "TXDiversity: ", 13 ) ) {
-			config.txDiversity =
+			ai->config.txDiversity =
 				(line[13]=='l') ? 1 :
 				((line[13]=='r')? 2: 3);
+			ai->need_commit = 1;
 		} else if ( !strncmp( line, "RXDiversity: ", 13 ) ) {
-			config.rxDiversity =
+			ai->config.rxDiversity =
 				(line[13]=='l') ? 1 :
 				((line[13]=='r')? 2: 3);
+			ai->need_commit = 1;
 		} else if ( !strncmp( line, "FragThreshold: ", 15 ) ) {
 			int v, i = 0;
 
@@ -2588,22 +3365,23 @@
 			v = get_dec_u16(line, &i, 4);
 			v = (v<256) ? 256 : ((v>2312) ? 2312 : v);
 			v = v & 0xfffe; /* Make sure its even */
-			config.fragThresh = (u16)v;
+			ai->config.fragThresh = (u16)v;
+			ai->need_commit = 1;
 		} else if (!strncmp(line, "Modulation: ", 12)) {
 			line += 12;
 			switch(*line) {
-			case 'd':  config.modulation=MOD_DEFAULT; break;
-			case 'c':  config.modulation=MOD_CCK; break;
-			case 'm':  config.modulation=MOD_MOK; break;
+			case 'd':  ai->config.modulation=MOD_DEFAULT; ai->need_commit=1; break;
+			case 'c':  ai->config.modulation=MOD_CCK; ai->need_commit=1; break;
+			case 'm':  ai->config.modulation=MOD_MOK; ai->need_commit=1; break;
 			default:
 				printk( KERN_WARNING "airo: Unknown modulation\n" );
 			}
 		} else if (!strncmp(line, "Preamble: ", 10)) {
 			line += 10;
 			switch(*line) {
-			case 'a': config.preamble=PREAMBLE_AUTO; break;
-			case 'l': config.preamble=PREAMBLE_LONG; break;
-			case 's': config.preamble=PREAMBLE_SHORT; break;
+			case 'a': ai->config.preamble=PREAMBLE_AUTO; ai->need_commit=1; break;
+			case 'l': ai->config.preamble=PREAMBLE_LONG; ai->need_commit=1; break;
+			case 's': ai->config.preamble=PREAMBLE_SHORT; ai->need_commit=1; break;
 		        default: printk(KERN_WARNING "airo: Unknown preamble\n");
 			}
 		} else {
@@ -2612,8 +3390,7 @@
 		while( line[0] && line[0] != '\n' ) line++;
 		if ( line[0] ) line++;
 	}
-	checkThrottle(&config);
-	ai->config = config;
+	disable_MAC(ai);
 	if (need_reset) {
 		APListRid APList_rid;
 		SsidRid SSID_rid;
@@ -2621,25 +3398,34 @@
 		readAPListRid(ai, &APList_rid);
 		readSsidRid(ai, &SSID_rid);
 		reset_airo_card(dev);
+		disable_MAC(ai);
 		writeSsidRid(ai, &SSID_rid);
 		writeAPListRid(ai, &APList_rid);
 	}
-	writeConfigRid(ai, &config);
+	writeConfigRid(ai);
 	enable_MAC(ai, &rsp);
+	if (need_reset)
+		airo_set_promisc(ai);
+}
+
+static char *get_rmode(u16 mode) {
+        switch(mode&0xff) {
+        case RXMODE_RFMON:  return "rfmon";
+        case RXMODE_RFMON_ANYBSS:  return "yna (any) bss rfmon";
+        case RXMODE_LANMON:  return "lanmon";
+        }
+        return "ESS";
 }
 
 static int proc_config_open( struct inode *inode, struct file *file ) {
 	struct proc_data *data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = (struct airo_info*)dev->priv;
-	ConfigRid config;
+	struct airo_info *ai = dev->priv;
 	int i;
 
 	MOD_INC_USE_COUNT;
 
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2657,7 +3443,7 @@
 	data->maxwritelen = 2048;
 	data->on_close = proc_config_on_close;
 
-	readConfigRid(ai, &config);
+	readConfigRid(ai);
 
 	i = sprintf( data->rbuffer,
 		     "Mode: %s\n"
@@ -2667,25 +3453,25 @@
 		     "DataRates: %d %d %d %d %d %d %d %d\n"
 		     "Channel: %d\n"
 		     "XmitPower: %d\n",
-		     config.opmode == 0 ? "adhoc" :
-		     config.opmode == 1 ? "ESS" :
-		     config.opmode == 2 ? "AP" :
-		     config.opmode == 3 ? "AP RPTR" : "Error",
+		     (ai->config.opmode & 0xFF) == 0 ? "adhoc" :
+		     (ai->config.opmode & 0xFF) == 1 ? get_rmode(ai->config.rmode):
+		     (ai->config.opmode & 0xFF) == 2 ? "AP" :
+		     (ai->config.opmode & 0xFF) == 3 ? "AP RPTR" : "Error",
 		     ai->flags&FLAG_RADIO_OFF ? "off" : "on",
-		     config.nodeName,
-		     config.powerSaveMode == 0 ? "CAM" :
-		     config.powerSaveMode == 1 ? "PSP" :
-		     config.powerSaveMode == 2 ? "PSPCAM" : "Error",
-		     (int)config.rates[0],
-		     (int)config.rates[1],
-		     (int)config.rates[2],
-		     (int)config.rates[3],
-		     (int)config.rates[4],
-		     (int)config.rates[5],
-		     (int)config.rates[6],
-		     (int)config.rates[7],
-		     (int)config.channelSet,
-		     (int)config.txPower
+		     ai->config.nodeName,
+		     ai->config.powerSaveMode == 0 ? "CAM" :
+		     ai->config.powerSaveMode == 1 ? "PSP" :
+		     ai->config.powerSaveMode == 2 ? "PSPCAM" : "Error",
+		     (int)ai->config.rates[0],
+		     (int)ai->config.rates[1],
+		     (int)ai->config.rates[2],
+		     (int)ai->config.rates[3],
+		     (int)ai->config.rates[4],
+		     (int)ai->config.rates[5],
+		     (int)ai->config.rates[6],
+		     (int)ai->config.rates[7],
+		     (int)ai->config.channelSet,
+		     (int)ai->config.txPower
 		);
 	sprintf( data->rbuffer + i,
 		 "LongRetryLimit: %d\n"
@@ -2699,24 +3485,24 @@
 		 "WEP: %s\n"
 		 "Modulation: %s\n"
 		 "Preamble: %s\n",
-		 (int)config.longRetryLimit,
-		 (int)config.shortRetryLimit,
-		 (int)config.rtsThres,
-		 (int)config.txLifetime,
-		 (int)config.rxLifetime,
-		 config.txDiversity == 1 ? "left" :
-		 config.txDiversity == 2 ? "right" : "both",
-		 config.rxDiversity == 1 ? "left" :
-		 config.rxDiversity == 2 ? "right" : "both",
-		 (int)config.fragThresh,
-		 config.authType == AUTH_ENCRYPT ? "encrypt" :
-		 config.authType == AUTH_SHAREDKEY ? "shared" : "open",
-		 config.modulation == 0 ? "default" :
-		 config.modulation == MOD_CCK ? "cck" :
-		 config.modulation == MOD_MOK ? "mok" : "error",
-		 config.preamble == PREAMBLE_AUTO ? "auto" :
-		 config.preamble == PREAMBLE_LONG ? "long" :
-		 config.preamble == PREAMBLE_SHORT ? "short" : "error"
+		 (int)ai->config.longRetryLimit,
+		 (int)ai->config.shortRetryLimit,
+		 (int)ai->config.rtsThres,
+		 (int)ai->config.txLifetime,
+		 (int)ai->config.rxLifetime,
+		 ai->config.txDiversity == 1 ? "left" :
+		 ai->config.txDiversity == 2 ? "right" : "both",
+		 ai->config.rxDiversity == 1 ? "left" :
+		 ai->config.rxDiversity == 2 ? "right" : "both",
+		 (int)ai->config.fragThresh,
+		 ai->config.authType == AUTH_ENCRYPT ? "encrypt" :
+		 ai->config.authType == AUTH_SHAREDKEY ? "shared" : "open",
+		 ai->config.modulation == 0 ? "default" :
+		 ai->config.modulation == MOD_CCK ? "cck" :
+		 ai->config.modulation == MOD_MOK ? "mok" : "error",
+		 ai->config.preamble == PREAMBLE_AUTO ? "auto" :
+		 ai->config.preamble == PREAMBLE_LONG ? "long" :
+		 ai->config.preamble == PREAMBLE_SHORT ? "short" : "error"
 		);
 	data->readlen = strlen( data->rbuffer );
 	return 0;
@@ -2724,10 +3510,11 @@
 
 static void proc_SSID_on_close( struct inode *inode, struct file *file ) {
 	struct proc_data *data = (struct proc_data *)file->private_data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = (struct airo_info*)dev->priv;
+	struct airo_info *ai = dev->priv;
 	SsidRid SSID_rid;
+	Resp rsp;
 	int i;
 	int offset = 0;
 
@@ -2748,7 +3535,9 @@
 		       offset < data->writelen ) offset++;
 		offset++;
 	}
+	disable_MAC(ai);
 	writeSsidRid(ai, &SSID_rid);
+	enable_MAC(ai, &rsp);
 }
 
 inline static u8 hexVal(char c) {
@@ -2760,10 +3549,11 @@
 
 static void proc_APList_on_close( struct inode *inode, struct file *file ) {
 	struct proc_data *data = (struct proc_data *)file->private_data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = (struct airo_info*)dev->priv;
+	struct airo_info *ai = dev->priv;
 	APListRid APList_rid;
+	Resp rsp;
 	int i;
 
 	if ( !data->writelen ) return;
@@ -2786,7 +3576,9 @@
 			}
 		}
 	}
+	disable_MAC(ai);
 	writeAPListRid(ai, &APList_rid);
+	enable_MAC(ai, &rsp);
 }
 
 /* This function wraps PC4500_writerid with a MAC disable */
@@ -2826,7 +3618,7 @@
 
 static int set_wep_key(struct airo_info *ai, u16 index,
 		       const char *key, u16 keylen, int perm ) {
-	static const unsigned char macaddr[6] = { 0x01, 0, 0, 0, 0, 0 };
+	static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
 	WepKeyRid wkr;
 
 	memset(&wkr, 0, sizeof(wkr));
@@ -2843,7 +3635,7 @@
 		wkr.kindex = index;
 		wkr.klen = keylen;
 		memcpy( wkr.key, key, keylen );
-		memcpy( wkr.mac, macaddr, 6 );
+		memcpy( wkr.mac, macaddr, ETH_ALEN );
 		printk(KERN_INFO "Setting key %d\n", index);
 	}
 
@@ -2853,9 +3645,9 @@
 
 static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
 	struct proc_data *data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = (struct airo_info*)dev->priv;
+	struct airo_info *ai = dev->priv;
 	int i;
 	char key[16];
 	u16 index = 0;
@@ -2863,7 +3655,6 @@
 
 	memset(key, 0, sizeof(key));
 
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
 	data = (struct proc_data *)file->private_data;
 	if ( !data->writelen ) return;
 
@@ -2895,9 +3686,9 @@
 
 static int proc_wepkey_open( struct inode *inode, struct file *file ) {
 	struct proc_data *data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = (struct airo_info*)dev->priv;
+	struct airo_info *ai = dev->priv;
 	char *ptr;
 	WepKeyRid wkr;
 	u16 lastindex;
@@ -2906,8 +3697,6 @@
 
 	MOD_INC_USE_COUNT;
 
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2949,17 +3738,15 @@
 
 static int proc_SSID_open( struct inode *inode, struct file *file ) {
 	struct proc_data *data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = (struct airo_info*)dev->priv;
+	struct airo_info *ai = dev->priv;
 	int i;
 	char *ptr;
 	SsidRid SSID_rid;
 
 	MOD_INC_USE_COUNT;
 
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2997,17 +3784,15 @@
 
 static int proc_APList_open( struct inode *inode, struct file *file ) {
 	struct proc_data *data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = (struct airo_info*)dev->priv;
+	struct airo_info *ai = dev->priv;
 	int i;
 	char *ptr;
 	APListRid APList_rid;
 
 	MOD_INC_USE_COUNT;
 
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -3049,9 +3834,9 @@
 
 static int proc_BSSList_open( struct inode *inode, struct file *file ) {
 	struct proc_data *data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = (struct airo_info*)dev->priv;
+	struct airo_info *ai = dev->priv;
 	char *ptr;
 	BSSListRid BSSList_rid;
 	int rc;
@@ -3060,8 +3845,6 @@
 
 	MOD_INC_USE_COUNT;
 
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -3082,7 +3865,10 @@
 
 			memset(&cmd, 0, sizeof(cmd));
 			cmd.cmd=CMD_LISTBSS;
-			lock_issuecommand(ai, &cmd, &rsp);
+			if (down_interruptible(&ai->sem))
+				return -ERESTARTSYS;
+			issuecommand(ai, &cmd, &rsp);
+			up(&ai->sem);
 			data->readlen = 0;
 			return 0;
 		}
@@ -3133,46 +3919,53 @@
 	struct net_device_list *next;
 } *airo_devices = 0;
 
-/* Since the card doesnt automatically switch to the right WEP mode,
+/* Since the card doesn't automatically switch to the right WEP mode,
    we will make it do it.  If the card isn't associated, every secs we
    will switch WEP modes to see if that will help.  If the card is
    associated we will check every minute to see if anything has
    changed. */
 static void timer_func( u_long data ) {
 	struct net_device *dev = (struct net_device*)data;
-	struct airo_info *apriv = (struct airo_info *)dev->priv;
+	struct airo_info *apriv = dev->priv;
 	u16 linkstat = IN4500(apriv, LINKSTAT);
+	Resp rsp;
 
-	if (linkstat != 0x400 ) {
+	if (!(apriv->flags & FLAG_FLASHING) && (linkstat != 0x400)) {
 /* We don't have a link so try changing the authtype */
-		ConfigRid config = apriv->config;
+		if (down_trylock(&apriv->sem) != 0) {
+			apriv->timer.expires = RUN_AT(1);
+			add_timer(&apriv->timer);
+			return;
+		}
+		__set_bit(FLAG_LOCKED, &apriv->flags);
 
-		switch(apriv->authtype) {
+		readConfigRid(apriv);
+		disable_MAC(apriv);
+		switch(apriv->config.authType) {
 		case AUTH_ENCRYPT:
 /* So drop to OPEN */
-			config.authType = AUTH_OPEN;
-			apriv->authtype = AUTH_OPEN;
+			apriv->config.authType = AUTH_OPEN;
 			break;
 		case AUTH_SHAREDKEY:
 			if (apriv->keyindex < auto_wep) {
 				set_wep_key(apriv, apriv->keyindex, 0, 0, 0);
-				config.authType = AUTH_SHAREDKEY;
-				apriv->authtype = AUTH_SHAREDKEY;
+				apriv->config.authType = AUTH_SHAREDKEY;
 				apriv->keyindex++;
 			} else {
 			        /* Drop to ENCRYPT */
 				apriv->keyindex = 0;
 				set_wep_key(apriv, apriv->defindex, 0, 0, 0);
-				config.authType = AUTH_ENCRYPT;
-				apriv->authtype = AUTH_ENCRYPT;
+				apriv->config.authType = AUTH_ENCRYPT;
 			}
 			break;
 		default:  /* We'll escalate to SHAREDKEY */
-			config.authType = AUTH_SHAREDKEY;
-			apriv->authtype = AUTH_SHAREDKEY;
+			apriv->config.authType = AUTH_SHAREDKEY;
 		}
-		checkThrottle(&config);
-		writeConfigRid(apriv, &config);
+		apriv->need_commit = 1;
+		writeConfigRid(apriv);
+		enable_MAC(apriv, &rsp);
+		clear_bit(FLAG_LOCKED, &apriv->flags);
+		up(&apriv->sem);
 
 /* Schedule check to see if the change worked */
 		apriv->timer.expires = RUN_AT(HZ*3);
@@ -3192,7 +3985,6 @@
 		timer->function = timer_func;
 		timer->data = (u_long)dev;
 		init_timer(timer);
-		apriv->authtype = AUTH_SHAREDKEY;
 	}
 
 	node->dev = dev;
@@ -3273,911 +4065,1729 @@
 /*
  * Initial Wireless Extension code for Aironet driver by :
  *	Jean Tourrilhes <jt@hpl.hp.com> - HPL - 17 November 00
+ * Conversion to new driver API by :
+ *	Jean Tourrilhes <jt@hpl.hp.com> - HPL - 26 March 02
+ * Javier also did a good amount of work here, adding some new extensions
+ * and fixing my code. Let's just say that without him this code just
+ * would not work at all... - Jean II
  */
-#ifndef IW_ENCODE_NOKEY
-#define IW_ENCODE_NOKEY         0x0800  /* Key is write only, so not present */
-#define IW_ENCODE_MODE  (IW_ENCODE_DISABLED | IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)
-#endif /* IW_ENCODE_NOKEY */
-#endif /* WIRELESS_EXT */
 
+/*------------------------------------------------------------------*/
 /*
- * This defines the configuration part of the Wireless Extensions
- * Note : irq and spinlock protection will occur in the subroutines
- *
- * TODO :
- *	o Check input value more carefully and fill correct values in range
- *	o Implement : POWER, SPY, APLIST
- *	o Optimise when adapter is closed (aggregate changes, commit later)
- *	o Test and shakeout the bugs (if any)
- *
- * Jean II
- *
- * Javier Achirica did a great job of merging code from the unnamed CISCO
- * developer that added support for flashing the card.
+ * Wireless Handler : get protocol name
  */
-static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int airo_get_name(struct net_device *dev,
+			 struct iw_request_info *info,
+			 char *cwrq,
+			 char *extra)
 {
-	int i, rc = 0;
-#ifdef WIRELESS_EXT
-	struct airo_info *local = (struct airo_info*) dev->priv;
-	struct iwreq *wrq = (struct iwreq *) rq;
-	ConfigRid config;		/* Configuration info */
-	CapabilityRid cap_rid;		/* Card capability info */
-	StatusRid status_rid;		/* Card status info */
+	strcpy(cwrq, "IEEE 802.11-DS");
+	return 0;
+}
 
-#ifdef CISCO_EXT
-	if (cmd != SIOCGIWPRIV && cmd != AIROIOCTL && cmd != AIROIDIFC
-#ifdef AIROOLDIOCTL
-		&& cmd != AIROOLDIOCTL && cmd != AIROOLDIDIFC
-#endif
-		)
-#endif /* CISCO_EXT */
-	{
-		/* If the command read some stuff, we better get it out of
-		 * the card first... */
-		if(IW_IS_GET(cmd))
-			readStatusRid(local, &status_rid);
-		if(IW_IS_GET(cmd) || (cmd == SIOCSIWRATE) || (cmd == SIOCSIWENCODE))
-			readCapabilityRid(local, &cap_rid);
-		/* Get config in all cases, because SET will just modify it */
-		readConfigRid(local, &config);
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set frequency
+ */
+static int airo_set_freq(struct net_device *dev,
+			 struct iw_request_info *info,
+			 struct iw_freq *fwrq,
+			 char *extra)
+{
+	struct airo_info *local = dev->priv;
+	int rc = -EINPROGRESS;		/* Call commit handler */
+
+	/* If setting by frequency, convert to a channel */
+	if((fwrq->e == 1) &&
+	   (fwrq->m >= (int) 2.412e8) &&
+	   (fwrq->m <= (int) 2.487e8)) {
+		int f = fwrq->m / 100000;
+		int c = 0;
+		while((c < 14) && (f != frequency_list[c]))
+			c++;
+		/* Hack to fall through... */
+		fwrq->e = 0;
+		fwrq->m = c + 1;
 	}
-#endif /* WIRELESS_EXT */
+	/* Setting by channel number */
+	if((fwrq->m > 1000) || (fwrq->e > 0))
+		rc = -EOPNOTSUPP;
+	else {
+		int channel = fwrq->m;
+		/* We should do a better check than that,
+		 * based on the card capability !!! */
+		if((channel < 1) || (channel > 16)) {
+			printk(KERN_DEBUG "%s: New channel value of %d is invalid!\n", dev->name, fwrq->m);
+			rc = -EINVAL;
+		} else {
+			/* Yes ! We can set it !!! */
+			local->config.channelSet = (u16)(channel - 1);
+			local->need_commit = 1;
+		}
+	}
+	return rc;
+}
 
-	switch (cmd) {
-#ifdef WIRELESS_EXT
-		// Get name
-	case SIOCGIWNAME:
-		strcpy(wrq->u.name, "IEEE 802.11-DS");
-		break;
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get frequency
+ */
+static int airo_get_freq(struct net_device *dev,
+			 struct iw_request_info *info,
+			 struct iw_freq *fwrq,
+			 char *extra)
+{
+	struct airo_info *local = dev->priv;
+	StatusRid status_rid;		/* Card status info */
 
-		// Set frequency/channel
-	case SIOCSIWFREQ:
-		/* If setting by frequency, convert to a channel */
-		if((wrq->u.freq.e == 1) &&
-		   (wrq->u.freq.m >= (int) 2.412e8) &&
-		   (wrq->u.freq.m <= (int) 2.487e8)) {
-			int f = wrq->u.freq.m / 100000;
-			int c = 0;
-			while((c < 14) && (f != frequency_list[c]))
-				c++;
-			/* Hack to fall through... */
-			wrq->u.freq.e = 0;
-			wrq->u.freq.m = c + 1;
-		}
-		/* Setting by channel number */
-		if((wrq->u.freq.m > 1000) || (wrq->u.freq.e > 0))
-			rc = -EOPNOTSUPP;
-		else {
-			int channel = wrq->u.freq.m;
-			/* We should do a better check than that,
-			 * based on the card capability !!! */
-			if((channel < 1) || (channel > 16)) {
-				printk(KERN_DEBUG "%s: New channel value of %d is invalid!\n", dev->name, wrq->u.freq.m);
-				rc = -EINVAL;
-			} else {
-				/* Yes ! We can set it !!! */
-				config.channelSet = (u16)(channel - 1);
-				local->need_commit = 1;
-			}
-		}
-		break;
+	readStatusRid(local, &status_rid);
 
-		// Get frequency/channel
-	case SIOCGIWFREQ:
+	/* Will return zero in infrastructure mode */
 #ifdef WEXT_USECHANNELS
-		wrq->u.freq.m = ((int)status_rid.channel) + 1;
-		wrq->u.freq.e = 0;
+	fwrq->m = ((int)status_rid.channel) + 1;
+	fwrq->e = 0;
 #else
-		{
-			int f = (int)status_rid.channel;
-			wrq->u.freq.m = frequency_list[f] * 100000;
-			wrq->u.freq.e = 1;
-		}
+	{
+		int f = (int)status_rid.channel;
+		fwrq->m = frequency_list[f] * 100000;
+		fwrq->e = 1;
+	}
 #endif
-		break;
-
-		// Set desired network name (ESSID)
-	case SIOCSIWESSID:
-		if (wrq->u.data.pointer) {
-			char	essid[IW_ESSID_MAX_SIZE + 1];
-			SsidRid SSID_rid;		/* SSIDs */
-
-			/* Reload the list of current SSID */
-			readSsidRid(local, &SSID_rid);
-
-			/* Check if we asked for `any' */
-			if(wrq->u.data.flags == 0) {
-				/* Just send an empty SSID list */
-				memset(&SSID_rid, 0, sizeof(SSID_rid));
-			} else {
-				int	index = (wrq->u.data.flags &
-						 IW_ENCODE_INDEX) - 1;
 
-				/* Check the size of the string */
-				if(wrq->u.data.length > IW_ESSID_MAX_SIZE+1) {
-					rc = -E2BIG;
-					break;
-				}
-				/* Check if index is valid */
-				if((index < 0) || (index >= 4)) {
-					rc = -EINVAL;
-					break;
-				}
+	return 0;
+}
 
-				/* Set the SSID */
-				memset(essid, 0, sizeof(essid));
-				if (copy_from_user(essid,
-					       wrq->u.data.pointer,
-					       wrq->u.data.length)) {
-					rc = -EFAULT;
-					break;
-				}
-				memcpy(SSID_rid.ssids[index].ssid, essid,
-				       sizeof(essid) - 1);
-				SSID_rid.ssids[index].len = wrq->u.data.length - 1;
-			}
-			/* Write it to the card */
-			writeSsidRid(local, &SSID_rid);
-		}
-		break;
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set ESSID
+ */
+static int airo_set_essid(struct net_device *dev,
+			  struct iw_request_info *info,
+			  struct iw_point *dwrq,
+			  char *extra)
+{
+	struct airo_info *local = dev->priv;
+	Resp rsp;
+	SsidRid SSID_rid;		/* SSIDs */
 
-		// Get current network name (ESSID)
-	case SIOCGIWESSID:
-		if (wrq->u.data.pointer) {
-			char essid[IW_ESSID_MAX_SIZE + 1];
-
-			/* Note : if wrq->u.data.flags != 0, we should
-			 * get the relevant SSID from the SSID list... */
-
-			/* Get the current SSID */
-			memcpy(essid, status_rid.SSID, status_rid.SSIDlen);
-			essid[status_rid.SSIDlen] = '\0';
-			/* If none, we may want to get the one that was set */
-
-			/* Push it out ! */
-			wrq->u.data.length = strlen(essid) + 1;
-			wrq->u.data.flags = 1; /* active */
-			if (copy_to_user(wrq->u.data.pointer, essid, sizeof(essid)))
-				rc = -EFAULT;
-		}
-		break;
+	/* Reload the list of current SSID */
+	readSsidRid(local, &SSID_rid);
 
-	case SIOCSIWAP:
-		if (wrq->u.ap_addr.sa_family != ARPHRD_ETHER)
-			rc = -EINVAL;
-		else {
-			APListRid APList_rid;
+	/* Check if we asked for `any' */
+	if(dwrq->flags == 0) {
+		/* Just send an empty SSID list */
+		memset(&SSID_rid, 0, sizeof(SSID_rid));
+	} else {
+		int	index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
 
-			memset(&APList_rid, 0, sizeof(APList_rid));
-			APList_rid.len = sizeof(APList_rid);
-			memcpy(APList_rid.ap[0], wrq->u.ap_addr.sa_data, 6);
-			writeAPListRid(local, &APList_rid);
-			local->need_commit = 1;
+		/* Check the size of the string */
+		if(dwrq->length > IW_ESSID_MAX_SIZE+1) {
+			return -E2BIG ;
+		}
+		/* Check if index is valid */
+		if((index < 0) || (index >= 4)) {
+			return -EINVAL;
 		}
-		break;
 
-		// Get current Access Point (BSSID)
-	case SIOCGIWAP:
-		/* Tentative. This seems to work, wow, I'm lucky !!! */
-		memcpy(wrq->u.ap_addr.sa_data, status_rid.bssid[0], 6);
-		wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
-		break;
+		/* Set the SSID */
+		memset(SSID_rid.ssids[index].ssid, 0,
+		       sizeof(SSID_rid.ssids[index].ssid));
+		memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
+		SSID_rid.ssids[index].len = dwrq->length - 1;
+	}
+	/* Write it to the card */
+	disable_MAC(local);
+	writeSsidRid(local, &SSID_rid);
+	enable_MAC(local, &rsp);
 
-		// Set desired station name
-	case SIOCSIWNICKN:
-		if (wrq->u.data.pointer) {
-			char	name[16 + 1];
+	return 0;
+}
 
-			/* Check the size of the string */
-			if(wrq->u.data.length > 16 + 1) {
-				rc = -E2BIG;
-				break;
-			}
-			memset(name, 0, sizeof(name));
-			if (copy_from_user(name, wrq->u.data.pointer,
-					   wrq->u.data.length)) {
-				rc = -EFAULT;
-				break;
-			}
-			memcpy(config.nodeName, name, 16);
-			local->need_commit = 1;
-		}
-		break;
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get ESSID
+ */
+static int airo_get_essid(struct net_device *dev,
+			  struct iw_request_info *info,
+			  struct iw_point *dwrq,
+			  char *extra)
+{
+	struct airo_info *local = dev->priv;
+	StatusRid status_rid;		/* Card status info */
 
-		// Get current station name
-	case SIOCGIWNICKN:
-		if (wrq->u.data.pointer) {
-			char name[IW_ESSID_MAX_SIZE + 1];
-
-			strncpy(name, config.nodeName, 16);
-			name[16] = '\0';
-			wrq->u.data.length = strlen(name) + 1;
-			if (copy_to_user(wrq->u.data.pointer, name, sizeof(name)))
-				rc = -EFAULT;
-		}
-		break;
+	readStatusRid(local, &status_rid);
 
-		// Set the desired bit-rate
-	case SIOCSIWRATE:
-	{
-		/* First : get a valid bit rate value */
-		u8	brate = 0;
-		int	i;
-
-		/* Which type of value ? */
-		if((wrq->u.bitrate.value < 8) &&
-		   (wrq->u.bitrate.value >= 0)) {
-			/* Setting by rate index */
-			/* Find value in the magic rate table */
-			brate = cap_rid.supportedRates[wrq->u.bitrate.value];
-		} else {
-			/* Setting by frequency value */
-			u8	normvalue = (u8) (wrq->u.bitrate.value/500000);
+	/* Note : if dwrq->flags != 0, we should
+	 * get the relevant SSID from the SSID list... */
 
-			/* Check if rate is valid */
-			for(i = 0 ; i < 8 ; i++) {
-				if(normvalue == cap_rid.supportedRates[i]) {
-					brate = normvalue;
-					break;
-				}
-			}
-		}
-		/* -1 designed the max rate (mostly auto mode) */
-		if(wrq->u.bitrate.value == -1) {
-			/* Get the highest available rate */
-			for(i = 0 ; i < 8 ; i++) {
-				if(cap_rid.supportedRates[i] == 0)
-					break;
-			}
-			if(i != 0)
-				brate = cap_rid.supportedRates[i - 1];
-		}
-		/* Check that it is valid */
-		if(brate == 0) {
-			rc = -EINVAL;
-			break;
-		}
+	/* Get the current SSID */
+	memcpy(extra, status_rid.SSID, status_rid.SSIDlen);
+	extra[status_rid.SSIDlen] = '\0';
+	/* If none, we may want to get the one that was set */
+
+	/* Push it out ! */
+	dwrq->length = status_rid.SSIDlen + 1;
+	dwrq->flags = 1; /* active */
 
-		/* Now, check if we want a fixed or auto value */
-		if(wrq->u.bitrate.fixed == 0) {
-			/* Fill all the rates up to this max rate */
-			memset(config.rates, 0, 8);
-			for(i = 0 ; i < 8 ; i++) {
-				config.rates[i] = cap_rid.supportedRates[i];
-				if(config.rates[i] == brate)
-					break;
-			}
-			local->need_commit = 1;
-		} else {
-			/* Fixed mode */
-			/* One rate, fixed */
-			memset(config.rates, 0, 8);
-			config.rates[0] = brate;
-			local->need_commit = 1;
-		}
-		break;
-	}
+	return 0;
+}
 
-	// Get the current bit-rate
-	case SIOCGIWRATE:
-	{
-		int brate = status_rid.currentXmitRate;
-		wrq->u.bitrate.value = brate * 500000;
-		/* If more than one rate, set auto */
-		wrq->u.rts.fixed = (config.rates[1] == 0);
-	}
-	break;
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set AP address
+ */
+static int airo_set_wap(struct net_device *dev,
+			struct iw_request_info *info,
+			struct sockaddr *awrq,
+			char *extra)
+{
+	struct airo_info *local = dev->priv;
+	Cmd cmd;
+	Resp rsp;
+	APListRid APList_rid;
+	static const unsigned char bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 };
 
-	// Set the desired RTS threshold
-	case SIOCSIWRTS:
-	{
-		int rthr = wrq->u.rts.value;
-		if(wrq->u.rts.disabled)
-			rthr = 2312;
-		if((rthr < 0) || (rthr > 2312)) {
-			rc = -EINVAL;
-		} else {
-			config.rtsThres = rthr;
-			local->need_commit = 1;
-		}
+	if (awrq->sa_family != ARPHRD_ETHER)
+		return -EINVAL;
+	else if (!memcmp(bcast, awrq->sa_data, ETH_ALEN)) {
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.cmd=CMD_LOSE_SYNC;
+		if (down_interruptible(&local->sem))
+			return -ERESTARTSYS;
+		issuecommand(local, &cmd, &rsp);
+		up(&local->sem);
+	} else {
+		memset(&APList_rid, 0, sizeof(APList_rid));
+		APList_rid.len = sizeof(APList_rid);
+		memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN);
+		disable_MAC(local);
+		writeAPListRid(local, &APList_rid);
+		enable_MAC(local, &rsp);
 	}
-	break;
-
-	// Get the current RTS threshold
-	case SIOCGIWRTS:
-		wrq->u.rts.value = config.rtsThres;
-		wrq->u.rts.disabled = (wrq->u.rts.value >= 2312);
-		wrq->u.rts.fixed = 1;
-		break;
+	return 0;
+}
 
-		// Set the desired fragmentation threshold
-	case SIOCSIWFRAG:
-	{
-		int fthr = wrq->u.frag.value;
-		if(wrq->u.frag.disabled)
-			fthr = 2312;
-		if((fthr < 256) || (fthr > 2312)) {
-			rc = -EINVAL;
-		} else {
-			fthr &= ~0x1;	/* Get an even value */
-			config.fragThresh = (u16)fthr;
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get AP address
+ */
+static int airo_get_wap(struct net_device *dev,
+			struct iw_request_info *info,
+			struct sockaddr *awrq,
+			char *extra)
+{
+	struct airo_info *local = dev->priv;
+	StatusRid status_rid;		/* Card status info */
+
+	readStatusRid(local, &status_rid);
+
+	/* Tentative. This seems to work, wow, I'm lucky !!! */
+	memcpy(awrq->sa_data, status_rid.bssid[0], ETH_ALEN);
+	awrq->sa_family = ARPHRD_ETHER;
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set Nickname
+ */
+static int airo_set_nick(struct net_device *dev,
+			 struct iw_request_info *info,
+			 struct iw_point *dwrq,
+			 char *extra)
+{
+	struct airo_info *local = dev->priv;
+
+	/* Check the size of the string */
+	if(dwrq->length > 16 + 1) {
+		return -E2BIG;
+	}
+	memset(local->config.nodeName, 0, sizeof(local->config.nodeName));
+	memcpy(local->config.nodeName, extra, dwrq->length);
+	local->need_commit = 1;
+
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get Nickname
+ */
+static int airo_get_nick(struct net_device *dev,
+			 struct iw_request_info *info,
+			 struct iw_point *dwrq,
+			 char *extra)
+{
+	struct airo_info *local = dev->priv;
+
+	strncpy(extra, local->config.nodeName, 16);
+	extra[16] = '\0';
+	dwrq->length = strlen(extra) + 1;
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set Bit-Rate
+ */
+static int airo_set_rate(struct net_device *dev,
+			 struct iw_request_info *info,
+			 struct iw_param *vwrq,
+			 char *extra)
+{
+	struct airo_info *local = dev->priv;
+	CapabilityRid cap_rid;		/* Card capability info */
+	u8	brate = 0;
+	int	i;
+
+	/* First : get a valid bit rate value */
+	readCapabilityRid(local, &cap_rid);
+
+	/* Which type of value ? */
+	if((vwrq->value < 8) && (vwrq->value >= 0)) {
+		/* Setting by rate index */
+		/* Find value in the magic rate table */
+		brate = cap_rid.supportedRates[vwrq->value];
+	} else {
+		/* Setting by frequency value */
+		u8	normvalue = (u8) (vwrq->value/500000);
+
+		/* Check if rate is valid */
+		for(i = 0 ; i < 8 ; i++) {
+			if(normvalue == cap_rid.supportedRates[i]) {
+				brate = normvalue;
+				break;
+			}
+		}
+	}
+	/* -1 designed the max rate (mostly auto mode) */
+	if(vwrq->value == -1) {
+		/* Get the highest available rate */
+		for(i = 0 ; i < 8 ; i++) {
+			if(cap_rid.supportedRates[i] == 0)
+				break;
+		}
+		if(i != 0)
+			brate = cap_rid.supportedRates[i - 1];
+	}
+	/* Check that it is valid */
+	if(brate == 0) {
+		return -EINVAL;
+	}
+
+	/* Now, check if we want a fixed or auto value */
+	if(vwrq->fixed == 0) {
+		/* Fill all the rates up to this max rate */
+		memset(local->config.rates, 0, 8);
+		for(i = 0 ; i < 8 ; i++) {
+			local->config.rates[i] = cap_rid.supportedRates[i];
+			if(local->config.rates[i] == brate)
+				break;
+		}
+	} else {
+		/* Fixed mode */
+		/* One rate, fixed */
+		memset(local->config.rates, 0, 8);
+		local->config.rates[0] = brate;
+	}
+	local->need_commit = 1;
+
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get Bit-Rate
+ */
+static int airo_get_rate(struct net_device *dev,
+			 struct iw_request_info *info,
+			 struct iw_param *vwrq,
+			 char *extra)
+{
+	struct airo_info *local = dev->priv;
+	StatusRid status_rid;		/* Card status info */
+
+	readStatusRid(local, &status_rid);
+
+	vwrq->value = status_rid.currentXmitRate * 500000;
+	/* If more than one rate, set auto */
+	vwrq->fixed = (local->config.rates[1] == 0);
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set RTS threshold
+ */
+static int airo_set_rts(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_param *vwrq,
+			char *extra)
+{
+	struct airo_info *local = dev->priv;
+	int rthr = vwrq->value;
+
+	if(vwrq->disabled)
+		rthr = 2312;
+	if((rthr < 0) || (rthr > 2312)) {
+		return -EINVAL;
+	}
+	local->config.rtsThres = rthr;
+	local->need_commit = 1;
+
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get RTS threshold
+ */
+static int airo_get_rts(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_param *vwrq,
+			char *extra)
+{
+	struct airo_info *local = dev->priv;
+
+	vwrq->value = local->config.rtsThres;
+	vwrq->disabled = (vwrq->value >= 2312);
+	vwrq->fixed = 1;
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set Fragmentation threshold
+ */
+static int airo_set_frag(struct net_device *dev,
+			 struct iw_request_info *info,
+			 struct iw_param *vwrq,
+			 char *extra)
+{
+	struct airo_info *local = dev->priv;
+	int fthr = vwrq->value;
+
+	if(vwrq->disabled)
+		fthr = 2312;
+	if((fthr < 256) || (fthr > 2312)) {
+		return -EINVAL;
+	}
+	fthr &= ~0x1;	/* Get an even value - is it really needed ??? */
+	local->config.fragThresh = (u16)fthr;
+	local->need_commit = 1;
+
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get Fragmentation threshold
+ */
+static int airo_get_frag(struct net_device *dev,
+			 struct iw_request_info *info,
+			 struct iw_param *vwrq,
+			 char *extra)
+{
+	struct airo_info *local = dev->priv;
+
+	vwrq->value = local->config.fragThresh;
+	vwrq->disabled = (vwrq->value >= 2312);
+	vwrq->fixed = 1;
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set Mode of Operation
+ */
+static int airo_set_mode(struct net_device *dev,
+			 struct iw_request_info *info,
+			 __u32 *uwrq,
+			 char *extra)
+{
+	struct airo_info *local = dev->priv;
+
+	switch(*uwrq) {
+		case IW_MODE_ADHOC:
+			local->config.opmode &= 0xFF00;
+			local->config.opmode |= MODE_STA_IBSS;
+			break;
+		case IW_MODE_INFRA:
+			local->config.opmode &= 0xFF00;
+			local->config.opmode |= MODE_STA_ESS;
+			break;
+		case IW_MODE_MASTER:
+			local->config.opmode &= 0xFF00;
+			local->config.opmode |= MODE_AP;
+			break;
+		case IW_MODE_REPEAT:
+			local->config.opmode &= 0xFF00;
+			local->config.opmode |= MODE_AP_RPTR;
+			break;
+		default:
+			return -EINVAL;
+	}
+	local->need_commit = 1;
+
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get Mode of Operation
+ */
+static int airo_get_mode(struct net_device *dev,
+			 struct iw_request_info *info,
+			 __u32 *uwrq,
+			 char *extra)
+{
+	struct airo_info *local = dev->priv;
+
+	/* If not managed, assume it's ad-hoc */
+	switch (local->config.opmode & 0xFF) {
+		case MODE_STA_ESS:
+			*uwrq = IW_MODE_INFRA;
+			break;
+		case MODE_AP:
+			*uwrq = IW_MODE_MASTER;
+			break;
+		case MODE_AP_RPTR:
+			*uwrq = IW_MODE_REPEAT;
+			break;
+		default:
+			*uwrq = IW_MODE_ADHOC;
+	}
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set Encryption Key
+ */
+static int airo_set_encode(struct net_device *dev,
+			   struct iw_request_info *info,
+			   struct iw_point *dwrq,
+			   char *extra)
+{
+	struct airo_info *local = dev->priv;
+	CapabilityRid cap_rid;		/* Card capability info */
+
+	/* Is WEP supported ? */
+	readCapabilityRid(local, &cap_rid);
+	/* Older firmware doesn't support this...
+	if(!(cap_rid.softCap & 2)) {
+		return -EOPNOTSUPP;
+	} */
+
+	/* Basic checking: do we have a key to set ?
+	 * Note : with the new API, it's impossible to get a NULL pointer.
+	 * Therefore, we need to check a key size == 0 instead.
+	 * New version of iwconfig properly set the IW_ENCODE_NOKEY flag
+	 * when no key is present (only change flags), but older versions
+	 * don't do it. - Jean II */
+	if (dwrq->length > 0) {
+		wep_key_t key;
+		int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+		int current_index = get_wep_key(local, 0xffff);
+		/* Check the size of the key */
+		if (dwrq->length > MAX_KEY_SIZE) {
+			return -EINVAL;
+		}
+		/* Check the index (none -> use current) */
+		if ((index < 0) || (index>=(cap_rid.softCap&0x80)?4:1))
+			index = current_index;
+		/* Set the length */
+		if (dwrq->length > MIN_KEY_SIZE)
+			key.len = MAX_KEY_SIZE;
+		else
+			if (dwrq->length > 0)
+				key.len = MIN_KEY_SIZE;
+			else
+				/* Disable the key */
+				key.len = 0;
+		/* Check if the key is not marked as invalid */
+		if(!(dwrq->flags & IW_ENCODE_NOKEY)) {
+			/* Cleanup */
+			memset(key.key, 0, MAX_KEY_SIZE);
+			/* Copy the key in the driver */
+			memcpy(key.key, extra, dwrq->length);
+			/* Send the key to the card */
+			set_wep_key(local, index, key.key, key.len, 1);
+		}
+		/* WE specify that if a valid key is set, encryption
+		 * should be enabled (user may turn it off later)
+		 * This is also how "iwconfig ethX key on" works */
+		if((index == current_index) && (key.len > 0) &&
+		   (local->config.authType == AUTH_OPEN)) {
+			local->config.authType = AUTH_ENCRYPT;
 			local->need_commit = 1;
 		}
+	} else {
+		/* Do we want to just set the transmit key index ? */
+		int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+		if ((index>=0) && (index<(cap_rid.softCap&0x80)?4:1)) {
+			set_wep_key(local, index, 0, 0, 1);
+		} else
+			/* Don't complain if only change the mode */
+			if(!dwrq->flags & IW_ENCODE_MODE) {
+				return -EINVAL;
+			}
+	}
+	/* Read the flags */
+	if(dwrq->flags & IW_ENCODE_DISABLED)
+		local->config.authType = AUTH_OPEN;	// disable encryption
+	if(dwrq->flags & IW_ENCODE_RESTRICTED)
+		local->config.authType = AUTH_SHAREDKEY;	// Only Both
+	if(dwrq->flags & IW_ENCODE_OPEN)
+		local->config.authType = AUTH_ENCRYPT;	// Only Wep
+	/* Commit the changes to flags if needed */
+	if(dwrq->flags & IW_ENCODE_MODE)
+		local->need_commit = 1;
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get Encryption Key
+ */
+static int airo_get_encode(struct net_device *dev,
+			   struct iw_request_info *info,
+			   struct iw_point *dwrq,
+			   char *extra)
+{
+	struct airo_info *local = dev->priv;
+	int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+	CapabilityRid cap_rid;		/* Card capability info */
+
+	/* Is it supported ? */
+	readCapabilityRid(local, &cap_rid);
+	if(!(cap_rid.softCap & 2)) {
+		return -EOPNOTSUPP;
 	}
-	break;
+	/* Check encryption mode */
+	switch(local->config.authType)	{
+		case AUTH_ENCRYPT:
+			dwrq->flags = IW_ENCODE_OPEN;
+			break;
+		case AUTH_SHAREDKEY:
+			dwrq->flags = IW_ENCODE_RESTRICTED;
+			break;
+		default:
+		case AUTH_OPEN:
+			dwrq->flags = IW_ENCODE_DISABLED;
+			break;
+	}
+	/* We can't return the key, so set the proper flag and return zero */
+	dwrq->flags |= IW_ENCODE_NOKEY;
+	memset(extra, 0, 16);
+
+	/* Which key do we want ? -1 -> tx index */
+	if((index < 0) || (index >= (cap_rid.softCap & 0x80) ? 4 : 1))
+		index = get_wep_key(local, 0xffff);
+	dwrq->flags |= index + 1;
+	/* Copy the key to the user buffer */
+	dwrq->length = get_wep_key(local, index);
+	if (dwrq->length > 16) {
+		dwrq->length=0;
+	}
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set Tx-Power
+ */
+static int airo_set_txpow(struct net_device *dev,
+			  struct iw_request_info *info,
+			  struct iw_param *vwrq,
+			  char *extra)
+{
+	struct airo_info *local = dev->priv;
+	CapabilityRid cap_rid;		/* Card capability info */
+	int i;
+	int rc = -EINVAL;
+
+	readCapabilityRid(local, &cap_rid);
+
+	if (vwrq->disabled) {
+		local->flags |= FLAG_RADIO_OFF;
+		local->need_commit = 1;
+		return -EINPROGRESS;		/* Call commit handler */
+	}
+	if (vwrq->flags != IW_TXPOW_MWATT) {
+		return -EINVAL;
+	}
+	local->flags &= ~FLAG_RADIO_OFF;
+	for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
+		if ((vwrq->value==cap_rid.txPowerLevels[i])) {
+			local->config.txPower = vwrq->value;
+			local->need_commit = 1;
+			rc = -EINPROGRESS;	/* Call commit handler */
+			break;
+		}
+	return rc;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get Tx-Power
+ */
+static int airo_get_txpow(struct net_device *dev,
+			  struct iw_request_info *info,
+			  struct iw_param *vwrq,
+			  char *extra)
+{
+	struct airo_info *local = dev->priv;
+
+	vwrq->value = local->config.txPower;
+	vwrq->fixed = 1;	/* No power control */
+	vwrq->disabled = (local->flags & FLAG_RADIO_OFF);
+	vwrq->flags = IW_TXPOW_MWATT;
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set Retry limits
+ */
+static int airo_set_retry(struct net_device *dev,
+			  struct iw_request_info *info,
+			  struct iw_param *vwrq,
+			  char *extra)
+{
+	struct airo_info *local = dev->priv;
+	int rc = -EINVAL;
+
+	if(vwrq->disabled) {
+		return -EINVAL;
+	}
+	if(vwrq->flags & IW_RETRY_LIMIT) {
+		if(vwrq->flags & IW_RETRY_MAX)
+			local->config.longRetryLimit = vwrq->value;
+		else if (vwrq->flags & IW_RETRY_MIN)
+			local->config.shortRetryLimit = vwrq->value;
+		else {
+			/* No modifier : set both */
+			local->config.longRetryLimit = vwrq->value;
+			local->config.shortRetryLimit = vwrq->value;
+		}
+		local->need_commit = 1;
+		rc = -EINPROGRESS;		/* Call commit handler */
+	}
+	if(vwrq->flags & IW_RETRY_LIFETIME) {
+		local->config.txLifetime = vwrq->value / 1024;
+		local->need_commit = 1;
+		rc = -EINPROGRESS;		/* Call commit handler */
+	}
+	return rc;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get Retry limits
+ */
+static int airo_get_retry(struct net_device *dev,
+			  struct iw_request_info *info,
+			  struct iw_param *vwrq,
+			  char *extra)
+{
+	struct airo_info *local = dev->priv;
+
+	vwrq->disabled = 0;      /* Can't be disabled */
+
+	/* Note : by default, display the min retry number */
+	if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+		vwrq->flags = IW_RETRY_LIFETIME;
+		vwrq->value = (int)local->config.txLifetime * 1024;
+	} else if((vwrq->flags & IW_RETRY_MAX)) {
+		vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+		vwrq->value = (int)local->config.longRetryLimit;
+	} else {
+		vwrq->flags = IW_RETRY_LIMIT;
+		vwrq->value = (int)local->config.shortRetryLimit;
+		if((int)local->config.shortRetryLimit != (int)local->config.longRetryLimit)
+			vwrq->flags |= IW_RETRY_MIN;
+	}
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get range info
+ */
+static int airo_get_range(struct net_device *dev,
+			  struct iw_request_info *info,
+			  struct iw_point *dwrq,
+			  char *extra)
+{
+	struct airo_info *local = dev->priv;
+	struct iw_range *range = (struct iw_range *) extra;
+	CapabilityRid cap_rid;		/* Card capability info */
+	int		i;
+	int		k;
+
+	readCapabilityRid(local, &cap_rid);
+
+	dwrq->length = sizeof(struct iw_range);
+	memset(range, 0, sizeof(range));
+	range->min_nwid = 0x0000;
+	range->max_nwid = 0x0000;
+	range->num_channels = 14;
+	/* Should be based on cap_rid.country to give only
+	 * what the current card support */
+	k = 0;
+	for(i = 0; i < 14; i++) {
+		range->freq[k].i = i + 1; /* List index */
+		range->freq[k].m = frequency_list[i] * 100000;
+		range->freq[k++].e = 1;	/* Values in table in MHz -> * 10^5 * 10 */
+	}
+	range->num_frequency = k;
+
+	/* Hum... Should put the right values there */
+	range->max_qual.qual = 10;
+	range->max_qual.level = 0x100 - 120;	/* -120 dBm */
+	range->max_qual.noise = 0;
+	range->sensitivity = 65535;
+
+	for(i = 0 ; i < 8 ; i++) {
+		range->bitrate[i] = cap_rid.supportedRates[i] * 500000;
+		if(range->bitrate[i] == 0)
+			break;
+	}
+	range->num_bitrates = i;
+
+	/* Set an indication of the max TCP throughput
+	 * in bit/s that we can expect using this interface.
+	 * May be use for QoS stuff... Jean II */
+	if(i > 2)
+		range->throughput = 5000 * 1000;
+	else
+		range->throughput = 1500 * 1000;
+
+	range->min_rts = 0;
+	range->max_rts = 2312;
+	range->min_frag = 256;
+	range->max_frag = 2312;
+
+	if(cap_rid.softCap & 2) {
+		// WEP: RC4 40 bits
+		range->encoding_size[0] = 5;
+		// RC4 ~128 bits
+		if (cap_rid.softCap & 0x100) {
+			range->encoding_size[1] = 13;
+			range->num_encoding_sizes = 2;
+		} else
+			range->num_encoding_sizes = 1;
+		range->max_encoding_tokens = (cap_rid.softCap & 0x80) ? 4 : 1;
+	} else {
+		range->num_encoding_sizes = 0;
+		range->max_encoding_tokens = 0;
+	}
+	range->min_pmp = 0;
+	range->max_pmp = 5000000;	/* 5 secs */
+	range->min_pmt = 0;
+	range->max_pmt = 65535 * 1024;	/* ??? */
+	range->pmp_flags = IW_POWER_PERIOD;
+	range->pmt_flags = IW_POWER_TIMEOUT;
+	range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
+
+	/* Transmit Power - values are in mW */
+	for(i = 0 ; i < 8 ; i++) {
+		range->txpower[i] = cap_rid.txPowerLevels[i];
+		if(range->txpower[i] == 0)
+			break;
+	}
+	range->num_txpower = i;
+	range->txpower_capa = IW_TXPOW_MWATT;
+	range->we_version_source = 12;
+	range->we_version_compiled = WIRELESS_EXT;
+	range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
+	range->retry_flags = IW_RETRY_LIMIT;
+	range->r_time_flags = IW_RETRY_LIFETIME;
+	range->min_retry = 1;
+	range->max_retry = 65535;
+	range->min_r_time = 1024;
+	range->max_r_time = 65535 * 1024;
+	/* Experimental measurements - boundary 11/5.5 Mb/s */
+	/* Note : with or without the (local->rssi), results
+	 * are somewhat different. - Jean II */
+	range->avg_qual.qual = 6;
+	if (local->rssi)
+		range->avg_qual.level = 186;	/* -70 dBm */
+	else
+		range->avg_qual.level = 176;	/* -80 dBm */
+	range->avg_qual.noise = 0;
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set Power Management
+ */
+static int airo_set_power(struct net_device *dev,
+			  struct iw_request_info *info,
+			  struct iw_param *vwrq,
+			  char *extra)
+{
+	struct airo_info *local = dev->priv;
+
+	if (vwrq->disabled) {
+		if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
+			return -EINVAL;
+		}
+		local->config.powerSaveMode = POWERSAVE_CAM;
+		local->config.rmode &= 0xFF00;
+		local->config.rmode |= RXMODE_BC_MC_ADDR;
+		local->need_commit = 1;
+		return -EINPROGRESS;		/* Call commit handler */
+	}
+	if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+		local->config.fastListenDelay = (vwrq->value + 500) / 1024;
+		local->config.powerSaveMode = POWERSAVE_PSPCAM;
+		local->need_commit = 1;
+	} else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
+		local->config.fastListenInterval = local->config.listenInterval = (vwrq->value + 500) / 1024;
+		local->config.powerSaveMode = POWERSAVE_PSPCAM;
+		local->need_commit = 1;
+	}
+	switch (vwrq->flags & IW_POWER_MODE) {
+		case IW_POWER_UNICAST_R:
+			if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
+				return -EINVAL;
+			}
+			local->config.rmode &= 0xFF00;
+			local->config.rmode |= RXMODE_ADDR;
+			local->need_commit = 1;
+			break;
+		case IW_POWER_ALL_R:
+			if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
+				return -EINVAL;
+			}
+			local->config.rmode &= 0xFF00;
+			local->config.rmode |= RXMODE_BC_MC_ADDR;
+			local->need_commit = 1;
+		case IW_POWER_ON:
+			break;
+		default:
+			return -EINVAL;
+	}
+	// Note : we may want to factor local->need_commit here
+	// Note2 : may also want to factor RXMODE_RFMON test
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get Power Management
+ */
+static int airo_get_power(struct net_device *dev,
+			  struct iw_request_info *info,
+			  struct iw_param *vwrq,
+			  char *extra)
+{
+	struct airo_info *local = dev->priv;
+
+	int mode = local->config.powerSaveMode;
+	if ((vwrq->disabled = (mode == POWERSAVE_CAM)))
+		return 0;
+	if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+		vwrq->value = (int)local->config.fastListenDelay * 1024;
+		vwrq->flags = IW_POWER_TIMEOUT;
+	} else {
+		vwrq->value = (int)local->config.fastListenInterval * 1024;
+		vwrq->flags = IW_POWER_PERIOD;
+	}
+	if ((local->config.rmode & 0xFF) == RXMODE_ADDR)
+		vwrq->flags |= IW_POWER_UNICAST_R;
+	else
+		vwrq->flags |= IW_POWER_ALL_R;
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set Sensitivity
+ */
+static int airo_set_sens(struct net_device *dev,
+			 struct iw_request_info *info,
+			 struct iw_param *vwrq,
+			 char *extra)
+{
+	struct airo_info *local = dev->priv;
+
+	local->config.rssiThreshold = vwrq->disabled ? RSSI_DEFAULT : vwrq->value;
+	local->need_commit = 1;
+
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get Sensitivity
+ */
+static int airo_get_sens(struct net_device *dev,
+			 struct iw_request_info *info,
+			 struct iw_param *vwrq,
+			 char *extra)
+{
+	struct airo_info *local = dev->priv;
+
+	vwrq->value = local->config.rssiThreshold;
+	vwrq->disabled = (vwrq->value == 0);
+	vwrq->fixed = 1;
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get AP List
+ * Note : this is deprecated in favor of IWSCAN
+ */
+static int airo_get_aplist(struct net_device *dev,
+			   struct iw_request_info *info,
+			   struct iw_point *dwrq,
+			   char *extra)
+{
+	struct airo_info *local = dev->priv;
+	struct sockaddr *address = (struct sockaddr *) extra;
+	struct iw_quality qual[IW_MAX_AP];
+	BSSListRid BSSList;
+	int i;
+	int loseSync = capable(CAP_NET_ADMIN) ? 1: -1;
+
+	for (i = 0; i < IW_MAX_AP; i++) {
+		if (readBSSListRid(local, loseSync, &BSSList))
+			break;
+		loseSync = 0;
+		memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN);
+		address[i].sa_family = ARPHRD_ETHER;
+		if (local->rssi)
+			qual[i].level = 0x100 - local->rssi[BSSList.rssi].rssidBm;
+		else
+			qual[i].level = (BSSList.rssi + 321) / 2;
+		qual[i].qual = qual[i].noise = 0;
+		qual[i].updated = 2;
+		if (BSSList.index == 0xffff)
+			break;
+	}
+	if (!i) {
+		StatusRid status_rid;		/* Card status info */
+		readStatusRid(local, &status_rid);
+		for (i = 0;
+		     i < min(IW_MAX_AP, 4) &&
+			     (status_rid.bssid[i][0]
+			      & status_rid.bssid[i][1]
+			      & status_rid.bssid[i][2]
+			      & status_rid.bssid[i][3]
+			      & status_rid.bssid[i][4]
+			      & status_rid.bssid[i][5])!=-1 &&
+			     (status_rid.bssid[i][0]
+			      | status_rid.bssid[i][1]
+			      | status_rid.bssid[i][2]
+			      | status_rid.bssid[i][3]
+			      | status_rid.bssid[i][4]
+			      | status_rid.bssid[i][5]);
+		     i++) {
+			memcpy(address[i].sa_data,
+			       status_rid.bssid[i], ETH_ALEN);
+			address[i].sa_family = ARPHRD_ETHER;
+		}
+	} else {
+		dwrq->flags = 1; /* Should be define'd */
+		memcpy(extra + sizeof(struct sockaddr)*i,
+		       &qual,  sizeof(struct iw_quality)*i);
+	}
+	dwrq->length = i;
+
+	return 0;
+}
+
+#if WIRELESS_EXT > 13
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : Initiate Scan
+ */
+static int airo_set_scan(struct net_device *dev,
+			 struct iw_request_info *info,
+			 struct iw_param *vwrq,
+			 char *extra)
+{
+	struct airo_info *ai = dev->priv;
+	Cmd cmd;
+	Resp rsp;
+
+	/* Note : you may have realised that, as this is a SET operation,
+	 * this is priviledged and therefore a normal user can't
+	 * perform scanning.
+	 * This is not an error, while the device perform scanning,
+	 * traffic doesn't flow, so it's a perfect DoS...
+	 * Jean II */
+
+	/* Initiate a scan command */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd=CMD_LISTBSS;
+	if (down_interruptible(&ai->sem))
+		return -ERESTARTSYS;
+	issuecommand(ai, &cmd, &rsp);
+	ai->scan_timestamp = jiffies;
+	up(&ai->sem);
+
+	/* At this point, just return to the user. */
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Translate scan data returned from the card to a card independant
+ * format that the Wireless Tools will understand - Jean II
+ */
+static inline char *airo_translate_scan(struct net_device *dev,
+					char *current_ev,
+					char *end_buf,
+					BSSListRid *list)
+{
+	struct airo_info *ai = dev->priv;
+	struct iw_event		iwe;		/* Temporary buffer */
+	u16			capabilities;
+	char *			current_val;	/* For rates */
+	int			i;
+
+	/* First entry *MUST* be the AP MAC address */
+	iwe.cmd = SIOCGIWAP;
+	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+	memcpy(iwe.u.ap_addr.sa_data, list->bssid, ETH_ALEN);
+	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
+
+	/* Other entries will be displayed in the order we give them */
+
+	/* Add the ESSID */
+	iwe.u.data.length = list->ssidLen;
+	if(iwe.u.data.length > 32)
+		iwe.u.data.length = 32;
+	iwe.cmd = SIOCGIWESSID;
+	iwe.u.data.flags = 1;
+	current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, list->ssid);
+
+	/* Add mode */
+	iwe.cmd = SIOCGIWMODE;
+	capabilities = le16_to_cpu(list->cap);
+	if(capabilities & (CAP_ESS | CAP_IBSS)) {
+		if(capabilities & CAP_ESS)
+			iwe.u.mode = IW_MODE_INFRA;
+		else
+			iwe.u.mode = IW_MODE_ADHOC;
+		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
+	}
+
+	/* Add frequency */
+	iwe.cmd = SIOCGIWFREQ;
+	iwe.u.freq.m = le16_to_cpu(list->dsChannel);
+	iwe.u.freq.m = frequency_list[iwe.u.freq.m] * 100000;
+	iwe.u.freq.e = 1;
+	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
+
+	/* Add quality statistics */
+	iwe.cmd = IWEVQUAL;
+	if (ai->rssi)
+		iwe.u.qual.level = 0x100 - ai->rssi[list->rssi].rssidBm;
+	else
+		iwe.u.qual.level = (list->rssi + 321) / 2;
+	iwe.u.qual.noise = 0;
+	iwe.u.qual.qual = 0;
+	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
+
+	/* Add encryption capability */
+	iwe.cmd = SIOCGIWENCODE;
+	if(capabilities & CAP_PRIVACY)
+		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+	else
+		iwe.u.data.flags = IW_ENCODE_DISABLED;
+	iwe.u.data.length = 0;
+	current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, list->ssid);
+
+	/* Rate : stuffing multiple values in a single event require a bit
+	 * more of magic - Jean II */
+	current_val = current_ev + IW_EV_LCP_LEN;
+
+	iwe.cmd = SIOCGIWRATE;
+	/* Those two flags are ignored... */
+	iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+	/* Max 8 values */
+	for(i = 0 ; i < 8 ; i++) {
+		/* NULL terminated */
+		if(list->rates[i] == 0)
+			break;
+		/* Bit rate given in 500 kb/s units (+ 0x80) */
+		iwe.u.bitrate.value = ((list->rates[i] & 0x7f) * 500000);
+		/* Add new value to event */
+		current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
+	}
+	/* Check if we added any event */
+	if((current_val - current_ev) > IW_EV_LCP_LEN)
+		current_ev = current_val;
+
+	/* The other data in the scan result are not really
+	 * interesting, so for now drop it - Jean II */
+	return current_ev;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : Read Scan Results
+ */
+static int airo_get_scan(struct net_device *dev,
+			 struct iw_request_info *info,
+			 struct iw_point *dwrq,
+			 char *extra)
+{
+	struct airo_info *ai = dev->priv;
+	BSSListRid BSSList;
+	int rc;
+	char *current_ev = extra;
+
+	/* When we are associated again, the scan has surely finished.
+	 * Just in case, let's make sure enough time has elapsed since
+	 * we started the scan. - Javier */
+	if(ai->scan_timestamp && time_before(jiffies,ai->scan_timestamp+3*HZ)) {
+		/* Important note : we don't want to block the caller
+		 * until results are ready for various reasons.
+		 * First, managing wait queues is complex and racy
+		 * (there may be multiple simultaneous callers).
+		 * Second, we grab some rtnetlink lock before comming
+		 * here (in dev_ioctl()).
+		 * Third, the caller can wait on the Wireless Event
+		 * - Jean II */
+		return -EAGAIN;
+	}
+	ai->scan_timestamp = 0;
+
+	/* There's only a race with proc_BSSList_open(), but its
+	 * consequences are begnign. So I don't bother fixing it - Javier */
+
+	/* Try to read the first entry of the scan result */
+	rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList));
+	if((rc) || (BSSList.index == 0xffff)) {
+		/* Client error, no scan results...
+		 * The caller need to restart the scan. */
+		return -ENODATA;
+	}
+
+	/* Read and parse all entries */
+	while((!rc) && (BSSList.index != 0xffff)) {
+		/* Translate to WE format this entry */
+		current_ev = airo_translate_scan(dev, current_ev,
+						 extra + IW_SCAN_MAX_DATA,
+						 &BSSList);
+
+		/* Read next entry */
+		rc = PC4500_readrid(ai, RID_BSSLISTNEXT,
+				    &BSSList, sizeof(BSSList));
+	}
+	/* Length of data */
+	dwrq->length = (current_ev - extra);
+	dwrq->flags = 0;	/* todo */
+
+	return 0;
+}
+#endif	/* WIRELESS_EXT > 13 */
+
+#ifdef WIRELESS_SPY
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set Spy List
+ */
+static int airo_set_spy(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *dwrq,
+			char *extra)
+{
+	struct airo_info *local = dev->priv;
+	struct sockaddr *address = (struct sockaddr *) extra;
+
+	/* Disable spy while we copy the addresses.
+	 * As we don't disable interrupts, we need to do this to avoid races */
+	local->spy_number = 0;
+
+	if (dwrq->length > 0) {
+		int i;
+
+		/* Copy addresses */
+		for (i = 0; i < dwrq->length; i++)
+			memcpy(local->spy_address[i], address[i].sa_data, ETH_ALEN);
+		/* Reset stats */
+		memset(local->spy_stat, 0, sizeof(struct iw_quality) * IW_MAX_SPY);
+	}
+	/* Enable addresses */
+	local->spy_number = dwrq->length;
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get Spy List
+ */
+static int airo_get_spy(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *dwrq,
+			char *extra)
+{
+	struct airo_info *local = dev->priv;
+	struct sockaddr *address = (struct sockaddr *) extra;
+	int i;
+
+	dwrq->length = local->spy_number;
+
+	/* Copy addresses. */
+	for(i = 0; i < local->spy_number; i++) 	{
+		memcpy(address[i].sa_data, local->spy_address[i], ETH_ALEN);
+		address[i].sa_family = AF_UNIX;
+	}
+	/* Copy stats to the user buffer (just after). */
+	if(local->spy_number > 0)
+		memcpy(extra  + (sizeof(struct sockaddr) * local->spy_number),
+		       local->spy_stat, sizeof(struct iw_quality) * local->spy_number);
+	/* Reset updated flags. */
+	for (i=0; i<local->spy_number; i++)
+		local->spy_stat[i].updated = 0;
+	return 0;
+}
+#endif			/* WIRELESS_SPY */
+
+/*------------------------------------------------------------------*/
+/*
+ * Commit handler : called after a bunch of SET operations
+ */
+static int airo_config_commit(struct net_device *dev,
+			      struct iw_request_info *info,	/* NULL */
+			      void *zwrq,			/* NULL */
+			      char *extra)			/* NULL */
+{
+	struct airo_info *local = dev->priv;
+	Resp rsp;
+
+	if (!local->need_commit)
+		return 0;
+
+	/* Some of the "SET" function may have modified some of the
+	 * parameters. It's now time to commit them in the card */
+	disable_MAC(local);
+	writeConfigRid(local);
+	enable_MAC(local, &rsp);
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Structures to export the Wireless Handlers
+ */
+
+static const struct iw_priv_args airo_private_args[] = {
+/*{ cmd,         set_args,                            get_args, name } */
+  { AIROIOCTL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl),
+    IW_PRIV_TYPE_BYTE | 2047, "airoioctl" },
+  { AIROIDIFC, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl),
+    IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" },
+};
+
+#if WIRELESS_EXT > 12
+static const iw_handler		airo_handler[] =
+{
+	(iw_handler) airo_config_commit,	/* SIOCSIWCOMMIT */
+	(iw_handler) airo_get_name,		/* SIOCGIWNAME */
+	(iw_handler) NULL,			/* SIOCSIWNWID */
+	(iw_handler) NULL,			/* SIOCGIWNWID */
+	(iw_handler) airo_set_freq,		/* SIOCSIWFREQ */
+	(iw_handler) airo_get_freq,		/* SIOCGIWFREQ */
+	(iw_handler) airo_set_mode,		/* SIOCSIWMODE */
+	(iw_handler) airo_get_mode,		/* SIOCGIWMODE */
+	(iw_handler) airo_set_sens,		/* SIOCSIWSENS */
+	(iw_handler) airo_get_sens,		/* SIOCGIWSENS */
+	(iw_handler) NULL,			/* SIOCSIWRANGE */
+	(iw_handler) airo_get_range,		/* SIOCGIWRANGE */
+	(iw_handler) NULL,			/* SIOCSIWPRIV */
+	(iw_handler) NULL,			/* SIOCGIWPRIV */
+	(iw_handler) NULL,			/* SIOCSIWSTATS */
+	(iw_handler) NULL,			/* SIOCGIWSTATS */
+#ifdef WIRELESS_SPY
+	(iw_handler) airo_set_spy,		/* SIOCSIWSPY */
+	(iw_handler) airo_get_spy,		/* SIOCGIWSPY */
+#else	/* WIRELESS_SPY */
+	(iw_handler) NULL,			/* SIOCSIWSPY */
+	(iw_handler) NULL,			/* SIOCGIWSPY */
+#endif	/* WIRELESS_SPY */
+	(iw_handler) NULL,			/* -- hole -- */
+	(iw_handler) NULL,			/* -- hole -- */
+	(iw_handler) airo_set_wap,		/* SIOCSIWAP */
+	(iw_handler) airo_get_wap,		/* SIOCGIWAP */
+	(iw_handler) NULL,			/* -- hole -- */
+	(iw_handler) airo_get_aplist,		/* SIOCGIWAPLIST */
+#if WIRELESS_EXT > 13
+	(iw_handler) airo_set_scan,		/* SIOCSIWSCAN */
+	(iw_handler) airo_get_scan,		/* SIOCGIWSCAN */
+#else	/* WIRELESS_EXT > 13 */
+	(iw_handler) NULL,			/* SIOCSIWSCAN */
+	(iw_handler) NULL,			/* SIOCGIWSCAN */
+#endif	/* WIRELESS_EXT > 13 */
+	(iw_handler) airo_set_essid,		/* SIOCSIWESSID */
+	(iw_handler) airo_get_essid,		/* SIOCGIWESSID */
+	(iw_handler) airo_set_nick,		/* SIOCSIWNICKN */
+	(iw_handler) airo_get_nick,		/* SIOCGIWNICKN */
+	(iw_handler) NULL,			/* -- hole -- */
+	(iw_handler) NULL,			/* -- hole -- */
+	(iw_handler) airo_set_rate,		/* SIOCSIWRATE */
+	(iw_handler) airo_get_rate,		/* SIOCGIWRATE */
+	(iw_handler) airo_set_rts,		/* SIOCSIWRTS */
+	(iw_handler) airo_get_rts,		/* SIOCGIWRTS */
+	(iw_handler) airo_set_frag,		/* SIOCSIWFRAG */
+	(iw_handler) airo_get_frag,		/* SIOCGIWFRAG */
+	(iw_handler) airo_set_txpow,		/* SIOCSIWTXPOW */
+	(iw_handler) airo_get_txpow,		/* SIOCGIWTXPOW */
+	(iw_handler) airo_set_retry,		/* SIOCSIWRETRY */
+	(iw_handler) airo_get_retry,		/* SIOCGIWRETRY */
+	(iw_handler) airo_set_encode,		/* SIOCSIWENCODE */
+	(iw_handler) airo_get_encode,		/* SIOCGIWENCODE */
+	(iw_handler) airo_set_power,		/* SIOCSIWPOWER */
+	(iw_handler) airo_get_power,		/* SIOCGIWPOWER */
+};
+
+/* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here.
+ * We want to force the use of the ioctl code, because those can't be
+ * won't work the iw_handler code (because they simultaneously read
+ * and write data and iw_handler can't do that).
+ * Note that it's perfectly legal to read/write on a single ioctl command,
+ * you just can't use iwpriv and need to force it via the ioctl handler.
+ * Jean II */
+static const iw_handler		airo_private_handler[] =
+{
+	NULL,				/* SIOCIWFIRSTPRIV */
+};
+
+static const struct iw_handler_def	airo_handler_def =
+{
+	num_standard:	sizeof(airo_handler)/sizeof(iw_handler),
+	num_private:	sizeof(airo_private_handler)/sizeof(iw_handler),
+	num_private_args: sizeof(airo_private_args)/sizeof(struct iw_priv_args),
+	standard:	(iw_handler *) airo_handler,
+	private:	(iw_handler *) airo_private_handler,
+	private_args:	(struct iw_priv_args *) airo_private_args,
+};
+
+#endif /* WIRELESS_EXT > 12 */
+#endif /* WIRELESS_EXT */
+
+/*
+ * This defines the configuration part of the Wireless Extensions
+ * Note : irq and spinlock protection will occur in the subroutines
+ *
+ * TODO :
+ *	o Check input value more carefully and fill correct values in range
+ *	o Test and shakeout the bugs (if any)
+ *
+ * Jean II
+ *
+ * Javier Achirica did a great job of merging code from the unnamed CISCO
+ * developer that added support for flashing the card.
+ */
+static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	int rc = 0;
+#if defined(WIRELESS_EXT) && WIRELESS_EXT < 13
+	struct iwreq *wrq = (struct iwreq *) rq;
+#endif /* WIRELESS_EXT < 13 */
 
-	// Get the current fragmentation threshold
-	case SIOCGIWFRAG:
-		wrq->u.frag.value = config.fragThresh;
-		wrq->u.frag.disabled = (wrq->u.frag.value >= 2312);
-		wrq->u.frag.fixed = 1;
+	switch (cmd) {
+/* WE 13 and higher will use airo_handler_def */
+#if defined(WIRELESS_EXT) && WIRELESS_EXT < 13
+	case SIOCGIWNAME:	// Get name
+		airo_get_name(dev, NULL, (char *) &(wrq->u.name), NULL);
 		break;
 
-		// Set mode of operation
-	case SIOCSIWMODE:
-		switch(wrq->u.mode) {
-		case IW_MODE_ADHOC:
-			config.opmode = MODE_STA_IBSS;
-			local->need_commit = 1;
-			break;
-		case IW_MODE_INFRA:
-			config.opmode = MODE_STA_ESS;
-			local->need_commit = 1;
-			break;
-		case IW_MODE_MASTER:
-			config.opmode = MODE_AP;
-			local->need_commit = 1;
-			break;
-		case IW_MODE_REPEAT:
-			config.opmode = MODE_AP_RPTR;
-			local->need_commit = 1;
-			break;
-		default:
-			rc = -EINVAL;
+	case SIOCSIWFREQ:	// Set frequency/channel
+		rc = airo_set_freq(dev, NULL, &(wrq->u.freq), NULL);
+		break;
+
+	case SIOCGIWFREQ:	// Get frequency/channel
+		rc = airo_get_freq(dev, NULL, &(wrq->u.freq), NULL);
+		break;
+
+	case SIOCSIWESSID:	// Set desired network name (ESSID)
+		{
+			char essidbuf[IW_ESSID_MAX_SIZE+1];
+			if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) {
+				rc = -E2BIG;
+				break;
+			}
+			if (copy_from_user(essidbuf, wrq->u.essid.pointer,
+					   wrq->u.essid.length)) {
+				rc = -EFAULT;
+				break;
+			}
+			rc = airo_set_essid(dev, NULL,
+					    &(wrq->u.essid), essidbuf);
 		}
 		break;
 
-		// Get mode of operation
-	case SIOCGIWMODE:
-		/* If not managed, assume it's ad-hoc */
-		switch (config.opmode & 0xFF) {
-		case MODE_STA_ESS:
-			wrq->u.mode = IW_MODE_INFRA;
-			break;
-		case MODE_AP:
-			wrq->u.mode = IW_MODE_MASTER;
-			break;
-		case MODE_AP_RPTR:
-			wrq->u.mode = IW_MODE_REPEAT;
-			break;
-		default:
-			wrq->u.mode = IW_MODE_ADHOC;
+	case SIOCGIWESSID:	// Get current network name (ESSID)
+		{
+			char essidbuf[IW_ESSID_MAX_SIZE+1];
+			if (wrq->u.essid.pointer)
+				rc = airo_get_essid(dev, NULL,
+						    &(wrq->u.essid), essidbuf);
+				if ( copy_to_user(wrq->u.essid.pointer,
+						  essidbuf,
+						  wrq->u.essid.length) )
+					rc = -EFAULT;
 		}
 		break;
 
-		// Set WEP keys and mode
-	case SIOCSIWENCODE:
-		/* Is WEP supported ? */
-		/* Older firmware doesn't support this...
-		if(!(cap_rid.softCap & 2)) {
-			rc = -EOPNOTSUPP;
-			break;
-		} */
-		/* Basic checking: do we have a key to set ? */
-		if (wrq->u.encoding.pointer != (caddr_t) 0) {
-			wep_key_t key;
-			int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1;
-			int current_index = get_wep_key(local, 0xffff);
-			/* Check the size of the key */
-			if (wrq->u.encoding.length > MAX_KEY_SIZE) {
-				rc = -EINVAL;
+	case SIOCSIWAP:
+		rc = airo_set_wap(dev, NULL, &(wrq->u.ap_addr), NULL);
+		break;
+
+	case SIOCGIWAP:		// Get current Access Point (BSSID)
+		rc = airo_get_wap(dev, NULL, &(wrq->u.ap_addr), NULL);
+		break;
+
+	case SIOCSIWNICKN:	// Set desired station name
+		{
+			char nickbuf[IW_ESSID_MAX_SIZE+1];
+			if (wrq->u.data.length > IW_ESSID_MAX_SIZE) {
+				rc = -E2BIG;
 				break;
 			}
-			/* Check the index (none -> use current) */
-			if ((index < 0) || (index>=(cap_rid.softCap&0x80)?4:1))
-				index = current_index;
-			/* Set the length */
-			if (wrq->u.encoding.length > MIN_KEY_SIZE)
-				key.len = MAX_KEY_SIZE;
-			else
-				if (wrq->u.encoding.length > 0)
-					key.len = MIN_KEY_SIZE;
-				else
-					/* Disable the key */
-					key.len = 0;
-			/* Check if the key is not marked as invalid */
-			if(!(wrq->u.encoding.flags & IW_ENCODE_NOKEY)) {
-				/* Cleanup */
-				memset(key.key, 0, MAX_KEY_SIZE);
-				/* Copy the key in the driver */
-				if(copy_from_user(key.key,
-						  wrq->u.encoding.pointer,
-						  wrq->u.encoding.length)) {
-					key.len = 0;
+			if (copy_from_user(nickbuf, wrq->u.data.pointer,
+					   wrq->u.data.length)) {
+				rc = -EFAULT;
+				break;
+			}
+			rc = airo_set_nick(dev, NULL,
+					   &(wrq->u.data), nickbuf);
+		}
+		break;
+
+	case SIOCGIWNICKN:	// Get current station name
+		{
+			char nickbuf[IW_ESSID_MAX_SIZE+1];
+			if (wrq->u.data.pointer)
+				rc = airo_get_nick(dev, NULL,
+						   &(wrq->u.data), nickbuf);
+				if ( copy_to_user(wrq->u.data.pointer,
+						  nickbuf,
+						  wrq->u.data.length) )
 					rc = -EFAULT;
+		}
+		break;
+
+	case SIOCSIWRATE:	// Set the desired bit-rate
+		rc = airo_set_rate(dev, NULL, &(wrq->u.bitrate), NULL);
+		break;
+
+	case SIOCGIWRATE:	// Get the current bit-rate
+		rc = airo_get_rate(dev, NULL, &(wrq->u.bitrate), NULL);
+		break;
+
+	case SIOCSIWRTS:	// Set the desired RTS threshold
+		rc = airo_set_rts(dev, NULL, &(wrq->u.rts), NULL);
+		break;
+
+	case SIOCGIWRTS:	// Get the current RTS threshold
+		rc = airo_get_rts(dev, NULL, &(wrq->u.rts), NULL);
+		break;
+
+	case SIOCSIWFRAG:	// Set the desired fragmentation threshold
+		rc = airo_set_frag(dev, NULL, &(wrq->u.frag), NULL);
+		break;
+
+	case SIOCGIWFRAG:	// Get the current fragmentation threshold
+		rc = airo_get_frag(dev, NULL, &(wrq->u.frag), NULL);
+		break;
+
+	case SIOCSIWMODE:	// Set mode of operation
+		rc = airo_set_mode(dev, NULL, &(wrq->u.mode), NULL);
+		break;
+
+	case SIOCGIWMODE:	// Get mode of operation
+		rc = airo_get_mode(dev, NULL, &(wrq->u.mode), NULL);
+		break;
+
+	case SIOCSIWENCODE:	// Set WEP keys and mode
+		{
+			char keybuf[MAX_KEY_SIZE];
+			if (wrq->u.encoding.pointer) {
+				/* We actually have a key to set */
+				if (wrq->u.encoding.length > MAX_KEY_SIZE) {
+					rc = -E2BIG;
 					break;
 				}
-				/* Send the key to the card */
-				set_wep_key(local, index, key.key,
-					    key.len, 1);
-			}
-			/* WE specify that if a valid key is set, encryption
-			 * should be enabled (user may turn it off later)
-			 * This is also how "iwconfig ethX key on" works */
-			if((index == current_index) && (key.len > 0) &&
-			   (config.authType == AUTH_OPEN)) {
-				config.authType = AUTH_ENCRYPT;
-				local->need_commit = 1;
-			}
-		} else {
-			/* Do we want to just set the transmit key index ? */
-			int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1;
-			if ((index>=0) && (index<(cap_rid.softCap&0x80)?4:1)) {
-				set_wep_key(local, index, 0, 0, 1);
-			} else
-				/* Don't complain if only change the mode */
-				if(!wrq->u.encoding.flags & IW_ENCODE_MODE) {
-					rc = -EINVAL;
+				if (copy_from_user(keybuf,
+						   wrq->u.encoding.pointer,
+						   wrq->u.encoding.length)) {
+					rc = -EFAULT;
 					break;
 				}
+			} else if (wrq->u.encoding.length != 0) {
+				rc = -EINVAL;
+				break;
+			}
+			rc = airo_set_encode(dev, NULL,
+					     &(wrq->u.encoding), keybuf);
 		}
-		/* Read the flags */
-		if(wrq->u.encoding.flags & IW_ENCODE_DISABLED)
-			config.authType = AUTH_OPEN;	// disable encryption
-		if(wrq->u.encoding.flags & IW_ENCODE_RESTRICTED)
-			config.authType = AUTH_SHAREDKEY;	// Only Both
-		if(wrq->u.encoding.flags & IW_ENCODE_OPEN)
-			config.authType = AUTH_ENCRYPT;	// Only Wep
-		/* Commit the changes if needed */
-		if(wrq->u.encoding.flags & IW_ENCODE_MODE)
-			local->need_commit = 1;
 		break;
 
-		// Get the WEP keys and mode
-	case SIOCGIWENCODE:
-		/* Is it supported ? */
-		if(!(cap_rid.softCap & 2)) {
-			rc = -EOPNOTSUPP;
-			break;
-		}
+	case SIOCGIWENCODE:	// Get the WEP keys and mode
 		// Only super-user can see WEP key
+		// Note : this is needed only for very old versions of WE
 		if (!capable(CAP_NET_ADMIN)) {
 			rc = -EPERM;
 			break;
 		}
-
-		// Basic checking...
-		if (wrq->u.encoding.pointer != (caddr_t) 0) {
-			char zeros[16];
-			int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1;
-
-			memset(zeros,0, sizeof(zeros));
-			/* Check encryption mode */
-			wrq->u.encoding.flags = IW_ENCODE_NOKEY;
-			/* Is WEP enabled ??? */
-			switch(config.authType)	{
-			case AUTH_ENCRYPT:
-				wrq->u.encoding.flags |= IW_ENCODE_OPEN;
-				break;
-			case AUTH_SHAREDKEY:
-				wrq->u.encoding.flags |= IW_ENCODE_RESTRICTED;
-				break;
-			default:
-			case AUTH_OPEN:
-				wrq->u.encoding.flags |= IW_ENCODE_DISABLED;
-				break;
-			}
-
-			/* Which key do we want ? -1 -> tx index */
-			if((index < 0) || (index >= (cap_rid.softCap&0x80)?4:1))
-				index = get_wep_key(local, 0xffff);
-			wrq->u.encoding.flags |= index + 1;
-			/* Copy the key to the user buffer */
-			wrq->u.encoding.length = get_wep_key(local, index);
-			if (wrq->u.encoding.length > 16) {
-				wrq->u.encoding.length=0;
+		{
+			char keybuf[MAX_KEY_SIZE];
+			rc = airo_get_encode(dev, NULL,
+					     &(wrq->u.encoding), keybuf);
+			if (wrq->u.encoding.pointer) {
+				if (copy_to_user(wrq->u.encoding.pointer,
+						 keybuf,
+						 wrq->u.encoding.length))
+					rc = -EFAULT;
 			}
-
-			if(copy_to_user(wrq->u.encoding.pointer, zeros,
-					wrq->u.encoding.length))
-				rc = -EFAULT;
 		}
 		break;
 
-#if WIRELESS_EXT > 9
-		// Get the current Tx-Power
-	case SIOCGIWTXPOW:
-		wrq->u.txpower.value = config.txPower;
-		wrq->u.txpower.fixed = 1;	/* No power control */
-		wrq->u.txpower.disabled = (local->flags & FLAG_RADIO_OFF);
-		wrq->u.txpower.flags = IW_TXPOW_MWATT;
+	case SIOCGIWTXPOW:	// Get the current Tx-Power
+		rc=airo_get_txpow(dev, NULL, &(wrq->u.txpower), NULL);
 		break;
 	case SIOCSIWTXPOW:
-		if (wrq->u.txpower.disabled) {
-			local->flags |= FLAG_RADIO_OFF;
-			local->need_commit = 1;
-			break;
-		}
-		if (wrq->u.txpower.flags != IW_TXPOW_MWATT) {
-			rc = -EINVAL;
-			break;
-		}
-		local->flags &= ~FLAG_RADIO_OFF;
-		rc = -EINVAL;
-		for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
-			if ((wrq->u.txpower.value==cap_rid.txPowerLevels[i])) {
-				config.txPower = wrq->u.txpower.value;
-				local->need_commit = 1;
-				rc = 0;
-				break;
-			}
+		rc=airo_set_txpow(dev, NULL, &(wrq->u.txpower), NULL);
 		break;
-#endif /* WIRELESS_EXT > 9 */
 
-#if WIRELESS_EXT > 10
 	case SIOCSIWRETRY:
-		if(wrq->u.retry.disabled) {
-			rc = -EINVAL;
-			break;
-		}
-		local->need_commit = 0;
-		if(wrq->u.retry.flags & IW_RETRY_LIMIT) {
-			if(wrq->u.retry.flags & IW_RETRY_MAX)
-				config.longRetryLimit = wrq->u.retry.value;
-			else if (wrq->u.retry.flags & IW_RETRY_MIN)
-				config.shortRetryLimit = wrq->u.retry.value;
-			else {
-				/* No modifier : set both */
-				config.longRetryLimit = wrq->u.retry.value;
-				config.shortRetryLimit = wrq->u.retry.value;
-			}
-			local->need_commit = 1;
-		}
-		if(wrq->u.retry.flags & IW_RETRY_LIFETIME) {
-			config.txLifetime = wrq->u.retry.value / 1024;
-			local->need_commit = 1;
-		}
-		if(local->need_commit == 0) {
-			rc = -EINVAL;
-		}
+		rc=airo_set_retry(dev, NULL, &(wrq->u.retry), NULL);
 		break;
-
 	case SIOCGIWRETRY:
-		wrq->u.retry.disabled = 0;      /* Can't be disabled */
-
-		/* Note : by default, display the min retry number */
-		if((wrq->u.retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
-			wrq->u.retry.flags = IW_RETRY_LIFETIME;
-			wrq->u.retry.value = (int)config.txLifetime * 1024;
-		} else if((wrq->u.retry.flags & IW_RETRY_MAX)) {
-			wrq->u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
-			wrq->u.retry.value = (int)config.longRetryLimit;
-		} else {
-			wrq->u.retry.flags = IW_RETRY_LIMIT;
-			wrq->u.retry.value = (int)config.shortRetryLimit;
-			if((int)config.shortRetryLimit != (int)config.longRetryLimit)
-				wrq->u.retry.flags |= IW_RETRY_MIN;
-		}
-
+		rc=airo_get_retry(dev, NULL, &(wrq->u.retry), NULL);
 		break;
-#endif /* WIRELESS_EXT > 10 */
 
-		// Get range of parameters
-	case SIOCGIWRANGE:
-		if (wrq->u.data.pointer) {
+	case SIOCGIWRANGE:	// Get range of parameters
+		{
 			struct iw_range range;
-			int		i;
-			int		k;
-
-			wrq->u.data.length = sizeof(range);
-			memset(&range, 0, sizeof(range));
-			range.min_nwid = 0x0000;
-			range.max_nwid = 0x0000;
-			range.num_channels = 14;
-			/* Should be based on cap_rid.country to give only
-			 * what the current card support */
-			k = 0;
-			for(i = 0; i < 14; i++) {
-				range.freq[k].i = i + 1; /* List index */
-				range.freq[k].m = frequency_list[i] * 100000;
-				range.freq[k++].e = 1;	/* Values in table in MHz -> * 10^5 * 10 */
-			}
-			range.num_frequency = k;
-
-			/* Hum... Should put the right values there */
-			range.max_qual.qual = 10;
-			range.max_qual.level = 0x100 - 120;	/* -120 dBm */
-			range.max_qual.noise = 0;
-			range.sensitivity = 65535;
-
-			for(i = 0 ; i < 8 ; i++) {
-				range.bitrate[i] = cap_rid.supportedRates[i] * 500000;
-				if(range.bitrate[i] == 0)
-					break;
-			}
-			range.num_bitrates = i;
-
-			/* Set an indication of the max TCP throughput
-			 * in bit/s that we can expect using this interface.
-			 * May be use for QoS stuff... Jean II */
-			if(i > 2)
-				range.throughput = 5 * 1000 * 1000;
-			else
-				range.throughput = 1.5 * 1000 * 1000;
-
-			range.min_rts = 0;
-			range.max_rts = 2312;
-			range.min_frag = 256;
-			range.max_frag = 2312;
-
-			if(cap_rid.softCap & 2) {
-				// WEP: RC4 40 bits
-				range.encoding_size[0] = 5;
-				// RC4 ~128 bits
-				if (cap_rid.softCap & 0x100) {
-					range.encoding_size[1] = 13;
-					range.num_encoding_sizes = 2;
-				} else
-					range.num_encoding_sizes = 1;
-				range.max_encoding_tokens = (cap_rid.softCap & 0x80) ? 4 : 1;
-			} else {
-				range.num_encoding_sizes = 0;
-				range.max_encoding_tokens = 0;
-			}
-#if WIRELESS_EXT > 9
-			range.min_pmp = 0;
-			range.max_pmp = 5000000;	/* 5 secs */
-			range.min_pmt = 0;
-			range.max_pmt = 65535 * 1024;	/* ??? */
-			range.pmp_flags = IW_POWER_PERIOD;
-			range.pmt_flags = IW_POWER_TIMEOUT;
-			range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
-
-			/* Transmit Power - values are in mW */
-			for(i = 0 ; i < 8 ; i++) {
-				range.txpower[i] = cap_rid.txPowerLevels[i];
-				if(range.txpower[i] == 0)
-					break;
-			}
-			range.num_txpower = i;
-			range.txpower_capa = IW_TXPOW_MWATT;
-#endif /* WIRELESS_EXT > 9 */
-#if WIRELESS_EXT > 10
-			range.we_version_source = 12;
-			range.we_version_compiled = WIRELESS_EXT;
-			range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
-			range.retry_flags = IW_RETRY_LIMIT;
-			range.r_time_flags = IW_RETRY_LIFETIME;
-			range.min_retry = 1;
-			range.max_retry = 65535;
-			range.min_r_time = 1024;
-			range.max_r_time = 65535 * 1024;
-#endif /* WIRELESS_EXT > 10 */
-#if WIRELESS_EXT > 11
-			/* Experimental measurements - boundary 11/5.5 Mb/s */
-			/* Note : with or without the (local->rssi), results
-			 * are somewhat different. - Jean II */
-			range.avg_qual.qual = 6;
-			if (local->rssi)
-				range.avg_qual.level = 186;	/* -70 dBm */
-			else
-				range.avg_qual.level = 176;	/* -80 dBm */
-			range.avg_qual.noise = 0;
-#endif /* WIRELESS_EXT > 11 */
-
-			if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range)))
+			rc = airo_get_range(dev, NULL,
+					    &(wrq->u.data), (char *) &range);
+			if (copy_to_user(wrq->u.data.pointer, &range,
+					 sizeof(struct iw_range)))
 				rc = -EFAULT;
 		}
 		break;
 
 	case SIOCGIWPOWER:
-	{
-		int mode = config.powerSaveMode;
-		if ((wrq->u.power.disabled = (mode == POWERSAVE_CAM)))
-			break;
-		if ((wrq->u.power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
-			wrq->u.power.value = (int)config.fastListenDelay * 1024;
-			wrq->u.power.flags = IW_POWER_TIMEOUT;
-		} else {
-			wrq->u.power.value = (int)config.fastListenInterval * 1024;
-			wrq->u.power.flags = IW_POWER_PERIOD;
-		}
-		if ((config.rmode & 0xFF) == RXMODE_ADDR)
-			wrq->u.power.flags |= IW_POWER_UNICAST_R;
-		else
-			wrq->u.power.flags |= IW_POWER_ALL_R;
-	}
-	break;
+		rc=airo_get_power(dev, NULL, &(wrq->u.power), NULL);
+		break;
 
 	case SIOCSIWPOWER:
-		if (wrq->u.power.disabled) {
-			if ((config.rmode & 0xFF) >= RXMODE_RFMON) {
-				rc = -EINVAL;
-				break;
-			}
-			config.powerSaveMode = POWERSAVE_CAM;
-			config.rmode &= 0xFF00;
-			config.rmode |= RXMODE_BC_MC_ADDR;
-			local->need_commit = 1;
-			break;
-		}
-		if ((wrq->u.power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
-			config.fastListenDelay = (wrq->u.power.value + 500) / 1024;
-			config.powerSaveMode = POWERSAVE_PSPCAM;
-			local->need_commit = 1;
-		} else if ((wrq->u.power.flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
-			config.fastListenInterval = config.listenInterval = (wrq->u.power.value + 500) / 1024;
-			config.powerSaveMode = POWERSAVE_PSPCAM;
-			local->need_commit = 1;
-		}
-		switch (wrq->u.power.flags & IW_POWER_MODE) {
-		case IW_POWER_UNICAST_R:
-			if ((config.rmode & 0xFF) >= RXMODE_RFMON) {
-				rc = -EINVAL;
-				break;
-			}
-			config.rmode &= 0xFF00;
-			config.rmode |= RXMODE_ADDR;
-			local->need_commit = 1;
-			break;
-		case IW_POWER_ALL_R:
-			if ((config.rmode & 0xFF) >= RXMODE_RFMON) {
-				rc = -EINVAL;
-				break;
-			}
-			config.rmode &= 0xFF00;
-			config.rmode |= RXMODE_BC_MC_ADDR;
-			local->need_commit = 1;
-		case IW_POWER_ON:
-			break;
-		default:
-			rc = -EINVAL;
-		}
+		rc=airo_set_power(dev, NULL, &(wrq->u.power), NULL);
 		break;
 
 	case SIOCGIWSENS:
-		wrq->u.sens.value = config.rssiThreshold;
-		wrq->u.sens.disabled = (wrq->u.sens.value == 0);
-		wrq->u.sens.fixed = 1;
+		rc = airo_get_sens(dev, NULL, &(wrq->u.sens), NULL);
 		break;
 
 	case SIOCSIWSENS:
-		config.rssiThreshold = wrq->u.sens.disabled ? RSSI_DEFAULT : wrq->u.sens.value;
-		local->need_commit = 1;
+		rc = airo_set_sens(dev, NULL, &(wrq->u.sens), NULL);
 		break;
 
 	case SIOCGIWAPLIST:
-		if (wrq->u.data.pointer) {
-			int i, rc;
-			struct sockaddr s[IW_MAX_AP];
-			struct iw_quality qual[IW_MAX_AP];
-			BSSListRid BSSList;
-			int loseSync = capable(CAP_NET_ADMIN) ? 1: -1;
-			for (i = 0; i < IW_MAX_AP; i++) {
-				if (readBSSListRid(local, loseSync, &BSSList))
-					break;
-				loseSync = 0;
-				memcpy(s[i].sa_data, BSSList.bssid, 6);
-				s[i].sa_family = ARPHRD_ETHER;
-				if (local->rssi)
-					qual[i].level = 0x100 - local->rssi[BSSList.rssi].rssidBm;
-				else
-					qual[i].level = (BSSList.rssi + 321) / 2;
-				qual[i].qual = qual[i].noise = 0;
-				qual[i].updated = 2;
-				if (BSSList.index == 0xffff) break;
-			}
-			if (!i) {
-				for (i = 0;
-				     i < min(IW_MAX_AP, 4) &&
-					     (status_rid.bssid[i][0]
-					      & status_rid.bssid[i][1]
-					      & status_rid.bssid[i][2]
-					      & status_rid.bssid[i][3]
-					      & status_rid.bssid[i][4]
-					      & status_rid.bssid[i][5])!=-1 &&
-					     (status_rid.bssid[i][0]
-					      | status_rid.bssid[i][1]
-					      | status_rid.bssid[i][2]
-					      | status_rid.bssid[i][3]
-					      | status_rid.bssid[i][4]
-					      | status_rid.bssid[i][5]);
-				     i++) {
-					memcpy(s[i].sa_data,
-					       status_rid.bssid[i], 6);
-					s[i].sa_family = ARPHRD_ETHER;
-				}
-			} else {
-				wrq->u.data.flags = 1; /* Should be define'd */
-				if (copy_to_user(wrq->u.data.pointer
-						 + sizeof(struct sockaddr)*i,
-						 &qual,
-						 sizeof(struct iw_quality)*i))
+		{
+			char buffer[IW_MAX_AP * (sizeof(struct sockaddr) +
+						  sizeof(struct iw_quality))];
+			if (wrq->u.data.pointer) {
+				rc = airo_get_aplist(dev, NULL,
+						     &(wrq->u.data), buffer);
+				if (copy_to_user(wrq->u.data.pointer,
+						 buffer,
+						 (wrq->u.data.length *
+						  (sizeof(struct sockaddr) +
+						   sizeof(struct iw_quality)))
+						 ))
 					rc = -EFAULT;
 			}
-			wrq->u.data.length = i;
-			if (copy_to_user(wrq->u.data.pointer, &s,
-					 sizeof(struct sockaddr)*i))
-				rc = -EFAULT;
 		}
 		break;
 
 #ifdef WIRELESS_SPY
-		// Set the spy list
-	case SIOCSIWSPY:
-		if (wrq->u.data.length > IW_MAX_SPY)
-		{
-			rc = -E2BIG;
-			break;
-		}
-		local->spy_number = wrq->u.data.length;
-		if (local->spy_number > 0)
+	case SIOCSIWSPY:	// Set the spy list
 		{
 			struct sockaddr address[IW_MAX_SPY];
-			int i;
-
-			if (copy_from_user(address, wrq->u.data.pointer,
-					   sizeof(struct sockaddr) * local->spy_number)) {
+			/* Check the number of addresses */
+			if (wrq->u.data.length > IW_MAX_SPY) {
+				rc = -E2BIG;
+				break;
+			}
+			/* Get the data in the driver */
+			if (wrq->u.data.pointer) {
+				if (copy_from_user((char *) address,
+						   wrq->u.data.pointer,
+						   sizeof(struct sockaddr) *
+						   wrq->u.data.length)) {
 				rc = -EFAULT;
 				break;
+				}
+			} else if (wrq->u.data.length != 0) {
+				rc = -EINVAL;
+				break;
 			}
-			for (i=0; i<local->spy_number; i++)
-				memcpy(local->spy_address[i], address[i].sa_data, 6);
-			memset(local->spy_stat, 0, sizeof(struct iw_quality) * IW_MAX_SPY);
+			rc=airo_set_spy(dev, NULL, &(wrq->u.data),
+					(char *) address);
 		}
 		break;
 
-		// Get the spy list
-	case SIOCGIWSPY:
-		wrq->u.data.length = local->spy_number;
-		if ((local->spy_number > 0) && (wrq->u.data.pointer))
+	case SIOCGIWSPY:	// Get the spy list
 		{
-			struct sockaddr address[IW_MAX_SPY];
-			int i;
-			rc = verify_area(VERIFY_WRITE, wrq->u.data.pointer, (sizeof(struct iw_quality)+sizeof(struct sockaddr)) * IW_MAX_SPY);
-			if (rc)
-				break;
-			for (i=0; i<local->spy_number; i++)
-			{
-				memcpy(address[i].sa_data, local->spy_address[i], 6);
-				address[i].sa_family = AF_UNIX;
-			}
-			if (copy_to_user(wrq->u.data.pointer, address, sizeof(struct sockaddr) * local->spy_number)) {
-				rc = -EFAULT;
-				break;
-			}
-			if (copy_to_user(wrq->u.data.pointer + (sizeof(struct sockaddr)*local->spy_number), local->spy_stat, sizeof(struct iw_quality) * local->spy_number)) {
-				rc = -EFAULT;
-				break;
+			char buffer[IW_MAX_SPY * (sizeof(struct sockaddr) +
+						  sizeof(struct iw_quality))];
+			if (wrq->u.data.pointer) {
+				rc = airo_get_spy(dev, NULL,
+						  &(wrq->u.data), buffer);
+				if (copy_to_user(wrq->u.data.pointer,
+						 buffer,
+						 (wrq->u.data.length *
+						  (sizeof(struct sockaddr) +
+						   sizeof(struct iw_quality)))
+						 ))
+					rc = -EFAULT;
 			}
-			for (i=0; i<local->spy_number; i++)
-				local->spy_stat[i].updated = 0;
 		}
 		break;
 #endif /* WIRELESS_SPY */
 
 #ifdef CISCO_EXT
 	case SIOCGIWPRIV:
-		if(wrq->u.data.pointer)
-		{
-			struct iw_priv_args   priv[] =
-			{ /* cmd, set_args, get_args, name */
-				{ AIROIOCTL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl), IW_PRIV_TYPE_BYTE | 2047, "airoioctl" },
-				{ AIROIDIFC, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl), IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" },
-			};
-
+		if(wrq->u.data.pointer) {
 			/* Set the number of ioctl available */
-			wrq->u.data.length = 2;
+			wrq->u.data.length = sizeof(airo_private_args) / sizeof( airo_private_args[0]);
 
 			/* Copy structure to the user buffer */
-			if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
-					sizeof(priv)))
+			if(copy_to_user(wrq->u.data.pointer,
+					(u_char *) airo_private_args,
+					sizeof(airo_private_args)))
 				rc = -EFAULT;
 		}
 		break;
 #endif /* CISCO_EXT */
-#endif /* WIRELESS_EXT */
+#endif /* WIRELESS_EXT < 13 */
 
 #ifdef CISCO_EXT
 	case AIROIDIFC:
@@ -4210,7 +5820,7 @@
 
 		/* Seperate R/W functions bracket legality here
 		 */
-		if ( com.command <= AIROGSTATSD32 )
+		if ( com.command <= AIROGMICSTATS )
 			rc = readrids(dev,&com);
 		else if ( com.command >= AIROPCAP && com.command <= AIROPLEAPUSR )
 			rc = writerids(dev,&com);
@@ -4227,31 +5837,16 @@
 		rc = -EOPNOTSUPP;
 	}
 
-#ifdef WIRELESS_EXT
+#if defined(WIRELESS_EXT) && WIRELESS_EXT < 13
+	/* WE 13 and higher will use airo_config_commit */
 	/* Some of the "SET" function may have modified some of the
 	 * parameters. It's now time to commit them in the card */
-	if(local->need_commit) {
-		/* A classical optimisation here is to not commit any change
-		 * if the card is not "opened". This is what we do in
-		 * wvlan_cs (see for details).
-		 * For that, we would need to have the config RID saved in
-		 * the airo_info struct and make sure to not re-read it if
-		 * local->need_commit != 0. Then, you need to patch "open"
-		 * to do the final commit of all parameters...
-		 * Jean II */
-		Resp rsp;
-
-		disable_MAC(local);
-		local->config = config;	/* ???? config is local !!! */
-		checkThrottle(&config);
-		writeConfigRid(local, &config);
-		enable_MAC(local, &rsp);
-
-		local->need_commit = 0;
-	}
-#endif /* WIRELESS_EXT */
+	airo_config_commit(dev, NULL, NULL, NULL);
+	if (rc == -EINPROGRESS)
+		return 0;
+#endif /* WIRELESS_EXT < 13 */
 
-	return(rc);
+	return rc;
 }
 
 #ifdef WIRELESS_EXT
@@ -4267,7 +5862,7 @@
  */
 struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
 {
-	struct airo_info *local = (struct airo_info*) dev->priv;
+	struct airo_info *local = dev->priv;
 	StatusRid status_rid;
 	StatsRid stats_rid;
 	u32 *vals = stats_rid.vals;
@@ -4292,15 +5887,11 @@
 	 * specific problems */
 	local->wstats.discard.nwid = vals[56] + vals[57] + vals[58];/* SSID Mismatch */
 	local->wstats.discard.code = vals[6];/* RxWepErr */
-#if WIRELESS_EXT > 11
 	local->wstats.discard.fragment = vals[30];
 	local->wstats.discard.retries = vals[10];
 	local->wstats.discard.misc = vals[1] + vals[32];
 	local->wstats.miss.beacon = vals[34];
-#else /* WIRELESS_EXT > 11 */
-	local->wstats.discard.misc = vals[1] + vals[30] + vals[32];
-#endif /* WIRELESS_EXT > 11 */
-	return (&local->wstats);
+	return &local->wstats;
 }
 #endif /* WIRELESS_EXT */
 
@@ -4314,11 +5905,16 @@
 static int readrids(struct net_device *dev, aironet_ioctl *comp) {
 	unsigned short ridcode;
 	unsigned char iobuf[2048];
+	struct airo_info *ai = dev->priv;
+
+	if (ai->flags & FLAG_FLASHING)
+		return -EIO;
 
 	switch(comp->command)
 	{
 	case AIROGCAP:      ridcode = RID_CAPABILITIES; break;
-	case AIROGCFG:      ridcode = RID_CONFIG;       break;
+	case AIROGCFG: writeConfigRid (ai);
+			    ridcode = RID_CONFIG;       break;
 	case AIROGSLIST:    ridcode = RID_SSID;         break;
 	case AIROGVLIST:    ridcode = RID_APLIST;       break;
 	case AIROGDRVNAM:   ridcode = RID_DRVNAME;      break;
@@ -4336,12 +5932,17 @@
 	case AIROGSTAT:     ridcode = RID_STATUS;       break;
 	case AIROGSTATSD32: ridcode = RID_STATSDELTA;   break;
 	case AIROGSTATSC32: ridcode = RID_STATS;        break;
+	case AIROGMICSTATS:
+		if (copy_to_user(comp->data, &ai->micstats,
+				 min((int)comp->len,(int)sizeof(ai->micstats))))
+			return -EFAULT;
+		return 0;
 	default:
 		return -EINVAL;
 		break;
 	}
 
-	PC4500_readrid((struct airo_info *)dev->priv,ridcode,iobuf,sizeof(iobuf));
+	PC4500_readrid(ai,ridcode,iobuf,sizeof(iobuf));
 	/* get the count of bytes in the rid  docs say 1st 2 bytes is it.
 	 * then return it to the user
 	 * 9/22/2000 Honor user given length
@@ -4358,7 +5959,8 @@
  */
 
 static int writerids(struct net_device *dev, aironet_ioctl *comp) {
-	int  ridcode;
+	struct airo_info *ai = dev->priv;
+	int  ridcode, enabled;
 	Resp      rsp;
 	static int (* writer)(struct airo_info *, u16 rid, const void *, int);
 	unsigned char iobuf[2048];
@@ -4367,6 +5969,9 @@
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
+	if (ai->flags & FLAG_FLASHING)
+		return -EIO;
+
 	ridcode = 0;
 	writer = do_writerid;
 
@@ -4375,7 +5980,8 @@
 	case AIROPSIDS:     ridcode = RID_SSID;         break;
 	case AIROPCAP:      ridcode = RID_CAPABILITIES; break;
 	case AIROPAPLIST:   ridcode = RID_APLIST;       break;
-	case AIROPCFG:      ridcode = RID_CONFIG;       break;
+	case AIROPCFG: ai->config.len = 0;
+			    ridcode = RID_CONFIG;       break;
 	case AIROPWEPKEYNV: ridcode = RID_WEP_PERM;     break;
 	case AIROPLEAPUSR:  ridcode = RID_LEAPUSERNAME; break;
 	case AIROPLEAPPWD:  ridcode = RID_LEAPPASSWORD; break;
@@ -4386,7 +5992,7 @@
 		 * same with MAC off
 		 */
 	case AIROPMACON:
-		if (enable_MAC(dev->priv, &rsp) != 0)
+		if (enable_MAC(ai, &rsp) != 0)
 			return -EIO;
 		return 0;
 
@@ -4395,7 +6001,7 @@
 		 * as disable_MAC. it's probably so short the compiler does not gen one.
 		 */
 	case AIROPMACOFF:
-		disable_MAC(dev->priv);
+		disable_MAC(ai);
 		return 0;
 
 		/* This command merely clears the counts does not actually store any data
@@ -4403,9 +6009,11 @@
 		 * writerid routines.
 		 */
 	case AIROPSTCLR:
-		ridcode = RID_STATSDELTACLEAR;
+		PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,sizeof(iobuf));
 
-		PC4500_readrid(dev->priv,ridcode,iobuf,sizeof(iobuf));
+		enabled = ai->micstats.enabled;
+		memset(&ai->micstats,0,sizeof(ai->micstats));
+		ai->micstats.enabled = enabled;
 
 		if (copy_to_user(comp->data, iobuf,
 				 min((int)comp->len, (int)sizeof(iobuf))))
@@ -4420,7 +6028,20 @@
 
 	if (copy_from_user(iobuf,comp->data,comp->len))
 		return -EFAULT;
-	if((*writer)((struct airo_info *)dev->priv, ridcode, iobuf,comp->len))
+
+	if (comp->command == AIROPCFG) {
+		ConfigRid *cfg = (ConfigRid *)iobuf;
+
+		if (ai->flags & FLAG_MIC_CAPABLE)
+			cfg->opmode |= MODE_MIC;
+
+		if ((cfg->opmode & 0xFF) == MODE_STA_IBSS)
+			ai->flags |= FLAG_ADHOC;
+		else
+			ai->flags &= ~FLAG_ADHOC;
+	}
+
+	if((*writer)(ai, ridcode, iobuf,comp->len))
 		return -EIO;
 	return 0;
 }
@@ -4525,14 +6146,23 @@
  */
 
 int setflashmode (struct airo_info *ai) {
+	ai->flags |= FLAG_FLASHING;
+
 	OUT4500(ai, SWS0, FLASH_COMMAND);
 	OUT4500(ai, SWS1, FLASH_COMMAND);
-	OUT4500(ai, SWS0, FLASH_COMMAND);
-	OUT4500(ai, COMMAND,0x10);
+	if (probe) {
+		OUT4500(ai, SWS0, FLASH_COMMAND);
+		OUT4500(ai, COMMAND,0x10);
+	} else {
+		OUT4500(ai, SWS2, FLASH_COMMAND);
+		OUT4500(ai, SWS3, FLASH_COMMAND);
+		OUT4500(ai, COMMAND,0);
+	}
 	set_current_state (TASK_UNINTERRUPTIBLE);
 	schedule_timeout (HZ/2); /* 500ms delay */
 
 	if(!waitbusy(ai)) {
+		ai->flags &= ~FLAG_FLASHING;
 		printk(KERN_INFO "Waitbusy hang after setflash mode\n");
 		return -EIO;
 	}
@@ -4638,10 +6268,11 @@
 
 	set_current_state (TASK_UNINTERRUPTIBLE);
 	schedule_timeout (HZ);          /* Added 12/7/00 */
-	status = setup_card(ai, dev->dev_addr,&((struct airo_info*)dev->priv)->config);
+	ai->flags &= ~FLAG_FLASHING;
+	status = setup_card(ai, dev->dev_addr);
 
 	for( i = 0; i < MAX_FIDS; i++ ) {
-		ai->fids[i] = transmit_allocate( ai, 2312 );
+		ai->fids[i] = transmit_allocate( ai, 2312, i >= MAX_FIDS / 2 );
 	}
 
 	set_current_state (TASK_UNINTERRUPTIBLE);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wireless/airo_cs.c linux-2.4.20/drivers/net/wireless/airo_cs.c
--- linux-2.4.19/drivers/net/wireless/airo_cs.c	2002-02-25 19:38:03.000000000 +0000
+++ linux-2.4.20/drivers/net/wireless/airo_cs.c	2002-10-29 11:18:35.000000000 +0000
@@ -15,7 +15,7 @@
 
     In addition this module was derived from dummy_cs.
     The initial developer of dummy_cs is David A. Hinds
-    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.    
     
 ======================================================================*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/wireless/orinoco_plx.c linux-2.4.20/drivers/net/wireless/orinoco_plx.c
--- linux-2.4.19/drivers/net/wireless/orinoco_plx.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/wireless/orinoco_plx.c	2002-10-29 11:18:50.000000000 +0000
@@ -363,6 +363,7 @@
 
 
 static struct pci_device_id orinoco_plx_pci_id_table[] __devinitdata = {
+	{0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,},	/* 3ComAirConnect */
 	{0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,},	/* Siemens SpeedStream SS1023 */
 	{0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,},	/* Netgear MA301 */
 	{0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,},	/* Correga  - does this work? */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/yellowfin.c linux-2.4.20/drivers/net/yellowfin.c
--- linux-2.4.19/drivers/net/yellowfin.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/yellowfin.c	2002-10-29 11:18:37.000000000 +0000
@@ -1020,18 +1020,12 @@
 					if (tx_errs & 0x0800) yp->stats.tx_carrier_errors++;
 					if (tx_errs & 0x2000) yp->stats.tx_window_errors++;
 					if (tx_errs & 0x8000) yp->stats.tx_fifo_errors++;
-#ifdef ETHER_STATS
-					if (tx_errs & 0x1000) yp->stats.collisions16++;
-#endif
 				} else {
 #ifndef final_version
 					if (yellowfin_debug > 4)
 						printk(KERN_DEBUG "%s: Normal transmit, Tx status %4.4x.\n",
 							   dev->name, tx_errs);
 #endif
-#ifdef ETHER_STATS
-					if (tx_errs & 0x0400) yp->stats.tx_deferred++;
-#endif
 					yp->stats.tx_bytes += skb->len;
 					yp->stats.collisions += tx_errs & 15;
 					yp->stats.tx_packets++;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/zlib.c linux-2.4.20/drivers/net/zlib.c
--- linux-2.4.19/drivers/net/zlib.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/net/zlib.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,5376 +0,0 @@
-/*
- * This file is derived from various .h and .c files from the zlib-1.0.4
- * distribution by Jean-loup Gailly and Mark Adler, with some additions
- * by Paul Mackerras to aid in implementing Deflate compression and
- * decompression for PPP packets.  See zlib.h for conditions of
- * distribution and use.
- *
- * Changes that have been made include:
- * - added Z_PACKET_FLUSH (see zlib.h for details)
- * - added inflateIncomp and deflateOutputPending
- * - allow strm->next_out to be NULL, meaning discard the output
- *
- * $Id: zlib.c,v 1.3 1997/12/23 10:47:42 paulus Exp $
- */
-
-/* 
- *  ==FILEVERSION 20020318==
- *
- * This marker is used by the Linux installation script to determine
- * whether an up-to-date version of this file is already installed.
- */
-
-#define NO_DUMMY_DECL
-#define NO_ZCFUNCS
-#define MY_ZCALLOC
-
-#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL))
-#define inflate	inflate_ppp	/* FreeBSD already has an inflate :-( */
-#endif
-
-
-/* +++ zutil.h */
-/* zutil.h -- internal interface and configuration of the compression library
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-/* From: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp $ */
-
-#ifndef _Z_UTIL_H
-#define _Z_UTIL_H
-
-#include "zlib.h"
-
-#if defined(KERNEL) || defined(_KERNEL)
-/* Assume this is a *BSD or SVR4 kernel */
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/systm.h>
-#  define HAVE_MEMCPY
-#  define memcpy(d, s, n)	bcopy((s), (d), (n))
-#  define memset(d, v, n)	bzero((d), (n))
-#  define memcmp		bcmp
-
-#else
-#if defined(__KERNEL__)
-/* Assume this is a Linux kernel */
-#include <linux/string.h>
-#define HAVE_MEMCPY
-
-#else /* not kernel */
-
-#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS)
-#   include <stddef.h>
-#   include <errno.h>
-#else
-    extern int errno;
-#endif
-#ifdef STDC
-#  include <string.h>
-#  include <stdlib.h>
-#endif
-#endif /* __KERNEL__ */
-#endif /* _KERNEL || KERNEL */
-
-#ifndef local
-#  define local static
-#endif
-/* compile with -Dlocal if your debugger can't find static symbols */
-
-typedef unsigned char  uch;
-typedef uch FAR uchf;
-typedef unsigned short ush;
-typedef ush FAR ushf;
-typedef unsigned long  ulg;
-
-extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
-/* (size given to avoid silly warnings with Visual C++) */
-
-#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
-
-#define ERR_RETURN(strm,err) \
-  return (strm->msg = (char*)ERR_MSG(err), (err))
-/* To be used only when the state is known to be valid */
-
-        /* common constants */
-
-#ifndef DEF_WBITS
-#  define DEF_WBITS MAX_WBITS
-#endif
-/* default windowBits for decompression. MAX_WBITS is for compression only */
-
-#if MAX_MEM_LEVEL >= 8
-#  define DEF_MEM_LEVEL 8
-#else
-#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
-#endif
-/* default memLevel */
-
-#define STORED_BLOCK 0
-#define STATIC_TREES 1
-#define DYN_TREES    2
-/* The three kinds of block type */
-
-#define MIN_MATCH  3
-#define MAX_MATCH  258
-/* The minimum and maximum match lengths */
-
-#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
-
-        /* target dependencies */
-
-#ifdef MSDOS
-#  define OS_CODE  0x00
-#  ifdef __TURBOC__
-#    include <alloc.h>
-#  else /* MSC or DJGPP */
-#    include <malloc.h>
-#  endif
-#endif
-
-#ifdef OS2
-#  define OS_CODE  0x06
-#endif
-
-#ifdef WIN32 /* Window 95 & Windows NT */
-#  define OS_CODE  0x0b
-#endif
-
-#if defined(VAXC) || defined(VMS)
-#  define OS_CODE  0x02
-#  define FOPEN(name, mode) \
-     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
-#endif
-
-#ifdef AMIGA
-#  define OS_CODE  0x01
-#endif
-
-#if defined(ATARI) || defined(atarist)
-#  define OS_CODE  0x05
-#endif
-
-#ifdef MACOS
-#  define OS_CODE  0x07
-#endif
-
-#ifdef __50SERIES /* Prime/PRIMOS */
-#  define OS_CODE  0x0F
-#endif
-
-#ifdef TOPS20
-#  define OS_CODE  0x0a
-#endif
-
-#if defined(_BEOS_) || defined(RISCOS)
-#  define fdopen(fd,mode) NULL /* No fdopen() */
-#endif
-
-        /* Common defaults */
-
-#ifndef OS_CODE
-#  define OS_CODE  0x03  /* assume Unix */
-#endif
-
-#ifndef FOPEN
-#  define FOPEN(name, mode) fopen((name), (mode))
-#endif
-
-         /* functions */
-
-#ifdef HAVE_STRERROR
-   extern char *strerror OF((int));
-#  define zstrerror(errnum) strerror(errnum)
-#else
-#  define zstrerror(errnum) ""
-#endif
-
-#if defined(pyr)
-#  define NO_MEMCPY
-#endif
-#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER)
- /* Use our own functions for small and medium model with MSC <= 5.0.
-  * You may have to use the same strategy for Borland C (untested).
-  */
-#  define NO_MEMCPY
-#endif
-#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
-#  define HAVE_MEMCPY
-#endif
-#ifdef HAVE_MEMCPY
-#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
-#    define zmemcpy _fmemcpy
-#    define zmemcmp _fmemcmp
-#    define zmemzero(dest, len) _fmemset(dest, 0, len)
-#  else
-#    define zmemcpy memcpy
-#    define zmemcmp memcmp
-#    define zmemzero(dest, len) memset(dest, 0, len)
-#  endif
-#else
-   extern void zmemcpy  OF((Bytef* dest, Bytef* source, uInt len));
-   extern int  zmemcmp  OF((Bytef* s1,   Bytef* s2, uInt len));
-   extern void zmemzero OF((Bytef* dest, uInt len));
-#endif
-
-/* Diagnostic functions */
-#ifdef DEBUG_ZLIB
-#  include <stdio.h>
-#  ifndef verbose
-#    define verbose 0
-#  endif
-   extern void z_error    OF((char *m));
-#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
-#  define Trace(x) fprintf x
-#  define Tracev(x) {if (verbose) fprintf x ;}
-#  define Tracevv(x) {if (verbose>1) fprintf x ;}
-#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
-#else
-#  define Assert(cond,msg)
-#  define Trace(x)
-#  define Tracev(x)
-#  define Tracevv(x)
-#  define Tracec(c,x)
-#  define Tracecv(c,x)
-#endif
-
-
-typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len));
-
-voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
-void   zcfree  OF((voidpf opaque, voidpf ptr));
-
-#define ZALLOC(strm, items, size) \
-           (*((strm)->zalloc))((strm)->opaque, (items), (size))
-#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
-#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
-
-#endif /* _Z_UTIL_H */
-/* --- zutil.h */
-
-/* +++ deflate.h */
-/* deflate.h -- internal compression state
- * Copyright (C) 1995-1996 Jean-loup Gailly
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-/* From: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */
-
-#ifndef _DEFLATE_H
-#define _DEFLATE_H
-
-/* #include "zutil.h" */
-
-/* ===========================================================================
- * Internal compression state.
- */
-
-#define LENGTH_CODES 29
-/* number of length codes, not counting the special END_BLOCK code */
-
-#define LITERALS  256
-/* number of literal bytes 0..255 */
-
-#define L_CODES (LITERALS+1+LENGTH_CODES)
-/* number of Literal or Length codes, including the END_BLOCK code */
-
-#define D_CODES   30
-/* number of distance codes */
-
-#define BL_CODES  19
-/* number of codes used to transfer the bit lengths */
-
-#define HEAP_SIZE (2*L_CODES+1)
-/* maximum heap size */
-
-#define MAX_BITS 15
-/* All codes must not exceed MAX_BITS bits */
-
-#define INIT_STATE    42
-#define BUSY_STATE   113
-#define FINISH_STATE 666
-/* Stream status */
-
-
-/* Data structure describing a single value and its code string. */
-typedef struct ct_data_s {
-    union {
-        ush  freq;       /* frequency count */
-        ush  code;       /* bit string */
-    } fc;
-    union {
-        ush  dad;        /* father node in Huffman tree */
-        ush  len;        /* length of bit string */
-    } dl;
-} FAR ct_data;
-
-#define Freq fc.freq
-#define Code fc.code
-#define Dad  dl.dad
-#define Len  dl.len
-
-typedef struct static_tree_desc_s  static_tree_desc;
-
-typedef struct tree_desc_s {
-    ct_data *dyn_tree;           /* the dynamic tree */
-    int     max_code;            /* largest code with non zero frequency */
-    static_tree_desc *stat_desc; /* the corresponding static tree */
-} FAR tree_desc;
-
-typedef ush Pos;
-typedef Pos FAR Posf;
-typedef unsigned IPos;
-
-/* A Pos is an index in the character window. We use short instead of int to
- * save space in the various tables. IPos is used only for parameter passing.
- */
-
-typedef struct deflate_state {
-    z_streamp strm;      /* pointer back to this zlib stream */
-    int   status;        /* as the name implies */
-    Bytef *pending_buf;  /* output still pending */
-    ulg   pending_buf_size; /* size of pending_buf */
-    Bytef *pending_out;  /* next pending byte to output to the stream */
-    int   pending;       /* nb of bytes in the pending buffer */
-    int   noheader;      /* suppress zlib header and adler32 */
-    Byte  data_type;     /* UNKNOWN, BINARY or ASCII */
-    Byte  method;        /* STORED (for zip only) or DEFLATED */
-    int   last_flush;    /* value of flush param for previous deflate call */
-
-                /* used by deflate.c: */
-
-    uInt  w_size;        /* LZ77 window size (32K by default) */
-    uInt  w_bits;        /* log2(w_size)  (8..16) */
-    uInt  w_mask;        /* w_size - 1 */
-
-    Bytef *window;
-    /* Sliding window. Input bytes are read into the second half of the window,
-     * and move to the first half later to keep a dictionary of at least wSize
-     * bytes. With this organization, matches are limited to a distance of
-     * wSize-MAX_MATCH bytes, but this ensures that IO is always
-     * performed with a length multiple of the block size. Also, it limits
-     * the window size to 64K, which is quite useful on MSDOS.
-     * To do: use the user input buffer as sliding window.
-     */
-
-    ulg window_size;
-    /* Actual size of window: 2*wSize, except when the user input buffer
-     * is directly used as sliding window.
-     */
-
-    Posf *prev;
-    /* Link to older string with same hash index. To limit the size of this
-     * array to 64K, this link is maintained only for the last 32K strings.
-     * An index in this array is thus a window index modulo 32K.
-     */
-
-    Posf *head; /* Heads of the hash chains or NIL. */
-
-    uInt  ins_h;          /* hash index of string to be inserted */
-    uInt  hash_size;      /* number of elements in hash table */
-    uInt  hash_bits;      /* log2(hash_size) */
-    uInt  hash_mask;      /* hash_size-1 */
-
-    uInt  hash_shift;
-    /* Number of bits by which ins_h must be shifted at each input
-     * step. It must be such that after MIN_MATCH steps, the oldest
-     * byte no longer takes part in the hash key, that is:
-     *   hash_shift * MIN_MATCH >= hash_bits
-     */
-
-    long block_start;
-    /* Window position at the beginning of the current output block. Gets
-     * negative when the window is moved backwards.
-     */
-
-    uInt match_length;           /* length of best match */
-    IPos prev_match;             /* previous match */
-    int match_available;         /* set if previous match exists */
-    uInt strstart;               /* start of string to insert */
-    uInt match_start;            /* start of matching string */
-    uInt lookahead;              /* number of valid bytes ahead in window */
-
-    uInt prev_length;
-    /* Length of the best match at previous step. Matches not greater than this
-     * are discarded. This is used in the lazy match evaluation.
-     */
-
-    uInt max_chain_length;
-    /* To speed up deflation, hash chains are never searched beyond this
-     * length.  A higher limit improves compression ratio but degrades the
-     * speed.
-     */
-
-    uInt max_lazy_match;
-    /* Attempt to find a better match only when the current match is strictly
-     * smaller than this value. This mechanism is used only for compression
-     * levels >= 4.
-     */
-#   define max_insert_length  max_lazy_match
-    /* Insert new strings in the hash table only if the match length is not
-     * greater than this length. This saves time but degrades compression.
-     * max_insert_length is used only for compression levels <= 3.
-     */
-
-    int level;    /* compression level (1..9) */
-    int strategy; /* favor or force Huffman coding*/
-
-    uInt good_match;
-    /* Use a faster search when the previous match is longer than this */
-
-    int nice_match; /* Stop searching when current match exceeds this */
-
-                /* used by trees.c: */
-    /* Didn't use ct_data typedef below to suppress compiler warning */
-    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
-    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
-    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
-
-    struct tree_desc_s l_desc;               /* desc. for literal tree */
-    struct tree_desc_s d_desc;               /* desc. for distance tree */
-    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
-
-    ush bl_count[MAX_BITS+1];
-    /* number of codes at each bit length for an optimal tree */
-
-    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
-    int heap_len;               /* number of elements in the heap */
-    int heap_max;               /* element of largest frequency */
-    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
-     * The same heap array is used to build all trees.
-     */
-
-    uch depth[2*L_CODES+1];
-    /* Depth of each subtree used as tie breaker for trees of equal frequency
-     */
-
-    uchf *l_buf;          /* buffer for literals or lengths */
-
-    uInt  lit_bufsize;
-    /* Size of match buffer for literals/lengths.  There are 4 reasons for
-     * limiting lit_bufsize to 64K:
-     *   - frequencies can be kept in 16 bit counters
-     *   - if compression is not successful for the first block, all input
-     *     data is still in the window so we can still emit a stored block even
-     *     when input comes from standard input.  (This can also be done for
-     *     all blocks if lit_bufsize is not greater than 32K.)
-     *   - if compression is not successful for a file smaller than 64K, we can
-     *     even emit a stored file instead of a stored block (saving 5 bytes).
-     *     This is applicable only for zip (not gzip or zlib).
-     *   - creating new Huffman trees less frequently may not provide fast
-     *     adaptation to changes in the input data statistics. (Take for
-     *     example a binary file with poorly compressible code followed by
-     *     a highly compressible string table.) Smaller buffer sizes give
-     *     fast adaptation but have of course the overhead of transmitting
-     *     trees more frequently.
-     *   - I can't count above 4
-     */
-
-    uInt last_lit;      /* running index in l_buf */
-
-    ushf *d_buf;
-    /* Buffer for distances. To simplify the code, d_buf and l_buf have
-     * the same number of elements. To use different lengths, an extra flag
-     * array would be necessary.
-     */
-
-    ulg opt_len;        /* bit length of current block with optimal trees */
-    ulg static_len;     /* bit length of current block with static trees */
-    ulg compressed_len; /* total bit length of compressed file */
-    uInt matches;       /* number of string matches in current block */
-    int last_eob_len;   /* bit length of EOB code for last block */
-
-#ifdef DEBUG_ZLIB
-    ulg bits_sent;      /* bit length of the compressed data */
-#endif
-
-    ush bi_buf;
-    /* Output buffer. bits are inserted starting at the bottom (least
-     * significant bits).
-     */
-    int bi_valid;
-    /* Number of valid bits in bi_buf.  All bits above the last valid bit
-     * are always zero.
-     */
-
-} FAR deflate_state;
-
-/* Output a byte on the stream.
- * IN assertion: there is enough room in pending_buf.
- */
-#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
-
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
-/* In order to simplify the code, particularly on 16 bit machines, match
- * distances are limited to MAX_DIST instead of WSIZE.
- */
-
-        /* in trees.c */
-void _tr_init         OF((deflate_state *s));
-int  _tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
-ulg  _tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
-			  int eof));
-void _tr_align        OF((deflate_state *s));
-void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
-                          int eof));
-void _tr_stored_type_only OF((deflate_state *));
-
-#endif
-/* --- deflate.h */
-
-/* +++ deflate.c */
-/* deflate.c -- compress data using the deflation algorithm
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/*
- *  ALGORITHM
- *
- *      The "deflation" process depends on being able to identify portions
- *      of the input text which are identical to earlier input (within a
- *      sliding window trailing behind the input currently being processed).
- *
- *      The most straightforward technique turns out to be the fastest for
- *      most input files: try all possible matches and select the longest.
- *      The key feature of this algorithm is that insertions into the string
- *      dictionary are very simple and thus fast, and deletions are avoided
- *      completely. Insertions are performed at each input character, whereas
- *      string matches are performed only when the previous match ends. So it
- *      is preferable to spend more time in matches to allow very fast string
- *      insertions and avoid deletions. The matching algorithm for small
- *      strings is inspired from that of Rabin & Karp. A brute force approach
- *      is used to find longer strings when a small match has been found.
- *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
- *      (by Leonid Broukhis).
- *         A previous version of this file used a more sophisticated algorithm
- *      (by Fiala and Greene) which is guaranteed to run in linear amortized
- *      time, but has a larger average cost, uses more memory and is patented.
- *      However the F&G algorithm may be faster for some highly redundant
- *      files if the parameter max_chain_length (described below) is too large.
- *
- *  ACKNOWLEDGEMENTS
- *
- *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
- *      I found it in 'freeze' written by Leonid Broukhis.
- *      Thanks to many people for bug reports and testing.
- *
- *  REFERENCES
- *
- *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
- *      Available in ftp://ds.internic.net/rfc/rfc1951.txt
- *
- *      A description of the Rabin and Karp algorithm is given in the book
- *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
- *
- *      Fiala,E.R., and Greene,D.H.
- *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
- *
- */
-
-/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */
-
-/* #include "deflate.h" */
-
-char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly ";
-/*
-  If you use the zlib library in a product, an acknowledgment is welcome
-  in the documentation of your product. If for some reason you cannot
-  include such an acknowledgment, I would appreciate that you keep this
-  copyright string in the executable of your product.
- */
-
-/* ===========================================================================
- *  Function prototypes.
- */
-typedef enum {
-    need_more,      /* block not completed, need more input or more output */
-    block_done,     /* block flush performed */
-    finish_started, /* finish started, need only more output at next deflate */
-    finish_done     /* finish done, accept no more input or output */
-} block_state;
-
-typedef block_state (*compress_func) OF((deflate_state *s, int flush));
-/* Compression function. Returns the block state after the call. */
-
-local void fill_window    OF((deflate_state *s));
-local block_state deflate_stored OF((deflate_state *s, int flush));
-local block_state deflate_fast   OF((deflate_state *s, int flush));
-local block_state deflate_slow   OF((deflate_state *s, int flush));
-local void lm_init        OF((deflate_state *s));
-local void putShortMSB    OF((deflate_state *s, uInt b));
-local void flush_pending  OF((z_streamp strm));
-local int read_buf        OF((z_streamp strm, charf *buf, unsigned size));
-#ifdef ASMV
-      void match_init OF((void)); /* asm code initialization */
-      uInt longest_match  OF((deflate_state *s, IPos cur_match));
-#else
-local uInt longest_match  OF((deflate_state *s, IPos cur_match));
-#endif
-
-#ifdef DEBUG_ZLIB
-local  void check_match OF((deflate_state *s, IPos start, IPos match,
-                            int length));
-#endif
-
-/* ===========================================================================
- * Local data
- */
-
-#define NIL 0
-/* Tail of hash chains */
-
-#ifndef TOO_FAR
-#  define TOO_FAR 4096
-#endif
-/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-/* Values for max_lazy_match, good_match and max_chain_length, depending on
- * the desired pack level (0..9). The values given below have been tuned to
- * exclude worst case performance for pathological files. Better values may be
- * found for specific files.
- */
-typedef struct config_s {
-   ush good_length; /* reduce lazy search above this match length */
-   ush max_lazy;    /* do not perform lazy search above this match length */
-   ush nice_length; /* quit search above this match length */
-   ush max_chain;
-   compress_func func;
-} config;
-
-local config configuration_table[10] = {
-/*      good lazy nice chain */
-/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
-/* 1 */ {4,    4,  8,    4, deflate_fast}, /* maximum speed, no lazy matches */
-/* 2 */ {4,    5, 16,    8, deflate_fast},
-/* 3 */ {4,    6, 32,   32, deflate_fast},
-
-/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
-/* 5 */ {8,   16, 32,   32, deflate_slow},
-/* 6 */ {8,   16, 128, 128, deflate_slow},
-/* 7 */ {8,   32, 128, 256, deflate_slow},
-/* 8 */ {32, 128, 258, 1024, deflate_slow},
-/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
-
-/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
- * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
- * meaning.
- */
-
-#define EQUAL 0
-/* result of memcmp for equal strings */
-
-#ifndef NO_DUMMY_DECL
-struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
-#endif
-
-/* ===========================================================================
- * Update a hash value with the given input byte
- * IN  assertion: all calls to UPDATE_HASH are made with consecutive
- *    input characters, so that a running hash key can be computed from the
- *    previous key instead of complete recalculation each time.
- */
-#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
-
-
-/* ===========================================================================
- * Insert string str in the dictionary and set match_head to the previous head
- * of the hash chain (the most recent string with same hash key). Return
- * the previous length of the hash chain.
- * IN  assertion: all calls to INSERT_STRING are made with consecutive
- *    input characters and the first MIN_MATCH bytes of str are valid
- *    (except for the last MIN_MATCH-1 bytes of the input file).
- */
-#define INSERT_STRING(s, str, match_head) \
-   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
-    s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
-    s->head[s->ins_h] = (Pos)(str))
-
-/* ===========================================================================
- * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
- * prev[] will be initialized on the fly.
- */
-#define CLEAR_HASH(s) \
-    s->head[s->hash_size-1] = NIL; \
-    zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
-
-/* ========================================================================= */
-int deflateInit_(strm, level, version, stream_size)
-    z_streamp strm;
-    int level;
-    const char *version;
-    int stream_size;
-{
-    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
-			 Z_DEFAULT_STRATEGY, version, stream_size);
-    /* To do: ignore strm->next_in if we use it as window */
-}
-
-/* ========================================================================= */
-int deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
-		  version, stream_size)
-    z_streamp strm;
-    int  level;
-    int  method;
-    int  windowBits;
-    int  memLevel;
-    int  strategy;
-    const char *version;
-    int stream_size;
-{
-    deflate_state *s;
-    int noheader = 0;
-    static char* my_version = ZLIB_VERSION;
-
-    ushf *overlay;
-    /* We overlay pending_buf and d_buf+l_buf. This works since the average
-     * output size for (length,distance) codes is <= 24 bits.
-     */
-
-    if (version == Z_NULL || version[0] != my_version[0] ||
-        stream_size != sizeof(z_stream)) {
-	return Z_VERSION_ERROR;
-    }
-    if (strm == Z_NULL) return Z_STREAM_ERROR;
-
-    strm->msg = Z_NULL;
-#ifndef NO_ZCFUNCS
-    if (strm->zalloc == Z_NULL) {
-	strm->zalloc = zcalloc;
-	strm->opaque = (voidpf)0;
-    }
-    if (strm->zfree == Z_NULL) strm->zfree = zcfree;
-#endif
-
-    if (level == Z_DEFAULT_COMPRESSION) level = 6;
-
-    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
-        noheader = 1;
-        windowBits = -windowBits;
-    }
-    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
-        windowBits < 9 || windowBits > 15 || level < 0 || level > 9 ||
-	strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
-        return Z_STREAM_ERROR;
-    }
-    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
-    if (s == Z_NULL) return Z_MEM_ERROR;
-    strm->state = (struct internal_state FAR *)s;
-    s->strm = strm;
-
-    s->noheader = noheader;
-    s->w_bits = windowBits;
-    s->w_size = 1 << s->w_bits;
-    s->w_mask = s->w_size - 1;
-
-    s->hash_bits = memLevel + 7;
-    s->hash_size = 1 << s->hash_bits;
-    s->hash_mask = s->hash_size - 1;
-    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
-
-    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
-    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
-    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
-
-    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
-
-    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
-    s->pending_buf = (uchf *) overlay;
-    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
-
-    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
-        s->pending_buf == Z_NULL) {
-        strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
-        deflateEnd (strm);
-        return Z_MEM_ERROR;
-    }
-    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
-    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
-
-    s->level = level;
-    s->strategy = strategy;
-    s->method = (Byte)method;
-
-    return deflateReset(strm);
-}
-
-/* ========================================================================= */
-int deflateSetDictionary (strm, dictionary, dictLength)
-    z_streamp strm;
-    const Bytef *dictionary;
-    uInt  dictLength;
-{
-    deflate_state *s;
-    uInt length = dictLength;
-    uInt n;
-    IPos hash_head = 0;
-
-    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
-	return Z_STREAM_ERROR;
-
-    s = (deflate_state *) strm->state;
-    if (s->status != INIT_STATE) return Z_STREAM_ERROR;
-
-    strm->adler = adler32(strm->adler, dictionary, dictLength);
-
-    if (length < MIN_MATCH) return Z_OK;
-    if (length > MAX_DIST(s)) {
-	length = MAX_DIST(s);
-#ifndef USE_DICT_HEAD
-	dictionary += dictLength - length; /* use the tail of the dictionary */
-#endif
-    }
-    zmemcpy((charf *)s->window, dictionary, length);
-    s->strstart = length;
-    s->block_start = (long)length;
-
-    /* Insert all strings in the hash table (except for the last two bytes).
-     * s->lookahead stays null, so s->ins_h will be recomputed at the next
-     * call of fill_window.
-     */
-    s->ins_h = s->window[0];
-    UPDATE_HASH(s, s->ins_h, s->window[1]);
-    for (n = 0; n <= length - MIN_MATCH; n++) {
-	INSERT_STRING(s, n, hash_head);
-    }
-    if (hash_head) hash_head = 0;  /* to make compiler happy */
-    return Z_OK;
-}
-
-/* ========================================================================= */
-int deflateReset (strm)
-    z_streamp strm;
-{
-    deflate_state *s;
-    
-    if (strm == Z_NULL || strm->state == Z_NULL ||
-        strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
-
-    strm->total_in = strm->total_out = 0;
-    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
-    strm->data_type = Z_UNKNOWN;
-
-    s = (deflate_state *)strm->state;
-    s->pending = 0;
-    s->pending_out = s->pending_buf;
-
-    if (s->noheader < 0) {
-        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
-    }
-    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
-    strm->adler = 1;
-    s->last_flush = Z_NO_FLUSH;
-
-    _tr_init(s);
-    lm_init(s);
-
-    return Z_OK;
-}
-
-/* ========================================================================= */
-int deflateParams(strm, level, strategy)
-    z_streamp strm;
-    int level;
-    int strategy;
-{
-    deflate_state *s;
-    compress_func func;
-    int err = Z_OK;
-
-    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
-    s = (deflate_state *) strm->state;
-
-    if (level == Z_DEFAULT_COMPRESSION) {
-	level = 6;
-    }
-    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
-	return Z_STREAM_ERROR;
-    }
-    func = configuration_table[s->level].func;
-
-    if (func != configuration_table[level].func && strm->total_in != 0) {
-	/* Flush the last buffer: */
-	err = deflate(strm, Z_PARTIAL_FLUSH);
-    }
-    if (s->level != level) {
-	s->level = level;
-	s->max_lazy_match   = configuration_table[level].max_lazy;
-	s->good_match       = configuration_table[level].good_length;
-	s->nice_match       = configuration_table[level].nice_length;
-	s->max_chain_length = configuration_table[level].max_chain;
-    }
-    s->strategy = strategy;
-    return err;
-}
-
-/* =========================================================================
- * Put a short in the pending buffer. The 16-bit value is put in MSB order.
- * IN assertion: the stream state is correct and there is enough room in
- * pending_buf.
- */
-local void putShortMSB (s, b)
-    deflate_state *s;
-    uInt b;
-{
-    put_byte(s, (Byte)(b >> 8));
-    put_byte(s, (Byte)(b & 0xff));
-}   
-
-/* =========================================================================
- * Flush as much pending output as possible. All deflate() output goes
- * through this function so some applications may wish to modify it
- * to avoid allocating a large strm->next_out buffer and copying into it.
- * (See also read_buf()).
- */
-local void flush_pending(strm)
-    z_streamp strm;
-{
-    deflate_state *s = (deflate_state *) strm->state;
-    unsigned len = s->pending;
-
-    if (len > strm->avail_out) len = strm->avail_out;
-    if (len == 0) return;
-
-    if (strm->next_out != Z_NULL) {
-	zmemcpy(strm->next_out, s->pending_out, len);
-	strm->next_out += len;
-    }
-    s->pending_out += len;
-    strm->total_out += len;
-    strm->avail_out  -= len;
-    s->pending -= len;
-    if (s->pending == 0) {
-        s->pending_out = s->pending_buf;
-    }
-}
-
-/* ========================================================================= */
-int deflate (strm, flush)
-    z_streamp strm;
-    int flush;
-{
-    int old_flush; /* value of flush param for previous deflate call */
-    deflate_state *s;
-
-    if (strm == Z_NULL || strm->state == Z_NULL ||
-	flush > Z_FINISH || flush < 0) {
-        return Z_STREAM_ERROR;
-    }
-    s = (deflate_state *) strm->state;
-
-    if ((strm->next_in == Z_NULL && strm->avail_in != 0) ||
-	(s->status == FINISH_STATE && flush != Z_FINISH)) {
-        ERR_RETURN(strm, Z_STREAM_ERROR);
-    }
-    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
-
-    s->strm = strm; /* just in case */
-    old_flush = s->last_flush;
-    s->last_flush = flush;
-
-    /* Write the zlib header */
-    if (s->status == INIT_STATE) {
-
-        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
-        uInt level_flags = (s->level-1) >> 1;
-
-        if (level_flags > 3) level_flags = 3;
-        header |= (level_flags << 6);
-	if (s->strstart != 0) header |= PRESET_DICT;
-        header += 31 - (header % 31);
-
-        s->status = BUSY_STATE;
-        putShortMSB(s, header);
-
-	/* Save the adler32 of the preset dictionary: */
-	if (s->strstart != 0) {
-	    putShortMSB(s, (uInt)(strm->adler >> 16));
-	    putShortMSB(s, (uInt)(strm->adler & 0xffff));
-	}
-	strm->adler = 1L;
-    }
-
-    /* Flush as much pending output as possible */
-    if (s->pending != 0) {
-        flush_pending(strm);
-        if (strm->avail_out == 0) {
-	    /* Since avail_out is 0, deflate will be called again with
-	     * more output space, but possibly with both pending and
-	     * avail_in equal to zero. There won't be anything to do,
-	     * but this is not an error situation so make sure we
-	     * return OK instead of BUF_ERROR at next call of deflate:
-             */
-	    s->last_flush = -1;
-	    return Z_OK;
-	}
-
-    /* Make sure there is something to do and avoid duplicate consecutive
-     * flushes. For repeated and useless calls with Z_FINISH, we keep
-     * returning Z_STREAM_END instead of Z_BUFF_ERROR.
-     */
-    } else if (strm->avail_in == 0 && flush <= old_flush &&
-	       flush != Z_FINISH) {
-        ERR_RETURN(strm, Z_BUF_ERROR);
-    }
-
-    /* User must not provide more input after the first FINISH: */
-    if (s->status == FINISH_STATE && strm->avail_in != 0) {
-        ERR_RETURN(strm, Z_BUF_ERROR);
-    }
-
-    /* Start a new block or continue the current one.
-     */
-    if (strm->avail_in != 0 || s->lookahead != 0 ||
-        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
-        block_state bstate;
-
-	bstate = (*(configuration_table[s->level].func))(s, flush);
-
-        if (bstate == finish_started || bstate == finish_done) {
-            s->status = FINISH_STATE;
-        }
-        if (bstate == need_more || bstate == finish_started) {
-	    if (strm->avail_out == 0) {
-	        s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
-	    }
-	    return Z_OK;
-	    /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
-	     * of deflate should use the same flush parameter to make sure
-	     * that the flush is complete. So we don't have to output an
-	     * empty block here, this will be done at next call. This also
-	     * ensures that for a very small output buffer, we emit at most
-	     * one empty block.
-	     */
-	}
-        if (bstate == block_done) {
-            if (flush == Z_PARTIAL_FLUSH) {
-                _tr_align(s);
-	    } else if (flush == Z_PACKET_FLUSH) {
-		/* Output just the 3-bit `stored' block type value,
-		   but not a zero length. */
-		_tr_stored_type_only(s);
-            } else { /* FULL_FLUSH or SYNC_FLUSH */
-                _tr_stored_block(s, (char*)0, 0L, 0);
-                /* For a full flush, this empty block will be recognized
-                 * as a special marker by inflate_sync().
-                 */
-                if (flush == Z_FULL_FLUSH) {
-                    CLEAR_HASH(s);             /* forget history */
-                }
-            }
-            flush_pending(strm);
-	    if (strm->avail_out == 0) {
-	      s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
-	      return Z_OK;
-	    }
-        }
-    }
-    Assert(strm->avail_out > 0, "bug2");
-
-    if (flush != Z_FINISH) return Z_OK;
-    if (s->noheader) return Z_STREAM_END;
-
-    /* Write the zlib trailer (adler32) */
-    putShortMSB(s, (uInt)(strm->adler >> 16));
-    putShortMSB(s, (uInt)(strm->adler & 0xffff));
-    flush_pending(strm);
-    /* If avail_out is zero, the application will call deflate again
-     * to flush the rest.
-     */
-    s->noheader = -1; /* write the trailer only once! */
-    return s->pending != 0 ? Z_OK : Z_STREAM_END;
-}
-
-/* ========================================================================= */
-int deflateEnd (strm)
-    z_streamp strm;
-{
-    int status;
-    deflate_state *s;
-
-    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
-    s = (deflate_state *) strm->state;
-
-    status = s->status;
-    if (status != INIT_STATE && status != BUSY_STATE &&
-	status != FINISH_STATE) {
-      return Z_STREAM_ERROR;
-    }
-
-    /* Deallocate in reverse order of allocations: */
-    TRY_FREE(strm, s->pending_buf);
-    TRY_FREE(strm, s->head);
-    TRY_FREE(strm, s->prev);
-    TRY_FREE(strm, s->window);
-
-    ZFREE(strm, s);
-    strm->state = Z_NULL;
-
-    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
-}
-
-/* =========================================================================
- * Copy the source state to the destination state.
- */
-int deflateCopy (dest, source)
-    z_streamp dest;
-    z_streamp source;
-{
-    deflate_state *ds;
-    deflate_state *ss;
-    ushf *overlay;
-
-    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL)
-        return Z_STREAM_ERROR;
-    ss = (deflate_state *) source->state;
-
-    *dest = *source;
-
-    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
-    if (ds == Z_NULL) return Z_MEM_ERROR;
-    dest->state = (struct internal_state FAR *) ds;
-    *ds = *ss;
-    ds->strm = dest;
-
-    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
-    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
-    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
-    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
-    ds->pending_buf = (uchf *) overlay;
-
-    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
-        ds->pending_buf == Z_NULL) {
-        deflateEnd (dest);
-        return Z_MEM_ERROR;
-    }
-    /* ??? following zmemcpy doesn't work for 16-bit MSDOS */
-    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
-    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
-    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
-    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
-
-    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
-    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
-    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
-
-    ds->l_desc.dyn_tree = ds->dyn_ltree;
-    ds->d_desc.dyn_tree = ds->dyn_dtree;
-    ds->bl_desc.dyn_tree = ds->bl_tree;
-
-    return Z_OK;
-}
-
-/* ===========================================================================
- * Return the number of bytes of output which are immediately available
- * for output from the decompressor.
- */
-int deflateOutputPending (strm)
-    z_streamp strm;
-{
-    if (strm == Z_NULL || strm->state == Z_NULL) return 0;
-    
-    return ((deflate_state *)(strm->state))->pending;
-}
-
-/* ===========================================================================
- * Read a new buffer from the current input stream, update the adler32
- * and total number of bytes read.  All deflate() input goes through
- * this function so some applications may wish to modify it to avoid
- * allocating a large strm->next_in buffer and copying from it.
- * (See also flush_pending()).
- */
-local int read_buf(strm, buf, size)
-    z_streamp strm;
-    charf *buf;
-    unsigned size;
-{
-    unsigned len = strm->avail_in;
-
-    if (len > size) len = size;
-    if (len == 0) return 0;
-
-    strm->avail_in  -= len;
-
-    if (!((deflate_state *)(strm->state))->noheader) {
-        strm->adler = adler32(strm->adler, strm->next_in, len);
-    }
-    zmemcpy(buf, strm->next_in, len);
-    strm->next_in  += len;
-    strm->total_in += len;
-
-    return (int)len;
-}
-
-/* ===========================================================================
- * Initialize the "longest match" routines for a new zlib stream
- */
-local void lm_init (s)
-    deflate_state *s;
-{
-    s->window_size = (ulg)2L*s->w_size;
-
-    CLEAR_HASH(s);
-
-    /* Set the default configuration parameters:
-     */
-    s->max_lazy_match   = configuration_table[s->level].max_lazy;
-    s->good_match       = configuration_table[s->level].good_length;
-    s->nice_match       = configuration_table[s->level].nice_length;
-    s->max_chain_length = configuration_table[s->level].max_chain;
-
-    s->strstart = 0;
-    s->block_start = 0L;
-    s->lookahead = 0;
-    s->match_length = s->prev_length = MIN_MATCH-1;
-    s->match_available = 0;
-    s->ins_h = 0;
-#ifdef ASMV
-    match_init(); /* initialize the asm code */
-#endif
-}
-
-/* ===========================================================================
- * Set match_start to the longest match starting at the given string and
- * return its length. Matches shorter or equal to prev_length are discarded,
- * in which case the result is equal to prev_length and match_start is
- * garbage.
- * IN assertions: cur_match is the head of the hash chain for the current
- *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
- * OUT assertion: the match length is not greater than s->lookahead.
- */
-#ifndef ASMV
-/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
- * match.S. The code will be functionally equivalent.
- */
-local uInt longest_match(s, cur_match)
-    deflate_state *s;
-    IPos cur_match;                             /* current match */
-{
-    unsigned chain_length = s->max_chain_length;/* max hash chain length */
-    register Bytef *scan = s->window + s->strstart; /* current string */
-    register Bytef *match;                       /* matched string */
-    register int len;                           /* length of current match */
-    int best_len = s->prev_length;              /* best match length so far */
-    int nice_match = s->nice_match;             /* stop if match long enough */
-    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
-        s->strstart - (IPos)MAX_DIST(s) : NIL;
-    /* Stop when cur_match becomes <= limit. To simplify the code,
-     * we prevent matches with the string of window index 0.
-     */
-    Posf *prev = s->prev;
-    uInt wmask = s->w_mask;
-
-#ifdef UNALIGNED_OK
-    /* Compare two bytes at a time. Note: this is not always beneficial.
-     * Try with and without -DUNALIGNED_OK to check.
-     */
-    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
-    register ush scan_start = *(ushf*)scan;
-    register ush scan_end   = *(ushf*)(scan+best_len-1);
-#else
-    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
-    register Byte scan_end1  = scan[best_len-1];
-    register Byte scan_end   = scan[best_len];
-#endif
-
-    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
-     * It is easy to get rid of this optimization if necessary.
-     */
-    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
-
-    /* Do not waste too much time if we already have a good match: */
-    if (s->prev_length >= s->good_match) {
-        chain_length >>= 2;
-    }
-    /* Do not look for matches beyond the end of the input. This is necessary
-     * to make deflate deterministic.
-     */
-    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
-
-    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
-
-    do {
-        Assert(cur_match < s->strstart, "no future");
-        match = s->window + cur_match;
-
-        /* Skip to next match if the match length cannot increase
-         * or if the match length is less than 2:
-         */
-#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
-        /* This code assumes sizeof(unsigned short) == 2. Do not use
-         * UNALIGNED_OK if your compiler uses a different size.
-         */
-        if (*(ushf*)(match+best_len-1) != scan_end ||
-            *(ushf*)match != scan_start) continue;
-
-        /* It is not necessary to compare scan[2] and match[2] since they are
-         * always equal when the other bytes match, given that the hash keys
-         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
-         * strstart+3, +5, ... up to strstart+257. We check for insufficient
-         * lookahead only every 4th comparison; the 128th check will be made
-         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
-         * necessary to put more guard bytes at the end of the window, or
-         * to check more often for insufficient lookahead.
-         */
-        Assert(scan[2] == match[2], "scan[2]?");
-        scan++, match++;
-        do {
-        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 scan < strend);
-        /* The funny "do {}" generates better code on most compilers */
-
-        /* Here, scan <= window+strstart+257 */
-        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-        if (*scan == *match) scan++;
-
-        len = (MAX_MATCH - 1) - (int)(strend-scan);
-        scan = strend - (MAX_MATCH-1);
-
-#else /* UNALIGNED_OK */
-
-        if (match[best_len]   != scan_end  ||
-            match[best_len-1] != scan_end1 ||
-            *match            != *scan     ||
-            *++match          != scan[1])      continue;
-
-        /* The check at best_len-1 can be removed because it will be made
-         * again later. (This heuristic is not always a win.)
-         * It is not necessary to compare scan[2] and match[2] since they
-         * are always equal when the other bytes match, given that
-         * the hash keys are equal and that HASH_BITS >= 8.
-         */
-        scan += 2, match++;
-        Assert(*scan == *match, "match[2]?");
-
-        /* We check for insufficient lookahead only every 8th comparison;
-         * the 256th check will be made at strstart+258.
-         */
-        do {
-        } while (*++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 scan < strend);
-
-        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-
-        len = MAX_MATCH - (int)(strend - scan);
-        scan = strend - MAX_MATCH;
-
-#endif /* UNALIGNED_OK */
-
-        if (len > best_len) {
-            s->match_start = cur_match;
-            best_len = len;
-            if (len >= nice_match) break;
-#ifdef UNALIGNED_OK
-            scan_end = *(ushf*)(scan+best_len-1);
-#else
-            scan_end1  = scan[best_len-1];
-            scan_end   = scan[best_len];
-#endif
-        }
-    } while ((cur_match = prev[cur_match & wmask]) > limit
-             && --chain_length != 0);
-
-    if ((uInt)best_len <= s->lookahead) return best_len;
-    return s->lookahead;
-}
-#endif /* ASMV */
-
-#ifdef DEBUG_ZLIB
-/* ===========================================================================
- * Check that the match at match_start is indeed a match.
- */
-local void check_match(s, start, match, length)
-    deflate_state *s;
-    IPos start, match;
-    int length;
-{
-    /* check that the match is indeed a match */
-    if (zmemcmp((charf *)s->window + match,
-                (charf *)s->window + start, length) != EQUAL) {
-        fprintf(stderr, " start %u, match %u, length %d\n",
-		start, match, length);
-        do {
-	    fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
-	} while (--length != 0);
-        z_error("invalid match");
-    }
-    if (z_verbose > 1) {
-        fprintf(stderr,"\\[%d,%d]", start-match, length);
-        do { putc(s->window[start++], stderr); } while (--length != 0);
-    }
-}
-#else
-#  define check_match(s, start, match, length)
-#endif
-
-/* ===========================================================================
- * Fill the window when the lookahead becomes insufficient.
- * Updates strstart and lookahead.
- *
- * IN assertion: lookahead < MIN_LOOKAHEAD
- * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
- *    At least one byte has been read, or avail_in == 0; reads are
- *    performed for at least two bytes (required for the zip translate_eol
- *    option -- not supported here).
- */
-local void fill_window(s)
-    deflate_state *s;
-{
-    register unsigned n, m;
-    register Posf *p;
-    unsigned more;    /* Amount of free space at the end of the window. */
-    uInt wsize = s->w_size;
-
-    do {
-        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
-
-        /* Deal with !@#$% 64K limit: */
-        if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
-            more = wsize;
-
-        } else if (more == (unsigned)(-1)) {
-            /* Very unlikely, but possible on 16 bit machine if strstart == 0
-             * and lookahead == 1 (input done one byte at time)
-             */
-            more--;
-
-        /* If the window is almost full and there is insufficient lookahead,
-         * move the upper half to the lower one to make room in the upper half.
-         */
-        } else if (s->strstart >= wsize+MAX_DIST(s)) {
-
-            zmemcpy((charf *)s->window, (charf *)s->window+wsize,
-                   (unsigned)wsize);
-            s->match_start -= wsize;
-            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
-            s->block_start -= (long) wsize;
-
-            /* Slide the hash table (could be avoided with 32 bit values
-               at the expense of memory usage). We slide even when level == 0
-               to keep the hash table consistent if we switch back to level > 0
-               later. (Using level 0 permanently is not an optimal usage of
-               zlib, so we don't care about this pathological case.)
-             */
-            n = s->hash_size;
-            p = &s->head[n];
-            do {
-                m = *--p;
-                *p = (Pos)(m >= wsize ? m-wsize : NIL);
-            } while (--n);
-
-            n = wsize;
-            p = &s->prev[n];
-            do {
-                m = *--p;
-                *p = (Pos)(m >= wsize ? m-wsize : NIL);
-                /* If n is not on any hash chain, prev[n] is garbage but
-                 * its value will never be used.
-                 */
-            } while (--n);
-            more += wsize;
-        }
-        if (s->strm->avail_in == 0) return;
-
-        /* If there was no sliding:
-         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
-         *    more == window_size - lookahead - strstart
-         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
-         * => more >= window_size - 2*WSIZE + 2
-         * In the BIG_MEM or MMAP case (not yet supported),
-         *   window_size == input_size + MIN_LOOKAHEAD  &&
-         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
-         * Otherwise, window_size == 2*WSIZE so more >= 2.
-         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
-         */
-        Assert(more >= 2, "more < 2");
-
-        n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead,
-                     more);
-        s->lookahead += n;
-
-        /* Initialize the hash value now that we have some input: */
-        if (s->lookahead >= MIN_MATCH) {
-            s->ins_h = s->window[s->strstart];
-            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
-#if MIN_MATCH != 3
-            Call UPDATE_HASH() MIN_MATCH-3 more times
-#endif
-        }
-        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
-         * but this is not important since only literal bytes will be emitted.
-         */
-
-    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
-}
-
-/* ===========================================================================
- * Flush the current block, with given end-of-file flag.
- * IN assertion: strstart is set to the end of the current match.
- */
-#define FLUSH_BLOCK_ONLY(s, eof) { \
-   _tr_flush_block(s, (s->block_start >= 0L ? \
-                   (charf *)&s->window[(unsigned)s->block_start] : \
-                   (charf *)Z_NULL), \
-		(ulg)((long)s->strstart - s->block_start), \
-		(eof)); \
-   s->block_start = s->strstart; \
-   flush_pending(s->strm); \
-   Tracev((stderr,"[FLUSH]")); \
-}
-
-/* Same but force premature exit if necessary. */
-#define FLUSH_BLOCK(s, eof) { \
-   FLUSH_BLOCK_ONLY(s, eof); \
-   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
-}
-
-/* ===========================================================================
- * Copy without compression as much as possible from the input stream, return
- * the current block state.
- * This function does not insert new strings in the dictionary since
- * uncompressible data is probably not useful. This function is used
- * only for the level=0 compression option.
- * NOTE: this function should be optimized to avoid extra copying from
- * window to pending_buf.
- */
-local block_state deflate_stored(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
-     * to pending_buf_size, and each stored block has a 5 byte header:
-     */
-    ulg max_block_size = 0xffff;
-    ulg max_start;
-
-    if (max_block_size > s->pending_buf_size - 5) {
-        max_block_size = s->pending_buf_size - 5;
-    }
-
-    /* Copy as much as possible from input to output: */
-    for (;;) {
-        /* Fill the window as much as possible: */
-        if (s->lookahead <= 1) {
-
-            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
-		   s->block_start >= (long)s->w_size, "slide too late");
-
-            fill_window(s);
-            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
-
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-	Assert(s->block_start >= 0L, "block gone");
-
-	s->strstart += s->lookahead;
-	s->lookahead = 0;
-
-	/* Emit a stored block if pending_buf will be full: */
- 	max_start = s->block_start + max_block_size;
-        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
-	    /* strstart == 0 is possible when wraparound on 16-bit machine */
-	    s->lookahead = (uInt)(s->strstart - max_start);
-	    s->strstart = (uInt)max_start;
-            FLUSH_BLOCK(s, 0);
-	}
-	/* Flush if we may have to slide, otherwise block_start may become
-         * negative and the data will be gone:
-         */
-        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
-            FLUSH_BLOCK(s, 0);
-	}
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-
-/* ===========================================================================
- * Compress as much as possible from the input stream, return the current
- * block state.
- * This function does not perform lazy evaluation of matches and inserts
- * new strings in the dictionary only for unmatched strings or for short
- * matches. It is used only for the fast compression options.
- */
-local block_state deflate_fast(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    IPos hash_head = NIL; /* head of the hash chain */
-    int bflush;           /* set if current block must be flushed */
-
-    for (;;) {
-        /* Make sure that we always have enough lookahead, except
-         * at the end of the input file. We need MAX_MATCH bytes
-         * for the next match, plus MIN_MATCH bytes to insert the
-         * string following the next match.
-         */
-        if (s->lookahead < MIN_LOOKAHEAD) {
-            fill_window(s);
-            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
-	        return need_more;
-	    }
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-
-        /* Insert the string window[strstart .. strstart+2] in the
-         * dictionary, and set hash_head to the head of the hash chain:
-         */
-        if (s->lookahead >= MIN_MATCH) {
-            INSERT_STRING(s, s->strstart, hash_head);
-        }
-
-        /* Find the longest match, discarding those <= prev_length.
-         * At this point we have always match_length < MIN_MATCH
-         */
-        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
-            /* To simplify the code, we prevent matches with the string
-             * of window index 0 (in particular we have to avoid a match
-             * of the string with itself at the start of the input file).
-             */
-            if (s->strategy != Z_HUFFMAN_ONLY) {
-                s->match_length = longest_match (s, hash_head);
-            }
-            /* longest_match() sets match_start */
-        }
-        if (s->match_length >= MIN_MATCH) {
-            check_match(s, s->strstart, s->match_start, s->match_length);
-
-            bflush = _tr_tally(s, s->strstart - s->match_start,
-                               s->match_length - MIN_MATCH);
-
-            s->lookahead -= s->match_length;
-
-            /* Insert new strings in the hash table only if the match length
-             * is not too large. This saves time but degrades compression.
-             */
-            if (s->match_length <= s->max_insert_length &&
-                s->lookahead >= MIN_MATCH) {
-                s->match_length--; /* string at strstart already in hash table */
-                do {
-                    s->strstart++;
-                    INSERT_STRING(s, s->strstart, hash_head);
-                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
-                     * always MIN_MATCH bytes ahead.
-                     */
-                } while (--s->match_length != 0);
-                s->strstart++; 
-            } else {
-                s->strstart += s->match_length;
-                s->match_length = 0;
-                s->ins_h = s->window[s->strstart];
-                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
-#if MIN_MATCH != 3
-                Call UPDATE_HASH() MIN_MATCH-3 more times
-#endif
-                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
-                 * matter since it will be recomputed at next deflate call.
-                 */
-            }
-        } else {
-            /* No match, output a literal byte */
-            Tracevv((stderr,"%c", s->window[s->strstart]));
-            bflush = _tr_tally (s, 0, s->window[s->strstart]);
-            s->lookahead--;
-            s->strstart++; 
-        }
-        if (bflush) FLUSH_BLOCK(s, 0);
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-
-/* ===========================================================================
- * Same as above, but achieves better compression. We use a lazy
- * evaluation for matches: a match is finally adopted only if there is
- * no better match at the next window position.
- */
-local block_state deflate_slow(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    IPos hash_head = NIL;    /* head of hash chain */
-    int bflush;              /* set if current block must be flushed */
-
-    /* Process the input block. */
-    for (;;) {
-        /* Make sure that we always have enough lookahead, except
-         * at the end of the input file. We need MAX_MATCH bytes
-         * for the next match, plus MIN_MATCH bytes to insert the
-         * string following the next match.
-         */
-        if (s->lookahead < MIN_LOOKAHEAD) {
-            fill_window(s);
-            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
-	        return need_more;
-	    }
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-
-        /* Insert the string window[strstart .. strstart+2] in the
-         * dictionary, and set hash_head to the head of the hash chain:
-         */
-        if (s->lookahead >= MIN_MATCH) {
-            INSERT_STRING(s, s->strstart, hash_head);
-        }
-
-        /* Find the longest match, discarding those <= prev_length.
-         */
-        s->prev_length = s->match_length, s->prev_match = s->match_start;
-        s->match_length = MIN_MATCH-1;
-
-        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
-            s->strstart - hash_head <= MAX_DIST(s)) {
-            /* To simplify the code, we prevent matches with the string
-             * of window index 0 (in particular we have to avoid a match
-             * of the string with itself at the start of the input file).
-             */
-            if (s->strategy != Z_HUFFMAN_ONLY) {
-                s->match_length = longest_match (s, hash_head);
-            }
-            /* longest_match() sets match_start */
-
-            if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
-                 (s->match_length == MIN_MATCH &&
-                  s->strstart - s->match_start > TOO_FAR))) {
-
-                /* If prev_match is also MIN_MATCH, match_start is garbage
-                 * but we will ignore the current match anyway.
-                 */
-                s->match_length = MIN_MATCH-1;
-            }
-        }
-        /* If there was a match at the previous step and the current
-         * match is not better, output the previous match:
-         */
-        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
-            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
-            /* Do not insert strings in hash table beyond this. */
-
-            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
-
-            bflush = _tr_tally(s, s->strstart -1 - s->prev_match,
-                               s->prev_length - MIN_MATCH);
-
-            /* Insert in hash table all strings up to the end of the match.
-             * strstart-1 and strstart are already inserted. If there is not
-             * enough lookahead, the last two strings are not inserted in
-             * the hash table.
-             */
-            s->lookahead -= s->prev_length-1;
-            s->prev_length -= 2;
-            do {
-                if (++s->strstart <= max_insert) {
-                    INSERT_STRING(s, s->strstart, hash_head);
-                }
-            } while (--s->prev_length != 0);
-            s->match_available = 0;
-            s->match_length = MIN_MATCH-1;
-            s->strstart++;
-
-            if (bflush) FLUSH_BLOCK(s, 0);
-
-        } else if (s->match_available) {
-            /* If there was no match at the previous position, output a
-             * single literal. If there was a match but the current match
-             * is longer, truncate the previous match to a single literal.
-             */
-            Tracevv((stderr,"%c", s->window[s->strstart-1]));
-            if (_tr_tally (s, 0, s->window[s->strstart-1])) {
-                FLUSH_BLOCK_ONLY(s, 0);
-            }
-            s->strstart++;
-            s->lookahead--;
-            if (s->strm->avail_out == 0) return need_more;
-        } else {
-            /* There is no previous match to compare with, wait for
-             * the next step to decide.
-             */
-            s->match_available = 1;
-            s->strstart++;
-            s->lookahead--;
-        }
-    }
-    Assert (flush != Z_NO_FLUSH, "no flush?");
-    if (s->match_available) {
-        Tracevv((stderr,"%c", s->window[s->strstart-1]));
-        _tr_tally (s, 0, s->window[s->strstart-1]);
-        s->match_available = 0;
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-/* --- deflate.c */
-
-/* +++ trees.c */
-/* trees.c -- output deflated data using Huffman coding
- * Copyright (C) 1995-1996 Jean-loup Gailly
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/*
- *  ALGORITHM
- *
- *      The "deflation" process uses several Huffman trees. The more
- *      common source values are represented by shorter bit sequences.
- *
- *      Each code tree is stored in a compressed form which is itself
- * a Huffman encoding of the lengths of all the code strings (in
- * ascending order by source values).  The actual code strings are
- * reconstructed from the lengths in the inflate process, as described
- * in the deflate specification.
- *
- *  REFERENCES
- *
- *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
- *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
- *
- *      Storer, James A.
- *          Data Compression:  Methods and Theory, pp. 49-50.
- *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
- *
- *      Sedgewick, R.
- *          Algorithms, p290.
- *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
- */
-
-/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */
-
-/* #include "deflate.h" */
-
-#ifdef DEBUG_ZLIB
-#  include <ctype.h>
-#endif
-
-/* ===========================================================================
- * Constants
- */
-
-#define MAX_BL_BITS 7
-/* Bit length codes must not exceed MAX_BL_BITS bits */
-
-#define END_BLOCK 256
-/* end of block literal code */
-
-#define REP_3_6      16
-/* repeat previous bit length 3-6 times (2 bits of repeat count) */
-
-#define REPZ_3_10    17
-/* repeat a zero length 3-10 times  (3 bits of repeat count) */
-
-#define REPZ_11_138  18
-/* repeat a zero length 11-138 times  (7 bits of repeat count) */
-
-local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
-   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
-
-local int extra_dbits[D_CODES] /* extra bits for each distance code */
-   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
-
-local int extra_blbits[BL_CODES]/* extra bits for each bit length code */
-   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
-
-local uch bl_order[BL_CODES]
-   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
-/* The lengths of the bit length codes are sent in order of decreasing
- * probability, to avoid transmitting the lengths for unused bit length codes.
- */
-
-#define Buf_size (8 * 2*sizeof(char))
-/* Number of bits used within bi_buf. (bi_buf might be implemented on
- * more than 16 bits on some systems.)
- */
-
-/* ===========================================================================
- * Local data. These are initialized only once.
- */
-
-local ct_data static_ltree[L_CODES+2];
-/* The static literal tree. Since the bit lengths are imposed, there is no
- * need for the L_CODES extra codes used during heap construction. However
- * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
- * below).
- */
-
-local ct_data static_dtree[D_CODES];
-/* The static distance tree. (Actually a trivial tree since all codes use
- * 5 bits.)
- */
-
-local uch dist_code[512];
-/* distance codes. The first 256 values correspond to the distances
- * 3 .. 258, the last 256 values correspond to the top 8 bits of
- * the 15 bit distances.
- */
-
-local uch length_code[MAX_MATCH-MIN_MATCH+1];
-/* length code for each normalized match length (0 == MIN_MATCH) */
-
-local int base_length[LENGTH_CODES];
-/* First normalized length for each code (0 = MIN_MATCH) */
-
-local int base_dist[D_CODES];
-/* First normalized distance for each code (0 = distance of 1) */
-
-struct static_tree_desc_s {
-    ct_data *static_tree;        /* static tree or NULL */
-    intf    *extra_bits;         /* extra bits for each code or NULL */
-    int     extra_base;          /* base index for extra_bits */
-    int     elems;               /* max number of elements in the tree */
-    int     max_length;          /* max bit length for the codes */
-};
-
-local static_tree_desc  static_l_desc =
-{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
-
-local static_tree_desc  static_d_desc =
-{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
-
-local static_tree_desc  static_bl_desc =
-{(ct_data *)0, extra_blbits, 0,      BL_CODES, MAX_BL_BITS};
-
-/* ===========================================================================
- * Local (static) routines in this file.
- */
-
-local void tr_static_init OF((void));
-local void init_block     OF((deflate_state *s));
-local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
-local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
-local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
-local void build_tree     OF((deflate_state *s, tree_desc *desc));
-local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
-local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
-local int  build_bl_tree  OF((deflate_state *s));
-local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
-                              int blcodes));
-local void compress_block OF((deflate_state *s, ct_data *ltree,
-                              ct_data *dtree));
-local void set_data_type  OF((deflate_state *s));
-local unsigned bi_reverse OF((unsigned value, int length));
-local void bi_windup      OF((deflate_state *s));
-local void bi_flush       OF((deflate_state *s));
-local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
-                              int header));
-
-#ifndef DEBUG_ZLIB
-#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
-   /* Send a code of the given tree. c and tree must not have side effects */
-
-#else /* DEBUG_ZLIB */
-#  define send_code(s, c, tree) \
-     { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
-       send_bits(s, tree[c].Code, tree[c].Len); }
-#endif
-
-#define d_code(dist) \
-   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
-/* Mapping from a distance to a distance code. dist is the distance - 1 and
- * must not have side effects. dist_code[256] and dist_code[257] are never
- * used.
- */
-
-/* ===========================================================================
- * Output a short LSB first on the stream.
- * IN assertion: there is enough room in pendingBuf.
- */
-#define put_short(s, w) { \
-    put_byte(s, (uch)((w) & 0xff)); \
-    put_byte(s, (uch)((ush)(w) >> 8)); \
-}
-
-/* ===========================================================================
- * Send a value on a given number of bits.
- * IN assertion: length <= 16 and value fits in length bits.
- */
-#ifdef DEBUG_ZLIB
-local void send_bits      OF((deflate_state *s, int value, int length));
-
-local void send_bits(s, value, length)
-    deflate_state *s;
-    int value;  /* value to send */
-    int length; /* number of bits */
-{
-    Tracevv((stderr," l %2d v %4x ", length, value));
-    Assert(length > 0 && length <= 15, "invalid length");
-    s->bits_sent += (ulg)length;
-
-    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
-     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
-     * unused bits in value.
-     */
-    if (s->bi_valid > (int)Buf_size - length) {
-        s->bi_buf |= (value << s->bi_valid);
-        put_short(s, s->bi_buf);
-        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
-        s->bi_valid += length - Buf_size;
-    } else {
-        s->bi_buf |= value << s->bi_valid;
-        s->bi_valid += length;
-    }
-}
-#else /* !DEBUG_ZLIB */
-
-#define send_bits(s, value, length) \
-{ int len = length;\
-  if (s->bi_valid > (int)Buf_size - len) {\
-    int val = value;\
-    s->bi_buf |= (val << s->bi_valid);\
-    put_short(s, s->bi_buf);\
-    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
-    s->bi_valid += len - Buf_size;\
-  } else {\
-    s->bi_buf |= (value) << s->bi_valid;\
-    s->bi_valid += len;\
-  }\
-}
-#endif /* DEBUG_ZLIB */
-
-
-#define MAX(a,b) (a >= b ? a : b)
-/* the arguments must not have side effects */
-
-/* ===========================================================================
- * Initialize the various 'constant' tables. In a multi-threaded environment,
- * this function may be called by two threads concurrently, but this is
- * harmless since both invocations do exactly the same thing.
- */
-local void tr_static_init()
-{
-    static int static_init_done;
-    int n;        /* iterates over tree elements */
-    int bits;     /* bit counter */
-    int length;   /* length value */
-    int code;     /* code value */
-    int dist;     /* distance index */
-    ush bl_count[MAX_BITS+1];
-    /* number of codes at each bit length for an optimal tree */
-
-    if (static_init_done) return;
-
-    /* Initialize the mapping length (0..255) -> length code (0..28) */
-    length = 0;
-    for (code = 0; code < LENGTH_CODES-1; code++) {
-        base_length[code] = length;
-        for (n = 0; n < (1<<extra_lbits[code]); n++) {
-            length_code[length++] = (uch)code;
-        }
-    }
-    Assert (length == 256, "tr_static_init: length != 256");
-    /* Note that the length 255 (match length 258) can be represented
-     * in two different ways: code 284 + 5 bits or code 285, so we
-     * overwrite length_code[255] to use the best encoding:
-     */
-    length_code[length-1] = (uch)code;
-
-    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
-    dist = 0;
-    for (code = 0 ; code < 16; code++) {
-        base_dist[code] = dist;
-        for (n = 0; n < (1<<extra_dbits[code]); n++) {
-            dist_code[dist++] = (uch)code;
-        }
-    }
-    Assert (dist == 256, "tr_static_init: dist != 256");
-    dist >>= 7; /* from now on, all distances are divided by 128 */
-    for ( ; code < D_CODES; code++) {
-        base_dist[code] = dist << 7;
-        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
-            dist_code[256 + dist++] = (uch)code;
-        }
-    }
-    Assert (dist == 256, "tr_static_init: 256+dist != 512");
-
-    /* Construct the codes of the static literal tree */
-    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
-    n = 0;
-    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
-    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
-    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
-    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
-    /* Codes 286 and 287 do not exist, but we must include them in the
-     * tree construction to get a canonical Huffman tree (longest code
-     * all ones)
-     */
-    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
-
-    /* The static distance tree is trivial: */
-    for (n = 0; n < D_CODES; n++) {
-        static_dtree[n].Len = 5;
-        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
-    }
-    static_init_done = 1;
-}
-
-/* ===========================================================================
- * Initialize the tree data structures for a new zlib stream.
- */
-void _tr_init(s)
-    deflate_state *s;
-{
-    tr_static_init();
-
-    s->compressed_len = 0L;
-
-    s->l_desc.dyn_tree = s->dyn_ltree;
-    s->l_desc.stat_desc = &static_l_desc;
-
-    s->d_desc.dyn_tree = s->dyn_dtree;
-    s->d_desc.stat_desc = &static_d_desc;
-
-    s->bl_desc.dyn_tree = s->bl_tree;
-    s->bl_desc.stat_desc = &static_bl_desc;
-
-    s->bi_buf = 0;
-    s->bi_valid = 0;
-    s->last_eob_len = 8; /* enough lookahead for inflate */
-#ifdef DEBUG_ZLIB
-    s->bits_sent = 0L;
-#endif
-
-    /* Initialize the first block of the first file: */
-    init_block(s);
-}
-
-/* ===========================================================================
- * Initialize a new block.
- */
-local void init_block(s)
-    deflate_state *s;
-{
-    int n; /* iterates over tree elements */
-
-    /* Initialize the trees. */
-    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
-    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
-    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
-
-    s->dyn_ltree[END_BLOCK].Freq = 1;
-    s->opt_len = s->static_len = 0L;
-    s->last_lit = s->matches = 0;
-}
-
-#define SMALLEST 1
-/* Index within the heap array of least frequent node in the Huffman tree */
-
-
-/* ===========================================================================
- * Remove the smallest element from the heap and recreate the heap with
- * one less element. Updates heap and heap_len.
- */
-#define pqremove(s, tree, top) \
-{\
-    top = s->heap[SMALLEST]; \
-    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
-    pqdownheap(s, tree, SMALLEST); \
-}
-
-/* ===========================================================================
- * Compares to subtrees, using the tree depth as tie breaker when
- * the subtrees have equal frequency. This minimizes the worst case length.
- */
-#define smaller(tree, n, m, depth) \
-   (tree[n].Freq < tree[m].Freq || \
-   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
-
-/* ===========================================================================
- * Restore the heap property by moving down the tree starting at node k,
- * exchanging a node with the smallest of its two sons if necessary, stopping
- * when the heap property is re-established (each father smaller than its
- * two sons).
- */
-local void pqdownheap(s, tree, k)
-    deflate_state *s;
-    ct_data *tree;  /* the tree to restore */
-    int k;               /* node to move down */
-{
-    int v = s->heap[k];
-    int j = k << 1;  /* left son of k */
-    while (j <= s->heap_len) {
-        /* Set j to the smallest of the two sons: */
-        if (j < s->heap_len &&
-            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
-            j++;
-        }
-        /* Exit if v is smaller than both sons */
-        if (smaller(tree, v, s->heap[j], s->depth)) break;
-
-        /* Exchange v with the smallest son */
-        s->heap[k] = s->heap[j];  k = j;
-
-        /* And continue down the tree, setting j to the left son of k */
-        j <<= 1;
-    }
-    s->heap[k] = v;
-}
-
-/* ===========================================================================
- * Compute the optimal bit lengths for a tree and update the total bit length
- * for the current block.
- * IN assertion: the fields freq and dad are set, heap[heap_max] and
- *    above are the tree nodes sorted by increasing frequency.
- * OUT assertions: the field len is set to the optimal bit length, the
- *     array bl_count contains the frequencies for each bit length.
- *     The length opt_len is updated; static_len is also updated if stree is
- *     not null.
- */
-local void gen_bitlen(s, desc)
-    deflate_state *s;
-    tree_desc *desc;    /* the tree descriptor */
-{
-    ct_data *tree  = desc->dyn_tree;
-    int max_code   = desc->max_code;
-    ct_data *stree = desc->stat_desc->static_tree;
-    intf *extra    = desc->stat_desc->extra_bits;
-    int base       = desc->stat_desc->extra_base;
-    int max_length = desc->stat_desc->max_length;
-    int h;              /* heap index */
-    int n, m;           /* iterate over the tree elements */
-    int bits;           /* bit length */
-    int xbits;          /* extra bits */
-    ush f;              /* frequency */
-    int overflow = 0;   /* number of elements with bit length too large */
-
-    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
-
-    /* In a first pass, compute the optimal bit lengths (which may
-     * overflow in the case of the bit length tree).
-     */
-    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
-
-    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
-        n = s->heap[h];
-        bits = tree[tree[n].Dad].Len + 1;
-        if (bits > max_length) bits = max_length, overflow++;
-        tree[n].Len = (ush)bits;
-        /* We overwrite tree[n].Dad which is no longer needed */
-
-        if (n > max_code) continue; /* not a leaf node */
-
-        s->bl_count[bits]++;
-        xbits = 0;
-        if (n >= base) xbits = extra[n-base];
-        f = tree[n].Freq;
-        s->opt_len += (ulg)f * (bits + xbits);
-        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
-    }
-    if (overflow == 0) return;
-
-    Trace((stderr,"\nbit length overflow\n"));
-    /* This happens for example on obj2 and pic of the Calgary corpus */
-
-    /* Find the first bit length which could increase: */
-    do {
-        bits = max_length-1;
-        while (s->bl_count[bits] == 0) bits--;
-        s->bl_count[bits]--;      /* move one leaf down the tree */
-        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
-        s->bl_count[max_length]--;
-        /* The brother of the overflow item also moves one step up,
-         * but this does not affect bl_count[max_length]
-         */
-        overflow -= 2;
-    } while (overflow > 0);
-
-    /* Now recompute all bit lengths, scanning in increasing frequency.
-     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
-     * lengths instead of fixing only the wrong ones. This idea is taken
-     * from 'ar' written by Haruhiko Okumura.)
-     */
-    for (bits = max_length; bits != 0; bits--) {
-        n = s->bl_count[bits];
-        while (n != 0) {
-            m = s->heap[--h];
-            if (m > max_code) continue;
-            if (tree[m].Len != (unsigned) bits) {
-                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
-                s->opt_len += ((long)bits - (long)tree[m].Len)
-                              *(long)tree[m].Freq;
-                tree[m].Len = (ush)bits;
-            }
-            n--;
-        }
-    }
-}
-
-/* ===========================================================================
- * Generate the codes for a given tree and bit counts (which need not be
- * optimal).
- * IN assertion: the array bl_count contains the bit length statistics for
- * the given tree and the field len is set for all tree elements.
- * OUT assertion: the field code is set for all tree elements of non
- *     zero code length.
- */
-local void gen_codes (tree, max_code, bl_count)
-    ct_data *tree;             /* the tree to decorate */
-    int max_code;              /* largest code with non zero frequency */
-    ushf *bl_count;            /* number of codes at each bit length */
-{
-    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
-    ush code = 0;              /* running code value */
-    int bits;                  /* bit index */
-    int n;                     /* code index */
-
-    /* The distribution counts are first used to generate the code values
-     * without bit reversal.
-     */
-    for (bits = 1; bits <= MAX_BITS; bits++) {
-        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
-    }
-    /* Check that the bit counts in bl_count are consistent. The last code
-     * must be all ones.
-     */
-    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
-            "inconsistent bit counts");
-    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
-
-    for (n = 0;  n <= max_code; n++) {
-        int len = tree[n].Len;
-        if (len == 0) continue;
-        /* Now reverse the bits */
-        tree[n].Code = bi_reverse(next_code[len]++, len);
-
-        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
-             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
-    }
-}
-
-/* ===========================================================================
- * Construct one Huffman tree and assigns the code bit strings and lengths.
- * Update the total bit length for the current block.
- * IN assertion: the field freq is set for all tree elements.
- * OUT assertions: the fields len and code are set to the optimal bit length
- *     and corresponding code. The length opt_len is updated; static_len is
- *     also updated if stree is not null. The field max_code is set.
- */
-local void build_tree(s, desc)
-    deflate_state *s;
-    tree_desc *desc; /* the tree descriptor */
-{
-    ct_data *tree   = desc->dyn_tree;
-    ct_data *stree  = desc->stat_desc->static_tree;
-    int elems       = desc->stat_desc->elems;
-    int n, m;          /* iterate over heap elements */
-    int max_code = -1; /* largest code with non zero frequency */
-    int node;          /* new node being created */
-
-    /* Construct the initial heap, with least frequent element in
-     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
-     * heap[0] is not used.
-     */
-    s->heap_len = 0, s->heap_max = HEAP_SIZE;
-
-    for (n = 0; n < elems; n++) {
-        if (tree[n].Freq != 0) {
-            s->heap[++(s->heap_len)] = max_code = n;
-            s->depth[n] = 0;
-        } else {
-            tree[n].Len = 0;
-        }
-    }
-
-    /* The pkzip format requires that at least one distance code exists,
-     * and that at least one bit should be sent even if there is only one
-     * possible code. So to avoid special checks later on we force at least
-     * two codes of non zero frequency.
-     */
-    while (s->heap_len < 2) {
-        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
-        tree[node].Freq = 1;
-        s->depth[node] = 0;
-        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
-        /* node is 0 or 1 so it does not have extra bits */
-    }
-    desc->max_code = max_code;
-
-    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
-     * establish sub-heaps of increasing lengths:
-     */
-    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
-
-    /* Construct the Huffman tree by repeatedly combining the least two
-     * frequent nodes.
-     */
-    node = elems;              /* next internal node of the tree */
-    do {
-        pqremove(s, tree, n);  /* n = node of least frequency */
-        m = s->heap[SMALLEST]; /* m = node of next least frequency */
-
-        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
-        s->heap[--(s->heap_max)] = m;
-
-        /* Create a new node father of n and m */
-        tree[node].Freq = tree[n].Freq + tree[m].Freq;
-        s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
-        tree[n].Dad = tree[m].Dad = (ush)node;
-#ifdef DUMP_BL_TREE
-        if (tree == s->bl_tree) {
-            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
-                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
-        }
-#endif
-        /* and insert the new node in the heap */
-        s->heap[SMALLEST] = node++;
-        pqdownheap(s, tree, SMALLEST);
-
-    } while (s->heap_len >= 2);
-
-    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
-
-    /* At this point, the fields freq and dad are set. We can now
-     * generate the bit lengths.
-     */
-    gen_bitlen(s, (tree_desc *)desc);
-
-    /* The field len is now set, we can generate the bit codes */
-    gen_codes ((ct_data *)tree, max_code, s->bl_count);
-}
-
-/* ===========================================================================
- * Scan a literal or distance tree to determine the frequencies of the codes
- * in the bit length tree.
- */
-local void scan_tree (s, tree, max_code)
-    deflate_state *s;
-    ct_data *tree;   /* the tree to be scanned */
-    int max_code;    /* and its largest code of non zero frequency */
-{
-    int n;                     /* iterates over all tree elements */
-    int prevlen = -1;          /* last emitted length */
-    int curlen;                /* length of current code */
-    int nextlen = tree[0].Len; /* length of next code */
-    int count = 0;             /* repeat count of the current code */
-    int max_count = 7;         /* max repeat count */
-    int min_count = 4;         /* min repeat count */
-
-    if (nextlen == 0) max_count = 138, min_count = 3;
-    tree[max_code+1].Len = (ush)0xffff; /* guard */
-
-    for (n = 0; n <= max_code; n++) {
-        curlen = nextlen; nextlen = tree[n+1].Len;
-        if (++count < max_count && curlen == nextlen) {
-            continue;
-        } else if (count < min_count) {
-            s->bl_tree[curlen].Freq += count;
-        } else if (curlen != 0) {
-            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
-            s->bl_tree[REP_3_6].Freq++;
-        } else if (count <= 10) {
-            s->bl_tree[REPZ_3_10].Freq++;
-        } else {
-            s->bl_tree[REPZ_11_138].Freq++;
-        }
-        count = 0; prevlen = curlen;
-        if (nextlen == 0) {
-            max_count = 138, min_count = 3;
-        } else if (curlen == nextlen) {
-            max_count = 6, min_count = 3;
-        } else {
-            max_count = 7, min_count = 4;
-        }
-    }
-}
-
-/* ===========================================================================
- * Send a literal or distance tree in compressed form, using the codes in
- * bl_tree.
- */
-local void send_tree (s, tree, max_code)
-    deflate_state *s;
-    ct_data *tree; /* the tree to be scanned */
-    int max_code;       /* and its largest code of non zero frequency */
-{
-    int n;                     /* iterates over all tree elements */
-    int prevlen = -1;          /* last emitted length */
-    int curlen;                /* length of current code */
-    int nextlen = tree[0].Len; /* length of next code */
-    int count = 0;             /* repeat count of the current code */
-    int max_count = 7;         /* max repeat count */
-    int min_count = 4;         /* min repeat count */
-
-    /* tree[max_code+1].Len = -1; */  /* guard already set */
-    if (nextlen == 0) max_count = 138, min_count = 3;
-
-    for (n = 0; n <= max_code; n++) {
-        curlen = nextlen; nextlen = tree[n+1].Len;
-        if (++count < max_count && curlen == nextlen) {
-            continue;
-        } else if (count < min_count) {
-            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
-
-        } else if (curlen != 0) {
-            if (curlen != prevlen) {
-                send_code(s, curlen, s->bl_tree); count--;
-            }
-            Assert(count >= 3 && count <= 6, " 3_6?");
-            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
-
-        } else if (count <= 10) {
-            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
-
-        } else {
-            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
-        }
-        count = 0; prevlen = curlen;
-        if (nextlen == 0) {
-            max_count = 138, min_count = 3;
-        } else if (curlen == nextlen) {
-            max_count = 6, min_count = 3;
-        } else {
-            max_count = 7, min_count = 4;
-        }
-    }
-}
-
-/* ===========================================================================
- * Construct the Huffman tree for the bit lengths and return the index in
- * bl_order of the last bit length code to send.
- */
-local int build_bl_tree(s)
-    deflate_state *s;
-{
-    int max_blindex;  /* index of last bit length code of non zero freq */
-
-    /* Determine the bit length frequencies for literal and distance trees */
-    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
-    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
-
-    /* Build the bit length tree: */
-    build_tree(s, (tree_desc *)(&(s->bl_desc)));
-    /* opt_len now includes the length of the tree representations, except
-     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
-     */
-
-    /* Determine the number of bit length codes to send. The pkzip format
-     * requires that at least 4 bit length codes be sent. (appnote.txt says
-     * 3 but the actual value used is 4.)
-     */
-    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
-        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
-    }
-    /* Update opt_len to include the bit length tree and counts */
-    s->opt_len += 3*(max_blindex+1) + 5+5+4;
-    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
-            s->opt_len, s->static_len));
-
-    return max_blindex;
-}
-
-/* ===========================================================================
- * Send the header for a block using dynamic Huffman trees: the counts, the
- * lengths of the bit length codes, the literal tree and the distance tree.
- * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
- */
-local void send_all_trees(s, lcodes, dcodes, blcodes)
-    deflate_state *s;
-    int lcodes, dcodes, blcodes; /* number of codes for each tree */
-{
-    int rank;                    /* index in bl_order */
-
-    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
-    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
-            "too many codes");
-    Tracev((stderr, "\nbl counts: "));
-    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
-    send_bits(s, dcodes-1,   5);
-    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
-    for (rank = 0; rank < blcodes; rank++) {
-        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
-        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
-    }
-    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
-
-    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
-    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
-
-    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
-    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
-}
-
-/* ===========================================================================
- * Send a stored block
- */
-void _tr_stored_block(s, buf, stored_len, eof)
-    deflate_state *s;
-    charf *buf;       /* input block */
-    ulg stored_len;   /* length of input block */
-    int eof;          /* true if this is the last block for a file */
-{
-    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
-    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
-    s->compressed_len += (stored_len + 4) << 3;
-
-    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
-}
-
-/* Send just the `stored block' type code without any length bytes or data.
- */
-void _tr_stored_type_only(s)
-    deflate_state *s;
-{
-    send_bits(s, (STORED_BLOCK << 1), 3);
-    bi_windup(s);
-    s->compressed_len = (s->compressed_len + 3) & ~7L;
-}
-
-
-/* ===========================================================================
- * Send one empty static block to give enough lookahead for inflate.
- * This takes 10 bits, of which 7 may remain in the bit buffer.
- * The current inflate code requires 9 bits of lookahead. If the
- * last two codes for the previous block (real code plus EOB) were coded
- * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
- * the last real code. In this case we send two empty static blocks instead
- * of one. (There are no problems if the previous block is stored or fixed.)
- * To simplify the code, we assume the worst case of last real code encoded
- * on one bit only.
- */
-void _tr_align(s)
-    deflate_state *s;
-{
-    send_bits(s, STATIC_TREES<<1, 3);
-    send_code(s, END_BLOCK, static_ltree);
-    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
-    bi_flush(s);
-    /* Of the 10 bits for the empty block, we have already sent
-     * (10 - bi_valid) bits. The lookahead for the last real code (before
-     * the EOB of the previous block) was thus at least one plus the length
-     * of the EOB plus what we have just sent of the empty static block.
-     */
-    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
-        send_bits(s, STATIC_TREES<<1, 3);
-        send_code(s, END_BLOCK, static_ltree);
-        s->compressed_len += 10L;
-        bi_flush(s);
-    }
-    s->last_eob_len = 7;
-}
-
-/* ===========================================================================
- * Determine the best encoding for the current block: dynamic trees, static
- * trees or store, and output the encoded block to the zip file. This function
- * returns the total compressed length for the file so far.
- */
-ulg _tr_flush_block(s, buf, stored_len, eof)
-    deflate_state *s;
-    charf *buf;       /* input block, or NULL if too old */
-    ulg stored_len;   /* length of input block */
-    int eof;          /* true if this is the last block for a file */
-{
-    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
-    int max_blindex = 0;  /* index of last bit length code of non zero freq */
-
-    /* Build the Huffman trees unless a stored block is forced */
-    if (s->level > 0) {
-
-	 /* Check if the file is ascii or binary */
-	if (s->data_type == Z_UNKNOWN) set_data_type(s);
-
-	/* Construct the literal and distance trees */
-	build_tree(s, (tree_desc *)(&(s->l_desc)));
-	Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
-		s->static_len));
-
-	build_tree(s, (tree_desc *)(&(s->d_desc)));
-	Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
-		s->static_len));
-	/* At this point, opt_len and static_len are the total bit lengths of
-	 * the compressed block data, excluding the tree representations.
-	 */
-
-	/* Build the bit length tree for the above two trees, and get the index
-	 * in bl_order of the last bit length code to send.
-	 */
-	max_blindex = build_bl_tree(s);
-
-	/* Determine the best encoding. Compute first the block length in bytes*/
-	opt_lenb = (s->opt_len+3+7)>>3;
-	static_lenb = (s->static_len+3+7)>>3;
-
-	Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
-		opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
-		s->last_lit));
-
-	if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
-
-    } else {
-        Assert(buf != (char*)0, "lost buf");
-	opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
-    }
-
-    /* If compression failed and this is the first and last block,
-     * and if the .zip file can be seeked (to rewrite the local header),
-     * the whole file is transformed into a stored file:
-     */
-#ifdef STORED_FILE_OK
-#  ifdef FORCE_STORED_FILE
-    if (eof && s->compressed_len == 0L) { /* force stored file */
-#  else
-    if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) {
-#  endif
-        /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
-        if (buf == (charf*)0) error ("block vanished");
-
-        copy_block(s, buf, (unsigned)stored_len, 0); /* without header */
-        s->compressed_len = stored_len << 3;
-        s->method = STORED;
-    } else
-#endif /* STORED_FILE_OK */
-
-#ifdef FORCE_STORED
-    if (buf != (char*)0) { /* force stored block */
-#else
-    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
-                       /* 4: two words for the lengths */
-#endif
-        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
-         * Otherwise we can't have processed more than WSIZE input bytes since
-         * the last block flush, because compression would have been
-         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
-         * transform a block into a stored block.
-         */
-        _tr_stored_block(s, buf, stored_len, eof);
-
-#ifdef FORCE_STATIC
-    } else if (static_lenb >= 0) { /* force static trees */
-#else
-    } else if (static_lenb == opt_lenb) {
-#endif
-        send_bits(s, (STATIC_TREES<<1)+eof, 3);
-        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
-        s->compressed_len += 3 + s->static_len;
-    } else {
-        send_bits(s, (DYN_TREES<<1)+eof, 3);
-        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
-                       max_blindex+1);
-        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
-        s->compressed_len += 3 + s->opt_len;
-    }
-    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
-    init_block(s);
-
-    if (eof) {
-        bi_windup(s);
-        s->compressed_len += 7;  /* align on byte boundary */
-    }
-    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
-           s->compressed_len-7*eof));
-
-    return s->compressed_len >> 3;
-}
-
-/* ===========================================================================
- * Save the match info and tally the frequency counts. Return true if
- * the current block must be flushed.
- */
-int _tr_tally (s, dist, lc)
-    deflate_state *s;
-    unsigned dist;  /* distance of matched string */
-    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
-{
-    s->d_buf[s->last_lit] = (ush)dist;
-    s->l_buf[s->last_lit++] = (uch)lc;
-    if (dist == 0) {
-        /* lc is the unmatched char */
-        s->dyn_ltree[lc].Freq++;
-    } else {
-        s->matches++;
-        /* Here, lc is the match length - MIN_MATCH */
-        dist--;             /* dist = match distance - 1 */
-        Assert((ush)dist < (ush)MAX_DIST(s) &&
-               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
-               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
-
-        s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
-        s->dyn_dtree[d_code(dist)].Freq++;
-    }
-
-    /* Try to guess if it is profitable to stop the current block here */
-    if (s->level > 2 && (s->last_lit & 0xfff) == 0) {
-        /* Compute an upper bound for the compressed length */
-        ulg out_length = (ulg)s->last_lit*8L;
-        ulg in_length = (ulg)((long)s->strstart - s->block_start);
-        int dcode;
-        for (dcode = 0; dcode < D_CODES; dcode++) {
-            out_length += (ulg)s->dyn_dtree[dcode].Freq *
-                (5L+extra_dbits[dcode]);
-        }
-        out_length >>= 3;
-        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
-               s->last_lit, in_length, out_length,
-               100L - out_length*100L/in_length));
-        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
-    }
-    return (s->last_lit == s->lit_bufsize-1);
-    /* We avoid equality with lit_bufsize because of wraparound at 64K
-     * on 16 bit machines and because stored blocks are restricted to
-     * 64K-1 bytes.
-     */
-}
-
-/* ===========================================================================
- * Send the block data compressed using the given Huffman trees
- */
-local void compress_block(s, ltree, dtree)
-    deflate_state *s;
-    ct_data *ltree; /* literal tree */
-    ct_data *dtree; /* distance tree */
-{
-    unsigned dist;      /* distance of matched string */
-    int lc;             /* match length or unmatched char (if dist == 0) */
-    unsigned lx = 0;    /* running index in l_buf */
-    unsigned code;      /* the code to send */
-    int extra;          /* number of extra bits to send */
-
-    if (s->last_lit != 0) do {
-        dist = s->d_buf[lx];
-        lc = s->l_buf[lx++];
-        if (dist == 0) {
-            send_code(s, lc, ltree); /* send a literal byte */
-            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
-        } else {
-            /* Here, lc is the match length - MIN_MATCH */
-            code = length_code[lc];
-            send_code(s, code+LITERALS+1, ltree); /* send the length code */
-            extra = extra_lbits[code];
-            if (extra != 0) {
-                lc -= base_length[code];
-                send_bits(s, lc, extra);       /* send the extra length bits */
-            }
-            dist--; /* dist is now the match distance - 1 */
-            code = d_code(dist);
-            Assert (code < D_CODES, "bad d_code");
-
-            send_code(s, code, dtree);       /* send the distance code */
-            extra = extra_dbits[code];
-            if (extra != 0) {
-                dist -= base_dist[code];
-                send_bits(s, dist, extra);   /* send the extra distance bits */
-            }
-        } /* literal or match pair ? */
-
-        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
-        Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
-
-    } while (lx < s->last_lit);
-
-    send_code(s, END_BLOCK, ltree);
-    s->last_eob_len = ltree[END_BLOCK].Len;
-}
-
-/* ===========================================================================
- * Set the data type to ASCII or BINARY, using a crude approximation:
- * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
- * IN assertion: the fields freq of dyn_ltree are set and the total of all
- * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
- */
-local void set_data_type(s)
-    deflate_state *s;
-{
-    int n = 0;
-    unsigned ascii_freq = 0;
-    unsigned bin_freq = 0;
-    while (n < 7)        bin_freq += s->dyn_ltree[n++].Freq;
-    while (n < 128)    ascii_freq += s->dyn_ltree[n++].Freq;
-    while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
-    s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
-}
-
-/* ===========================================================================
- * Reverse the first len bits of a code, using straightforward code (a faster
- * method would use a table)
- * IN assertion: 1 <= len <= 15
- */
-local unsigned bi_reverse(code, len)
-    unsigned code; /* the value to invert */
-    int len;       /* its bit length */
-{
-    register unsigned res = 0;
-    do {
-        res |= code & 1;
-        code >>= 1, res <<= 1;
-    } while (--len > 0);
-    return res >> 1;
-}
-
-/* ===========================================================================
- * Flush the bit buffer, keeping at most 7 bits in it.
- */
-local void bi_flush(s)
-    deflate_state *s;
-{
-    if (s->bi_valid == 16) {
-        put_short(s, s->bi_buf);
-        s->bi_buf = 0;
-        s->bi_valid = 0;
-    } else if (s->bi_valid >= 8) {
-        put_byte(s, (Byte)s->bi_buf);
-        s->bi_buf >>= 8;
-        s->bi_valid -= 8;
-    }
-}
-
-/* ===========================================================================
- * Flush the bit buffer and align the output on a byte boundary
- */
-local void bi_windup(s)
-    deflate_state *s;
-{
-    if (s->bi_valid > 8) {
-        put_short(s, s->bi_buf);
-    } else if (s->bi_valid > 0) {
-        put_byte(s, (Byte)s->bi_buf);
-    }
-    s->bi_buf = 0;
-    s->bi_valid = 0;
-#ifdef DEBUG_ZLIB
-    s->bits_sent = (s->bits_sent+7) & ~7;
-#endif
-}
-
-/* ===========================================================================
- * Copy a stored block, storing first the length and its
- * one's complement if requested.
- */
-local void copy_block(s, buf, len, header)
-    deflate_state *s;
-    charf    *buf;    /* the input data */
-    unsigned len;     /* its length */
-    int      header;  /* true if block header must be written */
-{
-    bi_windup(s);        /* align on byte boundary */
-    s->last_eob_len = 8; /* enough lookahead for inflate */
-
-    if (header) {
-        put_short(s, (ush)len);   
-        put_short(s, (ush)~len);
-#ifdef DEBUG_ZLIB
-        s->bits_sent += 2*16;
-#endif
-    }
-#ifdef DEBUG_ZLIB
-    s->bits_sent += (ulg)len<<3;
-#endif
-    /* bundle up the put_byte(s, *buf++) calls */
-    zmemcpy(&s->pending_buf[s->pending], buf, len);
-    s->pending += len;
-}
-/* --- trees.c */
-
-/* +++ inflate.c */
-/* inflate.c -- zlib interface to inflate modules
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-
-/* +++ infblock.h */
-/* infblock.h -- header to use infblock.c
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-struct inflate_blocks_state;
-typedef struct inflate_blocks_state FAR inflate_blocks_statef;
-
-extern inflate_blocks_statef * inflate_blocks_new OF((
-    z_streamp z,
-    check_func c,               /* check function */
-    uInt w));                   /* window size */
-
-extern int inflate_blocks OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));                      /* initial return code */
-
-extern void inflate_blocks_reset OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    uLongf *));                  /* check value on output */
-
-extern int inflate_blocks_free OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    uLongf *));                  /* check value on output */
-
-extern void inflate_set_dictionary OF((
-    inflate_blocks_statef *s,
-    const Bytef *d,  /* dictionary */
-    uInt  n));       /* dictionary length */
-
-extern int inflate_addhistory OF((
-    inflate_blocks_statef *,
-    z_streamp));
-
-extern int inflate_packet_flush OF((
-    inflate_blocks_statef *));
-/* --- infblock.h */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* inflate private state */
-struct internal_state {
-
-  /* mode */
-  enum {
-      METHOD,   /* waiting for method byte */
-      FLAG,     /* waiting for flag byte */
-      DICT4,    /* four dictionary check bytes to go */
-      DICT3,    /* three dictionary check bytes to go */
-      DICT2,    /* two dictionary check bytes to go */
-      DICT1,    /* one dictionary check byte to go */
-      DICT0,    /* waiting for inflateSetDictionary */
-      BLOCKS,   /* decompressing blocks */
-      CHECK4,   /* four check bytes to go */
-      CHECK3,   /* three check bytes to go */
-      CHECK2,   /* two check bytes to go */
-      CHECK1,   /* one check byte to go */
-      DONE,     /* finished check, done */
-      BAD}      /* got an error--stay here */
-    mode;               /* current inflate mode */
-
-  /* mode dependent information */
-  union {
-    uInt method;        /* if FLAGS, method byte */
-    struct {
-      uLong was;                /* computed check value */
-      uLong need;               /* stream check value */
-    } check;            /* if CHECK, check values to compare */
-    uInt marker;        /* if BAD, inflateSync's marker bytes count */
-  } sub;        /* submode */
-
-  /* mode independent information */
-  int  nowrap;          /* flag for no wrapper */
-  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
-  inflate_blocks_statef 
-    *blocks;            /* current inflate_blocks state */
-
-};
-
-
-int inflateReset(z)
-z_streamp z;
-{
-  uLong c;
-
-  if (z == Z_NULL || z->state == Z_NULL)
-    return Z_STREAM_ERROR;
-  z->total_in = z->total_out = 0;
-  z->msg = Z_NULL;
-  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
-  inflate_blocks_reset(z->state->blocks, z, &c);
-  Trace((stderr, "inflate: reset\n"));
-  return Z_OK;
-}
-
-
-int inflateEnd(z)
-z_streamp z;
-{
-  uLong c;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
-    return Z_STREAM_ERROR;
-  if (z->state->blocks != Z_NULL)
-    inflate_blocks_free(z->state->blocks, z, &c);
-  ZFREE(z, z->state);
-  z->state = Z_NULL;
-  Trace((stderr, "inflate: end\n"));
-  return Z_OK;
-}
-
-
-int inflateInit2_(z, w, version, stream_size)
-z_streamp z;
-int w;
-const char *version;
-int stream_size;
-{
-  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
-      stream_size != sizeof(z_stream))
-      return Z_VERSION_ERROR;
-
-  /* initialize state */
-  if (z == Z_NULL)
-    return Z_STREAM_ERROR;
-  z->msg = Z_NULL;
-#ifndef NO_ZCFUNCS
-  if (z->zalloc == Z_NULL)
-  {
-    z->zalloc = zcalloc;
-    z->opaque = (voidpf)0;
-  }
-  if (z->zfree == Z_NULL) z->zfree = zcfree;
-#endif
-  if ((z->state = (struct internal_state FAR *)
-       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
-    return Z_MEM_ERROR;
-  z->state->blocks = Z_NULL;
-
-  /* handle undocumented nowrap option (no zlib header or check) */
-  z->state->nowrap = 0;
-  if (w < 0)
-  {
-    w = - w;
-    z->state->nowrap = 1;
-  }
-
-  /* set window size */
-  if (w < 8 || w > 15)
-  {
-    inflateEnd(z);
-    return Z_STREAM_ERROR;
-  }
-  z->state->wbits = (uInt)w;
-
-  /* create inflate_blocks state */
-  if ((z->state->blocks =
-      inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
-      == Z_NULL)
-  {
-    inflateEnd(z);
-    return Z_MEM_ERROR;
-  }
-  Trace((stderr, "inflate: allocated\n"));
-
-  /* reset state */
-  inflateReset(z);
-  return Z_OK;
-}
-
-
-int inflateInit_(z, version, stream_size)
-z_streamp z;
-const char *version;
-int stream_size;
-{
-  return inflateInit2_(z, DEF_WBITS, version, stream_size);
-}
-
-
-#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
-#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
-
-int inflate(z, f)
-z_streamp z;
-int f;
-{
-  int r;
-  uInt b;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0)
-    return Z_STREAM_ERROR;
-  r = Z_BUF_ERROR;
-  while (1) switch (z->state->mode)
-  {
-    case METHOD:
-      NEEDBYTE
-      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"unknown compression method";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"invalid window size";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      z->state->mode = FLAG;
-    case FLAG:
-      NEEDBYTE
-      b = NEXTBYTE;
-      if (((z->state->sub.method << 8) + b) % 31)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"incorrect header check";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      Trace((stderr, "inflate: zlib header ok\n"));
-      if (!(b & PRESET_DICT))
-      {
-        z->state->mode = BLOCKS;
-	break;
-      }
-      z->state->mode = DICT4;
-    case DICT4:
-      NEEDBYTE
-      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-      z->state->mode = DICT3;
-    case DICT3:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-      z->state->mode = DICT2;
-    case DICT2:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-      z->state->mode = DICT1;
-    case DICT1:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE;
-      z->adler = z->state->sub.check.need;
-      z->state->mode = DICT0;
-      return Z_NEED_DICT;
-    case DICT0:
-      z->state->mode = BAD;
-      z->msg = (char*)"need dictionary";
-      z->state->sub.marker = 0;       /* can try inflateSync */
-      return Z_STREAM_ERROR;
-    case BLOCKS:
-      r = inflate_blocks(z->state->blocks, z, r);
-      if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
-	  r = inflate_packet_flush(z->state->blocks);
-      if (r == Z_DATA_ERROR)
-      {
-        z->state->mode = BAD;
-        z->state->sub.marker = 0;       /* can try inflateSync */
-        break;
-      }
-      if (r != Z_STREAM_END)
-        return r;
-      r = Z_OK;
-      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
-      if (z->state->nowrap)
-      {
-        z->state->mode = DONE;
-        break;
-      }
-      z->state->mode = CHECK4;
-    case CHECK4:
-      NEEDBYTE
-      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-      z->state->mode = CHECK3;
-    case CHECK3:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-      z->state->mode = CHECK2;
-    case CHECK2:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-      z->state->mode = CHECK1;
-    case CHECK1:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE;
-
-      if (z->state->sub.check.was != z->state->sub.check.need)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"incorrect data check";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      Trace((stderr, "inflate: zlib check ok\n"));
-      z->state->mode = DONE;
-    case DONE:
-      return Z_STREAM_END;
-    case BAD:
-      return Z_DATA_ERROR;
-    default:
-      return Z_STREAM_ERROR;
-  }
-
- empty:
-  if (f != Z_PACKET_FLUSH)
-    return r;
-  z->state->mode = BAD;
-  z->msg = (char *)"need more for packet flush";
-  z->state->sub.marker = 0;       /* can try inflateSync */
-  return Z_DATA_ERROR;
-}
-
-
-int inflateSetDictionary(z, dictionary, dictLength)
-z_streamp z;
-const Bytef *dictionary;
-uInt  dictLength;
-{
-  uInt length = dictLength;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
-    return Z_STREAM_ERROR;
-
-  if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
-  z->adler = 1L;
-
-  if (length >= ((uInt)1<<z->state->wbits))
-  {
-    length = (1<<z->state->wbits)-1;
-    dictionary += dictLength - length;
-  }
-  inflate_set_dictionary(z->state->blocks, dictionary, length);
-  z->state->mode = BLOCKS;
-  return Z_OK;
-}
-
-/*
- * This subroutine adds the data at next_in/avail_in to the output history
- * without performing any output.  The output buffer must be "caught up";
- * i.e. no pending output (hence s->read equals s->write), and the state must
- * be BLOCKS (i.e. we should be willing to see the start of a series of
- * BLOCKS).  On exit, the output will also be caught up, and the checksum
- * will have been updated if need be.
- */
-
-int inflateIncomp(z)
-z_stream *z;
-{
-    if (z->state->mode != BLOCKS)
-	return Z_DATA_ERROR;
-    return inflate_addhistory(z->state->blocks, z);
-}
-
-
-int inflateSync(z)
-z_streamp z;
-{
-  uInt n;       /* number of bytes to look at */
-  Bytef *p;     /* pointer to bytes */
-  uInt m;       /* number of marker bytes found in a row */
-  uLong r, w;   /* temporaries to save total_in and total_out */
-
-  /* set up */
-  if (z == Z_NULL || z->state == Z_NULL)
-    return Z_STREAM_ERROR;
-  if (z->state->mode != BAD)
-  {
-    z->state->mode = BAD;
-    z->state->sub.marker = 0;
-  }
-  if ((n = z->avail_in) == 0)
-    return Z_BUF_ERROR;
-  p = z->next_in;
-  m = z->state->sub.marker;
-
-  /* search */
-  while (n && m < 4)
-  {
-    if (*p == (Byte)(m < 2 ? 0 : 0xff))
-      m++;
-    else if (*p)
-      m = 0;
-    else
-      m = 4 - m;
-    p++, n--;
-  }
-
-  /* restore */
-  z->total_in += p - z->next_in;
-  z->next_in = p;
-  z->avail_in = n;
-  z->state->sub.marker = m;
-
-  /* return no joy or set up to restart on a new block */
-  if (m != 4)
-    return Z_DATA_ERROR;
-  r = z->total_in;  w = z->total_out;
-  inflateReset(z);
-  z->total_in = r;  z->total_out = w;
-  z->state->mode = BLOCKS;
-  return Z_OK;
-}
-
-#undef NEEDBYTE
-#undef NEXTBYTE
-/* --- inflate.c */
-
-/* +++ infblock.c */
-/* infblock.c -- interpret and process block types to last block
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "infblock.h" */
-
-/* +++ inftrees.h */
-/* inftrees.h -- header to use inftrees.c
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-/* Huffman code lookup table entry--this entry is four bytes for machines
-   that have 16-bit pointers (e.g. PC's in the small or medium model). */
-
-typedef struct inflate_huft_s FAR inflate_huft;
-
-struct inflate_huft_s {
-  union {
-    struct {
-      Byte Exop;        /* number of extra bits or operation */
-      Byte Bits;        /* number of bits in this code or subcode */
-    } what;
-    Bytef *pad;         /* pad structure to a power of 2 (4 bytes for */
-  } word;               /*  16-bit, 8 bytes for 32-bit machines) */
-  union {
-    uInt Base;          /* literal, length base, or distance base */
-    inflate_huft *Next; /* pointer to next level of table */
-  } more;
-};
-
-#ifdef DEBUG_ZLIB
-  extern uInt inflate_hufts;
-#endif
-
-extern int inflate_trees_bits OF((
-    uIntf *,                    /* 19 code lengths */
-    uIntf *,                    /* bits tree desired/actual depth */
-    inflate_huft * FAR *,       /* bits tree result */
-    z_streamp ));               /* for zalloc, zfree functions */
-
-extern int inflate_trees_dynamic OF((
-    uInt,                       /* number of literal/length codes */
-    uInt,                       /* number of distance codes */
-    uIntf *,                    /* that many (total) code lengths */
-    uIntf *,                    /* literal desired/actual bit depth */
-    uIntf *,                    /* distance desired/actual bit depth */
-    inflate_huft * FAR *,       /* literal/length tree result */
-    inflate_huft * FAR *,       /* distance tree result */
-    z_streamp ));               /* for zalloc, zfree functions */
-
-extern int inflate_trees_fixed OF((
-    uIntf *,                    /* literal desired/actual bit depth */
-    uIntf *,                    /* distance desired/actual bit depth */
-    inflate_huft * FAR *,       /* literal/length tree result */
-    inflate_huft * FAR *));     /* distance tree result */
-
-extern int inflate_trees_free OF((
-    inflate_huft *,             /* tables to free */
-    z_streamp ));               /* for zfree function */
-
-/* --- inftrees.h */
-
-/* +++ infcodes.h */
-/* infcodes.h -- header to use infcodes.c
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-struct inflate_codes_state;
-typedef struct inflate_codes_state FAR inflate_codes_statef;
-
-extern inflate_codes_statef *inflate_codes_new OF((
-    uInt, uInt,
-    inflate_huft *, inflate_huft *,
-    z_streamp ));
-
-extern int inflate_codes OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));
-
-extern void inflate_codes_free OF((
-    inflate_codes_statef *,
-    z_streamp ));
-
-/* --- infcodes.h */
-
-/* +++ infutil.h */
-/* infutil.h -- types and macros common to blocks and codes
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-#ifndef _INFUTIL_H
-#define _INFUTIL_H
-
-typedef enum {
-      TYPE,     /* get type bits (3, including end bit) */
-      LENS,     /* get lengths for stored */
-      STORED,   /* processing stored block */
-      TABLE,    /* get table lengths */
-      BTREE,    /* get bit lengths tree for a dynamic block */
-      DTREE,    /* get length, distance trees for a dynamic block */
-      CODES,    /* processing fixed or dynamic block */
-      DRY,      /* output remaining window bytes */
-      DONEB,    /* finished last block, done */
-      BADB}     /* got a data error--stuck here */
-inflate_block_mode;
-
-/* inflate blocks semi-private state */
-struct inflate_blocks_state {
-
-  /* mode */
-  inflate_block_mode  mode;     /* current inflate_block mode */
-
-  /* mode dependent information */
-  union {
-    uInt left;          /* if STORED, bytes left to copy */
-    struct {
-      uInt table;               /* table lengths (14 bits) */
-      uInt index;               /* index into blens (or border) */
-      uIntf *blens;             /* bit lengths of codes */
-      uInt bb;                  /* bit length tree depth */
-      inflate_huft *tb;         /* bit length decoding tree */
-    } trees;            /* if DTREE, decoding info for trees */
-    struct {
-      inflate_huft *tl;
-      inflate_huft *td;         /* trees to free */
-      inflate_codes_statef 
-         *codes;
-    } decode;           /* if CODES, current state */
-  } sub;                /* submode */
-  uInt last;            /* true if this block is the last block */
-
-  /* mode independent information */
-  uInt bitk;            /* bits in bit buffer */
-  uLong bitb;           /* bit buffer */
-  Bytef *window;        /* sliding window */
-  Bytef *end;           /* one byte after sliding window */
-  Bytef *read;          /* window read pointer */
-  Bytef *write;         /* window write pointer */
-  check_func checkfn;   /* check function */
-  uLong check;          /* check on output */
-
-};
-
-
-/* defines for inflate input/output */
-/*   update pointers and return */
-#define UPDBITS {s->bitb=b;s->bitk=k;}
-#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
-#define UPDOUT {s->write=q;}
-#define UPDATE {UPDBITS UPDIN UPDOUT}
-#define LEAVE {UPDATE return inflate_flush(s,z,r);}
-/*   get bytes and bits */
-#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
-#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
-#define NEXTBYTE (n--,*p++)
-#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-#define DUMPBITS(j) {b>>=(j);k-=(j);}
-/*   output bytes */
-#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
-#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
-#define WWRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
-#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
-#define NEEDOUT {if(m==0){WWRAP if(m==0){FLUSH WWRAP if(m==0) LEAVE}}r=Z_OK;}
-#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
-/*   load local pointers */
-#define LOAD {LOADIN LOADOUT}
-
-/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
-extern uInt inflate_mask[17];
-
-/* copy as much as possible from the sliding window to the output area */
-extern int inflate_flush OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));
-
-#ifndef NO_DUMMY_DECL
-struct internal_state      {int dummy;}; /* for buggy compilers */
-#endif
-
-#endif
-/* --- infutil.h */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* Table for deflate from PKZIP's appnote.txt. */
-local const uInt border[] = { /* Order of the bit length code lengths */
-        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-
-/*
-   Notes beyond the 1.93a appnote.txt:
-
-   1. Distance pointers never point before the beginning of the output
-      stream.
-   2. Distance pointers can point back across blocks, up to 32k away.
-   3. There is an implied maximum of 7 bits for the bit length table and
-      15 bits for the actual data.
-   4. If only one code exists, then it is encoded using one bit.  (Zero
-      would be more efficient, but perhaps a little confusing.)  If two
-      codes exist, they are coded using one bit each (0 and 1).
-   5. There is no way of sending zero distance codes--a dummy must be
-      sent if there are none.  (History: a pre 2.0 version of PKZIP would
-      store blocks with no distance codes, but this was discovered to be
-      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
-      zero distance codes, which is sent as one code of zero bits in
-      length.
-   6. There are up to 286 literal/length codes.  Code 256 represents the
-      end-of-block.  Note however that the static length tree defines
-      288 codes just to fill out the Huffman codes.  Codes 286 and 287
-      cannot be used though, since there is no length base or extra bits
-      defined for them.  Similarily, there are up to 30 distance codes.
-      However, static trees define 32 codes (all 5 bits) to fill out the
-      Huffman codes, but the last two had better not show up in the data.
-   7. Unzip can check dynamic Huffman blocks for complete code sets.
-      The exception is that a single code would not be complete (see #4).
-   8. The five bits following the block type is really the number of
-      literal codes sent minus 257.
-   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
-      (1+6+6).  Therefore, to output three times the length, you output
-      three codes (1+1+1), whereas to output four times the same length,
-      you only need two codes (1+3).  Hmm.
-  10. In the tree reconstruction algorithm, Code = Code + Increment
-      only if BitLength(i) is not zero.  (Pretty obvious.)
-  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
-  12. Note: length code 284 can represent 227-258, but length code 285
-      really is 258.  The last length deserves its own, short code
-      since it gets used a lot in very redundant files.  The length
-      258 is special since 258 - 3 (the min match length) is 255.
-  13. The literal/length and distance code bit lengths are read as a
-      single stream of lengths.  It is possible (and advantageous) for
-      a repeat code (16, 17, or 18) to go across the boundary between
-      the two sets of lengths.
- */
-
-
-void inflate_blocks_reset(s, z, c)
-inflate_blocks_statef *s;
-z_streamp z;
-uLongf *c;
-{
-  if (s->checkfn != Z_NULL)
-    *c = s->check;
-  if (s->mode == BTREE || s->mode == DTREE)
-    ZFREE(z, s->sub.trees.blens);
-  if (s->mode == CODES)
-  {
-    inflate_codes_free(s->sub.decode.codes, z);
-    inflate_trees_free(s->sub.decode.td, z);
-    inflate_trees_free(s->sub.decode.tl, z);
-  }
-  s->mode = TYPE;
-  s->bitk = 0;
-  s->bitb = 0;
-  s->read = s->write = s->window;
-  if (s->checkfn != Z_NULL)
-    z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0);
-  Trace((stderr, "inflate:   blocks reset\n"));
-}
-
-
-inflate_blocks_statef *inflate_blocks_new(z, c, w)
-z_streamp z;
-check_func c;
-uInt w;
-{
-  inflate_blocks_statef *s;
-
-  if ((s = (inflate_blocks_statef *)ZALLOC
-       (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
-    return s;
-  if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
-  {
-    ZFREE(z, s);
-    return Z_NULL;
-  }
-  s->end = s->window + w;
-  s->checkfn = c;
-  s->mode = TYPE;
-  Trace((stderr, "inflate:   blocks allocated\n"));
-  inflate_blocks_reset(s, z, &s->check);
-  return s;
-}
-
-
-#ifdef DEBUG_ZLIB
-  extern uInt inflate_hufts;
-#endif
-int inflate_blocks(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt t;               /* temporary storage */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Bytef *p;             /* input data pointer */
-  uInt n;               /* bytes available there */
-  Bytef *q;             /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-
-  /* copy input/output information to locals (UPDATE macro restores) */
-  LOAD
-
-  /* process input based on current state */
-  while (1) switch (s->mode)
-  {
-    case TYPE:
-      NEEDBITS(3)
-      t = (uInt)b & 7;
-      s->last = t & 1;
-      switch (t >> 1)
-      {
-        case 0:                         /* stored */
-          Trace((stderr, "inflate:     stored block%s\n",
-                 s->last ? " (last)" : ""));
-          DUMPBITS(3)
-          t = k & 7;                    /* go to byte boundary */
-          DUMPBITS(t)
-          s->mode = LENS;               /* get length of stored block */
-          break;
-        case 1:                         /* fixed */
-          Trace((stderr, "inflate:     fixed codes block%s\n",
-                 s->last ? " (last)" : ""));
-          {
-            uInt bl, bd;
-            inflate_huft *tl, *td;
-
-            inflate_trees_fixed(&bl, &bd, &tl, &td);
-            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
-            if (s->sub.decode.codes == Z_NULL)
-            {
-              r = Z_MEM_ERROR;
-              LEAVE
-            }
-            s->sub.decode.tl = Z_NULL;  /* don't try to free these */
-            s->sub.decode.td = Z_NULL;
-          }
-          DUMPBITS(3)
-          s->mode = CODES;
-          break;
-        case 2:                         /* dynamic */
-          Trace((stderr, "inflate:     dynamic codes block%s\n",
-                 s->last ? " (last)" : ""));
-          DUMPBITS(3)
-          s->mode = TABLE;
-          break;
-        case 3:                         /* illegal */
-          DUMPBITS(3)
-          s->mode = BADB;
-          z->msg = (char*)"invalid block type";
-          r = Z_DATA_ERROR;
-          LEAVE
-      }
-      break;
-    case LENS:
-      NEEDBITS(32)
-      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
-      {
-        s->mode = BADB;
-        z->msg = (char*)"invalid stored block lengths";
-        r = Z_DATA_ERROR;
-        LEAVE
-      }
-      s->sub.left = (uInt)b & 0xffff;
-      b = k = 0;                      /* dump bits */
-      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
-      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
-      break;
-    case STORED:
-      if (n == 0)
-        LEAVE
-      NEEDOUT
-      t = s->sub.left;
-      if (t > n) t = n;
-      if (t > m) t = m;
-      zmemcpy(q, p, t);
-      p += t;  n -= t;
-      q += t;  m -= t;
-      if ((s->sub.left -= t) != 0)
-        break;
-      Tracev((stderr, "inflate:       stored end, %lu total out\n",
-              z->total_out + (q >= s->read ? q - s->read :
-              (s->end - s->read) + (q - s->window))));
-      s->mode = s->last ? DRY : TYPE;
-      break;
-    case TABLE:
-      NEEDBITS(14)
-      s->sub.trees.table = t = (uInt)b & 0x3fff;
-#ifndef PKZIP_BUG_WORKAROUND
-      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
-      {
-        s->mode = BADB;
-        z->msg = (char*)"too many length or distance symbols";
-        r = Z_DATA_ERROR;
-        LEAVE
-      }
-#endif
-      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
-      if (t < 19)
-        t = 19;
-      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
-      {
-        r = Z_MEM_ERROR;
-        LEAVE
-      }
-      DUMPBITS(14)
-      s->sub.trees.index = 0;
-      Tracev((stderr, "inflate:       table sizes ok\n"));
-      s->mode = BTREE;
-    case BTREE:
-      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
-      {
-        NEEDBITS(3)
-        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
-        DUMPBITS(3)
-      }
-      while (s->sub.trees.index < 19)
-        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
-      s->sub.trees.bb = 7;
-      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
-                             &s->sub.trees.tb, z);
-      if (t != Z_OK)
-      {
-        r = t;
-        if (r == Z_DATA_ERROR)
-	{
-	  ZFREE(z, s->sub.trees.blens);
-          s->mode = BADB;
-	}
-        LEAVE
-      }
-      s->sub.trees.index = 0;
-      Tracev((stderr, "inflate:       bits tree ok\n"));
-      s->mode = DTREE;
-    case DTREE:
-      while (t = s->sub.trees.table,
-             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
-      {
-        inflate_huft *h;
-        uInt i, j, c;
-
-        t = s->sub.trees.bb;
-        NEEDBITS(t)
-        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
-        t = h->word.what.Bits;
-        c = h->more.Base;
-        if (c < 16)
-        {
-          DUMPBITS(t)
-          s->sub.trees.blens[s->sub.trees.index++] = c;
-        }
-        else /* c == 16..18 */
-        {
-          i = c == 18 ? 7 : c - 14;
-          j = c == 18 ? 11 : 3;
-          NEEDBITS(t + i)
-          DUMPBITS(t)
-          j += (uInt)b & inflate_mask[i];
-          DUMPBITS(i)
-          i = s->sub.trees.index;
-          t = s->sub.trees.table;
-          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
-              (c == 16 && i < 1))
-          {
-            inflate_trees_free(s->sub.trees.tb, z);
-            ZFREE(z, s->sub.trees.blens);
-            s->mode = BADB;
-            z->msg = (char*)"invalid bit length repeat";
-            r = Z_DATA_ERROR;
-            LEAVE
-          }
-          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
-          do {
-            s->sub.trees.blens[i++] = c;
-          } while (--j);
-          s->sub.trees.index = i;
-        }
-      }
-      inflate_trees_free(s->sub.trees.tb, z);
-      s->sub.trees.tb = Z_NULL;
-      {
-        uInt bl, bd;
-        inflate_huft *tl, *td;
-        inflate_codes_statef *c;
-
-        bl = 9;         /* must be <= 9 for lookahead assumptions */
-        bd = 6;         /* must be <= 9 for lookahead assumptions */
-        t = s->sub.trees.table;
-#ifdef DEBUG_ZLIB
-      inflate_hufts = 0;
-#endif
-        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
-                                  s->sub.trees.blens, &bl, &bd, &tl, &td, z);
-        if (t != Z_OK)
-        {
-          if (t == (uInt)Z_DATA_ERROR)
-	  {
-	    ZFREE(z, s->sub.trees.blens);
-            s->mode = BADB;
-	  }
-          r = t;
-          LEAVE
-        }
-        Tracev((stderr, "inflate:       trees ok, %d * %d bytes used\n",
-              inflate_hufts, sizeof(inflate_huft)));
-        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
-        {
-          inflate_trees_free(td, z);
-          inflate_trees_free(tl, z);
-          r = Z_MEM_ERROR;
-          LEAVE
-        }
-        ZFREE(z, s->sub.trees.blens);
-        s->sub.decode.codes = c;
-        s->sub.decode.tl = tl;
-        s->sub.decode.td = td;
-      }
-      s->mode = CODES;
-    case CODES:
-      UPDATE
-      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
-        return inflate_flush(s, z, r);
-      r = Z_OK;
-      inflate_codes_free(s->sub.decode.codes, z);
-      inflate_trees_free(s->sub.decode.td, z);
-      inflate_trees_free(s->sub.decode.tl, z);
-      LOAD
-      Tracev((stderr, "inflate:       codes end, %lu total out\n",
-              z->total_out + (q >= s->read ? q - s->read :
-              (s->end - s->read) + (q - s->window))));
-      if (!s->last)
-      {
-        s->mode = TYPE;
-        break;
-      }
-      if (k > 7)              /* return unused byte, if any */
-      {
-        Assert(k < 16, "inflate_codes grabbed too many bytes")
-        k -= 8;
-        n++;
-        p--;                    /* can always return one */
-      }
-      s->mode = DRY;
-    case DRY:
-      FLUSH
-      if (s->read != s->write)
-        LEAVE
-      s->mode = DONEB;
-    case DONEB:
-      r = Z_STREAM_END;
-      LEAVE
-    case BADB:
-      r = Z_DATA_ERROR;
-      LEAVE
-    default:
-      r = Z_STREAM_ERROR;
-      LEAVE
-  }
-}
-
-
-int inflate_blocks_free(s, z, c)
-inflate_blocks_statef *s;
-z_streamp z;
-uLongf *c;
-{
-  inflate_blocks_reset(s, z, c);
-  ZFREE(z, s->window);
-  ZFREE(z, s);
-  Trace((stderr, "inflate:   blocks freed\n"));
-  return Z_OK;
-}
-
-
-void inflate_set_dictionary(s, d, n)
-inflate_blocks_statef *s;
-const Bytef *d;
-uInt  n;
-{
-  zmemcpy((charf *)s->window, d, n);
-  s->read = s->write = s->window + n;
-}
-
-/*
- * This subroutine adds the data at next_in/avail_in to the output history
- * without performing any output.  The output buffer must be "caught up";
- * i.e. no pending output (hence s->read equals s->write), and the state must
- * be BLOCKS (i.e. we should be willing to see the start of a series of
- * BLOCKS).  On exit, the output will also be caught up, and the checksum
- * will have been updated if need be.
- */
-int inflate_addhistory(s, z)
-inflate_blocks_statef *s;
-z_stream *z;
-{
-    uLong b;              /* bit buffer */  /* NOT USED HERE */
-    uInt k;               /* bits in bit buffer */ /* NOT USED HERE */
-    uInt t;               /* temporary storage */
-    Bytef *p;             /* input data pointer */
-    uInt n;               /* bytes available there */
-    Bytef *q;             /* output window write pointer */
-    uInt m;               /* bytes to end of window or read pointer */
-
-    if (s->read != s->write)
-	return Z_STREAM_ERROR;
-    if (s->mode != TYPE)
-	return Z_DATA_ERROR;
-
-    /* we're ready to rock */
-    LOAD
-    /* while there is input ready, copy to output buffer, moving
-     * pointers as needed.
-     */
-    while (n) {
-	t = n;  /* how many to do */
-	/* is there room until end of buffer? */
-	if (t > m) t = m;
-	/* update check information */
-	if (s->checkfn != Z_NULL)
-	    s->check = (*s->checkfn)(s->check, q, t);
-	zmemcpy(q, p, t);
-	q += t;
-	p += t;
-	n -= t;
-	z->total_out += t;
-	s->read = q;    /* drag read pointer forward */
-/*      WWRAP  */ 	/* expand WWRAP macro by hand to handle s->read */
-	if (q == s->end) {
-	    s->read = q = s->window;
-	    m = WAVAIL;
-	}
-    }
-    UPDATE
-    return Z_OK;
-}
-
-
-/*
- * At the end of a Deflate-compressed PPP packet, we expect to have seen
- * a `stored' block type value but not the (zero) length bytes.
- */
-int inflate_packet_flush(s)
-    inflate_blocks_statef *s;
-{
-    if (s->mode != LENS)
-	return Z_DATA_ERROR;
-    s->mode = TYPE;
-    return Z_OK;
-}
-/* --- infblock.c */
-
-/* +++ inftrees.c */
-/* inftrees.c -- generate Huffman trees for efficient decoding
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-
-char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler ";
-/*
-  If you use the zlib library in a product, an acknowledgment is welcome
-  in the documentation of your product. If for some reason you cannot
-  include such an acknowledgment, I would appreciate that you keep this
-  copyright string in the executable of your product.
- */
-
-#ifndef NO_DUMMY_DECL
-struct internal_state  {int dummy;}; /* for buggy compilers */
-#endif
-
-/* simplify the use of the inflate_huft type with some defines */
-#define base more.Base
-#define next more.Next
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-
-local int huft_build OF((
-    uIntf *,            /* code lengths in bits */
-    uInt,               /* number of codes */
-    uInt,               /* number of "simple" codes */
-    const uIntf *,      /* list of base values for non-simple codes */
-    const uIntf *,      /* list of extra bits for non-simple codes */
-    inflate_huft * FAR*,/* result: starting table */
-    uIntf *,            /* maximum lookup bits (returns actual) */
-    z_streamp ));       /* for zalloc function */
-
-local voidpf falloc OF((
-    voidpf,             /* opaque pointer (not used) */
-    uInt,               /* number of items */
-    uInt));             /* size of item */
-
-/* Tables for deflate from PKZIP's appnote.txt. */
-local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
-        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
-        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
-        /* see note #13 above about 258 */
-local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
-        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
-        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
-local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
-        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
-        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
-        8193, 12289, 16385, 24577};
-local const uInt cpdext[30] = { /* Extra bits for distance codes */
-        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
-        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
-        12, 12, 13, 13};
-
-/*
-   Huffman code decoding is performed using a multi-level table lookup.
-   The fastest way to decode is to simply build a lookup table whose
-   size is determined by the longest code.  However, the time it takes
-   to build this table can also be a factor if the data being decoded
-   is not very long.  The most common codes are necessarily the
-   shortest codes, so those codes dominate the decoding time, and hence
-   the speed.  The idea is you can have a shorter table that decodes the
-   shorter, more probable codes, and then point to subsidiary tables for
-   the longer codes.  The time it costs to decode the longer codes is
-   then traded against the time it takes to make longer tables.
-
-   This results of this trade are in the variables lbits and dbits
-   below.  lbits is the number of bits the first level table for literal/
-   length codes can decode in one step, and dbits is the same thing for
-   the distance codes.  Subsequent tables are also less than or equal to
-   those sizes.  These values may be adjusted either when all of the
-   codes are shorter than that, in which case the longest code length in
-   bits is used, or when the shortest code is *longer* than the requested
-   table size, in which case the length of the shortest code in bits is
-   used.
-
-   There are two different values for the two tables, since they code a
-   different number of possibilities each.  The literal/length table
-   codes 286 possible values, or in a flat code, a little over eight
-   bits.  The distance table codes 30 possible values, or a little less
-   than five bits, flat.  The optimum values for speed end up being
-   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
-   The optimum values may differ though from machine to machine, and
-   possibly even between compilers.  Your mileage may vary.
- */
-
-
-/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
-#define BMAX 15         /* maximum bit length of any code */
-#define N_MAX 288       /* maximum number of codes in any set */
-
-#ifdef DEBUG_ZLIB
-  uInt inflate_hufts;
-#endif
-
-local int huft_build(b, n, s, d, e, t, m, zs)
-uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
-uInt n;                 /* number of codes (assumed <= N_MAX) */
-uInt s;                 /* number of simple-valued codes (0..s-1) */
-const uIntf *d;         /* list of base values for non-simple codes */
-const uIntf *e;         /* list of extra bits for non-simple codes */
-inflate_huft * FAR *t;  /* result: starting table */
-uIntf *m;               /* maximum lookup bits, returns actual */
-z_streamp zs;           /* for zalloc function */
-/* Given a list of code lengths and a maximum table size, make a set of
-   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
-   if the given code set is incomplete (the tables are still built in this
-   case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
-   lengths), or Z_MEM_ERROR if not enough memory. */
-{
-
-  uInt a;                       /* counter for codes of length k */
-  uInt c[BMAX+1];               /* bit length count table */
-  uInt f;                       /* i repeats in table every f entries */
-  int g;                        /* maximum code length */
-  int h;                        /* table level */
-  register uInt i;              /* counter, current code */
-  register uInt j;              /* counter */
-  register int k;               /* number of bits in current code */
-  int l;                        /* bits per table (returned in m) */
-  register uIntf *p;            /* pointer into c[], b[], or v[] */
-  inflate_huft *q;              /* points to current table */
-  struct inflate_huft_s r;      /* table entry for structure assignment */
-  inflate_huft *u[BMAX];        /* table stack */
-  uInt v[N_MAX];                /* values in order of bit length */
-  register int w;               /* bits before this table == (l * h) */
-  uInt x[BMAX+1];               /* bit offsets, then code stack */
-  uIntf *xp;                    /* pointer into x */
-  int y;                        /* number of dummy codes added */
-  uInt z;                       /* number of entries in current table */
-
-
-  /* Generate counts for each bit length */
-  p = c;
-#define C0 *p++ = 0;
-#define C2 C0 C0 C0 C0
-#define C4 C2 C2 C2 C2
-  C4                            /* clear c[]--assume BMAX+1 is 16 */
-  p = b;  i = n;
-  do {
-    c[*p++]++;                  /* assume all entries <= BMAX */
-  } while (--i);
-  if (c[0] == n)                /* null input--all zero length codes */
-  {
-    *t = (inflate_huft *)Z_NULL;
-    *m = 0;
-    return Z_OK;
-  }
-
-
-  /* Find minimum and maximum length, bound *m by those */
-  l = *m;
-  for (j = 1; j <= BMAX; j++)
-    if (c[j])
-      break;
-  k = j;                        /* minimum code length */
-  if ((uInt)l < j)
-    l = j;
-  for (i = BMAX; i; i--)
-    if (c[i])
-      break;
-  g = i;                        /* maximum code length */
-  if ((uInt)l > i)
-    l = i;
-  *m = l;
-
-
-  /* Adjust last length count to fill out codes, if needed */
-  for (y = 1 << j; j < i; j++, y <<= 1)
-    if ((y -= c[j]) < 0)
-      return Z_DATA_ERROR;
-  if ((y -= c[i]) < 0)
-    return Z_DATA_ERROR;
-  c[i] += y;
-
-
-  /* Generate starting offsets into the value table for each length */
-  x[1] = j = 0;
-  p = c + 1;  xp = x + 2;
-  while (--i) {                 /* note that i == g from above */
-    *xp++ = (j += *p++);
-  }
-
-
-  /* Make a table of values in order of bit lengths */
-  p = b;  i = 0;
-  do {
-    if ((j = *p++) != 0)
-      v[x[j]++] = i;
-  } while (++i < n);
-  n = x[g];                   /* set n to length of v */
-
-
-  /* Generate the Huffman codes and for each, make the table entries */
-  x[0] = i = 0;                 /* first Huffman code is zero */
-  p = v;                        /* grab values in bit order */
-  h = -1;                       /* no tables yet--level -1 */
-  w = -l;                       /* bits decoded == (l * h) */
-  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
-  q = (inflate_huft *)Z_NULL;   /* ditto */
-  z = 0;                        /* ditto */
-
-  /* go through the bit lengths (k already is bits in shortest code) */
-  for (; k <= g; k++)
-  {
-    a = c[k];
-    while (a--)
-    {
-      /* here i is the Huffman code of length k bits for value *p */
-      /* make tables up to required level */
-      while (k > w + l)
-      {
-        h++;
-        w += l;                 /* previous table always l bits */
-
-        /* compute minimum size table less than or equal to l bits */
-        z = g - w;
-        z = z > (uInt)l ? l : z;        /* table size upper limit */
-        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
-        {                       /* too few codes for k-w bit table */
-          f -= a + 1;           /* deduct codes from patterns left */
-          xp = c + k;
-          if (j < z)
-            while (++j < z)     /* try smaller tables up to z bits */
-            {
-              if ((f <<= 1) <= *++xp)
-                break;          /* enough codes to use up j bits */
-              f -= *xp;         /* else deduct codes from patterns */
-            }
-        }
-        z = 1 << j;             /* table entries for j-bit table */
-
-        /* allocate and link in new table */
-        if ((q = (inflate_huft *)ZALLOC
-             (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
-        {
-          if (h)
-            inflate_trees_free(u[0], zs);
-          return Z_MEM_ERROR;   /* not enough memory */
-        }
-#ifdef DEBUG_ZLIB
-        inflate_hufts += z + 1;
-#endif
-        *t = q + 1;             /* link to list for huft_free() */
-        *(t = &(q->next)) = Z_NULL;
-        u[h] = ++q;             /* table starts after link */
-
-        /* connect to last table, if there is one */
-        if (h)
-        {
-          x[h] = i;             /* save pattern for backing up */
-          r.bits = (Byte)l;     /* bits to dump before this table */
-          r.exop = (Byte)j;     /* bits in this table */
-          r.next = q;           /* pointer to this table */
-          j = i >> (w - l);     /* (get around Turbo C bug) */
-          u[h-1][j] = r;        /* connect to last table */
-        }
-      }
-
-      /* set up table entry in r */
-      r.bits = (Byte)(k - w);
-      if (p >= v + n)
-        r.exop = 128 + 64;      /* out of values--invalid code */
-      else if (*p < s)
-      {
-        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
-        r.base = *p++;          /* simple code is just the value */
-      }
-      else
-      {
-        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
-        r.base = d[*p++ - s];
-      }
-
-      /* fill code-like entries with r */
-      f = 1 << (k - w);
-      for (j = i >> w; j < z; j += f)
-        q[j] = r;
-
-      /* backwards increment the k-bit code i */
-      for (j = 1 << (k - 1); i & j; j >>= 1)
-        i ^= j;
-      i ^= j;
-
-      /* backup over finished tables */
-      while ((i & ((1 << w) - 1)) != x[h])
-      {
-        h--;                    /* don't need to update q */
-        w -= l;
-      }
-    }
-  }
-
-
-  /* Return Z_BUF_ERROR if we were given an incomplete table */
-  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
-}
-
-
-int inflate_trees_bits(c, bb, tb, z)
-uIntf *c;               /* 19 code lengths */
-uIntf *bb;              /* bits tree desired/actual depth */
-inflate_huft * FAR *tb; /* bits tree result */
-z_streamp z;            /* for zfree function */
-{
-  int r;
-
-  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
-  if (r == Z_DATA_ERROR)
-    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
-  else if (r == Z_BUF_ERROR || *bb == 0)
-  {
-    inflate_trees_free(*tb, z);
-    z->msg = (char*)"incomplete dynamic bit lengths tree";
-    r = Z_DATA_ERROR;
-  }
-  return r;
-}
-
-
-int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
-uInt nl;                /* number of literal/length codes */
-uInt nd;                /* number of distance codes */
-uIntf *c;               /* that many (total) code lengths */
-uIntf *bl;              /* literal desired/actual bit depth */
-uIntf *bd;              /* distance desired/actual bit depth */
-inflate_huft * FAR *tl; /* literal/length tree result */
-inflate_huft * FAR *td; /* distance tree result */
-z_streamp z;            /* for zfree function */
-{
-  int r;
-
-  /* build literal/length tree */
-  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z);
-  if (r != Z_OK || *bl == 0)
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed literal/length tree";
-    else if (r != Z_MEM_ERROR)
-    {
-      inflate_trees_free(*tl, z);
-      z->msg = (char*)"incomplete literal/length tree";
-      r = Z_DATA_ERROR;
-    }
-    return r;
-  }
-
-  /* build distance tree */
-  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z);
-  if (r != Z_OK || (*bd == 0 && nl > 257))
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed distance tree";
-    else if (r == Z_BUF_ERROR) {
-#ifdef PKZIP_BUG_WORKAROUND
-      r = Z_OK;
-    }
-#else
-      inflate_trees_free(*td, z);
-      z->msg = (char*)"incomplete distance tree";
-      r = Z_DATA_ERROR;
-    }
-    else if (r != Z_MEM_ERROR)
-    {
-      z->msg = (char*)"empty distance tree with lengths";
-      r = Z_DATA_ERROR;
-    }
-    inflate_trees_free(*tl, z);
-    return r;
-#endif
-  }
-
-  /* done */
-  return Z_OK;
-}
-
-
-/* build fixed tables only once--keep them here */
-local int fixed_built = 0;
-#define FIXEDH 530      /* number of hufts used by fixed tables */
-local inflate_huft fixed_mem[FIXEDH];
-local uInt fixed_bl;
-local uInt fixed_bd;
-local inflate_huft *fixed_tl;
-local inflate_huft *fixed_td;
-
-
-local voidpf falloc(q, n, s)
-voidpf q;       /* opaque pointer */
-uInt n;         /* number of items */
-uInt s;         /* size of item */
-{
-  Assert(s == sizeof(inflate_huft) && n <= *(intf *)q,
-         "inflate_trees falloc overflow");
-  *(intf *)q -= n+s-s; /* s-s to avoid warning */
-  return (voidpf)(fixed_mem + *(intf *)q);
-}
-
-
-int inflate_trees_fixed(bl, bd, tl, td)
-uIntf *bl;               /* literal desired/actual bit depth */
-uIntf *bd;               /* distance desired/actual bit depth */
-inflate_huft * FAR *tl;  /* literal/length tree result */
-inflate_huft * FAR *td;  /* distance tree result */
-{
-  /* build fixed tables if not already (multiple overlapped executions ok) */
-  if (!fixed_built)
-  {
-    int k;              /* temporary variable */
-    unsigned c[288];    /* length list for huft_build */
-    z_stream z;         /* for falloc function */
-    int f = FIXEDH;     /* number of hufts left in fixed_mem */
-
-    /* set up fake z_stream for memory routines */
-    z.zalloc = falloc;
-    z.zfree = Z_NULL;
-    z.opaque = (voidpf)&f;
-
-    /* literal table */
-    for (k = 0; k < 144; k++)
-      c[k] = 8;
-    for (; k < 256; k++)
-      c[k] = 9;
-    for (; k < 280; k++)
-      c[k] = 7;
-    for (; k < 288; k++)
-      c[k] = 8;
-    fixed_bl = 7;
-    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
-
-    /* distance table */
-    for (k = 0; k < 30; k++)
-      c[k] = 5;
-    fixed_bd = 5;
-    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
-
-    /* done */
-    Assert(f == 0, "invalid build of fixed tables");
-    fixed_built = 1;
-  }
-  *bl = fixed_bl;
-  *bd = fixed_bd;
-  *tl = fixed_tl;
-  *td = fixed_td;
-  return Z_OK;
-}
-
-
-int inflate_trees_free(t, z)
-inflate_huft *t;        /* table to free */
-z_streamp z;            /* for zfree function */
-/* Free the malloc'ed tables built by huft_build(), which makes a linked
-   list of the tables it made, with the links in a dummy first entry of
-   each table. */
-{
-  register inflate_huft *p, *q, *r;
-
-  /* Reverse linked list */
-  p = Z_NULL;
-  q = t;
-  while (q != Z_NULL)
-  {
-    r = (q - 1)->next;
-    (q - 1)->next = p;
-    p = q;
-    q = r;
-  }
-  /* Go through linked list, freeing from the malloced (t[-1]) address. */
-  while (p != Z_NULL)
-  {
-    q = (--p)->next;
-    ZFREE(z,p);
-    p = q;
-  } 
-  return Z_OK;
-}
-/* --- inftrees.c */
-
-/* +++ infcodes.c */
-/* infcodes.c -- process literals and length/distance pairs
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-/* #include "infblock.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-
-/* +++ inffast.h */
-/* inffast.h -- header to use inffast.c
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-extern int inflate_fast OF((
-    uInt,
-    uInt,
-    inflate_huft *,
-    inflate_huft *,
-    inflate_blocks_statef *,
-    z_streamp ));
-/* --- inffast.h */
-
-/* simplify the use of the inflate_huft type with some defines */
-#define base more.Base
-#define next more.Next
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-/* inflate codes private state */
-struct inflate_codes_state {
-
-  /* mode */
-  enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
-      START,    /* x: set up for LEN */
-      LEN,      /* i: get length/literal/eob next */
-      LENEXT,   /* i: getting length extra (have base) */
-      DIST,     /* i: get distance next */
-      DISTEXT,  /* i: getting distance extra */
-      COPY,     /* o: copying bytes in window, waiting for space */
-      LIT,      /* o: got literal, waiting for output space */
-      WASH,     /* o: got eob, possibly still output waiting */
-      END,      /* x: got eob and all data flushed */
-      BADCODE}  /* x: got error */
-    mode;               /* current inflate_codes mode */
-
-  /* mode dependent information */
-  uInt len;
-  union {
-    struct {
-      inflate_huft *tree;       /* pointer into tree */
-      uInt need;                /* bits needed */
-    } code;             /* if LEN or DIST, where in tree */
-    uInt lit;           /* if LIT, literal */
-    struct {
-      uInt get;                 /* bits to get for extra */
-      uInt dist;                /* distance back to copy from */
-    } copy;             /* if EXT or COPY, where and how much */
-  } sub;                /* submode */
-
-  /* mode independent information */
-  Byte lbits;           /* ltree bits decoded per branch */
-  Byte dbits;           /* dtree bits decoder per branch */
-  inflate_huft *ltree;          /* literal/length/eob tree */
-  inflate_huft *dtree;          /* distance tree */
-
-};
-
-
-inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-z_streamp z;
-{
-  inflate_codes_statef *c;
-
-  if ((c = (inflate_codes_statef *)
-       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
-  {
-    c->mode = START;
-    c->lbits = (Byte)bl;
-    c->dbits = (Byte)bd;
-    c->ltree = tl;
-    c->dtree = td;
-    Tracev((stderr, "inflate:       codes new\n"));
-  }
-  return c;
-}
-
-
-int inflate_codes(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt j;               /* temporary storage */
-  inflate_huft *t;      /* temporary pointer */
-  uInt e;               /* extra bits or operation */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Bytef *p;             /* input data pointer */
-  uInt n;               /* bytes available there */
-  Bytef *q;             /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-  Bytef *f;             /* pointer to copy strings from */
-  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
-
-  /* copy input/output information to locals (UPDATE macro restores) */
-  LOAD
-
-  /* process input and output based on current state */
-  while (1) switch (c->mode)
-  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
-    case START:         /* x: set up for LEN */
-#ifndef SLOW
-      if (m >= 258 && n >= 10)
-      {
-        UPDATE
-        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
-        LOAD
-        if (r != Z_OK)
-        {
-          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
-          break;
-        }
-      }
-#endif /* !SLOW */
-      c->sub.code.need = c->lbits;
-      c->sub.code.tree = c->ltree;
-      c->mode = LEN;
-    case LEN:           /* i: get length/literal/eob next */
-      j = c->sub.code.need;
-      NEEDBITS(j)
-      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
-      DUMPBITS(t->bits)
-      e = (uInt)(t->exop);
-      if (e == 0)               /* literal */
-      {
-        c->sub.lit = t->base;
-        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-                 "inflate:         literal '%c'\n" :
-                 "inflate:         literal 0x%02x\n", t->base));
-        c->mode = LIT;
-        break;
-      }
-      if (e & 16)               /* length */
-      {
-        c->sub.copy.get = e & 15;
-        c->len = t->base;
-        c->mode = LENEXT;
-        break;
-      }
-      if ((e & 64) == 0)        /* next table */
-      {
-        c->sub.code.need = e;
-        c->sub.code.tree = t->next;
-        break;
-      }
-      if (e & 32)               /* end of block */
-      {
-        Tracevv((stderr, "inflate:         end of block\n"));
-        c->mode = WASH;
-        break;
-      }
-      c->mode = BADCODE;        /* invalid code */
-      z->msg = (char*)"invalid literal/length code";
-      r = Z_DATA_ERROR;
-      LEAVE
-    case LENEXT:        /* i: getting length extra (have base) */
-      j = c->sub.copy.get;
-      NEEDBITS(j)
-      c->len += (uInt)b & inflate_mask[j];
-      DUMPBITS(j)
-      c->sub.code.need = c->dbits;
-      c->sub.code.tree = c->dtree;
-      Tracevv((stderr, "inflate:         length %u\n", c->len));
-      c->mode = DIST;
-    case DIST:          /* i: get distance next */
-      j = c->sub.code.need;
-      NEEDBITS(j)
-      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
-      DUMPBITS(t->bits)
-      e = (uInt)(t->exop);
-      if (e & 16)               /* distance */
-      {
-        c->sub.copy.get = e & 15;
-        c->sub.copy.dist = t->base;
-        c->mode = DISTEXT;
-        break;
-      }
-      if ((e & 64) == 0)        /* next table */
-      {
-        c->sub.code.need = e;
-        c->sub.code.tree = t->next;
-        break;
-      }
-      c->mode = BADCODE;        /* invalid code */
-      z->msg = (char*)"invalid distance code";
-      r = Z_DATA_ERROR;
-      LEAVE
-    case DISTEXT:       /* i: getting distance extra */
-      j = c->sub.copy.get;
-      NEEDBITS(j)
-      c->sub.copy.dist += (uInt)b & inflate_mask[j];
-      DUMPBITS(j)
-      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
-      c->mode = COPY;
-    case COPY:          /* o: copying bytes in window, waiting for space */
-#ifndef __TURBOC__ /* Turbo C bug for following expression */
-      f = (uInt)(q - s->window) < c->sub.copy.dist ?
-          s->end - (c->sub.copy.dist - (q - s->window)) :
-          q - c->sub.copy.dist;
-#else
-      f = q - c->sub.copy.dist;
-      if ((uInt)(q - s->window) < c->sub.copy.dist)
-        f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
-#endif
-      while (c->len)
-      {
-        NEEDOUT
-        OUTBYTE(*f++)
-        if (f == s->end)
-          f = s->window;
-        c->len--;
-      }
-      c->mode = START;
-      break;
-    case LIT:           /* o: got literal, waiting for output space */
-      NEEDOUT
-      OUTBYTE(c->sub.lit)
-      c->mode = START;
-      break;
-    case WASH:          /* o: got eob, possibly more output */
-      FLUSH
-      if (s->read != s->write)
-        LEAVE
-      c->mode = END;
-    case END:
-      r = Z_STREAM_END;
-      LEAVE
-    case BADCODE:       /* x: got error */
-      r = Z_DATA_ERROR;
-      LEAVE
-    default:
-      r = Z_STREAM_ERROR;
-      LEAVE
-  }
-}
-
-
-void inflate_codes_free(c, z)
-inflate_codes_statef *c;
-z_streamp z;
-{
-  ZFREE(z, c);
-  Tracev((stderr, "inflate:       codes free\n"));
-}
-/* --- infcodes.c */
-
-/* +++ infutil.c */
-/* inflate_util.c -- data and routines common to blocks and codes
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "infblock.h" */
-/* #include "inftrees.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* And'ing with mask[n] masks the lower n bits */
-uInt inflate_mask[17] = {
-    0x0000,
-    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
-    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-};
-
-
-/* copy as much as possible from the sliding window to the output area */
-int inflate_flush(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt n;
-  Bytef *p;
-  Bytef *q;
-
-  /* local copies of source and destination pointers */
-  p = z->next_out;
-  q = s->read;
-
-  /* compute number of bytes to copy as far as end of window */
-  n = (uInt)((q <= s->write ? s->write : s->end) - q);
-  if (n > z->avail_out) n = z->avail_out;
-  if (n && r == Z_BUF_ERROR) r = Z_OK;
-
-  /* update counters */
-  z->avail_out -= n;
-  z->total_out += n;
-
-  /* update check information */
-  if (s->checkfn != Z_NULL)
-    z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-  /* copy as far as end of window */
-  if (p != Z_NULL) {
-    zmemcpy(p, q, n);
-    p += n;
-  }
-  q += n;
-
-  /* see if more to copy at beginning of window */
-  if (q == s->end)
-  {
-    /* wrap pointers */
-    q = s->window;
-    if (s->write == s->end)
-      s->write = s->window;
-
-    /* compute bytes to copy */
-    n = (uInt)(s->write - q);
-    if (n > z->avail_out) n = z->avail_out;
-    if (n && r == Z_BUF_ERROR) r = Z_OK;
-
-    /* update counters */
-    z->avail_out -= n;
-    z->total_out += n;
-
-    /* update check information */
-    if (s->checkfn != Z_NULL)
-      z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-    /* copy */
-    if (p != Z_NULL) {
-      zmemcpy(p, q, n);
-      p += n;
-    }
-    q += n;
-  }
-
-  /* update pointers */
-  z->next_out = p;
-  s->read = q;
-
-  /* done */
-  return r;
-}
-/* --- infutil.c */
-
-/* +++ inffast.c */
-/* inffast.c -- process literals and length/distance pairs fast
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-/* #include "infblock.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-/* #include "inffast.h" */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* simplify the use of the inflate_huft type with some defines */
-#define base more.Base
-#define next more.Next
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-/* macros for bit input with no checking and for returning unused bytes */
-#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;}
-
-/* Called with number of bytes left to write in window at least 258
-   (the maximum string length) and number of input bytes available
-   at least ten.  The ten bytes are six bytes for the longest length/
-   distance pair plus four bytes for overloading the bit buffer. */
-
-int inflate_fast(bl, bd, tl, td, s, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-inflate_blocks_statef *s;
-z_streamp z;
-{
-  inflate_huft *t;      /* temporary pointer */
-  uInt e;               /* extra bits or operation */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Bytef *p;             /* input data pointer */
-  uInt n;               /* bytes available there */
-  Bytef *q;             /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-  uInt ml;              /* mask for literal/length tree */
-  uInt md;              /* mask for distance tree */
-  uInt c;               /* bytes to copy */
-  uInt d;               /* distance back to copy from */
-  Bytef *r;             /* copy source pointer */
-
-  /* load input, output, bit values */
-  LOAD
-
-  /* initialize masks */
-  ml = inflate_mask[bl];
-  md = inflate_mask[bd];
-
-  /* do until not enough input or output space for fast loop */
-  do {                          /* assume called with m >= 258 && n >= 10 */
-    /* get literal/length code */
-    GRABBITS(20)                /* max bits for literal/length code */
-    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
-    {
-      DUMPBITS(t->bits)
-      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-                "inflate:         * literal '%c'\n" :
-                "inflate:         * literal 0x%02x\n", t->base));
-      *q++ = (Byte)t->base;
-      m--;
-      continue;
-    }
-    do {
-      DUMPBITS(t->bits)
-      if (e & 16)
-      {
-        /* get extra bits for length */
-        e &= 15;
-        c = t->base + ((uInt)b & inflate_mask[e]);
-        DUMPBITS(e)
-        Tracevv((stderr, "inflate:         * length %u\n", c));
-
-        /* decode distance base of block to copy */
-        GRABBITS(15);           /* max bits for distance code */
-        e = (t = td + ((uInt)b & md))->exop;
-        do {
-          DUMPBITS(t->bits)
-          if (e & 16)
-          {
-            /* get extra bits to add to distance base */
-            e &= 15;
-            GRABBITS(e)         /* get extra bits (up to 13) */
-            d = t->base + ((uInt)b & inflate_mask[e]);
-            DUMPBITS(e)
-            Tracevv((stderr, "inflate:         * distance %u\n", d));
-
-            /* do the copy */
-            m -= c;
-            if ((uInt)(q - s->window) >= d)     /* offset before dest */
-            {                                   /*  just copy */
-              r = q - d;
-              *q++ = *r++;  c--;        /* minimum count is three, */
-              *q++ = *r++;  c--;        /*  so unroll loop a little */
-            }
-            else                        /* else offset after destination */
-            {
-              e = d - (uInt)(q - s->window); /* bytes from offset to end */
-              r = s->end - e;           /* pointer to offset */
-              if (c > e)                /* if source crosses, */
-              {
-                c -= e;                 /* copy to end of window */
-                do {
-                  *q++ = *r++;
-                } while (--e);
-                r = s->window;          /* copy rest from start of window */
-              }
-            }
-            do {                        /* copy all or what's left */
-              *q++ = *r++;
-            } while (--c);
-            break;
-          }
-          else if ((e & 64) == 0)
-            e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
-          else
-          {
-            z->msg = (char*)"invalid distance code";
-            UNGRAB
-            UPDATE
-            return Z_DATA_ERROR;
-          }
-        } while (1);
-        break;
-      }
-      if ((e & 64) == 0)
-      {
-        if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
-        {
-          DUMPBITS(t->bits)
-          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-                    "inflate:         * literal '%c'\n" :
-                    "inflate:         * literal 0x%02x\n", t->base));
-          *q++ = (Byte)t->base;
-          m--;
-          break;
-        }
-      }
-      else if (e & 32)
-      {
-        Tracevv((stderr, "inflate:         * end of block\n"));
-        UNGRAB
-        UPDATE
-        return Z_STREAM_END;
-      }
-      else
-      {
-        z->msg = (char*)"invalid literal/length code";
-        UNGRAB
-        UPDATE
-        return Z_DATA_ERROR;
-      }
-    } while (1);
-  } while (m >= 258 && n >= 10);
-
-  /* not enough input or output--restore pointers and return */
-  UNGRAB
-  UPDATE
-  return Z_OK;
-}
-/* --- inffast.c */
-
-/* +++ zutil.c */
-/* zutil.c -- target dependent utility functions for the compression library
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */
-
-/* #include "zutil.h" */
-
-#ifndef NO_DUMMY_DECL
-struct internal_state      {int dummy;}; /* for buggy compilers */
-#endif
-
-#ifndef STDC
-extern void exit OF((int));
-#endif
-
-const char *z_errmsg[10] = {
-"need dictionary",     /* Z_NEED_DICT       2  */
-"stream end",          /* Z_STREAM_END      1  */
-"",                    /* Z_OK              0  */
-"file error",          /* Z_ERRNO         (-1) */
-"stream error",        /* Z_STREAM_ERROR  (-2) */
-"data error",          /* Z_DATA_ERROR    (-3) */
-"insufficient memory", /* Z_MEM_ERROR     (-4) */
-"buffer error",        /* Z_BUF_ERROR     (-5) */
-"incompatible version",/* Z_VERSION_ERROR (-6) */
-""};
-
-
-const char *zlibVersion()
-{
-    return ZLIB_VERSION;
-}
-
-#ifdef DEBUG_ZLIB
-void z_error (m)
-    char *m;
-{
-    fprintf(stderr, "%s\n", m);
-    exit(1);
-}
-#endif
-
-#ifndef HAVE_MEMCPY
-
-void zmemcpy(dest, source, len)
-    Bytef* dest;
-    Bytef* source;
-    uInt  len;
-{
-    if (len == 0) return;
-    do {
-        *dest++ = *source++; /* ??? to be unrolled */
-    } while (--len != 0);
-}
-
-int zmemcmp(s1, s2, len)
-    Bytef* s1;
-    Bytef* s2;
-    uInt  len;
-{
-    uInt j;
-
-    for (j = 0; j < len; j++) {
-        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
-    }
-    return 0;
-}
-
-void zmemzero(dest, len)
-    Bytef* dest;
-    uInt  len;
-{
-    if (len == 0) return;
-    do {
-        *dest++ = 0;  /* ??? to be unrolled */
-    } while (--len != 0);
-}
-#endif
-
-#ifdef __TURBOC__
-#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
-/* Small and medium model in Turbo C are for now limited to near allocation
- * with reduced MAX_WBITS and MAX_MEM_LEVEL
- */
-#  define MY_ZCALLOC
-
-/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
- * and farmalloc(64K) returns a pointer with an offset of 8, so we
- * must fix the pointer. Warning: the pointer must be put back to its
- * original form in order to free it, use zcfree().
- */
-
-#define MAX_PTR 10
-/* 10*64K = 640K */
-
-local int next_ptr = 0;
-
-typedef struct ptr_table_s {
-    voidpf org_ptr;
-    voidpf new_ptr;
-} ptr_table;
-
-local ptr_table table[MAX_PTR];
-/* This table is used to remember the original form of pointers
- * to large buffers (64K). Such pointers are normalized with a zero offset.
- * Since MSDOS is not a preemptive multitasking OS, this table is not
- * protected from concurrent access. This hack doesn't work anyway on
- * a protected system like OS/2. Use Microsoft C instead.
- */
-
-voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
-{
-    voidpf buf = opaque; /* just to make some compilers happy */
-    ulg bsize = (ulg)items*size;
-
-    /* If we allocate less than 65520 bytes, we assume that farmalloc
-     * will return a usable pointer which doesn't have to be normalized.
-     */
-    if (bsize < 65520L) {
-        buf = farmalloc(bsize);
-        if (*(ush*)&buf != 0) return buf;
-    } else {
-        buf = farmalloc(bsize + 16L);
-    }
-    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
-    table[next_ptr].org_ptr = buf;
-
-    /* Normalize the pointer to seg:0 */
-    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
-    *(ush*)&buf = 0;
-    table[next_ptr++].new_ptr = buf;
-    return buf;
-}
-
-void  zcfree (voidpf opaque, voidpf ptr)
-{
-    int n;
-    if (*(ush*)&ptr != 0) { /* object < 64K */
-        farfree(ptr);
-        return;
-    }
-    /* Find the original pointer */
-    for (n = 0; n < next_ptr; n++) {
-        if (ptr != table[n].new_ptr) continue;
-
-        farfree(table[n].org_ptr);
-        while (++n < next_ptr) {
-            table[n-1] = table[n];
-        }
-        next_ptr--;
-        return;
-    }
-    ptr = opaque; /* just to make some compilers happy */
-    Assert(0, "zcfree: ptr not found");
-}
-#endif
-#endif /* __TURBOC__ */
-
-
-#if defined(M_I86) && !defined(__32BIT__)
-/* Microsoft C in 16-bit mode */
-
-#  define MY_ZCALLOC
-
-#if (!defined(_MSC_VER) || (_MSC_VER < 600))
-#  define _halloc  halloc
-#  define _hfree   hfree
-#endif
-
-voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
-{
-    if (opaque) opaque = 0; /* to make compiler happy */
-    return _halloc((long)items, size);
-}
-
-void  zcfree (voidpf opaque, voidpf ptr)
-{
-    if (opaque) opaque = 0; /* to make compiler happy */
-    _hfree(ptr);
-}
-
-#endif /* MSC */
-
-
-#ifndef MY_ZCALLOC /* Any system without a special alloc function */
-
-#ifndef STDC
-extern voidp  calloc OF((uInt items, uInt size));
-extern void   free   OF((voidpf ptr));
-#endif
-
-voidpf zcalloc (opaque, items, size)
-    voidpf opaque;
-    unsigned items;
-    unsigned size;
-{
-    if (opaque) items += size - size; /* make compiler happy */
-    return (voidpf)calloc(items, size);
-}
-
-void  zcfree (opaque, ptr)
-    voidpf opaque;
-    voidpf ptr;
-{
-    free(ptr);
-    if (opaque) return; /* make compiler happy */
-}
-
-#endif /* MY_ZCALLOC */
-/* --- zutil.c */
-
-/* +++ adler32.c */
-/* adler32.c -- compute the Adler-32 checksum of a data stream
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */
-
-/* #include "zlib.h" */
-
-#define BASE 65521L /* largest prime smaller than 65536 */
-#define NMAX 5552
-/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
-
-#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
-#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
-#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
-#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
-#define DO16(buf)   DO8(buf,0); DO8(buf,8);
-
-/* ========================================================================= */
-uLong adler32(adler, buf, len)
-    uLong adler;
-    const Bytef *buf;
-    uInt len;
-{
-    unsigned long s1 = adler & 0xffff;
-    unsigned long s2 = (adler >> 16) & 0xffff;
-    int k;
-
-    if (buf == Z_NULL) return 1L;
-
-    while (len > 0) {
-        k = len < NMAX ? len : NMAX;
-        len -= k;
-        while (k >= 16) {
-            DO16(buf);
-	    buf += 16;
-            k -= 16;
-        }
-        if (k != 0) do {
-            s1 += *buf++;
-	    s2 += s1;
-        } while (--k);
-        s1 %= BASE;
-        s2 %= BASE;
-    }
-    return (s2 << 16) | s1;
-}
-/* --- adler32.c */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/net/zlib.h linux-2.4.20/drivers/net/zlib.h
--- linux-2.4.19/drivers/net/zlib.h	1997-12-23 18:57:31.000000000 +0000
+++ linux-2.4.20/drivers/net/zlib.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,1010 +0,0 @@
-/*	$Id: zlib.h,v 1.2 1997/12/23 10:47:44 paulus Exp $	*/
-
-/*
- * This file is derived from zlib.h and zconf.h from the zlib-1.0.4
- * distribution by Jean-loup Gailly and Mark Adler, with some additions
- * by Paul Mackerras to aid in implementing Deflate compression and
- * decompression for PPP packets.
- */
-
-/*
- *  ==FILEVERSION 971127==
- *
- * This marker is used by the Linux installation script to determine
- * whether an up-to-date version of this file is already installed.
- */
-
-
-/* +++ zlib.h */
-/* zlib.h -- interface of the 'zlib' general purpose compression library
-  version 1.0.4, Jul 24th, 1996.
-
-  Copyright (C) 1995-1996 Jean-loup Gailly and Mark Adler
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  Jean-loup Gailly        Mark Adler
-  gzip@prep.ai.mit.edu    madler@alumni.caltech.edu
-
-
-  The data format used by the zlib library is described by RFCs (Request for
-  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
-  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
-*/
-
-#ifndef _ZLIB_H
-#define _ZLIB_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* +++ zconf.h */
-/* zconf.h -- configuration of the zlib compression library
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: zconf.h,v 1.20 1996/07/02 15:09:28 me Exp $ */
-
-#ifndef _ZCONF_H
-#define _ZCONF_H
-
-/*
- * If you *really* need a unique prefix for all types and library functions,
- * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
- */
-#ifdef Z_PREFIX
-#  define deflateInit_	z_deflateInit_
-#  define deflate	z_deflate
-#  define deflateEnd	z_deflateEnd
-#  define inflateInit_ 	z_inflateInit_
-#  define inflate	z_inflate
-#  define inflateEnd	z_inflateEnd
-#  define deflateInit2_	z_deflateInit2_
-#  define deflateSetDictionary z_deflateSetDictionary
-#  define deflateCopy	z_deflateCopy
-#  define deflateReset	z_deflateReset
-#  define deflateParams	z_deflateParams
-#  define inflateInit2_	z_inflateInit2_
-#  define inflateSetDictionary z_inflateSetDictionary
-#  define inflateSync	z_inflateSync
-#  define inflateReset	z_inflateReset
-#  define compress	z_compress
-#  define uncompress	z_uncompress
-#  define adler32	z_adler32
-#  define crc32		z_crc32
-#  define get_crc_table z_get_crc_table
-
-#  define Byte		z_Byte
-#  define uInt		z_uInt
-#  define uLong		z_uLong
-#  define Bytef	        z_Bytef
-#  define charf		z_charf
-#  define intf		z_intf
-#  define uIntf		z_uIntf
-#  define uLongf	z_uLongf
-#  define voidpf	z_voidpf
-#  define voidp		z_voidp
-#endif
-
-#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
-#  define WIN32
-#endif
-#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
-#  ifndef __32BIT__
-#    define __32BIT__
-#  endif
-#endif
-#if defined(__MSDOS__) && !defined(MSDOS)
-#  define MSDOS
-#endif
-
-/*
- * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
- * than 64k bytes at a time (needed on systems with 16-bit int).
- */
-#if defined(MSDOS) && !defined(__32BIT__)
-#  define MAXSEG_64K
-#endif
-#ifdef MSDOS
-#  define UNALIGNED_OK
-#endif
-
-#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
-#  define STDC
-#endif
-#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC)
-#  define STDC
-#endif
-
-#ifndef STDC
-#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
-#    define const
-#  endif
-#endif
-
-/* Some Mac compilers merge all .h files incorrectly: */
-#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
-#  define NO_DUMMY_DECL
-#endif
-
-/* Maximum value for memLevel in deflateInit2 */
-#ifndef MAX_MEM_LEVEL
-#  ifdef MAXSEG_64K
-#    define MAX_MEM_LEVEL 8
-#  else
-#    define MAX_MEM_LEVEL 9
-#  endif
-#endif
-
-/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
-#ifndef MAX_WBITS
-#  define MAX_WBITS   15 /* 32K LZ77 window */
-#endif
-
-/* The memory requirements for deflate are (in bytes):
-            1 << (windowBits+2)   +  1 << (memLevel+9)
- that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
- plus a few kilobytes for small objects. For example, if you want to reduce
- the default memory requirements from 256K to 128K, compile with
-     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
- Of course this will generally degrade compression (there's no free lunch).
-
-   The memory requirements for inflate are (in bytes) 1 << windowBits
- that is, 32K for windowBits=15 (default value) plus a few kilobytes
- for small objects.
-*/
-
-                        /* Type declarations */
-
-#ifndef OF /* function prototypes */
-#  ifdef STDC
-#    define OF(args)  args
-#  else
-#    define OF(args)  ()
-#  endif
-#endif
-
-/* The following definitions for FAR are needed only for MSDOS mixed
- * model programming (small or medium model with some far allocations).
- * This was tested only with MSC; for other MSDOS compilers you may have
- * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
- * just define FAR to be empty.
- */
-#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
-   /* MSC small or medium model */
-#  define SMALL_MEDIUM
-#  ifdef _MSC_VER
-#    define FAR __far
-#  else
-#    define FAR far
-#  endif
-#endif
-#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
-#  ifndef __32BIT__
-#    define SMALL_MEDIUM
-#    define FAR __far
-#  endif
-#endif
-#ifndef FAR
-#   define FAR
-#endif
-
-typedef unsigned char  Byte;  /* 8 bits */
-typedef unsigned int   uInt;  /* 16 bits or more */
-typedef unsigned long  uLong; /* 32 bits or more */
-
-#if defined(__BORLANDC__) && defined(SMALL_MEDIUM)
-   /* Borland C/C++ ignores FAR inside typedef */
-#  define Bytef Byte FAR
-#else
-   typedef Byte  FAR Bytef;
-#endif
-typedef char  FAR charf;
-typedef int   FAR intf;
-typedef uInt  FAR uIntf;
-typedef uLong FAR uLongf;
-
-#ifdef STDC
-   typedef void FAR *voidpf;
-   typedef void     *voidp;
-#else
-   typedef Byte FAR *voidpf;
-   typedef Byte     *voidp;
-#endif
-
-
-/* Compile with -DZLIB_DLL for Windows DLL support */
-#if (defined(_WINDOWS) || defined(WINDOWS)) && defined(ZLIB_DLL)
-#  include <windows.h>
-#  define EXPORT  WINAPI
-#else
-#  define EXPORT
-#endif
-
-#endif /* _ZCONF_H */
-/* --- zconf.h */
-
-#define ZLIB_VERSION "1.0.4P"
-
-/* 
-     The 'zlib' compression library provides in-memory compression and
-  decompression functions, including integrity checks of the uncompressed
-  data.  This version of the library supports only one compression method
-  (deflation) but other algorithms may be added later and will have the same
-  stream interface.
-
-     For compression the application must provide the output buffer and
-  may optionally provide the input buffer for optimization. For decompression,
-  the application must provide the input buffer and may optionally provide
-  the output buffer for optimization.
-
-     Compression can be done in a single step if the buffers are large
-  enough (for example if an input file is mmap'ed), or can be done by
-  repeated calls of the compression function.  In the latter case, the
-  application must provide more input and/or consume the output
-  (providing more output space) before each call.
-
-     The library does not install any signal handler. It is recommended to
-  add at least a handler for SIGSEGV when decompressing; the library checks
-  the consistency of the input data whenever possible but may go nuts
-  for some forms of corrupted input.
-*/
-
-typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
-typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
-
-struct internal_state;
-
-typedef struct z_stream_s {
-    Bytef    *next_in;  /* next input byte */
-    uInt     avail_in;  /* number of bytes available at next_in */
-    uLong    total_in;  /* total nb of input bytes read so far */
-
-    Bytef    *next_out; /* next output byte should be put there */
-    uInt     avail_out; /* remaining free space at next_out */
-    uLong    total_out; /* total nb of bytes output so far */
-
-    char     *msg;      /* last error message, NULL if no error */
-    struct internal_state FAR *state; /* not visible by applications */
-
-    alloc_func zalloc;  /* used to allocate the internal state */
-    free_func  zfree;   /* used to free the internal state */
-    voidpf     opaque;  /* private data object passed to zalloc and zfree */
-
-    int     data_type;  /* best guess about the data type: ascii or binary */
-    uLong   adler;      /* adler32 value of the uncompressed data */
-    uLong   reserved;   /* reserved for future use */
-} z_stream;
-
-typedef z_stream FAR *z_streamp;
-
-/*
-   The application must update next_in and avail_in when avail_in has
-   dropped to zero. It must update next_out and avail_out when avail_out
-   has dropped to zero. The application must initialize zalloc, zfree and
-   opaque before calling the init function. All other fields are set by the
-   compression library and must not be updated by the application.
-
-   The opaque value provided by the application will be passed as the first
-   parameter for calls of zalloc and zfree. This can be useful for custom
-   memory management. The compression library attaches no meaning to the
-   opaque value.
-
-   zalloc must return Z_NULL if there is not enough memory for the object.
-   On 16-bit systems, the functions zalloc and zfree must be able to allocate
-   exactly 65536 bytes, but will not be required to allocate more than this
-   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
-   pointers returned by zalloc for objects of exactly 65536 bytes *must*
-   have their offset normalized to zero. The default allocation function
-   provided by this library ensures this (see zutil.c). To reduce memory
-   requirements and avoid any allocation of 64K objects, at the expense of
-   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
-
-   The fields total_in and total_out can be used for statistics or
-   progress reports. After compression, total_in holds the total size of
-   the uncompressed data and may be saved for use in the decompressor
-   (particularly if the decompressor wants to decompress everything in
-   a single step).
-*/
-
-                        /* constants */
-
-#define Z_NO_FLUSH      0
-#define Z_PARTIAL_FLUSH 1
-#define Z_PACKET_FLUSH	2
-#define Z_SYNC_FLUSH    3
-#define Z_FULL_FLUSH    4
-#define Z_FINISH        5
-/* Allowed flush values; see deflate() below for details */
-
-#define Z_OK            0
-#define Z_STREAM_END    1
-#define Z_NEED_DICT     2
-#define Z_ERRNO        (-1)
-#define Z_STREAM_ERROR (-2)
-#define Z_DATA_ERROR   (-3)
-#define Z_MEM_ERROR    (-4)
-#define Z_BUF_ERROR    (-5)
-#define Z_VERSION_ERROR (-6)
-/* Return codes for the compression/decompression functions. Negative
- * values are errors, positive values are used for special but normal events.
- */
-
-#define Z_NO_COMPRESSION         0
-#define Z_BEST_SPEED             1
-#define Z_BEST_COMPRESSION       9
-#define Z_DEFAULT_COMPRESSION  (-1)
-/* compression levels */
-
-#define Z_FILTERED            1
-#define Z_HUFFMAN_ONLY        2
-#define Z_DEFAULT_STRATEGY    0
-/* compression strategy; see deflateInit2() below for details */
-
-#define Z_BINARY   0
-#define Z_ASCII    1
-#define Z_UNKNOWN  2
-/* Possible values of the data_type field */
-
-#define Z_DEFLATED   8
-/* The deflate compression method (the only one supported in this version) */
-
-#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
-
-#define zlib_version zlibVersion()
-/* for compatibility with versions < 1.0.2 */
-
-                        /* basic functions */
-
-extern const char * EXPORT zlibVersion OF((void));
-/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
-   If the first character differs, the library code actually used is
-   not compatible with the zlib.h header file used by the application.
-   This check is automatically made by deflateInit and inflateInit.
- */
-
-/* 
-extern int EXPORT deflateInit OF((z_streamp strm, int level));
-
-     Initializes the internal stream state for compression. The fields
-   zalloc, zfree and opaque must be initialized before by the caller.
-   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
-   use default allocation functions.
-
-     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
-   1 gives best speed, 9 gives best compression, 0 gives no compression at
-   all (the input data is simply copied a block at a time).
-   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
-   compression (currently equivalent to level 6).
-
-     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
-   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
-   with the version assumed by the caller (ZLIB_VERSION).
-   msg is set to null if there is no error message.  deflateInit does not
-   perform any compression: this will be done by deflate().
-*/
-
-
-extern int EXPORT deflate OF((z_streamp strm, int flush));
-/*
-  Performs one or both of the following actions:
-
-  - Compress more input starting at next_in and update next_in and avail_in
-    accordingly. If not all input can be processed (because there is not
-    enough room in the output buffer), next_in and avail_in are updated and
-    processing will resume at this point for the next call of deflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly. This action is forced if the parameter flush is non zero.
-    Forcing flush frequently degrades the compression ratio, so this parameter
-    should be set only when necessary (in interactive applications).
-    Some output may be provided even if flush is not set.
-
-  Before the call of deflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating avail_in or avail_out accordingly; avail_out
-  should never be zero before the call. The application can consume the
-  compressed output when it wants, for example when the output buffer is full
-  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
-  and with zero avail_out, it must be called again after making room in the
-  output buffer because there might be more output pending.
-
-    If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
-  block is terminated and flushed to the output buffer so that the
-  decompressor can get all input data available so far. For method 9, a future
-  variant on method 8, the current block will be flushed but not terminated.
-  Z_SYNC_FLUSH has the same effect as partial flush except that the compressed
-  output is byte aligned (the compressor can clear its internal bit buffer)
-  and the current block is always terminated; this can be useful if the
-  compressor has to be restarted from scratch after an interruption (in which
-  case the internal state of the compressor may be lost).
-    If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
-  special marker is output and the compression dictionary is discarded; this
-  is useful to allow the decompressor to synchronize if one compressed block
-  has been damaged (see inflateSync below).  Flushing degrades compression and
-  so should be used only when necessary.  Using Z_FULL_FLUSH too often can
-  seriously degrade the compression. If deflate returns with avail_out == 0,
-  this function must be called again with the same value of the flush
-  parameter and more output space (updated avail_out), until the flush is
-  complete (deflate returns with non-zero avail_out).
-
-    If the parameter flush is set to Z_PACKET_FLUSH, the compression
-  block is terminated, and a zero-length stored block is output,
-  omitting the length bytes (the effect of this is that the 3-bit type
-  code 000 for a stored block is output, and the output is then
-  byte-aligned).  This is designed for use at the end of a PPP packet.
-
-    If the parameter flush is set to Z_FINISH, pending input is processed,
-  pending output is flushed and deflate returns with Z_STREAM_END if there
-  was enough output space; if deflate returns with Z_OK, this function must be
-  called again with Z_FINISH and more output space (updated avail_out) but no
-  more input data, until it returns with Z_STREAM_END or an error. After
-  deflate has returned Z_STREAM_END, the only possible operations on the
-  stream are deflateReset or deflateEnd.
-  
-    Z_FINISH can be used immediately after deflateInit if all the compression
-  is to be done in a single step. In this case, avail_out must be at least
-  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
-  Z_STREAM_END, then it must be called again as described above.
-
-    deflate() may update data_type if it can make a good guess about
-  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
-  binary. This field is only for information purposes and does not affect
-  the compression algorithm in any manner.
-
-    deflate() returns Z_OK if some progress has been made (more input
-  processed or more output produced), Z_STREAM_END if all input has been
-  consumed and all output has been produced (only when flush is set to
-  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
-  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible.
-*/
-
-
-extern int EXPORT deflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
-   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
-   prematurely (some input or output was discarded). In the error case,
-   msg may be set but then points to a static string (which must not be
-   deallocated).
-*/
-
-
-/* 
-extern int EXPORT inflateInit OF((z_streamp strm));
-
-     Initializes the internal stream state for decompression. The fields
-   zalloc, zfree and opaque must be initialized before by the caller.  If
-   zalloc and zfree are set to Z_NULL, inflateInit updates them to use default
-   allocation functions.
-
-     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_VERSION_ERROR if the zlib library version is incompatible
-   with the version assumed by the caller.  msg is set to null if there is no
-   error message. inflateInit does not perform any decompression: this will be
-   done by inflate().
-*/
-
-
-extern int EXPORT inflate OF((z_streamp strm, int flush));
-/*
-  Performs one or both of the following actions:
-
-  - Decompress more input starting at next_in and update next_in and avail_in
-    accordingly. If not all input can be processed (because there is not
-    enough room in the output buffer), next_in is updated and processing
-    will resume at this point for the next call of inflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly.  inflate() provides as much output as possible, until there
-    is no more input data or no more space in the output buffer (see below
-    about the flush parameter).
-
-  Before the call of inflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating the next_* and avail_* values accordingly.
-  The application can consume the uncompressed output when it wants, for
-  example when the output buffer is full (avail_out == 0), or after each
-  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
-  must be called again after making room in the output buffer because there
-  might be more output pending.
-
-    If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
-  inflate flushes as much output as possible to the output buffer. The
-  flushing behavior of inflate is not specified for values of the flush
-  parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
-  current implementation actually flushes as much output as possible
-  anyway.  For Z_PACKET_FLUSH, inflate checks that once all the input data
-  has been consumed, it is expecting to see the length field of a stored
-  block; if not, it returns Z_DATA_ERROR.
-
-    inflate() should normally be called until it returns Z_STREAM_END or an
-  error. However if all decompression is to be performed in a single step
-  (a single call of inflate), the parameter flush should be set to
-  Z_FINISH. In this case all pending input is processed and all pending
-  output is flushed; avail_out must be large enough to hold all the
-  uncompressed data. (The size of the uncompressed data may have been saved
-  by the compressor for this purpose.) The next operation on this stream must
-  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
-  is never required, but can be used to inform inflate that a faster routine
-  may be used for the single inflate() call.
-
-    inflate() returns Z_OK if some progress has been made (more input
-  processed or more output produced), Z_STREAM_END if the end of the
-  compressed data has been reached and all uncompressed output has been
-  produced, Z_NEED_DICT if a preset dictionary is needed at this point (see
-  inflateSetDictionary below), Z_DATA_ERROR if the input data was corrupted,
-  Z_STREAM_ERROR if the stream structure was inconsistent (for example if
-  next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
-  Z_BUF_ERROR if no progress is possible or if there was not enough room in
-  the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the
-  application may then call inflateSync to look for a good compression block.
-  In the Z_NEED_DICT case, strm->adler is set to the Adler32 value of the
-  dictionary chosen by the compressor.
-*/
-
-
-extern int EXPORT inflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
-   was inconsistent. In the error case, msg may be set but then points to a
-   static string (which must not be deallocated).
-*/
-
-                        /* Advanced functions */
-
-/*
-    The following functions are needed only in some special applications.
-*/
-
-/*   
-extern int EXPORT deflateInit2 OF((z_streamp strm,
-                                   int  level,
-                                   int  method,
-                                   int  windowBits,
-                                   int  memLevel,
-                                   int  strategy));
-
-     This is another version of deflateInit with more compression options. The
-   fields next_in, zalloc, zfree and opaque must be initialized before by
-   the caller.
-
-     The method parameter is the compression method. It must be Z_DEFLATED in
-   this version of the library. (Method 9 will allow a 64K history buffer and
-   partial block flushes.)
-
-     The windowBits parameter is the base two logarithm of the window size
-   (the size of the history buffer).  It should be in the range 8..15 for this
-   version of the library (the value 16 will be allowed for method 9). Larger
-   values of this parameter result in better compression at the expense of
-   memory usage. The default value is 15 if deflateInit is used instead.
-
-     The memLevel parameter specifies how much memory should be allocated
-   for the internal compression state. memLevel=1 uses minimum memory but
-   is slow and reduces compression ratio; memLevel=9 uses maximum memory
-   for optimal speed. The default value is 8. See zconf.h for total memory
-   usage as a function of windowBits and memLevel.
-
-     The strategy parameter is used to tune the compression algorithm. Use the
-   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
-   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
-   string match).  Filtered data consists mostly of small values with a
-   somewhat random distribution. In this case, the compression algorithm is
-   tuned to compress them better. The effect of Z_FILTERED is to force more
-   Huffman coding and less string matching; it is somewhat intermediate
-   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
-   the compression ratio but not the correctness of the compressed output even
-   if it is not set appropriately.
-
-     If next_in is not null, the library will use this buffer to hold also
-   some history information; the buffer must either hold the entire input
-   data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in
-   is null, the library will allocate its own history buffer (and leave next_in
-   null). next_out need not be provided here but must be provided by the
-   application for the next call of deflate().
-
-     If the history buffer is provided by the application, next_in must
-   must never be changed by the application since the compressor maintains
-   information inside this buffer from call to call; the application
-   must provide more input only by increasing avail_in. next_in is always
-   reset by the library in this case.
-
-      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
-   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
-   an invalid method). msg is set to null if there is no error message.
-   deflateInit2 does not perform any compression: this will be done by
-   deflate(). 
-*/
-                            
-extern int EXPORT deflateSetDictionary OF((z_streamp strm,
-                                           const Bytef *dictionary,
-				           uInt  dictLength));
-/*
-     Initializes the compression dictionary (history buffer) from the given
-   byte sequence without producing any compressed output. This function must
-   be called immediately after deflateInit or deflateInit2, before any call
-   of deflate. The compressor and decompressor must use exactly the same
-   dictionary (see inflateSetDictionary).
-     The dictionary should consist of strings (byte sequences) that are likely
-   to be encountered later in the data to be compressed, with the most commonly
-   used strings preferably put towards the end of the dictionary. Using a
-   dictionary is most useful when the data to be compressed is short and
-   can be predicted with good accuracy; the data can then be compressed better
-   than with the default empty dictionary. In this version of the library,
-   only the last 32K bytes of the dictionary are used.
-     Upon return of this function, strm->adler is set to the Adler32 value
-   of the dictionary; the decompressor may later use this value to determine
-   which dictionary has been used by the compressor. (The Adler32 value
-   applies to the whole dictionary even if only a subset of the dictionary is
-   actually used by the compressor.)
-
-     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state
-   is inconsistent (for example if deflate has already been called for this
-   stream). deflateSetDictionary does not perform any compression: this will
-   be done by deflate(). 
-*/
-
-extern int EXPORT deflateCopy OF((z_streamp dest,
-                                  z_streamp source));
-/*
-     Sets the destination stream as a complete copy of the source stream.  If
-   the source stream is using an application-supplied history buffer, a new
-   buffer is allocated for the destination stream.  The compressed output
-   buffer is always application-supplied. It's the responsibility of the
-   application to provide the correct values of next_out and avail_out for the
-   next call of deflate.
-
-     This function can be useful when several compression strategies will be
-   tried, for example when there are several ways of pre-processing the input
-   data with a filter. The streams that will be discarded should then be freed
-   by calling deflateEnd.  Note that deflateCopy duplicates the internal
-   compression state which can be quite large, so this strategy is slow and
-   can consume lots of memory.
-
-     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
-   (such as zalloc being NULL). msg is left unchanged in both source and
-   destination.
-*/
-
-extern int EXPORT deflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to deflateEnd followed by deflateInit,
-   but does not free and reallocate all the internal compression state.
-   The stream will keep the same compression level and any other attributes
-   that may have been set by deflateInit2.
-
-      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent (such as zalloc or state being NULL).
-*/
-
-extern int EXPORT deflateParams OF((z_streamp strm, int level, int strategy));
-/*
-     Dynamically update the compression level and compression strategy.
-   This can be used to switch between compression and straight copy of
-   the input data, or to switch to a different kind of input data requiring
-   a different strategy. If the compression level is changed, the input
-   available so far is compressed with the old level (and may be flushed);
-   the new level will take effect only at the next call of deflate().
-
-     Before the call of deflateParams, the stream state must be set as for
-   a call of deflate(), since the currently available input may have to
-   be compressed and flushed. In particular, strm->avail_out must be non-zero.
-
-     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
-   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
-   if strm->avail_out was zero.
-*/
-
-extern int EXPORT deflateOutputPending OF((z_streamp strm));
-/*
-     Returns the number of bytes of output which are immediately
-   available from the compressor (i.e. without any further input
-   or flush).
-*/
-
-/*   
-extern int EXPORT inflateInit2 OF((z_streamp strm,
-                                   int  windowBits));
-
-     This is another version of inflateInit with more compression options. The
-   fields next_out, zalloc, zfree and opaque must be initialized before by
-   the caller.
-
-     The windowBits parameter is the base two logarithm of the maximum window
-   size (the size of the history buffer).  It should be in the range 8..15 for
-   this version of the library (the value 16 will be allowed soon). The
-   default value is 15 if inflateInit is used instead. If a compressed stream
-   with a larger window size is given as input, inflate() will return with
-   the error code Z_DATA_ERROR instead of trying to allocate a larger window.
-
-     If next_out is not null, the library will use this buffer for the history
-   buffer; the buffer must either be large enough to hold the entire output
-   data, or have at least 1<<windowBits bytes.  If next_out is null, the
-   library will allocate its own buffer (and leave next_out null). next_in
-   need not be provided here but must be provided by the application for the
-   next call of inflate().
-
-     If the history buffer is provided by the application, next_out must
-   never be changed by the application since the decompressor maintains
-   history information inside this buffer from call to call; the application
-   can only reset next_out to the beginning of the history buffer when
-   avail_out is zero and all output has been consumed.
-
-      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
-   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
-   windowBits < 8). msg is set to null if there is no error message.
-   inflateInit2 does not perform any decompression: this will be done by
-   inflate().
-*/
-
-extern int EXPORT inflateSetDictionary OF((z_streamp strm,
-				           const Bytef *dictionary,
-					   uInt  dictLength));
-/*
-     Initializes the decompression dictionary (history buffer) from the given
-   uncompressed byte sequence. This function must be called immediately after
-   a call of inflate if this call returned Z_NEED_DICT. The dictionary chosen
-   by the compressor can be determined from the Adler32 value returned by this
-   call of inflate. The compressor and decompressor must use exactly the same
-   dictionary (see deflateSetDictionary).
-
-     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state is
-   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
-   expected one (incorrect Adler32 value). inflateSetDictionary does not
-   perform any decompression: this will be done by subsequent calls of
-   inflate().
-*/
-
-extern int EXPORT inflateSync OF((z_streamp strm));
-/* 
-    Skips invalid compressed data until the special marker (see deflate()
-  above) can be found, or until all available input is skipped. No output
-  is provided.
-
-    inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
-  if no more input was provided, Z_DATA_ERROR if no marker has been found,
-  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
-  case, the application may save the current current value of total_in which
-  indicates where valid compressed data was found. In the error case, the
-  application may repeatedly call inflateSync, providing more input each time,
-  until success or end of the input data.
-*/
-
-extern int EXPORT inflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to inflateEnd followed by inflateInit,
-   but does not free and reallocate all the internal decompression state.
-   The stream will keep attributes that may have been set by inflateInit2.
-
-      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent (such as zalloc or state being NULL).
-*/
-
-extern int inflateIncomp OF((z_stream *strm));
-/*
-     This function adds the data at next_in (avail_in bytes) to the output
-   history without performing any output.  There must be no pending output,
-   and the decompressor must be expecting to see the start of a block.
-   Calling this function is equivalent to decompressing a stored block
-   containing the data at next_in (except that the data is not output).
-*/
-
-                        /* utility functions */
-
-/*
-     The following utility functions are implemented on top of the
-   basic stream-oriented functions. To simplify the interface, some
-   default options are assumed (compression level, window size,
-   standard memory allocation functions). The source code of these
-   utility functions can easily be modified if you need special options.
-*/
-
-extern int EXPORT compress OF((Bytef *dest,   uLongf *destLen,
-			       const Bytef *source, uLong sourceLen));
-/*
-     Compresses the source buffer into the destination buffer.  sourceLen is
-   the byte length of the source buffer. Upon entry, destLen is the total
-   size of the destination buffer, which must be at least 0.1% larger than
-   sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
-   compressed buffer.
-     This function can be used to compress a whole file at once if the
-   input file is mmap'ed.
-     compress returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_BUF_ERROR if there was not enough room in the output
-   buffer.
-*/
-
-extern int EXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
-				 const Bytef *source, uLong sourceLen));
-/*
-     Decompresses the source buffer into the destination buffer.  sourceLen is
-   the byte length of the source buffer. Upon entry, destLen is the total
-   size of the destination buffer, which must be large enough to hold the
-   entire uncompressed data. (The size of the uncompressed data must have
-   been saved previously by the compressor and transmitted to the decompressor
-   by some mechanism outside the scope of this compression library.)
-   Upon exit, destLen is the actual size of the compressed buffer.
-     This function can be used to decompress a whole file at once if the
-   input file is mmap'ed.
-
-     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_BUF_ERROR if there was not enough room in the output
-   buffer, or Z_DATA_ERROR if the input data was corrupted.
-*/
-
-
-typedef voidp gzFile;
-
-extern gzFile EXPORT gzopen  OF((const char *path, const char *mode));
-/*
-     Opens a gzip (.gz) file for reading or writing. The mode parameter
-   is as in fopen ("rb" or "wb") but can also include a compression level
-   ("wb9").  gzopen can be used to read a file which is not in gzip format;
-   in this case gzread will directly read from the file without decompression.
-     gzopen returns NULL if the file could not be opened or if there was
-   insufficient memory to allocate the (de)compression state; errno
-   can be checked to distinguish the two cases (if errno is zero, the
-   zlib error is Z_MEM_ERROR).
-*/
-
-extern gzFile EXPORT gzdopen  OF((int fd, const char *mode));
-/*
-     gzdopen() associates a gzFile with the file descriptor fd.  File
-   descriptors are obtained from calls like open, dup, creat, pipe or
-   fileno (in the file has been previously opened with fopen).
-   The mode parameter is as in gzopen.
-     The next call of gzclose on the returned gzFile will also close the
-   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
-   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
-     gzdopen returns NULL if there was insufficient memory to allocate
-   the (de)compression state.
-*/
-
-extern int EXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
-/*
-     Reads the given number of uncompressed bytes from the compressed file.
-   If the input file was not in gzip format, gzread copies the given number
-   of bytes into the buffer.
-     gzread returns the number of uncompressed bytes actually read (0 for
-   end of file, -1 for error). */
-
-extern int EXPORT    gzwrite OF((gzFile file, const voidp buf, unsigned len));
-/*
-     Writes the given number of uncompressed bytes into the compressed file.
-   gzwrite returns the number of uncompressed bytes actually written
-   (0 in case of error).
-*/
-
-extern int EXPORT    gzflush OF((gzFile file, int flush));
-/*
-     Flushes all pending output into the compressed file. The parameter
-   flush is as in the deflate() function. The return value is the zlib
-   error number (see function gzerror below). gzflush returns Z_OK if
-   the flush parameter is Z_FINISH and all output could be flushed.
-     gzflush should be called only when strictly necessary because it can
-   degrade compression.
-*/
-
-extern int EXPORT    gzclose OF((gzFile file));
-/*
-     Flushes all pending output if necessary, closes the compressed file
-   and deallocates all the (de)compression state. The return value is the zlib
-   error number (see function gzerror below).
-*/
-
-extern const char * EXPORT gzerror OF((gzFile file, int *errnum));
-/*
-     Returns the error message for the last error which occurred on the
-   given compressed file. errnum is set to zlib error number. If an
-   error occurred in the file system and not in the compression library,
-   errnum is set to Z_ERRNO and the application may consult errno
-   to get the exact error code.
-*/
-
-                        /* checksum functions */
-
-/*
-     These functions are not related to compression but are exported
-   anyway because they might be useful in applications using the
-   compression library.
-*/
-
-extern uLong EXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
-
-/*
-     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
-   return the updated checksum. If buf is NULL, this function returns
-   the required initial value for the checksum.
-   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
-   much faster. Usage example:
-
-     uLong adler = adler32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       adler = adler32(adler, buffer, length);
-     }
-     if (adler != original_adler) error();
-*/
-
-extern uLong EXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
-/*
-     Update a running crc with the bytes buf[0..len-1] and return the updated
-   crc. If buf is NULL, this function returns the required initial value
-   for the crc. Pre- and post-conditioning (one's complement) is performed
-   within this function so it shouldn't be done by the application.
-   Usage example:
-
-     uLong crc = crc32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       crc = crc32(crc, buffer, length);
-     }
-     if (crc != original_crc) error();
-*/
-
-
-                        /* various hacks, don't look :) */
-
-/* deflateInit and inflateInit are macros to allow checking the zlib version
- * and the compiler's view of z_stream:
- */
-extern int EXPORT deflateInit_ OF((z_streamp strm, int level,
-			           const char *version, int stream_size));
-extern int EXPORT inflateInit_ OF((z_streamp strm,
-				   const char *version, int stream_size));
-extern int EXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
-				    int windowBits, int memLevel, int strategy,
-				    const char *version, int stream_size));
-extern int EXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
-				    const char *version, int stream_size));
-#define deflateInit(strm, level) \
-        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
-#define inflateInit(strm) \
-        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
-#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
-        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
-		      (strategy),           ZLIB_VERSION, sizeof(z_stream))
-#define inflateInit2(strm, windowBits) \
-        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
-
-#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
-    struct internal_state {int dummy;}; /* hack for buggy compilers */
-#endif
-
-uLongf *get_crc_table OF((void)); /* can be used by asm versions of crc32() */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ZLIB_H */
-/* --- zlib.h */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/nubus/nubus.c linux-2.4.20/drivers/nubus/nubus.c
--- linux-2.4.19/drivers/nubus/nubus.c	2001-06-28 00:10:55.000000000 +0000
+++ linux-2.4.20/drivers/nubus/nubus.c	2002-10-29 11:18:34.000000000 +0000
@@ -72,7 +72,7 @@
    Etcetera, etcetera.  Hopefully this clears up some confusion over
    what the following code actually does.  */
  
-extern inline int not_useful(void *p, int map)
+static inline int not_useful(void *p, int map)
 {
 	unsigned long pv=(unsigned long)p;
 	pv &= 3;
@@ -148,14 +148,14 @@
    have to expand it from a 24-bit signed number to a 32-bit signed
    number. */
 
-extern inline long nubus_expand32(long foo)
+static inline long nubus_expand32(long foo)
 {
 	if(foo & 0x00800000)	/* 24bit negative */
 		foo |= 0xFF000000;
 	return foo;
 }
 
-extern inline void *nubus_rom_addr(int slot)
+static inline void *nubus_rom_addr(int slot)
 {	
 	/*
 	 *	Returns the first byte after the card. We then walk
@@ -961,18 +961,18 @@
 	return strlen(ptr);
 }
 
-static int nubus_read_proc(char *buf, char **start, off_t off,
+static int nubus_read_proc(char *page, char **start, off_t off,
 				int count, int *eof, void *data)
 {
 	int nprinted, len, begin = 0;
-	int slot,size;
+	int size = PAGE_SIZE;
 	struct nubus_board* board;
 	
-	len   = sprintf(buf, "Nubus devices found:\n");
+	len   = sprintf(page, "Nubus devices found:\n");
 	/* Walk the list of NuBus boards */
 	for (board = nubus_boards; board != NULL; board = board->next)
 	{
-		nprinted = sprint_nubus_board(board, buf + len, size - len);
+		nprinted = sprint_nubus_board(board, page + len, size - len);
 		if (nprinted < 0)
 			break;
 		len += nprinted;
@@ -983,10 +983,10 @@
 		if (len+begin >= off+count)
 			break;
 	}
-	if (slot==16 || len+begin < off)
+	if (len+begin < off)
 		*eof = 1;
 	off -= begin;
-	*start = buf + off;
+	*start = page + off;
 	len -= off;
 	if (len>count)
 		len = count;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/parport/init.c linux-2.4.20/drivers/parport/init.c
--- linux-2.4.19/drivers/parport/init.c	2001-07-10 23:07:46.000000000 +0000
+++ linux-2.4.20/drivers/parport/init.c	2002-10-29 11:18:48.000000000 +0000
@@ -31,6 +31,7 @@
 extern int parport_sunbpp_init(void);
 extern int parport_amiga_init(void);
 extern int parport_mfc3_init(void);
+extern int parport_atari_init(void);
 
 static int parport_setup_ptr __initdata = 0;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/parport/parport_gsc.c linux-2.4.20/drivers/parport/parport_gsc.c
--- linux-2.4.19/drivers/parport/parport_gsc.c	2001-05-23 02:54:04.000000000 +0000
+++ linux-2.4.20/drivers/parport/parport_gsc.c	2002-10-29 11:18:36.000000000 +0000
@@ -7,7 +7,7 @@
  *      the Free Software Foundation; either version 2 of the License, or
  *      (at your option) any later version.
  *
- *	by Helge Deller <deller@gmx.de>
+ *	(C) 1999-2001 by Helge Deller <deller@gmx.de>
  *
  * 
  * based on parport_pc.c by 
@@ -36,6 +36,7 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/uaccess.h>
+#include <asm/superio.h>
 
 #include <linux/parport.h>
 #include <asm/gsc.h>
@@ -47,6 +48,7 @@
 MODULE_AUTHOR("Helge Deller <deller@gmx.de>");
 MODULE_DESCRIPTION("HP-PARISC PC-style parallel port driver");
 MODULE_SUPPORTED_DEVICE("integrated PC-style parallel port");
+MODULE_LICENSE("GPL");
 
 
 /*
@@ -347,13 +349,6 @@
 	struct parport tmp;
 	struct parport *p = &tmp;
 
-#if 1
-#warning Take this out when region handling works again, <deller@gmx,de>
-#else
-	if (check_region(base, 3)) 
-	    return NULL;
-#endif
-	    
 	priv = kmalloc (sizeof (struct parport_gsc_private), GFP_KERNEL);
 	if (!priv) {
 		printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
@@ -430,12 +425,6 @@
 	printk("]\n");
 	parport_proc_register(p);
 
-	request_region (p->base, 3, p->name);
-	if (p->size > 3)
-		request_region (p->base + 3, p->size - 3, p->name);
-	if (p->modes & PARPORT_MODE_ECP)
-		request_region (p->base_hi, 3, p->name);
-
 	if (p->irq != PARPORT_IRQ_NONE) {
 		if (request_irq (p->irq, parport_gsc_interrupt,
 				 0, p->name, p)) {
@@ -465,62 +454,56 @@
 
 static int __initdata parport_count;
 
-static int __init parport_init_chip(struct hp_device *d, struct pa_iodc_driver *dri)
+static int __devinit parport_init_chip(struct parisc_device *dev)
 {
 	unsigned long port;
-	int irq;
-
-	irq = busdevice_alloc_irq(d); 
 
-	if (!irq) {
-	    printk(KERN_DEBUG "IRQ not found for parallel device at 0x%p\n", d->hpa);
-	    return -ENODEV;
+	if (!dev->irq) {
+		printk("IRQ not found for parallel device at 0x%lx\n", dev->hpa);
+		return -ENODEV;
 	}
 
-	port = ((unsigned long) d->hpa) + PARPORT_GSC_OFFSET;
+	port = dev->hpa + PARPORT_GSC_OFFSET;
 	
-	/* 
-	    some older machines with ASP-chip don't support the enhanced parport modes 
-	*/
-	if (!pdc_add_valid( (void *)(port+4))) {
-	    /* Initialize bidirectional-mode (0x10) & data-tranfer-mode #1 (0x20) */
-	    printk(KERN_DEBUG "%s: initialize bidirectional-mode.\n", __FUNCTION__);
-	    parport_writeb ( (0x10 + 0x20), port + 4);
+	/* some older machines with ASP-chip don't support
+	 * the enhanced parport modes.
+	 */
+	if (boot_cpu_data.cpu_type > pcxt && !pdc_add_valid(port+4)) {
+
+		/* Initialize bidirectional-mode (0x10) & data-tranfer-mode #1 (0x20) */
+		printk("%s: initialize bidirectional-mode.\n", __FUNCTION__);
+		parport_writeb ( (0x10 + 0x20), port + 4);
+
 	} else {
-	    printk(KERN_DEBUG "%s: enhanced parport-modes not supported.\n", __FUNCTION__);
+		printk("%s: enhanced parport-modes not supported.\n", __FUNCTION__);
 	}
 	
-	if (parport_gsc_probe_port(port, 0, 
-		    irq, /* PARPORT_IRQ_NONE */
-		    PARPORT_DMA_NONE, NULL))
-	    parport_count++;
+	if (parport_gsc_probe_port(port, 0, dev->irq,
+			/* PARPORT_IRQ_NONE */ PARPORT_DMA_NONE, NULL))
+		parport_count++;
 
 	return 0;
 }
 
-static struct pa_iodc_driver parport_drivers_for[] __initdata = {
-  {HPHW_FIO, 0x0, 0x0, 0x74, 0x0, 0,			/* 715/64 */
-	DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-	"parallel device", "HP 7xx - Series", (void *) parport_init_chip},
-  { 0 }
+static struct parisc_device_id parport_tbl[] = {
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x74 },
+	{ 0, }
 };
 
-int __init parport_gsc_init(void)
-{
-	parport_count = 0;
-	
-	register_driver(parport_drivers_for);
-
-	return 0;
-}
+MODULE_DEVICE_TABLE(parisc, parport_tbl);
 
+static struct parisc_driver parport_driver = {
+	name:		"Parallel",
+	id_table:	parport_tbl,
+	probe:		parport_init_chip,
+};
 
-static int __init parport_gsc_init_module(void)
-{	
-	return !parport_gsc_init();
+int __devinit parport_gsc_init(void)
+{
+	return register_parisc_driver(&parport_driver);
 }
 
-static void __exit parport_gsc_exit_module(void)
+static void __devexit parport_gsc_exit(void)
 {
 	struct parport *p = parport_enumerate(), *tmp;
 	while (p) {
@@ -532,11 +515,6 @@
 				free_dma(p->dma);
 			if (p->irq != PARPORT_IRQ_NONE)
 				free_irq(p->irq, p);
-			release_region(p->base, 3);
-			if (p->size > 3)
-				release_region(p->base + 3, p->size - 3);
-			if (p->modes & PARPORT_MODE_ECP)
-				release_region(p->base_hi, 3);
 			parport_proc_unregister(p);
 			if (priv->dma_buf)
 				pci_free_consistent(priv->dev, PAGE_SIZE,
@@ -548,9 +526,10 @@
 		}
 		p = tmp;
 	}
+	unregister_parisc_driver(&parport_driver);
 }
 
 EXPORT_NO_SYMBOLS;
 
-module_init(parport_gsc_init_module);
-module_exit(parport_gsc_exit_module);
+module_init(parport_gsc_init);
+module_exit(parport_gsc_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/parport/parport_mfc3.c linux-2.4.20/drivers/parport/parport_mfc3.c
--- linux-2.4.19/drivers/parport/parport_mfc3.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/parport/parport_mfc3.c	2002-10-29 11:18:36.000000000 +0000
@@ -332,7 +332,7 @@
 int __init parport_mfc3_init(void)
 {
 	struct parport *p;
-	int pias;
+	int pias = 0;
 	struct pia *pp;
 	struct zorro_dev *z = NULL;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/parport/parport_pc.c linux-2.4.20/drivers/parport/parport_pc.c
--- linux-2.4.19/drivers/parport/parport_pc.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/parport/parport_pc.c	2002-10-29 11:18:39.000000000 +0000
@@ -2409,7 +2409,9 @@
 
 void parport_pc_unregister_port (struct parport *p)
 {
+#ifdef CONFIG_PARPORT_PC_FIFO
 	struct parport_pc_private *priv = p->private_data;
+#endif /* CONFIG_PARPORT_PC_FIFO */
 	struct parport_operations *ops = p->ops;
 	if (p->dma != PARPORT_DMA_NONE)
 		free_dma(p->dma);
@@ -2421,10 +2423,12 @@
 	if (p->modes & PARPORT_MODE_ECP)
 		release_region(p->base_hi, 3);
 	parport_proc_unregister(p);
+#ifdef CONFIG_PARPORT_PC_FIFO
 	if (priv->dma_buf)
 		pci_free_consistent(priv->dev, PAGE_SIZE,
 				    priv->dma_buf,
 				    priv->dma_handle);
+#endif /* CONFIG_PARPORT_PC_FIFO */
 	kfree (p->private_data);
 	parport_unregister_port(p);
 	kfree (ops); /* hope no-one cached it */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pci/Makefile linux-2.4.20/drivers/pci/Makefile
--- linux-2.4.19/drivers/pci/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/pci/Makefile	2002-10-29 11:18:50.000000000 +0000
@@ -27,7 +27,7 @@
 obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o
 obj-$(CONFIG_PARISC) += setup-bus.o
 obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o
-obj-$(CONFIG_ALL_PPC) += setup-bus.o
+obj-$(CONFIG_PPC32) += setup-irq.o
 obj-$(CONFIG_SGI_IP27) += setup-irq.o
 obj-$(CONFIG_SGI_IP32) += setup-irq.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pci/pci.c linux-2.4.20/drivers/pci/pci.c
--- linux-2.4.19/drivers/pci/pci.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/pci/pci.c	2002-10-29 11:18:35.000000000 +0000
@@ -358,25 +358,41 @@
 }
 
 /**
- * pci_enable_device - Initialize device before it's used by a driver.
+ * pci_enable_device_bars - Initialize some of a device for use
  * @dev: PCI device to be initialized
+ * @bars: bitmask of BAR's that must be configured
  *
  *  Initialize device before it's used by a driver. Ask low-level code
- *  to enable I/O and memory. Wake up the device if it was suspended.
- *  Beware, this function can fail.
+ *  to enable selected I/O and memory resources. Wake up the device if it 
+ *  was suspended. Beware, this function can fail.
  */
+ 
 int
-pci_enable_device(struct pci_dev *dev)
+pci_enable_device_bars(struct pci_dev *dev, int bars)
 {
 	int err;
 
 	pci_set_power_state(dev, 0);
-	if ((err = pcibios_enable_device(dev)) < 0)
+	if ((err = pcibios_enable_device(dev, bars)) < 0)
 		return err;
 	return 0;
 }
 
 /**
+ * pci_enable_device - Initialize device before it's used by a driver.
+ * @dev: PCI device to be initialized
+ *
+ *  Initialize device before it's used by a driver. Ask low-level code
+ *  to enable I/O and memory. Wake up the device if it was suspended.
+ *  Beware, this function can fail.
+ */
+int
+pci_enable_device(struct pci_dev *dev)
+{
+	return pci_enable_device_bars(dev, 0x3F);
+}
+
+/**
  * pci_disable_device - Disable PCI device after use
  * @dev: PCI device to be disabled
  *
@@ -463,6 +479,69 @@
 }
 
 /**
+ *	pci_release_region - Release a PCI bar
+ *	@pdev: PCI device whose resources were previously reserved by pci_request_region
+ *	@bar: BAR to release
+ *
+ *	Releases the PCI I/O and memory resources previously reserved by a
+ *	successful call to pci_request_region.  Call this function only
+ *	after all use of the PCI regions has ceased.
+ */
+void pci_release_region(struct pci_dev *pdev, int bar)
+{
+	if (pci_resource_len(pdev, bar) == 0)
+		return;
+	if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
+		release_region(pci_resource_start(pdev, bar),
+				pci_resource_len(pdev, bar));
+	else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
+		release_mem_region(pci_resource_start(pdev, bar),
+				pci_resource_len(pdev, bar));
+}
+
+/**
+ *	pci_request_region - Reserved PCI I/O and memory resource
+ *	@pdev: PCI device whose resources are to be reserved
+ *	@bar: BAR to be reserved
+ *	@res_name: Name to be associated with resource.
+ *
+ *	Mark the PCI region associated with PCI device @pdev BR @bar as
+ *	being reserved by owner @res_name.  Do not access any
+ *	address inside the PCI regions unless this call returns
+ *	successfully.
+ *
+ *	Returns 0 on success, or %EBUSY on error.  A warning
+ *	message is also printed on failure.
+ */
+int pci_request_region(struct pci_dev *pdev, int bar, char *res_name)
+{
+	if (pci_resource_len(pdev, bar) == 0)
+		return 0;
+		
+	if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) {
+		if (!request_region(pci_resource_start(pdev, bar),
+			    pci_resource_len(pdev, bar), res_name))
+			goto err_out;
+	}
+	else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
+		if (!request_mem_region(pci_resource_start(pdev, bar),
+				        pci_resource_len(pdev, bar), res_name))
+			goto err_out;
+	}
+	
+	return 0;
+
+err_out:
+	printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%lx@%lx for device %s\n",
+		pci_resource_flags(pdev, bar) & IORESOURCE_IO ? "I/O" : "mem",
+		bar + 1, /* PCI BAR # */
+		pci_resource_len(pdev, bar), pci_resource_start(pdev, bar),
+		pdev->slot_name);
+	return -EBUSY;
+}
+
+
+/**
  *	pci_release_regions - Release reserved PCI I/O and memory resources
  *	@pdev: PCI device whose resources were previously reserved by pci_request_regions
  *
@@ -470,22 +549,13 @@
  *	successful call to pci_request_regions.  Call this function only
  *	after all use of the PCI regions has ceased.
  */
+
 void pci_release_regions(struct pci_dev *pdev)
 {
 	int i;
 	
-	for (i = 0; i < 6; i++) {
-		if (pci_resource_len(pdev, i) == 0)
-			continue;
-
-		if (pci_resource_flags(pdev, i) & IORESOURCE_IO)
-			release_region(pci_resource_start(pdev, i),
-				       pci_resource_len(pdev, i));
-
-		else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM)
-			release_mem_region(pci_resource_start(pdev, i),
-					   pci_resource_len(pdev, i));
-	}
+	for (i = 0; i < 6; i++)
+		pci_release_region(pdev, i);
 }
 
 /**
@@ -505,23 +575,9 @@
 {
 	int i;
 	
-	for (i = 0; i < 6; i++) {
-		if (pci_resource_len(pdev, i) == 0)
-			continue;
-
-		if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
-			if (!request_region(pci_resource_start(pdev, i),
-					    pci_resource_len(pdev, i), res_name))
-				goto err_out;
-		}
-		
-		else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
-			if (!request_mem_region(pci_resource_start(pdev, i),
-					        pci_resource_len(pdev, i), res_name))
-				goto err_out;
-		}
-	}
-	
+	for (i = 0; i < 6; i++)
+		if(pci_request_region(pdev, i, res_name))
+			goto err_out;
 	return 0;
 
 err_out:
@@ -530,7 +586,9 @@
 		i + 1, /* PCI BAR # */
 		pci_resource_len(pdev, i), pci_resource_start(pdev, i),
 		pdev->slot_name);
-	pci_release_regions(pdev);
+	while(--i >= 0)
+		pci_release_region(pdev, i);
+		
 	return -EBUSY;
 }
 
@@ -1073,6 +1131,13 @@
 	if (!dev)		/* It's a host bus, nothing to read */
 		return;
 
+	if (dev->transparent) {
+		printk("Transparent bridge - %s\n", dev->name);
+		for(i = 0; i < 4; i++)
+			child->resource[i] = child->parent->resource[i];
+		return;
+	}
+
 	for(i=0; i<3; i++)
 		child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
 
@@ -1094,14 +1159,6 @@
 		res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
 		res->start = base;
 		res->end = limit + 0xfff;
-		res->name = child->name;
-	} else {
-		/*
-		 * Ugh. We don't know enough about this bridge. Just assume
-		 * that it's entirely transparent.
-		 */
-		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 0);
-		child->resource[0] = child->parent->resource[0];
 	}
 
 	res = child->resource[1];
@@ -1113,11 +1170,6 @@
 		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
 		res->start = base;
 		res->end = limit + 0xfffff;
-		res->name = child->name;
-	} else {
-		/* See comment above. Same thing */
-		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 1);
-		child->resource[1] = child->parent->resource[1];
 	}
 
 	res = child->resource[2];
@@ -1144,11 +1196,6 @@
 		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
 		res->start = base;
 		res->end = limit + 0xfffff;
-		res->name = child->name;
-	} else {
-		/* See comments above */
-		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 2);
-		child->resource[2] = child->parent->resource[2];
 	}
 }
 
@@ -1190,9 +1237,11 @@
 	child->primary = parent->secondary;
 	child->subordinate = 0xff;
 
-	/* Set up default resource pointers.. */
-	for (i = 0; i < 4; i++)
+	/* Set up default resource pointers and names.. */
+	for (i = 0; i < 4; i++) {
 		child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+		child->resource[i]->name = child->name;
+	}
 
 	return child;
 }
@@ -1334,6 +1383,10 @@
 	case PCI_HEADER_TYPE_BRIDGE:		    /* bridge header */
 		if (class != PCI_CLASS_BRIDGE_PCI)
 			goto bad;
+		/* The PCI-to-PCI bridge spec requires that subtractive
+		   decoding (i.e. transparent) bridge must have programming
+		   interface code of 0x01. */ 
+		dev->transparent = ((class & 0xff) == 1);
 		pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
 		break;
 
@@ -1642,7 +1695,7 @@
 	return 0;
 }
 
-static int pci_pm_resume(void)
+int pci_pm_resume(void)
 {
 	struct list_head *list;
 	struct pci_bus *bus;
@@ -1662,10 +1715,10 @@
 
 	switch (rqst) {
 	case PM_SAVE_STATE:
-		error = pci_pm_save_state((u32)data);
+		error = pci_pm_save_state((unsigned long)data);
 		break;
 	case PM_SUSPEND:
-		error = pci_pm_suspend((u32)data);
+		error = pci_pm_suspend((unsigned long)data);
 		break;
 	case PM_RESUME:
 		error = pci_pm_resume();
@@ -2066,11 +2119,14 @@
 EXPORT_SYMBOL(pci_write_config_dword);
 EXPORT_SYMBOL(pci_devices);
 EXPORT_SYMBOL(pci_root_buses);
+EXPORT_SYMBOL(pci_enable_device_bars);
 EXPORT_SYMBOL(pci_enable_device);
 EXPORT_SYMBOL(pci_disable_device);
 EXPORT_SYMBOL(pci_find_capability);
 EXPORT_SYMBOL(pci_release_regions);
 EXPORT_SYMBOL(pci_request_regions);
+EXPORT_SYMBOL(pci_release_region);
+EXPORT_SYMBOL(pci_request_region);
 EXPORT_SYMBOL(pci_find_class);
 EXPORT_SYMBOL(pci_find_device);
 EXPORT_SYMBOL(pci_find_slot);
@@ -2096,11 +2152,13 @@
 EXPORT_SYMBOL(pci_add_new_bus);
 EXPORT_SYMBOL(pci_do_scan_bus);
 EXPORT_SYMBOL(pci_scan_slot);
+EXPORT_SYMBOL(pci_scan_bus);
 #ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(pci_proc_attach_device);
 EXPORT_SYMBOL(pci_proc_detach_device);
 EXPORT_SYMBOL(pci_proc_attach_bus);
 EXPORT_SYMBOL(pci_proc_detach_bus);
+EXPORT_SYMBOL(proc_bus_pci_dir);
 #endif
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pci/pci.ids linux-2.4.20/drivers/pci/pci.ids
--- linux-2.4.19/drivers/pci/pci.ids	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/pci/pci.ids	2002-10-29 11:18:30.000000000 +0000
@@ -7,7 +7,7 @@
 #	so if you have anything to contribute, please visit the home page or
 #	send a diff -u against the most recent pci.ids to pci-ids@ucw.cz.
 #
-#	$Id: pci.ids,v 1.39 2002/03/23 14:58:55 mares Exp $
+#	$Id: pci.ids,v 1.46 2002/08/14 17:38:51 mares Exp $
 #
 
 # Vendors, devices and subsystems. Please keep sorted.
@@ -73,12 +73,31 @@
 	ae6d  NorthStar CPU to PCI Bridge
 	b011  Integrated Netelligent 10/100
 	b012  Netelligent 10 T/2
+	b01e  NC3120 Fast Ethernet NIC
+	b01f  NC3122 Fast Ethernet NIC
 	b02f  NC1120 Ethernet NIC
 	b030  Netelligent WS 5100
+	b04a  10/100 TX PCI Intel WOL UTP Controller
 	b060  Smart Array 5300 Controller
+	b0c6  NC3161 Fast Ethernet NIC
+	b0c7  NC3160 Fast Ethernet NIC
+	b0d7  NC3121 Fast Ethernet NIC
+	b0dd  NC3131 Fast Ethernet NIC
+	b0de  NC3132 Fast Ethernet Module
+	b0df  NC6132 Gigabit Module
+	b0e0  NC6133 Gigabit Module
+	b0e1  NC3133 Fast Ethernet Module
+	b123  NC6134 Gigabit NIC
+	b134  NC3163 Fast Ethernet NIC
+	b13c  NC3162 Fast Ethernet NIC
+	b144  NC3123 Fast Ethernet NIC
+	b163  NC3134 Fast Ethernet NIC
+	b164  NC3165 Fast Ethernet Upgrade Module
 	b178  Smart Array 5i/532
+	b1a4  NC7131 Gigabit Server Adapter
 	f130  NetFlex-3/P ThunderLAN 1.0
 	f150  NetFlex-3/P ThunderLAN 2.3
+0e55  HaSoTec GmbH
 1000  LSI Logic / Symbios Logic (formerly NCR)
 	0001  53c810
 		1000 1000  8100S
@@ -90,6 +109,7 @@
 	000a  53c1510
 	000b  53c896
 	000c  53c895
+		1de1 3907  DC-390U2W
 	000d  53c885
 	000f  53c875
 		0e11 7004  Embedded Ultra Wide SCSI Controller
@@ -99,9 +119,12 @@
 		0e11 4040  Integrated Array Controller
 		0e11 4048  Integrated Array Controller
 	0012  53c895a
+	0013  53c875a
 	0020  53c1010 Ultra3 SCSI Adapter
+		1de1 1020  DC-390U3W
 	0021  53c1010 66MHz  Ultra3 SCSI Adapter
 	0030  53c1030
+		1028 1010  LSI U320 SCSI Controller
 	0040  53c1035
 	008f  53c875J
 		1092 8000  FirePort 40 SCSI Controller
@@ -120,7 +143,11 @@
 		1318 0000  PEI100X
 	0901  61C102
 	1000  63C815
-1001  Initio
+	1960  PowerEdge Expandable RAID Controller 4
+		1028 0518  PowerEdge Expandable RAID Controller 4/DC
+		1028 0520  PowerEdge Expandable RAID Controller 4/SC
+		1028 0531  PowerEdge Expandable RAID Controller 4/QC
+1001  Kolter Electronic
 	0010  PCI 1616 Measurement card with 32 digital I/O lines
 	0011  OPTO-PCI Opto-Isolated digital I/O board
 	0012  PCI-AD/DA Analogue I/O board
@@ -228,9 +255,11 @@
 	4c54  264LT [Mach64 LT]
 	4c57  Radeon Mobility M7 LW
 		1028 00e6  Radeon Mobility M7 LW (Dell Inspiron 8100)
-	4c58  Radeon Mobility M6 LX
+	4c58  Radeon Mobility M7 LX [Radeon Mobility FireGL 7800]
 	4c59  Radeon Mobility M6 LY
-		104d 80e7  Vaio PCG Series video card
+		1014 0235  ThinkPad A30p (2653-64G)
+		1014 0239  ThinkPad X22/X23/X24
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	4c5a  Radeon Mobility M6 LZ
 	4d46  Rage Mobility M4 AGP
 	4d4c  Rage Mobility M4 AGP
@@ -287,14 +316,18 @@
 	5145  Radeon QE
 	5146  Radeon QF
 	5147  Radeon QG
-	5148  Radeon R200 QH
+	5148  Radeon R200 QH [Radeon 8500]
+		1002 0152  FireGL 8800
+		1002 0172  FireGL 8700
 	5149  Radeon R200 QI
 	514a  Radeon R200 QJ
 	514b  Radeon R200 QK
-	514c  Radeon QL
+	514c  Radeon R200 QL [Radeon 8500 LE]
+		1002 003a  Radeon R200 QL [Radeon 8500 LE]
 		1002 013a  Radeon 8500
 	5157  Radeon 7500 QW
 		1002 013a  Radeon 7500
+		174b 7161  Radeon RV200 QW [Radeon 7500 LE]
 	5158  Radeon 7500 QX
 	5159  Radeon VE QY
 		1002 000a  Radeon 7000/Radeon VE
@@ -302,6 +335,7 @@
 		1002 003a  Radeon 7000/Radeon VE
 		1002 00ba  Radeon 7000/Radeon VE
 		1002 013a  Radeon 7000/Radeon VE
+		174b 7112  Radeon 7000 64M TVO
 	515a  Radeon VE QZ
 	5168  Radeon R200 Qh
 	5169  Radeon R200 Qi
@@ -435,6 +469,7 @@
 	0007  NVRAM [Zephyr NVRAM]
 	0008  KZPSA [KZPSA]
 	0009  DECchip 21140 [FasterNet]
+		1025 0310  21140 Fast Ethernet
 		10b8 2001  SMC9332BDT EtherPower 10/100
 		10b8 2002  SMC9332BVT EtherPower T4 10/100
 		10b8 2003  SMC9334BDT EtherPower 10/100 (1-port)
@@ -447,6 +482,7 @@
 		1186 1112  DFE-570TX Fast Ethernet
 		1186 1140  DFE-660 Cardbus Ethernet 10/100
 		1186 1142  DFE-660 Cardbus Ethernet 10/100
+		11f6 0503  Freedomline Fast Ethernet
 		1282 9100  AEF-380TXD Fast Ethernet
 		1385 1100  FA310TX Fast Ethernet
 		2646 0001  KNE100TX Fast Ethernet
@@ -457,11 +493,16 @@
 		1186 0100  DE-530+
 	0016  DGLPB [OPPO]
 	0019  DECchip 21142/43
-		1011 500b  DE500 Fast Ethernet
+		1011 500a  DE500A Fast Ethernet
+		1011 500b  DE500B Fast Ethernet
 		1014 0001  10/100 EtherJet Cardbus
 		1025 0315  ALN315 Fast Ethernet
+		1033 800c  PC-9821-CS01
+		1033 800d  PC-9821NR-B06
 		108d 0016  Rapidfire 2327 10/100 Ethernet
+		108d 0017  GoCard 2250 Ethernet 10/100 Cardbus
 		10b8 2005  SMC8032DT Extreme Ethernet 10/100
+		10b8 8034  SMC8034 Extreme Ethernet 10/100
 		10ef 8169  Cardbus Fast Ethernet
 		1109 2a00  ANA-6911A/TX Fast Ethernet
 		1109 2b00  ANA-6911A/TXC Fast Ethernet
@@ -474,10 +515,15 @@
 		1186 1100  DFE-500TX Fast Ethernet
 		1186 1101  DFE-500TX Fast Ethernet
 		1186 1102  DFE-500TX Fast Ethernet
+		1259 2800  AT-2800Tx Fast Ethernet
 		1266 0004  Eagle Fast EtherMAX
 		12af 0019  NetFlyer Cardbus Fast Ethernet
 		1374 0001  Cardbus Ethernet Card 10/100
+		1374 0002  Cardbus Ethernet Card 10/100
+		1374 0007  Cardbus Ethernet Card 10/100
+		1374 0008  Cardbus Ethernet Card 10/100
 		1395 0001  10/100 Ethernet CardBus PC Card
+		13d1 ab01  EtherFast 10/100 Cardbus (PCMPC200)
 		8086 0001  EtherExpress PRO/100 Mobile CardBus 32
 	001a  Farallon PN9000SX
 	0021  DECchip 21052
@@ -486,6 +532,8 @@
 	0024  DECchip 21152
 	0025  DECchip 21153
 	0026  DECchip 21154
+	0034  56k Modem Cardbus
+		1374 0003  56k Modem Cardbus
 	0045  DECchip 21553
 	0046  DECchip 21554
 		0e11 4050  Integrated Smart Array
@@ -496,8 +544,9 @@
 		9005 0365  Adaptec 5400S
 		9005 1364  Dell PowerEdge RAID Controller 2
 		9005 1365  Dell PowerEdge RAID Controller 2
+		e4bf 1000  CC8-1-BLUES
 	1065  StrongARM DC21285
-		1069 0020  DAC960P
+		1069 0020  DAC960P / DAC1164P
 1012  Micronics Computers Inc
 1013  Cirrus Logic
 	0038  GD 7548
@@ -515,7 +564,10 @@
 	00d0  GD 5462
 	00d2  GD 5462 [Laguna I]
 	00d4  GD 5464 [Laguna]
+	00d5  GD 5464 BD [Laguna]
 	00d6  GD 5465 [Laguna]
+		13ce 8031  Barco Metheus 2 Megapixel, Dual Head
+		13cf 8031  Barco Metheus 2 Megapixel, Dual Head
 	00e8  GD 5436U
 	1100  CL 6729
 	1110  PD 6832 PCMCIA/CardBus Ctrlr
@@ -591,6 +643,8 @@
 	00b7  256-bit Graphics Rasterizer [Fire GL1]
 		1902 00b8  Fire GL1
 	00be  ATM 622MBPS Controller (1410be00)
+	00fc  CPC710 Dual Bridge and Memory Controller (PCI-64)
+	0105  CPC710 Dual Bridge and Memory Controller (PCI-32)
 	0142  Yotta Video Compositor Input
 		1014 0143  Yotta Input Controller (ytin)
 	0144  Yotta Video Compositor Output
@@ -629,7 +683,9 @@
 		101e 0475  MegaRAID 475 Express 500 RAID Controller
 		101e 0493  MegaRAID 493 Elite 1600 RAID Controller
 		1028 0471  PowerEdge RAID Controller 3/QC
+		1028 0475  PowerEdge RAID Controller 3/SC
 		1028 0493  PowerEdge RAID Controller 3/DC
+		1028 0511  PowerEdge Cost Effective RAID Controller ATA100/4Ch
 	9010  MegaRAID 428 Ultra RAID Controller
 	9030  EIDE Controller
 	9031  EIDE Controller
@@ -638,6 +694,7 @@
 	9040  Multimedia card
 	9060  MegaRAID 434 Ultra GT RAID Controller
 	9063  MegaRAC
+		101e 0767  Dell Remote Assistant Card 2
 101f  PictureTel
 1020  Hitachi Computer Products
 1021  OKI Electric Industry Co. Ltd.
@@ -660,6 +717,7 @@
 		1668 0299  ActionLink Home Network Adapter
 	2020  53c974 [PCscsi]
 	2040  79c974
+	3000  ELanSC520 Microcontroller
 	7006  AMD-751 [Irongate] System Controller
 	7007  AMD-751 [Irongate] AGP Bridge
 	700c  AMD-760 MP [IGD4-2P] System Controller
@@ -679,10 +737,11 @@
 	7413  AMD-766 [ViperPlus] ACPI
 	7414  AMD-766 [ViperPlus] USB
 	7440  AMD-768 [Opus] ISA
-		1043 8044  Asus A7M-D motherboard ISA bridge
+		1043 8044  A7M-D Mainboard
 	7441  AMD-768 [Opus] IDE
 	7443  AMD-768 [Opus] ACPI
-		1043 8044  Asus A7M-D motherboard
+		1043 8044  A7M-D Mainboard
+	7445  AMD-768 [Opus] Audio
 	7448  AMD-768 [Opus] PCI
 	7449  AMD-768 [Opus] USB
 	7454  AMD-8151 System Controller
@@ -726,8 +785,9 @@
 	9470  TGUI 9470
 	9520  Cyber 9520
 	9525  Cyber 9525
+		10cf 1094  Lifebook C6155
 	9540  Cyber 9540
-	9660  TGUI 9660/968x/968x
+	9660  TGUI 9660/938x/968x
 	9680  TGUI 9680
 	9682  TGUI 9682
 	9683  TGUI 9683
@@ -804,15 +864,26 @@
 		10b9 7101  M7101 PCI PMU Power Management Controller
 1028  Dell Computer Corporation
 	0001  PowerEdge Expandable RAID Controller 2/Si
-	0002  PowerEdge Expandable RAID Controller 3/Di
+		1028 0001  PowerEdge Expandable RAID Controller 2/Si
+	0002  PowerEdge Expandable RAID Controller 3
+		1028 0002  PowerEdge Expandable RAID Controller 3/Di
+		1028 00d1  PowerEdge Expandable RAID Controller 3/Di
+		1028 00d9  PowerEdge Expandable RAID Controller 3/Di
 	0003  PowerEdge Expandable RAID Controller 3/Si
+		1028 0003  PowerEdge Expandable RAID Controller 3/Si
 	0004  PowerEdge Expandable RAID Controller 3/Si
+		1028 00d0  PowerEdge Expandable RAID Controller 3/Si
 	0005  PowerEdge Expandable RAID Controller 3/Di
 	0006  PowerEdge Expandable RAID Controller 3/Di
-	0007  Remote Assitant Card 3
+	0007  Remote Assistant Card 3
 	0008  PowerEdge Expandable RAID Controller 3/Di
-	000a  PowerEdge Expandable RAID Controller 3/Di
+	000a  PowerEdge Expandable RAID Controller 3
+		1027 0121  PowerEdge Expandable RAID Controller 3/Di
+		1028 0106  PowerEdge Expandable RAID Controller 3/Di
+		1028 011b  PowerEdge Expandable RAID Controller 3/Di
 	000c  Embedded Systems Management Device 4
+	000e  PowerEdge Expandable RAID Controller
+	000f  PowerEdge Expandable RAID Controller 4/Di
 1029  Siemens Nixdorf IS
 102a  LSI Logic
 	0000  HYDRA
@@ -922,6 +993,8 @@
 		1705 0003  Digital First Millennium G450 32MB
 		1705 0004  Digital First Millennium G450 16MB
 		b16f 0e11  MGA-G400 AGP
+	0527  MGA Parhelia AGP
+		102b 0840  Parhelia 128Mb
 	0d10  MGA Ultima/Impression
 	1000  MGA G100 [Productiva]
 		102b ff01  Productiva G100
@@ -955,12 +1028,14 @@
 	00f0  F68554
 	00f4  F68554 HiQVision
 	00f5  F68555
+	0c30  F69030
 102d  Wyse Technology Inc.
 	50dc  3328 Audio
 102e  Olivetti Advanced Technology
 102f  Toshiba America
 	0009  r4x00
 	0020  ATM Meteor 155
+		102f 00f8  ATM Meteor 155
 1030  TMC Research
 1031  Miro Computer Products AG
 	5601  DC20 ASIC
@@ -983,6 +1058,7 @@
 	0029  PowerVR PCX1
 	002a  PowerVR 3D
 	0035  USB
+		1179 0001  USB
 		12ee 7000  Root Hub
 	003e  NAPCCARD Cardbus Controller
 	0046  PowerVR PCX2 [midas]
@@ -1018,10 +1094,12 @@
 	0008  85C503/5513
 	0009  ACPI
 	0018  SiS85C503/5513 (LPC Bridge)
-	0200  5597/5598 VGA
+	0200  5597/5598/6326 VGA
 		1039 0000  SiS5597 SVGA (Shared RAM)
 	0204  82C204
 	0205  SG86C205
+	0300  300/200
+		107d 2720  Leadtek WinFast VR300
 	0406  85C501/2
 	0496  85C496
 	0530  530 Host
@@ -1030,10 +1108,19 @@
 	0601  85C601
 	0620  620 Host
 	0630  630 Host
+	0633  633 Host
+	0635  635 Host
+	0645  645 Host
+	0646  645DX Host
+	0650  650 Host
 	0730  730 Host
+	0733  733 Host
 	0735  735 Host
+	0740  740 Host
+	0745  745 Host
 	0900  SiS900 10/100 Ethernet
 		1039 0900  SiS900 10/100 Ethernet Adapter
+	0961  SiS961 [MuTIOL Media IO]
 	3602  83C602
 	5107  5107
 	5300  SiS540 PCI Display Adapter
@@ -1055,7 +1142,7 @@
 	6300  SiS630 GUI Accelerator+3D
 	6306  6306 3D-AGP
 		1039 6306  SiS530,620 GUI Accelerator+3D
-	6326  86C326
+	6326  86C326 5598/6326
 		1039 6326  SiS6326 GUI Accelerator
 		1092 0a50  SpeedStar A50
 		1092 0a70  SpeedStar A70
@@ -1095,6 +1182,9 @@
 103b  Tatung Co. of America
 103c  Hewlett-Packard Company
 	1005  A4977A Visualize EG
+	1006  Visualize FX6
+	1008  Visualize FX4
+	100a  Visualize FX2
 	1028  Tach TL Fibre Channel Host Adapter
 	1029  Tach XL2 Fibre Channel Host Adapter
 		107e 000f  Interphase 5560 Fibre Channel Adapter
@@ -1112,7 +1202,16 @@
 	1040  J2973A DeskDirect 10BaseT NIC
 	1041  J2585B DeskDirect 10/100 NIC
 	1042  J2970A DeskDirect 10BaseT/2 NIC
+	1048  Diva Serial [GSP] Multiport UART
+		103c 1049  Tosca Console
+		103c 104a  Tosca Secondary
+		103c 104b  Maestro SP2
+		103c 1223  Halfdome Console
+		103c 1226  Keystone SP2
+		103c 1227  Powerbar SP2
+		103c 1282  Everest SP2
 	1064  79C970 PCnet Ethernet Controller
+	108b  Visualize FXe
 	10c1  NetServer Smart IRQ Router
 	10ed  TopTools Remote Control
 	1200  82557B 10/100 NIC
@@ -1123,6 +1222,7 @@
 	1229  zx1 System Bus Adapter
 	122a  zx1 I/O Controller
 	122e  zx1 Local Bus Adapter
+	1290  Auxiliary Diva Serial Port
 	2910  E2910A PCIBus Exerciser
 	2925  E2925A 32 Bit, 33 MHzPCI Exerciser & Analyzer
 103e  Solliday Engineering
@@ -1189,8 +1289,8 @@
 	c567  82C750 [Vendetta], device 0
 	c568  82C750 [Vendetta], device 1
 	c569  82C579 [Viper XPress+ Chipset]
-	c621  82C621
-	c700  82C700
+	c621  82C621 [Viper-M/N+]
+	c700  82C700 [FireStar]
 	c701  82C701 [FireStar Plus]
 	c814  82C814 [Firebridge 1]
 	c822  82C822
@@ -1201,9 +1301,11 @@
 	c895  82C895
 	c935  EV1935 ECTIVA MachOne PCI Audio
 	d568  82C825 [Firebridge 2]
+	d721  IDE [FireStar]
 1046  IPC Corporation, Ltd.
 1047  Genoa Systems Corp
 1048  Elsa AG
+	0d22  Quadro4 900XGL [ELSA GLoria4 900XGL]
 	1000  QuickStep 1000
 	3000  QuickStep 3000
 1049  Fountain Technologies, Inc.
@@ -1257,14 +1359,17 @@
 		e4bf 1010  CF2-1-CYMBAL
 	8020  TSB12LV26 IEEE-1394 Controller (Link)
 	8021  TSB43AA22 IEEE-1394 Controller (PHY/Link Integrated)
-		104d 80e7  Notebook Computer Vaio PCG Series
-	8022  TSB43AB22 IEEE-1394 Controller (PHY/Link) 1394a-2000
-	8024  TSB43AB23 IEEE-1394 Controller (PHY/Link) 1394a-2000
-	8026  TSB43AB21 IEEE-1394 Controller (PHY/Link) 1394a-2000
+		104d 80df  Vaio PCG-FX403
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+	8022  TSB43AB22 IEEE-1394a-2000 Controller (PHY/Link)
+	8023  TSB43AB22/A IEEE-1394a-2000 Controller (PHY/Link)
+	8024  TSB43AB23 IEEE-1394a-2000 Controller (PHY/Link)
+	8026  TSB43AB21 IEEE-1394a-2000 Controller (PHY/Link)
 	8027  PCI4451 IEEE-1394 Controller
 		1028 00e6  PCI4451 IEEE-1394 Controller (Dell Inspiron 8100)
 	a001  TDC1570
 	a100  TDC1561
+	a102  TNETA1575 HyperSAR Plus w/PCI Host i/f & UTOPIA i/f
 	ac10  PCI1050
 	ac11  PCI1053
 	ac12  PCI1130
@@ -1282,6 +1387,9 @@
 	ac1f  PCI1251B
 	ac20  TI 2030
 	ac21  PCI2031
+	ac22  PCI2032 PCI Docking Bridge
+	ac23  PCI2250 PCI-to-PCI Bridge
+	ac28  PCI2050 PCI-to-PCI Bridge
 	ac30  PCI1260 PC card Cardbus Controller
 	ac40  PCI4450 PC card Cardbus Controller
 	ac41  PCI4410 PC card Cardbus Controller
@@ -1289,8 +1397,13 @@
 		1028 00e6  PCI4451 PC card CardBus Controller (Dell Inspiron 8100)
 	ac50  PCI1410 PC card Cardbus Controller
 	ac51  PCI1420
+		1014 023b  ThinkPad T23 (2647-4MG)
+		10cf 1095  Lifebook C6155
+		e4bf 1000  CP2-2-HIPHOP
 	ac52  PCI1451 PC card Cardbus Controller
 	ac53  PCI1421 PC card Cardbus Controller
+	ac55  PCI1250 PC card Cardbus Controller
+	ac60  PCI2040 PCI to DSP Bridge Controller
 	fe00  FireWire Host Controller
 	fe03  12C01A FireWire Host Controller
 104d  Sony Corporation
@@ -1298,7 +1411,6 @@
 	8039  CXD3222 i.LINK Controller
 	8056  Rockwell HCF 56K modem
 	808a  Memory Stick Controller
-	80e7  Vaio PCG-GR114MK
 104e  Oak Technology, Inc
 	0017  OTI-64017
 	0107  OTI-107 [Spitfire]
@@ -1321,20 +1433,22 @@
 1052  ?Young Micro Systems
 1053  Young Micro Systems
 1054  Hitachi, Ltd
-1055  EFAR Microsystems
-	9130  EIDE Controller
-	9460  PCI to ISA Bridge
-	9462  USB Universal Host Controller
-	9463  Power Management Controller [Bridge]
+1055  Efar Microsystems
+	9130  SLC90E66 [Victory66] IDE
+	9460  SLC90E66 [Victory66] ISA
+	9462  SLC90E66 [Victory66] USB
+	9463  SLC90E66 [Victory66] ACPI
 1056  ICL
 # Motorola made a mistake and used 1507 instead of 1057 in some chips. Please look at the 1507 entry as well when updating this.
 1057  Motorola
 	0001  MPC105 [Eagle]
 	0002  MPC106 [Grackle]
+	0003  MPC8240 [Kahlua]
 	0100  MC145575 [HFC-PCI]
 	0431  KTI829c 100VG
 	1801  Audio I/O Controller (MIDI)
 		ecc0 0030  Layla
+	18c0  MPC8265A/MPC8266
 	4801  Raven
 	4802  Falcon
 	4803  Hawk
@@ -1358,6 +1472,7 @@
 		14c8 0302  SM56 PCI Fax Modem
 		1668 0300  SM56 PCI Speakerphone Modem
 		1668 0302  SM56 PCI Fax Modem
+	6400  MPC190 Security Processor (S1 family, encryption)
 1058  Electronics & Telecommunications RSH
 1059  Teknor Industrial Computers Inc
 105a  Promise Technology, Inc.
@@ -1365,10 +1480,12 @@
 		105a 4d33  Ultra100
 	0d38  20263
 		105a 4d39  Fasttrak66
+	1275  20275
 	4d30  20267
 		105a 4d33  Ultra100
 		105a 4d39  Fasttrak100
 	4d33  20246
+		105a 4d33  20246 IDE Controller
 	4d38  20262
 		105a 4d30  Ultra Device on SuperTrak
 		105a 4d33  Ultra66
@@ -1380,6 +1497,9 @@
 		105a 0275  SuperTrak SX6000 IDE
 	5300  DC5300
 	6268  20268R
+	6269  PDC20271
+		105a 6269  Fasttrack tx2
+	7275  PDC20277
 105b  Foxconn International, Inc.
 105c  Wipro Infotech Limited
 105d  Number 9 Computer Company
@@ -1397,7 +1517,24 @@
 		105d 0009  Imagine 128 series 2e 4Mb DRAM
 		105d 000a  Imagine 128 series 2 8Mb VRAM
 		105d 000b  Imagine 128 series 2 8Mb H-VRAM
+		11a4 000a  Barco Metheus 5 Megapixel
+		13cc 0000  Barco Metheus 5 Megapixel
+		13cc 0004  Barco Metheus 5 Megapixel
+		13cc 0005  Barco Metheus 5 Megapixel
+		13cc 0006  Barco Metheus 5 Megapixel
+		13cc 0008  Barco Metheus 5 Megapixel
+		13cc 0009  Barco Metheus 5 Megapixel
+		13cc 000a  Barco Metheus 5 Megapixel
+		13cc 000c  Barco Metheus 5 Megapixel
 	493d  Imagine 128 T2R [Ticket to Ride]
+		11a4 000a  Barco Metheus 5 Megapixel, Dual Head
+		11a4 000b  Barco Metheus 5 Megapixel, Dual Head
+		13cc 0002  Barco Metheus 4 Megapixel, Dual Head
+		13cc 0003  Barco Metheus 5 Megapixel, Dual Head
+		13cc 0007  Barco Metheus 5 Megapixel, Dual Head
+		13cc 0008  Barco Metheus 5 Megapixel, Dual Head
+		13cc 0009  Barco Metheus 5 Megapixel, Dual Head
+		13cc 000a  Barco Metheus 5 Megapixel, Dual Head
 	5348  Revolution 4
 105e  Vtech Computers Ltd
 105f  Infotronic America Inc
@@ -1433,10 +1570,12 @@
 1065  Texas Microsystems
 1066  PicoPower Technology
 	0000  PT80C826
-	0001  PT86C52x [Vesuvius]
-	0002  PT80C524 [Nile]
+	0001  PT86C521 [Vesuvius v1] Host Bridge
+	0002  PT86C523 [Vesuvius v3] PCI-ISA Bridge Master
+	0003  PT86C524 [Nile] PCI-to-PCI Bridge
+	0004  PT86C525 [Nile-II] PCI-to-PCI Bridge
 	0005  National PC87550 System Controller
-	8002  PT80C524 [Nile]
+	8002  PT86C523 [Vesuvius v3] PCI-ISA Bridge Slave
 1067  Mitsubishi Electric
 	1002  VG500 [VolumePro Volume Rendering Accelerator]
 1068  Diversified Technology
@@ -1585,9 +1724,10 @@
 1087  Cache Computer
 1088  Microcomputer Systems (M) Son
 1089  Data General Corporation
-108a  Bit3 Computer Corp.
+108a  SBS Technologies (formerly Bit3 Computer Corp.)
 	0001  VME Bridge Model 617
 	0010  VME Bridge Model 618
+	0040  dataBLIZZARD
 	3000  VME Bridge Model 2706
 108c  Oakleigh Systems Inc.
 108d  Olicom
@@ -1689,6 +1829,7 @@
 		101e 0649  AMI MegaRAID IDE 100 Controller
 	0650  PBC0650A
 	0670  USB0670
+		1095 0670  USB0670
 	0673  USB0673
 	0680  PCI0680
 1096  Alacron
@@ -1702,18 +1843,23 @@
 109c  Megachips Corporation
 109d  Zida Technologies Ltd.
 109e  Brooktree Corporation
-	0350  Bt848 TV with DMA push
+	0350  Bt848 Video Capture
 	0351  Bt849A Video capture
+	0369  Bt878 Video Capture
+		1002 0001  TV-Wonder
+		1002 0003  TV-Wonder/VE
 	036c  Bt879(??) Video Capture
 		13e9 0070  Win/TV (Video Section)
-	036e  Bt878
+	036e  Bt878 Video Capture
 		0070 13eb  WinTV/GO
 		0070 ff01  Viewcast Osprey 200
+		11bd 001c  PCTV Sat (DBC receiver)
 		127a 0001  Bt878 Mediastream Controller NTSC
 		127a 0002  Bt878 Mediastream Controller PAL BG
 		127a 0003  Bt878a Mediastream Controller PAL BG
 		127a 0048  Bt878/832 Mediastream Controller
 		144f 3000  MagicTView CPH060 - Video
+		1461 0004  AVerTV WDM Video Capture
 		14f1 0001  Bt878 Mediastream Controller NTSC
 		14f1 0002  Bt878 Mediastream Controller PAL BG
 		14f1 0003  Bt878a Mediastream Controller PAL BG
@@ -1721,7 +1867,7 @@
 		1851 1850  FlyVideo'98 - Video
 		1851 1851  FlyVideo II
 		1852 1852  FlyVideo'98 - Video (with FM Tuner)
-	036f  Bt879
+	036f  Bt879 Video Capture
 		127a 0044  Bt879 Video Capture NTSC
 		127a 0122  Bt879 Video Capture PAL I
 		127a 0144  Bt879 Video Capture NTSC
@@ -1755,20 +1901,24 @@
 		1851 1850  FlyVideo'98
 		1851 1851  FlyVideo'98 EZ - video
 		1852 1852  FlyVideo'98 (with FM Tuner)
-	0878  Bt878
+	0878  Bt878 Audio Capture
 		0070 13eb  WinTV/GO
 		0070 ff01  Viewcast Osprey 200
+		1002 0001  TV-Wonder
+		1002 0003  TV-Wonder/VE
+		11bd 001c  PCTV Sat (DBC receiver)
 		127a 0001  Bt878 Video Capture (Audio Section)
 		127a 0002  Bt878 Video Capture (Audio Section)
 		127a 0003  Bt878 Video Capture (Audio Section)
 		127a 0048  Bt878 Video Capture (Audio Section)
 		13e9 0070  Win/TV (Audio Section)
 		144f 3000  MagicTView CPH060 - Audio
+		1461 0004  AVerTV WDM Audio Capture
 		14f1 0001  Bt878 Video Capture (Audio Section)
 		14f1 0002  Bt878 Video Capture (Audio Section)
 		14f1 0003  Bt878 Video Capture (Audio Section)
 		14f1 0048  Bt878 Video Capture (Audio Section)
-	0879  Bt879 Video Capture (Audio Section)
+	0879  Bt879 Audio Capture
 		127a 0044  Bt879 Video Capture (Audio Section)
 		127a 0122  Bt879 Video Capture (Audio Section)
 		127a 0144  Bt879 Video Capture (Audio Section)
@@ -1795,7 +1945,7 @@
 		14f1 1522  Bt879 Video Capture (Audio Section)
 		14f1 1622  Bt879 Video Capture (Audio Section)
 		14f1 1722  Bt879 Video Capture (Audio Section)
-	0880  Bt880 Video Capture (Audio Section)
+	0880  Bt880 Audio Capture
 	2115  BtV 2115 Mediastream controller
 	2125  BtV 2125 Mediastream controller
 	2164  BtV 2164
@@ -1869,6 +2019,7 @@
 	1103  VScom 200 2 port serial adaptor
 	1146  VScom 010 1 port parallel adaptor
 	1147  VScom 020 2 port parallel adaptor
+	2724  Thales PCSM Security Card
 	9030  PCI <-> IOBus Bridge Hot Swap
 		15ed 1002  MCCS 8-port Serial Hot Swap
 		15ed 1003  MCCS 16-port Serial Hot Swap
@@ -1877,6 +2028,8 @@
 		10b5 2273  SH-ARC SoHard ARCnet card
 		1522 0001  RockForce 4 Port V.90 Data/Fax/Voice Modem
 		1522 0002  RockForce 2 Port V.90 Data/Fax/Voice Modem
+		1522 0003  RockForce 6 Port V.90 Data/Fax/Voice Modem
+		1522 0004  RockForce 8 Port V.90 Data/Fax/Voice Modem
 		1522 0010  RockForce2000 4 Port V.90 Data/Fax/Voice Modem
 		1522 0020  RockForce2000 2 Port V.90 Data/Fax/Voice Modem
 		15ed 1000  Macrolink MCCS 8-port Serial
@@ -1901,6 +2054,8 @@
 		d84d 4065  EX-4065 8S(16C550) RS-232
 		d84d 4068  EX-4068 8S(16C650) RS-232
 		d84d 4078  EX-4078 2S(16C552) RS-232+1P
+	9054  PCI <-> IOBus Bridge
+		10b5 2455  Wessex Techology PHIL-PCI
 	9060  9060
 	906d  9060SD
 		125c 0640  Aries 16000P
@@ -1937,6 +2092,7 @@
 	1001  Collage 155 ATM Server Adapter
 10b7  3Com Corporation
 	0001  3c985 1000BaseSX (SX/TX)
+	1006  MINI PCI type 3B Data Fax Modem
 	1007  Mini PCI 56k Winmodem
 		10b7 615c  Mini PCI 56K Modem
 	3390  3c339 TokenLink Velocity
@@ -1962,13 +2118,13 @@
 	6056  3c556B Hurricane CardBus
 		10b7 6556  10/100 Mini PCI Ethernet Adapter
 	6560  3CCFE656 Cyclone CardBus
-		10b7 656a  3CCFEM656 10/100 LAN 56K Modem CardBus
-	6561  3CCFEM656 10/100 LAN 56K Modem CardBus
-		10b7 656b  3CCFEM656 10/100 LAN 56K Modem CardBus
+		10b7 656a  3CCFEM656 10/100 LAN+56K Modem CardBus
+	6561  3CCFEM656 10/100 LAN+56K Modem CardBus
+		10b7 656b  3CCFEM656 10/100 LAN+56K Modem CardBus
 	6562  3CCFEM656 [id 6562] Cyclone CardBus
-		10b7 656b  3CCFEM656B 10/100 LAN 56K Modem CardBus
-	6563  3CCFEM656B 10/100 LAN 56K Modem CardBus
-		10b7 656b  3CCFEM656 10/100 LAN 56K Modem CardBus
+		10b7 656b  3CCFEM656B 10/100 LAN+56K Modem CardBus
+	6563  3CCFEM656B 10/100 LAN+56K Modem CardBus
+		10b7 656b  3CCFEM656 10/100 LAN+56K Modem CardBus
 	6564  3CCFEM656 [id 6564] Cyclone CardBus
 	7646  3cSOHO100-TX Hurricane
 	7940  3c803 FDDILink UTP Controller
@@ -2011,6 +2167,7 @@
 	9058  3c905B-Combo [Deluxe Etherlink XL 10/100]
 	905a  3c905B-FX [Fast Etherlink XL FX 10/100]
 	9200  3c905C-TX/TX-M [Tornado]
+		1028 0095  Integrated 3C905C-TX Fast Etherlink for PC Management NIC
 		10b7 1000  3C905C-TX Fast Etherlink for PC Management NIC
 		10b7 7000  10/100 Mini PCI Ethernet Adapter
 	9800  3c980-TX [Fast Etherlink XL Server Adapter]
@@ -2019,10 +2176,14 @@
 		10b7 1201  3c982-TXM 10/100baseTX Dual Port A [Hydra]
 		10b7 1202  3c982-TXM 10/100baseTX Dual Port B [Hydra]
 		10b7 9805  3c980 10/100baseTX NIC [Python-T]
+	9900  3C990-TX Typhoon
 	9902  3CR990-TX-95 56-bit Typhoon Client
 	9903  3CR990-TX-97 168-bit Typhoon Client
+	9904  3C990B-TX-M/3C990BSVR [Typhoon2]
+	9905  3CR990-FX-95/97/95 [Typhon Fiber]
 	9908  3CR990SVR95 56-bit Typhoon Server
 	9909  3CR990SVR97 Typhoon Server
+	990b  3C990SVR [Typhoon Server]
 10b8  Standard Microsystems Corp [SMC]
 	0005  83C170QF
 		1055 e000  LANEPIC 10/100 [EVB171Q-PCI]
@@ -2089,7 +2250,7 @@
 	5219  M5219
 	5225  M5225
 	5229  M5229 IDE
-		1043 8053  A7A66 Motherboard IDE
+		1043 8053  A7A266 Motherboard IDE
 	5235  M5225
 	5237  USB 1.1 Controller
 	5239  USB 2.0 Controller
@@ -2207,12 +2368,13 @@
 	10dc  ATT2C15-3 FPGA
 10dd  Evans & Sutherland
 10de  nVidia Corporation
-	0008  EDGE 3D [NV1]
-	0009  EDGE 3D [NV1]
-	0010  Mutara V08 [NV2]
-	0020  Riva TnT [NV04]
+	0008  NV1 [EDGE 3D]
+	0009  NV1 [EDGE 3D]
+	0010  NV2 [Mutara V08]
+	0020  NV4 [Riva TnT]
 		1043 0200  V3400 TNT
 		1048 0c18  Erazor II SGRAM
+		1048 0c1b  Erazor II
 		1092 0550  Viper V550
 		1092 0552  Viper V550
 		1092 4804  Viper V550
@@ -2225,10 +2387,12 @@
 		1092 4904  Viper V550
 		1092 4914  Viper V550
 		1092 8225  Viper V550
+		10b4 273d  Velocity 4400
+		10b4 2740  Velocity 4400
 		10de 0020  Riva TNT
 		1102 1015  Graphics Blaster CT6710
 		1102 1016  Graphics Blaster RIVA TNT
-	0028  Riva TnT2 [NV5]
+	0028  NV5 [Riva TnT2]
 		1043 0200  AGP-V3800 SGRAM
 		1043 0201  AGP-V3800 SDRAM
 		1043 0205  PCI-V3800
@@ -2236,13 +2400,15 @@
 		1092 4804  Viper V770
 		1092 4a00  Viper V770
 		1092 4a02  Viper V770 Ultra
+		1092 5a00  RIVA TNT2/TNT2 Pro
 		1092 6a02  Viper V770 Ultra
 		1092 7a02  Viper V770 Ultra
 		10de 0005  RIVA TNT2 Pro
+		10de 000f  Compaq NVIDIA TNT2 Pro
 		1102 1020  3D Blaster RIVA TNT2
 		1102 1026  3D Blaster RIVA TNT2 Digital
 		14af 5810  Maxi Gamer Xentor
-	0029  Riva TnT2 Ultra [NV5]
+	0029  NV5 [Riva TnT2 Ultra]
 		1043 0200  AGP-V3800 Deluxe
 		1043 0201  AGP-V3800 Ultra SDRAM
 		1043 0205  PCI-V3800 Ultra
@@ -2250,82 +2416,97 @@
 		1102 1029  3D Blaster RIVA TNT2 Ultra
 		1102 102f  3D Blaster RIVA TNT2 Ultra
 		14af 5820  Maxi Gamer Xentor 32
-	002a  Riva TnT2 [NV5]
-	002b  Riva TnT2 [NV5]
-	002c  Vanta [NV6]
+	002a  NV5 [Riva TnT2]
+	002b  NV5 [Riva TnT2]
+	002c  NV6 [Vanta]
 		1043 0200  AGP-V3800 Combat SDRAM
 		1043 0201  AGP-V3800 Combat
 		1092 6820  Viper V730
 		1102 1031  CT6938 VANTA 8MB
 		1102 1034  CT6894 VANTA 16MB
 		14af 5008  Maxi Gamer Phoenix 2
-	002d  Vanta [NV6]
+	002d  RIVA TNT2 Model 64
 		1043 0200  AGP-V3800M
 		1043 0201  AGP-V3800M
 		1102 1023  CT6892 RIVA TNT2 Value
 		1102 1024  CT6932 RIVA TNT2 Value 32Mb
-		1102 102c  CT6931 RIVA TNT2 Value (Jumper)
+		1102 102c  CT6931 RIVA TNT2 Value [Jumper]
 		1462 8808  MSI-8808
-	002e  Vanta [NV6]
-	002f  Vanta [NV6]
-	00a0  Riva TNT2
+		1554 1041  PixelView RIVA TNT2 M64 32MB
+	002e  NV6 [Vanta]
+	002f  NV6 [Vanta]
+	00a0  NV5 [Riva TNT2]
 		14af 5810  Maxi Gamer Xentor
-	0100  NV10 (GeForce 256)
+	0100  NV10 [GeForce 256 SDR]
 		1043 0200  AGP-V6600 SGRAM
 		1043 0201  AGP-V6600 SDRAM
 		1043 4008  AGP-V6600 SGRAM
 		1043 4009  AGP-V6600 SDRAM
 		1102 102d  CT6941 GeForce 256
 		14af 5022  3D Prophet SE
-	0101  GeForce 256 DDR
+	0101  NV10 [GeForce 256 DDR]
 		1043 0202  AGP-V6800 DDR
 		1043 400a  AGP-V6800 DDR SGRAM
 		1043 400b  AGP-V6800 DDR SDRAM
 		1102 102e  CT6971 GeForce 256 DDR
 		14af 5021  3D Prophet DDR-DVI
-	0103  Quadro (GeForce 256 GL)
-	0110  NV11 (GeForce2 MX)
-		1043 4015  AGP-7100 Pro with TV output
+	0103  NV10 [Quadro]
+	0110  NV11 [GeForce2 MX]
+		1043 4015  AGP-V7100 Pro
 		1043 4031  V7100 Pro with TV output
-	0111  NV11 (GeForce2 MX DDR)
-	0112  GeForce2 Go
-	0113  NV11 (GeForce2 MXR)
-	0150  NV15 (GeForce2 Pro)
+		14af 7103  3D Prophet II MX Dual-Display
+	0111  NV11 [GeForce2 MX DDR]
+	0112  NV11 [GeForce2 Go]
+	0113  NV11 [GeForce2 MXR]
+	0150  NV15 [GeForce2 GTS]
 		1043 4016  V7700 AGP Video Card
 		107d 2840  WinFast GeForce2 GTS with TV output
 		1462 8831  Creative GeForce2 Pro
-	0151  NV15 DDR (GeForce2 GTS)
-	0152  NV15 Bladerunner (GeForce2 Ultra)
-	0153  NV15 GL (Quadro2 Pro)
-	0170  NV1x
-	0171  NV1x
-	0172  NV1x
+	0151  NV15 [GeForce2 Ti]
+	0152  NV15 [GeForce2 Ultra, Bladerunner]
+		1048 0c56  GLADIAC Ultra
+	0153  NV15 [Quadro2 Pro]
+	0170  NV17 [GeForce4 MX460]
+	0171  NV17 [GeForce4 MX440]
+	0172  NV17 [GeForce4 MX420]
 	0173  NV1x
-	0174  NV1x
-	0175  NV1x
-	0176  GeForce4 420 Go 32M
-	0178  NV1x
-	0179  GeForce4 440 Go 64M
-	017a  NV1x
-	017b  NV1x
-	017c  NV1x
-	01a0  GeForce2 Integrated GPU
+	0174  NV17 [GeForce4 440 Go]
+	0175  NV17 [GeForce4 420 Go]
+	0176  NV17 [GeForce4 420 Go 32M]
+	0178  Quadro4 500XGL
+	0179  NV17 [GeForce4 440 Go 64M]
+	017a  Quadro4 200/400NVS
+	017b  Quadro4 550XGL
+	017c  Quadro4 550 GoGL
+	01a0  NV15 [GeForce2 - nForce GPU]
+	01a4  nForce CPU bridge
+	01ab  nForce 420 Memory Controller (DDR)
+	01ac  nForce 220/420 Memory Controller
+	01ad  nForce 220/420 Memory Controller
+	01b1  nForce Audio
+	01b2  nForce ISA Bridge
+	01b4  nForce PCI System Management
+	01b7  nForce AGP to PCI Bridge
+	01b8  nForce PCI-to-PCI bridge
 	01bc  nForce IDE
-	0200  NV20 (GeForce3)
+	0200  NV20 [GeForce3]
 		1043 402f  AGP-V8200 DDR
-	0201  GeForce3 Ti200
-	0202  GeForce3 Ti500
+	0201  NV20 [GeForce3 Ti200]
+	0202  NV20 [GeForce3 Ti500]
 		1043 405b  V8200 T5
-	0203  Quadro DCC
-	0250  NV25 (GeForce 4)
-	0251  GeForce4 Ti 4400
-	0253  GeForce4 Ti 4200
-	0258  NV25 (GeForce 4)
-	025b  NV25 (GeForce 4)
+	0203  NV20 [Quadro DCC]
+	0250  NV25 [GeForce4 Ti4600]
+	0251  NV25 [GeForce4 Ti4400]
+	0253  NV25 [GeForce4 Ti4200]
+	0258  Quadro4 900XGL
+	0259  Quadro4 750XGL
+	025b  Quadro4 700XGL
 10df  Emulex Corporation
 	10df  Light Pulse Fibre Channel Adapter
 	1ae5  LP6000 Fibre Channel Host Adapter
 	f700  LP7000 Fibre Channel Host Adapter
+	f800  LP8000 Fibre Channel Host Adapter
+	f900  LP9000 Fibre Channel Host Adapter
 10e0  Integrated Micro Solutions Inc.
 	5026  IMS5026/27/28
 	5027  IMS5027
@@ -2376,8 +2557,8 @@
 	8111  Twist3 Frame Grabber
 10ec  Realtek Semiconductor Co., Ltd.
 	8029  RTL-8029(AS)
-		10b8 2011  EZ-Card
-		10ec 8029  RT8029(AS)
+		10b8 2011  EZ-Card (SMC1208)
+		10ec 8029  RTL-8029(AS)
 		1113 1208  EN1208
 		1186 0300  DE-528
 		1259 2400  AT-2400
@@ -2385,14 +2566,16 @@
 		10ec 8129  RT8129 Fast Ethernet Adapter
 	8138  RT8139 (B/C) Cardbus Fast Ethernet Adapter
 		10ec 8138  RT8139 (B/C) Fast Ethernet Adapter
-	8139  RTL-8139/8139C
+	8139  RTL-8139/8139C/8139C+
 		1025 8920  ALN-325
 		1025 8921  ALN-325
 		10bd 0320  EP-320X-R
 		10ec 8139  RT8139
 		1186 1300  DFE-538TX
 		1186 1320  SN5200
+		1186 8139  DRN-32TX
 		1259 2500  AT-2500TX
+		1259 2503  AT-2500TX/ACPI
 		1429 d010  ND010
 		1432 9130  EN-9130TX
 		1436 8139  RT8139
@@ -2405,6 +2588,7 @@
 		8e2e 7000  KF-230TX
 		8e2e 7100  KF-230TX/2
 		a0a0 0007  ALN-325C
+	8169  RTL-8169
 10ed  Ascii Corporation
 	7310  V7310
 10ee  Xilinx, Inc.
@@ -2412,6 +2596,8 @@
 	3fc1  RME Digi96/8
 	3fc2  RME Digi96/8 Pro
 	3fc3  RME Digi96/8 Pad
+	3fc4  RME Digi9652 (Hammerfall)
+	3fc5  RME Hammerfall DSP
 10ef  Racore Computer Products, Inc.
 	8154  M815x Token Ring Adapter
 10f0  Peritek Corporation
@@ -2453,34 +2639,45 @@
 		1102 8025  SBLive! Mainboard Implementation
 		1102 8026  CT4830 SBLive! Value
 		1102 8027  CT4832 SBLive! Value
+		1102 8028  CT4760 SBLive! OEM version
 		1102 8031  CT4831 SBLive! Value
 		1102 8040  CT4760 SBLive!
 		1102 8051  CT4850 SBLive! Value
+		1102 8061  SBLive! Player 5.1
 	0004  SB Audigy
+		1102 0051  SB0090 Audigy Player
 	4001  SB Audigy FireWire Port
 	7002  SB Live! MIDI/Game Port
 		1102 0020  Gameport Joystick
 	7003  SB Audigy MIDI/Game port
+		1102 0040  SB Audigy MIDI/Gameport
 	8938  ES1371
 1103  Triones Technologies, Inc.
 	0003  HPT343
-	0004  HPT366 / HPT370
+# Revisions: 01=HPT366, 03=HPT370, 04=HPT370A, 05=HPT372
+	0004  HPT366/368/370/370A/372
+		1103 0001  HPT370A
 		1103 0005  HPT370 UDMA100
-# Not HPT370A, It's HPT370. I don't know what ID HPT370A has.
-	0005  HPT370
+	0005  HPT372A
+	0006  HPT302
+	0007  HPT371
+	0008  HPT374
 1104  RasterOps Corp.
 1105  Sigma Designs, Inc.
+	1105  REALmagic Xcard MPEG 1/2/3/4 DVD Decoder
 	8300  REALmagic Hollywood Plus DVD Decoder
 	8400  EM840x REALmagic DVD/MPEG-2 Audio/Video Decoder
 1106  VIA Technologies, Inc.
+	0130  VT6305 1394.A Controller
 	0305  VT8363/8365 [KT133/KM133]
-		1043 8042  A7V133/A7V133-C
-		147b a401  KT7/KT7-RAID/KT7A/KT7A-RAID
+		1043 8033  A7V Mainboard
+		1043 8042  A7V133/A7V133-C Mainboard
+		147b a401  KT7/KT7-RAID/KT7A/KT7A-RAID Mainboard
 	0391  VT8371 [KX133]
 	0501  VT8501 [Apollo MVP4]
 	0505  VT82C505
 	0561  VT82C561
-	0571  Bus Master IDE
+	0571  VT82C586B PIPC Bus Master IDE
 	0576  VT82C576 3V [Apollo Master]
 	0585  VT82C585VP [Apollo VP1/VPX]
 	0586  VT82C586/A/B PCI-to-ISA [Apollo VP]
@@ -2495,7 +2692,8 @@
 	0605  VT8605 [ProSavage PM133]
 	0680  VT82C680 [Apollo P6]
 	0686  VT82C686 [Apollo Super South]
-		1043 8042  ATV133/A7V133-C
+		1043 8033  A7V Mainboard
+		1043 8042  A7V133/A7V133-C Mainboard
 		1106 0000  VT82C686/A PCI to ISA Bridge
 		1106 0686  VT82C686/A PCI to ISA Bridge
 	0691  VT82C693A/694x [Apollo PRO133x]
@@ -2507,9 +2705,11 @@
 	1106  VT82C570MV
 	1571  VT82C416MV
 	1595  VT82C595/97 [Apollo VP2/97]
-	3038  UHCI USB
+	3038  USB
+		0925 1234  USB Controller
+		1234 0925  MVP3 USB Controller
 	3040  VT82C586B ACPI
-	3043  VT3043 [Rhine]
+	3043  VT86C100A [Rhine]
 		10bd 0000  VT86C100A Fast Ethernet Adapter
 		1106 0100  VT86C100A Fast Ethernet Adapter
 		1186 1400  DFE-530TX rev A
@@ -2517,10 +2717,14 @@
 	3050  VT82C596 Power Management
 	3051  VT82C596 Power Management
 	3057  VT82C686 [Apollo Super ACPI]
-		1043 8042  ATV133/A7V133-C
+		1043 8033  A7V Mainboard
+		1043 8042  A7V133/A7V133-C Mainboard
 	3058  VT82C686 AC97 Audio Controller
+		0e11 b194  Soundmax integrated digital audio
+		1106 4511  Onboard Audio on EP7KXA
 		1458 7600  Onboard Audio
 		1462 3091  MS-6309 Onboard Audio
+		15dd 7609  Onboard Audio
 	3059  VT8233 AC97 Audio Controller
 	3065  VT6102 [Rhine-II]
 		1186 1400  DFE-530TX rev A
@@ -2529,13 +2733,24 @@
 	3074  VT8233 PCI to ISA Bridge
 	3091  VT8633 [Apollo Pro266]
 	3099  VT8367 [KT266]
+		1043 8064  A7V266-E
+		1043 807f  A7V333
+	3101  VT8653 Host Bridge
+	3102  VT8662 Host Bridge
+	3103  VT8615 Host Bridge
 	3104  USB 2.0
 	3109  VT8233C PCI to ISA Bridge
+	3112  VT8361 [KLE133] Host Bridge
 	3128  VT8753 [P4X266 AGP]
+	3133  VT3133 Host Bridge
+	3147  VT8233A ISA Bridge
+	3148  P4M266 Host Bridge
+	3156  P/KN266 Host Bridge
+	3177  VT8233A ISA Bridge
 	5030  VT82C596 ACPI [Apollo PRO]
 	6100  VT85C100A [Rhine II]
 	8231  VT8231 [PCI-to-ISA Bridge]
-	8235  VT8235 Power Management
+	8235  VT8235 ACPI
 	8305  VT8363/8365 [KT133/KM133 AGP]
 	8391  VT8371 [KX133 AGP]
 	8501  VT8501 [Apollo MVP4 AGP]
@@ -2545,8 +2760,13 @@
 	8601  VT8601 [Apollo ProMedia AGP]
 	8605  VT8605 [PM133 AGP]
 	8691  VT82C691 [Apollo Pro]
+	8693  VT82C693 [Apollo Pro Plus] PCI Bridge
 	b091  VT8633 [Apollo Pro266 AGP]
-	b099  VT8367 [KT266 AGP]
+	b099  VT8367 [KT333 AGP]
+	b101  VT8653 AGP Bridge
+	b102  VT8362 AGP Bridge
+	b103  VT8615 AGP Bridge
+	b112  VT8361 [KLE133] AGP Bridge
 1107  Stratus Computers
 	0576  VIA VT82C570MV [Apollo] (Wrong vendor ID!)
 1108  Proteon, Inc.
@@ -2713,9 +2933,10 @@
 	0200  ForeRunner PCA-200 ATM
 	0210  PCA-200PC
 	0250  ATM
-	0300  PCA-200E
+	0300  ForeRunner PCA-200EPC ATM
 	0310  ATM
 	0400  ForeRunnerHE ATM Adapter
+		1127 0400  ForeRunnerHE ATM
 1129  Firmworks
 112a  Hermes Electronics Company, Ltd.
 112b  Linotype - Hell AG
@@ -2727,6 +2948,9 @@
 	0001  MVC IM-PCI Video frame grabber/processor
 1130  Computervision
 1131  Philips Semiconductors
+	7130  SAA7130 Video Broadcast Decoder
+# PCI audio and video broadcast decoder (http://www.semiconductors.philips.com/pip/saa7134hl)
+	7134  SAA7134
 	7145  SAA7145
 	7146  SAA7146
 		114b 2003  DVRaptor Video Edit/Capture Card
@@ -2761,6 +2985,7 @@
 		1133 e012  DIVA Server BRI-8M
 	e014  DIVA Server PRI-30M
 		1133 e014  DIVA Server PRI-30M
+	e018  DIVA Server BRI-2M/-2F
 1134  Mercury Computer Systems
 	0001  Raceway Bridge
 1135  Fuji Xerox Co Ltd
@@ -2831,6 +3056,7 @@
 		1148 9844  SK-9844 (1000Base-SX dual link)
 		1148 9861  SK-9861 (1000Base-SX VF45 single link)
 		1148 9862  SK-9862 (1000Base-SX VF45 dual link)
+	4400  Gigabit Ethernet
 1149  Win System Corporation
 114a  VMIC
 	5579  VMIPCI-5579 (Reflective Memory Card)
@@ -2903,6 +3129,7 @@
 		1014 9181  10/100 EtherJet Cardbus Adapter
 		115d 0181  Cardbus Ethernet 10/100
 		115d 1181  Cardbus Ethernet 10/100
+		1179 0181  Cardbus Ethernet 10/100
 		8086 8181  EtherExpress PRO/100 Mobile CardBus 32 Adapter
 		8086 9181  EtherExpress PRO/100 Mobile CardBus 32 Adapter
 	0005  Cardbus Ethernet 10/100
@@ -2925,6 +3152,8 @@
 	0101  Cardbus 56k modem
 		115d 1081  Cardbus 56k Modem
 	0103  Cardbus Ethernet + 56k Modem
+		1014 9181  Cardbus 56k Modem
+		1115 1181  Cardbus Ethernet 100 + 56k Modem
 		115d 1181  CBEM56G-100 Ethernet + 56k Modem
 		8086 9181  PRO/100 LAN + Modem56 CardBus
 115e  Peer Protocols Inc
@@ -2940,16 +3169,27 @@
 1165  Imagraph Corporation
 	0001  Motion TPEG Recorder/Player with audio
 1166  ServerWorks
+	0005  CNB20-LE Host Bridge
 	0007  CNB20-LE Host Bridge
 	0008  CNB20HE Host Bridge
 	0009  CNB20LE Host Bridge
 	0010  CIOB30
 	0011  CMIC-HE
+	0013  CNB20-HE Host Bridge
+	0014  CNB20-HE Host Bridge
+	0015  CMIC-GC Host Bridge
+	0016  CMIC-GC Host Bridge
+	0017  GCNB-LE Host Bridge
 	0200  OSB4 South Bridge
 	0201  CSB5 South Bridge
+	0203  CSB6 South Bridge
 	0211  OSB4 IDE Controller
 	0212  CSB5 IDE Controller
-	0220  OSB4/CSB5 USB Controller
+	0213  CSB6 RAID/IDE Controller
+	0220  OSB4/CSB5 OHCI USB Controller
+	0221  CSB6 OHCI USB Controller
+	0225  GCLE Host Bridge
+	0227  GCLE-2 Host Bridge
 1167  Mutoh Industries Inc
 1168  Thine Electronics Inc
 1169  Centre for Development of Advanced Computing
@@ -2974,6 +3214,7 @@
 1178  Alfa, Inc.
 	afa1  Fast Ethernet Adapter
 1179  Toshiba America Info Systems
+	0103  EX-IDE Type-B
 	0404  DVD Decoder card
 	0406  Tecra Video Capture device
 	0407  DVD Decoder card (Version 2)
@@ -2985,6 +3226,8 @@
 	0618  CPU to PCI and PCI to ISA bridge
 # Claimed to be Lucent DSP1645 [Mars], but that's apparently incorrect. Does anyone know the correct ID?
 	0701  FIR Port
+	0804  TC6371AF SmartMedia Controller
+	0805  SD TypA Controller
 	0d01  FIR Port Type-DO
 		1179 0001  FIR Port Type-DO
 117a  A-Trend Technology
@@ -2998,8 +3241,14 @@
 	0466  RL5c466
 	0475  RL5c475
 	0476  RL5c476 II
+		104d 80df  Vaio PCG-FX403
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	0477  RL5c477
 	0478  RL5c478
+		1014 0184  ThinkPad A30p (2653-64G)
+	0522  R5C522 IEEE 1394 Controller
+		1014 01cf  ThinkPad A30p (2653-64G)
+	0551  R5C551 IEEE 1394 Controller
 	0552  R5C552 IEEE 1394 Controller
 1181  Telmatics International
 1183  Fujikura Ltd
@@ -3007,8 +3256,12 @@
 1185  Dataworld International Ltd
 1186  D-Link System Inc
 	0100  DC21041
-	1002  Sundance Ethernet
+	1002  DL10050 Sundance Ethernet
+		1186 1002  DFE-550TX
+		1186 1012  DFE-580TX
 	1300  RTL8139 Ethernet
+		1186 1300  DFE-538TX 10/100 Ethernet Adapter
+		1186 1301  DFE-530TX+ 10/100 Ethernet Adapter
 	1340  DFE-690TXD CardBus PC Card
 	1561  DRP-32TXD Cardbus PC Card
 	4000  DL2K Ethernet
@@ -3100,6 +3353,7 @@
 		11ad ffff  LNE100TX
 		1385 f004  FA310TX
 	c115  LNE100TX [Linksys EtherFast 10/100]
+		11ad c001  LNE100TX [ver 2.0]
 11ae  Aztech System Ltd
 11af  Avid Technology Inc.
 11b0  V3 Semiconductor Inc.
@@ -3198,6 +3452,7 @@
 		13e0 0041  TelePath Internet 56k WinModem
 		1436 0440  Lucent Win Modem
 		144f 0449  Lucent 56k V.90 DFi Modem
+		1468 0410  IBM ThinkPad T23 (2647-4MG)
 		1468 0440  Lucent Win Modem
 		1468 0449  Presario 56k V.90 DFi Modem
 	044a  F-1156IV WinModem (V90, 56KFlex)
@@ -3224,6 +3479,8 @@
 	0461  V90 WildWire Modem
 	0462  V90 WildWire Modem
 	0480  Venus Modem (V90, 56KFlex)
+	5801  USB
+	5802  USS-312 USB Controller
 	5811  FW323
 		dead 0800  FireWire Host Bus Adapter
 11c2  Sand Microelectronics
@@ -3312,6 +3569,7 @@
 	0113  FreedomLine 100
 	1401  ReadyLink 2000
 	2011  RL100-ATX 10/100
+		11f6 2011  RL100-ATX
 	2201  ReadyLink 100TX (Winbond W89C840)
 		11f6 2011  ReadyLink 100TX
 	9881  RL100TX
@@ -3330,11 +3588,13 @@
 	0004  RocketPort 32 Intf
 	0005  RocketPort Octacable
 	0006  RocketPort 8J
+	0007  RocketPort 4-port
 	0008  RocketPort 8-port
 	0009  RocketPort 16-port
 	000a  RocketPort Plus Quadcable
 	000b  RocketPort Plus Octacable
 	000c  RocketPort 8-port Modem
+	8015  RocketPort 4-port UART 16954
 11ff  Scion Corporation
 1200  CSS Corporation
 1201  Vista Controls Corp
@@ -3351,18 +3611,21 @@
 120c  Technical Corp.
 120d  Compression Labs, Inc.
 120e  Cyclades Corporation
-	0100  Cyclom_Y below first megabyte
-	0101  Cyclom_Y above first megabyte
-	0102  Cyclom_4Y below first megabyte
-	0103  Cyclom_4Y above first megabyte
-	0104  Cyclom_8Y below first megabyte
-	0105  Cyclom_8Y above first megabyte
-	0200  Cyclom_Z below first megabyte
-	0201  Cyclom_Z above first megabyte
-	0300  PC300 RX 2
-	0301  PC300 RX 1
-	0310  PC300 TE 2
-	0311  PC300 TE 1
+	0100  Cyclom-Y below first megabyte
+	0101  Cyclom-Y above first megabyte
+	0102  Cyclom-4Y below first megabyte
+	0103  Cyclom-4Y above first megabyte
+	0104  Cyclom-8Y below first megabyte
+	0105  Cyclom-8Y above first megabyte
+	0200  Cyclades-Z below first megabyte
+	0201  Cyclades-Z above first megabyte
+	0300  PC300/RSV or /X21 (2 ports)
+	0301  PC300/RSV or /X21 (1 port)
+	0310  PC300/TE (2 ports)
+	0311  PC300/TE (1 port)
+	0320  PC300/TE-M (2 ports)
+	0321  PC300/TE-M (1 port)
+	0400  PC400
 120f  Essential Communications
 	0001  Roadrunner serial HIPPI
 1210  Hyperparallel Technologies
@@ -3373,12 +3636,15 @@
 1215  Interware Co., Ltd
 1216  Purup Prepress A/S
 1217  O2 Micro, Inc.
-	6729  6729
-	673a  6730
-	6832  6832
-	6836  6836
+	6729  OZ6729
+	673a  OZ6730
+	6832  OZ6832/6833 Cardbus Controller
+	6836  OZ6836/6860 Cardbus Controller
 	6872  OZ6812 Cardbus Controller
+	6925  OZ6922 Cardbus Controller
 	6933  OZ6933 Cardbus Controller
+		1025 1016  Travelmate 612 TX
+	6972  OZ6912 Cardbus Controller
 1218  Hybricon Corp.
 1219  First Virtual Corporation
 121a  3Dfx Interactive, Inc.
@@ -3492,7 +3758,10 @@
 1240  Marathon Technologies Corp.
 1241  DSC Communications
 1242  Jaycor Networks, Inc.
+	1242  JNI Corporation (former Jaycor Networks, Inc.)
 	4643  FCI-1063 Fibre Channel Adapter
+	6562  FCX2-6562 Dual Channel PCI-X Fibre Channel Adapter
+	656a  FCX-6562 PCI-X Fibre Channel Adapter
 1243  Delphax
 1244  AVM Audiovisuelles MKTG & Computer System GmbH
 	0700  B1 ISDN
@@ -3542,6 +3811,7 @@
 125b  Asix Electronics Corporation
 	1400  ALFA GFC2204
 125c  Aurora Technologies, Inc.
+	0640  Aries 16000P
 125d  ESS Technology
 	0000  ES336H Fax Modem (Early Model)
 	1948  Solo?
@@ -3582,6 +3852,8 @@
 125e  Specialvideo Engineering SRL
 125f  Concurrent Technologies, Inc.
 1260  Harris Semiconductor
+	3873  Prism 2.5 Wavelan chipset
+		1186 3501  DWL-520 Wireless PCI Adapter
 	8130  HMP8130 NTSC/PAL Video Decoder
 	8131  HMP8131 NTSC/PAL Video Decoder
 1261  Matsushita-Kotobuki Electronics Industries, Ltd.
@@ -3618,6 +3890,7 @@
 	0002  DirecPC
 1274  Ensoniq
 	1371  ES1371 [AudioPCI-97]
+		0e11 0024  AudioPCI on Motherboard Compaq Deskpro
 		0e11 b1a7  ES1371, ES1373 AudioPCI
 		1033 80ac  ES1371, ES1373 AudioPCI
 		1042 1854  Tazer
@@ -3694,70 +3967,70 @@
 127a  Rockwell International
 	1002  HCF 56k Data/Fax Modem
 		1092 094c  SupraExpress 56i PRO [Diamond SUP2380]
-		122d 4002  HPG / MDP3858-U # Aztech
-		122d 4005  MDP3858-E # Aztech
-		122d 4007  MDP3858-A/-NZ # Aztech
-		122d 4012  MDP3858-SA # Aztech
-		122d 4017  MDP3858-W # Aztech
-		122d 4018  MDP3858-W # Aztech
+		122d 4002  HPG / MDP3858-U
+		122d 4005  MDP3858-E
+		122d 4007  MDP3858-A/-NZ
+		122d 4012  MDP3858-SA
+		122d 4017  MDP3858-W
+		122d 4018  MDP3858-W
 		127a 1002  Rockwell 56K D/F HCF Modem
 	1003  HCF 56k Data/Fax Modem
-		0e11 b0bc  229-DF Zephyr # Compaq
-		0e11 b114  229-DF Cheetah # Compaq
-		1033 802b  229-DF # NEC
-		13df 1003  PCI56RX Modem # E-Tech Inc
-		13e0 0117  IBM # GVC
-		13e0 0147  IBM # GVC F-1156IV /R3 Spain V.90 Modem
-		13e0 0197  IBM # GVC
-		13e0 01c7  IBM # GVC F-1156IV /R3 WW V.90 Modem
-		13e0 01f7  IBM # GVC
-		1436 1003  IBM # CIS
-		1436 1103  IBM # CIS 5614PM3G V.90 Modem
+		0e11 b0bc  229-DF Zephyr
+		0e11 b114  229-DF Cheetah
+		1033 802b  229-DF
+		13df 1003  PCI56RX Modem
+		13e0 0117  IBM
+		13e0 0147  IBM F-1156IV+/R3 Spain V.90 Modem
+		13e0 0197  IBM
+		13e0 01c7  IBM F-1156IV+/R3 WW V.90 Modem
+		13e0 01f7  IBM
+		1436 1003  IBM
+		1436 1103  IBM 5614PM3G V.90 Modem
 		1436 1602  Compaq 229-DF Ducati
 	1004  HCF 56k Data/Fax/Voice Modem
 		1048 1500  MicroLink 56k Modem
 		10cf 1059  Fujitsu 229-DFRT
 	1005  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
-		1033 8029  229-DFSV # NEC
-		1033 8054  Modem # NEC
+		1033 8029  229-DFSV
+		1033 8054  Modem
 		10cf 103c  Fujitsu
 		10cf 1055  Fujitsu 229-DFSV
 		10cf 1056  Fujitsu 229-DFSV
-		122d 4003  MDP3858SP-U # Aztech
-		122d 4006  Packard Bell MDP3858V-E # Aztech
-		122d 4008  MDP3858SP-A/SP-NZ # Aztech
-		122d 4009  MDP3858SP-E # Aztech
-		122d 4010  MDP3858V-U # Aztech
-		122d 4011  MDP3858SP-SA # Aztech
-		122d 4013  MDP3858V-A/V-NZ # Aztech
-		122d 4015  MDP3858SP-W # Aztech
-		122d 4016  MDP3858V-W # Aztech
-		122d 4019  MDP3858V-SA # Aztech
-		13df 1005  PCI56RVP Modem  # E-Tech Inc
-		13e0 0187  IBM # GVC
-		13e0 01a7  IBM # GVC
-		13e0 01b7  IBM # GVC DF-1156IV /R3 Spain V.90 Modem
-		13e0 01d7  IBM # GVC DF-1156IV /R3 WW V.90 Modem
-		1436 1005  IBM # CIS
-		1436 1105  IBM # CIS
-		1437 1105  IBM # CIS 5614PS3G V.90 Modem
+		122d 4003  MDP3858SP-U
+		122d 4006  Packard Bell MDP3858V-E
+		122d 4008  MDP3858SP-A/SP-NZ
+		122d 4009  MDP3858SP-E
+		122d 4010  MDP3858V-U
+		122d 4011  MDP3858SP-SA
+		122d 4013  MDP3858V-A/V-NZ
+		122d 4015  MDP3858SP-W
+		122d 4016  MDP3858V-W
+		122d 4019  MDP3858V-SA
+		13df 1005  PCI56RVP Modem
+		13e0 0187  IBM
+		13e0 01a7  IBM
+		13e0 01b7  IBM DF-1156IV+/R3 Spain V.90 Modem
+		13e0 01d7  IBM DF-1156IV+/R3 WW V.90 Modem
+		1436 1005  IBM
+		1436 1105  IBM
+		1437 1105  IBM 5614PS3G V.90 Modem
 	1022  HCF 56k Modem
 		1436 1303  M3-5614PM3G V.90 Modem
 	1023  HCF 56k Data/Fax Modem
-		122d 4020  Packard Bell MDP3858-WE # Aztech
-		122d 4023  MDP3858-UE # Aztech
-		13e0 0247  IBM # GVC F-1156IV /R6 Spain V.90 Modem
-		13e0 0297  IBM # GVC
-		13e0 02c7  IBM # GVC F-1156IV /R6 WW V.90 Modem
-		1436 1203  IBM # CIS
-		1436 1303  IBM # CIS
+		122d 4020  Packard Bell MDP3858-WE
+		122d 4023  MDP3858-UE
+		13e0 0247  IBM F-1156IV+/R6 Spain V.90 Modem
+		13e0 0297  IBM
+		13e0 02c7  IBM F-1156IV+/R6 WW V.90 Modem
+		1436 1203  IBM
+		1436 1303  IBM
 	1024  HCF 56k Data/Fax/Voice Modem
 	1025  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
 		10cf 106a  Fujitsu 235-DFSV
-		122d 4021  Packard Bell MDP3858V-WE # Aztech
-		122d 4022  MDP3858SP-WE # Aztech
-		122d 4024  MDP3858V-UE # Aztech
-		122d 4025  MDP3858SP-UE # Aztech
+		122d 4021  Packard Bell MDP3858V-WE
+		122d 4022  MDP3858SP-WE
+		122d 4024  MDP3858V-UE
+		122d 4025  MDP3858SP-UE
 	1026  HCF 56k PCI Speakerphone Modem
 	1032  HCF 56k Modem
 	1033  HCF 56k Modem
@@ -3766,30 +4039,30 @@
 	1036  HCF 56k Modem
 	1085  HCF 56k Volcano PCI Modem
 	2005  HCF 56k Data/Fax Modem
-		104d 8044  229-DFSV # Sony
-		104d 8045  229-DFSV # Sony
-		104d 8055  PBE/Aztech 235W-DFSV # Sony
-		104d 8056  235-DFSV # Sony
-		104d 805a  Modem # Sony
-		104d 805f  Modem # Sony
-		104d 8074  Modem # Sony
+		104d 8044  229-DFSV
+		104d 8045  229-DFSV
+		104d 8055  PBE/Aztech 235W-DFSV
+		104d 8056  235-DFSV
+		104d 805a  Modem
+		104d 805f  Modem
+		104d 8074  Modem
 	2013  HSF 56k Data/Fax Modem
-		1179 0001  Modem # Toshiba
-		1179 ff00  Modem # Toshiba
+		1179 0001  Modem
+		1179 ff00  Modem
 	2014  HSF 56k Data/Fax/Voice Modem
 		10cf 1057  Fujitsu Citicorp III
-		122d 4050  MSP3880-U # Aztech
-		122d 4055  MSP3880-W # Aztech
+		122d 4050  MSP3880-U
+		122d 4055  MSP3880-W
 	2015  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
 		10cf 1063  Fujitsu
 		10cf 1064  Fujitsu
 		1468 2015  Fujitsu
 	2016  HSF 56k Data/Fax/Voice/Spkp Modem
-		122d 4051  MSP3880V-W # Aztech
-		122d 4052  MSP3880SP-W # Aztech
-		122d 4054  MSP3880V-U # Aztech
-		122d 4056  MSP3880SP-U # Aztech
-		122d 4057  MSP3880SP-A # Aztech
+		122d 4051  MSP3880V-W
+		122d 4052  MSP3880SP-W
+		122d 4054  MSP3880V-U
+		122d 4056  MSP3880SP-U
+		122d 4057  MSP3880SP-A
 	4311  Riptide HSF 56k PCI Modem
 		127a 4311  Ring Modular? Riptide HSF RT HP Dom
 		13e0 0210  HP-GVC
@@ -3799,7 +4072,7 @@
 		1235 4321  Hewlett Packard DF
 		1235 4324  Hewlett Packard DF
 		13e0 0210  Hewlett Packard DF
-		144d 2321  Riptide # Samsung
+		144d 2321  Riptide
 	4322  Riptide PCI Game Controller
 		1235 4322  Riptide PCI Game Controller
 	8234  RapidFire 616X ATM155 Adapter
@@ -3877,7 +4150,7 @@
 12ac  Measurex Corporation
 12ad  Multidata GmbH
 12ae  Alteon Networks Inc.
-	0001  AceNIC Gigabit Ethernet (Fibre)
+	0001  AceNIC Gigabit Ethernet
 		12ae 0001  Gigabit Ethernet-SX (Universal)
 		1410 0104  Gigabit Ethernet-SX PCI Adapter
 	0002  AceNIC Gigabit Ethernet (Copper)
@@ -3928,6 +4201,8 @@
 	5598  PCI NE2K Ethernet
 12c4  Connect Tech Inc
 12c5  Picture Elements Incorporated
+	007e  Imaging/Scanning Subsystem Engine
+	007f  Imaging/Scanning Subsystem Engine
 	0081  PCIVST [Grayscale Thresholding Engine]
 	0085  Video Simulator/Sender
 	0086  THR2 Multi-scale Thresholder
@@ -4005,6 +4280,7 @@
 		1092 2100  Sonic Impact A3D
 		1092 2110  Sonic Impact A3D
 		1092 2200  Sonic Impact A3D
+		122d 1002  AU8820 Vortex Digital Audio Processor
 		12eb 0001  AU8820 Vortex Digital Audio Processor
 		5053 3355  Montego
 	0002  Vortex 2
@@ -4225,6 +4501,7 @@
 135a  Brain Boxes
 135b  Giganet Inc
 135c  Quatech Inc
+	00f0  MPAC-100 Syncronous Serial Card (Zilog 85230)
 135d  ABB Network Partner AB
 135e  Sealevel Systems Inc
 	7101  Single Port RS-232/422/485/530
@@ -4298,6 +4575,7 @@
 	3200  Intellio C320 Turbo PCI
 1394  Level One Communications
 	0001  LXT1001 Gigabit Ethernet
+		1394 0001  NetCelerator Adapter
 1395  Ambicom Inc
 1396  Cipher Systems Inc
 1397  Cologne Chip Designs GmbH
@@ -4307,6 +4585,9 @@
 1398  Clarion co. Ltd
 1399  Rios systems Co Ltd
 139a  Alacritech Inc
+	0001  Quad Port 10/100 Server Accelerator
+	0003  Single Port 10/100 Server Accelerator
+	0005  Single Port Gigabit Server Accelerator
 139b  Mediasonic Multimedia Systems Ltd
 139c  Quantum 3d Inc
 139d  EPL limited
@@ -4354,6 +4635,7 @@
 13c1  3ware Inc
 	1000  3ware ATA-RAID
 	1001  3ware 7000-series ATA-RAID
+	1002  3ware ATA-RAID
 13c2  Technotrend Systemtechnik GmbH
 13c3  Janz Computer AG
 13c4  Phase Metrics
@@ -4404,7 +4686,7 @@
 13ee  Hayes Microcomputer Products Inc
 13ef  Coppercom Inc
 13f0  Sundance Technology Inc
-	0201  Sundance Ethernet
+	0201  ST201 Sundance Ethernet
 13f1  Oce' - Technologies B.V.
 13f2  Ford Microelectronics Inc
 13f3  Mcdata Corporation
@@ -4418,6 +4700,7 @@
 		13f6 0101  CMI8338-031 PCI Audio Device
 	0111  CM8738
 		1043 8077  CMI8738 6-channel audio controller
+		1043 80e2  CMI8738 6ch-MX
 		13f6 0111  CMI8738/C3DX PCI Audio Device
 	0211  CM8738
 13f7  Wildfire Communications
@@ -4428,6 +4711,7 @@
 13fc  Computer Peripherals International
 13fd  Micro Science Inc
 13fe  Advantech Co. Ltd
+	1756  PCI-1756
 13ff  Silicon Spice Inc
 1400  Artx Inc
 	1401  9432 TX
@@ -4447,6 +4731,7 @@
 	0500  Lava Single Serial
 	0600  Lava Port 650
 	8000  Lava Parallel
+	8001  Dual parallel port controller A
 	8002  Lava Dual Parallel port A
 	8003  Lava Dual Parallel port B
 	8800  BOCA Research IOPPAR
@@ -4467,9 +4752,11 @@
 1414  Microsoft Corporation
 1415  Oxford Semiconductor Ltd
 	8403  VScom 011H-EP1 1 port parallel adaptor
-	9501  Quad 16950 UART
+	9501  OX16PCI954 (Quad 16950 UART) function 0
 		15ed 2000  MCCR Serial p0-3 of 8
 		15ed 2001  MCCR Serial p0-3 of 16
+	950a  EXSYS EX-41092 Dual 16950 Serial adapter
+	950b  OXCB950 Cardbus 16950 UART
 	9511  OX16PCI954 (Quad 16950 UART) function 1
 		15ed 2000  MCCR Serial p4-7 of 8
 		15ed 2001  MCCR Serial p4-15 of 16
@@ -4716,18 +5003,21 @@
 	0007  PCI224
 	0008  PCI234
 	0009  PCI236
+	000a  PCI272
+	000b  PCI215
 14dd  Boulder Design Labs Inc
 14de  Applied Integration Corporation
 14df  ASIC Communications Corp
 14e1  INVERTEX
 14e2  INFOLIBRIA
 14e3  AMTELCO
-14e4  BROADCOM Corporation
+14e4  Broadcom Corporation
 	1644  NetXtreme BCM5700 Gigabit Ethernet
-		1014 0277  Vigil B5700 1000BaseTX
-		1028 00d1  NetXtreme 1000BaseTX
-		1028 0106  NetXtreme 1000BaseTX
-		1028 0109  NetXtreme 1000BaseTX
+		1014 0277  Broadcom Vigil B5700 1000BaseTX
+		1028 00d1  Broadcom BCM5700
+		1028 0106  Broadcom BCM5700
+		1028 0109  Broadcom BCM5700 1000BaseTX
+		1028 010a  Broadcom BCM5700 1000BaseTX
 		10b7 1000  3C996-T 1000BaseTX
 		10b7 1001  3C996B-T 1000BaseTX
 		10b7 1002  3C996C-T 1000BaseTX
@@ -4739,47 +5029,50 @@
 		14e4 0003  NetXtreme 1000BaseSX
 		14e4 0004  NetXtreme 1000BaseTX
 		14e4 1028  NetXtreme 1000BaseTX
-		14e4 1644  NetXtreme BCM5700 1000BaseTX
+		14e4 1644  BCM5700 1000BaseTX
 	1645  NetXtreme BCM5701 Gigabit Ethernet
 		0e11 007c  NC7770 Gigabit Server Adapter (PCI-X, 10/100/1000-T)
 		0e11 007d  NC6770 Gigabit Server Adapter (PCI-X, 1000-SX)
 		0e11 0085  NC7780 Gigabit Server Adapter (embedded, WOL)
 		0e11 0099  NC7780 Gigabit Server Adapter (embedded, WOL)
 		0e11 009a  NC7770 Gigabit Server Adapter (PCI-X, 10/100/1000-T)
-		1028 0121  NetXtreme BCM5701 1000BaseTX
+		1028 0121  Broadcom BCM5701 1000BaseTX
 		10b7 1004  3C996-SX 1000BaseSX
 		10b7 1006  3C996B-T 1000BaseTX
 		10b7 1007  3C1000-T 1000BaseTX
 		10b7 1008  3C940-BR01 1000BaseTX
-		14e4 0001  NetXtreme BCM5701 1000BaseTX
-		14e4 0005  NetXtreme BCM5701 1000BaseTX
-		14e4 0006  NetXtreme BCM5701 1000BaseTX
-		14e4 0007  NetXtreme BCM5701 1000BaseSX
-		14e4 0008  NetXtreme BCM5701 1000BaseTX
-		14e4 8008  NetXtreme BCM5701 1000BaseTX
+		14e4 0001  BCM5701 1000BaseTX
+		14e4 0005  BCM5701 1000BaseTX
+		14e4 0006  BCM5701 1000BaseTX
+		14e4 0007  BCM5701 1000BaseSX
+		14e4 0008  BCM5701 1000BaseTX
+		14e4 8008  BCM5701 1000BaseTX
 	1646  NetXtreme BCM5702 Gigabit Ethernet
 		0e11 00bb  NC7760 1000BaseTX
-		1028 0126  NetXtreme BCM5702 1000BaseTX
-		14e4 8009  NetXtreme BCM5702 1000BaseTX
+		1028 0126  Broadcom BCM5702 1000BaseTX
+		14e4 8009  BCM5702 1000BaseTX
 	1647  NetXtreme BCM5703 Gigabit Ethernet
 		0e11 0099  NC7780 1000BaseTX
 		0e11 009a  NC7770 1000BaseTX
-		14e4 0009  NetXtreme BCM5703 1000BaseTX
-		14e4 000a  NetXtreme BCM5703 1000BaseSX
-		14e4 000b  NetXtreme BCM5703 1000BaseTX
-		14e4 8009  NetXtreme BCM5703 1000BaseTX
-		14e4 800a  NetXtreme BCM5703 1000BaseTX
+		14e4 0009  BCM5703 1000BaseTX
+		14e4 000a  BCM5703 1000BaseSX
+		14e4 000b  BCM5703 1000BaseTX
+		14e4 8009  BCM5703 1000BaseTX
+		14e4 800a  BCM5703 1000BaseTX
+	1648  NetXtreme BCM5704 Gigabit Ethernet
 	164d  NetXtreme BCM5702FE Gigabit Ethernet
 	16a6  NetXtreme BCM5702X Gigabit Ethernet
 	16a7  NetXtreme BCM5703X Gigabit Ethernet
 	4212  BCM v.90 56k modem
 	5820  BCM5820 Crypto Accelerator
+	5821  BCM5821 Crypto Accelerator
 14e5  Pixelfusion Ltd
 14e6  SHINING Technology Inc
 14e7  3CX
 14e8  RAYCER Inc
 14e9  GARNETS System CO Ltd
-14ea  PLANEX COMMUNICATIONS Inc
+14ea  Planex Communications, Inc
+	ab06  FNW-3603-TX CardBus Fast Ethernet
 14eb  SEIKO EPSON Corp
 14ec  ACQIRIS
 14ed  DATAKINETICS Ltd
@@ -4805,12 +5098,12 @@
 		122d 4034  Dell Thor - MDP3880-W(U) Data Fax Modem
 		13e0 020d  Dell Copper
 		13e0 020e  Dell Silver
-		13e0 0261  IBM # GVC
+		13e0 0261  IBM
 		13e0 0290  Compaq Goldwing
-		13e0 02a0  IBM # GVC
-		13e0 02b0  IBM # GVC
+		13e0 02a0  IBM
+		13e0 02b0  IBM
 		13e0 02c0  Compaq Scooter
-		13e0 02d0  IBM # GVC
+		13e0 02d0  IBM
 		144f 1500  IBM P85-DF (1)
 		144f 1501  IBM P85-DF (2)
 		144f 150a  IBM P85-DF (3)
@@ -4844,8 +5137,8 @@
 	1435  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
 	1436  HCF 56k Data/Fax Modem
 	1453  HCF 56k Data/Fax Modem
-		13e0 0240  IBM # GVC
-		13e0 0250  IBM # GVC
+		13e0 0240  IBM
+		13e0 0250  IBM
 		144f 1502  IBM P95-DF (1)
 		144f 1503  IBM P95-DF (2)
 	1454  HCF 56k Data/Fax/Voice Modem
@@ -4853,6 +5146,8 @@
 	1456  HCF 56k Data/Fax/Voice/Spkp Modem
 		122d 4035  Dell Europa - MDP3900V-W
 		122d 4302  Dell MP3930V-W(C) MiniPCI
+	1610  ADSL AccessRunner PCI Arbitration Device
+	1611  AccessRunner PCI ADSL Interface Device
 	1803  HCF 56k Modem
 		0e11 0023  623-LAN Grizzly
 		0e11 0043  623-LAN Yogi
@@ -4902,9 +5197,9 @@
 	2365  HSF 56k Data/Fax/Voice/Spkp (w/HS) CardBus Modem (Mob SmartDAA)
 	2366  HSF 56k Data/Fax/Voice/Spkp CardBus Modem (Mob SmartDAA)
 	2443  HSF 56k Data/Fax Modem (Mob WorldW SmartDAA)
-		104d 8075  Modem # Sony
-		104d 8083  Modem # Sony
-		104d 8097  Modem # Sony
+		104d 8075  Modem
+		104d 8083  Modem
+		104d 8097  Modem
 	2444  HSF 56k Data/Fax/Voice Modem (Mob WorldW SmartDAA)
 	2445  HSF 56k Data/Fax/Voice/Spkp (w/HS) Modem (Mob WorldW SmartDAA)
 	2446  HSF 56k Data/Fax/Voice/Spkp Modem (Mob WorldW SmartDAA)
@@ -4915,6 +5210,8 @@
 	2f00  HSF 56k HSFi Modem
 		13e0 8d84  IBM HSFi V.90
 		13e0 8d85  Compaq Stinger
+		14f1 2004  Dynalink 56PMi
+	8234  RS8234 ATM SAR Controller [ServiceSAR Plus]
 14f2  MOBILITY Electronics
 14f3  BROADLOGIC
 14f4  TOKYO Electronic Industry CO Ltd
@@ -4962,6 +5259,8 @@
 1514  TFL LAN Inc
 1515  Advent design
 1516  MYSON Technology Inc
+	0803  SURECOM EP-320X-S 100/10M Ethernet PCI Adapter
+		1320 10bd  SURECOM EP-320X-S 100/10M Ethernet PCI Adapter
 1517  ECHOTEK Corp
 1518  PEP MODULAR Computers GmbH
 1519  TELEFON AKTIEBOLAGET LM Ericsson
@@ -4982,7 +5281,7 @@
 		1522 0200  RockForceDUO 2 Port V.92/V.44 Data/Fax/Voice Modem
 		1522 0300  RockForceQUATRO 4 Port V.92/V.44 Data/Fax/Voice Modem
 		1522 0400  RockForceDUO+ 2 Port V.92/V.44 Data/Fax/Voice Modem
-		1522 0500  RockForceQUATRO 4 Port V.92/V.44 Data/Fax/Voice Modem
+		1522 0500  RockForceQUATRO+ 4 Port V.92/V.44 Data/Fax/Voice Modem
 		1522 0600  RockForce+ 2 Port V.90 Data/Fax/Voice Modem
 1523  MUSIC Semiconductors
 1524  ENE Technology Inc
@@ -5176,7 +5475,8 @@
 15c4  EVSX Inc
 15c5  Procomp Informatics Ltd
 15c6  Technical University of Budapest
-15c7  Tateyama Dystem Laboratory Co Ltd
+15c7  Tateyama System Laboratory Co Ltd
+	0349  Tateyama C-PCI PLC/NC card Rev.01A
 15c8  Penta Media Co Ltd
 15c9  Serome Technology Inc
 15ca  Bitboys OY
@@ -5210,6 +5510,7 @@
 15e6  Agere Inc
 15e7  Get Engineering Corp
 15e8  National Datacomm Corp
+	0130  Wireless PCI Card
 15e9  Pacific Digital Corp
 15ea  Tokyo Denshi Sekei K.K.
 15eb  Drsearch GmbH
@@ -5249,16 +5550,32 @@
 1629  Kongsberg Spacetec AS
 	1003  Format synchronizer v3.0
 	2002  Fast Universal Data Output
+1638  Standard Microsystems Corp [SMC]
+	1100  SMC2602W EZConnect / Addtron AWA-100
 1657  Brocade Communications Systems, Inc.
+165d  Hsing Tech. Enterprise Co., Ltd.
+1661  Worldspace Corp.
 1668  Action Tec Electronics Inc
+16ec  U.S. Robotics
+	3685  Wireless Access PCI Adapter Model 022415
 16f6  VideoTele.com, Inc.
 170b  NetOctave Inc
 170c  YottaYotta Inc.
-173b  Altima (nee BroadCom)
+173b  Altima (nee Broadcom)
 	03e8  AC1000 Gigabit Ethernet
 	03ea  AC9100 Gigabit Ethernet
 1743  Peppercon AG
 	8139  ROL/F-100 Fast Ethernet Adapter with ROL
+174b  PC Partner Limited
+175e  Sanera Systems, Inc.
+# also used by Struck Innovative Systeme for joint developments
+1796  Research Centre Juelich
+	0001  SIS1100 [Gigabit link]
+	0002  HOTlink
+	0003  Counter Timer
+	0004  CAMAC Controller
+	0005  PROFIBUS
+	0006  AMCC HOTlink
 1813  Ambient Technologies Inc
 1a08  Sierra semiconductor
 	0000  SC15064
@@ -5289,7 +5606,7 @@
 		3388 8011  VXPro II Chipset CPU to PCI Bridge
 	8012  VXPro II Chipset
 		3388 8012  VXPro II Chipset PCI to ISA Bridge
-	8013  VXPro II Chipset
+	8013  VXPro II IDE
 		3388 8013  VXPro II Chipset EIDE Controller
 3411  Quantum Designs (H.K.) Inc
 3513  ARCOM Control Systems Ltd
@@ -5356,11 +5673,29 @@
 		4a14 5000  RT8029-Based Ethernet Adapter
 4b10  Buslogic Inc.
 4c48  LUNG HWA Electronics
+4c53  SBS Technologies
 4ca1  Seanix Technology Inc
 4d51  MediaQ Inc.
 	0200  MQ-200
 4d54  Microtechnica Co Ltd
 4ddc  ILC Data Device Corp
+	0100  DD-42924I5-300 (ARINC 429 Data Bus)
+	0801  BU-65570I1 MIL-STD-1553 Test and Simulation
+	0802  BU-65570I2 MIL-STD-1553 Test and Simulation
+	0811  BU-65572I1 MIL-STD-1553 Test and Simulation
+	0812  BU-65572I2 MIL-STD-1553 Test and Simulation
+	0881  BU-65570T1 MIL-STD-1553 Test and Simulation
+	0882  BU-65570T2 MIL-STD-1553 Test and Simulation
+	0891  BU-65572T1 MIL-STD-1553 Test and Simulation
+	0892  BU-65572T2 MIL-STD-1553 Test and Simulation
+	0901  BU-65565C1 MIL-STD-1553 Data Bus
+	0902  BU-65565C2 MIL-STD-1553 Data Bus
+	0903  BU-65565C3 MIL-STD-1553 Data Bus
+	0904  BU-65565C4 MIL-STD-1553 Data Bus
+	0b01  BU-65569I1 MIL-STD-1553 Data Bus
+	0b02  BU-65569I2 MIL-STD-1553 Data Bus
+	0b03  BU-65569I3 MIL-STD-1553 Data Bus
+	0b04  BU-65569I4 MIL-STD-1553 Data Bus
 5046  GemTek Technology Corporation
 	1001  PCI Radio
 5053  Voyetra Technologies
@@ -5471,12 +5806,27 @@
 	8a26  ProSavage KM133
 	8c00  ViRGE/M3
 	8c01  ViRGE/MX
+		1179 0001  ViRGE/MX
 	8c02  ViRGE/MX+
 	8c03  ViRGE/MX+MV
 	8c10  86C270-294 Savage/MX-MV
 	8c11  82C270-294 Savage/MX
 	8c12  86C270-294 Savage/IX-MV
 	8c13  86C270-294 Savage/IX
+	8c22  SuperSavage MX/128
+	8c24  SuperSavage MX/64
+	8c26  SuperSavage MX/64C
+	8c2a  SuperSavage IX/128 SDR
+	8c2b  SuperSavage IX/128 DDR
+	8c2c  SuperSavage IX/64 SDR
+	8c2d  SuperSavage IX/64 DDR
+	8c2e  SuperSavage IX/C SDR
+		1014 01fc  ThinkPad T23 (2647-4MG)
+	8c2f  SuperSavage IX/C DDR
+# Integrated in VIA ProSavage PN133 North Bridge
+	8d01  VT8603 [ProSavage PN133] AGP4X VGA Controller (Twister)
+	8d02  VT8636A [ProSavage KN133] AGP4X VGA Controller (TwisterK)
+	8d04  VT8751 [ProSavageDDR P4M266] VGA Controller
 	9102  86C410 Savage 2000
 		1092 5932  Viper II Z200
 		1092 5934  Viper II Z200
@@ -5511,6 +5861,7 @@
 	0011  PWDOG2 [PCI-Watchdog 2]
 8086  Intel Corp.
 	0007  82379AB
+	0008  Extended Express System Support Controller
 	0039  21145
 	0122  82437FX
 	0482  82375EB
@@ -5533,8 +5884,8 @@
 		0e11 004a  NC6136 Gigabit Server Adapter
 		1014 01ea  Netfinity Gigabit Ethernet SX Adapter
 		8086 1003  PRO/1000 F Server Adapter
-	1002  Pro 100 LAN Modem 56 Cardbus II
-		8086 200e  Pro 100 LAN Modem 56 Cardbus II
+	1002  Pro 100 LAN+Modem 56 Cardbus II
+		8086 200e  Pro 100 LAN+Modem 56 Cardbus II
 		8086 2013  Pro 100 SR Mobile Combo Adapter
 		8086 2017  Pro 100 S Combo Mobile Adapter
 	1004  82543GC Gigabit Ethernet Controller
@@ -5551,34 +5902,54 @@
 		8086 1109  PRO/1000 XF Server Adapter
 		8086 2109  PRO/1000 XF Server Adapter
 	100c  82544GC Gigabit Ethernet Controller
-		8086 1109  PRO/1000 T Desktop Adapter
 		8086 1112  PRO/1000 T Desktop Adapter
-		8086 2109  PRO/1000 T Desktop Adapter
 		8086 2112  PRO/1000 T Desktop Adapter
 	100d  82544GC Gigabit Ethernet Controller
+	100e  82540EM Gigabit Ethernet Controller
+		8086 001e  PRO/1000 MT Desktop Adapter
+		8086 002e  PRO/1000 MT Desktop Adapter
+	100f  82545EM Gigabit Ethernet Controller
+		8086 1001  PRO/1000 MT Server Adapter
+	1010  82546EB Gigabit Ethernet Controller
+		8086 1011  PRO/1000 MT Dual Port Server Adapter
+	1011  82545EM Gigabit Ethernet Controller
+		8086 1002  PRO/1000 MF Server Adapter
+	1012  82546EB Gigabit Ethernet Controller
+		8086 1012  PRO/1000 MF Dual Port Server Adapter
 	1029  82559 Ethernet Controller
 	1030  82559 InBusiness 10/100
-	1031  82801CAM (ICH3) Chipset Ethernet Controller
-		1014 0209  EtherExpress PRO/100 VE
-		104d 80e7  Vaio PCG Series
+	1031  82801CAM (ICH3) PRO/100 VE (LOM) Ethernet Controller
+		1014 0209  ThinkPad A30p (2653-64G)
+		104d 80e7  Vaio PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 		107b 5350  EtherExpress PRO/100 VE
 		1179 0001  EtherExpress PRO/100 VE
 		144d c000  EtherExpress PRO/100 VE
 		144d c001  EtherExpress PRO/100 VE
 		144d c003  EtherExpress PRO/100 VE
-	1032  82801CAM (ICH3) Chipset Ethernet Controller
-	1033  82801CAM (ICH3) Chipset Ethernet Controller
-	1034  82801CAM (ICH3) Chipset Ethernet Controller
-	1035  82801CAM (ICH3) Chipset Ethernet Controller
-	1036  82801CAM (ICH3) Chipset Ethernet Controller
+	1032  82801CAM (ICH3) PRO/100 VE Ethernet Controller
+	1033  82801CAM (ICH3) PRO/100 VM (LOM) Ethernet Controller
+	1034  82801CAM (ICH3) PRO/100 VM Ethernet Controller
+	1035  82801CAM (ICH3)/82562EH (LOM)  Ethernet Controller
+	1036  82801CAM (ICH3) 82562EH Ethernet Controller
 	1037  82801CAM (ICH3) Chipset Ethernet Controller
-	1038  82801CAM (ICH3) Chipset Ethernet Controller
+	1038  82801CAM (ICH3) PRO/100 VM (KM) Ethernet Controller
+	1039  82801BD PRO/100 VE (LOM) Ethernet Controller
+	103a  82801BD PRO/100 VE (CNR) Ethernet Controller
+	103b  82801BD PRO/100 VM (LOM) Ethernet Controller
+	103c  82801BD PRO/100 VM (CNR) Ethernet Controller
+	103d  82801BD PRO/100 VE (MOB) Ethernet Controller
+	103e  82801BD PRO/100 VM (MOB) Ethernet Controller
+	1059  82551QM Ethernet Controller
 	1130  82815 815 Chipset Host Bridge and Memory Controller Hub
+		1043 8027  TUSL2-C Mainboard
+		104d 80df  Vaio PCG-FX403
 	1131  82815 815 Chipset AGP Bridge
 	1132  82815 CGC [Chipset Graphics Controller]
+		1025 1016  Travelmate 612 TX
+		104d 80df  Vaio PCG-FX403
 	1161  82806AA PCI64 Hub Advanced Programmable Interrupt Controller
 		8086 1161  82806AA PCI64 Hub APIC
-	1200  Unknown device
+	1200  Intel IXP1200 Network Processor
 		172a 0000  AEP SSL Accelerator
 	1209  82559ER
 	1221  82092AA_0
@@ -5614,6 +5985,7 @@
 		0e11 b164  NC3135 Fast Ethernet Upgrade Module (dual port)
 		0e11 b1a4  NC7131 Gigabit Server Adapter
 		1014 005c  82558B Ethernet Pro 10/100
+		1014 01bc  82559 Fast Ethernet LAN On Motherboard
 		1014 01f1  10/100 Ethernet Server Adapter
 		1014 01f2  10/100 Ethernet Server Adapter
 		1014 0207  Ethernet Pro/100 S
@@ -5628,6 +6000,9 @@
 		1033 8000  PC-9821X-B06
 		1033 8016  PK-UG-X006
 		1033 801f  PK-UG-X006
+		1033 8026  PK-UG-X006
+		1033 8063  82559-based Fast Ethernet Adapter
+		1033 8064  82559-based Fast Ethernet Adapter
 		103c 10c0  NetServer 10/100TX
 		103c 10c3  NetServer 10/100TX
 		103c 10ca  NetServer 10/100TX
@@ -5636,7 +6011,11 @@
 		103c 10e4  NetServer 10/100TX
 		103c 1200  NetServer 10/100TX
 		10c3 1100  SmartEther100 SC1100
+		10cf 1115  8255x-based Ethernet Adapter (10/100)
+		10cf 1143  8255x-based Ethernet Adapter (10/100)
+		1179 0001  8255x-based Ethernet Adapter (10/100)
 		1179 0002  PCI FastEther LAN on Docker
+		1179 0003  8255x-based Fast Ethernet
 		1259 2560  AT-2560 100
 		1259 2561  AT-2560 100 FX Ethernet Adapter
 		1266 0001  NE10/100 Adapter
@@ -5744,6 +6123,8 @@
 	1250  430HX - 82439HX TXC [Triton II]
 	1360  82806AA PCI64 Hub PCI Bridge
 	1361  82806AA PCI64 Hub Controller (HRes)
+		8086 1361  82806AA PCI64 Hub Controller (HRes)
+		8086 8000  82806AA PCI64 Hub Controller (HRes)
 	1460  82870P2 P64H2 Hub PCI Bridge
 	1461  82870P2 P64H2 I/OxAPIC
 	1462  82870P2 P64H2 Hot Plug Controller
@@ -5780,6 +6161,7 @@
 	2412  82801AA USB
 	2413  82801AA SMBus
 	2415  82801AA AC'97 Audio
+		1028 0095  Precision Workstation 220 Integrated Digital Audio
 		11d4 0040  SoundMAX Integrated Digital Audio
 		11d4 0048  SoundMAX Integrated Digital Audio
 		11d4 5340  SoundMAX Integrated Digital Audio
@@ -5796,14 +6178,55 @@
 	2428  82801AB PCI Bridge
 	2440  82801BA ISA Bridge (LPC)
 	2442  82801BA/BAM USB (Hub #1)
+		104d 80df  Vaio PCG-FX403
+		147b 0507  TH7II-RAID
 	2443  82801BA/BAM SMBus
+		1043 8027  TUSL2-C Mainboard
+		104d 80df  Vaio PCG-FX403
+		147b 0507  TH7II-RAID
 	2444  82801BA/BAM USB (Hub #2)
+		104d 80df  Vaio PCG-FX403
+		147b 0507  TH7II-RAID
 	2445  82801BA/BAM AC'97 Audio
+		104d 80df  Vaio PCG-FX403
+		1462 3370  STAC9721 AC
+		147b 0507  TH7II-RAID
 	2446  82801BA/BAM AC'97 Modem
+		104d 80df  Vaio PCG-FX403
 	2448  82801BAM/CAM PCI Bridge
 	2449  82801BA/BAM/CA/CAM Ethernet Controller
+		0e11 0012  EtherExpress PRO/100 VM
+		0e11 0091  EtherExpress PRO/100 VE
+		1014 01ce  EtherExpress PRO/100 VE
+		1014 01dc  EtherExpress PRO/100 VE
+		1014 01eb  EtherExpress PRO/100 VE
+		1014 01ec  EtherExpress PRO/100 VE
+		1014 0202  EtherExpress PRO/100 VE
+		1014 0205  EtherExpress PRO/100 VE
+		1014 0217  EtherExpress PRO/100 VE
+		1014 0234  EtherExpress PRO/100 VE
+		1014 023d  EtherExpress PRO/100 VE
+		1014 0244  EtherExpress PRO/100 VE
+		1014 0245  EtherExpress PRO/100 VE
+		109f 315d  EtherExpress PRO/100 VE
+		109f 3181  EtherExpress PRO/100 VE
+		1186 7801  EtherExpress PRO/100 VE
+		144d 2602  HomePNA 1M CNR
+		8086 3010  EtherExpress PRO/100 VE
+		8086 3011  EtherExpress PRO/100 VM
+		8086 3012  82562EH based Phoneline
+		8086 3013  EtherExpress PRO/100 VE
+		8086 3014  EtherExpress PRO/100 VM
+		8086 3015  82562EH based Phoneline
+		8086 3016  EtherExpress PRO/100 P Mobile Combo
+		8086 3017  EtherExpress PRO/100 P Mobile
+		8086 3018  EtherExpress PRO/100
 	244a  82801BAM IDE U100
+		1025 1016  Travelmate 612TX
+		104d 80df  Vaio PCG-FX403
 	244b  82801BA IDE U100
+		1043 8027  TUSL2-C Mainboard
+		147b 0507  TH7II-RAID
 	244c  82801BAM ISA Bridge (LPC)
 	244e  82801BA/CA/DB PCI Bridge
 	2450  82801E ISA Bridge (LPC)
@@ -5815,12 +6238,28 @@
 	245e  82801E PCI Bridge
 	2480  82801CA ISA Bridge (LPC)
 	2482  82801CA/CAM USB (Hub #1)
+		1014 0220  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	2483  82801CA/CAM SMBus
+		1014 0220  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	2484  82801CA/CAM USB (Hub #2)
+		1014 0220  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	2485  82801CA/CAM AC'97 Audio
+		1014 0222  ThinkPad T23 (2647-4MG)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	2486  82801CA/CAM AC'97 Modem
+		1014 0223  ThinkPad A30p (2653-64G)
+		1014 0503  ThinkPad R31 2656BBG
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+		134d 4c21  Dell Inspiron 2100 internal modem
 	2487  82801CA/CAM USB (Hub #3)
+		1014 0220  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	248a  82801CAM IDE U100
+		1014 0220  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	248b  82801CA IDE U100
 	248c  82801CAM ISA Bridge (LPC)
 	24c0  82801DB ISA Bridge (LPC)
@@ -5830,9 +6269,10 @@
 	24c5  82801DB AC'97 Audio
 	24c6  82801DB AC'97 Modem
 	24c7  82801DB USB (Hub #3)
-	24cb  82801DB IDE U100
+	24cb  82801DB ICH4 IDE
 	24cd  82801DB USB EHCI Controller
 	2500  82820 820 (Camino) Chipset Host Bridge (MCH)
+		1028 0095  Precision Workstation 220 Chipset
 		1043 801c  P3C-2000 system chipset
 	2501  82820 820 (Camino) Chipset Host Bridge (MCH)
 		1043 801c  P3C-2000 system chipset
@@ -5841,20 +6281,26 @@
 	2520  82805AA MTH Memory Translator Hub
 	2521  82804AA MRH-S Memory Repeater Hub for SDRAM
 	2530  82850 850 (Tehama) Chipset Host Bridge (MCH)
-	2531  82850 860 (Wombat) Chipset Host Bridge (MCH)
+		147b 0507  TH7II-RAID
+	2531  82860 860 (Wombat) Chipset Host Bridge (MCH)
 	2532  82850 850 (Tehama) Chipset AGP Bridge
 	2533  82860 860 (Wombat) Chipset AGP Bridge
 	2534  82860 860 (Wombat) Chipset PCI Bridge
-	2540  e7500 (Plumas) DRAM Controller
-	2541  e7500 (Plumas) DRAM Controller Error Reporting
-	2543  e7500 (Plumas) HI_B Virtual PCI-to-PCI Bridge (F0)
-	2544  e7500 (Plumas) HI_B Virtual PCI-to-PCI Bridge (F1)
-	2545  e7500 (Plumas) HI_C Virtual PCI-to-PCI Bridge (F0)
-	2546  e7500 (Plumas) HI_C Virtual PCI-to-PCI Bridge (F1)
-	2547  e7500 (Plumas) HI_D Virtual PCI-to-PCI Bridge (F0)
-	2548  e7500 (Plumas) HI_D Virtual PCI-to-PCI Bridge (F1)
+	2540  e7500 [Plumas] DRAM Controller
+	2541  e7500 [Plumas] DRAM Controller Error Reporting
+	2543  e7500 [Plumas] HI_B Virtual PCI Bridge (F0)
+	2544  e7500 [Plumas] HI_B Virtual PCI Bridge (F1)
+	2545  e7500 [Plumas] HI_C Virtual PCI Bridge (F0)
+	2546  e7500 [Plumas] HI_C Virtual PCI Bridge (F1)
+	2547  e7500 [Plumas] HI_D Virtual PCI Bridge (F0)
+	2548  e7500 [Plumas] HI_D Virtual PCI Bridge (F1)
+	2560  82845G/GL [Brookdale-G] Chipset Host Bridge
+	2561  82845G/GL [Brookdale-G] Chipset AGP Bridge
+	2562  82845G/GL [Brookdale-G] Chipset Integrated Graphics Device
 	3092  Integrated RAID
 	3575  82830 830 Chipset Host Bridge
+		1014 021d  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	3576  82830 830 Chipset AGP Bridge
 	3577  82830 CGC [Chipset Graphics Controller]
 	3578  82830 830 Chipset Host Bridge
@@ -5901,10 +6347,10 @@
 	71a0  440GX - 82443GX Host bridge
 	71a1  440GX - 82443GX AGP bridge
 	71a2  440GX - 82443GX Host bridge (AGP disabled)
-	7600  82372FB PCI to ISA Bridge
-	7601  82372FB PIIX4 IDE
-	7602  82372FB [PCI-to-USB UHCI]
-	7603  82372FB System Management Bus Controller
+	7600  82372FB PIIX5 ISA
+	7601  82372FB PIIX5 IDE
+	7602  82372FB PIIX5 USB
+	7603  82372FB PIIX5 SMBus
 	7800  i740
 		003d 0008  Starfighter AGP
 		003d 000b  Starfighter AGP
@@ -5919,14 +6365,20 @@
 	84cb  450NX - 82454NX/84460GX PCI Expander Bridge
 	84e0  460GX - 84460GX System Address Controller (SAC)
 	84e1  460GX - 84460GX System Data Controller (SDC)
-	84e2  460GX - 84460GX AGP Bridge (GXB)
+	84e2  460GX - 84460GX AGP Bridge (GXB function 2)
 	84e3  460GX - 84460GX Memory Address Controller (MAC)
 	84e4  460GX - 84460GX Memory Data Controller (MDC)
 	84e6  460GX - 82466GX Wide and fast PCI eXpander Bridge (WXB)
+	84ea  460GX - 84460GX AGP Bridge (GXB function 1)
 	9621  Integrated RAID
 	9622  Integrated RAID
 	9641  Integrated RAID
 	96a1  Integrated RAID
+	b152  21152 PCI-to-PCI Bridge
+# observed, and documented in Intel revision note; new mask of 1011:0026
+	b154  21154 PCI-to-PCI Bridge
+	b555  21555 Non transparent PCI-to-PCI Bridge
+		e4bf 1000  CC8-1-BLUES
 	ffff  450NX/GX [Orion] - 82453KX/GX Memory controller [BUG]
 8800  Trigem Computer Inc.
 	2008  Video assistent component
@@ -5954,6 +6406,7 @@
 	5478  AIC-7850
 	5575  AVA-2930
 	5578  AIC-7855
+	5647  ANA-7711 TCP Offload Engine
 	5675  AIC-755x
 	5678  AIC-7856
 	5775  AIC-755x
@@ -6078,6 +6531,8 @@
 	00c3  AIC-7899D U160/m
 	00c5  RAID subsystem HBA
 	00cf  AIC-7899P U160/m
+	0285  AAC-RAID
+		1028 0287  PowerEdge Expandable RAID Controller 320/DC
 907f  Atronics
 	2015  IDE-2015PL
 919a  Gigapixel Corp
@@ -6087,7 +6542,7 @@
 	6565  6565
 9710  NetMos Technology
 	9815  VScom 021H-EP2 2 port parallel adaptor
-	9835  2xserial 1xparallel port adapter
+	9835  222N-2 I/O Card (2S+1P)
 a0a0  AOPEN Inc.
 a0f1  UNISYS Corporation
 a200  NEC Corporation
@@ -6116,10 +6571,24 @@
 	0001  Model 300 128k
 		0059 0001  128k ISDN-S/T Adapter
 		0059 0003  128k ISDN-U Adapter
+	0002  Tiger100APC ISDN chipset
 e4bf  EKF Elektronik GmbH
 ea01  Eagle Technology
 eabb  Aashima Technology B.V.
 eace  Endace Measurement Systems, Ltd
+	3100  DAG 3.10 OC-3/OC-12
+	3200  DAG 3.2x OC-3/OC-12
+	320e  DAG 3.2E Fast Ethernet
+	340e  DAG 3.4E Fast Ethernet
+	341e  DAG 3.41E Fast Ethernet
+	3500  DAG 3.5 OC-3/OC-12
+	351c  DAG 3.5ECM Fast Ethernet
+	4100  DAG 4.10 OC-48
+	4110  DAG 4.11 OC-48
+	4220  DAG 4.2 OC-48
+	422e  DAG 4.2E Dual Gigabit Ethernet
+ec80  Belkin Corporation
+	ec00  F5D6000
 ecc0  Echo Corporation
 edd8  ARK Logic Inc
 	a091  1000PV [Stingray]
@@ -6265,6 +6734,7 @@
 	03  USB Controller
 		00  UHCI
 		10  OHCI
+		20  EHCI
 		80  Unspecified
 		fe  USB Device
 	04  Fibre Channel
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pci/proc.c linux-2.4.20/drivers/pci/proc.c
--- linux-2.4.19/drivers/pci/proc.c	2001-11-17 02:38:39.000000000 +0000
+++ linux-2.4.20/drivers/pci/proc.c	2002-10-29 11:18:48.000000000 +0000
@@ -369,7 +369,7 @@
 	show:	show_device
 };
 
-static struct proc_dir_entry *proc_bus_pci_dir;
+struct proc_dir_entry *proc_bus_pci_dir;
 
 int pci_proc_attach_device(struct pci_dev *dev)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pci/quirks.c linux-2.4.20/drivers/pci/quirks.c
--- linux-2.4.19/drivers/pci/quirks.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/pci/quirks.c	2002-10-29 11:18:31.000000000 +0000
@@ -471,6 +471,29 @@
 	r -> end = 0xffffff;
 }
 
+static void __init quirk_transparent_bridge(struct pci_dev *dev)
+{
+	dev->transparent = 1;
+}
+
+/*
+ * Common misconfiguration of the MediaGX/Geode PCI master that will
+ * reduce PCI bandwidth from 70MB/s to 25MB/s.  See the GXM/GXLV/GX1
+ * datasheets found at http://www.national.com/ds/GX for info on what
+ * these bits do.  <christer@weinigel.se>
+ */
+ 
+static void __init quirk_mediagx_master(struct pci_dev *dev)
+{
+	u8 reg;
+	pci_read_config_byte(dev, 0x41, &reg);
+	if (reg & 2) {
+		reg &= ~2;
+		printk(KERN_INFO "PCI: Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", reg);
+                pci_write_config_byte(dev, 0x41, reg);
+	}
+}
+
 /*
  *  The main table of quirks.
  */
@@ -525,6 +548,15 @@
 
 	{ PCI_FIXUP_FINAL, 	PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_VIPER_7410,	quirk_amd_ioapic },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering },
+	/*
+	 * i82380FB mobile docking controller: its PCI-to-PCI bridge
+	 * is subtractive decoding (transparent), and does indicate this
+	 * in the ProgIf. Unfortunately, the ProgIf value is wrong - 0x80
+	 * instead of 0x01.
+	 */
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82380FB,	quirk_transparent_bridge },
+
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_CYRIX,	PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master },
 
 	{ 0 }
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pci/setup-bus.c linux-2.4.20/drivers/pci/setup-bus.c
--- linux-2.4.19/drivers/pci/setup-bus.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/pci/setup-bus.c	2002-10-29 11:18:40.000000000 +0000
@@ -11,7 +11,10 @@
 
 /*
  * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
- *	     PCI-PCI bridges cleanup, sorted resource allocation
+ *	     PCI-PCI bridges cleanup, sorted resource allocation.
+ * Feb 2002, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
+ *	     Converted to allocation in 3 passes, which gives
+ *	     tighter packing. Prefetchable range support.
  */
 
 #include <linux/init.h>
@@ -23,7 +26,7 @@
 #include <linux/slab.h>
 
 
-#define DEBUG_CONFIG 0
+#define DEBUG_CONFIG 1
 #if DEBUG_CONFIG
 # define DBGC(args)     printk args
 #else
@@ -33,16 +36,14 @@
 #define ROUND_UP(x, a)		(((x) + (a) - 1) & ~((a) - 1))
 
 static int __init
-pbus_assign_resources_sorted(struct pci_bus *bus,
-			     struct pbus_set_ranges_data *ranges)
+pbus_assign_resources_sorted(struct pci_bus *bus)
 {
 	struct list_head *ln;
 	struct resource *res;
-	struct resource_list head_io, head_mem, *list, *tmp;
-	unsigned long io_reserved = 0, mem_reserved = 0;
+	struct resource_list head, *list, *tmp;
 	int idx, found_vga = 0;
 
-	head_io.next = head_mem.next = NULL;
+	head.next = NULL;
 	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
 		struct pci_dev *dev = pci_dev_b(ln);
 		u16 class = dev->class >> 8;
@@ -64,63 +65,26 @@
 			pci_write_config_word(dev, PCI_COMMAND, cmd);
 		}
 
-		/* Reserve some resources for CardBus.
-		   Are these values reasonable? */
-		if (class == PCI_CLASS_BRIDGE_CARDBUS) {
-			io_reserved += 8*1024;
-			mem_reserved += 32*1024*1024;
-			continue;
-		}
-
-		pdev_sort_resources(dev, &head_io, IORESOURCE_IO);
-		pdev_sort_resources(dev, &head_mem, IORESOURCE_MEM);
+		pdev_sort_resources(dev, &head);
 	}
 
-	for (list = head_io.next; list;) {
+	for (list = head.next; list;) {
 		res = list->res;
 		idx = res - &list->dev->resource[0];
-		if (pci_assign_resource(list->dev, idx) == 0
-		    && ranges->io_end < res->end)
-			ranges->io_end = res->end;
+		pci_assign_resource(list->dev, idx);
 		tmp = list;
 		list = list->next;
 		kfree(tmp);
 	}
-	for (list = head_mem.next; list;) {
-		res = list->res;
-		idx = res - &list->dev->resource[0];
-		if (pci_assign_resource(list->dev, idx) == 0
-		    && ranges->mem_end < res->end)
-			ranges->mem_end = res->end;
-		tmp = list;
-		list = list->next;
-		kfree(tmp);
-	}
-
-	ranges->io_end += io_reserved;
-	ranges->mem_end += mem_reserved;
-
-	/* PCI-to-PCI Bridge Architecture Specification rev. 1.1 (1998)
-	   requires that if there is no I/O ports or memory behind the
-	   bridge, corresponding range must be turned off by writing base
-	   value greater than limit to the bridge's base/limit registers.  */
-#if 1
-	/* But assuming that some hardware designed before 1998 might
-	   not support this (very unlikely - at least all DEC bridges
-	   are ok and I believe that was standard de-facto. -ink), we
-	   must allow for at least one unit.  */
-	if (ranges->io_end == ranges->io_start)
-		ranges->io_end += 1;
-	if (ranges->mem_end == ranges->mem_start)
-		ranges->mem_end += 1;
-#endif
-	ranges->io_end = ROUND_UP(ranges->io_end, 4*1024);
-	ranges->mem_end = ROUND_UP(ranges->mem_end, 1024*1024);
 
 	return found_vga;
 }
 
-/* Initialize bridges with base/limit values we have collected */
+/* Initialize bridges with base/limit values we have collected.
+   PCI-to-PCI Bridge Architecture Specification rev. 1.1 (1998)
+   requires that if there is no I/O ports or memory behind the
+   bridge, corresponding range must be turned off by writing base
+   value greater than limit to the bridge's base/limit registers.  */
 static void __init
 pci_setup_bridge(struct pci_bus *bus)
 {
@@ -130,130 +94,307 @@
 
 	if (!bridge || (bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI)
 		return;
+
 	ranges.io_start = bus->resource[0]->start;
 	ranges.io_end = bus->resource[0]->end;
 	ranges.mem_start = bus->resource[1]->start;
 	ranges.mem_end = bus->resource[1]->end;
+	ranges.prefetch_start = bus->resource[2]->start;
+	ranges.prefetch_end = bus->resource[2]->end;
 	pcibios_fixup_pbus_ranges(bus, &ranges);
 
-	DBGC((KERN_ERR "PCI: Bus %d, bridge: %s\n", bus->number, bridge->name));
-	DBGC((KERN_ERR "  IO window: %04lx-%04lx\n", ranges.io_start, ranges.io_end));
-	DBGC((KERN_ERR "  MEM window: %08lx-%08lx\n", ranges.mem_start, ranges.mem_end));
+	DBGC((KERN_INFO "PCI: Bus %d, bridge: %s\n",
+			bus->number, bridge->name));
 
 	/* Set up the top and bottom of the PCI I/O segment for this bus. */
-	pci_read_config_dword(bridge, PCI_IO_BASE, &l);
-	l &= 0xffff0000;
-	l |= (ranges.io_start >> 8) & 0x00f0;
-	l |= ranges.io_end & 0xf000;
+	if (bus->resource[0]->flags & IORESOURCE_IO) {
+		pci_read_config_dword(bridge, PCI_IO_BASE, &l);
+		l &= 0xffff0000;
+		l |= (ranges.io_start >> 8) & 0x00f0;
+		l |= ranges.io_end & 0xf000;
+		/* Set up upper 16 bits of I/O base/limit. */
+		pci_write_config_word(bridge, PCI_IO_BASE_UPPER16,
+				      ranges.io_start >> 16);
+		pci_write_config_word(bridge, PCI_IO_LIMIT_UPPER16,
+				      ranges.io_end >> 16);
+		DBGC((KERN_INFO "  IO window: %04lx-%04lx\n",
+				ranges.io_start, ranges.io_end));
+	}
+	else {
+		/* Clear upper 16 bits of I/O base/limit. */
+		pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0);
+		l = 0x00f0;
+		DBGC((KERN_INFO "  IO window: disabled.\n"));
+	}
 	pci_write_config_dword(bridge, PCI_IO_BASE, l);
 
-	/* Clear upper 16 bits of I/O base/limit. */
-	pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0);
+	/* Set up the top and bottom of the PCI Memory segment
+	   for this bus. */
+	if (bus->resource[1]->flags & IORESOURCE_MEM) {
+		l = (ranges.mem_start >> 16) & 0xfff0;
+		l |= ranges.mem_end & 0xfff00000;
+		DBGC((KERN_INFO "  MEM window: %08lx-%08lx\n",
+				ranges.mem_start, ranges.mem_end));
+	}
+	else {
+		l = 0x0000fff0;
+		DBGC((KERN_INFO "  MEM window: disabled.\n"));
+	}
+	pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
 
 	/* Clear out the upper 32 bits of PREF base/limit. */
 	pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
 	pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
 
-	/* Set up the top and bottom of the PCI Memory segment
-	   for this bus. */
-	l = (ranges.mem_start >> 16) & 0xfff0;
-	l |= ranges.mem_end & 0xfff00000;
-	pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
-
 	/* Set up PREF base/limit. */
-	l = (bus->resource[2]->start >> 16) & 0xfff0;
-	l |= bus->resource[2]->end & 0xfff00000;
+	if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
+		l = (ranges.prefetch_start >> 16) & 0xfff0;
+		l |= ranges.prefetch_end & 0xfff00000;
+		DBGC((KERN_INFO "  PREFETCH window: %08lx-%08lx\n",
+				ranges.prefetch_start, ranges.prefetch_end));
+	}
+	else {
+		l = 0x0000fff0;
+		DBGC((KERN_INFO "  PREFETCH window: disabled.\n"));
+	}
 	pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
 
 	/* Check if we have VGA behind the bridge.
-	   Enable ISA in either case. */
+	   Enable ISA in either case (FIXME!). */
 	l = (bus->resource[0]->flags & IORESOURCE_BUS_HAS_VGA) ? 0x0c : 0x04;
 	pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, l);
 }
 
+/* Check whether the bridge supports optional I/O and
+   prefetchable memory ranges. If not, the respective
+   base/limit registers must be read-only and read as 0. */
 static void __init
-pbus_assign_resources(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
+pci_bridge_check_ranges(struct pci_bus *bus)
+{
+	u16 io;
+	u32 pmem;
+	struct pci_dev *bridge = bus->self;
+	struct resource *b_res;
+
+	if (!bridge || (bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+		return;
+
+	b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
+	b_res[1].flags |= IORESOURCE_MEM;
+
+	pci_read_config_word(bridge, PCI_IO_BASE, &io);
+	if (!io) {
+		pci_write_config_word(bridge, PCI_IO_BASE, 0xf0f0);
+		pci_read_config_word(bridge, PCI_IO_BASE, &io);
+ 		pci_write_config_word(bridge, PCI_IO_BASE, 0x0);
+ 	}
+ 	if (io)
+		b_res[0].flags |= IORESOURCE_IO;
+	/*  DECchip 21050 pass 2 errata: the bridge may miss an address
+	    disconnect boundary by one PCI data phase.
+	    Workaround: do not use prefetching on this device. */
+	if (bridge->vendor == PCI_VENDOR_ID_DEC && bridge->device == 0x0001)
+		return;
+	pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
+	if (!pmem) {
+		pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE,
+					       0xfff0fff0);
+		pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
+		pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0);
+	}
+	if (pmem)
+		b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
+}
+
+/* Sizing the IO windows of the PCI-PCI bridge is trivial,
+   since these windows have 4K granularity and the IO ranges
+   of non-bridge PCI devices are limited to 256 bytes.
+   We must be careful with the ISA aliasing though. */
+static void __init
+pbus_size_io(struct pci_bus *bus)
 {
 	struct list_head *ln;
-	int found_vga = pbus_assign_resources_sorted(bus, ranges);
+	struct resource *b_res = bus->resource[0];
+	unsigned long size = 0, size1 = 0;
 
-	if (!ranges->found_vga && found_vga) {
-		struct pci_bus *b;
+	if (!(b_res->flags & IORESOURCE_IO))
+		return;
 
-		ranges->found_vga = 1;
-		/* Propogate presence of the VGA to upstream bridges */
-		for (b = bus; b->parent; b = b->parent) {
-#if 0
-			/* ? Do we actually need to enable PF memory? */
-			b->resource[2]->start = 0;
+	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+		struct pci_dev *dev = pci_dev_b(ln);
+		int i;
+		
+		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+			struct resource *r = &dev->resource[i];
+			unsigned long r_size;
+
+			if (r->parent || !(r->flags & IORESOURCE_IO))
+				continue;
+			r_size = r->end - r->start + 1;
+
+			if (r_size < 0x400)
+				/* Might be re-aligned for ISA */
+				size += r_size;
+			else
+				size1 += r_size;
+		}
+		/* ??? Reserve some resources for CardBus. */
+		if ((dev->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS)
+			size1 += 4*1024;
+	}
+/* To be fixed in 2.5: we should have sort of HAVE_ISA
+   flag in the struct pci_bus. */
+#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
+	size = (size & 0xff) + ((size & ~0xffUL) << 2);
 #endif
-			b->resource[0]->flags |= IORESOURCE_BUS_HAS_VGA;
+	size = ROUND_UP(size + size1, 4096);
+	if (!size) {
+		b_res->flags = 0;
+		return;
+	}
+	/* Alignment of the IO window is always 4K */
+	b_res->start = 4096;
+	b_res->end = b_res->start + size - 1;
+}
+
+/* Calculate the size of the bus and minimal alignment which
+   guarantees that all child resources fit in this size. */
+static void __init
+pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
+{
+	struct list_head *ln;
+	unsigned long min_align, align, size;
+	unsigned long aligns[12];	/* Alignments from 1Mb to 2Gb */
+	int order, max_order;
+	struct resource *b_res = (type & IORESOURCE_PREFETCH) ?
+				 bus->resource[2] : bus->resource[1];
+
+	memset(aligns, 0, sizeof(aligns));
+	max_order = 0;
+	size = 0;
+
+	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+		struct pci_dev *dev = pci_dev_b(ln);
+		int i;
+		
+		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+			struct resource *r = &dev->resource[i];
+			unsigned long r_size;
+
+			if (r->parent || (r->flags & mask) != type)
+				continue;
+			r_size = r->end - r->start + 1;
+			/* For bridges size != alignment */
+			align = (i < PCI_BRIDGE_RESOURCES) ? r_size : r->start;
+			order = ffz(~align) - 20;
+			if (order > 11) {
+				printk(KERN_WARNING "PCI: region %s/%d "
+				       "too large: %lx-%lx\n",
+				       dev->slot_name, i, r->start, r->end);
+				r->flags = 0;
+				continue;
+			}
+			size += r_size;
+			if (order < 0)
+				order = 0;
+			/* Exclude ranges with size > align from
+			   calculation of the alignment. */
+			if (size == align)
+				aligns[order] += align;
+			if (order > max_order)
+				max_order = order;
+		}
+		/* ??? Reserve some resources for CardBus. */
+		if ((dev->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) {
+			size += 1UL << 24;		/* 16 Mb */
+			aligns[24 - 20] += 1UL << 24;
 		}
 	}
-	for (ln=bus->children.next; ln != &bus->children; ln=ln->next) {
-		struct pci_bus *b = pci_bus_b(ln);
 
-		b->resource[0]->start = ranges->io_start = ranges->io_end;
-		b->resource[1]->start = ranges->mem_start = ranges->mem_end;
+	align = 0;
+	min_align = 0;
+	for (order = 0; order <= max_order; order++) {
+		unsigned long align1 = 1UL << (order + 20);
+
+		if (!align)
+			min_align = align1;
+		else if (ROUND_UP(align + min_align, min_align) < align1)
+			min_align = align1 >> 1;
+		align += aligns[order];
+	}
+	size = ROUND_UP(size, min_align);
+	if (!size) {
+		b_res->flags = 0;
+		return;
+	}
+	b_res->start = min_align;
+	b_res->end = size + min_align - 1;
+}
+
+void __init
+pbus_size_bridges(struct pci_bus *bus)
+{
+	struct list_head *ln;
+	unsigned long mask, type;
+
+	for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
+		pbus_size_bridges(pci_bus_b(ln));
 
-		pbus_assign_resources(b, ranges);
+	/* The root bus? */
+	if (!bus->self)
+		return;
 
-		b->resource[0]->end = ranges->io_end - 1;
-		b->resource[1]->end = ranges->mem_end - 1;
+	pci_bridge_check_ranges(bus);
 
-		/* Add bridge resources to the resource tree. */
-		if (b->resource[0]->end > b->resource[0]->start &&
-		    request_resource(bus->resource[0], b->resource[0]) < 0)
-			printk(KERN_ERR "PCI: failed to reserve IO "
-					"for bus %d\n",	b->number);
-		if (b->resource[1]->end > b->resource[1]->start &&
-		    request_resource(bus->resource[1], b->resource[1]) < 0)
-			printk(KERN_ERR "PCI: failed to reserve MEM "
-					"for bus %d\n", b->number);
+	pbus_size_io(bus);
 
-		pci_setup_bridge(b);
+	mask = type = IORESOURCE_MEM;
+	/* If the bridge supports prefetchable range, size it separately. */
+	if (bus->resource[2] &&
+	    bus->resource[2]->flags & IORESOURCE_PREFETCH) {
+		pbus_size_mem(bus, IORESOURCE_PREFETCH, IORESOURCE_PREFETCH);
+		mask |= IORESOURCE_PREFETCH;	/* Size non-prefetch only. */
 	}
+	pbus_size_mem(bus, mask, type);
 }
 
 void __init
-pci_assign_unassigned_resources(void)
+pbus_assign_resources(struct pci_bus *bus)
 {
-	struct pbus_set_ranges_data ranges;
 	struct list_head *ln;
-	struct pci_dev *dev;
+	int found_vga = pbus_assign_resources_sorted(bus);
 
-	for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next) {
-		struct pci_bus *b = pci_bus_b(ln);
+	if (found_vga) {
+		struct pci_bus *b;
 
-		ranges.io_start = b->resource[0]->start + PCIBIOS_MIN_IO;
-		ranges.mem_start = b->resource[1]->start + PCIBIOS_MIN_MEM;
-		ranges.io_end = ranges.io_start;
-		ranges.mem_end = ranges.mem_start;
-		ranges.found_vga = 0;
-		pbus_assign_resources(b, &ranges);
+		/* Propagate presence of the VGA to upstream bridges */
+		for (b = bus; b->parent; b = b->parent) {
+			b->resource[0]->flags |= IORESOURCE_BUS_HAS_VGA;
+		}
 	}
-	pci_for_each_dev(dev) {
-		pdev_enable_device(dev);
+	for (ln=bus->children.next; ln != &bus->children; ln=ln->next) {
+		struct pci_bus *b = pci_bus_b(ln);
+
+		pbus_assign_resources(b);
+		pci_setup_bridge(b);
 	}
 }
 
-/* Check whether the bridge supports I/O forwarding.
-   If not, its I/O base/limit register must be
-   read-only and read as 0. */
-unsigned long __init
-pci_bridge_check_io(struct pci_dev *bridge)
+void __init
+pci_assign_unassigned_resources(void)
 {
-	u16 io;
+	struct list_head *ln;
+	struct pci_dev *dev;
 
-	pci_read_config_word(bridge, PCI_IO_BASE, &io);
-	if (!io) {
-		pci_write_config_word(bridge, PCI_IO_BASE, 0xf0f0);
-		pci_read_config_word(bridge, PCI_IO_BASE, &io);
-		pci_write_config_word(bridge, PCI_IO_BASE, 0x0);
+	/* Depth first, calculate sizes and alignments of all
+	   subordinate buses. */
+	for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next)
+		pbus_size_bridges(pci_bus_b(ln));
+	/* Depth last, allocate resources and update the hardware. */
+	for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next)
+		pbus_assign_resources(pci_bus_b(ln));
+
+	pci_for_each_dev(dev) {
+		pdev_enable_device(dev);
 	}
-	if (io)
-		return IORESOURCE_IO;
-	printk(KERN_WARNING "PCI: bridge %s does not support I/O forwarding!\n",
-				bridge->name);
-	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pci/setup-res.c linux-2.4.20/drivers/pci/setup-res.c
--- linux-2.4.19/drivers/pci/setup-res.c	2001-10-05 01:47:08.000000000 +0000
+++ linux-2.4.20/drivers/pci/setup-res.c	2002-10-29 11:18:36.000000000 +0000
@@ -69,6 +69,7 @@
 	unsigned int type_mask,
 	int resno)
 {
+	unsigned long align;
 	int i;
 
 	type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
@@ -81,12 +82,20 @@
 		if ((res->flags ^ r->flags) & type_mask)
 			continue;
 
-		/* We cannot allocate a non-prefetching resource from a pre-fetching area */
-		if ((r->flags & IORESOURCE_PREFETCH) && !(res->flags & IORESOURCE_PREFETCH))
+		/* We cannot allocate a non-prefetching resource
+		   from a pre-fetching area */
+		if ((r->flags & IORESOURCE_PREFETCH) &&
+		    !(res->flags & IORESOURCE_PREFETCH))
 			continue;
 
+		/* The bridge resources are special, as their
+		   size != alignment. Sizing routines return
+		   required alignment in the "start" field. */
+		align = (resno < PCI_BRIDGE_RESOURCES) ? size : res->start;
+
 		/* Ok, try it out.. */
-		if (allocate_resource(r, res, size, min, -1, size, pcibios_align_resource, dev) < 0)
+		if (allocate_resource(r, res, size, min, -1, align,
+				      pcibios_align_resource, dev) < 0)
 			continue;
 
 		/* Update PCI config space.  */
@@ -127,47 +136,45 @@
 	return 0;
 }
 
-/* Sort resources of a given type by alignment */
+/* Sort resources by alignment */
 void __init
-pdev_sort_resources(struct pci_dev *dev,
-		    struct resource_list *head, u32 type_mask)
+pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
 {
 	int i;
 
 	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
 		struct resource *r;
 		struct resource_list *list, *tmp;
-		unsigned long r_size;
-
-		/* PCI-PCI bridges may have I/O ports or
-		   memory on the primary bus */
-		if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI &&
-						i >= PCI_BRIDGE_RESOURCES)
-			continue;
+		unsigned long r_align;
 
 		r = &dev->resource[i];
-		r_size = r->end - r->start;
+		r_align = r->end - r->start;
 		
-		if (!(r->flags & type_mask) || r->parent)
+		if (!(r->flags) || r->parent)
 			continue;
-		if (!r_size) {
+		if (!r_align) {
 			printk(KERN_WARNING "PCI: Ignore bogus resource %d "
-					 "[%lx:%lx] of %s\n",
-					  i, r->start, r->end, dev->name);
+					    "[%lx:%lx] of %s\n",
+					    i, r->start, r->end, dev->name);
 			continue;
 		}
+		r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start;
 		for (list = head; ; list = list->next) {
-			unsigned long size = 0;
+			unsigned long align = 0;
 			struct resource_list *ln = list->next;
+			int idx;
 
-			if (ln)
-				size = ln->res->end - ln->res->start;
-			if (r_size > size) {
+			if (ln) {
+				idx = ln->res - &ln->dev->resource[0];
+				align = (idx < PCI_BRIDGE_RESOURCES) ?
+					ln->res->end - ln->res->start + 1 :
+					ln->res->start;
+			}
+			if (r_align > align) {
 				tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
-				if (!tmp) {
-					printk(KERN_ERR "pdev_sort_resources(): kmalloc() failed!\n");
-					continue;
-				}
+				if (!tmp)
+					panic("pdev_sort_resources(): "
+					      "kmalloc() failed!\n");
 				tmp->next = ln;
 				tmp->res = r;
 				tmp->dev = dev;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pcmcia/au1000_generic.c linux-2.4.20/drivers/pcmcia/au1000_generic.c
--- linux-2.4.19/drivers/pcmcia/au1000_generic.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/pcmcia/au1000_generic.c	2002-10-29 11:18:36.000000000 +0000
@@ -59,6 +59,7 @@
 static int pc_debug;
 #endif
 
+MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Pete Popov, MontaVista Software <ppopov@mvista.com>");
 MODULE_DESCRIPTION("Linux PCMCIA Card Services: Au1x00 Socket Controller");
 
@@ -84,7 +85,7 @@
 static int  au1000_pcmcia_driver_init(void);
 static void au1000_pcmcia_driver_shutdown(void);
 static void au1000_pcmcia_task_handler(void *data);
-static void au1000_pcmcia_poll_event(u32 data);
+static void au1000_pcmcia_poll_event(unsigned long data);
 static void au1000_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs);
 static struct tq_struct au1000_pcmcia_task;
 
@@ -141,6 +142,11 @@
 
 	printk("\nAu1x00 PCMCIA (CS release %s)\n", CS_RELEASE);
 
+#ifndef CONFIG_64BIT_PHYS_ADDR
+	printk(KERN_ERR "Au1x00 PCMCIA 36 bit IO support not enabled\n");
+	return -1;
+#endif
+
 	CardServices(GetCardServicesInfo, &info);
 
 	if(info.Revision!=CS_RELEASE_CODE){
@@ -148,10 +154,8 @@
 		return -1;
 	}
 
-#ifdef CONFIG_MIPS_PB1000
-	pcmcia_low_level=&pb1000_pcmcia_ops;
-#elif defined(CONFIG_MIPS_PB1500)
-	pcmcia_low_level=&pb1500_pcmcia_ops;
+#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500)
+	pcmcia_low_level=&pb1x00_pcmcia_ops;
 #else
 #error Unsupported AU1000 board.
 #endif
@@ -162,12 +166,7 @@
 		return -EIO;
 	}
 
-	/* setup the static bus controller */
-	timing3 = 0x100e3a07;
-	writel(0x00000002, MEM_STCFG3);  /* type = PCMCIA */
-	writel(timing3, MEM_STTIME3); 
-	writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */
-	au_sync_delay(1);
+	/* NOTE: the chip select must already be setup */
 
 	pcmcia_socket = 
 		kmalloc(sizeof(struct au1000_pcmcia_socket) * socket_count, 
@@ -179,6 +178,11 @@
 	memset(pcmcia_socket, 0,
 			sizeof(struct au1000_pcmcia_socket) * socket_count);
 			
+	/* 
+	 * Assuming max of 2 sockets, which the Au1000 supports.
+	 * WARNING: the Pb1000 has two sockets, and both work, but you
+	 * can't use them both at the same time due to glue logic conflicts.
+	 */
 	for(i=0; i < socket_count; i++) {
 
 		if(pcmcia_low_level->socket_state(i, &state)<0){
@@ -190,13 +194,15 @@
 		
 		if (i == 0) {
 			pcmcia_socket[i].virt_io = 
-				(u32)ioremap(0xC0000000, 0x1000);
-			pcmcia_socket[i].phys_attr = 0xC4000000;
-			pcmcia_socket[i].phys_mem = 0xC8000000;
+				(u32)ioremap((ioaddr_t)0xF00000000, 0x1000);
+			pcmcia_socket[i].phys_attr = (memaddr_t)0xF40000000;
+			pcmcia_socket[i].phys_mem = (memaddr_t)0xF80000000;
 		}
 		else  {
-			printk(KERN_ERR "au1000: socket 1 not supported\n");
-			return 1;
+			pcmcia_socket[i].virt_io = 
+				(u32)ioremap((ioaddr_t)0xF08000000, 0x1000);
+			pcmcia_socket[i].phys_attr = (memaddr_t)0xF48000000;
+			pcmcia_socket[i].phys_mem = (memaddr_t)0xF88000000;
 		}
 	}
 
@@ -299,7 +305,7 @@
 };
 
 
-static void au1000_pcmcia_poll_event(u32 dummy)
+static void au1000_pcmcia_poll_event(unsigned long dummy)
 {
 	poll_timer.function = au1000_pcmcia_poll_event;
 	poll_timer.expires = jiffies + AU1000_PCMCIA_POLL_PERIOD;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pcmcia/au1000_pb1000.c linux-2.4.20/drivers/pcmcia/au1000_pb1000.c
--- linux-2.4.19/drivers/pcmcia/au1000_pb1000.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/pcmcia/au1000_pb1000.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,307 +0,0 @@
-/*
- *
- * Alchemy Semi PB1000 board specific pcmcia routines.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *         	ppopov@mvista.com or source@mvista.com
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- *
- * 
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/config.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/tqueue.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/proc_fs.h>
-#include <linux/version.h>
-#include <linux/types.h>
-
-#include <pcmcia/version.h>
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/ss.h>
-#include <pcmcia/bulkmem.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/bus_ops.h>
-#include "cs_internal.h"
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#include <asm/au1000.h>
-#include <asm/au1000_pcmcia.h>
-#include <asm/pb1000.h>
-
-
-extern struct pcmcia_x_table x_table;
-
-static int pb1000_pcmcia_init(struct pcmcia_init *init)
-{
-	u32 pcr;
-	pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST;
-
-	writel(0x8000, PB1000_MDR); /* clear pcmcia interrupt */
-	au_sync_delay(100);
-	writel(0x4000, PB1000_MDR); /* enable pcmcia interrupt */
-	au_sync();
-
-	pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0);
-	pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1);
-	writew(pcr, PB1000_PCR);
-	au_sync_delay(20);
-	  
-	/* There's two sockets, but only the first one, 0, is used and tested */
-	return 1;
-}
-
-static int pb1000_pcmcia_shutdown(void)
-{
-	u16 pcr;
-	pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST;
-	pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0);
-	pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1);
-	writew(pcr, PB1000_PCR);
-	au_sync_delay(20);
-	return 0;
-}
-
-static int 
-pb1000_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
-{
-	u16 levels, pcr;
-	unsigned char vs;
-
-	levels = readw(PB1000_ACR1);
-	pcr = readw(PB1000_PCR);
-
-	state->ready = 0;
-	state->vs_Xv = 0;
-	state->vs_3v = 0;
-	state->detect = 0;
-
-	/* 
-	 * This is tricky. The READY pin is also the #IRQ pin.  We'll treat
-	 * READY as #IRQ and set state->ready to 1 whenever state->detect 
-	 * is true.
-	 */
-
-	/* 
-	 * CD1/2 are active low; so are the VSS pins; Ready is active high
-	 */
-	if (sock == 0) {
-		if (!(levels & (ACR1_SLOT_0_CD1 | ACR1_SLOT_0_CD2))) {
-			state->detect = 1;
-			vs =  (levels >> 4) & 0x3;
-			switch (vs) {
-				case 0:
-				case 1:
-				case 2:
-					state->vs_3v=1;
-					break;
-				case 3:
-				default:
-					break;
-			}
-		}
-	}
-	else if (sock == 1) {
-		if (!(levels & (ACR1_SLOT_1_CD1 | ACR1_SLOT_1_CD2))) {
-			state->detect = 1;
-			vs =  (levels >> 12) & 0x3;
-			switch (vs) {
-				case 0:
-				case 1:
-				case 2:
-					state->vs_3v=1;
-					break;
-				case 3:
-				default:
-					break;
-			}
-		}
-	}
-	else  {
-		printk(KERN_ERR "pb1000 socket_state bad sock %d\n", sock);
-	}
-
-	if (state->detect)
-		state->ready = 1;
-
-	state->bvd1=1;
-	state->bvd2=1;
-	state->wrprot=0; 
-	return 1;
-}
-
-
-static int pb1000_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
-{
-
-	if(info->sock > PCMCIA_MAX_SOCK) return -1;
-
-	if(info->sock == 0)
-		info->irq = AU1000_GPIO_15;
-	else 
-		info->irq = -1;
-
-	return 0;
-}
-
-
-static int 
-pb1000_pcmcia_configure_socket(const struct pcmcia_configure *configure)
-{
-	u16 pcr;
-
-	if(configure->sock > PCMCIA_MAX_SOCK) return -1;
-
-	pcr = readw(PB1000_PCR);
-
-	if (configure->sock == 0) {
-		pcr &= ~(PCR_SLOT_0_VCC0 | PCR_SLOT_0_VCC1 | 
-				PCR_SLOT_0_VPP0 | PCR_SLOT_0_VPP1);
-	}
-	else  {
-		pcr &= ~(PCR_SLOT_1_VCC0 | PCR_SLOT_1_VCC1 | 
-				PCR_SLOT_1_VPP0 | PCR_SLOT_1_VPP1);
-	}
-
-	pcr &= ~PCR_SLOT_0_RST;
-	/*
-	writew(pcr, PB1000_PCR);
-	au_sync_delay(200);
-	*/
-	DEBUG(KERN_INFO "Vcc %dV Vpp %dV, pcr %x\n", 
-			configure->vcc, configure->vpp, pcr);
-	switch(configure->vcc){
-		case 0:  /* Vcc 0 */
-			switch(configure->vpp) {
-				case 0:
-					pcr |= SET_VCC_VPP(VCC_HIZ,VPP_GND,
-							configure->sock);
-					break;
-				case 12:
-					pcr |= SET_VCC_VPP(VCC_HIZ,VPP_12V,
-							configure->sock);
-					break;
-				case 50:
-					pcr |= SET_VCC_VPP(VCC_HIZ,VPP_5V,
-							configure->sock);
-					break;
-				case 33:
-					pcr |= SET_VCC_VPP(VCC_HIZ,VPP_3V,
-							configure->sock);
-					break;
-				default:
-					pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
-							configure->sock);
-					printk("%s: bad Vcc/Vpp (%d:%d)\n", 
-							__FUNCTION__, 
-							configure->vcc, 
-							configure->vpp);
-					break;
-			}
-			break;
-		case 50: /* Vcc 5V */
-			switch(configure->vpp) {
-				case 0:
-					pcr |= SET_VCC_VPP(VCC_5V,VPP_GND,
-							configure->sock);
-					break;
-				case 50:
-					pcr |= SET_VCC_VPP(VCC_5V,VPP_5V,
-							configure->sock);
-					break;
-				case 12:
-					pcr |= SET_VCC_VPP(VCC_5V,VPP_12V,
-							configure->sock);
-					break;
-				case 33:
-					pcr |= SET_VCC_VPP(VCC_5V,VPP_3V,
-							configure->sock);
-					break;
-				default:
-					pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
-							configure->sock);
-					printk("%s: bad Vcc/Vpp (%d:%d)\n", 
-							__FUNCTION__, 
-							configure->vcc, 
-							configure->vpp);
-					break;
-			}
-			break;
-		case 33: /* Vcc 3.3V */
-			switch(configure->vpp) {
-				case 0:
-					pcr |= SET_VCC_VPP(VCC_3V,VPP_GND,
-							configure->sock);
-					break;
-				case 50:
-					pcr |= SET_VCC_VPP(VCC_3V,VPP_5V,
-							configure->sock);
-					break;
-				case 12:
-					pcr |= SET_VCC_VPP(VCC_3V,VPP_12V,
-							configure->sock);
-					break;
-				case 33:
-					pcr |= SET_VCC_VPP(VCC_3V,VPP_3V,
-							configure->sock);
-					break;
-				default:
-					pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
-							configure->sock);
-					printk("%s: bad Vcc/Vpp (%d:%d)\n", 
-							__FUNCTION__, 
-							configure->vcc, 
-							configure->vpp);
-					break;
-			}
-			break;
-		default: /* what's this ? */
-			pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,configure->sock);
-			printk(KERN_ERR "%s: bad Vcc %d\n", 
-					__FUNCTION__, configure->vcc);
-			break;
-	}
-
-	pcr &= ~(PCR_SLOT_0_RST);
-	if (configure->reset) {
-		pcr |= PCR_SLOT_0_RST;
-	}
-	writew(pcr, PB1000_PCR);
-	au_sync_delay(300);
-	return 0;
-}
-
-struct pcmcia_low_level pb1000_pcmcia_ops = { 
-	pb1000_pcmcia_init,
-	pb1000_pcmcia_shutdown,
-	pb1000_pcmcia_socket_state,
-	pb1000_pcmcia_get_irq_info,
-	pb1000_pcmcia_configure_socket
-};
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pcmcia/au1000_pb1x00.c linux-2.4.20/drivers/pcmcia/au1000_pb1x00.c
--- linux-2.4.19/drivers/pcmcia/au1000_pb1x00.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/pcmcia/au1000_pb1x00.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,411 @@
+/*
+ *
+ * Alchemy Semi Pb1x00 boards specific pcmcia routines.
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or source@mvista.com
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/tqueue.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/proc_fs.h>
+#include <linux/version.h>
+#include <linux/types.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/bus_ops.h>
+#include "cs_internal.h"
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include <asm/au1000.h>
+#include <asm/au1000_pcmcia.h>
+
+#ifdef CONFIG_MIPS_PB1000
+#include <asm/pb1000.h>
+#define PCMCIA_IRQ AU1000_GPIO_15
+#elif defined (CONFIG_MIPS_PB1500)
+#include <asm/pb1500.h>
+#define PCMCIA_IRQ AU1000_GPIO_11   /* fixme */
+#elif defined (CONFIG_MIPS_PB1100)
+#include <asm/pb1100.h>
+#define PCMCIA_IRQ AU1000_GPIO_11
+#endif
+
+static int pb1x00_pcmcia_init(struct pcmcia_init *init)
+{
+#ifdef CONFIG_MIPS_PB1000
+	u16 pcr;
+	pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST;
+
+	au_writel(0x8000, PB1000_MDR); /* clear pcmcia interrupt */
+	au_sync_delay(100);
+	au_writel(0x4000, PB1000_MDR); /* enable pcmcia interrupt */
+	au_sync();
+
+	pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0);
+	pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1);
+	au_writel(pcr, PB1000_PCR);
+	au_sync_delay(20);
+	  
+	return PCMCIA_NUM_SOCKS;
+
+#else /* fixme -- take care of the Pb1500 at some point */
+
+	u16 pcr;
+	pcr = au_readw(PB1100_MEM_PCMCIA) & ~0xf; /* turn off power */
+	pcr &= ~(PB1100_PC_DEASSERT_RST | PB1100_PC_DRV_EN);
+	au_writew(pcr, PB1100_MEM_PCMCIA);
+	au_sync_delay(500);
+	return PCMCIA_NUM_SOCKS;
+#endif
+}
+
+static int pb1x00_pcmcia_shutdown(void)
+{
+#ifdef CONFIG_MIPS_PB1000
+	u16 pcr;
+	pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST;
+	pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0);
+	pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1);
+	au_writel(pcr, PB1000_PCR);
+	au_sync_delay(20);
+	return 0;
+#else
+	u16 pcr;
+	pcr = au_readw(PB1100_MEM_PCMCIA) & ~0xf; /* turn off power */
+	pcr &= ~(PB1100_PC_DEASSERT_RST | PB1100_PC_DRV_EN);
+	au_writew(pcr, PB1100_MEM_PCMCIA);
+	au_sync_delay(2);
+	return 0;
+#endif
+}
+
+static int 
+pb1x00_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
+{
+	u32 inserted0, inserted1;
+	u16 vs0, vs1;
+
+#ifdef CONFIG_MIPS_PB1000
+	vs0 = vs1 = (u16)au_readl(PB1000_ACR1);
+	inserted0 = !(vs0 & (ACR1_SLOT_0_CD1 | ACR1_SLOT_0_CD2));
+	inserted1 = !(vs1 & (ACR1_SLOT_1_CD1 | ACR1_SLOT_1_CD2));
+	vs0 = (vs0 >> 4) & 0x3;
+	vs1 = (vs1 >> 12) & 0x3;
+#else
+	vs0 = (au_readw(PB1100_BOARD_STATUS) >> 4) & 0x3;
+	inserted0 = !((au_readl(SYS_PINSTATERD) >> 9) & 0x1); /* gpio 9 */
+#endif
+
+	state->ready = 0;
+	state->vs_Xv = 0;
+	state->vs_3v = 0;
+	state->detect = 0;
+
+	if (sock == 0) {
+		if (inserted0) {
+			switch (vs0) {
+				case 0:
+				case 2:
+					state->vs_3v=1;
+					break;
+				case 3: /* 5V */
+					break;
+				default:
+					/* return without setting 'detect' */
+					printk(KERN_ERR "pb1x00 bad VS (%d)\n",
+							vs0);
+					return;
+			}
+			state->detect = 1;
+		}
+	}
+	else  {
+		if (inserted1) {
+			switch (vs1) {
+				case 0:
+				case 2:
+					state->vs_3v=1;
+					break;
+				case 3: /* 5V */
+					break;
+				default:
+					/* return without setting 'detect' */
+					printk(KERN_ERR "pb1x00 bad VS (%d)\n",
+							vs1);
+					return;
+			}
+			state->detect = 1;
+		}
+	}
+
+	if (state->detect) {
+		state->ready = 1;
+	}
+
+	state->bvd1=1;
+	state->bvd2=1;
+	state->wrprot=0; 
+	return 1;
+}
+
+
+static int pb1x00_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+
+	if(info->sock > PCMCIA_MAX_SOCK) return -1;
+
+	/*
+	 * Even in the case of the Pb1000, both sockets are connected
+	 * to the same irq line.
+	 */
+	info->irq = PCMCIA_IRQ;
+
+	return 0;
+}
+
+
+static int 
+pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
+{
+	u16 pcr;
+
+	if(configure->sock > PCMCIA_MAX_SOCK) return -1;
+
+#ifdef CONFIG_MIPS_PB1000
+	pcr = au_readl(PB1000_PCR);
+
+	if (configure->sock == 0) {
+		pcr &= ~(PCR_SLOT_0_VCC0 | PCR_SLOT_0_VCC1 | 
+				PCR_SLOT_0_VPP0 | PCR_SLOT_0_VPP1);
+	}
+	else  {
+		pcr &= ~(PCR_SLOT_1_VCC0 | PCR_SLOT_1_VCC1 | 
+				PCR_SLOT_1_VPP0 | PCR_SLOT_1_VPP1);
+	}
+
+	pcr &= ~PCR_SLOT_0_RST;
+	DEBUG(KERN_INFO "Vcc %dV Vpp %dV, pcr %x\n", 
+			configure->vcc, configure->vpp, pcr);
+	switch(configure->vcc){
+		case 0:  /* Vcc 0 */
+			switch(configure->vpp) {
+				case 0:
+					pcr |= SET_VCC_VPP(VCC_HIZ,VPP_GND,
+							configure->sock);
+					break;
+				case 12:
+					pcr |= SET_VCC_VPP(VCC_HIZ,VPP_12V,
+							configure->sock);
+					break;
+				case 50:
+					pcr |= SET_VCC_VPP(VCC_HIZ,VPP_5V,
+							configure->sock);
+					break;
+				case 33:
+					pcr |= SET_VCC_VPP(VCC_HIZ,VPP_3V,
+							configure->sock);
+					break;
+				default:
+					pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
+							configure->sock);
+					printk("%s: bad Vcc/Vpp (%d:%d)\n", 
+							__FUNCTION__, 
+							configure->vcc, 
+							configure->vpp);
+					break;
+			}
+			break;
+		case 50: /* Vcc 5V */
+			switch(configure->vpp) {
+				case 0:
+					pcr |= SET_VCC_VPP(VCC_5V,VPP_GND,
+							configure->sock);
+					break;
+				case 50:
+					pcr |= SET_VCC_VPP(VCC_5V,VPP_5V,
+							configure->sock);
+					break;
+				case 12:
+					pcr |= SET_VCC_VPP(VCC_5V,VPP_12V,
+							configure->sock);
+					break;
+				case 33:
+					pcr |= SET_VCC_VPP(VCC_5V,VPP_3V,
+							configure->sock);
+					break;
+				default:
+					pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
+							configure->sock);
+					printk("%s: bad Vcc/Vpp (%d:%d)\n", 
+							__FUNCTION__, 
+							configure->vcc, 
+							configure->vpp);
+					break;
+			}
+			break;
+		case 33: /* Vcc 3.3V */
+			switch(configure->vpp) {
+				case 0:
+					pcr |= SET_VCC_VPP(VCC_3V,VPP_GND,
+							configure->sock);
+					break;
+				case 50:
+					pcr |= SET_VCC_VPP(VCC_3V,VPP_5V,
+							configure->sock);
+					break;
+				case 12:
+					pcr |= SET_VCC_VPP(VCC_3V,VPP_12V,
+							configure->sock);
+					break;
+				case 33:
+					pcr |= SET_VCC_VPP(VCC_3V,VPP_3V,
+							configure->sock);
+					break;
+				default:
+					pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
+							configure->sock);
+					printk("%s: bad Vcc/Vpp (%d:%d)\n", 
+							__FUNCTION__, 
+							configure->vcc, 
+							configure->vpp);
+					break;
+			}
+			break;
+		default: /* what's this ? */
+			pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,configure->sock);
+			printk(KERN_ERR "%s: bad Vcc %d\n", 
+					__FUNCTION__, configure->vcc);
+			break;
+	}
+
+	if (configure->sock == 0) {
+	pcr &= ~(PCR_SLOT_0_RST);
+		if (configure->reset)
+		pcr |= PCR_SLOT_0_RST;
+	}
+	else {
+		pcr &= ~(PCR_SLOT_1_RST);
+		if (configure->reset)
+			pcr |= PCR_SLOT_1_RST;
+	}
+	au_writel(pcr, PB1000_PCR);
+	au_sync_delay(300);
+
+#else
+
+	pcr = au_readw(PB1100_MEM_PCMCIA) & ~0xf;
+
+	DEBUG(KERN_INFO "Vcc %dV Vpp %dV, pcr %x, reset %d\n", 
+			configure->vcc, configure->vpp, pcr, configure->reset);
+
+
+	switch(configure->vcc){
+		case 0:  /* Vcc 0 */
+			pcr |= SET_VCC_VPP(0,0);
+			break;
+		case 50: /* Vcc 5V */
+			switch(configure->vpp) {
+				case 0:
+					pcr |= SET_VCC_VPP(2,0);
+					break;
+				case 50:
+					pcr |= SET_VCC_VPP(2,1);
+					break;
+				case 12:
+					pcr |= SET_VCC_VPP(2,2);
+					break;
+				case 33:
+				default:
+					pcr |= SET_VCC_VPP(0,0);
+					printk("%s: bad Vcc/Vpp (%d:%d)\n", 
+							__FUNCTION__, 
+							configure->vcc, 
+							configure->vpp);
+					break;
+			}
+			break;
+		case 33: /* Vcc 3.3V */
+			switch(configure->vpp) {
+				case 0:
+					pcr |= SET_VCC_VPP(1,0);
+					break;
+				case 12:
+					pcr |= SET_VCC_VPP(1,2);
+					break;
+				case 33:
+					pcr |= SET_VCC_VPP(1,1);
+					break;
+				case 50:
+				default:
+					pcr |= SET_VCC_VPP(0,0);
+					printk("%s: bad Vcc/Vpp (%d:%d)\n", 
+							__FUNCTION__, 
+							configure->vcc, 
+							configure->vpp);
+					break;
+			}
+			break;
+		default: /* what's this ? */
+			pcr |= SET_VCC_VPP(0,0);
+			printk(KERN_ERR "%s: bad Vcc %d\n", 
+					__FUNCTION__, configure->vcc);
+			break;
+	}
+
+	au_writew(pcr, PB1100_MEM_PCMCIA);
+	au_sync_delay(300);
+
+	if (!configure->reset) {
+		pcr |= PB1100_PC_DRV_EN;
+		au_writew(pcr, PB1100_MEM_PCMCIA);
+		au_sync_delay(100);
+		pcr |= PB1100_PC_DEASSERT_RST;
+		au_writew(pcr, PB1100_MEM_PCMCIA);
+		au_sync_delay(100);
+	}
+	else {
+		pcr &= ~(PB1100_PC_DEASSERT_RST | PB1100_PC_DRV_EN);
+		au_writew(pcr, PB1100_MEM_PCMCIA);
+		au_sync_delay(100);
+	}
+#endif
+	return 0;
+}
+
+struct pcmcia_low_level pb1x00_pcmcia_ops = { 
+	pb1x00_pcmcia_init,
+	pb1x00_pcmcia_shutdown,
+	pb1x00_pcmcia_socket_state,
+	pb1x00_pcmcia_get_irq_info,
+	pb1x00_pcmcia_configure_socket
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pcmcia/bulkmem.c linux-2.4.20/drivers/pcmcia/bulkmem.c
--- linux-2.4.19/drivers/pcmcia/bulkmem.c	2001-08-13 00:37:53.000000000 +0000
+++ linux-2.4.20/drivers/pcmcia/bulkmem.c	2002-10-29 11:18:48.000000000 +0000
@@ -211,7 +211,7 @@
     retry_erase((erase_busy_t *)arg, MTD_REQ_TIMEOUT);
 }
 
-static int setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
+static void setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
 {
     erase_busy_t *busy;
     region_info_t *info;
@@ -229,8 +229,10 @@
 	else {
 	    erase->State = 1;
 	    busy = kmalloc(sizeof(erase_busy_t), GFP_KERNEL);
-	    if (!busy)
-		return CS_GENERAL_FAILURE;
+	    if (!busy) {
+		erase->State = ERASE_FAILED;
+		return;
+	    }
 	    busy->erase = erase;
 	    busy->client = handle;
 	    init_timer(&busy->timeout);
@@ -240,7 +242,6 @@
 	    retry_erase(busy, 0);
 	}
     }
-    return CS_SUCCESS;
 } /* setup_erase_request */
 
 /*======================================================================
@@ -325,7 +326,7 @@
     
 ======================================================================*/
 
-static int setup_regions(client_handle_t handle, int attr,
+static void setup_regions(client_handle_t handle, int attr,
 			  memory_handle_t *list)
 {
     int i, code, has_jedec, has_geo;
@@ -340,7 +341,7 @@
 
     code = (attr) ? CISTPL_DEVICE_A : CISTPL_DEVICE;
     if (read_tuple(handle, code, &device) != CS_SUCCESS)
-	return CS_GENERAL_FAILURE;
+	return;
     code = (attr) ? CISTPL_JEDEC_A : CISTPL_JEDEC_C;
     has_jedec = (read_tuple(handle, code, &jedec) == CS_SUCCESS);
     if (has_jedec && (device.ndev != jedec.nid)) {
@@ -363,8 +364,10 @@
 	if ((device.dev[i].type != CISTPL_DTYPE_NULL) &&
 	    (device.dev[i].size != 0)) {
 	    r = kmalloc(sizeof(*r), GFP_KERNEL);
-	    if (!r)
-		return CS_GENERAL_FAILURE;
+	    if (!r) {
+		printk(KERN_NOTICE "cs: setup_regions: kmalloc failed!\n");
+		return;
+	    }
 	    r->region_magic = REGION_MAGIC;
 	    r->state = 0;
 	    r->dev_info[0] = '\0';
@@ -389,7 +392,6 @@
 	}
 	offset += device.dev[i].size;
     }
-    return CS_SUCCESS;
 } /* setup_regions */
 
 /*======================================================================
@@ -423,10 +425,8 @@
     
     if ((handle->Attributes & INFO_MASTER_CLIENT) &&
 	(!(s->state & SOCKET_REGION_INFO))) {
-	if (setup_regions(handle, 0, &s->c_region) != CS_SUCCESS)
-	    return CS_GENERAL_FAILURE;
-	if (setup_regions(handle, 1, &s->a_region) != CS_SUCCESS)
-	    return CS_GENERAL_FAILURE;
+	setup_regions(handle, 0, &s->c_region);
+	setup_regions(handle, 1, &s->a_region);
 	s->state |= SOCKET_REGION_INFO;
     }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pcmcia/cardbus.c linux-2.4.20/drivers/pcmcia/cardbus.c
--- linux-2.4.19/drivers/pcmcia/cardbus.c	2001-11-12 17:39:01.000000000 +0000
+++ linux-2.4.20/drivers/pcmcia/cardbus.c	2002-10-29 11:18:35.000000000 +0000
@@ -15,7 +15,7 @@
     rights and limitations under the License.
 
     The initial developer of the original code is David A. Hinds
-    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pcmcia/cirrus.h linux-2.4.20/drivers/pcmcia/cirrus.h
--- linux-2.4.19/drivers/pcmcia/cirrus.h	2001-02-17 00:02:36.000000000 +0000
+++ linux-2.4.20/drivers/pcmcia/cirrus.h	2002-10-29 11:18:34.000000000 +0000
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pcmcia/i82092.c linux-2.4.20/drivers/pcmcia/i82092.c
--- linux-2.4.19/drivers/pcmcia/i82092.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/pcmcia/i82092.c	2002-10-29 11:18:51.000000000 +0000
@@ -25,6 +25,8 @@
 #include "i82092aa.h"
 #include "i82365.h"
 
+MODULE_LICENSE("GPL");
+
 /* PCI core routines */
 static struct pci_device_id i82092aa_pci_ids[] = {
 	{
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pcmcia/i82365.c linux-2.4.20/drivers/pcmcia/i82365.c
--- linux-2.4.19/drivers/pcmcia/i82365.c	2001-11-12 17:39:01.000000000 +0000
+++ linux-2.4.20/drivers/pcmcia/i82365.c	2002-10-29 11:18:49.000000000 +0000
@@ -15,7 +15,7 @@
     rights and limitations under the License.
 
     The initial developer of the original code is David A. Hinds
-    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pcmcia/i82365.h linux-2.4.20/drivers/pcmcia/i82365.h
--- linux-2.4.19/drivers/pcmcia/i82365.h	2001-02-17 00:02:36.000000000 +0000
+++ linux-2.4.20/drivers/pcmcia/i82365.h	2002-10-29 11:18:34.000000000 +0000
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pcmcia/o2micro.h linux-2.4.20/drivers/pcmcia/o2micro.h
--- linux-2.4.19/drivers/pcmcia/o2micro.h	2001-02-17 00:02:36.000000000 +0000
+++ linux-2.4.20/drivers/pcmcia/o2micro.h	2002-10-29 11:18:35.000000000 +0000
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pcmcia/ricoh.h linux-2.4.20/drivers/pcmcia/ricoh.h
--- linux-2.4.19/drivers/pcmcia/ricoh.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/pcmcia/ricoh.h	2002-10-29 11:18:40.000000000 +0000
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pcmcia/tcic.c linux-2.4.20/drivers/pcmcia/tcic.c
--- linux-2.4.19/drivers/pcmcia/tcic.c	2001-09-30 19:26:07.000000000 +0000
+++ linux-2.4.20/drivers/pcmcia/tcic.c	2002-10-29 11:18:31.000000000 +0000
@@ -15,7 +15,7 @@
     rights and limitations under the License.
 
     The initial developer of the original code is David A. Hinds
-    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
@@ -67,7 +67,7 @@
 #define DEBUG(n, args...)
 #endif
 
-MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>");
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
 MODULE_DESCRIPTION("Databook TCIC-2 PCMCIA socket driver");
 MODULE_LICENSE("Dual MPL/GPL");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pcmcia/tcic.h linux-2.4.20/drivers/pcmcia/tcic.h
--- linux-2.4.19/drivers/pcmcia/tcic.h	2001-02-17 00:02:36.000000000 +0000
+++ linux-2.4.20/drivers/pcmcia/tcic.h	2002-10-29 11:18:40.000000000 +0000
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pcmcia/ti113x.h linux-2.4.20/drivers/pcmcia/ti113x.h
--- linux-2.4.19/drivers/pcmcia/ti113x.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/pcmcia/ti113x.h	2002-10-29 11:18:37.000000000 +0000
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pcmcia/topic.h linux-2.4.20/drivers/pcmcia/topic.h
--- linux-2.4.19/drivers/pcmcia/topic.h	2001-02-17 00:02:36.000000000 +0000
+++ linux-2.4.20/drivers/pcmcia/topic.h	2002-10-29 11:18:51.000000000 +0000
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pcmcia/vg468.h linux-2.4.20/drivers/pcmcia/vg468.h
--- linux-2.4.19/drivers/pcmcia/vg468.h	2001-02-17 00:02:36.000000000 +0000
+++ linux-2.4.20/drivers/pcmcia/vg468.h	2002-10-29 11:18:37.000000000 +0000
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pnp/isapnp.c linux-2.4.20/drivers/pnp/isapnp.c
--- linux-2.4.19/drivers/pnp/isapnp.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/pnp/isapnp.c	2002-10-29 11:18:48.000000000 +0000
@@ -28,6 +28,8 @@
  *  2001-11-07  Added isapnp_{,un}register_driver calls along the lines
  *              of the pci driver interface
  *              Kai Germaschewski <kai.germaschewski@gmx.de>
+ *  2002-06-06  Made the use of dma channel 0 configurable 
+ *              Gerald Teschl <gerald.teschl@univie.ac.at>
  */
 
 #include <linux/config.h>
@@ -59,6 +61,7 @@
 int isapnp_disable;			/* Disable ISA PnP */
 int isapnp_rdp;				/* Read Data Port */
 int isapnp_reset = 1;			/* reset all PnP cards (deactivate) */
+int isapnp_allow_dma0 = -1;		/* allow dma 0 during auto activation: -1=off (:default), 0=off (set by user), 1=on */
 int isapnp_skip_pci_scan;		/* skip PCI resource scanning */
 int isapnp_verbose = 1;			/* verbose mode */
 int isapnp_reserve_irq[16] = { [0 ... 15] = -1 };	/* reserve (don't use) some IRQ */
@@ -74,6 +77,8 @@
 MODULE_PARM_DESC(isapnp_rdp, "ISA Plug & Play read data port");
 MODULE_PARM(isapnp_reset, "i");
 MODULE_PARM_DESC(isapnp_reset, "ISA Plug & Play reset all cards");
+MODULE_PARM(isapnp_allow_dma0, "i");
+MODULE_PARM_DESC(isapnp_allow_dma0, "Allow dma value 0 during auto activation");
 MODULE_PARM(isapnp_skip_pci_scan, "i");
 MODULE_PARM_DESC(isapnp_skip_pci_scan, "ISA Plug & Play skip PCI resource scanning");
 MODULE_PARM(isapnp_verbose, "i");
@@ -1750,13 +1755,14 @@
 
 static int isapnp_check_dma(struct isapnp_cfgtmp *cfg, int dma, int idx)
 {
-	int i;
+	int i, mindma =1;
 	struct pci_dev *dev;
 
 	/* Some machines allow DMA 0, but others don't. In fact on some 
 	   boxes DMA 0 is the memory refresh. Play safe */
-	   
-	if (dma < 1 || dma == 4 || dma > 7)
+	if (isapnp_allow_dma0 == 1)
+		mindma = 0;
+	if (dma < mindma || dma == 4 || dma > 7)
 		return 1;
 	for (i = 0; i < 8; i++) {
 		if (isapnp_reserve_dma[i] == dma)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/pnp/isapnp_proc.c linux-2.4.20/drivers/pnp/isapnp_proc.c
--- linux-2.4.19/drivers/pnp/isapnp_proc.c	2001-01-17 21:29:14.000000000 +0000
+++ linux-2.4.20/drivers/pnp/isapnp_proc.c	2002-10-29 11:18:37.000000000 +0000
@@ -944,6 +944,22 @@
 	res->start = res->end = dma;
 	res->flags = IORESOURCE_DMA;
 }
+
+extern int isapnp_allow_dma0;
+static int isapnp_set_allow_dma0(char *line)
+{
+	int i;
+	char value[32];
+
+	isapnp_get_str(value, line, sizeof(value));
+	i = simple_strtoul(value, NULL, 0);
+	if (i < 0 || i > 1) {
+		printk("isapnp: wrong value %i for allow_dma0\n", i);
+		return 1;
+	}
+	isapnp_allow_dma0 = i;
+	return 0;
+}
  
 static int isapnp_set_dma(char *line)
 {
@@ -1030,6 +1046,8 @@
 	char cmd[32];
 
 	line = isapnp_get_str(cmd, line, sizeof(cmd));
+	if (!strcmp(cmd, "allow_dma0"))
+		return isapnp_set_allow_dma0(line);
 	if (!strcmp(cmd, "card"))
 		return isapnp_set_card(line);
 	if (!strcmp(cmd, "csn"))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/s390/block/dasd.c linux-2.4.20/drivers/s390/block/dasd.c
--- linux-2.4.19/drivers/s390/block/dasd.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/s390/block/dasd.c	2002-10-29 11:18:40.000000000 +0000
@@ -4055,7 +4055,12 @@
 dasd_statistics_write (struct file *file, const char *user_buf,
 		       size_t user_len, loff_t * offset)
 {
-	char *buffer = vmalloc (user_len);
+	char *buffer;
+	
+	if(user_len > 65536)
+		user_len = 65536;
+		
+	buffer = vmalloc (user_len);
 
 	if (buffer == NULL)
 		return -ENOMEM;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/s390/char/hwc.h linux-2.4.20/drivers/s390/char/hwc.h
--- linux-2.4.19/drivers/s390/char/hwc.h	2001-07-25 21:12:02.000000000 +0000
+++ linux-2.4.20/drivers/s390/char/hwc.h	2002-10-29 11:18:48.000000000 +0000
@@ -22,6 +22,7 @@
 #define ET_PMsgCmd		0x09
 #define ET_CntlProgOpCmd	0x20
 #define ET_CntlProgIdent	0x0B
+#define ET_SigQuiesce	0x1D
 
 #define ET_OpCmd_Mask	0x80000000
 #define ET_Msg_Mask		0x40000000
@@ -29,6 +30,7 @@
 #define ET_PMsgCmd_Mask	0x00800000
 #define ET_CtlProgOpCmd_Mask	0x00000001
 #define ET_CtlProgIdent_Mask	0x00200000
+#define ET_SigQuiesce_Mask	0x00000008
 
 #define GMF_DOM		0x8000
 #define GMF_SndAlrm	0x4000
@@ -214,7 +216,8 @@
 	0x0000,
 	0x0000,
 	sizeof (_hwcb_mask_t),
-	ET_OpCmd_Mask | ET_PMsgCmd_Mask | ET_StateChange_Mask,
+	ET_OpCmd_Mask | ET_PMsgCmd_Mask |
+	ET_StateChange_Mask | ET_SigQuiesce_Mask,
 	ET_Msg_Mask | ET_PMsgCmd_Mask | ET_CtlProgIdent_Mask
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/s390/char/hwc_rw.c linux-2.4.20/drivers/s390/char/hwc_rw.c
--- linux-2.4.19/drivers/s390/char/hwc_rw.c	2001-09-30 19:26:07.000000000 +0000
+++ linux-2.4.20/drivers/s390/char/hwc_rw.c	2002-10-29 11:18:33.000000000 +0000
@@ -35,6 +35,8 @@
 #define MIN(a,b) (((a<b) ? a : b))
 #endif
 
+extern void ctrl_alt_del (void);
+
 #define HWC_RW_PRINT_HEADER "hwc low level driver: "
 
 #define  USE_VM_DETECTION
@@ -172,6 +174,7 @@
 	unsigned char read_nonprio:1;
 	unsigned char read_prio:1;
 	unsigned char read_statechange:1;
+	unsigned char sig_quiesce:1;
 
 	unsigned char flags;
 
@@ -222,6 +225,7 @@
 	    0,
 	    0,
 	    0,
+	    0,
 	    NULL,
 	    NULL
 
@@ -231,6 +235,8 @@
 static unsigned long cr0_save __attribute__ ((aligned (8)));
 static unsigned char psw_mask __attribute__ ((aligned (8)));
 
+static ext_int_info_t ext_int_info_hwc;
+
 #define DELAYED_WRITE 0
 #define IMMEDIATE_WRITE 1
 
@@ -1527,6 +1533,19 @@
 				       HWC_RW_PRINT_HEADER
 				 "can not read state change notifications\n");
 
+	hwc_data.sig_quiesce
+	    = ((mask & ET_SigQuiesce_Mask) == ET_SigQuiesce_Mask);
+	if (hwc_data.sig_quiesce)
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "can receive signal quiesce\n");
+	else
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "can not receive signal quiesce\n");
+
 	hwc_data.read_nonprio
 	    = ((mask & ET_OpCmd_Mask) == ET_OpCmd_Mask);
 	if (hwc_data.read_nonprio)
@@ -1607,6 +1626,48 @@
 	return retval;
 }
 
+#ifdef CONFIG_SMP
+extern unsigned long cpu_online_map;
+static volatile unsigned long cpu_quiesce_map;
+
+static void 
+do_load_quiesce_psw (void)
+{
+	psw_t quiesce_psw;
+
+	clear_bit (smp_processor_id (), &cpu_quiesce_map);
+	if (smp_processor_id () == 0) {
+
+		while (cpu_quiesce_map != 0) ;
+
+		quiesce_psw.mask = _DW_PSW_MASK;
+		quiesce_psw.addr = 0xfff;
+		__load_psw (quiesce_psw);
+	}
+	signal_processor (smp_processor_id (), sigp_stop);
+}
+
+static void 
+do_machine_quiesce (void)
+{
+	cpu_quiesce_map = cpu_online_map;
+	smp_call_function (do_load_quiesce_psw, NULL, 0, 0);
+	do_load_quiesce_psw ();
+}
+
+#else
+static void 
+do_machine_quiesce (void)
+{
+	psw_t quiesce_psw;
+
+	quiesce_psw.mask = _DW_PSW_MASK;
+	queisce_psw.addr = 0xfff;
+	__load_psw (quiesce_psw);
+}
+
+#endif
+
 static int 
 process_evbufs (void *start, void *end)
 {
@@ -1642,6 +1703,13 @@
 			retval += eval_statechangebuf
 			    ((statechangebuf_t *) evbuf);
 			break;
+		case ET_SigQuiesce:
+
+			_machine_restart = do_machine_quiesce;
+			_machine_halt = do_machine_quiesce;
+			_machine_power_off = do_machine_quiesce;
+			ctrl_alt_del ();
+			break;
 		default:
 			internal_print (
 					       DELAYED_WRITE,
@@ -2004,7 +2072,8 @@
 
 #endif
 
-	if (register_external_interrupt (0x2401, hwc_interrupt_handler) != 0)
+	if (register_early_external_interrupt (0x2401, hwc_interrupt_handler,
+					       &ext_int_info_hwc) != 0)
 		panic ("Couldn't request external interrupts 0x2401");
 
 	spin_lock_init (&hwc_data.lock);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/s390/char/tuball.c linux-2.4.20/drivers/s390/char/tuball.c
--- linux-2.4.19/drivers/s390/char/tuball.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/s390/char/tuball.c	2002-10-29 11:18:35.000000000 +0000
@@ -222,6 +222,16 @@
 	MOD_DEC_USE_COUNT;
 }
 
+static int
+tub3270_is_ours(s390_dev_info_t *dp)
+{
+	if ((dp->sid_data.cu_type & 0xfff0) == 0x3270)
+		return 1;
+	if (dp->sid_data.cu_type == 0x3174)
+		return 1;
+	return 0;
+}
+
 /*
  * tub3270_init() called by kernel or module initialization
  */
@@ -277,7 +287,7 @@
 		}
 #endif /* LINUX_VERSION_CODE */
 #endif /* CONFIG_TN3270_CONSOLE */
-		if ((d.sid_data.cu_type & 0xfff0) != 0x3270)
+		if (!tub3270_is_ours(&d))
 			continue;
 
 		rc = tubmakemin(i, &d);
@@ -450,6 +460,8 @@
 			tubp->cmd = TBC_CONOPEN;
 			tubp->flags |= TUB_OPEN_STET | TUB_INPUT_HACK;
 			tty3270_size(tubp, &flags);
+			tubp->tty_input = kmalloc(GEOM_INPLEN,
+				GFP_KERNEL|GFP_DMA);
 			tty3270_aid_init(tubp);
 			tty3270_scl_init(tubp);
 			tub3270_con_irq = tubp->irq;
@@ -491,6 +503,10 @@
 			tubdelbyirq(tubp, tubp->irq);
 			tty3270_rcl_fini(tubp);
 			kfree(tubp->tty_bcb.bc_buf);
+			if (tubp->tty_input) {
+				kfree(tubp->tty_input);
+				tubp->tty_input = NULL;
+			}
 			tubp->tty_bcb.bc_buf = NULL;
 			tubp->ttyscreen = NULL;
 			kfree(tubp);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/s390/char/tubfs.c linux-2.4.20/drivers/s390/char/tubfs.c
--- linux-2.4.19/drivers/s390/char/tubfs.c	2001-09-07 16:28:38.000000000 +0000
+++ linux-2.4.20/drivers/s390/char/tubfs.c	2002-10-29 11:18:32.000000000 +0000
@@ -42,11 +42,11 @@
 {
 	char name[16];
 
-	sprintf(name, "tub%.3x", tubp->devno);
+	sprintf(name, "tub%.4x", tubp->devno);
 	devfs_register(fs3270_devfs_dir, name, DEVFS_FL_DEFAULT,
 		       IBM_FS3270_MAJOR, tubp->minor,
 		       S_IFCHR | S_IRUSR | S_IWUSR, &fs3270_fops, NULL);
-	sprintf(name, "tty%.3x", tubp->devno);
+	sprintf(name, "tty%.4x", tubp->devno);
 	tty_register_devfs_name(&tty3270_driver, 0, tubp->minor,
 				fs3270_devfs_dir, name);
 }
@@ -56,12 +56,12 @@
 	char name[16];
 	devfs_handle_t handle;
 
-	sprintf(name, "tub%.3x", tubp->devno);
+	sprintf(name, "tub%.4x", tubp->devno);
 	handle = devfs_find_handle (fs3270_devfs_dir, name,
 				    IBM_FS3270_MAJOR, tubp->minor,
 				    DEVFS_SPECIAL_CHR, 0);
 	devfs_unregister (handle);
-	sprintf(name, "tty%.3x", tubp->devno);
+	sprintf(name, "tty%.4x", tubp->devno);
 	handle = devfs_find_handle (fs3270_devfs_dir, name,
 				    IBM_TTY3270_MAJOR, tubp->minor,
 				    DEVFS_SPECIAL_CHR, 0);
@@ -241,12 +241,18 @@
 {
 	long flags;
 	tub_t *tubp;
+	addr_t *ip;
 
 	tubp = data;
 	TUBLOCK(tubp->irq, flags);
 	tubp->flags &= ~TUB_BHPENDING;
 
 	if (tubp->wbuf) {       /* if we were writing */
+		for (ip = tubp->wbuf; ip < tubp->wbuf+33; ip++) {
+			if (*ip == 0)
+				break;
+			kfree(phys_to_virt(*ip));
+		}
 		kfree(tubp->wbuf);
 		tubp->wbuf = NULL;
 	}
@@ -289,8 +295,6 @@
 #define	DEV_UE_BUSY \
 	(DEV_STAT_CHN_END | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP)
 
-	tubp->dstat = dsp->dstat;
-
 #ifdef RBHNOTYET
 	/* XXX needs more work; must save 2d arg to fs370_io() */
 	/* Handle CE-DE-UE and subsequent UDE */
@@ -373,47 +377,77 @@
 	ccw1_t *cp;
 	int rc;
 	long flags;
+	addr_t *idalp, *ip;
+	char *tp;
+	int count, piece;
+	int size;
+
+	if (len == 0 || len > 65535) {
+		return -EINVAL;
+	}
 
 	if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
 		return -ENODEV;
-	if ((rc = fs3270_wait(tubp, &flags)) != 0) {
-		TUBUNLOCK(tubp->irq, flags);
-		return rc;
+
+	if ((ip = idalp = idal_alloc(33)) == NULL)
+		return -EFAULT;
+	memset(idalp, 0, 33 * sizeof *idalp);
+	count = len;
+	while (count) {
+		piece = MIN(count, 0x800);
+		size = count == len? piece: 0x800;
+		if ((kp = kmalloc(size, GFP_KERNEL|GFP_DMA)) == NULL) {
+			len = -ENOMEM;
+			goto do_cleanup;
+		}
+		*ip++ = virt_to_phys(kp);
+		count -= piece;
 	}
 
-	kp = kmalloc(len, GFP_KERNEL|GFP_DMA);
-	if (kp == NULL) {
+	if ((rc = fs3270_wait(tubp, &flags)) != 0) {
 		TUBUNLOCK(tubp->irq, flags);
-		return -ENOMEM;
+		len = rc;
+		goto do_cleanup;
 	}
-
 	cp = &tubp->rccw;
 	if (tubp->icmd == 0 && tubp->ocmd != 0)  tubp->icmd = 6;
 	cp->cmd_code = tubp->icmd?:2;
-	cp->flags = CCW_FLAG_SLI;
+	cp->flags = CCW_FLAG_SLI | CCW_FLAG_IDA;
 	cp->count = len;
-	cp->cda = virt_to_phys(kp);
+	cp->cda = virt_to_phys(idalp);
 	tubp->flags |= TUB_RDPENDING;
 	TUBUNLOCK(tubp->irq, flags);
 
 	if ((rc = fs3270_wait(tubp, &flags)) != 0) {
 		tubp->flags &= ~TUB_RDPENDING;
+		len = rc;
 		TUBUNLOCK(tubp->irq, flags);
-		kfree(kp);
-		return rc;
+		goto do_cleanup;
 	}
+	TUBUNLOCK(tubp->irq, flags);
 
 	len -= tubp->cswl;
-	TUBUNLOCK(tubp->irq, flags);
-	if (tubdebug & 1)
-		printk(KERN_DEBUG "minor %d: %.8x %.8x %.8x %.8x\n",
-			tubp->minor,
-			*(int*)((long)kp + 0),
-			*(int*)((long)kp + 4),
-			*(int*)((long)kp + 8),
-			*(int*)((long)kp + 12));
-	copy_to_user(dp, kp, len);
-	kfree(kp);
+	count = len;
+	tp = dp;
+	ip = idalp;
+	while (count) {
+		piece = MIN(count, 0x800);
+		if (copy_to_user(tp, phys_to_virt(*ip), piece) != 0) {
+			len = -EFAULT;
+			goto do_cleanup;
+		}
+		count -= piece;
+		tp += piece;
+		ip++;
+	}
+
+do_cleanup:
+	for (ip = idalp; ip < idalp+33; ip++) {
+		if (*ip == 0)
+			break;
+		kfree(phys_to_virt(*ip));
+	}
+	idal_free(idalp);
 	return len;
 }
 
@@ -428,34 +462,64 @@
 	int rc;
 	long flags;
 	void *kb;
+	addr_t *idalp, *ip;
+	int count, piece;
+	int index;
+	int size;
+
+	if (len > 65535 || len == 0)
+		return -EINVAL;
 
 	/* Locate the tube */
 	if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
 		return -ENODEV;
 
-	/* Copy data to write from user address space */
-	if ((kb = kmalloc(len, GFP_KERNEL|GFP_DMA)) == NULL)
-		return -ENOMEM;
-	if (copy_from_user(kb, dp, len) != 0) {
-		kfree(kb);
+	if ((ip = idalp = idal_alloc(33)) == NULL)
 		return -EFAULT;
+	memset(idalp, 0, 33 * sizeof *idalp);
+
+	count = len;
+	index = 0;
+	while (count) {
+		piece = MIN(count, 0x800);
+		size = count == len? piece: 0x800;
+		if ((kb = kmalloc(size, GFP_KERNEL|GFP_DMA)) == NULL) {
+			len = -ENOMEM;
+			goto do_cleanup;
+		}
+		*ip++ = virt_to_phys(kb);
+		if (copy_from_user(kb, &dp[index], piece) != 0) {
+			len = -EFAULT;
+			goto do_cleanup;
+		}
+		count -= piece;
+		index += piece;
 	}
 
 	/* Wait till tube's not working or signal is pending */
 	if ((rc = fs3270_wait(tubp, &flags))) {
+		len = rc;
 		TUBUNLOCK(tubp->irq, flags);
-		kfree(kb);
-		return rc;
+		goto do_cleanup;
 	}
 
-	/* Make CCW and start I/O.  Back end will free buffer. */
-	tubp->wbuf = kb;
+	/* Make CCW and start I/O.  Back end will free buffers & idal. */
+	tubp->wbuf = idalp;
 	cp = &tubp->wccw;
 	cp->cmd_code = tubp->ocmd? tubp->ocmd == 5? 13: tubp->ocmd: 1;
-	cp->flags = CCW_FLAG_SLI;
+	cp->flags = CCW_FLAG_SLI | CCW_FLAG_IDA;
 	cp->count = len;
 	cp->cda = virt_to_phys(tubp->wbuf);
 	fs3270_io(tubp, cp);
 	TUBUNLOCK(tubp->irq, flags);
 	return len;
+
+do_cleanup:
+	for (ip = idalp; ip < idalp+33; ip++) {
+		if (*ip == 0)
+			break;
+		kfree(phys_to_virt(*ip));
+	}
+	idal_free(idalp);
+	return len;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/s390/char/tubio.h linux-2.4.20/drivers/s390/char/tubio.h
--- linux-2.4.19/drivers/s390/char/tubio.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/s390/char/tubio.h	2002-10-29 11:18:30.000000000 +0000
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include <asm/irq.h>
 #include <asm/io.h>
+#include <asm/idals.h>
 #include <linux/console.h>
 #include <linux/interrupt.h>
 #include <asm/ebcdic.h>
@@ -80,10 +81,17 @@
 #define TAT_CHARS 0x43
 #define TAT_TRANS 0x46
 
+/* Extended-Highlighting Bytes */
+#define TAX_RESET 0x00
+#define TAX_BLINK 0xf1
+#define TAX_REVER 0xf2
+#define TAX_UNDER 0xf4
+
 /* Reset value */
 #define TAR_RESET 0x00
 
 /* Color values */
+#define TAC_RESET 0x00
 #define TAC_BLUE 0xf1
 #define TAC_RED 0xf2
 #define TAC_PINK 0xf3
@@ -219,7 +227,7 @@
 	devstat_t       devstat;
 	ccw1_t          rccw;
 	ccw1_t          wccw;
-	void            *wbuf;
+	addr_t		*wbuf;
 	int             cswl;
 	void            (*intv)(struct tub_s *, devstat_t *);
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
@@ -241,12 +249,13 @@
 
 	/* Stuff for tty-driver support */
 	struct tty_struct *tty;
-	char tty_input[GEOM_MAXINPLEN]; /* tty input area */
+	char *tty_input;		/* tty input area */
 	int tty_inattr;         	/* input-area field attribute */
 #define TTY_OUTPUT_SIZE 1024
 	bcb_t tty_bcb;			/* Output buffer control info */
 	int tty_oucol;                  /* Kludge */
 	int tty_nextlogx;               /* next screen-log position */
+	int tty_savecursor;		/* saved cursor position */
 	int tty_scrolltime;             /* scrollforward wait time, sec */
 	struct timer_list tty_stimer;   /* timer for scrolltime */
 	aid_t tty_aid[64];              /* Aid descriptors */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/s390/char/tubtty.c linux-2.4.20/drivers/s390/char/tubtty.c
--- linux-2.4.19/drivers/s390/char/tubtty.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/s390/char/tubtty.c	2002-10-29 11:18:49.000000000 +0000
@@ -214,8 +214,10 @@
 	tubp->tty = tty;
 	tubp->lnopen = 1;
 	tty->driver_data = tubp;
-	tty->winsize.ws_row = tubp->geom_rows;
+	tty->winsize.ws_row = tubp->geom_rows - 2;
 	tty->winsize.ws_col = tubp->geom_cols;
+	if (tubp->tty_input == NULL)
+		tubp->tty_input = kmalloc(GEOM_INPLEN, GFP_KERNEL|GFP_DMA);
 	tubp->tty_inattr = TF_INPUT;
 	tubp->cmd = cmd;
 	tty3270_build(tubp);
@@ -471,11 +473,11 @@
 			tubp = (*tubminors)[i];
 #ifdef CONFIG_TN3270_CONSOLE
 			if (CONSOLE_IS_3270 && tubp == tub3270_con_tubp)
-				len += sprintf(buf + len, "%.3x CONSOLE %d\n",
+				len += sprintf(buf + len, "%.4x CONSOLE %d\n",
 					       tubp->devno, i);
 			else
 #endif
-				len += sprintf(buf + len, "%.3x %d %d\n",
+				len += sprintf(buf + len, "%.4x %d %d\n",
 					       tubp->devno, tty3270_major, i);
 			if (begin + len > off + count)
 				break;
@@ -799,7 +801,9 @@
 static void
 tty3270_start_input(tub_t *tubp)
 {
-	tubp->ttyccw.cda = virt_to_phys(&tubp->tty_input);
+	if (tubp->tty_input == NULL)
+		return;
+	tubp->ttyccw.cda = virt_to_phys(tubp->tty_input);
 	tubp->ttyccw.cmd_code = TC_READMOD;
 	tubp->ttyccw.count = GEOM_INPLEN;
 	tubp->ttyccw.flags = CCW_FLAG_SLI;
@@ -816,7 +820,8 @@
 	char *aidstring;
 
 	count = GEOM_INPLEN - tubp->cswl;
-	in = tubp->tty_input;
+	if ((in = tubp->tty_input) == NULL)
+		goto do_build;
 	tty3270_aid_get(tubp, in[0], &aidflags, &aidstring);
 
 	if (aidflags & TA_CLEARKEY) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/s390/char/tubttybld.c linux-2.4.20/drivers/s390/char/tubttybld.c
--- linux-2.4.19/drivers/s390/char/tubttybld.c	2001-09-07 16:28:38.000000000 +0000
+++ linux-2.4.20/drivers/s390/char/tubttybld.c	2002-10-29 11:18:37.000000000 +0000
@@ -15,10 +15,12 @@
 extern int tty3270_io(tub_t *);
 static void tty3270_set_status_area(tub_t *, char **);
 static int tty3270_next_char(tub_t *);
+static void tty3270_unnext_char(tub_t *, char);
 static void tty3270_update_log_area(tub_t *, char **);
-static void tty3270_update_log_area_esc(tub_t *, char **);
+static int tty3270_update_log_area_esc(tub_t *, char **, int *);
 static void tty3270_clear_log_area(tub_t *, char **);
 static void tty3270_tub_bufadr(tub_t *, int, char **);
+static void tty3270_set_bufadr(tub_t *, char **, int *);
 
 /*
  * tty3270_clear_log_area(tub_t *tubp, char **cpp)
@@ -47,69 +49,74 @@
 	int sba_needed = 1;
 	char *overrun = &(*tubp->ttyscreen)[tubp->ttyscreenl - TS_LENGTH];
 
-	/* Place characters */
-	while (tubp->tty_bcb.bc_cnt != 0) {
-		if (tubp->tty_nextlogx >= lastx) {
-			if (sba_needed == 0 || tubp->stat == TBS_RUNNING) {
-				tubp->stat = TBS_MORE;
-				tty3270_set_status_area(tubp, cpp);
-				tty3270_scl_settimer(tubp);
-			}
-			break;
+	/* Check for possible ESC sequence work to do */
+	if (tubp->tty_escx != 0) {
+		/* If compiling new escape sequence */
+		if (tubp->tty_esca[0] == 0x1b) {
+			if (tty3270_update_log_area_esc(tubp, cpp, &sba_needed))
+				return;
+		/* If esc seq needs refreshing after a write */
+		} else if (tubp->tty_esca[0] == TO_SA) {
+			tty3270_set_bufadr(tubp, cpp, &sba_needed);
+			for (i = 0; i < tubp->tty_escx; i++)
+				*(*cpp)++ = tubp->tty_esca[i];
+		} else {
+			printk(KERN_WARNING "tty3270_update_log_area esca "
+			"character surprising:  %.2x\n", tubp->tty_esca[0]);
 		}
+	}
 
-		/* Check for room for another char + possible ESCs */
-		if (&(*cpp)[tubp->tty_escx + 1] >= overrun)
+	/* Place characters */
+	while (tubp->tty_bcb.bc_cnt != 0) {
+		/* Check for room.  TAB could take up to 4 chars. */
+		if (&(*cpp)[4] >= overrun)
 			break;
 
 		/* Fetch a character */
 		if ((c = tty3270_next_char(tubp)) == -1)
 			break;
 
-		/* Add a Set-Buffer-Address Order if we haven't */
-		if (sba_needed) {
-			sba_needed = 0;
-			*(*cpp)++ = TO_SBA;
-			TUB_BUFADR(tubp->tty_nextlogx, cpp);
-		}
-
 		switch(c) {
 		default:
-			if (c < ' ')    /* Blank it if we don't know it */
-				c = ' ';
-			for (i = 0; i < tubp->tty_escx; i++)
-				*(*cpp)++ = tubp->tty_esca[i];
-			tubp->tty_escx = 0;
-			*(*cpp)++ = tub_ascebc[(int)c];
+			if (tubp->tty_nextlogx >= lastx) {
+				if (sba_needed == 0 ||
+				    tubp->stat == TBS_RUNNING) {
+					tty3270_unnext_char(tubp, c);
+					tubp->stat = TBS_MORE;
+					tty3270_set_status_area(tubp, cpp);
+					tty3270_scl_settimer(tubp);
+				}
+				goto do_return;
+			}
+			tty3270_set_bufadr(tubp, cpp, &sba_needed);
+			/* Use blank if we don't know the character */
+			*(*cpp)++ = tub_ascebc[(int)(c < ' '? ' ': c)];
 			tubp->tty_nextlogx++;
 			tubp->tty_oucol++;
 			break;
 		case 0x1b:              /* ESC */
-			tty3270_update_log_area_esc(tubp, cpp);
+			tubp->tty_escx = 0;
+			if (tty3270_update_log_area_esc(tubp, cpp, &sba_needed))
+				return;
+			break;
+		case '\r':		/* 0x0d -- Carriage Return */
+			tubp->tty_nextlogx -=
+				tubp->tty_nextlogx % GEOM_COLS;
+			sba_needed = 1;
 			break;
-		case '\r':
-			break;          /* completely ignore 0x0d = CR. */
-		case '\n':
+		case '\n':		/* 0x0a -- New Line */
 			if (tubp->tty_oucol == GEOM_COLS) {
 				tubp->tty_oucol = 0;
 				break;
 			}
 			next = (tubp->tty_nextlogx + GEOM_COLS) /
 				GEOM_COLS * GEOM_COLS;
-			next = MIN(next, lastx);
-			fill = next - tubp->tty_nextlogx;
-			if (fill < 5) {
-				for (i = 0; i < fill; i++)
-					*(*cpp)++ = tub_ascebc[' '];
-			} else {
-				*(*cpp)++ = TO_RA;
-				TUB_BUFADR(next, cpp);
-				*(*cpp)++ = tub_ascebc[' '];
-			}
 			tubp->tty_nextlogx = next;
 			tubp->tty_oucol = 0;
+			sba_needed = 1;
 			break;
-		case '\t':
+		case '\t':		/* 0x09 -- Tabulate */
+			tty3270_set_bufadr(tubp, cpp, &sba_needed);
 			fill = (tubp->tty_nextlogx % GEOM_COLS) % 8;
 			for (; fill < 8; fill++) {
 				if (tubp->tty_nextlogx >= lastx)
@@ -119,72 +126,116 @@
 				tubp->tty_oucol++;
 			}
 			break;
-		case '\a':
+		case '\a':		/* 0x07 -- Alarm */
 			tubp->flags |= TUB_ALARM;
 			break;
-		case '\f':
+		case '\f':		/* 0x0c -- Form Feed */
 			tty3270_clear_log_area(tubp, cpp);
 			break;
+		case 0xf:	/* SuSE "exit alternate mode" */
+			break;
 		}
 	}
+do_return:
 }
 
 #define NUMQUANT 8
-static void
-tty3270_update_log_area_esc(tub_t *tubp, char **cpp)
+static int
+tty3270_update_log_area_esc(tub_t *tubp, char **cpp, int *sba_needed)
 {
-	int lastx = GEOM_INPUT;
 	int c;
-	int i;
-	int start, next, fill;
+	int i, j;
+	int start, end, next;
 	int quant[NUMQUANT];
+	char *overrun = &(*tubp->ttyscreen)[tubp->ttyscreenl - TS_LENGTH];
+	char sabuf[NUMQUANT*3], *sap = sabuf, *cp;
 
-	if ((c = tty3270_next_char(tubp)) != '[') {
-		return;
+	/* If starting a sequence, stuff ESC at [0] */
+	if (tubp->tty_escx == 0)
+		tubp->tty_esca[tubp->tty_escx++] = 0x1b;
+
+	/* Now that sequence is started, see if room in buffer */
+	if (&(*cpp)[NUMQUANT * 3] >= overrun)
+		return tubp->tty_escx;
+
+	/* Gather the rest of the sequence's characters */
+	while (tubp->tty_escx < sizeof tubp->tty_esca) {
+		if ((c = tty3270_next_char(tubp)) == -1)
+			return tubp->tty_escx;
+		if (tubp->tty_escx == 1) {
+			switch(c) {
+			case '[':
+				tubp->tty_esca[tubp->tty_escx++] = c;
+				continue;
+			case '7':
+				tubp->tty_savecursor = tubp->tty_nextlogx;
+				goto done_return;
+			case '8':
+				next = tubp->tty_savecursor;
+				goto do_setcur;
+			default:
+				goto error_return;
+			}
+		}
+		tubp->tty_esca[tubp->tty_escx++] = c;
+		if (c != ';' && (c < '0' || c > '9'))
+			break;
 	}
 
-	/*
-	 * Parse potentially empty string "nn;nn;nn..."
-	 */
+	/* Check for overrun */
+	if (tubp->tty_escx == sizeof tubp->tty_esca)
+		goto error_return;
+
+	/* Parse potentially empty string "nn;nn;nn..." */
 	i = -1;
+	j = 2;		/* skip ESC, [ */
 	c = ';';
 	do {
 		if (c == ';') {
 			if (++i == NUMQUANT)
-				break;
+				goto error_return;
 			quant[i] = 0;
 		} else if (c < '0' || c > '9') {
 			break;
 		} else {
 			quant[i] = quant[i] * 10 + c - '0';
 		}
-	} while ((c = tty3270_next_char(tubp)) != -1);
-	if (c == -1) {
-		return;
-	}
-	if (i >= NUMQUANT) {
-		return;
-	}
+		c = tubp->tty_esca[j];
+	} while (j++ < tubp->tty_escx);
+
+	/* Add 3270 data stream output to execute the sequence */
 	switch(c) {
-	case -1:
-		return;
 	case 'm':		/* Set Attribute */
 		for (next = 0; next <= i; next++) {
 			int type = -1, value = 0;
 
-			if (tubp->tty_escx + 3 > MAX_TTY_ESCA)
-				break;
 			switch(quant[next]) {
 			case 0:		/* Reset */
-				tubp->tty_esca[tubp->tty_escx++] = TO_SA;
-				tubp->tty_esca[tubp->tty_escx++] = TAT_RESET;
-				tubp->tty_esca[tubp->tty_escx++] = TAR_RESET;
+				next = tubp->tty_nextlogx;
+				tty3270_set_bufadr(tubp, cpp, sba_needed);
+				*(*cpp)++ = TO_SA;
+				*(*cpp)++ = TAT_EXTHI;
+				*(*cpp)++ = TAX_RESET;
+				*(*cpp)++ = TO_SA;
+				*(*cpp)++ = TAT_COLOR;
+				*(*cpp)++ = TAC_RESET;
+				tubp->tty_nextlogx = next;
+				*sba_needed = 1;
+				sap = sabuf;
 				break;
 			case 1:		/* Bright */
+				break;
 			case 2:		/* Dim */
+				break;
 			case 4:		/* Underscore */
+				type = TAT_EXTHI; value = TAX_UNDER;
+				break;
 			case 5:		/* Blink */
+				type = TAT_EXTHI; value = TAX_BLINK;
+				break;
 			case 7:		/* Reverse */
+				type = TAT_EXTHI; value = TAX_REVER;
+				break;
 			case 8:		/* Hidden */
 				break;		/* For now ... */
 			/* Foreground Colors */
@@ -230,53 +281,110 @@
 				break;
 			}
 			if (type != -1) {
-				tubp->tty_esca[tubp->tty_escx++] = TO_SA;
-				tubp->tty_esca[tubp->tty_escx++] = type;
-				tubp->tty_esca[tubp->tty_escx++] = value;
+				tty3270_set_bufadr(tubp, cpp, sba_needed);
+				*(*cpp)++ = TO_SA;
+				*(*cpp)++ = type;
+				*(*cpp)++ = value;
+				*sap++ = TO_SA;
+				*sap++ = type;
+				*sap++ = value;
 			}
 		}
 		break;
+
 	case 'H':		/* Cursor Home */
 	case 'f':		/* Force Cursor Position */
-		return;
+		if (quant[0]) quant[0]--;
+		if (quant[1]) quant[1]--;
+		next = quant[0] * GEOM_COLS + quant[1];
+		goto do_setcur;
 	case 'A':		/* Cursor Up */
-		return;
+		if (quant[i] == 0) quant[i] = 1;
+		next = tubp->tty_nextlogx - GEOM_COLS * quant[i];
+		goto do_setcur;
 	case 'B':		/* Cursor Down */
-		return;
+		if (quant[i] == 0) quant[i] = 1;
+		next = tubp->tty_nextlogx + GEOM_COLS * quant[i];
+		goto do_setcur;
 	case 'C':		/* Cursor Forward */
+		if (quant[i] == 0) quant[i] = 1;
 		next = tubp->tty_nextlogx % GEOM_COLS;
 		start = tubp->tty_nextlogx - next;
 		next = start + MIN(next + quant[i], GEOM_COLS - 1);
-		next = MIN(next, lastx);
-do_fill:
-		fill = next - tubp->tty_nextlogx;
-		if (fill < 5) {
-			for (i = 0; i < fill; i++)
-				*(*cpp)++ = tub_ascebc[' '];
-		} else {
-			*(*cpp)++ = TO_RA;
-			TUB_BUFADR(next, cpp);
-			*(*cpp)++ = tub_ascebc[' '];
-		}
-		tubp->tty_nextlogx = next;
-		tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
-		break;
+		goto do_setcur;
 	case 'D':		/* Cursor Backward */
+		if (quant[i] == 0) quant[i] = 1;
 		next = MIN(quant[i], tubp->tty_nextlogx % GEOM_COLS);
-		tubp->tty_nextlogx -= next;
+		next = tubp->tty_nextlogx - next;
+		goto do_setcur;
+	case 'G':
+		if (quant[0]) quant[0]--;
+		next = tubp->tty_nextlogx / GEOM_COLS * GEOM_COLS + quant[0];
+do_setcur:
+		if (next < 0)
+			break;
+		tubp->tty_nextlogx = next;
 		tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
+		*sba_needed = 1;
+		break;
+
+	case 'r':		/* Define scroll area */
+		start = quant[0];
+		if (start <= 0) start = 1;
+		if (start > GEOM_ROWS - 2) start = GEOM_ROWS - 2;
+		tubp->tty_nextlogx = (start - 1) * GEOM_COLS;
+		tubp->tty_oucol = 0;
+		*sba_needed = 1;
+		break;
+
+	case 'X':		/* Erase for n chars from cursor */
+		start = tubp->tty_nextlogx;
+		end = start + (quant[0]?: 1);
+		goto do_fill;
+	case 'J':		/* Erase to screen end from cursor */
+		*(*cpp)++ = TO_SBA;
+		TUB_BUFADR(tubp->tty_nextlogx, cpp);
+		*(*cpp)++ = TO_RA;
+		TUB_BUFADR(GEOM_INPUT, cpp);
+		*(*cpp)++ = tub_ascebc[' '];
 		*(*cpp)++ = TO_SBA;
 		TUB_BUFADR(tubp->tty_nextlogx, cpp);
 		break;
-	case 'G':
-		start = tubp->tty_nextlogx / GEOM_COLS * GEOM_COLS;
-		next = MIN(quant[i], GEOM_COLS - 1) + start;
-		next = MIN(next, lastx);
-		goto do_fill;
+	case 'K':
+		start = tubp->tty_nextlogx;
+		end = (start + GEOM_COLS) / GEOM_COLS * GEOM_COLS;
+do_fill:
+		if (start >= GEOM_INPUT)
+			break;
+		if (end > GEOM_INPUT)
+			end = GEOM_INPUT;
+		if (end <= start)
+			break;
+		*(*cpp)++ = TO_SBA;
+		TUB_BUFADR(start, cpp);
+		if (end - start > 4) {
+			*(*cpp)++ = TO_RA;
+			TUB_BUFADR(end, cpp);
+			*(*cpp)++ = tub_ascebc[' '];
+		} else while (start++ < end) {
+			*(*cpp)++ = tub_ascebc[' '];
+		}
+		tubp->tty_nextlogx = end;
+		tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
+		*sba_needed = 1;
+		break;
 	}
+done_return:
+	tubp->tty_escx = 0;
+	cp = sabuf;
+	while (cp != sap)
+		tubp->tty_esca[tubp->tty_escx++] = *cp++;
+	return 0;
+error_return:
+	tubp->tty_escx = 0;
+	return 0;
 }
 
-
 static int
 tty3270_next_char(tub_t *tubp)
 {
@@ -293,6 +401,18 @@
 	return c;
 }
 
+static void
+tty3270_unnext_char(tub_t *tubp, char c)
+{
+	bcb_t *ib;
+
+	ib = &tubp->tty_bcb;
+	if (ib->bc_rd == 0)
+		ib->bc_rd = ib->bc_len;
+	ib->bc_buf[--ib->bc_rd] = c;
+	ib->bc_cnt++;
+}
+
 
 static void
 tty3270_clear_input_area(tub_t *tubp, char **cpp)
@@ -452,3 +572,17 @@
 		*(*cpp)++ = tub_ebcgraf[adr & 0x3f];
 	}
 }
+
+static void
+tty3270_set_bufadr(tub_t *tubp, char **cpp, int *sba_needed)
+{
+	if (!*sba_needed)
+		return;
+	if (tubp->tty_nextlogx >= GEOM_INPUT) {
+		tubp->tty_nextlogx = GEOM_INPUT - 1;
+		tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
+	}
+	*(*cpp)++ = TO_SBA;
+	TUB_BUFADR(tubp->tty_nextlogx, cpp);
+	*sba_needed = 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/s390/misc/chandev.c linux-2.4.20/drivers/s390/misc/chandev.c
--- linux-2.4.19/drivers/s390/misc/chandev.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/s390/misc/chandev.c	2002-10-29 11:18:38.000000000 +0000
@@ -2013,7 +2013,7 @@
 		/* This is required because the device can go & come back */
                 /* even before we realize it is gone owing to the waits in our kernel threads */
 		/* & the device will be marked as not owned but its status will be good */
-                /* & an attempt to accidentally reprobe it may be done. */ 
+                /* & an attempt to accidently reprobe it may be done. */ 
 		remove:
 		chandev_remove(chandev_get_by_irq(curr_irqinfo->sch.irq));
 		
@@ -3140,6 +3140,9 @@
 	int         rc;
 	char        *buff;
 	
+	if(count > 65536)
+		count = 65536;
+		
 	buff=vmalloc(count+1);
 	if(buff)
 	{
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/s390/net/netiucv.c linux-2.4.20/drivers/s390/net/netiucv.c
--- linux-2.4.19/drivers/s390/net/netiucv.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/s390/net/netiucv.c	2002-10-29 11:18:48.000000000 +0000
@@ -1362,7 +1362,7 @@
 
 	privptr = (netiucv_priv *)dev->priv;
 
-	if (count >= 39)
+	if (count >= CTRL_BUFSIZE-1)
 		return -EINVAL;
 
 	if (copy_from_user(tmp, buf, count))
@@ -1459,7 +1459,7 @@
 
 	privptr = (netiucv_priv *)dev->priv;
 
-	if (count >= 39)
+	if (count >= CTRL_BUFSIZE-1)
 		return -EINVAL;
 
 	if (copy_from_user(tmp, buf, count))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/s390/s390io.c linux-2.4.20/drivers/s390/s390io.c
--- linux-2.4.19/drivers/s390/s390io.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/s390/s390io.c	2002-10-29 11:18:34.000000000 +0000
@@ -1,6 +1,7 @@
 /*
  *  drivers/s390/s390io.c
  *   S/390 common I/O routines
+ *   $Revision: 1.171.2.21 $
  *
  *  S390 version
  *    Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
@@ -26,8 +27,22 @@
  *               08/02/2001 Cornelia Huck not already known devices can be blacklisted
  *                                        by piping to /proc/cio_ignore
  *               09/xx/2001 couple more fixes
+ *               10/15/2001 Cornelia Huck xsch - internal only for now
  *               10/29/2001 Cornelia Huck Blacklisting reworked again
  *               10/29/2001 Cornelia Huck improved utilization of debug feature
+ *               10/29/2001 Cornelia Huck more work on cancel_IO - use the flag
+ *                                        DOIO_CANCEL_ON_TIMEOUT in do_IO to get
+ *                                        io cancelled
+ *               11/15/2001 Cornelia Huck proper behaviour with procfs off
+ *               12/10/2001 Cornelia Huck added private_data + functions to 
+ *                                        ioinfo_t
+ *               11-12/2001 Cornelia Huck various cleanups
+ *               01/09/2002 Cornelia Huck PGID fixes
+ *                                        process css machine checks 
+ *               01/10/2002 Cornelia Huck added /proc/chpids
+ *               04/10/2002 Cornelia Huck fixed reaction on css machine checks
+ *               04/23/2002 Cornelia Huck fixed console isc (un)setting
+ *               06/06/2002 Cornelia Huck added detection of locked devices
  */
 
 #include <linux/module.h>
@@ -46,7 +61,7 @@
 #include <linux/bootmem.h>
 #ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
-#endif 
+#endif
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -57,7 +72,7 @@
 #include <asm/processor.h>
 #include <asm/lowcore.h>
 #include <asm/idals.h>
-#include <asm/uaccess.h> 
+#include <asm/uaccess.h>
 #include <asm/cpcmd.h>
 
 #include <asm/s390io.h>
@@ -76,96 +91,148 @@
 		return (-ENODEV); \
 	if (ioinfo[irq] == INVALID_STORAGE_AREA) \
 		return (-ENODEV); \
-	} while(0) 
+        if (ioinfo[irq]->st) \
+                return -ENODEV; \
+	} while(0)
+
+#define CIO_TRACE_EVENT(imp, txt) do { \
+	if (cio_debug_initialized) \
+		debug_text_event(cio_debug_trace_id, \
+				 imp, \
+				 txt); \
+        }while (0)
+
+#define CIO_MSG_EVENT(imp, args...) do { \
+        if (cio_debug_initialized) \
+                debug_sprintf_event(cio_debug_msg_id, \
+                                    imp, \
+                                    ##args); \
+        } while (0)
+
+#define CIO_CRW_EVENT(imp, args...) do { \
+        if (cio_debug_initialized) \
+                debug_sprintf_event(cio_debug_crw_id, \
+                                    imp, \
+                                    ##args); \
+        } while (0)
 
 #undef  CONFIG_DEBUG_IO
 #define CONFIG_DEBUG_CRW
+#define CONFIG_DEBUG_CHSC
 
-unsigned int           highest_subchannel;
-ioinfo_t              *ioinfo_head = NULL;
-ioinfo_t              *ioinfo_tail = NULL;
-ioinfo_t              *ioinfo[__MAX_SUBCHANNELS] = {
-	[0 ... (__MAX_SUBCHANNELS-1)] = INVALID_STORAGE_AREA
+unsigned int highest_subchannel;
+ioinfo_t *ioinfo_head = NULL;
+ioinfo_t *ioinfo_tail = NULL;
+ioinfo_t *ioinfo[__MAX_SUBCHANNELS] = {
+	[0 ... (__MAX_SUBCHANNELS - 1)] = INVALID_STORAGE_AREA
 };
 
-static atomic_t    sync_isc     = ATOMIC_INIT(-1);
-static int         sync_isc_cnt = 0;      // synchronous irq processing lock
-
-static spinlock_t  adapter_lock = SPIN_LOCK_UNLOCKED;
-                                          // adapter interrupt lock
-static int        cons_dev          = -1; // identify console device
-static int        init_IRQ_complete = 0;
-static int        cio_show_msg      = 0;
-static schib_t   *p_init_schib      = NULL;
-static irb_t     *p_init_irb        = NULL;
-static __u64      irq_IPL_TOD;
-static adapter_int_handler_t adapter_handler   = NULL;
+#ifdef CONFIG_CHSC
+__u64 chpids[4] = {0,0,0,0};
+__u64 chpids_logical[4] = {-1,-1,-1,-1};
+__u64 chpids_known[4] = {0,0,0,0};
+#endif /* CONFIG_CHSC */
+
+static atomic_t sync_isc = ATOMIC_INIT (-1);
+static int sync_isc_cnt = 0;	/* synchronous irq processing lock */
+
+static spinlock_t adapter_lock = SPIN_LOCK_UNLOCKED;	/* adapter interrupt lock */
+static int cons_dev = -1;	/* identify console device */
+static int init_IRQ_complete = 0;
+static int cio_show_msg = 0;
+static schib_t *p_init_schib = NULL;
+static irb_t *p_init_irb = NULL;
+static __u64 irq_IPL_TOD;
+static adapter_int_handler_t adapter_handler = NULL;
+static pgid_t * global_pgid;
 
 /* for use of debug feature */
-debug_info_t *cio_debug_msg_id = NULL;  
+debug_info_t *cio_debug_msg_id = NULL;
 debug_info_t *cio_debug_trace_id = NULL;
 debug_info_t *cio_debug_crw_id = NULL;
 int cio_debug_initialized = 0;
 
-static void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs);
-static void s390_process_subchannels( void);
-static void s390_device_recognition_all( void);
-static void s390_device_recognition_irq( int irq);
+#ifdef CONFIG_CHSC
+int cio_chsc_desc_avail = 0;
+int cio_chsc_err_msg = 0;
+#endif
+
+static void init_IRQ_handler (int irq, void *dev_id, struct pt_regs *regs);
+static void s390_process_subchannels (void);
+static void s390_device_recognition_all (void);
+static void s390_device_recognition_irq (int irq);
 #ifdef CONFIG_PROC_FS
-static void s390_redo_validation(void);
+static void s390_redo_validation (void);
 #endif
-static int  s390_validate_subchannel( int irq, int enable);
-static int  s390_SenseID( int irq, senseid_t *sid, __u8 lpm);
-static int  s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid);
-static int  s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid);
-static int  s390_process_IRQ( unsigned int irq );
-static int  enable_subchannel( unsigned int irq);
-static int  disable_subchannel( unsigned int irq);
+static int s390_validate_subchannel (int irq, int enable);
+static int s390_SenseID (int irq, senseid_t * sid, __u8 lpm);
+static int s390_SetPGID (int irq, __u8 lpm);
+static int s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid);
+static int s390_process_IRQ (unsigned int irq);
+static int enable_subchannel (unsigned int irq);
+static int disable_subchannel (unsigned int irq);
+int cancel_IO (int irq);
+int s390_start_IO (int irq, ccw1_t * cpa, unsigned long user_intparm,
+		   __u8 lpm, unsigned long flag);
+
+static int s390_send_nop(int irq, __u8 lpm);
 
 #ifdef CONFIG_PROC_FS
-static int chan_proc_init( void );
-#endif 
+static int chan_proc_init (void);
+#endif
 
-static inline void do_adapter_IO( __u32 intparm );
+static inline void do_adapter_IO (__u32 intparm);
 
-int  s390_DevicePathVerification( int irq, __u8 domask );
-int  s390_register_adapter_interrupt( adapter_int_handler_t handler );
-int  s390_unregister_adapter_interrupt( adapter_int_handler_t handler );
+int s390_DevicePathVerification (int irq, __u8 domask);
+int s390_register_adapter_interrupt (adapter_int_handler_t handler);
+int s390_unregister_adapter_interrupt (adapter_int_handler_t handler);
 
-extern int  do_none(unsigned int irq, int cpu, struct pt_regs * regs);
-extern int  enable_none(unsigned int irq);
-extern int  disable_none(unsigned int irq);
+extern int do_none (unsigned int irq, int cpu, struct pt_regs *regs);
+extern int enable_none (unsigned int irq);
+extern int disable_none (unsigned int irq);
 
-asmlinkage void do_IRQ( struct pt_regs regs );
+asmlinkage void do_IRQ (struct pt_regs regs);
+
+#ifdef CONFIG_CHSC
+static chsc_area_t *chsc_area_ssd = NULL;
+static chsc_area_t *chsc_area_sei = NULL;
+static spinlock_t chsc_lock_ssd = SPIN_LOCK_UNLOCKED;
+static spinlock_t chsc_lock_sei = SPIN_LOCK_UNLOCKED;
+static int chsc_get_sch_descriptions( void );
+int s390_vary_chpid( __u8 chpid, int on );
+#endif
 
 #ifdef CONFIG_PROC_FS
 #define MAX_CIO_PROCFS_ENTRIES 0x300
 /* magic number; we want to have some room to spare */
 
-int cio_procfs_device_create(int devno);
-int cio_procfs_device_remove(int devno);
-int cio_procfs_device_purge(void);
+int cio_procfs_device_create (int devno);
+int cio_procfs_device_remove (int devno);
+int cio_procfs_device_purge (void);
 #endif
 
 int cio_notoper_msg = 1;
+
 #ifdef CONFIG_PROC_FS
-int cio_proc_devinfo = 0; /* switch off the /proc/deviceinfo/ stuff by default
-			     until problems are dealt with */
+int cio_proc_devinfo = 0;	/* switch off the /proc/deviceinfo/ stuff by default
+				   until problems are dealt with */
 #endif
 
-unsigned long s390_irq_count[NR_CPUS]; /* trace how many irqs have occured per cpu... */
-int cio_count_irqs = 1;       /* toggle use here... */
+unsigned long s390_irq_count[NR_CPUS];	/* trace how many irqs have occured per cpu... */
+int cio_count_irqs = 1;		/* toggle use here... */
+
+int cio_sid_with_pgid = 0;     /* if we need a PGID for SenseID, switch this on */
 
 /* 
  * "Blacklisting" of certain devices:
  * Device numbers given in the commandline as cio_ignore=... won't be known to Linux
  * These can be single devices or ranges of devices
- *
+ * 
  * 10/23/01 reworked to get rid of lists
  */
 
-static unsigned long bl_dev[2048] = {0,};
-    
+static u32 bl_dev[2048];
+
 static spinlock_t blacklist_lock = SPIN_LOCK_UNLOCKED;
 static int highest_ignored = 0;
 static int nr_ignored = 0;
@@ -175,31 +242,36 @@
  * Blacklist the devices from-to
  */
 
-static inline void blacklist_range_add( int from, int to,int locked)
+static inline void
+blacklist_range_add (int from, int to, int locked)
 {
- 
-     unsigned long flags;
-     int i;
 
-     if (to && (from>to)) {
-	     printk(KERN_WARNING "Invalid blacklist range %x to %x, skipping\n", from, to);
-	     return;
-     }
-     if(!locked)
-	     spin_lock_irqsave( &blacklist_lock, flags );
+	unsigned long flags;
+	int i;
 
-     if (!to) 
-	     to = from;
-     for (i=from;i<=to;i++) {
-	     set_bit(i,&bl_dev);
-	     nr_ignored++;
-     }
+	if ((to && (from > to))
+	    || (to<0) || (to > 0xffff)
+	    || (from<0) || (from > 0xffff)) {
+		printk (KERN_WARNING
+			"Invalid blacklist range %x to %x, skipping\n", from,
+			to);
+		return;
+	}
+	if (!locked)
+		spin_lock_irqsave (&blacklist_lock, flags);
+
+	if (!to)
+		to = from;
+	for (i = from; i <= to; i++) {
+		set_bit (i, &bl_dev);
+		nr_ignored++;
+	}
 
-     if (to>=highest_ignored)
-	     highest_ignored = to;
+	if (to >= highest_ignored)
+		highest_ignored = to;
 
-     if(!locked)
-	     spin_unlock_irqrestore( &blacklist_lock, flags );
+	if (!locked)
+		spin_unlock_irqrestore (&blacklist_lock, flags);
 }
 
 /* 
@@ -207,22 +279,34 @@
  * Removes a range from the blacklist chain
  */
 
-static inline void blacklist_range_remove( int from, int to )
+static inline void
+blacklist_range_remove (int from, int to)
 {
-     long flags;
+	long flags;
 	int i;
 
-     spin_lock_irqsave( &blacklist_lock, flags );
-     
-	for (i=from;i<=to;i++) {
-		clear_bit(i,&bl_dev);
+	if ((to<0) || (to > 0xffff)
+	    || (from<0) || (from > 0xffff)) {
+		printk (KERN_WARNING
+			"Invalid blacklist range %x to %x, "
+			"not freeing\n",
+			from, to);
+		return;
+	}
+
+	spin_lock_irqsave (&blacklist_lock, flags);
+
+	for (i = from; i <= to; i++) {
+		clear_bit (i, &bl_dev);
 		nr_ignored--;
 	}
 
-	if (to == highest_ignored) 
-		for (highest_ignored=from;(highest_ignored>0) && (!test_bit(highest_ignored,&bl_dev));highest_ignored--);
+	if (to == highest_ignored)
+		for (highest_ignored = from; (highest_ignored > 0)
+		     && (!test_bit (highest_ignored, &bl_dev));
+		     highest_ignored--) ;
 
-     spin_unlock_irqrestore( &blacklist_lock, flags );
+	spin_unlock_irqrestore (&blacklist_lock, flags);
 }
 
 /* Parsing the commandline for blacklist parameters */
@@ -231,13 +315,14 @@
  * Variable to hold the blacklisted devices given by the parameter line
  * cio_ignore=...
  */
-char *blacklist[256] = {NULL, };
+char *blacklist[256] = { NULL, };
 
 /*
  * Get the cio_ignore=... items from the parameter line
  */
 
-static void blacklist_split_parm_string (char *str)
+static void
+blacklist_split_parm_string (char *str)
 {
 	char *tmp = str;
 	int count = 0;
@@ -252,9 +337,11 @@
 			*end = '\0';
 			end++;
 		}
-		blacklist[count] = alloc_bootmem (len * sizeof (char) );
+		blacklist[count] = alloc_bootmem (len * sizeof (char));
 		if (blacklist == NULL) {
-			printk (KERN_WARNING "can't store cio_ignore= parameter no %d\n", count + 1);
+			printk (KERN_WARNING
+				"can't store cio_ignore= parameter no %d\n",
+				count + 1);
 			break;
 		}
 		memset (blacklist[count], 0, len * sizeof (char));
@@ -268,21 +355,21 @@
  * The blacklist parameters as one concatenated string
  */
 
-static char blacklist_parm_string[1024] __initdata = {0,};
-
+static char blacklist_parm_string[1024] __initdata = { 0, };
 
 /* 
  * function: blacklist_strtoul
  * Strip leading '0x' and interpret the values as Hex
  */
-static inline int blacklist_strtoul (char *str, char **stra)
+static inline int
+blacklist_strtoul (char *str, char **stra)
 {
 	char *temp = str;
 	int val;
 	if (*temp == '0') {
-		temp++;		                /* strip leading zero */
+		temp++;		/* strip leading zero */
 		if (*temp == 'x')
-			temp++;	                /* strip leading x */
+			temp++;	/* strip leading x */
 	}
 	val = simple_strtoul (temp, &temp, 16);	/* interpret anything as hex */
 	*stra = temp;
@@ -295,52 +382,53 @@
  * Add the blacklisted devices to the blacklist chain
  */
 
-static inline void blacklist_parse( char **str )
+static inline void
+blacklist_parse (char **str)
 {
-     char *temp;
-     int from, to;
+	char *temp;
+	int from, to;
 
-     while (*str) {
-	  temp = *str;
-	  from = 0;
-	  to = 0;
-	  
-	  from = blacklist_strtoul( temp, &temp );
-	  if (*temp == '-') {
-	       temp++;
-	       to = blacklist_strtoul( temp, &temp );
-	  }
-	  blacklist_range_add( from, to, 0 );
+	while (*str) {
+		temp = *str;
+		from = 0;
+		to = 0;
+
+		from = blacklist_strtoul (temp, &temp);
+		if (*temp == '-') {
+			temp++;
+			to = blacklist_strtoul (temp, &temp);
+		}
+		blacklist_range_add (from, to, 0);
 #ifdef CONFIG_DEBUG_IO
-	  printk( KERN_INFO "Blacklisted range from %X to %X\n", from, to );
+		printk (KERN_INFO "Blacklisted range from %X to %X\n", from,
+			to);
 #endif
-	  str++;
-     }
+		str++;
+	}
 }
 
-
 /*
  * Initialisation of blacklist 
  */
 
-void __init blacklist_init( void )
+void __init
+blacklist_init (void)
 {
-#ifdef CONFIG_DEBUG_IO     
-     printk( KERN_DEBUG "Reading blacklist...\n");
+#ifdef CONFIG_DEBUG_IO
+	printk (KERN_DEBUG "Reading blacklist...\n");
 #endif
-     if (cio_debug_initialized)
-	     debug_sprintf_event(cio_debug_msg_id, 6,
-				 "Reading blacklist\n");
-     blacklist_split_parm_string( blacklist_parm_string );
-     blacklist_parse( blacklist );
-}
+	CIO_MSG_EVENT(6, "Reading blacklist\n");
 
+	blacklist_split_parm_string (blacklist_parm_string);
+	blacklist_parse (blacklist);
+}
 
 /*
  * Get all the blacklist parameters from parameter line
  */
 
-void __init blacklist_setup (char *str, int *ints)
+void __init
+blacklist_setup (char *str, int *ints)
 {
 	int len = strlen (blacklist_parm_string);
 	if (len != 0) {
@@ -349,19 +437,20 @@
 	strcat (blacklist_parm_string, str);
 }
 
-int __init blacklist_call_setup (char *str)
+int __init
+blacklist_call_setup (char *str)
 {
-        int dummy;
+	int dummy;
 #ifdef CONFIG_DEBUG_IO
-	printk( KERN_DEBUG "Reading blacklist parameters...\n" );
+	printk (KERN_DEBUG "Reading blacklist parameters...\n");
 #endif
-	if (cio_debug_initialized)
-		debug_sprintf_event(cio_debug_msg_id, 6,
-				    "Reading blacklist parameters\n");
-        blacklist_setup(str,&dummy);
-	
-	blacklist_init(); /* Blacklist ranges must be ready when device recognition starts */
-       
+	CIO_MSG_EVENT(6, "Reading blacklist parameters\n");
+
+	blacklist_setup (str, &dummy);
+
+	/* Blacklist ranges must be ready when device recognition starts */
+	blacklist_init ();
+
 	return 1;
 }
 
@@ -374,18 +463,19 @@
  * Returns 1 if the given devicenumber can be found in the blacklist, otherwise 0.
  */
 
-static inline int is_blacklisted( int devno )
+static inline int
+is_blacklisted (int devno)
 {
-     long flags;
-     int retval=0;
+	long flags;
+	int retval = 0;
 
-     spin_lock_irqsave( &blacklist_lock, flags ); 
+	spin_lock_irqsave (&blacklist_lock, flags);
 
-     if (test_bit(devno,&bl_dev)) 
-		     retval=1;
+	if (test_bit (devno, &bl_dev))
+		retval = 1;
 
-     spin_unlock_irqrestore( &blacklist_lock, flags );
-     return retval;
+	spin_unlock_irqrestore (&blacklist_lock, flags);
+	return retval;
 }
 
 /*
@@ -393,19 +483,20 @@
  * set all blacklisted devices free...
  */
 
-void blacklist_free_all_ranges(void) 
+void
+blacklist_free_all_ranges (void)
 {
 	unsigned long flags;
 	int i;
 
-	spin_lock_irqsave( &blacklist_lock, flags ); 
+	spin_lock_irqsave (&blacklist_lock, flags);
 
-	for (i=0;i<=highest_ignored;i++)
-		clear_bit(i,&bl_dev);
+	for (i = 0; i <= highest_ignored; i++)
+		clear_bit (i, &bl_dev);
 	highest_ignored = 0;
 	nr_ignored = 0;
 
-	spin_unlock_irqrestore( &blacklist_lock, flags );
+	spin_unlock_irqrestore (&blacklist_lock, flags);
 }
 
 #ifdef CONFIG_PROC_FS
@@ -413,7 +504,8 @@
  * Function: blacklist_parse_proc_parameters
  * parse the stuff which is piped to /proc/cio_ignore
  */
-void blacklist_parse_proc_parameters(char *buf)
+void
+blacklist_parse_proc_parameters (char *buf)
 {
 	char *tmp;
 	int i;
@@ -426,194 +518,227 @@
 	int err = 0;
 
 	tmp = buf;
-	if (strstr(tmp, "free ")) {
-		for (i=0; i<5; i++) {
+	if (strstr (tmp, "free ")) {
+		for (i = 0; i < 5; i++) {
 			tmp++;
 		}
-		if (strstr(tmp, "all")) {
-			blacklist_free_all_ranges();
-			s390_redo_validation();
+		if (strstr (tmp, "all")) {
+			blacklist_free_all_ranges ();
+			s390_redo_validation ();
 		} else {
 			while (tmp != NULL) {
-				end = strchr(tmp, ',');
+				end = strchr (tmp, ',');
 				if (end == NULL) {
-					len = strlen(tmp) + 1;
+					len = strlen (tmp) + 1;
 				} else {
-					len = (long)end - (long) tmp + 1;
+					len = (long) end - (long) tmp + 1;
 					*end = '\0';
 					end++;
 				}
-				param =  (char*) kmalloc(len * sizeof(char) + 1, GFP_KERNEL);
-				strncpy(param, (const char *) tmp, len);
+				param =
+				    (char *) kmalloc (len * sizeof (char) + 1,
+						      GFP_KERNEL);
+				strncpy (param, (const char *) tmp, len);
 				tmp = end;
-				from = blacklist_strtoul(param, &param);
+				from = blacklist_strtoul (param, &param);
 				if (*param == '-') {
 					param++;
-					to = blacklist_strtoul(param, &param);
+					to = blacklist_strtoul (param, &param);
 				} else {
 					to = from;
 				}
-				blacklist_range_remove( from, to );
-				kfree(param);
+				blacklist_range_remove (from, to);
+				kfree (param);
 			}
-				s390_redo_validation();
+			s390_redo_validation ();
 		}
-	} else if (strstr(tmp, "add ")) {
-		for (i=0;i<4;i++){
+	} else if (strstr (tmp, "add ")) {
+		for (i = 0; i < 4; i++) {
 			tmp++;
 		}
 		while (tmp != NULL) {
-			end = strchr(tmp, ',');
+			end = strchr (tmp, ',');
 			if (end == NULL) {
-				len = strlen(tmp) + 1;
+				len = strlen (tmp) + 1;
 			} else {
-				len = (long)end - (long) tmp + 1;
+				len = (long) end - (long) tmp + 1;
 				*end = '\0';
 				end++;
 			}
-			param =  (char*) kmalloc(len * sizeof(char) + 1, GFP_KERNEL);
-			strncpy(param, (const char *) tmp, len);
+			param =
+			    (char *) kmalloc (len * sizeof (char) + 1,
+					      GFP_KERNEL);
+			strncpy (param, (const char *) tmp, len);
 			tmp = end;
-			from = blacklist_strtoul(param, &param);
+			from = blacklist_strtoul (param, &param);
 			if (*param == '-') {
 				param++;
-				to = blacklist_strtoul(param, &param);
+				to = blacklist_strtoul (param, &param);
 			} else {
 				to = from;
 			}
-			spin_lock_irqsave( &blacklist_lock, flags ); 
-			
+			spin_lock_irqsave (&blacklist_lock, flags);
+
 			/*
 			 * Don't allow for already known devices to be
 			 * blacklisted
 			 * The criterion is a bit dumb, devices which once were
 			 * there but are already gone are also caught...
 			 */
-			
+
 			err = 0;
-			for (i=0; i<=highest_subchannel; i++) {
-				if (ioinfo[i]!=INVALID_STORAGE_AREA) {
-					if (   (ioinfo[i]->schib.pmcw.dev >= from)
-					    && (ioinfo[i]->schib.pmcw.dev <= to)  ) {
-						printk(KERN_WARNING "cio_ignore: Won't blacklist "
-						       "already known devices, skipping range "
-						       "%x to %x\n", from, to);
-						err = 1;
-						break;
-					}
+			for (i = 0; i <= highest_subchannel; i++) {
+				if (ioinfo[i] != INVALID_STORAGE_AREA) {
+					if (!ioinfo[i]->st) 
+						if ((ioinfo[i]->schib.pmcw.dev >= from)
+						    && (ioinfo[i]->schib.pmcw.dev <=
+							to)) {
+							printk (KERN_WARNING
+								"cio_ignore: Won't blacklist "
+								"already known devices, "
+								"skipping range %x to %x\n",
+								from, to);
+							err = 1;
+							break;
+						}
 				}
 			}
 
-			if (!err) 
-				blacklist_range_add(from, to, 1);
-			
-			spin_unlock_irqrestore( &blacklist_lock, flags );
-			kfree(param);
+			if (!err)
+				blacklist_range_add (from, to, 1);
+
+			spin_unlock_irqrestore (&blacklist_lock, flags);
+			kfree (param);
 		}
 
 	} else {
-		printk( KERN_WARNING "cio_ignore: Parse error; try using 'free all|<devno-range>,<devno-range>,...'\n");
-		printk( KERN_WARNING "or 'add <devno-range>,<devno-range>,...'\n");
+		printk (KERN_WARNING
+			"cio_ignore: Parse error; "
+			"try using 'free all|<devno-range>,<devno-range>,...'\n");
+		printk (KERN_WARNING
+			"or 'add <devno-range>,<devno-range>,...'\n");
 	}
 }
 #endif
 /* End of blacklist handling */
 
+void s390_displayhex (char *str, void *ptr, s32 cnt);
+void s390_displayhex2 (char *str, void *ptr, s32 cnt, int level);
 
-void s390_displayhex(char *str,void *ptr,s32 cnt);
-void s390_displayhex2(char *str, void *ptr, s32 cnt, int level);
-
-void s390_displayhex(char *str,void *ptr,s32 cnt)
+void
+s390_displayhex (char *str, void *ptr, s32 cnt)
 {
-	s32	cnt1,cnt2,maxcnt2;
-	u32	*currptr=(__u32 *)ptr;
+	s32 cnt1, cnt2, maxcnt2;
+	u32 *currptr = (__u32 *) ptr;
 
-	printk("\n%s\n",str);
+	printk ("\n%s\n", str);
 
-	for(cnt1=0;cnt1<cnt;cnt1+=16)
-	{
-		printk("%08lX ",(unsigned long)currptr);
-		maxcnt2=cnt-cnt1;
-		if(maxcnt2>16)
-			maxcnt2=16;
-		for(cnt2=0;cnt2<maxcnt2;cnt2+=4)
-			printk("%08X ",*currptr++);
-		printk("\n");
+	for (cnt1 = 0; cnt1 < cnt; cnt1 += 16) {
+		printk ("%08lX ", (unsigned long) currptr);
+		maxcnt2 = cnt - cnt1;
+		if (maxcnt2 > 16)
+			maxcnt2 = 16;
+		for (cnt2 = 0; cnt2 < maxcnt2; cnt2 += 4)
+			printk ("%08X ", *currptr++);
+		printk ("\n");
 	}
 }
 
-void s390_displayhex2(char *str, void *ptr, s32 cnt, int level)
+void
+s390_displayhex2 (char *str, void *ptr, s32 cnt, int level)
 {
 	s32 cnt1, cnt2, maxcnt2;
-	u32 *currptr = (__u32 *)ptr;
-	char buffer[cnt*12];
+	u32 *currptr = (__u32 *) ptr;
+	char buffer[cnt * 12];
 
-	debug_sprintf_event(cio_debug_msg_id, level, "%s\n", str);
+	debug_text_event (cio_debug_msg_id, level, str);
 
-	for (cnt1 = 0; cnt1<cnt; cnt1+=16) {
-		sprintf(buffer, "%08lX ", (unsigned long)currptr);
+	for (cnt1 = 0; cnt1 < cnt; cnt1 += 16) {
+		sprintf (buffer, "%08lX ", (unsigned long) currptr);
 		maxcnt2 = cnt - cnt1;
 		if (maxcnt2 > 16)
 			maxcnt2 = 16;
 		for (cnt2 = 0; cnt2 < maxcnt2; cnt2 += 4)
-			sprintf(buffer, "%08X ", *currptr++);
+			sprintf (buffer, "%08X ", *currptr++);
 	}
-	debug_sprintf_event(cio_debug_msg_id, level, "%s\n",buffer);
+	debug_text_event (cio_debug_msg_id, level, buffer);
 }
 
-static int __init cio_setup( char *parm )
+static int __init
+cio_setup (char *parm)
 {
-	if ( !strcmp( parm, "yes") )
-	{
+	if (!strcmp (parm, "yes")) {
 		cio_show_msg = 1;
-	}
-	else if ( !strcmp( parm, "no") )
-	{
+	} else if (!strcmp (parm, "no")) {
 		cio_show_msg = 0;
-	}
-	else
-	{
-		printk( KERN_ERR "cio_setup : invalid cio_msg parameter '%s'", parm);
+	} else {
+		printk (KERN_ERR "cio_setup : invalid cio_msg parameter '%s'",
+			parm);
 
-	} /* endif */
+	}
 
 	return 1;
 }
 
-__setup("cio_msg=", cio_setup);
+__setup ("cio_msg=", cio_setup);
 
-static int __init cio_notoper_setup(char *parm)
+static int __init
+cio_notoper_setup (char *parm)
 {
-	if (!strcmp(parm, "yes")) {
+	if (!strcmp (parm, "yes")) {
 		cio_notoper_msg = 1;
-	} else if (!strcmp(parm, "no")) {
+	} else if (!strcmp (parm, "no")) {
 		cio_notoper_msg = 0;
 	} else {
-		printk( KERN_ERR "cio_notoper_setup: invalid cio_notoper_msg parameter '%s'", parm);
+		printk (KERN_ERR
+			"cio_notoper_setup: "
+			"invalid cio_notoper_msg parameter '%s'", parm);
 	}
 
 	return 1;
 }
-	
-__setup("cio_notoper_msg=", cio_notoper_setup);
+
+__setup ("cio_notoper_msg=", cio_notoper_setup);
 
 #ifdef CONFIG_PROC_FS
-static int __init cio_proc_devinfo_setup(char *parm)
+static int __init
+cio_proc_devinfo_setup (char *parm)
 {
-	if (!strcmp(parm, "yes")) {
+	if (!strcmp (parm, "yes")) {
 		cio_proc_devinfo = 1;
-	} else if (!strcmp(parm, "no")) {
+	} else if (!strcmp (parm, "no")) {
 		cio_proc_devinfo = 0;
 	} else {
-		printk( KERN_ERR "cio_proc_devinfo_setup: invalid parameter '%s'\n",parm);
+		printk (KERN_ERR
+			"cio_proc_devinfo_setup: invalid parameter '%s'\n",
+			parm);
 	}
 
 	return 1;
 }
 
-__setup("cio_proc_devinfo=", cio_proc_devinfo_setup);
+__setup ("cio_proc_devinfo=", cio_proc_devinfo_setup);
 #endif
 
+static int __init
+cio_pgid_setup (char *parm)
+{
+	if (!strcmp (parm, "yes")) {
+		cio_sid_with_pgid = 1;
+	} else if (!strcmp (parm, "no")) {
+		cio_sid_with_pgid = 0;
+	} else {
+		printk (KERN_ERR 
+			"cio_pgid_setup : invalid cio_msg parameter '%s'",
+			parm);
+
+	}
+
+	return 1;
+}
+
+__setup ("cio_sid_with_pgid=", cio_pgid_setup);
+
 /*
  * register for adapter interrupts
  *
@@ -625,590 +750,629 @@
  *  being shared interrupts, and thus build a linked list
  *  of adapter handlers ... to be evaluated ...
  */
-int  s390_register_adapter_interrupt( adapter_int_handler_t handler )
+int
+s390_register_adapter_interrupt (adapter_int_handler_t handler)
 {
 	int ret = 0;
 	char dbf_txt[15];
-	
-	if (cio_debug_initialized)
-		debug_text_event(cio_debug_trace_id, 4, "rgaint");
 
-	spin_lock( &adapter_lock );
+	CIO_TRACE_EVENT (4, "rgaint");
 
-	if ( handler == NULL )
+	spin_lock (&adapter_lock);
+
+	if (handler == NULL)
 		ret = -EINVAL;
-	else if ( adapter_handler )
+	else if (adapter_handler)
 		ret = -EBUSY;
 	else
 		adapter_handler = handler;
-  	
-	spin_unlock( &adapter_lock ); 	
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt,"ret:%d",ret);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	spin_unlock (&adapter_lock);
 
-	return( ret);
-}
+	sprintf (dbf_txt, "ret:%d", ret);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
+	return (ret);
+}
 
-int  s390_unregister_adapter_interrupt( adapter_int_handler_t handler )
+int
+s390_unregister_adapter_interrupt (adapter_int_handler_t handler)
 {
 	int ret = 0;
 	char dbf_txt[15];
-	
-	if (cio_debug_initialized)
-		debug_text_event(cio_debug_trace_id, 4, "urgaint");
 
-	spin_lock( &adapter_lock ); 	
+	CIO_TRACE_EVENT (4, "urgaint");
 
-	if ( handler == NULL )
+	spin_lock (&adapter_lock);
+
+	if (handler == NULL)
 		ret = -EINVAL;
-	else if ( handler != adapter_handler )
+	else if (handler != adapter_handler)
 		ret = -EINVAL;
 	else
 		adapter_handler = NULL;
-  	
-	spin_unlock( &adapter_lock ); 	
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt,"ret:%d",ret);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	spin_unlock (&adapter_lock);
 
-	return( ret);
+	sprintf (dbf_txt, "ret:%d", ret);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	return (ret);
 }
 
-static inline void do_adapter_IO( __u32 intparm )
+static inline void
+do_adapter_IO (__u32 intparm)
 {
-	if (cio_debug_initialized)
-		debug_text_event(cio_debug_trace_id, 4, "doaio");
+	CIO_TRACE_EVENT (4, "doaio");
+
+	spin_lock (&adapter_lock);
+
+	if (adapter_handler)
+		(*adapter_handler) (intparm);
+
+	spin_unlock (&adapter_lock);
+
+	return;
+}
+
+
+/*
+ * Function: s390_send_nop
+ * 
+ * sends a nop CCW to the specified subchannel down the given path(s)
+ */
+static int
+s390_send_nop(int irq, __u8 lpm)
+{
+	char dbf_txt[15];
+	ccw1_t *nop_ccw;
+	devstat_t devstat;
+	devstat_t *pdevstat = &devstat;
+	unsigned long flags;
+
+	int irq_ret = 0;
+	int inlreq = 0;
+
+	SANITY_CHECK(irq);
+
+	if (!ioinfo[irq]->ui.flags.oper)
+		/* no sense in trying */
+		return -ENODEV;
+
+	sprintf(dbf_txt, "snop%x", irq);
+	CIO_TRACE_EVENT(5, dbf_txt);
+
+	if (!ioinfo[irq]->ui.flags.ready) {
+		/*
+		 * If there's no handler, use our dummy handler.
+		 */
+		irq_ret = request_irq (irq,
+				       init_IRQ_handler,
+				       SA_PROBE,
+				       "SNOP",
+				       pdevstat);
+		if (!irq_ret)
+			inlreq = 1;
+	} else {
+		pdevstat = ioinfo[irq]->irq_desc.dev_id;
+	}
+	
+	if (irq_ret)
+		return irq_ret;
+
+	s390irq_spin_lock_irqsave (irq, flags);
+
+	if (init_IRQ_complete)
+		nop_ccw = kmalloc (sizeof (ccw1_t), GFP_DMA);
+	else
+		nop_ccw = alloc_bootmem_low (sizeof (ccw1_t));
+
+	nop_ccw->cmd_code = CCW_CMD_NOOP;
+	nop_ccw->cda = 0;
+	nop_ccw->count = 0;
+	nop_ccw->flags = CCW_FLAG_SLI;
+
+	memset (pdevstat, '\0', sizeof (devstat_t));
+	
+	irq_ret = s390_start_IO (irq, nop_ccw, 0xE2D5D6D7, lpm,
+				 DOIO_WAIT_FOR_INTERRUPT
+				 | DOIO_TIMEOUT
+				 | DOIO_DONT_CALL_INTHDLR
+				 | DOIO_VALID_LPM);
 	
-	spin_lock( &adapter_lock ); 	
+	if (irq_ret == -ETIMEDOUT) {
+
+		/* better cancel... */
+		cancel_IO(irq);
+	}
+
+	if (init_IRQ_complete) 
+		kfree (nop_ccw);
+	else
+		free_bootmem ((unsigned long) nop_ccw, sizeof (ccw1_t));
 
-	if ( adapter_handler )
-		(*adapter_handler)( intparm );
+	s390irq_spin_unlock_irqrestore (irq, flags);
 
-	spin_unlock( &adapter_lock );
+	if (inlreq)
+		free_irq (irq, pdevstat);
+
+	return irq_ret;
 
-	return;  	
 }
 
+
+
 /*
  * Note : internal use of irqflags SA_PROBE for NOT path grouping 
  *
  */
-int s390_request_irq_special( int                      irq,
-                              io_handler_func_t        io_handler,
-                              not_oper_handler_func_t  not_oper_handler,
-                              unsigned long            irqflags,
-                              const char              *devname,
-                              void                    *dev_id)
-{
-	int		retval = 0;
-	unsigned long	flags;
-	char            dbf_txt[15];
-	int             retry;
+int
+s390_request_irq_special (int irq,
+			  io_handler_func_t io_handler,
+			  not_oper_handler_func_t not_oper_handler,
+			  unsigned long irqflags,
+			  const char *devname, void *dev_id)
+{
+	int retval = 0;
+	unsigned long flags;
+	char dbf_txt[15];
+	int retry;
 
 	if (irq >= __MAX_SUBCHANNELS)
 		return -EINVAL;
 
-	if ( !io_handler || !dev_id )
+	if (!io_handler || !dev_id)
 		return -EINVAL;
 
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
+	if (ioinfo[irq] == INVALID_STORAGE_AREA)
+		return -ENODEV;
+	
+	if (ioinfo[irq]->st)
 		return -ENODEV;
 
-
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "reqsp%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "reqs%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
 	/*
 	 * The following block of code has to be executed atomically
 	 */
-	s390irq_spin_lock_irqsave( irq, flags);
+	s390irq_spin_lock_irqsave (irq, flags);
 
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
+	if (!ioinfo[irq]->ui.flags.ready) {
 		retry = 5;
-		
+
 		ioinfo[irq]->irq_desc.handler = io_handler;
-		ioinfo[irq]->irq_desc.name    = devname;
-		ioinfo[irq]->irq_desc.dev_id  = dev_id;
-		ioinfo[irq]->ui.flags.ready   = 1;
-		
-		
+		ioinfo[irq]->irq_desc.name = devname;
+		ioinfo[irq]->irq_desc.dev_id = dev_id;
+		ioinfo[irq]->ui.flags.ready = 1;
+
 		do {
-			retval = enable_subchannel(irq);
+			retval = enable_subchannel (irq);
 			if (retval) {
 				ioinfo[irq]->ui.flags.ready = 0;
 				break;
 			}
-			
-			stsch(irq,&ioinfo[irq]->schib);
-			if (ioinfo[irq]->schib.pmcw.ena) 
+
+			stsch (irq, &ioinfo[irq]->schib);
+			if (ioinfo[irq]->schib.pmcw.ena)
 				retry = 0;
 			else
 				retry--;
 
 		} while (retry);
-	}
-	else
-	{
+	} else {
 		/*
 		 *  interrupt already owned, and shared interrupts
 		 *   aren't supported on S/390.
 		 */
 		retval = -EBUSY;
 
-	} /* endif */
-
-	s390irq_spin_unlock_irqrestore(irq,flags);
-
+	}
 
+	s390irq_spin_unlock_irqrestore (irq, flags);
 
-	if ( retval == 0 )
-	{
-		if ( !(irqflags & SA_PROBE))
-			s390_DevicePathVerification( irq, 0 );
+	if (retval == 0) {
+		if (!(irqflags & SA_PROBE) &&
+		    (!ioinfo[irq]->ui.flags.unfriendly)) 
+			s390_DevicePathVerification (irq, 0);
 
 		ioinfo[irq]->ui.flags.newreq = 1;
-		ioinfo[irq]->nopfunc         = not_oper_handler;  	
+		ioinfo[irq]->nopfunc = not_oper_handler;
 	}
 
 	if (cio_debug_initialized)
-		debug_int_event(cio_debug_trace_id, 4, retval);
+		debug_int_event (cio_debug_trace_id, 4, retval);
 
 	return retval;
 }
 
-
-int s390_request_irq( unsigned int   irq,
-                      void           (*handler)(int, void *, struct pt_regs *),
-                      unsigned long  irqflags,
-                      const char    *devname,
-                      void          *dev_id)
+int
+s390_request_irq (unsigned int irq,
+		  void (*handler) (int, void *, struct pt_regs *),
+		  unsigned long irqflags, const char *devname, void *dev_id)
 {
 	int ret;
 
-	ret = s390_request_irq_special( irq,
-                                   (io_handler_func_t)handler,
-                                   NULL,
-                                   irqflags,
-                                   devname,
-                                   dev_id);
+	ret = s390_request_irq_special (irq,
+					(io_handler_func_t) handler,
+					NULL, irqflags, devname, dev_id);
 
-	if ( ret == 0 )
-	{
+	if (ret == 0) {
 		ioinfo[irq]->ui.flags.newreq = 0;
 
-	} /* endif */
-
-	return( ret);
+	}
+	return (ret);
 }
 
-void s390_free_irq(unsigned int irq, void *dev_id)
+void
+s390_free_irq (unsigned int irq, void *dev_id)
 {
 	unsigned long flags;
-	int          ret;
+	int ret;
 
 	char dbf_txt[15];
 
-	if ( irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA )
+	if (irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA)
 		return;
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "free%x", irq);
-		debug_text_event(cio_debug_trace_id, 2, dbf_txt);
-	}
+	if (ioinfo[irq]->st)
+		return;
 
-	s390irq_spin_lock_irqsave( irq, flags);
+	sprintf (dbf_txt, "free%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	s390irq_spin_lock_irqsave (irq, flags);
 
 #ifdef  CONFIG_KERNEL_DEBUG
-	if ( irq != cons_dev )
-		printk( KERN_DEBUG "Trying to free IRQ%d\n",irq);
+	if (irq != cons_dev)
+		printk (KERN_DEBUG "Trying to free IRQ%d\n", irq);
 #endif
-	if (cio_debug_initialized)
-		debug_sprintf_event(cio_debug_msg_id, 2, "Trying to free IRQ %d\n", irq);
+	CIO_MSG_EVENT(2, "Trying to free IRQ %d\n", irq);
 
 	/*
 	 * disable the device and reset all IRQ info if
 	 *  the IRQ is actually owned by the handler ...
 	 */
-	if ( ioinfo[irq]->ui.flags.ready ) {
-		if ( dev_id == ioinfo[irq]->irq_desc.dev_id ) {
+	if (ioinfo[irq]->ui.flags.ready) {
+		if (dev_id == ioinfo[irq]->irq_desc.dev_id) {
 			/* start deregister */
 			ioinfo[irq]->ui.flags.unready = 1;
 
-			/*
-			 * Try to stop IO first...
-			 * ... it seems disable_subchannel is sometimes
-			 * successfully called with IO still pending.
-			 */
-			halt_IO( irq,
-				 0xC8C1D3E3,
-				 DOIO_WAIT_FOR_INTERRUPT );
+			ret = disable_subchannel (irq);
 
-				ret = disable_subchannel( irq);
+			if (ret == -EBUSY) {
 
-			if ( ret == -EBUSY ) {
-
-					/*
-					 * kill it !
-					 * ... we first try sync and eventually
-					 *  try terminating the current I/O by
-					 *  an async request, twice halt, then
-					 *  clear.
-					 */
-				ret = halt_IO( irq,
-						                0xC8C1D3E3,
-						                DOIO_WAIT_FOR_INTERRUPT );
-   	
-				if ( ret == -EBUSY ) {
-							halt_IO( irq, 0xC8C1D3E3, 0);
-							s390irq_spin_unlock_irqrestore( irq, flags);
-							udelay( 200000 ); /* 200 ms */
-							s390irq_spin_lock_irqsave( irq, flags);
+				/*
+				 * kill it !
+				 * We try to terminate the I/O by halt_IO first,
+				 * then clear_IO.
+				 * Because the device may be gone (machine 
+				 * check handling), we can't use sync I/O.
+				 */
 
-						} /* endif */
-				
-				ret = disable_subchannel(irq);
+				halt_IO (irq, 0xC8C1D3E3, 0);
+				s390irq_spin_unlock_irqrestore (irq, flags);
+				udelay (200000);	/* 200 ms */
+				s390irq_spin_lock_irqsave (irq, flags);
+				ret = disable_subchannel (irq);
 
 				if (ret == -EBUSY) {
-   	
-					clear_IO( irq, 0x40C3D3D9,0 );
-							s390irq_spin_unlock_irqrestore( irq, flags);
-							udelay( 1000000 ); /* 1000 ms */
-							s390irq_spin_lock_irqsave( irq, flags);
-
-						/* give it a very last try ... */
-						disable_subchannel( irq);
-
-					if ( ioinfo[irq]->ui.flags.busy ) {
-							printk( KERN_CRIT"free_irq(%04X) "
-							       "- device %04X busy, retry "
-							       "count exceeded\n",
-								irq,
-								ioinfo[irq]->devstat.devno);
-							if (cio_debug_initialized)
-								debug_sprintf_event(cio_debug_msg_id, 0,
-										    "free_irq(%04X) - device %04X busy, retry count exceeded\n",
-										    irq, ioinfo[irq]->devstat.devno);
 
-						} /* endif */
+					clear_IO (irq, 0x40C3D3D9, 0);
+					s390irq_spin_unlock_irqrestore (irq,
+									flags);
+					udelay (1000000);	/* 1000 ms */
+					s390irq_spin_lock_irqsave (irq, flags);
+
+					/* give it a very last try ... */
+					disable_subchannel (irq);
+
+					if (ioinfo[irq]->ui.flags.busy) {
+						printk (KERN_CRIT
+							"free_irq(%04X) "
+							"- device %04X busy, retry "
+							"count exceeded\n", irq,
+							ioinfo[irq]->devstat.
+							devno);
+						CIO_MSG_EVENT( 0,
+							       "free_irq(%04X) - "
+							       "device %04X busy, "
+							       "retry count exceeded\n",
+							       irq,
+							       ioinfo[irq]->
+							       devstat.devno);
 						
-					} /* endif */
+					}
+				}
+			}
 
-				} /* endif */
-		
-			ioinfo[irq]->ui.flags.ready   = 0;
-			ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */
+			ioinfo[irq]->ui.flags.ready = 0;
+			ioinfo[irq]->ui.flags.unready = 0;	/* deregister ended */
 
 			ioinfo[irq]->nopfunc = NULL;
 
-			s390irq_spin_unlock_irqrestore( irq, flags);
+			s390irq_spin_unlock_irqrestore (irq, flags);
 		} else {
-			s390irq_spin_unlock_irqrestore( irq, flags);
+			s390irq_spin_unlock_irqrestore (irq, flags);
 
-			printk( KERN_ERR "free_irq(%04X) : error, "
-			        "dev_id does not match !\n", irq);
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_msg_id, 0, 
-						    "free_irq(%04X) : error, dev_id does not match !\n", irq);
+			printk (KERN_ERR "free_irq(%04X) : error, "
+				"dev_id does not match !\n", irq);
+			CIO_MSG_EVENT( 0,
+				       "free_irq(%04X) : error, "
+				       "dev_id does not match !\n",
+				       irq);
 
-		} /* endif */
+		}
 	} else {
-		s390irq_spin_unlock_irqrestore( irq, flags);
-
-		printk( KERN_ERR "free_irq(%04X) : error, "
-		        "no action block ... !\n", irq);
-		if (cio_debug_initialized)
-			debug_sprintf_event(cio_debug_msg_id, 0,
-					    "free_irq(%04X) : error, no action block ... !\n", irq);
+		s390irq_spin_unlock_irqrestore (irq, flags);
 
-	} /* endif */
+		printk (KERN_ERR "free_irq(%04X) : error, "
+			"no action block ... !\n", irq);
+		CIO_MSG_EVENT(0,
+			      "free_irq(%04X) : error, "
+			      "no action block ... !\n", irq);
 
+	}
 }
 
 /*
  * Generic enable/disable code
  */
-int disable_irq(unsigned int irq)
+int
+disable_irq (unsigned int irq)
 {
 	unsigned long flags;
-	int           ret;
+	int ret;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if ( !ioinfo[irq]->ui.flags.ready )
+	if (!ioinfo[irq]->ui.flags.ready)
 		return -ENODEV;
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "disirq%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "dirq%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	s390irq_spin_lock_irqsave(irq, flags);
-	ret = disable_subchannel(irq);
-	s390irq_spin_unlock_irqrestore(irq, flags);
+	s390irq_spin_lock_irqsave (irq, flags);
+	ret = disable_subchannel (irq);
+	s390irq_spin_unlock_irqrestore (irq, flags);
 
-	synchronize_irq();
+	synchronize_irq ();
 
-	if (cio_debug_initialized) 
-		debug_int_event(cio_debug_trace_id, 4, ret);
+	sprintf (dbf_txt, "ret:%d", ret);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	return( ret);
+	return (ret);
 }
 
-int enable_irq(unsigned int irq)
+int
+enable_irq (unsigned int irq)
 {
 	unsigned long flags;
-	int           ret;
+	int ret;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if ( !ioinfo[irq]->ui.flags.ready )
+	if (!ioinfo[irq]->ui.flags.ready)
 		return -ENODEV;
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "enirq%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "eirq%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	s390irq_spin_lock_irqsave(irq, flags);
-	ret = enable_subchannel(irq);
-	s390irq_spin_unlock_irqrestore(irq, flags);
+	s390irq_spin_lock_irqsave (irq, flags);
+	ret = enable_subchannel (irq);
+	s390irq_spin_unlock_irqrestore (irq, flags);
 
-	if (cio_debug_initialized) 
-		debug_int_event(cio_debug_trace_id, 4, ret);
+	sprintf (dbf_txt, "ret:%d", ret);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	return(ret);
+	return (ret);
 }
 
 /*
  * Enable IRQ by modifying the subchannel
  */
-static int enable_subchannel( unsigned int irq)
+static int
+enable_subchannel (unsigned int irq)
 {
-	int   ret = 0;
-	int   ccode;
-	int   retry = 5;
+	int ret = 0;
+	int ccode;
+	int retry = 5;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "ensch%x", irq);
-		debug_text_event(cio_debug_trace_id, 2, dbf_txt);
-	}
+	sprintf (dbf_txt, "esch%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
 
 	/*
 	 * If a previous disable request is pending we reset it. However, this
 	 *  status implies that the device may (still) be not-operational.
 	 */
-	if (  ioinfo[irq]->ui.flags.d_disable )
-	{
+	if (ioinfo[irq]->ui.flags.d_disable) {
 		ioinfo[irq]->ui.flags.d_disable = 0;
-		ret                             = 0;
-	}
-	else
-	{
-		ccode = stsch(irq, &(ioinfo[irq]->schib) );
+		ret = 0;
+	} else {
+		ccode = stsch (irq, &(ioinfo[irq]->schib));
 
-		if ( ccode )
-		{
+		if (ccode) {
 			ret = -ENODEV;
-		}
-		else
-		{
+		} else {
 			ioinfo[irq]->schib.pmcw.ena = 1;
 
-			if ( irq == cons_dev )
-			{
+			if (irq == cons_dev) {
 				ioinfo[irq]->schib.pmcw.isc = 7;
-			}
-			else	
-			{
+			} else {
 				ioinfo[irq]->schib.pmcw.isc = 3;
 
-			} /* endif */
+			}
 
-			do
-			{
-				ccode = msch( irq, &(ioinfo[irq]->schib) );
+			do {
+				ccode = msch (irq, &(ioinfo[irq]->schib));
 
 				switch (ccode) {
-				case 0: /* ok */
+				case 0:	/* ok */
 					ret = 0;
 					retry = 0;
 					break;
 
-				case 1: /* status pending */
+				case 1:	/* status pending */
 
 					ioinfo[irq]->ui.flags.s_pend = 1;
-					s390_process_IRQ( irq );
+					s390_process_IRQ (irq);
 					ioinfo[irq]->ui.flags.s_pend = 0;
 
-					ret = -EIO;    /* might be overwritten */
-					               /* ... on re-driving    */
-					               /* ... the msch()       */
+					ret = -EIO;
+					/* 
+					 * might be overwritten on re-driving 
+					 * the msch()       
+					 */
 					retry--;
 					break;
 
-				case 2: /* busy */
-					udelay(100);	/* allow for recovery */
+				case 2:	/* busy */
+					udelay (100);	/* allow for recovery */
 					ret = -EBUSY;
 					retry--;
 					break;
 
-				case 3: /* not oper */
+				case 3:	/* not oper */
 					ioinfo[irq]->ui.flags.oper = 0;
 					retry = 0;
 					ret = -ENODEV;
 					break;
 				}
 
-			} while ( retry );
-
-		} /* endif */
+			} while (retry);
 
-	}  /* endif */
-
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt,"ret:%d",ret);
-		debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+		}
 	}
 
-	return( ret );
-}
+	sprintf (dbf_txt, "ret:%d", ret);
+	CIO_TRACE_EVENT (2, dbf_txt);
 
+	return (ret);
+}
 
 /*
  * Disable IRQ by modifying the subchannel
  */
-static int disable_subchannel( unsigned int irq)
+static int
+disable_subchannel (unsigned int irq)
 {
-	int  cc;          /* condition code */
-	int  ret = 0;     /* function return value */
-	int  retry = 5;
+	int cc;			/* condition code */
+	int ret = 0;		/* function return value */
+	int retry = 5;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
-	
-	if ( ioinfo[irq]->ui.flags.busy )
-	{
+	SANITY_CHECK (irq);
+
+	sprintf (dbf_txt, "dsch%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	if (ioinfo[irq]->ui.flags.busy) {
 		/*
 		 * the disable function must not be called while there are
 		 *  requests pending for completion !
 		 */
 		ret = -EBUSY;
-	}
-	else
-	{
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "dissch%x", irq);
-			debug_text_event(cio_debug_trace_id, 2, dbf_txt);
-		}
-		
+	} else {
+
 		/*
 		 * If device isn't operational we have to perform delayed
 		 *  disabling when the next interrupt occurs - unless the
 		 *  irq is re-requested prior to the interrupt to occur.
 		 */
-		cc = stsch(irq, &(ioinfo[irq]->schib) );
+		cc = stsch (irq, &(ioinfo[irq]->schib));
 
-		if ( cc == 3 )
-		{
-			ioinfo[irq]->ui.flags.oper      = 0;
+		if (cc == 3) {
+			ioinfo[irq]->ui.flags.oper = 0;
 			ioinfo[irq]->ui.flags.d_disable = 1;
 
 			ret = 0;
-		}
-		else // cc == 0
-		{
+		} else {	/* cc == 0 */
+
 			ioinfo[irq]->schib.pmcw.ena = 0;
 
-			do
-			{
-				cc = msch( irq, &(ioinfo[irq]->schib) );
+			do {
+				cc = msch (irq, &(ioinfo[irq]->schib));
 
 				switch (cc) {
-				case 0: /* ok */
+				case 0:	/* ok */
 					retry = 0;
-					ret = 0;   
+					ret = 0;
 					break;
 
-				case 1: /* status pending */
+				case 1:	/* status pending */
 					ioinfo[irq]->ui.flags.s_pend = 1;
-					s390_process_IRQ( irq );
+					s390_process_IRQ (irq);
 					ioinfo[irq]->ui.flags.s_pend = 0;
 
-					ret = -EIO; /* might be overwritten  */
-					            /* ... on re-driving the */
-					            /* ... msch() call       */
+					ret = -EIO;
+					/* 
+					 * might be overwritten on re-driving 
+					 * the msch() call       
+					 */
 					retry--;
 					break;
 
-				case 2: /* busy; this should not happen! */
-					printk( KERN_CRIT"disable_subchannel(%04X) "
-					        "- unexpected busy condition for "
-						"device %04X received !\n",
-					        irq,
-					        ioinfo[irq]->devstat.devno);
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_msg_id, 0, 
-								    "disable_subchannel(%04X) - unexpected busy condition for device %04X received !\n",
-								    irq, ioinfo[irq]->devstat.devno);
+				case 2:	/* busy; this should not happen! */
+					printk (KERN_CRIT
+						"disable_subchannel(%04X) "
+						"- unexpected busy condition for "
+						"device %04X received !\n", irq,
+						ioinfo[irq]->devstat.devno);
+					CIO_MSG_EVENT(0,
+						      "disable_subchannel(%04X) "
+						      "- unexpected busy condition "
+						      "for device %04X received !\n",
+						      irq,
+						      ioinfo[irq]->devstat.
+						      devno);
 					retry = 0;
 					ret = -EBUSY;
 					break;
 
-				case 3: /* not oper */
+				case 3:	/* not oper */
 					/*
 					 * should hardly occur ?!
 					 */
-					ioinfo[irq]->ui.flags.oper      = 0;
+					ioinfo[irq]->ui.flags.oper = 0;
 					ioinfo[irq]->ui.flags.d_disable = 1;
 					retry = 0;
 
-					ret = 0; /* if the device has gone we */
-					         /* ... don't need to disable */
-					         /* ... it anymore !          */
+					ret = 0;
+					/* 
+					 * if the device has gone, we don't need 
+					 * to disable it anymore !          
+					 */
 					break;
 
-				} /* endswitch */
-
-			} while ( retry );
-
-		} /* endif */
+				}
 
-	} /* endif */
+			} while (retry);
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "ret:%d",ret);
-		debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+		}
 	}
 
-	return( ret);
-}
+	sprintf (dbf_txt, "ret:%d", ret);
+	CIO_TRACE_EVENT (2, dbf_txt);
 
+	return (ret);
+}
 
-void s390_init_IRQ( void )
+void
+s390_init_IRQ (void)
 {
-	unsigned long flags;     /* PSW flags */
-	long          cr6 __attribute__ ((aligned (8)));
+	unsigned long flags;	/* PSW flags */
+	long cr6 __attribute__ ((aligned (8)));
 
-	asm volatile ("STCK %0" : "=m" (irq_IPL_TOD));
+	asm volatile ("STCK %0":"=m" (irq_IPL_TOD));
+
+	p_init_schib = alloc_bootmem_low (sizeof (schib_t));
+	p_init_irb = alloc_bootmem_low (sizeof (irb_t));
 
-	p_init_schib = alloc_bootmem_low( sizeof(schib_t));
-	p_init_irb   = alloc_bootmem_low( sizeof(irb_t));
-	
-	
 	/*
 	 * As we don't know about the calling environment
 	 *  we assure running disabled. Before leaving the
@@ -1218,96 +1382,103 @@
 	 *        we shouldn't use cli(), but __cli() as this
 	 *        affects the current CPU only.
 	 */
-	__save_flags(flags);
-	__cli();
+	__save_flags (flags);
+	__cli ();
 
 	/*
 	 * disable all interrupts
 	 */
 	cr6 = 0;
-	__ctl_load( cr6, 6, 6);
+	__ctl_load (cr6, 6, 6);
 
-	s390_process_subchannels();
+	s390_process_subchannels ();
 
 	if (cio_count_irqs) {
 		int i;
-		for (i=0; i<NR_CPUS; i++) 
-			s390_irq_count[i]=0;
+		for (i = 0; i < NR_CPUS; i++)
+			s390_irq_count[i] = 0;
 	}
 
+	
+	/*
+	 * Let's build our path group ID here.
+	 */
+	
+	global_pgid = (pgid_t *)alloc_bootmem(sizeof(pgid_t));
+
+	global_pgid->cpu_addr = *(__u16 *) __LC_CPUADDR;
+	global_pgid->cpu_id = ((cpuid_t *) __LC_CPUID)->ident;
+	global_pgid->cpu_model = ((cpuid_t *) __LC_CPUID)->machine;
+	global_pgid->tod_high = *(__u32 *) & irq_IPL_TOD;
+
+
 	/*
 	 * enable default I/O-interrupt sublass 3
 	 */
 	cr6 = 0x10000000;
-	__ctl_load( cr6, 6, 6);
+	__ctl_load (cr6, 6, 6);
 
-	s390_device_recognition_all();
+	s390_device_recognition_all ();
 
 	init_IRQ_complete = 1;
 
-	__restore_flags(flags);
+	__restore_flags (flags);
 
 	return;
 }
 
-
 /*
  * dummy handler, used during init_IRQ() processing for compatibility only
  */
-void  init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs)
+void
+init_IRQ_handler (int irq, void *dev_id, struct pt_regs *regs)
 {
-   /* this is a dummy handler only ... */
+	/* this is a dummy handler only ... */
 }
 
-
-int s390_start_IO( int            irq,      /* IRQ */
-                   ccw1_t        *cpa,      /* logical channel prog addr */
-                   unsigned long  user_intparm,  /* interruption parameter */
-                   __u8           lpm,      /* logical path mask */
-                   unsigned long  flag)     /* flags */
-{
-	int            ccode;
-	int            ret = 0;
+int
+s390_start_IO (int irq,		/* IRQ */
+	       ccw1_t * cpa,	/* logical channel prog addr */
+	       unsigned long user_intparm,	/* interruption parameter */
+	       __u8 lpm,	/* logical path mask */
+	       unsigned long flag)
+{				/* flags */
+	int ccode;
+	int ret = 0;
 	char buffer[80];
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
 	/*
 	 * The flag usage is mutal exclusive ...
 	 */
-	if (    (flag & DOIO_EARLY_NOTIFICATION)
-	     && (flag & DOIO_REPORT_ALL     ) )
-	{
-		return( -EINVAL );
-
-	} /* endif */
-
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "stIO%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	if ((flag & DOIO_EARLY_NOTIFICATION)
+	    && (flag & DOIO_REPORT_ALL)) {
+		return (-EINVAL);
+
 	}
 
+	sprintf (dbf_txt, "stIO%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
 	/*
 	 * setup ORB
 	 */
-  	ioinfo[irq]->orb.intparm = (__u32)(long)&ioinfo[irq]->u_intparm;
-	ioinfo[irq]->orb.fmt     = 1;
+	ioinfo[irq]->orb.intparm = (__u32) (long) &ioinfo[irq]->u_intparm;
+	ioinfo[irq]->orb.fmt = 1;
 
 	ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH);
-	ioinfo[irq]->orb.spnd =  (flag & DOIO_ALLOW_SUSPEND ? TRUE : FALSE);
-	ioinfo[irq]->orb.ssic =  (    (flag & DOIO_ALLOW_SUSPEND )
-	                           && (flag & DOIO_SUPPRESS_INTER) );
+	ioinfo[irq]->orb.spnd = (flag & DOIO_ALLOW_SUSPEND ? TRUE : FALSE);
+	ioinfo[irq]->orb.ssic = ((flag & DOIO_ALLOW_SUSPEND)
+				 && (flag & DOIO_SUPPRESS_INTER));
 
-	if ( flag & DOIO_VALID_LPM )
-	{
+	if (flag & DOIO_VALID_LPM) {
 		ioinfo[irq]->orb.lpm = lpm;
-	}
-	else
-	{
+	} else {
 		ioinfo[irq]->orb.lpm = ioinfo[irq]->opm;
 
-	} /* endif */
+	}
 
 #ifdef CONFIG_ARCH_S390X
 	/* 
@@ -1317,72 +1488,64 @@
 	ioinfo[irq]->orb.i2k = 0;
 #endif
 
-	ioinfo[irq]->orb.cpa = (__u32)virt_to_phys( cpa);
+	ioinfo[irq]->orb.cpa = (__u32) virt_to_phys (cpa);
 
 	/*
 	 * If sync processing was requested we lock the sync ISC, modify the
 	 *  device to present interrupts for this ISC only and switch the
 	 *  CPU to handle this ISC + the console ISC exclusively.
 	 */
-	if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-	{
-		ret = enable_cpu_sync_isc( irq);
-	
-		if ( ret )
-		{
-			return( ret);
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+		ret = enable_cpu_sync_isc (irq);
+
+		if (ret) {
+			return (ret);
 		}
 
-	} /* endif */
+	}
 
-	if ( flag & DOIO_DONT_CALL_INTHDLR )
-	{
+	if (flag & DOIO_DONT_CALL_INTHDLR) {
 		ioinfo[irq]->ui.flags.repnone = 1;
 
-	} /* endif */
+	}
 
 	/*
 	 * Issue "Start subchannel" and process condition code
 	 */
-	ccode = ssch( irq, &(ioinfo[irq]->orb) );
+	ccode = ssch (irq, &(ioinfo[irq]->orb));
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "ccode:%d", ccode);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	switch ( ccode ) {
+	switch (ccode) {
 	case 0:
 
-		if ( !ioinfo[irq]->ui.flags.w4sense )
-		{
+		if (!ioinfo[irq]->ui.flags.w4sense) {
 			/*
 			 * init the device driver specific devstat irb area
 			 *
 			 * Note : dont clear saved irb info in case of sense !
 			 */
-			memset( &((devstat_t *)ioinfo[irq]->irq_desc.dev_id)->ii.irb,
-				'\0', sizeof( irb_t) );
-		} /* endif */
-
-		memset( &ioinfo[irq]->devstat.ii.irb,
-		        '\0',
-		        sizeof( irb_t) );
+			memset (&((devstat_t *) ioinfo[irq]->irq_desc.dev_id)->
+				ii.irb, '\0', sizeof (irb_t));
+		}
+
+		memset (&ioinfo[irq]->devstat.ii.irb, '\0', sizeof (irb_t));
 
 		/*
 		 * initialize device status information
 		 */
-		ioinfo[irq]->ui.flags.busy   = 1;
-		ioinfo[irq]->ui.flags.doio   = 1;
+		ioinfo[irq]->ui.flags.busy = 1;
+		ioinfo[irq]->ui.flags.doio = 1;
 
-		ioinfo[irq]->u_intparm       = user_intparm;
-		ioinfo[irq]->devstat.cstat   = 0;
-		ioinfo[irq]->devstat.dstat   = 0;
-		ioinfo[irq]->devstat.lpum    = 0;
-		ioinfo[irq]->devstat.flag    = DEVSTAT_START_FUNCTION;
-		ioinfo[irq]->devstat.scnt    = 0;
+		ioinfo[irq]->u_intparm = user_intparm;
+		ioinfo[irq]->devstat.cstat = 0;
+		ioinfo[irq]->devstat.dstat = 0;
+		ioinfo[irq]->devstat.lpum = 0;
+		ioinfo[irq]->devstat.flag = DEVSTAT_START_FUNCTION;
+		ioinfo[irq]->devstat.scnt = 0;
 
-		ioinfo[irq]->ui.flags.fast   = 0;
+		ioinfo[irq]->ui.flags.fast = 0;
 		ioinfo[irq]->ui.flags.repall = 0;
 
 		/*
@@ -1390,15 +1553,12 @@
 		 *  or if we are to return all interrupt info.
 		 * Default is to call IRQ handler at secondary status only
 		 */
-		if ( flag & DOIO_EARLY_NOTIFICATION )
-		{
+		if (flag & DOIO_EARLY_NOTIFICATION) {
 			ioinfo[irq]->ui.flags.fast = 1;
-		}
-		else if ( flag & DOIO_REPORT_ALL )
-		{
+		} else if (flag & DOIO_REPORT_ALL) {
 			ioinfo[irq]->ui.flags.repall = 1;
 
-		} /* endif */
+		}
 
 		ioinfo[irq]->ulpm = ioinfo[irq]->orb.lpm;
 
@@ -1410,17 +1570,15 @@
 		 *  for the first interrupt, but must poll until ours
 		 *  pops up.
 		 */
-		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-		{
-			unsigned long    psw_mask;
-			int              ccode;
-			uint64_t         time_start;    	
-			uint64_t         time_curr;    	
-
-			int              ready    = 0;
-			int              io_sub   = -1;
-			struct _lowcore *lc       = NULL;
-			int              do_retry = 1;
+		if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+			unsigned long psw_mask;
+			int ccode;
+			uint64_t time_start;
+			uint64_t time_curr;
+
+			int ready = 0;
+			int io_sub = -1;
+			int do_retry = 1;
 
 			/*
 			 * We shouldn't perform a TPI loop, waiting for an
@@ -1431,104 +1589,100 @@
 			 *  its original value.
 			 */
 
-			ccode = iac();
+			ccode = iac ();
 
 			switch (ccode) {
-			case 0:  		// primary-space
+			case 0:	/* primary-space */
 				psw_mask = _IO_PSW_MASK
 				    | _PSW_PRIM_SPACE_MODE | _PSW_IO_WAIT;
 				break;
-			case 1:			// secondary-space
+			case 1:	/* secondary-space */
 				psw_mask = _IO_PSW_MASK
 				    | _PSW_SEC_SPACE_MODE | _PSW_IO_WAIT;
 				break;
-			case 2:			// access-register
+			case 2:	/* access-register */
 				psw_mask = _IO_PSW_MASK
 				    | _PSW_ACC_REG_MODE | _PSW_IO_WAIT;
 				break;
-			case 3:			// home-space	
+			case 3:	/* home-space */
 				psw_mask = _IO_PSW_MASK
 				    | _PSW_HOME_SPACE_MODE | _PSW_IO_WAIT;
 				break;
 			default:
-				panic( "start_IO() : unexpected "
-				       "address-space-control %d\n",
-				       ccode);
+				panic ("start_IO() : unexpected "
+				       "address-space-control %d\n", ccode);
 				break;
-			} /* endswitch */
+			}
 
 			/*
 			 * Martin didn't like modifying the new PSW, now we take
 			 *  a fast exit in do_IRQ() instead
 			 */
-			*(__u32 *)__LC_SYNC_IO_WORD  = 1;
+			*(__u32 *) __LC_SYNC_IO_WORD = 1;
 
-			asm volatile ("STCK %0" : "=m" (time_start));
+			asm volatile ("STCK %0":"=m" (time_start));
 
 			time_start = time_start >> 32;
 
-			do
-			{
-				if ( flag & DOIO_TIMEOUT )
-				{
-					tpi_info_t tpi_info={0,};
+			do {
+				if (flag & DOIO_TIMEOUT) {
+					tpi_info_t tpi_info = { 0, };
 
-					do
-					{
-						if ( tpi(&tpi_info) == 1 )
-						{
+					do {
+						if (tpi (&tpi_info) == 1) {
 							io_sub = tpi_info.irq;
 							break;
-						}
-						else
-						{
-							udelay(100); /* usecs */
-							asm volatile ("STCK %0" : "=m" (time_curr));
+						} else {
+							udelay (100);	/* usecs */
+							asm volatile
+							 ("STCK %0":"=m"
+							  (time_curr));
+
+							if (((time_curr >> 32) -
+							     time_start) >= 3)
+								do_retry = 0;
 
-							if ( ((time_curr >> 32) - time_start ) >= 3 )
-								do_retry = 0;          							
+						}
 
-						} /* endif */
-				
-					} while ( do_retry );
-				}
-				else
-				{
-					__load_psw_mask( psw_mask );
+					} while (do_retry);
+				} else {
+					__load_psw_mask (psw_mask);
 
-					io_sub  = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
+					io_sub =
+					    (__u32) *
+					    (__u16 *) __LC_SUBCHANNEL_NR;
 
-				} /* endif */
+				}
 
- 				if ( do_retry )
-					ready = s390_process_IRQ( io_sub );
+				if (do_retry)
+					ready = s390_process_IRQ (io_sub);
 
 				/*
 				 * surrender when retry count's exceeded ...
 				 */
-			} while ( !(     ( io_sub == irq )
-			              && ( ready  == 1   ))
-			            && do_retry             );
+			} while (!((io_sub == irq)
+				   && (ready == 1))
+				 && do_retry);
 
-			*(__u32 *)__LC_SYNC_IO_WORD = 0;
+			*(__u32 *) __LC_SYNC_IO_WORD = 0;
 
-			if ( !do_retry )
+			if (!do_retry)
 				ret = -ETIMEDOUT;
 
-		} /* endif */
+		}
 
 		break;
 
-	case 1 :            /* status pending */
+	case 1:		/* status pending */
 
-		ioinfo[irq]->devstat.flag =   DEVSTAT_START_FUNCTION
-		                            | DEVSTAT_STATUS_PENDING;
+		ioinfo[irq]->devstat.flag = DEVSTAT_START_FUNCTION
+		    | DEVSTAT_STATUS_PENDING;
 
 		/*
 		 * initialize the device driver specific devstat irb area
 		 */
-		memset( &((devstat_t *) ioinfo[irq]->irq_desc.dev_id)->ii.irb,
-		        '\0', sizeof( irb_t) );
+		memset (&((devstat_t *) ioinfo[irq]->irq_desc.dev_id)->ii.irb,
+			'\0', sizeof (irb_t));
 
 		/*
 		 * Let the common interrupt handler process the pending status.
@@ -1538,20 +1692,20 @@
 		 *  must terminate synchronously - especially if device sensing
 		 *  is required.
 		 */
-		ioinfo[irq]->ui.flags.s_pend   = 1;
-		ioinfo[irq]->ui.flags.busy     = 1;
-		ioinfo[irq]->ui.flags.doio     = 1;
-
-		s390_process_IRQ( irq );
+		ioinfo[irq]->ui.flags.s_pend = 1;
+		ioinfo[irq]->ui.flags.busy = 1;
+		ioinfo[irq]->ui.flags.doio = 1;
+
+		s390_process_IRQ (irq);
+
+		ioinfo[irq]->ui.flags.s_pend = 0;
+		ioinfo[irq]->ui.flags.busy = 0;
+		ioinfo[irq]->ui.flags.doio = 0;
 
-		ioinfo[irq]->ui.flags.s_pend   = 0;
-		ioinfo[irq]->ui.flags.busy     = 0;
-		ioinfo[irq]->ui.flags.doio     = 0;
-
-		ioinfo[irq]->ui.flags.repall   = 0;
-		ioinfo[irq]->ui.flags.w4final  = 0;
+		ioinfo[irq]->ui.flags.repall = 0;
+		ioinfo[irq]->ui.flags.w4final = 0;
 
-		ioinfo[irq]->devstat.flag     |= DEVSTAT_FINAL_STATUS;
+		ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
 
 		/*
 		 * In multipath mode a condition code 3 implies the last path
@@ -1560,225 +1714,216 @@
 		 *  results in return code EIO as well as 3 with another path
 		 *  than the one used (i.e. path available mask is non-zero).
 		 */
-		if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
-		{
-			if ( flag & DOIO_VALID_LPM )
-			{
-				ioinfo[irq]->opm &= ~(ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum);
-			}
-			else
-			{
+		if (ioinfo[irq]->devstat.ii.irb.scsw.cc == 3) {
+			if (flag & DOIO_VALID_LPM) {
+				ioinfo[irq]->opm &=
+				    ~(ioinfo[irq]->devstat.ii.irb.esw.esw1.
+				      lpum);
+			} else {
 				ioinfo[irq]->opm = 0;
 
-			} /* endif */
-	
-			if ( ioinfo[irq]->opm == 0 ) 	
-			{
-				ret                         = -ENODEV;
-				ioinfo[irq]->ui.flags.oper  = 0;
 			}
-			else
-			{
+
+			if (ioinfo[irq]->opm == 0) {
+				ret = -ENODEV;
+				ioinfo[irq]->ui.flags.oper = 0;
+			} else {
 				ret = -EIO;
 
-			} /* endif */
+			}
 
-			ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;
+			ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
 
 #ifdef CONFIG_DEBUG_IO
 			{
 
-			stsch(irq, &(ioinfo[irq]->schib) );
+				stsch (irq, &(ioinfo[irq]->schib));
 
-			sprintf( buffer, "s390_start_IO(%04X) - irb for "
-			         "device %04X, after status pending\n",
-			         irq,
-			         ioinfo[irq]->devstat.devno );
-
-			s390_displayhex( buffer,
-			                 &(ioinfo[irq]->devstat.ii.irb) ,
-			                 sizeof(irb_t));
+				sprintf (buffer,
+					 "s390_start_IO(%04X) - irb for "
+					 "device %04X, after status pending\n",
+					 irq, ioinfo[irq]->devstat.devno);
 
-			sprintf( buffer, "s390_start_IO(%04X) - schib for "
-			         "device %04X, after status pending\n",
-			         irq,
-			         ioinfo[irq]->devstat.devno );
+				s390_displayhex (buffer,
+						 &(ioinfo[irq]->devstat.ii.irb),
+						 sizeof (irb_t));
 
-			s390_displayhex( buffer,
-			                 &(ioinfo[irq]->schib) ,
-			                 sizeof(schib_t));
+				sprintf (buffer,
+					 "s390_start_IO(%04X) - schib for "
+					 "device %04X, after status pending\n",
+					 irq, ioinfo[irq]->devstat.devno);
 
+				s390_displayhex (buffer,
+						 &(ioinfo[irq]->schib),
+						 sizeof (schib_t));
+
+				if (ioinfo[irq]->devstat.
+				    flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+					sprintf (buffer,
+						 "s390_start_IO(%04X) "
+						 "- sense data for device %04X,"
+						 " after status pending\n",
+						 irq,
+						 ioinfo[irq]->devstat.devno);
 
-			if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL)
-			{
-				sprintf( buffer, "s390_start_IO(%04X) - sense "
-				         "data for "
-				         "device %04X, after status pending\n",
-				         irq,
-				         ioinfo[irq]->devstat.devno );
-
-				s390_displayhex( buffer,
-					ioinfo[irq]->irq_desc.dev_id->ii.sense.data,
-					ioinfo[irq]->irq_desc.dev_id->rescnt);
+					s390_displayhex (buffer,
+							 ioinfo[irq]->irq_desc.
+							 dev_id->ii.sense.data,
+							 ioinfo[irq]->irq_desc.
+							 dev_id->rescnt);
 
-			} /* endif */
+				}
 			}
 #endif
 			if (cio_debug_initialized) {
-				stsch(irq, &(ioinfo[irq]->schib) );
-				
-				sprintf( buffer, "s390_start_IO(%04X) - irb for "
+				stsch (irq, &(ioinfo[irq]->schib));
+
+				sprintf (buffer,
+					 "s390_start_IO(%04X) - irb for "
 					 "device %04X, after status pending\n",
-					 irq,
-					 ioinfo[irq]->devstat.devno );
-				
-				s390_displayhex2( buffer,
-						 &(ioinfo[irq]->devstat.ii.irb) ,
-						 sizeof(irb_t), 2);
-				
-				sprintf( buffer, "s390_start_IO(%04X) - schib for "
+					 irq, ioinfo[irq]->devstat.devno);
+
+				s390_displayhex2 (buffer,
+						  &(ioinfo[irq]->devstat.ii.
+						    irb), sizeof (irb_t), 2);
+
+				sprintf (buffer,
+					 "s390_start_IO(%04X) - schib for "
 					 "device %04X, after status pending\n",
-					 irq,
-					 ioinfo[irq]->devstat.devno );
-				
-				s390_displayhex2( buffer,
-						 &(ioinfo[irq]->schib) ,
-						 sizeof(schib_t), 2);
-				
-				
-				if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL) {
-					sprintf( buffer, "s390_start_IO(%04X) - sense "
-						 "data for "
-						 "device %04X, after status pending\n",
+					 irq, ioinfo[irq]->devstat.devno);
+
+				s390_displayhex2 (buffer,
+						  &(ioinfo[irq]->schib),
+						  sizeof (schib_t), 2);
+
+				if (ioinfo[irq]->devstat.
+				    flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+					sprintf (buffer,
+						 "s390_start_IO(%04X) "
+						 "- sense data for device %04X,"
+						 " after status pending\n",
 						 irq,
-						 ioinfo[irq]->devstat.devno );
-					
-					s390_displayhex2( buffer,
-							  ioinfo[irq]->irq_desc.dev_id->ii.sense.data,
-							  ioinfo[irq]->irq_desc.dev_id->rescnt, 2);
-					
-				} /* endif */
+						 ioinfo[irq]->devstat.devno);
+
+					s390_displayhex2 (buffer,
+							  ioinfo[irq]->irq_desc.
+							  dev_id->ii.sense.data,
+							  ioinfo[irq]->irq_desc.
+							  dev_id->rescnt, 2);
+
+				}
 			}
-		}
-		else
-		{
-			ret                         = -EIO;
-			ioinfo[irq]->devstat.flag  &= ~DEVSTAT_NOT_OPER;
-			ioinfo[irq]->ui.flags.oper  = 1;
+		} else {
+			ret = -EIO;
+			ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
+			ioinfo[irq]->ui.flags.oper = 1;
 
-		} /* endif */
+		}
 
 		break;
 
-	case 2 :            /* busy */
+	case 2:		/* busy */
 
 		ret = -EBUSY;
 		break;
 
-	default:            /* device/path not operational */
-		
-		if ( flag & DOIO_VALID_LPM )
-		{
+	default:		/* device/path not operational */
+
+		if (flag & DOIO_VALID_LPM) {
 			ioinfo[irq]->opm &= ~lpm;
-		}
-		else
-		{
+		} else {
 			ioinfo[irq]->opm = 0;
 
-		} /* endif */
-	
-		if ( ioinfo[irq]->opm == 0 ) 	
-		{
-			ioinfo[irq]->ui.flags.oper  = 0;
-			ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;
+		}
 
-		} /* endif */
+		if (ioinfo[irq]->opm == 0) {
+			ioinfo[irq]->ui.flags.oper = 0;
+			ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
 
-		ret = -ENODEV;
+		}
 
-		memcpy( ioinfo[irq]->irq_desc.dev_id,
-		        &(ioinfo[irq]->devstat),
-		        sizeof( devstat_t) );
+		ret = -ENODEV;
 
+		memcpy (ioinfo[irq]->irq_desc.dev_id,
+			&(ioinfo[irq]->devstat), sizeof (devstat_t));
 
 #ifdef CONFIG_DEBUG_IO
 
-   			stsch(irq, &(ioinfo[irq]->schib) );
+		stsch (irq, &(ioinfo[irq]->schib));
+
+		sprintf (buffer, "s390_start_IO(%04X) - schib for "
+			 "device %04X, after 'not oper' status\n",
+			 irq, ioinfo[irq]->devstat.devno);
 
-			sprintf( buffer, "s390_start_IO(%04X) - schib for "
-			         "device %04X, after 'not oper' status\n",
-			         irq,
-			         ioinfo[irq]->devstat.devno );
-
-			s390_displayhex( buffer,
-			                 &(ioinfo[irq]->schib),
-			                 sizeof(schib_t));
+		s390_displayhex (buffer,
+				 &(ioinfo[irq]->schib), sizeof (schib_t));
 #endif
 		if (cio_debug_initialized) {
-			stsch(irq, &(ioinfo[irq]->schib) );
+			stsch (irq, &(ioinfo[irq]->schib));
 
-			sprintf( buffer, "s390_start_IO(%04X) - schib for "
-			         "device %04X, after 'not oper' status\n",
-			         irq,
-			         ioinfo[irq]->devstat.devno );
-
-			s390_displayhex2( buffer,
-			                 &(ioinfo[irq]->schib),
-			                 sizeof(schib_t), 2);
+			sprintf (buffer, "s390_start_IO(%04X) - schib for "
+				 "device %04X, after 'not oper' status\n",
+				 irq, ioinfo[irq]->devstat.devno);
+
+			s390_displayhex2 (buffer,
+					  &(ioinfo[irq]->schib),
+					  sizeof (schib_t), 2);
 		}
-			
+
 		break;
 
-	} /* endswitch */
+	}
 
-	if ( flag & DOIO_WAIT_FOR_INTERRUPT)
-	{
-		disable_cpu_sync_isc( irq );
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+		disable_cpu_sync_isc (irq);
 
-	} /* endif */
+	}
 
-	if ( flag & DOIO_DONT_CALL_INTHDLR )
-	{
+	if (flag & DOIO_DONT_CALL_INTHDLR) {
 		ioinfo[irq]->ui.flags.repnone = 0;
 
-   } /* endif */
+	}
 
-	return( ret);
+	return (ret);
 }
 
-int do_IO( int            irq,          /* IRQ */
-           ccw1_t        *cpa,          /* channel program address */
-           unsigned long  user_intparm, /* interruption parameter */
-           __u8           lpm,          /* logical path mask */
-           unsigned long  flag)         /* flags : see above */
-{
+int
+do_IO (int irq,			/* IRQ */
+       ccw1_t * cpa,		/* channel program address */
+       unsigned long user_intparm,	/* interruption parameter */
+       __u8 lpm,		/* logical path mask */
+       unsigned long flag)
+{				/* flags : see above */
 	int ret = 0;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
 	/* handler registered ? or free_irq() in process already ? */
-	if ( !ioinfo[irq]->ui.flags.ready || ioinfo[irq]->ui.flags.unready )
-	{
-		return( -ENODEV );
-
-	} /* endif */
-
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "doIO%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	if (!ioinfo[irq]->ui.flags.ready || ioinfo[irq]->ui.flags.unready) {
+		return (-ENODEV);
+
 	}
 
+	sprintf (dbf_txt, "doIO%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
 	/*
 	 * Note: We ignore the device operational status - if not operational,
 	 *        the SSCH will lead to an -ENODEV condition ...
 	 */
-	if ( !ioinfo[irq]->ui.flags.busy )         /* last I/O completed ? */
-	{
-		ret = s390_start_IO( irq, cpa, user_intparm, lpm, flag);
-	}
-	else if ( ioinfo[irq]->ui.flags.fast )
-	{
+	if (!ioinfo[irq]->ui.flags.busy) {	/* last I/O completed ? */
+		ret = s390_start_IO (irq, cpa, user_intparm, lpm, flag);
+		if ((ret == -ETIMEDOUT) && (flag & DOIO_CANCEL_ON_TIMEOUT)) {
+			/*
+			 * We should better cancel the io request here
+			 * or we might not be able to do io on this sch
+			 * again
+			 */
+			cancel_IO (irq);
+		}
+
+	} else if (ioinfo[irq]->ui.flags.fast) {
 		/*
 		 * If primary status was received and ending status is missing,
 		 *  the device driver won't be notified on the ending status
@@ -1788,92 +1933,81 @@
 		 *  needs to be issued and the queued request must be deleted
 		 *  but its intparm must be returned (see halt_IO() processing)
 		 */
-		if (     ioinfo[irq]->ui.flags.w4final
-		      && !ioinfo[irq]->ui.flags.doio_q )
-		{
-			ioinfo[irq]->qflag    = flag;
-			ioinfo[irq]->qcpa     = cpa;
+		if (ioinfo[irq]->ui.flags.w4final
+		    && !ioinfo[irq]->ui.flags.doio_q) {
+			ioinfo[irq]->qflag = flag;
+			ioinfo[irq]->qcpa = cpa;
 			ioinfo[irq]->qintparm = user_intparm;
-			ioinfo[irq]->qlpm     = lpm;
-		}
-		else
-		{
+			ioinfo[irq]->qlpm = lpm;
+		} else {
 			ret = -EBUSY;
 
-		} /* endif */
-	}
-	else
-	{
+		}
+	} else {
 		ret = -EBUSY;
 
-	} /* endif */
+	}
 
-	return( ret );
+	return (ret);
 
 }
 
 /*
  * resume suspended I/O operation
  */
-int resume_IO( int irq)
+int
+resume_IO (int irq)
 {
 	int ret = 0;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "resIO%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "rsIO%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
 	/*
 	 * We allow for 'resume' requests only for active I/O operations
 	 */
-	if ( ioinfo[irq]->ui.flags.busy )
-	{
+	if (ioinfo[irq]->ui.flags.busy) {
 		int ccode;
 
-		ccode = rsch( irq);
+		ccode = rsch (irq);
 
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "ccode:%d",ccode);
-			debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-		}
+		sprintf (dbf_txt, "ccode:%d", ccode);
+		CIO_TRACE_EVENT (4, dbf_txt);
 
 		switch (ccode) {
-		case 0 :
+		case 0:
 			break;
 
-		case 1 :
-		  	s390_process_IRQ( irq );
+		case 1:
+			s390_process_IRQ (irq);
 			ret = -EBUSY;
 			break;
 
-		case 2 :
+		case 2:
 			ret = -EINVAL;
 			break;
 
-		case 3 :
+		case 3:
 			/*
 			 * useless to wait for request completion
 			 *  as device is no longer operational !
 			 */
 			ioinfo[irq]->ui.flags.oper = 0;
 			ioinfo[irq]->ui.flags.busy = 0;
-			ret                        = -ENODEV;
+			ret = -ENODEV;
 			break;
 
-		} /* endswitch */          	
-		
-	}
-	else
-	{
+		}
+
+	} else {
 		ret = -ENOTCONN;
 
-	} /* endif  */
+	}
 
-	return( ret);
+	return (ret);
 }
 
 /*
@@ -1882,247 +2016,218 @@
  *       it allows the device interrupt handler to associate the upcoming
  *       interrupt with the halt_IO() request.
  */
-int halt_IO( int           irq,
-             unsigned long user_intparm,
-             unsigned long flag)  /* possible DOIO_WAIT_FOR_INTERRUPT */
-{
-	int            ret;
-	int            ccode;
+int
+halt_IO (int irq, unsigned long user_intparm, unsigned long flag)
+{				/* possible DOIO_WAIT_FOR_INTERRUPT */
+	int ret;
+	int ccode;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
 	/*
 	 * we only allow for halt_IO if the device has an I/O handler associated
 	 */
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
-		ret = -ENODEV;
+	if (!ioinfo[irq]->ui.flags.ready) {
+		return -ENODEV;
 	}
 	/*
 	 * we ignore the halt_io() request if ending_status was received but
 	 *  a SENSE operation is waiting for completion.
 	 */
-	else if ( ioinfo[irq]->ui.flags.w4sense )
-	{
-		ret = 0;
+	if (ioinfo[irq]->ui.flags.w4sense) {
+		return 0;
 	}
-	else
-	{
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "haltIO%x", irq);
-			debug_text_event(cio_debug_trace_id, 2, dbf_txt);
-		}
-		/*
-		 * If sync processing was requested we lock the sync ISC,
-		 *  modify the device to present interrupts for this ISC only
-		 *  and switch the CPU to handle this ISC + the console ISC
-		 *  exclusively.
-		 */
-		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-		{
-			ret = enable_cpu_sync_isc( irq);
-
-			if ( ret )
-			{
-				return( ret);
-  	
-			} /* endif */
+	CIO_TRACE_EVENT (2, "haltIO");
+	sprintf (dbf_txt, "%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
 
-		} /* endif */
+	/*
+	 * If sync processing was requested we lock the sync ISC,
+	 *  modify the device to present interrupts for this ISC only
+	 *  and switch the CPU to handle this ISC + the console ISC
+	 *  exclusively.
+	 */
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+		ret = enable_cpu_sync_isc (irq);
 
-		/*
-		 * Issue "Halt subchannel" and process condition code
-		 */
-		ccode = hsch( irq );
+		if (ret)
+			return (ret);
+	}
 
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "ccode:%d",ccode);
-			debug_text_event(cio_debug_trace_id, 2, dbf_txt);
-		}		
+	/*
+	 * Issue "Halt subchannel" and process condition code
+	 */
+	ccode = hsch (irq);
 
-		switch ( ccode ) {
-		case 0:
+	sprintf (dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT (2, dbf_txt);
 
-			ioinfo[irq]->ui.flags.haltio = 1;
+	switch (ccode) {
+	case 0:
 
-			if ( !ioinfo[irq]->ui.flags.doio )
-			{
-				ioinfo[irq]->ui.flags.busy   = 1;
-				ioinfo[irq]->u_intparm       = user_intparm;
-				ioinfo[irq]->devstat.cstat   = 0;
-				ioinfo[irq]->devstat.dstat   = 0;
-				ioinfo[irq]->devstat.lpum    = 0;
-				ioinfo[irq]->devstat.flag    = DEVSTAT_HALT_FUNCTION;
-				ioinfo[irq]->devstat.scnt    = 0;
+		ioinfo[irq]->ui.flags.haltio = 1;
 
-			}
-			else
-			{
-				ioinfo[irq]->devstat.flag   |= DEVSTAT_HALT_FUNCTION;
+		if (!ioinfo[irq]->ui.flags.doio) {
+			ioinfo[irq]->ui.flags.busy = 1;
+			ioinfo[irq]->u_intparm = user_intparm;
+			ioinfo[irq]->devstat.cstat = 0;
+			ioinfo[irq]->devstat.dstat = 0;
+			ioinfo[irq]->devstat.lpum = 0;
+			ioinfo[irq]->devstat.flag = DEVSTAT_HALT_FUNCTION;
+			ioinfo[irq]->devstat.scnt = 0;
 
-			} /* endif */
+		} else {
+			ioinfo[irq]->devstat.flag |= DEVSTAT_HALT_FUNCTION;
 
-			/*
-			 * If synchronous I/O processing is requested, we have
-			 *  to wait for the corresponding interrupt to occur by
-			 *  polling the interrupt condition. However, as multiple
-			 *  interrupts may be outstanding, we must not just wait
-			 *  for the first interrupt, but must poll until ours
-			 *  pops up.
-			 */
-			if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-			{
-				int              io_sub;
-				__u32            io_parm;
-				unsigned long    psw_mask;
-				int              ccode;
-  	
-				int              ready = 0;
-				struct _lowcore *lc    = NULL;
+		}
 
-				/*
-				 * We shouldn't perform a TPI loop, waiting for
-				 *  an interrupt to occur, but should load a
-				 *  WAIT PSW instead. Otherwise we may keep the
-				 *  channel subsystem busy, not able to present
-				 *  the interrupt. When our sync. interrupt
-				 *  arrived we reset the I/O old PSW to its
-				 *  original value.
-				 */
+		/*
+		 * If synchronous I/O processing is requested, we have
+		 *  to wait for the corresponding interrupt to occur by
+		 *  polling the interrupt condition. However, as multiple
+		 *  interrupts may be outstanding, we must not just wait
+		 *  for the first interrupt, but must poll until ours
+		 *  pops up.
+		 */
+		if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+			int io_sub;
+			__u32 io_parm;
+			unsigned long psw_mask;
+			int ccode;
 
-				ccode = iac();
+			int ready = 0;
 
-				switch (ccode) {
-				case 0:  		// primary-space
-					psw_mask = _IO_PSW_MASK
-						| _PSW_PRIM_SPACE_MODE
-						| _PSW_IO_WAIT;
-					break;
-				case 1:			// secondary-space
-					psw_mask = _IO_PSW_MASK
-						| _PSW_SEC_SPACE_MODE
-						| _PSW_IO_WAIT;
-					break;
-				case 2:			// access-register
-					psw_mask = _IO_PSW_MASK
-						| _PSW_ACC_REG_MODE
-						| _PSW_IO_WAIT;
-					break;
-				case 3:			// home-space	
-					psw_mask = _IO_PSW_MASK
-						| _PSW_HOME_SPACE_MODE
-						| _PSW_IO_WAIT;
-					break;
-				default:
-					panic( "halt_IO() : unexpected "
-					       "address-space-control %d\n",
-					       ccode);
-					break;
-				} /* endswitch */
+			/*
+			 * We shouldn't perform a TPI loop, waiting for
+			 *  an interrupt to occur, but should load a
+			 *  WAIT PSW instead. Otherwise we may keep the
+			 *  channel subsystem busy, not able to present
+			 *  the interrupt. When our sync. interrupt
+			 *  arrived we reset the I/O old PSW to its
+			 *  original value.
+			 */
 
-				/*
-				 * Martin didn't like modifying the new PSW, now we take
-				 *  a fast exit in do_IRQ() instead
-				 */
-				*(__u32 *)__LC_SYNC_IO_WORD  = 1;
+			ccode = iac ();
 
-				do
-				{
+			switch (ccode) {
+			case 0:	/* primary-space */
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_PRIM_SPACE_MODE | _PSW_IO_WAIT;
+				break;
+			case 1:	/* secondary-space */
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_SEC_SPACE_MODE | _PSW_IO_WAIT;
+				break;
+			case 2:	/* access-register */
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_ACC_REG_MODE | _PSW_IO_WAIT;
+				break;
+			case 3:	/* home-space */
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_HOME_SPACE_MODE | _PSW_IO_WAIT;
+				break;
+			default:
+				panic ("halt_IO() : unexpected "
+				       "address-space-control %d\n", ccode);
+				break;
+			}
 
-					__load_psw_mask( psw_mask );
+			/*
+			 * Martin didn't like modifying the new PSW, now we take
+			 *  a fast exit in do_IRQ() instead
+			 */
+			*(__u32 *) __LC_SYNC_IO_WORD = 1;
 
-				   io_parm = *(__u32 *)__LC_IO_INT_PARM;
-				   io_sub  = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
+			do {
+				__load_psw_mask (psw_mask);
 
-				   ready = s390_process_IRQ( io_sub );
+				io_parm = *(__u32 *) __LC_IO_INT_PARM;
+				io_sub = (__u32) * (__u16 *) __LC_SUBCHANNEL_NR;
 
-				} while ( !((io_sub == irq) && (ready == 1)) );
+				ready = s390_process_IRQ (io_sub);
 
-				*(__u32 *)__LC_SYNC_IO_WORD = 0;
+			} while (!((io_sub == irq) && (ready == 1)));
 
-			} /* endif */
+			*(__u32 *) __LC_SYNC_IO_WORD = 0;
 
-			ret = 0;
-			break;
+		}
 
-		case 1 :            /* status pending */
-	
-			ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
+		ret = 0;
+		break;
 
-			/*
-			 * initialize the device driver specific devstat irb area
-			 */
-			memset( &ioinfo[irq]->irq_desc.dev_id->ii.irb,
-			        '\0', sizeof( irb_t) );
+	case 1:		/* status pending */
 
-			/*
-			 * Let the common interrupt handler process the pending
-			 *  status. However, we must avoid calling the user
-			 *  action handler, as it won't be prepared to handle
-			 *  a pending status during do_IO() processing inline.
-			 *  This also implies that s390_process_IRQ must
-			 *  terminate synchronously - especially if device
-			 *  sensing is required.
-			 */
-			ioinfo[irq]->ui.flags.s_pend   = 1;
-			ioinfo[irq]->ui.flags.busy     = 1;
-			ioinfo[irq]->ui.flags.doio     = 1;
+		ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
 
-			s390_process_IRQ( irq );
-			
-			ioinfo[irq]->ui.flags.s_pend   = 0;
-			ioinfo[irq]->ui.flags.busy     = 0;
-			ioinfo[irq]->ui.flags.doio     = 0;
-			ioinfo[irq]->ui.flags.repall   = 0;
-			ioinfo[irq]->ui.flags.w4final  = 0;
+		/*
+		 * initialize the device driver specific devstat irb area
+		 */
+		memset (&ioinfo[irq]->irq_desc.dev_id->ii.irb,
+			'\0', sizeof (irb_t));
 
-			ioinfo[irq]->devstat.flag     |= DEVSTAT_FINAL_STATUS;
+		/*
+		 * Let the common interrupt handler process the pending
+		 *  status. However, we must avoid calling the user
+		 *  action handler, as it won't be prepared to handle
+		 *  a pending status during do_IO() processing inline.
+		 *  This also implies that s390_process_IRQ must
+		 *  terminate synchronously - especially if device
+		 *  sensing is required.
+		 */
+		ioinfo[irq]->ui.flags.s_pend = 1;
+		ioinfo[irq]->ui.flags.busy = 1;
+		ioinfo[irq]->ui.flags.doio = 1;
+
+		s390_process_IRQ (irq);
+
+		ioinfo[irq]->ui.flags.s_pend = 0;
+		ioinfo[irq]->ui.flags.busy = 0;
+		ioinfo[irq]->ui.flags.doio = 0;
+		ioinfo[irq]->ui.flags.repall = 0;
+		ioinfo[irq]->ui.flags.w4final = 0;
 
-			/*
-			 * In multipath mode a condition code 3 implies the last
-			 *  path has gone, except we have previously restricted
-			 *  the I/O to a particular path. A condition code 1
-			 *  (0 won't occur) results in return code EIO as well
-			 *  as 3 with another path than the one used (i.e. path available mask is non-zero).
-			 */
-			if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
-			{
-				ret                         = -ENODEV;
-				ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;
-				ioinfo[irq]->ui.flags.oper  = 0;
-			}
-			else
-			{
-				ret                         = -EIO;
-				ioinfo[irq]->devstat.flag  &= ~DEVSTAT_NOT_OPER;
-				ioinfo[irq]->ui.flags.oper  = 1;
+		ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
 
-			} /* endif */
+		/*
+		 * In multipath mode a condition code 3 implies the last
+		 *  path has gone, except we have previously restricted
+		 *  the I/O to a particular path. A condition code 1
+		 *  (0 won't occur) results in return code EIO as well
+		 *  as 3 with another path than the one used (i.e. path 
+		 *  available mask is non-zero).
+		 */
+		if (ioinfo[irq]->devstat.ii.irb.scsw.cc == 3) {
+			ret = -ENODEV;
+			ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
+			ioinfo[irq]->ui.flags.oper = 0;
+		} else {
+			ret = -EIO;
+			ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
+			ioinfo[irq]->ui.flags.oper = 1;
 
-			break;
+		}
 
-		case 2 :            /* busy */
+		break;
 
-			ret = -EBUSY;
-			break;
+	case 2:		/* busy */
 
-		default:            /* device not operational */
+		ret = -EBUSY;
+		break;
 
-			ret = -ENODEV;
-			break;
+	default:		/* device not operational */
 
-		} /* endswitch */
+		ret = -ENODEV;
+		break;
 
-		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-		{
-			disable_cpu_sync_isc( irq );
+	}
 
-		} /* endif */
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+		disable_cpu_sync_isc (irq);
 
-	} /* endif */
+	}
 
-	return( ret );
+	return (ret);
 }
 
 /*
@@ -2131,201 +2236,220 @@
  *       it allows the device interrupt handler to associate the upcoming
  *       interrupt with the clear_IO() request.
  */
-int clear_IO( int           irq,
-              unsigned long user_intparm,
-              unsigned long flag)  /* possible DOIO_WAIT_FOR_INTERRUPT */
-{
-	int            ret = 0;
-	int            ccode;
+int
+clear_IO (int irq, unsigned long user_intparm, unsigned long flag)
+{				/* possible DOIO_WAIT_FOR_INTERRUPT */
+	int ret = 0;
+	int ccode;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
-		return( -ENODEV);
-   }
+	if (ioinfo[irq] == INVALID_STORAGE_AREA)
+		return (-ENODEV);
 
 	/*
 	 * we only allow for clear_IO if the device has an I/O handler associated
 	 */
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
-		ret = -ENODEV;
-	}
+	if (!ioinfo[irq]->ui.flags.ready)
+		return -ENODEV;
 	/*
 	 * we ignore the clear_io() request if ending_status was received but
 	 *  a SENSE operation is waiting for completion.
 	 */
-	else if ( ioinfo[irq]->ui.flags.w4sense )
-	{
-		ret = 0;
-	}
-	else
-	{
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "clearIO%x", irq);
-			debug_text_event(cio_debug_trace_id, 2, dbf_txt);
-		}
-		/*
-		 * If sync processing was requested we lock the sync ISC,
-		 *  modify the device to present interrupts for this ISC only
-		 *  and switch the CPU to handle this ISC + the console ISC
-		 *  exclusively.
-		 */
-		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-		{
-			ret = enable_cpu_sync_isc( irq);
+	if (ioinfo[irq]->ui.flags.w4sense)
+		return 0;
 
-			if ( ret )
-			{
-				return( ret);
-  	
-			} /* endif */
+	CIO_TRACE_EVENT (2, "clearIO");
+	sprintf (dbf_txt, "%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
 
-		} /* endif */
+	/*
+	 * If sync processing was requested we lock the sync ISC,
+	 *  modify the device to present interrupts for this ISC only
+	 *  and switch the CPU to handle this ISC + the console ISC
+	 *  exclusively.
+	 */
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+		ret = enable_cpu_sync_isc (irq);
 
-		/*
-		 * Issue "Clear subchannel" and process condition code
-		 */
-		ccode = csch( irq );
+		if (ret)
+			return (ret);
+	}
 
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "ccode:%d",ccode);
-			debug_text_event(cio_debug_trace_id, 2, dbf_txt);
-		}
+	/*
+	 * Issue "Clear subchannel" and process condition code
+	 */
+	ccode = csch (irq);
 
-		switch ( ccode ) {
-		case 0:
+	sprintf (dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT (2, dbf_txt);
 
-			ioinfo[irq]->ui.flags.haltio = 1;
+	switch (ccode) {
+	case 0:
 
-			if ( !ioinfo[irq]->ui.flags.doio )
-			{
-				ioinfo[irq]->ui.flags.busy   = 1;
-				ioinfo[irq]->u_intparm       = user_intparm;
-				ioinfo[irq]->devstat.cstat   = 0;
-				ioinfo[irq]->devstat.dstat   = 0;
-				ioinfo[irq]->devstat.lpum    = 0;
-				ioinfo[irq]->devstat.flag    = DEVSTAT_CLEAR_FUNCTION;
-				ioinfo[irq]->devstat.scnt    = 0;
+		ioinfo[irq]->ui.flags.haltio = 1;
 
-			}
-			else
-			{
-				ioinfo[irq]->devstat.flag   |= DEVSTAT_CLEAR_FUNCTION;
+		if (!ioinfo[irq]->ui.flags.doio) {
+			ioinfo[irq]->ui.flags.busy = 1;
+			ioinfo[irq]->u_intparm = user_intparm;
+			ioinfo[irq]->devstat.cstat = 0;
+			ioinfo[irq]->devstat.dstat = 0;
+			ioinfo[irq]->devstat.lpum = 0;
+			ioinfo[irq]->devstat.flag = DEVSTAT_CLEAR_FUNCTION;
+			ioinfo[irq]->devstat.scnt = 0;
+
+		} else {
+			ioinfo[irq]->devstat.flag |= DEVSTAT_CLEAR_FUNCTION;
+
+		}
+
+		/*
+		 * If synchronous I/O processing is requested, we have
+		 *  to wait for the corresponding interrupt to occur by
+		 *  polling the interrupt condition. However, as multiple
+		 *  interrupts may be outstanding, we must not just wait
+		 *  for the first interrupt, but must poll until ours
+		 *  pops up.
+		 */
+		if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+			int io_sub;
+			__u32 io_parm;
+			unsigned long psw_mask;
+			int ccode;
 
-			} /* endif */
+			int ready = 0;
 
 			/*
-			 * If synchronous I/O processing is requested, we have
-			 *  to wait for the corresponding interrupt to occur by
-			 *  polling the interrupt condition. However, as multiple
-			 *  interrupts may be outstanding, we must not just wait
-			 *  for the first interrupt, but must poll until ours
-			 *  pops up.
+			 * We shouldn't perform a TPI loop, waiting for
+			 *  an interrupt to occur, but should load a
+			 *  WAIT PSW instead. Otherwise we may keep the
+			 *  channel subsystem busy, not able to present
+			 *  the interrupt. When our sync. interrupt
+			 *  arrived we reset the I/O old PSW to its
+			 *  original value.
 			 */
-			if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-			{
-				int              io_sub;
-				__u32            io_parm;
-				unsigned long    psw_mask;
-				int              ccode;
-  	
-				int              ready = 0;
-				struct _lowcore *lc    = NULL;
 
-				/*
-				 * We shouldn't perform a TPI loop, waiting for
-				 *  an interrupt to occur, but should load a
-				 *  WAIT PSW instead. Otherwise we may keep the
-				 *  channel subsystem busy, not able to present
-				 *  the interrupt. When our sync. interrupt
-				 *  arrived we reset the I/O old PSW to its
-				 *  original value.
-				 */
+			ccode = iac ();
+
+			switch (ccode) {
+			case 0:	/* primary-space */
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_PRIM_SPACE_MODE | _PSW_IO_WAIT;
+				break;
+			case 1:	/* secondary-space */
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_SEC_SPACE_MODE | _PSW_IO_WAIT;
+				break;
+			case 2:	/* access-register */
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_ACC_REG_MODE | _PSW_IO_WAIT;
+				break;
+			case 3:	/* home-space */
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_HOME_SPACE_MODE | _PSW_IO_WAIT;
+				break;
+			default:
+				panic ("clear_IO() : unexpected "
+				       "address-space-control %d\n", ccode);
+				break;
+			}
 
-				ccode = iac();
+			/*
+			 * Martin didn't like modifying the new PSW, now we take
+			 *  a fast exit in do_IRQ() instead
+			 */
+			*(__u32 *) __LC_SYNC_IO_WORD = 1;
 
-				switch (ccode) {
-				case 0:  		// primary-space
-					psw_mask = _IO_PSW_MASK
-						| _PSW_PRIM_SPACE_MODE
-						| _PSW_IO_WAIT;
-					break;
-				case 1:			// secondary-space
-					psw_mask = _IO_PSW_MASK
-						| _PSW_SEC_SPACE_MODE
-						| _PSW_IO_WAIT;
-					break;
-				case 2:			// access-register
-					psw_mask = _IO_PSW_MASK
-						| _PSW_ACC_REG_MODE
-						| _PSW_IO_WAIT;
-					break;
-				case 3:			// home-space	
-					psw_mask =   _IO_PSW_MASK
-					        | _PSW_HOME_SPACE_MODE
-					        | _PSW_IO_WAIT;
-					break;
-				default:
-					panic( "clear_IO() : unexpected "
-					       "address-space-control %d\n",
-					       ccode);
-					break;
-				} /* endswitch */
+			do {
+				__load_psw_mask (psw_mask);
 
-				/*
-				 * Martin didn't like modifying the new PSW, now we take
-				 *  a fast exit in do_IRQ() instead
-				 */
-				*(__u32 *)__LC_SYNC_IO_WORD  = 1;
+				io_parm = *(__u32 *) __LC_IO_INT_PARM;
+				io_sub = (__u32) * (__u16 *) __LC_SUBCHANNEL_NR;
 
-				do
-				{
-					__load_psw_mask( psw_mask );
+				ready = s390_process_IRQ (io_sub);
 
-				   io_parm = *(__u32 *)__LC_IO_INT_PARM;
-				   io_sub  = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
+			} while (!((io_sub == irq) && (ready == 1)));
 
-				   ready = s390_process_IRQ( io_sub );
+			*(__u32 *) __LC_SYNC_IO_WORD = 0;
 
-				} while ( !((io_sub == irq) && (ready == 1)) );
+		}
 
-				*(__u32 *)__LC_SYNC_IO_WORD = 0;
+		ret = 0;
+		break;
 
-			} /* endif */
+	case 1:		/* no status pending for csh */
+		BUG ();
+		break;
 
-			ret = 0;
-			break;
+	case 2:		/* no busy for csh */
+		BUG ();
+		break;
 
-		case 1 :            /* no status pending for csh */
-			BUG();
-			break;
+	default:		/* device not operational */
 
+		ret = -ENODEV;
+		break;
 
-		case 2 :            /* no busy for csh*/
-			BUG();
-			break;
+	}
 
-		default:            /* device not operational */
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+		disable_cpu_sync_isc (irq);
 
-			ret = -ENODEV;
-			break;
+	}
 
-		} /* endswitch */
+	return (ret);
+}
 
-		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-		{
-			disable_cpu_sync_isc( irq );
+/*
+ * Function: cancel_IO
+ * Issues a "Cancel Subchannel" on the specified subchannel
+ * Note: We don't need any fancy intparms and flags here
+ *       since xsch is executed synchronously.
+ * Only for common I/O internal use as for now.
+ */
+int
+cancel_IO (int irq)
+{
 
-		} /* endif */
+	int ccode;
+	char dbf_txt[15];
+	int ret = 0;
 
-	} /* endif */
+	SANITY_CHECK (irq);
 
-	return( ret );
-}
+	CIO_TRACE_EVENT (2, "cancelIO");
+	sprintf (dbf_txt, "%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	ccode = xsch (irq);
+
+	sprintf (dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	switch (ccode) {
+
+	case 0:		/* success */
+		ret = 0;
+		break;
+
+	case 1:		/* status pending */
+
+		/* process the pending irq... */
+		s390_process_IRQ (irq);
+		ret = -EBUSY;
+		break;
+
+	case 2:		/* not applicable */
+		ret = -EINVAL;
+		break;
+
+	default:		/* not oper */
+		ret = -ENODEV;
+	}
 
+	return ret;
+}
 
 /*
  * do_IRQ() handles all normal I/O device IRQ's (the special
@@ -2333,13 +2457,14 @@
  *          handlers).
  *
  */
-asmlinkage void do_IRQ( struct pt_regs regs )
+asmlinkage void
+do_IRQ (struct pt_regs regs)
 {
 	/*
 	 * Get interrupt info from lowcore
 	 */
-	volatile tpi_info_t *tpi_info = (tpi_info_t*)(__LC_SUBCHANNEL_ID);
-	int cpu = smp_processor_id();
+	volatile tpi_info_t *tpi_info = (tpi_info_t *) (__LC_SUBCHANNEL_ID);
+	int cpu = smp_processor_id ();
 
 	/*
 	 * take fast exit if CPU is in sync. I/O state
@@ -2348,30 +2473,26 @@
 	 *       interrupts prior to return as this was the initial
 	 *       entry condition to synchronous I/O.
 	 */
- 	if (    *(__u32 *)__LC_SYNC_IO_WORD )
-	{
+	if (*(__u32 *) __LC_SYNC_IO_WORD) {
 		regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT);
 		return;
-	} /* endif */
-
+	}
+	/* endif */
 #ifdef CONFIG_FAST_IRQ
 	do {
-#endif /*  CONFIG_FAST_IRQ */
-		
+#endif				/* CONFIG_FAST_IRQ */
+
 		/*
 		 * Non I/O-subchannel thin interrupts are processed differently
 		 */
-		if ( tpi_info->adapter_IO == 1 &&
-		     tpi_info->int_type == IO_INTERRUPT_TYPE )
-		{
-			irq_enter(cpu, -1);
-			do_adapter_IO( tpi_info->intparm );
-			irq_exit(cpu, -1);
-		} 
-		else 
-		{
+		if (tpi_info->adapter_IO == 1 &&
+		    tpi_info->int_type == IO_INTERRUPT_TYPE) {
+			irq_enter (cpu, -1);
+			do_adapter_IO (tpi_info->intparm);
+			irq_exit (cpu, -1);
+		} else {
 			unsigned int irq = tpi_info->irq;
-	
+
 			/*
 			 * fix me !!!
 			 *
@@ -2379,16 +2500,22 @@
 			 * recognition, the interrupt stays pending. We need to
 			 * dynamically allocate an ioinfo structure, etc..
 			 */
-			if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-			{
+			if (ioinfo[irq] == INVALID_STORAGE_AREA) {
 				return;	/* this keeps the device boxed ... */
 			}
-	
-			irq_enter(cpu, irq);
-			s390irq_spin_lock( irq );
-			s390_process_IRQ( irq );
-			s390irq_spin_unlock( irq );
-			irq_exit(cpu, irq);
+
+			if (ioinfo[irq]->st) {
+				/* How can that be? */
+				printk(KERN_WARNING "Received interrupt on "
+				       "non-IO subchannel %x!\n", irq);
+				return;
+			}
+
+			irq_enter (cpu, irq);
+			s390irq_spin_lock (irq);
+			s390_process_IRQ (irq);
+			s390irq_spin_unlock (irq);
+			irq_exit (cpu, irq);
 		}
 
 #ifdef CONFIG_FAST_IRQ
@@ -2398,14 +2525,13 @@
 		 * If so, the tpi instruction will update the lowcore 
 		 * to hold the info for the next interrupt.
 		 */
-	} while ( tpi( NULL ) != 0 );
+	} while (tpi (NULL) != 0);
 
-#endif /*  CONFIG_FAST_IRQ */
+#endif				/* CONFIG_FAST_IRQ */
 
 	return;
 }
 
-
 /*
  * s390_process_IRQ() handles status pending situations and interrupts
  *
@@ -2417,48 +2543,58 @@
  * Returns: 0 - no ending status received, no further action taken
  *          1 - interrupt handler was called with ending status
  */
-int s390_process_IRQ( unsigned int irq )
+int
+s390_process_IRQ (unsigned int irq)
 {
-	int                    ccode;      /* cond code from tsch() operation */
-	int                    irb_cc;     /* cond code from irb */
-	int                    sdevstat;   /* struct devstat size to copy */
-	unsigned int           fctl;       /* function control */
-	unsigned int           stctl;      /* status   control */
-	unsigned int           actl;       /* activity control */
-
-	int               issense         = 0;
-	int               ending_status   = 0;
-	int               allow4handler   = 1;
-	int               chnchk          = 0;
-	devstat_t        *dp;
-	devstat_t        *udp;
+	int ccode;		/* cond code from tsch() operation */
+	int irb_cc;		/* cond code from irb */
+	int sdevstat;		/* struct devstat size to copy */
+	unsigned int fctl;	/* function control */
+	unsigned int stctl;	/* status   control */
+	unsigned int actl;	/* activity control */
+
+	int issense = 0;
+	int ending_status = 0;
+	int allow4handler = 1;
+	int chnchk = 0;
+	devstat_t *dp;
+	devstat_t *udp;
 
 	char dbf_txt[15];
-	char buffer[80];
-
+	char buffer[256];
 
 	if (cio_count_irqs) {
-		int cpu = smp_processor_id();
+		int cpu = smp_processor_id ();
 		s390_irq_count[cpu]++;
 	}
-	
-	
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "procIRQ%x", irq);
-		debug_text_event(cio_debug_trace_id, 3, dbf_txt);
-	}
 
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
+	CIO_TRACE_EVENT (3, "procIRQ");
+	sprintf (dbf_txt, "%x", irq);
+	CIO_TRACE_EVENT (3, dbf_txt);
+
+	if (ioinfo[irq] == INVALID_STORAGE_AREA) {
 		/* we can't properly process the interrupt ... */
-		tsch( irq, p_init_irb );
-		return( 1 );
+#ifdef CONFIG_DEBUG_IO
+		printk (KERN_CRIT "s390_process_IRQ(%04X) - got interrupt "
+			"for non-initialized subchannel!\n", irq);
+#endif /* CONFIG_DEBUG_IO */
+		CIO_MSG_EVENT (0,
+			       "s390_process_IRQ(%04X) - got interrupt "
+			       "for non-initialized subchannel!\n",
+			       irq);
+		tsch (irq, p_init_irb);
+		return (1);
+
+	}
 
-	} /* endif */
+	if (ioinfo[irq]->st) {
+		/* can't be */
+		BUG();
+		return 1;
+	}
 
-	dp  = &ioinfo[irq]->devstat;
+	dp = &ioinfo[irq]->devstat;
 	udp = ioinfo[irq]->irq_desc.dev_id;
-	
 
 	/*
 	 * It might be possible that a device was not-oper. at the time
@@ -2466,24 +2602,23 @@
 	 *  available when the device possibly becomes ready again. In
 	 *  this case we perform delayed disable_subchannel() processing.
 	 */
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
-		if ( !ioinfo[irq]->ui.flags.d_disable )
-		{
+	if (!ioinfo[irq]->ui.flags.ready) {
+		if (!ioinfo[irq]->ui.flags.d_disable) {
 #ifdef CONFIG_DEBUG_IO
-			printk( KERN_CRIT"s390_process_IRQ(%04X) "
-			        "- no interrupt handler registered "
-					  "for device %04X !\n",
-			        irq,
-			        ioinfo[irq]->devstat.devno);
-#endif /* CONFIG_DEBUG_IO */
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_msg_id, 0,
-						    "s390_process_IRQ(%04X) - no interrupt handler registered for device %04X !\n",
-						    irq, ioinfo[irq]->devstat.devno);
-		} /* endif */
-
-	} /* endif */
+			printk (KERN_CRIT "s390_process_IRQ(%04X) "
+				"- no interrupt handler registered "
+				"for device %04X !\n",
+				irq, ioinfo[irq]->devstat.devno);
+#endif				/* CONFIG_DEBUG_IO */
+			CIO_MSG_EVENT(0,
+				      "s390_process_IRQ(%04X) "
+				      "- no interrupt handler "
+				      "registered for device "
+				      "%04X !\n",
+				      irq,
+				      ioinfo[irq]->devstat.devno);
+		}
+	}
 
 	/*
 	 * retrieve the i/o interrupt information (irb),
@@ -2503,204 +2638,194 @@
 	 *         issued for an idle device, the intparm must not
 	 *         be taken from lowcore, but from the devstat area.
 	 */
-	ccode = tsch( irq, &(dp->ii.irb) );
+	ccode = tsch (irq, &(dp->ii.irb));
+
+	sprintf (dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT (3, dbf_txt);
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "ccode:%d", ccode);
-		debug_text_event(cio_debug_trace_id, 3, dbf_txt);
+	if (ccode == 1) {
+#ifdef CONFIG_DEBUG_IO
+		printk (KERN_INFO "s390_process_IRQ(%04X) - no status "
+			 "pending...\n", irq);
+#endif /* CONFIG_DEBUG_IO */
+		CIO_MSG_EVENT(2,
+			      "s390_process_IRQ(%04X) - no status pending\n",
+			      irq);
+	} else if (ccode == 3) {
+#ifdef CONFIG_DEBUG_IO
+		printk (KERN_WARNING "s390_process_IRQ(%04X) - subchannel "
+			"is not operational!\n",
+			irq);
+#endif /* CONFIG_DEBUG_IO */
+		CIO_MSG_EVENT(0,
+			      "s390_process_IRQ(%04X) - subchannel "
+			      "is not operational!\n",
+			      irq);
 	}
 
-	//
-	// We must only accumulate the status if the device is busy already
-	//
-	if ( ioinfo[irq]->ui.flags.busy )
-	{
-		dp->dstat   |= dp->ii.irb.scsw.dstat;
-		dp->cstat   |= dp->ii.irb.scsw.cstat;
-                dp->intparm  = ioinfo[irq]->u_intparm;
+	/*
+	 * We must only accumulate the status if the device is busy already
+	 */
+	if (ioinfo[irq]->ui.flags.busy) {
+		dp->dstat |= dp->ii.irb.scsw.dstat;
+		dp->cstat |= dp->ii.irb.scsw.cstat;
+		dp->intparm = ioinfo[irq]->u_intparm;
 
-	}
-	else
-	{
-		dp->dstat    = dp->ii.irb.scsw.dstat;
-		dp->cstat    = dp->ii.irb.scsw.cstat;
+	} else {
+		dp->dstat = dp->ii.irb.scsw.dstat;
+		dp->cstat = dp->ii.irb.scsw.cstat;
 
-		dp->flag     = 0;   // reset status flags
-		dp->intparm  = 0;
+		dp->flag = 0;	/* reset status flags */
+		dp->intparm = 0;
 
-	} /* endif */
+	}
 
 	dp->lpum = dp->ii.irb.esw.esw1.lpum;
 
 	/*
 	 * reset device-busy bit if no longer set in irb
 	 */
-	if (    (dp->dstat & DEV_STAT_BUSY                   ) 
-	     && ((dp->ii.irb.scsw.dstat & DEV_STAT_BUSY) == 0))
-	{
+	if ((dp->dstat & DEV_STAT_BUSY)
+	    && ((dp->ii.irb.scsw.dstat & DEV_STAT_BUSY) == 0)) {
 		dp->dstat &= ~DEV_STAT_BUSY;
 
-	} /* endif */
+	}
 
 	/*
-	 * Save residual count and CCW information in case primary and
-	 *  secondary status are presented with different interrupts.
+	   * Save residual count and CCW information in case primary and
+	   *  secondary status are presented with different interrupts.
 	 */
-	if ( dp->ii.irb.scsw.stctl
-	     & ( SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_INTER_STATUS ) ) {
+	if (dp->ii.irb.scsw.stctl
+	    & (SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_INTER_STATUS)) {
 
 		/*
 		 * If the subchannel status shows status pending
 		 * and we received a check condition, the count
 		 * information is not meaningful.
 		 */
-		
-		 if ( !(    (dp->ii.irb.scsw.stctl & SCSW_STCTL_STATUS_PEND) 
-			 && (   dp->ii.irb.scsw.cstat 
-			      & (   SCHN_STAT_CHN_DATA_CHK
-				  | SCHN_STAT_CHN_CTRL_CHK
-				  | SCHN_STAT_INTF_CTRL_CHK
-				  | SCHN_STAT_PROG_CHECK
-				  | SCHN_STAT_PROT_CHECK
-				  | SCHN_STAT_CHAIN_CHECK )))) {
-
-			 dp->rescnt = dp->ii.irb.scsw.count;
-		 } else {
-			 dp->rescnt = SENSE_MAX_COUNT;
-		 }
 
-		dp->cpa    = dp->ii.irb.scsw.cpa;
+		if (!((dp->ii.irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)
+		      && (dp->ii.irb.scsw.cstat
+			  & (SCHN_STAT_CHN_DATA_CHK
+			     | SCHN_STAT_CHN_CTRL_CHK
+			     | SCHN_STAT_INTF_CTRL_CHK
+			     | SCHN_STAT_PROG_CHECK
+			     | SCHN_STAT_PROT_CHECK
+			     | SCHN_STAT_CHAIN_CHECK)))) {
 
-#ifdef CONFIG_DEBUG_IO
-		if ( irq != cons_dev )
-			printk( KERN_DEBUG "s390_process_IRQ( %04X ) : "
-			        "residual count from irb after tsch() %d\n",
-			        irq, dp->rescnt );
-#endif
-		if (cio_debug_initialized)
-			debug_sprintf_event(cio_debug_msg_id, 6,
-					    "s390_process_IRQ( %04X ) : residual count from irq after tsch() %d\n",
-					    irq, dp->rescnt);
+			dp->rescnt = dp->ii.irb.scsw.count;
+		} else {
+			dp->rescnt = SENSE_MAX_COUNT;
+		}
 
-	} /* endif */
+		dp->cpa = dp->ii.irb.scsw.cpa;
 
+	}
 	irb_cc = dp->ii.irb.scsw.cc;
 
-	//
-	// check for any kind of channel or interface control check but don't
-	//  issue the message for the console device
-	//
-	if (    (dp->ii.irb.scsw.cstat
-	            & (  SCHN_STAT_CHN_DATA_CHK
-	               | SCHN_STAT_CHN_CTRL_CHK
-			 | SCHN_STAT_INTF_CTRL_CHK )))
-	{
+	/*
+	 * check for any kind of channel or interface control check but don't
+	 * issue the message for the console device
+	 */
+	if ((dp->ii.irb.scsw.cstat
+	     & (SCHN_STAT_CHN_DATA_CHK
+		| SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK))) {
 		if (irq != cons_dev)
-			printk( KERN_WARNING "Channel-Check or Interface-Control-Check "
+			printk (KERN_WARNING
+				"Channel-Check or Interface-Control-Check "
 				"received\n"
 				" ... device %04X on subchannel %04X, dev_stat "
 				": %02X sch_stat : %02X\n",
-				ioinfo[irq]->devstat.devno,
-				irq,
-				dp->dstat,
+				ioinfo[irq]->devstat.devno, irq, dp->dstat,
 				dp->cstat);
-		if (cio_debug_initialized) {
-			debug_sprintf_event(cio_debug_msg_id, 0,
-					    "Channel-Check or Interface-Control-Check received\n");
-			debug_sprintf_event(cio_debug_msg_id, 0,
-					    "... device %04X on subchannel %04X, dev_stat: %02X sch_stat: %02X\n",
-					    ioinfo[irq]->devstat.devno, irq, dp->dstat, dp->cstat);
-		}
+		CIO_MSG_EVENT(0,
+			      "Channel-Check or "
+			      "Interface-Control-Check received\n");
+		CIO_MSG_EVENT(0,
+			      "... device %04X on subchannel %04X,"
+			      " dev_stat: %02X sch_stat: %02X\n",
+			      ioinfo[irq]->devstat.devno, irq,
+			      dp->dstat, dp->cstat);
+	
 
 		chnchk = 1;
 
-	} /* endif */
+	}
 
-	if( dp->ii.irb.scsw.ectl==0)
-	{
-		issense=0;
-	}
-	else if (    (dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND)
-	          && (dp->ii.irb.scsw.eswf  == 0                     ))
-	{
+	if (dp->ii.irb.scsw.ectl == 0) {
 		issense = 0;
-	}
-	else if (   (dp->ii.irb.scsw.stctl ==
-		      (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_INTER_STATUS)) 
-		 && ((dp->ii.irb.scsw.actl & SCSW_ACTL_SUSPENDED) == 0)  )
-	{
+	} else if ((dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND)
+		   && (dp->ii.irb.scsw.eswf == 0)) {
 		issense = 0;
-	}
-	else
-	{
+	} else if ((dp->ii.irb.scsw.stctl ==
+		    (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_INTER_STATUS))
+		   && ((dp->ii.irb.scsw.actl & SCSW_ACTL_SUSPENDED) == 0)) {
+		issense = 0;
+	} else {
 		issense = dp->ii.irb.esw.esw0.erw.cons;
 
-	} /* endif */
+	}
 
-	if ( issense )
-	{
-		dp->scnt  = dp->ii.irb.esw.esw0.erw.scnt;
+	if (issense) {
+		dp->scnt = dp->ii.irb.esw.esw0.erw.scnt;
 		dp->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
-                  	
-		sdevstat = sizeof( devstat_t);
+
+		sdevstat = sizeof (devstat_t);
 
 #ifdef CONFIG_DEBUG_IO
-		if ( irq != cons_dev )
-			printk( KERN_DEBUG "s390_process_IRQ( %04X ) : "
-			        "concurrent sense bytes avail %d\n",
-			        irq, dp->scnt );
-#endif
-		if (cio_debug_initialized)
-			debug_sprintf_event(cio_debug_msg_id, 4,
-					    "s390_process_IRQ( %04X ): concurrent sense bytes avail %d\n",
-					    irq, dp->scnt);
-	}
-	else
-	{
+		if (irq != cons_dev)
+			printk (KERN_DEBUG "s390_process_IRQ( %04X ) : "
+				"concurrent sense bytes avail %d\n",
+				irq, dp->scnt);
+#endif
+		CIO_MSG_EVENT(4,
+			      "s390_process_IRQ( %04X ): "
+			      "concurrent sense bytes avail %d\n",
+			      irq, dp->scnt);
+	} else {
 		/* don't copy the sense data area ! */
-		sdevstat = sizeof( devstat_t) - SENSE_MAX_COUNT;
+		sdevstat = sizeof (devstat_t) - SENSE_MAX_COUNT;
 
-	} /* endif */
+	}
 
-	switch ( irb_cc ) {
-	case 1:      /* status pending */
+	switch (irb_cc) {
+	case 1:		/* status pending */
 
 		dp->flag |= DEVSTAT_STATUS_PENDING;
 
-	case 0:      /* normal i/o interruption */
+	case 0:		/* normal i/o interruption */
 
-		fctl  = dp->ii.irb.scsw.fctl;
+		fctl = dp->ii.irb.scsw.fctl;
 		stctl = dp->ii.irb.scsw.stctl;
-		actl  = dp->ii.irb.scsw.actl;
+		actl = dp->ii.irb.scsw.actl;
 
-		if ( chnchk )
-		{
-			sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
-			         "device %04X after channel check\n",
-			         irq,
-			         dp->devno );
-
-			s390_displayhex( buffer,
-			                 &(dp->ii.irb) ,
-			                 sizeof(irb_t));
+		if (chnchk) {
+			sprintf (buffer, "s390_process_IRQ(%04X) - irb for "
+				 "device %04X after channel check "
+				 "or interface control check\n",
+				 irq, dp->devno);
+
+			s390_displayhex (buffer, &(dp->ii.irb), sizeof (irb_t));
 			if (cio_debug_initialized) {
-				
-				sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
-			         "device %04X after channel check\n",
-			         irq,
-			         dp->devno );
-
-				s390_displayhex2( buffer,
-						  &(dp->ii.irb) ,
-						  sizeof(irb_t), 0);
+
+				sprintf (buffer,
+					 "s390_process_IRQ(%04X) - irb for "
+					 "device %04X after channel check "
+					 "or interface control check\n",
+					 irq, dp->devno);
+
+				s390_displayhex2 (buffer,
+						  &(dp->ii.irb),
+						  sizeof (irb_t), 0);
 			}
-		} /* endif */
-			
+		}
+
 		ioinfo[irq]->stctl |= stctl;
 
-		ending_status =    ( stctl & SCSW_STCTL_SEC_STATUS )
-			        || ( stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND) )
-			        || ( stctl == SCSW_STCTL_STATUS_PEND);
+		ending_status = (stctl & SCSW_STCTL_SEC_STATUS)
+		    || (stctl ==
+			(SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))
+		    || (stctl == SCSW_STCTL_STATUS_PEND);
 
 		/*
 		 * Check for unsolicited interrupts - for debug purposes only
@@ -2713,53 +2838,48 @@
 		 *       unsolicited interrupt applies to the console device
 		 *       itself !
 		 */
-		if (    !( stctl & SCSW_STCTL_ALERT_STATUS )
-		     &&  ( ioinfo[irq]->ui.flags.busy == 0 ) )
-		{
+		if (!(stctl & SCSW_STCTL_ALERT_STATUS)
+		    && (ioinfo[irq]->ui.flags.busy == 0)) {
 #ifdef CONFIG_DEBUG_IO
 			if (irq != cons_dev)
-				printk( KERN_INFO "Unsolicited interrupt received for device %04X on subchannel %04X\n"
-					" ... device status : %02X subchannel status : %02X\n",
-					dp->devno,
-					irq,
-					dp->dstat,
-					dp->cstat);
-			
-			sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
-			         "device %04X, ending_status %d\n",
-			         irq,
-			         dp->devno,
-			         ending_status);
-
-			s390_displayhex( buffer,
-			                 &(dp->ii.irb) ,
-			                 sizeof(irb_t));
-#endif
+				printk (KERN_INFO
+					"Unsolicited interrupt received for "
+					"device %04X on subchannel %04X\n"
+					" ... device status : %02X "
+					"subchannel status : %02X\n",
+					dp->devno, irq, dp->dstat, dp->cstat);
+
+			sprintf (buffer, "s390_process_IRQ(%04X) - irb for "
+				 "device %04X, ending_status %d\n",
+				 irq, dp->devno, ending_status);
+
+			s390_displayhex (buffer, &(dp->ii.irb), sizeof (irb_t));
+#endif
+			CIO_MSG_EVENT(2,
+				      "Unsolicited interrupt "
+				      "received for device %04X "
+				      "on subchannel %04X\n"
+				      " ... device status : %02X "
+				      "subchannel status : %02X\n",
+				      dp->devno,
+				      irq, dp->dstat, dp->cstat);
 			if (cio_debug_initialized) {
-				debug_sprintf_event(cio_debug_msg_id, 2, 
-						    "Unsolicited interrupt received for device %04X on subchannel %04X\n"
-						    " ... device status : %02X subchannel status : %02X\n",
-						    dp->devno,
-						    irq,
-						    dp->dstat,
-						    dp->cstat);
-				sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
-					 "device %04X, ending_status %d\n",
-					 irq,
-					 dp->devno,
-					 ending_status);
+				sprintf (buffer,
+					 "s390_process_IRQ(%04X) - irb for "
+					 "device %04X, ending_status %d\n", irq,
+					 dp->devno, ending_status);
 				
-				s390_displayhex2( buffer,
-						 &(dp->ii.irb) ,
-						 sizeof(irb_t), 2);	
+				s390_displayhex2 (buffer,
+						  &(dp->ii.irb),
+						  sizeof (irb_t), 2);
 			}
-		} /* endif */
+		}
 
 		/*
 		 * take fast exit if no handler is available
 		 */
-		if ( !ioinfo[irq]->ui.flags.ready )
-			return( ending_status );     		
+		if (!ioinfo[irq]->ui.flags.ready)
+			return (ending_status);
 
 		/*
 		 * Check whether we must issue a SENSE CCW ourselves if there is no
@@ -2771,38 +2891,38 @@
 		 *       sense facility available/supported when enabling the
 		 *       concurrent sense facility.
 		 */
-		if (    (    (dp->ii.irb.scsw.dstat & DEV_STAT_UNIT_CHECK )
-		          && (!issense                                    ) )
-		     || (ioinfo[irq]->ui.flags.delsense && ending_status    ) )
-		{
-			int            ret_io;
-			ccw1_t        *s_ccw  = &ioinfo[irq]->senseccw;
-			unsigned long  s_flag = 0;
+		if (((dp->ii.irb.scsw.dstat & DEV_STAT_UNIT_CHECK)
+		     && (!issense))
+		    || (ioinfo[irq]->ui.flags.delsense && ending_status)) {
+			int ret_io;
+			ccw1_t *s_ccw = &ioinfo[irq]->senseccw;
+			unsigned long s_flag = 0;
 
-			if ( ending_status )
-			{
+			if (ending_status) {
 				/*
 				 * We copy the current status information into the device driver
 				 *  status area. Then we can use the local devstat area for device
 				 *  sensing. When finally calling the IRQ handler we must not overlay
 				 *  the original device status but copy the sense data only.
 				 */
-				memcpy( udp, dp, sizeof( devstat_t) );
+				memcpy (udp, dp, sizeof (devstat_t));
 
 				s_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
-				s_ccw->cda      = (__u32)virt_to_phys( ioinfo[irq]->sense_data );
-				s_ccw->count    = SENSE_MAX_COUNT;
-				s_ccw->flags    = CCW_FLAG_SLI;
+				s_ccw->cda =
+				    (__u32) virt_to_phys (ioinfo[irq]->
+							  sense_data);
+				s_ccw->count = SENSE_MAX_COUNT;
+				s_ccw->flags = CCW_FLAG_SLI;
 
 				/*
 				 * If free_irq() or a sync do_IO/s390_start_IO() is in
 				 *  process we have to sense synchronously
 				 */
-				if ( ioinfo[irq]->ui.flags.unready || ioinfo[irq]->ui.flags.syncio )
-				{
+				if (ioinfo[irq]->ui.flags.unready
+				    || ioinfo[irq]->ui.flags.syncio) {
 					s_flag = DOIO_WAIT_FOR_INTERRUPT;
 
-				} /* endif */
+				}
 
 				/*
 				 * Reset status info
@@ -2816,27 +2936,23 @@
 				 *
 				 * Note : this may be a delayed sense request !
 				 */
-				allow4handler                  = 0;
+				allow4handler = 0;
 
-				ioinfo[irq]->ui.flags.fast     = 0;
-				ioinfo[irq]->ui.flags.repall   = 0;
-				ioinfo[irq]->ui.flags.w4final  = 0;
+				ioinfo[irq]->ui.flags.fast = 0;
+				ioinfo[irq]->ui.flags.repall = 0;
+				ioinfo[irq]->ui.flags.w4final = 0;
 				ioinfo[irq]->ui.flags.delsense = 0;
 
-				dp->cstat     = 0;
-				dp->dstat     = 0;
-				dp->rescnt    = SENSE_MAX_COUNT;
-
-				ioinfo[irq]->ui.flags.w4sense  = 1;
-			
-				ret_io = s390_start_IO( irq,
-				                        s_ccw,
-				                        0xE2C5D5E2,  // = SENSe
-				                        0,           // n/a
-				                        s_flag);
-			}
-			else
-			{
+				dp->cstat = 0;
+				dp->dstat = 0;
+				dp->rescnt = SENSE_MAX_COUNT;
+
+				ioinfo[irq]->ui.flags.w4sense = 1;
+
+				ret_io = s390_start_IO (irq, s_ccw, 0xE2C5D5E2,	/* = SENSe */
+							0,	/* n/a */
+							s_flag);
+			} else {
 				/*
 				 * we received an Unit Check but we have no final
 				 *  status yet, therefore we must delay the SENSE
@@ -2844,15 +2960,15 @@
 				 *  intermediate status to the device interrupt
 				 *  handler.
 				 */
-				ioinfo[irq]->ui.flags.fast     = 0;
-				ioinfo[irq]->ui.flags.repall   = 0;
+				ioinfo[irq]->ui.flags.fast = 0;
+				ioinfo[irq]->ui.flags.repall = 0;
 
 				ioinfo[irq]->ui.flags.delsense = 1;
-				allow4handler                  = 0;
+				allow4handler = 0;
 
-			} /* endif */
+			}
 
-		} /* endif */
+		}
 
 		/*
 		 * we allow for the device action handler if .
@@ -2863,15 +2979,15 @@
 		 *  - unsollicited interrupts
 		 *
 		 */
-		if ( allow4handler )
-		{
-			allow4handler =    ending_status
-				|| ( ioinfo[irq]->ui.flags.repall                                      )
-				|| ( stctl & SCSW_STCTL_INTER_STATUS                                   )
-				|| ( (ioinfo[irq]->ui.flags.fast ) && (stctl & SCSW_STCTL_PRIM_STATUS) )
-				|| ( ioinfo[irq]->ui.flags.oper == 0                                   );
+		if (allow4handler) {
+			allow4handler = ending_status
+			    || (ioinfo[irq]->ui.flags.repall)
+			    || (stctl & SCSW_STCTL_INTER_STATUS)
+			    || ((ioinfo[irq]->ui.flags.fast)
+				&& (stctl & SCSW_STCTL_PRIM_STATUS))
+			    || (ioinfo[irq]->ui.flags.oper == 0);
 
-		} /* endif */
+		}
 
 		/*
 		 * We used to copy the device status information right before
@@ -2882,52 +2998,48 @@
 		 *  call the device action handler.
 		 *
 		 */
-		if ( allow4handler )
-		{
+		if (allow4handler) {
 			/*
 			 * if we were waiting for sense data we copy the sense
 			 *  bytes only as the original status information was
 			 *  saved prior to sense already.
 			 */
-			if ( ioinfo[irq]->ui.flags.w4sense )
-			{
-				int sense_count = SENSE_MAX_COUNT-ioinfo[irq]->devstat.rescnt;
+			if (ioinfo[irq]->ui.flags.w4sense) {
+				int sense_count =
+				    SENSE_MAX_COUNT -
+				    ioinfo[irq]->devstat.rescnt;
 
 #ifdef CONFIG_DEBUG_IO
-				if ( irq != cons_dev )
-					printk( KERN_DEBUG "s390_process_IRQ( %04X ) : "
+				if (irq != cons_dev)
+					printk (KERN_DEBUG
+						"s390_process_IRQ( %04X ) : "
 						"BASIC SENSE bytes avail %d\n",
-						irq, sense_count );
+						irq, sense_count);
 #endif
-				if (cio_debug_initialized)
-					debug_sprintf_event(cio_debug_msg_id, 4,
-							    "s390_process_IRQ( %04X ): BASIC SENSE bytes avail %d\n",
-							    irq, sense_count);
+				CIO_MSG_EVENT(4,
+					      "s390_process_IRQ( %04X ): "
+					      "BASIC SENSE bytes avail %d\n",
+					      irq, sense_count);
 				ioinfo[irq]->ui.flags.w4sense = 0;
 				udp->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
-				udp->scnt  = sense_count;
+				udp->scnt = sense_count;
 
-				if ( sense_count >= 0 )
-				{
-					memcpy( udp->ii.sense.data,
-					        ioinfo[irq]->sense_data,
-					        sense_count);
-				}
-				else
-				{
-					panic( "s390_process_IRQ(%04x) encountered "
-					       "negative sense count\n",
-					       irq);
+				if (sense_count >= 0) {
+					memcpy (udp->ii.sense.data,
+						ioinfo[irq]->sense_data,
+						sense_count);
+				} else {
+					panic
+					    ("s390_process_IRQ(%04x) encountered "
+					     "negative sense count\n", irq);
 
-				} /* endif */
-			}
-			else
-			{
-				memcpy( udp, dp, sdevstat );
+				}
+			} else {
+				memcpy (udp, dp, sdevstat);
 
-			}  /* endif */
+			}
 
-		} /* endif */
+		}
 
 		/*
 		 * for status pending situations other than deferred interrupt
@@ -2935,74 +3047,74 @@
 		 *  call the handler. This will synchronously be reported back
 		 *  to the caller instead, e.g. when detected during do_IO().
 		 */
-		if (    ioinfo[irq]->ui.flags.s_pend
-		     || ioinfo[irq]->ui.flags.unready
-		     || ioinfo[irq]->ui.flags.repnone )
-		{		
-			if ( ending_status )
-			{
+		if (ioinfo[irq]->ui.flags.s_pend
+		    || ioinfo[irq]->ui.flags.unready
+		    || ioinfo[irq]->ui.flags.repnone) {
+			if (ending_status) {
+
+				ioinfo[irq]->ui.flags.busy = 0;
+				ioinfo[irq]->ui.flags.doio = 0;
+				ioinfo[irq]->ui.flags.haltio = 0;
+				ioinfo[irq]->ui.flags.fast = 0;
+				ioinfo[irq]->ui.flags.repall = 0;
+				ioinfo[irq]->ui.flags.w4final = 0;
 
-				ioinfo[irq]->ui.flags.busy     = 0;
-				ioinfo[irq]->ui.flags.doio     = 0;
-				ioinfo[irq]->ui.flags.haltio   = 0;
-				ioinfo[irq]->ui.flags.fast     = 0;
-				ioinfo[irq]->ui.flags.repall   = 0;
-				ioinfo[irq]->ui.flags.w4final  = 0;
-
-				dp->flag  |= DEVSTAT_FINAL_STATUS;
+				dp->flag |= DEVSTAT_FINAL_STATUS;
 				udp->flag |= DEVSTAT_FINAL_STATUS;
 
-			} /* endif */
+			}
 
 			allow4handler = 0;
 
-		} /* endif */
+		}
 
 		/*
 		 * Call device action handler if applicable
 		 */
-		if ( allow4handler )
-		{
+		if (allow4handler) {
 
 			/*
 			 *  We only reset the busy condition when we are sure that no further
 			 *   interrupt is pending for the current I/O request (ending_status).
 			 */
-			if ( ending_status || !ioinfo[irq]->ui.flags.oper )
-			{
-				ioinfo[irq]->ui.flags.oper     = 1;  /* dev IS oper */
+			if (ending_status || !ioinfo[irq]->ui.flags.oper) {
+				ioinfo[irq]->ui.flags.oper = 1;	/* dev IS oper */
 
-				ioinfo[irq]->ui.flags.busy     = 0;
-				ioinfo[irq]->ui.flags.doio     = 0;
-				ioinfo[irq]->ui.flags.haltio   = 0;
-				ioinfo[irq]->ui.flags.fast     = 0;
-				ioinfo[irq]->ui.flags.repall   = 0;
-				ioinfo[irq]->ui.flags.w4final  = 0;
+				ioinfo[irq]->ui.flags.busy = 0;
+				ioinfo[irq]->ui.flags.doio = 0;
+				ioinfo[irq]->ui.flags.haltio = 0;
+				ioinfo[irq]->ui.flags.fast = 0;
+				ioinfo[irq]->ui.flags.repall = 0;
+				ioinfo[irq]->ui.flags.w4final = 0;
 
-				dp->flag  |= DEVSTAT_FINAL_STATUS;
+				dp->flag |= DEVSTAT_FINAL_STATUS;
 				udp->flag |= DEVSTAT_FINAL_STATUS;
 
-				ioinfo[irq]->irq_desc.handler( irq, udp, NULL );
+				ioinfo[irq]->irq_desc.handler (irq, udp, NULL);
 
-				//
-				// reset intparm after final status or we will badly present unsolicited
-				//  interrupts with a intparm value possibly no longer valid.
-				//
-				dp->intparm   = 0;
-
-				//
-				// Was there anything queued ? Start the pending channel program
-				//  if there is one.
-				//
-				if ( ioinfo[irq]->ui.flags.doio_q )
-				{
-					int ret;
+				/*
+				 * reset intparm after final status or we will badly present unsolicited
+				 *  interrupts with a intparm value possibly no longer valid.
+				 */
+				dp->intparm = 0;
 
-					ret = s390_start_IO( irq,
-					                     ioinfo[irq]->qcpa,
-					                     ioinfo[irq]->qintparm,
-						             ioinfo[irq]->qlpm,
-					                     ioinfo[irq]->qflag);
+				/*
+				 * Was there anything queued ? Start the pending channel program
+				 *  if there is one.
+				 */
+				if (ioinfo[irq]->ui.flags.doio_q) {
+					int ret;
+					int do_cancel =
+					    ioinfo[irq]->
+					    qflag & DOIO_CANCEL_ON_TIMEOUT;
+
+					ret = s390_start_IO (irq,
+							     ioinfo[irq]->qcpa,
+							     ioinfo[irq]->
+							     qintparm,
+							     ioinfo[irq]->qlpm,
+							     ioinfo[irq]->
+							     qflag);
 
 					ioinfo[irq]->ui.flags.doio_q = 0;
 
@@ -3012,17 +3124,22 @@
 					 *  s390_start_IO() accordingly already (status pending
 					 *  condition).
 					 */
-					if ( ret )
-					{
-						ioinfo[irq]->irq_desc.handler( irq, udp, NULL );
+					if (ret) {
+						ioinfo[irq]->irq_desc.
+						    handler (irq, udp, NULL);
+
+					}
 
-					} /* endif */
+					/* 
+					 * better cancel the io when we time out...
+					 */
+					if ((ret == -ETIMEDOUT) && do_cancel) {
+						cancel_IO (irq);
+					}
 
-				} /* endif */
+				}
 
-			}
-			else
-			{
+			} else {
 				ioinfo[irq]->ui.flags.w4final = 1;
 
 				/*
@@ -3030,53 +3147,48 @@
 				 *  set the PCI or SUSPENDED flag in the user
 				 *  device status block if appropriate.
 				 */
-				if ( dp->cstat & SCHN_STAT_PCI )
-				{
+				if (dp->cstat & SCHN_STAT_PCI) {
 					udp->flag |= DEVSTAT_PCI;
 					dp->cstat &= ~SCHN_STAT_PCI;
 				}
 
-				if ( actl & SCSW_ACTL_SUSPENDED )
-				{
+				if (actl & SCSW_ACTL_SUSPENDED) {
 					udp->flag |= DEVSTAT_SUSPENDED;
 
-				} /* endif */
+				}
 
-				ioinfo[irq]->irq_desc.handler( irq, udp, NULL );
+				ioinfo[irq]->irq_desc.handler (irq, udp, NULL);
 
-			} /* endif */
+			}
 
-		} /* endif */
+		}
 
 		break;
 
-	case 3:      /* device/path not operational */
+	case 3:		/* device/path not operational */
 
-		ioinfo[irq]->ui.flags.busy    = 0;
-		ioinfo[irq]->ui.flags.doio    = 0;
-		ioinfo[irq]->ui.flags.haltio  = 0;
+		ioinfo[irq]->ui.flags.busy = 0;
+		ioinfo[irq]->ui.flags.doio = 0;
+		ioinfo[irq]->ui.flags.haltio = 0;
 
-		dp->cstat    = 0;
-		dp->dstat    = 0;
+		dp->cstat = 0;
+		dp->dstat = 0;
 
-		if ( ioinfo[irq]->ulpm != ioinfo[irq]->opm )
-		{
+		if (ioinfo[irq]->ulpm != ioinfo[irq]->opm) {
 			/*
 			 * either it was the only path or it was restricted ...
 			 */
-			ioinfo[irq]->opm &= ~(ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum);
-		}
-		else
-		{
+			ioinfo[irq]->opm &=
+			    ~(ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum);
+		} else {
 			ioinfo[irq]->opm = 0;
 
-		} /* endif */
-	
-		if ( ioinfo[irq]->opm == 0 ) 	
-		{
-			ioinfo[irq]->ui.flags.oper  = 0;
+		}
+
+		if (ioinfo[irq]->opm == 0) {
+			ioinfo[irq]->ui.flags.oper = 0;
 
-		} /* endif */
+		}
 
 		ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
 		ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
@@ -3092,50 +3204,48 @@
 		 *       interrupts on "not oper" conditions.
 		 */
 
-		if (    ( ioinfo[irq]->ui.flags.fast    )
-		     && ( ioinfo[irq]->ui.flags.w4final ) )
-		{
+		if ((ioinfo[irq]->ui.flags.fast)
+		    && (ioinfo[irq]->ui.flags.w4final)) {
 			/*
 			 * If a new request was queued already, we have
 			 *  to simulate the "not oper" status for the
 			 *  queued request by switching the "intparm" value
 			 *  and notify the interrupt handler.
 			 */
-			if ( ioinfo[irq]->ui.flags.doio_q )
-			{
-				ioinfo[irq]->devstat.intparm = ioinfo[irq]->qintparm;
+			if (ioinfo[irq]->ui.flags.doio_q) {
+				ioinfo[irq]->devstat.intparm =
+				    ioinfo[irq]->qintparm;
 
-			} /* endif */
-
-		} /* endif */
+			}
+		}
 
-		ioinfo[irq]->ui.flags.fast    = 0;
-		ioinfo[irq]->ui.flags.repall  = 0;
+		ioinfo[irq]->ui.flags.fast = 0;
+		ioinfo[irq]->ui.flags.repall = 0;
 		ioinfo[irq]->ui.flags.w4final = 0;
 
 		/*
 		 * take fast exit if no handler is available
 		 */
-		if ( !ioinfo[irq]->ui.flags.ready )
-			return( ending_status );     		
+		if (!ioinfo[irq]->ui.flags.ready)
+			return (ending_status);
 
-		memcpy( udp, &(ioinfo[irq]->devstat), sdevstat );
+		memcpy (udp, &(ioinfo[irq]->devstat), sdevstat);
 
-		ioinfo[irq]->devstat.intparm  = 0;
+		ioinfo[irq]->devstat.intparm = 0;
 
-		if ( !ioinfo[irq]->ui.flags.s_pend )
-		{
-			ioinfo[irq]->irq_desc.handler( irq, udp, NULL );
+		if (!ioinfo[irq]->ui.flags.s_pend
+		    && !ioinfo[irq]->ui.flags.repnone) {
+			ioinfo[irq]->irq_desc.handler (irq, udp, NULL);
 
-		} /* endif */
+		}
 
-		ending_status    = 1;
+		ending_status = 1;
 
 		break;
 
-	} /* endswitch */
+	}
 
-	return( ending_status );
+	return (ending_status);
 }
 
 /*
@@ -3155,456 +3265,409 @@
  *  encountered, wait_cons_dev(9 calls do_IRQ() to have
  *  the console device driver processing the interrupt.
  */
-int set_cons_dev( int irq )
+int
+set_cons_dev (int irq)
 {
-	int           ccode;
-	unsigned long cr6 __attribute__ ((aligned (8)));
-	int           rc = 0;
+	int ccode;
+	int rc = 0;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if ( cons_dev != -1  )
-	{
-		rc = -EBUSY;
-	}
-	else
-	{
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "scons%x", irq);
-			debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-		}
-		
-		/*
-		 * modify the indicated console device to operate
-		 *  on special console interrupt sublass 7
-		 */
-		ccode = stsch( irq, &(ioinfo[irq]->schib) );
+	if (cons_dev != -1)
+		return -EBUSY;
 
-		if (ccode)
-		{
-			rc                         = -ENODEV;
-			ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
-		}
-		else
-		{
-			ioinfo[irq]->schib.pmcw.isc = 7;
+	sprintf (dbf_txt, "scd%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-			ccode = msch( irq, &(ioinfo[irq]->schib) );
+	/*
+	 * modify the indicated console device to operate
+	 *  on special console interrupt sublass 7
+	 */
+	ccode = stsch (irq, &(ioinfo[irq]->schib));
 
-			if (ccode)
-			{
-				rc = -EIO;
-			}
-			else
-			{
-				cons_dev = irq;
+	if (ccode) {
+		rc = -ENODEV;
+		ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
+	} else {
+		ioinfo[irq]->schib.pmcw.isc = 7;
 
-				/*
-				 * enable console I/O-interrupt sublass 7
-				 */
-				__ctl_store( cr6, 6, 6);
-				cr6 |= 0x01000000;
-				__ctl_load( cr6, 6, 6);
+		ccode = msch (irq, &(ioinfo[irq]->schib));
 
-			} /* endif */
+		if (ccode) {
+			rc = -EIO;
+		} else {
+			cons_dev = irq;
 
-		} /* endif */
+			/*
+			 * enable console I/O-interrupt sublass 7
+			 */
+			ctl_set_bit (6, 24);
 
-	} /* endif */
+		}
+	}
 
-	return( rc);
+	return (rc);
 }
 
-int reset_cons_dev( int irq)
+int
+reset_cons_dev (int irq)
 {
-	int     rc = 0;
-	int     ccode;
-	long    cr6 __attribute__ ((aligned (8)));
+	int rc = 0;
+	int ccode;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if ( cons_dev != -1  )
-	{
-		rc = -EBUSY;
-	}
-	else
-	{
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "rcons%x", irq);
-			debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-		}
-
-		/*
-		 * reset the indicated console device to operate
-		 *  on default console interrupt sublass 3
-		 */
-		ccode = stsch( irq, &(ioinfo[irq]->schib) );
+	if (cons_dev != -1)
+		return -EBUSY;
 
-		if (ccode)
-		{
-			rc                         = -ENODEV;
-			ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
-		}
-		else
-		{
+	sprintf (dbf_txt, "rscd%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-			ioinfo[irq]->schib.pmcw.isc = 3;
+	/*
+	 * reset the indicated console device to operate
+	 *  on default console interrupt sublass 3
+	 */
+	ccode = stsch (irq, &(ioinfo[irq]->schib));
 
-			ccode = msch( irq, &(ioinfo[irq]->schib) );
+	if (ccode) {
+		rc = -ENODEV;
+		ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
+	} else {
 
-			if (ccode)
-			{
-				rc = -EIO;
-			}
-			else
-			{
-				cons_dev = -1;
+		ioinfo[irq]->schib.pmcw.isc = 3;
 
-				/*
-				 * disable special console I/O-interrupt sublass 7
-				 */
-				__ctl_store( cr6, 6, 6);
-				cr6 &= 0xFEFFFFFF;
-				__ctl_load( cr6, 6, 6);
+		ccode = msch (irq, &(ioinfo[irq]->schib));
 
-			} /* endif */
+		if (ccode) {
+			rc = -EIO;
+		} else {
+			cons_dev = -1;
 
-		} /* endif */
+			/*
+			 * disable special console I/O-interrupt sublass 7
+			 */
+			ctl_clear_bit(6, 24);
 
-	} /* endif */
+		}
+	}
 
-	return( rc);
+	return (rc);
 }
 
-int wait_cons_dev( int irq )
+int
+wait_cons_dev (int irq)
 {
-	int              rc = 0;
-	long             save_cr6;
+	int rc = 0;
+	long save_cr6;
 	char dbf_txt[15];
 
-	if ( irq == cons_dev )
-	{
+	if (irq != cons_dev)
+		return -EINVAL;
 
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "wcons%x", irq);
-			debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-		}
+	sprintf (dbf_txt, "wcd%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	/*
+	 * before entering the spinlock we may already have
+	 *  processed the interrupt on a different CPU ...
+	 */
+	if (ioinfo[irq]->ui.flags.busy == 1) {
+		long cr6 __attribute__ ((aligned (8)));
 
 		/*
-		 * before entering the spinlock we may already have
-		 *  processed the interrupt on a different CPU ...
+		 * disable all, but isc 7 (console device)
 		 */
-		if ( ioinfo[irq]->ui.flags.busy == 1 )
-		{
-			long cr6 __attribute__ ((aligned (8)));
+		__ctl_store (cr6, 6, 6);
+		save_cr6 = cr6;
+		cr6 &= 0x01FFFFFF;
+		__ctl_load (cr6, 6, 6);
 
-			/*
-			 * disable all, but isc 7 (console device)
-			 */
-			__ctl_store( cr6, 6, 6);
-			save_cr6  = cr6;
-			cr6      &= 0x01FFFFFF;
-			__ctl_load( cr6, 6, 6);
-
-			do {
-				tpi_info_t tpi_info = {0,};
-				if (tpi(&tpi_info) == 1) {
-					s390_process_IRQ( tpi_info.irq );
-				} else {
-					s390irq_spin_unlock(irq);
-					udelay(100);
-					s390irq_spin_lock(irq);
-				}
-				eieio();
-			} while (ioinfo[irq]->ui.flags.busy == 1);
-
-			/*
-			 * restore previous isc value
-			 */
-			cr6 = save_cr6;
-			__ctl_load( cr6, 6, 6);
+		do {
+			tpi_info_t tpi_info = { 0, };
+			if (tpi (&tpi_info) == 1) {
+				s390_process_IRQ (tpi_info.irq);
+			} else {
+				s390irq_spin_unlock (irq);
+				udelay (100);
+				s390irq_spin_lock (irq);
+			}
+			eieio ();
+		} while (ioinfo[irq]->ui.flags.busy == 1);
 
-		} /* endif */
+		/*
+		 * restore previous isc value
+		 */
+		cr6 = save_cr6;
+		__ctl_load (cr6, 6, 6);
 
 	}
-	else
-	{
-		rc = EINVAL;
-
-	} /* endif */
 
-
-	return(rc);
+	return (rc);
 }
 
-
-int enable_cpu_sync_isc( int irq )
+int
+enable_cpu_sync_isc (int irq)
 {
-	int             ccode;
-	long            cr6 __attribute__ ((aligned (8)));
+	int ccode;
+	long cr6 __attribute__ ((aligned (8)));
 
-	int             retry = 3;
-	int             rc    = 0;
+	int retry = 3;
+	int rc = 0;
 	char dbf_txt[15];
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "enisc%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "eisc%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
 	/* This one spins until it can get the sync_isc lock for irq# irq */
 
-	if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA )
-	{
-		if ( atomic_read( &sync_isc ) != irq )
-			atomic_compare_and_swap_spin( -1, irq, &sync_isc );
+	if ((irq <= highest_subchannel) && 
+	    (ioinfo[irq] != INVALID_STORAGE_AREA) &&
+	    (!ioinfo[irq]->st)) {
+		if (atomic_read (&sync_isc) != irq)
+			atomic_compare_and_swap_spin (-1, irq, &sync_isc);
 
 		sync_isc_cnt++;
-		
-		if ( sync_isc_cnt > 255 ) /* fixme : magic number */
-		{
-			panic("Too many recursive calls to enable_sync_isc");
+
+		if (sync_isc_cnt > 255) {	/* fixme : magic number */
+			panic ("Too many recursive calls to enable_sync_isc");
 
 		}
 		/*
 		 * we only run the STSCH/MSCH path for the first enablement
 		 */
-		else if ( sync_isc_cnt == 1 )
-		{
+		else if (sync_isc_cnt == 1) {
 			ioinfo[irq]->ui.flags.syncio = 1;
 
-			ccode = stsch( irq, &(ioinfo[irq]->schib) );
+			ccode = stsch (irq, &(ioinfo[irq]->schib));
 
-			if ( !ccode )
-			{
+			if (!ccode) {
 				ioinfo[irq]->schib.pmcw.isc = 5;
 
-				do
-				{
-					ccode = msch( irq,
-					              &(ioinfo[irq]->schib) );
+				do {
+					ccode = msch (irq,
+						      &(ioinfo[irq]->schib));
 
 					switch (ccode) {
-					case 0: 
+					case 0:
 						/*
 						 * enable special isc
 						 */
-						__ctl_store( cr6, 6, 6);
-						cr6 |= 0x04000000;  // enable sync isc 5
-						cr6 &= 0xEFFFFFFF;  // disable standard isc 3
-						__ctl_load( cr6, 6, 6);
+						__ctl_store (cr6, 6, 6);
+						/* enable sync isc 5 */
+						cr6 |= 0x04000000;
+						/* disable standard isc 3 */
+						cr6 &= 0xEFFFFFFF;
+						/* disable console isc 7,
+						 * if neccessary */
+						if (cons_dev != -1)
+							cr6 &= 0xFEFFFFFF;
+						__ctl_load (cr6, 6, 6);
+						rc = 0;
 						retry = 0;
 						break;
-					
+
 					case 1:
-						//
-						// process pending status
-						//
-						ioinfo[irq]->ui.flags.s_pend = 1;
-						s390_process_IRQ( irq );
-						ioinfo[irq]->ui.flags.s_pend = 0;
-						
-						rc = -EIO;  /* might be overwritten... */
+						/*
+						 * process pending status
+						 */
+						ioinfo[irq]->ui.flags.s_pend =
+						    1;
+						s390_process_IRQ (irq);
+						ioinfo[irq]->ui.flags.s_pend =
+						    0;
+
+						rc = -EIO;	/* might be overwritten... */
 						retry--;
 						break;
 
-					case 2: /* busy */
+					case 2:	/* busy */
 						retry = 0;
-						rc = -EBUSY; 
+						rc = -EBUSY;
 						break;
 
-					case 3: /* not oper*/
+					case 3:	/* not oper */
 						retry = 0;
-						rc = -ENODEV; 
+						rc = -ENODEV;
 						break;
-					
-					}
 
-				} while ( retry );
-
-			}
-			else
-			{
-				rc = -ENODEV;     // device is not-operational
+					}
 
-			} /* endif */
+				} while (retry);
 
-		} /* endif */
+			} else {
+				rc = -ENODEV;	/* device is not-operational */
 
+			}
+		}
 
-		if ( rc )	/* can only happen if stsch/msch fails */
-		{
+		if (rc) {	/* can only happen if stsch/msch fails */
 			sync_isc_cnt = 0;
-			atomic_set( &sync_isc, -1);
+			atomic_set (&sync_isc, -1);
 		}
-	}
-	else
-	{
+	} else {
 #ifdef CONFIG_SYNC_ISC_PARANOIA
-		panic( "enable_sync_isc: called with invalid %x\n", irq );
+		panic ("enable_sync_isc: called with invalid %x\n", irq);
 #endif
 
 		rc = -EINVAL;
 
-	} /* endif */
+	}
 
-	return( rc);
+	return (rc);
 }
 
-int disable_cpu_sync_isc( int irq)
+int
+disable_cpu_sync_isc (int irq)
 {
-	int     rc         = 0;
-	int     retry1     = 5;
-	int     retry2     = 5;
-	int     clear_pend = 0;
+	int rc = 0;
+	int retry1 = 5;
+	int retry2 = 5;
+	int clear_pend = 0;
 
-	int     ccode;
-	long    cr6 __attribute__ ((aligned (8)));
+	int ccode;
+	long cr6 __attribute__ ((aligned (8)));
 
 	char dbf_txt[15];
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "disisc%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "disc%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA )
-	{
+	if ((irq <= highest_subchannel) && 
+	    (ioinfo[irq] != INVALID_STORAGE_AREA) && 
+	    (!ioinfo[irq]->st)) {
 		/*
 		 * We disable if we're the top user only, as we may
-		 *  run recursively ...	
+		 *  run recursively ... 
 		 * We must not decrease the count immediately; during
 		 *  msch() processing we may face another pending
 		 *  status we have to process recursively (sync).
 		 */
 
 #ifdef CONFIG_SYNC_ISC_PARANOIA
-		if ( atomic_read( &sync_isc ) != irq )
-			panic( "disable_sync_isc: called for %x while %x locked\n",
-				irq, atomic_read( &sync_isc ) );
+		if (atomic_read (&sync_isc) != irq)
+			panic
+			    ("disable_sync_isc: called for %x while %x locked\n",
+			     irq, atomic_read (&sync_isc));
 #endif
 
-		if ( sync_isc_cnt == 1 )
-		{
-			ccode = stsch( irq, &(ioinfo[irq]->schib) );
+		if (sync_isc_cnt == 1) {
+			ccode = stsch (irq, &(ioinfo[irq]->schib));
 
 			ioinfo[irq]->schib.pmcw.isc = 3;
 
-			do
-			{
-			        retry2 = 5;
-				do
-				{
-					ccode = msch( irq, &(ioinfo[irq]->schib) );
+			do {
+				retry2 = 5;
+				do {
+					ccode =
+					    msch (irq, &(ioinfo[irq]->schib));
 
-					switch ( ccode ) {
+					switch (ccode) {
 					case 0:
 						/*
 						 * disable special interrupt subclass in CPU
 						 */
-						__ctl_store( cr6, 6, 6);
-						cr6 &= 0xFBFFFFFF; // disable sync isc 5
-						cr6 |= 0x10000000; // enable standard isc 3
-						__ctl_load( cr6, 6, 6);
+						__ctl_store (cr6, 6, 6);
+						/* disable sync isc 5 */
+						cr6 &= 0xFBFFFFFF;
+						/* enable standard isc 3 */
+						cr6 |= 0x10000000;
+						/* enable console isc 7,
+						 * if neccessary */
+						if (cons_dev != -1)
+							cr6 |= 0x01000000;
+						__ctl_load (cr6, 6, 6);
 
 						retry2 = 0;
 						break;
 
-					case 1: /* status pending */
-						ioinfo[irq]->ui.flags.s_pend = 1;
-						s390_process_IRQ( irq );
-						ioinfo[irq]->ui.flags.s_pend = 0;
+					case 1:	/* status pending */
+						ioinfo[irq]->ui.flags.s_pend =
+						    1;
+						s390_process_IRQ (irq);
+						ioinfo[irq]->ui.flags.s_pend =
+						    0;
 
 						retry2--;
 						break;
 
-					case 2: /* busy */
-					        retry2--;
-						udelay( 100); // give it time
+					case 2:	/* busy */
+						retry2--;
+						udelay (100);	/* give it time */
 						break;
-						
-					default: /* not oper */
+
+					default:	/* not oper */
 						retry2 = 0;
 						break;
-					} /* endswitch */
+					}
 
-				} while ( retry2 );
+				} while (retry2);
 
 				retry1--;
 
 				/* try stopping it ... */
-				if ( (ccode) && !clear_pend )
-				{
-					clear_IO( irq, 0x00004711, 0 );
+				if ((ccode) && !clear_pend) {
+					clear_IO (irq, 0x00004711, 0);
 					clear_pend = 1;
-               	
-				} /* endif */
 
-				udelay( 100);
+				}
+
+				udelay (100);
 
-			} while ( retry1 && ccode );
+			} while (retry1 && ccode);
 
 			ioinfo[irq]->ui.flags.syncio = 0;
-		
-			sync_isc_cnt = 0;	
-			atomic_set( &sync_isc, -1);
 
-		}
-		else
-		{
+			sync_isc_cnt = 0;
+			atomic_set (&sync_isc, -1);
+
+		} else {
 			sync_isc_cnt--;
 
-		} /* endif */
-	}
-	else
-	{
+		}
+	} else {
 #ifdef CONFIG_SYNC_ISC_PARANOIA
-		if ( atomic_read( &sync_isc ) != -1 )
-			panic( "disable_sync_isc: called with invalid %x while %x locked\n", 
-				irq, atomic_read( &sync_isc ) );
+		if (atomic_read (&sync_isc) != -1)
+			panic
+			    ("disable_sync_isc: called with invalid %x while %x locked\n",
+			     irq, atomic_read (&sync_isc));
 #endif
 
 		rc = -EINVAL;
 
-	} /* endif */
+	}
 
-	return( rc);
+	return (rc);
 }
 
-//
-// Input :
-//   devno - device number
-//   ps    - pointer to sense ID data area
-//
-// Output : none
-//
-void VM_virtual_device_info( __u16      devno,
-                             senseid_t *ps )
+/*
+ * Input :
+ *   devno - device number
+ *   ps    - pointer to sense ID data area
+ * Output : none
+ */
+void
+VM_virtual_device_info (__u16 devno, senseid_t * ps)
 {
-	diag210_t  *p_diag_data;
-	int        ccode;
+	diag210_t *p_diag_data;
+	int ccode;
 
-	int        error = 0;
+	int error = 0;
 
-	if (cio_debug_initialized) 
-		debug_text_event(cio_debug_trace_id, 4, "VMvdinf");
+	CIO_TRACE_EVENT (4, "VMvdinf");
 
-	if ( init_IRQ_complete )
-	{
-		p_diag_data = kmalloc( sizeof( diag210_t), GFP_DMA );
-	}
-	else
-	{
-		p_diag_data = alloc_bootmem_low( sizeof( diag210_t));
+	if (init_IRQ_complete) {
+		p_diag_data = kmalloc (sizeof (diag210_t), GFP_DMA);
+	} else {
+		p_diag_data = alloc_bootmem_low (sizeof (diag210_t));
 
-	} /* endif */
+	}
 
 	p_diag_data->vrdcdvno = devno;
-	p_diag_data->vrdclen  = sizeof( diag210_t);
-	ccode                 = diag210( (diag210_t *)virt_to_phys( p_diag_data ) );
-	ps->reserved          = 0xff;
+	p_diag_data->vrdclen = sizeof (diag210_t);
+	ccode = diag210 ((diag210_t *) virt_to_phys (p_diag_data));
+	ps->reserved = 0xff;
 
 	switch (p_diag_data->vrdcvcla) {
 	case 0x80:
@@ -3612,7 +3675,7 @@
 		switch (p_diag_data->vrdcvtyp) {
 		case 00:
 
-			ps->cu_type   = 0x3215;
+			ps->cu_type = 0x3215;
 
 			break;
 
@@ -3622,7 +3685,7 @@
 
 			break;
 
-		} /* endswitch */
+		}
 
 		break;
 
@@ -3631,25 +3694,25 @@
 		switch (p_diag_data->vrdcvtyp) {
 		case 0xC0:
 
-			ps->cu_type   = 0x5080;
+			ps->cu_type = 0x5080;
 
 			break;
 
 		case 0x80:
 
-			ps->cu_type   = 0x2250;
+			ps->cu_type = 0x2250;
 
 			break;
 
 		case 0x04:
 
-			ps->cu_type   = 0x3277;
+			ps->cu_type = 0x3277;
 
 			break;
 
 		case 0x01:
 
-			ps->cu_type   = 0x3278;
+			ps->cu_type = 0x3278;
 
 			break;
 
@@ -3659,7 +3722,7 @@
 
 			break;
 
-		} /* endswitch */
+		}
 
 		break;
 
@@ -3668,19 +3731,19 @@
 		switch (p_diag_data->vrdcvtyp) {
 		case 0x84:
 
-			ps->cu_type   = 0x3505;
+			ps->cu_type = 0x3505;
 
 			break;
 
 		case 0x82:
 
-			ps->cu_type   = 0x2540;
+			ps->cu_type = 0x2540;
 
 			break;
 
 		case 0x81:
 
-			ps->cu_type   = 0x2501;
+			ps->cu_type = 0x2501;
 
 			break;
 
@@ -3690,7 +3753,7 @@
 
 			break;
 
-		} /* endswitch */
+		}
 
 		break;
 
@@ -3699,13 +3762,13 @@
 		switch (p_diag_data->vrdcvtyp) {
 		case 0x84:
 
-			ps->cu_type   = 0x3525;
+			ps->cu_type = 0x3525;
 
 			break;
 
 		case 0x82:
 
-			ps->cu_type   = 0x2540;
+			ps->cu_type = 0x2540;
 
 			break;
 
@@ -3713,7 +3776,7 @@
 		case 0x4E:
 		case 0x48:
 
-			ps->cu_type   = 0x3820;
+			ps->cu_type = 0x3820;
 
 			break;
 
@@ -3721,43 +3784,43 @@
 		case 0x49:
 		case 0x45:
 
-			ps->cu_type   = 0x3800;
+			ps->cu_type = 0x3800;
 
 			break;
 
 		case 0x4B:
 
-			ps->cu_type   = 0x4248;
+			ps->cu_type = 0x4248;
 
 			break;
 
 		case 0x4A:
 
-			ps->cu_type   = 0x4245;
+			ps->cu_type = 0x4245;
 
 			break;
 
 		case 0x47:
 
-			ps->cu_type   = 0x3262;
+			ps->cu_type = 0x3262;
 
 			break;
 
 		case 0x43:
 
-			ps->cu_type   = 0x3203;
+			ps->cu_type = 0x3203;
 
 			break;
 
 		case 0x42:
 
-			ps->cu_type   = 0x3211;
+			ps->cu_type = 0x3211;
 
 			break;
 
 		case 0x41:
 
-			ps->cu_type   = 0x1403;
+			ps->cu_type = 0x1403;
 
 			break;
 
@@ -3767,7 +3830,7 @@
 
 			break;
 
-		} /* endswitch */
+		}
 
 		break;
 
@@ -3776,43 +3839,43 @@
 		switch (p_diag_data->vrdcvtyp) {
 		case 0x82:
 
-			ps->cu_type   = 0x3422;
+			ps->cu_type = 0x3422;
 
 			break;
 
 		case 0x81:
 
-			ps->cu_type   = 0x3490;
+			ps->cu_type = 0x3490;
 
 			break;
 
 		case 0x10:
 
-			ps->cu_type   = 0x3420;
+			ps->cu_type = 0x3420;
 
 			break;
 
 		case 0x02:
 
-			ps->cu_type   = 0x3430;
+			ps->cu_type = 0x3430;
 
 			break;
 
 		case 0x01:
 
-			ps->cu_type   = 0x3480;
+			ps->cu_type = 0x3480;
 
 			break;
 
 		case 0x42:
 
-			ps->cu_type   = 0x3424;
+			ps->cu_type = 0x3424;
 
 			break;
 
 		case 0x44:
 
-			ps->cu_type   = 0x9348;
+			ps->cu_type = 0x9348;
 
 			break;
 
@@ -3822,26 +3885,26 @@
 
 			break;
 
-		} /* endswitch */
+		}
 
 		break;
 
-	case 02: /* special device class ... */
+	case 02:		/* special device class ... */
 
 		switch (p_diag_data->vrdcvtyp) {
-		case 0x20: /* OSA */
+		case 0x20:	/* OSA */
 
-			ps->cu_type   = 0x3088;
-			ps->cu_model  = 0x60;
+			ps->cu_type = 0x3088;
+			ps->cu_model = 0x60;
 
 			break;
 
 		default:
 
 			error = 1;
-      	break;
+			break;
 
-		} /* endswitch */
+		}
 
 		break;
 
@@ -3851,47 +3914,44 @@
 
 		break;
 
-	} /* endswitch */
-
-	if ( init_IRQ_complete )
-	{
-		kfree( p_diag_data );
 	}
-	else
-	{
-		free_bootmem( (unsigned long)p_diag_data, sizeof( diag210_t) );
 
-	} /* endif */
+	if (init_IRQ_complete) {
+		kfree (p_diag_data);
+	} else {
+		free_bootmem ((unsigned long) p_diag_data, sizeof (diag210_t));
+
+	}
 
-	if ( error )
-	{
-		printk( KERN_ERR "DIAG X'210' for "
-		        "device %04X returned "
-		        "(cc = %d): vdev class : %02X, "
-			"vdev type : %04X \n ...  rdev class : %02X, rdev type : %04X, rdev model: %02X\n",
+	if (error) {
+		printk (KERN_ERR "DIAG X'210' for "
+			"device %04X returned "
+			"(cc = %d): vdev class : %02X, "
+			"vdev type : %04X \n"
+			" ...  rdev class : %02X, rdev type : %04X, "
+			"rdev model: %02X\n",
 			devno,
 			ccode,
 			p_diag_data->vrdcvcla,
 			p_diag_data->vrdcvtyp,
 			p_diag_data->vrdcrccl,
-			p_diag_data->vrdccrty,
-			p_diag_data->vrdccrmd );
-		if (cio_debug_initialized)
-			debug_sprintf_event( cio_debug_msg_id, 0,
-					     "DIAG X'210' for "
-					     "device %04X returned "
-					     "(cc = %d): vdev class : %02X, "
-					     "vdev type : %04X \n ...  rdev class : %02X, rdev type : %04X, rdev model: %02X\n",
-					     devno,
-					     ccode,
-					     p_diag_data->vrdcvcla,
-					     p_diag_data->vrdcvtyp,
-					     p_diag_data->vrdcrccl,
-					     p_diag_data->vrdccrty,
-					     p_diag_data->vrdccrmd );
-
-	} /* endif */
-
+			p_diag_data->vrdccrty, p_diag_data->vrdccrmd);
+		CIO_MSG_EVENT(0,
+			      "DIAG X'210' for "
+			      "device %04X returned "
+			      "(cc = %d): vdev class : %02X, "
+			      "vdev type : %04X \n ...  "
+			      "rdev class : %02X, rdev type : %04X, "
+			      "rdev model: %02X\n",
+			      devno,
+			      ccode,
+			      p_diag_data->vrdcvcla,
+			      p_diag_data->vrdcvtyp,
+			      p_diag_data->vrdcrccl,
+			      p_diag_data->vrdccrty,
+			      p_diag_data->vrdccrmd);
+		
+	}
 }
 
 /*
@@ -3917,371 +3977,351 @@
  *         b) without unnecessarily increase system startup by
  *            evaluating devices eventually not used at all.
  */
-int read_dev_chars( int irq, void **buffer, int length )
+int
+read_dev_chars (int irq, void **buffer, int length)
 {
-	unsigned int  flags;
-	ccw1_t       *rdc_ccw;
-	devstat_t     devstat;
-	char         *rdc_buf;
-	int           devflag = 0;
-
-	int           ret      = 0;
-	int           emulated = 0;
-	int           retry    = 5;
+	unsigned int flags;
+	ccw1_t *rdc_ccw;
+	devstat_t devstat;
+	char *rdc_buf;
+	int devflag = 0;
+
+	int ret = 0;
+	int emulated = 0;
+	int retry = 5;
 
 	char dbf_txt[15];
 
-	if ( !buffer || !length )
-	{
-		return( -EINVAL );
+	if (!buffer || !length) {
+		return (-EINVAL);
+
+	}
 
-	} /* endif */
+	SANITY_CHECK (irq);
 
-	SANITY_CHECK(irq);
+	if (ioinfo[irq]->ui.flags.oper == 0) {
+		return (-ENODEV);
 
-	if ( ioinfo[irq]->ui.flags.oper == 0 )
-	{
-		return( -ENODEV );
-
-	} /* endif */
-
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "rddevch%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
 	}
 
+ 	if (ioinfo[irq]->ui.flags.unfriendly) {
+ 		/* don't even try it */
+ 		return -EUSERS;
+ 	}
+
+	sprintf (dbf_txt, "rdc%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
 	/*
 	 * Before playing around with irq locks we should assure
 	 *   running disabled on (just) our CPU. Sync. I/O requests
 	 *   also require to run disabled.
 	 *
 	 * Note : as no global lock is required, we must not use
-	 *        cli(), but __cli() instead.  	
+	 *        cli(), but __cli() instead.   
 	 */
-	__save_flags(flags);
-	__cli();
+	__save_flags (flags);
+	__cli ();
 
 	rdc_ccw = &ioinfo[irq]->senseccw;
 
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
-		ret = request_irq( irq,
-		                   init_IRQ_handler,
-		                   SA_PROBE, "RDC", &devstat );
+	if (!ioinfo[irq]->ui.flags.ready) {
+		ret = request_irq (irq,
+				   init_IRQ_handler, SA_PROBE, "RDC", &devstat);
 
-		if ( !ret )
-		{
+		if (!ret) {
 			emulated = 1;
 
-		} /* endif */
+		}
 
-	} /* endif */
+	}
 
-	if ( !ret )
-	{
-		if ( ! *buffer )
-		{
-			rdc_buf  = kmalloc( length, GFP_KERNEL);
-		}
-		else
-		{
+	if (!ret) {
+		if (!*buffer) {
+			rdc_buf = kmalloc (length, GFP_KERNEL);
+		} else {
 			rdc_buf = *buffer;
 
-		} /* endif */
+		}
 
-		if ( !rdc_buf )
-		{
+		if (!rdc_buf) {
 			ret = -ENOMEM;
-		}
-		else
-		{
-			do
-			{
+		} else {
+			do {
 				rdc_ccw->cmd_code = CCW_CMD_RDC;
-				rdc_ccw->count    = length;
-				rdc_ccw->flags    = CCW_FLAG_SLI;
-				ret = set_normalized_cda( rdc_ccw, (unsigned long)rdc_buf );
+				rdc_ccw->count = length;
+				rdc_ccw->flags = CCW_FLAG_SLI;
+				ret =
+				    set_normalized_cda (rdc_ccw, (unsigned long)
+							rdc_buf);
 				if (!ret) {
 
-					memset( ioinfo[irq]->irq_desc.dev_id,
-						'\0',
-						sizeof( devstat_t));
-
-					ret = s390_start_IO( irq,
-							     rdc_ccw,
-							     0x00524443, // RDC
-							     0,          // n/a
+					memset (ioinfo[irq]->irq_desc.dev_id,
+						'\0', sizeof (devstat_t));
+
+					ret = s390_start_IO (irq, rdc_ccw, 0x00524443,	/* RDC */
+							     0,	/* n/a */
 							     DOIO_WAIT_FOR_INTERRUPT
-							     | DOIO_DONT_CALL_INTHDLR );
+							     |
+							     DOIO_DONT_CALL_INTHDLR);
 					retry--;
-					devflag = ioinfo[irq]->irq_desc.dev_id->flag;   
-					
-					clear_normalized_cda( rdc_ccw);  
+					devflag =
+					    ioinfo[irq]->irq_desc.dev_id->flag;
+
+					clear_normalized_cda (rdc_ccw);
 				} else {
-					udelay(100);  //wait for recovery
+					udelay (100);	/* wait for recovery */
 					retry--;
 				}
 
-			} while (    ( retry                                     )
-			          && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) );
+			} while ((retry)
+				 && (ret
+				     || (devflag & DEVSTAT_STATUS_PENDING)));
 
-		} /* endif */
+		}
 
-		if ( !retry )
-		{
-			ret = (ret==-ENOMEM)?-ENOMEM:-EBUSY;
+		if (!retry) {
+			ret = (ret == -ENOMEM) ? -ENOMEM : -EBUSY;
 
-		} /* endif */
+		}
 
-		__restore_flags(flags);
+		__restore_flags (flags);
 
 		/*
 		 * on success we update the user input parms
 		 */
-		if ( !ret )
-		{
+		if (!ret) {
 			*buffer = rdc_buf;
 
-		} /* endif */
+		}
 
-		if ( emulated )
-		{
-			free_irq( irq, &devstat);
+		if (emulated) {
+			free_irq (irq, &devstat);
 
-		} /* endif */
+		}
 
-	} /* endif */
+	} else {
+		__restore_flags (flags);
+	}
 
-	return( ret );
+	return (ret);
 }
 
 /*
  *  Read Configuration data
  */
-int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
+int
+read_conf_data (int irq, void **buffer, int *length, __u8 lpm)
 {
 	unsigned long flags;
-	int           ciw_cnt;
+	int ciw_cnt;
 
-	int           found  = 0; // RCD CIW found
-	int           ret    = 0; // return code
+	int found = 0;		/* RCD CIW found */
+	int ret = 0;		/* return code */
 
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
+
+	if (!buffer || !length) {
+		return (-EINVAL);
+	} else if (ioinfo[irq]->ui.flags.oper == 0) {
+		return (-ENODEV);
+	} else if (ioinfo[irq]->ui.flags.esid == 0) {
+		*buffer = NULL;
+		*length = 0;
+		return (-EOPNOTSUPP);
 
-	if ( !buffer || !length )
-	{
-		return( -EINVAL);
-	}
-	else if ( ioinfo[irq]->ui.flags.oper == 0 )
-	{
-		return( -ENODEV );
-	}
-	else if ( ioinfo[irq]->ui.flags.esid == 0 )
-	{
-		return( -EOPNOTSUPP );
-
-	} /* endif */
-
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "rdconf%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
 	}
 
+ 	if (ioinfo[irq]->ui.flags.unfriendly) {
+ 		/* don't even try it */
+ 		return -EUSERS;
+ 	}
+
+	sprintf (dbf_txt, "rcd%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
 	/*
 	 * scan for RCD command in extended SenseID data
 	 */
-	
-	for ( ciw_cnt = 0; (found == 0) && (ciw_cnt < 62); ciw_cnt++ )
-	{
-		if ( ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD )
-		{
+
+	for (ciw_cnt = 0; (found == 0) && (ciw_cnt < MAX_CIWS); ciw_cnt++) {
+		if (ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD) {
 			/*
 			 * paranoia check ...
 			 */
-			if ( ioinfo[irq]->senseid.ciw[ciw_cnt].cmd != 0 )
-			{
+			if (ioinfo[irq]->senseid.ciw[ciw_cnt].cmd != 0
+			    && ioinfo[irq]->senseid.ciw[ciw_cnt].count != 0) {
 				found = 1;
 
-			} /* endif */
+			}
 
 			break;
 
-		} /* endif */
-
-	} /* endfor */
+		}
+	}
 
-	if ( found )
-	{
-		devstat_t  devstat;  /* inline device status area */
+	if (found) {
+		devstat_t devstat;	/* inline device status area */
 		devstat_t *pdevstat;
-		int        ioflags;
+		int ioflags;
 
-		ccw1_t    *rcd_ccw  = &ioinfo[irq]->senseccw;
-		char      *rcd_buf  = NULL;
-		int        emulated = 0; /* no i/O handler installed */
-		int        retry    = 5; /* retry count */
+		ccw1_t *rcd_ccw = &ioinfo[irq]->senseccw;
+		char *rcd_buf = NULL;
+		int emulated = 0;	/* no i/O handler installed */
+		int retry = 5;	/* retry count */
 
-		__save_flags(flags);
-		__cli();
+		__save_flags (flags);
+		__cli ();
 
-		if ( !ioinfo[irq]->ui.flags.ready )
-		{
+		if (!ioinfo[irq]->ui.flags.ready) {
 			pdevstat = &devstat;
-			ret      = request_irq( irq,
-			                        init_IRQ_handler,
-			                        SA_PROBE, "RCD", pdevstat );
+			ret = request_irq (irq,
+					   init_IRQ_handler,
+					   SA_PROBE, "RCD", pdevstat);
 
-			if ( !ret )
-			{
+			if (!ret) {
 				emulated = 1;
 
-			} /* endif */
-		}
-		else
-		{
+			}	/* endif */
+		} else {
 			pdevstat = ioinfo[irq]->irq_desc.dev_id;
 
-		} /* endif */
-
-		if ( !ret )
-		{
-			if ( init_IRQ_complete )
-			{
-				rcd_buf = kmalloc( ioinfo[irq]->senseid.ciw[ciw_cnt].count,
-				                   GFP_DMA);
-			}
-			else
-			{
-				rcd_buf = alloc_bootmem_low( ioinfo[irq]->senseid.ciw[ciw_cnt].count);
+		}		/* endif */
 
-   		} /* endif */
+		if (!ret) {
+			if (init_IRQ_complete) {
+				rcd_buf =
+				    kmalloc (ioinfo[irq]->senseid.ciw[ciw_cnt].
+					     count, GFP_DMA);
+			} else {
+				rcd_buf =
+				    alloc_bootmem_low (ioinfo[irq]->senseid.
+						       ciw[ciw_cnt].count);
 
-			if ( rcd_buf == NULL )
-			{
-				ret = -ENOMEM;	
+			}
 
-			} /* endif */
+			if (rcd_buf == NULL) {
+				ret = -ENOMEM;
 
-			if ( !ret )
-			{
-				memset( rcd_buf,
-				        '\0',
-				        ioinfo[irq]->senseid.ciw[ciw_cnt].count);
-       	
-				do
-				{
-					rcd_ccw->cmd_code = ioinfo[irq]->senseid.ciw[ciw_cnt].cmd;
-					rcd_ccw->cda      = (__u32)virt_to_phys( rcd_buf );
-					rcd_ccw->count    = ioinfo[irq]->senseid.ciw[ciw_cnt].count;
-					rcd_ccw->flags    = CCW_FLAG_SLI;
+			}
+			if (!ret) {
+				memset (rcd_buf,
+					'\0',
+					ioinfo[irq]->senseid.ciw[ciw_cnt].
+					count);
 
-					memset( pdevstat, '\0', sizeof( devstat_t));
+				do {
+					rcd_ccw->cmd_code =
+					    ioinfo[irq]->senseid.ciw[ciw_cnt].
+					    cmd;
+					rcd_ccw->cda =
+					    (__u32) virt_to_phys (rcd_buf);
+					rcd_ccw->count =
+					    ioinfo[irq]->senseid.ciw[ciw_cnt].
+					    count;
+					rcd_ccw->flags = CCW_FLAG_SLI;
+
+					memset (pdevstat, '\0',
+						sizeof (devstat_t));
+
+					if (lpm) {
+						ioflags =
+						    DOIO_WAIT_FOR_INTERRUPT |
+						    DOIO_VALID_LPM |
+						    DOIO_DONT_CALL_INTHDLR;
+					} else {
+						ioflags =
+						    DOIO_WAIT_FOR_INTERRUPT |
+						    DOIO_DONT_CALL_INTHDLR;
 
-					if ( lpm )
-					{
-						ioflags = DOIO_WAIT_FOR_INTERRUPT
-						          | DOIO_VALID_LPM    					
-						          | DOIO_DONT_CALL_INTHDLR;
 					}
-					else
-					{
-						ioflags =   DOIO_WAIT_FOR_INTERRUPT
-						          | DOIO_DONT_CALL_INTHDLR;
-						             					
-					} /* endif */
-
-					ret = s390_start_IO( irq,
-					                     rcd_ccw,
-					                     0x00524344,  // == RCD
-					                     lpm,
-					                     ioflags );
-					switch ( ret ) {
+
+					ret = s390_start_IO (irq, rcd_ccw, 0x00524344,	/* == RCD */
+							     lpm, ioflags);
+					switch (ret) {
 					case 0:
 					case -EIO:
-						
-						if ( !(pdevstat->flag & (   DEVSTAT_STATUS_PENDING
-									    | DEVSTAT_NOT_OPER
-									    | DEVSTAT_FLAG_SENSE_AVAIL ) ) )
+
+						if (!
+						    (pdevstat->
+						     flag &
+						     (DEVSTAT_STATUS_PENDING |
+						      DEVSTAT_NOT_OPER |
+						      DEVSTAT_FLAG_SENSE_AVAIL)))
 						{
-							retry = 0;  // we got it ...
+							retry = 0;	/* we got it ... */
+						} else {
+							retry--;	/* try again ... */
+
 						}
-						else
-						{
-							retry--;    // try again ...
-								
-						} /* endif */
-						
+
 						break;
 
-					default:   // -EBUSY, -ENODEV, ???
+					default:	/* -EBUSY, -ENODEV, ??? */
 						retry = 0;
-						
-					} /* endswitch */
-					
-				} while ( retry );
 
-			} /* endif */
+					}
 
-			__restore_flags( flags );
+				} while (retry);
+			}
+		}
 
-		} /* endif */
+		__restore_flags (flags);
 
 		/*
 		 * on success we update the user input parms
 		 */
-		if ( ret == 0 )
-		{
+		if (ret == 0) {
 			*length = ioinfo[irq]->senseid.ciw[ciw_cnt].count;
 			*buffer = rcd_buf;
-		}
-		else
-		{
-			if ( rcd_buf != NULL )
-			{
-				if ( init_IRQ_complete )
-				{
-					kfree( rcd_buf );
-				}
-				else
-				{
-					free_bootmem( (unsigned long)rcd_buf,
-					              ioinfo[irq]->senseid.ciw[ciw_cnt].count);
+		} else {
+			if (rcd_buf != NULL) {
+				if (init_IRQ_complete) {
+					kfree (rcd_buf);
+				} else {
+					free_bootmem ((unsigned long) rcd_buf,
+						      ioinfo[irq]->senseid.
+						      ciw[ciw_cnt].count);
 
-   			} /* endif */
+				}
 
-			} /* endif */
+			}
 
 			*buffer = NULL;
 			*length = 0;
-    	
-		} /* endif */
 
-		if ( emulated )
-			free_irq( irq, pdevstat);
-	}
-	else
-	{
+		}
+
+		if (emulated)
+			free_irq (irq, pdevstat);
+	} else {
+		*buffer = NULL;
+		*length = 0;
 		ret = -EOPNOTSUPP;
 
-	} /* endif */
+	}
 
-	return( ret );
+	return (ret);
 
 }
 
-int get_dev_info( int irq, s390_dev_info_t * pdi)
+int
+get_dev_info (int irq, s390_dev_info_t * pdi)
 {
-	return( get_dev_info_by_irq( irq, pdi));
+	return (get_dev_info_by_irq (irq, pdi));
 }
 
-static int __inline__ get_next_available_irq( ioinfo_t *pi)
+static int __inline__
+get_next_available_irq (ioinfo_t * pi)
 {
 	int ret_val = -ENODEV;
 
-	while ( pi!=NULL ) {
-		if ( pi->ui.flags.oper ) {
+	while (pi != NULL) {
+		if ((!pi->st) 
+		    && (pi->ui.flags.oper)
+		    && (!pi->ui.flags.unfriendly)) {
 			ret_val = pi->irq;
 			break;
 		} else {
@@ -4292,214 +4332,200 @@
 	return ret_val;
 }
 
-
-int get_irq_first( void )
+int
+get_irq_first (void)
 {
-   int ret_irq;
+	int ret_irq;
 
-	if ( ioinfo_head )
-	{
-		if ( ioinfo_head->ui.flags.oper )
-		{
+	if (ioinfo_head) {
+		if ((ioinfo_head->ui.flags.oper) && 
+		    (!ioinfo_head->ui.flags.unfriendly) &&
+		    (!ioinfo_head->st)) {
 			ret_irq = ioinfo_head->irq;
-		}
-		else if ( ioinfo_head->next )
-		{
-			ret_irq = get_next_available_irq( ioinfo_head->next );
+		} else if (ioinfo_head->next) {
+			ret_irq = get_next_available_irq (ioinfo_head->next);
 
-		}
-		else
-		{
+		} else {
 			ret_irq = -ENODEV;
-   	
-		} /* endif */
-	}
-	else
-	{
+
+		}
+	} else {
 		ret_irq = -ENODEV;
 
-	} /* endif */
+	}
 
 	return ret_irq;
 }
 
-int get_irq_next( int irq )
+int
+get_irq_next (int irq)
 {
-	int ret_irq;	
+	int ret_irq;
 
-	if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-	{
-		if ( ioinfo[irq]->next )
-		{
-			if ( ioinfo[irq]->next->ui.flags.oper )
-			{
+	if (ioinfo[irq] != INVALID_STORAGE_AREA) {
+		if (ioinfo[irq]->next) {
+			if ((ioinfo[irq]->next->ui.flags.oper) &&
+			    (!ioinfo[irq]->next->ui.flags.unfriendly) &&
+			    (!ioinfo[irq]->next->st)) {
 				ret_irq = ioinfo[irq]->next->irq;
+			} else {
+				ret_irq =
+				    get_next_available_irq (ioinfo[irq]->next);
+
 			}
-			else
-			{
-				ret_irq = get_next_available_irq( ioinfo[irq]->next );
+		} else {
+			ret_irq = -ENODEV;
 
-			} /* endif */
 		}
-		else
-		{
-			ret_irq = -ENODEV;     	
-
-		} /* endif */
-	}
-	else
-	{
+	} else {
 		ret_irq = -EINVAL;
 
-	} /* endif */
+	}
 
 	return ret_irq;
 }
 
-int get_dev_info_by_irq( int irq, s390_dev_info_t *pdi)
+int
+get_dev_info_by_irq (int irq, s390_dev_info_t * pdi)
 {
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if ( pdi == NULL )
+	if (pdi == NULL)
 		return -EINVAL;
 
 	pdi->devno = ioinfo[irq]->schib.pmcw.dev;
-	pdi->irq   = irq;
-	
-	if (   ioinfo[irq]->ui.flags.oper
-	    && !ioinfo[irq]->ui.flags.unknown ) 
-	{
+	pdi->irq = irq;
+
+	if (ioinfo[irq]->ui.flags.oper && !ioinfo[irq]->ui.flags.unknown) {
 		pdi->status = 0;
-		memcpy( &(pdi->sid_data),
-			&ioinfo[irq]->senseid,
-			sizeof( senseid_t));
-	}
-	else if ( ioinfo[irq]->ui.flags.unknown )
-	{
+		memcpy (&(pdi->sid_data),
+			&ioinfo[irq]->senseid, sizeof (senseid_t));
+ 
+ 	} else if (ioinfo[irq]->ui.flags.unfriendly) {
+ 		pdi->status = DEVSTAT_UNFRIENDLY_DEV;
+ 		memset (&(pdi->sid_data), '\0', sizeof (senseid_t));
+ 		pdi->sid_data.cu_type = 0xFFFF;
+
+	} else if (ioinfo[irq]->ui.flags.unknown) {
 		pdi->status = DEVSTAT_UNKNOWN_DEV;
-		memset( &(pdi->sid_data),
-			'\0',
-			sizeof( senseid_t));
+		memset (&(pdi->sid_data), '\0', sizeof (senseid_t));
 		pdi->sid_data.cu_type = 0xFFFF;
-			
-	}
-	else
-	{
+
+	} else {
 		pdi->status = DEVSTAT_NOT_OPER;
-		memset( &(pdi->sid_data),
-			'\0',
-			sizeof( senseid_t));
+		memset (&(pdi->sid_data), '\0', sizeof (senseid_t));
 		pdi->sid_data.cu_type = 0xFFFF;
-		
-	} /* endif */
-	
-	if ( ioinfo[irq]->ui.flags.ready )
-		pdi->status |= DEVSTAT_DEVICE_OWNED;
 
+	}
+
+	if (ioinfo[irq]->ui.flags.ready)
+		pdi->status |= DEVSTAT_DEVICE_OWNED;
 
 	return 0;
 }
 
-
-int get_dev_info_by_devno( __u16 devno, s390_dev_info_t *pdi)
+int
+get_dev_info_by_devno (__u16 devno, s390_dev_info_t * pdi)
 {
 	int i;
 	int rc = -ENODEV;
 
-	if ( devno > 0x0000ffff )
+	if (devno > 0x0000ffff)
 		return -ENODEV;
-        if ( pdi == NULL )
+	if (pdi == NULL)
 		return -EINVAL;
 
-	for ( i=0; i <= highest_subchannel; i++ ) {
-		
-		if (    ioinfo[i] != INVALID_STORAGE_AREA
-		     && ioinfo[i]->schib.pmcw.dev == devno )
-		{
-			
-			pdi->irq   = i;
+	for (i = 0; i <= highest_subchannel; i++) {
+
+		if ((ioinfo[i] != INVALID_STORAGE_AREA) &&
+		    (!ioinfo[i]->st) &&
+		    (ioinfo[i]->schib.pmcw.dev == devno)) {
+
+			pdi->irq = i;
 			pdi->devno = devno;
-			
-			if (    ioinfo[i]->ui.flags.oper
-			     && !ioinfo[i]->ui.flags.unknown )
-			{
+
+			if (ioinfo[i]->ui.flags.oper
+			    && !ioinfo[i]->ui.flags.unknown) {
 				pdi->status = 0;
-				memcpy( &(pdi->sid_data),
+				memcpy (&(pdi->sid_data),
 					&ioinfo[i]->senseid,
-					sizeof( senseid_t));
-			}
-			else if ( ioinfo[i]->ui.flags.unknown )
-			{
+					sizeof (senseid_t));
+ 
+ 			} else if (ioinfo[i]->ui.flags.unfriendly) {
+ 				pdi->status = DEVSTAT_UNFRIENDLY_DEV;
+ 				memset (&(pdi->sid_data), '\0', 
+ 					sizeof (senseid_t));
+ 				pdi->sid_data.cu_type = 0xFFFF;
+ 
+
+			} else if (ioinfo[i]->ui.flags.unknown) {
 				pdi->status = DEVSTAT_UNKNOWN_DEV;
 
-				memset( &(pdi->sid_data),
-					'\0',
-					sizeof( senseid_t));
+				memset (&(pdi->sid_data),
+					'\0', sizeof (senseid_t));
 
 				pdi->sid_data.cu_type = 0xFFFF;
-			}
-			else
-			{
+			} else {
 				pdi->status = DEVSTAT_NOT_OPER;
-				
-				memset( &(pdi->sid_data),
-					'\0',
-					sizeof( senseid_t));
+
+				memset (&(pdi->sid_data),
+					'\0', sizeof (senseid_t));
 
 				pdi->sid_data.cu_type = 0xFFFF;
 
-			} /* endif */
+			}
 
-			if ( ioinfo[i]->ui.flags.ready )
+			if (ioinfo[i]->ui.flags.ready)
 				pdi->status |= DEVSTAT_DEVICE_OWNED;
 
-			rc = 0; /* found */
+			if (!ioinfo[i]->ui.flags.unfriendly)
+				rc = 0;	/* found */
+			else
+				rc = -EUSERS;
 			break;
 
-		} /* endif */
-
-	} /* endfor */
+		}
+	}
 
-	return( rc);
+	return (rc);
 
 }
 
-int get_irq_by_devno( __u16 devno )
+int
+get_irq_by_devno (__u16 devno)
 {
 	int i;
 	int rc = -1;
 
-	if ( devno <= 0x0000ffff )
-	{
-		for ( i=0; i <= highest_subchannel; i++ )
-		{
-			if (    (ioinfo[i] != INVALID_STORAGE_AREA )
-			     && (ioinfo[i]->schib.pmcw.dev == devno)
-			     && (ioinfo[i]->schib.pmcw.dnv == 1    ) )
-			{
+	if (devno <= 0x0000ffff) {
+		for (i = 0; i <= highest_subchannel; i++) {
+			if ((ioinfo[i] != INVALID_STORAGE_AREA)
+			    && (!ioinfo[i]->st)
+			    && (ioinfo[i]->schib.pmcw.dev == devno)
+			    && (ioinfo[i]->schib.pmcw.dnv == 1)) {
 				rc = i;
 				break;
+			}
+		}
+	}
 
-			} /* endif */
-
-		} /* endfor */
-	
-	} /* endif */
-
-	return( rc);
+	return (rc);
 }
 
-unsigned int get_devno_by_irq( int irq )
+unsigned int
+get_devno_by_irq (int irq)
 {
 
-	if (    ( irq > highest_subchannel            )
-	     || ( irq < 0                             )
-	     || ( ioinfo[irq] == INVALID_STORAGE_AREA ) )
-	{
+	if ((irq > highest_subchannel)
+	    || (irq < 0)
+	    || (ioinfo[irq] == INVALID_STORAGE_AREA)) {
+		return -1;
+
+	}
+
+	if (ioinfo[irq]->st) 
 		return -1;
-	
-	} /* endif */
 
 	/*
 	 * we don't need to check for the device be operational
@@ -4508,8 +4534,8 @@
 	 *  existing or not. However, there could be subchannels
 	 *  defined who's device number isn't valid ...
 	 */
-	if ( ioinfo[irq]->schib.pmcw.dnv )
-		return( ioinfo[irq]->schib.pmcw.dev );
+	if (ioinfo[irq]->schib.pmcw.dnv)
+		return (ioinfo[irq]->schib.pmcw.dev);
 	else
 		return -1;
 }
@@ -4521,102 +4547,138 @@
  *  independant SenseID command to obtain info the device type.
  *
  */
-void s390_device_recognition_irq( int irq )
+void
+s390_device_recognition_irq (int irq)
 {
-	int           ret;
+	int ret;
 	char dbf_txt[15];
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "devrec%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "dri%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
 	/*
 	 * We issue the SenseID command on I/O subchannels we think are
 	 *  operational only.
 	 */
-	if (    ( ioinfo[irq] != INVALID_STORAGE_AREA )	
-	     && ( ioinfo[irq]->schib.pmcw.st == 0     )
-	     && ( ioinfo[irq]->ui.flags.oper == 1     ) )
-	{
-		int       irq_ret;
+	if ((ioinfo[irq] != INVALID_STORAGE_AREA)
+	    && (!ioinfo[irq]->st)
+	    && (ioinfo[irq]->schib.pmcw.st == 0)
+	    && (ioinfo[irq]->ui.flags.oper == 1)) {
+		int irq_ret;
 		devstat_t devstat;
 
-		irq_ret = request_irq( irq,
-		                       init_IRQ_handler,
-		                       SA_PROBE,
-		                       "INIT",
-		                       &devstat);
-
-		if ( !irq_ret )
-		{
-			ret = enable_cpu_sync_isc( irq );
+		irq_ret = request_irq (irq,
+				       init_IRQ_handler,
+				       SA_PROBE, "INIT", &devstat);
 
-			if ( !ret ) 
-			{
-				ioinfo[irq]->ui.flags.unknown = 0;
+		if (!irq_ret) {
+			ret = enable_cpu_sync_isc (irq);
 
-				memset( &ioinfo[irq]->senseid, '\0', sizeof( senseid_t));
+			if (!ret) {
+ 				pgid_t pgid;
+ 				/*
+ 				 * First thing we should do is a sensePGID in
+ 				 * order to find out how we can proceed with
+ 				 * the recognition process. 
+ 				 * An unfriendly (locked by so else) device 
+ 				 * won't take kindly to our attempts at 
+ 				 * SetPGID and SenseID...
+ 				 */
+  
+ 				memcpy(&pgid, global_pgid, sizeof(pgid_t));
+ 				ret = s390_SensePGID(irq, 0xff, &pgid);
+
+				if (ret == -EOPNOTSUPP) 
+					/* 
+					 * Doesn't prevent us from proceeding
+					 */
+					ret = 0;
+ 				
+ 				if (!ret && !ioinfo[irq]->ui.flags.unfriendly) {
+
+					ioinfo[irq]->ui.flags.unknown = 0;
+					
+					memset (&ioinfo[irq]->senseid, '\0',
+						sizeof (senseid_t));
+					
+					if (cio_sid_with_pgid) {
+						
+						ret = s390_DevicePathVerification(irq,0);
+						
+						if (ret == -EOPNOTSUPP) 
+							/* 
+							 * Doesn't prevent us from proceeding
+							 */
+							ret = 0;
+					}
 
-				s390_SenseID( irq, &ioinfo[irq]->senseid, 0xff );
-#if 0	/* FIXME */
+					/*
+					 * we'll fallthrough here if we don't want
+					 * to do SPID before SID
+					 */
+					if (!ret) {
+						s390_SenseID (irq, &ioinfo[irq]->senseid, 0xff);
+#if 0				/* FIXME */
 				/*
 				 * We initially check the configuration data for
 				 *  those devices with more than a single path
 				 */
-				if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
-				{
-					char     *prcd;
-					int       lrcd;
+				if (ioinfo[irq]->schib.pmcw.pim != 0x80) {
+					char *prcd;
+					int lrcd;
+
+					ret =
+					    read_conf_data (irq,
+							    (void **) &prcd,
+							    &lrcd, 0);
 
-					ret = read_conf_data( irq, (void **)&prcd, &lrcd, 0 );
-
-					if ( !ret )	// on success only ...
+					if (!ret)	// on success only ...
 					{
 						char buffer[80];
 #ifdef CONFIG_DEBUG_IO
-						sprintf( buffer,
-						         "RCD for device(%04X)/"
-						         "subchannel(%04X) returns :\n",
-						         ioinfo[irq]->schib.pmcw.dev,
-						         irq );
+						sprintf (buffer,
+							 "RCD for device(%04X)/"
+							 "subchannel(%04X) returns :\n",
+							 ioinfo[irq]->schib.
+							 pmcw.dev, irq);
 
-						s390_displayhex( buffer, prcd, lrcd );
-#endif      				
+						s390_displayhex (buffer, prcd,
+								 lrcd);
+#endif
 						if (cio_debug_initialized) {
-							sprintf( buffer,
+							sprintf (buffer,
 								 "RCD for device(%04X)/"
 								 "subchannel(%04X) returns :\n",
-								 ioinfo[irq]->schib.pmcw.dev,
-								 irq );
-							
-							s390_displayhex2( buffer, prcd, lrcd, 2);
-						}
-						if ( init_IRQ_complete )
-						{
-							kfree( prcd );
+								 ioinfo[irq]->
+								 schib.pmcw.dev,
+								 irq);
+
+							s390_displayhex2
+							    (buffer, prcd, lrcd,
+							     2);
 						}
-						else
-						{
-							free_bootmem( (unsigned long)prcd, lrcd );
-
- 			  			} /* endif */
+						if (init_IRQ_complete) {
+							kfree (prcd);
+						} else {
+							free_bootmem ((unsigned
+								       long)
+								      prcd,
+								      lrcd);
 
-					} /* endif */
-					
-				} /* endif */
+						}
+					}
+				}
 #endif
+					}
+				}
+				disable_cpu_sync_isc (irq);
 
-				disable_cpu_sync_isc( irq );
-
-			} /* endif */  	
-
-			free_irq( irq, &devstat );
+			}
 
-		} /* endif */
-		
-	} /* endif */
+			free_irq (irq, &devstat);
 
+		}
+	}
 }
 
 /*
@@ -4625,17 +4687,17 @@
  * Used for system wide device recognition.
  *
  */
-void s390_device_recognition_all( void)
+void
+s390_device_recognition_all (void)
 {
-	int irq = 0; /* let's start with subchannel 0 ... */
+	int irq = 0;		/* let's start with subchannel 0 ... */
 
-	do
-	{
-		s390_device_recognition_irq( irq );
+	do {
+		s390_device_recognition_irq (irq);
 
-		irq ++;
+		irq++;
 
-	} while ( irq <= highest_subchannel );
+	} while (irq <= highest_subchannel);
 
 }
 
@@ -4645,39 +4707,72 @@
  * FIXME: there must be a better way to do this...
  */
 
-void s390_redo_validation(void) 
+void
+s390_redo_validation (void)
 {
 	int irq = 0;
 	int ret;
 
-	if (cio_debug_initialized) {
-		debug_text_event(cio_debug_trace_id, 0, "redoval");
-	}
+	CIO_TRACE_EVENT (0, "redoval");
+
 	do {
 		if (ioinfo[irq] == INVALID_STORAGE_AREA) {
-			ret = s390_validate_subchannel(irq, 0);
+			ret = s390_validate_subchannel (irq, 0);
 			if (!ret) {
-				s390_device_recognition_irq(irq);
+				s390_device_recognition_irq (irq);
 				if (ioinfo[irq]->ui.flags.oper) {
 					devreg_t *pdevreg;
-					
-					pdevreg = s390_search_devreg( ioinfo[irq] );
-					if ( pdevreg != NULL ) {
-						if ( pdevreg->oper_func != NULL )
-							pdevreg->oper_func( irq, pdevreg );
-						
-					} 
+
+					pdevreg =
+					    s390_search_devreg (ioinfo[irq]);
+					if (pdevreg != NULL) {
+						if (pdevreg->oper_func != NULL)
+							pdevreg->oper_func (irq,
+									    pdevreg);
+
+					}
 				}
 #ifdef CONFIG_PROC_FS
-				if (cio_proc_devinfo) 
+				if (cio_proc_devinfo)
 					if (irq < MAX_CIO_PROCFS_ENTRIES) {
-						cio_procfs_device_create(ioinfo[irq]->devno);
-				}
+						cio_procfs_device_create (ioinfo
+									  [irq]->
+									  devno);
+					}
 #endif
 			}
 		}
 		irq++;
-	} while (irq<=highest_subchannel);
+	} while (irq <= highest_subchannel);
+}
+
+
+/*
+ * s390_trigger_resense
+ *
+ * try to re-sense the device on subchannel irq
+ * only to be called without interrupt handler
+ */
+int
+s390_trigger_resense(int irq)
+{
+	char dbf_txt[8];
+
+	SANITY_CHECK(irq);
+
+	CIO_TRACE_EVENT (2, "tsns");
+	sprintf(dbf_txt, "%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	if (ioinfo[irq]->ui.flags.ready) {
+		printk (KERN_WARNING "s390_trigger_resense(%04X): "
+			"Device is in use!\n", irq);
+		return -EBUSY;
+	}
+
+	s390_device_recognition_irq(irq);
+
+	return 0;
 }
 
 /*
@@ -4686,28 +4781,27 @@
  * Determines all subchannels available to the system.
  *
  */
-void s390_process_subchannels( void)
+void
+s390_process_subchannels (void)
 {
-	int   ret;
-	int   irq = 0;   /* Evaluate all subchannels starting with 0 ... */
+	int ret;
+	int irq = 0;		/* Evaluate all subchannels starting with 0 ... */
 
-	do
-	{
-		ret = s390_validate_subchannel( irq, 0);
+	do {
+		ret = s390_validate_subchannel (irq, 0);
 
-		if ( ret != -ENXIO)
+		if (ret != -ENXIO)
 			irq++;
-	
-  	} while ( (ret != -ENXIO) && (irq < __MAX_SUBCHANNELS) );
+
+	} while ((ret != -ENXIO) && (irq < __MAX_SUBCHANNELS));
 
 	highest_subchannel = (--irq);
 
-	printk( KERN_INFO "Highest subchannel number detected (hex) : %04X\n",
-	        highest_subchannel);
-	if (cio_debug_initialized)
-		debug_sprintf_event(cio_debug_msg_id, 0, 
-				    "Highest subchannel number detected (hex) : %04X\n",
-				    highest_subchannel);	
+	printk (KERN_INFO "Highest subchannel number detected (hex) : %04X\n",
+		highest_subchannel);
+	CIO_MSG_EVENT(0,
+		      "Highest subchannel number detected "
+		      "(hex) : %04X\n", highest_subchannel);
 }
 
 /*
@@ -4716,362 +4810,357 @@
  * Process the subchannel for the requested irq. Returns 1 for valid
  *  subchannels, otherwise 0.
  */
-int s390_validate_subchannel( int irq, int enable )
+int
+s390_validate_subchannel (int irq, int enable)
 {
 
-	int      retry;     /* retry count for status pending conditions */
-	int      ccode;     /* condition code for stsch() only */
-	int      ccode2;    /* condition code for other I/O routines */
+	int retry;		/* retry count for status pending conditions */
+	int ccode;		/* condition code for stsch() only */
+	int ccode2;		/* condition code for other I/O routines */
 	schib_t *p_schib;
-	int      ret;
-	
+	int ret;
+#ifdef CONFIG_CHSC
+	int      chp = 0;
+	int      mask;
+#endif /* CONFIG_CHSC */
+
 	char dbf_txt[15];
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "valsch%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "vals%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
 	/*
 	 * The first subchannel that is not-operational (ccode==3)
 	 *  indicates that there aren't any more devices available.
 	 */
-	if (    ( init_IRQ_complete                   )
-	     && ( ioinfo[irq] != INVALID_STORAGE_AREA ) )
-	{
+	if ((init_IRQ_complete)
+	    && (ioinfo[irq] != INVALID_STORAGE_AREA)) {
 		p_schib = &ioinfo[irq]->schib;
-	}
-	else
-	{
+	} else {
 		p_schib = p_init_schib;
 
-	} /* endif */
+	}
 
 	/*
-	 * If we knew the device before we assume the worst case ... 	
+	 * If we knew the device before we assume the worst case ...    
 	 */
-	if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-	{
+	if (ioinfo[irq] != INVALID_STORAGE_AREA) {
 		ioinfo[irq]->ui.flags.oper = 0;
 		ioinfo[irq]->ui.flags.dval = 0;
 
-	} /* endif */
+	}
 
-	ccode = stsch( irq, p_schib);
+	ccode = stsch (irq, p_schib);
 
-	if ( !ccode )
-	{
-		/*
-		 * ... just being curious we check for non I/O subchannels
-		 */
-		if ( p_schib->pmcw.st )
-		{
-			printk( KERN_INFO "Subchannel %04X reports "
-			        "non-I/O subchannel type %04X\n",
-			        irq,
-			        p_schib->pmcw.st);
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_msg_id, 0,
-						    "Subchannel %04X reports non-I/O subchannel type %04X\n",
-						    irq, p_schib->pmcw.st);
+	if (ccode) {
+		return -ENXIO;
+	}
+	/*
+	 * ... just being curious we check for non I/O subchannels
+	 */
+	if (p_schib->pmcw.st) {
+		if (cio_show_msg) {
+			printk (KERN_INFO "Subchannel %04X reports "
+				"non-I/O subchannel type %04X\n",
+				irq, p_schib->pmcw.st);
+		}
+		CIO_MSG_EVENT(0,
+			      "Subchannel %04X reports "
+			      "non-I/O subchannel type %04X\n",
+			      irq, p_schib->pmcw.st);
 
-			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-				ioinfo[irq]->ui.flags.oper = 0;
+		if (ioinfo[irq] != INVALID_STORAGE_AREA)
+			ioinfo[irq]->ui.flags.oper = 0;
 
-		} /* endif */
+	}
 
-		if ( p_schib->pmcw.dnv )
-		{
-		     if ( is_blacklisted( p_schib->pmcw.dev )) {
-			  /* 
-			   * This device must not be known to Linux. So we simply say that 
-			   * there is no device and return ENODEV.
-			   */
+	if ((!p_schib->pmcw.dnv) && (!p_schib->pmcw.st)) {
+		return -ENODEV;
+	}
+	if (!p_schib->pmcw.st) {
+		if (is_blacklisted (p_schib->pmcw.dev)) {
+			/* 
+			 * This device must not be known to Linux. So we simply say that 
+			 * there is no device and return ENODEV.
+			 */
 #ifdef CONFIG_DEBUG_IO
-			  printk( KERN_DEBUG "Blacklisted device detected at devno %04X\n", p_schib->pmcw.dev );
-#endif
-			  if (cio_debug_initialized)
-				  debug_sprintf_event(cio_debug_msg_id, 0,
-						      "Blacklisted device detected at devno %04X\n",
-						      p_schib->pmcw.dev);
-			  ret = -ENODEV;
-		     } else {
-		        if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-			{	
-				if ( !init_IRQ_complete )
-				{
-					ioinfo[irq] =
-					   (ioinfo_t *)alloc_bootmem_low( sizeof(ioinfo_t));
-				}
-				else
-				{
-					ioinfo[irq] =
-					   (ioinfo_t *)kmalloc( sizeof(ioinfo_t),
-				                           GFP_DMA );
-
-				} /* endif */
-
-				memset( ioinfo[irq], '\0', sizeof( ioinfo_t));
-				memcpy( &ioinfo[irq]->schib,
-			           p_init_schib,
-			           sizeof( schib_t));
-			
-				/*
-				 * We have to insert the new ioinfo element
-				 *  into the linked list, either at its head,
-				 *  its tail or insert it.
-				 */
-				if ( ioinfo_head == NULL )  /* first element */
-				{
-					ioinfo_head = ioinfo[irq];
-					ioinfo_tail = ioinfo[irq];
-				}
-				else if ( irq < ioinfo_head->irq ) /* new head */
-				{
-					ioinfo[irq]->next = ioinfo_head;
-					ioinfo_head->prev = ioinfo[irq];
-					ioinfo_head       = ioinfo[irq];
-				}
-				else if ( irq > ioinfo_tail->irq ) /* new tail */
-				{
-					ioinfo_tail->next = ioinfo[irq];
-					ioinfo[irq]->prev = ioinfo_tail;
-					ioinfo_tail       = ioinfo[irq];
-				}
-				else /* insert element */
-				{
-					ioinfo_t *pi = ioinfo_head;
+			printk (KERN_DEBUG
+				"Blacklisted device detected at devno %04X\n",
+				p_schib->pmcw.dev);
+#endif
+			CIO_MSG_EVENT(0,
+				      "Blacklisted device detected at devno %04X\n",
+				      p_schib->pmcw.dev);
+			return -ENODEV;
+		}
+	}
+	
+	if (ioinfo[irq] == INVALID_STORAGE_AREA) {
+		if (!init_IRQ_complete) {
+			ioinfo[irq] = (ioinfo_t *)
+			    alloc_bootmem_low (sizeof (ioinfo_t));
+		} else {
+			ioinfo[irq] = (ioinfo_t *)
+			    kmalloc (sizeof (ioinfo_t), GFP_DMA);
 
-					for (pi=ioinfo_head; pi!=NULL; pi=pi->next) {
+		}
 
-						if ( irq < pi->next->irq )
-						{
-							ioinfo[irq]->next = pi->next;
-							ioinfo[irq]->prev = pi;
-							pi->next->prev    = ioinfo[irq];
-							pi->next          = ioinfo[irq];
-							break;
-						
-						} /* endif */
-					}
-				} /* endif */
+		memset (ioinfo[irq], '\0', sizeof (ioinfo_t));
+		memcpy (&ioinfo[irq]->schib, p_init_schib, sizeof (schib_t));
 
-			} /* endif */
+		/*
+		 * We have to insert the new ioinfo element
+		 *  into the linked list, either at its head,
+		 *  its tail or insert it.
+		 */
+		if (ioinfo_head == NULL) {	/* first element */
+			ioinfo_head = ioinfo[irq];
+			ioinfo_tail = ioinfo[irq];
+		} else if (irq < ioinfo_head->irq) {	/* new head */
+			ioinfo[irq]->next = ioinfo_head;
+			ioinfo_head->prev = ioinfo[irq];
+			ioinfo_head = ioinfo[irq];
+		} else if (irq > ioinfo_tail->irq) {	/* new tail */
+			ioinfo_tail->next = ioinfo[irq];
+			ioinfo[irq]->prev = ioinfo_tail;
+			ioinfo_tail = ioinfo[irq];
+		} else {	/* insert element */
 
-			// initialize some values ...	
-			ioinfo[irq]->ui.flags.pgid_supp = 1;
+			ioinfo_t *pi = ioinfo_head;
 
-			ioinfo[irq]->opm =   ioinfo[irq]->schib.pmcw.pim
-			                   & ioinfo[irq]->schib.pmcw.pam
-			                   & ioinfo[irq]->schib.pmcw.pom;
+			for (pi = ioinfo_head; pi != NULL; pi = pi->next) {
 
-			if ( cio_show_msg )
-			{
-				printk( KERN_INFO"Detected device %04X "
-				        "on subchannel %04X"
-				        " - PIM = %02X, PAM = %02X, POM = %02X\n",
-				        ioinfo[irq]->schib.pmcw.dev,
-				        irq,
-			   	     ioinfo[irq]->schib.pmcw.pim,
-			      	  ioinfo[irq]->schib.pmcw.pam,
-			 	       ioinfo[irq]->schib.pmcw.pom);
-
-			} /* endif */
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_msg_id, 0,
-						    "Detected device %04X "
-						    "on subchannel %04X"
-						    " - PIM = %02X, PAM = %02X, POM = %02X\n",
-						    ioinfo[irq]->schib.pmcw.dev,
-						    irq,
-						    ioinfo[irq]->schib.pmcw.pim,
-						    ioinfo[irq]->schib.pmcw.pam,
-						    ioinfo[irq]->schib.pmcw.pom);
+				if (irq < pi->next->irq) {
+					ioinfo[irq]->next = pi->next;
+					ioinfo[irq]->prev = pi;
+					pi->next->prev = ioinfo[irq];
+					pi->next = ioinfo[irq];
+					break;
 
-			/*
-			 * initialize ioinfo structure
-			 */
-			ioinfo[irq]->irq             = irq;
-			if(!ioinfo[irq]->ui.flags.ready)
-			{
-				ioinfo[irq]->nopfunc         = NULL;
-				ioinfo[irq]->ui.flags.busy   = 0;
-				ioinfo[irq]->ui.flags.dval   = 1;
-				ioinfo[irq]->devstat.intparm = 0;
-				
+				}
 			}
-			ioinfo[irq]->devstat.devno   = ioinfo[irq]->schib.pmcw.dev;
-			ioinfo[irq]->devno           = ioinfo[irq]->schib.pmcw.dev;
+		}
+	}
 
-			/*
-			 * We should have at least one CHPID ...
-			 */
-			if ( ioinfo[irq]->opm )
-			{
+	/* initialize some values ... */
+	ioinfo[irq]->irq = irq;
+	ioinfo[irq]->st = ioinfo[irq]->schib.pmcw.st;
+	if (ioinfo[irq]->st)
+		return -ENODEV;
+
+	ioinfo[irq]->ui.flags.pgid_supp = 1;
+
+	ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim
+	    & ioinfo[irq]->schib.pmcw.pam & ioinfo[irq]->schib.pmcw.pom;
+
+#ifdef CONFIG_CHSC
+	if (ioinfo[irq]->opm) {
+		for (chp=0;chp<=7;chp++) {
+			mask = 0x80 >> chp;
+			if (ioinfo[irq]->opm & mask) {
+				if (!test_bit
+				    (ioinfo[irq]->schib.pmcw.chpid[chp], 
+				     &chpids_logical)) {
+					/* disable using this path */
+					ioinfo[irq]->opm &= ~mask;
+				}
+			}
+		}
+	}
+#endif /* CONFIG_CHSC */
+
+	if (cio_show_msg) {
+		printk (KERN_INFO
+			"Detected device %04X "
+			"on subchannel %04X"
+			" - PIM = %02X, PAM = %02X, POM = %02X\n",
+			ioinfo[irq]->schib.pmcw.dev,
+			irq,
+			ioinfo[irq]->schib.pmcw.pim,
+			ioinfo[irq]->schib.pmcw.pam,
+			ioinfo[irq]->schib.pmcw.pom);
+
+	}
+	CIO_MSG_EVENT(0,
+		      "Detected device %04X "
+		      "on subchannel %04X"
+		      " - PIM = %02X, "
+		      "PAM = %02X, POM = %02X\n",
+		      ioinfo[irq]->schib.pmcw.dev, 
+		      irq,
+		      ioinfo[irq]->schib.pmcw.pim,
+		      ioinfo[irq]->schib.pmcw.pam, 
+		      ioinfo[irq]->schib.pmcw.pom);
+
+	/*
+	 * initialize ioinfo structure
+	 */
+	if (!ioinfo[irq]->ui.flags.ready) {
+		ioinfo[irq]->nopfunc = NULL;
+		ioinfo[irq]->ui.flags.busy = 0;
+		ioinfo[irq]->ui.flags.dval = 1;
+		ioinfo[irq]->devstat.intparm = 0;
+
+	}
+	ioinfo[irq]->devstat.devno = ioinfo[irq]->schib.pmcw.dev;
+	ioinfo[irq]->devno = ioinfo[irq]->schib.pmcw.dev;
+
+	/*
+	 * We should have at least one CHPID ...
+	 */
+	if (ioinfo[irq]->opm) {
+		/*
+		 * We now have to initially ...
+		 *  ... set "interruption sublass"
+		 *  ... enable "concurrent sense"
+		 *  ... enable "multipath mode" if more than one
+		 *        CHPID is available. This is done regardless
+		 *        whether multiple paths are available for us.
+		 *
+		 * Note : we don't enable the device here, this is temporarily
+		 *        done during device sensing below.
+		 */
+		ioinfo[irq]->schib.pmcw.isc = 3;	/* could be smth. else */
+		ioinfo[irq]->schib.pmcw.csense = 1;	/* concurrent sense */
+		ioinfo[irq]->schib.pmcw.ena = enable;
+		ioinfo[irq]->schib.pmcw.intparm = ioinfo[irq]->schib.pmcw.dev;
+
+		if ((ioinfo[irq]->opm != 0x80)
+		    && (ioinfo[irq]->opm != 0x40)
+		    && (ioinfo[irq]->opm != 0x20)
+		    && (ioinfo[irq]->opm != 0x10)
+		    && (ioinfo[irq]->opm != 0x08)
+		    && (ioinfo[irq]->opm != 0x04)
+		    && (ioinfo[irq]->opm != 0x02)
+		    && (ioinfo[irq]->opm != 0x01)) {
+			ioinfo[irq]->schib.pmcw.mp = 1;	/* multipath mode */
+
+		}
+
+		retry = 5;
+
+		do {
+			ccode2 = msch_err (irq, &ioinfo[irq]->schib);
+
+			switch (ccode2) {
+			case 0:
 				/*
-				 * We now have to initially ...
-				 *  ... set "interruption sublass"
-				 *  ... enable "concurrent sense"
-				 *  ... enable "multipath mode" if more than one
-				 *        CHPID is available. This is done regardless
-				 *        whether multiple paths are available for us.
+				 * successful completion
 				 *
-				 * Note : we don't enable the device here, this is temporarily
-				 *        done during device sensing below.
+				 * concurrent sense facility available
 				 */
-				ioinfo[irq]->schib.pmcw.isc     = 3; /* could be smth. else */
-				ioinfo[irq]->schib.pmcw.csense  = 1; /* concurrent sense */
-				ioinfo[irq]->schib.pmcw.ena     = enable;
-				ioinfo[irq]->schib.pmcw.intparm =
-				                     ioinfo[irq]->schib.pmcw.dev;
-
-				if (    ( ioinfo[irq]->opm != 0x80 )
-				     && ( ioinfo[irq]->opm != 0x40 )
-				     && ( ioinfo[irq]->opm != 0x20 )
-				     && ( ioinfo[irq]->opm != 0x10 )
-				     && ( ioinfo[irq]->opm != 0x08 )
-				     && ( ioinfo[irq]->opm != 0x04 )
-				     && ( ioinfo[irq]->opm != 0x02 )
-				     && ( ioinfo[irq]->opm != 0x01 ) )
-				{
-					ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */
-
-				} /* endif */
-
-				retry = 5;
-
-				do
-				{
-					ccode2 = msch_err( irq, &ioinfo[irq]->schib);
-
-					switch (ccode2) {
-					case 0:  // successful completion
-						//
-						// concurrent sense facility available ...
-						//
-						ioinfo[irq]->ui.flags.oper   = 1;
-						ioinfo[irq]->ui.flags.consns = 1;
-						ret                          = 0;
-						break;
-      	
-					case 1:  // status pending
-						//
-						// How can we have a pending status as
-						//  device is disabled for interrupts ?
-						//  Anyway, process it ...
-						//
-						ioinfo[irq]->ui.flags.s_pend = 1;
-						s390_process_IRQ( irq);
-						ioinfo[irq]->ui.flags.s_pend = 0;
-						retry--;
-						ret = -EIO;
-						break;
-   	
-					case 2:  // busy
-						/*
-						 * we mark it not-oper as we can't
-						 *  properly operate it !
-						 */
-						ioinfo[irq]->ui.flags.oper = 0;
-						udelay( 100);	/* allow for recovery */
-						retry--;
-						ret = -EBUSY;
-						break;
+				ioinfo[irq]->ui.flags.oper = 1;
+				ioinfo[irq]->ui.flags.consns = 1;
+				ret = 0;
+				break;
 
-					case 3:  // not operational
-						ioinfo[irq]->ui.flags.oper = 0;
-						retry                      = 0;
-						ret = -ENODEV;
-						break;
+			case 1:
+				/*
+				 * status pending
+				 *
+				 * How can we have a pending status 
+				 * as the device is disabled for 
+				 * interrupts ?
+				 * Anyway, process it ...
+				 */
+				ioinfo[irq]->ui.flags.s_pend = 1;
+				s390_process_IRQ (irq);
+				ioinfo[irq]->ui.flags.s_pend = 0;
+				retry--;
+				ret = -EIO;
+				break;
+
+			case 2:
+				/*
+				 * busy
+				 *
+				 * we mark it not-oper as we can't 
+				 * properly operate it !
+				 */
+				ioinfo[irq]->ui.flags.oper = 0;
+				udelay (100);	/* allow for recovery */
+				retry--;
+				ret = -EBUSY;
+				break;
+
+			case 3:	/* not operational */
+				ioinfo[irq]->ui.flags.oper = 0;
+				retry = 0;
+				ret = -ENODEV;
+				break;
 
-					default:
+			default:
 #define PGMCHK_OPERAND_EXC      0x15
 
-						if ( (ccode2 & PGMCHK_OPERAND_EXC) == PGMCHK_OPERAND_EXC )
-						{
-							/*
-							 * re-issue the modify subchannel without trying to
-							 *  enable the concurrent sense facility
-							 */
-							ioinfo[irq]->schib.pmcw.csense = 0;
-   	
-							ccode2 = msch_err( irq, &ioinfo[irq]->schib);
-
-							if ( ccode2 != 0 )
-							{
-								printk( KERN_ERR " ... msch() (2) failed with CC = %X\n",
-								        ccode2 );
-								if (cio_debug_initialized)
-									debug_sprintf_event(cio_debug_msg_id, 0,
-											    "msch() (2) failed with CC=%X\n",
-											    ccode2);
-								ioinfo[irq]->ui.flags.oper = 0;
-								ret                        = -EIO;
-							}
-							else
-							{
-								ioinfo[irq]->ui.flags.oper   = 1;
-								ioinfo[irq]->ui.flags.consns = 0;
-								ret                          = 0;
+				if ((ccode2 & PGMCHK_OPERAND_EXC)
+				    == PGMCHK_OPERAND_EXC) {
+					/*
+					 * re-issue the modify subchannel without trying to
+					 *  enable the concurrent sense facility
+					 */
+					ioinfo[irq]->schib.pmcw.csense = 0;
 
-							} /* endif */
-						}
-						else
-						{
-							printk( KERN_ERR " ... msch() (1) failed with CC = %X\n",
-							        ccode2);
-							if (cio_debug_initialized)
-								debug_sprintf_event(cio_debug_msg_id, 0,
-										    "msch() (1) failed with CC = %X\n",
-										    ccode2);
-							ioinfo[irq]->ui.flags.oper = 0;
-							ret                        = -EIO;
-
-						} /* endif */
-   	
-						retry  = 0;
-						break;
+					ccode2 =
+					    msch_err (irq, &ioinfo[irq]->schib);
+
+					if (ccode2 != 0) {
+						printk (KERN_ERR
+							" ... msch() (2) failed"
+							" with CC = %X\n",
+							ccode2);
+						CIO_MSG_EVENT(0,
+							      "msch() (2) failed"
+							      " with CC=%X\n",
+							      ccode2);
+						ioinfo[irq]->ui.flags.oper = 0;
+						ret = -EIO;
+					} else {
+						ioinfo[irq]->ui.flags.oper = 1;
+						ioinfo[irq]->ui.
+						    flags.consns = 0;
+						ret = 0;
+
+					}
 
-					} /* endswitch */
+				} else {
+					printk (KERN_ERR
+						" ... msch() (1) failed with "
+						"CC = %X\n", ccode2);
+					CIO_MSG_EVENT(0,
+						      "msch() (1) failed with "
+						      "CC = %X\n", ccode2);
+					ioinfo[irq]->ui.flags.oper = 0;
+					ret = -EIO;
 
-				} while ( ccode2 && retry );
+				}
 
-				if ( (ccode2 != 0) && (ccode2 != 3) && (!retry) )
-				{
-					printk( KERN_ERR " ... msch() retry count for "
-					        "subchannel %04X exceeded, CC = %d\n",
-					        irq,
-					        ccode2);
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_msg_id, 0,
-								    " ... msch() retry count for "
-								    "subchannel %04X exceeded, CC = %d\n",
-								    irq, ccode2);		    
+				retry = 0;
+				break;
 
-				} /* endif */
 			}
-			else
-			{
-				/* no path available ... */
-				ioinfo[irq]->ui.flags.oper = 0;
-				ret                        = -ENODEV;    	
 
-			} /* endif */
-		     }
+		} while (ccode2 && retry);
+
+		if ((ccode2 != 0) && (ccode2 != 3)
+		    && (!retry)) {
+			printk (KERN_ERR
+				" ... msch() retry count for "
+				"subchannel %04X exceeded, CC = %d\n",
+				irq, ccode2);
+			CIO_MSG_EVENT(0,
+				      " ... msch() retry count for "
+				      "subchannel %04X exceeded, CC = %d\n",
+				      irq, ccode2);
+
 		}
-		else
-		{
-			ret = -ENODEV;
+	} else {
+		/* no path available ... */
+		ioinfo[irq]->ui.flags.oper = 0;
+		ret = -ENODEV;
 
-		} /* endif */
 	}
-	else
-	{
-		ret = -ENXIO;
 
-	} /* endif */
-
-	return( ret );
+	return (ret);
 }
 
 /*
@@ -5087,43 +5176,46 @@
  *  s390_SenseID() related device interrupts - interruption
  *  parameter used is 0x00E2C9C4 ( SID ).
  */
-int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
+int
+s390_SenseID (int irq, senseid_t * sid, __u8 lpm)
 {
-	ccw1_t    *sense_ccw;     /* ccw area for SenseID command */
-	senseid_t  isid;          /* internal sid */				
-	devstat_t  devstat;       /* required by request_irq() */
-	__u8       pathmask;      /* calulate path mask */
-	__u8       domask;        /* path mask to use */
-	int        inlreq;        /* inline request_irq() */
-	int        irq_ret;       /* return code */
-	devstat_t *pdevstat;      /* ptr to devstat in use */
-	int        retry;         /* retry count */
-	int        io_retry;      /* retry indicator */
+	ccw1_t *sense_ccw;	/* ccw area for SenseID command */
+	senseid_t isid;		/* internal sid */
+	devstat_t devstat;	/* required by request_irq() */
+	__u8 pathmask;		/* calulate path mask */
+	__u8 domask;		/* path mask to use */
+	int inlreq;		/* inline request_irq() */
+	int irq_ret;		/* return code */
+	devstat_t *pdevstat;	/* ptr to devstat in use */
+	int retry;		/* retry count */
+	int io_retry;		/* retry indicator */
 
-	senseid_t *psid     = sid;/* start with the external buffer */	
-	int        sbuffer  = 0;  /* switch SID data buffer */
+	senseid_t *psid = sid;	/* start with the external buffer */
+	int sbuffer = 0;	/* switch SID data buffer */
 
 	char dbf_txt[15];
+	int i;
+	int failure = 0;	/* nothing went wrong yet */
 
-	int failure = 0;          /* nothing went wrong yet */
+	SANITY_CHECK (irq);
 
-	SANITY_CHECK(irq);
+	if (ioinfo[irq]->ui.flags.oper == 0) {
+		return (-ENODEV);
 
-	if ( ioinfo[irq]->ui.flags.oper == 0 )
-	{
-		return( -ENODEV );
+	}
 
-	} /* endif */
+ 	if (ioinfo[irq]->ui.flags.unfriendly) {
+ 		/* don't even try it */
+ 		return -EUSERS;
+ 	}
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "snsID%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	CIO_TRACE_EVENT (4, "senseID");
+	sprintf (dbf_txt, "%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	inlreq = 0; /* to make the compiler quiet... */
+	inlreq = 0;		/* to make the compiler quiet... */
 
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
+	if (!ioinfo[irq]->ui.flags.ready) {
 
 		pdevstat = &devstat;
 
@@ -5133,471 +5225,421 @@
 		 *  requests and evaluate the devstat area on return therefore
 		 *  we don't need a real I/O handler in place.
 		 */
-		irq_ret = request_irq( irq, init_IRQ_handler, SA_PROBE, "SID", &devstat);
+		irq_ret =
+		    request_irq (irq, init_IRQ_handler, SA_PROBE, "SID",
+				 &devstat);
 
-		if ( irq_ret == 0 )
+		if (irq_ret == 0)
 			inlreq = 1;
-	}
-	else
-	{
-		inlreq   = 0;
-		irq_ret  = 0;
+	} else {
+		inlreq = 0;
+		irq_ret = 0;
 		pdevstat = ioinfo[irq]->irq_desc.dev_id;
 
-  	} /* endif */
+	}
 
-	if ( irq_ret == 0 )
-	{
-		int i;
+	if (irq_ret) {
+		return irq_ret;
+	}
 
-		s390irq_spin_lock( irq);
+	s390irq_spin_lock (irq);
 
-		if ( init_IRQ_complete )
-		{
-			sense_ccw = kmalloc( 2*sizeof( ccw1_t), GFP_DMA);
-		}
-		else	
-		{
-			sense_ccw = alloc_bootmem_low( 2*sizeof( ccw1_t));
-
-		} /* endif */
-
-		// more than one path installed ?
-		if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
-		{
-			sense_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN;
-			sense_ccw[0].cda      = 0;
-			sense_ccw[0].count    = 0;
-			sense_ccw[0].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
-
-			sense_ccw[1].cmd_code = CCW_CMD_SENSE_ID;
-			sense_ccw[1].cda      = (__u32)virt_to_phys( sid );
-			sense_ccw[1].count    = sizeof( senseid_t);
-			sense_ccw[1].flags    = CCW_FLAG_SLI;
-		}
-		else
-		{
-			sense_ccw[0].cmd_code = CCW_CMD_SENSE_ID;
-			sense_ccw[0].cda      = (__u32)virt_to_phys( sid );
-			sense_ccw[0].count    = sizeof( senseid_t);
-			sense_ccw[0].flags    = CCW_FLAG_SLI;
+	if (init_IRQ_complete) {
+		sense_ccw = kmalloc (2 * sizeof (ccw1_t), GFP_DMA);
+	} else {
+		sense_ccw = alloc_bootmem_low (2 * sizeof (ccw1_t));
 
-		} /* endif */
+	}
 
-		for ( i = 0 ; (i < 8) ; i++ )
-		{
-			pathmask = 0x80 >> i;						
+	/* more than one path installed ? */
+	if (ioinfo[irq]->schib.pmcw.pim != 0x80) {
+		sense_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN;
+		sense_ccw[0].cda = 0;
+		sense_ccw[0].count = 0;
+		sense_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
 
-			domask = ioinfo[irq]->opm & pathmask;
+		sense_ccw[1].cmd_code = CCW_CMD_SENSE_ID;
+		sense_ccw[1].cda = (__u32) virt_to_phys (sid);
+		sense_ccw[1].count = sizeof (senseid_t);
+		sense_ccw[1].flags = CCW_FLAG_SLI;
+	} else {
+		sense_ccw[0].cmd_code = CCW_CMD_SENSE_ID;
+		sense_ccw[0].cda = (__u32) virt_to_phys (sid);
+		sense_ccw[0].count = sizeof (senseid_t);
+		sense_ccw[0].flags = CCW_FLAG_SLI;
 
-			if ( lpm )
-				domask &= lpm;
+	}
 
-			if ( domask )
-			{
-				failure = 0;
-				
-				psid->reserved   = 0;
-				psid->cu_type    = 0xFFFF;  /* initialize fields ... */
-				psid->cu_model   = 0;
-				psid->dev_type   = 0;
-				psid->dev_model  = 0;
+	for (i = 0; (i < 8); i++) {
+		pathmask = 0x80 >> i;
 
-				retry            = 5;  /* retry count    */
-				io_retry         = 1;  /* enable retries */
+		domask = ioinfo[irq]->opm & pathmask;
 
-				/*
-				 * We now issue a SenseID request. In case of BUSY,
-				 *  STATUS PENDING or non-CMD_REJECT error conditions
-				 *  we run simple retries.
-				 */
-				do
-				{
-					memset( pdevstat, '\0', sizeof( devstat_t) );
-
-					irq_ret = s390_start_IO( irq,
-					                         sense_ccw,
-					                         0x00E2C9C4,  // == SID
-								 domask,
-					                         DOIO_WAIT_FOR_INTERRUPT
-					                          | DOIO_TIMEOUT
-					                          | DOIO_VALID_LPM
-					                          | DOIO_DONT_CALL_INTHDLR );
+		if (lpm)
+			domask &= lpm;
 
+		if (!domask)
+			continue;
 
-					if ( psid->cu_type  == 0xFFFF )
-					{
+		failure = 0;
 
-						failure = 1;
+		memset(psid, 0, sizeof(senseid_t));
+		psid->cu_type = 0xFFFF;	/* initialize fields ... */
 
-						if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
-						{
+		retry = 5;	/* retry count    */
+		io_retry = 1;	/* enable retries */
+
+		/*
+		 * We now issue a SenseID request. In case of BUSY,
+		 *  STATUS PENDING or non-CMD_REJECT error conditions
+		 *  we run simple retries.
+		 */
+		do {
+			memset (pdevstat, '\0', sizeof (devstat_t));
+
+			irq_ret = s390_start_IO (irq, sense_ccw, 0x00E2C9C4,	/* == SID */
+						 domask,
+						 DOIO_WAIT_FOR_INTERRUPT
+						 | DOIO_TIMEOUT
+						 | DOIO_VALID_LPM
+						 | DOIO_DONT_CALL_INTHDLR);
+
+			if ((psid->cu_type != 0xFFFF)
+			    && (psid->reserved == 0xFF)) {
+				if (!sbuffer) {	/* switch buffers */
+					/*
+					 * we report back the
+					 *  first hit only
+					 */
+					psid = &isid;
+
+					if (ioinfo[irq]->schib.pmcw.pim != 0x80) {
+						sense_ccw[1].cda = (__u32)
+						    virt_to_phys (psid);
+					} else {
+						sense_ccw[0].cda = (__u32)
+						    virt_to_phys (psid);
+
+					}
+
+					/*
+					 * if just the very first
+					 *  was requested to be
+					 *  sensed disable further
+					 *  scans.
+					 */
+					if (!lpm)
+						lpm = domask;
+
+					sbuffer = 1;
+
+				}
+
+				if (pdevstat->rescnt < (sizeof (senseid_t) - 8)) {
+					ioinfo[irq]->ui.flags.esid = 1;
+
+				}
+
+				io_retry = 0;
+
+				break;
+			}
+
+			failure = 1;
+
+			if (pdevstat->flag & DEVSTAT_STATUS_PENDING) {
 #ifdef CONFIG_DEBUG_IO
-							printk( KERN_DEBUG "SenseID : device %04X on "
-							        "Subchannel %04X "
-							        "reports pending status, "
-							        "retry : %d\n",
-							        ioinfo[irq]->schib.pmcw.dev,
-								irq,
-							        retry);
-#endif
-							if (cio_debug_initialized)
-								debug_sprintf_event(cio_debug_msg_id, 2,
-										    "SenseID : device %04X on "
-										    "Subchannel %04X "
-										    "reports pending status, "
-										    "retry : %d\n",
-										    ioinfo[irq]->schib.pmcw.dev,
-										    irq,
-										    retry);		    
-						} /* endif */
+				printk (KERN_DEBUG
+					"SenseID : device %04X on "
+					"Subchannel %04X "
+					"reports pending status, "
+					"retry : %d\n",
+					ioinfo[irq]->schib.pmcw.dev, irq,
+					retry);
+#endif
+				CIO_MSG_EVENT(2,
+					      "SenseID : device %04X on "
+					      "Subchannel %04X "
+					      "reports pending status, "
+					      "retry : %d\n",
+					      ioinfo
+					      [irq]->schib.pmcw.dev, irq, retry);
+			}
 
-						else if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
-						{
-							/*
-							 * if the device doesn't support the SenseID
-							 *  command further retries wouldn't help ...
-							 */
-							if (  pdevstat->ii.sense.data[0]
-							    & (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ) )
-							{
+			else if (pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+				/*
+				 * if the device doesn't support the SenseID
+				 *  command further retries wouldn't help ...
+				 */
+				if (pdevstat->ii.sense.data[0]
+				    & (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)) {
 #ifdef CONFIG_DEBUG_IO
-								printk( KERN_ERR "SenseID : device %04X on "
-								        "Subchannel %04X "
-								        "reports cmd reject or "
-								        "intervention required\n",
-								        ioinfo[irq]->schib.pmcw.dev,
-								        irq);
-#endif
-								if (cio_debug_initialized)
-									debug_sprintf_event(cio_debug_msg_id, 2,
-											    "SenseID : device %04X on "
-											    "Subchannel %04X "
-											    "reports cmd reject or "
-											    "intervention required\n",
-											    ioinfo[irq]->schib.pmcw.dev,
-											    irq);		    
-								io_retry = 0;
-							}
+					printk (KERN_ERR
+						"SenseID : device %04X on "
+						"Subchannel %04X "
+						"reports cmd reject or "
+						"intervention required\n",
+						ioinfo[irq]->schib.pmcw.dev,
+						irq);
+#endif
+					CIO_MSG_EVENT(2,
+						      "SenseID : device %04X on "
+						      "Subchannel %04X "
+						      "reports cmd reject or "
+						      "intervention required\n",
+						      ioinfo[irq]->schib.pmcw.dev, 
+						      irq);
+					io_retry = 0;
+				} else {
+#ifdef CONFIG_DEBUG_IO
+					printk
+					    (KERN_WARNING
+					     "SenseID : UC on "
+					     "dev %04X, "
+					     "retry %d, "
+					     "lpum %02X, "
+					     "cnt %02d, "
+					     "sns :"
+					     " %02X%02X%02X%02X "
+					     "%02X%02X%02X%02X ...\n",
+					     ioinfo[irq]->schib.pmcw.dev,
+					     retry,
+					     pdevstat->lpum,
+					     pdevstat->scnt,
+					     pdevstat->ii.sense.data[0],
+					     pdevstat->ii.sense.data[1],
+					     pdevstat->ii.sense.data[2],
+					     pdevstat->ii.sense.data[3],
+					     pdevstat->ii.sense.data[4],
+					     pdevstat->ii.sense.data[5],
+					     pdevstat->ii.sense.data[6],
+					     pdevstat->ii.sense.data[7]);
+#endif
+					CIO_MSG_EVENT(2,
+						      "SenseID : UC on "
+						      "dev %04X, "
+						      "retry %d, "
+						      "lpum %02X, "
+						      "cnt %02d, "
+						      "sns :"
+						      " %02X%02X%02X%02X "
+						      "%02X%02X%02X%02X ...\n",
+						      ioinfo[irq]->
+						      schib.pmcw.dev,
+						      retry,
+						      pdevstat->lpum,
+						      pdevstat->scnt,
+						      pdevstat->
+						      ii.sense.data[0],
+						      pdevstat->
+						      ii.sense.data[1],
+						      pdevstat->
+						      ii.sense.data[2],
+						      pdevstat->
+						      ii.sense.data[3],
+						      pdevstat->
+						      ii.sense.data[4],
+						      pdevstat->
+						      ii.sense.data[5],
+						      pdevstat->
+						      ii.sense.data[6],
+						      pdevstat->
+						      ii.sense.data[7]);
 
-							else
-							{
-#ifdef CONFIG_DEBUG_IO							
-								printk( KERN_WARNING "SenseID : UC on "
-								        "dev %04X, "
-								        "retry %d, "
-								        "lpum %02X, "
-								        "cnt %02d, "
-								        "sns :"
-								        " %02X%02X%02X%02X "
-								        "%02X%02X%02X%02X ...\n",
-								        ioinfo[irq]->schib.pmcw.dev,
-								        retry,
-								        pdevstat->lpum,
-								        pdevstat->scnt,
-								        pdevstat->ii.sense.data[0],
-								        pdevstat->ii.sense.data[1],
-								        pdevstat->ii.sense.data[2],
-								        pdevstat->ii.sense.data[3],
-								        pdevstat->ii.sense.data[4],
-								        pdevstat->ii.sense.data[5],
-								        pdevstat->ii.sense.data[6],
-								        pdevstat->ii.sense.data[7]);
-#endif
-								if (cio_debug_initialized) {
-									debug_sprintf_event(cio_debug_msg_id, 2,
-											    "SenseID : UC on "
-											    "dev %04X, "
-											    "retry %d, "
-											    "lpum %02X, "
-											    "cnt %02d, "
-											    "sns :"
-											    " %02X%02X%02X%02X "
-											    "%02X%02X%02X%02X ...\n",
-											    ioinfo[irq]->schib.pmcw.dev,
-											    retry,
-											    pdevstat->lpum,
-											    pdevstat->scnt,
-											    pdevstat->ii.sense.data[0],
-											    pdevstat->ii.sense.data[1],
-											    pdevstat->ii.sense.data[2],
-											    pdevstat->ii.sense.data[3],
-											    pdevstat->ii.sense.data[4],
-											    pdevstat->ii.sense.data[5],
-											    pdevstat->ii.sense.data[6],
-											    pdevstat->ii.sense.data[7]);	    
-									if (psid->reserved != 0xFF) 
-										debug_sprintf_event(cio_debug_msg_id, 2,
-												    "SenseID was not properly "
-												    "executed!\n");
-								}
-							} /* endif */
+				}
 
-						}
-						else if (    ( pdevstat->flag & DEVSTAT_NOT_OPER )
-							  || ( irq_ret        == -ENODEV         ) )
-						{
+			} else if ((pdevstat->flag & DEVSTAT_NOT_OPER)
+				   || (irq_ret == -ENODEV)) {
 #ifdef CONFIG_DEBUG_IO
-							printk( KERN_ERR "SenseID : path %02X for "
-							        "device %04X on "
-							        "subchannel %04X "
-							        "is 'not operational'\n",
-							        domask,
-							        ioinfo[irq]->schib.pmcw.dev,
-							        irq);
-#endif
-							if (cio_debug_initialized)
-								debug_sprintf_event(cio_debug_msg_id, 2, 
-										    "SenseID : path %02X for "
-										    "device %04X on "
-										    "subchannel %04X "
-										    "is 'not operational'\n",
-										    domask,
-										    ioinfo[irq]->schib.pmcw.dev,
-										    irq);		    
-
-							io_retry          = 0;
-							ioinfo[irq]->opm &= ~domask;
-      	
-						}
+				printk (KERN_ERR
+					"SenseID : path %02X for "
+					"device %04X on "
+					"subchannel %04X "
+					"is 'not operational'\n",
+					domask,
+					ioinfo[irq]->schib.pmcw.dev, irq);
+#endif
+				CIO_MSG_EVENT(2,
+					      "SenseID : path %02X for "
+					      "device %04X on "
+					      "subchannel %04X "
+					      "is 'not operational'\n",
+					      domask,
+					      ioinfo[irq]->schib.pmcw.dev, irq);
+				
+				io_retry = 0;
+				ioinfo[irq]->opm &= ~domask;
 
-						else if (     ( pdevstat->flag !=
-							       (   DEVSTAT_START_FUNCTION
-								 | DEVSTAT_FINAL_STATUS    ) )
-							   && !( pdevstat->flag &
-								DEVSTAT_STATUS_PENDING       ) )
-						{
+			} else {
 #ifdef CONFIG_DEBUG_IO
-							printk( KERN_INFO "SenseID : start_IO() for "
-							        "device %04X on "
-							        "subchannel %04X "
-							        "returns %d, retry %d, "
-							        "status %04X\n",
-							        ioinfo[irq]->schib.pmcw.dev,
-							        irq,
-							        irq_ret,
-							        retry,
-							        pdevstat->flag);
-#endif
-							if (cio_debug_initialized)
-								debug_sprintf_event(cio_debug_msg_id, 2,
-										    "SenseID : start_IO() for "
-										    "device %04X on "
-										    "subchannel %04X "
-										    "returns %d, retry %d, "
-										    "status %04X\n",
-										    ioinfo[irq]->schib.pmcw.dev,
-										    irq,
-										    irq_ret,
-										    retry,
-										    pdevstat->flag);		    
+				printk (KERN_INFO
+					"SenseID : start_IO() for "
+					"device %04X on "
+					"subchannel %04X "
+					"returns %d, retry %d, "
+					"status %04X\n",
+					ioinfo[irq]->schib.pmcw.dev,
+					irq, irq_ret, retry, pdevstat->flag);
+#endif
+				CIO_MSG_EVENT(2,
+					     "SenseID : start_IO() for "
+					     "device %04X on "
+					     "subchannel %04X "
+					     "returns %d, retry %d, "
+					     "status %04X\n",
+					     ioinfo[irq]->schib.pmcw.dev, irq,
+					     irq_ret, retry, pdevstat->flag);
 
-						} /* endif */
+				if (irq_ret == -ETIMEDOUT) {
+					int xret;
 
-					}
-					else   // we got it ...
-					{
-						if (psid->reserved != 0xFF) {
-							/* No, we failed after all... */
-							failure = 1;
-							retry--;
-
-						} else {
-					       
-							if ( !sbuffer )	// switch buffers
-							{
-								/*
-								 * we report back the
-								 *  first hit only
-								 */
-								psid = &isid;
-								
-								if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
-								{
-									sense_ccw[1].cda = (__u32)virt_to_phys( psid );
-								}
-								else
-								{
-									sense_ccw[0].cda = (__u32)virt_to_phys( psid );
-
-								} /* endif */
-
-								/*
-								 * if just the very first
-								 *  was requested to be
-								 *  sensed disable further
-								 *  scans.
-								 */	
-								if ( !lpm )
-									lpm = domask;
-								
-								sbuffer = 1;
-								
-							} /* endif */
-
-							if ( pdevstat->rescnt < (sizeof( senseid_t) - 8) )
-							{
-								ioinfo[irq]->ui.flags.esid = 1;
-       							
-							} /* endif */
+					/*
+					 * Seems we need to cancel the first ssch sometimes...
+					 * On the next try, the ssch will usually be fine.
+					 */
 
-							io_retry = 0;
-						
-						}
+					xret = cancel_IO (irq);
 
-					} /* endif */
+					if (!xret)
+						CIO_MSG_EVENT(2,
+							      "SenseID: sch canceled "
+							      "successfully for irq %x\n",
+							      irq);
+				}
 
-					if ( io_retry )
-					{
-						retry--;
+			}
 
-						if ( retry == 0 )
-						{
-							io_retry = 0;
+			if (io_retry) {
+				retry--;
 
-						} /* endif */
-      	
-					} /* endif */
+				if (retry == 0) {
+					io_retry = 0;
 
-					if ((failure) && (io_retry)) {
-						/* reset fields... */
+				}
+			}
 
-						failure = 0;
-						
-						psid->reserved   = 0;
-						psid->cu_type    = 0xFFFF;  
-						psid->cu_model   = 0;
-						psid->dev_type   = 0;
-						psid->dev_model  = 0;
-					}
-						
-				} while ( (io_retry) );
+			if ((failure) && (io_retry)) {
+				/* reset fields... */
 
- 			} /* endif - domask */
+				failure = 0;
 
-		} /* endfor */
+				memset(psid, 0, sizeof(senseid_t));
+				psid->cu_type = 0xFFFF;
+			}
 
-		if ( init_IRQ_complete )
-		{
-			kfree( sense_ccw );
-		}
-		else	
-		{
-			free_bootmem( (unsigned long)sense_ccw, 2*sizeof(ccw1_t) );
+		} while ((io_retry));
 
-		} /* endif */
+	}
 
-		s390irq_spin_unlock( irq);
+	if (init_IRQ_complete) {
+		kfree (sense_ccw);
+	} else {
+		free_bootmem ((unsigned long) sense_ccw, 2 * sizeof (ccw1_t));
 
-		/*
-		 * If we installed the irq action handler we have to
-		 *  release it too.
-		 */
-		if ( inlreq )
-			free_irq( irq, pdevstat);
+	}
 
-		/*
-		 * if running under VM check there ... perhaps we should do
-		 *  only if we suffered a command reject, but it doesn't harm
-		 */
-		if (    ( sid->cu_type == 0xFFFF    )
-		     && ( MACHINE_IS_VM             ) )
-		{
-			VM_virtual_device_info( ioinfo[irq]->schib.pmcw.dev,
-			                        sid );
-		} /* endif */
+	s390irq_spin_unlock (irq);
 
-		if ( sid->cu_type == 0xFFFF )
-		{
-			/*
-			 * SenseID CU-type of 0xffff indicates that no device
-			 *  information could be retrieved (pre-init value).
-			 *
-			 * If we can't couldn't identify the device type we
-			 *  consider the device "not operational".
-			 */
-#ifdef CONFIG_DEBUG_IO
-			printk( KERN_WARNING "SenseID : unknown device %04X on subchannel %04X\n",
-			        ioinfo[irq]->schib.pmcw.dev,
-			        irq);
-#endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_msg_id, 2,
-						    "SenseID : unknown device %04X on subchannel %04X\n",
-						    ioinfo[irq]->schib.pmcw.dev,
-						    irq);		    
-			ioinfo[irq]->ui.flags.unknown = 1;
+	/*
+	 * If we installed the irq action handler we have to
+	 *  release it too.
+	 */
+	if (inlreq)
+		free_irq (irq, pdevstat);
 
-		} /* endif */
+	/*
+	 * if running under VM check there ... perhaps we should do
+	 *  only if we suffered a command reject, but it doesn't harm
+	 */
+	if ((sid->cu_type == 0xFFFF)
+	    && (MACHINE_IS_VM)) {
+		VM_virtual_device_info (ioinfo[irq]->schib.pmcw.dev, sid);
+	}
 
-	
+	if (sid->cu_type == 0xFFFF) {
 		/*
-		 * Issue device info message if unit was operational .
+		 * SenseID CU-type of 0xffff indicates that no device
+		 *  information could be retrieved (pre-init value).
+		 *
+		 * If we can't couldn't identify the device type we
+		 *  consider the device "not operational".
 		 */
-		if ( !ioinfo[irq]->ui.flags.unknown ) {
-			if ( sid->dev_type != 0 ) {
-				if ( cio_show_msg ) 
-					printk( KERN_INFO"SenseID : device %04X reports: "
-						"CU  Type/Mod = %04X/%02X,"
-						" Dev Type/Mod = %04X/%02X\n",
-						ioinfo[irq]->schib.pmcw.dev,
-						sid->cu_type,
-						sid->cu_model,
-						sid->dev_type,
-						sid->dev_model);
-				if (cio_debug_initialized)
-					debug_sprintf_event(cio_debug_msg_id, 2,
-							    "SenseID : device %04X reports: "
-							    "CU  Type/Mod = %04X/%02X,"
-							    " Dev Type/Mod = %04X/%02X\n",
-							    ioinfo[irq]->schib.pmcw.dev,
-							    sid->cu_type,
-							    sid->cu_model,
-							    sid->dev_type,
-							    sid->dev_model);
-			} else {
-				if ( cio_show_msg ) 
-					printk( KERN_INFO"SenseID : device %04X reports:"
-						" Dev Type/Mod = %04X/%02X\n",
-						ioinfo[irq]->schib.pmcw.dev,
-						sid->cu_type,
-						sid->cu_model);
-				if (cio_debug_initialized)
-					debug_sprintf_event(cio_debug_msg_id, 2,
-							    "SenseID : device %04X reports:"
-							    " Dev Type/Mod = %04X/%02X\n",
-							    ioinfo[irq]->schib.pmcw.dev,
-							    sid->cu_type,
-							    sid->cu_model);		    
-			} /* endif */
+#ifdef CONFIG_DEBUG_IO
+		printk (KERN_WARNING
+			"SenseID : unknown device %04X on subchannel %04X\n",
+			ioinfo[irq]->schib.pmcw.dev, irq);
+#endif
+		CIO_MSG_EVENT(2,
+			      "SenseID : unknown device %04X on subchannel %04X\n",
+			      ioinfo[irq]->schib.pmcw.dev, irq);
+		ioinfo[irq]->ui.flags.unknown = 1;
 
-		} /* endif */
+	}
 
-		if ( !ioinfo[irq]->ui.flags.unknown )
-			irq_ret = 0;
-		else
-			irq_ret = -ENODEV;
+	/*
+	 * Issue device info message if unit was operational .
+	 */
+	if (!ioinfo[irq]->ui.flags.unknown) {
+		if (sid->dev_type != 0) {
+			if (cio_show_msg)
+				printk (KERN_INFO
+					"SenseID : device %04X reports: "
+					"CU  Type/Mod = %04X/%02X,"
+					" Dev Type/Mod = %04X/%02X\n",
+					ioinfo[irq]->schib.pmcw.dev,
+					sid->cu_type, sid->cu_model,
+					sid->dev_type, sid->dev_model);
+			CIO_MSG_EVENT(2,
+				      "SenseID : device %04X reports: "
+				      "CU  Type/Mod = %04X/%02X,"
+				      " Dev Type/Mod = %04X/%02X\n",
+				      ioinfo[irq]->schib.
+				      pmcw.dev,
+				      sid->cu_type,
+				      sid->cu_model,
+				      sid->dev_type,
+				      sid->dev_model);
+		} else {
+			if (cio_show_msg)
+				printk (KERN_INFO
+					"SenseID : device %04X reports:"
+					" Dev Type/Mod = %04X/%02X\n",
+					ioinfo[irq]->schib.pmcw.dev,
+					sid->cu_type, sid->cu_model);
+			CIO_MSG_EVENT(2,
+				      "SenseID : device %04X reports:"
+				      " Dev Type/Mod = %04X/%02X\n",
+				      ioinfo[irq]->schib.
+				      pmcw.dev,
+				      sid->cu_type,
+				      sid->cu_model);
+		}
 
-	} /* endif */
+	}
+
+	if (!ioinfo[irq]->ui.flags.unknown)
+		irq_ret = 0;
+	else
+		irq_ret = -ENODEV;
 
-   return( irq_ret );
+	return (irq_ret);
 }
 
-static int __inline__ s390_SetMultiPath( int irq )
+static int __inline__
+s390_SetMultiPath (int irq)
 {
 	int cc;
 
-	cc = stsch( irq, &ioinfo[irq]->schib );
+	cc = stsch (irq, &ioinfo[irq]->schib);
 
-	if ( !cc )
-	{
-		ioinfo[irq]->schib.pmcw.mp = 1;     /* multipath mode */
+	if (!cc) {
+		ioinfo[irq]->schib.pmcw.mp = 1;	/* multipath mode */
 
-		cc = msch( irq, &ioinfo[irq]->schib );
+		cc = msch (irq, &ioinfo[irq]->schib);
 
-	} /* endif */
+	}
 
-	return( cc);
+	return (cc);
 }
 
 /*
@@ -5610,182 +5652,308 @@
  * Note : This function must not be called during normal device recognition,
  *         but during device driver initiated request_irq() processing only.
  */
-int s390_DevicePathVerification( int irq, __u8 usermask )
+int
+s390_DevicePathVerification (int irq, __u8 usermask)
 {
-	int  ccode;
+	int ccode;
 	__u8 pathmask;
 	__u8 domask;
+#ifdef CONFIG_CHSC
+	int chp;
+	int mask;
+	int old_opm = 0;
+#endif /* CONFIG_CHSC */
 
 	int ret = 0;
+	int i;
+	pgid_t pgid;
+	__u8 dev_path;
+	int first = 1;
 
 	char dbf_txt[15];
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "dpver%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
-
-	if ( ioinfo[irq]->ui.flags.pgid_supp == 0 )
-	{
-		return( 0);	// just exit ...
+	sprintf (dbf_txt, "dpvf%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	} /* endif */
+	if (ioinfo[irq]->st) 
+		return -ENODEV;
 
-	ccode = stsch( irq, &(ioinfo[irq]->schib) );
+#ifdef CONFIG_CHSC
+	old_opm = ioinfo[irq]->opm;
+#endif /* CONFIG_CHSC */
+	ccode = stsch (irq, &(ioinfo[irq]->schib));
 
-	if ( ccode )
-	{
-		ret = -ENODEV;
+	if (ccode) {
+		return -ENODEV;
 	}
-	else if ( ioinfo[irq]->schib.pmcw.pim == 0x80 )
-	{
+	if (ioinfo[irq]->schib.pmcw.pim == 0x80) {
 		/*
 		 * no error, just not required for single path only devices
-		 */	
+		 */
 		ioinfo[irq]->ui.flags.pgid_supp = 0;
 		ret = 0;
+
+#ifdef CONFIG_CHSC
+		/*
+		 * disable if chpid is logically offline
+		 */
+		if (!test_bit(ioinfo[irq]->schib.pmcw.chpid[0], 
+			      &chpids_logical)) {
+			not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
+			int was_oper = ioinfo[irq]->ui.flags.oper;
+
+			ioinfo[irq]->opm = 0;
+			ioinfo[irq]->ui.flags.oper = 0;
+			printk(KERN_WARNING 
+			       "No logical path for sch %d...\n",
+			       irq);
+			if (old_opm && 
+			    was_oper && 
+			    ioinfo[irq]->ui.flags.ready) {
+#ifdef CONFIG_PROC_FS
+				if (cio_proc_devinfo)
+					cio_procfs_device_remove
+						(ioinfo[irq]->devno);
+#endif /* CONFIG_PROC_FS */
+				free_irq( irq, ioinfo[irq]->irq_desc.dev_id);
+				if (nopfunc)
+					nopfunc( irq, DEVSTAT_DEVICE_GONE);
+			}
+			ret = -ENODEV;
+		} else if (!old_opm) {
+
+			/*
+			 * check for opm...
+			 */
+			ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim
+				& ioinfo[irq]->schib.pmcw.pam
+				& ioinfo[irq]->schib.pmcw.pom;
+				
+			if (ioinfo[irq]->opm) {
+				devreg_t *pdevreg;
+
+				ioinfo[irq]->ui.flags.oper = 1;
+				pdevreg = s390_search_devreg( ioinfo[irq] );
+
+				if (pdevreg) 
+					if (pdevreg->oper_func)
+						pdevreg->oper_func
+							( irq, pdevreg);
+#ifdef CONFIG_PROC_FS
+				if (cio_proc_devinfo) 
+					if (highest_subchannel 
+					    < MAX_CIO_PROCFS_ENTRIES) {
+						cio_procfs_device_create
+							(ioinfo[irq]->devno);
+					}
+#endif /* CONFIG_PROC_FS */
+			}
+			ret = 0;
+		} else {
+			ret = 0;
+		}
+#endif /* CONFIG_CHSC */
+		return ret;
 	}
-	else
-	{
-		int    i;
-		pgid_t pgid;
-		__u8   dev_path;
-		int    first  = 1;
-
-		ioinfo[irq]->opm =   ioinfo[irq]->schib.pmcw.pim
-		                   & ioinfo[irq]->schib.pmcw.pam
-		                   & ioinfo[irq]->schib.pmcw.pom;
-
-		if ( usermask )
-		{
-			dev_path = usermask;
+
+	ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim
+	    & ioinfo[irq]->schib.pmcw.pam & ioinfo[irq]->schib.pmcw.pom;
+
+#ifdef CONFIG_CHSC
+	if (ioinfo[irq]->opm) {
+		for (chp=0;chp<=7;chp++) {
+			mask = 0x80 >> chp;
+			if (ioinfo[irq]->opm & mask) {
+				if (!test_bit
+				    (ioinfo[irq]->schib.pmcw.chpid[chp], 
+				     &chpids_logical)) {
+					/* disable using this path */
+					ioinfo[irq]->opm &= ~mask;
+				}
+			}
 		}
-		else
-		{
-			dev_path = ioinfo[irq]->opm;
+	}
+	
+	if ((ioinfo[irq]->opm == 0) && (old_opm)) {
+		not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
+		int was_oper = ioinfo[irq]->ui.flags.ready;
 
-		} /* endif */
+		ioinfo[irq]->ui.flags.oper = 0;
+		printk(KERN_WARNING "No logical path for sch %d...\n",irq);
+		if (was_oper && ioinfo[irq]->ui.flags.oper) {
+#ifdef CONFIG_PROC_FS
+			if (cio_proc_devinfo)
+				cio_procfs_device_remove(ioinfo[irq]->devno);
+#endif /* CONFIG_PROC_FS */
+				free_irq( irq, ioinfo[irq]->irq_desc.dev_id);
+				if (nopfunc)
+					nopfunc( irq, DEVSTAT_DEVICE_GONE);
+		}
+		return -ENODEV;
+	}
 
-		/*
-		 * let's build a path group ID if we don't have one yet
-		 */
-		if ( ioinfo[irq]->ui.flags.pgid == 0)
-		{
-			ioinfo[irq]->pgid.cpu_addr  = *(__u16 *)__LC_CPUADDR;
-			ioinfo[irq]->pgid.cpu_id    = ((cpuid_t *)__LC_CPUID)->ident;
-			ioinfo[irq]->pgid.cpu_model = ((cpuid_t *)__LC_CPUID)->machine;
-			ioinfo[irq]->pgid.tod_high  = *(__u32 *)&irq_IPL_TOD;
+	if (!old_opm) {
+		/* Hey, we have a new logical path... */
+		devreg_t *pdevreg;
+		
+		ioinfo[irq]->ui.flags.oper = 1;
+		pdevreg = s390_search_devreg( ioinfo[irq] );
+		
+		if (pdevreg) 
+			if (pdevreg->oper_func)
+				pdevreg->oper_func( irq, pdevreg);
+#ifdef CONFIG_PROC_FS		
+		if (cio_proc_devinfo) 
+			if (highest_subchannel < MAX_CIO_PROCFS_ENTRIES) {
+				cio_procfs_device_create(ioinfo[irq]->devno);
+			}
+#endif /* CONFIG_PROC_FS */
+	}
+#endif /* CONFIG_CHSC */
 
-			ioinfo[irq]->ui.flags.pgid  = 1;
+	if ( ioinfo[irq]->ui.flags.pgid_supp == 0 )
+		return( 0);	/* just exit ... */
 
-		} /* endif */     		
+	if (usermask) {
+		dev_path = usermask;
+	} else {
+		dev_path = ioinfo[irq]->opm;
 
-		memcpy( &pgid, &ioinfo[irq]->pgid, sizeof(pgid_t));
+	}
 
-		for ( i = 0; i < 8 && !ret ; i++)
-		{
-			pathmask = 0x80 >> i;						
+	if (ioinfo[irq]->ui.flags.pgid == 0) {
+		memcpy (&ioinfo[irq]->pgid, global_pgid, sizeof (pgid_t));
+		ioinfo[irq]->ui.flags.pgid = 1;
+	}
 
-			domask = dev_path & pathmask;
+	for (i = 0; i < 8 && !ret; i++) {
+		pathmask = 0x80 >> i;
 
-			if ( domask )
-			{
-				ret = s390_SetPGID( irq, domask, &pgid );
+		domask = dev_path & pathmask;
 
-				/*
-				 * For the *first* path we are prepared
-				 *  for recovery
-				 *
-				 *  - If we fail setting the PGID we assume its
-				 *     using  a different PGID already (VM) we
-				 *     try to sense.
-				 */
-				if ( ret == -EOPNOTSUPP && first )
-				{
-					*(int *)&pgid = 0;
-					
-					ret   = s390_SensePGID( irq, domask, &pgid);
-					first = 0;
+		if (domask) {
+			ret = s390_SetPGID (irq, domask);
 
-					if ( ret == 0 )
-					{
-						/*
-						 * Check whether we retrieved
-						 *  a reasonable PGID ...
-						 */	
-						if ( pgid.inf.ps.state1 == SNID_STATE1_GROUPED )
-						{
-							memcpy( &(ioinfo[irq]->pgid),
-							        &pgid,
-							        sizeof(pgid_t) );
-						}
-						else // ungrouped or garbage ...
-						{
-							ret = -EOPNOTSUPP;
+			/*
+			 * For the *first* path we are prepared
+			 *  for recovery
+			 *
+			 *  - If we fail setting the PGID we assume its
+			 *     using  a different PGID already (VM) we
+			 *     try to sense.
+			 */
+			if (ret == -EOPNOTSUPP && first) {
+				*(int *) &pgid = 0;
+
+				ret = s390_SensePGID (irq, domask, &pgid);
+				first = 0;
+
+				if (ret == 0) {
+					/*
+					 * Check whether we retrieved
+					 *  a reasonable PGID ...
+					 */
+					if (pgid.inf.ps.state1 ==
+					    SNID_STATE1_GROUPED) {
+						memcpy (&ioinfo[irq]->pgid,
+							&pgid, sizeof (pgid_t));
+					} else {	/* ungrouped or garbage ... */
+						ret = -EOPNOTSUPP;
 
-						} /* endif */
 					}
-					else
-					{
-						ioinfo[irq]->ui.flags.pgid_supp = 0;
+				} else {
+					ioinfo[irq]->ui.flags.pgid_supp = 0;
 
 #ifdef CONFIG_DEBUG_IO
-						printk( KERN_WARNING "PathVerification(%04X) "
-						        "- Device %04X doesn't "
-						        " support path grouping\n",
-						        irq,
-						        ioinfo[irq]->schib.pmcw.dev);
-#endif
-						if (cio_debug_initialized)
-							debug_sprintf_event(cio_debug_msg_id, 2,
-									    "PathVerification(%04X) "
-									    "- Device %04X doesn't "
-									    " support path grouping\n",
-									    irq,
-									    ioinfo[irq]->schib.pmcw.dev);		    
-
-					} /* endif */
+					printk (KERN_WARNING
+						"PathVerification(%04X) "
+						"- Device %04X doesn't "
+						" support path grouping\n",
+						irq,
+						ioinfo[irq]->schib.pmcw.dev);
+#endif
+					CIO_MSG_EVENT(2,
+						      "PathVerification(%04X) "
+						      "- Device %04X doesn't "
+						      " support path grouping\n",
+						      irq,
+						      ioinfo[irq]->schib.
+						      pmcw.dev);
+					
 				}
-				else if ( ret == -EIO ) 
-				{
+			} else if (ret == -EIO) {
 #ifdef CONFIG_DEBUG_IO
-					printk( KERN_ERR "PathVerification(%04X) - I/O error "
-					       "on device %04X\n", irq,
-					       ioinfo[irq]->schib.pmcw.dev);
+				printk (KERN_ERR
+					"PathVerification(%04X) - I/O error "
+					"on device %04X\n", irq,
+					ioinfo[irq]->schib.pmcw.dev);
 #endif
 
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_msg_id, 2,
-								    "PathVerification(%04X) - I/O error "
-								    "on device %04X\n", irq,
-								    ioinfo[irq]->schib.pmcw.dev);
+				CIO_MSG_EVENT(2,
+					      "PathVerification(%04X) - I/O error "
+					      "on device %04X\n", irq,
+					      ioinfo[irq]->schib.pmcw.dev);
+				
+				ioinfo[irq]->ui.flags.pgid_supp = 0;
 
-					ioinfo[irq]->ui.flags.pgid_supp = 0;
-		    
-				} else {
+			} else if (ret == -ETIMEDOUT) {
 #ifdef CONFIG_DEBUG_IO
-					printk( KERN_ERR "PathVerification(%04X) "
-						"- Unexpected error on device %04X\n",
-						irq,
-						ioinfo[irq]->schib.pmcw.dev);
+				printk (KERN_ERR
+					"PathVerification(%04X) - I/O timed "
+					"out on device %04X\n", 
+					irq,
+					ioinfo[irq]->schib.pmcw.dev);
 #endif
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_msg_id, 2,
-								    "PathVerification(%04X) - "
-								    "Unexpected error on device %04X\n",
-								    irq,
-								    ioinfo[irq]->schib.pmcw.dev);		    
-					
-					ioinfo[irq]->ui.flags.pgid_supp = 0;
-					
-				} /* endif */
+				CIO_MSG_EVENT(2,
+					      "PathVerification(%04X) - I/O timed "
+					      "out on device %04X\n", irq,
+					      ioinfo[irq]->schib.pmcw.dev);
+				
+				ioinfo[irq]->ui.flags.pgid_supp = 0;
 
-			} /* endif */
-			
-		} /* endfor */
+			} else if (ret == -EAGAIN) {
 
-	} /* endif */
+				ret = 0;
 
+			} else if (ret == -EUSERS) {
+				
+#ifdef CONFIG_DEBUG_IO
+				printk (KERN_ERR 
+					"PathVerification(%04X) "
+					"- Device is locked by someone else!\n",
+					irq);
+#endif
+				CIO_MSG_EVENT(2,
+					      "PathVerification(%04X) "
+					      "- Device is locked by someone else!\n",
+					      irq);
+			} else if (ret == -ENODEV) {
+#ifdef CONFIG_DEBUG_IO
+				printk (KERN_ERR 
+					"PathVerification(%04X) "
+					"- Device %04X is no longer there?!?\n",
+					irq, ioinfo[irq]->schib.pmcw.dev);
+#endif
+				CIO_MSG_EVENT(2,
+					      "PathVerification(%04X) "
+					      "- Device %04X is no longer there?!?\n",
+					      irq, ioinfo[irq]->schib.pmcw.dev);
+			} else if (ret) {
+#ifdef CONFIG_DEBUG_IO
+				printk (KERN_ERR
+					"PathVerification(%04X) "
+					"- Unexpected error %d on device %04X\n",
+					irq, ret, ioinfo[irq]->schib.pmcw.dev);
+#endif
+				CIO_MSG_EVENT(2,
+					      "PathVerification(%04X) - "
+					      "Unexpected error %d on device %04X\n",
+					      irq, ret, ioinfo[irq]->schib.pmcw.dev);
+				
+				ioinfo[irq]->ui.flags.pgid_supp = 0;
+			}
+		}
+	}
 	return ret;
 
 }
@@ -5796,275 +5964,285 @@
  * Set Path Group ID
  *
  */
-int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
+int
+s390_SetPGID (int irq, __u8 lpm)
 {
-	ccw1_t    *spid_ccw;    /* ccw area for SPID command */
-	devstat_t  devstat;     /* required by request_irq() */
+	ccw1_t *spid_ccw;	/* ccw area for SPID command */
+	devstat_t devstat;	/* required by request_irq() */
 	devstat_t *pdevstat = &devstat;
-        unsigned long flags;
+	unsigned long flags;
 	char dbf_txt[15];
 
+	int irq_ret = 0;	/* return code */
+	int retry = 5;		/* retry count */
+	int inlreq = 0;		/* inline request_irq() */
+	int mpath = 1;		/* try multi-path first */
 
-	int        irq_ret = 0; /* return code */
-	int        retry   = 5; /* retry count */
-	int        inlreq  = 0; /* inline request_irq() */
-	int        mpath   = 1; /* try multi-path first */
+	SANITY_CHECK (irq);
 
-	SANITY_CHECK(irq);
+	if (ioinfo[irq]->ui.flags.oper == 0) {
+		return (-ENODEV);
 
-	if ( ioinfo[irq]->ui.flags.oper == 0 )
-	{
-		return( -ENODEV );
+	}
 
-	} /* endif */
+ 	if (ioinfo[irq]->ui.flags.unfriendly) {
+ 		/* don't even try it */
+ 		return -EUSERS;
+ 	}
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt,"SPID%x",irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "SPID%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
+	if (!ioinfo[irq]->ui.flags.ready) {
 		/*
 		 * Perform SetPGID command processing. We have to request device
 		 *  ownership and provide a dummy I/O handler. We issue sync. I/O
 		 *  requests and evaluate the devstat area on return therefore
 		 *  we don't need a real I/O handler in place.
 		 */
-		irq_ret = request_irq( irq,
-		                       init_IRQ_handler,
-		                       SA_PROBE,
-		                       "SPID",
-		                       pdevstat);
+		irq_ret = request_irq (irq,
+				       init_IRQ_handler,
+				       SA_PROBE, "SPID", pdevstat);
 
-		if ( irq_ret == 0 )
+		if (irq_ret == 0)
 			inlreq = 1;
-	}
-	else
-	{
+	} else {
 		pdevstat = ioinfo[irq]->irq_desc.dev_id;
 
-	} /* endif */
-
-	if ( irq_ret == 0 )
-	{
-		s390irq_spin_lock_irqsave( irq, flags);
+	}
 
-		if ( init_IRQ_complete )
-		{
-			spid_ccw = kmalloc( 2*sizeof( ccw1_t), GFP_DMA);
-		}
-		else	
-		{
-			spid_ccw = alloc_bootmem_low( 2*sizeof( ccw1_t));
+	if (irq_ret) {
+		return irq_ret;
+	}
 
-		} /* endif */
+	s390irq_spin_lock_irqsave (irq, flags);
 
-		spid_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN;	
-		spid_ccw[0].cda      = 0;
-		spid_ccw[0].count    = 0;
-		spid_ccw[0].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
+	if (init_IRQ_complete) {
+		spid_ccw = kmalloc (2 * sizeof (ccw1_t), GFP_DMA);
+	} else {
+		spid_ccw = alloc_bootmem_low (2 * sizeof (ccw1_t));
 
-		spid_ccw[1].cmd_code = CCW_CMD_SET_PGID;
-		spid_ccw[1].cda      = (__u32)virt_to_phys( pgid );
-		spid_ccw[1].count    = sizeof( pgid_t);
-		spid_ccw[1].flags    = CCW_FLAG_SLI;
+	}
 
-		pgid->inf.fc = SPID_FUNC_MULTI_PATH | SPID_FUNC_ESTABLISH;
+	spid_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN;
+	spid_ccw[0].cda = 0;
+	spid_ccw[0].count = 0;
+	spid_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
 
-		/*
-		 * We now issue a SetPGID request. In case of BUSY
-		 *  or STATUS PENDING conditions we retry 5 times.
-		 */
-		do
-		{
-			memset( pdevstat, '\0', sizeof( devstat_t) );
+	spid_ccw[1].cmd_code = CCW_CMD_SET_PGID;
+	spid_ccw[1].cda = (__u32) virt_to_phys (&ioinfo[irq]->pgid);
+	spid_ccw[1].count = sizeof (pgid_t);
+	spid_ccw[1].flags = CCW_FLAG_SLI;
 
-			irq_ret = s390_start_IO( irq,
-			                         spid_ccw,
-			                         0xE2D7C9C4,  // == SPID
-			                         lpm,         // n/a
-			                         DOIO_WAIT_FOR_INTERRUPT
-			                          | DOIO_VALID_LPM
-			                          | DOIO_DONT_CALL_INTHDLR );
+	ioinfo[irq]->pgid.inf.fc = SPID_FUNC_MULTI_PATH | SPID_FUNC_ESTABLISH;
 
-			if ( !irq_ret )
-			{
-				if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
-				{
-#ifdef CONFIG_DEBUG_IO
-					printk( KERN_DEBUG "SPID - Device %04X "
-					        "on Subchannel %04X "
-					        "reports pending status, "
-					        "retry : %d\n",
-					        ioinfo[irq]->schib.pmcw.dev,
-					        irq,
-					        retry);
-#endif
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_msg_id, 2,
-								    "SPID - Device %04X "
-								    "on Subchannel %04X "
-								    "reports pending status, "
-								    "retry : %d\n",
-								    ioinfo[irq]->schib.pmcw.dev,
-								    irq,
-								    retry);	    
-					retry--;
-					irq_ret = -EIO;
-				} /* endif */
+	/*
+	 * We now issue a SetPGID request. In case of BUSY
+	 *  or STATUS PENDING conditions we retry 5 times.
+	 */
+	do {
+		memset (pdevstat, '\0', sizeof (devstat_t));
 
-				if ( pdevstat->flag == (   DEVSTAT_START_FUNCTION
-				                         | DEVSTAT_FINAL_STATUS   ) )
-				{
-					retry = 0;	// successfully set ...
-					irq_ret = 0;
-				}
-				else if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
-				{
-					/*
-					 * If the device doesn't support the
-					 *  Sense Path Group ID command
-					 *  further retries wouldn't help ...
-					 */
-					if ( pdevstat->ii.sense.data[0] & SNS0_CMD_REJECT )
-					{
-						if ( mpath )
-						{
-							/*
-							 * We now try single path mode.
-							 * Note we must not issue the suspend
-							 * multipath reconnect, or we will get
-							 * a command reject by tapes.
-							 */
-							
-							spid_ccw[0].cmd_code = CCW_CMD_SET_PGID;
-							spid_ccw[0].cda      = (__u32)virt_to_phys( pgid );
-							spid_ccw[0].count    = sizeof( pgid_t);
-							spid_ccw[0].flags    = CCW_FLAG_SLI;
-
-							pgid->inf.fc =   SPID_FUNC_SINGLE_PATH
-							               | SPID_FUNC_ESTABLISH;
-							mpath        = 0;
-							retry--;
-							irq_ret = -EIO;
-						}
-						else
-						{
-							irq_ret = -EOPNOTSUPP;
-							retry   = 0;			
+		irq_ret = s390_start_IO (irq, spid_ccw, 0xE2D7C9C4,	/* == SPID */
+					 lpm,	/* n/a */
+					 DOIO_WAIT_FOR_INTERRUPT
+					 | DOIO_VALID_LPM
+					 | DOIO_DONT_CALL_INTHDLR
+					 | DOIO_TIMEOUT);
 
-						} /* endif */
-					}
-					else
-					{
+		if (!irq_ret) {
+			if (pdevstat->flag & DEVSTAT_STATUS_PENDING) {
 #ifdef CONFIG_DEBUG_IO
-						printk( KERN_WARNING "SPID - device %04X,"
-						        " unit check,"
-						        " retry %d, cnt %02d,"
-						        " sns :"
-						        " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
-						        ioinfo[irq]->schib.pmcw.dev,
-						        retry,
-						        pdevstat->scnt,
-						        pdevstat->ii.sense.data[0],
-						        pdevstat->ii.sense.data[1],
-						        pdevstat->ii.sense.data[2],
-						        pdevstat->ii.sense.data[3],
-						        pdevstat->ii.sense.data[4],
-						        pdevstat->ii.sense.data[5],
-						        pdevstat->ii.sense.data[6],
-						        pdevstat->ii.sense.data[7]);
-#endif
-
-						if (cio_debug_initialized)
-							debug_sprintf_event(cio_debug_msg_id, 2,
-									    "SPID - device %04X,"
-									    " unit check,"
-									    " retry %d, cnt %02d,"
-									    " sns :"
-									    " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
-									    ioinfo[irq]->schib.pmcw.dev,
-									    retry,
-									    pdevstat->scnt,
-									    pdevstat->ii.sense.data[0],
-									    pdevstat->ii.sense.data[1],
-									    pdevstat->ii.sense.data[2],
-									    pdevstat->ii.sense.data[3],
-									    pdevstat->ii.sense.data[4],
-									    pdevstat->ii.sense.data[5],
-									    pdevstat->ii.sense.data[6],
-									    pdevstat->ii.sense.data[7]);
+				printk (KERN_DEBUG "SPID - Device %04X "
+					"on Subchannel %04X "
+					"reports pending status, "
+					"retry : %d\n",
+					ioinfo[irq]->schib.pmcw.dev,
+					irq, retry);
+#endif
+				CIO_MSG_EVENT(2,
+					      "SPID - Device %04X "
+					      "on Subchannel %04X "
+					      "reports pending status, "
+					      "retry : %d\n",
+					      ioinfo[irq]->schib.pmcw.
+					      dev, irq, retry);
+				retry--;
+				irq_ret = -EIO;
+			}
+
+			if (pdevstat->flag == (DEVSTAT_START_FUNCTION
+					       | DEVSTAT_FINAL_STATUS)) {
+				retry = 0;	/* successfully set ... */
+				irq_ret = 0;
+			} else if (pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+				/*
+				 * If the device doesn't support the
+				 *  Sense Path Group ID command
+				 *  further retries wouldn't help ...
+				 */
+				if (pdevstat->ii.sense.
+				    data[0] & SNS0_CMD_REJECT) {
+					if (mpath) {
+						/*
+						 * We now try single path mode.
+						 * Note we must not issue the suspend
+						 * multipath reconnect, or we will get
+						 * a command reject by tapes.
+						 */
 
+						spid_ccw[0].cmd_code =
+						    CCW_CMD_SET_PGID;
+						spid_ccw[0].cda = (__u32)
+						    virt_to_phys (&ioinfo[irq]->pgid);
+						spid_ccw[0].count =
+						    sizeof (pgid_t);
+						spid_ccw[0].flags =
+						    CCW_FLAG_SLI;
+
+						ioinfo[irq]->pgid.inf.fc =
+						    SPID_FUNC_SINGLE_PATH
+						    | SPID_FUNC_ESTABLISH;
+						mpath = 0;
 						retry--;
 						irq_ret = -EIO;
-		    
-					} /* endif */
+					} else {
+						irq_ret = -EOPNOTSUPP;
+						retry = 0;
 
-				}
-				else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
-				{
-					/* don't issue warnings during startup unless requested*/
-					if (init_IRQ_complete || cio_notoper_msg) {   
-						
-						printk( KERN_WARNING "SPID - Device %04X "
-							"on Subchannel %04X "
-							"became 'not operational'\n",
-							ioinfo[irq]->schib.pmcw.dev,
-							irq);
-						if (cio_debug_initialized)
-							debug_sprintf_event(cio_debug_msg_id, 2,
-									    "SPID - Device %04X "
-									    "on Subchannel %04X "
-									    "became 'not operational'\n",
-									    ioinfo[irq]->schib.pmcw.dev,
-									    irq);		    
 					}
+				} else {
+#ifdef CONFIG_DEBUG_IO
+					printk (KERN_WARNING
+						"SPID - device %04X,"
+						" unit check,"
+						" retry %d, cnt %02d,"
+						" sns :"
+						" %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+						ioinfo[irq]->schib.pmcw.
+						dev, retry,
+						pdevstat->scnt,
+						pdevstat->ii.sense.
+						data[0],
+						pdevstat->ii.sense.
+						data[1],
+						pdevstat->ii.sense.
+						data[2],
+						pdevstat->ii.sense.
+						data[3],
+						pdevstat->ii.sense.
+						data[4],
+						pdevstat->ii.sense.
+						data[5],
+						pdevstat->ii.sense.
+						data[6],
+						pdevstat->ii.sense.data[7]);
+#endif
+
+					CIO_MSG_EVENT(2,
+						     "SPID - device %04X,"
+						     " unit check,"
+						     " retry %d, cnt %02d,"
+						     " sns :"
+						     " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+						     ioinfo[irq]->schib.
+						     pmcw.dev, retry,
+						     pdevstat->scnt,
+						     pdevstat->ii.sense.
+						     data[0],
+						     pdevstat->ii.sense.
+						     data[1],
+						     pdevstat->ii.sense.
+						     data[2],
+						     pdevstat->ii.sense.
+						     data[3],
+						     pdevstat->ii.sense.
+						     data[4],
+						     pdevstat->ii.sense.
+						     data[5],
+						     pdevstat->ii.sense.
+						     data[6],
+						     pdevstat->ii.sense.
+						     data[7]);
 
-					retry = 0;
+					retry--;
 					irq_ret = -EIO;
 
-				} /* endif */
+				}
+
+			} else if (pdevstat->flag & DEVSTAT_NOT_OPER) {
+				/* don't issue warnings during startup unless requested */
+				if (init_IRQ_complete || cio_notoper_msg) {
+
+					printk (KERN_WARNING
+						"SPID - Device %04X "
+						"on Subchannel %04X, "
+						"lpm %02X, "
+						"became 'not operational'\n",
+						ioinfo[irq]->schib.pmcw.
+						dev, irq,
+						lpm);
+					CIO_MSG_EVENT(2,
+						     "SPID - Device %04X "
+						     "on Subchannel %04X, "
+						      "lpm %02X, "
+						     "became 'not operational'\n",
+						     ioinfo[irq]->schib.
+						     pmcw.dev, irq,
+						     lpm);
+				}
+
+				retry = 0;
+				ioinfo[irq]->opm &= ~lpm;
+				irq_ret = -EAGAIN;
+
 			}
-			else if ( irq_ret != -ENODEV )
-			{
-				retry--;
-				irq_ret = -EIO;
-			}
-			else
-			{
-				retry = 0;
-				irq_ret = -ENODEV;
 
-			} /* endif */
+		} else if (irq_ret == -ETIMEDOUT) {
+			/* 
+			 * SetPGID timed out, so we cancel it before
+			 * we retry
+			 */
+			int xret;
 
-		} while ( retry > 0 );
+			xret = cancel_IO(irq);
 
+			if (!xret) 
+				CIO_MSG_EVENT(2,
+					      "SetPGID: sch canceled "
+					      "successfully for irq %x\n",
+					      irq);
+			retry--;
+
+		} else if (irq_ret != -ENODEV) {
+			retry--;
+			irq_ret = -EIO;
+		} else {
+			retry = 0;
+			irq_ret = -ENODEV;
 
-		if ( init_IRQ_complete )
-		{
-			kfree( spid_ccw );
 		}
-		else	
-		{
-			free_bootmem( (unsigned long)spid_ccw, 2*sizeof(ccw1_t) );
 
-		} /* endif */
+	} while (retry > 0);
 
-		s390irq_spin_unlock_irqrestore( irq, flags);
+	if (init_IRQ_complete) {
+		kfree (spid_ccw);
+	} else {
+		free_bootmem ((unsigned long) spid_ccw, 2 * sizeof (ccw1_t));
 
-		/*
-		 * If we installed the irq action handler we have to
-		 *  release it too.
-		 */
-		if ( inlreq )
-			free_irq( irq, pdevstat);
+	}
 
-	} /* endif */
+	s390irq_spin_unlock_irqrestore (irq, flags);
 
-   return( irq_ret );
-}
+	/*
+	 * If we installed the irq action handler we have to
+	 *  release it too.
+	 */
+	if (inlreq)
+		free_irq (irq, pdevstat);
 
+	return (irq_ret);
+}
 
 /*
  * s390_SensePGID
@@ -6072,253 +6250,1360 @@
  * Sense Path Group ID
  *
  */
-int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
+int
+s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid)
 {
-	ccw1_t    *snid_ccw;    /* ccw area for SNID command */
-	devstat_t  devstat;     /* required by request_irq() */
+	ccw1_t *snid_ccw;	/* ccw area for SNID command */
+	devstat_t devstat;	/* required by request_irq() */
 	devstat_t *pdevstat = &devstat;
 	char dbf_txt[15];
+	pgid_t * tmp_pgid;
 
-	int        irq_ret = 0; /* return code */
-	int        retry   = 5; /* retry count */
-	int        inlreq  = 0; /* inline request_irq() */
+	int irq_ret = 0;	/* return code */
+	int retry = 5;		/* retry count */
+	int inlreq = 0;		/* inline request_irq() */
 	unsigned long flags;
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if ( ioinfo[irq]->ui.flags.oper == 0 )
-	{
-		return( -ENODEV );
+	if (ioinfo[irq]->ui.flags.oper == 0) {
+		return (-ENODEV);
 
-	} /* endif */
-
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt,"SNID%x",irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
 	}
 
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
+	sprintf (dbf_txt, "SNID%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	if (!ioinfo[irq]->ui.flags.ready) {
 		/*
 		 * Perform SENSE PGID command processing. We have to request device
 		 *  ownership and provide a dummy I/O handler. We issue sync. I/O
 		 *  requests and evaluate the devstat area on return therefore
 		 *  we don't need a real I/O handler in place.
 		 */
-		irq_ret = request_irq( irq,
-		                       init_IRQ_handler,
-		                       SA_PROBE,
-		                       "SNID",
-		                       pdevstat);
+		irq_ret = request_irq (irq,
+				       init_IRQ_handler,
+				       SA_PROBE, "SNID", pdevstat);
 
-		if ( irq_ret == 0 )
+		if (irq_ret == 0)
 			inlreq = 1;
 
-   }
-	else
-	{
+	} else {
 		pdevstat = ioinfo[irq]->irq_desc.dev_id;
 
-	} /* endif */
+	}
+
+	if (irq_ret) {
+		return irq_ret;
+	}
+
+	s390irq_spin_lock_irqsave (irq, flags);
+
+	ioinfo[irq]->ui.flags.unfriendly = 0; /* assume it's friendly... */
+
+	if (init_IRQ_complete) {
+		snid_ccw = kmalloc (sizeof (ccw1_t), GFP_DMA);
+		tmp_pgid = kmalloc (sizeof (pgid_t), GFP_DMA);
+	} else {
+		snid_ccw = alloc_bootmem_low (sizeof (ccw1_t));
+		tmp_pgid = alloc_bootmem_low (sizeof (pgid_t));
+	}
+
+	snid_ccw->cmd_code = CCW_CMD_SENSE_PGID;
+	snid_ccw->cda = (__u32) virt_to_phys (tmp_pgid);
+	snid_ccw->count = sizeof (pgid_t);
+	snid_ccw->flags = CCW_FLAG_SLI;
+
+	/*
+	 * We now issue a SensePGID request. In case of BUSY
+	 *  or STATUS PENDING conditions we retry 5 times.
+	 */
+	do {
+		memset (pdevstat, '\0', sizeof (devstat_t));
+
+		irq_ret = s390_start_IO (irq, snid_ccw, 0xE2D5C9C4,	/* == SNID */
+					 lpm,	/* n/a */
+					 DOIO_WAIT_FOR_INTERRUPT
+ 					 | DOIO_TIMEOUT
+					 | DOIO_VALID_LPM
+					 | DOIO_DONT_CALL_INTHDLR);
+
+		if (irq_ret == 0) {
+			if (pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+				/*
+				 * If the device doesn't support the
+				 *  Sense Path Group ID command
+				 *  further retries wouldn't help ...
+				 */
+				if (pdevstat->ii.sense.data[0] & 
+				    (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)) {
+					retry = 0;
+					irq_ret = -EOPNOTSUPP;
+				} else {
+#ifdef CONFIG_DEBUG_IO
+					printk (KERN_WARNING
+						"SNID - device %04X,"
+						" unit check,"
+						" flag %04X, "
+						" retry %d, cnt %02d,"
+						" sns :"
+						" %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+						ioinfo[irq]->schib.pmcw.
+						dev, pdevstat->flag,
+						retry, pdevstat->scnt,
+						pdevstat->ii.sense.
+						data[0],
+						pdevstat->ii.sense.
+						data[1],
+						pdevstat->ii.sense.
+						data[2],
+						pdevstat->ii.sense.
+						data[3],
+						pdevstat->ii.sense.
+						data[4],
+						pdevstat->ii.sense.
+						data[5],
+						pdevstat->ii.sense.
+						data[6],
+						pdevstat->ii.sense.data[7]);
+
+#endif
+					CIO_MSG_EVENT(2,
+						     "SNID - device %04X,"
+						     " unit check,"
+						     " flag %04X, "
+						     " retry %d, cnt %02d,"
+						     " sns :"
+						     " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+						     ioinfo[irq]->schib.
+						     pmcw.dev,
+						     pdevstat->flag,
+						     retry,
+						     pdevstat->scnt,
+						     pdevstat->ii.sense.
+						     data[0],
+						     pdevstat->ii.sense.
+						     data[1],
+						     pdevstat->ii.sense.
+						     data[2],
+						     pdevstat->ii.sense.
+						     data[3],
+						     pdevstat->ii.sense.
+						     data[4],
+						     pdevstat->ii.sense.
+						     data[5],
+						     pdevstat->ii.sense.
+						     data[6],
+						     pdevstat->ii.sense.
+						     data[7]);
+					retry--;
+					irq_ret = -EIO;
+
+				}
+			} else if (pdevstat->flag & DEVSTAT_NOT_OPER) {
+				/* don't issue warnings during startup unless requested */
+				if (init_IRQ_complete || cio_notoper_msg) {
+					printk (KERN_WARNING
+						"SNID - Device %04X "
+						"on Subchannel %04X, "
+						"lpm %02X, "
+						"became 'not operational'\n",
+						ioinfo[irq]->schib.pmcw.
+						dev, irq,
+						lpm);
+					CIO_MSG_EVENT(2,
+						     "SNID - Device %04X "
+						     "on Subchannel %04X, "
+						     "lpm %02X, "
+						     "became 'not operational'\n",
+						     ioinfo[irq]->schib.
+						     pmcw.dev, irq,
+						     lpm);
+				}
+
+				retry = 0;
+				irq_ret = -EIO;
+
+			} else {
+				retry = 0;	/* success ... */
+				irq_ret = 0;
+ 				/*
+ 				 * Check if device is locked by someone else
+ 				 * -- we'll fail other commands if that is
+ 				 * the case
+ 				 */
+ 				if (pgid->inf.ps.state2 ==
+ 				    SNID_STATE2_RESVD_ELSE) {
+ 					printk (KERN_WARNING 
+ 						"SNID - Device %04X "
+ 						"on Subchannel %04X "
+ 						"is reserved by "
+ 						"someone else\n",
+ 						ioinfo[irq]->schib.pmcw.dev,
+ 						irq);
+ 					CIO_MSG_EVENT(2,
+ 						      "SNID - Device %04X "
+ 						      "on Subchannel %04X "
+ 						      "is reserved by "
+ 						      "someone else\n",
+ 						      ioinfo[irq]->schib.
+ 						      pmcw.dev,
+ 						      irq);
+ 				
+ 					ioinfo[irq]->ui.flags.unfriendly = 1;
+ 				} else {
+ 					/*
+ 					 * device is friendly to us :)
+ 					 */
+ 					ioinfo[irq]->ui.flags.unfriendly = 0;
+ 				}
+				memcpy(pgid, tmp_pgid, sizeof(pgid_t));
+			}
+
+ 		} else if (irq_ret == -ETIMEDOUT) {
+#ifdef CONFIG_DEBUG_IO
+ 			printk(KERN_INFO "SNID - Operation timed out "
+ 			       "on Device %04X, Subchannel %04X... "
+ 			       "cancelling IO\n",
+ 			       ioinfo[irq]->schib.pmcw.dev,
+ 			       irq);
+#endif /* CONFIG_DEBUG_IO */
+ 			CIO_MSG_EVENT(2,
+ 				      "SNID - Operation timed out "
+ 				      "on Device %04X, Subchannel %04X... "
+ 				      "cancelling IO\n",
+ 				      ioinfo[irq]->schib.pmcw.dev,
+ 				      irq);
+ 			cancel_IO(irq);
+ 			retry--;
+
+		} else if (irq_ret != -ENODEV) {	/* -EIO, or -EBUSY */
+
+			if (pdevstat->flag & DEVSTAT_STATUS_PENDING) {
+#ifdef CONFIG_DEBUG_IO
+				printk (KERN_INFO "SNID - Device %04X "
+					"on Subchannel %04X "
+					"reports pending status, "
+					"retry : %d\n",
+					ioinfo[irq]->schib.pmcw.dev,
+					irq, retry);
+#endif
+				CIO_MSG_EVENT(2,
+					     "SNID - Device %04X "
+					     "on Subchannel %04X "
+					     "reports pending status, "
+					     "retry : %d\n",
+					     ioinfo[irq]->schib.pmcw.
+					     dev, irq, retry);
+			}
+
+			printk (KERN_WARNING "SNID - device %04X,"
+				" start_io() reports rc : %d, retrying ...\n",
+				ioinfo[irq]->schib.pmcw.dev, irq_ret);
+			CIO_MSG_EVENT(2,
+				      "SNID - device %04X,"
+				      " start_io() reports rc : %d,"
+				      " retrying ...\n",
+				      ioinfo[irq]->schib.pmcw.dev, irq_ret);
+			retry--;
+			irq_ret = -EIO;
+		} else {	/* -ENODEV ... */
+
+			retry = 0;
+			irq_ret = -ENODEV;
+
+		}
+
+	} while (retry > 0);
+
+	if (init_IRQ_complete) {
+		kfree (snid_ccw);
+		kfree (tmp_pgid);
+	} else {
+		free_bootmem ((unsigned long) snid_ccw, sizeof (ccw1_t));
+		free_bootmem ((unsigned long) tmp_pgid, sizeof (pgid_t));
+
+	}
+
+	s390irq_spin_unlock_irqrestore (irq, flags);
+
+	/*
+	 * If we installed the irq action handler we have to
+	 *  release it too.
+	 */
+	if (inlreq)
+		free_irq (irq, pdevstat);
+
+	return (irq_ret);
+}
+
+void
+s390_process_subchannel_source (int irq)
+{
+	int dev_oper = 0;
+	int dev_no = -1;
+	int lock = 0;
+	int is_owned = 0;
+
+	/*
+	 * If the device isn't known yet
+	 *   we can't lock it ...
+	 */
+	if (ioinfo[irq] != INVALID_STORAGE_AREA) {
+		s390irq_spin_lock (irq);
+		lock = 1;
+
+		if (!ioinfo[irq]->st) {
+			dev_oper = ioinfo[irq]->ui.flags.oper;
+			
+			if (ioinfo[irq]->ui.flags.dval)
+				dev_no = ioinfo[irq]->devno;
+			
+			is_owned = ioinfo[irq]->ui.flags.ready;
+		}
+
+	}
+#ifdef CONFIG_DEBUG_CRW
+	printk (KERN_DEBUG
+		"do_crw_pending : subchannel validation - start ...\n");
+#endif
+	CIO_CRW_EVENT(4, "subchannel validation - start\n");
+	s390_validate_subchannel (irq, is_owned);
+
+	if (irq > highest_subchannel)
+		highest_subchannel = irq;
+
+#ifdef CONFIG_DEBUG_CRW
+	printk (KERN_DEBUG "do_crw_pending : subchannel validation - done\n");
+#endif
+	CIO_CRW_EVENT(4, "subchannel validation - done\n");
+	/*
+	 * After the validate processing
+	 *   the ioinfo control block
+	 *   should be allocated ...
+	 */
+	if (lock) {
+		s390irq_spin_unlock (irq);
+	}
+
+	if (ioinfo[irq] != INVALID_STORAGE_AREA) {
+#ifdef CONFIG_DEBUG_CRW
+		printk (KERN_DEBUG "do_crw_pending : ioinfo at "
+#ifdef CONFIG_ARCH_S390X
+			"%08lX\n", (unsigned long) ioinfo[irq]
+#else				/* CONFIG_ARCH_S390X */
+			"%08X\n", (unsigned) ioinfo[irq]
+#endif				/* CONFIG_ARCH_S390X */
+			);
+#endif
+#ifdef CONFIG_ARCH_S390X
+		CIO_CRW_EVENT(4, "ioinfo at %08lX\n", 
+			      (unsigned long)ioinfo[irq]);
+#else				/* CONFIG_ARCH_S390X */
+		CIO_CRW_EVENT(4, "ioinfo at %08X\n", 
+			      (unsigned)ioinfo[irq]);
+#endif				/* CONFIG_ARCH_S390X */
+
+		if (ioinfo[irq]->st)
+			return;
+
+		if (ioinfo[irq]->ui.flags.oper == 0) {
+			not_oper_handler_func_t nopfunc = ioinfo[irq]->nopfunc;
+#ifdef CONFIG_PROC_FS
+			/* remove procfs entry */
+			if (cio_proc_devinfo)
+				cio_procfs_device_remove (dev_no);
+#endif
+			/*
+			 * If the device has gone
+			 *  call not oper handler               
+			 */
+			if ((dev_oper == 1)
+			    && (nopfunc != NULL)) {
+
+				free_irq (irq, ioinfo[irq]->irq_desc.dev_id);
+				nopfunc (irq, DEVSTAT_DEVICE_GONE);
+
+			}
+		} else {
+#ifdef CONFIG_DEBUG_CRW
+			printk (KERN_DEBUG
+				"do_crw_pending : device "
+				"recognition - start ...\n");
+#endif
+			CIO_CRW_EVENT( 4,
+				       "device recognition - start\n");
+			s390_device_recognition_irq (irq);
+
+#ifdef CONFIG_DEBUG_CRW
+			printk (KERN_DEBUG
+				"do_crw_pending : device "
+				"recognition - done\n");
+#endif
+			CIO_CRW_EVENT( 4,
+				       "device recognition - done\n");
+			/*
+			 * the device became operational
+			 */
+			if (dev_oper == 0) {
+				devreg_t *pdevreg;
+
+				pdevreg = s390_search_devreg (ioinfo[irq]);
+
+				if (pdevreg != NULL) {
+					if (pdevreg->oper_func != NULL)
+						pdevreg->
+						    oper_func (irq, pdevreg);
+
+				}
+#ifdef CONFIG_PROC_FS
+				/* add new procfs entry */
+				if (cio_proc_devinfo)
+					if (highest_subchannel <
+					    MAX_CIO_PROCFS_ENTRIES) {
+						cio_procfs_device_create
+						    (ioinfo[irq]->devno);
+					}
+#endif
+			}
+			/*
+			 * ... it is and was operational, but
+			 *      the devno may have changed
+			 */
+			else if ((ioinfo[irq]->devno != dev_no)
+				 && (ioinfo[irq]->nopfunc != NULL)) {
+#ifdef CONFIG_PROC_FS
+				int devno_old = ioinfo[irq]->devno;
+#endif
+				ioinfo[irq]->nopfunc (irq, DEVSTAT_REVALIDATE);
+#ifdef CONFIG_PROC_FS
+				/* remove old entry, add new */
+				if (cio_proc_devinfo) {
+					cio_procfs_device_remove (devno_old);
+					cio_procfs_device_create
+					    (ioinfo[irq]->devno);
+				}
+#endif
+			}
+		}
+#ifdef CONFIG_PROC_FS
+		/* get rid of dead procfs entries */
+		if (cio_proc_devinfo)
+			cio_procfs_device_purge ();
+#endif
+	}
+}
+
+#ifdef CONFIG_CHSC
+static int 
+chsc_get_sch_desc_irq(int irq)
+{
+	int j = 0;
+	int ccode;
+
+	spin_lock(&chsc_lock_ssd);
+		
+	if (!chsc_area_ssd)
+		chsc_area_ssd = kmalloc(sizeof(chsc_area_t),GFP_KERNEL);
+	
+	if (!chsc_area_ssd) {
+		printk( KERN_CRIT "No memory to determine sch descriptions...\n");
+		spin_unlock(&chsc_lock_ssd);
+		return -ENOMEM;
+	}
+	
+	memset(chsc_area_ssd, 0, sizeof(chsc_area_t));
+	
+	chsc_area_ssd->request_block.command_code1=0x0010;
+	chsc_area_ssd->request_block.command_code2=0x0004;
+	chsc_area_ssd->request_block.request_block_data.ssd_req.f_sch=irq;
+	chsc_area_ssd->request_block.request_block_data.ssd_req.l_sch=irq;
+	
+	ccode = chsc(chsc_area_ssd);
+#ifdef CONFIG_DEBUG_CHSC
+	if (ccode)
+		printk( KERN_DEBUG "chsc returned with ccode = %d\n",ccode);
+#endif /* CONFIG_DEBUG_CHSC */
+	if (!ccode) {
+		if (chsc_area_ssd->response_block.response_code == 0x0003) {
+#ifdef CONFIG_DEBUG_CHSC
+			printk( KERN_WARNING "Error in chsc request block!\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			CIO_CRW_EVENT( 2, "Error in chsc request block!\n");
+			spin_unlock(&chsc_lock_ssd);
+			return -EINVAL;
+			
+		} else if (chsc_area_ssd->response_block.response_code == 0x0004) {
+#ifdef CONFIG_DEBUG_CHSC
+			printk( KERN_WARNING "Model does not provide ssd\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			CIO_CRW_EVENT( 2, "Model does not provide ssd\n");
+			spin_unlock(&chsc_lock_ssd);
+			return -EOPNOTSUPP;
+
+		} else if (chsc_area_ssd->response_block.response_code == 0x0002) {
+#ifdef CONFIG_DEBUG_CHSC
+			printk( KERN_WARNING "chsc: Invalid command!\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			CIO_CRW_EVENT( 2,
+				       "chsc: Invalid command!\n");
+			return -EINVAL;
+
+		} else if (chsc_area_ssd->response_block.response_code == 0x0001) {
+			/* everything ok */
+					
+			switch (chsc_area_ssd->response_block.response_block_data.ssd_res.st) {
+				
+			case 0:  /* I/O subchannel */
+				
+				/* 
+				 * All fields have meaning
+				 */
+#ifdef CONFIG_DEBUG_CHSC
+				if (cio_show_msg) 
+					printk( KERN_DEBUG 
+						"ssd: sch %x is I/O subchannel\n",
+						irq);
+#endif /* CONFIG_DEBUG_CHSC */
+				CIO_CRW_EVENT( 6,
+					       "ssd: sch %x is I/O subchannel\n",
+					       irq);
+
+				if (ioinfo[irq] == INVALID_STORAGE_AREA)
+					/* FIXME: we should do device rec. here... */
+					break;
+
+				ioinfo[irq]->ssd_info.valid = 1;
+				ioinfo[irq]->ssd_info.type = 0;
+				for (j=0;j<8;j++) {
+					if ((0x80 >> j) & 
+					    chsc_area_ssd->response_block.
+					    response_block_data.ssd_res.path_mask & 
+					    chsc_area_ssd->response_block.
+					    response_block_data.ssd_res.fla_valid_mask) {
+
+						if (chsc_area_ssd->response_block.
+						    response_block_data.ssd_res.chpid[j]) 
+
+							if (!test_and_set_bit
+							    (chsc_area_ssd->response_block.
+							     response_block_data.
+							     ssd_res.chpid[j],
+							     &chpids_known)) 
+
+								if (test_bit
+								    (chsc_area_ssd->response_block.
+								     response_block_data.
+								     ssd_res.chpid[j],
+								     &chpids_logical))
+
+									set_bit(chsc_area_ssd->response_block.
+										response_block_data.
+										ssd_res.chpid[j],
+										&chpids);
+
+						ioinfo[irq]->ssd_info.chpid[j] = 
+							chsc_area_ssd->response_block.
+							response_block_data.ssd_res.chpid[j];
+						ioinfo[irq]->ssd_info.fla[j] = 
+							chsc_area_ssd->response_block.
+							response_block_data.ssd_res.fla[j];
+					}
+				}
+				break;
+				
+			case 1:  /* CHSC subchannel */
+				
+				/*
+				 * Only sch_val, st and sch have meaning
+				 */
+#ifdef CONFIG_DEBUG_CHSC
+				if (cio_show_msg)
+					printk( KERN_DEBUG 
+						"ssd: sch %x is chsc subchannel\n",
+						irq);
+#endif /* CONFIG_DEBUG_CHSC */
+				CIO_CRW_EVENT( 6,
+					       "ssd: sch %x is chsc subchannel\n",
+					       irq);
+
+				if (ioinfo[irq] == INVALID_STORAGE_AREA)
+					/* FIXME: we should do device rec. here... */
+					break;
+
+				ioinfo[irq]->ssd_info.valid = 1;
+				ioinfo[irq]->ssd_info.type = 1;
+				break;
+				
+			case 2: /* Message subchannel */
+				
+				/*
+				 * All fields except unit_addr have meaning
+				 */
+#ifdef CONFIG_DEBUG_CHSC
+				if (cio_show_msg)
+					printk( KERN_DEBUG 
+						"ssd: sch %x is message subchannel\n",
+						irq);
+#endif
+				CIO_CRW_EVENT( 6,
+					       "ssd: sch %x is message subchannel\n",
+					       irq);
+
+				if (ioinfo[irq] == INVALID_STORAGE_AREA)
+					/* FIXME: we should do device rec. here... */
+					break;
+
+				ioinfo[irq]->ssd_info.valid = 1;
+				ioinfo[irq]->ssd_info.type = 2;
+				for (j=0;j<8;j++) {
+					if ((0x80 >> j) & 
+					    chsc_area_ssd->response_block.
+					    response_block_data.ssd_res.path_mask & 
+					    chsc_area_ssd->response_block.
+					    response_block_data.ssd_res.fla_valid_mask) {
+						if (chsc_area_ssd->response_block.
+						    response_block_data.ssd_res.chpid[j])
+
+							if (!test_and_set_bit
+							    (chsc_area_ssd->response_block.
+							     response_block_data.
+							     ssd_res.chpid[j],
+							     &chpids_known)) 
+
+								if (test_bit
+								    (chsc_area_ssd->response_block.
+								     response_block_data.
+								     ssd_res.chpid[j],
+								     &chpids_logical))
+
+									set_bit(chsc_area_ssd->response_block.
+										response_block_data.
+										ssd_res.chpid[j],
+										&chpids);
+
+						ioinfo[irq]->ssd_info.chpid[j] = 
+							chsc_area_ssd->response_block.
+							response_block_data.ssd_res.chpid[j];
+						ioinfo[irq]->ssd_info.fla[j] = 
+							chsc_area_ssd->response_block.
+							response_block_data.ssd_res.fla[j];
+					}
+				}
+				break;
+				
+			case 3: /* ADM subchannel */
+				
+				/*
+				 * Only sch_val, st and sch have meaning
+				 */
+#ifdef CONFIG_DEBUG_CHSC
+				if (cio_show_msg) 
+					printk( KERN_DEBUG 
+						"ssd: sch %x is ADM subchannel\n",
+						irq);
+#endif /* CONFIG_DEBUG_CHSC */
+				CIO_CRW_EVENT( 6,
+					       "ssd: sch %x is ADM subchannel\n",
+					       irq);
+
+				if (ioinfo[irq] == INVALID_STORAGE_AREA)
+					/* FIXME: we should do device rec. here... */
+					break;
+
+				ioinfo[irq]->ssd_info.valid = 1;
+				ioinfo[irq]->ssd_info.type = 3;
+				break;
+				
+			default: /* uhm, that looks strange... */
+#ifdef CONFIG_DEBUG_CHSC
+				if (cio_show_msg) 
+					printk( KERN_DEBUG 
+						"Strange subchannel type %d for sch %x\n", 
+						chsc_area_ssd->response_block.
+						response_block_data.ssd_res.st,
+						irq);
+#endif /* CONFIG_DEBUG_CHSC */
+				CIO_CRW_EVENT( 0, 
+					       "Strange subchannel type %d for "
+					       "sch %x\n", 
+					       chsc_area_ssd->response_block.
+					       response_block_data.ssd_res.st,
+					       irq);
+			}
+			spin_unlock(&chsc_lock_ssd);
+			return 0;
+		}
+	} else {
+		spin_unlock(&chsc_lock_ssd);
+		if (ccode == 3)
+			return -ENODEV;
+		return -EBUSY;
+	}
+	return -EIO;
+}
+
+
+static int 
+chsc_get_sch_descriptions( void )
+{
+
+	int irq = 0;
+	int err = 0;
+
+	CIO_TRACE_EVENT( 4, "gsdesc");
+
+	/*
+	 * get information about chpids and link addresses 
+	 * by executing the chsc command 'store subchannel description'
+	 */
+
+	if (init_IRQ_complete) {
+		
+		for (irq=0; irq<=highest_subchannel; irq++) {
+
+			/*
+			 * retrieve information for each sch
+			 */
+			err = chsc_get_sch_desc_irq(irq);
+			if (err) {
+				if (!cio_chsc_err_msg) {
+					printk( KERN_ERR
+						"chsc_get_sch_descriptions:"
+						" Error %d while doing chsc; "
+						"processing "
+						"some machine checks may "
+						"not work\n", 
+						err);
+					cio_chsc_err_msg=1;
+				}
+				return err;
+			}
+		}
+		cio_chsc_desc_avail = 1;
+		return 0;
+	} else {
+		/* Paranoia... */
+		
+		printk( KERN_ERR 
+			"Error: chsc_get_sch_descriptions called before "
+		       "initialization complete\n");
+		return -EINVAL;
+	}
+	
+}
+
+__initcall(chsc_get_sch_descriptions);
+
+void 
+s390_do_chpid_processing( __u8 chpid)
+{
+
+	int irq;
+	int j;
+	int mask;
+	char dbf_txt[15];
+	int ccode;
+	int was_oper;
+	int chp = 0;
+	int mask2;
+	int ret = 0;
+
+	sprintf(dbf_txt, "chpr%x", chpid);
+	CIO_TRACE_EVENT( 2, dbf_txt);
+
+	/* 
+	 * TODO: the chpid may be not the chpid with the link incident,
+	 * but the chpid the report came in through. How to handle???
+	 */
+	clear_bit(chpid, &chpids);
+	if (!test_and_clear_bit(chpid, &chpids_known))
+		return;  /* we didn't know the chpid anyway */
+
+	for (irq=0;irq<=highest_subchannel;irq++) {
+		if (ioinfo[irq] == INVALID_STORAGE_AREA) 
+			continue;  /* we don't know the device anyway */
+		if (ioinfo[irq]->st)
+			continue; /* non-io subchannel */
+		for (j=0; j<8;j++) {
+			if (ioinfo[irq]->schib.pmcw.chpid[j] == chpid) {
+				
+				/*
+				 * Send nops down each path to find out
+				 * which path is gone (ssch will yield cc=3 
+				 * and the path will be switched off in the opm)
+				 */
+				
+				/* 
+				 * Note: irq spinlock is grabbed several times
+				 * in here
+				 */
+				for (chp=0;chp<=7;chp++) {
+					mask2 = 0x80 >> chp;
+					if (mask2 & ioinfo[irq]->opm)
+						ret = s390_send_nop (irq, mask2);
+				}
+				
+				s390irq_spin_lock(irq);
+
+				/*
+				 * FIXME: is this neccessary?
+				 */
+				ccode = stsch(irq, &ioinfo[irq]->schib);
+				if (ccode) {
+#ifdef CONFIG_DEBUG_CRW
+					printk( KERN_WARNING 
+						"do_crw_pending: device on "
+						"sch %x is not operational\n",
+						irq);
+#endif /* CONFIG_DEBUG_CRW */
+					CIO_CRW_EVENT( 2,
+						       "device on sch %x is "
+						       "not operational\n",
+						       irq);
+					ioinfo[irq]->ui.flags.oper = 0;
+					break;
+				}
+
+				ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim &
+					ioinfo[irq]->schib.pmcw.pam &
+					ioinfo[irq]->schib.pmcw.pom;
+
+				if (ioinfo[irq]->opm) {
+					for (chp=0;chp<=7;chp++) {
+						mask2 = 0x80 >> chp;
+						if (ioinfo[irq]->opm & mask2) {
+							if (!test_bit
+							    (ioinfo[irq]->
+							     schib.pmcw.chpid[chp], 
+							     &chpids_logical)) {
+								/* disable using this path */
+								ioinfo[irq]->opm 
+									&= ~mask2;
+							}
+						}
+					}
+				}
+
+				if (!ioinfo[irq]->opm) {
+					/*
+					 * sh*t, our last path has gone...
+					 * Set the device status to not operational
+					 * and eventually notify the device driver
+					 */
+#ifdef CONFIG_DEBUG_CRW
+					printk( KERN_WARNING 
+						"do_crw_pending: Last path gone for "
+						"device %x, sch %x\n",
+						ioinfo[irq]->devno, irq);
+#endif /* CONFIG_DEBUG_CRW */
+					CIO_CRW_EVENT( 2,
+						       "Last path gone for "
+						       "device %x, sch %x\n",
+						       ioinfo[irq]->devno,
+						       irq);
+					
+					was_oper = ioinfo[irq]->ui.flags.oper;
+					
+					ioinfo[irq]->ui.flags.oper = 0;
+					
+					if (was_oper && ioinfo[irq]->ui.flags.ready) {
+						
+						not_oper_handler_func_t nopfunc = 
+							ioinfo[irq]->nopfunc;
+#ifdef CONFIG_PROC_FS						
+						if (cio_proc_devinfo)
+							cio_procfs_device_remove
+								(ioinfo[irq]->devno);
+#endif /* CONFIG_PROC_FS */
+						free_irq(irq, 
+							 ioinfo[irq]->irq_desc.dev_id);
+						if (nopfunc)
+							nopfunc(irq, 
+								DEVSTAT_DEVICE_GONE);
+					}
+					
+				} else if (ioinfo[irq]->ui.flags.ready) {
+					/* 
+					 * Re-do path verification for the chpid in question
+					 * FIXME: is this neccessary?
+					 */
+					mask = 0x80 >> j;
+
+					if (!s390_DevicePathVerification(irq,mask)) {
+#ifdef CONFIG_DEBUG_CRW
+						printk( KERN_DEBUG 
+							"DevicePathVerification "
+							"successful for"
+							" Subchannel %x, "
+							"chpid %x\n",
+							irq, chpid);
+#endif /* CONFIG_DEBUG_CRW */
+						CIO_CRW_EVENT( 2,
+							       "DevicePathVerification "
+							       "successful for"
+							       " Subchannel %x, "
+							       "chpid %x\n",
+							       irq, chpid);
+					}
+				}
+					
+				j=8;
+				s390irq_spin_unlock(irq);
+			}
+			
+		}
+	}	
+}
+
+
+void 
+s390_do_res_acc_processing( __u8 chpid, __u16 fla, int info)
+{
+
+	char dbf_txt[15];
+	int irq = 0;
+	int ccode;
+	__u32 fla_mask = 0xffff;
+	int chp;
+	int mask, mask2;
+	int ret;
+
+	sprintf(dbf_txt, "accp%x", chpid);
+	CIO_TRACE_EVENT( 2, dbf_txt);
+	if (info != CHSC_SEI_ACC_CHPID) {
+		sprintf(dbf_txt, "fla%x", fla);
+		CIO_TRACE_EVENT( 2, dbf_txt);
+	}
+	sprintf(dbf_txt, "info:%d", info);
+	CIO_TRACE_EVENT( 2, dbf_txt);
+	
+	/*
+	 * I/O resources may have become accessible.
+	 * Scan through all subchannels that may be concerned and
+	 * do a validation on those.
+	 * The more information we have (info), the less scanning
+	 * will we have to do.
+	 */
+
+	if (!cio_chsc_desc_avail) 
+		chsc_get_sch_descriptions();
+
+	if (!cio_chsc_desc_avail) {
+		/*
+		 * Something went wrong...
+		 */
+#ifdef CONFIG_DEBUG_CRW
+		printk( KERN_WARNING 
+			"Error: Could not retrieve subchannel descriptions, "
+		       "will not process css machine check...\n");
+#endif /* CONFIG_DEBUG_CRW */
+		CIO_CRW_EVENT( 0,
+			       "Error: Could not retrieve subchannel descriptions, "
+			       "will not process css machine check...\n");
+		return;
+	} 
+
+	if (!test_bit(chpid, &chpids_logical))
+		return; /* no need to do the rest */
+
+	switch (info) {
+	case CHSC_SEI_ACC_CHPID: /*
+				  * worst case, we only know about the chpid
+				  * the devices are attached to
+				  */
+#ifdef CONFIG_DEBUG_CHSC
+		printk( KERN_DEBUG "Looking at chpid %x...\n", chpid);
+#endif /* CONFIG_DEBUG_CHSC */
+		
+		for (irq=0; irq<=__MAX_SUBCHANNELS; irq++) {
+			
+			if((ioinfo[irq] != INVALID_STORAGE_AREA) 
+			   && (!ioinfo[irq]->st)) {
+				
+				/*
+				 * Send nops down each path to find out
+				 * which path is there 
+				 */
+				
+				for (chp=0;chp<=7;chp++) {
+					mask = 0x80 >> chp;
+
+					/*
+					 * check if chpid is in information
+					 * updated by ssd
+					 */
+					if ((ioinfo[irq]->ssd_info.valid) &&
+					    (ioinfo[irq]->ssd_info.chpid[chp]
+					     == chpid))
+						ret = s390_send_nop (irq, mask);
+				}
+
+				ccode = stsch(irq, &ioinfo[irq]->schib);
+				if (!ccode) {
+
+					ioinfo[irq]->opm = 
+						ioinfo[irq]->schib.pmcw.pim &
+						ioinfo[irq]->schib.pmcw.pam &
+						ioinfo[irq]->schib.pmcw.pom;
+
+					if (ioinfo[irq]->opm) {
+						for (chp=0;chp<=7;chp++) {
+							mask = 0x80 >> chp;
+							if (ioinfo[irq]->opm 
+							    & mask) {
+								if (!test_bit
+								    (ioinfo[irq]->
+								     schib.pmcw.chpid[chp], 
+								     &chpids_logical)) {
+									/* disable using this path */
+									ioinfo[irq]->opm 
+										&= ~mask;
+								}
+							}
+						}
+					}
+
+					if ((ioinfo[irq]->ui.flags.ready) 
+					    && (chpid & ioinfo[irq]->opm))
+						s390_DevicePathVerification(irq, chpid);
+
+				} else {
+					ioinfo[irq]->ui.flags.oper = 0;
+				}
+			} else if (ioinfo[irq] == INVALID_STORAGE_AREA) {
+				/*
+				 * We don't know the device yet, but since a path
+				 * may be available now to the device we'll have
+				 * to do recognition again.
+				 * Since we don't have any idea about which chpid
+				 * that beast may be on we'll have to do a stsch
+				 * on all devices, grr...
+				 */
+				int valret = 0;
+				
+				valret = s390_validate_subchannel(irq,0);
+				if (valret == -ENXIO) {
+					/* We're through */
+					return;
+				}
+				if (irq > highest_subchannel)
+					highest_subchannel = irq;
+				if (valret == 0)
+					s390_device_recognition_irq(irq);
+			}
+		}
+
+		break;
+		
+	case CHSC_SEI_ACC_LINKADDR: /*
+				     * better, we know the link determined by
+				     * the link address and the chpid
+				     */
+		fla_mask = 0xff00;
+		/* fallthrough */
+
+	case CHSC_SEI_ACC_FULLLINKADDR: /*
+					 * best case, we know the CU image
+					 * by chpid and full link address
+					 */
+
+#ifdef CONFIG_DEBUG_CHSC
+		printk( KERN_DEBUG "Looking at chpid %x, link addr %x...\n", 
+			chpid, fla);
+#endif /* CONFIG_DEBUG_CHSC */
+		
+		for (irq=0; irq<=__MAX_SUBCHANNELS; irq++) {
+			
+			/*
+			 * Walk through all subchannels and
+			 * look if our chpid and our (masked) link 
+			 * address are in somewhere
+			 * Do a stsch for the found subchannels and
+			 * perform path grouping  
+			 */
+			if ((ioinfo[irq] != INVALID_STORAGE_AREA) 
+			    && (!ioinfo[irq]->st)) {
+				int j;
+				
+				/* Update our ssd_info */
+				if (chsc_get_sch_desc_irq(irq)) 
+					break;
+				
+				for (j=0;j<8;j++) {
+					if ((ioinfo[irq]->ssd_info.chpid[j] == chpid) &&
+					    ((ioinfo[irq]->ssd_info.fla[j]&fla_mask) == fla)) {
 
-	if ( irq_ret == 0 )
-	{
-		s390irq_spin_lock_irqsave( irq, flags);
+						mask2 = 0x80 >> j;
+						ret = s390_send_nop (irq, mask2);
+						
+						ccode = stsch(irq,&ioinfo[irq]->schib);
+						if (!ccode) {
+							ioinfo[irq]->opm = 
+								ioinfo[irq]->schib.pmcw.pim &
+								ioinfo[irq]->schib.pmcw.pam &
+								ioinfo[irq]->schib.pmcw.pom;
+
+							if (ioinfo[irq]->opm) {
+								for (chp=0;chp<=7;chp++) {
+									mask = 0x80 >> chp;
+									if (ioinfo[irq]->opm 
+									    & mask) {
+										if (!test_bit
+										    (ioinfo[irq]->
+										     schib.pmcw.chpid[chp], 
+										     &chpids_logical)) {
+											/* disable using this path */
+											ioinfo[irq]->opm 
+												&= ~mask;
+										}
+									}
+								}
+							}
 
-		if ( init_IRQ_complete )
-		{
-			snid_ccw = kmalloc( sizeof( ccw1_t), GFP_DMA);
+							if (ioinfo[irq]->ui.flags.ready)
+								s390_DevicePathVerification(irq, chpid);
+						}
+						break;
+					}
+				}
+			} else if (ioinfo[irq] == INVALID_STORAGE_AREA) {
+				/* The full program again (see above), grr... */
+				int valret = 0;
+				
+				valret = s390_validate_subchannel(irq,0);
+				if (valret == -ENXIO) {
+					/* We're done */
+					return;
+				}
+				if (irq > highest_subchannel)
+					highest_subchannel = irq;
+				if (valret == 0)
+					s390_device_recognition_irq(irq);
+				
+			}
 		}
-		else	
-		{
-			snid_ccw = alloc_bootmem_low( sizeof( ccw1_t));
-
-		} /* endif */
-
-		snid_ccw->cmd_code = CCW_CMD_SENSE_PGID;
-		snid_ccw->cda      = (__u32)virt_to_phys( pgid );
-		snid_ccw->count    = sizeof( pgid_t);
-		snid_ccw->flags    = CCW_FLAG_SLI;
+		
+		break;
 
-		/*
-		 * We now issue a SensePGID request. In case of BUSY
-		 *  or STATUS PENDING conditions we retry 5 times.
-		 */
-		do
-		{
-			memset( pdevstat, '\0', sizeof( devstat_t) );
+	default: BUG();
+	}
+}
 
-			irq_ret = s390_start_IO( irq,
-			                         snid_ccw,
-			                         0xE2D5C9C4,  // == SNID
-			                         lpm,         // n/a
-			                         DOIO_WAIT_FOR_INTERRUPT
-			                          | DOIO_VALID_LPM
-			                          | DOIO_DONT_CALL_INTHDLR );
+void 
+s390_process_css( void ) 
+{
 
-			if ( irq_ret == 0 )
-			{
-				if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
-				{
-					/*
-					 * If the device doesn't support the
-					 *  Sense Path Group ID command
-					 *  further retries wouldn't help ...
-					 */
-					if ( pdevstat->ii.sense.data[0] & SNS0_CMD_REJECT )
-					{
-						retry   = 0;
-						irq_ret = -EOPNOTSUPP;
-					}
-					else
-					{
-#ifdef CONFIG_DEBUG_IO
-						printk( KERN_WARNING "SNID - device %04X,"
-						        " unit check,"
-						        " flag %04X, "
-						        " retry %d, cnt %02d,"
-						        " sns :"
-						        " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
-						        ioinfo[irq]->schib.pmcw.dev,
-						        pdevstat->flag,
-						        retry,
-						        pdevstat->scnt,
-						        pdevstat->ii.sense.data[0],
-						        pdevstat->ii.sense.data[1],
-						        pdevstat->ii.sense.data[2],
-						        pdevstat->ii.sense.data[3],
-						        pdevstat->ii.sense.data[4],
-						        pdevstat->ii.sense.data[5],
-						        pdevstat->ii.sense.data[6],
-						        pdevstat->ii.sense.data[7]);
-
-#endif
-						if (cio_debug_initialized)
-							debug_sprintf_event(cio_debug_msg_id, 2,
-									    "SNID - device %04X,"
-									    " unit check,"
-									    " flag %04X, "
-									    " retry %d, cnt %02d,"
-									    " sns :"
-									    " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
-									    ioinfo[irq]->schib.pmcw.dev,
-									    pdevstat->flag,
-									    retry,
-									    pdevstat->scnt,
-									    pdevstat->ii.sense.data[0],
-									    pdevstat->ii.sense.data[1],
-									    pdevstat->ii.sense.data[2],
-									    pdevstat->ii.sense.data[3],
-									    pdevstat->ii.sense.data[4],
-									    pdevstat->ii.sense.data[5],
-									    pdevstat->ii.sense.data[6],
-									    pdevstat->ii.sense.data[7]);		    
-						retry--;
-						irq_ret = -EIO;
+	int ccode;
 
-					} /* endif */
-				}
-				else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
-				{
-					/* don't issue warnings during startup unless requested*/
-					if (init_IRQ_complete || cio_notoper_msg) {  
-						printk( KERN_WARNING "SNID - Device %04X "
-							"on Subchannel %04X "
-							"became 'not operational'\n",
-							ioinfo[irq]->schib.pmcw.dev,
-							irq);
-						if (cio_debug_initialized)
-							debug_sprintf_event(cio_debug_msg_id, 2,
-									    "SNID - Device %04X "
-									    "on Subchannel %04X "
-									    "became 'not operational'\n",
-									    ioinfo[irq]->schib.pmcw.dev,
-									    irq);		    
-					}
+	CIO_TRACE_EVENT( 2, "prcss");
 
-					retry = 0;
-					irq_ret = -EIO;
+	spin_lock(&chsc_lock_sei);
 
-				}
-				else
-				{
-					retry = 0; // success ...
-					irq_ret = 0;
+	if (!chsc_area_sei) {
+		if (init_IRQ_complete) 
+			chsc_area_sei = kmalloc(sizeof(chsc_area_t),GFP_KERNEL);
+		else
+			chsc_area_sei = alloc_bootmem(sizeof(chsc_area_t));
+	}
+	
+	if (!chsc_area_sei) {
+		printk( KERN_CRIT 
+			"No memory to store event information...\n");
+		spin_unlock(&chsc_lock_sei);
+		return;
+	}
 
-				} /* endif */
+	/* 
+	 * build the chsc request block for store event information 
+	 * and do the call 
+	 */
+	memset(chsc_area_sei,0,sizeof(chsc_area_t));
+	chsc_area_sei->request_block.command_code1=0x0010;
+	chsc_area_sei->request_block.command_code2=0x000E;
+
+	ccode = chsc(chsc_area_sei);
+
+
+	if (!ccode) {
+		/* for debug purposes, check for problems */
+		if (chsc_area_sei->response_block.response_code == 0x0003) {
+#ifdef CONFIG_DEBUG_CHSC
+			printk( KERN_WARNING 
+				"s390_process_css: error in chsc request block!\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			CIO_CRW_EVENT( 2, 
+				       "s390_process_css: "
+				       "error in chsc request block!\n");
+
+		} else if (chsc_area_sei->response_block.response_code == 0x0005) {
+#ifdef CONFIG_DEBUG_CHSC
+			printk( KERN_WARNING 
+				"s390_process_css: no event information stored\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			CIO_CRW_EVENT( 2, 
+				       "s390_process_css: "
+				       "no event information stored\n");
+
+		} else if (chsc_area_sei->response_block.response_code == 0x0002) {
+#ifdef CONFIG_DEBUG_CHSC
+			printk( KERN_WARNING
+				"s390_process_css: invalid command!\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			CIO_CRW_EVENT( 2,
+				       "s390_process_css: "
+				       "invalid command!\n");
+
+		} else if (chsc_area_sei->response_block.response_code == 0x0001) {
+			/* everything ok */
+#ifdef CONFIG_DEBUG_CHSC
+			printk( KERN_DEBUG 
+				"s390_process_css: "
+				"event information successfully stored\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			CIO_CRW_EVENT( 4, 
+				       "s390_process_css: "
+				       "event information successfully stored\n");
+
+			if (chsc_area_sei->response_block.
+			    response_block_data.sei_res.rs != 4) {
+#ifdef CONFIG_DEBUG_CHSC
+				printk( KERN_ERR
+					"s390_process_css: "
+					"reporting source (%04X) isn't a chpid!"
+					"Aborting processing of machine check...\n",
+					chsc_area_sei->response_block.
+					response_block_data.sei_res.rsid);
+#endif /* CONFIG_DEBUG_CHSC */
+				CIO_CRW_EVENT( 2,
+					       "s390_process_css: "
+					       "reporting source (%04X) isn't a chpid!"
+					       "Aborting processing of machine check...\n",
+					       chsc_area_sei->response_block.
+					       response_block_data.sei_res.rsid);
+				return;
 			}
-			else if ( irq_ret != -ENODEV ) // -EIO, or -EBUSY
-			{
+			
+			/* which kind of information was stored? */
+			switch (chsc_area_sei->response_block.
+				response_block_data.sei_res.cc) {
+			case 1: /* link incident*/
+#ifdef CONFIG_DEBUG_CHSC
+				printk( KERN_DEBUG 
+					"s390_process_css: "
+					"channel subsystem reports link incident,"
+					" source is chpid %x\n", 
+					chsc_area_sei->response_block.
+					response_block_data.sei_res.rsid);
+#endif /* CONFIG_DEBUG_CHSC */
+				CIO_CRW_EVENT( 4,
+					       "s390_process_css: "
+					       "channel subsystem reports "
+					       "link incident, "
+					       "source is chpid %x\n", 
+					       chsc_area_sei->response_block.
+					       response_block_data.sei_res.rsid);
+
+				s390_do_chpid_processing(chsc_area_sei->response_block.
+							 response_block_data.sei_res.rsid);
+							    
+				break;
 
-				if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
-				{
-#ifdef CONFIG_DEBUG_IO
-					printk( KERN_INFO "SNID - Device %04X "
-					        "on Subchannel %04X "
-					        "reports pending status, "
-					        "retry : %d\n",
-					        ioinfo[irq]->schib.pmcw.dev,
-					        irq,
-					        retry);
-#endif
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_msg_id, 2,
-								    "SNID - Device %04X "
-								    "on Subchannel %04X "
-								    "reports pending status, "
-								    "retry : %d\n",
-								    ioinfo[irq]->schib.pmcw.dev,
-								    irq,
-								    retry);		    
-				} /* endif */
-
-
-				printk( KERN_WARNING "SNID - device %04X,"
-				        " start_io() reports rc : %d, retrying ...\n",
-				        ioinfo[irq]->schib.pmcw.dev,
-				        irq_ret);
-				if (cio_debug_initialized)
-					debug_sprintf_event(cio_debug_msg_id, 2, 
-							    "SNID - device %04X,"
-							    " start_io() reports rc : %d, retrying ...\n",
-							    ioinfo[irq]->schib.pmcw.dev,
-							    irq_ret);
-				retry--;
-				irq_ret = -EIO;
-			}
-			else	// -ENODEV ...
-			{
-				retry = 0;
-				irq_ret = -ENODEV;
+			case 2: /* i/o resource accessibiliy */
+#ifdef CONFIG_DEBUG_CHSC
+				printk( KERN_DEBUG 
+					"s390_process_css: channel subsystem "
+					"reports some I/O devices "
+					"may have become accessable\n");
+#endif /* CONFIG_DEBUG_CHSC */
+				CIO_CRW_EVENT( 4,
+					       "s390_process_css: "
+					       "channel subsystem reports "
+					       "some I/O devices "
+					       "may have become accessable\n");
+#ifdef CONFIG_DEBUG_CHSC
+				printk( KERN_DEBUG 
+					"Data received after sei: \n");
+				printk( KERN_DEBUG 
+					"Validity flags: %x\n", 
+				       chsc_area_sei->response_block.
+					response_block_data.sei_res.vf);
+#endif /* CONFIG_DEBUG_CHSC */
+				if ((chsc_area_sei->response_block.
+				    response_block_data.sei_res.vf&0x80)
+				    == 0) {
+#ifdef CONFIG_DEBUG_CHSC
+					printk( KERN_DEBUG "chpid: %x\n",
+						chsc_area_sei->response_block.
+						response_block_data.sei_res.rsid);
+#endif /* CONFIG_DEBUG_CHSC */
+					s390_do_res_acc_processing
+						(chsc_area_sei->response_block.
+						 response_block_data.sei_res.rsid,
+						 0,
+						 CHSC_SEI_ACC_CHPID);
+				} else if ((chsc_area_sei->response_block.
+					   response_block_data.sei_res.vf&0xc0)
+					   == 0x80) {
+#ifdef CONFIG_DEBUG_CHSC
+					printk( KERN_DEBUG 
+						"chpid: %x  link addr: %x\n",
+						chsc_area_sei->response_block.
+						response_block_data.sei_res.rsid,
+						chsc_area_sei->response_block.
+						response_block_data.sei_res.fla);
+#endif /* CONFIG_DEBUG_CHSC */
+					s390_do_res_acc_processing
+						(chsc_area_sei->response_block.
+						 response_block_data.sei_res.rsid, 
+						 chsc_area_sei->response_block.
+						 response_block_data.sei_res.fla,
+						 CHSC_SEI_ACC_LINKADDR);
+				} else if ((chsc_area_sei->response_block.
+					    response_block_data.sei_res.vf & 0xc0)
+					   == 0xc0) {
+#ifdef CONFIG_DEBUG_CHSC
+					printk( KERN_DEBUG 
+						"chpid: %x  "
+						"full link addr: %x\n",
+						chsc_area_sei->response_block.
+						response_block_data.sei_res.rsid,
+						chsc_area_sei->response_block.
+						response_block_data.sei_res.fla);
+#endif /* CONFIG_DEBUG_CHSC */
+					s390_do_res_acc_processing
+						(chsc_area_sei->response_block.
+						 response_block_data.sei_res.rsid, 
+						 chsc_area_sei->response_block.
+						 response_block_data.sei_res.fla,
+						 CHSC_SEI_ACC_FULLLINKADDR);
+				}
+#ifdef CONFIG_DEBUG_CHSC
+				printk( KERN_DEBUG "\n");
+#endif /* CONFIG_DEBUG_CHSC */
 
-			} /* endif */
+				break;
 
-		} while ( retry > 0 );
+			default: /* other stuff */
+#ifdef CONFIG_DEBUG_CHSC
+				printk( KERN_DEBUG 
+					"s390_process_css: event %d\n",
+					chsc_area_sei->response_block.
+					response_block_data.sei_res.cc);
+#endif /* CONFIG_DEBUG_CHSC */
+				CIO_CRW_EVENT( 4, 
+					       "s390_process_css: event %d\n",
+					       chsc_area_sei->response_block.
+					       response_block_data.sei_res.cc);
 
+				break;
 
-		if ( init_IRQ_complete )
-		{
-			kfree( snid_ccw );
+			}
 		}
-		else	
-		{
-			free_bootmem( (unsigned long)snid_ccw, sizeof(ccw1_t) );
-
-		} /* endif */
-
-		s390irq_spin_unlock_irqrestore( irq, flags);
-
-		/*
-		 * If we installed the irq action handler we have to
-		 *  release it too.
-		 */
-		if ( inlreq )
-			free_irq( irq, pdevstat);
-
-	} /* endif */
-
-   return( irq_ret );
+	}
+	spin_unlock(&chsc_lock_sei);
 }
+#endif
 
 /*
  * s390_do_crw_pending
@@ -6328,298 +7613,116 @@
  *
  * Note : we currently process CRWs for subchannel source only
  */
-void s390_do_crw_pending( crwe_t *pcrwe )
+void
+s390_do_crw_pending (crwe_t * pcrwe)
 {
 	int irq;
 	int chpid;
-	int dev_oper = 0;
-	int dev_no   = -1;	
-	int lock     = 0;
-
+	
 #ifdef CONFIG_DEBUG_CRW
-	printk( KERN_DEBUG "do_crw_pending : starting ...\n");
+	printk (KERN_DEBUG "do_crw_pending : starting ...\n");
 #endif
-	if (cio_debug_initialized) 
-		debug_sprintf_event(cio_debug_crw_id, 2, 
-				    "do_crw_pending: starting\n");
-	while ( pcrwe != NULL )
-	{
-		int is_owned = 0;
-
-		switch ( pcrwe->crw.rsc ) {	
-		case CRW_RSC_SCH :
+	CIO_CRW_EVENT( 2, "do_crw_pending: starting\n");
+	while (pcrwe != NULL) {
 
+		switch (pcrwe->crw.rsc) {
+		case CRW_RSC_SCH:
+			
 			irq = pcrwe->crw.rsid;
-
-#ifdef CONFIG_DEBUG_CRW
-			printk( KERN_NOTICE"do_crw_pending : source is "
-			        "subchannel %04X\n", irq);
-#endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_crw_id, 2,
-						    "source is subchannel %04X\n", irq);
-			/*
-			 * If the device isn't known yet
-			 *   we can't lock it ...
-			 */
-			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-			{
-				s390irq_spin_lock( irq );
-				lock = 1;
-
-				dev_oper = ioinfo[irq]->ui.flags.oper;
-
-				if ( ioinfo[irq]->ui.flags.dval )
-					dev_no = ioinfo[irq]->devno;
-
-				is_owned = ioinfo[irq]->ui.flags.ready;
-
-			} /* endif */
-
-#ifdef CONFIG_DEBUG_CRW
-			printk( KERN_DEBUG "do_crw_pending : subchannel validation - start ...\n");
-#endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_crw_id, 4,
-						    "subchannel validation - start\n");
-			s390_validate_subchannel( irq, is_owned );
-
-			if ( irq > highest_subchannel )
-				highest_subchannel = irq;
-
-#ifdef CONFIG_DEBUG_CRW
-			printk( KERN_DEBUG "do_crw_pending : subchannel validation - done\n");
-#endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_crw_id, 4,
-						    "subchannel validation - done\n");
-			/*
-			 * After the validate processing
-			 *   the ioinfo control block
-			 *   should be allocated ...
-			 */
-			if ( lock )
-			{
-				s390irq_spin_unlock( irq );
-
-			} /* endif */
-
-
-			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-			{
-#ifdef CONFIG_DEBUG_CRW
-				printk( KERN_DEBUG "do_crw_pending : ioinfo at "
-#ifdef CONFIG_ARCH_S390X
-					"%08lX\n",
-					(unsigned long)ioinfo[irq]);
-#else /* CONFIG_ARCH_S390X */
-					"%08X\n",
-				        (unsigned)ioinfo[irq]);
-#endif /* CONFIG_ARCH_S390X */
-#endif
-				if (cio_debug_initialized)
-					debug_sprintf_event(cio_debug_crw_id, 4,
-							    "ioinfo at "
-#ifdef CONFIG_ARCH_S390X
-							    "%08lX\n",
-							    (unsigned long)ioinfo[irq]);
-#else /* CONFIG_ARCH_S390X */
-				                            "%08X\n",
-							    (unsigned)ioinfo[irq]);
-#endif /* CONFIG_ARCH_S390X */
-			} /* endif */
-
-
-			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-			{
-				if ( ioinfo[irq]->ui.flags.oper == 0 )
-				{
-					 not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
-#ifdef CONFIG_PROC_FS					 
-					 /* remove procfs entry */
-					 if (cio_proc_devinfo)
-						 cio_procfs_device_remove(dev_no);
-#endif
-					/*
-					 * If the device has gone
-					 *  call not oper handler        	
-					 */       	
-					 if (( dev_oper == 1 )
-					     && ( nopfunc != NULL))
-					{
-						
-						free_irq( irq,ioinfo[irq]->irq_desc.dev_id );
-						nopfunc( irq,DEVSTAT_DEVICE_GONE );			
-
-					} /* endif */
-				}
-				else
-				{
-#ifdef CONFIG_DEBUG_CRW
-					printk( KERN_DEBUG "do_crw_pending : device "
-					        "recognition - start ...\n");
-#endif
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_crw_id, 4,
-								    "device recognition - start\n");
-					s390_device_recognition_irq( irq );
-
+			
 #ifdef CONFIG_DEBUG_CRW
-					printk( KERN_DEBUG "do_crw_pending : device "
-					        "recognition - done\n");
-#endif
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_crw_id, 4,
-								    "device recognition - done\n");
-					/*
-					 * the device became operational
-					 */
-					if ( dev_oper == 0 )
-					{
-						devreg_t *pdevreg;
-
-						pdevreg = s390_search_devreg( ioinfo[irq] );
-
-						if ( pdevreg != NULL )
-						{
-							if ( pdevreg->oper_func != NULL )
-								pdevreg->oper_func( irq, pdevreg );
-
-						} /* endif */
-#ifdef CONFIG_PROC_FS
-						/* add new procfs entry */
-						if (cio_proc_devinfo) 
-							if (highest_subchannel < MAX_CIO_PROCFS_ENTRIES) {
-								cio_procfs_device_create(ioinfo[irq]->devno);
-							}
-#endif
-					}
-					/*
-					 * ... it is and was operational, but
-					 *      the devno may have changed
-					 */
-					else if ((ioinfo[irq]->devno != dev_no) && ( ioinfo[irq]->nopfunc != NULL ))   					
-					{
-#ifdef CONFIG_PROC_FS
-						int devno_old = ioinfo[irq]->devno;
-#endif
-						ioinfo[irq]->nopfunc( irq,
-						                      DEVSTAT_REVALIDATE );				
-#ifdef CONFIG_PROC_FS
-						/* remove old entry, add new */
-						if (cio_proc_devinfo) {
-							cio_procfs_device_remove(devno_old);
-							cio_procfs_device_create(ioinfo[irq]->devno);
-						}
-#endif
-					} /* endif */
-
-				} /* endif */
-#ifdef CONFIG_PROC_FS
-				/* get rid of dead procfs entries */
-				if (cio_proc_devinfo) 
-					cio_procfs_device_purge();
+			printk (KERN_NOTICE "do_crw_pending : source is "
+				"subchannel %04X\n", irq);
 #endif
-			} /* endif */
+			CIO_CRW_EVENT(2, "source is subchannel %04X\n",
+				      irq);
+			s390_process_subchannel_source (irq);
 
 			break;
 
-		case CRW_RSC_MONITOR :
+		case CRW_RSC_MONITOR:
 
 #ifdef CONFIG_DEBUG_CRW
-			printk( KERN_NOTICE "do_crw_pending : source is "
-			        "monitoring facility\n");
+			printk (KERN_NOTICE "do_crw_pending : source is "
+				"monitoring facility\n");
 #endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_crw_id, 2,
-						    "source is monitoring facility\n");
+			CIO_CRW_EVENT(2, "source is monitoring facility\n");
 			break;
 
-		case CRW_RSC_CPATH :   	
+		case CRW_RSC_CPATH:
 
 			chpid = pcrwe->crw.rsid;
 
 #ifdef CONFIG_DEBUG_CRW
-			printk( KERN_NOTICE "do_crw_pending : source is "
-			        "channel path %02X\n", chpid);
+			printk (KERN_NOTICE "do_crw_pending : source is "
+				"channel path %02X\n", chpid);
 #endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_crw_id, 2,
-						    "source is channel path %02X\n");
+			CIO_CRW_EVENT(2, "source is channel path %02X\n");
 			break;
 
-		case CRW_RSC_CONFIG : 	
+		case CRW_RSC_CONFIG:
 
 #ifdef CONFIG_DEBUG_CRW
-			printk( KERN_NOTICE "do_crw_pending : source is "
-			        "configuration-alert facility\n");
+			printk (KERN_NOTICE "do_crw_pending : source is "
+				"configuration-alert facility\n");
 #endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_crw_id, 2,
-						    "source is configuration-alert facility\n");
+			CIO_CRW_EVENT(2, "source is configuration-alert facility\n");
 			break;
 
-		case CRW_RSC_CSS :
+		case CRW_RSC_CSS:
 
 #ifdef CONFIG_DEBUG_CRW
-			printk( KERN_NOTICE "do_crw_pending : source is "
-			        "channel subsystem\n");
+			printk (KERN_NOTICE "do_crw_pending : source is "
+				"channel subsystem\n");
+#endif
+			CIO_CRW_EVENT(2, "source is channel subsystem\n");
+#ifdef CONFIG_CHSC
+			s390_process_css();
 #endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_crw_id, 2,
-						    "source is channel subsystem\n");
 			break;
 
-		default :
+		default:
 
 #ifdef CONFIG_DEBUG_CRW
-			printk( KERN_NOTICE "do_crw_pending : unknown source\n");
+			printk (KERN_NOTICE
+				"do_crw_pending : unknown source\n");
 #endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_crw_id, 2,
-						    "unknown source\n");
-			break;		
+			CIO_CRW_EVENT( 2, "unknown source\n");
+			break;
 
-		} /* endswitch */
+		}
 
 		pcrwe = pcrwe->crwe_next;
 
-	} /* endwhile */
+	}
 
 #ifdef CONFIG_DEBUG_CRW
-	printk( KERN_DEBUG "do_crw_pending : done\n");
+	printk (KERN_DEBUG "do_crw_pending : done\n");
 #endif
-	if (cio_debug_initialized)
-		debug_sprintf_event(cio_debug_crw_id, 2,
-				    "do_crw_pending: done\n");
-   return;
+	CIO_CRW_EVENT(2, "do_crw_pending: done\n");
+	return;
 }
 
-
 /* added by Holger Smolinski for reipl support in reipl.S */
 extern void do_reipl (int);
 void
-reipl ( int sch )
+reipl (int sch)
 {
 	int i;
 	s390_dev_info_t dev_info;
 
-	for ( i = 0; i <= highest_subchannel; i ++ ) 
-	{
-		if (    get_dev_info_by_irq( i, &dev_info ) == 0
-                    && (dev_info.status & DEVSTAT_DEVICE_OWNED) )
-		{
-			free_irq ( i, ioinfo[i]->irq_desc.dev_id );
+	for (i = 0; i <= highest_subchannel; i++) {
+		if (get_dev_info_by_irq (i, &dev_info) == 0
+		    && (dev_info.status & DEVSTAT_DEVICE_OWNED)) {
+			free_irq (i, ioinfo[i]->irq_desc.dev_id);
 		}
 	}
-
 	if (MACHINE_IS_VM)
-		cpcmd("IPL", NULL, 0);
+		cpcmd ("IPL", NULL, 0);
 	else
-		do_reipl( 0x10000 | sch );
+		do_reipl (0x10000 | sch);
 }
 
-
 /*
  * Function: cio_debug_init
  * Initializes three debug logs (under /proc/s390dbf) for common I/O:
@@ -6628,40 +7731,29 @@
  * - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on
  * debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW
  */
-int cio_debug_init( void )
+int
+cio_debug_init (void)
 {
 	int ret = 0;
 
-	cio_debug_msg_id = debug_register("cio_msg",4,4,16*sizeof(long));
+	cio_debug_msg_id = debug_register ("cio_msg", 4, 4, 16 * sizeof (long));
 	if (cio_debug_msg_id != NULL) {
-		debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
-#ifdef CONFIG_DEBUG_IO
-		debug_set_level(cio_debug_msg_id, 6);
-#else /* CONFIG_DEBUG_IO */
-		debug_set_level(cio_debug_msg_id, 2);
-#endif /* CONFIG_DEBUG_IO */
+		debug_register_view (cio_debug_msg_id, &debug_sprintf_view);
+		debug_set_level (cio_debug_msg_id, 6);
 	} else {
 		ret = -1;
 	}
-	cio_debug_trace_id = debug_register("cio_trace",4,4,8);
+	cio_debug_trace_id = debug_register ("cio_trace", 4, 4, 8);
 	if (cio_debug_trace_id != NULL) {
-		debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
-#ifdef CONFIG_DEBUG_IO
-		debug_set_level(cio_debug_trace_id, 6);
-#else /* CONFIG_DEBUG_IO */
-		debug_set_level(cio_debug_trace_id, 2);
-#endif /* CONFIG_DEBUG_IO */
+		debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view);
+		debug_set_level (cio_debug_trace_id, 6);
 	} else {
 		ret = -1;
 	}
-	cio_debug_crw_id = debug_register("cio_crw",2,4,16*sizeof(long));
+	cio_debug_crw_id = debug_register ("cio_crw", 2, 4, 16 * sizeof (long));
 	if (cio_debug_crw_id != NULL) {
-		debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
-#ifdef CONFIG_DEBUG_CRW
-		debug_set_level(cio_debug_crw_id, 6);
-#else /* CONFIG_DEBUG_CRW */
-		debug_set_level(cio_debug_crw_id, 2);
-#endif /* CONFIG_DEBUG_CRW */
+		debug_register_view (cio_debug_crw_id, &debug_sprintf_view);
+		debug_set_level (cio_debug_crw_id, 6);
 	} else {
 		ret = -1;
 	}
@@ -6671,157 +7763,325 @@
 	return 0;
 }
 
-__initcall(cio_debug_init);
+__initcall (cio_debug_init);
 
 #ifdef CONFIG_PROC_FS
+#ifdef CONFIG_CHSC
+/*
+ * Function: cio_parse_chpids_proc_parameters
+ * parse the stuff piped to /proc/chpids
+ */
+void 
+cio_parse_chpids_proc_parameters(char* buf)
+{
+	int i;
+	int cp;
+	int ret;
+
+	if (strstr(buf, "on ")) {
+		for (i=0; i<3; i++) {
+			buf++;
+		}
+		cp = blacklist_strtoul(buf, &buf);
+
+		chsc_get_sch_descriptions();
+		if (!cio_chsc_desc_avail) {
+			printk(KERN_ERR "Could not get chpid status, "
+			       "vary on/off not available\n");
+			return;
+		}
+ 
+		if (!test_bit(cp, &chpids)) {
+			ret = s390_vary_chpid(cp, 1);
+			if (ret == -EINVAL) {
+#ifdef CONFIG_DEBUG_CHSC
+				printk(KERN_ERR "/proc/chpids: "
+				       "Invalid chpid specified\n");
+#else /* CONFIG_DEBUG_CHSC */
+				printk(KERN_DEBUG "/proc/chpids: "
+				       "Invalid chpid specified\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			} else if (ret == 0) {
+				printk(KERN_INFO "/proc/chpids: "
+				       "Varied chpid %x logically online\n",
+				       cp);
+			}
+		} else {
+			printk(KERN_ERR "/proc/chpids: chpid %x is "
+			       "already online\n",
+			       cp);
+		}
+	} else if (strstr(buf, "off ")) {
+		for (i=0; i<4; i++) {
+			buf++;
+		}
+		cp = blacklist_strtoul(buf, &buf);
+
+		chsc_get_sch_descriptions();
+		if (!cio_chsc_desc_avail) {
+			printk(KERN_ERR "Could not get chpid status, "
+			       "vary on/off not available\n");
+			return;
+		}
+		
+		if (test_bit(cp, &chpids)) {
+			ret = s390_vary_chpid(cp, 0);
+			if (ret == -EINVAL) {
+#ifdef CONFIG_DEBUG_CHSC
+				printk(KERN_ERR "/proc/chpids: "
+				       "Invalid chpid specified\n");
+#else /* CONFIG_DEBUG_CHSC */
+				printk(KERN_DEBUG "/proc/chpids: "
+				       "Invalid chpid specified\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			} else if (ret == 0) {
+				printk(KERN_INFO "/proc/chpids: "
+				       "Varied chpid %x logically offline\n",
+				       cp);
+			}
+		} else { 
+			printk(KERN_ERR "/proc/chpids: "
+			       "chpid %x is already offline\n",
+			       cp);
+		}
+	} else {
+		printk(KERN_ERR "/proc/chpids: Parse error; "
+		       "try using '{on,off} <chpid>'\n");
+	}
+}
+
+
+/*
+ * Function: s390_vary_chpid
+ * Varies the specified chpid online or offline
+ */
+int 
+s390_vary_chpid( __u8 chpid, int on) 
+{
+	char dbf_text[15];
+	int irq;
+
+	if ((chpid <=0) || (chpid >= NR_CHPIDS))
+		return -EINVAL;
+
+	sprintf(dbf_text, on?"varyon%x":"varyoff%x", chpid);
+	CIO_TRACE_EVENT( 2, dbf_text);
+
+	if (!test_bit(chpid, &chpids_known)) {
+		printk(KERN_ERR "Can't vary unknown chpid %02X\n", chpid);
+		return -EINVAL;
+	}
+
+	if (on && test_bit(chpid, &chpids_logical)) {
+		printk(KERN_ERR "chpid %02X already logically online\n", 
+		       chpid);
+		return -EINVAL;
+	}
+
+	if (!on && !test_bit(chpid, &chpids_logical)) {
+		printk(KERN_ERR "chpid %02X already logically offline\n", 
+		       chpid);
+		return -EINVAL;
+	}
+
+	if (on) {
+		set_bit(chpid, &chpids_logical);
+		set_bit(chpid, &chpids);
+
+	} else {
+		clear_bit(chpid, &chpids_logical);
+		clear_bit(chpid, &chpids);
+	}
+
+	/*
+	 * Redo PathVerification on the devices the chpid connects to 
+	 */
+	
+	for (irq=0;irq<=highest_subchannel;irq++) {
+
+		/* 
+		 * We don't need to adjust the opm, as this will be done in
+		 * DevicePathVerification...
+		 */
+
+		if (ioinfo[irq] == INVALID_STORAGE_AREA)
+			continue;
+
+		if (ioinfo[irq]->st)
+			continue;
+
+		if (ioinfo[irq]->ssd_info.valid) {
+			if ((ioinfo[irq]->ssd_info.chpid[0] == chpid) ||
+			    (ioinfo[irq]->ssd_info.chpid[1] == chpid) ||
+			    (ioinfo[irq]->ssd_info.chpid[2] == chpid) ||
+			    (ioinfo[irq]->ssd_info.chpid[3] == chpid) ||
+			    (ioinfo[irq]->ssd_info.chpid[4] == chpid) ||
+			    (ioinfo[irq]->ssd_info.chpid[5] == chpid) ||
+			    (ioinfo[irq]->ssd_info.chpid[6] == chpid) ||
+			    (ioinfo[irq]->ssd_info.chpid[7] == chpid)) {
+#ifdef CONFIG_DEBUG_CHSC
+				printk(KERN_DEBUG "Calling "
+				       "DevicePathVerification for irq %d\n", 
+				       irq);
+#endif /* CONFIG_DEBUG_CHSC */
+				s390_DevicePathVerification(irq, 0);
+			}
+		}
+	}
+
+	return 0;
+}
+#endif /* CONFIG_CHSC */
+
 /* 
  * Display info on subchannels in /proc/subchannels. 
  * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01.      
  */
 
 typedef struct {
-     char *data;
-     int len;
+	char *data;
+	int len;
 } tempinfo_t;
 
 #define MIN(a,b) ((a)<(b)?(a):(b))
 
 static struct proc_dir_entry *chan_subch_entry;
 
-static int chan_subch_open( struct inode *inode, struct file *file)
+static int
+chan_subch_open (struct inode *inode, struct file *file)
 {
-     int rc = 0;
-     int size = 1;
-     int len = 0;
-     int i = 0;
-     int j = 0;
-     tempinfo_t *info;
-     
-     info = (tempinfo_t *) vmalloc( sizeof (tempinfo_t));
-     if (info == NULL) {
-	  printk( KERN_WARNING "No memory available for data\n");
-	  return -ENOMEM;
-     } else {
-	  file->private_data = ( void * ) info;
-     }
+	int rc = 0;
+	int size = 1;
+	int len = 0;
+	int i = 0;
+	int j = 0;
+	tempinfo_t *info;
 
-     size += (highest_subchannel+1) * 128;
-     info->data = (char *) vmalloc( size );
-     
-     if (size && info->data == NULL) {
+	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
+	if (info == NULL) {
 		printk (KERN_WARNING "No memory available for data\n");
-		vfree (info);
 		return -ENOMEM;
+	} else {
+		file->private_data = (void *) info;
 	}
-     
-     len += sprintf( info->data+len, 
-		     "Device sch.  Dev Type/Model CU  in use  PIM PAM POM LPUM CHPIDs\n");
-     len += sprintf( info->data+len, 
-		     "--------------------------------------------------------------------------\n");
-
-     for ( i=0; i <= highest_subchannel; i++) {
-	  if ( !((ioinfo[i] == NULL) || (ioinfo[i] == INVALID_STORAGE_AREA) || !(ioinfo[i]->ui.flags.oper)) ) {
-	       len += sprintf( info->data+len, 
-			       "%04X   %04X  ", 
-			       ioinfo[i]->schib.pmcw.dev, 
-			       i );
-	       if ( ioinfo[i]->senseid.dev_type != 0 ) {
-		    len += sprintf( info->data+len, 
-				    "%04X/%02X   %04X/%02X", 
-				    ioinfo[i]->senseid.dev_type,
-				    ioinfo[i]->senseid.dev_model, 
-				    ioinfo[i]->senseid.cu_type,
-				    ioinfo[i]->senseid.cu_model );
-	       } else {
-		    len += sprintf( info->data+len, 
-				    "          %04X/%02X", 
-				    ioinfo[i]->senseid.cu_type, 
-				    ioinfo[i]->senseid.cu_model );
-	       }
-	       if (ioinfo[i]->ui.flags.ready) {
-		    len += sprintf( info->data+len, "  yes " );
-	       } else {
-		    len += sprintf( info->data+len, "      " );
-	       }
-	       len += sprintf( info->data+len,
-			       "    %02X  %02X  %02X  %02X   ",
-			       ioinfo[i]->schib.pmcw.pim,
-			       ioinfo[i]->schib.pmcw.pam,
-			       ioinfo[i]->schib.pmcw.pom,
-			       ioinfo[i]->schib.pmcw.lpum );
-	       for ( j=0; j < 8; j++ ) {
-		    len += sprintf( info->data+len,
-				    "%02X",
-				    ioinfo[i]->schib.pmcw.chpid[j] );
-		    if (j==3) {
-			 len += sprintf( info->data+len, " " );
-		    }
-	       }
-	       len += sprintf( info->data+len, "\n" );
-	  }
-     }
-     info->len = len;
 
-     return rc;
-}
+	size += (highest_subchannel + 1) * 128;
+	info->data = (char *) vmalloc (size);
 
-static int chan_subch_close( struct inode *inode, struct file *file)
-{
-     int rc = 0;
-     tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+	if (size && info->data == NULL) {
+		printk (KERN_WARNING "No memory available for data\n");
+		vfree (info);
+		return -ENOMEM;
+	}
 
-     if (p_info) {
-	  if (p_info->data)
-	       vfree( p_info->data );
-	  vfree( p_info );
-     }
-     
-     return rc;
+	len += sprintf (info->data + len,
+			"Device sch.  Dev Type/Model CU  in use  PIM PAM POM CHPIDs\n");
+	len += sprintf (info->data + len,
+			"---------------------------------------------------------------------\n");
+
+	for (i = 0; i <= highest_subchannel; i++) {
+		if (!((ioinfo[i] == NULL) || (ioinfo[i] == INVALID_STORAGE_AREA)
+		      || (ioinfo[i]->st )|| !(ioinfo[i]->ui.flags.oper))) {
+			len +=
+			    sprintf (info->data + len, "%04X   %04X  ",
+				     ioinfo[i]->schib.pmcw.dev, i);
+			if (ioinfo[i]->senseid.dev_type != 0) {
+				len += sprintf (info->data + len,
+						"%04X/%02X   %04X/%02X",
+						ioinfo[i]->senseid.dev_type,
+						ioinfo[i]->senseid.dev_model,
+						ioinfo[i]->senseid.cu_type,
+						ioinfo[i]->senseid.cu_model);
+			} else {
+				len += sprintf (info->data + len,
+						"          %04X/%02X",
+						ioinfo[i]->senseid.cu_type,
+						ioinfo[i]->senseid.cu_model);
+			}
+			if (ioinfo[i]->ui.flags.ready) {
+				len += sprintf (info->data + len, "  yes ");
+			} else {
+				len += sprintf (info->data + len, "      ");
+			}
+			len += sprintf (info->data + len,
+					"    %02X  %02X  %02X  ",
+					ioinfo[i]->schib.pmcw.pim,
+					ioinfo[i]->schib.pmcw.pam,
+					ioinfo[i]->schib.pmcw.pom);
+			for (j = 0; j < 8; j++) {
+				len += sprintf (info->data + len,
+						"%02X",
+						ioinfo[i]->schib.pmcw.chpid[j]);
+				if (j == 3) {
+					len += sprintf (info->data + len, " ");
+				}
+			}
+			len += sprintf (info->data + len, "\n");
+		}
+	}
+	info->len = len;
+
+	return rc;
 }
 
-static ssize_t chan_subch_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+static int
+chan_subch_close (struct inode *inode, struct file *file)
 {
-     loff_t len;
-     tempinfo_t *p_info = (tempinfo_t *) file->private_data;
-     
-     if ( *offset>=p_info->len) {
-	  return 0;
-     } else {
-	  len = MIN(user_len, (p_info->len - *offset));
-	  if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
-	       return -EFAULT; 
-	  (* offset) += len;
-	  return len;
-     }
+	int rc = 0;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+	if (p_info) {
+		if (p_info->data)
+			vfree (p_info->data);
+		vfree (p_info);
+	}
+
+	return rc;
 }
 
-static struct file_operations chan_subch_file_ops =
+static ssize_t
+chan_subch_read (struct file *file, char *user_buf, size_t user_len,
+		 loff_t * offset)
 {
-     read:chan_subch_read,
-     open:chan_subch_open,
-     release:chan_subch_close,
+	loff_t len;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+	if (*offset >= p_info->len) {
+		return 0;
+	} else {
+		len = MIN (user_len, (p_info->len - *offset));
+		if (copy_to_user (user_buf, &(p_info->data[*offset]), len))
+			return -EFAULT;
+		(*offset) += len;
+		return len;
+	}
+}
+
+static struct file_operations chan_subch_file_ops = {
+	read:chan_subch_read, open:chan_subch_open, release:chan_subch_close,
 };
 
-static int chan_proc_init( void )
+static int
+chan_proc_init (void)
 {
-     chan_subch_entry = create_proc_entry( "subchannels", S_IFREG|S_IRUGO, &proc_root);
-     chan_subch_entry->proc_fops = &chan_subch_file_ops;
+	chan_subch_entry =
+	    create_proc_entry ("subchannels", S_IFREG | S_IRUGO, &proc_root);
+	chan_subch_entry->proc_fops = &chan_subch_file_ops;
 
-     return 1;
+	return 1;
 }
 
-__initcall(chan_proc_init);
+__initcall (chan_proc_init);
 
-void chan_proc_cleanup( void )
+void
+chan_proc_cleanup (void)
 {
-     remove_proc_entry( "subchannels", &proc_root);
+	remove_proc_entry ("subchannels", &proc_root);
 }
 
 /* 
  * Display device specific information under /proc/deviceinfo/<devno>
- */
-
-static struct proc_dir_entry *cio_procfs_deviceinfo_root = NULL;
+ */ static struct proc_dir_entry *cio_procfs_deviceinfo_root = NULL;
 
 /* 
  * cio_procfs_device_list holds all devno-specific procfs directories
@@ -6835,7 +8095,7 @@
 	struct proc_dir_entry *cio_chpid_entry;
 } cio_procfs_entry_t;
 
-typedef struct _cio_procfs_device{
+typedef struct _cio_procfs_device {
 	struct _cio_procfs_device *next;
 	cio_procfs_entry_t *entry;
 } cio_procfs_device_t;
@@ -6846,38 +8106,41 @@
  * File operations
  */
 
-static int cio_device_entry_close( struct inode *inode, struct file *file)
+static int
+cio_device_entry_close (struct inode *inode, struct file *file)
 {
-     int rc = 0;
-     tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+	int rc = 0;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
 
-     if (p_info) {
-	  if (p_info->data)
-	       vfree( p_info->data );
-	  vfree( p_info );
-     }
-     
-     return rc;
+	if (p_info) {
+		if (p_info->data)
+			vfree (p_info->data);
+		vfree (p_info);
+	}
+
+	return rc;
 }
 
-static ssize_t cio_device_entry_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+static ssize_t
+cio_device_entry_read (struct file *file, char *user_buf, size_t user_len,
+		       loff_t * offset)
 {
-     loff_t len;
-     tempinfo_t *p_info = (tempinfo_t *) file->private_data;
-     
-     if ( *offset>=p_info->len) {
-	  return 0;
-     } else {
-	  len = MIN(user_len, (p_info->len - *offset));
-	  if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
-	       return -EFAULT; 
-	  (* offset) += len;
-	  return len;
-     }
-}
+	loff_t len;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
 
+	if (*offset >= p_info->len) {
+		return 0;
+	} else {
+		len = MIN (user_len, (p_info->len - *offset));
+		if (copy_to_user (user_buf, &(p_info->data[*offset]), len))
+			return -EFAULT;
+		(*offset) += len;
+		return len;
+	}
+}
 
-static int cio_sensedata_entry_open( struct inode *inode, struct file *file)
+static int
+cio_sensedata_entry_open (struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	int size = 1;
@@ -6885,49 +8148,67 @@
 	tempinfo_t *info;
 	int irq;
 	int devno;
-	char * devno_str;
+	char *devno_str;
 
-	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
 	if (info == NULL) {
-		printk( KERN_WARNING "No memory available for data\n");
+		printk (KERN_WARNING "No memory available for data\n");
 		rc = -ENOMEM;
 	} else {
 		file->private_data = (void *) info;
 		size += 2 * 32;
-		info->data = (char *) vmalloc(size);
+		info->data = (char *) vmalloc (size);
 		if (size && info->data == NULL) {
-			printk(KERN_WARNING "No memory available for data\n");
-			vfree(info);
+			printk (KERN_WARNING "No memory available for data\n");
+			vfree (info);
 			rc = -ENOMEM;
 		} else {
-			devno_str = kmalloc(6*sizeof(char), GFP_KERNEL);
-			memset(devno_str, 0, 6*sizeof(char));
-			memcpy(devno_str,file->f_dentry->d_parent->d_name.name, strlen(file->f_dentry->d_parent->d_name.name)+1);
-			devno = simple_strtoul(devno_str, &devno_str, 16);
-			irq = get_irq_by_devno(devno);
+			devno_str = kmalloc (6 * sizeof (char), GFP_KERNEL);
+			memset (devno_str, 0, 6 * sizeof (char));
+			memcpy (devno_str,
+				file->f_dentry->d_parent->d_name.name,
+				strlen (file->f_dentry->d_parent->d_name.name) +
+				1);
+			devno = simple_strtoul (devno_str, &devno_str, 16);
+			irq = get_irq_by_devno (devno);
 			if (irq != -1) {
-				len += sprintf(info->data+len, "Dev Type/Mod: ");
+				len +=
+				    sprintf (info->data + len,
+					     "Dev Type/Mod: ");
 				if (ioinfo[irq]->senseid.dev_type == 0) {
-					len += sprintf(info->data+len, "%04X/%02X\n",
-						       ioinfo[irq]->senseid.cu_type,
-						       ioinfo[irq]->senseid.cu_model);
+					len +=
+					    sprintf (info->data + len,
+						     "%04X/%02X\n",
+						     ioinfo[irq]->senseid.
+						     cu_type,
+						     ioinfo[irq]->senseid.
+						     cu_model);
 				} else {
-					len += sprintf(info->data+len, "%04X/%02X\n",
-						       ioinfo[irq]->senseid.dev_type,
-						       ioinfo[irq]->senseid.dev_model);
-					len+= sprintf(info->data+len, "CU Type/Mod:  %04X/%02X\n",
-						      ioinfo[irq]->senseid.cu_type,
-						      ioinfo[irq]->senseid.cu_model);
+					len +=
+					    sprintf (info->data + len,
+						     "%04X/%02X\n",
+						     ioinfo[irq]->senseid.
+						     dev_type,
+						     ioinfo[irq]->senseid.
+						     dev_model);
+					len +=
+					    sprintf (info->data + len,
+						     "CU Type/Mod:  %04X/%02X\n",
+						     ioinfo[irq]->senseid.
+						     cu_type,
+						     ioinfo[irq]->senseid.
+						     cu_model);
 				}
 			}
 			info->len = len;
 		}
 	}
-	
+
 	return rc;
 }
 
-static int cio_in_use_entry_open( struct inode *inode, struct file *file)
+static int
+cio_in_use_entry_open (struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	int size = 1;
@@ -6935,37 +8216,44 @@
 	tempinfo_t *info;
 	int irq;
 	int devno;
-	char * devno_str;
+	char *devno_str;
 
-	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
 	if (info == NULL) {
-		printk( KERN_WARNING "No memory available for data\n");
+		printk (KERN_WARNING "No memory available for data\n");
 		rc = -ENOMEM;
 	} else {
 		file->private_data = (void *) info;
 		size += 8;
-		info->data = (char *) vmalloc(size);
+		info->data = (char *) vmalloc (size);
 		if (size && info->data == NULL) {
-			printk(KERN_WARNING "No memory available for data\n");
-			vfree(info);
+			printk (KERN_WARNING "No memory available for data\n");
+			vfree (info);
 			rc = -ENOMEM;
 		} else {
-			devno_str = kmalloc(6*sizeof(char), GFP_KERNEL);
-			memset(devno_str, 0, 6*sizeof(char));
-			memcpy(devno_str,file->f_dentry->d_parent->d_name.name, strlen(file->f_dentry->d_parent->d_name.name)+1);
-			devno = simple_strtoul(devno_str, &devno_str, 16);
-			irq = get_irq_by_devno(devno);
+			devno_str = kmalloc (6 * sizeof (char), GFP_KERNEL);
+			memset (devno_str, 0, 6 * sizeof (char));
+			memcpy (devno_str,
+				file->f_dentry->d_parent->d_name.name,
+				strlen (file->f_dentry->d_parent->d_name.name) +
+				1);
+			devno = simple_strtoul (devno_str, &devno_str, 16);
+			irq = get_irq_by_devno (devno);
 			if (irq != -1) {
-				len += sprintf(info->data+len, "%s\n", ioinfo[irq]->ui.flags.ready?"yes":"no");
+				len +=
+				    sprintf (info->data + len, "%s\n",
+					     ioinfo[irq]->ui.flags.
+					     ready ? "yes" : "no");
 			}
 			info->len = len;
 		}
 	}
-	
+
 	return rc;
 }
 
-static int cio_chpid_entry_open( struct inode *inode, struct file *file)
+static int
+cio_chpid_entry_open (struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	int size = 1;
@@ -6974,30 +8262,38 @@
 	int irq;
 	int devno;
 	int i;
-	char * devno_str;
+	char *devno_str;
 
-	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
 	if (info == NULL) {
-		printk( KERN_WARNING "No memory available for data\n");
+		printk (KERN_WARNING "No memory available for data\n");
 		rc = -ENOMEM;
 	} else {
 		file->private_data = (void *) info;
-		size += 8*16;
-		info->data = (char *) vmalloc(size);
+		size += 8 * 16;
+		info->data = (char *) vmalloc (size);
 		if (size && info->data == NULL) {
-			printk(KERN_WARNING "No memory available for data\n");
-			vfree(info);
+			printk (KERN_WARNING "No memory available for data\n");
+			vfree (info);
 			rc = -ENOMEM;
 		} else {
-			devno_str = kmalloc(6*sizeof(char), GFP_KERNEL);
-			memset(devno_str, 0, 6*sizeof(char));
-			memcpy(devno_str,file->f_dentry->d_parent->d_name.name, strlen(file->f_dentry->d_parent->d_name.name)+1);
-			devno = simple_strtoul(devno_str, &devno_str, 16);
-			irq = get_irq_by_devno(devno);
+			devno_str = kmalloc (6 * sizeof (char), GFP_KERNEL);
+			memset (devno_str, 0, 6 * sizeof (char));
+			memcpy (devno_str,
+				file->f_dentry->d_parent->d_name.name,
+				strlen (file->f_dentry->d_parent->d_name.name) +
+				1);
+			devno = simple_strtoul (devno_str, &devno_str, 16);
+			irq = get_irq_by_devno (devno);
 			if (irq != -1) {
-				for (i=0; i<8; i++) {
-					len += sprintf(info->data+len, "CHPID[%d]: ", i);
-					len += sprintf(info->data+len, "%02X\n", ioinfo[irq]->schib.pmcw.chpid[i]);
+				for (i = 0; i < 8; i++) {
+					len +=
+					    sprintf (info->data + len,
+						     "CHPID[%d]: ", i);
+					len +=
+					    sprintf (info->data + len, "%02X\n",
+						     ioinfo[irq]->schib.pmcw.
+						     chpid[i]);
 				}
 			}
 			info->len = len;
@@ -7007,25 +8303,19 @@
 	return rc;
 }
 
-static struct file_operations cio_sensedata_entry_file_ops =
-{
-     read:cio_device_entry_read,
-     open:cio_sensedata_entry_open,
-     release:cio_device_entry_close,
+static struct file_operations cio_sensedata_entry_file_ops = {
+	read:cio_device_entry_read, open:cio_sensedata_entry_open,
+	release:cio_device_entry_close,
 };
 
-static struct file_operations cio_in_use_entry_file_ops =
-{
-     read:cio_device_entry_read,
-     open:cio_in_use_entry_open,
-     release:cio_device_entry_close,
+static struct file_operations cio_in_use_entry_file_ops = {
+	read:cio_device_entry_read, open:cio_in_use_entry_open,
+	release:cio_device_entry_close,
 };
 
-static struct file_operations cio_chpid_entry_file_ops =
-{
-     read:cio_device_entry_read,
-     open:cio_chpid_entry_open,
-     release:cio_device_entry_close,
+static struct file_operations cio_chpid_entry_file_ops = {
+	read:cio_device_entry_read, open:cio_chpid_entry_open,
+	release:cio_device_entry_close,
 };
 
 /*
@@ -7033,7 +8323,8 @@
  * create procfs entry for given device number
  * and insert it into list
  */
-int cio_procfs_device_create(int devno)
+int
+cio_procfs_device_create (int devno)
 {
 	cio_procfs_entry_t *entry;
 	cio_procfs_device_t *tmp;
@@ -7042,26 +8333,30 @@
 	int i;
 	int rc = 0;
 
-
 	/* create the directory entry */
-	entry = (cio_procfs_entry_t *)kmalloc(sizeof(cio_procfs_entry_t), GFP_KERNEL);
+	entry =
+	    (cio_procfs_entry_t *) kmalloc (sizeof (cio_procfs_entry_t),
+					    GFP_KERNEL);
 	if (entry) {
 		entry->devno = devno;
-		sprintf(buf, "%x", devno);
-		entry->cio_device_entry = proc_mkdir(buf, cio_procfs_deviceinfo_root);
-		
+		sprintf (buf, "%x", devno);
+		entry->cio_device_entry =
+		    proc_mkdir (buf, cio_procfs_deviceinfo_root);
+
 		if (entry->cio_device_entry) {
-			tmp = (cio_procfs_device_t *)kmalloc(sizeof(cio_procfs_device_t), GFP_KERNEL);
+			tmp = (cio_procfs_device_t *)
+			    kmalloc (sizeof (cio_procfs_device_t), GFP_KERNEL);
 			if (tmp) {
 				tmp->entry = entry;
-				
+
 				if (cio_procfs_device_list == NULL) {
 					cio_procfs_device_list = tmp;
 					tmp->next = NULL;
 				} else {
 					where = cio_procfs_device_list;
 					i = where->entry->devno;
-					while ((devno>i) && (where->next != NULL)) {
+					while ((devno > i)
+					       && (where->next != NULL)) {
 						where = where->next;
 						i = where->entry->devno;
 					}
@@ -7074,26 +8369,42 @@
 					}
 				}
 				/* create the different entries */
-				entry->cio_sensedata_entry = create_proc_entry( "sensedata", S_IFREG|S_IRUGO, entry->cio_device_entry);
-				entry->cio_sensedata_entry->proc_fops = &cio_sensedata_entry_file_ops;
-				entry->cio_in_use_entry = create_proc_entry( "in_use", S_IFREG|S_IRUGO, entry->cio_device_entry);
-				entry->cio_in_use_entry->proc_fops = &cio_in_use_entry_file_ops;
-				entry->cio_chpid_entry = create_proc_entry( "chpids", S_IFREG|S_IRUGO, entry->cio_device_entry);
-				entry->cio_chpid_entry->proc_fops = &cio_chpid_entry_file_ops;
+				entry->cio_sensedata_entry =
+				    create_proc_entry ("sensedata",
+						       S_IFREG | S_IRUGO,
+						       entry->cio_device_entry);
+				entry->cio_sensedata_entry->proc_fops =
+				    &cio_sensedata_entry_file_ops;
+				entry->cio_in_use_entry =
+				    create_proc_entry ("in_use",
+						       S_IFREG | S_IRUGO,
+						       entry->cio_device_entry);
+				entry->cio_in_use_entry->proc_fops =
+				    &cio_in_use_entry_file_ops;
+				entry->cio_chpid_entry =
+				    create_proc_entry ("chpids",
+						       S_IFREG | S_IRUGO,
+						       entry->cio_device_entry);
+				entry->cio_chpid_entry->proc_fops =
+				    &cio_chpid_entry_file_ops;
 			} else {
-				printk( KERN_WARNING "Error, could not allocate procfs structure!\n");
-				remove_proc_entry(buf, cio_procfs_deviceinfo_root);
-				kfree(entry);
+				printk (KERN_WARNING
+					"Error, could not allocate procfs structure!\n");
+				remove_proc_entry (buf,
+						   cio_procfs_deviceinfo_root);
+				kfree (entry);
 				rc = -ENOMEM;
 			}
 		} else {
-			printk( KERN_WARNING "Error, could not allocate procfs structure!\n");
-			kfree(entry);
+			printk (KERN_WARNING
+				"Error, could not allocate procfs structure!\n");
+			kfree (entry);
 			rc = -ENOMEM;
 		}
 
 	} else {
-		printk( KERN_WARNING "Error, could not allocate procfs structure!\n");
+		printk (KERN_WARNING
+			"Error, could not allocate procfs structure!\n");
 		rc = -ENOMEM;
 	}
 	return rc;
@@ -7103,36 +8414,36 @@
  * Function: cio_procfs_device_remove
  * remove procfs entry for given device number
  */
-int cio_procfs_device_remove(int devno)
+int
+cio_procfs_device_remove (int devno)
 {
 	int rc = 0;
 	cio_procfs_device_t *tmp;
 	cio_procfs_device_t *prev = NULL;
 
-	tmp=cio_procfs_device_list;
+	tmp = cio_procfs_device_list;
 	while (tmp) {
 		if (tmp->entry->devno == devno)
 			break;
 		prev = tmp;
 		tmp = tmp->next;
 	}
-
 	if (tmp) {
 		char buf[8];
-		
-		remove_proc_entry("sensedata", tmp->entry->cio_device_entry);
-		remove_proc_entry("in_use", tmp->entry->cio_device_entry);
-		remove_proc_entry("chpid", tmp->entry->cio_device_entry);
-		sprintf(buf, "%x", devno);
-		remove_proc_entry(buf, cio_procfs_deviceinfo_root);
-		
+
+		remove_proc_entry ("sensedata", tmp->entry->cio_device_entry);
+		remove_proc_entry ("in_use", tmp->entry->cio_device_entry);
+		remove_proc_entry ("chpid", tmp->entry->cio_device_entry);
+		sprintf (buf, "%x", devno);
+		remove_proc_entry (buf, cio_procfs_deviceinfo_root);
+
 		if (tmp == cio_procfs_device_list) {
 			cio_procfs_device_list = tmp->next;
 		} else {
 			prev->next = tmp->next;
 		}
-		kfree(tmp->entry);
-		kfree(tmp);
+		kfree (tmp->entry);
+		kfree (tmp);
 	} else {
 		rc = -ENODEV;
 	}
@@ -7145,17 +8456,17 @@
  * purge /proc/deviceinfo of entries for gone devices
  */
 
-int cio_procfs_device_purge(void) 
+int
+cio_procfs_device_purge (void)
 {
 	int i;
 
-	for (i=0; i<=highest_subchannel; i++) {
+	for (i = 0; i <= highest_subchannel; i++) {
 		if (ioinfo[i] != INVALID_STORAGE_AREA) {
-			if (!ioinfo[i]->ui.flags.oper) 
-				cio_procfs_device_remove(ioinfo[i]->devno);
+			if (!ioinfo[i]->ui.flags.oper)
+				cio_procfs_device_remove (ioinfo[i]->devno);
 		}
 	}
-
 	return 0;
 }
 
@@ -7163,38 +8474,45 @@
  * Function: cio_procfs_create
  * create /proc/deviceinfo/ and subdirs for the devices
  */
-static int cio_procfs_create( void )
+static int
+cio_procfs_create (void)
 {
 	int irq;
 
 	if (cio_proc_devinfo) {
 
-		cio_procfs_deviceinfo_root = proc_mkdir( "deviceinfo", &proc_root);
-		
+		cio_procfs_deviceinfo_root =
+		    proc_mkdir ("deviceinfo", &proc_root);
+
 		if (highest_subchannel >= MAX_CIO_PROCFS_ENTRIES) {
-			printk(KERN_ALERT "Warning: Not enough inodes for creating all entries under /proc/deviceinfo/. "
-			       "Not every device will get an entry.\n");
+			printk (KERN_ALERT
+				"Warning: Not enough inodes for creating all "
+				"entries under /proc/deviceinfo/. "
+				"Not every device will get an entry.\n");
 		}
-		
-		for (irq=0; irq<=highest_subchannel; irq++) {
+
+		for (irq = 0; irq <= highest_subchannel; irq++) {
 			if (irq >= MAX_CIO_PROCFS_ENTRIES)
 				break;
 			if (ioinfo[irq] != INVALID_STORAGE_AREA) {
-				if (ioinfo[irq]->ui.flags.oper) 
-					if (cio_procfs_device_create(ioinfo[irq]->devno) == -ENOMEM) {
-						printk(KERN_CRIT "Out of memory while creating entries in /proc/deviceinfo/, "
-						       "not all devices might show up\n");
-					break;
+				if (ioinfo[irq]->ui.flags.oper)
+					if (cio_procfs_device_create
+					    (ioinfo[irq]->devno) == -ENOMEM) {
+						printk (KERN_CRIT
+							"Out of memory while creating "
+							"entries in /proc/deviceinfo/, "
+							"not all devices might show up\n");
+						break;
 					}
 			}
 		}
-	
+
 	}
-	
+
 	return 1;
 }
 
-__initcall(cio_procfs_create);
+__initcall (cio_procfs_create);
 
 /*
  * Entry /proc/cio_ignore to display blacklisted ranges of devices.
@@ -7206,7 +8524,8 @@
  */
 
 static struct proc_dir_entry *cio_ignore_proc_entry;
-static int cio_ignore_proc_open(struct inode *inode, struct file *file)
+static int
+cio_ignore_proc_open (struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	int size = 1;
@@ -7215,107 +8534,123 @@
 	long flags;
 	int i, j;
 
-	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
 	if (info == NULL) {
-		printk( KERN_WARNING "No memory available for data\n");
+		printk (KERN_WARNING "No memory available for data\n");
 		rc = -ENOMEM;
 	} else {
 		file->private_data = (void *) info;
 		size += nr_ignored * 6;
-		info->data = (char *) vmalloc(size);
+		info->data = (char *) vmalloc (size);
 		if (size && info->data == NULL) {
-			printk( KERN_WARNING "No memory available for data\n");
+			printk (KERN_WARNING "No memory available for data\n");
 			vfree (info);
 			rc = -ENOMEM;
 		} else {
-			spin_lock_irqsave( &blacklist_lock, flags ); 
-			for (i=0;i<=highest_ignored;i++) 
-				if (test_bit(i,&bl_dev)) {
-					len += sprintf(info->data+len, "%04x ", i);
-					for (j=i;(j<=highest_ignored) && (test_bit(j,&bl_dev));j++);
+			spin_lock_irqsave (&blacklist_lock, flags);
+			for (i = 0; i <= highest_ignored; i++)
+				if (test_bit (i, &bl_dev)) {
+					len +=
+					    sprintf (info->data + len, "%04x ",
+						     i);
+					for (j = i; (j <= highest_ignored)
+					     && (test_bit (j, &bl_dev)); j++) ;
 					j--;
-					if (i != j) 
-						len += sprintf(info->data+len, "- %04x", j);
-				len += sprintf(info->data+len, "\n");
-					i=j;
-			}
-			spin_unlock_irqrestore( &blacklist_lock, flags );
+					if (i != j)
+						len +=
+						    sprintf (info->data + len,
+							     "- %04x", j);
+					len += sprintf (info->data + len, "\n");
+					i = j;
+				}
+			spin_unlock_irqrestore (&blacklist_lock, flags);
 			info->len = len;
 		}
 	}
 	return rc;
 }
 
-static int cio_ignore_proc_close(struct inode *inode, struct file *file)
+static int
+cio_ignore_proc_close (struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
 
-     if (p_info) {
-	  if (p_info->data)
-	       vfree( p_info->data );
-	  vfree( p_info );
-     }
-     
-     return rc;
+	if (p_info) {
+		if (p_info->data)
+			vfree (p_info->data);
+		vfree (p_info);
+	}
+
+	return rc;
 }
 
-static ssize_t cio_ignore_proc_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+static ssize_t
+cio_ignore_proc_read (struct file *file, char *user_buf, size_t user_len,
+		      loff_t * offset)
 {
-     loff_t len;
-     tempinfo_t *p_info = (tempinfo_t *) file->private_data;
-     
-     if ( *offset>=p_info->len) {
-	  return 0;
-     } else {
-	  len = MIN(user_len, (p_info->len - *offset));
-	  if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
-	       return -EFAULT; 
-	  (* offset) += len;
-	  return len;
-     }
+	loff_t len;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+	if (*offset >= p_info->len) {
+		return 0;
+	} else {
+		len = MIN (user_len, (p_info->len - *offset));
+		if (copy_to_user (user_buf, &(p_info->data[*offset]), len))
+			return -EFAULT;
+		(*offset) += len;
+		return len;
+	}
 }
 
-static ssize_t cio_ignore_proc_write (struct file *file, const char *user_buf,
-				      size_t user_len, loff_t * offset)
+static ssize_t
+cio_ignore_proc_write (struct file *file, const char *user_buf,
+		       size_t user_len, loff_t * offset)
 {
-	char *buffer = vmalloc (user_len);
-
+	char *buffer
+	
+	if(user_len > 65536)
+		user_len = 65536;
+	
+	buffer = vmalloc (user_len + 1);
+	
 	if (buffer == NULL)
 		return -ENOMEM;
 	if (copy_from_user (buffer, user_buf, user_len)) {
 		vfree (buffer);
 		return -EFAULT;
 	}
-	buffer[user_len]='\0';
-#ifdef CIO_DEBUG_IO
-	printk ( KERN_DEBUG "/proc/cio_ignore: '%s'\n", buffer);
-#endif /* CIO_DEBUG_IO */
+	buffer[user_len] = '\0';
+#ifdef CONFIG_DEBUG_IO
+	printk (KERN_DEBUG "/proc/cio_ignore: '%s'\n", buffer);
+#endif /* CONFIG_DEBUG_IO */
 	if (cio_debug_initialized)
-		debug_sprintf_event(cio_debug_msg_id, 2, "/proc/cio_ignore: '%s'\n",buffer);
+		debug_sprintf_event (cio_debug_msg_id, 2,
+				     "/proc/cio_ignore: '%s'\n", buffer);
 
-	blacklist_parse_proc_parameters(buffer);
+	blacklist_parse_proc_parameters (buffer);
 
+	vfree (buffer);
 	return user_len;
 }
 
-static struct file_operations cio_ignore_proc_file_ops =
-{
-	read:cio_ignore_proc_read,
-	open:cio_ignore_proc_open,
-	write:cio_ignore_proc_write,
-	release:cio_ignore_proc_close,
+static struct file_operations cio_ignore_proc_file_ops = {
+	read:cio_ignore_proc_read, open:cio_ignore_proc_open,
+	write:cio_ignore_proc_write, release:cio_ignore_proc_close,
 };
 
-static int cio_ignore_proc_init(void)
+static int
+cio_ignore_proc_init (void)
 {
-	cio_ignore_proc_entry = create_proc_entry("cio_ignore", S_IFREG|S_IRUGO|S_IWUSR, &proc_root);
+	cio_ignore_proc_entry =
+	    create_proc_entry ("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR,
+			       &proc_root);
 	cio_ignore_proc_entry->proc_fops = &cio_ignore_proc_file_ops;
 
 	return 1;
 }
 
-__initcall(cio_ignore_proc_init);
+__initcall (cio_ignore_proc_init);
 
 /*
  * Entry /proc/irq_count
@@ -7324,7 +8659,8 @@
 
 static struct proc_dir_entry *cio_irq_proc_entry;
 
-static int cio_irq_proc_open(struct inode *inode, struct file *file)
+static int
+cio_irq_proc_open (struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	int size = 1;
@@ -7332,22 +8668,24 @@
 	tempinfo_t *info;
 	int i;
 
-	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
 	if (info == NULL) {
-		printk( KERN_WARNING "No memory available for data\n");
+		printk (KERN_WARNING "No memory available for data\n");
 		rc = -ENOMEM;
 	} else {
 		file->private_data = (void *) info;
 		size += NR_CPUS * 16;
-		info->data = (char *) vmalloc(size);
+		info->data = (char *) vmalloc (size);
 		if (size && info->data == NULL) {
-			printk( KERN_WARNING "No memory available for data\n");
+			printk (KERN_WARNING "No memory available for data\n");
 			vfree (info);
 			rc = -ENOMEM;
 		} else {
-			for (i=0; i< NR_CPUS; i++) {
-				if (s390_irq_count[i] != 0) 
-					len += sprintf(info->data+len, "%lx\n", s390_irq_count[i]);
+			for (i = 0; i < NR_CPUS; i++) {
+				if (s390_irq_count[i] != 0)
+					len +=
+					    sprintf (info->data + len, "%lx\n",
+						     s390_irq_count[i]);
 			}
 			info->len = len;
 		}
@@ -7355,88 +8693,265 @@
 	return rc;
 }
 
-static int cio_irq_proc_close(struct inode *inode, struct file *file)
+static int
+cio_irq_proc_close (struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
 
 	if (p_info) {
-		if (p_info->data) 
-			vfree(p_info->data);
-		vfree(p_info);
+		if (p_info->data)
+			vfree (p_info->data);
+		vfree (p_info);
 	}
 
 	return rc;
 }
 
-static ssize_t cio_irq_proc_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+static ssize_t
+cio_irq_proc_read (struct file *file, char *user_buf, size_t user_len,
+		   loff_t * offset)
 {
 	loff_t len;
 	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
-	
-	if ( *offset>=p_info->len) {
+
+	if (*offset >= p_info->len) {
 		return 0;
 	} else {
-		len = MIN(user_len, (p_info->len - *offset));
-		if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
-			return -EFAULT; 
-		(* offset) += len;
+		len = MIN (user_len, (p_info->len - *offset));
+		if (copy_to_user (user_buf, &(p_info->data[*offset]), len))
+			return -EFAULT;
+		(*offset) += len;
 		return len;
 	}
 }
 
-static struct file_operations cio_irq_proc_file_ops = 
-	{
-		read:    cio_irq_proc_read,
-		open:    cio_irq_proc_open,
-		release: cio_irq_proc_close,
-	};
+static struct file_operations cio_irq_proc_file_ops = {
+	read:cio_irq_proc_read, open:cio_irq_proc_open,
+	release:cio_irq_proc_close,
+};
 
-static int cio_irq_proc_init(void)
+static int
+cio_irq_proc_init (void)
 {
 
 	int i;
 
 	if (cio_count_irqs) {
-		for (i=0; i<NR_CPUS; i++) 
-			s390_irq_count[i]=0;
-		cio_irq_proc_entry = create_proc_entry("irq_count", S_IFREG|S_IRUGO, &proc_root);
+		for (i = 0; i < NR_CPUS; i++)
+			s390_irq_count[i] = 0;
+		cio_irq_proc_entry =
+		    create_proc_entry ("irq_count", S_IFREG | S_IRUGO,
+				       &proc_root);
 		cio_irq_proc_entry->proc_fops = &cio_irq_proc_file_ops;
 	}
 
 	return 1;
 }
 
-__initcall(cio_irq_proc_init);	
+__initcall (cio_irq_proc_init);
+
+
+#ifdef CONFIG_CHSC
+/*
+ * /proc/chpids to display available chpids
+ * vary chpids on/off by piping to it
+ */
+
+static struct proc_dir_entry *cio_chpids_proc_entry;
+
+static int 
+cio_chpids_proc_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	int size = 1;
+	int len = 0;
+	tempinfo_t *info;
+	int i;
+
+	if (!cio_chsc_desc_avail) {
+		/* 
+		 * We have not yet retrieved the link addresses,
+		 * so we do it now.
+		 */
+		chsc_get_sch_descriptions();
+	}
+
+
+	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	if (info == NULL) {
+		printk( KERN_WARNING "No memory available for data\n");
+		rc = -ENOMEM;
+	} else {
+		file->private_data = (void *) info;
+		size += NR_CHPIDS * 16;
+		info->data = (char *) vmalloc(size);
+		if ( size && info->data == NULL) {
+			printk( KERN_WARNING "No memory available for data\n");
+			vfree (info);
+			rc = -ENOMEM;
+		} else {
+			/* update our stuff */
+			chsc_get_sch_descriptions();
+			if (!cio_chsc_desc_avail) {
+				len += sprintf(info->data+len, "no info available\n");
+			} else {
+				for (i=0;i<NR_CHPIDS;i++) {
+					if ((test_bit(i, &chpids)) && 
+					    test_bit(i, &chpids_logical))
+						len += sprintf(info->data+len, 
+							       "%02X online\n", 
+							       i);
+					else if (test_bit(i, &chpids_known))
+						len += sprintf(info->data+len, 
+							       "%02X logically offline\n", 
+							       i);
+				}
+			}
+			info->len = len;
+		}
+	}
+	return rc;
+}
+
+static int 
+cio_chpids_proc_close(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+     if (p_info) {
+	  if (p_info->data)
+	       vfree( p_info->data );
+	  vfree( p_info );
+     }
+     
+     return rc;
+}
+
+static ssize_t 
+cio_chpids_proc_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+{
+     loff_t len;
+     tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+     
+     if ( *offset>=p_info->len) {
+	  return 0;
+     } else {
+	  len = MIN(user_len, (p_info->len - *offset));
+	  if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
+	       return -EFAULT; 
+	  (* offset) += len;
+	  return len;
+     }
+}
+
+static ssize_t 
+cio_chpids_proc_write (struct file *file, const char *user_buf,
+		       size_t user_len, loff_t * offset)
+{
+	char *buffer;
+	
+	if(user_len > 65536)
+		user_len = 65536;
+	
+	buffer = vmalloc (user_len + 1);
+
+	if (buffer == NULL)
+		return -ENOMEM;
+	if (copy_from_user (buffer, user_buf, user_len)) {
+		vfree (buffer);
+		return -EFAULT;
+	}
+	buffer[user_len]='\0';
+#ifdef CIO_DEBUG_IO
+	printk("/proc/chpids: '%s'\n", buffer);
+#endif /* CIO_DEBUG_IO */
+	CIO_MSG_EVENT( 2, "/proc/chpids: '%s'\n", buffer);
+
+	cio_parse_chpids_proc_parameters(buffer);
+
+	vfree (buffer);
+	return user_len;
+}
+
+static struct file_operations cio_chpids_proc_file_ops =
+{
+	read:cio_chpids_proc_read,
+	open:cio_chpids_proc_open,
+	write:cio_chpids_proc_write,
+	release:cio_chpids_proc_close,
+};
+
+static int 
+cio_chpids_proc_init(void)
+{
+
+	cio_chpids_proc_entry = create_proc_entry("chpids", S_IFREG|S_IRUGO|S_IWUSR, &proc_root);
+	cio_chpids_proc_entry->proc_fops = &cio_chpids_proc_file_ops;
+	
+	return 1;
+
 
+}
+
+__initcall(cio_chpids_proc_init);
+#endif
 /* end of procfs stuff */
 #endif
 
-schib_t *s390_get_schib( int irq )
+schib_t *
+s390_get_schib (int irq)
 {
-	if ( (irq > highest_subchannel) || (irq < 0) )
+	if ((irq > highest_subchannel) || (irq < 0))
+		return NULL;
+	if (ioinfo[irq] == INVALID_STORAGE_AREA)
 		return NULL;
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
+	if (ioinfo[irq]->st)
 		return NULL;
 	return &ioinfo[irq]->schib;
 
 }
 
+int
+s390_set_private_data(int irq, void *data)
+{
+	SANITY_CHECK(irq);
+	
+	ioinfo[irq]->private_data = data;
+		
+	return 0;
+}
+
+void *
+s390_get_private_data(int irq)
+{
+	if ((irq > highest_subchannel) || (irq < 0))
+		return NULL;
+	if (ioinfo[irq] == INVALID_STORAGE_AREA)
+		return NULL;
+	if (ioinfo[irq]->st)
+		return NULL;
+	return ioinfo[irq]->private_data;
+}
 
-EXPORT_SYMBOL(halt_IO);
-EXPORT_SYMBOL(clear_IO);
-EXPORT_SYMBOL(do_IO);
-EXPORT_SYMBOL(resume_IO);
-EXPORT_SYMBOL(ioinfo);
-EXPORT_SYMBOL(get_dev_info_by_irq);
-EXPORT_SYMBOL(get_dev_info_by_devno);
-EXPORT_SYMBOL(get_irq_by_devno);
-EXPORT_SYMBOL(get_devno_by_irq);
-EXPORT_SYMBOL(get_irq_first);
-EXPORT_SYMBOL(get_irq_next);
-EXPORT_SYMBOL(read_conf_data);
-EXPORT_SYMBOL(read_dev_chars);
-EXPORT_SYMBOL(s390_request_irq_special);
-EXPORT_SYMBOL(s390_get_schib);
-EXPORT_SYMBOL(s390_register_adapter_interrupt);
-EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
+EXPORT_SYMBOL (halt_IO);
+EXPORT_SYMBOL (clear_IO);
+EXPORT_SYMBOL (do_IO);
+EXPORT_SYMBOL (resume_IO);
+EXPORT_SYMBOL (ioinfo);
+EXPORT_SYMBOL (get_dev_info_by_irq);
+EXPORT_SYMBOL (get_dev_info_by_devno);
+EXPORT_SYMBOL (get_irq_by_devno);
+EXPORT_SYMBOL (get_devno_by_irq);
+EXPORT_SYMBOL (get_irq_first);
+EXPORT_SYMBOL (get_irq_next);
+EXPORT_SYMBOL (read_conf_data);
+EXPORT_SYMBOL (read_dev_chars);
+EXPORT_SYMBOL (s390_request_irq_special);
+EXPORT_SYMBOL (s390_get_schib);
+EXPORT_SYMBOL (s390_register_adapter_interrupt);
+EXPORT_SYMBOL (s390_unregister_adapter_interrupt);
+EXPORT_SYMBOL (s390_set_private_data);
+EXPORT_SYMBOL (s390_get_private_data);
+EXPORT_SYMBOL (s390_trigger_resense);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/s390/s390mach.c linux-2.4.20/drivers/s390/s390mach.c
--- linux-2.4.19/drivers/s390/s390mach.c	2001-11-09 22:05:02.000000000 +0000
+++ linux-2.4.20/drivers/s390/s390mach.c	2002-10-29 11:18:50.000000000 +0000
@@ -22,6 +22,11 @@
 #include <asm/s390io.h>
 #include <asm/s390dyn.h>
 #include <asm/s390mach.h>
+#ifdef CONFIG_MACHCHK_WARNING
+#include <asm/signal.h>
+#endif
+
+extern void ctrl_alt_del(void);
 
 #define S390_MACHCHK_DEBUG
 
@@ -31,6 +36,9 @@
 static void        s390_enqueue_free_mchchk( mache_t *mchchk );
 static mache_t    *s390_dequeue_free_mchchk( void );
 static int         s390_collect_crw_info( void );
+#ifdef CONFIG_MACHCHK_WARNING
+static int         s390_post_warning( void );
+#endif
 
 static mache_t    *mchchk_queue_head = NULL;
 static mache_t    *mchchk_queue_tail = NULL;
@@ -41,6 +49,9 @@
 
 static struct semaphore s_sem;
 
+#ifdef CONFIG_MACHCHK_WARNING
+static int mchchk_wng_posted = 0;
+#endif
 
 /*
  * s390_init_machine_check
@@ -98,31 +109,50 @@
 	} /* endif */
 
 #ifdef S390_MACHCHK_DEBUG
-	printk( "init_mach : starting machine check handler\n");
+	printk( KERN_NOTICE "init_mach : starting machine check handler\n");
 #endif	
 
 	kernel_thread( s390_machine_check_handler, &s_sem, CLONE_FS | CLONE_FILES);
 
 	ctl_clear_bit( 14, 25 );  // disable damage MCH 	
+
+	ctl_set_bit( 14, 26 ); /* enable degradation MCH */
+	ctl_set_bit( 14, 27 ); /* enable system recovery MCH */
 #if 1
   	ctl_set_bit( 14, 28 );		// enable channel report MCH
 #endif
+#ifdef CONFIG_MACHCK_WARNING
+	ctl_set_bit( 14, 24);   /* enable warning MCH */
+#endif
 
 #ifdef S390_MACHCHK_DEBUG
-	printk( "init_mach : machine check buffer : head = %08X\n",
+	printk( KERN_DEBUG "init_mach : machine check buffer : head = %08X\n",
             (unsigned)&mchchk_queue_head);
-	printk( "init_mach : machine check buffer : tail = %08X\n",
+	printk( KERN_DEBUG "init_mach : machine check buffer : tail = %08X\n",
             (unsigned)&mchchk_queue_tail);
-	printk( "init_mach : machine check buffer : free = %08X\n",
+	printk( KERN_DEBUG "init_mach : machine check buffer : free = %08X\n",
             (unsigned)&mchchk_queue_free);
-	printk( "init_mach : CRW entry buffer anchor = %08X\n",
+	printk( KERN_DEBUG "init_mach : CRW entry buffer anchor = %08X\n",
             (unsigned)&crw_buffer_anchor);
-	printk( "init_mach : machine check handler ready\n");
+	printk( KERN_DEBUG "init_mach : machine check handler ready\n");
 #endif	
 
 	return;
 }
 
+static void s390_handle_damage(char * msg){
+
+	unsigned long caller = (unsigned long) __builtin_return_address(0);
+
+	printk(KERN_EMERG "%s\n", msg);
+#ifdef CONFIG_SMP
+	smp_send_stop();
+#endif
+	disabled_wait(caller);
+	return;
+}
+
+
 /*
  * s390_do_machine_check
  *
@@ -135,13 +165,31 @@
 	mcic_t   mcic;
 
 #ifdef S390_MACHCHK_DEBUG
-	printk( "s390_do_machine_check : starting ...\n");
+	printk( KERN_INFO "s390_do_machine_check : starting ...\n");
 #endif
 
 	memcpy( &mcic,
 	        &S390_lowcore.mcck_interruption_code,
 	        sizeof(__u64));
  		
+	if (mcic.mcc.mcd.sd) /* system damage */
+		s390_handle_damage("received system damage machine check\n");
+
+	if (mcic.mcc.mcd.pd) /* instruction processing damage */
+		s390_handle_damage("received instruction processing damage machine check\n");
+
+	if (mcic.mcc.mcd.se) /* storage error uncorrected */
+		s390_handle_damage("received storage error uncorrected machine check\n");
+
+	if (mcic.mcc.mcd.sc) /* storage error corrected */
+		printk(KERN_WARNING "received storage error corrected machine check\n");
+
+	if (mcic.mcc.mcd.ke) /* storage key-error uncorrected */
+		s390_handle_damage("received storage key-error uncorrected machine check\n");
+
+	if (mcic.mcc.mcd.ds && mcic.mcc.mcd.fa) /* storage degradation */
+		s390_handle_damage("received storage degradation machine check\n");
+
 	if ( mcic.mcc.mcd.cp )	// CRW pending ?
 	{
 		crw_count = s390_collect_crw_info();
@@ -153,9 +201,38 @@
 		} /* endif */
 
 	} /* endif */
+#ifdef CONFIG_MACHCHK_WARNING
+/*
+ * The warning may remain for a prolonged period on the bare iron.
+ * (actually till the machine is powered off, or until the problem is gone)
+ * So we just stop listening for the WARNING MCH and prevent continuously
+ * being interrupted.  One caveat is however, that we must do this per 
+ * processor and cannot use the smp version of ctl_clear_bit().
+ * On VM we only get one interrupt per virtally presented machinecheck.
+ * Though one suffices, we may get one interrupt per (virtual) processor. 
+ */
+	if ( mcic.mcc.mcd.w )	// WARNING pending ?
+	{
+		// Use single machine clear, as we cannot handle smp right now
+		__ctl_clear_bit( 14, 24 );	// Disable WARNING MCH
+
+		if ( ! mchchk_wng_posted )
+		{ 
+			mchchk_wng_posted = s390_post_warning();
+
+			if ( mchchk_wng_posted )
+			{
+				up( &s_sem );
+
+			} /* endif */
+
+		} /* endif */
+
+	} /* endif */
+#endif
 
 #ifdef S390_MACHCHK_DEBUG
-	printk( "s390_do_machine_check : done \n");
+	printk( KERN_INFO "s390_do_machine_check : done \n");
 #endif
 
 	return;
@@ -183,19 +260,19 @@
         sigfillset(&current->blocked);
 
 #ifdef S390_MACHCHK_DEBUG
-	printk( "mach_handler : ready\n");
+	printk( KERN_NOTICE "mach_handler : ready\n");
 #endif	
 
 	do {
 
 #ifdef S390_MACHCHK_DEBUG
-		printk( "mach_handler : waiting for wakeup\n");
+		printk( KERN_NOTICE "mach_handler : waiting for wakeup\n");
 #endif	
 
 		down_interruptible( sem );
 
 #ifdef S390_MACHCHK_DEBUG
-		printk( "\nmach_handler : wakeup ... \n");
+		printk( KERN_NOTICE "\nmach_handler : wakeup ... \n");
 #endif	
 		found = 0; /* init ... */
 
@@ -240,6 +317,16 @@
 
 			} /* endif */
 
+#ifdef CONFIG_MACHCHK_WARNING
+			if ( pmache->mcic.mcc.mcd.w )
+			{
+				ctrl_alt_del();		// shutdown NOW!
+#ifdef S390_MACHCHK_DEBUG
+			printk( KERN_DEBUG "mach_handler : kill -SIGPWR init\n");
+#endif
+			} /* endif */
+#endif
+
 			s390_enqueue_free_mchchk( pmache );
 		}
 		else
@@ -247,7 +334,7 @@
 
 			// unconditional surrender ...
 #ifdef S390_MACHCHK_DEBUG
-			printk( "mach_handler : nothing to do, sleeping\n");
+			printk( KERN_DEBUG "mach_handler : nothing to do, sleeping\n");
 #endif	
 
 		} /* endif */	
@@ -424,7 +511,7 @@
 	int      count  = 0;    /* CRW count */
 
 #ifdef S390_MACHCHK_DEBUG
-	printk( "crw_info : looking for CRWs ...\n");
+	printk( KERN_DEBUG "crw_info : looking for CRWs ...\n");
 #endif
 
 	do
@@ -436,7 +523,7 @@
 			count++;
 			
 #ifdef S390_MACHCHK_DEBUG
-			printk( "crw_info : CRW reports "
+			printk( KERN_DEBUG "crw_info : CRW reports "
 			        "slct=%d, oflw=%d, chn=%d, "
 			        "rsc=%X, anc=%d, erc=%X, "
 			        "rsid=%X\n",
@@ -508,7 +595,7 @@
 			if ( pccrw->crw.chn )
 			{
 #ifdef S390_MACHCHK_DEBUG
-				printk( "crw_info : "
+				printk( KERN_DEBUG "crw_info : "
 				        "chained CRWs pending ...\n\n");
 #endif
 				chain = 1;
@@ -532,3 +619,40 @@
 	return( count );
 }
 
+#ifdef CONFIG_MACHCHK_WARNING
+/*
+ * s390_post_warning
+ *
+ * Post a warning type machine check
+ *
+ * The function returns 1 when succesfull (panics otherwise)
+ */
+static int s390_post_warning( void )
+{
+	mache_t  *pmache = NULL; /* ptr to mchchk entry */
+
+	pmache = s390_dequeue_free_mchchk();
+
+	if ( pmache != NULL )
+	{
+		memset( pmache, '\0', sizeof(mache_t) );
+
+		pmache->mcic.mcc.mcd.w = 1;
+
+		s390_enqueue_mchchk( pmache );
+	}
+	else
+	{
+		panic( 	"post_warning : "
+			"unable to dequeue "
+			"free mchchk buffer" );
+	} /* endif */
+
+#ifdef S390_MACHCHK_DEBUG
+	printk( KERN_DEBUG "post_warning : 1 warning machine check posted\n");
+#endif
+
+	return ( 1 );
+}
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/s390/sysinfo.c linux-2.4.20/drivers/s390/sysinfo.c
--- linux-2.4.19/drivers/s390/sysinfo.c	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.20/drivers/s390/sysinfo.c	2002-10-29 11:18:48.000000000 +0000
@@ -239,106 +239,99 @@
 
 	level = stsi_0 ();
 
-	if (level < 1)
-		goto out;
-	if (stsi_1_1_1 (&info->sysinfo_1_1_1))
-		goto out;
-
-	len += sprintf (page+len, "Manufacturer:         %-16.16s\n",
-			info->sysinfo_1_1_1.manufacturer);
-	len += sprintf (page+len, "Type:                 %-4.4s\n",
-			info->sysinfo_1_1_1.type);
-	len += sprintf (page+len, "Model:                %-16.16s\n",
-			info->sysinfo_1_1_1.model);
-	len += sprintf (page+len, "Sequence Code:        %-16.16s\n",
-			info->sysinfo_1_1_1.sequence);
-	len += sprintf (page+len, "Plant:                %-4.4s\n",
-			info->sysinfo_1_1_1.plant);
-
-	if (stsi_1_2_2 (&info->sysinfo_1_2_2))
-		goto out;
-
-	len += sprintf (page+len, "\n");
-	len += sprintf (page+len, "CPUs Total:           %d\n",
-			info->sysinfo_1_2_2.cpus_total);
-	len += sprintf (page+len, "CPUs Configured:      %d\n",
-			info->sysinfo_1_2_2.cpus_configured);
-	len += sprintf (page+len, "CPUs Standby:         %d\n",
-			info->sysinfo_1_2_2.cpus_standby);
-	len += sprintf (page+len, "CPUs Reserved:        %d\n",
-			info->sysinfo_1_2_2.cpus_reserved);
-
-	len += sprintf (page+len, "Capability:           %d\n",
-			info->sysinfo_1_2_2.capability);
-
-	for (i = 2; i <= info->sysinfo_1_2_2.cpus_total; i++)
-		len += sprintf (page+len, "Adjustment %02d-way:    %d\n",
-				i, info->sysinfo_1_2_2.adjustment[i-2]);
-			
-	if (level < 2)
-		goto out;
-	if (stsi_2_2_2 (&info->sysinfo_2_2_2))
-		goto out;
-
-	len += sprintf (page+len, "\n");
-	len += sprintf (page+len, "LPAR Number:          %d\n",
-			info->sysinfo_2_2_2.lpar_number);
-
-	len += sprintf (page+len, "LPAR Characteristics: ");
-	if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_DEDICATED)
-		len += sprintf (page+len, "Dedicated ");
-	if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_SHARED)
-		len += sprintf (page+len, "Shared ");
-	if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_LIMITED)
-		len += sprintf (page+len, "Limited ");
-	len += sprintf (page+len, "\n");
-
-	len += sprintf (page+len, "LPAR Name:            %-8.8s\n",
-			info->sysinfo_2_2_2.name);
-
-	len += sprintf (page+len, "LPAR Adjustment:      %d\n",
-			info->sysinfo_2_2_2.caf);
-
-	len += sprintf (page+len, "LPAR CPUs Total:      %d\n",
-			info->sysinfo_2_2_2.cpus_total);
-	len += sprintf (page+len, "LPAR CPUs Configured: %d\n",
-			info->sysinfo_2_2_2.cpus_configured);
-	len += sprintf (page+len, "LPAR CPUs Standby:    %d\n",
-			info->sysinfo_2_2_2.cpus_standby);
-	len += sprintf (page+len, "LPAR CPUs Reserved:   %d\n",
-			info->sysinfo_2_2_2.cpus_reserved);
-	len += sprintf (page+len, "LPAR CPUs Dedicated:  %d\n",
-			info->sysinfo_2_2_2.cpus_dedicated);
-	len += sprintf (page+len, "LPAR CPUs Shared:     %d\n",
-			info->sysinfo_2_2_2.cpus_shared);
-
-	if (level < 3)
-		goto out;
-	if (stsi_3_2_2 (&info->sysinfo_3_2_2))
-		goto out;
+	if (level >= 1 && stsi_1_1_1 (&info->sysinfo_1_1_1) == 0)
+	{
+		len += sprintf (page+len, "Manufacturer:         %-16.16s\n",
+				info->sysinfo_1_1_1.manufacturer);
+		len += sprintf (page+len, "Type:                 %-4.4s\n",
+				info->sysinfo_1_1_1.type);
+		len += sprintf (page+len, "Model:                %-16.16s\n",
+				info->sysinfo_1_1_1.model);
+		len += sprintf (page+len, "Sequence Code:        %-16.16s\n",
+				info->sysinfo_1_1_1.sequence);
+		len += sprintf (page+len, "Plant:                %-4.4s\n",
+				info->sysinfo_1_1_1.plant);
+	}
+
+	if (level >= 1 && stsi_1_2_2 (&info->sysinfo_1_2_2) == 0)
+	{
+		len += sprintf (page+len, "\n");
+		len += sprintf (page+len, "CPUs Total:           %d\n",
+				info->sysinfo_1_2_2.cpus_total);
+		len += sprintf (page+len, "CPUs Configured:      %d\n",
+				info->sysinfo_1_2_2.cpus_configured);
+		len += sprintf (page+len, "CPUs Standby:         %d\n",
+				info->sysinfo_1_2_2.cpus_standby);
+		len += sprintf (page+len, "CPUs Reserved:        %d\n",
+				info->sysinfo_1_2_2.cpus_reserved);
+	
+		len += sprintf (page+len, "Capability:           %d\n",
+				info->sysinfo_1_2_2.capability);
+
+		for (i = 2; i <= info->sysinfo_1_2_2.cpus_total; i++)
+			len += sprintf (page+len, "Adjustment %02d-way:    %d\n",
+					i, info->sysinfo_1_2_2.adjustment[i-2]);
+	}
 
-	for (i = 0; i < info->sysinfo_3_2_2.count; i++)
+	if (level >= 2 && stsi_2_2_2 (&info->sysinfo_2_2_2) == 0)
 	{
 		len += sprintf (page+len, "\n");
-		len += sprintf (page+len, "VM%02d Name:            %-8.8s\n",
-				i, info->sysinfo_3_2_2.vm[i].name);
-		len += sprintf (page+len, "VM%02d Control Program: %-16.16s\n",
-				i, info->sysinfo_3_2_2.vm[i].cpi);
-
-		len += sprintf (page+len, "VM%02d Adjustment:      %d\n",
-				i, info->sysinfo_3_2_2.vm[i].caf);
-
-		len += sprintf (page+len, "VM%02d CPUs Total:      %d\n",
-				i, info->sysinfo_3_2_2.vm[i].cpus_total);
-		len += sprintf (page+len, "VM%02d CPUs Configured: %d\n",
-				i, info->sysinfo_3_2_2.vm[i].cpus_configured);
-		len += sprintf (page+len, "VM%02d CPUs Standby:    %d\n",
-				i, info->sysinfo_3_2_2.vm[i].cpus_standby);
-		len += sprintf (page+len, "VM%02d CPUs Reserved:   %d\n",
-				i, info->sysinfo_3_2_2.vm[i].cpus_reserved);
+		len += sprintf (page+len, "LPAR Number:          %d\n",
+				info->sysinfo_2_2_2.lpar_number);
+
+		len += sprintf (page+len, "LPAR Characteristics: ");
+		if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_DEDICATED)
+			len += sprintf (page+len, "Dedicated ");
+		if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_SHARED)
+			len += sprintf (page+len, "Shared ");
+		if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_LIMITED)
+			len += sprintf (page+len, "Limited ");
+		len += sprintf (page+len, "\n");
+	
+		len += sprintf (page+len, "LPAR Name:            %-8.8s\n",
+				info->sysinfo_2_2_2.name);
+	
+		len += sprintf (page+len, "LPAR Adjustment:      %d\n",
+				info->sysinfo_2_2_2.caf);
+	
+		len += sprintf (page+len, "LPAR CPUs Total:      %d\n",
+				info->sysinfo_2_2_2.cpus_total);
+		len += sprintf (page+len, "LPAR CPUs Configured: %d\n",
+				info->sysinfo_2_2_2.cpus_configured);
+		len += sprintf (page+len, "LPAR CPUs Standby:    %d\n",
+				info->sysinfo_2_2_2.cpus_standby);
+		len += sprintf (page+len, "LPAR CPUs Reserved:   %d\n",
+				info->sysinfo_2_2_2.cpus_reserved);
+		len += sprintf (page+len, "LPAR CPUs Dedicated:  %d\n",
+				info->sysinfo_2_2_2.cpus_dedicated);
+		len += sprintf (page+len, "LPAR CPUs Shared:     %d\n",
+				info->sysinfo_2_2_2.cpus_shared);
+	}
+
+	if (level >= 3 && stsi_3_2_2 (&info->sysinfo_3_2_2) == 0)
+	{
+		for (i = 0; i < info->sysinfo_3_2_2.count; i++)
+		{
+			len += sprintf (page+len, "\n");
+			len += sprintf (page+len, "VM%02d Name:            %-8.8s\n",
+					i, info->sysinfo_3_2_2.vm[i].name);
+			len += sprintf (page+len, "VM%02d Control Program: %-16.16s\n",
+					i, info->sysinfo_3_2_2.vm[i].cpi);
+	
+			len += sprintf (page+len, "VM%02d Adjustment:      %d\n",
+					i, info->sysinfo_3_2_2.vm[i].caf);
+	
+			len += sprintf (page+len, "VM%02d CPUs Total:      %d\n",
+					i, info->sysinfo_3_2_2.vm[i].cpus_total);
+			len += sprintf (page+len, "VM%02d CPUs Configured: %d\n",
+					i, info->sysinfo_3_2_2.vm[i].cpus_configured);
+			len += sprintf (page+len, "VM%02d CPUs Standby:    %d\n",
+					i, info->sysinfo_3_2_2.vm[i].cpus_standby);
+			len += sprintf (page+len, "VM%02d CPUs Reserved:   %d\n",
+					i, info->sysinfo_3_2_2.vm[i].cpus_reserved);
+		}
 	}
 
-out:
 	free_page (info_page);
         return len;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sbus/audio/dbri.c linux-2.4.20/drivers/sbus/audio/dbri.c
--- linux-2.4.19/drivers/sbus/audio/dbri.c	2001-10-11 06:42:46.000000000 +0000
+++ linux-2.4.20/drivers/sbus/audio/dbri.c	2002-10-29 11:18:33.000000000 +0000
@@ -17,6 +17,7 @@
  *   - Data sheet of the T7903, a newer but very similar ISA bus equivalent
  *     available from the Lucent (formarly AT&T microelectronics) home
  *     page.
+ *   - http://www.freesoft.org/Linux/DBRI/
  * - MMCODEC: Crystal Semiconductor CS4215 16 bit Multimedia Audio Codec
  *   Interfaces: CHI, Audio In & Out, 2 bits parallel
  *   Documentation: from the Crystal Semiconductor home page.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sbus/char/Config.in linux-2.4.20/drivers/sbus/char/Config.in
--- linux-2.4.19/drivers/sbus/char/Config.in	2000-02-09 02:23:13.000000000 +0000
+++ linux-2.4.20/drivers/sbus/char/Config.in	2002-10-29 11:18:33.000000000 +0000
@@ -2,7 +2,7 @@
 comment 'Misc Linux/SPARC drivers'
 tristate '/dev/openprom device support' CONFIG_SUN_OPENPROMIO
 tristate 'Mostek real time clock support' CONFIG_SUN_MOSTEK_RTC
-if [ "$ARCH" = "sparc64" ]; then
+if [ "$CONFIG_SPARC64" = "y" ]; then
    if [ "$CONFIG_PCI" = "y" ]; then
       tristate 'Siemens SAB82532 serial support' CONFIG_SAB82532
    fi
@@ -14,7 +14,7 @@
    tristate 'Videopix Frame Grabber (EXPERIMENTAL)' CONFIG_SUN_VIDEOPIX
    tristate 'Aurora Multiboard 1600se (EXPERIMENTAL)' CONFIG_SUN_AURORA
 
-   if [ "$ARCH" = "sparc" ]; then
+   if [ "$CONFIG_SPARC32" = "y" ]; then
       tristate 'Tadpole TS102 Microcontroller support (EXPERIMENTAL)' CONFIG_TADPOLE_TS102_UCTRL
 
       tristate 'JavaStation OS Flash SIMM (EXPERIMENTAL)' CONFIG_SUN_JSFLASH
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sbus/char/aurora.c linux-2.4.20/drivers/sbus/char/aurora.c
--- linux-2.4.19/drivers/sbus/char/aurora.c	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.20/drivers/sbus/char/aurora.c	2002-10-29 11:18:33.000000000 +0000
@@ -136,25 +136,25 @@
  */
 
 /* Get board number from pointer */
-extern inline int board_No (struct Aurora_board const * bp)
+static inline int board_No (struct Aurora_board const * bp)
 {
 	return bp - aurora_board;
 }
 
 /* Get port number from pointer */
-extern inline int port_No (struct Aurora_port const * port)
+static inline int port_No (struct Aurora_port const * port)
 {
 	return AURORA_PORT(port - aurora_port); 
 }
 
 /* Get pointer to board from pointer to port */
-extern inline struct Aurora_board * port_Board(struct Aurora_port const * port)
+static inline struct Aurora_board * port_Board(struct Aurora_port const * port)
 {
 	return &aurora_board[AURORA_BOARD(port - aurora_port)];
 }
 
 /* Wait for Channel Command Register ready */
-extern inline void aurora_wait_CCR(struct aurora_reg128 * r)
+static inline void aurora_wait_CCR(struct aurora_reg128 * r)
 {
 	unsigned long delay;
 
@@ -173,7 +173,7 @@
  */
 
 /* Must be called with enabled interrupts */
-extern inline void aurora_long_delay(unsigned long delay)
+static inline void aurora_long_delay(unsigned long delay)
 {
 	unsigned long i;
 
@@ -432,7 +432,7 @@
 	sbus_iounmap((unsigned long)bp->r3, 4);
 }
 
-extern inline void aurora_mark_event(struct Aurora_port * port, int event)
+static inline void aurora_mark_event(struct Aurora_port * port, int event)
 {
 #ifdef AURORA_DEBUG
 	printk("aurora_mark_event: start\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sbus/dvma.c linux-2.4.20/drivers/sbus/dvma.c
--- linux-2.4.19/drivers/sbus/dvma.c	2001-02-09 19:37:03.000000000 +0000
+++ linux-2.4.20/drivers/sbus/dvma.c	2002-10-29 11:18:36.000000000 +0000
@@ -18,7 +18,7 @@
 struct sbus_dma *dma_chain;
 
 /* Print out the current values in the DMA control registers */
-extern __inline__ void dump_dma_regs(unsigned long dregs)
+static inline void dump_dma_regs(unsigned long dregs)
 {
 	printk("DMA CONTROL<%08x> ADDR<%08x> CNT<%08x> TEST<%08x>\n",
 	       sbus_readl(dregs + DMA_CSR), sbus_readl(dregs + DMA_ADDR),
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/3w-xxxx.c linux-2.4.20/drivers/scsi/3w-xxxx.c
--- linux-2.4.19/drivers/scsi/3w-xxxx.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/3w-xxxx.c	2002-10-29 11:18:38.000000000 +0000
@@ -144,6 +144,22 @@
                  Fix bug in raw command post with data ioctl method.
                  Fix bug where rollcall sometimes failed with cable errors.
    1.02.00.025 - Print unit # on all command timeouts.
+   1.02.00.026 - Fix possible infinite retry bug with power glitch induced
+                 drive timeouts.
+                 Cleanup some AEN severity levels.
+   1.02.00.027 - Add drive not supported AEN code for SATA controllers.
+                 Remove spurious unknown ioctl error message.
+   1.02.00.028 - Fix bug where multiple controllers with no units were the
+                 same card number.
+                 Fix bug where cards were being shut down more than once.
+   1.02.00.029 - Add new pci dma mapping for kernel 2.4 for highmem support.
+                 Replace pci_map_single() with pci_map_page() for highmem.
+                 Check for tw_setfeature() failure.
+   1.02.00.030 - Make driver 64-bit clean.
+   1.02.00.031 - Cleanup polling timeouts/routines in several places.
+                 Add support for mode sense opcode.
+                 Add support for cache mode page.
+                 Add support for synchronize cache opcode.
 */
 
 #include <linux/module.h>
@@ -190,6 +206,9 @@
 static void tw_copy_mem_info(TW_Info *info, char *data, int len);
 static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
 static int tw_halt(struct notifier_block *nb, ulong event, void *buf);
+static int tw_map_scsi_sg_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
+static u32 tw_map_scsi_single_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
+static void tw_unmap_scsi_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
 
 /* Notifier block to get a notify on system shutdown/halt/reboot */
 static struct notifier_block tw_notifier = {
@@ -197,7 +216,7 @@
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.025";
+char *tw_driver_version="1.02.00.031";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 
@@ -208,7 +227,7 @@
 {
 	TW_Param *param;
 	unsigned short aen;
-	int error = 0;
+	int error = 0, table_max = 0;
 
 	dprintk(KERN_WARNING "3w-xxxx: tw_aen_complete()\n");
 	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
@@ -223,7 +242,8 @@
 	if (aen == 0x0ff) {
 		printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: INFO: AEN queue overflow.\n", tw_dev->host->host_no);
 	} else {
-		if ((aen & 0x0ff) < TW_AEN_STRING_MAX) {
+		table_max = sizeof(tw_aen_string)/sizeof(char *);
+		if ((aen & 0x0ff) < table_max) {
 			if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
 				printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s%d.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff], aen >> 8);
 			} else {
@@ -272,11 +292,10 @@
 {
 	TW_Command *command_packet;
 	TW_Param *param;
-	int tries = 0;
 	int request_id = 0;
-	u32 command_que_value = 0, command_que_addr;
-	u32 status_reg_value = 0, status_reg_addr;
-	u32 param_value;
+	u32 command_que_addr;
+	unsigned long command_que_value;
+	unsigned long param_value;
 	TW_Response_Queue response_queue;
 	u32 response_que_addr;
 	unsigned short aen;
@@ -284,13 +303,11 @@
 	int finished = 0;
 	int first_reset = 0;
 	int queue = 0;
-	int imax, i;
-	int found = 0;
+	int found = 0, table_max = 0;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue()\n");
 
 	command_que_addr = tw_dev->registers.command_que_addr;
-	status_reg_addr = tw_dev->registers.status_reg_addr;
 	response_que_addr = tw_dev->registers.response_que_addr;
 
 	if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT | TW_STATUS_MICROCONTROLLER_READY, 30)) {
@@ -342,113 +359,95 @@
 	command_packet->byte8.param.sgl[0].address = param_value;
 	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
 
-	imax = TW_POLL_MAX_RETRIES;
-
 	/* Now drain the controller's aen queue */
 	do {
 		/* Post command packet */
 		outl(command_que_value, command_que_addr);
 
 		/* Now poll for completion */
-		for (i=0;i<imax;i++) {
-			mdelay(5);
-			status_reg_value = inl(status_reg_addr);
-			if (tw_check_bits(status_reg_value)) {
-				dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected bits.\n");
-				tw_decode_bits(tw_dev, status_reg_value, 0);
+		if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
+			response_queue.value = inl(response_que_addr);
+			request_id = (unsigned char)response_queue.u.response_id;
+			if (request_id != 0) {
+				/* Unexpected request id */
+				printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected request id.\n");
 				return 1;
 			}
-			if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
-				response_queue.value = inl(response_que_addr);
-				request_id = (unsigned char)response_queue.u.response_id;
-    
-				if (request_id != 0) {
-					/* Unexpected request id */
-					printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected request id.\n");
+	
+			if (command_packet->status != 0) {
+				if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) {
+					/* Bad response */
+					tw_decode_sense(tw_dev, request_id, 0);
 					return 1;
+				} else {
+					/* We know this is a 3w-1x00, and doesn't support aen's */
+					return 0;
 				}
-	
-				if (command_packet->status != 0) {
-					if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) {
-						/* Bad response */
-						tw_decode_sense(tw_dev, request_id, 0);
+			}
+
+			/* Now check the aen */
+			aen = *(unsigned short *)(param->data);
+			aen_code = (aen & 0x0ff);
+			queue = 0;
+			switch (aen_code) {
+				case TW_AEN_QUEUE_EMPTY:
+					dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
+					if (first_reset != 1) {
 						return 1;
 					} else {
-						/* We know this is a 3w-1x00, and doesn't support aen's */
-						return 0;
+						finished = 1;
 					}
-				}
-
-				/* Now check the aen */
-				aen = *(unsigned short *)(param->data);
-				aen_code = (aen & 0x0ff);
-				queue = 0;
-				switch (aen_code) {
-					case TW_AEN_QUEUE_EMPTY:
-						dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
-						if (first_reset != 1) {
-							continue;
-						} else {
-							finished = 1;
-						}
-						break;
-					case TW_AEN_SOFT_RESET:
-						if (first_reset == 0) {
-							first_reset = 1;
-						} else {
-							printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
-							tw_dev->aen_count++;
-							queue = 1;
-						}
-						break;
-					default:
-						if (aen == 0x0ff) {
-							printk(KERN_WARNING "3w-xxxx: AEN: INFO: AEN queue overflow.\n");
-						} else {
-							if ((aen & 0x0ff) < TW_AEN_STRING_MAX) {
-								if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
-									printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8);
-								} else {
-									printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
-								}
-							} else
-								printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen);
-						}
+					break;
+				case TW_AEN_SOFT_RESET:
+					if (first_reset == 0) {
+						first_reset = 1;
+					} else {
+						printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
 						tw_dev->aen_count++;
 						queue = 1;
-				}
-
-				/* Now put the aen on the aen_queue */
-				if (queue == 1) {
-					tw_dev->aen_queue[tw_dev->aen_tail] = aen;
-					if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
-						tw_dev->aen_tail = TW_Q_START;
+					}
+					break;
+				default:
+					if (aen == 0x0ff) {
+						printk(KERN_WARNING "3w-xxxx: AEN: INFO: AEN queue overflow.\n");
 					} else {
-						tw_dev->aen_tail = tw_dev->aen_tail + 1;
+						table_max = sizeof(tw_aen_string)/sizeof(char *);
+						if ((aen & 0x0ff) < table_max) {
+							if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
+								printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8);
+							} else {
+								printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
+							}
+						} else
+							printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen);
 					}
-					if (tw_dev->aen_head == tw_dev->aen_tail) {
-						if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
-							tw_dev->aen_head = TW_Q_START;
-						} else {
-							tw_dev->aen_head = tw_dev->aen_head + 1;
-						}
+					tw_dev->aen_count++;
+					queue = 1;
+			}
+
+			/* Now put the aen on the aen_queue */
+			if (queue == 1) {
+				tw_dev->aen_queue[tw_dev->aen_tail] = aen;
+				if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
+					tw_dev->aen_tail = TW_Q_START;
+				} else {
+					tw_dev->aen_tail = tw_dev->aen_tail + 1;
+				}
+				if (tw_dev->aen_head == tw_dev->aen_tail) {
+					if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
+						tw_dev->aen_head = TW_Q_START;
+					} else {
+						tw_dev->aen_head = tw_dev->aen_head + 1;
 					}
 				}
-				found = 1;
-				break;
 			}
+			found = 1;
 		}
 		if (found == 0) {
 			printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Response never received.\n");
 			return 1;
 		}
-		tries++;
-	} while ((tries < TW_MAX_AEN_TRIES) && (finished == 0));
-
-	if (tries >=TW_MAX_AEN_TRIES) {
-		printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Aen queue error.\n");
-		return 1;
-	}
+	} while (finished == 0);
 
 	return 0;
 } /* End tw_aen_drain_queue() */
@@ -458,9 +457,10 @@
 {
 	TW_Command *command_packet;
 	TW_Param *param;
-	u32 command_que_value = 0, command_que_addr;
+	u32 command_que_addr;
+	unsigned long command_que_value;
 	u32 status_reg_value = 0, status_reg_addr;
-	u32 param_value = 0;
+	unsigned long param_value = 0;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_aen_read_queue()\n");
 	command_que_addr = tw_dev->registers.command_que_addr;
@@ -525,39 +525,55 @@
 } /* End tw_aen_read_queue() */
 
 /* This function will allocate memory and check if it is 16 d-word aligned */
-int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which)
+int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
 {
-	u32 *virt_addr = kmalloc(size, GFP_ATOMIC);
+	int i, imax;
+	dma_addr_t dma_handle;
+	unsigned long *cpu_addr = NULL;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n");
 
-	if (!virt_addr) {
-		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() failed.\n");
-		return 1;
-	}
 
-	if ((u32)virt_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {
-		kfree(virt_addr);
-		printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");
-		return 1;
-	}
+	if (which == 2)
+		imax = TW_MAX_BOUNCEBUF;
+	else
+		imax = TW_Q_LENGTH;
 
-	switch(which) {
-	case 0:
-		tw_dev->command_packet_virtual_address[request_id] = virt_addr;
-		tw_dev->command_packet_physical_address[request_id] = virt_to_bus(virt_addr);
-		break;
-	case 1:
-		tw_dev->alignment_virtual_address[request_id] = virt_addr;
-		tw_dev->alignment_physical_address[request_id] = virt_to_bus(virt_addr);
-		break;
-	case 2:
-		tw_dev->bounce_buffer[request_id] = virt_addr;
-		break;
-	default:
-		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
-		return 1;
+	for (i=0;i<imax;i++) {
+		cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size, &dma_handle);
+		if (cpu_addr == NULL) {
+			printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n");
+			return 1;
+		}
+
+		if ((unsigned long)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {
+			printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");
+			pci_free_consistent(tw_dev->tw_pci_dev, size, cpu_addr, dma_handle);
+			return 1;
+		}
+
+		switch(which) {
+		case 0:
+			tw_dev->command_packet_virtual_address[i] = cpu_addr;
+			tw_dev->command_packet_physical_address[i] = dma_handle;
+			memset(tw_dev->command_packet_virtual_address[i], 0, size);
+			break;
+		case 1:
+			tw_dev->alignment_virtual_address[i] = cpu_addr;
+			tw_dev->alignment_physical_address[i] = dma_handle;
+			memset(tw_dev->alignment_virtual_address[i], 0, size);
+			break;
+		case 2:
+			tw_dev->bounce_buffer[i] = cpu_addr;
+			tw_dev->bounce_buffer_phys[i] = dma_handle;
+			memset(tw_dev->bounce_buffer[i], 0, size);
+			break;
+		default:
+			printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
+			return 1;
+		}
 	}
+
 	return 0;
 } /* End tw_allocate_memory() */
 
@@ -802,19 +818,29 @@
 	struct pci_dev *tw_pci_dev = NULL;
 	u32 status_reg_value;
 	unsigned char c = 1;
-	int i;
+	int i, j = -1;
 	u16 device[TW_NUMDEVICES] = { TW_DEVICE_ID, TW_DEVICE_ID2 };
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_findcards()\n");
 
 	for (i=0;i<TW_NUMDEVICES;i++) {
 		while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, device[i], tw_pci_dev))) {
+			j++;
 			if (pci_enable_device(tw_pci_dev))
 				continue;
+
+			/* We only need 32-bit addressing for 5,6,7xxx cards */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)
+			if (pci_set_dma_mask(tw_pci_dev, 0xffffffff)) {
+				printk(KERN_WARNING "3w-xxxx: No suitable DMA available.\n");
+				continue;
+			}
+#endif
+
 			/* Prepare temporary device extension */
 			tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC);
 			if (tw_dev == NULL) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for card %d.\n", j);
 				continue;
 			}
 			memset(tw_dev, 0, sizeof(TW_Device_Extension));
@@ -824,7 +850,7 @@
 
 			error = tw_initialize_device_extension(tw_dev);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", j);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
 				continue;
@@ -844,7 +870,7 @@
 			
 			/* Poll status register for 60 secs for 'Controller Ready' flag */
 			if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", j);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
 				continue;
@@ -859,14 +885,14 @@
 
 				error = tw_aen_drain_queue(tw_dev);
 				if (error) {
-					printk(KERN_WARNING "3w-xxxx: AEN drain failed for card %d.\n", numcards);
+					printk(KERN_WARNING "3w-xxxx: AEN drain failed for card %d.\n", j);
 					tries++;
 					continue;
 				}
 
 				/* Check for controller errors */
 				if (tw_check_errors(tw_dev)) {
-					printk(KERN_WARNING "3w-xxxx: Controller errors found, retrying for card %d.\n", numcards);
+					printk(KERN_WARNING "3w-xxxx: Controller errors found, retrying for card %d.\n", j);
 					tries++;
 					continue;
 				}
@@ -876,7 +902,7 @@
 			}
 
 			if (tries >= TW_MAX_RESET_TRIES) {
-				printk(KERN_WARNING "3w-xxxx: Controller errors, card not responding, check all cabling for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: Controller errors, card not responding, check all cabling for card %d.\n", j);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
 				continue;
@@ -887,7 +913,7 @@
 				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", 
 				       (tw_dev->tw_pci_dev->resource[0].start), 
 				       (tw_dev->tw_pci_dev->resource[0].start) + 
-				       TW_IO_ADDRESS_RANGE, numcards);
+				       TW_IO_ADDRESS_RANGE, j);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
 				continue;
@@ -897,7 +923,7 @@
 			request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME);
 			error = tw_initialize_units(tw_dev);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: No valid units for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: No valid units for card %d.\n", j);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
@@ -906,13 +932,16 @@
 
 			error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: Connection initialization failed for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: Connection initialization failed for card %d.\n", j);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
 				continue;
 			}
 
+			/* Set card status as online */
+			tw_dev->online = 1;
+
 			/* Calculate max cmds per lun, and setup queues */
 			if (tw_dev->num_units > 0) {
 				if ((tw_dev->num_raid_five > 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
@@ -931,7 +960,7 @@
 		/* Register the card with the kernel SCSI layer */
 			host = scsi_register(tw_host, sizeof(TW_Device_Extension));
 			if (host == NULL) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", j);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
@@ -973,7 +1002,7 @@
 				tw_device_extension_count = numcards;
 				tw_dev2->host = host;
 			} else { 
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", j);
 				scsi_unregister(host);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
@@ -982,12 +1011,21 @@
 			}
 
 			/* Tell the firmware we support shutdown notification*/
-			tw_setfeature(tw_dev2, 2, 1, &c);
+			error = tw_setfeature(tw_dev2, 2, 1, &c);
+			if (error) {
+				printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Error setting features for card %d.\n", j);
+				scsi_unregister(host);
+				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				numcards--;
+				continue;
+			}
 
 			/* Now setup the interrupt handler */
 			error = tw_setup_irq(tw_dev2);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", numcards-1);
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", j);
 				scsi_unregister(host);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 
@@ -1022,16 +1060,16 @@
 	dprintk(KERN_NOTICE "3w-xxxx: tw_free_device_extension()\n");
 	/* Free command packet and generic buffer memory */
 	for (i=0;i<TW_Q_LENGTH;i++) {
-		if (tw_dev->command_packet_virtual_address[i]) 
-			kfree(tw_dev->command_packet_virtual_address[i]);
+		if (tw_dev->command_packet_virtual_address[i])
+			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector), tw_dev->command_packet_virtual_address[i], tw_dev->command_packet_physical_address[i]);
 
 		if (tw_dev->alignment_virtual_address[i])
-			kfree(tw_dev->alignment_virtual_address[i]);
+			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector), tw_dev->alignment_virtual_address[i], tw_dev->alignment_physical_address[i]);
 
 	}
 	for (i=0;i<TW_MAX_BOUNCEBUF;i++) {
 		if (tw_dev->bounce_buffer[i])
-			kfree(tw_dev->bounce_buffer[i]);
+			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector)*TW_MAX_BOUNCE_SECTORS, tw_dev->bounce_buffer[i], tw_dev->bounce_buffer_phys[i]);
 	}
 } /* End tw_free_device_extension() */
 
@@ -1041,8 +1079,11 @@
 	int i;
 
 	for (i=0;i<tw_device_extension_count;i++) {
-		printk(KERN_NOTICE "3w-xxxx: Shutting down card %d.\n", i);
-		tw_shutdown_device(tw_device_extension_list[i]);
+		if (tw_device_extension_list[i]->online == 1) {
+			printk(KERN_NOTICE "3w-xxxx: Shutting down card %d.\n", i);
+			tw_shutdown_device(tw_device_extension_list[i]);
+			tw_device_extension_list[i]->online = 0;
+		}
 	}
 	unregister_reboot_notifier(&tw_notifier);
 
@@ -1052,18 +1093,15 @@
 /* This function will send an initconnection command to controller */
 int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits) 
 {
-	u32 command_que_addr, command_que_value;
-	u32 status_reg_addr, status_reg_value;
+	unsigned long command_que_value;
+	u32 command_que_addr;
 	u32 response_que_addr;
 	TW_Command  *command_packet;
 	TW_Response_Queue response_queue;
 	int request_id = 0;
-	int i = 0;
-	int imax = 0;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_initconnection()\n");
 	command_que_addr = tw_dev->registers.command_que_addr;
-	status_reg_addr = tw_dev->registers.status_reg_addr;
 	response_que_addr = tw_dev->registers.response_que_addr;
 
 	/* Initialize InitConnection command packet */
@@ -1095,29 +1133,18 @@
 	outl(command_que_value, command_que_addr);
     
 	/* Poll for completion */
-	imax = TW_POLL_MAX_RETRIES;
-	for (i=0;i<imax;i++) {
-		mdelay(5);
-		status_reg_value = inl(status_reg_addr);
-		if (tw_check_bits(status_reg_value)) {
-			dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected bits.\n");
-			tw_decode_bits(tw_dev, status_reg_value, 0);
+	if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
+		response_queue.value = inl(response_que_addr);
+		request_id = (unsigned char)response_queue.u.response_id;
+		if (request_id != 0) {
+			/* unexpected request id */
+			printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected request id.\n");
 			return 1;
 		}
-		if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
-			response_queue.value = inl(response_que_addr);
-			request_id = (unsigned char)response_queue.u.response_id;
-			if (request_id != 0) {
-				/* unexpected request id */
-				printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected request id.\n");
-				return 1;
-			}
-			if (command_packet->status != 0) {
-				/* bad response */
-				tw_decode_sense(tw_dev, request_id, 0);
-				return 1;
-			}
-			break;	/* Response was okay, so we exit */
+		if (command_packet->status != 0) {
+			/* bad response */
+			tw_decode_sense(tw_dev, request_id, 0);
+			return 1;
 		}
 	}
 	return 0;
@@ -1126,27 +1153,25 @@
 /* This function will initialize the fields of a device extension */
 int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
 {
-	int i;
+	int i, error = 0;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n");
 
-	for (i=0;i<TW_Q_LENGTH;i++) {
-		/* Initialize command packet buffers */
-		tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 0);
-		if (tw_dev->command_packet_virtual_address[i] == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): Bad command packet virtual address.\n");
-			return 1;
-		}
-		memset(tw_dev->command_packet_virtual_address[i], 0, sizeof(TW_Sector));
-    
-		/* Initialize generic buffer */
-		tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 1);
-		if (tw_dev->alignment_virtual_address[i] == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): Bad alignment virtual address.\n");
-			return 1;
-		}
-		memset(tw_dev->alignment_virtual_address[i], 0, sizeof(TW_Sector));
+	/* Initialize command packet buffers */
+	error = tw_allocate_memory(tw_dev, sizeof(TW_Command), 0);
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: Command packet memory allocation failed.\n");
+		return 1;
+	}
 
+	/* Initialize generic buffer */
+	error = tw_allocate_memory(tw_dev, sizeof(TW_Sector), 1);
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: Generic memory allocation failed.\n");
+		return 1;
+	}
+	
+	for (i=0;i<TW_Q_LENGTH;i++) {
 		tw_dev->free_queue[i] = i;
 		tw_dev->state[i] = TW_S_INITIAL;
 	}
@@ -1161,22 +1186,21 @@
 /* This function will get unit info from the controller */
 int tw_initialize_units(TW_Device_Extension *tw_dev) 
 {
-	int found = 0;
+	int found = 0, error = 0;
 	unsigned char request_id = 0;
 	TW_Command *command_packet;
 	TW_Param *param;
 	int i, j, imax, num_units = 0, num_raid_five = 0;
-	u32 status_reg_addr, status_reg_value;
-	u32 command_que_addr, command_que_value;
+	unsigned long command_que_value;
+	u32 command_que_addr;
 	u32 response_que_addr;
 	TW_Response_Queue response_queue;
-	u32 param_value;
+	unsigned long param_value;
 	unsigned char *is_unit_present;
 	unsigned char *raid_level;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units()\n");
 
-	status_reg_addr = tw_dev->registers.status_reg_addr;
 	command_que_addr = tw_dev->registers.command_que_addr;
 	response_que_addr = tw_dev->registers.response_que_addr;
   
@@ -1225,31 +1249,20 @@
 	outl(command_que_value, command_que_addr);
 
 	/* Poll for completion */
-	imax = TW_POLL_MAX_RETRIES;
-	for(i=0; i<imax; i++) {
-		mdelay(5);
-		status_reg_value = inl(status_reg_addr);
-		if (tw_check_bits(status_reg_value)) {
-			dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
-			tw_decode_bits(tw_dev, status_reg_value, 0);
+	if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
+		response_queue.value = inl(response_que_addr);
+		request_id = (unsigned char)response_queue.u.response_id;
+		if (request_id != 0) {
+			/* unexpected request id */
+			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n");
 			return 1;
 		}
-		if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
-			response_queue.value = inl(response_que_addr);
-			request_id = (unsigned char)response_queue.u.response_id;
-			if (request_id != 0) {
-				/* unexpected request id */
-				printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n");
-				return 1;
-			}
-			if (command_packet->status != 0) {
-				/* bad response */
-				tw_decode_sense(tw_dev, request_id, 0);
-				return 1;
-			}
-			found = 1;
-			break;
+		if (command_packet->status != 0) {
+			/* bad response */
+			tw_decode_sense(tw_dev, request_id, 0);
+			return 1;
 		}
+		found = 1;
 	}
 	if (found == 0) {
 		/* response never received */
@@ -1328,31 +1341,20 @@
 		outl(command_que_value, command_que_addr);
 
 		/* Poll for completion */
-		imax = TW_POLL_MAX_RETRIES;
-		for(i=0; i<imax; i++) {
-			mdelay(5);
-			status_reg_value = inl(status_reg_addr);
-			if (tw_check_bits(status_reg_value)) {
-				dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
-				tw_decode_bits(tw_dev, status_reg_value, 0);
+		if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
+			response_queue.value = inl(response_que_addr);
+			request_id = (unsigned char)response_queue.u.response_id;
+			if (request_id != 0) {
+				/* unexpected request id */
+				printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n");
 				return 1;
 			}
-			if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
-				response_queue.value = inl(response_que_addr);
-				request_id = (unsigned char)response_queue.u.response_id;
-				if (request_id != 0) {
-					/* unexpected request id */
-					printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n");
-					return 1;
-				}
-				if (command_packet->status != 0) {
-					/* bad response */
-					tw_decode_sense(tw_dev, request_id, 0);
-					return 1;
-				}
-				found = 1;
-				break;
+			if (command_packet->status != 0) {
+				/* bad response */
+				tw_decode_sense(tw_dev, request_id, 0);
+				return 1;
 			}
+			found = 1;
 		}
 		if (found == 0) {
 			/* response never received */
@@ -1372,13 +1374,10 @@
 
 	/* Now allocate raid5 bounce buffers */
 	if ((num_raid_five != 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
-		for (i=0;i<TW_MAX_BOUNCEBUF;i++) {
-			tw_allocate_memory(tw_dev, i, sizeof(TW_Sector)*TW_MAX_BOUNCE_SECTORS, 2);
-			if (tw_dev->bounce_buffer[i] == NULL) {
-				printk(KERN_WARNING "3w-xxxx: Bounce buffer allocation failed.\n");
-				return 1;
-			}
-			memset(tw_dev->bounce_buffer[i], 0, sizeof(TW_Sector)*TW_MAX_BOUNCE_SECTORS);
+		error = tw_allocate_memory(tw_dev, sizeof(TW_Sector)*TW_MAX_BOUNCE_SECTORS, 2);
+		if (error) {
+			printk(KERN_WARNING "3w-xxxx: Bounce buffer allocation failed.\n");
+			return 1;
 		}
 	}
   
@@ -1533,6 +1532,13 @@
 						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_CAPACITY\n");
 						error = tw_scsiop_read_capacity_complete(tw_dev, request_id);
 						break;
+					case MODE_SENSE:
+						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught MODE_SENSE\n");
+						error = tw_scsiop_mode_sense_complete(tw_dev, request_id);
+						break;
+					case SYNCHRONIZE_CACHE:
+						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught SYNCHRONIZE_CACHE\n");
+						break;
 					case TW_IOCTL:
 						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TW_IOCTL\n");
 						error = tw_ioctl_complete(tw_dev, request_id);
@@ -1549,7 +1555,8 @@
 
 					/* If error, command failed */
 					if (error == 1) {
-						tw_dev->srb[request_id]->result = (DID_RESET << 16);
+						/* Ask for a host reset */
+						tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
 					}
 					
 					/* Now complete the io */
@@ -1558,6 +1565,7 @@
 						tw_state_request_finish(tw_dev, request_id);
 						tw_dev->posted_request_count--;
 						tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+						tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
 					}
 				}
 
@@ -1588,12 +1596,13 @@
 	int bufflen, error = 0;
 	TW_Param *param;
 	TW_Command *command_packet, *command_save;
-	u32 param_value;
+	unsigned long param_value;
 	TW_Ioctl *ioctl = NULL;
 	TW_Passthru *passthru = NULL;
 	int tw_aen_code, i, use_sg;
-	char *data_ptr;
+	unsigned long *data_ptr;
 	int total_bytes = 0, posted = 0;
+	dma_addr_t dma_handle;
 	struct timeval before, timeout;
 
 	ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
@@ -1698,10 +1707,10 @@
 			passthru = (TW_Passthru *)tw_dev->command_packet_virtual_address[request_id];
 			passthru->sg_list[0].length = passthru->sector_count*512;
 			if (passthru->sg_list[0].length > TW_MAX_PASSTHRU_BYTES) {
-				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%ld) too big.\n", passthru->sg_list[0].length);
+				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%d) too big.\n", passthru->sg_list[0].length);
 				return 1;
 			}
-			passthru->sg_list[0].address = virt_to_bus(tw_dev->alignment_virtual_address[request_id]);
+			passthru->sg_list[0].address = tw_dev->alignment_physical_address[request_id];
 			tw_post_command_packet(tw_dev, request_id);
 			return 0;
 		case TW_CMD_PACKET:
@@ -1733,17 +1742,18 @@
 					use_sg = command_packet->size - 3;
 					for (i=0;i<use_sg;i++)
 						total_bytes+=command_packet->byte8.param.sgl[i].length;
-					tw_dev->ioctl_data[request_id] = kmalloc(total_bytes, GFP_ATOMIC);
+					tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle);
+
 					if (!tw_dev->ioctl_data[request_id]) {
-						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): kmalloc failed for request_id %d.\n", tw_dev->host->host_no, request_id);
+						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): pci_alloc_consistent() failed for request_id %d.\n", tw_dev->host->host_no, request_id);
 						return 1;
 					}
 
 					/* Copy param sglist into the kernel */
 					data_ptr = tw_dev->ioctl_data[request_id];
 					for (i=0;i<use_sg;i++) {
-						if ((u32 *)command_packet->byte8.param.sgl[i].address != NULL) {
-							error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length);
+						if (command_packet->byte8.param.sgl[i].address != 0) {
+							error = copy_from_user(data_ptr, (void *)(unsigned long)command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length);
 							if (error) {
 								dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist from userspace.\n", tw_dev->host->host_no);
 								goto tw_ioctl_bail;
@@ -1756,24 +1766,25 @@
 						data_ptr+=command_packet->byte8.param.sgl[i].length;
 					}
 					command_packet->size = 4;
-					command_packet->byte8.param.sgl[0].address = virt_to_bus(tw_dev->ioctl_data[request_id]);
+					command_packet->byte8.param.sgl[0].address = dma_handle;
 					command_packet->byte8.param.sgl[0].length = total_bytes;
 				}
 				if (command_packet->byte0.sgl_offset == 3) {
 					use_sg = command_packet->size - 4;
 					for (i=0;i<use_sg;i++)
 						total_bytes+=command_packet->byte8.io.sgl[i].length;
-					tw_dev->ioctl_data[request_id] = kmalloc(total_bytes, GFP_ATOMIC);
+					tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle);
+
 					if (!tw_dev->ioctl_data[request_id]) {
-						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): kmalloc failed for request_id %d.\n", tw_dev->host->host_no, request_id);
+						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): pci_alloc_consistent() failed for request_id %d.\n", tw_dev->host->host_no, request_id);
 						return 1;
 					}
 					if (command_packet->byte0.opcode == TW_OP_WRITE) {
 						/* Copy io sglist into the kernel */
 						data_ptr = tw_dev->ioctl_data[request_id];
 						for (i=0;i<use_sg;i++) {
-							if ((u32 *)command_packet->byte8.io.sgl[i].address != NULL) {
-								error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length);
+							if (command_packet->byte8.io.sgl[i].address != 0) {
+								error = copy_from_user(data_ptr, (void *)(unsigned long)command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length);
 								if (error) {
 									dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist from userspace.\n", tw_dev->host->host_no);
 									goto tw_ioctl_bail;
@@ -1787,7 +1798,7 @@
 						}
 					}
 					command_packet->size = 5;
-					command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->ioctl_data[request_id]);
+					command_packet->byte8.io.sgl[0].address = dma_handle;
 					command_packet->byte8.io.sgl[0].length = total_bytes;
 				}
 
@@ -1827,10 +1838,10 @@
 				/* Now copy up the param or io sglist to userspace */
 				if (command_packet->byte0.sgl_offset == 2) {
 					use_sg = command_save->size - 3;
-					data_ptr = phys_to_virt(command_packet->byte8.param.sgl[0].address);
+					data_ptr = tw_dev->ioctl_data[request_id];
 					for (i=0;i<use_sg;i++) {
-						if ((u32 *)command_save->byte8.param.sgl[i].address != NULL) {
-							error = copy_to_user((u32 *)command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length);
+						if (command_save->byte8.param.sgl[i].address != 0) {
+							error = copy_to_user((void *)(unsigned long)command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length);
 							if (error) {
 								dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist to userspace.\n", tw_dev->host->host_no);
 								goto tw_ioctl_bail;
@@ -1847,10 +1858,10 @@
 				if (command_packet->byte0.sgl_offset == 3) {
 					use_sg = command_save->size - 4;
 					if (command_packet->byte0.opcode == TW_OP_READ) {
-						data_ptr = phys_to_virt(command_packet->byte8.io.sgl[0].address);
+						data_ptr = tw_dev->ioctl_data[request_id];
 						for(i=0;i<use_sg;i++) {
-							if ((u32 *)command_save->byte8.io.sgl[i].address != NULL) {
-								error = copy_to_user((u32 *)command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length);
+							if (command_save->byte8.io.sgl[i].address != 0) {
+								error = copy_to_user((void *)(unsigned long)command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length);
 								if (error) {
 									dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist to userspace.\n", tw_dev->host->host_no);
 									goto tw_ioctl_bail;
@@ -1870,7 +1881,7 @@
 
 				/* Free up sglist memory */
 				if (tw_dev->ioctl_data[request_id])
-					kfree(tw_dev->ioctl_data[request_id]);
+					pci_free_consistent(tw_dev->tw_pci_dev, total_bytes, tw_dev->ioctl_data[request_id], dma_handle);
 				else
 					printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Error freeing ioctl data.\n", tw_dev->host->host_no);
 				
@@ -1886,7 +1897,7 @@
 				return 1;
 			}
 		default:
-			printk(KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n", opcode);
+			dprintk(KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n", opcode);
 			tw_dev->state[request_id] = TW_S_COMPLETED;
 			tw_state_request_finish(tw_dev, request_id);
 			tw_dev->srb[request_id]->result = (DID_OK << 16);
@@ -1969,6 +1980,55 @@
 	return 0;
 } /* End tw_ioctl_complete() */
 
+static int tw_map_scsi_sg_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
+{
+	int use_sg;
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
+	
+	if (cmd->use_sg == 0)
+		return 0;
+
+	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+
+	if (use_sg == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n");
+		return 0;
+	}
+
+	cmd->SCp.phase = 2;
+	cmd->SCp.have_data_in = use_sg;
+
+	return use_sg;
+} /* End tw_map_scsi_sg_data() */
+
+static u32 tw_map_scsi_single_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
+{
+	dma_addr_t mapping;
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n");
+	
+	if (cmd->request_bufflen == 0)
+		return 0;
+#ifdef BLK_BOUNCE_HIGH
+	mapping = pci_map_page(pdev, virt_to_page(cmd->request_buffer), ((unsigned long)cmd->request_buffer & ~PAGE_MASK), cmd->request_bufflen, dma_dir);
+#else
+	mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, dma_dir);
+#endif
+
+	if (mapping == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data(): pci_map_page() failed.\n");
+		return 0;
+	}
+
+	cmd->SCp.phase = 1;
+	cmd->SCp.have_data_in = mapping;
+
+	return mapping;
+} /* End tw_map_scsi_single_data() */
+
 /* This function will mask the command interrupt */
 void tw_mask_command_interrupt(TW_Device_Extension *tw_dev)
 {
@@ -2012,11 +2072,45 @@
 	return 0;
 } /* End tw_poll_status() */
 
+/* This function will poll the status register for disappearance of a flag */
+int tw_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds)
+{
+        u32 status_reg_addr, status_reg_value;
+        struct timeval before, timeout;
+
+        status_reg_addr = tw_dev->registers.status_reg_addr;
+        do_gettimeofday(&before);
+        status_reg_value = inl(status_reg_addr);
+
+	if (tw_check_bits(status_reg_value)) {
+		dprintk(KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Unexpected bits.\n");
+		tw_decode_bits(tw_dev, status_reg_value, 0);
+	}
+
+        while ((status_reg_value & flag) != 0) {
+                status_reg_value = inl(status_reg_addr);
+
+		if (tw_check_bits(status_reg_value)) {
+			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Unexpected bits.\n");
+			tw_decode_bits(tw_dev, status_reg_value, 0);
+		}
+
+                do_gettimeofday(&timeout);
+                if (before.tv_sec + seconds < timeout.tv_sec) {
+			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Flag 0x%x never disappeared.\n", flag);
+                        return 1;
+                }
+                mdelay(5);
+        }
+        return 0;
+} /* End tw_poll_status_gone() */
+
 /* This function will attempt to post a command packet to the board */
 int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id)
 {
 	u32 status_reg_addr, status_reg_value;
-	u32 command_que_addr, command_que_value;
+	unsigned long command_que_value;
+	u32 command_que_addr;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_post_command_packet()\n");
 	command_que_addr = tw_dev->registers.command_que_addr;
@@ -2082,6 +2176,7 @@
 			if (srb != NULL) {
 				srb->result = (DID_RESET << 16);
 				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+				tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
 			}
 		}
 	}
@@ -2225,14 +2320,14 @@
 	for (i=0;i<TW_Q_LENGTH;i++) {
 		if (tw_dev->srb[i] == SCpnt) {
 			if (tw_dev->state[i] == TW_S_STARTED) {
-				printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (0x%x) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, (u32)SCpnt);
+				printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, SCpnt);
 				tw_dev->state[i] = TW_S_COMPLETED;
 				tw_state_request_finish(tw_dev, i);
 				spin_unlock(&tw_dev->tw_lock);
 				return (SUCCESS);
 			}
 			if (tw_dev->state[i] == TW_S_PENDING) {
-				printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (0x%x) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, (u32)SCpnt);
+				printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, SCpnt);
 				if (tw_dev->pending_head == TW_Q_LENGTH-1) {
 					tw_dev->pending_head = TW_Q_START;
 				} else {
@@ -2246,7 +2341,7 @@
 			}
 			if (tw_dev->state[i] == TW_S_POSTED) {
 				/* If the command has already been posted, we have to reset the card */
-				printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, (u32)SCpnt);
+				printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out, resetting card.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, SCpnt);
 				/* We have to let AEN requests through before the reset */
 				spin_unlock(&tw_dev->tw_lock);
 				spin_unlock_irq(&io_request_lock);
@@ -2339,9 +2434,9 @@
 					printk(KERN_INFO "3w-xxxx: Request_id: %d\n", j);
 					printk(KERN_INFO "Opcode: 0x%x\n", command->byte0.opcode);
 					printk(KERN_INFO "Block_count: 0x%x\n", command->byte6.block_count);
-					printk(KERN_INFO "LBA: 0x%x\n", (u32)command->byte8.io.lba);
-					printk(KERN_INFO "Physical command packet addr: 0x%x\n", tw_dev->command_packet_physical_address[j]);
-					printk(KERN_INFO "Scsi_Cmnd: 0x%x\n", (u32)tw_dev->srb[j]);
+					printk(KERN_INFO "LBA: 0x%x\n", command->byte8.io.lba);
+					printk(KERN_INFO "Physical command packet addr: 0x%lx\n", tw_dev->command_packet_physical_address[j]);
+					printk(KERN_INFO "Scsi_Cmnd: %p\n", tw_dev->srb[j]);
 				}
 			}
 			printk(KERN_INFO "3w-xxxx: Free_head: %3d\n", tw_dev->free_head);
@@ -2434,6 +2529,14 @@
 		        dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught REQUEST_SENSE.\n");
 		        error = tw_scsiop_request_sense(tw_dev, request_id);
 		        break;
+		case MODE_SENSE:
+			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught MODE_SENSE.\n");
+			error = tw_scsiop_mode_sense(tw_dev, request_id);
+			break;
+		case SYNCHRONIZE_CACHE:
+			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught SYNCHRONIZE_CACHE.\n");
+			error = tw_scsiop_synchronize_cache(tw_dev, request_id);
+			break;
 		case TW_IOCTL:
 			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TW_SCSI_IOCTL.\n");
 			error = tw_ioctl(tw_dev, request_id);
@@ -2489,8 +2592,9 @@
 {
 	TW_Param *param;
 	TW_Command *command_packet;
-	u32 command_que_value, command_que_addr;
-	u32 param_value;
+	unsigned long command_que_value;
+	u32 command_que_addr;
+	unsigned long param_value;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry()\n");
 
@@ -2588,13 +2692,115 @@
 	return 0;
 } /* End tw_scsiop_inquiry_complete() */
 
+/* This function handles scsi mode_sense commands */
+int tw_scsiop_mode_sense(TW_Device_Extension *tw_dev, int request_id)
+{
+	TW_Param *param;
+	TW_Command *command_packet;
+	unsigned long command_que_value;
+	unsigned long param_value;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense()\n");
+
+	/* Only page control = 0, page code = 0x8 (cache page) supported */
+	if (tw_dev->srb[request_id]->cmnd[2] != 0x8) {
+		tw_dev->state[request_id] = TW_S_COMPLETED;
+		tw_state_request_finish(tw_dev, request_id);
+		tw_dev->srb[request_id]->result = (DID_OK << 16);
+		tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+		return 0;
+	}
+
+	/* Now read firmware cache setting for this unit */
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet virtual address.\n");
+		return 1;
+	}
+
+	/* Setup the command packet */
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->byte0.opcode = TW_OP_GET_PARAM;
+	command_packet->byte0.sgl_offset = 2;
+	command_packet->size = 4;
+	command_packet->request_id = request_id;
+	command_packet->byte3.unit = 0;
+	command_packet->byte3.host_id = 0;
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.parameter_count = 1;
+
+	/* Setup the param */
+	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment virtual address.\n");
+		return 1;
+	}
+
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	memset(param, 0, sizeof(TW_Sector));
+	param->table_id = TW_UNIT_INFORMATION_TABLE_BASE + tw_dev->srb[request_id]->target;
+	param->parameter_id = 7; /* unit flags */
+	param->parameter_size_bytes = 1;
+	param_value = tw_dev->alignment_physical_address[request_id];
+	if (param_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment physical address.\n");
+		return 1;
+	}
+
+	command_packet->byte8.param.sgl[0].address = param_value;
+	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet physical address.\n");
+		return 1;
+	}
+
+	/* Now try to post the command packet */
+	tw_post_command_packet(tw_dev, request_id);
+
+	return 0;
+} /* End tw_scsiop_mode_sense() */
+
+/* This function is called by the isr to complete a mode sense command */
+int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+	TW_Param *param;
+	unsigned char *flags;
+	unsigned char *request_buffer;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense_complete()\n");
+
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	if (param == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense_complete(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	flags = (char *)&(param->data[0]);
+	request_buffer = tw_dev->srb[request_id]->buffer;
+	memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+
+	request_buffer[0] = 0xf;        /* mode data length */
+	request_buffer[1] = 0;          /* default medium type */
+	request_buffer[2] = 0x10;       /* dpo/fua support on */
+	request_buffer[3] = 0;          /* no block descriptors */
+	request_buffer[4] = 0x8;        /* caching page */
+	request_buffer[5] = 0xa;        /* page length */
+	if (*flags & 0x1)
+		request_buffer[6] = 0x4;        /* WCE on */
+	else
+		request_buffer[6] = 0x0;        /* WCE off */
+
+	return 0;
+} /* End tw_scsiop_mode_sense_complete() */
+
 /* This function handles scsi read_capacity commands */
 int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id) 
 {
 	TW_Param *param;
 	TW_Command *command_packet;
-	u32 command_que_addr, command_que_value;
-	u32 param_value;
+	unsigned long command_que_value;
+	u32 command_que_addr;
+	unsigned long param_value;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity()\n");
 
@@ -2698,9 +2904,10 @@
 int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) 
 {
 	TW_Command *command_packet;
-	u32 command_que_addr, command_que_value = 0;
-	u32 lba = 0x0, num_sectors = 0x0;
-	int i, count = 0;
+	unsigned long command_que_value;
+	u32 command_que_addr = 0x0;
+	u32 lba = 0x0, num_sectors = 0x0, buffaddr = 0x0;
+	int i, use_sg, count = 0;
 	Scsi_Cmnd *srb;
 	struct scatterlist *sglist;
 
@@ -2761,16 +2968,24 @@
 		/* Do this if there are no sg list entries */
 		if (tw_dev->srb[request_id]->use_sg == 0) {    
 			dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
-			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->srb[request_id]->request_buffer);
+			buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+			if (buffaddr == 0)
+				return 1;
+
+			command_packet->byte8.io.sgl[0].address = buffaddr;
 			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
 			command_packet->size+=2;
 		}
 
 		/* Do this if we have multiple sg list entries */
 		if (tw_dev->srb[request_id]->use_sg > 0) {
-			for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
-				command_packet->byte8.io.sgl[i].address = virt_to_bus(sglist[i].address);
-				command_packet->byte8.io.sgl[i].length = sglist[i].length;
+			use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+			if (use_sg == 0)
+				return 1;
+
+			for (i=0;i<use_sg; i++) {
+				command_packet->byte8.io.sgl[i].address = sg_dma_address(&sglist[i]);
+				command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
 				command_packet->size+=2;
 			}
 		}
@@ -2779,7 +2994,7 @@
                 if (tw_dev->srb[request_id]->use_sg == 0) {
 			dprintk(KERN_WARNING "doing raid 5 write use_sg = 0, bounce_buffer[%d] = 0x%p\n", request_id, tw_dev->bounce_buffer[request_id]);
 			memcpy(tw_dev->bounce_buffer[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen);
-			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
+			command_packet->byte8.io.sgl[0].address = tw_dev->bounce_buffer_phys[request_id];
 			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
 			command_packet->size+=2;
                 }
@@ -2791,7 +3006,7 @@
                                 memcpy((char *)(tw_dev->bounce_buffer[request_id])+count, sglist[i].address, sglist[i].length);
 				count+=sglist[i].length;
                         }
-                        command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
+                        command_packet->byte8.io.sgl[0].address = tw_dev->bounce_buffer_phys[request_id];
                         command_packet->byte8.io.sgl[0].length = count;
                         command_packet->size = 5; /* single sgl */
                 }
@@ -2832,6 +3047,44 @@
 	return 0;
 } /* End tw_scsiop_request_sense() */
 
+/* This function will handle synchronize cache scsi command */
+int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id)
+{
+	TW_Command *command_packet;
+	unsigned long command_que_value;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_synchronize_cache()\n");
+
+	/* Send firmware flush command for this unit */
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet virtual address.\n");
+		return 1;
+	}
+
+	/* Setup the command packet */
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->byte0.opcode = TW_OP_FLUSH_CACHE;
+	command_packet->byte0.sgl_offset = 0;
+	command_packet->size = 2;
+	command_packet->request_id = request_id;
+	command_packet->byte3.unit = tw_dev->srb[request_id]->target;
+	command_packet->byte3.host_id = 0;
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.parameter_count = 1;
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet physical address.\n");
+		return 1;
+	}
+
+	/* Now try to post the command packet */
+	tw_post_command_packet(tw_dev, request_id);
+
+	return 0;
+} /* End tw_scsiop_synchronize_cache() */
+
 /* This function will handle test unit ready scsi command */
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id)
 {
@@ -2854,11 +3107,10 @@
 	TW_Command  *command_packet;
 	TW_Response_Queue response_queue;
 	int request_id = 0;
-	u32 command_que_value, command_que_addr;
-	u32 status_reg_addr, status_reg_value;
+	unsigned long command_que_value;
+	u32 command_que_addr;
 	u32 response_que_addr;
-	u32 param_value;
-	int imax, i;
+	unsigned long param_value;
 
   	/* Initialize SetParam command packet */
 	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
@@ -2897,40 +3149,28 @@
 	return 1;
 	}
 	command_que_addr = tw_dev->registers.command_que_addr;
-	status_reg_addr = tw_dev->registers.status_reg_addr;
 	response_que_addr = tw_dev->registers.response_que_addr;
 
 	/* Send command packet to the board */
 	outl(command_que_value, command_que_addr);
 
 	/* Poll for completion */
-	imax = TW_POLL_MAX_RETRIES;
-	for (i=0;i<imax;i++) {
-		mdelay(5);
-		status_reg_value = inl(status_reg_addr);
-		if (tw_check_bits(status_reg_value)) {
-			dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected bits.\n");
-			tw_decode_bits(tw_dev, status_reg_value, 1);
+	if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
+		response_queue.value = inl(response_que_addr);
+		request_id = (unsigned char)response_queue.u.response_id;
+		if (request_id != 0) {
+			/* unexpected request id */
+			printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected request id.\n");
 			return 1;
 		}
-		if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
-			response_queue.value = inl(response_que_addr);
-			request_id = (unsigned char)response_queue.u.response_id;
-			if (request_id != 0) {
-				/* unexpected request id */
-				printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected request id.\n");
-				return 1;
-			}
-			if (command_packet->status != 0) {
-				/* bad response */
-				tw_decode_sense(tw_dev, request_id, 0);
-				return 1;
-			}
-			break; /* Response was okay, so we exit */
+		if (command_packet->status != 0) {
+			/* bad response */
+			tw_decode_sense(tw_dev, request_id, 0);
+			return 1;
 		}
 	}
 
-  return 0;
+	return 0;
 } /* End tw_setfeature() */
 
 /* This function will setup the interrupt handler */
@@ -3034,6 +3274,26 @@
 	return 0;
 } /* End tw_state_request_start() */
 
+static void tw_unmap_scsi_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
+{
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+	
+	dprintk(KERN_WARNING "3w-xxxx: tw_unamp_scsi_data()\n");
+	
+	switch(cmd->SCp.phase) {
+		case 1:
+#ifdef BLK_BOUNCE_HIGH
+			pci_unmap_page(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, dma_dir);
+#else
+			pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, dma_dir);
+#endif
+			break;
+		case 2:
+			pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir);
+			break;
+	}
+} /* End tw_unmap_scsi_data() */
+
 /* This function will unmask the command interrupt on the controller */
 void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/3w-xxxx.h linux-2.4.20/drivers/scsi/3w-xxxx.h
--- linux-2.4.19/drivers/scsi/3w-xxxx.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/3w-xxxx.h	2002-10-29 11:18:34.000000000 +0000
@@ -91,14 +91,13 @@
 	"INFO: Verify started: Unit #",                // 0x029
 	"ERROR: Verify failed: Port #",                // 0x02A
 	"INFO: Verify complete: Unit #",               // 0x02B
-	"ERROR: Overwrote bad sector during rebuild: Port #",   //0x02C
-	"ERROR: Encountered bad sector during rebuild: Port #", //0x02D
-	"INFO: Replacement drive is too small: Port #",         //0x02E
-	"WARNING: Verify error: Unit not previously initialized: Unit #" //0x02F
+	"WARNING: Overwrote bad sector during rebuild: Port #",  //0x02C
+	"ERROR: Encountered bad sector during rebuild: Port #",  //0x02D
+	"ERROR: Replacement drive is too small: Port #",         //0x02E
+	"WARNING: Verify error: Unit not previously initialized: Unit #", //0x02F
+	"ERROR: Drive not supported: Port #"           // 0x030
 };
 
-#define TW_AEN_STRING_MAX                      0x030
-
 /* 
    Sense key lookup table 
    Format: ESDC/flags,SenseKey,AdditionalSenseCode,AdditionalSenseCodeQualifier
@@ -166,7 +165,7 @@
 #define TW_RESPONSE_ID_MASK		       0x00000FF0
 
 /* PCI related defines */
-#define TW_IO_ADDRESS_RANGE		       0xD
+#define TW_IO_ADDRESS_RANGE		       0x10
 #define TW_DEVICE_NAME			       "3ware Storage Controller"
 #define TW_VENDOR_ID (0x13C1)	/* 3ware */
 #define TW_DEVICE_ID (0x1000)	/* Storage Controller */
@@ -185,6 +184,7 @@
 #define TW_OP_SET_PARAM	      0x13
 #define TW_OP_SECTOR_INFO     0x1a
 #define TW_OP_AEN_LISTEN      0x1c
+#define TW_OP_FLUSH_CACHE     0x0e
 #define TW_CMD_PACKET         0x1d
 #define TW_ATA_PASSTHRU       0x1e
 #define TW_CMD_PACKET_WITH_DATA 0x1f
@@ -224,7 +224,6 @@
 #define TW_MAX_CMDS_PER_LUN		      255
 #define TW_BLOCK_SIZE			      0x200 /* 512-byte blocks */
 #define TW_IOCTL                              0x80
-#define TW_MAX_AEN_TRIES                      100
 #define TW_UNIT_ONLINE                        1
 #define TW_IN_INTR                            1
 #define TW_IN_IOCTL                           2
@@ -253,8 +252,8 @@
 
 /* Scatter Gather List Entry */
 typedef struct TAG_TW_SG_Entry {
-	unsigned long address;
-	unsigned long length;
+	u32 address;
+	u32 length;
 } TW_SG_Entry;
 
 typedef unsigned char TW_Sector[512];
@@ -282,17 +281,17 @@
 	} byte6;
 	union {
 		struct {
-			unsigned long lba;
+			u32 lba;
 			TW_SG_Entry sgl[TW_MAX_SGL_LENGTH];
-			unsigned long padding;	/* pad to 512 bytes */
+			u32 padding;	/* pad to 512 bytes */
 		} io;
 		struct {
 			TW_SG_Entry sgl[TW_MAX_SGL_LENGTH];
-			unsigned long padding[2];
+			u32 padding[2];
 		} param;
 		struct {
-			unsigned long response_queue_pointer;
-			unsigned long padding[125];
+			u32 response_queue_pointer;
+			u32 padding[125];
 		} init_connection;
 		struct {
 			char version[504];
@@ -384,15 +383,16 @@
 
 typedef struct TAG_TW_Device_Extension {
 	TW_Registers		registers;
-	u32			*alignment_virtual_address[TW_Q_LENGTH];
-	u32			alignment_physical_address[TW_Q_LENGTH];
-	u32			*bounce_buffer[TW_Q_LENGTH];
+	unsigned long		*alignment_virtual_address[TW_Q_LENGTH];
+	unsigned long		alignment_physical_address[TW_Q_LENGTH];
+	unsigned long		*bounce_buffer[TW_Q_LENGTH];
+	unsigned long		bounce_buffer_phys[TW_Q_LENGTH];
 	int			is_unit_present[TW_MAX_UNITS];
 	int			is_raid_five[TW_MAX_UNITS];
 	int			num_units;
 	int			num_raid_five;
-	u32			*command_packet_virtual_address[TW_Q_LENGTH];
-	u32			command_packet_physical_address[TW_Q_LENGTH];
+	unsigned long		*command_packet_virtual_address[TW_Q_LENGTH];
+	unsigned long		command_packet_physical_address[TW_Q_LENGTH];
 	struct pci_dev		*tw_pci_dev;
 	Scsi_Cmnd		*srb[TW_Q_LENGTH];
 	unsigned char		free_queue[TW_Q_LENGTH];
@@ -422,15 +422,16 @@
 	unsigned char		aen_head;
 	unsigned char		aen_tail;
 	volatile long		flags; /* long req'd for set_bit --RR */
-	char			*ioctl_data[TW_Q_LENGTH];
+	unsigned long		*ioctl_data[TW_Q_LENGTH];
 	int			reset_print;
+	char                    online;
 } TW_Device_Extension;
 
 /* Function prototypes */
 int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_aen_drain_queue(TW_Device_Extension *tw_dev);
 int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
-int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which);
+int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which);
 int tw_check_bits(u32 status_reg_value);
 int tw_check_errors(TW_Device_Extension *tw_dev);
 void tw_clear_all_interrupts(TW_Device_Extension *tw_dev);
@@ -451,6 +452,7 @@
 int tw_ioctl_complete(TW_Device_Extension *tw_dev, int request_id);
 void tw_mask_command_interrupt(TW_Device_Extension *tw_dev);
 int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds);
+int tw_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds);
 int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id);
 int tw_reset_device_extension(TW_Device_Extension *tw_dev);
 int tw_reset_sequence(TW_Device_Extension *tw_dev);
@@ -463,10 +465,13 @@
 int tw_scsi_release(struct Scsi_Host *tw_host);
 int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id);
+int tw_scsiop_mode_sense(TW_Device_Extension *tw_dev, int request_id);
+int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id);
+int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id);
 int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, 
 		  unsigned char *val);
@@ -478,6 +483,40 @@
 void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev);
 
 /* Scsi_Host_Template Initializer */
+#ifdef BLK_BOUNCE_HIGH
+#define TWXXXX {					\
+	next : NULL,					\
+	module : NULL,					\
+	proc_name : "3w-xxxx",				\
+	proc_info : tw_scsi_proc_info,			\
+	name : "3ware Storage Controller",		\
+	detect : tw_scsi_detect,			\
+	release : tw_scsi_release,			\
+	info : NULL,					\
+	ioctl : NULL,                  			\
+	command : NULL,					\
+	queuecommand : tw_scsi_queue,			\
+	eh_strategy_handler : NULL,			\
+	eh_abort_handler : tw_scsi_eh_abort,		\
+	eh_device_reset_handler : NULL,			\
+	eh_bus_reset_handler : NULL,			\
+	eh_host_reset_handler : tw_scsi_eh_reset,	\
+	abort : NULL,					\
+	reset : NULL,					\
+	slave_attach : NULL,				\
+	bios_param : tw_scsi_biosparam,			\
+	can_queue : TW_Q_LENGTH-1,			\
+	this_id: -1,					\
+	sg_tablesize : TW_MAX_SGL_LENGTH,		\
+	cmd_per_lun: TW_MAX_CMDS_PER_LUN,		\
+	present : 0,					\
+	unchecked_isa_dma : 0,				\
+	use_clustering : ENABLE_CLUSTERING,		\
+ 	use_new_eh_code : 1,				\
+	emulated : 1,					\
+	highmem_io : 1					\
+}
+#else
 #define TWXXXX {					\
 	next : NULL,					\
 	module : NULL,					\
@@ -509,4 +548,5 @@
  	use_new_eh_code : 1,				\
 	emulated : 1					\
 }
+#endif /* BLK_BOUNCE_HIGH */
 #endif /* _3W_XXXX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/53c700.c linux-2.4.20/drivers/scsi/53c700.c
--- linux-2.4.19/drivers/scsi/53c700.c	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.20/drivers/scsi/53c700.c	2002-10-29 11:18:33.000000000 +0000
@@ -51,6 +51,14 @@
 
 /* CHANGELOG
  *
+ * Version 2.8
+ *
+ * Fixed bad bug affecting tag starvation processing (previously the
+ * driver would hang the system if too many tags starved.  Also fixed
+ * bad bug having to do with 10 byte command processing and REQUEST
+ * SENSE (the command would loop forever getting a transfer length
+ * mismatch in the CMD phase).
+ *
  * Version 2.7
  *
  * Fixed scripts problem which caused certain devices (notably CDRWs)
@@ -104,7 +112,7 @@
  * Initial modularisation from the D700.  See NCR_D700.c for the rest of
  * the changelog.
  * */
-#define NCR_700_VERSION "2.7"
+#define NCR_700_VERSION "2.8"
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -676,21 +684,34 @@
 			print_sense("53c700", SCp);
 
 #endif
-			SCp->use_sg = SCp->cmnd[8];
+			/* restore the old result if the request sense was
+			 * successful */
 			if(result == 0)
 				result = SCp->cmnd[7];
+			/* now restore the original command */
+			memcpy((void *) SCp->cmnd, (void *) SCp->data_cmnd,
+			       sizeof(SCp->data_cmnd));
+			SCp->request_buffer = SCp->buffer;
+			SCp->request_bufflen = SCp->bufflen;
+			SCp->use_sg = SCp->old_use_sg;
+			SCp->cmd_len = SCp->old_cmd_len;
+			SCp->sc_data_direction = SCp->sc_old_data_direction;
+			SCp->underflow = SCp->old_underflow;
+			
 		}
 
 		free_slot(slot, hostdata);
-
-		SCp->host_scribble = NULL;
-		SCp->result = result;
-		SCp->scsi_done(SCp);
+#ifdef NCR_700_DEBUG
 		if(NCR_700_get_depth(SCp->device) == 0 ||
 		   NCR_700_get_depth(SCp->device) > NCR_700_MAX_TAGS)
 			printk(KERN_ERR "Invalid depth in NCR_700_scsi_done(): %d\n",
 			       NCR_700_get_depth(SCp->device));
+#endif /* NCR_700_DEBUG */
 		NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) - 1);
+
+		SCp->host_scribble = NULL;
+		SCp->result = result;
+		SCp->scsi_done(SCp);
 	} else {
 		printk(KERN_ERR "53c700: SCSI DONE HAS NULL SCp\n");
 	}
@@ -1050,7 +1071,6 @@
 				 * of the command */
 				SCp->cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC;
 				SCp->cmnd[7] = hostdata->status[0];
-				SCp->cmnd[8] = SCp->use_sg;
 				SCp->use_sg = 0;
 				SCp->sc_data_direction = SCSI_DATA_READ;
 				pci_dma_sync_single(hostdata->pci_dev,
@@ -1893,6 +1913,10 @@
 				printk(KERN_WARNING "scsi%d (%d:%d) Target is suffering from tag starvation.\n", SCp->host->host_no, SCp->target, SCp->lun);
 				NCR_700_set_flag(SCp->device, NCR_700_DEV_TAG_STARVATION_WARNED);
 			}
+			/* Release the slot and ajust the depth before refusing
+			 * the command */
+			free_slot(slot, hostdata);
+			NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) - 1);
 			return 1;
 		}
 		slot->tag = SCp->device->current_tag++;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/53c7xx.c linux-2.4.20/drivers/scsi/53c7xx.c
--- linux-2.4.19/drivers/scsi/53c7xx.c	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.20/drivers/scsi/53c7xx.c	2002-10-29 11:18:48.000000000 +0000
@@ -1119,8 +1119,9 @@
  */
 
 int 
-ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip, 
-    u32 base, int io_port, int irq, int dma, long long options, int clock)
+ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
+    unsigned long base, int io_port, int irq, int dma, 
+    long long options, int clock)
 {
     struct Scsi_Host *instance;
     struct NCR53c7x0_hostdata *hostdata;
@@ -1144,8 +1145,8 @@
     	return -1;
     }
 
-    printk("scsi-ncr53c7xx : %s at memory 0x%x, io 0x%x, irq %d",
-    	chip_str, (unsigned) base, io_port, irq);
+    printk("scsi-ncr53c7xx : %s at memory 0x%lx, io 0x%x, irq %d",
+    	chip_str, base, io_port, irq);
     if (dma == DMA_NONE)
     	printk("\n");
     else 
@@ -1224,7 +1225,8 @@
     memset((void *)instance->hostdata[0], 0, 8192);
     cache_push(virt_to_phys((void *)(instance->hostdata[0])), 8192);
     cache_clear(virt_to_phys((void *)(instance->hostdata[0])), 8192);
-    kernel_set_cachemode(instance->hostdata[0], 8192, IOMAP_NOCACHE_SER);
+    kernel_set_cachemode((void *)(instance->hostdata[0]), 8192,
+			 IOMAP_NOCACHE_SER);
 
     /* FIXME : if we ever support an ISA NCR53c7xx based board, we
        need to check if the chip is running in a 16 bit mode, and if so 
@@ -1251,7 +1253,7 @@
      */
 
     if (base) {
-	instance->base = (unsigned char *) (unsigned long) base;
+	instance->base = (unsigned long) base;
 	/* Check for forced I/O mapping */
     	if (!(options & OPTION_IO_MAPPED)) {
 	    options |= OPTION_MEMORY_MAPPED;
@@ -1423,7 +1425,7 @@
     	memory_to_ncr = tmp|DMODE_800_DIOM;
     	ncr_to_memory = tmp|DMODE_800_SIOM;
     } else {
-    	base = virt_to_bus(host->base);
+    	base = virt_to_bus((void *)host->base);
 	memory_to_ncr = ncr_to_memory = tmp;
     }
 
@@ -3049,7 +3051,7 @@
     /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, which
      * XXX may be invalid (CONFIG_060_WRITETHROUGH)
      */
-    kernel_set_cachemode((u32)addr, 4096, IOMAP_FULL_CACHING);
+    kernel_set_cachemode(addr, 4096, IOMAP_FULL_CACHING);
     free_page ((u32)addr);
 }
 
@@ -3058,7 +3060,7 @@
     struct Scsi_Host *host = cmd->host;
     struct NCR53c7x0_hostdata *hostdata = 
 	(struct NCR53c7x0_hostdata *) host->hostdata[0];
-    u32 real;			/* Real address */
+    void *real;			/* Real address */
     int size;			/* Size of *tmp */
     struct NCR53c7x0_cmd *tmp;
     unsigned long flags;
@@ -3101,12 +3103,12 @@
             printk (KERN_ERR "53c7xx: allocate_cmd size > 4K\n");
 	    return NULL;
 	}
-        real = get_free_page(GFP_ATOMIC);
+        real = (void *)get_free_page(GFP_ATOMIC);
         if (real == 0)
         	return NULL;
-        memset((void *)real, 0, 4096);
-        cache_push(virt_to_phys((void *)real), 4096);
-        cache_clear(virt_to_phys((void *)real), 4096);
+        memset(real, 0, 4096);
+        cache_push(virt_to_phys(real), 4096);
+        cache_clear(virt_to_phys(real), 4096);
         kernel_set_cachemode(real, 4096, IOMAP_NOCACHE_SER);
 	tmp = ROUNDUP(real, void *);
 #ifdef FORCE_DSA_ALIGNMENT
@@ -3115,12 +3117,12 @@
 		tmp = (struct NCR53c7x0_cmd *)((u32)tmp + 255);
 	    tmp = (struct NCR53c7x0_cmd *)(((u32)tmp & ~0xff) + CmdPageStart);
 #if 0
-	    printk ("scsi: size = %d, real = 0x%08x, tmp set to 0x%08x\n",
+	    printk ("scsi: size = %d, real = %p, tmp set to 0x%08x\n",
 			size, real, (u32)tmp);
 #endif
 	}
 #endif
-	tmp->real = (void *)real;
+	tmp->real = real;
 	tmp->size = size;			
 	tmp->free = ((void (*)(void *, int)) my_free_page);
 	save_flags (flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/ChangeLog.ips linux-2.4.20/drivers/scsi/ChangeLog.ips
--- linux-2.4.19/drivers/scsi/ChangeLog.ips	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/ChangeLog.ips	2002-10-29 11:18:38.000000000 +0000
@@ -1,6 +1,10 @@
 IBM ServeRAID driver Change Log
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+        5.00.01  - Sarasota ( 5i ) adapters must always be scanned first  
+                 - Get rid on IOCTL_NEW_COMMAND code  
+                 - Add Extended DCDB Commands for Tape Support in 5I                  
+        
         4.90.11  - Don't actually RESET unless it's physically required
                  - Remove unused compile options
         
@@ -116,4 +120,3 @@
                 - Fixed read/write errors when the adapter is using an
                   8K stripe size.
 
-
\ No newline at end of file
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/Config.in linux-2.4.20/drivers/scsi/Config.in
--- linux-2.4.19/drivers/scsi/Config.in	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/Config.in	2002-10-29 11:18:39.000000000 +0000
@@ -36,9 +36,7 @@
    dep_tristate 'SGI WD93C93 SCSI Driver' CONFIG_SGIWD93_SCSI $CONFIG_SCSI
 fi
 if [ "$CONFIG_DECSTATION" = "y" ]; then
-   if [ "$CONFIG_TC" = "y" ]; then
-      dep_tristate 'DEC NCR53C94 Scsi Driver' CONFIG_SCSI_DECNCR $CONFIG_SCSI
-   fi
+   dep_tristate 'DEC NCR53C94 Scsi Driver' CONFIG_SCSI_DECNCR $CONFIG_SCSI $CONFIG_TC
    dep_tristate 'DEC SII Scsi Driver' CONFIG_SCSI_DECSII $CONFIG_SCSI
 fi
 
@@ -150,7 +148,10 @@
 if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_SYM53C8XX_2" != "y" ]; then
    dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
    dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI
-   if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
+   if [ "$CONFIG_PARISC" = "y" ]; then
+      dep_tristate 'Zalon SCSI support' CONFIG_SCSI_ZALON $CONFIG_GSC $CONFIG_SCSI
+   fi
+   if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -o "$CONFIG_SCSI_ZALON" = "y" -o "$CONFIG_SCSI_ZALON" = "m" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
       int  '  default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
       int  '  maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
       int  '  synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/Makefile linux-2.4.20/drivers/scsi/Makefile
--- linux-2.4.19/drivers/scsi/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/Makefile	2002-10-29 11:18:35.000000000 +0000
@@ -118,6 +118,7 @@
 obj-$(CONFIG_SCSI_PLUTO)	+= pluto.o
 obj-$(CONFIG_SCSI_DECNCR)	+= NCR53C9x.o	dec_esp.o
 obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o
+obj-$(CONFIG_SCSI_ZALON)	+= zalon7xx_mod.o
 obj-$(CONFIG_SCSI_PPA)		+= ppa.o
 obj-$(CONFIG_SCSI_IMM)		+= imm.o
 obj-$(CONFIG_JAZZ_ESP)		+= NCR53C9x.o	jazz_esp.o
@@ -136,7 +137,8 @@
 obj-$(CONFIG_BLK_DEV_SR)	+= sr_mod.o
 obj-$(CONFIG_CHR_DEV_SG)	+= sg.o
 
-list-multi	:= scsi_mod.o sd_mod.o sr_mod.o initio.o a100u2w.o cpqfc.o
+list-multi	:= scsi_mod.o sd_mod.o sr_mod.o initio.o a100u2w.o cpqfc.o \
+			zalon7xx_mod.o
 scsi_mod-objs	:= scsi.o hosts.o scsi_ioctl.o constants.o \
 			scsicam.o scsi_proc.o scsi_error.o \
 			scsi_obsolete.o scsi_queue.o scsi_lib.o \
@@ -146,6 +148,7 @@
 sr_mod-objs	:= sr.o sr_ioctl.o sr_vendor.o
 initio-objs	:= ini9100u.o i91uscsi.o
 a100u2w-objs	:= inia100.o i60uscsi.o
+zalon7xx_mod-objs := zalon7xx.o ncr53c8xx.o
 cpqfc-objs	:= cpqfcTSinit.o cpqfcTScontrol.o cpqfcTSi2c.o \
 		   cpqfcTSworker.o cpqfcTStrigger.o
 
@@ -167,6 +170,9 @@
 a100u2w.o: $(a100u2w-objs)
 	$(LD) -r -o $@ $(a100u2w-objs)
 
+zalon7xx_mod.o: $(zalon7xx_mod-objs)
+	$(LD) -r -o $@ $(zalon7xx_mod-objs)
+
 cpqfc.o: $(cpqfc-objs)
 	$(LD) -r -o $@ $(cpqfc-objs)
 
@@ -183,7 +189,7 @@
 
 53c7xx_d.h: 53c7xx.scr script_asm.pl
 	ln -sf 53c7xx.scr fake7.c
-	$(CPP) $(CPPFLAGS) -traditional -DCHIP=710 fake7.c | grep -v '^#' | $(PERL) -s script_asm.pl -ncr7x0_family
+	$(CPP) $(CPPFLAGS) -traditional -DCHIP=710 fake7.c | grep -v '^#' | $(PERL) -s script_asm.pl -ncr710
 	mv script.h 53c7xx_d.h
 	mv scriptu.h 53c7xx_u.h
 	rm fake7.c
@@ -194,7 +200,7 @@
 
 sim710_d.h: sim710.scr script_asm.pl
 	ln -sf sim710.scr fake7.c
-	$(CPP) $(CPPFLAGS) -traditional -DCHIP=710 fake7.c | grep -v '^#' | $(PERL) -s script_asm.pl -ncr7x0_family
+	$(CPP) $(CPPFLAGS) -traditional -DCHIP=710 fake7.c | grep -v '^#' | $(PERL) -s script_asm.pl -ncr710
 	mv script.h sim710_d.h
 	mv scriptu.h sim710_u.h
 	rm fake7.c
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/NCR53C9x.c linux-2.4.20/drivers/scsi/NCR53C9x.c
--- linux-2.4.19/drivers/scsi/NCR53C9x.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/NCR53C9x.c	2002-10-29 11:18:34.000000000 +0000
@@ -289,7 +289,7 @@
 #endif
 
 #ifdef DEBUG_ESP_CMDS
-extern inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs,
+inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs,
 			   unchar cmd)
 {
 	esp->espcmdlog[esp->espcmdent] = cmd;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/README.st linux-2.4.20/drivers/scsi/README.st
--- linux-2.4.19/drivers/scsi/README.st	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.20/drivers/scsi/README.st	2002-10-29 11:18:34.000000000 +0000
@@ -2,7 +2,7 @@
 The driver is currently maintained by Kai Mkisara (email
 Kai.Makisara@metla.fi)
 
-Last modified: Tue Feb  5 21:33:23 2002 by makisara
+Last modified: Tue Apr 16 22:32:10 2002 by makisara
 
 
 BASICS
@@ -188,6 +188,8 @@
 max_buffers=xxx            the maximum number of tape buffer set to xxx
 max_sg_segs=xxx		   the maximum number of scatter/gather
 			   segments
+blocking_open=xxx	   block in open() if drive not ready, O_NONBLOCK
+			   not used, and blocking_open non-zero
 
 Note that if the buffer size is changed but the write threshold is not
 set, the write threshold is set to the new buffer size - 2 kB.
@@ -395,6 +397,11 @@
 The recovered write errors are considered fatal if ST_RECOVERED_WRITE_FATAL
 is defined.
 
+By default, open() does not block if the drive is not ready. The
+behaviour can be changed by setting ST_BLOCKING_OPEN to one. The
+behaviour can be changed also with the boot/module option
+blocking_open. The blocking open times out after ST_BLOCK_SECONDS.
+
 The maximum number of tape devices is determined by the define
 ST_MAX_TAPES. If more tapes are detected at driver initialization, the
 maximum is adjusted accordingly.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aacraid/Makefile linux-2.4.20/drivers/scsi/aacraid/Makefile
--- linux-2.4.19/drivers/scsi/aacraid/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aacraid/Makefile	2002-10-29 11:18:32.000000000 +0000
@@ -5,6 +5,6 @@
 obj-m		:= $(O_TARGET)
 
 obj-y		:= linit.o aachba.o commctrl.o comminit.o commsup.o \
-		   dpcsup.o rx.o sap1sup.o
+		   dpcsup.o rx.o sa.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aacraid/README linux-2.4.20/drivers/scsi/aacraid/README
--- linux-2.4.19/drivers/scsi/aacraid/README	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aacraid/README	2002-10-29 11:18:33.000000000 +0000
@@ -3,13 +3,11 @@
 Introduction
 -------------------------
 The aacraid driver adds support for Adaptec (http://www.adaptec.com)
-OEM based RAID controllers. This is a major rewrite from the original 
+RAID controllers. This is a major rewrite from the original 
 Adaptec supplied driver. It has signficantly cleaned up both the code
 and the running binary size (the module is less than half the size of
 the original).
 
-This driver is experimental.
-
 Supported Cards/Chipsets
 -------------------------
 	Dell Computer Corporation PERC 2 Quad Channel
@@ -17,16 +15,18 @@
 	Dell Computer Corporation PERC 3/Si
 	Dell Computer Corporation PERC 3/Di
 	HP NetRAID-4M
-
-Probably Supported Devices
--------------------------
-	Any and All Adaptec branded AAC964/5400 series raid controllers.
+	ADAPTEC 2120S
+	ADAPTEC 2200S
+	ADAPTEC 5400S
 
 People
 -------------------------
 Alan Cox <alan@redhat.com>
 Christoph Hellwig <hch@infradead.org>	(small cleanups/fixes)
 Matt Domsch <matt_domsch@dell.com>	(revision ioctl, adapter messages)
+Deanna Bonds <deanna_bonds@adaptec.com> (non-DASD support, PAE fibs and 64 bit, added new adaptec controllers
+					 added new ioctls, changed scsi interface to use new error handler,
+					 increased the number of fibs and outstanding commands to a container)
 
 Original Driver
 -------------------------
@@ -36,6 +36,7 @@
 -------------------------
 None currently. Also note this is very different to Brian's original driver
 so don't expect him to support it.
+Adaptec does support this driver.  Contact either tech support or deanna bonds.
 
 Original by Brian Boerner February 2001
 Rewritten by Alan Cox, November 2001
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aacraid/aachba.c linux-2.4.20/drivers/scsi/aacraid/aachba.c
--- linux-2.4.19/drivers/scsi/aacraid/aachba.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aacraid/aachba.c	2002-10-29 11:18:50.000000000 +0000
@@ -42,6 +42,8 @@
 #include "aacraid.h"
 
 /*	SCSI Commands */
+/*	TODO:  dmb - use the ones defined in include/scsi/scsi.h */
+
 #define	SS_TEST			0x00	/* Test unit ready */
 #define SS_REZERO		0x01	/* Rezero unit */
 #define	SS_REQSEN		0x03	/* Request Sense */
@@ -60,19 +62,19 @@
 #define SS_SEEK			0x2B	/* Seek */
 
 /* values for inqd_pdt: Peripheral device type in plain English */
-#define	INQD_PDT_DA	0x00	/* Direct-access (DISK) device */
-#define	INQD_PDT_PROC	0x03	/* Processor device */
-#define	INQD_PDT_CHNGR	0x08	/* Changer (jukebox, scsi2) */
-#define	INQD_PDT_COMM	0x09	/* Communication device (scsi2) */
-#define	INQD_PDT_NOLUN2 0x1f	/* Unknown Device (scsi2) */
-#define	INQD_PDT_NOLUN	0x7f	/* Logical Unit Not Present */
-
-#define	INQD_PDT_DMASK	0x1F	/* Peripheral Device Type Mask */
-#define	INQD_PDT_QMASK	0xE0	/* Peripheral Device Qualifer Mask */
-
-#define	TARGET_LUN_TO_CONTAINER(target, lun)	(((lun) << 4) | target)
-#define CONTAINER_TO_TARGET(cont)		((cont) & 0xf)
-#define CONTAINER_TO_LUN(cont)			((cont) >> 4)
+#define	INQD_PDT_DA	0x00		/* Direct-access (DISK) device */
+#define	INQD_PDT_PROC	0x03		/* Processor device */
+#define	INQD_PDT_CHNGR	0x08		/* Changer (jukebox, scsi2) */
+#define	INQD_PDT_COMM	0x09		/* Communication device (scsi2) */
+#define	INQD_PDT_NOLUN2 0x1f		/* Unknown Device (scsi2) */
+#define	INQD_PDT_NOLUN	0x7f		/* Logical Unit Not Present */
+
+#define	INQD_PDT_DMASK	0x1F		/* Peripheral Device Type Mask */
+#define	INQD_PDT_QMASK	0xE0		/* Peripheral Device Qualifer Mask */
+
+#define	TARGET_LUN_TO_CONTAINER(target, lun)	(target)
+#define CONTAINER_TO_TARGET(cont)		((cont))
+#define CONTAINER_TO_LUN(cont)			(0)
 
 #define MAX_FIB_DATA (sizeof(struct hw_fib) - sizeof(FIB_HEADER))
 
@@ -81,22 +83,22 @@
 /*
  *	Sense keys
  */
-#define SENKEY_NO_SENSE      0x00	
-#define SENKEY_UNDEFINED     0x01	
-#define SENKEY_NOT_READY     0x02	
-#define SENKEY_MEDIUM_ERR    0x03	
-#define SENKEY_HW_ERR        0x04	
-#define SENKEY_ILLEGAL       0x05	
-#define SENKEY_ATTENTION     0x06	
-#define SENKEY_PROTECTED     0x07	
-#define SENKEY_BLANK         0x08	
-#define SENKEY_V_UNIQUE      0x09	
-#define SENKEY_CPY_ABORT     0x0A	
-#define SENKEY_ABORT         0x0B	
-#define SENKEY_EQUAL         0x0C	
-#define SENKEY_VOL_OVERFLOW  0x0D	
-#define SENKEY_MISCOMP       0x0E	
-#define SENKEY_RESERVED      0x0F	
+#define SENKEY_NO_SENSE      			0x00	
+#define SENKEY_UNDEFINED     			0x01	
+#define SENKEY_NOT_READY     			0x02	
+#define SENKEY_MEDIUM_ERR    			0x03	
+#define SENKEY_HW_ERR        			0x04	
+#define SENKEY_ILLEGAL       			0x05	
+#define SENKEY_ATTENTION     			0x06	
+#define SENKEY_PROTECTED     			0x07	
+#define SENKEY_BLANK         			0x08	
+#define SENKEY_V_UNIQUE      			0x09	
+#define SENKEY_CPY_ABORT     			0x0A	
+#define SENKEY_ABORT         			0x0B	
+#define SENKEY_EQUAL         			0x0C	
+#define SENKEY_VOL_OVERFLOW  			0x0D	
+#define SENKEY_MISCOMP       			0x0E	
+#define SENKEY_RESERVED      			0x0F	
 
 /*
  *	Sense codes
@@ -160,16 +162,16 @@
  *----------------------------------------------------------------------------*/
 /* SCSI inquiry data */
 struct inquiry_data {
-	u8 inqd_pdt;	/* Peripheral qualifier | Peripheral Device Type  */
-	u8 inqd_dtq;	/* RMB | Device Type Qualifier  */
-	u8 inqd_ver;	/* ISO version | ECMA version | ANSI-approved version */
-	u8 inqd_rdf;	/* AENC | TrmIOP | Response data format */
-	u8 inqd_len;	/* Additional length (n-4) */
-	u8 inqd_pad1[2];/* Reserved - must be zero */
-	u8 inqd_pad2;	/* RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
-	u8 inqd_vid[8];	/* Vendor ID */
-	u8 inqd_pid[16];/* Product ID */
-	u8 inqd_prl[4];	/* Product Revision Level */
+	u8 inqd_pdt;		/* Peripheral qualifier | Peripheral Device Type  */
+	u8 inqd_dtq;		/* RMB | Device Type Qualifier  */
+	u8 inqd_ver;		/* ISO version | ECMA version | ANSI-approved version */
+	u8 inqd_rdf;		/* AENC | TrmIOP | Response data format */
+	u8 inqd_len;		/* Additional length (n-4) */
+	u8 inqd_pad1[2];	/* Reserved - must be zero */
+	u8 inqd_pad2;		/* RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
+	u8 inqd_vid[8];		/* Vendor ID */
+	u8 inqd_pid[16];	/* Product ID */
+	u8 inqd_prl[4];		/* Product Revision Level */
 };
 
 struct sense_data {
@@ -215,6 +217,12 @@
 static struct fsa_scsi_hba *fsa_dev[MAXIMUM_NUM_ADAPTERS];	/*  SCSI Device Instance Pointers */
 static struct sense_data sense_data[MAXIMUM_NUM_CONTAINERS];
 static void get_sd_devname(int disknum, char *buffer);
+static unsigned long aac_build_sg(Scsi_Cmnd* scsicmd, struct sgmap* sgmap);
+static unsigned long aac_build_sg64(Scsi_Cmnd* scsicmd, struct sgmap64* psg);
+static int aac_send_srb_fib(Scsi_Cmnd* scsicmd);
+#ifdef AAC_DETAILED_STATUS_INFO
+static char *aac_get_status_string(u32 status);
+#endif
 
 /**
  *	aac_get_containers	-	list containers
@@ -225,7 +233,7 @@
 int aac_get_containers(struct aac_dev *dev)
 {
 	struct fsa_scsi_hba *fsa_dev_ptr;
-	int index, status = 0;
+	u32 index, status = 0;
 	struct aac_query_mount *dinfo;
 	struct aac_mount *dresp;
 	struct fib * fibptr;
@@ -396,9 +404,8 @@
 	struct scsi_inq *str;
 	char *findit;
 	struct aac_driver_ident *mp;
-	extern struct aac_driver_ident aac_drivers[];	/* HACK FIXME */
 
-	mp = &aac_drivers[devtype];
+	mp = aac_get_driver_ident(devtype);
    
 	str = (struct scsi_inq *)(data); /* cast data to scsi inq block */
 
@@ -413,19 +420,19 @@
 	if (tindex < (sizeof(container_types)/sizeof(char *))){
 		inqstrcpy (container_types[tindex], findit);
 	}
-	inqstrcpy ("0001", str->prl);
+	inqstrcpy ("V1.0", str->prl);
 }
 
-void set_sense(char *sense_buf, u8 sense_key, u8 sense_code,
+void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,
 		    u8 a_sense_code, u8 incorrect_length,
-		    u8 bit_pointer, unsigned field_pointer,
-		    unsigned long residue)
+		    u8 bit_pointer, u16 field_pointer,
+		    u32 residue)
 {
 	sense_buf[0] = 0xF0;	/* Sense data valid, err code 70h (current error) */
 	sense_buf[1] = 0;	/* Segment number, always zero */
 
 	if (incorrect_length) {
-		sense_buf[2] = sense_key | 0x20;	/* Set the ILI bit | sense key */
+		sense_buf[2] = sense_key | 0x20;	/* Set ILI bit | sense key */
 		sense_buf[3] = BYTE3(residue);
 		sense_buf[4] = BYTE2(residue);
 		sense_buf[5] = BYTE1(residue);
@@ -469,13 +476,76 @@
 	scsicmd->scsi_done(scsicmd);
 }
 
+int aac_get_adapter_info(struct aac_dev* dev)
+{
+	struct fib* fibptr;
+	struct aac_adapter_info* info;
+	int rcode;
+	u32 tmp;
+	if (!(fibptr = fib_alloc(dev)))
+		return -ENOMEM;
+
+	fib_init(fibptr);
+	info = (struct aac_adapter_info*) fib_data(fibptr);
+
+	memset(info,0,sizeof(struct aac_adapter_info));
+
+	rcode = fib_send(RequestAdapterInfo,
+			fibptr, 
+			sizeof(struct aac_adapter_info),
+			FsaNormal, 
+			1, 1, 
+			NULL, 
+			NULL);
+
+	memcpy(&dev->adapter_info, info, sizeof(struct aac_adapter_info));
+
+	tmp = dev->adapter_info.kernelrev;
+	printk(KERN_INFO "%s%d: kernel %d.%d.%d build %d\n", 
+			dev->name, dev->id,
+			tmp>>24,(tmp>>16)&0xff,(tmp>>8)&0xff,
+			dev->adapter_info.kernelbuild);
+	tmp = dev->adapter_info.monitorrev;
+	printk(KERN_INFO "%s%d: monitor %d.%d.%d build %d\n", 
+			dev->name, dev->id,
+			tmp>>24,(tmp>>16)&0xff,(tmp>>8)&0xff,
+			dev->adapter_info.monitorbuild);
+	tmp = dev->adapter_info.biosrev;
+	printk(KERN_INFO "%s%d: bios %d.%d.%d build %d\n", 
+			dev->name, dev->id,
+			tmp>>24,(tmp>>16)&0xff,(tmp>>8)&0xff,
+			dev->adapter_info.biosbuild);
+	printk(KERN_INFO "%s%d: serial %x%x\n",
+			dev->name, dev->id,
+			dev->adapter_info.serial[0],
+			dev->adapter_info.serial[1]);
+	dev->pae_support = 0;
+	dev->nondasd_support = 0;
+	if( BITS_PER_LONG >= 64 && 
+	  (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)){
+		printk(KERN_INFO "%s%d: 64 Bit PAE enabled\n", dev->name, dev->id);
+		dev->pae_support = 1;
+	}
+	/* TODO - dmb temporary until fw can set this bit  */
+	dev->pae_support = (BITS_PER_LONG >= 64);
+	if(dev->pae_support != 0) {
+		printk(KERN_INFO "%s%d: 64 Bit PAE enabled\n", dev->name, dev->id);
+	}
+
+	if(dev->adapter_info.options & AAC_OPT_NONDASD){
+		dev->nondasd_support = 1;
+	}
+	return rcode;
+}
+
+
 static void read_callback(void *context, struct fib * fibptr)
 {
 	struct aac_dev *dev;
 	struct aac_read_reply *readreply;
 	Scsi_Cmnd *scsicmd;
-	unsigned long lba;
-	int cid;
+	u32 lba;
+	u32 cid;
 
 	scsicmd = (Scsi_Cmnd *) context;
 
@@ -483,7 +553,7 @@
 	cid =TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun);
 
 	lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
-	dprintk((KERN_DEBUG "read_callback[cpu %d]: lba = %ld, t = %ld.\n", smp_processor_id(), lba, jiffies));
+	dprintk((KERN_DEBUG "read_callback[cpu %d]: lba = %d, t = %ld.\n", smp_processor_id(), lba, jiffies));
 
 	if (fibptr == NULL)
 		BUG();
@@ -494,7 +564,7 @@
 			scsicmd->use_sg,
 			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
 	else if(scsicmd->request_bufflen)
-		pci_unmap_single(dev->pdev, (dma_addr_t)(long)scsicmd->SCp.ptr,
+		pci_unmap_single(dev->pdev, (dma_addr_t)(unsigned long)scsicmd->SCp.ptr,
 				 scsicmd->request_bufflen,
 				 scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
 	readreply = (struct aac_read_reply *)fib_data(fibptr);
@@ -503,7 +573,7 @@
 	else {
 		printk(KERN_WARNING "read_callback: read failed, status = %d\n", readreply->status);
 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
-		set_sense((char *) &sense_data[cid],
+		set_sense((u8 *) &sense_data[cid],
 				    SENKEY_HW_ERR,
 				    SENCODE_INTERNAL_TARGET_FAILURE,
 				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
@@ -520,15 +590,15 @@
 	struct aac_dev *dev;
 	struct aac_write_reply *writereply;
 	Scsi_Cmnd *scsicmd;
-	unsigned long lba;
-	int cid;
+	u32 lba;
+	u32 cid;
 
 	scsicmd = (Scsi_Cmnd *) context;
 	dev = (struct aac_dev *)scsicmd->host->hostdata;
 	cid = TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun);
 
 	lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
-	dprintk((KERN_DEBUG "write_callback[cpu %d]: lba = %ld, t = %ld.\n", smp_processor_id(), lba, jiffies));
+	dprintk((KERN_DEBUG "write_callback[cpu %d]: lba = %d, t = %ld.\n", smp_processor_id(), lba, jiffies));
 	if (fibptr == NULL)
 		BUG();
 
@@ -538,7 +608,7 @@
 			scsicmd->use_sg,
 			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
 	else if(scsicmd->request_bufflen)
-		pci_unmap_single(dev->pdev, (dma_addr_t)(long)scsicmd->SCp.ptr,
+		pci_unmap_single(dev->pdev, (dma_addr_t)(unsigned long)scsicmd->SCp.ptr,
 				 scsicmd->request_bufflen,
 				 scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
 
@@ -548,7 +618,7 @@
 	else {
 		printk(KERN_WARNING "write_callback: write failed, status = %d\n", writereply->status);
 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
-		set_sense((char *) &sense_data[cid],
+		set_sense((u8 *) &sense_data[cid],
 				    SENKEY_HW_ERR,
 				    SENCODE_INTERNAL_TARGET_FAILURE,
 				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
@@ -562,12 +632,10 @@
 
 int aac_read(Scsi_Cmnd * scsicmd, int cid)
 {
-	unsigned long lba;
-	unsigned long count;
-	unsigned long byte_count = 0;
+	u32 lba;
+	u32 count;
 	int status;
 
-	struct aac_read *readcmd;
 	u16 fibsize;
 	struct aac_dev *dev;
 	struct fib * cmd_fibcontext;
@@ -591,7 +659,7 @@
 		lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
 	}
-	dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %lu, t = %ld.\n", smp_processor_id(), lba, jiffies));
+	dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
 	/*
 	 *	Alocate and initialize a Fib
 	 */
@@ -603,71 +671,58 @@
 
 	fib_init(cmd_fibcontext);
 
-	readcmd = (struct aac_read *) fib_data(cmd_fibcontext);
-	readcmd->command = cpu_to_le32(VM_CtBlockRead);
-	readcmd->cid = cpu_to_le32(cid);
-	readcmd->block = cpu_to_le32(lba);
-	readcmd->count = cpu_to_le32(count * 512);
-	readcmd->sg.count = cpu_to_le32(1);
-
-	if (count * 512 > (64 * 1024))
-		BUG();
-	/*
-	 *	Build Scatter/Gather list
-	 */
-	if (scsicmd->use_sg)	/* use scatter/gather list */
-	{
-		struct scatterlist *sg;
-		int i;
-		int sg_count;
-
-		sg = (struct scatterlist *) scsicmd->request_buffer;
+	if(dev->pae_support == 1){
+		struct aac_read64 *readcmd;
+		readcmd = (struct aac_read64 *) fib_data(cmd_fibcontext);
+		readcmd->command = cpu_to_le32(VM_CtHostRead64);
+		readcmd->cid = cpu_to_le16(cid);
+		readcmd->sector_count = cpu_to_le16(count);
+		readcmd->block = cpu_to_le32(lba);
+		readcmd->pad   = cpu_to_le16(0);
+		readcmd->flags = cpu_to_le16(0); 
 		
-		sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
-			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
-			
-		byte_count = 0;
-
-		for (i = 0; i < sg_count; i++) {
-			readcmd->sg.sg[i].addr = cpu_to_le32(sg_dma_address(sg));
-			readcmd->sg.sg[i].count = cpu_to_le32(sg_dma_len(sg));
-			byte_count += sg->length;
-			if (sg->length > (64 * 1024))
-				BUG();
-			sg++;
-		}
-		readcmd->sg.count = cpu_to_le32(sg_count);
-
-		if (sg_count > MAX_DRIVER_SG_SEGMENT_COUNT)
+		aac_build_sg64(scsicmd, &readcmd->sg);
+		if(readcmd->sg.count > MAX_DRIVER_SG_SEGMENT_COUNT)
 			BUG();
-	}
-	else if(scsicmd->request_bufflen)
-	{
-		dma_addr_t addr;
-		addr = pci_map_single(dev->pdev, scsicmd->request_buffer,
-				scsicmd->request_bufflen, scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
-		scsicmd->SCp.ptr = (void *)(long)addr;
-		readcmd->sg.sg[0].addr = cpu_to_le32(addr);
-		readcmd->sg.sg[0].count = cpu_to_le32(scsicmd->request_bufflen);
+		fibsize = sizeof(struct aac_read64) + ((readcmd->sg.count - 1) * sizeof (struct sgentry64));
+		/*
+		 *	Now send the Fib to the adapter
+		 */
+		status = fib_send(ContainerCommand64, 
+			  cmd_fibcontext, 
+			  fibsize, 
+			  FsaNormal, 
+			  0, 1, 
+			  (fib_callback) read_callback, 
+			  (void *) scsicmd);
+	} else {
+		struct aac_read *readcmd;
+		readcmd = (struct aac_read *) fib_data(cmd_fibcontext);
+		readcmd->command = cpu_to_le32(VM_CtBlockRead);
+		readcmd->cid = cpu_to_le32(cid);
+		readcmd->block = cpu_to_le32(lba);
+		readcmd->count = cpu_to_le32(count * 512);
 
-		byte_count = scsicmd->request_bufflen;
+		if (count * 512 > (64 * 1024))
+			BUG();
 
-		if (byte_count > (64 * 1024))
+		aac_build_sg(scsicmd, &readcmd->sg);
+		if(readcmd->sg.count > MAX_DRIVER_SG_SEGMENT_COUNT)
 			BUG();
-	}
-	if (byte_count != readcmd->count)
-		BUG();
-	/*
-	 *	Now send the Fib to the adapter
-	 */
-	fibsize = sizeof(struct aac_read) + ((readcmd->sg.count - 1) * sizeof (struct sgentry));
-	status = fib_send(ContainerCommand, 
+		fibsize = sizeof(struct aac_read) + ((readcmd->sg.count - 1) * sizeof (struct sgentry));
+		/*
+		 *	Now send the Fib to the adapter
+		 */
+		status = fib_send(ContainerCommand, 
 			  cmd_fibcontext, 
 			  fibsize, 
 			  FsaNormal, 
 			  0, 1, 
 			  (fib_callback) read_callback, 
 			  (void *) scsicmd);
+	}
+	
+	
 	/*
 	 *	Check that the command queued to the controller
 	 */
@@ -687,11 +742,9 @@
 
 static int aac_write(Scsi_Cmnd * scsicmd, int cid)
 {
-	unsigned long lba;
-	unsigned long count;
-	unsigned long byte_count = 0;
+	u32 lba;
+	u32 count;
 	int status;
-	struct aac_write *writecmd;
 	u16 fibsize;
 	struct aac_dev *dev;
 	struct fib * cmd_fibcontext;
@@ -722,75 +775,61 @@
 	}
 	fib_init(cmd_fibcontext);
 
-	writecmd = (struct aac_write *) fib_data(cmd_fibcontext);
-	writecmd->command = cpu_to_le32(VM_CtBlockWrite);
-	writecmd->cid = cpu_to_le32(cid);
-	writecmd->block = cpu_to_le32(lba);
-	writecmd->count = cpu_to_le32(count * 512);
-	writecmd->sg.count = cpu_to_le32(1);
-	/* FIXME: why isnt ->stable setup */
-
-	if (count * 512 > (64 * 1024)) {
-		BUG();
-	}
-	/*
-	 *	Build Scatter/Gather list
-	 */
-	if (scsicmd->use_sg)
+	if(dev->pae_support == 1)
 	{
-		struct scatterlist *sg;
-		int i;
-		int sg_count;
-		
-		sg = (struct scatterlist *) scsicmd->request_buffer;
+		struct aac_write64 *writecmd;
+		writecmd = (struct aac_write64 *) fib_data(cmd_fibcontext);
+		writecmd->command = cpu_to_le32(VM_CtHostWrite64);
+		writecmd->cid = cpu_to_le16(cid);
+		writecmd->sector_count = cpu_to_le16(count); 
+		writecmd->block = cpu_to_le32(lba);
+		writecmd->pad	= cpu_to_le16(0);
+		writecmd->flags	= cpu_to_le16(0);
 
-		sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
-			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
-
-		byte_count = 0;
-
-		for (i = 0; i < scsicmd->use_sg; i++) {
-			writecmd->sg.sg[i].addr = cpu_to_le32(sg_dma_address(sg));
-			writecmd->sg.sg[i].count = cpu_to_le32(sg_dma_len(sg));
-			byte_count += sg->length;
-
-			if (sg->length > (64 * 1024))
-				BUG();
-			sg++;
-		}
-		writecmd->sg.count = cpu_to_le32(sg_count);
-
-		if (sg_count > MAX_DRIVER_SG_SEGMENT_COUNT)
+		aac_build_sg64(scsicmd, &writecmd->sg);
+		if(writecmd->sg.count > MAX_DRIVER_SG_SEGMENT_COUNT)
 			BUG();
+		fibsize = sizeof(struct aac_write64) + ((writecmd->sg.count - 1) * sizeof (struct sgentry64));
+		/*
+		 *	Now send the Fib to the adapter
+		 */
+		status = fib_send(ContainerCommand64, 
+			  cmd_fibcontext, 
+			  fibsize, 
+			  FsaNormal, 
+			  0, 1, 
+			  (fib_callback) write_callback, 
+			  (void *) scsicmd);
 	}
-	else if(scsicmd->request_bufflen)
+	else 
 	{
-		dma_addr_t addr; 
-		addr = pci_map_single(dev->pdev,
-				scsicmd->request_buffer,
-				scsicmd->request_bufflen,
-				scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
-		writecmd->sg.sg[0].addr = cpu_to_le32(addr);
-		writecmd->sg.sg[0].count = cpu_to_le32(scsicmd->request_bufflen);  
-		scsicmd->SCp.ptr = (void *)(long)addr;
-		byte_count = scsicmd->request_bufflen;
+		struct aac_write *writecmd;
+		writecmd = (struct aac_write *) fib_data(cmd_fibcontext);
+		writecmd->command = cpu_to_le32(VM_CtBlockWrite);
+		writecmd->cid = cpu_to_le32(cid);
+		writecmd->block = cpu_to_le32(lba);
+		writecmd->count = cpu_to_le32(count * 512);
+		writecmd->sg.count = cpu_to_le32(1);
+		/* ->stable is not used - it did mean which type of write */
 
-		if (byte_count > (64 * 1024))
+		if (count * 512 > (64 * 1024))
+			BUG();
+		aac_build_sg(scsicmd, &writecmd->sg);
+		if(writecmd->sg.count > MAX_DRIVER_SG_SEGMENT_COUNT)
 			BUG();
+		fibsize = sizeof(struct aac_write) + ((writecmd->sg.count - 1) * sizeof (struct sgentry));
+		/*
+		 *	Now send the Fib to the adapter
+		 */
+		status = fib_send(ContainerCommand, 
+			  cmd_fibcontext, 
+			  fibsize, 
+			  FsaNormal, 
+			  0, 1, 
+			  (fib_callback) write_callback, 
+			  (void *) scsicmd);
 	}
-	if (byte_count != writecmd->count)
-		BUG();
-	/*
-	 *	Now send the Fib to the adapter
-	 */
-	fibsize = sizeof (struct aac_write) + ((writecmd->sg.count - 1) * sizeof (struct sgentry));
 
-	status = fib_send(ContainerCommand, 
-			  cmd_fibcontext,
-			  fibsize, FsaNormal,
-			  0, 1,
-			  (fib_callback) write_callback,
-			  (void *) scsicmd);
 	/*
 	 *	Check that the command queued to the controller
 	 */
@@ -821,7 +860,7 @@
  
 int aac_scsi_cmd(Scsi_Cmnd * scsicmd)
 {
-	int cid = 0;
+	u32 cid = 0;
 	struct fsa_scsi_hba *fsa_dev_ptr;
 	int cardtype;
 	int ret;
@@ -837,159 +876,174 @@
 	 *	itself.
 	 */
 	if (scsicmd->target != scsicmd->host->this_id) {
-		if ((scsicmd->channel > 0) ||(scsicmd->target > 15) || (scsicmd->lun > 7)) 
-		{
-			dprintk((KERN_DEBUG "The bus, target or lun is out of range = %d, %d, %d.\n", 
-				scsicmd->channel, scsicmd->target, scsicmd->lun));
-			scsicmd->result = DID_BAD_TARGET << 16;
-			__aac_io_done(scsicmd);
-			return -1;
-		}
-		cid = TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun);
-		/*
-		 *	If the target container doesn't exist, it may have
-		 *	been newly created
-		 */
-		if (fsa_dev_ptr->valid[cid] == 0) {
-			switch (scsicmd->cmnd[0]) {
-			case SS_INQUIR:
-			case SS_RDCAP:
-			case SS_TEST:
-				spin_unlock_irq(&io_request_lock);
-				probe_container(dev, cid);
-				spin_lock_irq(&io_request_lock);
-			default:
-				break;
+		if ((scsicmd->channel == 0) ){
+			if( (scsicmd->target >= AAC_MAX_TARGET) || (scsicmd->lun != 0)){ 
+				scsicmd->result = DID_NO_CONNECT << 16;
+				__aac_io_done(scsicmd);
+				return 0;
+			}
+			cid = TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun);
+
+			/*
+			 *	If the target container doesn't exist, it may have
+			 *	been newly created
+			 */
+			if (fsa_dev_ptr->valid[cid] == 0) {
+				switch (scsicmd->cmnd[0]) {
+				case SS_INQUIR:
+				case SS_RDCAP:
+				case SS_TEST:
+					spin_unlock_irq(&io_request_lock);
+					probe_container(dev, cid);
+					spin_lock_irq(&io_request_lock);
+					if (fsa_dev_ptr->valid[cid] == 0) {
+						scsicmd->result = DID_NO_CONNECT << 16;
+						__aac_io_done(scsicmd);
+						return 0;
+					}
+				default:
+					break;
+				}
+			}
+			/*
+			 *	If the target container still doesn't exist, 
+			 *	return failure
+			 */
+			if (fsa_dev_ptr->valid[cid] == 0) {
+				scsicmd->result = DID_BAD_TARGET << 16;
+				__aac_io_done(scsicmd);
+				return -1;
+			}
+		} else {  /* check for physical non-dasd devices */
+			if(dev->nondasd_support == 1){
+				return aac_send_srb_fib(scsicmd);
+			} else {
+				scsicmd->result = DID_NO_CONNECT << 16;
+				__aac_io_done(scsicmd);
+				return 0;
 			}
 		}
-		/*
-		 *	If the target container still doesn't exist, 
-		 *	return failure
-		 */
-		if (fsa_dev_ptr->valid[cid] == 0) {
-			scsicmd->result = DID_BAD_TARGET << 16;
-			__aac_io_done(scsicmd);
-			return -1;
-		}
-	} 
+	}
+	/*
+	 * else Command for the controller itself
+	 */
 	else if ((scsicmd->cmnd[0] != SS_INQUIR) &&	/* only INQUIRY & TUR cmnd supported for controller */
-	    (scsicmd->cmnd[0] != SS_TEST)) 
+		(scsicmd->cmnd[0] != SS_TEST)) 
 	{
-		/*
-		 *	Command aimed at the controller
-		 */
 		dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0]));
 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
-		set_sense((char *) &sense_data[cid],
+		set_sense((u8 *) &sense_data[cid],
 			    SENKEY_ILLEGAL,
 			    SENCODE_INVALID_COMMAND,
 			    ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
 		__aac_io_done(scsicmd);
 		return -1;
 	}
+
+
 	/* Handle commands here that don't really require going out to the adapter */
-	switch (scsicmd->cmnd[0]) 
+	switch (scsicmd->cmnd[0]) {
+	case SS_INQUIR:
 	{
-		case SS_INQUIR:
-		{
-			struct inquiry_data *inq_data_ptr;
-
-			dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->target));
-			inq_data_ptr = (struct inquiry_data *)scsicmd->request_buffer;
-			memset(inq_data_ptr, 0, sizeof (struct inquiry_data));
-
-			inq_data_ptr->inqd_ver = 2;	/* claim compliance to SCSI-2 */
-			inq_data_ptr->inqd_dtq = 0x80;	/* set RMB bit to one indicating that the medium is removable */
-			inq_data_ptr->inqd_rdf = 2;	/* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
-			inq_data_ptr->inqd_len = 31;
+		struct inquiry_data *inq_data_ptr;
 
-			/*
-			 *	Set the Vendor, Product, and Revision Level
-			 *	see: <vendor>.c i.e. aac.c
-			 */
-			setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr->type[cid]);
-			if (scsicmd->target == scsicmd->host->this_id)
-			    	inq_data_ptr->inqd_pdt = INQD_PDT_PROC;	/* Processor device */
-			else
-				inq_data_ptr->inqd_pdt = INQD_PDT_DA;	/* Direct/random access device */
-			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
-			__aac_io_done(scsicmd);
-			return 0;
-		}
-		case SS_RDCAP:
-		{
-			int capacity;
-			char *cp;
-
-			dprintk((KERN_DEBUG "READ CAPACITY command.\n"));
-			capacity = fsa_dev_ptr->size[cid] - 1;
-			cp = scsicmd->request_buffer;
-			cp[0] = (capacity >> 24) & 0xff;
-			cp[1] = (capacity >> 16) & 0xff;
-			cp[2] = (capacity >> 8) & 0xff;
-			cp[3] = (capacity >> 0) & 0xff;
-			cp[4] = 0;
-			cp[5] = 0;
-			cp[6] = 2;
-			cp[7] = 0;
+		dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->target));
+		inq_data_ptr = (struct inquiry_data *)scsicmd->request_buffer;
+		memset(inq_data_ptr, 0, sizeof (struct inquiry_data));
+
+		inq_data_ptr->inqd_ver = 2;	/* claim compliance to SCSI-2 */
+		inq_data_ptr->inqd_dtq = 0x80;	/* set RMB bit to one indicating that the medium is removable */
+		inq_data_ptr->inqd_rdf = 2;	/* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
+		inq_data_ptr->inqd_len = 31;
+		/*Format for "pad2" is  RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
+		inq_data_ptr->inqd_pad2= 0x32 ;	 /*WBus16|Sync|CmdQue */
+		/*
+		 *	Set the Vendor, Product, and Revision Level
+		 *	see: <vendor>.c i.e. aac.c
+		 */
+		setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr->type[cid]);
+		if (scsicmd->target == scsicmd->host->this_id)
+			inq_data_ptr->inqd_pdt = INQD_PDT_PROC;	/* Processor device */
+		else
+			inq_data_ptr->inqd_pdt = INQD_PDT_DA;	/* Direct/random access device */
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+		__aac_io_done(scsicmd);
+		return 0;
+	}
+	case SS_RDCAP:
+	{
+		int capacity;
+		char *cp;
 
-			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
-			__aac_io_done(scsicmd);
+		dprintk((KERN_DEBUG "READ CAPACITY command.\n"));
+		capacity = fsa_dev_ptr->size[cid] - 1;
+		cp = scsicmd->request_buffer;
+		cp[0] = (capacity >> 24) & 0xff;
+		cp[1] = (capacity >> 16) & 0xff;
+		cp[2] = (capacity >> 8) & 0xff;
+		cp[3] = (capacity >> 0) & 0xff;
+		cp[4] = 0;
+		cp[5] = 0;
+		cp[6] = 2;
+		cp[7] = 0;
 
-			return 0;
-		}
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+		__aac_io_done(scsicmd);
 
-		case SS_MODESEN:
-		{
-			char *mode_buf;
-
-			dprintk((KERN_DEBUG "MODE SENSE command.\n"));
-			mode_buf = scsicmd->request_buffer;
-			mode_buf[0] = 0;	/* Mode data length (MSB) */
-			mode_buf[1] = 6;	/* Mode data length (LSB) */
-			mode_buf[2] = 0;	/* Medium type - default */
-			mode_buf[3] = 0;	/* Device-specific param, bit 8: 0/1 = write enabled/protected */
-			mode_buf[4] = 0;	/* reserved */
-			mode_buf[5] = 0;	/* reserved */
-			mode_buf[6] = 0;	/* Block descriptor length (MSB) */
-			mode_buf[7] = 0;	/* Block descriptor length (LSB) */
+		return 0;
+	}
 
-			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
-			__aac_io_done(scsicmd);
+	case SS_MODESEN:
+	{
+		char *mode_buf;
 
-			return 0;
-		}
-		case SS_REQSEN:
-			dprintk((KERN_DEBUG "REQUEST SENSE command.\n"));
-			memcpy(scsicmd->sense_buffer, &sense_data[cid], sizeof (struct sense_data));
-			memset(&sense_data[cid], 0, sizeof (struct sense_data));
-			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
-			__aac_io_done(scsicmd);
-			return (0);
+		dprintk((KERN_DEBUG "MODE SENSE command.\n"));
+		mode_buf = scsicmd->request_buffer;
+		mode_buf[0] = 0;	/* Mode data length (MSB) */
+		mode_buf[1] = 6;	/* Mode data length (LSB) */
+		mode_buf[2] = 0;	/* Medium type - default */
+		mode_buf[3] = 0;	/* Device-specific param, bit 8: 0/1 = write enabled/protected */
+		mode_buf[4] = 0;	/* reserved */
+		mode_buf[5] = 0;	/* reserved */
+		mode_buf[6] = 0;	/* Block descriptor length (MSB) */
+		mode_buf[7] = 0;	/* Block descriptor length (LSB) */
 
-		case SS_LOCK:
-			dprintk((KERN_DEBUG "LOCK command.\n"));
-			if (scsicmd->cmnd[4])
-				fsa_dev_ptr->locked[cid] = 1;
-			else
-				fsa_dev_ptr->locked[cid] = 0;
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+		__aac_io_done(scsicmd);
 
-			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
-			__aac_io_done(scsicmd);
-			return 0;
-		/*
-		 *	These commands are all No-Ops
-		 */
-		case SS_TEST:
-		case SS_RESERV:
-		case SS_RELES:
-		case SS_REZERO:
-		case SS_REASGN:
-		case SS_SEEK:
-		case SS_ST_SP:
-			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
-			__aac_io_done(scsicmd);
-			return (0);
+		return 0;
+	}
+	case SS_REQSEN:
+		dprintk((KERN_DEBUG "REQUEST SENSE command.\n"));
+		memcpy(scsicmd->sense_buffer, &sense_data[cid], sizeof (struct sense_data));
+		memset(&sense_data[cid], 0, sizeof (struct sense_data));
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+		__aac_io_done(scsicmd);
+		return (0);
+
+	case SS_LOCK:
+		dprintk((KERN_DEBUG "LOCK command.\n"));
+		if (scsicmd->cmnd[4])
+			fsa_dev_ptr->locked[cid] = 1;
+		else
+			fsa_dev_ptr->locked[cid] = 0;
+
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+		__aac_io_done(scsicmd);
+		return 0;
+	/*
+	 *	These commands are all No-Ops
+	 */
+	case SS_TEST:
+	case SS_RESERV:
+	case SS_RELES:
+	case SS_REZERO:
+	case SS_REASGN:
+	case SS_SEEK:
+	case SS_ST_SP:
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+		__aac_io_done(scsicmd);
+		return (0);
 	}
 
 	switch (scsicmd->cmnd[0]) 
@@ -1020,7 +1074,7 @@
 			 */
 			printk(KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0]);
 			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
-			set_sense((char *) &sense_data[cid],
+			set_sense((u8 *) &sense_data[cid],
 				SENKEY_ILLEGAL, SENCODE_INVALID_COMMAND,
 			ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
 			__aac_io_done(scsicmd);
@@ -1153,3 +1207,452 @@
 	}
 }
 
+/**
+ *
+ * aac_srb_callback
+ * @context: the context set in the fib - here it is scsi cmd
+ * @fibptr: pointer to the fib
+ *
+ * Handles the completion of a scsi command to a non dasd device
+ *
+ */
+
+static void aac_srb_callback(void *context, struct fib * fibptr)
+{
+	struct aac_dev *dev;
+	struct aac_srb_reply *srbreply;
+	Scsi_Cmnd *scsicmd;
+
+	scsicmd = (Scsi_Cmnd *) context;
+	dev = (struct aac_dev *)scsicmd->host->hostdata;
+
+	if (fibptr == NULL)
+		BUG();
+
+	srbreply = (struct aac_srb_reply *) fib_data(fibptr);
+
+	scsicmd->sense_buffer[0] = '\0';  // initialize sense valid flag to false
+	// calculate resid for sg 
+	scsicmd->resid = scsicmd->request_bufflen - srbreply->data_xfer_length;
+
+	if(scsicmd->use_sg)
+		pci_unmap_sg(dev->pdev, 
+			(struct scatterlist *)scsicmd->buffer,
+			scsicmd->use_sg,
+			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+	else if(scsicmd->request_bufflen)
+		pci_unmap_single(dev->pdev, (ulong)scsicmd->SCp.ptr, scsicmd->request_bufflen,
+			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+
+	/*
+	 * First check the fib status
+	 */
+
+	if (le32_to_cpu(srbreply->status) != ST_OK){
+		int len;
+		printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status));
+		len = (srbreply->sense_data_size > sizeof(scsicmd->sense_buffer))?
+				sizeof(scsicmd->sense_buffer):srbreply->sense_data_size;
+		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
+	}
+
+	/*
+	 * Next check the srb status
+	 */
+	switch(le32_to_cpu(srbreply->srb_status)){
+	case SRB_STATUS_ERROR_RECOVERY:
+	case SRB_STATUS_PENDING:
+	case SRB_STATUS_SUCCESS:
+		if(scsicmd->cmnd[0] == INQUIRY ){
+			u8 b;
+			/* We can't expose disk devices because we can't tell whether they
+			 * are the raw container drives or stand alone drives
+			 */
+			b = *(u8*)scsicmd->buffer;
+			if( (b & 0x0f) == TYPE_DISK ){
+				scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
+			}
+		} else {
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+		}
+		break;
+	case SRB_STATUS_DATA_OVERRUN:
+		switch(scsicmd->cmnd[0]){
+		case  READ_6:
+		case  WRITE_6:
+		case  READ_10:
+		case  WRITE_10:
+		case  READ_12:
+		case  WRITE_12:
+			if(le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow ) {
+				printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
+			} else {
+				printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n");
+			}
+			scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
+			break;
+		default:
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+			break;
+		}
+		break;
+	case SRB_STATUS_ABORTED:
+		scsicmd->result = DID_ABORT << 16 | ABORT << 8;
+		break;
+	case SRB_STATUS_ABORT_FAILED:
+		// Not sure about this one - but assuming the hba was trying to abort for some reason
+		scsicmd->result = DID_ERROR << 16 | ABORT << 8;
+		break;
+	case SRB_STATUS_PARITY_ERROR:
+		scsicmd->result = DID_PARITY << 16 | MSG_PARITY_ERROR << 8;
+		break;
+	case SRB_STATUS_NO_DEVICE:
+	case SRB_STATUS_INVALID_PATH_ID:
+	case SRB_STATUS_INVALID_TARGET_ID:
+	case SRB_STATUS_INVALID_LUN:
+	case SRB_STATUS_SELECTION_TIMEOUT:
+		scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
+		break;
+
+	case SRB_STATUS_COMMAND_TIMEOUT:
+	case SRB_STATUS_TIMEOUT:
+		scsicmd->result = DID_TIME_OUT << 16 | COMMAND_COMPLETE << 8;
+		break;
+
+	case SRB_STATUS_BUSY:
+		scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
+		break;
+
+	case SRB_STATUS_BUS_RESET:
+		scsicmd->result = DID_RESET << 16 | COMMAND_COMPLETE << 8;
+		break;
+
+	case SRB_STATUS_MESSAGE_REJECTED:
+		scsicmd->result = DID_ERROR << 16 | MESSAGE_REJECT << 8;
+		break;
+	case SRB_STATUS_REQUEST_FLUSHED:
+	case SRB_STATUS_ERROR:
+	case SRB_STATUS_INVALID_REQUEST:
+	case SRB_STATUS_REQUEST_SENSE_FAILED:
+	case SRB_STATUS_NO_HBA:
+	case SRB_STATUS_UNEXPECTED_BUS_FREE:
+	case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
+	case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
+	case SRB_STATUS_DELAYED_RETRY:
+	case SRB_STATUS_BAD_FUNCTION:
+	case SRB_STATUS_NOT_STARTED:
+	case SRB_STATUS_NOT_IN_USE:
+	case SRB_STATUS_FORCE_ABORT:
+	case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
+	default:
+#ifdef AAC_DETAILED_STATUS_INFO
+		printk("aacraid: SRB ERROR (%s)\n",aac_get_status_string(le32_to_cpu(srbreply->srb_status)));
+#endif
+		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
+		break;
+	}
+	if (le32_to_cpu(srbreply->scsi_status) == 0x02 ){  // Check Condition
+		int len;
+		len = (srbreply->sense_data_size > sizeof(scsicmd->sense_buffer))?
+				sizeof(scsicmd->sense_buffer):srbreply->sense_data_size;
+		printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", le32_to_cpu(srbreply->status), len);
+		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
+	}
+	/*
+	 * OR in the scsi status (already shifted up a bit)
+	 */
+	scsicmd->result |= le32_to_cpu(srbreply->scsi_status);
+
+	fib_complete(fibptr);
+	fib_free(fibptr);
+	aac_io_done(scsicmd);
+}
+
+/**
+ *
+ * aac_send_scb_fib
+ * @scsicmd: the scsi command block
+ *
+ * This routine will form a FIB and fill in the aac_srb from the 
+ * scsicmd passed in.
+ */
+
+static int aac_send_srb_fib(Scsi_Cmnd* scsicmd)
+{
+	struct fib* cmd_fibcontext;
+	struct aac_dev* dev;
+	int status;
+	struct aac_srb *srbcmd;
+	u16 fibsize;
+	u32 flag;
+
+	if( scsicmd->target > 15 || scsicmd->lun > 7) {
+		scsicmd->result = DID_NO_CONNECT << 16;
+		__aac_io_done(scsicmd);
+		return 0;
+	}
+
+	dev = (struct aac_dev *)scsicmd->host->hostdata;
+	switch(scsicmd->sc_data_direction){
+	case SCSI_DATA_WRITE:
+		flag = SRB_DataOut;
+		break;
+	case SCSI_DATA_UNKNOWN:  
+		flag = SRB_DataIn | SRB_DataOut;
+		break;
+	case SCSI_DATA_READ:
+		flag = SRB_DataIn;
+		break;
+	case SCSI_DATA_NONE: 
+	default:
+		flag = SRB_NoDataXfer;
+		break;
+	}
+
+
+	/*
+	 *	Allocate and initialize a Fib then setup a BlockWrite command
+	 */
+	if (!(cmd_fibcontext = fib_alloc(dev))) {
+		scsicmd->result = DID_ERROR << 16;
+		__aac_io_done(scsicmd);
+		return -1;
+	}
+	fib_init(cmd_fibcontext);
+
+	srbcmd = (struct aac_srb*) fib_data(cmd_fibcontext);
+	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
+	srbcmd->channel  = cpu_to_le32(aac_logical_to_phys(scsicmd->channel));
+	srbcmd->target   = cpu_to_le32(scsicmd->target);
+	srbcmd->lun      = cpu_to_le32(scsicmd->lun);
+	srbcmd->flags    = cpu_to_le32(flag);
+	srbcmd->timeout  = cpu_to_le32(0);  // timeout not used
+	srbcmd->retry_limit =cpu_to_le32(0); // Obsolete parameter
+	srbcmd->cdb_size = cpu_to_le32(scsicmd->cmd_len);
+	
+	if( dev->pae_support ==1 ) {
+		aac_build_sg64(scsicmd, (struct sgmap64*) &srbcmd->sg);
+		srbcmd->count = cpu_to_le32(scsicmd->request_bufflen);
+
+		memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
+		memcpy(srbcmd->cdb, scsicmd->cmnd, scsicmd->cmd_len);
+		/*
+		 *	Build Scatter/Gather list
+		 */
+		fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry64));
+
+		/*
+		 *	Now send the Fib to the adapter
+		 */
+		status = fib_send(ScsiPortCommand64, cmd_fibcontext, fibsize, FsaNormal, 0, 1,
+				  (fib_callback) aac_srb_callback, (void *) scsicmd);
+	} else {
+		aac_build_sg(scsicmd, (struct sgmap*)&srbcmd->sg);
+		srbcmd->count = cpu_to_le32(scsicmd->request_bufflen);
+
+		memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
+		memcpy(srbcmd->cdb, scsicmd->cmnd, scsicmd->cmd_len);
+		/*
+		 *	Build Scatter/Gather list
+		 */
+		fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
+
+		/*
+		 *	Now send the Fib to the adapter
+		 */
+		status = fib_send(ScsiPortCommand, cmd_fibcontext, fibsize, FsaNormal, 0, 1,
+				  (fib_callback) aac_srb_callback, (void *) scsicmd);
+	}
+	/*
+	 *	Check that the command queued to the controller
+	 */
+	if (status == -EINPROGRESS){
+		return 0;
+	}
+
+	printk(KERN_WARNING "aac_srb: fib_send failed with status: %d\n", status);
+	/*
+	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
+	 */
+	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | QUEUE_FULL;
+	__aac_io_done(scsicmd);
+
+	fib_complete(cmd_fibcontext);
+	fib_free(cmd_fibcontext);
+
+	return -1;
+}
+
+static unsigned long aac_build_sg(Scsi_Cmnd* scsicmd, struct sgmap* psg)
+{
+	struct aac_dev *dev;
+	unsigned long byte_count = 0;
+
+	dev = (struct aac_dev *)scsicmd->host->hostdata;
+	// Get rid of old data
+	psg->count = cpu_to_le32(0);
+	psg->sg[0].addr = cpu_to_le32(NULL);
+	psg->sg[0].count = cpu_to_le32(0);  
+	if (scsicmd->use_sg) {
+		struct scatterlist *sg;
+		int i;
+		int sg_count;
+		sg = (struct scatterlist *) scsicmd->request_buffer;
+
+		sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
+			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+		psg->count = cpu_to_le32(sg_count);
+
+		byte_count = 0;
+
+		for (i = 0; i < sg_count; i++) {
+			psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg));
+			psg->sg[i].count = cpu_to_le32(sg_dma_len(sg));
+			byte_count += sg_dma_len(sg);
+			sg++;
+		}
+		/* hba wants the size to be exact */
+		if(byte_count > scsicmd->request_bufflen){
+			psg->sg[i-1].count -= (byte_count - scsicmd->request_bufflen);
+			byte_count = scsicmd->request_bufflen;
+		}
+		/* Check for command underflow */
+		if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
+			printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
+					byte_count, scsicmd->underflow);
+		}
+	}
+	else if(scsicmd->request_bufflen) {
+		dma_addr_t addr; 
+		addr = pci_map_single(dev->pdev,
+				scsicmd->request_buffer,
+				scsicmd->request_bufflen,
+				scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+		psg->count = cpu_to_le32(1);
+		psg->sg[0].addr = cpu_to_le32(addr);
+		psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen);  
+		scsicmd->SCp.ptr = (void *)addr;
+		byte_count = scsicmd->request_bufflen;
+	}
+	return byte_count;
+}
+
+
+static unsigned long aac_build_sg64(Scsi_Cmnd* scsicmd, struct sgmap64* psg)
+{
+	struct aac_dev *dev;
+	unsigned long byte_count = 0;
+	u64 le_addr;
+
+	dev = (struct aac_dev *)scsicmd->host->hostdata;
+	// Get rid of old data
+	psg->count = cpu_to_le32(0);
+	psg->sg[0].addr[0] = cpu_to_le32(NULL);
+	psg->sg[0].addr[1] = cpu_to_le32(NULL);
+	psg->sg[0].count = cpu_to_le32(0);  
+	if (scsicmd->use_sg) {
+		struct scatterlist *sg;
+		int i;
+		int sg_count;
+		sg = (struct scatterlist *) scsicmd->request_buffer;
+
+		sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
+			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+		psg->count = cpu_to_le32(sg_count);
+
+		byte_count = 0;
+
+		for (i = 0; i < sg_count; i++) {
+			le_addr = cpu_to_le64(sg_dma_address(sg));
+			psg->sg[i].addr[1] = (u32)(le_addr>>32);
+			psg->sg[i].addr[0] = (u32)(le_addr & 0xffffffff);
+			psg->sg[i].count = cpu_to_le32(sg_dma_len(sg));
+			byte_count += sg_dma_len(sg);
+			sg++;
+		}
+		/* hba wants the size to be exact */
+		if(byte_count > scsicmd->request_bufflen){
+			psg->sg[i-1].count -= (byte_count - scsicmd->request_bufflen);
+			byte_count = scsicmd->request_bufflen;
+		}
+		/* Check for command underflow */
+		if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
+			printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
+					byte_count, scsicmd->underflow);
+		}
+	}
+	else if(scsicmd->request_bufflen) {
+		dma_addr_t addr; 
+		addr = pci_map_single(dev->pdev,
+				scsicmd->request_buffer,
+				scsicmd->request_bufflen,
+				scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
+		psg->count = cpu_to_le32(1);
+		le_addr = cpu_to_le64(addr);
+		psg->sg[0].addr[1] = (u32)(le_addr>>32);
+		psg->sg[0].addr[0] = (u32)(le_addr & 0xffffffff);
+		psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen);  
+		scsicmd->SCp.ptr = (void *)addr;
+		byte_count = scsicmd->request_bufflen;
+	}
+	return byte_count;
+}
+
+#ifdef AAC_DETAILED_STATUS_INFO
+
+struct aac_srb_status_info {
+	u32	status;
+	char	*str;
+};
+
+
+static struct aac_srb_status_info srb_status_info[] = {
+	{ SRB_STATUS_PENDING,		"Pending Status"},
+	{ SRB_STATUS_SUCCESS,		"Success"},
+	{ SRB_STATUS_ABORTED,		"Aborted Command"},
+	{ SRB_STATUS_ABORT_FAILED,	"Abort Failed"},
+	{ SRB_STATUS_ERROR,		"Error Event"}, 
+	{ SRB_STATUS_BUSY,		"Device Busy"},
+	{ SRB_STATUS_INVALID_REQUEST,	"Invalid Request"},
+	{ SRB_STATUS_INVALID_PATH_ID,	"Invalid Path ID"},
+	{ SRB_STATUS_NO_DEVICE,		"No Device"},
+	{ SRB_STATUS_TIMEOUT,		"Timeout"},
+	{ SRB_STATUS_SELECTION_TIMEOUT,	"Selection Timeout"},
+	{ SRB_STATUS_COMMAND_TIMEOUT,	"Command Timeout"},
+	{ SRB_STATUS_MESSAGE_REJECTED,	"Message Rejected"},
+	{ SRB_STATUS_BUS_RESET,		"Bus Reset"},
+	{ SRB_STATUS_PARITY_ERROR,	"Parity Error"},
+	{ SRB_STATUS_REQUEST_SENSE_FAILED,"Request Sense Failed"},
+	{ SRB_STATUS_NO_HBA,		"No HBA"},
+	{ SRB_STATUS_DATA_OVERRUN,	"Data Overrun/Data Underrun"},
+	{ SRB_STATUS_UNEXPECTED_BUS_FREE,"Unexpected Bus Free"},
+	{ SRB_STATUS_PHASE_SEQUENCE_FAILURE,"Phase Error"},
+	{ SRB_STATUS_BAD_SRB_BLOCK_LENGTH,"Bad Srb Block Length"},
+	{ SRB_STATUS_REQUEST_FLUSHED,	"Request Flushed"},
+	{ SRB_STATUS_DELAYED_RETRY,	"Delayed Retry"},
+	{ SRB_STATUS_INVALID_LUN,	"Invalid LUN"}, 
+	{ SRB_STATUS_INVALID_TARGET_ID,	"Invalid TARGET ID"},
+	{ SRB_STATUS_BAD_FUNCTION,	"Bad Function"},
+	{ SRB_STATUS_ERROR_RECOVERY,	"Error Recovery"},
+	{ SRB_STATUS_NOT_STARTED,	"Not Started"},
+	{ SRB_STATUS_NOT_IN_USE,	"Not In Use"},
+    	{ SRB_STATUS_FORCE_ABORT,	"Force Abort"},
+	{ SRB_STATUS_DOMAIN_VALIDATION_FAIL,"Domain Validation Failure"},
+	{ 0xff,				"Unknown Error"}
+};
+
+char *aac_get_status_string(u32 status)
+{
+	int i;
+
+	for(i=0; i < (sizeof(srb_status_info)/sizeof(struct aac_srb_status_info)); i++ ){
+		if(srb_status_info[i].status == status){
+			return srb_status_info[i].str;
+		}
+	}
+
+	return "Bad Status Code";
+}
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aacraid/aacraid.h linux-2.4.20/drivers/scsi/aacraid/aacraid.h
--- linux-2.4.19/drivers/scsi/aacraid/aacraid.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aacraid/aacraid.h	2002-10-29 11:18:50.000000000 +0000
@@ -1,12 +1,29 @@
 #define dprintk(x)
-
-#define AAC_NUM_FIB	128
-#define AAC_NUM_IO_FIB	116
+/*#define dprintk(x) printk x */
 
 /*------------------------------------------------------------------------------
  *              D E F I N E S
  *----------------------------------------------------------------------------*/
 
+#define MAXIMUM_NUM_CONTAINERS	31
+#define MAXIMUM_NUM_ADAPTERS	8
+
+#define AAC_NUM_FIB	578
+#define AAC_NUM_IO_FIB	512
+
+#define AAC_MAX_TARGET (MAXIMUM_NUM_CONTAINERS+1)
+//#define AAC_MAX_TARGET 	(16)
+#define AAC_MAX_LUN	(8)
+
+/*
+ * These macros convert from physical channels to virtual channels
+ */
+#define CONTAINER_CHANNEL	(0)
+#define aac_phys_to_logical(x)  (x+1)
+#define aac_logical_to_phys(x)  (x?x-1:0)
+
+#define AAC_DETAILED_STATUS_INFO
+
 struct diskparm
 {
 	int heads;
@@ -62,10 +79,16 @@
 /*
  *	Host side memory scatter gather list
  *	Used by the adapter for read, write, and readdirplus operations
+ *	We have seperate 32 and 64 bit version because even
+ *	on 64 bit systems not all cards support the 64 bit version
  */
-
 struct sgentry {
-	u32	addr;	/* 32-bit Base address. */
+	u32	addr;	/* 32-bit address. */
+	u32	count;	/* Length. */
+};
+
+struct sgentry64 {
+	u32	addr[2];	/* 64-bit addr. 2 pieces for data alignment */
 	u32	count;	/* Length. */
 };
 
@@ -74,15 +97,16 @@
  *
  *	This is the SGMAP structure for all commands that use
  *	32-bit addressing.
- *
- *	Note that the upper 16 bits of SgCount are used as flags.
- *	Only the lower 16 bits of SgCount are actually used as the
- *	SG element count.
  */
 
 struct sgmap {
 	u32		count;
-	struct sgentry	sg[1];
+	struct sgentry	sg[1]; 
+};
+
+struct sgmap64 {
+	u32		count;
+	struct sgentry64 sg[1];
 };
 
 struct creation_info
@@ -100,7 +124,7 @@
 						 * unsigned 	Minute		:6;	// 0 - 60
 						 * unsigned 	Second		:6;	// 0 - 60
 						 */
-	u64		serial;			/* e.g., 0x1DEADB0BFAFAF001 */
+	u32		serial[2];			/* e.g., 0x1DEADB0BFAFAF001 */
 };
 
 
@@ -145,8 +169,8 @@
  */
 
 struct aac_entry {
-	u32 size;       /* Size in bytes of the Fib which this QE points to */
-	u32 addr;	/* Receiver addressable address of the FIB (low 32 address bits) */
+	u32 size;          /* Size in bytes of Fib which this QE points to */
+	u32 addr; /* Receiver address of the FIB */
 };
 
 /*
@@ -225,10 +249,10 @@
 #define		FsaNormal	1
 #define		FsaHigh		2
 
-//
-// Define the FIB. The FIB is the where all the requested data and
-// command information are put to the application on the FSA adapter.
-//
+/*
+ * Define the FIB. The FIB is the where all the requested data and
+ * command information are put to the application on the FSA adapter.
+ */
 
 struct aac_fibhdr {
 	u32 XferState;			// Current transfer state for this CCB
@@ -308,6 +332,7 @@
  *	Scsi Port commands (scsi passthrough)
  */
 #define		ScsiPortCommand			600
+#define		ScsiPortCommand64		601
 /*
  *	Misc house keeping and generic adapter initiated commands
  */
@@ -395,6 +420,7 @@
 	void (*adapter_notify)(struct aac_dev *dev, u32 event);
 	void (*adapter_enable_int)(struct aac_dev *dev, u32 event);
 	void (*adapter_disable_int)(struct aac_dev *dev, u32 event);
+	int  (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 *status);
 };
 
 /*
@@ -411,6 +437,7 @@
 	char *	name;
 	char *	vname;
 	char *	model;
+	u16	channels;
 };
 
 /*
@@ -459,29 +486,29 @@
 struct sa_drawbridge_CSR {
 						//	 Offset |	Name
 	u32	reserved[10];			//	00h-27h |   Reserved
-	u8	LUT_Offset;			//		28h	|	Looup Table Offset
+	u8	LUT_Offset;			//	28h	|	Looup Table Offset
 	u8	reserved1[3];			// 	29h-2bh	|	Reserved
-	u32	LUT_Data;			//		2ch	|	Looup Table Data	
+	u32	LUT_Data;			//	2ch	|	Looup Table Data	
 	u32	reserved2[26];			//	30h-97h	|	Reserved
-	u16	PRICLEARIRQ;			//		98h	|	Primary Clear Irq
-	u16	SECCLEARIRQ;			//		9ah	|	Secondary Clear Irq
-	u16	PRISETIRQ;			//		9ch	|	Primary Set Irq
-	u16	SECSETIRQ;			//		9eh	|	Secondary Set Irq
-	u16	PRICLEARIRQMASK;		//		a0h	|	Primary Clear Irq Mask
-	u16	SECCLEARIRQMASK;		//		a2h	|	Secondary Clear Irq Mask
-	u16	PRISETIRQMASK;			//		a4h	|	Primary Set Irq Mask
-	u16	SECSETIRQMASK;			//		a6h	|	Secondary Set Irq Mask
-	u32	MAILBOX0;			//		a8h	|	Scratchpad 0
-	u32	MAILBOX1;			//		ach	|	Scratchpad 1
-	u32	MAILBOX2;			//		b0h	|	Scratchpad 2
-	u32	MAILBOX3;			//		b4h	|	Scratchpad 3
-	u32	MAILBOX4;			//		b8h	|	Scratchpad 4
-	u32	MAILBOX5;			//		bch	|	Scratchpad 5
-	u32	MAILBOX6;			//		c0h	|	Scratchpad 6
-	u32	MAILBOX7;			//		c4h	|	Scratchpad 7
+	u16	PRICLEARIRQ;			//	98h	|	Primary Clear Irq
+	u16	SECCLEARIRQ;			//	9ah	|	Secondary Clear Irq
+	u16	PRISETIRQ;			//	9ch	|	Primary Set Irq
+	u16	SECSETIRQ;			//	9eh	|	Secondary Set Irq
+	u16	PRICLEARIRQMASK;		//	a0h	|	Primary Clear Irq Mask
+	u16	SECCLEARIRQMASK;		//	a2h	|	Secondary Clear Irq Mask
+	u16	PRISETIRQMASK;			//	a4h	|	Primary Set Irq Mask
+	u16	SECSETIRQMASK;			//	a6h	|	Secondary Set Irq Mask
+	u32	MAILBOX0;			//	a8h	|	Scratchpad 0
+	u32	MAILBOX1;			//	ach	|	Scratchpad 1
+	u32	MAILBOX2;			//	b0h	|	Scratchpad 2
+	u32	MAILBOX3;			//	b4h	|	Scratchpad 3
+	u32	MAILBOX4;			//	b8h	|	Scratchpad 4
+	u32	MAILBOX5;			//	bch	|	Scratchpad 5
+	u32	MAILBOX6;			//	c0h	|	Scratchpad 6
+	u32	MAILBOX7;			//	c4h	|	Scratchpad 7
 
-	u32	ROM_Setup_Data;			//		c8h | 	Rom Setup and Data
-	u32	ROM_Control_Addr;		//		cch | 	Rom Control and Address
+	u32	ROM_Setup_Data;			//	c8h | 	Rom Setup and Data
+	u32	ROM_Control_Addr;		//	cch | 	Rom Control and Address
 
 	u32	reserved3[12];			//	d0h-ffh	| 	reserved
 	u32	LUT[64];			// 100h-1ffh|	Lookup Table Entries
@@ -597,7 +624,7 @@
 struct aac_fib_context {
 	s16	 		type;		// used for verification of structure	
 	s16	 		size;
-	u32			jiffies;	// used for cleanup
+	ulong			jiffies;	// used for cleanup - dmb changed to ulong
 	struct list_head	next;		// used to link context's into a linked list
 	struct semaphore 	wait_sem;	// this is used to wait for the next fib to arrive.
 	int			wait;		// Set to true when thread is in WaitForSingleObject
@@ -605,17 +632,14 @@
 	struct list_head	fibs;
 };
 
-#define MAXIMUM_NUM_CONTAINERS	64		// 4 Luns * 16 Targets
-#define MAXIMUM_NUM_ADAPTERS	8
-
 struct fsa_scsi_hba {
-	unsigned long		size[MAXIMUM_NUM_CONTAINERS];
-	unsigned long		type[MAXIMUM_NUM_CONTAINERS];
-	unsigned char		valid[MAXIMUM_NUM_CONTAINERS];
-	unsigned char		ro[MAXIMUM_NUM_CONTAINERS];
-	unsigned char		locked[MAXIMUM_NUM_CONTAINERS];
-	unsigned char		deleted[MAXIMUM_NUM_CONTAINERS];
-	long			devno[MAXIMUM_NUM_CONTAINERS];
+	u32		size[MAXIMUM_NUM_CONTAINERS];
+	u32		type[MAXIMUM_NUM_CONTAINERS];
+	u8		valid[MAXIMUM_NUM_CONTAINERS];
+	u8		ro[MAXIMUM_NUM_CONTAINERS];
+	u8		locked[MAXIMUM_NUM_CONTAINERS];
+	u8		deleted[MAXIMUM_NUM_CONTAINERS];
+	u32		devno[MAXIMUM_NUM_CONTAINERS];
 };
 
 struct fib {
@@ -634,10 +658,10 @@
 	struct semaphore 	event_wait;
 	spinlock_t		event_lock;
 
-	unsigned long		done;	/* gets set to 1 when fib is complete */
+	u32			done;	/* gets set to 1 when fib is complete */
 	fib_callback 		callback;
 	void 			*callback_data;
-	unsigned long		flags;
+	u32			flags; // u32 dmb was ulong
 	/*
 	 *	The following is used to put this fib context onto the 
 	 *	Outstanding I/O queue.
@@ -648,6 +672,68 @@
 	struct hw_fib		*fib;		/* Actual shared object */
 };
 
+/*
+ *	Adapter Information Block
+ *
+ *	This is returned by the RequestAdapterInfo block
+ */
+ 
+struct aac_adapter_info
+{
+	u32	platform;
+	u32	cpu;
+	u32	subcpu;
+	u32	clock;
+	u32	execmem;
+	u32	buffermem;
+	u32	totalmem;
+	u32	kernelrev;
+	u32	kernelbuild;
+	u32	monitorrev;
+	u32	monitorbuild;
+	u32	hwrev;
+	u32	hwbuild;
+	u32	biosrev;
+	u32	biosbuild;
+	u32	cluster;
+	u32	serial[2];
+	u32	battery;
+	u32	options;
+	u32	OEM;
+};
+
+/*
+ * Battery platforms
+ */
+#define AAC_BAT_REQ_PRESENT	(1)
+#define AAC_BAT_REQ_NOTPRESENT	(2)
+#define AAC_BAT_OPT_PRESENT	(3)
+#define AAC_BAT_OPT_NOTPRESENT	(4)
+#define AAC_BAT_NOT_SUPPORTED	(5)
+/*
+ * cpu types
+ */
+#define AAC_CPU_SIMULATOR	(1)
+#define AAC_CPU_I960		(2)
+#define AAC_CPU_STRONGARM	(3)
+
+/*
+ * Supported Options
+ */
+#define AAC_OPT_SNAPSHOT	cpu_to_le32(1)
+#define AAC_OPT_CLUSTERS	cpu_to_le32(1<<1)
+#define AAC_OPT_WRITE_CACHE	cpu_to_le32(1<<2)
+#define AAC_OPT_64BIT_DATA	cpu_to_le32(1<<3)
+#define AAC_OPT_HOST_TIME_FIB	cpu_to_le32(1<<4)
+#define AAC_OPT_RAID50		cpu_to_le32(1<<5)
+#define AAC_OPT_4GB_WINDOW	cpu_to_le32(1<<6)
+#define AAC_OPT_SCSI_UPGRADEABLE cpu_to_le32(1<<7)
+#define AAC_OPT_SOFT_ERR_REPORT	cpu_to_le32(1<<8)
+#define AAC_OPT_SUPPORTED_RECONDITION cpu_to_le32(1<<9)
+#define AAC_OPT_SGMAP_HOST64	cpu_to_le32(1<<10)
+#define AAC_OPT_ALARM		cpu_to_le32(1<<11)
+#define AAC_OPT_NONDASD		cpu_to_le32(1<<12)
+
 struct aac_dev
 {
 	struct aac_dev		*next;
@@ -660,6 +746,9 @@
 	 */	
 	dma_addr_t		hw_fib_pa;
 	struct hw_fib		*hw_fib_va;
+#if BITS_PER_LONG >= 64
+	ulong			fib_base_va;
+#endif
 	/*
 	 *	Fib Headers
 	 */
@@ -706,17 +795,17 @@
 	/*
 	 *	The following is the number of the individual adapter
 	 */
-	long			devnum;
-	int			aif_thread;
+	u32			devnum;
+	u32			aif_thread;
 	struct completion	aif_completion;
+	struct aac_adapter_info adapter_info;
+	/* These are in adapter info but they are in the io flow so
+	 * lets break them out so we don't have to do an AND to check them
+	 */
+	u8			nondasd_support; 
+	u8			pae_support;
 };
 
-#define AllocateAndMapFibSpace(dev, MapFibContext) \
-	dev->a_ops.AllocateAndMapFibSpace(dev, MapFibContext)
-
-#define UnmapAndFreeFibSpace(dev, MapFibContext) \
-	dev->a_ops.UnmapAndFreeFibSpace(dev, MapFibContext)
-
 #define aac_adapter_interrupt(dev) \
 	dev->a_ops.adapter_interrupt(dev)
 
@@ -846,6 +935,17 @@
 	struct sgmap	sg;	// Must be last in struct because it is variable
 };
 
+struct aac_read64
+{
+	u32	 	command;
+	u16 		cid;
+	u16 		sector_count;
+	u32 		block;
+	u16		pad;
+	u16		flags;
+	struct sgmap64	sg;	// Must be last in struct because it is variable
+};
+
 struct aac_read_reply
 {
 	u32	 	status;
@@ -858,10 +958,20 @@
 	u32 		cid;
 	u32 		block;
 	u32 		count;
-	u32	 	stable;
+	u32	 	stable;	// Not used
 	struct sgmap	sg;	// Must be last in struct because it is variable
 };
 
+struct aac_write64
+{
+	u32	 	command;
+	u16 		cid;
+	u16 		sector_count;
+	u32 		block;
+	u16		pad;
+	u16		flags;
+	struct sgmap64	sg;	// Must be last in struct because it is variable
+};
 struct aac_write_reply
 {
 	u32		status;
@@ -869,6 +979,100 @@
 	u32		committed;
 };
 
+struct aac_srb
+{
+	u32		function;
+	u32		channel;
+	u32		target;
+	u32		lun;
+	u32		timeout;
+	u32		flags;
+	u32		count;		// Data xfer size
+	u32		retry_limit;
+	u32		cdb_size;
+	u8		cdb[16];
+	struct	sgmap	sg;
+};
+
+
+
+#define		AAC_SENSE_BUFFERSIZE	 30
+
+struct aac_srb_reply
+{
+	u32		status;
+	u32		srb_status;
+	u32		scsi_status;
+	u32		data_xfer_length;
+	u32		sense_data_size;
+	u8		sense_data[AAC_SENSE_BUFFERSIZE]; // Can this be SCSI_SENSE_BUFFERSIZE
+};
+/*
+ * SRB Flags
+ */
+#define		SRB_NoDataXfer		 0x0000
+#define		SRB_DisableDisconnect	 0x0004
+#define		SRB_DisableSynchTransfer 0x0008
+#define 	SRB_BypassFrozenQueue	 0x0010
+#define		SRB_DisableAutosense	 0x0020
+#define		SRB_DataIn		 0x0040
+#define 	SRB_DataOut		 0x0080
+
+/*
+ * SRB Functions - set in aac_srb->function
+ */
+#define	SRBF_ExecuteScsi	0x0000
+#define	SRBF_ClaimDevice	0x0001
+#define	SRBF_IO_Control		0x0002
+#define	SRBF_ReceiveEvent	0x0003
+#define	SRBF_ReleaseQueue	0x0004
+#define	SRBF_AttachDevice	0x0005
+#define	SRBF_ReleaseDevice	0x0006
+#define	SRBF_Shutdown		0x0007
+#define	SRBF_Flush		0x0008
+#define	SRBF_AbortCommand	0x0010
+#define	SRBF_ReleaseRecovery	0x0011
+#define	SRBF_ResetBus		0x0012
+#define	SRBF_ResetDevice	0x0013
+#define	SRBF_TerminateIO	0x0014
+#define	SRBF_FlushQueue		0x0015
+#define	SRBF_RemoveDevice	0x0016
+#define	SRBF_DomainValidation	0x0017
+
+/* 
+ * SRB SCSI Status - set in aac_srb->scsi_status
+ */
+#define SRB_STATUS_PENDING                  0x00
+#define SRB_STATUS_SUCCESS                  0x01
+#define SRB_STATUS_ABORTED                  0x02
+#define SRB_STATUS_ABORT_FAILED             0x03
+#define SRB_STATUS_ERROR                    0x04
+#define SRB_STATUS_BUSY                     0x05
+#define SRB_STATUS_INVALID_REQUEST          0x06
+#define SRB_STATUS_INVALID_PATH_ID          0x07
+#define SRB_STATUS_NO_DEVICE                0x08
+#define SRB_STATUS_TIMEOUT                  0x09
+#define SRB_STATUS_SELECTION_TIMEOUT        0x0A
+#define SRB_STATUS_COMMAND_TIMEOUT          0x0B
+#define SRB_STATUS_MESSAGE_REJECTED         0x0D
+#define SRB_STATUS_BUS_RESET                0x0E
+#define SRB_STATUS_PARITY_ERROR             0x0F
+#define SRB_STATUS_REQUEST_SENSE_FAILED     0x10
+#define SRB_STATUS_NO_HBA                   0x11
+#define SRB_STATUS_DATA_OVERRUN             0x12
+#define SRB_STATUS_UNEXPECTED_BUS_FREE      0x13
+#define SRB_STATUS_PHASE_SEQUENCE_FAILURE   0x14
+#define SRB_STATUS_BAD_SRB_BLOCK_LENGTH     0x15
+#define SRB_STATUS_REQUEST_FLUSHED          0x16
+#define SRB_STATUS_DELAYED_RETRY	    0x17
+#define SRB_STATUS_INVALID_LUN              0x20
+#define SRB_STATUS_INVALID_TARGET_ID        0x21
+#define SRB_STATUS_BAD_FUNCTION             0x22
+#define SRB_STATUS_ERROR_RECOVERY           0x23
+#define SRB_STATUS_NOT_STARTED		    0x24
+#define SRB_STATUS_NOT_IN_USE		    0x30
+#define SRB_STATUS_FORCE_ABORT		    0x31
+#define SRB_STATUS_DOMAIN_VALIDATION_FAIL   0x32
 
 /*
  * Object-Server / Volume-Manager Dispatch Classes
@@ -893,8 +1097,10 @@
 #define		VM_CtBlockRead64	16
 #define		VM_CtBlockWrite64	17
 #define		VM_CtBlockVerify64	18
+#define		VM_CtHostRead64		19
+#define		VM_CtHostWrite64	20
 
-#define		MAX_VMCOMMAND_NUM	19	/* used for sizing stats array - leave last */
+#define		MAX_VMCOMMAND_NUM	21	/* used for sizing stats array - leave last */
 
 /*
  *	Descriptive information (eg, vital stats)
@@ -926,7 +1132,7 @@
 
 struct aac_mntent {
 	u32    			oid;
-	char			name[16];	// if applicable
+	u8			name[16];	// if applicable
 	struct creation_info	create_info;	// if applicable
 	u32			capacity;
 	u32			vol;    	// substrate structure
@@ -988,9 +1194,9 @@
 
 struct revision
 {
-	int compat;
-	unsigned long version;
-	unsigned long build;
+	u32 compat;
+	u32 version;
+	u32 build;
 };
 	
 /*
@@ -1014,36 +1220,39 @@
  */
 
 #define FSACTL_SENDFIB                  	CTL_CODE(2050, METHOD_BUFFERED)
+#define FSACTL_SEND_RAW_SRB               	CTL_CODE(2067, METHOD_BUFFERED)
 #define FSACTL_DELETE_DISK			0x163
 #define FSACTL_QUERY_DISK			0x173
 #define FSACTL_OPEN_GET_ADAPTER_FIB		CTL_CODE(2100, METHOD_BUFFERED)
 #define FSACTL_GET_NEXT_ADAPTER_FIB		CTL_CODE(2101, METHOD_BUFFERED)
 #define FSACTL_CLOSE_GET_ADAPTER_FIB		CTL_CODE(2102, METHOD_BUFFERED)
 #define FSACTL_MINIPORT_REV_CHECK               CTL_CODE(2107, METHOD_BUFFERED)
+#define FSACTL_GET_PCI_INFO               	CTL_CODE(2119, METHOD_BUFFERED)
 #define FSACTL_FORCE_DELETE_DISK		CTL_CODE(2120, METHOD_NEITHER)
 
+
 struct aac_common
 {
 	/*
 	 *	If this value is set to 1 then interrupt moderation will occur 
 	 *	in the base commuication support.
 	 */
-	unsigned long irq_mod;
-	int peak_fibs;
-	int zero_fibs;
-	unsigned long fib_timeouts;
+	u32 irq_mod;
+	u32 peak_fibs;
+	u32 zero_fibs;
+	u32 fib_timeouts;
 	/*
 	 *	Statistical counters in debug mode
 	 */
 #ifdef DBG
-	unsigned long FibsSent;
-	unsigned long FibRecved;
-	unsigned long NoResponseSent;
-	unsigned long NoResponseRecved;
-	unsigned long AsyncSent;
-	unsigned long AsyncRecved;
-	unsigned long NormalSent;
-	unsigned long NormalRecved;
+	u32 FibsSent;
+	u32 FibRecved;
+	u32 NoResponseSent;
+	u32 NoResponseRecved;
+	u32 AsyncSent;
+	u32 AsyncRecved;
+	u32 NormalSent;
+	u32 NormalRecved;
 #endif
 };
 
@@ -1063,11 +1272,17 @@
 
 /*
  *	Adapter direct commands
+ *	Monitor/Kernel API
  */
 
-#define	BREAKPOINT_REQUEST		0x00000004
-#define	INIT_STRUCT_BASE_ADDRESS	0x00000005
-#define	SEND_SYNCHRONOUS_FIB		0x0000000c
+#define	BREAKPOINT_REQUEST		cpu_to_le32(0x00000004)
+#define	INIT_STRUCT_BASE_ADDRESS	cpu_to_le32(0x00000005)
+#define READ_PERMANENT_PARAMETERS	cpu_to_le32(0x0000000a)
+#define WRITE_PERMANENT_PARAMETERS	cpu_to_le32(0x0000000b)
+#define HOST_CRASHING			cpu_to_le32(0x0000000d)
+#define	SEND_SYNCHRONOUS_FIB		cpu_to_le32(0x0000000c)
+#define GET_ADAPTER_PROPERTIES		cpu_to_le32(0x00000019)
+#define RE_INIT_ADAPTER			cpu_to_le32(0x000000ee)
 
 /*
  *	Adapter Status Register
@@ -1138,37 +1353,6 @@
 	u8 data[1];		/* Undefined length (from kernel viewpoint) */
 };
 
-/*
- *	Adapter Information Block
- *
- *	This is returned by the RequestAdapterInfo block
- */
- 
-struct aac_adapter_info
-{
-	u32	platform;
-	u32	cpu;
-	u32	subcpu;
-	u32	clock;
-	u32	execmem;
-	u32	buffermem;
-	u32	totalmem;
-	u32	kernelrev;
-	u32	kernelbuild;
-	u32	monitorrev;
-	u32	monitorbuild;
-	u32	hwrev;
-	u32	hwbuild;
-	u32	biosrev;
-	u32	biosbuild;
-	u32	clustering;
-	u32	clustermask;
-	u64	serial;
-	u32	battery;
-	u32	options;
-	u32	OEM;
-};
-
 static inline u32 fib2addr(struct hw_fib *hw)
 {
 	return (u32)hw;
@@ -1206,3 +1390,5 @@
 int aac_command_thread(struct aac_dev * dev);
 int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx);
 int fib_adapter_complete(struct fib * fibptr, unsigned short size);
+struct aac_driver_ident* aac_get_driver_ident(int devtype);
+int aac_get_adapter_info(struct aac_dev* dev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aacraid/commctrl.c linux-2.4.20/drivers/scsi/aacraid/commctrl.c
--- linux-2.4.19/drivers/scsi/aacraid/commctrl.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aacraid/commctrl.c	2002-10-29 11:18:33.000000000 +0000
@@ -364,8 +364,8 @@
 	struct revision response;
 
 	response.compat = 1;
-	response.version = 0x03000400;
-	response.build = 0x5125;
+	response.version = dev->adapter_info.kernelrev;
+	response.build = dev->adapter_info.kernelbuild;
 
 	if (copy_to_user(arg, &response, sizeof(response)))
 		return -EFAULT;
@@ -373,6 +373,25 @@
 }
 
 
+struct aac_pci_info {
+        u32 bus;
+        u32 slot;
+};
+
+
+int aac_get_pci_info(struct aac_dev* dev, void* arg)
+{
+        struct aac_pci_info pci_info;
+
+	pci_info.bus = dev->pdev->bus->number;
+	pci_info.slot = PCI_SLOT(dev->pdev->devfn);
+
+       if(copy_to_user( arg, (void*)&pci_info, sizeof(struct aac_pci_info)))
+               return -EFAULT;
+        return 0;
+ }
+ 
+
 int aac_do_ioctl(struct aac_dev * dev, int cmd, void *arg)
 {
 	int status;
@@ -401,6 +420,9 @@
 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
 		status = close_getadapter_fib(dev, arg);
 		break;
+	case FSACTL_GET_PCI_INFO:
+		status = aac_get_pci_info(dev,arg);
+		break;
 	default:
 		status = -ENOTTY;
 	  	break;	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aacraid/comminit.c linux-2.4.20/drivers/scsi/aacraid/comminit.c
--- linux-2.4.19/drivers/scsi/aacraid/comminit.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aacraid/comminit.c	2002-10-29 11:18:48.000000000 +0000
@@ -38,6 +38,7 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/blk.h>
+#include <linux/completion.h>
 #include <asm/semaphore.h>
 #include "scsi.h"
 #include "hosts.h"
@@ -57,6 +58,7 @@
 	struct aac_init *init;
 	dma_addr_t phys;
 
+	/* FIXME: Adaptec add 128 bytes to this value - WHY ?? */
 	size = fibsize + sizeof(struct aac_init) + commsize + commalign + printfbufsiz;
 
 	base = pci_alloc_consistent(dev->pdev, size, &phys);
@@ -72,6 +74,14 @@
 	dev->init = (struct aac_init *)(base + fibsize);
 	dev->init_pa = phys + fibsize;
 
+	/*
+	 *	Cache the upper bits of the virtual mapping for 64bit boxes
+	 *	FIXME: this crap should be rewritten
+	 */
+#if BITS_PER_LONG >= 64 
+	dev->fib_base_va = ((ulong)base & 0xffffffff00000000);
+#endif
+
 	init = dev->init;
 
 	init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION);
@@ -82,7 +92,7 @@
 	 *	Adapter Fibs are the first thing allocated so that they
 	 *	start page aligned
 	 */
-	init->AdapterFibsVirtualAddress = cpu_to_le32((long)base);
+	init->AdapterFibsVirtualAddress = cpu_to_le32((u32)base);
 	init->AdapterFibsPhysicalAddress = cpu_to_le32(phys);
 	init->AdapterFibsSize = cpu_to_le32(fibsize);
 	init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib));
@@ -238,7 +248,7 @@
 
 	queues = (struct aac_entry *)((unsigned char *)headers + hdrsize);
 
-	/* Adapter to Host normal priority Command queue */ 
+	/* Adapter to Host normal proirity Command queue */ 
 	comm->queue[HostNormCmdQueue].base = queues;
 	aac_queue_init(dev, &comm->queue[HostNormCmdQueue], headers, HOST_NORM_CMD_ENTRIES);
 	queues += HOST_NORM_CMD_ENTRIES;
@@ -319,7 +329,6 @@
 		return NULL;
 		
 	INIT_LIST_HEAD(&dev->fib_list);
-	spin_lock_init(&dev->fib_lock);
 	init_completion(&dev->aif_completion);
 	/*
 	 *	Add this adapter in to our dev List.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aacraid/commsup.c linux-2.4.20/drivers/scsi/aacraid/commsup.c
--- linux-2.4.19/drivers/scsi/aacraid/commsup.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aacraid/commsup.c	2002-10-29 11:18:33.000000000 +0000
@@ -180,7 +180,7 @@
 	} else {
 		if (fibptr->fib->header.XferState != 0) {
 			printk(KERN_WARNING "fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n", 
-					 fibptr, fibptr->fib->header.XferState);
+				 (void *)fibptr, fibptr->fib->header.XferState);
 		}
 		fibptr->next = fibptr->dev->free_fib;
 		fibptr->dev->free_fib = fibptr;
@@ -280,8 +280,7 @@
 	else BUG();
 
         if (*index + 1 == le32_to_cpu(*(q->headers.consumer))) { /* Queue is full */
-		printk(KERN_WARNING "Queue %d full, %ld outstanding.\n",
-				qid, q->numpending);
+		printk(KERN_WARNING "Queue %d full, %ld outstanding.\n", qid, q->numpending);
 		return 0;
 	} else {
 	        *entry = q->base + *index;
@@ -336,7 +335,7 @@
         	 *	Setup queue entry with command, status and fib mapped
         	 */
         	entry->size = cpu_to_le32(le16_to_cpu(fib->header.Size));
-        	entry->addr = cpu_to_le32(fib->header.SenderFibAddress);     			/* Restore adapters pointer to the FIB */
+        	entry->addr = cpu_to_le32(fib->header.SenderFibAddress);     		/* Restore adapters pointer to the FIB */
 		fib->header.ReceiverFibAddress = fib->header.SenderFibAddress;		/* Let the adapter now where to find its data */
         	map = 0;
 	} 
@@ -682,7 +681,7 @@
 	}
 	else 
 	{
-        	printk(KERN_WARNING "fib_complete: Unknown xferstate detected.\n");
+        	printk(KERN_WARNING "fib_adapter_complete: Unknown xferstate detected.\n");
         	BUG();
 	}   
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aacraid/dpcsup.c linux-2.4.20/drivers/scsi/aacraid/dpcsup.c
--- linux-2.4.19/drivers/scsi/aacraid/dpcsup.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aacraid/dpcsup.c	2002-10-29 11:18:40.000000000 +0000
@@ -59,8 +59,8 @@
 {
 	struct aac_dev * dev = q->dev;
 	struct aac_entry *entry;
-	struct hw_fib * fib;
-	struct fib * fibctx;
+	struct hw_fib * hwfib;
+	struct fib * fib;
 	int consumed = 0;
 	unsigned long flags;
 
@@ -77,22 +77,22 @@
 		int fast;
 
 		fast = (int) (entry->addr & 0x01);
-		fib = addr2fib(entry->addr & ~0x01);
+		hwfib = addr2fib(entry->addr & ~0x01);
 		aac_consumer_free(dev, q, HostNormRespQueue);
-		fibctx = &dev->fibs[fib->header.SenderData];
+		fib = &dev->fibs[hwfib->header.SenderData];
 		/*
-		 *	Remove this fibctx from the Outstanding I/O queue.
+		 *	Remove this fib from the Outstanding I/O queue.
 		 *	But only if it has not already been timed out.
 		 *
 		 *	If the fib has been timed out already, then just 
 		 *	continue. The caller has already been notified that
 		 *	the fib timed out.
 		 */
-		if (!(fibctx->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
-			list_del(&fibctx->queue);
+		if (!(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
+			list_del(&fib->queue);
 			dev->queues->queue[AdapNormCmdQueue].numpending--;
 		} else {
-			printk(KERN_WARNING "aacraid: FIB timeout.\n");
+			printk(KERN_WARNING "aacraid: FIB timeout (%x).\n", fib->flags);
 			continue;
 		}
 		spin_unlock_irqrestore(q->lock, flags);
@@ -101,35 +101,35 @@
 			/*
 			 *	Doctor the fib
 			 */
-			*(u32 *)fib->data = cpu_to_le32(ST_OK);
-			fib->header.XferState |= cpu_to_le32(AdapterProcessed);
+			*(u32 *)hwfib->data = cpu_to_le32(ST_OK);
+			hwfib->header.XferState |= cpu_to_le32(AdapterProcessed);
 		}
 
 		FIB_COUNTER_INCREMENT(aac_config.FibRecved);
 
-		if (fib->header.Command == cpu_to_le16(NuFileSystem))
+		if (hwfib->header.Command == cpu_to_le16(NuFileSystem))
 		{
-			u32 *pstatus = (u32 *)fib->data;
+			u32 *pstatus = (u32 *)hwfib->data;
 			if (*pstatus & cpu_to_le32(0xffff0000))
 				*pstatus = cpu_to_le32(ST_OK);
 		}
-		if (fib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) 
+		if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) 
 		{
-	        	if (fib->header.XferState & cpu_to_le32(NoResponseExpected))
+	        	if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected))
 				FIB_COUNTER_INCREMENT(aac_config.NoResponseRecved);
 			else 
 				FIB_COUNTER_INCREMENT(aac_config.AsyncRecved);
 			/*
-			 *	NOTE:  we cannot touch the fibctx after this
+			 *	NOTE:  we cannot touch the fib after this
 			 *	    call, because it may have been deallocated.
 			 */
-			fibctx->callback(fibctx->callback_data, fibctx);
+			fib->callback(fib->callback_data, fib);
 		} else {
 			unsigned long flagv;
-			spin_lock_irqsave(&fibctx->event_lock, flagv);
-			fibctx->done = 1;
-			up(&fibctx->event_wait);
-			spin_unlock_irqrestore(&fibctx->event_lock, flagv);
+			spin_lock_irqsave(&fib->event_lock, flagv);
+			fib->done = 1;
+			up(&fib->event_wait);
+			spin_unlock_irqrestore(&fib->event_lock, flagv);
 			FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
 		}
 		consumed++;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aacraid/linit.c linux-2.4.20/drivers/scsi/aacraid/linit.c
--- linux-2.4.19/drivers/scsi/aacraid/linit.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aacraid/linit.c	2002-10-29 11:18:32.000000000 +0000
@@ -35,7 +35,7 @@
  *	
  */
 
-#define AAC_DRIVER_VERSION		"0.9.9ac4-rel"
+#define AAC_DRIVER_VERSION		"0.9.9ac6-TEST"
 #define AAC_DRIVER_BUILD_DATE		__DATE__
 
 #include <linux/module.h>
@@ -58,34 +58,47 @@
 
 #define AAC_DRIVERNAME	"aacraid"
 
-MODULE_AUTHOR("Red Hat Inc and Adaptec OEM RAID Solutions");
-MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, and HP NetRAID-4M devices.  http://domsch.com/linux/");
+MODULE_AUTHOR("Red Hat Inc and Adaptec");
+MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, Adaptec 2120S, 2200S, 5400S, and HP NetRAID-4M devices. http://domsch.com/linux/ or http://linux.adaptec.com");
 MODULE_LICENSE("GPL");
+MODULE_PARM(nondasd, "i");
+MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on");
+
+static int nondasd=-1;
 
 struct aac_dev *aac_devices[MAXIMUM_NUM_ADAPTERS];
 
 static unsigned aac_count = 0;
 static int aac_cfg_major = -1;
-static int single_command_done = 0;
 
 /*
  * Because of the way Linux names scsi devices, the order in this table has
  * become important.  Check for on-board Raid first, add-in cards second.
+ *
+ * dmb - For now we add the number of channels to this structure.  
+ * In the future we should add a fib that reports the number of channels
+ * for the card.  At that time we can remove the channels from here
  */
-
-/* FIXME static */struct aac_driver_ident aac_drivers[] = {
-	{ 0x1028, 0x0001, 0x1028, 0x0001, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 2/Si */
-	{ 0x1028, 0x0002, 0x1028, 0x0002, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
-	{ 0x1028, 0x0003, 0x1028, 0x0003, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Si */
-	{ 0x1028, 0x0004, 0x1028, 0x00d0, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Si */
-	{ 0x1028, 0x0002, 0x1028, 0x00d1, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
-	{ 0x1028, 0x0002, 0x1028, 0x00d9, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
-	{ 0x1028, 0x000a, 0x1028, 0x0106, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
-	{ 0x1028, 0x000a, 0x1028, 0x011b, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
-	{ 0x1028, 0x000a, 0x1028, 0x0121, aac_rx_init, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
-	{ 0x1011, 0x0046, 0x9005, 0x1364, aac_sa_init, "percraid", "DELL    ", "PERCRAID        " }, /* Dell PERC2 "Quad Channel" */
-	{ 0x1011, 0x0046, 0x9005, 0x0365, aac_sa_init, "aacraid",  "ADAPTEC ", "Adaptec 5400S   " }, /* Adaptec 5400S */
-	{ 0x1011, 0x0046, 0x103c, 0x10c2, aac_sa_init, "hpnraid",  "HP      ", "NetRAID-4M      " }  /* HP NetRAID-4M */
+ 
+static struct aac_driver_ident aac_drivers[] = {
+	{ 0x1028, 0x0001, 0x1028, 0x0001, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, /* PERC 2/Si */
+	{ 0x1028, 0x0002, 0x1028, 0x0002, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, /* PERC 3/Di */
+	{ 0x1028, 0x0003, 0x1028, 0x0003, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, /* PERC 3/Si */
+	{ 0x1028, 0x0004, 0x1028, 0x00d0, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, /* PERC 3/Si */
+	{ 0x1028, 0x0002, 0x1028, 0x00d1, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, /* PERC 3/Di */
+	{ 0x1028, 0x0002, 0x1028, 0x00d9, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, /* PERC 3/Di */
+	{ 0x1028, 0x000a, 0x1028, 0x0106, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, /* PERC 3/Di */
+	{ 0x1028, 0x000a, 0x1028, 0x011b, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, /* PERC 3/Di */
+	{ 0x1028, 0x000a, 0x1028, 0x0121, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, /* PERC 3/Di */
+	{ 0x9005, 0x0283, 0x9005, 0x0283, aac_rx_init, "aacraid",  "ADAPTEC ", "catapult        ", 2 }, /* catapult*/
+	{ 0x9005, 0x0284, 0x9005, 0x0284, aac_rx_init, "aacraid",  "ADAPTEC ", "tomcat          ", 2 }, /* tomcat*/
+	{ 0x9005, 0x0285, 0x9005, 0x0286, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2120S   ", 1 }, /* Adaptec 2120S (Crusader)*/
+	{ 0x9005, 0x0285, 0x9005, 0x0285, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2 }, /* Adaptec 2200S (Vulcan)*/
+	{ 0x9005, 0x0285, 0x9005, 0x0287, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2 }, /* Adaptec 2200S (Vulcan-2m)*/
+	{ 0x1011, 0x0046, 0x9005, 0x0365, aac_sa_init, "aacraid",  "ADAPTEC ", "Adaptec 5400S   ", 4 }, /* Adaptec 5400S (Mustang)*/
+	{ 0x1011, 0x0046, 0x9005, 0x0364, aac_sa_init, "aacraid",  "ADAPTEC ", "AAC-364         ", 4 }, /* Adaptec 5400S (Mustang)*/
+	{ 0x1011, 0x0046, 0x9005, 0x1364, aac_sa_init, "percraid", "DELL    ", "PERCRAID        ", 4 }, /* Dell PERC2 "Quad Channel" */
+	{ 0x1011, 0x0046, 0x103c, 0x10c2, aac_sa_init, "hpnraid",  "HP      ", "NetRAID-4M      ", 4 }  /* HP NetRAID-4M */
 };
 
 #define NUM_AACTYPES	(sizeof(aac_drivers) / sizeof(struct aac_driver_ident))
@@ -105,12 +118,13 @@
 static int aac_detect(Scsi_Host_Template *);
 static int aac_release(struct Scsi_Host *);
 static int aac_queuecommand(Scsi_Cmnd *, void (*CompletionRoutine)(Scsi_Cmnd *));
-static int aac_command(Scsi_Cmnd *);
-static int aac_abortcommand(Scsi_Cmnd *scsi_cmnd_ptr);
-static int aac_resetcommand(Scsi_Cmnd *, unsigned int);
 static int aac_biosparm(Scsi_Disk *, kdev_t, int *);
 static int aac_procinfo(char *, char **, off_t, int, int, int);
 static int aac_ioctl(Scsi_Device *, int, void *);
+static int aac_eh_abort(Scsi_Cmnd * cmd);
+static int aac_eh_device_reset(Scsi_Cmnd* cmd);
+static int aac_eh_bus_reset(Scsi_Cmnd* cmd);
+static int aac_eh_reset(Scsi_Cmnd* cmd);
 
 static void aac_queuedepth(struct Scsi_Host *, Scsi_Device *);
 
@@ -160,8 +174,7 @@
 			aac_drivers[index].subsystem_device));
 
 		dev = NULL;
-		while((dev = pci_find_device(vendor_id, device_id, dev)))
-		{
+		while((dev = pci_find_device(vendor_id, device_id, dev))) {
 			if (pci_enable_device(dev))
 				continue;
 			pci_set_master(dev);
@@ -237,13 +250,50 @@
 				printk(KERN_WARNING "aacraid: device initialization failed.\n");
 				scsi_unregister(host_ptr);
 				aac_count--;
+				continue;
 			} 
-			else
+			dprintk((KERN_DEBUG "%s:%d device initialization successful.\n", name, host_ptr->unique_id));
+			aac_get_adapter_info(aac);
+			if(nondasd != -1) 
 			{
-				dprintk((KERN_DEBUG "%s:%d device initialization successful.\n", name, host_ptr->unique_id));
-				aac_get_containers(aac);
-				aac_devices[aac_count-1] = aac;
+				/* someone told us how to set this on the cmdline */
+				aac->nondasd_support = (nondasd!=0);
 			}
+			if(aac->nondasd_support != 0){
+				printk(KERN_INFO "%s%d: Non-DASD support enabled\n", aac->name, aac->id);
+			}
+			dprintk((KERN_DEBUG "%s:%d options flag %04x.\n",name, host_ptr->unique_id,aac->adapter_info.options));
+			if(aac->nondasd_support == 1)
+			{
+				/*
+				 * max channel will be the physical channels plus 1 virtual channel 
+				 * all containers are on the virtual channel 0
+				 * physical channels are address by their actual physical number+1
+				 */
+				host_ptr->max_channel = aac_drivers[index].channels+1;
+			} else {
+				host_ptr->max_channel = 1;
+ 			}
+			dprintk((KERN_DEBUG "Device has %d logical channels\n", host_ptr->max_channel));
+			aac_get_containers(aac);
+			aac_devices[aac_count-1] = aac;
+
+			/*
+			 * dmb - we may need to move these 3 parms somewhere else once
+			 * we get a fib that can report the actual numbers
+			 */
+			host_ptr->max_id = AAC_MAX_TARGET;
+			host_ptr->max_lun = AAC_MAX_LUN;
+			
+			/*
+			 *  If we are PAE capable then our future DMA mappings
+			 *  (for read/write commands) are 64bit clean and don't 
+			 *  need bouncing. This assumes we do no other 32bit only
+			 *  allocations (eg fib table expands) after this point.
+			 */
+			 
+			if(aac->pae_support)
+				pci_set_dma_mask(dev, 0xFFFFFFFFFFFFFFFFUL);
 		}
 	}
 
@@ -305,11 +355,11 @@
  *	Queues a command for execution by the associated Host Adapter.
  */ 
 
-static int aac_queuecommand(Scsi_Cmnd *scsi_cmnd_ptr, void (*CompletionRoutine)(Scsi_Cmnd *))
+static int aac_queuecommand(Scsi_Cmnd *scsi_cmnd_ptr, void (*complete)(Scsi_Cmnd *))
 {
 	int ret;
 
-	scsi_cmnd_ptr->scsi_done = CompletionRoutine;
+	scsi_cmnd_ptr->scsi_done = complete;
 	/*
 	 *	aac_scsi_cmd() handles command processing, setting the 
 	 *	result code and calling completion routine. 
@@ -319,79 +369,6 @@
 	return ret;
 } 
 
-
-/**
- *	aac_done	-	Callback function for a non-queued command.
- *	@scsi_cmnd_ptr:	SCSI command block to wait for
- *
- *	Sets single_command done to 1. This lets aac_command complete. 
- *	This function is obsolete.
- *
- *	Bugs: Doesn't actually work properly with multiple controllers
- */
- 
-static void aac_done(Scsi_Cmnd * scsi_cmnd_ptr) 
-{
-	single_command_done = 1;
-}
-
-/**
- *	aac_command	-	synchronous SCSI command execution
- *	@scsi_cmnd_ptr:	SCSI command to issue
- *
- *	Accepts a single command for execution by the associated Host Adapter.
- *	Waits until it completes an then returns an int where:
- *		Byte 0 = SCSI status code
- *		Byte 1 = SCSI 1 byte message
- *		Byte 2 = host error return
- *		Byte 3 = mid level error return
- */
- 
-static int aac_command(Scsi_Cmnd *scsi_cmnd_ptr )
-{
-	scsi_cmnd_ptr->scsi_done = aac_done;
-	dprintk((KERN_DEBUG "aac_command.\n"));
-
-	/*
-	 *	aac_scsi_cmd() handles command processing, setting the 
-	 *	result code and calling completion routine.
-	 */
-	single_command_done = 0;
-	aac_scsi_cmd(scsi_cmnd_ptr);
-	while(!single_command_done)
-		rmb();
-	return scsi_cmnd_ptr->result;
-} 
-
-/**
- *	aac_abortcommand	-	Abort command if possible.
- *	@scsi_cmnd_ptr:	SCSI command block to abort
- *
- *	Called when the midlayer wishes to abort a command. We don't support
- *	this facility, and our firmware looks after life for us. We just
- *	report the command as busy. 
- */
- 
-static int aac_abortcommand(Scsi_Cmnd *scsi_cmnd_ptr )
-{
-	return SCSI_ABORT_BUSY;
-}
-
-/**
- *	aac_resetcommand	-	Reset command handling
- *	@scsi_cmnd_ptr:	SCSI command block causing the reset
- *	@reset_flags: Reset hints from the midlayer code
- *
- *	Issue a reset of a SCSI command. We are ourselves not truely a SCSI
- *	controller and our firmware will do the work for us anyway. Thus this
- *	is a no-op. We just return SCSI_RESET_PUNT
- */
- 
-static int aac_resetcommand(struct scsi_cmnd *scsi_cmnd_ptr, unsigned int reset_flags )
-{
-	return SCSI_RESET_PUNT;
-}
-
 /**
  *	aac_driverinfo		-	Returns the host adapter name
  *	@host_ptr:	Scsi host to report on
@@ -406,6 +383,17 @@
 }
 
 /**
+ *	aac_get_driver_ident
+ * 	@devtype: index into lookup table
+ *
+ * 	Returns a pointer to the entry in the driver lookup table.
+ */
+struct aac_driver_ident* aac_get_driver_ident(int devtype)
+{
+	return  &aac_drivers[devtype];
+}
+
+/**
  *	aac_biosparm	-	return BIOS parameters for disk
  *	@disk: SCSI disk object to process
  *	@device: kdev_t of the disk in question
@@ -558,13 +546,75 @@
 	}
 }
 
-/*------------------------------------------------------------------------------
-	aac_ioctl()
 
-		Handle SCSI ioctls
- *----------------------------------------------------------------------------*/
+/**
+ *	aac_eh_abort	-	Abort command if possible.
+ *	@cmd:	SCSI command block to abort
+ *
+ *	Called when the midlayer wishes to abort a command. We don't support
+ *	this facility, and our firmware looks after life for us. We just
+ *	report this as failing
+ */
+ 
+static int aac_eh_abort(Scsi_Cmnd *cmd)
+{
+	return FAILED;
+}
+
+/**
+ *	aac_eh_device_reset	-	Reset command handling
+ *	@cmd:	SCSI command block causing the reset
+ *
+ *	Issue a reset of a SCSI device. We are ourselves not truely a SCSI
+ *	controller and our firmware will do the work for us anyway. Thus this
+ *	is a no-op. We just return FAILED.
+ */
+
+static int aac_eh_device_reset(Scsi_Cmnd *cmd)
+{
+	return FAILED;
+}
+
+/**
+ *	aac_eh_bus_reset	-	Reset command handling
+ *	@scsi_cmd:	SCSI command block causing the reset
+ *
+ *	Issue a reset of a SCSI bus. We are ourselves not truely a SCSI
+ *	controller and our firmware will do the work for us anyway. Thus this
+ *	is a no-op. We just return FAILED.
+ */
+
+static int aac_eh_bus_reset(Scsi_Cmnd* cmd)
+{
+	return FAILED;
+}
+
+/**
+ *	aac_eh_hba_reset	-	Reset command handling
+ *	@scsi_cmd:	SCSI command block causing the reset
+ *
+ *	Issue a reset of a SCSI host. If things get this bad then arguably we should
+ *	go take a look at what the host adapter is doing and see if something really
+ *	broke (as can occur at least on my Dell QC card if a drive keeps failing spinup)
+ */
+
+static int aac_eh_reset(Scsi_Cmnd* cmd)
+{
+	printk(KERN_ERR "aacraid: Host adapter reset request. SCSI hang ?\n");
+	return FAILED;
+}
+
+/**
+ *	aac_ioctl 	-	Handle SCSI ioctls
+ *	@scsi_dev_ptr: scsi device to operate upon
+ *	@cmd: ioctl command to use issue
+ *	@arg: ioctl data pointer
+ *
+ *	Issue an ioctl on an aacraid device. Returns a standard unix error code or
+ *	zero for success
+ */
+ 
 static int aac_ioctl(Scsi_Device * scsi_dev_ptr, int cmd, void * arg)
-/*----------------------------------------------------------------------------*/
 {
 	struct aac_dev *dev;
 	dprintk((KERN_DEBUG "aac_ioctl.\n"));
@@ -640,17 +690,19 @@
 	release:        	aac_release,
 	info:           	aac_driverinfo,
 	ioctl:          	aac_ioctl,
-	command:        	aac_command,
 	queuecommand:   	aac_queuecommand,
-	abort:          	aac_abortcommand,
-	reset:          	aac_resetcommand,
 	bios_param:     	aac_biosparm,	
 	can_queue:      	AAC_NUM_IO_FIB,	
 	this_id:        	16,
 	sg_tablesize:   	16,
 	max_sectors:    	128,
-	cmd_per_lun:    	1,
-	eh_abort_handler:       aac_abortcommand,
+	cmd_per_lun:    	AAC_NUM_IO_FIB,
+	eh_abort_handler:       aac_eh_abort,
+	eh_device_reset_handler:aac_eh_device_reset,
+	eh_bus_reset_handler:	aac_eh_bus_reset,
+	eh_host_reset_handler:	aac_eh_reset,
+	use_new_eh_code:	1, 
+
 	use_clustering:		ENABLE_CLUSTERING,
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aacraid/rx.c linux-2.4.20/drivers/scsi/aacraid/rx.c
--- linux-2.4.19/drivers/scsi/aacraid/rx.c	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aacraid/rx.c	2002-10-29 11:18:48.000000000 +0000
@@ -50,7 +50,6 @@
 	struct aac_dev *dev = dev_id;
 	unsigned long bellbits;
 	u8 intstat, mask;
-
 	intstat = rx_readb(dev, MUnit.OISR);
 	/*
 	 *	Read mask and invert because drawbridge is reversed.
@@ -62,28 +61,24 @@
 	if (intstat & mask) 
 	{
 		bellbits = rx_readl(dev, OutboundDoorbellReg);
-		if (bellbits & DoorBellPrintfReady)
-		{
+		if (bellbits & DoorBellPrintfReady) {
 			aac_printf(dev, le32_to_cpu(rx_readl (dev, IndexRegs.Mailbox[5])));
 			rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);
 			rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
 		}
-		else if (bellbits & DoorBellAdapterNormCmdReady)
-		{
+		else if (bellbits & DoorBellAdapterNormCmdReady) {
 			aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
 			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
 		}
-		else if (bellbits & DoorBellAdapterNormRespReady) 
-		{
+		else if (bellbits & DoorBellAdapterNormRespReady) {
 			aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
 			rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
 		}
-		else if (bellbits & DoorBellAdapterNormCmdNotFull)
-		{
+		else if (bellbits & DoorBellAdapterNormCmdNotFull) {
 			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
 		}
-		else if (bellbits & DoorBellAdapterNormRespNotFull)
-		{
+		else if (bellbits & DoorBellAdapterNormRespNotFull) {
+			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
 			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
 		}
 	}
@@ -160,7 +155,7 @@
  *	for its	completion.
  */
 
-static int rx_sync_cmd(struct aac_dev *dev, unsigned long command, unsigned long p1, unsigned long *status)
+static int rx_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 *status)
 {
 	unsigned long start;
 	int ok;
@@ -251,7 +246,7 @@
 
 static void aac_rx_interrupt_adapter(struct aac_dev *dev)
 {
-	unsigned long ret;
+	u32 ret;
 	rx_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret);
 }
 
@@ -304,7 +299,7 @@
 
 static void aac_rx_start_adapter(struct aac_dev *dev)
 {
-	unsigned long status;
+	u32 status;
 	struct aac_init *init;
 
 	init = dev->init;
@@ -323,7 +318,8 @@
 //	rx_writeb(dev, MUnit.OIMR, ~(u8)OUTBOUND_DOORBELL_INTERRUPT_MASK);
 	rx_writeb(dev, MUnit.OIMR, 0xfb);
 
-	rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (unsigned long) dev->init_pa, &status);
+	// We can only use a 32 bit address here
+	rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, &status);
 }
 
 /**
@@ -344,7 +340,6 @@
 	const char * name;
 
 	dev->devnum = num;
-
 	instance = dev->id;
 	name     = dev->name;
 
@@ -372,11 +367,11 @@
 	}
 	start = jiffies;
 	/*
-	 *	Wait for the adapter to be up and running. Wait up to 30 seconds.
+	 *	Wait for the adapter to be up and running. Wait up to 3 minutes
 	 */
 	while (!(rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING)) 
 	{
-		if(time_after(jiffies, start+30*HZ))
+		if(time_after(jiffies, start+180*HZ))
 		{
 			status = rx_readl(dev, IndexRegs.Mailbox[7]) >> 16;
 			printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %ld.\n", dev->name, instance, status);
@@ -397,6 +392,7 @@
 	dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt;
 	dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt;
 	dev->a_ops.adapter_notify = aac_rx_notify_adapter;
+	dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
 
 	if (aac_init_adapter(dev) == NULL)
 		return -1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aacraid/sa.c linux-2.4.20/drivers/scsi/aacraid/sa.c
--- linux-2.4.19/drivers/scsi/aacraid/sa.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aacraid/sa.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,396 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * 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, 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; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  sa.c
+ *
+ * Abstract: Drawbridge specific support functions
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/blk.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <asm/semaphore.h>
+#include "scsi.h"
+#include "hosts.h"
+
+#include "aacraid.h"
+
+static void aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct aac_dev *dev = dev_id;
+	unsigned short intstat, mask;
+
+	intstat = sa_readw(dev, DoorbellReg_p);
+	/*
+	 *	Read mask and invert because drawbridge is reversed.
+	 *	This allows us to only service interrupts that have been enabled.
+	 */
+	mask = ~(sa_readw(dev, SaDbCSR.PRISETIRQMASK));
+
+	/* Check to see if this is our interrupt.  If it isn't just return */
+
+	if (intstat & mask) {
+		if (intstat & PrintfReady) {
+			aac_printf(dev, le32_to_cpu(sa_readl(dev, Mailbox5)));
+			sa_writew(dev, DoorbellClrReg_p, PrintfReady); /* clear PrintfReady */
+			sa_writew(dev, DoorbellReg_s, PrintfDone);
+		} else if (intstat & DOORBELL_1) {	// dev -> Host Normal Command Ready
+			aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
+			sa_writew(dev, DoorbellClrReg_p, DOORBELL_1);
+		} else if (intstat & DOORBELL_2) {	// dev -> Host Normal Response Ready
+			aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
+			sa_writew(dev, DoorbellClrReg_p, DOORBELL_2);
+		} else if (intstat & DOORBELL_3) {	// dev -> Host Normal Command Not Full
+			sa_writew(dev, DoorbellClrReg_p, DOORBELL_3);
+		} else if (intstat & DOORBELL_4) {	// dev -> Host Normal Response Not Full
+			sa_writew(dev, DoorbellClrReg_p, DOORBELL_4);
+		}
+	}
+}
+
+/**
+ *	aac_sa_enable_interrupt	-	enable an interrupt event
+ *	@dev: Which adapter to enable.
+ *	@event: Which adapter event.
+ *
+ *	This routine will enable the corresponding adapter event to cause an interrupt on 
+ * 	the host.
+ */
+ 
+void aac_sa_enable_interrupt(struct aac_dev *dev, u32 event)
+{
+	switch (event) {
+
+	case HostNormCmdQue:
+		sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_1);
+		break;
+
+	case HostNormRespQue:
+		sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_2);
+		break;
+
+	case AdapNormCmdNotFull:
+		sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_3);
+		break;
+
+	case AdapNormRespNotFull:
+		sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_4);
+		break;
+	}
+}
+
+/**
+ *	aac_sa_disable_interrupt	-	disable an interrupt event
+ *	@dev: Which adapter to enable.
+ *	@event: Which adapter event.
+ *
+ *	This routine will enable the corresponding adapter event to cause an interrupt on 
+ * 	the host.
+ */
+
+void aac_sa_disable_interrupt (struct aac_dev *dev, u32 event)
+{
+	switch (event) {
+
+	case HostNormCmdQue:
+		sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_1);
+		break;
+
+	case HostNormRespQue:
+		sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_2);
+		break;
+
+	case AdapNormCmdNotFull:
+		sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_3);
+		break;
+
+	case AdapNormRespNotFull:
+		sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_4);
+		break;
+	}
+}
+
+/**
+ *	aac_sa_notify_adapter		-	handle adapter notification
+ *	@dev:	Adapter that notification is for
+ *	@event:	Event to notidy
+ *
+ *	Notify the adapter of an event
+ */
+ 
+void aac_sa_notify_adapter(struct aac_dev *dev, u32 event)
+{
+	switch (event) {
+
+	case AdapNormCmdQue:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_1);
+		break;
+	case HostNormRespNotFull:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_4);
+		break;
+	case AdapNormRespQue:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_2);
+		break;
+	case HostNormCmdNotFull:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_3);
+		break;
+	case HostShutdown:
+		//sa_sync_cmd(dev, HOST_CRASHING, 0, &ret);
+		break;
+	case FastIo:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_6);
+		break;
+	case AdapPrintfDone:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_5);
+		break;
+	default:
+		BUG();
+		break;
+	}
+}
+
+
+/**
+ *	sa_sync_cmd	-	send a command and wait
+ *	@dev: Adapter
+ *	@command: Command to execute
+ *	@p1: first parameter
+ *	@ret: adapter status
+ *
+ *	This routine will send a synchronous comamnd to the adapter and wait 
+ *	for its	completion.
+ */
+
+static int sa_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 *ret)
+{
+	unsigned long start;
+ 	int ok;
+	/*
+	 *	Write the Command into Mailbox 0
+	 */
+	sa_writel(dev, Mailbox0, cpu_to_le32(command));
+	/*
+	 *	Write the parameters into Mailboxes 1 - 4
+	 */
+	sa_writel(dev, Mailbox1, cpu_to_le32(p1));
+	sa_writel(dev, Mailbox2, 0);
+	sa_writel(dev, Mailbox3, 0);
+	sa_writel(dev, Mailbox4, 0);
+	/*
+	 *	Clear the synch command doorbell to start on a clean slate.
+	 */
+	sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
+	/*
+	 *	Signal that there is a new synch command
+	 */
+	sa_writew(dev, DoorbellReg_s, DOORBELL_0);
+
+	ok = 0;
+	start = jiffies;
+
+	while(time_before(jiffies, start+30*HZ))
+	{
+		/*
+		 *	Delay 5uS so that the monitor gets access
+		 */
+		udelay(5);
+		/*
+		 *	Mon110 will set doorbell0 bit when it has 
+		 *	completed the command.
+		 */
+		if(sa_readw(dev, DoorbellReg_p) & DOORBELL_0)  {
+			ok = 1;
+			break;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+
+	if (ok != 1)
+		return -ETIMEDOUT;
+	/*
+	 *	Clear the synch command doorbell.
+	 */
+	sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
+	/*
+	 *	Pull the synch status from Mailbox 0.
+	 */
+	*ret = le32_to_cpu(sa_readl(dev, Mailbox0));
+	return 0;
+}
+
+/**
+ *	aac_sa_interrupt_adapter	-	interrupt an adapter
+ *	@dev: Which adapter to enable.
+ *
+ *	Breakpoint an adapter.
+ */
+ 
+static void aac_sa_interrupt_adapter (struct aac_dev *dev)
+{
+	u32 ret;
+	sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret);
+}
+
+/**
+ *	aac_sa_start_adapter		-	activate adapter
+ *	@dev:	Adapter
+ *
+ *	Start up processing on an ARM based AAC adapter
+ */
+
+static void aac_sa_start_adapter(struct aac_dev *dev)
+{
+	u32 ret;
+	struct aac_init *init;
+	/*
+	 * Fill in the remaining pieces of the init.
+	 */
+	init = dev->init;
+	init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ);
+
+	dprintk(("INIT\n"));
+	/*
+	 * Tell the adapter we are back and up and running so it will scan its command
+	 * queues and enable our interrupts
+	 */
+	dev->irq_mask =	(PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4);
+	/*
+	 *	First clear out all interrupts.  Then enable the one's that 
+	 *	we can handle.
+	 */
+	dprintk(("MASK\n"));
+	sa_writew(dev, SaDbCSR.PRISETIRQMASK, cpu_to_le16(0xffff));
+	sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4));
+	dprintk(("SYNCCMD\n"));
+	/* We can only use a 32 bit address here */
+	sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, &ret);
+}
+
+/**
+ *	aac_sa_init	-	initialize an ARM based AAC card
+ *	@dev: device to configure
+ *	@devnum: adapter number
+ *
+ *	Allocate and set up resources for the ARM based AAC variants. The 
+ *	device_interface in the commregion will be allocated and linked 
+ *	to the comm region.
+ */
+
+int aac_sa_init(struct aac_dev *dev, unsigned long devnum)
+{
+	unsigned long start;
+	unsigned long status;
+	int instance;
+	const char *name;
+
+	dev->devnum = devnum;
+
+	dprintk(("PREINST\n"));
+	instance = dev->id;
+	name     = dev->name;
+
+	/*
+	 *	Map in the registers from the adapter.
+	 */
+	dprintk(("PREMAP\n"));
+
+	if((dev->regs.sa = (struct sa_registers *)ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL)
+	{	
+		printk(KERN_WARNING "aacraid: unable to map ARM.\n" );
+		return -1;
+	}
+	/*
+	 *	Check to see if the board failed any self tests.
+	 */
+	if (sa_readl(dev, Mailbox7) & SELF_TEST_FAILED) {
+		printk(KERN_WARNING "%s%d: adapter self-test failed.\n", name, instance);
+		return -1;
+	}
+	/*
+	 *	Check to see if the board panic'd while booting.
+	 */
+	if (sa_readl(dev, Mailbox7) & KERNEL_PANIC) {
+		printk(KERN_WARNING "%s%d: adapter kernel panic'd.\n", name, instance);
+		return -1;
+	}
+	start = jiffies;
+	/*
+	 *	Wait for the adapter to be up and running. Wait up to 3 minutes.
+	 */
+	while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) {
+		if (time_after(start+180*HZ, jiffies)) {
+			status = sa_readl(dev, Mailbox7) >> 16;
+			printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %d.\n", name, instance, le32_to_cpu(status));
+			return -1;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+
+	dprintk(("ATIRQ\n"));
+	if (request_irq(dev->scsi_host_ptr->irq, aac_sa_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev ) < 0) {
+		printk(KERN_WARNING "%s%d: Interrupt unavailable.\n", name, instance);
+		return -1;
+	}
+
+	/*
+	 *	Fill in the function dispatch table.
+	 */
+
+	dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter;
+	dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt;
+	dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt;
+	dev->a_ops.adapter_notify = aac_sa_notify_adapter;
+	dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
+
+	dprintk(("FUNCDONE\n"));
+
+	if(aac_init_adapter(dev) == NULL)
+		return -1;
+
+	dprintk(("NEWADAPTDONE\n"));
+	/*
+	 *	Start any kernel threads needed
+	 */
+	dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0);
+	/*
+	 *	Tell the adapter that all is configure, and it can start 
+	 *	accepting requests
+	 */
+	dprintk(("STARTING\n"));
+	aac_sa_start_adapter(dev);
+	dprintk(("STARTED\n"));
+	return 0;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aacraid/sap1sup.c linux-2.4.20/drivers/scsi/aacraid/sap1sup.c
--- linux-2.4.19/drivers/scsi/aacraid/sap1sup.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aacraid/sap1sup.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,394 +0,0 @@
-/*
- *	Adaptec AAC series RAID controller driver
- *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
- *
- * based on the old aacraid driver that is..
- * Adaptec aacraid device driver for Linux.
- *
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
- *
- * 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, 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; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Module Name:
- *  sap1sup.c
- *
- * Abstract: Drawbridge specific support functions
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/blk.h>
-#include <linux/delay.h>
-#include <linux/completion.h>
-#include <asm/semaphore.h>
-#include "scsi.h"
-#include "hosts.h"
-
-#include "aacraid.h"
-
-static void aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct aac_dev *dev = dev_id;
-	unsigned short intstat, mask;
-
-	intstat = sa_readw(dev, DoorbellReg_p);
-	/*
-	 *	Read mask and invert because drawbridge is reversed.
-	 *	This allows us to only service interrupts that have been enabled.
-	 */
-	mask = ~(sa_readw(dev, SaDbCSR.PRISETIRQMASK));
-
-	/* Check to see if this is our interrupt.  If it isn't just return */
-
-	if (intstat & mask) {
-		if (intstat & PrintfReady) {
-			aac_printf(dev, le32_to_cpu(sa_readl(dev, Mailbox5)));
-			sa_writew(dev, DoorbellClrReg_p, PrintfReady); /* clear PrintfReady */
-			sa_writew(dev, DoorbellReg_s, PrintfDone);
-		} else if (intstat & DOORBELL_1) {	// dev -> Host Normal Command Ready
-			aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
-			sa_writew(dev, DoorbellClrReg_p, DOORBELL_1);
-		} else if (intstat & DOORBELL_2) {	// dev -> Host Normal Response Ready
-			aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
-			sa_writew(dev, DoorbellClrReg_p, DOORBELL_2);
-		} else if (intstat & DOORBELL_3) {	// dev -> Host Normal Command Not Full
-			sa_writew(dev, DoorbellClrReg_p, DOORBELL_3);
-		} else if (intstat & DOORBELL_4) {	// dev -> Host Normal Response Not Full
-			sa_writew(dev, DoorbellClrReg_p, DOORBELL_4);
-		}
-	}
-}
-
-/**
- *	aac_sa_enable_interrupt	-	enable an interrupt event
- *	@dev: Which adapter to enable.
- *	@event: Which adapter event.
- *
- *	This routine will enable the corresponding adapter event to cause an interrupt on 
- * 	the host.
- */
- 
-void aac_sa_enable_interrupt(struct aac_dev *dev, u32 event)
-{
-	switch (event) {
-
-	case HostNormCmdQue:
-		sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_1);
-		break;
-
-	case HostNormRespQue:
-		sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_2);
-		break;
-
-	case AdapNormCmdNotFull:
-		sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_3);
-		break;
-
-	case AdapNormRespNotFull:
-		sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_4);
-		break;
-	}
-}
-
-/**
- *	aac_sa_disable_interrupt	-	disable an interrupt event
- *	@dev: Which adapter to enable.
- *	@event: Which adapter event.
- *
- *	This routine will enable the corresponding adapter event to cause an interrupt on 
- * 	the host.
- */
-
-void aac_sa_disable_interrupt (struct aac_dev *dev, u32 event)
-{
-	switch (event) {
-
-	case HostNormCmdQue:
-		sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_1);
-		break;
-
-	case HostNormRespQue:
-		sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_2);
-		break;
-
-	case AdapNormCmdNotFull:
-		sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_3);
-		break;
-
-	case AdapNormRespNotFull:
-		sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_4);
-		break;
-	}
-}
-
-/**
- *	aac_sa_notify_adapter		-	handle adapter notification
- *	@dev:	Adapter that notification is for
- *	@event:	Event to notidy
- *
- *	Notify the adapter of an event
- */
- 
-void aac_sa_notify_adapter(struct aac_dev *dev, u32 event)
-{
-	switch (event) {
-
-	case AdapNormCmdQue:
-		sa_writew(dev, DoorbellReg_s,DOORBELL_1);
-		break;
-	case HostNormRespNotFull:
-		sa_writew(dev, DoorbellReg_s,DOORBELL_4);
-		break;
-	case AdapNormRespQue:
-		sa_writew(dev, DoorbellReg_s,DOORBELL_2);
-		break;
-	case HostNormCmdNotFull:
-		sa_writew(dev, DoorbellReg_s,DOORBELL_3);
-		break;
-	case HostShutdown:
-		//sa_sync_cmd(dev, HOST_CRASHING, 0, &ret);
-		break;
-	case FastIo:
-		sa_writew(dev, DoorbellReg_s,DOORBELL_6);
-		break;
-	case AdapPrintfDone:
-		sa_writew(dev, DoorbellReg_s,DOORBELL_5);
-		break;
-	default:
-		BUG();
-		break;
-	}
-}
-
-
-/**
- *	sa_sync_cmd	-	send a command and wait
- *	@dev: Adapter
- *	@command: Command to execute
- *	@p1: first parameter
- *	@ret: adapter status
- *
- *	This routine will send a synchronous comamnd to the adapter and wait 
- *	for its	completion.
- */
-
-static int sa_sync_cmd(struct aac_dev *dev, unsigned long command, unsigned long p1, unsigned long *ret)
-{
-	unsigned long start;
- 	int ok;
-	/*
-	 *	Write the Command into Mailbox 0
-	 */
-	sa_writel(dev, Mailbox0, cpu_to_le32(command));
-	/*
-	 *	Write the parameters into Mailboxes 1 - 4
-	 */
-	sa_writel(dev, Mailbox1, cpu_to_le32(p1));
-	sa_writel(dev, Mailbox2, 0);
-	sa_writel(dev, Mailbox3, 0);
-	sa_writel(dev, Mailbox4, 0);
-	/*
-	 *	Clear the synch command doorbell to start on a clean slate.
-	 */
-	sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
-	/*
-	 *	Signal that there is a new synch command
-	 */
-	sa_writew(dev, DoorbellReg_s, DOORBELL_0);
-
-	ok = 0;
-	start = jiffies;
-
-	while(time_before(jiffies, start+30*HZ))
-	{
-		/*
-		 *	Delay 5uS so that the monitor gets access
-		 */
-		udelay(5);
-		/*
-		 *	Mon110 will set doorbell0 bit when it has 
-		 *	completed the command.
-		 */
-		if(sa_readw(dev, DoorbellReg_p) & DOORBELL_0)  {
-			ok = 1;
-			break;
-		}
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(1);
-	}
-
-	if (ok != 1)
-		return -ETIMEDOUT;
-	/*
-	 *	Clear the synch command doorbell.
-	 */
-	sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
-	/*
-	 *	Pull the synch status from Mailbox 0.
-	 */
-	*ret = le32_to_cpu(sa_readl(dev, Mailbox0));
-	return 0;
-}
-
-/**
- *	aac_sa_interrupt_adapter	-	interrupt an adapter
- *	@dev: Which adapter to enable.
- *
- *	Breakpoint an adapter.
- */
- 
-static void aac_sa_interrupt_adapter (struct aac_dev *dev)
-{
-	unsigned long ret;
-	sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret);
-}
-
-/**
- *	aac_sa_start_adapter		-	activate adapter
- *	@dev:	Adapter
- *
- *	Start up processing on an ARM based AAC adapter
- */
-
-static void aac_sa_start_adapter(struct aac_dev *dev)
-{
-	unsigned long ret;
-	struct aac_init *init;
-	/*
-	 * Fill in the remaining pieces of the init.
-	 */
-	init = dev->init;
-	init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ);
-
-	dprintk(("INIT\n"));
-	/*
-	 * Tell the adapter we are back and up and running so it will scan its command
-	 * queues and enable our interrupts
-	 */
-	dev->irq_mask =	(PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4);
-	/*
-	 *	First clear out all interrupts.  Then enable the one's that 
-	 *	we can handle.
-	 */
-	dprintk(("MASK\n"));
-	sa_writew(dev, SaDbCSR.PRISETIRQMASK, cpu_to_le16(0xffff));
-	sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4));
-	dprintk(("SYNCCMD\n"));
-	sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (unsigned long) dev->init_pa, &ret);
-}
-
-/**
- *	aac_sa_init	-	initialize an ARM based AAC card
- *	@dev: device to configure
- *	@devnum: adapter number
- *
- *	Allocate and set up resources for the ARM based AAC variants. The 
- *	device_interface in the commregion will be allocated and linked 
- *	to the comm region.
- */
-
-int aac_sa_init(struct aac_dev *dev, unsigned long devnum)
-{
-	unsigned long start;
-	unsigned long status;
-	int instance;
-	const char *name;
-
-	dev->devnum = devnum;
-
-	dprintk(("PREINST\n"));
-	instance = dev->id;
-	name     = dev->name;
-
-	/*
-	 *	Map in the registers from the adapter.
-	 */
-	dprintk(("PREMAP\n"));
-
-	if((dev->regs.sa = (struct sa_registers *)ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL)
-	{	
-		printk(KERN_WARNING "aacraid: unable to map ARM.\n" );
-		return -1;
-	}
-	/*
-	 *	Check to see if the board failed any self tests.
-	 */
-	if (sa_readl(dev, Mailbox7) & SELF_TEST_FAILED) {
-		printk(KERN_WARNING "%s%d: adapter self-test failed.\n", name, instance);
-		return -1;
-	}
-	/*
-	 *	Check to see if the board panic'd while booting.
-	 */
-	if (sa_readl(dev, Mailbox7) & KERNEL_PANIC) {
-		printk(KERN_WARNING "%s%d: adapter kernel panic'd.\n", name, instance);
-		return -1;
-	}
-	start = jiffies;
-	/*
-	 *	Wait for the adapter to be up and running. Wait up to 3 minutes.
-	 */
-	while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) {
-		if (time_after(start+180*HZ, jiffies)) {
-			status = sa_readl(dev, Mailbox7) >> 16;
-			printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %d.\n", name, instance, le32_to_cpu(status));
-			return -1;
-		}
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(1);
-	}
-
-	dprintk(("ATIRQ\n"));
-	if (request_irq(dev->scsi_host_ptr->irq, aac_sa_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev ) < 0) {
-		printk(KERN_WARNING "%s%d: Interrupt unavailable.\n", name, instance);
-		return -1;
-	}
-
-	/*
-	 *	Fill in the function dispatch table.
-	 */
-
-	dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter;
-	dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt;
-	dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt;
-	dev->a_ops.adapter_notify = aac_sa_notify_adapter;
-
-	dprintk(("FUNCDONE\n"));
-
-	if(aac_init_adapter(dev) == NULL)
-		return -1;
-
-	dprintk(("NEWADAPTDONE\n"));
-	/*
-	 *	Start any kernel threads needed
-	 */
-	dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0);
-	/*
-	 *	Tell the adapter that all is configure, and it can start 
-	 *	accepting requests
-	 */
-	dprintk(("STARTING\n"));
-	aac_sa_start_adapter(dev);
-	dprintk(("STARTED\n"));
-	return 0;
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aha152x.c linux-2.4.20/drivers/scsi/aha152x.c
--- linux-2.4.19/drivers/scsi/aha152x.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aha152x.c	2002-10-29 11:18:32.000000000 +0000
@@ -602,7 +602,11 @@
 #define SCDONE(SCpnt)		SCDATA(SCpnt)->done
 #define SCSEM(SCpnt)		SCDATA(SCpnt)->sem
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#define SG_ADDRESS(buffer)	((buffer)->address)
+#else
 #define SG_ADDRESS(buffer)	((char *) (page_address((buffer)->page)+(buffer)->offset))
+#endif
 
 /* state handling */
 static void seldi_run(struct Scsi_Host *shpnt);
@@ -2657,7 +2661,7 @@
 		 * STCNT to trigger ENSWRAP interrupt, instead of
 		 * polling for DFIFOFULL
 		 */
-		the_time=jiffies + 10*HZ;
+		the_time=jiffies + 100*HZ;
 		while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time))
 			barrier();
 
@@ -2670,7 +2674,7 @@
 		if(TESTHI(DMASTAT, DFIFOFULL)) {
 			fifodata = 128;
 		} else {
-			the_time=jiffies + 10*HZ;
+			the_time=jiffies + 100*HZ;
 			while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time))
 				barrier();
 
@@ -2826,7 +2830,7 @@
 			CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
 		}
 
-		the_time=jiffies + 10*HZ;
+		the_time=jiffies + 100*HZ;
 		while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time))
 			barrier();
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aic7xxx/aic7770.c linux-2.4.20/drivers/scsi/aic7xxx/aic7770.c
--- linux-2.4.19/drivers/scsi/aic7xxx/aic7770.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aic7xxx/aic7770.c	2002-10-29 11:18:51.000000000 +0000
@@ -273,8 +273,8 @@
 
 	if (bootverbose)
 		printf("%s: Reading SEEPROM...", ahc_name(ahc));
-	have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)&sc,
-					/*start_addr*/0, sizeof(sc)/2);
+	have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc,
+					/*start_addr*/0, sizeof(*sc)/2);
 
 	if (have_seeprom) {
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aic7xxx/aic7xxx_core.c linux-2.4.20/drivers/scsi/aic7xxx/aic7xxx_core.c
--- linux-2.4.19/drivers/scsi/aic7xxx/aic7xxx_core.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aic7xxx/aic7xxx_core.c	2002-10-29 11:18:40.000000000 +0000
@@ -4367,7 +4367,7 @@
 	/*
 	 * DMA tag for our command fifos and other data in system memory
 	 * the card's sequencer must be able to access.  For initiator
-	 * roles, we need to allocate space for the the qinfifo and qoutfifo.
+	 * roles, we need to allocate space for the qinfifo and qoutfifo.
 	 * The qinfifo and qoutfifo are composed of 256 1 byte elements. 
 	 * When providing for the target mode role, we must additionally
 	 * provide space for the incoming target command fifo and an extra
@@ -6928,7 +6928,7 @@
 		panic("ahc_update_scsiid called on non-multitid unit\n");
 
 	/*
-	 * Since we will rely on the the TARGID mask
+	 * Since we will rely on the TARGID mask
 	 * for selection enables, ensure that OID
 	 * in SCSIID is not set to some other ID
 	 * that we don't want to allow selections on.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aic7xxx/aic7xxx_host.h linux-2.4.20/drivers/scsi/aic7xxx/aic7xxx_host.h
--- linux-2.4.19/drivers/scsi/aic7xxx/aic7xxx_host.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aic7xxx/aic7xxx_host.h	2002-10-29 11:18:39.000000000 +0000
@@ -89,7 +89,8 @@
 	present: 0,		 /* number of 7xxx's present  */\
 	unchecked_isa_dma: 0,	 /* no memory DMA restrictions*/\
 	use_clustering: ENABLE_CLUSTERING,			\
-	use_new_eh_code: 1					\
+	use_new_eh_code: 1,					\
+	highmem_io: 1,						\
 }
 
 #endif /* _AIC7XXX_HOST_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aic7xxx/aic7xxx_pci.c linux-2.4.20/drivers/scsi/aic7xxx/aic7xxx_pci.c
--- linux-2.4.19/drivers/scsi/aic7xxx/aic7xxx_pci.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aic7xxx/aic7xxx_pci.c	2002-10-29 11:18:32.000000000 +0000
@@ -1768,41 +1768,6 @@
 	*eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0;
 }
 	
-int
-ahc_acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd)
-{
-	int wait;
-
-	if ((ahc->features & AHC_SPIOCAP) != 0
-	 && (ahc_inb(ahc, SPIOCAP) & SEEPROM) == 0)
-		return (0);
-
-	/*
-	 * Request access of the memory port.  When access is
-	 * granted, SEERDY will go high.  We use a 1 second
-	 * timeout which should be near 1 second more than
-	 * is needed.  Reason: after the chip reset, there
-	 * should be no contention.
-	 */
-	SEEPROM_OUTB(sd, sd->sd_MS);
-	wait = 1000;  /* 1 second timeout in msec */
-	while (--wait && ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0)) {
-		ahc_delay(1000);  /* delay 1 msec */
-	}
-	if ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0) {
-		SEEPROM_OUTB(sd, 0); 
-		return (0);
-	}
-	return(1);
-}
-
-void
-ahc_release_seeprom(struct seeprom_descriptor *sd)
-{
-	/* Release access to the memory port and the serial EEPROM. */
-	SEEPROM_OUTB(sd, 0);
-}
-
 static void
 write_brdctl(struct ahc_softc *ahc, uint8_t value)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aic7xxx/aic7xxx_proc.c linux-2.4.20/drivers/scsi/aic7xxx/aic7xxx_proc.c
--- linux-2.4.19/drivers/scsi/aic7xxx/aic7xxx_proc.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aic7xxx/aic7xxx_proc.c	2002-10-29 11:18:31.000000000 +0000
@@ -54,6 +54,44 @@
 				      struct ahc_linux_device *dev);
 static int	ahc_proc_write_seeprom(struct ahc_softc *ahc,
 				       char *buffer, int length);
+				       
+
+int
+ahc_acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd)
+{
+	int wait;
+
+	if ((ahc->features & AHC_SPIOCAP) != 0
+	 && (ahc_inb(ahc, SPIOCAP) & SEEPROM) == 0)
+		return (0);
+
+	/*
+	 * Request access of the memory port.  When access is
+	 * granted, SEERDY will go high.  We use a 1 second
+	 * timeout which should be near 1 second more than
+	 * is needed.  Reason: after the chip reset, there
+	 * should be no contention.
+	 */
+	SEEPROM_OUTB(sd, sd->sd_MS);
+	wait = 1000;  /* 1 second timeout in msec */
+	while (--wait && ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0)) {
+		ahc_delay(1000);  /* delay 1 msec */
+	}
+	if ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0) {
+		SEEPROM_OUTB(sd, 0); 
+		return (0);
+	}
+	return(1);
+}
+
+
+void
+ahc_release_seeprom(struct seeprom_descriptor *sd)
+{
+	/* Release access to the memory port and the serial EEPROM. */
+	SEEPROM_OUTB(sd, 0);
+}
+
 
 static void
 copy_mem_info(struct info_str *info, char *data, int len)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/aic7xxx_old/aic7xxx.h linux-2.4.20/drivers/scsi/aic7xxx_old/aic7xxx.h
--- linux-2.4.19/drivers/scsi/aic7xxx_old/aic7xxx.h	2001-03-04 22:30:18.000000000 +0000
+++ linux-2.4.20/drivers/scsi/aic7xxx_old/aic7xxx.h	2002-10-29 11:18:31.000000000 +0000
@@ -55,7 +55,8 @@
 	present: 0,		/* number of 7xxx's present   */\
 	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
 	use_clustering: ENABLE_CLUSTERING,			\
-	use_new_eh_code: 0					\
+	use_new_eh_code: 0,					\
+	highmem_io: 1						\
 }
 
 extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/bvme6000.c linux-2.4.20/drivers/scsi/bvme6000.c
--- linux-2.4.19/drivers/scsi/bvme6000.c	2001-10-25 20:53:49.000000000 +0000
+++ linux-2.4.20/drivers/scsi/bvme6000.c	2002-10-29 11:18:33.000000000 +0000
@@ -23,9 +23,9 @@
 
 #include<linux/stat.h>
 
-extern ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
-			u32 base, int io_port, int irq, int dma,
-			long long options, int clock);
+extern int ncr53c7xx_init(Scsi_Host_Template *tpnt, int board, int chip,
+			  u32 base, int io_port, int irq, int dma,
+			  long long options, int clock);
 
 int bvme6000_scsi_detect(Scsi_Host_Template *tpnt)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/cpqfcTSinit.c linux-2.4.20/drivers/scsi/cpqfcTSinit.c
--- linux-2.4.19/drivers/scsi/cpqfcTSinit.c	2001-10-25 20:53:50.000000000 +0000
+++ linux-2.4.20/drivers/scsi/cpqfcTSinit.c	2002-10-29 11:18:32.000000000 +0000
@@ -261,10 +261,22 @@
 /* "Entry" point to discover if any supported PCI 
    bus adapter can be found
 */
-// We're supporting:
-// Compaq 64-bit, 66MHz HBA with Tachyon TS
-// Agilent XL2 
-#define HBA_TYPES 2
+/* We're supporting:
+ * Compaq 64-bit, 66MHz HBA with Tachyon TS
+ * Agilent XL2 
+ * HP Tachyon
+ */
+#define HBA_TYPES 3
+
+#ifndef PCI_DEVICE_ID_COMPAQ_
+#define PCI_DEVICE_ID_COMPAQ_TACHYON	0xa0fc
+#endif
+
+static struct SupportedPCIcards cpqfc_boards[] __initdata = {
+	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TACHYON},
+	{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHLITE},
+	{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHYON},
+};
 
 
 int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
@@ -274,35 +286,28 @@
   struct Scsi_Host *HostAdapter = NULL;
   CPQFCHBA *cpqfcHBAdata = NULL; 
   struct timer_list *cpqfcTStimer = NULL;
-  SupportedPCIcards PCIids[HBA_TYPES];
   int i;
-  
+
   ENTER("cpqfcTS_detect");
-  
+
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
   ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS;
 #else
   ScsiHostTemplate->proc_name = "cpqfcTS";
 #endif
-  
+
   if( pci_present() == 0) // no PCI busses?
   {
     printk( "  no PCI bus?@#!\n");
     return NumberOfAdapters;
   }
 
-  // what HBA adapters are we supporting?
-  PCIids[0].vendor_id = PCI_VENDOR_ID_COMPAQ;
-  PCIids[0].device_id = CPQ_DEVICE_ID;
-  PCIids[1].vendor_id = PCI_VENDOR_ID_HP; // i.e. 103Ch (Agilent == HP for now)
-  PCIids[1].device_id = AGILENT_XL2_ID;   // i.e. 1029h
-
   for( i=0; i < HBA_TYPES; i++)
   {
     // look for all HBAs of each type
 
-    while( (PciDev =
-      pci_find_device( PCIids[i].vendor_id, PCIids[i].device_id, PciDev) ))
+    while((PciDev = pci_find_device(cpqfc_boards[i].vendor_id,
+				    cpqfc_boards[i].device_id, PciDev)))
     {
 
       if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/cpqfcTSstructs.h linux-2.4.20/drivers/scsi/cpqfcTSstructs.h
--- linux-2.4.19/drivers/scsi/cpqfcTSstructs.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/cpqfcTSstructs.h	2002-10-29 11:18:39.000000000 +0000
@@ -95,14 +95,11 @@
 
 #define DEV_NAME "cpqfcTS"
 
-#define CPQ_DEVICE_ID     0xA0FC
-#define AGILENT_XL2_ID    0x1029
-
-typedef struct
+struct SupportedPCIcards
 {
   __u16 vendor_id;
   __u16 device_id;
-} SupportedPCIcards;
+};
 			 
 // nn:nn denotes bit field
                             // TachyonHeader struct def.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/cpqfcTSworker.c linux-2.4.20/drivers/scsi/cpqfcTSworker.c
--- linux-2.4.19/drivers/scsi/cpqfcTSworker.c	2001-10-25 20:53:50.000000000 +0000
+++ linux-2.4.20/drivers/scsi/cpqfcTSworker.c	2002-10-29 11:18:34.000000000 +0000
@@ -2911,7 +2911,7 @@
     }
   }
 
-Done:  
+Done:  ;
 }
 
 static void 
@@ -3028,7 +3028,7 @@
 
 
 
-Done:
+Done: ;
 
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/cpqioctl.c linux-2.4.20/drivers/scsi/cpqioctl.c
--- linux-2.4.19/drivers/scsi/cpqioctl.c	2000-09-19 15:01:35.000000000 +0000
+++ linux-2.4.20/drivers/scsi/cpqioctl.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,76 +0,0 @@
-// Test program for CPQFCTS ioctl calls
-// build with:
-// gcc -o cpqioctl cpqioctl.c
-// ld -o cpqioctl /lib/crt0.o cpqioctl.o -lc
-
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <linux/types.h>
-#include "../../include/scsi/scsi.h"
-#include "cpqfcTSioctl.h"
-
-typedef struct scsi_fctargaddress {
-        unsigned long host_port_id;
-        unsigned char host_wwn[8];
-} Scsi_FCTargAddress;
-
-int main(int argc, char **argv) {
-
- int fd, i;
- Scsi_FCTargAddress targ;
- int uselect=0;
-
-
-
-  if ( argc < 2 ) {
-    printf("usage: cpqioctl <Devfile>\n");
-    exit(1);
-  }
-
-  if ( (fd = open(argv[1], O_RDONLY)) == -1) {
-    perror("open");
-    exit(1);
-  }
-
-  if ( ioctl(fd, SCSI_IOCTL_FC_TARGET_ADDRESS, &targ) ) {
-    perror("ioctl");
-    exit(1);
-  }
-
-
-  printf("portid: %08x. wwn: ", targ.host_port_id);
-
-  for (i=0;i<8;i++) printf(" %02x", targ.host_wwn[i]);
-  printf("\n");
-
- while( uselect != 27 ) // not ESC key
-  {
-    printf("\n IOCTL \n");
-    printf( "1. Get PCI info\n");
-    printf( "2. Send Passthru\n");
-    printf( " ==> ");
-    scanf("%c", &uselect);
-
-    switch( uselect  )
-    {
-      case '1':
-      {
-        cciss_pci_info_struct pciinfo;
-	
-  	if( ioctl( fd, CCPQFCTS_GETPCIINFO ,&pciinfo ))
-          perror("ioctl");
-	else
-          printf( "\nPCI bus %d, dev_fn %d, board_id %Xh\n",
-            pciinfo.bus, pciinfo.dev_fn, pciinfo.board_id);
-      }
-
-    }
-  }
-
-
-  close(fd);
-  return 0;
-} 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/dec_esp.c linux-2.4.20/drivers/scsi/dec_esp.c
--- linux-2.4.19/drivers/scsi/dec_esp.c	2001-09-09 17:52:35.000000000 +0000
+++ linux-2.4.20/drivers/scsi/dec_esp.c	2002-10-29 11:18:33.000000000 +0000
@@ -46,6 +46,8 @@
 #include <asm/dec/ioasic_ints.h>
 #include <asm/dec/machtype.h>
 
+#include <asm/system.h>
+
 /*
  * Once upon a time the pmaz code used to be working but
  * it hasn't been maintained for quite some time.
@@ -101,6 +103,8 @@
 volatile unsigned long *scsi_sdr0;
 volatile unsigned long *scsi_sdr1;
 
+static void scsi_dma_merr_int(int, void *, struct pt_regs *);
+static void scsi_dma_err_int(int, void *, struct pt_regs *);
 static void scsi_dma_int(int, void *, struct pt_regs *);
 
 static Scsi_Host_Template driver_template = SCSI_DEC_ESP;
@@ -179,7 +183,7 @@
 		/* get virtual dma address for command buffer */
 		esp->esp_command_dvma = (__u32) KSEG1ADDR((volatile unsigned char *) cmd_buffer);
 	
-		esp->irq = SCSI_INT;
+		esp->irq = dec_interrupt[DEC_IRQ_ASC];
 
 		esp->scsi_id = 7;
 		
@@ -189,11 +193,20 @@
 		esp_initialize(esp);
 
 		if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, 
-				"NCR 53C94 SCSI", NULL))
+				"ncr53c94", NULL))
 			goto err_dealloc;
-		if (request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT, 
-				"JUNKIO SCSI DMA", NULL))
+		if (request_irq(dec_interrupt[DEC_IRQ_ASC_MERR],
+				scsi_dma_merr_int, SA_INTERRUPT, 
+				"ncr53c94 error", NULL))
 			goto err_free_irq;
+		if (request_irq(dec_interrupt[DEC_IRQ_ASC_ERR],
+				scsi_dma_err_int, SA_INTERRUPT, 
+				"ncr53c94 overrun", NULL))
+			goto err_free_irq_merr;
+		if (request_irq(dec_interrupt[DEC_IRQ_ASC_DMA],
+				scsi_dma_int, SA_INTERRUPT, 
+				"ncr53c94 dma", NULL))
+			goto err_free_irq_err;
  			
 	}
 
@@ -271,41 +284,35 @@
 	}
 	return 0;
 
- err_free_irq:
+err_free_irq_err:
+	free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], scsi_dma_err_int);
+err_free_irq_merr:
+	free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], scsi_dma_merr_int);
+err_free_irq:
 	free_irq(esp->irq, esp_intr);
- err_dealloc:
+err_dealloc:
 	esp_deallocate(esp);
 	return 0;
 }
 
 /************************************************************* DMA Functions */
-static void scsi_dma_int(int irq, void *dev_id, struct pt_regs *regs)
+static void scsi_dma_merr_int(int irq, void *dev_id, struct pt_regs *regs)
 {
-	extern volatile unsigned int *isr;
-	unsigned int dummy;
+	printk("Got unexpected SCSI DMA Interrupt! < ");
+	printk("SCSI_DMA_MEMRDERR ");
+	printk(">\n");
+}
 
-	if (*isr & SCSI_PTR_LOADED) {
-		/* next page */
-		*scsi_next_ptr = ((*scsi_dma_ptr + PAGE_SIZE) & PAGE_MASK) << 3;
-		*isr &= ~SCSI_PTR_LOADED;
-	} else {
-		if (*isr & SCSI_PAGOVRRUN)
-			*isr &= ~SCSI_PAGOVRRUN;
-		if (*isr & SCSI_DMA_MEMRDERR) {
-			printk("Got unexpected SCSI DMA Interrupt! < ");
-			printk("SCSI_DMA_MEMRDERR ");
-		printk(">\n");
-			*isr &= ~SCSI_DMA_MEMRDERR;
-		}
-	}
+static void scsi_dma_err_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* empty */
+}
 
-	/*
-	 * This routine will only work on IOASIC machines
-	 * so we can avoid an indirect function call here
-	 * and flush the writeback buffer the fast way
-	 */
-	dummy = *isr;
-	dummy = *isr;
+static void scsi_dma_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* next page */
+	*scsi_next_ptr = ((*scsi_dma_ptr + PAGE_SIZE) & PAGE_MASK) << 3;
+	fast_iob();
 }
 
 static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
@@ -357,9 +364,6 @@
 
 static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length)
 {
-	extern volatile unsigned int *isr;
-	unsigned int dummy;
-
 	if (vaddress & 3)
 		panic("dec_efs.c: unable to handle partial word transfers, yet...");
 
@@ -372,19 +376,11 @@
 	/* prepare for next page */
 	*scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3;
 	*ioasic_ssr |= (SCSI_DMA_DIR | SCSI_DMA_EN);
-
-	/*
-	 * see above
-	 */
-	dummy = *isr;
-	dummy = *isr;
+	fast_iob();
 }
 
 static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length)
 {
-	extern volatile unsigned int *isr;
-	unsigned int dummy;
-
 	if (vaddress & 3)
 		panic("dec_efs.c: unable to handle partial word transfers, yet...");
 
@@ -397,22 +393,17 @@
 	/* prepare for next page */
 	*scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3;
 	*ioasic_ssr |= SCSI_DMA_EN;
-
-	/*
-	 * see above
-	 */
-	dummy = *isr;
-	dummy = *isr;
+	fast_iob();
 }
 
 static void dma_ints_off(struct NCR_ESP *esp)
 {
-	disable_irq(SCSI_DMA_INT);
+	disable_irq(dec_interrupt[DEC_IRQ_ASC_DMA]);
 }
 
 static void dma_ints_on(struct NCR_ESP *esp)
 {
-	enable_irq(SCSI_DMA_INT);
+	enable_irq(dec_interrupt[DEC_IRQ_ASC_DMA]);
 }
 
 static int dma_irq_p(struct NCR_ESP *esp)
@@ -459,12 +450,12 @@
 		sg[sz].dvma_addr = PHYSADDR(sg[sz].addr);
 	sz--;
     }
-	sp->SCp.ptr = (char *) ((unsigned long) sp->SCp.buffer->dvma_address);
+	sp->SCp.ptr = (char *) ((unsigned long) sp->SCp.buffer->dma_address);
 }
 
 static void dma_advance_sg(Scsi_Cmnd * sp)
 {
-	sp->SCp.ptr = (char *) ((unsigned long) sp->SCp.buffer->dvma_address);
+	sp->SCp.ptr = (char *) ((unsigned long) sp->SCp.buffer->dma_address);
 }
 
 static void pmaz_dma_drain(struct NCR_ESP *esp)
@@ -483,6 +474,8 @@
 
 	*dmareg = TC_ESP_DMA_ADDR(esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE);
 
+	iob();
+
 	esp_virt_buffer = vaddress;
 	scsi_current_length = length;
 }
@@ -497,6 +490,7 @@
 	*dmareg = TC_ESP_DMAR_WRITE | 
 		TC_ESP_DMA_ADDR(esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE);
 
+	iob();
 }
 
 static void pmaz_dma_ints_off(struct NCR_ESP *esp)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/dpt_i2o.c linux-2.4.20/drivers/scsi/dpt_i2o.c
--- linux-2.4.19/drivers/scsi/dpt_i2o.c	2001-11-09 22:05:06.000000000 +0000
+++ linux-2.4.20/drivers/scsi/dpt_i2o.c	2002-10-29 11:18:35.000000000 +0000
@@ -85,7 +85,7 @@
 #elif defined(__alpha__)
 	PROC_ALPHA ,
 #else
-	(-1),
+	(-1),(-1)
 #endif
 	 FT_HBADRVR, 0, OEM_DPT, OS_LINUX, CAP_OVERLAP, DEV_ALL,
 	ADF_ALL_SC5, 0, 0, DPT_VERSION, DPT_REVISION, DPT_SUBREVISION,
@@ -110,10 +110,6 @@
 static adpt_hba* hba_chain = NULL;
 static int hba_count = 0;
 
-// Debug flags to be put into the HBA flags field when initialized
-// Make sure to enable DEBUG_PRINT for these flags to work
-static unsigned long DebugFlags = HBA_FLAGS_DBG_SCAN_B | HBA_FLAGS_DBG_FLAGS_MASK;
-
 static struct file_operations adpt_fops = {
 	ioctl: adpt_ioctl,
 	open: adpt_open,
@@ -1141,7 +1137,8 @@
        // to support async LCT get
 	wait_data->next = adpt_post_wait_queue;
 	adpt_post_wait_queue = wait_data;
-	adpt_post_wait_id = (++adpt_post_wait_id & 0x7fff);
+	adpt_post_wait_id++;
+	adpt_post_wait_id = (adpt_post_wait_id & 0x7fff);
 	wait_data->id =  adpt_post_wait_id;
 	spin_unlock_irqrestore(&adpt_post_wait_lock, flags);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/eata.c linux-2.4.20/drivers/scsi/eata.c
--- linux-2.4.19/drivers/scsi/eata.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/eata.c	2002-10-29 11:18:36.000000000 +0000
@@ -1,9 +1,45 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
- *      01 Jan 2002 Rev. 6.50 for linux 2.4.16
+ *      25 Jun 2002 Rev. 6.70 for linux 2.4.19
+ *        + This release is the first one tested on a Big Endian platform:
+ *          fixed endian-ness problem due to bitfields;
+ *          fixed endian-ness problem in read_pio.
+ *        + Added new options for selectively probing ISA, EISA and PCI bus:
+ *
+ *          Boot option   Parameter name    Default according to
+ *
+ *          ip:[y|n]      isa_probe=[1|0]   CONFIG_ISA  defined
+ *          ep:[y|n]      eisa_probe=[1|0]  CONFIG_EISA defined
+ *          pp:[y|n]      pci_probe=[1|0]   CONFIG_PCI  defined
+ *
+ *          The default action is to perform probing if the corrisponding
+ *          bus is configured and to skip probing otherwise.
+ *
+ *        + If pci_probe is in effect and a list of I/O  ports is specified
+ *          as parameter or boot option, pci_enable_device() is performed
+ *          on all pci devices matching PCI_CLASS_STORAGE_SCSI.
+ *
+ *      21 Feb 2002 Rev. 6.52 for linux 2.4.18
+ *        + Backport from rev. 7.22 (use io_request_lock).
+ *
+ *      20 Feb 2002 Rev. 7.22 for linux 2.5.5
+ *        + Remove any reference to virt_to_bus().
+ *        + Fix pio hang while detecting multiple HBAs.
+ *        + Fixed a board detection bug: in a system with
+ *          multiple ISA/EISA boards, all but the first one
+ *          were erroneously detected as PCI.
+ *
+ *      01 Jan 2002 Rev. 7.20 for linux 2.5.1
  *        + Use the dynamic DMA mapping API.
  *
+ *      19 Dec 2001 Rev. 7.02 for linux 2.5.1
+ *        + Use SCpnt->sc_data_direction if set.
+ *        + Use sglist.page instead of sglist.address.
+ *
+ *      11 Dec 2001 Rev. 7.00 for linux 2.5.1
+ *        + Use host->host_lock instead of io_request_lock.
+ *
  *       1 May 2001 Rev. 6.05 for linux 2.4.4
  *        + Clean up all pci related routines.
  *        + Fix data transfer direction for opcode SEND_CUE_SHEET (0x5d)
@@ -22,7 +58,7 @@
  *          boot time.
  *        + Improved boot messages: all tagged capable device are
  *          indicated as "tagged" or "soft-tagged" :
- *          - "soft-tagged"  means that the driver is trying to do its 
+ *          - "soft-tagged"  means that the driver is trying to do its
  *            own tagging (i.e. the tc:y option is in effect);
  *          - "tagged" means that the device supports tagged commands,
  *            but the driver lets the HBA be responsible for tagging
@@ -33,7 +69,7 @@
  *        + When loaded as a module, accepts the new parameter boot_options
  *          which value is a string with the same format of the kernel boot
  *          command line options. A valid example is:
- *          modprobe eata boot_options=\"0x7410,0x230,lc:y,tc:n,mq:4\"
+ *          modprobe eata 'boot_options="0x7410,0x230,lc:y,tc:n,mq:4"'
  *
  *       9 Sep 1999 Rev. 5.10 for linux 2.2.12 and 2.3.17
  *        + 64bit cleanup for Linux/Alpha platform support
@@ -297,7 +333,7 @@
  *  include in the list of i/o ports to be probed all the PCI SCSI controllers.
  *
  *  Due to a DPT BIOS "feature", it might not be possible to force an EISA
- *  address on more then a single DPT PCI board, so in this case you have to
+ *  address on more than a single DPT PCI board, so in this case you have to
  *  let the PCI BIOS assign the addresses.
  *
  *  The sequence of detection probes is:
@@ -414,6 +450,9 @@
 MODULE_PARM(tag_mode, "i");
 MODULE_PARM(ext_tran, "i");
 MODULE_PARM(rev_scan, "i");
+MODULE_PARM(isa_probe, "i");
+MODULE_PARM(eisa_probe, "i");
+MODULE_PARM(pci_probe, "i");
 MODULE_AUTHOR("Dario Ballabio");
 
 #endif
@@ -441,11 +480,15 @@
 #include <linux/ctype.h>
 #include <linux/spinlock.h>
 
+#if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD)
+#error "Adjust your <asm/byteorder.h> defines"
+#endif
+
 /* Subversion values */
 #define ISA  0
 #define ESA 1
 
-#undef FORCE_CONFIG
+#undef  FORCE_CONFIG
 
 #undef  DEBUG_LINKED_COMMANDS
 #undef  DEBUG_DETECT
@@ -498,7 +541,7 @@
 #define REG_LM          3
 #define REG_MID         4
 #define REG_MSB         5
-#define REGION_SIZE     9
+#define REGION_SIZE     9UL
 #define MAX_ISA_ADDR    0x03ff
 #define MIN_EISA_ADDR   0x1c88
 #define MAX_EISA_ADDR   0xfc88
@@ -522,7 +565,7 @@
 #define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM)
 
 /* "EATA", in Big Endian format */
-#define EATA_SIGNATURE 0x41544145
+#define EATA_SIG_BE 0x45415441
 
 /* Number of valid bytes in the board config structure for EATA 2.0x */
 #define EATA_2_0A_SIZE 28
@@ -533,6 +576,12 @@
 struct eata_info {
    u_int32_t data_len;  /* Number of valid bytes after this field */
    u_int32_t sign;      /* ASCII "EATA" signature */
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+   unchar version:4, :4;
+   unchar  haaval:1, ata:1, drqvld:1, dmasup:1, morsup:1, trnxfr:1, tarsup:1,
+           ocsena:1;
+#else
    unchar        :4,    /* unused low nibble */
           version:4;    /* EATA version, should be 0x1 */
    unchar  ocsena:1,    /* Overlap Command Support Enabled */
@@ -543,6 +592,8 @@
            drqvld:1,    /* DRQ Index (DRQX) is valid */
               ata:1,    /* This is an ATA device */
            haaval:1;    /* Host Adapter Address Valid */
+#endif
+
    ushort cp_pad_len;   /* Number of pad bytes after cp_len */
    unchar host_addr[4]; /* Host Adapter SCSI ID for channels 3, 2, 1, 0 */
    u_int32_t cp_len;    /* Number of valid bytes in cp */
@@ -550,6 +601,15 @@
    ushort queue_size;   /* Max number of cp that can be queued */
    ushort unused;
    ushort scatt_size;   /* Max number of entries in scatter/gather table */
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+   unchar    drqx:2, second:1, irq_tr:1, irq:4;
+   unchar  sync;
+   unchar         :4, res1:1, large_sg:1, forcaddr:1, isaena:1;
+   unchar max_chan:3, max_id:5;
+   unchar   max_lun;
+   unchar     eisa:1, pci:1, idquest:1, m1:1, :4;
+#else
    unchar     irq:4,    /* Interrupt Request assigned to this controller */
            irq_tr:1,    /* 0 for edge triggered, 1 for level triggered */
            second:1,    /* 1 if this is a secondary (not primary) controller */
@@ -572,6 +632,8 @@
           idquest:1,    /* RAIDNUM returned is questionable */
               pci:1,    /* This board is PCI */
              eisa:1;    /* This board is EISA */
+#endif
+
    unchar   raidnum;    /* Uniquely identifies this HBA in a system */
    unchar   notused;
 
@@ -581,18 +643,30 @@
 /* Board config structure */
 struct eata_config {
    ushort len;          /* Number of bytes following this field */
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+   unchar     :4, tarena:1, mdpena:1, ocena:1, edis:1;
+#else
    unchar edis:1,       /* Disable EATA interface after config command */
          ocena:1,       /* Overlapped Commands Enabled */
         mdpena:1,       /* Transfer all Modified Data Pointer Messages */
         tarena:1,       /* Target Mode Enabled for this controller */
               :4;
+#endif
+
    unchar cpad[511];
    };
 
 /* Returned status packet structure */
 struct mssp {
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+   unchar            eoc:1, adapter_status:7;
+#else
    unchar adapter_status:7,    /* State related to current command */
                      eoc:1;    /* End Of Command (1 = command completed) */
+#endif
+
    unchar target_status;       /* SCSI status received after data transfer */
    unchar unused[2];
    u_int32_t inv_res_len;      /* Number of bytes not transferred */
@@ -607,6 +681,16 @@
 
 /* MailBox SCSI Command Packet */
 struct mscp {
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+   unchar     din:1, dout:1, interp:1, :1, sg:1, reqsen:1, init:1, sreset:1;
+   unchar sense_len;
+   unchar unused[3];
+   unchar        :7, fwnest:1;
+   unchar        :5, hbaci:1, iat:1, phsunit:1;
+   unchar channel:3, target:5;
+   unchar     one:1, dispri:1, luntar:1, lun:5;
+#else
    unchar  sreset:1,     /* SCSI Bus Reset Signal should be asserted */
              init:1,     /* Re-initialize controller and self test */
            reqsen:1,     /* Transfer Request Sense Data to addr using DMA */
@@ -629,6 +713,8 @@
            luntar:1,     /* This cp is for Target (not LUN) */
            dispri:1,     /* Disconnect Privilege granted */
               one:1;     /* 1 */
+#endif
+
    unchar mess[3];       /* Massage to/from Target */
    unchar cdb[12];       /* Command Descriptor Block */
    u_int32_t data_len;   /* If sg=0 Data Length, if sg=1 sglist length */
@@ -636,11 +722,18 @@
    u_int32_t data_address; /* If sg=0 Data Address, if sg=1 sglist address */
    u_int32_t sp_dma_addr;  /* Address where sp is DMA'ed when cp completes */
    u_int32_t sense_addr; /* Address where Sense Data is DMA'ed on error */
+
    /* Additional fields begin here. */
    Scsi_Cmnd *SCpnt;
-   struct sg_list *sglist;
+
+   /* All the cp structure is zero filled by queuecommand except the
+      following CP_TAIL_SIZE bytes, initialized by detect */
+   dma_addr_t cp_dma_addr; /* dma handle for this cp structure */
+   struct sg_list *sglist; /* pointer to the allocated SG list */
    };
 
+#define CP_TAIL_SIZE (sizeof(struct sglist *) + sizeof(dma_addr_t))
+
 struct hostdata {
    struct mscp cp[MAX_MAILBOXES];       /* Mailboxes for this board */
    unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */
@@ -648,7 +741,6 @@
    unsigned int iocount;                /* Total i/o done for this board */
    int board_number;                    /* Number of this board */
    char board_name[16];                 /* Name of this board */
-   char board_id[256];                  /* data from INQUIRY on this board */
    int in_reset;                        /* True if board is doing a reset */
    int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */
    int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If TRUE redo i/o on target */
@@ -698,10 +790,13 @@
 #define BN(board) (HD(board)->board_name)
 
 /* Device is Big Endian */
-#define H2DEV(x) cpu_to_be32(x)
-#define DEV2H(x) be32_to_cpu(x)
+#define H2DEV(x)   cpu_to_be32(x)
+#define DEV2H(x)   be32_to_cpu(x)
+#define H2DEV16(x) cpu_to_be16(x)
+#define DEV2H16(x) be16_to_cpu(x)
 
-#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
+/* But transfer orientation from the 16 bit data register is Little Endian */
+#define REG2H(x)   le16_to_cpu(x)
 
 static void do_interrupt_handler(int, void *, struct pt_regs *);
 static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
@@ -731,6 +826,24 @@
 static int max_queue_depth = MAX_CMD_PER_LUN;
 #endif
 
+#if defined(CONFIG_ISA)
+static int isa_probe = TRUE;
+#else
+static int isa_probe = FALSE;
+#endif
+
+#if defined(CONFIG_EISA)
+static int eisa_probe = TRUE;
+#else
+static int eisa_probe = FALSE;
+#endif
+
+#if defined(CONFIG_PCI)
+static int pci_probe = TRUE;
+#else
+static int pci_probe = FALSE;
+#endif
+
 static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
    Scsi_Device *dev;
    int j, ntag = 0, nuntag = 0, tqd, utqd;
@@ -801,14 +914,18 @@
 }
 
 static inline int do_dma(unsigned long iobase, unsigned long addr, unchar cmd) {
+   unsigned char *byaddr;
+   unsigned long devaddr;
 
    if (wait_on_busy(iobase, (addr ? MAXLOOP * 100 : MAXLOOP))) return TRUE;
 
-   if ((addr = V2DEV(addr))) {
-      outb((char) (addr >> 24), iobase + REG_LOW);
-      outb((char) (addr >> 16), iobase + REG_LM);
-      outb((char) (addr >> 8),  iobase + REG_MID);
-      outb((char)  addr,        iobase + REG_MSB);
+   if (addr) {
+      devaddr = H2DEV(addr);
+      byaddr = (unsigned char *) &devaddr;
+      outb(byaddr[3], iobase + REG_LOW);
+      outb(byaddr[2], iobase + REG_LM);
+      outb(byaddr[1], iobase + REG_MID);
+      outb(byaddr[0], iobase + REG_MSB);
       }
 
    outb(cmd, iobase + REG_CMD);
@@ -827,7 +944,7 @@
          }
 
       loop = MAXLOOP;
-      *p = inw(iobase);
+      *p = REG2H(inw(iobase));
       }
 
    return FALSE;
@@ -858,6 +975,29 @@
    return NULL;
 }
 
+static void enable_pci_ports(void) {
+
+#if defined(CONFIG_PCI)
+
+   struct pci_dev *dev = NULL;
+
+   if (!pci_present()) return;
+
+   while((dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) {
+
+#if defined(DEBUG_PCI_DETECT)
+      printk("%s: enable_pci_ports, bus %d, devfn 0x%x.\n",
+             driver_name, dev->bus->number, dev->devfn);
+#endif
+
+      if (pci_enable_device (dev))
+         printk("%s: warning, pci_enable_device failed, bus %d devfn 0x%x.\n",
+                driver_name, dev->bus->number, dev->devfn);
+      }
+
+#endif /* end CONFIG_PCI */
+}
+
 static inline int port_detect \
       (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt) {
    unsigned char irq, dma_channel, subversion, i, is_pci = FALSE;
@@ -881,36 +1021,54 @@
       }
 
    if (do_dma(port_base, 0, READ_CONFIG_PIO)) {
+#if defined(DEBUG_DETECT)
+      printk("%s: detect, do_dma failed at 0x%03lx.\n", name, port_base);
+#endif
       release_region(port_base, REGION_SIZE);
       return FALSE;
       }
 
    /* Read the info structure */
    if (read_pio(port_base, (ushort *)&info, (ushort *)&info.ipad[0])) {
+#if defined(DEBUG_DETECT)
+      printk("%s: detect, read_pio failed at 0x%03lx.\n", name, port_base);
+#endif
       release_region(port_base, REGION_SIZE);
       return FALSE;
       }
 
+   info.data_len = DEV2H(info.data_len);
+   info.sign = DEV2H(info.sign);
+   info.cp_pad_len = DEV2H16(info.cp_pad_len);
+   info.cp_len = DEV2H(info.cp_len);
+   info.sp_len = DEV2H(info.sp_len);
+   info.scatt_size = DEV2H16(info.scatt_size);
+   info.queue_size = DEV2H16(info.queue_size);
+
    /* Check the controller "EATA" signature */
-   if (info.sign != EATA_SIGNATURE) {
+   if (info.sign != EATA_SIG_BE) {
+#if defined(DEBUG_DETECT)
+      printk("%s: signature 0x%04x discarded.\n", name, info.sign);
+#endif
       release_region(port_base, REGION_SIZE);
       return FALSE;
       }
 
-   if (DEV2H(info.data_len) < EATA_2_0A_SIZE) {
+   if (info.data_len < EATA_2_0A_SIZE) {
       printk("%s: config structure size (%d bytes) too short, detaching.\n",
-             name, DEV2H(info.data_len));
+             name, info.data_len);
       release_region(port_base, REGION_SIZE);
       return FALSE;
       }
-   else if (DEV2H(info.data_len) == EATA_2_0A_SIZE)
+   else if (info.data_len == EATA_2_0A_SIZE)
       protocol_rev = 'A';
-   else if (DEV2H(info.data_len) == EATA_2_0B_SIZE)
+   else if (info.data_len == EATA_2_0B_SIZE)
       protocol_rev = 'B';
    else
       protocol_rev = 'C';
 
-   if (!setup_done && j > 0 && j <= MAX_PCI) {
+   if (protocol_rev != 'A' && info.forcaddr) {
+      printk("%s: warning, port address has been forced.\n", name);
       bus_type = "PCI";
       is_pci = TRUE;
       subversion = ESA;
@@ -973,7 +1131,7 @@
 
    if (is_pci) {
       pdev = get_pci_dev(port_base);
-      if (!pdev) 
+      if (!pdev)
          printk("%s: warning, failed to get pci_dev structure.\n", name);
       }
    else
@@ -1003,18 +1161,29 @@
 
 #if defined(FORCE_CONFIG)
    {
-   struct eata_config config;
+   struct eata_config *cf;
+   dma_addr_t cf_dma_addr;
+
+   cf = pci_alloc_consistent(pdev, sizeof(struct eata_config), &cf_dma_addr);
+
+   if (!cf) {
+      printk("%s: config, pci_alloc_consistent failed, detaching.\n", name);
+      release_region(port_base, REGION_SIZE);
+      return FALSE;
+      }
 
    /* Set board configuration */
-   memset((char *)&config, 0, sizeof(struct eata_config));
-   config.len = (ushort) cpu_to_be16((ushort)510);
-   config.ocena = TRUE;
+   memset((char *)cf, 0, sizeof(struct eata_config));
+   cf->len = (ushort) H2DEV16((ushort)510);
+   cf->ocena = TRUE;
 
-   if (do_dma(port_base, (unsigned long)&config, SET_CONFIG_DMA)) {
+   if (do_dma(port_base, cf_dma_addr, SET_CONFIG_DMA)) {
       printk("%s: busy timeout sending configuration, detaching.\n", name);
+      pci_free_consistent(pdev, sizeof(struct eata_config), cf, cf_dma_addr);
       release_region(port_base, REGION_SIZE);
       return FALSE;
       }
+
    }
 #endif
 
@@ -1036,9 +1205,9 @@
    sh[j]->n_io_port = REGION_SIZE;
    sh[j]->dma_channel = dma_channel;
    sh[j]->irq = irq;
-   sh[j]->sg_tablesize = (ushort) be16_to_cpu(info.scatt_size);
+   sh[j]->sg_tablesize = (ushort) info.scatt_size;
    sh[j]->this_id = (ushort) info.host_addr[3];
-   sh[j]->can_queue = (ushort) be16_to_cpu(info.queue_size);
+   sh[j]->can_queue = (ushort) info.queue_size;
    sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
    sh[j]->select_queue_depths = select_queue_depths;
    memset(HD(j), 0, sizeof(struct hostdata));
@@ -1102,6 +1271,10 @@
    else                       sprintf(dma_name, "DMA %u", dma_channel);
 
    for (i = 0; i < sh[j]->can_queue; i++)
+      HD(j)->cp[i].cp_dma_addr = pci_map_single(HD(j)->pdev,
+            &HD(j)->cp[i], sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL);
+
+   for (i = 0; i < sh[j]->can_queue; i++)
       if (! ((&HD(j)->cp[i])->sglist = kmalloc(
             sh[j]->sg_tablesize * sizeof(struct sg_list),
             (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) {
@@ -1110,7 +1283,7 @@
          return FALSE;
          }
 
-   if (! (HD(j)->sp_cpu_addr = pci_alloc_consistent(HD(j)->pdev, 
+   if (! (HD(j)->sp_cpu_addr = pci_alloc_consistent(HD(j)->pdev,
          sizeof(struct mssp), &HD(j)->sp_dma_addr))) {
       printk("%s: pci_alloc_consistent failed, detaching.\n", BN(j));
       eata2x_release(sh[j]);
@@ -1132,9 +1305,11 @@
 
    if (j == 0) {
       printk("EATA/DMA 2.0x: Copyright (C) 1994-2002 Dario Ballabio.\n");
-      printk("%s config options -> tc:%c, lc:%c, mq:%d, rs:%c, et:%c.\n",
-             driver_name, tag_type, YESNO(linked_comm), max_queue_depth,
-             YESNO(rev_scan), YESNO(ext_tran));
+      printk("%s config options -> tc:%c, lc:%c, mq:%d, rs:%c, et:%c, "\
+             "ip:%c, ep:%c, pp:%c.\n", driver_name, tag_type,
+             YESNO(linked_comm), max_queue_depth, YESNO(rev_scan),
+             YESNO(ext_tran), YESNO(isa_probe), YESNO(eisa_probe),
+             YESNO(pci_probe));
       }
 
    printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d.\n",
@@ -1153,8 +1328,8 @@
    printk("%s: Vers. 0x%x, ocs %u, tar %u, trnxfr %u, more %u, SYNC 0x%x, "\
           "sec. %u, infol %d, cpl %d spl %d.\n", name, info.version,
           info.ocsena, info.tarsup, info.trnxfr, info.morsup, info.sync,
-          info.second, DEV2H(info.data_len), DEV2H(info.cp_len),
-          DEV2H(info.sp_len));
+          info.second, info.data_len, info.cp_len,
+          info.sp_len);
 
    if (protocol_rev == 'B' || protocol_rev == 'C')
       printk("%s: isaena %u, forcaddr %u, max_id %u, max_chan %u, "\
@@ -1204,6 +1379,9 @@
       else if (!strncmp(cur, "ls:", 3))  link_statistics = val;
       else if (!strncmp(cur, "et:", 3))  ext_tran = val;
       else if (!strncmp(cur, "rs:", 3))  rev_scan = val;
+      else if (!strncmp(cur, "ip:", 3))  isa_probe = val;
+      else if (!strncmp(cur, "ep:", 3))  eisa_probe = val;
+      else if (!strncmp(cur, "pp:", 3))  pci_probe = val;
 
       if ((cur = strchr(cur, ','))) ++cur;
       }
@@ -1285,7 +1463,19 @@
 
    for (k = 0; k < MAX_BOARDS + 1; k++) sh[k] = NULL;
 
-   if (!setup_done) add_pci_ports();
+   for (k = MAX_INT_PARAM; io_port[k]; k++)
+      if (io_port[k] == SKIP) continue;
+      else if (io_port[k] <= MAX_ISA_ADDR) {
+         if (!isa_probe) io_port[k] = SKIP;
+         }
+      else if (io_port[k] >= MIN_EISA_ADDR && io_port[k] <= MAX_EISA_ADDR) {
+         if (!eisa_probe) io_port[k] = SKIP;
+         }
+
+   if (pci_probe) {
+      if (!setup_done) add_pci_ports();
+      else          enable_pci_ports();
+      }
 
    for (k = 0; io_port[k]; k++) {
 
@@ -1315,10 +1505,10 @@
 
    if (!SCpnt->use_sg) {
 
-      if (!SCpnt->request_bufflen)
-         cpp->data_address = V2DEV(SCpnt->request_buffer);
+      /* If we get here with PCI_DMA_NONE, pci_map_single triggers a BUG() */
+      if (!SCpnt->request_bufflen) pci_dir = PCI_DMA_BIDIRECTIONAL;
 
-      else if (SCpnt->request_buffer)
+      if (SCpnt->request_buffer)
          cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev,
                   SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir));
 
@@ -1335,7 +1525,8 @@
       }
 
    cpp->sg = TRUE;
-   cpp->data_address = V2DEV(cpp->sglist);
+   cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, cpp->sglist,
+                             SCpnt->use_sg * sizeof(struct sg_list), pci_dir));
    cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list)));
 }
 
@@ -1351,13 +1542,14 @@
       pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
                        DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
 
-   if (SCpnt->use_sg) 
+   if (SCpnt->use_sg)
       pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir);
 
-   else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len))
-      pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), 
-                       DEV2H(cpp->data_len), pci_dir);
+   if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL;
 
+   if (DEV2H(cpp->data_address))
+      pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address),
+                       DEV2H(cpp->data_len), pci_dir);
 }
 
 static void sync_dma(unsigned int i, unsigned int j) {
@@ -1372,14 +1564,15 @@
       pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
                           DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
 
-   if (SCpnt->use_sg) 
-      pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, 
+   if (SCpnt->use_sg)
+      pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer,
                          SCpnt->use_sg, pci_dir);
 
-   else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len))
-      pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), 
-                          DEV2H(cpp->data_len), pci_dir);
+   if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL;
 
+   if (DEV2H(cpp->data_address))
+      pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address),
+                       DEV2H(cpp->data_len), pci_dir);
 }
 
 static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) {
@@ -1400,8 +1593,7 @@
    struct mscp *cpp;
    Scsi_Cmnd *SCpnt;
 
-   cpp = &HD(j)->cp[i];
-   SCpnt = cpp->SCpnt;
+   cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
 
    if (SCpnt->sc_data_direction == SCSI_DATA_READ) {
       cpp->din  = TRUE;
@@ -1419,7 +1611,7 @@
       return;
       }
 
-   if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) 
+   if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN)
       panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j));
 
    for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
@@ -1470,7 +1662,7 @@
    /* Set pointer to control packet structure */
    cpp = &HD(j)->cp[i];
 
-   memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *));
+   memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE);
 
    /* Set pointer to status packet structure, Big Endian format */
    cpp->sp_dma_addr = H2DEV(HD(j)->sp_dma_addr);
@@ -1527,7 +1719,7 @@
       }
 
    /* Send control packet to the board */
-   if (do_dma(sh[j]->io_port, (unsigned long) cpp, SEND_CP_DMA)) {
+   if (do_dma(sh[j]->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) {
       unmap_dma(i, j);
       SCpnt->host_scribble = NULL;
       printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n",
@@ -1926,7 +2118,7 @@
    for (n = 0; n < n_ready; n++) {
       k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
 
-      if (do_dma(sh[j]->io_port, (unsigned long) cpp, SEND_CP_DMA)) {
+      if (do_dma(sh[j]->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) {
          printk("%s: %s, target %d.%d:%d, pid %ld, mbox %d, adapter"\
                 " busy, will abort.\n", BN(j), (ihdlr ? "ihdlr" : "qcomm"),
                 SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k);
@@ -1975,8 +2167,21 @@
    /* Read the status register to clear the interrupt indication */
    reg = inb(sh[j]->io_port + REG_STATUS);
 
+#if defined (DEBUG_INTERRUPT)
+   {
+   unsigned char *bytesp;
+   int cnt;
+   bytesp= (unsigned char *) spp;
+   if (HD(j)->iocount < 200) {
+      printk("sp[] =");
+      for (cnt=0; cnt < 15; cnt++) printk(" 0x%x", bytesp[cnt]);
+      printk("\n");
+      }
+   }
+#endif
+
    /* Reject any sp with supspect data */
-   if (spp->eoc == FALSE)
+   if (spp->eoc == FALSE && HD(j)->iocount > 1)
       printk("%s: ihdlr, spp->eoc == FALSE, irq %d, reg 0x%x, count %d.\n",
              BN(j), irq, reg, HD(j)->iocount);
    if (spp->cpp_index < 0 || spp->cpp_index >= sh[j]->can_queue)
@@ -2182,10 +2387,14 @@
    for (i = 0; i < sh[j]->can_queue; i++)
       if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
 
-   if (HD(j)->sp_cpu_addr) 
+   for (i = 0; i < sh[j]->can_queue; i++)
+      pci_unmap_single(HD(j)->pdev, HD(j)->cp[i].cp_dma_addr,
+                     sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL);
+
+   if (HD(j)->sp_cpu_addr)
       pci_free_consistent(HD(j)->pdev, sizeof(struct mssp),
                           HD(j)->sp_cpu_addr, HD(j)->sp_dma_addr);
-                       
+
    free_irq(sh[j]->irq, &sha[j]);
 
    if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/eata.h linux-2.4.20/drivers/scsi/eata.h
--- linux-2.4.19/drivers/scsi/eata.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/eata.h	2002-10-29 11:18:34.000000000 +0000
@@ -13,7 +13,7 @@
 int eata2x_reset(Scsi_Cmnd *);
 int eata2x_biosparam(Disk *, kdev_t, int *);
 
-#define EATA_VERSION "6.50.00"
+#define EATA_VERSION "6.70.00"
 
 #define EATA {                                                               \
                 name:              "EATA/DMA 2.0x rev. " EATA_VERSION " ",   \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/esp.c linux-2.4.20/drivers/scsi/esp.c
--- linux-2.4.19/drivers/scsi/esp.c	2001-02-19 03:49:55.000000000 +0000
+++ linux-2.4.20/drivers/scsi/esp.c	2002-10-29 11:18:40.000000000 +0000
@@ -378,7 +378,7 @@
 #endif
 
 #ifdef DEBUG_ESP_CMDS
-extern inline void esp_cmd(struct esp *esp, u8 cmd)
+static inline void esp_cmd(struct esp *esp, u8 cmd)
 {
 	esp->espcmdlog[esp->espcmdent] = cmd;
 	esp->espcmdent = (esp->espcmdent + 1) & 31;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/esp.h linux-2.4.20/drivers/scsi/esp.h
--- linux-2.4.19/drivers/scsi/esp.h	2000-09-18 20:40:17.000000000 +0000
+++ linux-2.4.20/drivers/scsi/esp.h	2002-10-29 11:18:31.000000000 +0000
@@ -8,6 +8,8 @@
 #ifndef _SPARC_ESP_H
 #define _SPARC_ESP_H
 
+#include <linux/config.h>
+
 /* For dvma controller register definitions. */
 #include <asm/dma.h>
 
@@ -400,6 +402,28 @@
 			 int hostno, int inout);
 extern int esp_revoke(Scsi_Device* SDptr);
 
+#ifdef CONFIG_SPARC64
+#define SCSI_SPARC_ESP {                                        \
+		proc_name:      "esp",				\
+		proc_info:      &esp_proc_info,			\
+		name:           "Sun ESP 100/100a/200",		\
+		detect:         esp_detect,			\
+		revoke:		esp_revoke,			\
+		info:           esp_info,			\
+		command:        esp_command,			\
+		queuecommand:   esp_queue,			\
+		abort:          esp_abort,			\
+		reset:          esp_reset,			\
+		can_queue:      7,				\
+		this_id:        7,				\
+		sg_tablesize:   SG_ALL,				\
+		cmd_per_lun:    1,				\
+		use_clustering: ENABLE_CLUSTERING,		\
+		use_new_eh_code: 0,				\
+		highmem_io:	1				\
+}
+#else
+/* Sparc32's iommu code cannot handle highmem pages yet. */
 #define SCSI_SPARC_ESP {                                        \
 		proc_name:      "esp",				\
 		proc_info:      &esp_proc_info,			\
@@ -416,8 +440,8 @@
 		sg_tablesize:   SG_ALL,				\
 		cmd_per_lun:    1,				\
 		use_clustering: ENABLE_CLUSTERING,		\
-		use_new_eh_code: 0				\
 }
+#endif
 
 /* For our interrupt engine. */
 #define for_each_esp(esp) \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/fdomain.c linux-2.4.20/drivers/scsi/fdomain.c
--- linux-2.4.19/drivers/scsi/fdomain.c	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.20/drivers/scsi/fdomain.c	2002-10-29 11:18:33.000000000 +0000
@@ -2041,7 +2041,7 @@
 		free_irq(shpnt->irq, shpnt);
 	if (shpnt->io_port && shpnt->n_io_port)
 		release_region(shpnt->io_port, shpnt->n_io_port);
-
+	return 0;
 }
 
 MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/hosts.c linux-2.4.20/drivers/scsi/hosts.c
--- linux-2.4.19/drivers/scsi/hosts.c	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.20/drivers/scsi/hosts.c	2002-10-29 11:18:32.000000000 +0000
@@ -129,7 +129,7 @@
  * once we are 100% sure that we want to use this host adapter -  it is a
  * pain to reverse this, so we try to avoid it 
  */
-
+extern int blk_nohighio;
 struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
     struct Scsi_Host * retval, *shpnt, *o_shp;
     Scsi_Host_Name *shn, *shn2;
@@ -235,6 +235,8 @@
     retval->cmd_per_lun = tpnt->cmd_per_lun;
     retval->unchecked_isa_dma = tpnt->unchecked_isa_dma;
     retval->use_clustering = tpnt->use_clustering;   
+    if (!blk_nohighio)
+	retval->highmem_io = tpnt->highmem_io;
 
     retval->select_queue_depths = tpnt->select_queue_depths;
     retval->max_sectors = tpnt->max_sectors;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/hosts.h linux-2.4.20/drivers/scsi/hosts.h
--- linux-2.4.19/drivers/scsi/hosts.h	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.20/drivers/scsi/hosts.h	2002-10-29 11:18:36.000000000 +0000
@@ -291,6 +291,8 @@
      */
     unsigned emulated:1;
 
+    unsigned highmem_io:1;
+
     /*
      * Name of proc directory
      */
@@ -390,6 +392,8 @@
     unsigned in_recovery:1;
     unsigned unchecked_isa_dma:1;
     unsigned use_clustering:1;
+    unsigned highmem_io:1;
+
     /*
      * True if this host was loaded as a loadable module
      */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/ide-scsi.c linux-2.4.20/drivers/scsi/ide-scsi.c
--- linux-2.4.19/drivers/scsi/ide-scsi.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/ide-scsi.c	2002-10-29 11:18:32.000000000 +0000
@@ -739,7 +739,7 @@
 	int segments = pc->scsi_cmd->use_sg;
 	struct scatterlist *sg = pc->scsi_cmd->request_buffer;
 
-	if (!drive->using_dma || !pc->request_transfer || pc->request_transfer % 1024)
+	if (!drive->using_dma || !pc->request_transfer || pc->request_transfer & 1023)
 		return NULL;
 	if (idescsi_set_direction(pc))
 		return NULL;
@@ -750,12 +750,22 @@
 		printk ("ide-scsi: %s: building DMA table, %d segments, %dkB total\n", drive->name, segments, pc->request_transfer >> 10);
 #endif /* IDESCSI_DEBUG_LOG */
 		while (segments--) {
-			bh->b_data = sg->address;
+			if (sg->address) {
+				bh->b_page = virt_to_page(sg->address);
+				bh->b_data = (char *) ((unsigned long) sg->address & ~PAGE_MASK);
+			} else if (sg->page) {
+				bh->b_page = sg->page;
+				bh->b_data = (char *) sg->offset;
+			}
+
 			bh->b_size = sg->length;
 			bh = bh->b_reqnext;
 			sg++;
 		}
 	} else {
+		/*
+		 * non-sg requests are guarenteed not to reside in highmem /jens
+		 */
 		if ((first_bh = bh = idescsi_kmalloc_bh (1)) == NULL)
 			return NULL;
 #if IDESCSI_DEBUG_LOG
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/imm.c linux-2.4.20/drivers/scsi/imm.c
--- linux-2.4.19/drivers/scsi/imm.c	2001-09-30 19:26:07.000000000 +0000
+++ linux-2.4.20/drivers/scsi/imm.c	2002-10-29 11:18:51.000000000 +0000
@@ -1120,7 +1120,7 @@
 }
 
 /*
- * Apparently the the disk->capacity attribute is off by 1 sector 
+ * Apparently the disk->capacity attribute is off by 1 sector 
  * for all disk drives.  We add the one here, but it should really
  * be done in sd.c.  Even if it gets fixed there, this will still
  * work.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/ips.c linux-2.4.20/drivers/scsi/ips.c
--- linux-2.4.19/drivers/scsi/ips.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/ips.c	2002-10-29 11:18:31.000000000 +0000
@@ -2,6 +2,8 @@
 /* ips.c -- driver for the IBM ServeRAID controller                          */
 /*                                                                           */
 /* Written By: Keith Mitchell, IBM Corporation                               */
+/*             Jack Hammer, Adaptec, Inc.                                    */
+/*             David Jeffery, Adaptec, Inc.                                  */
 /*                                                                           */
 /* Copyright (C) 2000 IBM Corporation                                        */
 /*                                                                           */
@@ -40,7 +42,7 @@
 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 /*                                                                           */
 /* Bugs/Comments/Suggestions about this driver should be mailed to:          */
-/*      ipslinux@us.ibm.com          	                                      */
+/*      ipslinux@adaptec.com     	                                         */
 /*                                                                           */
 /* For system support issues, contact your local IBM Customer support.       */
 /* Directions to find IBM Customer Support for each country can be found at: */
@@ -121,6 +123,9 @@
 /* 4.90.08  - Data Corruption if First Scatter Gather Element is > 64K       */
 /* 4.90.11  - Don't actually RESET unless it's physically required           */
 /*          - Remove unused compile options                                  */
+/* 5.00.01  - Sarasota ( 5i ) adapters must always be scanned first          */
+/*          - Get rid on IOCTL_NEW_COMMAND code                              */
+/*          - Add Extended DCDB Commands for Tape Support in 5I              */
 /*****************************************************************************/
 
 /*
@@ -193,8 +198,9 @@
 /*
  * DRIVER_VER
  */
-#define IPS_VERSION_HIGH        "4.90"
-#define IPS_VERSION_LOW         ".18 "
+#define IPS_VERSION_HIGH        "5.10"
+#define IPS_VERSION_LOW         ".21 "
+
 
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
 struct proc_dir_entry proc_scsi_ips = {
@@ -262,17 +268,32 @@
 static int          ips_cd_boot = 0;                 /* Booting from ServeRAID Manager CD */
 static char        *ips_FlashData = NULL;            /* CD Boot - Flash Data Buffer      */
 static int          ips_FlashDataInUse = 0;          /* CD Boot - Flash Data In Use Flag */
+static uint32_t     MaxLiteCmds = 32;                /* Max Active Cmds for a Lite Adapter */  
 
 IPS_DEFINE_COMPAT_TABLE( Compatable );               /* Version Compatability Table      */
 
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
+   /* This table describes any / all ServeRAID Adapters */
    static struct  pci_device_id  ips_pci_table[]  __devinitdata = {
-           { 0x1014, 0x002E, PCI_ANY_ID,PCI_ANY_ID, 0, 0, 0 },
-           { 0x1014, 0x01BD, PCI_ANY_ID,PCI_ANY_ID, 0, 0, 0 },
+           { 0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+           { 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
            { 0, }
    };
 
+   /* This table describes only Sarasota ( ServeRAID 5i ) Adapters */
+   static struct  pci_device_id  ips_pci_table_5i[]  __devinitdata = {
+                   { 0x1014, 0x01BD, PCI_ANY_ID, 0x259, 0, 0 },
+                   { 0x1014, 0x01BD, PCI_ANY_ID, 0x258, 0, 0 },
+                   { 0, }
+                   };   
+    
+   /* This table describes all i960 Adapters */
+   static struct  pci_device_id  ips_pci_table_i960[]  __devinitdata = {
+                   { 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+                   { 0, }
+                   };   
+
    MODULE_DEVICE_TABLE( pci, ips_pci_table );
 
    static char ips_hot_plug_name[] = "ips";
@@ -284,8 +305,23 @@
        name:		ips_hot_plug_name,
        id_table:	ips_pci_table,
        probe:		ips_insert_device,
-       remove:		__devexit_p(ips_remove_device),
+       remove:		ips_remove_device,
+   }; 
+           
+   struct pci_driver ips_pci_driver_5i = {
+       name:		ips_hot_plug_name,
+       id_table:	ips_pci_table_5i,
+       probe:		ips_insert_device,
+       remove:		ips_remove_device,
+   };
+
+   struct pci_driver ips_pci_driver_i960 = {
+       name:		ips_hot_plug_name,
+       id_table:	ips_pci_table_i960,
+       probe:		ips_insert_device,
+       remove:		ips_remove_device,
    };
+
 #endif
 
 /*
@@ -307,8 +343,8 @@
    "ServeRAID 4L",
    "ServeRAID 4Mx",
    "ServeRAID 4Lx",
-   "ServeRAID 5I",
-   "ServeRAID 5I"
+   "ServeRAID 5i",
+   "ServeRAID 5i"
 };
 
 static struct notifier_block ips_notifier = {
@@ -322,7 +358,7 @@
 IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN,   IPS_DATA_IN,   IPS_DATA_OUT,
 IPS_DATA_IN,   IPS_DATA_IN,   IPS_DATA_OUT,  IPS_DATA_IN,   IPS_DATA_UNK,
 IPS_DATA_OUT,  IPS_DATA_OUT,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_IN,   IPS_DATA_NONE, IPS_DATA_IN,   IPS_DATA_IN,   IPS_DATA_OUT,
+IPS_DATA_IN,   IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN,   IPS_DATA_OUT,
 IPS_DATA_IN,   IPS_DATA_OUT,  IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_OUT,
 IPS_DATA_NONE, IPS_DATA_IN,   IPS_DATA_NONE, IPS_DATA_IN,   IPS_DATA_OUT,
 IPS_DATA_NONE, IPS_DATA_UNK,  IPS_DATA_IN,   IPS_DATA_UNK,  IPS_DATA_IN,
@@ -385,7 +421,6 @@
 void do_ipsintr(int, void *, struct pt_regs *);
 static int ips_hainit(ips_ha_t *);
 static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *);
-static int ips_send(ips_ha_t *, ips_scb_t *, ips_scb_callback);
 static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int);
 static int ips_send_cmd(ips_ha_t *, ips_scb_t *);
 static int ips_online(ips_ha_t *, ips_scb_t *);
@@ -424,13 +459,10 @@
 static int ips_erase_bios_memio(ips_ha_t *);
 static int ips_program_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t);
 static int ips_verify_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t);
-static void ips_flash_bios_section(void *);
-static void ips_flash_bios_segment(void *);
 static int ips_flash_copperhead(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
 static int ips_flash_bios(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
 static int ips_flash_firmware(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
 static void ips_free_flash_copperhead(ips_ha_t *ha);
-static void ips_scheduled_flash_bios(void *);
 static void ips_get_bios_version(ips_ha_t *, int);
 static void ips_identify_controller(ips_ha_t *);
 static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
@@ -472,7 +504,6 @@
 static int ips_is_passthru(Scsi_Cmnd *);
 static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int);
 static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
-static int ips_newusrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
 static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *);
 
 int  ips_proc_info(char *, char **, off_t, int, int, int);
@@ -516,6 +547,7 @@
       {"nommap", &ips_force_memio, 0},
       {"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE},
       {"cdboot", &ips_cd_boot, 0},
+      {"maxcmds", &MaxLiteCmds, 32},
    };
     
    /* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */
@@ -543,7 +575,6 @@
    }
 
    return (1);
-}
 
 #else
 
@@ -578,10 +609,14 @@
          }
       }
    }
-}
 
 #endif
 
+}
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
+__setup("ips=", ips_setup);
+#endif
 
 /****************************************************************************/
 /*                                                                          */
@@ -622,6 +657,7 @@
    uint32_t          maskbar;
    uint8_t           barnum;
 #endif
+   uint32_t          IsDead;
 
    METHOD_TRACE("ips_detect", 1);
 
@@ -706,12 +742,23 @@
 /**********************************************************************************/
 /* For Kernel Versions 2.4 or greater, use new PCI ( Hot Pluggable ) architecture */
 /**********************************************************************************/
+
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
    spin_unlock_irq(&io_request_lock);
-   pci_module_init(&ips_pci_driver);
+
+   /* By definition, a Sarasota ( 5i ) Adapter MUST be enumerated first or the */
+   /* server may not boot properly. The adapters must be enumerated in exactly */
+   /* the same order as ServeRAID BIOS for the machine to come up properly.    */
+
+   pci_module_init(&ips_pci_driver_5i);          /* Ask for 5i Adapters First  */
+   if (ips_num_controllers)                      /* If there is a 5i Adapter   */
+      pci_module_init(&ips_pci_driver_i960);     /*    Get all i960's next     */
+   pci_module_init(&ips_pci_driver);             /* Get all remaining Adapters */
+                                                 /*  ( in normal BUS order )   */
    spin_lock_irq(&io_request_lock);
    if (ips_num_controllers > 0) 
       register_reboot_notifier(&ips_notifier);
+
    return (ips_num_controllers);
 #endif
 
@@ -1111,6 +1158,14 @@
             else
                ha->func.issue = ips_issue_copperhead;
          }
+            
+         /* If Morpheus appears dead, reset it */
+         if ( IPS_IS_MORPHEUS( ha ) ) {
+             IsDead = readl( ha->mem_ptr + IPS_REG_I960_MSG1 );
+             if ( IsDead == 0xDEADBEEF ) {
+                 ips_reset_morpheus( ha );
+             }
+         }
 
          /*
           * Initialize the card if it isn't already
@@ -1639,10 +1694,6 @@
 
 }
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
-__setup("ips=", ips_setup);
-#endif
-
 /****************************************************************************/
 /*                                                                          */
 /* Routine Name: ips_queue                                                  */
@@ -1717,21 +1768,7 @@
    if (ips_is_passthru(SC)) {
 
       ips_copp_wait_item_t *scratch;
-
-      /* The IPS_IOCTL_NEW_COMMAND is only used to flash an adapter.  This should */
-      /* never happen when the adapter is active.  Just in case, check here, and  */
-      /* reject the command if anything else is going on.                         */
-      if (SC->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
-         if (ha->scb_activelist.count != 0) {
-            /* printk( KERN_WARNING "New IOCTL Cmd Return BUSY: %d Cmds Active\n", */
-            /*                       ha->scb_activelist.count );                   */
-            SC->result = DID_BUS_BUSY << 16;
-            done(SC);
-
-            return (0);
-         }
-      }
-
+      
       /* A Reset IOCTL is only sent by the ServeRAID boot CD in extreme cases. */
       /* There can never be any system activity ( network or disk ), but check */
       /* anyway just as a good practice.                                       */
@@ -1770,6 +1807,9 @@
    else
       ips_putq_wait_tail(&ha->scb_waitlist, SC);
 
+   if(ha->scb_waitlist.count + ha->scb_activelist.count > 32)
+         mod_timer(&SC->eh_timeout, jiffies + 120 * HZ);
+
    IPS_HA_LOCK(cpu_flags);
    if ((!test_bit(IPS_IN_INTR, &ha->flags)) &&
        (!test_bit(IPS_IN_ABORT, &ha->flags)) &&
@@ -1779,43 +1819,7 @@
    } else {
       IPS_HA_UNLOCK(cpu_flags);
    }
-
-   /*
-    * If this request was a new style IOCTL wait
-    * for it to finish.
-    *
-    * NOTE: we relinquished the lock above so this should
-    * not cause contention problems
-    */
-   if (ips_is_passthru(SC) && SC->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
-      char      *user_area;
-      char      *kern_area;
-      uint32_t  datasize;
-
-      /* free io_request_lock */
-      spin_unlock_irq(&io_request_lock);
-
-      /* wait for the command to finish */
-      down(&ha->ioctl_sem);
-
-      /* command finished -- copy back */
-      user_area = *((char **) &SC->cmnd[4]);
-      kern_area = ha->ioctl_data;
-      datasize = *((uint32_t *) &SC->cmnd[8]);
-
-      if (datasize) {
-         if (copy_to_user(user_area, kern_area, datasize) > 0) {
-            DEBUG_VAR(1, "(%s%d) passthru failed - unable to copy out user data",
-                      ips_name, ha->host_num);
-            SC->result = DID_ERROR << 16;
-         }
-      }
-
-      /* reobtain the lock */
-      spin_lock_irq(&io_request_lock);
-      SC->scsi_done(SC);
-   }
-
+   
    /* If We were using the CD Boot Flash Buffer, Restore the Old Values */
    if ( ips_FlashData == ha->ioctl_data ) {                               
       ha->ioctl_data = ha->flash_data;                           
@@ -2214,7 +2218,7 @@
    if (!SC)
       return (0);
 
-   if (((SC->cmnd[0] == IPS_IOCTL_COMMAND) || (SC->cmnd[0] == IPS_IOCTL_NEW_COMMAND)) &&
+   if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) &&
        (SC->channel == 0) &&
        (SC->target == IPS_ADAPTER_ID) &&
        (SC->lun == 0) &&
@@ -2361,314 +2365,13 @@
          if(ha->device_id == IPS_DEVICEID_COPPERHEAD &&
             pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW)
             return ips_flash_copperhead(ha, pt, scb);
-         if (ips_usrcmd(ha, pt, scb))
-            return (IPS_SUCCESS);
-         else
-            return (IPS_FAILURE);
-      } else if (SC->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
-
-         if (SC->request_bufflen < (sizeof(ips_passthru_t))) {
-            /* wrong size */
-            DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
-                      ips_name, ha->host_num);
-
-            SC->result = DID_ERROR << 16;
-
-            return (IPS_FAILURE);
-         }
-
-         /* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can     */
-         /* avoid allocating a huge buffer per adapter ( which can fail ). */
-         if ( (ips_FlashData) &&                                            
-              (pt->CmdBSize == IPS_IMAGE_SIZE) &&                                   
-              (ips_FlashDataInUse == 0) ) {                                 
-            ips_FlashDataInUse = 1;                                         
-            ha->flash_data  = ha->ioctl_data;
-            ha->flash_order = ha->ioctl_order;
-            ha->flash_datasize = ha->ioctl_datasize;
-            ha->ioctl_data  = ips_FlashData;                                
-            ha->ioctl_order = 7;                                            
-            ha->ioctl_datasize = IPS_IMAGE_SIZE;                                    
-         }  
-
-         /*
-          * IPSSEND flashing BIOS
-          */
-         if ((pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW) &&
-             (pt->CoppCP.cmd.flashfw.type == 1) &&
-             (pt->CoppCP.cmd.flashfw.direction == 2) &&
-             (ha->device_id == IPS_DEVICEID_COPPERHEAD)) {
-            struct tq_struct  task;
-            IPS_FLASH_DATA    flash_data;
-
-            /* We only support one packet */
-            if (pt->CoppCP.cmd.flashfw.total_packets != 1) {
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-            /* copy in the size/buffer ptr from the scsi command */
-            memcpy(&pt->CmdBuffer, &SC->cmnd[4], 4);
-            memcpy(&pt->CmdBSize, &SC->cmnd[8], 4);
-
-            if (pt->CmdBSize > le32_to_cpu(pt->CoppCP.cmd.flashfw.count)) {
-               pt->CmdBSize = le32_to_cpu(pt->CoppCP.cmd.flashfw.count);
-            } else {
-               /* ERROR: Command/Buffer mismatch */
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-      if ((!ha->func.programbios) ||
-          (!ha->func.erasebios) ||
-                (!ha->func.verifybios)) {
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
 
-            /* must have a buffer */
-            if ((!pt->CmdBSize) || (!pt->CmdBuffer)) {
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-            /* make sure buffer is big enough */
-            if (pt->CmdBSize > ha->ioctl_datasize) {
-               void *bigger_struct;
-               uint32_t count;
-               uint32_t order;
-
-               /* try to allocate a bigger struct */
-               for (count = PAGE_SIZE, order = 0;
-                    count < pt->CmdBSize;
-                    order++, count <<= 1);
-
-               bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order);
-               if (bigger_struct) {
-                  /* free the old memory */
-                  free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
-
-                  /* use the new memory */
-                  ha->ioctl_data = (char *) bigger_struct;
-                  ha->ioctl_order = order;
-                  ha->ioctl_datasize = count;
-               } else {
-                  pt->BasicStatus = 0x0B;
-                  pt->ExtendedStatus = 0x00;
-                  SC->result = DID_ERROR << 16;
-
-                  spin_unlock(&ha->ips_lock);
-
-                  return (IPS_FAILURE);
-               }
-            }
-
-            /* copy in the buffer */
-            if (copy_from_user(ha->ioctl_data, pt->CmdBuffer, pt->CmdBSize) > 0) {
-               DEBUG_VAR(1, "(%s%d) flash bios failed - unable to copy user buffer",
-                         ips_name, ha->host_num);
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-            flash_data.userbuffer = pt->CmdBuffer;
-            flash_data.usersize = pt->CmdBSize;
-            flash_data.kernbuffer = ha->ioctl_data;
-            flash_data.kernsize = ha->ioctl_datasize;
-            flash_data.offset = 0;
-            flash_data.SC = (void *) SC;
-            flash_data.pt = (void *) pt;
-            flash_data.ha = (void *) ha;
-            sema_init( &ha->flash_ioctl_sem, 0 );
-            flash_data.sem = &ha->flash_ioctl_sem;
-
-            task.sync = 0;
-            task.routine = ips_scheduled_flash_bios;
-            task.data = (void *) &flash_data;
-
-            /* Unlock the master lock */
-            spin_unlock_irq(&io_request_lock);
-
-            queue_task(&task, &tq_immediate);
-            mark_bh(IMMEDIATE_BH);
-            
-            /* Wait for the flash to complete */
-            down(&ha->flash_ioctl_sem);
-
-            /* Obtain the master lock */
-            spin_lock_irq(&io_request_lock);
-
-            return (flash_data.retcode);
-         }
-
-         /*
-          * IPSSEND flashing BIOS in sectioned mode
-          */
-         if ((pt->CoppCP.cmd.flashbios.op_code == IPS_CMD_RW_BIOSFW) &&
-             (pt->CoppCP.cmd.flashbios.type == 1) &&
-             (pt->CoppCP.cmd.flashbios.direction == 4) &&
-             (ha->device_id == IPS_DEVICEID_COPPERHEAD)) {
-            struct tq_struct  task;
-            IPS_FLASH_DATA    flash_data;
-
-            /* copy in the size/buffer ptr from the scsi command */
-            memcpy(&pt->CmdBuffer, &SC->cmnd[4], 4);
-            memcpy(&pt->CmdBSize, &SC->cmnd[8], 4);
-
-            if (pt->CmdBSize > le32_to_cpu(pt->CoppCP.cmd.flashbios.count)) {
-               pt->CmdBSize = le32_to_cpu(pt->CoppCP.cmd.flashbios.count);
-            } else {
-               /* ERROR: Command/Buffer mismatch */
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-            /* Update the Card BIOS */
-            if ((!ha->func.programbios) ||
-                (!ha->func.erasebios) ||
-                (!ha->func.verifybios)) {
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-      /* must have a buffer */
-            if ((!pt->CmdBSize) || (!pt->CmdBuffer)) {
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-      /* make sure buffer is big enough */
-      if (pt->CmdBSize > ha->ioctl_datasize) {
-         void *bigger_struct;
-               uint32_t count;
-               uint32_t order;
-
-         /* try to allocate a bigger struct */
-               for (count = PAGE_SIZE, order = 0;
-                    count < pt->CmdBSize;
-                    order++, count <<= 1);
-
-               bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order);
-         if (bigger_struct) {
-            /* free the old memory */
-                  free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
-
-            /* use the new memory */
-                  ha->ioctl_data = (char *) bigger_struct;
-                  ha->ioctl_order = order;
-                  ha->ioctl_datasize = count;
-               } else {
-                  pt->BasicStatus = 0x0B;
-                  pt->ExtendedStatus = 0x00;
-                  SC->result = DID_ERROR << 16;
-
-                  spin_unlock(&ha->ips_lock);
-
-                  return (IPS_FAILURE);
-               }
-            }
-
-      /* copy in the buffer */
-      if (copy_from_user(ha->ioctl_data, pt->CmdBuffer, pt->CmdBSize) > 0) {
-         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to copy user buffer",
-                   ips_name, ha->host_num);
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (EFAULT);
-            }
-
-            flash_data.userbuffer = pt->CmdBuffer;
-            flash_data.usersize = pt->CmdBSize;
-            flash_data.kernbuffer = ha->ioctl_data;
-            flash_data.kernsize = ha->ioctl_datasize;
-            flash_data.offset = le32_to_cpu(pt->CoppCP.cmd.flashbios.offset);
-            flash_data.SC = (void *) SC;
-            flash_data.pt = (void *) pt;
-            flash_data.ha = (void *) ha;
-            sema_init( &ha->flash_ioctl_sem, 0 );
-            flash_data.sem = &ha->flash_ioctl_sem;
-
-            task.sync = 0;
-            task.routine = ips_flash_bios_section;
-            task.data = (void *) &flash_data;
-
-            /* Unlock the master lock */
-            spin_unlock_irq(&io_request_lock);
-
-            queue_task(&task, &tq_immediate);
-            mark_bh(IMMEDIATE_BH);
-            
-            /* Wait for the flash to complete */
-            down(&ha->flash_ioctl_sem);
-
-            /* Obtain the master lock */
-            spin_lock_irq(&io_request_lock);
-
-            return (flash_data.retcode);
-         }
-
-         if ((pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW) &&
-             (pt->CoppCP.cmd.flashfw.type == 1) &&
-             (pt->CoppCP.cmd.flashfw.direction == 3) &&
-             (ha->device_id == IPS_DEVICEID_COPPERHEAD)) {
-            /* Erase the Card BIOS */
-            if (!ha->func.erasebios) {
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-      if ((*ha->func.erasebios)(ha)) {
-         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
-                   ips_name, ha->host_num);
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-            SC->result = DID_OK << 16;
-            pt->BasicStatus = 0x00;
-            pt->ExtendedStatus = 0x00;
-
-            return (IPS_SUCCESS_IMM);
-         }
-
-         if (ips_newusrcmd(ha, pt, scb))
+         if (ips_usrcmd(ha, pt, scb))
             return (IPS_SUCCESS);
          else
             return (IPS_FAILURE);
-      }
-
+      } 
+     
       break;
 
    } /* end switch */
@@ -2848,149 +2551,6 @@
 
 /****************************************************************************/
 /*                                                                          */
-/* Routine Name: ips_scheduled_flash_bios                                   */
-/*                                                                          */
-/* Routine Description:                                                     */
-/*                                                                          */
-/*   Flash the BIOS on a Copperhead style controller                        */
-/*   To be called from a task queue                                         */
-/*                                                                          */
-/****************************************************************************/
-static void
-ips_scheduled_flash_bios(void *data) {
-   ips_ha_t       *ha;
-   Scsi_Cmnd      *SC;
-   ips_passthru_t *pt;
-   IPS_FLASH_DATA *fd;
-
-   fd = (IPS_FLASH_DATA *) data;
-   ha = (ips_ha_t *) fd->ha;
-   pt = (ips_passthru_t *) fd->pt;
-   SC = (Scsi_Cmnd *) fd->SC;
-
-   /*
-    * Set initial return codes
-    */
-   SC->result = DID_OK << 16;
-   pt->BasicStatus = 0x00;
-   pt->ExtendedStatus = 0x00;
-   fd->retcode = IPS_SUCCESS_IMM;
-
-   /*
-    * Fix the size/ptr to account for the
-    * flash header
-    */
-   fd->kernbuffer += 0xC0;
-   fd->kernsize -= 0xC0;
-   fd->userbuffer += 0xC0;
-   fd->usersize -= 0xC0;
-
-   if ((*ha->func.erasebios)(ha)) {
-      DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
-                   ips_name, ha->host_num);
-      pt->BasicStatus = 0x0B;
-      pt->ExtendedStatus = 0x00;
-      SC->result = DID_ERROR << 16;
-      fd->retcode = IPS_FAILURE;
-      up(fd->sem);
-
-      return ;
-   }
-
-   ips_flash_bios_segment(data);
-
-   if (fd->retcode == IPS_FAILURE)
-      return ;
-
-   if ((*ha->func.verifybios)(ha, fd->kernbuffer, fd->usersize, fd->offset)) {
-         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to verify flash",
-                   ips_name, ha->host_num);
-      pt->BasicStatus = 0x0B;
-      pt->ExtendedStatus = 0x00;
-      SC->result = DID_ERROR << 16;
-      fd->retcode = IPS_FAILURE;
-      up(fd->sem);
-
-      return ;
-   }
-
-   /* Tell them we are done */
-   if (fd->retcode != IPS_FAILURE)
-      up(fd->sem);
-}
-
-/****************************************************************************/
-/*                                                                          */
-/* Routine Name: ips_flash_bios_section                                     */
-/*                                                                          */
-/* Routine Description:                                                     */
-/*                                                                          */
-/*   wrapper for ips_flash_bios_segment that raises the semaphore           */
-/*                                                                          */
-/****************************************************************************/
-static void
-ips_flash_bios_section(void *data) {
-   ips_ha_t       *ha;
-   Scsi_Cmnd      *SC;
-   ips_passthru_t *pt;
-   IPS_FLASH_DATA *fd;
-
-   fd = (IPS_FLASH_DATA *) data;
-   ha = (ips_ha_t *) fd->ha;
-   pt = (ips_passthru_t *) fd->pt;
-   SC = (Scsi_Cmnd *) fd->SC;
-
-   /*
-    * Set initial return codes
-    */
-   SC->result = DID_OK << 16;
-   pt->BasicStatus = 0x00;
-   pt->ExtendedStatus = 0x00;
-   fd->retcode = IPS_SUCCESS_IMM;
-
-   ips_flash_bios_segment(data);
-
-   if (fd->retcode != IPS_FAILURE)
-      up(fd->sem);
-}
-
-/****************************************************************************/
-/*                                                                          */
-/* Routine Name: ips_flash_bios_segment                                     */
-/*                                                                          */
-/* Routine Description:                                                     */
-/*                                                                          */
-/*   Flash a portion of the BIOS on a Copperhead style controller           */
-/*   To be called from a task queue                                         */
-/*                                                                          */
-/****************************************************************************/
-static void
-ips_flash_bios_segment(void *data) {
-   ips_ha_t       *ha;
-   Scsi_Cmnd      *SC;
-   ips_passthru_t *pt;
-   IPS_FLASH_DATA *fd;
-
-   fd = (IPS_FLASH_DATA *) data;
-   ha = (ips_ha_t *) fd->ha;
-   pt = (ips_passthru_t *) fd->pt;
-   SC = (Scsi_Cmnd *) fd->SC;
-
-   if ((*ha->func.programbios)(ha, fd->kernbuffer, fd->usersize, fd->offset)) {
-      DEBUG_VAR(1, "(%s%d) flash bios failed - unable to program flash",
-                ips_name, ha->host_num);
-      pt->BasicStatus = 0x0B;
-      pt->ExtendedStatus = 0x00;
-      SC->result = DID_ERROR << 16;
-      fd->retcode = IPS_FAILURE;
-      up(fd->sem);
-
-      return ;
-   }
-}
-
-/****************************************************************************/
-/*                                                                          */
 /* Routine Name: ips_usrcmd                                                 */
 /*                                                                          */
 /* Routine Description:                                                     */
@@ -3074,126 +2634,6 @@
 
 /****************************************************************************/
 /*                                                                          */
-/* Routine Name: ips_newusrcmd                                              */
-/*                                                                          */
-/* Routine Description:                                                     */
-/*                                                                          */
-/*   Process a user command and make it ready to send                       */
-/*                                                                          */
-/****************************************************************************/
-static int
-ips_newusrcmd(ips_ha_t *ha, ips_passthru_t *pt, ips_scb_t *scb) {
-   IPS_SG_LIST    *sg_list;
-   char           *user_area;
-   char           *kern_area;
-   uint32_t        datasize;
-
-   METHOD_TRACE("ips_newusrcmd", 1);
-
-   if ((!scb) || (!pt) || (!ha))
-      return (0);
-
-   /* Save the S/G list pointer so it doesn't get clobbered */
-   sg_list = scb->sg_list;
-
-   /* copy in the CP */
-   memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof(IPS_IOCTL_CMD));
-   memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof(IPS_DCDB_TABLE));
-
-   /* FIX stuff that might be wrong */
-   scb->sg_list = sg_list;
-   scb->scb_busaddr = VIRT_TO_BUS(scb);
-   scb->bus = scb->scsi_cmd->channel;
-   scb->target_id = scb->scsi_cmd->target;
-   scb->lun = scb->scsi_cmd->lun;
-   scb->sg_len = 0;
-   scb->data_len = 0;
-   scb->flags = 0;
-   scb->op_code = 0;
-   scb->callback = ipsintr_done;
-   scb->timeout = ips_cmd_timeout;
-   scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
-
-   /* we don't support DCDB/READ/WRITE Scatter Gather */
-   if ((scb->cmd.basic_io.op_code == IPS_CMD_READ_SG) ||
-       (scb->cmd.basic_io.op_code == IPS_CMD_WRITE_SG) ||
-       (scb->cmd.basic_io.op_code == IPS_CMD_DCDB_SG))
-      return (0);
-
-   if (pt->CmdBSize) {
-      if (pt->CmdBSize > ha->ioctl_datasize) {
-         void *bigger_struct;
-         uint32_t count;
-         uint32_t order;
-
-         /* try to allocate a bigger struct */
-         for (count = PAGE_SIZE, order = 0;
-              count < pt->CmdBSize;
-              order++, count <<= 1);
-
-         bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order);
-         if (bigger_struct) {
-            /* free the old memory */
-            free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
-
-            /* use the new memory */
-            ha->ioctl_data = (char *) bigger_struct;
-            ha->ioctl_order = order;
-            ha->ioctl_datasize = count;
-         } else
-            return (0);
-
-      }
-
-      scb->data_busaddr = VIRT_TO_BUS(ha->ioctl_data);
-
-      /* Attempt to copy in the data */
-      user_area = *((char **) &scb->scsi_cmd->cmnd[4]);
-      kern_area = ha->ioctl_data;
-      datasize = *((uint32_t *) &scb->scsi_cmd->cmnd[8]);
-
-      if (copy_from_user(kern_area, user_area, datasize) > 0) {
-         DEBUG_VAR(1, "(%s%d) passthru failed - unable to copy in user data",
-                   ips_name, ha->host_num);
-
-         return (0);
-      }
-
-   } else {
-      scb->data_busaddr = 0L;
-   }
-
-   if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
-      scb->cmd.dcdb.dcdb_address = cpu_to_le32(VIRT_TO_BUS(&scb->dcdb));
-
-   if (pt->CmdBSize) {
-      if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
-         scb->dcdb.buffer_pointer = cpu_to_le32(scb->data_busaddr);
-      else
-         scb->cmd.basic_io.sg_addr = cpu_to_le32(scb->data_busaddr);
-   }
-
-   /* set timeouts */
-   if (pt->TimeOut) {
-      scb->timeout = pt->TimeOut;
-
-      if (pt->TimeOut <= 10)
-         scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
-      else if (pt->TimeOut <= 60)
-         scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
-      else
-         scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
-   }
-
-   /* assume success */
-   scb->scsi_cmd->result = DID_OK << 16;
-
-   /* success */
-   return (1);
-}
-
-/****************************************************************************/
-/*                                                                          */
 /* Routine Name: ips_cleanup_passthru                                       */
 /*                                                                          */
 /* Routine Description:                                                     */
@@ -3225,8 +2665,6 @@
    pt->BasicStatus = scb->basic_status;
    pt->ExtendedStatus = scb->extended_status;
    pt->AdapterType = ha->ad_type;
-   if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) 
-      up(&ha->ioctl_sem);
 
    if(ha->device_id == IPS_DEVICEID_COPPERHEAD && 
      (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD || 
@@ -3725,6 +3163,14 @@
       }
    }
 
+   /* Limit the Active Commands on a Lite Adapter */
+   if ((ha->ad_type == IPS_ADTYPE_SERVERAID3L) ||
+       (ha->ad_type == IPS_ADTYPE_SERVERAID4L) ||
+       (ha->ad_type == IPS_ADTYPE_SERVERAID4LX)) {
+      if ((ha->max_cmds > MaxLiteCmds) && (MaxLiteCmds)) 
+         ha->max_cmds = MaxLiteCmds;
+   }
+
    /* set controller IDs */
    ha->ha_id[0] = IPS_ADAPTER_ID;
    for (i = 1; i < ha->nbus; i++) {
@@ -3812,17 +3258,7 @@
       case IPS_FAILURE:
          if (scb->scsi_cmd) {
             scb->scsi_cmd->result = DID_ERROR << 16;
-
-            /* raise the semaphore */
-            if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
-               uint32_t datasize;
-
-               datasize = 0;
-               memcpy(&scb->scsi_cmd->cmnd[8], &datasize, 4);
-               up(&ha->ioctl_sem);
-            } else {
-               scb->scsi_cmd->scsi_done(scb->scsi_cmd);
-         }
+            scb->scsi_cmd->scsi_done(scb->scsi_cmd);
          }
 
          ips_freescb(ha, scb);
@@ -3830,17 +3266,7 @@
       case IPS_SUCCESS_IMM:
          if (scb->scsi_cmd) {
             scb->scsi_cmd->result = DID_OK << 16;
-
-            /* raise the semaphore */
-            if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
-               uint32_t datasize;
-
-               datasize = 0;
-               memcpy(&scb->scsi_cmd->cmnd[8], &datasize, 4);
-               up(&ha->ioctl_sem);
-            } else {
-               scb->scsi_cmd->scsi_done(scb->scsi_cmd);
-            }
+            scb->scsi_cmd->scsi_done(scb->scsi_cmd);
          }
 
          ips_freescb(ha, scb);
@@ -3866,22 +3292,12 @@
       switch(ret) {
       case IPS_FAILURE:
          if (scb->scsi_cmd) {
-            /* raise the semaphore */
-            if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND)
-               up(&ha->ioctl_sem);
-
             scb->scsi_cmd->result = DID_ERROR << 16;
          }
 
          ips_freescb(ha, scb);
          break;
       case IPS_SUCCESS_IMM:
-         if (scb->scsi_cmd) {
-            /* raise the semaphore */
-            if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND)
-               up(&ha->ioctl_sem);
-         }
-
          ips_freescb(ha, scb);
          break;
       default:
@@ -4012,8 +3428,7 @@
 
       }
 
-      scb->dcdb.cmd_attribute |=
-         ips_command_direction[scb->scsi_cmd->cmnd[0]];
+      scb->dcdb.cmd_attribute = ips_command_direction[scb->scsi_cmd->cmnd[0]];
 
       if (!scb->dcdb.cmd_attribute & 0x3)
          scb->dcdb.transfer_length = 0;
@@ -4626,6 +4041,7 @@
 
          bk_save = scb->breakup;
          scb->breakup = 0;
+         mod_timer(&scb->scsi_cmd->eh_timeout, jiffies + 120 * HZ);
 
          if (scb->sg_count) {
             /* S/G request */
@@ -4727,8 +4143,7 @@
             scb->sg_len = 0;
          }
 
-         scb->dcdb.cmd_attribute |=
-            ips_command_direction[scb->scsi_cmd->cmnd[0]];
+         scb->dcdb.cmd_attribute |= ips_command_direction[scb->scsi_cmd->cmnd[0]];
 
          if (!scb->dcdb.cmd_attribute & 0x3)
             scb->dcdb.transfer_length = 0;
@@ -4771,9 +4186,7 @@
       IPS_HA_UNLOCK(cpu_flags);
    }
 
-   /* call back to SCSI layer */
-   if (scb->scsi_cmd && scb->scsi_cmd->cmnd[0] != IPS_IOCTL_NEW_COMMAND)
-      scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+   scb->scsi_cmd->scsi_done(scb->scsi_cmd);
 
    ips_freescb(ha, scb);
 }
@@ -4791,6 +4204,8 @@
 ips_map_status(ips_ha_t *ha, ips_scb_t *scb, ips_stat_t *sp) {
    int       errcode;
    int       device_error;
+   uint32_t  transfer_len;
+   IPS_DCDB_TABLE_TAPE *tapeDCDB;
 
    METHOD_TRACE("ips_map_status", 1);
 
@@ -4832,8 +4247,16 @@
 
          break;
 
-      case IPS_ERR_OU_RUN:
-         if ((scb->bus) && (scb->dcdb.transfer_length < scb->data_len)) {
+      case IPS_ERR_OU_RUN:   
+         if ( ( scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB ) ||
+              ( scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG ) ) {
+             tapeDCDB = ( IPS_DCDB_TABLE_TAPE * ) &scb->dcdb;
+             transfer_len = tapeDCDB->transfer_length;
+         } else {
+             transfer_len = ( uint32_t ) scb->dcdb.transfer_length;
+         }
+
+        if ((scb->bus) && (transfer_len < scb->data_len)) {
             /* Underrun - set default to no error */
             errcode = DID_OK;
 
@@ -4864,9 +4287,15 @@
 
       case IPS_ERR_CKCOND:
          if (scb->bus) {
-            memcpy(scb->scsi_cmd->sense_buffer, scb->dcdb.sense_info,
-                   sizeof(scb->scsi_cmd->sense_buffer));
-
+            if ((scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB) ||
+                (scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG)) {
+               tapeDCDB = (IPS_DCDB_TABLE_TAPE *) &scb->dcdb;
+               memcpy(scb->scsi_cmd->sense_buffer, tapeDCDB->sense_info,
+                      sizeof(scb->scsi_cmd->sense_buffer));
+            } else {
+               memcpy(scb->scsi_cmd->sense_buffer, scb->dcdb.sense_info,
+                      sizeof(scb->scsi_cmd->sense_buffer));
+            }
             device_error = 2; /* check condition */
          }
 
@@ -4888,28 +4317,6 @@
 
 /****************************************************************************/
 /*                                                                          */
-/* Routine Name: ips_send                                                   */
-/*                                                                          */
-/* Routine Description:                                                     */
-/*                                                                          */
-/*   Wrapper for ips_send_cmd                                               */
-/*                                                                          */
-/****************************************************************************/
-static int
-ips_send(ips_ha_t *ha, ips_scb_t *scb, ips_scb_callback callback) {
-   int ret;
-
-   METHOD_TRACE("ips_send", 1);
-
-   scb->callback = callback;
-
-   ret = ips_send_cmd(ha, scb);
-
-   return (ret);
-}
-
-/****************************************************************************/
-/*                                                                          */
 /* Routine Name: ips_send_wait                                              */
 /*                                                                          */
 /* Routine Description:                                                     */
@@ -4928,9 +4335,9 @@
    if (intr != IPS_FFDC) {      /* Won't be Waiting if this is a Time Stamp */
       ha->waitflag = TRUE;
       ha->cmd_in_progress = scb->cdb[0];
-    }
-
-   ret = ips_send(ha, scb, ipsintr_blocking);
+   }
+   scb->callback = ipsintr_blocking;
+   ret = ips_send_cmd(ha, scb);
 
    if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM))
       return (ret);
@@ -4955,6 +4362,7 @@
    int       ret;
    char     *sp;
    int       device_error;
+   IPS_DCDB_TABLE_TAPE *tapeDCDB;
 
    METHOD_TRACE("ips_send_cmd", 1);
 
@@ -5183,26 +4591,63 @@
       scb->cmd.dcdb.reserved2 = 0;
       scb->cmd.dcdb.reserved3 = 0;
 
-      scb->dcdb.device_address = ((scb->bus - 1) << 4) | scb->target_id;
-      scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED;
-
-      if (scb->timeout) {
-         if (scb->timeout <= 10)
-            scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
-         else if (scb->timeout <= 60)
-            scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
+      if (ha->subsys->param[4] & 0x00100000) {          /* If NEW Tape DCDB is Supported */
+         if (!scb->sg_len)
+            scb->cmd.dcdb.op_code = IPS_CMD_EXTENDED_DCDB;
          else
-            scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
-      }
+            scb->cmd.dcdb.op_code = IPS_CMD_EXTENDED_DCDB_SG;
+ 
+         tapeDCDB = (IPS_DCDB_TABLE_TAPE *) &scb->dcdb; /* Use Same Data Area as Old DCDB Struct */
+         tapeDCDB->device_address = ((scb->bus - 1) << 4) | scb->target_id;
+         tapeDCDB->cmd_attribute |= IPS_DISCONNECT_ALLOWED;
+         tapeDCDB->cmd_attribute &= ~IPS_TRANSFER64K;   /* Always Turn OFF 64K Size Flag */
+
+         if (scb->timeout) {
+           if (scb->timeout <= 10)
+               tapeDCDB->cmd_attribute |= IPS_TIMEOUT10;
+            else if (scb->timeout <= 60)
+               tapeDCDB->cmd_attribute |= IPS_TIMEOUT60;
+            else
+               tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;
+         }
 
-      if (!(scb->dcdb.cmd_attribute & IPS_TIMEOUT20M))
-         scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
+         if (!(tapeDCDB->cmd_attribute & IPS_TIMEOUT20M))
+            tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;
 
-      scb->dcdb.sense_length = sizeof(scb->scsi_cmd->sense_buffer);
-      scb->dcdb.buffer_pointer = cpu_to_le32(scb->data_busaddr);
-      scb->dcdb.sg_count = scb->sg_len;
-      scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len;
-      memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd, scb->scsi_cmd->cmd_len);
+         tapeDCDB->sense_length = sizeof(tapeDCDB->sense_info);
+         tapeDCDB->transfer_length = scb->data_len;
+         tapeDCDB->buffer_pointer = cpu_to_le32(scb->data_busaddr);
+         tapeDCDB->sg_count = scb->sg_len;
+         tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len;
+         tapeDCDB->reserved_for_LUN = 0;
+         tapeDCDB->reserved = 0;
+         tapeDCDB->scsi_status = 0;
+         memcpy(tapeDCDB->scsi_cdb, scb->scsi_cmd->cmnd, scb->scsi_cmd->cmd_len);
+      } else {
+         scb->dcdb.device_address = ((scb->bus - 1) << 4) | scb->target_id;
+         scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED;
+
+         if (scb->timeout) {
+           if (scb->timeout <= 10)
+               scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
+            else if (scb->timeout <= 60)
+               scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
+            else
+               scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
+         }
+
+         if (!(scb->dcdb.cmd_attribute & IPS_TIMEOUT20M))
+            scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
+
+         scb->dcdb.sense_length = sizeof(scb->dcdb.sense_info);
+         scb->dcdb.transfer_length = scb->data_len;
+         if ( scb->dcdb.cmd_attribute & IPS_TRANSFER64K ) 
+             scb->dcdb.transfer_length = 0;
+         scb->dcdb.buffer_pointer = cpu_to_le32(scb->data_busaddr);
+         scb->dcdb.sg_count = scb->sg_len;
+         scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len;
+         memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd, scb->scsi_cmd->cmd_len);
+      }
    }
 
    return ((*ha->func.issue)(ha, scb));
@@ -7808,17 +7253,17 @@
 
  if  (strncmp(FirmwareVersion, Compatable[ ha->nvram->adapter_type ], IPS_COMPAT_ID_LENGTH) != 0)
  {
-     /* if (ips_cd_boot == 0)                                                                              */
-     /*   printk(KERN_WARNING "Warning: Adapter %d Firmware Compatible Version is %s, but should be %s\n", */
-     /*          ha->host_num, FirmwareVersion, Compatable[ ha->nvram->adapter_type ]);                    */
+     if (ips_cd_boot == 0)                                                                              
+       printk(KERN_WARNING "Warning: Adapter %d Firmware Compatible Version is %s, but should be %s\n", 
+              ha->host_num, FirmwareVersion, Compatable[ ha->nvram->adapter_type ]);                    
      MatchError = 1;
  }
 
  if  (strncmp(BiosVersion, IPS_COMPAT_BIOS, IPS_COMPAT_ID_LENGTH) != 0)
  {
-     /* if (ips_cd_boot == 0)                                                                          */
-     /*   printk(KERN_WARNING "Warning: Adapter %d BIOS Compatible Version is %s, but should be %s\n", */
-     /*          ha->host_num, BiosVersion, IPS_COMPAT_BIOS);                                          */
+     if (ips_cd_boot == 0)                                                                          
+       printk(KERN_WARNING "Warning: Adapter %d BIOS Compatible Version is %s, but should be %s\n", 
+              ha->host_num, BiosVersion, IPS_COMPAT_BIOS);                                          
      MatchError = 1;
  }
 
@@ -7827,8 +7272,8 @@
  if  (MatchError)
  {
      ha->nvram->version_mismatch = 1;
-     /* if (ips_cd_boot == 0)                                               */
-     /*  printk(KERN_WARNING "Warning ! ! ! ServeRAID Version Mismatch\n"); */
+     if (ips_cd_boot == 0)                                               
+       printk(KERN_WARNING "Warning ! ! ! ServeRAID Version Mismatch\n");
  }
  else
  {
@@ -7964,6 +7409,7 @@
    uint32_t          count;
    char             *ioremap_ptr;
    char             *mem_ptr;             
+   uint32_t          IsDead
 
    METHOD_TRACE("ips_init_phase1", 1);
    index = IPS_MAX_ADAPTERS;
@@ -8227,6 +7673,14 @@
           ha->func.issue = ips_issue_copperhead;
     }
 
+    if ( IPS_IS_MORPHEUS( ha ) ) {
+        /* If Morpheus appears dead, reset it */
+        IsDead = readl( ha->mem_ptr + IPS_REG_I960_MSG1 );
+        if ( IsDead == 0xDEADBEEF ) {
+            ips_reset_morpheus( ha );
+        }
+    }
+
     /*
      * Initialize the card if it isn't already
      */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/ips.h linux-2.4.20/drivers/scsi/ips.h
--- linux-2.4.19/drivers/scsi/ips.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/ips.h	2002-10-29 11:18:34.000000000 +0000
@@ -2,6 +2,8 @@
 /* ips.h -- driver for the IBM ServeRAID controller                          */
 /*                                                                           */
 /* Written By: Keith Mitchell, IBM Corporation                               */
+/*             Jack Hammer, Adaptec, Inc.                                    */
+/*             David Jeffery, Adaptec, Inc.                                  */
 /*                                                                           */
 /* Copyright (C) 1999 IBM Corporation                                        */
 /*                                                                           */
@@ -40,7 +42,7 @@
 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 /*                                                                           */
 /* Bugs/Comments/Suggestions should be mailed to:                            */
-/*      ipslinux@us.ibm.com                                                  */
+/*      ipslinux@adaptec.com     	                                         */
 /*                                                                           */
 /*****************************************************************************/
 
@@ -168,12 +170,14 @@
    #define IPS_CMD_WRITE_SG             0x83
    #define IPS_CMD_DCDB                 0x04
    #define IPS_CMD_DCDB_SG              0x84
+   #define IPS_CMD_EXTENDED_DCDB 	    0x95
+	#define IPS_CMD_EXTENDED_DCDB_SG		 0x96
    #define IPS_CMD_CONFIG_SYNC          0x58
    #define IPS_CMD_ERROR_TABLE          0x17
    #define IPS_CMD_DOWNLOAD             0x20
    #define IPS_CMD_RW_BIOSFW            0x22
    #define IPS_CMD_GET_VERSION_INFO     0xC6
-   #define IPS_CMD_RESET_CHANNEL        0x1A
+   #define IPS_CMD_RESET_CHANNEL        0x1A  
 
    /*
     * Adapter Equates
@@ -199,7 +203,6 @@
    #define IPS_GOOD_POST_STATUS         0x80
    #define IPS_SEM_TIMEOUT              2000
    #define IPS_IOCTL_COMMAND            0x0D
-   #define IPS_IOCTL_NEW_COMMAND        0x81
    #define IPS_INTR_ON                  0
    #define IPS_INTR_IORL                1
    #define IPS_FFDC                     99
@@ -704,6 +707,21 @@
    uint8_t   reserved2[3];
 } IPS_DCDB_TABLE, *PIPS_DCDB_TABLE;
 
+typedef struct {
+   uint8_t   device_address;
+   uint8_t   cmd_attribute;
+   uint8_t   cdb_length;
+   uint8_t   reserved_for_LUN; 	 
+   uint32_t  transfer_length;
+   uint32_t  buffer_pointer;
+   uint16_t  sg_count;
+   uint8_t   sense_length;
+   uint8_t   scsi_status;
+   uint32_t  reserved;
+   uint8_t   scsi_cdb[16];
+   uint8_t   sense_info[56];
+} IPS_DCDB_TABLE_TAPE, *PIPS_DCDB_TABLE_TAPE;
+
 typedef union {
    struct {
       volatile uint8_t  reserved;
@@ -1206,39 +1224,42 @@
 *
 *************************************************************************/
 
-#define IPS_VER_MAJOR 4
-#define IPS_VER_MAJOR_STRING "4"
-#define IPS_VER_MINOR 90
-#define IPS_VER_MINOR_STRING "90"
-#define IPS_VER_BUILD_STRING "18"
-#define IPS_VER_STRING "4.90.18"
+#define IPS_VER_MAJOR 5
+#define IPS_VER_MAJOR_STRING "5"
+#define IPS_VER_MINOR 10
+#define IPS_VER_MINOR_STRING "10"
+#define IPS_VER_BUILD 21
+#define IPS_VER_BUILD_STRING "21"
+#define IPS_VER_STRING "5.10.21"
 #define IPS_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002. All Rights Reserved."
+#define IPS_ADAPTECCOPYRIGHT_STRING "(c) Copyright Adaptec, Inc. 2002 to present. All Rights Reserved."
 #define IPS_NT_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002."
 
 /* Version numbers for various adapters */
 #define IPS_VER_SERVERAID1 "2.25.01"
 #define IPS_VER_SERVERAID2 "2.88.13"
 #define IPS_VER_NAVAJO "2.88.13"
-#define IPS_VER_SERVERAID3 "3.84.01"
-#define IPS_VER_SERVERAID4H "4.84.01"
-#define IPS_VER_SERVERAID4MLx "4.90.18"
-#define IPS_VER_SARASOTA "0.00.00"
+#define IPS_VER_SERVERAID3 "5.10.21"
+#define IPS_VER_SERVERAID4H "5.10.21"
+#define IPS_VER_SERVERAID4MLx "5.10.21"
+#define IPS_VER_SARASOTA "5.10.21"
 
 /* Compatability IDs for various adapters */
 #define IPS_COMPAT_UNKNOWN ""
+#define IPS_COMPAT_CURRENT "SA510"
 #define IPS_COMPAT_SERVERAID1 "2.25.01"
 #define IPS_COMPAT_SERVERAID2 "2.88.13"
 #define IPS_COMPAT_NAVAJO  "2.88.13"
 #define IPS_COMPAT_KIOWA "2.88.13"
-#define IPS_COMPAT_SERVERAID3H  "3.84.01"
-#define IPS_COMPAT_SERVERAID3L  "3.84.01"
-#define IPS_COMPAT_SERVERAID4H  "4.84.01"
-#define IPS_COMPAT_SERVERAID4M  "MA490"
-#define IPS_COMPAT_SERVERAID4L  "MA490"
-#define IPS_COMPAT_SERVERAID4Mx "MA490"
-#define IPS_COMPAT_SERVERAID4Lx "MA490"
-#define IPS_COMPAT_SARASOTA     "XXXXX"
-#define IPS_COMPAT_BIOS "MA490"
+#define IPS_COMPAT_SERVERAID3H  "SA510"
+#define IPS_COMPAT_SERVERAID3L  "SA510"
+#define IPS_COMPAT_SERVERAID4H  "SA510"
+#define IPS_COMPAT_SERVERAID4M  "SA510"
+#define IPS_COMPAT_SERVERAID4L  "SA510"
+#define IPS_COMPAT_SERVERAID4Mx "SA510"
+#define IPS_COMPAT_SERVERAID4Lx "SA510"
+#define IPS_COMPAT_SARASOTA     "SA510"
+#define IPS_COMPAT_BIOS "SA510"
 
 #define IPS_COMPAT_MAX_ADAPTER_TYPE 14
 #define IPS_COMPAT_ID_LENGTH 8
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/lasi700.c linux-2.4.20/drivers/scsi/lasi700.c
--- linux-2.4.19/drivers/scsi/lasi700.c	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.20/drivers/scsi/lasi700.c	2002-10-29 11:18:33.000000000 +0000
@@ -152,12 +152,6 @@
 		return 1;
 	}
 	memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
-	if(request_mem_region(base, 64, driver_name) == NULL) {
-		printk(KERN_ERR "%s: Failed to claim memory region\n",
-		       driver_name);
-		kfree(hostdata);
-		return 1;
-	}
 	hostdata->base = base;
 	hostdata->differential = 0;
 	if(dev->id.sversion == LASI_700_SVERSION) {
@@ -172,7 +166,6 @@
 	hostdata->pci_dev = ccio_get_fake(dev);
 	if((host = NCR_700_detect(host_tpnt, hostdata)) == NULL) {
 		kfree(hostdata);
-		release_mem_region(host->base, 64);
 		return 1;
 	}
 	host->irq = dev->irq;
@@ -196,7 +189,6 @@
 	NCR_700_release(host);
 	kfree(hostdata);
 	free_irq(host->irq, host);
-	release_mem_region(host->base, 64);
 	unregister_parisc_driver(&lasi700_driver);
 	return 1;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/mac_esp.c linux-2.4.20/drivers/scsi/mac_esp.c
--- linux-2.4.19/drivers/scsi/mac_esp.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/mac_esp.c	2002-10-29 11:18:40.000000000 +0000
@@ -360,14 +360,14 @@
 			} else {
 				/* q950, 900, 700 */
 				quick = 1;
-				writel(0x1d1, 0xf9800024);
+				out_be32(0xf9800024, 0x1d1);
 				esp->dregs = (void *) 0xf9800024;
 			}
 
 		} else { /* chipnum */
 
 			quick = 1;
-			writel(0x1d1, 0xf9800028);
+			out_be32(0xf9800028, 0x1d1);
 			esp->dregs = (void *) 0xf9800028;
 
 		} /* chipnum == 0 */
@@ -377,7 +377,7 @@
 
 		/* Set the command buffer */
 		esp->esp_command = (volatile unsigned char*) cmd_buffer;
-		esp->esp_command_dvma = (volatile unsigned char*) cmd_buffer;
+		esp->esp_command_dvma = (__u32) cmd_buffer;
 
 		/* various functions */
 		esp->dma_bytes_sent = &dma_bytes_sent;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/megaraid.c linux-2.4.20/drivers/scsi/megaraid.c
--- linux-2.4.19/drivers/scsi/megaraid.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/megaraid.c	2002-10-29 11:18:31.000000000 +0000
@@ -2271,7 +2271,7 @@
 
 	u_char byte;
 
-#ifdef __LP64__
+#if BITS_PER_LONG==64
 	u64 phys_mbox;
 #else
 	u32 phys_mbox;
@@ -2557,7 +2557,7 @@
 	megaCfg->mbox = &megaCfg->mailbox64.mailbox;
 #endif
 
-#ifdef __LP64__
+#if BITS_PER_LONG==64
 	megaCfg->mbox = (mega_mailbox *) ((((u64) megaCfg->mbox) + 16) & ((u64) (-1) ^ 0x0F));
 	megaCfg->adjdmahandle64 = (megaCfg->dma_handle64 + 16) & ((u64) (-1) ^ 0x0F);
 	megaCfg->mbox64 = (mega_mailbox64 *) ((u_char *) megaCfg->mbox - sizeof (u64));
@@ -2835,7 +2835,7 @@
 
 	int		i;
 
-#ifdef __LP64__
+#if BITS_PER_LONG==64
 	u64 megaBase;
 #else
 	u32 megaBase;
@@ -3153,7 +3153,7 @@
 		/* Set the Mode of addressing to 64 bit */
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 		if ((megaCfg->flag & BOARD_64BIT) && BITS_PER_LONG == 64)
-#ifdef __LP64__
+#if BITS_PER_LONG==64
 			pdev->dma_mask = 0xffffffffffffffff;
 #else
 			pdev->dma_mask = 0xffffffff;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/megaraid.h linux-2.4.20/drivers/scsi/megaraid.h
--- linux-2.4.19/drivers/scsi/megaraid.h	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.20/drivers/scsi/megaraid.h	2002-10-29 11:18:48.000000000 +0000
@@ -223,7 +223,8 @@
     cmd_per_lun:    	MAX_CMD_PER_LUN,	/* SCSI Commands per LUN	*/\
     present:	  	0,		       	/* Present			*/\
     unchecked_isa_dma:	0,		       	/* Default Unchecked ISA DMA	*/\
-    use_clustering:   	ENABLE_CLUSTERING  	/* Enable Clustering		*/\
+    use_clustering:   	ENABLE_CLUSTERING, 	/* Enable Clustering		*/\
+	highmem_io:		1, /* enable HIGHMEM I/O */ \
   }
 #endif
 
@@ -708,7 +709,7 @@
 	u8 numldrv;
 	u32 flag;
 
-#ifdef __LP64__
+#if BITS_PER_LONG==64
 	u64 base;
 #else
 	u32 base;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/mesh.c linux-2.4.20/drivers/scsi/mesh.c
--- linux-2.4.19/drivers/scsi/mesh.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/mesh.c	2002-10-29 11:18:49.000000000 +0000
@@ -498,14 +498,11 @@
 mesh_abort(Scsi_Cmnd *cmd)
 {
 	struct mesh_state *ms = (struct mesh_state *) cmd->host->hostdata;
-	unsigned long flags;
 
 	printk(KERN_DEBUG "mesh_abort(%p)\n", cmd);
-	spin_lock_irqsave(&io_request_lock, flags);
 	mesh_dump_regs(ms);
 	dumplog(ms, cmd->target);
 	dumpslog(ms);
-	spin_unlock_irqrestore(&io_request_lock, flags);
 	return SCSI_ABORT_SNOOZE;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/mvme16x.c linux-2.4.20/drivers/scsi/mvme16x.c
--- linux-2.4.19/drivers/scsi/mvme16x.c	2001-10-25 20:53:51.000000000 +0000
+++ linux-2.4.20/drivers/scsi/mvme16x.c	2002-10-29 11:18:35.000000000 +0000
@@ -21,9 +21,9 @@
 
 #include<linux/stat.h>
 
-extern ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
-			u32 base, int io_port, int irq, int dma,
-			long long options, int clock);
+extern int ncr53c7xx_init(Scsi_Host_Template *tpnt, int board, int chip,
+			  u32 base, int io_port, int irq, int dma,
+			  long long options, int clock);
 
 int mvme16x_scsi_detect(Scsi_Host_Template *tpnt)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/ncr53c8xx.c linux-2.4.20/drivers/scsi/ncr53c8xx.c
--- linux-2.4.19/drivers/scsi/ncr53c8xx.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/scsi/ncr53c8xx.c	2002-10-29 11:18:35.000000000 +0000
@@ -7185,7 +7185,7 @@
 **
 **	Possible cases:		   hs  sir   msg_in value  send   goto
 **	We try to negotiate:
-**	-> target doesnt't msgin   NEG FAIL  noop   defa.  -      dispatch
+**	-> target doesn't msgin    NEG FAIL  noop   defa.  -      dispatch
 **	-> target rejected our msg NEG FAIL  reject defa.  -      dispatch
 **	-> target answered  (ok)   NEG SYNC  sdtr   set    -      clrack
 **	-> target answered (!ok)   NEG SYNC  sdtr   defa.  REJ--->msg_bad
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/pas16.c linux-2.4.20/drivers/scsi/pas16.c
--- linux-2.4.19/drivers/scsi/pas16.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/scsi/pas16.c	2002-10-29 11:18:31.000000000 +0000
@@ -311,7 +311,7 @@
  *	the passed in pas16= options
  */
 
-int __init pas16_setup(char *str, int *ints)
+int __init pas16_setup(char *str)
 {
 	static int commandline_current = 0;
 	int i;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/ppa.c linux-2.4.20/drivers/scsi/ppa.c
--- linux-2.4.19/drivers/scsi/ppa.c	2001-09-30 19:26:07.000000000 +0000
+++ linux-2.4.20/drivers/scsi/ppa.c	2002-10-29 11:18:32.000000000 +0000
@@ -995,7 +995,7 @@
 }
 
 /*
- * Apparently the the disk->capacity attribute is off by 1 sector 
+ * Apparently the disk->capacity attribute is off by 1 sector 
  * for all disk drives.  We add the one here, but it should really
  * be done in sd.c.  Even if it gets fixed there, this will still
  * work.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/qlogicfc.h linux-2.4.20/drivers/scsi/qlogicfc.h
--- linux-2.4.19/drivers/scsi/qlogicfc.h	2001-10-21 17:36:54.000000000 +0000
+++ linux-2.4.20/drivers/scsi/qlogicfc.h	2002-10-29 11:18:37.000000000 +0000
@@ -95,7 +95,8 @@
 	cmd_per_lun:		QLOGICFC_CMD_PER_LUN, 			   \
         present:                0,                                         \
         unchecked_isa_dma:      0,                                         \
-        use_clustering:         ENABLE_CLUSTERING 			   \
+        use_clustering:         ENABLE_CLUSTERING,			   \
+	highmem_io:		1					   \
 }
 
 #endif /* _QLOGICFC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/qlogicpti.h linux-2.4.20/drivers/scsi/qlogicpti.h
--- linux-2.4.19/drivers/scsi/qlogicpti.h	1999-12-21 06:06:42.000000000 +0000
+++ linux-2.4.20/drivers/scsi/qlogicpti.h	2002-10-29 11:18:33.000000000 +0000
@@ -6,6 +6,8 @@
 #ifndef _QLOGICPTI_H
 #define _QLOGICPTI_H
 
+#include <linux/config.h>
+
 /* Qlogic/SBUS controller registers. */
 #define SBUS_CFG1	0x006UL
 #define SBUS_CTRL	0x008UL
@@ -512,6 +514,7 @@
 #define HCCTRL_B1ENAB           0x0008      /* Breakpoint 1 enable              */
 #define HCCTRL_B0ENAB           0x0004      /* Breakpoint 0 enable              */
 
+#ifdef CONFIG_SPARC64
 #define QLOGICPTI {						   \
 	detect:		qlogicpti_detect,			   \
 	release:	qlogicpti_release,			   \
@@ -524,8 +527,25 @@
 	sg_tablesize:	QLOGICPTI_MAX_SG(QLOGICPTI_REQ_QUEUE_LEN), \
 	cmd_per_lun:	1,					   \
 	use_clustering:	ENABLE_CLUSTERING,			   \
-	use_new_eh_code: 0					   \
+	use_new_eh_code: 0,					   \
+	highmem_io:	1					   \
 }
+#else
+/* Sparc32's iommu code cannot handle highmem pages yet. */
+#define QLOGICPTI {						   \
+	detect:		qlogicpti_detect,			   \
+	release:	qlogicpti_release,			   \
+	info:		qlogicpti_info,				   \
+	queuecommand:	qlogicpti_queuecommand_slow,		   \
+	abort:		qlogicpti_abort,			   \
+	reset:		qlogicpti_reset,			   \
+	can_queue:	QLOGICPTI_REQ_QUEUE_LEN,		   \
+	this_id:	7,					   \
+	sg_tablesize:	QLOGICPTI_MAX_SG(QLOGICPTI_REQ_QUEUE_LEN), \
+	cmd_per_lun:	1,					   \
+	use_clustering:	ENABLE_CLUSTERING,			   \
+}
+#endif
 
 /* For our interrupt engine. */
 #define for_each_qlogicpti(qp) \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/script_asm.pl linux-2.4.20/drivers/scsi/script_asm.pl
--- linux-2.4.19/drivers/scsi/script_asm.pl	1999-11-22 01:41:43.000000000 +0000
+++ linux-2.4.20/drivers/scsi/script_asm.pl	2002-10-29 11:18:38.000000000 +0000
@@ -12,6 +12,7 @@
 #
 #   Support for 53c710 (via -ncr7x0_family switch) added by Richard
 #   Hirst <richard@sleepie.demon.co.uk> - 15th March 1997
+#   Renamed to -ncr7x0_family to -ncr710, and added -ncr700 - 5th May 2000.
 #
 #   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
@@ -77,7 +78,7 @@
 # 	and = 0x04_00_00_00
 # 	add = 0x06_00_00_00
 
-if ($ncr7x0_family) {
+if ($ncr700 || $ncr710) {
   %operators = (
     '|', 0x02_00_00_00, 'OR', 0x02_00_00_00,
     '&', 0x04_00_00_00, 'AND', 0x04_00_00_00,
@@ -99,7 +100,24 @@
 
 # Table of register addresses
 
-if ($ncr7x0_family) {
+if ($ncr700) {
+  %registers = (
+    'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3,
+    'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7,
+    'SFBR', 8, 'SIDL', 9, 'SBDL', 10, 'SBCL', 11,
+    'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
+    'CTEST0', 20, 'CTEST1', 21, 'CTEST2', 22, 'CTEST3', 23,
+    'CTEST4', 24, 'CTEST5', 25, 'CTEST6', 26, 'CTEST7', 27,
+    'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
+    'DFIFO', 32, 'ISTAT', 33, 'CTEST8', 34,
+    'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
+    'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
+    'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
+    'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
+    'DMODE', 52, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
+  );
+}
+elsif ($ncr710) {
   %registers = (
     'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3,
     'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7,
@@ -171,7 +189,7 @@
 # be escaped, I can't use the join() trick I used for the register
 # regex
 
-if ($ncr7x0_family) {
+if ($ncr700 || $ncr710) {
   $operator = '\||OR|AND|\&|\+';
 }
 else {
@@ -468,7 +486,7 @@
 # Process MOVE length, address, WITH|WHEN phase instruction
     } elsif (/^\s*MOVE\s+(.*)/i) {
 	$rest = $1;
-	if ($rest =~ /^FROM\s+($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) {
+	if (!$ncr700 && ($rest =~ /^FROM\s+($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i)) {
 	    $transfer_addr = $1;
 	    $with_when = $2;
 	    $scsi_phase = $3;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/scsi.c linux-2.4.20/drivers/scsi/scsi.c
--- linux-2.4.19/drivers/scsi/scsi.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/scsi.c	2002-10-29 11:18:48.000000000 +0000
@@ -191,10 +191,13 @@
  *              handler in the list - ultimately they call scsi_request_fn
  *              to do the dirty deed.
  */
-void  scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt) {
-	blk_init_queue(&SDpnt->request_queue, scsi_request_fn);
-        blk_queue_headactive(&SDpnt->request_queue, 0);
-        SDpnt->request_queue.queuedata = (void *) SDpnt;
+void  scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt)
+{
+	request_queue_t *q = &SDpnt->request_queue;
+
+	blk_init_queue(q, scsi_request_fn);
+	blk_queue_headactive(q, 0);
+	q->queuedata = (void *) SDpnt;
 }
 
 #ifdef MODULE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/scsi.h linux-2.4.20/drivers/scsi/scsi.h
--- linux-2.4.19/drivers/scsi/scsi.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/scsi.h	2002-10-29 11:18:35.000000000 +0000
@@ -48,7 +48,7 @@
 #if ((SCSI_DATA_UNKNOWN == PCI_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == PCI_DMA_TODEVICE) && (SCSI_DATA_READ == PCI_DMA_FROMDEVICE) && (SCSI_DATA_NONE == PCI_DMA_NONE))
 #define scsi_to_pci_dma_dir(scsi_dir)	((int)(scsi_dir))
 #else
-extern __inline__ int scsi_to_pci_dma_dir(unsigned char scsi_dir)
+static inline int scsi_to_pci_dma_dir(unsigned char scsi_dir)
 {
         if (scsi_dir == SCSI_DATA_UNKNOWN)
                 return PCI_DMA_BIDIRECTIONAL;
@@ -66,7 +66,7 @@
 #if ((SCSI_DATA_UNKNOWN == SBUS_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == SBUS_DMA_TODEVICE) && (SCSI_DATA_READ == SBUS_DMA_FROMDEVICE) && (SCSI_DATA_NONE == SBUS_DMA_NONE))
 #define scsi_to_sbus_dma_dir(scsi_dir)	((int)(scsi_dir))
 #else
-extern __inline__ int scsi_to_sbus_dma_dir(unsigned char scsi_dir)
+static inline int scsi_to_sbus_dma_dir(unsigned char scsi_dir)
 {
         if (scsi_dir == SCSI_DATA_UNKNOWN)
                 return SBUS_DMA_BIDIRECTIONAL;
@@ -386,15 +386,6 @@
 #define ASKED_FOR_SENSE 0x20
 #define SYNC_RESET      0x40
 
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-#include <asm/pgtable.h>
-#define CONTIGUOUS_BUFFERS(X,Y) \
-	(virt_to_phys((X)->b_data+(X)->b_size-1)+1==virt_to_phys((Y)->b_data))
-#else
-#define CONTIGUOUS_BUFFERS(X,Y) ((X->b_data+X->b_size) == Y->b_data)
-#endif
-
-
 /*
  * This is the crap from the old error handling code.  We have it in a special
  * place so that we can more easily delete it later on.
@@ -633,7 +624,7 @@
 	struct scatterlist *buffer;	/* which buffer */
 	int buffers_residual;	/* how many buffers left */
 
-        dma_addr_t dma_handle;
+	dma_addr_t dma_handle;
 
 	volatile int Status;
 	volatile int Message;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/scsi_debug.c linux-2.4.20/drivers/scsi/scsi_debug.c
--- linux-2.4.19/drivers/scsi/scsi_debug.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/scsi_debug.c	2002-10-29 11:18:48.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: scsi_debug.c,v 1.1 1992/07/24 06:27:38 root Exp root $
+/* 
  *  linux/kernel/scsi_debug.c
  *
  *  Copyright (C) 1992  Eric Youngdale
@@ -12,9 +12,10 @@
  *
  *  For documentation see http://www.torque.net/sg/sdebug.html
  *
- *   D. Gilbert (dpg) work for MOD device test [20010421]
- *   dpg, work for devfs large number of disks [20010809]
- *   dpg, use vmalloc() more inquiry+mode_sense [20020302]
+ *   D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
+ *   dpg: work for devfs large number of disks [20010809]
+ *        use vmalloc() more inquiry+mode_sense [20020302]
+ *        add timers for delayed responses [20020721]
  */
 
 #include <linux/config.h>
@@ -33,20 +34,22 @@
 #include <linux/smp_lock.h>
 #include <linux/vmalloc.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include <linux/blk.h>
 #include "scsi.h"
 #include "hosts.h"
 
-#include<linux/stat.h>
+#include <linux/stat.h>
 
 #ifndef LINUX_VERSION_CODE
 #include <linux/version.h>
 #endif
 
-static char scsi_debug_version_str[] = "Version: 0.58 (20020302)";
+#include "scsi_debug.h"
+
+static const char * scsi_debug_version_str = "Version: 0.61 (20020815)";
+
 
 #ifndef SCSI_CMD_READ_16
 #define SCSI_CMD_READ_16 0x88
@@ -54,29 +57,36 @@
 #ifndef SCSI_CMD_WRITE_16
 #define SCSI_CMD_WRITE_16 0x8a
 #endif
+#ifndef REPORT_LUNS
+#define REPORT_LUNS 0xa0
+#endif
 
 /* A few options that we want selected */
 #define DEF_NR_FAKE_DEVS   1
 #define DEF_DEV_SIZE_MB   8
 #define DEF_FAKE_BLK0   0
+#define DEF_EVERY_NTH   100
+#define DEF_DELAY   1
 
 #define DEF_OPTS   0
 #define SCSI_DEBUG_OPT_NOISE   1
 #define SCSI_DEBUG_OPT_MEDIUM_ERR   2
+#define SCSI_DEBUG_OPT_EVERY_NTH   4
 
 #define OPT_MEDIUM_ERR_ADDR   0x1234
 
 static int scsi_debug_num_devs = DEF_NR_FAKE_DEVS;
 static int scsi_debug_opts = DEF_OPTS;
+static int scsi_debug_every_nth = DEF_EVERY_NTH;
+static int scsi_debug_cmnd_count = 0;
+static int scsi_debug_delay = DEF_DELAY;
 
 #define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1)
 #define N_HEAD          8
 #define N_SECTOR        32
 #define DEV_READONLY(TGT)      (0)
 #define DEV_REMOVEABLE(TGT)    (0)
-#define DEVICE_TYPE(TGT) (TYPE_DISK);
-
-#define SCSI_DEBUG_MAILBOXES (scsi_debug_num_devs + 1)
+#define PERIPH_DEVICE_TYPE(TGT) (TYPE_DISK);
 
 static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
 #define STORE_SIZE (scsi_debug_dev_size_mb * 1024 * 1024)
@@ -87,135 +97,116 @@
 
 #define N_CYLINDER (STORE_SIZE / (SECT_SIZE * N_SECTOR * N_HEAD))
 
-/* Do not attempt to use a timer to simulate a real disk with latency */
-/* Only use this in the actual kernel, not in the simulator. */
-#define IMMEDIATE
-
-#define START_PARTITION 4
-
 /* Time to wait before completing a command */
-#define DISK_SPEED     (HZ/10)	/* 100ms */
 #define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER)
 #define SECT_SIZE_PER(TGT) SECT_SIZE
 
-static int starts[] =
-{N_SECTOR,
- N_HEAD * N_SECTOR,		/* Single cylinder */
- N_HEAD * N_SECTOR * 4,
- 0 /* CAPACITY */, 0};
 
-static unsigned char * fake_storep;
+#define SDEBUG_SENSE_LEN 32
 
-typedef struct sdebug_dev_info {
+struct sdebug_dev_info {
 	Scsi_Device * sdp;
-	unsigned short host_no;
-	unsigned short id;
+	unsigned char sense_buff[SDEBUG_SENSE_LEN];	/* weak nexus */
 	char reset;
-	char sb_index;
-} Sdebug_dev_info;
-static Sdebug_dev_info * devInfop;
+};
+static struct sdebug_dev_info * devInfop;
+
+typedef void (* done_funct_t) (Scsi_Cmnd *);
+
+struct sdebug_queued_cmd {
+	int in_use;
+	struct timer_list cmnd_timer;
+	done_funct_t done_funct;
+	struct scsi_cmnd * a_cmnd;
+	int scsi_result;
+};
+static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
+
+static unsigned char * fake_storep;	/* ramdisk storage */
+
+static unsigned char broken_buff[SDEBUG_SENSE_LEN];
 
 static int num_aborts = 0;
 static int num_dev_resets = 0;
 static int num_bus_resets = 0;
 static int num_host_resets = 0;
 
-static spinlock_t mailbox_lock = SPIN_LOCK_UNLOCKED;
-static rwlock_t sdebug_atomic_rw = RW_LOCK_UNLOCKED;
-
-#include "scsi_debug.h"
-
-typedef void (*done_fct_t) (Scsi_Cmnd *);
+static spinlock_t queued_arr_lock = SPIN_LOCK_UNLOCKED;
+static rwlock_t atomic_rw = RW_LOCK_UNLOCKED;
 
-static volatile done_fct_t * do_done = 0;
 
-static struct Scsi_Host * SHpnt = NULL;
-
-static int scsi_debug_inquiry(unsigned char * cmd, int target,
-			      unsigned char * buff, int bufflen,
-			      Sdebug_dev_info * devip);
-static int scsi_debug_mode_sense(unsigned char * cmd, int target,
-			         unsigned char * buff, int bufflen,
-			         Sdebug_dev_info * devip);
-static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
-			   int num, int * errstsp, Sdebug_dev_info * devip);
-static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
-			    int num, int * errstsp, Sdebug_dev_info * devip);
-static void scsi_debug_intr_handle(unsigned long);
-static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp);
-static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, 
+/* function declarations */
+static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
+			int bufflen, struct sdebug_dev_info * devip);
+static int resp_mode_sense(unsigned char * cmd, int target,
+			   unsigned char * buff, int bufflen,
+			   struct sdebug_dev_info * devip);
+static int resp_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+		     int num, struct sdebug_dev_info * devip);
+static int resp_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num,
+		      struct sdebug_dev_info * devip);
+static int resp_report_luns(unsigned char * cmd, unsigned char * buff,
+			    int bufflen, struct sdebug_dev_info * devip);
+static void timer_intr_handler(unsigned long);
+static struct sdebug_dev_info * devInfoReg(Scsi_Device * sdp);
+static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, 
 			    int asc, int asq, int inbandLen);
-static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip);
-
-static struct timer_list * timeout = 0;
-static Scsi_Cmnd ** SCint = 0;
+static int check_reset(Scsi_Cmnd * SCpnt, struct sdebug_dev_info * devip);
+static int schedule_resp(struct scsi_cmnd * cmnd, 
+			 struct sdebug_dev_info * devip, 
+			 done_funct_t done, int scsi_result, int delta_jiff);
+static void init_all_queued(void);
+static void stop_all_queued(void);
+static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
+static int inquiry_evpd_83(unsigned char * arr, int dev_id_num,
+                           const char * dev_id_str, int dev_id_str_len);
 
-/*
- * Semaphore used to simulate bus lockups.
- */
-static int scsi_debug_lockup = 0;
 
-#define NUM_SENSE_BUFFS 4
-#define SENSE_BUFF_LEN 32
-static char sense_buffers[NUM_SENSE_BUFFS][SENSE_BUFF_LEN];
+static Scsi_Host_Template driver_template = SCSI_DEBUG_TEMPLATE;
 
 
 static
-int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done)
 {
 	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
 	int block;
 	int upper_blk;
 	unsigned char *buff;
-	int scsi_debug_errsts;
+	int errsts = 0;
 	int target = SCpnt->target;
 	int bufflen = SCpnt->request_bufflen;
-	unsigned long iflags;
-	int i, num, capac;
-	Sdebug_dev_info * devip = NULL;
-	char * sbuff;
-
-	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
-		printk(KERN_INFO "scsi_debug: queue_command: cmd ");
-		for (i = 0, num = SCpnt->cmd_len; i < num; ++i)
-	            printk("%02x ", cmd[i]);
-		printk("   use_sg=%d\n", SCpnt->use_sg);
-	}
-	/*
-	 * If we are being notified of the mid-level reposessing a command
-	 * due to timeout, just return.
-	 */
-	if (done == NULL) {
-		return 0;
-	}
-
-        if (SCpnt->use_sg) { /* just use first element */
-                struct scatterlist *sgpnt = (struct scatterlist *)
-                                                SCpnt->request_buffer;
-
-                buff = sgpnt[0].address;
-                bufflen = sgpnt[0].length;
-                /* READ and WRITE process scatterlist themselves */
+	int num, capac;
+	struct sdebug_dev_info * devip = NULL;
+	unsigned char * sbuff;
+
+	if (done == NULL)
+		return 0;	/* assume mid level reprocessing command */
+
+	if (SCpnt->use_sg) { /* just use first element */
+		struct scatterlist *sgpnt = (struct scatterlist *)
+						SCpnt->request_buffer;
+
+		buff = sgpnt[0].address;
+		bufflen = sgpnt[0].length;
+		/* READ and WRITE process scatterlist themselves */
+	}
+	else 
+		buff = (unsigned char *) SCpnt->request_buffer;
+	if (NULL == buff) {
+		printk(KERN_WARNING "scsi_debug:qc: buff was NULL??\n");
+		buff = broken_buff;	/* just point at dummy */
+		bufflen = SDEBUG_SENSE_LEN;
+	}
+
+        if(target == driver_template.this_id) {
+                printk(KERN_WARNING 
+		       "scsi_debug: initiator's id used as target!\n");
+		return schedule_resp(SCpnt, NULL, done, 0, 0);
         }
-        else
-                buff = (unsigned char *) SCpnt->request_buffer;
 
-        /*
-         * If a command comes for the ID of the host itself, just print
-         * a silly message and return.
-         */
-        if(target == 7) {
-                printk(KERN_WARNING "How do you do!\n");
-                SCpnt->result = 0;
-                done(SCpnt);
-                return 0;
-        }
-
-	if ((target > 7) || (SCpnt->lun != 0)) {
-		SCpnt->result = DID_NO_CONNECT << 16;
-		done(SCpnt);
-		return 0;
-	}
+	if ((target > driver_template.this_id) || (SCpnt->lun != 0))
+		return schedule_resp(SCpnt, NULL, done, 
+				     DID_NO_CONNECT << 16, 0);
 #if 0
 	printk(KERN_INFO "sdebug:qc: host_no=%d, id=%d, sdp=%p, cmd=0x%x\n",
 	       (int)SCpnt->device->host->host_no, (int)SCpnt->device->id,
@@ -223,101 +214,93 @@
 #endif
 	if (NULL == SCpnt->device->hostdata) {
 		devip = devInfoReg(SCpnt->device);
-		if (NULL == devip) {
-			SCpnt->result = DID_NO_CONNECT << 16;
-			done(SCpnt);
-			return 0;
-		}
+		if (NULL == devip)
+			return schedule_resp(SCpnt, NULL, done, 
+					     DID_NO_CONNECT << 16, 0);
 		SCpnt->device->hostdata = devip;
 	}
 	devip = SCpnt->device->hostdata;
 
+        if ((SCSI_DEBUG_OPT_EVERY_NTH & scsi_debug_opts) &&
+            (scsi_debug_every_nth > 0) &&
+            (++scsi_debug_cmnd_count >= scsi_debug_every_nth)) {
+                scsi_debug_cmnd_count =0;
+                return 0; /* ignore command causing timeout */
+        }
+
 	switch (*cmd) {
 	case INQUIRY:     /* mandatory */
-		scsi_debug_errsts = scsi_debug_inquiry(cmd, target, buff, 
-						       bufflen, devip);
 		/* assume INQUIRY called first so setup max_cmd_len */
 		if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
 			SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
+		errsts = resp_inquiry(cmd, target, buff, bufflen, devip);
 		break;
 	case REQUEST_SENSE:	/* mandatory */
-		SCSI_LOG_LLQUEUE(3, printk("Request sense...\n"));
+		/* Since this driver indicates autosense by placing the
+		 * sense buffer in the scsi_cmnd structure in the response
+		 * (when CHECK_CONDITION is set), the mid level shouldn't
+		 * need to call REQUEST_SENSE */
 		if (devip) {
-			sbuff = &sense_buffers[(int)devip->sb_index][0];
-			devip->sb_index = 0; 
+			sbuff = devip->sense_buff;
+			memcpy(buff, sbuff, (bufflen < SDEBUG_SENSE_LEN) ? 
+					     bufflen : SDEBUG_SENSE_LEN);
+			mk_sense_buffer(devip, 0, 0x0, 0, 7);
+		} else {
+			memset(buff, 0, bufflen);
+			buff[0] = 0x70;
 		}
-		else
-		    sbuff = &sense_buffers[0][0]; 
-		memcpy(buff, sbuff, (bufflen < SENSE_BUFF_LEN) ? 
-				     bufflen : SENSE_BUFF_LEN);
-		memset(sbuff, 0, SENSE_BUFF_LEN);
-		sbuff[0] = 0x70;
-		SCpnt->result = 0;
-		done(SCpnt);
-		return 0;
+		break;
 	case START_STOP:
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
-		SCSI_LOG_LLQUEUE(3, printk("START_STOP\n"));
-		scsi_debug_errsts = 0;
+		errsts = check_reset(SCpnt, devip);
 		break;
 	case ALLOW_MEDIUM_REMOVAL:
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
-		if (cmd[4]) {
-			SCSI_LOG_LLQUEUE(2, printk(
-					"Medium removal inhibited..."));
-		} else {
-			SCSI_LOG_LLQUEUE(2, 
-					printk("Medium removal enabled..."));
-		}
-		scsi_debug_errsts = 0;
+		if ((errsts = check_reset(SCpnt, devip)))
+			break;
+		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+			printk("\tMedium removal %s\n",
+			       cmd[4] ? "inhibited" : "enabled");
 		break;
 	case SEND_DIAGNOSTIC:     /* mandatory */
-		SCSI_LOG_LLQUEUE(3, printk("Send Diagnostic\n"));
-		if (buff)
-			memset(buff, 0, bufflen);
-		scsi_debug_errsts = 0;
+		memset(buff, 0, bufflen);
 		break;
 	case TEST_UNIT_READY:     /* mandatory */
-		SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", 
-					   buff, bufflen));
-		if (buff)
-			memset(buff, 0, bufflen);
-		scsi_debug_errsts = 0;
+		memset(buff, 0, bufflen);
 		break;
+        case RESERVE:
+		errsts = check_reset(SCpnt, devip);
+		memset(buff, 0, bufflen);
+                break;
+        case RESERVE_10:
+		errsts = check_reset(SCpnt, devip);
+		memset(buff, 0, bufflen);
+                break;
+        case RELEASE:
+		errsts = check_reset(SCpnt, devip);
+		memset(buff, 0, bufflen);
+                break;
+        case RELEASE_10:
+		errsts = check_reset(SCpnt, devip);
+		memset(buff, 0, bufflen);
+                break;
 	case READ_CAPACITY:
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
-		SCSI_LOG_LLQUEUE(3, printk("Read Capacity\n"));
-                SHpnt = SCpnt->host;
+		errsts = check_reset(SCpnt, devip);
 		memset(buff, 0, bufflen);
-		capac = CAPACITY - 1;
-		buff[0] = (capac >> 24);
-		buff[1] = (capac >> 16) & 0xff;
-		buff[2] = (capac >> 8) & 0xff;
-		buff[3] = capac & 0xff;
-		buff[4] = 0;
-		buff[5] = 0;
-		buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
-		buff[7] = SECT_SIZE_PER(target) & 0xff;
-
-		scsi_debug_errsts = 0;
+		if (bufflen > 7) {
+			capac = CAPACITY - 1;
+			buff[0] = (capac >> 24);
+			buff[1] = (capac >> 16) & 0xff;
+			buff[2] = (capac >> 8) & 0xff;
+			buff[3] = capac & 0xff;
+			buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+			buff[7] = SECT_SIZE_PER(target) & 0xff;
+		}
 		break;
 	case SCSI_CMD_READ_16:	/* SBC-2 */
 	case READ_12:
 	case READ_10:
 	case READ_6:
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
+		if ((errsts = check_reset(SCpnt, devip)))
+			break;
 		upper_blk = 0;
 		if ((*cmd) == SCSI_CMD_READ_16) {
 			upper_blk = cmd[5] + (cmd[4] << 8) + 
@@ -326,38 +309,31 @@
 				(cmd[7] << 16) + (cmd[6] << 24);
 			num = cmd[13] + (cmd[12] << 8) + 
 				(cmd[11] << 16) + (cmd[10] << 24);
-		}
-		else if ((*cmd) == READ_12) {
+		} else if ((*cmd) == READ_12) {
 			block = cmd[5] + (cmd[4] << 8) + 
 				(cmd[3] << 16) + (cmd[2] << 24);
 			num = cmd[9] + (cmd[8] << 8) + 
 				(cmd[7] << 16) + (cmd[6] << 24);
-		}
-		else if ((*cmd) == READ_10) {
+		} else if ((*cmd) == READ_10) {
 			block = cmd[5] + (cmd[4] << 8) + 
 				(cmd[3] << 16) + (cmd[2] << 24);
 			num = cmd[8] + (cmd[7] << 8);
-		}
-		else {
+		} else {
 			block = cmd[3] + (cmd[2] << 8) + 
 				((cmd[1] & 0x1f) << 16);
 			num = cmd[4];
 		}
-		if (scsi_debug_read(SCpnt, upper_blk, block, num, 
-				    &scsi_debug_errsts, devip))
-			break;
-		SCpnt->result = 0;
-/* calls bottom half in upper layers before return from scsi_do_...() */
-		(done) (SCpnt);	
-		return 0;
+		errsts = resp_read(SCpnt, upper_blk, block, num, devip);
+		break;
+	case REPORT_LUNS:
+		errsts = resp_report_luns(cmd, buff, bufflen, devip);
+		break;
 	case SCSI_CMD_WRITE_16:	/* SBC-2 */
 	case WRITE_12:
 	case WRITE_10:
 	case WRITE_6:
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
+		if ((errsts = check_reset(SCpnt, devip)))
+			break;
 		upper_blk = 0;
 		if ((*cmd) == SCSI_CMD_WRITE_16) {
 			upper_blk = cmd[5] + (cmd[4] << 8) + 
@@ -366,97 +342,38 @@
 				(cmd[7] << 16) + (cmd[6] << 24);
 			num = cmd[13] + (cmd[12] << 8) + 
 				(cmd[11] << 16) + (cmd[10] << 24);
-		}
-		else if ((*cmd) == WRITE_12) {
+		} else if ((*cmd) == WRITE_12) {
 			block = cmd[5] + (cmd[4] << 8) + 
 				(cmd[3] << 16) + (cmd[2] << 24);
 			num = cmd[9] + (cmd[8] << 8) + 
 				(cmd[7] << 16) + (cmd[6] << 24);
-		}
-		else if ((*cmd) == WRITE_10) {
+		} else if ((*cmd) == WRITE_10) {
 			block = cmd[5] + (cmd[4] << 8) + 
 				(cmd[3] << 16) + (cmd[2] << 24);
 			num = cmd[8] + (cmd[7] << 8);
-		}
-		else {
+		} else {
 			block = cmd[3] + (cmd[2] << 8) + 
 				((cmd[1] & 0x1f) << 16);
 			num = cmd[4];
 		}
-		if (scsi_debug_write(SCpnt, upper_blk, block, num, 
-				     &scsi_debug_errsts, devip))
-			break;
-		SCpnt->result = 0;
-/* calls bottom half in upper layers before return from scsi_do_...() */
-		(done) (SCpnt);	
-		return 0;
+		errsts = resp_write(SCpnt, upper_blk, block, num, devip);
+		break;
 	case MODE_SENSE:
 	case MODE_SENSE_10:
-		scsi_debug_errsts = 
-		    scsi_debug_mode_sense(cmd, target, buff, bufflen, devip);
+		errsts = resp_mode_sense(cmd, target, buff, bufflen, devip);
 		break;
 	default:
 #if 0
 		printk(KERN_INFO "scsi_debug: Unsupported command, "
 		       "opcode=0x%x\n", (int)cmd[0]);
 #endif
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
-		scsi_debug_errsts = (COMMAND_COMPLETE << 8) |
-				    (CHECK_CONDITION << 1);
-		mk_sense_buffer(devip, 2, ILLEGAL_REQUEST, 0x20, 0, 14);
-		break;
-	}
-
-	spin_lock_irqsave(&mailbox_lock, iflags);
-	for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
-		if (timeout[i].function == NULL)
+		if ((errsts = check_reset(SCpnt, devip)))
 			break;
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x20, 0, 14);
+		errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
+		break;
 	}
-
-	/*
-	 * If all of the slots are full, just return 1.  The new error 
-	 * handling scheme allows this, and the mid-level should queue things.
-	 */
-	if (i >= SCSI_DEBUG_MAILBOXES || timeout[i].function != 0) {
-		SCSI_LOG_LLQUEUE(1, printk("Command rejected - host busy\n"));
-		spin_unlock_irqrestore(&mailbox_lock, iflags);
-		return 1;
-	}
-	SCSI_LOG_LLQUEUE(1, printk("Command accepted - slot %d\n", i));
-
-#ifdef IMMEDIATE
-	if (!scsi_debug_lockup) {
-		SCpnt->result = scsi_debug_errsts;
-		SCint[i] = SCpnt;
-		do_done[i] = done;
-		scsi_debug_intr_handle(i);	/* No timer - do this one right away */
-	}
-	spin_unlock_irqrestore(&mailbox_lock, iflags);
-#else
-
-	SCpnt->result = scsi_debug_errsts;
-	timeout[i].function = scsi_debug_intr_handle;
-	timeout[i].data = i;
-	timeout[i].expires = jiffies + DISK_SPEED;
-	SCint[i] = SCpnt;
-	do_done[i] = done;
-
-	spin_unlock_irqrestore(&mailbox_lock, iflags);
-	add_timer(&timeout[i]);
-	if (!done)
-		printk(KERN_ERR "scsi_debug_queuecommand: "
-		       "done can't be NULL\n");
-
-#if 0
-	printk(KERN_INFO "Sending command (%d %x %d %d)...", i, done, 
-	       timeout[i].expires, jiffies);
-#endif
-#endif
-
-	return 0;
+	return schedule_resp(SCpnt, devip, done, errsts, scsi_debug_delay);
 }
 
 static int scsi_debug_ioctl(Scsi_Device *dev, int cmd, void *arg)
@@ -464,58 +381,101 @@
 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
 		printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
 	}
-	return -ENOTTY;
+	/* return -ENOTTY; // Unix mandates this but apps get upset */
+	return -EINVAL;
 }
 
-static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip)
+static int check_reset(Scsi_Cmnd * SCpnt, struct sdebug_dev_info * devip)
 {
 	if (devip->reset) {
 		devip->reset = 0;
-		mk_sense_buffer(devip, 3, UNIT_ATTENTION, 0x29, 0, 14);
-		SCpnt->result = (COMMAND_COMPLETE << 8) | 
-				(CHECK_CONDITION << 1);
-                return 1;
+		mk_sense_buffer(devip, UNIT_ATTENTION, 0x29, 0, 14);
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
 	return 0;
 }
 
-#define SDEBUG_MAX_INQ_SZ 58
+#define SDEBUG_LONG_INQ_SZ 58
+#define SDEBUG_MAX_INQ_ARR_SZ 128
 
-static int scsi_debug_inquiry(unsigned char * cmd, int target,
-			      unsigned char * buff, int bufflen,
-			      Sdebug_dev_info * devip)
+static const char * vendor_id = "Linux   ";
+static const char * product_id = "scsi_debug      ";
+static const char * product_rev = "0004";
+
+static int inquiry_evpd_83(unsigned char * arr, int dev_id_num, 
+			   const char * dev_id_str, int dev_id_str_len)
+{
+	int num;
+
+	/* Two identification descriptors: */
+	/* T10 vendor identifier field format (faked) */
+	arr[0] = 0x2;	/* ASCII */
+	arr[1] = 0x1;
+	arr[2] = 0x0;
+	memcpy(&arr[4], vendor_id, 8);
+	memcpy(&arr[12], product_id, 16);
+	memcpy(&arr[28], dev_id_str, dev_id_str_len);
+	num = 8 + 16 + dev_id_str_len;
+	arr[3] = num;
+	num += 4;
+	/* NAA IEEE registered identifier (faked) */
+	arr[num] = 0x1;	/* binary */
+	arr[num + 1] = 0x3;
+	arr[num + 2] = 0x0;
+	arr[num + 3] = 0x8;
+	arr[num + 4] = 0x51;	/* ieee company id=0x123456 (faked) */
+	arr[num + 5] = 0x23;
+	arr[num + 6] = 0x45;
+	arr[num + 7] = 0x60;
+	arr[num + 8] = (dev_id_num >> 24);
+	arr[num + 9] = (dev_id_num >> 16) & 0xff;
+	arr[num + 10] = (dev_id_num >> 8) & 0xff;
+	arr[num + 11] = dev_id_num & 0xff;
+	return num + 12;
+}
+
+static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
+			int bufflen, struct sdebug_dev_info * devip)
 {
 	unsigned char pq_pdt;
-	unsigned char arr[SDEBUG_MAX_INQ_SZ];
-	int min_len = bufflen > SDEBUG_MAX_INQ_SZ ? 
-			SDEBUG_MAX_INQ_SZ : bufflen;
+	unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ];
+	int min_len = bufflen > SDEBUG_MAX_INQ_ARR_SZ ? 
+			SDEBUG_MAX_INQ_ARR_SZ : bufflen;
 
-	SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen));
 	if (bufflen < cmd[4])
 		printk(KERN_INFO "scsi_debug: inquiry: bufflen=%d "
 		       "< alloc_length=%d\n", bufflen, (int)cmd[4]);
 	memset(buff, 0, bufflen);
-	memset(arr, 0, SDEBUG_MAX_INQ_SZ);
-	pq_pdt = DEVICE_TYPE(target);
+	memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ);
+	pq_pdt = PERIPH_DEVICE_TYPE(target);
 	arr[0] = pq_pdt;
 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
-		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14);
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
 		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
-	}
-	else if (0x1 & cmd[1]) {  /* EVPD bit set */
+	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
+		int dev_id_num, len;
+		char dev_id_str[6];
+		
+		dev_id_num = ((devip->sdp->host->host_no + 1) * 1000) + 
+			      devip->sdp->id;
+		len = snprintf(dev_id_str, 6, "%d", dev_id_num);
+		len = (len > 6) ? 6 : len;
 		if (0 == cmd[2]) { /* supported vital product data pages */
-			arr[3] = 1;
-			arr[4] = 0x80; /* ... only unit serial number */
-		}
-		else if (0x80 == cmd[2]) { /* unit serial number */
+			arr[3] = 3;
+			arr[4] = 0x0; /* this page */
+			arr[5] = 0x80; /* unit serial number */
+			arr[6] = 0x83; /* device identification */
+		} else if (0x80 == cmd[2]) { /* unit serial number */
 			arr[1] = 0x80;
-			arr[3] = 4;
-			arr[4] = '1'; arr[5] = '2'; arr[6] = '3';
-			arr[7] = '4';
-		}
-		else {
+			arr[3] = len;
+			memcpy(&arr[4], dev_id_str, len);
+		} else if (0x83 == cmd[2]) { /* device identification */
+			arr[1] = 0x83;
+			arr[3] = inquiry_evpd_83(&arr[4], dev_id_num,
+						 dev_id_str, len);
+		} else {
 			/* Illegal request, invalid field in cdb */
-			mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14);
+			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
 			return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 		}
 		memcpy(buff, arr, min_len); 
@@ -524,18 +484,18 @@
 	/* drops through here for a standard inquiry */
 	arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */
 	arr[2] = 3;	/* claim SCSI 3 */
-	arr[4] = SDEBUG_MAX_INQ_SZ - 5;
+	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
 	arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */
-	memcpy(&arr[8], "Linux   ", 8);
-	memcpy(&arr[16], "scsi_debug      ", 16);
-	memcpy(&arr[32], "0003", 4);
+	memcpy(&arr[8], vendor_id, 8);
+	memcpy(&arr[16], product_id, 16);
+	memcpy(&arr[32], product_rev, 4);
 	memcpy(buff, arr, min_len);
 	return 0;
 }
 
 /* <<Following mode page info copied from ST318451LW>> */ 
 
-static int sdebug_err_recov_pg(unsigned char * p, int pcontrol, int target)
+static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
 {	/* Read-Write Error Recovery page for mode_sense */
 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 
 					5, 0, 0xff, 0xff};
@@ -546,7 +506,7 @@
 	return sizeof(err_recov_pg);
 }
 
-static int sdebug_disconnect_pg(unsigned char * p, int pcontrol, int target)
+static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
 { 	/* Disconnect-Reconnect page for mode_sense */
 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 
 					 0, 0, 0, 0, 0, 0, 0, 0};
@@ -557,7 +517,25 @@
 	return sizeof(disconnect_pg);
 }
 
-static int sdebug_caching_pg(unsigned char * p, int pcontrol, int target)
+static int resp_format_pg(unsigned char * p, int pcontrol, int target)
+{       /* Format device page for mode_sense */
+        unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
+                                     0, 0, 0, 0, 0, 0, 0, 0,
+                                     0, 0, 0, 0, 0x40, 0, 0, 0};
+
+        memcpy(p, format_pg, sizeof(format_pg));
+        p[10] = (N_SECTOR >> 8) & 0xff;
+        p[11] = N_SECTOR & 0xff;
+        p[12] = (SECT_SIZE >> 8) & 0xff;
+        p[13] = SECT_SIZE & 0xff;
+        if (DEV_REMOVEABLE(target))
+                p[20] |= 0x20; /* should agree with INQUIRY */
+        if (1 == pcontrol)
+                memset(p + 2, 0, sizeof(format_pg) - 2);
+        return sizeof(format_pg);
+}
+
+static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
 { 	/* Caching page for mode_sense */
 	unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 
 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
@@ -568,7 +546,7 @@
 	return sizeof(caching_pg);
 }
 
-static int sdebug_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
+static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
 { 	/* Control mode page for mode_sense */
 	unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
 				     0, 0, 0x2, 0x4b};
@@ -582,9 +560,9 @@
 
 #define SDEBUG_MAX_MSENSE_SZ 256
 
-static int scsi_debug_mode_sense(unsigned char * cmd, int target,
-			         unsigned char * buff, int bufflen,
-			         Sdebug_dev_info * devip)
+static int resp_mode_sense(unsigned char * cmd, int target,
+			   unsigned char * buff, int bufflen,
+			   struct sdebug_dev_info * devip)
 {
 	unsigned char dbd;
 	int pcontrol, pcode;
@@ -610,15 +588,14 @@
 	memset(buff, 0, bufflen);
 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
 	if (0x3 == pcontrol) {  /* Saving values not supported */
-		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x39, 0, 14);
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x39, 0, 14);
 		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
 	dev_spec = DEV_READONLY(target) ? 0x80 : 0x0;
 	if (msense_6) {
 		arr[2] = dev_spec;
 		offset = 4;
-	}
-	else {
+	} else {
 		arr[3] = dev_spec;
 		offset = 8;
 	}
@@ -626,30 +603,34 @@
 
 	switch (pcode) {
 	case 0x1:	/* Read-Write error recovery page, direct access */
-		len = sdebug_err_recov_pg(ap, pcontrol, target);
+		len = resp_err_recov_pg(ap, pcontrol, target);
 		offset += len;
 		break;
 	case 0x2:	/* Disconnect-Reconnect page, all devices */
-		len = sdebug_disconnect_pg(ap, pcontrol, target);
+		len = resp_disconnect_pg(ap, pcontrol, target);
 		offset += len;
 		break;
+        case 0x3:       /* Format device page, direct access */
+                len = resp_format_pg(ap, pcontrol, target);
+                offset += len;
+                break;
 	case 0x8:	/* Caching page, direct access */
-		len = sdebug_caching_pg(ap, pcontrol, target);
+		len = resp_caching_pg(ap, pcontrol, target);
 		offset += len;
 		break;
 	case 0xa:	/* Control Mode page, all devices */
-		len = sdebug_ctrl_m_pg(ap, pcontrol, target);
+		len = resp_ctrl_m_pg(ap, pcontrol, target);
 		offset += len;
 		break;
 	case 0x3f:	/* Read all Mode pages */
-		len = sdebug_err_recov_pg(ap, pcontrol, target);
-		len += sdebug_disconnect_pg(ap + len, pcontrol, target);
-		len += sdebug_caching_pg(ap + len, pcontrol, target);
-		len += sdebug_ctrl_m_pg(ap + len, pcontrol, target);
+		len = resp_err_recov_pg(ap, pcontrol, target);
+		len += resp_disconnect_pg(ap + len, pcontrol, target);
+		len += resp_caching_pg(ap + len, pcontrol, target);
+		len += resp_ctrl_m_pg(ap + len, pcontrol, target);
 		offset += len;
 		break;
 	default:
-		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14);
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
 		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
 	if (msense_6)
@@ -663,8 +644,8 @@
 	return 0;
 }
 
-static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
-			   int num, int * errstsp, Sdebug_dev_info * devip)
+static int resp_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, 
+		     struct sdebug_dev_info * devip)
 {
         unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
         int nbytes, sgcount;
@@ -673,30 +654,17 @@
 	unsigned long iflags;
 
 	if (upper_blk || (block + num > CAPACITY)) {
-		*errstsp = (COMMAND_COMPLETE << 8) |
-			   (CHECK_CONDITION << 1);
-		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
-		return 1;
-	}
-#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
-	{
-		int delay = SCSI_SETUP_LATENCY;
-
-		delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
-		if (delay)
-			usleep(delay);
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x21, 0, 14);
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
-#endif
 	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
 	    (block >= OPT_MEDIUM_ERR_ADDR) && 
 	    (block < (OPT_MEDIUM_ERR_ADDR + num))) {
-		*errstsp = (COMMAND_COMPLETE << 8) |
-			   (CHECK_CONDITION << 1);
-		mk_sense_buffer(devip, 1, MEDIUM_ERROR, 0x11, 0, 14);
+		mk_sense_buffer(devip, MEDIUM_ERROR, 0x11, 0, 14);
 		/* claim unrecoverable read error */
-		return 1;
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
-	read_lock_irqsave(&sdebug_atomic_rw, iflags);
+	read_lock_irqsave(&atomic_rw, iflags);
         sgcount = 0;
 	nbytes = bufflen;
 	/* printk(KERN_INFO "scsi_debug_read: block=%d, tot_bufflen=%d\n", 
@@ -707,24 +675,8 @@
 		buff = sgpnt[sgcount].address;
 		bufflen = sgpnt[sgcount].length;
 	}
-	*errstsp = 0;
 	do {
 		memcpy(buff, fake_storep + (block * SECT_SIZE), bufflen);
-#if 0
-		/* Simulate a disk change */
-		if (block == 0xfff0) {
-			sense_buffer[0] = 0x70;
-			sense_buffer[2] = UNIT_ATTENTION;
-			starts[0] += 10;
-			starts[1] += 10;
-			starts[2] += 10;
-
-			*errstsp = (COMMAND_COMPLETE << 8) | 
-				   (CHECK_CONDITION << 1);
-			read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
-			return 1;
-		}	/* End phony disk change code */
-#endif
 		nbytes -= bufflen;
 		if (SCpnt->use_sg) {
 			block += bufflen >> POW2_SECT_SIZE;
@@ -733,17 +685,16 @@
 				buff = sgpnt[sgcount].address;
 				bufflen = sgpnt[sgcount].length;
 			}
-		}
-		else if (nbytes > 0)
-			printk(KERN_WARNING "sdebug_read: unexpected "
+		} else if (nbytes > 0)
+			printk(KERN_WARNING "scsi_debug:resp_read: unexpected "
 			       "nbytes=%d\n", nbytes);
 	} while (nbytes);
-	read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+	read_unlock_irqrestore(&atomic_rw, iflags);
 	return 0;
 }
 
-static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
-			    int num, int * errstsp, Sdebug_dev_info * devip)
+static int resp_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, 
+		      struct sdebug_dev_info * devip)
 {
         unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
         int nbytes, sgcount;
@@ -752,13 +703,11 @@
 	unsigned long iflags;
 
 	if (upper_blk || (block + num > CAPACITY)) {
-		*errstsp = (COMMAND_COMPLETE << 8) |
-			   (CHECK_CONDITION << 1);
-		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
-		return 1;
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x21, 0, 14);
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
 
-	write_lock_irqsave(&sdebug_atomic_rw, iflags);
+	write_lock_irqsave(&atomic_rw, iflags);
         sgcount = 0;
 	nbytes = bufflen;
 	if (SCpnt->use_sg) {
@@ -767,7 +716,6 @@
 		buff = sgpnt[sgcount].address;
 		bufflen = sgpnt[sgcount].length;
 	}
-	*errstsp = 0;
 	do {
 		memcpy(fake_storep + (block * SECT_SIZE), buff, bufflen);
 
@@ -779,101 +727,61 @@
 				buff = sgpnt[sgcount].address;
 				bufflen = sgpnt[sgcount].length;
 			}
-		}
-		else if (nbytes > 0)
-			printk(KERN_WARNING "sdebug_write: "
+		} else if (nbytes > 0)
+			printk(KERN_WARNING "scsi_debug:resp_write: "
 			       "unexpected nbytes=%d\n", nbytes);
 	} while (nbytes);
-	write_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+	write_unlock_irqrestore(&atomic_rw, iflags);
 	return 0;
 }
 
-/* A "high" level interrupt handler.  This should be called once per jiffy
- * to simulate a regular scsi disk.  We use a timer to do this. */
-
-static void scsi_debug_intr_handle(unsigned long indx)
+static int resp_report_luns(unsigned char * cmd, unsigned char * buff,
+			    int bufflen, struct sdebug_dev_info * devip)
 {
-	Scsi_Cmnd *SCtmp;
-	void (*my_done) (Scsi_Cmnd *);
-#if 0
-	del_timer(&timeout[indx]);
-#endif
-
-	SCtmp = (Scsi_Cmnd *) SCint[indx];
-	my_done = do_done[indx];
-	do_done[indx] = NULL;
-	timeout[indx].function = NULL;
-	SCint[indx] = NULL;
+	unsigned int alloc_len;
+	int select_report = (int)cmd[2];
 
-	if (!my_done) {
-		printk(KERN_ERR "scsi_debug_intr_handle: Unexpected "
-		       "interrupt\n");
-		return;
+	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
+	if ((alloc_len < 16) || (select_report > 2)) {
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
-#if 0
-	printk(KERN_INFO "In intr_handle...");
-	printk(KERN_INFO "...done %d %x %d %d\n", i, my_done, to, jiffies);
-	printk(KERN_INFO "In intr_handle: %d %x %x\n", i, SCtmp, my_done);
-#endif
-
-	my_done(SCtmp);
-#if 0
-	printk(KERN_INFO "Called done.\n");
-#endif
+	if (bufflen > 3) {
+		memset(buff, 0, bufflen);
+		buff[3] = 8;
+	}
+	return 0;
 }
 
-static int initialized = 0;
-
-static int do_init(void)
+/* When timer goes off this function is called. */
+static void timer_intr_handler(unsigned long indx)
 {
-	int sz = STORE_SIZE;
-
-	starts[3] = CAPACITY;
-	fake_storep = vmalloc(sz);
-	if (NULL == fake_storep)
-		return 1;
-	memset(fake_storep, 0, sz);
-
-	sz = sizeof(done_fct_t) * SCSI_DEBUG_MAILBOXES;
-	do_done = kmalloc(sz, GFP_ATOMIC);
-	if (NULL == do_done)
-		goto out;
-	memset((void *)do_done, 0, sz);
-
-	sz = sizeof(struct timer_list) * SCSI_DEBUG_MAILBOXES;
-	timeout = kmalloc(sz, GFP_ATOMIC);
-	if (NULL == timeout)
-		goto out;
-	memset(timeout, 0, sz);
-
-	sz = sizeof(Scsi_Cmnd *) * SCSI_DEBUG_MAILBOXES;
-	SCint = kmalloc(sz, GFP_ATOMIC);
-	if (NULL == SCint)
-		goto out;
-	memset(SCint, 0, sz);
+	struct sdebug_queued_cmd * sqcp;
+	unsigned int iflags;
 
-	return 0;
-
-out:
-	if (fake_storep)
-		vfree(fake_storep);
-	if (do_done)
-		kfree((void *)do_done);
-	if (timeout)
-		kfree(timeout);
-	if (SCint)
-		kfree(SCint);
-	return 1;
-}
-
-static void do_end(void)
-{
-	kfree(SCint);
-	kfree(timeout);
-	kfree((void *)do_done);
-	vfree(fake_storep);
+	if (indx >= SCSI_DEBUG_CANQUEUE) {
+		printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
+		       "large\n");
+		return;
+	}
+	spin_lock_irqsave(&queued_arr_lock, iflags);
+	sqcp = &queued_arr[(int)indx];
+	if (! sqcp->in_use) {
+		printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
+		       "interrupt\n");
+		spin_unlock_irqrestore(&queued_arr_lock, iflags);
+		return;
+	}
+	sqcp->in_use = 0;
+	if (sqcp->done_funct)
+		sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
+	sqcp->done_funct = NULL;
+	spin_unlock_irqrestore(&queued_arr_lock, iflags);
 }
 
+static int initialized = 0;
+static int num_present = 0;
+static const char * sdebug_proc_name = "scsi_debug";
 
 static int scsi_debug_detect(Scsi_Host_Template * tpnt)
 {
@@ -883,28 +791,33 @@
 		printk(KERN_INFO "scsi_debug: detect\n");
 	if (0 == initialized) {
 		++initialized;
-		sz = sizeof(Sdebug_dev_info) * scsi_debug_num_devs;
-		devInfop = kmalloc(sz, GFP_ATOMIC);
+		sz = sizeof(struct sdebug_dev_info) * scsi_debug_num_devs;
+		devInfop = vmalloc(sz);
 		if (NULL == devInfop) {
 			printk(KERN_ERR "scsi_debug_detect: out of "
 			       "memory, 0.5\n");
 			return 0;
 		}
 		memset(devInfop, 0, sz);
-		if (do_init()) {
+		sz = STORE_SIZE;
+		fake_storep = vmalloc(sz);
+		if (NULL == fake_storep) {
 			printk(KERN_ERR "scsi_debug_detect: out of memory"
 			       ", 0\n");
 			return 0;
 		}
-		for (k = 0; k < NUM_SENSE_BUFFS; ++k)
-			sense_buffers[k][0] = 0x70;
-		for (k = 0; k < NR_HOSTS_PRESENT; k++) {
-			tpnt->proc_name = "scsi_debug";	/* In the loop??? */
-			scsi_register(tpnt, 0);
+		memset(fake_storep, 0, sz);
+		init_all_queued();
+		tpnt->proc_name = (char *)sdebug_proc_name;
+		for (num_present = 0, k = 0; k < NR_HOSTS_PRESENT; k++) {
+			if (NULL == scsi_register(tpnt, 0))
+				printk(KERN_ERR "scsi_debug_detect: "
+					"scsi_register failed k=%d\n", k);
+			else
+				++num_present;
 		}
-		return NR_HOSTS_PRESENT;
-	}
-	else {
+		return num_present;
+	} else {
 		printk(KERN_WARNING "scsi_debug_detect: called again\n");
 		return 0;
 	}
@@ -917,51 +830,47 @@
 {
 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
 		printk(KERN_INFO "scsi_debug: release\n");
+	stop_all_queued();
 	scsi_unregister(hpnt);
-	if (++num_releases != NR_HOSTS_PRESENT)
-		return 0;
-	do_end();
-	kfree(devInfop);
+	if (++num_releases == num_present) {
+		vfree(fake_storep);
+		vfree(devInfop);
+	}
 	return 0;
 }
 
-static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp)
+static struct sdebug_dev_info * devInfoReg(Scsi_Device * sdp)
 {
 	int k;
-	unsigned short host_no, id;
-	Sdebug_dev_info * devip;
+	struct sdebug_dev_info * devip;
 
-	host_no = sdp->host->host_no;
-	id = (unsigned short)sdp->id;
 	for (k = 0; k < scsi_debug_num_devs; ++k) {
 		devip = &devInfop[k];
-		if (devip->sdp && (host_no == devip->host_no) &&
-		    (id == devip->id)) {
-			devip->sdp = sdp; /* overwrite previous sdp */
+		if (devip->sdp == sdp)
 			return devip;
-		}
+	}
+	for (k = 0; k < scsi_debug_num_devs; ++k) {
+		devip = &devInfop[k];
 		if (NULL == devip->sdp) {
 			devip->sdp = sdp;
-			devip->host_no = host_no;
-			devip->id = id;
 			devip->reset = 1;
-			devip->sb_index = 0;
+			memset(devip->sense_buff, 0, SDEBUG_SENSE_LEN);
+			devip->sense_buff[0] = 0x70;
 			return devip;
 		}
 	}
 	return NULL;
 }
 
-static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, 
+static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, 
 			    int asc, int asq, int inbandLen)
 {
-	char * sbuff;
-	if ((index < 0) || (index >= NUM_SENSE_BUFFS))
-		return;
-	if (devip)
-		devip->sb_index = index;
-	sbuff = &sense_buffers[index][0];
-	memset(sbuff, 0, SENSE_BUFF_LEN);
+	unsigned char * sbuff;
+
+	sbuff = devip->sense_buff;
+	memset(sbuff, 0, SDEBUG_SENSE_LEN);
+	if (inbandLen > SDEBUG_SENSE_LEN)
+		inbandLen = SDEBUG_SENSE_LEN;
 	sbuff[0] = 0x70;
 	sbuff[2] = key;
 	sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0;
@@ -973,27 +882,9 @@
 {
 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
 		printk(KERN_INFO "scsi_debug: abort\n");
-#if 1
 	++num_aborts;
+	stop_queued_cmnd(SCpnt);
 	return SUCCESS;
-#else
-	int j;
-	void (*my_done) (Scsi_Cmnd *);
-	unsigned long iflags;
-	SCpnt->result = SCpnt->abort_reason << 16;
-	for (j = 0; j < SCSI_DEBUG_MAILBOXES; j++) {
-		if (SCpnt == SCint[j]) {
-			my_done = do_done[j];
-			my_done(SCpnt);
-			spin_lock_irqsave(&mailbox_lock, iflags);
-			timeout[j] = 0;
-			SCint[j] = NULL;
-			do_done[j] = NULL;
-			spin_unlock_irqrestore(&mailbox_lock, iflags);
-		}
-	}
-	return SCSI_ABORT_SNOOZE;
-#endif
 }
 
 static int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info)
@@ -1055,12 +946,124 @@
 	++num_host_resets;
 	for (k = 0; k < scsi_debug_num_devs; ++k)
 		devInfop[k].reset = 1;
+	stop_all_queued();
 
 	return SUCCESS;
 }
 
+/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
+static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
+{
+	unsigned long iflags;
+	int k;
+	struct sdebug_queued_cmd * sqcp;
+
+	spin_lock_irqsave(&queued_arr_lock, iflags);
+	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+		sqcp = &queued_arr[k];
+		if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
+			del_timer_sync(&sqcp->cmnd_timer);
+			sqcp->in_use = 0;
+			sqcp->a_cmnd = NULL;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&queued_arr_lock, iflags);
+	return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
+}
+
+/* Deletes (stops) timers of all queued commands */
+static void stop_all_queued(void)
+{
+	unsigned long iflags;
+	int k;
+	struct sdebug_queued_cmd * sqcp;
+
+	spin_lock_irqsave(&queued_arr_lock, iflags);
+	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+		sqcp = &queued_arr[k];
+		if (sqcp->in_use && sqcp->a_cmnd) {
+			del_timer_sync(&sqcp->cmnd_timer);
+			sqcp->in_use = 0;
+			sqcp->a_cmnd = NULL;
+		}
+	}
+	spin_unlock_irqrestore(&queued_arr_lock, iflags);
+}
+
+/* Initializes timers in queued array */
+static void init_all_queued(void)
+{
+	unsigned long iflags;
+	int k;
+	struct sdebug_queued_cmd * sqcp;
+
+	spin_lock_irqsave(&queued_arr_lock, iflags);
+	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+		sqcp = &queued_arr[k];
+		init_timer(&sqcp->cmnd_timer);
+		sqcp->in_use = 0;
+		sqcp->a_cmnd = NULL;
+	}
+	spin_unlock_irqrestore(&queued_arr_lock, iflags);
+}
+
+static int schedule_resp(struct scsi_cmnd * cmnd, 
+			 struct sdebug_dev_info * devip,
+			 done_funct_t done, int scsi_result, int delta_jiff)
+{
+	int k, num; 
+
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
+		printk(KERN_INFO "scsi_debug: cmd ");
+		for (k = 0, num = cmnd->cmd_len; k < num; ++k)
+	            printk("%02x ", (int)cmnd->cmnd[k]);
+		printk("result=0x%x\n", scsi_result);
+	}
+	if (cmnd && devip) {
+		/* simulate autosense by this driver */
+		if (CHECK_CONDITION == status_byte(scsi_result))
+			memcpy(cmnd->sense_buffer, devip->sense_buff, 
+			       (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
+			       SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
+	}
+	if (delta_jiff <= 0) {
+		if (cmnd)
+			cmnd->result = scsi_result;
+		if (done)
+			done(cmnd);
+		return 0;
+	} else {
+		unsigned long iflags;
+		int k;
+		struct sdebug_queued_cmd * sqcp = NULL;
+
+		spin_lock_irqsave(&queued_arr_lock, iflags);
+		for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+			sqcp = &queued_arr[k];
+			if (! sqcp->in_use)
+				break;
+		}
+		if (k >= SCSI_DEBUG_CANQUEUE) {
+			spin_unlock_irqrestore(&queued_arr_lock, iflags);
+			printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
+			return 1;	/* report busy to mid level */
+		}
+		sqcp->in_use = 1;
+		sqcp->a_cmnd = cmnd;
+		sqcp->scsi_result = scsi_result;
+		sqcp->done_funct = done;
+		sqcp->cmnd_timer.function = timer_intr_handler;
+		sqcp->cmnd_timer.data = k;
+		sqcp->cmnd_timer.expires = jiffies + delta_jiff;
+		add_timer(&sqcp->cmnd_timer);
+		spin_unlock_irqrestore(&queued_arr_lock, iflags);
+		return 0;
+	}
+}
+
 #ifndef MODULE
-static int __init scsi_debug_num_devs_setup(char *str)
+static int __init num_devs_setup(char *str)
 {   
     int tmp; 
     
@@ -1074,10 +1077,9 @@
         return 0;
     }
 }
+__setup("scsi_debug_num_devs=", num_devs_setup);
 
-__setup("scsi_debug_num_devs=", scsi_debug_num_devs_setup);
-
-static int __init scsi_debug_dev_size_mb_setup(char *str)
+static int __init dev_size_mb_setup(char *str)
 {   
     int tmp; 
     
@@ -1092,10 +1094,9 @@
         return 0;
     }
 }
+__setup("scsi_debug_dev_size_mb=", dev_size_mb_setup);
 
-__setup("scsi_debug_dev_size_mb=", scsi_debug_dev_size_mb_setup);
-
-static int __init scsi_debug_opts_setup(char *str)
+static int __init opts_setup(char *str)
 {   
     int tmp; 
     
@@ -1110,8 +1111,41 @@
         return 0;
     }
 }
+__setup("scsi_debug_opts=", opts_setup);
+
+static int __init every_nth_setup(char *str)
+{
+    int tmp;
+
+    if (get_option(&str, &tmp) == 1) {
+        if (tmp > 0)
+            scsi_debug_every_nth = tmp;
+        return 1;
+    } else {
+        printk(KERN_INFO "scsi_debug_every_nth: usage "
+               "scsi_debug_every_nth=<n>\n"
+               "    timeout every nth command (when ...)\n");
+        return 0;
+    }
+}
+__setup("scsi_debug_every_nth=", every_nth_setup);
+
+static int __init delay_setup(char *str)
+{
+    int tmp;
+
+    if (get_option(&str, &tmp) == 1) {
+	scsi_debug_delay = tmp;
+        return 1;
+    } else {
+        printk(KERN_INFO "scsi_debug_delay: usage "
+               "scsi_debug_delay=<n>\n"
+               "    delay response <n> jiffies\n");
+        return 0;
+    }
+}
+__setup("scsi_debug_delay=", delay_setup);
 
-__setup("scsi_debug_opts=", scsi_debug_opts_setup);
 #endif
 
 MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
@@ -1122,14 +1156,17 @@
 MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs");
 MODULE_PARM(scsi_debug_opts, "i");
 MODULE_PARM_DESC(scsi_debug_opts, "1->noise, 2->medium_error, 4->...");
-
+MODULE_PARM(scsi_debug_every_nth, "i");
+MODULE_PARM_DESC(scsi_debug_every_nth, "timeout every nth command(def=100)");
+MODULE_PARM(scsi_debug_delay, "i");
+MODULE_PARM_DESC(scsi_debug_delay, "# of jiffies to delay response(def=1)");
 #ifdef MODULE_LICENSE
 MODULE_LICENSE("GPL");
 #endif
 
 static char sdebug_info[256];
 
-const char * scsi_debug_info(struct Scsi_Host * shp)
+static const char * scsi_debug_info(struct Scsi_Host * shp)
 {
 	sprintf(sdebug_info, "scsi_debug, %s, num_devs=%d, "
 		"dev_size_mb=%d, opts=0x%x", scsi_debug_version_str,
@@ -1141,8 +1178,8 @@
 /* scsi_debug_proc_info
  * Used if the driver currently has no own support for /proc/scsi
  */
-int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
-			 int length, int inode, int inout)
+static int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
+				int length, int inode, int inout)
 {
 	int len, pos, begin;
 	int orig_length;
@@ -1160,17 +1197,21 @@
 		if (1 != sscanf(arr, "%d", &pos))
 			return -EINVAL;
 		scsi_debug_opts = pos;
+		if (SCSI_DEBUG_OPT_EVERY_NTH & scsi_debug_opts)
+                        scsi_debug_cmnd_count = 0;
 		return length;
 	}
 	begin = 0;
 	pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n"
-	    "num_devs=%d, shared (ram) size=%d MB, opts=0x%x\n"
-	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
-	    "number of aborts=%d, device_reset=%d, bus_resets=%d, " 
+	    "num_devs=%d, shared (ram) size=%d MB, opts=0x%x, "
+	    "every_nth=%d(curr:%d)\n"
+	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d, "
+	    "delay=%d\nnumber of aborts=%d, device_reset=%d, bus_resets=%d, " 
 	    "host_resets=%d\n",
 	    scsi_debug_version_str, scsi_debug_num_devs, 
-	    scsi_debug_dev_size_mb, scsi_debug_opts, SECT_SIZE,
-	    N_CYLINDER, N_HEAD, N_SECTOR,
+	    scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
+	    scsi_debug_cmnd_count,
+	    SECT_SIZE, N_CYLINDER, N_HEAD, N_SECTOR, scsi_debug_delay,
 	    num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
 	if (pos < offset) {
 		len = 0;
@@ -1184,8 +1225,4 @@
 	return (len);
 }
 
-/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = SCSI_DEBUG_TEMPLATE;
-
 #include "scsi_module.c"
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/scsi_debug.h linux-2.4.20/drivers/scsi/scsi_debug.h
--- linux-2.4.19/drivers/scsi/scsi_debug.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/scsi_debug.h	2002-10-29 11:18:40.000000000 +0000
@@ -4,24 +4,22 @@
 #include <linux/kdev_t.h>
 
 static int scsi_debug_detect(Scsi_Host_Template *);
+static int scsi_debug_release(struct Scsi_Host *);
 /* static int scsi_debug_command(Scsi_Cmnd *); */
 static int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-static int scsi_debug_abort(Scsi_Cmnd *);
+static int scsi_debug_ioctl(Scsi_Device *, int, void *);
 static int scsi_debug_biosparam(Disk *, kdev_t, int[]);
+static int scsi_debug_abort(Scsi_Cmnd *);
 static int scsi_debug_bus_reset(Scsi_Cmnd *);
 static int scsi_debug_device_reset(Scsi_Cmnd *);
 static int scsi_debug_host_reset(Scsi_Cmnd *);
 static int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
 static const char * scsi_debug_info(struct Scsi_Host *);
 
-#ifndef NULL
-#define NULL 0
-#endif
-
 /*
  * This driver is written for the lk 2.4 series
  */
-#define SCSI_DEBUG_CANQUEUE  255
+#define SCSI_DEBUG_CANQUEUE  255 	/* needs to be >= 1 */
 
 #define SCSI_DEBUG_MAX_CMD_LEN 16
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/scsi_error.c linux-2.4.20/drivers/scsi/scsi_error.c
--- linux-2.4.19/drivers/scsi/scsi_error.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/scsi_error.c	2002-10-29 11:18:31.000000000 +0000
@@ -1884,7 +1884,7 @@
 	/*
 	 * Wake up the thread that created us.
 	 */
-	SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent %d\n", host->eh_notify->count.counter));
+	SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent %d\n", sem_getcount(host->eh_notify)));
 
 	up(host->eh_notify);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/scsi_lib.c linux-2.4.20/drivers/scsi/scsi_lib.c
--- linux-2.4.19/drivers/scsi/scsi_lib.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/scsi_lib.c	2002-10-29 11:18:47.000000000 +0000
@@ -360,9 +360,10 @@
 				     int requeue,
 				     int frequeue)
 {
+	request_queue_t *q = &SCpnt->device->request_queue;
 	struct request *req;
 	struct buffer_head *bh;
-        Scsi_Device * SDpnt;
+	unsigned long flags;
 	int nsect;
 
 	ASSERT_LOCK(&io_request_lock, 0);
@@ -388,6 +389,7 @@
 				req->nr_sectors -= nsect;
 
 				req->current_nr_sectors = bh->b_size >> 9;
+				req->hard_cur_sectors = req->current_nr_sectors;
 				if (req->nr_sectors < req->current_nr_sectors) {
 					req->nr_sectors = req->current_nr_sectors;
 					printk("scsi_end_request: buffer-list destroyed\n");
@@ -401,35 +403,29 @@
 	 * to queue the remainder of them.
 	 */
 	if (req->bh) {
-                request_queue_t *q;
-
-		if( !requeue )
-		{
-			return SCpnt;
-		}
-
-                q = &SCpnt->device->request_queue;
-
-		req->buffer = bh->b_data;
 		/*
 		 * Bleah.  Leftovers again.  Stick the leftovers in
 		 * the front of the queue, and goose the queue again.
 		 */
-		scsi_queue_next_request(q, SCpnt);
+		if (requeue)
+			scsi_queue_next_request(q, SCpnt);
+
 		return SCpnt;
 	}
+
 	/*
 	 * This request is done.  If there is someone blocked waiting for this
 	 * request, wake them up.  Typically used to wake up processes trying
 	 * to swap a page into memory.
 	 */
-	if (req->waiting != NULL) {
+	if (req->waiting)
 		complete(req->waiting);
-	}
+
+	spin_lock_irqsave(&io_request_lock, flags);
 	req_finished_io(req);
-	add_blkdev_randomness(MAJOR(req->rq_dev));
+	spin_unlock_irqrestore(&io_request_lock, flags);
 
-        SDpnt = SCpnt->device;
+	add_blkdev_randomness(MAJOR(req->rq_dev));
 
 	/*
 	 * This will goose the queue request function at the end, so we don't
@@ -437,12 +433,9 @@
 	 */
 	__scsi_release_command(SCpnt);
 
-	if( frequeue ) {
-		request_queue_t *q;
+	if (frequeue)
+		scsi_queue_next_request(q, NULL);
 
-		q = &SDpnt->request_queue;
-		scsi_queue_next_request(q, NULL);                
-	}
 	return NULL;
 }
 
@@ -549,6 +542,7 @@
 	int result = SCpnt->result;
 	int this_count = SCpnt->bufflen >> 9;
 	request_queue_t *q = &SCpnt->device->request_queue;
+	struct request *req = &SCpnt->request;
 
 	/*
 	 * We must do one of several things here:
@@ -581,7 +575,7 @@
 		if (bbpnt) {
 			for (i = 0; i < SCpnt->use_sg; i++) {
 				if (bbpnt[i]) {
-					if (SCpnt->request.cmd == READ) {
+					if (req->cmd == READ) {
 						memcpy(bbpnt[i],
 						       sgpnt[i].address,
 						       sgpnt[i].length);
@@ -592,11 +586,11 @@
 		}
 		scsi_free(SCpnt->buffer, SCpnt->sglist_len);
 	} else {
-		if (SCpnt->buffer != SCpnt->request.buffer) {
-			if (SCpnt->request.cmd == READ) {
-				memcpy(SCpnt->request.buffer, SCpnt->buffer,
-				       SCpnt->bufflen);
-			}
+		if (SCpnt->buffer != req->buffer) {
+			if (PageHighMem(req->bh->b_page))
+				BUG();
+			if (req->cmd == READ)
+				memcpy(req->buffer, SCpnt->buffer, SCpnt->bufflen);
 			scsi_free(SCpnt->buffer, SCpnt->bufflen);
 		}
 	}
@@ -620,7 +614,7 @@
 					      good_sectors));
 		SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n ", SCpnt->use_sg));
 
-		SCpnt->request.errors = 0;
+		req->errors = 0;
 		/*
 		 * If multiple sectors are requested in one buffer, then
 		 * they will have been finished off by the first command.
@@ -702,7 +696,7 @@
 
 		switch (SCpnt->sense_buffer[2]) {
 		case ILLEGAL_REQUEST:
-			if (SCpnt->device->ten) {
+			if (SCpnt->device->ten && SCSI_RETRY_10(SCpnt->cmnd[0])) {
 				SCpnt->device->ten = 0;
 				/*
 				 * This will cause a retry with a 6-byte
@@ -1049,17 +1043,25 @@
 			 * get those allocated here.  
 			 */
 			if (!SDpnt->scsi_init_io_fn(SCpnt)) {
-				SCpnt = __scsi_end_request(SCpnt, 0, 
-							   SCpnt->request.nr_sectors, 0, 0);
-				if( SCpnt != NULL )
-				{
-					panic("Should not have leftover blocks\n");
-				}
+				/*
+				 * probably we ran out of sgtable memory, or
+				 * __init_io() wanted to revert to a single
+				 * segment request. this would require bouncing
+				 * on highmem i/o, so mark the device as
+				 * starved and continue later instead
+				 */
 				spin_lock_irq(&io_request_lock);
 				SHpnt->host_busy--;
 				SDpnt->device_busy--;
-				continue;
+				if (SDpnt->device_busy == 0) {
+					SDpnt->starved = 1;
+					SHpnt->some_device_starved = 1;
+				}
+				SCpnt->request.special = SCpnt;
+				list_add(&SCpnt->request.queue, &q->queue_head);
+				break;
 			}
+
 			/*
 			 * Initialize the actual SCSI command for this request.
 			 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/scsi_merge.c linux-2.4.20/drivers/scsi/scsi_merge.c
--- linux-2.4.19/drivers/scsi/scsi_merge.c	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.20/drivers/scsi/scsi_merge.c	2002-10-29 11:18:38.000000000 +0000
@@ -6,6 +6,7 @@
  *                        Based upon conversations with large numbers
  *                        of people at Linux Expo.
  *	Support for dynamic DMA mapping: Jakub Jelinek (jakub@redhat.com).
+ *	Support for highmem I/O: Jens Axboe <axboe@suse.de>
  */
 
 /*
@@ -48,7 +49,6 @@
 #include <linux/delay.h>
 #include <linux/smp_lock.h>
 
-
 #define __KERNEL_SYSCALLS__
 
 #include <linux/unistd.h>
@@ -64,6 +64,12 @@
 #include <scsi/scsi_ioctl.h>
 
 /*
+ * scsi_malloc() can only dish out items of PAGE_SIZE or less, so we cannot
+ * build a request that requires an sg table allocation of more than that.
+ */
+static const int scsi_max_sg = PAGE_SIZE / sizeof(struct scatterlist);
+
+/*
  * This means that bounce buffers cannot be allocated in chunks > PAGE_SIZE.
  * Ultimately we should get away from using a dedicated DMA bounce buffer
  * pool, and we should instead try and use kmalloc() instead.  If we can
@@ -95,7 +101,7 @@
 		printk("Segment 0x%p, blocks %d, addr 0x%lx\n",
 		       bh,
 		       bh->b_size >> 9,
-		       virt_to_phys(bh->b_data - 1));
+		       bh_phys(bh) - 1);
 	}
 	panic("Ththththaats all folks.  Too dangerous to continue.\n");
 }
@@ -216,11 +222,10 @@
 			 * DMA capable host, make sure that a segment doesn't span
 			 * the DMA threshold boundary.  
 			 */
-			if (dma_host &&
-			    virt_to_phys(bhnext->b_data) - 1 == ISA_DMA_THRESHOLD) {
+			if (dma_host && bh_phys(bhnext) - 1 == ISA_DMA_THRESHOLD) {
 				ret++;
 				reqsize = bhnext->b_size;
-			} else if (CONTIGUOUS_BUFFERS(bh, bhnext)) {
+			} else if (blk_seg_merge_ok(bh, bhnext)) {
 				/*
 				 * This one is OK.  Let it go.
 				 */ 
@@ -234,8 +239,7 @@
 				 * kind of screwed and we need to start
 				 * another segment.
 				 */
-				if( dma_host
-				    && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD
+				if( dma_host && bh_phys(bh) - 1 >= ISA_DMA_THRESHOLD
 				    && reqsize + bhnext->b_size > PAGE_SIZE )
 				{
 					ret++;
@@ -297,7 +301,7 @@
 }
 
 #define MERGEABLE_BUFFERS(X,Y) \
-(((((long)(X)->b_data+(X)->b_size)|((long)(Y)->b_data)) & \
+(((((long)bh_phys((X))+(X)->b_size)|((long)bh_phys((Y)))) & \
   (DMA_CHUNK_SIZE - 1)) == 0)
 
 #ifdef DMA_CHUNK_SIZE
@@ -399,11 +403,11 @@
 {
 	unsigned int count;
 	unsigned int segment_size = 0;
-	Scsi_Device *SDpnt;
-	struct Scsi_Host *SHpnt;
+	Scsi_Device *SDpnt = q->queuedata;
+	struct Scsi_Host *SHpnt = SDpnt->host;
 
-	SDpnt = (Scsi_Device *) q->queuedata;
-	SHpnt = SDpnt->host;
+	if (max_segments > scsi_max_sg)
+		max_segments = scsi_max_sg;
 
 #ifdef DMA_CHUNK_SIZE
 	if (max_segments > 64)
@@ -413,6 +417,9 @@
 	if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors)
 		return 0;
 
+	if (!BH_PHYS_4G(req->bhtail, bh))
+		return 0;
+
 	if (use_clustering) {
 		/* 
 		 * See if we can do this without creating another
@@ -420,14 +427,11 @@
 		 * DMA capable host, make sure that a segment doesn't span
 		 * the DMA threshold boundary.  
 		 */
-		if (dma_host &&
-		    virt_to_phys(req->bhtail->b_data) - 1 == ISA_DMA_THRESHOLD) {
+		if (dma_host && bh_phys(req->bhtail) - 1 == ISA_DMA_THRESHOLD)
 			goto new_end_segment;
-		}
-		if (CONTIGUOUS_BUFFERS(req->bhtail, bh)) {
+		if (BH_CONTIG(req->bhtail, bh)) {
 #ifdef DMA_SEGMENT_SIZE_LIMITED
-			if( dma_host
-			    && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) {
+			if (dma_host && bh_phys(bh) - 1 >= ISA_DMA_THRESHOLD) {
 				segment_size = 0;
 				count = __count_segments(req, use_clustering, dma_host, &segment_size);
 				if( segment_size + bh->b_size > PAGE_SIZE ) {
@@ -458,11 +462,11 @@
 {
 	unsigned int count;
 	unsigned int segment_size = 0;
-	Scsi_Device *SDpnt;
-	struct Scsi_Host *SHpnt;
+	Scsi_Device *SDpnt = q->queuedata;
+	struct Scsi_Host *SHpnt = SDpnt->host;
 
-	SDpnt = (Scsi_Device *) q->queuedata;
-	SHpnt = SDpnt->host;
+	if (max_segments > scsi_max_sg)
+		max_segments = scsi_max_sg;
 
 #ifdef DMA_CHUNK_SIZE
 	if (max_segments > 64)
@@ -472,6 +476,9 @@
 	if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors)
 		return 0;
 
+	if (!BH_PHYS_4G(bh, req->bh))
+		return 0;
+
 	if (use_clustering) {
 		/* 
 		 * See if we can do this without creating another
@@ -479,14 +486,12 @@
 		 * DMA capable host, make sure that a segment doesn't span
 		 * the DMA threshold boundary. 
 		 */
-		if (dma_host &&
-		    virt_to_phys(bh->b_data) - 1 == ISA_DMA_THRESHOLD) {
+		if (dma_host && bh_phys(bh) - 1 == ISA_DMA_THRESHOLD) {
 			goto new_start_segment;
 		}
-		if (CONTIGUOUS_BUFFERS(bh, req->bh)) {
+		if (BH_CONTIG(bh, req->bh)) {
 #ifdef DMA_SEGMENT_SIZE_LIMITED
-			if( dma_host
-			    && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) {
+			if (dma_host && bh_phys(bh) - 1 >= ISA_DMA_THRESHOLD) {
 				segment_size = bh->b_size;
 				count = __count_segments(req, use_clustering, dma_host, &segment_size);
 				if( count != req->nr_segments ) {
@@ -593,8 +598,8 @@
 					     int use_clustering,
 					     int dma_host)
 {
-	Scsi_Device *SDpnt;
-	struct Scsi_Host *SHpnt;
+	Scsi_Device *SDpnt = q->queuedata;
+	struct Scsi_Host *SHpnt = SDpnt->host;
 
 	/*
 	 * First check if the either of the requests are re-queued
@@ -603,8 +608,8 @@
 	if (req->special || next->special)
 		return 0;
 
-	SDpnt = (Scsi_Device *) q->queuedata;
-	SHpnt = SDpnt->host;
+	if (max_segments > scsi_max_sg)
+		max_segments = scsi_max_sg;
 
 #ifdef DMA_CHUNK_SIZE
 	if (max_segments > 64)
@@ -634,6 +639,9 @@
 	if ((req->nr_sectors + next->nr_sectors) > SHpnt->max_sectors)
 		return 0;
 
+	if (!BH_PHYS_4G(req->bhtail, next->bh))
+		return 0;
+
 	/*
 	 * The main question is whether the two segments at the boundaries
 	 * would be considered one or two.
@@ -645,18 +653,15 @@
 		 * DMA capable host, make sure that a segment doesn't span
 		 * the DMA threshold boundary.  
 		 */
-		if (dma_host &&
-		    virt_to_phys(req->bhtail->b_data) - 1 == ISA_DMA_THRESHOLD) {
+		if (dma_host && bh_phys(req->bhtail) - 1 == ISA_DMA_THRESHOLD)
 			goto dont_combine;
-		}
 #ifdef DMA_SEGMENT_SIZE_LIMITED
 		/*
 		 * We currently can only allocate scatter-gather bounce
 		 * buffers in chunks of PAGE_SIZE or less.
 		 */
-		if (dma_host
-		    && CONTIGUOUS_BUFFERS(req->bhtail, next->bh)
-		    && virt_to_phys(req->bhtail->b_data) - 1 >= ISA_DMA_THRESHOLD )
+		if (dma_host && BH_CONTIG(req->bhtail, next->bh)
+		    && bh_phys(req->bhtail) - 1 >= ISA_DMA_THRESHOLD)
 		{
 			int segment_size = 0;
 			int count = 0;
@@ -668,7 +673,7 @@
 			}
 		}
 #endif
-		if (CONTIGUOUS_BUFFERS(req->bhtail, next->bh)) {
+		if (BH_CONTIG(req->bhtail, next->bh)) {
 			/*
 			 * This one is OK.  Let it go.
 			 */
@@ -796,37 +801,13 @@
 	char		   * buff;
 	int		     count;
 	int		     i;
-	struct request     * req;
+	struct request     * req = &SCpnt->request;
 	int		     sectors;
 	struct scatterlist * sgpnt;
 	int		     this_count;
 	void		   ** bbpnt;
 
 	/*
-	 * FIXME(eric) - don't inline this - it doesn't depend on the
-	 * integer flags.   Come to think of it, I don't think this is even
-	 * needed any more.  Need to play with it and see if we hit the
-	 * panic.  If not, then don't bother.
-	 */
-	if (!SCpnt->request.bh) {
-		/* 
-		 * Case of page request (i.e. raw device), or unlinked buffer 
-		 * Typically used for swapping, but this isn't how we do
-		 * swapping any more.
-		 */
-		panic("I believe this is dead code.  If we hit this, I was wrong");
-#if 0
-		SCpnt->request_bufflen = SCpnt->request.nr_sectors << 9;
-		SCpnt->request_buffer = SCpnt->request.buffer;
-		SCpnt->use_sg = 0;
-		/*
-		 * FIXME(eric) - need to handle DMA here.
-		 */
-#endif
-		return 1;
-	}
-	req = &SCpnt->request;
-	/*
 	 * First we need to know how many scatter gather segments are needed.
 	 */
 	if (!sg_count_valid) {
@@ -841,21 +822,27 @@
 	 * buffer.
 	 */
 	if (dma_host && scsi_dma_free_sectors <= 10) {
-		this_count = SCpnt->request.current_nr_sectors;
+		this_count = req->current_nr_sectors;
 		goto single_segment;
 	}
 	/*
-	 * Don't bother with scatter-gather if there is only one segment.
-	 */
-	if (count == 1) {
-		this_count = SCpnt->request.nr_sectors;
+	 * we really want to use sg even for a single segment request,
+	 * however some people just cannot be bothered to write decent
+	 * driver code so we can't risk to break somebody making the
+	 * assumption that sg requests will always contain at least 2
+	 * segments. if the driver is 32-bit dma safe, then use sg for
+	 * 1 entry anyways. if not, don't rely on the driver handling this
+	 * case.
+ 	 */
+	if (count == 1 && !SCpnt->host->highmem_io) {
+		this_count = req->current_nr_sectors;
 		goto single_segment;
 	}
-	SCpnt->use_sg = count;
 
-	/* 
-	 * Allocate the actual scatter-gather table itself.
+	/*
+	 * for sane drivers, use sg even for 1 entry request
 	 */
+	SCpnt->use_sg = count;
 	SCpnt->sglist_len = (SCpnt->use_sg * sizeof(struct scatterlist));
 
 	/* If we could potentially require ISA bounce buffers, allocate
@@ -875,15 +862,25 @@
 	 * Now fill the scatter-gather table.
 	 */
 	if (!sgpnt) {
+#if 0
 		/*
 		 * If we cannot allocate the scatter-gather table, then
 		 * simply write the first buffer all by itself.
 		 */
 		printk("Warning - running *really* short on DMA buffers\n");
-		this_count = SCpnt->request.current_nr_sectors;
+		this_count = req->current_nr_sectors;
 		goto single_segment;
+#else
+		/*
+		 * it's probably better to simply always back off a little,
+		 * and let some memory be returned to dma pool instead of
+		 * always falling back to (slow) single segments
+		 */
+		return 0;
+#endif
 	}
-	/* 
+
+	/*
 	 * Next, walk the list, and fill in the addresses and sizes of
 	 * each segment.
 	 */
@@ -900,13 +897,11 @@
 
 	SCpnt->bounce_buffers = bbpnt;
 
-	for (count = 0, bh = SCpnt->request.bh;
-	     bh; bh = bh->b_reqnext) {
+	for (count = 0, bh = req->bh; bh; bh = bh->b_reqnext) {
 		if (use_clustering && bhprev != NULL) {
-			if (dma_host &&
-			    virt_to_phys(bhprev->b_data) - 1 == ISA_DMA_THRESHOLD) {
+			if (dma_host && bh_phys(bhprev) - 1 == ISA_DMA_THRESHOLD) {
 				/* Nothing - fall through */
-			} else if (CONTIGUOUS_BUFFERS(bhprev, bh)) {
+			} else if (blk_seg_merge_ok(bhprev, bh)) {
 				/*
 				 * This one is OK.  Let it go.  Note that we
 				 * do not have the ability to allocate
@@ -915,7 +910,7 @@
 				 */
 				if( dma_host ) {
 #ifdef DMA_SEGMENT_SIZE_LIMITED
-					if( virt_to_phys(bh->b_data) - 1 < ISA_DMA_THRESHOLD
+					if (bh_phys(bh) - 1 < ISA_DMA_THRESHOLD
 					    || sgpnt[count - 1].length + bh->b_size <= PAGE_SIZE ) {
 						sgpnt[count - 1].length += bh->b_size;
 						bhprev = bh;
@@ -934,13 +929,25 @@
 				}
 			}
 		}
-		count++;
-		sgpnt[count - 1].address = bh->b_data;
-		sgpnt[count - 1].page = NULL;
-		sgpnt[count - 1].length += bh->b_size;
-		if (!dma_host) {
-			SCpnt->request_bufflen += bh->b_size;
+
+		if (SCpnt->host->highmem_io) {
+			sgpnt[count].page = bh->b_page;
+			sgpnt[count].offset = bh_offset(bh);
+			sgpnt[count].address = NULL;
+		} else {
+			if (PageHighMem(bh->b_page))
+				BUG();
+
+			sgpnt[count].page = NULL;
+			sgpnt[count].address = bh->b_data;
 		}
+		
+		sgpnt[count].length = bh->b_size;
+
+		if (!dma_host)
+			SCpnt->request_bufflen += bh->b_size;
+
+		count++;
 		bhprev = bh;
 	}
 
@@ -963,6 +970,10 @@
 	for (i = 0; i < count; i++) {
 		sectors = (sgpnt[i].length >> 9);
 		SCpnt->request_bufflen += sgpnt[i].length;
+		/*
+		 * only done for dma_host, in which case .page is not
+		 * set since it's guarenteed to be a low memory page
+		 */
 		if (virt_to_phys(sgpnt[i].address) + sgpnt[i].length - 1 >
 		    ISA_DMA_THRESHOLD) {
 			if( scsi_dma_free_sectors - sectors <= 10  ) {
@@ -998,7 +1009,7 @@
 				}
 				break;
 			}
-			if (SCpnt->request.cmd == WRITE) {
+			if (req->cmd == WRITE) {
 				memcpy(sgpnt[i].address, bbpnt[i],
 				       sgpnt[i].length);
 			}
@@ -1043,8 +1054,7 @@
 	 * single-block requests if we had hundreds of free sectors.
 	 */
 	if( scsi_dma_free_sectors > 30 ) {
-		for (this_count = 0, bh = SCpnt->request.bh;
-		     bh; bh = bh->b_reqnext) {
+		for (this_count = 0, bh = req->bh; bh; bh = bh->b_reqnext) {
 			if( scsi_dma_free_sectors - this_count < 30 
 			    || this_count == sectors )
 			{
@@ -1057,21 +1067,32 @@
 		/*
 		 * Yow!   Take the absolute minimum here.
 		 */
-		this_count = SCpnt->request.current_nr_sectors;
+		this_count = req->current_nr_sectors;
 	}
 
 	/*
 	 * Now drop through into the single-segment case.
 	 */
 	
-      single_segment:
+single_segment:
+	/*
+	 * for highmem cases, we have to revert to bouncing for single
+	 * segments. rather just give up now and let the device starvation
+	 * path reinitiate this i/o later
+	 */
+	if (SCpnt->host->highmem_io)
+		return 0;
+
 	/*
 	 * Come here if for any reason we choose to do this as a single
 	 * segment.  Possibly the entire request, or possibly a small
 	 * chunk of the entire request.
 	 */
-	bh = SCpnt->request.bh;
-	buff = SCpnt->request.buffer;
+	bh = req->bh;
+	buff = req->buffer = bh->b_data;
+
+	if (PageHighMem(bh->b_page))
+		BUG();
 
 	if (dma_host) {
 		/*
@@ -1079,21 +1100,21 @@
 		 * back and allocate a really small one - enough to satisfy
 		 * the first buffer.
 		 */
-		if (virt_to_phys(SCpnt->request.bh->b_data)
-		    + (this_count << 9) - 1 > ISA_DMA_THRESHOLD) {
+		if (bh_phys(bh) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD) {
 			buff = (char *) scsi_malloc(this_count << 9);
 			if (!buff) {
 				printk("Warning - running low on DMA memory\n");
-				this_count = SCpnt->request.current_nr_sectors;
+				this_count = req->current_nr_sectors;
 				buff = (char *) scsi_malloc(this_count << 9);
 				if (!buff) {
 					dma_exhausted(SCpnt, 0);
 				}
 			}
-			if (SCpnt->request.cmd == WRITE)
-				memcpy(buff, (char *) SCpnt->request.buffer, this_count << 9);
+			if (req->cmd == WRITE)
+				memcpy(buff, (char *) req->buffer, this_count << 9);
 		}
 	}
+
 	SCpnt->request_bufflen = this_count << 9;
 	SCpnt->request_buffer = buff;
 	SCpnt->use_sg = 0;
@@ -1132,21 +1153,11 @@
  */
 void initialize_merge_fn(Scsi_Device * SDpnt)
 {
-	request_queue_t *q;
-	struct Scsi_Host *SHpnt;
-	SHpnt = SDpnt->host;
-
-	q = &SDpnt->request_queue;
+	struct Scsi_Host *SHpnt = SDpnt->host;
+	request_queue_t *q = &SDpnt->request_queue;
+	dma64_addr_t bounce_limit;
 
 	/*
-	 * If the host has already selected a merge manager, then don't
-	 * pick a new one.
-	 */
-#if 0
-	if (q->back_merge_fn && q->front_merge_fn)
-		return;
-#endif
-	/*
 	 * If this host has an unlimited tablesize, then don't bother with a
 	 * merge manager.  The whole point of the operation is to make sure
 	 * that requests don't grow too large, and this host isn't picky.
@@ -1178,4 +1189,20 @@
 		q->merge_requests_fn = scsi_merge_requests_fn_dc;
 		SDpnt->scsi_init_io_fn = scsi_init_io_vdc;
 	}
+
+	/*
+	 * now enable highmem I/O, if appropriate
+	 */
+	bounce_limit = BLK_BOUNCE_HIGH;
+	if (SHpnt->highmem_io && (SDpnt->type == TYPE_DISK)) {
+		if (!PCI_DMA_BUS_IS_PHYS)
+			/* Platforms with virtual-DMA translation
+ 			 * hardware have no practical limit.
+			 */
+			bounce_limit = BLK_BOUNCE_ANY;
+		else
+			bounce_limit = SHpnt->pci_dev->dma_mask;
+	}
+
+	blk_queue_bounce_limit(q, bounce_limit);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/scsi_scan.c linux-2.4.20/drivers/scsi/scsi_scan.c
--- linux-2.4.19/drivers/scsi/scsi_scan.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/scsi_scan.c	2002-10-29 11:18:35.000000000 +0000
@@ -113,7 +113,6 @@
 	{"HP", "A6188A", "*", BLIST_SPARSELUN},			/* HP Va7100 Array */
 	{"HP", "A6189A", "*", BLIST_SPARSELUN},			/* HP Va7400 Array */
 	{"HP", "A6189B", "*", BLIST_SPARSELUN},			/* HP Va7410 Array */
-	{"HP", "OPEN-", "*", BLIST_SPARSELUN},			/* HP XP Arrays */
 	{"YAMAHA", "CDR100", "1.00", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
 	{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},		/* Locks up if polled for lun != 0  
 								 * extra reset */
@@ -163,6 +162,7 @@
 	{"DELL", "PV530F",    "*", BLIST_SPARSELUN | BLIST_LARGELUN}, // Dell PV 530F
 	{"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
 	{"HP", "A6189A", "*", BLIST_SPARSELUN |  BLIST_LARGELUN}, // HP VA7400, by Alar Aun
+	{"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},			/* HP XP Arrays */
 	{"CMD", "CRA-7280", "*", BLIST_SPARSELUN | BLIST_LARGELUN},   // CMD RAID Controller
 	{"CNSI", "G7324", "*", BLIST_SPARSELUN | BLIST_LARGELUN},     // Chaparral G7324 RAID
 	{"CNSi", "G8324", "*", BLIST_SPARSELUN},     // Chaparral G8324 RAID
@@ -181,6 +181,7 @@
 	{"HITACHI", "DF400", "*", BLIST_SPARSELUN},
 	{"HITACHI", "DF500", "*", BLIST_SPARSELUN},
 	{"HITACHI", "DF600", "*", BLIST_SPARSELUN},
+	{"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
 
 	/*
 	 * Must be at end of list...
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/seagate.c linux-2.4.20/drivers/scsi/seagate.c
--- linux-2.4.19/drivers/scsi/seagate.c	2001-09-30 19:26:07.000000000 +0000
+++ linux-2.4.20/drivers/scsi/seagate.c	2002-10-29 11:18:40.000000000 +0000
@@ -21,7 +21,7 @@
  * linux 2.1.112, simplified some #defines etc. <pavel@ucw.cz>
  *
  * Aug 2000 - aeb - deleted seagate_st0x_biosparam(). It would try to
- * read the physical disk geometry, a bad mistake. Of course it doesnt
+ * read the physical disk geometry, a bad mistake. Of course it doesn't
  * matter much what geometry one invents, but on large disks it
  * returned 256 (or more) heads, causing all kind of failures.
  * Of course this means that people might see a different geometry now,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/sr.c linux-2.4.20/drivers/scsi/sr.c
--- linux-2.4.19/drivers/scsi/sr.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/sr.c	2002-10-29 11:18:35.000000000 +0000
@@ -347,7 +347,8 @@
 	}
 	if (old_sg) {
 		memcpy(sg + i, old_sg, SCpnt->use_sg * sizeof(struct scatterlist));
-		memcpy(bbpnt + i, old_bbpnt, SCpnt->use_sg * sizeof(void *));
+		if (old_bbpnt)
+			memcpy(bbpnt + i, old_bbpnt, SCpnt->use_sg * sizeof(void *));
 		scsi_free(old_sg, (((SCpnt->use_sg * sizeof(struct scatterlist)) +
 				    (SCpnt->use_sg * sizeof(void *))) + 511) & ~511);
 	} else {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/sr_ioctl.c linux-2.4.20/drivers/scsi/sr_ioctl.c
--- linux-2.4.19/drivers/scsi/sr_ioctl.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/sr_ioctl.c	2002-10-29 11:18:49.000000000 +0000
@@ -158,13 +158,11 @@
 			if (!quiet)
 				printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL "
 				       "REQUEST.\n", target);
+			err = -EIO;
 			if (SRpnt->sr_sense_buffer[12] == 0x20 &&
-			    SRpnt->sr_sense_buffer[13] == 0x00) {
+			    SRpnt->sr_sense_buffer[13] == 0x00)
 				/* sense: Invalid command operation code */
 				err = -EDRIVE_CANT_DO_THIS;
-			} else {
-				err = -EINVAL;
-			}
 #ifdef DEBUG
 			print_command(sr_cmd);
 			print_req_sense("sr", SRpnt);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/st.c linux-2.4.20/drivers/scsi/st.c
--- linux-2.4.19/drivers/scsi/st.c	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.20/drivers/scsi/st.c	2002-10-29 11:18:48.000000000 +0000
@@ -12,7 +12,7 @@
    Copyright 1992 - 2002 Kai Makisara
    email Kai.Makisara@metla.fi
 
-   Last modified: Tue Feb  5 21:25:55 2002 by makisara
+   Last modified: Mon Aug  5 22:54:13 2002 by makisara
    Some small formal changes - aeb, 950809
 
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
@@ -21,7 +21,7 @@
    error handling will be discarded.
  */
 
-static char *verstr = "20020205";
+static char *verstr = "20020805";
 
 #include <linux/module.h>
 
@@ -75,6 +75,8 @@
 static int write_threshold_kbs;
 static int max_buffers = (-1);
 static int max_sg_segs;
+static int blocking_open = ST_BLOCKING_OPEN;
+
 
 MODULE_AUTHOR("Kai Makisara");
 MODULE_DESCRIPTION("SCSI Tape Driver");
@@ -88,6 +90,8 @@
 MODULE_PARM_DESC(max_buffers, "Maximum number of buffer allocated at initialisation (4)");
 MODULE_PARM(max_sg_segs, "i");
 MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (32)");
+MODULE_PARM(blocking_open, "i");
+MODULE_PARM_DESC(blocking_open, "Block in open if not ready an no O_NONBLOCK (0)");
 
 EXPORT_NO_SYMBOLS;
 
@@ -107,6 +111,9 @@
 	},
 	{
 		"max_sg_segs", &max_sg_segs
+	},
+	{
+		"blocking_open", &blocking_open
 	}
 };
 #endif
@@ -157,6 +164,7 @@
 static ST_buffer *new_tape_buffer(int, int, int);
 static int enlarge_buffer(ST_buffer *, int, int);
 static void normalize_buffer(ST_buffer *);
+static int set_sg_lengths(ST_buffer *, unsigned int);
 static int append_to_buffer(const char *, ST_buffer *, int);
 static int from_buffer(ST_buffer *, char *, int);
 
@@ -239,7 +247,7 @@
 		return 0;
 	}
 
-	if (driver_byte(result) & DRIVER_SENSE)
+	if ((driver_byte(result) & DRIVER_SENSE) == DRIVER_SENSE)
 		scode = sense[2] & 0x0f;
 	else {
 		sense[0] = 0;
@@ -378,12 +386,11 @@
 	if (SRpnt->sr_device->scsi_level <= SCSI_2)
 		cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0;
 	init_completion(&STp->wait);
-	SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ?
+	SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg_lengths[0]) ?
 	    (STp->buffer)->use_sg : 0;
 	if (SRpnt->sr_use_sg) {
 		bp = (char *) &((STp->buffer)->sg[0]);
-		if ((STp->buffer)->sg_segs < SRpnt->sr_use_sg)
-			SRpnt->sr_use_sg = (STp->buffer)->sg_segs;
+		SRpnt->sr_use_sg = set_sg_lengths(STp->buffer, bytes);
 	} else
 		bp = (STp->buffer)->b_data;
 	SRpnt->sr_data_direction = direction;
@@ -638,20 +645,97 @@
 	return 0;
 }
 
+/* Test if the drive is ready. Returns either one of the codes below or a negative system
+   error code. */
+#define CHKRES_READY       0
+#define CHKRES_NEW_SESSION 1
+#define CHKRES_NOT_READY   2
+#define CHKRES_NO_TAPE     3
+
+#define MAX_ATTENTIONS    10
+
+static int test_ready(Scsi_Tape *STp, int do_wait)
+{
+	int attentions, waits, max_wait, scode;
+	int retval = CHKRES_READY, new_session = FALSE;
+	unsigned char cmd[MAX_COMMAND_SIZE];
+	Scsi_Request *SRpnt = NULL;
+
+	max_wait = do_wait ? ST_BLOCK_SECONDS : 0;
+
+	for (attentions=waits=0; ; ) {
+		memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
+		cmd[0] = TEST_UNIT_READY;
+		SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
+				   STp->long_timeout, MAX_READY_RETRIES, TRUE);
+
+		if (!SRpnt) {
+			retval = (STp->buffer)->syscall_result;
+			break;
+		}
+
+		if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) {
+
+			scode = (SRpnt->sr_sense_buffer[2] & 0x0f);
+
+			if (scode == UNIT_ATTENTION) { /* New media? */
+				new_session = TRUE;
+				if (attentions < MAX_ATTENTIONS) {
+					attentions++;
+					continue;
+				}
+				else {
+					retval = (-EIO);
+					break;
+				}
+			}
+
+			if (scode == NOT_READY) {
+				if (waits < max_wait) {
+					set_current_state(TASK_INTERRUPTIBLE);
+					schedule_timeout(HZ);
+					if (signal_pending(current)) {
+						retval = (-EINTR);
+						break;
+					}
+					waits++;
+					continue;
+				}
+				else {
+					if ((STp->device)->scsi_level >= SCSI_2 &&
+					    SRpnt->sr_sense_buffer[12] == 0x3a)	/* Check ASC */
+						retval = CHKRES_NO_TAPE;
+					else
+						retval = CHKRES_NOT_READY;
+					break;
+				}
+			}
+		}
+
+		retval = (STp->buffer)->syscall_result;
+		if (!retval)
+			retval = new_session ? CHKRES_NEW_SESSION : CHKRES_READY;
+		break;
+	}
+
+	if (SRpnt != NULL)
+		scsi_release_request(SRpnt);
+	return retval;
+}
+
+
 /* See if the drive is ready and gather information about the tape. Return values:
    < 0   negative error code from errno.h
    0     drive ready
    1     drive not ready (possibly no tape)
 */
-#define CHKRES_READY      0
-#define CHKRES_NOT_READY  1
 
 static int check_tape(Scsi_Tape *STp, struct file *filp)
 {
-	int i, retval, new_session = FALSE;
+	int i, retval, new_session = FALSE, do_wait;
 	unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning;
 	unsigned short st_flags = filp->f_flags;
-	Scsi_Request *SRpnt;
+	Scsi_Request *SRpnt = NULL;
 	ST_mode *STm;
 	ST_partstat *STps;
 	int dev = TAPE_NR(STp->devt);
@@ -668,32 +752,16 @@
 	}
 	STm = &(STp->modes[STp->current_mode]);
 
-	memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
-	cmd[0] = TEST_UNIT_READY;
-
 	saved_cleaning = STp->cleaning_req;
 	STp->cleaning_req = 0;
-	SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->long_timeout,
-			   MAX_READY_RETRIES, TRUE);
-	if (!SRpnt) {
-		retval = (STp->buffer)->syscall_result;
-		goto err_out;
-	}
 
-	if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
-	    (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
+	do_wait = (blocking_open && (filp->f_flags & O_NONBLOCK) == 0);
+	retval = test_ready(STp, do_wait);
 
-		/* Flush the queued UNIT ATTENTION sense data */
-		for (i=0; i < 10; i++) {
-                        memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
-                        cmd[0] = TEST_UNIT_READY;
-                        SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
-					   STp->long_timeout, MAX_READY_RETRIES, TRUE);
-                        if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
-                            (SRpnt->sr_sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
-                                break;
-		}
+	if (retval < 0)
+		goto err_out;
 
+	if (retval == CHKRES_NEW_SESSION) {
 		(STp->device)->was_reset = 0;
 		STp->partition = STp->new_partition = 0;
 		if (STp->can_partitions)
@@ -710,26 +778,23 @@
 		}
 		new_session = TRUE;
 	}
-	else
+	else {
 		STp->cleaning_req |= saved_cleaning;
 
-	if ((STp->buffer)->syscall_result != 0) {
-		if ((STp->device)->scsi_level >= SCSI_2 &&
-		    (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
-		    (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
-		    SRpnt->sr_sense_buffer[12] == 0x3a) {	/* Check ASC */
-			STp->ready = ST_NO_TAPE;
-		} else
-			STp->ready = ST_NOT_READY;
-		scsi_release_request(SRpnt);
-		SRpnt = NULL;
-		STp->density = 0;	/* Clear the erroneous "residue" */
-		STp->write_prot = 0;
-		STp->block_size = 0;
-		STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
-		STp->partition = STp->new_partition = 0;
-		STp->door_locked = ST_UNLOCKED;
-		return CHKRES_NOT_READY;
+		if (retval == CHKRES_NOT_READY || retval == CHKRES_NO_TAPE) {
+			if (retval == CHKRES_NO_TAPE)
+				STp->ready = ST_NO_TAPE;
+			else
+				STp->ready = ST_NOT_READY;
+
+			STp->density = 0;	/* Clear the erroneous "residue" */
+			STp->write_prot = 0;
+			STp->block_size = 0;
+			STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
+			STp->partition = STp->new_partition = 0;
+			STp->door_locked = ST_UNLOCKED;
+			return CHKRES_NOT_READY;
+		}
 	}
 
 	if (STp->omit_blklims)
@@ -740,6 +805,10 @@
 
 		SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, SCSI_DATA_READ, STp->timeout,
 				   MAX_READY_RETRIES, TRUE);
+		if (!SRpnt) {
+			retval = (STp->buffer)->syscall_result;
+			goto err_out;
+		}
 
 		if (!SRpnt->sr_result && !SRpnt->sr_sense_buffer[0]) {
 			STp->max_block = ((STp->buffer)->b_data[1] << 16) |
@@ -763,6 +832,10 @@
 
 	SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, SCSI_DATA_READ, STp->timeout,
 			   MAX_READY_RETRIES, TRUE);
+	if (!SRpnt) {
+		retval = (STp->buffer)->syscall_result;
+		goto err_out;
+	}
 
 	if ((STp->buffer)->syscall_result != 0) {
                 DEBC(printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev));
@@ -915,11 +988,11 @@
 
 	/* Compute the usable buffer size for this SCSI adapter */
 	if (!(STp->buffer)->use_sg)
-		(STp->buffer)->buffer_size = (STp->buffer)->sg[0].length;
+		(STp->buffer)->buffer_size = (STp->buffer)->sg_lengths[0];
 	else {
 		for (i = 0, (STp->buffer)->buffer_size = 0; i < (STp->buffer)->use_sg &&
 		     i < (STp->buffer)->sg_segs; i++)
-			(STp->buffer)->buffer_size += (STp->buffer)->sg[i].length;
+			(STp->buffer)->buffer_size += (STp->buffer)->sg_lengths[i];
 	}
 
 	STp->write_prot = ((filp->f_flags & O_ACCMODE) == O_RDONLY);
@@ -935,6 +1008,12 @@
 	retval = check_tape(STp, filp);
 	if (retval < 0)
 		goto err_out;
+	if (blocking_open &&
+	    (filp->f_flags & O_NONBLOCK) == 0 &&
+	    retval != CHKRES_READY) {
+		retval = (-EIO);
+		goto err_out;
+	}
 	return 0;
 
  err_out:
@@ -2229,14 +2308,16 @@
 
 	if (!retval) {	/* SCSI command successful */
 
-		if (!load_code)
+		if (!load_code) {
 			STp->rew_at_close = 0;
-		else
+			STp->ready = ST_NO_TAPE;
+		}
+		else {
 			STp->rew_at_close = STp->autorew_dev;
-
-		retval = check_tape(STp, filp);
-		if (retval > 0)
-			retval = 0;
+			retval = check_tape(STp, filp);
+			if (retval > 0)
+				retval = 0;
+		}
 	}
 	else {
 		STps = &(STp->ps[STp->partition]);
@@ -3330,9 +3411,12 @@
 	else
 		priority = GFP_KERNEL;
 
-	i = sizeof(ST_buffer) + (st_max_sg_segs - 1) * sizeof(struct scatterlist);
+	i = sizeof(ST_buffer) + (st_max_sg_segs - 1) * sizeof(struct scatterlist) +
+		st_max_sg_segs * sizeof(unsigned int);
 	tb = kmalloc(i, priority);
 	if (tb) {
+		tb->sg_lengths = (unsigned int *)(&tb->sg[0] + st_max_sg_segs);
+
 		if (need_dma)
 			priority |= GFP_DMA;
 
@@ -3346,7 +3430,7 @@
 			tb->sg[0].address =
 			    (unsigned char *) __get_free_pages(priority, order);
 			if (tb->sg[0].address != NULL) {
-				tb->sg[0].length = b_size;
+				tb->sg_lengths[0] = b_size;
 				break;
 			}
 		}
@@ -3358,10 +3442,10 @@
 
 			for (b_size = PAGE_SIZE, order=0;
 			     st_buffer_size >
-                                     tb->sg[0].length + (ST_FIRST_SG - 1) * b_size;
+                                     tb->sg_lengths[0] + (ST_FIRST_SG - 1) * b_size;
 			     order++, b_size *= 2)
 				;
-			for (segs = 1, got = tb->sg[0].length;
+			for (segs = 1, got = tb->sg_lengths[0];
 			     got < st_buffer_size && segs < ST_FIRST_SG;) {
 				tb->sg[segs].address =
 					(unsigned char *) __get_free_pages(priority,
@@ -3383,7 +3467,7 @@
 					break;
 				}
 				tb->sg[segs].page = NULL;
-				tb->sg[segs].length = b_size;
+				tb->sg_lengths[segs] = b_size;
 				got += b_size;
 				segs++;
 			}
@@ -3403,7 +3487,7 @@
                     st_nbr_buffers, got, tb->sg_segs, need_dma, tb->b_data);
              printk(ST_DEB_MSG
                     "st: segment sizes: first %d, last %d bytes.\n",
-                    tb->sg[0].length, tb->sg[segs - 1].length);
+                    tb->sg_lengths[0], tb->sg_lengths[segs - 1]);
 	)
 	tb->in_use = in_use;
 	tb->dma = need_dma;
@@ -3457,7 +3541,7 @@
 			return FALSE;
 		}
 		STbuffer->sg[segs].page = NULL;
-		STbuffer->sg[segs].length = b_size;
+		STbuffer->sg_lengths[segs] = b_size;
 		STbuffer->sg_segs += 1;
 		got += b_size;
 		STbuffer->buffer_size = got;
@@ -3477,11 +3561,11 @@
 	int i, order, b_size;
 
 	for (i = STbuffer->orig_sg_segs; i < STbuffer->sg_segs; i++) {
-		for (b_size=PAGE_SIZE, order=0; b_size < STbuffer->sg[i].length;
+		for (b_size=PAGE_SIZE, order=0; b_size < STbuffer->sg_lengths[i];
 		     order++, b_size *= 2)
 			; /* empty */
 		free_pages((unsigned long)(STbuffer->sg[i].address), order);
-		STbuffer->buffer_size -= STbuffer->sg[i].length;
+		STbuffer->buffer_size -= STbuffer->sg_lengths[i];
 	}
         DEB(
 	if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
@@ -3500,15 +3584,15 @@
 	int i, cnt, res, offset;
 
 	for (i = 0, offset = st_bp->buffer_bytes;
-	     i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
-		offset -= st_bp->sg[i].length;
+	     i < st_bp->sg_segs && offset >= st_bp->sg_lengths[i]; i++)
+		offset -= st_bp->sg_lengths[i];
 	if (i == st_bp->sg_segs) {	/* Should never happen */
 		printk(KERN_WARNING "st: append_to_buffer offset overflow.\n");
 		return (-EIO);
 	}
 	for (; i < st_bp->sg_segs && do_count > 0; i++) {
-		cnt = st_bp->sg[i].length - offset < do_count ?
-		    st_bp->sg[i].length - offset : do_count;
+		cnt = st_bp->sg_lengths[i] - offset < do_count ?
+		    st_bp->sg_lengths[i] - offset : do_count;
 		res = copy_from_user(st_bp->sg[i].address + offset, ubp, cnt);
 		if (res)
 			return (-EFAULT);
@@ -3533,15 +3617,15 @@
 	int i, cnt, res, offset;
 
 	for (i = 0, offset = st_bp->read_pointer;
-	     i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
-		offset -= st_bp->sg[i].length;
+	     i < st_bp->sg_segs && offset >= st_bp->sg_lengths[i]; i++)
+		offset -= st_bp->sg_lengths[i];
 	if (i == st_bp->sg_segs) {	/* Should never happen */
 		printk(KERN_WARNING "st: from_buffer offset overflow.\n");
 		return (-EIO);
 	}
 	for (; i < st_bp->sg_segs && do_count > 0; i++) {
-		cnt = st_bp->sg[i].length - offset < do_count ?
-		    st_bp->sg[i].length - offset : do_count;
+		cnt = st_bp->sg_lengths[i] - offset < do_count ?
+		    st_bp->sg_lengths[i] - offset : do_count;
 		res = copy_to_user(ubp, st_bp->sg[i].address + offset, cnt);
 		if (res)
 			return (-EFAULT);
@@ -3560,6 +3644,25 @@
 }
 
 
+/* Set the scatter/gather list length fields to sum up to the transfer length.
+   Return the number of segments being used. */
+static int set_sg_lengths(ST_buffer *st_bp, unsigned int length)
+{
+	int i;
+
+	for (i=0; i < st_bp->sg_segs; i++) {
+		if (length > st_bp->sg_lengths[i])
+			st_bp->sg[i].length = st_bp->sg_lengths[i];
+		else {
+			st_bp->sg[i].length = length;
+			break;
+		}
+		length -= st_bp->sg_lengths[i];
+	}
+	return i + 1;
+}
+
+
 /* Validate the options from command line or module parameters */
 static void validate_options(void)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/st.h linux-2.4.20/drivers/scsi/st.h
--- linux-2.4.19/drivers/scsi/st.h	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.20/drivers/scsi/st.h	2002-10-29 11:18:35.000000000 +0000
@@ -24,6 +24,7 @@
 	unsigned short use_sg;	/* zero or number of segments for this adapter */
 	unsigned short sg_segs;	/* total number of allocated segments */
 	unsigned short orig_sg_segs;	/* number of segments allocated at first try */
+	unsigned int *sg_lengths;
 	struct scatterlist sg[1];	/* MUST BE last item */
 } ST_buffer;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/st_options.h linux-2.4.20/drivers/scsi/st_options.h
--- linux-2.4.19/drivers/scsi/st_options.h	2000-04-24 20:54:22.000000000 +0000
+++ linux-2.4.20/drivers/scsi/st_options.h	2002-10-29 11:18:32.000000000 +0000
@@ -1,9 +1,9 @@
 /*
    The compile-time configurable defaults for the Linux SCSI tape driver.
 
-   Copyright 1995-2000 Kai Makisara.
+   Copyright 1995-2002 Kai Makisara.
 
-   Last modified: Sat Apr 22 14:47:02 2000 by makisara@kai.makisara.local
+   Last modified: Wed May  1 11:06:47 2002 by makisara
 */
 
 #ifndef _ST_OPTIONS_H
@@ -99,5 +99,12 @@
    The default is BSD semantics. */
 #define ST_SYSV 0
 
+/* Open without O_NONBLOCK blocks if the drive is not ready (blocking times out
+   after 2 minutes) */
+#define ST_BLOCKING_OPEN 0
+
+/* Time to wait for the drive to become ready if blocking open */
+#define ST_BLOCK_SECONDS     120
+
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/sun3x_esp.c linux-2.4.20/drivers/scsi/sun3x_esp.c
--- linux-2.4.19/drivers/scsi/sun3x_esp.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/sun3x_esp.c	2002-10-29 11:18:33.000000000 +0000
@@ -46,11 +46,12 @@
 static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp);
 static void dma_advance_sg (Scsi_Cmnd *sp);
 
+#if 0
+/* This is where all commands are put before they are trasfered to the ESP chip
+ * via PIO.
+ */
 static volatile unsigned char cmd_buffer[16];
-                                /* This is where all commands are put
-                                 * before they are trasfered to the ESP chip
-                                 * via PIO.
-                                 */
+#endif
 
 /* Detecting ESP chips on the machine.  This is the simple and easy
  * version.
@@ -354,7 +355,7 @@
 
 static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp)
 {
-    dvma_unmap(sp->SCp.have_data_in);
+    dvma_unmap((char *)sp->SCp.have_data_in);
 }
 
 static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
@@ -363,7 +364,7 @@
     struct mmu_sglist *sg = (struct mmu_sglist *)sp->buffer;
                         
     while(sz >= 0) {
-        dvma_unmap(sg[sz].dvma_addr);
+        dvma_unmap((char *)sg[sz].dvma_addr);
         sz--;
     }
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/sym53c8xx.c linux-2.4.20/drivers/scsi/sym53c8xx.c
--- linux-2.4.19/drivers/scsi/sym53c8xx.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/sym53c8xx.c	2002-10-29 11:18:33.000000000 +0000
@@ -2651,7 +2651,7 @@
 	**	The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS 
 	**	is a critical path. If it is partially executed, it then 
 	**	may happen that the job address is not yet in the DSA 
-	**	and the the next queue position points to the next JOB.
+	**	and the next queue position points to the next JOB.
 	*/
 	SCR_LOAD_ABS (dsa, 4),
 		PADDRH (startpos),
@@ -12880,7 +12880,7 @@
 **    differ and attach them using the order in the NVRAM.
 **
 **    If no NVRAM is found or data appears invalid attach boards in 
-**    the the order they are detected.
+**    the order they are detected.
 **===================================================================
 */
 int __init sym53c8xx_detect(Scsi_Host_Template *tpnt)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/sym53c8xx.h linux-2.4.20/drivers/scsi/sym53c8xx.h
--- linux-2.4.19/drivers/scsi/sym53c8xx.h	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/scsi/sym53c8xx.h	2002-10-29 11:18:39.000000000 +0000
@@ -97,7 +97,8 @@
 			sg_tablesize:   SCSI_NCR_SG_TABLESIZE,	\
 			cmd_per_lun:    SCSI_NCR_CMD_PER_LUN,	\
 			max_sectors:    MAX_SEGMENTS*8,		\
-			use_clustering: DISABLE_CLUSTERING} 
+			use_clustering: DISABLE_CLUSTERING,	\
+			highmem_io:	1}
 
 #else
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/sym53c8xx_2/sym53c8xx.h linux-2.4.20/drivers/scsi/sym53c8xx_2/sym53c8xx.h
--- linux-2.4.19/drivers/scsi/sym53c8xx_2/sym53c8xx.h	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/scsi/sym53c8xx_2/sym53c8xx.h	2002-10-29 11:18:51.000000000 +0000
@@ -119,7 +119,8 @@
 	this_id:		7,					\
 	sg_tablesize:		0,					\
 	cmd_per_lun:		0,					\
-	use_clustering:		DISABLE_CLUSTERING}
+	use_clustering:		DISABLE_CLUSTERING,			\
+	highmem_io:		1}
 
 #endif /* defined(HOSTS_C) || defined(MODULE) */ 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/sym53c8xx_2/sym_fw1.h linux-2.4.20/drivers/scsi/sym53c8xx_2/sym_fw1.h
--- linux-2.4.19/drivers/scsi/sym53c8xx_2/sym_fw1.h	2001-11-09 23:22:54.000000000 +0000
+++ linux-2.4.20/drivers/scsi/sym53c8xx_2/sym_fw1.h	2002-10-29 11:18:34.000000000 +0000
@@ -283,7 +283,7 @@
 	 *  The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS 
 	 *  is a critical path. If it is partially executed, it then 
 	 *  may happen that the job address is not yet in the DSA 
-	 *  and the the next queue position points to the next JOB.
+	 *  and the next queue position points to the next JOB.
 	 */
 }/*-------------------------< GETJOB_BEGIN >---------------------*/,{
 	/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/sym53c8xx_2/sym_fw2.h linux-2.4.20/drivers/scsi/sym53c8xx_2/sym_fw2.h
--- linux-2.4.19/drivers/scsi/sym53c8xx_2/sym_fw2.h	2001-11-09 23:22:54.000000000 +0000
+++ linux-2.4.20/drivers/scsi/sym53c8xx_2/sym_fw2.h	2002-10-29 11:18:36.000000000 +0000
@@ -280,7 +280,7 @@
 	 *  The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS 
 	 *  is a critical path. If it is partially executed, it then 
 	 *  may happen that the job address is not yet in the DSA 
-	 *  and the the next queue position points to the next JOB.
+	 *  and the next queue position points to the next JOB.
 	 */
 	SCR_LOAD_ABS (dsa, 4),
 		PADDR_B (startpos),
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/sym53c8xx_2/sym_glue.c linux-2.4.20/drivers/scsi/sym53c8xx_2/sym_glue.c
--- linux-2.4.19/drivers/scsi/sym53c8xx_2/sym_glue.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/scsi/sym53c8xx_2/sym_glue.c	2002-10-29 11:18:48.000000000 +0000
@@ -125,7 +125,7 @@
  *
  *  The whole SCSI sub-system under Linux is basically single-threaded.
  *  Everything, including low-level driver interrupt routine, happens 
- *  whith the `io_request_lock' held.
+ *  with the `io_request_lock' held.
  *  The sym53c8xx-1.x drivers series ran their interrupt code using a 
  *  spin mutex per controller. This added complexity without improving 
  *  scalability significantly. the sym-2 driver still use a spinlock 
@@ -1890,7 +1890,7 @@
 					sym_name(np));
 		}
 		else {
-			if (!pci_set_dma_mask(np->s.device, 0xffffffffUL))
+			if (pci_set_dma_mask(np->s.device, 0xffffffffUL))
 				goto out_err32;
 		}
 	}
@@ -2140,6 +2140,7 @@
 	instance->max_cmd_len	= 16;
 #endif
 	instance->select_queue_depths = sym53c8xx_select_queue_depths;
+	instance->highmem_io	= 1;
 
 	SYM_UNLOCK_HCB(np, flags);
 
@@ -2714,7 +2715,7 @@
  *  differ and attach them using the order in the NVRAM.
  *
  *  If no NVRAM is found or data appears invalid attach boards in 
- *  the the order they are detected.
+ *  the order they are detected.
  */
 int __init sym53c8xx_detect(Scsi_Host_Template *tpnt)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/sym53c8xx_2/sym_malloc.c linux-2.4.20/drivers/scsi/sym53c8xx_2/sym_malloc.c
--- linux-2.4.19/drivers/scsi/sym53c8xx_2/sym_malloc.c	2001-11-09 23:22:54.000000000 +0000
+++ linux-2.4.20/drivers/scsi/sym53c8xx_2/sym_malloc.c	2002-10-29 11:18:35.000000000 +0000
@@ -143,12 +143,15 @@
 	a = (m_addr_t) ptr;
 
 	while (1) {
-#ifdef SYM_MEM_FREE_UNUSED
 		if (s == SYM_MEM_CLUSTER_SIZE) {
+#ifdef SYM_MEM_FREE_UNUSED
 			M_FREE_MEM_CLUSTER(a);
+#else
+			((m_link_p) a)->next = h[i].next;
+			h[i].next = (m_link_p) a;
+#endif
 			break;
 		}
-#endif
 		b = a ^ s;
 		q = &h[i];
 		while (q->next && q->next != (m_link_p) b) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/sym53c8xx_comm.h linux-2.4.20/drivers/scsi/sym53c8xx_comm.h
--- linux-2.4.19/drivers/scsi/sym53c8xx_comm.h	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/scsi/sym53c8xx_comm.h	2002-10-29 11:18:31.000000000 +0000
@@ -2509,7 +2509,7 @@
 **    differ and attach them using the order in the NVRAM.
 **
 **    If no NVRAM is found or data appears invalid attach boards in 
-**    the the order they are detected.
+**    the order they are detected.
 **
 **===================================================================
 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/u14-34f.c linux-2.4.20/drivers/scsi/u14-34f.c
--- linux-2.4.19/drivers/scsi/u14-34f.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/u14-34f.c	2002-10-29 11:18:36.000000000 +0000
@@ -1,9 +1,26 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
- *      01 Jan 2002 Rev. 6.50 for linux 2.4.16
+ *      25 Jun 2002 Rev. 6.70 for linux 2.4.19
+ *        + Fixed endian-ness problem due to bitfields.
+ *
+ *      21 Feb 2002 Rev. 6.52 for linux 2.4.18
+ *        + Backport from rev. 7.22 (use io_request_lock).
+ *
+ *      20 Feb 2002 Rev. 7.22 for linux 2.5.5
+ *        + Remove any reference to virt_to_bus().
+ *        + Fix pio hang while detecting multiple HBAs.
+ *
+ *      01 Jan 2002 Rev. 7.20 for linux 2.5.1
  *        + Use the dynamic DMA mapping API.
  *
+ *      19 Dec 2001 Rev. 7.02 for linux 2.5.1
+ *        + Use SCpnt->sc_data_direction if set.
+ *        + Use sglist.page instead of sglist.address.
+ *
+ *      11 Dec 2001 Rev. 7.00 for linux 2.5.1
+ *        + Use host->host_lock instead of io_request_lock.
+ *
  *       1 May 2001 Rev. 6.05 for linux 2.4.4
  *        + Fix data transfer direction for opcode SEND_CUE_SHEET (0x5d)
  *
@@ -23,7 +40,7 @@
  *        + When loaded as a module, accepts the new parameter boot_options
  *          which value is a string with the same format of the kernel boot
  *          command line options. A valid example is:
- *          modprobe u14-34f boot_options=\"0x230,0x340,lc:y,mq:4\"
+ *          modprobe u14-34f 'boot_options="0x230,0x340,lc:y,mq:4"'
  *
  *      22 Jul 1999 Rev. 5.00 for linux 2.2.10 and 2.3.11
  *        + Removed pre-2.2 source code compatibility.
@@ -382,6 +399,10 @@
 #include <linux/ctype.h>
 #include <linux/spinlock.h>
 
+#if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD)
+#error "Adjust your <asm/byteorder.h> defines"
+#endif
+
 /* Values for the PRODUCT_ID ports for the 14/34F */
 #define PRODUCT_ID1  0x56
 #define PRODUCT_ID2  0x40        /* NOTE: Only upper nibble is used */
@@ -448,7 +469,7 @@
 #define REG_CONFIG2       7
 #define REG_OGM           8
 #define REG_ICM           12
-#define REGION_SIZE       13
+#define REGION_SIZE       13UL
 #define BSY_ASSERTED      0x01
 #define IRQ_ASSERTED      0x01
 #define CMD_RESET         0xc0
@@ -470,14 +491,21 @@
 
 /* MailBox SCSI Command Packet */
 struct mscp {
-   unsigned char opcode: 3;             /* type of command */
-   unsigned char xdir: 2;               /* data transfer direction */
-   unsigned char dcn: 1;                /* disable disconnect */
-   unsigned char ca: 1;                 /* use cache (if available) */
-   unsigned char sg: 1;                 /* scatter/gather operation */
-   unsigned char target: 3;             /* SCSI target id */
-   unsigned char channel: 2;            /* SCSI channel number */
-   unsigned char lun: 3;                /* SCSI logical unit number */
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+   unsigned char sg:1, ca:1, dcn:1, xdir:2, opcode:3;
+   unsigned char lun: 3, channel:2, target:3;
+#else
+   unsigned char opcode: 3,             /* type of command */
+                 xdir: 2,               /* data transfer direction */
+                 dcn: 1,                /* disable disconnect */
+                 ca: 1,                 /* use cache (if available) */
+                 sg: 1;                 /* scatter/gather operation */
+   unsigned char target: 3,             /* SCSI target id */
+                 channel: 2,            /* SCSI channel number */
+                 lun: 3;                /* SCSI logical unit number */
+#endif
+
    unsigned int data_address PACKED;    /* transfer data pointer */
    unsigned int data_len PACKED;        /* length in bytes */
    unsigned int link_address PACKED;    /* for linking command chains */
@@ -489,11 +517,19 @@
    unsigned char adapter_status;        /* non-zero indicates HA error */
    unsigned char target_status;         /* non-zero indicates target error */
    unsigned int sense_addr PACKED;
+
+   /* Additional fields begin here. */
    Scsi_Cmnd *SCpnt;
    unsigned int cpp_index;              /* cp index */
-   struct sg_list *sglist;
+
+   /* All the cp structure is zero filled by queuecommand except the
+      following CP_TAIL_SIZE bytes, initialized by detect */
+   dma_addr_t cp_dma_addr; /* dma handle for this cp structure */
+   struct sg_list *sglist; /* pointer to the allocated SG list */
    };
 
+#define CP_TAIL_SIZE (sizeof(struct sglist *) + sizeof(dma_addr_t))
+
 struct hostdata {
    struct mscp cp[MAX_MAILBOXES];       /* Mailboxes for this board */
    unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */
@@ -501,7 +537,6 @@
    unsigned int iocount;                /* Total i/o done for this board */
    int board_number;                    /* Number of this board */
    char board_name[16];                 /* Name of this board */
-   char board_id[256];                  /* data from INQUIRY on this board */
    int in_reset;                        /* True if board is doing a reset */
    int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */
    int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If TRUE redo i/o on target */
@@ -511,9 +546,7 @@
    struct pci_dev *pdev;                /* Always NULL */
    unsigned char heads;
    unsigned char sectors;
-
-   /* slot != 0 for the U24F, slot == 0 for both the U14F and U34F */
-   unsigned char slot;
+   char board_id[256];                  /* data from INQUIRY on this board */
    };
 
 static struct Scsi_Host *sh[MAX_BOARDS + 1];
@@ -543,8 +576,6 @@
 #define H2DEV(x) cpu_to_le32(x)
 #define DEV2H(x) le32_to_cpu(x)
 
-#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
-
 static void do_interrupt_handler(int, void *, struct pt_regs *);
 static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
 static int do_trace = FALSE;
@@ -637,13 +668,18 @@
 
 static int board_inquiry(unsigned int j) {
    struct mscp *cpp;
+   dma_addr_t id_dma_addr;
    unsigned int time, limit = 0;
 
+   id_dma_addr = pci_map_single(HD(j)->pdev, HD(j)->board_id,
+                    sizeof(HD(j)->board_id), PCI_DMA_BIDIRECTIONAL);
    cpp = &HD(j)->cp[0];
-   memset(cpp, 0, sizeof(struct mscp));
+   cpp->cp_dma_addr = pci_map_single(HD(j)->pdev, cpp, sizeof(struct mscp),
+                                     PCI_DMA_BIDIRECTIONAL);
+   memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE);
    cpp->opcode = OP_HOST_ADAPTER;
    cpp->xdir = DTD_IN;
-   cpp->data_address = V2DEV(HD(j)->board_id);
+   cpp->data_address = H2DEV(id_dma_addr);
    cpp->data_len = H2DEV(sizeof(HD(j)->board_id));
    cpp->cdb_len = 6;
    cpp->cdb[0] = HA_CMD_INQUIRY;
@@ -659,7 +695,7 @@
    outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
 
    /* Store pointer in OGM address bytes */
-   outl(V2DEV(cpp), sh[j]->io_port + REG_OGM);
+   outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM);
 
    /* Issue OGM interrupt */
    outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
@@ -675,6 +711,10 @@
       return TRUE;
       }
 
+   pci_unmap_single(HD(j)->pdev, cpp->cp_dma_addr, sizeof(struct mscp),
+                    PCI_DMA_BIDIRECTIONAL);
+   pci_unmap_single(HD(j)->pdev, id_dma_addr, sizeof(HD(j)->board_id),
+                    PCI_DMA_BIDIRECTIONAL);
    return FALSE;
 }
 
@@ -706,17 +746,27 @@
            };
 
    struct config_1 {
-      unsigned char bios_segment: 3;
-      unsigned char removable_disks_as_fixed: 1;
-      unsigned char interrupt: 2;
-      unsigned char dma_channel: 2;
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+      unsigned char dma_channel: 2, interrupt:2,
+                    removable_disks_as_fixed:1, bios_segment: 3;
+#else
+      unsigned char bios_segment: 3, removable_disks_as_fixed: 1,
+                    interrupt: 2, dma_channel: 2;
+#endif
+
       } config_1;
 
    struct config_2 {
-      unsigned char ha_scsi_id: 3;
-      unsigned char mapping_mode: 2;
-      unsigned char bios_drive_number: 1;
-      unsigned char tfr_port: 2;
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+      unsigned char tfr_port: 2, bios_drive_number: 1,
+                    mapping_mode: 2, ha_scsi_id: 3;
+#else
+      unsigned char ha_scsi_id: 3, mapping_mode: 2,
+                    bios_drive_number: 1, tfr_port: 2;
+#endif
+
       } config_2;
 
    char name[16];
@@ -812,6 +862,7 @@
    HD(j)->heads = mapping_table[config_2.mapping_mode].heads;
    HD(j)->sectors = mapping_table[config_2.mapping_mode].sectors;
    HD(j)->subversion = subversion;
+   HD(j)->pdev = NULL;
    HD(j)->board_number = j;
 
    if (have_old_firmware) sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
@@ -859,6 +910,10 @@
    else                       sprintf(dma_name, "DMA %u", dma_channel);
 
    for (i = 0; i < sh[j]->can_queue; i++)
+      HD(j)->cp[i].cp_dma_addr = pci_map_single(HD(j)->pdev,
+            &HD(j)->cp[i], sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL);
+
+   for (i = 0; i < sh[j]->can_queue; i++)
       if (! ((&HD(j)->cp[i])->sglist = kmalloc(
             sh[j]->sg_tablesize * sizeof(struct sg_list),
             (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) {
@@ -972,7 +1027,8 @@
 }
 
 static inline void map_dma(unsigned int i, unsigned int j) {
-   unsigned int k, count, data_len = 0, pci_dir;
+   unsigned int data_len = 0;
+   unsigned int k, count, pci_dir;
    struct scatterlist *sgpnt;
    struct mscp *cpp;
    Scsi_Cmnd *SCpnt;
@@ -988,10 +1044,10 @@
 
    if (!SCpnt->use_sg) {
 
-      if (!SCpnt->request_bufflen)
-         cpp->data_address = V2DEV(SCpnt->request_buffer);
+      /* If we get here with PCI_DMA_NONE, pci_map_single triggers a BUG() */
+      if (!SCpnt->request_bufflen) pci_dir = PCI_DMA_BIDIRECTIONAL;
 
-      else if (SCpnt->request_buffer)
+      if (SCpnt->request_buffer)
          cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev,
                   SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir));
 
@@ -1010,7 +1066,8 @@
 
    cpp->sg = TRUE;
    cpp->use_sg = SCpnt->use_sg;
-   cpp->data_address = V2DEV(cpp->sglist);
+   cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, cpp->sglist,
+                             SCpnt->use_sg * sizeof(struct sg_list), pci_dir));
    cpp->data_len = H2DEV(data_len);
 }
 
@@ -1026,13 +1083,14 @@
       pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
                        DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
 
-   if (SCpnt->use_sg) 
+   if (SCpnt->use_sg)
       pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir);
 
-   else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len))
-      pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), 
-                       DEV2H(cpp->data_len), pci_dir);
+   if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL;
 
+   if (DEV2H(cpp->data_address))
+      pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address),
+                       DEV2H(cpp->data_len), pci_dir);
 }
 
 static void sync_dma(unsigned int i, unsigned int j) {
@@ -1047,14 +1105,15 @@
       pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
                           DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
 
-   if (SCpnt->use_sg) 
-      pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, 
+   if (SCpnt->use_sg)
+      pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer,
                          SCpnt->use_sg, pci_dir);
 
-   else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len))
-      pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), 
-                          DEV2H(cpp->data_len), pci_dir);
+   if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL;
 
+   if (DEV2H(cpp->data_address))
+      pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address),
+                       DEV2H(cpp->data_len), pci_dir);
 }
 
 static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) {
@@ -1090,7 +1149,7 @@
       return;
       }
 
-   if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) 
+   if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN)
       panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j));
 
    cpp->xdir = DTD_IN;
@@ -1143,7 +1202,7 @@
    /* Set pointer to control packet structure */
    cpp = &HD(j)->cp[i];
 
-   memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *));
+   memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE);
    SCpnt->scsi_done = done;
    cpp->cpp_index = i;
    SCpnt->host_scribble = (unsigned char *) &cpp->cpp_index;
@@ -1182,7 +1241,7 @@
       }
 
    /* Store pointer in OGM address bytes */
-   outl(V2DEV(cpp), sh[j]->io_port + REG_OGM);
+   outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM);
 
    /* Issue OGM interrupt */
    outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
@@ -1592,7 +1651,7 @@
          continue;
          }
 
-      outl(V2DEV(cpp), sh[j]->io_port + REG_OGM);
+      outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM);
       outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
       HD(j)->cp_stat[k] = IN_USE;
       }
@@ -1630,11 +1689,11 @@
 
    /* Find the mailbox to be serviced on this board */
    for (i = 0; i < sh[j]->can_queue; i++)
-      if (V2DEV(&(HD(j)->cp[i])) == ret) break;
+      if (H2DEV(HD(j)->cp[i].cp_dma_addr) == ret) break;
 
    if (i >= sh[j]->can_queue)
       panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j),
-            (void *)ret, (void *)V2DEV(HD(j)->cp));
+            (void *)ret, (void *)H2DEV(HD(j)->cp[0].cp_dma_addr));
 
    cpp = &(HD(j)->cp[i]);
    spp = cpp;
@@ -1834,6 +1893,10 @@
    for (i = 0; i < sh[j]->can_queue; i++)
       if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
 
+   for (i = 0; i < sh[j]->can_queue; i++)
+      pci_unmap_single(HD(j)->pdev, HD(j)->cp[i].cp_dma_addr,
+                     sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL);
+
    free_irq(sh[j]->irq, &sha[j]);
 
    if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/u14-34f.h linux-2.4.20/drivers/scsi/u14-34f.h
--- linux-2.4.19/drivers/scsi/u14-34f.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/scsi/u14-34f.h	2002-10-29 11:18:49.000000000 +0000
@@ -13,7 +13,7 @@
 int u14_34f_reset(Scsi_Cmnd *);
 int u14_34f_biosparam(Disk *, kdev_t, int *);
 
-#define U14_34F_VERSION "6.50.00"
+#define U14_34F_VERSION "6.70.00"
 
 #define ULTRASTOR_14_34F {                                                   \
                 name:         "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/wd33c93.h linux-2.4.20/drivers/scsi/wd33c93.h
--- linux-2.4.19/drivers/scsi/wd33c93.h	2001-10-25 20:53:51.000000000 +0000
+++ linux-2.4.20/drivers/scsi/wd33c93.h	2002-10-29 11:18:34.000000000 +0000
@@ -19,12 +19,9 @@
  * GNU General Public License for more details.
  *
  */
-
 #ifndef WD33C93_H
 #define WD33C93_H
 
-#include <linux/config.h>
-
 #define PROC_INTERFACE     /* add code for /proc/scsi/wd33c93/xxx interface */
 #ifdef  PROC_INTERFACE
 #define PROC_STATISTICS    /* add code for keeping various real time stats */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/zalon7xx.c linux-2.4.20/drivers/scsi/zalon7xx.c
--- linux-2.4.19/drivers/scsi/zalon7xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/scsi/zalon7xx.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,162 @@
+/*
+ * Zalon 53c7xx device driver.
+ * By Richard Hirst (rhirst@linuxcare.com)
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/blk.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/delay.h>
+#include <asm/gsc.h>
+
+#include "scsi.h"
+#include "hosts.h"
+
+/*
+ * **      Define the BSD style u_int32 and u_int64 type.
+ * **      Are in fact u_int32_t and u_int64_t :-)
+ * */
+typedef u32 u_int32;
+typedef u64 u_int64;
+typedef u_long          vm_offset_t;
+
+#include "zalon7xx.h"
+
+
+/* hosts_* are kluges to pass info between the zalon7xx_detected()
+** and the register_parisc_driver() callbacks.
+*/
+static Scsi_Host_Template *hosts_tptr;
+static int hosts_used=0;
+static int zalon_id = 0;
+
+extern int zalon_attach(Scsi_Host_Template *tpnt,
+			unsigned long base_addr,
+			struct parisc_device *dev,
+			int irq_vector,
+			int unit
+			);
+
+
+#if 0
+/* FIXME:
+ * Is this function dead code? or is someone planning on using it in the
+ * future.  The clock = (int) pdc_result[16] does not look correct to
+ * me ... I think it should be iodc_data[16].  Since this cause a compile
+ * error with the new encapsulated PDC, I'm not compiling in this function.
+ * - RB
+ */
+/* poke SCSI clock out of iodc data */
+
+static u8 iodc_data[32] __attribute__ ((aligned (64)));
+static unsigned long pdc_result[32] __attribute__ ((aligned (16))) ={0,0,0,0};
+
+static int 
+lasi_scsi_clock(void * hpa, int defaultclock)
+{
+	int clock, status;
+
+	status = pdc_iodc_read(&pdc_result, hpa, 0, &iodc_data, 32 );
+	if (status == PDC_RET_OK) {
+		clock = (int) pdc_result[16];
+	} else {
+		printk(KERN_WARNING "%s: pdc_iodc_read returned %d\n", __FUNCTION__, status);
+		clock = defaultclock; 
+	}
+
+	printk(KERN_DEBUG "%s: SCSI clock %d\n", __FUNCTION__, clock);
+ 	return clock;
+}
+#endif
+
+static int __init
+zalon_scsi_callback(struct parisc_device *dev)
+{
+	struct gsc_irq gsc_irq;
+	u32 zalon_vers;
+	int irq;
+	unsigned long zalon = dev->hpa;
+
+	__raw_writel(CMD_RESET, zalon + IO_MODULE_IO_COMMAND);
+	while (!(__raw_readl(zalon + IO_MODULE_IO_STATUS) & IOSTATUS_RY))
+		;
+	__raw_writel(IOIIDATA_MINT5EN | IOIIDATA_PACKEN | IOIIDATA_PREFETCHEN,
+		zalon + IO_MODULE_II_CDATA);
+
+	/* XXX: Save the Zalon version for bug workarounds? */
+	zalon_vers = __raw_readl(dev->hpa + IO_MODULE_II_CDATA) & 0x07000000;
+	zalon_vers >>= 24;
+
+	/* Setup the interrupts first.
+	** Later on request_irq() will register the handler.
+	*/
+        irq = gsc_alloc_irq(&gsc_irq);
+
+	printk("%s: Zalon vers field is 0x%x, IRQ %d\n", __FUNCTION__,
+		zalon_vers, irq);
+
+	__raw_writel(gsc_irq.txn_addr | gsc_irq.txn_data, dev->hpa + IO_MODULE_EIM);
+
+	if ( zalon_vers == 0)
+		printk(KERN_WARNING "%s: Zalon 1.1 or earlier\n", __FUNCTION__);
+
+	/*
+	**  zalon_attach: returns -1 on failure, 0 on success
+	*/
+	hosts_used = zalon_attach(hosts_tptr, dev->hpa + GSC_SCSI_ZALON_OFFSET,
+			dev, irq, zalon_id);
+
+	if (hosts_used == 0)
+		zalon_id++;
+
+	hosts_used = (hosts_used == 0);
+	return (hosts_used == 0);
+}
+
+static struct parisc_device_id zalon_tbl[] = {
+	{ HPHW_A_DMA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00089 }, 
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, zalon_tbl);
+
+static struct parisc_driver zalon_driver = {
+	name:		"GSC SCSI (Zalon)",
+	id_table:	zalon_tbl,
+	probe:		zalon_scsi_callback,
+};
+
+int zalon7xx_detect(Scsi_Host_Template *tpnt)
+{
+	/* "pass" the parameter to the callback functions */
+	hosts_tptr = tpnt;
+	hosts_used = 0;
+
+	/* claim all zalon cards. */
+	register_parisc_driver(&zalon_driver);
+
+	/* Check if any callbacks actually found/claimed anything. */
+	return (hosts_used != 0);
+}
+
+#ifdef MODULE
+extern int ncr53c8xx_release(struct Scsi_Host *host);
+
+int zalon7xx_release(struct Scsi_Host *host)
+{
+	ncr53c8xx_release(host);
+	unregister_parisc_driver(&zalon_driver);
+	return 1;
+}
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/scsi/zalon7xx.h linux-2.4.20/drivers/scsi/zalon7xx.h
--- linux-2.4.19/drivers/scsi/zalon7xx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/scsi/zalon7xx.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,60 @@
+#ifndef ZALON7XX_H
+#define ZALON7XX_H
+
+#include <linux/types.h>
+
+#include "sym53c8xx_defs.h"
+
+extern int zalon7xx_detect(Scsi_Host_Template *);
+
+#include <scsi/scsicam.h>
+
+extern struct proc_dir_entry proc_scsi_zalon7xx;
+
+/* borrowed from drivers/scsi/ncr53c8xx.h */
+int ncr53c8xx_abort(Scsi_Cmnd *);
+int zalon7xx_detect(Scsi_Host_Template *tpnt);
+const char *ncr53c8xx_info(struct Scsi_Host *host);
+int ncr53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int ncr53c8xx_reset(Scsi_Cmnd *, unsigned int);
+
+#ifdef MODULE
+int zalon7xx_release(struct Scsi_Host *);
+#else
+#define zalon7xx_release NULL
+#endif
+
+#define SCSI_ZALON { proc_name:		"zalon720",	\
+			detect:         zalon7xx_detect,	\
+			release:        zalon7xx_release,	\
+			info:           ncr53c8xx_info, 	\
+			queuecommand:   ncr53c8xx_queue_command,\
+			abort:          ncr53c8xx_abort,	\
+			reset:          ncr53c8xx_reset,	\
+			bios_param:     scsicam_bios_param,	\
+			can_queue:      SCSI_NCR_CAN_QUEUE,	\
+			this_id:        7,			\
+			sg_tablesize:   SCSI_NCR_SG_TABLESIZE,	\
+			cmd_per_lun:    SCSI_NCR_CMD_PER_LUN,	\
+			use_clustering: DISABLE_CLUSTERING} 
+
+
+#define GSC_SCSI_ZALON_OFFSET 0x800
+
+#define IO_MODULE_EIM		(1*4)
+#define IO_MODULE_DC_ADATA	(2*4)
+#define IO_MODULE_II_CDATA	(3*4)
+#define IO_MODULE_IO_COMMAND	(12*4)
+#define IO_MODULE_IO_STATUS	(13*4)
+
+#define IOSTATUS_RY             0x40
+#define IOSTATUS_FE             0x80
+#define IOIIDATA_SMINT5L        0x40000000
+#define IOIIDATA_MINT5EN        0x20000000
+#define IOIIDATA_PACKEN         0x10000000
+#define IOIIDATA_PREFETCHEN     0x08000000
+#define IOIIDATA_IOII           0x00000020
+
+#define CMD_RESET		5
+
+#endif /* ZALON7XX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sgi/Config.in linux-2.4.20/drivers/sgi/Config.in
--- linux-2.4.19/drivers/sgi/Config.in	2000-07-10 05:32:58.000000000 +0000
+++ linux-2.4.20/drivers/sgi/Config.in	2002-10-29 11:18:33.000000000 +0000
@@ -10,8 +10,8 @@
 fi
 bool 'SGI DS1286  RTC support' CONFIG_SGI_DS1286
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then  
-   tristate 'SGI Newport Graphics support' CONFIG_SGI_NEWPORT_GFX
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   tristate 'SGI Newport Graphics support (EXPERIMENTAL)' CONFIG_SGI_NEWPORT_GFX
 fi
 
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sgi/char/ds1286.c linux-2.4.20/drivers/sgi/char/ds1286.c
--- linux-2.4.19/drivers/sgi/char/ds1286.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/sgi/char/ds1286.c	2002-10-29 11:18:36.000000000 +0000
@@ -1,8 +1,8 @@
 /*
- * DS1286 Real Time Clock interface for Linux	
+ * DS1286 Real Time Clock interface for Linux
  *
  * Copyright (C) 1998, 1999, 2000 Ralf Baechle
- *	
+ *
  * Based on code written by Paul Gortmaker.
  *
  * This driver allows use of the real time clock (built into nearly all
@@ -82,7 +82,7 @@
 unsigned char ds1286_status;		/* bitmapped status byte.	*/
 unsigned long ds1286_freq;		/* Current periodic IRQ rate	*/
 
-unsigned char days_in_mo[] = 
+unsigned char days_in_mo[] =
 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
 /*
@@ -99,7 +99,7 @@
                         unsigned int cmd, unsigned long arg)
 {
 
-	struct rtc_time wtime; 
+	struct rtc_time wtime;
 
 	switch (cmd) {
 	case RTC_AIE_OFF:	/* Mask alarm int. enab. bit	*/
@@ -175,7 +175,7 @@
 		 */
 
 		ds1286_get_alm_time(&wtime);
-		break; 
+		break;
 	}
 	case RTC_ALM_SET:	/* Store a time into the alarm */
 	{
@@ -229,7 +229,7 @@
 		if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
 				   sizeof(struct rtc_time)))
 			return -EFAULT;
-		
+
 		return ds1286_set_time(&rtc_tm);
 	}
 	default:
@@ -396,13 +396,13 @@
 	unsigned char save_control;
 	unsigned int flags;
 	unsigned long uip_watchdog = jiffies;
-	
+
 	/*
 	 * read RTC once any update in progress is done. The update
 	 * can take just over 2ms. We wait 10 to 20ms. There is no need to
 	 * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
 	 * If you need to know *exactly* when a second has started, enable
-	 * periodic update complete interrupts, (via ioctl) and then 
+	 * periodic update complete interrupts, (via ioctl) and then
 	 * immediately read /dev/rtc which will block until you get the IRQ.
 	 * Once the read clears, read the RTC time (again via ioctl). Easy.
 	 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sgi/char/graphics.c linux-2.4.20/drivers/sgi/char/graphics.c
--- linux-2.4.19/drivers/sgi/char/graphics.c	2001-10-11 16:43:30.000000000 +0000
+++ linux-2.4.20/drivers/sgi/char/graphics.c	2002-10-29 11:18:31.000000000 +0000
@@ -95,10 +95,10 @@
 		struct gfx_getboardinfo_args *bia = (void *) arg;
 		void   *dest_buf;
 		int    max_len;
-		
+
 		i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct gfx_getboardinfo_args));
 		if (i) return i;
-		
+
 		if (__get_user (board,    &bia->board) ||
 		    __get_user (dest_buf, &bia->buf) ||
 		    __get_user (max_len,  &bia->len))
@@ -185,7 +185,7 @@
 	default:
 		if (cards [devnum].g_ioctl)
 			return (*cards [devnum].g_ioctl)(devnum, cmd, arg);
-		
+
 	}
 	return -EINVAL;
 }
@@ -210,14 +210,14 @@
 	return 0;
 }
 
-/* 
+/*
  * This is the core of the direct rendering engine.
  */
 struct page *
 sgi_graphics_nopage (struct vm_area_struct *vma, unsigned long address, int
 		     no_share)
 {
-	pgd_t *pgd; pmd_t *pmd; pte_t *pte; 
+	pgd_t *pgd; pmd_t *pmd; pte_t *pte;
 	int board = GRAPHICS_CARD (vma->vm_dentry->d_inode->i_rdev);
 
 	unsigned long virt_add, phys_add;
@@ -226,7 +226,7 @@
 	printk ("Got a page fault for board %d address=%lx guser=%lx\n", board,
 		address, (unsigned long) cards[board].g_user);
 #endif
-	
+
 	/* Figure out if another process has this mapped, and revoke the mapping
 	 * in that case. */
 	if (cards[board].g_user && cards[board].g_user != current) {
@@ -260,7 +260,7 @@
 static struct vm_operations_struct graphics_mmap = {
 	nopage:	sgi_graphics_nopage,	/* our magic no-page fault handler */
 };
-	
+
 int
 sgi_graphics_mmap (struct file *file, struct vm_area_struct *vma)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sgi/char/graphics.h linux-2.4.20/drivers/sgi/char/graphics.h
--- linux-2.4.19/drivers/sgi/char/graphics.h	1999-06-26 00:39:34.000000000 +0000
+++ linux-2.4.20/drivers/sgi/char/graphics.h	2002-10-29 11:18:34.000000000 +0000
@@ -6,7 +6,7 @@
 
 	/* Last process that got the graphics registers mapped  */
 	struct task_struct *g_user;
-	
+
 	/* Board info */
 	void               *g_board_info;
 	int                g_board_info_len;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sgi/char/newport.c linux-2.4.20/drivers/sgi/char/newport.c
--- linux-2.4.19/drivers/sgi/char/newport.c	2001-08-27 15:56:31.000000000 +0000
+++ linux-2.4.20/drivers/sgi/char/newport.c	2002-10-29 11:18:35.000000000 +0000
@@ -28,7 +28,7 @@
 #define LOAD(val) x->val = npregs->set.val;
 #define LOADI(val) x->val = npregs->set.val.word;
 #define LOADC(val) x->val = npregs->cset.val;
-	
+
 	LOAD(drawmode1);
 	LOAD(drawmode0);
 	LOAD(lsmode);
@@ -65,9 +65,9 @@
 	LOAD(wrmask);
 	LOAD(hostrw0);
 	LOAD(hostrw1);
-	
+
         /* configregs */
-	
+
 	LOADC(smask1x);
 	LOADC(smask1y);
 	LOADC(smask2x);
@@ -112,7 +112,7 @@
 #define STOREI(val) npregs->set.val.word = x->val
 #define STOREC(val) npregs->cset.val = x->val
 	newport_wait ();
-	
+
 	STORE(drawmode1);
 	STORE(drawmode0);
 	STORE(lsmode);
@@ -149,9 +149,9 @@
 	STORE(wrmask);
 	STORE(hostrw0);
 	STORE(hostrw1);
-	
+
         /* configregs */
-	
+
 	STOREC(smask1x);
 	STOREC(smask1y);
 	STOREC(smask2x);
@@ -174,7 +174,7 @@
 	switch (cmd){
 	case NG1_SETDISPLAYMODE: {
 		struct ng1_setdisplaymode_args request;
-		
+
 		if (copy_from_user (&request, (void *) arg, sizeof (request)))
 			return -EFAULT;
 
@@ -183,8 +183,8 @@
 		npregs->set.dcbmode = DCB_XMAP0 | XM9_CRS_FIFO_AVAIL |
 			DCB_DATAWIDTH_1 | R_DCB_XMAP9_PROTOCOL;
 		xmap9FIFOWait (npregs);
-		
-		/* FIXME: timing is wrong, just be extracted from 
+
+		/* FIXME: timing is wrong, just be extracted from
 		 * the per-board timing table.  I still have to figure
 		 * out where this comes from
 		 *
@@ -206,13 +206,13 @@
 	}
 	case NG1_SET_CURSOR_HOTSPOT: {
 		struct ng1_set_cursor_hotspot request;
-		
+
 		if (copy_from_user (&request, (void *) arg, sizeof (request)))
 			return -EFAULT;
 		/* FIXME: make request.xhot, request.yhot the hot spot */
 		return 0;
 	}
-	
+
 	case NG1_SETGAMMARAMP0:
 		/* FIXME: load the gamma ramps :-) */
 		return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sgi/char/rrm.c linux-2.4.20/drivers/sgi/char/rrm.c
--- linux-2.4.19/drivers/sgi/char/rrm.c	2001-08-27 15:56:31.000000000 +0000
+++ linux-2.4.20/drivers/sgi/char/rrm.c	2002-10-29 11:18:37.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Linux Rendering Resource Manager 
+ * Linux Rendering Resource Manager
  *
  *          Implements the SGI-compatible rendering resource manager.
  *          This takes care of implementing the virtualized video hardware
@@ -51,7 +51,7 @@
 rrm_command (unsigned int cmd, void *arg)
 {
 	int i, rnid;
-	
+
 	if (cmd > RRM_FUNCTIONS){
 		printk ("Called unimplemented rrm ioctl: %d\n", cmd + RRM_BASE);
 		return -EINVAL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sgi/char/sgicons.c linux-2.4.20/drivers/sgi/char/sgicons.c
--- linux-2.4.19/drivers/sgi/char/sgicons.c	2001-08-27 15:56:31.000000000 +0000
+++ linux-2.4.20/drivers/sgi/char/sgicons.c	2002-10-29 11:18:32.000000000 +0000
@@ -4,7 +4,7 @@
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
  *
- * This implement a virtual console interface.
+ * This implements a virtual console interface.
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sgi/char/sgiserial.c linux-2.4.20/drivers/sgi/char/sgiserial.c
--- linux-2.4.19/drivers/sgi/char/sgiserial.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/sgi/char/sgiserial.c	2002-10-29 11:18:35.000000000 +0000
@@ -104,7 +104,7 @@
 /* serial subtype definitions */
 #define SERIAL_TYPE_NORMAL	1
 #define SERIAL_TYPE_CALLOUT	2
-  
+
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
 
@@ -170,7 +170,7 @@
 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
 	9600, 19200, 38400, 57600, 115200, 0 };
 
-/* 
+/*
  * Reading and writing Zilog8530 registers.  The delays are to make this
  * driver work on the Sun4 which needs a settling delay after each chip
  * register access, other machines handle this in hardware via auxiliary
@@ -295,7 +295,7 @@
 
 	if (serial_paranoia_check(info, tty->device, "rs_stop"))
 		return;
-	
+
 	save_flags(flags); cli();
 	if (info->curregs[5] & TxENAB) {
 		info->curregs[5] &= ~TxENAB;
@@ -309,10 +309,10 @@
 {
 	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
 	unsigned long flags;
-	
+
 	if (serial_paranoia_check(info, tty->device, "rs_start"))
 		return;
-	
+
 	save_flags(flags); cli();
 	if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
 		info->curregs[5] |= TxENAB;
@@ -374,7 +374,7 @@
  * rs_interrupt() should try to keep the interrupt handler as fast as
  * possible.  After you are done making modifications, it is not a bad
  * idea to do:
- * 
+ *
  * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
  *
  * and look at the resulting assemble code in serial.s.
@@ -632,7 +632,7 @@
 {
 	struct sgi_serial	*info = (struct sgi_serial *) private_;
 	struct tty_struct	*tty;
-	
+
 	tty = info->tty;
 	if (!tty)
 		return;
@@ -652,13 +652,13 @@
  *
  * 	serial interrupt routine -> (scheduler tqueue) ->
  * 	do_serial_hangup() -> tty->hangup() -> rs_hangup()
- * 
+ *
  */
 static void do_serial_hangup(void *private_)
 {
 	struct sgi_serial	*info = (struct sgi_serial *) private_;
 	struct tty_struct	*tty;
-	
+
 	tty = info->tty;
 	if (!tty)
 		return;
@@ -724,7 +724,7 @@
 	write_zsreg(info->zs_channel, 3, info->curregs[3]);
 	write_zsreg(info->zs_channel, 5, info->curregs[5]);
 	write_zsreg(info->zs_channel, 9, info->curregs[9]);
-	
+
 	/*
 	 * And clear the interrupt registers again for luck.
 	 */
@@ -764,9 +764,9 @@
 	printk("Shutting down serial port %d (irq %d)....", info->line,
 	       info->irq);
 #endif
-	
+
 	save_flags(flags); cli(); /* Disable interrupts */
-	
+
 	if (info->xmit_buf) {
 		free_page((unsigned long) info->xmit_buf);
 		info->xmit_buf = 0;
@@ -774,7 +774,7 @@
 
 	if (info->tty)
 		set_bit(TTY_IO_ERROR, &info->tty->flags);
-	
+
 	info->flags &= ~ZILOG_INITIALIZED;
 	restore_flags(flags);
 }
@@ -901,7 +901,7 @@
 	restore_flags(flags);
 }
 
-/* 
+/*
  * This is the more generic put_char function for the driver.
  * In earlier versions of this driver, "rs_put_char" was the
  * name of the console-specific fucntion, now called zs_cons_put_char
@@ -909,7 +909,7 @@
 
 static void rs_put_char(struct tty_struct *tty, char ch)
 {
-	struct sgi_zschannel *chan = 
+	struct sgi_zschannel *chan =
 		((struct sgi_serial *)tty->driver_data)->zs_channel;
 	volatile unsigned char junk;
 	int flags, loops = 0;
@@ -1014,7 +1014,7 @@
 
 	save_flags(flags);
 	while (1) {
-		cli();		
+		cli();
 		c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
 				   SERIAL_XMIT_SIZE - info->xmit_head));
 		if (c <= 0)
@@ -1078,7 +1078,7 @@
 {
 	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
 	int	ret;
-				
+
 	if (serial_paranoia_check(info, tty->device, "rs_write_room"))
 		return 0;
 	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
@@ -1090,7 +1090,7 @@
 static int rs_chars_in_buffer(struct tty_struct *tty)
 {
 	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
-				
+
 	if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
 		return 0;
 	return info->xmit_cnt;
@@ -1099,7 +1099,7 @@
 static void rs_flush_buffer(struct tty_struct *tty)
 {
 	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
-				
+
 	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
 		return;
 	cli();
@@ -1155,7 +1155,7 @@
 /*
  * ------------------------------------------------------------
  * rs_throttle()
- * 
+ *
  * This routine is called by the upper-layer tty layer to signal that
  * incoming characters should be throttled.
  * ------------------------------------------------------------
@@ -1165,14 +1165,14 @@
 	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
-	
+
 	printk("throttle %s: %d....\n", _tty_name(tty, buf),
 	       tty->ldisc.chars_in_buffer(tty));
 #endif
 
 	if (serial_paranoia_check(info, tty->device, "rs_throttle"))
 		return;
-	
+
 	if (I_IXOFF(tty))
 		info->x_char = STOP_CHAR(tty);
 
@@ -1189,14 +1189,14 @@
 	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
-	
+
 	printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
 	       tty->ldisc.chars_in_buffer(tty));
 #endif
 
 	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
 		return;
-	
+
 	if (I_IXOFF(tty)) {
 		if (info->x_char)
 			info->x_char = 0;
@@ -1222,7 +1222,7 @@
 			   struct serial_struct * retinfo)
 {
 	struct serial_struct tmp;
-  
+
 	if (!retinfo)
 		return -EFAULT;
 	memset(&tmp, 0, sizeof(tmp));
@@ -1291,7 +1291,7 @@
  * 	    release the bus after transmitting. This must be done when
  * 	    the transmit shift register is empty, not be done when the
  * 	    transmit holding register is empty.  This functionality
- * 	    allows an RS485 driver to be written in user space. 
+ * 	    allows an RS485 driver to be written in user space.
  */
 static int get_lsr_info(struct sgi_serial * info, unsigned int *value)
 {
@@ -1304,7 +1304,7 @@
 	junk = ioc_icontrol->istat0;
 	sti();
 	return put_user(status,value);
-} 
+}
 
 static int get_modem_info(struct sgi_serial * info, unsigned int *value)
 {
@@ -1333,7 +1333,7 @@
 	if (get_user(arg, value))
 		return -EFAULT;
 	switch (cmd) {
-	case TIOCMBIS: 
+	case TIOCMBIS:
 		if (arg & TIOCM_RTS)
 			info->curregs[5] |= RTS;
 		if (arg & TIOCM_DTR)
@@ -1389,7 +1389,7 @@
 		if (tty->flags & (1 << TTY_IO_ERROR))
 		    return -EIO;
 	}
-	
+
 	switch (cmd) {
 		case TCSBRK:	/* SVID version: non-zero arg --> no break */
 			retval = tty_check_change(tty);
@@ -1438,7 +1438,7 @@
 				    info, sizeof(struct sgi_serial)))
 				return -EFAULT;
 			return 0;
-			
+
 		default:
 			return -ENOIOCTLCMD;
 		}
@@ -1464,7 +1464,7 @@
 /*
  * ------------------------------------------------------------
  * rs_close()
- * 
+ *
  * This routine is called when the serial port gets closed.  First, we
  * wait for the last remaining data to be sent.  Then, we unlink its
  * ZILOG structure from the interrupt chain if necessary, and we free
@@ -1478,14 +1478,14 @@
 
 	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
 		return;
-	
+
 	save_flags(flags); cli();
-	
+
 	if (tty_hung_up_p(filp)) {
 		restore_flags(flags);
 		return;
 	}
-	
+
 #ifdef SERIAL_DEBUG_OPEN
 	printk("rs_close ttys%d, count = %d\n", info->line, info->count);
 #endif
@@ -1520,7 +1520,7 @@
 	if (info->flags & ZILOG_CALLOUT_ACTIVE)
 		info->callout_termios = *tty->termios;
 	/*
-	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * Now we wait for the transmit buffer to clear; and we notify
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	tty->closing = 1;
@@ -1576,10 +1576,10 @@
 void rs_hangup(struct tty_struct *tty)
 {
 	struct sgi_serial * info = (struct sgi_serial *)tty->driver_data;
-	
+
 	if (serial_paranoia_check(info, tty->device, "rs_hangup"))
 		return;
-	
+
 	rs_flush_buffer(tty);
 	shutdown(info);
 	info->event = 0;
@@ -1635,7 +1635,7 @@
 		info->flags |= ZILOG_CALLOUT_ACTIVE;
 		return 0;
 	}
-	
+
 	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
@@ -1655,7 +1655,7 @@
 		if (tty->termios->c_cflag & CLOCAL)
 			do_clocal = 1;
 	}
-	
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -1683,7 +1683,7 @@
 			if (info->flags & ZILOG_HUP_NOTIFY)
 				retval = -EAGAIN;
 			else
-				retval = -ERESTARTSYS;	
+				retval = -ERESTARTSYS;
 #else
 			retval = -EAGAIN;
 #endif
@@ -1715,7 +1715,7 @@
 		return retval;
 	info->flags |= ZILOG_NORMAL_ACTIVE;
 	return 0;
-}	
+}
 
 /*
  * This routine is called whenever a serial port is opened.  It
@@ -1767,17 +1767,17 @@
 	if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) {
 		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
 			*tty->termios = info->normal_termios;
-		else 
+		else
 			*tty->termios = info->callout_termios;
 		change_speed(info);
 	}
 
-	/* If this is the serial console change the speed to 
+	/* If this is the serial console change the speed to
 	 * the right value
 	 */
 	if (info->is_cons) {
 		info->tty->termios->c_cflag = sgisercon->cflag;
-		change_speed(info);		
+		change_speed(info);
 	}
 
 	info->session = current->session;
@@ -1868,7 +1868,7 @@
 
 	/* Initialize the tty_driver structure */
 	/* SGI: Not all of this is exactly right for us. */
-	
+
 	memset(&serial_driver, 0, sizeof(struct tty_driver));
 	serial_driver.magic = TTY_DRIVER_MAGIC;
 #ifdef CONFIG_DEVFS_FS
@@ -1923,7 +1923,7 @@
 		panic("Couldn't register serial driver");
 	if (tty_register_driver(&callout_driver))
 		panic("Couldn't register callout driver");
-	
+
 	save_flags(flags); cli();
 
 	/* Set up our interrupt linked list */
@@ -2014,7 +2014,7 @@
 		info->normal_termios = serial_driver.init_termios;
 		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->close_wait);
-		printk("tty%02d at 0x%04x (irq = %d)", info->line, 
+		printk("tty%02d at 0x%04x (irq = %d)", info->line,
 		       info->port, info->irq);
 		printk(" is a Zilog8530\n");
 	}
@@ -2052,7 +2052,7 @@
 rs_cons_hook(int chip, int out, int line)
 {
 	int channel;
-	
+
 	if(chip)
 		panic("rs_cons_hook called with chip not zero");
 	if(line != 0 && line != 1)
@@ -2068,11 +2068,11 @@
 	zs_soft[channel].change_needed = 0;
 	zs_soft[channel].clk_divisor = 16;
 	zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
-	if(out) 
+	if(out)
 		zs_cons_chanout = ((chip * 2) + channel);
-	else 
+	else
 		zs_cons_chanin = ((chip * 2) + channel);
-	
+
 	rs_cons_check(&zs_soft[channel], channel);
 }
 
@@ -2136,7 +2136,7 @@
 	int	cflag = CREAD | HUPCL | CLOCAL;
 	char	*s, *dbaud;
 	int     i, brg;
-    
+
 	if (options) {
 		baud = simple_strtoul(options, NULL, 10);
 		s = options;
@@ -2213,8 +2213,8 @@
         rs_cons_hook(0, 0, con->index);
 	info = zs_soft + con->index;
 	info->is_cons = 1;
-    
-	printk("Console: ttyS%d (Zilog8530), %d baud\n", 
+
+	printk("Console: ttyS%d (Zilog8530), %d baud\n",
 						info->line, baud);
 
 	i = con->cflag & CBAUD;
@@ -2254,14 +2254,14 @@
 		zscons_regs[4] |= SB2;
 	else
 		zscons_regs[4] |= SB1;
-	
+
 	sgisercon = con;
 
 	brg = BPS_TO_BRG(baud, ZS_CLOCK / info->clk_divisor);
 	zscons_regs[12] = brg & 0xff;
 	zscons_regs[13] = (brg >> 8) & 0xff;
 	memcpy(info->curregs, zscons_regs, sizeof(zscons_regs));
-	memcpy(info->pendregs, zscons_regs, sizeof(zscons_regs));    
+	memcpy(info->pendregs, zscons_regs, sizeof(zscons_regs));
 	load_zsregs(info->zs_channel, zscons_regs);
 	ZS_CLEARERR(info->zs_channel);
 	ZS_CLEARFIFO(info->zs_channel);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sgi/char/sgiserial.h linux-2.4.20/drivers/sgi/char/sgiserial.h
--- linux-2.4.19/drivers/sgi/char/sgiserial.h	2001-08-27 15:56:31.000000000 +0000
+++ linux-2.4.20/drivers/sgi/char/sgiserial.h	2002-10-29 11:18:39.000000000 +0000
@@ -57,7 +57,7 @@
 /*
  * Definitions for ZILOG_struct (and serial_struct) flags field
  */
-#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
+#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
 				   on the callout port */
 #define ZILOG_FOURPORT  0x0002	/* Set OU1, OUT2 per AST Fourport settings */
 #define ZILOG_SAK	0x0004	/* Secure Attention Key (Orange book) */
@@ -93,7 +93,7 @@
 #ifdef __KERNEL__
 /*
  * This is our internal structure for each serial port's state.
- * 
+ *
  * Many fields are paralleled by the structure used by the serial_struct
  * structure.
  *
@@ -406,7 +406,7 @@
 /* Read Register 15 (value of WR 15) */
 
 /* Misc inlines */
-extern inline void ZS_CLEARERR(struct sgi_zschannel *channel)
+static inline void ZS_CLEARERR(struct sgi_zschannel *channel)
 {
 	volatile unsigned char junk;
 
@@ -416,7 +416,7 @@
 		junk = ioc_icontrol->istat0;
 }
 
-extern inline void ZS_CLEARFIFO(struct sgi_zschannel *channel)
+static inline void ZS_CLEARFIFO(struct sgi_zschannel *channel)
 {
 	volatile unsigned char junk;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sgi/char/shmiq.c linux-2.4.20/drivers/sgi/char/shmiq.c
--- linux-2.4.19/drivers/sgi/char/shmiq.c	2001-08-27 15:56:31.000000000 +0000
+++ linux-2.4.20/drivers/sgi/char/shmiq.c	2002-10-29 11:18:49.000000000 +0000
@@ -10,7 +10,7 @@
  * any other number implements /dev/qcntl${minor-1}
  *
  * /dev/shmiq is used by the X server for two things:
- * 
+ *
  *    1. for I_LINK()ing trough ioctl the file handle of a
  *       STREAMS device.
  *
@@ -36,7 +36,7 @@
  * need an strace from an X server that runs on a machine with more
  * than one keyboard.  And this is a problem since the file handles
  * are pushed in /dev/shmiq, while the events should be dispatched to
- * the /dev/qcntlN device. 
+ * the /dev/qcntlN device.
  *
  * Until then, I just allow for 1 qcntl device.
  *
@@ -84,7 +84,7 @@
 	int    tail;		/* our copy of the shmiq->tail */
 	int    events;
 	int    mapped;
-	
+
 	wait_queue_head_t    proc_list;
 	struct fasync_struct *fasync;
 } shmiqs [MAX_SHMI_QUEUES];
@@ -106,12 +106,12 @@
 		return;
 	}
 	tail_next = (s->tail + 1) % (shmiqs [device].events);
-	
+
 	if (tail_next == s->head){
 		s->flags |= SHMIQ_OVERFLOW;
 		return;
 	}
-	
+
 	e->un.time = jiffies;
 	s->events [s->tail] = *e;
 	printk ("KERNEL: dev=%d which=%d type=%d flags=%d\n",
@@ -151,7 +151,7 @@
 
 	if (fdes > MAX_SHMIQ_DEVS)
 		return -EINVAL;
-	
+
 	if (!shmiq_pushed_devices [fdes].used)
 		return -EINVAL;
 
@@ -179,7 +179,7 @@
 
 	case QIOCIISTR: {
 		struct muxioctl *mux = (struct muxioctl *) s->ic_dp;
-		
+
 		printk ("Double indirect ioctl: [%d, %x\n", mux->index, mux->realcmd);
 		return -EINVAL;
 	}
@@ -225,12 +225,12 @@
 	case I_UNLINK:
 		v = shmiq_forget_file (arg);
 		return v;
-		
+
 	case I_STR:
 		v = get_sioc (&sioc, arg);
 		if (v)
 			return v;
-		
+
 		/* FIXME: This forces device = 0 */
 		return shmiq_sioc (0, sioc.ic_cmd, &sioc);
 	}
@@ -249,7 +249,7 @@
 	struct shmiqreq req;
 	struct vm_area_struct *vma;
 	int v;
-	
+
 	switch (cmd) {
 		/*
 		 * The address space is already mapped as a /dev/zero
@@ -259,7 +259,7 @@
 		case QIOCATTACH: {
 			unsigned long vaddr;
 			int s;
-	
+
 			v = verify_area (VERIFY_READ, (void *) arg,
 			                 sizeof (struct shmiqreq));
 			if (v)
@@ -318,7 +318,7 @@
 	int           minor = MINOR (file->f_dentry->d_inode->i_rdev), error;
 	unsigned int  size;
 	unsigned long mem, start;
-	
+
 	/* mmap is only supported on the qcntl devices */
 	if (minor-- == 0)
 		return -EINVAL;
@@ -327,7 +327,7 @@
 		return -EINVAL;
 
 	size  = vma->vm_end - vma->vm_start;
-	start = vma->vm_start; 
+	start = vma->vm_start;
 	lock_kernel();
 	mem = (unsigned long) shmiqs [minor].shmiq_vaddr =  vmalloc_uncached (size);
 	if (!mem) {
@@ -338,7 +338,7 @@
 	/* Prevent the swapper from considering these pages for swap and touching them */
 	vma->vm_flags    |= (VM_SHM  | VM_LOCKED | VM_IO);
 	vma->vm_ops = &qcntl_mmap;
-	
+
 	/* Uncache the pages */
 	vma->vm_page_prot = PAGE_USERIO;
 
@@ -348,7 +348,7 @@
 	/* Init the shared memory input queue */
 	memset (shmiqs [minor].shmiq_vaddr, 0, size);
 	unlock_kernel();
-	
+
 	return error;
 }
 
@@ -374,7 +374,7 @@
 
 	if (!shmiqs [minor].mapped)
 		return 0;
-	
+
 	poll_wait (filp, &shmiqs [minor].proc_list, wait);
 	s = shmiqs [minor].shmiq_vaddr;
 	if (s->head != s->tail)
@@ -421,7 +421,7 @@
 {
 	int minor = MINOR (inode->i_rdev);
 	int j;
-	
+
 	if (minor-- == 0){
 		for (j = 0; j < MAX_SHMIQ_DEVS; j++)
 			shmiq_forget_file (j);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sgi/char/streamable.c linux-2.4.20/drivers/sgi/char/streamable.c
--- linux-2.4.19/drivers/sgi/char/streamable.c	2000-07-13 04:58:43.000000000 +0000
+++ linux-2.4.20/drivers/sgi/char/streamable.c	2002-10-29 11:18:33.000000000 +0000
@@ -36,13 +36,13 @@
 get_sioc (struct strioctl *sioc, unsigned long arg)
 {
 	int v;
-	
+
 	v = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct strioctl));
 	if (v)
 		return v;
 	if (copy_from_user (sioc, (void *) arg, sizeof (struct strioctl)))
 		return -EFAULT;
-		
+
 	v = verify_area (VERIFY_WRITE, (void *) sioc->ic_dp, sioc->ic_len);
 	if (v)
 		return v;
@@ -61,7 +61,7 @@
 struct file_operations sgi_gfx_fops = {
 	ioctl:		sgi_gfx_ioctl,
 };
- 
+
 static struct miscdevice dev_gfx = {
 	SGI_GFX_MINOR, "sgi-gfx", &sgi_gfx_fops
 };
@@ -83,12 +83,12 @@
 sgi_kbd_sioc (idevInfo *dinfo, int cmd, int size, char *data, int *found)
 {
 	*found = 1;
-	
+
 	switch (cmd){
 
 	case IDEVINITDEVICE:
 		return 0;
-			
+
 	case IDEVGETDEVICEDESC:
 		if (size >= sizeof (idevDesc)){
 			if (copy_to_user (data, &sgi_kbd_desc, sizeof (sgi_kbd_desc)))
@@ -114,7 +114,7 @@
 {
 	struct strioctl sioc;
 	int    f, v;
-	
+
 	/* IRIX calls I_PUSH on the opened device, go figure */
 	if (cmd == I_PUSH)
 		return 0;
@@ -129,16 +129,16 @@
 		 * call a stock IRIX xxx_wioctl routine
 		 *
 		 * The NULL is supposed to be a idevInfo, right now we
-		 * do not support this in our kernel.  
+		 * do not support this in our kernel.
 		 */
 		return sgi_kbd_sioc (NULL, sioc.ic_cmd, sioc.ic_len, sioc.ic_dp, &f);
 	}
-	
+
 	if (cmd == SHMIQ_ON){
 		kbd_assigned_device = arg;
 		forward_chars = fg_console + 1;
 		kbd_prev_mode = kbd_table [fg_console].kbdmode;
-		
+
 	        kbd_table [fg_console].kbdmode = VC_RAW;
 	} else if (cmd == SHMIQ_OFF && forward_chars){
 		kbd_table [forward_chars-1].kbdmode = kbd_prev_mode;
@@ -203,15 +203,15 @@
 
 static int mouse_opened;
 static idevValuatorDesc mouse_valuators [MOUSE_VALUATORS];
-	
+
 int
 sgi_mouse_open (struct inode *inode, struct file *file)
 {
 	int i;
-	
+
 	if (mouse_opened)
 		return -EBUSY;
-	
+
 	mouse_opened = 1;
 	for (i = 0; i < MOUSE_VALUATORS; i++)
 		mouse_valuators [i] = mouse_default_valuator;
@@ -235,7 +235,7 @@
 	switch (cmd){
 	case IDEVINITDEVICE:
 		return 0;
-			
+
 	case IDEVGETDEVICEDESC:
 		if (size >= sizeof (idevDesc)){
 			if (copy_to_user (data, &sgi_mouse_desc, sizeof (sgi_mouse_desc)))
@@ -246,7 +246,7 @@
 
 	case IDEVGETVALUATORDESC: {
 		idevGetSetValDesc request, *ureq = (idevGetSetValDesc *) data;
-		
+
 		if (size < sizeof (idevGetSetValDesc))
 			return -EINVAL;
 
@@ -254,7 +254,7 @@
 			return -EFAULT;
 		if (request.valNum >= MOUSE_VALUATORS)
 			return -EINVAL;
-		if (copy_to_user ((void *)&ureq->desc, 
+		if (copy_to_user ((void *)&ureq->desc,
 				  (void *)&mouse_valuators [request.valNum],
 				  sizeof (idevValuatorDesc)))
 			return -EFAULT;
@@ -280,16 +280,16 @@
 		v = get_sioc (&sioc, arg);
 		if (v)
 			return v;
-		
+
 		/* Why like this?  Because this is a sample piece of code
 		 * that can be copied into other drivers and shows how to
 		 * call a stock IRIX xxx_wioctl routine
 		 *
 		 * The NULL is supposed to be a idevInfo, right now we
-		 * do not support this in our kernel.  
+		 * do not support this in our kernel.
 		 */
 		return sgi_mouse_sioc (NULL, sioc.ic_cmd, sioc.ic_len, sioc.ic_dp, &f);
-		
+
 	case SHMIQ_ON:
 	case SHMIQ_OFF:
 		return 0;
@@ -313,7 +313,7 @@
 {
 	printk ("streamable misc devices registered (keyb:%d, gfx:%d)\n",
 		SGI_STREAMS_KEYBOARD, SGI_GFX_MINOR);
-	
+
 	misc_register (&dev_gfx);
 	misc_register (&dev_input_keyboard);
 	misc_register (&dev_input_mouse);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sgi/char/usema.c linux-2.4.20/drivers/sgi/char/usema.c
--- linux-2.4.19/drivers/sgi/char/usema.c	2001-08-27 15:56:31.000000000 +0000
+++ linux-2.4.20/drivers/sgi/char/usema.c	2002-10-29 11:18:39.000000000 +0000
@@ -18,7 +18,7 @@
  *
  * For more information:
  * usema(7m), usinit(3p), usnewsema(3p)
- * /usr/include/sys/usioctl.h 
+ * /usr/include/sys/usioctl.h
  *
  */
 #include <linux/fs.h>
@@ -52,7 +52,7 @@
 	newfd = get_unused_fd();
 	if (newfd < 0)
 		return newfd;
-	
+
 	get_file(usema->filp);
 	fd_install(newfd, usema->filp);
 	/* Is that it? */
@@ -66,7 +66,7 @@
 {
 	struct irix_usema *usema = file->private_data;
 	int retval;
-	
+
 	printk("[%s:%d] wants ioctl 0x%xd (arg 0x%lx)",
 	       current->comm, current->pid, cmd, arg);
 
@@ -140,10 +140,10 @@
 sgi_usemaclone_poll(struct file *filp, poll_table *wait)
 {
 	struct irix_usema *usema = filp->private_data;
-	
+
 	printk("[%s:%d] wants to poll usema %p",
 	       current->comm, current->pid, usema);
-	
+
 	return 0;
 }
 
@@ -155,7 +155,7 @@
 	usema = kmalloc (sizeof (struct irix_usema), GFP_KERNEL);
 	if (!usema)
 		return -ENOMEM;
-	
+
 	usema->filp        = filp;
 	init_waitqueue_head(&usema->proc_list);
 	filp->private_data = usema;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sgi/char/usema.h linux-2.4.20/drivers/sgi/char/usema.h
--- linux-2.4.19/drivers/sgi/char/usema.h	1999-06-26 00:39:35.000000000 +0000
+++ linux-2.4.20/drivers/sgi/char/usema.h	2002-10-29 11:18:48.000000000 +0000
@@ -5,6 +5,6 @@
 #ifndef _SGI_USEMA_H
 #define _SGI_USEMA_H
 
-void usema_init (void); 
+void usema_init (void);
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/Config.in linux-2.4.20/drivers/sound/Config.in
--- linux-2.4.19/drivers/sound/Config.in	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/sound/Config.in	2002-10-29 11:18:49.000000000 +0000
@@ -6,6 +6,7 @@
 
 # Prompt user for primary drivers.
 
+dep_tristate '  ALi5455 audio support' CONFIG_SOUND_ALI5455 $CONFIG_SOUND $CONFIG_PCI
 dep_tristate '  BT878 audio dma' CONFIG_SOUND_BT878 $CONFIG_SOUND $CONFIG_PCI
 dep_tristate '  C-Media PCI (CMI8338/8738)' CONFIG_SOUND_CMPCI $CONFIG_SOUND $CONFIG_PCI
 if [ "$CONFIG_SOUND_CMPCI" = "y" -o "$CONFIG_SOUND_CMPCI" = "m" ]; then
@@ -42,7 +43,11 @@
 dep_tristate '  ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND $CONFIG_PCI
 dep_tristate '  ESS Maestro, Maestro2, Maestro2E driver' CONFIG_SOUND_MAESTRO $CONFIG_SOUND $CONFIG_PCI
 dep_tristate '  ESS Maestro3/Allegro driver (EXPERIMENTAL)' CONFIG_SOUND_MAESTRO3 $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL
-dep_tristate '  Intel ICH (i8xx), SiS 7012, NVidia nForce Audio or AMD 768' CONFIG_SOUND_ICH $CONFIG_PCI
+dep_tristate '  ForteMedia FM801 driver (EXPERIMENTAL)' CONFIG_SOUND_FORTE $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL
+dep_tristate '  Intel ICH (i8xx), SiS 7012, NVidia nForce Audio or AMD 768/811x' CONFIG_SOUND_ICH $CONFIG_PCI
+if [ "$CONFIG_GSC_LASI" = "y" ]; then
+   dep_tristate '  PA Harmony audio driver' CONFIG_SOUND_HARMONY $CONFIG_SOUND
+fi
 if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then
     dep_tristate '  IT8172G Sound' CONFIG_SOUND_IT8172 $CONFIG_SOUND
 fi
@@ -207,7 +212,7 @@
          bool '      Audio Excel DSP 16 (MPU401 emulation)' CONFIG_AEDSP16_MPU401
       fi
    fi
-	 
+
    if [ "$CONFIG_ARM" = "y" ]; then
       if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" ]; then
          dep_tristate '    VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/Makefile linux-2.4.20/drivers/sound/Makefile
--- linux-2.4.19/drivers/sound/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/sound/Makefile	2002-10-29 11:18:35.000000000 +0000
@@ -22,6 +22,7 @@
 
 obj-$(CONFIG_SOUND_HAL2)	+= hal2.o
 obj-$(CONFIG_SOUND_AEDSP16)	+= aedsp16.o
+obj-$(CONFIG_SOUND_ALI5455)	+= ali5455.o ac97_codec.o
 obj-$(CONFIG_SOUND_PSS)		+= pss.o ad1848.o mpu401.o
 obj-$(CONFIG_SOUND_TRIX)	+= trix.o ad1848.o sb_lib.o uart401.o
 obj-$(CONFIG_SOUND_OPL3SA1)	+= opl3sa.o ad1848.o uart401.o
@@ -70,7 +71,9 @@
 obj-$(CONFIG_SOUND_FUSION)	+= cs46xx.o ac97_codec.o
 obj-$(CONFIG_SOUND_MAESTRO)	+= maestro.o
 obj-$(CONFIG_SOUND_MAESTRO3)	+= maestro3.o ac97_codec.o
+obj-$(CONFIG_SOUND_FORTE)	+= forte.o ac97_codec.o
 obj-$(CONFIG_SOUND_TRIDENT)	+= trident.o ac97_codec.o
+obj-$(CONFIG_SOUND_HARMONY)	+= harmony.o
 obj-$(CONFIG_SOUND_EMU10K1)	+= ac97_codec.o
 obj-$(CONFIG_SOUND_BCM_CS4297A)	+= swarm_cs4297a.o
 obj-$(CONFIG_SOUND_RME96XX)     += rme96xx.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/ac97_codec.c linux-2.4.20/drivers/sound/ac97_codec.c
--- linux-2.4.19/drivers/sound/ac97_codec.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/sound/ac97_codec.c	2002-10-29 11:18:33.000000000 +0000
@@ -654,6 +654,27 @@
 }
 
 /**
+ *	codec_id	-  Turn id1/id2 into a PnP string
+ *	@id1: Vendor ID1
+ *	@id2: Vendor ID2
+ *	@buf: 10 byte buffer
+ *
+ *	Fills buf with a zero terminated PnP ident string for the id1/id2
+ *	pair. For convenience the return is the passed in buffer pointer.
+ */
+ 
+static char *codec_id(u16 id1, u16 id2, char *buf)
+{
+	if(id1&0x8080)
+		snprintf(buf, 10, "%0x4X:%0x4X", id1, id2);
+	buf[0] = (id1 >> 8);
+	buf[1] = (id1 & 0xFF);
+	buf[2] = (id2 >> 8);
+	snprintf(buf+3, 7, "%d", id2&0xFF);
+	return buf;
+}
+ 
+/**
  *	ac97_probe_codec - Initialize and setup AC97-compatible codec
  *	@codec: (in/out) Kernel info for a single AC97 codec
  *
@@ -681,6 +702,7 @@
 	u16 id1, id2;
 	u16 audio, modem;
 	int i;
+	char cidbuf[10];
 
 	/* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should 
 	 * be read zero.
@@ -698,13 +720,16 @@
 
 	if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) {
 		printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n",
-		       codec->id ? "Secondary" : "Primary");
+		       (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary") 
+		       : (codec->id&1 ? "Secondary":  "Primary"));
 		return 0;
 	}
 
 	/* probe for Modem Codec */
 	codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0L);
-	modem = codec->codec_read(codec, AC97_EXTENDED_MODEM_ID);
+	modem = codec->codec_read(codec, AC97_EXTENDED_MODEM_ID) & 1;
+	modem |= (audio&2);
+	audio &= ~2;
 
 	codec->name = NULL;
 	codec->codec_ops = &null_ops;
@@ -721,9 +746,9 @@
 	}
 	if (codec->name == NULL)
 		codec->name = "Unknown";
-	printk(KERN_INFO "ac97_codec: AC97 %s codec, id: 0x%04x:"
-	       "0x%04x (%s)\n", audio ? "Audio" : (modem ? "Modem" : ""),
-	       id1, id2, codec->name);
+	printk(KERN_INFO "ac97_codec: AC97 %s codec, id: %s(%s)\n", 
+		modem ? "Modem" : (audio ? "Audio" : ""),
+	       codec_id(id1, id2, cidbuf), codec->name);
 
 	return ac97_init_mixer(codec);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/ali5455.c linux-2.4.20/drivers/sound/ali5455.c
--- linux-2.4.19/drivers/sound/ali5455.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/sound/ali5455.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,3731 @@
+/*
+ *	ALI  ali5455 and friends ICH driver for Linux
+ *	LEI HU <Lei_Hu@ali.com.tw>
+ *
+ *  Built from:
+ *	drivers/sound/i810_audio
+ *
+ *  	The ALi 5455 is similar but not quite identical to the Intel ICH
+ *	series of controllers. Its easier to keep the driver seperated from
+ *	the i810 driver.
+ *
+ *	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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *	ALi 5455 theory of operation
+ *
+ *	The chipset provides three DMA channels that talk to an AC97
+ *	CODEC (AC97 is a digital/analog mixer standard). At its simplest
+ *	you get 48Khz audio with basic volume and mixer controls. At the
+ *	best you get rate adaption in the codec. We set the card up so
+ *	that we never take completion interrupts but instead keep the card
+ *	chasing its tail around a ring buffer. This is needed for mmap
+ *	mode audio and happens to work rather well for non-mmap modes too.
+ *
+ *	The board has one output channel for PCM audio (supported) and
+ *	a stereo line in and mono microphone input. Again these are normally
+ *	locked to 48Khz only. Right now recording is not finished.
+ *
+ *	There is no midi support, no synth support. Use timidity. To get
+ *	esd working you need to use esd -r 48000 as it won't probe 48KHz
+ *	by default. mpg123 can't handle 48Khz only audio so use xmms.
+ *
+ *	If you need to force a specific rate set the clocking= option
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/sound.h>
+#include <linux/slab.h>
+#include <linux/soundcard.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/ac97_codec.h>
+#include <linux/wrapper.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+
+#ifndef PCI_DEVICE_ID_ALI_5455
+#define PCI_DEVICE_ID_ALI_5455	0x5455
+#endif
+
+#ifndef PCI_VENDOR_ID_ALI
+#define PCI_VENDOR_ID_ALI	0x10b9
+#endif
+
+static int strict_clocking = 0;
+static unsigned int clocking = 0;
+static unsigned int codec_pcmout_share_spdif_locked = 0;
+static unsigned int codec_independent_spdif_locked = 0;
+static unsigned int controller_pcmout_share_spdif_locked = 0;
+static unsigned int controller_independent_spdif_locked = 0;
+static unsigned int globel = 0;
+
+#define ADC_RUNNING	1
+#define DAC_RUNNING	2
+#define CODEC_SPDIFOUT_RUNNING 8
+#define CONTROLLER_SPDIFOUT_RUNNING 4
+
+#define SPDIF_ENABLE_OUTPUT	4	/* bits 0,1 are PCM */
+
+#define ALI5455_FMT_16BIT	1
+#define ALI5455_FMT_STEREO	2
+#define ALI5455_FMT_MASK	3
+
+#define SPDIF_ON	0x0004
+#define SURR_ON		0x0010
+#define CENTER_LFE_ON	0x0020
+#define VOL_MUTED	0x8000
+
+
+#define ALI_SPDIF_OUT_CH_STATUS 0xbf
+/* the 810's array of pointers to data buffers */
+
+struct sg_item {
+#define BUSADDR_MASK	0xFFFFFFFE
+	u32 busaddr;
+#define CON_IOC 	0x80000000	/* interrupt on completion */
+#define CON_BUFPAD	0x40000000	/* pad underrun with last sample, else 0 */
+#define CON_BUFLEN_MASK	0x0000ffff	/* buffer length in samples */
+	u32 control;
+};
+
+/* an instance of the ali channel */
+#define SG_LEN 32
+struct ali_channel {
+	/* these sg guys should probably be allocated
+	   seperately as nocache. Must be 8 byte aligned */
+	struct sg_item sg[SG_LEN];	/* 32*8 */
+	u32 offset;		/* 4 */
+	u32 port;		/* 4 */
+	u32 used;
+	u32 num;
+};
+
+/*
+ * we have 3 seperate dma engines.  pcm in, pcm out, and mic.
+ * each dma engine has controlling registers.  These goofy
+ * names are from the datasheet, but make it easy to write
+ * code while leafing through it.
+ */
+
+#define ENUM_ENGINE(PRE,DIG) 									\
+enum {												\
+	PRE##_BDBAR =	0x##DIG##0,		/* Buffer Descriptor list Base Address */	\
+	PRE##_CIV =	0x##DIG##4,		/* Current Index Value */			\
+	PRE##_LVI =	0x##DIG##5,		/* Last Valid Index */				\
+	PRE##_SR =	0x##DIG##6,		/* Status Register */				\
+	PRE##_PICB =	0x##DIG##8,		/* Position In Current Buffer */		\
+	PRE##_CR =	0x##DIG##b		/* Control Register */				\
+}
+
+ENUM_ENGINE(OFF, 0);		/* Offsets */
+ENUM_ENGINE(PI, 4);		/* PCM In */
+ENUM_ENGINE(PO, 5);		/* PCM Out */
+ENUM_ENGINE(MC, 6);		/* Mic In */
+ENUM_ENGINE(CODECSPDIFOUT, 7);	/* CODEC SPDIF OUT  */
+ENUM_ENGINE(CONTROLLERSPDIFIN, A);	/* CONTROLLER SPDIF In */
+ENUM_ENGINE(CONTROLLERSPDIFOUT, B);	/* CONTROLLER SPDIF OUT */
+
+
+enum {
+	ALI_SCR = 0x00,		/* System Control Register */
+	ALI_SSR = 0x04,		/* System Status Register  */
+	ALI_DMACR = 0x08,	/* DMA Control Register    */
+	ALI_FIFOCR1 = 0x0c,	/* FIFO Control Register 1  */
+	ALI_INTERFACECR = 0x10,	/* Interface Control Register */
+	ALI_INTERRUPTCR = 0x14,	/* Interrupt control Register */
+	ALI_INTERRUPTSR = 0x18,	/* Interrupt  Status Register */
+	ALI_FIFOCR2 = 0x1c,	/* FIFO Control Register 2   */
+	ALI_CPR = 0x20,		/* Command Port Register     */
+	ALI_SPR = 0x24,		/* Status Port Register      */
+	ALI_FIFOCR3 = 0x2c,	/* FIFO Control Register 3  */
+	ALI_TTSR = 0x30,	/* Transmit Tag Slot Register */
+	ALI_RTSR = 0x34,	/* Receive Tag Slot  Register */
+	ALI_CSPSR = 0x38,	/* Command/Status Port Status Register */
+	ALI_CAS = 0x3c,		/* Codec Write Semaphore Register */
+	ALI_SPDIFCSR = 0xf8,	/* spdif channel status register  */
+	ALI_SPDIFICS = 0xfc	/* spdif interface control/status  */
+};
+
+// x-status register(x:pcm in ,pcm out, mic in,)
+/* interrupts for a dma engine */
+#define DMA_INT_FIFO		(1<<4)	/* fifo under/over flow */
+#define DMA_INT_COMPLETE	(1<<3)	/* buffer read/write complete and ioc set */
+#define DMA_INT_LVI		(1<<2)	/* last valid done */
+#define DMA_INT_CELV		(1<<1)	/* last valid is current */
+#define DMA_INT_DCH		(1)	/* DMA Controller Halted (happens on LVI interrupts) */	//not eqult intel
+#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)
+
+/* interrupts for the whole chip */// by interrupt status register finish
+
+#define INT_SPDIFOUT   (1<<23)	/* controller spdif out INTERRUPT */
+#define INT_SPDIFIN   (1<<22)
+#define INT_CODECSPDIFOUT   (1<<19)
+#define INT_MICIN   (1<<18)
+#define INT_PCMOUT   (1<<17)
+#define INT_PCMIN   (1<<16)
+#define INT_CPRAIS   (1<<7)
+#define INT_SPRAIS   (1<<5)
+#define INT_GPIO    (1<<1)
+#define INT_MASK   (INT_SPDIFOUT|INT_CODECSPDIFOUT|INT_MICIN|INT_PCMOUT|INT_PCMIN)
+
+#define DRIVER_VERSION "0.02ac"
+
+/* magic numbers to protect our data structures */
+#define ALI5455_CARD_MAGIC		0x5072696E	/* "Prin" */
+#define ALI5455_STATE_MAGIC		0x63657373	/* "cess" */
+#define ALI5455_DMA_MASK		0xffffffff	/* DMA buffer mask for pci_alloc_consist */
+#define NR_HW_CH			5	//I think 5 channel
+
+/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
+#define NR_AC97		2
+
+/* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */
+/* stream at a minimum for this card to be happy */
+static const unsigned sample_size[] = { 1, 2, 2, 4 };
+/* Samples are 16bit values, so we are shifting to a word, not to a byte, hence shift */
+/* values are one less than might be expected */
+static const unsigned sample_shift[] = { -1, 0, 0, 1 };
+
+#define ALI5455
+static char *card_names[] = {
+	"ALI 5455"
+};
+
+static struct pci_device_id ali_pci_tbl[] __initdata = {
+	{PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5455,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALI5455},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, ali_pci_tbl);
+
+#ifdef CONFIG_PM
+#define PM_SUSPENDED(card) (card->pm_suspended)
+#else
+#define PM_SUSPENDED(card) (0)
+#endif
+
+/* "software" or virtual channel, an instance of opened /dev/dsp */
+struct ali_state {
+	unsigned int magic;
+	struct ali_card *card;	/* Card info */
+
+	/* single open lock mechanism, only used for recording */
+	struct semaphore open_sem;
+	wait_queue_head_t open_wait;
+
+	/* file mode */
+	mode_t open_mode;
+
+	/* virtual channel number */
+	int virt;
+
+#ifdef CONFIG_PM
+	unsigned int pm_saved_dac_rate, pm_saved_adc_rate;
+#endif
+	struct dmabuf {
+		/* wave sample stuff */
+		unsigned int rate;
+		unsigned char fmt, enable, trigger;
+
+		/* hardware channel */
+		struct ali_channel *read_channel;
+		struct ali_channel *write_channel;
+		struct ali_channel *codec_spdifout_channel;
+		struct ali_channel *controller_spdifout_channel;
+
+		/* OSS buffer management stuff */
+		void *rawbuf;
+		dma_addr_t dma_handle;
+		unsigned buforder;
+		unsigned numfrag;
+		unsigned fragshift;
+
+		/* our buffer acts like a circular ring */
+		unsigned hwptr;	/* where dma last started, updated by update_ptr */
+		unsigned swptr;	/* where driver last clear/filled, updated by read/write */
+		int count;	/* bytes to be consumed or been generated by dma machine */
+		unsigned total_bytes;	/* total bytes dmaed by hardware */
+
+		unsigned error;	/* number of over/underruns */
+		wait_queue_head_t wait;	/* put process on wait queue when no more space in buffer */
+
+		/* redundant, but makes calculations easier */
+		/* what the hardware uses */
+		unsigned dmasize;
+		unsigned fragsize;
+		unsigned fragsamples;
+
+		/* what we tell the user to expect */
+		unsigned userfrags;
+		unsigned userfragsize;
+
+		/* OSS stuff */
+		unsigned mapped:1;
+		unsigned ready:1;
+		unsigned update_flag;
+		unsigned ossfragsize;
+		unsigned ossmaxfrags;
+		unsigned subdivision;
+	} dmabuf;
+};
+
+
+struct ali_card {
+	struct ali_channel channel[5];
+	unsigned int magic;
+
+	/* We keep ali5455 cards in a linked list */
+	struct ali_card *next;
+
+	/* The ali has a certain amount of cross channel interaction
+	   so we use a single per card lock */
+	spinlock_t lock;
+
+	/* PCI device stuff */
+	struct pci_dev *pci_dev;
+	u16 pci_id;
+#ifdef CONFIG_PM
+	u16 pm_suspended;
+	u32 pm_save_state[64 / sizeof(u32)];
+	int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97];
+#endif
+	/* soundcore stuff */
+	int dev_audio;
+
+	/* structures for abstraction of hardware facilities, codecs, banks and channels */
+	struct ac97_codec *ac97_codec[NR_AC97];
+	struct ali_state *states[NR_HW_CH];
+
+	u16 ac97_features;
+	u16 ac97_status;
+	u16 channels;
+
+	/* hardware resources */
+	unsigned long iobase;
+
+	u32 irq;
+
+	/* Function support */
+	struct ali_channel *(*alloc_pcm_channel) (struct ali_card *);
+	struct ali_channel *(*alloc_rec_pcm_channel) (struct ali_card *);
+	struct ali_channel *(*alloc_rec_mic_channel) (struct ali_card *);
+	struct ali_channel *(*alloc_codec_spdifout_channel) (struct ali_card *);
+	struct ali_channel *(*alloc_controller_spdifout_channel) (struct  ali_card *);
+	void (*free_pcm_channel) (struct ali_card *, int chan);
+
+	/* We have a *very* long init time possibly, so use this to block */
+	/* attempts to open our devices before we are ready (stops oops'es) */
+	int initializing;
+};
+
+
+static struct ali_card *devs = NULL;
+
+static int ali_open_mixdev(struct inode *inode, struct file *file);
+static int ali_ioctl_mixdev(struct inode *inode, struct file *file,
+			    unsigned int cmd, unsigned long arg);
+static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg);
+static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
+
+static struct ali_channel *ali_alloc_pcm_channel(struct ali_card *card)
+{
+	if (card->channel[1].used == 1)
+		return NULL;
+	card->channel[1].used = 1;
+	return &card->channel[1];
+}
+
+static struct ali_channel *ali_alloc_rec_pcm_channel(struct ali_card *card)
+{
+	if (card->channel[0].used == 1)
+		return NULL;
+	card->channel[0].used = 1;
+	return &card->channel[0];
+}
+
+static struct ali_channel *ali_alloc_rec_mic_channel(struct ali_card *card)
+{
+	if (card->channel[2].used == 1)
+		return NULL;
+	card->channel[2].used = 1;
+	return &card->channel[2];
+}
+
+static struct ali_channel *ali_alloc_codec_spdifout_channel(struct ali_card *card)
+{
+	if (card->channel[3].used == 1)
+		return NULL;
+	card->channel[3].used = 1;
+	return &card->channel[3];
+}
+
+static struct ali_channel *ali_alloc_controller_spdifout_channel(struct ali_card *card)
+{
+	if (card->channel[4].used == 1)
+		return NULL;
+	card->channel[4].used = 1;
+	return &card->channel[4];
+}
+static void ali_free_pcm_channel(struct ali_card *card, int channel)
+{
+	card->channel[channel].used = 0;
+}
+
+
+//add support  codec spdif out 
+static int ali_valid_spdif_rate(struct ac97_codec *codec, int rate)
+{
+	unsigned long id = 0L;
+
+	id = (ali_ac97_get(codec, AC97_VENDOR_ID1) << 16);
+	id |= ali_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff;
+	switch (id) {
+	case 0x41445361:	/* AD1886 */
+		if (rate == 48000) {
+			return 1;
+		}
+		break;
+	case 0x414c4720:	/* ALC650 */
+		if (rate == 48000) {
+			return 1;
+		}
+		break;
+	default:		/* all other codecs, until we know otherwiae */
+		if (rate == 48000 || rate == 44100 || rate == 32000) {
+			return 1;
+		}
+		break;
+	}
+	return (0);
+}
+
+/* ali_set_spdif_output
+ * 
+ *  Configure the S/PDIF output transmitter. When we turn on
+ *  S/PDIF, we turn off the analog output. This may not be
+ *  the right thing to do.
+ *
+ *  Assumptions:
+ *     The DSP sample rate must already be set to a supported
+ *     S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort.
+ */
+static void ali_set_spdif_output(struct ali_state *state, int slots,
+				 int rate)
+{
+	int vol;
+	int aud_reg;
+	struct ac97_codec *codec = state->card->ac97_codec[0];
+
+	if (!(state->card->ac97_features & 4)) {
+		state->card->ac97_status &= ~SPDIF_ON;
+	} else {
+		if (slots == -1) {	/* Turn off S/PDIF */
+			aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
+			ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
+
+			/* If the volume wasn't muted before we turned on S/PDIF, unmute it */
+			if (!(state->card->ac97_status & VOL_MUTED)) {
+				aud_reg = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO);
+				ali_ac97_set(codec, AC97_MASTER_VOL_STEREO,
+					     (aud_reg & ~VOL_MUTED));
+			}
+			state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);
+			return;
+		}
+
+		vol = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO);
+		state->card->ac97_status = vol & VOL_MUTED;
+
+		/* Set S/PDIF transmitter sample rate */
+		aud_reg = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
+		switch (rate) {
+		case 32000:
+			aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K;
+			break;
+		case 44100:
+			aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K;
+			break;
+		case 48000:
+			aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K;
+			break;
+		default:
+			/* turn off S/PDIF */
+			aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
+			ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
+			state->card->ac97_status &= ~SPDIF_ON;
+			return;
+		}
+
+		ali_ac97_set(codec, AC97_SPDIF_CONTROL, aud_reg);
+
+		aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
+		aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_SPDIF;
+		ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
+
+		aud_reg = ali_ac97_get(codec, AC97_POWER_CONTROL);
+		aud_reg |= 0x0002;
+		ali_ac97_set(codec, AC97_POWER_CONTROL, aud_reg);
+		udelay(1);
+
+		state->card->ac97_status |= SPDIF_ON;
+
+		/* Check to make sure the configuration is valid */
+		aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
+		if (!(aud_reg & 0x0400)) {
+			/* turn off S/PDIF */
+			ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
+			state->card->ac97_status &= ~SPDIF_ON;
+			return;
+		}
+		if (codec_independent_spdif_locked > 0) {
+			aud_reg = ali_ac97_get(codec, 0x6a);
+			ali_ac97_set(codec, 0x6a, (aud_reg & 0xefff));
+		}
+		/* Mute the analog output */
+		/* Should this only mute the PCM volume??? */
+	}
+}
+
+/* ali_set_dac_channels
+ *
+ *  Configure the codec's multi-channel DACs
+ *
+ *  The logic is backwards. Setting the bit to 1 turns off the DAC. 
+ *
+ *  What about the ICH? We currently configure it using the
+ *  SNDCTL_DSP_CHANNELS ioctl.  If we're turnning on the DAC, 
+ *  does that imply that we want the ICH set to support
+ *  these channels?
+ *  
+ *  TODO:
+ *    vailidate that the codec really supports these DACs
+ *    before turning them on. 
+ */
+static void ali_set_dac_channels(struct ali_state *state, int channel)
+{
+	int aud_reg;
+	struct ac97_codec *codec = state->card->ac97_codec[0];
+
+	aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
+	aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK;
+	state->card->ac97_status &= ~(SURR_ON | CENTER_LFE_ON);
+
+	switch (channel) {
+	case 2:		/* always enabled */
+		break;
+	case 4:
+		aud_reg &= ~AC97_EA_PRJ;
+		state->card->ac97_status |= SURR_ON;
+		break;
+	case 6:
+		aud_reg &= ~(AC97_EA_PRJ | AC97_EA_PRI | AC97_EA_PRK);
+		state->card->ac97_status |= SURR_ON | CENTER_LFE_ON;
+		break;
+	default:
+		break;
+	}
+	ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
+
+}
+
+/* set playback sample rate */
+static unsigned int ali_set_dac_rate(struct ali_state *state,
+				     unsigned int rate)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	u32 new_rate;
+	struct ac97_codec *codec = state->card->ac97_codec[0];
+
+	if (!(state->card->ac97_features & 0x0001)) {
+		dmabuf->rate = clocking;
+		return clocking;
+	}
+
+	if (rate > 48000)
+		rate = 48000;
+	if (rate < 8000)
+		rate = 8000;
+	dmabuf->rate = rate;
+
+	/*
+	 *      Adjust for misclocked crap
+	 */
+
+	rate = (rate * clocking) / 48000;
+
+	if (strict_clocking && rate < 8000) {
+		rate = 8000;
+		dmabuf->rate = (rate * 48000) / clocking;
+	}
+
+	new_rate = ac97_set_dac_rate(codec, rate);
+	if (new_rate != rate) {
+		dmabuf->rate = (new_rate * 48000) / clocking;
+	}
+	rate = new_rate;
+	return dmabuf->rate;
+}
+
+/* set recording sample rate */
+static unsigned int ali_set_adc_rate(struct ali_state *state,
+				     unsigned int rate)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	u32 new_rate;
+	struct ac97_codec *codec = state->card->ac97_codec[0];
+
+	if (!(state->card->ac97_features & 0x0001)) {
+		dmabuf->rate = clocking;
+		return clocking;
+	}
+
+	if (rate > 48000)
+		rate = 48000;
+	if (rate < 8000)
+		rate = 8000;
+	dmabuf->rate = rate;
+
+	/*
+	 *      Adjust for misclocked crap
+	 */
+
+	rate = (rate * clocking) / 48000;
+	if (strict_clocking && rate < 8000) {
+		rate = 8000;
+		dmabuf->rate = (rate * 48000) / clocking;
+	}
+
+	new_rate = ac97_set_adc_rate(codec, rate);
+
+	if (new_rate != rate) {
+		dmabuf->rate = (new_rate * 48000) / clocking;
+		rate = new_rate;
+	}
+	return dmabuf->rate;
+}
+
+/* set codec independent spdifout sample rate */
+static unsigned int ali_set_codecspdifout_rate(struct ali_state *state,
+					       unsigned int rate)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+
+	if (!(state->card->ac97_features & 0x0001)) {
+		dmabuf->rate = clocking;
+		return clocking;
+	}
+
+	if (rate > 48000)
+		rate = 48000;
+	if (rate < 8000)
+		rate = 8000;
+	dmabuf->rate = rate;
+
+	return dmabuf->rate;
+}
+
+/* set  controller independent spdif out function sample rate */
+static void ali_set_spdifout_rate(struct ali_state *state,
+				  unsigned int rate)
+{
+	unsigned char ch_st_sel;
+	unsigned short status_rate;
+
+	switch (rate) {
+	case 44100:
+		status_rate = 0;
+		break;
+	case 32000:
+		status_rate = 0x300;
+		break;
+	case 48000:
+	default:
+		status_rate = 0x200;
+		break;
+	}
+
+	ch_st_sel = inb(state->card->iobase + ALI_SPDIFICS) & ALI_SPDIF_OUT_CH_STATUS;	//select spdif_out
+
+	ch_st_sel |= 0x80;	//select right
+	outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS));
+	outb(status_rate | 0x20, (state->card->iobase + ALI_SPDIFCSR + 2));
+
+	ch_st_sel &= (~0x80);	//select left
+	outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS));
+	outw(status_rate | 0x10, (state->card->iobase + ALI_SPDIFCSR + 2));
+}
+
+/* get current playback/recording dma buffer pointer (byte offset from LBA),
+   called with spinlock held! */
+
+static inline unsigned ali_get_dma_addr(struct ali_state *state, int rec)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned int civ, offset, port, port_picb;
+	unsigned int data;
+
+	if (!dmabuf->enable)
+		return 0;
+
+	if (rec == 1)
+		port = state->card->iobase + dmabuf->read_channel->port;
+	else if (rec == 2)
+		port = state->card->iobase + dmabuf->codec_spdifout_channel->port;
+	else if (rec == 3)
+		port = state->card->iobase + dmabuf->controller_spdifout_channel->port;
+	else
+		port = state->card->iobase + dmabuf->write_channel->port;
+
+	port_picb = port + OFF_PICB;
+
+	do {
+		civ = inb(port + OFF_CIV) & 31;
+		offset = inw(port_picb);
+		/* Must have a delay here! */
+		if (offset == 0)
+			udelay(1);
+
+		/* Reread both registers and make sure that that total
+		 * offset from the first reading to the second is 0.
+		 * There is an issue with SiS hardware where it will count
+		 * picb down to 0, then update civ to the next value,
+		 * then set the new picb to fragsize bytes.  We can catch
+		 * it between the civ update and the picb update, making
+		 * it look as though we are 1 fragsize ahead of where we
+		 * are.  The next to we get the address though, it will
+		 * be back in thdelay is more than long enough
+		 * that we won't have to worry about the chip still being
+		 * out of sync with reality ;-)
+		 */
+	} while (civ != (inb(port + OFF_CIV) & 31) || offset != inw(port_picb));
+
+	data = ((civ + 1) * dmabuf->fragsize - (2 * offset)) % dmabuf->dmasize;
+	if (inw(port_picb) == 0)
+		data -= 2048;
+
+	return data;
+}
+
+/* Stop recording (lock held) */
+static inline void __stop_adc(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct ali_card *card = state->card;
+
+	dmabuf->enable &= ~ADC_RUNNING;
+
+	outl((1 << 18) | (1 << 16), card->iobase + ALI_DMACR);
+	udelay(1);
+
+	outb(0, card->iobase + PI_CR);
+	while (inb(card->iobase + PI_CR) != 0);
+
+	// now clear any latent interrupt bits (like the halt bit)
+	outb(inb(card->iobase + PI_SR) | 0x001e, card->iobase + PI_SR);
+	outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMIN, card->iobase + ALI_INTERRUPTSR);
+}
+
+static void stop_adc(struct ali_state *state)
+{
+	struct ali_card *card = state->card;
+	unsigned long flags;
+	spin_lock_irqsave(&card->lock, flags);
+	__stop_adc(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static inline void __start_adc(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+
+	if (dmabuf->count < dmabuf->dmasize && dmabuf->ready
+	    && !dmabuf->enable && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
+		dmabuf->enable |= ADC_RUNNING;
+		outb((1 << 4) | (1 << 2), state->card->iobase + PI_CR);
+		if (state->card->channel[0].used == 1)
+			outl(1, state->card->iobase + ALI_DMACR);	// DMA CONTROL REGISTRER
+		udelay(100);
+		if (state->card->channel[2].used == 1)
+			outl((1 << 2), state->card->iobase + ALI_DMACR);	//DMA CONTROL REGISTER
+		udelay(100);
+	}
+}
+
+static void start_adc(struct ali_state *state)
+{
+	struct ali_card *card = state->card;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	__start_adc(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/* stop playback (lock held) */
+static inline void __stop_dac(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct ali_card *card = state->card;
+
+	dmabuf->enable &= ~DAC_RUNNING;
+	outl(0x00020000, card->iobase + 0x08);
+	outb(0, card->iobase + PO_CR);
+	while (inb(card->iobase + PO_CR) != 0)
+		cpu_relax();
+
+	outb(inb(card->iobase + PO_SR) | 0x001e, card->iobase + PO_SR);
+
+	outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMOUT, card->iobase + ALI_INTERRUPTSR);
+}
+
+static void stop_dac(struct ali_state *state)
+{
+	struct ali_card *card = state->card;
+	unsigned long flags;
+	spin_lock_irqsave(&card->lock, flags);
+	__stop_dac(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static inline void __start_dac(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
+	    (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
+		dmabuf->enable |= DAC_RUNNING;
+		outb((1 << 4) | (1 << 2), state->card->iobase + PO_CR);
+		outl((1 << 1), state->card->iobase + 0x08);	//dma control register
+	}
+}
+
+static void start_dac(struct ali_state *state)
+{
+	struct ali_card *card = state->card;
+	unsigned long flags;
+	spin_lock_irqsave(&card->lock, flags);
+	__start_dac(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/* stop codec and controller spdif out  (lock held) */
+static inline void __stop_spdifout(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct ali_card *card = state->card;
+
+	if (codec_independent_spdif_locked > 0) {
+		dmabuf->enable &= ~CODEC_SPDIFOUT_RUNNING;
+		outl((1 << 19), card->iobase + 0x08);
+		outb(0, card->iobase + CODECSPDIFOUT_CR);
+
+		while (inb(card->iobase + CODECSPDIFOUT_CR) != 0)
+			cpu_relax();
+
+		outb(inb(card->iobase + CODECSPDIFOUT_SR) | 0x001e, card->iobase + CODECSPDIFOUT_SR);
+		outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_CODECSPDIFOUT, card->iobase + ALI_INTERRUPTSR);
+	} else {
+		if (controller_independent_spdif_locked > 0) {
+			dmabuf->enable &= ~CONTROLLER_SPDIFOUT_RUNNING;
+			outl((1 << 23), card->iobase + 0x08);
+			outb(0, card->iobase + CONTROLLERSPDIFOUT_CR);
+			while (inb(card->iobase + CONTROLLERSPDIFOUT_CR) != 0)
+				cpu_relax();
+			outb(inb(card->iobase + CONTROLLERSPDIFOUT_SR) | 0x001e, card->iobase + CONTROLLERSPDIFOUT_SR);
+			outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_SPDIFOUT, card->iobase + ALI_INTERRUPTSR);
+		}
+	}
+}
+
+static void stop_spdifout(struct ali_state *state)
+{
+	struct ali_card *card = state->card;
+	unsigned long flags;
+	spin_lock_irqsave(&card->lock, flags);
+	__stop_spdifout(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static inline void __start_spdifout(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
+	    (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
+		if (codec_independent_spdif_locked > 0) {
+			dmabuf->enable |= CODEC_SPDIFOUT_RUNNING;
+			outb((1 << 4) | (1 << 2), state->card->iobase + CODECSPDIFOUT_CR);
+			outl((1 << 3), state->card->iobase + 0x08);	//dma control register
+		} else {
+			if (controller_independent_spdif_locked > 0) {
+				dmabuf->enable |= CONTROLLER_SPDIFOUT_RUNNING;
+				outb((1 << 4) | (1 << 2), state->card->iobase + CONTROLLERSPDIFOUT_CR);
+				outl((1 << 7), state->card->iobase + 0x08);	//dma control register
+			}
+		}
+	}
+}
+
+static void start_spdifout(struct ali_state *state)
+{
+	struct ali_card *card = state->card;
+	unsigned long flags;
+	spin_lock_irqsave(&card->lock, flags);
+	__start_spdifout(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
+#define DMABUF_MINORDER 1
+
+/* allocate DMA buffer, playback , recording,spdif out  buffer should be allocated seperately */
+static int alloc_dmabuf(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	void *rawbuf = NULL;
+	int order, size;
+	struct page *page, *pend;
+
+	/* If we don't have any oss frag params, then use our default ones */
+	if (dmabuf->ossmaxfrags == 0)
+		dmabuf->ossmaxfrags = 4;
+	if (dmabuf->ossfragsize == 0)
+		dmabuf->ossfragsize = (PAGE_SIZE << DMABUF_DEFAULTORDER) / dmabuf->ossmaxfrags;
+	size = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
+
+	if (dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size)
+		return 0;
+	/* alloc enough to satisfy the oss params */
+	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
+		if ((PAGE_SIZE << order) > size)
+			continue;
+		if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,
+						   PAGE_SIZE << order,
+						   &dmabuf->dma_handle)))
+			break;
+	}
+	if (!rawbuf)
+		return -ENOMEM;
+
+	dmabuf->ready = dmabuf->mapped = 0;
+	dmabuf->rawbuf = rawbuf;
+	dmabuf->buforder = order;
+
+	/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+	pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
+	for (page = virt_to_page(rawbuf); page <= pend; page++)
+		mem_map_reserve(page);
+	return 0;
+}
+
+/* free DMA buffer */
+static void dealloc_dmabuf(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct page *page, *pend;
+
+	if (dmabuf->rawbuf) {
+		/* undo marking the pages as reserved */
+		pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
+		for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
+			mem_map_unreserve(page);
+		pci_free_consistent(state->card->pci_dev,
+				    PAGE_SIZE << dmabuf->buforder,
+				    dmabuf->rawbuf, dmabuf->dma_handle);
+	}
+	dmabuf->rawbuf = NULL;
+	dmabuf->mapped = dmabuf->ready = 0;
+}
+
+static int prog_dmabuf(struct ali_state *state, unsigned rec)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct ali_channel *c = NULL;
+	struct sg_item *sg;
+	unsigned long flags;
+	int ret;
+	unsigned fragint;
+	int i;
+
+	spin_lock_irqsave(&state->card->lock, flags);
+	if (dmabuf->enable & DAC_RUNNING)
+		__stop_dac(state);
+	if (dmabuf->enable & ADC_RUNNING)
+		__stop_adc(state);
+	if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+		__stop_spdifout(state);
+	if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+		__stop_spdifout(state);
+
+	dmabuf->total_bytes = 0;
+	dmabuf->count = dmabuf->error = 0;
+	dmabuf->swptr = dmabuf->hwptr = 0;
+	spin_unlock_irqrestore(&state->card->lock, flags);
+
+	/* allocate DMA buffer, let alloc_dmabuf determine if we are already
+	 * allocated well enough or if we should replace the current buffer
+	 * (assuming one is already allocated, if it isn't, then allocate it).
+	 */
+	if ((ret = alloc_dmabuf(state)))
+		return ret;
+
+	/* FIXME: figure out all this OSS fragment stuff */
+	/* I did, it now does what it should according to the OSS API.  DL */
+	/* We may not have realloced our dmabuf, but the fragment size to
+	 * fragment number ratio may have changed, so go ahead and reprogram
+	 * things
+	 */
+
+	dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder;
+	dmabuf->numfrag = SG_LEN;
+	dmabuf->fragsize = dmabuf->dmasize / dmabuf->numfrag;
+	dmabuf->fragsamples = dmabuf->fragsize >> 1;
+	dmabuf->userfragsize = dmabuf->ossfragsize;
+	dmabuf->userfrags = dmabuf->dmasize / dmabuf->ossfragsize;
+
+	memset(dmabuf->rawbuf, 0, dmabuf->dmasize);
+
+	if (dmabuf->ossmaxfrags == 4) {
+		fragint = 8;
+		dmabuf->fragshift = 2;
+	} else if (dmabuf->ossmaxfrags == 8) {
+		fragint = 4;
+		dmabuf->fragshift = 3;
+	} else if (dmabuf->ossmaxfrags == 16) {
+		fragint = 2;
+		dmabuf->fragshift = 4;
+	} else {
+		fragint = 1;
+		dmabuf->fragshift = 5;
+	}
+	/*
+	 *      Now set up the ring 
+	 */
+
+	if (rec == 1)
+		c = dmabuf->read_channel;
+	else if (rec == 2)
+		c = dmabuf->codec_spdifout_channel;
+	else if (rec == 3)
+		c = dmabuf->controller_spdifout_channel;
+	else if (rec == 0)
+		c = dmabuf->write_channel;
+	if (c != NULL) {
+		sg = &c->sg[0];
+		/*
+		 *      Load up 32 sg entries and take an interrupt at half
+		 *      way (we might want more interrupts later..) 
+		 */
+		for (i = 0; i < dmabuf->numfrag; i++) {
+			sg->busaddr =
+			    virt_to_bus(dmabuf->rawbuf +
+					dmabuf->fragsize * i);
+			// the card will always be doing 16bit stereo
+			sg->control = dmabuf->fragsamples;
+			sg->control |= CON_BUFPAD;	//I modify
+			// set us up to get IOC interrupts as often as needed to
+			// satisfy numfrag requirements, no more
+			if (((i + 1) % fragint) == 0) {
+				sg->control |= CON_IOC;
+			}
+			sg++;
+		}
+		spin_lock_irqsave(&state->card->lock, flags);
+		outb(2, state->card->iobase + c->port + OFF_CR);	/* reset DMA machine */
+		outl(virt_to_bus(&c->sg[0]), state->card->iobase + c->port + OFF_BDBAR);
+		outb(0, state->card->iobase + c->port + OFF_CIV);
+		outb(0, state->card->iobase + c->port + OFF_LVI);
+		spin_unlock_irqrestore(&state->card->lock, flags);
+	}
+	/* set the ready flag for the dma buffer */
+	dmabuf->ready = 1;
+	return 0;
+}
+
+static void __ali_update_lvi(struct ali_state *state, int rec)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int x, port;
+	port = state->card->iobase;
+	if (rec == 1)
+		port += dmabuf->read_channel->port;
+	else if (rec == 2)
+		port += dmabuf->codec_spdifout_channel->port;
+	else if (rec == 3)
+		port += dmabuf->controller_spdifout_channel->port;
+	else if (rec == 0)
+		port += dmabuf->write_channel->port;
+	/* if we are currently stopped, then our CIV is actually set to our
+	 * *last* sg segment and we are ready to wrap to the next.  However,
+	 * if we set our LVI to the last sg segment, then it won't wrap to
+	 * the next sg segment, it won't even get a start.  So, instead, when
+	 * we are stopped, we set both the LVI value and also we increment
+	 * the CIV value to the next sg segment to be played so that when
+	 * we call start_{dac,adc}, things will operate properly
+	 */
+	if (!dmabuf->enable && dmabuf->ready) {
+		if (rec && dmabuf->count < dmabuf->dmasize && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
+			outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
+			__start_adc(state);
+			while (! (inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
+				cpu_relax();
+		} else if (!rec && dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
+			outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
+			__start_dac(state);
+			while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
+				cpu_relax();
+		} else if (rec && dmabuf->count && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
+			if (codec_independent_spdif_locked > 0) {
+				// outb((inb(port+OFF_CIV))&31, port+OFF_LVI);
+				outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
+				__start_spdifout(state);
+				while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
+					cpu_relax();
+			} else {
+				if (controller_independent_spdif_locked > 0) {
+					outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
+					__start_spdifout(state);
+					while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
+						cpu_relax();
+				}
+			}
+		}
+	}
+
+	/* swptr - 1 is the tail of our transfer */
+	x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize;
+	x /= dmabuf->fragsize;
+	outb(x, port + OFF_LVI);
+}
+
+static void ali_update_lvi(struct ali_state *state, int rec)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	if (!dmabuf->ready)
+		return;
+	spin_lock_irqsave(&state->card->lock, flags);
+	__ali_update_lvi(state, rec);
+	spin_unlock_irqrestore(&state->card->lock, flags);
+}
+
+/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
+static void ali_update_ptr(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned hwptr;
+	int diff;
+	
+	/* error handling and process wake up for DAC */
+	if (dmabuf->enable == ADC_RUNNING) {
+		/* update hardware pointer */
+		hwptr = ali_get_dma_addr(state, 1);
+		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+		dmabuf->hwptr = hwptr;
+		dmabuf->total_bytes += diff;
+		dmabuf->count += diff;
+		if (dmabuf->count > dmabuf->dmasize) {
+			/* buffer underrun or buffer overrun */
+			/* this is normal for the end of a read */
+			/* only give an error if we went past the */
+			/* last valid sg entry */
+			if ((inb(state->card->iobase + PI_CIV) & 31) != (inb(state->card->iobase + PI_LVI) & 31)) {
+				printk(KERN_WARNING "ali_audio: DMA overrun on read\n");
+				dmabuf->error++;
+			}
+		}
+		if (dmabuf->count > dmabuf->userfragsize)
+			wake_up(&dmabuf->wait);
+	}
+	/* error handling and process wake up for DAC */
+	if (dmabuf->enable == DAC_RUNNING) {
+		/* update hardware pointer */
+		hwptr = ali_get_dma_addr(state, 0);
+		diff =
+		    (dmabuf->dmasize + hwptr -
+		     dmabuf->hwptr) % dmabuf->dmasize;
+#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
+		printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+#endif
+		dmabuf->hwptr = hwptr;
+		dmabuf->total_bytes += diff;
+		dmabuf->count -= diff;
+		if (dmabuf->count < 0) {
+			/* buffer underrun or buffer overrun */
+			/* this is normal for the end of a write */
+			/* only give an error if we went past the */
+			/* last valid sg entry */
+			if ((inb(state->card->iobase + PO_CIV) & 31) != (inb(state->card->iobase + PO_LVI) & 31)) {
+				printk(KERN_WARNING "ali_audio: DMA overrun on write\n");
+				printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n",
+				     			inb(state->card->iobase + PO_CIV) & 31,
+				     			inb(state->card->iobase + PO_LVI) & 31, 
+							dmabuf->hwptr,
+							dmabuf->count);
+				dmabuf->error++;
+			}
+		}
+		if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
+		    	wake_up(&dmabuf->wait);
+	}
+
+	/* error handling and process wake up for CODEC SPDIF OUT */
+	if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
+		/* update hardware pointer */
+		hwptr = ali_get_dma_addr(state, 2);
+		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+		dmabuf->hwptr = hwptr;
+		dmabuf->total_bytes += diff;
+		dmabuf->count -= diff;
+		if (dmabuf->count < 0) {
+			/* buffer underrun or buffer overrun */
+			/* this is normal for the end of a write */
+			/* only give an error if we went past the */
+			/* last valid sg entry */
+			if ((inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31)) {
+				printk(KERN_WARNING "ali_audio: DMA overrun on write\n");
+				printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n", 
+				        inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31,
+					inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31,
+					dmabuf->hwptr, dmabuf->count);
+				dmabuf->error++;
+			}
+		}
+		if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
+			wake_up(&dmabuf->wait);
+	}
+	/* error handling and process wake up for CONTROLLER SPDIF OUT */
+	if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
+		/* update hardware pointer */
+		hwptr = ali_get_dma_addr(state, 3);
+		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+		dmabuf->hwptr = hwptr;
+		dmabuf->total_bytes += diff;
+		dmabuf->count -= diff;
+		if (dmabuf->count < 0) {
+			/* buffer underrun or buffer overrun */
+			/* this is normal for the end of a write */
+			/* only give an error if we went past the */
+			/* last valid sg entry */
+			if ((inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31)) {
+				printk(KERN_WARNING
+				       "ali_audio: DMA overrun on write\n");
+				printk("ali_audio: CIV %d, LVI %d, hwptr %x, "
+					"count %d\n",
+				     		inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31,
+				     		inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31,
+				     		dmabuf->hwptr, dmabuf->count);
+				dmabuf->error++;
+			}
+		}
+		if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
+			wake_up(&dmabuf->wait);
+	}
+}
+
+static inline int ali_get_free_write_space(struct
+					   ali_state
+					   *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int free;
+	ali_update_ptr(state);
+	// catch underruns during playback
+	if (dmabuf->count < 0) {
+		dmabuf->count = 0;
+		dmabuf->swptr = dmabuf->hwptr;
+	}
+	free = dmabuf->dmasize - dmabuf->count;
+	free -= (dmabuf->hwptr % dmabuf->fragsize);
+	if (free < 0)
+		return (0);
+	return (free);
+}
+
+static inline int ali_get_available_read_data(struct
+					      ali_state
+					      *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int avail;
+	ali_update_ptr(state);
+	// catch overruns during record
+	if (dmabuf->count > dmabuf->dmasize) {
+		dmabuf->count = dmabuf->dmasize;
+		dmabuf->swptr = dmabuf->hwptr;
+	}
+	avail = dmabuf->count;
+	avail -= (dmabuf->hwptr % dmabuf->fragsize);
+	if (avail < 0)
+		return (0);
+	return (avail);
+}
+
+static int drain_dac(struct ali_state *state, int signals_allowed)
+{
+
+	DECLARE_WAITQUEUE(wait, current);
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	unsigned long tmo;
+	int count;
+	if (!dmabuf->ready)
+		return 0;
+	if (dmabuf->mapped) {
+		stop_dac(state);
+		return 0;
+	}
+	add_wait_queue(&dmabuf->wait, &wait);
+	for (;;) {
+
+		spin_lock_irqsave(&state->card->lock, flags);
+		ali_update_ptr(state);
+		count = dmabuf->count;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+		if (count <= 0)
+			break;
+		/* 
+		 * This will make sure that our LVI is correct, that our
+		 * pointer is updated, and that the DAC is running.  We
+		 * have to force the setting of dmabuf->trigger to avoid
+		 * any possible deadlocks.
+		 */
+		if (!dmabuf->enable) {
+			dmabuf->trigger = PCM_ENABLE_OUTPUT;
+			ali_update_lvi(state, 0);
+		}
+		if (signal_pending(current) && signals_allowed) {
+			break;
+		}
+
+		/* It seems that we have to set the current state to
+		 * TASK_INTERRUPTIBLE every time to make the process
+		 * really go to sleep.  This also has to be *after* the
+		 * update_ptr() call because update_ptr is likely to
+		 * do a wake_up() which will unset this before we ever
+		 * try to sleep, resuling in a tight loop in this code
+		 * instead of actually sleeping and waiting for an
+		 * interrupt to wake us up!
+		 */
+		set_current_state(TASK_INTERRUPTIBLE);
+		/*
+		 * set the timeout to significantly longer than it *should*
+		 * take for the DAC to drain the DMA buffer
+		 */
+		tmo = (count * HZ) / (dmabuf->rate);
+		if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
+			printk(KERN_ERR "ali_audio: drain_dac, dma timeout?\n");
+			count = 0;
+			break;
+		}
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&dmabuf->wait, &wait);
+	if (count > 0 && signal_pending(current) && signals_allowed)
+		return -ERESTARTSYS;
+	stop_dac(state);
+	return 0;
+}
+
+
+static int drain_spdifout(struct ali_state *state, int signals_allowed)
+{
+
+	DECLARE_WAITQUEUE(wait, current);
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	unsigned long tmo;
+	int count;
+	if (!dmabuf->ready)
+		return 0;
+	if (dmabuf->mapped) {
+		stop_spdifout(state);
+		return 0;
+	}
+	add_wait_queue(&dmabuf->wait, &wait);
+	for (;;) {
+
+		spin_lock_irqsave(&state->card->lock, flags);
+		ali_update_ptr(state);
+		count = dmabuf->count;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+		if (count <= 0)
+			break;
+		/* 
+		 * This will make sure that our LVI is correct, that our
+		 * pointer is updated, and that the DAC is running.  We
+		 * have to force the setting of dmabuf->trigger to avoid
+		 * any possible deadlocks.
+		 */
+		if (!dmabuf->enable) {
+			if (codec_independent_spdif_locked > 0) {
+				dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
+				ali_update_lvi(state, 2);
+			} else {
+				if (controller_independent_spdif_locked > 0) {
+					dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
+					ali_update_lvi(state, 3);
+				}
+			}
+		}
+		if (signal_pending(current) && signals_allowed) {
+			break;
+		}
+
+		/* It seems that we have to set the current state to
+		 * TASK_INTERRUPTIBLE every time to make the process
+		 * really go to sleep.  This also has to be *after* the
+		 * update_ptr() call because update_ptr is likely to
+		 * do a wake_up() which will unset this before we ever
+		 * try to sleep, resuling in a tight loop in this code
+		 * instead of actually sleeping and waiting for an
+		 * interrupt to wake us up!
+		 */
+		set_current_state(TASK_INTERRUPTIBLE);
+		/*
+		 * set the timeout to significantly longer than it *should*
+		 * take for the DAC to drain the DMA buffer
+		 */
+		tmo = (count * HZ) / (dmabuf->rate);
+		if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
+			printk(KERN_ERR "ali_audio: drain_spdifout, dma timeout?\n");
+			count = 0;
+			break;
+		}
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&dmabuf->wait, &wait);
+	if (count > 0 && signal_pending(current) && signals_allowed)
+		return -ERESTARTSYS;
+	stop_spdifout(state);
+	return 0;
+}
+
+static void ali_channel_interrupt(struct ali_card *card)
+{
+	int i, count;
+	
+	for (i = 0; i < NR_HW_CH; i++) {
+		struct ali_state *state = card->states[i];
+		struct ali_channel *c = NULL;
+		struct dmabuf *dmabuf;
+		unsigned long port = card->iobase;
+		u16 status;
+		if (!state)
+			continue;
+		if (!state->dmabuf.ready)
+			continue;
+		dmabuf = &state->dmabuf;
+		if (codec_independent_spdif_locked > 0) {
+			if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
+				c = dmabuf->codec_spdifout_channel;
+			}
+		} else {
+			if (controller_independent_spdif_locked > 0) {
+				if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+					c = dmabuf->controller_spdifout_channel;
+			} else {
+				if (dmabuf->enable & DAC_RUNNING) {
+					c = dmabuf->write_channel;
+				} else if (dmabuf->enable & ADC_RUNNING) {
+					c = dmabuf->read_channel;
+				} else
+					continue;
+			}
+		}
+		port += c->port;
+
+		status = inw(port + OFF_SR);
+
+		if (status & DMA_INT_COMPLETE) {
+			/* only wake_up() waiters if this interrupt signals
+			 * us being beyond a userfragsize of data open or
+			 * available, and ali_update_ptr() does that for
+			 * us
+			 */
+			ali_update_ptr(state);
+		}
+
+		if (status & DMA_INT_LVI) {
+			ali_update_ptr(state);
+			wake_up(&dmabuf->wait);
+
+			if (dmabuf->enable & DAC_RUNNING)
+				count = dmabuf->count;
+			else if (dmabuf->enable & ADC_RUNNING)
+				count = dmabuf->dmasize - dmabuf->count;
+			else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+				count = dmabuf->count;
+			else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+				count = dmabuf->count;
+			else count = 0;
+
+			if (count > 0) {
+				if (dmabuf->enable & DAC_RUNNING)
+					outl((1 << 1), state->card->iobase + ALI_DMACR);
+				else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+						outl((1 << 3), state->card->iobase + ALI_DMACR);
+				else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+					outl((1 << 7), state->card->iobase + ALI_DMACR);
+			} else {
+				if (dmabuf->enable & DAC_RUNNING)
+					__stop_dac(state);
+				if (dmabuf->enable & ADC_RUNNING)
+					__stop_adc(state);
+				if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+					__stop_spdifout(state);
+				if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+					__stop_spdifout(state);
+				dmabuf->enable = 0;
+				wake_up(&dmabuf->wait);
+			}
+
+		}
+		if (!(status & DMA_INT_DCH)) {
+			ali_update_ptr(state);
+			wake_up(&dmabuf->wait);
+			if (dmabuf->enable & DAC_RUNNING)
+				count = dmabuf->count;
+			else if (dmabuf->enable & ADC_RUNNING)
+				count = dmabuf->dmasize - dmabuf->count;
+			else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+				count = dmabuf->count;
+			else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+				count = dmabuf->count;
+			else
+				count = 0;
+
+			if (count > 0) {
+				if (dmabuf->enable & DAC_RUNNING)
+					outl((1 << 1), state->card->iobase + ALI_DMACR);
+				else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+					outl((1 << 3), state->card->iobase + ALI_DMACR);
+				else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+					outl((1 << 7), state->card->iobase + ALI_DMACR);
+			} else {
+				if (dmabuf->enable & DAC_RUNNING)
+					__stop_dac(state);
+				if (dmabuf->enable & ADC_RUNNING)
+					__stop_adc(state);
+				if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+					__stop_spdifout(state);
+				if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+					__stop_spdifout(state);
+				dmabuf->enable = 0;
+				wake_up(&dmabuf->wait);
+			}
+		}
+		outw(status & DMA_INT_MASK, port + OFF_SR);
+	}
+}
+
+static void ali_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct ali_card *card = (struct ali_card *) dev_id;
+	u32 status;
+	u16 status2;
+
+	spin_lock(&card->lock);
+	status = inl(card->iobase + ALI_INTERRUPTSR);
+	if (!(status & INT_MASK)) {
+		spin_unlock(&card->lock);
+		return;		/* not for us */
+	}
+
+	if (codec_independent_spdif_locked > 0) {
+		if (globel == 0) {
+			globel += 1;
+			status2 = inw(card->iobase + 0x76);
+			outw(status2 | 0x000c, card->iobase + 0x76);
+		} else {
+			if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
+				ali_channel_interrupt(card);
+		}
+	} else {
+		if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
+			ali_channel_interrupt(card);
+	}
+
+	/* clear 'em */
+	outl(status & INT_MASK, card->iobase + ALI_INTERRUPTSR);
+	spin_unlock(&card->lock);
+}
+
+/* in this loop, dmabuf.count signifies the amount of data that is
+   waiting to be copied to the user's buffer.  It is filled by the dma
+   machine and drained by this loop. */
+
+static ssize_t ali_read(struct file *file, char *buffer,
+			size_t count, loff_t * ppos)
+{
+	struct ali_state *state = (struct ali_state *) file->private_data;
+	struct ali_card *card = state ? state->card : 0;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	ssize_t ret;
+	unsigned long flags;
+	unsigned int swptr;
+	int cnt;
+	DECLARE_WAITQUEUE(waita, current);
+#ifdef DEBUG2
+	printk("ali_audio: ali_read called, count = %d\n", count);
+#endif
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (dmabuf->mapped)
+		return -ENXIO;
+	if (dmabuf->enable & DAC_RUNNING)
+		return -ENODEV;
+	if (!dmabuf->read_channel) {
+		dmabuf->ready = 0;
+		dmabuf->read_channel = card->alloc_rec_pcm_channel(card);
+		if (!dmabuf->read_channel) {
+			return -EBUSY;
+		}
+	}
+	if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
+		return ret;
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return -EFAULT;
+	ret = 0;
+	add_wait_queue(&dmabuf->wait, &waita);
+	while (count > 0) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_lock_irqsave(&card->lock, flags);
+		if (PM_SUSPENDED(card)) {
+			spin_unlock_irqrestore(&card->lock, flags);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			continue;
+		}
+		swptr = dmabuf->swptr;
+		cnt = ali_get_available_read_data(state);
+		// this is to make the copy_to_user simpler below
+		if (cnt > (dmabuf->dmasize - swptr))
+			cnt = dmabuf->dmasize - swptr;
+		spin_unlock_irqrestore(&card->lock, flags);
+		if (cnt > count)
+			cnt = count;
+		/* Lop off the last two bits to force the code to always
+		 * write in full samples.  This keeps software that sets
+		 * O_NONBLOCK but doesn't check the return value of the
+		 * write call from getting things out of state where they
+		 * think a full 4 byte sample was written when really only
+		 * a portion was, resulting in odd sound and stereo
+		 * hysteresis.
+		 */
+		cnt &= ~0x3;
+		if (cnt <= 0) {
+			unsigned long tmo;
+			/*
+			 * Don't let us deadlock.  The ADC won't start if
+			 * dmabuf->trigger isn't set.  A call to SETTRIGGER
+			 * could have turned it off after we set it to on
+			 * previously.
+			 */
+			dmabuf->trigger = PCM_ENABLE_INPUT;
+			/*
+			 * This does three things.  Updates LVI to be correct,
+			 * makes sure the ADC is running, and updates the
+			 * hwptr.
+			 */
+			ali_update_lvi(state, 1);
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				goto done;
+			}
+			/* Set the timeout to how long it would take to fill
+			 * two of our buffers.  If we haven't been woke up
+			 * by then, then we know something is wrong.
+			 */
+			tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
+			    
+			/* There are two situations when sleep_on_timeout returns, one is when
+			   the interrupt is serviced correctly and the process is waked up by
+			   ISR ON TIME. Another is when timeout is expired, which means that
+			   either interrupt is NOT serviced correctly (pending interrupt) or it
+			   is TOO LATE for the process to be scheduled to run (scheduler latency)
+			   which results in a (potential) buffer overrun. And worse, there is
+			   NOTHING we can do to prevent it. */
+			if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
+				printk(KERN_ERR
+				       "ali_audio: recording schedule timeout, "
+				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+				       dmabuf->dmasize, dmabuf->fragsize,
+				       dmabuf->count, dmabuf->hwptr,
+				       dmabuf->swptr);
+				/* a buffer overrun, we delay the recovery until next time the
+				   while loop begin and we REALLY have space to record */
+			}
+			if (signal_pending(current)) {
+				ret = ret ? ret : -ERESTARTSYS;
+				goto done;
+			}
+			continue;
+		}
+
+		if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			goto done;
+		}
+
+		swptr = (swptr + cnt) % dmabuf->dmasize;
+		spin_lock_irqsave(&card->lock, flags);
+		if (PM_SUSPENDED(card)) {
+			spin_unlock_irqrestore(&card->lock, flags);
+			continue;
+		}
+		dmabuf->swptr = swptr;
+		dmabuf->count -= cnt;
+		spin_unlock_irqrestore(&card->lock, flags);
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+	}
+done:
+	ali_update_lvi(state, 1);
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&dmabuf->wait, &waita);
+	return ret;
+}
+
+/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
+   the soundcard.  it is drained by the dma machine and filled by this loop. */
+static ssize_t ali_write(struct file *file,
+			 const char *buffer, size_t count, loff_t * ppos)
+{
+	struct ali_state *state = (struct ali_state *) file->private_data;
+	struct ali_card *card = state ? state->card : 0;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	ssize_t ret;
+	unsigned long flags;
+	unsigned int swptr = 0;
+	int cnt, x;
+	DECLARE_WAITQUEUE(waita, current);
+#ifdef DEBUG2
+	printk("ali_audio: ali_write called, count = %d\n", count);
+#endif
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (dmabuf->mapped)
+		return -ENXIO;
+	if (dmabuf->enable & ADC_RUNNING)
+		return -ENODEV;
+	if (codec_independent_spdif_locked > 0) {
+		if (!dmabuf->codec_spdifout_channel) {
+			dmabuf->ready = 0;
+			dmabuf->codec_spdifout_channel = card->alloc_codec_spdifout_channel(card);
+			if (!dmabuf->codec_spdifout_channel)
+				return -EBUSY;
+		}
+	} else {
+		if (controller_independent_spdif_locked > 0) {
+			if (!dmabuf->controller_spdifout_channel) {
+				dmabuf->ready = 0;
+				dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card);
+				if (!dmabuf->controller_spdifout_channel)
+					return -EBUSY;
+			}
+		} else {
+			if (!dmabuf->write_channel) {
+				dmabuf->ready = 0;
+				dmabuf->write_channel =
+				    card->alloc_pcm_channel(card);
+				if (!dmabuf->write_channel)
+					return -EBUSY;
+			}
+		}
+	}
+
+	if (codec_independent_spdif_locked > 0) {
+		if (!dmabuf->ready && (ret = prog_dmabuf(state, 2)))
+			return ret;
+	} else {
+		if (controller_independent_spdif_locked > 0) {
+			if (!dmabuf->ready && (ret = prog_dmabuf(state, 3)))
+				return ret;
+		} else {
+
+			if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
+				return ret;
+		}
+	}
+	if (!access_ok(VERIFY_READ, buffer, count))
+		return -EFAULT;
+	ret = 0;
+	add_wait_queue(&dmabuf->wait, &waita);
+	while (count > 0) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_lock_irqsave(&state->card->lock, flags);
+		if (PM_SUSPENDED(card)) {
+			spin_unlock_irqrestore(&card->lock, flags);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			continue;
+		}
+
+		swptr = dmabuf->swptr;
+		cnt = ali_get_free_write_space(state);
+		/* Bound the maximum size to how much we can copy to the
+		 * dma buffer before we hit the end.  If we have more to
+		 * copy then it will get done in a second pass of this
+		 * loop starting from the beginning of the buffer.
+		 */
+		if (cnt > (dmabuf->dmasize - swptr))
+			cnt = dmabuf->dmasize - swptr;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+#ifdef DEBUG2
+		printk(KERN_INFO
+		       "ali_audio: ali_write: %d bytes available space\n",
+		       cnt);
+#endif
+		if (cnt > count)
+			cnt = count;
+		/* Lop off the last two bits to force the code to always
+		 * write in full samples.  This keeps software that sets
+		 * O_NONBLOCK but doesn't check the return value of the
+		 * write call from getting things out of state where they
+		 * think a full 4 byte sample was written when really only
+		 * a portion was, resulting in odd sound and stereo
+		 * hysteresis.
+		 */
+		cnt &= ~0x3;
+		if (cnt <= 0) {
+			unsigned long tmo;
+			// There is data waiting to be played
+			/*
+			 * Force the trigger setting since we would
+			 * deadlock with it set any other way
+			 */
+			if (codec_independent_spdif_locked > 0) {
+				dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
+				ali_update_lvi(state, 2);
+			} else {
+				if (controller_independent_spdif_locked > 0) {
+					dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
+					ali_update_lvi(state, 3);
+				} else {
+
+					dmabuf->trigger = PCM_ENABLE_OUTPUT;
+					ali_update_lvi(state, 0);
+				}
+			}
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				goto ret;
+			}
+			/* Not strictly correct but works */
+			tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
+			/* There are two situations when sleep_on_timeout returns, one is when
+			   the interrupt is serviced correctly and the process is waked up by
+			   ISR ON TIME. Another is when timeout is expired, which means that
+			   either interrupt is NOT serviced correctly (pending interrupt) or it
+			   is TOO LATE for the process to be scheduled to run (scheduler latency)
+			   which results in a (potential) buffer underrun. And worse, there is
+			   NOTHING we can do to prevent it. */
+			   
+			/* FIXME - do timeout handling here !! */
+
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				goto ret;
+			}
+			continue;
+		}
+		if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			goto ret;
+		}
+
+		swptr = (swptr + cnt) % dmabuf->dmasize;
+		spin_lock_irqsave(&state->card->lock, flags);
+		if (PM_SUSPENDED(card)) {
+			spin_unlock_irqrestore(&card->lock, flags);
+			continue;
+		}
+
+		dmabuf->swptr = swptr;
+		dmabuf->count += cnt;
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+	}
+	if (swptr % dmabuf->fragsize) {
+		x = dmabuf->fragsize - (swptr % dmabuf->fragsize);
+		memset(dmabuf->rawbuf + swptr, '\0', x);
+	}
+ret:
+	if (codec_independent_spdif_locked > 0) {
+		ali_update_lvi(state, 2);
+	} else {
+		if (controller_independent_spdif_locked > 0) {
+			ali_update_lvi(state, 3);
+		} else {
+			ali_update_lvi(state, 0);
+		}
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&dmabuf->wait, &waita);
+	return ret;
+}
+
+/* No kernel lock - we have our own spinlock */
+static unsigned int ali_poll(struct file *file, struct poll_table_struct
+			     *wait)
+{
+	struct ali_state *state = (struct ali_state *) file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	unsigned int mask = 0;
+	if (!dmabuf->ready)
+		return 0;
+	poll_wait(file, &dmabuf->wait, wait);
+	spin_lock_irqsave(&state->card->lock, flags);
+	ali_update_ptr(state);
+	if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) {
+		if (dmabuf->count >= (signed) dmabuf->fragsize)
+			mask |= POLLIN | POLLRDNORM;
+	}
+	if (file->f_mode & FMODE_WRITE  && (dmabuf->enable & (DAC_RUNNING|CODEC_SPDIFOUT_RUNNING|CONTROLLER_SPDIFOUT_RUNNING))) {
+		if ((signed) dmabuf->dmasize >= dmabuf->count + (signed) dmabuf->fragsize)
+			mask |= POLLOUT | POLLWRNORM;
+	}
+	spin_unlock_irqrestore(&state->card->lock, flags);
+	return mask;
+}
+
+static int ali_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct ali_state *state = (struct ali_state *) file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int ret = -EINVAL;
+	unsigned long size;
+	lock_kernel();
+	if (vma->vm_flags & VM_WRITE) {
+		if (!dmabuf->write_channel && (dmabuf->write_channel = state->card->alloc_pcm_channel(state->card)) == NULL) {
+			ret = -EBUSY;
+			goto out;
+		}
+	}
+	if (vma->vm_flags & VM_READ) {
+		if (!dmabuf->read_channel && (dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card)) == NULL) {
+			ret = -EBUSY;
+			goto out;
+		}
+	}
+	if ((ret = prog_dmabuf(state, 0)) != 0)
+		goto out;
+	ret = -EINVAL;
+	if (vma->vm_pgoff != 0)
+		goto out;
+	size = vma->vm_end - vma->vm_start;
+	if (size > (PAGE_SIZE << dmabuf->buforder))
+		goto out;
+	ret = -EAGAIN;
+	if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf), size, vma->vm_page_prot))
+		goto out;
+	dmabuf->mapped = 1;
+	dmabuf->trigger = 0;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
+}
+
+static int ali_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct ali_state *state = (struct ali_state *) file->private_data;
+	struct ali_channel *c = NULL;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	audio_buf_info abinfo;
+	count_info cinfo;
+	unsigned int i_scr;
+	int val = 0, ret;
+	struct ac97_codec *codec = state->card->ac97_codec[0];
+#ifdef DEBUG
+	printk("ali_audio: ali_ioctl, arg=0x%x, cmd=",
+	       arg ? *(int *) arg : 0);
+#endif
+	switch (cmd) {
+	case OSS_GETVERSION:
+#ifdef DEBUG
+		printk("OSS_GETVERSION\n");
+#endif
+		return put_user(SOUND_VERSION, (int *) arg);
+	case SNDCTL_DSP_RESET:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_RESET\n");
+#endif
+		spin_lock_irqsave(&state->card->lock, flags);
+		if (dmabuf->enable == DAC_RUNNING) {
+			c = dmabuf->write_channel;
+			__stop_dac(state);
+		}
+		if (dmabuf->enable == ADC_RUNNING) {
+			c = dmabuf->read_channel;
+			__stop_adc(state);
+		}
+		if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
+			c = dmabuf->codec_spdifout_channel;
+			__stop_spdifout(state);
+		}
+		if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
+			c = dmabuf->controller_spdifout_channel;
+			__stop_spdifout(state);
+		}
+		if (c != NULL) {
+			outb(2, state->card->iobase + c->port + OFF_CR);	/* reset DMA machine */
+			outl(virt_to_bus(&c->sg[0]),
+			     state->card->iobase + c->port + OFF_BDBAR);
+			outb(0, state->card->iobase + c->port + OFF_CIV);
+			outb(0, state->card->iobase + c->port + OFF_LVI);
+		}
+
+		spin_unlock_irqrestore(&state->card->lock, flags);
+		synchronize_irq();
+		dmabuf->ready = 0;
+		dmabuf->swptr = dmabuf->hwptr = 0;
+		dmabuf->count = dmabuf->total_bytes = 0;
+		return 0;
+	case SNDCTL_DSP_SYNC:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SYNC\n");
+#endif
+		if (codec_independent_spdif_locked > 0) {
+			if (dmabuf->enable != CODEC_SPDIFOUT_RUNNING
+			    || file->f_flags & O_NONBLOCK)
+				return 0;
+			if ((val = drain_spdifout(state, 1)))
+				return val;
+		} else {
+			if (controller_independent_spdif_locked > 0) {
+				if (dmabuf->enable !=
+				    CONTROLLER_SPDIFOUT_RUNNING
+				    || file->f_flags & O_NONBLOCK)
+					return 0;
+				if ((val = drain_spdifout(state, 1)))
+					return val;
+			} else {
+				if (dmabuf->enable != DAC_RUNNING
+				    || file->f_flags & O_NONBLOCK)
+					return 0;
+				if ((val = drain_dac(state, 1)))
+					return val;
+			}
+		}
+		dmabuf->total_bytes = 0;
+		return 0;
+	case SNDCTL_DSP_SPEED:	/* set smaple rate */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SPEED\n");
+#endif
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		if (val >= 0) {
+			if (file->f_mode & FMODE_WRITE) {
+				if ((state->card->ac97_status & SPDIF_ON)) {	/* S/PDIF Enabled */
+					/* RELTEK ALC650 only support 48000, need to check that */
+					if (ali_valid_spdif_rate(codec, val)) {
+						if (codec_independent_spdif_locked > 0) {
+							ali_set_spdif_output(state, -1, 0);
+							stop_spdifout(state);
+							dmabuf->ready = 0;
+							/* I add test codec independent spdif out */
+							spin_lock_irqsave(&state->card->lock, flags);
+							ali_set_codecspdifout_rate(state, val);	// I modified
+							spin_unlock_irqrestore(&state->card->lock, flags);
+							/* Set S/PDIF transmitter rate. */
+							i_scr = inl(state->card->iobase + ALI_SCR);
+							if ((i_scr & 0x00300000) == 0x00100000) {
+								ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
+							} else {
+								if ((i_scr&0x00300000)  == 0x00200000)
+								{
+									ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
+								} else {
+									if ((i_scr & 0x00300000) == 0x00300000) {
+										ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
+									} else {
+										ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
+									}
+								}
+							}
+
+							if (!(state->card->ac97_status & SPDIF_ON)) {
+								val = dmabuf->rate;
+							}
+						} else {
+							if (controller_independent_spdif_locked > 0) 
+							{
+								stop_spdifout(state);
+								dmabuf->ready = 0;
+								spin_lock_irqsave(&state->card->lock, flags);
+								ali_set_spdifout_rate(state, controller_independent_spdif_locked);
+								spin_unlock_irqrestore(&state->card->lock, flags);
+							} else {
+								/* Set DAC rate */
+								ali_set_spdif_output(state, -1, 0);
+								stop_dac(state);
+								dmabuf->ready = 0;
+								spin_lock_irqsave(&state->card->lock, flags);
+								ali_set_dac_rate(state, val);
+								spin_unlock_irqrestore(&state->card->lock, flags);
+								/* Set S/PDIF transmitter rate. */
+								ali_set_spdif_output(state, AC97_EA_SPSA_3_4, val);
+								if (!(state->card->ac97_status & SPDIF_ON))
+								{
+									val = dmabuf->rate;
+								}
+							}
+						}
+					} else {	/* Not a valid rate for S/PDIF, ignore it */
+						val = dmabuf->rate;
+					}
+				} else {
+					stop_dac(state);
+					dmabuf->ready = 0;
+					spin_lock_irqsave(&state->card->lock, flags);
+					ali_set_dac_rate(state, val);
+					spin_unlock_irqrestore(&state->card->lock, flags);
+				}
+			}
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(state);
+				dmabuf->ready = 0;
+				spin_lock_irqsave(&state->card->lock, flags);
+				ali_set_adc_rate(state, val);
+				spin_unlock_irqrestore(&state->card->lock, flags);
+			}
+		}
+		return put_user(dmabuf->rate, (int *) arg);
+	case SNDCTL_DSP_STEREO:	/* set stereo or mono channel */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_STEREO\n");
+#endif
+		if (dmabuf->enable & DAC_RUNNING) {
+			stop_dac(state);
+		}
+		if (dmabuf->enable & ADC_RUNNING) {
+			stop_adc(state);
+		}
+		if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
+			stop_spdifout(state);
+		}
+		if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) {
+			stop_spdifout(state);
+		}
+		return put_user(1, (int *) arg);
+	case SNDCTL_DSP_GETBLKSIZE:
+		if (file->f_mode & FMODE_WRITE) {
+			if (codec_independent_spdif_locked > 0) {
+				if (!dmabuf->ready && (val = prog_dmabuf(state, 2)))
+					return val;
+			} else {
+				if (controller_independent_spdif_locked > 0) {
+					if (!dmabuf->ready && (val = prog_dmabuf(state, 3)))
+						return val;
+				} else {
+					if (!dmabuf->ready && (val = prog_dmabuf(state, 0)))
+						return val;
+				}
+			}
+		}
+
+		if (file->f_mode & FMODE_READ) {
+			if (!dmabuf->ready && (val = prog_dmabuf(state, 1)))
+				return val;
+		}
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize);
+#endif
+		return put_user(dmabuf->userfragsize, (int *) arg);
+	case SNDCTL_DSP_GETFMTS:	/* Returns a mask of supported sample format */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETFMTS\n");
+#endif
+		return put_user(AFMT_S16_LE, (int *) arg);
+	case SNDCTL_DSP_SETFMT:	/* Select sample format */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SETFMT\n");
+#endif
+		return put_user(AFMT_S16_LE, (int *) arg);
+	case SNDCTL_DSP_CHANNELS:	// add support 4,6 channel 
+#ifdef DEBUG
+		printk("SNDCTL_DSP_CHANNELS\n");
+#endif
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		if (val > 0) {
+			if (dmabuf->enable & DAC_RUNNING) {
+				stop_dac(state);
+			}
+			if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
+				stop_spdifout(state);
+			}
+			if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) {
+				stop_spdifout(state);
+			}
+			if (dmabuf->enable & ADC_RUNNING) {
+				stop_adc(state);
+			}
+		} else {
+			return put_user(state->card->channels, (int *) arg);
+		}
+
+		i_scr = inl(state->card->iobase + ALI_SCR);
+		/* Current # of channels enabled */
+		if (i_scr & 0x00000100)
+			ret = 4;
+		else if (i_scr & 0x00000200)
+			ret = 6;
+		else
+			ret = 2;
+		switch (val) {
+		case 2:	/* 2 channels is always supported */
+			if (codec_independent_spdif_locked > 0) {
+				outl(((i_scr & 0xfffffcff) | 0x00100000), (state->card->iobase + ALI_SCR));
+			} else
+				outl((i_scr & 0xfffffcff), (state->card->iobase + ALI_SCR));
+			/* Do we need to change mixer settings????  */
+			break;
+		case 4:	/* Supported on some chipsets, better check first */
+			if (codec_independent_spdif_locked > 0) {
+				outl(((i_scr & 0xfffffcff) | 0x00000100 | 0x00200000), (state->card->iobase + ALI_SCR));
+			} else
+				outl(((i_scr & 0xfffffcff) | 0x00000100), (state->card->iobase + ALI_SCR));
+			break;
+		case 6:	/* Supported on some chipsets, better check first */
+			if (codec_independent_spdif_locked > 0) {
+				outl(((i_scr & 0xfffffcff) | 0x00000200 | 0x00008000 | 0x00300000), (state->card->iobase + ALI_SCR));
+			} else
+				outl(((i_scr & 0xfffffcff) | 0x00000200 | 0x00008000), (state->card->iobase + ALI_SCR));
+			break;
+		default:	/* nothing else is ever supported by the chipset */
+			val = ret;
+			break;
+		}
+		return put_user(val, (int *) arg);
+	case SNDCTL_DSP_POST:	/* the user has sent all data and is notifying us */
+		/* we update the swptr to the end of the last sg segment then return */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_POST\n");
+#endif
+		if (codec_independent_spdif_locked > 0) {
+			if (!dmabuf->ready || (dmabuf->enable != CODEC_SPDIFOUT_RUNNING))
+				return 0;
+		} else {
+			if (controller_independent_spdif_locked > 0) {
+				if (!dmabuf->ready || (dmabuf->enable != CONTROLLER_SPDIFOUT_RUNNING))
+					return 0;
+			} else {
+				if (!dmabuf->ready || (dmabuf->enable != DAC_RUNNING))
+					return 0;
+			}
+		}
+		if ((dmabuf->swptr % dmabuf->fragsize) != 0) {
+			val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize);
+			dmabuf->swptr += val;
+			dmabuf->count += val;
+		}
+		return 0;
+	case SNDCTL_DSP_SUBDIVIDE:
+		if (dmabuf->subdivision)
+			return -EINVAL;
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		if (val != 1 && val != 2 && val != 4)
+			return -EINVAL;
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SUBDIVIDE %d\n", val);
+#endif
+		dmabuf->subdivision = val;
+		dmabuf->ready = 0;
+		return 0;
+	case SNDCTL_DSP_SETFRAGMENT:
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		dmabuf->ossfragsize = 1 << (val & 0xffff);
+		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
+		if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags)
+			return -EINVAL;
+		/*
+		 * Bound the frag size into our allowed range of 256 - 4096
+		 */
+		if (dmabuf->ossfragsize < 256)
+			dmabuf->ossfragsize = 256;
+		else if (dmabuf->ossfragsize > 4096)
+			dmabuf->ossfragsize = 4096;
+		/*
+		 * The numfrags could be something reasonable, or it could
+		 * be 0xffff meaning "Give me as much as possible".  So,
+		 * we check the numfrags * fragsize doesn't exceed our
+		 * 64k buffer limit, nor is it less than our 8k minimum.
+		 * If it fails either one of these checks, then adjust the
+		 * number of fragments, not the size of them.  It's OK if
+		 * our number of fragments doesn't equal 32 or anything
+		 * like our hardware based number now since we are using
+		 * a different frag count for the hardware.  Before we get
+		 * into this though, bound the maxfrags to avoid overflow
+		 * issues.  A reasonable bound would be 64k / 256 since our
+		 * maximum buffer size is 64k and our minimum frag size is
+		 * 256.  On the other end, our minimum buffer size is 8k and
+		 * our maximum frag size is 4k, so the lower bound should
+		 * be 2.
+		 */
+		if (dmabuf->ossmaxfrags > 256)
+			dmabuf->ossmaxfrags = 256;
+		else if (dmabuf->ossmaxfrags < 2)
+			dmabuf->ossmaxfrags = 2;
+		val = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
+		while (val < 8192) {
+			val <<= 1;
+			dmabuf->ossmaxfrags <<= 1;
+		}
+		while (val > 65536) {
+			val >>= 1;
+			dmabuf->ossmaxfrags >>= 1;
+		}
+		dmabuf->ready = 0;
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val,
+		       dmabuf->ossfragsize, dmabuf->ossmaxfrags);
+#endif
+		return 0;
+	case SNDCTL_DSP_GETOSPACE:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		if (codec_independent_spdif_locked > 0) {
+			if (!dmabuf->ready && (val = prog_dmabuf(state, 2)) != 0)
+				return val;
+		} else {
+			if (controller_independent_spdif_locked > 0) {
+				if (!dmabuf->ready && (val = prog_dmabuf(state, 3)) != 0)
+					return val;
+			} else {
+				if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
+					return val;
+			}
+		}
+		spin_lock_irqsave(&state->card->lock, flags);
+		ali_update_ptr(state);
+		abinfo.fragsize = dmabuf->userfragsize;
+		abinfo.fragstotal = dmabuf->userfrags;
+		if (dmabuf->mapped)
+			abinfo.bytes = dmabuf->dmasize;
+		else
+			abinfo.bytes = ali_get_free_write_space(state);
+		abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+#if defined(DEBUG) || defined(DEBUG_MMAP)
+		printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n",
+		       abinfo.bytes, abinfo.fragsize, abinfo.fragments,
+		       abinfo.fragstotal);
+#endif
+		return copy_to_user((void *) arg, &abinfo,
+				    sizeof(abinfo)) ? -EFAULT : 0;
+	case SNDCTL_DSP_GETOPTR:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		if (codec_independent_spdif_locked > 0) {
+			if (!dmabuf->ready && (val = prog_dmabuf(state, 2)) != 0)
+				return val;
+		} else {
+			if (controller_independent_spdif_locked > 0) {
+				if (!dmabuf->ready && (val = prog_dmabuf(state, 3)) != 0)
+					return val;
+			} else {
+				if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
+					return val;
+			}
+		}
+		spin_lock_irqsave(&state->card->lock, flags);
+		val = ali_get_free_write_space(state);
+		cinfo.bytes = dmabuf->total_bytes;
+		cinfo.ptr = dmabuf->hwptr;
+		cinfo.blocks = val / dmabuf->userfragsize;
+		if (codec_independent_spdif_locked > 0) {
+			if (dmabuf->mapped && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
+				dmabuf->count += val;
+				dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
+				__ali_update_lvi(state, 2);
+			}
+		} else {
+			if (controller_independent_spdif_locked > 0) {
+				if (dmabuf->mapped && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
+					dmabuf->count += val;
+					dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
+					__ali_update_lvi(state, 3);
+				}
+			} else {
+				if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
+					dmabuf->count += val;
+					dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
+					__ali_update_lvi(state, 0);
+				}
+			}
+		}
+		spin_unlock_irqrestore(&state->card->lock, flags);
+#if defined(DEBUG) || defined(DEBUG_MMAP)
+		printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes,
+		       cinfo.blocks, cinfo.ptr, dmabuf->count);
+#endif
+		return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
+	case SNDCTL_DSP_GETISPACE:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
+			return val;
+		spin_lock_irqsave(&state->card->lock, flags);
+		abinfo.bytes = ali_get_available_read_data(state);
+		abinfo.fragsize = dmabuf->userfragsize;
+		abinfo.fragstotal = dmabuf->userfrags;
+		abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+#if defined(DEBUG) || defined(DEBUG_MMAP)
+		printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n",
+		       abinfo.bytes, abinfo.fragsize, abinfo.fragments,
+		       abinfo.fragstotal);
+#endif
+		return copy_to_user((void *) arg, &abinfo,
+				    sizeof(abinfo)) ? -EFAULT : 0;
+	case SNDCTL_DSP_GETIPTR:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
+			return val;
+		spin_lock_irqsave(&state->card->lock, flags);
+		val = ali_get_available_read_data(state);
+		cinfo.bytes = dmabuf->total_bytes;
+		cinfo.blocks = val / dmabuf->userfragsize;
+		cinfo.ptr = dmabuf->hwptr;
+		if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
+			dmabuf->count -= val;
+			dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
+			__ali_update_lvi(state, 1);
+		}
+		spin_unlock_irqrestore(&state->card->lock, flags);
+#if defined(DEBUG) || defined(DEBUG_MMAP)
+		printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes,
+		       cinfo.blocks, cinfo.ptr, dmabuf->count);
+#endif
+		return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
+	case SNDCTL_DSP_NONBLOCK:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_NONBLOCK\n");
+#endif
+		file->f_flags |= O_NONBLOCK;
+		return 0;
+	case SNDCTL_DSP_GETCAPS:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETCAPS\n");
+#endif
+		return put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER |
+				DSP_CAP_MMAP | DSP_CAP_BIND, (int *) arg);
+	case SNDCTL_DSP_GETTRIGGER:
+		val = 0;
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger);
+#endif
+		return put_user(dmabuf->trigger, (int *) arg);
+	case SNDCTL_DSP_SETTRIGGER:
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+#if defined(DEBUG) || defined(DEBUG_MMAP)
+		printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
+#endif
+		if (!(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
+			stop_adc(state);
+		}
+		if (!(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
+			stop_dac(state);
+		}
+		if (!(val & SPDIF_ENABLE_OUTPUT) && dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
+			stop_spdifout(state);
+		}
+		if (!(val & SPDIF_ENABLE_OUTPUT) && dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
+			stop_spdifout(state);
+		}
+		dmabuf->trigger = val;
+		if (val & PCM_ENABLE_OUTPUT && !(dmabuf->enable & DAC_RUNNING)) {
+			if (!dmabuf->write_channel) {
+				dmabuf->ready = 0;
+				dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
+				if (!dmabuf->write_channel)
+					return -EBUSY;
+			}
+			if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
+				return ret;
+			if (dmabuf->mapped) {
+				spin_lock_irqsave(&state->card->lock, flags);
+				ali_update_ptr(state);
+				dmabuf->count = 0;
+				dmabuf->swptr = dmabuf->hwptr;
+				dmabuf->count = ali_get_free_write_space(state);
+				dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
+				__ali_update_lvi(state, 0);
+				spin_unlock_irqrestore(&state->card->lock,
+						       flags);
+			} else
+				start_dac(state);
+		}
+		if (val & SPDIF_ENABLE_OUTPUT && !(dmabuf->enable & CODEC_SPDIFOUT_RUNNING)) {
+			if (!dmabuf->codec_spdifout_channel) {
+				dmabuf->ready = 0;
+				dmabuf->codec_spdifout_channel = state->card->alloc_codec_spdifout_channel(state->card);
+				if (!dmabuf->codec_spdifout_channel)
+					return -EBUSY;
+			}
+			if (!dmabuf->ready && (ret = prog_dmabuf(state, 2)))
+				return ret;
+			if (dmabuf->mapped) {
+				spin_lock_irqsave(&state->card->lock, flags);
+				ali_update_ptr(state);
+				dmabuf->count = 0;
+				dmabuf->swptr = dmabuf->hwptr;
+				dmabuf->count = ali_get_free_write_space(state);
+				dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
+				__ali_update_lvi(state, 2);
+				spin_unlock_irqrestore(&state->card->lock,
+						       flags);
+			} else
+				start_spdifout(state);
+		}
+		if (val & SPDIF_ENABLE_OUTPUT && !(dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)) {
+			if (!dmabuf->controller_spdifout_channel) {
+				dmabuf->ready = 0;
+				dmabuf->controller_spdifout_channel = state->card->alloc_controller_spdifout_channel(state->card);
+				if (!dmabuf->controller_spdifout_channel)
+					return -EBUSY;
+			}
+			if (!dmabuf->ready && (ret = prog_dmabuf(state, 3)))
+				return ret;
+			if (dmabuf->mapped) {
+				spin_lock_irqsave(&state->card->lock, flags);
+				ali_update_ptr(state);
+				dmabuf->count = 0;
+				dmabuf->swptr = dmabuf->hwptr;
+				dmabuf->count = ali_get_free_write_space(state);
+				dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
+				__ali_update_lvi(state, 3);
+				spin_unlock_irqrestore(&state->card->lock, flags);
+			} else
+				start_spdifout(state);
+		}
+		if (val & PCM_ENABLE_INPUT && !(dmabuf->enable & ADC_RUNNING)) {
+			if (!dmabuf->read_channel) {
+				dmabuf->ready = 0;
+				dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
+				if (!dmabuf->read_channel)
+					return -EBUSY;
+			}
+			if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
+				return ret;
+			if (dmabuf->mapped) {
+				spin_lock_irqsave(&state->card->lock,
+						  flags);
+				ali_update_ptr(state);
+				dmabuf->swptr = dmabuf->hwptr;
+				dmabuf->count = 0;
+				spin_unlock_irqrestore(&state->card->lock, flags);
+			}
+			ali_update_lvi(state, 1);
+			start_adc(state);
+		}
+		return 0;
+	case SNDCTL_DSP_SETDUPLEX:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SETDUPLEX\n");
+#endif
+		return -EINVAL;
+	case SNDCTL_DSP_GETODELAY:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		spin_lock_irqsave(&state->card->lock, flags);
+		ali_update_ptr(state);
+		val = dmabuf->count;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count);
+#endif
+		return put_user(val, (int *) arg);
+	case SOUND_PCM_READ_RATE:
+#ifdef DEBUG
+		printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate);
+#endif
+		return put_user(dmabuf->rate, (int *) arg);
+	case SOUND_PCM_READ_CHANNELS:
+#ifdef DEBUG
+		printk("SOUND_PCM_READ_CHANNELS\n");
+#endif
+		return put_user(2, (int *) arg);
+	case SOUND_PCM_READ_BITS:
+#ifdef DEBUG
+		printk("SOUND_PCM_READ_BITS\n");
+#endif
+		return put_user(AFMT_S16_LE, (int *) arg);
+	case SNDCTL_DSP_SETSPDIF:	/* Set S/PDIF Control register */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SETSPDIF\n");
+#endif
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		/* Check to make sure the codec supports S/PDIF transmitter */
+		if ((state->card->ac97_features & 4)) {
+			/* mask out the transmitter speed bits so the user can't set them */
+			val &= ~0x3000;
+			/* Add the current transmitter speed bits to the passed value */
+			ret = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
+			val |= (ret & 0x3000);
+			ali_ac97_set(codec, AC97_SPDIF_CONTROL, val);
+			if (ali_ac97_get(codec, AC97_SPDIF_CONTROL) != val) {
+				printk(KERN_ERR "ali_audio: Unable to set S/PDIF configuration to 0x%04x.\n", val);
+				return -EFAULT;
+			}
+		}
+#ifdef DEBUG
+		else
+			printk(KERN_WARNING "ali_audio: S/PDIF transmitter not avalible.\n");
+#endif
+		return put_user(val, (int *) arg);
+	case SNDCTL_DSP_GETSPDIF:	/* Get S/PDIF Control register */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETSPDIF\n");
+#endif
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		/* Check to make sure the codec supports S/PDIF transmitter */
+		if (!(state->card->ac97_features & 4)) {
+#ifdef DEBUG
+			printk(KERN_WARNING "ali_audio: S/PDIF transmitter not avalible.\n");
+#endif
+			val = 0;
+		} else {
+			val = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
+		}
+
+		return put_user(val, (int *) arg);
+//end add support spdif out
+//add support 4,6 channel
+	case SNDCTL_DSP_GETCHANNELMASK:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETCHANNELMASK\n");
+#endif
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		/* Based on AC'97 DAC support, not ICH hardware */
+		val = DSP_BIND_FRONT;
+		if (state->card->ac97_features & 0x0004)
+			val |= DSP_BIND_SPDIF;
+		if (state->card->ac97_features & 0x0080)
+			val |= DSP_BIND_SURR;
+		if (state->card->ac97_features & 0x0140)
+			val |= DSP_BIND_CENTER_LFE;
+		return put_user(val, (int *) arg);
+	case SNDCTL_DSP_BIND_CHANNEL:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_BIND_CHANNEL\n");
+#endif
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		if (val == DSP_BIND_QUERY) {
+			val = DSP_BIND_FRONT;	/* Always report this as being enabled */
+			if (state->card->ac97_status & SPDIF_ON)
+				val |= DSP_BIND_SPDIF;
+			else {
+				if (state->card->ac97_status & SURR_ON)
+					val |= DSP_BIND_SURR;
+				if (state->card->
+				    ac97_status & CENTER_LFE_ON)
+					val |= DSP_BIND_CENTER_LFE;
+			}
+		} else {	/* Not a query, set it */
+			if (!(file->f_mode & FMODE_WRITE))
+				return -EINVAL;
+			if (dmabuf->enable == DAC_RUNNING) {
+				stop_dac(state);
+			}
+			if (val & DSP_BIND_SPDIF) {	/* Turn on SPDIF */
+				/*  Ok, this should probably define what slots
+				 *  to use. For now, we'll only set it to the
+				 *  defaults:
+				 * 
+				 *   non multichannel codec maps to slots 3&4
+				 *   2 channel codec maps to slots 7&8
+				 *   4 channel codec maps to slots 6&9
+				 *   6 channel codec maps to slots 10&11
+				 *
+				 *  there should be some way for the app to
+				 *  select the slot assignment.
+				 */
+				i_scr = inl(state->card->iobase + ALI_SCR);
+				if (codec_independent_spdif_locked > 0) {
+
+					if ((i_scr & 0x00300000) == 0x00100000) {
+						ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
+					} else {
+						if ((i_scr & 0x00300000) == 0x00200000) {
+							ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
+						} else {
+							if ((i_scr & 0x00300000) == 0x00300000) {
+								ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
+							}
+						}
+					}
+				} else {	/* codec spdif out (pcm out share ) */
+					ali_set_spdif_output(state, AC97_EA_SPSA_3_4, dmabuf->rate);	//I do not modify
+				}
+
+				if (!(state->card->ac97_status & SPDIF_ON))
+					val &= ~DSP_BIND_SPDIF;
+			} else {
+				int mask;
+				int channels;
+				/* Turn off S/PDIF if it was on */
+				if (state->card->ac97_status & SPDIF_ON)
+					ali_set_spdif_output(state, -1, 0);
+				mask =
+				    val & (DSP_BIND_FRONT | DSP_BIND_SURR |
+					   DSP_BIND_CENTER_LFE);
+				switch (mask) {
+				case DSP_BIND_FRONT:
+					channels = 2;
+					break;
+				case DSP_BIND_FRONT | DSP_BIND_SURR:
+					channels = 4;
+					break;
+				case DSP_BIND_FRONT | DSP_BIND_SURR | DSP_BIND_CENTER_LFE:
+					channels = 6;
+					break;
+				default:
+					val = DSP_BIND_FRONT;
+					channels = 2;
+					break;
+				}
+				ali_set_dac_channels(state, channels);
+				/* check that they really got turned on */
+				if (!state->card->ac97_status & SURR_ON)
+					val &= ~DSP_BIND_SURR;
+				if (!state->card->
+				    ac97_status & CENTER_LFE_ON)
+					val &= ~DSP_BIND_CENTER_LFE;
+			}
+		}
+		return put_user(val, (int *) arg);
+	case SNDCTL_DSP_MAPINBUF:
+	case SNDCTL_DSP_MAPOUTBUF:
+	case SNDCTL_DSP_SETSYNCRO:
+	case SOUND_PCM_WRITE_FILTER:
+	case SOUND_PCM_READ_FILTER:
+		return -EINVAL;
+	}
+	return -EINVAL;
+}
+
+static int ali_open(struct inode *inode, struct file *file)
+{
+	int i = 0;
+	struct ali_card *card = devs;
+	struct ali_state *state = NULL;
+	struct dmabuf *dmabuf = NULL;
+	unsigned int i_scr;
+	
+	/* find an available virtual channel (instance of /dev/dsp) */
+	
+	while (card != NULL) {
+
+		/*
+		 * If we are initializing and then fail, card could go
+		 * away unuexpectedly while we are in the for() loop.
+		 * So, check for card on each iteration before we check
+		 * for card->initializing to avoid a possible oops.
+		 * This usually only matters for times when the driver is
+		 * autoloaded by kmod.
+		 */
+		for (i = 0; i < 50 && card && card->initializing; i++) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(HZ / 20);
+		}
+
+		for (i = 0; i < NR_HW_CH && card && !card->initializing; i++) {
+			if (card->states[i] == NULL) {
+				state = card->states[i] = (struct ali_state *) kmalloc(sizeof(struct ali_state), GFP_KERNEL);
+				if (state == NULL)
+					return -ENOMEM;
+				memset(state, 0, sizeof(struct ali_state));
+				dmabuf = &state->dmabuf;
+				goto found_virt;
+			}
+		}
+		card = card->next;
+	}
+
+	/* no more virtual channel avaiable */
+	if (!state)
+		return -ENODEV;
+found_virt:
+	/* initialize the virtual channel */
+
+	state->virt = i;
+	state->card = card;
+	state->magic = ALI5455_STATE_MAGIC;
+	init_waitqueue_head(&dmabuf->wait);
+	init_MUTEX(&state->open_sem);
+	file->private_data = state;
+	dmabuf->trigger = 0;
+	/* allocate hardware channels */
+	if (file->f_mode & FMODE_READ) {
+		if ((dmabuf->read_channel =
+		     card->alloc_rec_pcm_channel(card)) == NULL) {
+			kfree(card->states[i]);
+			card->states[i] = NULL;
+			return -EBUSY;
+		}
+		dmabuf->trigger |= PCM_ENABLE_INPUT;
+		ali_set_adc_rate(state, 8000);
+	}
+	if (file->f_mode & FMODE_WRITE) {
+		if (codec_independent_spdif_locked > 0) {
+			if ((dmabuf->codec_spdifout_channel = card->alloc_codec_spdifout_channel(card)) == NULL) {
+				kfree(card->states[i]);
+				card->states[i] = NULL;
+				return -EBUSY;
+			}
+			dmabuf->trigger |= SPDIF_ENABLE_OUTPUT;
+			ali_set_codecspdifout_rate(state, codec_independent_spdif_locked);	//It must add
+			i_scr = inl(state->card->iobase + ALI_SCR);
+			if ((i_scr & 0x00300000) == 0x00100000) {
+				ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
+			} else {
+				if ((i_scr & 0x00300000) == 0x00200000) {
+					ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
+				} else {
+					if ((i_scr & 0x00300000) == 0x00300000) {
+						ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
+					} else {
+						ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
+					}
+				}
+
+			}
+		} else {
+			if (controller_independent_spdif_locked > 0) {
+				if ((dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card)) == NULL) {
+					kfree(card->states[i]);
+					card->states[i] = NULL;
+					return -EBUSY;
+				}
+				dmabuf->trigger |= SPDIF_ENABLE_OUTPUT;
+				ali_set_spdifout_rate(state, controller_independent_spdif_locked);
+			} else {
+				if ((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) {
+					kfree(card->states[i]);
+					card->states[i] = NULL;
+					return -EBUSY;
+				}
+				/* Initialize to 8kHz?  What if we don't support 8kHz? */
+				/*  Let's change this to check for S/PDIF stuff */
+
+				dmabuf->trigger |= PCM_ENABLE_OUTPUT;
+				if (codec_pcmout_share_spdif_locked) {
+					ali_set_dac_rate(state, codec_pcmout_share_spdif_locked);
+					ali_set_spdif_output(state, AC97_EA_SPSA_3_4, codec_pcmout_share_spdif_locked);
+				} else {
+					ali_set_dac_rate(state, 8000);
+				}
+			}
+
+		}
+	}
+
+	/* set default sample format. According to OSS Programmer's Guide  /dev/dsp
+	   should be default to unsigned 8-bits, mono, with sample rate 8kHz and
+	   /dev/dspW will accept 16-bits sample, but we don't support those so we
+	   set it immediately to stereo and 16bit, which is all we do support */
+	dmabuf->fmt |= ALI5455_FMT_16BIT | ALI5455_FMT_STEREO;
+	dmabuf->ossfragsize = 0;
+	dmabuf->ossmaxfrags = 0;
+	dmabuf->subdivision = 0;
+	state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+	outl(0x00000000, card->iobase + ALI_INTERRUPTCR);
+	outl(0x00000000, card->iobase + ALI_INTERRUPTSR);
+	return 0;
+}
+
+static int ali_release(struct inode *inode, struct file *file)
+{
+	struct ali_state *state = (struct ali_state *) file->private_data;
+	struct ali_card *card = state->card;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	lock_kernel();
+	
+	/* stop DMA state machine and free DMA buffers/channels */
+	if (dmabuf->trigger & PCM_ENABLE_OUTPUT)
+		drain_dac(state, 0);
+
+	if (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)
+		drain_spdifout(state, 0);
+	
+	if (dmabuf->trigger & PCM_ENABLE_INPUT)
+		stop_adc(state);
+	
+	spin_lock_irqsave(&card->lock, flags);
+	dealloc_dmabuf(state);
+	if (file->f_mode & FMODE_WRITE) {
+		if (codec_independent_spdif_locked > 0) {
+			state->card->free_pcm_channel(state->card, dmabuf->codec_spdifout_channel->num);
+		} else {
+			if (controller_independent_spdif_locked > 0)
+				state->card->free_pcm_channel(state->card,
+							      dmabuf->controller_spdifout_channel->num);
+			else state->card->free_pcm_channel(state->card,
+							      dmabuf->write_channel->num);
+		}
+	}
+	if (file->f_mode & FMODE_READ)
+		state->card->free_pcm_channel(state->card, dmabuf->read_channel->num);
+
+	state->card->states[state->virt] = NULL;
+	kfree(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+	unlock_kernel();
+	return 0;
+}
+
+static /*const */ struct file_operations ali_audio_fops = {
+	owner:THIS_MODULE, 
+	llseek:no_llseek, 
+	read:ali_read,
+	write:ali_write, 
+	poll:ali_poll,
+	ioctl:ali_ioctl,
+	mmap:ali_mmap,
+	open:ali_open,
+	release:ali_release,
+};
+
+/* Read AC97 codec registers */
+static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg)
+{
+	struct ali_card *card = dev->private_data;
+	int count1 = 100;
+	char val;
+	unsigned short int data, count, addr1, addr2;
+
+	while (count1-- && (inl(card->iobase + ALI_CAS) & 0x80000000))
+		udelay(1);
+
+	addr1 = reg;
+	reg |= 0x0080;
+	for (count = 0; count < 0x7f; count++) {
+		val = inb(card->iobase + ALI_CSPSR);
+		if (val & 0x08)
+			break;
+	}
+	if (count == 0x7f)
+		return -1;
+	outw(reg, (card->iobase + ALI_CPR) + 2);
+	for (count = 0; count < 0x7f; count++) {
+		val = inb(card->iobase + ALI_CSPSR);
+		if (val & 0x02) {
+			data = inw(card->iobase + ALI_SPR);
+			addr2 = inw((card->iobase + ALI_SPR) + 2);
+			break;
+		}
+	}
+	if (count == 0x7f)
+		return -1;
+	if (addr2 != addr1)
+		return -1;
+	return ((u16) data);
+}
+
+/* write ac97 codec register   */
+
+static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
+{
+	struct ali_card *card = dev->private_data;
+	int count1 = 100;
+	unsigned long flags;
+	char val;
+	unsigned short int count;
+
+	while (count1-- && (inl(card->iobase + ALI_CAS) & 0x80000000))
+		udelay(1);
+
+	for (count = 0; count < 0x7f; count++) {
+		val = inb(card->iobase + ALI_CSPSR);
+		if (val & 0x08)
+			break;
+	}
+	if (count == 0x7f) {
+		printk(KERN_WARNING "ali_ac96_set: AC97 codec register access timed out. \n");
+		return;
+	}
+	outw(data, (card->iobase + ALI_CPR));
+	outb(reg, (card->iobase + ALI_CPR) + 2);
+	for (count = 0; count < 0x7f; count++) {
+		val = inb(card->iobase + ALI_CSPSR);
+		if (val & 0x01)
+			break;
+	}
+	if (count == 0x7f) {
+		printk(KERN_WARNING "ali_ac96_set: AC97 codec register access timed out. \n");
+		return;
+	}
+	return;
+}
+
+/* OSS /dev/mixer file operation methods */
+
+static int ali_open_mixdev(struct inode *inode, struct file *file)
+{
+	int i;
+	int minor = MINOR(inode->i_rdev);
+	struct ali_card *card = devs;
+	for (card = devs; card != NULL; card = card->next) {
+		/*
+		 * If we are initializing and then fail, card could go
+		 * away unuexpectedly while we are in the for() loop.
+		 * So, check for card on each iteration before we check
+		 * for card->initializing to avoid a possible oops.
+		 * This usually only matters for times when the driver is
+		 * autoloaded by kmod.
+		 */
+		for (i = 0; i < 50 && card && card->initializing; i++) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(HZ / 20);
+		}
+		for (i = 0; i < NR_AC97 && card && !card->initializing; i++)
+			if (card->ac97_codec[i] != NULL
+			    && card->ac97_codec[i]->dev_mixer == minor) {
+				file->private_data = card->ac97_codec[i];
+				return 0;
+			}
+	}
+	return -ENODEV;
+}
+
+static int ali_ioctl_mixdev(struct inode *inode,
+			    struct file *file,
+			    unsigned int cmd, unsigned long arg)
+{
+	struct ac97_codec *codec = (struct ac97_codec *) file->private_data;
+	return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static /*const */ struct file_operations ali_mixer_fops = {
+	owner:THIS_MODULE, 
+	llseek:no_llseek, 
+	ioctl:ali_ioctl_mixdev,
+	open:ali_open_mixdev,
+};
+
+/* AC97 codec initialisation.  These small functions exist so we don't
+   duplicate code between module init and apm resume */
+
+static inline int ali_ac97_exists(struct ali_card *card, int ac97_number)
+{
+	unsigned int i = 1;
+	u32 reg = inl(card->iobase + ALI_RTSR);
+	if (ac97_number) {
+		while (i < 100) {
+
+			reg = inl(card->iobase + ALI_RTSR);
+			if (reg & 0x40) {
+				break;
+			} else {
+				outl(reg | 0x00000040,
+				     card->iobase + 0x34);
+				udelay(1);
+			}
+			i++;
+		}
+
+	} else {
+		while (i < 100) {
+			reg = inl(card->iobase + ALI_RTSR);
+			if (reg & 0x80) {
+				break;
+			} else {
+				outl(reg | 0x00000080,
+				     card->iobase + 0x34);
+				udelay(1);
+			}
+			i++;
+		}
+	}
+
+	if (ac97_number)
+		return reg & 0x40;
+	else
+		return reg & 0x80;
+}
+
+static inline int ali_ac97_enable_variable_rate(struct ac97_codec *codec)
+{
+	ali_ac97_set(codec, AC97_EXTENDED_STATUS, 9);
+	ali_ac97_set(codec, AC97_EXTENDED_STATUS, ali_ac97_get(codec, AC97_EXTENDED_STATUS) | 0xE800);
+	return (ali_ac97_get(codec, AC97_EXTENDED_STATUS) & 1);
+}
+
+
+static int ali_ac97_probe_and_powerup(struct ali_card *card, struct ac97_codec *codec)
+{
+	/* Returns 0 on failure */
+	int i;
+	u16 addr;
+	if (ac97_probe_codec(codec) == 0)
+		return 0;
+	/* ac97_probe_codec is success ,then begin to init codec */
+	ali_ac97_set(codec, AC97_RESET, 0xffff);
+	if (card->channel[0].used == 1) {
+		ali_ac97_set(codec, AC97_RECORD_SELECT, 0x0000);
+		ali_ac97_set(codec, AC97_LINEIN_VOL, 0x0808);
+		ali_ac97_set(codec, AC97_RECORD_GAIN, 0x0F0F);
+	}
+
+	if (card->channel[2].used == 1)	//if MICin then init codec
+	{
+		ali_ac97_set(codec, AC97_RECORD_SELECT, 0x0000);
+		ali_ac97_set(codec, AC97_MIC_VOL, 0x8808);
+		ali_ac97_set(codec, AC97_RECORD_GAIN, 0x0F0F);
+		ali_ac97_set(codec, AC97_RECORD_GAIN_MIC, 0x0000);
+	}
+
+	ali_ac97_set(codec, AC97_MASTER_VOL_STEREO, 0x0000);
+	ali_ac97_set(codec, AC97_HEADPHONE_VOL, 0x0000);
+	ali_ac97_set(codec, AC97_PCMOUT_VOL, 0x0000);
+	ali_ac97_set(codec, AC97_CD_VOL, 0x0808);
+	ali_ac97_set(codec, AC97_VIDEO_VOL, 0x0808);
+	ali_ac97_set(codec, AC97_AUX_VOL, 0x0808);
+	ali_ac97_set(codec, AC97_PHONE_VOL, 0x8048);
+	ali_ac97_set(codec, AC97_PCBEEP_VOL, 0x0000);
+	ali_ac97_set(codec, AC97_GENERAL_PURPOSE, AC97_GP_MIX);
+	ali_ac97_set(codec, AC97_MASTER_VOL_MONO, 0x0000);
+	ali_ac97_set(codec, 0x38, 0x0000);
+	addr = ali_ac97_get(codec, 0x2a);
+	ali_ac97_set(codec, 0x2a, addr | 0x0001);
+	addr = ali_ac97_get(codec, 0x2a);
+	addr = ali_ac97_get(codec, 0x28);
+	ali_ac97_set(codec, 0x2c, 0xbb80);
+	addr = ali_ac97_get(codec, 0x2c);
+	/* power it all up */
+	ali_ac97_set(codec, AC97_POWER_CONTROL,
+		     ali_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
+	/* wait for analog ready */
+	for (i = 10; i && ((ali_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ / 20);
+	}
+	/* FIXME !! */
+	i++;
+	return i;
+}
+
+
+/* I clone ali5455(2.4.7 )  not clone i810_audio(2.4.18)  */
+
+static int ali_reset_5455(struct ali_card *card)
+{
+	outl(0x80000003, card->iobase + ALI_SCR);
+	outl(0x83838383, card->iobase + ALI_FIFOCR1);
+	outl(0x83838383, card->iobase + ALI_FIFOCR2);
+	if (controller_pcmout_share_spdif_locked > 0) {
+		outl((inl(card->iobase + ALI_SPDIFICS) | 0x00000001),
+		     card->iobase + ALI_SPDIFICS);
+		outl(0x0408000a, card->iobase + ALI_INTERFACECR);
+	} else {
+		if (codec_independent_spdif_locked > 0) {
+			outl((inl(card->iobase + ALI_SCR) | 0x00100000), card->iobase + ALI_SCR);	// now I select slot 7 & 8
+			outl(0x00200000, card->iobase + ALI_INTERFACECR);	//enable codec independent spdifout 
+		} else
+			outl(0x04080002, card->iobase + ALI_INTERFACECR);
+	}
+
+	outl(0x00000000, card->iobase + ALI_INTERRUPTCR);
+	outl(0x00000000, card->iobase + ALI_INTERRUPTSR);
+	if (controller_independent_spdif_locked > 0)
+		outl((inl(card->iobase + ALI_SPDIFICS) | 0x00000001),
+		     card->iobase + ALI_SPDIFICS);
+	return 1;
+}
+
+
+static int ali_ac97_random_init_stuff(struct ali_card
+				      *card)
+{
+	u32 reg = inl(card->iobase + ALI_SCR);
+	int i = 0;
+	reg = inl(card->iobase + ALI_SCR);
+	if ((reg & 2) == 0)	/* Cold required */
+		reg |= 2;
+	else
+		reg |= 1;	/* Warm */
+	reg &= ~0x80000000;	/* ACLink on */
+	outl(reg, card->iobase + ALI_SCR);
+
+	while (i < 10) {
+		if ((inl(card->iobase + 0x18) & (1 << 1)) == 0)
+			break;
+		current->state = TASK_UNINTERRUPTIBLE;
+		schedule_timeout(HZ / 20);
+		i++;
+	}
+	if (i == 10) {
+		printk(KERN_ERR "ali_audio: AC'97 reset failed.\n");
+		return 0;
+	}
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ / 2);
+	return 1;
+}
+
+/* AC97 codec initialisation. */
+
+static int __init ali_ac97_init(struct ali_card *card)
+{
+	int num_ac97 = 0;
+	int total_channels = 0;
+	struct ac97_codec *codec;
+	u16 eid;
+
+	if (!ali_ac97_random_init_stuff(card))
+		return 0;
+
+	/* Number of channels supported */
+	/* What about the codec?  Just because the ICH supports */
+	/* multiple channels doesn't mean the codec does.       */
+	/* we'll have to modify this in the codec section below */
+	/* to reflect what the codec has.                       */
+	/* ICH and ICH0 only support 2 channels so don't bother */
+	/* to check....                                         */
+	inl(card->iobase + ALI_CPR);
+	card->channels = 2;
+
+	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+
+		/* Assume codec isn't available until we go through the
+		 * gauntlet below */
+		card->ac97_codec[num_ac97] = NULL;
+		/* The ICH programmer's reference says you should   */
+		/* check the ready status before probing. So we chk */
+		/*   What do we do if it's not ready?  Wait and try */
+		/*   again, or abort?                               */
+		if (!ali_ac97_exists(card, num_ac97)) {
+			if (num_ac97 == 0)
+				printk(KERN_ERR "ali_audio: Primary codec not ready.\n");
+			break;
+		}
+
+		if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
+			return -ENOMEM;
+		memset(codec, 0, sizeof(struct ac97_codec));
+		/* initialize some basic codec information, other fields will be filled
+		   in ac97_probe_codec */
+		codec->private_data = card;
+		codec->id = num_ac97;
+		codec->codec_read = ali_ac97_get;
+		codec->codec_write = ali_ac97_set;
+		if (!ali_ac97_probe_and_powerup(card, codec)) {
+			printk(KERN_ERR "ali_audio: timed out waiting for codec %d analog ready",
+			     num_ac97);
+			kfree(codec);
+			break;	/* it didn't work */
+		}
+		
+		/* Store state information about S/PDIF transmitter */
+		card->ac97_status = 0;
+		/* Don't attempt to get eid until powerup is complete */
+		eid = ali_ac97_get(codec, AC97_EXTENDED_ID);
+		if (eid == 0xFFFFFF) {
+			printk(KERN_ERR "ali_audio: no codec attached ?\n");
+			kfree(codec);
+			break;
+		}
+
+		card->ac97_features = eid;
+		/* Now check the codec for useful features to make up for
+		   the dumbness of the ali5455 hardware engine */
+		if (!(eid & 0x0001))
+			printk(KERN_WARNING
+			       "ali_audio: only 48Khz playback available.\n");
+		else {
+			if (!ali_ac97_enable_variable_rate(codec)) {
+				printk(KERN_WARNING
+				       "ali_audio: Codec refused to allow VRA, using 48Khz only.\n");
+				card->ac97_features &= ~1;
+			}
+		}
+
+		/* Determine how many channels the codec(s) support   */
+		/*   - The primary codec always supports 2            */
+		/*   - If the codec supports AMAP, surround DACs will */
+		/*     automaticlly get assigned to slots.            */
+		/*     * Check for surround DACs and increment if     */
+		/*       found.                                       */
+		/*   - Else check if the codec is revision 2.2        */
+		/*     * If surround DACs exist, assign them to slots */
+		/*       and increment channel count.                 */
+
+		/* All of this only applies to ICH2 and above. ICH    */
+		/* and ICH0 only support 2 channels.  ICH2 will only  */
+		/* support multiple codecs in a "split audio" config. */
+		/* as described above.                                */
+
+		/* TODO: Remove all the debugging messages!           */
+
+		if ((eid & 0xc000) == 0)	/* primary codec */
+			total_channels += 2;
+		if ((codec->dev_mixer = register_sound_mixer(&ali_mixer_fops, -1)) < 0) {
+			printk(KERN_ERR "ali_audio: couldn't register mixer!\n");
+			kfree(codec);
+			break;
+		}
+		card->ac97_codec[num_ac97] = codec;
+	}
+	/* pick the minimum of channels supported by ICHx or codec(s) */
+	card->channels = (card->channels > total_channels) ? total_channels : card->channels;
+	return num_ac97;
+}
+
+static void __init ali_configure_clocking(void)
+{
+	struct ali_card *card;
+	struct ali_state *state;
+	struct dmabuf *dmabuf;
+	unsigned int i, offset, new_offset;
+	unsigned long flags;
+	card = devs;
+
+	/* We could try to set the clocking for multiple cards, but can you even have
+	 * more than one ali in a machine?  Besides, clocking is global, so unless
+	 * someone actually thinks more than one ali in a machine is possible and
+	 * decides to rewrite that little bit, setting the rate for more than one card
+	 * is a waste of time.
+	 */
+	if (card != NULL) {
+		state = card->states[0] = (struct ali_state *)
+		    kmalloc(sizeof(struct ali_state), GFP_KERNEL);
+		if (state == NULL)
+			return;
+		memset(state, 0, sizeof(struct ali_state));
+		dmabuf = &state->dmabuf;
+		dmabuf->write_channel = card->alloc_pcm_channel(card);
+		state->virt = 0;
+		state->card = card;
+		state->magic = ALI5455_STATE_MAGIC;
+		init_waitqueue_head(&dmabuf->wait);
+		init_MUTEX(&state->open_sem);
+		dmabuf->fmt = ALI5455_FMT_STEREO | ALI5455_FMT_16BIT;
+		dmabuf->trigger = PCM_ENABLE_OUTPUT;
+		ali_set_dac_rate(state, 48000);
+		if (prog_dmabuf(state, 0) != 0)
+			goto config_out_nodmabuf;
+		
+		if (dmabuf->dmasize < 16384)
+			goto config_out;
+		
+		dmabuf->count = dmabuf->dmasize;
+		outb(31, card->iobase + dmabuf->write_channel->port + OFF_LVI);
+		
+		save_flags(flags);
+		cli();
+		start_dac(state);
+		offset = ali_get_dma_addr(state, 0);
+		mdelay(50);
+		new_offset = ali_get_dma_addr(state, 0);
+		stop_dac(state);
+		
+		outb(2, card->iobase + dmabuf->write_channel->port + OFF_CR);
+		restore_flags(flags);
+
+		i = new_offset - offset;
+
+		if (i == 0)
+			goto config_out;
+		i = i / 4 * 20;
+		if (i > 48500 || i < 47500) {
+			clocking = clocking * clocking / i;
+		}
+config_out:
+		dealloc_dmabuf(state);
+config_out_nodmabuf:
+		state->card->free_pcm_channel(state->card, state->dmabuf. write_channel->num);
+		kfree(state);
+		card->states[0] = NULL;
+	}
+}
+
+/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
+   until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
+
+static int __init ali_probe(struct pci_dev *pci_dev, const struct pci_device_id
+			    *pci_id)
+{
+	struct ali_card *card;
+	if (pci_enable_device(pci_dev))
+		return -EIO;
+	if (pci_set_dma_mask(pci_dev, ALI5455_DMA_MASK)) {
+		printk(KERN_ERR "ali5455: architecture does not support"
+		       " 32bit PCI busmaster DMA\n");
+		return -ENODEV;
+	}
+
+	if ((card = kmalloc(sizeof(struct ali_card), GFP_KERNEL)) == NULL) {
+		printk(KERN_ERR "ali_audio: out of memory\n");
+		return -ENOMEM;
+	}
+	memset(card, 0, sizeof(*card));
+	card->initializing = 1;
+	card->iobase = pci_resource_start(pci_dev, 0);
+	card->pci_dev = pci_dev;
+	card->pci_id = pci_id->device;
+	card->irq = pci_dev->irq;
+	card->next = devs;
+	card->magic = ALI5455_CARD_MAGIC;
+#ifdef CONFIG_PM
+	card->pm_suspended = 0;
+#endif
+	spin_lock_init(&card->lock);
+	devs = card;
+	pci_set_master(pci_dev);
+	printk(KERN_INFO "ali: %s found at IO 0x%04lx, IRQ %d\n",
+	       card_names[pci_id->driver_data], card->iobase, card->irq);
+	card->alloc_pcm_channel = ali_alloc_pcm_channel;
+	card->alloc_rec_pcm_channel = ali_alloc_rec_pcm_channel;
+	card->alloc_rec_mic_channel = ali_alloc_rec_mic_channel;
+	card->alloc_codec_spdifout_channel = ali_alloc_codec_spdifout_channel;
+	card->alloc_controller_spdifout_channel = ali_alloc_controller_spdifout_channel;
+	card->free_pcm_channel = ali_free_pcm_channel;
+	card->channel[0].offset = 0;
+	card->channel[0].port = 0x40;
+	card->channel[0].num = 0;
+	card->channel[1].offset = 0;
+	card->channel[1].port = 0x50;
+	card->channel[1].num = 1;
+	card->channel[2].offset = 0;
+	card->channel[2].port = 0x60;
+	card->channel[2].num = 2;
+	card->channel[3].offset = 0;
+	card->channel[3].port = 0x70;
+	card->channel[3].num = 3;
+	card->channel[4].offset = 0;
+	card->channel[4].port = 0xb0;
+	card->channel[4].num = 4;
+	/* claim our iospace and irq */
+	request_region(card->iobase, 256, card_names[pci_id->driver_data]);
+	if (request_irq(card->irq, &ali_interrupt, SA_SHIRQ,
+			card_names[pci_id->driver_data], card)) {
+		printk(KERN_ERR "ali_audio: unable to allocate irq %d\n",
+		       card->irq);
+		release_region(card->iobase, 256);
+		kfree(card);
+		return -ENODEV;
+	}
+
+	if (ali_reset_5455(card) <= 0) {
+		unregister_sound_dsp(card->dev_audio);
+		release_region(card->iobase, 256);
+		free_irq(card->irq, card);
+		kfree(card);
+		return -ENODEV;
+	}
+
+	/* initialize AC97 codec and register /dev/mixer */
+	if (ali_ac97_init(card) < 0) {
+		release_region(card->iobase, 256);
+		free_irq(card->irq, card);
+		kfree(card);
+		return -ENODEV;
+	}
+	
+	pci_set_drvdata(pci_dev, card);
+	
+	if (clocking == 0) {
+		clocking = 48000;
+		ali_configure_clocking();
+	}
+
+	/* register /dev/dsp */
+	if ((card->dev_audio = register_sound_dsp(&ali_audio_fops, -1)) < 0) {
+		int i;
+		printk(KERN_ERR"ali_audio: couldn't register DSP device!\n");
+		release_region(card->iobase, 256);
+		free_irq(card->irq, card);
+		for (i = 0; i < NR_AC97; i++)
+			if (card->ac97_codec[i] != NULL) {
+				unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
+				kfree(card->ac97_codec[i]);
+			}
+		kfree(card);
+		return -ENODEV;
+	}
+	card->initializing = 0;
+	return 0;
+}
+
+static void __devexit ali_remove(struct pci_dev *pci_dev)
+{
+	int i;
+	struct ali_card *card = pci_get_drvdata(pci_dev);
+	/* free hardware resources */
+	free_irq(card->irq, devs);
+	release_region(card->iobase, 256);
+	/* unregister audio devices */
+	for (i = 0; i < NR_AC97; i++)
+		if (card->ac97_codec[i] != NULL) {
+			unregister_sound_mixer(card->ac97_codec[i]->
+					       dev_mixer);
+			kfree(card->ac97_codec[i]);
+			card->ac97_codec[i] = NULL;
+		}
+	unregister_sound_dsp(card->dev_audio);
+	kfree(card);
+}
+
+#ifdef CONFIG_PM
+static int ali_pm_suspend(struct pci_dev *dev, u32 pm_state)
+{
+	struct ali_card *card = pci_get_drvdata(dev);
+	struct ali_state *state;
+	unsigned long flags;
+	struct dmabuf *dmabuf;
+	int i, num_ac97;
+
+	if (!card)
+		return 0;
+	spin_lock_irqsave(&card->lock, flags);
+	card->pm_suspended = 1;
+	for (i = 0; i < NR_HW_CH; i++) {
+		state = card->states[i];
+		if (!state)
+			continue;
+		/* this happens only if there are open files */
+		dmabuf = &state->dmabuf;
+		if (dmabuf->enable & DAC_RUNNING ||
+		    (dmabuf->count
+		     && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) {
+			state->pm_saved_dac_rate = dmabuf->rate;
+			stop_dac(state);
+		} else {
+			state->pm_saved_dac_rate = 0;
+		}
+		if (dmabuf->enable & ADC_RUNNING) {
+			state->pm_saved_adc_rate = dmabuf->rate;
+			stop_adc(state);
+		} else {
+			state->pm_saved_adc_rate = 0;
+		}
+		dmabuf->ready = 0;
+		dmabuf->swptr = dmabuf->hwptr = 0;
+		dmabuf->count = dmabuf->total_bytes = 0;
+	}
+
+	spin_unlock_irqrestore(&card->lock, flags);
+	/* save mixer settings */
+	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+		struct ac97_codec *codec = card->ac97_codec[num_ac97];
+		if (!codec)
+			continue;
+		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+			if ((supported_mixer(codec, i)) && (codec->read_mixer)) {
+				card->pm_saved_mixer_settings[i][num_ac97] = codec->read_mixer(codec, i);
+			}
+		}
+	}
+	pci_save_state(dev, card->pm_save_state);	/* XXX do we need this? */
+	pci_disable_device(dev);	/* disable busmastering */
+	pci_set_power_state(dev, 3);	/* Zzz. */
+	return 0;
+}
+
+
+static int ali_pm_resume(struct pci_dev *dev)
+{
+	int num_ac97, i = 0;
+	struct ali_card *card = pci_get_drvdata(dev);
+	pci_enable_device(dev);
+	pci_restore_state(dev, card->pm_save_state);
+	/* observation of a toshiba portege 3440ct suggests that the 
+	   hardware has to be more or less completely reinitialized from
+	   scratch after an apm suspend.  Works For Me.   -dan */
+	ali_ac97_random_init_stuff(card);
+	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+		struct ac97_codec *codec = card->ac97_codec[num_ac97];
+		/* check they haven't stolen the hardware while we were
+		   away */
+		if (!codec || !ali_ac97_exists(card, num_ac97)) {
+			if (num_ac97)
+				continue;
+			else
+				BUG();
+		}
+		if (!ali_ac97_probe_and_powerup(card, codec))
+			BUG();
+		if ((card->ac97_features & 0x0001)) {
+			/* at probe time we found we could do variable
+			   rates, but APM suspend has made it forget
+			   its magical powers */
+			if (!ali_ac97_enable_variable_rate(codec))
+				BUG();
+		}
+		/* we lost our mixer settings, so restore them */
+		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+			if (supported_mixer(codec, i)) {
+				int val = card->pm_saved_mixer_settings[i][num_ac97];
+				codec->mixer_state[i] = val;
+				codec->write_mixer(codec, i,
+						   (val & 0xff),
+						   ((val >> 8) & 0xff));
+			}
+		}
+	}
+
+	/* we need to restore the sample rate from whatever it was */
+	for (i = 0; i < NR_HW_CH; i++) {
+		struct ali_state *state = card->states[i];
+		if (state) {
+			if (state->pm_saved_adc_rate)
+				ali_set_adc_rate(state, state->pm_saved_adc_rate);
+			if (state->pm_saved_dac_rate)
+				ali_set_dac_rate(state, state->pm_saved_dac_rate);
+		}
+	}
+
+	card->pm_suspended = 0;
+	/* any processes that were reading/writing during the suspend
+	   probably ended up here */
+	for (i = 0; i < NR_HW_CH; i++) {
+		struct ali_state *state = card->states[i];
+		if (state)
+			wake_up(&state->dmabuf.wait);
+	}
+	return 0;
+}
+#endif				/* CONFIG_PM */
+
+MODULE_AUTHOR("");
+MODULE_DESCRIPTION("ALI 5455 audio support");
+MODULE_LICENSE("GPL");
+MODULE_PARM(clocking, "i");
+MODULE_PARM(strict_clocking, "i");
+MODULE_PARM(codec_pcmout_share_spdif_locked, "i");
+MODULE_PARM(codec_independent_spdif_locked, "i");
+MODULE_PARM(controller_pcmout_share_spdif_locked, "i");
+MODULE_PARM(controller_independent_spdif_locked, "i");
+#define ALI5455_MODULE_NAME "ali5455"
+static struct pci_driver ali_pci_driver = {
+	name:ALI5455_MODULE_NAME, id_table:ali_pci_tbl, probe:ali_probe,
+	    remove:__devexit_p(ali_remove),
+#ifdef CONFIG_PM
+	suspend:ali_pm_suspend, resume:ali_pm_resume,
+#endif				/* CONFIG_PM */
+};
+
+static int __init ali_init_module(void)
+{
+	if (!pci_present())	/* No PCI bus in this machine! */
+		return -ENODEV;
+	printk(KERN_INFO "ALI 5455 + AC97 Audio, version "
+	       DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
+
+	if (codec_independent_spdif_locked > 0) {
+		if (codec_independent_spdif_locked == 32000
+		    || codec_independent_spdif_locked == 44100
+		    || codec_independent_spdif_locked == 48000) {
+			printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", codec_independent_spdif_locked);
+		} else {
+			printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
+			codec_independent_spdif_locked = 0;
+		}
+	}
+	if (controller_independent_spdif_locked > 0) {
+		if (controller_independent_spdif_locked == 32000
+		    || controller_independent_spdif_locked == 44100
+		    || controller_independent_spdif_locked == 48000) {
+			printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", controller_independent_spdif_locked);
+		} else {
+			printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
+			controller_independent_spdif_locked = 0;
+		}
+	}
+
+	if (codec_pcmout_share_spdif_locked > 0) {
+		if (codec_pcmout_share_spdif_locked == 32000
+		    || codec_pcmout_share_spdif_locked == 44100
+		    || codec_pcmout_share_spdif_locked == 48000) {
+			printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", codec_pcmout_share_spdif_locked);
+		} else {
+			printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
+			codec_pcmout_share_spdif_locked = 0;
+		}
+	}
+	if (controller_pcmout_share_spdif_locked > 0) {
+		if (controller_pcmout_share_spdif_locked == 32000
+		    || controller_pcmout_share_spdif_locked == 44100
+		    || controller_pcmout_share_spdif_locked == 48000) {
+			printk(KERN_INFO "ali_audio: Enabling controller S/PDIF at sample rate %dHz.\n", controller_pcmout_share_spdif_locked);
+		} else {
+			printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
+			controller_pcmout_share_spdif_locked = 0;
+		}
+	}
+	if (!pci_register_driver(&ali_pci_driver)) {
+		pci_unregister_driver(&ali_pci_driver);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void __exit ali_cleanup_module(void)
+{
+	pci_unregister_driver(&ali_pci_driver);
+}
+
+module_init(ali_init_module);
+module_exit(ali_cleanup_module);
+/*
+Local Variables:
+c-basic-offset: 8
+End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/au1000.c linux-2.4.20/drivers/sound/au1000.c
--- linux-2.4.19/drivers/sound/au1000.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/sound/au1000.c	2002-10-29 11:18:32.000000000 +0000
@@ -42,6 +42,13 @@
  *
  *  Revision history
  *    06.27.2001  Initial version
+ *    03.20.2002  Added mutex locks around read/write methods, to prevent
+ *                simultaneous access on SMP or preemptible kernels. Also
+ *                removed the counter/pointer fragment aligning at the end
+ *                of read/write methods [stevel].
+ *    03.21.2002  Add support for coherent DMA on the audio read/write DMA
+ *                channels [stevel].
+ *
  */
 #include <linux/version.h>
 #include <linux/module.h>
@@ -73,6 +80,7 @@
 #define AU1000_DEBUG
 #undef AU1000_VERBOSE_DEBUG
 
+#define USE_COHERENT_DMA
 
 #define AU1000_MODULE_NAME "Au1000 audio"
 #define PFX AU1000_MODULE_NAME
@@ -110,18 +118,18 @@
 #endif				/* AU1000_DEBUG */
 
 	struct ac97_codec codec;
-	unsigned        codec_base_caps;	// AC'97 reg 00h, "Reset Register"
+	unsigned        codec_base_caps;// AC'97 reg 00h, "Reset Register"
 	unsigned        codec_ext_caps;	// AC'97 reg 28h, "Extended Audio ID"
 	int             no_vra;	// do not use VRA
 
 	spinlock_t      lock;
 	struct semaphore open_sem;
+	struct semaphore sem;
 	mode_t          open_mode;
 	wait_queue_head_t open_wait;
 
 	struct dmabuf {
 		unsigned int    dmanr;	// DMA Channel number
-		int             irq;	// DMA Channel Done IRQ number
 		unsigned        sample_rate;	// Hz
 		unsigned src_factor;     // SRC interp/decimation (no vra)
 		unsigned        sample_size;	// 8 or 16
@@ -136,7 +144,7 @@
 		unsigned numfrag;        // # of DMA fragments in DMA buffer
 		unsigned        fragshift;
 		void           *nextIn;	// ptr to next-in to DMA buffer
-		void           *nextOut;	// ptr to next-out from DMA buffer
+		void           *nextOut;// ptr to next-out from DMA buffer
 		int             count;	// current byte count in DMA buffer
 		unsigned        total_bytes;	// total bytes written or read
 		unsigned        error;	// over/underrun
@@ -185,6 +193,34 @@
 }
 
 
+#ifdef USE_COHERENT_DMA
+static inline void * dma_alloc(size_t size, dma_addr_t * dma_handle)
+{
+	void* ret = (void *)__get_free_pages(GFP_ATOMIC | GFP_DMA,
+					     get_order(size));
+	if (ret != NULL) {
+		memset(ret, 0, size);
+		*dma_handle = virt_to_phys(ret);
+	}
+	return ret;
+}
+
+static inline void dma_free(size_t size, void* va, dma_addr_t dma_handle)
+{
+	free_pages((unsigned long)va, get_order(size));
+}
+#else
+static inline void * dma_alloc(size_t size, dma_addr_t * dma_handle)
+{
+	return pci_alloc_consistent(NULL, size, dma_handle);
+}
+
+static inline void dma_free(size_t size, void* va, dma_addr_t dma_handle)
+{
+	pci_free_consistent(NULL, size, va, dma_handle);
+}
+#endif
+
 /* --------------------------------------------------------------------- */
 
 static void au1000_delay(int msec)
@@ -304,6 +340,7 @@
 
 /* --------------------------------------------------------------------- */
 
+/* stop the ADC before calling */
 static void set_adc_rate(struct au1000_state *s, unsigned rate)
 {
 	struct dmabuf  *adc = &s->dma_adc;
@@ -348,6 +385,7 @@
 	dac->sample_rate = dac_rate;
 }
 
+/* stop the DAC before calling */
 static void set_dac_rate(struct au1000_state *s, unsigned rate)
 {
 	struct dmabuf  *dac = &s->dma_dac;
@@ -483,17 +521,20 @@
 
 	set_xmit_slots(db->num_channels);
 
-	set_dma_count(db->dmanr, db->dma_fragsize>>1);
+	init_dma(db->dmanr);
 	if (get_dma_active_buffer(db->dmanr) == 0) {
+		clear_dma_done0(db->dmanr);	// clear DMA done bit
 		set_dma_addr0(db->dmanr, buf1);
 		set_dma_addr1(db->dmanr, buf2);
 	} else {
+		clear_dma_done1(db->dmanr);	// clear DMA done bit
 		set_dma_addr1(db->dmanr, buf1);
 		set_dma_addr0(db->dmanr, buf2);
 	}
+	set_dma_count(db->dmanr, db->dma_fragsize>>1);
 	enable_dma_buffers(db->dmanr);
 
-	enable_dma(db->dmanr);
+	start_dma(db->dmanr);
 
 #ifdef AU1000_VERBOSE_DEBUG
 	dump_au1000_dma_channel(db->dmanr);
@@ -525,17 +566,20 @@
 
 	set_recv_slots(db->num_channels);
 
-	set_dma_count(db->dmanr, db->dma_fragsize>>1);
+	init_dma(db->dmanr);
 	if (get_dma_active_buffer(db->dmanr) == 0) {
+		clear_dma_done0(db->dmanr);	// clear DMA done bit
 		set_dma_addr0(db->dmanr, buf1);
 		set_dma_addr1(db->dmanr, buf2);
 	} else {
+		clear_dma_done1(db->dmanr);	// clear DMA done bit
 		set_dma_addr1(db->dmanr, buf1);
 		set_dma_addr0(db->dmanr, buf2);
 	}
+	set_dma_count(db->dmanr, db->dma_fragsize>>1);
 	enable_dma_buffers(db->dmanr);
 
-	enable_dma(db->dmanr);
+	start_dma(db->dmanr);
 
 #ifdef AU1000_VERBOSE_DEBUG
 	dump_au1000_dma_channel(db->dmanr);
@@ -561,8 +605,7 @@
 				    (PAGE_SIZE << db->buforder) - 1);
 		for (page = virt_to_page(db->rawbuf); page <= pend; page++)
 			mem_map_unreserve(page);
-		pci_free_consistent(NULL, PAGE_SIZE << db->buforder,
-				    db->rawbuf, db->dmaaddr);
+		dma_free(PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
 	}
 	db->rawbuf = db->nextIn = db->nextOut = NULL;
 	db->mapped = db->ready = 0;
@@ -580,9 +623,7 @@
 		db->ready = db->mapped = 0;
 		for (order = DMABUF_DEFAULTORDER;
 		     order >= DMABUF_MINORDER; order--)
-			if ((db->rawbuf =
-			     pci_alloc_consistent(NULL,
-						  PAGE_SIZE << order,
+			if ((db->rawbuf = dma_alloc(PAGE_SIZE << order,
 						  &db->dmaaddr)))
 				break;
 		if (!db->rawbuf)
@@ -686,6 +727,8 @@
 		return;
 	}
 
+	spin_lock(&s->lock);
+	
 	if (buff_done != (DMA_D0 | DMA_D1)) {
 		dac->nextOut += dac->dma_fragsize;
 		if (dac->nextOut >= dac->rawbuf + dac->dmasize)
@@ -699,9 +742,16 @@
 		dac->count -= dac->dma_fragsize;
 		dac->total_bytes += dac->dma_fragsize;
 
-		if (dac->count <= 0)
+		if (dac->count <= 0) {
+#ifdef AU1000_VERBOSE_DEBUG
+			dbg("dac underrun");
+#endif
+			spin_unlock(&s->lock);
 			stop_dac(s);
-		else if (buff_done == DMA_D0) {
+			spin_lock(&s->lock);
+			dac->count = 0;
+			dac->nextIn = dac->nextOut;
+		} else if (buff_done == DMA_D0) {
 			clear_dma_done0(dac->dmanr);	// clear DMA done bit
 			set_dma_count0(dac->dmanr, dac->dma_fragsize>>1);
 			set_dma_addr0(dac->dmanr, newptr);
@@ -714,7 +764,9 @@
 		}
 	} else {
 		// both done bits set, we missed an interrupt
+		spin_unlock(&s->lock);
 		stop_dac(s);
+		spin_lock(&s->lock);
 
 		dac->nextOut += 2*dac->dma_fragsize;
 		if (dac->nextOut >= dac->rawbuf + dac->dmasize)
@@ -723,14 +775,18 @@
 		dac->count -= 2*dac->dma_fragsize;
 		dac->total_bytes += 2*dac->dma_fragsize;
 
-		if (dac->count > 0)
+		if (dac->count > 0) {
+			spin_unlock(&s->lock);
 			start_dac(s);
+			spin_lock(&s->lock);
+		}
 	}
 
-
 	/* wake up anybody listening */
 	if (waitqueue_active(&dac->wait))
-		wake_up_interruptible(&dac->wait);
+		wake_up(&dac->wait);
+
+	spin_unlock(&s->lock);
 }
 
 
@@ -752,9 +808,12 @@
 		return;
 	}
 
+	spin_lock(&s->lock);
+	
 	if (buff_done != (DMA_D0 | DMA_D1)) {
 		if (adc->count + adc->dma_fragsize > adc->dmasize) {
 			// Overrun. Stop ADC and log the error
+			spin_unlock(&s->lock);
 			stop_adc(s);
 			adc->error++;
 			err("adc overrun");
@@ -786,12 +845,15 @@
 		}
 	} else {
 		// both done bits set, we missed an interrupt
+		spin_unlock(&s->lock);
 		stop_adc(s);
+		spin_lock(&s->lock);
 		
 		if (adc->count + 2*adc->dma_fragsize > adc->dmasize) {
 			// Overrun. Log the error
 			adc->error++;
 			err("adc overrun");
+			spin_unlock(&s->lock);
 			return;
 		}
 
@@ -802,12 +864,16 @@
 		adc->count += 2*adc->dma_fragsize;
 		adc->total_bytes += 2*adc->dma_fragsize;
 		
+		spin_unlock(&s->lock);
 		start_adc(s);
+		spin_lock(&s->lock);
 	}
 
 	/* wake up anybody listening */
 	if (waitqueue_active(&adc->wait))
-		wake_up_interruptible(&adc->wait);
+		wake_up(&adc->wait);
+
+	spin_unlock(&s->lock);
 }
 
 /* --------------------------------------------------------------------- */
@@ -924,7 +990,7 @@
 	for (sample = 0; sample < num_samples; sample++) {
 		if (copy_from_user(usersample, userbuf,
 				   db->user_bytes_per_sample)) {
-			dbg(__FUNCTION__ "fault");
+			dbg(__FUNCTION__ ": fault");
 			return -EFAULT;
 		}
 
@@ -988,7 +1054,7 @@
 
 		if (copy_to_user(userbuf, usersample,
 				 db->user_bytes_per_sample)) {
-			dbg(__FUNCTION__ "fault");
+			dbg(__FUNCTION__ ": fault");
 			return -EFAULT;
 		}
 
@@ -1050,9 +1116,10 @@
 {
 	struct au1000_state *s = (struct au1000_state *)file->private_data;
 	struct dmabuf  *db = &s->dma_adc;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t         ret;
 	unsigned long   flags;
-	int             cnt, remainder, usercnt, avail;
+	int             cnt, usercnt, avail;
 
 	if (ppos != &file->f_pos)
 		return -ESPIPE;
@@ -1064,6 +1131,9 @@
 
 	count *= db->cnt_factor;
 
+	down(&s->sem);
+	add_wait_queue(&db->wait, &wait);
+
 	while (count > 0) {
 		// wait for samples in ADC dma buffer
 		do {
@@ -1071,19 +1141,23 @@
 				start_adc(s);
 			spin_lock_irqsave(&s->lock, flags);
 			avail = db->count;
+			if (avail <= 0)
+				__set_current_state(TASK_INTERRUPTIBLE);
 			spin_unlock_irqrestore(&s->lock, flags);
 			if (avail <= 0) {
 				if (file->f_flags & O_NONBLOCK) {
 					if (!ret)
 						ret = -EAGAIN;
-					return ret;
+					goto out;
 				}
-				interruptible_sleep_on(&db->wait);
+				up(&s->sem);
+				schedule();
 				if (signal_pending(current)) {
 					if (!ret)
 						ret = -ERESTARTSYS;
-					return ret;
+					goto out2;
 				}
+				down(&s->sem);
 			}
 		} while (avail <= 0);
 
@@ -1093,16 +1167,15 @@
 					    avail : count, 1)) < 0) {
 			if (!ret)
 				ret = -EFAULT;
-			return ret;
+			goto out;
 		}
 
 		spin_lock_irqsave(&s->lock, flags);
 		db->count -= cnt;
-		spin_unlock_irqrestore(&s->lock, flags);
-
 		db->nextOut += cnt;
 		if (db->nextOut >= db->rawbuf + db->dmasize)
 			db->nextOut -= db->dmasize;
+		spin_unlock_irqrestore(&s->lock, flags);
 
 		count -= cnt;
 		usercnt = cnt / db->cnt_factor;
@@ -1110,25 +1183,11 @@
 		ret += usercnt;
 	}			// while (count > 0)
 
-	/*
-	 * See if the dma buffer count after this read call is
-	 * aligned on a dma_fragsize boundary. If not, read from
-	 * buffer until we reach a boundary, and let's hope this
-	 * is just the last remainder of an audio record. If not
-	 * it means the user is not reading in fragsize chunks, in
-	 * which case it's his/her fault that there are audio gaps
-	 * in their record.
-	 */
-	spin_lock_irqsave(&s->lock, flags);
-	remainder = db->count % db->dma_fragsize;
-	if (remainder) {
-		db->nextOut += remainder;
-		if (db->nextOut >= db->rawbuf + db->dmasize)
-			db->nextOut -= db->dmasize;
-		db->count -= remainder;
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-
+out:
+	up(&s->sem);
+out2:
+	remove_wait_queue(&db->wait, &wait);
+	set_current_state(TASK_RUNNING);
 	return ret;
 }
 
@@ -1137,9 +1196,14 @@
 {
 	struct au1000_state *s = (struct au1000_state *)file->private_data;
 	struct dmabuf  *db = &s->dma_dac;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t         ret = 0;
 	unsigned long   flags;
-	int             cnt, remainder, usercnt, avail;
+	int             cnt, usercnt, avail;
+
+#ifdef AU1000_VERBOSE_DEBUG
+	dbg("write: count=%d", count);
+#endif
 
 	if (ppos != &file->f_pos)
 		return -ESPIPE;
@@ -1150,45 +1214,51 @@
 
 	count *= db->cnt_factor;
 
+	down(&s->sem);	
+	add_wait_queue(&db->wait, &wait);
+
 	while (count > 0) {
 		// wait for space in playback buffer
 		do {
 			spin_lock_irqsave(&s->lock, flags);
 			avail = (int) db->dmasize - db->count;
+			if (avail <= 0)
+				__set_current_state(TASK_INTERRUPTIBLE);
 			spin_unlock_irqrestore(&s->lock, flags);
 			if (avail <= 0) {
 				if (file->f_flags & O_NONBLOCK) {
 					if (!ret)
 						ret = -EAGAIN;
-					return ret;
+					goto out;
 				}
-				interruptible_sleep_on(&db->wait);
+				up(&s->sem);
+				schedule();
 				if (signal_pending(current)) {
 					if (!ret)
 						ret = -ERESTARTSYS;
-					return ret;
+					goto out2;
 				}
+				down(&s->sem);
 			}
 		} while (avail <= 0);
 
-		// copy to nextIn
+		// copy from user to nextIn
 		if ((cnt = copy_dmabuf_user(db, (char *) buffer,
 					    count > avail ?
 					    avail : count, 0)) < 0) {
 			if (!ret)
 				ret = -EFAULT;
-			return ret;
+			goto out;
 		}
 
 		spin_lock_irqsave(&s->lock, flags);
 		db->count += cnt;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (db->stopped)
-			start_dac(s);
-
 		db->nextIn += cnt;
 		if (db->nextIn >= db->rawbuf + db->dmasize)
 			db->nextIn -= db->dmasize;
+		spin_unlock_irqrestore(&s->lock, flags);
+		if (db->stopped)
+			start_dac(s);
 
 		count -= cnt;
 		usercnt = cnt / db->cnt_factor;
@@ -1196,27 +1266,11 @@
 		ret += usercnt;
 	}			// while (count > 0)
 
-	/*
-	 * See if the dma buffer count after this write call is
-	 * aligned on a dma_fragsize boundary. If not, fill buffer
-	 * with silence to the next boundary, and let's hope this
-	 * is just the last remainder of an audio playback. If not
-	 * it means the user is not sending us fragsize chunks, in
-	 * which case it's his/her fault that there are audio gaps
-	 * in their playback.
-	 */
-	spin_lock_irqsave(&s->lock, flags);
-	remainder = db->count % db->dma_fragsize;
-	if (remainder) {
-		int fill_cnt = db->dma_fragsize - remainder;
-		memset(db->nextIn, 0, fill_cnt);
-		db->nextIn += fill_cnt;
-		if (db->nextIn >= db->rawbuf + db->dmasize)
-			db->nextIn -= db->dmasize;
-		db->count += fill_cnt;
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-
+out:
+	up(&s->sem);
+out2:
+	remove_wait_queue(&db->wait, &wait);
+	set_current_state(TASK_RUNNING);
 	return ret;
 }
 
@@ -1241,6 +1295,7 @@
 	}
 
 	spin_lock_irqsave(&s->lock, flags);
+	
 	if (file->f_mode & FMODE_READ) {
 		if (s->dma_adc.count >= (signed)s->dma_adc.dma_fragsize)
 			mask |= POLLIN | POLLRDNORM;
@@ -1265,35 +1320,40 @@
 	struct au1000_state *s = (struct au1000_state *)file->private_data;
 	struct dmabuf  *db;
 	unsigned long   size;
+	int ret = 0;
 
 	dbg(__FUNCTION__);
     
 	lock_kernel();
+	down(&s->sem);
 	if (vma->vm_flags & VM_WRITE)
 		db = &s->dma_dac;
 	else if (vma->vm_flags & VM_READ)
 		db = &s->dma_adc;
 	else {
-		unlock_kernel();
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 	if (vma->vm_pgoff != 0) {
-		unlock_kernel();
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 	size = vma->vm_end - vma->vm_start;
 	if (size > (PAGE_SIZE << db->buforder)) {
-		unlock_kernel();
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf),
 			     size, vma->vm_page_prot)) {
-		unlock_kernel();
-		return -EAGAIN;
+		ret = -EAGAIN;
+		goto out;
 	}
+	vma->vm_flags &= ~VM_IO;
 	db->mapped = 1;
+out:
+	up(&s->sem);
 	unlock_kernel();
-	return 0;
+	return ret;
 }
 
 
@@ -1368,9 +1428,9 @@
 			break;
 	}
 	if (count < sizeof(ioctl_str) / sizeof(ioctl_str[0]))
-		dbg("ioctl %s, arg=0x%x", ioctl_str[count].str, arg);
+		dbg("ioctl %s, arg=0x%lx", ioctl_str[count].str, arg);
 	else
-		dbg("ioctl 0x%s unknown, arg=0x%x", cmd, arg);
+		dbg("ioctl 0x%x unknown, arg=0x%lx", cmd, arg);
 #endif
 
 	switch (cmd) {
@@ -1609,6 +1669,9 @@
 			s->dma_dac.cnt_factor;
 		abinfo.fragstotal = s->dma_dac.numfrag;
 		abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+#ifdef AU1000_VERBOSE_DEBUG
+		dbg("bytes=%d, fragments=%d", abinfo.bytes, abinfo.fragments);
+#endif
 		return copy_to_user((void *) arg, &abinfo,
 				    sizeof(abinfo)) ? -EFAULT : 0;
 
@@ -1844,6 +1907,7 @@
 
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
 	up(&s->open_sem);
+	init_MUTEX(&s->sem);
 	return 0;
 }
 
@@ -1852,8 +1916,13 @@
 	struct au1000_state *s = (struct au1000_state *)file->private_data;
 
 	lock_kernel();
-	if (file->f_mode & FMODE_WRITE)
+	
+	if (file->f_mode & FMODE_WRITE) {
+		unlock_kernel();
 		drain_dac(s, file->f_flags & O_NONBLOCK);
+		lock_kernel();
+	}
+
 	down(&s->open_sem);
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(s);
@@ -1906,9 +1975,12 @@
 	// print out digital controller state
 	len += sprintf(buf + len, "AU1000 Audio Controller registers\n");
 	len += sprintf(buf + len, "---------------------------------\n");
-	len += sprintf (buf + len, "AC97C_CONFIG = %08x\n", au_readl(AC97C_CONFIG));
-	len += sprintf (buf + len, "AC97C_STATUS = %08x\n", au_readl(AC97C_STATUS));
-	len += sprintf (buf + len, "AC97C_CNTRL  = %08x\n", au_readl(AC97C_CNTRL));
+	len += sprintf (buf + len, "AC97C_CONFIG = %08x\n",
+			au_readl(AC97C_CONFIG));
+	len += sprintf (buf + len, "AC97C_STATUS = %08x\n",
+			au_readl(AC97C_STATUS));
+	len += sprintf (buf + len, "AC97C_CNTRL  = %08x\n",
+			au_readl(AC97C_CNTRL));
 
 	/* print out CODEC state */
 	len += sprintf(buf + len, "\nAC97 CODEC registers\n");
@@ -1964,33 +2036,37 @@
 	}
 	// Allocate the DMA Channels
 	if ((s->dma_dac.dmanr = request_au1000_dma(DMA_ID_AC97C_TX,
-						   "audio DAC")) < 0) {
+						   "audio DAC",
+						   dac_dma_interrupt,
+						   SA_INTERRUPT, s)) < 0) {
 		err("Can't get DAC DMA");
 		goto err_dma1;
 	}
 	if ((s->dma_adc.dmanr = request_au1000_dma(DMA_ID_AC97C_RX,
-						   "audio ADC")) < 0) {
+						   "audio ADC",
+						   adc_dma_interrupt,
+						   SA_INTERRUPT, s)) < 0) {
 		err("Can't get ADC DMA");
 		goto err_dma2;
 	}
 
-	s->dma_dac.irq = get_dma_done_irq(s->dma_dac.dmanr);
-	s->dma_adc.irq = get_dma_done_irq(s->dma_adc.dmanr);
-
-	if (request_irq(s->dma_dac.irq, dac_dma_interrupt,
-			SA_INTERRUPT, "audio DAC", s)) {
-		err("Can't get DAC irq #%d", s->dma_dac.irq);
-		goto err_irq1;
-	}
-	if (request_irq(s->dma_adc.irq, adc_dma_interrupt,
-			SA_INTERRUPT, "audio ADC", s)) {
-		err("Can't get ADC irq #%d", s->dma_adc.irq);
-		goto err_irq2;
-	}
-
 	info("DAC: DMA%d/IRQ%d, ADC: DMA%d/IRQ%d",
-	     s->dma_dac.dmanr, s->dma_dac.irq,
-	     s->dma_adc.dmanr, s->dma_adc.irq);
+	     s->dma_dac.dmanr, get_dma_done_irq(s->dma_dac.dmanr),
+	     s->dma_adc.dmanr, get_dma_done_irq(s->dma_adc.dmanr));
+
+#ifdef USE_COHERENT_DMA
+	// enable DMA coherency in read/write DMA channels
+	set_dma_mode(s->dma_dac.dmanr,
+		     get_dma_mode(s->dma_dac.dmanr) & ~DMA_NC);
+	set_dma_mode(s->dma_adc.dmanr,
+		     get_dma_mode(s->dma_adc.dmanr) & ~DMA_NC);
+#else
+	// disable DMA coherency in read/write DMA channels
+	set_dma_mode(s->dma_dac.dmanr,
+		     get_dma_mode(s->dma_dac.dmanr) | DMA_NC);
+	set_dma_mode(s->dma_adc.dmanr,
+		     get_dma_mode(s->dma_adc.dmanr) | DMA_NC);
+#endif
 
 	/* register devices */
 
@@ -2089,10 +2165,6 @@
  err_dma2:
 	free_au1000_dma(s->dma_dac.dmanr);
  err_dma1:
-	free_irq(s->dma_adc.irq, s);
- err_irq2:
-	free_irq(s->dma_dac.irq, s);
- err_irq1:
 	release_region(virt_to_phys((void *) AC97C_CONFIG), 0x14);
 	return -1;
 }
@@ -2108,8 +2180,6 @@
 		remove_proc_entry(AU1000_MODULE_NAME, NULL);
 #endif /* AU1000_DEBUG */
 	synchronize_irq();
-	free_irq(s->dma_adc.irq, s);
-	free_irq(s->dma_dac.irq, s);
 	free_au1000_dma(s->dma_adc.dmanr);
 	free_au1000_dma(s->dma_dac.dmanr);
 	release_region(virt_to_phys((void *) AC97C_CONFIG), 0x14);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/awe_wave.c linux-2.4.20/drivers/sound/awe_wave.c
--- linux-2.4.19/drivers/sound/awe_wave.c	2001-09-30 19:26:08.000000000 +0000
+++ linux-2.4.20/drivers/sound/awe_wave.c	2002-10-29 11:18:39.000000000 +0000
@@ -4773,21 +4773,16 @@
 }
 	
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
-static struct {
-	unsigned short card_vendor, card_device;
-	unsigned short vendor;
-	unsigned short function;
-	char *name;
-} isapnp_awe_list[] __initdata = {
+static struct isapnp_device_id isapnp_awe_list[] __initdata = {
 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021),
-		"AWE32 WaveTable" },
+		(unsigned long)"AWE32 WaveTable" },
 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022),
-		"AWE64 WaveTable" },
+		(unsigned long)"AWE64 WaveTable" },
 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023),
-		"AWE64 Gold WaveTable" },
+		(unsigned long)"AWE64 Gold WaveTable" },
 	{0}
 };
 
@@ -4818,7 +4813,7 @@
 		if (!idev)
 			continue;
 		printk(KERN_INFO "ISAPnP reports %s at i/o %#x\n",
-		       isapnp_awe_list[i].name, *port);
+		       (char*)isapnp_awe_list[i].driver_data, *port);
 		return 0;
 	}
 	return -ENODEV;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/bin2hex.c linux-2.4.20/drivers/sound/bin2hex.c
--- linux-2.4.19/drivers/sound/bin2hex.c	2000-03-15 18:28:32.000000000 +0000
+++ linux-2.4.20/drivers/sound/bin2hex.c	2002-10-29 11:18:31.000000000 +0000
@@ -1,4 +1,5 @@
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 int main( int argc, const char * argv [] )
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/btaudio.c linux-2.4.20/drivers/sound/btaudio.c
--- linux-2.4.19/drivers/sound/btaudio.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/sound/btaudio.c	2002-10-29 11:18:34.000000000 +0000
@@ -144,17 +144,17 @@
 	int sampleshift;
 	int channels;
 	int analog;
+	int rate;
+};
+
+struct cardinfo {
+	char *name;
+	int rate;
 };
 
 static struct btaudio *btaudios = NULL;
-static unsigned int dsp1 = -1;
-static unsigned int dsp2 = -1;
-static unsigned int mixer = -1;
 static unsigned int debug = 0;
 static unsigned int irq_debug = 0;
-static int digital = 1;
-static int analog = 1;
-static int rate = 32000;
 
 /* -------------------------------------------------------------- */
 
@@ -657,7 +657,7 @@
 		if (bta->analog) {
 			return put_user(HWBASE_AD*4/bta->decimation>>bta->sampleshift, (int*)arg);
 		} else {
-			return put_user(rate, (int*)arg);
+			return put_user(bta->rate, (int*)arg);
 		}
 
         case SNDCTL_DSP_STEREO:
@@ -870,11 +870,33 @@
 
 /* -------------------------------------------------------------- */
 
+static unsigned int dsp1 = -1;
+static unsigned int dsp2 = -1;
+static unsigned int mixer = -1;
+static int latency = -1;
+static int digital = 1;
+static int analog = 1;
+static int rate = 0;
+
+#define BTA_OSPREY200 1
+
+static struct cardinfo cards[] = {
+	[0] = {
+		name: "default",
+		rate: 32000,
+	},
+	[BTA_OSPREY200] = {
+		name: "Osprey 200",
+		rate: 44100,
+	},
+};
+
 static int __devinit btaudio_probe(struct pci_dev *pci_dev,
 				   const struct pci_device_id *pci_id)
 {
 	struct btaudio *bta;
-	unsigned char revision,latency;
+	struct cardinfo *card = &cards[pci_id->driver_data];
+	unsigned char revision,lat;
 	int rc = -EBUSY;
 
 	if (pci_enable_device(pci_dev))
@@ -908,16 +930,27 @@
 		bta->sampleshift = 1;
 	}
 
+	/* sample rate */
+	bta->rate = card->rate;
+	if (rate)
+		bta->rate = rate;
+	
 	init_MUTEX(&bta->lock);
         init_waitqueue_head(&bta->readq);
 
+	if (-1 != latency) {
+		printk(KERN_INFO "btaudio: setting pci latency timer to %d\n",
+		       latency);
+		pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
+	}
         pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
-        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &latency);
+        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &lat);
         printk(KERN_INFO "btaudio: Bt%x (rev %d) at %02x:%02x.%x, ",
 	       pci_dev->device,revision,pci_dev->bus->number,
 	       PCI_SLOT(pci_dev->devfn),PCI_FUNC(pci_dev->devfn));
-        printk("irq: %d, latency: %d, memory: 0x%lx\n",
-	       bta->irq, latency, bta->mem);
+        printk("irq: %d, latency: %d, mmio: 0x%lx\n",
+	       bta->irq, lat, bta->mem);
+	printk("btaudio: using card config \"%s\"\n", card->name);
 
 	/* init hw */
         btwrite(0, REG_GPIO_DMA_CTL);
@@ -926,7 +959,7 @@
 	pci_set_master(pci_dev);
 
 	if ((rc = request_irq(bta->irq, btaudio_irq, SA_SHIRQ|SA_INTERRUPT,
-			       "btaudio",(void *)bta)) < 0) {
+			      "btaudio",(void *)bta)) < 0) {
 		printk(KERN_WARNING
 		       "btaudio: can't request irq (rc=%d)\n",rc);
 		goto fail1;
@@ -1028,11 +1061,25 @@
 /* -------------------------------------------------------------- */
 
 static struct pci_device_id btaudio_pci_tbl[] __devinitdata = {
-        { PCI_VENDOR_ID_BROOKTREE, 0x0878,
-          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-        { PCI_VENDOR_ID_BROOKTREE, 0x0879,
-          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-        {0,}
+        {
+		vendor:       PCI_VENDOR_ID_BROOKTREE,
+		device:       0x0878,
+		subvendor:    0x0070,
+		subdevice:    0xff01,
+		driver_data:  BTA_OSPREY200,
+	},{
+		vendor:       PCI_VENDOR_ID_BROOKTREE,
+		device:       0x0878,
+		subvendor:    PCI_ANY_ID,
+		subdevice:    PCI_ANY_ID,
+	},{
+		vendor:       PCI_VENDOR_ID_BROOKTREE,
+		device:       0x0878,
+		subvendor:    PCI_ANY_ID,
+		subdevice:    PCI_ANY_ID,
+        },{
+		/* --- end of list --- */
+	}
 };
 
 static struct pci_driver btaudio_pci_driver = {
@@ -1044,7 +1091,7 @@
 
 static int btaudio_init_module(void)
 {
-	printk(KERN_INFO "btaudio: driver version 0.6 loaded [%s%s%s]\n",
+	printk(KERN_INFO "btaudio: driver version 0.7 loaded [%s%s%s]\n",
 	       digital ? "digital" : "",
 	       analog && digital ? "+" : "",
 	       analog ? "analog" : "");
@@ -1068,6 +1115,8 @@
 MODULE_PARM(digital,"i");
 MODULE_PARM(analog,"i");
 MODULE_PARM(rate,"i");
+MODULE_PARM(latency,"i");
+MODULE_PARM_DESC(latency,"pci latency timer");
 
 MODULE_DEVICE_TABLE(pci, btaudio_pci_tbl);
 MODULE_DESCRIPTION("bt878 audio dma driver");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/cs4232.c linux-2.4.20/drivers/sound/cs4232.c
--- linux-2.4.19/drivers/sound/cs4232.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/sound/cs4232.c	2002-10-29 11:18:32.000000000 +0000
@@ -158,7 +158,7 @@
 	 * method conflicts with possible PnP support in the OS. For this reason 
 	 * driver is just a temporary kludge.
 	 *
-	 * Also the Cirrus/Crystal method doesnt always work. Try ISA PnP first ;)
+	 * Also the Cirrus/Crystal method doesn't always work. Try ISA PnP first ;)
 	 */
 
 	/*
@@ -444,6 +444,7 @@
 	isapnpcfg->io_base	= dev->resource[0].start;
 	if (probe_cs4232(isapnpcfg,TRUE) == 0) {
 		printk(KERN_ERR "cs4232: ISA PnP card found, but not detected?\n");
+		kfree(isapnpcfg);
 		return -ENODEV;
 	}
 	attach_cs4232(isapnpcfg);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/es1370.c linux-2.4.20/drivers/sound/es1370.c
--- linux-2.4.19/drivers/sound/es1370.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/sound/es1370.c	2002-10-29 11:18:40.000000000 +0000
@@ -2673,7 +2673,8 @@
 	}
 	set_fs(fs);
 	/* register gameport */
-	gameport_register_port(&s->gameport);
+	if(s->gameport.io)
+		gameport_register_port(&s->gameport);
 
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/es1371.c linux-2.4.20/drivers/sound/es1371.c
--- linux-2.4.19/drivers/sound/es1371.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/sound/es1371.c	2002-10-29 11:18:34.000000000 +0000
@@ -2968,7 +2968,8 @@
 	/* turn on S/PDIF output driver if requested */
 	outl(cssr, s->io+ES1371_REG_STATUS);
 	/* register gameport */
-	gameport_register_port(&s->gameport);
+	if(s->gameport.io)
+		gameport_register_port(&s->gameport);
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
 	/* put it into driver list */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/forte.c linux-2.4.20/drivers/sound/forte.c
--- linux-2.4.19/drivers/sound/forte.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/sound/forte.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,2084 @@
+/*
+ * forte.c - ForteMedia FM801 OSS Driver
+ *
+ * Written by Martin K. Petersen <mkp@mkp.net>
+ * Copyright (C) 2002 Hewlett-Packard Company
+ *
+ * Based upon the ALSA FM801 driver by Jaroslav Kysela and OSS drivers
+ * by Thomas Sailer, Alan Cox, Zach Brown, and Jeff Garzik.  Thanks
+ * guys!
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ */
+ 
+/*
+ * TODO:
+ *	MMIO
+ *	Multichannelize
+ *	Multichipify
+ *	MPU401
+ *	M^Gameport
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/kernel.h>
+
+#include <linux/sound.h>
+#include <linux/ac97_codec.h>
+#include <linux/wrapper.h>
+
+#include <linux/proc_fs.h>
+
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+
+#define DRIVER_NAME	"forte"
+#define DRIVER_VERSION 	"$Id: forte.c,v 1.55 2002/10/02 00:01:42 mkp Exp $"
+#define PFX 		DRIVER_NAME ": "
+
+#undef M_DEBUG
+
+#ifdef M_DEBUG
+#define DPRINTK(args...) printk(KERN_WARNING args)
+#else
+#define DPRINTK(args...)
+#endif
+
+/* Card capabilities */
+#define FORTE_CAPS              (DSP_CAP_MMAP | DSP_CAP_TRIGGER)
+
+/* Supported audio formats */
+#define FORTE_FMTS		(AFMT_U8 | AFMT_S16_LE)
+
+/* Buffers */
+#define FORTE_MIN_FRAG_SIZE     256
+#define FORTE_MAX_FRAG_SIZE     PAGE_SIZE
+#define FORTE_DEF_FRAG_SIZE     256
+#define FORTE_MIN_FRAGMENTS     16
+#define FORTE_MAX_FRAGMENTS     256
+#define FORTE_DEF_FRAGMENTS     16
+#define FORTE_MIN_BUF           16386
+
+/* PCI BARs */
+#define FORTE_PCM_VOL           0x00    /* PCM Output Volume */
+#define FORTE_FM_VOL            0x02    /* FM Output Volume */
+#define FORTE_I2S_VOL           0x04    /* I2S Volume */
+#define FORTE_REC_SRC           0x06    /* Record Source */
+#define FORTE_PLY_CTRL          0x08    /* Playback Control */
+#define FORTE_PLY_COUNT         0x0a    /* Playback Count */
+#define FORTE_PLY_BUF1          0x0c    /* Playback Buffer I */
+#define FORTE_PLY_BUF2          0x10    /* Playback Buffer II */
+#define FORTE_CAP_CTRL          0x14    /* Capture Control */
+#define FORTE_CAP_COUNT         0x16    /* Capture Count */
+#define FORTE_CAP_BUF1          0x18    /* Capture Buffer I */
+#define FORTE_CAP_BUF2          0x1c    /* Capture Buffer II */
+#define FORTE_CODEC_CTRL        0x22    /* Codec Control */
+#define FORTE_I2S_MODE          0x24    /* I2S Mode Control */
+#define FORTE_VOLUME            0x26    /* Volume Up/Down/Mute Status */
+#define FORTE_I2C_CTRL          0x29    /* I2C Control */
+#define FORTE_AC97_CMD          0x2a    /* AC'97 Command */
+#define FORTE_AC97_DATA         0x2c    /* AC'97 Data */
+#define FORTE_MPU401_DATA       0x30    /* MPU401 Data */
+#define FORTE_MPU401_CMD        0x31    /* MPU401 Command */
+#define FORTE_GPIO_CTRL         0x52    /* General Purpose I/O Control */
+#define FORTE_GEN_CTRL          0x54    /* General Control */
+#define FORTE_IRQ_MASK          0x56    /* Interrupt Mask */
+#define FORTE_IRQ_STATUS        0x5a    /* Interrupt Status */
+#define FORTE_OPL3_BANK0        0x68    /* OPL3 Status Read / Bank 0 Write */
+#define FORTE_OPL3_DATA0        0x69    /* OPL3 Data 0 Write */
+#define FORTE_OPL3_BANK1        0x6a    /* OPL3 Bank 1 Write */
+#define FORTE_OPL3_DATA1        0x6b    /* OPL3 Bank 1 Write */
+#define FORTE_POWERDOWN         0x70    /* Blocks Power Down Control */
+
+#define FORTE_CAP_OFFSET        FORTE_CAP_CTRL - FORTE_PLY_CTRL
+
+#define FORTE_AC97_ADDR_SHIFT   10
+
+/* Playback and record control register bits */
+#define FORTE_BUF1_LAST         (1<<1)
+#define FORTE_BUF2_LAST         (1<<2)
+#define FORTE_START             (1<<5)
+#define FORTE_PAUSE             (1<<6)
+#define FORTE_IMMED_STOP        (1<<7)
+#define FORTE_RATE_SHIFT        8
+#define FORTE_RATE_MASK         (15 << FORTE_RATE_SHIFT)
+#define FORTE_CHANNELS_4        (1<<12) /* Playback only */
+#define FORTE_CHANNELS_6        (2<<12) /* Playback only */
+#define FORTE_CHANNELS_6MS      (3<<12) /* Playback only */
+#define FORTE_CHANNELS_MASK     (3<<12)
+#define FORTE_16BIT             (1<<14)
+#define FORTE_STEREO            (1<<15)
+
+/* IRQ status bits */
+#define FORTE_IRQ_PLAYBACK      (1<<8)
+#define FORTE_IRQ_CAPTURE       (1<<9)
+#define FORTE_IRQ_VOLUME        (1<<14)
+#define FORTE_IRQ_MPU           (1<<15)
+
+/* CODEC control */
+#define FORTE_CC_CODEC_RESET    (1<<5)
+#define FORTE_CC_AC97_RESET     (1<<6)
+
+/* AC97 cmd */
+#define FORTE_AC97_WRITE        (0<<7)
+#define FORTE_AC97_READ         (1<<7)
+#define FORTE_AC97_DP_INVALID   (0<<8)
+#define FORTE_AC97_DP_VALID     (1<<8)
+#define FORTE_AC97_PORT_RDY     (0<<9)
+#define FORTE_AC97_PORT_BSY     (1<<9)
+
+
+struct forte_channel {
+        const char 		*name;
+
+	unsigned short		ctrl; 		/* Ctrl BAR contents */
+	unsigned long 		iobase;		/* Ctrl BAR address */
+
+	wait_queue_head_t	wait;
+
+	void 			*buf; 		/* Buffer */
+	dma_addr_t		buf_handle; 	/* Buffer handle */
+
+        unsigned int 		record;
+	unsigned int		format;
+        unsigned int		rate;
+	unsigned int		stereo;
+
+	unsigned int		frag_sz; 	/* Current fragment size */
+	unsigned int		frag_num; 	/* Current # of fragments */
+	unsigned int		buf_sz;		/* Current buffer size */
+
+	unsigned int		hwptr;		/* Tail */
+	unsigned int		swptr; 		/* Head */
+	unsigned int		filled_frags; 	/* Fragments currently full */
+	unsigned int		next_buf;	/* Index of next buffer */
+
+	unsigned int		blocked;	/* Blocked on I/O */
+	unsigned int		drain;		/* Drain queued buffers */
+	unsigned int		active;		/* Channel currently in use */
+	unsigned int		mapped;		/* mmap */
+
+	unsigned int		buf_pages;	/* Real size of buffer */
+	unsigned int		nr_irqs;	/* Number of interrupts */
+	unsigned int		bytes;		/* Total bytes */
+};
+
+
+struct forte_chip {
+	struct pci_dev		*pci_dev;
+	unsigned long		iobase;
+	int			irq;
+
+	struct semaphore	open_sem; 	/* Device access */
+	spinlock_t		lock;		/* State */
+
+	spinlock_t		ac97_lock;
+	struct ac97_codec	*ac97;
+
+	int			multichannel;
+	int			dsp; 		/* OSS handle */
+	int                     trigger;	/* mmap I/O trigger */
+
+	struct forte_channel	play;
+	struct forte_channel	rec;
+};
+
+
+static int channels[] = { 2, 4, 6, };
+static int rates[]    = { 5500, 8000, 9600, 11025, 16000, 19200, 
+			  22050, 32000, 38400, 44100, 48000, };
+
+static struct forte_chip *forte;
+static int found;
+
+
+/* AC97 Codec -------------------------------------------------------------- */
+
+
+/** 
+ * forte_ac97_wait:
+ * @chip:	fm801 instance whose AC97 codec to wait on
+ *
+ * FIXME:
+ *		Stop busy-waiting
+ */
+
+static inline int
+forte_ac97_wait (struct forte_chip *chip)
+{
+	int i = 10000;
+
+	while ( (inw (chip->iobase + FORTE_AC97_CMD) & FORTE_AC97_PORT_BSY) 
+		&& i-- )
+		cpu_relax();
+
+	return i == 0;
+}
+
+
+/**
+ * forte_ac97_read:
+ * @codec:	AC97 codec to read from
+ * @reg:	register to read
+ */
+
+u16
+forte_ac97_read (struct ac97_codec *codec, u8 reg)
+{
+	u16 ret = 0;
+	struct forte_chip *chip = codec->private_data;
+
+	spin_lock (&chip->ac97_lock);
+
+	/* Knock, knock */
+	if (forte_ac97_wait (chip)) {
+		printk (KERN_ERR PFX "ac97_read: Serial bus busy\n");
+		goto out;
+	}
+
+	/* Send read command */
+	outw (reg | (1<<7), chip->iobase + FORTE_AC97_CMD);
+
+	if (forte_ac97_wait (chip)) {
+		printk (KERN_ERR PFX "ac97_read: Bus busy reading reg 0x%x\n",
+			reg);
+		goto out;
+	}
+	
+	/* Sanity checking */
+	if (inw (chip->iobase + FORTE_AC97_CMD) & FORTE_AC97_DP_INVALID) {
+		printk (KERN_ERR PFX "ac97_read: Invalid data port");
+		goto out;
+	}
+
+	/* Fetch result */
+	ret = inw (chip->iobase + FORTE_AC97_DATA);
+
+ out:
+	spin_unlock (&chip->ac97_lock);
+	return ret;
+}
+
+
+/**
+ * forte_ac97_write:
+ * @codec:	AC97 codec to send command to
+ * @reg:	register to write
+ * @val:	value to write
+ */
+
+void
+forte_ac97_write (struct ac97_codec *codec, u8 reg, u16 val)
+{
+	struct forte_chip *chip = codec->private_data;
+
+	spin_lock (&chip->ac97_lock);
+
+	/* Knock, knock */
+	if (forte_ac97_wait (chip)) {
+		printk (KERN_ERR PFX "ac97_write: Serial bus busy\n");
+		goto out;
+	}
+
+	outw (val, chip->iobase + FORTE_AC97_DATA);
+	outb (reg | FORTE_AC97_WRITE, chip->iobase + FORTE_AC97_CMD);
+
+	/* Wait for completion */
+	if (forte_ac97_wait (chip)) {
+		printk (KERN_ERR PFX "ac97_write: Bus busy after write\n");
+		goto out;
+	}
+
+ out:
+	spin_unlock (&chip->ac97_lock);
+}
+
+
+/* Mixer ------------------------------------------------------------------- */
+
+
+/**
+ * forte_mixer_open:
+ * @inode:		
+ * @file:		
+ */
+
+static int
+forte_mixer_open (struct inode *inode, struct file *file)
+{
+	struct forte_chip *chip = forte;
+
+	MOD_INC_USE_COUNT;
+
+	file->private_data = chip->ac97;
+
+	return 0;
+}
+
+
+/**
+ * forte_mixer_release:
+ * @inode:		
+ * @file:		
+ */
+
+static int
+forte_mixer_release (struct inode *inode, struct file *file)
+{
+	/* We will welease Wodewick */
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+
+/**
+ * forte_mixer_ioctl:
+ * @inode:		
+ * @file:		
+ */
+
+static int
+forte_mixer_ioctl (struct inode *inode, struct file *file, 
+		   unsigned int cmd, unsigned long arg)
+{
+	struct ac97_codec *codec = (struct ac97_codec *) file->private_data;
+
+	return codec->mixer_ioctl (codec, cmd, arg);
+}
+
+
+static struct file_operations forte_mixer_fops = {
+	owner:	    		THIS_MODULE,
+	llseek:         	no_llseek,
+	ioctl:          	forte_mixer_ioctl,
+	open:           	forte_mixer_open,
+	release:        	forte_mixer_release,
+};
+
+
+/* Channel ----------------------------------------------------------------- */
+
+/** 
+ * forte_channel_reset:
+ * @channel:	Channel to reset
+ * 
+ * Locking:	Must be called with lock held.
+ */
+
+static void
+forte_channel_reset (struct forte_channel *channel)
+{
+	if (!channel || !channel->iobase)
+		return;
+
+	DPRINTK ("%s: channel = %s\n", __FUNCTION__, channel->name);
+
+	channel->ctrl &= ~FORTE_START;
+	outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
+	
+	/* We always play at least two fragments, hence these defaults */
+ 	channel->hwptr = channel->frag_sz;
+	channel->next_buf = 1;
+	channel->swptr = 0;
+	channel->filled_frags = 0;
+	channel->blocked = 0;
+	channel->drain = 0;
+	channel->active = 0;
+	channel->bytes = 0;
+	channel->nr_irqs = 0;
+	channel->mapped = 0;
+}
+
+
+/** 
+ * forte_channel_start:
+ * @channel: 	Channel to start (record/playback)
+ *
+ * Locking:	Must be called with lock held.
+ */
+
+static void inline
+forte_channel_start (struct forte_channel *channel)
+{
+	if (!channel || !channel->iobase) 
+		return;
+
+	DPRINTK ("%s: channel = %s\n", __FUNCTION__, channel->name);
+
+	channel->ctrl &= ~(FORTE_PAUSE | FORTE_BUF1_LAST | FORTE_BUF2_LAST);
+	channel->ctrl |= FORTE_START;
+	channel->active = 1;
+	outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
+}
+
+
+/** 
+ * forte_channel_stop:
+ * @channel: 	Channel to stop
+ *
+ * Locking:	Must be called with lock held.
+ */
+
+static void inline
+forte_channel_stop (struct forte_channel *channel)
+{
+	if (!channel || !channel->iobase) 
+		return;
+
+	DPRINTK ("%s: channel = %s\n", __FUNCTION__, channel->name);
+
+	channel->ctrl &= ~FORTE_START;
+	channel->active = 0;
+	outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
+}
+
+
+/** 
+ * forte_channel_rate:
+ * @channel: 	Channel whose rate to set.  Playback and record are
+ *           	independent.
+ * @rate:    	Channel rate in Hz
+ *
+ * Locking:	Must be called with lock held.
+ */
+
+static int
+forte_channel_rate (struct forte_channel *channel, unsigned int rate)
+{
+	int new_rate;
+
+	if (!channel || !channel->iobase) 
+		return -EINVAL;
+
+	/* The FM801 only supports a handful of fixed frequencies.
+	 * We find the value closest to what userland requested.
+	 */
+	if      (rate <= 6250)  { rate = 5500;  new_rate =  0; }
+	else if (rate <= 8800)  { rate = 8000;  new_rate =  1; }
+	else if (rate <= 10312) { rate = 9600;  new_rate =  2; }
+	else if (rate <= 13512) { rate = 11025; new_rate =  3; }
+	else if (rate <= 17600) { rate = 16000; new_rate =  4; }
+	else if (rate <= 20625) { rate = 19200; new_rate =  5; }
+	else if (rate <= 27025) { rate = 22050; new_rate =  6; }
+	else if (rate <= 35200) { rate = 32000; new_rate =  7; }
+	else if (rate <= 41250) { rate = 38400; new_rate =  8; }
+	else if (rate <= 46050) { rate = 44100; new_rate =  9; }
+	else                    { rate = 48000; new_rate = 10; }
+
+	channel->ctrl &= ~FORTE_RATE_MASK;
+	channel->ctrl |= new_rate << FORTE_RATE_SHIFT;
+	channel->rate = rate;
+
+	DPRINTK ("%s: %s rate = %d\n", __FUNCTION__, channel->name, rate);
+
+	return rate;
+}
+
+
+/** 
+ * forte_channel_format:
+ * @channel: 	Channel whose audio format to set
+ * @format:  	OSS format ID
+ *
+ * Locking:	Must be called with lock held.
+ */
+
+static int
+forte_channel_format (struct forte_channel *channel, int format)
+{
+	if (!channel || !channel->iobase) 
+		return -EINVAL;
+
+	switch (format) {
+
+	case AFMT_QUERY:
+		break;
+	
+	case AFMT_U8:
+		channel->ctrl &= ~FORTE_16BIT;
+		channel->format = AFMT_U8;
+		break;
+
+	case AFMT_S16_LE:
+	default:
+		channel->ctrl |= FORTE_16BIT;
+		channel->format = AFMT_S16_LE;
+		break;
+	}
+
+	DPRINTK ("%s: %s want %d format, got %d\n", __FUNCTION__, channel->name, 
+		 format, channel->format);
+
+	return channel->format;
+}
+
+
+/** 
+ * forte_channel_stereo:
+ * @channel: 	Channel to toggle
+ * @stereo:  	0 for Mono, 1 for Stereo
+ *
+ * Locking:	Must be called with lock held.
+ */
+
+static int
+forte_channel_stereo (struct forte_channel *channel, unsigned int stereo)
+{
+	int ret;
+
+	if (!channel || !channel->iobase)
+		return -EINVAL;
+
+	DPRINTK ("%s: %s stereo = %d\n", __FUNCTION__, channel->name, stereo);
+
+	switch (stereo) {
+
+	case 0:
+		channel->ctrl &= ~(FORTE_STEREO | FORTE_CHANNELS_MASK);
+		channel-> stereo = stereo;
+		ret = stereo;
+		break;
+
+	case 1:
+		channel->ctrl &= ~FORTE_CHANNELS_MASK;
+		channel->ctrl |= FORTE_STEREO;
+		channel-> stereo = stereo;
+		ret = stereo;
+		break;
+
+	default:
+		DPRINTK ("Unsupported channel format");
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+
+/** 
+ * forte_channel_buffer:
+ * @channel:	Channel whose buffer to set up
+ *
+ * Locking:	Must be called with lock held.
+ *
+ * FIXME:	Buffer scaling dependent on rate/channels/bits
+ */
+
+static void
+forte_channel_buffer (struct forte_channel *channel, int sz, int num)
+{
+	/* Go away, I'm busy */
+	if (channel->filled_frags || channel->bytes)
+		return;
+
+	channel->frag_sz = sz;
+	channel->frag_num = num;
+
+	if (channel->frag_sz < FORTE_MIN_FRAG_SIZE)
+		channel->frag_sz = FORTE_MIN_FRAG_SIZE;
+
+	if (channel->frag_sz > FORTE_MAX_FRAG_SIZE)
+		channel->frag_sz = FORTE_MAX_FRAG_SIZE;
+
+	if (channel->frag_num < FORTE_MIN_FRAGMENTS)
+		channel->frag_num = FORTE_MIN_FRAGMENTS;
+
+	if (channel->frag_num > FORTE_MAX_FRAGMENTS)
+		channel->frag_num = FORTE_MAX_FRAGMENTS;
+
+	if (channel->frag_sz * channel->frag_num < FORTE_MIN_BUF)
+		channel->frag_num = FORTE_MIN_BUF / channel->frag_sz;
+
+	channel->buf_sz = channel->frag_sz * channel->frag_num;
+
+	DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d\n", 
+		 __FUNCTION__, channel->name, channel->frag_sz, 
+		 channel->frag_num, channel->buf_sz);
+}
+
+
+/** 
+ * forte_channel_prep:
+ * @channel:	Channel whose buffer to prepare
+ *
+ * Locking:	Lock held.
+ */
+
+static void
+forte_channel_prep (struct forte_channel *channel)
+{
+	struct page *page;
+	int i;
+	
+	if (channel->buf)
+		return;
+
+	channel->buf_pages = channel->buf_sz >> PAGE_SHIFT;
+
+	if (channel->buf_sz % PAGE_SIZE)
+		channel->buf_pages++;
+
+	DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d, pg = %d\n", 
+		 __FUNCTION__, channel->name, channel->frag_sz, 
+		 channel->frag_num, channel->buf_sz, channel->buf_pages);
+
+	/* DMA buffer */
+	channel->buf = pci_alloc_consistent (forte->pci_dev, 
+					     channel->buf_pages * PAGE_SIZE,
+					     &channel->buf_handle);
+
+	if (!channel->buf || !channel->buf_handle)
+		BUG();
+
+	page = virt_to_page (channel->buf);
+	
+	for (i = 0 ; i < channel->buf_pages ; i++)
+		mem_map_reserve (page++);
+
+	/* Prep buffer registers */
+	outw (channel->frag_sz - 1, channel->iobase + FORTE_PLY_COUNT);
+	outl (channel->buf_handle, channel->iobase + FORTE_PLY_BUF1);
+	outl (channel->buf_handle + channel->frag_sz, 
+	      channel->iobase + FORTE_PLY_BUF2);
+
+	/* Reset hwptr */
+ 	channel->hwptr = channel->frag_sz;
+	channel->next_buf = 1;
+
+	DPRINTK ("%s: %s buffer @ %p (%p)\n", __FUNCTION__, channel->name, 
+		 channel->buf, channel->buf_handle);
+}
+
+
+/** 
+ * forte_channel_drain:
+ * @chip:	
+ * @channel:	
+ *
+ * Locking:	Don't hold the lock.
+ */
+
+static inline int
+forte_channel_drain (struct forte_channel *channel)
+{
+	DECLARE_WAITQUEUE (wait, current);
+	unsigned long flags;
+
+	if (!channel->active)
+		return 0;
+
+	if (channel->mapped) {
+		spin_lock_irqsave (&forte->lock, flags);
+		forte_channel_stop (channel);
+		spin_unlock_irqrestore (&forte->lock, flags);
+		return 0;
+	}
+
+	channel->drain = 1;
+	add_wait_queue (&channel->wait, &wait);
+
+	for (;;) {
+		spin_lock_irqsave (&forte->lock, flags);
+
+		if (channel->active == 0 || channel->filled_frags < 1)
+			break;
+
+		spin_unlock_irqrestore (&forte->lock, flags);
+		__set_current_state (TASK_INTERRUPTIBLE);
+		schedule();
+	}
+
+	channel->drain = 0;
+	spin_unlock_irqrestore (&forte->lock, flags);
+	set_current_state (TASK_RUNNING);
+	remove_wait_queue (&channel->wait, &wait);
+
+	return 0;
+}
+
+
+/** 
+ * forte_channel_init:
+ * @chip: 	Forte chip instance the channel hangs off
+ * @channel: 	Channel to initialize
+ *
+ * Description:
+ *	        Initializes a channel, sets defaults, and allocates
+ *	        buffers.
+ *
+ * Locking:	No lock held.
+ */
+
+static int
+forte_channel_init (struct forte_chip *chip, struct forte_channel *channel)
+{
+	DPRINTK ("%s: chip iobase @ %p\n", __FUNCTION__, (void *)chip->iobase);
+
+	spin_lock_irq (&chip->lock);
+	memset (channel, 0x0, sizeof (*channel));
+
+	if (channel == &chip->play) {
+		channel->name = "PCM_OUT";
+		channel->iobase = chip->iobase;
+		DPRINTK ("%s: PCM-OUT iobase @ %p\n", __FUNCTION__,
+			 (void *) channel->iobase);
+	}
+	else if (channel == &chip->rec) {
+		channel->name = "PCM_IN";
+		channel->iobase = chip->iobase + FORTE_CAP_OFFSET;
+		channel->record = 1;
+		DPRINTK ("%s: PCM-IN iobase @ %p\n", __FUNCTION__, 
+			 (void *) channel->iobase);
+	}
+	else
+		BUG();
+
+	init_waitqueue_head (&channel->wait);
+
+	/* Defaults: 48kHz, 16-bit, stereo */
+	channel->ctrl = inw (channel->iobase + FORTE_PLY_CTRL);
+	forte_channel_reset (channel);
+	forte_channel_stereo (channel, 1);
+	forte_channel_format (channel, AFMT_S16_LE);
+	forte_channel_rate (channel, 48000);
+	forte_channel_buffer (channel, FORTE_DEF_FRAG_SIZE, 
+			      FORTE_DEF_FRAGMENTS);
+
+	chip->trigger = 0;
+	spin_unlock_irq (&chip->lock);
+
+	return 0;
+}
+
+
+/** 
+ * forte_channel_free:
+ * @chip:	Chip this channel hangs off
+ * @channel:	Channel to nuke 
+ *
+ * Description:
+ * 		Resets channel and frees buffers.
+ *
+ * Locking:	Hold your horses.
+ */
+
+static void
+forte_channel_free (struct forte_chip *chip, struct forte_channel *channel)
+{
+	DPRINTK ("%s: %s\n", __FUNCTION__, channel->name);
+
+	if (!channel->buf_handle)
+		return;
+
+	pci_free_consistent (chip->pci_dev, channel->buf_pages * PAGE_SIZE, 
+			     channel->buf, channel->buf_handle);
+	
+	memset (channel, 0x0, sizeof (*channel));
+}
+
+
+/* DSP --------------------------------------------------------------------- */
+
+
+/**
+ * forte_dsp_ioctl:
+ */
+
+static int
+forte_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
+		 unsigned long arg)
+{
+	int ival=0, ret, rval=0, rd, wr, count;
+	struct forte_chip *chip;
+	struct audio_buf_info abi;
+	struct count_info cinfo;
+
+	chip = file->private_data;
+	
+	if (file->f_mode & FMODE_WRITE)
+		wr = 1;
+	else 
+		wr = 0;
+
+	if (file->f_mode & FMODE_READ)
+		rd = 1;
+	else
+		rd = 0;
+
+	switch (cmd) {
+
+	case OSS_GETVERSION:
+		return put_user (SOUND_VERSION, (int *) arg);
+
+	case SNDCTL_DSP_GETCAPS:
+		DPRINTK ("%s: GETCAPS\n", __FUNCTION__);
+
+		ival = FORTE_CAPS; /* DUPLEX */
+		return put_user (ival, (int *) arg);
+
+	case SNDCTL_DSP_GETFMTS:
+		DPRINTK ("%s: GETFMTS\n", __FUNCTION__);
+
+		ival = FORTE_FMTS; /* U8, 16LE */
+		return put_user (ival, (int *) arg);
+
+	case SNDCTL_DSP_SETFMT:	/* U8, 16LE */
+		DPRINTK ("%s: SETFMT\n", __FUNCTION__);
+
+		if (get_user (ival, (int *) arg))
+			return -EFAULT;
+
+		spin_lock_irq (&chip->lock);
+
+		if (rd) {
+			forte_channel_stop (&chip->rec);
+			rval = forte_channel_format (&chip->rec, ival);
+		}
+
+		if (wr) {
+			forte_channel_stop (&chip->rec);
+			rval = forte_channel_format (&chip->play, ival);
+		}
+
+		spin_unlock_irq (&chip->lock);
+	
+		return put_user (rval, (int *) arg);
+
+	case SNDCTL_DSP_STEREO:	/* 0 - mono, 1 - stereo */
+		DPRINTK ("%s: STEREO\n", __FUNCTION__);
+
+		if (get_user (ival, (int *) arg))
+			return -EFAULT;
+
+		spin_lock_irq (&chip->lock);
+
+		if (rd) {
+			forte_channel_stop (&chip->rec);
+			rval = forte_channel_stereo (&chip->rec, ival);
+		}
+
+		if (wr) {
+			forte_channel_stop (&chip->rec);
+			rval = forte_channel_stereo (&chip->play, ival);
+		}
+
+		spin_unlock_irq (&chip->lock);
+
+                return put_user (rval, (int *) arg);
+
+	case SNDCTL_DSP_CHANNELS: /* 1 - mono, 2 - stereo */
+		DPRINTK ("%s: CHANNELS\n", __FUNCTION__);
+
+		if (get_user (ival, (int *) arg))
+			return -EFAULT;
+
+		spin_lock_irq (&chip->lock);
+
+		if (rd) {
+			forte_channel_stop (&chip->rec);
+			rval = forte_channel_stereo (&chip->rec, ival-1) + 1;
+		}
+
+		if (wr) {
+			forte_channel_stop (&chip->play);
+			rval = forte_channel_stereo (&chip->play, ival-1) + 1;
+		}
+
+		spin_unlock_irq (&chip->lock);
+
+                return put_user (rval, (int *) arg);
+
+	case SNDCTL_DSP_SPEED:
+		DPRINTK ("%s: SPEED\n", __FUNCTION__);
+
+		if (get_user (ival, (int *) arg))
+                        return -EFAULT;
+
+		spin_lock_irq (&chip->lock);
+
+		if (rd) {
+			forte_channel_stop (&chip->rec);
+			rval = forte_channel_rate (&chip->rec, ival);
+		}
+
+		if (wr) {
+			forte_channel_stop (&chip->play);
+			rval = forte_channel_rate (&chip->play, ival);
+		}
+
+		spin_unlock_irq (&chip->lock);
+
+                return put_user(rval, (int*) arg);
+
+	case SNDCTL_DSP_GETBLKSIZE:
+		DPRINTK ("%s: GETBLKSIZE\n", __FUNCTION__);
+
+		spin_lock_irq (&chip->lock);
+
+		if (rd)
+			ival = chip->rec.frag_sz;
+
+		if (wr)
+			ival = chip->play.frag_sz;
+
+		spin_unlock_irq (&chip->lock);
+
+                return put_user (ival, (int *) arg);
+
+	case SNDCTL_DSP_RESET:
+		DPRINTK ("%s: RESET\n", __FUNCTION__);
+
+		spin_lock_irq (&chip->lock);
+
+		if (rd)
+			forte_channel_reset (&chip->rec);
+
+		if (wr)
+			forte_channel_reset (&chip->play);
+
+		spin_unlock_irq (&chip->lock);
+
+                return 0;
+
+	case SNDCTL_DSP_SYNC:
+		DPRINTK ("%s: SYNC\n", __FUNCTION__);
+
+		if (wr) {
+			ret = forte_channel_drain (&chip->play);
+			spin_lock_irq (&chip->lock);
+			forte_channel_reset (&chip->play);
+			spin_unlock_irq (&chip->lock);
+		}
+
+		return 0;
+
+	case SNDCTL_DSP_POST:
+		DPRINTK ("%s: POST\n", __FUNCTION__);
+
+		if (wr) {
+			spin_lock_irq (&chip->lock);
+			forte_channel_reset (&chip->play);
+			spin_unlock_irq (&chip->lock);
+		}
+
+                return 0;
+
+	case SNDCTL_DSP_SETFRAGMENT:
+		DPRINTK ("%s: SETFRAGMENT\n", __FUNCTION__);
+
+		if (get_user (ival, (int *) arg))
+			return -EFAULT;
+
+		spin_lock_irq (&chip->lock);
+
+		if (rd) {
+			forte_channel_buffer (&chip->rec, ival & 0xffff, 
+					      (ival >> 16) & 0xffff);
+			ival = (chip->rec.frag_num << 16) + chip->rec.frag_sz;
+		}
+
+		if (wr) {
+			forte_channel_buffer (&chip->play, ival & 0xffff, 
+					      (ival >> 16) & 0xffff);
+			ival = (chip->play.frag_num << 16) +chip->play.frag_sz;
+		}
+
+		spin_unlock_irq (&chip->lock);
+
+		return put_user (ival, (int *) arg);
+                
+        case SNDCTL_DSP_GETISPACE:
+		DPRINTK ("%s: GETISPACE\n", __FUNCTION__);
+
+		if (!rd)
+			return -EINVAL;
+
+		spin_lock_irq (&chip->lock);
+
+		abi.fragstotal = chip->rec.frag_num;
+		abi.fragsize = chip->rec.frag_sz;
+			
+		if (chip->rec.mapped) {
+			abi.fragments = chip->rec.frag_num - 2;
+			abi.bytes = abi.fragments * abi.fragsize;
+		}
+		else {
+			abi.fragments = chip->rec.filled_frags;
+			abi.bytes = abi.fragments * abi.fragsize;
+		}
+
+		spin_unlock_irq (&chip->lock);
+
+		return copy_to_user ((void *) arg, &abi, sizeof (abi));
+
+	case SNDCTL_DSP_GETIPTR:
+		DPRINTK ("%s: GETIPTR\n", __FUNCTION__);
+
+		if (!rd)
+			return -EINVAL;
+
+		spin_lock_irq (&chip->lock);
+
+		if (chip->rec.active) 
+			cinfo.ptr = chip->rec.hwptr;
+		else
+			cinfo.ptr = 0;
+
+		cinfo.bytes = chip->rec.bytes;
+		cinfo.blocks = chip->rec.nr_irqs;
+		chip->rec.nr_irqs = 0;
+
+		spin_unlock_irq (&chip->lock);
+
+		return copy_to_user ((void *) arg, &cinfo, sizeof (cinfo));
+
+        case SNDCTL_DSP_GETOSPACE:
+		if (!wr)
+			return -EINVAL;
+
+		spin_lock_irq (&chip->lock);
+
+		abi.fragstotal = chip->play.frag_num;
+		abi.fragsize = chip->play.frag_sz;
+
+		if (chip->play.mapped) {
+			abi.fragments = chip->play.frag_num - 2;
+			abi.bytes = chip->play.buf_sz;
+		}
+		else {
+			abi.fragments = chip->play.frag_num - 
+				chip->play.filled_frags;
+			abi.bytes = abi.fragments * abi.fragsize;
+		}
+
+		spin_unlock_irq (&chip->lock);
+		
+		return copy_to_user ((void *) arg, &abi, sizeof (abi));
+
+	case SNDCTL_DSP_GETOPTR:
+		if (!wr)
+			return -EINVAL;
+
+		spin_lock_irq (&chip->lock);
+
+		if (chip->play.active) 
+			cinfo.ptr = chip->play.hwptr;
+		else
+			cinfo.ptr = 0;
+
+		cinfo.bytes = chip->play.bytes;
+		cinfo.blocks = chip->play.nr_irqs;
+		chip->play.nr_irqs = 0;
+
+		spin_unlock_irq (&chip->lock);
+
+		return copy_to_user ((void *) arg, &cinfo, sizeof (cinfo));
+
+	case SNDCTL_DSP_GETODELAY:
+		if (!chip->play.active)
+			return 0;
+
+		if (!wr)
+			return -EINVAL;
+
+		spin_lock_irq (&chip->lock);
+
+		if (chip->play.mapped) {
+			count = inw (chip->play.iobase + FORTE_PLY_COUNT) + 1;
+			ival = chip->play.frag_sz - count;
+		}
+		else {
+			ival = chip->play.filled_frags * chip->play.frag_sz;
+		}
+
+		spin_unlock_irq (&chip->lock);
+
+		return put_user (ival, (int *) arg);
+
+	case SNDCTL_DSP_SETDUPLEX:
+		DPRINTK ("%s: SETDUPLEX\n", __FUNCTION__);
+
+		return -EINVAL;
+
+	case SNDCTL_DSP_GETTRIGGER:
+		DPRINTK ("%s: GETTRIGGER\n", __FUNCTION__);
+		
+		return put_user (chip->trigger, (int *) arg);
+		
+	case SNDCTL_DSP_SETTRIGGER:
+
+		if (get_user (ival, (int *) arg))
+			return -EFAULT;
+
+		DPRINTK ("%s: SETTRIGGER %d\n", __FUNCTION__, ival);
+
+		if (wr) {
+			spin_lock_irq (&chip->lock);
+
+			if (ival & PCM_ENABLE_OUTPUT)
+				forte_channel_start (&chip->play);
+			else {		
+				chip->trigger = 1;
+				forte_channel_prep (&chip->play);
+				forte_channel_stop (&chip->play);
+			}
+
+			spin_unlock_irq (&chip->lock);
+		}
+		else if (rd) {
+			spin_lock_irq (&chip->lock);
+
+			if (ival & PCM_ENABLE_INPUT)
+				forte_channel_start (&chip->rec);
+			else {		
+				chip->trigger = 1;
+				forte_channel_prep (&chip->rec);
+				forte_channel_stop (&chip->rec);
+			}
+
+			spin_unlock_irq (&chip->lock);
+		}
+
+		return 0;
+		
+	case SOUND_PCM_READ_RATE:
+		DPRINTK ("%s: PCM_READ_RATE\n", __FUNCTION__);		
+		return put_user (chip->play.rate, (int *) arg);
+
+	case SOUND_PCM_READ_CHANNELS:
+		DPRINTK ("%s: PCM_READ_CHANNELS\n", __FUNCTION__);		
+		return put_user (chip->play.stereo, (int *) arg);
+
+	case SOUND_PCM_READ_BITS:
+		DPRINTK ("%s: PCM_READ_BITS\n", __FUNCTION__);		
+		return put_user (chip->play.format, (int *) arg);
+
+	default:
+		DPRINTK ("Unsupported ioctl: %x (%p)\n", cmd, (void *) arg);
+		break;
+	}
+
+	return -EINVAL;
+}
+
+
+/**
+ * forte_dsp_open:
+ */
+
+static int 
+forte_dsp_open (struct inode *inode, struct file *file)
+{
+	struct forte_chip *chip = forte; /* FIXME: HACK FROM HELL! */
+
+	if (down_interruptible (&chip->open_sem)) {
+		DPRINTK ("%s: returning -ERESTARTSYS\n", __FUNCTION__);
+		return -ERESTARTSYS;
+	}
+
+	file->private_data = forte;
+
+	DPRINTK ("%s: chip @ %p\n", __FUNCTION__, file->private_data);
+
+	if (file->f_mode & FMODE_WRITE)
+		forte_channel_init (forte, &forte->play);
+
+	if (file->f_mode & FMODE_READ)
+		forte_channel_init (forte, &forte->rec);
+
+	return 0;
+}
+
+
+/**
+ * forte_dsp_release:
+ */
+
+static int 
+forte_dsp_release (struct inode *inode, struct file *file)
+{
+	struct forte_chip *chip = file->private_data;
+	int ret = 0;
+
+	DPRINTK ("%s: chip @ %p\n", __FUNCTION__, chip);
+
+	if (file->f_mode & FMODE_WRITE) {
+		forte_channel_drain (&chip->play);
+
+		spin_lock_irq (&chip->lock);
+
+		chip->play.ctrl |= FORTE_IMMED_STOP;
+		forte_channel_stop (&chip->play);
+		forte_channel_free (chip, &chip->play);
+
+		spin_unlock_irq (&chip->lock);
+        }
+
+	if (file->f_mode & FMODE_READ) {
+		while (chip->rec.filled_frags > 0)
+			interruptible_sleep_on (&chip->rec.wait);
+
+		spin_lock_irq (&chip->lock);
+
+		chip->play.ctrl |= FORTE_IMMED_STOP;
+		forte_channel_stop (&chip->rec);
+		forte_channel_free (chip, &chip->rec);
+
+		spin_unlock_irq (&chip->lock);
+	}
+
+	up (&chip->open_sem);
+
+	return ret;
+}
+
+
+/**
+ * forte_dsp_poll:
+ *
+ * FIXME:	Racy
+ */
+
+static unsigned int 
+forte_dsp_poll (struct file *file, struct poll_table_struct *wait)
+{
+	struct forte_chip *chip;
+	struct forte_channel *channel;
+	unsigned int mask = 0;
+
+	chip = file->private_data;
+
+	if (file->f_mode & FMODE_WRITE) {
+		channel = &chip->play;
+
+		if (channel->active)
+			poll_wait (file, &channel->wait, wait);
+
+		if (channel->filled_frags)
+			mask |= POLLOUT | POLLWRNORM;
+	}
+
+	if (file->f_mode & FMODE_READ) {
+		channel = &chip->rec;
+
+		if (channel->active)
+			poll_wait (file, &channel->wait, wait);
+
+		if (channel->filled_frags > 0)
+			mask |= POLLIN | POLLRDNORM;
+	}
+
+	return mask;
+}
+
+
+/**
+ * forte_dsp_mmap:
+ */
+
+static int
+forte_dsp_mmap (struct file *file, struct vm_area_struct *vma)
+{
+	struct forte_chip *chip;
+	struct forte_channel *channel;
+	unsigned long size;
+	int ret;
+
+	chip = file->private_data;
+
+	DPRINTK ("%s: start %lXh, size %ld, pgoff %ld\n", __FUNCTION__,
+                 vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_pgoff);
+
+	spin_lock_irq (&chip->lock);
+
+	if (vma->vm_flags & VM_WRITE && chip->play.active) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+        if (vma->vm_flags & VM_READ && chip->rec.active) {
+		ret = -EBUSY;
+		goto out;
+        }
+
+	if (file->f_mode & FMODE_WRITE)
+		channel = &chip->play;
+	else if (file->f_mode & FMODE_READ)
+		channel = &chip->rec;
+	else {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	forte_channel_prep (channel);
+	channel->mapped = 1;
+
+        if (vma->vm_pgoff != 0) {
+		ret = -EINVAL;
+                goto out;
+	}
+
+        size = vma->vm_end - vma->vm_start;
+
+        if (size > channel->buf_pages * PAGE_SIZE) {
+		DPRINTK ("%s: size (%ld) > buf_sz (%d) \n", __FUNCTION__,
+			 size, channel->buf_sz);
+		ret = -EINVAL;
+                goto out;
+	}
+
+        if (remap_page_range (vma->vm_start, virt_to_phys (channel->buf),
+			      size, vma->vm_page_prot)) {
+		DPRINTK ("%s: remap el a no worko\n", __FUNCTION__);
+		ret = -EAGAIN;
+                goto out;
+	}
+
+        ret = 0;
+
+ out:
+	spin_unlock_irq (&chip->lock);
+        return ret;
+}
+
+
+/**
+ * forte_dsp_write:
+ */
+
+static ssize_t 
+forte_dsp_write (struct file *file, const char *buffer, size_t bytes, 
+		 loff_t *ppos)
+{
+	struct forte_chip *chip;
+	struct forte_channel *channel;
+	unsigned int i = bytes, sz = 0;
+	unsigned long flags;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (!access_ok (VERIFY_READ, buffer, bytes))
+		return -EFAULT;
+
+	chip = (struct forte_chip *) file->private_data;
+
+	if (!chip)
+		BUG();
+
+	channel = &chip->play;
+
+	if (!channel)
+		BUG();
+
+	spin_lock_irqsave (&chip->lock, flags);
+
+	/* Set up buffers with the right fragment size */
+	forte_channel_prep (channel);
+
+	while (i) {
+		/* All fragment buffers in use -> wait */
+		if (channel->frag_num - channel->filled_frags == 0) {
+			DECLARE_WAITQUEUE (wait, current);
+
+			/* For trigger mode operation, get out */
+			if (chip->trigger) {
+				spin_unlock_irqrestore (&chip->lock, flags);
+				return -EAGAIN;
+			}
+
+			/* Otherwise wait for buffers */
+			channel->blocked = 1;
+			add_wait_queue (&channel->wait, &wait);
+
+			for (;;) {
+				if (channel->active == 0)
+					break;
+
+				if (channel->frag_num - channel->filled_frags)
+					break;
+
+				spin_unlock_irqrestore (&chip->lock, flags);
+
+				set_current_state (TASK_INTERRUPTIBLE);
+				schedule();				
+
+				spin_lock_irqsave (&chip->lock, flags);
+			}
+
+			set_current_state (TASK_RUNNING);
+			remove_wait_queue (&channel->wait, &wait);
+			channel->blocked = 0;
+		}
+
+		if (i > channel->frag_sz)
+			sz = channel->frag_sz;
+		else
+			sz = i;
+
+		spin_unlock_irqrestore (&chip->lock, flags);
+
+		/* Clear the fragment so we don't get noise when copying
+		 * smaller buffers
+		 */
+		memset ((void *) channel->buf + channel->swptr, 0x0, sz);
+
+		if (copy_from_user ((void *) channel->buf + channel->swptr, 
+				    buffer, sz)) {
+			return -EFAULT;
+		}
+
+		spin_lock_irqsave (&chip->lock, flags);
+
+		/* Advance software pointer */
+		buffer += sz;
+		channel->filled_frags++;
+		channel->swptr += channel->frag_sz;
+		channel->swptr %= channel->buf_sz;
+		i -= sz;
+
+		/* If playback isn't active, start it */
+		if (channel->active == 0 && chip->trigger == 0)
+			forte_channel_start (channel);
+	}
+
+	spin_unlock_irqrestore (&chip->lock, flags);
+
+	return bytes - i;
+}
+
+
+/**
+ * forte_dsp_read:
+ */
+
+static ssize_t 
+forte_dsp_read (struct file *file, char *buffer, size_t bytes, 
+		loff_t *ppos)
+{
+	struct forte_chip *chip;
+	struct forte_channel *channel;
+	unsigned int i = bytes, sz;
+	unsigned long flags;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (!access_ok (VERIFY_WRITE, buffer, bytes))
+		return -EFAULT;
+
+	chip = (struct forte_chip *) file->private_data;
+
+	if (!chip)
+		BUG();
+
+	channel = &chip->rec;
+
+	if (!channel)
+		BUG();
+
+	spin_lock_irqsave (&chip->lock, flags);
+
+	/* Set up buffers with the right fragment size */
+	forte_channel_prep (channel);
+
+	/* Start recording */
+	if (!chip->trigger)
+		forte_channel_start (channel);
+
+	while (i) {
+		/* No fragment buffers in use -> wait */
+		if (channel->filled_frags == 0) {
+			DECLARE_WAITQUEUE (wait, current);
+
+			/* For trigger mode operation, get out */
+			if (chip->trigger) {
+				spin_unlock_irqrestore (&chip->lock, flags);
+				return -EAGAIN;
+			}
+
+			channel->blocked = 1;
+			add_wait_queue (&channel->wait, &wait);
+
+			for (;;) {
+				if (channel->active == 0)
+					break;
+
+				if (channel->filled_frags)
+					break;
+						
+				spin_unlock_irqrestore (&chip->lock, flags);
+
+				set_current_state (TASK_INTERRUPTIBLE);
+				schedule();
+
+				spin_lock_irqsave (&chip->lock, flags);
+			}
+
+			set_current_state (TASK_RUNNING);
+			remove_wait_queue (&channel->wait, &wait);
+			channel->blocked = 0;
+		}
+
+		if (i > channel->frag_sz)
+			sz = channel->frag_sz;
+		else
+			sz = i;
+
+		spin_unlock_irqrestore (&chip->lock, flags);
+
+		if (copy_to_user (buffer, (void *)channel->buf+channel->swptr, sz)) {
+			DPRINTK ("%s: copy_to_user failed\n", __FUNCTION__);
+			return -EFAULT;
+		}
+
+		spin_lock_irqsave (&chip->lock, flags);
+
+		/* Advance software pointer */
+		buffer += sz;
+		channel->filled_frags--;
+		channel->swptr += channel->frag_sz;
+		channel->swptr %= channel->buf_sz;
+		i -= sz;
+	}
+
+	spin_unlock_irqrestore (&chip->lock, flags);
+
+	return bytes - i;
+}
+
+
+static struct file_operations forte_dsp_fops = {
+	owner:			THIS_MODULE,
+	llseek:     		&no_llseek,
+	read:       		&forte_dsp_read,
+	write:      		&forte_dsp_write,
+	poll:       		&forte_dsp_poll,
+	ioctl:      		&forte_dsp_ioctl,
+	open:       		&forte_dsp_open,
+	release:    		&forte_dsp_release,
+	mmap:			&forte_dsp_mmap,
+};
+
+
+/* Common ------------------------------------------------------------------ */
+
+
+/**
+ * forte_interrupt:
+ */
+
+static void
+forte_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct forte_chip *chip = dev_id;
+	struct forte_channel *channel = NULL;
+	u16 status, count; 
+
+	status = inw (chip->iobase + FORTE_IRQ_STATUS);
+
+	/* If this is not for us, get outta here ASAP */
+	if ((status & (FORTE_IRQ_PLAYBACK | FORTE_IRQ_CAPTURE)) == 0)
+		return;
+	
+	if (status & FORTE_IRQ_PLAYBACK) {
+		channel = &chip->play;
+		spin_lock (&chip->lock);
+
+		/* Declare a fragment done */
+		channel->filled_frags--;
+
+		/* Get # of completed bytes */
+		count = inw (channel->iobase + FORTE_PLY_COUNT) + 1;
+		channel->bytes += count;
+
+		if (count == 0) {
+			DPRINTK ("%s: last, filled_frags = %d\n", __FUNCTION__,
+				 channel->filled_frags);
+			channel->filled_frags = 0;
+			forte_channel_stop (channel);
+			goto pack;
+		}
+
+		channel->nr_irqs++;
+		
+		/* Flip-flop between buffer I and II */
+		channel->next_buf ^= 1;
+
+		/* Advance hardware pointer by fragment size and wrap around */
+		channel->hwptr += channel->frag_sz;
+		channel->hwptr %= channel->buf_sz;
+
+		/* Buffer I or buffer II BAR */
+                outl (channel->buf_handle + channel->hwptr, 
+		      channel->next_buf == 0 ?
+		      channel->iobase + FORTE_PLY_BUF1 :
+		      channel->iobase + FORTE_PLY_BUF2);
+
+		/* If the currently playing fragment is last, schedule stop */
+		if (channel->filled_frags == 1)
+			forte_channel_stop (channel);
+	pack:
+		/* Acknowledge interrupt */
+                outw (FORTE_IRQ_PLAYBACK, chip->iobase + FORTE_IRQ_STATUS);
+
+		spin_unlock (&chip->lock);
+
+		if (channel->blocked || channel->drain)
+			wake_up_interruptible (&channel->wait);
+	}
+
+	if (status & FORTE_IRQ_CAPTURE) {
+		channel = &chip->rec;
+		spin_lock (&chip->lock);
+
+		/* One fragment filled */
+		channel->filled_frags++;
+
+		/* Get # of completed bytes */
+		count = inw (channel->iobase + FORTE_PLY_COUNT) + 1;
+
+		if (count == 0) {
+			DPRINTK ("%s: last, filled_frags = %d\n", __FUNCTION__,
+				 channel->filled_frags);
+			channel->filled_frags = 0;
+			goto rack;
+		}
+		
+		/* Buffer I or buffer II BAR */
+                outl (channel->buf_handle + channel->hwptr, 
+		      channel->next_buf == 0 ?
+		      channel->iobase + FORTE_PLY_BUF1 :
+		      channel->iobase + FORTE_PLY_BUF2);
+
+		/* Flip-flop between buffer I and II */
+		channel->next_buf ^= 1;
+
+		/* Advance hardware pointer by fragment size and wrap around */
+		channel->hwptr += channel->frag_sz;
+		channel->hwptr %= channel->buf_sz;
+
+		/* Out of buffers */
+		if (channel->filled_frags == channel->frag_num - 1)
+			forte_channel_stop (channel);
+	rack:
+		/* Acknowledge interrupt */
+                outw (FORTE_IRQ_CAPTURE, chip->iobase + FORTE_IRQ_STATUS);
+
+		spin_unlock (&chip->lock);
+
+		if (channel->blocked)
+			wake_up_all (&channel->wait);		
+	}
+
+	return;
+}
+
+
+/**
+ * forte_proc_read:
+ */
+
+static int
+forte_proc_read (char *page, char **start, off_t off, int count, 
+		 int *eof, void *data)
+{
+	int i = 0, p_rate, p_chan, r_rate;
+	unsigned short p_reg, r_reg;
+
+	i += sprintf (page, "ForteMedia FM801 OSS Lite driver\n%s\n\n", 
+		      DRIVER_VERSION);
+
+	if (!forte->iobase)
+		return i;
+
+	p_rate = p_chan = -1;
+	p_reg  = inw (forte->iobase + FORTE_PLY_CTRL);
+	p_rate = (p_reg >> 8) & 15;
+	p_chan = (p_reg >> 12) & 3;
+
+ 	if (p_rate >= 0 || p_rate <= 10)
+		p_rate = rates[p_rate];
+
+	if (p_chan >= 0 || p_chan <= 2)
+		p_chan = channels[p_chan];
+
+	r_rate = -1;
+	r_reg  = inw (forte->iobase + FORTE_CAP_CTRL);
+	r_rate = (r_reg >> 8) & 15;
+
+ 	if (r_rate >= 0 || r_rate <= 10)
+		r_rate = rates[r_rate]; 
+
+	i += sprintf (page + i,
+		      "             Playback  Capture\n"
+		      "FIFO empty : %-3s       %-3s\n"
+		      "Buf1 Last  : %-3s       %-3s\n"
+		      "Buf2 Last  : %-3s       %-3s\n"
+		      "Started    : %-3s       %-3s\n"
+		      "Paused     : %-3s       %-3s\n"
+		      "Immed Stop : %-3s       %-3s\n"
+		      "Rate       : %-5d     %-5d\n"
+		      "Channels   : %-5d     -\n"
+		      "16-bit     : %-3s       %-3s\n"
+		      "Stereo     : %-3s       %-3s\n",
+		      p_reg & 1<<0  ? "yes" : "no",
+		      r_reg & 1<<0  ? "yes" : "no",
+		      p_reg & 1<<1  ? "yes" : "no",
+		      r_reg & 1<<1  ? "yes" : "no",
+		      p_reg & 1<<2  ? "yes" : "no",
+		      r_reg & 1<<2  ? "yes" : "no",
+		      p_reg & 1<<5  ? "yes" : "no",
+		      r_reg & 1<<5  ? "yes" : "no",
+		      p_reg & 1<<6  ? "yes" : "no",
+		      r_reg & 1<<6  ? "yes" : "no",
+		      p_reg & 1<<7  ? "yes" : "no",
+		      r_reg & 1<<7  ? "yes" : "no",
+		      p_rate, r_rate,
+		      p_chan,
+		      p_reg & 1<<14 ? "yes" : "no",
+		      r_reg & 1<<14 ? "yes" : "no",
+		      p_reg & 1<<15 ? "yes" : "no",
+		      r_reg & 1<<15 ? "yes" : "no");
+
+	return i;
+}
+
+
+/**
+ * forte_proc_init:
+ *
+ * Creates driver info entries in /proc
+ */
+
+static int __init 
+forte_proc_init (void)
+{
+	if (!proc_mkdir ("driver/forte", 0))
+		return -EIO;
+
+	if (!create_proc_read_entry ("driver/forte/chip", 0, 0, forte_proc_read, forte)) {
+		remove_proc_entry ("driver/forte", NULL);
+		return -EIO;
+	}
+
+	if (!create_proc_read_entry("driver/forte/ac97", 0, 0, ac97_read_proc, forte->ac97)) {
+		remove_proc_entry ("driver/forte/chip", NULL);
+		remove_proc_entry ("driver/forte", NULL);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+
+/**
+ * forte_proc_remove:
+ *
+ * Removes driver info entries in /proc
+ */
+
+static void
+forte_proc_remove (void)
+{
+	remove_proc_entry ("driver/forte/ac97", NULL);
+	remove_proc_entry ("driver/forte/chip", NULL);
+	remove_proc_entry ("driver/forte", NULL);	
+}
+
+
+/**
+ * forte_chip_init:
+ * @chip:	Chip instance to initialize
+ *
+ * Description:
+ * 		Resets chip, configures codec and registers the driver with
+ * 		the sound subsystem.
+ *
+ * 		Press and hold Start for 8 secs, then switch on Run
+ * 		and hold for 4 seconds.  Let go of Start.  Numbers
+ * 		assume a properly oiled TWG.
+ */
+
+static int __devinit
+forte_chip_init (struct forte_chip *chip)
+{
+	u8 revision;
+	u16 cmdw;
+	struct ac97_codec *codec;
+
+	pci_read_config_byte (chip->pci_dev, PCI_REVISION_ID, &revision);
+
+	if (revision >= 0xB1) {
+		chip->multichannel = 1;
+		printk (KERN_INFO PFX "Multi-channel device detected.\n");
+	}
+
+	/* Reset chip */
+	outw (FORTE_CC_CODEC_RESET | FORTE_CC_AC97_RESET, 
+	      chip->iobase + FORTE_CODEC_CTRL);
+	udelay(100);
+	outw (0, chip->iobase + FORTE_CODEC_CTRL);
+
+	/* Request read from AC97 */
+	outw (FORTE_AC97_READ | (0 << FORTE_AC97_ADDR_SHIFT), 
+	      chip->iobase + FORTE_AC97_CMD);
+	mdelay(750);
+
+	if ((inw (chip->iobase + FORTE_AC97_CMD) & (3<<8)) != (1<<8)) {
+		printk (KERN_INFO PFX "AC97 codec not responding");
+		return -EIO;
+	}
+
+	/* Init volume */
+	outw (0x0808, chip->iobase + FORTE_PCM_VOL);
+	outw (0x9f1f, chip->iobase + FORTE_FM_VOL);
+	outw (0x8808, chip->iobase + FORTE_I2S_VOL);
+
+	/* I2S control - I2S mode */
+	outw (0x0003, chip->iobase + FORTE_I2S_MODE);
+
+	/* Interrupt setup - unmask PLAYBACK & CAPTURE */
+	cmdw = inw (chip->iobase + FORTE_IRQ_MASK);
+	cmdw &= ~0x0003;
+	outw (cmdw, chip->iobase + FORTE_IRQ_MASK);
+
+	/* Interrupt clear */
+	outw (FORTE_IRQ_PLAYBACK|FORTE_IRQ_CAPTURE, 
+	      chip->iobase + FORTE_IRQ_STATUS);
+
+	/* Set up the AC97 codec */
+	if ((codec = kmalloc (sizeof (struct ac97_codec), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+	memset (codec, 0, sizeof (struct ac97_codec));
+
+	codec->private_data = chip;
+	codec->codec_read = forte_ac97_read;
+	codec->codec_write = forte_ac97_write;
+	codec->id = 0;
+
+	if (ac97_probe_codec (codec) == 0) {
+		printk (KERN_ERR PFX "codec probe failed\n");
+		kfree (codec);
+		return -1;
+	}
+
+	/* Register mixer */
+	if ((codec->dev_mixer = 
+	     register_sound_mixer (&forte_mixer_fops, -1)) < 0) {
+		printk (KERN_ERR PFX "couldn't register mixer!\n");
+		kfree (codec);
+		return -1;
+	}
+
+	chip->ac97 = codec;
+
+	/* Register DSP */
+	if ((chip->dsp = register_sound_dsp (&forte_dsp_fops, -1) ) < 0) {
+		printk (KERN_ERR PFX "couldn't register dsp!\n");
+		return -1;
+	}
+
+	/* Register with /proc */
+	if (forte_proc_init()) {
+		printk (KERN_ERR PFX "couldn't add entries to /proc!\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * forte_probe:
+ * @pci_dev:	PCI struct for probed device
+ * @pci_id:	
+ *
+ * Description:
+ *		Allocates chip instance, I/O region, and IRQ
+ */
+static int __init 
+forte_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
+{
+	struct forte_chip *chip;
+	int ret = 0;
+
+	/* FIXME: Support more than one chip */
+	if (found++)
+		return -EIO;
+
+	/* Ignition */
+	if (pci_enable_device (pci_dev))
+		return -EIO;
+
+	pci_set_master (pci_dev);
+
+	/* Allocate chip instance and configure */
+	forte = (struct forte_chip *) 
+		kmalloc (sizeof (struct forte_chip), GFP_KERNEL);
+	chip = forte;
+
+	if (chip == NULL) {
+		printk (KERN_WARNING PFX "Out of memory");
+		return -ENOMEM;
+	}
+
+	memset (chip, 0, sizeof (struct forte_chip));
+	chip->pci_dev = pci_dev;
+
+	init_MUTEX(&chip->open_sem);
+	spin_lock_init (&chip->lock);
+	spin_lock_init (&chip->ac97_lock);
+
+	if (! request_region (pci_resource_start (pci_dev, 0),
+			      pci_resource_len (pci_dev, 0), DRIVER_NAME)) {
+		printk (KERN_WARNING PFX "Unable to reserve I/O space");
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	chip->iobase = pci_resource_start (pci_dev, 0);
+	chip->irq = pci_dev->irq;
+
+	if (request_irq (chip->irq, forte_interrupt, SA_SHIRQ, DRIVER_NAME,
+			 chip)) {
+		printk (KERN_WARNING PFX "Unable to reserve IRQ");
+		ret = -EIO;
+		goto error;
+	}		
+	
+	pci_set_drvdata (pci_dev, chip);
+
+	printk (KERN_INFO PFX "FM801 chip found at 0x%04lX-0x%04lX IRQ %u\n", 
+		chip->iobase, pci_resource_end (pci_dev, 0), chip->irq);
+
+	/* Power it up */
+	if ((ret = forte_chip_init (chip)) == 0)
+		return 0;
+
+ error:
+	if (chip->irq)
+		free_irq (chip->irq, chip);
+
+	if (chip->iobase) 
+		release_region (pci_resource_start (pci_dev, 0),
+				pci_resource_len (pci_dev, 0));
+		
+	kfree (chip);
+
+	return ret;
+}
+
+
+/**
+ * forte_remove:
+ * @pci_dev:	PCI device to unclaim
+ *
+ */
+
+static void 
+forte_remove (struct pci_dev *pci_dev)
+{
+	struct forte_chip *chip = pci_get_drvdata (pci_dev);
+
+	if (chip == NULL)
+		return;
+
+	/* Turn volume down to avoid popping */
+	outw (0x1f1f, chip->iobase + FORTE_PCM_VOL);
+	outw (0x1f1f, chip->iobase + FORTE_FM_VOL);
+	outw (0x1f1f, chip->iobase + FORTE_I2S_VOL);
+
+	forte_proc_remove();
+	free_irq (chip->irq, chip);
+	release_region (chip->iobase, pci_resource_len (pci_dev, 0));
+
+	unregister_sound_dsp (chip->dsp);
+	unregister_sound_mixer (chip->ac97->dev_mixer);
+
+	kfree (chip);
+
+	printk (KERN_INFO PFX "driver released\n");
+}
+
+
+static struct pci_device_id forte_pci_ids[] __devinitdata = {
+	{ 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+	{ 0, }
+};
+
+
+static struct pci_driver forte_pci_driver = {
+	name:       		DRIVER_NAME,
+	id_table:   		forte_pci_ids,
+	probe:      		forte_probe,
+	remove:     		forte_remove,
+
+};
+
+
+/**
+ * forte_init_module:
+ *
+ */
+
+static int __init
+forte_init_module (void)
+{
+	if (!pci_present())
+		return -ENODEV;
+
+	printk (KERN_INFO PFX DRIVER_VERSION "\n");
+
+	if (!pci_register_driver (&forte_pci_driver)) {
+		pci_unregister_driver (&forte_pci_driver);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+
+/**
+ * forte_cleanup_module:
+ *
+ */
+
+static void __exit 
+forte_cleanup_module (void)
+{
+	pci_unregister_driver (&forte_pci_driver);
+}
+
+
+module_init(forte_init_module);
+module_exit(forte_cleanup_module);
+
+MODULE_AUTHOR("Martin K. Petersen <mkp@mkp.net>");
+MODULE_DESCRIPTION("ForteMedia FM801 OSS Driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE (pci, forte_pci_ids);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/harmony.c linux-2.4.20/drivers/sound/harmony.c
--- linux-2.4.19/drivers/sound/harmony.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/sound/harmony.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,1295 @@
+/*
+ 	drivers/sound/harmony.c 
+
+	This is a sound driver for ASP's and Lasi's Harmony sound chip
+	and is unlikely to be used for anything other than on a HP PA-RISC.
+
+	Harmony is found in HP 712s, 715/new and many other GSC based machines.
+	On older 715 machines you'll find the technically identical chip 
+	called 'Vivace'. Both Harmony and Vicace are supported by this driver.
+
+	Copyright 2000 (c) Linuxcare Canada, Alex deVries <alex@linuxcare.com>
+	Copyright 2000-2002 (c) Helge Deller <deller@gmx.de>
+	Copyright 2001 (c) Matthieu Delahaye <delahaym@esiee.fr>
+	Copyright 2001 (c) Jean-Christophe Vaugeois <vaugeoij@esiee.fr>
+
+				
+TODO:
+	- fix SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE ioctls to
+		return the real values
+	- add private ioctl for selecting line- or microphone input
+		(only one of them is available at the same time)
+	- add module parameters
+	- implement mmap functionality
+	- implement gain meter ?
+	- ...
+*/
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+
+#include <asm/gsc.h>
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+
+#include "sound_config.h"
+
+
+#define PFX "harmony: "
+#define HARMONY_VERSION "V0.9a"
+
+#undef DEBUG
+#ifdef DEBUG
+# define DPRINTK printk 
+#else
+# define DPRINTK(x,...)
+#endif
+
+
+#define MAX_BUFS 10		/* maximum number of rotating buffers */
+#define HARMONY_BUF_SIZE 4096	/* needs to be a multiple of PAGE_SIZE (4096)! */
+
+#define CNTL_C		0x80000000
+#define	CNTL_ST		0x00000020
+#define CNTL_44100	0x00000015	/* HARMONY_SR_44KHZ */
+#define CNTL_8000	0x00000008	/* HARMONY_SR_8KHZ */
+
+#define GAINCTL_HE	0x08000000
+#define GAINCTL_LE	0x04000000
+#define GAINCTL_SE	0x02000000
+
+#define DSTATUS_PN	0x00000200
+#define DSTATUS_RN	0x00000002
+
+#define DSTATUS_IE	0x80000000
+
+#define HARMONY_DF_16BIT_LINEAR	0
+#define HARMONY_DF_8BIT_ULAW	1
+#define HARMONY_DF_8BIT_ALAW	2
+
+#define HARMONY_SS_MONO		0
+#define HARMONY_SS_STEREO	1
+
+#define HARMONY_SR_8KHZ		0x08
+#define HARMONY_SR_16KHZ	0x09
+#define HARMONY_SR_27KHZ	0x0A
+#define HARMONY_SR_32KHZ	0x0B
+#define HARMONY_SR_48KHZ	0x0E
+#define HARMONY_SR_9KHZ		0x0F
+#define HARMONY_SR_5KHZ		0x10
+#define HARMONY_SR_11KHZ	0x11
+#define HARMONY_SR_18KHZ	0x12
+#define HARMONY_SR_22KHZ	0x13
+#define HARMONY_SR_37KHZ	0x14
+#define HARMONY_SR_44KHZ	0x15
+#define HARMONY_SR_33KHZ	0x16
+#define HARMONY_SR_6KHZ		0x17
+
+/*
+ * Some magics numbers used to auto-detect file formats
+ */
+
+#define HARMONY_MAGIC_8B_ULAW	1
+#define HARMONY_MAGIC_8B_ALAW	27
+#define HARMONY_MAGIC_16B_LINEAR 3
+#define HARMONY_MAGIC_MONO	1
+#define HARMONY_MAGIC_STEREO	2
+
+/*
+ * Channels Positions in mixer register
+ */
+
+#define GAIN_HE_SHIFT   27
+#define GAIN_HE_MASK    ( 1 << GAIN_HE_SHIFT) 
+#define GAIN_LE_SHIFT   26
+#define GAIN_LE_MASK    ( 1 << GAIN_LE_SHIFT) 
+#define GAIN_SE_SHIFT   25
+#define GAIN_SE_MASK    ( 1 << GAIN_SE_SHIFT) 
+#define GAIN_IS_SHIFT   24
+#define GAIN_IS_MASK    ( 1 << GAIN_IS_SHIFT) 
+#define GAIN_MA_SHIFT   20
+#define GAIN_MA_MASK    ( 0x0f << GAIN_MA_SHIFT) 
+#define GAIN_LI_SHIFT   16
+#define GAIN_LI_MASK    ( 0x0f << GAIN_LI_SHIFT) 
+#define GAIN_RI_SHIFT   12
+#define GAIN_RI_MASK    ( 0x0f << GAIN_RI_SHIFT) 
+#define GAIN_LO_SHIFT   6
+#define GAIN_LO_MASK    ( 0x3f << GAIN_LO_SHIFT) 
+#define GAIN_RO_SHIFT   0
+#define GAIN_RO_MASK    ( 0x3f << GAIN_RO_SHIFT) 
+
+
+#define MAX_OUTPUT_LEVEL (GAIN_RO_MASK >> GAIN_RO_SHIFT)
+#define MAX_INPUT_LEVEL  (GAIN_RI_MASK >> GAIN_RI_SHIFT)
+#define MAX_VOLUME_LEVEL (GAIN_MA_MASK >> GAIN_MA_SHIFT)
+
+/*
+ * Channels Mask in mixer register
+ */
+
+#define GAIN_TOTAL_SILENCE 0x00F00FFF
+#define GAIN_DEFAULT       0x0FF00000
+
+
+struct harmony_hpa {
+	u8	unused000;
+	u8	id;
+	u8	teleshare_id;
+	u8	unused003;
+	u32	reset;
+	u32	cntl;
+	u32	gainctl;
+	u32	pnxtadd;
+	u32	pcuradd;
+	u32	rnxtadd;
+	u32	rcuradd;
+	u32	dstatus;
+	u32	ov;
+	u32	pio;
+	u32	unused02c;
+	u32	unused030[3];
+	u32	diag;
+};
+
+struct harmony_dev {
+	int irq;
+	struct harmony_hpa *hpa;
+	u32 current_gain;
+	u8 data_format;		/* HARMONY_DF_xx_BIT_xxx */
+	u8 sample_rate;		/* HARMONY_SR_xx_KHZ */
+	u8 stereo_select;	/* HARMONY_SS_MONO or HARMONY_SS_STEREO */
+	int format_initialized;
+	u32 dac_rate;		/* 8000 ... 48000 (Hz) */
+	int suspended_playing;
+	int suspended_recording;
+	
+	int blocked_playing;
+	int blocked_recording;
+	
+	wait_queue_head_t wq_play, wq_record;
+	int first_filled_play;	/* first buffer containing data (next to play) */
+	int nb_filled_play; 
+	int play_offset;
+	int first_filled_record;
+	int nb_filled_record;
+		
+	int audio_open, mixer_open;
+	int dsp_unit, mixer_unit;
+
+	struct pci_dev *fake_pci_dev; /* The fake pci_dev needed for 
+					pci_* functions under ccio. */
+};
+
+
+static struct harmony_dev harmony;
+
+
+/*
+ * Dynamic sound buffer allocation and DMA memory
+ */
+
+struct harmony_buffer {
+	unsigned char *addr;
+	dma_addr_t dma_handle;
+	int dma_consistent;	/* Zero if pci_alloc_consistent() fails */
+	int len;
+};
+
+/*
+ * Harmony memory buffers
+ */
+
+static struct harmony_buffer played_buf, recorded_buf, silent, graveyard;
+
+
+#define CHECK_WBACK_INV_OFFSET(b,offset,len) \
+        do { if (!b.dma_consistent) \
+		dma_cache_wback_inv((unsigned long)b.addr+offset,len); \
+	} while (0) 
+
+	
+static int __init harmony_alloc_buffer(struct harmony_buffer *b, 
+		int buffer_count)
+{
+	b->len = buffer_count * HARMONY_BUF_SIZE;
+	b->addr = pci_alloc_consistent(harmony.fake_pci_dev, 
+			  b->len, &b->dma_handle);
+	if (b->addr && b->dma_handle) {
+		b->dma_consistent = 1;
+		DPRINTK(KERN_INFO PFX "consistent memory: 0x%lx, played_buf: 0x%lx\n",
+				(unsigned long)b->dma_handle, (unsigned long)b->addr);
+	} else {
+		b->dma_consistent = 0;
+		/* kmalloc()ed memory will HPMC on ccio machines ! */
+		b->addr = kmalloc(b->len, GFP_KERNEL);
+		if (!b->addr) {
+			printk(KERN_ERR PFX "couldn't allocate memory\n");
+			return -EBUSY;
+		}
+		b->dma_handle = __pa(b->addr);
+	}
+	return 0;
+}
+
+static void __exit harmony_free_buffer(struct harmony_buffer *b)
+{
+	if (!b->addr)
+		return;
+
+	if (b->dma_consistent)
+		pci_free_consistent(harmony.fake_pci_dev,
+				b->len, b->addr, b->dma_handle);
+	else
+		kfree(b->addr);
+
+	memset(b, 0, sizeof(*b));
+}
+
+
+
+/*
+ * Low-Level sound-chip programming
+ */
+
+static void __inline__ harmony_wait_CNTL(void)
+{
+	/* Wait until we're out of control mode */
+	while (gsc_readl(&harmony.hpa->cntl) & CNTL_C)
+		/* wait */ ;
+}
+
+
+static void harmony_update_control(void) 
+{
+	u32 default_cntl;
+	
+	/* Set CNTL */
+	default_cntl = (CNTL_C |  		/* The C bit */
+		(harmony.data_format << 6) |	/* Set the data format */
+		(harmony.stereo_select << 5) |	/* Stereo select */
+		(harmony.sample_rate));		/* Set sample rate */
+	harmony.format_initialized = 1;
+	
+	/* initialize CNTL */
+	gsc_writel(default_cntl, &harmony.hpa->cntl);
+}
+
+static void harmony_set_control(u8 data_format, u8 sample_rate, u8 stereo_select) 
+{
+	harmony.sample_rate = sample_rate;
+	harmony.data_format = data_format;
+	harmony.stereo_select = stereo_select;
+	harmony_update_control();
+}
+
+static void harmony_set_rate(u8 data_rate) 
+{
+	harmony.sample_rate = data_rate;
+	harmony_update_control();
+}
+
+static int harmony_detect_rate(int *freq)
+{
+	int newrate;
+	switch (*freq) {
+	case 8000:	newrate = HARMONY_SR_8KHZ;	break;
+	case 16000:	newrate = HARMONY_SR_16KHZ;	break; 
+	case 27428:	newrate = HARMONY_SR_27KHZ;	break; 
+	case 32000:	newrate = HARMONY_SR_32KHZ;	break; 
+	case 48000:	newrate = HARMONY_SR_48KHZ;	break; 
+	case 9600:	newrate = HARMONY_SR_9KHZ;	break; 
+	case 5125:	newrate = HARMONY_SR_5KHZ;	break; 
+	case 11025:	newrate = HARMONY_SR_11KHZ;	break; 
+	case 18900:	newrate = HARMONY_SR_18KHZ;	break; 
+	case 22050:	newrate = HARMONY_SR_22KHZ;	break; 
+	case 37800:	newrate = HARMONY_SR_37KHZ;	break; 
+	case 44100:	newrate = HARMONY_SR_44KHZ;	break; 
+	case 33075:	newrate = HARMONY_SR_33KHZ;	break; 
+	case 6615:	newrate = HARMONY_SR_6KHZ;	break; 
+	default:	newrate = HARMONY_SR_8KHZ; 
+			*freq = 8000;			break;
+	}
+	return newrate;
+}
+
+static void harmony_set_format(u8 data_format) 
+{
+	harmony.data_format = data_format;
+	harmony_update_control();
+}
+
+static void harmony_set_stereo(u8 stereo_select) 
+{
+	harmony.stereo_select = stereo_select;
+	harmony_update_control();
+}
+
+static void harmony_disable_interrupts(void) 
+{
+	harmony_wait_CNTL();
+	gsc_writel(0, &harmony.hpa->dstatus); 
+}
+
+static void harmony_enable_interrupts(void) 
+{
+	harmony_wait_CNTL();
+	gsc_writel(DSTATUS_IE, &harmony.hpa->dstatus); 
+}
+
+/*
+ * harmony_silence()
+ *
+ * This subroutine fills in a buffer starting at location start and
+ * silences for length bytes.  This references the current
+ * configuration of the audio format.
+ *
+ */
+
+static void harmony_silence(struct harmony_buffer *buffer, int start, int length) 
+{
+	u8 silence_char;
+
+	/* Despite what you hear, silence is different in
+	   different audio formats.  */
+	switch (harmony.data_format) {
+		case HARMONY_DF_8BIT_ULAW:	silence_char = 0x55; break;
+		case HARMONY_DF_8BIT_ALAW:	silence_char = 0xff; break;
+		case HARMONY_DF_16BIT_LINEAR:	/* fall through */
+		default:			silence_char = 0;
+	}
+
+	memset(buffer->addr+start, silence_char, length);
+}
+
+
+static int harmony_audio_open(struct inode *inode, struct file *file)
+{
+	if (harmony.audio_open) 
+		return -EBUSY;
+	
+	harmony.audio_open++;
+	harmony.suspended_playing = harmony.suspended_recording = 1;
+	harmony.blocked_playing   = harmony.blocked_recording   = 0;
+	harmony.first_filled_play = harmony.first_filled_record = 0;
+	harmony.nb_filled_play    = harmony.nb_filled_record    = 0;
+	harmony.play_offset = 0;
+	init_waitqueue_head(&harmony.wq_play);
+	init_waitqueue_head(&harmony.wq_record);
+	
+	/* Start off in a balanced mode. */
+	harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO);
+	harmony_update_control();
+	harmony.format_initialized = 0;
+
+	/* Clear out all the buffers and flush to cache */
+	harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
+	CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
+	
+	return 0;
+}
+
+/*
+ * Release (close) the audio device.
+ */
+
+static int harmony_audio_release(struct inode *inode, struct file *file)
+{
+	if (!harmony.audio_open) 
+		return -EBUSY;
+	
+	harmony.audio_open--;
+
+	return 0;
+}
+
+/*
+ * Read recorded data off the audio device.
+ */
+
+static ssize_t harmony_audio_read(struct file *file,
+                                char *buffer,
+                                size_t size_count,
+                                loff_t *ppos)
+{
+	int total_count = (int) size_count;
+	int count = 0;
+	int buf_to_read;
+
+	while (count<total_count) {
+		/* Wait until we're out of control mode */
+		harmony_wait_CNTL();
+		
+		/* Figure out which buffer to fill in */
+		if (harmony.nb_filled_record <= 2) {
+			harmony.blocked_recording = 1;
+		        if (harmony.suspended_recording) {
+				harmony.suspended_recording = 0;
+				harmony_enable_interrupts();
+			}
+							
+			interruptible_sleep_on(&harmony.wq_record);
+			harmony.blocked_recording = 0;
+		}
+		
+		if (harmony.nb_filled_record < 2)
+			return -EBUSY;
+		
+		buf_to_read = harmony.first_filled_record;
+
+		/* Copy the page to an aligned buffer */
+		copy_to_user(buffer+count, 
+			     recorded_buf.addr+(HARMONY_BUF_SIZE*buf_to_read), 
+			     HARMONY_BUF_SIZE);
+		
+		harmony.nb_filled_record--;
+		harmony.first_filled_record++;
+		harmony.first_filled_record %= MAX_BUFS;
+				
+		count += HARMONY_BUF_SIZE;
+	}
+	return count;
+}
+
+
+
+
+/*
+ * Here is the place where we try to recognize file format.
+ * Sun/NeXT .au files begin with the string .snd
+ * At offset 12 is specified the encoding.
+ * At offset 16 is specified speed rate
+ * At Offset 20 is specified the numbers of voices
+ */
+
+#define four_bytes_to_u32(start) (file_header[start] << 24)|\
+                                  (file_header[start+1] << 16)|\
+                                  (file_header[start+2] << 8)|\
+                                  (file_header[start+3]);
+
+#define test_rate(tested,real_value,harmony_value) if ((tested)<=(real_value))\
+                                                    
+
+static void harmony_format_auto_detect(const char *buffer, int block_size)
+{
+	u8 file_header[24];
+	u32 start_string;
+	
+	if (block_size>24) {
+		copy_from_user(file_header, buffer, sizeof(file_header));
+		start_string = four_bytes_to_u32(0);
+		
+		if ((file_header[4]==0) && (start_string==0x2E736E64)) {
+			u32 format;
+			u32 nb_voices;
+			u32 speed;
+			
+			format = four_bytes_to_u32(12);
+			nb_voices = four_bytes_to_u32(20);
+			speed = four_bytes_to_u32(16);
+			
+			switch (format) {
+			case HARMONY_MAGIC_8B_ULAW:
+				harmony.data_format = HARMONY_DF_8BIT_ULAW;
+				break;
+			case HARMONY_MAGIC_8B_ALAW:
+				harmony.data_format = HARMONY_DF_8BIT_ALAW;
+				break;
+			case HARMONY_MAGIC_16B_LINEAR:
+				harmony.data_format = HARMONY_DF_16BIT_LINEAR;
+				break;
+			default:
+				harmony_set_control(HARMONY_DF_16BIT_LINEAR,
+						HARMONY_SR_44KHZ, HARMONY_SS_STEREO);
+				return;
+			}
+			switch (nb_voices) {
+			case HARMONY_MAGIC_MONO:
+				harmony.stereo_select = HARMONY_SS_MONO;
+				break;
+			case HARMONY_MAGIC_STEREO:
+				harmony.stereo_select = HARMONY_SS_STEREO;
+				break;
+			default:
+				harmony.stereo_select = HARMONY_SS_MONO;
+				break;
+			}
+			harmony_set_rate(harmony_detect_rate(&speed));
+			harmony.dac_rate = speed;
+			return;			
+		}
+	}
+	harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO);
+}
+#undef four_bytes_to_u32
+
+
+static ssize_t harmony_audio_write(struct file *file,
+                                 const char *buffer,
+                                 size_t size_count,
+                                 loff_t *ppos)
+{
+	int total_count = (int) size_count;
+	int count = 0;
+	int frame_size;
+	int buf_to_fill;
+
+	if (!harmony.format_initialized) 
+	   harmony_format_auto_detect(buffer, total_count);
+	
+	while (count<total_count) {
+		/* Wait until we're out of control mode */
+		harmony_wait_CNTL();
+
+		/* Figure out which buffer to fill in */
+		if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset) {
+			harmony.blocked_playing = 1;
+			interruptible_sleep_on(&harmony.wq_play);
+			harmony.blocked_playing = 0;
+		}
+		if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset)
+			return -EBUSY;
+		
+		
+		buf_to_fill = (harmony.first_filled_play+harmony.nb_filled_play); 
+		if (harmony.play_offset)
+			buf_to_fill--;
+		buf_to_fill %= MAX_BUFS;
+
+		/* Figure out the size of the frame */
+		if ((total_count-count) > HARMONY_BUF_SIZE - harmony.play_offset) {
+			frame_size = HARMONY_BUF_SIZE - harmony.play_offset;
+		} else {
+			frame_size = total_count - count;
+			/* Clear out the buffer, since there we'll only be 
+			   overlaying part of the old buffer with the new one */
+			harmony_silence(&played_buf, 
+				HARMONY_BUF_SIZE*buf_to_fill+frame_size+harmony.play_offset,
+				HARMONY_BUF_SIZE-frame_size-harmony.play_offset);
+		}
+
+		/* Copy the page to an aligned buffer */
+		copy_from_user(played_buf.addr + (HARMONY_BUF_SIZE*buf_to_fill) + harmony.play_offset, 
+				buffer+count, frame_size);
+		CHECK_WBACK_INV_OFFSET(played_buf, (HARMONY_BUF_SIZE*buf_to_fill + harmony.play_offset), 
+				frame_size);
+	
+		if (!harmony.play_offset)
+			harmony.nb_filled_play++;
+		
+		count += frame_size;
+		harmony.play_offset += frame_size;
+		harmony.play_offset %= HARMONY_BUF_SIZE;
+		if (harmony.suspended_playing && (harmony.nb_filled_play>=4))
+			harmony_enable_interrupts();
+	}
+	
+	return count;
+}
+
+static unsigned int harmony_audio_poll(struct file *file,
+                                     struct poll_table_struct *wait)
+{
+	unsigned int mask = 0;
+	
+	if (file->f_mode & FMODE_READ) {
+		if (!harmony.suspended_recording)
+			poll_wait(file, &harmony.wq_record, wait);
+		if (harmony.nb_filled_record)
+			mask |= POLLIN | POLLRDNORM;
+	}
+
+	if (file->f_mode & FMODE_WRITE) {
+		if (!harmony.suspended_playing)
+			poll_wait(file, &harmony.wq_play, wait);
+		if (harmony.nb_filled_play)
+			mask |= POLLOUT | POLLWRNORM;
+	}
+
+	return mask;
+}
+
+static int harmony_audio_ioctl(struct inode *inode,
+                                struct file *file,
+				unsigned int cmd,
+                                unsigned long arg)
+{
+	int ival, new_format;
+	int frag_size, frag_buf;
+	struct audio_buf_info info;
+	
+	switch (cmd) {
+	case OSS_GETVERSION:
+		return put_user(SOUND_VERSION, (int *) arg);
+
+	case SNDCTL_DSP_GETCAPS:
+		ival = DSP_CAP_DUPLEX;
+		return put_user(ival, (int *) arg);
+
+	case SNDCTL_DSP_GETFMTS:
+		ival = (AFMT_S16_BE | AFMT_MU_LAW | AFMT_A_LAW ); 
+		return put_user(ival, (int *) arg);
+	
+	case SNDCTL_DSP_SETFMT:
+		if (get_user(ival, (int *) arg)) 
+			return -EFAULT;
+		if (ival != AFMT_QUERY) {
+			switch (ival) {
+			case AFMT_MU_LAW:	new_format = HARMONY_DF_8BIT_ULAW; break;
+			case AFMT_A_LAW:	new_format = HARMONY_DF_8BIT_ALAW; break;
+			case AFMT_S16_LE:	/* fall through, but not really supported */
+			case AFMT_S16_BE:	new_format = HARMONY_DF_16BIT_LINEAR;
+						ival = AFMT_S16_BE;
+						break; 
+			default: {
+				DPRINTK(KERN_WARNING PFX 
+					"unsupported sound format 0x%04x requested.\n",
+					ival);
+				return -EINVAL;
+			}
+			}
+			harmony_set_format(new_format);
+		} else {
+			switch (harmony.data_format) {
+			case HARMONY_DF_8BIT_ULAW:	ival = AFMT_MU_LAW; break;
+			case HARMONY_DF_8BIT_ALAW:	ival = AFMT_A_LAW;  break;
+			case HARMONY_DF_16BIT_LINEAR:	ival = AFMT_U16_BE; break;
+			default: ival = 0;
+			}
+		}
+		return put_user(ival, (int *) arg);
+
+	case SOUND_PCM_READ_RATE:
+		ival = harmony.dac_rate;
+		return put_user(ival, (int *) arg);
+
+	case SNDCTL_DSP_SPEED:
+		if (get_user(ival, (int *) arg))
+			return -EFAULT;
+		harmony_set_rate(harmony_detect_rate(&ival));
+		harmony.dac_rate = ival;
+		return put_user(ival, (int*) arg);
+
+	case SNDCTL_DSP_STEREO:
+		if (get_user(ival, (int *) arg))
+			return -EFAULT;
+		if (ival != 0 && ival != 1)
+			return -EINVAL;
+		harmony_set_stereo(ival);
+		return put_user(ival, (int *) arg);
+
+	case SNDCTL_DSP_GETBLKSIZE:
+		ival = HARMONY_BUF_SIZE;
+		return put_user(ival, (int *) arg);
+		
+        case SNDCTL_DSP_NONBLOCK:
+                file->f_flags |= O_NONBLOCK;
+                return 0;
+
+        case SNDCTL_DSP_RESET:
+		if (!harmony.suspended_recording) {
+			/* TODO: stop_recording() */
+		}
+		return 0;
+
+	case SNDCTL_DSP_SETFRAGMENT:
+		if (get_user(ival, (int *)arg))
+			return -EFAULT;
+		frag_size = ival & 0xffff;
+		frag_buf = (ival>>16) & 0xffff;
+		/* TODO: We use hardcoded fragment sizes and numbers for now */
+		frag_size = 12;  /* 4096 == 2^12 */
+		frag_buf  = MAX_BUFS;
+		ival = (frag_buf << 16) + frag_size;
+		return put_user(ival, (int *) arg);
+		
+	case SNDCTL_DSP_GETOSPACE:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		info.fragstotal = MAX_BUFS;
+                info.fragments = MAX_BUFS - harmony.nb_filled_play;
+		info.fragsize = HARMONY_BUF_SIZE;
+                info.bytes = info.fragments * info.fragsize;
+		return copy_to_user((void *)arg, &info, sizeof(info));
+
+	case SNDCTL_DSP_GETISPACE:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		info.fragstotal = MAX_BUFS;
+                info.fragments = /*MAX_BUFS-*/ harmony.nb_filled_record;
+		info.fragsize = HARMONY_BUF_SIZE;
+                info.bytes = info.fragments * info.fragsize;
+		return copy_to_user((void *)arg, &info, sizeof(info));
+	
+	case SNDCTL_DSP_SYNC:
+		return 0;
+	}
+	
+	return -EINVAL;
+}
+
+
+/*
+ * harmony_interrupt()
+ *
+ * harmony interruption service routine
+ * 
+ */
+
+static void harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+	u32 dstatus;
+	struct harmony_hpa *hpa;
+
+	/* Setup the hpa */
+	hpa = ((struct harmony_dev *)dev)->hpa;
+	harmony_wait_CNTL();
+
+	/* Read dstatus and pcuradd (the current address) */
+	dstatus = gsc_readl(&hpa->dstatus);
+	
+	/* Turn off interrupts */
+	harmony_disable_interrupts();
+	
+	/* Check if this is a request to get the next play buffer */
+	if (dstatus & DSTATUS_PN) {
+		if (!harmony.nb_filled_play) {
+			harmony.suspended_playing = 1;
+			gsc_writel((unsigned long)silent.dma_handle, &hpa->pnxtadd);
+						
+			if (!harmony.suspended_recording)
+				harmony_enable_interrupts();
+		} else {
+			harmony.suspended_playing = 0;
+			gsc_writel((unsigned long)played_buf.dma_handle + 
+					(HARMONY_BUF_SIZE*harmony.first_filled_play),
+					&hpa->pnxtadd);
+			harmony.first_filled_play++;
+			harmony.first_filled_play %= MAX_BUFS;
+			harmony.nb_filled_play--;
+			
+		       	harmony_enable_interrupts();
+		}
+		
+		if (harmony.blocked_playing)
+			wake_up_interruptible(&harmony.wq_play);
+	}
+	
+	/* Check if we're being asked to fill in a recording buffer */
+	if (dstatus & DSTATUS_RN) {
+		if((harmony.nb_filled_record+2>=MAX_BUFS) || harmony.suspended_recording)
+		{
+			harmony.nb_filled_record = 0;
+			harmony.first_filled_record = 0;
+			harmony.suspended_recording = 1;
+			gsc_writel((unsigned long)graveyard.dma_handle, &hpa->rnxtadd);
+			if (!harmony.suspended_playing)
+				harmony_enable_interrupts();
+		} else {
+			int buf_to_fill;
+			buf_to_fill = (harmony.first_filled_record+harmony.nb_filled_record) % MAX_BUFS;
+			CHECK_WBACK_INV_OFFSET(recorded_buf, HARMONY_BUF_SIZE*buf_to_fill, HARMONY_BUF_SIZE);
+			gsc_writel((unsigned long)recorded_buf.dma_handle +
+					HARMONY_BUF_SIZE*buf_to_fill,
+					&hpa->rnxtadd);
+			harmony.nb_filled_record++;
+			harmony_enable_interrupts();
+		}
+
+		if (harmony.blocked_recording && harmony.nb_filled_record>3)
+			wake_up_interruptible(&harmony.wq_record);
+	}
+}
+
+/*
+ * Sound playing functions
+ */
+
+static struct file_operations harmony_audio_fops = {
+	owner:	THIS_MODULE,
+	llseek:	no_llseek,
+	read: 	harmony_audio_read,
+	write:	harmony_audio_write,
+	poll: 	harmony_audio_poll,
+	ioctl: 	harmony_audio_ioctl,
+	open: 	harmony_audio_open,
+	release:harmony_audio_release,
+};
+
+static int harmony_audio_init(void)
+{
+	/* Request that IRQ */
+	if (request_irq(harmony.irq, harmony_interrupt, 0 ,"harmony", &harmony)) {
+		printk(KERN_ERR PFX "Error requesting irq %d.\n", harmony.irq);
+		return -EFAULT;
+	}
+
+   	harmony.dsp_unit = register_sound_dsp(&harmony_audio_fops, -1);
+	if (harmony.dsp_unit < 0) {
+		printk(KERN_ERR PFX "Error registering dsp\n");
+		free_irq(harmony.irq, &harmony);
+		return -EFAULT;
+	}
+	
+	/* Clear the buffers so you don't end up with crap in the buffers. */ 
+	harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
+
+	/* Make sure this makes it to cache */
+	CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
+
+	/* Clear out the silent buffer and flush to cache */
+	harmony_silence(&silent, 0, HARMONY_BUF_SIZE);
+	CHECK_WBACK_INV_OFFSET(silent, 0, HARMONY_BUF_SIZE);
+	
+	harmony.audio_open = 0;
+	
+	return 0;
+}
+
+
+/*
+ * mixer functions 
+ */
+
+static void harmony_mixer_set_gain(void)
+{
+	harmony_wait_CNTL();
+	gsc_writel(harmony.current_gain, &harmony.hpa->gainctl);
+}
+
+/* 
+ *  Read gain of selected channel.
+ *  The OSS rate is from 0 (silent) to 100 -> need some conversions
+ *
+ *  The harmony gain are attenuation for output and monitor gain.
+ *                   is amplifaction for input gain
+ */
+#define to_harmony_level(level,max) ((level)*max/100)
+#define to_oss_level(level,max) ((level)*100/max)
+
+static int harmony_mixer_get_level(int channel)
+{
+	int left_level;
+	int right_level;
+
+	switch (channel) {
+		case SOUND_MIXER_OGAIN:
+			left_level  = (harmony.current_gain & GAIN_LO_MASK) >> GAIN_LO_SHIFT;
+			right_level = (harmony.current_gain & GAIN_RO_MASK) >> GAIN_RO_SHIFT;
+			left_level  = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL);
+			right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL);
+			return (right_level << 8)+left_level;
+			
+		case SOUND_MIXER_IGAIN:
+			left_level = (harmony.current_gain & GAIN_LI_MASK) >> GAIN_LI_SHIFT;
+			right_level= (harmony.current_gain & GAIN_RI_MASK) >> GAIN_RI_SHIFT;
+			left_level = to_oss_level(left_level, MAX_INPUT_LEVEL);
+			right_level= to_oss_level(right_level, MAX_INPUT_LEVEL);
+			return (right_level << 8)+left_level;
+			
+		case SOUND_MIXER_VOLUME:
+			left_level = (harmony.current_gain & GAIN_MA_MASK) >> GAIN_MA_SHIFT;
+			left_level = to_oss_level(MAX_VOLUME_LEVEL-left_level, MAX_VOLUME_LEVEL);
+			return left_level;
+	}
+	return -EINVAL;
+}
+
+
+
+/*
+ * Some conversions for the same reasons.
+ * We give back the new real value(s) due to
+ * the rescale.
+ */
+
+static int harmony_mixer_set_level(int channel, int value)
+{
+	int left_level;
+	int right_level;
+	int new_left_level;
+	int new_right_level;
+
+	right_level = (value & 0x0000ff00) >> 8;
+	left_level = value & 0x000000ff;
+  
+	switch (channel) {
+		case SOUND_MIXER_OGAIN:
+			right_level = to_harmony_level(100-right_level, MAX_OUTPUT_LEVEL);
+			left_level  = to_harmony_level(100-left_level, MAX_OUTPUT_LEVEL);
+			new_right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL);
+			new_left_level  = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL);
+			harmony.current_gain = (harmony.current_gain & ~(GAIN_LO_MASK | GAIN_RO_MASK)) 
+					| (left_level << GAIN_LO_SHIFT) | (right_level << GAIN_RO_SHIFT);
+			harmony_mixer_set_gain();
+			return (new_right_level << 8) + new_left_level;
+			
+		case SOUND_MIXER_IGAIN:
+			right_level = to_harmony_level(right_level, MAX_INPUT_LEVEL);
+			left_level  = to_harmony_level(left_level, MAX_INPUT_LEVEL);
+			new_right_level = to_oss_level(right_level, MAX_INPUT_LEVEL);
+			new_left_level  = to_oss_level(left_level, MAX_INPUT_LEVEL);
+			harmony.current_gain = (harmony.current_gain & ~(GAIN_LI_MASK | GAIN_RI_MASK))
+					| (left_level << GAIN_LI_SHIFT) | (right_level << GAIN_RI_SHIFT);
+			harmony_mixer_set_gain();
+			return (new_right_level << 8) + new_left_level;
+	
+		case SOUND_MIXER_VOLUME:
+			left_level = to_harmony_level(100-left_level, MAX_VOLUME_LEVEL);
+			new_left_level = to_oss_level(MAX_VOLUME_LEVEL-left_level, MAX_VOLUME_LEVEL);
+			harmony.current_gain = (harmony.current_gain & ~GAIN_MA_MASK)| (left_level << GAIN_MA_SHIFT);
+			harmony_mixer_set_gain();
+			return new_left_level;
+	}
+
+	return -EINVAL;
+}
+
+#undef to_harmony_level
+#undef to_oss_level
+
+/* 
+ * Return the selected input device (mic or line)
+ */
+
+static int harmony_mixer_get_recmask(void) 
+{
+	int current_input_line;
+	
+	current_input_line = (harmony.current_gain & GAIN_IS_MASK) 
+				    >> GAIN_IS_SHIFT;
+	if (current_input_line) 
+		return SOUND_MASK_MIC;
+
+	return SOUND_MASK_LINE;
+}
+
+/*
+ * Set the input (only one at time, arbitrary priority to line in)
+ */
+
+static int harmony_mixer_set_recmask(int recmask)
+{
+	int new_input_line;
+	int new_input_mask;
+
+	if ((recmask & SOUND_MASK_LINE)) {
+		new_input_line = 0;
+		new_input_mask = SOUND_MASK_LINE;
+	} else  {
+		new_input_line = 1;
+		new_input_mask = SOUND_MASK_MIC;
+	}
+	harmony.current_gain = ((harmony.current_gain & ~GAIN_IS_MASK) | 
+				(new_input_line << GAIN_IS_SHIFT ));
+	harmony_mixer_set_gain();
+	return new_input_mask;
+}
+
+
+/* 
+ * give the active outlines
+ */
+
+static int harmony_mixer_get_outmask(void)
+{
+	int outmask = 0;
+	
+	if (harmony.current_gain & GAIN_HE_MASK) outmask |=SOUND_MASK_PHONEOUT;
+	if (harmony.current_gain & GAIN_LE_MASK) outmask |=SOUND_MASK_LINE;
+	if (harmony.current_gain & GAIN_SE_MASK) outmask |=SOUND_MASK_SPEAKER;
+	
+	return outmask;
+}
+
+
+static int harmony_mixer_set_outmask(int outmask)
+{
+	if (outmask & SOUND_MASK_PHONEOUT) 
+		harmony.current_gain |= GAIN_HE_MASK; 
+	else 
+		harmony.current_gain &= ~GAIN_HE_MASK;
+	
+	if (outmask & SOUND_MASK_LINE) 
+		harmony.current_gain |= GAIN_LE_MASK;
+	else 
+		harmony.current_gain &= ~GAIN_LE_MASK;
+	
+	if (outmask & SOUND_MASK_SPEAKER) 
+		harmony.current_gain |= GAIN_SE_MASK;
+	else 
+		harmony.current_gain &= ~GAIN_SE_MASK;
+	
+	harmony_mixer_set_gain();
+
+	return (outmask & (SOUND_MASK_PHONEOUT | SOUND_MASK_LINE | SOUND_MASK_SPEAKER));
+}
+
+/*
+ * This code is inspired from sb_mixer.c
+ */
+
+static int harmony_mixer_ioctl(struct inode * inode, struct file * file,
+		unsigned int cmd, unsigned long arg)
+{
+	int val;
+	int ret;
+
+	if (cmd == SOUND_MIXER_INFO) {
+		mixer_info info;
+		memset(&info, 0, sizeof(info));
+                strncpy(info.id, "harmony", sizeof(info.id)-1);
+                strncpy(info.name, "Harmony audio", sizeof(info.name)-1);
+                info.modify_counter = 1; /* ? */
+                if (copy_to_user((void *)arg, &info, sizeof(info)))
+                        return -EFAULT;
+		return 0;
+	}
+	
+	if (cmd == OSS_GETVERSION)
+		return put_user(SOUND_VERSION, (int *)arg);
+
+	/* read */
+	val = 0;
+	if (_SIOC_DIR(cmd) & _SIOC_WRITE)
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+
+	switch (cmd) {
+	case MIXER_READ(SOUND_MIXER_CAPS):
+		ret = SOUND_CAP_EXCL_INPUT;
+		break;
+	case MIXER_READ(SOUND_MIXER_STEREODEVS):
+		ret = SOUND_MASK_IGAIN | SOUND_MASK_OGAIN;
+		break;
+		
+	case MIXER_READ(SOUND_MIXER_RECMASK):
+		ret = SOUND_MASK_MIC | SOUND_MASK_LINE;
+		break;
+	case MIXER_READ(SOUND_MIXER_DEVMASK):
+		ret = SOUND_MASK_OGAIN | SOUND_MASK_IGAIN |
+			SOUND_MASK_VOLUME;
+		break;
+	case MIXER_READ(SOUND_MIXER_OUTMASK):
+		ret = SOUND_MASK_SPEAKER | SOUND_MASK_LINE |
+			SOUND_MASK_PHONEOUT;
+		break;
+		
+	case MIXER_WRITE(SOUND_MIXER_RECSRC):
+		ret = harmony_mixer_set_recmask(val);
+		break;
+	case MIXER_READ(SOUND_MIXER_RECSRC):
+		ret = harmony_mixer_get_recmask();
+		break;
+	      
+	case MIXER_WRITE(SOUND_MIXER_OUTSRC):
+		ret = harmony_mixer_set_outmask(val);
+		break;
+	case MIXER_READ(SOUND_MIXER_OUTSRC):
+		ret = harmony_mixer_get_outmask();
+		break;
+	
+	case MIXER_WRITE(SOUND_MIXER_OGAIN):
+	case MIXER_WRITE(SOUND_MIXER_IGAIN):
+	case MIXER_WRITE(SOUND_MIXER_VOLUME):
+		ret = harmony_mixer_set_level(cmd & 0xff, val);
+		break;
+
+	case MIXER_READ(SOUND_MIXER_OGAIN):
+	case MIXER_READ(SOUND_MIXER_IGAIN):
+	case MIXER_READ(SOUND_MIXER_VOLUME):
+		ret = harmony_mixer_get_level(cmd & 0xff);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (put_user(ret, (int *)arg))
+		return -EFAULT;
+	return 0;
+}
+
+
+static int harmony_mixer_open(struct inode *inode, struct file *file)
+{
+	if (harmony.mixer_open) 
+		return -EBUSY;
+	harmony.mixer_open++;
+	return 0;
+}
+
+static int harmony_mixer_release(struct inode *inode, struct file *file)
+{
+	if (!harmony.mixer_open) 
+		return -EBUSY;
+	harmony.mixer_open--;
+	return 0;
+}
+
+static struct file_operations harmony_mixer_fops = {
+	owner:		THIS_MODULE,
+	llseek:		no_llseek,
+	open:		harmony_mixer_open,
+	release:	harmony_mixer_release,
+	ioctl:		harmony_mixer_ioctl,
+};
+
+
+/*
+ * Mute all the output and reset Harmony.
+ */
+
+static void __init harmony_mixer_reset(void)
+{
+	harmony.current_gain = GAIN_TOTAL_SILENCE;
+	harmony_mixer_set_gain();
+	harmony_wait_CNTL();
+	gsc_writel(1, &harmony.hpa->reset);
+	mdelay(50);		/* wait 50 ms */
+	gsc_writel(0, &harmony.hpa->reset);
+	harmony.current_gain = GAIN_DEFAULT;
+	harmony_mixer_set_gain();
+}
+
+static int __init harmony_mixer_init(void)
+{
+	/* Register the device file operations */
+	harmony.mixer_unit = register_sound_mixer(&harmony_mixer_fops, -1);
+	if (harmony.mixer_unit < 0) {
+		printk(KERN_WARNING PFX "Error Registering Mixer Driver\n");
+		return -EFAULT;
+	}
+  
+	harmony_mixer_reset();
+	harmony.mixer_open = 0;
+	
+	return 0;
+}
+
+
+
+/* 
+ * This is the callback that's called by the inventory hardware code 
+ * if it finds a match to the registered driver. 
+ */
+static int __init
+harmony_driver_callback(struct parisc_device *dev)
+{
+	u8	id;
+	u8	rev;
+	u32	cntl;
+	int	ret;
+
+	if (harmony.hpa) {
+		/* We only support one Harmony at this time */
+		printk(KERN_ERR PFX "driver already registered\n");
+		return -EBUSY;
+	}
+
+	/* Set the HPA of harmony */
+	harmony.hpa = (struct harmony_hpa *)dev->hpa;
+
+	harmony.irq = dev->irq;
+	if (!harmony.irq) {
+		printk(KERN_ERR PFX "no irq found\n");
+		return -ENODEV;
+	}
+
+	/* Grab the ID and revision from the device */
+	id = gsc_readb(&harmony.hpa->id);
+	if ((id | 1) != 0x15) {
+		printk(KERN_WARNING PFX "wrong harmony id 0x%02x\n", id);
+		return -EBUSY;
+	}
+	cntl = gsc_readl(&harmony.hpa->cntl);
+	rev = (cntl>>20) & 0xff;
+
+	printk(KERN_INFO "Lasi Harmony Audio driver " HARMONY_VERSION ", "
+			"h/w id %i, rev. %i at 0x%lx, IRQ %i\n",
+			id, rev, dev->hpa, harmony.irq);
+	
+	/* Make sure the control bit isn't set, although I don't think it 
+	   ever is. */
+	if (cntl & CNTL_C) {
+		printk(KERN_WARNING PFX "CNTL busy\n");
+		harmony.hpa = 0;
+		return -EBUSY;
+	}
+
+	/* a fake pci_dev is needed for pci_* functions under ccio */
+	harmony.fake_pci_dev = ccio_get_fake(dev);
+	
+	/* Initialize the memory buffers */
+	if (harmony_alloc_buffer(&played_buf, MAX_BUFS) || 
+	    harmony_alloc_buffer(&recorded_buf, MAX_BUFS) ||
+	    harmony_alloc_buffer(&graveyard, 1) ||
+	    harmony_alloc_buffer(&silent, 1)) {
+		ret = -EBUSY;
+		goto out_err;
+	}
+
+	/* Initialize /dev/mixer and /dev/audio  */
+	if ((ret=harmony_mixer_init())) 
+		goto out_err;
+	if ((ret=harmony_audio_init())) 
+		goto out_err;
+
+	return 0;
+
+out_err:
+	harmony.hpa = 0;
+	harmony_free_buffer(&played_buf);
+	harmony_free_buffer(&recorded_buf);
+	harmony_free_buffer(&graveyard);
+	harmony_free_buffer(&silent);
+	return ret;
+}
+
+
+static struct parisc_device_id harmony_tbl[] = {
+ /* { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007A }, Bushmaster/Flounder */
+ { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007B }, /* 712/715 Audio */
+ { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007E }, /* Pace Audio */
+ { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007F }, /* Outfield / Coral II */
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, harmony_tbl);
+
+static struct parisc_driver harmony_driver = {
+	name:		"Lasi Harmony",
+	id_table:	harmony_tbl,
+	probe:		harmony_driver_callback,
+};
+
+static int __init init_harmony(void)
+{
+	return register_parisc_driver(&harmony_driver);
+}
+
+static void __exit cleanup_harmony(void)
+{
+	free_irq(harmony.irq, &harmony);
+	unregister_sound_mixer(harmony.mixer_unit);
+	unregister_sound_dsp(harmony.dsp_unit);
+	harmony_free_buffer(&played_buf);
+	harmony_free_buffer(&recorded_buf);
+	harmony_free_buffer(&graveyard);
+	harmony_free_buffer(&silent);
+	unregister_parisc_driver(&harmony_driver);
+}
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR("Alex DeVries <alex@linuxcare.com>");
+MODULE_DESCRIPTION("Harmony sound driver");
+MODULE_LICENSE("GPL");
+
+module_init(init_harmony);
+module_exit(cleanup_harmony);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/i810_audio.c linux-2.4.20/drivers/sound/i810_audio.c
--- linux-2.4.19/drivers/sound/i810_audio.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/sound/i810_audio.c	2002-10-29 11:18:49.000000000 +0000
@@ -239,7 +239,8 @@
 	INTELICH4,
 	SI7012,
 	NVIDIA_NFORCE,
-	AMD768
+	AMD768,
+	AMD8111
 };
 
 static char * card_names[] = {
@@ -251,7 +252,8 @@
 	"Intel ICH4",
 	"SiS 7012",
 	"NVIDIA nForce Audio",
-	"AMD 768"
+	"AMD 768",
+	"AMD-8111 IOHub"
 };
 
 static struct pci_device_id i810_pci_tbl [] __initdata = {
@@ -273,6 +275,8 @@
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
 	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_768_AUDIO,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD768},
+	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_AC97,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD8111},
 	{0,}
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/maestro3.c linux-2.4.20/drivers/sound/maestro3.c
--- linux-2.4.19/drivers/sound/maestro3.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/sound/maestro3.c	2002-10-29 11:18:49.000000000 +0000
@@ -28,6 +28,9 @@
  * Shouts go out to Mike "DJ XPCom" Ang.
  *
  * History
+ *  v1.23 - Jun 5 2002 - Michael Olson <olson@cs.odu.edu>
+ *   added a module option to allow selection of GPIO pin number 
+ *   for external amp 
  *  v1.22 - Feb 28 2001 - Zach Brown <zab@zabbo.net>
  *   allocate mem at insmod/setup, rather than open
  *   limit pci dma addresses to 28bit, thanks guys.
@@ -153,7 +156,7 @@
 
 #define M_DEBUG 1
 
-#define DRIVER_VERSION      "1.22"
+#define DRIVER_VERSION      "1.23"
 #define M3_MODULE_NAME      "maestro3"
 #define PFX                 M3_MODULE_NAME ": "
 
@@ -190,6 +193,7 @@
 };
 
 int external_amp = 1;
+int gpio_pin = -1;
 
 struct m3_state {
     unsigned int magic;
@@ -2469,14 +2473,20 @@
     if(!external_amp)
         return;
 
-    switch (card->card_type) {
-        case ESS_ALLEGRO:
-            polarity_port = 0x1800;
-            break;
-        default:
-            /* presumably this is for all 'maestro3's.. */
-            polarity_port = 0x1100;
-            break;
+    if (gpio_pin >= 0  && gpio_pin <= 15) {
+        polarity_port = 0x1000 + (0x100 * gpio_pin);
+    } else {
+        switch (card->card_type) {
+            case ESS_ALLEGRO:
+                polarity_port = 0x1800;
+                break;
+            default:
+                polarity_port = 0x1100;
+                /* Panasonic toughbook CF72 has to be different... */
+                if(card->pcidev->subsystem_vendor == 0x10F7 && card->pcidev->subsystem_device == 0x833D)
+                	polarity_port = 0x1D00;
+                break;
+        }
     }
 
     gpo = (polarity_port >> 8) & 0x0F;
@@ -2911,6 +2921,7 @@
 MODULE_PARM(debug,"i");
 #endif
 MODULE_PARM(external_amp,"i");
+MODULE_PARM(gpio_pin, "i");
 
 static struct pci_driver m3_pci_driver = {
     name:       "ess_m3_audio",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/pss.c linux-2.4.20/drivers/sound/pss.c
--- linux-2.4.19/drivers/sound/pss.c	2002-02-25 19:38:06.000000000 +0000
+++ linux-2.4.20/drivers/sound/pss.c	2002-10-29 11:18:48.000000000 +0000
@@ -1131,7 +1131,7 @@
 MODULE_PARM(pss_mixer, "b");
 MODULE_PARM_DESC(pss_mixer, "Enable (1) or disable (0) PSS mixer (controlling of output volume, bass, treble, synth volume). The mixer is not available on all PSS cards.");
 MODULE_AUTHOR("Hannu Savolainen, Vladimir Michl");
-MODULE_DESCRIPTION("Module for PSS sound cards (based on AD1848, ADSP-2115 and ESC614). This module includes control of output amplifier and synth volume of the Beethoven ADSP-16 card (this may work with other PSS cards).\n");
+MODULE_DESCRIPTION("Module for PSS sound cards (based on AD1848, ADSP-2115 and ESC614). This module includes control of output amplifier and synth volume of the Beethoven ADSP-16 card (this may work with other PSS cards).");
 MODULE_LICENSE("GPL");
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/swarm_cs4297a.c linux-2.4.20/drivers/sound/swarm_cs4297a.c
--- linux-2.4.19/drivers/sound/swarm_cs4297a.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/sound/swarm_cs4297a.c	2002-10-29 11:18:40.000000000 +0000
@@ -200,9 +200,6 @@
         }                                          \
 })
 
-#define list_for_each(pos, head) \
-        for (pos = (head)->next; pos != (head); pos = pos->next)
-
 struct list_head cs4297a_devs = { &cs4297a_devs, &cs4297a_devs };
 
 typedef struct serdma_descr_s {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/trident.c linux-2.4.20/drivers/sound/trident.c
--- linux-2.4.19/drivers/sound/trident.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/sound/trident.c	2002-10-29 11:18:49.000000000 +0000
@@ -36,6 +36,41 @@
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  *  History
+ *  v0.14.10h
+ *	Sept 10 2002 Pascal Schmidt <der.eremit@email.de>
+ *	added support for ALi 5451 joystick port
+ *  v0.14.10g
+ *	Sept 05 2002 Alan Cox <alan@redhat.com>
+ *	adapt to new pci joystick attachment interface
+ *  v0.14.10f
+ *      July 24 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
+ *      patch from Eric Lemar (via Ian Soboroff): in suspend and resume, 
+ *      fix wrong cast from pci_dev* to struct trident_card*. 
+ *  v0.14.10e
+ *      July 19 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
+ *      rewrite the DMA buffer allocation/deallcoation functions, to make it 
+ *      modular and fix a bug where we would call free_pages on memory 
+ *      obtained with pci_alloc_consistent. Also remove unnecessary #ifdef 
+ *      CONFIG_PROC_FS and various other cleanups.
+ *  v0.14.10d
+ *      July 19 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
+ *      made several printk(KERN_NOTICE...) into TRDBG(...), to avoid spamming
+ *      my syslog with hundreds of messages. 
+ *  v0.14.10c
+ *      July 16 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
+ *      Cleaned up Lei Hu's 0.4.10 driver to conform to Documentation/CodingStyle
+ *      and the coding style used in the rest of the file. 
+ *  v0.14.10b
+ *      June 23 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
+ *      add a missing unlock_set_fmt, remove a superflous lock/unlock pair 
+ *      with nothing in between. 
+ *  v0.14.10a
+ *      June 21 2002 Muli Ben-Yehuda <mulix@actcom.co.il> 
+ *      use a debug macro instead of #ifdef CONFIG_DEBUG, trim to 80 columns 
+ *      per line, use 'do {} while (0)' in statement macros. 
+ *  v0.14.10
+ *      June 6 2002 Lei Hu <Lei_hu@ali.com.tw>
+ *      rewrite the part to read/write registers of audio codec for Ali5451 
  *  v0.14.9d
  *  	October 8 2001 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  *	use set_current_state, properly release resources on failure in
@@ -46,7 +81,7 @@
  *	this chip is often found in settop boxes (combined video+audio)
  *  v0.14.9b
  *	Switch to static inline not extern inline (gcc 3)
- *  v0.14.9a
+ *  v0.14.9a 
  *	Aug 6 2001 Alan Cox
  *	0.14.9 crashed on rmmod due to a timer/bh left running. Simplified
  *	the existing logic (the BH doesnt help as ac97 is lock_irqsave)
@@ -158,19 +193,22 @@
 #include <linux/slab.h>
 #include <linux/soundcard.h>
 #include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
 #include <linux/ac97_codec.h>
 #include <linux/wrapper.h>
-#include <asm/uaccess.h>
-#include <asm/hardirq.h>
 #include <linux/bitops.h>
 #include <linux/proc_fs.h>
 #include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/gameport.h>
+#include <linux/pci_gameport.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+#include <asm/io.h>
+#include <asm/dma.h>
 
 #if defined CONFIG_ALPHA_NAUTILUS || CONFIG_ALPHA_GENERIC
 #include <asm/hwrpb.h>
@@ -178,9 +216,7 @@
 
 #include "trident.h"
 
-#include <linux/pm.h>
-
-#define DRIVER_VERSION "0.14.9d"
+#define DRIVER_VERSION "0.14.10h"
 
 /* magic numbers to protect our data structures */
 #define TRIDENT_CARD_MAGIC	0x5072696E /* "Prin" */
@@ -198,7 +234,13 @@
 /* minor number of /dev/swmodem (temporary, experimental) */
 #define SND_DEV_SWMODEM	7
 
-static const unsigned ali_multi_channels_5_1[] = { /*ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL,*/ ALI_CENTER_CHANNEL, ALI_LEF_CHANNEL, ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL};
+static const unsigned ali_multi_channels_5_1[] = { 
+	/*ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL,*/
+	ALI_CENTER_CHANNEL, 
+	ALI_LEF_CHANNEL, 
+	ALI_SURR_LEFT_CHANNEL, 
+	ALI_SURR_RIGHT_CHANNEL
+};
 
 static const unsigned sample_size[] = { 1, 2, 2, 4 };
 static const unsigned sample_shift[] = { 0, 1, 1, 2 };
@@ -288,7 +330,7 @@
 		
 	} dmabuf;
 
-	/* 5.1channels */	
+	/* 5.1 channels */	
 	struct trident_state *other_states[4];
 	int multi_channels_adjust_count;
 	unsigned chans_num;
@@ -315,6 +357,7 @@
 	u32 aint;
 	u32 aint_en;
 };
+
 static struct trident_pcm_bank_address bank_a_addrs =
 {
 	T4D_START_A,
@@ -322,6 +365,7 @@
 	T4D_AINT_A,
 	T4D_AINTEN_A
 };
+
 static struct trident_pcm_bank_address bank_b_addrs =
 {
 	T4D_START_B,
@@ -329,6 +373,7 @@
 	T4D_AINT_B,
 	T4D_AINTEN_B
 };
+
 struct trident_pcm_bank {
 	/* register addresses to control bank operations */
 	struct trident_pcm_bank_address *addresses;
@@ -382,6 +427,8 @@
 	/* Added for hardware volume control */
 	int hwvolctl;
 	struct timer_list timer;
+
+	struct pcigame *joystick;	/* joystick device */
 };
 
 /* table to map from CHANNELMASK to channel attribute for SiS 7018 */
@@ -391,6 +438,7 @@
 	HSET, MIC, MODEM_LINE1, MODEM_LINE2,
 	I2S_LR, SPDIF_LR
 };
+
 /* table to map from channel attribute to CHANNELMASK for SiS 7018 */
 static int attr2mask [] = {
 	DSP_BIND_MODEM1, DSP_BIND_MODEM2, DSP_BIND_FRONT, DSP_BIND_HANDSET,
@@ -399,7 +447,7 @@
 
 /* Added by Matt Wu 01-05-2001 for spdif in */
 static int ali_close_multi_channels(void);
-static void ali_delay(struct trident_card *card,int interval);
+static void ali_delay(struct trident_card *card, int interval);
 static void ali_detect_spdif_rate(struct trident_card *card);
 
 static void ali_ac97_write(struct ac97_codec *codec, u8 reg, u16 val);
@@ -431,8 +479,11 @@
 static void ali_disable_spdif_in(struct trident_card *card);
 static void ali_disable_special_channel(struct trident_card *card, int ch);
 static void ali_setup_spdif_out(struct trident_card *card, int flag);
-static int ali_write_5_1(struct trident_state *state, const char *buffer,int cnt_for_multi_channel, unsigned int *copy_count, unsigned int *state_cnt);
-static int ali_allocate_other_states_resources(struct trident_state *state, int chan_nums);
+static int ali_write_5_1(struct trident_state *state, const char *buffer,
+			 int cnt_for_multi_channel, unsigned int *copy_count, 
+			 unsigned int *state_cnt);
+static int ali_allocate_other_states_resources(struct trident_state *state, 
+					       int chan_nums);
 static void ali_free_other_states_resources(struct trident_state *state);
 
 
@@ -443,22 +494,29 @@
 	unsigned mixer_regs[ALI_MIXER_REGS];
 } ali_registers;
 
-#define seek_offset(dma_ptr, buffer, cnt, offset, copy_count)	(dma_ptr) += (offset);	\
-							(buffer) += (offset);	\
-							(cnt) -= (offset);	\
-							(copy_count) += (offset);
-
-#define lock_set_fmt(state)	{spin_lock_irqsave(&state->card->lock, flags);			\
-				if (state->fmt_flag) {						\
-					spin_unlock_irqrestore(&state->card->lock, flags);	\
-					return -EFAULT;						\
-				}								\
-				state->fmt_flag = 1;						\
-				spin_unlock_irqrestore(&state->card->lock, flags);}
+#define seek_offset(dma_ptr, buffer, cnt, offset, copy_count)	do { \
+        (dma_ptr) += (offset);	  \
+	(buffer) += (offset);	  \
+        (cnt) -= (offset);	  \
+	(copy_count) += (offset); \
+} while (0)
+	  
+
+#define lock_set_fmt(state) do { \
+        spin_lock_irqsave(&state->card->lock, flags);			\
+	if (state->fmt_flag) {						\
+	       spin_unlock_irqrestore(&state->card->lock, flags);	\
+               return -EFAULT;					        \
+	}								\
+	state->fmt_flag = 1;						\
+	spin_unlock_irqrestore(&state->card->lock, flags);              \
+} while (0)
 				
-#define unlock_set_fmt(state)	{spin_lock_irqsave(&state->card->lock, flags);		\
-				state->fmt_flag = 0;					\
-				spin_unlock_irqrestore(&state->card->lock, flags);}
+#define unlock_set_fmt(state)  do {                             \
+        spin_lock_irqsave(&state->card->lock, flags);		\
+	state->fmt_flag = 0;					\
+	spin_unlock_irqrestore(&state->card->lock, flags);      \
+} while (0)
 
 static int trident_enable_loop_interrupts(struct trident_card * card)
 {
@@ -483,10 +541,9 @@
 
 	outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR));
 
-#ifdef DEBUG
-	printk("trident: Enable Loop Interrupts, globctl = 0x%08X\n",
-			inl(TRID_REG(card, T4D_LFO_GC_CIR)));
-#endif
+	TRDBG("trident: Enable Loop Interrupts, globctl = 0x%08X\n",
+	      inl(TRID_REG(card, T4D_LFO_GC_CIR)));
+
 	return (TRUE);
 }
 
@@ -498,10 +555,9 @@
 	global_control &= ~(ENDLP_IE | MIDLP_IE);
 	outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR));
 
-#ifdef DEBUG
-	printk("trident: Disabled Loop Interrupts, globctl = 0x%08X\n",
-	       global_control);
-#endif
+	TRDBG("trident: Disabled Loop Interrupts, globctl = 0x%08X\n",
+	      global_control);
+
 	return (TRUE);
 }
 
@@ -517,9 +573,9 @@
 
 #ifdef DEBUG
 	reg = inl(TRID_REG(card, addr));
-	printk("trident: enabled IRQ on channel %d, %s = 0x%08x(addr:%X)\n",
-		channel, addr==T4D_AINTEN_B? "AINTEN_B":"AINTEN_A",reg,addr);
-#endif
+	TRDBG("trident: enabled IRQ on channel %d, %s = 0x%08x(addr:%X)\n",
+	      channel, addr==T4D_AINTEN_B? "AINTEN_B":"AINTEN_A",reg,addr);
+#endif /* DEBUG */ 
 }
 
 static void trident_disable_voice_irq(struct trident_card * card, unsigned int channel)
@@ -537,9 +593,9 @@
 
 #ifdef DEBUG
 	reg = inl(TRID_REG(card, addr));
-	printk("trident: disabled IRQ on channel %d, %s = 0x%08x(addr:%X)\n",
-		channel, addr==T4D_AINTEN_B? "AINTEN_B":"AINTEN_A",reg,addr);
-#endif
+	TRDBG("trident: disabled IRQ on channel %d, %s = 0x%08x(addr:%X)\n",
+	      channel, addr==T4D_AINTEN_B? "AINTEN_B":"AINTEN_A",reg,addr);
+#endif /* DEBUG */ 
 }
 
 static void trident_start_voice(struct trident_card * card, unsigned int channel)
@@ -550,15 +606,15 @@
 
 #ifdef DEBUG
 	u32 reg;
-#endif
+#endif /* DEBUG */ 
 
 	outl(mask, TRID_REG(card, addr));
 
-#ifdef DEBUG
+#ifdef DEBUG 
 	reg = inl(TRID_REG(card, addr));
-	printk("trident: start voice on channel %d, %s = 0x%08x(addr:%X)\n",
-		channel, addr==T4D_START_B? "START_B":"START_A",reg,addr);
-#endif
+	TRDBG("trident: start voice on channel %d, %s = 0x%08x(addr:%X)\n",
+	      channel, addr==T4D_START_B? "START_B":"START_A",reg,addr);
+#endif /* DEBUG */ 
 }
 
 static void trident_stop_voice(struct trident_card * card, unsigned int channel)
@@ -569,15 +625,15 @@
 
 #ifdef DEBUG
 	u32 reg;
-#endif
+#endif /* DEBUG */ 
 
 	outl(mask, TRID_REG(card, addr));
 
 #ifdef DEBUG
 	reg = inl(TRID_REG(card, addr));
-	printk("trident: stop voice on channel %d, %s = 0x%08x(addr:%X)\n",
-		channel, addr==T4D_STOP_B? "STOP_B":"STOP_A",reg,addr);
-#endif
+	TRDBG("trident: stop voice on channel %d, %s = 0x%08x(addr:%X)\n",
+	      channel, addr==T4D_STOP_B? "STOP_B":"STOP_A",reg,addr);
+#endif /* DEBUG */ 
 }
 
 static u32 trident_get_interrupt_mask (struct trident_card * card, unsigned int channel)
@@ -594,9 +650,9 @@
 
 #ifdef DEBUG
 	if (reg & mask)
-		printk("trident: channel %d has interrupt, %s = 0x%08x\n",
-			channel,reg==T4D_AINT_B? "AINT_B":"AINT_A", reg);
-#endif
+		TRDBG("trident: channel %d has interrupt, %s = 0x%08x\n",
+		      channel,reg==T4D_AINT_B? "AINT_B":"AINT_A", reg);
+#endif /* DEBUG */ 
 	return (reg & mask) ? TRUE : FALSE;
 }
 
@@ -612,9 +668,9 @@
 
 #ifdef DEBUG
 	reg = inl(TRID_REG(card, T4D_AINT_B));
-	printk("trident: Ack channel %d interrupt, AINT_B = 0x%08x\n",
-	       channel, reg);
-#endif
+	TRDBG("trident: Ack channel %d interrupt, AINT_B = 0x%08x\n",
+	      channel, reg);
+#endif /* DEBUG */ 
 }
 
 static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *card)
@@ -862,9 +918,7 @@
 
 	trident_write_voice_regs(state);
 
-#ifdef DEBUG
-	printk("trident: called trident_set_dac_rate : rate = %d\n", rate);
-#endif
+	TRDBG("trident: called trident_set_dac_rate : rate = %d\n", rate);
 
 	return rate;
 }
@@ -884,9 +938,8 @@
 
 	trident_write_voice_regs(state);
 
-#ifdef DEBUG
-	printk("trident: called trident_set_adc_rate : rate = %d\n", rate);
-#endif
+	TRDBG("trident: called trident_set_adc_rate : rate = %d\n", rate);
+
 	return rate;
 }
 
@@ -928,11 +981,11 @@
 	if (dmabuf->fmt & TRIDENT_FMT_STEREO)
 		/* stereo */
 		channel->control |= CHANNEL_STEREO;
-#ifdef DEBUG
-	printk("trident: trident_play_setup, LBA = 0x%08x, "
-	       "Delta = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",
-	       channel->lba, channel->delta, channel->eso, channel->control);
-#endif
+
+	TRDBG("trident: trident_play_setup, LBA = 0x%08x, "
+	      "Delta = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",
+	      channel->lba, channel->delta, channel->eso, channel->control);
+
 	trident_write_voice_regs(state);
 }
 
@@ -1014,11 +1067,11 @@
 	if (dmabuf->fmt & TRIDENT_FMT_STEREO)
 		/* stereo */
 		channel->control |= CHANNEL_STEREO;
-#ifdef DEBUG
-	printk("trident: trident_rec_setup, LBA = 0x%08x, "
-	       "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",
-	       channel->lba, channel->delta, channel->eso, channel->control);
-#endif
+	
+	TRDBG("trident: trident_rec_setup, LBA = 0x%08x, "
+	      "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",
+	      channel->lba, channel->delta, channel->eso, channel->control);
+
 	trident_write_voice_regs(state);
 }
 
@@ -1051,11 +1104,10 @@
 		return 0;
 	}
 
-#ifdef DEBUG
-	printk("trident: trident_get_dma_addr: chip reported channel: %d, "
-	       "cso = 0x%04x\n",
-	       dmabuf->channel->num, cso);
-#endif
+	
+	TRDBG("trident: trident_get_dma_addr: chip reported channel: %d, "
+	      "cso = 0x%04x\n", dmabuf->channel->num, cso);
+
 	/* ESO and CSO are in units of Samples, convert to byte offset */
 	cso <<= sample_shift[dmabuf->fmt];
 
@@ -1153,27 +1205,18 @@
 #define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
 #define DMABUF_MINORDER 1
 
-/* allocate DMA buffer, playback and recording buffer should be allocated seperately */
-static int alloc_dmabuf(struct trident_state *state)
+/* alloc a DMA buffer of with a buffer of this order */ 
+static int alloc_dmabuf(struct dmabuf* dmabuf, struct pci_dev* pci_dev, int order)
 {
-	struct dmabuf *dmabuf = &state->dmabuf;
 	void *rawbuf = NULL;
-	int order;
 	struct page *page, *pend;
 
-	/* alloc as big a chunk as we can, FIXME: is this necessary ?? */
-	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
-		if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,
-						   PAGE_SIZE << order,
-						   &dmabuf->dma_handle)))
-			break;
-	if (!rawbuf)
+	if (!(rawbuf = pci_alloc_consistent(pci_dev, PAGE_SIZE << order,
+					    &dmabuf->dma_handle)))
 		return -ENOMEM;
 
-#ifdef DEBUG
-	printk("trident: allocated %ld (order = %d) bytes at %p\n",
-	       PAGE_SIZE << order, order, rawbuf);
-#endif
+	TRDBG("trident: allocated %ld (order = %d) bytes at %p\n",
+	      PAGE_SIZE << order, order, rawbuf);
 
 	dmabuf->ready  = dmabuf->mapped = 0;
 	dmabuf->rawbuf = rawbuf;
@@ -1187,21 +1230,37 @@
 	return 0;
 }
 
-/* free DMA buffer */
-static void dealloc_dmabuf(struct trident_state *state)
+/* allocate the main DMA buffer, playback and recording buffer should be */ 
+/* allocated seperately */
+static int alloc_main_dmabuf(struct trident_state *state)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-	struct page *page, *pend;
+	int order;
+	int ret = -ENOMEM; 
+
+	/* alloc as big a chunk as we can, FIXME: is this necessary ?? */
+	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
+		if (!(ret = alloc_dmabuf(dmabuf, state->card->pci_dev, order)))
+			return 0; 
+		/* else try again */ 
+	}
+	return ret; 
+}
 
+/* deallocate a DMA buffer */ 
+static void dealloc_dmabuf(struct dmabuf* dmabuf, struct pci_dev* pci_dev)
+{
+	struct page *page, *pend;
+	
 	if (dmabuf->rawbuf) {
 		/* undo marking the pages as reserved */
 		pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
 		for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
 			mem_map_unreserve(page);
-		pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder,
+		pci_free_consistent(pci_dev, PAGE_SIZE << dmabuf->buforder,
 				    dmabuf->rawbuf, dmabuf->dma_handle);
+		dmabuf->rawbuf = NULL;
 	}
-	dmabuf->rawbuf = NULL;
 	dmabuf->mapped = dmabuf->ready = 0;
 }
 
@@ -1213,16 +1272,16 @@
 	unsigned bufsize, dma_nums;
 	unsigned long flags;
 	int ret, i, order;
-	struct page *page, *pend;
 	
 	lock_set_fmt(state);
 	if (state->chans_num == 6)
 		dma_nums = 5;
-	else 	dma_nums = 1;
+	else 	
+		dma_nums = 1;
 	
 	for (i = 0; i < dma_nums; i++) {
 		if (i > 0) {
-			s = state->other_states[i - 1];			
+			s = state->other_states[i - 1];
 			dmabuf = &s->dmabuf;
 			dmabuf->fmt = state->dmabuf.fmt;
 			dmabuf->rate = state->dmabuf.rate;
@@ -1236,35 +1295,25 @@
 		/* allocate DMA buffer if not allocated yet */
 		if (!dmabuf->rawbuf) {
 			if (i == 0) {
-				if ((ret = alloc_dmabuf(state))) {
+				if ((ret = alloc_main_dmabuf(state))) {
 					unlock_set_fmt(state);
 					return ret;
 				}
-			}
-			else {
+			} else {
+				ret = -ENOMEM; 
 				if ((order = state->dmabuf.buforder - 1) >= DMABUF_MINORDER) {
-					dmabuf->rawbuf = pci_alloc_consistent(state->card->pci_dev,
-									      PAGE_SIZE << order,
-									      &dmabuf->dma_handle);
+					ret = alloc_dmabuf(dmabuf, state->card->pci_dev, order); 
 				}
-				if (!dmabuf->rawbuf) {
-					free_pages((unsigned long)state->dmabuf.rawbuf, state->dmabuf.buforder);
-					state->dmabuf.rawbuf = NULL;
-					i-=2;
-					for (; i >= 0; i--) {
-						pci_free_consistent(state->card->pci_dev,
-								    PAGE_SIZE << state->other_states[i]->dmabuf.buforder,
-								    state->other_states[i]->dmabuf.rawbuf,
-								    state->other_states[i]->dmabuf.dma_handle);
-					}
+				if (ret) {
+					/* release the main DMA buffer */ 
+					dealloc_dmabuf(&state->dmabuf, state->card->pci_dev); 
+					/* release the auxiliary DMA buffers */ 
+					for (i-=2; i >= 0; i--)
+						dealloc_dmabuf(&state->other_states[i]->dmabuf, 
+							       state->card->pci_dev); 
 					unlock_set_fmt(state);
-					return -ENOMEM;
+					return ret; 
 				}
-				dmabuf->ready  = dmabuf->mapped = 0;
-				dmabuf->buforder = order;
-				pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << order) - 1);
-				for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
-					mem_map_reserve(page);
 			}
 		}
 		/* FIXME: figure out all this OSS fragment stuff */
@@ -1294,22 +1343,20 @@
 		       dmabuf->dmasize);
 
 		spin_lock_irqsave(&s->card->lock, flags);
-		if (rec) {
+		if (rec) 
 			trident_rec_setup(s);
-		} else {
+		else 
 			trident_play_setup(s);
-		}
+		
 		spin_unlock_irqrestore(&s->card->lock, flags);
 
 		/* set the ready flag for the dma buffer */
 		dmabuf->ready = 1;
 
-#ifdef DEBUG
-	printk("trident: prog_dmabuf(%d), sample rate = %d, format = %d, numfrag = %d, "
-	       "fragsize = %d dmasize = %d\n",
-	       dmabuf->channel->num, dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
-	       dmabuf->fragsize, dmabuf->dmasize);
-#endif
+		TRDBG("trident: prog_dmabuf(%d), sample rate = %d, format = %d, numfrag = %d, "
+		      "fragsize = %d dmasize = %d\n",
+		      dmabuf->channel->num, dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
+		      dmabuf->fragsize, dmabuf->dmasize);
 	}
 	unlock_set_fmt(state);
 	return 0;
@@ -1533,19 +1580,21 @@
 {
 	int i;
 	struct trident_state *state;
+	unsigned int channel; 
 	
 	/* Update the pointers for all channels we are running. */
 	/* FIXME: should read interrupt status only once */
 	for (i = 0; i < NR_HW_CH; i++) {
-		if (trident_check_channel_interrupt(card, 63 - i)) {
-			trident_ack_channel_interrupt(card, 63 - i);
+		channel = 63 - i; 
+		if (trident_check_channel_interrupt(card, channel)) {
+			trident_ack_channel_interrupt(card, channel);
 			if ((state = card->states[i]) != NULL) {
 				trident_update_ptr(state);
 			} else {
-				printk("trident: spurious channel irq %d.\n",
-				       63 - i);
-				trident_stop_voice(card, 63 - i);
-				trident_disable_voice_irq(card, 63 - i);
+				printk(KERN_WARNING "trident: spurious channel "
+				       "irq %d.\n", channel);
+				trident_stop_voice(card, channel);
+				trident_disable_voice_irq(card, channel);
 			}
 		}
 	}
@@ -1653,29 +1702,29 @@
 {
 	int i,irq_status;
 	struct trident_state *state;
+	unsigned int channel; 
 
 	/* Update the pointers for all channels we are running. */
 	/* FIXED: read interrupt status only once */
 	irq_status=inl(TRID_REG(card, T4D_AINT_A) );
-#ifdef DEBUG	
-	printk("cyber_address_interrupt: irq_status 0x%X\n",irq_status);
-#endif
-	for (i = 0; i < NR_HW_CH; i++) {
-		if (irq_status & ( 1 << (31 - i)) ) {
 
+	TRDBG("cyber_address_interrupt: irq_status 0x%X\n",irq_status);
+
+	for (i = 0; i < NR_HW_CH; i++) {
+		channel = 31 - i; 
+		if (irq_status & ( 1 << channel) ) {
 			/* clear bit by writing a 1, zeroes are ignored */ 		
-			outl( (1 <<(31-i)), TRID_REG(card, T4D_AINT_A));
+			outl( (1 << channel), TRID_REG(card, T4D_AINT_A));
 		
-#ifdef DEBUG	
-	printk("cyber_interrupt: channel %d\n", 31-i);
-#endif
+			TRDBG("cyber_interrupt: channel %d\n", channel);
+
 			if ((state = card->states[i]) != NULL) {
 				trident_update_ptr(state);
 			} else {
-				printk("cyber5050: spurious channel irq %d.\n",
-				       31 - i);
-				trident_stop_voice(card, 31 - i);
-				trident_disable_voice_irq(card, 31 - i);
+				printk(KERN_WARNING "cyber5050: spurious "
+				       "channel irq %d.\n", channel); 
+				trident_stop_voice(card, channel);
+				trident_disable_voice_irq(card, channel);
 			}
 		}
 	}
@@ -1690,9 +1739,7 @@
 	spin_lock(&card->lock);
 	event = inl(TRID_REG(card, T4D_MISCINT));
 
-#ifdef DEBUG
-	printk("trident: trident_interrupt called, MISCINT = 0x%08x\n", event);
-#endif
+	TRDBG("trident: trident_interrupt called, MISCINT = 0x%08x\n", event);
 
 	if (event & ADDRESS_IRQ) {
 		card->address_interrupt(card);
@@ -1730,9 +1777,7 @@
 	unsigned swptr;
 	int cnt;
 
-#ifdef DEBUG
-	printk("trident: trident_read called, count = %d\n", count);
-#endif
+	TRDBG("trident: trident_read called, count = %d\n", count);
 
 	VALIDATE_STATE(state);
 	if (ppos != &file->f_pos)
@@ -1786,12 +1831,11 @@
 			   which results in a (potential) buffer overrun. And worse, there is
 			   NOTHING we can do to prevent it. */
 			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
-#ifdef DEBUG
-				printk(KERN_ERR "trident: recording schedule timeout, "
-				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
-				       dmabuf->hwptr, dmabuf->swptr);
-#endif
+				TRDBG(KERN_ERR "trident: recording schedule timeout, "
+				      "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+				      dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
+				      dmabuf->hwptr, dmabuf->swptr);
+
 				/* a buffer overrun, we delay the recovery until next time the
 				   while loop begin and we REALLY have space to record */
 			}
@@ -1845,9 +1889,8 @@
 	unsigned int state_cnt;
 	unsigned int copy_count;
 
-#ifdef DEBUG
-	printk("trident: trident_write called, count = %d\n", count);
-#endif
+	TRDBG("trident: trident_write called, count = %d\n", count);
+
 	VALIDATE_STATE(state);
 	if (ppos != &file->f_pos)
 		return -ESPIPE;
@@ -1915,12 +1958,11 @@
 			   which results in a (potential) buffer underrun. And worse, there is
 			   NOTHING we can do to prevent it. */
 			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
-#ifdef DEBUG
-				printk(KERN_ERR "trident: playback schedule timeout, "
-				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
-				       dmabuf->hwptr, dmabuf->swptr);
-#endif
+				TRDBG(KERN_ERR "trident: playback schedule timeout, "
+				      "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+				      dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
+				      dmabuf->hwptr, dmabuf->swptr);
+
 				/* a buffer underrun, we delay the recovery until next time the
 				   while loop begin and we REALLY have data to play */
 			}
@@ -2099,10 +2141,8 @@
 	VALIDATE_STATE(state);
 	mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) ||
 		((file->f_mode & FMODE_READ) && dmabuf->mapped);
-#ifdef DEBUG
-	printk("trident: trident_ioctl, command = %2d, arg = 0x%08x\n",
-	       _IOC_NR(cmd), arg ? *(int *)arg : 0);
-#endif
+	TRDBG("trident: trident_ioctl, command = %2d, arg = 0x%08x\n",
+	      _IOC_NR(cmd), arg ? *(int *)arg : 0);
 
 	switch (cmd) 
 	{
@@ -2262,6 +2302,7 @@
 						{
 							printk(KERN_ERR "trident: Record is working on the card!\n");
 							ret = -EBUSY;
+							unlock_set_fmt(state); 
 							break;
 						}
 
@@ -2665,10 +2706,8 @@
 	state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
 	up(&card->open_sem);
 
-#ifdef DEBUG
-       printk(KERN_ERR "trident: open virtual channel %d, hard channel %d\n", 
+	TRDBG("trident: open virtual channel %d, hard channel %d\n", 
               state->virt, dmabuf->channel->num);
-#endif
 
 	return 0;
 }
@@ -2678,7 +2717,6 @@
 	struct trident_state *state = (struct trident_state *)file->private_data;
 	struct trident_card *card;
 	struct dmabuf *dmabuf;
-	unsigned long flags;
 
 	lock_kernel();
 	card = state->card;
@@ -2690,20 +2728,15 @@
 		drain_dac(state, file->f_flags & O_NONBLOCK);
 	}
 
-#ifdef DEBUG
-	printk(KERN_ERR "trident: closing virtual channel %d, hard channel %d\n", 
-		state->virt, dmabuf->channel->num);
-#endif
+	TRDBG("trident: closing virtual channel %d, hard channel %d\n", 
+	      state->virt, dmabuf->channel->num);
 
 	/* stop DMA state machine and free DMA buffers/channels */
 	down(&card->open_sem);
 
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(state);
-		lock_set_fmt(state);
-
-		unlock_set_fmt(state);
-		dealloc_dmabuf(state);
+		dealloc_dmabuf(&state->dmabuf, state->card->pci_dev);
 		state->card->free_pcm_channel(state->card, dmabuf->channel->num);
 
 		/* Added by Matt Wu */
@@ -2719,7 +2752,7 @@
 	}
 	if (file->f_mode & FMODE_READ) {
 		stop_adc(state);
-		dealloc_dmabuf(state);
+		dealloc_dmabuf(&state->dmabuf, state->card->pci_dev);
 		state->card->free_pcm_channel(state->card, dmabuf->channel->num);
 
 		/* Added by Matt Wu */
@@ -2868,62 +2901,74 @@
 	return ((u16) (data >> 16));
 }
 
-/* Write AC97 codec registers for ALi*/
-static void ali_ac97_set(struct trident_card *card, int secondary, u8 reg, u16 val)
+/* rewrite ac97 read and write mixer register by hulei for ALI*/
+static int acquirecodecaccess(struct trident_card *card)
 {
-	unsigned int address, mask;
-	unsigned int wCount1 = 0xffff;
-	unsigned int wCount2= 0xffff;
-	unsigned long chk1, chk2;
-	unsigned long flags;
-	u32 data;
-
-	data = ((u32) val) << 16;
-
-	if(!card)
-		BUG();
-		
-	address = ALI_AC97_WRITE;
-	mask = ALI_AC97_WRITE_ACTION | ALI_AC97_AUDIO_BUSY;
-	if (secondary)
-		mask |= ALI_AC97_SECONDARY;
-	if (card->revision == ALI_5451_V02)
-		mask |= ALI_AC97_WRITE_MIXER_REGISTER;
+	u16 wsemamask=0x6000; /* bit 14..13 */
+	u16 wsemabits;
+        u16 wcontrol ;
+	int block = 0;
+	int ncount = 25;
+	while (1) {
+		wcontrol = inw(TRID_REG(card,  ALI_AC97_WRITE));
+		wsemabits = wcontrol & wsemamask;
 		
-	spin_lock_irqsave(&card->lock, flags);
-	while (wCount1--) {
-		if ((inw(TRID_REG(card, address)) & ALI_AC97_BUSY_WRITE) == 0) {
-			data |= (mask | (reg & AC97_REG_ADDR));
-			
-			chk1 = inl(TRID_REG(card,  ALI_STIMER));
-			chk2 = inl(TRID_REG(card,  ALI_STIMER));
-			while (wCount2-- && (chk1 == chk2))
-				chk2 = inl(TRID_REG(card,  ALI_STIMER));
-			if (wCount2 == 0) {
-				spin_unlock_irqrestore(&card->lock, flags);
-				return;
-			}
-			outl(data, TRID_REG(card, address));	//write!
-			spin_unlock_irqrestore(&card->lock, flags);
-			return;	//success
+		if (wsemabits==0x4000)
+			return 1; /* 0x4000 is audio ,then success */
+		if (ncount-- < 0)
+			break;
+		if (wsemabits == 0)
+		{
+		unlock:
+			outl(((u32)(wcontrol & 0x1eff)|0x00004000), TRID_REG(card, ALI_AC97_WRITE));
+			continue;
 		}
-		inw(TRID_REG(card, address));	//wait for a read cycle
+		udelay(20);
+	}
+	if(!block)
+	{
+		TRDBG("accesscodecsemaphore: try unlock\n");
+		block = 1;
+		goto unlock;
 	}
+	printk(KERN_ERR "accesscodecsemaphore: fail\n");
+	return 0;
+}
 
-	printk(KERN_ERR "ali: AC97 CODEC write timed out.\n");
-	spin_unlock_irqrestore(&card->lock, flags);
-	return;
+static void releasecodecaccess(struct trident_card *card)
+{ 
+	unsigned long wcontrol;
+	wcontrol = inl(TRID_REG(card,  ALI_AC97_WRITE));
+	outl((wcontrol & 0xffff1eff), TRID_REG(card, ALI_AC97_WRITE));
+}
+
+static int waitforstimertick(struct trident_card *card)
+{
+	unsigned long chk1, chk2;
+	unsigned int wcount = 0xffff;
+	chk1 = inl(TRID_REG(card,  ALI_STIMER));
+	
+	while(1) {
+		chk2 = inl(TRID_REG(card,  ALI_STIMER));
+		if( (wcount > 0) && chk1 != chk2)
+			return 1;
+		if(wcount <= 0)
+			break;
+		udelay(50);
+	}
+
+	printk(KERN_NOTICE "waitforstimertick :BIT_CLK is dead\n");
+	return 0;
 }
 
 /* Read AC97 codec registers for ALi*/
 static u16 ali_ac97_get(struct trident_card *card, int secondary, u8 reg)
 {
 	unsigned int address, mask;
-        unsigned int wCount1 = 0xffff;
-        unsigned int wCount2= 0xffff;
-        unsigned long chk1, chk2;
-	unsigned long flags;
+	unsigned int ncount;
+        unsigned long aud_reg;
 	u32 data;
+        u16 wcontrol;
 
 	if(!card)
 		BUG();
@@ -2935,37 +2980,102 @@
 	mask = ALI_AC97_READ_ACTION | ALI_AC97_AUDIO_BUSY;
 	if (secondary)
 		mask |= ALI_AC97_SECONDARY;
+    
+	if (!acquirecodecaccess(card))
+		printk(KERN_ERR "access codec fail\n");
+	
+	wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE));
+	wcontrol &= 0xfe00;
+	wcontrol |= (0x8000|reg);
+	outw(wcontrol,TRID_REG(card,  ALI_AC97_WRITE));
 
-	spin_lock_irqsave(&card->lock, flags);
 	data = (mask | (reg & AC97_REG_ADDR));
-	while (wCount1--) {
-		if ((inw(TRID_REG(card, address)) & ALI_AC97_BUSY_READ) == 0) {
-			chk1 = inl(TRID_REG(card,  ALI_STIMER));
-			chk2 = inl(TRID_REG(card,  ALI_STIMER));
-			while (wCount2-- && (chk1 == chk2))
-				chk2 = inl(TRID_REG(card,  ALI_STIMER));
-			if (wCount2 == 0) {
-				printk(KERN_ERR "ali: AC97 CODEC read timed out.\n");
-				spin_unlock_irqrestore(&card->lock, flags);
-				return 0;
-			}
-			outl(data, TRID_REG(card, address));	//read!
-			wCount2 = 0xffff;
-			while (wCount2--) {
-				if ((inw(TRID_REG(card, address)) & ALI_AC97_BUSY_READ) == 0) {
-					data = inl(TRID_REG(card, address));
-					spin_unlock_irqrestore(&card->lock, flags);
-					return ((u16) (data >> 16));
-				}
-			}
+	
+	if(!waitforstimertick(card)) {
+		printk(KERN_ERR "BIT_CLOCK is dead\n");
+		goto releasecodec;
+	}
+	
+	udelay(20);		
+	
+	ncount=10;
+	
+	while(1) {
+		if ((inw(TRID_REG(card,ALI_AC97_WRITE)) & ALI_AC97_BUSY_READ) != 0)
+			break;
+		if(ncount <=0)
+			break;
+		if(ncount--==1) {
+			TRDBG("ali_ac97_read :try clear busy flag\n");
+			aud_reg = inl(TRID_REG(card,  ALI_AC97_WRITE));
+			outl((aud_reg & 0xffff7fff), TRID_REG(card, ALI_AC97_WRITE));
 		}
-		inw(TRID_REG(card, address));	//wait a read cycle
+		udelay(10);
 	}
-	spin_unlock_irqrestore(&card->lock, flags);
+	
+	data = inl(TRID_REG(card, address));
+	
+	return ((u16) (data >> 16));
+
+ releasecodec: 
+	releasecodecaccess(card);
 	printk(KERN_ERR "ali: AC97 CODEC read timed out.\n");
 	return 0;
 }
 
+
+/* Write AC97 codec registers for hulei*/
+static void ali_ac97_set(struct trident_card *card, int secondary, u8 reg, u16 val)
+{
+	unsigned int address, mask;
+	unsigned int ncount;
+	u32 data;
+        u16 wcontrol;
+	
+	data = ((u32) val) << 16;
+	
+	if(!card)
+		BUG();
+	
+	address = ALI_AC97_WRITE;
+	mask = ALI_AC97_WRITE_ACTION | ALI_AC97_AUDIO_BUSY;
+	if (secondary)
+		mask |= ALI_AC97_SECONDARY;
+	if (card->revision == ALI_5451_V02)
+		mask |= ALI_AC97_WRITE_MIXER_REGISTER;
+		
+        if (!acquirecodecaccess(card))      
+		printk(KERN_ERR "access codec fail\n");
+			
+	wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE));
+	wcontrol &= 0xff00;
+	wcontrol |= (0x8100|reg);/* bit 8=1: (ali1535 )reserved /ali1535+ write */
+	outl(( data |wcontrol), TRID_REG(card,ALI_AC97_WRITE ));
+
+        if(!waitforstimertick(card)) {
+		printk(KERN_ERR "BIT_CLOCK is dead\n");
+		goto releasecodec;
+	}
+	
+        ncount = 10;
+	while(1) {
+		wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE));
+		if(!wcontrol & 0x8000)
+			break;
+		if(ncount <= 0)
+			break;
+		if(ncount-- == 1) {
+			TRDBG("ali_ac97_set :try clear busy flag!!\n");
+			outw(wcontrol & 0x7fff, TRID_REG(card, ALI_AC97_WRITE));
+		}
+		udelay(10);
+	}
+	
+ releasecodec:
+	releasecodecaccess(card);
+	return;
+}
+
 static void ali_enable_special_channel(struct trident_state *stat)
 {
 	struct trident_card *card = stat->card;
@@ -3463,7 +3573,7 @@
 
 static int trident_suspend(struct pci_dev *dev, u32 unused)
 {
-	struct trident_card *card = (struct trident_card *) dev;
+	struct trident_card *card = pci_get_drvdata(dev); 
 
 	if(card->pci_id == PCI_DEVICE_ID_ALI_5451) {
 		ali_save_regs(card);
@@ -3473,7 +3583,7 @@
 
 static int trident_resume(struct pci_dev *dev)
 {
-	struct trident_card *card = (struct trident_card *) dev;
+	struct trident_card *card = pci_get_drvdata(dev); 
 
 	if(card->pci_id == PCI_DEVICE_ID_ALI_5451) {
 		ali_restore_regs(card);
@@ -3600,7 +3710,10 @@
 depend on a master state's DMA, and changing the counters of the master
 state DMA is protected by a spinlock.
 */
-static int ali_write_5_1(struct trident_state *state,  const char *buf, int cnt_for_multi_channel, unsigned int *copy_count, unsigned int *state_cnt)
+static int ali_write_5_1(struct trident_state *state,  
+			 const char *buf, int cnt_for_multi_channel, 
+			 unsigned int *copy_count, 
+			 unsigned int *state_cnt)
 {
 	
 	struct dmabuf *dmabuf = &state->dmabuf;
@@ -3706,7 +3819,7 @@
 	other_states_count = state->chans_num - 2;	/* except PCM L/R channels*/
 	for ( i = 0; i < other_states_count; i++) {
 		s = state->other_states[i];
-		dealloc_dmabuf(s);
+		dealloc_dmabuf(&s->dmabuf, card->pci_dev);
 		ali_disable_special_channel(s->card, s->dmabuf.channel->num);
 		state->card->free_pcm_channel(s->card, s->dmabuf.channel->num);
 		card->states[s->virt] = NULL;
@@ -3714,7 +3827,6 @@
 	}
 }
 
-#ifdef CONFIG_PROC_FS
 struct proc_dir_entry *res;
 static int ali_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
 {
@@ -3752,7 +3864,6 @@
 
 	return count;
 }
-#endif
 
 /* OSS /dev/mixer file operation methods */
 static int trident_open_mixdev(struct inode *inode, struct file *file)
@@ -4030,13 +4141,11 @@
 		/* ALi SPDIF OUT function */
 		if(card->revision == ALI_5451_V02) {
 			ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT);		
-#ifdef CONFIG_PROC_FS
 			res = create_proc_entry("ALi5451", 0, NULL);
 			if (res) {
 				res->write_proc = ali_write_proc;
 				res->data = card;
 			}
-#endif
 		}
 
 		/* Add H/W Volume Control By Matt Wu Jul. 06, 2001 */
@@ -4129,7 +4238,7 @@
 				ali_ac97_set(card, 0, AC97_POWER_CONTROL, ac97_data | ALI_EAPD_POWER_DOWN);
 			}
 		}
-#endif
+#endif /* CONFIG_ALPHA_NAUTILUS || CONFIG_ALPHA_GENERIC */ 
 		/* edited by HMSEO for GT sound*/
 	}
 	rc = 0;
@@ -4137,18 +4246,21 @@
 
 	/* Enable Address Engine Interrupts */
 	trident_enable_loop_interrupts(card);
+	
+	/* Attach joystick */
+	if((pci_dev->vendor == PCI_VENDOR_ID_TRIDENT) ||
+	   (pci_dev->vendor == PCI_VENDOR_ID_AL))
+		card->joystick = pcigame_attach(pci_dev, PCIGAME_4DWAVE);
 out:	return rc;
 out_unregister_sound_dsp:
 	unregister_sound_dsp(card->dev_audio);
 out_free_irq:
 	free_irq(card->irq, card);
 out_proc_fs:
-#ifdef CONFIG_PROC_FS
 	if (res) {
 		remove_proc_entry("ALi5451", NULL);
 		res = NULL;
 	}
-#endif
 	kfree(card);
 	devs = NULL;
 out_release_region:
@@ -4173,9 +4285,7 @@
 		ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT);
                 ali_disable_special_channel(card, ALI_SPDIF_OUT_CHANNEL);
                 ali_disable_spdif_in(card);
-#ifdef CONFIG_PROC_FS
 		remove_proc_entry("ALi5451", NULL);
-#endif
 	}
 
 	/* Kill interrupts, and SP/DIF */
@@ -4192,6 +4302,9 @@
 			kfree (card->ac97_codec[i]);
 		}
 	unregister_sound_dsp(card->dev_audio);
+	
+	if(card->joystick)
+		pcigame_detach(card->joystick);
 
 	kfree(card);
 
@@ -4219,8 +4332,9 @@
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
 
-	printk(KERN_INFO "Trident 4DWave/SiS 7018/ALi 5451,Tvia CyberPro 5050 PCI Audio, version "
-	       DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "Trident 4DWave/SiS 7018/ALi 5451,Tvia CyberPro "
+	       "5050 PCI Audio, version " DRIVER_VERSION ", " 
+	       __TIME__ " " __DATE__ "\n");
 
 	if (!pci_register_driver(&trident_pci_driver)) {
 		pci_unregister_driver(&trident_pci_driver);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/sound/trident.h linux-2.4.20/drivers/sound/trident.h
--- linux-2.4.19/drivers/sound/trident.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/sound/trident.h	2002-10-29 11:18:31.000000000 +0000
@@ -358,5 +358,16 @@
 	return r;
 }
 
-#endif /* __TRID4DWAVE_H */
+#ifdef DEBUG
+
+#define TRDBG(msg, args...) do {          \
+        printk(KERN_DEBUG msg , ##args ); \
+} while (0)
+
+#else /* !defined(DEBUG) */ 
 
+#define TRDBG(msg, args...) do { } while (0)
+
+#endif /* DEBUG */ 
+
+#endif /* __TRID4DWAVE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/tc/lk201-map.map linux-2.4.20/drivers/tc/lk201-map.map
--- linux-2.4.19/drivers/tc/lk201-map.map	2001-08-27 15:56:31.000000000 +0000
+++ linux-2.4.20/drivers/tc/lk201-map.map	2002-10-29 11:18:39.000000000 +0000
@@ -3,8 +3,8 @@
 # Change the above line into
 #	keymaps 0-2,4-6,8,12
 # in case you want the entries
-#	altgr   control keycode  83 = Boot            
-#	altgr   control keycode 111 = Boot            
+#	altgr   control keycode  83 = Boot
+#	altgr   control keycode 111 = Boot
 # below.
 #
 # In fact AltGr is used very little, and one more keymap can
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/tc/lk201-remap.c linux-2.4.20/drivers/tc/lk201-remap.c
--- linux-2.4.19/drivers/tc/lk201-remap.c	2001-08-27 15:56:31.000000000 +0000
+++ linux-2.4.20/drivers/tc/lk201-remap.c	2002-10-29 11:18:34.000000000 +0000
@@ -1,17 +1,17 @@
 /*
  * Keyboard mappings for DEC LK201/401/501 keyboards
- * 
+ *
  * 17.05.99 Michael Engel (engel@unix-ag.org)
  *
  * DEC US keyboards generate keycodes in the range 0x55 - 0xfb
  *
- * This conflicts with Linux scancode conventions which define 
+ * This conflicts with Linux scancode conventions which define
  * 0x00-0x7f as "normal" and 0x80-0xff as "shifted" scancodes, so we
  * have to remap the keycodes to 0x00-0x7f with the scancodeRemap
  * array. The generated scancode is simply the number of the key counted
  * from the left upper to the right lower corner of the keyboard ...
  *
- * These scancodes are then being remapped (I hope ;-)) with the 
+ * These scancodes are then being remapped (I hope ;-)) with the
  * lk501*map[] arrays which define scancode -> Linux code mapping
  *
  * Oh man is this horrible ;-)
@@ -91,7 +91,7 @@
 /* ----- 								*/
 /* 60 */ 0,		0,		0,		0,
 /* ----- F6		F7		F8		F9		*/
-/* 64 */ 0x06,		0x07,		0x08,		0x09, 
+/* 64 */ 0x06,		0x07,		0x08,		0x09,
 /* ----- F10								*/
 /* 68 */ 0x0a,		0,		0,		0,
 /* ----- 								*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/tc/lk201.c linux-2.4.20/drivers/tc/lk201.c
--- linux-2.4.19/drivers/tc/lk201.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/tc/lk201.c	2002-10-29 11:18:51.000000000 +0000
@@ -4,7 +4,8 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2001 Maciej W. Rozycki <macro@ds2.pg.gda.pl>
+ * Copyright (C) 1999-2002 Harald Koerfgen <hkoerfg@web.de>
+ * Copyright (C) 2001, 2002  Maciej W. Rozycki <macro@ds2.pg.gda.pl>
  */
 
 #include <linux/config.h>
@@ -20,7 +21,6 @@
 #include <linux/vt_kern.h>
 
 #include <asm/keyboard.h>
-#include <asm/wbflush.h>
 #include <asm/dec/tc.h>
 #include <asm/dec/machtype.h>
 
@@ -47,19 +47,18 @@
 static void lk201_kbd_rx_char(unsigned char, unsigned char);
 
 struct zs_hook lk201_kbdhook = {
-	init_channel:   lk201_init,
-	init_info:      lk201_info,
-	rx_char:        NULL,
-	poll_rx_char:   NULL,
-	poll_tx_char:   NULL,
-	cflags:         B4800 | CS8 | CSTOPB | CLOCAL
+	init_channel:	lk201_init,
+	init_info:	lk201_info,
+	rx_char:	NULL,
+	poll_rx_char:	NULL,
+	poll_tx_char:	NULL,
+	cflags:		B4800 | CS8 | CSTOPB | CLOCAL
 };
 
 /*
  * This is used during keyboard initialisation
  */
 static unsigned char lk201_reset_string[] = {
-	LK_CMD_LEDS_ON, LK_PARAM_LED_MASK(0xf),	/* show we are resetting */
 	LK_CMD_SET_DEFAULTS,
 	LK_CMD_MODE(LK_MODE_RPT_DOWN, 1),
 	LK_CMD_MODE(LK_MODE_RPT_DOWN, 2),
@@ -75,27 +74,85 @@
 	LK_CMD_MODE(LK_MODE_RPT_DOWN, 12),
 	LK_CMD_MODE(LK_MODE_DOWN, 13),
 	LK_CMD_MODE(LK_MODE_RPT_DOWN, 14),
-	LK_CMD_ENB_RPT,
 	LK_CMD_DIS_KEYCLK,
-	LK_CMD_RESUME,
 	LK_CMD_ENB_BELL, LK_PARAM_VOLUME(4),
-	LK_CMD_LEDS_OFF, LK_PARAM_LED_MASK(0xf)
 };
 
 static struct dec_serial* lk201kbd_info;
 
-static int __init lk201_reset(struct dec_serial *info)
+static int lk201_send(struct dec_serial *info, unsigned char ch)
 {
-	int i;
+	if (info->hook->poll_tx_char(info, ch)) {
+		printk(KERN_ERR "lk201: transmit timeout\n");
+		return -EIO;
+	}
+	return 0;
+}
 
-	for (i = 0; i < sizeof(lk201_reset_string); i++)
-		if (info->hook->poll_tx_char(info, lk201_reset_string[i])) {
-			printk(__FUNCTION__" transmit timeout\n");
-			return -EIO;
-		}
+static inline int lk201_get_id(struct dec_serial *info)
+{
+	return lk201_send(info, LK_CMD_REQ_ID);
+}
+
+static int lk201_reset(struct dec_serial *info)
+{
+	int i, r;
+
+	for (i = 0; i < sizeof(lk201_reset_string); i++) {
+		r = lk201_send(info, lk201_reset_string[i]);
+		if (r < 0)
+			return r;
+	}
 	return 0;
 }
 
+static void lk201_report(unsigned char id[6])
+{
+	char *report = "lk201: keyboard attached, ";
+
+	switch (id[2]) {
+	case LK_STAT_PWRUP_OK:
+		printk(KERN_INFO "%sself-test OK\n", report);
+		break;
+	case LK_STAT_PWRUP_KDOWN:
+		/* The keyboard will resend the power-up ID
+		   after all keys are released, so we don't
+		   bother handling the error specially.  Still
+		   there may be a short-circuit inside.
+		 */
+		printk(KERN_ERR "%skey down (stuck?), code: 0x%02x\n",
+		       report, id[3]);
+		break;
+	case LK_STAT_PWRUP_ERROR:
+		printk(KERN_ERR "%sself-test failure\n", report);
+		break;
+	default:
+		printk(KERN_ERR "%sunknown error: 0x%02x\n",
+		       report, id[2]);
+	}
+}
+
+static void lk201_id(unsigned char id[6])
+{
+	/*
+	 * Report whether there is an LK201 or an LK401
+	 * The LK401 has ALT keys...
+	 */
+	switch (id[4]) {
+	case 1:
+		printk(KERN_INFO "lk201: LK201 detected\n");
+		break;
+	case 2:
+		printk(KERN_INFO "lk201: LK401 detected\n");
+		break;
+	default:
+		printk(KERN_WARNING
+		       "lk201: unknown keyboard detected, ID %d\n", id[4]);
+		printk(KERN_WARNING "lk201: ... please report to "
+		       "<linux-mips@oss.sgi.com>\n");
+	}
+}
+
 #define DEFAULT_KEYB_REP_DELAY	(250/5)	/* [5ms] */
 #define DEFAULT_KEYB_REP_RATE	30	/* [cps] */
 
@@ -231,56 +288,92 @@
 
 static void lk201_kbd_rx_char(unsigned char ch, unsigned char stat)
 {
+	static unsigned char id[6];
+	static int id_i;
+
 	static int shift_state = 0;
 	static int prev_scancode;
 	unsigned char c = scancodeRemap[ch];
 
-	if (!stat || stat == 4) {
-		switch (ch) {
-		case LK_STAT_RESUME_ERR:
-		case LK_STAT_ERROR:
-		case LK_STAT_INHIBIT_ACK:
-		case LK_STAT_TEST_ACK:
-		case LK_STAT_MODE_KEYDOWN:
-		case LK_STAT_MODE_ACK:
-			break;
-		case LK_KEY_LOCK:
-			shift_state ^= LK_LOCK;
-			handle_scancode(c, shift_state && LK_LOCK ? 1 : 0);
-			break;
-		case LK_KEY_SHIFT:
-			shift_state ^= LK_SHIFT;
-			handle_scancode(c, shift_state && LK_SHIFT ? 1 : 0);
-			break;
-		case LK_KEY_CTRL:
-			shift_state ^= LK_CTRL;
-			handle_scancode(c, shift_state && LK_CTRL ? 1 : 0);
-			break;
-		case LK_KEY_COMP:
-			shift_state ^= LK_COMP;
-			handle_scancode(c, shift_state && LK_COMP ? 1 : 0);
-			break;
-		case LK_KEY_RELEASE:
-			if (shift_state & LK_SHIFT)
-				handle_scancode(scancodeRemap[LK_KEY_SHIFT], 0);
-			if (shift_state & LK_CTRL)
-				handle_scancode(scancodeRemap[LK_KEY_CTRL], 0);
-			if (shift_state & LK_COMP)
-				handle_scancode(scancodeRemap[LK_KEY_COMP], 0);
-			if (shift_state & LK_LOCK)
-				handle_scancode(scancodeRemap[LK_KEY_LOCK], 0);
-			shift_state = 0;
-			break;
-		case LK_KEY_REPEAT:
-			handle_scancode(prev_scancode, 1);
-			break;
-		default:
-			prev_scancode = c;
-			handle_scancode(c, 1);
-			break;
+	if (stat && stat != 4) {
+		printk(KERN_ERR "lk201: keyboard receive error: 0x%02x\n",
+		       stat);
+		return;
+	}
+
+	/* Assume this is a power-up ID. */
+	if (ch == LK_STAT_PWRUP_ID && !id_i) {
+		id[id_i++] = ch;
+		return;
+	}
+
+	/* Handle the power-up sequence. */
+	if (id_i) {
+		id[id_i++] = ch;
+		if (id_i == 4) {
+			/* OK, the power-up concluded. */
+			lk201_report(id);
+			if (id[2] == LK_STAT_PWRUP_OK)
+				lk201_get_id(lk201kbd_info);
+			else {
+				id_i = 0;
+				printk(KERN_ERR "lk201: keyboard power-up "
+				       "error, skipping initialization\n");
+			}
+		} else if (id_i == 6) {
+			/* We got the ID; report it and start an operation. */
+			id_i = 0;
+			lk201_id(id);
+			lk201_reset(lk201kbd_info);
 		}
-	} else
-		printk("Error reading LKx01 keyboard: 0x%02x\n", stat);
+		return;
+	}
+
+	/* Everything else is a scancode/status response. */
+	id_i = 0;
+	switch (ch) {
+	case LK_STAT_RESUME_ERR:
+	case LK_STAT_ERROR:
+	case LK_STAT_INHIBIT_ACK:
+	case LK_STAT_TEST_ACK:
+	case LK_STAT_MODE_KEYDOWN:
+	case LK_STAT_MODE_ACK:
+		break;
+	case LK_KEY_LOCK:
+		shift_state ^= LK_LOCK;
+		handle_scancode(c, shift_state && LK_LOCK ? 1 : 0);
+		break;
+	case LK_KEY_SHIFT:
+		shift_state ^= LK_SHIFT;
+		handle_scancode(c, shift_state && LK_SHIFT ? 1 : 0);
+		break;
+	case LK_KEY_CTRL:
+		shift_state ^= LK_CTRL;
+		handle_scancode(c, shift_state && LK_CTRL ? 1 : 0);
+		break;
+	case LK_KEY_COMP:
+		shift_state ^= LK_COMP;
+		handle_scancode(c, shift_state && LK_COMP ? 1 : 0);
+		break;
+	case LK_KEY_RELEASE:
+		if (shift_state & LK_SHIFT)
+			handle_scancode(scancodeRemap[LK_KEY_SHIFT], 0);
+		if (shift_state & LK_CTRL)
+			handle_scancode(scancodeRemap[LK_KEY_CTRL], 0);
+		if (shift_state & LK_COMP)
+			handle_scancode(scancodeRemap[LK_KEY_COMP], 0);
+		if (shift_state & LK_LOCK)
+			handle_scancode(scancodeRemap[LK_KEY_LOCK], 0);
+		shift_state = 0;
+		break;
+	case LK_KEY_REPEAT:
+		handle_scancode(prev_scancode, 1);
+		break;
+	default:
+		prev_scancode = c;
+		handle_scancode(c, 1);
+		break;
+	}
 	tasklet_schedule(&keyboard_tasklet);
 }
 
@@ -290,45 +383,16 @@
 
 static int __init lk201_init(struct dec_serial *info)
 {
-	unsigned int ch, id = 0;
-	int result;
-
-	printk("DECstation LK keyboard driver v0.04... ");
-
-	result = lk201_reset(info);
-	if (result)
-		return result;
-	mdelay(10);
-
-	/*
-	 * Detect whether there is an LK201 or an LK401
-	 * The LK401 has ALT keys...
-	 */
-	info->hook->poll_tx_char(info, LK_CMD_REQ_ID);
-	while ((ch = info->hook->poll_rx_char(info)) > 0)
-		id = ch;
-
-	switch (id) {
-	case 1:
-		printk("LK201 detected\n");
-		break;
-	case 2:
-		printk("LK401 detected\n");
-		break;
-	default:
-		printk("unknown keyboard, ID %d,\n", id);
-		printk("... please report to <linux-mips@oss.sgi.com>\n");
-	}
-
-	/*
-	 * now we're ready
-	 */
-	info->hook->rx_char = lk201_kbd_rx_char;
-
+	/* First install handlers. */
 	lk201kbd_info = info;
 	kbd_rate = lk201kbd_rate;
 	kd_mksound = lk201kd_mksound;
 
+	info->hook->rx_char = lk201_kbd_rx_char;
+
+	/* Then just issue a reset -- the handlers will do the rest. */
+	lk201_send(info, LK_CMD_POWER_UP);
+
 	return 0;
 }
 
@@ -337,26 +401,29 @@
 	extern int register_zs_hook(unsigned int, struct zs_hook *);
 	extern int unregister_zs_hook(unsigned int);
 
+	/* Maxine uses LK501 at the Access.Bus. */
+	if (mips_machtype == MACH_DS5000_XX)
+		return;
+
+	printk(KERN_INFO "lk201: DECstation LK keyboard driver v0.05.\n");
+
 	if (TURBOCHANNEL) {
-		if (mips_machtype != MACH_DS5000_XX) {
-			/*
-			 * This is not a MAXINE, so:
-			 *
-			 * kbd_init_hw() is being called before
-			 * rs_init() so just register the kbd hook
-			 * and let zs_init do the rest :-)
-			 */
-			if (mips_machtype == MACH_DS5000_200)
-				printk("LK201 Support for DS5000/200 not yet ready ...\n");
-			else
-				if(!register_zs_hook(KEYB_LINE, &lk201_kbdhook))
-					unregister_zs_hook(KEYB_LINE);
-		}
+		/*
+		 * kbd_init_hw() is being called before
+		 * rs_init() so just register the kbd hook
+		 * and let zs_init do the rest :-)
+		 */
+		if (mips_machtype == MACH_DS5000_200)
+			printk(KERN_ERR "lk201: support for DS5000/200 "
+			       "not yet ready.\n");
+		else
+			if(!register_zs_hook(KEYB_LINE, &lk201_kbdhook))
+				unregister_zs_hook(KEYB_LINE);
 	} else {
 		/*
 		 * TODO: modify dz.c to allow similar hooks
 		 * for LK201 handling on DS2100, DS3100, and DS5000/200
 		 */
-		printk("LK201 Support for DS3100 not yet ready ...\n");
+		printk(KERN_ERR "lk201: support for DS3100 not yet ready.\n");
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/tc/lk201.h linux-2.4.20/drivers/tc/lk201.h
--- linux-2.4.19/drivers/tc/lk201.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/tc/lk201.h	2002-10-29 11:18:40.000000000 +0000
@@ -20,7 +20,7 @@
 #define LK_CMD_ENB_BELL		0x23	/* enable the bell */
 					/* 1st param: volume */
 #define LK_CMD_BELL		0xa7	/* emit a bell */
-#define LK_CMD_TMP_NORPT	0xc1	/* disable typematic */
+#define LK_CMD_TMP_NORPT	0xd1	/* disable typematic */
 					/* for the currently pressed key */
 #define LK_CMD_ENB_RPT		0xe3	/* enable typematic */
 					/* for RPT_DOWN groups */
@@ -33,15 +33,15 @@
 #define LK_CMD_TEST_EXIT	0x80	/* exit the factory test mode */
 #define LK_CMD_SET_DEFAULTS	0xd3	/* set power-up defaults */
 
-#define LK_CMD_MODE(m,div)	(LK_PARAM|(((div)&0xf)<<3)|m)
+#define LK_CMD_MODE(m,div)	(LK_PARAM|(((div)&0xf)<<3)|(((m)&0x3)<<1))
 					/* select the repeat mode */
 					/* for the selected key group */
-#define LK_CMD_MODE_AR(m,div)	((((div)&0xf)<<3)|m)
+#define LK_CMD_MODE_AR(m,div)	((((div)&0xf)<<3)|(((m)&0x3)<<1))
 					/* select the repeat mode */
 					/* and the repeat register */
 					/* for the selected key group */
 					/* 1st param: register number */
-#define LK_CMD_RPT_RATE(r)	(0x04|((((r)&0x3)<<1)))
+#define LK_CMD_RPT_RATE(r)	(0x78|(((r)&0x3)<<1))
 					/* set the delay and repeat rate */
 					/* for the selected repeat register */
 					/* 1st param: initial delay */
@@ -59,8 +59,8 @@
 
 /* mode set command details, div is a key group number */
 #define LK_MODE_DOWN		0x0	/* make only */
-#define LK_MODE_RPT_DOWN	0x2	/* make and typematic */
-#define LK_MODE_DOWN_UP		0x6	/* make and release */
+#define LK_MODE_RPT_DOWN	0x1	/* make and typematic */
+#define LK_MODE_DOWN_UP		0x3	/* make and release */
 
 /* there are 4 repeat registers */
 #define LK_PARAM_AR(r)		(LK_PARAM|((v)&0x3))
@@ -115,6 +115,7 @@
 					/* the keycode follows */
 #define LK_STAT_MODE_ACK	0xba	/* the mode command succeeded */
 
+#define LK_STAT_PWRUP_ID	0x01	/* the power-up response start mark */
 #define LK_STAT_PWRUP_OK	0x00	/* the power-up self test OK */
 #define LK_STAT_PWRUP_KDOWN	0x3d	/* a key was down during the test */
 #define LK_STAT_PWRUP_ERROR	0x3e	/* keyboard self test failure */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/tc/tc.c linux-2.4.20/drivers/tc/tc.c
--- linux-2.4.19/drivers/tc/tc.c	2001-10-11 16:43:30.000000000 +0000
+++ linux-2.4.20/drivers/tc/tc.c	2002-10-29 11:18:50.000000000 +0000
@@ -8,20 +8,22 @@
  * for more details.
  *
  * Copyright (c) Harald Koerfgen, 1998
+ * Copyright (c) 2001  Maciej W. Rozycki
  */
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
 #include <asm/addrspace.h>
 #include <asm/errno.h>
 #include <asm/dec/machtype.h>
 #include <asm/dec/tcinfo.h>
 #include <asm/dec/tcmodule.h>
 #include <asm/dec/interrupts.h>
-
+#include <asm/paccess.h>
 #include <asm/ptrace.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
 
 #define TC_DEBUG
 
@@ -32,7 +34,6 @@
 
 unsigned long system_base;
 
-extern void (*dbe_board_handler)(struct pt_regs *regs);
 extern unsigned long *(*rex_slot_address)(int);
 extern void *(*rex_gettcinfo)(void);
 
@@ -40,7 +41,7 @@
  * Interface to the world. Read comment in include/asm-mips/tc.h.
  */
 
-int search_tc_card(char *name)
+int search_tc_card(const char *name)
 {
 	int slot;
 	slot_info *sip;
@@ -93,73 +94,83 @@
 /*
  * Probing for TURBOchannel modules
  */
-static void __init my_dbe_handler(struct pt_regs *regs)
-{
-	regs->cp0_epc += 4;
-}
-
 static void __init tc_probe(unsigned long startaddr, unsigned long size, int max_slot)
 {
-	int i, slot;
+	int i, slot, err;
 	long offset;
+	unsigned char pattern[4];
 	unsigned char *module;
-	void (*old_be_handler)(struct pt_regs *regs);
-
-	/* Install our exception handler temporarily */
 
-	old_be_handler = dbe_board_handler;
-	dbe_board_handler = my_dbe_handler;
 	for (slot = 0; slot <= max_slot; slot++) {
 		module = (char *)(startaddr + slot * size);
-		offset = -1;
-		if (module[OLDCARD + TC_PATTERN0] == 0x55 && module[OLDCARD + TC_PATTERN1] == 0x00
-		  && module[OLDCARD + TC_PATTERN2] == 0xaa && module[OLDCARD + TC_PATTERN3] == 0xff)
-			offset = OLDCARD;
-		if (module[TC_PATTERN0] == 0x55 && module[TC_PATTERN1] == 0x00
-		  && module[TC_PATTERN2] == 0xaa && module[TC_PATTERN3] == 0xff)
-			offset = 0;
-
-		if (offset != -1) {
-			tc_bus[slot].base_addr = (unsigned long)module;
-			for(i = 0; i < 8; i++) {
-				tc_bus[slot].firmware[i] = module[TC_FIRM_VER + offset + 4 * i];
-				tc_bus[slot].vendor[i] = module[TC_VENDOR + offset + 4 * i];
-				tc_bus[slot].name[i] = module[TC_MODULE + offset + 4 * i];
-			}
-			tc_bus[slot].firmware[8] = 0;
-			tc_bus[slot].vendor[8] = 0;
-			tc_bus[slot].name[8] = 0;
-			/*
-			 * Looks unneccesary, but we may change
-			 * TC? in the future
-			 */
-			switch (slot) {
-			case 0:
-				tc_bus[slot].interrupt = TC0;
-				break;
-			case 1:
-				tc_bus[slot].interrupt = TC1;
-				break;
-			case 2:
-				tc_bus[slot].interrupt = TC2;
-				break;
-			/*
-			 * Yuck! DS5000/200 onboard devices
-			 */
-			case 5:
-				tc_bus[slot].interrupt = SCSI_INT;
-				break;
-			case 6:
-				tc_bus[slot].interrupt = ETHER;
-				break;
-			default:
-				tc_bus[slot].interrupt = -1;
-				break;
-			}	
+
+		offset = OLDCARD;
+
+		err = 0;
+		err |= get_dbe(pattern[0], module + OLDCARD + TC_PATTERN0);
+		err |= get_dbe(pattern[1], module + OLDCARD + TC_PATTERN1);
+		err |= get_dbe(pattern[2], module + OLDCARD + TC_PATTERN2);
+		err |= get_dbe(pattern[3], module + OLDCARD + TC_PATTERN3);
+		if (err)
+			continue;
+
+		if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
+		    pattern[2] != 0xaa || pattern[3] != 0xff) {
+			offset = NEWCARD;
+
+			err = 0;
+			err |= get_dbe(pattern[0], module + TC_PATTERN0);
+			err |= get_dbe(pattern[1], module + TC_PATTERN1);
+			err |= get_dbe(pattern[2], module + TC_PATTERN2);
+			err |= get_dbe(pattern[3], module + TC_PATTERN3);
+			if (err)
+				continue;
 		}
-	}
 
-	dbe_board_handler = old_be_handler;
+		if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
+		    pattern[2] != 0xaa || pattern[3] != 0xff)
+			continue;
+
+		tc_bus[slot].base_addr = (unsigned long)module;
+		for(i = 0; i < 8; i++) {
+			tc_bus[slot].firmware[i] =
+				module[TC_FIRM_VER + offset + 4 * i];
+			tc_bus[slot].vendor[i] =
+				module[TC_VENDOR + offset + 4 * i];
+			tc_bus[slot].name[i] =
+				module[TC_MODULE + offset + 4 * i];
+		}
+		tc_bus[slot].firmware[8] = 0;
+		tc_bus[slot].vendor[8] = 0;
+		tc_bus[slot].name[8] = 0;
+		/*
+		 * Looks unneccesary, but we may change
+		 * TC? in the future
+		 */
+		switch (slot) {
+		case 0:
+			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC0];
+			break;
+		case 1:
+			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC1];
+			break;
+		case 2:
+			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC2];
+			break;
+		/*
+		 * Yuck! DS5000/200 onboard devices
+		 */
+		case 5:
+			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC5];
+			break;
+		case 6:
+			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC6];
+			break;
+		default:
+			tc_bus[slot].interrupt = -1;
+			break;
+		}
+	}
 }
 
 /*
@@ -221,7 +232,7 @@
  			i = 2;
 		else
  			i = 1;
- 		
+
  	        system_base = slot0addr + slot_size * (max_tcslot + i);
 
 #ifdef TC_DEBUG
@@ -242,4 +253,4 @@
 EXPORT_SYMBOL(get_tc_base_addr);
 EXPORT_SYMBOL(get_tc_irq_nr);
 EXPORT_SYMBOL(get_tc_speed);
-
+EXPORT_SYMBOL(system_base);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/tc/zs.c linux-2.4.20/drivers/tc/zs.c
--- linux-2.4.19/drivers/tc/zs.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/tc/zs.c	2002-10-29 11:18:35.000000000 +0000
@@ -6,7 +6,7 @@
  *
  * DECstation changes
  * Copyright (C) 1998-2000 Harald Koerfgen
- * Copyright (C) 2000,2001 Maciej W. Rozycki <macro@ds2.pg.gda.pl>
+ * Copyright (C) 2000, 2001, 2002  Maciej W. Rozycki <macro@ds2.pg.gda.pl>
  *
  * For the rest of the code the original Copyright applies:
  * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
@@ -67,7 +67,6 @@
 #include <asm/segment.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
-#include <asm/wbflush.h>
 #include <asm/bootinfo.h>
 #ifdef CONFIG_DECSTATION
 #include <asm/dec/interrupts.h>
@@ -96,7 +95,7 @@
 #define NUM_SERIAL	2		/* Max number of ZS chips supported */
 #define NUM_CHANNELS	(NUM_SERIAL * 2)	/* 2 channels per chip */
 #define CHANNEL_A_NR  (zs_parms->channel_a_offset > zs_parms->channel_b_offset)
-                                        /* Number of channel A in the chip */ 
+                                        /* Number of channel A in the chip */
 #define ZS_CHAN_IO_SIZE 8
 #define ZS_CLOCK        7372800 	/* Z8530 RTxC input clock rate */
 
@@ -107,7 +106,8 @@
 	unsigned long scc1;
 	int channel_a_offset;
 	int channel_b_offset;
-	int irq;
+	int irq0;
+	int irq1;
 	int clock;
 };
 
@@ -119,7 +119,8 @@
 	scc1 : SCC1,
 	channel_a_offset : 1,
 	channel_b_offset : 9,
-	irq : SERIAL,
+	irq0 : -1,
+	irq1 : -1,
 	clock : ZS_CLOCK
 };
 #endif
@@ -129,7 +130,8 @@
 	scc1 : UNI_SCC1,
 	channel_a_offset : 9,
 	channel_b_offset : 1,
-	irq : BAGET_SCC_IRQ,
+	irq0 : BAGET_SCC_IRQ,
+	irq1 : BAGET_SCC_IRQ,
 	clock : 14745000
 };
 #endif
@@ -263,7 +265,7 @@
 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
 	9600, 19200, 38400, 57600, 115200, 0 };
 
-/* 
+/*
  * Reading and writing Z8530 registers.
  */
 static inline unsigned char read_zsreg(struct dec_zschannel *channel,
@@ -273,7 +275,7 @@
 
 	if (reg != 0) {
 		*channel->control = reg & 0xf;
-		wbflush(); RECOVERY_DELAY;
+		fast_iob(); RECOVERY_DELAY;
 	}
 	retval = *channel->control;
 	RECOVERY_DELAY;
@@ -285,10 +287,10 @@
 {
 	if (reg != 0) {
 		*channel->control = reg & 0xf;
-		wbflush(); RECOVERY_DELAY;
+		fast_iob(); RECOVERY_DELAY;
 	}
 	*channel->control = value;
-	wbflush(); RECOVERY_DELAY;
+	fast_iob(); RECOVERY_DELAY;
 	return;
 }
 
@@ -305,7 +307,7 @@
 				unsigned char value)
 {
 	*channel->data = value;
-	wbflush(); RECOVERY_DELAY;
+	fast_iob(); RECOVERY_DELAY;
 	return;
 }
 
@@ -409,7 +411,7 @@
 		stat = read_zsreg(info->zs_channel, R1);
 		ch = read_zsdata(info->zs_channel);
 
-		if (!tty && !info->hook && !info->hook->rx_char)
+		if (!tty && (!info->hook || !info->hook->rx_char))
 			continue;
 
 		if (tty_break) {
@@ -456,7 +458,7 @@
 			(*info->hook->rx_char)(ch, flag);
 			return;
   		}
-		
+
 		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
 			static int flip_buf_ovf;
 			++flip_buf_ovf;
@@ -471,7 +473,9 @@
 
 		*tty->flip.flag_buf_ptr++ = flag;
 		*tty->flip.char_buf_ptr++ = ch;
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
 	ignore_char:
+#endif
 	}
 	if (tty)
 		tty_flip_buffer_push(tty);
@@ -522,9 +526,9 @@
 
 	if (info->zs_channel != info->zs_chan_a) {
 
-		/* FIXEM: Check for DCD transitions */
-		if (((stat ^ info->read_reg_zero) & DCD) != 0
-		    && info->tty && !C_CLOCAL(info->tty)) {
+		/* Check for DCD transitions */
+		if (info->tty && !C_CLOCAL(info->tty) &&
+		    ((stat ^ info->read_reg_zero) & DCD) != 0 ) {
 			if (stat & DCD) {
 				wake_up_interruptible(&info->open_wait);
 			} else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
@@ -575,7 +579,7 @@
 		shift = 0;	/* Channel B */
 
 	for (;;) {
-		zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift; 
+		zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift;
 		if ((zs_intreg & CHAN_IRQMASK) == 0)
 			break;
 
@@ -589,7 +593,7 @@
 			status_handle(info);
 		}
 	}
-	
+
 	/* Why do we need this ? */
 	write_zsreg(info->zs_channel, 0, RES_H_IUS);
 }
@@ -598,14 +602,14 @@
 void zs_dump (void) {
 	int i, j;
 	for (i = 0; i < zs_channels_found; i++) {
-		struct dec_zschannel *ch = &zs_channels[i]; 
+		struct dec_zschannel *ch = &zs_channels[i];
 		if ((long)ch->control == UNI_IO_BASE+UNI_SCC1A_CTRL) {
 			for (j = 0; j < 15; j++) {
-				printk("W%d = 0x%x\t", 
+				printk("W%d = 0x%x\t",
 				       j, (int)ch->curregs[j]);
 			}
 			for (j = 0; j < 15; j++) {
-				printk("R%d = 0x%x\t", 
+				printk("R%d = 0x%x\t",
 				       j, (int)read_zsreg(ch,j));
 			}
 			printk("\n\n");
@@ -634,7 +638,7 @@
 
 	if (serial_paranoia_check(info, tty->device, "rs_stop"))
 		return;
-	
+
 #if 1
 	save_flags(flags); cli();
 	if (info->zs_channel->curregs[5] & TxENAB) {
@@ -649,10 +653,10 @@
 {
 	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
 	unsigned long flags;
-	
+
 	if (serial_paranoia_check(info, tty->device, "rs_start"))
 		return;
-	
+
 	save_flags(flags); cli();
 #if 1
 	if (info->xmit_cnt && info->xmit_buf && !(info->zs_channel->curregs[5] & TxENAB)) {
@@ -685,7 +689,7 @@
 {
 	struct dec_serial	*info = (struct dec_serial *) private_;
 	struct tty_struct	*tty;
-	
+
 	tty = info->tty;
 	if (!tty)
 		return;
@@ -786,9 +790,9 @@
 	printk("Shutting down serial port %d (irq %d)....", info->line,
 	       info->irq);
 #endif
-	
+
 	save_flags(flags); cli(); /* Disable interrupts */
-	
+
 	if (info->xmit_buf) {
 		free_page((unsigned long) info->xmit_buf);
 		info->xmit_buf = 0;
@@ -854,7 +858,7 @@
 		brg = BPS_TO_BRG(info->zs_baud, zs_parms->clock/info->clk_divisor);
 		info->zs_channel->curregs[12] = (brg & 255);
 		info->zs_channel->curregs[13] = ((brg >> 8) & 255);
-		zs_rtsdtr(info, DTR, 1); 
+		zs_rtsdtr(info, DTR, 1);
 	} else {
 		zs_rtsdtr(info, RTS | DTR, 0);
 		return;
@@ -957,7 +961,7 @@
 
 	save_flags(flags);
 	while (1) {
-		cli();		
+		cli();
 		c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
 				   SERIAL_XMIT_SIZE - info->xmit_head));
 		if (c <= 0)
@@ -991,7 +995,7 @@
 {
 	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
 	int	ret;
-				
+
 	if (serial_paranoia_check(info, tty->device, "rs_write_room"))
 		return 0;
 	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
@@ -1003,7 +1007,7 @@
 static int rs_chars_in_buffer(struct tty_struct *tty)
 {
 	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-			
+
 	if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
 		return 0;
 	return info->xmit_cnt;
@@ -1012,7 +1016,7 @@
 static void rs_flush_buffer(struct tty_struct *tty)
 {
 	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-				
+
 	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
 		return;
 	cli();
@@ -1027,7 +1031,7 @@
 /*
  * ------------------------------------------------------------
  * rs_throttle()
- * 
+ *
  * This routine is called by the upper-layer tty layer to signal that
  * incoming characters should be throttled.
  * ------------------------------------------------------------
@@ -1039,14 +1043,14 @@
 
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
-	
+
 	printk("throttle %s: %d....\n", _tty_name(tty, buf),
 	       tty->ldisc.chars_in_buffer(tty));
 #endif
 
 	if (serial_paranoia_check(info, tty->device, "rs_throttle"))
 		return;
-	
+
 	if (I_IXOFF(tty)) {
 		save_flags(flags); cli();
 		info->x_char = STOP_CHAR(tty);
@@ -1067,14 +1071,14 @@
 
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
-	
+
 	printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
 	       tty->ldisc.chars_in_buffer(tty));
 #endif
 
 	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
 		return;
-	
+
 	if (I_IXOFF(tty)) {
 		save_flags(flags); cli();
 		if (info->x_char)
@@ -1171,7 +1175,7 @@
  * 	    release the bus after transmitting. This must be done when
  * 	    the transmit shift register is empty, not be done when the
  * 	    transmit holding register is empty.  This functionality
- * 	    allows an RS485 driver to be written in user space. 
+ * 	    allows an RS485 driver to be written in user space.
  */
 static int get_lsr_info(struct dec_serial * info, unsigned int *value)
 {
@@ -1232,7 +1236,7 @@
 		info->zs_chan_a->curregs[5] &= ~bits;
 		break;
 	case TIOCMSET:
-		info->zs_chan_a->curregs[5] = 
+		info->zs_chan_a->curregs[5] =
 			(info->zs_chan_a->curregs[5] & ~(DTR | RTS)) | bits;
 		break;
 	default:
@@ -1284,7 +1288,7 @@
 		if (tty->flags & (1 << TTY_IO_ERROR))
 		    return -EIO;
 	}
-	
+
 	switch (cmd) {
 		case TIOCMGET:
 			error = verify_area(VERIFY_WRITE, (void *) arg,
@@ -1322,7 +1326,7 @@
 			copy_from_user((struct dec_serial *) arg,
 				       info, sizeof(struct dec_serial));
 			return 0;
-			
+
 		default:
 			return -ENOIOCTLCMD;
 		}
@@ -1347,7 +1351,7 @@
 /*
  * ------------------------------------------------------------
  * rs_close()
- * 
+ *
  * This routine is called when the serial port gets closed.
  * Wait for the last remaining data to be sent.
  * ------------------------------------------------------------
@@ -1359,14 +1363,14 @@
 
 	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
 		return;
-	
+
 	save_flags(flags); cli();
-	
+
 	if (tty_hung_up_p(filp)) {
 		restore_flags(flags);
 		return;
 	}
-	
+
 #ifdef SERIAL_DEBUG_OPEN
 	printk("rs_close ttyS%02d, count = %d\n", info->line, info->count);
 #endif
@@ -1401,7 +1405,7 @@
 	if (info->flags & ZILOG_CALLOUT_ACTIVE)
 		info->callout_termios = *tty->termios;
 	/*
-	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * Now we wait for the transmit buffer to clear; and we notify
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	tty->closing = 1;
@@ -1542,7 +1546,7 @@
 		info->flags |= ZILOG_CALLOUT_ACTIVE;
 		return 0;
 	}
-	
+
 	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
@@ -1562,7 +1566,7 @@
 		if (tty->termios->c_cflag & CLOCAL)
 			do_clocal = 1;
 	}
-	
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -1577,7 +1581,7 @@
 	       info->line, info->count);
 #endif
 	cli();
-	if (!tty_hung_up_p(filp)) 
+	if (!tty_hung_up_p(filp))
 		info->count--;
 	sti();
 	info->blocked_open++;
@@ -1594,7 +1598,7 @@
 			if (info->flags & ZILOG_HUP_NOTIFY)
 				retval = -EAGAIN;
 			else
-				retval = -ERESTARTSYS;	
+				retval = -ERESTARTSYS;
 #else
 			retval = -EAGAIN;
 #endif
@@ -1627,7 +1631,7 @@
 		return retval;
 	info->flags |= ZILOG_NORMAL_ACTIVE;
 	return 0;
-}	
+}
 
 /*
  * This routine is called whenever a serial port is opened.  It
@@ -1693,7 +1697,7 @@
 	if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) {
 		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
 			*tty->termios = info->normal_termios;
-		else 
+		else
 			*tty->termios = info->callout_termios;
 		change_speed(info);
 	}
@@ -1719,7 +1723,7 @@
 
 static void __init show_serial_version(void)
 {
-	printk("DECstation Z8530 serial driver version 0.05\n");
+	printk("DECstation Z8530 serial driver version 0.07\n");
 }
 
 /*  Initialize Z8530s zs_channels
@@ -1737,7 +1741,7 @@
 		printk("Not on JUNKIO machine, skipping probe_sccs\n");
 		return;
 	}
-	
+
 	/*
 	 * When serial console is activated, tc_init has not been called yet
 	 * and system_base is undefined. Unfortunately we have to hardcode
@@ -1749,16 +1753,21 @@
 		system_base = 0xbf800000;
 		n_chips = 2;
 		zs_parms = &ds_parms;
+		zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
+		zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
 		break;
 	case MACH_DS5000_1XX:
 		system_base = 0xbc000000;
 		n_chips = 2;
 		zs_parms = &ds_parms;
+		zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
+		zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
 		break;
 	case MACH_DS5000_XX:
 		system_base = 0xbc000000;
 		n_chips = 1;
 		zs_parms = &ds_parms;
+		zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
 		break;
 #endif
 #ifdef CONFIG_BAGET_MIPS
@@ -1784,12 +1793,12 @@
 			/*
 			 * The sccs reside on the high byte of the 16 bit IOBUS
 			 */
-			zs_channels[n_channels].control = 
-				(volatile unsigned char *)system_base + 
-			  (0 == chip ? zs_parms->scc0 : zs_parms->scc1) + 
-			  (0 == channel ? zs_parms->channel_a_offset : 
+			zs_channels[n_channels].control =
+				(volatile unsigned char *)system_base +
+			  (0 == chip ? zs_parms->scc0 : zs_parms->scc1) +
+			  (0 == channel ? zs_parms->channel_a_offset :
 			                  zs_parms->channel_b_offset);
-			zs_channels[n_channels].data = 
+			zs_channels[n_channels].data =
 				zs_channels[n_channels].control + 4;
 
 #ifndef CONFIG_SERIAL_CONSOLE
@@ -1807,20 +1816,24 @@
 				       ZS_CHAN_IO_SIZE, "SCC");
 #endif
 			zs_soft[n_channels].zs_channel = &zs_channels[n_channels];
-			zs_soft[n_channels].irq = zs_parms->irq;
+			/* HACK alert! */
+			if (!(chip & 1))
+				zs_soft[n_channels].irq = zs_parms->irq0;
+			else
+				zs_soft[n_channels].irq = zs_parms->irq1;
 
-			/* 
+			/*
 			 *  Identification of channel A. Location of channel A
                          *  inside chip depends on mapping of internal address
 			 *  the chip decodes channels by.
-			 *  CHANNEL_A_NR returns either 0 (in case of 
+			 *  CHANNEL_A_NR returns either 0 (in case of
 			 *  DECstations) or 1 (in case of Baget).
 			 */
 			if (CHANNEL_A_NR == channel)
-				zs_soft[n_channels].zs_chan_a = 
+				zs_soft[n_channels].zs_chan_a =
 				    &zs_channels[n_channels+1-2*CHANNEL_A_NR];
 			else
-				zs_soft[n_channels].zs_chan_a = 
+				zs_soft[n_channels].zs_chan_a =
 				    &zs_channels[n_channels];
 
 			*pp = &zs_soft[n_channels];
@@ -1846,7 +1859,7 @@
 			write_zsreg(zs_soft[n].zs_chan_a, R9, 0);
 		}
 		load_zsregs(zs_soft[n].zs_channel, zs_soft[n].zs_channel->curregs);
-	} 
+	}
 	restore_flags(flags); */
 }
 
@@ -1932,34 +1945,30 @@
 	save_flags(flags); cli();
 
 	for (channel = 0; channel < zs_channels_found; ++channel) {
-		if (zs_soft[channel].hook &&
-		    zs_soft[channel].hook->init_channel)
-			(*zs_soft[channel].hook->init_channel)
-				(&zs_soft[channel]);
+		if (request_irq(zs_soft[channel].irq, rs_interrupt, SA_SHIRQ,
+				"scc", &zs_soft[channel]))
+			printk(KERN_ERR "decserial: can't get irq %d\n",
+			       zs_soft[channel].irq);
 
 		zs_soft[channel].clk_divisor = 16;
 		zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
-
-		if (request_irq(zs_parms->irq, rs_interrupt, SA_SHIRQ,
-				"SCC", &zs_soft[channel]))
-			printk(KERN_ERR "decserial: can't get irq %d\n",
-			       zs_parms->irq);
 	}
 
-	for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
-	{
-		if (info->hook && info->hook->init_info) {
-			(*info->hook->init_info)(info);
+	for (info = zs_chain, i = 0; info; info = info->zs_next, i++) {
+
+		/* Needed before interrupts are enabled. */
+		info->tty = 0;
+		info->x_char = 0;
+
+		if (info->hook && info->hook->init_info)
 			continue;
-		}
+
 		info->magic = SERIAL_MAGIC;
 		info->port = (int) info->zs_channel->control;
 		info->line = i;
-		info->tty = 0;
 		info->custom_divisor = 16;
 		info->close_delay = 50;
 		info->closing_wait = 3000;
-		info->x_char = 0;
 		info->event = 0;
 		info->count = 0;
 		info->blocked_open = 0;
@@ -1969,7 +1978,7 @@
 		info->normal_termios = serial_driver.init_termios;
 		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->close_wait);
-		printk("ttyS%02d at 0x%08x (irq = %d)", info->line, 
+		printk("ttyS%02d at 0x%08x (irq = %d)", info->line,
 		       info->port, info->irq);
 		printk(" is a Z85C30 SCC\n");
 		tty_register_devfs(&serial_driver, 0,
@@ -1981,6 +1990,18 @@
 
 	restore_flags(flags);
 
+	for (channel = 0; channel < zs_channels_found; ++channel) {
+		if (zs_soft[channel].hook &&
+		    zs_soft[channel].hook->init_channel)
+			(*zs_soft[channel].hook->init_channel)
+				(&zs_soft[channel]);
+	}
+
+	for (info = zs_chain, i = 0; info; info = info->zs_next, i++) {
+		if (info->hook && info->hook->init_info)
+			(*info->hook->init_info)(info);
+	}
+
 	return 0;
 }
 
@@ -2010,32 +2031,19 @@
 
 	if(chan) {
 		int loops = 10000;
-//		int nine = read_zsreg(chan, R9);
-
-		RECOVERY_DELAY;
-//        	write_zsreg(chan, R9, nine & ~MIE);
-               	wbflush();
-		RECOVERY_DELAY;
-
-        	while (!(*(chan->control) & Tx_BUF_EMP) && --loops)
-	        	RECOVERY_DELAY;
-
-                if (loops) {
-                        ret = 0;
-        	        *(chan->data) = ch;
-                	wbflush();
-			RECOVERY_DELAY;
-                } else
-                        ret = -EAGAIN;
 
-//        	write_zsreg(chan, R9, nine);
-               	wbflush();
-		RECOVERY_DELAY;
+		while (loops && !(read_zsreg(chan, 0) & Tx_BUF_EMP))
+			loops--;
 
-                return ret;
-        }
+		if (loops) {
+			write_zsdata(chan, ch);
+			ret = 0;
+		} else
+			ret = -EAGAIN;
 
-	return -ENODEV;
+		return ret;
+	} else
+		return -ENODEV;
 }
 
 static int
@@ -2047,17 +2055,17 @@
 	if(chan) {
                 int loops = 10000;
 
-                while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
-		        loops--;
+		while (loops && !(read_zsreg(chan, 0) & Rx_CH_AV))
+			loops--;
 
                 if (loops)
                         ret = read_zsdata(chan);
                 else
                         ret = -EAGAIN;
 
-                return ret;
-        } else
-                return -ENODEV;
+		return ret;
+	} else
+		return -ENODEV;
 }
 
 unsigned int register_zs_hook(unsigned int channel, struct zs_hook *hook)
@@ -2215,7 +2223,7 @@
 		break;
 	}
 	co->cflag = cflag;
-#if 1 
+#if 1
 	save_and_cli(flags);
 
 	/*
@@ -2321,7 +2329,7 @@
 	write_zsreg(chan, 9, nine);
 }
 
-static int kgdbhook_init_channel(struct dec_serial* info) 
+static int kgdbhook_init_channel(struct dec_serial* info)
 {
 	return 0;
 }
@@ -2330,7 +2338,7 @@
 {
 }
 
-static void kgdbhook_rx_char(struct dec_serial* info, 
+static void kgdbhook_rx_char(struct dec_serial* info,
 			     unsigned char ch, unsigned char stat)
 {
 	if (ch == 0x03 || ch == '$')
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/tc/zs.h linux-2.4.20/drivers/tc/zs.h
--- linux-2.4.19/drivers/tc/zs.h	2001-08-27 15:56:31.000000000 +0000
+++ linux-2.4.20/drivers/tc/zs.h	2002-10-29 11:18:36.000000000 +0000
@@ -38,7 +38,7 @@
 /*
  * Definitions for ZILOG_struct (and serial_struct) flags field
  */
-#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
+#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
 				   on the callout port */
 #define ZILOG_FOURPORT  0x0002	/* Set OU1, OUT2 per AST Fourport settings */
 #define ZILOG_SAK	0x0004	/* Secure Attention Key (Orange book) */
@@ -74,7 +74,7 @@
 #ifdef __KERNEL__
 /*
  * This is our internal structure for each serial port's state.
- * 
+ *
  * Many fields are paralleled by the structure used by the serial_struct
  * structure.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/telephony/ixj.c linux-2.4.20/drivers/telephony/ixj.c
--- linux-2.4.19/drivers/telephony/ixj.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/telephony/ixj.c	2002-10-29 11:18:32.000000000 +0000
@@ -2807,7 +2807,10 @@
 	};
 
 	while (len--)
-		*buff++ = table_ulaw2alaw[*(unsigned char *)buff];
+	{
+		*buff = table_ulaw2alaw[*(unsigned char *)buff];
+		buff++;
+	}
 }
 
 static void alaw2ulaw(unsigned char *buff, unsigned long len)
@@ -2849,7 +2852,10 @@
 	};
 
         while (len--)
-                *buff++ = table_alaw2ulaw[*(unsigned char *)buff];
+        {
+                *buff = table_alaw2ulaw[*(unsigned char *)buff];
+                buff++;
+	}
 }
 
 static ssize_t ixj_read(struct file * file_p, char *buf, size_t length, loff_t * ppos)
@@ -5944,7 +5950,7 @@
 	lcp = kmalloc(sizeof(IXJ_CADENCE), GFP_KERNEL);
 	if (lcp == NULL)
 		return -ENOMEM;
-	if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_CADENCE)) || (unsigned)lcp->elements_used >= ~0U/sizeof(IXJ_CADENCE) )
+	if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_CADENCE)) || (unsigned)lcp->elements_used >= ~0U/sizeof(IXJ_CADENCE_ELEMENT) )
         {
                 kfree(lcp);
                 return -EFAULT;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/CDCEther.c linux-2.4.20/drivers/usb/CDCEther.c
--- linux-2.4.19/drivers/usb/CDCEther.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/CDCEther.c	2002-10-29 11:18:32.000000000 +0000
@@ -148,7 +148,7 @@
 	// Give this to the USB subsystem so it can tell us 
 	// when more data arrives.
 	if ( (res = usb_submit_urb(&ether_dev->rx_urb)) ) {
-		warn( __FUNCTION__ " failed submit rx_urb %d", res);
+		warn("%s failed submit rx_urb %d", __FUNCTION__, res);
 	}
 	
 	// We are no longer busy, show us the frames!!!
@@ -379,7 +379,7 @@
 
 	// Turn on the USB and let the packets flow!!!
 	if ( (res = enable_net_traffic( ether_dev )) ) {
-		err( __FUNCTION__ "can't enable_net_traffic() - %d", res );
+		err("%s can't enable_net_traffic() - %d", __FUNCTION__, res );
 		return -EIO;
 	}
 
@@ -392,7 +392,7 @@
 	/* Put it out there so the device can send us stuff */
 	if ( (res = usb_submit_urb(&ether_dev->rx_urb)) ) {
 		/* Hmm...  Okay... */
-		warn( __FUNCTION__ " failed rx_urb %d", res );
+		warn( "%s failed rx_urb %d", __FUNCTION__, res );
 	}
 
 	if (ether_dev->properties & HAVE_NOTIFICATION_ELEMENT) {
@@ -406,7 +406,7 @@
 			ether_dev,
 			ether_dev->intr_interval);
 		if ( (res = usb_submit_urb(&ether_dev->intr_urb)) ) {
-			warn( __FUNCTION__ " failed intr_urb %d", res );
+			warn("%s failed intr_urb %d", __FUNCTION__, res );
 		}
 	}
 
@@ -497,14 +497,14 @@
 static void CDC_SetEthernetPacketFilter (ether_dev_t *ether_dev)
 {
 #if 0
-	devrequest *dr = &ether_dev->ctrl_dr;
+	struct usb_ctrlrequest *dr = &ether_dev->ctrl_dr;
 	int res;
 
-	dr->requesttype = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;
-	dr->request = SET_ETHERNET_PACKET_FILTER;
-	dr->value = cpu_to_le16(ether_dev->mode_flags);
-	dr->index = cpu_to_le16((u16)ether_dev->comm_interface);
-	dr->length = 0;
+	dr->bRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;
+	dr->bRequest = SET_ETHERNET_PACKET_FILTER;
+	dr->wValue = cpu_to_le16(ether_dev->mode_flags);
+	dr->wIndex = cpu_to_le16((u16)ether_dev->comm_interface);
+	dr->wLength = 0;
 
 	FILL_CONTROL_URB(&ether_dev->ctrl_urb,
 			ether_dev->usb,
@@ -515,7 +515,7 @@
 			setpktfilter_done,
 			ether_dev);
 	if ( (res = usb_submit_urb(&ether_dev->ctrl_urb)) ) {
-		warn( __FUNCTION__ " failed submit ctrl_urb %d", res);
+		warn("%s failed submit ctrl_urb %d", __FUNCTION__, res);
 	}
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/CDCEther.h linux-2.4.20/drivers/usb/CDCEther.h
--- linux-2.4.19/drivers/usb/CDCEther.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/CDCEther.h	2002-10-29 11:18:34.000000000 +0000
@@ -75,7 +75,7 @@
 	__u8			bNumberPowerFilters;
 	__u16			mode_flags;
 	int			intr_interval;
-	devrequest		ctrl_dr;
+	struct usb_ctrlrequest	ctrl_dr;
 	struct urb		rx_urb, tx_urb, intr_urb, ctrl_urb;
 	unsigned char		rx_buff[CDC_ETHER_MAX_MTU] __attribute__((aligned(L1_CACHE_BYTES)));
 	unsigned char		tx_buff[CDC_ETHER_MAX_MTU] __attribute__((aligned(L1_CACHE_BYTES)));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/Config.in linux-2.4.20/drivers/usb/Config.in
--- linux-2.4.19/drivers/usb/Config.in	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/Config.in	2002-10-29 11:18:38.000000000 +0000
@@ -33,6 +33,7 @@
    dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
    dep_tristate '    EMI 2|6 USB Audio interface support' CONFIG_USB_EMI26 $CONFIG_USB_AUDIO
    dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB MIDI support' CONFIG_USB_MIDI $CONFIG_USB
    if [ "$CONFIG_SCSI" = "n" ]; then
       comment '  SCSI support is needed for USB Storage'
    fi
@@ -44,6 +45,7 @@
       dep_mbool '    Microtech CompactFlash/SmartMedia support' CONFIG_USB_STORAGE_DPCM $CONFIG_USB_STORAGE
       dep_mbool '    HP CD-Writer 82xx support' CONFIG_USB_STORAGE_HP8200e $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
       dep_mbool '    SanDisk SDDR-09 (and other SmartMedia) support' CONFIG_USB_STORAGE_SDDR09 $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
+      dep_mbool '    SanDisk SDDR-55 SmartMedia support' CONFIG_USB_STORAGE_SDDR55 $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
       dep_mbool '    Lexar Jumpshot Compact Flash Reader' CONFIG_USB_STORAGE_JUMPSHOT $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
    dep_tristate '  USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
    dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
@@ -59,6 +61,7 @@
       dep_tristate '  USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT
       dep_tristate '  USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT
    fi
+   dep_tristate '  Aiptek 6000U/8000U tablet support' CONFIG_USB_AIPTEK $CONFIG_USB $CONFIG_INPUT
    dep_tristate '  Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
 
    comment 'USB Imaging devices'
@@ -101,6 +104,8 @@
    comment 'USB Miscellaneous drivers'
    dep_tristate '  USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
    dep_tristate '  USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD $CONFIG_USB $CONFIG_EXPERIMENTAL
+   dep_tristate '  Texas Instruments Graph Link USB (aka SilverLink) cable support' CONFIG_USB_TIGL $CONFIG_USB
    dep_tristate '  Tieman Voyager USB Braille display support (EXPERIMENTAL)' CONFIG_USB_BRLVGER $CONFIG_USB $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB LCD device support' CONFIG_USB_LCD $CONFIG_USB
 fi
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/Makefile linux-2.4.20/drivers/usb/Makefile
--- linux-2.4.19/drivers/usb/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/Makefile	2002-10-29 11:18:39.000000000 +0000
@@ -62,6 +62,7 @@
 obj-$(CONFIG_USB_MOUSE)		+= usbmouse.o
 obj-$(CONFIG_USB_HID)		+= hid.o
 obj-$(CONFIG_USB_KBD)		+= usbkbd.o
+obj-$(CONFIG_USB_AIPTEK)	+= aiptek.o
 obj-$(CONFIG_USB_WACOM)		+= wacom.o
 
 obj-$(CONFIG_USB_SCANNER)	+= scanner.o
@@ -69,6 +70,7 @@
 obj-$(CONFIG_USB_PRINTER)	+= printer.o
 obj-$(CONFIG_USB_AUDIO)		+= audio.o
 obj-$(CONFIG_USB_EMI26)		+= emi26.o
+obj-$(CONFIG_USB_MIDI)		+= usb-midi.o
 obj-$(CONFIG_USB_IBMCAM)	+= ibmcam.o usbvideo.o ultracam.o
 obj-$(CONFIG_USB_PWC)		+= pwc.o
 obj-$(CONFIG_USB_DC2XX)		+= dc2xx.o
@@ -85,6 +87,7 @@
 obj-$(CONFIG_USB_KAWETH)        += kaweth.o
 obj-$(CONFIG_USB_CDCETHER)	+= CDCEther.o
 obj-$(CONFIG_USB_RIO500)	+= rio500.o
+obj-$(CONFIG_USB_TIGL)          += tiglusb.o
 obj-$(CONFIG_USB_DSBR)		+= dsbr100.o
 obj-$(CONFIG_USB_MICROTEK)	+= microtek.o
 obj-$(CONFIG_USB_HPUSBSCSI)	+= hpusbscsi.o
@@ -92,6 +95,7 @@
 obj-$(CONFIG_USB_USBNET)	+= usbnet.o
 obj-$(CONFIG_USB_AUERSWALD)	+= auerswald.o
 obj-$(CONFIG_USB_BRLVGER)	+= brlvger.o
+obj-$(CONFIG_USB_LCD)		+= usblcd.o
 
 # Object files in subdirectories
 mod-subdirs	:= serial hcd
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/acm.c linux-2.4.20/drivers/usb/acm.c
--- linux-2.4.19/drivers/usb/acm.c	2001-10-05 19:06:08.000000000 +0000
+++ linux-2.4.20/drivers/usb/acm.c	2002-10-29 11:18:32.000000000 +0000
@@ -184,7 +184,7 @@
 static void acm_ctrl_irq(struct urb *urb)
 {
 	struct acm *acm = urb->context;
-	devrequest *dr = urb->transfer_buffer;
+	struct usb_ctrlrequest *dr = urb->transfer_buffer;
 	unsigned char *data = (unsigned char *)(dr + 1);
 	int newctrl;
 
@@ -195,7 +195,7 @@
 		return;
 	}
 
-	switch (dr->request) {
+	switch (dr->bRequest) {
 
 		case ACM_IRQ_NETWORK:
 
@@ -223,7 +223,7 @@
 
 		default:
 			dbg("unknown control event received: request %d index %d len %d data0 %d data1 %d",
-				dr->request, dr->index, dr->length, data[0], data[1]);
+				dr->bRequest, dr->wIndex, dr->wLength, data[0], data[1]);
 			return;
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/aiptek.c linux-2.4.20/drivers/usb/aiptek.c
--- linux-2.4.19/drivers/usb/aiptek.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/aiptek.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,332 @@
+/*
+ *  Native support for the Aiptek 8000U
+ *
+ *  Copyright (c) 2001 Chris Atenasio		<chris@crud.net>
+ *
+ *  based on wacom.c by
+ *     Vojtech Pavlik      <vojtech@suse.cz>
+ *     Andreas Bach Aaen   <abach@stofanet.dk>
+ *     Clifford Wolf       <clifford@clifford.at>
+ *     Sam Mosel           <sam.mosel@computer.org>
+ *     James E. Blair      <corvus@gnu.org>
+ *     Daniel Egger        <egger@suse.de>
+ *
+ *
+ *  Many thanks to Oliver Kuechemann for his support.
+ *
+ *  ChangeLog:
+ *      v0.1 - Initial release
+ *      v0.2 - Hack to get around fake event 28's.
+ *      v0.3 - Make URB dynamic (Bryan W. Headley, Jun-8-2002)
+ */
+
+/*
+ * 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
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.3"
+#define DRIVER_AUTHOR "Chris Atenasio <chris@crud.net>"
+#define DRIVER_DESC "USB Aiptek 6000U/8000U tablet driver (Linux 2.4.x)"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Aiptek status packet:
+ *
+ *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
+ * byte0   0     0     0     0     0     0     1     0
+ * byte1  X7    X6    X5    X4    X3    X2    X1    X0
+ * byte2  X15   X14   X13   X12   X11   X10   X9    X8
+ * byte3  Y7    Y6    Y5    Y4    Y3    Y2    Y1    Y0
+ * byte4  Y15   Y14   Y13   Y12   Y11   Y10   Y9    Y8
+ * byte5   *     *     *    BS2   BS1   Tip   DV    IR
+ * byte6  P7    P6    P5    P4    P3    P2    P1    P0
+ * byte7  P15   P14   P13   P12   P11   P10   P9    P8
+ *
+ * IR: In Range = Proximity on
+ * DV = Data Valid
+ *
+ * 
+ * Command Summary:
+ *
+ * Command/Data    Description     Return Bytes    Return Value
+ * 0x10/0x00       SwitchToMouse       0
+ * 0x10/0x01       SwitchToTablet      0
+ * 0x18/0x04       Resolution500LPI    0
+ * 0x17/0x00       FilterOn            0
+ * 0x12/0xFF       AutoGainOn          0
+ * 0x01/0x00       GetXExtension       2           MaxX
+ * 0x01/0x01       GetYExtension       2           MaxY
+ * 0x02/0x00       GetModelCode        2           ModelCode = LOBYTE
+ * 0x03/0x00       GetODMCode          2           ODMCode
+ * 0x08/0x00       GetPressureLevels   2           =512
+ * 0x04/0x00       GetFirmwareVersion  2           Firmware Version
+ *
+ *
+ * To initialize the tablet:
+ *
+ * (1) Send command Resolution500LPI
+ * (2) Option Commands (GetXExtension, GetYExtension)
+ * (3) Send command SwitchToTablet
+ */
+
+#define USB_VENDOR_ID_AIPTEK   0x08ca
+
+struct aiptek_features {
+	char *name;
+	int pktlen;
+	int x_max;
+	int y_max;
+	int pressure_min;
+	int pressure_max;
+	void (*irq) (struct urb * urb);
+	unsigned long evbit;
+	unsigned long absbit;
+	unsigned long relbit;
+	unsigned long btnbit;
+	unsigned long digibit;
+};
+
+struct aiptek {
+	signed char data[10];
+	struct input_dev dev;
+	struct usb_device *usbdev;
+	struct urb *irq;
+	struct aiptek_features *features;
+	int tool;
+	int open;
+};
+
+static void
+aiptek_irq(struct urb *urb)
+{
+	struct aiptek *aiptek = urb->context;
+	unsigned char *data = aiptek->data;
+	struct input_dev *dev = &aiptek->dev;
+	int x;
+	int y;
+	int pressure;
+	int proximity;
+
+	if (urb->status)
+		return;
+
+	if ((data[0] & 2) == 0) {
+		dbg("received unknown report #%d", data[0]);
+	}
+
+	proximity = data[5] & 0x01;
+	input_report_key(dev, BTN_TOOL_PEN, proximity);
+
+	x = ((__u32) data[1]) | ((__u32) data[2] << 8);
+	y = ((__u32) data[3]) | ((__u32) data[4] << 8);
+	pressure = ((__u32) data[6]) | ((__u32) data[7] << 8);
+	pressure -= aiptek->features->pressure_min;
+
+	if (pressure < 0) {
+		pressure = 0;
+	}
+
+	if (proximity) {
+		input_report_abs(dev, ABS_X, x);
+		input_report_abs(dev, ABS_Y, y);
+		input_report_abs(dev, ABS_PRESSURE, pressure);
+		input_report_key(dev, BTN_TOUCH, data[5] & 0x04);
+		input_report_key(dev, BTN_STYLUS, data[5] & 0x08);
+		input_report_key(dev, BTN_STYLUS2, data[5] & 0x10);
+	}
+
+}
+
+struct aiptek_features aiptek_features[] = {
+	{"Aiptek 6000U/8000U", 
+	 8, 3000, 2250, 26, 511, aiptek_irq, 0, 0, 0, 0},
+	{NULL, 0}
+};
+
+struct usb_device_id aiptek_ids[] = {
+	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x20), driver_info:0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, aiptek_ids);
+
+static int
+aiptek_open(struct input_dev *dev)
+{
+	struct aiptek *aiptek = dev->private;
+
+	if (aiptek->open++)
+		return 0;
+
+	aiptek->irq->dev = aiptek->usbdev;
+	if (usb_submit_urb(aiptek->irq))
+		return -EIO;
+
+	return 0;
+}
+
+static void
+aiptek_close(struct input_dev *dev)
+{
+	struct aiptek *aiptek = dev->private;
+
+	if (!--aiptek->open)
+		usb_unlink_urb(aiptek->irq);
+}
+
+static void
+aiptek_command(struct usb_device *dev, unsigned int ifnum,
+	       unsigned char command, unsigned char data)
+{
+	__u8 buf[3];
+
+	buf[0] = 4;
+	buf[1] = command;
+	buf[2] = data;
+
+	if (usb_set_report(dev, ifnum, 3, 2, buf, 3) != 3) {
+		dbg("aiptek_command: 0x%x 0x%x\n", command, data);
+	}
+}
+
+static void*
+aiptek_probe(struct usb_device *dev, unsigned int ifnum,
+	     const struct usb_device_id *id)
+{
+	struct usb_endpoint_descriptor *endpoint;
+	struct aiptek *aiptek;
+
+	if (!(aiptek = kmalloc(sizeof (struct aiptek), GFP_KERNEL)))
+		return NULL;
+
+	memset(aiptek, 0, sizeof (struct aiptek));
+
+	aiptek->irq = usb_alloc_urb(0);
+	if (!aiptek->irq) {
+		kfree(aiptek);
+		return NULL;
+	}
+
+	// Resolution500LPI
+	aiptek_command(dev, ifnum, 0x18, 0x04);
+
+	// SwitchToTablet
+	aiptek_command(dev, ifnum, 0x10, 0x01);
+
+	aiptek->features = aiptek_features + id->driver_info;
+
+	aiptek->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC) |
+	    aiptek->features->evbit;
+
+	aiptek->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) |
+	    BIT(ABS_MISC) | aiptek->features->absbit;
+
+	aiptek->dev.relbit[0] |= aiptek->features->relbit;
+
+	aiptek->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
+	    BIT(BTN_MIDDLE) | aiptek->features->btnbit;
+
+	aiptek->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) |
+	    BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOUCH) |
+	    BIT(BTN_STYLUS) | BIT(BTN_STYLUS2) | aiptek->features->digibit;
+
+	aiptek->dev.mscbit[0] = BIT(MSC_SERIAL);
+
+	aiptek->dev.absmax[ABS_X] = aiptek->features->x_max;
+	aiptek->dev.absmax[ABS_Y] = aiptek->features->y_max;
+	aiptek->dev.absmax[ABS_PRESSURE] = aiptek->features->pressure_max -
+	    aiptek->features->pressure_min;
+
+	aiptek->dev.absfuzz[ABS_X] = 0;
+	aiptek->dev.absfuzz[ABS_Y] = 0;
+
+	aiptek->dev.private = aiptek;
+	aiptek->dev.open = aiptek_open;
+	aiptek->dev.close = aiptek_close;
+
+	aiptek->dev.name = aiptek->features->name;
+	aiptek->dev.idbus = BUS_USB;
+	aiptek->dev.idvendor = dev->descriptor.idVendor;
+	aiptek->dev.idproduct = dev->descriptor.idProduct;
+	aiptek->dev.idversion = dev->descriptor.bcdDevice;
+	aiptek->usbdev = dev;
+
+	endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
+
+	FILL_INT_URB(aiptek->irq,
+		  dev,
+		  usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+		         aiptek->data,
+		  aiptek->features->pktlen,
+		         aiptek->features->irq,
+		  aiptek,
+		  endpoint->bInterval);
+
+	input_register_device(&aiptek->dev);
+
+	printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
+	       aiptek->dev.number, aiptek->features->name, dev->bus->busnum,
+	       dev->devnum, ifnum);
+
+	return aiptek;
+}
+
+static void
+aiptek_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct aiptek *aiptek = ptr;
+	usb_unlink_urb(aiptek->irq);
+	input_unregister_device(&aiptek->dev);
+	usb_free_urb(aiptek->irq);
+	kfree(aiptek);
+}
+
+static struct usb_driver aiptek_driver = {
+	name:"aiptek",
+	probe:aiptek_probe,
+	disconnect:aiptek_disconnect,
+	id_table:aiptek_ids,
+};
+
+static int __init
+aiptek_init(void)
+{
+	usb_register(&aiptek_driver);
+	info(DRIVER_VERSION " " DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+	return 0;
+}
+
+static void __exit
+aiptek_exit(void)
+{
+	usb_deregister(&aiptek_driver);
+}
+
+module_init(aiptek_init);
+module_exit(aiptek_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/audio.c linux-2.4.20/drivers/usb/audio.c
--- linux-2.4.19/drivers/usb/audio.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/audio.c	2002-10-29 11:18:50.000000000 +0000
@@ -297,13 +297,13 @@
 #define FLG_CONNECTED    32
 
 struct my_data_urb {
-	urb_t urb;
-	iso_packet_descriptor_t isoframe[DESCFRAMES];
+	struct urb urb;
+	struct iso_packet_descriptor isoframe[DESCFRAMES];
 };
 
 struct my_sync_urb {
-	urb_t urb;
-	iso_packet_descriptor_t isoframe[SYNCFRAMES];
+	struct urb urb;
+	struct iso_packet_descriptor isoframe[SYNCFRAMES];
 };
 
 
@@ -833,7 +833,7 @@
 	}
 }		
 
-static int usbin_prepare_desc(struct usbin *u, purb_t urb)
+static int usbin_prepare_desc(struct usbin *u, struct urb *urb)
 {
 	unsigned int i, maxsize, offs;
 
@@ -850,7 +850,7 @@
  * return value: 0 if descriptor should be restarted, -1 otherwise
  * convert sample format on the fly if necessary
  */
-static int usbin_retire_desc(struct usbin *u, purb_t urb)
+static int usbin_retire_desc(struct usbin *u, struct urb *urb)
 {
 	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, dmafree;
 	unsigned char *cp;
@@ -930,7 +930,7 @@
 /*
  * we output sync data
  */
-static int usbin_sync_prepare_desc(struct usbin *u, purb_t urb)
+static int usbin_sync_prepare_desc(struct usbin *u, struct urb *urb)
 {
 	unsigned char *cp = urb->transfer_buffer;
 	unsigned int i, offs;
@@ -948,7 +948,7 @@
 /*
  * return value: 0 if descriptor should be restarted, -1 otherwise
  */
-static int usbin_sync_retire_desc(struct usbin *u, purb_t urb)
+static int usbin_sync_retire_desc(struct usbin *u, struct urb *urb)
 {
 	unsigned int i;
 	
@@ -996,7 +996,7 @@
 {
 	struct usb_device *dev = as->state->usbdev;
 	struct usbin *u = &as->usbin;
-	purb_t urb;
+	struct urb *urb;
 	unsigned long flags;
 	unsigned int maxsze, bufsz;
 
@@ -1186,7 +1186,7 @@
 	}
 }		
 
-static int usbout_prepare_desc(struct usbout *u, purb_t urb)
+static int usbout_prepare_desc(struct usbout *u, struct urb *urb)
 {
 	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, offs;
 	unsigned char *cp = urb->transfer_buffer;
@@ -1238,7 +1238,7 @@
 /*
  * return value: 0 if descriptor should be restarted, -1 otherwise
  */
-static int usbout_retire_desc(struct usbout *u, purb_t urb)
+static int usbout_retire_desc(struct usbout *u, struct urb *urb)
 {
 	unsigned int i;
 
@@ -1285,7 +1285,7 @@
 	spin_unlock_irqrestore(&as->lock, flags);
 }
 
-static int usbout_sync_prepare_desc(struct usbout *u, purb_t urb)
+static int usbout_sync_prepare_desc(struct usbout *u, struct urb *urb)
 {
 	unsigned int i, offs;
 
@@ -1299,7 +1299,7 @@
 /*
  * return value: 0 if descriptor should be restarted, -1 otherwise
  */
-static int usbout_sync_retire_desc(struct usbout *u, purb_t urb)
+static int usbout_sync_retire_desc(struct usbout *u, struct urb *urb)
 {
 	unsigned char *cp = urb->transfer_buffer;
 	unsigned int f, i;
@@ -1361,7 +1361,7 @@
 {
 	struct usb_device *dev = as->state->usbdev;
 	struct usbout *u = &as->usbout;
-	purb_t urb;
+	struct urb *urb;
 	unsigned long flags;
 	unsigned int maxsze, bufsz;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/auerswald.c linux-2.4.20/drivers/usb/auerswald.c
--- linux-2.4.19/drivers/usb/auerswald.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/auerswald.c	2002-10-29 11:18:31.000000000 +0000
@@ -2,7 +2,7 @@
 /*
  *      auerswald.c  --  Auerswald PBX/System Telephone usb driver.
  *
- *      Copyright (C) 2001  Wolfgang Mes (wmues@nexgo.de)
+ *      Copyright (C) 2001  Wolfgang Mes (wolfgang@iksw-muees.de)
  *
  *      Very much code of this driver is borrowed from dabusb.c (Deti Fliegl)
  *      and from the USB Skeleton driver (Greg Kroah-Hartman). Thank you.
@@ -50,7 +50,7 @@
 /*-------------------------------------------------------------------*/
 /* Version Information */
 #define DRIVER_VERSION "0.9.11"
-#define DRIVER_AUTHOR  "Wolfgang Mes <wmues@nexgo.de>"
+#define DRIVER_AUTHOR  "Wolfgang Mes <wolfgang@iksw-muees.de>"
 #define DRIVER_DESC    "Auerswald PBX/System Telephone usb driver"
 
 /*-------------------------------------------------------------------*/
@@ -176,7 +176,7 @@
 typedef struct
 {
         struct auerchain *chain;        /* pointer to the chain to which this element belongs */
-        urb_t * urbp;                   /* pointer to attached urb */
+        struct urb * urbp;                   /* pointer to attached urb */
         void *context;                  /* saved URB context */
         usb_complete_t complete;        /* saved URB completion function */
         struct list_head list;          /* to include element into a list */
@@ -206,8 +206,8 @@
         char *bufp;                     /* reference to allocated data buffer */
         unsigned int len;               /* number of characters in data buffer */
 	unsigned int retries;		/* for urb retries */
-        devrequest *dr;                 /* for setup data in control messages */
-        urb_t * urbp;                   /* USB urb */
+        struct usb_ctrlrequest *dr;                 /* for setup data in control messages */
+        struct urb * urbp;                   /* USB urb */
         struct auerbufctl *list;        /* pointer to list */
         struct list_head buff_list;     /* reference to next buffer in list */
 } auerbuf_t,*pauerbuf_t;
@@ -244,7 +244,7 @@
 	int			open_count;	    /* count the number of open character channels */
         char 			dev_desc[AUSI_DLEN];/* for storing a textual description */
         unsigned int 		maxControlLength;   /* max. Length of control paket (without header) */
-        urb_t * 		inturbp;            /* interrupt urb */
+        struct urb * 		inturbp;            /* interrupt urb */
         char *			intbufp;            /* data buffer for interrupt urb */
 	unsigned int 		irqsize;	    /* size of interrupt endpoint 1 */
         struct auerchain 	controlchain;  	    /* for chaining of control messages */
@@ -281,7 +281,7 @@
 
 /*-------------------------------------------------------------------*/
 /* Forwards */
-static void auerswald_ctrlread_complete (urb_t * urb);
+static void auerswald_ctrlread_complete (struct urb * urb);
 static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp);
 
 
@@ -290,7 +290,7 @@
 /* --------------------------                                        */
 
 /* completion function for chained urbs */
-static void auerchain_complete (urb_t * urb)
+static void auerchain_complete (struct urb * urb)
 {
 	unsigned long flags;
         int result;
@@ -357,7 +357,7 @@
    this function may be called from completion context or from user space!
    early = 1 -> submit in front of chain
 */
-static int auerchain_submit_urb_list (pauerchain_t acp, urb_t * urb, int early)
+static int auerchain_submit_urb_list (pauerchain_t acp, struct urb * urb, int early)
 {
         int result;
         unsigned long flags;
@@ -431,7 +431,7 @@
 /* submit function for chained urbs
    this function may be called from completion context or from user space!
 */
-static int auerchain_submit_urb (pauerchain_t acp, urb_t * urb)
+static int auerchain_submit_urb (pauerchain_t acp, struct urb * urb)
 {
 	return auerchain_submit_urb_list (acp, urb, 0);
 }
@@ -440,10 +440,10 @@
    the result is 0 if the urb is cancelled, or -EINPROGRESS if
    USB_ASYNC_UNLINK is set and the function is successfully started.
 */
-static int auerchain_unlink_urb (pauerchain_t acp, urb_t * urb)
+static int auerchain_unlink_urb (pauerchain_t acp, struct urb * urb)
 {
 	unsigned long flags;
-        urb_t * urbp;
+        struct urb * urbp;
         pauerchainelement_t acep;
         struct list_head *tmp;
 
@@ -499,7 +499,7 @@
 static void auerchain_unlink_all (pauerchain_t acp)
 {
 	unsigned long flags;
-        urb_t * urbp;
+        struct urb * urbp;
         pauerchainelement_t acep;
 
         dbg ("auerchain_unlink_all called");
@@ -605,7 +605,7 @@
 
 
 /* completion handler for synchronous chained URBs */
-static void auerchain_blocking_completion (urb_t *urb)
+static void auerchain_blocking_completion (struct urb *urb)
 {
 	pauerchain_chs_t pchs = (pauerchain_chs_t)urb->context;
 	pchs->done = 1;
@@ -615,7 +615,7 @@
 
 
 /* Starts chained urb and waits for completion or timeout */
-static int auerchain_start_wait_urb (pauerchain_t acp, urb_t *urb, int timeout, int* actual_length)
+static int auerchain_start_wait_urb (pauerchain_t acp, struct urb *urb, int timeout, int* actual_length)
 {
 	DECLARE_WAITQUEUE (wait, current);
 	auerchain_chs_t chs;
@@ -690,12 +690,12 @@
 			          __u16 value, __u16 index, void *data, __u16 size, int timeout)
 {
 	int ret;
-	devrequest *dr;
-	urb_t *urb;
+	struct usb_ctrlrequest *dr;
+	struct urb *urb;
         int length;
 
         dbg ("auerchain_control_msg");
-        dr = kmalloc (sizeof (devrequest), GFP_KERNEL);
+        dr = kmalloc (sizeof (struct usb_ctrlrequest), GFP_KERNEL);
 	if (!dr)
 		return -ENOMEM;
 	urb = usb_alloc_urb (0);
@@ -704,11 +704,11 @@
 		return -ENOMEM;
         }
 
-	dr->requesttype = requesttype;
-	dr->request = request;
-	dr->value  = cpu_to_le16 (value);
-	dr->index  = cpu_to_le16 (index);
-	dr->length = cpu_to_le16 (size);
+	dr->bRequestType = requesttype;
+	dr->bRequest = request;
+	dr->wValue  = cpu_to_le16 (value);
+	dr->wIndex  = cpu_to_le16 (index);
+	dr->wLength = cpu_to_le16 (size);
 
 	FILL_CONTROL_URB (urb, dev, pipe, (unsigned char*)dr, data, size,    /* build urb */
 		          (usb_complete_t)auerchain_blocking_completion,0);
@@ -799,7 +799,7 @@
                 INIT_LIST_HEAD (&bep->buff_list);
                 bep->bufp = (char *) kmalloc (bufsize, GFP_KERNEL);
                 if (!bep->bufp) goto bl_fail;
-                bep->dr = (devrequest *) kmalloc (sizeof (devrequest), GFP_KERNEL);
+                bep->dr = (struct usb_ctrlrequest *) kmalloc (sizeof (struct usb_ctrlrequest), GFP_KERNEL);
                 if (!bep->dr) goto bl_fail;
                 bep->urbp = usb_alloc_urb (0);
                 if (!bep->urbp) goto bl_fail;
@@ -874,7 +874,7 @@
 }
 
 /* Completion of asynchronous write block */
-static void auerchar_ctrlwrite_complete (urb_t * urb)
+static void auerchar_ctrlwrite_complete (struct urb * urb)
 {
 	pauerbuf_t bp = (pauerbuf_t) urb->context;
 	pauerswald_t cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
@@ -887,7 +887,7 @@
 }
 
 /* Completion handler for dummy retry packet */
-static void auerswald_ctrlread_wretcomplete (urb_t * urb)
+static void auerswald_ctrlread_wretcomplete (struct urb * urb)
 {
         pauerbuf_t bp = (pauerbuf_t) urb->context;
         pauerswald_t cp;
@@ -907,13 +907,13 @@
 	}
 
 	/* fill the control message */
-	bp->dr->requesttype = AUT_RREQ;
-	bp->dr->request     = AUV_RBLOCK;
-	bp->dr->length      = bp->dr->value;	/* temporary stored */
-	bp->dr->value       = cpu_to_le16 (1);	/* Retry Flag */
+	bp->dr->bRequestType = AUT_RREQ;
+	bp->dr->bRequest     = AUV_RBLOCK;
+	bp->dr->wLength      = bp->dr->wValue;	/* temporary stored */
+	bp->dr->wValue       = cpu_to_le16 (1);	/* Retry Flag */
 	/* bp->dr->index    = channel id;          remains */
 	FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_rcvctrlpipe (cp->usbdev, 0),
-                          (unsigned char*)bp->dr, bp->bufp, le16_to_cpu (bp->dr->length),
+                          (unsigned char*)bp->dr, bp->bufp, le16_to_cpu (bp->dr->wLength),
 		          (usb_complete_t)auerswald_ctrlread_complete,bp);
 
 	/* submit the control msg as next paket */
@@ -926,7 +926,7 @@
 }
 
 /* completion handler for receiving of control messages */
-static void auerswald_ctrlread_complete (urb_t * urb)
+static void auerswald_ctrlread_complete (struct urb * urb)
 {
         unsigned int  serviceid;
         pauerswald_t  cp;
@@ -955,11 +955,11 @@
 		bp->retries++;
 		dbg ("Retry count = %d", bp->retries);
 		/* send a long dummy control-write-message to allow device firmware to react */
-		bp->dr->requesttype = AUT_WREQ;
-		bp->dr->request     = AUV_DUMMY;
-		bp->dr->value       = bp->dr->length; /* temporary storage */
+		bp->dr->bRequestType = AUT_WREQ;
+		bp->dr->bRequest     = AUV_DUMMY;
+		bp->dr->wValue       = bp->dr->wLength; /* temporary storage */
 		// bp->dr->index    channel ID remains
-		bp->dr->length      = cpu_to_le16 (32); /* >= 8 bytes */
+		bp->dr->wLength      = cpu_to_le16 (32); /* >= 8 bytes */
 		FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_sndctrlpipe (cp->usbdev, 0),
   			(unsigned char*)bp->dr, bp->bufp, 32,
 	   		(usb_complete_t)auerswald_ctrlread_wretcomplete,bp);
@@ -972,7 +972,7 @@
                		auerswald_ctrlread_wretcomplete (bp->urbp);
 		}
                 return;
-        }
+	} 
 
         /* get the actual bytecount (incl. headerbyte) */
         bp->len = urb->actual_length;
@@ -998,7 +998,7 @@
    messages from the USB device.
 */
 /* int completion handler. */
-static void auerswald_int_complete (urb_t * urb)
+static void auerswald_int_complete (struct urb * urb)
 {
         unsigned long flags;
         unsigned  int channelid;
@@ -1074,11 +1074,11 @@
         }
 
 	/* fill the control message */
-        bp->dr->requesttype = AUT_RREQ;
-	bp->dr->request     = AUV_RBLOCK;
-	bp->dr->value       = cpu_to_le16 (0);
-	bp->dr->index       = cpu_to_le16 (channelid | AUH_DIRECT | AUH_UNSPLIT);
-	bp->dr->length      = cpu_to_le16 (bytecount);
+        bp->dr->bRequestType = AUT_RREQ;
+	bp->dr->bRequest     = AUV_RBLOCK;
+	bp->dr->wValue       = cpu_to_le16 (0);
+	bp->dr->wIndex       = cpu_to_le16 (channelid | AUH_DIRECT | AUH_UNSPLIT);
+	bp->dr->wLength      = cpu_to_le16 (bytecount);
 	FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_rcvctrlpipe (cp->usbdev, 0),
                           (unsigned char*)bp->dr, bp->bufp, bytecount,
 		          (usb_complete_t)auerswald_ctrlread_complete,bp);
@@ -1327,7 +1327,7 @@
 }
 
 
-/* remove a service from the the device
+/* remove a service from the device
    scp->id must be set! */
 static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp)
 {
@@ -1813,11 +1813,11 @@
 
 	/* Set the transfer Parameters */
 	bp->len = len+AUH_SIZE;
-        bp->dr->requesttype = AUT_WREQ;
-	bp->dr->request     = AUV_WBLOCK;
-	bp->dr->value       = cpu_to_le16 (0);
-	bp->dr->index       = cpu_to_le16 (ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT);
-	bp->dr->length      = cpu_to_le16 (len+AUH_SIZE);
+        bp->dr->bRequestType = AUT_WREQ;
+	bp->dr->bRequest     = AUV_WBLOCK;
+	bp->dr->wValue       = cpu_to_le16 (0);
+	bp->dr->wIndex       = cpu_to_le16 (ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT);
+	bp->dr->wLength      = cpu_to_le16 (len+AUH_SIZE);
 	FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_sndctrlpipe (cp->usbdev, 0),
                    (unsigned char*)bp->dr, bp->bufp, len+AUH_SIZE,
 		    auerchar_ctrlwrite_complete, bp);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/bluetooth.c linux-2.4.20/drivers/usb/bluetooth.c
--- linux-2.4.19/drivers/usb/bluetooth.c	2001-11-13 17:19:41.000000000 +0000
+++ linux-2.4.20/drivers/usb/bluetooth.c	2002-10-29 11:18:34.000000000 +0000
@@ -4,8 +4,12 @@
  * Copyright (c) 2000, 2001 Greg Kroah-Hartman	<greg@kroah.com>
  * Copyright (c) 2000 Mark Douglas Corner	<mcorner@umich.edu>
  *
- * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B
+ * USB Bluetooth TTY driver, based on the Bluetooth Spec version 1.0B
  * 
+ * (2001/11/30) Version 0.13 gkh
+ *	- added locking patch from Masoodur Rahman <rmasoodu@in.ibm.com>
+ *	- removed active variable, as open_count will do.
+ *
  * (2001/07/09) Version 0.12 gkh
  *	- removed in_interrupt() call, as it doesn't make sense to do 
  *	  that anymore.
@@ -100,17 +104,14 @@
 
 
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
+#include <asm/uaccess.h>
 
 #define DEBUG
 #include <linux/usb.h>
@@ -118,7 +119,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.12"
+#define DRIVER_VERSION "v0.13"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman, Mark Douglas Corner"
 #define DRIVER_DESC "USB Bluetooth tty driver"
 
@@ -170,12 +171,12 @@
 	struct tty_struct *	tty;		/* the coresponding tty for this port */
 
 	unsigned char		minor;		/* the starting minor number for this device */
-	char			active;		/* someone has this device open */
 	int			throttle;	/* throttled by tty layer */
+	int			open_count;
 	
 	__u8			control_out_bInterfaceNum;
 	struct urb *		control_urb_pool[NUM_CONTROL_URBS];
-	devrequest		dr[NUM_CONTROL_URBS];
+	struct usb_ctrlrequest	dr[NUM_CONTROL_URBS];
 
 	unsigned char *		interrupt_in_buffer;
 	struct urb *		interrupt_in_urb;
@@ -200,6 +201,7 @@
 	unsigned char		int_buffer[EVENT_BUFFER_SIZE];
 	unsigned int		bulk_packet_pos;
 	unsigned char		bulk_buffer[ACL_BUFFER_SIZE];	/* 64k preallocated, fix? */
+	struct semaphore	lock;
 };
 
 
@@ -232,10 +234,10 @@
 MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids);
 
 static struct usb_driver usb_bluetooth_driver = {
-	name:		"bluetooth",
-	probe:		usb_bluetooth_probe,
-	disconnect:	usb_bluetooth_disconnect,
-	id_table:	usb_bluetooth_ids,
+	.name =		"bluetty",
+	.probe =	usb_bluetooth_probe,
+	.disconnect =	usb_bluetooth_disconnect,
+	.id_table =	usb_bluetooth_ids,
 };
 
 static int			bluetooth_refcount;
@@ -283,11 +285,11 @@
 static int bluetooth_ctrl_msg (struct usb_bluetooth *bluetooth, int request, int value, const unsigned char *buf, int len)
 {
 	struct urb *urb = NULL;
-	devrequest *dr = NULL;
+	struct usb_ctrlrequest *dr = NULL;
 	int i;
 	int status;
 
-	dbg (__FUNCTION__);
+	dbg ("%s", __FUNCTION__);
 
 	/* try to find a free urb in our list */
 	for (i = 0; i < NUM_CONTROL_URBS; ++i) {
@@ -298,7 +300,7 @@
 		}
 	}
 	if (urb == NULL) {
-		dbg (__FUNCTION__ " - no free urbs");
+		dbg ("%s - no free urbs", __FUNCTION__);
 		return -ENOMEM;
 	}
 
@@ -306,7 +308,7 @@
 	if (urb->transfer_buffer == NULL) {
 		urb->transfer_buffer = kmalloc (len, GFP_KERNEL);
 		if (urb->transfer_buffer == NULL) {
-			err (__FUNCTION__" - out of memory");
+			err ("%s - out of memory", __FUNCTION__);
 			return -ENOMEM;
 		}
 	}
@@ -314,17 +316,17 @@
 		kfree (urb->transfer_buffer);
 		urb->transfer_buffer = kmalloc (len, GFP_KERNEL);
 		if (urb->transfer_buffer == NULL) {
-			err (__FUNCTION__" - out of memory");
+			err ("%s - out of memory", __FUNCTION__);
 			return -ENOMEM;
 		}
 	}
 	memcpy (urb->transfer_buffer, buf, len);
 
-	dr->requesttype = BLUETOOTH_CONTROL_REQUEST_TYPE;
-	dr->request = request;
-	dr->value = cpu_to_le16((u16) value);
-	dr->index = cpu_to_le16((u16) bluetooth->control_out_bInterfaceNum);
-	dr->length = cpu_to_le16((u16) len);
+	dr->bRequestType= BLUETOOTH_CONTROL_REQUEST_TYPE;
+	dr->bRequest = request;
+	dr->wValue = cpu_to_le16((u16) value);
+	dr->wIndex = cpu_to_le16((u16) bluetooth->control_out_bInterfaceNum);
+	dr->wLength = cpu_to_le16((u16) len);
 	
 	FILL_CONTROL_URB (urb, bluetooth->dev, usb_sndctrlpipe(bluetooth->dev, 0),
 			  (unsigned char*)dr, urb->transfer_buffer, len, bluetooth_ctrl_callback, bluetooth);
@@ -332,7 +334,7 @@
 	/* send it down the pipe */
 	status = usb_submit_urb(urb);
 	if (status)
-		dbg(__FUNCTION__ " - usb_submit_urb(control) failed with status = %d", status);
+		dbg("%s - usb_submit_urb(control) failed with status = %d", __FUNCTION__, status);
 	
 	return status;
 }
@@ -349,7 +351,7 @@
 	struct usb_bluetooth *bluetooth;
 	int result;
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	/* initialize the pointer incase something fails */
 	tty->driver_data = NULL;
@@ -361,43 +363,46 @@
 		return -ENODEV;
 	}
 
-	if (bluetooth->active) {
-		dbg (__FUNCTION__ " - device already open");
-		return -EINVAL;
-	}
-
-	/* set up our structure making the tty driver remember our object, and us it */
-	tty->driver_data = bluetooth;
-	bluetooth->tty = tty;
-
-	/* force low_latency on so that our tty_push actually forces the data through, 
-	 * otherwise it is scheduled, and with high data rates (like with OHCI) data
-	 * can get lost. */
-	bluetooth->tty->low_latency = 1;
+	down (&bluetooth->lock);
+ 
+	++bluetooth->open_count;
+	if (bluetooth->open_count == 1) {
+		/* set up our structure making the tty driver remember our object, and us it */
+		tty->driver_data = bluetooth;
+		bluetooth->tty = tty;
+
+		/* force low_latency on so that our tty_push actually forces the data through, 
+		 * otherwise it is scheduled, and with high data rates (like with OHCI) data
+		 * can get lost. */
+		bluetooth->tty->low_latency = 1;
 	
-	bluetooth->active = 1;
-
-	/* Reset the packet position counters */
-	bluetooth->int_packet_pos = 0;
-	bluetooth->bulk_packet_pos = 0;
+		/* Reset the packet position counters */
+		bluetooth->int_packet_pos = 0;
+		bluetooth->bulk_packet_pos = 0;
 
 #ifndef BTBUGGYHARDWARE
-	/* Start reading from the device */
-	FILL_BULK_URB(bluetooth->read_urb, bluetooth->dev, 
-		      usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
-		      bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, 
-		      bluetooth_read_bulk_callback, bluetooth);
-	result = usb_submit_urb(bluetooth->read_urb);
-	if (result)
-		dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed with status %d", result);
+		/* Start reading from the device */
+		FILL_BULK_URB (bluetooth->read_urb, bluetooth->dev, 
+			       usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
+			       bluetooth->bulk_in_buffer,
+			       bluetooth->bulk_in_buffer_size,
+			       bluetooth_read_bulk_callback, bluetooth);
+		result = usb_submit_urb(bluetooth->read_urb);
+		if (result)
+			dbg("%s - usb_submit_urb(read bulk) failed with status %d", __FUNCTION__, result);
 #endif
-	FILL_INT_URB(bluetooth->interrupt_in_urb, bluetooth->dev, 
-		     usb_rcvintpipe(bluetooth->dev, bluetooth->interrupt_in_endpointAddress),
-		     bluetooth->interrupt_in_buffer, bluetooth->interrupt_in_buffer_size, 
-		     bluetooth_int_callback, bluetooth, bluetooth->interrupt_in_interval);
-	result = usb_submit_urb(bluetooth->interrupt_in_urb);
-	if (result)
-		dbg(__FUNCTION__ " - usb_submit_urb(interrupt in) failed with status %d", result);
+		FILL_INT_URB (bluetooth->interrupt_in_urb, bluetooth->dev, 
+			      usb_rcvintpipe(bluetooth->dev, bluetooth->interrupt_in_endpointAddress),
+			      bluetooth->interrupt_in_buffer,
+			      bluetooth->interrupt_in_buffer_size,
+			      bluetooth_int_callback, bluetooth,
+			      bluetooth->interrupt_in_interval);
+		result = usb_submit_urb(bluetooth->interrupt_in_urb);
+		if (result)
+			dbg("%s - usb_submit_urb(interrupt in) failed with status %d", __FUNCTION__, result);
+	}
+	
+	up(&bluetooth->lock);
 
 	return 0;
 }
@@ -412,20 +417,26 @@
 		return;
 	}
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
-	if (!bluetooth->active) {
-		dbg (__FUNCTION__ " - device not opened");
+	if (!bluetooth->open_count) {
+		dbg ("%s - device not opened", __FUNCTION__);
 		return;
 	}
 
-	/* shutdown any bulk reads and writes that might be going on */
-	for (i = 0; i < NUM_BULK_URBS; ++i)
-		usb_unlink_urb (bluetooth->write_urb_pool[i]);
-	usb_unlink_urb (bluetooth->read_urb);
-	usb_unlink_urb (bluetooth->interrupt_in_urb);
+	down (&bluetooth->lock);
+ 
+	--bluetooth->open_count;
+	if (bluetooth->open_count <= 0) {
+		bluetooth->open_count = 0;
 
-	bluetooth->active = 0;
+		/* shutdown any bulk reads and writes that might be going on */
+		for (i = 0; i < NUM_BULK_URBS; ++i)
+			usb_unlink_urb (bluetooth->write_urb_pool[i]);
+		usb_unlink_urb (bluetooth->read_urb);
+		usb_unlink_urb (bluetooth->interrupt_in_urb);
+	}
+	up(&bluetooth->lock);
 }
 
 
@@ -445,24 +456,24 @@
 		return -ENODEV;
 	}
 
-	dbg(__FUNCTION__ " - %d byte(s)", count);
+	dbg("%s - %d byte(s)", __FUNCTION__, count);
 
-	if (!bluetooth->active) {
-		dbg (__FUNCTION__ " - device not opened");
+	if (!bluetooth->open_count) {
+		dbg ("%s - device not opened", __FUNCTION__);
 		return -EINVAL;
 	}
 
 	if (count == 0) {
-		dbg(__FUNCTION__ " - write request of 0 bytes");
+		dbg("%s - write request of 0 bytes", __FUNCTION__);
 		return 0;
 	}
 	if (count == 1) {
-		dbg(__FUNCTION__ " - write request only included type %d", buf[0]);
+		dbg("%s - write request only included type %d", __FUNCTION__, buf[0]);
 		return 1;
 	}
 
 #ifdef DEBUG
-	printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count);
+	printk (KERN_DEBUG __FILE__ ": %s - length = %d, data = ", __FUNCTION__, count);
 	for (i = 0; i < count; ++i) {
 		printk ("%.2x ", buf[i]);
 	}
@@ -472,11 +483,14 @@
 	if (from_user) {
 		temp_buffer = kmalloc (count, GFP_KERNEL);
 		if (temp_buffer == NULL) {
-			err (__FUNCTION__ "- out of memory.");
+			err ("%s - out of memory.", __FUNCTION__);
 			retval = -ENOMEM;
 			goto exit;
 		}
-		copy_from_user (temp_buffer, buf, count);
+		if (copy_from_user (temp_buffer, buf, count)) {
+			retval = -EFAULT;
+			goto exit;
+		}
 		current_buffer = temp_buffer;
 	} else {
 		current_buffer = buf;
@@ -485,7 +499,7 @@
 	switch (*current_buffer) {
 		/* First byte indicates the type of packet */
 		case CMD_PKT:
-			/* dbg(__FUNCTION__ "- Send cmd_pkt len:%d", count);*/
+			/* dbg("%s- Send cmd_pkt len:%d", __FUNCTION__, count);*/
 
 			retval = bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, &current_buffer[1], count-1);
 			if (retval) {
@@ -511,7 +525,7 @@
 					}
 				}
 				if (urb == NULL) {
-					dbg (__FUNCTION__ " - no free urbs");
+					dbg ("%s - no free urbs", __FUNCTION__);
 					retval = bytes_sent;
 					goto exit;
 				}
@@ -528,7 +542,7 @@
 				/* send it down the pipe */
 				retval = usb_submit_urb(urb);
 				if (retval) {
-					dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with error = %d", retval);
+					dbg("%s - usb_submit_urb(write bulk) failed with error = %d", __FUNCTION__, retval);
 					goto exit;
 				}
 #ifdef BTBUGGYHARDWARE
@@ -547,7 +561,7 @@
 			break;
 		
 		default :
-			dbg(__FUNCTION__" - unsupported (at this time) write type");
+			dbg("%s - unsupported (at this time) write type", __FUNCTION__);
 			retval = -EINVAL;
 			break;
 	}
@@ -570,10 +584,10 @@
 		return -ENODEV;
 	}
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
-	if (!bluetooth->active) {
-		dbg (__FUNCTION__ " - device not open");
+	if (!bluetooth->open_count) {
+		dbg ("%s - device not open", __FUNCTION__);
 		return -EINVAL;
 	}
 
@@ -583,7 +597,7 @@
 		}
 	}
 
-	dbg(__FUNCTION__ " - returns %d", room);
+	dbg("%s - returns %d", __FUNCTION__, room);
 	return room;
 }
 
@@ -598,8 +612,8 @@
 		return -ENODEV;
 	}
 
-	if (!bluetooth->active) {
-		dbg (__FUNCTION__ " - device not open");
+	if (!bluetooth->open_count) {
+		dbg ("%s - device not open", __FUNCTION__);
 		return -EINVAL;
 	}
 
@@ -609,7 +623,7 @@
 		}
 	}
 
-	dbg (__FUNCTION__ " - returns %d", chars);
+	dbg ("%s - returns %d", __FUNCTION__, chars);
 	return chars;
 }
 
@@ -622,14 +636,14 @@
 		return;
 	}
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
-	if (!bluetooth->active) {
-		dbg (__FUNCTION__ " - device not open");
+	if (!bluetooth->open_count) {
+		dbg ("%s - device not open", __FUNCTION__);
 		return;
 	}
 	
-	dbg(__FUNCTION__ " unsupported (at this time)");
+	dbg("%s unsupported (at this time)", __FUNCTION__);
 
 	return;
 }
@@ -643,14 +657,14 @@
 		return;
 	}
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
-	if (!bluetooth->active) {
-		dbg (__FUNCTION__ " - device not open");
+	if (!bluetooth->open_count) {
+		dbg ("%s - device not open", __FUNCTION__);
 		return;
 	}
 
-	dbg(__FUNCTION__ " unsupported (at this time)");
+	dbg("%s unsupported (at this time)", __FUNCTION__);
 }
 
 
@@ -662,10 +676,10 @@
 		return -ENODEV;
 	}
 
-	dbg(__FUNCTION__ " - cmd 0x%.4x", cmd);
+	dbg("%s - cmd 0x%.4x", __FUNCTION__, cmd);
 
-	if (!bluetooth->active) {
-		dbg (__FUNCTION__ " - device not open");
+	if (!bluetooth->open_count) {
+		dbg ("%s - device not open", __FUNCTION__);
 		return -ENODEV;
 	}
 
@@ -682,10 +696,10 @@
 		return;
 	}
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
-	if (!bluetooth->active) {
-		dbg (__FUNCTION__ " - device not open");
+	if (!bluetooth->open_count) {
+		dbg ("%s - device not open", __FUNCTION__);
 		return;
 	}
 
@@ -704,10 +718,10 @@
 		return;
 	}
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
-	if (!bluetooth->active) {
-		dbg (__FUNCTION__ " - device not open");
+	if (!bluetooth->open_count) {
+		dbg ("%s - device not open", __FUNCTION__);
 		return;
 	}
 
@@ -718,7 +732,7 @@
 			      bluetooth_read_bulk_callback, bluetooth);
 		result = usb_submit_urb(bluetooth->read_urb);
 		if (result)
-			err (__FUNCTION__ " - failed submitting read urb, error %d", result);
+			err ("%s - failed submitting read urb, error %d", __FUNCTION__, result);
 	}
 }
 
@@ -729,10 +743,10 @@
 		return;
 	}
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
-	if (!bluetooth->active) {
-		dbg (__FUNCTION__ " - device not open");
+	if (!bluetooth->open_count) {
+		dbg ("%s - device not open", __FUNCTION__);
 		return;
 	}
 
@@ -755,27 +769,27 @@
 	unsigned int count = urb->actual_length;
 	unsigned int packet_size;
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	if (!bluetooth) {
-		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
+		dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__);
 		return;
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero int status received: %d", urb->status);
+		dbg("%s - nonzero int status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
 	if (!count) {
-		dbg(__FUNCTION__ " - zero length int");
+		dbg("%s - zero length int", __FUNCTION__);
 		return;
 	}
 
 
 #ifdef DEBUG
 	if (count) {
-		printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", count);
+		printk (KERN_DEBUG __FILE__ ": %s- length = %d, data = ", __FUNCTION__, count);
 		for (i = 0; i < count; ++i) {
 			printk ("%.2x ", data[i]);
 		}
@@ -805,7 +819,7 @@
 	}
 	
 	if (bluetooth->int_packet_pos + count > EVENT_BUFFER_SIZE) {
-		err(__FUNCTION__ " - exceeded EVENT_BUFFER_SIZE");
+		err("%s - exceeded EVENT_BUFFER_SIZE", __FUNCTION__);
 		bluetooth->int_packet_pos = 0;
 		return;
 	}
@@ -821,7 +835,7 @@
 		return;
 
 	if (packet_size + EVENT_HDR_SIZE < bluetooth->int_packet_pos) {
-		err(__FUNCTION__ " - packet was too long");
+		err("%s - packet was too long", __FUNCTION__);
 		bluetooth->int_packet_pos = 0;
 		return;
 	}
@@ -845,15 +859,15 @@
 {
 	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	if (!bluetooth) {
-		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
+		dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__);
 		return;
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 }
@@ -869,30 +883,30 @@
 	int result;
 
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	if (!bluetooth) {
-		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
+		dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__);
 		return;
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
 		if (urb->status == -ENOENT) {                   
-			dbg(__FUNCTION__ " - URB canceled, won't reschedule");
+			dbg("%s - URB canceled, won't reschedule", __FUNCTION__);
 			return;
 		}
 		goto exit;
 	}
 
 	if (!count) {
-		dbg(__FUNCTION__ " - zero length read bulk");
+		dbg("%s - zero length read bulk", __FUNCTION__);
 		goto exit;
 	}
 
 #ifdef DEBUG
 	if (count) {
-		printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", count);
+		printk (KERN_DEBUG __FILE__ ": %s- length = %d, data = ", __FUNCTION__, count);
 		for (i = 0; i < count; ++i) {
 			printk ("%.2x ", data[i]);
 		}
@@ -909,7 +923,7 @@
 			      bluetooth_read_bulk_callback, bluetooth);
 		result = usb_submit_urb(bluetooth->read_urb);
 		if (result)
-			err (__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+			err ("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
 
 		return;
 	}
@@ -926,7 +940,7 @@
 	}
 
 	if (bluetooth->bulk_packet_pos + count > ACL_BUFFER_SIZE) {
-		err(__FUNCTION__ " - exceeded ACL_BUFFER_SIZE");
+		err("%s - exceeded ACL_BUFFER_SIZE", __FUNCTION__);
 		bluetooth->bulk_packet_pos = 0;
 		goto exit;
 	}
@@ -943,7 +957,7 @@
 	}
 
 	if (packet_size + ACL_HDR_SIZE < bluetooth->bulk_packet_pos) {
-		err(__FUNCTION__ " - packet was too long");
+		err("%s - packet was too long", __FUNCTION__);
 		bluetooth->bulk_packet_pos = 0;
 		goto exit;
 	}
@@ -961,7 +975,7 @@
 	}	
 
 exit:
-	if (!bluetooth || !bluetooth->active)
+	if (!bluetooth || !bluetooth->open_count)
 		return;
 
 	FILL_BULK_URB(bluetooth->read_urb, bluetooth->dev, 
@@ -970,7 +984,7 @@
 		      bluetooth_read_bulk_callback, bluetooth);
 	result = usb_submit_urb(bluetooth->read_urb);
 	if (result)
-		err (__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+		err ("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
 
 	return;
 }
@@ -980,15 +994,15 @@
 {
 	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	if (!bluetooth) {
-		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
+		dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__);
 		return;
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
@@ -1004,7 +1018,7 @@
 	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)private, __FUNCTION__);
 	struct tty_struct *tty;
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	if (!bluetooth) {
 		return;
@@ -1012,7 +1026,7 @@
 
 	tty = bluetooth->tty;
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
-		dbg(__FUNCTION__ " - write wakeup call.");
+		dbg("%s - write wakeup call.", __FUNCTION__);
 		(tty->ldisc.write_wakeup)(tty);
 	}
 
@@ -1074,7 +1088,7 @@
 	if ((num_bulk_in != 1) ||
 	    (num_bulk_out != 1) ||
 	    (num_interrupt_in != 1)) {
-		dbg (__FUNCTION__ " - improper number of endpoints. Bluetooth driver not bound.");
+		dbg ("%s - improper number of endpoints. Bluetooth driver not bound.", __FUNCTION__);
 		return NULL;
 	}
 
@@ -1102,6 +1116,7 @@
 	bluetooth->minor = minor;
 	bluetooth->tqueue.routine = bluetooth_softint;
 	bluetooth->tqueue.data = bluetooth;
+	init_MUTEX(&bluetooth->lock);
 
 	/* record the interface number for the control out */
 	bluetooth->control_out_bInterfaceNum = control_out_endpoint;
@@ -1136,7 +1151,8 @@
 
 	endpoint = bulk_out_endpoint[0];
 	bluetooth->bulk_out_endpointAddress = endpoint->bEndpointAddress;
-	
+	bluetooth->bulk_out_buffer_size = endpoint->wMaxPacketSize * 2;
+
 	/* create our write urb pool */ 
 	for (i = 0; i < NUM_BULK_URBS; ++i) {
 		struct urb  *urb = usb_alloc_urb(0);
@@ -1151,8 +1167,6 @@
 		}
 		bluetooth->write_urb_pool[i] = urb;
 	}
-	
-	bluetooth->bulk_out_buffer_size = endpoint->wMaxPacketSize * 2;
 
 	endpoint = interrupt_in_endpoint[0];
 	bluetooth->interrupt_in_urb = usb_alloc_urb(0);
@@ -1217,10 +1231,10 @@
 	int i;
 
 	if (bluetooth) {
-		if ((bluetooth->active) && (bluetooth->tty))
+		if ((bluetooth->open_count) && (bluetooth->tty))
 			tty_hangup(bluetooth->tty);
 
-		bluetooth->active = 0;
+		bluetooth->open_count = 0;
 
 		if (bluetooth->read_urb) {
 			usb_unlink_urb (bluetooth->read_urb);
@@ -1271,30 +1285,30 @@
 
 
 static struct tty_driver bluetooth_tty_driver = {
-	magic:			TTY_DRIVER_MAGIC,
-	driver_name:		"usb-bluetooth",
-	name:			"usb/ttub/%d",
-	major:			BLUETOOTH_TTY_MAJOR,
-	minor_start:		0,
-	num:			BLUETOOTH_TTY_MINORS,
-	type:			TTY_DRIVER_TYPE_SERIAL,
-	subtype:		SERIAL_TYPE_NORMAL,
-	flags:			TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
-
-	refcount:		&bluetooth_refcount,
-	table:			bluetooth_tty,
-	termios:		bluetooth_termios,
-	termios_locked:		bluetooth_termios_locked,
-
-	open:			bluetooth_open,
-	close:			bluetooth_close,
-	write:			bluetooth_write,
-	write_room:		bluetooth_write_room,
-	ioctl:			bluetooth_ioctl,
-	set_termios:		bluetooth_set_termios,
-	throttle:		bluetooth_throttle,
-	unthrottle:		bluetooth_unthrottle,
-	chars_in_buffer:	bluetooth_chars_in_buffer,
+	.magic =		TTY_DRIVER_MAGIC,
+	.driver_name =		"usb-bluetooth",
+	.name =			"usb/ttub/%d",
+	.major =		BLUETOOTH_TTY_MAJOR,
+	.minor_start =		0,
+	.num =			BLUETOOTH_TTY_MINORS,
+	.type =			TTY_DRIVER_TYPE_SERIAL,
+	.subtype =		SERIAL_TYPE_NORMAL,
+	.flags =		TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+
+	.refcount =		&bluetooth_refcount,
+	.table =		bluetooth_tty,
+	.termios =		bluetooth_termios,
+	.termios_locked =	bluetooth_termios_locked,
+
+	.open =			bluetooth_open,
+	.close =		bluetooth_close,
+	.write =		bluetooth_write,
+	.write_room =		bluetooth_write_room,
+	.ioctl =		bluetooth_ioctl,
+	.set_termios =		bluetooth_set_termios,
+	.throttle =		bluetooth_throttle,
+	.unthrottle =		bluetooth_unthrottle,
+	.chars_in_buffer =	bluetooth_chars_in_buffer,
 };
 
 
@@ -1314,7 +1328,7 @@
 	bluetooth_tty_driver.init_termios          = tty_std_termios;
 	bluetooth_tty_driver.init_termios.c_cflag  = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
 	if (tty_register_driver (&bluetooth_tty_driver)) {
-		err(__FUNCTION__ " - failed to register tty driver");
+		err("%s - failed to register tty driver", __FUNCTION__);
 		return -1;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/brlvger.c linux-2.4.20/drivers/usb/brlvger.c
--- linux-2.4.19/drivers/usb/brlvger.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/brlvger.c	2002-10-29 11:18:36.000000000 +0000
@@ -208,8 +208,8 @@
 #define err(args...) \
     ({ printk(KERN_ERR "Voyager: " args); \
        printk("\n"); })
-#define dbgprint(args...) \
-    ({ printk(KERN_DEBUG "Voyager: " __FUNCTION__ ": " args); \
+#define dbgprint(fmt, args...) \
+    ({ printk(KERN_DEBUG "Voyager: %s: " fmt, __FUNCTION__ , ##args); \
        printk("\n"); })
 #define dbg(args...) \
     ({ if(debug >= 1) dbgprint(args); })
@@ -586,7 +586,9 @@
 	struct brlvger_priv *priv = file->private_data;
 	char buf[MAX_BRLVGER_CELLS];
 	int ret;
-	int rs, off;
+	size_t rs;
+	loff_t off;
+
 	__u16 written;
 
 	if(!priv->dev)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/catc.c linux-2.4.20/drivers/usb/catc.c
--- linux-2.4.19/drivers/usb/catc.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/catc.c	2002-10-29 11:18:40.000000000 +0000
@@ -7,6 +7,9 @@
  *
  *  Based on the work of
  *		Donald Becker
+ * 
+ *  Old chipset support added by Simon Evans <spse@secret.org.uk> 2002
+ *    - adds support for Belkin F5U011
  */
 
 /*
@@ -69,6 +72,7 @@
 #define RX_MAX_BURST		15	/* Max packets per rx buffer (> 0, < 16) */
 #define TX_MAX_BURST		15	/* Max full sized packets per tx buffer (> 0) */
 #define CTRL_QUEUE		16	/* Max control requests in flight (power of two) */
+#define RX_PKT_SZ		1600	/* Max size of receive packet for F5U011 */
 
 /*
  * Control requests.
@@ -79,6 +83,7 @@
 	GetMac =	0xf2,
 	Reset =		0xf4,
 	SetMac =	0xf5,
+	SetRxMode =     0xf5,  /* F5U011 only */
 	WriteROM =	0xf8,
 	SetReg =	0xfa,
 	GetReg =	0xfb,
@@ -126,6 +131,7 @@
 	RxForceOK =	0x04,
 	RxMultiCast =	0x08,
 	RxPromisc =	0x10,
+	AltRxPromisc =  0x20, /* F5U011 uses different bit */
 };
 
 enum led_values {
@@ -136,6 +142,12 @@
 	LEDLink =	0x08,
 };
 
+enum link_status {
+	LinkNoChange = 0,
+	LinkGood     = 1,
+	LinkBad      = 2
+};
+
 /*
  * The catc struct.
  */
@@ -159,7 +171,7 @@
 	u8 rx_buf[RX_MAX_BURST * (PKT_SZ + 2)];
 	u8 irq_buf[2];
 	u8 ctrl_buf[64];
-	devrequest ctrl_dr;
+	struct usb_ctrlrequest ctrl_dr;
 
 	struct timer_list timer;
 	u8 stats_buf[8];
@@ -179,6 +191,10 @@
 	} ctrl_queue[CTRL_QUEUE];
 
 	struct urb tx_urb, rx_urb, irq_urb, ctrl_urb;
+
+	u8 is_f5u011;	/* Set if device is an F5U011 */
+	u8 rxmode[2];	/* Used for F5U011 */
+	atomic_t recq_sz; /* Used for F5U011 - counter of waiting rx packets */
 };
 
 /*
@@ -192,6 +208,10 @@
 #define catc_write_mem(catc, addr, buf, size)		catc_ctrl_msg(catc, USB_DIR_OUT, WriteMem, 0, addr, buf, size)
 #define catc_read_mem(catc, addr, buf, size)		catc_ctrl_msg(catc, USB_DIR_IN,  ReadMem, 0, addr, buf, size)
 
+#define f5u011_rxmode(catc, rxmode)			catc_ctrl_msg(catc, USB_DIR_OUT, SetRxMode, 0, 1, rxmode, 2)
+#define f5u011_rxmode_async(catc, rxmode)		catc_ctrl_async(catc, USB_DIR_OUT, SetRxMode, 0, 1, &rxmode, 2, NULL)
+#define f5u011_mchash_async(catc, hash)			catc_ctrl_async(catc, USB_DIR_OUT, SetRxMode, 0, 2, &hash, 8, NULL)
+
 #define catc_set_reg_async(catc, reg, val)		catc_ctrl_async(catc, USB_DIR_OUT, SetReg, val, reg, NULL, 0, NULL)
 #define catc_get_reg_async(catc, reg, cb)		catc_ctrl_async(catc, USB_DIR_IN, GetReg, 0, reg, NULL, 1, cb)
 #define catc_write_mem_async(catc, addr, buf, size)	catc_ctrl_async(catc, USB_DIR_OUT, WriteMem, 0, addr, buf, size, NULL)
@@ -205,9 +225,12 @@
 	struct catc *catc = urb->context;
 	u8 *pkt_start = urb->transfer_buffer;
 	struct sk_buff *skb;
-	int pkt_len;
+	int pkt_len, pkt_offset = 0;
 
-	clear_bit(RX_RUNNING, &catc->flags);
+	if (!catc->is_f5u011) {
+		clear_bit(RX_RUNNING, &catc->flags);
+		pkt_offset = 2;
+	}
 
 	if (urb->status) {
 		dbg("rx_done, status %d, length %d", urb->status, urb->actual_length);
@@ -215,19 +238,22 @@
 	}
 
 	do {
-		pkt_len = le16_to_cpup((u16*)pkt_start);
-
-		if (pkt_len > urb->actual_length) {
-			catc->stats.rx_length_errors++;
-			catc->stats.rx_errors++;
-			break;
+		if(!catc->is_f5u011) {
+			pkt_len = le16_to_cpup((u16*)pkt_start);
+			if (pkt_len > urb->actual_length) {
+				catc->stats.rx_length_errors++;
+				catc->stats.rx_errors++;
+				break;
+			}
+		} else {
+			pkt_len = urb->actual_length;
 		}
 
 		if (!(skb = dev_alloc_skb(pkt_len)))
 			return;
 
 		skb->dev = catc->netdev;
-		eth_copy_and_sum(skb, pkt_start + 2, pkt_len, 0);
+		eth_copy_and_sum(skb, pkt_start + pkt_offset, pkt_len, 0);
 		skb_put(skb, pkt_len);
 
 		skb->protocol = eth_type_trans(skb, catc->netdev);
@@ -236,11 +262,28 @@
 		catc->stats.rx_packets++;
 		catc->stats.rx_bytes += pkt_len;
 
+		/* F5U011 only does one packet per RX */
+		if (catc->is_f5u011)
+			break;
 		pkt_start += (((pkt_len + 1) >> 6) + 1) << 6;
 
 	} while (pkt_start - (u8 *) urb->transfer_buffer < urb->actual_length);
 
 	catc->netdev->last_rx = jiffies;
+
+	if (catc->is_f5u011) {
+		if (atomic_read(&catc->recq_sz)) {
+			int status;
+			atomic_dec(&catc->recq_sz);
+			dbg("getting extra packet");
+			urb->dev = catc->usbdev;
+			if ((status = usb_submit_urb(urb)) < 0) {
+				dbg("submit(rx_urb) status %d", status);
+			}
+		} else {
+			clear_bit(RX_RUNNING, &catc->flags);
+		}
+	}
 }
 
 static void catc_irq_done(struct urb *urb)
@@ -248,29 +291,48 @@
 	struct catc *catc = urb->context;
 	u8 *data = urb->transfer_buffer;
 	int status;
+	unsigned int hasdata = 0, linksts = LinkNoChange;
+
+	if (!catc->is_f5u011) {
+		hasdata = data[1] & 0x80;
+		if (data[1] & 0x40)
+			linksts = LinkGood;
+		else if (data[1] & 0x20)
+			linksts = LinkBad;
+	} else {
+		hasdata = (unsigned int)(be16_to_cpup((u16*)data) & 0x0fff);
+		if (data[0] == 0x90)
+			linksts = LinkGood;
+		else if (data[0] == 0xA0)
+			linksts = LinkBad;
+	}
 
 	if (urb->status) {
 		dbg("irq_done, status %d, data %02x %02x.", urb->status, data[0], data[1]);
 		return;
 	}
 
-	if ((data[1] & 0x80) && !test_and_set_bit(RX_RUNNING, &catc->flags)) {
-		catc->rx_urb.dev = catc->usbdev;
-		if ((status = usb_submit_urb(&catc->rx_urb)) < 0) {
-			err("submit(rx_urb) status %d", status);
-			return;
-		} 
-	}
-
-	if (data[1] & 0x40) {
+	if (linksts == LinkGood) {
 		netif_carrier_on(catc->netdev);
 		dbg("link ok");
 	}
 
-	if (data[1] & 0x20) {
+	if (linksts == LinkBad) {
 		netif_carrier_off(catc->netdev);
 		dbg("link bad");
 	}
+
+	if (hasdata) {
+		if (test_and_set_bit(RX_RUNNING, &catc->flags)) {
+			if (catc->is_f5u011)
+				atomic_inc(&catc->recq_sz);
+		} else {
+			catc->rx_urb.dev = catc->usbdev;
+			if ((status = usb_submit_urb(&catc->rx_urb)) < 0) {
+				err("submit(rx_urb) status %d", status);
+			}
+		} 
+	}
 }
 
 /*
@@ -281,6 +343,9 @@
 {
 	int status;
 
+	if (catc->is_f5u011)
+		catc->tx_ptr = (catc->tx_ptr + 63) & ~63;
+
 	catc->tx_urb.transfer_buffer_length = catc->tx_ptr;
 	catc->tx_urb.transfer_buffer = catc->tx_buf[catc->tx_idx];
 	catc->tx_urb.dev = catc->usbdev;
@@ -337,14 +402,16 @@
 
 	catc->tx_ptr = (((catc->tx_ptr - 1) >> 6) + 1) << 6;
 	tx_buf = catc->tx_buf[catc->tx_idx] + catc->tx_ptr;
-	*((u16*)tx_buf) = cpu_to_le16((u16)skb->len);
+	*((u16*)tx_buf) = (catc->is_f5u011) ? 
+		cpu_to_be16((u16)skb->len) : cpu_to_le16((u16)skb->len);
 	memcpy(tx_buf + 2, skb->data, skb->len);
 	catc->tx_ptr += skb->len + 2;
 
 	if (!test_and_set_bit(TX_RUNNING, &catc->flags))
 		catc_tx_run(catc);
 
-	if (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2)))
+	if ((catc->is_f5u011 && catc->tx_ptr)
+	     || (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2))))
 		netif_stop_queue(netdev);
 
 	spin_unlock_irqrestore(&catc->tx_lock, flags);
@@ -383,14 +450,14 @@
 	struct ctrl_queue *q = catc->ctrl_queue + catc->ctrl_tail;
 	struct usb_device *usbdev = catc->usbdev;
 	struct urb *urb = &catc->ctrl_urb;
-	devrequest *dr = &catc->ctrl_dr;
+	struct usb_ctrlrequest *dr = &catc->ctrl_dr;
 	int status;
 
-	dr->request = q->request;
-	dr->requesttype = 0x40 | q->dir;
-	dr->value = cpu_to_le16(q->value);
-	dr->index = cpu_to_le16(q->index);
-	dr->length = cpu_to_le16(q->len);
+	dr->bRequest = q->request;
+	dr->bRequestType = 0x40 | q->dir;
+	dr->wValue = cpu_to_le16(q->value);
+	dr->wIndex = cpu_to_le16(q->index);
+	dr->wLength = cpu_to_le16(q->len);
 
         urb->pipe = q->dir ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0);
 	urb->transfer_buffer_length = q->len;
@@ -529,15 +596,20 @@
  * Receive modes. Broadcast, Multicast, Promisc.
  */
 
-static void catc_multicast(unsigned char *addr, u8 *multicast)
+static inline u32 ether_crc_le(int cnt, unsigned char *addr)
 {
 	unsigned int crc = 0xffffffff;
 	u8 byte, idx, bit;
-
-        for (idx = 0; idx < 6; idx++)
+	
+        for (idx = 0; idx < cnt; idx++)
                 for (byte = *addr++, bit = 0; bit < 8; bit++, byte >>= 1)
                         crc = (crc >> 1) ^ (((crc ^ byte) & 1) ? 0xedb88320U : 0);
+	return crc;
+}
 
+static void catc_multicast(unsigned char *addr, u8 *multicast)
+{
+	unsigned int crc = ether_crc_le(6, addr);
 	multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7);
 }
 
@@ -557,17 +629,33 @@
 
 	if (netdev->flags & IFF_PROMISC) {
 		memset(catc->multicast, 0xff, 64);
-		rx |= RxPromisc;
+		rx |= (!catc->is_f5u011) ? RxPromisc : AltRxPromisc;
 	} 
 
-	if (netdev->flags & IFF_ALLMULTI)
+	if (netdev->flags & IFF_ALLMULTI) {
 		memset(catc->multicast, 0xff, 64);
-
-	for (i = 0, mc = netdev->mc_list; mc && i < netdev->mc_count; i++, mc = mc->next)
-		catc_multicast(mc->dmi_addr, catc->multicast);
-
-	catc_set_reg_async(catc, RxUnit, rx);
-	catc_write_mem_async(catc, 0xfa80, catc->multicast, 64);
+	} else {
+		for (i = 0, mc = netdev->mc_list; mc && i < netdev->mc_count; i++, mc = mc->next) {
+			u32 crc = ether_crc_le(6, mc->dmi_addr);
+			if (!catc->is_f5u011) {
+				catc->multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7);
+			} else {
+				catc->multicast[7-(crc >> 29)] |= 1 << ((crc >> 26) & 7);
+			}
+		}
+	}
+	if (!catc->is_f5u011) {
+		catc_set_reg_async(catc, RxUnit, rx);
+		catc_write_mem_async(catc, 0xfa80, catc->multicast, 64);
+	} else {
+		f5u011_mchash_async(catc, catc->multicast);
+		if (catc->rxmode[0] != rx) {
+			catc->rxmode[0] = rx;
+			dbg("Setting RX mode to %2.2X %2.2X", catc->rxmode[0],
+			    catc->rxmode[1]);
+			f5u011_rxmode_async(catc, catc->rxmode);
+		}
+	}
 }
 
 /*
@@ -594,6 +682,30 @@
                         return -EFAULT;
                 return 0;
         }
+
+	/* get settings */
+	case ETHTOOL_GSET:
+		if (catc->is_f5u011) {
+			struct ethtool_cmd ecmd = { 
+				ETHTOOL_GSET, 
+				SUPPORTED_10baseT_Half | SUPPORTED_TP, 
+				ADVERTISED_10baseT_Half | ADVERTISED_TP, 
+				SPEED_10, 
+				DUPLEX_HALF, 
+				PORT_TP, 
+				0, 
+				XCVR_INTERNAL, 
+				AUTONEG_DISABLE, 
+				1, 
+				1 
+			};
+			if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+				return -EFAULT;
+			return 0;
+		} else {
+			return -EOPNOTSUPP;
+		}
+
         /* get link status */
         case ETHTOOL_GLINK: {
                 struct ethtool_value edata = {ETHTOOL_GLINK};
@@ -635,7 +747,8 @@
 
 	netif_start_queue(netdev);
 
-	mod_timer(&catc->timer, jiffies + STATS_UPDATE);
+	if (!catc->is_f5u011)
+		mod_timer(&catc->timer, jiffies + STATS_UPDATE);
 
 	return 0;
 }
@@ -646,7 +759,8 @@
 
 	netif_stop_queue(netdev);
 
-	del_timer_sync(&catc->timer);
+	if (!catc->is_f5u011)
+		del_timer_sync(&catc->timer);
 
 	usb_unlink_urb(&catc->rx_urb);
 	usb_unlink_urb(&catc->tx_urb);
@@ -665,7 +779,7 @@
 	struct net_device *netdev;
 	struct catc *catc;
 	u8 broadcast[6];
-	int i;
+	int i, pktsz;
 
 	if (usb_set_interface(usbdev, ifnum, 1)) {
                 err("Can't set altsetting 1.");
@@ -704,6 +818,20 @@
 	catc->timer.data = (long) catc;
 	catc->timer.function = catc_stats_timer;
 
+	/* The F5U011 has the same vendor/product as the netmate 
+	 *  but a device version of 0x130
+	 */
+	if (usbdev->descriptor.idVendor == 0x0423 && 
+	    usbdev->descriptor.idProduct == 0xa &&
+	    catc->usbdev->descriptor.bcdDevice == 0x0130) {
+		dbg("Testing for f5u011");
+		catc->is_f5u011 = 1;
+		atomic_set(&catc->recq_sz, 0);
+		pktsz = RX_PKT_SZ;
+	} else {
+		pktsz = RX_MAX_BURST * (PKT_SZ + 2);
+	}
+
 	FILL_CONTROL_URB(&catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0),
 		NULL, NULL, 0, catc_ctrl_done, catc);
 
@@ -711,20 +839,21 @@
 		NULL, 0, catc_tx_done, catc);
 
 	FILL_BULK_URB(&catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1),
-		catc->rx_buf, RX_MAX_BURST * (PKT_SZ + 2), catc_rx_done, catc);
+		catc->rx_buf, pktsz, catc_rx_done, catc);
 
 	FILL_INT_URB(&catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2),
                 catc->irq_buf, 2, catc_irq_done, catc, 1);
 
-	dbg("Checking memory size\n");
-
-	i = 0x12345678;
-	catc_write_mem(catc, 0x7a80, &i, 4);
-	i = 0x87654321;	
-	catc_write_mem(catc, 0xfa80, &i, 4);
-	catc_read_mem(catc, 0x7a80, &i, 4);
+	if (!catc->is_f5u011) {
+		dbg("Checking memory size\n");
 
-	switch (i) {
+		i = 0x12345678;
+		catc_write_mem(catc, 0x7a80, &i, 4);
+		i = 0x87654321;	
+		catc_write_mem(catc, 0xfa80, &i, 4);
+		catc_read_mem(catc, 0x7a80, &i, 4);
+	  
+		switch (i) {
 		case 0x12345678:
 			catc_set_reg(catc, TxBufCount, 8);
 			catc_set_reg(catc, RxBufCount, 32);
@@ -737,44 +866,52 @@
 			catc_set_reg(catc, RxBufCount, 16);
 			dbg("32k Memory\n");
 			break;
+		}
+	  
+		dbg("Getting MAC from SEEROM.");
+	  
+		catc_get_mac(catc, netdev->dev_addr);
+		
+		dbg("Setting MAC into registers.");
+	  
+		for (i = 0; i < 6; i++)
+			catc_set_reg(catc, StationAddr0 - i, netdev->dev_addr[i]);
+		
+		dbg("Filling the multicast list.");
+	  
+		memset(broadcast, 0xff, 6);
+		catc_multicast(broadcast, catc->multicast);
+		catc_multicast(netdev->dev_addr, catc->multicast);
+		catc_write_mem(catc, 0xfa80, catc->multicast, 64);
+		
+		dbg("Clearing error counters.");
+		
+		for (i = 0; i < 8; i++)
+			catc_set_reg(catc, EthStats + i, 0);
+		catc->last_stats = jiffies;
+		
+		dbg("Enabling.");
+		
+		catc_set_reg(catc, MaxBurst, RX_MAX_BURST);
+		catc_set_reg(catc, OpModes, OpTxMerge | OpRxMerge | OpLenInclude | Op3MemWaits);
+		catc_set_reg(catc, LEDCtrl, LEDLink);
+		catc_set_reg(catc, RxUnit, RxEnable | RxPolarity | RxMultiCast);
+	} else {
+		dbg("Performing reset\n");
+		catc_reset(catc);
+		catc_get_mac(catc, netdev->dev_addr);
+		
+		dbg("Setting RX Mode");
+		catc->rxmode[0] = RxEnable | RxPolarity | RxMultiCast;
+		catc->rxmode[1] = 0;
+		f5u011_rxmode(catc, catc->rxmode);
 	}
-
-	dbg("Getting MAC from SEEROM.");
-
-	catc_get_mac(catc, netdev->dev_addr);
-
-	dbg("Setting MAC into registers.");
-
-	for (i = 0; i < 6; i++)
-		catc_set_reg(catc, StationAddr0 - i, netdev->dev_addr[i]);
-
-	dbg("Filling the multicast list.");
-
-	memset(broadcast, 0xff, 8);
-	catc_multicast(broadcast, catc->multicast);
-	catc_multicast(netdev->dev_addr, catc->multicast);
-	catc_write_mem(catc, 0xfa80, catc->multicast, 64);
-
-	dbg("Clearing error counters.");
-
-	for (i = 0; i < 8; i++)
-		catc_set_reg(catc, EthStats + i, 0);
-	catc->last_stats = jiffies;
-
-	dbg("Enabling.");
-
-	catc_set_reg(catc, MaxBurst, RX_MAX_BURST);
-	catc_set_reg(catc, OpModes, OpTxMerge | OpRxMerge | OpLenInclude | Op3MemWaits);
-	catc_set_reg(catc, LEDCtrl, LEDLink);
-	catc_set_reg(catc, RxUnit, RxEnable | RxPolarity | RxMultiCast);
-
 	dbg("Init done.");
-
-	printk(KERN_INFO "%s: CATC EL1210A NetMate USB Ethernet at usb%d:%d.%d, ",
-		netdev->name, usbdev->bus->busnum, usbdev->devnum, ifnum);
+	printk(KERN_INFO "%s: %s USB Ethernet at usb%d:%d.%d, ",
+	       netdev->name, (catc->is_f5u011) ? "Belkin F5U011" : "CATC EL1210A NetMate",
+	       usbdev->bus->busnum, usbdev->devnum, ifnum);
 	for (i = 0; i < 5; i++) printk("%2.2x:", netdev->dev_addr[i]);
 	printk("%2.2x.\n", netdev->dev_addr[i]);
-
 	return catc;
 }
 
@@ -791,7 +928,7 @@
  */
 
 static struct usb_device_id catc_id_table [] = {
-	{ USB_DEVICE(0x0423, 0xa) },	/* CATC Netmate */
+	{ USB_DEVICE(0x0423, 0xa) },	/* CATC Netmate, Belkin F5U011 */
 	{ USB_DEVICE(0x0423, 0xc) },	/* CATC Netmate II, Belkin F5U111 */
 	{ USB_DEVICE(0x08d1, 0x1) },	/* smartBridges smartNIC */
 	{ }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/dabusb.c linux-2.4.20/drivers/usb/dabusb.c
--- linux-2.4.19/drivers/usb/dabusb.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/usb/dabusb.c	2002-10-29 11:18:31.000000000 +0000
@@ -83,7 +83,7 @@
 }
 /*-------------------------------------------------------------------*/
 #ifdef DEBUG 
-static void dump_urb (purb_t purb)
+static void dump_urb (struct urb *purb)
 {
 	dbg("urb                   :%p", purb);
 	dbg("next                  :%p", purb->next);
@@ -167,7 +167,7 @@
 	return 0;
 }
 /*-------------------------------------------------------------------*/
-static void dabusb_iso_complete (purb_t purb)
+static void dabusb_iso_complete (struct urb *purb)
 {
 	pbuff_t b = purb->context;
 	pdabusb_t s = b->s;
@@ -482,7 +482,7 @@
 	int rem;
 	int cnt;
 	pbuff_t b;
-	purb_t purb = NULL;
+	struct urb *purb = NULL;
 
 	dbg("dabusb_read");
 
@@ -605,6 +605,7 @@
 	}
 	if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
 		err("set_interface failed");
+		up(&s->mutex);
 		return -EINVAL;
 	}
 	s->opened = 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/dabusb.h linux-2.4.20/drivers/usb/dabusb.h
--- linux-2.4.19/drivers/usb/dabusb.h	2000-10-03 16:24:40.000000000 +0000
+++ linux-2.4.20/drivers/usb/dabusb.h	2002-10-29 11:18:32.000000000 +0000
@@ -38,7 +38,7 @@
 typedef struct 
 {
 	pdabusb_t s;
-	purb_t purb;
+	struct urb *purb;
 	struct list_head buff_list;
 } buff_t,*pbuff_t;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/devices.c linux-2.4.20/drivers/usb/devices.c
--- linux-2.4.19/drivers/usb/devices.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/devices.c	2002-10-29 11:18:39.000000000 +0000
@@ -61,6 +61,8 @@
 #include <linux/usbdevice_fs.h>
 #include <asm/uaccess.h>
 
+#include "hcd.h"
+
 #define MAX_TOPO_LEVEL		6
 
 /* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/devio.c linux-2.4.20/drivers/usb/devio.c
--- linux-2.4.19/drivers/usb/devio.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/devio.c	2002-10-29 11:18:47.000000000 +0000
@@ -52,7 +52,7 @@
 	unsigned int signr;
 	void *userbuffer;
         void *userurb;
-        urb_t urb;
+        struct urb urb;
 };
 
 static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
@@ -138,7 +138,7 @@
 	return ret;
 }
 
-extern inline unsigned int ld2(unsigned int x)
+static inline unsigned int ld2(unsigned int x)
 {
         unsigned int r = 0;
         
@@ -169,7 +169,7 @@
 
 static struct async *alloc_async(unsigned int numisoframes)
 {
-        unsigned int assize = sizeof(struct async) + numisoframes * sizeof(iso_packet_descriptor_t);
+        unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct iso_packet_descriptor);
         struct async *as = kmalloc(assize, GFP_KERNEL);
         if (!as)
                 return NULL;
@@ -188,7 +188,7 @@
         kfree(as);
 }
 
-extern __inline__ void async_newpending(struct async *as)
+static inline void async_newpending(struct async *as)
 {
         struct dev_state *ps = as->ps;
         unsigned long flags;
@@ -198,7 +198,7 @@
         spin_unlock_irqrestore(&ps->lock, flags);
 }
 
-extern __inline__ void async_removepending(struct async *as)
+static inline void async_removepending(struct async *as)
 {
         struct dev_state *ps = as->ps;
         unsigned long flags;
@@ -209,7 +209,7 @@
         spin_unlock_irqrestore(&ps->lock, flags);
 }
 
-extern __inline__ struct async *async_getcompleted(struct dev_state *ps)
+static inline struct async *async_getcompleted(struct dev_state *ps)
 {
         unsigned long flags;
         struct async *as = NULL;
@@ -224,7 +224,7 @@
         return as;
 }
 
-extern __inline__ struct async *async_getpending(struct dev_state *ps, void *userurb)
+static inline struct async *async_getpending(struct dev_state *ps, void *userurb)
 {
         unsigned long flags;
         struct async *as;
@@ -245,7 +245,7 @@
         return NULL;
 }
 
-static void async_completed(purb_t urb)
+static void async_completed(struct urb *urb)
 {
         struct async *as = (struct async *)urb->context;
         struct dev_state *ps = as->ps;
@@ -772,7 +772,7 @@
 	struct usbdevfs_iso_packet_desc *isopkt = NULL;
 	struct usb_endpoint_descriptor *ep_desc;
 	struct async *as;
-	devrequest *dr = NULL;
+	struct usb_ctrlrequest *dr = NULL;
 	unsigned int u, totlen, isofrmlen;
 	int ret;
 
@@ -802,23 +802,23 @@
 		/* min 8 byte setup packet, max arbitrary */
 		if (uurb.buffer_length < 8 || uurb.buffer_length > PAGE_SIZE)
 			return -EINVAL;
-		if (!(dr = kmalloc(sizeof(devrequest), GFP_KERNEL)))
+		if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
 			return -ENOMEM;
 		if (copy_from_user(dr, (unsigned char*)uurb.buffer, 8)) {
 			kfree(dr);
 			return -EFAULT;
 		}
-		if (uurb.buffer_length < (le16_to_cpup(&dr->length) + 8)) {
+		if (uurb.buffer_length < (le16_to_cpup(&dr->wLength) + 8)) {
 			kfree(dr);
 			return -EINVAL;
 		}
-		if ((ret = check_ctrlrecip(ps, dr->requesttype, le16_to_cpup(&dr->index)))) {
+		if ((ret = check_ctrlrecip(ps, dr->bRequestType, le16_to_cpup(&dr->wIndex)))) {
 			kfree(dr);
 			return ret;
 		}
-		uurb.endpoint = (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->requesttype & USB_ENDPOINT_DIR_MASK);
+		uurb.endpoint = (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
 		uurb.number_of_packets = 0;
-		uurb.buffer_length = le16_to_cpup(&dr->length);
+		uurb.buffer_length = le16_to_cpup(&dr->wLength);
 		uurb.buffer += 8;
 		if (!access_ok((uurb.endpoint & USB_DIR_IN) ?  VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) {
 			kfree(dr);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/hc_simple.c linux-2.4.20/drivers/usb/hc_simple.c
--- linux-2.4.19/drivers/usb/hc_simple.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/hc_simple.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,1072 @@
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*
+ * simple generic USB HCD frontend Version 0.9.5 (10/28/2001)
+ * for embedded HCs (SL811HS)
+ * 
+ * USB URB handling, hci_ hcs_
+ * URB queueing, qu_
+ * Transfer scheduling, sh_
+ * 
+ *
+ *-------------------------------------------------------------------------*
+ * 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
+ *
+ *-------------------------------------------------------------------------*/
+
+/* main lock for urb access */
+static spinlock_t usb_urb_lock = SPIN_LOCK_UNLOCKED;
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+/* URB HCD API function layer
+ * * * */
+
+/***************************************************************************
+ * Function Name : hcs_urb_queue
+ *
+ * This function initializes the urb status and length before queueing the 
+ * urb. 
+ *
+ * Input:  hci = data structure for the host controller
+ *         urb = USB request block data structure 
+ *
+ * Return: 0 
+ **************************************************************************/
+static inline int hcs_urb_queue (hci_t * hci, struct urb * urb)
+{
+	int i;
+
+	DBGFUNC ("enter hcs_urb_queue\n");
+	if (usb_pipeisoc (urb->pipe)) {
+		DBGVERBOSE ("hcs_urb_queue: isoc pipe\n");
+		for (i = 0; i < urb->number_of_packets; i++) {
+			urb->iso_frame_desc[i].actual_length = 0;
+			urb->iso_frame_desc[i].status = -EXDEV;
+		}
+
+		/* urb->next hack : 1 .. resub, 0 .. single shot */
+		/* urb->interval = urb->next ? 1 : 0; */
+	}
+
+	urb->status = -EINPROGRESS;
+	urb->actual_length = 0;
+	urb->error_count = 0;
+
+	if (usb_pipecontrol (urb->pipe))
+		hc_flush_data_cache (hci, urb->setup_packet, 8);
+	if (usb_pipeout (urb->pipe))
+		hc_flush_data_cache (hci, urb->transfer_buffer,
+				     urb->transfer_buffer_length);
+
+	qu_queue_urb (hci, urb);
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : hcs_return_urb
+ *
+ * This function the return path of URB back to the USB core. It calls the
+ * the urb complete function if exist, and also handles the resubmition of
+ * interrupt URBs.
+ *
+ * Input:  hci = data structure for the host controller
+ *         urb = USB request block data structure 
+ *         resub_ok = resubmit flag: 1 = submit urb again, 0 = not submit 
+ *
+ * Return: 0 
+ **************************************************************************/
+static int hcs_return_urb (hci_t * hci, struct urb * urb, int resub_ok)
+{
+	struct usb_device *dev = urb->dev;
+	int resubmit = 0;
+
+	DBGFUNC ("enter hcs_return_urb, urb pointer = 0x%x, "
+		 "transferbuffer point = 0x%x, "
+		 " setup packet pointer = 0x%x, context pointer = 0x%x \n",
+		 (__u32 *) urb, (__u32 *) urb->transfer_buffer,
+		 (__u32 *) urb->setup_packet, (__u32 *) urb->context);
+	if (urb_debug)
+		urb_print (urb, "RET", usb_pipeout (urb->pipe));
+
+	resubmit = urb->interval && resub_ok;
+
+	urb->dev = urb->hcpriv = NULL;
+
+	if (urb->complete) {
+		urb->complete (urb);	/* call complete */
+	}
+
+	if (resubmit) {
+		/* requeue the URB */
+		urb->dev = dev;
+		hcs_urb_queue (hci, urb);
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : hci_submit_urb
+ *
+ * This function is called by the USB core API when an URB is available to
+ * process.  This function does the following
+ *
+ * 1) Check the validity of the URB
+ * 2) Parse the device number from the URB
+ * 3) Pass the URB to the root hub routine if its intended for the hub, else
+ *    queue the urb for the attached device. 
+ *
+ * Input: urb = USB request block data structure 
+ *
+ * Return: 0 if success or error code 
+ **************************************************************************/
+static int hci_submit_urb (struct urb * urb)
+{
+	hci_t *hci;
+	unsigned int pipe = urb->pipe;
+	unsigned long flags;
+	int ret;
+
+	DBGFUNC ("enter hci_submit_urb, pipe = 0x%x\n", urb->pipe);
+	if (!urb->dev || !urb->dev->bus || urb->hcpriv)
+		return -EINVAL;
+
+	if (usb_endpoint_halted
+	    (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) {
+		printk ("hci_submit_urb: endpoint_halted\n");
+		return -EPIPE;
+	}
+	hci = (hci_t *) urb->dev->bus->hcpriv;
+
+	/* a request to the virtual root hub */
+
+	if (usb_pipedevice (pipe) == hci->rh.devnum) {
+		if (urb_debug > 1)
+			urb_print (urb, "SUB-RH", usb_pipein (pipe));
+
+		return rh_submit_urb (urb);
+	}
+
+	/* queue the URB to its endpoint-queue */
+
+	spin_lock_irqsave (&usb_urb_lock, flags);
+	ret = hcs_urb_queue (hci, urb);
+	if (ret != 0) {
+		/* error on return */
+		DBGERR
+		    ("hci_submit_urb: return err, ret = 0x%x, urb->status = 0x%x\n",
+		     ret, urb->status);
+	}
+
+	spin_unlock_irqrestore (&usb_urb_lock, flags);
+
+	return ret;
+
+}
+
+/***************************************************************************
+ * Function Name : hci_unlink_urb
+ *
+ * This function mark the URB to unlink
+ *
+ * Input: urb = USB request block data structure 
+ *
+ * Return: 0 if success or error code 
+ **************************************************************************/
+static int hci_unlink_urb (struct urb * urb)
+{
+	unsigned long flags;
+	hci_t *hci;
+	DECLARE_WAITQUEUE (wait, current);
+	void *comp = NULL;
+
+	DBGFUNC ("enter hci_unlink_urb\n");
+
+	if (!urb)		/* just to be sure */
+		return -EINVAL;
+
+	if (!urb->dev || !urb->dev->bus)
+		return -ENODEV;
+
+	hci = (hci_t *) urb->dev->bus->hcpriv;
+
+	/* a request to the virtual root hub */
+	if (usb_pipedevice (urb->pipe) == hci->rh.devnum) {
+		return rh_unlink_urb (urb);
+	}
+
+	if (urb_debug)
+		urb_print (urb, "UNLINK", 1);
+
+	spin_lock_irqsave (&usb_urb_lock, flags);
+
+	if (!list_empty (&urb->urb_list) && urb->status == -EINPROGRESS) {
+		/* URB active? */
+
+		if (urb->
+		    transfer_flags & (USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED)) {
+			/* asynchron with callback */
+
+			list_del (&urb->urb_list);	/* relink the urb to the del list */
+			list_add (&urb->urb_list, &hci->del_list);
+			spin_unlock_irqrestore (&usb_urb_lock, flags);
+
+		} else {
+			/* synchron without callback */
+
+			add_wait_queue (&hci->waitq, &wait);
+
+			set_current_state (TASK_UNINTERRUPTIBLE);
+			comp = urb->complete;
+			urb->complete = NULL;
+
+			list_del (&urb->urb_list);	/* relink the urb to the del list */
+			list_add (&urb->urb_list, &hci->del_list);
+
+			spin_unlock_irqrestore (&usb_urb_lock, flags);
+
+			schedule_timeout (HZ / 50);
+
+			if (!list_empty (&urb->urb_list))
+				list_del (&urb->urb_list);
+
+			urb->complete = comp;
+			urb->hcpriv = NULL;
+			remove_wait_queue (&hci->waitq, &wait);
+		}
+	} else {
+		/* hcd does not own URB but we keep the driver happy anyway */
+		spin_unlock_irqrestore (&usb_urb_lock, flags);
+
+		if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK)) {
+			urb->status = -ENOENT;
+			urb->actual_length = 0;
+			urb->complete (urb);
+			urb->status = 0;
+		} else {
+			urb->status = -ENOENT;
+		}
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : hci_alloc_dev
+ *
+ * This function allocates private data space for the usb device and 
+ * initialize the endpoint descriptor heads.
+ *
+ * Input: usb_dev = pointer to the usb device 
+ *
+ * Return: 0 if success or error code 
+ **************************************************************************/
+static int hci_alloc_dev (struct usb_device *usb_dev)
+{
+	struct hci_device *dev;
+	int i;
+
+	DBGFUNC ("enter hci_alloc_dev\n");
+	dev = kmalloc (sizeof (*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	memset (dev, 0, sizeof (*dev));
+
+	for (i = 0; i < 32; i++) {
+		INIT_LIST_HEAD (&(dev->ed[i].urb_queue));
+		dev->ed[i].pipe_head = NULL;
+	}
+
+	usb_dev->hcpriv = dev;
+
+	DBGVERBOSE ("USB HC dev alloc %d bytes\n", sizeof (*dev));
+
+	return 0;
+
+}
+
+/***************************************************************************
+ * Function Name : hci_free_dev
+ *
+ * This function de-allocates private data space for the usb devic
+ *
+ * Input: usb_dev = pointer to the usb device 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int hci_free_dev (struct usb_device *usb_dev)
+{
+	DBGFUNC ("enter hci_free_dev\n");
+
+	if (usb_dev->hcpriv)
+		kfree (usb_dev->hcpriv);
+
+	usb_dev->hcpriv = NULL;
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : hci_get_current_frame_number
+ *
+ * This function get the current USB frame number
+ *
+ * Input: usb_dev = pointer to the usb device 
+ *
+ * Return: frame number  
+ **************************************************************************/
+static int hci_get_current_frame_number (struct usb_device *usb_dev)
+{
+	hci_t *hci = usb_dev->bus->hcpriv;
+	DBGFUNC ("enter hci_get_current_frame_number, frame = 0x%x \r\n",
+		 hci->frame_number);
+
+	return (hci->frame_number);
+}
+
+/***************************************************************************
+ * List of all io-functions 
+ **************************************************************************/
+
+static struct usb_operations hci_device_operations = {
+	allocate:		hci_alloc_dev,
+	deallocate:		hci_free_dev,
+	get_frame_number:	hci_get_current_frame_number,
+	submit_urb:		hci_submit_urb,
+	unlink_urb:		hci_unlink_urb,
+};
+
+/***************************************************************************
+ * URB queueing:
+ * 
+ * For each type of transfer (INTR, BULK, ISO, CTRL) there is a list of 
+ * active URBs.
+ * (hci->intr_list, hci->bulk_list, hci->iso_list, hci->ctrl_list)
+ * For every endpoint the head URB of the queued URBs is linked to one of 
+ * those lists.
+ * 
+ * The rest of the queued URBs of an endpoint are linked into a 
+ * private URB list for each endpoint. (hci_dev->ed [endpoint_io].urb_queue)
+ * hci_dev->ed [endpoint_io].pipe_head .. points to the head URB which is 
+ * in one of the active URB lists.
+ * 
+ * The index of an endpoint consists of its number and its direction.
+ * 
+ * The state of an intr and iso URB is 0. 
+ * For ctrl URBs the states are US_CTRL_SETUP, US_CTRL_DATA, US_CTRL_ACK
+ * Bulk URBs states are US_BULK and US_BULK0 (with 0-len packet)
+ * 
+ **************************************************************************/
+
+/***************************************************************************
+ * Function Name : qu_urb_timeout
+ *
+ * This function is called when the URB timeout. The function unlinks the 
+ * URB. 
+ *
+ * Input: lurb: URB 
+ *
+ * Return: none  
+ **************************************************************************/
+#ifdef HC_URB_TIMEOUT
+static void qu_urb_timeout (unsigned long lurb)
+{
+	struct urb *urb = (struct urb *) lurb;
+
+	DBGFUNC ("enter qu_urb_timeout\n");
+	urb->transfer_flags |= USB_TIMEOUT_KILLED;
+	hci_unlink_urb (urb);
+}
+#endif
+
+/***************************************************************************
+ * Function Name : qu_pipeindex
+ *
+ * This function gets the index of the pipe.   
+ *
+ * Input: pipe: the urb pipe 
+ *
+ * Return: index  
+ **************************************************************************/
+static inline int qu_pipeindex (__u32 pipe)
+{
+	DBGFUNC ("enter qu_pipeindex\n");
+	return (usb_pipeendpoint (pipe) << 1) | (usb_pipecontrol (pipe) ? 0 : usb_pipeout (pipe));
+}
+
+/***************************************************************************
+ * Function Name : qu_seturbstate
+ *
+ * This function set the state of the URB.  
+ * 
+ * control pipe: 3 states -- Setup, data, status
+ * interrupt and bulk pipe: 1 state -- data    
+ *
+ * Input: urb = USB request block data structure 
+ *        state = the urb state
+ *
+ * Return: none  
+ **************************************************************************/
+static inline void qu_seturbstate (struct urb * urb, int state)
+{
+	DBGFUNC ("enter qu_seturbstate\n");
+	urb->pipe &= ~0x1f;
+	urb->pipe |= state & 0x1f;
+}
+
+/***************************************************************************
+ * Function Name : qu_urbstate
+ *
+ * This function get the current state of the URB.  
+ * 
+ * Input: urb = USB request block data structure 
+ *
+ * Return: none  
+ **************************************************************************/
+static inline int qu_urbstate (struct urb * urb)
+{
+
+	DBGFUNC ("enter qu_urbstate\n");
+
+	return urb->pipe & 0x1f;
+}
+
+/***************************************************************************
+ * Function Name : qu_queue_active_urb
+ *
+ * This function adds the urb to the appropriate active urb list and set
+ * the urb state.
+ * 
+ * There are four active lists: isochoronous list, interrupt list, 
+ * control list, and bulk list.
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *        ed = endpoint descriptor
+ *
+ * Return: none  
+ **************************************************************************/
+static inline void qu_queue_active_urb (hci_t * hci, struct urb * urb, epd_t * ed)
+{
+	int urb_state = 0;
+	DBGFUNC ("enter qu_queue_active_urb\n");
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_CONTROL:
+		list_add (&urb->urb_list, &hci->ctrl_list);
+		urb_state = US_CTRL_SETUP;
+		break;
+
+	case PIPE_BULK:
+		list_add (&urb->urb_list, &hci->bulk_list);
+		if ((urb->transfer_flags & USB_ZERO_PACKET)
+		    && urb->transfer_buffer_length > 0
+		    &&
+		    ((urb->transfer_buffer_length %
+		      usb_maxpacket (urb->dev, urb->pipe,
+				     usb_pipeout (urb->pipe))) == 0)) {
+			urb_state = US_BULK0;
+		}
+		break;
+
+	case PIPE_INTERRUPT:
+		urb->start_frame = hci->frame_number;
+		list_add (&urb->urb_list, &hci->intr_list);
+		break;
+
+	case PIPE_ISOCHRONOUS:
+		list_add (&urb->urb_list, &hci->iso_list);
+		break;
+	}
+
+#ifdef HC_URB_TIMEOUT
+	if (urb->timeout) {
+		ed->timeout.data = (unsigned long) urb;
+		ed->timeout.expires = urb->timeout + jiffies;
+		ed->timeout.function = qu_urb_timeout;
+		add_timer (&ed->timeout);
+	}
+#endif
+
+	qu_seturbstate (urb, urb_state);
+}
+
+/***************************************************************************
+ * Function Name : qu_queue_urb
+ *
+ * This function adds the urb to the endpoint descriptor list 
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *
+ * Return: none  
+ **************************************************************************/
+static int qu_queue_urb (hci_t * hci, struct urb * urb)
+{
+	struct hci_device *hci_dev = usb_to_hci (urb->dev);
+	epd_t *ed = &hci_dev->ed[qu_pipeindex (urb->pipe)];
+
+	DBGFUNC ("Enter qu_queue_urb\n");
+
+	/* for ISOC transfers calculate start frame index */
+
+	if (usb_pipeisoc (urb->pipe) && urb->transfer_flags & USB_ISO_ASAP) {
+		urb->start_frame = ((ed->pipe_head) ? (ed->last_iso + 1) : hci_get_current_frame_number (urb-> dev) + 1) & 0xffff;
+	}
+
+	if (ed->pipe_head) {
+		__list_add (&urb->urb_list, ed->urb_queue.prev,
+			    &(ed->urb_queue));
+	} else {
+		ed->pipe_head = urb;
+		qu_queue_active_urb (hci, urb, ed);
+		if (++hci->active_urbs == 1)
+			hc_start_int (hci);
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : qu_next_urb
+ *
+ * This function removes the URB from the queue and add the next URB to 
+ * active list. 
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *        resub_ok = resubmit flag
+ *
+ * Return: pointer to the next urb  
+ **************************************************************************/
+static struct urb *qu_next_urb (hci_t * hci, struct urb * urb, int resub_ok)
+{
+	struct hci_device *hci_dev = usb_to_hci (urb->dev);
+	epd_t *ed = &hci_dev->ed[qu_pipeindex (urb->pipe)];
+
+	DBGFUNC ("enter qu_next_urb\n");
+	list_del (&urb->urb_list);
+	INIT_LIST_HEAD (&urb->urb_list);
+	if (ed->pipe_head == urb) {
+
+#ifdef HC_URB_TIMEOUT
+		if (urb->timeout)
+			del_timer (&ed->timeout);
+#endif
+
+		if (!--hci->active_urbs)
+			hc_stop_int (hci);
+
+		if (!list_empty (&ed->urb_queue)) {
+			urb = list_entry (ed->urb_queue.next, struct urb, urb_list);
+			list_del (&urb->urb_list);
+			INIT_LIST_HEAD (&urb->urb_list);
+			ed->pipe_head = urb;
+			qu_queue_active_urb (hci, urb, ed);
+		} else {
+			ed->pipe_head = NULL;
+			urb = NULL;
+		}
+	}
+	return urb;
+}
+
+/***************************************************************************
+ * Function Name : qu_return_urb
+ *
+ * This function is part of the return path.   
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *        resub_ok = resubmit flag
+ *
+ * Return: pointer to the next urb  
+ **************************************************************************/
+static struct urb *qu_return_urb (hci_t * hci, struct urb * urb, int resub_ok)
+{
+	struct urb *next_urb;
+
+	DBGFUNC ("enter qu_return_rub\n");
+	next_urb = qu_next_urb (hci, urb, resub_ok);
+	hcs_return_urb (hci, urb, resub_ok);
+	return next_urb;
+}
+
+/***************************************************************************
+ * Function Name : sh_scan_iso_urb_list
+ *
+ * This function goes throught the isochronous urb list and schedule the 
+ * the transfer.   
+ *
+ * Note: This function has not tested yet
+ * 
+ * Input: hci = data structure for the host controller 
+ *        list_lh = pointer to the isochronous list 
+ *        frame_number = the frame number 
+ *
+ * Return: 0 = unsuccessful; 1 = successful  
+ **************************************************************************/
+static int sh_scan_iso_urb_list (hci_t * hci, struct list_head *list_lh,
+				 int frame_number)
+{
+	struct list_head *lh = list_lh->next;
+	struct urb *urb;
+
+	DBGFUNC ("enter sh_scan_iso_urb_list\n");
+	hci->td_array->len = 0;
+
+	while (lh != list_lh) {
+		urb = list_entry (lh, struct urb, urb_list);
+		lh = lh->next;
+		if (((frame_number - urb->start_frame) & 0x7ff) <
+		    urb->number_of_packets) {
+			if (!sh_add_packet (hci, urb)) {
+				return 0;
+			} else {
+				if (((frame_number -
+				      urb->start_frame) & 0x7ff) > 0x400) {
+					if (qu_urbstate (urb) > 0)
+						urb = qu_return_urb (hci, urb, 1);
+					else
+						urb = qu_next_urb (hci, urb, 1);
+
+					if (lh == list_lh && urb)
+						lh = &urb->urb_list;
+				}
+			}
+		}
+	}
+	return 1;
+}
+
+/***************************************************************************
+ * Function Name : sh_scan_urb_list
+ *
+ * This function goes through the urb list and schedule the 
+ * the transaction.   
+ * 
+ * Input: hci = data structure for the host controller 
+ *        list_lh = pointer to the isochronous list 
+ *
+ * Return: 0 = unsuccessful; 1 = successful  
+ **************************************************************************/
+static int sh_scan_urb_list (hci_t * hci, struct list_head *list_lh)
+{
+	struct list_head *lh = NULL;
+	struct urb *urb;
+
+	if (list_lh == NULL) {
+		DBGERR ("sh_scan_urb_list: error, list_lh == NULL\n");
+	}
+
+	DBGFUNC ("enter sh_scan_urb_list: frame# \n");
+
+	list_for_each (lh, list_lh) {
+		urb = list_entry (lh, struct urb, urb_list);
+		if (urb == NULL)
+			return 1;
+		if (!usb_pipeint (urb->pipe)
+		    || (((hci->frame_number - urb->start_frame)
+			 & 0x7ff) >= urb->interval)) {
+			DBGVERBOSE ("sh_scan_urb_list !INT: %d fr_no: %d int: %d pint: %d\n",
+				    urb->start_frame, hci->frame_number, urb->interval,
+				    usb_pipeint (urb->pipe));
+			if (!sh_add_packet (hci, urb)) {
+				return 0;
+			} else {
+				DBGVERBOSE ("INT: start: %d fr_no: %d int: %d pint: %d\n",
+					    urb->start_frame, hci->frame_number,
+					    urb->interval, usb_pipeint (urb->pipe));
+				urb->start_frame = hci->frame_number;
+				return 0;
+
+			}
+		}
+	}
+	return 1;
+}
+
+/***************************************************************************
+ * Function Name : sh_shedule_trans
+ *
+ * This function schedule the USB transaction.
+ * This function will process the endpoint in the following order: 
+ * interrupt, control, and bulk.    
+ * 
+ * Input: hci = data structure for the host controller 
+ *        isSOF = flag indicate if Start Of Frame has occurred 
+ *
+ * Return: 0   
+ **************************************************************************/
+static int sh_schedule_trans (hci_t * hci, int isSOF)
+{
+	int units_left = 1;
+	struct list_head *lh;
+
+	if (hci == NULL) {
+		DBGERR ("sh_schedule_trans: hci == NULL\n");
+		return 0;
+	}
+	if (hci->td_array == NULL) {
+		DBGERR ("sh_schedule_trans: hci->td_array == NULL\n");
+		return 0;
+	}
+
+	if (hci->td_array->len != 0) {
+		DBGERR ("ERROR: schedule, hci->td_array->len = 0x%x, s/b: 0\n",
+			hci->td_array->len);
+	}
+
+	/* schedule the next available interrupt transfer or the next
+	 * stage of the interrupt transfer */
+
+	if (hci->td_array->len == 0 && !list_empty (&hci->intr_list)) {
+		units_left = sh_scan_urb_list (hci, &hci->intr_list);
+	}
+
+	/* schedule the next available control transfer or the next
+	 * stage of the control transfer */
+
+	if (hci->td_array->len == 0 && !list_empty (&hci->ctrl_list) && units_left > 0) {
+		units_left = sh_scan_urb_list (hci, &hci->ctrl_list);
+	}
+
+	/* schedule the next available bulk transfer or the next
+	 * stage of the bulk transfer */
+
+	if (hci->td_array->len == 0 && !list_empty (&hci->bulk_list) && units_left > 0) {
+		sh_scan_urb_list (hci, &hci->bulk_list);
+
+		/* be fair to each BULK URB (move list head around) 
+		 * only when the new SOF happens */
+
+		lh = hci->bulk_list.next;
+		list_del (&hci->bulk_list);
+		list_add (&hci->bulk_list, lh);
+	}
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : sh_add_packet
+ *
+ * This function forms the packet and transmit the packet. This function
+ * will handle all endpoint type: isochoronus, interrupt, control, and 
+ * bulk.
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *
+ * Return: 0 = unsucessful; 1 = successful   
+ **************************************************************************/
+static int sh_add_packet (hci_t * hci, struct urb * urb)
+{
+	__u8 *data = NULL;
+	int len = 0;
+	int toggle = 0;
+	int maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
+	int endpoint = usb_pipeendpoint (urb->pipe);
+	int address = usb_pipedevice (urb->pipe);
+	int slow = (((urb->pipe) >> 26) & 1);
+	int out = usb_pipeout (urb->pipe);
+	int pid = 0;
+	int ret;
+	int i = 0;
+	int iso = 0;
+
+	DBGFUNC ("enter sh_add_packet\n");
+	if (maxps == 0)
+		maxps = 8;
+
+	/* calculate len, toggle bit and add the transaction */
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_ISOCHRONOUS:
+		pid = out ? PID_OUT : PID_IN;
+		iso = 1;
+		i = hci->frame_number - urb->start_frame;
+		data = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+		len = urb->iso_frame_desc[i].length;
+		break;
+
+	case PIPE_BULK:	/* BULK and BULK0 */
+	case PIPE_INTERRUPT:
+		pid = out ? PID_OUT : PID_IN;
+		len = urb->transfer_buffer_length - urb->actual_length;
+		data = urb->transfer_buffer + urb->actual_length;
+		toggle = usb_gettoggle (urb->dev, endpoint, out);
+		break;
+
+	case PIPE_CONTROL:
+		switch (qu_urbstate (urb)) {
+		case US_CTRL_SETUP:
+			len = 8;
+			pid = PID_SETUP;
+			data = urb->setup_packet;
+			toggle = 0;
+			break;
+
+		case US_CTRL_DATA:
+			if (!hci->last_packet_nak) {
+				/* The last packet received is not a nak:
+				 * reset the nak count
+				 */
+
+				hci->nakCnt = 0;
+			}
+			if (urb->transfer_buffer_length != 0) {
+				pid = out ? PID_OUT : PID_IN;
+				len = urb->transfer_buffer_length - urb->actual_length;
+				data = urb->transfer_buffer + urb->actual_length;
+				toggle = (urb->actual_length & maxps) ? 0 : 1;
+				usb_settoggle (urb->dev,
+					       usb_pipeendpoint (urb->pipe),
+					       usb_pipeout (urb->pipe), toggle);
+				break;
+			} else {
+				/* correct state and fall through */
+				qu_seturbstate (urb, US_CTRL_ACK);
+			}
+
+		case US_CTRL_ACK:
+			len = 0;
+
+			/* reply in opposite direction */
+			pid = !out ? PID_OUT : PID_IN;
+			toggle = 1;
+			usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+				       usb_pipeout (urb->pipe), toggle);
+			break;
+		}
+	}
+
+	ret =
+	    hc_add_trans (hci, len, data, toggle, maxps, slow, endpoint,
+			  address, pid, iso, qu_urbstate (urb));
+
+	DBGVERBOSE ("transfer_pa: addr:%d ep:%d pid:%x tog:%x iso:%x sl:%x "
+		    "max:%d\n len:%d ret:%d data:%p left:%d\n",
+		    address, endpoint, pid, toggle, iso, slow,
+		    maxps, len, ret, data, hci->hp.units_left);
+
+	if (ret >= 0) {
+		hci->td_array->td[hci->td_array->len].urb = urb;
+		hci->td_array->td[hci->td_array->len].len = ret;
+		hci->td_array->td[hci->td_array->len].iso_index = i;
+		hci->td_array->len++;
+		hci->active_trans = 1;
+		return 1;
+	}
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : cc_to_error
+ *
+ * This function maps the SL811HS hardware error code to the linux USB error
+ * code.
+ * 
+ * Input: cc = hardware error code 
+ *
+ * Return: USB error code   
+ **************************************************************************/
+static int cc_to_error (int cc)
+{
+	int errCode = 0;
+	if (cc & SL11H_STATMASK_ERROR) {
+		errCode |= -EILSEQ;
+	} else if (cc & SL11H_STATMASK_OVF) {
+		errCode |= -EOVERFLOW;
+	} else if (cc & SL11H_STATMASK_STALL) {
+		errCode |= -EPIPE;
+	}
+	return errCode;
+}
+
+/***************************************************************************
+ * Function Name : sh_done_list
+ *
+ * This function process the packet when it has done finish transfer.
+ * 
+ * 1) It handles hardware error
+ * 2) It updates the URB state
+ * 3) If the USB transaction is complete, it start the return stack path.
+ * 
+ * Input: hci = data structure for the host controller 
+ *        isExcessNak = flag tells if there excess NAK condition occurred 
+ *
+ * Return:  urb_state or -1 if the transaction has complete   
+ **************************************************************************/
+static int sh_done_list (hci_t * hci, int *isExcessNak)
+{
+	int actbytes = 0;
+	int active = 0;
+	void *data = NULL;
+	int cc;
+	int maxps;
+	int toggle;
+	struct urb *urb;
+	int urb_state = 0;
+	int ret = 1;		/* -1 parse abbort, 1 parse ok, 0 last element */
+	int trans = 0;
+	int len;
+	int iso_index = 0;
+	int out;
+	int pid = 0;
+	int debugLen = 0;
+
+	*isExcessNak = 0;
+
+	DBGFUNC ("enter sh_done_list: td_array->len = 0x%x\n",
+		 hci->td_array->len);
+
+	debugLen = hci->td_array->len;
+	if (debugLen > 1)
+		DBGERR ("sh_done_list: td_array->len = 0x%x > 1\n",
+			hci->td_array->len);
+
+	for (trans = 0; ret && trans < hci->td_array->len && trans < MAX_TRANS;
+	     trans++) {
+		urb = hci->td_array->td[trans].urb;
+		len = hci->td_array->td[trans].len;
+		out = usb_pipeout (urb->pipe);
+
+		if (usb_pipeisoc (urb->pipe)) {
+			iso_index = hci->td_array->td[trans].iso_index;
+			data = urb->transfer_buffer + urb->iso_frame_desc[iso_index].offset;
+			toggle = 0;
+		} else {
+			data = urb->transfer_buffer + urb->actual_length;
+			toggle = usb_gettoggle (urb->dev,
+						usb_pipeendpoint (urb->pipe),
+						usb_pipeout (urb->pipe));
+
+		}
+		urb_state = qu_urbstate (urb);
+		pid = out ? PID_OUT : PID_IN;
+		ret = hc_parse_trans (hci, &actbytes, data, &cc, &toggle, len,
+				      pid, urb_state);
+		maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
+
+		if (maxps == 0)
+			maxps = 8;
+
+		active = (urb_state != US_CTRL_SETUP) && (actbytes && !(actbytes & (maxps - 1)));
+
+		/* If the transfer is not bulk in, then it is necessary to get all
+		 * data specify by the urb->transfer_len.
+		 */
+
+		if (!(usb_pipebulk (urb->pipe) && usb_pipein (urb->pipe)))
+			active = active && (urb->transfer_buffer_length != urb->actual_length + actbytes);
+
+		if (urb->transfer_buffer_length == urb->actual_length + actbytes)
+			active = 0;
+
+		if ((cc &
+		     (SL11H_STATMASK_ERROR | SL11H_STATMASK_TMOUT |
+		      SL11H_STATMASK_OVF | SL11H_STATMASK_STALL))
+		    && !(cc & SL11H_STATMASK_NAK)) {
+			if (++urb->error_count > 3) {
+				DBGERR ("done_list: excessive error: errcount = 0x%x, cc = 0x%x\n",
+					urb->error_count, cc);
+				urb_state = 0;
+				active = 0;
+			} else {
+				DBGERR ("done_list: packet err, cc = 0x%x, "
+					" urb->length = 0x%x, actual_len = 0x%x,"
+					" urb_state =0x%x\n",
+					cc, urb->transfer_buffer_length,
+					urb->actual_length, urb_state);
+//			if (cc & SL11H_STATMASK_STALL) {
+				/* The USB function is STALLED on a control pipe (0), 
+				 * then it needs to send the SETUP command again to 
+				 * clear the STALL condition
+				 */
+
+//				if (usb_pipeendpoint (urb->pipe) == 0) {
+//					urb_state = 2;  
+//					active = 0;
+//				}
+//			} else   
+				active = 1;
+			}
+		} else {
+			if (cc & SL11H_STATMASK_NAK) {
+				if (hci->nakCnt < 0x10000) {
+					hci->nakCnt++;
+					hci->last_packet_nak = 1;
+					active = 1;
+					*isExcessNak = 0;
+				} else {
+					DBGERR ("done_list: nak count exceed limit\n");
+					active = 0;
+					*isExcessNak = 1;
+					hci->nakCnt = 0;
+				}
+			} else {
+				hci->nakCnt = 0;
+				hci->last_packet_nak = 0;
+			}
+
+			if (urb_state != US_CTRL_SETUP) {
+				/* no error */
+				urb->actual_length += actbytes;
+				usb_settoggle (urb->dev,
+					       usb_pipeendpoint (urb->pipe),
+					       usb_pipeout (urb->pipe), toggle);
+			}
+			if (usb_pipeisoc (urb->pipe)) {
+				urb->iso_frame_desc[iso_index].actual_length = actbytes;
+				urb->iso_frame_desc[iso_index].status = cc_to_error (cc);
+				active = (iso_index < urb->number_of_packets);
+			}
+		}
+		if (!active) {
+			if (!urb_state) {
+				urb->status = cc_to_error (cc);
+				if (urb->status) {
+					DBGERR ("error on received packet: urb->status = 0x%x\n",
+						urb->status);
+				}
+				hci->td_array->len = 0;
+				qu_return_urb (hci, urb, 1);
+				return -1;
+			} else {
+				/* We do not want to decrement the urb_state if exceeded nak,
+				 * because we need to finish the data stage of the control 
+				 * packet 
+				 */
+
+				if (!(*isExcessNak))
+					urb_state--;
+				qu_seturbstate (urb, urb_state);
+			}
+		}
+	}
+
+	if (urb_state < 0)
+		DBGERR ("ERROR: done_list, urb_state = %d, suppose > 0\n",
+			urb_state);
+	if (debugLen != hci->td_array->len) {
+		DBGERR ("ERROR: done_list, debugLen!= td_array->len,"
+			"debugLen = 0x%x, hci->td_array->len = 0x%x\n",
+			debugLen, hci->td_array->len);
+	}
+
+	hci->td_array->len = 0;
+
+	return urb_state;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/hc_simple.h linux-2.4.20/drivers/usb/hc_simple.h
--- linux-2.4.19/drivers/usb/hc_simple.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/hc_simple.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,231 @@
+/*-------------------------------------------------------------------------*/
+/* list of all controllers using this driver 
+ * */
+
+static LIST_HEAD (hci_hcd_list);
+
+/* URB states (urb_state) */
+/* isoc, interrupt single state */
+
+/* bulk transfer main state and 0-length packet */
+#define US_BULK		0
+#define US_BULK0	1
+/* three setup states */
+#define US_CTRL_SETUP	2
+#define US_CTRL_DATA	1
+#define US_CTRL_ACK	0
+
+/*-------------------------------------------------------------------------*/
+/* HC private part of a device descriptor
+ * */
+
+#define NUM_EDS 32
+
+typedef struct epd {
+	struct urb *pipe_head;
+	struct list_head urb_queue;
+//	int urb_state;
+	struct timer_list timeout;
+	int last_iso;		/* timestamp of last queued ISOC transfer */
+
+} epd_t;
+
+struct hci_device {
+	epd_t ed[NUM_EDS];
+};
+
+/*-------------------------------------------------------------------------*/
+/* Virtual Root HUB 
+ */
+
+#define usb_to_hci(usb)	((struct hci_device *)(usb)->hcpriv)
+
+struct virt_root_hub {
+	int devnum;		/* Address of Root Hub endpoint */
+	void *urb;		/* interrupt URB of root hub */
+	int send;		/* active flag */
+	int interval;		/* intervall of roothub interrupt transfers */
+	struct timer_list rh_int_timer;	/* intervall timer for rh interrupt EP */
+};
+
+#if 1
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h and USB spec) */
+
+/* destination of request */
+#define RH_INTERFACE		0x01
+#define RH_ENDPOINT		0x02
+#define RH_OTHER		0x03
+
+#define RH_CLASS		0x20
+#define RH_VENDOR		0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS		0x0080
+#define RH_CLEAR_FEATURE	0x0100
+#define RH_SET_FEATURE		0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR	0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE		0x0280
+#define RH_GET_INTERFACE	0x0A80
+#define RH_SET_INTERFACE	0x0B00
+#define RH_SYNC_FRAME		0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP		0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION	0x00
+#define RH_PORT_ENABLE		0x01
+#define RH_PORT_SUSPEND		0x02
+#define RH_PORT_OVER_CURRENT	0x03
+#define RH_PORT_RESET		0x04
+#define RH_PORT_POWER		0x08
+#define RH_PORT_LOW_SPEED	0x09
+
+#define RH_C_PORT_CONNECTION	0x10
+#define RH_C_PORT_ENABLE	0x11
+#define RH_C_PORT_SUSPEND	0x12
+#define RH_C_PORT_OVER_CURRENT	0x13
+#define RH_C_PORT_RESET		0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER	0x00
+#define RH_C_HUB_OVER_CURRENT	0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP	0x00
+#define RH_ENDPOINT_STALL	0x01
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+/* struct for each HC 
+ */
+
+#define MAX_TRANS	32
+
+typedef struct td {
+	struct urb *urb;
+	__u16 len;
+	__u16 iso_index;
+} td_t;
+
+typedef struct td_array {
+	int len;
+	td_t td[MAX_TRANS];
+} td_array_t;
+
+typedef struct hci {
+	struct virt_root_hub rh;	/* roothub */
+	wait_queue_head_t waitq;	/* deletion of URBs and devices needs a waitqueue */
+	int active;			/* HC is operating */
+
+	struct list_head ctrl_list;	/* set of ctrl endpoints */
+	struct list_head bulk_list;	/* set of bulk endpoints */
+	struct list_head iso_list;	/* set of isoc endpoints */
+	struct list_head intr_list;	/* ordered (tree) set of int endpoints */
+	struct list_head del_list;	/* set of entpoints to be deleted */
+
+	td_array_t *td_array;
+	td_array_t a_td_array;
+	td_array_t i_td_array[2];
+
+	struct list_head hci_hcd_list;	/* list of all hci_hcd */
+	struct usb_bus *bus;		/* our bus */
+
+//	int trans;			/* number of transactions pending */
+	int active_urbs;
+	int active_trans;
+	int frame_number;		/* frame number */
+	hcipriv_t hp;			/* individual part of hc type */
+	int nakCnt;
+	int last_packet_nak;
+
+} hci_t;
+
+/*-------------------------------------------------------------------------*/
+/* condition (error) CC codes and mapping OHCI like
+ */
+
+#define TD_CC_NOERROR		0x00
+#define TD_CC_CRC		0x01
+#define TD_CC_BITSTUFFING	0x02
+#define TD_CC_DATATOGGLEM	0x03
+#define TD_CC_STALL		0x04
+#define TD_DEVNOTRESP		0x05
+#define TD_PIDCHECKFAIL		0x06
+#define TD_UNEXPECTEDPID	0x07
+#define TD_DATAOVERRUN		0x08
+#define TD_DATAUNDERRUN		0x09
+#define TD_BUFFEROVERRUN	0x0C
+#define TD_BUFFERUNDERRUN	0x0D
+#define TD_NOTACCESSED		0x0F
+
+
+/* urb interface functions */
+static int hci_get_current_frame_number (struct usb_device *usb_dev);
+static int hci_unlink_urb (struct urb * urb);
+
+static int qu_queue_urb (hci_t * hci, struct urb * urb);
+
+/* root hub */
+static int rh_init_int_timer (struct urb * urb);
+static int rh_submit_urb (struct urb * urb);
+static int rh_unlink_urb (struct urb * urb);
+
+/* schedule functions */
+static int sh_add_packet (hci_t * hci, struct urb * urb);
+
+/* hc specific functions */
+static inline void hc_flush_data_cache (hci_t * hci, void *data, int len);
+static inline int hc_parse_trans (hci_t * hci, int *actbytes, __u8 * data,
+				  int *cc, int *toggle, int length, int pid,
+				  int urb_state);
+static inline int hc_add_trans (hci_t * hci, int len, void *data, int toggle,
+				int maxps, int slow, int endpoint, int address,
+				int pid, int format, int urb_state);
+
+static void hc_start_int (hci_t * hci);
+static void hc_stop_int (hci_t * hci);
+static void SL811Write (hci_t * hci, char offset, char data);
+
+/* debug| print the main components of an URB     
+ * small: 0) header + data packets 1) just header */
+
+static void urb_print (struct urb * urb, char *str, int small)
+{
+	unsigned int pipe = urb->pipe;
+	int i, len;
+
+	if (!urb->dev || !urb->dev->bus) {
+		dbg ("%s URB: no dev", str);
+		return;
+	}
+
+	printk ("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,flags:%4x,len:%d/%d,stat:%d(%x)\n",
+		str, hci_get_current_frame_number (urb->dev),
+		usb_pipedevice (pipe), usb_pipeendpoint (pipe),
+		usb_pipeout (pipe) ? 'O' : 'I',
+		usb_pipetype (pipe) < 2 ? (usb_pipeint (pipe) ? "INTR" : "ISOC")
+		: (usb_pipecontrol (pipe) ? "CTRL" : "BULK"), urb->transfer_flags,
+		urb->actual_length, urb->transfer_buffer_length, urb->status,
+		urb->status);
+	if (!small) {
+		if (usb_pipecontrol (pipe)) {
+			printk (__FILE__ ": cmd(8):");
+			for (i = 0; i < 8; i++)
+				printk (" %02x", ((__u8 *) urb->setup_packet)[i]);
+			printk ("\n");
+		}
+		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
+			printk (__FILE__ ": data(%d/%d):", urb->actual_length,
+				urb->transfer_buffer_length);
+			len = usb_pipeout (pipe) ? urb-> transfer_buffer_length : urb->actual_length;
+			for (i = 0; i < 2096 && i < len; i++)
+				printk (" %02x", ((__u8 *) urb->transfer_buffer)[i]);
+			printk ("%s stat:%d\n", i < len ? "..." : "",
+				urb->status);
+		}
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/hc_sl811.c linux-2.4.20/drivers/usb/hc_sl811.c
--- linux-2.4.19/drivers/usb/hc_sl811.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/hc_sl811.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,1359 @@
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*
+ * SL811HS USB HCD for Linux Version 0.1 (10/28/2001)
+ * 
+ * requires (includes) hc_simple.[hc] simple generic HCD frontend
+ *  
+ * COPYRIGHT(C) 2001 by CYPRESS SEMICONDUCTOR 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 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
+ *
+ *-------------------------------------------------------------------------*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/list.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/usb.h>
+#include "../core/hcd.h"
+
+#undef HC_URB_TIMEOUT
+#undef HC_SWITCH_INT
+#undef HC_ENABLE_ISOC
+
+#define SL811_DEBUG_ERR
+
+#ifdef SL811_DEBUG_ERR
+#define DBGERR(fmt, args...) printk(fmt,## args)
+#else
+#define DBGERR(fmt, args...)
+#endif
+
+#ifdef SL811_DEBUG
+#define DBG(fmt, args...) printk(fmt,## args)
+#else
+#define DBG(fmt, args...)
+#endif
+
+#ifdef SL811_DEBUG_FUNC
+#define DBGFUNC(fmt, args...) printk(fmt,## args)
+#else
+#define DBGFUNC(fmt, args...)
+#endif
+
+#ifdef SL811_DEBUG_DATA
+#define DBGDATAR(fmt, args...) printk(fmt,## args)
+#define DBGDATAW(fmt, args...) printk(fmt,## args)
+#else
+#define DBGDATAR(fmt, args...)
+#define DBGDATAW(fmt, args...)
+#endif
+
+#ifdef SL811_DEBUG_VERBOSE
+#define DBGVERBOSE(fmt, args...) printk(fmt,## args)
+#else
+#define DBGVERBOSE(fmt, args...)
+#endif
+
+#define TRUE 1
+#define FALSE 0
+
+#define HC_SWITCH_INT
+#include "hc_sl811.h"
+#include "hc_simple.h"
+
+static int urb_debug = 0;
+
+#include "hc_simple.c"
+#include "hc_sl811_rh.c"
+
+/* The base_addr, data_reg_addr, and irq number are board specific.
+ * The current values are design to run on the Accelent SA1110 IDP
+ * NOTE: values need to modify for different development boards 
+ */
+
+static int base_addr = 0xd3800000;
+static int data_reg_addr = 0xd3810000;
+static int irq = 34;
+
+/* forware declaration */
+
+int SL11StartXaction (hci_t * hci, __u8 addr, __u8 epaddr, int pid, int len,
+		      int toggle, int slow, int urb_state);
+
+static int sofWaitCnt = 0;
+
+MODULE_PARM (urb_debug, "i");
+MODULE_PARM_DESC (urb_debug, "debug urb messages, default is 0 (no)");
+
+MODULE_PARM (base_addr, "i");
+MODULE_PARM_DESC (base_addr, "sl811 base address 0xd3800000");
+MODULE_PARM (data_reg_addr, "i");
+MODULE_PARM_DESC (data_reg_addr, "sl811 data register address 0xd3810000");
+MODULE_PARM (irq, "i");
+MODULE_PARM_DESC (irq, "IRQ 34 (default)");
+
+static int hc_reset (hci_t * hci);
+
+/***************************************************************************
+ * Function Name : SL811Read
+ *
+ * Read a byte of data from the SL811H/SL11H
+ *
+ * Input:  hci = data structure for the host controller
+ *         offset = address of SL811/SL11H register or memory
+ *
+ * Return: data 
+ **************************************************************************/
+char SL811Read (hci_t * hci, char offset)
+{
+	hcipriv_t *hp = &hci->hp;
+	char data;
+	writeb (offset, hp->hcport);
+	wmb ();
+	data = readb (hp->hcport2);
+	rmb ();
+	return (data);
+}
+
+/***************************************************************************
+ * Function Name : SL811Write
+ *
+ * Write a byte of data to the SL811H/SL11H
+ *
+ * Input:  hci = data structure for the host controller
+ *         offset = address of SL811/SL11H register or memory
+ *         data  = the data going to write to SL811H
+ *
+ * Return: none 
+ **************************************************************************/
+void SL811Write (hci_t * hci, char offset, char data)
+{
+	hcipriv_t *hp = &hci->hp;
+	writeb (offset, hp->hcport);
+	writeb (data, hp->hcport2);
+	wmb ();
+}
+
+/***************************************************************************
+ * Function Name : SL811BufRead
+ *
+ * Read consecutive bytes of data from the SL811H/SL11H buffer
+ *
+ * Input:  hci = data structure for the host controller
+ *         offset = SL811/SL11H register offset
+ *         buf = the buffer where the data will store
+ *         size = number of bytes to read
+ *
+ * Return: none 
+ **************************************************************************/
+void SL811BufRead (hci_t * hci, short offset, char *buf, short size)
+{
+	hcipriv_t *hp = &hci->hp;
+	if (size <= 0)
+		return;
+	writeb ((char) offset, hp->hcport);
+	wmb ();
+	DBGDATAR ("SL811BufRead: offset = 0x%x, data = ", offset);
+	while (size--) {
+		*buf++ = (char) readb (hp->hcport2);
+		DBGDATAR ("0x%x ", *(buf - 1));
+		rmb ();
+	}
+	DBGDATAR ("\n");
+}
+
+/***************************************************************************
+ * Function Name : SL811BufWrite
+ *
+ * Write consecutive bytes of data to the SL811H/SL11H buffer
+ *
+ * Input:  hci = data structure for the host controller
+ *         offset = SL811/SL11H register offset
+ *         buf = the data buffer 
+ *         size = number of bytes to write
+ *
+ * Return: none 
+ **************************************************************************/
+void SL811BufWrite (hci_t * hci, short offset, char *buf, short size)
+{
+	hcipriv_t *hp = &hci->hp;
+	if (size <= 0)
+		return;
+	writeb ((char) offset, hp->hcport);
+	wmb ();
+	DBGDATAW ("SL811BufWrite: offset = 0x%x, data = ", offset);
+	while (size--) {
+		DBGDATAW ("0x%x ", *buf);
+		writeb (*buf, hp->hcport2);
+		wmb ();
+		buf++;
+	}
+	DBGDATAW ("\n");
+}
+
+/***************************************************************************
+ * Function Name : regTest
+ *
+ * This routine test the Read/Write functionality of SL811HS registers  
+ *
+ * 1) Store original register value into a buffer
+ * 2) Write to registers with a RAMP pattern. (10, 11, 12, ..., 255)
+ * 3) Read from register
+ * 4) Compare the written value with the read value and make sure they are 
+ *    equivalent
+ * 5) Restore the original register value 
+ *
+ * Input:  hci = data structure for the host controller
+ *   
+ *
+ * Return: TRUE = passed; FALSE = failed 
+ **************************************************************************/
+int regTest (hci_t * hci)
+{
+	int i, data, result = TRUE;
+	char buf[256];
+
+	DBGFUNC ("Enter regTest\n");
+	for (i = 0x10; i < 256; i++) {
+		/* save the original buffer */
+		buf[i] = (char) SL811Read (hci, i);
+
+		/* Write the new data to the buffer */
+		SL811Write (hci, i, i);
+	}
+
+	/* compare the written data */
+	for (i = 0x10; i < 256; i++) {
+		data = SL811Read (hci, i);
+		if (data != i) {
+			DBGERR ("Pattern test failed!! value = 0x%x, s/b 0x%x\n",
+				data, i);
+			result = FALSE;
+		}
+	}
+
+	/* restore the data */
+	for (i = 0x10; i < 256; i++) {
+		SL811Write (hci, i, buf[i]);
+	}
+
+	return (result);
+}
+
+/***************************************************************************
+ * Function Name : regShow
+ *
+ * Display all SL811HS register values
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return: none 
+ **************************************************************************/
+void regShow (hci_t * hci)
+{
+	int i;
+	for (i = 0; i < 256; i++) {
+		printk ("offset %d: 0x%x\n", i, SL811Read (hci, i));
+	}
+}
+
+/************************************************************************
+ * Function Name : USBReset
+ *  
+ * This function resets SL811HS controller and detects the speed of
+ * the connecting device				  
+ *
+ * Input:  hci = data structure for the host controller
+ *                
+ * Return: 0 = no device attached; 1 = USB device attached
+ *                
+ ***********************************************************************/
+static int USBReset (hci_t * hci)
+{
+	int status;
+	hcipriv_t *hp = &hci->hp;
+
+	DBGFUNC ("enter USBReset\n");
+
+	SL811Write (hci, SL11H_CTLREG2, 0xae);
+
+	// setup master and full speed
+
+	SL811Write (hci, SL11H_CTLREG1, 0x08);	// reset USB
+	mdelay (20);		// 20ms                             
+	SL811Write (hci, SL11H_CTLREG1, 0);	// remove SE0        
+
+	for (status = 0; status < 100; status++)
+		SL811Write (hci, SL11H_INTSTATREG, 0xff);	// clear all interrupt bits
+
+	status = SL811Read (hci, SL11H_INTSTATREG);
+
+	if (status & 0x40)	// Check if device is removed
+	{
+		DBG ("USBReset: Device removed\n");
+		SL811Write (hci, SL11H_INTENBLREG,
+			    SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |
+			    SL11H_INTMASK_INSRMV);
+		hp->RHportStatus->portStatus &=
+		    ~(PORT_CONNECT_STAT | PORT_ENABLE_STAT);
+
+		return 0;
+	}
+
+	SL811Write (hci, SL11H_BUFLNTHREG_B, 0);	//zero lenth
+	SL811Write (hci, SL11H_PIDEPREG_B, 0x50);	//send SOF to EP0       
+	SL811Write (hci, SL11H_DEVADDRREG_B, 0x01);	//address0
+	SL811Write (hci, SL11H_SOFLOWREG, 0xe0);
+
+	if (!(status & 0x80)) {
+		/* slow speed device connect directly to root-hub */
+
+		DBG ("USBReset: low speed Device attached\n");
+		SL811Write (hci, SL11H_CTLREG1, 0x8);
+		mdelay (20);
+		SL811Write (hci, SL11H_SOFTMRREG, 0xee);
+		SL811Write (hci, SL11H_CTLREG1, 0x21);
+
+		/* start the SOF or EOP */
+
+		SL811Write (hci, SL11H_HOSTCTLREG_B, 0x01);
+		hp->RHportStatus->portStatus |=
+		    (PORT_CONNECT_STAT | PORT_LOW_SPEED_DEV_ATTACH_STAT);
+
+		/* clear all interrupt bits */
+
+		for (status = 0; status < 20; status++)
+			SL811Write (hci, SL11H_INTSTATREG, 0xff);
+	} else {
+		/* full speed device connect directly to root hub */
+
+		DBG ("USBReset: full speed Device attached\n");
+		SL811Write (hci, SL11H_CTLREG1, 0x8);
+		mdelay (20);
+		SL811Write (hci, SL11H_SOFTMRREG, 0xae);
+		SL811Write (hci, SL11H_CTLREG1, 0x01);
+
+		/* start the SOF or EOP */
+
+		SL811Write (hci, SL11H_HOSTCTLREG_B, 0x01);
+		hp->RHportStatus->portStatus |= (PORT_CONNECT_STAT);
+		hp->RHportStatus->portStatus &= ~PORT_LOW_SPEED_DEV_ATTACH_STAT;
+
+		/* clear all interrupt bits */
+
+		SL811Write (hci, SL11H_INTSTATREG, 0xff);
+
+	}
+
+	/* enable all interrupts */
+	SL811Write (hci, SL11H_INTENBLREG,
+		    SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |
+		    SL11H_INTMASK_INSRMV);
+
+	return 1;
+}
+
+/*-------------------------------------------------------------------------*/
+/* tl functions */
+static inline void hc_mark_last_trans (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+	__u8 *ptd = hp->tl;
+
+	dbg ("enter hc_mark_last_trans\n");
+	if (ptd == NULL) {
+		printk ("hc_mark_last_trans: ptd = null\n");
+		return;
+	}
+	if (hp->xferPktLen > 0)
+		*(ptd + hp->tl_last) |= (1 << 3);
+}
+
+static inline void hc_flush_data_cache (hci_t * hci, void *data, int len)
+{
+}
+
+/************************************************************************
+ * Function Name : hc_add_trans
+ *  
+ * This function sets up the SL811HS register and transmit the USB packets.
+ * 
+ * 1) Determine if enough time within the current frame to send the packet
+ * 2) Load the data into the SL811HS register
+ * 3) Set the appropriate command to the register and trigger the transmit
+ *
+ * Input:  hci = data structure for the host controller
+ *         len = data length
+ *         data = transmitting data
+ *         toggle = USB toggle bit, either 0 or 1
+ *         maxps = maximum packet size for this endpoint
+ *         slow = speed of the device
+ *         endpoint = endpoint number
+ *         address = USB address of the device
+ *         pid = packet ID
+ *         format = 
+ *         urb_state = the current stage of USB transaction
+ *       
+ * Return: 0 = no time left to schedule the transfer
+ *         1 = success 
+ *                
+ ***********************************************************************/
+static inline int hc_add_trans (hci_t * hci, int len, void *data, int toggle,
+				int maxps, int slow, int endpoint, int address,
+				int pid, int format, int urb_state)
+{
+	hcipriv_t *hp = &hci->hp;
+	__u16 speed;
+	int ii, jj, kk;
+
+	DBGFUNC ("enter hc_addr_trans: len =0x%x, toggle:0x%x, endpoing:0x%x,"
+		 " addr:0x%x, pid:0x%x,format:0x%x\n", len, toggle, endpoint,
+		 i address, pid, format);
+
+	if (len > maxps) {
+		len = maxps;
+	}
+
+	speed = hp->RHportStatus->portStatus;
+	if (speed & PORT_LOW_SPEED_DEV_ATTACH_STAT) {
+//      ii = (8*7*8 + 6*3) * len + 800; 
+		ii = 8 * 8 * len + 1024;
+	} else {
+		if (slow) {
+//          ii = (8*7*8 + 6*3) * len + 800; 
+			ii = 8 * 8 * len + 2048;
+		} else
+//          ii = (8*7 + 6*3)*len + 110;
+			ii = 8 * len + 256;
+	}
+
+	ii += 2 * 10 * len;
+
+	jj = SL811Read (hci, SL11H_SOFTMRREG);
+	kk = (jj & 0xFF) * 64 - ii;
+
+	if (kk < 0) {
+		DBGVERBOSE
+		    ("hc_add_trans: no bandwidth for schedule, ii = 0x%x,"
+		     "jj = 0x%x, len =0x%x, active_trans = 0x%x\n", ii, jj, len,
+		     hci->active_trans);
+		return (-1);
+	}
+
+	if (pid != PID_IN) {
+		/* Load data into hc */
+
+		SL811BufWrite (hci, SL11H_DATA_START, (__u8 *) data, len);
+	}
+
+	/* transmit */
+
+	SL11StartXaction (hci, (__u8) address, (__u8) endpoint, (__u8) pid, len,
+			  toggle, slow, urb_state);
+
+	return len;
+}
+
+/************************************************************************
+ * Function Name : hc_parse_trans
+ *  
+ * This function checks the status of the transmitted or received packet
+ * and copy the data from the SL811HS register into a buffer.
+ *
+ * 1) Check the status of the packet 
+ * 2) If successful, and IN packet then copy the data from the SL811HS register
+ *    into a buffer
+ *
+ * Input:  hci = data structure for the host controller
+ *         actbytes = pointer to actual number of bytes
+ *         data = data buffer
+ *         cc = packet status
+ *         length = the urb transmit length
+ *         pid = packet ID
+ *         urb_state = the current stage of USB transaction
+ *       
+ * Return: 0 
+ ***********************************************************************/
+static inline int hc_parse_trans (hci_t * hci, int *actbytes, __u8 * data,
+				  int *cc, int *toggle, int length, int pid,
+				  int urb_state)
+{
+	__u8 addr;
+	__u8 len;
+
+	DBGFUNC ("enter hc_parse_trans\n");
+
+	/* get packet status; convert ack rcvd to ack-not-rcvd */
+
+	*cc = (int) SL811Read (hci, SL11H_PKTSTATREG);
+
+	if (*cc &
+	    (SL11H_STATMASK_ERROR | SL11H_STATMASK_TMOUT | SL11H_STATMASK_OVF |
+	     SL11H_STATMASK_NAK | SL11H_STATMASK_STALL)) {
+		if (*cc & SL11H_STATMASK_OVF)
+			DBGERR ("parse trans: error recv ack, cc = 0x%x, TX_BASE_Len = "
+				"0x%x, TX_count=0x%x\n", *cc,
+				SL811Read (hci, SL11H_BUFLNTHREG),
+				SL811Read (hci, SL11H_XFERCNTREG));
+
+	} else {
+		DBGVERBOSE ("parse trans: recv ack, cc = 0x%x, len = 0x%x, \n",
+			    *cc, length);
+
+		/* Successful data */
+		if ((pid == PID_IN) && (urb_state != US_CTRL_SETUP)) {
+
+			/* Find the base address */
+			addr = SL811Read (hci, SL11H_BUFADDRREG);
+
+			/* Find the Transmit Length */
+			len = SL811Read (hci, SL11H_BUFLNTHREG);
+
+			/* The actual data length = xmit length reg - xfer count reg */
+			*actbytes = len - SL811Read (hci, SL11H_XFERCNTREG);
+
+			if ((data != NULL) && (*actbytes > 0)) {
+				SL811BufRead (hci, addr, data, *actbytes);
+
+			} else if ((data == NULL) && (*actbytes <= 0)) {
+				DBGERR ("hc_parse_trans: data = NULL or actbyte = 0x%x\n",
+					*actbytes);
+				return 0;
+			}
+		} else if (pid == PID_OUT) {
+			*actbytes = length;
+		} else {
+			// printk ("ERR:parse_trans, pid != IN or OUT, pid = 0x%x\n", pid);
+		}
+		*toggle = !*toggle;
+	}
+
+	return 0;
+}
+
+/************************************************************************
+ * Function Name : hc_start_int
+ *  
+ * This function enables SL811HS interrupts
+ *
+ * Input:  hci = data structure for the host controller
+ *       
+ * Return: none 
+ ***********************************************************************/
+static void hc_start_int (hci_t * hci)
+{
+#ifdef HC_SWITCH_INT
+	int mask =
+	    SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |
+	    SL11H_INTMASK_INSRMV | SL11H_INTMASK_USBRESET;
+	SL811Write (hci, IntEna, mask);
+#endif
+}
+
+/************************************************************************
+ * Function Name : hc_stop_int
+ *  
+ * This function disables SL811HS interrupts
+ *
+ * Input:  hci = data structure for the host controller
+ *       
+ * Return: none 
+ ***********************************************************************/
+static void hc_stop_int (hci_t * hci)
+{
+#ifdef HC_SWITCH_INT
+	SL811Write (hci, SL11H_INTSTATREG, 0xff);
+//  SL811Write(hci, SL11H_INTENBLREG, SL11H_INTMASK_INSRMV);
+
+#endif
+}
+
+/************************************************************************
+ * Function Name : handleInsRmvIntr
+ *  
+ * This function handles the insertion or removal of device on  SL811HS. 
+ * It resets the controller and updates the port status
+ *
+ * Input:  hci = data structure for the host controller
+ *       
+ * Return: none 
+ ***********************************************************************/
+void handleInsRmvIntr (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+
+	USBReset (hci);
+
+	/* Changes in connection status */
+
+	hp->RHportStatus->portChange |= PORT_CONNECT_CHANGE;
+
+	/* Port Enable or Disable */
+
+	if (hp->RHportStatus->portStatus & PORT_CONNECT_STAT) {
+		/* device is connected to the port:
+		 *    1) Enable port 
+		 *    2) Resume ?? 
+		 */
+//               hp->RHportStatus->portChange |= PORT_ENABLE_CHANGE;
+
+		/* Over Current is not supported by the SL811 HW ?? */
+
+		/* How about the Port Power ?? */
+
+	} else {
+		/* Device has disconnect:
+		 *    1) Disable port
+		 */
+
+		hp->RHportStatus->portStatus &= ~(PORT_ENABLE_STAT);
+		hp->RHportStatus->portChange |= PORT_ENABLE_CHANGE;
+
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: SL11StartXaction
+ *  
+ * This functions load the registers with appropriate value and 
+ * transmit the packet.				  
+ *
+ * Input:  hci = data structure for the host controller
+ *         addr = USB address of the device
+ *         epaddr = endpoint number
+ *         pid = packet ID
+ *         len = data length
+ *         toggle = USB toggle bit, either 0 or 1
+ *         slow = speed of the device
+ *         urb_state = the current stage of USB transaction
+ *
+ * Return: 0 = error; 1 = successful
+ *                
+ *****************************************************************/
+int SL11StartXaction (hci_t * hci, __u8 addr, __u8 epaddr, int pid, int len,
+		      int toggle, int slow, int urb_state)
+{
+
+	hcipriv_t *hp = &hci->hp;
+	__u8 cmd = 0;
+	__u8 setup_data[4];
+	__u16 speed;
+
+	speed = hp->RHportStatus->portStatus;
+	if (!(speed & PORT_LOW_SPEED_DEV_ATTACH_STAT) && slow) {
+		cmd |= SL11H_HCTLMASK_PREAMBLE;
+	}
+	switch (pid) {
+	case PID_SETUP:
+		cmd &= SL11H_HCTLMASK_PREAMBLE;
+		cmd |=
+		    (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP |
+		     SL11H_HCTLMASK_WRITE);
+		break;
+
+	case PID_OUT:
+		cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE);
+		cmd |=
+		    (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP |
+		     SL11H_HCTLMASK_WRITE);
+		if (toggle) {
+			cmd |= SL11H_HCTLMASK_SEQ;
+		}
+		break;
+
+	case PID_IN:
+		cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE);
+		cmd |= (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP);
+		break;
+
+	default:
+		DBGERR ("ERR: SL11StartXaction: unknow pid = 0x%x\n", pid);
+		return 0;
+	}
+	setup_data[0] = SL11H_DATA_START;
+	setup_data[1] = len;
+	setup_data[2] = (((pid & 0x0F) << 4) | (epaddr & 0xF));
+	setup_data[3] = addr & 0x7F;
+
+	SL811BufWrite (hci, SL11H_BUFADDRREG, (__u8 *) & setup_data[0], 4);
+
+	SL811Write (hci, SL11H_HOSTCTLREG, cmd);
+
+#if 0
+	/* The SL811 has a hardware flaw when hub devices sends out
+	 * SE0 between packets. It has been found in a TI chipset and
+	 * cypress hub chipset. It causes the SL811 to hang
+	 * The workaround is to re-issue the preample again.
+	 */
+
+	if ((cmd & SL11H_HCTLMASK_PREAMBLE)) {
+		SL811Write (hci, SL11H_PIDEPREG_B, 0xc0);
+		SL811Write (hci, SL11H_HOSTCTLREG_B, 0x1);	// send the premable
+	}
+#endif
+	return 1;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_interrupt
+ *
+ * Interrupt service routine. 
+ *
+ * 1) determine the causes of interrupt
+ * 2) clears all interrupts
+ * 3) calls appropriate function to service the interrupt
+ *
+ * Input:  irq = interrupt line associated with the controller 
+ *         hci = data structure for the host controller
+ *         r = holds the snapshot of the processor's context before 
+ *             the processor entered interrupt code. (not used here) 
+ *
+ * Return value  : None.
+ *                
+ *****************************************************************/
+static void hc_interrupt (int irq, void *__hci, struct pt_regs *r)
+{
+	char ii;
+	hci_t *hci = __hci;
+	int isExcessNak = 0;
+	int urb_state = 0;
+	char tmpIrq = 0;
+
+	/* Get value from interrupt status register */
+
+	ii = SL811Read (hci, SL11H_INTSTATREG);
+
+	if (ii & SL11H_INTMASK_INSRMV) {
+		/* Device insertion or removal detected for the USB port */
+
+		SL811Write (hci, SL11H_INTENBLREG, 0);
+		SL811Write (hci, SL11H_CTLREG1, 0);
+		mdelay (100);	// wait for device stable 
+		handleInsRmvIntr (hci);
+		return;
+	}
+
+	/* Clear all interrupts */
+
+	SL811Write (hci, SL11H_INTSTATREG, 0xff);
+
+	if (ii & SL11H_INTMASK_XFERDONE) {
+		/* USB Done interrupt occurred */
+
+		urb_state = sh_done_list (hci, &isExcessNak);
+#ifdef WARNING
+		if (hci->td_array->len > 0)
+			printk ("WARNING: IRQ, td_array->len = 0x%x, s/b:0\n",
+				hci->td_array->len);
+#endif
+		if (hci->td_array->len == 0 && !isExcessNak
+		    && !(ii & SL11H_INTMASK_SOFINTR) && (urb_state == 0)) {
+			if (urb_state == 0) {
+				/* All urb_state has not been finished yet! 
+				 * continue with the current urb transaction 
+				 */
+
+				if (hci->last_packet_nak == 0) {
+					if (!usb_pipecontrol
+					    (hci->td_array->td[0].urb->pipe))
+						sh_add_packet (hci, hci->td_array-> td[0].urb);
+				}
+			} else {
+				/* The last transaction has completed:
+				 * schedule the next transaction 
+				 */
+
+				sh_schedule_trans (hci, 0);
+			}
+		}
+		SL811Write (hci, SL11H_INTSTATREG, 0xff);
+		return;
+	}
+
+	if (ii & SL11H_INTMASK_SOFINTR) {
+		hci->frame_number = (hci->frame_number + 1) % 2048;
+		if (hci->td_array->len == 0)
+			sh_schedule_trans (hci, 1);
+		else {
+			if (sofWaitCnt++ > 100) {
+				/* The last transaction has not completed.
+				 * Need to retire the current td, and let
+				 * it transmit again later on.
+				 * (THIS NEEDS TO BE WORK ON MORE, IT SHOULD NEVER 
+				 *  GET TO THIS POINT)
+				 */
+
+				DBGERR ("SOF interrupt: td_array->len = 0x%x, s/b: 0\n",
+					hci->td_array->len);
+				urb_print (hci->td_array->td[hci->td_array->len - 1].urb,
+					   "INTERRUPT", 0);
+				sh_done_list (hci, &isExcessNak);
+				SL811Write (hci, SL11H_INTSTATREG, 0xff);
+				hci->td_array->len = 0;
+				sofWaitCnt = 0;
+			}
+		}
+		tmpIrq = SL811Read (hci, SL11H_INTSTATREG) & SL811Read (hci, SL11H_INTENBLREG);
+		if (tmpIrq) {
+			DBG ("IRQ occurred while service SOF: irq = 0x%x\n",
+			     tmpIrq);
+
+			/* If we receive a DONE IRQ after schedule, need to 
+			 * handle DONE IRQ again 
+			 */
+
+			if (tmpIrq & SL11H_INTMASK_XFERDONE) {
+				DBGERR ("IRQ occurred while service SOF: irq = 0x%x\n",
+					tmpIrq);
+				urb_state = sh_done_list (hci, &isExcessNak);
+			}
+			SL811Write (hci, SL11H_INTSTATREG, 0xff);
+		}
+	} else {
+		DBG ("SL811 ISR: unknown, int = 0x%x \n", ii);
+	}
+
+	SL811Write (hci, SL11H_INTSTATREG, 0xff);
+	return;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_reset
+ *
+ * This function does register test and resets the SL811HS 
+ * controller.
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0
+ *                
+ *****************************************************************/
+static int hc_reset (hci_t * hci)
+{
+	int attachFlag = 0;
+
+	DBGFUNC ("Enter hc_reset\n");
+	regTest (hci);
+	attachFlag = USBReset (hci);
+	if (attachFlag) {
+		setPortChange (hci, PORT_CONNECT_CHANGE);
+	}
+	return (0);
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_alloc_trans_buffer
+ *
+ * This function allocates all transfer buffer  
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0
+ *                
+ *****************************************************************/
+static int hc_alloc_trans_buffer (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+	int maxlen;
+
+	hp->itl0_len = 0;
+	hp->itl1_len = 0;
+	hp->atl_len = 0;
+
+	hp->itl_buffer_len = 1024;
+	hp->atl_buffer_len = 4096 - 2 * hp->itl_buffer_len;	/* 2048 */
+
+	maxlen = (hp->itl_buffer_len > hp->atl_buffer_len) ? hp->itl_buffer_len : hp->atl_buffer_len;
+
+	hp->tl = kmalloc (maxlen, GFP_KERNEL);
+
+	if (!hp->tl)
+		return -ENOMEM;
+
+	memset (hp->tl, 0, maxlen);
+	return 0;
+}
+
+/*****************************************************************
+ *
+ * Function Name: getPortStatusAndChange
+ *
+ * This function gets the ports status from SL811 and format it 
+ * to a USB request format
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : port status and change
+ *                
+ *****************************************************************/
+static __u32 getPortStatusAndChange (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+	__u32 portstatus;
+
+	DBGFUNC ("enter getPorStatusAndChange\n");
+
+	portstatus = hp->RHportStatus->portChange << 16 | hp->RHportStatus->portStatus;
+
+	return (portstatus);
+}
+
+/*****************************************************************
+ *
+ * Function Name: setPortChange
+ *
+ * This function set the bit position of portChange.
+ *
+ * Input:  hci = data structure for the host controller
+ *         bitPos = the bit position
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+static void setPortChange (hci_t * hci, __u16 bitPos)
+{
+	hcipriv_t *hp = &hci->hp;
+
+	switch (bitPos) {
+	case PORT_CONNECT_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_ENABLE_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_RESET_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_POWER_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_SUSPEND_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_OVER_CURRENT_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: clrPortChange
+ *
+ * This function clear the bit position of portChange.
+ *
+ * Input:  hci = data structure for the host controller
+ *         bitPos = the bit position
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+static void clrPortChange (hci_t * hci, __u16 bitPos)
+{
+	hcipriv_t *hp = &hci->hp;
+	switch (bitPos) {
+	case PORT_CONNECT_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+
+	case PORT_ENABLE_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+
+	case PORT_RESET_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+
+	case PORT_SUSPEND_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+
+	case PORT_OVER_CURRENT_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: clrPortStatus
+ *
+ * This function clear the bit position of portStatus.
+ *
+ * Input:  hci = data structure for the host controller
+ *         bitPos = the bit position
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+static void clrPortStatus (hci_t * hci, __u16 bitPos)
+{
+	hcipriv_t *hp = &hci->hp;
+	switch (bitPos) {
+	case PORT_ENABLE_STAT:
+		hp->RHportStatus->portStatus &= ~bitPos;
+		break;
+
+	case PORT_RESET_STAT:
+		hp->RHportStatus->portStatus &= ~bitPos;
+		break;
+
+	case PORT_POWER_STAT:
+		hp->RHportStatus->portStatus &= ~bitPos;
+		break;
+
+	case PORT_SUSPEND_STAT:
+		hp->RHportStatus->portStatus &= ~bitPos;
+		break;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: setPortStatus
+ *
+ * This function set the bit position of portStatus.
+ *
+ * Input:  hci = data structure for the host controller
+ *         bitPos = the bit position
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+static void setPortStatus (hci_t * hci, __u16 bitPos)
+{
+	hcipriv_t *hp = &hci->hp;
+	switch (bitPos) {
+	case PORT_ENABLE_STAT:
+		hp->RHportStatus->portStatus |= bitPos;
+		break;
+
+	case PORT_RESET_STAT:
+		hp->RHportStatus->portStatus |= bitPos;
+		break;
+
+	case PORT_POWER_STAT:
+		hp->RHportStatus->portStatus |= bitPos;
+		break;
+
+	case PORT_SUSPEND_STAT:
+		hp->RHportStatus->portStatus |= bitPos;
+		break;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_start
+ *
+ * This function starts the root hub functionality. 
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0 
+ *                
+ *****************************************************************/
+static int hc_start (hci_t * hci)
+{
+	DBGFUNC ("Enter hc_start\n");
+
+	rh_connect_rh (hci);
+
+	return 0;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_alloc_hci
+ *
+ * This function allocates all data structure and store in the 
+ * private data structure. 
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0 
+ *                
+ *****************************************************************/
+static hci_t *__devinit hc_alloc_hci (void)
+{
+	hci_t *hci;
+	hcipriv_t *hp;
+	portstat_t *ps;
+	struct usb_bus *bus;
+
+	DBGFUNC ("Enter hc_alloc_hci\n");
+	hci = (hci_t *) kmalloc (sizeof (hci_t), GFP_KERNEL);
+	if (!hci)
+		return NULL;
+
+	memset (hci, 0, sizeof (hci_t));
+
+	hp = &hci->hp;
+
+	hp->irq = -1;
+	hp->hcport = -1;
+
+	/* setup root hub port status */
+
+	ps = (portstat_t *) kmalloc (sizeof (portstat_t), GFP_KERNEL);
+
+	if (!ps)
+		return NULL;
+	ps->portStatus = PORT_STAT_DEFAULT;
+	ps->portChange = PORT_CHANGE_DEFAULT;
+	hp->RHportStatus = ps;
+
+	hci->nakCnt = 0;
+	hci->last_packet_nak = 0;
+
+	hci->a_td_array.len = 0;
+	hci->i_td_array[0].len = 0;
+	hci->i_td_array[1].len = 0;
+	hci->td_array = &hci->a_td_array;
+	hci->active_urbs = 0;
+	hci->active_trans = 0;
+	INIT_LIST_HEAD (&hci->hci_hcd_list);
+	list_add (&hci->hci_hcd_list, &hci_hcd_list);
+	init_waitqueue_head (&hci->waitq);
+
+	INIT_LIST_HEAD (&hci->ctrl_list);
+	INIT_LIST_HEAD (&hci->bulk_list);
+	INIT_LIST_HEAD (&hci->iso_list);
+	INIT_LIST_HEAD (&hci->intr_list);
+	INIT_LIST_HEAD (&hci->del_list);
+
+	bus = usb_alloc_bus (&hci_device_operations);
+	if (!bus) {
+		kfree (hci);
+		return NULL;
+	}
+
+	hci->bus = bus;
+	bus->bus_name = "sl811";
+	bus->hcpriv = (void *) hci;
+
+	return hci;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_release_hci
+ *
+ * This function De-allocate all resources  
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0 
+ *                
+ *****************************************************************/
+static void hc_release_hci (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+
+	DBGFUNC ("Enter hc_release_hci\n");
+
+	/* disconnect all devices */
+	if (hci->bus->root_hub)
+		usb_disconnect (&hci->bus->root_hub);
+
+	hc_reset (hci);
+
+	if (hp->tl)
+		kfree (hp->tl);
+
+	if (hp->hcport > 0) {
+		release_region (hp->hcport, 2);
+		hp->hcport = 0;
+	}
+
+	if (hp->irq >= 0) {
+		free_irq (hp->irq, hci);
+		hp->irq = -1;
+	}
+
+	usb_deregister_bus (hci->bus);
+	usb_free_bus (hci->bus);
+
+	list_del (&hci->hci_hcd_list);
+	INIT_LIST_HEAD (&hci->hci_hcd_list);
+
+	kfree (hci);
+}
+
+/*****************************************************************
+ *
+ * Function Name: init_irq
+ *
+ * This function is board specific.  It sets up the interrupt to 
+ * be an edge trigger and trigger on the rising edge  
+ *
+ * Input: none 
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+void init_irq (void)
+{
+	GPDR &= ~(1 << 13);
+	set_GPIO_IRQ_edge (1 << 13, GPIO_RISING_EDGE);
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_found_hci
+ *
+ * This function request IO memory regions, request IRQ, and
+ * allocate all other resources. 
+ *
+ * Input: addr = first IO address
+ *        addr2 = second IO address
+ *        irq = interrupt number 
+ *
+ * Return: 0 = success or error condition 
+ *                
+ *****************************************************************/
+static int __devinit hc_found_hci (int addr, int addr2, int irq)
+{
+	hci_t *hci;
+	hcipriv_t *hp;
+
+	DBGFUNC ("Enter hc_found_hci\n");
+	hci = hc_alloc_hci ();
+	if (!hci) {
+		return -ENOMEM;
+	}
+
+	init_irq ();
+	hp = &hci->hp;
+
+	if (!request_region (addr, 256, "SL811 USB HOST")) {
+		DBGERR ("request address %d failed", addr);
+		hc_release_hci (hci);
+		return -EBUSY;
+	}
+	hp->hcport = addr;
+	if (!hp->hcport) {
+		DBGERR ("Error mapping SL811 Memory 0x%x", hp->hcport);
+	}
+
+	if (!request_region (addr2, 256, "SL811 USB HOST")) {
+		DBGERR ("request address %d failed", addr2);
+		hc_release_hci (hci);
+		return -EBUSY;
+	}
+	hp->hcport2 = addr2;
+	if (!hp->hcport2) {
+		DBGERR ("Error mapping SL811 Memory 0x%x", hp->hcport2);
+	}
+
+	if (hc_alloc_trans_buffer (hci)) {
+		hc_release_hci (hci);
+		return -ENOMEM;
+	}
+
+	usb_register_bus (hci->bus);
+
+	if (request_irq (irq, hc_interrupt, 0, "SL811", hci) != 0) {
+		DBGERR ("request interrupt %d failed", irq);
+		hc_release_hci (hci);
+		return -EBUSY;
+	}
+	hp->irq = irq;
+
+	printk (KERN_INFO __FILE__ ": USB SL811 at %x, addr2 = %x, IRQ %d\n",
+		addr, addr2, irq);
+	hc_reset (hci);
+
+	if (hc_start (hci) < 0) {
+		DBGERR ("can't start usb-%x", addr);
+		hc_release_hci (hci);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hci_hcd_init
+ *
+ * This is an init function, and it is the first function being called
+ *
+ * Input: none 
+ *
+ * Return: 0 = success or error condition 
+ *                
+ *****************************************************************/
+static int __init hci_hcd_init (void)
+{
+	int ret;
+
+	DBGFUNC ("Enter hci_hcd_init\n");
+	ret = hc_found_hci (base_addr, data_reg_addr, irq);
+
+	return ret;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hci_hcd_cleanup
+ *
+ * This is a cleanup function, and it is called when module is 
+ * unloaded. 
+ *
+ * Input: none 
+ *
+ * Return: none 
+ *                
+ *****************************************************************/
+static void __exit hci_hcd_cleanup (void)
+{
+	struct list_head *hci_l;
+	hci_t *hci;
+
+	DBGFUNC ("Enter hci_hcd_cleanup\n");
+	for (hci_l = hci_hcd_list.next; hci_l != &hci_hcd_list;) {
+		hci = list_entry (hci_l, hci_t, hci_hcd_list);
+		hci_l = hci_l->next;
+		hc_release_hci (hci);
+	}
+}
+
+module_init (hci_hcd_init);
+module_exit (hci_hcd_cleanup);
+
+MODULE_AUTHOR ("Pei Liu <pbl@cypress.com>");
+MODULE_DESCRIPTION ("USB SL811HS Host Controller Driver");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/hc_sl811.h linux-2.4.20/drivers/usb/hc_sl811.h
--- linux-2.4.19/drivers/usb/hc_sl811.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/hc_sl811.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,385 @@
+/*
+ * SL811HS HCD (Host Controller Driver) for USB.
+ * 
+ * COPYRIGHT (C) by CYPRESS SEMICONDUCTOR INC 
+ * 
+ *
+ */
+
+#define GET_FRAME_NUMBER(hci)	READ_REG32 (hci, HcFmNumber)
+
+/*
+ * Maximum number of root hub ports
+ */
+#define MAX_ROOT_PORTS		15	/* maximum OHCI root hub ports */
+
+/* control and status registers */
+#define HcRevision		0x00
+#define HcControl		0x01
+#define HcCommandStatus		0x02
+#define HcInterruptStatus	0x03
+#define HcInterruptEnable	0x04
+#define HcInterruptDisable	0x05
+#define HcFmInterval		0x0D
+#define HcFmRemaining		0x0E
+#define HcFmNumber		0x0F
+#define HcLSThreshold		0x11
+#define HcRhDescriptorA		0x12
+#define HcRhDescriptorB		0x13
+#define HcRhStatus		0x14
+#define HcRhPortStatus		0x15
+
+#define HcHardwareConfiguration 0x20
+#define HcDMAConfiguration	0x21
+#define HcTransferCounter	0x22
+#define HcuPInterrupt		0x24
+#define HcuPInterruptEnable	0x25
+#define HcChipID		0x27
+#define HcScratch		0x28
+#define HcSoftwareReset		0x29
+#define HcITLBufferLength	0x2A
+#define HcATLBufferLength	0x2B
+#define HcBufferStatus		0x2C
+#define HcReadBackITL0Length	0x2D
+#define HcReadBackITL1Length	0x2E
+#define HcITLBufferPort		0x40
+#define HcATLBufferPort		0x41
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_HCFS		(3 << 6)	/* BUS state mask */
+#define OHCI_CTRL_RWC		(1 << 9)	/* remote wakeup connected */
+#define OHCI_CTRL_RWE		(1 << 10)	/* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+#define OHCI_USB_RESET		(0 << 6)
+#define OHCI_USB_RESUME		(1 << 6)
+#define OHCI_USB_OPER		(2 << 6)
+#define OHCI_USB_SUSPEND	(3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR	(1 << 0)	/* host controller reset */
+#define OHCI_SO		(3 << 16)	/* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO	(1 << 0)	/* scheduling overrun */
+
+#define OHCI_INTR_SF	(1 << 2)	/* start frame */
+#define OHCI_INTR_RD	(1 << 3)	/* resume detect */
+#define OHCI_INTR_UE	(1 << 4)	/* unrecoverable error */
+#define OHCI_INTR_FNO	(1 << 5)	/* frame number overflow */
+#define OHCI_INTR_RHSC	(1 << 6)	/* root hub status change */
+#define OHCI_INTR_ATD	(1 << 7)	/* scheduling overrun */
+
+#define OHCI_INTR_MIE	(1 << 31)	/* master interrupt enable */
+
+/*
+ * HcHardwareConfiguration
+ */
+#define InterruptPinEnable	(1 << 0)
+#define InterruptPinTrigger	(1 << 1)
+#define InterruptOutputPolarity	(1 << 2)
+#define DataBusWidth16		(1 << 3)
+#define DREQOutputPolarity	(1 << 5)
+#define DACKInputPolarity	(1 << 6)
+#define EOTInputPolarity	(1 << 7)
+#define DACKMode		(1 << 8)
+#define AnalogOCEnable		(1 << 10)
+#define SuspendClkNotStop	(1 << 11)
+#define DownstreamPort15KRSel	(1 << 12)
+
+/* 
+ * HcDMAConfiguration
+ */
+#define DMAReadWriteSelect 	(1 << 0)
+#define ITL_ATL_DataSelect	(1 << 1)
+#define DMACounterSelect	(1 << 2)
+#define DMAEnable		(1 << 4)
+#define BurstLen_1		0
+#define BurstLen_4		(1 << 5)
+#define BurstLen_8		(2 << 5)
+
+/*
+ * HcuPInterrupt
+ */
+#define SOFITLInt		(1 << 0)
+#define ATLInt			(1 << 1)
+#define AllEOTInterrupt		(1 << 2)
+#define OPR_Reg			(1 << 4)
+#define HCSuspended		(1 << 5)
+#define ClkReady		(1 << 6)
+
+/*
+ * HcBufferStatus
+ */
+#define ITL0BufferFull		(1 << 0)
+#define ITL1BufferFull		(1 << 1)
+#define ATLBufferFull		(1 << 2)
+#define ITL0BufferDone		(1 << 3)
+#define ITL1BufferDone		(1 << 4)
+#define ATLBufferDone		(1 << 5)
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS            0x00000001	/* current connect status */
+#define RH_PS_PES            0x00000002	/* port enable status */
+#define RH_PS_PSS            0x00000004	/* port suspend status */
+#define RH_PS_POCI           0x00000008	/* port over current indicator */
+#define RH_PS_PRS            0x00000010	/* port reset status */
+#define RH_PS_PPS            0x00000100	/* port power status */
+#define RH_PS_LSDA           0x00000200	/* low speed device attached */
+#define RH_PS_CSC            0x00010000	/* connect status change */
+#define RH_PS_PESC           0x00020000	/* port enable status change */
+#define RH_PS_PSSC           0x00040000	/* port suspend status change */
+#define RH_PS_OCIC           0x00080000	/* over current indicator change */
+#define RH_PS_PRSC           0x00100000	/* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS		0x00000001	/* local power status */
+#define RH_HS_OCI		0x00000002	/* over current indicator */
+#define RH_HS_DRWE		0x00008000	/* device remote wakeup enable */
+#define RH_HS_LPSC		0x00010000	/* local power status change */
+#define RH_HS_OCIC		0x00020000	/* over current indicator change */
+#define RH_HS_CRWE		0x80000000	/* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR			0x0000ffff	/* device removable flags */
+#define RH_B_PPCM		0xffff0000	/* port power control mask */
+
+/* roothub.a masks */
+#define	RH_A_NDP		(0xff << 0)	/* number of downstream ports */
+#define	RH_A_PSM		(1 << 8)	/* power switching mode */
+#define	RH_A_NPS		(1 << 9)	/* no power switching */
+#define	RH_A_DT			(1 << 10)	/* device type (mbz) */
+#define	RH_A_OCPM		(1 << 11)	/* over current protection mode */
+#define	RH_A_NOCP		(1 << 12)	/* no over current protection */
+#define	RH_A_POTPGT		(0xff << 24)	/* power on to power good time */
+
+#define URB_DEL 1
+
+#define PORT_STAT_DEFAULT		0x0100
+#define PORT_CONNECT_STAT  		0x1
+#define PORT_ENABLE_STAT		0x2
+#define PORT_SUSPEND_STAT		0x4
+#define PORT_OVER_CURRENT_STAT		0x8
+#define PORT_RESET_STAT			0x10
+#define PORT_POWER_STAT			0x100
+#define PORT_LOW_SPEED_DEV_ATTACH_STAT	0x200
+
+#define PORT_CHANGE_DEFAULT		0x0
+#define PORT_CONNECT_CHANGE		0x1
+#define PORT_ENABLE_CHANGE		0x2
+#define PORT_SUSPEND_CHANGE		0x4
+#define PORT_OVER_CURRENT_CHANGE	0x8
+#define PORT_RESET_CHANGE		0x10
+
+/* Port Status Request info */
+
+typedef struct portstat {
+	__u16 portChange;
+	__u16 portStatus;
+} portstat_t;
+
+typedef struct hcipriv {
+	int irq;
+	int disabled;		/* e.g. got a UE, we're hung */
+	atomic_t resume_count;	/* defending against multiple resumes */
+	struct ohci_regs *regs;	/* OHCI controller's memory */
+	int hcport;		/* I/O base address */
+	int hcport2;		/* I/O data reg addr */
+
+	struct portstat *RHportStatus;	/* root hub port status */
+
+	int intrstatus;
+	__u32 hc_control;	/* copy of the hc control reg */
+
+	int frame;
+
+	__u8 *tl;
+	int xferPktLen;
+	int atl_len;
+	int atl_buffer_len;
+	int itl0_len;
+	int itl1_len;
+	int itl_buffer_len;
+	int itl_index;
+	int tl_last;
+	int units_left;
+
+} hcipriv_t;
+struct hci;
+
+#define cClt        0		// Control
+#define cISO        1		// ISO
+#define cBULK       2		// BULK
+#define cInt        3		// Interrupt
+#define ISO_BIT     0x10
+
+/*-------------------------------------------------------------------------
+ * EP0 use for configuration and Vendor Specific command interface
+ *------------------------------------------------------------------------*/
+#define cMemStart       0x10
+#define EP0Buf          0x40	/* SL11H/SL811H memory start at 0x40 */
+#define EP0Len          0x40	/* Length of config buffer EP0Buf */
+#define EP1Buf          0x60
+#define EP1Len          0x40
+
+/*-------------------------------------------------------------------------
+ * SL11H/SL811H memory from 80h-ffh use as ping-pong buffer.
+ *------------------------------------------------------------------------*/
+#define uBufA           0x80	/* buffer A address for DATA0 */
+#define uBufB           0xc0	/* buffer B address for DATA1 */
+#define uXferLen        0x40	/* xfer length */
+#define sMemSize        0xc0	/* Total SL11 memory size */
+#define cMemEnd         256
+
+/*-------------------------------------------------------------------------
+ * SL811H Register Control memory map
+ * --Note: 
+ *      --SL11H only has one control register set from 0x00-0x04
+ *      --SL811H has two control register set from 0x00-0x04 and 0x08-0x0c
+ *------------------------------------------------------------------------*/
+
+#define EP0Control      0x00
+#define EP0Address      0x01
+#define EP0XferLen      0x02
+#define EP0Status       0x03
+#define EP0Counter      0x04
+
+#define EP1Control      0x08
+#define EP1Address      0x09
+#define EP1XferLen      0x0a
+#define EP1Status       0x0b
+#define EP1Counter      0x0c
+
+#define CtrlReg         0x05
+#define IntEna          0x06
+			 // 0x07 is reserved
+#define IntStatus       0x0d
+#define cDATASet        0x0e
+#define cSOFcnt         0x0f
+#define IntMask         0x57	/* Reset|DMA|EP0|EP2|EP1 for IntEna */
+#define HostMask        0x47	/* Host request command  for IntStatus */
+#define ReadMask        0xd7	/* Read mask interrupt   for IntStatus */
+
+/*-------------------------------------------------------------------------
+ * Standard Chapter 9 definition
+ *-------------------------------------------------------------------------
+ */
+#define GET_STATUS      0x00
+#define CLEAR_FEATURE   0x01
+#define SET_FEATURE     0x03
+#define SET_ADDRESS     0x05
+#define GET_DESCRIPTOR  0x06
+#define SET_DESCRIPTOR  0x07
+#define GET_CONFIG      0x08
+#define SET_CONFIG      0x09
+#define GET_INTERFACE   0x0a
+#define SET_INTERFACE   0x0b
+#define SYNCH_FRAME     0x0c
+
+#define DEVICE          0x01
+#define CONFIGURATION   0x02
+#define STRING          0x03
+#define INTERFACE       0x04
+#define ENDPOINT        0x05
+
+/*-------------------------------------------------------------------------
+ * SL11H/SL811H definition
+ *-------------------------------------------------------------------------
+ */
+#define DATA0_WR	0x07	// (Arm+Enable+tranmist to Host+DATA0)
+#define DATA1_WR	0x47	// (Arm+Enable+tranmist to Host on DATA1)
+#define ZDATA0_WR	0x05	// (Arm+Transaction Ignored+tranmist to Host+DATA0)
+#define ZDATA1_WR	0x45	// (Arm+Transaction Ignored+tranmist to Host+DATA1)
+#define DATA0_RD	0x03	// (Arm+Enable+received from Host+DATA0)
+#define DATA1_RD	0x43	// (Arm+Enable+received from Host+DATA1)
+
+#define PID_SETUP	0x2d	// USB Specification 1.1 Standard Definition
+#define PID_SOF		0xA5
+#define PID_IN		0x69
+#define PID_OUT		0xe1
+
+#define MAX_RETRY	0xffff
+#define TIMEOUT		5		/* 2 mseconds */
+
+#define SL11H_HOSTCTLREG	0
+#define SL11H_BUFADDRREG	1
+#define SL11H_BUFLNTHREG	2
+#define SL11H_PKTSTATREG	3	/* read */
+#define SL11H_PIDEPREG		3	/* write */
+#define SL11H_XFERCNTREG	4	/* read */
+#define SL11H_DEVADDRREG	4	/* write */
+#define SL11H_CTLREG1		5
+#define SL11H_INTENBLREG	6
+
+#define SL11H_HOSTCTLREG_B	8
+#define SL11H_BUFADDRREG_B	9
+#define SL11H_BUFLNTHREG_B	0x0A
+#define SL11H_PKTSTATREG_B	0x0B	/* read */
+#define SL11H_PIDEPREG_B	0x0B	/* write */
+#define SL11H_XFERCNTREG_B	0x0C	/* read */
+#define SL11H_DEVADDRREG_B	0x0C	/* write */
+
+#define SL11H_INTSTATREG	0x0D	/* write clears bitwise */
+#define SL11H_HWREVREG		0x0E	/* read */
+#define SL11H_SOFLOWREG		0x0E	/* write */
+#define SL11H_SOFTMRREG		0x0F	/* read */
+#define SL11H_CTLREG2		0x0F	/* write */
+#define SL11H_DATA_START	0x10
+
+/* Host control register bits (addr 0) */
+#define SL11H_HCTLMASK_ARM	1
+#define SL11H_HCTLMASK_ENBLEP	2
+#define SL11H_HCTLMASK_WRITE	4
+#define SL11H_HCTLMASK_ISOCH	0x10
+#define SL11H_HCTLMASK_AFTERSOF	0x20
+#define SL11H_HCTLMASK_SEQ	0x40
+#define SL11H_HCTLMASK_PREAMBLE	0x80
+
+/* Packet status register bits (addr 3) */
+#define SL11H_STATMASK_ACK	1
+#define SL11H_STATMASK_ERROR	2
+#define SL11H_STATMASK_TMOUT	4
+#define SL11H_STATMASK_SEQ	8
+#define SL11H_STATMASK_SETUP	0x10
+#define SL11H_STATMASK_OVF	0x20
+#define SL11H_STATMASK_NAK	0x40
+#define SL11H_STATMASK_STALL	0x80
+
+/* Control register 1 bits (addr 5) */
+#define SL11H_CTL1MASK_DSBLSOF	1
+#define SL11H_CTL1MASK_NOTXEOF2	4
+#define SL11H_CTL1MASK_DSTATE	0x18
+#define SL11H_CTL1MASK_NSPD	0x20
+#define SL11H_CTL1MASK_SUSPEND	0x40
+#define SL11H_CTL1MASK_CLK12	0x80
+
+#define SL11H_CTL1VAL_RESET	8
+
+/* Interrut enable (addr 6) and interrupt status register bits (addr 0xD) */
+#define SL11H_INTMASK_XFERDONE	1
+#define SL11H_INTMASK_SOFINTR	0x10
+#define SL11H_INTMASK_INSRMV	0x20
+#define SL11H_INTMASK_USBRESET	0x40
+#define SL11H_INTMASK_DSTATE	0x80	/* only in status reg */
+
+/* HW rev and SOF lo register bits (addr 0xE) */
+#define SL11H_HWRMASK_HWREV	0xF0
+
+/* SOF counter and control reg 2 (addr 0xF) */
+#define SL11H_CTL2MASK_SOFHI	0x3F
+#define SL11H_CTL2MASK_DSWAP	0x40
+#define SL11H_CTL2MASK_HOSTMODE	0xae
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/hc_sl811_rh.c linux-2.4.20/drivers/usb/hc_sl811_rh.c
--- linux-2.4.19/drivers/usb/hc_sl811_rh.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/hc_sl811_rh.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,526 @@
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*
+ * SL811HS virtual root hub
+ *  
+ * based on usb-ohci.c by R. Weissgaerber et al.
+ *-------------------------------------------------------------------------*
+ * 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
+ *
+ *-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#undef DEBUG
+#endif
+static __u32 getPortStatusAndChange (hci_t * hci);
+static void setPortStatus (hci_t * hci, __u16 bitPos);
+static void setPortChange (hci_t * hci, __u16 bitPos);
+static void clrPortStatus (hci_t * hci, __u16 bitPos);
+static void clrPortChange (hci_t * hci, __u16 bitPos);
+static int USBReset (hci_t * hci);
+static int cc_to_error (int cc);
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub 
+ *-------------------------------------------------------------------------*/
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] = {
+	0x12,			/*  __u8  bLength; */
+	0x01,			/*  __u8  bDescriptorType; Device */
+	0x10,			/*  __u16 bcdUSB; v1.1 */
+	0x01,
+	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  bDeviceSubClass; */
+	0x00,			/*  __u8  bDeviceProtocol; */
+	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,			/*  __u16 idVendor; */
+	0x00,
+	0x00,			/*  __u16 idProduct; */
+	0x00,
+	0x00,			/*  __u16 bcdDevice; */
+	0x00,
+	0x00,			/*  __u8  iManufacturer; */
+	0x02,			/*  __u8  iProduct; */
+	0x01,			/*  __u8  iSerialNumber; */
+	0x01			/*  __u8  bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] = {
+	0x09,			/*  __u8  bLength; */
+	0x02,			/*  __u8  bDescriptorType; Configuration */
+	0x19,			/*  __u16 wTotalLength; */
+	0x00,
+	0x01,			/*  __u8  bNumInterfaces; */
+	0x01,			/*  __u8  bConfigurationValue; */
+	0x00,			/*  __u8  iConfiguration; */
+	0x40,			/*  __u8  bmAttributes; 
+				   Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 
+				   4..0: resvd */
+	0x00,			/*  __u8  MaxPower; */
+
+	/* interface */
+	0x09,			/*  __u8  if_bLength; */
+	0x04,			/*  __u8  if_bDescriptorType; Interface */
+	0x00,			/*  __u8  if_bInterfaceNumber; */
+	0x00,			/*  __u8  if_bAlternateSetting; */
+	0x01,			/*  __u8  if_bNumEndpoints; */
+	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  if_bInterfaceSubClass; */
+	0x00,			/*  __u8  if_bInterfaceProtocol; */
+	0x00,			/*  __u8  if_iInterface; */
+
+	/* endpoint */
+	0x07,			/*  __u8  ep_bLength; */
+	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
+	0x02,			/*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+	0x00,
+	0xff			/*  __u8  ep_bInterval; 255 ms */
+};
+
+/* Hub class-specific descriptor is constructed dynamically */
+
+/***************************************************************************
+ * Function Name : rh_send_irq
+ * 
+ * This function examine the port change in the virtual root hub.
+ * 
+ * Note: This function assumes only one port exist in the root hub.
+ *
+ * Input:  hci = data structure for the host controller
+ *         rh_data = The pointer to port change data
+ *         rh_len = length of the data in bytes
+ *
+ * Return: length of data  
+ **************************************************************************/
+static int rh_send_irq (hci_t * hci, void *rh_data, int rh_len)
+{
+	int num_ports;
+	int i;
+	int ret;
+	int len;
+	__u8 data[8];
+
+	DBGFUNC ("enter rh_send_irq: \n");
+
+	/* Assuming the root hub has one port.  This value need to change if
+	 * there are more than one port for the root hub
+	 */
+
+	num_ports = 1;
+
+	/* The root hub status is not implemented, it basically has two fields:
+	 *     -- Local Power Status
+	 *     -- Over Current Indicator
+	 *     -- Local Power Change
+	 *     -- Over Current Indicator
+	 *
+	 * Right now, It is assume the power is good and no changes 
+	 */
+
+	*(__u8 *) data = 0;
+
+	ret = *(__u8 *) data;
+
+	/* Has the port status change within the root hub: It checks for
+	 *      -- Port Connect Status change
+	 *      -- Port Enable Change
+	 */
+
+	for (i = 0; i < num_ports; i++) {
+		*(__u8 *) (data + (i + 1) / 8) |=
+		    (((getPortStatusAndChange (hci) >> 16) & (PORT_CONNECT_STAT | PORT_ENABLE_STAT)) ? 1 : 0) << ((i + 1) % 8);
+		ret += *(__u8 *) (data + (i + 1) / 8);
+
+		/* After the port change is read, it should be reset so the next time 
+		 * is it doesn't trigger a change again */
+
+	}
+	len = i / 8 + 1;
+
+	if (ret > 0) {
+		memcpy (rh_data, data, min (len, min (rh_len, (int)sizeof (data))));
+		return len;
+	}
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : rh_int_timer_do
+ * 
+ * This function is called when the timer expires.  It gets the the port 
+ * change data and pass along to the upper protocol.
+ * 
+ * Note:  The virtual root hub interrupt pipe are polled by the timer
+ *        every "interval" ms
+ *
+ * Input:  ptr = ptr to the urb
+ *
+ * Return: none  
+ **************************************************************************/
+static void rh_int_timer_do (unsigned long ptr)
+{
+	int len;
+	struct urb *urb = (struct urb *) ptr;
+	hci_t *hci = urb->dev->bus->hcpriv;
+
+	DBGFUNC ("enter rh_int_timer_do\n");
+
+	if (hci->rh.send) {
+		len = rh_send_irq (hci, urb->transfer_buffer,
+				   urb->transfer_buffer_length);
+		if (len > 0) {
+			urb->actual_length = len;
+			if (urb_debug == 2)
+				urb_print (urb, "RET-t(rh)",
+					   usb_pipeout (urb->pipe));
+
+			if (urb->complete) {
+				urb->complete (urb);
+			}
+		}
+	}
+
+	/* re-activate the timer */
+	rh_init_int_timer (urb);
+}
+
+/***************************************************************************
+ * Function Name : rh_init_int_timer
+ * 
+ * This function creates a timer that act as interrupt pipe in the
+ * virtual hub.   
+ * 
+ * Note:  The virtual root hub's interrupt pipe are polled by the timer
+ *        every "interval" ms
+ *
+ * Input: urb = USB request block 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int rh_init_int_timer (struct urb * urb)
+{
+	hci_t *hci = urb->dev->bus->hcpriv;
+	hci->rh.interval = urb->interval;
+
+	init_timer (&hci->rh.rh_int_timer);
+	hci->rh.rh_int_timer.function = rh_int_timer_do;
+	hci->rh.rh_int_timer.data = (unsigned long) urb;
+	hci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;
+	add_timer (&hci->rh.rh_int_timer);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* helper macro */
+#define OK(x) 			len = (x); break
+
+/***************************************************************************
+ * Function Name : rh_submit_urb
+ * 
+ * This function handles all USB request to the the virtual root hub
+ * 
+ * Input: urb = USB request block 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int rh_submit_urb (struct urb * urb)
+{
+	struct usb_device *usb_dev = urb->dev;
+	hci_t *hci = usb_dev->bus->hcpriv;
+	unsigned int pipe = urb->pipe;
+	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
+	void *data = urb->transfer_buffer;
+	int leni = urb->transfer_buffer_length;
+	int len = 0;
+	int status = TD_CC_NOERROR;
+	__u32 datab[4];
+	__u8 *data_buf = (__u8 *) datab;
+
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+	DBGFUNC ("enter rh_submit_urb\n");
+	if (usb_pipeint (pipe)) {
+		hci->rh.urb = urb;
+		hci->rh.send = 1;
+		hci->rh.interval = urb->interval;
+		rh_init_int_timer (urb);
+		urb->status = cc_to_error (TD_CC_NOERROR);
+
+		return 0;
+	}
+
+	bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8);
+	wValue = le16_to_cpu (cmd->wValue);
+	wIndex = le16_to_cpu (cmd->wIndex);
+	wLength = le16_to_cpu (cmd->wLength);
+
+	DBG ("rh_submit_urb, req = %d(%x) len=%d",
+	     bmRType_bReq, bmRType_bReq, wLength);
+
+	switch (bmRType_bReq) {
+		/* Request Destination:
+		   without flags: Device, 
+		   RH_INTERFACE: interface, 
+		   RH_ENDPOINT: endpoint,
+		   RH_CLASS means HUB here, 
+		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
+		 */
+
+	case RH_GET_STATUS:
+		*(__u16 *) data_buf = cpu_to_le16 (1);
+		OK (2);
+
+	case RH_GET_STATUS | RH_INTERFACE:
+		*(__u16 *) data_buf = cpu_to_le16 (0);
+		OK (2);
+
+	case RH_GET_STATUS | RH_ENDPOINT:
+		*(__u16 *) data_buf = cpu_to_le16 (0);
+		OK (2);
+
+	case RH_GET_STATUS | RH_CLASS:
+		*(__u32 *) data_buf = cpu_to_le32 (0);
+		OK (4);
+
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+		*(__u32 *) data_buf =
+		    cpu_to_le32 (getPortStatusAndChange (hci));
+		OK (4);
+
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		switch (wValue) {
+		case (RH_ENDPOINT_STALL):
+			OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		switch (wValue) {
+		case RH_C_HUB_LOCAL_POWER:
+			OK (0);
+
+		case (RH_C_HUB_OVER_CURRENT):
+			/* Over Current Not Implemented */
+			OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_ENABLE):
+			clrPortStatus (hci, PORT_ENABLE_STAT);
+			OK (0);
+
+		case (RH_PORT_SUSPEND):
+			clrPortStatus (hci, PORT_SUSPEND_STAT);
+			OK (0);
+
+		case (RH_PORT_POWER):
+			clrPortStatus (hci, PORT_POWER_STAT);
+			OK (0);
+
+		case (RH_C_PORT_CONNECTION):
+			clrPortChange (hci, PORT_CONNECT_STAT);
+			OK (0);
+
+		case (RH_C_PORT_ENABLE):
+			clrPortChange (hci, PORT_ENABLE_STAT);
+			OK (0);
+
+		case (RH_C_PORT_SUSPEND):
+			clrPortChange (hci, PORT_SUSPEND_STAT);
+			OK (0);
+
+		case (RH_C_PORT_OVER_CURRENT):
+			clrPortChange (hci, PORT_OVER_CURRENT_STAT);
+			OK (0);
+
+		case (RH_C_PORT_RESET):
+			clrPortChange (hci, PORT_RESET_STAT);
+			OK (0);
+		}
+		break;
+
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_SUSPEND):
+			setPortStatus (hci, PORT_SUSPEND_STAT);
+			OK (0);
+
+		case (RH_PORT_RESET):
+			setPortStatus (hci, PORT_RESET_STAT);
+			// USBReset(hci);
+			clrPortChange (hci,
+				       PORT_CONNECT_CHANGE | PORT_ENABLE_CHANGE
+				       | PORT_SUSPEND_CHANGE |
+				       PORT_OVER_CURRENT_CHANGE);
+			setPortChange (hci, PORT_RESET_CHANGE);
+			clrPortStatus (hci, PORT_RESET_STAT);
+			setPortStatus (hci, PORT_ENABLE_STAT);
+
+			OK (0);
+
+		case (RH_PORT_POWER):
+			setPortStatus (hci, PORT_POWER_STAT);
+			OK (0);
+
+		case (RH_PORT_ENABLE):
+			setPortStatus (hci, PORT_ENABLE_STAT);
+			OK (0);
+		}
+		break;
+
+	case RH_SET_ADDRESS:
+		hci->rh.devnum = wValue;
+		OK (0);
+
+	case RH_GET_DESCRIPTOR:
+		DBGVERBOSE ("rh_submit_urb: RH_GET_DESCRIPTOR, wValue = 0x%x\n", wValue);
+		switch ((wValue & 0xff00) >> 8) {
+		case (0x01):	/* device descriptor */
+			len = min (leni, min ((__u16)sizeof (root_hub_dev_des), wLength));
+			data_buf = root_hub_dev_des;
+			OK (len);
+
+		case (0x02):	/* configuration descriptor */
+			len = min (leni, min ((__u16)sizeof (root_hub_config_des), wLength));
+			data_buf = root_hub_config_des;
+			OK (len);
+
+		case (0x03):	/* string descriptors */
+			len = usb_root_hub_string (wValue & 0xff, (int) (long) 0,
+						   "SL811HS", data, wLength);
+			if (len > 0) {
+				data_buf = data;
+				OK (min (leni, len));
+			}
+
+		default:
+			status = SL11H_STATMASK_STALL;
+		}
+		break;
+
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+		data_buf[0] = 9;	// min length;
+		data_buf[1] = 0x29;
+		data_buf[2] = 1;	// # of downstream port
+		data_buf[3] = 0;
+		datab[1] = 0;
+		data_buf[5] = 50;	// 100 ms for port reset
+		data_buf[7] = 0xfc;	// which port is attachable
+		if (data_buf[2] < 7) {
+			data_buf[8] = 0xff;
+		} else {
+		}
+
+		len = min (leni, min ((__u16)data_buf[0], wLength));
+		OK (len);
+
+	case RH_GET_CONFIGURATION:
+		*(__u8 *) data_buf = 0x01;
+		OK (1);
+
+	case RH_SET_CONFIGURATION:
+		OK (0);
+
+	default:
+		DBGERR ("unsupported root hub command");
+		status = SL11H_STATMASK_STALL;
+	}
+
+	len = min (len, leni);
+	if (data != data_buf)
+		memcpy (data, data_buf, len);
+	urb->actual_length = len;
+	urb->status = cc_to_error (status);
+
+	urb->hcpriv = NULL;
+	urb->dev = NULL;
+	if (urb->complete) {
+		urb->complete (urb);
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : rh_unlink_urb
+ * 
+ * This function unlinks the URB 
+ * 
+ * Input: urb = USB request block 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int rh_unlink_urb (struct urb * urb)
+{
+	hci_t *hci = urb->dev->bus->hcpriv;
+
+	DBGFUNC ("enter rh_unlink_urb\n");
+	if (hci->rh.urb == urb) {
+		hci->rh.send = 0;
+		del_timer (&hci->rh.rh_int_timer);
+		hci->rh.urb = NULL;
+
+		urb->hcpriv = NULL;
+		usb_put_dev (urb->dev);
+		urb->dev = NULL;
+		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+			urb->status = -ECONNRESET;
+			if (urb->complete) {
+				urb->complete (urb);
+			}
+		} else
+			urb->status = -ENOENT;
+	}
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : rh_connect_rh
+ * 
+ * This function connect the virtual root hub to the USB stack 
+ * 
+ * Input: urb = USB request block 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int rh_connect_rh (hci_t * hci)
+{
+	struct usb_device *usb_dev;
+
+	hci->rh.devnum = 0;
+	usb_dev = usb_alloc_dev (NULL, hci->bus);
+	if (!usb_dev)
+		return -ENOMEM;
+
+	hci->bus->root_hub = usb_dev;
+	usb_connect (usb_dev);
+	if (usb_new_device (usb_dev) != 0) {
+		usb_free_dev (usb_dev);
+		return -ENODEV;
+	}
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/hcd/ehci-hcd.c linux-2.4.20/drivers/usb/hcd/ehci-hcd.c
--- linux-2.4.19/drivers/usb/hcd/ehci-hcd.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/hcd/ehci-hcd.c	2002-10-29 11:18:40.000000000 +0000
@@ -434,10 +434,6 @@
 	scan_async (ehci);
 	if (ehci->next_uframe != -1)
 		scan_periodic (ehci);
-
-	// FIXME:  when nothing is connected to the root hub,
-	// turn off the RUN bit so the host can enter C3 "sleep" power
-	// saving mode; make root hub code scan memory less often.
 }
 
 /*-------------------------------------------------------------------------*/
@@ -582,7 +578,10 @@
 		return 0;
 
 	case PIPE_INTERRUPT:
-		intr_deschedule (ehci, urb->start_frame, qh, urb->interval);
+		intr_deschedule (ehci, urb->start_frame, qh,
+			(urb->dev->speed == USB_SPEED_HIGH)
+			    ? urb->interval
+			    : (urb->interval << 3));
 		if (ehci->hcd.state == USB_STATE_HALT)
 			urb->status = -ESHUTDOWN;
 		qh_completions (ehci, qh, 1);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/hcd/ehci-q.c linux-2.4.20/drivers/usb/hcd/ehci-q.c
--- linux-2.4.19/drivers/usb/hcd/ehci-q.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/hcd/ehci-q.c	2002-10-29 11:18:30.000000000 +0000
@@ -368,7 +368,7 @@
 		/* SETUP for control urb? */
 		if (unlikely (QTD_PID (token) == 2))
 			pci_unmap_single (ehci->hcd.pdev,
-				qtd->buf_dma, sizeof (devrequest),
+				qtd->buf_dma, sizeof (struct usb_ctrlrequest),
 				PCI_DMA_TODEVICE);
 	}
 
@@ -419,7 +419,7 @@
 			 */
 			if (!unmapped++ && usb_pipecontrol (urb->pipe)) {
 				direction = PCI_DMA_TODEVICE;
-				size = sizeof (devrequest);
+				size = sizeof (struct usb_ctrlrequest);
 			} else {
 				direction = usb_pipein (urb->pipe)
 					? PCI_DMA_FROMDEVICE
@@ -470,13 +470,13 @@
 		qtd->buf_dma = pci_map_single (
 					ehci->hcd.pdev,
 					urb->setup_packet,
-					sizeof (devrequest),
+					sizeof (struct usb_ctrlrequest),
 					PCI_DMA_TODEVICE);
 		if (unlikely (!qtd->buf_dma))
 			goto cleanup;
 
 		/* SETUP pid */
-		qtd_fill (qtd, qtd->buf_dma, sizeof (devrequest),
+		qtd_fill (qtd, qtd->buf_dma, sizeof (struct usb_ctrlrequest),
 			token | (2 /* "setup" */ << 8));
 
 		/* ... and always at least one more pid */
@@ -681,6 +681,8 @@
 	default:
 #ifdef DEBUG
 		BUG ();
+#else
+		;
 #endif
 	}
 
@@ -817,9 +819,9 @@
 		} else {
 			// dbg_qh ("empty qh", ehci, qh);
 
-// FIXME:  how handle usb_clear_halt() for an EP with queued URBs?
-// usbcore may not let us handle that cleanly...
-// likely must cancel them all first!
+			/* NOTE: we already canceled any queued URBs
+			 * when the endpoint halted.
+			 */
 
 			/* usb_clear_halt() means qh data toggle gets reset */
 			if (usb_pipebulk (urb->pipe)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/hcd/ehci-sched.c linux-2.4.20/drivers/usb/hcd/ehci-sched.c
--- linux-2.4.19/drivers/usb/hcd/ehci-sched.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/hcd/ehci-sched.c	2002-10-29 11:18:36.000000000 +0000
@@ -881,7 +881,7 @@
 	unsigned long	flags
 ) {
 	struct urb				*urb = itd->urb;
-	iso_packet_descriptor_t			*desc;
+	struct iso_packet_descriptor		*desc;
 	u32					t;
 
 	/* update status for this uframe's transfers */
@@ -919,17 +919,9 @@
 		return flags;
 
 	/*
-	 * For now, always give the urb back to the driver ... expect it
-	 * to submit a new urb (or resubmit this), and to have another
-	 * already queued when un-interrupted transfers are needed.
-	 * No, that's not what OHCI or UHCI are now doing.
-	 *
-	 * FIXME Revisit the ISO URB model.  It's cleaner not to have all
-	 * the special case magic, but it'd be faster to reuse existing
-	 * ITD/DMA setup and schedule state.  Easy to dma_sync/complete(),
-	 * then either reschedule or, if unlinking, free and giveback().
-	 * But we can't overcommit like the full and low speed HCs do, and
-	 * there's no clean way to report an error when rescheduling...
+	 * Always give the urb back to the driver ... expect it to submit
+	 * a new urb (or resubmit this), and to have another already queued
+	 * when un-interrupted transfers are needed.
 	 *
 	 * NOTE that for now we don't accelerate ISO unlinks; they just
 	 * happen according to the current schedule.  Means a delay of
@@ -964,15 +956,6 @@
 	if (urb->iso_frame_desc [0].offset != 0)
 		return -EINVAL;
 	
-	/*
-	 * NOTE doing this for now, anticipating periodic URB models
-	 * get updated to be "explicit resubmit".
-	 */
-	if (urb->next) {
-		dbg ("use explicit resubmit for ISO");
-		return -EINVAL;
-	}
-
 	/* allocate ITDs w/o locking anything */
 	status = itd_urb_transaction (ehci, urb, mem_flags);
 	if (status < 0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/hcd.c linux-2.4.20/drivers/usb/hcd.c
--- linux-2.4.19/drivers/usb/hcd.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/hcd.c	2002-10-29 11:18:40.000000000 +0000
@@ -56,7 +56,8 @@
  * USB Host Controller Driver framework
  *
  * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing
- * HCD-specific behaviors/bugs.
+ * HCD-specific behaviors/bugs.  Think of it as the "upper level" of
+ * some drivers, where the "lower level" is hardware-specific.
  *
  * This does error checks, tracks devices and urbs, and delegates to a
  * "hc_driver" only for code (and data) that really needs to know about
@@ -78,6 +79,9 @@
  * Roman Weissgaerber, Rory Bolt, ...
  *
  * HISTORY:
+ * 2002-sept	Merge some 2.5 updates so we can share hardware level HCD
+ * 	code between the 2.4.20+ and 2.5 trees.
+ * 2002-feb	merge to 2.4.19
  * 2001-12-12	Initial patch version for Linux 2.5.1 kernel.
  */
 
@@ -316,16 +320,16 @@
 /* Root hub control transfers execute synchronously */
 static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
 {
-	devrequest	*cmd = (devrequest *) urb->setup_packet;
+	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
  	u16		typeReq, wValue, wIndex, wLength;
 	const u8	*bufp = 0;
 	u8		*ubuf = urb->transfer_buffer;
 	int		len = 0;
 
-	typeReq  = (cmd->requesttype << 8) | cmd->request;
-	wValue   = le16_to_cpu (cmd->value);
-	wIndex   = le16_to_cpu (cmd->index);
-	wLength  = le16_to_cpu (cmd->length);
+	typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;
+	wValue   = le16_to_cpu (cmd->wValue);
+	wIndex   = le16_to_cpu (cmd->wIndex);
+	wLength  = le16_to_cpu (cmd->wLength);
 
 	if (wLength > urb->transfer_buffer_length)
 		goto error;
@@ -583,7 +587,6 @@
 	struct hc_driver	*driver;
 	unsigned long		resource, len;
 	void			*base;
-	u8			latency, limit;
 	struct usb_bus		*bus;
 	struct usb_hcd		*hcd;
 	int			retval, region;
@@ -662,15 +665,6 @@
 	hcd->pdev = dev;
 	info ("%s @ %s, %s", hcd->description,  dev->slot_name, dev->name);
 
-	pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
-	if (latency) {
-		pci_read_config_byte (dev, PCI_MAX_LAT, &limit);
-		if (limit && limit < latency) {
-			dbg ("PCI latency reduced to max %d", limit);
-			pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit);
-		}
-	}
-
 #ifndef __sparc__
 	sprintf (buf, "%d", dev->irq);
 #else
@@ -701,7 +695,8 @@
 		goto clean_3;
 	}
 	hcd->bus = bus;
-	hcd->bus_name = dev->slot_name;
+	hcd->bus_name = dev->slot_name;		/* prefer bus->bus_name */
+	bus->bus_name = dev->slot_name;
 	hcd->product_desc = dev->name;
 	bus->hcpriv = (void *) hcd;
 
@@ -1072,6 +1067,8 @@
 	if (urb->transfer_buffer_length < 0)
 		return -EINVAL;
 
+	// FIXME set urb->transfer_dma and/or setup_dma 
+
 	if (urb->next) {
 		warn ("use explicit queuing not urb->next");
 		return -EINVAL;
@@ -1463,6 +1460,8 @@
 		dbg ("giveback urb %p status %d len %d",
 			urb, urb->status, urb->actual_length);
 
+	// FIXME unmap urb->transfer_dma and/or setup_dma 
+
 	/* pass ownership to the completion handler */
 	urb->complete (urb);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/hcd.h linux-2.4.20/drivers/usb/hcd.h
--- linux-2.4.19/drivers/usb/hcd.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/hcd.h	2002-10-29 11:18:32.000000000 +0000
@@ -153,6 +153,7 @@
 
 #ifdef CONFIG_PCI
 
+struct pci_device_id;
 extern int usb_hcd_pci_probe (struct pci_dev *dev,
 				const struct pci_device_id *id);
 extern void usb_hcd_pci_remove (struct pci_dev *dev);
@@ -206,6 +207,54 @@
 
 /*-------------------------------------------------------------------------*/
 
+/*
+ * Generic bandwidth allocation constants/support
+ */
+#define FRAME_TIME_USECS	1000L
+#define BitTime(bytecount)  (7 * 8 * bytecount / 6)  /* with integer truncation */
+		/* Trying not to use worst-case bit-stuffing
+                   of (7/6 * 8 * bytecount) = 9.33 * bytecount */
+		/* bytecount = data payload byte count */
+
+#define NS_TO_US(ns)	((ns + 500L) / 1000L)
+			/* convert & round nanoseconds to microseconds */
+
+extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb,
+		int bustime, int isoc);
+extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
+		int isoc);
+
+/*
+ * Full/low speed bandwidth allocation constants/support.
+ */
+#define BW_HOST_DELAY	1000L		/* nanoseconds */
+#define BW_HUB_LS_SETUP	333L		/* nanoseconds */
+                        /* 4 full-speed bit times (est.) */
+
+#define FRAME_TIME_BITS         12000L		/* frame = 1 millisecond */
+#define FRAME_TIME_MAX_BITS_ALLOC	(90L * FRAME_TIME_BITS / 100L)
+#define FRAME_TIME_MAX_USECS_ALLOC	(90L * FRAME_TIME_USECS / 100L)
+
+extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
+
+/*
+ * Ceiling microseconds (typical) for that many bytes at high speed
+ * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
+ * to preallocate bandwidth)
+ */
+#define USB2_HOST_DELAY	5	/* nsec, guess */
+#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \
+	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
+	+ USB2_HOST_DELAY)
+#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \
+	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
+	+ USB2_HOST_DELAY)
+
+extern long usb_calc_bus_time (int speed, int is_input,
+			int isoc, int bytecount);
+
+/*-------------------------------------------------------------------------*/
+
 /* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */
 // bleech -- resurfaced in 2.4.11 or 2.4.12
 #define bitmap 	DeviceRemovable
@@ -217,3 +266,20 @@
 
 #define	RUN_CONTEXT (in_irq () ? "in_irq" \
 		: (in_interrupt () ? "in_interrupt" : "can sleep"))
+
+/* 2.5 changes ... */
+
+#ifndef container_of
+#define	container_of	list_entry
+#endif
+
+#define usb_get_urb(x) (x)
+#define usb_put_urb(x)
+
+static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
+	{ return hcd->bus; }
+
+static inline void
+usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe)
+	{ }
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/hid-core.c linux-2.4.20/drivers/usb/hid-core.c
--- linux-2.4.19/drivers/usb/hid-core.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/hid-core.c	2002-10-29 11:18:48.000000000 +0000
@@ -988,7 +988,7 @@
 
 static int hid_submit_out(struct hid_device *hid)
 {
-	hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.length);
+	hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.wLength);
 	hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer;
 	hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr);
 	hid->urbout.dev = hid->dev;
@@ -1018,8 +1018,8 @@
 {
 	hid_output_report(report, hid->out[hid->outhead].buffer);
 
-	hid->out[hid->outhead].dr.value = cpu_to_le16(0x200 | report->id);
-	hid->out[hid->outhead].dr.length = cpu_to_le16((report->size + 7) >> 3);
+	hid->out[hid->outhead].dr.wValue = cpu_to_le16(0x200 | report->id);
+	hid->out[hid->outhead].dr.wLength = cpu_to_le16((report->size + 7) >> 3);
 
 	hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1);
 
@@ -1065,8 +1065,8 @@
 			list = report_enum->report_list.next;
 			while (list != &report_enum->report_list) {
 				report = (struct hid_report *) list;
-				usb_set_idle(hid->dev, hid->ifnum, 0, report->id);
 				hid_read_report(hid, report);
+				usb_set_idle(hid->dev, hid->ifnum, 0, report->id);
 				list = list->next;
 			}
 		}
@@ -1204,9 +1204,9 @@
 	hid->ifnum = interface->bInterfaceNumber;
 
 	for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) {
-		hid->out[n].dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-		hid->out[n].dr.request = USB_REQ_SET_REPORT;
-		hid->out[n].dr.index = cpu_to_le16(hid->ifnum);
+		hid->out[n].dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+		hid->out[n].dr.bRequest = USB_REQ_SET_REPORT;
+		hid->out[n].dr.wIndex = cpu_to_le16(hid->ifnum);
 	}
 
 	hid->name[0] = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/hid-input.c linux-2.4.20/drivers/usb/hid-input.c
--- linux-2.4.19/drivers/usb/hid-input.c	2001-11-11 18:09:37.000000000 +0000
+++ linux-2.4.20/drivers/usb/hid-input.c	2002-10-29 11:18:39.000000000 +0000
@@ -271,7 +271,7 @@
 	set_bit(usage->type, input->evbit);
 
 	while (usage->code <= max && test_and_set_bit(usage->code, bit)) {
-		usage->code = find_next_zero_bit(bit, max + 1, usage->code);
+		usage->code = find_next_zero_bit(bit, usage->code, max + 1);
 	}
 
 	if (usage->code > max) return;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/hid.h linux-2.4.20/drivers/usb/hid.h
--- linux-2.4.19/drivers/usb/hid.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/hid.h	2002-10-29 11:18:31.000000000 +0000
@@ -287,7 +287,7 @@
 #define HID_CONTROL_FIFO_SIZE	8
 
 struct hid_control_fifo {
-	devrequest dr;
+	struct usb_ctrlrequest dr;
 	char buffer[HID_BUFFER_SIZE];
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/hpusbscsi.c linux-2.4.20/drivers/usb/hpusbscsi.c
--- linux-2.4.19/drivers/usb/hpusbscsi.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/hpusbscsi.c	2002-10-29 11:18:51.000000000 +0000
@@ -1,3 +1,51 @@
+/*
+ * hpusbscsi
+ * (C) Copyright 2001 Oliver Neukum 
+ * Sponsored by the Linux Usb Project
+ * Large parts based on or taken from code by John Fremlin and Matt Dharm
+ * 
+ * This driver is known to work with the following scanners (VID, PID)
+ *    (0x03f0, 0x0701)  HP 53xx 
+ *    (0x03f0, 0x0801)  HP 7400 
+ *    (0x0638, 0x026a)  Minolta Scan Dual II
+ *    (0x0686, 0x4004)  Minolta Elite II
+ * To load with full debugging load with "insmod hpusbscsi debug=2"
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Contributors:
+ *   Oliver Neukum
+ *   John Fremlin
+ *   Matt Dharm
+ *   .
+ *   .
+ *   Timothy Jedlicka <bonzo@lucent.com>
+ *
+ * History
+ *
+ * 22-Apr-2002
+ *
+ * - Added Elite II scanner - bonzo
+ * - Cleaned up the debug statements and made them optional at load time - bonzo
+ *
+ * 20020618
+ *
+ * - Confirm to stupid 2.4 rules on io_request_lock
+ *
+ */
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -16,12 +64,28 @@
 
 #include "hpusbscsi.h"
 
-#define DEBUG(x...) \
-	printk( KERN_DEBUG x )
-
 static char *states[]={"FREE", "BEGINNING", "WORKING", "ERROR", "WAIT", "PREMATURE"};
 
-#define TRACE_STATE printk(KERN_DEBUG"hpusbscsi->state = %s at line %d\n", states[hpusbscsi->state], __LINE__)
+/* DEBUG related parts */
+#define HPUSBSCSI_DEBUG
+
+#ifdef HPUSBSCSI_DEBUG
+#  define PDEBUG(level, fmt, args...) \
+          if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , \
+                 ## args)
+#else
+#  define PDEBUG(level, fmt, args...) do {} while(0)
+#endif
+
+
+/* 0=no debug messages
+ * 1=everything but trace states
+ * 2=trace states
+ */
+static int debug; /* = 0 */
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level: 0=none, 1=no trace states, 2=trace states");
 
 /* global variables */
 
@@ -54,7 +118,7 @@
 					      GFP_KERNEL);
 	if (new == NULL)
 		return NULL;
-	DEBUG ("Allocated memory\n");
+	PDEBUG (1, "Allocated memory");
 	memset (new, 0, sizeof (struct hpusbscsi));
 	spin_lock_init (&new->dataurb.lock);
 	spin_lock_init (&new->controlurb.lock);
@@ -136,14 +200,26 @@
 static void
 hpusbscsi_usb_disconnect (struct usb_device *dev, void *ptr)
 {
-                 usb_unlink_urb(&(((struct hpusbscsi *) ptr)->controlurb));
-	((struct hpusbscsi *) ptr)->dev = NULL;
+	struct hpusbscsi *hp = (struct hpusbscsi *)ptr;
+
+	usb_unlink_urb(&hp->controlurb);
+	usb_unlink_urb(&hp->dataurb);
+
+	spin_lock_irq(&io_request_lock);
+	hp->dev = NULL;
+	spin_unlock_irq(&io_request_lock);
 }
 
 static struct usb_device_id hpusbscsi_usb_ids[] = {
 	{USB_DEVICE (0x03f0, 0x0701)},	/* HP 53xx */
 	{USB_DEVICE (0x03f0, 0x0801)},	/* HP 7400 */
+	{USB_DEVICE (0x0638, 0x0268)},  /*iVina 1200U */
 	{USB_DEVICE (0x0638, 0x026a)},	/*Scan Dual II */
+	{USB_DEVICE (0x0638, 0x0A13)},  /*Avision AV600U */
+	{USB_DEVICE (0x0638, 0x0A16)},  /*Avision DS610CU Scancopier */
+	{USB_DEVICE (0x0638, 0x0A18)},  /*Avision AV600U Plus */
+	{USB_DEVICE (0x0638, 0x0A23)},  /*Avision AV220 */
+	{USB_DEVICE (0x0638, 0x0A24)},  /*Avision AV210 */
 	{USB_DEVICE (0x0686, 0x4004)},  /*Minolta Elite II */
 	{}			/* Terminating entry */
 };
@@ -167,7 +243,8 @@
 	int result;
 
 	INIT_LIST_HEAD (&hpusbscsi_devices);
-
+	PDEBUG(0, "driver loaded, DebugLvel=%d", debug);
+ 
 	if ((result = usb_register (&hpusbscsi_usb_driver)) < 0) {
 		printk (KERN_ERR "hpusbscsi: driver registration failed\n");
 		return -1;
@@ -210,6 +287,7 @@
 	/* What a hideous hack! */
 
 	char local_name[48];
+	spin_unlock_irq(&io_request_lock);
 
 
 	/* set up the name of our subdirectory under /proc/scsi/ */
@@ -218,6 +296,7 @@
 	/* FIXME: where is this freed ? */
 
 	if (!sht->proc_name) {
+		spin_lock_irq(&io_request_lock);
 		return 0;
 	}
 
@@ -238,6 +317,7 @@
 
 	if ( 0  >  usb_submit_urb(&desc->controlurb)) {
 		kfree(sht->proc_name);
+		spin_lock_irq(&io_request_lock);
 		return 0;
 	}
 
@@ -246,10 +326,11 @@
 	if (desc->host == NULL) {
 		kfree (sht->proc_name);
 		usb_unlink_urb(&desc->controlurb);
+		spin_lock_irq(&io_request_lock);
 		return 0;
 	}
 	desc->host->hostdata[0] = (unsigned long) desc;
-
+	spin_lock_irq(&io_request_lock);
 
 	return 1;
 }
@@ -260,15 +341,13 @@
 	usb_urb_callback usb_callback;
 	int res;
 
-	hpusbscsi->use_count++;
+	spin_unlock_irq(&io_request_lock);
 
 	/* we don't answer for anything but our single device on any faked host controller */
 	if ( srb->device->lun || srb->device->id || srb->device->channel ) {
-		if (callback) {
-			srb->result = DID_BAD_TARGET;
-			callback(srb);
-		}
-                	goto out;
+		srb->result = DID_BAD_TARGET;
+		callback(srb);
+		goto out;
 	}
 
 	/* Now we need to decide which callback to give to the urb we send the command with */
@@ -297,7 +376,7 @@
 	}
 
 
-	TRACE_STATE;
+	PDEBUG(2, "state= %s", states[hpusbscsi->state]);
 	if (hpusbscsi->state != HP_STATE_FREE) {
 		printk(KERN_CRIT"hpusbscsi - Ouch: queueing violation!\n");
 		return 1; /* This must not happen */
@@ -307,7 +386,7 @@
         memset(srb->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 
 	hpusbscsi->state = HP_STATE_BEGINNING;
-	TRACE_STATE;
+	PDEBUG(2, "state= %s", states[hpusbscsi->state]);
 
 	/* We prepare the urb for writing out the scsi command */
 	FILL_BULK_URB(
@@ -321,19 +400,24 @@
 	);
 	hpusbscsi->scallback = callback;
 	hpusbscsi->srb = srb;
+	
+	if (hpusbscsi->dev == NULL) {
+		srb->result = DID_ERROR;
+		callback(srb);
+		goto out;
+	}
 
 	res = usb_submit_urb(&hpusbscsi->dataurb);
 	if (res) {
 		hpusbscsi->state = HP_STATE_FREE;
-		TRACE_STATE;
-		if (callback) {
-			srb->result = DID_ERROR;
-			callback(srb);
-		}
+		PDEBUG(2, "state= %s", states[hpusbscsi->state]);
+		srb->result = DID_ERROR;
+		callback(srb);
+
 	}
 
 out:
-	hpusbscsi->use_count--;
+	spin_lock_irq(&io_request_lock);
 	return 0;
 }
 
@@ -341,9 +425,9 @@
 {
 	struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
 
-	printk(KERN_DEBUG"SCSI reset requested.\n");
+	PDEBUG(1, "SCSI reset requested");
 	//usb_reset_device(hpusbscsi->dev);
-	//printk(KERN_DEBUG"SCSI reset completed.\n");
+	//PDEBUG(1, "SCSI reset completed");
 	hpusbscsi->state = HP_STATE_FREE;
 
 	return 0;
@@ -352,11 +436,14 @@
 static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb)
 {
 	struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
-	printk(KERN_DEBUG"Request is canceled.\n");
+	PDEBUG(1, "Request is canceled");
 
+	spin_unlock_irq(&io_request_lock);
 	usb_unlink_urb(&hpusbscsi->dataurb);
 	hpusbscsi->state = HP_STATE_FREE;
 
+	spin_lock_irq(&io_request_lock);
+
 	return SCSI_ABORT_PENDING;
 }
 
@@ -376,7 +463,7 @@
 	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
 	u8 scsi_state;
 
-DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
+	PDEBUG(1, "Getting status byte %d",hpusbscsi->scsi_state_byte);
 	if(u->status < 0) {
                 if (hpusbscsi->state != HP_STATE_FREE)
                         handle_usb_error(hpusbscsi);
@@ -402,24 +489,24 @@
 		/* we do a callback to the scsi layer if and only if all data has been transfered */
 		hpusbscsi->scallback(hpusbscsi->srb);
 
-	TRACE_STATE;
+	PDEBUG(2, "state= %s", states[hpusbscsi->state]);
 	switch (hpusbscsi->state) {
 	case HP_STATE_WAIT:
 		hpusbscsi->state = HP_STATE_FREE;
-	TRACE_STATE;
+	PDEBUG(2, "state= %s", states[hpusbscsi->state]);
 		break;
 	case HP_STATE_WORKING:
 	case HP_STATE_BEGINNING:
 		hpusbscsi->state = HP_STATE_PREMATURE;
-	TRACE_STATE;
+	PDEBUG(2, "state= %s", states[hpusbscsi->state]);
 		break;
 	case HP_STATE_ERROR:
 		break;
 	default:
 		printk(KERN_ERR"hpusbscsi: Unexpected status report.\n");
-	TRACE_STATE;
+	PDEBUG(2, "state= %s", states[hpusbscsi->state]);
 		hpusbscsi->state = HP_STATE_FREE;
-	TRACE_STATE;
+	PDEBUG(2, "state= %s", states[hpusbscsi->state]);
 		break;
 	}
 }
@@ -431,15 +518,15 @@
 		handle_usb_error(hpusbscsi);
 		return;
         }
-	TRACE_STATE;
+	PDEBUG(2, "state= %s", states[hpusbscsi->state]);
 	if (hpusbscsi->state != HP_STATE_PREMATURE) {
-	        TRACE_STATE;
+	        PDEBUG(2, "state= %s", states[hpusbscsi->state]);
 		hpusbscsi->state = HP_STATE_WAIT;
 	} else {
 		if (hpusbscsi->scallback != NULL)
 			hpusbscsi->scallback(hpusbscsi->srb);
 		hpusbscsi->state = HP_STATE_FREE;
-	TRACE_STATE;
+	PDEBUG(2, "state= %s", states[hpusbscsi->state]);
 	}
 }
 
@@ -450,7 +537,7 @@
         usb_urb_callback callback;
         int res;
 
-        DEBUG("Going through scatter/gather\n");
+        PDEBUG(1, "Going through scatter/gather"); // bonzo - this gets hit a lot - maybe make it a 2
         if (u->status < 0) {
                 handle_usb_error(hpusbscsi);
                 return;
@@ -461,10 +548,10 @@
         else
                 callback = simple_done;
 
-	TRACE_STATE;
+	PDEBUG(2, "state= %s", states[hpusbscsi->state]);
         if (hpusbscsi->state != HP_STATE_PREMATURE)
 		hpusbscsi->state = HP_STATE_WORKING;
-	TRACE_STATE;
+	PDEBUG(2, "state= %s", states[hpusbscsi->state]);
 
         FILL_BULK_URB(
                 u,
@@ -479,7 +566,7 @@
         res = usb_submit_urb(u);
         if (res)
         	handle_usb_error(hpusbscsi);
-	TRACE_STATE;
+	PDEBUG(2, "state= %s", states[hpusbscsi->state]);
 }
 
 static void simple_done (struct urb *u)
@@ -490,8 +577,8 @@
                 handle_usb_error(hpusbscsi);
                 return;
         }
-        DEBUG("Data transfer done\n");
-	TRACE_STATE;
+	PDEBUG(1, "Data transfer done");
+	PDEBUG(2, "state= %s", states[hpusbscsi->state]);
 	if (hpusbscsi->state != HP_STATE_PREMATURE) {
 		if (u->status < 0) {
 			handle_usb_error(hpusbscsi);
@@ -501,7 +588,7 @@
 			} else {
 				issue_request_sense(hpusbscsi);
 			}
-		TRACE_STATE;
+		PDEBUG(2, "state= %s", states[hpusbscsi->state]);
 		}
 	} else {
 		if (hpusbscsi->scallback != NULL)
@@ -535,10 +622,10 @@
                 handle_usb_error(hpusbscsi);
 		return;
         }
-	TRACE_STATE;
+	PDEBUG(2, "state= %s", states[hpusbscsi->state]);
 	if (hpusbscsi->state != HP_STATE_PREMATURE) {
 		hpusbscsi->state = HP_STATE_WORKING;
-	TRACE_STATE;
+	PDEBUG(2, "state= %s", states[hpusbscsi->state]);
 	}
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/hub.c linux-2.4.20/drivers/usb/hub.c
--- linux-2.4.19/drivers/usb/hub.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.20/drivers/usb/hub.c	2002-10-29 11:18:40.000000000 +0000
@@ -155,7 +155,7 @@
 static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint)
 {
 	struct usb_device *dev = hub->dev;
-	struct usb_hub_status hubstatus;
+	struct usb_hub_status *hubstatus;
 	char portstr[USB_MAXCHILDREN + 1];
 	unsigned int pipe;
 	int i, maxp, ret;
@@ -258,20 +258,29 @@
 
 	dbg("port removable status: %s", portstr);
 
-	ret = usb_get_hub_status(dev, &hubstatus);
+	hubstatus = kmalloc(sizeof *hubstatus, GFP_KERNEL);
+	if (!hubstatus) {
+		err("Unable to allocate hubstatus");
+		kfree(hub->descriptor);
+		return -1;
+	}
+	ret = usb_get_hub_status(dev, hubstatus);
 	if (ret < 0) {
 		err("Unable to get hub status (err = %d)", ret);
+		kfree(hubstatus);
 		kfree(hub->descriptor);
 		return -1;
 	}
 
-	le16_to_cpus(&hubstatus.wHubStatus);
+	le16_to_cpus(&hubstatus->wHubStatus);
 
 	dbg("local power source is %s",
-		(hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good");
+		(hubstatus->wHubStatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good");
 
 	dbg("%sover-current condition exists",
-		(hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
+		(hubstatus->wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
+
+	kfree(hubstatus);
 
 	/* Start the interrupt endpoint */
 	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
@@ -287,8 +296,11 @@
 		return -1;
 	}
 
-	FILL_INT_URB(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq,
-		hub, endpoint->bInterval);
+	FILL_INT_URB(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq, hub,
+		/* NOTE:  in 2.5 fill_int_urb() converts the encoding */
+		(dev->speed == USB_SPEED_HIGH)
+			? 1 << (endpoint->bInterval - 1)
+			: endpoint->bInterval);
 	ret = usb_submit_urb(hub->urb);
 	if (ret) {
 		err("usb_submit_urb failed (%d)", ret);
@@ -666,7 +678,6 @@
 	struct usb_device *dev;
 	unsigned int delay = HUB_SHORT_RESET_TIME;
 	int i;
-	char *portstr, *tempstr;
 
 	dbg("port %d, portstatus %x, change %x, %s",
 		port + 1, portstatus, portchange, portspeed (portstatus));
@@ -694,11 +705,9 @@
 
 	down(&usb_address0_sem);
 
-	tempstr = kmalloc(1024, GFP_KERNEL);
-	portstr = kmalloc(1024, GFP_KERNEL);
-
 	for (i = 0; i < HUB_PROBE_TRIES; i++) {
-		struct usb_device *pdev, *cdev;
+		struct usb_device *pdev;
+		int len;
 
 		/* Allocate a new device struct */
 		dev = usb_alloc_dev(hub, hub->bus);
@@ -728,32 +737,28 @@
 			dev->ttport = port + 1;
 		}
 
-		/* Create a readable topology string */
-		cdev = dev;
+		/* Save readable and stable topology id, distinguishing
+		 * devices by location for diagnostics, tools, etc.  The
+		 * string is a path along hub ports, from the root.  Each
+		 * device's id will be stable until USB is re-cabled, and
+		 * hubs are often labeled with these port numbers.
+		 *
+		 * Initial size: ".NN" times five hubs + NUL = 16 bytes max
+		 * (quite rare, since most hubs have 4-6 ports).
+		 */
 		pdev = dev->parent;
-		if (portstr && tempstr) {
-			portstr[0] = 0;
-			while (pdev) {
-				int port;
-
-				for (port = 0; port < pdev->maxchild; port++)
-					if (pdev->children[port] == cdev)
-						break;
-
-				strcpy(tempstr, portstr);
-				if (!strlen(tempstr))
-					sprintf(portstr, "%d", port + 1);
-				else
-					sprintf(portstr, "%d/%s", port + 1, tempstr);
-
-				cdev = pdev;
-				pdev = pdev->parent;
-			}
-			info("USB new device connect on bus%d/%s, assigned device number %d",
-				dev->bus->busnum, portstr, dev->devnum);
-		} else
-			info("USB new device connect on bus%d, assigned device number %d",
-				dev->bus->busnum, dev->devnum);
+		if (pdev->devpath [0] != '0')	/* parent not root? */
+			len = snprintf (dev->devpath, sizeof dev->devpath,
+				"%s.%d", pdev->devpath, port + 1);
+		/* root == "0", root port 2 == "2", port 3 that hub "2.3" */
+		else
+			len = snprintf (dev->devpath, sizeof dev->devpath,
+				"%d", port + 1);
+		if (len == sizeof dev->devpath)
+			warn ("devpath size! usb/%03d/%03d path %s",
+				dev->bus->busnum, dev->devnum, dev->devpath);
+		info("new USB device %s-%s, assigned address %d",
+			dev->bus->bus_name, dev->devpath, dev->devnum);
 
 		/* Run it through the hoops (find a driver, etc) */
 		if (!usb_new_device(dev))
@@ -770,10 +775,6 @@
 	usb_hub_port_disable(hub, port);
 done:
 	up(&usb_address0_sem);
-	if (portstr)
-		kfree(portstr);
-	if (tempstr)
-		kfree(tempstr);
 }
 
 static void usb_hub_events(void)
@@ -782,7 +783,7 @@
 	struct list_head *tmp;
 	struct usb_device *dev;
 	struct usb_hub *hub;
-	struct usb_hub_status hubsts;
+	struct usb_hub_status *hubsts;
 	u16 hubstatus;
 	u16 hubchange;
 	u16 portstatus;
@@ -872,21 +873,27 @@
 		} /* end for i */
 
 		/* deal with hub status changes */
-		if (usb_get_hub_status(dev, &hubsts) < 0)
-			err("get_hub_status failed");
-		else {
-			hubstatus = le16_to_cpup(&hubsts.wHubStatus);
-			hubchange = le16_to_cpup(&hubsts.wHubChange);
-			if (hubchange & HUB_CHANGE_LOCAL_POWER) {
-				dbg("hub power change");
-				usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER);
-			}
-			if (hubchange & HUB_CHANGE_OVERCURRENT) {
-				dbg("hub overcurrent change");
-				wait_ms(500);	/* Cool down */
-				usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT);
-                        	usb_hub_power_on(hub);
+		hubsts = kmalloc(sizeof *hubsts, GFP_KERNEL);
+		if (!hubsts) {
+			err("couldn't allocate hubsts");
+		} else {
+			if (usb_get_hub_status(dev, hubsts) < 0)
+				err("get_hub_status failed");
+			else {
+				hubstatus = le16_to_cpup(&hubsts->wHubStatus);
+				hubchange = le16_to_cpup(&hubsts->wHubChange);
+				if (hubchange & HUB_CHANGE_LOCAL_POWER) {
+					dbg("hub power change");
+					usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER);
+				}
+				if (hubchange & HUB_CHANGE_OVERCURRENT) {
+					dbg("hub overcurrent change");
+					wait_ms(500);	/* Cool down */
+					usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT);
+					usb_hub_power_on(hub);
+				}
 			}
+			kfree(hubsts);
 		}
 		up(&hub->khubd_sem);
         } /* end while (1) */
@@ -995,7 +1002,7 @@
 int usb_reset_device(struct usb_device *dev)
 {
 	struct usb_device *parent = dev->parent;
-	struct usb_device_descriptor descriptor;
+	struct usb_device_descriptor *descriptor;
 	int i, ret, port = -1;
 
 	if (!parent) {
@@ -1044,17 +1051,22 @@
 	 * If nothing changed, we reprogram the configuration and then
 	 * the alternate settings.
 	 */
-	ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &descriptor,
-			sizeof(descriptor));
+	descriptor = kmalloc(sizeof *descriptor, GFP_NOIO);
+	if (!descriptor) {
+		return -ENOMEM;
+	}
+	ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, descriptor,
+			sizeof(*descriptor));
 	if (ret < 0)
 		return ret;
 
-	le16_to_cpus(&descriptor.bcdUSB);
-	le16_to_cpus(&descriptor.idVendor);
-	le16_to_cpus(&descriptor.idProduct);
-	le16_to_cpus(&descriptor.bcdDevice);
+	le16_to_cpus(&descriptor->bcdUSB);
+	le16_to_cpus(&descriptor->idVendor);
+	le16_to_cpus(&descriptor->idProduct);
+	le16_to_cpus(&descriptor->bcdDevice);
 
-	if (memcmp(&dev->descriptor, &descriptor, sizeof(descriptor))) {
+	if (memcmp(&dev->descriptor, descriptor, sizeof(*descriptor))) {
+		kfree(descriptor);
 		usb_destroy_configuration(dev);
 
 		ret = usb_get_device_descriptor(dev);
@@ -1084,6 +1096,8 @@
 		return 1;
 	}
 
+	kfree(descriptor);
+
 	ret = usb_set_configuration(dev, dev->actconfig->bConfigurationValue);
 	if (ret < 0) {
 		err("failed to set active configuration (error=%d)", ret);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/inode.c linux-2.4.20/drivers/usb/inode.c
--- linux-2.4.19/drivers/usb/inode.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/inode.c	2002-10-29 11:18:32.000000000 +0000
@@ -628,6 +628,7 @@
         s->s_root = d_alloc_root(root_inode);
         if (!s->s_root)
                 goto out_no_root;
+	lock_kernel();
 	list_add_tail(&s->u.usbdevfs_sb.slist, &superlist);
 	for (i = 0; i < NRSPECIAL; i++) {
 		if (!(inode = iget(s, IROOT+1+i)))
@@ -646,6 +647,7 @@
 		recurse_new_dev_inode(bus->root_hub, s);
 	}
 	up (&usb_bus_list_lock);
+	unlock_kernel();
         return s;
 
  out_no_root:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/kaweth.c linux-2.4.20/drivers/usb/kaweth.c
--- linux-2.4.19/drivers/usb/kaweth.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/kaweth.c	2002-10-29 11:18:49.000000000 +0000
@@ -5,17 +5,18 @@
  *     (c) 2000 Interlan Communications
  *     (c) 2000 Stephane Alnet
  *     (C) 2001 Brad Hards
+ *     (C) 2002 Oliver Neukum
  *
  *     Original author: The Zapman <zapman@interlan.net>
- *     Inspired by, and much credit goes to Michael Rothwell 
+ *     Inspired by, and much credit goes to Michael Rothwell
  *     <rothwell@interlan.net> for the test equipment, help, and patience
  *     Based off of (and with thanks to) Petko Manolov's pegaus.c driver.
- *     Also many thanks to Joel Silverman and Ed Surprenant at Kawasaki 
+ *     Also many thanks to Joel Silverman and Ed Surprenant at Kawasaki
  *     for providing the firmware and driver resources.
  *
  *     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, or 
+ *     published by the Free Software Foundation; either version 2, or
  *     (at your option) any later version.
  *
  *     This program is distributed in the hope that it will be useful,
@@ -25,7 +26,7 @@
  *
  *     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. 
+ *     Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
  ****************************************************************/
 
@@ -36,8 +37,8 @@
  * Fix bugs from previous two steps
  * Snoop other OSs for any tricks we're not doing
  * SMP locking
- * Reduce arbitrary timeouts 
- * Smart multicast support 
+ * Reduce arbitrary timeouts
+ * Smart multicast support
  * Temporary MAC change support
  * Tunable SOFs parameter - ioctl()?
  * Ethernet stats collection
@@ -54,7 +55,10 @@
 #include <linux/etherdevice.h>
 #include <linux/usb.h>
 #include <linux/types.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 #include <asm/semaphore.h>
+#include <asm/byteorder.h>
 
 #define DEBUG
 
@@ -73,6 +77,7 @@
 #define KAWETH_MTU			1514
 #define KAWETH_BUF_SIZE			1664
 #define KAWETH_TX_TIMEOUT		(5 * HZ)
+#define KAWETH_SCRATCH_SIZE		32
 #define KAWETH_FIRMWARE_BUF_SIZE	4096
 #define KAWETH_CONTROL_TIMEOUT		(30 * HZ)
 
@@ -98,8 +103,14 @@
 
 #define KAWETH_SOFS_TO_WAIT			0x05
 
+#define INTBUFFERSIZE				4
 
-MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr> and Brad Hards <bhards@bigpond.net.au>");
+#define STATE_OFFSET				0
+#define STATE_MASK				0x40
+#define	STATE_SHIFT				5
+
+
+MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr>, Brad Hards <bhards@bigpond.net.au> and Oliver Neukum <oliver@neukum.org>");
 MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver");
 MODULE_LICENSE("GPL");
 
@@ -110,28 +121,28 @@
 	);
 static void kaweth_disconnect(struct usb_device *dev, void *ptr);
 int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
-				devrequest *cmd, void *data, int len,
-				int timeout);
+				struct usb_ctrlrequest *cmd, void *data,
+				int len, int timeout);
 
 /****************************************************************
  *     usb_device_id
  ****************************************************************/
 static struct usb_device_id usb_klsi_table[] = {
-	{ USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */ 
+	{ USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */
 	{ USB_DEVICE(0x04bb, 0x0901) }, /* I-O DATA USB-ET/T */
-	{ USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */ 
-	{ USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */ 
-	{ USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */ 
+	{ USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */
+	{ USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */
+	{ USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */
 	{ USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */
 	{ USB_DEVICE(0x0565, 0x0003) }, /* Optus@Home UEP1045A */
-	{ USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */ 
+	{ USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */
 	{ USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */
 	{ USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */
-	{ USB_DEVICE(0x066b, 0x2202) }, /* Linksys USB10T */ 
-	{ USB_DEVICE(0x06e1, 0x0008) }, /* ADS USB-10BT */ 
-	{ USB_DEVICE(0x06e1, 0x0009) }, /* ADS USB-10BT */ 
-	{ USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */ 
-	{ USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */ 
+	{ USB_DEVICE(0x066b, 0x2202) }, /* Linksys USB10T */
+	{ USB_DEVICE(0x06e1, 0x0008) }, /* ADS USB-10BT */
+	{ USB_DEVICE(0x06e1, 0x0009) }, /* ADS USB-10BT */
+	{ USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */
+	{ USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */
 	{ USB_DEVICE(0x07b8, 0x4000) }, /* D-Link DU-E10 */
 	{ USB_DEVICE(0x0846, 0x1001) }, /* NetGear EA-101 */
 	{ USB_DEVICE(0x0846, 0x1002) }, /* NetGear EA-101 */
@@ -143,9 +154,10 @@
 	{ USB_DEVICE(0x10bd, 0x1427) }, /* ASANTE USB To Ethernet Adapter */
 	{ USB_DEVICE(0x1342, 0x0204) }, /* Mobility USB-Ethernet Adapter */
 	{ USB_DEVICE(0x13d2, 0x0400) }, /* Shark Pocket Adapter */
-	{ USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */ 
-	{ USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */ 
-	{ USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */ 
+	{ USB_DEVICE(0x1485, 0x0001) },	/* Silicom U2E */
+	{ USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */
+	{ USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */
+	{ USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */
 	{ USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */
 	{} /* Null terminator */
 };
@@ -156,10 +168,10 @@
  *     kaweth_driver
  ****************************************************************/
 static struct usb_driver kaweth_driver = {
-	name:		"kaweth",
-	probe:		kaweth_probe,
-	disconnect:	kaweth_disconnect,
-	id_table:       usb_klsi_table,
+	.name =		"kaweth",
+	.probe =	kaweth_probe,
+	.disconnect =	kaweth_disconnect,
+	.id_table =     usb_klsi_table,
 };
 
 typedef __u8 eth_addr_t[6];
@@ -198,17 +210,25 @@
 	spinlock_t device_lock;
 
 	__u32 status;
+	int end;
+	int removed;
+	int suspend_lowmem;
+	int linkstate;
 
 	struct usb_device *dev;
 	struct net_device *net;
-	wait_queue_head_t control_wait;
+	wait_queue_head_t term_wait;
 
 	struct urb *rx_urb;
 	struct urb *tx_urb;
+	struct urb *irq_urb;
 	
-	__u8 firmware_buf[KAWETH_FIRMWARE_BUF_SIZE];
-	__u8 tx_buf[KAWETH_BUF_SIZE];
+	struct sk_buff *tx_skb;
+
+	__u8 *firmware_buf;
+	__u8 scratch[KAWETH_SCRATCH_SIZE];
 	__u8 rx_buf[KAWETH_BUF_SIZE];
+	__u8 intbuffer[INTBUFFERSIZE];
 	__u16 packet_filter_bitmap;
 
 	struct kaweth_ethernet_configuration configuration;
@@ -221,16 +241,16 @@
  *     kaweth_control
  ****************************************************************/
 static int kaweth_control(struct kaweth_device *kaweth,
-			  unsigned int pipe, 
-			  __u8 request, 
-			  __u8 requesttype, 
-			  __u16 value, 
+			  unsigned int pipe,
+			  __u8 request,
+			  __u8 requesttype,
+			  __u16 value,
 			  __u16 index,
-			  void *data, 
-			  __u16 size, 
+			  void *data,
+			  __u16 size,
 			  int timeout)
 {
-	devrequest *dr;
+	struct usb_ctrlrequest *dr;
 
 	kaweth_dbg("kaweth_control()");
 
@@ -239,19 +259,18 @@
 		return -EBUSY;
 	}
 
-	dr = kmalloc(sizeof(devrequest), GFP_ATOMIC);
+	dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
 
-	if(!dr)
-	{
+	if (!dr) {
 		kaweth_dbg("kmalloc() failed");
 		return -ENOMEM;
 	}
-	
-	dr->requesttype = requesttype;
-	dr->request = request;
-	dr->value = cpu_to_le16p(&value);
-	dr->index = cpu_to_le16p(&index);
-	dr->length = cpu_to_le16p(&size);
+
+	dr->bRequestType= requesttype;
+	dr->bRequest = request;
+	dr->wValue = cpu_to_le16p(&value);
+	dr->wIndex = cpu_to_le16p(&index);
+	dr->wLength = cpu_to_le16p(&size);
 
 	return kaweth_internal_control_msg(kaweth->dev,
 					pipe,
@@ -298,7 +317,7 @@
 				USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
 				urb_size,
 				0,
-				(void *)&kaweth->firmware_buf,
+				(void *)&kaweth->scratch,
 				0,
 				KAWETH_CONTROL_TIMEOUT);
 
@@ -320,7 +339,7 @@
 				USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
 				sofs_wait,
 				0,
-				(void *)&kaweth->firmware_buf,
+				(void *)&kaweth->scratch,
 				0,
 				KAWETH_CONTROL_TIMEOUT);
 
@@ -343,7 +362,7 @@
 				USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
 				receive_filter,
 				0,
-				(void *)&kaweth->firmware_buf,
+				(void *)&kaweth->scratch,
 				0,
 				KAWETH_CONTROL_TIMEOUT);
 
@@ -353,19 +372,19 @@
 /****************************************************************
  *     kaweth_download_firmware
  ****************************************************************/
-static int kaweth_download_firmware(struct kaweth_device *kaweth, 
-				    __u8 *data, 
+static int kaweth_download_firmware(struct kaweth_device *kaweth,
+				    __u8 *data,
 				    __u16 data_len,
 				    __u8 interrupt,
 				    __u8 type)
-{	
+{
 	if(data_len > KAWETH_FIRMWARE_BUF_SIZE)	{
 		kaweth_err("Firmware too big: %d", data_len);
 		return -ENOSPC;
 	}
-	
+
 	memcpy(kaweth->firmware_buf, data, data_len);
-	
+
 	kaweth->firmware_buf[2] = (data_len & 0xFF) - 7;
 	kaweth->firmware_buf[3] = data_len >> 8;
 	kaweth->firmware_buf[4] = type;
@@ -374,8 +393,8 @@
 	kaweth_dbg("High: %i, Low:%i", kaweth->firmware_buf[3],
 		   kaweth->firmware_buf[2]);
 
-	kaweth_dbg("Downloading firmware at %p to kaweth device at %p", 
-	    data, 
+	kaweth_dbg("Downloading firmware at %p to kaweth device at %p",
+	    data,
 	    kaweth);
 	kaweth_dbg("Firmware length: %d", data_len);
 
@@ -385,7 +404,7 @@
 			      USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
 			      0,
 			      0,
-			      (void *)&kaweth->firmware_buf,
+			      (void *)kaweth->firmware_buf,
 			      data_len,
 			      KAWETH_CONTROL_TIMEOUT);
 }
@@ -404,7 +423,7 @@
 	kaweth->firmware_buf[5] = interrupt;
 	kaweth->firmware_buf[6] = 0x00;
 	kaweth->firmware_buf[7] = 0x00;
-	
+
 	kaweth_dbg("Triggering firmware");
 
 	return kaweth_control(kaweth,
@@ -413,7 +432,7 @@
 			      USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
 			      0,
 			      0,
-			      (void *)&kaweth->firmware_buf,
+			      (void *)kaweth->firmware_buf,
 			      8,
 			      KAWETH_CONTROL_TIMEOUT);
 }
@@ -428,12 +447,12 @@
 	kaweth_dbg("kaweth_reset(%p)", kaweth);
 	result = kaweth_control(kaweth,
 				usb_sndctrlpipe(kaweth->dev, 0),
-				USB_REQ_SET_CONFIGURATION, 
-				0, 
+				USB_REQ_SET_CONFIGURATION,
+				0,
 				kaweth->dev->config[0].bConfigurationValue,
-				0, 
-				NULL, 
-				0, 
+				0,
+				NULL,
+				0,
 				KAWETH_CONTROL_TIMEOUT);
 
 	udelay(10000);
@@ -444,15 +463,39 @@
 }
 
 static void kaweth_usb_receive(struct urb *);
+static void kaweth_resubmit_rx_urb(struct kaweth_device *);
+
+/****************************************************************
+	int_callback
+*****************************************************************/
+static void int_callback(struct urb *u)
+{
+	struct kaweth_device *kaweth = u->context;
+	int act_state;
+
+	/* we abuse the interrupt urb for rebsubmitting under low memory saving a timer */
+	if (kaweth->suspend_lowmem)
+		kaweth_resubmit_rx_urb(kaweth);
+
+	/* we check the link state to report changes */
+	if (kaweth->linkstate != (act_state = ( kaweth->intbuffer[STATE_OFFSET] | STATE_MASK) >> STATE_SHIFT)) {
+		if (!act_state)
+			netif_carrier_on(kaweth->net);
+		else
+			netif_carrier_off(kaweth->net);
+
+		kaweth->linkstate = act_state;
+	}
+
+}
 
 /****************************************************************
  *     kaweth_resubmit_rx_urb
  ****************************************************************/
-static inline void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth)
+static void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth)
 {
 	int result;
-
-	memset(kaweth->rx_urb, 0, sizeof(*kaweth->rx_urb));
+	long flags;
 
 	FILL_BULK_URB(kaweth->rx_urb,
 		      kaweth->dev,
@@ -462,9 +505,17 @@
 		      kaweth_usb_receive,
 		      kaweth);
 
-	if((result = usb_submit_urb(kaweth->rx_urb))) {
-		kaweth_err("resubmitting rx_urb %d failed", result);
+	spin_lock_irqsave(&kaweth->device_lock, flags);
+	if (!kaweth->removed) { /* no resubmit if disconnecting */
+		if((result = usb_submit_urb(kaweth->rx_urb))) {
+			if (result == -ENOMEM)
+				kaweth->suspend_lowmem = 1;
+			kaweth_err("resubmitting rx_urb %d failed", result);
+		} else {
+			kaweth->suspend_lowmem = 0;
+		}
 	}
+	spin_unlock_irqrestore(&kaweth->device_lock, flags);
 }
 
 static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth);
@@ -476,23 +527,30 @@
 {
 	struct kaweth_device *kaweth = urb->context;
 	struct net_device *net = kaweth->net;
-	
+
 	int count = urb->actual_length;
 	int count2 = urb->transfer_buffer_length;
-			
+
 	__u16 pkt_len = le16_to_cpup((u16 *)kaweth->rx_buf);
 
 	struct sk_buff *skb;
 
-	if(kaweth->status & KAWETH_STATUS_CLOSING) {
+	if(urb->status == -ECONNRESET || urb->status == -ECONNABORTED)
+	/* we are killed - set a flag and wake the disconnect handler */
+	{
+		kaweth->end = 1;
+		wake_up(&kaweth->term_wait);
 		return;
 	}
-	
-	if(urb->status && urb->status != -EREMOTEIO && count != 1) { 
+
+	if (kaweth->status & KAWETH_STATUS_CLOSING)
+		return;
+
+	if(urb->status && urb->status != -EREMOTEIO && count != 1) {
 		kaweth_err("%s RX status: %d count: %d packet_len: %d",
-                           net->name, 
+                           net->name,
 			   urb->status,
-			   count, 
+			   count,
 			   (int)pkt_len);
 		kaweth_resubmit_rx_urb(kaweth);
                 return;
@@ -506,22 +564,24 @@
 		        kaweth_resubmit_rx_urb(kaweth);
                         return;
                 }
-		
+
 		if(!(skb = dev_alloc_skb(pkt_len+2))) {
 		        kaweth_resubmit_rx_urb(kaweth);
                         return;
 		}
 
+		skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
+
 		skb->dev = net;
 
 		eth_copy_and_sum(skb, kaweth->rx_buf + 2, pkt_len, 0);
-		
+
 		skb_put(skb, pkt_len);
 
 		skb->protocol = eth_type_trans(skb, net);
-		
+
 		netif_rx(skb);
-		
+
 		kaweth->stats.rx_packets++;
 		kaweth->stats.rx_bytes += pkt_len;
 	}
@@ -540,11 +600,23 @@
 
 	kaweth_dbg("Opening network device.");
 
+	MOD_INC_USE_COUNT;
+
 	kaweth_resubmit_rx_urb(kaweth);
 
-	netif_start_queue(net);
+	FILL_INT_URB(
+		kaweth->irq_urb,
+		kaweth->dev,
+		usb_rcvintpipe(kaweth->dev, 3),
+		kaweth->intbuffer,
+		INTBUFFERSIZE,
+		int_callback,
+		kaweth,
+		HZ/4);
 
-	MOD_INC_USE_COUNT;
+	usb_submit_urb(kaweth->irq_urb);
+
+	netif_start_queue(net);
 
 	kaweth_async_set_rx_mode(kaweth);
 	return 0;
@@ -558,9 +630,12 @@
 	struct kaweth_device *kaweth = net->priv;
 
 	netif_stop_queue(net);
-
+	
+	spin_lock_irq(&kaweth->device_lock);
 	kaweth->status |= KAWETH_STATUS_CLOSING;
+	spin_unlock_irq(&kaweth->device_lock);
 
+	usb_unlink_urb(kaweth->irq_urb);
 	usb_unlink_urb(kaweth->rx_urb);
 
 	kaweth->status &= ~KAWETH_STATUS_CLOSING;
@@ -572,11 +647,35 @@
 	return 0;
 }
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+	
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "kaweth", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
+}
+
 /****************************************************************
  *     kaweth_ioctl
  ****************************************************************/
 static int kaweth_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
 {
+	switch (cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(net, (void *) rq->ifr_data);
+	}
 	return -EOPNOTSUPP;
 }
 
@@ -586,11 +685,13 @@
 static void kaweth_usb_transmit_complete(struct urb *urb)
 {
 	struct kaweth_device *kaweth = urb->context;
+	struct sk_buff *skb = kaweth->tx_skb;
 
-	if (urb->status)
+	if (urb->status != 0)
 		kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status);
 
 	netif_wake_queue(kaweth->net);
+	dev_kfree_skb(skb);
 }
 
 /****************************************************************
@@ -599,45 +700,66 @@
 static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
 {
 	struct kaweth_device *kaweth = net->priv;
-	int count = skb->len;
-	
+	char *private_header;
+
 	int res;
 
 	spin_lock(&kaweth->device_lock);
 
+	if (kaweth->removed) {
+	/* our device is undergoing disconnection - we bail out */
+		spin_unlock(&kaweth->device_lock);
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
 	kaweth_async_set_rx_mode(kaweth);
 	netif_stop_queue(net);
 
-	*((__u16 *)kaweth->tx_buf) = cpu_to_le16(skb->len);
-
-	memcpy(kaweth->tx_buf + 2, skb->data, skb->len);
+	/* We now decide whether we can put our special header into the sk_buff */
+	if (skb_cloned(skb) || skb_headroom(skb) < 2) {
+		/* no such luck - we make our own */
+		struct sk_buff *copied_skb;
+		copied_skb = skb_copy_expand(skb, 2, 0, GFP_ATOMIC);
+		dev_kfree_skb_any(skb);
+		skb = copied_skb;
+		if (!copied_skb) {
+			kaweth->stats.tx_errors++;
+			netif_start_queue(net);
+			spin_unlock(&kaweth->device_lock);
+			return 0;
+		}
+	}
 
-	memset(kaweth->tx_urb, 0, sizeof(*kaweth->tx_urb));
+	private_header = __skb_push(skb, 2);
+	*private_header = cpu_to_le16(skb->len);
+	kaweth->tx_skb = skb;
 
 	FILL_BULK_URB(kaweth->tx_urb,
 		      kaweth->dev,
 		      usb_sndbulkpipe(kaweth->dev, 2),
-		      kaweth->tx_buf,
-		      count + 2,
+		      private_header,
+		      skb->len,
 		      kaweth_usb_transmit_complete,
 		      kaweth);
+	kaweth->end = 0;
+	kaweth->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
 
 	if((res = usb_submit_urb(kaweth->tx_urb)))
 	{
 		kaweth_warn("kaweth failed tx_urb %d", res);
 		kaweth->stats.tx_errors++;
-		
+
 		netif_start_queue(net);
-	} 
-	else 
+		dev_kfree_skb(skb);
+	}
+	else
 	{
 		kaweth->stats.tx_packets++;
 		kaweth->stats.tx_bytes += skb->len;
 		net->trans_start = jiffies;
 	}
 
-	dev_kfree_skb(skb);
-
 	spin_unlock(&kaweth->device_lock);
 
 	return 0;
@@ -649,7 +771,7 @@
 static void kaweth_set_rx_mode(struct net_device *net)
 {
 	struct kaweth_device *kaweth = net->priv;
-	
+
 	__u16 packet_filter_bitmap = KAWETH_PACKET_FILTER_DIRECTED |
                                      KAWETH_PACKET_FILTER_BROADCAST |
 		                     KAWETH_PACKET_FILTER_MULTICAST;
@@ -660,7 +782,7 @@
 
 	if (net->flags & IFF_PROMISC) {
 		packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS;
-	} 
+	}
 	else if ((net->mc_count) || (net->flags & IFF_ALLMULTI)) {
 		packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST;
 	}
@@ -675,7 +797,7 @@
 static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth)
 {
 	__u16 packet_filter_bitmap = kaweth->packet_filter_bitmap;
-	kaweth->packet_filter_bitmap = 0;	
+	kaweth->packet_filter_bitmap = 0;
 	if(packet_filter_bitmap == 0) return;
 
 	{
@@ -686,7 +808,7 @@
 				USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
 				packet_filter_bitmap,
 				0,
-				(void *)&kaweth->firmware_buf,
+				(void *)&kaweth->scratch,
 				0,
 				KAWETH_CONTROL_TIMEOUT);
 
@@ -718,7 +840,6 @@
 	kaweth->stats.tx_errors++;
 	net->trans_start = jiffies;
 
-	kaweth->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
 	usb_unlink_urb(kaweth->tx_urb);
 }
 
@@ -736,14 +857,14 @@
 	int result = 0;
 
 	kaweth_dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x",
-		 dev->devnum, 
-		 (int)dev->descriptor.idVendor, 
+		 dev->devnum,
+		 (int)dev->descriptor.idVendor,
 		 (int)dev->descriptor.idProduct,
 		 (int)dev->descriptor.bcdDevice);
 
 	kaweth_dbg("Device at %p", dev);
 
-	kaweth_dbg("Descriptor length: %x type: %x", 
+	kaweth_dbg("Descriptor length: %x type: %x",
 		 (int)dev->descriptor.bLength,
 		 (int)dev->descriptor.bDescriptorType);
 
@@ -755,10 +876,9 @@
 	memset(kaweth, 0, sizeof(struct kaweth_device));
 
 	kaweth->dev = dev;
-	kaweth->status = 0;
-	kaweth->net = NULL;
-	kaweth->device_lock = SPIN_LOCK_UNLOCKED;
-		
+	spin_lock_init(&kaweth->device_lock);
+	init_waitqueue_head(&kaweth->term_wait);
+
 	kaweth_dbg("Resetting.");
 
 	kaweth_reset(kaweth);
@@ -773,22 +893,25 @@
 	} else {
 		/* Download the firmware */
 		kaweth_info("Downloading firmware...");
-		if ((result = kaweth_download_firmware(kaweth, 
-						      kaweth_new_code, 
-						      len_kaweth_new_code, 
-						      100, 
+		kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL);
+		if ((result = kaweth_download_firmware(kaweth,
+						      kaweth_new_code,
+						      len_kaweth_new_code,
+						      100,
 						      2)) < 0) {
 			kaweth_err("Error downloading firmware (%d)", result);
+			free_page((unsigned long)kaweth->firmware_buf);
 			kfree(kaweth);
 			return NULL;
 		}
 
-		if ((result = kaweth_download_firmware(kaweth, 
-						      kaweth_new_code_fix, 
-						      len_kaweth_new_code_fix, 
-						      100, 
+		if ((result = kaweth_download_firmware(kaweth,
+						      kaweth_new_code_fix,
+						      len_kaweth_new_code_fix,
+						      100,
 						      3)) < 0) {
 			kaweth_err("Error downloading firmware fix (%d)", result);
+			free_page((unsigned long)kaweth->firmware_buf);
 			kfree(kaweth);
 			return NULL;
 		}
@@ -799,6 +922,7 @@
 						      126,
 						      2)) < 0) {
 			kaweth_err("Error downloading trigger code (%d)", result);
+			free_page((unsigned long)kaweth->firmware_buf);
 			kfree(kaweth);
 			return NULL;
 		}
@@ -809,6 +933,7 @@
 						      126,
 						      3)) < 0) {
 			kaweth_err("Error downloading trigger code fix (%d)", result);
+			free_page((unsigned long)kaweth->firmware_buf);
 			kfree(kaweth);
 			return NULL;
 		}
@@ -816,12 +941,14 @@
 
 		if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) {
 			kaweth_err("Error triggering firmware (%d)", result);
+			free_page((unsigned long)kaweth->firmware_buf);
 			kfree(kaweth);
 			return NULL;
 		}
 
 		/* Device will now disappear for a moment...  */
 		kaweth_info("Firmware loaded.  I'll be back...");
+		free_page((unsigned long)kaweth->firmware_buf);
 		kfree(kaweth);
 		return NULL;
 	}
@@ -846,7 +973,7 @@
 		 (int)kaweth->configuration.hw_addr[5]);
 
 	if(!memcmp(&kaweth->configuration.hw_addr,
-                   &bcast_addr, 
+                   &bcast_addr,
 		   sizeof(bcast_addr))) {
 		kaweth_err("Firmware not functioning properly, no net device created");
 		kfree(kaweth);
@@ -857,13 +984,13 @@
 		kaweth_dbg("Error setting URB size");
 		return kaweth;
 	}
-	
+
 	if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) {
 		kaweth_err("Error setting SOFS wait");
 		return kaweth;
 	}
 
-	result = kaweth_set_receive_filter(kaweth, 
+	result = kaweth_set_receive_filter(kaweth,
                                            KAWETH_PACKET_FILTER_DIRECTED |
                                            KAWETH_PACKET_FILTER_BROADCAST |
                                            KAWETH_PACKET_FILTER_MULTICAST);
@@ -872,11 +999,18 @@
 		kaweth_err("Error setting receive filter");
 		return kaweth;
 	}
-	
+
 	kaweth_dbg("Initializing net device.");
 
 	kaweth->tx_urb = usb_alloc_urb(0);
+	if (!kaweth->tx_urb)
+		goto err_no_urb;
 	kaweth->rx_urb = usb_alloc_urb(0);
+	if (!kaweth->rx_urb)
+		goto err_only_tx;
+	kaweth->irq_urb = usb_alloc_urb(0);
+	if (!kaweth->irq_urb)
+		goto err_tx_and_rx;
 
 	kaweth->net = init_etherdev(0, 0);
 	if (!kaweth->net) {
@@ -885,17 +1019,17 @@
 	}
 
 	memcpy(kaweth->net->broadcast, &bcast_addr, sizeof(bcast_addr));
-	memcpy(kaweth->net->dev_addr, 
+	memcpy(kaweth->net->dev_addr,
                &kaweth->configuration.hw_addr,
                sizeof(kaweth->configuration.hw_addr));
-	 
+
 	kaweth->net->priv = kaweth;
 	kaweth->net->open = kaweth_open;
 	kaweth->net->stop = kaweth_close;
 
 	kaweth->net->watchdog_timeo = KAWETH_TX_TIMEOUT;
 	kaweth->net->tx_timeout = kaweth_tx_timeout;
-	
+
 	kaweth->net->do_ioctl = kaweth_ioctl;
 	kaweth->net->hard_start_xmit = kaweth_start_xmit;
 	kaweth->net->set_multicast_list = kaweth_set_rx_mode;
@@ -905,10 +1039,18 @@
 	memset(&kaweth->stats, 0, sizeof(kaweth->stats));
 
 	kaweth_info("kaweth interface created at %s", kaweth->net->name);
-								
+
 	kaweth_dbg("Kaweth probe returning.");
 
 	return kaweth;
+
+err_tx_and_rx:
+	usb_free_urb(kaweth->rx_urb);
+err_only_tx:
+	usb_free_urb(kaweth->tx_urb);
+err_no_urb:
+	kfree(kaweth);
+	return NULL;
 }
 
 /****************************************************************
@@ -925,8 +1067,18 @@
 		return;
 	}
 
+	kaweth->removed = 1;
+	usb_unlink_urb(kaweth->irq_urb);
 	usb_unlink_urb(kaweth->rx_urb);
-	usb_unlink_urb(kaweth->tx_urb);
+
+	/* we need to wait for the urb to be cancelled, if it is active */
+	spin_lock_irq(&kaweth->device_lock);
+	if (usb_unlink_urb(kaweth->tx_urb) == -EINPROGRESS) {
+		spin_unlock_irq(&kaweth->device_lock);
+		wait_event(kaweth->term_wait, kaweth->end);
+	} else {
+		spin_unlock_irq(&kaweth->device_lock);
+	}
 
 	if(kaweth->net) {
 		if(kaweth->net->flags & IFF_UP) {
@@ -945,12 +1097,19 @@
 }
 
 
+// FIXME this completion stuff is a modified clone of
+// an OLD version of some stuff in usb.c ...
+struct kw_api_data {
+	wait_queue_head_t wqh;
+	int done;
+};
+
 /*-------------------------------------------------------------------*
  * completion handler for compatibility wrappers (sync control/bulk) *
  *-------------------------------------------------------------------*/
-static void usb_api_blocking_completion(urb_t *urb)
+static void usb_api_blocking_completion(struct urb *urb)
 {
-        struct usb_api_data *awd = (struct usb_api_data *)urb->context;
+        struct kw_api_data *awd = (struct kw_api_data *)urb->context;
 
 	awd->done=1;
 	wake_up(&awd->wqh);
@@ -961,15 +1120,15 @@
  *-------------------------------------------------------------------*/
 
 // Starts urb and waits for completion or timeout
-static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
+static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
 {
         DECLARE_WAITQUEUE(wait, current);
-	struct usb_api_data awd;
+	struct kw_api_data awd;
         int status;
 
         init_waitqueue_head(&awd.wqh);
         awd.done = 0;
-        
+
         set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&awd.wqh, &wait);
         urb->context = &awd;
@@ -1009,9 +1168,10 @@
 /*-------------------------------------------------------------------*/
 // returns status (negative) or length (positive)
 int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
-                            devrequest *cmd,  void *data, int len, int timeout)
+                            struct usb_ctrlrequest *cmd, void *data, int len,
+			    int timeout)
 {
-        urb_t *urb;
+        struct urb *urb;
         int retv;
         int length;
 
@@ -1059,3 +1219,4 @@
 
 
 
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/mdc800.c linux-2.4.20/drivers/usb/mdc800.c
--- linux-2.4.19/drivers/usb/mdc800.c	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.20/drivers/usb/mdc800.c	2002-10-29 11:18:31.000000000 +0000
@@ -140,7 +140,7 @@
 
 	unsigned int		endpoint [4];
 
-	purb_t			irq_urb;
+	struct urb *		irq_urb;
 	wait_queue_head_t	irq_wait;
 	int                     irq_woken;
 	char*			irq_urb_buffer;
@@ -149,13 +149,13 @@
 	int 			camera_request_ready; // Status to synchronize with irq
 	char 			camera_response [8];  // last Bytes send after busy
 
-	purb_t   		write_urb;
+	struct urb *   		write_urb;
 	char*			write_urb_buffer;
 	wait_queue_head_t	write_wait;
 	int                     written;
 
 
-	purb_t	   		download_urb;
+	struct urb *		download_urb;
 	char*			download_urb_buffer;
 	wait_queue_head_t	download_wait;
 	int                     downloaded;
@@ -652,7 +652,7 @@
  */
 static ssize_t mdc800_device_read (struct file *file, char *buf, size_t len, loff_t *pos)
 {
-	int   left=len, sts=len; /* single transfer size */
+	size_t left=len, sts=len; /* single transfer size */
 	char* ptr=buf;
 	DECLARE_WAITQUEUE(wait, current);
 
@@ -746,7 +746,7 @@
  */
 static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t len, loff_t *pos)
 {
-	int i=0;
+	size_t i=0;
 	DECLARE_WAITQUEUE(wait, current);
 
 	down (&mdc800->io_lock);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/microtek.c linux-2.4.20/drivers/usb/microtek.c
--- linux-2.4.19/drivers/usb/microtek.c	2001-10-05 19:04:51.000000000 +0000
+++ linux-2.4.20/drivers/usb/microtek.c	2002-10-29 11:18:48.000000000 +0000
@@ -117,6 +117,8 @@
  *	20010320 Version 0.4.3
  *	20010408 Identify version on module load.
  *	20011003 Fix multiple requests
+ *	20020618 Version 0.4.4
+ *	20020618 Confirm to utterly stupid rules about io_request_lock
  */
 
 #include <linux/module.h>
@@ -144,7 +146,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.4.3"
+#define DRIVER_VERSION "v0.4.4"
 #define DRIVER_AUTHOR "John Fremlin <vii@penguinpowered.com>, Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>"
 #define DRIVER_DESC "Microtek Scanmaker X6 USB scanner driver"
 
@@ -326,10 +328,12 @@
 }  */
 
 static inline void mts_urb_abort(struct mts_desc* desc) {
+	spin_unlock_irq(&io_request_lock);
 	MTS_DEBUG_GOT_HERE();
 	mts_debug_dump(desc);
 
 	usb_unlink_urb( &desc->urb );
+	spin_lock_irq(&io_request_lock);
 }
 
 static struct mts_desc * mts_list; /* list of active scanners */
@@ -414,12 +418,14 @@
 
 static int mts_scsi_host_reset (Scsi_Cmnd *srb)
 {
-	struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]);
 
+	struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]);
+	spin_unlock_irq(&io_request_lock);
 	MTS_DEBUG_GOT_HERE();
 	mts_debug_dump(desc);
 
 	usb_reset_device(desc->usb_dev); /*FIXME: untested on new reset code */
+	spin_lock_irq(&io_request_lock);
 	return 0;  /* RANT why here 0 and not SUCCESS */
 }
 
@@ -435,6 +441,7 @@
 	/* What a hideous hack! */
 
 	char local_name[48];
+	spin_unlock_irq(&io_request_lock);
 
 	MTS_DEBUG_GOT_HERE();
 
@@ -445,6 +452,7 @@
 
 	if (!sht->proc_name) {
 		MTS_ERROR( "unable to allocate memory for proc interface!!\n" );
+		spin_lock_irq(&io_request_lock);
 		return 0;
 	}
 
@@ -457,11 +465,12 @@
 	if (desc->host == NULL) {
 		MTS_ERROR("Cannot register due to low memory");
 		kfree(sht->proc_name);
+		spin_lock_irq(&io_request_lock);
 		return 0;
 	}
 	desc->host->hostdata[0] = (unsigned long)desc;
 /* FIXME: what if sizeof(void*) != sizeof(unsigned long)? */
-
+	spin_lock_irq(&io_request_lock);
 	return 1;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/ov511.c linux-2.4.20/drivers/usb/ov511.c
--- linux-2.4.19/drivers/usb/ov511.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/ov511.c	2002-10-29 11:18:36.000000000 +0000
@@ -9,7 +9,8 @@
  * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
  * Changes by Claudio Matsuoka <claudio@conectiva.com>
  * Original SAA7111A code by Dave Perks <dperks@ibm.net>
- * Kernel I2C interface adapted from nt1003 driver
+ * URB error messages from pwc driver by Nemosoft
+ * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox
  *
  * Based on the Linux CPiA driver written by Peter Pregler,
  * Scott J. Bertin and Johannes Erdfelt.
@@ -57,19 +58,22 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.50 for Linux 2.4"
-#define EMAIL "mmcclell@bigfoot.com"
+#define DRIVER_VERSION "v1.61 for Linux 2.4"
+#define EMAIL "mark@alpha.dyndns.org"
 #define DRIVER_AUTHOR "Mark McClelland <mmcclell@bigfoot.com> & Bret Wallach \
 	& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
 	<cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"
-#define DRIVER_DESC "OV511 USB Camera Driver"
+#define DRIVER_DESC "ov511 USB Camera Driver"
 
 #define OV511_I2C_RETRIES 3
 #define ENABLE_Y_QUANTABLE 1
 #define ENABLE_UV_QUANTABLE 1
 
+#define OV511_MAX_UNIT_VIDEO 16
+
 /* Pixel count * 3 bytes for RGB */
 #define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3)
+
 #define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval))
 
 /* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */
@@ -77,128 +81,47 @@
 
 #define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM)
 
-/* PARAMETER VARIABLES: */
-/* (See ov511.txt for detailed descriptions of these.) */
-
-/* Sensor automatically changes brightness */
-static int autobright = 1;
-
-/* Sensor automatically changes gain */
-static int autogain = 1;
-
-/* Sensor automatically changes exposure */
-static int autoexp = 1;
-
-/* 0=no debug messages
- * 1=init/detection/unload and other significant messages,
- * 2=some warning messages
- * 3=config/control function calls
- * 4=most function calls and data parsing messages
- * 5=highly repetitive mesgs
- * NOTE: This should be changed to 0, 1, or 2 for production kernels
- */
-static int debug; /* = 0 */
-
-/* Fix vertical misalignment of red and blue at 640x480 */
-static int fix_rgb_offset; /* = 0 */
-
-/* Snapshot mode enabled flag */
-static int snapshot; /* = 0 */
-
-/* Force image to be read in RGB instead of BGR. This option allow
- * programs that expect RGB data (e.g. gqcam) to work with this driver. */
-static int force_rgb; /* = 0 */
-
-/* Number of seconds before inactive buffers are deallocated */
-static int buf_timeout = 5;
-
-/* Number of cameras to stream from simultaneously */
-static int cams = 1;
-
-/* Enable compression. Needs a fast (>300 MHz) CPU. */
-static int compress; /* = 0 */
-
-/* Display test pattern - doesn't work yet either */
-static int testpat; /* = 0 */
-
-/* Setting this to 1 will make the sensor output GBR422 instead of YUV420. Only
- * affects RGB24 mode. */
-static int sensor_gbr; /* = 0 */
-
-/* Dump raw pixel data. */
-static int dumppix; /* = 0 */
-
-/* LED policy. Only works on some OV511+ cameras. 0=off, 1=on (default), 2=auto
- * (on when open) */
-static int led = 1;
-
-/* Set this to 1 to dump the bridge register contents after initialization */
-static int dump_bridge; /* = 0 */
-
-/* Set this to 1 to dump the sensor register contents after initialization */
-static int dump_sensor; /* = 0 */
-
-/* Temporary option for debugging "works, but no image" problem. Prints the
- * first 12 bytes of data (potentially a packet header) in each isochronous
- * data frame. */
-static int printph; /* = 0 */
-
-/* Compression parameters - I'm not exactly sure what these do yet */
-static int phy = 0x1f;
-static int phuv = 0x05;
-static int pvy = 0x06;
-static int pvuv = 0x06;
-static int qhy = 0x14;
-static int qhuv = 0x03;
-static int qvy = 0x04;
-static int qvuv = 0x04;
-
-/* Light frequency. Set to 50 or 60 (Hz), or zero for default settings */
-static int lightfreq; /* = 0 */
-
-/* Set this to 1 to enable banding filter by default. Compensates for
- * alternating horizontal light/dark bands caused by (usually fluorescent)
- * lights */
-static int bandingfilter; /* = 0 */
-
-/* Pixel clock divisor */
-static int clockdiv = -1;
-
-/* Isoc packet size */
-static int packetsize = -1;
-
-/* Frame drop register (16h) */
-static int framedrop = -1;
-
-/* Allows picture settings (brightness, hue, etc...) to take effect immediately,
- * even in the middle of a frame. This reduces the time to change settings, but
- * can ruin frames during the change. Only affects OmniVision sensors. */
-static int fastset; /* = 0 */
-
-/* Forces the palette to a specific value. If an application requests a
- * different palette, it will be rejected. */
-static int force_palette; /* = 0 */
-
-/* Set tuner type, if not autodetected */
-static int tuner = -1;
-
-/* Allows proper exposure of objects that are illuminated from behind. Only
- * affects OmniVision sensors. */
-static int backlight; /* = 0 */
-
-/* If you change this, you must also change the MODULE_PARM definition */
-#define OV511_MAX_UNIT_VIDEO 16
+/**********************************************************************
+ * Module Parameters
+ * (See ov511.txt for detailed descriptions of these)
+ **********************************************************************/
 
-/* Allows specified minor numbers to be forced. They will be assigned in the
- * order that devices are detected. Note that you cannot specify 0 as a minor
- * number. If you do not specify any, the next available one will be used. This
- * requires kernel 2.4.5 or later. */
+/* These variables (and all static globals) default to zero */
+static int autobright		= 1;
+static int autogain		= 1;
+static int autoexp		= 1;
+static int debug;
+static int snapshot;
+static int fix_rgb_offset;
+static int force_rgb;
+static int cams			= 1;
+static int compress;
+static int testpat;
+static int sensor_gbr;
+static int dumppix;
+static int led 			= 1;
+static int dump_bridge;
+static int dump_sensor;
+static int printph;
+static int phy			= 0x1f;
+static int phuv			= 0x05;
+static int pvy			= 0x06;
+static int pvuv			= 0x06;
+static int qhy			= 0x14;
+static int qhuv			= 0x03;
+static int qvy			= 0x04;
+static int qvuv			= 0x04;
+static int lightfreq;
+static int bandingfilter;
+static int clockdiv		= -1;
+static int packetsize		= -1;
+static int framedrop		= -1;
+static int fastset;
+static int force_palette;
+static int backlight;
 static int unit_video[OV511_MAX_UNIT_VIDEO];
-
-/* Remove zero-padding from uncompressed incoming data. This will compensate for
- * the blocks of corruption that appear when the camera cannot keep up with the
- * speed of the USB bus (eg. at low frame resolutions) */
-static int remove_zeros; /* = 0 */
+static int remove_zeros;
+static int mirror;
 
 MODULE_PARM(autobright, "i");
 MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness");
@@ -209,15 +132,13 @@
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug,
   "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max");
+MODULE_PARM(snapshot, "i");
+MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
 MODULE_PARM(fix_rgb_offset, "i");
 MODULE_PARM_DESC(fix_rgb_offset,
   "Fix vertical misalignment of red and blue at 640x480");
-MODULE_PARM(snapshot, "i");
-MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
 MODULE_PARM(force_rgb, "i");
 MODULE_PARM_DESC(force_rgb, "Read RGB instead of BGR");
-MODULE_PARM(buf_timeout, "i");
-MODULE_PARM_DESC(buf_timeout, "Number of seconds before buffer deallocation");
 MODULE_PARM(cams, "i");
 MODULE_PARM_DESC(cams, "Number of simultaneous cameras");
 MODULE_PARM(compress, "i");
@@ -225,11 +146,6 @@
 MODULE_PARM(testpat, "i");
 MODULE_PARM_DESC(testpat,
   "Replace image with vertical bar testpattern (only partially working)");
-
-// Temporarily removed (needs to be rewritten for new format conversion code)
-// MODULE_PARM(sensor_gbr, "i");
-// MODULE_PARM_DESC(sensor_gbr, "Make sensor output GBR422 rather than YUV420");
-
 MODULE_PARM(dumppix, "i");
 MODULE_PARM_DESC(dumppix, "Dump raw pixel data");
 MODULE_PARM(led, "i");
@@ -273,21 +189,25 @@
 MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately");
 MODULE_PARM(force_palette, "i");
 MODULE_PARM_DESC(force_palette, "Force the palette to a specific value");
-MODULE_PARM(tuner, "i");
-MODULE_PARM_DESC(tuner, "Set tuner type, if not autodetected");
 MODULE_PARM(backlight, "i");
 MODULE_PARM_DESC(backlight, "For objects that are lit from behind");
-MODULE_PARM(unit_video, "0-16i");
+MODULE_PARM(unit_video, "1-" __MODULE_STRING(OV511_MAX_UNIT_VIDEO) "i");
 MODULE_PARM_DESC(unit_video,
   "Force use of specific minor number(s). 0 is not allowed.");
 MODULE_PARM(remove_zeros, "i");
 MODULE_PARM_DESC(remove_zeros,
   "Remove zero-padding from uncompressed incoming data");
+MODULE_PARM(mirror, "i");
+MODULE_PARM_DESC(mirror, "Reverse image horizontally");
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
+/**********************************************************************
+ * Miscellaneous Globals
+ **********************************************************************/
+
 static struct usb_driver ov511_driver;
 
 static struct ov51x_decomp_ops *ov511_decomp_ops;
@@ -302,20 +222,28 @@
 /* MMX support is present in kernel and CPU. Checked upon decomp module load. */
 static int ov51x_mmx_available;
 
-/* Function prototypes */
-static void ov51x_clear_snapshot(struct usb_ov511 *);
-static int ov51x_check_snapshot(struct usb_ov511 *);
-static inline int sensor_get_picture(struct usb_ov511 *, 
-				     struct video_picture *);
-static int sensor_get_exposure(struct usb_ov511 *, unsigned char *);
-static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int,
-			       unsigned long);
+static __devinitdata struct usb_device_id device_table [] = {
+	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
+	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
+	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518) },
+	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) },
+	{ USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
+	{ }  /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, device_table);
+
+static unsigned char yQuanTable511[] = OV511_YQUANTABLE;
+static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE;
+static unsigned char yQuanTable518[] = OV518_YQUANTABLE;
+static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE;
 
 /**********************************************************************
- * List of known OV511-based cameras
+ * Symbolic Names
  **********************************************************************/
 
-static struct cam_list clist[] = {
+/* Known OV511-based cameras */
+static struct symbolic_list camlist[] = {
 	{   0, "Generic Camera (no ID)" },
 	{   1, "Mustek WCam 3X" },
 	{   3, "D-Link DSB-C300" },
@@ -323,11 +251,13 @@
 	{   5, "Puretek PT-6007" },
 	{   6, "Lifeview USB Life TV (NTSC)" },
 	{  21, "Creative Labs WebCam 3" },
+	{  22, "Lifeview USB Life TV (PAL D/K+B/G)" },
 	{  36, "Koala-Cam" },
-	{  38, "Lifeview USB Life TV" },
+	{  38, "Lifeview USB Life TV (PAL)" },
 	{  41, "Samsung Anycam MPC-M10" },
 	{  43, "Mtekvision Zeca MV402" },
 	{  46, "Suma eON" },
+	{  70, "Lifeview USB Life TV (PAL/SECAM)" },
 	{ 100, "Lifeview RoboCam" },
 	{ 102, "AverMedia InterCam Elite" },
 	{ 112, "MediaForte MV300" },	/* or OV7110 evaluation kit */
@@ -335,97 +265,90 @@
 	{  -1, NULL }
 };
 
-static __devinitdata struct usb_device_id device_table [] = {
-	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
-	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
-	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518) },
-	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) },
-	{ USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
-	{ }  /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, device_table);
-
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
-static struct palette_list plist[] = {
+/* Video4Linux1 Palettes */
+static struct symbolic_list v4l1_plist[] = {
 	{ VIDEO_PALETTE_GREY,	"GREY" },
-	{ VIDEO_PALETTE_HI240,  "HI240" },
-	{ VIDEO_PALETTE_RGB565, "RGB565" },
+	{ VIDEO_PALETTE_HI240,	"HI240" },
+	{ VIDEO_PALETTE_RGB565,	"RGB565" },
 	{ VIDEO_PALETTE_RGB24,	"RGB24" },
 	{ VIDEO_PALETTE_RGB32,	"RGB32" },
-	{ VIDEO_PALETTE_RGB555, "RGB555" },
-	{ VIDEO_PALETTE_YUV422, "YUV422" },
-	{ VIDEO_PALETTE_YUYV,   "YUYV" },
-	{ VIDEO_PALETTE_UYVY,   "UYVY" },
-	{ VIDEO_PALETTE_YUV420, "YUV420" },
-	{ VIDEO_PALETTE_YUV411, "YUV411" },
-	{ VIDEO_PALETTE_RAW,    "RAW" },
+	{ VIDEO_PALETTE_RGB555,	"RGB555" },
+	{ VIDEO_PALETTE_YUV422,	"YUV422" },
+	{ VIDEO_PALETTE_YUYV,	"YUYV" },
+	{ VIDEO_PALETTE_UYVY,	"UYVY" },
+	{ VIDEO_PALETTE_YUV420,	"YUV420" },
+	{ VIDEO_PALETTE_YUV411,	"YUV411" },
+	{ VIDEO_PALETTE_RAW,	"RAW" },
 	{ VIDEO_PALETTE_YUV422P,"YUV422P" },
 	{ VIDEO_PALETTE_YUV411P,"YUV411P" },
 	{ VIDEO_PALETTE_YUV420P,"YUV420P" },
 	{ VIDEO_PALETTE_YUV410P,"YUV410P" },
 	{ -1, NULL }
 };
-#endif
 
-static unsigned char yQuanTable511[] = OV511_YQUANTABLE;
-static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE;
-static unsigned char yQuanTable518[] = OV518_YQUANTABLE;
-static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE;
+static struct symbolic_list brglist[] = {
+	{ BRG_OV511,		"OV511" },
+	{ BRG_OV511PLUS,	"OV511+" },
+	{ BRG_OV518,		"OV518" },
+	{ BRG_OV518PLUS,	"OV518+" },
+	{ -1, NULL }
+};
+
+static struct symbolic_list senlist[] = {
+	{ SEN_OV76BE,	"OV76BE" },
+	{ SEN_OV7610,	"OV7610" },
+	{ SEN_OV7620,	"OV7620" },
+	{ SEN_OV7620AE,	"OV7620AE" },
+	{ SEN_OV6620,	"OV6620" },
+	{ SEN_OV6630,	"OV6630" },
+	{ SEN_OV6630AE,	"OV6630AE" },
+	{ SEN_OV6630AF,	"OV6630AF" },
+	{ SEN_OV8600,	"OV8600" },
+	{ SEN_KS0127,	"KS0127" },
+	{ SEN_KS0127B,	"KS0127B" },
+	{ SEN_SAA7111A,	"SAA7111A" },
+	{ -1, NULL }
+};
+
+/* URB error codes: */
+static struct symbolic_list urb_errlist[] = {
+	{ -ENOSR,	"Buffer error (overrun)" },
+	{ -EPIPE,	"Stalled (device not responding)" },
+	{ -EOVERFLOW,	"Babble (bad cable?)" },
+	{ -EPROTO,	"Bit-stuff error (bad cable?)" },
+	{ -EILSEQ,	"CRC/Timeout" },
+	{ -ETIMEDOUT,	"NAK (device does not respond)" },
+	{ -1, NULL }
+};
 
 /**********************************************************************
- *
- * Memory management
- *
- * This is a shameless copy from the USB-cpia driver (linux kernel
- * version 2.3.29 or so, I have no idea what this code actually does ;).
- * Actually it seems to be a copy of a shameless copy of the bttv-driver.
- * Or that is a copy of a shameless copy of ... (To the powers: is there
- * no generic kernel-function to do this sort of stuff?)
- *
- * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
- * there will be one, but apparentely not yet -jerdfelt
- *
- * So I copied it again for the OV511 driver -claudio
+ * Prototypes
  **********************************************************************/
 
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline unsigned long 
-uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
-	unsigned long ret = 0UL;
-	pmd_t *pmd;
-	pte_t *ptep, pte;
-
-	if (!pgd_none(*pgd)) {
-		pmd = pmd_offset(pgd, adr);
-		if (!pmd_none(*pmd)) {
-			ptep = pte_offset(pmd, adr);
-			pte = *ptep;
-			if (pte_present(pte)) {
-				ret = (unsigned long) 
-				      page_address(pte_page(pte));
-				ret |= (adr & (PAGE_SIZE - 1));
-			}
-		}
-	}
+static void ov51x_clear_snapshot(struct usb_ov511 *);
+static inline int sensor_get_picture(struct usb_ov511 *,
+				     struct video_picture *);
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+static int sensor_get_exposure(struct usb_ov511 *, unsigned char *);
+static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int,
+			       unsigned long);
+static int ov51x_check_snapshot(struct usb_ov511 *);
+#endif
 
-	return ret;
-}
+/**********************************************************************
+ * Memory management
+ **********************************************************************/
 
 /* Here we want the physical address of the memory.
- * This is used when initializing the contents of the
- * area and marking the pages as reserved.
+ * This is used when initializing the contents of the area.
  */
-static inline unsigned long 
+static inline unsigned long
 kvirt_to_pa(unsigned long adr)
 {
-	unsigned long va, kva, ret;
+	unsigned long kva, ret;
 
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
 	ret = __pa(kva);
 	return ret;
 }
@@ -434,12 +357,9 @@
 rvmalloc(unsigned long size)
 {
 	void *mem;
-	unsigned long adr, page;
-
-	/* Round it off to PAGE_SIZE */
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
+	unsigned long adr;
 
+	size = PAGE_ALIGN(size);
 	mem = vmalloc_32(size);
 	if (!mem)
 		return NULL;
@@ -447,38 +367,27 @@
 	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
 	adr = (unsigned long) mem;
 	while (size > 0) {
-		page = kvirt_to_pa(adr);
-		mem_map_reserve(virt_to_page(__va(page)));
+		mem_map_reserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 
 	return mem;
 }
 
-static void 
+static void
 rvfree(void *mem, unsigned long size)
 {
-	unsigned long adr, page;
+	unsigned long adr;
 
 	if (!mem)
 		return;
 
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
-
-	adr=(unsigned long) mem;
-	while (size > 0) {
-		page = kvirt_to_pa(adr);
-		mem_map_unreserve(virt_to_page(__va(page)));
+	adr = (unsigned long) mem;
+	while ((long) size > 0) {
+		mem_map_unreserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 	vfree(mem);
 }
@@ -500,12 +409,12 @@
 #define YES_NO(x) ((x) ? "yes" : "no")
 
 /* /proc/video/ov511/<minor#>/info */
-static int 
+static int
 ov511_read_proc_info(char *page, char **start, off_t off, int count, int *eof,
 		     void *data)
 {
 	char *out = page;
-	int i, j, len;
+	int i, len;
 	struct usb_ov511 *ov = data;
 	struct video_picture p;
 	unsigned char exp;
@@ -521,8 +430,7 @@
 
 	out += sprintf(out, "driver_version  : %s\n", DRIVER_VERSION);
 	out += sprintf(out, "custom_id       : %d\n", ov->customid);
-	out += sprintf(out, "model           : %s\n", ov->desc ?
-		       clist[ov->desc].description : "unknown");
+	out += sprintf(out, "model           : %s\n", ov->desc);
 	out += sprintf(out, "streaming       : %s\n", YES_NO(ov->streaming));
 	out += sprintf(out, "grabbing        : %s\n", YES_NO(ov->grabbing));
 	out += sprintf(out, "compress        : %s\n", YES_NO(ov->compress));
@@ -543,36 +451,16 @@
 			       ov->frame[i].depth);
 		out += sprintf(out, "  size          : %d %d\n",
 			       ov->frame[i].width, ov->frame[i].height);
-		out += sprintf(out, "  format        : ");
-		for (j = 0; plist[j].num >= 0; j++) {
-			if (plist[j].num == ov->frame[i].format) {
-				out += sprintf(out, "%s\n", plist[j].name);
-				break;
-			}
-		}
-		if (plist[j].num < 0)
-			out += sprintf(out, "unknown\n");
+		out += sprintf(out, "  format        : %s\n",
+			       symbolic(v4l1_plist, ov->frame[i].format));
 		out += sprintf(out, "  data_buffer   : 0x%p\n",
 			       ov->frame[i].data);
 	}
 	out += sprintf(out, "snap_enabled    : %s\n", YES_NO(ov->snap_enabled));
 	out += sprintf(out, "bridge          : %s\n",
-		       ov->bridge == BRG_OV511 ? "OV511" :
-			ov->bridge == BRG_OV511PLUS ? "OV511+" :
-			ov->bridge == BRG_OV518 ? "OV518" :
-			ov->bridge == BRG_OV518PLUS ? "OV518+" :
-			"unknown");
+		       symbolic(brglist, ov->bridge));
 	out += sprintf(out, "sensor          : %s\n",
-		       ov->sensor == SEN_OV6620 ? "OV6620" :
-			ov->sensor == SEN_OV6630 ? "OV6630" :
-			ov->sensor == SEN_OV7610 ? "OV7610" :
-			ov->sensor == SEN_OV7620 ? "OV7620" :
-			ov->sensor == SEN_OV7620AE ? "OV7620AE" :
-			ov->sensor == SEN_OV8600 ? "OV8600" :
-			ov->sensor == SEN_KS0127 ? "KS0127" :
-			ov->sensor == SEN_KS0127B ? "KS0127B" :
-			ov->sensor == SEN_SAA7111A ? "SAA7111A" :
-			"unknown");
+		       symbolic(senlist, ov->sensor));
 	out += sprintf(out, "packet_size     : %d\n", ov->packet_size);
 	out += sprintf(out, "framebuffer     : 0x%p\n", ov->fbuf);
 
@@ -595,13 +483,13 @@
  * When the camera's button is pressed, the output of this will change from a
  * 0 to a 1 (ASCII). It will retain this value until it is read, after which
  * it will reset to zero.
- * 
+ *
  * SECURITY NOTE: Since reading this file can change the state of the snapshot
  * status, it is important for applications that open it to keep it locked
  * against access by other processes, using flock() or a similar mechanism. No
  * locking is provided by this driver.
  */
-static int 
+static int
 ov511_read_proc_button(char *page, char **start, off_t off, int count, int *eof,
 		       void *data)
 {
@@ -633,97 +521,95 @@
 	return len;
 }
 
-static void 
-create_proc_ov511_cam(struct usb_ov511 *ov511)
+static void
+create_proc_ov511_cam(struct usb_ov511 *ov)
 {
 	char dirname[10];
 
-	if (!ov511_proc_entry || !ov511)
+	if (!ov511_proc_entry || !ov)
 		return;
 
 	/* Create per-device directory */
-	snprintf(dirname, 10, "%d", ov511->vdev.minor);
+	snprintf(dirname, 10, "%d", ov->vdev.minor);
 	PDEBUG(4, "creating /proc/video/ov511/%s/", dirname);
-	ov511->proc_devdir = create_proc_entry(dirname, S_IFDIR,
-		ov511_proc_entry);
-	if (!ov511->proc_devdir)
+	ov->proc_devdir = create_proc_entry(dirname, S_IFDIR, ov511_proc_entry);
+	if (!ov->proc_devdir)
 		return;
-	ov511->proc_devdir->owner = THIS_MODULE;
+	ov->proc_devdir->owner = THIS_MODULE;
 
 	/* Create "info" entry (human readable device information) */
 	PDEBUG(4, "creating /proc/video/ov511/%s/info", dirname);
-	ov511->proc_info = create_proc_read_entry("info",
-		S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir,
-		ov511_read_proc_info, ov511);
-	if (!ov511->proc_info)
+	ov->proc_info = create_proc_read_entry("info", S_IFREG|S_IRUGO|S_IWUSR,
+		ov->proc_devdir, ov511_read_proc_info, ov);
+	if (!ov->proc_info)
 		return;
-	ov511->proc_info->owner = THIS_MODULE;
+	ov->proc_info->owner = THIS_MODULE;
 
 	/* Don't create it if old snapshot mode on (would cause race cond.) */
 	if (!snapshot) {
 		/* Create "button" entry (snapshot button status) */
 		PDEBUG(4, "creating /proc/video/ov511/%s/button", dirname);
-		ov511->proc_button = create_proc_read_entry("button",
-			S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir,
-			ov511_read_proc_button, ov511);
-		if (!ov511->proc_button)
+		ov->proc_button = create_proc_read_entry("button",
+			S_IFREG|S_IRUGO|S_IWUSR, ov->proc_devdir,
+			ov511_read_proc_button, ov);
+		if (!ov->proc_button)
 			return;
 	}
-	ov511->proc_button->owner = THIS_MODULE;
+	ov->proc_button->owner = THIS_MODULE;
 
 	/* Create "control" entry (ioctl() interface) */
 	PDEBUG(4, "creating /proc/video/ov511/%s/control", dirname);
 	lock_kernel();
-	ov511->proc_control = create_proc_entry("control",
-		S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir);
-	if (!ov511->proc_control) {
+	ov->proc_control = create_proc_entry("control",	S_IFREG|S_IRUGO|S_IWUSR,
+		ov->proc_devdir);
+	if (!ov->proc_control) {
 		unlock_kernel();
 		return;
 	}
-	ov511->proc_control->owner = THIS_MODULE;
-	ov511->proc_control->data = ov511;
-	ov511->proc_control->proc_fops = &ov511_control_fops;
+	ov->proc_control->owner = THIS_MODULE;
+	ov->proc_control->data = ov;
+	ov->proc_control->proc_fops = &ov511_control_fops;
 	unlock_kernel();
 }
 
-static void 
-destroy_proc_ov511_cam(struct usb_ov511 *ov511)
+static void
+destroy_proc_ov511_cam(struct usb_ov511 *ov)
 {
 	char dirname[10];
-	
-	if (!ov511 || !ov511->proc_devdir)
+
+	if (!ov || !ov->proc_devdir)
 		return;
 
-	snprintf(dirname, 10, "%d", ov511->vdev.minor);
+	snprintf(dirname, 10, "%d", ov->vdev.minor);
 
 	/* Destroy "control" entry */
-	if (ov511->proc_control) {
+	if (ov->proc_control) {
 		PDEBUG(4, "destroying /proc/video/ov511/%s/control", dirname);
-		remove_proc_entry("control", ov511->proc_devdir);
-		ov511->proc_control = NULL;
+		remove_proc_entry("control", ov->proc_devdir);
+		ov->proc_control = NULL;
 	}
 
 	/* Destroy "button" entry */
-	if (ov511->proc_button) {
+	if (ov->proc_button) {
 		PDEBUG(4, "destroying /proc/video/ov511/%s/button", dirname);
-		remove_proc_entry("button", ov511->proc_devdir);
-		ov511->proc_button = NULL;
+		remove_proc_entry("button", ov->proc_devdir);
+		ov->proc_button = NULL;
 	}
 
 	/* Destroy "info" entry */
-	if (ov511->proc_info) {
+	if (ov->proc_info) {
 		PDEBUG(4, "destroying /proc/video/ov511/%s/info", dirname);
-		remove_proc_entry("info", ov511->proc_devdir);
-		ov511->proc_info = NULL;
+		remove_proc_entry("info", ov->proc_devdir);
+		ov->proc_info = NULL;
 	}
 
 	/* Destroy per-device directory */
 	PDEBUG(4, "destroying /proc/video/ov511/%s/", dirname);
 	remove_proc_entry(dirname, ov511_proc_entry);
-	ov511->proc_devdir = NULL;
+	ov->proc_devdir = NULL;
 }
 
-static void 
+static void
 proc_ov511_create(void)
 {
 	/* No current standard here. Alan prefers /proc/video/ as it keeps
@@ -744,7 +630,7 @@
 		err("Unable to create /proc/video/ov511");
 }
 
-static void 
+static void
 proc_ov511_destroy(void)
 {
 	PDEBUG(3, "removing /proc/video/ov511");
@@ -763,7 +649,7 @@
  **********************************************************************/
 
 /* Write an OV51x register */
-static int 
+static int
 reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
 {
 	int rc;
@@ -774,20 +660,20 @@
 	ov->cbuf[0] = value;
 	rc = usb_control_msg(ov->dev,
 			     usb_sndctrlpipe(ov->dev, 0),
-			     2 /* REG_IO */,
-			     USB_TYPE_CLASS | USB_RECIP_DEVICE,
-			     0, (__u16)reg, &ov->cbuf[0], 1, HZ);	
+			     (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
+			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			     0, (__u16)reg, &ov->cbuf[0], 1, HZ);
 	up(&ov->cbuf_lock);
 
 	if (rc < 0)
-		err("reg write: error %d", rc);
+		err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
 
 	return rc;
 }
 
 /* Read from an OV51x register */
 /* returns: negative is error, pos or zero is data */
-static int 
+static int
 reg_r(struct usb_ov511 *ov, unsigned char reg)
 {
 	int rc;
@@ -795,16 +681,16 @@
 	down(&ov->cbuf_lock);
 	rc = usb_control_msg(ov->dev,
 			     usb_rcvctrlpipe(ov->dev, 0),
-			     2 /* REG_IO */,
-			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE,
+			     (ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
+			     USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			     0, (__u16)reg, &ov->cbuf[0], 1, HZ);
-                               
-	PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
-	
-	if (rc < 0)
-		err("reg read: error %d", rc);
-	else
-		rc = ov->cbuf[0];	
+
+	if (rc < 0) {
+		err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc));
+	} else {
+		rc = ov->cbuf[0];
+		PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
+	}
 
 	up(&ov->cbuf_lock);
 
@@ -814,10 +700,10 @@
 /*
  * Writes bits at positions specified by mask to an OV51x reg. Bits that are in
  * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless 
+ * that are in the same position as 0's in "mask" are preserved, regardless
  * of their respective state in "value".
  */
-static int 
+static int
 reg_w_mask(struct usb_ov511 *ov,
 	   unsigned char reg,
 	   unsigned char value,
@@ -842,7 +728,7 @@
  * Writes multiple (n) byte value to a single register. Only valid with certain
  * registers (0x30 and 0xc4 - 0xce).
  */
-static int 
+static int
 ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
 {
 	int rc;
@@ -855,18 +741,19 @@
 
 	rc = usb_control_msg(ov->dev,
 			     usb_sndctrlpipe(ov->dev, 0),
-			     2 /* REG_IO */,
-			     USB_TYPE_CLASS | USB_RECIP_DEVICE,
+			     1 /* REG_IO */,
+			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			     0, (__u16)reg, ov->cbuf, n, HZ);
 	up(&ov->cbuf_lock);
 
 	if (rc < 0)
-		err("reg write multiple: error %d", rc);
+		err("reg write multiple: error %d: %s", rc,
+		    symbolic(urb_errlist, rc));
 
 	return rc;
 }
 
-static int 
+static int
 ov511_upload_quan_tables(struct usb_ov511 *ov)
 {
 	unsigned char *pYTable = yQuanTable511;
@@ -876,10 +763,8 @@
 
 	PDEBUG(4, "Uploading quantization tables");
 
-	for (i = 0; i < OV511_QUANTABLESIZE / 2; i++)
-	{
-		if (ENABLE_Y_QUANTABLE)
-		{
+	for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) {
+		if (ENABLE_Y_QUANTABLE)	{
 			val0 = *pYTable++;
 			val1 = *pYTable++;
 			val0 &= 0x0f;
@@ -890,8 +775,7 @@
 				return rc;
 		}
 
-		if (ENABLE_UV_QUANTABLE)
-		{
+		if (ENABLE_UV_QUANTABLE) {
 			val0 = *pUVTable++;
 			val1 = *pUVTable++;
 			val0 &= 0x0f;
@@ -909,7 +793,7 @@
 }
 
 /* OV518 quantization tables are 8x4 (instead of 8x8) */
-static int 
+static int
 ov518_upload_quan_tables(struct usb_ov511 *ov)
 {
 	unsigned char *pYTable = yQuanTable518;
@@ -919,10 +803,8 @@
 
 	PDEBUG(4, "Uploading quantization tables");
 
-	for (i = 0; i < OV518_QUANTABLESIZE / 2; i++)
-	{
-		if (ENABLE_Y_QUANTABLE)
-		{
+	for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) {
+		if (ENABLE_Y_QUANTABLE) {
 			val0 = *pYTable++;
 			val1 = *pYTable++;
 			val0 &= 0x0f;
@@ -933,8 +815,7 @@
 				return rc;
 		}
 
-		if (ENABLE_UV_QUANTABLE)
-		{
+		if (ENABLE_UV_QUANTABLE) {
 			val0 = *pUVTable++;
 			val1 = *pUVTable++;
 			val0 &= 0x0f;
@@ -951,16 +832,16 @@
 	return 0;
 }
 
-static int 
+static int
 ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type)
 {
 	int rc;
-		
+
 	/* Setting bit 0 not allowed on 518/518Plus */
 	if (ov->bclass == BCL_OV518)
 		reset_type &= 0xfe;
 
-	PDEBUG(4, "Reset: type=0x%X", reset_type);
+	PDEBUG(4, "Reset: type=0x%02X", reset_type);
 
 	rc = reg_w(ov, R51x_SYS_RESET, reset_type);
 	rc = reg_w(ov, R51x_SYS_RESET, 0);
@@ -973,7 +854,7 @@
 
 /**********************************************************************
  *
- * I2C (sensor) I/O
+ * Low-level I2C I/O functions
  *
  **********************************************************************/
 
@@ -982,7 +863,7 @@
  * This is normally only called from i2c_w(). Note that this function
  * always succeeds regardless of whether the sensor is present and working.
  */
-static int 
+static int
 ov518_i2c_write_internal(struct usb_ov511 *ov,
 			 unsigned char reg,
 			 unsigned char value)
@@ -993,25 +874,21 @@
 
 	/* Select camera register */
 	rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	/* Write "value" to I2C data port of OV511 */
 	rc = reg_w(ov, R51x_I2C_DATA, value);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	/* Initiate 3-byte write cycle */
 	rc = reg_w(ov, R518_I2C_CTL, 0x01);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	return 0;
-
-error:
-	err("ov518 i2c write: error %d", rc);
-	return rc;
 }
 
 /* NOTE: Do not call this function directly! */
-static int 
+static int
 ov511_i2c_write_internal(struct usb_ov511 *ov,
 			 unsigned char reg,
 			 unsigned char value)
@@ -1024,38 +901,33 @@
 	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Select camera register */
 		rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		/* Write "value" to I2C data port of OV511 */
-		rc = reg_w(ov, R51x_I2C_DATA, value);	
-		if (rc < 0) goto error;
+		rc = reg_w(ov, R51x_I2C_DATA, value);
+		if (rc < 0) return rc;
 
 		/* Initiate 3-byte write cycle */
 		rc = reg_w(ov, R511_I2C_CTL, 0x01);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		do rc = reg_r(ov, R511_I2C_CTL);
 		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		if ((rc&2) == 0) /* Ack? */
 			break;
 #if 0
-		/* I2C abort */	
+		/* I2C abort */
 		reg_w(ov, R511_I2C_CTL, 0x10);
 #endif
 		if (--retries < 0) {
 			err("i2c write retries exhausted");
-			rc = -1;
-			goto error;
+			return -1;
 		}
 	}
 
 	return 0;
-
-error:
-	err("i2c write: error %d", rc);
-	return rc;
 }
 
 /* NOTE: Do not call this function directly!
@@ -1063,37 +935,33 @@
  * This is normally only called from i2c_r(). Note that this function
  * always succeeds regardless of whether the sensor is present and working.
  */
-static int 
+static int
 ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
 {
 	int rc, value;
 
 	/* Select camera register */
 	rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	/* Initiate 2-byte write cycle */
 	rc = reg_w(ov, R518_I2C_CTL, 0x03);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	/* Initiate 2-byte read cycle */
 	rc = reg_w(ov, R518_I2C_CTL, 0x05);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	value = reg_r(ov, R51x_I2C_DATA);
 
 	PDEBUG(5, "0x%02X:0x%02X", reg, value);
 
 	return value;
-
-error:
-	err("ov518 i2c read: error %d", rc);
-	return rc;
 }
 
 /* NOTE: Do not call this function directly!
  * returns: negative is error, pos or zero is data */
-static int 
+static int
 ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
 {
 	int rc, value, retries;
@@ -1102,26 +970,25 @@
 	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Select camera register */
 		rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		/* Initiate 2-byte write cycle */
 		rc = reg_w(ov, R511_I2C_CTL, 0x03);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		do rc = reg_r(ov, R511_I2C_CTL);
 		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		if ((rc&2) == 0) /* Ack? */
 			break;
 
-		/* I2C abort */	
+		/* I2C abort */
 		reg_w(ov, R511_I2C_CTL, 0x10);
 
 		if (--retries < 0) {
 			err("i2c write retries exhausted");
-			rc = -1;
-			goto error;
+			return -1;
 		}
 	}
 
@@ -1129,44 +996,39 @@
 	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Initiate 2-byte read cycle */
 		rc = reg_w(ov, R511_I2C_CTL, 0x05);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		do rc = reg_r(ov, R511_I2C_CTL);
 		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		if ((rc&2) == 0) /* Ack? */
 			break;
 
-		/* I2C abort */	
+		/* I2C abort */
 		rc = reg_w(ov, R511_I2C_CTL, 0x10);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		if (--retries < 0) {
 			err("i2c read retries exhausted");
-			rc = -1;
-			goto error;
+			return -1;
 		}
 	}
 
 	value = reg_r(ov, R51x_I2C_DATA);
 
 	PDEBUG(5, "0x%02X:0x%02X", reg, value);
-		
+
 	/* This is needed to make i2c_w() work */
 	rc = reg_w(ov, R511_I2C_CTL, 0x05);
 	if (rc < 0)
-		goto error;
-	
-	return value;
+		return rc;
 
-error:
-	err("i2c read: error %d", rc);
-	return rc;
+	return value;
 }
 
 /* returns: negative is error, pos or zero is data */
-static int 
+static int
 i2c_r(struct usb_ov511 *ov, unsigned char reg)
 {
 	int rc;
@@ -1183,7 +1045,7 @@
 	return rc;
 }
 
-static int 
+static int
 i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
 {
 	int rc;
@@ -1201,7 +1063,7 @@
 }
 
 /* Do not call this function directly! */
-static int 
+static int
 ov51x_i2c_write_mask_internal(struct usb_ov511 *ov,
 			      unsigned char reg,
 			      unsigned char value,
@@ -1234,10 +1096,10 @@
 
 /* Writes bits at positions specified by mask to an I2C reg. Bits that are in
  * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless 
+ * that are in the same position as 0's in "mask" are preserved, regardless
  * of their respective state in "value".
  */
-static int 
+static int
 i2c_w_mask(struct usb_ov511 *ov,
 	   unsigned char reg,
 	   unsigned char value,
@@ -1252,8 +1114,29 @@
 	return rc;
 }
 
+/* Set the read and write slave IDs. The "slave" argument is the write slave,
+ * and the read slave will be set to (slave + 1). ov->i2c_lock should be held
+ * when calling this. This should not be called from outside the i2c I/O
+ * functions.
+ */
+static inline int
+i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave)
+{
+	int rc;
+
+	rc = reg_w(ov, R51x_I2C_W_SID, slave);
+	if (rc < 0) return rc;
+
+	rc = reg_w(ov, R51x_I2C_R_SID, slave + 1);
+	if (rc < 0) return rc;
+
+	return 0;
+}
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+
 /* Write to a specific I2C slave ID and register, using the specified mask */
-static int 
+static int
 i2c_w_slave(struct usb_ov511 *ov,
 	    unsigned char slave,
 	    unsigned char reg,
@@ -1265,38 +1148,22 @@
 	down(&ov->i2c_lock);
 
 	/* Set new slave IDs */
-	if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) {
-		rc = -EIO;
-		goto out;
-	}
-
-	if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) {
-		rc = -EIO;
-		goto out;
-	}
+	rc = i2c_set_slave_internal(ov, slave);
+	if (rc < 0) goto out;
 
 	rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
-	/* Don't bail out yet if error; IDs must be restored */
 
+out:
 	/* Restore primary IDs */
-	slave = ov->primary_i2c_slave;
-	if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) {
-		rc = -EIO;
-		goto out;
-	}
-
-	if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) {
-		rc = -EIO;
-		goto out;
-	}
+	if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
+		err("Couldn't restore primary I2C slave");
 
-out:
 	up(&ov->i2c_lock);
 	return rc;
 }
 
 /* Read from a specific I2C slave ID and register */
-static int 
+static int
 i2c_r_slave(struct usb_ov511 *ov,
 	    unsigned char slave,
 	    unsigned char reg)
@@ -1306,60 +1173,46 @@
 	down(&ov->i2c_lock);
 
 	/* Set new slave IDs */
-	if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) {
-		rc = -EIO;
-		goto out;
-	}
-
-	if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) {
-		rc = -EIO;
-		goto out;
-	}
+	rc = i2c_set_slave_internal(ov, slave);
+	if (rc < 0) goto out;
 
 	if (ov->bclass == BCL_OV518)
 		rc = ov518_i2c_read_internal(ov, reg);
 	else
 		rc = ov511_i2c_read_internal(ov, reg);
-	/* Don't bail out yet if error; IDs must be restored */
 
+out:
 	/* Restore primary IDs */
-	slave = ov->primary_i2c_slave;
-	if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) {
-		rc = -EIO;
-		goto out;
-	}
-
-	if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) {
-		rc = -EIO;
-		goto out;
-	}
+	if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
+		err("Couldn't restore primary I2C slave");
 
-out:
 	up(&ov->i2c_lock);
 	return rc;
 }
 
+#endif /* defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) */
+
 /* Sets I2C read and write slave IDs. Returns <0 for error */
-static int 
+static int
 ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
 {
+	int rc;
+
 	down(&ov->i2c_lock);
 
-	if (reg_w(ov, R51x_I2C_W_SID, sid) < 0)
-		return -EIO;
+	rc = i2c_set_slave_internal(ov, sid);
+	if (rc < 0) goto out;
 
-	if (reg_w(ov, R51x_I2C_R_SID, sid + 1) < 0)
-		return -EIO;
-
-	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
-		return -EIO;
+	// FIXME: Is this actually necessary?
+	rc = ov51x_reset(ov, OV511_RESET_NOREGS);
+	if (rc < 0) goto out;
 
+out:
 	up(&ov->i2c_lock);
-
-	return 0;
+	return rc;
 }
 
-static int 
+static int
 write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals)
 {
 	int rc;
@@ -1367,26 +1220,21 @@
 	while (pRegvals->bus != OV511_DONE_BUS) {
 		if (pRegvals->bus == OV511_REG_BUS) {
 			if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0)
-				goto error;
+				return rc;
 		} else if (pRegvals->bus == OV511_I2C_BUS) {
 			if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0)
-				goto error;
+				return rc;
 		} else {
 			err("Bad regval array");
-			rc = -1;
-			goto error;
+			return -1;
 		}
 		pRegvals++;
 	}
 	return 0;
-
-error:
-	err("write regvals: error %d", rc);
-	return rc;
 }
 
-#ifdef OV511_DEBUG 
-static void 
+#ifdef OV511_DEBUG
+static void
 dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn)
 {
 	int i;
@@ -1394,18 +1242,18 @@
 
 	for (i = reg1; i <= regn; i++) {
 		rc = i2c_r(ov, i);
-		info("OV7610[0x%X] = 0x%X", i, rc);
+		info("Sensor[0x%02X] = 0x%02X", i, rc);
 	}
 }
 
-static void 
+static void
 dump_i2c_regs(struct usb_ov511 *ov)
 {
 	info("I2C REGS");
 	dump_i2c_range(ov, 0x00, 0x7C);
 }
 
-static void 
+static void
 dump_reg_range(struct usb_ov511 *ov, int reg1, int regn)
 {
 	int i;
@@ -1413,12 +1261,12 @@
 
 	for (i = reg1; i <= regn; i++) {
 		rc = reg_r(ov, i);
-		info("OV511[0x%X] = 0x%X", i, rc);
+		info("OV511[0x%02X] = 0x%02X", i, rc);
 	}
 }
 
 /* FIXME: Should there be an OV518 version of this? */
-static void 
+static void
 ov511_dump_regs(struct usb_ov511 *ov)
 {
 	info("CAMERA INTERFACE REGS");
@@ -1445,43 +1293,29 @@
 }
 #endif
 
-/**********************************************************************
- *
- * Kernel I2C Interface
- *
- **********************************************************************/
-
-/* For as-yet unimplemented I2C interface */
-static void 
-call_i2c_clients(struct usb_ov511 *ov, unsigned int cmd,
-		 void *arg)
-{
-	/* Do nothing */
-}
-
 /*****************************************************************************/
 
 /* Temporarily stops OV511 from functioning. Must do this before changing
  * registers while the camera is streaming */
-static inline int 
+static inline int
 ov51x_stop(struct usb_ov511 *ov)
 {
 	PDEBUG(4, "stopping");
-	ov->stopped = 1;	
+	ov->stopped = 1;
 	if (ov->bclass == BCL_OV518)
-		return (reg_w(ov, R51x_SYS_RESET, 0x3a));
+		return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a));
 	else
 		return (reg_w(ov, R51x_SYS_RESET, 0x3d));
 }
 
 /* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
  * actually stopped (for performance). */
-static inline int 
+static inline int
 ov51x_restart(struct usb_ov511 *ov)
 {
 	if (ov->stopped) {
 		PDEBUG(4, "restarting");
-		ov->stopped = 0;	
+		ov->stopped = 0;
 
 		/* Reinitialize the stream */
 		if (ov->bclass == BCL_OV518)
@@ -1494,7 +1328,7 @@
 }
 
 /* Resets the hardware snapshot button */
-static void 
+static void
 ov51x_clear_snapshot(struct usb_ov511 *ov)
 {
 	if (ov->bclass == BCL_OV511) {
@@ -1506,12 +1340,12 @@
 	} else {
 		err("clear snap: invalid bridge type");
 	}
-	
 }
 
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
 /* Checks the status of the snapshot button. Returns 1 if it was pressed since
  * it was last cleared, and zero in all other cases (including errors) */
-static int 
+static int
 ov51x_check_snapshot(struct usb_ov511 *ov)
 {
 	int ret, status = 0;
@@ -1531,19 +1365,20 @@
 
 	return status;
 }
+#endif
 
 /* This does an initial reset of an OmniVision sensor and ensures that I2C
  * is synchronized. Returns <0 for failure.
  */
-static int 
+static int
 init_ov_sensor(struct usb_ov511 *ov)
 {
 	int i, success;
 
-	/* Reset the sensor */ 
+	/* Reset the sensor */
 	if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO;
 
-	/* Wait for it to initialize */ 
+	/* Wait for it to initialize */
 	schedule_timeout (1 + 150 * HZ / 1000);
 
 	for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
@@ -1553,9 +1388,9 @@
 			continue;
 		}
 
-		/* Reset the sensor */ 
+		/* Reset the sensor */
 		if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO;
-		/* Wait for it to initialize */ 
+		/* Wait for it to initialize */
 		schedule_timeout(1 + 150 * HZ / 1000);
 		/* Dummy read to sync I2C */
 		if (i2c_r(ov, 0x00) < 0) return -EIO;
@@ -1563,14 +1398,14 @@
 
 	if (!success)
 		return -EIO;
-	
+
 	PDEBUG(1, "I2C synced in %d attempt(s)", i);
 
 	return 0;
 }
 
-static int 
-ov51x_set_packet_size(struct usb_ov511 *ov, int size)
+static int
+ov511_set_packet_size(struct usb_ov511 *ov, int size)
 {
 	int alt, mult;
 
@@ -1602,7 +1437,44 @@
 			err("Set packet size: invalid size (%d)", size);
 			return -EINVAL;
 		}
-	} else if (ov->bclass == BCL_OV518) {
+	} else {
+		err("Set packet size: Invalid bridge type");
+		return -EINVAL;
+	}
+
+	PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt);
+
+	if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0)
+		return -EIO;
+
+	if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
+		err("Set packet size: set interface error");
+		return -EBUSY;
+	}
+
+	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
+		return -EIO;
+
+	ov->packet_size = size;
+
+	if (ov51x_restart(ov) < 0)
+		return -EIO;
+
+	return 0;
+}
+
+/* Note: Unlike the OV511/OV511+, the size argument does NOT include the
+ * optional packet number byte. The actual size *is* stored in ov->packet_size,
+ * though. */
+static int
+ov518_set_packet_size(struct usb_ov511 *ov, int size)
+{
+	int alt;
+
+	if (ov51x_stop(ov) < 0)
+		return -EIO;
+
+	if (ov->bclass == BCL_OV518) {
 		if (size == 0) alt = OV518_ALT_SIZE_0;
 		else if (size == 128) alt = OV518_ALT_SIZE_128;
 		else if (size == 256) alt = OV518_ALT_SIZE_256;
@@ -1620,35 +1492,32 @@
 		return -EINVAL;
 	}
 
-	PDEBUG(3, "set packet size: %d, mult=%d, alt=%d", size, mult, alt);
+	PDEBUG(3, "%d, alt=%d", size, alt);
 
-	// FIXME: Don't know how to do this on OV518 yet
-	if (ov->bclass == BCL_OV511) {
-		if (reg_w(ov, R51x_FIFO_PSIZE,
-				    mult) < 0) {
-			return -EIO;
-		}
+	ov->packet_size = size;
+	if (size > 0) {
+		/* Program ISO FIFO size reg (packet number isn't included) */
+		ov518_reg_w32(ov, 0x30, size, 2);
+
+		if (ov->packet_numbering)
+			++ov->packet_size;
 	}
-	
+
 	if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
 		err("Set packet size: set interface error");
 		return -EBUSY;
 	}
 
 	/* Initialize the stream */
-	if (ov->bclass == BCL_OV518)
-		if (reg_w(ov, 0x2f, 0x80) < 0)
-			return -EIO;
-
-	// FIXME - Should we only reset the FIFO?
-	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
+	if (reg_w(ov, 0x2f, 0x80) < 0)
 		return -EIO;
 
-	ov->packet_size = size;
-
 	if (ov51x_restart(ov) < 0)
 		return -EIO;
 
+	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
+		return -EIO;
+
 	return 0;
 }
 
@@ -1659,7 +1528,6 @@
 	int rc = 0;
 
 	if (!ov->compress_inited) {
-
 		reg_w(ov, 0x70, phy);
 		reg_w(ov, 0x71, phuv);
 		reg_w(ov, 0x72, pvy);
@@ -1677,7 +1545,7 @@
 	}
 
 	ov->compress_inited = 1;
-out:	
+out:
 	return rc;
 }
 
@@ -1688,7 +1556,6 @@
 	int rc = 0;
 
 	if (!ov->compress_inited) {
-
 		if (ov518_upload_quan_tables(ov) < 0) {
 			err("Error uploading quantization tables");
 			rc = -EIO;
@@ -1697,7 +1564,7 @@
 	}
 
 	ov->compress_inited = 1;
-out:	
+out:
 	return rc;
 }
 
@@ -1718,13 +1585,19 @@
 	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV6620:
-	case SEN_OV6630:
 	{
 		rc = i2c_w(ov, OV7610_REG_CNT, val >> 8);
 		if (rc < 0)
 			goto out;
 		break;
 	}
+	case SEN_OV6630:
+	{
+		rc = i2c_w_mask(ov, OV7610_REG_CNT, val >> 12, 0x0f);
+		if (rc < 0)
+			goto out;
+		break;
+	}
 	case SEN_OV7620:
 	{
 		unsigned char ctab[] = {
@@ -1771,13 +1644,19 @@
 	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV6620:
-	case SEN_OV6630:
 		rc = i2c_r(ov, OV7610_REG_CNT);
 		if (rc < 0)
 			return rc;
 		else
 			*val = rc << 8;
 		break;
+	case SEN_OV6630:
+		rc = i2c_r(ov, OV7610_REG_CNT);
+		if (rc < 0)
+			return rc;
+		else
+			*val = rc << 12;
+		break;
 	case SEN_OV7620:
 		/* Use Y gamma reg instead. Bit 0 is the enable bit. */
 		rc = i2c_r(ov, 0x64);
@@ -1816,7 +1695,7 @@
 
 	switch (ov->sensor) {
 	case SEN_OV7610:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV6620:
 	case SEN_OV6630:
 		rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
@@ -1859,7 +1738,7 @@
 
 	switch (ov->sensor) {
 	case SEN_OV7610:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV7620:
 	case SEN_OV6620:
 	case SEN_OV6630:
@@ -1899,7 +1778,7 @@
 
 	switch (ov->sensor) {
 	case SEN_OV7610:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV6620:
 	case SEN_OV6630:
 		rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
@@ -1943,7 +1822,7 @@
 
 	switch (ov->sensor) {
 	case SEN_OV7610:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV6620:
 	case SEN_OV6630:
 		rc = i2c_r(ov, OV7610_REG_SAT);
@@ -2142,6 +2021,7 @@
 	return 0;
 }
 
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
 // FIXME: Exposure range is only 0x00-0x7f in interlace mode
 /* Sets current exposure for sensor. This only has an effect if auto-exposure
  * is off */
@@ -2161,7 +2041,7 @@
 	case SEN_OV6630:
 	case SEN_OV7610:
 	case SEN_OV7620:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV8600:
 		rc = i2c_w(ov, 0x10, val);
 		if (rc < 0)
@@ -2199,7 +2079,7 @@
 	case SEN_OV6620:
 	case SEN_OV6630:
 	case SEN_OV7620:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV8600:
 		rc = i2c_r(ov, 0x10);
 		if (rc < 0)
@@ -2223,9 +2103,10 @@
 
 	return 0;
 }
+#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
 
 /* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */
-static inline void 
+static inline void
 ov51x_led_control(struct usb_ov511 *ov, int enable)
 {
 	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
@@ -2243,7 +2124,7 @@
  *	50 - 50Hz, for European and Asian lighting
  *	60 - 60Hz, for American lighting
  *
- * Tested with: OV7610, OV7620, OV7620AE, OV6620
+ * Tested with: OV7610, OV7620, OV76BE, OV6620
  * Unsupported: KS0127, KS0127B, SAA7111A
  * Returns: 0 for success
  */
@@ -2271,12 +2152,12 @@
 		i2c_w_mask(ov, 0x13, 0x00, 0x10);
 		break;
 	case SEN_OV7620:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV8600:
 		i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
 		i2c_w(ov, 0x2b, sixty?0x00:0xac);
 		i2c_w_mask(ov, 0x76, 0x01, 0x01);
-		break;		
+		break;
 	case SEN_OV6620:
 	case SEN_OV6630:
 		i2c_w(ov, 0x2b, sixty?0xa8:0x28);
@@ -2302,7 +2183,7 @@
  * caused by some (usually fluorescent) lighting. The light frequency must be
  * set either before or after enabling it with ov51x_set_light_freq().
  *
- * Tested with: OV7610, OV7620, OV7620AE, OV6620.
+ * Tested with: OV7610, OV7620, OV76BE, OV6620.
  * Unsupported: KS0127, KS0127B, SAA7111A
  * Returns: 0 for success
  */
@@ -2364,7 +2245,7 @@
  */
 static inline int
 sensor_set_auto_exposure(struct usb_ov511 *ov, int enable)
-{	
+{
 	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
 
 	switch (ov->sensor) {
@@ -2373,10 +2254,10 @@
 		break;
 	case SEN_OV6620:
 	case SEN_OV7620:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV8600:
 		i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01);
-		break;		
+		break;
 	case SEN_OV6630:
 		i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10);
 		break;
@@ -2399,13 +2280,12 @@
  * that are illuminated from behind.
  *
  * Tested with: OV6620, OV7620
- * Unsupported: OV7610, OV7620AE, KS0127, KS0127B, SAA7111A
+ * Unsupported: OV7610, OV76BE, KS0127, KS0127B, SAA7111A
  * Returns: 0 for success
  */
 static int
 sensor_set_backlight(struct usb_ov511 *ov, int enable)
 {
-
 	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
 
 	switch (ov->sensor) {
@@ -2414,7 +2294,7 @@
 		i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0);
 		i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
 		i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
-		break;		
+		break;
 	case SEN_OV6620:
 		i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0);
 		i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
@@ -2426,7 +2306,7 @@
 		i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
 		break;
 	case SEN_OV7610:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_KS0127:
 	case SEN_KS0127B:
 	case SEN_SAA7111A:
@@ -2442,27 +2322,56 @@
 	return 0;
 }
 
+static inline int
+sensor_set_mirror(struct usb_ov511 *ov, int enable)
+{
+	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
+
+	switch (ov->sensor) {
+	case SEN_OV6620:
+	case SEN_OV6630:
+	case SEN_OV7610:
+	case SEN_OV7620:
+	case SEN_OV76BE:
+	case SEN_OV8600:
+		i2c_w_mask(ov, 0x12, enable?0x40:0x00, 0x40);
+		break;
+	case SEN_KS0127:
+	case SEN_KS0127B:
+	case SEN_SAA7111A:
+		PDEBUG(5, "Unsupported with this sensor");
+		return -EPERM;
+	default:
+		err("Sensor not supported for set_mirror");
+		return -EINVAL;
+	}
+
+	ov->mirror = enable;
+
+	return 0;
+}
+
 /* Returns number of bits per pixel (regardless of where they are located;
  * planar or not), or zero for unsupported format.
  */
-static inline int 
+static inline int
 get_depth(int palette)
 {
 	switch (palette) {
 	case VIDEO_PALETTE_GREY:    return 8;
+	case VIDEO_PALETTE_YUV420:  return 12;
+	case VIDEO_PALETTE_YUV420P: return 12; /* Planar */
 	case VIDEO_PALETTE_RGB565:  return 16;
-	case VIDEO_PALETTE_RGB24:   return 24;  
+	case VIDEO_PALETTE_RGB24:   return 24;
 	case VIDEO_PALETTE_YUV422:  return 16;
 	case VIDEO_PALETTE_YUYV:    return 16;
-	case VIDEO_PALETTE_YUV420:  return 12;
 	case VIDEO_PALETTE_YUV422P: return 16; /* Planar */
-	case VIDEO_PALETTE_YUV420P: return 12; /* Planar */
 	default:		    return 0;  /* Invalid format */
 	}
 }
 
 /* Bytes per frame. Used by read(). Return of 0 indicates error */
-static inline long int 
+static inline long int
 get_frame_length(struct ov511_frame *frame)
 {
 	if (!frame)
@@ -2502,7 +2411,7 @@
 		i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0);
 		i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
 		break;
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 //		i2c_w(ov, 0x2b, 0x00);
 		i2c_w(ov, 0x14, qvga?0xa4:0x84);
 // FIXME: Enable this once 7620AE uses 7620 initial settings
@@ -2528,13 +2437,13 @@
 	/******** Palette-specific regs ********/
 
 	if (mode == VIDEO_PALETTE_GREY) {
-		if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) {
+		if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
 			/* these aren't valid on the OV6620/OV7620/6630? */
 			i2c_w_mask(ov, 0x0e, 0x40, 0x40);
 		}
 		i2c_w_mask(ov, 0x13, 0x20, 0x20);
 	} else {
-		if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) {
+		if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
 			/* not valid on the OV6620/OV7620/6630? */
 			i2c_w_mask(ov, 0x0e, 0x00, 0x40);
 		}
@@ -2596,8 +2505,7 @@
 	if (framedrop >= 0)
 		i2c_w(ov, 0x16, framedrop);
 
-	/* We only have code to convert GBR -> RGB24 */
-	if ((mode == VIDEO_PALETTE_RGB24) && sensor_gbr)
+	if (sensor_gbr)
 		i2c_w_mask(ov, 0x12, 0x08, 0x08);
 	else
 		i2c_w_mask(ov, 0x12, 0x00, 0x08);
@@ -2614,7 +2522,7 @@
 	// This will go away as soon as ov51x_mode_init_sensor_regs()
 	// is fully tested.
 	/* 7620/6620/6630? don't have register 0x35, so play it safe */
-	if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) {
+	if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
 		if (width == 640 && height == 480)
 			i2c_w(ov, 0x35, 0x9e);
 		else
@@ -2636,13 +2544,13 @@
 	 * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */
 	switch (ov->sensor) {
 	case SEN_OV7610:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 		hwsbase = 0x38;
 		hwebase = 0x3a;
 		vwsbase = vwebase = 0x05;
 		break;
 	case SEN_OV6620:
-	case SEN_OV6630:	// FIXME: Is this right?
+	case SEN_OV6630:
 		hwsbase = 0x38;
 		hwebase = 0x3a;
 		vwsbase = 0x05;
@@ -2659,7 +2567,9 @@
 	}
 
 	if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) {
-		if (width > 176 && height > 144) {  /* CIF */
+		/* Note: OV518(+) does downsample on its own) */
+		if ((width > 176 && height > 144)
+		    || ov->bclass == BCL_OV518) {  /* CIF */
 			ret = mode_init_ov_sensor_regs(ov, width, height,
 				mode, sub_flag, 0);
 			if (ret < 0)
@@ -2736,7 +2646,7 @@
 ov511_mode_init_regs(struct usb_ov511 *ov,
 		     int width, int height, int mode, int sub_flag)
 {
-	int lncnt, pxcnt, rc = 0;
+	int hsegs, vsegs;
 
 	if (sub_flag) {
 		width = ov->subw;
@@ -2752,11 +2662,11 @@
 		if (width == 320 && height == 240) {
 			/* No need to do anything special */
 		} else if (width == 640 && height == 480) {
-			/* Set the OV511 up as 320x480, but keep the V4L
-			 * resolution as 640x480 */
+			/* Set the OV511 up as 320x480, but keep the
+			 * V4L resolution as 640x480 */
 			width = 320;
 		} else {
-			err("SAA7111A only supports 320x240 or 640x480");
+			err("SAA7111A only allows 320x240 or 640x480");
 			return -EINVAL;
 		}
 	}
@@ -2788,11 +2698,11 @@
 	/* Here I'm assuming that snapshot size == image size.
 	 * I hope that's always true. --claudio
 	 */
-	pxcnt = (width >> 3) - 1;
-	lncnt = (height >> 3) - 1;
+	hsegs = (width >> 3) - 1;
+	vsegs = (height >> 3) - 1;
 
-	reg_w(ov, R511_CAM_PXCNT, pxcnt);
-	reg_w(ov, R511_CAM_LNCNT, lncnt);
+	reg_w(ov, R511_CAM_PXCNT, hsegs);
+	reg_w(ov, R511_CAM_LNCNT, vsegs);
 	reg_w(ov, R511_CAM_PXDIV, 0x00);
 	reg_w(ov, R511_CAM_LNDIV, 0x00);
 
@@ -2800,8 +2710,8 @@
 	reg_w(ov, R511_CAM_OPTS, 0x03);
 
 	/* Snapshot additions */
-	reg_w(ov, R511_SNAP_PXCNT, pxcnt);
-	reg_w(ov, R511_SNAP_LNCNT, lncnt);
+	reg_w(ov, R511_SNAP_PXCNT, hsegs);
+	reg_w(ov, R511_SNAP_LNCNT, vsegs);
 	reg_w(ov, R511_SNAP_PXDIV, 0x00);
 	reg_w(ov, R511_SNAP_LNDIV, 0x00);
 
@@ -2811,27 +2721,17 @@
 		reg_w(ov, R511_COMP_LUT_EN, 0x03);
 		ov51x_reset(ov, OV511_RESET_OMNICE);
 	}
-//out:
+
 	if (ov51x_restart(ov) < 0)
 		return -EIO;
 
-	return rc;
+	return 0;
 }
 
-static struct mode_list_518 mlist518[] = {
-	/* W    H   reg28 reg29 reg2a reg2c reg2e reg24 reg25 */
-	{ 352, 288, 0x00, 0x16, 0x48, 0x00, 0x00, 0x9f, 0x90 },
-	{ 320, 240, 0x00, 0x14, 0x3c, 0x10, 0x18, 0x9f, 0x90 },
-	{ 176, 144, 0x05, 0x0b, 0x24, 0x00, 0x00, 0xff, 0xf0 },
-	{ 160, 120, 0x05, 0x0a, 0x1e, 0x08, 0x0c, 0xff, 0xf0 },
-	{ 0, 0 }
-};
-
 /* Sets up the OV518/OV518+ with the given image parameters
  *
  * OV518 needs a completely different approach, until we can figure out what
- * the individual registers do. Many register ops are commented out until we
- * can find out if they are still valid. Also, only 15 FPS is supported now.
+ * the individual registers do. Also, only 15 FPS is supported now.
  *
  * Do not put any sensor-specific code in here (including I2C I/O functions)
  */
@@ -2839,112 +2739,110 @@
 ov518_mode_init_regs(struct usb_ov511 *ov,
 		     int width, int height, int mode, int sub_flag)
 {
-	int i;
+	int hsegs, vsegs, hi_res;
+
+	if (sub_flag) {
+		width = ov->subw;
+		height = ov->subh;
+	}
 
 	PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
 	       width, height, mode, sub_flag);
 
+	if (width % 16 || height % 8) {
+		err("Invalid size (%d, %d)", width, height);
+		return -EINVAL;
+	}
+
+	if (width < ov->minwidth || height < ov->minheight) {
+		err("Requested dimensions are too small");
+		return -EINVAL;
+	}
+
+	if (width >= 320 && height >= 240) {
+		hi_res = 1;
+	} else if (width >= 320 || height >= 240) {
+		err("Invalid width/height combination (%d, %d)", width, height);
+		return -EINVAL;
+	} else {
+		hi_res = 0;
+	}
+
 	if (ov51x_stop(ov) < 0)
 		return -EIO;
 
-	for (i = 0; mlist518[i].width; i++) {
-//		int lncnt, pxcnt;
+	/******** Set the mode ********/
 
-		if (width != mlist518[i].width || height != mlist518[i].height)
-			continue;
+	reg_w(ov, 0x2b, 0);
+	reg_w(ov, 0x2c, 0);
+	reg_w(ov, 0x2d, 0);
+	reg_w(ov, 0x2e, 0);
+	reg_w(ov, 0x3b, 0);
+	reg_w(ov, 0x3c, 0);
+	reg_w(ov, 0x3d, 0);
+	reg_w(ov, 0x3e, 0);
 
-// FIXME: Subcapture won't be possible until we know what the registers do
-// FIXME: We can't handle anything but YUV420 so far
+	reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
+	reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
 
-//		/* Here I'm assuming that snapshot size == image size.
-//		 * I hope that's always true. --claudio
-//		 */
-//		pxcnt = sub_flag ? (ov511->subw >> 3) - 1 : mlist[i].pxcnt;
-//		lncnt = sub_flag ? (ov511->subh >> 3) - 1 : mlist[i].lncnt;
-//
-//		reg_w(ov511, 0x12, pxcnt);
-//		reg_w(ov511, 0x13, lncnt);
-
-		/******** Set the mode ********/		
-
-		/* Mode independent regs */
-		reg_w(ov, 0x2b, 0x00);
-		reg_w(ov, 0x2d, 0x00);
-		reg_w(ov, 0x3b, 0x00);
-		reg_w(ov, 0x3d, 0x00);
-
-		/* Mode dependent regs. Regs 38 - 3e are always the same as
-		 * regs 28 - 2e */
-		reg_w_mask(ov, 0x28, mlist518[i].reg28
-			| (mode == VIDEO_PALETTE_GREY) ? 0x80:0x00, 0x8f);
-		reg_w(ov, 0x29, mlist518[i].reg29);
-		reg_w(ov, 0x2a, mlist518[i].reg2a);
-		reg_w(ov, 0x2c, mlist518[i].reg2c);
-		reg_w(ov, 0x2e, mlist518[i].reg2e);
-		reg_w_mask(ov, 0x38, mlist518[i].reg28 
-			| (mode == VIDEO_PALETTE_GREY) ? 0x80:0x00, 0x8f);
-		reg_w(ov, 0x39, mlist518[i].reg29);
-		reg_w(ov, 0x3a, mlist518[i].reg2a);
-		reg_w(ov, 0x3c, mlist518[i].reg2c);
-		reg_w(ov, 0x3e, mlist518[i].reg2e);
-		reg_w(ov, 0x24, mlist518[i].reg24);
-		reg_w(ov, 0x25, mlist518[i].reg25);
-
-		/* Windows driver does this here; who knows why */
-		reg_w(ov, 0x2f, 0x80);
-
-		/******** Set the framerate (to 15 FPS) ********/		
-
-		/* Mode independent, but framerate dependent, regs */
-		/* These are for 15 FPS only */
-		reg_w(ov, 0x51, 0x08);
-		reg_w(ov, 0x22, 0x18);
-		reg_w(ov, 0x23, 0xff);
-		reg_w(ov, 0x71, 0x19);  /* Compression-related? */
-
-		// FIXME: Sensor-specific
-		/* Bit 5 is what matters here. Of course, it is "reserved" */
-		i2c_w(ov, 0x54, 0x23);
-
-		reg_w(ov, 0x2f, 0x80);
-
-		/* Mode dependent regs */
-		if ((width == 352 && height == 288) ||
-		    (width == 320 && height == 240)) {
-			/*  640 (280h) byte iso packets */
-			ov518_reg_w32(ov, 0x30,    640, 2);	/* 280h   */
-			ov518_reg_w32(ov, 0xc4,    400, 2);	/* 190h   */
-			ov518_reg_w32(ov, 0xc6,    500, 2);	/* 1f4h   */
-			ov518_reg_w32(ov, 0xc7,    500, 2);	/* 1f4h   */
-			ov518_reg_w32(ov, 0xc8,    142, 2);	/* 8eh    */
-			ov518_reg_w32(ov, 0xca, 131098, 3);	/* 2001ah */
-			ov518_reg_w32(ov, 0xcb,    532, 2);	/* 214h   */
-			ov518_reg_w32(ov, 0xcc,   2000, 2);	/* 7d0h   */
-			ov518_reg_w32(ov, 0xcd,     32, 2);	/* 20h    */
-			ov518_reg_w32(ov, 0xce,    608, 2);	/* 260h   */
-		} else if ((width == 176 && height == 144) ||
-			   (width == 160 && height == 120)) {
-			/*  384 (180h) byte iso packets */
-			ov518_reg_w32(ov, 0x30,    384, 2);	/* 180h   */
-			ov518_reg_w32(ov, 0xc4,    200, 2);	/* c8h    */
-			ov518_reg_w32(ov, 0xc6,    320, 2);	/* 140h   */
-			ov518_reg_w32(ov, 0xc7,    320, 2);	/* 140h   */
-			ov518_reg_w32(ov, 0xc8,     96, 2);	/* 60h    */
-			ov518_reg_w32(ov, 0xca,  78607, 3);	/* 1330fh */
-			ov518_reg_w32(ov, 0xcb,    320, 2);	/* 140h   */
-			ov518_reg_w32(ov, 0xcc,   1260, 2);	/* 4ech   */
-			ov518_reg_w32(ov, 0xcd,     19, 2);	/* 13h    */
-			ov518_reg_w32(ov, 0xce,    365, 2);	/* 16dh   */
-		} else {
-			/* Can't happen, since we already handled this case */
-			err("ov518_mode_init_regs(): **** logic error ****");
-		}
+	hsegs = width / 16;
+	vsegs = height / 4;
 
-		reg_w(ov, 0x2f, 0x80);
+	reg_w(ov, 0x29, hsegs);
+	reg_w(ov, 0x2a, vsegs);
 
-		break;
+	reg_w(ov, 0x39, hsegs);
+	reg_w(ov, 0x3a, vsegs);
+
+	/* Windows driver does this here; who knows why */
+	reg_w(ov, 0x2f, 0x80);
+
+	/******** Set the framerate (to 15 FPS) ********/
+
+	/* Mode independent, but framerate dependent, regs */
+	reg_w(ov, 0x51, 0x02);	/* Clock divider; lower==faster */
+	reg_w(ov, 0x22, 0x18);
+	reg_w(ov, 0x23, 0xff);
+
+	if (ov->bridge == BRG_OV518PLUS)
+		reg_w(ov, 0x21, 0x19);
+	else
+		reg_w(ov, 0x71, 0x19);	/* Compression-related? */
+
+	// FIXME: Sensor-specific
+	/* Bit 5 is what matters here. Of course, it is "reserved" */
+	i2c_w(ov, 0x54, 0x23);
+
+	reg_w(ov, 0x2f, 0x80);
+
+	if (ov->bridge == BRG_OV518PLUS) {
+		reg_w(ov, 0x24, 0x94);
+		reg_w(ov, 0x25, 0x90);
+		ov518_reg_w32(ov, 0xc4,    400, 2);	/* 190h   */
+		ov518_reg_w32(ov, 0xc6,    540, 2);	/* 21ch   */
+		ov518_reg_w32(ov, 0xc7,    540, 2);	/* 21ch   */
+		ov518_reg_w32(ov, 0xc8,    108, 2);	/* 6ch    */
+		ov518_reg_w32(ov, 0xca, 131098, 3);	/* 2001ah */
+		ov518_reg_w32(ov, 0xcb,    532, 2);	/* 214h   */
+		ov518_reg_w32(ov, 0xcc,   2400, 2);	/* 960h   */
+		ov518_reg_w32(ov, 0xcd,     32, 2);	/* 20h    */
+		ov518_reg_w32(ov, 0xce,    608, 2);	/* 260h   */
+	} else {
+		reg_w(ov, 0x24, 0x9f);
+		reg_w(ov, 0x25, 0x90);
+		ov518_reg_w32(ov, 0xc4,    400, 2);	/* 190h   */
+		ov518_reg_w32(ov, 0xc6,    500, 2);	/* 1f4h   */
+		ov518_reg_w32(ov, 0xc7,    500, 2);	/* 1f4h   */
+		ov518_reg_w32(ov, 0xc8,    142, 2);	/* 8eh    */
+		ov518_reg_w32(ov, 0xca, 131098, 3);	/* 2001ah */
+		ov518_reg_w32(ov, 0xcb,    532, 2);	/* 214h   */
+		ov518_reg_w32(ov, 0xcc,   2000, 2);	/* 7d0h   */
+		ov518_reg_w32(ov, 0xcd,     32, 2);	/* 20h    */
+		ov518_reg_w32(ov, 0xce,    608, 2);	/* 260h   */
 	}
 
+	reg_w(ov, 0x2f, 0x80);
+
 	if (ov51x_restart(ov) < 0)
 		return -EIO;
 
@@ -2952,11 +2850,6 @@
 	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
 		return -EIO;
 
-	if (mlist518[i].width == 0) {
-		err("Unknown mode (%d, %d): %d", width, height, mode);
-		return -EINVAL;
-	}
-
 	return 0;
 }
 
@@ -2982,7 +2875,7 @@
 	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV7620:
-	case SEN_OV7620AE:
+	case SEN_OV76BE:
 	case SEN_OV8600:
 	case SEN_OV6620:
 	case SEN_OV6630:
@@ -2994,10 +2887,10 @@
 		rc = -EINVAL;
 		break;
 	case SEN_SAA7111A:
-//		rc = mode_init_saa_sensor_regs(ov, width, height, mode, 
+//		rc = mode_init_saa_sensor_regs(ov, width, height, mode,
 //					       sub_flag);
 
-		PDEBUG(1, "SAA status = 0X%x", i2c_r(ov, 0x1f));
+		PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f));
 		break;
 	default:
 		err("Unknown sensor");
@@ -3030,19 +2923,21 @@
 	if (FATAL_ERROR(rc))
 		return rc;
 
+	rc = sensor_set_mirror(ov, ov->mirror);
+	if (FATAL_ERROR(rc))
+		return rc;
+
 	return 0;
 }
 
-/* This sets the default image parameters (Size = max, RGB24). This is
- * useful for apps that use read() and do not set these.
+/* This sets the default image parameters. This is useful for apps that use
+ * read() and do not set these.
  */
-static int 
+static int
 ov51x_set_default_params(struct usb_ov511 *ov)
 {
 	int i;
 
-	PDEBUG(3, "%dx%d, RGB24", ov->maxwidth, ov->maxheight);
-
 	/* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
 	 * (using read() instead). */
 	for (i = 0; i < OV511_NUMFRAMES; i++) {
@@ -3053,10 +2948,14 @@
 			ov->frame[i].format = force_palette;
 		else
 			ov->frame[i].format = VIDEO_PALETTE_RGB24;
+
 		ov->frame[i].depth = get_depth(ov->frame[i].format);
 	}
 
-	/* Initialize to max width/height, RGB24 */
+	PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight,
+	       symbolic(v4l1_plist, ov->frame[0].format));
+
+	/* Initialize to max width/height, YUV420 or RGB24 (if supported) */
 	if (mode_init_regs(ov, ov->maxwidth, ov->maxheight,
 			   ov->frame[0].format, 0) < 0)
 		return -EINVAL;
@@ -3071,7 +2970,7 @@
  **********************************************************************/
 
 /* Set analog input port of decoder */
-static int 
+static int
 decoder_set_input(struct usb_ov511 *ov, int input)
 {
 	PDEBUG(4, "port %d", input);
@@ -3093,7 +2992,7 @@
 }
 
 /* Get ASCII name of video input */
-static int 
+static int
 decoder_get_input_name(struct usb_ov511 *ov, int input, char *name)
 {
 	switch (ov->sensor) {
@@ -3105,7 +3004,6 @@
 			sprintf(name, "CVBS-%d", input);
 		else // if (input < 8)
 			sprintf(name, "S-Video-%d", input - 4);
-
 		break;
 	}
 	default:
@@ -3116,7 +3014,7 @@
 }
 
 /* Set norm (NTSC, PAL, SECAM, AUTO) */
-static int 
+static int
 decoder_set_norm(struct usb_ov511 *ov, int norm)
 {
 	PDEBUG(4, "%d", norm);
@@ -3131,7 +3029,7 @@
 			reg_e = 0x00;	/* NTSC M / PAL BGHI */
 		} else if (norm == VIDEO_MODE_PAL) {
 			reg_8 = 0x00;	/* 50 Hz */
-			reg_e = 0x00;	/* NTSC M / PAL BGHI */	
+			reg_e = 0x00;	/* NTSC M / PAL BGHI */
 		} else if (norm == VIDEO_MODE_AUTO) {
 			reg_8 = 0x80;	/* Auto field detect */
 			reg_e = 0x00;	/* NTSC M / PAL BGHI */
@@ -3153,7 +3051,6 @@
 	return 0;
 }
 
-
 /**********************************************************************
  *
  * Color correction functions
@@ -3176,21 +3073,21 @@
  * coefficients are scaled into 16.16 fixed-point integers.
  * They were determined as follows:
  *
- *	double brightness = 1.0;  (0->black; 1->full scale) 
+ *	double brightness = 1.0;  (0->black; 1->full scale)
  *	double saturation = 1.0;  (0->greyscale; 1->full color)
  *	double fixScale = brightness * 256 * 256;
  *	int rvScale = (int)(1.402 * saturation * fixScale);
  *	int guScale = (int)(-0.344136 * saturation * fixScale);
  *	int gvScale = (int)(-0.714136 * saturation * fixScale);
  *	int buScale = (int)(1.772 * saturation * fixScale);
- *	int yScale = (int)(fixScale);	
+ *	int yScale = (int)(fixScale);
  */
 
 /* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
 #define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
 
 static inline void
-move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, 
+move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v,
 	       int rowPixels, unsigned char * rgb, int bits)
 {
 	const int rvScale = 91881;
@@ -3229,14 +3126,14 @@
 		rgb[5] = LIMIT(r+yBR);
 	} else if (bits == 16) {
 		/* Write out top two pixels */
-		rgb[0] = ((LIMIT(b+yTL) >> 3) & 0x1F) 
+		rgb[0] = ((LIMIT(b+yTL) >> 3) & 0x1F)
 			| ((LIMIT(g+yTL) << 3) & 0xE0);
 		rgb[1] = ((LIMIT(g+yTL) >> 5) & 0x07)
 			| (LIMIT(r+yTL) & 0xF8);
 
-		rgb[2] = ((LIMIT(b+yTR) >> 3) & 0x1F) 
+		rgb[2] = ((LIMIT(b+yTR) >> 3) & 0x1F)
 			| ((LIMIT(g+yTR) << 3) & 0xE0);
-		rgb[3] = ((LIMIT(g+yTR) >> 5) & 0x07) 
+		rgb[3] = ((LIMIT(g+yTR) >> 5) & 0x07)
 			| (LIMIT(r+yTR) & 0xF8);
 
 		/* Skip down to next line to write out bottom two pixels */
@@ -3263,7 +3160,7 @@
 /* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the
  * image at pOut is specified by w.
  */
-static inline void 
+static inline void
 make_8x8(unsigned char *pIn, unsigned char *pOut, int w)
 {
 	unsigned char *pOut1 = pOut;
@@ -3276,7 +3173,6 @@
 		}
 		pOut += w;
 	}
-		
 }
 
 /*
@@ -3394,7 +3290,7 @@
  * low, and the blue channel about 1 pixel high. After YUV->RGB
  * conversion, we can correct this easily. OSL 2/24/2000.
  */
-static void 
+static void
 fixFrameRGBoffset(struct ov511_frame *frame)
 {
 	int x, y;
@@ -3403,7 +3299,7 @@
 	const int shift = 1;  /* Distance to shift pixels by, vertically */
 
 	/* Don't bother with little images */
-	if (frame->width < 400) 
+	if (frame->width < 400)
 		return;
 
 	/* This only works with RGB24 */
@@ -3437,7 +3333,7 @@
  * accordingly. Returns -ENXIO if decompressor is not available, otherwise
  * returns 0 if no other error.
  */
-static int 
+static int
 request_decompressor(struct usb_ov511 *ov)
 {
 	if (!ov)
@@ -3476,24 +3372,24 @@
 	}
 
 	if (ov->decomp_ops) {
-		if (!ov->decomp_ops->decomp_lock) {
+		if (!ov->decomp_ops->owner) {
 			ov->decomp_ops = NULL;
 			unlock_kernel();
 			return -ENOSYS;
 		}
-		ov->decomp_ops->decomp_lock();
+		__MOD_INC_USE_COUNT(ov->decomp_ops->owner);
 		unlock_kernel();
 		return 0;
 	} else {
 		unlock_kernel();
-		return -ENXIO;
+		return -ENOSYS;
 	}
 }
 
 /* Unlocks decompression module and nulls ov->decomp_ops. Safe to call even
  * if ov->decomp_ops is NULL.
  */
-static void 
+static void
 release_decompressor(struct usb_ov511 *ov)
 {
 	int released = 0;	/* Did we actually do anything? */
@@ -3503,20 +3399,20 @@
 
 	lock_kernel();
 
-	if (ov->decomp_ops && ov->decomp_ops->decomp_unlock) {
-		ov->decomp_ops->decomp_unlock();
+	if (ov->decomp_ops && ov->decomp_ops->owner) {
+		__MOD_DEC_USE_COUNT(ov->decomp_ops->owner);
 		released = 1;
 	}
 
 	ov->decomp_ops = NULL;
-	
+
 	unlock_kernel();
 
 	if (released)
 		PDEBUG(3, "Decompressor released");
 }
 
-static void 
+static void
 decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
 	   unsigned char *pIn0, unsigned char *pOut0)
 {
@@ -3526,19 +3422,22 @@
 
 	PDEBUG(4, "Decompressing %d bytes", frame->bytes_recvd);
 
-	if (frame->format == VIDEO_PALETTE_GREY 
+	if (frame->format == VIDEO_PALETTE_GREY
 	    && ov->decomp_ops->decomp_400) {
 		int ret = ov->decomp_ops->decomp_400(
 			pIn0,
 			pOut0,
+			frame->compbuf,
 			frame->rawwidth,
 			frame->rawheight,
 			frame->bytes_recvd);
 		PDEBUG(4, "DEBUG: decomp_400 returned %d", ret);
-	} else if (ov->decomp_ops->decomp_420) {
+	} else if (frame->format != VIDEO_PALETTE_GREY
+		   && ov->decomp_ops->decomp_420) {
 		int ret = ov->decomp_ops->decomp_420(
 			pIn0,
 			pOut0,
+			frame->compbuf,
 			frame->rawwidth,
 			frame->rawheight,
 			frame->bytes_recvd);
@@ -3555,7 +3454,7 @@
  **********************************************************************/
 
 /* Converts from planar YUV420 to RGB24. */
-static void 
+static void
 yuv420p_to_rgb(struct ov511_frame *frame,
 	       unsigned char *pIn0, unsigned char *pOut0, int bits)
 {
@@ -3578,10 +3477,9 @@
 
 			move_420_block(y00, y01, y10, y11, u, v,
 				       frame->width, pOut, bits);
-	
+
 			pY += 2;
 			pOut += 2 * bytes;
-
 		}
 		pY += frame->width;
 		pOut += frame->width * bytes;
@@ -3610,7 +3508,7 @@
 		for (i = 0; i <= frame->width - 2; i += 2) {
 			int u = *pU++;
 			int v = *pV++;
-			
+
 			*pOut = u;
 			*(pOut+2) = v;
 			*(pOut+frame->width*2) = u;
@@ -3725,27 +3623,11 @@
 	}
 }
 
-/* Post-processes the specified frame. This consists of:
- * 	1. Decompress frame, if necessary
- *	2. Deinterlace frame and scale to proper size, if necessary
- * 	3. Convert from YUV planar to destination format, if necessary
- * 	4. Fix the RGB offset, if necessary
- */
-static void 
-ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
+static void
+ov51x_postprocess_grey(struct usb_ov511 *ov, struct ov511_frame *frame)
 {
-	if (dumppix) {
-		memset(frame->data, 0, 
-			MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
-		PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd);
-		memmove(frame->data, frame->rawdata, frame->bytes_recvd);
-		return;
-	}
-
-	/* YUV400 must be handled separately */
-	if (frame->format == VIDEO_PALETTE_GREY) {
 		/* Deinterlace frame, if necessary */
-		if (ov->sensor == SEN_SAA7111A && frame->rawheight == 480) {
+		if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
 			if (frame->compressed)
 				decompress(ov, frame, frame->rawdata,
 						 frame->tempdata);
@@ -3763,19 +3645,23 @@
 				yuv400raw_to_yuv400p(frame, frame->rawdata,
 						     frame->data);
 		}
+}
 
-		return;
-	}
-
-	/* Process frame->data to frame->rawdata */
+/* Process raw YUV420 data into the format requested by the app. Conversion
+ * between V4L formats is allowed.
+ */
+static void
+ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame)
+{
+	/* Process frame->rawdata to frame->tempdata */
 	if (frame->compressed)
 		decompress(ov, frame, frame->rawdata, frame->tempdata);
 	else
 		yuv420raw_to_yuv420p(frame, frame->rawdata, frame->tempdata);
 
 	/* Deinterlace frame, if necessary */
-	if (ov->sensor == SEN_SAA7111A && frame->rawheight == 480) {
-		memmove(frame->rawdata, frame->tempdata,
+	if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
+		memcpy(frame->rawdata, frame->tempdata,
 			MAX_RAW_DATA_SIZE(frame->width, frame->height));
 		deinterlace(frame, RAWFMT_YUV420, frame->rawdata,
 		            frame->tempdata);
@@ -3784,11 +3670,6 @@
 	/* Frame should be (width x height) and not (rawwidth x rawheight) at
          * this point. */
 
-#if 0
-	/* Clear output buffer for testing purposes */
-	memset(frame->data, 0, MAX_DATA_SIZE(frame->width, frame->height));
-#endif
-
 	/* Process frame->tempdata to frame->data */
 	switch (frame->format) {
 	case VIDEO_PALETTE_RGB565:
@@ -3803,348 +3684,124 @@
 		break;
 	case VIDEO_PALETTE_YUV420:
 	case VIDEO_PALETTE_YUV420P:
-		memmove(frame->data, frame->tempdata,
+		memcpy(frame->data, frame->tempdata,
 			MAX_RAW_DATA_SIZE(frame->width, frame->height));
 		break;
 	case VIDEO_PALETTE_YUV422P:
 		/* Data is converted in place, so copy it in advance */
-		memmove(frame->data, frame->tempdata,
+		memcpy(frame->data, frame->tempdata,
 			MAX_RAW_DATA_SIZE(frame->width, frame->height));
 
 		yuv420p_to_yuv422p(frame, frame->data);
 		break;
 	default:
-		err("Cannot convert data to this format");
+		err("Cannot convert YUV420 to %s",
+		    symbolic(v4l1_plist, frame->format));
 	}
 
 	if (fix_rgb_offset)
 		fixFrameRGBoffset(frame);
 }
 
-/**********************************************************************
- *
- * OV51x data transfer, IRQ handler
- *
- **********************************************************************/
-
-static int 
-ov511_move_data(struct usb_ov511 *ov, struct urb *urb)
+/* Post-processes the specified frame. This consists of:
+ * 	1. Decompress frame, if necessary
+ *	2. Deinterlace frame and scale to proper size, if necessary
+ * 	3. Convert from YUV planar to destination format, if necessary
+ * 	4. Fix the RGB offset, if necessary
+ */
+static void
+ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
 {
-	unsigned char *cdata;
-	int data_size, num, offset, i, totlen = 0;
-	int aPackNum[FRAMES_PER_DESC];
-	struct ov511_frame *frame;
-	struct timeval *ts;
-
-	PDEBUG(5, "Moving %d packets", urb->number_of_packets);
-
-	data_size = ov->packet_size - 1;
-
-	for (i = 0; i < urb->number_of_packets; i++) {
-		int n = urb->iso_frame_desc[i].actual_length;
-		int st = urb->iso_frame_desc[i].status;
-
-		urb->iso_frame_desc[i].actual_length = 0;
-		urb->iso_frame_desc[i].status = 0;
-
-		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
-		aPackNum[i] = n ? cdata[ov->packet_size - 1] : -1;
-
-		if (!n || ov->curframe == -1)
-			continue;
-
-		if (st)
-			PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st);
-
-		frame = &ov->frame[ov->curframe];
-
-		/* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
-		 * byte non-zero. The EOF packet has image width/height in the
-		 * 10th and 11th bytes. The 9th byte is given as follows:
-		 *
-		 * bit 7: EOF
-		 *     6: compression enabled
-		 *     5: 422/420/400 modes
-		 *     4: 422/420/400 modes
-		 *     3: 1
-		 *     2: snapshot button on
-		 *     1: snapshot frame
-		 *     0: even/odd field
-		 */
-
-		if (printph) {
-			info("packet header (%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
-				cdata[ov->packet_size - 1],
-				cdata[0], cdata[1], cdata[2], cdata[3], cdata[4], cdata[5],
-				cdata[6], cdata[7], cdata[8], cdata[9], cdata[10], cdata[11]);
-		}
-
-		/* Check for SOF/EOF packet */
-		if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] |
-		     cdata[4] | cdata[5] | cdata[6] | cdata[7]) ||
-		     (~cdata[8] & 0x08))
-			goto check_middle;
-
-		/* Frame end */
-		if (cdata[8] & 0x80) {
-			ts = (struct timeval *)(frame->data 
-			      + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
-			do_gettimeofday(ts);
-
-			/* Get the actual frame size from the EOF header */
-			frame->rawwidth = ((int)(cdata[9]) + 1) * 8;
-			frame->rawheight = ((int)(cdata[10]) + 1) * 8;
-
-	 		PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d, recvd=%d",
-				ov->curframe,
-				(int)(cdata[ov->packet_size - 1]),
-				frame->rawwidth,
-				frame->rawheight,
-				frame->bytes_recvd);
-
-			/* Validate the header data */
-			RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
-			RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
-
-			/* Don't allow byte count to exceed buffer size */
-			RESTRICT_TO_RANGE(frame->bytes_recvd,
-					  8, 
-					  MAX_RAW_DATA_SIZE(ov->maxwidth,
-					                    ov->maxheight));
-
-			if (frame->scanstate == STATE_LINES) {
-		    		int iFrameNext;
-
-				frame->grabstate = FRAME_DONE;	// FIXME: Is this right?
-
-				if (waitqueue_active(&frame->wq)) {
-					frame->grabstate = FRAME_DONE;
-					wake_up_interruptible(&frame->wq);
-				}
-
-				/* If next frame is ready or grabbing,
-                                 * point to it */
-				iFrameNext = (ov->curframe + 1) % OV511_NUMFRAMES;
-				if (ov->frame[iFrameNext].grabstate == FRAME_READY
-				    || ov->frame[iFrameNext].grabstate == FRAME_GRABBING) {
-					ov->curframe = iFrameNext;
-					ov->frame[iFrameNext].scanstate = STATE_SCANNING;
-				} else {
-					if (frame->grabstate == FRAME_DONE) {
-						PDEBUG(4, "Frame done! congratulations");
-					} else {
-						PDEBUG(4, "Frame not ready? state = %d",
-							ov->frame[iFrameNext].grabstate);
-					}
-
-					ov->curframe = -1;
-				}
-			} else {
-				PDEBUG(5, "Frame done, but not scanning");
-			}
-			/* Image corruption caused by misplaced frame->segment = 0
-			 * fixed by carlosf@conectiva.com.br
-			 */
-		} else {
-			/* Frame start */
-			PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
-
-			/* Check to see if it's a snapshot frame */
-			/* FIXME?? Should the snapshot reset go here? Performance? */
-			if (cdata[8] & 0x02) {
-				frame->snapshot = 1;
-				PDEBUG(3, "snapshot detected");
-			}
-
-			frame->scanstate = STATE_LINES;
-			frame->bytes_recvd = 0;
-			frame->compressed = cdata[8] & 0x40;
-		}
-
-check_middle:
-		/* Are we in a frame? */
-		if (frame->scanstate != STATE_LINES) {
-			PDEBUG(5, "Not in a frame; packet skipped");
-			continue;
-		}
-
-#if 0
-		/* Skip packet if first 9 bytes are zero. These are common, so
-		 * we use a less expensive test here instead of later */
-		if (frame->compressed) {
-			int b, skip = 1;
-
-			for (b = 0; b < 9; b++) { 
-				if (cdata[b])
-					skip=0;
-			}
-
-			if (skip) {
-				PDEBUG(5, "Skipping packet (all zero)");
-				continue;
-			}
-		}
-#endif
-		/* If frame start, skip header */
-		if (frame->bytes_recvd == 0)
-			offset = 9;
-		else
-			offset = 0;
-
-		num = n - offset - 1;
-
-		/* Dump all data exactly as received */
-		if (dumppix == 2) {
-			frame->bytes_recvd += n - 1;
-			if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight))
-				memmove(frame->rawdata + frame->bytes_recvd - (n - 1),
-					&cdata[0], n - 1);
-			else
-				PDEBUG(3, "Raw data buffer overrun!! (%d)",
-					frame->bytes_recvd
-					- MAX_RAW_DATA_SIZE(ov->maxwidth,
-							    ov->maxheight));
-		} else if (!frame->compressed && !remove_zeros) {
-			frame->bytes_recvd += num;
-			if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight))
-				memmove(frame->rawdata + frame->bytes_recvd - num,
-					&cdata[offset], num);
-			else
-				PDEBUG(3, "Raw data buffer overrun!! (%d)",
-					frame->bytes_recvd
-					- MAX_RAW_DATA_SIZE(ov->maxwidth,
-							    ov->maxheight));
-		} else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
-			int b, in = 0, allzero, copied=0;
-			if (offset) {
-				frame->bytes_recvd += 32 - offset;	// Bytes out
-				memmove(frame->rawdata,
-					&cdata[offset], 32 - offset);
-				in += 32;
-			}
-
-			while (in < n - 1) {
-				allzero = 1;
-				for (b = 0; b < 32; b++) {
-					if (cdata[in + b]) {
-						allzero = 0;
-						break;
-					}
-				}
-
-				if (allzero) {
-					/* Don't copy it */
-				} else {
-					if (frame->bytes_recvd + copied + 32
-					    <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) {
-						memmove(frame->rawdata + frame->bytes_recvd + copied,
-							&cdata[in], 32);
-						copied += 32;
-					} else {
-						PDEBUG(3, "Raw data buffer overrun!!");
-					}
-				}
-				in += 32;
-			}
-
-			frame->bytes_recvd += copied;
+	if (dumppix) {
+		memset(frame->data, 0,
+			MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
+		PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd);
+		memcpy(frame->data, frame->rawdata, frame->bytes_recvd);
+	} else {
+		switch (frame->format) {
+		case VIDEO_PALETTE_GREY:
+			ov51x_postprocess_grey(ov, frame);
+			break;
+		case VIDEO_PALETTE_YUV420:
+		case VIDEO_PALETTE_YUV420P:
+		case VIDEO_PALETTE_RGB565:
+		case VIDEO_PALETTE_RGB24:
+		case VIDEO_PALETTE_YUV422:
+		case VIDEO_PALETTE_YUYV:
+		case VIDEO_PALETTE_YUV422P:
+			ov51x_postprocess_yuv420(ov, frame);
+			break;
+		default:
+			err("Cannot convert data to %s",
+			    symbolic(v4l1_plist, frame->format));
 		}
-
 	}
-
-	PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d",
-		aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4],
-		aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]);
-
-	return totlen;
 }
 
-static int 
-ov518_move_data(struct usb_ov511 *ov, struct urb *urb)
+/**********************************************************************
+ *
+ * OV51x data transfer, IRQ handler
+ *
+ **********************************************************************/
+
+static inline void
+ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
 {
-	unsigned char *cdata;
-	int i, data_size, totlen = 0;
-	struct ov511_frame *frame;
+	int num, offset;
+	int pnum = in[ov->packet_size - 1];		/* Get packet number */
+	int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
+	struct ov511_frame *frame = &ov->frame[ov->curframe];
 	struct timeval *ts;
 
-	PDEBUG(5, "Moving %d packets", urb->number_of_packets);
-
-	/* OV518(+) has no packet numbering */
-	data_size = ov->packet_size;
-
-	for (i = 0; i < urb->number_of_packets; i++) {
-		int n = urb->iso_frame_desc[i].actual_length;
-		int st = urb->iso_frame_desc[i].status;
-
-		urb->iso_frame_desc[i].actual_length = 0;
-		urb->iso_frame_desc[i].status = 0;
-
-		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
-		if (!n) {
-			PDEBUG(4, "Zero-length packet");
-			continue;
-		}
-
-		if (ov->curframe == -1) {
-			PDEBUG(4, "No frame currently active");
-			continue;
-		}
+	/* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
+	 * byte non-zero. The EOF packet has image width/height in the
+	 * 10th and 11th bytes. The 9th byte is given as follows:
+	 *
+	 * bit 7: EOF
+	 *     6: compression enabled
+	 *     5: 422/420/400 modes
+	 *     4: 422/420/400 modes
+	 *     3: 1
+	 *     2: snapshot button on
+	 *     1: snapshot frame
+	 *     0: even/odd field
+	 */
 
-		if (st)
-			PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st);
+	if (printph) {
+		info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
+		     pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
+		     in[7], in[8], in[9], in[10], in[11]);
+	}
 
-		frame = &ov->frame[ov->curframe];
+	/* Check for SOF/EOF packet */
+	if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) ||
+	    (~in[8] & 0x08))
+		goto check_middle;
 
-		if (printph) {
-			info("packet header: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
-				cdata[0], cdata[1], cdata[2], cdata[3], cdata[4], cdata[5],
-				cdata[6], cdata[7], cdata[8], cdata[9], cdata[10], cdata[11]);
-		}
-
-		/* A false positive here is likely, until OVT gives me
-		 * the definitive SOF/EOF format */
-		if ((!(cdata[0] | cdata[1] | cdata[2] | cdata[3] |
-		      cdata[5])) && cdata[6]) {
-			
-			if (frame->scanstate == STATE_LINES) {
-				PDEBUG(4, "Detected frame end/start");
-				goto eof;
-			} else { //scanstate == STATE_SCANNING
-				/* Frame start */
-				PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
-				goto sof;
-			}
-		} else {
-			goto check_middle;
-		}
-	
-eof:
+	/* Frame end */
+	if (in[8] & 0x80) {
 		ts = (struct timeval *)(frame->data
 		      + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
 		do_gettimeofday(ts);
 
- 		PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d",
-			ov->curframe,
-			(int)(cdata[9]), (int)(cdata[10]), frame->bytes_recvd);
-
-		// FIXME: Since we don't know the header formats yet,
-		// there is no way to know what the actual image size is
-		frame->rawwidth = frame->width;
-		frame->rawheight = frame->height;
+		/* Get the actual frame size from the EOF header */
+		frame->rawwidth = ((int)(in[9]) + 1) * 8;
+		frame->rawheight = ((int)(in[10]) + 1) * 8;
+
+ 		PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d",
+			ov->curframe, pnum, frame->rawwidth, frame->rawheight,
+			frame->bytes_recvd);
 
 		/* Validate the header data */
 		RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
-		RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
+		RESTRICT_TO_RANGE(frame->rawheight, ov->minheight,
+				  ov->maxheight);
 
 		/* Don't allow byte count to exceed buffer size */
-		RESTRICT_TO_RANGE(frame->bytes_recvd,
-				  8, 
-				  MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight));
+		RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
 
 		if (frame->scanstate == STATE_LINES) {
-	    		int iFrameNext;
+	    		int nextf;
 
 			frame->grabstate = FRAME_DONE;	// FIXME: Is this right?
 
@@ -4155,115 +3812,280 @@
 
 			/* If next frame is ready or grabbing,
 			 * point to it */
-			iFrameNext = (ov->curframe + 1) % OV511_NUMFRAMES;
-			if (ov->frame[iFrameNext].grabstate == FRAME_READY
-			    || ov->frame[iFrameNext].grabstate == FRAME_GRABBING) {
-				ov->curframe = iFrameNext;
-				ov->frame[iFrameNext].scanstate = STATE_SCANNING;
-				frame = &ov->frame[iFrameNext];
+			nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
+			if (ov->frame[nextf].grabstate == FRAME_READY
+			    || ov->frame[nextf].grabstate == FRAME_GRABBING) {
+				ov->curframe = nextf;
+				ov->frame[nextf].scanstate = STATE_SCANNING;
 			} else {
 				if (frame->grabstate == FRAME_DONE) {
-					PDEBUG(4, "Frame done! congratulations");
+					PDEBUG(4, "** Frame done **");
 				} else {
 					PDEBUG(4, "Frame not ready? state = %d",
-						ov->frame[iFrameNext].grabstate);
+						ov->frame[nextf].grabstate);
 				}
 
 				ov->curframe = -1;
-				PDEBUG(4, "SOF dropped (no active frame)");
-				continue;  /* Nowhere to store this frame */
 			}
+		} else {
+			PDEBUG(5, "Frame done, but not scanning");
 		}
 		/* Image corruption caused by misplaced frame->segment = 0
 		 * fixed by carlosf@conectiva.com.br
 		 */
-sof:
-		PDEBUG(4, "Starting capture on frame %d", frame->framenum);
-// Snapshot not reverse-engineered yet.
-#if 0
+	} else {
+		/* Frame start */
+		PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
+
 		/* Check to see if it's a snapshot frame */
 		/* FIXME?? Should the snapshot reset go here? Performance? */
-		if (cdata[8] & 0x02) {
+		if (in[8] & 0x02) {
 			frame->snapshot = 1;
 			PDEBUG(3, "snapshot detected");
 		}
-#endif
+
 		frame->scanstate = STATE_LINES;
 		frame->bytes_recvd = 0;
-//		frame->compressed = 1;
+		frame->compressed = in[8] & 0x40;
+	}
 
 check_middle:
-		/* Are we in a frame? */
-		if (frame->scanstate != STATE_LINES) {
-			PDEBUG(4, "scanstate: no SOF yet");
-			continue;
-		}
+	/* Are we in a frame? */
+	if (frame->scanstate != STATE_LINES) {
+		PDEBUG(5, "Not in a frame; packet skipped");
+		return;
+	}
 
-		/* Dump all data exactly as received */
-		if (dumppix == 2) {
-			frame->bytes_recvd += n;
-			if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight))
-				memmove(frame->rawdata + frame->bytes_recvd - n,
-					&cdata[0], n);
-			else
-				PDEBUG(3, "Raw data buffer overrun!! (%d)",
-					frame->bytes_recvd
-					- MAX_RAW_DATA_SIZE(ov->maxwidth,
-							    ov->maxheight));
-		} else {
-			/* All incoming data are divided into 8-byte segments. If the
-			 * segment contains all zero bytes, it must be skipped. These
-			 * zero-segments allow the OV518 to mainain a constant data rate
-			 * regardless of the effectiveness of the compression. Segments
-			 * are aligned relative to the beginning of each isochronous
-			 * packet. The first segment is a header (the decompressor
-			 * skips it later).
-			 */
-
-			int b, in = 0, allzero, copied=0;
-
-			while (in < n) {
-				allzero = 1;
-				for (b = 0; b < 8; b++) {
-					if (cdata[in + b]) {
-						allzero = 0;
-						break;
-					}
+	/* If frame start, skip header */
+	if (frame->bytes_recvd == 0)
+		offset = 9;
+	else
+		offset = 0;
+
+	num = n - offset - 1;
+
+	/* Dump all data exactly as received */
+	if (dumppix == 2) {
+		frame->bytes_recvd += n - 1;
+		if (frame->bytes_recvd <= max_raw)
+			memcpy(frame->rawdata + frame->bytes_recvd - (n - 1),
+				in, n - 1);
+		else
+			PDEBUG(3, "Raw data buffer overrun!! (%d)",
+				frame->bytes_recvd - max_raw);
+	} else if (!frame->compressed && !remove_zeros) {
+		frame->bytes_recvd += num;
+		if (frame->bytes_recvd <= max_raw)
+			memcpy(frame->rawdata + frame->bytes_recvd - num,
+				in + offset, num);
+		else
+			PDEBUG(3, "Raw data buffer overrun!! (%d)",
+				frame->bytes_recvd - max_raw);
+	} else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
+		int b, read = 0, allzero, copied = 0;
+		if (offset) {
+			frame->bytes_recvd += 32 - offset;	// Bytes out
+			memcpy(frame->rawdata,	in + offset, 32 - offset);
+			read += 32;
+		}
+
+		while (read < n - 1) {
+			allzero = 1;
+			for (b = 0; b < 32; b++) {
+				if (in[read + b]) {
+					allzero = 0;
+					break;
 				}
+			}
 
-				if (allzero) {
+			if (allzero) {
 				/* Don't copy it */
+			} else {
+				if (frame->bytes_recvd + copied + 32 <= max_raw)
+				{
+					memcpy(frame->rawdata
+						+ frame->bytes_recvd + copied,
+						in + read, 32);
+					copied += 32;
 				} else {
-					if (frame->bytes_recvd + copied + 8
-					    <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) {
-						memmove(frame->rawdata + frame->bytes_recvd + copied,
-							&cdata[in], 8);
-						copied += 8;
-					} else {
-						PDEBUG(3, "Raw data buffer overrun!!");
-					}
+					PDEBUG(3, "Raw data buffer overrun!!");
 				}
-				in += 8;
 			}
-			frame->bytes_recvd += copied;
+			read += 32;
 		}
+
+		frame->bytes_recvd += copied;
 	}
+}
 
-	return totlen;
+static inline void
+ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
+{
+	int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
+	struct ov511_frame *frame = &ov->frame[ov->curframe];
+	struct timeval *ts;
+
+	/* Don't copy the packet number byte */
+	if (ov->packet_numbering)
+		--n;
+
+	/* A false positive here is likely, until OVT gives me
+	 * the definitive SOF/EOF format */
+	if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) {
+		if (printph) {
+			info("ph: %2x %2x %2x %2x %2x %2x %2x %2x", in[0],
+			     in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
+		}
+
+		if (frame->scanstate == STATE_LINES) {
+			PDEBUG(4, "Detected frame end/start");
+			goto eof;
+		} else { //scanstate == STATE_SCANNING
+			/* Frame start */
+			PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
+			goto sof;
+		}
+	} else {
+		goto check_middle;
+	}
+
+eof:
+	ts = (struct timeval *)(frame->data
+	      + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
+	do_gettimeofday(ts);
+
+	PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d",
+		ov->curframe,
+		(int)(in[9]), (int)(in[10]), frame->bytes_recvd);
+
+	// FIXME: Since we don't know the header formats yet,
+	// there is no way to know what the actual image size is
+	frame->rawwidth = frame->width;
+	frame->rawheight = frame->height;
+
+	/* Validate the header data */
+	RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
+	RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
+
+	/* Don't allow byte count to exceed buffer size */
+	RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
+
+	if (frame->scanstate == STATE_LINES) {
+    		int nextf;
+
+		frame->grabstate = FRAME_DONE;	// FIXME: Is this right?
+
+		if (waitqueue_active(&frame->wq)) {
+			frame->grabstate = FRAME_DONE;
+			wake_up_interruptible(&frame->wq);
+		}
+
+		/* If next frame is ready or grabbing,
+		 * point to it */
+		nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
+		if (ov->frame[nextf].grabstate == FRAME_READY
+		    || ov->frame[nextf].grabstate == FRAME_GRABBING) {
+			ov->curframe = nextf;
+			ov->frame[nextf].scanstate = STATE_SCANNING;
+			frame = &ov->frame[nextf];
+		} else {
+			if (frame->grabstate == FRAME_DONE) {
+				PDEBUG(4, "** Frame done **");
+			} else {
+				PDEBUG(4, "Frame not ready? state = %d",
+				       ov->frame[nextf].grabstate);
+			}
+
+			ov->curframe = -1;
+			PDEBUG(4, "SOF dropped (no active frame)");
+			return;  /* Nowhere to store this frame */
+		}
+	}
+sof:
+	PDEBUG(4, "Starting capture on frame %d", frame->framenum);
+
+// Snapshot not reverse-engineered yet.
+#if 0
+	/* Check to see if it's a snapshot frame */
+	/* FIXME?? Should the snapshot reset go here? Performance? */
+	if (in[8] & 0x02) {
+		frame->snapshot = 1;
+		PDEBUG(3, "snapshot detected");
+	}
+#endif
+	frame->scanstate = STATE_LINES;
+	frame->bytes_recvd = 0;
+	frame->compressed = 1;
+
+check_middle:
+	/* Are we in a frame? */
+	if (frame->scanstate != STATE_LINES) {
+		PDEBUG(4, "scanstate: no SOF yet");
+		return;
+	}
+
+	/* Dump all data exactly as received */
+	if (dumppix == 2) {
+		frame->bytes_recvd += n;
+		if (frame->bytes_recvd <= max_raw)
+			memcpy(frame->rawdata + frame->bytes_recvd - n, in, n);
+		else
+			PDEBUG(3, "Raw data buffer overrun!! (%d)",
+				frame->bytes_recvd - max_raw);
+	} else {
+		/* All incoming data are divided into 8-byte segments. If the
+		 * segment contains all zero bytes, it must be skipped. These
+		 * zero-segments allow the OV518 to mainain a constant data rate
+		 * regardless of the effectiveness of the compression. Segments
+		 * are aligned relative to the beginning of each isochronous
+		 * packet. The first segment in each image is a header (the
+		 * decompressor skips it later).
+		 */
+
+		int b, read = 0, allzero, copied = 0;
+
+		while (read < n) {
+			allzero = 1;
+			for (b = 0; b < 8; b++) {
+				if (in[read + b]) {
+					allzero = 0;
+					break;
+				}
+			}
+
+			if (allzero) {
+			/* Don't copy it */
+			} else {
+				if (frame->bytes_recvd + copied + 8 <= max_raw)
+				{
+					memcpy(frame->rawdata
+						+ frame->bytes_recvd + copied,
+						in + read, 8);
+					copied += 8;
+				} else {
+					PDEBUG(3, "Raw data buffer overrun!!");
+				}
+			}
+			read += 8;
+		}
+		frame->bytes_recvd += copied;
+	}
 }
 
-static void 
+static void
 ov51x_isoc_irq(struct urb *urb)
 {
-	int len;
+	int i;
 	struct usb_ov511 *ov;
+	struct ov511_sbuf *sbuf;
 
 	if (!urb->context) {
 		PDEBUG(4, "no context");
 		return;
 	}
 
-	ov = (struct usb_ov511 *) urb->context;
+	sbuf = urb->context;
+	ov = sbuf->ov;
 
 	if (!ov || !ov->dev || !ov->user) {
 		PDEBUG(4, "no device, or not open");
@@ -4275,16 +4097,51 @@
 		return;
 	}
 
+        if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
+                PDEBUG(4, "URB unlinked");
+                return;
+        }
+
+	if (urb->status != -EINPROGRESS && urb->status != 0) {
+		err("ERROR: urb->status=%d: %s", urb->status,
+		    symbolic(urb_errlist, urb->status));
+	}
+
 	/* Copy the data received into our frame buffer */
-	if (ov->curframe >= 0) {
-		if (ov->bclass == BCL_OV511)
-			len = ov511_move_data(ov, urb);
-		else if (ov->bclass == BCL_OV518)
-			len = ov518_move_data(ov, urb);
-		else
-			err("Unknown bridge device (%d)", ov->bridge);
-	} else if (waitqueue_active(&ov->wq)) {
-		wake_up_interruptible(&ov->wq);
+	PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n,
+	       urb->number_of_packets);
+	for (i = 0; i < urb->number_of_packets; i++) {
+		/* Warning: Don't call *_move_data() if no frame active! */
+		if (ov->curframe >= 0) {
+			int n = urb->iso_frame_desc[i].actual_length;
+			int st = urb->iso_frame_desc[i].status;
+			unsigned char *cdata;
+
+			urb->iso_frame_desc[i].actual_length = 0;
+			urb->iso_frame_desc[i].status = 0;
+
+			cdata = urb->transfer_buffer
+				+ urb->iso_frame_desc[i].offset;
+
+			if (!n) {
+				PDEBUG(4, "Zero-length packet");
+				continue;
+			}
+
+			if (st)
+				PDEBUG(2, "data error: [%d] len=%d, status=%d",
+				       i, n, st);
+
+			if (ov->bclass == BCL_OV511)
+				ov511_move_data(ov, cdata, n);
+			else if (ov->bclass == BCL_OV518)
+				ov518_move_data(ov, cdata, n);
+			else
+				err("Unknown bridge device (%d)", ov->bridge);
+
+		} else if (waitqueue_active(&ov->wq)) {
+			wake_up_interruptible(&ov->wq);
+		}
 	}
 
 	urb->dev = ov->dev;
@@ -4298,7 +4155,7 @@
  *
  ***************************************************************************/
 
-static int 
+static int
 ov51x_init_isoc(struct usb_ov511 *ov)
 {
 	struct urb *urb;
@@ -4340,27 +4197,32 @@
 		return -1;
 	}
 
-	if (packetsize == -1) {
-		// FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now
-		if (ov->bclass == BCL_OV518)
-			ov51x_set_packet_size(ov, 640);
-		else
-			ov51x_set_packet_size(ov, size);
+	// FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now
+	if (ov->bclass == BCL_OV518) {
+		if (packetsize == -1) {
+			ov518_set_packet_size(ov, 640);
+		} else {
+			info("Forcing packet size to %d", packetsize);
+			ov518_set_packet_size(ov, packetsize);
+		}
 	} else {
+		if (packetsize == -1) {
+			ov511_set_packet_size(ov, size);
+		} else {
 			info("Forcing packet size to %d", packetsize);
-			ov51x_set_packet_size(ov, packetsize);
+			ov511_set_packet_size(ov, packetsize);
+		}
 	}
 
 	for (n = 0; n < OV511_NUMSBUF; n++) {
 		urb = usb_alloc_urb(FRAMES_PER_DESC);
-	
 		if (!urb) {
 			err("init isoc: usb_alloc_urb ret. NULL");
 			return -ENOMEM;
 		}
 		ov->sbuf[n].urb = urb;
 		urb->dev = ov->dev;
-		urb->context = ov;
+		urb->context = &ov->sbuf[n];
 		urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS);
 		urb->transfer_flags = USB_ISO_ASAP;
 		urb->transfer_buffer = ov->sbuf[n].data;
@@ -4382,31 +4244,23 @@
 	for (n = 0; n < OV511_NUMSBUF; n++) {
 		ov->sbuf[n].urb->dev = ov->dev;
 		err = usb_submit_urb(ov->sbuf[n].urb);
-		if (err)
+		if (err) {
 			err("init isoc: usb_submit_urb(%d) ret %d", n, err);
+			return err;
+		}
 	}
 
 	return 0;
 }
 
-static void 
-ov51x_stop_isoc(struct usb_ov511 *ov)
+static void
+ov51x_unlink_isoc(struct usb_ov511 *ov)
 {
 	int n;
 
-	if (!ov->streaming || !ov->dev)
-		return;
-
-	PDEBUG(3, "*** Stopping capture ***");
-
-	ov51x_set_packet_size(ov, 0);
-
-	ov->streaming = 0;
-
 	/* Unschedule all of the iso td's */
 	for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
 		if (ov->sbuf[n].urb) {
-			ov->sbuf[n].urb->next = NULL;
 			usb_unlink_urb(ov->sbuf[n].urb);
 			usb_free_urb(ov->sbuf[n].urb);
 			ov->sbuf[n].urb = NULL;
@@ -4414,7 +4268,25 @@
 	}
 }
 
-static int 
+static void
+ov51x_stop_isoc(struct usb_ov511 *ov)
+{
+	if (!ov->streaming || !ov->dev)
+		return;
+
+	PDEBUG(3, "*** Stopping capture ***");
+
+	if (ov->bclass == BCL_OV518)
+		ov518_set_packet_size(ov, 0);
+	else
+		ov511_set_packet_size(ov, 0);
+
+	ov->streaming = 0;
+
+	ov51x_unlink_isoc(ov);
+}
+
+static int
 ov51x_new_frame(struct usb_ov511 *ov, int framenum)
 {
 	struct ov511_frame *frame;
@@ -4436,7 +4308,7 @@
 
 	frame = &ov->frame[framenum];
 
-	PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum, 
+	PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum,
 	       frame->width, frame->height);
 
 	frame->grabstate = FRAME_GRABBING;
@@ -4465,172 +4337,133 @@
  *
  ***************************************************************************/
 
-static int 
-ov51x_alloc(struct usb_ov511 *ov)
+/*
+ * - You must acquire buf_lock before entering this function.
+ * - Because this code will free any non-null pointer, you must be sure to null
+ *   them if you explicitly free them somewhere else!
+ */
+static void
+ov51x_do_dealloc(struct usb_ov511 *ov)
 {
 	int i;
-	const int w = ov->maxwidth;
-	const int h = ov->maxheight;
-	const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h);
-	const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
-
 	PDEBUG(4, "entered");
-	down(&ov->buf_lock);
-
-	if (ov->buf_state == BUF_PEND_DEALLOC) {
-		ov->buf_state = BUF_ALLOCATED;
-		del_timer(&ov->buf_timer);
-	}
-
-	if (ov->buf_state == BUF_ALLOCATED)
-		goto out;
 
-	ov->fbuf = rvmalloc(data_bufsize);
-	if (!ov->fbuf)
-		goto error;
-
-	ov->rawfbuf = vmalloc(raw_bufsize);
-	if (!ov->rawfbuf) {
-		rvfree(ov->fbuf, data_bufsize);
+	if (ov->fbuf) {
+		rvfree(ov->fbuf, OV511_NUMFRAMES
+		       * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
 		ov->fbuf = NULL;
-		goto error;
 	}
-	memset(ov->rawfbuf, 0, raw_bufsize);
 
-	ov->tempfbuf = vmalloc(raw_bufsize);
-	if (!ov->tempfbuf) {
+	if (ov->rawfbuf) {
 		vfree(ov->rawfbuf);
 		ov->rawfbuf = NULL;
-		rvfree(ov->fbuf, data_bufsize);
-		ov->fbuf = NULL;
-		goto error;
 	}
-	memset(ov->tempfbuf, 0, raw_bufsize);
 
-	for (i = 0; i < OV511_NUMSBUF; i++) {
-		ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
-			MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
-		if (!ov->sbuf[i].data) {
-			while (--i) {
-				kfree(ov->sbuf[i].data);
-				ov->sbuf[i].data = NULL;
-			}
-			vfree(ov->tempfbuf);
-			ov->tempfbuf = NULL;
-			vfree(ov->rawfbuf);
-			ov->rawfbuf = NULL;
-			rvfree(ov->fbuf, data_bufsize);
-			ov->fbuf = NULL;
+	if (ov->tempfbuf) {
+		vfree(ov->tempfbuf);
+		ov->tempfbuf = NULL;
+	}
 
-			goto error;
+	for (i = 0; i < OV511_NUMSBUF; i++) {
+		if (ov->sbuf[i].data) {
+			kfree(ov->sbuf[i].data);
+			ov->sbuf[i].data = NULL;
 		}
-		PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data);
 	}
 
 	for (i = 0; i < OV511_NUMFRAMES; i++) {
-		ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h);
-		ov->frame[i].rawdata = ov->rawfbuf 
-		 + i * MAX_RAW_DATA_SIZE(w, h);
-		ov->frame[i].tempdata = ov->tempfbuf 
-		 + i * MAX_RAW_DATA_SIZE(w, h);
-		PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data);
+		ov->frame[i].data = NULL;
+		ov->frame[i].rawdata = NULL;
+		ov->frame[i].tempdata = NULL;
+		if (ov->frame[i].compbuf) {
+			free_page((unsigned long) ov->frame[i].compbuf);
+			ov->frame[i].compbuf = NULL;
+		}
 	}
 
-	ov->buf_state = BUF_ALLOCATED;
-out:
-	up(&ov->buf_lock);
-	PDEBUG(4, "leaving");
-	return 0;
-error:
+	PDEBUG(4, "buffer memory deallocated");
 	ov->buf_state = BUF_NOT_ALLOCATED;
-	up(&ov->buf_lock);
-	PDEBUG(4, "errored");
-	return -ENOMEM;
+	PDEBUG(4, "leaving");
 }
 
-/* 
- * - You must acquire buf_lock before entering this function.
- * - Because this code will free any non-null pointer, you must be sure to null
- *   them if you explicitly free them somewhere else!
- */
-static void 
-ov51x_do_dealloc(struct usb_ov511 *ov)
+static int
+ov51x_alloc(struct usb_ov511 *ov)
 {
 	int i;
+	const int w = ov->maxwidth;
+	const int h = ov->maxheight;
+	const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h);
+	const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
+
 	PDEBUG(4, "entered");
+	down(&ov->buf_lock);
 
-	if (ov->fbuf) {
-		rvfree(ov->fbuf, OV511_NUMFRAMES
-		       * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
-		ov->fbuf = NULL;
+	if (ov->buf_state == BUF_PEND_DEALLOC) {
+		ov->buf_state = BUF_ALLOCATED;
+		del_timer(&ov->buf_timer);
 	}
 
-	if (ov->rawfbuf) {
-		vfree(ov->rawfbuf);
-		ov->rawfbuf = NULL;
-	}
+	if (ov->buf_state == BUF_ALLOCATED)
+		goto out;
+
+	ov->fbuf = rvmalloc(data_bufsize);
+	if (!ov->fbuf)
+		goto error;
+
+	ov->rawfbuf = vmalloc(raw_bufsize);
+	if (!ov->rawfbuf)
+		goto error;
+
+	memset(ov->rawfbuf, 0, raw_bufsize);
 
-	if (ov->tempfbuf) {
-		vfree(ov->tempfbuf);
-		ov->tempfbuf = NULL;
-	}
+	ov->tempfbuf = vmalloc(raw_bufsize);
+	if (!ov->tempfbuf)
+		goto error;
+
+	memset(ov->tempfbuf, 0, raw_bufsize);
 
 	for (i = 0; i < OV511_NUMSBUF; i++) {
-		if (ov->sbuf[i].data) {
-			kfree(ov->sbuf[i].data);
-			ov->sbuf[i].data = NULL;
-		}
-	}
+		ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
+			MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
+		if (!ov->sbuf[i].data)
+			goto error;
 
-	for (i = 0; i < OV511_NUMFRAMES; i++) {
-		ov->frame[i].data = NULL;
-		ov->frame[i].rawdata = NULL;
-		ov->frame[i].tempdata = NULL;
+		PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data);
 	}
 
-	PDEBUG(4, "buffer memory deallocated");
-	ov->buf_state = BUF_NOT_ALLOCATED;
-	PDEBUG(4, "leaving");
-}
+	for (i = 0; i < OV511_NUMFRAMES; i++) {
+		ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h);
+		ov->frame[i].rawdata = ov->rawfbuf
+		 + i * MAX_RAW_DATA_SIZE(w, h);
+		ov->frame[i].tempdata = ov->tempfbuf
+		 + i * MAX_RAW_DATA_SIZE(w, h);
 
-static void 
-ov51x_buf_callback(unsigned long data)
-{
-	struct usb_ov511 *ov = (struct usb_ov511 *)data;
-	PDEBUG(4, "entered");
-	down(&ov->buf_lock);
+		ov->frame[i].compbuf =
+		 (unsigned char *) __get_free_page(GFP_KERNEL);
+		if (!ov->frame[i].compbuf)
+			goto error;
 
-	if (ov->buf_state == BUF_PEND_DEALLOC)
-		ov51x_do_dealloc(ov);
+		PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data);
+	}
 
+	ov->buf_state = BUF_ALLOCATED;
+out:
 	up(&ov->buf_lock);
 	PDEBUG(4, "leaving");
+	return 0;
+error:
+	ov51x_do_dealloc(ov);
+	up(&ov->buf_lock);
+	PDEBUG(4, "errored");
+	return -ENOMEM;
 }
 
-static void 
+static void
 ov51x_dealloc(struct usb_ov511 *ov, int now)
 {
-	struct timer_list *bt = &(ov->buf_timer);
 	PDEBUG(4, "entered");
 	down(&ov->buf_lock);
-
-	PDEBUG(4, "deallocating buffer memory %s", now ? "now" : "later");
-
-	if (ov->buf_state == BUF_PEND_DEALLOC) {
-		ov->buf_state = BUF_ALLOCATED;
-		del_timer(bt);
-	}
-
-	if (now)
-		ov51x_do_dealloc(ov);
-	else {
-		ov->buf_state = BUF_PEND_DEALLOC;
-		init_timer(bt);
-		bt->function = ov51x_buf_callback;
-		bt->data = (unsigned long)ov;
-		bt->expires = jiffies + buf_timeout * HZ;
-		add_timer(bt);
-	}
+	ov51x_do_dealloc(ov);
 	up(&ov->buf_lock);
 	PDEBUG(4, "leaving");
 }
@@ -4641,7 +4474,7 @@
  *
  ***************************************************************************/
 
-static int 
+static int
 ov51x_v4l1_open(struct video_device *vdev, int flags)
 {
 	struct usb_ov511 *ov = vdev->priv;
@@ -4652,17 +4485,18 @@
 	down(&ov->lock);
 
 	err = -EBUSY;
-	if (ov->user) 
+	if (ov->user)
 		goto out;
 
-	err = -ENOMEM;
-	if (ov51x_alloc(ov))
+	err = ov51x_alloc(ov);
+	if (err < 0)
 		goto out;
 
 	ov->sub_flag = 0;
 
 	/* In case app doesn't set them... */
-	if (ov51x_set_default_params(ov) < 0)
+	err = ov51x_set_default_params(ov);
+	if (err < 0)
 		goto out;
 
 	/* Make sure frames are reset */
@@ -4671,7 +4505,7 @@
 		ov->frame[i].bytes_read = 0;
 	}
 
-	/* If compression is on, make sure now that a 
+	/* If compression is on, make sure now that a
 	 * decompressor can be loaded */
 	if (ov->compress && !ov->decomp_ops) {
 		err = request_decompressor(ov);
@@ -4686,23 +4520,22 @@
 	}
 
 	ov->user++;
-	
+
 	if (ov->led_policy == LED_AUTO)
 		ov51x_led_control(ov, 1);
 
 out:
 	up(&ov->lock);
-
 	return err;
 }
 
-static void 
+static void
 ov51x_v4l1_close(struct video_device *vdev)
 {
 	struct usb_ov511 *ov = vdev->priv;
 
 	PDEBUG(4, "ov511_close");
-	
+
 	down(&ov->lock);
 
 	ov->user--;
@@ -4731,129 +4564,93 @@
 		kfree(ov);
 		ov = NULL;
 	}
-}
-
-static int 
-ov51x_v4l1_init_done(struct video_device *vdev)
-{
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
-	create_proc_ov511_cam(vdev->priv);
-#endif
-
-	return 0;
-}
 
-static long 
-ov51x_v4l1_write(struct video_device *vdev, const char *buf,
-		 unsigned long count, int noblock)
-{
-	return -EINVAL;
+	return;
 }
 
 /* Do not call this function directly! */
-static int 
-ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd,
+static int
+ov51x_v4l1_ioctl_internal(struct usb_ov511 *ov, unsigned int cmd,
 			  void *arg)
 {
-	struct usb_ov511 *ov = vdev->priv;
-
 	PDEBUG(5, "IOCtl: 0x%X", cmd);
 
 	if (!ov->dev)
-		return -EIO;	
+		return -EIO;
 
 	switch (cmd) {
 	case VIDIOCGCAP:
 	{
-		struct video_capability b;
+		struct video_capability *b = arg;
 
 		PDEBUG(4, "VIDIOCGCAP");
 
-		memset(&b, 0, sizeof(b));
-		sprintf(b.name, "%s USB Camera",
-			ov->bridge == BRG_OV511 ? "OV511" :
-			ov->bridge == BRG_OV511PLUS ? "OV511+" :
-			ov->bridge == BRG_OV518 ? "OV518" :
-			ov->bridge == BRG_OV518PLUS ? "OV518+" :
-			"unknown");
-		b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
-		if (ov->has_tuner)
-			b.type |= VID_TYPE_TUNER;
-		b.channels = ov->num_inputs;
-		b.audios = ov->has_audio_proc ? 1:0;
-		b.maxwidth = ov->maxwidth;
-		b.maxheight = ov->maxheight;
-		b.minwidth = ov->minwidth;
-		b.minheight = ov->minheight;
+		memset(b, 0, sizeof(struct video_capability));
+		sprintf(b->name, "%s USB Camera",
+			symbolic(brglist, ov->bridge));
+		b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
+		b->channels = ov->num_inputs;
+		b->audios = 0;
+		b->maxwidth = ov->maxwidth;
+		b->maxheight = ov->maxheight;
+		b->minwidth = ov->minwidth;
+		b->minheight = ov->minheight;
 
-		if (copy_to_user(arg, &b, sizeof(b)))
-			return -EFAULT;
-				
 		return 0;
 	}
 	case VIDIOCGCHAN:
 	{
-		struct video_channel v;
+		struct video_channel *v = arg;
 
 		PDEBUG(4, "VIDIOCGCHAN");
 
-		if (copy_from_user(&v, arg, sizeof(v)))
-			return -EFAULT;
-
-		if ((unsigned)(v.channel) >= ov->num_inputs) {
-			err("Invalid channel (%d)", v.channel);
+		if ((unsigned)(v->channel) >= ov->num_inputs) {
+			err("Invalid channel (%d)", v->channel);
 			return -EINVAL;
 		}
 
-		v.norm = ov->norm;
-		v.type = (ov->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA;
-		v.flags = (ov->has_tuner) ? VIDEO_VC_TUNER : 0;
-		v.flags |= (ov->has_audio_proc) ? VIDEO_VC_AUDIO : 0;
-//		v.flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
-		v.tuners = (ov->has_tuner) ? 1:0;
-		decoder_get_input_name(ov, v.channel, v.name);
+		v->norm = ov->norm;
+		v->type = VIDEO_TYPE_CAMERA;
+		v->flags = 0;
+//		v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
+		v->tuners = 0;
+		decoder_get_input_name(ov, v->channel, v->name);
 
-		if (copy_to_user(arg, &v, sizeof(v)))
-			return -EFAULT;
-				
 		return 0;
 	}
 	case VIDIOCSCHAN:
 	{
-		struct video_channel v;
+		struct video_channel *v = arg;
 		int err;
 
 		PDEBUG(4, "VIDIOCSCHAN");
 
-		if (copy_from_user(&v, arg, sizeof(v)))
-			return -EFAULT;
-
 		/* Make sure it's not a camera */
 		if (!ov->has_decoder) {
-			if (v.channel == 0)
+			if (v->channel == 0)
 				return 0;
 			else
 				return -EINVAL;
 		}
 
-		if (v.norm != VIDEO_MODE_PAL &&
-		    v.norm != VIDEO_MODE_NTSC &&
-		    v.norm != VIDEO_MODE_SECAM &&
-		    v.norm != VIDEO_MODE_AUTO) {
-			err("Invalid norm (%d)", v.norm);
+		if (v->norm != VIDEO_MODE_PAL &&
+		    v->norm != VIDEO_MODE_NTSC &&
+		    v->norm != VIDEO_MODE_SECAM &&
+		    v->norm != VIDEO_MODE_AUTO) {
+			err("Invalid norm (%d)", v->norm);
 			return -EINVAL;
 		}
 
-		if ((unsigned)(v.channel) >= ov->num_inputs) {
-			err("Invalid channel (%d)", v.channel);
+		if ((unsigned)(v->channel) >= ov->num_inputs) {
+			err("Invalid channel (%d)", v->channel);
 			return -EINVAL;
 		}
 
-		err = decoder_set_input(ov, v.channel);
+		err = decoder_set_input(ov, v->channel);
 		if (err)
 			return err;
 
-		err = decoder_set_norm(ov, v.norm);
+		err = decoder_set_norm(ov, v->norm);
 		if (err)
 			return err;
 
@@ -4861,43 +4658,37 @@
 	}
 	case VIDIOCGPICT:
 	{
-		struct video_picture p;
+		struct video_picture *p = arg;
 
 		PDEBUG(4, "VIDIOCGPICT");
 
-		memset(&p, 0, sizeof(p));
-
-		if (sensor_get_picture(ov, &p))
+		memset(p, 0, sizeof(struct video_picture));
+		if (sensor_get_picture(ov, p))
 			return -EIO;
 
-		if (copy_to_user(arg, &p, sizeof(p)))
-			return -EFAULT;
-
 		return 0;
 	}
 	case VIDIOCSPICT:
 	{
-		struct video_picture p;
+		struct video_picture *p = arg;
 		int i;
 
 		PDEBUG(4, "VIDIOCSPICT");
 
-		if (copy_from_user(&p, arg, sizeof(p)))
-			return -EFAULT;
-
-		if (!get_depth(p.palette))
+		if (!get_depth(p->palette))
 			return -EINVAL;
 
-		if (sensor_set_picture(ov, &p))
+		if (sensor_set_picture(ov, p))
 			return -EIO;
 
-		if (force_palette && p.palette != force_palette) {
-			info("Palette rejected (%d)", p.palette);
+		if (force_palette && p->palette != force_palette) {
+			info("Palette rejected (%s)",
+			     symbolic(v4l1_plist, p->palette));
 			return -EINVAL;
 		}
 
 		// FIXME: Format should be independent of frames
-		if (p.palette != ov->frame[0].format) {
+		if (p->palette != ov->frame[0].format) {
 			PDEBUG(4, "Detected format change");
 
 			/* If we're collecting previous frame wait
@@ -4906,79 +4697,73 @@
 			if (signal_pending(current)) return -EINTR;
 
 			mode_init_regs(ov, ov->frame[0].width,
-				ov->frame[0].height, p.palette, ov->sub_flag);
+				ov->frame[0].height, p->palette, ov->sub_flag);
 		}
 
-		PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette);
+		PDEBUG(4, "Setting depth=%d, palette=%s",
+		       p->depth, symbolic(v4l1_plist, p->palette));
+
 		for (i = 0; i < OV511_NUMFRAMES; i++) {
-			ov->frame[i].depth = p.depth;
-			ov->frame[i].format = p.palette;
+			ov->frame[i].depth = p->depth;
+			ov->frame[i].format = p->palette;
 		}
 
 		return 0;
 	}
 	case VIDIOCGCAPTURE:
 	{
-		int vf;
+		int *vf = arg;
 
 		PDEBUG(4, "VIDIOCGCAPTURE");
 
-		if (copy_from_user(&vf, arg, sizeof(vf)))
-			return -EFAULT;
-		ov->sub_flag = vf;
+		ov->sub_flag = *vf;
 		return 0;
 	}
 	case VIDIOCSCAPTURE:
 	{
-		struct video_capture vc;
+		struct video_capture *vc = arg;
 
 		PDEBUG(4, "VIDIOCSCAPTURE");
 
-		if (copy_from_user(&vc, arg, sizeof(vc)))
-			return -EFAULT;
-		if (vc.flags)
+		if (vc->flags)
 			return -EINVAL;
-		if (vc.decimation)
+		if (vc->decimation)
 			return -EINVAL;
 
-		vc.x &= ~3L;
-		vc.y &= ~1L;
-		vc.y &= ~31L;
-
-		if (vc.width == 0)
-			vc.width = 32;
-
-		vc.height /= 16;
-		vc.height *= 16;
-		if (vc.height == 0)
-			vc.height = 16;
-
-		ov->subx = vc.x;
-		ov->suby = vc.y;
-		ov->subw = vc.width;
-		ov->subh = vc.height;
+		vc->x &= ~3L;
+		vc->y &= ~1L;
+		vc->y &= ~31L;
+
+		if (vc->width == 0)
+			vc->width = 32;
+
+		vc->height /= 16;
+		vc->height *= 16;
+		if (vc->height == 0)
+			vc->height = 16;
+
+		ov->subx = vc->x;
+		ov->suby = vc->y;
+		ov->subw = vc->width;
+		ov->subh = vc->height;
 
 		return 0;
 	}
 	case VIDIOCSWIN:
 	{
-		struct video_window vw;
+		struct video_window *vw = arg;
 		int i, result;
 
-		if (copy_from_user(&vw, arg, sizeof(vw)))
-			return -EFAULT;
-
-		PDEBUG(4, "VIDIOCSWIN: width=%d, height=%d",
-			vw.width, vw.height);
+		PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height);
 
 #if 0
-		if (vw.flags)
+		if (vw->flags)
 			return -EINVAL;
-		if (vw.clipcount)
+		if (vw->clipcount)
 			return -EINVAL;
-		if (vw.height != ov->maxheight)
+		if (vw->height != ov->maxheight)
 			return -EINVAL;
-		if (vw.width != ov->maxwidth)
+		if (vw->width != ov->maxwidth)
 			return -EINVAL;
 #endif
 
@@ -4987,140 +4772,131 @@
 		interruptible_sleep_on(&ov->wq);
 		if (signal_pending(current)) return -EINTR;
 
-		result = mode_init_regs(ov, vw.width, vw.height,
+		result = mode_init_regs(ov, vw->width, vw->height,
 			ov->frame[0].format, ov->sub_flag);
 		if (result < 0)
 			return result;
 
 		for (i = 0; i < OV511_NUMFRAMES; i++) {
-			ov->frame[i].width = vw.width;
-			ov->frame[i].height = vw.height;
+			ov->frame[i].width = vw->width;
+			ov->frame[i].height = vw->height;
 		}
 
 		return 0;
 	}
 	case VIDIOCGWIN:
 	{
-		struct video_window vw;
-
-		memset(&vw, 0, sizeof(vw));
-		vw.x = 0;		/* FIXME */
-		vw.y = 0;
-		vw.width = ov->frame[0].width;
-		vw.height = ov->frame[0].height;
-		vw.flags = 30;
+		struct video_window *vw = arg;
 
-		PDEBUG(4, "VIDIOCGWIN: %dx%d", vw.width, vw.height);
+		memset(vw, 0, sizeof(struct video_window));
+		vw->x = 0;		/* FIXME */
+		vw->y = 0;
+		vw->width = ov->frame[0].width;
+		vw->height = ov->frame[0].height;
+		vw->flags = 30;
 
-		if (copy_to_user(arg, &vw, sizeof(vw)))
-			return -EFAULT;
+		PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height);
 
 		return 0;
 	}
 	case VIDIOCGMBUF:
 	{
-		struct video_mbuf vm;
+		struct video_mbuf *vm = arg;
 		int i;
 
 		PDEBUG(4, "VIDIOCGMBUF");
 
-		memset(&vm, 0, sizeof(vm));
-		vm.size = OV511_NUMFRAMES
-			* MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
-		vm.frames = OV511_NUMFRAMES;
+		memset(vm, 0, sizeof(struct video_mbuf));
+		vm->size = OV511_NUMFRAMES
+			   * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
+		vm->frames = OV511_NUMFRAMES;
 
-		vm.offsets[0] = 0;
+		vm->offsets[0] = 0;
 		for (i = 1; i < OV511_NUMFRAMES; i++) {
-			vm.offsets[i] = vm.offsets[i-1]
+			vm->offsets[i] = vm->offsets[i-1]
 			   + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
 		}
 
-		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
-			return -EFAULT;
-
 		return 0;
 	}
 	case VIDIOCMCAPTURE:
 	{
-		struct video_mmap vm;
+		struct video_mmap *vm = arg;
 		int ret, depth;
+		unsigned int f = vm->frame;
 
-		if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
-			return -EFAULT;
-
-		PDEBUG(4, "CMCAPTURE");
-		PDEBUG(4, "frame: %d, size: %dx%d, format: %d",
-			vm.frame, vm.width, vm.height, vm.format);
+		PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width,
+			vm->height, symbolic(v4l1_plist, vm->format));
 
-		depth = get_depth(vm.format);
+		depth = get_depth(vm->format);
 		if (!depth) {
-			err("VIDIOCMCAPTURE: invalid format (%d)", vm.format);
+			err("VIDIOCMCAPTURE: invalid format (%s)",
+			    symbolic(v4l1_plist, vm->format));
 			return -EINVAL;
 		}
 
-		if ((unsigned)vm.frame >= OV511_NUMFRAMES) {
-			err("VIDIOCMCAPTURE: invalid frame (%d)", vm.frame);
+		if (f >= OV511_NUMFRAMES) {
+			err("VIDIOCMCAPTURE: invalid frame (%d)", f);
 			return -EINVAL;
 		}
 
-		if (vm.width > ov->maxwidth 
-		    || vm.height > ov->maxheight) {
+		if (vm->width > ov->maxwidth
+		    || vm->height > ov->maxheight) {
 			err("VIDIOCMCAPTURE: requested dimensions too big");
 			return -EINVAL;
 		}
 
-		if (ov->frame[vm.frame].grabstate == FRAME_GRABBING) {
+		if (ov->frame[f].grabstate == FRAME_GRABBING) {
 			PDEBUG(4, "VIDIOCMCAPTURE: already grabbing");
 			return -EBUSY;
 		}
 
-		if (force_palette && vm.format != force_palette) {
-			info("palette rejected (%d)", vm.format);
+		if (force_palette && (vm->format != force_palette)) {
+			info("palette rejected (%s)",
+			     symbolic(v4l1_plist, vm->format));
 			return -EINVAL;
 		}
 
-		if ((ov->frame[vm.frame].width != vm.width) ||
-		    (ov->frame[vm.frame].height != vm.height) ||
-		    (ov->frame[vm.frame].format != vm.format) ||
-		    (ov->frame[vm.frame].sub_flag != ov->sub_flag) ||
-		    (ov->frame[vm.frame].depth != depth)) {
+		if ((ov->frame[f].width != vm->width) ||
+		    (ov->frame[f].height != vm->height) ||
+		    (ov->frame[f].format != vm->format) ||
+		    (ov->frame[f].sub_flag != ov->sub_flag) ||
+		    (ov->frame[f].depth != depth)) {
 			PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
 
 			/* If we're collecting previous frame wait
 			   before changing modes */
 			interruptible_sleep_on(&ov->wq);
 			if (signal_pending(current)) return -EINTR;
-			ret = mode_init_regs(ov, vm.width, vm.height,
-				vm.format, ov->sub_flag);
+			ret = mode_init_regs(ov, vm->width, vm->height,
+				vm->format, ov->sub_flag);
 #if 0
 			if (ret < 0) {
 				PDEBUG(1, "Got error while initializing regs ");
 				return ret;
 			}
 #endif
-			ov->frame[vm.frame].width = vm.width;
-			ov->frame[vm.frame].height = vm.height;
-			ov->frame[vm.frame].format = vm.format;
-			ov->frame[vm.frame].sub_flag = ov->sub_flag;
-			ov->frame[vm.frame].depth = depth;
+			ov->frame[f].width = vm->width;
+			ov->frame[f].height = vm->height;
+			ov->frame[f].format = vm->format;
+			ov->frame[f].sub_flag = ov->sub_flag;
+			ov->frame[f].depth = depth;
 		}
 
 		/* Mark it as ready */
-		ov->frame[vm.frame].grabstate = FRAME_READY;
+		ov->frame[f].grabstate = FRAME_READY;
 
-		PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", vm.frame);
+		PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f);
 
-		return ov51x_new_frame(ov, vm.frame);
+		return ov51x_new_frame(ov, f);
 	}
 	case VIDIOCSYNC:
 	{
-		int fnum, rc;
+		unsigned int fnum = *((unsigned int *) arg);
 		struct ov511_frame *frame;
+		int rc;
 
-		if (copy_from_user((void *)&fnum, arg, sizeof(int)))
-			return -EFAULT;
-
-		if ((unsigned)fnum >= OV511_NUMFRAMES) {
+		if (fnum >= OV511_NUMFRAMES) {
 			err("VIDIOCSYNC: invalid frame (%d)", fnum);
 			return -EINVAL;
 		}
@@ -5154,7 +4930,7 @@
 					return ret;
 				goto redo;
 			}
-			/* Fall through */			
+			/* Fall through */
 		case FRAME_DONE:
 			if (ov->snap_enabled && !frame->snapshot) {
 				int ret;
@@ -5182,159 +4958,109 @@
 	}
 	case VIDIOCGFBUF:
 	{
-		struct video_buffer vb;
-
-		PDEBUG(4, "VIDIOCSCHAN");
+		struct video_buffer *vb = arg;
 
-		memset(&vb, 0, sizeof(vb));
-		vb.base = NULL;	/* frame buffer not supported, not used */
+		PDEBUG(4, "VIDIOCGFBUF");
 
-		if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
-			return -EFAULT;
+		memset(vb, 0, sizeof(struct video_buffer));
 
 		return 0;
 	}
 	case VIDIOCGUNIT:
 	{
-		struct video_unit vu;
+		struct video_unit *vu = arg;
 
 		PDEBUG(4, "VIDIOCGUNIT");
 
-		memset(&vu, 0, sizeof(vu));
-
-		vu.video = ov->vdev.minor;	/* Video minor */
-		vu.vbi = VIDEO_NO_UNIT;		/* VBI minor */
-		vu.radio = VIDEO_NO_UNIT;	/* Radio minor */
-		vu.audio = VIDEO_NO_UNIT;	/* Audio minor */
-		vu.teletext = VIDEO_NO_UNIT;	/* Teletext minor */
-
-		if (copy_to_user((void *)arg, (void *)&vu, sizeof(vu)))
-			return -EFAULT;
-
-		return 0;
-	}
-	case VIDIOCGTUNER:
-	{
-		struct video_tuner v;
-
-		PDEBUG(4, "VIDIOCGTUNER");
-
-		if (copy_from_user(&v, arg, sizeof(v)))
-			return -EFAULT;
-
-		if (!ov->has_tuner || v.tuner)	// Only tuner 0
-			return -EINVAL;
-
-		strcpy(v.name, "Television");
-
-		// FIXME: Need a way to get the real values
-		v.rangelow = 0;
-		v.rangehigh = ~0;
-
-		v.flags = VIDEO_TUNER_PAL | VIDEO_TUNER_NTSC |
-		    VIDEO_TUNER_SECAM;
-		v.mode = 0; 		/* FIXME:  Not sure what this is yet */
-		v.signal = 0xFFFF;	/* unknown */
-
-		call_i2c_clients(ov, cmd, &v);
-
-		if (copy_to_user(arg, &v, sizeof(v)))
-			return -EFAULT;
-
-		return 0;
-	}
-	case VIDIOCSTUNER:
-	{
-		struct video_tuner v;
-		int err;
-
-		PDEBUG(4, "VIDIOCSTUNER");
-
-		if (copy_from_user(&v, arg, sizeof(v)))
-			return -EFAULT;
-
-		/* Only no or one tuner for now */
-		if (!ov->has_tuner || v.tuner)
-			return -EINVAL;
-
-		/* and it only has certain valid modes */
-		if (v.mode != VIDEO_MODE_PAL &&
-		    v.mode != VIDEO_MODE_NTSC &&
-		    v.mode != VIDEO_MODE_SECAM) return -EOPNOTSUPP;
-
-		/* Is this right/necessary? */
-		err = decoder_set_norm(ov, v.mode);
-		if (err)
-			return err;
+		memset(vu, 0, sizeof(struct video_unit));
 
-		call_i2c_clients(ov, cmd, &v);
+		vu->video = ov->vdev.minor;
+		vu->vbi = VIDEO_NO_UNIT;
+		vu->radio = VIDEO_NO_UNIT;
+		vu->audio = VIDEO_NO_UNIT;
+		vu->teletext = VIDEO_NO_UNIT;
 
 		return 0;
 	}
-	case VIDIOCGFREQ:
-	{
-		unsigned long v = ov->freq;
+	default:
+		PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
+		return -ENOIOCTLCMD;
+	} /* end switch */
 
-		PDEBUG(4, "VIDIOCGFREQ");
+	return 0;
+}
 
-		if (!ov->has_tuner)
-			return -EINVAL;
-#if 0
-		/* FIXME: this is necessary for testing */
-		v = 46*16;
-#endif
-		if (copy_to_user(arg, &v, sizeof(v)))
-			return -EFAULT;
+/* This is implemented as video_generic_ioctl() in the new V4L's videodev.c */
+static int
+ov51x_v4l1_generic_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
+{
+	char	sbuf[128];
+	void    *mbuf = NULL;
+	void	*parg = NULL;
+	int	err  = -EINVAL;
+
+	/*  Copy arguments into temp kernel buffer  */
+	switch (_IOC_DIR(cmd)) {
+	case _IOC_NONE:
+		parg = arg;
+		break;
+	case _IOC_READ: /* some v4l ioctls are marked wrong ... */
+	case _IOC_WRITE:
+	case (_IOC_WRITE | _IOC_READ):
+		if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+			parg = sbuf;
+		} else {
+			/* too big to allocate from stack */
+			mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
+			if (NULL == mbuf)
+				return -ENOMEM;
+			parg = mbuf;
+		}
 
-		return 0;
+		err = -EFAULT;
+		if (copy_from_user(parg, arg, _IOC_SIZE(cmd)))
+			goto out;
+		break;
 	}
-	case VIDIOCSFREQ:
-	{
-		unsigned long v;
-
-		if (!ov->has_tuner)
-			return -EINVAL;
-
-		if (copy_from_user(&v, arg, sizeof(v)))
-			return -EFAULT;
-
-		PDEBUG(4, "VIDIOCSFREQ: %lx", v);
 
-		ov->freq = v;
-		call_i2c_clients(ov, cmd, &v);
+	err = ov51x_v4l1_ioctl_internal(vdev->priv, cmd, parg);
+	if (err == -ENOIOCTLCMD)
+		err = -EINVAL;
+	if (err < 0)
+		goto out;
 
-		return 0;
-	}
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
+	/*  Copy results into user buffer  */
+	switch (_IOC_DIR(cmd))
 	{
-		/* FIXME: Implement this... */
-		return 0;
+	case _IOC_READ:
+	case (_IOC_WRITE | _IOC_READ):
+		if (copy_to_user(arg, parg, _IOC_SIZE(cmd)))
+			err = -EFAULT;
+		break;
 	}
-	default:
-		PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
-		return -ENOIOCTLCMD;
-	} /* end switch */
 
-	return 0;
+out:
+	if (mbuf)
+		kfree(mbuf);
+	return err;
 }
 
-static int 
+static int
 ov51x_v4l1_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
 {
-	int rc;
 	struct usb_ov511 *ov = vdev->priv;
+	int rc;
 
 	if (down_interruptible(&ov->lock))
 		return -EINTR;
 
-	rc = ov51x_v4l1_ioctl_internal(vdev, cmd, arg);
+	rc = ov51x_v4l1_generic_ioctl(vdev, cmd, arg);
 
 	up(&ov->lock);
 	return rc;
 }
 
-static inline long 
+static inline long
 ov51x_v4l1_read(struct video_device *vdev, char *buf, unsigned long count,
 		int noblock)
 {
@@ -5397,7 +5123,7 @@
 
 	/* Wait while we're grabbing the image */
 	PDEBUG(4, "Waiting image grabbing");
-	rc = wait_event_interruptible(frame->wq, 
+	rc = wait_event_interruptible(frame->wq,
 		(frame->grabstate == FRAME_DONE)
 		|| (frame->grabstate == FRAME_ERROR));
 
@@ -5444,7 +5170,7 @@
 		get_frame_length(frame));
 
 	/* copy bytes to user space; we allow for partials reads */
-//	if ((count + frame->bytes_read) 
+//	if ((count + frame->bytes_read)
 //	    > get_frame_length((struct ov511_frame *)frame))
 //		count = frame->scanlength - frame->bytes_read;
 
@@ -5486,11 +5212,11 @@
 	return rc;
 }
 
-static int 
+static int
 ov51x_v4l1_mmap(struct video_device *vdev, const char *adr, unsigned long size)
 {
-	struct usb_ov511 *ov = vdev->priv;
 	unsigned long start = (unsigned long)adr;
+	struct usb_ov511 *ov = vdev->priv;
 	unsigned long page, pos;
 
 	if (ov->dev == NULL)
@@ -5533,14 +5259,12 @@
 	open:		ov51x_v4l1_open,
 	close:		ov51x_v4l1_close,
 	read:		ov51x_v4l1_read,
-	write:		ov51x_v4l1_write,
 	ioctl:		ov51x_v4l1_ioctl,
 	mmap:		ov51x_v4l1_mmap,
-	initialize:	ov51x_v4l1_init_done,
 };
 
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
-static int 
+static int
 ov51x_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 		    unsigned long ularg)
 {
@@ -5761,10 +5485,10 @@
  *
  ***************************************************************************/
 
-/* This initializes the OV7610, OV7620, or OV7620AE sensor. The OV7620AE uses
+/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
  * the same register settings as the OV7610, since they are very similar.
  */
-static int 
+static int
 ov7xx0_configure(struct usb_ov511 *ov)
 {
 	int i, success;
@@ -5915,7 +5639,7 @@
 			err("this to " EMAIL);
 			err("This is only a warning. You can attempt to use");
 			err("your camera anyway");
-// Only issue a warning for now  
+// Only issue a warning for now
 //			return -1;
 		} else {
 			PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1);
@@ -5932,20 +5656,23 @@
 		info("Sensor is an OV7610");
 		ov->sensor = SEN_OV7610;
 	} else if ((rc & 3) == 1) {
-		/* I don't know what's different about the 76BE yet */
-		if (i2c_r(ov, 0x15) & 1)
+		/* I don't know what's different about the 76BE yet. */
+		if (i2c_r(ov, 0x15) & 1) {
 			info("Sensor is an OV7620AE");
-		else
+			info("PLEASE REPORT THE EXISTENCE OF THIS SENSOR TO");
+			info("THE DRIVER AUTHOR");
+		} else {
 			info("Sensor is an OV76BE");
+		}
 
 		/* OV511+ will return all zero isoc data unless we
 		 * configure the sensor as a 7620. Someone needs to
 		 * find the exact reg. setting that causes this. */
 		if (ov->bridge == BRG_OV511PLUS) {
-			info("Enabling 511+/7620AE workaround");
+			info("Enabling 511+/76BE workaround");
 			ov->sensor = SEN_OV7620;
 		} else {
-			ov->sensor = SEN_OV7620AE;
+			ov->sensor = SEN_OV76BE;
 		}
 	} else if ((rc & 3) == 0) {
 		info("Sensor is an OV7620");
@@ -5981,7 +5708,7 @@
 }
 
 /* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
-static int 
+static int
 ov6xx0_configure(struct usb_ov511 *ov)
 {
 	int rc;
@@ -5995,6 +5722,8 @@
 		/* The ratio of 0x0c and 0x0d  controls the white point */
 		{ OV511_I2C_BUS, 0x0c, 0x24 },
 		{ OV511_I2C_BUS, 0x0d, 0x24 },
+		{ OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */
+		{ OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */
 		{ OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */
 		{ OV511_I2C_BUS, 0x14, 0x04 },
 		/* 0x16: 0x06 helps frame stability with moving objects */
@@ -6006,10 +5735,11 @@
 		{ OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
 //		{ OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
 		{ OV511_I2C_BUS, 0x2d, 0x99 },
+		{ OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Procesing Parameter */
 		{ OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */
 		{ OV511_I2C_BUS, 0x38, 0x8b },
 		{ OV511_I2C_BUS, 0x39, 0x40 },
-		
+
 		{ OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
 		{ OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
 		{ OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
@@ -6089,7 +5819,7 @@
 		 * control the color balance */
 //	/*OK?*/	{ OV511_I2C_BUS, 0x4a, 0x80 }, // Check these
 //	/*OK?*/	{ OV511_I2C_BUS, 0x4b, 0x80 },
-//	/*U*/	{ OV511_I2C_BUS, 0x4c, 0xd0 }, 
+//	/*U*/	{ OV511_I2C_BUS, 0x4c, 0xd0 },
 	/*d2?*/	{ OV511_I2C_BUS, 0x4d, 0x10 }, /* This reduces noise a bit */
 	/*c1?*/	{ OV511_I2C_BUS, 0x4e, 0x40 },
 	/*04?*/	{ OV511_I2C_BUS, 0x4f, 0x07 },
@@ -6107,7 +5837,7 @@
 	};
 
 	PDEBUG(4, "starting sensor configuration");
-	
+
 	if (init_ov_sensor(ov) < 0) {
 		err("Failed to read sensor ID. You might not have an OV6xx0,");
 		err("or it may be not responding. Report this to " EMAIL);
@@ -6122,19 +5852,18 @@
 	if (rc < 0) {
 		err("Error detecting sensor type");
 		return -1;
-	} else if ((rc & 3) == 0) {
-		info("Sensor is an OV6630");
+	}
+
+	if ((rc & 3) == 0)
 		ov->sensor = SEN_OV6630;
-	} else if ((rc & 3) == 1) {
-		info("Sensor is an OV6620");
+	else if ((rc & 3) == 1)
 		ov->sensor = SEN_OV6620;
-	} else if ((rc & 3) == 2) {
-		info("Sensor is an OV6630AE");
+	else if ((rc & 3) == 2)
 		ov->sensor = SEN_OV6630;
-	} else if ((rc & 3) == 3) {
-		info("Sensor is an OV6630AF");
+	else if ((rc & 3) == 3)
 		ov->sensor = SEN_OV6630;
-	} 
+
+	info("Sensor is an %s", symbolic(senlist, ov->sensor));
 
 	/* Set sensor-specific vars */
 	ov->maxwidth = 352;
@@ -6157,7 +5886,7 @@
 		if (write_regvals(ov, aRegvalsNorm6x30))
 			return -1;
 	}
-	
+
 	return 0;
 }
 
@@ -6219,8 +5948,8 @@
 }
 
 /* This initializes the SAA7111A video decoder. */
-static int 
-saa7111a_configure(struct usb_ov511 *ov511)
+static int
+saa7111a_configure(struct usb_ov511 *ov)
 {
 	int rc;
 
@@ -6264,45 +5993,51 @@
 	}
 #endif
 
-	/* Set sensor-specific vars */
-	ov511->maxwidth = 640;
-	ov511->maxheight = 480;		/* Even/Odd fields */
-	ov511->minwidth = 320;
-	ov511->minheight = 240;		/* Even field only */
-
-	ov511->has_decoder = 1;
-	ov511->num_inputs = 8;
-	ov511->norm = VIDEO_MODE_AUTO;
-	ov511->stop_during_set = 0;	/* Decoder guarantees stable image */
+	/* 640x480 not supported with PAL */
+	if (ov->pal) {
+		ov->maxwidth = 320;
+		ov->maxheight = 240;		/* Even field only */
+	} else {
+		ov->maxwidth = 640;
+		ov->maxheight = 480;		/* Even/Odd fields */
+	}
+
+	ov->minwidth = 320;
+	ov->minheight = 240;		/* Even field only */
+
+	ov->has_decoder = 1;
+	ov->num_inputs = 8;
+	ov->norm = VIDEO_MODE_AUTO;
+	ov->stop_during_set = 0;	/* Decoder guarantees stable image */
 
 	/* Decoder doesn't change these values, so we use these instead of
 	 * acutally reading the registers (which doesn't work) */
-	ov511->brightness = 0x80 << 8;
-	ov511->contrast = 0x40 << 9;
-	ov511->colour = 0x40 << 9;
-	ov511->hue = 32768;
+	ov->brightness = 0x80 << 8;
+	ov->contrast = 0x40 << 9;
+	ov->colour = 0x40 << 9;
+	ov->hue = 32768;
 
 	PDEBUG(4, "Writing SAA7111A registers");
-	if (write_regvals(ov511, aRegvalsNormSAA7111A))
+	if (write_regvals(ov, aRegvalsNormSAA7111A))
 		return -1;
 
 	/* Detect version of decoder. This must be done after writing the
          * initial regs or the decoder will lock up. */
-	rc = i2c_r(ov511, 0x00);
+	rc = i2c_r(ov, 0x00);
 
 	if (rc < 0) {
 		err("Error detecting sensor version");
 		return -1;
 	} else {
 		info("Sensor is an SAA7111A (version 0x%x)", rc);
-		ov511->sensor = SEN_SAA7111A;
+		ov->sensor = SEN_SAA7111A;
 	}
 
 	// FIXME: Fix this for OV518(+)
 	/* Latch to negative edge of clock. Otherwise, we get incorrect
 	 * colors and jitter in the digital signal. */
-	if (ov511->bclass == BCL_OV511)
-		reg_w(ov511, 0x11, 0x00);
+	if (ov->bclass == BCL_OV511)
+		reg_w(ov, 0x11, 0x00);
 	else
 		warn("SAA7111A not yet supported with OV518/OV518+");
 
@@ -6313,8 +6048,6 @@
 static int 
 ov511_configure(struct usb_ov511 *ov)
 {
-	int i;
-
 	static struct ov511_regvals aRegvalsInit511[] = {
 		{ OV511_REG_BUS, R51x_SYS_RESET,	0x7f },
 	 	{ OV511_REG_BUS, R51x_SYS_INIT,		0x01 },
@@ -6356,26 +6089,19 @@
 		goto error;
 	}
 
-	ov->desc = -1;
 	PDEBUG (1, "CustomID = %d", ov->customid);
-	for (i = 0; clist[i].id >= 0; i++) {
-		if (ov->customid == clist[i].id) {
-			info("model: %s", clist[i].description);
-			ov->desc = i;
-			break;
-		}
-	}
+	ov->desc = symbolic(camlist, ov->customid);
+	info("model: %s", ov->desc);
 
-	if (clist[i].id == -1) {
+	if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) {
 		err("Camera type (%d) not recognized", ov->customid);
 		err("Please notify " EMAIL " of the name,");
 		err("manufacturer, model, and this number of your camera.");
 		err("Also include the output of the detection process.");
 	} 
 
-	if (clist[i].id == 6) {	/* USB Life TV (NTSC) */
-		ov->tuner_type = 8;		/* Temic 4036FY5 3X 1981 */
-	}
+	if (ov->customid == 70)		/* USB Life TV (PAL/SECAM) */
+		ov->pal = 1;
 
 	if (write_regvals(ov, aRegvalsInit511)) goto error;
 
@@ -6394,9 +6120,10 @@
 
 	if (ov511_init_compression(ov)) goto error;
 
-	ov51x_set_packet_size(ov, 0);
+	ov->packet_numbering = 1;
+	ov511_set_packet_size(ov, 0);
 
-	ov->snap_enabled = snapshot;	
+	ov->snap_enabled = snapshot;
 
 	/* Test for 7xx0 */
 	PDEBUG(3, "Testing for 0V7xx0");
@@ -6415,21 +6142,21 @@
 			/* Test for 8xx0 */
 			PDEBUG(3, "Testing for 0V8xx0");
 			ov->primary_i2c_slave = OV8xx0_SID;
-			if (ov51x_set_slave_ids(ov, OV8xx0_SID))
+			if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
 				goto error;
 
 			if (i2c_w(ov, 0x12, 0x80) < 0) {
 				/* Test for SAA7111A */
 				PDEBUG(3, "Testing for SAA7111A");
 				ov->primary_i2c_slave = SAA7111A_SID;
-				if (ov51x_set_slave_ids(ov, SAA7111A_SID))
+				if (ov51x_set_slave_ids(ov, SAA7111A_SID) < 0)
 					goto error;
 
 				if (i2c_w(ov, 0x0d, 0x00) < 0) {
 					/* Test for KS0127 */
 					PDEBUG(3, "Testing for KS0127");
 					ov->primary_i2c_slave = KS0127_SID;
-					if (ov51x_set_slave_ids(ov, KS0127_SID))
+					if (ov51x_set_slave_ids(ov, KS0127_SID) < 0)
 						goto error;
 
 					if (i2c_w(ov, 0x10, 0x00) < 0) {
@@ -6473,9 +6200,10 @@
 }
 
 /* This initializes the OV518/OV518+ and the sensor */
-static int 
+static int
 ov518_configure(struct usb_ov511 *ov)
 {
+	/* For 518 and 518+ */
 	static struct ov511_regvals aRegvalsInit518[] = {
 		{ OV511_REG_BUS, R51x_SYS_RESET,	0x40 },
 	 	{ OV511_REG_BUS, R51x_SYS_INIT,		0xe1 },
@@ -6488,8 +6216,6 @@
 		{ OV511_DONE_BUS, 0x0, 0x00},
 	};
 
-	/* New values, based on Windows driver. Since what they do is not
-	 * known yet, this may be incorrect. */
 	static struct ov511_regvals aRegvalsNorm518[] = {
 		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 }, /* Reset */
 		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 }, /* Enable */
@@ -6503,11 +6229,33 @@
 		{ OV511_DONE_BUS, 0x0, 0x00 },
 	};
 
+	static struct ov511_regvals aRegvalsNorm518Plus[] = {
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 }, /* Reset */
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 }, /* Enable */
+		{ OV511_REG_BUS, 0x31, 			0x0f },
+		{ OV511_REG_BUS, 0x5d,			0x03 },
+		{ OV511_REG_BUS, 0x24,			0x9f },
+		{ OV511_REG_BUS, 0x25,			0x90 },
+		{ OV511_REG_BUS, 0x20,			0x60 }, /* Was 0x08 */
+		{ OV511_REG_BUS, 0x51,			0x02 },
+		{ OV511_REG_BUS, 0x71,			0x19 },
+		{ OV511_REG_BUS, 0x40,			0xff },
+		{ OV511_REG_BUS, 0x41,			0x42 },
+		{ OV511_REG_BUS, 0x46,			0x00 },
+		{ OV511_REG_BUS, 0x33,			0x04 },
+		{ OV511_REG_BUS, 0x21,			0x19 },
+		{ OV511_REG_BUS, 0x3f,			0x10 },
+		{ OV511_DONE_BUS, 0x0, 0x00 },
+	};
+
 	PDEBUG(4, "");
 
 	/* First 5 bits of custom ID reg are a revision ID on OV518 */
 	info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID));
 
+	/* Give it the default description */
+	ov->desc = symbolic(camlist, 0);
+
 	if (write_regvals(ov, aRegvalsInit518)) goto error;
 
 	/* Set LED GPIO pin to output mode */
@@ -6526,13 +6274,25 @@
 		warn("Compression required with OV518...enabling");
 	}
 
-	if (write_regvals(ov, aRegvalsNorm518)) goto error;
+	if (ov->bridge == BRG_OV518) {
+		if (write_regvals(ov, aRegvalsNorm518)) goto error;
+	} else if (ov->bridge == BRG_OV518PLUS) {
+		if (write_regvals(ov, aRegvalsNorm518Plus)) goto error;
+	} else {
+		err("Invalid bridge");
+	}
 
 	if (reg_w(ov, 0x2f, 0x80) < 0) goto error;
 
 	if (ov518_init_compression(ov)) goto error;
 
-	ov51x_set_packet_size(ov, 0);
+	/* OV518+ has packet numbering turned on by default */
+	if (ov->bridge == BRG_OV518)
+		ov->packet_numbering = 0;
+	else
+		ov->packet_numbering = 1;
+
+	ov518_set_packet_size(ov, 0);
 
 	ov->snap_enabled = snapshot;
 
@@ -6577,9 +6337,8 @@
 		}
 	}
 
-	// FIXME: Sizes > 320x240 are not working yet
-	ov->maxwidth = 320;
-	ov->maxheight = 240;
+	ov->maxwidth = 352;
+	ov->maxheight = 288;
 
 	// The OV518 cannot go as low as the sensor can
 	ov->minwidth = 160;
@@ -6640,46 +6399,42 @@
 	ov->lightfreq = lightfreq;
 	ov->num_inputs = 1;	   /* Video decoder init functs. change this */
 	ov->stop_during_set = !fastset;
-	ov->tuner_type = tuner;
 	ov->backlight = backlight;
-
+	ov->mirror = mirror;
 	ov->auto_brt = autobright;
 	ov->auto_gain = autogain;
 	ov->auto_exp = autoexp;
 
 	switch (dev->descriptor.idProduct) {
 	case PROD_OV511:
-		info("USB OV511 camera found");
 		ov->bridge = BRG_OV511;
 		ov->bclass = BCL_OV511;
 		break;
 	case PROD_OV511PLUS:
-		info("USB OV511+ camera found");
 		ov->bridge = BRG_OV511PLUS;
 		ov->bclass = BCL_OV511;
 		break;
 	case PROD_OV518:
-		info("USB OV518 camera found");
 		ov->bridge = BRG_OV518;
 		ov->bclass = BCL_OV518;
 		break;
 	case PROD_OV518PLUS:
-		info("USB OV518+ camera found");
 		ov->bridge = BRG_OV518PLUS;
 		ov->bclass = BCL_OV518;
 		break;
 	case PROD_ME2CAM:
 		if (dev->descriptor.idVendor != VEND_MATTEL)
 			goto error;
-		info("Intel Play Me2Cam (OV511+) found");
 		ov->bridge = BRG_OV511PLUS;
 		ov->bclass = BCL_OV511;
 		break;
 	default:
-		err("Unknown product ID 0x%x", dev->descriptor.idProduct);
+		err("Unknown product ID 0x%04x", dev->descriptor.idProduct);
 		goto error_dealloc;
 	}
 
+	info("USB %s video device found", symbolic(brglist, ov->bridge));
+
 	/* Workaround for some applications that want data in RGB
 	 * instead of BGR. */
 	if (force_rgb)
@@ -6713,6 +6468,12 @@
 		init_waitqueue_head(&ov->frame[i].wq);
 	}
 
+	for (i = 0; i < OV511_NUMSBUF; i++) {
+		ov->sbuf[i].ov = ov;
+		spin_lock_init(&ov->sbuf[i].lock);
+		ov->sbuf[i].n = i;
+	}
+
 	/* Unnecessary? (This is done on open(). Need to make sure variables
 	 * are properly initialized without this before removing it, though). */
 	if (ov51x_set_default_params(ov) < 0)
@@ -6747,12 +6508,14 @@
 
 	info("Device registered on minor %d", ov->vdev.minor);
 
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+	create_proc_ov511_cam(ov);
+#endif
+
 	MOD_DEC_USE_COUNT;
      	return ov;
 
 error:
-	err("Camera initialization failed");
-
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
 	/* Safe to call even if entry doesn't exist */
 	destroy_proc_ov511_cam(ov);
@@ -6765,9 +6528,6 @@
 		up(&ov->cbuf_lock);
 	}
 
-	usb_driver_release_interface(&ov511_driver,
-		&dev->actconfig->interface[ov->iface]);
-
 error_dealloc:
 	if (ov) {
 		kfree(ov);
@@ -6776,6 +6536,7 @@
 
 error_out:
 	MOD_DEC_USE_COUNT;
+	err("Camera initialization failed");
 	return NULL;
 }
 
@@ -6810,22 +6571,12 @@
 
 	ov->streaming = 0;
 
-	/* Unschedule all of the iso td's */
-	for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
-		if (ov->sbuf[n].urb) {
-			ov->sbuf[n].urb->next = NULL;
-			usb_unlink_urb(ov->sbuf[n].urb);
-			usb_free_urb(ov->sbuf[n].urb);
-			ov->sbuf[n].urb = NULL;
-		}
-	}
+	ov51x_unlink_isoc(ov);
 
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
         destroy_proc_ov511_cam(ov);
 #endif
 
-	usb_driver_release_interface(&ov511_driver,
-		&ov->dev->actconfig->interface[ov->iface]);
 	ov->dev = NULL;
 
 	/* Free the memory */
@@ -6858,7 +6609,7 @@
  ***************************************************************************/
 
 /* Returns 0 for success */
-int 
+int
 ov511_register_decomp_module(int ver, struct ov51x_decomp_ops *ops, int ov518,
 			     int mmx)
 {
@@ -6915,7 +6666,7 @@
 	return -EBUSY;
 }
 
-void 
+void
 ov511_deregister_decomp_module(int ov518, int mmx)
 {
 	lock_kernel();
@@ -6931,13 +6682,13 @@
 		else
 			ov511_decomp_ops = NULL;
 	}
-	
+
 	MOD_DEC_USE_COUNT;
 
 	unlock_kernel();
 }
 
-static int __init 
+static int __init
 usb_ov511_init(void)
 {
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
@@ -6947,11 +6698,8 @@
 	if (usb_register(&ov511_driver) < 0)
 		return -1;
 
-	// FIXME: Don't know how to determine this yet
-	ov51x_mmx_available = 0;
-
 #if defined (__i386__)
-	if (test_bit(X86_FEATURE_MMX, &boot_cpu_data.x86_capability))
+	if (test_bit(X86_FEATURE_MMX, boot_cpu_data.x86_capability))
 		ov51x_mmx_available = 1;
 #endif
 
@@ -6960,7 +6708,7 @@
 	return 0;
 }
 
-static void __exit 
+static void __exit
 usb_ov511_exit(void)
 {
 	usb_deregister(&ov511_driver);
@@ -6974,6 +6722,5 @@
 module_init(usb_ov511_init);
 module_exit(usb_ov511_exit);
 
-/* No version, for compatibility with binary-only modules */
-EXPORT_SYMBOL_NOVERS(ov511_register_decomp_module);
-EXPORT_SYMBOL_NOVERS(ov511_deregister_decomp_module);
+EXPORT_SYMBOL(ov511_register_decomp_module);
+EXPORT_SYMBOL(ov511_deregister_decomp_module);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/ov511.h linux-2.4.20/drivers/usb/ov511.h
--- linux-2.4.19/drivers/usb/ov511.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/ov511.h	2002-10-29 11:18:37.000000000 +0000
@@ -10,8 +10,8 @@
 
 #ifdef OV511_DEBUG
 	#define PDEBUG(level, fmt, args...) \
-		if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt,\
-		__LINE__ , ## args)
+		if (debug >= (level)) info("[%s:%d] " fmt, \
+		__PRETTY_FUNCTION__, __LINE__ , ## args)
 #else
 	#define PDEBUG(level, fmt, args...) do {} while(0)
 #endif
@@ -243,6 +243,16 @@
 
 #define OV511_ENDPOINT_ADDRESS	1	/* Isoc endpoint number */
 
+#define OV511_NUMFRAMES	2
+#if OV511_NUMFRAMES > VIDEO_MAX_FRAME
+	#error "OV511_NUMFRAMES is too high"
+#endif
+
+#define OV511_NUMSBUF		2
+
+/* Control transfers use up to 4 bytes */
+#define OV511_CBUF_SIZE		4
+
 /* Bridge types */
 enum {
 	BRG_UNKNOWN,
@@ -376,9 +386,14 @@
 			       struct ov511_i2c_struct)
 /* ------------- End IOCTL interface -------------- */
 
+struct usb_ov511;		/* Forward declaration */
+
 struct ov511_sbuf {
-	char *data;
+	struct usb_ov511 *ov;
+	unsigned char *data;
 	struct urb *urb;
+	spinlock_t lock;
+	int n;
 };
 
 enum {
@@ -401,9 +416,10 @@
 
 struct ov511_frame {
 	int framenum;		/* Index of this frame */
-	char *data;		/* Frame buffer */
-	char *tempdata;		/* Temp buffer for multi-stage conversions */
-	char *rawdata;		/* Raw camera data buffer */
+	unsigned char *data;	/* Frame buffer */
+	unsigned char *tempdata; /* Temp buffer for multi-stage conversions */
+	unsigned char *rawdata;	/* Raw camera data buffer */
+	unsigned char *compbuf;	/* Temp buffer for decompressor */
 
 	int depth;		/* Bytes per pixel */
 	int width;		/* Width application is expecting */
@@ -428,27 +444,19 @@
 	int snapshot;		/* True if frame was a snapshot */
 };
 
-#define DECOMP_INTERFACE_VER 2
+#define DECOMP_INTERFACE_VER 4
 
 /* Compression module operations */
 struct ov51x_decomp_ops {
-	int (*decomp_400)(unsigned char *, unsigned char *, int, int, int);
-	int (*decomp_420)(unsigned char *, unsigned char *, int, int, int);
-	int (*decomp_422)(unsigned char *, unsigned char *, int, int, int);
-	void (*decomp_lock)(void);
-	void (*decomp_unlock)(void);
+	int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *,
+			  int, int, int);
+	int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *,
+			  int, int, int);
+	int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *,
+			  int, int, int);
+	struct module *owner;
 };
 
-#define OV511_NUMFRAMES	2
-#if OV511_NUMFRAMES > VIDEO_MAX_FRAME
-	#error "OV511_NUMFRAMES is too high"
-#endif
-
-#define OV511_NUMSBUF		2
-
-/* Control transfers use up to 4 bytes */
-#define OV511_CBUF_SIZE		4
-
 struct usb_ov511 {
 	struct video_device vdev;
 
@@ -456,7 +464,7 @@
 	struct usb_device *dev;
 
 	int customid;
-	int desc;
+	char *desc;
 	unsigned char iface;
 
 	/* Determined by sensor type */
@@ -475,6 +483,7 @@
 	int auto_gain;		/* Auto gain control enabled flag */
 	int auto_exp;		/* Auto exposure enabled flag */
 	int backlight;		/* Backlight exposure algorithm flag */
+	int mirror;		/* Image is reversed horizontally */
 
 	int led_policy;		/* LED: off|on|auto; OV511+ only */
 
@@ -490,9 +499,9 @@
 	int lightfreq;		/* Power (lighting) frequency */
 	int bandfilt;		/* Banding filter enabled flag */
 
-	char *fbuf;		/* Videodev buffer area */
-	char *tempfbuf;		/* Temporary (intermediate) buffer area */
-	char *rawfbuf;		/* Raw camera data buffer area */
+	unsigned char *fbuf;	/* Videodev buffer area */
+	unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */
+	unsigned char *rawfbuf;	/* Raw camera data buffer area */
 
 	int sub_flag;		/* Pix Array subcapture on flag */
 	int subx;		/* Pix Array subcapture x offset */
@@ -513,9 +522,9 @@
 	int bclass;		/* Class of bridge (BCL_*) */
 	int sensor;		/* Type of image sensor chip (SEN_*) */
 	int sclass;		/* Type of image sensor chip (SCL_*) */
-	int tuner;		/* Type of TV tuner */
 
 	int packet_size;	/* Frame size per isoc desc */
+	int packet_numbering;	/* Is ISO frame numbering enabled? */
 
 	struct semaphore param_lock;	/* params lock for this camera */
 
@@ -542,12 +551,9 @@
 	int num_inputs;		/* Number of inputs */
 	int norm; 		/* NTSC / PAL / SECAM */
 	int has_decoder;	/* Device has a video decoder */
-	int has_tuner;		/* Device has a TV tuner */
-	int has_audio_proc;	/* Device has an audio processor */
-	int freq;		/* Current tuner frequency */
-	int tuner_type;		/* Specific tuner model */
+	int pal;		/* Device is designed for PAL resolution */
 
-	/* I2C interface to kernel */
+	/* I2C interface */
 	struct semaphore i2c_lock;	  /* Protect I2C controller regs */
 	unsigned char primary_i2c_slave;  /* I2C write id of sensor */
 
@@ -556,27 +562,28 @@
 	struct semaphore cbuf_lock;
 };
 
-struct cam_list {
-	int id;
-	char *description;
-};
-
-struct palette_list {
+/* Used to represent a list of values and their respective symbolic names */
+struct symbolic_list {
 	int num;
 	char *name;
 };
 
-struct mode_list_518 {
-	int width;
-	int height;
-	u8 reg28;
-	u8 reg29;
-	u8 reg2a;
-	u8 reg2c;
-	u8 reg2e;
-	u8 reg24;
-	u8 reg25;
-};
+#define NOT_DEFINED_STR "Unknown"
+
+/* Returns the name of the matching element in the symbolic_list array. The
+ * end of the list must be marked with an element that has a NULL name.
+ */
+static inline char * 
+symbolic(struct symbolic_list list[], int num)
+{
+	int i;
+
+	for (i = 0; list[i].name != NULL; i++)
+			if (list[i].num == num)
+				return (list[i].name);
+
+	return (NOT_DEFINED_STR);
+}
 
 /* Compression stuff */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/pegasus.c linux-2.4.20/drivers/usb/pegasus.c
--- linux-2.4.19/drivers/usb/pegasus.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/pegasus.c	2002-10-29 11:18:40.000000000 +0000
@@ -1,46 +1,31 @@
 /*
-**	Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
-**
-**	Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
-**	
-**
-**	ChangeLog:
-**		....	Most of the time spend reading sources & docs.
-**		v0.2.x	First official release for the Linux kernel.
-**		v0.3.0	Beutified and structured, some bugs fixed.
-**		v0.3.x	URBifying bulk requests and bugfixing. First relatively
-**			stable release. Still can touch device's registers only
-**			from top-halves.
-**		v0.4.0	Control messages remained unurbified are now URBs.
-**			Now we can touch the HW at any time.
-**		v0.4.9	Control urbs again use process context to wait. Argh...
-**			Some long standing bugs (enable_net_traffic) fixed.
-**			Also nasty trick about resubmiting control urb from
-**			interrupt context used. Please let me know how it
-**			behaves. Pegasus II support added since this version.
-**			TODO: suppressing HCD warnings spewage on disconnect.
-**		v0.4.13	Ethernet address is now set at probe(), not at open()
-**			time as this seems to break dhcpd. 
-**		v0.4.25	ethtool support added.
-*/
-
-/*
- * 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.
+ *  Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
  *
- * 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.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *	
  *
- * 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
+ *	ChangeLog:
+ *		....	Most of the time spend reading sources & docs.
+ *		v0.2.x	First official release for the Linux kernel.
+ *		v0.3.0	Beutified and structured, some bugs fixed.
+ *		v0.3.x	URBifying bulk requests and bugfixing. First relatively
+ *			stable release. Still can touch device's registers only
+ *			from top-halves.
+ *		v0.4.0	Control messages remained unurbified are now URBs.
+ *			Now we can touch the HW at any time.
+ *		v0.4.9	Control urbs again use process context to wait. Argh...
+ *			Some long standing bugs (enable_net_traffic) fixed.
+ *			Also nasty trick about resubmiting control urb from
+ *			interrupt context used. Please let me know how it
+ *			behaves. Pegasus II support added since this version.
+ *			TODO: suppressing HCD warnings spewage on disconnect.
+ *		v0.4.13	Ethernet address is now set at probe(), not at open()
+ *			time as this seems to break dhcpd. 
+ *		v0.4.25	ethtool support added.
  */
 
-
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/init.h>
@@ -69,7 +54,6 @@
 static int loopback = 0;
 static int mii_mode = 1;
 static int multicast_filter_limit = 32;
-static DECLARE_MUTEX(gsem);
 
 static struct usb_eth_dev usb_dev_id[] = {
 #define	PEGASUS_DEV(pn, vid, pid, flags)	\
@@ -84,104 +68,102 @@
 	{match_flags: USB_DEVICE_ID_MATCH_DEVICE, idVendor:vid, idProduct:pid},
 #include "pegasus.h"
 #undef	PEGASUS_DEV
-	{ }
+	{}
 };
 
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 MODULE_PARM(loopback, "i");
 MODULE_PARM(mii_mode, "i");
 MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)");
 MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0),default=MII mode = 0");
 
-MODULE_DEVICE_TABLE (usb, pegasus_ids);
-
+MODULE_DEVICE_TABLE(usb, pegasus_ids);
 
-static int update_eth_regs_async( pegasus_t * );
+static int update_eth_regs_async(pegasus_t *);
 /* Aargh!!! I _really_ hate such tweaks */
-static void ctrl_callback( struct urb *urb )
+static void ctrl_callback(struct urb *urb)
 {
-	pegasus_t	*pegasus = urb->context;
+	pegasus_t *pegasus = urb->context;
 
-	if ( !pegasus )
+	if (!pegasus)
 		return;
 
-	switch ( urb->status ) {
-		case 0:
-			if ( pegasus->flags & ETH_REGS_CHANGE ) {
-				pegasus->flags &= ~ETH_REGS_CHANGE;
-				pegasus->flags |= ETH_REGS_CHANGED;
-				update_eth_regs_async( pegasus );
-				return;
-			}
-			break;
-		case -EINPROGRESS:
+	switch (urb->status) {
+	case 0:
+		if (pegasus->flags & ETH_REGS_CHANGE) {
+			pegasus->flags &= ~ETH_REGS_CHANGE;
+			pegasus->flags |= ETH_REGS_CHANGED;
+			update_eth_regs_async(pegasus);
 			return;
-		case -ENOENT:
-			break;
-		default:
-			warn("%s: status %d", __FUNCTION__, urb->status);
+		}
+		break;
+	case -EINPROGRESS:
+		return;
+	case -ENOENT:
+		break;
+	default:
+		warn("%s: status %d", __FUNCTION__, urb->status);
 	}
 	pegasus->flags &= ~ETH_REGS_CHANGED;
-	wake_up(&pegasus->ctrl_wait );
+	wake_up(&pegasus->ctrl_wait);
 }
 
-
-static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
+static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
+			 void *data)
 {
-	int	ret;
+	int ret;
 	unsigned char *buffer;
 	DECLARE_WAITQUEUE(wait, current);
 
-	buffer = kmalloc(size,GFP_KERNEL);
+	buffer = kmalloc(size, GFP_KERNEL);
 	if (!buffer) {
 		err("unable to allocate memory for configuration descriptors");
 		return 0;
 	}
-	memcpy(buffer,data,size);
+	memcpy(buffer, data, size);
 
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
-	while ( pegasus->flags & ETH_REGS_CHANGED )
+	while (pegasus->flags & ETH_REGS_CHANGED)
 		schedule();
 	remove_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_RUNNING);
 
-	pegasus->dr.requesttype = PEGASUS_REQT_READ;
-	pegasus->dr.request = PEGASUS_REQ_GET_REGS;
-	pegasus->dr.value = cpu_to_le16 (0);
-	pegasus->dr.index = cpu_to_le16p(&indx);
-	pegasus->dr.length = cpu_to_le16p(&size);
+	pegasus->dr.bRequestType = PEGASUS_REQT_READ;
+	pegasus->dr.bRequest = PEGASUS_REQ_GET_REGS;
+	pegasus->dr.wValue = cpu_to_le16(0);
+	pegasus->dr.wIndex = cpu_to_le16p(&indx);
+	pegasus->dr.wLength = cpu_to_le16p(&size);
 	pegasus->ctrl_urb->transfer_buffer_length = size;
 
-	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
-			  usb_rcvctrlpipe(pegasus->usb,0),
-			  (char *)&pegasus->dr,
-			  buffer, size, ctrl_callback, pegasus );
+	FILL_CONTROL_URB(pegasus->ctrl_urb, pegasus->usb,
+			 usb_rcvctrlpipe(pegasus->usb, 0),
+			 (char *) &pegasus->dr,
+			 buffer, size, ctrl_callback, pegasus);
 
-	add_wait_queue( &pegasus->ctrl_wait, &wait );
-	set_current_state( TASK_UNINTERRUPTIBLE );
+	add_wait_queue(&pegasus->ctrl_wait, &wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
 
-	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
+	if ((ret = usb_submit_urb(pegasus->ctrl_urb))) {
 		err("%s: BAD CTRLs %d", __FUNCTION__, ret);
 		goto out;
 	}
 
 	schedule();
 out:
-	remove_wait_queue( &pegasus->ctrl_wait, &wait );
-	memcpy(data,buffer,size);
+	remove_wait_queue(&pegasus->ctrl_wait, &wait);
+	memcpy(data, buffer, size);
 	kfree(buffer);
 
 	return ret;
 }
 
-
-static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
+static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
+			 void *data)
 {
-	int	ret;
+	int ret;
 	unsigned char *buffer;
 	DECLARE_WAITQUEUE(wait, current);
 
@@ -194,47 +176,46 @@
 
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
-	while ( pegasus->flags & ETH_REGS_CHANGED )
+	while (pegasus->flags & ETH_REGS_CHANGED)
 		schedule();
 	remove_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_RUNNING);
 
-	pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
-	pegasus->dr.request = PEGASUS_REQ_SET_REGS;
-	pegasus->dr.value = cpu_to_le16 (0);
-	pegasus->dr.index = cpu_to_le16p( &indx );
-	pegasus->dr.length = cpu_to_le16p( &size );
+	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
+	pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS;
+	pegasus->dr.wValue = cpu_to_le16(0);
+	pegasus->dr.wIndex = cpu_to_le16p(&indx);
+	pegasus->dr.wLength = cpu_to_le16p(&size);
 	pegasus->ctrl_urb->transfer_buffer_length = size;
 
-	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
-			  usb_sndctrlpipe(pegasus->usb,0),
-			  (char *)&pegasus->dr,
-			  buffer, size, ctrl_callback, pegasus );
-			  
-	add_wait_queue( &pegasus->ctrl_wait, &wait );
-	set_current_state( TASK_UNINTERRUPTIBLE );
+	FILL_CONTROL_URB(pegasus->ctrl_urb, pegasus->usb,
+			 usb_sndctrlpipe(pegasus->usb, 0),
+			 (char *) &pegasus->dr,
+			 buffer, size, ctrl_callback, pegasus);
 
-	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
+	add_wait_queue(&pegasus->ctrl_wait, &wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+
+	if ((ret = usb_submit_urb(pegasus->ctrl_urb))) {
 		err("%s: BAD CTRL %d", __FUNCTION__, ret);
 		goto out;
 	}
-	
+
 	schedule();
 out:
-	remove_wait_queue( &pegasus->ctrl_wait, &wait );
+	remove_wait_queue(&pegasus->ctrl_wait, &wait);
 	kfree(buffer);
-	
+
 	return ret;
 }
 
-
-static int set_register( pegasus_t *pegasus, __u16 indx, __u8 data )
+static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
 {
-	int	ret;
+	int ret;
 	unsigned char *buffer;
 	__u16 dat = data;
 	DECLARE_WAITQUEUE(wait, current);
-	
+
 	buffer = kmalloc(1, GFP_KERNEL);
 	if (!buffer) {
 		err("unable to allocate memory for configuration descriptors");
@@ -244,129 +225,126 @@
 
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
-	while ( pegasus->flags & ETH_REGS_CHANGED )
+	while (pegasus->flags & ETH_REGS_CHANGED)
 		schedule();
 	remove_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_RUNNING);
 
-	pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
-	pegasus->dr.request = PEGASUS_REQ_SET_REG;
-	pegasus->dr.value = cpu_to_le16p( &dat);
-	pegasus->dr.index = cpu_to_le16p( &indx );
-	pegasus->dr.length = cpu_to_le16( 1 );
+	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
+	pegasus->dr.bRequest = PEGASUS_REQ_SET_REG;
+	pegasus->dr.wValue = cpu_to_le16p(&dat);
+	pegasus->dr.wIndex = cpu_to_le16p(&indx);
+	pegasus->dr.wLength = cpu_to_le16(1);
 	pegasus->ctrl_urb->transfer_buffer_length = 1;
 
-	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
-			  usb_sndctrlpipe(pegasus->usb,0),
-			  (char *)&pegasus->dr,
-			  buffer, 1, ctrl_callback, pegasus );
+	FILL_CONTROL_URB(pegasus->ctrl_urb, pegasus->usb,
+			 usb_sndctrlpipe(pegasus->usb, 0),
+			 (char *) &pegasus->dr,
+			 buffer, 1, ctrl_callback, pegasus);
 
-	add_wait_queue( &pegasus->ctrl_wait, &wait );
-	set_current_state( TASK_UNINTERRUPTIBLE );
+	add_wait_queue(&pegasus->ctrl_wait, &wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
 
-	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
+	if ((ret = usb_submit_urb(pegasus->ctrl_urb))) {
 		err("%s: BAD CTRL %d", __FUNCTION__, ret);
 		goto out;
 	}
 
 	schedule();
 out:
-	remove_wait_queue( &pegasus->ctrl_wait, &wait );
+	remove_wait_queue(&pegasus->ctrl_wait, &wait);
 	kfree(buffer);
 
 	return ret;
 }
 
-
-static int update_eth_regs_async( pegasus_t *pegasus )
+static int update_eth_regs_async(pegasus_t * pegasus)
 {
-	int	ret;
+	int ret;
 
-	pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
-	pegasus->dr.request = PEGASUS_REQ_SET_REGS;
-	pegasus->dr.value = 0;
-	pegasus->dr.index =  cpu_to_le16(EthCtrl0);
-	pegasus->dr.length = cpu_to_le16(3);
+	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
+	pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS;
+	pegasus->dr.wValue = 0;
+	pegasus->dr.wIndex = cpu_to_le16(EthCtrl0);
+	pegasus->dr.wLength = cpu_to_le16(3);
 	pegasus->ctrl_urb->transfer_buffer_length = 3;
 
-	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
-			  usb_sndctrlpipe(pegasus->usb,0),
-			  (char *)&pegasus->dr,
-			  pegasus->eth_regs, 3, ctrl_callback, pegasus );
+	FILL_CONTROL_URB(pegasus->ctrl_urb, pegasus->usb,
+			 usb_sndctrlpipe(pegasus->usb, 0),
+			 (char *) &pegasus->dr,
+			 pegasus->eth_regs, 3, ctrl_callback, pegasus);
+
+	if ((ret = usb_submit_urb(pegasus->ctrl_urb)))
+		err("%s: BAD CTRL %d, flgs %x", __FUNCTION__, ret,
+		    pegasus->flags);
 
-	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) )
-		err("%s: BAD CTRL %d, flgs %x",__FUNCTION__,ret,pegasus->flags);
-
-	return	ret;
+	return ret;
 }
 
-
-static int read_mii_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd )
+static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
 {
-	int	i;
-	__u8	data[4] = { phy, 0, 0, indx };
-	__u16  regdi;
-	
-	set_register( pegasus, PhyCtrl, 0 );
-	set_registers( pegasus, PhyAddr, sizeof(data), data );
-	set_register( pegasus, PhyCtrl, (indx | PHY_READ) );
+	int i;
+	__u8 data[4] = { phy, 0, 0, indx };
+	__u16 regdi;
+
+	set_register(pegasus, PhyCtrl, 0);
+	set_registers(pegasus, PhyAddr, sizeof(data), data);
+	set_register(pegasus, PhyCtrl, (indx | PHY_READ));
 	for (i = 0; i < REG_TIMEOUT; i++) {
 		get_registers(pegasus, PhyCtrl, 1, data);
-		if ( data[0] & PHY_DONE ) 
+		if (data[0] & PHY_DONE)
 			break;
 	}
-	if ( i < REG_TIMEOUT ) {
-		get_registers( pegasus, PhyData, 2, &regdi );
+	if (i < REG_TIMEOUT) {
+		get_registers(pegasus, PhyData, 2, &regdi);
 		*regd = le16_to_cpu(regdi);
-		return	0;
+		return 0;
 	}
 	warn("%s: failed", __FUNCTION__);
-	
+
 	return 1;
 }
 
-
-static int write_mii_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 regd )
+static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
 {
-	int	i;
-	__u8	data[4] = { phy, 0, 0, indx };
-	
-	*(data + 1) = cpu_to_le16p( &regd );
-	set_register( pegasus, PhyCtrl, 0 );
-	set_registers( pegasus, PhyAddr, 4, data );
-	set_register( pegasus, PhyCtrl, (indx | PHY_WRITE) );
+	int i;
+	__u8 data[4] = { phy, 0, 0, indx };
+
+	*(data + 1) = cpu_to_le16p(&regd);
+	set_register(pegasus, PhyCtrl, 0);
+	set_registers(pegasus, PhyAddr, 4, data);
+	set_register(pegasus, PhyCtrl, (indx | PHY_WRITE));
 	for (i = 0; i < REG_TIMEOUT; i++) {
 		get_registers(pegasus, PhyCtrl, 1, data);
-		if ( data[0] & PHY_DONE ) 
+		if (data[0] & PHY_DONE)
 			break;
 	}
-	if ( i < REG_TIMEOUT )
-		return	0;
+	if (i < REG_TIMEOUT)
+		return 0;
 	warn("%s: failed", __FUNCTION__);
 
 	return 1;
 }
 
-
-static int read_eprom_word( pegasus_t *pegasus, __u8 index, __u16 *retdata )
+static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata)
 {
-	int	i;
+	int i;
 	__u8 tmp;
 	__u16 retdatai;
-	
-	set_register( pegasus, EpromCtrl, 0 );
-	set_register( pegasus, EpromOffset, index );
-	set_register( pegasus, EpromCtrl, EPROM_READ); 
-
-	for ( i=0; i < REG_TIMEOUT; i++ ) {
-		get_registers( pegasus, EpromCtrl, 1, &tmp );
-		if ( tmp & EPROM_DONE )
+
+	set_register(pegasus, EpromCtrl, 0);
+	set_register(pegasus, EpromOffset, index);
+	set_register(pegasus, EpromCtrl, EPROM_READ);
+
+	for (i = 0; i < REG_TIMEOUT; i++) {
+		get_registers(pegasus, EpromCtrl, 1, &tmp);
+		if (tmp & EPROM_DONE)
 			break;
 	}
-	if ( i < REG_TIMEOUT ) {
-		get_registers( pegasus, EpromData, 2, &retdatai );
-		*retdata = le16_to_cpu (retdatai);
-		return	0;
+	if (i < REG_TIMEOUT) {
+		get_registers(pegasus, EpromData, 2, &retdatai);
+		*retdata = le16_to_cpu(retdatai);
+		return 0;
 	}
 	warn("%s: failed", __FUNCTION__);
 
@@ -374,199 +352,188 @@
 }
 
 #ifdef	PEGASUS_WRITE_EEPROM
-static inline void enable_eprom_write( pegasus_t *pegasus )
+static inline void enable_eprom_write(pegasus_t * pegasus)
 {
-	__u8	tmp;
+	__u8 tmp;
 
-	get_registers( pegasus, EthCtrl2, 1, &tmp );
-	set_register( pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE );
+	get_registers(pegasus, EthCtrl2, 1, &tmp);
+	set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE);
 }
 
-
-static inline void disable_eprom_write( pegasus_t *pegasus )
+static inline void disable_eprom_write(pegasus_t * pegasus)
 {
-	__u8 	tmp;
+	__u8 tmp;
 
-	get_registers( pegasus, EthCtrl2, 1, &tmp );
-	set_register( pegasus, EpromCtrl, 0 );
-	set_register( pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE );
+	get_registers(pegasus, EthCtrl2, 1, &tmp);
+	set_register(pegasus, EpromCtrl, 0);
+	set_register(pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE);
 }
 
-
-static int write_eprom_word( pegasus_t *pegasus, __u8 index, __u16 data )
+static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data)
 {
-	int	i, tmp;
-	__u8	d[4] = {0x3f, 0, 0, EPROM_WRITE};
+	int i, tmp;
+	__u8 d[4] = { 0x3f, 0, 0, EPROM_WRITE };
 
-	set_registers( pegasus, EpromOffset, 4, d );
-	enable_eprom_write( pegasus );
-	set_register( pegasus, EpromOffset, index );
-	set_registers( pegasus, EpromData, 2, &data );
-	set_register( pegasus, EpromCtrl, EPROM_WRITE );
+	set_registers(pegasus, EpromOffset, 4, d);
+	enable_eprom_write(pegasus);
+	set_register(pegasus, EpromOffset, index);
+	set_registers(pegasus, EpromData, 2, &data);
+	set_register(pegasus, EpromCtrl, EPROM_WRITE);
 
-	for ( i=0; i < REG_TIMEOUT; i++ ) {
-		get_registers( pegasus, EpromCtrl, 1, &tmp );
-		if ( tmp & EPROM_DONE )
+	for (i = 0; i < REG_TIMEOUT; i++) {
+		get_registers(pegasus, EpromCtrl, 1, &tmp);
+		if (tmp & EPROM_DONE)
 			break;
 	}
-	disable_eprom_write( pegasus );
-	if ( i < REG_TIMEOUT )
-		return	0;
+	disable_eprom_write(pegasus);
+	if (i < REG_TIMEOUT)
+		return 0;
 	warn("%s: failed", __FUNCTION__);
-	return	-1;
+	return -1;
 }
-#endif	/* PEGASUS_WRITE_EEPROM */
+#endif				/* PEGASUS_WRITE_EEPROM */
 
-static inline void get_node_id( pegasus_t *pegasus, __u8 *id )
+static inline void get_node_id(pegasus_t * pegasus, __u8 * id)
 {
-	int	i;
+	int i;
 	__u16 w16;
-	
+
 	for (i = 0; i < 3; i++) {
-		read_eprom_word( pegasus, i, &w16);
-		((__u16 *) id)[i] = cpu_to_le16p (&w16);
+		read_eprom_word(pegasus, i, &w16);
+		((__u16 *) id)[i] = cpu_to_le16p(&w16);
 	}
 }
 
-
-static void set_ethernet_addr( pegasus_t *pegasus )
+static void set_ethernet_addr(pegasus_t * pegasus)
 {
-	__u8	node_id[6];
+	__u8 node_id[6];
 
 	get_node_id(pegasus, node_id);
-	set_registers( pegasus, EthID, sizeof(node_id), node_id );
-	memcpy( pegasus->net->dev_addr, node_id, sizeof(node_id) );
+	set_registers(pegasus, EthID, sizeof(node_id), node_id);
+	memcpy(pegasus->net->dev_addr, node_id, sizeof(node_id));
 }
 
-
-static inline int reset_mac( pegasus_t *pegasus )
+static inline int reset_mac(pegasus_t * pegasus)
 {
-	__u8	data = 0x8;
-	int	i;
+	__u8 data = 0x8;
+	int i;
 
 	set_register(pegasus, EthCtrl1, data);
 	for (i = 0; i < REG_TIMEOUT; i++) {
 		get_registers(pegasus, EthCtrl1, 1, &data);
 		if (~data & 0x08) {
-			if (loopback & 1) 
+			if (loopback & 1)
 				break;
-			if ( mii_mode && (pegasus->features & HAS_HOME_PNA) )
-				set_register( pegasus, Gpio1, 0x34 );
+			if (mii_mode && (pegasus->features & HAS_HOME_PNA))
+				set_register(pegasus, Gpio1, 0x34);
 			else
-				set_register( pegasus, Gpio1, 0x26 );
-			set_register( pegasus, Gpio0, pegasus->features );
-			set_register( pegasus, Gpio0, DEFAULT_GPIO_SET );
+				set_register(pegasus, Gpio1, 0x26);
+			set_register(pegasus, Gpio0, pegasus->features);
+			set_register(pegasus, Gpio0, DEFAULT_GPIO_SET);
 			break;
 		}
 	}
-	if ( i == REG_TIMEOUT )
+	if (i == REG_TIMEOUT)
 		return 1;
 
 	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
 	    usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
-		__u16	auxmode;
+		__u16 auxmode;
 
 		read_mii_word(pegasus, 1, 0x1b, &auxmode);
 		write_mii_word(pegasus, 1, 0x1b, auxmode | 4);
 	}
 	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) {
-		__u16	auxmode;
+		__u16 auxmode;
 		read_mii_word(pegasus, 3, 0x1b, &auxmode);
 		write_mii_word(pegasus, 3, 0x1b, auxmode | 4);
 	}
-	return	0;
+	return 0;
 }
 
-
-static int enable_net_traffic( struct net_device *dev, struct usb_device *usb )
+static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
 {
-	__u16	linkpart, bmsr;
-	__u8	data[4];
+	__u16 linkpart, bmsr;
+	__u8 data[4];
 	pegasus_t *pegasus = dev->priv;
 
 	/* read twice 'cos this is a latch bit */
 	read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr);
 	read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr);
-	if ( !(bmsr & 4) && !loopback ) 
-		warn( "%s: link NOT established (0x%x) - check the cable.",
-			dev->name, bmsr );
-	if ( read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart) )
+	if (read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart))
 		return 2;
-	if ( !(linkpart & 1) )
-		warn( "link partner stat %x", linkpart );
+	if (!(linkpart & 1))
+		warn("link partner stat %x", linkpart);
 
 	data[0] = 0xc9;
 	data[1] = 0;
-	if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL) )
-		data[1] |= 0x20; /* set full duplex */
-	if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF) )
-		data[1] |= 0x10; /* set 100 Mbps */
-	if ( mii_mode )
+	if (linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL))
+		data[1] |= 0x20;	/* set full duplex */
+	if (linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF))
+		data[1] |= 0x10;	/* set 100 Mbps */
+	if (mii_mode)
 		data[1] = 0;
 	data[2] = (loopback & 1) ? 0x09 : 0x01;
-
-	memcpy( pegasus->eth_regs, data, sizeof(data) );
-
-	set_registers( pegasus, EthCtrl0, 3, data );
+	memcpy(pegasus->eth_regs, data, sizeof(data));
+	set_registers(pegasus, EthCtrl0, 3, data);
 
 	return 0;
 }
 
-
-static void read_bulk_callback( struct urb *urb )
+static void read_bulk_callback(struct urb *urb)
 {
 	pegasus_t *pegasus = urb->context;
 	struct net_device *net;
 	int count = urb->actual_length, res;
 	int rx_status;
-	struct sk_buff	*skb;
+	struct sk_buff *skb;
 	__u16 pkt_len;
 
-	if ( !pegasus || !(pegasus->flags & PEGASUS_RUNNING) )
+	if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING))
 		return;
 
 	net = pegasus->net;
-	if ( !netif_device_present(net) )
+	if (!netif_device_present(net))
 		return;
 
-	if ( pegasus->flags & PEGASUS_RX_BUSY ) {
+	if (pegasus->flags & PEGASUS_RX_BUSY) {
 		pegasus->stats.rx_errors++;
 		dbg("pegasus Rx busy");
 		return;
 	}
 	pegasus->flags |= PEGASUS_RX_BUSY;
 
-	switch ( urb->status ) {
-		case 0:
-			break;
-		case -ETIMEDOUT:
-			dbg( "reset MAC" );
-			pegasus->flags &= ~PEGASUS_RX_BUSY;
-			break;
-		default:
-			dbg( "%s: RX status %d", net->name, urb->status );
-			goto goon;
+	switch (urb->status) {
+	case 0:
+		break;
+	case -ETIMEDOUT:
+		dbg("reset MAC");
+		pegasus->flags &= ~PEGASUS_RX_BUSY;
+		break;
+	default:
+		dbg("%s: RX status %d", net->name, urb->status);
+		goto goon;
 	}
 
-	if ( !count )
+	if (!count)
 		goto goon;
 
-	rx_status = le32_to_cpu(*(int *)(pegasus->rx_buff + count - 4));
-	if ( rx_status & 0x000e0000 ) {
+	rx_status = le32_to_cpu(*(int *) (pegasus->rx_buff + count - 4));
+	if (rx_status & 0x000e0000) {
 		dbg("%s: RX packet error %x", net->name, rx_status & 0xe0000);
 		pegasus->stats.rx_errors++;
-		if ( rx_status & 0x060000 )
+		if (rx_status & 0x060000)
 			pegasus->stats.rx_length_errors++;
-		if ( rx_status & 0x080000 )
+		if (rx_status & 0x080000)
 			pegasus->stats.rx_crc_errors++;
-		if ( rx_status & 0x100000 )
+		if (rx_status & 0x100000)
 			pegasus->stats.rx_frame_errors++;
 		goto goon;
 	}
 
 	pkt_len = (rx_status & 0xfff) - 8;
 
-	if ( !(skb = dev_alloc_skb(pkt_len+2)) )
+	if (!(skb = dev_alloc_skb(pkt_len + 2)))
 		goto goon;
 
 	skb->dev = net;
@@ -580,102 +547,100 @@
 	pegasus->stats.rx_bytes += pkt_len;
 
 goon:
-	FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
-			usb_rcvbulkpipe(pegasus->usb, 1),
-			pegasus->rx_buff, PEGASUS_MAX_MTU, 
-			read_bulk_callback, pegasus );
-	if ( (res = usb_submit_urb(pegasus->rx_urb)) )
+	FILL_BULK_URB(pegasus->rx_urb, pegasus->usb,
+		      usb_rcvbulkpipe(pegasus->usb, 1),
+		      pegasus->rx_buff, PEGASUS_MAX_MTU,
+		      read_bulk_callback, pegasus);
+	if ((res = usb_submit_urb(pegasus->rx_urb)))
 		warn("%s: failed submint rx_urb %d", __FUNCTION__, res);
 	pegasus->flags &= ~PEGASUS_RX_BUSY;
 }
 
-
-static void write_bulk_callback( struct urb *urb )
+static void write_bulk_callback(struct urb *urb)
 {
 	pegasus_t *pegasus = urb->context;
 
-	if ( !pegasus || !(pegasus->flags & PEGASUS_RUNNING) )
+	if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING))
 		return;
 
-	if ( !netif_device_present(pegasus->net) )
+	if (!netif_device_present(pegasus->net))
 		return;
-		
-	if ( urb->status )
+
+	if (urb->status)
 		info("%s: TX status %d", pegasus->net->name, urb->status);
 
 	pegasus->net->trans_start = jiffies;
-	netif_wake_queue( pegasus->net );
+	netif_wake_queue(pegasus->net);
 }
 
 #ifdef	PEGASUS_USE_INTR
-static void intr_callback( struct urb *urb )
+static void intr_callback(struct urb *urb)
 {
 	pegasus_t *pegasus = urb->context;
 	struct net_device *net;
-	__u8	*d;
+	__u8 *d;
 
-	if ( !pegasus )
+	if (!pegasus)
 		return;
-		
-	switch ( urb->status ) {
-		case 0:
-			break;
-		case -ENOENT:
-			return;
-		default:
-			info("intr status %d", urb->status);
+
+	switch (urb->status) {
+	case 0:
+		break;
+	case -ENOENT:
+		return;
+	default:
+		info("intr status %d", urb->status);
 	}
 
 	d = urb->transfer_buffer;
 	net = pegasus->net;
-	if ( d[0] & 0xfc ) {
+	if (d[0] & 0xfc) {
 		pegasus->stats.tx_errors++;
-		if ( d[0] & TX_UNDERRUN )
+		if (d[0] & TX_UNDERRUN)
 			pegasus->stats.tx_fifo_errors++;
-		if ( d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT) )
+		if (d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT))
 			pegasus->stats.tx_aborted_errors++;
-		if ( d[0] & LATE_COL )
+		if (d[0] & LATE_COL)
 			pegasus->stats.tx_window_errors++;
-		if ( d[0] & (NO_CARRIER | LOSS_CARRIER) )
+		if (d[0] & (NO_CARRIER | LOSS_CARRIER))
 			pegasus->stats.tx_carrier_errors++;
 	}
 }
 #endif
 
-static void pegasus_tx_timeout( struct net_device *net )
+static void pegasus_tx_timeout(struct net_device *net)
 {
 	pegasus_t *pegasus = net->priv;
 
-	if ( !pegasus )
+	if (!pegasus)
 		return;
-		
+
 	warn("%s: Tx timed out.", net->name);
 	pegasus->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
-	usb_unlink_urb( pegasus->tx_urb );
+	usb_unlink_urb(pegasus->tx_urb);
 	pegasus->stats.tx_errors++;
 }
 
-
-static int pegasus_start_xmit( struct sk_buff *skb, struct net_device *net )
+static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
 {
-	pegasus_t	*pegasus = net->priv;
-	int 	count = ((skb->len+2) & 0x3f) ? skb->len+2 : skb->len+3;
-	int 	res;
+	pegasus_t *pegasus = net->priv;
+	int count = ((skb->len + 2) & 0x3f) ? skb->len + 2 : skb->len + 3;
+	int res;
 	__u16 l16 = skb->len;
-	
-	netif_stop_queue( net );
-		
-	((__u16 *)pegasus->tx_buff)[0] = cpu_to_le16( l16 );
-	memcpy(pegasus->tx_buff+2, skb->data, skb->len);
-	FILL_BULK_URB( pegasus->tx_urb, pegasus->usb,
-			usb_sndbulkpipe(pegasus->usb, 2),
-			pegasus->tx_buff, PEGASUS_MAX_MTU, 
-			write_bulk_callback, pegasus );
+
+	netif_stop_queue(net);
+
+	((__u16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16);
+	memcpy(pegasus->tx_buff + 2, skb->data, skb->len);
+	FILL_BULK_URB(pegasus->tx_urb, pegasus->usb,
+		      usb_sndbulkpipe(pegasus->usb, 2),
+		      pegasus->tx_buff, PEGASUS_MAX_MTU,
+		      write_bulk_callback, pegasus);
 	pegasus->tx_urb->transfer_buffer_length = count;
 	if ((res = usb_submit_urb(pegasus->tx_urb))) {
 		warn("failed tx_urb %d", res);
 		pegasus->stats.tx_errors++;
-		netif_start_queue( net );
+		netif_start_queue(net);
 	} else {
 		pegasus->stats.tx_packets++;
 		pegasus->stats.tx_bytes += skb->len;
@@ -687,42 +652,38 @@
 	return 0;
 }
 
-
-static struct net_device_stats *pegasus_netdev_stats( struct net_device *dev )
+static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
 {
-	return &((pegasus_t *)dev->priv)->stats;
+	return &((pegasus_t *) dev->priv)->stats;
 }
 
-
-static inline void disable_net_traffic( pegasus_t *pegasus )
+static inline void disable_net_traffic(pegasus_t * pegasus)
 {
-	int 	tmp=0;
+	int tmp = 0;
 
-	set_registers( pegasus, EthCtrl0, 2, &tmp );
+	set_registers(pegasus, EthCtrl0, 2, &tmp);
 }
 
-
-static inline void get_interrupt_interval( pegasus_t *pegasus )
+static inline void get_interrupt_interval(pegasus_t * pegasus)
 {
-	__u8	data[2];
+	__u8 data[2];
 
-	read_eprom_word( pegasus, 4, (__u16 *)data );
-	if ( data[1] < 0x80 ) {
-		info( "intr interval will be changed from %ums to %ums",
-		     data[1], 0x80 );
+	read_eprom_word(pegasus, 4, (__u16 *) data);
+	if (data[1] < 0x80) {
+		info("intr interval will be changed from %ums to %ums",
+		     data[1], 0x80);
 		data[1] = 0x80;
 #ifdef	PEGASUS_WRITE_EEPROM
-		write_eprom_word( pegasus, 4, *(__u16 *)data );
+		write_eprom_word(pegasus, 4, *(__u16 *) data);
 #endif
 	}
 	pegasus->intr_interval = data[1];
 }
 
-
 static void set_carrier(struct net_device *net)
 {
-	pegasus_t	*pegasus;
-	short		tmp;
+	pegasus_t *pegasus;
+	short tmp;
 
 	pegasus = net->priv;
 	read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp);
@@ -730,34 +691,32 @@
 		netif_carrier_on(net);
 	else
 		netif_carrier_off(net);
-	
-}
 
+}
 
 static int pegasus_open(struct net_device *net)
 {
-	pegasus_t *pegasus = (pegasus_t *)net->priv;
-	int	res;
-
+	pegasus_t *pegasus = (pegasus_t *) net->priv;
+	int res;
 
 	down(&pegasus->sem);
-	FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
-			usb_rcvbulkpipe(pegasus->usb, 1),
-			pegasus->rx_buff, PEGASUS_MAX_MTU, 
-			read_bulk_callback, pegasus );
-	if ( (res = usb_submit_urb(pegasus->rx_urb)) )
+	FILL_BULK_URB(pegasus->rx_urb, pegasus->usb,
+		      usb_rcvbulkpipe(pegasus->usb, 1),
+		      pegasus->rx_buff, PEGASUS_MAX_MTU,
+		      read_bulk_callback, pegasus);
+	if ((res = usb_submit_urb(pegasus->rx_urb)))
 		warn("%s: failed rx_urb %d", __FUNCTION__, res);
 #ifdef	PEGASUS_USE_INTR
-	FILL_INT_URB( pegasus->intr_urb, pegasus->usb,
-			usb_rcvintpipe(pegasus->usb, 3),
-			pegasus->intr_buff, sizeof(pegasus->intr_buff),
-			intr_callback, pegasus, pegasus->intr_interval );
-	if ( (res = usb_submit_urb(pegasus->intr_urb)) )
+	FILL_INT_URB(pegasus->intr_urb, pegasus->usb,
+		     usb_rcvintpipe(pegasus->usb, 3),
+		     pegasus->intr_buff, sizeof(pegasus->intr_buff),
+		     intr_callback, pegasus, pegasus->intr_interval);
+	if ((res = usb_submit_urb(pegasus->intr_urb)))
 		warn("%s: failed intr_urb %d", __FUNCTION__, res);
 #endif
-	netif_start_queue( net );
+	netif_start_queue(net);
 	pegasus->flags |= PEGASUS_RUNNING;
-	if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
+	if ((res = enable_net_traffic(net, pegasus->usb))) {
 		err("can't enable_net_traffic() - %d", res);
 		res = -EIO;
 		goto exit;
@@ -767,129 +726,126 @@
 	res = 0;
 exit:
 	up(&pegasus->sem);
-	
+
 	return res;
 }
 
-
-static int pegasus_close( struct net_device *net )
+static int pegasus_close(struct net_device *net)
 {
-	pegasus_t	*pegasus = net->priv;
+	pegasus_t *pegasus = net->priv;
 
 	down(&pegasus->sem);
 	pegasus->flags &= ~PEGASUS_RUNNING;
-	netif_stop_queue( net );
-	if ( !(pegasus->flags & PEGASUS_UNPLUG) )
-		disable_net_traffic( pegasus );
-
-	usb_unlink_urb( pegasus->rx_urb );
-	usb_unlink_urb( pegasus->tx_urb );
-	usb_unlink_urb( pegasus->ctrl_urb );
+	netif_stop_queue(net);
+	if (!(pegasus->flags & PEGASUS_UNPLUG))
+		disable_net_traffic(pegasus);
+
+	usb_unlink_urb(pegasus->rx_urb);
+	usb_unlink_urb(pegasus->tx_urb);
+	usb_unlink_urb(pegasus->ctrl_urb);
 #ifdef	PEGASUS_USE_INTR
-	usb_unlink_urb( pegasus->intr_urb );
+	usb_unlink_urb(pegasus->intr_urb);
 #endif
 	up(&pegasus->sem);
-	
+
 	return 0;
 }
 
-
 static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
 {
-	pegasus_t	*pegasus;
-	int		cmd;
-	char		tmp[128];
+	pegasus_t *pegasus;
+	int cmd;
+	char tmp[128];
 
 	pegasus = net->priv;
-	if (get_user(cmd, (int *)uaddr))
+	if (get_user(cmd, (int *) uaddr))
 		return -EFAULT;
 	switch (cmd) {
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
-		strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
-		sprintf(tmp, "usb%d:%d", pegasus->usb->bus->busnum,
-		        pegasus->usb->devnum);
-		strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
-		if (copy_to_user(uaddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_GSET: {
-		struct ethtool_cmd ecmd;
-		short	lpa, bmcr;
-
-		if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
-			return -EFAULT;
-		ecmd.supported = (SUPPORTED_10baseT_Half |
-		                 SUPPORTED_10baseT_Full |
-		                 SUPPORTED_100baseT_Half |
-		                 SUPPORTED_100baseT_Full |
-		                 SUPPORTED_Autoneg |
-		                 SUPPORTED_TP |
-		                 SUPPORTED_MII);
-		ecmd.port = PORT_TP;
-		ecmd.transceiver = XCVR_INTERNAL;
-		ecmd.phy_address = pegasus->phy;
-		read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr);
-		read_mii_word(pegasus, pegasus->phy, MII_LPA, &lpa);
-		if (bmcr & BMCR_ANENABLE) {
-			ecmd.autoneg = AUTONEG_ENABLE;
-			ecmd.speed = lpa & (LPA_100HALF|LPA_100FULL) ?
-		                     SPEED_100 : SPEED_10;
-			if (ecmd.speed == SPEED_100)
-				ecmd.duplex = lpa & LPA_100FULL ?
-				              DUPLEX_FULL : DUPLEX_HALF;
-			else
-				ecmd.duplex = lpa & LPA_10FULL ?
-				              DUPLEX_FULL : DUPLEX_HALF;
-		} else {
-			ecmd.autoneg = AUTONEG_DISABLE;
-			ecmd.speed = bmcr & BMCR_SPEED100 ? 
-			             SPEED_100 : SPEED_10;
-			ecmd.duplex = bmcr & BMCR_FULLDPLX ?
-			              DUPLEX_FULL : DUPLEX_HALF;
+	case ETHTOOL_GDRVINFO:{
+			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+			strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
+			strncpy(info.version, DRIVER_VERSION,
+				ETHTOOL_BUSINFO_LEN);
+			sprintf(tmp, "usb%d:%d", pegasus->usb->bus->busnum,
+				pegasus->usb->devnum);
+			strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
+			if (copy_to_user(uaddr, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+		}
+	case ETHTOOL_GSET:{
+			struct ethtool_cmd ecmd;
+			short lpa, bmcr;
+
+			if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
+				return -EFAULT;
+			ecmd.supported = (SUPPORTED_10baseT_Half |
+					  SUPPORTED_10baseT_Full |
+					  SUPPORTED_100baseT_Half |
+					  SUPPORTED_100baseT_Full |
+					  SUPPORTED_Autoneg |
+					  SUPPORTED_TP | SUPPORTED_MII);
+			ecmd.port = PORT_TP;
+			ecmd.transceiver = XCVR_INTERNAL;
+			ecmd.phy_address = pegasus->phy;
+			read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr);
+			read_mii_word(pegasus, pegasus->phy, MII_LPA, &lpa);
+			if (bmcr & BMCR_ANENABLE) {
+				ecmd.autoneg = AUTONEG_ENABLE;
+				ecmd.speed = lpa & (LPA_100HALF | LPA_100FULL) ?
+				    SPEED_100 : SPEED_10;
+				if (ecmd.speed == SPEED_100)
+					ecmd.duplex = lpa & LPA_100FULL ?
+					    DUPLEX_FULL : DUPLEX_HALF;
+				else
+					ecmd.duplex = lpa & LPA_10FULL ?
+					    DUPLEX_FULL : DUPLEX_HALF;
+			} else {
+				ecmd.autoneg = AUTONEG_DISABLE;
+				ecmd.speed = bmcr & BMCR_SPEED100 ?
+				    SPEED_100 : SPEED_10;
+				ecmd.duplex = bmcr & BMCR_FULLDPLX ?
+				    DUPLEX_FULL : DUPLEX_HALF;
+			}
+			if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
+				return -EFAULT;
+
+			return 0;
+		}
+	case ETHTOOL_SSET:{
+			return -EOPNOTSUPP;
+		}
+	case ETHTOOL_GLINK:{
+			struct ethtool_value edata = { ETHTOOL_GLINK };
+			edata.data = netif_carrier_ok(net);
+			if (copy_to_user(uaddr, &edata, sizeof(edata)))
+				return -EFAULT;
+			return 0;
 		}
-		if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		
-		return 0;
-	}
-	case ETHTOOL_SSET: {
-		return -EOPNOTSUPP;
-	}
-	case ETHTOOL_GLINK: {
-		struct ethtool_value edata = {ETHTOOL_GLINK};
-		edata.data = netif_carrier_ok(net);
-		if (copy_to_user(uaddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
 	default:
 		return -EOPNOTSUPP;
 	}
 }
 
-
-static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd )
+static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
 {
-	__u16 *data = (__u16 *)&rq->ifr_data;
-	pegasus_t	*pegasus = net->priv;
-	int	res;
+	__u16 *data = (__u16 *) & rq->ifr_data;
+	pegasus_t *pegasus = net->priv;
+	int res;
 
 	down(&pegasus->sem);
-	switch(cmd) {
+	switch (cmd) {
 	case SIOCETHTOOL:
 		res = pegasus_ethtool_ioctl(net, rq->ifr_data);
 		break;
 	case SIOCDEVPRIVATE:
 		data[0] = pegasus->phy;
-	case SIOCDEVPRIVATE+1:
-		read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
+	case SIOCDEVPRIVATE + 1:
+		read_mii_word(pegasus, data[0], data[1] & 0x1f, &data[3]);
 		res = 0;
 		break;
-	case SIOCDEVPRIVATE+2:
-		if ( !capable(CAP_NET_ADMIN) ) {
+	case SIOCDEVPRIVATE + 2:
+		if (!capable(CAP_NET_ADMIN)) {
 			up(&pegasus->sem);
 			return -EPERM;
 		}
@@ -904,8 +860,7 @@
 	return res;
 }
 
-
-static void pegasus_set_multicast( struct net_device *net )
+static void pegasus_set_multicast(struct net_device *net)
 {
 	pegasus_t *pegasus = net->priv;
 
@@ -915,7 +870,7 @@
 		pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS;
 		info("%s: Promiscuous mode enabled", net->name);
 	} else if ((net->mc_count > multicast_filter_limit) ||
-			(net->flags & IFF_ALLMULTI)) {
+		   (net->flags & IFF_ALLMULTI)) {
 		pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST;
 		pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
 		info("%s set allmulti", net->name);
@@ -925,100 +880,92 @@
 	}
 
 	pegasus->flags |= ETH_REGS_CHANGE;
-	ctrl_callback( pegasus->ctrl_urb );
+	ctrl_callback(pegasus->ctrl_urb);
 
 	netif_wake_queue(net);
 }
 
-
-static __u8 mii_phy_probe( pegasus_t *pegasus )
+static __u8 mii_phy_probe(pegasus_t * pegasus)
 {
-	int	i;
-	__u16	tmp;
+	int i;
+	__u16 tmp;
 
-	for ( i=0; i < 32; i++ ) {
-		read_mii_word( pegasus, i, MII_BMSR, &tmp );
-		if ( tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0 )
+	for (i = 0; i < 32; i++) {
+		read_mii_word(pegasus, i, MII_BMSR, &tmp);
+		if (tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0)
 			continue;
 		else
-			return	i;
+			return i;
 	}
 
-	return	0xff;
+	return 0xff;
 }
 
-
-static inline void setup_pegasus_II( pegasus_t *pegasus )
+static inline void setup_pegasus_II(pegasus_t * pegasus)
 {
-	set_register( pegasus, Reg1d, 0 );
-	set_register( pegasus, Reg7b, 2 );
-	if ( pegasus->features & HAS_HOME_PNA  && mii_mode )
-		set_register( pegasus, Reg81, 6 );
+	set_register(pegasus, Reg1d, 0);
+	set_register(pegasus, Reg7b, 2);
+	if (pegasus->features & HAS_HOME_PNA && mii_mode)
+		set_register(pegasus, Reg81, 6);
 	else
-		set_register( pegasus, Reg81, 2 );
+		set_register(pegasus, Reg81, 2);
 }
 
-
-static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
-			     const struct usb_device_id *id)
+static void *pegasus_probe(struct usb_device *dev, unsigned int ifnum,
+			   const struct usb_device_id *id)
 {
-	struct net_device	*net;
-	pegasus_t		*pegasus;
-	int			dev_index = id - pegasus_ids;
+	struct net_device *net;
+	pegasus_t *pegasus;
+	int dev_index = id - pegasus_ids;
 
 	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
 		err("usb_set_configuration() failed");
 		return NULL;
 	}
 
-	down(&gsem);
-	if(!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) {
+	if (!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) {
 		err("out of memory allocating device structure");
-		goto exit;
+		return NULL;
 	}
 
-	usb_inc_dev_use( dev );
+	usb_inc_dev_use(dev);
 	memset(pegasus, 0, sizeof(struct pegasus));
 	pegasus->dev_index = dev_index;
-	init_waitqueue_head( &pegasus->ctrl_wait );
+	init_waitqueue_head(&pegasus->ctrl_wait);
 
 	pegasus->ctrl_urb = usb_alloc_urb(0);
 	if (!pegasus->ctrl_urb) {
-		kfree (pegasus);
-		pegasus = NULL;
-		goto exit;
+		kfree(pegasus);
+		return NULL;
 	}
 	pegasus->rx_urb = usb_alloc_urb(0);
 	if (!pegasus->rx_urb) {
-		usb_free_urb (pegasus->ctrl_urb);
-		kfree (pegasus);
-		pegasus = NULL;
-		goto exit;
+		usb_free_urb(pegasus->ctrl_urb);
+		kfree(pegasus);
+		return NULL;
 	}
 	pegasus->tx_urb = usb_alloc_urb(0);
 	if (!pegasus->tx_urb) {
-		usb_free_urb (pegasus->rx_urb);
-		usb_free_urb (pegasus->ctrl_urb);
-		kfree (pegasus);
-		pegasus = NULL;
-		goto exit;
+		usb_free_urb(pegasus->rx_urb);
+		usb_free_urb(pegasus->ctrl_urb);
+		kfree(pegasus);
+		return NULL;
 	}
 	pegasus->intr_urb = usb_alloc_urb(0);
 	if (!pegasus->intr_urb) {
-		usb_free_urb (pegasus->tx_urb);
-		usb_free_urb (pegasus->rx_urb);
-		usb_free_urb (pegasus->ctrl_urb);
-		kfree (pegasus);
-		pegasus = NULL;
-		goto exit;
+		usb_free_urb(pegasus->tx_urb);
+		usb_free_urb(pegasus->rx_urb);
+		usb_free_urb(pegasus->ctrl_urb);
+		kfree(pegasus);
+		return NULL;
 	}
 
-	net = init_etherdev( NULL, 0 );
-	if ( !net ) {
-		usb_free_urb (pegasus->tx_urb);
-		usb_free_urb (pegasus->rx_urb);
-		usb_free_urb (pegasus->ctrl_urb);
-		kfree( pegasus );
+	net = init_etherdev(NULL, 0);
+	if (!net) {
+		usb_free_urb(pegasus->tx_urb);
+		usb_free_urb(pegasus->rx_urb);
+		usb_free_urb(pegasus->ctrl_urb);
+		kfree(pegasus);
 		return NULL;
 	}
 
@@ -1040,32 +987,32 @@
 
 	pegasus->features = usb_dev_id[dev_index].private;
 #ifdef	PEGASUS_USE_INTR
-	get_interrupt_interval( pegasus );
+	get_interrupt_interval(pegasus);
 #endif
-	if ( reset_mac(pegasus) ) {
+	if (reset_mac(pegasus)) {
 		err("can't reset MAC");
-		unregister_netdev( pegasus->net );
-		usb_free_urb (pegasus->tx_urb);
-		usb_free_urb (pegasus->rx_urb);
-		usb_free_urb (pegasus->ctrl_urb);
+		unregister_netdev(pegasus->net);
+		usb_free_urb(pegasus->tx_urb);
+		usb_free_urb(pegasus->rx_urb);
+		usb_free_urb(pegasus->ctrl_urb);
 		kfree(pegasus->net);
 		kfree(pegasus);
 		pegasus = NULL;
 		goto exit;
 	}
 
-	info( "%s: %s", net->name, usb_dev_id[dev_index].name );
+	info("%s: %s", net->name, usb_dev_id[dev_index].name);
 
-	set_ethernet_addr( pegasus );
+	set_ethernet_addr(pegasus);
 
-	if ( pegasus->features & PEGASUS_II ) {
-		info( "setup Pegasus II specific registers" );
-		setup_pegasus_II( pegasus );
-	}
-	
-	pegasus->phy = mii_phy_probe( pegasus );
-	if ( pegasus->phy == 0xff ) {
-		warn( "can't locate MII phy, using default" );
+	if (pegasus->features & PEGASUS_II) {
+		info("setup Pegasus II specific registers");
+		setup_pegasus_II(pegasus);
+	}
+
+	pegasus->phy = mii_phy_probe(pegasus);
+	if (pegasus->phy == 0xff) {
+		warn("can't locate MII phy, using default");
 		pegasus->phy = 1;
 	}
 
@@ -1074,19 +1021,18 @@
 	return pegasus;
 }
 
-
-static void pegasus_disconnect( struct usb_device *dev, void *ptr )
+static void pegasus_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct pegasus *pegasus = ptr;
 
-	if ( !pegasus ) {
+	if (!pegasus) {
 		warn("unregistering non-existant device");
 		return;
 	}
 
 	pegasus->flags |= PEGASUS_UNPLUG;
-	unregister_netdev( pegasus->net );
-	usb_dec_dev_use( dev );
+	unregister_netdev(pegasus->net);
+	usb_dec_dev_use(dev);
 	usb_unlink_urb(pegasus->intr_urb);
 	usb_unlink_urb(pegasus->tx_urb);
 	usb_unlink_urb(pegasus->rx_urb);
@@ -1095,12 +1041,11 @@
 	usb_free_urb(pegasus->tx_urb);
 	usb_free_urb(pegasus->rx_urb);
 	usb_free_urb(pegasus->ctrl_urb);
-	kfree( pegasus->net );
-	kfree( pegasus );
+	kfree(pegasus->net);
+	kfree(pegasus);
 	pegasus = NULL;
 }
 
-
 static struct usb_driver pegasus_driver = {
 	name:		"pegasus",
 	probe:		pegasus_probe,
@@ -1111,13 +1056,13 @@
 int __init pegasus_init(void)
 {
 	info(DRIVER_VERSION ":" DRIVER_DESC);
-	return usb_register( &pegasus_driver );
+	return usb_register(&pegasus_driver);
 }
 
 void __exit pegasus_exit(void)
 {
-	usb_deregister( &pegasus_driver );
+	usb_deregister(&pegasus_driver);
 }
 
-module_init( pegasus_init );
-module_exit( pegasus_exit );
+module_init(pegasus_init);
+module_exit(pegasus_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/pegasus.h linux-2.4.20/drivers/usb/pegasus.h
--- linux-2.4.19/drivers/usb/pegasus.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/pegasus.h	2002-10-29 11:18:50.000000000 +0000
@@ -2,18 +2,9 @@
  * Copyright (c) 1999-2002 Petko Manolov - Petkan (petkan@users.sourceforge.net)
  *
  * 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.
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
  *
- * 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
  */
 
 
@@ -99,7 +90,7 @@
 	int			dev_index;
 	int			intr_interval;
 	struct urb		*ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
-	devrequest		dr;
+	struct usb_ctrlrequest	dr;
 	wait_queue_head_t	ctrl_wait;
 	struct semaphore	sem;
 	unsigned char		rx_buff[PEGASUS_MAX_MTU];
@@ -122,6 +113,7 @@
 #define	VENDOR_ABOCOM		0x07b8
 #define	VENDOR_ACCTON		0x083a
 #define	VENDOR_ADMTEK		0x07a6
+#define	VENDOR_AEILAB		0x3334
 #define	VENDOR_ALLIEDTEL	0x07c9
 #define	VENDOR_BELKIN		0x050d
 #define	VENDOR_BILLIONTON	0x08dd
@@ -177,6 +169,8 @@
 		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
 PEGASUS_DEV( "ADMtek AN986A USB MAC", VENDOR_ADMTEK, 0x1986,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "AEI USB Fast Ethernet Adapter", VENDOR_AEILAB, 0x1701,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121,
@@ -193,6 +187,8 @@
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004,
 		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "Corega FEter", VENDOR_COREGA, 0x000d,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
 		LINKSYS_GPIO_RESET )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4002,
@@ -207,7 +203,7 @@
 		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
 PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1,
 		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "ELCON EPLC10Mi USB to Powerline Adapter", VENDOR_ELCON, 0x0002,
+PEGASUS_DEV( "GOLDPFEIL USB Adapter", VENDOR_ELCON, 0x0002,
 		DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
 PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
 		DEFAULT_GPIO_RESET )
@@ -256,6 +252,6 @@
 PEGASUS_DEV( "SOHOware NUB110 Ethernet", VENDOR_SOHOWARE, 0x9110,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
-		DEFAULT_GPIO_RESET )
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 
 #endif	/* PEGASUS_DEV */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/printer.c linux-2.4.20/drivers/usb/printer.c
--- linux-2.4.19/drivers/usb/printer.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/printer.c	2002-10-29 11:18:34.000000000 +0000
@@ -257,7 +257,7 @@
  * Get and print printer errors.
  */
 
-static char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" };
+static char *usblp_messages[] = { "ok", "out of paper", "off-line", "unknown error" };
 
 static int usblp_check_status(struct usblp *usblp, int err)
 {
@@ -388,7 +388,8 @@
 {
 	struct usblp *usblp = file->private_data;
 	int length, err, i;
-	unsigned char status, newChannel;
+	unsigned char lpstatus, newChannel;
+	int status;
 	int twoints[2];
 	int retval = 0;
 
@@ -539,12 +540,13 @@
 		switch (cmd) {
 
 			case LPGETSTATUS:
-				if (usblp_read_status(usblp, &status)) {
+				if (usblp_read_status(usblp, &lpstatus)) {
 					err("usblp%d: failed reading printer status", usblp->minor);
 					retval = -EIO;
 					goto done;
 				}
-				if (copy_to_user ((unsigned char *)arg, &status, 1))
+				status = lpstatus;
+				if (copy_to_user ((int *)arg, &status, sizeof(int)))
 					retval = -EFAULT;
 				break;
 
@@ -560,7 +562,8 @@
 static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct usblp *usblp = file->private_data;
-	int timeout, err = 0, writecount = 0;
+	int timeout, err = 0;
+	size_t writecount = 0;
 
 	while (writecount < count) {
 
@@ -616,10 +619,9 @@
 							 (count - writecount) : USBLP_BUF_SIZE;
 
 		if (copy_from_user(usblp->writeurb.transfer_buffer, buffer + writecount,
-				usblp->writeurb.transfer_buffer_length))
-		{
+				usblp->writeurb.transfer_buffer_length)) {
 			up(&usblp->sem);
-			return writecount?writecount:-EFAULT;
+			return writecount ? writecount : -EFAULT;
 		}
 
 		usblp->writeurb.dev = usblp->dev;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/pwc-if.c linux-2.4.20/drivers/usb/pwc-if.c
--- linux-2.4.19/drivers/usb/pwc-if.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/pwc-if.c	2002-10-29 11:18:49.000000000 +0000
@@ -65,7 +65,7 @@
 /* Function prototypes and driver templates */
 
 /* hotplug device table support */
-static __devinitdata struct usb_device_id pwc_device_table [] = {
+static struct usb_device_id pwc_device_table [] = {
 	{ USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
 	{ USB_DEVICE(0x0471, 0x0303) },
 	{ USB_DEVICE(0x0471, 0x0304) },
@@ -179,60 +179,25 @@
 /***************************************************************************/
 /* Private functions */
 
-/* Memory management functions, nicked from cpia.c, which nicked them from
-   bttv.c. So far, I've counted duplication of this code 6 times 
-   (bttv, cpia, ibmcam, ov511, pwc, ieee1394).
- */
-
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
-        unsigned long ret = 0UL;
-	pmd_t *pmd;
-	pte_t *ptep, pte;
-  
-	if (!pgd_none(*pgd)) {
-                pmd = pmd_offset(pgd, adr);
-                if (!pmd_none(*pmd)) {
-                        ptep = pte_offset(pmd, adr);
-                        pte = *ptep;
-                        if(pte_present(pte)) {
-				ret  = (unsigned long) page_address(pte_page(pte));
-				ret |= (adr & (PAGE_SIZE - 1));
-				
-			}
-                }
-        }
-	return ret;
-}
-
-
-
 /* Here we want the physical address of the memory.
- * This is used when initializing the contents of the
- * area and marking the pages as reserved.
+ * This is used when initializing the contents of the area.
  */
 static inline unsigned long kvirt_to_pa(unsigned long adr) 
 {
-        unsigned long va, kva, ret;
+        unsigned long kva, ret;
 
-        va = VMALLOC_VMADDR(adr);
-        kva = uvirt_to_kva(pgd_offset_k(va), va);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
 	ret = __pa(kva);
         return ret;
 }
 
-static void * rvmalloc(signed long size)
+static void * rvmalloc(unsigned long size)
 {
 	void * mem;
-	unsigned long adr, page;
+	unsigned long adr;
 
-        /* Round it off to PAGE_SIZE */
-        size += (PAGE_SIZE - 1);
-        size &= ~(PAGE_SIZE - 1);	
-        
+	size=PAGE_ALIGN(size);
         mem=vmalloc_32(size);
 	if (mem) 
 	{
@@ -240,8 +205,7 @@
 	        adr=(unsigned long) mem;
 		while (size > 0) 
                 {
-	                page = kvirt_to_pa(adr);
-			mem_map_reserve(virt_to_page(__va(page)));
+			mem_map_reserve(vmalloc_to_page((void *)adr));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -249,20 +213,16 @@
 	return mem;
 }
 
-static void rvfree(void * mem, signed long size)
+static void rvfree(void * mem, unsigned long size)
 {
-        unsigned long adr, page;
-        
-        /* Round it off to PAGE_SIZE */
-        size += (PAGE_SIZE - 1);
-        size &= ~(PAGE_SIZE - 1);	
+        unsigned long adr;
+
 	if (mem) 
 	{
 	        adr=(unsigned long) mem;
-		while (size > 0) 
+		while ((long) size > 0) 
                 {
-	                page = kvirt_to_pa(adr);
-			mem_map_unreserve(virt_to_page(__va(page)));
+			mem_map_unreserve(vmalloc_to_page((void *)adr));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/rtl8150.c linux-2.4.20/drivers/usb/rtl8150.c
--- linux-2.4.19/drivers/usb/rtl8150.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/rtl8150.c	2002-10-29 11:18:39.000000000 +0000
@@ -1,11 +1,9 @@
 /*
- * Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net)
- *
- *	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.
+ *  Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net)
  *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * version 2 as published by the Free Software Foundation.
  */
 
 #include <linux/config.h>
@@ -22,14 +20,11 @@
 #include <linux/init.h>
 #include <asm/uaccess.h>
 
-
-
 /* Version Information */
-#define DRIVER_VERSION "v0.4.0 (2002/03/28)"
+#define DRIVER_VERSION "v0.4.1 (2002/07/22)"
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "rtl8150 based usb-ethernet driver"
 
-
 #define	IRD			0x0120
 #define	MAR			0x0126
 #define	CR			0x012e
@@ -69,49 +64,48 @@
 #define	RX_REG_SET		1
 #define	RTL8150_UNPLUG		2
 
-
 /* Define these values to match your device */
 #define VENDOR_ID_REALTEK		0x0bda
+#define	VENDOR_ID_MELCO			0x0411
+
 #define PRODUCT_ID_RTL8150		0x8150
+#define	PRODUCT_ID_LUAKTX		0x0012
 
 /* table of devices that work with this driver */
-static struct usb_device_id rtl8150_table [] = {
-	{ USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150) },
-	{ }				
+static struct usb_device_id rtl8150_table[] = {
+	{USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)},
+	{USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)},
+	{}
 };
 
-MODULE_DEVICE_TABLE (usb, rtl8150_table);
-
+MODULE_DEVICE_TABLE(usb, rtl8150_table);
 
 struct rtl8150 {
-	unsigned long		flags;
-	struct usb_device	*udev;
-	struct usb_interface	*interface;
-	struct semaphore	sem;
-	struct net_device_stats	stats;
-	struct net_device	*netdev;
-	struct urb		*rx_urb, *tx_urb, *intr_urb, *ctrl_urb;
-	devrequest		dr;
-	int			intr_interval;
-	u16			rx_creg;
-	u8			rx_buff[RTL8150_MAX_MTU];
-	u8			tx_buff[RTL8150_MAX_MTU];
-	u8			intr_buff[8];
-	u8			phy;
+	unsigned int flags;
+	struct usb_device *udev;
+	struct usb_interface *interface;
+	struct semaphore sem;
+	struct net_device_stats stats;
+	struct net_device *netdev;
+	struct urb *rx_urb, *tx_urb, *intr_urb, *ctrl_urb;
+	struct usb_ctrlrequest dr;
+	int intr_interval;
+	u16 rx_creg;
+	u8 rx_buff[RTL8150_MAX_MTU];
+	u8 tx_buff[RTL8150_MAX_MTU];
+	u8 intr_buff[8];
+	u8 phy;
 };
 
-typedef	struct rtl8150	rtl8150_t;
-
+typedef struct rtl8150 rtl8150_t;
 
 /* the global usb devfs handle */
 extern devfs_handle_t usb_devfs_handle;
 unsigned long multicast_filter_limit = 32;
 
-
 static void rtl8150_disconnect(struct usb_device *dev, void *ptr);
-static void * rtl8150_probe(struct usb_device *dev, unsigned int ifnum,
-			    const struct usb_device_id *id);
-
+static void *rtl8150_probe(struct usb_device *dev, unsigned int ifnum,
+			   const struct usb_device_id *id);
 
 static struct usb_driver rtl8150_driver = {
 	name:		"rtl8150",
@@ -120,33 +114,29 @@
 	id_table:	rtl8150_table,
 };
 
-
-
 /*
 **
 **	device related part of the code
 **
 */
-static int get_registers(rtl8150_t *dev, u16 indx, u16 size, void *data)
+static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
 {
-	return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev,0),
-				RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
-				indx, 0, data, size, HZ/2);
+	return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+			       RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
+			       indx, 0, data, size, HZ / 2);
 }
 
-
-static int set_registers(rtl8150_t *dev, u16 indx, u16 size, void *data)
+static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
 {
-	return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev,0),
-				RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
-				indx, 0, data, size, HZ/2);
+	return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+			       RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
+			       indx, 0, data, size, HZ / 2);
 }
 
-
 static void ctrl_callback(struct urb *urb)
 {
-	rtl8150_t	*dev;
-	
+	rtl8150_t *dev;
+
 	switch (urb->status) {
 	case 0:
 		break;
@@ -161,22 +151,22 @@
 	clear_bit(RX_REG_SET, &dev->flags);
 }
 
-
-static int async_set_registers(rtl8150_t *dev, u16 indx, u16 size, void *data)
+static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
 {
-	int	ret;
+	int ret;
 
 	if (test_bit(RX_REG_SET, &dev->flags))
 		return -EAGAIN;
-	
-	dev->dr.requesttype = RTL8150_REQT_WRITE;
-	dev->dr.request = RTL8150_REQ_SET_REGS;
-	dev->dr.value = cpu_to_le16(indx);
-	dev->dr.index = 0;
-	dev->dr.length = cpu_to_le16(2);
+
+	dev->dr.bRequestType = RTL8150_REQT_WRITE;
+	dev->dr.bRequest = RTL8150_REQ_SET_REGS;
+	dev->dr.wValue = cpu_to_le16(indx);
+	dev->dr.wIndex = 0;
+	dev->dr.wLength = cpu_to_le16(2);
 	dev->ctrl_urb->transfer_buffer_length = 2;
-	FILL_CONTROL_URB(dev->ctrl_urb, dev->udev, usb_sndctrlpipe(dev->udev,0),
-	                 (char*)&dev->dr, &dev->rx_creg, 2, ctrl_callback, dev);
+	FILL_CONTROL_URB(dev->ctrl_urb, dev->udev,
+			 usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr,
+			 &dev->rx_creg, 2, ctrl_callback, dev);
 	if ((ret = usb_submit_urb(dev->ctrl_urb)))
 		err("control request submission failed: %d", ret);
 	else
@@ -185,11 +175,10 @@
 	return ret;
 }
 
-
-static int read_mii_word(rtl8150_t *dev, u8 phy, __u8 indx, u16 *reg)
+static int read_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 * reg)
 {
-	int	i;
-	u8	data[3], tmp;
+	int i;
+	u8 data[3], tmp;
 
 	data[0] = phy;
 	data[1] = data[2] = 0;
@@ -204,17 +193,16 @@
 
 	if (i < HZ) {
 		get_registers(dev, PHYDAT, 2, data);
-		*reg = le16_to_cpup(data);
+		*reg = le16_to_cpup((u16 *)data);
 		return 0;
 	} else
 		return 1;
 }
 
-
-static int write_mii_word(rtl8150_t *dev, u8 phy, __u8 indx, u16 reg)
+static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg)
 {
-	int	i;
-	u8	data[3], tmp;
+	int i;
+	u8 data[3], tmp;
 
 	data[0] = phy;
 	*(data + 1) = cpu_to_le16p(&reg);
@@ -225,7 +213,7 @@
 	set_registers(dev, PHYCNT, 1, &tmp);
 	do {
 		get_registers(dev, PHYCNT, 1, data);
-	} while((data[0] & PHY_GO) && (i++ < HZ));
+	} while ((data[0] & PHY_GO) && (i++ < HZ));
 
 	if (i < HZ)
 		return 0;
@@ -233,31 +221,28 @@
 		return 1;
 }
 
-
-static inline void set_ethernet_addr(rtl8150_t *dev)
+static inline void set_ethernet_addr(rtl8150_t * dev)
 {
-	u8	node_id[6];
+	u8 node_id[6];
 
 	get_registers(dev, IRD, sizeof(node_id), node_id);
 	memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
 }
 
-
-static int rtl8150_reset(rtl8150_t *dev)
+static int rtl8150_reset(rtl8150_t * dev)
 {
-	u8	data=0x10;
-	int	i=HZ;
+	u8 data = 0x10;
+	int i = HZ;
 
 	set_registers(dev, CR, 1, &data);
 	do {
 		get_registers(dev, CR, 1, &data);
 	} while ((data & 0x10) && --i);
-	
+
 	return (i > 0) ? 0 : -1;
 }
 
-
-static int alloc_all_urbs(rtl8150_t *dev)
+static int alloc_all_urbs(rtl8150_t * dev)
 {
 	dev->rx_urb = usb_alloc_urb(0);
 	if (!dev->rx_urb)
@@ -284,8 +269,7 @@
 	return 1;
 }
 
-
-static void free_all_urbs(rtl8150_t *dev)
+static void free_all_urbs(rtl8150_t * dev)
 {
 	usb_free_urb(dev->rx_urb);
 	usb_free_urb(dev->tx_urb);
@@ -293,8 +277,7 @@
 	usb_free_urb(dev->ctrl_urb);
 }
 
-
-static void unlink_all_urbs(rtl8150_t *dev)
+static void unlink_all_urbs(rtl8150_t * dev)
 {
 	usb_unlink_urb(dev->rx_urb);
 	usb_unlink_urb(dev->tx_urb);
@@ -302,14 +285,13 @@
 	usb_unlink_urb(dev->ctrl_urb);
 }
 
-
 static void read_bulk_callback(struct urb *urb)
 {
-	rtl8150_t	*dev;
-	int		pkt_len, res;
-	struct sk_buff	*skb;
+	rtl8150_t *dev;
+	int pkt_len, res;
+	struct sk_buff *skb;
 	struct net_device *netdev;
-	u16		rx_stat;
+	u16 rx_stat;
 
 	dev = urb->context;
 	if (!dev) {
@@ -333,11 +315,11 @@
 		warn("Rx status %d", urb->status);
 		goto goon;
 	}
-	
+
 	pkt_len = urb->actual_length - 4;
-	rx_stat = le16_to_cpu(*(u16 *)(dev->rx_buff + pkt_len));
+	rx_stat = le16_to_cpu(*(u16 *) (dev->rx_buff + pkt_len));
 
-	if (!(skb = dev_alloc_skb(pkt_len + 2))) 
+	if (!(skb = dev_alloc_skb(pkt_len + 2)))
 		goto goon;
 	skb->dev = netdev;
 	skb_reserve(skb, 2);
@@ -348,16 +330,15 @@
 	dev->stats.rx_packets++;
 	dev->stats.rx_bytes += pkt_len;
 goon:
-	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev,1),
-	              dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
-	if ((res=usb_submit_urb(dev->rx_urb)))
+	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
+		      dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
+	if ((res = usb_submit_urb(dev->rx_urb)))
 		warn("%s: Rx urb submission failed %d", netdev->name, res);
 }
 
-
 static void write_bulk_callback(struct urb *urb)
 {
-	rtl8150_t	*dev;
+	rtl8150_t *dev;
 
 	dev = urb->context;
 	if (!dev)
@@ -370,36 +351,32 @@
 	netif_wake_queue(dev->netdev);
 }
 
-
 void intr_callback(struct urb *urb)
 {
-	rtl8150_t	*dev;
+	rtl8150_t *dev;
 
 	dev = urb->context;
 	if (!dev)
 		return;
 	switch (urb->status) {
-		case 0:
-			break;
-		case -ENOENT:
-			return;
-		default:
-			info("%s: intr status %d", dev->netdev->name,
-			     urb->status);
+	case 0:
+		break;
+	case -ENOENT:
+		return;
+	default:
+		info("%s: intr status %d", dev->netdev->name, urb->status);
 	}
 }
 
-
 /*
 **
 **	network related part of the code
 **
 */
 
-
-static int enable_net_traffic(rtl8150_t *dev)
+static int enable_net_traffic(rtl8150_t * dev)
 {
-	u8	cr, tcr, rcr, msr;
+	u8 cr, tcr, rcr, msr;
 
 	if (rtl8150_reset(dev)) {
 		warn("%s - device reset failed", __FUNCTION__);
@@ -415,26 +392,23 @@
 	return 0;
 }
 
-
-static void disable_net_traffic(rtl8150_t *dev)
+static void disable_net_traffic(rtl8150_t * dev)
 {
-	u8	cr;
+	u8 cr;
 
 	get_registers(dev, CR, 1, &cr);
 	cr &= 0xf3;
 	set_registers(dev, CR, 1, &cr);
 }
 
-
 static struct net_device_stats *rtl8150_netdev_stats(struct net_device *dev)
 {
-	return &((rtl8150_t *)dev->priv)->stats;
+	return &((rtl8150_t *) dev->priv)->stats;
 }
 
-
 static void rtl8150_tx_timeout(struct net_device *netdev)
 {
-	rtl8150_t	*dev;
+	rtl8150_t *dev;
 
 	dev = netdev->priv;
 	if (!dev)
@@ -445,10 +419,9 @@
 	dev->stats.tx_errors++;
 }
 
-
 static void rtl8150_set_multicast(struct net_device *netdev)
 {
-	rtl8150_t	*dev;
+	rtl8150_t *dev;
 
 	dev = netdev->priv;
 	netif_stop_queue(netdev);
@@ -456,7 +429,7 @@
 		dev->rx_creg |= 0x0001;
 		info("%s: promiscuous mode", netdev->name);
 	} else if ((netdev->mc_count > multicast_filter_limit) ||
-	           (netdev->flags & IFF_ALLMULTI)) {
+		   (netdev->flags & IFF_ALLMULTI)) {
 		dev->rx_creg &= 0xfffe;
 		dev->rx_creg |= 0x0002;
 		info("%s: allmulti set", netdev->name);
@@ -468,18 +441,17 @@
 	netif_wake_queue(netdev);
 }
 
-
 static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
-	rtl8150_t	*dev;
-	int		count, res;
+	rtl8150_t *dev;
+	int count, res;
 
 	netif_stop_queue(netdev);
 	dev = netdev->priv;
 	count = (skb->len < 60) ? 60 : skb->len;
 	count = (count & 0x3f) ? count : count + 1;
 	memcpy(dev->tx_buff, skb->data, skb->len);
-	FILL_BULK_URB(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev,2),
+	FILL_BULK_URB(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
 		      dev->tx_buff, RTL8150_MAX_MTU, write_bulk_callback, dev);
 	dev->tx_urb->transfer_buffer_length = count;
 
@@ -497,26 +469,25 @@
 	return 0;
 }
 
-
 static int rtl8150_open(struct net_device *netdev)
 {
-	rtl8150_t	*dev;
-	int		res;
-	
+	rtl8150_t *dev;
+	int res;
+
 	dev = netdev->priv;
 	if (dev == NULL) {
 		return -ENODEV;
 	}
 
 	down(&dev->sem);
-	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev,1),
-			dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
-	if ((res=usb_submit_urb(dev->rx_urb)))
+	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
+		      dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
+	if ((res = usb_submit_urb(dev->rx_urb)))
 		warn("%s: rx_urb submit failed: %d", __FUNCTION__, res);
-	FILL_INT_URB(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev,3),
-			dev->intr_buff, sizeof(dev->intr_buff), intr_callback,
-			dev, dev->intr_interval);
-	if ((res=usb_submit_urb(dev->intr_urb)))
+	FILL_INT_URB(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3),
+		     dev->intr_buff, sizeof(dev->intr_buff), intr_callback,
+		     dev, dev->intr_interval);
+	if ((res = usb_submit_urb(dev->intr_urb)))
 		warn("%s: intr_urb submit failed: %d", __FUNCTION__, res);
 	netif_start_queue(netdev);
 	enable_net_traffic(dev);
@@ -525,7 +496,6 @@
 	return res;
 }
 
-
 static int rtl8150_close(struct net_device *netdev)
 {
 	rtl8150_t *dev;
@@ -545,93 +515,92 @@
 	return res;
 }
 
-
 static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr)
 {
-	rtl8150_t	*dev;
-	int		cmd;
-	char		tmp[128];
+	rtl8150_t *dev;
+	int cmd;
+	char tmp[128];
 
 	dev = netdev->priv;
-	if (get_user(cmd, (int *)uaddr))
+	if (get_user(cmd, (int *) uaddr))
 		return -EFAULT;
 
 	switch (cmd) {
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		
-		strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
-		strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
-		sprintf(tmp, "usb%d:%d", dev->udev->bus->busnum,
-		        dev->udev->devnum);
-		strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
-		if (copy_to_user(uaddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_GSET: {
-		struct ethtool_cmd ecmd;
-		short   lpa, bmcr;
-
-		if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
-			return -EFAULT;
-		ecmd.supported = (SUPPORTED_10baseT_Half |
-		                  SUPPORTED_10baseT_Full |
-		                  SUPPORTED_100baseT_Half |
-		                  SUPPORTED_100baseT_Full |
-		                  SUPPORTED_Autoneg |
-		                  SUPPORTED_TP |
-		                  SUPPORTED_MII);
-		ecmd.port = PORT_TP;
-		ecmd.transceiver = XCVR_INTERNAL;
-		ecmd.phy_address = dev->phy;
-		get_registers(dev, BMCR, 2, &bmcr);
-		get_registers(dev, ANLP, 2, &lpa);
-		if (bmcr & BMCR_ANENABLE) {
-			ecmd.autoneg = AUTONEG_ENABLE;
-			ecmd.speed = (lpa & (LPA_100HALF | LPA_100FULL)) ?
-			             SPEED_100 : SPEED_10;
-			if (ecmd.speed == SPEED_100)
-				ecmd.duplex = (lpa & LPA_100FULL) ?
-				              DUPLEX_FULL : DUPLEX_HALF;
-			else
-				ecmd.duplex = (lpa & LPA_10FULL) ?
-				              DUPLEX_FULL : DUPLEX_HALF;
-		} else {
-			ecmd.autoneg = AUTONEG_DISABLE;
-			ecmd.speed = (bmcr & BMCR_SPEED100) ?
-			             SPEED_100 : SPEED_10;
-			ecmd.duplex = (bmcr & BMCR_FULLDPLX) ?
-			              DUPLEX_FULL : DUPLEX_HALF;
+	case ETHTOOL_GDRVINFO:{
+			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+
+			strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
+			strncpy(info.version, DRIVER_VERSION,
+				ETHTOOL_BUSINFO_LEN);
+			sprintf(tmp, "usb%d:%d", dev->udev->bus->busnum,
+				dev->udev->devnum);
+			strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
+			if (copy_to_user(uaddr, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+		}
+	case ETHTOOL_GSET:{
+			struct ethtool_cmd ecmd;
+			short lpa, bmcr;
+
+			if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
+				return -EFAULT;
+			ecmd.supported = (SUPPORTED_10baseT_Half |
+					  SUPPORTED_10baseT_Full |
+					  SUPPORTED_100baseT_Half |
+					  SUPPORTED_100baseT_Full |
+					  SUPPORTED_Autoneg |
+					  SUPPORTED_TP | SUPPORTED_MII);
+			ecmd.port = PORT_TP;
+			ecmd.transceiver = XCVR_INTERNAL;
+			ecmd.phy_address = dev->phy;
+			get_registers(dev, BMCR, 2, &bmcr);
+			get_registers(dev, ANLP, 2, &lpa);
+			if (bmcr & BMCR_ANENABLE) {
+				ecmd.autoneg = AUTONEG_ENABLE;
+				ecmd.speed =
+				    (lpa & (LPA_100HALF | LPA_100FULL)) ?
+				    SPEED_100 : SPEED_10;
+				if (ecmd.speed == SPEED_100)
+					ecmd.duplex = (lpa & LPA_100FULL) ?
+					    DUPLEX_FULL : DUPLEX_HALF;
+				else
+					ecmd.duplex = (lpa & LPA_10FULL) ?
+					    DUPLEX_FULL : DUPLEX_HALF;
+			} else {
+				ecmd.autoneg = AUTONEG_DISABLE;
+				ecmd.speed = (bmcr & BMCR_SPEED100) ?
+				    SPEED_100 : SPEED_10;
+				ecmd.duplex = (bmcr & BMCR_FULLDPLX) ?
+				    DUPLEX_FULL : DUPLEX_HALF;
+			}
+			if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
+				return -EFAULT;
+			return 0;
 		}
-		if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-	}
 	case ETHTOOL_SSET:
 		return -ENOTSUPP;
-	case ETHTOOL_GLINK: {
-		struct ethtool_value edata = {ETHTOOL_GLINK};
+	case ETHTOOL_GLINK:{
+			struct ethtool_value edata = { ETHTOOL_GLINK };
 
-		edata.data = netif_carrier_ok(netdev);
-		if (copy_to_user(uaddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
+			edata.data = netif_carrier_ok(netdev);
+			if (copy_to_user(uaddr, &edata, sizeof(edata)))
+				return -EFAULT;
+			return 0;
+		}
 	default:
 		return -EOPNOTSUPP;
 	}
 }
 
-
-static int rtl8150_ioctl (struct net_device *netdev, struct ifreq *rq, int cmd)
+static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
 {
 	rtl8150_t *dev;
-	u16	*data;
-	int	res;
+	u16 *data;
+	int res;
 
 	dev = netdev->priv;
-	data = (u16 *)&rq->ifr_data;
+	data = (u16 *) & rq->ifr_data;
 	res = 0;
 
 	down(&dev->sem);
@@ -641,10 +610,10 @@
 		break;
 	case SIOCDEVPRIVATE:
 		data[0] = dev->phy;
-	case SIOCDEVPRIVATE+1:
+	case SIOCDEVPRIVATE + 1:
 		read_mii_word(dev, dev->phy, (data[1] & 0x1f), &data[3]);
 		break;
-	case SIOCDEVPRIVATE+2:
+	case SIOCDEVPRIVATE + 2:
 		if (!capable(CAP_NET_ADMIN)) {
 			up(&dev->sem);
 			return -EPERM;
@@ -659,9 +628,8 @@
 	return res;
 }
 
-
-static void * rtl8150_probe(struct usb_device *udev, unsigned int ifnum,
-			    const struct usb_device_id *id)
+static void *rtl8150_probe(struct usb_device *udev, unsigned int ifnum,
+			   const struct usb_device_id *id)
 {
 	rtl8150_t *dev;
 	struct net_device *netdev;
@@ -671,14 +639,9 @@
 		err("usb_set_configuration() failed");
 		return NULL;
 	}
-	if ((udev->descriptor.idVendor != VENDOR_ID_REALTEK) ||
-	    (udev->descriptor.idProduct != PRODUCT_ID_RTL8150)) {
-	    	err("Not the one we are interested about");
-		return NULL;
-	}
 	dev = kmalloc(sizeof(rtl8150_t), GFP_KERNEL);
 	if (!dev) {
-		err ("Out of memory");
+		err("Out of memory");
 		goto exit;
 	} else
 		memset(dev, 0, sizeof(rtl8150_t));
@@ -690,7 +653,7 @@
 		dev = NULL;
 		goto exit;
 	}
-		
+
 	init_MUTEX(&dev->sem);
 	dev->udev = udev;
 	dev->netdev = netdev;
@@ -724,7 +687,6 @@
 	return dev;
 }
 
-
 static void rtl8150_disconnect(struct usb_device *udev, void *ptr)
 {
 	rtl8150_t *dev;
@@ -740,21 +702,17 @@
 	dev = NULL;
 }
 
-
-
 static int __init usb_rtl8150_init(void)
 {
 	info(DRIVER_DESC " " DRIVER_VERSION);
 	return usb_register(&rtl8150_driver);
 }
 
-
 static void __exit usb_rtl8150_exit(void)
 {
 	usb_deregister(&rtl8150_driver);
 }
 
-
 module_init(usb_rtl8150_init);
 module_exit(usb_rtl8150_exit);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/scanner.c linux-2.4.20/drivers/usb/scanner.c
--- linux-2.4.19/drivers/usb/scanner.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/usb/scanner.c	2002-10-29 11:18:35.000000000 +0000
@@ -1,13 +1,13 @@
 /* -*- linux-c -*- */
 
 /* 
- * Driver for USB Scanners (linux-2.4.12)
+ * Driver for USB Scanners (linux-2.4.18)
  *
- * Copyright (C) 1999, 2000, 2001 David E. Nelson
+ * Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson
  *
  * Portions may be copyright Brad Keryan and Michael Gee.
  *
- * David E. Nelson (dnelson@jump.net)
+ * Brian Beattie <beattie@beattie-home.net>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -300,11 +300,24 @@
  *      Frank Zago <fzago@greshamstorage.com> and
  *      Oliver Neukum <520047054719-0001@t-online.de> for reviewing/testing.
  *
+ * 0.4.8  5/30/2002
+ *    - Added Mustek BearPaw 2400 TA.  Thanks to Sergey
+ *      Vlasov <vsu@mivlgu.murom.ru>.
+ *    - Added Mustek 1200UB Plus and Mustek BearPaw 1200 CU ID's.  These use
+ *      the Grandtech GT-6801 chip. Thanks to Henning
+ *      Meier-Geinitz <henning@meier-geinitz.de>.
+ *    - Increased Epson timeout to 60 secs as requested from 
+ *      Karl Heinz Kremer <khk@khk.net>.
+ *    - Changed maintainership from David E. Nelson to Brian
+ *      Beattie <beattie@beattie-home.net>.
+ *
  * TODO
+ *    - Remove the 2/3 endpoint limitation
  *    - Performance
  *    - Select/poll methods
  *    - More testing
  *    - Proper registry/assignment for LM9830 ioctl's
+ *    - More general usage ioctl's
  *
  *
  *  Thanks to:
@@ -320,6 +333,8 @@
  *    - All the folks who chimed in with reports and suggestions.
  *    - All the developers that are working on USB SANE backends or other
  *      applications to use USB scanners.
+ *    - Thanks to Greg KH <greg@kroah.com> for setting up Brian Beattie
+ *      to be the new USB Scanner maintainer.
  *
  *  Performance:
  *
@@ -747,7 +762,7 @@
  	case SCANNER_IOCTL_CTRLMSG:
  	{
  		struct ctrlmsg_ioctl {
- 			devrequest	req;
+ 			struct usb_ctrlrequest	req;
  			void		*data;
  		} cmsg;
  		int pipe, nb, ret;
@@ -756,12 +771,12 @@
  		if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg)))
  			return -EFAULT;
 
- 		nb = le16_to_cpup(&cmsg.req.length);
+ 		nb = cmsg.req.wLength;
 
  		if (nb > sizeof(buf))
  			return -EINVAL;
 
- 		if ((cmsg.req.requesttype & 0x80) == 0) {
+ 		if ((cmsg.req.bRequestType & 0x80) == 0) {
  			pipe = usb_sndctrlpipe(dev, 0);
  			if (nb > 0 && copy_from_user(buf, cmsg.data, nb))
  				return -EFAULT;
@@ -769,10 +784,10 @@
  			pipe = usb_rcvctrlpipe(dev, 0);
 		}
 
- 		ret = usb_control_msg(dev, pipe, cmsg.req.request,
- 				      cmsg.req.requesttype,
- 				      le16_to_cpup(&cmsg.req.value),
- 				      le16_to_cpup(&cmsg.req.index),
+ 		ret = usb_control_msg(dev, pipe, cmsg.req.bRequest,
+ 				      cmsg.req.bRequestType,
+ 				      cmsg.req.wValue,
+ 				      cmsg.req.wIndex,
  				      buf, nb, HZ);
 
  		if (ret < 0) {
@@ -780,7 +795,7 @@
  			return -EIO;
  		}
 
- 		if (nb > 0 && (cmsg.req.requesttype & 0x80) && copy_to_user(cmsg.data, buf, nb))
+ 		if (nb > 0 && (cmsg.req.bRequestType & 0x80) && copy_to_user(cmsg.data, buf, nb))
  			return -EFAULT;
 
  		return 0;
@@ -1017,7 +1032,7 @@
 
 	switch (dev->descriptor.idVendor) { /* Scanner specific read timeout parameters */
 	case 0x04b8:		/* Seiko/Epson */
-		scn->rd_nak_timeout = HZ * 40;
+		scn->rd_nak_timeout = HZ * 60;
 		break;
 	case 0x055f:		/* Mustek */
 	case 0x0400:		/* Another Mustek */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/scanner.h linux-2.4.20/drivers/usb/scanner.h
--- linux-2.4.19/drivers/usb/scanner.h	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/usb/scanner.h	2002-10-29 11:18:39.000000000 +0000
@@ -1,9 +1,9 @@
 /*
- * Driver for USB Scanners (linux-2.4.12)
+ * Driver for USB Scanners (linux-2.4.18)
  *
- * Copyright (C) 1999, 2000, 2001 David E. Nelson
+ * Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson
  *
- * David E. Nelson (dnelson@jump.net)
+ * Brian Beattie <beattie@beattie-home.net>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -48,7 +48,7 @@
 
 static __s32 vendor=-1, product=-1, read_timeout=0;
 
-MODULE_AUTHOR("David E. Nelson, dnelson@jump.net, http://www.jump.net/~dnelson");
+MODULE_AUTHOR("Brian Beattie, beattie@beattie-home.net");
 MODULE_DESCRIPTION(DRIVER_DESC" "DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 
@@ -90,9 +90,12 @@
 	{ USB_DEVICE(0x06bd, 0x2097) }, /* SnapScan e26 */
 	{ USB_DEVICE(0x06bd, 0x208d) }, /* Snapscan e40 */
 	/* Canon */
-	{ USB_DEVICE(0x04a9, 0x2202) }, /* FB620U */
+	{ USB_DEVICE(0x04a9, 0x2202) }, /* CanoScan FB620U */
+	{ USB_DEVICE(0x04a9, 0x2204) }, /* CanoScan FB630U/FB636U */
+	{ USB_DEVICE(0x04a9, 0x2206) }, /* CanoScan N650U/N656U */
+	{ USB_DEVICE(0x04a9, 0x2207) }, /* CanoScan N1220U */
+	{ USB_DEVICE(0x04a9, 0x2208) }, /* CanoScan D660U */ 
 	{ USB_DEVICE(0x04a9, 0x220b) }, /* D646U */
-	{ USB_DEVICE(0x04a9, 0x2207) }, /* 1220U */
 	/* Colorado -- See Primax/Colorado below */
 	/* Epson -- See Seiko/Epson below */
 	/* Genius */
@@ -110,6 +113,7 @@
 	{ USB_DEVICE(0x03f0, 0x0105) },	/* 4200C */
 	{ USB_DEVICE(0x03f0, 0x0305) }, /* 4300C */
 	{ USB_DEVICE(0x03f0, 0x0102) },	/* PhotoSmart S20 */
+	{ USB_DEVICE(0x03f0, 0x0705) }, /* 4400C */
 	{ USB_DEVICE(0x03f0, 0x0401) },	/* 5200C */
 	//	{ USB_DEVICE(0x03f0, 0x0701) },	/* 5300C - NOT SUPPORTED - see http://www.neatech.nl/oss/HP5300C/ */
 	{ USB_DEVICE(0x03f0, 0x0201) },	/* 6200C */
@@ -141,6 +145,8 @@
 	{ USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 */
 	{ USB_DEVICE(0x055f, 0x0008) }, /* 1200 CU Plus */
 	{ USB_DEVICE(0x0ff5, 0x0010) }, /* BearPaw 1200F */
+	{ USB_DEVICE(0x055f, 0x0218) }, /* BearPaw 2400 TA */
+	{ USB_DEVICE(0x05d8, 0x4002) }, /* 1200 CU and 1200 UB Plus */
 	/* Plustek */
 	{ USB_DEVICE(0x07b3, 0x0017) }, /* OpticPro UT12 */
 	{ USB_DEVICE(0x07b3, 0x0011) }, /* OpticPro UT24 */
@@ -179,8 +185,12 @@
 	{ USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */
 	{ USB_DEVICE(0x04b8, 0x010c) }, /* Perfection 640U */
 	{ USB_DEVICE(0x04b8, 0x010e) }, /* Expression 1680 */
+	{ USB_DEVICE(0x04b8, 0x010f) }, /* Perfection 1250U */
 	{ USB_DEVICE(0x04b8, 0x0110) }, /* Perfection 1650 */
 	{ USB_DEVICE(0x04b8, 0x0112) }, /* Perfection 2450 - GT-9700 for the Japanese mkt */
+	{ USB_DEVICE(0x04b8, 0x0114) }, /* Perfection 660 */
+	{ USB_DEVICE(0x04b8, 0x011b) }, /* Perfection 2400 Photo */
+	{ USB_DEVICE(0x04b8, 0x011e) }, /* Perfection 1660 Photo */
 	/* Umax */
 	{ USB_DEVICE(0x1606, 0x0010) },	/* Astra 1220U */
 	{ USB_DEVICE(0x1606, 0x0030) },	/* Astra 2000U */
@@ -230,7 +240,7 @@
 #define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int)
 #define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int)
 /* send/recv a control message to the scanner */
-#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, devrequest )
+#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, struct usb_ctrlrequest )
 
 
 #define SCN_MAX_MNR 16		/* We're allocated 16 minors */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/se401.c linux-2.4.20/drivers/usb/se401.c
--- linux-2.4.19/drivers/usb/se401.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/se401.c	2002-10-29 11:18:36.000000000 +0000
@@ -41,18 +41,12 @@
 #include <asm/semaphore.h>
 #include <linux/wrapper.h>
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
-#define virt_to_page(arg)	MAP_NR(arg)
-#define vmalloc_32		vmalloc
-#endif
-
 #include "se401.h"
 
 static int flickerless=0;
 static int video_nr = -1;
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 3, 0)
-static __devinitdata struct usb_device_id device_table [] = {
+static struct usb_device_id device_table [] = {
 	{ USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */
 	{ USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */
 	{ USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */
@@ -62,7 +56,6 @@
 };
 
 MODULE_DEVICE_TABLE(usb, device_table);
-#endif
 
 MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
 MODULE_DESCRIPTION("SE401 USB Camera Driver");
@@ -80,54 +73,17 @@
  *
  * Memory management
  *
- * This is a shameless copy from the USB-cpia driver (linux kernel
- * version 2.3.29 or so, I have no idea what this code actually does ;).
- * Actually it seems to be a copy of a shameless copy of the bttv-driver.
- * Or that is a copy of a shameless copy of ... (To the powers: is there
- * no generic kernel-function to do this sort of stuff?)
- *
- * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
- * there will be one, but apparentely not yet -jerdfelt
- *
- * So I copied it again for the ov511 driver -claudio
- *
- * Same for the se401 driver -Jeroen
  **********************************************************************/
 
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
-	unsigned long ret = 0UL;
-	pmd_t *pmd;
-	pte_t *ptep, pte;
-
-	if (!pgd_none(*pgd)) {
-		pmd = pmd_offset(pgd, adr);
-		if (!pmd_none(*pmd)) {
-			ptep = pte_offset(pmd, adr);
-			pte = *ptep;
-			if (pte_present(pte)) {
-				ret = (unsigned long) page_address(pte_page(pte));
-				ret |= (adr & (PAGE_SIZE - 1));
-			}
-		}
-	}
-
-	return ret;
-}
-
 /* Here we want the physical address of the memory.
- * This is used when initializing the contents of the
- * area and marking the pages as reserved.
+ * This is used when initializing the contents of the area.
  */
 static inline unsigned long kvirt_to_pa(unsigned long adr)
 {
-	unsigned long va, kva, ret;
+	unsigned long kva, ret;
 
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
 	ret = __pa(kva);
 	return ret;
 }
@@ -135,12 +91,9 @@
 static void *rvmalloc(unsigned long size)
 {
 	void *mem;
-	unsigned long adr, page;
-
-	/* Round it off to PAGE_SIZE */
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
+	unsigned long adr;
 
+	size = PAGE_ALIGN(size);
 	mem = vmalloc_32(size);
 	if (!mem)
 		return NULL;
@@ -148,13 +101,9 @@
 	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
 	adr = (unsigned long) mem;
 	while (size > 0) {
-		page = kvirt_to_pa(adr);
-		mem_map_reserve(virt_to_page(__va(page)));
+		mem_map_reserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 
 	return mem;
@@ -162,23 +111,16 @@
 
 static void rvfree(void *mem, unsigned long size)
 {
-	unsigned long adr, page;
+	unsigned long adr;
 
 	if (!mem)
 		return;
 
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
-
-	adr=(unsigned long) mem;
-	while (size > 0) {
-		page = kvirt_to_pa(adr);
-		mem_map_unreserve(virt_to_page(__va(page)));
+	adr = (unsigned long) mem;
+	while ((long) size > 0) {
+		mem_map_unreserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 	vfree(mem);
 }
@@ -610,7 +552,7 @@
 */
 static int se401_start_stream(struct usb_se401 *se401)
 {
-	urb_t *urb;
+	struct urb *urb;
 	int err=0, i;
 	se401->streaming=1;
 
@@ -704,7 +646,7 @@
 		return 0;
 
 	/* Check for a valid mode */
-	if (!width || !height)
+	if (width <= 0 || height <= 0)
 		return 1;
 	if ((width & 1) || (height & 1))
 		return 1;
@@ -738,7 +680,8 @@
 static inline void enhance_picture(unsigned char *frame, int len)
 {
 	while (len--) {
-		*frame++=(((*frame^255)*(*frame^255))/255)^255;
+		*frame=(((*frame^255)*(*frame^255))/255)^255;
+		frame++;
 	}
 }
 
@@ -972,7 +915,8 @@
 		/* Fix the top line */
 		framedata+=linelength;
 		for (i=0; i<linelength; i++) {
-			*--framedata=*(framedata+linelength);
+			framedata--;
+			*framedata=*(framedata+linelength);
 		}
 		/* Fix the left side (green is already present) */
 		for (i=0; i<se401->cheight; i++) {
@@ -1425,7 +1369,13 @@
 
 	se401->sizes=cp[4]+cp[5]*256;
 	se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+	if (!se401->width)
+		return 1;
 	se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+	if (!se401->height) {
+		kfree(se401->width);
+		return 1;
+	}
 	for (i=0; i<se401->sizes; i++) {
 		    se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256;
 		    se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256;
@@ -1491,12 +1441,8 @@
         return 0;
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
-static void* se401_probe(struct usb_device *dev, unsigned int ifnum)
-#else
-static void* __devinit se401_probe(struct usb_device *dev, unsigned int ifnum,
+static void* se401_probe(struct usb_device *dev, unsigned int ifnum,
 	const struct usb_device_id *id)
-#endif
 {
         struct usb_interface_descriptor *interface;
         struct usb_se401 *se401;
@@ -1625,9 +1571,7 @@
 
 static struct usb_driver se401_driver = {
         name:		"se401",
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 3, 0)
         id_table:	device_table,
-#endif
 	probe:		se401_probe,
         disconnect:	se401_disconnect
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/se401.h linux-2.4.20/drivers/usb/se401.h
--- linux-2.4.19/drivers/usb/se401.h	2001-09-07 17:59:04.000000000 +0000
+++ linux-2.4.20/drivers/usb/se401.h	2002-10-29 11:18:36.000000000 +0000
@@ -10,7 +10,7 @@
 
 #ifdef se401_DEBUG
 #  define PDEBUG(level, fmt, args...) \
-if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
+if (debug >= level) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
 #else
 #  define PDEBUG(level, fmt, args...) do {} while(0)
 #endif
@@ -197,8 +197,8 @@
 
 	char *fbuf;		/* Videodev buffer area */
 
-	urb_t *urb[SE401_NUMSBUF];
-	urb_t *inturb;
+	struct urb *urb[SE401_NUMSBUF];
+	struct urb *inturb;
 	
 	int button;
 	int buttonpressed;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/Config.in linux-2.4.20/drivers/usb/serial/Config.in
--- linux-2.4.19/drivers/usb/serial/Config.in	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/Config.in	2002-10-29 11:18:31.000000000 +0000
@@ -5,34 +5,39 @@
 comment 'USB Serial Converter support'
 
 dep_tristate 'USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB
-if [ "$CONFIG_USB_SERIAL" = "y" ]; then
-  dep_mbool '  USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG $CONFIG_USB_SERIAL
+if [ "$CONFIG_USB_SERIAL" != "n" ]; then
+   dep_bool '  USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG $CONFIG_USB_SERIAL
+   dep_mbool '  USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC $CONFIG_USB_SERIAL
+   dep_tristate '  USB Belkin and Peracom Single Port Serial Driver' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL
+   dep_tristate '  USB ConnectTech WhiteHEAT Serial Driver' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL
+   dep_tristate '  USB Digi International AccelePort USB Serial Driver' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
+   dep_tristate '  USB Empeg empeg-car Mark I/II Driver' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL
+   dep_tristate '  USB FTDI Single Port Serial Driver' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL
+   dep_tristate '  USB Handspring Visor / Palm m50x / Sony Clie Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
+   dep_tristate '  USB Compaq iPAQ / HP Jornada / Casio EM500 Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL
+   dep_tristate '  USB IR Dongle Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_IR $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB Inside Out Edgeport Serial Driver' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL
+   dep_tristate '  USB Inside Out Edgeport Serial Driver (TI devices)' CONFIG_USB_SERIAL_EDGEPORT_TI $CONFIG_USB_SERIAL
+   dep_tristate '  USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB Keyspan USA-xxx Serial Driver' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL
+   if [ "$CONFIG_USB_SERIAL_KEYSPAN" != "n" ]; then
+      bool '    USB Keyspan USA-28 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28
+      bool '    USB Keyspan USA-28X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28X
+      bool '    USB Keyspan USA-28XA Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28XA
+      bool '    USB Keyspan USA-28XB Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28XB
+      bool '    USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19
+      bool '    USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X
+      bool '    USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W
+      bool '    USB Keyspan USA-19QW Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19QW
+      bool '    USB Keyspan USA-19QI Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19QI
+      bool '    USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W
+   fi
+   dep_tristate '  USB MCT Single Port Serial Driver' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL
+   dep_tristate '  USB KL5KUSB105 (Palmconnect) Driver' CONFIG_USB_SERIAL_KLSI $CONFIG_USB_SERIAL
+   dep_tristate '  USB Prolific 2303 Single Port Serial Driver' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL
+   dep_tristate '  USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_CYBERJACK $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB Xircom / Entregra Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_XIRCOM $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 fi
-dep_mbool '  USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC $CONFIG_USB_SERIAL
-dep_tristate '  USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB Digi International AccelePort USB Serial Driver' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
-dep_tristate '  USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB Handspring Visor / Palm m50x / Sony Clie Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
-dep_tristate '  USB Compaq iPAQ / HP Jornada / Casio EM500 Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL
-dep_tristate '  USB IR Dongle Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_IR $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB Inside Out Edgeport Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-   dep_mbool '    USB Keyspan USA-28 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28 $CONFIG_USB_SERIAL_KEYSPAN
-   dep_mbool '    USB Keyspan USA-28X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28X $CONFIG_USB_SERIAL_KEYSPAN
-   dep_mbool '    USB Keyspan USA-28XA Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28XA $CONFIG_USB_SERIAL_KEYSPAN
-   dep_mbool '    USB Keyspan USA-28XB Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28XB $CONFIG_USB_SERIAL_KEYSPAN
-   dep_mbool '    USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19 $CONFIG_USB_SERIAL_KEYSPAN
-   dep_mbool '    USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X $CONFIG_USB_SERIAL_KEYSPAN
-   dep_mbool '    USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W $CONFIG_USB_SERIAL_KEYSPAN
-   dep_mbool '    USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W $CONFIG_USB_SERIAL_KEYSPAN
-dep_tristate '  USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB KL5KUSB105 (Palmconnect) Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KLSI $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB Prolific 2303 Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_CYBERJACK $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB Xircom / Entregra Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_XIRCOM $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/Makefile linux-2.4.20/drivers/usb/serial/Makefile
--- linux-2.4.19/drivers/usb/serial/Makefile	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/Makefile	2002-10-29 11:18:33.000000000 +0000
@@ -20,6 +20,7 @@
 obj-$(CONFIG_USB_SERIAL_EMPEG)			+= empeg.o
 obj-$(CONFIG_USB_SERIAL_MCT_U232)		+= mct_u232.o
 obj-$(CONFIG_USB_SERIAL_EDGEPORT)		+= io_edgeport.o
+obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI)		+= io_ti.o
 obj-$(CONFIG_USB_SERIAL_PL2303)			+= pl2303.o
 obj-$(CONFIG_USB_SERIAL_CYBERJACK)		+= cyberjack.o
 obj-$(CONFIG_USB_SERIAL_IR)			+= ir-usb.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/belkin_sa.c linux-2.4.20/drivers/usb/serial/belkin_sa.c
--- linux-2.4.19/drivers/usb/serial/belkin_sa.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/belkin_sa.c	2002-10-29 11:18:32.000000000 +0000
@@ -1,8 +1,8 @@
 /*
  * Belkin USB Serial Adapter Driver
  *
- *  Copyright (C) 2000
- *      William Greathouse (wgreathouse@smva.com)
+ *  Copyright (C) 2000		William Greathouse (wgreathouse@smva.com)
+ *  Copyright (C) 2000-2001 	Greg Kroah-Hartman (greg@kroah.com)
  *
  *  This program is largely derived from work by the linux-usb group
  *  and associated source files.  Please see the usb/serial files for
@@ -24,6 +24,9 @@
  * -- Add support for flush commands
  * -- Add everything that is missing :)
  *
+ * 27-Nov-2001 gkh
+ * 	compressed all the differnent device entries into 1.
+ *
  * 30-May-2001 gkh
  *	switched from using spinlock to a semaphore, which fixes lots of problems.
  *
@@ -62,18 +65,15 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <asm/uaccess.h>
 #include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
@@ -88,7 +88,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.1"
+#define DRIVER_VERSION "v1.2"
 #define DRIVER_AUTHOR "William Greathouse <wgreathouse@smva.com>"
 #define DRIVER_DESC "USB Belkin Serial converter driver"
 
@@ -103,146 +103,35 @@
 static void belkin_sa_break_ctl		(struct usb_serial_port *port, int break_state );
 
 
-static __devinitdata struct usb_device_id id_table_combined [] = {
+static struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(BELKIN_SA_VID, BELKIN_SA_PID) },
 	{ USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) },
 	{ USB_DEVICE(PERACOM_VID, PERACOM_PID) },
 	{ USB_DEVICE(GOHUBS_VID, GOHUBS_PID) },
+	{ USB_DEVICE(GOHUBS_VID, HANDYLINK_PID) },
 	{ USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) },
 	{ }							/* Terminating entry */
 };
 
-static __devinitdata struct usb_device_id belkin_dockstation_table [] = {
-	{ USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) },
-	{ }							/* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id belkin_sa_table [] = {
-	{ USB_DEVICE(BELKIN_SA_VID, BELKIN_SA_PID) },
-	{ }							/* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id belkin_old_table [] = {
-	{ USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) },
-	{ }							/* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id peracom_table [] = {
-	{ USB_DEVICE(PERACOM_VID, PERACOM_PID) },
-	{ }							/* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id gocom232_table [] = {
-	{ USB_DEVICE(GOHUBS_VID, GOHUBS_PID) },
-	{ }							/* Terminating entry */
-};
-
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
-/* All of the device info needed for the Belkin dockstation serial converter */
-static struct usb_serial_device_type belkin_dockstation_device = {
-	name:			"Belkin F5U120-PC USB Serial Adapter",
-	id_table:		belkin_dockstation_table,		/* the Belkin F5U103 device */
-	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
-	needs_bulk_in:		MUST_HAVE,			/* this device must have a bulk in endpoint */
-	needs_bulk_out:		MUST_HAVE,			/* this device must have a bulk out endpoint */
-	num_interrupt_in:	1,
-	num_bulk_in:		1,
-	num_bulk_out:		1,
-	num_ports:		1,
-	open:			belkin_sa_open,
-	close:			belkin_sa_close,
-	read_int_callback:	belkin_sa_read_int_callback,	/* How we get the status info */
-	ioctl:			belkin_sa_ioctl,
-	set_termios:		belkin_sa_set_termios,
-	break_ctl:		belkin_sa_break_ctl,
-	startup:		belkin_sa_startup,
-	shutdown:		belkin_sa_shutdown,
-};
-
-/* All of the device info needed for the Belkin serial converter */
-static struct usb_serial_device_type belkin_sa_device = {
-	name:			"Belkin F5U103 USB Serial Adapter",
-	id_table:		belkin_sa_table,		/* the Belkin F5U103 device */
-	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
-	needs_bulk_in:		MUST_HAVE,			/* this device must have a bulk in endpoint */
-	needs_bulk_out:		MUST_HAVE,			/* this device must have a bulk out endpoint */
-	num_interrupt_in:	1,
-	num_bulk_in:		1,
-	num_bulk_out:		1,
-	num_ports:		1,
-	open:			belkin_sa_open,
-	close:			belkin_sa_close,
-	read_int_callback:	belkin_sa_read_int_callback,	/* How we get the status info */
-	ioctl:			belkin_sa_ioctl,
-	set_termios:		belkin_sa_set_termios,
-	break_ctl:		belkin_sa_break_ctl,
-	startup:		belkin_sa_startup,
-	shutdown:		belkin_sa_shutdown,
-};
-
-
-/* This driver also supports the "old" school Belkin single port adaptor */
-static struct usb_serial_device_type belkin_old_device = {
-	name:			"Belkin USB Serial Adapter",
-	id_table:		belkin_old_table,		/* the old Belkin device */
-	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
-	needs_bulk_in:		MUST_HAVE,			/* this device must have a bulk in endpoint */
-	needs_bulk_out:		MUST_HAVE,			/* this device must have a bulk out endpoint */
-	num_interrupt_in:	1,
-	num_bulk_in:		1,
-	num_bulk_out:		1,
-	num_ports:		1,
-	open:			belkin_sa_open,
-	close:			belkin_sa_close,
-	read_int_callback:	belkin_sa_read_int_callback,	/* How we get the status info */
-	ioctl:			belkin_sa_ioctl,
-	set_termios:		belkin_sa_set_termios,
-	break_ctl:		belkin_sa_break_ctl,
-	startup:		belkin_sa_startup,
-	shutdown:		belkin_sa_shutdown,
-};
-
-/* this driver also works for the Peracom single port adapter */
-static struct usb_serial_device_type peracom_device = {
-	name:			"Peracom single port USB Serial Adapter",
-	id_table:		peracom_table,			/* the Peracom device */
-	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
-	needs_bulk_in:		MUST_HAVE,			/* this device must have a bulk in endpoint */
-	needs_bulk_out:		MUST_HAVE,			/* this device must have a bulk out endpoint */
-	num_interrupt_in:	1,
-	num_bulk_in:		1,
-	num_bulk_out:		1,
-	num_ports:		1,
-	open:			belkin_sa_open,
-	close:			belkin_sa_close,
-	read_int_callback:	belkin_sa_read_int_callback,	/* How we get the status info */
-	ioctl:			belkin_sa_ioctl,
-	set_termios:		belkin_sa_set_termios,
-	break_ctl:		belkin_sa_break_ctl,
-	startup:		belkin_sa_startup,
-	shutdown:		belkin_sa_shutdown,
-};
-
-/* the GoHubs Go-COM232 device is the same as the Peracom single port adapter */
-static struct usb_serial_device_type gocom232_device = {
-	name:			"GO-COM232 USB Serial Converter",
-	id_table:		gocom232_table,			/* the GO-COM232 device */
-	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
-	needs_bulk_in:		MUST_HAVE,			/* this device must have a bulk in endpoint */
-	needs_bulk_out:		MUST_HAVE,			/* this device must have a bulk out endpoint */
-	num_interrupt_in:	1,
-	num_bulk_in:		1,
-	num_bulk_out:		1,
-	num_ports:		1,
-	open:			belkin_sa_open,
-	close:			belkin_sa_close,
-	read_int_callback:	belkin_sa_read_int_callback,	/* How we get the status info */
-	ioctl:			belkin_sa_ioctl,
-	set_termios:		belkin_sa_set_termios,
-	break_ctl:		belkin_sa_break_ctl,
-	startup:		belkin_sa_startup,
-	shutdown:		belkin_sa_shutdown,
+/* All of the device info needed for the serial converters */
+static struct usb_serial_device_type belkin_device = {
+	.owner =		THIS_MODULE,
+	.name =			"Belkin / Peracom / GoHubs USB Serial Adapter",
+	.id_table =		id_table_combined,
+	.num_interrupt_in =	1,
+	.num_bulk_in =		1,
+	.num_bulk_out =		1,
+	.num_ports =		1,
+	.open =			belkin_sa_open,
+	.close =		belkin_sa_close,
+	.read_int_callback =	belkin_sa_read_int_callback,	/* How we get the status info */
+	.ioctl =		belkin_sa_ioctl,
+	.set_termios =		belkin_sa_set_termios,
+	.break_ctl =		belkin_sa_break_ctl,
+	.startup =		belkin_sa_startup,
+	.shutdown =		belkin_sa_shutdown,
 };
 
 
@@ -296,13 +185,10 @@
 {
 	int i;
 	
-	dbg (__FUNCTION__);
+	dbg ("%s", __FUNCTION__);
 
 	/* stop reads and writes on all ports */
 	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
-			belkin_sa_close (&serial->port[i], NULL);
-		}
 		/* My special items, the standard routines free my urbs */
 		if (serial->port[i].private)
 			kfree(serial->port[i].private);
@@ -314,36 +200,25 @@
 {
 	int retval = 0;
 
-	dbg(__FUNCTION__" port %d", port->number);
+	dbg("%s port %d", __FUNCTION__, port->number);
 
-	down (&port->sem);
-	
-	++port->open_count;
-	MOD_INC_USE_COUNT;
-	
-	if (!port->active) {
-		port->active = 1;
-
-		/*Start reading from the device*/
-		/* TODO: Look at possibility of submitting mulitple URBs to device to
-		 *       enhance buffering.  Win trace shows 16 initial read URBs.
-		 */
-		port->read_urb->dev = port->serial->dev;
-		retval = usb_submit_urb(port->read_urb);
-		if (retval) {
-			err("usb_submit_urb(read bulk) failed");
-			goto exit;
-		}
-
-		port->interrupt_in_urb->dev = port->serial->dev;
-		retval = usb_submit_urb(port->interrupt_in_urb);
-		if (retval)
-			err(" usb_submit_urb(read int) failed");
+	/*Start reading from the device*/
+	/* TODO: Look at possibility of submitting mulitple URBs to device to
+	 *       enhance buffering.  Win trace shows 16 initial read URBs.
+	 */
+	port->read_urb->dev = port->serial->dev;
+	retval = usb_submit_urb(port->read_urb);
+	if (retval) {
+		err("usb_submit_urb(read bulk) failed");
+		goto exit;
 	}
-	
-exit:
-	up (&port->sem);
 
+	port->interrupt_in_urb->dev = port->serial->dev;
+	retval = usb_submit_urb(port->interrupt_in_urb);
+	if (retval)
+		err(" usb_submit_urb(read int) failed");
+
+exit:
 	return retval;
 } /* belkin_sa_open */
 
@@ -359,24 +234,14 @@
 	if (!serial)
 		return;
 
-	dbg(__FUNCTION__" port %d", port->number);
-
-	down (&port->sem);
-
-	--port->open_count;
+	dbg("%s port %d", __FUNCTION__, port->number);
 
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			/* shutdown our bulk reads and writes */
-			usb_unlink_urb (port->write_urb);
-			usb_unlink_urb (port->read_urb);
-			usb_unlink_urb (port->interrupt_in_urb);
-		}
-		port->active = 0;
+	if (serial->dev) {
+		/* shutdown our bulk reads and writes */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->read_urb);
+		usb_unlink_urb (port->interrupt_in_urb);
 	}
-	
-	up (&port->sem);
-	MOD_DEC_USE_COUNT;
 } /* belkin_sa_close */
 
 
@@ -457,12 +322,31 @@
 {
 	struct usb_serial *serial = port->serial;
 	struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private;
-	unsigned int iflag = port->tty->termios->c_iflag;
-	unsigned int cflag = port->tty->termios->c_cflag;
-	unsigned int old_iflag = old_termios->c_iflag;
-	unsigned int old_cflag = old_termios->c_cflag;
+	unsigned int iflag;
+	unsigned int cflag;
+	unsigned int old_iflag = 0;
+	unsigned int old_cflag = 0;
 	__u16 urb_value = 0; /* Will hold the new flags */
 	
+	if ((!port->tty) || (!port->tty->termios)) {
+		dbg ("%s - no tty or termios structure", __FUNCTION__);
+		return;
+	}
+
+	iflag = port->tty->termios->c_iflag;
+	cflag = port->tty->termios->c_cflag;
+
+	/* check that they really want us to change something */
+	if (old_termios) {
+		if ((cflag == old_termios->c_cflag) &&
+		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+			dbg("%s - nothing to change...", __FUNCTION__);
+			return;
+		}
+		old_iflag = old_termios->c_iflag;
+		old_cflag = old_termios->c_cflag;
+	}
+
 	/* Set the baud rate */
 	if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
 		/* reassert DTR and (maybe) RTS on transition from B0 */
@@ -642,11 +526,7 @@
 
 static int __init belkin_sa_init (void)
 {
-	usb_serial_register (&belkin_dockstation_device);
-	usb_serial_register (&belkin_sa_device);
-	usb_serial_register (&belkin_old_device);
-	usb_serial_register (&peracom_device);
-	usb_serial_register (&gocom232_device);
+	usb_serial_register (&belkin_device);
 	info(DRIVER_DESC " " DRIVER_VERSION);
 	return 0;
 }
@@ -654,11 +534,7 @@
 
 static void __exit belkin_sa_exit (void)
 {
-	usb_serial_deregister (&belkin_dockstation_device);
-	usb_serial_deregister (&belkin_sa_device);
-	usb_serial_deregister (&belkin_old_device);
-	usb_serial_deregister (&peracom_device);
-	usb_serial_deregister (&gocom232_device);
+	usb_serial_deregister (&belkin_device);
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/belkin_sa.h linux-2.4.20/drivers/usb/serial/belkin_sa.h
--- linux-2.4.19/drivers/usb/serial/belkin_sa.h	2001-10-01 20:45:43.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/belkin_sa.h	2002-10-29 11:18:32.000000000 +0000
@@ -47,6 +47,7 @@
 
 #define GOHUBS_VID	0x0921	/* GoHubs vendor id */
 #define GOHUBS_PID	0x1000	/* GoHubs single port serial converter's id (identical to the Peracom device) */
+#define HANDYLINK_PID	0x1200	/* HandyLink USB's id (identical to the Peracom device) */
 
 /* Vendor Request Interface */
 #define BELKIN_SA_SET_BAUDRATE_REQUEST	0  /* Set baud rate */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/cyberjack.c linux-2.4.20/drivers/usb/serial/cyberjack.c
--- linux-2.4.19/drivers/usb/serial/cyberjack.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/cyberjack.c	2002-10-29 11:18:50.000000000 +0000
@@ -25,18 +25,15 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <asm/uaccess.h>
 #include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
@@ -69,7 +66,7 @@
 static void cyberjack_read_bulk_callback (struct urb *urb);
 static void cyberjack_write_bulk_callback (struct urb *urb);
 
-static __devinitdata struct usb_device_id id_table [] = {
+static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(CYBERJACK_VENDOR_ID, CYBERJACK_PRODUCT_ID) },
 	{ }			/* Terminating entry */
 };
@@ -77,23 +74,21 @@
 MODULE_DEVICE_TABLE (usb, id_table);
 
 static struct usb_serial_device_type cyberjack_device = {
-	name:			"Reiner SCT Cyberjack USB card reader",
-	id_table:		id_table,
-	needs_interrupt_in:	MUST_HAVE,
-	needs_bulk_in:		MUST_HAVE,
-	needs_bulk_out:		MUST_HAVE,
-	num_interrupt_in:	1,
-	num_bulk_in:		1,
-	num_bulk_out:		1,
-	num_ports:		1,
-	startup:		cyberjack_startup,
-	shutdown:		cyberjack_shutdown,
-	open:			cyberjack_open,
-	close:			cyberjack_close,
-	write:			cyberjack_write,
-	read_int_callback:	cyberjack_read_int_callback,
-	read_bulk_callback:	cyberjack_read_bulk_callback,
-	write_bulk_callback:	cyberjack_write_bulk_callback,
+	.owner =		THIS_MODULE,
+	.name =			"Reiner SCT Cyberjack USB card reader",
+	.id_table =		id_table,
+	.num_interrupt_in =	1,
+	.num_bulk_in =		1,
+	.num_bulk_out =		1,
+	.num_ports =		1,
+	.startup =		cyberjack_startup,
+	.shutdown =		cyberjack_shutdown,
+	.open =			cyberjack_open,
+	.close =		cyberjack_close,
+	.write =		cyberjack_write,
+	.read_int_callback =	cyberjack_read_int_callback,
+	.read_bulk_callback =	cyberjack_read_bulk_callback,
+	.write_bulk_callback =	cyberjack_write_bulk_callback,
 };
 
 struct cyberjack_private {
@@ -108,7 +103,7 @@
 {
 	struct cyberjack_private *priv;
 
-	dbg (__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	/* allocate the private data structure */
 	serial->port->private = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL);
@@ -130,13 +125,9 @@
 {
 	int i;
 	
-	dbg (__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
-	/* stop reads and writes on all ports */
 	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
-			cyberjack_close (&serial->port[i], NULL);
-		}
 		/* My special items, the standard routines free my urbs */
 		if (serial->port[i].private)
 			kfree(serial->port[i].private);
@@ -151,66 +142,43 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return -ENODEV;
 
-	MOD_INC_USE_COUNT;
-
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	down (&port->sem);
-
-	++port->open_count;
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	if (!port->active) {
-		port->active = 1;
-		/* force low_latency on so that our tty_push actually forces
-		 * the data through, otherwise it is scheduled, and with high
-		 * data rates (like with OHCI) data can get lost.
-		 */
-		port->tty->low_latency = 1;
-
-		priv = (struct cyberjack_private *)port->private;
-		priv->rdtodo = 0;
-		priv->wrfilled = 0;
-		priv->wrsent = 0;
+	/* force low_latency on so that our tty_push actually forces
+	 * the data through, otherwise it is scheduled, and with high
+	 * data rates (like with OHCI) data can get lost.
+	 */
+	port->tty->low_latency = 1;
 
-		/* shutdown any bulk reads that might be going on */
-		usb_unlink_urb (port->write_urb);
-		usb_unlink_urb (port->read_urb);
-		usb_unlink_urb (port->interrupt_in_urb);
-
-		port->interrupt_in_urb->dev = port->serial->dev;
-		result = usb_submit_urb(port->interrupt_in_urb);
-		if (result)
-			err(" usb_submit_urb(read int) failed");
-		dbg(__FUNCTION__ " - usb_submit_urb(int urb)");
-	}
+	priv = (struct cyberjack_private *)port->private;
+	priv->rdtodo = 0;
+	priv->wrfilled = 0;
+	priv->wrsent = 0;
 
-	up (&port->sem);
+	/* shutdown any bulk reads that might be going on */
+	usb_unlink_urb (port->write_urb);
+	usb_unlink_urb (port->read_urb);
+	usb_unlink_urb (port->interrupt_in_urb);
+
+	port->interrupt_in_urb->dev = port->serial->dev;
+	result = usb_submit_urb(port->interrupt_in_urb);
+	if (result)
+		err(" usb_submit_urb(read int) failed");
+	dbg("%s - usb_submit_urb(int urb)", __FUNCTION__);
 
 	return result;
 }
 
 static void cyberjack_close (struct usb_serial_port *port, struct file *filp)
 {
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	down (&port->sem);
-
-	--port->open_count;
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	if (port->open_count <= 0) {
-		if (port->serial->dev) {
-			/* shutdown any bulk reads that might be going on */
-			usb_unlink_urb (port->write_urb);
-			usb_unlink_urb (port->read_urb);
-			usb_unlink_urb (port->interrupt_in_urb);
-		}
-
-		port->active = 0;
-		port->open_count = 0;
+	if (port->serial->dev) {
+		/* shutdown any bulk reads that might be going on */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->read_urb);
+		usb_unlink_urb (port->interrupt_in_urb);
 	}
-
-	up (&port->sem);
-	MOD_DEC_USE_COUNT;
 }
 
 static int cyberjack_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
@@ -220,32 +188,28 @@
 	int result;
 	int wrexpected;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
-	dbg(__FUNCTION__ " - from_user %d", from_user);
+	dbg("%s - port %d", __FUNCTION__, port->number);
+	dbg("%s - from_user %d", __FUNCTION__, from_user);
 
 	if (count == 0) {
-		dbg(__FUNCTION__ " - write request of 0 bytes");
+		dbg("%s - write request of 0 bytes", __FUNCTION__);
 		return (0);
 	}
 
 	if (port->write_urb->status == -EINPROGRESS) {
-		dbg (__FUNCTION__ " - already writing");
+		dbg("%s - already writing", __FUNCTION__);
 		return (0);
 	}
 
-	down (&port->sem);
-
 	if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ) {
 		/* To much data  for buffer. Reset buffer. */
 		priv->wrfilled=0;
-		up (&port->sem);
 		return (0);
 	}
 
 	/* Copy data */
 	if (from_user) {
 		if (copy_from_user(priv->wrbuf+priv->wrfilled, buf, count)) {
-			up (&port->sem);
 			return -EFAULT;
 		}
 	} else {
@@ -257,7 +221,7 @@
 
 	if( priv->wrfilled >= 3 ) {
 		wrexpected = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3;
-		dbg(__FUNCTION__ " - expected data: %d", wrexpected);
+		dbg("%s - expected data: %d", __FUNCTION__, wrexpected);
 	} else {
 		wrexpected = sizeof(priv->wrbuf);
 	}
@@ -266,7 +230,7 @@
 		/* We have enough data to begin transmission */
 		int length;
 
-		dbg(__FUNCTION__ " - transmitting data (frame 1)");
+		dbg("%s - transmitting data (frame 1)", __FUNCTION__);
 		length = (wrexpected > port->bulk_out_size) ? port->bulk_out_size : wrexpected;
 
 		memcpy (port->write_urb->transfer_buffer, priv->wrbuf, length );
@@ -284,26 +248,24 @@
 		/* send the data out the bulk port */
 		result = usb_submit_urb(port->write_urb);
 		if (result) {
-			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+			err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 			/* Throw away data. No better idea what to do with it. */
 			priv->wrfilled=0;
 			priv->wrsent=0;
-			up (&port->sem);
 			return 0;
 		}
 
-		dbg(__FUNCTION__ " - priv->wrsent=%d",priv->wrsent);
-		dbg(__FUNCTION__ " - priv->wrfilled=%d",priv->wrfilled);
+		dbg("%s - priv->wrsent=%d", __FUNCTION__,priv->wrsent);
+		dbg("%s - priv->wrfilled=%d", __FUNCTION__,priv->wrfilled);
 
 		if( priv->wrsent>=priv->wrfilled ) {
-			dbg(__FUNCTION__ " - buffer cleaned");
+			dbg("%s - buffer cleaned", __FUNCTION__);
 			memset( priv->wrbuf, 0, sizeof(priv->wrbuf) );
 			priv->wrfilled=0;
 			priv->wrsent=0;
 		}
 	}
 
-	up (&port->sem);
 	return (count);
 } 
 
@@ -316,7 +278,7 @@
 
 	if (port_paranoia_check (port, __FUNCTION__)) return;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	/* the urb might have been killed. */
 	if (urb->status)
@@ -349,14 +311,14 @@
 		/* "+=" is probably more fault tollerant than "=" */
 		priv->rdtodo += size;
 
-		dbg(__FUNCTION__ " - rdtodo: %d", priv->rdtodo);
+		dbg("%s - rdtodo: %d", __FUNCTION__, priv->rdtodo);
 
 		if( !old_rdtodo ) {
 			port->read_urb->dev = port->serial->dev;
 			result = usb_submit_urb(port->read_urb);
 			if( result )
-				err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
-			dbg(__FUNCTION__ " - usb_submit_urb(read urb)");
+				err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
+			dbg("%s - usb_submit_urb(read urb)", __FUNCTION__);
 		}
 	}
 }
@@ -371,16 +333,16 @@
 	int i;
 	int result;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 
 	if (urb->status) {
 		usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
-		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
@@ -404,15 +366,15 @@
 	/* Just to be sure */
 	if( priv->rdtodo<0 ) priv->rdtodo=0;
 
-	dbg(__FUNCTION__ " - rdtodo: %d", priv->rdtodo);
+	dbg("%s - rdtodo: %d", __FUNCTION__, priv->rdtodo);
 
 	/* Continue to read if we have still urbs to do. */
 	if( priv->rdtodo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/ ) {
 		port->read_urb->dev = port->serial->dev;
 		result = usb_submit_urb(port->read_urb);
 		if (result)
-			err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
-		dbg(__FUNCTION__ " - usb_submit_urb(read urb)");
+			err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
+		dbg("%s - usb_submit_urb(read urb)", __FUNCTION__);
 	}
 }
 
@@ -422,15 +384,15 @@
 	struct cyberjack_private *priv = (struct cyberjack_private *)port->private;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
@@ -439,13 +401,11 @@
 		int length, blksize, result;
 
 		if (port->write_urb->status == -EINPROGRESS) {
-			dbg (__FUNCTION__ " - already writing");
+			dbg("%s - already writing", __FUNCTION__);
 			return;
 		}
 
-		down (&port->sem);
-
-		dbg(__FUNCTION__ " - transmitting data (frame n)");
+		dbg("%s - transmitting data (frame n)", __FUNCTION__);
 
 		length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ?
 			port->bulk_out_size : (priv->wrfilled - priv->wrsent);
@@ -466,29 +426,27 @@
 		/* send the data out the bulk port */
 		result = usb_submit_urb(port->write_urb);
 		if (result) {
-			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+			err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 			/* Throw away data. No better idea what to do with it. */
 			priv->wrfilled=0;
 			priv->wrsent=0;
-			up (&port->sem);
 			queue_task(&port->tqueue, &tq_immediate);
 			mark_bh(IMMEDIATE_BH);
 			return;
 		}
 
-		dbg(__FUNCTION__ " - priv->wrsent=%d",priv->wrsent);
-		dbg(__FUNCTION__ " - priv->wrfilled=%d",priv->wrfilled);
+		dbg("%s - priv->wrsent=%d", __FUNCTION__,priv->wrsent);
+		dbg("%s - priv->wrfilled=%d", __FUNCTION__,priv->wrfilled);
 
 		blksize = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3;
 
 		if( (priv->wrsent>=priv->wrfilled) || (priv->wrsent>=blksize) ) {
-			dbg(__FUNCTION__ " - buffer cleaned");
+			dbg("%s - buffer cleaned", __FUNCTION__);
 			memset( priv->wrbuf, 0, sizeof(priv->wrbuf) );
 			priv->wrfilled=0;
 			priv->wrsent=0;
 		}
 
-		up (&port->sem);
 		queue_task(&port->tqueue, &tq_immediate);
 		mark_bh(IMMEDIATE_BH);
 		return;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/digi_acceleport.c linux-2.4.20/drivers/usb/serial/digi_acceleport.c
--- linux-2.4.19/drivers/usb/serial/digi_acceleport.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/digi_acceleport.c	2002-10-29 11:18:40.000000000 +0000
@@ -14,6 +14,10 @@
 *  Peter Berger (pberger@brimson.com)
 *  Al Borchers (borchers@steinerpoint.com)
 * 
+* (12/03/2001) gkh
+*	switched to using port->open_count instead of private version.
+*	Removed port->active
+*
 * (04/08/2001) gb
 *	Identify version on module load.
 *
@@ -231,19 +235,16 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/tqueue.h>
+#include <asm/uaccess.h>
 #include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
@@ -411,14 +412,14 @@
 
 /* Structures */
 
-typedef struct digi_serial {
+struct digi_serial {
 	spinlock_t ds_serial_lock;
 	struct usb_serial_port *ds_oob_port;	/* out-of-band port */
 	int ds_oob_port_num;			/* index of out-of-band port */
 	int ds_device_started;
-} digi_serial_t;
+};
 
-typedef struct digi_port {
+struct digi_port {
 	spinlock_t dp_port_lock;
 	int dp_port_num;
 	int dp_out_buf_len;
@@ -429,7 +430,6 @@
 	int dp_write_urb_in_use;
 	unsigned int dp_modem_signals;
 	wait_queue_head_t dp_modem_change_wait;
-	int dp_open_count;			/* inc on open, dec on close */
 	int dp_transmit_idle;
 	wait_queue_head_t dp_transmit_idle_wait;
 	int dp_throttled;
@@ -438,7 +438,7 @@
 	int dp_in_close;			/* close in progress */
 	wait_queue_head_t dp_close_wait;	/* wait queue for close */
 	struct tq_struct dp_wakeup_task;
-} digi_port_t;
+};
 
 
 /* Local Function Declarations */
@@ -483,12 +483,12 @@
 	{ }						/* Terminating entry */
 };
 
-static __devinitdata struct usb_device_id id_table_2 [] = {
+static struct usb_device_id id_table_2 [] = {
 	{ USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) },
 	{ }						/* Terminating entry */
 };
 
-static __devinitdata struct usb_device_id id_table_4 [] = {
+static struct usb_device_id id_table_4 [] = {
 	{ USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) },
 	{ }						/* Terminating entry */
 };
@@ -498,55 +498,51 @@
 /* device info needed for the Digi serial converter */
 
 static struct usb_serial_device_type digi_acceleport_2_device = {
-	name:				"Digi USB",
-	id_table:			id_table_2,
-	needs_interrupt_in:		DONT_CARE,
-	needs_bulk_in:			MUST_HAVE,
-	needs_bulk_out:			MUST_HAVE,
-	num_interrupt_in:		0,
-	num_bulk_in:			4,
-	num_bulk_out:			4,
-	num_ports:			3,
-	open:				digi_open,
-	close:				digi_close,
-	write:				digi_write,
-	write_room:			digi_write_room,
-	write_bulk_callback: 		digi_write_bulk_callback,
-	read_bulk_callback:		digi_read_bulk_callback,
-	chars_in_buffer:		digi_chars_in_buffer,
-	throttle:			digi_rx_throttle,
-	unthrottle:			digi_rx_unthrottle,
-	ioctl:				digi_ioctl,
-	set_termios:			digi_set_termios,
-	break_ctl:			digi_break_ctl,
-	startup:			digi_startup,
-	shutdown:			digi_shutdown,
+	.owner =			THIS_MODULE,
+	.name =				"Digi USB",
+	.id_table =			id_table_2,
+	.num_interrupt_in =		0,
+	.num_bulk_in =			4,
+	.num_bulk_out =			4,
+	.num_ports =			3,
+	.open =				digi_open,
+	.close =			digi_close,
+	.write =			digi_write,
+	.write_room =			digi_write_room,
+	.write_bulk_callback = 		digi_write_bulk_callback,
+	.read_bulk_callback =		digi_read_bulk_callback,
+	.chars_in_buffer =		digi_chars_in_buffer,
+	.throttle =			digi_rx_throttle,
+	.unthrottle =			digi_rx_unthrottle,
+	.ioctl =			digi_ioctl,
+	.set_termios =			digi_set_termios,
+	.break_ctl =			digi_break_ctl,
+	.startup =			digi_startup,
+	.shutdown =			digi_shutdown,
 };
 
 static struct usb_serial_device_type digi_acceleport_4_device = {
-	name:				"Digi USB",
-	id_table:			id_table_4,
-	needs_interrupt_in:		DONT_CARE,
-	needs_bulk_in:			MUST_HAVE,
-	needs_bulk_out:			MUST_HAVE,
-	num_interrupt_in:		0,
-	num_bulk_in:			5,
-	num_bulk_out:			5,
-	num_ports:			4,
-	open:				digi_open,
-	close:				digi_close,
-	write:				digi_write,
-	write_room:			digi_write_room,
-	write_bulk_callback: 		digi_write_bulk_callback,
-	read_bulk_callback:		digi_read_bulk_callback,
-	chars_in_buffer:		digi_chars_in_buffer,
-	throttle:			digi_rx_throttle,
-	unthrottle:			digi_rx_unthrottle,
-	ioctl:				digi_ioctl,
-	set_termios:			digi_set_termios,
-	break_ctl:			digi_break_ctl,
-	startup:			digi_startup,
-	shutdown:			digi_shutdown,
+	.owner =			THIS_MODULE,
+	.name =				"Digi USB",
+	.id_table =			id_table_4,
+	.num_interrupt_in =		0,
+	.num_bulk_in =			5,
+	.num_bulk_out =			5,
+	.num_ports =			4,
+	.open =				digi_open,
+	.close =			digi_close,
+	.write =			digi_write,
+	.write_room =			digi_write_room,
+	.write_bulk_callback = 		digi_write_bulk_callback,
+	.read_bulk_callback =		digi_read_bulk_callback,
+	.chars_in_buffer =		digi_chars_in_buffer,
+	.throttle =			digi_rx_throttle,
+	.unthrottle =			digi_rx_unthrottle,
+	.ioctl =			digi_ioctl,
+	.set_termios =			digi_set_termios,
+	.break_ctl =			digi_break_ctl,
+	.startup =			digi_startup,
+	.shutdown =			digi_shutdown,
 };
 
 
@@ -600,13 +596,12 @@
 {
 
 	unsigned long flags;
-	digi_port_t *priv = (digi_port_t *)(port->private);
+	struct digi_port *priv = (struct digi_port *)(port->private);
 
 
 	spin_lock_irqsave( &priv->dp_port_lock, flags );
 	digi_wakeup_write( port );
 	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-	MOD_DEC_USE_COUNT;
 }
 
 static void digi_wakeup_write( struct usb_serial_port *port )
@@ -647,8 +642,8 @@
 
 	int ret = 0;
 	int len;
-	struct usb_serial_port *oob_port = (struct usb_serial_port *)((digi_serial_t *)port->serial->private)->ds_oob_port;
-	digi_port_t *oob_priv = (digi_port_t *)oob_port->private;
+	struct usb_serial_port *oob_port = (struct usb_serial_port *)((struct digi_serial *)port->serial->private)->ds_oob_port;
+	struct digi_port *oob_priv = (struct digi_port *)oob_port->private;
 	unsigned long flags = 0;
 
 
@@ -689,7 +684,7 @@
 	spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );
 
 	if( ret ) {
-		err( __FUNCTION__ ": usb_submit_urb failed, ret=%d",
+		err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__,
 			ret );
 	}
 
@@ -716,7 +711,7 @@
 
 	int ret = 0;
 	int len;
-	digi_port_t *priv = (digi_port_t *)(port->private);
+	struct digi_port *priv = (struct digi_port *)(port->private);
 	unsigned char *data = port->write_urb->transfer_buffer;
 	unsigned long flags = 0;
 
@@ -778,7 +773,7 @@
 	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
 
 	if( ret ) {
-		err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+		err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__,
 		ret, priv->dp_port_num );
 	}
 
@@ -802,9 +797,9 @@
 {
 
 	int ret;
-	digi_port_t *port_priv = (digi_port_t *)port->private;
-	struct usb_serial_port *oob_port = (struct usb_serial_port *)((digi_serial_t *)port->serial->private)->ds_oob_port;
-	digi_port_t *oob_priv = (digi_port_t *)oob_port->private;
+	struct digi_port *port_priv = (struct digi_port *)port->private;
+	struct usb_serial_port *oob_port = (struct usb_serial_port *)((struct digi_serial *)port->serial->private)->ds_oob_port;
+	struct digi_port *oob_priv = (struct digi_port *)oob_port->private;
 	unsigned char *data = oob_port->write_urb->transfer_buffer;
 	unsigned long flags = 0;
 
@@ -854,7 +849,7 @@
 	spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );
 
 	if( ret ) {
-		err( __FUNCTION__ ": usb_submit_urb failed, ret=%d",
+		err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__,
 		ret );
 	}
 
@@ -881,7 +876,7 @@
 
 	int ret;
 	unsigned char buf[2];
-	digi_port_t *priv = (digi_port_t *)(port->private);
+	struct digi_port *priv = (struct digi_port *)(port->private);
 	unsigned long flags = 0;
 
 
@@ -921,7 +916,7 @@
 {
 
 	unsigned long flags;
-	digi_port_t *priv = (digi_port_t *)(port->private);
+	struct digi_port *priv = (struct digi_port *)(port->private);
 
 
 dbg( "digi_rx_throttle: TOP: port=%d", priv->dp_port_num );
@@ -942,7 +937,7 @@
 	int ret = 0;
 	int len;
 	unsigned long flags;
-	digi_port_t *priv = (digi_port_t *)(port->private);
+	struct digi_port *priv = (struct digi_port *)(port->private);
 	struct tty_struct *tty = port->tty;
 
 
@@ -975,7 +970,7 @@
 	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
 
 	if( ret ) {
-		err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+		err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__,
 			ret, priv->dp_port_num );
 	}
 
@@ -986,7 +981,7 @@
 	struct termios *old_termios )
 {
 
-	digi_port_t *priv = (digi_port_t *)(port->private);
+	struct digi_port *priv = (struct digi_port *)(port->private);
 	unsigned int iflag = port->tty->termios->c_iflag;
 	unsigned int cflag = port->tty->termios->c_cflag;
 	unsigned int old_iflag = old_termios->c_iflag;
@@ -1210,7 +1205,7 @@
 	unsigned int cmd, unsigned long arg )
 {
 
-	digi_port_t *priv = (digi_port_t *)(port->private);
+	struct digi_port *priv = (struct digi_port *)(port->private);
 	unsigned int val;
 	unsigned long flags = 0;
 
@@ -1262,7 +1257,7 @@
 {
 
 	int ret,data_len,new_len;
-	digi_port_t *priv = (digi_port_t *)(port->private);
+	struct digi_port *priv = (struct digi_port *)(port->private);
 	unsigned char *data = port->write_urb->transfer_buffer;
 	unsigned char user_buf[64];	/* 64 bytes is max USB bulk packet */
 	unsigned long flags = 0;
@@ -1334,7 +1329,7 @@
 	/* return length of new data written, or error */
 	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
 	if( ret < 0 ) {
-		err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+		err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__,
 			ret, priv->dp_port_num );
 	}
 
@@ -1349,27 +1344,27 @@
 
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct usb_serial *serial;
-	digi_port_t *priv;
+	struct digi_port *priv;
 	int ret = 0;
 
 
 dbg( "digi_write_bulk_callback: TOP, urb->status=%d", urb->status );
 
 	/* port and serial sanity check */
-	if( port == NULL || (priv=(digi_port_t *)(port->private)) == NULL ) {
-		err( __FUNCTION__ ": port or port->private is NULL, status=%d",
+	if( port == NULL || (priv=(struct digi_port *)(port->private)) == NULL ) {
+		err("%s: port or port->private is NULL, status=%d", __FUNCTION__,
 			urb->status );
 		return;
 	}
 	serial = port->serial;
 	if( serial == NULL || serial->private == NULL ) {
-		err( __FUNCTION__ ": serial or serial->private is NULL, status=%d", urb->status );
+		err("%s: serial or serial->private is NULL, status=%d", __FUNCTION__, urb->status );
 		return;
 	}
 
 	/* handle oob callback */
 	if( priv->dp_port_num
-	== ((digi_serial_t *)(serial->private))->ds_oob_port_num ) {
+	== ((struct digi_serial *)(serial->private))->ds_oob_port_num ) {
 		dbg( "digi_write_bulk_callback: oob callback" );
 		spin_lock( &priv->dp_port_lock );
 		priv->dp_write_urb_in_use = 0;
@@ -1386,7 +1381,7 @@
 	/* try to send any buffered data on this port, if it is open */
 	spin_lock( &priv->dp_port_lock );
 	priv->dp_write_urb_in_use = 0;
-	if( priv->dp_open_count && port->write_urb->status != -EINPROGRESS
+	if( port->open_count && port->write_urb->status != -EINPROGRESS
 	&& priv->dp_out_buf_len > 0 ) {
 
 		*((unsigned char *)(port->write_urb->transfer_buffer))
@@ -1413,14 +1408,12 @@
 
 	/* also queue up a wakeup at scheduler time, in case we */
 	/* lost the race in write_chan(). */
-	MOD_INC_USE_COUNT;
-	if (schedule_task(&priv->dp_wakeup_task) == 0)
-		MOD_DEC_USE_COUNT;
+	schedule_task(&priv->dp_wakeup_task);
 
 	spin_unlock( &priv->dp_port_lock );
 
 	if( ret ) {
-		err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+		err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__,
 			ret, priv->dp_port_num );
 	}
 
@@ -1431,7 +1424,7 @@
 {
 
 	int room;
-	digi_port_t *priv = (digi_port_t *)(port->private);
+	struct digi_port *priv = (struct digi_port *)(port->private);
 	unsigned long flags = 0;
 
 
@@ -1454,7 +1447,7 @@
 static int digi_chars_in_buffer( struct usb_serial_port *port )
 {
 
-	digi_port_t *priv = (digi_port_t *)(port->private);
+	struct digi_port *priv = (struct digi_port *)(port->private);
 
 
 	if( port->write_urb->status == -EINPROGRESS
@@ -1475,12 +1468,12 @@
 
 	int ret;
 	unsigned char buf[32];
-	digi_port_t *priv = (digi_port_t *)(port->private);
+	struct digi_port *priv = (struct digi_port *)(port->private);
 	struct termios not_termios;
 	unsigned long flags = 0;
 
 
-dbg( "digi_open: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, port->active, priv->dp_open_count );
+dbg( "digi_open: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_count );
 
 	/* be sure the device is started up */
 	if( digi_startup_device( port->serial ) != 0 )
@@ -1494,32 +1487,17 @@
 		return( -EAGAIN );
 	}
 
-	/* inc module use count before sleeping to wait for closes */
-	++priv->dp_open_count;
-	MOD_INC_USE_COUNT;
-
 	/* wait for a close in progress to finish */
 	while( priv->dp_in_close ) {
 		cond_wait_interruptible_timeout_irqrestore(
 			&priv->dp_close_wait, DIGI_RETRY_TIMEOUT,
 			&priv->dp_port_lock, flags );
 		if( signal_pending(current) ) {
-			--priv->dp_open_count;
-			MOD_DEC_USE_COUNT;
 			return( -EINTR );
 		}
 		spin_lock_irqsave( &priv->dp_port_lock, flags );
 	}
 
-	/* if port is already open, just return */
-	/* be sure exactly one open proceeds */
-	if( port->active ) {
-		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-		return( 0 );
-	}
-
-	/* first open, mark port as active */
-	port->active = 1;
 	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
  
 	/* read modem signals automatically whenever they change */
@@ -1556,24 +1534,15 @@
 	int ret;
 	unsigned char buf[32];
 	struct tty_struct *tty = port->tty;
-	digi_port_t *priv = (digi_port_t *)port->private;
+	struct digi_port *priv = (struct digi_port *)port->private;
 	unsigned long flags = 0;
 
 
-dbg( "digi_close: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, port->active, priv->dp_open_count );
+dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_count );
 
 
 	/* do cleanup only after final close on this port */
 	spin_lock_irqsave( &priv->dp_port_lock, flags );
-	if( priv->dp_open_count > 1 ) {
-		--priv->dp_open_count;
-		MOD_DEC_USE_COUNT;
-		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-		return;
-	} else if( priv->dp_open_count <= 0 ) {
-		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-		return;
-	}
 	priv->dp_in_close = 1;
 	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
 
@@ -1644,11 +1613,8 @@
 	tty->closing = 0;
 
 	spin_lock_irqsave( &priv->dp_port_lock, flags );
-	port->active = 0;
 	priv->dp_write_urb_in_use = 0;
 	priv->dp_in_close = 0;
-	--priv->dp_open_count;
-	MOD_DEC_USE_COUNT;
 	wake_up_interruptible( &priv->dp_close_wait );
 	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
 
@@ -1667,7 +1633,7 @@
 {
 
 	int i,ret = 0;
-	digi_serial_t *serial_priv = (digi_serial_t *)serial->private;
+	struct digi_serial *serial_priv = (struct digi_serial *)serial->private;
 	struct usb_serial_port *port;
 
 
@@ -1689,8 +1655,7 @@
 		port->write_urb->dev = port->serial->dev;
 
 		if( (ret=usb_submit_urb(port->read_urb)) != 0 ) {
-			err(
-			__FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+			err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__,
 			ret, i );
 			break;
 		}
@@ -1706,8 +1671,8 @@
 {
 
 	int i;
-	digi_port_t *priv;
-	digi_serial_t *serial_priv;
+	struct digi_port *priv;
+	struct digi_serial *serial_priv;
 
 
 dbg( "digi_startup: TOP" );
@@ -1716,13 +1681,11 @@
 	/* number of regular ports + 1 for the out-of-band port */
 	for( i=0; i<serial->type->num_ports+1; i++ ) {
 
-		serial->port[i].active = 0;
-
 		/* allocate port private structure */
 		priv = serial->port[i].private =
-			(digi_port_t *)kmalloc( sizeof(digi_port_t),
+			(struct digi_port *)kmalloc( sizeof(struct digi_port),
 			GFP_KERNEL );
-		if( priv == (digi_port_t *)0 ) {
+		if( priv == (struct digi_port *)0 ) {
 			while( --i >= 0 )
 				kfree( serial->port[i].private );
 			return( 1 );			/* error */
@@ -1736,7 +1699,6 @@
 		priv->dp_write_urb_in_use = 0;
 		priv->dp_modem_signals = 0;
 		init_waitqueue_head( &priv->dp_modem_change_wait );
-		priv->dp_open_count = 0;
 		priv->dp_transmit_idle = 0;
 		init_waitqueue_head( &priv->dp_transmit_idle_wait );
 		priv->dp_throttled = 0;
@@ -1756,9 +1718,9 @@
 
 	/* allocate serial private structure */
 	serial_priv = serial->private =
-		(digi_serial_t *)kmalloc( sizeof(digi_serial_t),
+		(struct digi_serial *)kmalloc( sizeof(struct digi_serial),
 		GFP_KERNEL );
-	if( serial_priv == (digi_serial_t *)0 ) {
+	if( serial_priv == (struct digi_serial *)0 ) {
 		for( i=0; i<serial->type->num_ports+1; i++ )
 			kfree( serial->port[i].private );
 		return( 1 );			/* error */
@@ -1779,8 +1741,6 @@
 {
 
 	int i;
-	digi_port_t *priv;
-	unsigned long flags;
 
 
 dbg( "digi_shutdown: TOP, in_interrupt()=%d", in_interrupt() );
@@ -1791,17 +1751,6 @@
 		usb_unlink_urb( serial->port[i].write_urb );
 	}
 
-	/* dec module use count */
-	for( i=0; i<serial->type->num_ports; i++ ) {
-		priv = serial->port[i].private;
-		spin_lock_irqsave( &priv->dp_port_lock, flags );
-		while( priv->dp_open_count > 0 ) {
-			MOD_DEC_USE_COUNT;
-			--priv->dp_open_count;
-		}
-		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-	}
-
 	/* free the private data structures for all ports */
 	/* number of regular ports + 1 for the out-of-band port */
 	for( i=0; i<serial->type->num_ports+1; i++ )
@@ -1815,34 +1764,34 @@
 {
 
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-	digi_port_t *priv;
+	struct digi_port *priv;
 	int ret;
 
 
 dbg( "digi_read_bulk_callback: TOP" );
 
 	/* port sanity check, do not resubmit if port is not valid */
-	if( port == NULL || (priv=(digi_port_t *)(port->private)) == NULL ) {
-		err( __FUNCTION__ ": port or port->private is NULL, status=%d",
+	if( port == NULL || (priv=(struct digi_port *)(port->private)) == NULL ) {
+		err("%s: port or port->private is NULL, status=%d", __FUNCTION__,
 			urb->status );
 		return;
 	}
 	if( port->serial == NULL
 	|| serial_paranoia_check( port->serial, __FUNCTION__ )
 	|| port->serial->private == NULL ) {
-		err( __FUNCTION__ ": serial is bad or serial->private is NULL, status=%d", urb->status );
+		err("%s: serial is bad or serial->private is NULL, status=%d", __FUNCTION__, urb->status );
 		return;
 	}
 
 	/* do not resubmit urb if it has any status error */
 	if( urb->status ) {
-		err( __FUNCTION__ ": nonzero read bulk status: status=%d, port=%d", urb->status, priv->dp_port_num );
+		err("%s: nonzero read bulk status: status=%d, port=%d", __FUNCTION__, urb->status, priv->dp_port_num );
 		return;
 	}
 
 	/* handle oob or inb callback, do not resubmit if error */
 	if( priv->dp_port_num
-	== ((digi_serial_t *)(port->serial->private))->ds_oob_port_num ) {
+	== ((struct digi_serial *)(port->serial->private))->ds_oob_port_num ) {
 		if( digi_read_oob_callback( urb ) != 0 )
 			return;
 	} else {
@@ -1853,7 +1802,7 @@
 	/* continue read */
 	urb->dev = port->serial->dev;
 	if( (ret=usb_submit_urb(urb)) != 0 ) {
-		err( __FUNCTION__ ": failed resubmitting urb, ret=%d, port=%d",
+		err("%s: failed resubmitting urb, ret=%d, port=%d", __FUNCTION__,
 			ret, priv->dp_port_num );
 	}
 
@@ -1875,7 +1824,7 @@
 
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct tty_struct *tty = port->tty;
-	digi_port_t *priv = (digi_port_t *)(port->private);
+	struct digi_port *priv = (struct digi_port *)(port->private);
 	int opcode = ((unsigned char *)urb->transfer_buffer)[0];
 	int len = ((unsigned char *)urb->transfer_buffer)[1];
 	int status = ((unsigned char *)urb->transfer_buffer)[2];
@@ -1889,12 +1838,12 @@
 
 	/* do not process callbacks on closed ports */
 	/* but do continue the read chain */
-	if( priv->dp_open_count == 0 )
+	if( port->open_count == 0 )
 		return( 0 );
 
 	/* short/multiple packet check */
 	if( urb->actual_length != len + 2 ) {
-     		err( __FUNCTION__ ": INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", urb->status, priv->dp_port_num, opcode, len, urb->actual_length, status );
+     		err("%s: INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", __FUNCTION__, urb->status, priv->dp_port_num, opcode, len, urb->actual_length, status );
 		return( -1 );
 	}
 
@@ -1963,9 +1912,9 @@
 	spin_unlock( &priv->dp_port_lock );
 
 	if( opcode == DIGI_CMD_RECEIVE_DISABLE ) {
-		dbg( __FUNCTION__ ": got RECEIVE_DISABLE" );
+		dbg("%s: got RECEIVE_DISABLE", __FUNCTION__ );
 	} else if( opcode != DIGI_CMD_RECEIVE_DATA ) {
-		dbg( __FUNCTION__ ": unknown opcode: %d", opcode );
+		dbg("%s: unknown opcode: %d", __FUNCTION__, opcode );
 	}
 
 	return( throttled ? 1 : 0 );
@@ -1987,7 +1936,7 @@
 
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct usb_serial *serial = port->serial;
-	digi_port_t *priv = (digi_port_t *)(port->private);
+	struct digi_port *priv = (struct digi_port *)(port->private);
 	int opcode, line, status, val;
 	int i;
 
@@ -2023,7 +1972,7 @@
 			if( val & DIGI_READ_INPUT_SIGNALS_CTS ) {
 				priv->dp_modem_signals |= TIOCM_CTS;
 				/* port must be open to use tty struct */
-				if( priv->dp_open_count
+				if( port->open_count
 				&& port->tty->termios->c_cflag & CRTSCTS ) {
 					port->tty->hw_stopped = 0;
 					digi_wakeup_write( port );
@@ -2031,7 +1980,7 @@
 			} else {
 				priv->dp_modem_signals &= ~TIOCM_CTS;
 				/* port must be open to use tty struct */
-				if( priv->dp_open_count
+				if( port->open_count
 				&& port->tty->termios->c_cflag & CRTSCTS ) {
 					port->tty->hw_stopped = 1;
 				}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/empeg.c linux-2.4.20/drivers/usb/serial/empeg.c
--- linux-2.4.19/drivers/usb/serial/empeg.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/empeg.c	2002-10-29 11:18:40.000000000 +0000
@@ -53,18 +53,15 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <asm/uaccess.h>
 #include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
@@ -106,7 +103,7 @@
 static void empeg_write_bulk_callback	(struct urb *urb);
 static void empeg_read_bulk_callback	(struct urb *urb);
 
-static __devinitdata struct usb_device_id id_table [] = {
+static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(EMPEG_VENDOR_ID, EMPEG_PRODUCT_ID) },
 	{ }					/* Terminating entry */
 };
@@ -114,28 +111,26 @@
 MODULE_DEVICE_TABLE (usb, id_table);
 
 static struct usb_serial_device_type empeg_device = {
-	name:			"Empeg",
-	id_table:		id_table,
-	needs_interrupt_in:	MUST_HAVE_NOT,	/* must not have an interrupt in endpoint */
-	needs_bulk_in:		MUST_HAVE,	/* must have a bulk in endpoint */
-	needs_bulk_out:		MUST_HAVE,	/* must have a bulk out endpoint */
-	num_interrupt_in:	0,
-	num_bulk_in:		1,
-	num_bulk_out:		1,
-	num_ports:		1,
-	open:			empeg_open,
-	close:			empeg_close,
-	throttle:		empeg_throttle,
-	unthrottle:		empeg_unthrottle,
-	startup:		empeg_startup,
-	shutdown:		empeg_shutdown,
-	ioctl:			empeg_ioctl,
-	set_termios:		empeg_set_termios,
-	write:			empeg_write,
-	write_room:		empeg_write_room,
-	chars_in_buffer:	empeg_chars_in_buffer,
-	write_bulk_callback:	empeg_write_bulk_callback,
-	read_bulk_callback:	empeg_read_bulk_callback,
+	.owner =		THIS_MODULE,
+	.name =			"Empeg",
+	.id_table =		id_table,
+	.num_interrupt_in =	0,
+	.num_bulk_in =		1,
+	.num_bulk_out =		1,
+	.num_ports =		1,
+	.open =			empeg_open,
+	.close =		empeg_close,
+	.throttle =		empeg_throttle,
+	.unthrottle =		empeg_unthrottle,
+	.startup =		empeg_startup,
+	.shutdown =		empeg_shutdown,
+	.ioctl =		empeg_ioctl,
+	.set_termios =		empeg_set_termios,
+	.write =		empeg_write,
+	.write_room =		empeg_write_room,
+	.chars_in_buffer =	empeg_chars_in_buffer,
+	.write_bulk_callback =	empeg_write_bulk_callback,
+	.read_bulk_callback =	empeg_read_bulk_callback,
 };
 
 #define NUM_URBS			16
@@ -157,43 +152,31 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return -ENODEV;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	down (&port->sem);
+	/* Force default termio settings */
+	empeg_set_termios (port, NULL) ;
 
-	++port->open_count;
-	MOD_INC_USE_COUNT;
+	bytes_in = 0;
+	bytes_out = 0;
 
-	if (!port->active) {
-
-		/* Force default termio settings */
-		empeg_set_termios (port, NULL) ;
-
-		port->active = 1;
-		bytes_in = 0;
-		bytes_out = 0;
-
-		/* Start reading from the device */
-		FILL_BULK_URB(
-			port->read_urb,
-			serial->dev, 
-			usb_rcvbulkpipe(serial->dev,
-				port->bulk_in_endpointAddress),
-			port->read_urb->transfer_buffer,
-			port->read_urb->transfer_buffer_length,
-			empeg_read_bulk_callback,
-			port);
-
-		port->read_urb->transfer_flags |= USB_QUEUE_BULK;
-
-		result = usb_submit_urb(port->read_urb);
+	/* Start reading from the device */
+	FILL_BULK_URB(
+		port->read_urb,
+		serial->dev, 
+		usb_rcvbulkpipe(serial->dev,
+			port->bulk_in_endpointAddress),
+		port->read_urb->transfer_buffer,
+		port->read_urb->transfer_buffer_length,
+		empeg_read_bulk_callback,
+		port);
 
-		if (result)
-			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+	port->read_urb->transfer_flags |= USB_QUEUE_BULK;
 
-	}
+	result = usb_submit_urb(port->read_urb);
 
-	up (&port->sem);
+	if (result)
+		err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
 
 	return result;
 }
@@ -206,31 +189,18 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	serial = get_usb_serial (port, __FUNCTION__);
 	if (!serial)
 		return;
 
-	down (&port->sem);
-
-	--port->open_count;
-
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			/* shutdown our bulk read */
-			usb_unlink_urb (port->read_urb);
-		}
-		port->active = 0;
-		port->open_count = 0;
+	if (serial->dev) {
+		/* shutdown our bulk read */
+		usb_unlink_urb (port->read_urb);
 	}
-
-	up (&port->sem);
-
 	/* Uncomment the following line if you want to see some statistics in your syslog */
 	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
-
-	MOD_DEC_USE_COUNT;
 }
 
 
@@ -245,7 +215,7 @@
 	int bytes_sent = 0;
 	int transfer_size;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf);
 
@@ -266,14 +236,14 @@
 		spin_unlock_irqrestore (&write_urb_pool_lock, flags);
 
 		if (urb == NULL) {
-			dbg (__FUNCTION__ " - no more free urbs");
+			dbg("%s - no more free urbs", __FUNCTION__);
 			goto exit;
 		}
 
 		if (urb->transfer_buffer == NULL) {
-			urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+			urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC);
 			if (urb->transfer_buffer == NULL) {
-				err(__FUNCTION__" no more kernel memory...");
+				err("%s no more kernel memory...", __FUNCTION__);
 				goto exit;
 			}
 		}
@@ -305,7 +275,7 @@
 		/* send it down the pipe */
 		status = usb_submit_urb(urb);
 		if (status) {
-			err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
+			err("%s - usb_submit_urb(write bulk) failed with status = %d", __FUNCTION__, status);
 			bytes_sent = status;
 			break;
 		}
@@ -329,7 +299,7 @@
 	int i;
 	int room = 0;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	spin_lock_irqsave (&write_urb_pool_lock, flags);
 
@@ -342,7 +312,7 @@
 
 	spin_unlock_irqrestore (&write_urb_pool_lock, flags);
 
-	dbg(__FUNCTION__ " - returns %d", room);
+	dbg("%s - returns %d", __FUNCTION__, room);
 
 	return (room);
 
@@ -355,7 +325,7 @@
 	int i;
 	int chars = 0;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	spin_lock_irqsave (&write_urb_pool_lock, flags);
 
@@ -368,7 +338,7 @@
 
 	spin_unlock_irqrestore (&write_urb_pool_lock, flags);
 
-	dbg (__FUNCTION__ " - returns %d", chars);
+	dbg("%s - returns %d", __FUNCTION__, chars);
 
 	return (chars);
 
@@ -382,10 +352,10 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
@@ -409,15 +379,15 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
@@ -459,7 +429,7 @@
 	result = usb_submit_urb(port->read_urb);
 
 	if (result)
-		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+		err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
 
 	return;
 
@@ -468,16 +438,8 @@
 
 static void empeg_throttle (struct usb_serial_port *port)
 {
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	down (&port->sem);
-
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	usb_unlink_urb (port->read_urb);
-
-	up (&port->sem);
-
-	return;
-
 }
 
 
@@ -485,30 +447,25 @@
 {
 	int result;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	down (&port->sem);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	port->read_urb->dev = port->serial->dev;
 
 	result = usb_submit_urb(port->read_urb);
 
 	if (result)
-		err(__FUNCTION__ " - failed submitting read urb, error %d", result);
-
-	up (&port->sem);
+		err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
 
 	return;
-
 }
 
 
 static int  empeg_startup (struct usb_serial *serial)
 {
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
-	dbg(__FUNCTION__ " - Set config to 1");
+	dbg("%s - Set config to 1", __FUNCTION__);
 	usb_set_configuration (serial->dev, 1);
 
 	/* continue on with initialization */
@@ -519,23 +476,13 @@
 
 static void empeg_shutdown (struct usb_serial *serial)
 {
-	int i;
-
-	dbg (__FUNCTION__);
-
-	/* stop reads and writes on all ports */
-	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
-			empeg_close (&serial->port[i], NULL);
-		}
-	}
-
+	dbg ("%s", __FUNCTION__);
 }
 
 
 static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
 {
-	dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
+	dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
 
 	return -ENOIOCTLCMD;
 }
@@ -544,10 +491,10 @@
 static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios)
 {
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if ((!port->tty) || (!port->tty->termios)) {
-		dbg(__FUNCTION__" - no tty structures");
+		dbg("%s - no tty structures", __FUNCTION__);
 		return;
 	}
 
@@ -624,7 +571,8 @@
 		urb->transfer_buffer = NULL;
 		urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
 		if (!urb->transfer_buffer) {
-			err (__FUNCTION__ " - out of memory for urb buffers.");
+			err("%s - out of memory for urb buffers.", 
+			    __FUNCTION__);
 			continue;
 		}
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/ftdi_sio.c linux-2.4.20/drivers/usb/serial/ftdi_sio.c
--- linux-2.4.19/drivers/usb/serial/ftdi_sio.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/ftdi_sio.c	2002-10-29 11:18:35.000000000 +0000
@@ -4,6 +4,8 @@
  * 	Copyright (C) 1999 - 2001
  * 	    Greg Kroah-Hartman (greg@kroah.com)
  *          Bill Ryder (bryder@sgi.com)
+ *	Copyright (C) 2002
+ *	    Kuba Ober (kuba@mareimbrium.org)
  *
  * 	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
@@ -13,49 +15,63 @@
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
  * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
- *     and extra documentation
+ *	and extra documentation
+ *
+ * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch
+ *      Not tested by me but it doesn't break anything I use.
  * 
+ * (04/Jan/2002) Kuba Ober
+ *	Implemented 38400 baudrate kludge, where it can be substituted with other
+ *	  values. That's the only way to set custom baudrates.
+ *	Implemented TIOCSSERIAL, TIOCGSERIAL ioctl's so that setserial is happy.
+ *	FIXME: both baudrate things should eventually go to usbserial.c as other
+ *	  devices may need that functionality too. Actually, it can probably be
+ *	  merged in serial.c somehow - too many drivers repeat this code over
+ *	  and over.
+ *	Fixed baudrate forgetfulness - open() used to reset baudrate to 9600 every time.
+ *	Divisors for baudrates are calculated by a macro.
+ *	Small code cleanups. Ugly whitespace changes for Plato's sake only ;-].
+ *
  * (04/Nov/2001) Bill Ryder
- *     Fixed bug in read_bulk_callback where incorrect urb buffer was used.
- *     cleaned up write offset calculation
- *     added write_room since default values can be incorrect for sio
- *     changed write_bulk_callback to use same queue_task as other drivers
- *       (the previous version caused panics)
- *     Removed port iteration code since the device only has one I/O port and it 
- *       was wrong anyway.
+ *	Fixed bug in read_bulk_callback where incorrect urb buffer was used.
+ *	Cleaned up write offset calculation
+ *	Added write_room since default values can be incorrect for sio
+ *	Changed write_bulk_callback to use same queue_task as other drivers
+ *        (the previous version caused panics)
+ *	Removed port iteration code since the device only has one I/O port and it
+ *	  was wrong anyway.
  * 
  * (31/May/2001) gkh
- *	switched from using spinlock to a semaphore, which fixes lots of problems.
+ *	Switched from using spinlock to a semaphore, which fixes lots of problems.
  *
  * (23/May/2001)   Bill Ryder
- *     Added runtime debug patch (thanx Tyson D Sawyer).
- *     Cleaned up comments for 8U232
- *     Added parity, framing and overrun error handling
- *     Added receive break handling.
+ *	Added runtime debug patch (thanx Tyson D Sawyer).
+ *	Cleaned up comments for 8U232
+ *	Added parity, framing and overrun error handling
+ *	Added receive break handling.
  * 
  * (04/08/2001) gb
  *	Identify version on module load.
  *       
  * (18/March/2001) Bill Ryder
- *     (Not released)
- *     Added send break handling. (requires kernel patch too)
- *     Fixed 8U232AM hardware RTS/CTS etc status reporting.
- *     Added flipbuf fix copied from generic device
+ *	(Not released)
+ *	Added send break handling. (requires kernel patch too)
+ *	Fixed 8U232AM hardware RTS/CTS etc status reporting.
+ *	Added flipbuf fix copied from generic device
  * 
  * (12/3/2000) Bill Ryder
- *     Added support for 8U232AM device.
- *     Moved PID and VIDs into header file only.
- *     Turned on low-latency for the tty (device will do high baudrates)
- *     Added shutdown routine to close files when device removed.
- *     More debug and error message cleanups.
- *     
+ *	Added support for 8U232AM device.
+ *	Moved PID and VIDs into header file only.
+ *	Turned on low-latency for the tty (device will do high baudrates)
+ *	Added shutdown routine to close files when device removed.
+ *	More debug and error message cleanups.
  *
  * (11/13/2000) Bill Ryder
- *     Added spinlock protected open code and close code.
- *     Multiple opens work (sort of - see webpage mentioned above).
- *     Cleaned up comments. Removed multiple PID/VID definitions.
- *     Factorised cts/dtr code
- *     Made use of __FUNCTION__ in dbg's
+ *	Added spinlock protected open code and close code.
+ *	Multiple opens work (sort of - see webpage mentioned above).
+ *	Cleaned up comments. Removed multiple PID/VID definitions.
+ *	Factorised cts/dtr code
+ *	Made use of __FUNCTION__ in dbg's
  *      
  * (11/01/2000) Adam J. Richter
  *	usb_device_id table support
@@ -72,16 +88,16 @@
  *	driver is a loadable module now.
  *
  * (04/04/2000) Bill Ryder 
- *      Fixed bugs in TCGET/TCSET ioctls (by removing them - they are 
+ *	Fixed bugs in TCGET/TCSET ioctls (by removing them - they are
  *        handled elsewhere in the tty io driver chain).
  *
  * (03/30/2000) Bill Ryder 
- *      Implemented lots of ioctls
- * 	Fixed a race condition in write
- * 	Changed some dbg's to errs
+ *	Implemented lots of ioctls
+ *	Fixed a race condition in write
+ *	Changed some dbg's to errs
  *
  * (03/26/2000) gkh
- * 	Split driver up into device specific pieces.
+ *	Split driver up into device specific pieces.
  *
  */
 
@@ -90,22 +106,19 @@
 /*   to talk to the device */
 /* Thanx to gkh and the rest of the usb dev group for all code I have assimilated :-) */
 
-
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <asm/uaccess.h>
 #include <linux/usb.h>
+#include <linux/serial.h>
 #ifdef CONFIG_USB_SERIAL_DEBUG
 	static int debug = 1;
 #else
@@ -115,28 +128,30 @@
 #include "usb-serial.h"
 #include "ftdi_sio.h"
 
-
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.2.0"
-#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>"
-#define DRIVER_DESC "USB FTDI RS232 Converters Driver"
+#define DRIVER_VERSION "v1.2.1"
+#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>"
+#define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
-static __devinitdata struct usb_device_id id_table_sio [] = {
+static struct usb_device_id id_table_sio [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
 	{ }						/* Terminating entry */
 };
 
-/* THe 8U232AM has the same API as the sio except for:
-   - it can support MUCH higher baudrates (921600 at 48MHz/230400 
-     at 12MHz so .. it's baudrate setting codes are different 
-   - it has a two byte status code.
-   - it returns characters very 16ms (the FTDI does it every 40ms)
-  */
+/*
+ * The 8U232AM has the same API as the sio except for:
+ * - it can support MUCH higher baudrates; up to:
+ *   o 921600 for RS232 and 2000000 for RS422/485 at 48MHz
+ *   o 230400 at 12MHz
+ *   so .. 8U232AM's baudrate setting codes are different
+ * - it has a two byte status code.
+ * - it returns characters every 16ms (the FTDI does it every 40ms)
+ */
 
-   
-static __devinitdata struct usb_device_id id_table_8U232AM [] = {
+
+static struct usb_device_id id_table_8U232AM [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
 	{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
 	{ }						/* Terminating entry */
@@ -152,88 +167,98 @@
 
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
-
 struct ftdi_private {
-	ftdi_type_t ftdi_type;
-	__u16 last_set_data_urb_value ; /* the last data state set - needed for doing a break */
-        int write_offset;
+	ftdi_chip_type_t chip_type;
+				/* type of the device, either SIO or FT8U232AM */
+	int baud_base;		/* baud base clock for divisor setting */
+	int custom_divisor;	/* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */
+	__u16 last_set_data_urb_value ;
+				/* the last data state set - needed for doing a break */
+        int write_offset;       /* This is the offset in the usb data block to write the serial data - 
+				 * it is different between devices
+				 */
+	int flags;		/* some ASYNC_xxxx flags are supported */
+        wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
+ 	char prev_status, diff_status;        /* Used for TIOCMIWAIT */
 };
+
+/* Used for TIOCMIWAIT */
+#define FTDI_STATUS_B0_MASK	(FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD)
+#define FTDI_STATUS_B1_MASK	(FTDI_RS_BI)
+/* End TIOCMIWAIT */
+
+#define FTDI_IMPL_ASYNC_FLAGS = ( ASYNC_SPD_HI | ASYNC_SPD_VHI \
+ ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP )
+
 /* function prototypes for a FTDI serial converter */
-static int  ftdi_sio_startup		(struct usb_serial *serial);
+static int  ftdi_SIO_startup		(struct usb_serial *serial);
 static int  ftdi_8U232AM_startup	(struct usb_serial *serial);
-static void ftdi_sio_shutdown		(struct usb_serial *serial);
-static int  ftdi_sio_open		(struct usb_serial_port *port, struct file *filp);
-static void ftdi_sio_close		(struct usb_serial_port *port, struct file *filp);
-static int  ftdi_sio_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
-static int  ftdi_sio_write_room		(struct usb_serial_port *port);
-static void ftdi_sio_write_bulk_callback (struct urb *urb);
-static void ftdi_sio_read_bulk_callback	(struct urb *urb);
-static void ftdi_sio_set_termios	(struct usb_serial_port *port, struct termios * old);
-static int  ftdi_sio_ioctl		(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-static void ftdi_sio_break_ctl		(struct usb_serial_port *port, int break_state );
-
-/* Should rename most ftdi_sio's to ftdi_ now since there are two devices 
-   which share common code */ 
-
-static struct usb_serial_device_type ftdi_sio_device = {
-	name:			"FTDI SIO",
-	id_table:		id_table_sio,
-	needs_interrupt_in:	MUST_HAVE_NOT,
-	needs_bulk_in:		MUST_HAVE,
-	needs_bulk_out:		MUST_HAVE,
-	num_interrupt_in:	0,
-	num_bulk_in:		1,
-	num_bulk_out:		1,
-	num_ports:		1,
-	open:			ftdi_sio_open,
-	close:			ftdi_sio_close,
-	write:			ftdi_sio_write,
-	write_room:		ftdi_sio_write_room,
-	read_bulk_callback:	ftdi_sio_read_bulk_callback,
-	write_bulk_callback:	ftdi_sio_write_bulk_callback,
-	ioctl:			ftdi_sio_ioctl,
-	set_termios:		ftdi_sio_set_termios,
-	break_ctl:		ftdi_sio_break_ctl,
-	startup:		ftdi_sio_startup,
-        shutdown:               ftdi_sio_shutdown,
+static void ftdi_shutdown		(struct usb_serial *serial);
+static int  ftdi_open			(struct usb_serial_port *port, struct file *filp);
+static void ftdi_close			(struct usb_serial_port *port, struct file *filp);
+static int  ftdi_write			(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static int  ftdi_write_room		(struct usb_serial_port *port);
+static void ftdi_write_bulk_callback	(struct urb *urb);
+static void ftdi_read_bulk_callback	(struct urb *urb);
+static void ftdi_set_termios		(struct usb_serial_port *port, struct termios * old);
+static int  ftdi_ioctl			(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+static void ftdi_break_ctl		(struct usb_serial_port *port, int break_state );
+
+static struct usb_serial_device_type ftdi_SIO_device = {
+	.owner =		THIS_MODULE,
+	.name =			"FTDI SIO",
+	.id_table =		id_table_sio,
+	.num_interrupt_in =	0,
+	.num_bulk_in =		1,
+	.num_bulk_out =		1,
+	.num_ports =		1,
+	.open =			ftdi_open,
+	.close =		ftdi_close,
+	.write =		ftdi_write,
+	.write_room =		ftdi_write_room,
+	.read_bulk_callback =	ftdi_read_bulk_callback,
+	.write_bulk_callback =	ftdi_write_bulk_callback,
+	.ioctl =		ftdi_ioctl,
+	.set_termios =		ftdi_set_termios,
+	.break_ctl =		ftdi_break_ctl,
+	.startup =		ftdi_SIO_startup,
+	.shutdown =		ftdi_shutdown,
 };
 
 static struct usb_serial_device_type ftdi_8U232AM_device = {
-	name:			"FTDI 8U232AM",
-	id_table:		id_table_8U232AM,
-	needs_interrupt_in:	DONT_CARE,
-	needs_bulk_in:		MUST_HAVE,
-	needs_bulk_out:		MUST_HAVE,
-	num_interrupt_in:	0,
-	num_bulk_in:		1,
-	num_bulk_out:		1,
-	num_ports:		1,
-	open:			ftdi_sio_open,
-	close:			ftdi_sio_close,
-	write:			ftdi_sio_write,
-	write_room:		ftdi_sio_write_room,
-	read_bulk_callback:	ftdi_sio_read_bulk_callback,
-	write_bulk_callback:	ftdi_sio_write_bulk_callback,
-	ioctl:			ftdi_sio_ioctl,
-	set_termios:		ftdi_sio_set_termios,
-	break_ctl:		ftdi_sio_break_ctl,
-	startup:		ftdi_8U232AM_startup,
-        shutdown:               ftdi_sio_shutdown,
+	.owner =		THIS_MODULE,
+	.name =			"FTDI 8U232AM",
+	.id_table =		id_table_8U232AM,
+	.num_interrupt_in =	0,
+	.num_bulk_in =		1,
+	.num_bulk_out =		1,
+	.num_ports =		1,
+	.open =			ftdi_open,
+	.close =		ftdi_close,
+	.write =		ftdi_write,
+	.write_room =		ftdi_write_room,
+	.read_bulk_callback =	ftdi_read_bulk_callback,
+	.write_bulk_callback =	ftdi_write_bulk_callback,
+	.ioctl =		ftdi_ioctl,
+	.set_termios =		ftdi_set_termios,
+	.break_ctl =		ftdi_break_ctl,
+	.startup =		ftdi_8U232AM_startup,
+	.shutdown =		ftdi_shutdown,
 };
 
+#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+
+#define HIGH 1
+#define LOW 0
 
 /*
  * ***************************************************************************
- * FTDI SIO Serial Converter specific driver functions
+ * Utlity functions
  * ***************************************************************************
  */
 
-#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
 
-/* utility functions to set and unset dtr and rts */
-#define HIGH 1
-#define LOW 0
-static int set_rts(struct usb_device *dev, 
+static int set_rts(struct usb_device *dev,
 		   unsigned int pipe,
 		   int high_or_low)
 {
@@ -246,9 +271,11 @@
 			       ftdi_high_or_low, 0, 
 			       buf, 0, WDR_TIMEOUT));
 }
-static int set_dtr(struct usb_device *dev, 
-		   unsigned int pipe,
-		   int high_or_low)
+
+
+static int set_dtr(struct usb_device *dev,
+                   unsigned int pipe,
+                   int high_or_low)
 {
 	static char buf[1];
 	unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_DTR_HIGH : 
@@ -261,51 +288,238 @@
 }
 
 
+static __u16 get_ftdi_divisor(struct usb_serial_port * port);
+
 
-static int ftdi_sio_startup (struct usb_serial *serial)
+static int change_speed(struct usb_serial_port *port)
 {
-	struct ftdi_private *priv;
+	char buf[1];
+        __u16 urb_value;
+
+	urb_value = get_ftdi_divisor(port);
 	
+	return (usb_control_msg(port->serial->dev,
+			    usb_sndctrlpipe(port->serial->dev, 0),
+			    FTDI_SIO_SET_BAUDRATE_REQUEST,
+			    FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
+			    urb_value, 0,
+			    buf, 0, 100) < 0);
+}
+
+
+static __u16 get_ftdi_divisor(struct usb_serial_port * port)
+{ /* get_ftdi_divisor */
 	
+	struct ftdi_private * priv = (struct ftdi_private *)port->private;
+	__u16 urb_value = 0;
+	int baud;
+
+	/*
+	 * The logic involved in setting the baudrate can be cleanly split in 3 steps.
+	 * Obtaining the actual baud rate is a little tricky since unix traditionally
+	 * somehow ignored the possibility to set non-standard baud rates.
+	 * 1. Standard baud rates are set in tty->termios->c_cflag
+	 * 2. If these are not enough, you can set any speed using alt_speed as follows:
+	 *    - set tty->termios->c_cflag speed to B38400
+	 *    - set your real speed in tty->alt_speed; it gets ignored when
+	 *      alt_speed==0, (or)
+	 *    - call TIOCSSERIAL ioctl with (struct serial_struct) set as follows:
+	 *      flags & ASYNC_SPD_MASK == ASYNC_SPD_[HI, VHI, SHI, WARP], this just
+	 *      sets alt_speed to (HI: 57600, VHI: 115200, SHI: 230400, WARP: 460800)
+	 * ** Steps 1, 2 are done courtesy of tty_get_baud_rate
+	 * 3. You can also set baud rate by setting custom divisor as follows
+	 *    - set tty->termios->c_cflag speed to B38400
+	 *    - call TIOCSSERIAL ioctl with (struct serial_struct) set as follows:
+	 *      o flags & ASYNC_SPD_MASK == ASYNC_SPD_CUST
+	 *      o custom_divisor set to baud_base / your_new_baudrate
+	 * ** Step 3 is done courtesy of code borrowed from serial.c - I should really
+	 *    spend some time and separate+move this common code to serial.c, it is
+	 *    replicated in nearly every serial driver you see.
+	 */
+
+	/* 1. Get the baud rate from the tty settings, this observes alt_speed hack */
+
+	baud = tty_get_baud_rate(port->tty);
+	dbg("%s - tty_get_baud_rate reports speed %d", __FUNCTION__, baud);
+
+	/* 2. Observe async-compatible custom_divisor hack, update baudrate if needed */
+
+	if (baud == 38400 &&
+	    ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
+	     (priv->custom_divisor)) {
+		baud = priv->baud_base / priv->custom_divisor;
+		dbg("%s - custom divisor %d sets baud rate to %d", __FUNCTION__, priv->custom_divisor, baud);
+	}
+
+	/* 3. Convert baudrate to device-specific divisor */
+
+	if (!baud) baud = 9600;	
+	switch(priv->chip_type) {
+	case SIO: /* SIO chip */
+		switch(baud) {
+		case 300: urb_value = ftdi_sio_b300; break;
+		case 600: urb_value = ftdi_sio_b600; break;
+		case 1200: urb_value = ftdi_sio_b1200; break;
+		case 2400: urb_value = ftdi_sio_b2400; break;
+		case 4800: urb_value = ftdi_sio_b4800; break;
+		case 9600: urb_value = ftdi_sio_b9600; break;
+		case 19200: urb_value = ftdi_sio_b19200; break;
+		case 38400: urb_value = ftdi_sio_b38400; break;
+		case 57600: urb_value = ftdi_sio_b57600;  break;
+		case 115200: urb_value = ftdi_sio_b115200; break;
+		} /* baud */
+		if (urb_value == 0)
+			dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__,  baud);
+		break;
+	case FT8U232AM: /* 8U232AM chip */
+		if (baud <= 3000000) {
+			urb_value = FTDI_SIO_BAUD_TO_DIVISOR(baud);
+		} else {
+	                dbg("%s - Baud rate too high!", __FUNCTION__);
+		}
+		break;
+	} /* priv->chip_type */
+
+	if (urb_value == 0) {
+		urb_value = ftdi_sio_b9600;
+	} else {
+		dbg("%s - Baud rate set to %d (divisor %d) on chip %s", __FUNCTION__, baud, urb_value, (priv->chip_type == SIO) ? "SIO" : "FT8U232AM" );
+	}
+
+	return(urb_value);
+}
+
+
+static int get_serial_info(struct usb_serial_port * port, struct serial_struct * retinfo)
+{
+	struct ftdi_private * priv = (struct ftdi_private*) port->private;
+	struct serial_struct tmp;
+
+	if (!retinfo)
+		return -EFAULT;
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.flags = priv->flags;
+	tmp.baud_base = priv->baud_base;
+	tmp.custom_divisor = priv->custom_divisor;
+	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+} /* get_serial_info */
+
+
+static int set_serial_info(struct usb_serial_port * port, struct serial_struct * newinfo)
+{ /* set_serial_info */
+	struct ftdi_private * priv = (struct ftdi_private *) port->private;
+	struct serial_struct new_serial;
+	struct ftdi_private old_priv;
+
+	if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
+		return -EFAULT;
+	old_priv = * priv;
+
+	/* Do error checking and permission checking */
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		if (((new_serial.flags & ~ASYNC_USR_MASK) !=
+		     (priv->flags & ~ASYNC_USR_MASK)))
+			return -EPERM;
+		priv->flags = ((priv->flags & ~ASYNC_USR_MASK) |
+			       (new_serial.flags & ASYNC_USR_MASK));
+		priv->custom_divisor = new_serial.custom_divisor;
+		goto check_and_exit;
+	}
+
+	if ((new_serial.baud_base != priv->baud_base) ||
+	    (new_serial.baud_base < 9600))
+		return -EINVAL;
+
+	/* Make the changes - these are privileged changes! */
+
+	priv->flags = ((priv->flags & ~ASYNC_FLAGS) |
+	               (new_serial.flags & ASYNC_FLAGS));	
+	priv->custom_divisor = new_serial.custom_divisor;
+
+	port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+check_and_exit:
+	if (((old_priv.flags & ASYNC_SPD_MASK) !=
+	     (priv->flags & ASYNC_SPD_MASK)) ||
+	    (old_priv.custom_divisor != priv->custom_divisor)) {
+		if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			port->tty->alt_speed = 57600;
+		if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			port->tty->alt_speed = 115200;
+		if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+			port->tty->alt_speed = 230400;
+		if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+			port->tty->alt_speed = 460800;
+		change_speed(port);
+	}
+	
+	return (0);
+
+} /* set_serial_info */
+
+/*
+ * ***************************************************************************
+ * FTDI driver specific functions
+ * ***************************************************************************
+ */
+
+/* Startup for the SIO chip */
+static int ftdi_SIO_startup (struct usb_serial *serial)
+{
+	struct ftdi_private *priv;
+
 	priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
 	if (!priv){
-		err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct ftdi_private));
+		err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private));
 		return -ENOMEM;
 	}
 
-	priv->ftdi_type = sio;
+	priv->chip_type = SIO;
+	priv->baud_base = 12000000 / 16;
+	priv->custom_divisor = 0;
 	priv->write_offset = 1;
+ 	priv->prev_status = priv->diff_status = 0;
+	/* This will push the characters through immediately rather
+	   than queue a task to deliver them */
+	priv->flags = ASYNC_LOW_LATENCY;
 	
 	return (0);
 }
 
-
+/* Startup for the 8U232AM chip */
 static int ftdi_8U232AM_startup (struct usb_serial *serial)
 {
 	struct ftdi_private *priv;
- 
 
 	priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
 	if (!priv){
-		err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct ftdi_private));
+		err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private));
 		return -ENOMEM;
 	}
 
-	priv->ftdi_type = F8U232AM;
+	priv->chip_type = FT8U232AM;
+	priv->baud_base = 48000000 / 2; /* Would be / 16, but FTDI supports 0.125, 0.25 and 0.5 divisor fractions! */
+	priv->custom_divisor = 0;
 	priv->write_offset = 0;
+        init_waitqueue_head(&priv->delta_msr_wait);
+	/* This will push the characters through immediately rather
+	   than queue a task to deliver them */
+	priv->flags = ASYNC_LOW_LATENCY;
 	
 	return (0);
 }
 
-static void ftdi_sio_shutdown (struct usb_serial *serial)
-{
-	
-	dbg (__FUNCTION__);
 
+static void ftdi_shutdown (struct usb_serial *serial)
+{
+	dbg("%s", __FUNCTION__);
 
 	/* stop reads and writes on all ports */
 	while (serial->port[0].open_count > 0) {
-	        ftdi_sio_close (&serial->port[0], NULL);
+	        ftdi_close (&serial->port[0], NULL);
 	}
 	if (serial->port[0].private){
 		kfree(serial->port[0].private);
@@ -314,117 +528,92 @@
 }
 
 
-
-static int  ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
-{ /* ftdi_sio_open */
+static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
+{ /* ftdi_open */
 	struct termios tmp_termios;
 	struct usb_serial *serial = port->serial;
+	struct ftdi_private *priv = port->private;
+	
 	int result = 0;
 	char buf[1]; /* Needed for the usb_control_msg I think */
 
-	dbg(__FUNCTION__);
-
-	down (&port->sem);
-	
-	MOD_INC_USE_COUNT;
-	++port->open_count;
+	dbg("%s", __FUNCTION__);
 
-	if (!port->active){
-		port->active = 1;
 
-		/* This will push the characters through immediately rather 
-		   than queue a task to deliver them */
-		port->tty->low_latency = 1;
+	port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
-		/* No error checking for this (will get errors later anyway) */
-		/* See ftdi_sio.h for description of what is reset */
-		usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-				FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
-				FTDI_SIO_RESET_SIO, 
-				0, buf, 0, WDR_TIMEOUT);
+	/* No error checking for this (will get errors later anyway) */
+	/* See ftdi_sio.h for description of what is reset */
+	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
+			FTDI_SIO_RESET_SIO, 
+			0, buf, 0, WDR_TIMEOUT);
 
-		/* Setup termios defaults. According to tty_io.c the 
-		   settings are driver specific */
-		port->tty->termios->c_cflag =
-			B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	/* Termios defaults are set by usb_serial_init. We don't change
+	   port->tty->termios - this would loose speed settings, etc.
+	   This is same behaviour as serial.c/rs_open() - Kuba */
 
-		/* ftdi_sio_set_termios  will send usb control messages */
-		ftdi_sio_set_termios(port, &tmp_termios);	
+	/* ftdi_set_termios  will send usb control messages */
+	ftdi_set_termios(port, &tmp_termios);
 
-		/* Turn on RTS and DTR since we are not flow controlling by default */
-		if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) {
-			err(__FUNCTION__ " Error from DTR HIGH urb");
-		}
-		if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){
-			err(__FUNCTION__ " Error from RTS HIGH urb");
-		}
-	
-		/* Start reading from the device */
-		FILL_BULK_URB(port->read_urb, serial->dev, 
-			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-			      ftdi_sio_read_bulk_callback, port);
-		result = usb_submit_urb(port->read_urb);
-		if (result)
-			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+	/* FIXME: Flow control might be enabled, so it should be checked -
+	   we have no control of defaults! */
+	/* Turn on RTS and DTR since we are not flow controlling by default */
+	if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) {
+		err("%s Error from DTR HIGH urb", __FUNCTION__);
+	}
+	if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){
+		err("%s Error from RTS HIGH urb", __FUNCTION__);
 	}
 
-	up (&port->sem);
+	/* Start reading from the device */
+	FILL_BULK_URB(port->read_urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+		      ftdi_read_bulk_callback, port);
+	result = usb_submit_urb(port->read_urb);
+	if (result)
+		err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+
 	return result;
-} /* ftdi_sio_open */
+} /* ftdi_open */
 
 
-static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
-{ /* ftdi_sio_close */
+static void ftdi_close (struct usb_serial_port *port, struct file *filp)
+{ /* ftdi_close */
 	struct usb_serial *serial = port->serial; /* Checked in usbserial.c */
 	unsigned int c_cflag = port->tty->termios->c_cflag;
 	char buf[1];
 
-	dbg( __FUNCTION__);
-
-	down (&port->sem);
-	--port->open_count;
+	dbg("%s", __FUNCTION__);
 
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			if (c_cflag & HUPCL){
-				/* Disable flow control */
-				if (usb_control_msg(serial->dev, 
-						    usb_sndctrlpipe(serial->dev, 0),
-						    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
-						    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-						    0, 0, buf, 0, WDR_TIMEOUT) < 0) {
-					err("error from flowcontrol urb");
-				}	    
-
-				/* drop DTR */
-				if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), LOW) < 0){
-					err("Error from DTR LOW urb");
-				}
-				/* drop RTS */
-				if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0) {
-					err("Error from RTS LOW urb");
-				}	
-			} /* Note change no line is hupcl is off */
-
-			/* shutdown our bulk reads and writes */
-			/* ***CHECK*** behaviour when there is nothing queued */
-			usb_unlink_urb (port->write_urb);
-			usb_unlink_urb (port->read_urb);
-		}
-		port->active = 0;
-		port->open_count = 0;
-	} else {  
-		/* Send a HUP if necessary */
-		if (!(port->tty->termios->c_cflag & CLOCAL)){
-			tty_hangup(port->tty);
-		}
+	if (serial->dev) {
+		if (c_cflag & HUPCL){
+			/* Disable flow control */
+			if (usb_control_msg(serial->dev, 
+					    usb_sndctrlpipe(serial->dev, 0),
+					    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+					    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+					    0, 0, buf, 0, WDR_TIMEOUT) < 0) {
+				err("error from flowcontrol urb");
+			}	    
+
+			/* drop DTR */
+			if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), LOW) < 0){
+				err("Error from DTR LOW urb");
+			}
+			/* drop RTS */
+			if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0) {
+				err("Error from RTS LOW urb");
+			}	
+		} /* Note change no line is hupcl is off */
+
+		/* shutdown our bulk reads and writes */
+		/* ***CHECK*** behaviour when there is nothing queued */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->read_urb);
 	}
-
-	up (&port->sem);
-	MOD_DEC_USE_COUNT;
-
-} /* ftdi_sio_close */
+} /* ftdi_close */
 
 
   
@@ -433,16 +622,16 @@
  *  B1 0
  *  B2..7 length of message excluding byte 0
  */
-static int ftdi_sio_write (struct usb_serial_port *port, int from_user, 
+static int ftdi_write (struct usb_serial_port *port, int from_user,
 			   const unsigned char *buf, int count)
-{ /* ftdi_sio_write */
+{ /* ftdi_write */
 	struct usb_serial *serial = port->serial;
 	struct ftdi_private *priv = (struct ftdi_private *)port->private;
 	unsigned char *first_byte = port->write_urb->transfer_buffer;
 	int data_offset ;
 	int result;
 	
-	dbg(__FUNCTION__ " port %d, %d bytes", port->number, count);
+	dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count);
 
 	if (count == 0) {
 		err("write request of 0 bytes");
@@ -453,20 +642,17 @@
         dbg("data_offset set to %d",data_offset);
 
 	if (port->write_urb->status == -EINPROGRESS) {
-		dbg (__FUNCTION__ " - already writing");
+		dbg("%s - already writing", __FUNCTION__);
 		return (0);
 	}		
 
-	down(&port->sem);
-
 	count += data_offset;
 	count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
 
-		/* Copy in the data to send */
+	/* Copy in the data to send */
 	if (from_user) {
 		if (copy_from_user(port->write_urb->transfer_buffer + data_offset,
 				   buf, count - data_offset )){
-			up (&port->sem);
 			return -EFAULT;
 		}
 	} else {
@@ -480,41 +666,39 @@
 		*first_byte = 1 | ((count-data_offset) << 2) ; 
 	}
 
-	dbg(__FUNCTION__ " Bytes: %d, First Byte: 0x%02x",count, first_byte[0]);
+	dbg("%s Bytes: %d, First Byte: 0x%02x", __FUNCTION__,count, first_byte[0]);
 	usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte);
 		
 	/* send the data out the bulk port */
 	FILL_BULK_URB(port->write_urb, serial->dev, 
 		      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
 		      port->write_urb->transfer_buffer, count,
-		      ftdi_sio_write_bulk_callback, port);
+		      ftdi_write_bulk_callback, port);
 		
 	result = usb_submit_urb(port->write_urb);
 	if (result) {
-		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
-		up (&port->sem);
+		err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 		return 0;
 	}
-	up (&port->sem);
 
-	dbg(__FUNCTION__ " write returning: %d", count - data_offset);
+	dbg("%s write returning: %d", __FUNCTION__, count - data_offset);
 	return (count - data_offset);
+} /* ftdi_write */
 
-} /* ftdi_sio_write */
 
-static void ftdi_sio_write_bulk_callback (struct urb *urb)
+static void ftdi_write_bulk_callback (struct urb *urb)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct usb_serial *serial;
 
-	dbg("ftdi_sio_write_bulk_callback");
+	dbg("%s", __FUNCTION__);
 
-	if (port_paranoia_check (port, "ftdi_sio_write_bulk_callback")) {
+	if (port_paranoia_check (port, "ftdi_write_bulk_callback")) {
 		return;
 	}
 	
 	serial = port->serial;
-	if (serial_paranoia_check (serial, "ftdi_sio_write_bulk_callback")) {
+	if (serial_paranoia_check (serial, "ftdi_write_bulk_callback")) {
 		return;
 	}
 	
@@ -526,13 +710,14 @@
 	mark_bh(IMMEDIATE_BH);
 
 	return;
-} /* ftdi_sio_write_bulk_callback */
+} /* ftdi_write_bulk_callback */
 
 
-static int ftdi_sio_write_room( struct usb_serial_port *port )
+static int ftdi_write_room( struct usb_serial_port *port )
 {
 	struct ftdi_private *priv = (struct ftdi_private *)port->private;
 	int room;
+
 	if ( port->write_urb->status == -EINPROGRESS) {
 		/* There is a race here with the _write routines but it won't hurt */
 		room = 0;
@@ -540,16 +725,15 @@
 		room = port->bulk_out_size - priv->write_offset;
 	}
 	return(room);
+} /* ftdi_write_room */
 
 
-} /* ftdi_sio_write_room */
-
-
-static void ftdi_sio_read_bulk_callback (struct urb *urb)
-{ /* ftdi_sio_serial_buld_callback */
+static void ftdi_read_bulk_callback (struct urb *urb)
+{ /* ftdi_read_bulk_callback */
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct usb_serial *serial;
        	struct tty_struct *tty = port->tty ;
+	struct ftdi_private *priv = (struct ftdi_private *) port->private;
 	char error_flag;
        	unsigned char *data = urb->transfer_buffer;
 
@@ -557,7 +741,7 @@
 	int i;
 	int result;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
 		return;
@@ -586,6 +770,16 @@
 	/* See acm.c - you do a tty_hangup  - eg tty_hangup(tty) */
 	/* if CD is dropped and the line is not CLOCAL then we should hangup */
 
+	/* Compare new line status to the old one, signal if different */
+	if (priv != NULL) {
+		char new_status = data[0] & FTDI_STATUS_B0_MASK;
+		if (new_status != priv->prev_status) {
+			priv->diff_status |= new_status ^ priv->prev_status;
+			wake_up_interruptible(&priv->delta_msr_wait);
+			priv->prev_status = new_status;
+		}
+	}
+
 	/* Handle errors and break */
 	error_flag = TTY_NORMAL;
         /* Although the device uses a bitmask and hence can have multiple */
@@ -652,63 +846,17 @@
 	FILL_BULK_URB(port->read_urb, serial->dev, 
 		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
 		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-		      ftdi_sio_read_bulk_callback, port);
+		      ftdi_read_bulk_callback, port);
 
 	result = usb_submit_urb(port->read_urb);
 	if (result)
-		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+		err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
 
 	return;
-} /* ftdi_sio_serial_read_bulk_callback */
-
-
-static __u16 translate_baudrate_to_ftdi(unsigned int cflag, ftdi_type_t ftdi_type) 
-{ /* translate_baudrate_to_ftdi */
-	
-	__u16 urb_value = ftdi_sio_b9600;
+} /* ftdi_read_bulk_callback */
 
-	if (ftdi_type == sio){
-		switch(cflag & CBAUD){
-		case B0: break; /* ignored by this */
-		case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break;
-		case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break;
-		case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break;
-		case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break;
-		case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break;
-		case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break;
-		case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break;
-		case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break;
-		case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break;
-		case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break;
-		default: dbg(__FUNCTION__ " FTDI_SIO does not support the baudrate (%d) requested",
-			     (cflag & CBAUD)); 
-		   break;
-		}
-	} else { /* it is 8U232AM */
-		switch(cflag & CBAUD){
-		case B0: break; /* ignored by this */
-		case B300: urb_value = ftdi_8U232AM_48MHz_b300; dbg("Set to 300"); break;
-		case B600: urb_value = ftdi_8U232AM_48MHz_b600; dbg("Set to 600") ; break;
-		case B1200: urb_value = ftdi_8U232AM_48MHz_b1200; dbg("Set to 1200") ; break;
-		case B2400: urb_value = ftdi_8U232AM_48MHz_b2400; dbg("Set to 2400") ; break;
-		case B4800: urb_value = ftdi_8U232AM_48MHz_b4800; dbg("Set to 4800") ; break;
-		case B9600: urb_value = ftdi_8U232AM_48MHz_b9600; dbg("Set to 9600") ; break;
-		case B19200: urb_value = ftdi_8U232AM_48MHz_b19200; dbg("Set to 19200") ; break;
-		case B38400: urb_value = ftdi_8U232AM_48MHz_b38400; dbg("Set to 38400") ; break;
-		case B57600: urb_value = ftdi_8U232AM_48MHz_b57600; dbg("Set to 57600") ; break;
-		case B115200: urb_value = ftdi_8U232AM_48MHz_b115200; dbg("Set to 115200") ; break;
-		case B230400: urb_value = ftdi_8U232AM_48MHz_b230400; dbg("Set to 230400") ; break;
-		case B460800: urb_value = ftdi_8U232AM_48MHz_b460800; dbg("Set to 460800") ; break;
-		case B921600: urb_value = ftdi_8U232AM_48MHz_b921600; dbg("Set to 921600") ; break;
-		default: dbg(__FUNCTION__ " The baudrate (%d) requested is not implemented",
-			     (cflag & CBAUD)); 
-		   break;
-		}
-	}
-	return(urb_value);
-}
 
-static void ftdi_sio_break_ctl( struct usb_serial_port *port, int break_state )
+static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
 {
 	struct usb_serial *serial = port->serial;
 	struct ftdi_private *priv = (struct ftdi_private *)port->private;
@@ -731,22 +879,21 @@
 			    FTDI_SIO_SET_DATA_REQUEST_TYPE,
 			    urb_value , 0,
 			    buf, 0, WDR_TIMEOUT) < 0) {
-		err(__FUNCTION__ " FAILED to enable/disable break state (state was %d)",break_state);
+		err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state);
 	}	   
 
-	dbg(__FUNCTION__ " break state is %d - urb is %d",break_state, urb_value);
+	dbg("%s break state is %d - urb is %d", __FUNCTION__,break_state, urb_value);
 	
 }
 
 
+/* old_termios contains the original termios settings and tty->termios contains
+ * the new setting to be used
+ * WARNING: set_termios calls this with old_termios in kernel space
+ */
 
-/* As I understand this - old_termios contains the original termios settings */
-/*  and tty->termios contains the new setting to be used */
-/* */
-/*   WARNING: set_termios calls this with old_termios in kernel space */
-
-static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *old_termios)
-{ /* ftdi_sio_set_termios */
+static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{ /* ftdi_termios */
 	struct usb_serial *serial = port->serial;
 	unsigned int cflag = port->tty->termios->c_cflag;
 	struct ftdi_private *priv = (struct ftdi_private *)port->private;	
@@ -754,7 +901,7 @@
 	char buf[1]; /* Perhaps I should dynamically alloc this? */
 	
 	
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 
 	/* FIXME -For this cut I don't care if the line is really changing or 
@@ -793,12 +940,10 @@
 			    FTDI_SIO_SET_DATA_REQUEST_TYPE,
 			    urb_value , 0,
 			    buf, 0, 100) < 0) {
-		err(__FUNCTION__ " FAILED to set databits/stopbits/parity");
+		err("%s FAILED to set databits/stopbits/parity", __FUNCTION__);
 	}	   
 
 	/* Now do the baudrate */
-	urb_value = translate_baudrate_to_ftdi((cflag & CBAUD), priv->ftdi_type);
-	
 	if ((cflag & CBAUD) == B0 ) {
 		/* Disable flow control */
 		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
@@ -806,31 +951,27 @@
 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
 				    0, 0, 
 				    buf, 0, WDR_TIMEOUT) < 0) {
-			err(__FUNCTION__ " error from disable flowcontrol urb");
+			err("%s error from disable flowcontrol urb", __FUNCTION__);
 		}	    
 		/* Drop RTS and DTR */
 		if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){
-			err(__FUNCTION__ " Error from DTR LOW urb");
+			err("%s Error from DTR LOW urb", __FUNCTION__);
 		}
 		if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){
-			err(__FUNCTION__ " Error from RTS LOW urb");
+			err("%s Error from RTS LOW urb", __FUNCTION__);
 		}	
 		
 	} else {
 		/* set the baudrate determined before */
-		if (usb_control_msg(serial->dev, 
-				    usb_sndctrlpipe(serial->dev, 0),
-				    FTDI_SIO_SET_BAUDRATE_REQUEST, 
-				    FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
-				    urb_value, 0, 
-				    buf, 0, 100) < 0) {
-			err(__FUNCTION__ " urb failed to set baurdrate");
+		if (change_speed(port)) {
+			err("%s urb failed to set baurdrate", __FUNCTION__);
 		}
 	}
+
 	/* Set flow control */
 	/* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
 	if (cflag & CRTSCTS) {
-		dbg(__FUNCTION__ " Setting to CRTSCTS flow control");
+		dbg("%s Setting to CRTSCTS flow control", __FUNCTION__);
 		if (usb_control_msg(serial->dev, 
 				    usb_sndctrlpipe(serial->dev, 0),
 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
@@ -842,7 +983,7 @@
 		
 	} else { 
 		/* CHECKME Assuming XON/XOFF handled by tty stack - not by device */
-		dbg(__FUNCTION__ " Turning off hardware flow control");
+		dbg("%s Turning off hardware flow control", __FUNCTION__);
 		if (usb_control_msg(serial->dev, 
 				    usb_sndctrlpipe(serial->dev, 0),
 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
@@ -854,24 +995,27 @@
 		
 	}
 	return;
-} /* ftdi_sio_set_termios */
+} /* ftdi_termios */
+
 
-static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
 {
 	struct usb_serial *serial = port->serial;
 	struct ftdi_private *priv = (struct ftdi_private *)port->private;
+
 	__u16 urb_value=0; /* Will hold the new flags */
 	char buf[2];
 	int  ret, mask;
 	
-	dbg(__FUNCTION__ " cmd 0x%04x", cmd);
+	dbg("%s cmd 0x%04x", __FUNCTION__, cmd);
 
 	/* Based on code from acm.c and others */
 	switch (cmd) {
 
 	case TIOCMGET:
-		dbg(__FUNCTION__ " TIOCMGET");
-		if (priv->ftdi_type == sio){
+		dbg("%s TIOCMGET", __FUNCTION__);
+		switch (priv->chip_type) {
+		case SIO:
 			/* Request the status from the device */
 			if ((ret = usb_control_msg(serial->dev, 
 						   usb_rcvctrlpipe(serial->dev, 0),
@@ -879,12 +1023,13 @@
 						   FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
 						   0, 0, 
 						   buf, 1, WDR_TIMEOUT)) < 0 ) {
-				err(__FUNCTION__ " Could not get modem status of device - err: %d",
+				err("%s Could not get modem status of device - err: %d", __FUNCTION__,
 				    ret);
 				return(ret);
 			}
-		} else {
-			/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same 
+			break;
+		case FT8U232AM:
+			/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
 			   format as the data returned from the in point */
 			if ((ret = usb_control_msg(serial->dev, 
 						   usb_rcvctrlpipe(serial->dev, 0),
@@ -892,10 +1037,14 @@
 						   FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
 						   0, 0, 
 						   buf, 2, WDR_TIMEOUT)) < 0 ) {
-				err(__FUNCTION__ " Could not get modem status of device - err: %d",
+				err("%s Could not get modem status of device - err: %d", __FUNCTION__,
 				    ret);
 				return(ret);
 			}
+			break;
+		default:
+			return -EFAULT;
+			break;
 		}
 
 		return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
@@ -906,7 +1055,7 @@
 		break;
 
 	case TIOCMSET: /* Turns on and off the lines as specified by the mask */
-		dbg(__FUNCTION__ " TIOCMSET");
+		dbg("%s TIOCMSET", __FUNCTION__);
 		if (get_user(mask, (unsigned long *) arg))
 			return -EFAULT;
 		urb_value = ((mask & TIOCM_DTR) ? HIGH : LOW);
@@ -920,7 +1069,7 @@
 		break;
 					
 	case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
-		dbg(__FUNCTION__ " TIOCMBIS");
+		dbg("%s TIOCMBIS", __FUNCTION__);
  	        if (get_user(mask, (unsigned long *) arg))
 			return -EFAULT;
   	        if (mask & TIOCM_DTR){
@@ -942,7 +1091,7 @@
 					break;
 
 	case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
-		dbg(__FUNCTION__ " TIOCMBIC");
+		dbg("%s TIOCMBIC", __FUNCTION__);
  	        if (get_user(mask, (unsigned long *) arg))
 			return -EFAULT;
   	        if (mask & TIOCM_DTR){
@@ -972,38 +1121,83 @@
 		 *
 		 */
 
+	case TIOCGSERIAL: /* gets serial port data */
+		return get_serial_info(port, (struct serial_struct *) arg);
+
+	case TIOCSSERIAL: /* sets serial port data */
+		return set_serial_info(port, (struct serial_struct *) arg);
+
+	/*
+	 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+	 * - mask passed in arg for lines of interest
+	 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+	 * Caller should use TIOCGICOUNT to see which one it was.
+	 *
+	 * This code is borrowed from linux/drivers/char/serial.c
+	 */
+	case TIOCMIWAIT:
+		while (priv != NULL) {
+			interruptible_sleep_on(&priv->delta_msr_wait);
+			/* see if a signal did it */
+			if (signal_pending(current))
+				return -ERESTARTSYS;
+			else {
+				char diff = priv->diff_status;
+
+				if (diff == 0) {
+					return -EIO; /* no change => error */
+				}
+
+				/* Consume all events */
+				priv->diff_status = 0;
+
+				/* Return 0 if caller wanted to know about these bits */
+				if ( ((arg & TIOCM_RNG) && (diff & FTDI_RS0_RI)) ||
+				     ((arg & TIOCM_DSR) && (diff & FTDI_RS0_DSR)) ||
+				     ((arg & TIOCM_CD)  && (diff & FTDI_RS0_RLSD)) ||
+				     ((arg & TIOCM_CTS) && (diff & FTDI_RS0_CTS)) ) {
+					return 0;
+				}
+				/*
+				 * Otherwise caller can't care less about what happened,
+				 * and so we continue to wait for more events.
+				 */
+			}
+		}
+		/* NOTREACHED */
+
 	default:
 	  /* This is not an error - turns out the higher layers will do 
 	   *  some ioctls itself (see comment above)
  	   */
-		dbg(__FUNCTION__ " arg not supported - it was 0x%04x",cmd);
+		dbg("%s arg not supported - it was 0x%04x", __FUNCTION__,cmd);
 		return(-ENOIOCTLCMD);
 		break;
 	}
 	return 0;
-} /* ftdi_sio_ioctl */
+} /* ftdi_ioctl */
 
 
-static int __init ftdi_sio_init (void)
+static int __init ftdi_init (void)
 {
-	dbg(__FUNCTION__);
-	usb_serial_register (&ftdi_sio_device);
+	dbg("%s", __FUNCTION__);
+	usb_serial_register (&ftdi_SIO_device);
 	usb_serial_register (&ftdi_8U232AM_device);
 	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
 
 
-static void __exit ftdi_sio_exit (void)
+static void __exit ftdi_exit (void)
 {
-	dbg(__FUNCTION__);
-	usb_serial_deregister (&ftdi_sio_device);
+	dbg("%s", __FUNCTION__);
+	usb_serial_deregister (&ftdi_SIO_device);
 	usb_serial_deregister (&ftdi_8U232AM_device);
 }
 
 
-module_init(ftdi_sio_init);
-module_exit(ftdi_sio_exit);
+module_init(ftdi_init);
+module_exit(ftdi_exit);
 
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/ftdi_sio.h linux-2.4.20/drivers/usb/serial/ftdi_sio.h
--- linux-2.4.19/drivers/usb/serial/ftdi_sio.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/ftdi_sio.h	2002-10-29 11:18:36.000000000 +0000
@@ -81,17 +81,36 @@
 /*
  * BmRequestType:  0100 0000B
  * bRequest:       FTDI_SIO_SET_BAUDRATE
- * wValue:         BaudRate value - see below
+ * wValue:         BaudDivisor value - see below
  * wIndex:         Port
  * wLength:        0
  * Data:           None
+ * The BaudDivisor values are calculated as follows:
+ * - BaseClock is either 12000000 or 48000000 depending on the device. FIXME: I wish
+ *   I knew how to detect old chips to select proper base clock!
+ * - BaudDivisor is a fixed point number encoded in a funny way.
+ *   (--WRONG WAY OF THINKING--)
+ *   BaudDivisor is a fixed point number encoded with following bit weighs:
+ *   (-2)(-1)(13..0). It is a radical with a denominator of 4, so values
+ *   end with 0.0 (00...), 0.25 (10...), 0.5 (01...), and 0.75 (11...).
+ *   (--THE REALITY--)
+ *   The both-bits-set has quite different meaning from 0.75 - the chip designers
+ *   have decided it to mean 0.125 instead of 0.75.
+ *   This info looked up in FTDI application note "FT8U232 DEVICES \ Data Rates
+ *   and Flow Control Consideration for USB to RS232".
+ * - BaudDivisor = (BaseClock / 16) / BaudRate, where the (=) operation should
+ *   automagically re-encode the resulting value to take fractions into consideration.
+ * As all values are integers, some bit twiddling is in order:
+ *   BaudDivisor = (BaseClock / 16 / BaudRate) |
+ *   (((BaseClock / 2 / BaudRate) & 2) ? 0x8000 : 0) | // 0.25
+ *   (((BaseClock / 2 / BaudRate) & 4) ? 0x4000 : 0) | // 0.5
+ *   (((BaseClock / 2 / BaudRate) & 0x7) == 1 ? 0xc000) // 0.125 - this line due to funny encoding only
  */
 
 typedef enum {
-	sio = 1,
-	F8U232AM = 2,
-} ftdi_type_t;
-
+	SIO = 1,
+	FT8U232AM = 2,
+} ftdi_chip_type_t;
 
 typedef enum {
  ftdi_sio_b300 = 0, 
@@ -106,37 +125,18 @@
  ftdi_sio_b115200 = 9
 } FTDI_SIO_baudrate_t ;
 
+#define FTDI_SIO_BASE_BAUD_TO_DIVISOR(base, baud) ( \
+((base/2/baud) >> 3) | \
+(((base/2/baud) & 2) ? 0x8000 : 0) | \
+(((base/2/baud) & 4) ? 0x4000 : 0) | \
+((((base/2/baud) & 0x7) == 1) ? 0xc000 : 0) )
 
-typedef enum {
-  ftdi_8U232AM_12MHz_b300 = 0x09c4,
-  ftdi_8U232AM_12MHz_b600 = 0x04E2,
-  ftdi_8U232AM_12MHz_b1200 = 0x0271,
-  ftdi_8U232AM_12MHz_b2400 = 0x4138,
-  ftdi_8U232AM_12MHz_b4800 = 0x809c,
-  ftdi_8U232AM_12MHz_b9600 = 0xc04e,
-  ftdi_8U232AM_12MHz_b19200 = 0x0027,
-  ftdi_8U232AM_12MHz_b38400 = 0x4013,
-  ftdi_8U232AM_12MHz_b57600 = 0x000d,
-  ftdi_8U232AM_12MHz_b115200 = 0x4006,
-  ftdi_8U232AM_12MHz_b230400 = 0x8003,
-} FTDI_8U232AM_12MHz_baudrate_t;
-/* Apparently all devices are 48MHz */
-typedef enum {
-  ftdi_8U232AM_48MHz_b300 = 0x2710,
-  ftdi_8U232AM_48MHz_b600 = 0x1388,
-  ftdi_8U232AM_48MHz_b1200 = 0x09c4,
-  ftdi_8U232AM_48MHz_b2400 = 0x04e2,
-  ftdi_8U232AM_48MHz_b4800 = 0x0271,
-  ftdi_8U232AM_48MHz_b9600 = 0x4138,
-  ftdi_8U232AM_48MHz_b19200 = 0x809c,
-  ftdi_8U232AM_48MHz_b38400 = 0xc04e,
-  ftdi_8U232AM_48MHz_b57600 = 0x0034,
-  ftdi_8U232AM_48MHz_b115200 = 0x001a,
-  ftdi_8U232AM_48MHz_b230400 = 0x000d,
-  ftdi_8U232AM_48MHz_b460800 = 0x4006,
-  ftdi_8U232AM_48MHz_b921600 = 0x8003,
+#define FTDI_SIO_BAUD_TO_DIVISOR(baud) FTDI_SIO_BASE_BAUD_TO_DIVISOR(48000000, baud)
 
-} FTDI_8U232AM_48MHz_baudrate_t;
+/*
+ * The ftdi_8U232AM_xxMHz_byyy constans have been removed. Their values can
+ * be calculated as follows: FTDI_SIO_BAUD_TO_DIVISOR(xx000000, yyy)
+ */
 
 #define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA
 #define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40
@@ -440,6 +440,11 @@
  * B7	Error in RCVR FIFO
  * 
  */
+#define FTDI_RS0_CTS	(1 << 4)
+#define FTDI_RS0_DSR	(1 << 5)
+#define FTDI_RS0_RI	(1 << 6)
+#define FTDI_RS0_RLSD	(1 << 7)
+
 #define FTDI_RS_DR  1
 #define FTDI_RS_OE (1<<1)
 #define FTDI_RS_PE (1<<2)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/io_edgeport.c linux-2.4.20/drivers/usb/serial/io_edgeport.c
--- linux-2.4.19/drivers/usb/serial/io_edgeport.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/io_edgeport.c	2002-10-29 11:18:32.000000000 +0000
@@ -242,13 +242,9 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
@@ -256,7 +252,7 @@
 #include <linux/spinlock.h>
 #include <linux/serial.h>
 #include <linux/ioctl.h>
-#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
 #include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
@@ -274,7 +270,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v2.2"
+#define DRIVER_VERSION "v2.3"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"
 #define DRIVER_DESC "Edgeport USB Serial Driver"
 
@@ -372,8 +368,8 @@
 struct edgeport_serial {
 	char			name[MAX_NAME_LEN+1];		/* string name of this device */
 
-	EDGE_MANUF_DESCRIPTOR		manuf_descriptor;	/* the manufacturer descriptor */
-	EDGE_BOOT_DESCRIPTOR		boot_descriptor;	/* the boot firmware descriptor */
+	struct edge_manuf_descriptor	manuf_descriptor;	/* the manufacturer descriptor */
+	struct edge_boot_descriptor	boot_descriptor;	/* the boot firmware descriptor */
 	struct edgeport_product_info	product_info;		/* Product Info */
 
 	__u8			interrupt_in_endpoint;		/* the interrupt endpoint handle */
@@ -400,17 +396,17 @@
 };
 
 /* baud rate information */
-typedef struct _DIVISOR_TABLE_ENTRY {
+struct divisor_table_entry {
 	__u32   BaudRate;
 	__u16  Divisor;
-} DIVISOR_TABLE_ENTRY, *PDIVISOR_TABLE_ENTRY;
+};
 
 //
 // Define table of divisors for Rev A EdgePort/4 hardware
 // These assume a 3.6864MHz crystal, the standard /16, and
 // MCR.7 = 0.
 //
-static DIVISOR_TABLE_ENTRY  DivisorTable[] = {
+static struct divisor_table_entry divisor_table[] = {
 	{   75,		3072},  
 	{   110,	2095},		/* 2094.545455 => 230450   => .0217 % over */
 	{   134,	1713},		/* 1713.011152 => 230398.5 => .00065% under */
@@ -510,7 +506,7 @@
 	__u16 BootBuildNumber;
 	__u8 *BootImage;      
 	__u32 BootSize;
-	PEDGE_FIRMWARE_IMAGE_RECORD record;
+	struct edge_firmware_image_record *record;
 	unsigned char *firmware;
 	int response;
 
@@ -566,13 +562,13 @@
 		firmware = BootImage;
 
 		for (;;) {
-			record = (PEDGE_FIRMWARE_IMAGE_RECORD)firmware;
+			record = (struct edge_firmware_image_record *)firmware;
 			response = rom_write (edge_serial->serial, record->ExtAddr, record->Addr, record->Len, &record->Data[0]);
 			if (response < 0) {
 				err("sram_write failed (%x, %x, %d)", record->ExtAddr, record->Addr, record->Len);
 				break;
 			}
-			firmware += sizeof (EDGE_FIRMWARE_IMAGE_RECORD) + record->Len;
+			firmware += sizeof (struct edge_firmware_image_record) + record->Len;
 			if (firmware >= &BootImage[BootSize]) {
 				break;
 			}
@@ -593,7 +589,7 @@
 	struct usb_string_descriptor StringDesc;
 	struct usb_string_descriptor *pStringDesc;
 
-	dbg(__FUNCTION__ " - USB String ID = %d", Id );
+	dbg("%s - USB String ID = %d", __FUNCTION__, Id );
 
 	if (!usb_get_descriptor(dev, USB_DT_STRING, Id, &StringDesc, sizeof(StringDesc))) {
 		return 0;
@@ -628,7 +624,7 @@
 	struct usb_string_descriptor StringDesc;
 	struct usb_string_descriptor *pStringDesc;
 
-	dbg(__FUNCTION__ " - USB String ID = %d", Id );
+	dbg("%s - USB String ID = %d", __FUNCTION__, Id );
 
 	if (!usb_get_descriptor(dev, USB_DT_STRING, Id, &StringDesc, sizeof(StringDesc))) {
 		return 0;
@@ -763,14 +759,14 @@
 	int portNumber;
 	int result;
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	if (serial_paranoia_check (edge_serial->serial, __FUNCTION__)) {
 		return;
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__" - nonzero control read status received: %d", urb->status);
+		dbg("%s - nonzero control read status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
@@ -782,7 +778,7 @@
 			bytes_avail = data[0] | (data[1] << 8);
 			if (bytes_avail) {
 				edge_serial->rxBytesAvail += bytes_avail;
-				dbg(__FUNCTION__" - bytes_avail = %d, rxBytesAvail %d", bytes_avail, edge_serial->rxBytesAvail);
+				dbg("%s - bytes_avail = %d, rxBytesAvail %d", __FUNCTION__, bytes_avail, edge_serial->rxBytesAvail);
 
 				if ((edge_serial->rxBytesAvail > 0) &&
 				    (edge_serial->read_urb->status != -EINPROGRESS)) {
@@ -792,7 +788,7 @@
 					edge_serial->read_urb->dev = edge_serial->serial->dev;
 					result = usb_submit_urb(edge_serial->read_urb);
 					if (result) {
-						dbg(__FUNCTION__" - usb_submit_urb(read bulk) failed with result = %d", result);
+						dbg("%s - usb_submit_urb(read bulk) failed with result = %d", __FUNCTION__, result);
 					}
 				}
 			}
@@ -808,10 +804,11 @@
 					edge_port = (struct edgeport_port *)port->private;
 					if (edge_port->open) {
 						edge_port->txCredits += txCredits;
-						dbg(__FUNCTION__" - txcredits for port%d = %d", portNumber, edge_port->txCredits);
+						dbg("%s - txcredits for port%d = %d", __FUNCTION__, portNumber, edge_port->txCredits);
 
 						/* tell the tty driver that something has changed */
-						wake_up_interruptible(&edge_port->port->tty->write_wait);
+						if (edge_port->port->tty)
+							wake_up_interruptible(&edge_port->port->tty->write_wait);
 
 						// Since we have more credit, check if more data can be sent
 						send_more_port_data(edge_serial, edge_port);
@@ -837,14 +834,14 @@
 	int			status;
 	__u16			raw_data_length;
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	if (serial_paranoia_check (edge_serial->serial, __FUNCTION__)) {
 		return;
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__" - nonzero read bulk status received: %d", urb->status);
+		dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
@@ -856,7 +853,7 @@
 		/* decrement our rxBytes available by the number that we just got */
 		edge_serial->rxBytesAvail -= raw_data_length;
 
-		dbg(__FUNCTION__" - Received = %d, rxBytesAvail %d", raw_data_length, edge_serial->rxBytesAvail);
+		dbg("%s - Received = %d, rxBytesAvail %d", __FUNCTION__, raw_data_length, edge_serial->rxBytesAvail);
 
 		process_rcvd_data (edge_serial, data, urb->actual_length);
 
@@ -869,7 +866,7 @@
 			edge_serial->read_urb->dev = edge_serial->serial->dev;
 			status = usb_submit_urb(edge_serial->read_urb);
 			if (status) {
-				err(__FUNCTION__" - usb_submit_urb(read bulk) failed, status = %d", status);
+				err("%s - usb_submit_urb(read bulk) failed, status = %d", __FUNCTION__, status);
 			}
 		}
 	}
@@ -886,25 +883,27 @@
 	struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
 	struct tty_struct *tty;
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	if (port_paranoia_check (edge_port->port, __FUNCTION__)) {
 		return;
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__" - nonzero write bulk status received: %d", urb->status);
+		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 	}
 
 	tty = edge_port->port->tty;
 
-	/* let the tty driver wakeup if it has a special write_wakeup function */
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
-		(tty->ldisc.write_wakeup)(tty);
-	}
+	if (tty) {
+		/* let the tty driver wakeup if it has a special write_wakeup function */
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
+			(tty->ldisc.write_wakeup)(tty);
+		}
 
-	/* tell the tty driver that something has changed */
-	wake_up_interruptible(&tty->write_wait);
+		/* tell the tty driver that something has changed */
+		wake_up_interruptible(&tty->write_wait);
+	}
 
 	// Release the Write URB
 	edge_port->write_in_progress = FALSE;
@@ -925,10 +924,10 @@
 	struct tty_struct *tty;
 	int status = urb->status;
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	CmdUrbs--;
-	dbg(__FUNCTION__" - FREE URB %p (outstanding %d)", urb, CmdUrbs);
+	dbg("%s - FREE URB %p (outstanding %d)", __FUNCTION__, urb, CmdUrbs);
 
 
 	/* clean up the transfer buffer */
@@ -945,7 +944,7 @@
 	}
 
 	if (status) {
-		dbg(__FUNCTION__" - nonzero write bulk status received: %d", status);
+		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, status);
 		return;
 	}
 
@@ -953,7 +952,8 @@
 	tty = edge_port->port->tty;
 
 	/* tell the tty driver that something has changed */
-	wake_up_interruptible(&tty->write_wait);
+	if (tty)
+		wake_up_interruptible(&tty->write_wait);
 
 	/* we have completed the command */
 	edge_port->commandPending = FALSE;
@@ -982,139 +982,124 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return -ENODEV;
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (edge_port == NULL)
 		return -ENODEV;
 
-	++port->open_count;
-	MOD_INC_USE_COUNT;
-	
-	if (!port->active) {
-		port->active = 1;
-
-		/* force low_latency on so that our tty_push actually forces the data through, 
-		   otherwise it is scheduled, and with high data rates (like with OHCI) data
-		   can get lost. */
+	/* force low_latency on so that our tty_push actually forces the data through, 
+	   otherwise it is scheduled, and with high data rates (like with OHCI) data
+	   can get lost. */
+	if (port->tty)
 		port->tty->low_latency = 1;
+
+	/* see if we've set up our endpoint info yet (can't set it up in edge_startup
+	   as the structures were not set up at that time.) */
+	serial = port->serial;
+	edge_serial = (struct edgeport_serial *)serial->private;
+	if (edge_serial == NULL) {
+		return -ENODEV;
+	}
+	if (edge_serial->interrupt_in_buffer == NULL) {
+		struct usb_serial_port *port0 = &serial->port[0];
+		
+		/* not set up yet, so do it now */
+		edge_serial->interrupt_in_buffer = port0->interrupt_in_buffer;
+		edge_serial->interrupt_in_endpoint = port0->interrupt_in_endpointAddress;
+		edge_serial->interrupt_read_urb = port0->interrupt_in_urb;
+		edge_serial->bulk_in_buffer = port0->bulk_in_buffer;
+		edge_serial->bulk_in_endpoint = port0->bulk_in_endpointAddress;
+		edge_serial->read_urb = port0->read_urb;
+		edge_serial->bulk_out_endpoint = port0->bulk_out_endpointAddress;
 	
-		/* see if we've set up our endpoint info yet (can't set it up in edge_startup
-		   as the structures were not set up at that time.) */
-		serial = port->serial;
-		edge_serial = (struct edgeport_serial *)serial->private;
-		if (edge_serial == NULL) {
-			port->active = 0;
-			port->open_count = 0;
-			MOD_DEC_USE_COUNT;
-			return -ENODEV;
-		}
-		if (edge_serial->interrupt_in_buffer == NULL) {
-			struct usb_serial_port *port0 = &serial->port[0];
-			
-			/* not set up yet, so do it now */
-			edge_serial->interrupt_in_buffer = port0->interrupt_in_buffer;
-			edge_serial->interrupt_in_endpoint = port0->interrupt_in_endpointAddress;
-			edge_serial->interrupt_read_urb = port0->interrupt_in_urb;
-			edge_serial->bulk_in_buffer = port0->bulk_in_buffer;
-			edge_serial->bulk_in_endpoint = port0->bulk_in_endpointAddress;
-			edge_serial->read_urb = port0->read_urb;
-			edge_serial->bulk_out_endpoint = port0->bulk_out_endpointAddress;
+		/* set up our interrupt urb */
+		FILL_INT_URB(edge_serial->interrupt_read_urb,
+			     serial->dev,
+			     usb_rcvintpipe(serial->dev,
+					    port0->interrupt_in_endpointAddress),
+			     port0->interrupt_in_buffer,
+			     edge_serial->interrupt_read_urb->transfer_buffer_length,
+			     edge_interrupt_callback, edge_serial,
+			     edge_serial->interrupt_read_urb->interval);
 		
-			/* set up our interrupt urb */
-			FILL_INT_URB(edge_serial->interrupt_read_urb,
-				     serial->dev,
-				     usb_rcvintpipe(serial->dev,
-					            port0->interrupt_in_endpointAddress),
-				     port0->interrupt_in_buffer,
-				     edge_serial->interrupt_read_urb->transfer_buffer_length,
-				     edge_interrupt_callback, edge_serial,
-				     edge_serial->interrupt_read_urb->interval);
-			
-			/* set up our bulk in urb */
-			FILL_BULK_URB(edge_serial->read_urb, serial->dev,
-				      usb_rcvbulkpipe(serial->dev, port0->bulk_in_endpointAddress),
-				      port0->bulk_in_buffer,
-				      edge_serial->read_urb->transfer_buffer_length,
-				      edge_bulk_in_callback, edge_serial);
-
-			/* start interrupt read for this edgeport
-			 * this interrupt will continue as long as the edgeport is connected */
-			response = usb_submit_urb (edge_serial->interrupt_read_urb);
-			if (response) {
-				err(__FUNCTION__" - Error %d submitting control urb", response);
-			}
+		/* set up our bulk in urb */
+		FILL_BULK_URB(edge_serial->read_urb, serial->dev,
+			      usb_rcvbulkpipe(serial->dev, port0->bulk_in_endpointAddress),
+			      port0->bulk_in_buffer,
+			      edge_serial->read_urb->transfer_buffer_length,
+			      edge_bulk_in_callback, edge_serial);
+
+		/* start interrupt read for this edgeport
+		 * this interrupt will continue as long as the edgeport is connected */
+		response = usb_submit_urb (edge_serial->interrupt_read_urb);
+		if (response) {
+			err("%s - Error %d submitting control urb", __FUNCTION__, response);
 		}
-		
-		/* initialize our wait queues */
-		init_waitqueue_head(&edge_port->wait_open);
-		init_waitqueue_head(&edge_port->wait_chase);
-		init_waitqueue_head(&edge_port->delta_msr_wait);
-		init_waitqueue_head(&edge_port->wait_command);
-
-		/* initialize our icount structure */
-		memset (&(edge_port->icount), 0x00, sizeof(edge_port->icount));
-
-		/* initialize our port settings */
-		edge_port->txCredits            = 0;			/* Can't send any data yet */
-		edge_port->shadowMCR            = MCR_MASTER_IE;	/* Must always set this bit to enable ints! */
-		edge_port->chaseResponsePending = FALSE;
+	}
+	
+	/* initialize our wait queues */
+	init_waitqueue_head(&edge_port->wait_open);
+	init_waitqueue_head(&edge_port->wait_chase);
+	init_waitqueue_head(&edge_port->delta_msr_wait);
+	init_waitqueue_head(&edge_port->wait_command);
+
+	/* initialize our icount structure */
+	memset (&(edge_port->icount), 0x00, sizeof(edge_port->icount));
+
+	/* initialize our port settings */
+	edge_port->txCredits            = 0;			/* Can't send any data yet */
+	edge_port->shadowMCR            = MCR_MASTER_IE;	/* Must always set this bit to enable ints! */
+	edge_port->chaseResponsePending = FALSE;
+
+	/* send a open port command */
+	edge_port->openPending = TRUE;
+	edge_port->open        = FALSE;
+	response = send_iosp_ext_cmd (edge_port, IOSP_CMD_OPEN_PORT, 0);
 
-		/* send a open port command */
-		edge_port->openPending = TRUE;
-		edge_port->open        = FALSE;
-		response = send_iosp_ext_cmd (edge_port, IOSP_CMD_OPEN_PORT, 0);
+	if (response < 0) {
+		err("%s - error sending open port command", __FUNCTION__);
+		edge_port->openPending = FALSE;
+		return -ENODEV;
+	}
 
-		if (response < 0) {
-			err(__FUNCTION__" - error sending open port command");
-			edge_port->openPending = FALSE;
-			port->active = 0;
-			port->open_count = 0;
-			MOD_DEC_USE_COUNT;
-			return -ENODEV;
-		}
-
-		/* now wait for the port to be completly opened */
-		timeout = OPEN_TIMEOUT;
-		while (timeout && edge_port->openPending == TRUE) {
-			timeout = interruptible_sleep_on_timeout (&edge_port->wait_open, timeout);
-		}
-
-		if (edge_port->open == FALSE) {
-			/* open timed out */
-			dbg(__FUNCTION__" - open timedout");
-			edge_port->openPending = FALSE;
-			port->active = 0;
-			port->open_count = 0;
-			MOD_DEC_USE_COUNT;
-			return -ENODEV;
-		}
-
-		/* create the txfifo */
-		edge_port->txfifo.head	= 0;
-		edge_port->txfifo.tail	= 0;
-		edge_port->txfifo.count	= 0;
-		edge_port->txfifo.size	= edge_port->maxTxCredits;
-		edge_port->txfifo.fifo	= kmalloc (edge_port->maxTxCredits, GFP_KERNEL);
-
-		if (!edge_port->txfifo.fifo) {
-			dbg(__FUNCTION__" - no memory");
-			edge_close (port, filp);
-			return -ENOMEM;
-		}
+	/* now wait for the port to be completly opened */
+	timeout = OPEN_TIMEOUT;
+	while (timeout && edge_port->openPending == TRUE) {
+		timeout = interruptible_sleep_on_timeout (&edge_port->wait_open, timeout);
+	}
 
-		/* Allocate a URB for the write */
-		edge_port->write_urb = usb_alloc_urb (0);
+	if (edge_port->open == FALSE) {
+		/* open timed out */
+		dbg("%s - open timedout", __FUNCTION__);
+		edge_port->openPending = FALSE;
+		return -ENODEV;
+	}
 
-		if (!edge_port->write_urb) {
-			dbg(__FUNCTION__" - no memory");
-			edge_close (port, filp);
-			return -ENOMEM;
-		}
+	/* create the txfifo */
+	edge_port->txfifo.head	= 0;
+	edge_port->txfifo.tail	= 0;
+	edge_port->txfifo.count	= 0;
+	edge_port->txfifo.size	= edge_port->maxTxCredits;
+	edge_port->txfifo.fifo	= kmalloc (edge_port->maxTxCredits, GFP_KERNEL);
+
+	if (!edge_port->txfifo.fifo) {
+		dbg("%s - no memory", __FUNCTION__);
+		edge_close (port, filp);
+		return -ENOMEM;
+	}
+
+	/* Allocate a URB for the write */
+	edge_port->write_urb = usb_alloc_urb (0);
 
-		dbg(__FUNCTION__"(%d) - Initialize TX fifo to %d bytes", port->number, edge_port->maxTxCredits);
+	if (!edge_port->write_urb) {
+		dbg("%s - no memory", __FUNCTION__);
+		edge_close (port, filp);
+		return -ENOMEM;
 	}
 
-	dbg(__FUNCTION__" exited");
+	dbg("%s(%d) - Initialize TX fifo to %d bytes", __FUNCTION__, port->number, edge_port->maxTxCredits);
+
+	dbg("%s exited", __FUNCTION__);
 
 	return 0;
 }
@@ -1142,11 +1127,11 @@
 
 		// Did we get our Chase response
 		if (edge_port->chaseResponsePending == FALSE) {
-			dbg(__FUNCTION__" - Got Chase Response");
+			dbg("%s - Got Chase Response", __FUNCTION__);
 
 			// did we get all of our credit back?
 			if (edge_port->txCredits == edge_port->maxTxCredits ) {
-				dbg(__FUNCTION__" - Got all credits");
+				dbg("%s - Got all credits", __FUNCTION__);
 				return;
 			}
 		}
@@ -1159,12 +1144,12 @@
 			wait--;
 			if (wait == 0) {
 				edge_port->chaseResponsePending = FALSE;
-				dbg(__FUNCTION__" - Chase TIMEOUT");
+				dbg("%s - Chase TIMEOUT", __FUNCTION__);
 				return;
 			}
 		} else {
 			// Reset timout value back to 10 seconds
-			dbg(__FUNCTION__" - Last %d, Current %d", lastCredits, edge_port->txCredits);
+			dbg("%s - Last %d, Current %d", __FUNCTION__, lastCredits, edge_port->txCredits);
 			wait = 10;
 		}
 	}
@@ -1194,20 +1179,20 @@
 
 		// Is the Edgeport Buffer empty?
 		if (lastCount == 0) {
-			dbg(__FUNCTION__" - TX Buffer Empty");
+			dbg("%s - TX Buffer Empty", __FUNCTION__);
 			return;
 		}
 
 		// Block the thread for a while
 		interruptible_sleep_on_timeout (&edge_port->wait_chase, timeout);
 
-		dbg(__FUNCTION__ " wait");
+		dbg("%s wait", __FUNCTION__);
 
 		if (lastCount == fifo->count) {
 			// No activity.. count down.
 			wait--;
 			if (wait == 0) {
-				dbg(__FUNCTION__" - TIMEOUT");
+				dbg("%s - TIMEOUT", __FUNCTION__);
 				return;
 			}
 		} else {
@@ -1232,7 +1217,7 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 			 
 	serial = get_usb_serial (port, __FUNCTION__);
 	if (!serial)
@@ -1243,57 +1228,50 @@
 	if ((edge_serial == NULL) || (edge_port == NULL))
 		return;
 	
-	--port->open_count;
+	if (serial->dev) {
+		// block until tx is empty
+		block_until_tx_empty(edge_port);
+
+		edge_port->closePending = TRUE;
+
+		/* flush and chase */
+		edge_port->chaseResponsePending = TRUE;
+
+		dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+		if (status == 0) {
+			// block until chase finished
+			block_until_chase_response(edge_port);
+		} else {
+			edge_port->chaseResponsePending = FALSE;
+		}
 
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			// block until tx is empty
-			block_until_tx_empty(edge_port);
-
-			edge_port->closePending = TRUE;
-
-			/* flush and chase */
-			edge_port->chaseResponsePending = TRUE;
-
-			dbg(__FUNCTION__" - Sending IOSP_CMD_CHASE_PORT");
-			status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
-			if (status == 0) {
-				// block until chase finished
-				block_until_chase_response(edge_port);
-			} else {
-				edge_port->chaseResponsePending = FALSE;
-			}
+		/* close the port */
+		dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__);
+		send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
 
-			/* close the port */
-			dbg(__FUNCTION__" - Sending IOSP_CMD_CLOSE_PORT");
-			send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
-
-			//port->close = TRUE;
-			edge_port->closePending = FALSE;
-			edge_port->open = FALSE;
-			edge_port->openPending = FALSE;
+		//port->close = TRUE;
+		edge_port->closePending = FALSE;
+		edge_port->open = FALSE;
+		edge_port->openPending = FALSE;
 
-			if (edge_port->write_urb) {
-				usb_unlink_urb (edge_port->write_urb);
-			}
-		}
-	
 		if (edge_port->write_urb) {
-			/* if this urb had a transfer buffer already (old transfer) free it */
-			if (edge_port->write_urb->transfer_buffer != NULL) {
-				kfree(edge_port->write_urb->transfer_buffer);
-			}
-			usb_free_urb   (edge_port->write_urb);
+			usb_unlink_urb (edge_port->write_urb);
 		}
-		if (edge_port->txfifo.fifo) {
-			kfree(edge_port->txfifo.fifo);
+	}
+
+	if (edge_port->write_urb) {
+		/* if this urb had a transfer buffer already (old transfer) free it */
+		if (edge_port->write_urb->transfer_buffer != NULL) {
+			kfree(edge_port->write_urb->transfer_buffer);
 		}
-		port->active = 0;
-		port->open_count = 0;
+		usb_free_urb   (edge_port->write_urb);
+	}
+	if (edge_port->txfifo.fifo) {
+		kfree(edge_port->txfifo.fifo);
 	}
 
-	MOD_DEC_USE_COUNT;
-	dbg(__FUNCTION__" exited");
+	dbg("%s exited", __FUNCTION__);
 }   
 
 /*****************************************************************************
@@ -1312,7 +1290,7 @@
 	int firsthalf;
 	int secondhalf;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (edge_port == NULL)
 		return -ENODEV;
@@ -1323,12 +1301,12 @@
 	// calculate number of bytes to put in fifo
 	copySize = min ((unsigned int)count, (edge_port->txCredits - fifo->count));
 
-	dbg(__FUNCTION__"(%d) of %d byte(s) Fifo room  %d -- will copy %d bytes", 
+	dbg("%s(%d) of %d byte(s) Fifo room  %d -- will copy %d bytes", __FUNCTION__, 
 	    port->number, count, edge_port->txCredits - fifo->count, copySize);
 
 	/* catch writes of 0 bytes which the tty driver likes to give us, and when txCredits is empty */
 	if (copySize == 0) {
-		dbg (__FUNCTION__" - copySize = Zero");
+		dbg("%s - copySize = Zero", __FUNCTION__);
 		return 0;
 	}
 
@@ -1340,7 +1318,7 @@
 
 	bytesleft = fifo->size - fifo->head;
 	firsthalf = min (bytesleft, copySize);
-	dbg (__FUNCTION__" - copy %d bytes of %d into fifo ", firsthalf, bytesleft);
+	dbg("%s - copy %d bytes of %d into fifo ", __FUNCTION__, firsthalf, bytesleft);
 
 	/* now copy our data */
 	if (from_user) {
@@ -1362,7 +1340,7 @@
 	secondhalf = copySize-firsthalf;
 
 	if (secondhalf) {
-		dbg (__FUNCTION__" - copy rest of data %d", secondhalf);
+		dbg("%s - copy rest of data %d", __FUNCTION__, secondhalf);
 		if (from_user) {
 			if (copy_from_user(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf))
 				return -EFAULT;
@@ -1381,7 +1359,7 @@
 
 	send_more_port_data((struct edgeport_serial *)port->serial->private, edge_port);
 
-	dbg(__FUNCTION__" wrote %d byte(s) TxCredits %d, Fifo %d", copySize, edge_port->txCredits, fifo->count);
+	dbg("%s wrote %d byte(s) TxCredits %d, Fifo %d", __FUNCTION__, copySize, edge_port->txCredits, fifo->count);
 
 	return copySize;   
 }
@@ -1411,12 +1389,12 @@
 	int		firsthalf;
 	int		secondhalf;
 
-	dbg(__FUNCTION__"(%d)", edge_port->port->number);
+	dbg("%s(%d)", __FUNCTION__, edge_port->port->number);
 
 	if (edge_port->write_in_progress ||
 	    !edge_port->open             ||
 	    (fifo->count == 0)) {
-		dbg(__FUNCTION__"(%d) EXIT - fifo %d, PendingWrite = %d", edge_port->port->number, fifo->count, edge_port->write_in_progress);
+		dbg("%s(%d) EXIT - fifo %d, PendingWrite = %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->write_in_progress);
 		return;
 	}
 
@@ -1428,7 +1406,7 @@
 	//	it's better to wait for more credits so we can do a larger
 	//	write.
 	if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits)) {
-		dbg(__FUNCTION__"(%d) Not enough credit - fifo %d TxCredit %d", edge_port->port->number, fifo->count, edge_port->txCredits );
+		dbg("%s(%d) Not enough credit - fifo %d TxCredit %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->txCredits );
 		return;
 	}
 
@@ -1446,9 +1424,9 @@
 
 	/* build the data header for the buffer and port that we are about to send out */
 	count = fifo->count;
-	buffer = kmalloc (count+2, GFP_KERNEL);
+	buffer = kmalloc (count+2, GFP_ATOMIC);
 	if (buffer == NULL) {
-		err(__FUNCTION__" - no more kernel memory...");
+		err("%s - no more kernel memory...", __FUNCTION__);
 		edge_port->write_in_progress = FALSE;
 		return;
 	}
@@ -1488,14 +1466,14 @@
 	status = usb_submit_urb(urb);
 	if (status) {
 		/* something went wrong */
-		dbg(__FUNCTION__" - usb_submit_urb(write bulk) failed");
+		dbg("%s - usb_submit_urb(write bulk) failed", __FUNCTION__);
 		edge_port->write_in_progress = FALSE;
 	} else {
 		/* decrement the number of credits we have by the number we just sent */
 		edge_port->txCredits -= count;
 		edge_port->icount.tx += count;
 	}
-	dbg(__FUNCTION__" wrote %d byte(s) TxCredit %d, Fifo %d", count, edge_port->txCredits, fifo->count);
+	dbg("%s wrote %d byte(s) TxCredit %d, Fifo %d", __FUNCTION__, count, edge_port->txCredits, fifo->count);
 }
 
 
@@ -1512,24 +1490,24 @@
 	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
 	int room;
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	if (edge_port == NULL)
 		return -ENODEV;
 	if (edge_port->closePending == TRUE)
 		return -ENODEV;
 
-	dbg(__FUNCTION__" - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (!edge_port->open) {
-		dbg (__FUNCTION__" - port not opened");
+		dbg("%s - port not opened", __FUNCTION__);
 		return -EINVAL;
 	}
 
 	// total of both buffers is still txCredit
 	room = edge_port->txCredits - edge_port->txfifo.count;
 
-	dbg(__FUNCTION__" - returns %d", room);
+	dbg("%s - returns %d", __FUNCTION__, room);
 	return room;
 }
 
@@ -1548,7 +1526,7 @@
 	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
 	int num_chars;
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	if (edge_port == NULL)
 		return -ENODEV;
@@ -1556,13 +1534,13 @@
 		return -ENODEV;
 
 	if (!edge_port->open) {
-		dbg (__FUNCTION__" - port not opened");
+		dbg("%s - port not opened", __FUNCTION__);
 		return -EINVAL;
 	}
 
 	num_chars = edge_port->maxTxCredits - edge_port->txCredits + edge_port->txfifo.count;
 	if (num_chars) {
-		dbg(__FUNCTION__"(port %d) - returns %d", port->number, num_chars);
+		dbg("%s(port %d) - returns %d", __FUNCTION__, port->number, num_chars);
 	}
 
 	return num_chars;
@@ -1580,17 +1558,21 @@
 	struct tty_struct *tty;
 	int status;
 
-	dbg(__FUNCTION__" - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (edge_port == NULL)
 		return;
 
 	if (!edge_port->open) {
-		dbg (__FUNCTION__" - port not opened");
+		dbg("%s - port not opened", __FUNCTION__);
 		return;
 	}
 
 	tty = port->tty;
+	if (!tty) {
+		dbg ("%s - no tty available", __FUNCTION__);
+		return;
+	}
 
 	/* if we are implementing XON/XOFF, send the stop character */
 	if (I_IXOFF(tty)) {
@@ -1625,17 +1607,21 @@
 	struct tty_struct *tty;
 	int status;
 
-	dbg(__FUNCTION__" - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (edge_port == NULL)
 		return;
 
 	if (!edge_port->open) {
-		dbg (__FUNCTION__" - port not opened");
+		dbg("%s - port not opened", __FUNCTION__);
 		return;
 	}
 
 	tty = port->tty;
+	if (!tty) {
+		dbg ("%s - no tty available", __FUNCTION__);
+		return;
+	}
 
 	/* if we are implementing XON/XOFF, send the start character */
 	if (I_IXOFF(tty)) {
@@ -1667,31 +1653,39 @@
 {
 	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
 	struct tty_struct *tty = port->tty;
-	unsigned int cflag = tty->termios->c_cflag;
+	unsigned int cflag;
 
-	dbg(__FUNCTION__" - clfag %08x %08x iflag %08x %08x", 
-	    tty->termios->c_cflag,
-	    old_termios->c_cflag,
-	    RELEVANT_IFLAG(tty->termios->c_iflag),
-	    RELEVANT_IFLAG(old_termios->c_iflag)
-	   );
+	if (!port->tty || !port->tty->termios) {
+		dbg ("%s - no tty or termios", __FUNCTION__);
+		return;
+	}
 
+	cflag = tty->termios->c_cflag;
 	/* check that they really want us to change something */
 	if (old_termios) {
 		if ((cflag == old_termios->c_cflag) &&
 		    (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
-			dbg(__FUNCTION__" - nothing to change");
+			dbg("%s - nothing to change", __FUNCTION__);
 			return;
 		}
 	}
 
-	dbg(__FUNCTION__" - port %d", port->number);
+	dbg("%s - clfag %08x iflag %08x", __FUNCTION__, 
+	    tty->termios->c_cflag,
+	    RELEVANT_IFLAG(tty->termios->c_iflag));
+	if (old_termios) {
+		dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+		    old_termios->c_cflag,
+		    RELEVANT_IFLAG(old_termios->c_iflag));
+	}
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (edge_port == NULL)
 		return;
 
 	if (!edge_port->open) {
-		dbg (__FUNCTION__" - port not opened");
+		dbg("%s - port not opened", __FUNCTION__);
 		return;
 	}
 
@@ -1718,7 +1712,7 @@
 
 	if (edge_port->maxTxCredits == edge_port->txCredits &&
 	    edge_port->txfifo.count == 0) {
-		dbg(__FUNCTION__" -- Empty");
+		dbg("%s -- Empty", __FUNCTION__);
 		result = TIOCSER_TEMT;
 	}
 
@@ -1732,9 +1726,12 @@
 	unsigned int result = 0;
 	struct tty_struct *tty = edge_port->port->tty;
 
+	if (!tty)
+		return -ENOIOCTLCMD;
+
 	result = tty->read_cnt;
 
-	dbg(__FUNCTION__"(%d) = %d",  edge_port->port->number, result);
+	dbg("%s(%d) = %d", __FUNCTION__,  edge_port->port->number, result);
 	if (copy_to_user(value, &result, sizeof(int)))
 		return -EFAULT;
 	//return 0;
@@ -1799,7 +1796,7 @@
 		  | ((msr & MSR_DSR)	? TIOCM_DSR: 0);  /* 0x100 */
 
 
-	dbg(__FUNCTION__" -- %x", result);
+	dbg("%s -- %x", __FUNCTION__, result);
 
 	if (copy_to_user(value, &result, sizeof(int)))
 		return -EFAULT;
@@ -1850,40 +1847,40 @@
 	struct serial_icounter_struct icount;
 
 
-	dbg(__FUNCTION__" - port %d, cmd = 0x%x", port->number, cmd);
+	dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
 
 	switch (cmd) {
 		// return number of bytes available
 		case TIOCINQ:
-			dbg(__FUNCTION__" (%d) TIOCINQ",  port->number);
+			dbg("%s (%d) TIOCINQ", __FUNCTION__,  port->number);
 			return get_number_bytes_avail(edge_port, (unsigned int *) arg);
 			break;
 
 		case TIOCSERGETLSR:
-			dbg(__FUNCTION__" (%d) TIOCSERGETLSR",  port->number);
+			dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__,  port->number);
 			return get_lsr_info(edge_port, (unsigned int *) arg);
 			return 0;
 
 		case TIOCMBIS:
 		case TIOCMBIC:
 		case TIOCMSET:
-			dbg(__FUNCTION__" (%d) TIOCMSET/TIOCMBIC/TIOCMSET",  port->number);
+			dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__,  port->number);
 			return set_modem_info(edge_port, cmd, (unsigned int *) arg);
 
 		case TIOCMGET:  
-			dbg(__FUNCTION__" (%d) TIOCMGET",  port->number);
+			dbg("%s (%d) TIOCMGET", __FUNCTION__,  port->number);
 			return get_modem_info(edge_port, (unsigned int *) arg);
 
 		case TIOCGSERIAL:
-			dbg(__FUNCTION__" (%d) TIOCGSERIAL",  port->number);
+			dbg("%s (%d) TIOCGSERIAL", __FUNCTION__,  port->number);
 			return get_serial_info(edge_port, (struct serial_struct *) arg);
 
 		case TIOCSSERIAL:
-			dbg(__FUNCTION__" (%d) TIOCSSERIAL",  port->number);
+			dbg("%s (%d) TIOCSSERIAL", __FUNCTION__,  port->number);
 			break;
 
 		case TIOCMIWAIT:
-			dbg(__FUNCTION__" (%d) TIOCMIWAIT",  port->number);
+			dbg("%s (%d) TIOCMIWAIT", __FUNCTION__,  port->number);
 			cprev = edge_port->icount;
 			while (1) {
 				interruptible_sleep_on(&edge_port->delta_msr_wait);
@@ -1919,7 +1916,7 @@
 			icount.brk = cnow.brk;
 			icount.buf_overrun = cnow.buf_overrun;
 
-			dbg(__FUNCTION__" (%d) TIOCGICOUNT RX=%d, TX=%d",  port->number, icount.rx, icount.tx );
+			dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__,  port->number, icount.rx, icount.tx );
 			if (copy_to_user((void *)arg, &icount, sizeof(icount)))
 				return -EFAULT;
 			return 0;
@@ -1941,7 +1938,7 @@
 	/* flush and chase */
 	edge_port->chaseResponsePending = TRUE;
 
-	dbg(__FUNCTION__" - Sending IOSP_CMD_CHASE_PORT");
+	dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
 	status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
 	if (status == 0) {
 		// block until chase finished
@@ -1951,14 +1948,14 @@
 	}
 
 	if (break_state == -1) {
-		dbg(__FUNCTION__" - Sending IOSP_CMD_SET_BREAK");
+		dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__);
 		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
 	} else {
-		dbg(__FUNCTION__" - Sending IOSP_CMD_CLEAR_BREAK");
+		dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__);
 		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
 	}
 	if (status) {
-		dbg(__FUNCTION__" - error sending break set/clear command.");
+		dbg("%s - error sending break set/clear command.", __FUNCTION__);
 	}
 
 	return;
@@ -1978,14 +1975,14 @@
 	__u16 rxLen;
 	int i;
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	lastBufferLength = bufferLength + 1;
 
 	while (bufferLength > 0) {
 		/* failsafe incase we get a message that we don't understand */
 		if (lastBufferLength == bufferLength) {
-			dbg(__FUNCTION__" - stuck in loop, exiting it.");
+			dbg("%s - stuck in loop, exiting it.", __FUNCTION__);
 			break;
 		}
 		lastBufferLength = bufferLength;
@@ -2007,7 +2004,7 @@
 				++buffer;
 				--bufferLength;
 
-				dbg(__FUNCTION__" - Hdr1=%02X Hdr2=%02X", edge_serial->rxHeader1, edge_serial->rxHeader2);
+				dbg("%s - Hdr1=%02X Hdr2=%02X", __FUNCTION__, edge_serial->rxHeader1, edge_serial->rxHeader2);
 
 				// Process depending on whether this header is
 				// data or status
@@ -2038,7 +2035,7 @@
 					edge_serial->rxPort = IOSP_GET_HDR_PORT(edge_serial->rxHeader1);
 					edge_serial->rxBytesRemaining = IOSP_GET_HDR_DATA_LEN(edge_serial->rxHeader1, edge_serial->rxHeader2);
 
-					dbg(__FUNCTION__" - Data for Port %u Len %u", edge_serial->rxPort, edge_serial->rxBytesRemaining);
+					dbg("%s - Data for Port %u Len %u", __FUNCTION__, edge_serial->rxPort, edge_serial->rxBytesRemaining);
 
 					//ASSERT( DevExt->RxPort < DevExt->NumPorts );
 					//ASSERT( DevExt->RxBytesRemaining < IOSP_MAX_DATA_LENGTH );
@@ -2072,7 +2069,7 @@
 						if (edge_port->open) {
 							tty = edge_port->port->tty;
 							if (tty) {
-								dbg (__FUNCTION__" - Sending %d bytes to TTY for port %d", rxLen, edge_serial->rxPort);
+								dbg("%s - Sending %d bytes to TTY for port %d", __FUNCTION__, rxLen, edge_serial->rxPort);
 								for (i = 0; i < rxLen ; ++i) {
 									/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
 									if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
@@ -2125,17 +2122,17 @@
 	}
 	edge_port = (struct edgeport_port *)port->private;
 	if (edge_port == NULL) {
-		err (__FUNCTION__ " - edge_port == NULL for port %d", edge_serial->rxPort);
+		err("%s - edge_port == NULL for port %d", __FUNCTION__, edge_serial->rxPort);
 		return;
 	}
 
-	dbg(__FUNCTION__" - port %d", edge_serial->rxPort);
+	dbg("%s - port %d", __FUNCTION__, edge_serial->rxPort);
 
 	if (code == IOSP_EXT_STATUS) {
 		switch (byte2) {
 			case IOSP_EXT_STATUS_CHASE_RSP:
 				// we want to do EXT status regardless of port open/closed 
-				dbg(__FUNCTION__" - Port %u EXT CHASE_RSP Data = %02x", edge_serial->rxPort, byte3 );
+				dbg("%s - Port %u EXT CHASE_RSP Data = %02x", __FUNCTION__, edge_serial->rxPort, byte3 );
 				// Currently, the only EXT_STATUS is Chase, so process here instead of one more call
 				// to one more subroutine. If/when more EXT_STATUS, there'll be more work to do.
 				// Also, we currently clear flag and close the port regardless of content of above's Byte3.
@@ -2146,7 +2143,7 @@
 				return;
 
 			case IOSP_EXT_STATUS_RX_CHECK_RSP:
-				dbg( __FUNCTION__" ========== Port %u CHECK_RSP Sequence = %02x =============\n", edge_serial->rxPort, byte3 );
+				dbg("%s ========== Port %u CHECK_RSP Sequence = %02x =============\n", __FUNCTION__, edge_serial->rxPort, byte3 );
 				//Port->RxCheckRsp = TRUE;
 				return;
 		}
@@ -2155,11 +2152,12 @@
 	if (code == IOSP_STATUS_OPEN_RSP) {
 		edge_port->txCredits = GET_TX_BUFFER_SIZE(byte3);
 		edge_port->maxTxCredits = edge_port->txCredits;
-		dbg (__FUNCTION__" - Port %u Open Response Inital MSR = %02x TxBufferSize = %d", edge_serial->rxPort, byte2, edge_port->txCredits);
+		dbg("%s - Port %u Open Response Inital MSR = %02x TxBufferSize = %d", __FUNCTION__, edge_serial->rxPort, byte2, edge_port->txCredits);
 		handle_new_msr (edge_port, byte2);
 
 		/* send the current line settings to the port so we are in sync with any further termios calls */
-		change_port_settings (edge_port, edge_port->port->tty->termios);
+		if (edge_port->port->tty)
+			change_port_settings (edge_port, edge_port->port->tty->termios);
 
 		/* we have completed the open */
 		edge_port->openPending = FALSE;
@@ -2178,23 +2176,23 @@
 	switch (code) {
 		// Not currently sent by Edgeport
 		case IOSP_STATUS_LSR:
-			dbg(__FUNCTION__" - Port %u LSR Status = %02x", edge_serial->rxPort, byte2);
+			dbg("%s - Port %u LSR Status = %02x", __FUNCTION__, edge_serial->rxPort, byte2);
 			handle_new_lsr (edge_port, FALSE, byte2, 0);
 			break;
 
 		case IOSP_STATUS_LSR_DATA:
-			dbg(__FUNCTION__" - Port %u LSR Status = %02x, Data = %02x", edge_serial->rxPort, byte2, byte3);
+			dbg("%s - Port %u LSR Status = %02x, Data = %02x", __FUNCTION__, edge_serial->rxPort, byte2, byte3);
 			// byte2 is LSR Register
 			// byte3 is broken data byte
 			handle_new_lsr (edge_port, TRUE, byte2, byte3);
 			break;
 			//
 			//	case IOSP_EXT_4_STATUS:
-			//		dbg(__FUNCTION__" - Port %u LSR Status = %02x Data = %02x", edge_serial->rxPort, byte2, byte3);
+			//		dbg("%s - Port %u LSR Status = %02x Data = %02x", __FUNCTION__, edge_serial->rxPort, byte2, byte3);
 			//		break;
 			//
 		case IOSP_STATUS_MSR:
-			dbg(__FUNCTION__" - Port %u MSR Status = %02x", edge_serial->rxPort, byte2);
+			dbg("%s - Port %u MSR Status = %02x", __FUNCTION__, edge_serial->rxPort, byte2);
 
 			// Process this new modem status and generate appropriate
 			// events, etc, based on the new status. This routine
@@ -2203,7 +2201,7 @@
 			break;
 
 		default:
-			dbg(__FUNCTION__" - Unrecognized IOSP status code %u\n", code);
+			dbg("%s - Unrecognized IOSP status code %u\n", __FUNCTION__, code);
 			break;
 	}
 
@@ -2219,7 +2217,7 @@
 {
 	struct  async_icount *icount;
 
-	dbg(__FUNCTION__" %02x", newMsr);
+	dbg("%s %02x", __FUNCTION__, newMsr);
 
 	if (newMsr & (MSR_DELTA_CTS | MSR_DELTA_DSR | MSR_DELTA_RI | MSR_DELTA_CD)) {
 		icount = &edge_port->icount;
@@ -2256,7 +2254,7 @@
 	__u8    newLsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK));
 	struct  async_icount *icount;
 
-	dbg(__FUNCTION__" - %02x", newLsr);
+	dbg("%s - %02x", __FUNCTION__, newLsr);
 
 	edge_port->shadowLSR = lsr;
 
@@ -2270,7 +2268,7 @@
 	}
 
 	/* Place LSR data byte into Rx buffer */
-	if (lsrData) {
+	if (lsrData && edge_port->port->tty) {
 		tty_insert_flip_char(edge_port->port->tty, data, 0);
 		tty_flip_buffer_push(edge_port->port->tty);
 	}
@@ -2307,11 +2305,11 @@
 	__u16 current_length;
 	unsigned char *transfer_buffer;
 
-//	dbg (__FUNCTION__" - %x, %x, %d", extAddr, addr, length);
+//	dbg("%s - %x, %x, %d", __FUNCTION__, extAddr, addr, length);
 
 	transfer_buffer =  kmalloc (64, GFP_KERNEL);
 	if (!transfer_buffer) {
-		err(__FUNCTION__" - kmalloc(%d) failed.\n", 64);
+		err("%s - kmalloc(%d) failed.\n", __FUNCTION__, 64);
 		return -ENOMEM;
 	}
 
@@ -2323,7 +2321,7 @@
 		} else {
 			current_length = length;
 		}
-//		dbg (__FUNCTION__" - writing %x, %x, %d", extAddr, addr, current_length);
+//		dbg("%s - writing %x, %x, %d", __FUNCTION__, extAddr, addr, current_length);
 		memcpy (transfer_buffer, data, current_length);
 		result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), USB_REQUEST_ION_WRITE_RAM, 
 					  0x40, addr, extAddr, transfer_buffer, current_length, 300);
@@ -2352,11 +2350,11 @@
 	__u16 current_length;
 	unsigned char *transfer_buffer;
 
-//	dbg (__FUNCTION__" - %x, %x, %d", extAddr, addr, length);
+//	dbg("%s - %x, %x, %d", __FUNCTION__, extAddr, addr, length);
 
 	transfer_buffer =  kmalloc (64, GFP_KERNEL);
 	if (!transfer_buffer) {
-		err(__FUNCTION__" - kmalloc(%d) failed.\n", 64);
+		err("%s - kmalloc(%d) failed.\n", __FUNCTION__, 64);
 		return -ENOMEM;
 	}
 
@@ -2368,7 +2366,7 @@
 		} else {
 			current_length = length;
 		}
-//		dbg (__FUNCTION__" - writing %x, %x, %d", extAddr, addr, current_length);
+//		dbg("%s - writing %x, %x, %d", __FUNCTION__, extAddr, addr, current_length);
 		memcpy (transfer_buffer, data, current_length);
 		result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), USB_REQUEST_ION_WRITE_ROM, 
 					  0x40, addr, extAddr, transfer_buffer, current_length, 300);
@@ -2397,11 +2395,11 @@
 	__u16 current_length;
 	unsigned char *transfer_buffer;
 
-	dbg (__FUNCTION__" - %x, %x, %d", extAddr, addr, length);
+	dbg("%s - %x, %x, %d", __FUNCTION__, extAddr, addr, length);
 
 	transfer_buffer =  kmalloc (64, GFP_KERNEL);
 	if (!transfer_buffer) {
-		err(__FUNCTION__" - kmalloc(%d) failed.\n", 64);
+		err("%s - kmalloc(%d) failed.\n", __FUNCTION__, 64);
 		return -ENOMEM;
 	}
 
@@ -2413,7 +2411,7 @@
 		} else {
 			current_length = length;
 		}
-//		dbg (__FUNCTION__" - %x, %x, %d", extAddr, addr, current_length);
+//		dbg("%s - %x, %x, %d", __FUNCTION__, extAddr, addr, current_length);
 		result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), USB_REQUEST_ION_READ_ROM, 
 					  0xC0, addr, extAddr, transfer_buffer, current_length, 300);
 		if (result < 0)
@@ -2440,11 +2438,11 @@
 	int             length = 0;
 	int             status = 0;
 
-	dbg(__FUNCTION__" - %d, %d", command, param);
+	dbg("%s - %d, %d", __FUNCTION__, command, param);
 
-	buffer =  kmalloc (10, GFP_KERNEL);
+	buffer =  kmalloc (10, GFP_ATOMIC);
 	if (!buffer) {
-		err(__FUNCTION__" - kmalloc(%d) failed.\n", 10);
+		err("%s - kmalloc(%d) failed.\n", __FUNCTION__, 10);
 		return -ENOMEM;
 	}
 
@@ -2472,7 +2470,7 @@
 {
 	struct edgeport_serial *edge_serial = (struct edgeport_serial *)edge_port->port->serial->private;
 	int status = 0;
-	urb_t *urb;
+	struct urb *urb;
 	int timeout;
 
 	usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer);
@@ -2483,7 +2481,7 @@
 		return -ENOMEM;
 
 	CmdUrbs++;
-	dbg(__FUNCTION__" - ALLOCATE URB %p (outstanding %d)", urb, CmdUrbs);
+	dbg("%s - ALLOCATE URB %p (outstanding %d)", __FUNCTION__, urb, CmdUrbs);
 
 	FILL_BULK_URB (urb, edge_serial->serial->dev, 
 		       usb_sndbulkpipe(edge_serial->serial->dev, edge_serial->bulk_out_endpoint),
@@ -2497,7 +2495,7 @@
 
 	if (status) {
 		/* something went wrong */
-		dbg(__FUNCTION__" - usb_submit_urb(write bulk) failed");
+		dbg("%s - usb_submit_urb(write bulk) failed", __FUNCTION__);
 		usb_unlink_urb (urb);
 		usb_free_urb   (urb);
 		return status;
@@ -2512,7 +2510,7 @@
 
 	if (edge_port->commandPending == TRUE) {
 		/* command timed out */
-		dbg(__FUNCTION__" - command timed out");
+		dbg("%s - command timed out", __FUNCTION__);
 		status = -EINVAL;
 	}
 #endif
@@ -2534,18 +2532,18 @@
 	int status;
 	unsigned char number = edge_port->port->number - edge_port->port->serial->minor;
 
-	dbg(__FUNCTION__" - port = %d, baud = %d", edge_port->port->number, baudRate);
+	dbg("%s - port = %d, baud = %d", __FUNCTION__, edge_port->port->number, baudRate);
 
 	status = calc_baud_rate_divisor (baudRate, &divisor);
 	if (status) {
-		err(__FUNCTION__" - bad baud rate");
+		err("%s - bad baud rate", __FUNCTION__);
 		return status;
 	}
 
 	// Alloc memory for the string of commands.
-	cmdBuffer =  kmalloc (0x100, GFP_KERNEL);
+	cmdBuffer =  kmalloc (0x100, GFP_ATOMIC);
 	if (!cmdBuffer) {
-		err(__FUNCTION__" - kmalloc(%d) failed.\n", 0x100);
+		err("%s - kmalloc(%d) failed.\n", __FUNCTION__, 0x100);
 		return -ENOMEM;
 	}
 	currCmd = cmdBuffer;
@@ -2583,11 +2581,11 @@
 	__u16 round;
 
 
-	dbg(__FUNCTION__" - %d", baudrate);
+	dbg("%s - %d", __FUNCTION__, baudrate);
 
-	for (i = 0; i < NUM_ENTRIES(DivisorTable); i++) {
-		if ( DivisorTable[i].BaudRate == baudrate ) {
-			*divisor = DivisorTable[i].Divisor;
+	for (i = 0; i < NUM_ENTRIES(divisor_table); i++) {
+		if ( divisor_table[i].BaudRate == baudrate ) {
+			*divisor = divisor_table[i].Divisor;
 			return 0;
 		}
 	}
@@ -2607,7 +2605,7 @@
 		}
 		*divisor = custom;
 
-		dbg(__FUNCTION__" - Baud %d = %d\n", baudrate, custom);
+		dbg("%s - Baud %d = %d\n", __FUNCTION__, baudrate, custom);
 		return 0;
 	}
 
@@ -2626,10 +2624,10 @@
 	unsigned long cmdLen = 0;
 	int status;
 
-	dbg (__FUNCTION__" - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", regValue);
+	dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __FUNCTION__, regValue);
 
 	// Alloc memory for the string of commands.
-	cmdBuffer = kmalloc (0x10, GFP_KERNEL);
+	cmdBuffer = kmalloc (0x10, GFP_ATOMIC);
 	if (cmdBuffer == NULL ) {
 		return -ENOMEM;
 	}
@@ -2669,50 +2667,50 @@
 	__u8 txFlow;
 	int status;
 
-	dbg(__FUNCTION__" - port %d", edge_port->port->number);
+	dbg("%s - port %d", __FUNCTION__, edge_port->port->number);
 
 	if ((!edge_port->open) &&
 	    (!edge_port->openPending)) {
-		dbg(__FUNCTION__" - port not opened");
+		dbg("%s - port not opened", __FUNCTION__);
 		return;
 	}
 
 	tty = edge_port->port->tty;
 	if ((!tty) ||
 	    (!tty->termios)) {
-		dbg(__FUNCTION__" - no tty structures");
+		dbg("%s - no tty structures", __FUNCTION__);
 		return;
 	}
 
 	cflag = tty->termios->c_cflag;
 
 	switch (cflag & CSIZE) {
-		case CS5:   lData = LCR_BITS_5; mask = 0x1f;    dbg(__FUNCTION__" - data bits = 5");   break;
-		case CS6:   lData = LCR_BITS_6; mask = 0x3f;    dbg(__FUNCTION__" - data bits = 6");   break;
-		case CS7:   lData = LCR_BITS_7; mask = 0x7f;    dbg(__FUNCTION__" - data bits = 7");   break;
+		case CS5:   lData = LCR_BITS_5; mask = 0x1f;    dbg("%s - data bits = 5", __FUNCTION__);   break;
+		case CS6:   lData = LCR_BITS_6; mask = 0x3f;    dbg("%s - data bits = 6", __FUNCTION__);   break;
+		case CS7:   lData = LCR_BITS_7; mask = 0x7f;    dbg("%s - data bits = 7", __FUNCTION__);   break;
 		default:
-		case CS8:   lData = LCR_BITS_8;                 dbg(__FUNCTION__" - data bits = 8");   break;
+		case CS8:   lData = LCR_BITS_8;                 dbg("%s - data bits = 8", __FUNCTION__);   break;
 	}
 
 	lParity = LCR_PAR_NONE;
 	if (cflag & PARENB) {
 		if (cflag & PARODD) {
 			lParity = LCR_PAR_ODD;
-			dbg(__FUNCTION__" - parity = odd");
+			dbg("%s - parity = odd", __FUNCTION__);
 		} else {
 			lParity = LCR_PAR_EVEN;
-			dbg(__FUNCTION__" - parity = even");
+			dbg("%s - parity = even", __FUNCTION__);
 		}
 	} else {
-		dbg(__FUNCTION__" - parity = none");
+		dbg("%s - parity = none", __FUNCTION__);
 	}
 
 	if (cflag & CSTOPB) {
 		lStop = LCR_STOP_2;
-		dbg(__FUNCTION__" - stop bits = 2");
+		dbg("%s - stop bits = 2", __FUNCTION__);
 	} else {
 		lStop = LCR_STOP_1;
-		dbg(__FUNCTION__" - stop bits = 1");
+		dbg("%s - stop bits = 1", __FUNCTION__);
 	}
 
 	/* figure out the flow control settings */
@@ -2720,9 +2718,9 @@
 	if (cflag & CRTSCTS) {
 		rxFlow |= IOSP_RX_FLOW_RTS;
 		txFlow |= IOSP_TX_FLOW_CTS;
-		dbg(__FUNCTION__" - RTS/CTS is enabled");
+		dbg("%s - RTS/CTS is enabled", __FUNCTION__);
 	} else {
-		dbg(__FUNCTION__" - RTS/CTS is disabled");
+		dbg("%s - RTS/CTS is disabled", __FUNCTION__);
 	}
 
 	/* if we are implementing XON/XOFF, set the start and stop character in the device */
@@ -2736,17 +2734,17 @@
 		/* if we are implementing INBOUND XON/XOFF */
 		if (I_IXOFF(tty)) {
 			rxFlow |= IOSP_RX_FLOW_XON_XOFF;
-			dbg(__FUNCTION__" - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", start_char, stop_char);
+			dbg("%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", __FUNCTION__, start_char, stop_char);
 		} else {
-			dbg(__FUNCTION__" - INBOUND XON/XOFF is disabled");
+			dbg("%s - INBOUND XON/XOFF is disabled", __FUNCTION__);
 		}
 
 		/* if we are implementing OUTBOUND XON/XOFF */
 		if (I_IXON(tty)) {
 			txFlow |= IOSP_TX_FLOW_XON_XOFF;
-			dbg(__FUNCTION__" - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", start_char, stop_char);
+			dbg("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", __FUNCTION__, start_char, stop_char);
 		} else {
-			dbg(__FUNCTION__" - OUTBOUND XON/XOFF is disabled");
+			dbg("%s - OUTBOUND XON/XOFF is disabled", __FUNCTION__);
 		}
 	}
 
@@ -2783,7 +2781,7 @@
 		baud = 9600;
 	}
 
-	dbg(__FUNCTION__ " - baud rate = %d", baud);
+	dbg("%s - baud rate = %d", __FUNCTION__, baud);
 	status = send_cmd_write_baud_rate (edge_port, baud);
 
 	return;
@@ -2881,7 +2879,7 @@
  ****************************************************************************/
 static void load_application_firmware (struct edgeport_serial *edge_serial)
 {
-	PEDGE_FIRMWARE_IMAGE_RECORD record;
+	struct edge_firmware_image_record *record;
 	unsigned char *firmware;
 	unsigned char *FirmwareImage;
 	int ImageSize;
@@ -2919,13 +2917,13 @@
 
 
 	for (;;) {
-		record = (PEDGE_FIRMWARE_IMAGE_RECORD)firmware;
+		record = (struct edge_firmware_image_record *)firmware;
 		response = sram_write (edge_serial->serial, record->ExtAddr, record->Addr, record->Len, &record->Data[0]);
 		if (response < 0) {
 			err("sram_write failed (%x, %x, %d)", record->ExtAddr, record->Addr, record->Len);
 			break;
 		}
-		firmware += sizeof (EDGE_FIRMWARE_IMAGE_RECORD) + record->Len;
+		firmware += sizeof (struct edge_firmware_image_record) + record->Len;
 		if (firmware >= &FirmwareImage[ImageSize]) {
 			break;
 		}
@@ -2958,7 +2956,7 @@
 	/* create our private serial structure */
 	edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL);
 	if (edge_serial == NULL) {
-		err(__FUNCTION__" - Out of memory");
+		err("%s - Out of memory", __FUNCTION__);
 		return -ENOMEM;
 	}
 	memset (edge_serial, 0, sizeof(struct edgeport_serial));
@@ -2985,22 +2983,23 @@
 	/* set the number of ports from the manufacturing description */
 	/* serial->num_ports = serial->product_info.NumPorts; */
 	if (edge_serial->product_info.NumPorts != serial->num_ports) {
-		warn(__FUNCTION__ " - Device Reported %d serial ports vs core "
+		warn("%s - Device Reported %d serial ports vs core "
 		     "thinking we have %d ports, email greg@kroah.com this info.",
-		     edge_serial->product_info.NumPorts, serial->num_ports);
+		     __FUNCTION__, edge_serial->product_info.NumPorts, 
+		     serial->num_ports);
 	}
 
-	dbg(__FUNCTION__ " - time 1 %ld", jiffies);
+	dbg("%s - time 1 %ld", __FUNCTION__, jiffies);
 
 	/* now load the application firmware into this device */
 	load_application_firmware (edge_serial);
 
-	dbg(__FUNCTION__ " - time 2 %ld", jiffies);
+	dbg("%s - time 2 %ld", __FUNCTION__, jiffies);
 
 	/* Check current Edgeport EEPROM and update if necessary */
 	update_edgeport_E2PROM (edge_serial);
 	
-	dbg(__FUNCTION__ " - time 3 %ld", jiffies);
+	dbg("%s - time 3 %ld", __FUNCTION__, jiffies);
 
 	/* set the configuration to use #1 */
 //	dbg("set_configuration 1");
@@ -3013,7 +3012,7 @@
 	for (i = 0; i < serial->num_ports; ++i) {
 		edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL);
 		if (edge_port == NULL) {
-			err(__FUNCTION__" - Out of memory");
+			err("%s - Out of memory", __FUNCTION__);
 			return -ENOMEM;
 		}
 		memset (edge_port, 0, sizeof(struct edgeport_port));
@@ -3034,13 +3033,10 @@
 {
 	int i;
 
-	dbg (__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	/* stop reads and writes on all ports */
 	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
-			edge_close (&serial->port[i], NULL);
-		}
 		kfree (serial->port[i].private);
 		serial->port[i].private = NULL;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/io_edgeport.h linux-2.4.20/drivers/usb/serial/io_edgeport.h
--- linux-2.4.19/drivers/usb/serial/io_edgeport.h	2001-08-28 18:21:02.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/io_edgeport.h	2002-10-29 11:18:49.000000000 +0000
@@ -136,7 +136,6 @@
 	__u16	Strings[1];			/* Start of string block */
 };
 
-typedef struct string_block STRING_BLOCK, *PSTRING_BLOCK;
 
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/io_fw_boot.h linux-2.4.20/drivers/usb/serial/io_fw_boot.h
--- linux-2.4.19/drivers/usb/serial/io_fw_boot.h	2001-03-20 01:21:54.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/io_fw_boot.h	2002-10-29 11:18:51.000000000 +0000
@@ -12,20 +12,18 @@
 //Image structure definition
 #if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
 #define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
-	typedef struct _EDGE_FIRMWARE_IMAGE_RECORD
-	{
+	struct edge_firmware_image_record {
 		unsigned short ExtAddr;
 		unsigned short Addr;
 		unsigned short Len;
 		unsigned char  Data[0];
-	} EDGE_FIRMWARE_IMAGE_RECORD, *PEDGE_FIRMWARE_IMAGE_RECORD;
+	};
 
-	typedef struct _EDGE_FIRMWARE_VERSION_INFO
-	{
+	struct edge_firmware_version_info {
 		unsigned char	 MajorVersion;
 		unsigned char  MinorVersion;
 		unsigned short BuildNumber;
-	} EDGE_FIRMWARE_VERSION_INFO, *PEDGE_FIRMWARE_VERSION_INFO;
+	};
 
 #endif
 
@@ -549,7 +547,7 @@
     0x7e, 0x74, 0x00, 0x01, 0x02, 0x08, 0xd6, 
 };
 
-static EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME = {
+static struct edge_firmware_version_info IMAGE_VERSION_NAME = {
 	1, 12, 2 };		// Major, Minor, Build
 
 #undef IMAGE_VERSION_NAME
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/io_fw_boot2.h linux-2.4.20/drivers/usb/serial/io_fw_boot2.h
--- linux-2.4.19/drivers/usb/serial/io_fw_boot2.h	2001-03-20 01:21:54.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/io_fw_boot2.h	2002-10-29 11:18:34.000000000 +0000
@@ -12,20 +12,18 @@
 //Image structure definition
 #if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
 #define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
-	typedef struct _EDGE_FIRMWARE_IMAGE_RECORD
-	{
+	struct edge_firmware_image_record {
 		unsigned short ExtAddr;
 		unsigned short Addr;
 		unsigned short Len;
 		unsigned char  Data[0];
-	} EDGE_FIRMWARE_IMAGE_RECORD, *PEDGE_FIRMWARE_IMAGE_RECORD;
+	};
 
-	typedef struct _EDGE_FIRMWARE_VERSION_INFO
-	{
+	struct edge_firmware_version_info {
 		unsigned char	 MajorVersion;
 		unsigned char  MinorVersion;
 		unsigned short BuildNumber;
-	} EDGE_FIRMWARE_VERSION_INFO, *PEDGE_FIRMWARE_VERSION_INFO;
+	};
 
 #endif
 
@@ -539,7 +537,7 @@
 
 };
 
-static EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME = {
+static struct edge_firmware_version_info IMAGE_VERSION_NAME = {
 	2, 0, 3 };		// Major, Minor, Build
 
 #undef IMAGE_VERSION_NAME
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/io_fw_down.h linux-2.4.20/drivers/usb/serial/io_fw_down.h
--- linux-2.4.19/drivers/usb/serial/io_fw_down.h	2001-03-20 01:21:54.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/io_fw_down.h	2002-10-29 11:18:40.000000000 +0000
@@ -12,20 +12,18 @@
 //Image structure definition
 #if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
 	#define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
-	typedef struct _EDGE_FIRMWARE_IMAGE_RECORD
-	{
+	struct edge_firmware_image_record {
 		unsigned short	ExtAddr;
 		unsigned short	Addr;
 		unsigned short	Len;
 		unsigned char	Data[0];
-	} EDGE_FIRMWARE_IMAGE_RECORD, *PEDGE_FIRMWARE_IMAGE_RECORD;
+	};
 
-	typedef struct _EDGE_FIRMWARE_VERSION_INFO
-	{
+	struct edge_firmware_version_info {
 		unsigned char	MajorVersion;
 		unsigned char	MinorVersion;
 		unsigned short	BuildNumber;
-	} EDGE_FIRMWARE_VERSION_INFO, *PEDGE_FIRMWARE_VERSION_INFO;
+	};
 
 #endif
 
@@ -1114,7 +1112,7 @@
     0x08, 0xa5, 0xb8, 0x02, 0x03, 0x4e, 0xa0, 0x08, 0x22, 0x80, 0xfe, 
 };
 
-static EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME = {
+static struct edge_firmware_version_info IMAGE_VERSION_NAME = {
 	1, 12, 3 };		// Major, Minor, Build
 
 #undef IMAGE_VERSION_NAME
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/io_fw_down2.h linux-2.4.20/drivers/usb/serial/io_fw_down2.h
--- linux-2.4.19/drivers/usb/serial/io_fw_down2.h	2001-03-20 01:21:54.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/io_fw_down2.h	2002-10-29 11:18:35.000000000 +0000
@@ -12,20 +12,18 @@
 //Image structure definition
 #if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
 	#define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
-	typedef struct _EDGE_FIRMWARE_IMAGE_RECORD
-	{
+	struct edge_firmware_image_record {
 		unsigned short ExtAddr;
 		unsigned short Addr;
 		unsigned short Len;
 		unsigned char  Data[0];
-	} EDGE_FIRMWARE_IMAGE_RECORD, *PEDGE_FIRMWARE_IMAGE_RECORD;
+	};
 
-	typedef struct _EDGE_FIRMWARE_VERSION_INFO
-	{
-		unsigned char	 MajorVersion;
+	struct edge_firmware_version_info {
+		unsigned char  MajorVersion;
 		unsigned char  MinorVersion;
 		unsigned short BuildNumber;
-	} EDGE_FIRMWARE_VERSION_INFO, *PEDGE_FIRMWARE_VERSION_INFO;
+	};
 
 #endif
 
@@ -1126,7 +1124,7 @@
     0x02, 0x03, 0x4e, 0xa0, 0x08, 0x22, 0x80, 0xfe, 
 };
 
-static EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME = {
+static struct edge_firmware_version_info IMAGE_VERSION_NAME = {
 	2, 0, 3 };		// Major, Minor, Build
 
 #undef IMAGE_VERSION_NAME
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/io_fw_down3.h linux-2.4.20/drivers/usb/serial/io_fw_down3.h
--- linux-2.4.19/drivers/usb/serial/io_fw_down3.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/io_fw_down3.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,799 @@
+//**************************************************************
+//* Edgeport Binary Image (for TI based products)
+//* Generated by TIBin2C v1.00
+//* Copyright(c) 2001 Inside Out Networks, All rights reserved.
+//**************************************************************
+
+
+static int IMAGE_SIZE = 12166;
+
+struct EDGE_FIRMWARE_VERSION_INFO
+{
+	unsigned char   MajorVersion;
+	unsigned char   MinorVersion;
+	unsigned short  BuildNumber;
+};
+
+static struct EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME =
+{
+	4, 1, 0		// Major, Minor, Build
+
+};
+
+static unsigned char IMAGE_ARRAY_NAME[] = 
+{
+//  struct ImageHdr
+//  {
+//      WORD    Length;
+//      BYTE    CheckSum;
+//  };
+0x83, 0x2f, 
+0x33, 
+
+0x02, 0x24, 0x84, 0x02, 0x1f, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x1a, 0x85, 0x45, 
+0x8c, 0x85, 0x46, 0x8a, 0xc0, 0xe0, 0xc0, 0xd0, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, 
+0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0xe5, 0x44, 
+0x24, 0x08, 0xf8, 0xe6, 0x60, 0x2b, 0xe5, 0x44, 0x24, 0x10, 0xf8, 0xa6, 0x81, 0xe5, 0x44, 0x75, 
+0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, 0x78, 0x92, 0xe5, 0x81, 
+0x04, 0xc3, 0x98, 0xf9, 0x94, 0x22, 0x40, 0x03, 0x02, 0x11, 0x1a, 0xe6, 0xf0, 0x08, 0xa3, 0xd9, 
+0xfa, 0x74, 0x08, 0x25, 0x44, 0xf8, 0x05, 0x44, 0x08, 0xe6, 0x54, 0x80, 0x70, 0x0c, 0xe5, 0x44, 
+0xb4, 0x07, 0xf3, 0x78, 0x08, 0x75, 0x44, 0x00, 0x80, 0xef, 0xe5, 0x44, 0x24, 0x10, 0xf8, 0x86, 
+0x81, 0xe5, 0x44, 0x75, 0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, 
+0x78, 0x92, 0xe5, 0x81, 0x04, 0xc3, 0x98, 0xf9, 0xe0, 0xf6, 0x08, 0xa3, 0xd9, 0xfa, 0xd0, 0x07, 
+0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0x83, 
+0xd0, 0x82, 0xd0, 0xf0, 0xd0, 0xd0, 0xd0, 0xe0, 0x32, 0x30, 0x01, 0x4d, 0x30, 0xb4, 0x48, 0x10, 
+0x00, 0x45, 0x90, 0xff, 0x08, 0xe0, 0x54, 0x20, 0xf8, 0x90, 0xff, 0x48, 0xe0, 0x54, 0x20, 0xf9, 
+0x90, 0xff, 0x10, 0xe0, 0x54, 0x20, 0xfa, 0x90, 0xff, 0x50, 0xe0, 0x54, 0x20, 0xfb, 0x74, 0x00, 
+0xf5, 0x82, 0x74, 0xf8, 0xf5, 0x83, 0xe0, 0xc8, 0xf0, 0x68, 0x60, 0x02, 0x7e, 0x04, 0xa3, 0xe0, 
+0xc9, 0xf0, 0x69, 0x60, 0x02, 0x7e, 0x04, 0xa3, 0xe0, 0xca, 0xf0, 0x6a, 0x60, 0x02, 0x7e, 0x04, 
+0xa3, 0xe0, 0xcb, 0xf0, 0x6b, 0x60, 0x02, 0x7e, 0x04, 0x22, 0xc0, 0xe0, 0xc0, 0xd0, 0xc0, 0xf0, 
+0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 
+0xc0, 0x06, 0xc0, 0x07, 0x90, 0xff, 0x93, 0x74, 0x01, 0xf0, 0xe5, 0x81, 0x94, 0xfd, 0x40, 0x03, 
+0x02, 0x11, 0x1a, 0x85, 0x47, 0x8d, 0x85, 0x48, 0x8b, 0x74, 0xae, 0xf5, 0x82, 0x74, 0xfa, 0xf5, 
+0x83, 0xe0, 0xb4, 0x01, 0x1b, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x4a, 0xe0, 0x30, 0xe7, 0x2c, 
+0x90, 0xff, 0x4e, 0xe0, 0x30, 0xe7, 0x25, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x02, 0xf0, 0x80, 0x20, 
+0xb4, 0x02, 0x1d, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x25, 
+0x13, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x04, 0xd0, 0x83, 0xd0, 0x82, 
+0xa3, 0xe0, 0xb4, 0x01, 0x1b, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x52, 0xe0, 0x30, 0xe7, 0x2c, 
+0x90, 0xff, 0x56, 0xe0, 0x30, 0xe7, 0x25, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x02, 0xf0, 0x80, 0x20, 
+0xb4, 0x02, 0x1d, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x25, 
+0x13, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x04, 0xd0, 0x83, 0xd0, 0x82, 
+0x20, 0x02, 0x03, 0x30, 0x01, 0x7b, 0x74, 0x16, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xe0, 0x14, 
+0xfc, 0xf0, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0x64, 0x04, 0x70, 0x0f, 0xec, 0x70, 0x62, 0x7e, 
+0x01, 0x12, 0x00, 0xc9, 0x7c, 0x0a, 0x7d, 0xfa, 0x02, 0x02, 0x22, 0x12, 0x00, 0xc9, 0xee, 0x64, 
+0x04, 0x60, 0x1d, 0xec, 0x70, 0x4b, 0x7c, 0x0a, 0xed, 0x14, 0xfd, 0x70, 0x15, 0xee, 0x64, 0x02, 
+0x60, 0x07, 0x7e, 0x02, 0x7d, 0x32, 0x02, 0x02, 0x22, 0x7e, 0x01, 0x7d, 0xfa, 0x02, 0x02, 0x22, 
+0x7c, 0x0a, 0x74, 0x16, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0, 0xa3, 
+0xee, 0xf0, 0x14, 0x60, 0x18, 0x20, 0xe1, 0x0f, 0x20, 0x01, 0x06, 0xd2, 0xb1, 0xc2, 0xb0, 0x80, 
+0x10, 0xc2, 0xb1, 0xd2, 0xb0, 0x80, 0x0a, 0xc2, 0xb1, 0xc2, 0xb0, 0x80, 0x04, 0xd2, 0xb0, 0xd2, 
+0xb1, 0x78, 0x19, 0x79, 0x09, 0x7a, 0x07, 0xe7, 0x70, 0x04, 0xa6, 0x00, 0x80, 0x0b, 0xe6, 0x60, 
+0x08, 0x16, 0xe6, 0x70, 0x04, 0xe7, 0x44, 0x80, 0xf7, 0x08, 0x09, 0xda, 0xea, 0xe5, 0x43, 0x60, 
+0x13, 0x14, 0xf5, 0x43, 0x70, 0x0e, 0xe5, 0x44, 0x24, 0x08, 0xf8, 0x76, 0x00, 0x12, 0x10, 0x95, 
+0xd2, 0x8c, 0xd2, 0x8d, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 
+0xd0, 0x01, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0xd0, 0xd0, 0xd0, 0xe0, 0x32, 0x90, 
+0xff, 0x04, 0xe0, 0x90, 0xfa, 0xb5, 0xf0, 0x90, 0xff, 0x06, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, 0xec, 
+0xff, 0xea, 0xfe, 0xef, 0xc3, 0x94, 0x08, 0xee, 0x94, 0x01, 0x50, 0x02, 0x80, 0x04, 0x7e, 0x01, 
+0x7f, 0x08, 0x8e, 0x34, 0x8f, 0x35, 0x90, 0xff, 0x02, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, 0xec, 0xff, 
+0xea, 0x90, 0xfa, 0xb9, 0xf0, 0xef, 0xa3, 0xf0, 0x12, 0x18, 0x49, 0x78, 0x24, 0x7c, 0x00, 0x7d, 
+0x00, 0x12, 0x19, 0x6c, 0x7e, 0x00, 0x7f, 0x05, 0x12, 0x13, 0x8f, 0xe4, 0xf5, 0x53, 0xe5, 0x53, 
+0xc3, 0x94, 0x02, 0x50, 0x0f, 0x12, 0x18, 0x2a, 0xe4, 0x12, 0x13, 0xfb, 0x05, 0x53, 0x04, 0x12, 
+0x18, 0x1b, 0x80, 0xea, 0x12, 0x18, 0x49, 0x90, 0xff, 0x00, 0xe0, 0xff, 0x54, 0x60, 0x24, 0xc0, 
+0x70, 0x03, 0x02, 0x08, 0xb8, 0x24, 0x40, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 
+0xfe, 0x54, 0x0f, 0xf5, 0x53, 0xee, 0x30, 0xe7, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x0a, 0x90, 
+0xff, 0x01, 0xe0, 0x12, 0x15, 0x0f, 0x03, 0x55, 0x00, 0x04, 0x28, 0x01, 0x05, 0x2f, 0x03, 0x05, 
+0xf6, 0x05, 0x06, 0x38, 0x06, 0x07, 0x9a, 0x08, 0x07, 0xe2, 0x09, 0x08, 0x3e, 0x0a, 0x08, 0x7e, 
+0x0b, 0x00, 0x00, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 
+0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x64, 0x02, 0x45, 0x34, 
+0x60, 0x03, 0x02, 0x0e, 0xac, 0xef, 0x54, 0x1f, 0x14, 0x60, 0x2b, 0x14, 0x60, 0x47, 0x24, 0x02, 
+0x60, 0x03, 0x02, 0x0e, 0xac, 0xee, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0x2a, 0x74, 0x01, 
+0x12, 0x13, 0xfb, 0x78, 0x6d, 0xe6, 0x30, 0xe0, 0x08, 0x12, 0x18, 0x2a, 0x74, 0x02, 0x12, 0x13, 
+0xfb, 0x7f, 0x02, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 0x09, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 
+0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0xd3, 0x94, 0x01, 0x40, 0x03, 0x02, 0x0e, 0xac, 
+0x7f, 0x02, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 0x0e, 0x90, 0xfa, 0xb5, 0xe0, 0xff, 0x60, 
+0x07, 0x64, 0x80, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0f, 0x38, 0x40, 0x03, 0x02, 0x0e, 0xac, 
+0xe5, 0x53, 0x70, 0x19, 0x30, 0x0a, 0x0b, 0x90, 0xff, 0x80, 0x12, 0x18, 0x27, 0x12, 0x13, 0xfb, 
+0x80, 0x24, 0x90, 0xff, 0x82, 0x12, 0x18, 0x27, 0x12, 0x13, 0xfb, 0x80, 0x19, 0x15, 0x53, 0x30, 
+0x0a, 0x0b, 0x12, 0x18, 0xbd, 0x12, 0x18, 0x25, 0x12, 0x13, 0xfb, 0x80, 0x09, 0x12, 0x18, 0xcb, 
+0x12, 0x18, 0x25, 0x12, 0x13, 0xfb, 0x12, 0x18, 0x2a, 0x12, 0x13, 0xb5, 0x60, 0x05, 0x74, 0x01, 
+0x12, 0x13, 0xfb, 0x7f, 0x02, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 
+0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x14, 0x60, 0x2d, 0x14, 
+0x60, 0x59, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x04, 0xa3, 
+0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 
+0xac, 0x78, 0x6d, 0xe6, 0x54, 0xfe, 0xf6, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 
+0x06, 0x20, 0xe0, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe0, 0x09, 0x90, 0xfa, 0xb5, 0xe0, 
+0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe1, 0x0c, 0x90, 0xfa, 0xb5, 0xe0, 0xd3, 0x94, 
+0x01, 0x40, 0x03, 0x02, 0x0e, 0xac, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 
+0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0f, 0x38, 0x40, 0x03, 0x02, 0x0e, 0xac, 
+0xe5, 0x2c, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe0, 0x07, 
+0xe5, 0x53, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x53, 0x70, 0x0f, 0x90, 0xff, 0x82, 0xe0, 0x54, 
+0xf7, 0xf0, 0x90, 0xff, 0x80, 0xe0, 0x54, 0xf7, 0xf0, 0x22, 0xe5, 0x53, 0x24, 0xfe, 0x60, 0x1b, 
+0x04, 0x70, 0x2e, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, 0xe4, 0x33, 0xfd, 0x7f, 0x03, 0x12, 0x2a, 0xce, 
+0x80, 0x1f, 0xe4, 0xfd, 0x7f, 0x03, 0x12, 0x2a, 0xce, 0x80, 0x16, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, 
+0xe4, 0x33, 0xfd, 0x7f, 0x04, 0x12, 0x2a, 0xce, 0x80, 0x07, 0xe4, 0xfd, 0x7f, 0x04, 0x12, 0x2a, 
+0xce, 0x15, 0x53, 0x30, 0x0a, 0x0b, 0x12, 0x18, 0xbd, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0x80, 
+0x09, 0x12, 0x18, 0xcb, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 
+0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 
+0x12, 0x18, 0xd9, 0x14, 0x60, 0x2d, 0x14, 0x60, 0x55, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0e, 0xac, 
+0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x04, 0xa3, 0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 
+0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x78, 0x6d, 0xe6, 0x44, 0x01, 0xf6, 0xe4, 0xff, 
+0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 
+0x30, 0xe0, 0x07, 0xe5, 0x53, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe1, 0x0a, 0xe5, 
+0x53, 0xd3, 0x94, 0x01, 0x40, 0x03, 0x02, 0x0e, 0xac, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0x90, 0xfa, 
+0xb9, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0xff, 
+0x12, 0x2f, 0x3b, 0x40, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 
+0x02, 0x0e, 0xac, 0xe5, 0x53, 0x70, 0x09, 0x30, 0x0a, 0x03, 0x02, 0x19, 0x7a, 0x02, 0x19, 0x3e, 
+0xe5, 0x2c, 0x20, 0xe1, 0x03, 0x02, 0x0e, 0xac, 0x15, 0x53, 0x30, 0x0a, 0x0b, 0x12, 0x18, 0xbd, 
+0xf5, 0x83, 0xe0, 0x44, 0x08, 0xf0, 0x80, 0x09, 0x12, 0x18, 0xcb, 0xf5, 0x83, 0xe0, 0x44, 0x08, 
+0xf0, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 
+0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 
+0x12, 0x18, 0xd9, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe1, 0x03, 0x02, 0x0e, 0xac, 
+0x90, 0xfa, 0xba, 0xe0, 0x90, 0xff, 0xff, 0xf0, 0xe0, 0x60, 0x05, 0x43, 0x2c, 0x01, 0x80, 0x03, 
+0x53, 0x2c, 0xfe, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe7, 0x03, 0x02, 0x0e, 0xac, 
+0xe5, 0x35, 0x45, 0x34, 0x70, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x60, 0x03, 0x02, 0x0e, 
+0xac, 0x90, 0xfa, 0xb9, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xec, 0x24, 0xfe, 0x60, 0x3a, 0x14, 0x60, 
+0x75, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xed, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 
+0x49, 0x12, 0x19, 0x73, 0x7d, 0x03, 0x12, 0x0e, 0xf3, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0e, 
+0xb0, 0x90, 0xfa, 0xb2, 0xe0, 0xfd, 0xa3, 0x12, 0x18, 0x93, 0x12, 0x0f, 0x0f, 0x50, 0x02, 0x80, 
+0x04, 0xae, 0x34, 0xaf, 0x35, 0x02, 0x0f, 0x40, 0x12, 0x18, 0x49, 0x90, 0xf9, 0x65, 0xe0, 0x30, 
+0xe4, 0x0d, 0x12, 0x19, 0x73, 0x7d, 0x14, 0x12, 0x0e, 0xf3, 0x60, 0x10, 0x02, 0x0e, 0xac, 0x12, 
+0x19, 0x73, 0x7d, 0x04, 0x12, 0x0f, 0x47, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0e, 0xb0, 0x90, 
+0xfa, 0xb2, 0xe0, 0xfd, 0xa3, 0x12, 0x18, 0x93, 0x12, 0x0f, 0x0f, 0x50, 0x02, 0x80, 0x04, 0xae, 
+0x34, 0xaf, 0x35, 0x02, 0x0f, 0x40, 0x12, 0x19, 0x73, 0x7d, 0x05, 0x12, 0x0f, 0x47, 0x60, 0x03, 
+0x02, 0x0e, 0xac, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb2, 0x12, 0x18, 0x90, 0x7d, 0x01, 0x12, 0x23, 
+0xee, 0x90, 0xfa, 0xb3, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x14, 0x2f, 0x90, 0xfa, 0xba, 0xe0, 0x90, 
+0xfa, 0xb1, 0xf0, 0xe4, 0xf5, 0x52, 0x90, 0xfa, 0xb1, 0xe0, 0xff, 0xe5, 0x52, 0xc3, 0x9f, 0x50, 
+0x24, 0x12, 0x18, 0x8a, 0x12, 0x0f, 0x52, 0xff, 0xfd, 0x90, 0xfa, 0xb3, 0xe4, 0x8d, 0xf0, 0x12, 
+0x14, 0x2f, 0x90, 0xfa, 0xb2, 0xe0, 0xc3, 0x9f, 0xf0, 0xd3, 0x94, 0x00, 0x50, 0x03, 0x02, 0x0e, 
+0xac, 0x05, 0x52, 0x80, 0xd1, 0x12, 0x18, 0x8a, 0x12, 0x0f, 0x52, 0x24, 0xfe, 0xff, 0x90, 0xfa, 
+0xb2, 0xf0, 0xfd, 0xa3, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x14, 0x2f, 0x7a, 0xf9, 0x79, 0x6e, 0x7b, 
+0x01, 0x8b, 0x2d, 0x8a, 0x2e, 0x89, 0x2f, 0xe9, 0x24, 0x02, 0xf9, 0xe4, 0x3a, 0xfa, 0x12, 0x18, 
+0x90, 0x12, 0x23, 0xee, 0x8f, 0x52, 0x05, 0x52, 0x05, 0x52, 0x12, 0x18, 0x2a, 0xe5, 0x52, 0x12, 
+0x13, 0xfb, 0x12, 0x18, 0x2a, 0x90, 0x00, 0x01, 0x74, 0x03, 0x12, 0x14, 0x0d, 0xaf, 0x52, 0x7e, 
+0x00, 0xc3, 0xef, 0x95, 0x35, 0xee, 0x95, 0x34, 0x50, 0x02, 0x80, 0x04, 0xae, 0x34, 0xaf, 0x35, 
+0x8e, 0x30, 0x8f, 0x31, 0x02, 0x29, 0x2d, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe7, 0x03, 0x02, 
+0x0e, 0xac, 0xe5, 0x35, 0x64, 0x01, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 
+0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 
+0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe0, 0x06, 
+0x20, 0xe1, 0x03, 0x02, 0x0e, 0xac, 0x75, 0x2d, 0x00, 0x75, 0x2e, 0x00, 0x75, 0x2f, 0x29, 0x02, 
+0x0f, 0x2f, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 
+0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xd3, 0x90, 0xfa, 0xba, 
+0xe0, 0x94, 0x01, 0x90, 0xfa, 0xb9, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 
+0xd9, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe0, 0x06, 0x20, 0xe1, 0x03, 0x02, 0x0e, 
+0xac, 0x90, 0xfa, 0xba, 0xe0, 0xf5, 0x29, 0xe5, 0x29, 0x70, 0x08, 0x43, 0x2c, 0x01, 0x53, 0x2c, 
+0xfd, 0x80, 0x06, 0x53, 0x2c, 0xfe, 0x43, 0x2c, 0x02, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 
+0x20, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x64, 0x01, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 
+0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x02, 
+0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 
+0xac, 0xe5, 0x2c, 0x20, 0xe1, 0x03, 0x02, 0x0e, 0xac, 0x7f, 0x01, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 
+0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xd3, 
+0x90, 0xfa, 0xba, 0xe0, 0x94, 0x00, 0x90, 0xfa, 0xb9, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0e, 
+0xac, 0x12, 0x18, 0xd9, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe1, 0x03, 
+0x02, 0x0e, 0xac, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0x90, 0xff, 0x01, 0x12, 0x19, 0x8a, 0xef, 0x12, 
+0x13, 0xfb, 0x90, 0xfa, 0xb5, 0x12, 0x19, 0x8a, 0x90, 0x00, 0x01, 0xef, 0x12, 0x14, 0x0d, 0x90, 
+0x00, 0x02, 0xe4, 0x12, 0x14, 0x0d, 0x74, 0x03, 0x12, 0x18, 0x1b, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 
+0xa3, 0xe0, 0x85, 0x2f, 0x82, 0x85, 0x2e, 0x83, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0xff, 0x01, 
+0xe0, 0x12, 0x15, 0x0f, 0x09, 0x3d, 0x02, 0x09, 0x5f, 0x04, 0x09, 0x81, 0x05, 0x09, 0xad, 0x06, 
+0x09, 0xcb, 0x07, 0x09, 0xe9, 0x08, 0x0a, 0x07, 0x09, 0x0a, 0x25, 0x0b, 0x0a, 0xda, 0x80, 0x0c, 
+0xfa, 0x81, 0x0d, 0x1c, 0x82, 0x0b, 0x21, 0x83, 0x0b, 0x6a, 0x84, 0x0b, 0x89, 0x85, 0x0b, 0xc5, 
+0x86, 0x0c, 0x07, 0x87, 0x0c, 0x95, 0x88, 0x0c, 0xd0, 0x89, 0x0a, 0x43, 0x92, 0x0a, 0x43, 0x93, 
+0x0d, 0xcf, 0xc0, 0x0e, 0x00, 0xc1, 0x0e, 0x11, 0xc2, 0x00, 0x00, 0x0e, 0x9b, 0xe5, 0x2c, 0x20, 
+0xe7, 0x05, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 
+0xfd, 0x7c, 0x00, 0x7f, 0x07, 0x02, 0x10, 0x9c, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2c, 0xc0, 0xe5, 
+0x2c, 0x20, 0xe7, 0x05, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 
+0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0c, 0x02, 0x10, 0x9c, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2c, 
+0xc0, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 0x19, 0x99, 0x50, 0x06, 0xe5, 0x35, 
+0x45, 0x34, 0x70, 0x05, 0x7f, 0x02, 0x02, 0x2e, 0xa5, 0x90, 0xfa, 0xb5, 0xe0, 0x24, 0xfe, 0x24, 
+0xfd, 0x50, 0x02, 0x80, 0x03, 0x02, 0x2f, 0x28, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 
+0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 
+0x00, 0x7f, 0x08, 0x02, 0x10, 0x9c, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 
+0x02, 0x0e, 0xaf, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 
+0x09, 0x02, 0x10, 0x9c, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 
+0xaf, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0a, 0x02, 
+0x10, 0x9c, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 
+0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0b, 0x02, 0x10, 0x9c, 
+0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 0x18, 0xe0, 
+0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0e, 0x02, 0x10, 0x9c, 0x7f, 0x07, 
+0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x56, 0x12, 0x18, 0xd9, 0x70, 0x4a, 0x90, 0xff, 0x02, 
+0xe0, 0xf5, 0x52, 0xe5, 0x52, 0xb4, 0x82, 0x05, 0x75, 0x52, 0x61, 0x80, 0x12, 0xe5, 0x52, 0xb4, 
+0x83, 0x05, 0x75, 0x52, 0x62, 0x80, 0x08, 0xe5, 0x52, 0xc4, 0x54, 0xf0, 0x04, 0xf5, 0x52, 0x12, 
+0x17, 0x8b, 0x12, 0x19, 0x6c, 0x12, 0x22, 0xb8, 0x12, 0x18, 0xe8, 0x12, 0x13, 0xce, 0x60, 0x05, 
+0x12, 0x2f, 0x76, 0x80, 0x06, 0x85, 0x2a, 0x30, 0x85, 0x2b, 0x31, 0x75, 0x2d, 0x01, 0x75, 0x2e, 
+0xf9, 0x75, 0x2f, 0x71, 0x02, 0x29, 0x2d, 0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2c, 0xc0, 0x12, 0x18, 
+0xd9, 0x60, 0x05, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x19, 0x99, 0x40, 0x05, 0x7f, 0x03, 0x02, 
+0x2e, 0xa5, 0x90, 0xff, 0x02, 0xe0, 0xf5, 0x52, 0xe5, 0x52, 0xb4, 0x82, 0x05, 0x75, 0x52, 0x61, 
+0x80, 0x12, 0xe5, 0x52, 0xb4, 0x83, 0x05, 0x75, 0x52, 0x62, 0x80, 0x08, 0xe5, 0x52, 0xc4, 0x54, 
+0xf0, 0x04, 0xf5, 0x52, 0x12, 0x17, 0x8b, 0x02, 0x2f, 0x28, 0x12, 0x19, 0xa3, 0x12, 0x27, 0x19, 
+0x12, 0x18, 0x9b, 0xe0, 0x54, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x78, 
+0x6e, 0x12, 0x14, 0xeb, 0x90, 0x00, 0x02, 0x12, 0x13, 0xce, 0x30, 0xe7, 0xf2, 0x90, 0x00, 0x02, 
+0xe4, 0x12, 0x14, 0x0d, 0x90, 0xfa, 0xb6, 0xe0, 0x44, 0x80, 0xff, 0xf0, 0x78, 0x82, 0xe6, 0xfc, 
+0x08, 0xe6, 0x8c, 0x83, 0x12, 0x18, 0xa3, 0xef, 0xf0, 0x12, 0x2f, 0x80, 0xe4, 0xff, 0x02, 0x2e, 
+0xa5, 0x90, 0xfa, 0xb5, 0xe0, 0x64, 0x01, 0x70, 0x1f, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x7e, 0x00, 
+0x70, 0x06, 0xa3, 0xe0, 0xf5, 0x90, 0x80, 0x2d, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0x90, 0x90, 0xfa, 
+0xba, 0xe0, 0x42, 0x90, 0xd2, 0xaf, 0x80, 0x1d, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x7e, 0x00, 0x70, 
+0x06, 0xa3, 0xe0, 0xf5, 0xb0, 0x80, 0x0e, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0xb0, 0x90, 0xfa, 0xba, 
+0xe0, 0x42, 0xb0, 0xd2, 0xaf, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0x49, 0x90, 0xfa, 0xb5, 
+0xe0, 0xb4, 0x01, 0x0a, 0x12, 0x18, 0x2a, 0xe5, 0x90, 0x12, 0x13, 0xfb, 0x80, 0x08, 0x12, 0x18, 
+0x2a, 0xe5, 0xb0, 0x12, 0x13, 0xfb, 0x02, 0x0f, 0x2f, 0x90, 0xf9, 0x65, 0xe0, 0x20, 0xe1, 0x30, 
+0x12, 0x18, 0x53, 0x60, 0x18, 0x04, 0x70, 0x28, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x09, 0x90, 0xff, 
+0xa4, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x19, 0x12, 0x19, 0xad, 0xf0, 0x80, 0x13, 0x90, 0xfa, 0xb6, 
+0xe0, 0x60, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x04, 0x12, 0x19, 0xb4, 0xf0, 
+0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x90, 0xf9, 0x65, 0xe0, 0x20, 0xe1, 0x36, 0x12, 0x18, 0x53, 0x60, 
+0x1b, 0x04, 0x70, 0x2e, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20, 
+0xf0, 0x80, 0x1f, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x16, 0x90, 0xfa, 0xb6, 0xe0, 
+0x60, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54, 
+0xdf, 0xf0, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0x53, 0x60, 0x46, 0x04, 0x60, 0x03, 0x02, 
+0x0c, 0x90, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x17, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x04, 0xf0, 0x90, 
+0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x6a, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x61, 0x90, 
+0xff, 0xa4, 0xe0, 0x54, 0xfb, 0xf0, 0x90, 0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x53, 0x30, 0x95, 0x09, 
+0x90, 0xff, 0xa4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x47, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfd, 0xf0, 
+0x80, 0x3e, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x17, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x04, 0xf0, 0x90, 
+0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x2a, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x21, 0x90, 
+0xff, 0xb4, 0xe0, 0x54, 0xfb, 0xf0, 0x90, 0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x13, 0x30, 0x93, 0x09, 
+0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xfd, 0xf0, 
+0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0x53, 0x60, 0x1b, 0x04, 0x70, 0x2e, 0x90, 0xfa, 0xb6, 
+0xe0, 0x60, 0x09, 0x90, 0xff, 0xa2, 0xe0, 0x44, 0x40, 0xf0, 0x80, 0x1f, 0x90, 0xff, 0xa2, 0xe0, 
+0x54, 0xbf, 0xf0, 0x80, 0x16, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xb2, 0xe0, 0x44, 
+0x40, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb2, 0xe0, 0x54, 0xbf, 0xf0, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 
+0x12, 0x18, 0x49, 0x12, 0x18, 0x5b, 0x60, 0x0f, 0x04, 0x70, 0x16, 0x90, 0xff, 0xa4, 0xe0, 0x12, 
+0x18, 0x2a, 0x12, 0x13, 0xfb, 0x80, 0x0a, 0x90, 0xff, 0xb4, 0xe0, 0x12, 0x18, 0x2a, 0x12, 0x13, 
+0xfb, 0x75, 0x30, 0x00, 0x75, 0x31, 0x01, 0x02, 0x29, 0x2d, 0xe4, 0xff, 0x12, 0x2e, 0xa5, 0x12, 
+0x19, 0x46, 0x7f, 0x03, 0x12, 0x11, 0x9f, 0x90, 0xff, 0xfc, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0xff, 
+0x7e, 0x00, 0x12, 0x2d, 0xee, 0xc2, 0x90, 0xc2, 0xaf, 0x00, 0x80, 0xfd, 0xe4, 0xf5, 0x54, 0xf5, 
+0x55, 0x90, 0xfa, 0xbb, 0x74, 0x3e, 0xf0, 0xa3, 0xe4, 0xf0, 0x90, 0xfa, 0xb3, 0xf0, 0xa3, 0x74, 
+0x15, 0xf0, 0xe0, 0x54, 0x3f, 0xff, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0xfa, 0xb8, 0xf0, 0xd3, 0x94, 
+0x00, 0xe4, 0x94, 0x3e, 0x40, 0x08, 0x90, 0xfa, 0xbc, 0xe0, 0x90, 0xfa, 0xb8, 0xf0, 0x12, 0x0e, 
+0xd6, 0xe5, 0x23, 0x45, 0x22, 0x70, 0x73, 0x12, 0x18, 0x62, 0x90, 0xfa, 0xbb, 0x12, 0x19, 0x65, 
+0x60, 0x27, 0xd3, 0xef, 0x94, 0x40, 0xee, 0x94, 0x00, 0x40, 0x08, 0x90, 0xfa, 0xb8, 0x74, 0x40, 
+0xf0, 0x80, 0x08, 0x90, 0xfa, 0xbc, 0xe0, 0x90, 0xfa, 0xb8, 0xf0, 0x12, 0x0e, 0xd6, 0xe5, 0x23, 
+0x45, 0x22, 0x70, 0x46, 0x12, 0x18, 0x62, 0x80, 0xd1, 0x75, 0x52, 0x02, 0x90, 0xfa, 0xbb, 0xe4, 
+0xf0, 0xa3, 0x04, 0xf0, 0x90, 0xfa, 0xb3, 0xe4, 0xf0, 0xa3, 0x74, 0x0f, 0xf0, 0x7b, 0x00, 0x7a, 
+0x00, 0x79, 0x52, 0x90, 0xfa, 0xbc, 0xe0, 0xf5, 0x50, 0x7d, 0x0f, 0x7c, 0x00, 0x12, 0x26, 0x25, 
+0x75, 0x22, 0x00, 0x8f, 0x23, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x52, 0xe4, 0xf5, 0x40, 0xf5, 0x41, 
+0x7d, 0x01, 0x12, 0x23, 0xee, 0xe4, 0xf5, 0x22, 0xf5, 0x23, 0xaf, 0x23, 0x02, 0x2e, 0xa5, 0x90, 
+0xfa, 0xba, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x30, 0xe7, 0x10, 0xe0, 0x54, 0x0f, 0x90, 0xf9, 0x62, 
+0xf0, 0xd3, 0x94, 0x00, 0x40, 0x15, 0xc2, 0x95, 0x80, 0x11, 0x90, 0xfa, 0xb6, 0xe0, 0x54, 0x0f, 
+0x90, 0xf9, 0x61, 0xf0, 0xd3, 0x94, 0x00, 0x40, 0x02, 0xc2, 0x94, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 
+0x12, 0x19, 0xa3, 0xbf, 0x01, 0x04, 0xd2, 0x93, 0x80, 0x02, 0xc2, 0x93, 0xe4, 0xff, 0x02, 0x2e, 
+0xa5, 0x90, 0xfa, 0xba, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x54, 0x03, 0x14, 0x60, 0x0a, 0x14, 0x60, 
+0x0f, 0x14, 0x60, 0x08, 0x24, 0x03, 0x70, 0x2b, 0xd2, 0x91, 0x80, 0x27, 0xc2, 0x91, 0x80, 0x23, 
+0x12, 0x19, 0xad, 0x12, 0x0e, 0xfe, 0x60, 0x04, 0xd2, 0x91, 0x80, 0x17, 0x90, 0xff, 0xa4, 0xe0, 
+0x44, 0x10, 0x12, 0x0e, 0xfe, 0xff, 0xbf, 0xa0, 0x04, 0xc2, 0x91, 0x80, 0x02, 0xd2, 0x91, 0x12, 
+0x19, 0xad, 0xf0, 0x90, 0xfa, 0xb6, 0xe0, 0x54, 0x0c, 0xff, 0x13, 0x13, 0x54, 0x3f, 0x14, 0x60, 
+0x0a, 0x14, 0x60, 0x0f, 0x14, 0x60, 0x08, 0x24, 0x03, 0x70, 0x2b, 0xd2, 0x92, 0x80, 0x27, 0xc2, 
+0x92, 0x80, 0x23, 0x12, 0x19, 0xb4, 0x12, 0x0f, 0x1e, 0x60, 0x04, 0xd2, 0x92, 0x80, 0x17, 0x90, 
+0xff, 0xb4, 0xe0, 0x44, 0x10, 0x12, 0x0f, 0x1e, 0xff, 0xbf, 0xa0, 0x04, 0xc2, 0x92, 0x80, 0x02, 
+0xd2, 0x92, 0x12, 0x19, 0xb4, 0xf0, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x07, 
+0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2c, 0xc0, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x2f, 0x76, 0x22, 
+0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb2, 0x90, 0xfa, 0xb3, 0xe0, 0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x41, 
+0x7d, 0x01, 0x12, 0x23, 0xee, 0x90, 0xfa, 0xb3, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x14, 0x2f, 0xab, 
+0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 0x22, 0xaa, 0x54, 0xa9, 0x55, 0x7b, 0xff, 0x90, 0xfa, 0xb3, 0xe0, 
+0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, 0xb8, 0xe0, 0xf5, 0x50, 0x12, 0x26, 0x25, 0x75, 0x22, 0x00, 
+0x8f, 0x23, 0x22, 0x12, 0x20, 0xc5, 0x7e, 0x00, 0x8e, 0x22, 0x8f, 0x23, 0xef, 0x22, 0xf0, 0x7f, 
+0x01, 0x12, 0x11, 0x9f, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, 0xb7, 0xf0, 0x54, 0xa0, 0x22, 0x12, 
+0x23, 0xee, 0x8f, 0x52, 0x7e, 0x00, 0xc3, 0xef, 0x95, 0x35, 0xee, 0x95, 0x34, 0x22, 0xf0, 0x7f, 
+0x01, 0x12, 0x11, 0x9f, 0x90, 0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xb7, 0xf0, 0x54, 0xa0, 0x22, 0x75, 
+0x30, 0x00, 0x75, 0x31, 0x01, 0x02, 0x29, 0x2d, 0x90, 0xfa, 0xb5, 0xe0, 0xff, 0x02, 0x2f, 0x3b, 
+0x8e, 0x30, 0x8f, 0x31, 0x02, 0x29, 0x2d, 0x12, 0x20, 0xc5, 0x7e, 0x00, 0x8e, 0x22, 0x8f, 0x23, 
+0xef, 0x22, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x90, 0xfa, 0xb0, 0xe0, 0x22, 0xef, 0x90, 0xf8, 0x04, 
+0xf0, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0xee, 0x60, 0x0a, 0xc0, 0x05, 0x7d, 0x7f, 0xdd, 0xfe, 0xde, 
+0xfa, 0xd0, 0x05, 0xef, 0xc3, 0x94, 0x15, 0x50, 0x03, 0xd0, 0xa8, 0x22, 0x13, 0x70, 0x03, 0xd0, 
+0xa8, 0x22, 0xff, 0xd5, 0x07, 0xfd, 0xd0, 0xa8, 0x22, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 
+0x04, 0xc0, 0x05, 0xe5, 0x44, 0x24, 0x08, 0xf8, 0x86, 0x05, 0x53, 0x05, 0x7f, 0x7c, 0xff, 0x12, 
+0x0f, 0xfe, 0x7f, 0x00, 0x7e, 0x00, 0xe5, 0x49, 0x60, 0x46, 0xfc, 0x90, 0xf9, 0x19, 0xe0, 0x54, 
+0x7f, 0x6d, 0x70, 0x0f, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xa3, 0x15, 
+0x49, 0x80, 0x07, 0xa3, 0xa3, 0xa3, 0xdc, 0xe6, 0x80, 0x26, 0xdc, 0x06, 0xd0, 0x82, 0xd0, 0x83, 
+0x80, 0x1e, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, 
+0xa3, 0xe9, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, 
+0x12, 0x10, 0x95, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0x22, 0x85, 0xa8, 
+0x4a, 0x75, 0xa8, 0x88, 0xec, 0x70, 0x02, 0x7c, 0x3f, 0x8c, 0x43, 0x22, 0xe5, 0x44, 0x24, 0x08, 
+0xf8, 0x76, 0x00, 0x12, 0x10, 0xec, 0x80, 0xfb, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x04, 
+0xc0, 0x06, 0x7c, 0xff, 0x12, 0x0f, 0xfe, 0xe5, 0x49, 0x60, 0x42, 0xfe, 0x90, 0xf9, 0x19, 0xe0, 
+0x54, 0x7f, 0x6f, 0x70, 0x0b, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x15, 0x49, 0x80, 0x07, 
+0xa3, 0xa3, 0xa3, 0xde, 0xea, 0x80, 0x26, 0xde, 0x06, 0xd0, 0x82, 0xd0, 0x83, 0x80, 0xd8, 0xe0, 
+0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, 0xa3, 0xe9, 0xf0, 
+0xa3, 0xea, 0xf0, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, 0x78, 0x08, 0x08, 
+0x79, 0x18, 0x09, 0x7c, 0x01, 0xe6, 0x54, 0x7f, 0x6f, 0x70, 0x06, 0x76, 0x00, 0x77, 0x00, 0x80, 
+0x06, 0x08, 0x09, 0x0c, 0xbc, 0x08, 0xee, 0x12, 0x10, 0x95, 0xd0, 0x06, 0xd0, 0x04, 0xd0, 0x02, 
+0xd0, 0x01, 0xd0, 0x00, 0x22, 0x75, 0x43, 0x00, 0x85, 0x4a, 0xa8, 0x22, 0xc0, 0xf0, 0xc0, 0x82, 
+0xc0, 0x83, 0xc3, 0xe5, 0x49, 0x24, 0xe8, 0x50, 0x05, 0x12, 0x10, 0xec, 0x80, 0xf4, 0xef, 0x60, 
+0x31, 0x90, 0x2e, 0x2c, 0xe4, 0x93, 0xc3, 0x9f, 0x40, 0x2f, 0xc0, 0x04, 0x7c, 0xff, 0x12, 0x0f, 
+0xfe, 0xd0, 0x04, 0x43, 0x07, 0x80, 0xe5, 0x49, 0x75, 0xf0, 0x03, 0xa4, 0x24, 0x19, 0xf5, 0x82, 
+0xe4, 0x34, 0xf9, 0xf5, 0x83, 0xef, 0xf0, 0xec, 0xa3, 0xf0, 0xed, 0xa3, 0xf0, 0x05, 0x49, 0x12, 
+0x10, 0x95, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0x22, 0x02, 0x11, 0x1a, 0xc0, 0x04, 0x7c, 0x20, 
+0xd2, 0x8c, 0xd2, 0x8d, 0xd5, 0x04, 0xfd, 0xd0, 0x04, 0x22, 0x75, 0xa8, 0x00, 0x75, 0x88, 0x00, 
+0x75, 0xb8, 0x00, 0x75, 0xf0, 0x00, 0x75, 0xd0, 0x00, 0xe4, 0xf8, 0x90, 0xf8, 0x04, 0xf0, 0x90, 
+0x00, 0x00, 0xf6, 0x08, 0xb8, 0x00, 0xfb, 0x02, 0x00, 0x00, 0xc2, 0xaf, 0xe4, 0x90, 0xff, 0x48, 
+0xf0, 0x90, 0xff, 0x50, 0xf0, 0x90, 0xff, 0x08, 0xf0, 0x90, 0xff, 0x10, 0xf0, 0x90, 0xff, 0x80, 
+0xf0, 0xa3, 0xa3, 0xf0, 0xd2, 0xb1, 0xc2, 0xb0, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, 
+0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0xd2, 0xb0, 0xd2, 
+0xb1, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, 
+0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x80, 0xcc, 0xc3, 0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x03, 
+0x7f, 0xe8, 0xef, 0xf4, 0xff, 0xee, 0xf4, 0xfe, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x48, 0x8e, 
+0x47, 0x22, 0xc3, 0xef, 0x94, 0xbc, 0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x07, 0x7f, 0xd0, 0xef, 
+0xf4, 0xff, 0xee, 0xf4, 0xfe, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x46, 0x8e, 0x45, 0x22, 0xef, 
+0x70, 0x01, 0x22, 0xc0, 0x00, 0xe5, 0x44, 0x24, 0x18, 0xf8, 0xa6, 0x07, 0xe5, 0x44, 0x24, 0x08, 
+0xf8, 0xc6, 0x54, 0x7f, 0xf6, 0xe6, 0x30, 0xe7, 0x03, 0xd0, 0x00, 0x22, 0x12, 0x10, 0xec, 0x80, 
+0xf4, 0xc0, 0x00, 0x7f, 0x01, 0xef, 0x24, 0x08, 0xf8, 0xe6, 0x60, 0x09, 0x0f, 0xbf, 0x08, 0xf5, 
+0x12, 0x10, 0xec, 0x80, 0xee, 0xd0, 0x00, 0x22, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, 
+0xc0, 0x06, 0xc0, 0x04, 0xed, 0x24, 0x10, 0xf8, 0x76, 0xa0, 0xed, 0x75, 0xf0, 0x21, 0xa4, 0x24, 
+0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, 0xc0, 0x82, 0xc0, 0x83, 0xa3, 0xa3, 0xe4, 0x78, 
+0x0d, 0xf0, 0xa3, 0xd8, 0xfc, 0xef, 0x54, 0x7f, 0x75, 0xf0, 0x02, 0xa4, 0x24, 0x0e, 0xf5, 0x82, 
+0xe5, 0xf0, 0x34, 0x2e, 0xf5, 0x83, 0xe4, 0x93, 0xfe, 0x74, 0x01, 0x93, 0xfc, 0xd0, 0x83, 0xd0, 
+0x82, 0xec, 0xf0, 0xa3, 0xee, 0xf0, 0xed, 0x24, 0x08, 0xf8, 0xef, 0x44, 0x80, 0xf6, 0xd0, 0x04, 
+0xd0, 0x06, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0x22, 0x75, 0x44, 0x00, 0x75, 0x49, 
+0x00, 0x7a, 0x08, 0x79, 0x18, 0x78, 0x08, 0x76, 0x00, 0x77, 0x00, 0x08, 0x09, 0xda, 0xf8, 0x90, 
+0xf8, 0x04, 0xe0, 0xfc, 0x90, 0x2e, 0x2c, 0xe4, 0x93, 0xc3, 0x9c, 0x50, 0x05, 0xe4, 0x90, 0xf8, 
+0x04, 0xf0, 0x78, 0x08, 0x74, 0x80, 0x44, 0x7f, 0xf6, 0x74, 0x01, 0x44, 0x10, 0xf5, 0x89, 0x75, 
+0xb8, 0x00, 0xd2, 0xab, 0xd2, 0xa9, 0x22, 0x75, 0x81, 0x91, 0xd2, 0x8e, 0xd2, 0x8c, 0xd2, 0xaf, 
+0xe5, 0x49, 0x60, 0x36, 0xff, 0x90, 0xf9, 0x19, 0xe0, 0x54, 0x80, 0x60, 0x28, 0x78, 0x08, 0x79, 
+0x08, 0xe0, 0x54, 0x7f, 0xfa, 0x7b, 0x00, 0xe6, 0x54, 0x7f, 0xb5, 0x02, 0x02, 0x7b, 0xff, 0x08, 
+0xd9, 0xf5, 0xeb, 0x70, 0x10, 0xea, 0xf0, 0xc0, 0x07, 0x12, 0x11, 0xc1, 0xad, 0x07, 0xaf, 0x02, 
+0x12, 0x11, 0xd8, 0xd0, 0x07, 0xa3, 0xa3, 0xa3, 0xdf, 0xce, 0x12, 0x10, 0xec, 0x80, 0xc1, 0xe7, 
+0x09, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x46, 0xe7, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x3e, 0x88, 
+0x82, 0x8c, 0x83, 0xe7, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x32, 0xe3, 0x09, 0xf6, 0x08, 0xdf, 
+0xfa, 0x80, 0x78, 0xe3, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x70, 0x88, 0x82, 0x8c, 0x83, 0xe3, 
+0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x64, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf6, 0x08, 0xdf, 
+0xfa, 0x80, 0x58, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x4c, 0x80, 
+0xd2, 0x80, 0xfa, 0x80, 0xc6, 0x80, 0xd4, 0x80, 0x69, 0x80, 0xf2, 0x80, 0x33, 0x80, 0x10, 0x80, 
+0xa6, 0x80, 0xea, 0x80, 0x9a, 0x80, 0xa8, 0x80, 0xda, 0x80, 0xe2, 0x80, 0xca, 0x80, 0x33, 0x89, 
+0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 
+0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0x0d, 
+0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf6, 0x08, 0xdf, 0xf9, 0xec, 0xfa, 0xa9, 0xf0, 0xed, 
+0xfb, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 
+0x83, 0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xea, 0xde, 0xe8, 
+0x80, 0xdb, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf2, 0x08, 0xdf, 0xf9, 0x80, 0xcc, 0x88, 
+0xf0, 0xef, 0x60, 0x01, 0x0e, 0x4e, 0x60, 0xc3, 0x88, 0xf0, 0xed, 0x24, 0x02, 0xb4, 0x04, 0x00, 
+0x50, 0xb9, 0xf5, 0x82, 0xeb, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xaf, 0x23, 0x23, 0x45, 0x82, 
+0x23, 0x90, 0x13, 0x0f, 0x73, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 
+0xe7, 0x22, 0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 
+0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9, 
+0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82, 
+0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 
+0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xf8, 0xbb, 0x01, 
+0x0d, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0, 0x22, 0x50, 0x06, 
+0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x22, 0xbb, 0xfe, 0x05, 0xe9, 0x25, 0x82, 0xc8, 0xf2, 0x22, 0xc5, 
+0xf0, 0xf8, 0xa3, 0xe0, 0x28, 0xf0, 0xc5, 0xf0, 0xf8, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 
+0x83, 0xe0, 0x38, 0xf0, 0x22, 0xa3, 0xf8, 0xe0, 0xc5, 0xf0, 0x25, 0xf0, 0xf0, 0xe5, 0x82, 0x15, 
+0x82, 0x70, 0x02, 0x15, 0x83, 0xe0, 0xc8, 0x38, 0xf0, 0xe8, 0x22, 0xbb, 0x01, 0x10, 0xe5, 0x82, 
+0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0, 0xa3, 0xe0, 0x22, 0x50, 0x09, 
+0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe, 0x0a, 0xe9, 0x25, 0x82, 0xf8, 
+0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83, 0xe9, 0x93, 0xf5, 0xf0, 0xa3, 
+0xe9, 0x93, 0x22, 0xbb, 0x01, 0x0a, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0xe5, 0xf0, 0xa3, 0xf0, 0x22, 
+0x50, 0x06, 0xf7, 0x09, 0xa7, 0xf0, 0x19, 0x22, 0xbb, 0xfe, 0x06, 0xf3, 0xe5, 0xf0, 0x09, 0xf3, 
+0x19, 0x22, 0xf8, 0xbb, 0x01, 0x11, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 
+0xe8, 0xf0, 0xe5, 0xf0, 0xa3, 0xf0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x08, 0xa6, 
+0xf0, 0x22, 0xbb, 0xfe, 0x09, 0xe9, 0x25, 0x82, 0xc8, 0xf2, 0xe5, 0xf0, 0x08, 0xf2, 0x22, 0xa4, 
+0x25, 0x82, 0xf5, 0x82, 0xe5, 0xf0, 0x35, 0x83, 0xf5, 0x83, 0x22, 0xe6, 0xfb, 0x08, 0xe6, 0xfa, 
+0x08, 0xe6, 0xf9, 0x22, 0xeb, 0xf6, 0x08, 0xea, 0xf6, 0x08, 0xe9, 0xf6, 0x22, 0xe0, 0xfb, 0xa3, 
+0xe0, 0xfa, 0xa3, 0xe0, 0xf9, 0x22, 0xeb, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xe9, 0xf0, 0x22, 0xd0, 
+0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 
+0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 
+0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0x90, 0xff, 0xfa, 0x74, 0x08, 0xf0, 0xa3, 0x74, 0x16, 0xf0, 0x90, 
+0xff, 0xf9, 0x74, 0x02, 0xf0, 0x90, 0xfa, 0xcb, 0xe4, 0xf0, 0xa3, 0x74, 0x0b, 0xf0, 0x7b, 0x00, 
+0x7a, 0x00, 0x79, 0x37, 0x75, 0x40, 0x00, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0xe5, 0x37, 
+0x24, 0x80, 0x90, 0xff, 0xf8, 0xf0, 0xe5, 0x37, 0x64, 0x07, 0x60, 0x0b, 0xe5, 0x37, 0x64, 0x06, 
+0x60, 0x05, 0xe5, 0x37, 0xb4, 0x14, 0x1b, 0xd2, 0x94, 0xd2, 0x95, 0xd2, 0x92, 0xd2, 0x93, 0xe5, 
+0x37, 0xb4, 0x07, 0x08, 0x90, 0xf9, 0x65, 0x74, 0x02, 0xf0, 0x80, 0x06, 0x90, 0xf9, 0x65, 0x74, 
+0x01, 0xf0, 0x90, 0xfa, 0xcb, 0xe4, 0xf0, 0xa3, 0x74, 0x0d, 0xf0, 0x12, 0x17, 0x71, 0x90, 0xff, 
+0xf5, 0xe5, 0x37, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcb, 0xe4, 0xfd, 0x12, 0x20, 0xc5, 0x90, 
+0xfa, 0xcb, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x14, 0x2f, 0x12, 0x17, 0x71, 0xe5, 0x37, 0x30, 0xe7, 
+0x02, 0xd2, 0x02, 0xe4, 0xf5, 0x2c, 0xf5, 0x2a, 0xf5, 0x2b, 0xf5, 0x29, 0x12, 0x19, 0x92, 0x12, 
+0x18, 0x49, 0x12, 0x19, 0x6c, 0x90, 0xf9, 0x66, 0x12, 0x15, 0x06, 0x90, 0xf9, 0x6b, 0x12, 0x15, 
+0x06, 0x90, 0xff, 0xff, 0xe4, 0xf0, 0x90, 0xff, 0x83, 0xe0, 0xe4, 0xf0, 0x90, 0xff, 0x81, 0x74, 
+0x80, 0xf0, 0xa3, 0x74, 0x84, 0xf0, 0x90, 0xff, 0x80, 0xf0, 0xe4, 0xf5, 0x37, 0xe5, 0x37, 0x12, 
+0x18, 0xbf, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x37, 0x12, 0x18, 0xcd, 0xf5, 0x83, 0xe4, 0xf0, 0x05, 
+0x37, 0xe5, 0x37, 0xb4, 0x07, 0xe7, 0x78, 0x80, 0x76, 0xfe, 0x08, 0x76, 0xf0, 0x90, 0x2f, 0x06, 
+0xe4, 0x93, 0xff, 0x78, 0x7e, 0xf6, 0xfd, 0xad, 0x07, 0x90, 0x2f, 0x13, 0xe4, 0x93, 0xff, 0x08, 
+0xf6, 0xff, 0xed, 0x54, 0x0f, 0xfd, 0x12, 0x18, 0xaf, 0x74, 0x84, 0xf0, 0xed, 0x75, 0xf0, 0x08, 
+0xa4, 0x24, 0x47, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xc3, 0x74, 0xf0, 0x9f, 
+0x78, 0x81, 0xf6, 0x74, 0xfe, 0x94, 0x00, 0x18, 0x12, 0x18, 0x41, 0xce, 0xc3, 0x13, 0xce, 0x13, 
+0xd8, 0xf9, 0xff, 0xed, 0x12, 0x19, 0x07, 0xef, 0xf0, 0xed, 0x12, 0x19, 0x2d, 0xe4, 0xf5, 0x37, 
+0xe5, 0x37, 0x90, 0x2f, 0x00, 0x93, 0xff, 0x78, 0x7e, 0xf6, 0xfd, 0xe5, 0x37, 0x25, 0xe0, 0x24, 
+0x07, 0xf5, 0x82, 0xe4, 0x34, 0x2f, 0xf5, 0x83, 0xe4, 0x93, 0x08, 0xf6, 0xed, 0x30, 0xe7, 0x53, 
+0x18, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x18, 0xaf, 0x12, 0x19, 0x15, 0x24, 0x47, 0xf5, 0x82, 0xe4, 
+0x34, 0xff, 0x12, 0x18, 0x31, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0xe9, 0x12, 0x19, 
+0x07, 0xef, 0xf0, 0x12, 0x18, 0x38, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x19, 0x1a, 
+0x24, 0x45, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x12, 0x19, 0x2d, 0xe9, 
+0x75, 0xf0, 0x08, 0xa4, 0x24, 0x46, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x74, 0x80, 0xf0, 
+0x02, 0x17, 0x46, 0x78, 0x7e, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x18, 0xf9, 0x12, 0x19, 0x15, 0x24, 
+0x07, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x12, 0x18, 0x31, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 
+0x12, 0x19, 0x1a, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0x12, 0x18, 
+0x38, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x19, 0x1a, 0x24, 0x05, 0xf5, 0x82, 0xe4, 
+0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 
+0x34, 0xff, 0xf5, 0x83, 0xe4, 0xf0, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 
+0x34, 0xff, 0xf5, 0x83, 0xe4, 0xf0, 0x05, 0x37, 0xe5, 0x37, 0x64, 0x04, 0x60, 0x03, 0x02, 0x16, 
+0x70, 0x90, 0x2f, 0x05, 0xe4, 0x93, 0xff, 0x78, 0x7e, 0xf6, 0x12, 0x18, 0xf7, 0xe4, 0xf0, 0x90, 
+0x2f, 0x04, 0x93, 0xff, 0xf6, 0x12, 0x18, 0xad, 0xe4, 0xf0, 0x90, 0xff, 0xfd, 0x74, 0x05, 0xf0, 
+0x22, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x37, 0x90, 0xfa, 0xcb, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x14, 
+0x45, 0x85, 0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x02, 0x23, 0xee, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 
+0x2f, 0xe5, 0x52, 0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, 
+0x2e, 0xab, 0x2d, 0xfa, 0xa9, 0x2f, 0x74, 0x11, 0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 
+0x2f, 0xe4, 0x35, 0x2e, 0xf5, 0x2e, 0x90, 0xff, 0x06, 0xe0, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 
+0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, 0x2e, 0xab, 0x2d, 
+0xfa, 0xa9, 0x2f, 0xe4, 0x12, 0x13, 0xfb, 0x04, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, 
+0x2e, 0xab, 0x2d, 0xfa, 0xa9, 0x2f, 0xe4, 0x12, 0x13, 0xfb, 0x04, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 
+0x35, 0x2e, 0xf5, 0x2e, 0x90, 0xff, 0x04, 0xe0, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 0x12, 0x13, 
+0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, 0x2e, 0x90, 0xff, 0x05, 0xe0, 
+0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 
+0x35, 0x2e, 0xf5, 0x2e, 0x22, 0xf5, 0x83, 0xe0, 0x54, 0x08, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 
+0x22, 0xf5, 0x83, 0xef, 0xf0, 0xfd, 0x7c, 0x00, 0xc3, 0x78, 0x81, 0xe6, 0x9d, 0xf6, 0x18, 0xe6, 
+0x9c, 0xf6, 0xe6, 0xfe, 0x08, 0xe6, 0x78, 0x03, 0x22, 0x75, 0x2d, 0x01, 0x75, 0x2e, 0xf9, 0x75, 
+0x2f, 0x6e, 0x22, 0x90, 0xfa, 0xba, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x90, 0xfa, 0xb5, 0xe0, 0x24, 
+0xfc, 0x22, 0x90, 0xfa, 0xb8, 0xe0, 0xff, 0x7e, 0x00, 0xc3, 0x90, 0xfa, 0xbc, 0xe0, 0x9f, 0xf0, 
+0x90, 0xfa, 0xbb, 0xe0, 0x9e, 0xf0, 0x90, 0xfa, 0xb3, 0xee, 0x8f, 0xf0, 0x12, 0x14, 0x2f, 0xef, 
+0x25, 0x55, 0xf5, 0x55, 0xee, 0x35, 0x54, 0xf5, 0x54, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb0, 
+0x90, 0xfa, 0xb3, 0xe0, 0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x41, 0x22, 0x78, 0x82, 0xe6, 0xfe, 0x08, 
+0xe6, 0x8e, 0x83, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0x22, 0x54, 0x0f, 0x75, 
+0xf0, 0x08, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x22, 0xe5, 0x53, 0x75, 
+0xf0, 0x08, 0xa4, 0x24, 0x48, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x22, 0xe5, 0x53, 0x75, 0xf0, 0x08, 
+0xa4, 0x24, 0x08, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x22, 0x90, 0xff, 0x00, 0xe0, 0x54, 0x1f, 0x22, 
+0x90, 0xfa, 0xb5, 0xe0, 0xff, 0x24, 0xfc, 0x22, 0x75, 0x2a, 0x00, 0x8f, 0x2b, 0x90, 0xf9, 0x6b, 
+0x12, 0x14, 0xfd, 0x90, 0x00, 0x02, 0x22, 0x54, 0x0f, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 
+0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x22, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x41, 0xf5, 0x82, 0xe4, 
+0x34, 0xff, 0xf5, 0x83, 0x22, 0x74, 0x80, 0xf0, 0x08, 0xe6, 0xff, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 
+0x22, 0x74, 0xae, 0x25, 0x36, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, 0x22, 0x75, 0xf0, 0x08, 
+0xa4, 0x24, 0x42, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x74, 0x80, 0xf0, 0x22, 0x90, 0xff, 
+0x82, 0xe0, 0x44, 0x08, 0xf0, 0x22, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x03, 0xf0, 0x90, 0xff, 0xfc, 
+0xe0, 0x54, 0xfd, 0xf0, 0x22, 0x78, 0x6d, 0xe6, 0x54, 0xfd, 0xf6, 0x90, 0xff, 0xfd, 0x74, 0x65, 
+0xf0, 0x22, 0x12, 0x14, 0xdf, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x22, 0x7b, 0x01, 0x7a, 0xf9, 
+0x79, 0x6e, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb3, 0x22, 0x90, 0xff, 0x80, 0xe0, 0x44, 0x08, 
+0xf0, 0x22, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0x22, 0xe0, 0xff, 0x90, 0xf9, 0x66, 0x02, 
+0x14, 0xfd, 0x75, 0x30, 0x01, 0x75, 0x31, 0x09, 0x22, 0xd3, 0xe5, 0x35, 0x94, 0x08, 0xe5, 0x34, 
+0x94, 0x01, 0x22, 0x90, 0xfa, 0xba, 0xe0, 0xff, 0x90, 0xfa, 0xb6, 0xf0, 0x22, 0x90, 0xff, 0xa4, 
+0xe0, 0x54, 0xef, 0x22, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xef, 0x22, 0x8f, 0x38, 0x12, 0x27, 0x19, 
+0x78, 0x86, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, 0x08, 0x12, 0x20, 0x25, 0xe0, 0xfd, 
+0x12, 0x20, 0xa6, 0x8a, 0x83, 0x24, 0x0a, 0x12, 0x20, 0x25, 0xed, 0xf0, 0x12, 0x20, 0x7c, 0x24, 
+0x07, 0x12, 0x20, 0x25, 0xe0, 0xff, 0x12, 0x20, 0xbe, 0x24, 0x09, 0x12, 0x20, 0x25, 0xef, 0xf0, 
+0x90, 0xf9, 0x65, 0xe0, 0x30, 0xe4, 0x20, 0x08, 0x12, 0x20, 0x2f, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 
+0xe0, 0x25, 0xe0, 0xff, 0x05, 0x82, 0xd5, 0x82, 0x02, 0x15, 0x83, 0x15, 0x82, 0xe0, 0x33, 0xd0, 
+0x82, 0xd0, 0x83, 0xf0, 0xa3, 0xef, 0xf0, 0x78, 0x86, 0x12, 0x20, 0x2f, 0xe0, 0xfc, 0xa3, 0xe0, 
+0xfd, 0xec, 0xff, 0x12, 0x20, 0xa6, 0x8a, 0x83, 0x24, 0x08, 0x12, 0x20, 0x25, 0xef, 0xf0, 0xed, 
+0x12, 0x20, 0xbe, 0x24, 0x07, 0x12, 0x20, 0x25, 0xed, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 
+0xe0, 0xff, 0x53, 0x07, 0xc7, 0x08, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x12, 0x20, 0x69, 0xa3, 0xe0, 
+0x30, 0xe3, 0x12, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x05, 0x12, 0x20, 0x25, 0xe0, 0x90, 
+0x2f, 0x4d, 0x93, 0x42, 0x07, 0x53, 0x07, 0xfb, 0x12, 0x20, 0xae, 0x24, 0x06, 0x12, 0x20, 0x25, 
+0xe0, 0x60, 0x03, 0x43, 0x07, 0x04, 0x53, 0x07, 0xfc, 0x78, 0x86, 0x12, 0x20, 0x96, 0x24, 0x04, 
+0x12, 0x20, 0x25, 0xe0, 0x42, 0x07, 0x43, 0x07, 0x80, 0x12, 0x20, 0xa6, 0xf5, 0x82, 0x8a, 0x83, 
+0xa3, 0xa3, 0xef, 0xf0, 0x12, 0x20, 0xbe, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0xff, 0x8d, 0x82, 
+0x8c, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x30, 0xe1, 0x05, 0x53, 0x07, 0xdf, 0x80, 
+0x03, 0x43, 0x07, 0x20, 0xec, 0x30, 0xe4, 0x05, 0x53, 0x07, 0xef, 0x80, 0x03, 0x43, 0x07, 0x10, 
+0x90, 0xf9, 0x65, 0xe0, 0xfe, 0x54, 0x03, 0x60, 0x4c, 0x53, 0x07, 0xdf, 0xee, 0x30, 0xe1, 0x42, 
+0x12, 0x20, 0xae, 0x24, 0x09, 0x12, 0x20, 0x25, 0xe0, 0x14, 0x60, 0x31, 0x14, 0x60, 0x29, 0x14, 
+0x60, 0x26, 0x14, 0x60, 0x28, 0x24, 0x04, 0x70, 0x2c, 0xe5, 0x38, 0xb4, 0x03, 0x0d, 0x30, 0x95, 
+0x05, 0x43, 0x07, 0x02, 0x80, 0x1f, 0x53, 0x07, 0xfd, 0x80, 0x1a, 0x30, 0x93, 0x05, 0x43, 0x07, 
+0x02, 0x80, 0x12, 0x53, 0x07, 0xfd, 0x80, 0x0d, 0x43, 0x07, 0x02, 0x80, 0x08, 0x53, 0x07, 0xfd, 
+0x80, 0x03, 0x53, 0x07, 0xfd, 0x12, 0x20, 0x94, 0x24, 0x04, 0x12, 0x20, 0x25, 0xef, 0xf0, 0x8d, 
+0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xff, 0x90, 0xf9, 0x65, 0xe0, 0xfe, 0x54, 0x03, 0x60, 
+0x4a, 0xee, 0x30, 0xe1, 0x43, 0x08, 0x12, 0x20, 0xb0, 0x24, 0x09, 0x12, 0x20, 0x25, 0xe0, 0x14, 
+0x60, 0x2c, 0x14, 0x60, 0x2e, 0x14, 0x60, 0x26, 0x14, 0x60, 0x28, 0x24, 0x04, 0x70, 0x2c, 0xe5, 
+0x38, 0xb4, 0x03, 0x0d, 0x30, 0x94, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x1f, 0x43, 0x07, 0x80, 0x80, 
+0x1a, 0x30, 0x92, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x12, 0x43, 0x07, 0x80, 0x80, 0x0d, 0x53, 0x07, 
+0x7f, 0x80, 0x08, 0x43, 0x07, 0x80, 0x80, 0x03, 0x53, 0x07, 0x7f, 0x78, 0x86, 0x12, 0x20, 0x65, 
+0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x30, 0xe0, 0x05, 0x43, 0x07, 0x20, 0x80, 0x03, 0x53, 0x07, 0xdf, 
+0xec, 0x30, 0xe3, 0x05, 0x43, 0x07, 0x40, 0x80, 0x03, 0x53, 0x07, 0xbf, 0xec, 0x30, 0xe0, 0x05, 
+0x43, 0x07, 0x10, 0x80, 0x03, 0x53, 0x07, 0xef, 0xed, 0x30, 0xe4, 0x05, 0x43, 0x07, 0x08, 0x80, 
+0x03, 0x53, 0x07, 0xf7, 0xed, 0x30, 0xe5, 0x05, 0x43, 0x07, 0x04, 0x80, 0x03, 0x53, 0x07, 0xfb, 
+0xed, 0x30, 0xe6, 0x05, 0x43, 0x07, 0x01, 0x80, 0x03, 0x53, 0x07, 0xfe, 0xed, 0x30, 0xe7, 0x05, 
+0x43, 0x07, 0x02, 0x80, 0x03, 0x53, 0x07, 0xfd, 0x78, 0x84, 0x12, 0x20, 0x65, 0xa3, 0xef, 0xf0, 
+0x12, 0x2f, 0x80, 0x7f, 0x00, 0x22, 0x12, 0x0f, 0x89, 0x78, 0x8e, 0xef, 0xf6, 0x12, 0x27, 0x19, 
+0x12, 0x20, 0x70, 0x8e, 0x83, 0x24, 0x09, 0x12, 0x20, 0x25, 0xe0, 0xfd, 0x12, 0x20, 0x53, 0x90, 
+0x00, 0x0a, 0x12, 0x20, 0x78, 0x24, 0x0a, 0x12, 0x20, 0x25, 0xe0, 0x90, 0x00, 0x0b, 0x12, 0x14, 
+0x0d, 0x12, 0x20, 0x70, 0xf5, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf5, 0x59, 0x12, 0x20, 
+0x7c, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0xf5, 0x5a, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 
+0xf5, 0x5b, 0xe5, 0x59, 0xc4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x78, 0x8e, 0xf6, 0xd3, 0x94, 0x00, 
+0x40, 0x06, 0xe5, 0x5a, 0x30, 0xe1, 0x01, 0x06, 0x78, 0x8e, 0xe6, 0x12, 0x20, 0x52, 0x90, 0x00, 
+0x0c, 0xef, 0x12, 0x14, 0x0d, 0x78, 0x86, 0x12, 0x20, 0x2f, 0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 
+0xff, 0x53, 0x07, 0x0c, 0x53, 0x06, 0xe6, 0xe5, 0x59, 0x30, 0xe5, 0x03, 0x43, 0x07, 0x01, 0xe5, 
+0x5a, 0x20, 0xe5, 0x0e, 0xe5, 0x59, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x59, 0x20, 0xe7, 0x03, 0x43, 
+0x07, 0x02, 0xe5, 0x59, 0x30, 0xe3, 0x03, 0x43, 0x07, 0x10, 0xe5, 0x59, 0x30, 0xe2, 0x03, 0x43, 
+0x07, 0x20, 0xe5, 0x59, 0x54, 0x03, 0x60, 0x03, 0x43, 0x07, 0x40, 0xe5, 0x59, 0x30, 0xe1, 0x03, 
+0x43, 0x07, 0x80, 0xe5, 0x59, 0x30, 0xe4, 0x03, 0x43, 0x06, 0x01, 0xe5, 0x59, 0x30, 0xe6, 0x03, 
+0x43, 0x06, 0x08, 0xe5, 0x5a, 0x20, 0xe4, 0x0e, 0xe5, 0x59, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x59, 
+0x20, 0xe7, 0x03, 0x43, 0x06, 0x10, 0x53, 0x07, 0xfb, 0x53, 0x06, 0x79, 0x90, 0x00, 0x05, 0xee, 
+0x8f, 0xf0, 0x12, 0x14, 0xb2, 0xe5, 0x5b, 0x30, 0xe3, 0x12, 0x54, 0x30, 0xff, 0xc4, 0x54, 0x0f, 
+0x12, 0x20, 0x52, 0x90, 0x00, 0x08, 0xef, 0x12, 0x14, 0x0d, 0x80, 0x0a, 0x12, 0x20, 0x53, 0x90, 
+0x00, 0x08, 0xe4, 0x12, 0x14, 0x0d, 0xe5, 0x5b, 0x54, 0x03, 0x12, 0x20, 0x52, 0x90, 0x00, 0x07, 
+0xef, 0x12, 0x14, 0x0d, 0xe5, 0x5b, 0x54, 0x04, 0xff, 0xc3, 0x13, 0x90, 0x00, 0x09, 0x12, 0x14, 
+0x0d, 0x90, 0x00, 0x07, 0x12, 0x13, 0xce, 0x70, 0x13, 0x12, 0x20, 0x53, 0xe9, 0x24, 0x09, 0xf9, 
+0xe4, 0x3a, 0xfa, 0x12, 0x13, 0xb5, 0xff, 0xc3, 0x13, 0x12, 0x13, 0xfb, 0x12, 0x20, 0x94, 0x24, 
+0x08, 0x12, 0x20, 0x25, 0xe0, 0xfe, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x07, 0x12, 0x20, 
+0x25, 0xe0, 0xfd, 0xee, 0xed, 0x12, 0x20, 0x52, 0x90, 0x00, 0x03, 0xee, 0x8f, 0xf0, 0x12, 0x14, 
+0xb2, 0x12, 0x2f, 0x80, 0x7d, 0x0a, 0xe4, 0xff, 0x12, 0x2c, 0xc0, 0x02, 0x10, 0x0c, 0x90, 0xfa, 
+0xe2, 0xe0, 0xb4, 0x03, 0x06, 0x7e, 0x00, 0x7f, 0x40, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x08, 0x90, 
+0xfa, 0xd6, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0x00, 0x05, 0x12, 0x13, 0xce, 0xff, 0x7e, 0x00, 
+0x90, 0xfa, 0xd2, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x70, 0x03, 0x7f, 0x08, 0x22, 0x90, 0x00, 0x08, 
+0x12, 0x14, 0x5b, 0xff, 0x90, 0xfa, 0xd4, 0xe5, 0xf0, 0xf0, 0xa3, 0xef, 0xf0, 0xae, 0x02, 0xaf, 
+0x01, 0x8e, 0x56, 0x8f, 0x57, 0x74, 0x0a, 0x25, 0x57, 0xf5, 0x57, 0xe4, 0x35, 0x56, 0xf5, 0x56, 
+0x90, 0xfa, 0xd7, 0xe0, 0xff, 0x14, 0xfe, 0x90, 0xfa, 0xd5, 0xe0, 0x5e, 0xfe, 0xc3, 0xef, 0x9e, 
+0xff, 0x90, 0xfa, 0xd9, 0xf0, 0xc3, 0x90, 0xfa, 0xd3, 0xe0, 0x9f, 0x90, 0xfa, 0xd2, 0xe0, 0x94, 
+0x00, 0x50, 0x06, 0xa3, 0xe0, 0x90, 0xfa, 0xd9, 0xf0, 0x12, 0x1e, 0x2d, 0x60, 0x03, 0xe0, 0xff, 
+0x22, 0x12, 0x2a, 0x80, 0x90, 0xfa, 0xd2, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x60, 0x2b, 0x90, 
+0xfa, 0xd6, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xd3, 0xef, 0x9d, 0xee, 0x9c, 0x40, 0x07, 0xe0, 0x90, 
+0xfa, 0xd9, 0xf0, 0x80, 0x08, 0x90, 0xfa, 0xd3, 0xe0, 0x90, 0xfa, 0xd9, 0xf0, 0x12, 0x1e, 0x2d, 
+0x60, 0x03, 0xe0, 0xff, 0x22, 0x12, 0x2a, 0x80, 0x80, 0xca, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x58, 
+0xe4, 0xf5, 0x40, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x7f, 0x00, 0x22, 0xaa, 0x56, 0xa9, 
+0x57, 0x7b, 0x01, 0x90, 0xfa, 0xd4, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, 0xd9, 0xe0, 0xf5, 
+0x50, 0x12, 0x26, 0x25, 0x90, 0xfa, 0xd8, 0xef, 0xf0, 0x22, 0xef, 0x24, 0xae, 0x60, 0x52, 0x24, 
+0xfe, 0x60, 0x2e, 0x24, 0xfe, 0x70, 0x03, 0x02, 0x1e, 0xed, 0x24, 0x06, 0x60, 0x03, 0x02, 0x1f, 
+0x35, 0x78, 0x77, 0xe6, 0x54, 0xfb, 0xf6, 0x90, 0xff, 0xa5, 0xe0, 0xf5, 0x36, 0x44, 0x0f, 0xf0, 
+0x74, 0x33, 0x90, 0xfa, 0x90, 0xf0, 0xe5, 0x36, 0xa3, 0xf0, 0x90, 0xfa, 0xae, 0x74, 0x01, 0xf0, 
+0x22, 0x78, 0x78, 0xe6, 0x54, 0xfb, 0xf6, 0x90, 0xff, 0xb5, 0xe0, 0xf5, 0x36, 0x44, 0x0f, 0xf0, 
+0x74, 0x43, 0x90, 0xfa, 0x92, 0xf0, 0xe5, 0x36, 0xa3, 0xf0, 0x90, 0xfa, 0xaf, 0x74, 0x01, 0xf0, 
+0x22, 0x90, 0xfa, 0x9c, 0xe0, 0xa3, 0x20, 0xe5, 0x03, 0x02, 0x1f, 0x35, 0x90, 0xff, 0xa6, 0xe0, 
+0x90, 0xfa, 0xc9, 0xf0, 0xa3, 0xf0, 0x90, 0xfa, 0xc9, 0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, 
+0x90, 0xff, 0xa6, 0x12, 0x20, 0x83, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, 0xc9, 0xf0, 0x80, 0xe6, 
+0x90, 0xfa, 0xca, 0xe0, 0xff, 0x74, 0x34, 0xfe, 0x12, 0x29, 0xda, 0xef, 0x70, 0x57, 0x90, 0xfa, 
+0xca, 0xe0, 0xff, 0x74, 0x34, 0x90, 0xfa, 0x94, 0xf0, 0xef, 0xa3, 0xf0, 0x22, 0x90, 0xfa, 0xa6, 
+0xe0, 0xa3, 0x30, 0xe5, 0x40, 0x90, 0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xc9, 0xf0, 0xa3, 0xf0, 0x90, 
+0xfa, 0xc9, 0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, 0x90, 0xff, 0xb6, 0x12, 0x20, 0x83, 0x90, 
+0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xc9, 0xf0, 0x80, 0xe6, 0x90, 0xfa, 0xca, 0xe0, 0xff, 0x74, 0x44, 
+0xfe, 0x12, 0x29, 0xda, 0xef, 0x70, 0x0e, 0x90, 0xfa, 0xca, 0xe0, 0xff, 0x74, 0x44, 0x90, 0xfa, 
+0x96, 0xf0, 0xef, 0xa3, 0xf0, 0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 
+0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 
+0x06, 0xc0, 0x07, 0x90, 0xff, 0x92, 0xe0, 0xff, 0x90, 0xfa, 0xc8, 0xf0, 0x90, 0xff, 0x92, 0xe4, 
+0xf0, 0xef, 0x12, 0x15, 0x0f, 0x1f, 0xed, 0x26, 0x1f, 0xed, 0x2e, 0x1f, 0x90, 0x30, 0x1f, 0x90, 
+0x32, 0x1f, 0x9e, 0x38, 0x1f, 0xb0, 0x3a, 0x1f, 0xe2, 0x3e, 0x1f, 0xcd, 0x44, 0x1f, 0xc2, 0x46, 
+0x1f, 0xd8, 0x50, 0x1f, 0xd8, 0x52, 0x1f, 0xd8, 0x54, 0x1f, 0xd8, 0x56, 0x00, 0x00, 0x1f, 0xf2, 
+0x90, 0xfa, 0xc8, 0xe0, 0xfd, 0x7c, 0x00, 0x7f, 0x01, 0x12, 0x10, 0x9c, 0x80, 0x62, 0x7c, 0x00, 
+0x7d, 0x01, 0x7f, 0x03, 0x12, 0x10, 0x9c, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x50, 
+0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x02, 0x12, 0x10, 0x9c, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x40, 0xf0, 
+0x80, 0x3e, 0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x05, 0x12, 0x10, 0x9c, 0x80, 0x33, 0x7c, 0x00, 0x7d, 
+0x01, 0x7f, 0x06, 0x12, 0x10, 0x9c, 0x80, 0x28, 0x90, 0xfa, 0xc8, 0xe0, 0xff, 0x12, 0x1e, 0x4a, 
+0x80, 0x1e, 0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x04, 0x12, 0x10, 0x9c, 0x80, 0x13, 0x12, 0x25, 0x13, 
+0x80, 0x0e, 0x90, 0xfa, 0xc8, 0xe0, 0x24, 0x00, 0xff, 0xe4, 0x34, 0xff, 0xfe, 0x12, 0x29, 0xda, 
+0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 
+0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32, 0x78, 0x82, 0xe6, 0xfe, 0x08, 
+0xe6, 0x24, 0x04, 0x8e, 0x83, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0x22, 0x78, 0x82, 0xe6, 
+0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, 0x83, 0x22, 0x78, 0x86, 0xe6, 0xfe, 0x08, 0xe6, 0xaa, 0x06, 
+0xf8, 0xac, 0x02, 0x7d, 0x01, 0x7b, 0xff, 0x7a, 0x2f, 0x79, 0x52, 0x7e, 0x00, 0x7f, 0x0a, 0x02, 
+0x13, 0x8f, 0xff, 0x90, 0xf9, 0x6b, 0x02, 0x14, 0xfd, 0x90, 0xf9, 0x66, 0x12, 0x14, 0xfd, 0x90, 
+0x00, 0x04, 0x02, 0x13, 0xce, 0xe6, 0xfc, 0x08, 0xe6, 0xf5, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0x22, 
+0x78, 0x84, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x22, 0xed, 0x12, 0x14, 0x0d, 0x8f, 0x82, 0x8e, 0x83, 
+0xe5, 0x82, 0x22, 0xef, 0xf0, 0x90, 0xfa, 0xca, 0xe0, 0x54, 0x0f, 0x4e, 0xfe, 0xf0, 0xef, 0x54, 
+0xf0, 0x4e, 0xf0, 0x22, 0x78, 0x84, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x8c, 0x83, 0x22, 0xa6, 0x07, 
+0xe6, 0x24, 0x74, 0xf8, 0xe6, 0x22, 0x78, 0x84, 0xe6, 0xfa, 0x08, 0xe6, 0xfb, 0x22, 0x78, 0x86, 
+0xe6, 0xfc, 0x08, 0xe6, 0x8c, 0x83, 0x22, 0x26, 0xf6, 0x18, 0xee, 0x36, 0xf6, 0x22, 0x8b, 0x82, 
+0x8a, 0x83, 0xe5, 0x82, 0x22, 0x8b, 0x38, 0x8a, 0x39, 0x89, 0x3a, 0x8d, 0x3b, 0x90, 0xfa, 0xce, 
+0xe4, 0xf0, 0xa3, 0x74, 0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcd, 0x90, 0xfa, 0xce, 0xe0, 
+0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x90, 0xfa, 0xcd, 0xe0, 0x65, 
+0x3b, 0x60, 0x46, 0xa3, 0xe0, 0xff, 0xa3, 0xe0, 0xa3, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x12, 0x21, 
+0x54, 0x90, 0xfa, 0xcd, 0xe0, 0xff, 0x90, 0xfa, 0xd0, 0xe4, 0x8f, 0xf0, 0x12, 0x14, 0x2f, 0x12, 
+0x21, 0x54, 0x90, 0xfa, 0xd0, 0xe0, 0xff, 0xa3, 0xe0, 0x90, 0xfa, 0xce, 0xcf, 0xf0, 0xa3, 0xef, 
+0xf0, 0x90, 0xfa, 0xcd, 0xe0, 0xa3, 0x75, 0xf0, 0x00, 0x12, 0x14, 0x2f, 0x90, 0xfa, 0xce, 0xe4, 
+0x75, 0xf0, 0x04, 0x12, 0x14, 0x2f, 0x02, 0x20, 0xd6, 0x90, 0xfa, 0xcf, 0xe0, 0x24, 0x01, 0xff, 
+0x90, 0xfa, 0xce, 0xe0, 0x34, 0x00, 0xab, 0x38, 0xaa, 0x39, 0xa9, 0x3a, 0x8f, 0xf0, 0x12, 0x14, 
+0x93, 0x7f, 0x00, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcd, 0x90, 0xfa, 0xce, 0xe4, 0x75, 0xf0, 
+0x01, 0x12, 0x14, 0x2f, 0x85, 0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x02, 0x23, 0xee, 0x8f, 0x68, 
+0x12, 0x27, 0x19, 0x12, 0x20, 0x70, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x20, 0x25, 0xe0, 0x54, 0xfb, 
+0xf0, 0x44, 0x02, 0xf0, 0x08, 0x12, 0x20, 0x65, 0xe0, 0xa3, 0x30, 0xe5, 0x0c, 0x12, 0x20, 0x7c, 
+0x24, 0x0b, 0x12, 0x20, 0x25, 0xe0, 0x44, 0x01, 0xf0, 0x78, 0x82, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 
+0xf5, 0x82, 0x8e, 0x83, 0xe0, 0x54, 0xb8, 0xfd, 0xf0, 0xe5, 0x68, 0x24, 0xfe, 0x44, 0x20, 0xfc, 
+0x4d, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0x54, 0xb8, 0xf0, 0x4c, 0xf0, 0x8f, 
+0x82, 0x8e, 0x83, 0xa3, 0x74, 0x03, 0xf0, 0x18, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, 
+0x05, 0x12, 0x20, 0x25, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x74, 0x95, 0x25, 0x68, 0xf5, 0x82, 
+0xe4, 0x34, 0xfa, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0x44, 0x03, 0xfc, 0xed, 0x4c, 0xd0, 0x82, 0xd0, 
+0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 
+0x25, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x2f, 0x80, 0x74, 0x74, 0x25, 0x68, 0xf8, 0x74, 0x04, 0x46, 
+0xf6, 0x7f, 0x00, 0x22, 0x8b, 0x62, 0x8a, 0x63, 0x89, 0x64, 0x12, 0x2a, 0x62, 0x90, 0xfa, 0xbf, 
+0x12, 0x15, 0x06, 0xaa, 0x63, 0xa9, 0x64, 0x90, 0xfa, 0xc2, 0x12, 0x15, 0x06, 0x90, 0xfa, 0xc3, 
+0xe4, 0x75, 0xf0, 0x0a, 0x12, 0x14, 0x2f, 0x90, 0xfa, 0xc2, 0x12, 0x14, 0xfd, 0xe9, 0x24, 0x01, 
+0xf9, 0xe4, 0x3a, 0xfa, 0x90, 0xfa, 0xc5, 0x12, 0x15, 0x06, 0xab, 0x62, 0xaa, 0x63, 0xa9, 0x64, 
+0x12, 0x2a, 0x6e, 0xe0, 0xff, 0xc3, 0x13, 0xf0, 0xe4, 0x78, 0x88, 0xf6, 0x90, 0xfa, 0xbd, 0xe0, 
+0xff, 0x78, 0x88, 0xe6, 0xc3, 0x9f, 0x50, 0x4a, 0x90, 0xfa, 0xbf, 0x12, 0x2a, 0x43, 0xff, 0x78, 
+0x89, 0xf6, 0x90, 0xfa, 0xc2, 0x12, 0x2a, 0x43, 0xfe, 0xf4, 0x5f, 0xff, 0x78, 0x89, 0xf6, 0x12, 
+0x2a, 0x40, 0x5e, 0x4f, 0xff, 0x78, 0x89, 0xf6, 0x12, 0x2a, 0x49, 0x75, 0xf0, 0x02, 0x12, 0x14, 
+0x2f, 0x90, 0xfa, 0xc3, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x14, 0x2f, 0xab, 0x62, 0xaa, 0x63, 0xa9, 
+0x64, 0x90, 0x00, 0x04, 0x12, 0x13, 0xce, 0x30, 0xe4, 0x03, 0x12, 0x2a, 0x58, 0x78, 0x88, 0x06, 
+0x80, 0xaa, 0xe4, 0x90, 0xfa, 0xbe, 0xf0, 0x22, 0x8b, 0x5c, 0x8a, 0x5d, 0x89, 0x5e, 0x90, 0xfa, 
+0xbe, 0x74, 0x06, 0xf0, 0xe4, 0x90, 0xfa, 0xbd, 0xf0, 0x12, 0x13, 0xb5, 0x24, 0x6e, 0x60, 0x26, 
+0x14, 0x70, 0x70, 0x12, 0x2a, 0x2f, 0x60, 0x09, 0x24, 0x30, 0x70, 0x12, 0x12, 0x22, 0x14, 0x80, 
+0x62, 0x12, 0x2a, 0x79, 0x12, 0x1d, 0x5e, 0x90, 0xfa, 0xbe, 0xef, 0xf0, 0x80, 0x55, 0x90, 0xfa, 
+0xbe, 0x74, 0x81, 0xf0, 0x80, 0x4d, 0x12, 0x2a, 0x2f, 0x60, 0x09, 0x24, 0x30, 0x70, 0x3e, 0x12, 
+0x29, 0x85, 0x80, 0x3f, 0xe5, 0x5e, 0x24, 0x03, 0xf9, 0xe4, 0x35, 0x5d, 0xfa, 0x7b, 0x01, 0xc0, 
+0x03, 0xc0, 0x02, 0xc0, 0x01, 0x12, 0x2a, 0x79, 0x90, 0x00, 0x05, 0x12, 0x13, 0xce, 0xfd, 0x90, 
+0x00, 0x08, 0x12, 0x14, 0x5b, 0xf5, 0x41, 0x85, 0xf0, 0x40, 0xd0, 0x01, 0xd0, 0x02, 0xd0, 0x03, 
+0x12, 0x23, 0xee, 0x90, 0xfa, 0xbd, 0xef, 0xf0, 0xe4, 0xa3, 0xf0, 0x80, 0x06, 0x90, 0xfa, 0xbe, 
+0x74, 0x81, 0xf0, 0x90, 0xfa, 0xbe, 0xe0, 0x12, 0x2a, 0x79, 0x90, 0x00, 0x02, 0x12, 0x14, 0x0d, 
+0x90, 0xfa, 0xbd, 0xe0, 0xff, 0x22, 0x12, 0x0f, 0x89, 0x7f, 0x02, 0x12, 0x11, 0x9f, 0x78, 0x6d, 
+0xe6, 0x44, 0x02, 0xf6, 0xd2, 0xb0, 0xd2, 0xb1, 0xd2, 0xb3, 0x90, 0xff, 0xa4, 0xe0, 0x90, 0xfa, 
+0x7a, 0xf0, 0x90, 0xff, 0xb4, 0xe0, 0x90, 0xfa, 0x7b, 0xf0, 0x90, 0xff, 0xa2, 0xe0, 0x90, 0xfa, 
+0x78, 0xf0, 0x90, 0xff, 0xb2, 0xe0, 0x90, 0xfa, 0x79, 0xf0, 0x90, 0xff, 0xa4, 0x74, 0x30, 0xf0, 
+0x90, 0xff, 0xb4, 0xf0, 0x90, 0xff, 0xa2, 0x74, 0x40, 0xf0, 0x90, 0xff, 0xb2, 0xf0, 0x90, 0xfa, 
+0xe3, 0xe5, 0xa8, 0xf0, 0x75, 0xa8, 0x81, 0x90, 0xff, 0x92, 0xe0, 0x60, 0x04, 0xe4, 0xf0, 0x80, 
+0xf6, 0x90, 0xff, 0xfd, 0x74, 0x3a, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x90, 0xfa, 0x7a, 
+0xe0, 0x90, 0xff, 0xa4, 0xf0, 0x90, 0xfa, 0x7b, 0xe0, 0x90, 0xff, 0xb4, 0xf0, 0x90, 0xfa, 0x78, 
+0xe0, 0x90, 0xff, 0xa2, 0xf0, 0x90, 0xfa, 0x79, 0xe0, 0x90, 0xff, 0xb2, 0xf0, 0x90, 0xf9, 0x15, 
+0xe0, 0x60, 0x02, 0xc2, 0xb3, 0x90, 0xfa, 0xe3, 0xe0, 0xf5, 0xa8, 0x02, 0x10, 0x0c, 0x8b, 0x3c, 
+0x8a, 0x3d, 0x89, 0x3e, 0x8d, 0x3f, 0xe5, 0x3f, 0x70, 0x03, 0xaf, 0x3f, 0x22, 0x12, 0x2a, 0xa8, 
+0x70, 0x16, 0x12, 0x2a, 0xc7, 0xe5, 0x40, 0x90, 0xff, 0xf1, 0xf0, 0x12, 0x2e, 0xd4, 0x50, 0xf2, 
+0x12, 0x24, 0x7b, 0x40, 0x0b, 0x7f, 0x00, 0x22, 0x12, 0x2a, 0xc7, 0x12, 0x24, 0x7b, 0x50, 0xf8, 
+0x90, 0xff, 0xf3, 0x74, 0xa1, 0xf0, 0xe5, 0x3f, 0xb4, 0x01, 0x07, 0x90, 0xff, 0xf0, 0xe0, 0x44, 
+0x02, 0xf0, 0x90, 0xff, 0xf1, 0xe4, 0xf0, 0xf5, 0x42, 0xe5, 0x3f, 0x14, 0xff, 0xe5, 0x42, 0xc3, 
+0x9f, 0x50, 0x2a, 0x12, 0x2e, 0xbd, 0x40, 0x03, 0xaf, 0x42, 0x22, 0xc3, 0xe5, 0x3f, 0x95, 0x42, 
+0xff, 0xbf, 0x02, 0x07, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x02, 0xf0, 0x12, 0x2a, 0xba, 0x05, 0x42, 
+0x74, 0x01, 0x25, 0x3e, 0xf5, 0x3e, 0xe4, 0x35, 0x3d, 0xf5, 0x3d, 0x80, 0xcc, 0x12, 0x2e, 0xbd, 
+0x40, 0x03, 0x7f, 0x18, 0x22, 0x12, 0x2a, 0xba, 0xaf, 0x3f, 0x22, 0x90, 0xff, 0xf1, 0xe5, 0x41, 
+0xf0, 0x02, 0x2e, 0xd4, 0x75, 0xa8, 0x40, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x91, 
+0x02, 0x24, 0xce, 0x02, 0x2e, 0x88, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 
+0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 
+0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 
+0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x28, 
+0xcb, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 
+0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 
+0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 
+0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 
+0xe7, 0x80, 0xbe, 0xe4, 0xf5, 0x36, 0x12, 0x19, 0x21, 0xe0, 0xb4, 0x04, 0x0d, 0xe5, 0x36, 0x24, 
+0x03, 0xff, 0x12, 0x2d, 0x4f, 0x12, 0x19, 0x21, 0xe4, 0xf0, 0x05, 0x36, 0xe5, 0x36, 0xc3, 0x94, 
+0x02, 0x40, 0xe3, 0xe4, 0xf5, 0x36, 0x75, 0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 0x90, 0x12, 0x19, 
+0x62, 0x60, 0x2c, 0x12, 0x29, 0xda, 0xef, 0x60, 0x52, 0x75, 0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 
+0x90, 0x12, 0x14, 0xdf, 0xe4, 0xf0, 0xa3, 0xf0, 0x75, 0xf0, 0x0a, 0xe5, 0x36, 0x90, 0xfa, 0x9c, 
+0x12, 0x14, 0xdf, 0xe0, 0xa3, 0x30, 0xe6, 0x33, 0x12, 0x19, 0x21, 0x74, 0x04, 0xf0, 0x22, 0x75, 
+0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 0x94, 0x12, 0x19, 0x62, 0x60, 0x16, 0x12, 0x29, 0xda, 0xef, 
+0x60, 0x19, 0x75, 0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 0x94, 0x12, 0x14, 0xdf, 0xe4, 0xf0, 0xa3, 
+0xf0, 0x22, 0x05, 0x36, 0xe5, 0x36, 0xc3, 0x94, 0x02, 0x40, 0x9b, 0x22, 0xe4, 0xff, 0x90, 0xff, 
+0x83, 0xe0, 0x54, 0x0f, 0xfe, 0xef, 0xc3, 0x9e, 0x50, 0x17, 0x74, 0xf0, 0x2f, 0xf5, 0x82, 0xe4, 
+0x34, 0xfe, 0xf5, 0x83, 0xe0, 0x12, 0x18, 0x2a, 0x12, 0x13, 0xfb, 0x0f, 0x12, 0x18, 0x19, 0x80, 
+0xdd, 0xef, 0xfd, 0xc3, 0xe5, 0x31, 0x9d, 0xf5, 0x31, 0xe5, 0x30, 0x94, 0x00, 0xf5, 0x30, 0xd3, 
+0xe5, 0x31, 0x94, 0x00, 0xe5, 0x30, 0x94, 0x00, 0x40, 0x06, 0xe4, 0x90, 0xff, 0x83, 0xf0, 0x22, 
+0x12, 0x19, 0x3e, 0x12, 0x19, 0x92, 0x12, 0x19, 0x8c, 0x12, 0x13, 0xb5, 0x24, 0x6e, 0x60, 0x1e, 
+0x14, 0x60, 0x1b, 0x24, 0x8e, 0x70, 0x2d, 0x90, 0x00, 0x01, 0x12, 0x13, 0xce, 0xff, 0x24, 0xfc, 
+0x60, 0x03, 0x04, 0x70, 0x1f, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0d, 0x02, 0x10, 0x9c, 0x12, 0x19, 
+0x6c, 0x12, 0x22, 0xb8, 0x12, 0x18, 0xe8, 0x12, 0x13, 0xce, 0x60, 0x03, 0x02, 0x2f, 0x76, 0xe4, 
+0xff, 0x12, 0x2f, 0x6a, 0x22, 0x8b, 0x4b, 0x8a, 0x4c, 0x89, 0x4d, 0x8c, 0x4e, 0x8d, 0x4f, 0xd2, 
+0x00, 0x12, 0x2a, 0xa8, 0x70, 0x16, 0x12, 0x2a, 0xc7, 0xe5, 0x4e, 0x90, 0xff, 0xf1, 0xf0, 0x12, 
+0x2e, 0xd4, 0x50, 0xf2, 0x12, 0x26, 0x9a, 0x40, 0x0b, 0x7f, 0x18, 0x22, 0x12, 0x2a, 0xc7, 0x12, 
+0x26, 0x9a, 0x50, 0xf8, 0xe4, 0xf5, 0x51, 0xe5, 0x50, 0x14, 0xff, 0xe5, 0x51, 0xc3, 0x9f, 0x50, 
+0x17, 0x12, 0x26, 0x8a, 0x40, 0x03, 0x7f, 0x18, 0x22, 0x05, 0x51, 0x74, 0x01, 0x25, 0x4d, 0xf5, 
+0x4d, 0xe4, 0x35, 0x4c, 0xf5, 0x4c, 0x80, 0xdf, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x01, 0xf0, 0x12, 
+0x26, 0x8a, 0x40, 0x03, 0x7f, 0x18, 0x22, 0x7f, 0x00, 0x22, 0xab, 0x4b, 0xaa, 0x4c, 0xa9, 0x4d, 
+0x12, 0x13, 0xb5, 0x90, 0xff, 0xf1, 0xf0, 0x02, 0x2e, 0xd4, 0x90, 0xff, 0xf1, 0xe5, 0x4f, 0xf0, 
+0x02, 0x2e, 0xd4, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcb, 0xe4, 0xfd, 0x12, 0x20, 0xc5, 0x90, 0xfa, 
+0xcb, 0xe4, 0x75, 0xf0, 0x09, 0x12, 0x14, 0x2f, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x37, 0x90, 0xfa, 
+0xcb, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x14, 0x45, 0x85, 0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x12, 
+0x23, 0xee, 0x90, 0xff, 0xf7, 0xe5, 0x37, 0x12, 0x26, 0xfe, 0x90, 0xff, 0xf6, 0xe5, 0x37, 0xf0, 
+0x90, 0xfa, 0xcb, 0xe4, 0xf0, 0xa3, 0x74, 0x06, 0x12, 0x26, 0xfe, 0xe5, 0x37, 0x30, 0xe0, 0x07, 
+0x90, 0xff, 0xfc, 0x74, 0x94, 0xf0, 0x22, 0x90, 0xff, 0xfc, 0x74, 0x90, 0xf0, 0x22, 0xf0, 0x7b, 
+0x00, 0x7a, 0x00, 0x79, 0x37, 0x90, 0xfa, 0xcb, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x14, 0x45, 0x85, 
+0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x02, 0x23, 0xee, 0x15, 0x6b, 0xa8, 0x6b, 0xa6, 0x07, 0x30, 
+0x08, 0x05, 0x12, 0x10, 0xec, 0x80, 0xf8, 0xd2, 0x08, 0xa8, 0x6b, 0xe6, 0xff, 0xb4, 0x03, 0x0f, 
+0x78, 0x82, 0x76, 0xff, 0x08, 0x76, 0xe0, 0x08, 0x76, 0xff, 0x08, 0x76, 0xa0, 0x80, 0x0d, 0x78, 
+0x82, 0x76, 0xff, 0x08, 0x76, 0xe2, 0x08, 0x76, 0xff, 0x08, 0x76, 0xb0, 0x78, 0x86, 0x76, 0xfa, 
+0x08, 0x76, 0x9a, 0xef, 0x24, 0xfd, 0x75, 0xf0, 0x0a, 0xa4, 0xae, 0xf0, 0x12, 0x20, 0xb7, 0x7b, 
+0x01, 0x7a, 0xff, 0x79, 0x48, 0x78, 0x6e, 0x12, 0x14, 0xf4, 0xa8, 0x6b, 0xe6, 0x24, 0xfd, 0x75, 
+0xf0, 0x08, 0xa4, 0xff, 0xae, 0xf0, 0x78, 0x70, 0x12, 0x20, 0xb7, 0x79, 0x08, 0x78, 0x71, 0x12, 
+0x14, 0xf4, 0x78, 0x73, 0xef, 0x12, 0x20, 0xb7, 0x05, 0x6b, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, 
+0xab, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xfa, 0xe2, 0x74, 0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 
+0x79, 0xcb, 0xe4, 0xf5, 0x40, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x7e, 0x00, 0x90, 0xfa, 
+0xe0, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x64, 0x01, 0x70, 0x10, 0x90, 0xfa, 0xcb, 0xe0, 0xb4, 0x52, 
+0x09, 0x90, 0xf9, 0x65, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x29, 0x90, 0xfa, 0xe0, 0xe0, 0x70, 0x04, 
+0xa3, 0xe0, 0x64, 0x01, 0x70, 0x10, 0x90, 0xfa, 0xcb, 0xe0, 0xb4, 0x10, 0x09, 0x90, 0xf9, 0x65, 
+0xe0, 0x44, 0x10, 0xf0, 0x80, 0x0d, 0x90, 0xfa, 0xe2, 0x74, 0x03, 0xf0, 0x90, 0xf9, 0x65, 0xe0, 
+0x54, 0xef, 0xf0, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x22, 0x90, 0xff, 0x93, 0x74, 0x2a, 
+0xf0, 0x90, 0xff, 0xff, 0xe0, 0x60, 0x06, 0x90, 0xff, 0xfc, 0x74, 0x10, 0xf0, 0x90, 0xff, 0x91, 
+0xe0, 0x44, 0x90, 0xf0, 0x12, 0x27, 0x8b, 0x12, 0x15, 0x35, 0x12, 0x2d, 0xa5, 0x7e, 0x07, 0x7f, 
+0xd0, 0x12, 0x11, 0x68, 0x7e, 0x0f, 0x7f, 0xa0, 0x12, 0x11, 0x82, 0xe4, 0x78, 0x7d, 0xf6, 0x78, 
+0x7d, 0xe6, 0xff, 0xc3, 0x94, 0x06, 0x50, 0x0b, 0x74, 0x74, 0x2f, 0xf8, 0xe4, 0xf6, 0x78, 0x7d, 
+0x06, 0x80, 0xec, 0x7f, 0x03, 0x12, 0x2c, 0x5b, 0x90, 0xf9, 0x65, 0xe0, 0x20, 0xe4, 0x05, 0x7f, 
+0x04, 0x12, 0x2c, 0x5b, 0x90, 0xff, 0x9b, 0xe4, 0xf0, 0x90, 0xff, 0x9a, 0xf0, 0x90, 0xff, 0xe8, 
+0xe0, 0x54, 0x1f, 0xf0, 0xd2, 0xa8, 0x22, 0x12, 0x0f, 0x89, 0x78, 0x90, 0xef, 0xf6, 0x12, 0x27, 
+0x19, 0x12, 0x20, 0x59, 0x30, 0xe0, 0x25, 0x12, 0x20, 0x2d, 0xe0, 0x54, 0x7f, 0xf0, 0x78, 0x71, 
+0x12, 0x14, 0xeb, 0x90, 0x00, 0x02, 0x12, 0x13, 0xce, 0x30, 0xe7, 0x09, 0x90, 0x00, 0x02, 0xe4, 
+0x12, 0x14, 0x0d, 0x80, 0xe9, 0x12, 0x20, 0x2d, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x20, 0x59, 0x30, 
+0xe1, 0x1e, 0x12, 0x20, 0x1b, 0xe0, 0x54, 0x7f, 0xf0, 0x12, 0x2f, 0x15, 0x78, 0x6e, 0x12, 0x14, 
+0xeb, 0x90, 0x00, 0x02, 0x74, 0x80, 0x12, 0x14, 0x0d, 0x12, 0x20, 0x1b, 0xe0, 0x44, 0x80, 0xf0, 
+0x12, 0x2f, 0x80, 0xe4, 0xff, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x03, 0x6e, 0x01, 0xff, 0x48, 
+0x03, 0x71, 0x01, 0xff, 0x08, 0x02, 0x6c, 0x00, 0x00, 0x44, 0xfa, 0x94, 0x00, 0x00, 0x00, 0x00, 
+0x44, 0xfa, 0x90, 0x00, 0x00, 0x00, 0x00, 0x42, 0xfa, 0xae, 0x00, 0x00, 0x42, 0xfa, 0x7a, 0x00, 
+0x00, 0x42, 0xfa, 0x78, 0x00, 0x00, 0x42, 0xf9, 0x69, 0xff, 0xff, 0x42, 0xfa, 0x76, 0x00, 0x00, 
+0x43, 0xf9, 0x16, 0x0a, 0x32, 0x02, 0x41, 0xf9, 0x63, 0x20, 0x41, 0xf9, 0x64, 0x20, 0x41, 0xf9, 
+0x61, 0x00, 0x41, 0xf9, 0x62, 0x00, 0x44, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xf9, 0x65, 
+0x00, 0x41, 0xf9, 0x15, 0x00, 0x01, 0x20, 0x00, 0x41, 0xf8, 0x04, 0x00, 0x00, 0x12, 0x19, 0x82, 
+0xe5, 0x31, 0x64, 0x09, 0x70, 0x04, 0xe5, 0x30, 0x64, 0x01, 0x60, 0x48, 0xc3, 0xe5, 0x31, 0x94, 
+0x08, 0xe5, 0x30, 0x94, 0x00, 0x40, 0x11, 0x7f, 0x08, 0xef, 0xe5, 0x31, 0x94, 0x08, 0xf5, 0x31, 
+0xe5, 0x30, 0x94, 0x00, 0xf5, 0x30, 0x80, 0x05, 0xaf, 0x31, 0x12, 0x19, 0x92, 0xe4, 0xfe, 0xee, 
+0xc3, 0x9f, 0x50, 0x19, 0x12, 0x18, 0x2a, 0x12, 0x13, 0xb5, 0xfd, 0x74, 0xf8, 0x2e, 0xf5, 0x82, 
+0xe4, 0x34, 0xfe, 0xf5, 0x83, 0xed, 0xf0, 0x0e, 0x12, 0x18, 0x19, 0x80, 0xe2, 0xef, 0x54, 0x7f, 
+0x90, 0xff, 0x81, 0xf0, 0x22, 0x8b, 0x5f, 0x8a, 0x60, 0x89, 0x61, 0x12, 0x2a, 0x6e, 0x70, 0x05, 
+0xa3, 0x74, 0x08, 0xf0, 0x22, 0xab, 0x5f, 0xaa, 0x60, 0xa9, 0x61, 0x12, 0x2a, 0x62, 0x90, 0xfa, 
+0xc5, 0x12, 0x15, 0x06, 0xe5, 0x61, 0x24, 0x03, 0xf9, 0xe4, 0x35, 0x60, 0xfa, 0x90, 0xfa, 0xbf, 
+0x12, 0x15, 0x06, 0xe4, 0x90, 0xfa, 0xbe, 0xf0, 0x78, 0x91, 0xf6, 0x90, 0xfa, 0xbd, 0xe0, 0xff, 
+0x78, 0x91, 0xe6, 0xc3, 0x9f, 0x50, 0x12, 0x12, 0x2a, 0x40, 0xff, 0x12, 0x2a, 0x49, 0x12, 0x2a, 
+0x5c, 0x78, 0x91, 0x06, 0x12, 0x2a, 0x58, 0x80, 0xe2, 0x22, 0xad, 0x07, 0xac, 0x06, 0x90, 0x2f, 
+0x06, 0xe4, 0x93, 0xff, 0x78, 0x7a, 0xf6, 0x54, 0x0f, 0x12, 0x19, 0x07, 0xe0, 0x08, 0x76, 0x00, 
+0x08, 0xf6, 0x18, 0x12, 0x18, 0x42, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0x78, 0x7b, 
+0xee, 0xf6, 0x08, 0xef, 0xf6, 0xee, 0x44, 0xf8, 0x18, 0xf6, 0xef, 0x08, 0xf6, 0x90, 0xff, 0x7a, 
+0xe0, 0x20, 0xe7, 0x03, 0x7f, 0x00, 0x22, 0x78, 0x7b, 0xe6, 0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, 
+0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0, 0x90, 0xff, 0x7a, 0x74, 0x02, 0xf0, 0x7f, 0x01, 0x22, 0xab, 
+0x5c, 0xaa, 0x5d, 0xa9, 0x5e, 0x90, 0x00, 0x03, 0x12, 0x13, 0xce, 0x54, 0xf0, 0x24, 0xa0, 0x22, 
+0x90, 0xfa, 0xc5, 0x12, 0x14, 0xfd, 0x02, 0x13, 0xb5, 0x90, 0xfa, 0xbf, 0x12, 0x14, 0xfd, 0xef, 
+0x12, 0x13, 0xfb, 0x90, 0xfa, 0xc6, 0xe4, 0x22, 0x90, 0xfa, 0xc0, 0xe4, 0x75, 0xf0, 0x01, 0x02, 
+0x14, 0x2f, 0x90, 0x00, 0x08, 0x12, 0x14, 0x5b, 0xaa, 0xf0, 0xf9, 0x7b, 0x01, 0x22, 0x90, 0x00, 
+0x05, 0x12, 0x13, 0xce, 0x90, 0xfa, 0xbd, 0xf0, 0x22, 0xab, 0x5c, 0xaa, 0x5d, 0xa9, 0x5e, 0x22, 
+0x90, 0xfa, 0xd9, 0xe0, 0xff, 0x7e, 0x00, 0xc3, 0x90, 0xfa, 0xd3, 0xe0, 0x9f, 0xf0, 0x90, 0xfa, 
+0xd2, 0xe0, 0x9e, 0xf0, 0x90, 0xfa, 0xd4, 0xee, 0x8f, 0xf0, 0x12, 0x14, 0x2f, 0xef, 0x25, 0x57, 
+0xf5, 0x57, 0xee, 0x35, 0x56, 0xf5, 0x56, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, 0xfe, 0xf0, 0xe0, 
+0x54, 0xfd, 0xf0, 0x90, 0xfa, 0xe2, 0xe0, 0x64, 0x03, 0x22, 0x90, 0xff, 0xf2, 0xe0, 0xab, 0x3c, 
+0xaa, 0x3d, 0xa9, 0x3e, 0x02, 0x13, 0xfb, 0x90, 0xff, 0xf3, 0x74, 0xa0, 0xf0, 0x22, 0x8f, 0x6a, 
+0xed, 0x70, 0x0f, 0xe5, 0x6a, 0xb4, 0x03, 0x05, 0x7f, 0x01, 0x02, 0x2e, 0xeb, 0x7f, 0x02, 0x02, 
+0x2e, 0xeb, 0xaf, 0x6a, 0x12, 0x27, 0x19, 0x74, 0x74, 0x25, 0x6a, 0xf8, 0xe6, 0x30, 0xe2, 0x0b, 
+0xd2, 0x09, 0x12, 0x18, 0x9b, 0xe0, 0x54, 0x7f, 0xf0, 0x80, 0x02, 0xc2, 0x09, 0xe5, 0x6a, 0xb4, 
+0x03, 0x07, 0x7f, 0x81, 0x12, 0x2e, 0xeb, 0x80, 0x05, 0x7f, 0x82, 0x12, 0x2e, 0xeb, 0x30, 0x09, 
+0x07, 0x12, 0x18, 0x9b, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x2f, 0x80, 0x22, 0x12, 0x0f, 0x89, 0x90, 
+0xff, 0xfd, 0xe0, 0x44, 0x60, 0xf0, 0xd2, 0x01, 0x90, 0xff, 0xfc, 0xe0, 0x44, 0x02, 0xf0, 0x90, 
+0xff, 0x00, 0xe0, 0x30, 0xe7, 0x13, 0x90, 0xff, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x2c, 0x80, 
+0x90, 0xff, 0xfc, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x0d, 0x12, 0x19, 0x3e, 0x53, 0x2c, 0x7f, 0x90, 
+0xff, 0xfc, 0xe0, 0x54, 0xfe, 0xf0, 0x90, 0xff, 0x81, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x02, 0x9f, 
+0x12, 0x19, 0x46, 0x02, 0x10, 0x0c, 0x12, 0x0f, 0x89, 0x78, 0x8a, 0x12, 0x20, 0x9e, 0x30, 0xe1, 
+0x07, 0x7f, 0x13, 0x12, 0x2e, 0xa5, 0x80, 0x34, 0x90, 0xf9, 0x65, 0xe0, 0x54, 0x03, 0x60, 0x16, 
+0x78, 0x8a, 0xe6, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x07, 0x90, 
+0xff, 0xb4, 0xe0, 0x54, 0xdf, 0xf0, 0xc2, 0xb3, 0x90, 0xf9, 0x15, 0xe0, 0x04, 0xf0, 0x78, 0x8a, 
+0xe6, 0xff, 0x12, 0x20, 0x59, 0xfd, 0x12, 0x2d, 0x21, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x12, 
+0x0f, 0x89, 0x78, 0x8f, 0xef, 0xf6, 0xd2, 0x00, 0x12, 0x27, 0x19, 0x90, 0xf9, 0x66, 0x12, 0x14, 
+0xfd, 0xe9, 0x24, 0x03, 0xf9, 0xe4, 0x3a, 0xfa, 0xc0, 0x02, 0x78, 0x86, 0xe6, 0xfe, 0x08, 0xe6, 
+0xaa, 0x06, 0xf8, 0xac, 0x02, 0x7d, 0x01, 0xd0, 0x02, 0x12, 0x20, 0x4b, 0x12, 0x2f, 0x80, 0x78, 
+0x8f, 0xe6, 0xff, 0x12, 0x19, 0xbb, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x12, 0x0f, 0x89, 0x78, 
+0x8b, 0xef, 0xf6, 0x12, 0x2e, 0x4c, 0x12, 0x2e, 0xa5, 0x90, 0xf9, 0x65, 0xe0, 0x54, 0x03, 0x60, 
+0x16, 0x78, 0x8b, 0xe6, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x07, 
+0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xf9, 0x15, 0xe0, 0x14, 0xf0, 0xe0, 0x70, 0x02, 
+0xd2, 0xb3, 0x02, 0x10, 0x0c, 0x8f, 0x69, 0x12, 0x27, 0x19, 0x12, 0x20, 0x2d, 0xe0, 0x54, 0x3f, 
+0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0x54, 0x3f, 0xf0, 0x08, 0xe6, 0xfe, 0x08, 
+0xe6, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x20, 0x25, 0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x2f, 0x80, 0x74, 
+0x74, 0x25, 0x69, 0xf8, 0x74, 0xfb, 0x56, 0xf6, 0x7f, 0x00, 0x22, 0x8f, 0x37, 0xc2, 0x08, 0x12, 
+0x27, 0x19, 0x12, 0x20, 0x38, 0x78, 0x84, 0x12, 0x20, 0x1d, 0xe0, 0x44, 0x01, 0xf0, 0x12, 0x20, 
+0x70, 0x12, 0x20, 0x21, 0xe0, 0x20, 0xe0, 0xf6, 0xef, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x3e, 0xf5, 
+0x83, 0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x2f, 0x80, 0xaf, 0x37, 0x12, 0x19, 0xbb, 0x22, 0x12, 0x0f, 
+0x89, 0x12, 0x27, 0x19, 0x12, 0x20, 0x70, 0x24, 0x06, 0x12, 0x20, 0x23, 0xe0, 0xfd, 0x12, 0x20, 
+0x53, 0x90, 0x00, 0x03, 0x12, 0x20, 0x78, 0x24, 0x05, 0x12, 0x20, 0x25, 0xe0, 0x90, 0x00, 0x04, 
+0x12, 0x14, 0x0d, 0x12, 0x2f, 0x80, 0x7d, 0x02, 0xe4, 0xff, 0x12, 0x2c, 0xc0, 0x02, 0x10, 0x0c, 
+0xae, 0x05, 0x12, 0x18, 0xed, 0xef, 0x12, 0x14, 0x0d, 0x0e, 0x0e, 0x0e, 0xee, 0xd3, 0x95, 0x35, 
+0xe4, 0x95, 0x34, 0x40, 0x02, 0xae, 0x35, 0xee, 0xd3, 0x94, 0x08, 0x74, 0x80, 0x94, 0x81, 0x40, 
+0x0a, 0x7e, 0x03, 0x90, 0x00, 0x02, 0x74, 0x02, 0x12, 0x14, 0x0d, 0xaf, 0x06, 0x12, 0x2f, 0x6a, 
+0x22, 0x12, 0x0f, 0x89, 0x78, 0x8c, 0x12, 0x20, 0x9e, 0x30, 0xe2, 0x07, 0x7f, 0x13, 0x12, 0x2e, 
+0xa5, 0x80, 0x1b, 0x78, 0x8c, 0xe6, 0x24, 0x74, 0xf8, 0xe6, 0x20, 0xe1, 0x07, 0x7f, 0x12, 0x12, 
+0x2e, 0xa5, 0x80, 0x0a, 0x78, 0x8c, 0xe6, 0xff, 0x12, 0x21, 0x6e, 0x12, 0x2e, 0xa5, 0x02, 0x10, 
+0x0c, 0xae, 0x07, 0xed, 0x54, 0x03, 0x64, 0x01, 0x60, 0x03, 0x7f, 0x10, 0x22, 0xed, 0x54, 0x7c, 
+0xc3, 0x94, 0x04, 0x50, 0x03, 0x7f, 0x0b, 0x22, 0x74, 0x74, 0x2e, 0xf8, 0x74, 0x02, 0x46, 0xf6, 
+0x74, 0x95, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, 0xed, 0xf0, 0x7f, 0x00, 0x22, 0xbf, 
+0x03, 0x06, 0x7c, 0xff, 0x7d, 0xe0, 0x80, 0x04, 0x7c, 0xff, 0x7d, 0xe2, 0x8d, 0x82, 0x8c, 0x83, 
+0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0x44, 0x80, 0xf0, 0x74, 
+0x74, 0x2f, 0xf8, 0x74, 0x04, 0x46, 0xf6, 0x7f, 0x00, 0x22, 0x12, 0x0f, 0x89, 0xe5, 0x31, 0x64, 
+0x09, 0x70, 0x04, 0xe5, 0x30, 0x64, 0x01, 0x60, 0x16, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x0f, 0xff, 
+0xc3, 0xe5, 0x31, 0x9f, 0xe5, 0x30, 0x94, 0x00, 0x40, 0x05, 0x12, 0x25, 0x9c, 0x80, 0x03, 0x12, 
+0x2f, 0x76, 0x02, 0x10, 0x0c, 0x90, 0xff, 0xfc, 0xe0, 0x20, 0xe7, 0x1f, 0xc2, 0xaf, 0x7d, 0xff, 
+0xac, 0x05, 0x1d, 0xec, 0x60, 0x15, 0x7e, 0x04, 0x7f, 0x00, 0xef, 0x1f, 0xaa, 0x06, 0x70, 0x01, 
+0x1e, 0x4a, 0x60, 0xec, 0x90, 0xff, 0x92, 0xe4, 0xf0, 0x80, 0xef, 0x22, 0x12, 0x0f, 0x89, 0x78, 
+0x6c, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x30, 0xe0, 0x12, 0x30, 0xe1, 0x0f, 0x90, 0xff, 0xfc, 0xe0, 
+0x44, 0x20, 0xf0, 0x7f, 0x04, 0x12, 0x11, 0x9f, 0x12, 0x19, 0x55, 0x02, 0x10, 0x0c, 0x8e, 0x65, 
+0x8f, 0x66, 0xe5, 0x66, 0x15, 0x66, 0xae, 0x65, 0x70, 0x02, 0x15, 0x65, 0xd3, 0x94, 0x00, 0xee, 
+0x94, 0x00, 0x40, 0x09, 0x7e, 0x07, 0x7f, 0xd0, 0x12, 0x0f, 0x62, 0x80, 0xe5, 0x22, 0x11, 0x1a, 
+0x2b, 0x1c, 0x23, 0x56, 0x2f, 0x5c, 0x2d, 0xcc, 0x2d, 0x7a, 0x2e, 0x6b, 0x2c, 0x8e, 0x2b, 0x66, 
+0x2b, 0xec, 0x2c, 0xf1, 0x2e, 0x2d, 0x1b, 0xe6, 0x2b, 0xaf, 0x28, 0x67, 0x0e, 0x12, 0x0f, 0x89, 
+0x78, 0x8d, 0x12, 0x20, 0x9e, 0x20, 0xe2, 0x07, 0x7f, 0x11, 0x12, 0x2e, 0xa5, 0x80, 0x0a, 0x78, 
+0x8d, 0xe6, 0xff, 0x12, 0x2c, 0x25, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x8f, 0x67, 0x12, 0x2c, 
+0x25, 0xaf, 0x67, 0x12, 0x27, 0x19, 0x12, 0x20, 0x38, 0x12, 0x2f, 0x80, 0x74, 0x74, 0x25, 0x67, 
+0xf8, 0x74, 0xfd, 0x56, 0xf6, 0xaf, 0x67, 0x12, 0x19, 0xbb, 0x22, 0x12, 0x0f, 0x89, 0xe5, 0x31, 
+0x64, 0x09, 0x70, 0x04, 0xe5, 0x30, 0x64, 0x01, 0x60, 0x05, 0x12, 0x29, 0x2d, 0x80, 0x06, 0x12, 
+0x19, 0x7a, 0x12, 0x19, 0x82, 0x02, 0x10, 0x0c, 0x12, 0x27, 0xfb, 0x12, 0x12, 0x3b, 0x90, 0xf8, 
+0x04, 0xe0, 0xff, 0x60, 0x05, 0x7d, 0x01, 0x12, 0x11, 0xd8, 0x12, 0x26, 0xa3, 0x12, 0x12, 0x77, 
+0x12, 0x10, 0xfa, 0x80, 0xe3, 0x12, 0x18, 0xed, 0xef, 0x12, 0x14, 0x0d, 0xe4, 0xf5, 0x2a, 0xf5, 
+0x2b, 0xef, 0x60, 0x03, 0x02, 0x2f, 0x76, 0xe4, 0xff, 0x12, 0x2f, 0x6a, 0x22, 0x90, 0xff, 0xf0, 
+0xe0, 0xff, 0x54, 0xa0, 0x60, 0xf7, 0xef, 0x30, 0xe5, 0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, 
+0xc3, 0x22, 0xd3, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0xff, 0x54, 0x28, 0x60, 0xf7, 0xef, 0x30, 0xe5, 
+0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, 0xc3, 0x22, 0xd3, 0x22, 0xef, 0x30, 0xe7, 0x08, 0x12, 
+0x18, 0xad, 0xe0, 0x54, 0xdf, 0xf0, 0x22, 0xef, 0x12, 0x18, 0xf7, 0xe0, 0x54, 0xdf, 0xf0, 0x22, 
+0x81, 0x01, 0x82, 0x02, 0x83, 0x03, 0x87, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 
+0x00, 0x40, 0x00, 0x08, 0x00, 0x78, 0x84, 0x12, 0x20, 0x2f, 0xa3, 0xa3, 0xe0, 0xff, 0x30, 0xe7, 
+0x06, 0x54, 0x7f, 0xf0, 0x44, 0x80, 0xf0, 0x22, 0x85, 0x34, 0x30, 0x85, 0x35, 0x31, 0x90, 0xff, 
+0x82, 0xe0, 0x54, 0xf7, 0xf0, 0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0x22, 0xe4, 0xfe, 0xee, 0x90, 0x2f, 
+0x00, 0x93, 0xb5, 0x07, 0x02, 0xd3, 0x22, 0x0e, 0xbe, 0x07, 0xf2, 0xc3, 0x22, 0x00, 0x08, 0x18, 
+0x38, 0x28, 0x01, 0x81, 0x10, 0x0a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0f, 0x89, 0x7f, 
+0x02, 0x12, 0x10, 0x18, 0x12, 0x19, 0x55, 0x02, 0x10, 0x0c, 0x75, 0x30, 0x00, 0x8f, 0x31, 0x12, 
+0x18, 0x49, 0x12, 0x29, 0x2d, 0x22, 0x12, 0x19, 0x82, 0x12, 0x19, 0x3e, 0x12, 0x19, 0x7a, 0x22, 
+0xc2, 0x08, 0x22, 
+};
+
+#undef IMAGE_VERSION_NAME
+
+#undef IMAGE_ARRAY_NAME
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/io_ionsp.h linux-2.4.20/drivers/usb/serial/io_ionsp.h
--- linux-2.4.19/drivers/usb/serial/io_ionsp.h	2001-03-20 01:21:54.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/io_ionsp.h	2002-10-29 11:18:35.000000000 +0000
@@ -88,12 +88,12 @@
 // Interrupt pipe
 //
 
-typedef struct _INT_STATUS_PKT {
+struct int_status_pkt {
 	__u16      RxBytesAvail;		    // Additional bytes available to
 						    // be read from Bulk IN pipe
 	__u16      TxCredits[ MAX_RS232_PORTS ];   // Additional space available in
 						    // given port's TxBuffer
-} INT_STATUS_PKT, *PINT_STATUS_PKT;
+};
 
 
 #define GET_INT_STATUS_SIZE(NumPorts) (sizeof(__u16) + (sizeof(__u16) * (NumPorts)))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/io_tables.h linux-2.4.20/drivers/usb/serial/io_tables.h
--- linux-2.4.19/drivers/usb/serial/io_tables.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/io_tables.h	2002-10-29 11:18:32.000000000 +0000
@@ -14,12 +14,12 @@
 #ifndef IO_TABLES_H
 #define IO_TABLES_H
 
-static __devinitdata struct usb_device_id edgeport_1port_id_table [] = {
+static struct usb_device_id edgeport_1port_id_table [] = {
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_PARALLEL_PORT) },
 	{ }
 };
 
-static __devinitdata struct usb_device_id edgeport_2port_id_table [] = {
+static struct usb_device_id edgeport_2port_id_table [] = {
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) },
@@ -33,7 +33,7 @@
 	{ }
 };
 
-static __devinitdata struct usb_device_id edgeport_4port_id_table [] = {
+static struct usb_device_id edgeport_4port_id_table [] = {
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) },
@@ -50,7 +50,7 @@
 	{ }
 };
 
-static __devinitdata struct usb_device_id edgeport_8port_id_table [] = {
+static struct usb_device_id edgeport_8port_id_table [] = {
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) },
@@ -98,11 +98,9 @@
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
 static struct usb_serial_device_type edgeport_1port_device = {
+	owner:			THIS_MODULE,
 	name:			"Edgeport 1 port adapter",
 	id_table:		edgeport_1port_id_table,
-	needs_interrupt_in:	MUST_HAVE,
-	needs_bulk_in:		MUST_HAVE,
-	needs_bulk_out:		MUST_HAVE,
 	num_interrupt_in:	1,
 	num_bulk_in:		1,
 	num_bulk_out:		1,
@@ -122,11 +120,9 @@
 };
 
 static struct usb_serial_device_type edgeport_2port_device = {
+	owner:			THIS_MODULE,
 	name:			"Edgeport 2 port adapter",
 	id_table:		edgeport_2port_id_table,
-	needs_interrupt_in:	MUST_HAVE,
-	needs_bulk_in:		MUST_HAVE,
-	needs_bulk_out:		MUST_HAVE,
 	num_interrupt_in:	1,
 	num_bulk_in:		1,
 	num_bulk_out:		1,
@@ -146,11 +142,9 @@
 };
 
 static struct usb_serial_device_type edgeport_4port_device = {
+	owner:			THIS_MODULE,
 	name:			"Edgeport 4 port adapter",
 	id_table:		edgeport_4port_id_table,
-	needs_interrupt_in:	MUST_HAVE,
-	needs_bulk_in:		MUST_HAVE,
-	needs_bulk_out:		MUST_HAVE,
 	num_interrupt_in:	1,
 	num_bulk_in:		1,
 	num_bulk_out:		1,
@@ -170,11 +164,9 @@
 };
 
 static struct usb_serial_device_type edgeport_8port_device = {
+	owner:			THIS_MODULE,
 	name:			"Edgeport 8 port adapter",
 	id_table:		edgeport_8port_id_table,
-	needs_interrupt_in:	MUST_HAVE,
-	needs_bulk_in:		MUST_HAVE,
-	needs_bulk_out:		MUST_HAVE,
 	num_interrupt_in:	1,
 	num_bulk_in:		1,
 	num_bulk_out:		1,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/io_ti.c linux-2.4.20/drivers/usb/serial/io_ti.c
--- linux-2.4.19/drivers/usb/serial/io_ti.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/io_ti.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,2684 @@
+/*
+ * Edgeport USB Serial Converter driver
+ *
+ * Copyright(c) 2000-2002 Inside Out Networks, All rights reserved.
+ * Copyright(c) 2001-2002 Greg Kroah-Hartman <greg@kroah.com>
+ *
+ *	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.
+ *
+ * Supports the following devices:
+ *	EP/1 EP/2 EP/4
+ *
+ * Version history:
+ *
+ *	July 11, 2002 	Removed 4 port device structure since all TI UMP 
+ *			chips have only 2 ports 
+ *			David Iacovelli (davidi@ionetworks.com)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/serial.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/usb.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	static int debug = 1;
+#else
+	static int debug;
+#endif
+
+#include "usb-serial.h"
+
+#include "io_16654.h"
+#include "io_usbvend.h"
+#include "io_ti.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.2"
+#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"
+#define DRIVER_DESC "Edgeport USB Serial Driver"
+
+
+/* firmware image code */
+#define IMAGE_VERSION_NAME	PagableOperationalCodeImageVersion
+#define IMAGE_ARRAY_NAME	PagableOperationalCodeImage
+#define IMAGE_SIZE		PagableOperationalCodeSize
+#include "io_fw_down3.h"	/* Define array OperationalCodeImage[] */
+
+#define EPROM_PAGE_SIZE		64
+
+
+struct edgeport_uart_buf_desc {
+	__u32 count;		// Number of bytes currently in buffer
+};
+
+/* different hardware types */
+#define HARDWARE_TYPE_930	0
+#define HARDWARE_TYPE_TIUMP	1
+
+// IOCTL_PRIVATE_TI_GET_MODE Definitions
+#define	TI_MODE_CONFIGURING	0   // Device has not entered start device 
+#define	TI_MODE_BOOT		1   // Staying in boot mode
+#define TI_MODE_DOWNLOAD	2   // Made it to download mode
+#define TI_MODE_TRANSITIONING	3   // Currently in boot mode but transitioning to download mode
+
+
+/* Product information read from the Edgeport */
+struct product_info
+{
+	int	TiMode;			// Current TI Mode
+	__u8	hardware_type;		// Type of hardware
+} __attribute__((packed));
+
+
+struct edgeport_port {
+	__u16 uart_base;
+	__u16 dma_address;
+	__u8 shadow_msr;
+	__u8 shadow_mcr;
+	__u8 shadow_lsr;
+	__u8 lsr_mask;
+	__u32 ump_read_timeout;		/* Number of miliseconds the UMP will
+					   wait without data before completing
+					   a read short */
+	int baud_rate;
+	int close_pending;
+	int lsr_event;
+	struct edgeport_uart_buf_desc tx;
+	struct async_icount	icount;
+	wait_queue_head_t	delta_msr_wait;	/* for handling sleeping while
+						   waiting for msr change to
+						   happen */
+	struct edgeport_serial	*edge_serial;
+	struct usb_serial_port	*port;
+};
+
+struct edgeport_serial {
+	struct product_info product_info;
+	u8 TI_I2C_Type;			// Type of I2C in UMP
+	u8 TiReadI2C;			// Set to TRUE if we have read the I2c in Boot Mode
+	int num_ports_open;
+	struct usb_serial *serial;
+};
+
+
+/* Devices that this driver supports */
+static struct usb_device_id edgeport_1port_id_table [] = {
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
+	{ }
+};
+
+static struct usb_device_id edgeport_2port_id_table [] = {
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_BOOT) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_DOWN) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_BOOT) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_DOWN) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_42) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22) },
+	{ }
+};
+
+/* Devices that this driver supports */
+static __devinitdata struct usb_device_id id_table_combined [] = {
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_BOOT) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_DOWN) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_BOOT) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_DOWN) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_42) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22) },
+	{ }
+};
+
+MODULE_DEVICE_TABLE (usb, id_table_combined);
+
+
+static struct EDGE_FIRMWARE_VERSION_INFO OperationalCodeImageVersion;
+
+static int TIStayInBootMode = 0;
+static int ignore_cpu_rev = 0;
+
+
+
+static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+
+static int TIReadVendorRequestSync (struct usb_device *dev,
+				__u8		request,
+				__u16		value,
+				__u16		index,
+				u8 		*data,
+				int		size)
+{
+	int status;
+
+	status = usb_control_msg (dev,
+				usb_rcvctrlpipe(dev, 0),
+				request,
+				(USB_TYPE_VENDOR | 
+				 USB_RECIP_DEVICE | 
+				 USB_DIR_IN),
+				value,
+				index,
+				data,
+				size,
+				HZ);
+	if (status < 0)
+		return status;
+	if (status != size) {
+		dbg ("%s - wanted to write %d, but only wrote %d",
+		     __FUNCTION__, size, status);
+		return -ECOMM;
+	}
+	return 0;
+}
+
+static int TISendVendorRequestSync (struct usb_device *dev,
+				__u8		request,
+				__u16		value,
+				__u16		index,
+				u8 		*data,
+				int		size)
+{
+	int status;
+
+	status = usb_control_msg (dev,
+				usb_sndctrlpipe(dev, 0),
+				request,
+				(USB_TYPE_VENDOR | 
+				 USB_RECIP_DEVICE | 
+				 USB_DIR_OUT),
+				value,
+				index,
+				data,
+				size,
+				HZ);
+
+	if (status < 0)
+		return status;
+	if (status != size) {
+		dbg ("%s - wanted to write %d, but only wrote %d",
+		     __FUNCTION__, size, status);
+		return -ECOMM;
+	}
+	return 0;
+}
+
+static int TIWriteCommandSync (struct usb_device *dev, __u8 command,
+				__u8 moduleid, __u16 value, u8 *data,
+				int size)
+{
+	return TISendVendorRequestSync (dev,
+					  command,	  		// Request
+					  value,			// wValue 
+					  moduleid,			// wIndex
+					  data,				// TransferBuffer
+					  size);			// TransferBufferLength
+
+}
+
+
+/* clear tx/rx buffers and fifo in TI UMP */
+static int TIPurgeDataSync (struct usb_serial_port *port, __u16 mask)
+{
+	int port_number = port->number - port->serial->minor;
+
+	dbg ("%s - port %d, mask %x", __FUNCTION__, port_number, mask);
+
+	return TIWriteCommandSync (port->serial->dev,
+					UMPC_PURGE_PORT,
+					(__u8)(UMPM_UART1_PORT + port_number),
+					mask,
+					NULL,
+					0);
+}
+
+/**
+ * TIReadDownloadMemory - Read edgeport memory from TI chip
+ * @dev: usb device pointer
+ * @address: Device CPU address at which to read
+ * @length: Length of above data
+ * @address_type: Can read both XDATA and I2C
+ * @buffer: pointer to input data buffer
+ */
+int TIReadDownloadMemory (struct usb_device *dev, int start_address, int length,
+			  __u8 address_type, __u8 *buffer)
+{
+	int status = 0;
+	__u8 read_length;
+	__u16 be_start_address;
+	
+	dbg ("%s - @ %x for %d", __FUNCTION__, start_address, length);
+
+	/* Read in blocks of 64 bytes
+	 * (TI firmware can't handle more than 64 byte reads)
+	 */
+	while (length) {
+		if (length > 64)
+			read_length= 64;
+		else
+			read_length = (__u8)length;
+
+		if (read_length > 1) {
+			dbg ("%s - @ %x for %d", __FUNCTION__, 
+			     start_address, read_length);
+		}
+		be_start_address = cpu_to_be16 (start_address);
+		status = TIReadVendorRequestSync (dev,
+						  UMPC_MEMORY_READ,	// Request
+						  (__u16)address_type,	// wValue (Address type)
+						  be_start_address,	// wIndex (Address to read)
+						  buffer,		// TransferBuffer
+						  read_length);	// TransferBufferLength
+
+		if (status) {
+			dbg ("%s - ERROR %x", __FUNCTION__, status);
+			return status;
+		}
+
+		if (read_length > 1) {
+			usb_serial_debug_data (__FILE__, __FUNCTION__,
+					       read_length, buffer);
+		}
+
+		/* Update pointers/length */
+		start_address += read_length;
+		buffer += read_length;
+		length -= read_length;
+	}
+	
+	return status;
+}
+
+int TIReadRam (struct usb_device *dev, int start_address, int length, __u8 *buffer)
+{
+	return TIReadDownloadMemory (dev,
+				     start_address,
+				     length,
+				     DTK_ADDR_SPACE_XDATA,
+				     buffer);
+}
+
+/* Read edgeport memory to a given block */
+static int TIReadBootMemory (struct edgeport_serial *serial, int start_address, int length, __u8 * buffer)
+{
+	int status = 0;
+	int i;
+
+	for (i=0; i< length; i++) {
+		status = TIReadVendorRequestSync (serial->serial->dev,
+					UMPC_MEMORY_READ,		// Request
+					serial->TI_I2C_Type,		// wValue (Address type)
+					(__u16)(start_address+i),	// wIndex
+					&buffer[i],			// TransferBuffer
+					0x01);				// TransferBufferLength
+		if (status) {
+			dbg ("%s - ERROR %x", __FUNCTION__, status);
+			return status;
+		}
+	}
+
+	dbg ("%s - start_address = %x, length = %d", __FUNCTION__, start_address, length);
+	usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer);
+
+	serial->TiReadI2C = 1;
+
+	return status;
+}
+
+/* Write given block to TI EPROM memory */
+static int TIWriteBootMemory (struct edgeport_serial *serial, int start_address, int length, __u8 *buffer)
+{
+	int status = 0;
+	int i;
+	__u8 temp;
+
+	/* Must do a read before write */
+	if (!serial->TiReadI2C) {
+		status = TIReadBootMemory(serial, 0, 1, &temp);
+		if (status)
+			return status;
+	}
+
+	for (i=0; i < length; ++i) {
+		status = TISendVendorRequestSync (serial->serial->dev,
+						UMPC_MEMORY_WRITE,		// Request
+						buffer[i],			// wValue
+						(__u16)(i+start_address),	// wIndex
+						NULL,				// TransferBuffer
+						0);				// TransferBufferLength
+		if (status)
+			return status;
+	}
+
+  	dbg ("%s - start_sddr = %x, length = %d", __FUNCTION__, start_address, length);
+	usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer);
+
+	return status;
+}
+
+
+/* Write edgeport I2C memory to TI chip	*/
+static int TIWriteDownloadI2C (struct edgeport_serial *serial, int start_address, int length, __u8 address_type, __u8 *buffer)
+{
+	int status = 0;
+	int write_length;
+	__u16 be_start_address;
+
+	/* We can only send a maximum of 1 aligned byte page at a time */
+	
+	/* calulate the number of bytes left in the first page */
+	write_length = EPROM_PAGE_SIZE - (start_address & (EPROM_PAGE_SIZE - 1));
+
+	if (write_length > length)
+		write_length = length;
+
+	dbg ("%s - BytesInFirstPage Addr = %x, length = %d", __FUNCTION__, start_address, write_length);
+	usb_serial_debug_data (__FILE__, __FUNCTION__, write_length, buffer);
+
+	/* Write first page */
+	be_start_address = cpu_to_be16 (start_address);
+	status = TISendVendorRequestSync (serial->serial->dev,
+					UMPC_MEMORY_WRITE,	// Request
+					(__u16)address_type,	// wValue
+					be_start_address,	// wIndex
+					buffer,			// TransferBuffer
+					write_length);
+	if (status) {
+		dbg ("%s - ERROR %d", __FUNCTION__, status);
+		return status;
+	}
+
+	length		-= write_length;
+	start_address	+= write_length;
+	buffer		+= write_length;
+
+	/* We should be aligned now -- can write max page size bytes at a time */
+	while (length) {
+		if (length > EPROM_PAGE_SIZE)
+			write_length = EPROM_PAGE_SIZE;
+		else
+			write_length = length;
+
+		dbg ("%s - Page Write Addr = %x, length = %d", __FUNCTION__, start_address, write_length);
+		usb_serial_debug_data (__FILE__, __FUNCTION__, write_length, buffer);
+
+		/* Write next page */
+		be_start_address = cpu_to_be16 (start_address);
+		status = TISendVendorRequestSync (serial->serial->dev,
+						UMPC_MEMORY_WRITE,	// Request
+						(__u16)address_type,	// wValue
+						be_start_address,	// wIndex
+						buffer,	  		// TransferBuffer
+						write_length);		// TransferBufferLength
+		if (status) {
+			dbg ("%s - ERROR %d", __FUNCTION__, status);
+			return status;
+		}
+		
+		length		-= write_length;
+		start_address	+= write_length;
+		buffer		+= write_length;
+	}
+	return status;
+}
+
+/* Examine the UMP DMA registers and LSR
+ * 
+ * Check the MSBit of the X and Y DMA byte count registers.
+ * A zero in this bit indicates that the TX DMA buffers are empty
+ * then check the TX Empty bit in the UART.
+ */
+static int TIIsTxActive (struct edgeport_port *port)
+{
+	int status;
+	struct out_endpoint_desc_block *oedb;
+	__u8 lsr;
+	int bytes_left = 0;
+
+	oedb = kmalloc (sizeof (* oedb), GFP_KERNEL);
+	if (!oedb) {
+		err ("%s - out of memory", __FUNCTION__);
+		return -ENOMEM;
+	}
+
+	/* Read the DMA Count Registers */
+	status = TIReadRam (port->port->serial->dev,
+			    port->dma_address,
+			    sizeof( *oedb),
+			    (void *)oedb);
+
+	if (status)
+		goto exit_is_tx_active;
+
+	dbg ("%s - XByteCount    0x%X", __FUNCTION__, oedb->XByteCount);
+
+	/* and the LSR */
+	status = TIReadRam (port->port->serial->dev, 
+			    port->uart_base + UMPMEM_OFFS_UART_LSR,
+			    1,
+			    &lsr);
+
+	if (status)
+		goto exit_is_tx_active;
+	dbg ("%s - LSR = 0x%X", __FUNCTION__, lsr);
+	
+	/* If either buffer has data or we are transmitting then return TRUE */
+	if ((oedb->XByteCount & 0x80 ) != 0 )
+		bytes_left += 64;
+
+	if ((lsr & UMP_UART_LSR_TX_MASK ) == 0 )
+		bytes_left += 1;
+
+	/* We return Not Active if we get any kind of error */
+exit_is_tx_active:
+	dbg ("%s - return %d", __FUNCTION__, bytes_left );
+	return bytes_left;
+}
+
+static void TIChasePort(struct edgeport_port *port)
+{
+	int loops;
+	int last_count;
+	int write_size;
+
+restart_tx_loop:
+	// Base the LoopTime on the baud rate
+	if (port->baud_rate == 0)
+		port->baud_rate = 1200;
+
+	write_size = port->tx.count;
+	loops = max(100, (100*write_size)/(port->baud_rate/10));
+	dbg ("%s - write_size %d, baud %d loop = %d", __FUNCTION__,
+	     write_size, port->baud_rate, loops);
+
+	while (1) {
+		// Save Last count
+		last_count = port->tx.count;
+
+		dbg ("%s - Tx Buffer Size = %d loops = %d", __FUNCTION__,
+		     last_count, loops);
+
+		/* Is the Edgeport Buffer empty? */
+		if (port->tx.count == 0)
+			break;
+
+		/* Block the thread for 10ms */
+		wait_ms (10);
+
+		if (last_count == port->tx.count) {
+			/* No activity.. count down. */
+			--loops;
+			if (loops == 0) {
+				dbg ("%s - Wait for TxEmpty - TIMEOUT",
+				     __FUNCTION__);
+				return;
+			}
+		} else {
+			/* Reset timeout value back to a minimum of 1 second */
+			dbg ("%s - Wait for TxEmpty  Reset Count", __FUNCTION__);
+			goto restart_tx_loop;
+		}
+	}
+
+	dbg ("%s - Local Tx Buffer Empty -- Waiting for TI UMP to EMPTY X/Y and FIFO",
+	     __FUNCTION__);
+
+	write_size = TIIsTxActive (port);
+	loops = max(50, (100*write_size)/(port->baud_rate/10));
+	dbg ("%s - write_size %d, baud %d loop = %d", __FUNCTION__, 
+	     write_size, port->baud_rate, loops);
+
+	while (1) {
+		/* This function takes 4 ms; */
+		if (!TIIsTxActive (port)) {
+			/* Delay a few char times */
+			wait_ms (50);
+			dbg ("%s - Empty", __FUNCTION__);
+			return;
+		}
+
+		--loops;
+		if (loops == 0) {
+			dbg ("%s - TIMEOUT", __FUNCTION__);
+			return;
+		}
+	}
+}
+
+static int TIChooseConfiguration (struct usb_device *dev)
+{
+	// There may be multiple configurations on this device, in which case
+	// we would need to read and parse all of them to find out which one
+	// we want. However, we just support one config at this point,
+	// configuration # 1, which is Config Descriptor 0.
+
+	dbg ("%s - Number of Interfaces = %d", __FUNCTION__, dev->config->bNumInterfaces);
+	dbg ("%s - MAX Power            = %d", __FUNCTION__, dev->config->MaxPower*2);
+
+	if (dev->config->bNumInterfaces != 1) {
+		err ("%s - bNumInterfaces is not 1, ERROR!", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+int TIReadRom (struct edgeport_serial *serial, int start_address, int length, __u8 *buffer)
+{
+	int status;
+
+	if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) {
+		status = TIReadDownloadMemory (serial->serial->dev,
+					       start_address,
+					       length,
+					       serial->TI_I2C_Type,
+					       buffer);
+	} else {
+		status = TIReadBootMemory (serial,
+					   start_address,
+					   length,
+					   buffer);
+	}
+
+	return status;
+}
+
+int TIWriteRom (struct edgeport_serial *serial, int start_address, int length, __u8 *buffer)
+{
+	if (serial->product_info.TiMode == TI_MODE_BOOT)
+		return TIWriteBootMemory (serial,
+					  start_address,
+					  length,
+					  buffer);
+
+	if (serial->product_info.TiMode == TI_MODE_DOWNLOAD)
+		return TIWriteDownloadI2C (serial,
+					   start_address,
+					   length,
+					   serial->TI_I2C_Type,
+					   buffer);
+
+	return -EINVAL;
+}
+
+
+
+/* Read a descriptor header from I2C based on type */
+static int TIGetDescriptorAddress (struct edgeport_serial *serial, int desc_type, struct ti_i2c_desc *rom_desc)
+{
+	int start_address;
+	int status;
+
+	/* Search for requested descriptor in I2C */
+	start_address = 2;
+	do {
+		status = TIReadRom (serial,
+				   start_address,
+				   sizeof(struct ti_i2c_desc),
+				   (__u8 *)rom_desc );
+		if (status)
+			return 0;
+
+		if (rom_desc->Type == desc_type)
+			return start_address;
+
+		start_address = start_address + sizeof(struct ti_i2c_desc) +  rom_desc->Size;
+
+	} while ((start_address < TI_MAX_I2C_SIZE) && rom_desc->Type);
+	
+	return 0;
+}
+
+/* Validate descriptor checksum */
+static int ValidChecksum(struct ti_i2c_desc *rom_desc, __u8 *buffer)
+{
+	__u16 i;
+	__u8 cs = 0;
+
+	for (i=0; i < rom_desc->Size; i++) {
+		cs = (__u8)(cs + buffer[i]);
+	}
+	if (cs != rom_desc->CheckSum) {
+		dbg ("%s - Mismatch %x - %x", __FUNCTION__, rom_desc->CheckSum, cs);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* Make sure that the I2C image is good */
+static int TiValidateI2cImage (struct edgeport_serial *serial)
+{
+	int status = 0;
+	struct ti_i2c_desc *rom_desc;
+	int start_address = 2;
+	__u8 *buffer;
+
+	rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL);
+	if (!rom_desc) {
+		err ("%s - out of memory", __FUNCTION__);
+		return -ENOMEM;
+	}
+	buffer = kmalloc (TI_MAX_I2C_SIZE, GFP_KERNEL);
+	if (!buffer) {
+		err ("%s - out of memory when allocating buffer", __FUNCTION__);
+		kfree (rom_desc);
+		return -ENOMEM;
+	}
+
+	// Read the first byte (Signature0) must be 0x52
+	status = TIReadRom (serial, 0, 1, buffer);
+	if (status)
+		goto ExitTiValidateI2cImage; 
+
+	if (*buffer != 0x52) {
+		err ("%s - invalid buffer signature", __FUNCTION__);
+		status = -ENODEV;
+		goto ExitTiValidateI2cImage;
+	}
+
+	do {
+		// Validate the I2C
+		status = TIReadRom (serial,
+				start_address,
+				sizeof(struct ti_i2c_desc),
+				(__u8 *)rom_desc);
+		if (status)
+			break;
+
+		if ((start_address + sizeof(struct ti_i2c_desc) + rom_desc->Size) > TI_MAX_I2C_SIZE) {
+			status = -ENODEV;
+			dbg ("%s - structure too big, erroring out.", __FUNCTION__);
+			break;
+		}
+
+		dbg ("%s Type = 0x%x", __FUNCTION__, rom_desc->Type);
+
+		// Skip type 2 record
+		if ((rom_desc->Type & 0x0f) != I2C_DESC_TYPE_FIRMWARE_BASIC) {
+			// Read the descriptor data
+			status = TIReadRom(serial,
+						start_address+sizeof(struct ti_i2c_desc),
+						rom_desc->Size,
+						buffer);
+			if (status)
+				break;
+
+			status = ValidChecksum(rom_desc, buffer);
+			if (status)
+				break;
+		}
+		start_address = start_address + sizeof(struct ti_i2c_desc) + rom_desc->Size;
+
+	} while ((rom_desc->Type != I2C_DESC_TYPE_ION) && (start_address < TI_MAX_I2C_SIZE));
+
+	if ((rom_desc->Type != I2C_DESC_TYPE_ION) || (start_address > TI_MAX_I2C_SIZE))
+		status = -ENODEV;
+
+ExitTiValidateI2cImage:	
+	kfree (buffer);
+	kfree (rom_desc);
+	return status;
+}
+
+static int TIReadManufDescriptor (struct edgeport_serial *serial, __u8 *buffer)
+{
+	int status;
+	int start_address;
+	struct ti_i2c_desc *rom_desc;
+	struct edge_ti_manuf_descriptor *desc;
+
+	rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL);
+	if (!rom_desc) {
+		err ("%s - out of memory", __FUNCTION__);
+		return -ENOMEM;
+	}
+	start_address = TIGetDescriptorAddress (serial, I2C_DESC_TYPE_ION, rom_desc);
+
+	if (!start_address) {
+		dbg ("%s - Edge Descriptor not found in I2C", __FUNCTION__);
+		status = -ENODEV;
+		goto exit;
+	}
+
+	// Read the descriptor data
+	status = TIReadRom (serial,
+				start_address+sizeof(struct ti_i2c_desc),
+				rom_desc->Size,
+				buffer);
+	if (status)
+		goto exit;
+	
+	status = ValidChecksum(rom_desc, buffer);
+	
+	desc = (struct edge_ti_manuf_descriptor *)buffer;
+	dbg ( "%s - IonConfig      0x%x", __FUNCTION__, desc->IonConfig 	);
+	dbg ( "%s - Version          %d", __FUNCTION__, desc->Version	  	);
+	dbg ( "%s - Cpu/Board      0x%x", __FUNCTION__, desc->CpuRev_BoardRev	);
+	dbg ( "%s - NumPorts         %d", __FUNCTION__, desc->NumPorts  	);	
+	dbg ( "%s - NumVirtualPorts  %d", __FUNCTION__, desc->NumVirtualPorts	);	
+	dbg ( "%s - TotalPorts       %d", __FUNCTION__, desc->TotalPorts  	);	
+
+exit:
+	kfree (rom_desc);
+	return status;
+}
+
+/* Build firmware header used for firmware update */
+static int BuildI2CFirmwareHeader (__u8 *header)
+{
+	__u8 *buffer;
+	int buffer_size;
+	int i;
+	__u8 cs = 0;
+	struct ti_i2c_desc *i2c_header;
+	struct ti_i2c_image_header *img_header;
+	struct ti_i2c_firmware_rec *firmware_rec;
+
+	// In order to update the I2C firmware we must change the type 2 record to type 0xF2.
+	// This will force the UMP to come up in Boot Mode.  Then while in boot mode, the driver 
+	// will download the latest firmware (padded to 15.5k) into the UMP ram. 
+	// And finally when the device comes back up in download mode the driver will cause 
+	// the new firmware to be copied from the UMP Ram to I2C and the firmware will update
+	// the record type from 0xf2 to 0x02.
+	
+	// Allocate a 15.5k buffer + 2 bytes for version number (Firmware Record)
+	buffer_size = (((1024 * 16) - 512 )+ sizeof(struct ti_i2c_firmware_rec));
+
+	buffer = kmalloc (buffer_size, GFP_KERNEL);
+	if (!buffer) {
+		err ("%s - out of memory", __FUNCTION__);
+		return -ENOMEM;
+	}
+	
+	// Set entire image of 0xffs
+	memset (buffer, 0xff, buffer_size);
+
+	// Copy version number into firmware record
+	firmware_rec = (struct ti_i2c_firmware_rec *)buffer;
+
+	firmware_rec->Ver_Major	= OperationalCodeImageVersion.MajorVersion;
+	firmware_rec->Ver_Minor	= OperationalCodeImageVersion.MinorVersion;
+
+	// Pointer to fw_down memory image
+	img_header = (struct ti_i2c_image_header *)&PagableOperationalCodeImage[0];
+
+	memcpy (buffer + sizeof(struct ti_i2c_firmware_rec),
+		&PagableOperationalCodeImage[sizeof(struct ti_i2c_image_header)],
+		img_header->Length);
+
+	for (i=0; i < buffer_size; i++) {
+		cs = (__u8)(cs + buffer[i]);
+	}
+
+	kfree (buffer);
+
+	// Build new header
+	i2c_header =  (struct ti_i2c_desc *)header;
+	firmware_rec =  (struct ti_i2c_firmware_rec*)i2c_header->Data;
+	
+	i2c_header->Type	= I2C_DESC_TYPE_FIRMWARE_BLANK;
+	i2c_header->Size	= (__u16)buffer_size;
+	i2c_header->CheckSum	= cs;
+	firmware_rec->Ver_Major	= OperationalCodeImageVersion.MajorVersion;
+	firmware_rec->Ver_Minor	= OperationalCodeImageVersion.MinorVersion;
+
+	return 0;
+}
+
+/* Try to figure out what type of I2c we have */
+static int TIGetI2cTypeInBootMode (struct edgeport_serial *serial)
+{
+	int status;
+	__u8 data;
+		
+	// Try to read type 2
+	status = TIReadVendorRequestSync (serial->serial->dev,
+					UMPC_MEMORY_READ,		// Request
+					DTK_ADDR_SPACE_I2C_TYPE_II,	// wValue (Address type)
+					0,		 		// wIndex
+					&data,				// TransferBuffer
+					0x01);				// TransferBufferLength
+	if (status)
+		dbg ("%s - read 2 status error = %d", __FUNCTION__, status);
+	else
+		dbg ("%s - read 2 data = 0x%x", __FUNCTION__, data);
+	if ((!status) && data == 0x52) {
+		dbg ("%s - ROM_TYPE_II", __FUNCTION__);
+		serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
+		return 0;
+	}
+
+	// Try to read type 3
+	status = TIReadVendorRequestSync (serial->serial->dev,
+					UMPC_MEMORY_READ,		// Request
+					DTK_ADDR_SPACE_I2C_TYPE_III,	// wValue (Address type)
+					0,				// wIndex
+					&data,				// TransferBuffer
+					0x01);				// TransferBufferLength
+	if (status)
+		dbg ("%s - read 3 status error = %d", __FUNCTION__, status);
+	else
+		dbg ("%s - read 2 data = 0x%x", __FUNCTION__, data);
+	if ((!status) && data == 0x52) {
+		dbg ("%s - ROM_TYPE_III", __FUNCTION__);
+		serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_III;
+		return 0;
+	}
+
+	dbg ("%s - Unknown", __FUNCTION__);
+	serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
+	return -ENODEV;
+}
+
+static int TISendBulkTransferSync (struct usb_serial *serial, void *buffer, int length, int *num_sent)
+{
+	int status;
+
+	status = usb_bulk_msg (serial->dev,
+				usb_sndbulkpipe(serial->dev,
+						serial->port[0].bulk_out_endpointAddress),
+				buffer,
+				length,
+				num_sent,
+				HZ);
+	return status;
+}
+
+/* Download given firmware image to the device (IN BOOT MODE) */
+static int TIDownloadCodeImage (struct edgeport_serial *serial, __u8 *image, int image_length)
+{
+	int status = 0;
+	int pos;
+	int transfer;
+	int done;
+
+	// Transfer firmware image
+	for (pos = 0; pos < image_length; ) {
+		// Read the next buffer from file
+		transfer = image_length - pos;
+		if (transfer > EDGE_FW_BULK_MAX_PACKET_SIZE)
+			transfer = EDGE_FW_BULK_MAX_PACKET_SIZE;
+
+		// Transfer data
+		status = TISendBulkTransferSync (serial->serial, &image[pos], transfer, &done);
+		if (status)
+			break;
+		// Advance buffer pointer
+		pos += done;
+	}
+
+	return status;
+}
+
+// FIXME!!!
+static int TIConfigureBootDevice (struct usb_device *dev)
+{
+	return 0;
+}
+
+/**
+ * DownloadTIFirmware - Download run-time operating firmware to the TI5052
+ * 
+ * This routine downloads the main operating code into the TI5052, using the
+ * boot code already burned into E2PROM or ROM.
+ */
+static int TIDownloadFirmware (struct edgeport_serial *serial)
+{
+	int status = 0;
+	int start_address;
+	struct edge_ti_manuf_descriptor *ti_manuf_desc;
+	struct usb_interface_descriptor *interface;
+	int download_cur_ver;
+	int download_new_ver;
+
+	/* This routine is entered by both the BOOT mode and the Download mode
+	 * We can determine which code is running by the reading the config
+	 * descriptor and if we have only one bulk pipe it is in boot mode
+	 */
+	serial->product_info.hardware_type = HARDWARE_TYPE_TIUMP;
+
+	/* Default to type 2 i2c */
+	serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
+
+	status = TIChooseConfiguration (serial->serial->dev);
+	if (status)
+		return status;
+
+	interface = serial->serial->dev->config->interface->altsetting;
+	if (!interface) {
+		err ("%s - no interface set, error!", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	// Setup initial mode -- the default mode 0 is TI_MODE_CONFIGURING
+	// if we have more than one endpoint we are definitely in download mode
+	if (interface->bNumEndpoints > 1)
+		serial->product_info.TiMode = TI_MODE_DOWNLOAD;
+	else
+		// Otherwise we will remain in configuring mode
+		serial->product_info.TiMode = TI_MODE_CONFIGURING;
+
+	// Save Download Version Number
+	OperationalCodeImageVersion.MajorVersion = PagableOperationalCodeImageVersion.MajorVersion;
+	OperationalCodeImageVersion.MinorVersion = PagableOperationalCodeImageVersion.MinorVersion;
+	OperationalCodeImageVersion.BuildNumber	 = PagableOperationalCodeImageVersion.BuildNumber;
+
+	/********************************************************************/
+	/* Download Mode */
+	/********************************************************************/
+	if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) {
+		struct ti_i2c_desc *rom_desc;
+
+		dbg ("%s - <<<<<<<<<<<<<<<RUNNING IN DOWNLOAD MODE>>>>>>>>>>", __FUNCTION__);
+
+		status = TiValidateI2cImage (serial);
+		if (status) {
+			dbg ("%s - <<<<<<<<<<<<<<<DOWNLOAD MODE -- BAD I2C >>>>>>>>>>",
+			     __FUNCTION__);
+			return status;
+		}
+		
+		/* Validate Hardware version number
+		 * Read Manufacturing Descriptor from TI Based Edgeport
+		 */
+		ti_manuf_desc = kmalloc (sizeof (*ti_manuf_desc), GFP_KERNEL);
+		if (!ti_manuf_desc) {
+			err ("%s - out of memory.", __FUNCTION__);
+			return -ENOMEM;
+		}
+		status = TIReadManufDescriptor (serial, (__u8 *)ti_manuf_desc);
+		if (status) {
+			kfree (ti_manuf_desc);
+			return status;
+		}
+
+		// Check version number of ION descriptor
+		if (!ignore_cpu_rev && TI_GET_CPU_REVISION(ti_manuf_desc->CpuRev_BoardRev) < 2) {
+			dbg ( "%s - Wrong CPU Rev %d (Must be 2)", __FUNCTION__, 
+			     TI_GET_CPU_REVISION(ti_manuf_desc->CpuRev_BoardRev));
+			kfree (ti_manuf_desc);
+		   	return -EINVAL;
+		}
+
+		rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL);
+		if (!rom_desc) {
+			err ("%s - out of memory.", __FUNCTION__);
+			kfree (ti_manuf_desc);
+			return -ENOMEM;
+		}
+
+		// Search for type 2 record (firmware record)
+		if ((start_address = TIGetDescriptorAddress (serial, I2C_DESC_TYPE_FIRMWARE_BASIC, rom_desc)) != 0) {
+			struct ti_i2c_firmware_rec *firmware_version;
+			__u8 record;
+
+			dbg ("%s - Found Type FIRMWARE (Type 2) record", __FUNCTION__);
+
+			firmware_version = kmalloc (sizeof (*firmware_version), GFP_KERNEL);
+			if (!firmware_version) {
+				err ("%s - out of memory.", __FUNCTION__);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return -ENOMEM;
+			}
+
+			// Validate version number				
+			// Read the descriptor data
+			status = TIReadRom (serial,
+					start_address+sizeof(struct ti_i2c_desc),
+					sizeof(struct ti_i2c_firmware_rec),
+					(__u8 *)firmware_version);
+			if (status) {
+				kfree (firmware_version);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return status;
+			}
+
+			// Check version number of download with current version in I2c
+			download_cur_ver = (firmware_version->Ver_Major << 8) + 
+					   (firmware_version->Ver_Minor);
+			download_new_ver = (OperationalCodeImageVersion.MajorVersion << 8) +
+					   (OperationalCodeImageVersion.MinorVersion);
+
+			dbg ("%s - >>>Firmware Versions Device %d.%d  Driver %d.%d",
+			     __FUNCTION__,
+			     firmware_version->Ver_Major,
+			     firmware_version->Ver_Minor,
+			     OperationalCodeImageVersion.MajorVersion,
+			     OperationalCodeImageVersion.MinorVersion);
+
+			// Check if we have an old version in the I2C and update if necessary
+			if (download_cur_ver != download_new_ver) {
+				dbg ("%s - Update I2C Download from %d.%d to %d.%d",
+				     __FUNCTION__,
+				     firmware_version->Ver_Major,
+				     firmware_version->Ver_Minor,
+				     OperationalCodeImageVersion.MajorVersion,
+				     OperationalCodeImageVersion.MinorVersion);
+
+				// In order to update the I2C firmware we must change the type 2 record to type 0xF2.
+				// This will force the UMP to come up in Boot Mode.  Then while in boot mode, the driver 
+				// will download the latest firmware (padded to 15.5k) into the UMP ram. 
+				// And finally when the device comes back up in download mode the driver will cause 
+				// the new firmware to be copied from the UMP Ram to I2C and the firmware will update
+				// the record type from 0xf2 to 0x02.
+
+				record = I2C_DESC_TYPE_FIRMWARE_BLANK;
+
+				// Change the I2C Firmware record type to 0xf2 to trigger an update
+				status = TIWriteRom (serial,
+							start_address,
+							sizeof(record),
+							&record);
+				if (status) {
+					kfree (firmware_version);
+					kfree (rom_desc);
+					kfree (ti_manuf_desc);
+					return status;
+				}
+
+				// verify the write -- must do this in order for write to 
+				// complete before we do the hardware reset
+				status = TIReadRom (serial,
+							start_address,
+							sizeof(record),
+							&record);
+
+				if (status) {
+					kfree (firmware_version);
+					kfree (rom_desc);
+					kfree (ti_manuf_desc);
+					return status;
+				}
+
+				if (record != I2C_DESC_TYPE_FIRMWARE_BLANK) {
+					err ("%s - error resetting device", __FUNCTION__);
+					kfree (firmware_version);
+					kfree (rom_desc);
+					kfree (ti_manuf_desc);
+					return -ENODEV;
+				}
+
+				dbg ("%s - HARDWARE RESET", __FUNCTION__);
+
+				// Reset UMP -- Back to BOOT MODE
+				status = TISendVendorRequestSync (serial->serial->dev,
+								UMPC_HARDWARE_RESET,	// Request
+								0,			// wValue
+								0,			// wIndex
+								NULL,			// TransferBuffer
+								0);			// TransferBufferLength
+
+				dbg ( "%s - HARDWARE RESET return %d", __FUNCTION__, status);
+
+				/* return an error on purpose. */
+				return -ENODEV;
+			}
+		}
+		// Search for type 0xF2 record (firmware blank record)
+		else if ((start_address = TIGetDescriptorAddress (serial, I2C_DESC_TYPE_FIRMWARE_BLANK, rom_desc)) != 0) {
+			#define HEADER_SIZE	(sizeof(struct ti_i2c_desc) + sizeof(struct ti_i2c_firmware_rec))
+			__u8 *header;
+			__u8 *vheader;
+
+			header  = kmalloc (HEADER_SIZE, GFP_KERNEL);
+			if (!header) {
+				err ("%s - out of memory.", __FUNCTION__);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return -ENOMEM;
+			}
+				
+			vheader = kmalloc (HEADER_SIZE, GFP_KERNEL);
+			if (!vheader) {
+				err ("%s - out of memory.", __FUNCTION__);
+				kfree (header);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return -ENOMEM;
+			}
+			
+			dbg ("%s - Found Type BLANK FIRMWARE (Type F2) record", __FUNCTION__);
+
+			// In order to update the I2C firmware we must change the type 2 record to type 0xF2.
+			// This will force the UMP to come up in Boot Mode.  Then while in boot mode, the driver 
+			// will download the latest firmware (padded to 15.5k) into the UMP ram. 
+			// And finally when the device comes back up in download mode the driver will cause 
+			// the new firmware to be copied from the UMP Ram to I2C and the firmware will update
+			// the record type from 0xf2 to 0x02.
+			status = BuildI2CFirmwareHeader(header);
+			if (status) {
+				kfree (vheader);
+				kfree (header);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return status;
+			}
+
+			// Update I2C with type 0xf2 record with correct size and checksum
+			status = TIWriteRom (serial,
+						start_address,
+						HEADER_SIZE,
+						header);
+			if (status) {
+				kfree (vheader);
+				kfree (header);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return status;
+			}
+
+			// verify the write -- must do this in order for write to 
+			// complete before we do the hardware reset
+			status = TIReadRom (serial,
+						start_address,
+						HEADER_SIZE,
+						vheader);
+
+			if (status) {
+				dbg ("%s - can't read header back", __FUNCTION__);
+				kfree (vheader);
+				kfree (header);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return status;
+			}
+			if (memcmp(vheader, header, HEADER_SIZE)) {
+				dbg ("%s - write download record failed", __FUNCTION__);
+				kfree (vheader);
+				kfree (header);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return status;
+			}
+
+			kfree (vheader);
+			kfree (header);
+
+			dbg ("%s - Start firmware update", __FUNCTION__);
+
+			// Tell firmware to copy download image into I2C 
+			status = TISendVendorRequestSync (serial->serial->dev,
+						UMPC_COPY_DNLD_TO_I2C,	// Request
+						0,			// wValue 
+						0,			// wIndex
+						NULL,			// TransferBuffer
+						0);			// TransferBufferLength
+
+		  	dbg ("%s - Update complete 0x%x", __FUNCTION__, status);
+			if (status) {
+				dbg ("%s - UMPC_COPY_DNLD_TO_I2C failed", __FUNCTION__);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return status;
+			}
+		}
+
+		// The device is running the download code
+		kfree (rom_desc);
+		kfree (ti_manuf_desc);
+		return 0;
+	}
+
+	/********************************************************************/
+	/* Boot Mode */
+	/********************************************************************/
+	dbg ("%s - <<<<<<<<<<<<<<<RUNNING IN BOOT MODE>>>>>>>>>>>>>>>",
+	     __FUNCTION__);
+
+	// Configure the TI device so we can use the BULK pipes for download
+	status = TIConfigureBootDevice (serial->serial->dev);
+	if (status)
+		return status;
+
+	if (serial->serial->dev->descriptor.idVendor != USB_VENDOR_ID_ION) {
+		dbg ("%s - VID = 0x%x", __FUNCTION__,
+		     serial->serial->dev->descriptor.idVendor);
+		serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
+		goto StayInBootMode;
+	}
+
+	// We have an ION device (I2c Must be programmed)
+	// Determine I2C image type
+	if (TIGetI2cTypeInBootMode(serial)) {
+		goto StayInBootMode;
+	}
+
+	// Registry variable set?
+	if (TIStayInBootMode) {
+		dbg ("%s - TIStayInBootMode", __FUNCTION__);
+		goto StayInBootMode;
+	}
+
+	// Check for ION Vendor ID and that the I2C is valid
+	if (!TiValidateI2cImage(serial)) {
+		struct ti_i2c_image_header *header;
+		int i;
+		__u8 cs = 0;
+		__u8 *buffer;
+		int buffer_size;
+
+		/* Validate Hardware version number
+		 * Read Manufacturing Descriptor from TI Based Edgeport
+		 */
+		ti_manuf_desc = kmalloc (sizeof (*ti_manuf_desc), GFP_KERNEL);
+		if (!ti_manuf_desc) {
+			err ("%s - out of memory.", __FUNCTION__);
+			return -ENOMEM;
+		}
+		status = TIReadManufDescriptor (serial, (__u8 *)ti_manuf_desc);
+		if (status) {
+			kfree (ti_manuf_desc);
+			goto StayInBootMode;
+		}
+
+		// Check for version 2
+		if (!ignore_cpu_rev && TI_GET_CPU_REVISION(ti_manuf_desc->CpuRev_BoardRev) < 2) {
+			dbg ("%s - Wrong CPU Rev %d (Must be 2)", __FUNCTION__,
+			     TI_GET_CPU_REVISION(ti_manuf_desc->CpuRev_BoardRev));
+			kfree (ti_manuf_desc);
+			goto StayInBootMode;
+		}
+
+		kfree (ti_manuf_desc);
+
+		// In order to update the I2C firmware we must change the type 2 record to type 0xF2.
+		// This will force the UMP to come up in Boot Mode.  Then while in boot mode, the driver 
+		// will download the latest firmware (padded to 15.5k) into the UMP ram. 
+		// And finally when the device comes back up in download mode the driver will cause 
+		// the new firmware to be copied from the UMP Ram to I2C and the firmware will update
+		// the record type from 0xf2 to 0x02.
+		
+		/*
+		 * Do we really have to copy the whole firmware image,
+		 * or could we do this in place!
+		 */
+
+		// Allocate a 15.5k buffer + 3 byte header
+		buffer_size = (((1024 * 16) - 512) + sizeof(struct ti_i2c_image_header));
+		buffer = kmalloc (buffer_size, GFP_KERNEL);
+		if (!buffer) {
+			err ("%s - out of memory", __FUNCTION__);
+			return -ENOMEM;
+		}
+		
+		// Initialize the buffer to 0xff (pad the buffer)
+		memset (buffer, 0xff, buffer_size);
+
+		memcpy (buffer, &PagableOperationalCodeImage[0], PagableOperationalCodeSize);
+
+		for(i = sizeof(struct ti_i2c_image_header); i < buffer_size; i++) {
+			cs = (__u8)(cs + buffer[i]);
+		}
+		
+		header = (struct ti_i2c_image_header *)buffer;
+		
+		// update length and checksum after padding
+		header->Length 	 = (__u16)(buffer_size - sizeof(struct ti_i2c_image_header));
+		header->CheckSum = cs;
+
+		// Download the operational code 
+		dbg ("%s - Downloading operational code image (TI UMP)", __FUNCTION__);
+		status = TIDownloadCodeImage (serial, buffer, buffer_size);
+
+		kfree (buffer);
+
+		if (status) {
+	  		dbg ("%s - Error downloading operational code image", __FUNCTION__);
+			return status;
+		}
+
+		// Device will reboot
+		serial->product_info.TiMode = TI_MODE_TRANSITIONING;
+
+  		dbg ("%s - Download successful -- Device rebooting...", __FUNCTION__);
+
+		/* return an error on purpose */
+		return -ENODEV;
+	}
+
+StayInBootMode:
+	// Eprom is invalid or blank stay in boot mode
+	dbg ("%s - <<<<<<<<<<<<<<<STAYING IN BOOT MODE>>>>>>>>>>>>", __FUNCTION__);
+	serial->product_info.TiMode = TI_MODE_BOOT;
+
+	return 0;
+}
+
+
+static int TISetDtr (struct edgeport_port *port)
+{
+	int port_number = port->port->number - port->port->serial->minor;
+
+	dbg ("%s", __FUNCTION__);
+	port->shadow_mcr |= MCR_DTR;
+
+	return TIWriteCommandSync (port->port->serial->dev,
+				UMPC_SET_CLR_DTR,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				1,	/* set */
+				NULL,
+				0);
+}
+
+static int TIClearDtr (struct edgeport_port *port)
+{
+	int port_number = port->port->number - port->port->serial->minor;
+
+	dbg ("%s", __FUNCTION__);
+	port->shadow_mcr &= ~MCR_DTR;
+
+	return TIWriteCommandSync (port->port->serial->dev,
+				UMPC_SET_CLR_DTR,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				0,	/* clear */
+				NULL,
+				0);
+}
+
+static int TISetRts (struct edgeport_port *port)
+{
+	int port_number = port->port->number - port->port->serial->minor;
+
+	dbg ("%s", __FUNCTION__);
+	port->shadow_mcr |= MCR_RTS;
+
+	return TIWriteCommandSync (port->port->serial->dev,
+				UMPC_SET_CLR_RTS,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				1,	/* set */
+				NULL,
+				0);
+}
+
+static int TIClearRts (struct edgeport_port *port)
+{
+	int port_number = port->port->number - port->port->serial->minor;
+
+	dbg ("%s", __FUNCTION__);
+	port->shadow_mcr &= ~MCR_RTS;
+
+	return TIWriteCommandSync (port->port->serial->dev,
+				UMPC_SET_CLR_RTS,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				0,	/* clear */
+				NULL,
+				0);
+}
+
+static int TISetLoopBack (struct edgeport_port *port)
+{
+	int port_number = port->port->number - port->port->serial->minor;
+
+	dbg ("%s", __FUNCTION__);
+
+	return TIWriteCommandSync (port->port->serial->dev,
+				UMPC_SET_CLR_LOOPBACK,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				1,	/* set */
+				NULL,
+				0);
+}
+
+static int TIClearLoopBack (struct edgeport_port *port)
+{
+	int port_number = port->port->number - port->port->serial->minor;
+
+	dbg ("%s", __FUNCTION__);
+
+	return TIWriteCommandSync (port->port->serial->dev,
+				UMPC_SET_CLR_LOOPBACK,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				0,	/* clear */
+				NULL,
+				0);
+}
+
+static int TISetBreak (struct edgeport_port *port)
+{
+	int port_number = port->port->number - port->port->serial->minor;
+
+	dbg ("%s", __FUNCTION__);
+
+	return TIWriteCommandSync (port->port->serial->dev,
+				UMPC_SET_CLR_BREAK,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				1,	/* set */
+				NULL,
+				0);
+}
+
+static int TIClearBreak (struct edgeport_port *port)
+{
+	int port_number = port->port->number - port->port->serial->minor;
+
+	dbg ("%s", __FUNCTION__);
+
+	return TIWriteCommandSync (port->port->serial->dev,
+				UMPC_SET_CLR_BREAK,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				0,	/* clear */
+				NULL,
+				0);
+}
+
+static int TIRestoreMCR (struct edgeport_port *port, __u8 mcr)
+{
+	int status = 0;
+
+	dbg ("%s - %x", __FUNCTION__, mcr);
+
+	if (mcr & MCR_DTR)
+		status = TISetDtr (port);
+	else
+		status = TIClearDtr (port);
+
+	if (status)
+		return status;
+
+	if (mcr & MCR_RTS)
+		status = TISetRts (port);
+	else
+		status = TIClearRts (port);
+
+	if (status)
+		return status;
+
+	if (mcr & MCR_LOOPBACK)
+		status = TISetLoopBack (port);
+	else
+		status = TIClearLoopBack (port);
+
+	return status;
+}
+
+
+
+/* Convert TI LSR to standard UART flags */
+static __u8 MapLineStatus (__u8 ti_lsr)
+{
+	__u8 lsr = 0;
+
+#define MAP_FLAG(flagUmp, flagUart)    \
+	if (ti_lsr & flagUmp) lsr |= flagUart;
+
+	MAP_FLAG(UMP_UART_LSR_OV_MASK, LSR_OVER_ERR)	/* overrun */
+	MAP_FLAG(UMP_UART_LSR_PE_MASK, LSR_PAR_ERR)	/* parity error */
+	MAP_FLAG(UMP_UART_LSR_FE_MASK, LSR_FRM_ERR)	/* framing error */
+	MAP_FLAG(UMP_UART_LSR_BR_MASK, LSR_BREAK)	/* break detected */
+	MAP_FLAG(UMP_UART_LSR_RX_MASK, LSR_RX_AVAIL)	/* receive data available */
+	MAP_FLAG(UMP_UART_LSR_TX_MASK, LSR_TX_EMPTY)	/* transmit holding register empty */
+
+#undef MAP_FLAG
+
+	return lsr;
+}
+
+static void handle_new_msr (struct edgeport_port *edge_port, __u8 msr)
+{
+	struct async_icount *icount;
+
+	dbg ("%s - %02x", __FUNCTION__, msr);
+
+	if (msr & (MSR_DELTA_CTS | MSR_DELTA_DSR | MSR_DELTA_RI | MSR_DELTA_CD)) {
+		icount = &edge_port->icount;
+
+		/* update input line counters */
+		if (msr & MSR_DELTA_CTS)
+			icount->cts++;
+		if (msr & MSR_DELTA_DSR)
+			icount->dsr++;
+		if (msr & MSR_DELTA_CD)
+			icount->dcd++;
+		if (msr & MSR_DELTA_RI)
+			icount->rng++;
+		wake_up_interruptible (&edge_port->delta_msr_wait);
+	}
+
+	/* Save the new modem status */
+	edge_port->shadow_msr = msr & 0xf0;
+
+	return;
+}
+
+static void handle_new_lsr (struct edgeport_port *edge_port, int lsr_data, __u8 lsr, __u8 data)
+{
+	struct async_icount *icount;
+	__u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK));
+
+	dbg ("%s - %02x", __FUNCTION__, new_lsr);
+
+	edge_port->shadow_lsr = lsr;
+
+	if (new_lsr & LSR_BREAK) {
+		/*
+		 * Parity and Framing errors only count if they
+		 * occur exclusive of a break being received.
+		 */
+		new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK);
+	}
+
+	/* Place LSR data byte into Rx buffer */
+	if (lsr_data && edge_port->port->tty) {
+		tty_insert_flip_char(edge_port->port->tty, data, 0);
+		tty_flip_buffer_push(edge_port->port->tty);
+	}
+
+	/* update input line counters */
+	icount = &edge_port->icount;
+	if (new_lsr & LSR_BREAK)
+		icount->brk++;
+	if (new_lsr & LSR_OVER_ERR)
+		icount->overrun++;
+	if (new_lsr & LSR_PAR_ERR)
+		icount->parity++;
+	if (new_lsr & LSR_FRM_ERR)
+		icount->frame++;
+}
+
+
+static void edge_interrupt_callback (struct urb *urb)
+{
+	struct edgeport_serial	*edge_serial = (struct edgeport_serial *)urb->context;
+	struct usb_serial_port *port;
+	struct edgeport_port *edge_port;
+	unsigned char *data = urb->transfer_buffer;
+	int length = urb->actual_length;
+	int port_number;
+	int function;
+	__u8 lsr;
+	__u8 msr;
+
+	dbg("%s", __FUNCTION__);
+
+	if (serial_paranoia_check (edge_serial->serial, __FUNCTION__)) {
+		return;
+	}
+
+	if (urb->status) {
+		dbg("%s - nonzero control read status received: %d", __FUNCTION__, urb->status);
+		return;
+	}
+
+	if (!length) {
+		dbg ("%s - no data in urb", __FUNCTION__);
+		return;
+	}
+		
+	usb_serial_debug_data (__FILE__, __FUNCTION__, length, data);
+		
+	if (length != 2) {
+		dbg ("%s - expecting packet of size 2, got %d", __FUNCTION__, length);
+		return;
+	}
+
+	port_number = TIUMP_GET_PORT_FROM_CODE (data[0]);
+	function    = TIUMP_GET_FUNC_FROM_CODE (data[0]);
+	dbg ("%s - port_number %d, function %d, info 0x%x",
+	     __FUNCTION__, port_number, function, data[1]);
+	port = &edge_serial->serial->port[port_number];
+	if (port_paranoia_check (port, __FUNCTION__)) {
+		dbg ("%s - change found for port that is not present",
+		     __FUNCTION__);
+		return;
+	}
+	edge_port = port->private;
+	if (!edge_port) {
+		dbg ("%s - edge_port not found", __FUNCTION__);
+		return;
+	}
+	switch (function) {
+	case TIUMP_INTERRUPT_CODE_LSR:
+		lsr = MapLineStatus(data[1]);
+		if (lsr & UMP_UART_LSR_DATA_MASK) {
+			/* Save the LSR event for bulk read completion routine */
+			dbg ("%s - LSR Event Port %u LSR Status = %02x",
+			     __FUNCTION__, port_number, lsr);
+			edge_port->lsr_event = 1;
+			edge_port->lsr_mask = lsr;
+		} else {
+			dbg ("%s - ===== Port %d LSR Status = %02x ======",
+			     __FUNCTION__, port_number, lsr);
+			handle_new_lsr (edge_port, 0, lsr, 0);
+		}
+		break;
+
+	case TIUMP_INTERRUPT_CODE_MSR:	// MSR
+		/* Copy MSR from UMP */
+		msr = data[1];
+		dbg ("%s - ===== Port %u MSR Status = %02x ======\n",
+		     __FUNCTION__, port_number, msr);
+		handle_new_msr (edge_port, msr);
+		break;
+
+	default:
+		err ("%s - Unknown Interrupt code from UMP %x\n",
+		     __FUNCTION__, data[1]);
+		break;
+		
+	}
+}
+
+static void edge_bulk_in_callback (struct urb *urb)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
+	unsigned char *data = urb->transfer_buffer;
+	struct tty_struct *tty;
+	int status;
+	int i;
+	int port_number;
+
+	dbg("%s", __FUNCTION__);
+
+	if (port_paranoia_check (edge_port->port, __FUNCTION__))
+		return;
+
+	if (urb->status) {
+		dbg ("%s - nonzero read bulk status received: %d",
+		     __FUNCTION__, urb->status);
+
+		if (urb->status == -EPIPE) {
+			/* clear any problem that might have happened on this pipe */
+			usb_clear_halt (edge_port->port->serial->dev, urb->pipe);
+			goto exit;
+		}
+		return;
+	}
+
+	port_number = edge_port->port->number - edge_port->port->serial->minor;
+
+	if (edge_port->lsr_event) {
+		edge_port->lsr_event = 0;
+		dbg ("%s ===== Port %u LSR Status = %02x, Data = %02x ======",
+		     __FUNCTION__, port_number, edge_port->lsr_mask, *data);
+		handle_new_lsr (edge_port, 1, edge_port->lsr_mask, *data);
+		/* Adjust buffer length/pointer */
+		--urb->actual_length;
+		++data;
+	}
+
+	tty = edge_port->port->tty;
+	if (tty && urb->actual_length) {
+		usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+		if (edge_port->close_pending) {
+			dbg ("%s - close is pending, dropping data on the floor.", __FUNCTION__);
+		} else {
+			for (i = 0; i < urb->actual_length ; ++i) {
+				/* if we insert more than TTY_FLIPBUF_SIZE characters,
+				 * we drop them. */
+				if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+					tty_flip_buffer_push(tty);
+				}
+				/* this doesn't actually push the data through unless
+				 * tty->low_latency is set */
+				tty_insert_flip_char(tty, data[i], 0);
+			}
+			tty_flip_buffer_push(tty);
+		}
+		edge_port->icount.rx += urb->actual_length;
+	}
+
+exit:
+	/* continue always trying to read */
+	urb->dev = edge_port->port->serial->dev;
+	status = usb_submit_urb (urb);
+	if (status)
+		err ("%s - usb_submit_urb failed with result %d",
+		     __FUNCTION__, status);
+}
+
+static void edge_bulk_out_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+	struct tty_struct *tty;
+
+	dbg ("%s - port %d", __FUNCTION__, port->number);
+
+	if (!serial) {
+		dbg ("%s - bad serial pointer, exiting", __FUNCTION__);
+		return;
+	}
+
+	if (urb->status) {
+		dbg ("%s - nonzero write bulk status received: %d",
+		     __FUNCTION__, urb->status);
+
+		if (urb->status == -EPIPE) {
+			/* clear any problem that might have happened on this pipe */
+			usb_clear_halt (serial->dev, urb->pipe);
+		}
+		return;
+	}
+
+	tty = port->tty;
+	if (tty) {
+		/* let the tty driver wakeup if it has a special write_wakeup function */
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
+			(tty->ldisc.write_wakeup)(tty);
+		}
+
+		/* tell the tty driver that something has changed */
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+static int edge_open (struct usb_serial_port *port, struct file * filp)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)port->private;
+	struct edgeport_serial *edge_serial;
+	struct usb_device *dev;
+	struct urb *urb;
+	int port_number;
+	int status;
+	u16 open_settings;
+	u8 transaction_timeout;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return -ENODEV;
+	
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (edge_port == NULL)
+		return -ENODEV;
+
+	/* force low_latency on so that our tty_push actually forces the data through, 
+	   otherwise it is scheduled, and with high data rates (like with OHCI) data
+	   can get lost. */
+	if (port->tty)
+		port->tty->low_latency = 1;
+
+	port_number = port->number - port->serial->minor;
+	switch (port_number) {
+		case 0:
+			edge_port->uart_base = UMPMEM_BASE_UART1;
+			edge_port->dma_address = UMPD_OEDB1_ADDRESS;
+			break;
+		case 1:
+			edge_port->uart_base = UMPMEM_BASE_UART2;
+			edge_port->dma_address = UMPD_OEDB2_ADDRESS;
+			break;
+		default:
+			err ("Unknown port number!!!");
+			return -ENODEV;
+	}
+
+	dbg ("%s - port_number = %d, uart_base = %04x, dma_address = %04x",
+	     __FUNCTION__, port_number, edge_port->uart_base, edge_port->dma_address);
+
+	dev = port->serial->dev;
+
+	memset (&(edge_port->icount), 0x00, sizeof(edge_port->icount));
+	init_waitqueue_head (&edge_port->delta_msr_wait);
+
+	/* turn off loopback */
+	status = TIClearLoopBack (edge_port);
+	if (status)
+		return status;
+	
+	/* set up the port settings */
+	edge_set_termios (port, NULL);
+
+	/* open up the port */
+
+	/* milliseconds to timeout for DMA transfer */
+	transaction_timeout = 2;
+
+	edge_port->ump_read_timeout = max (20, ((transaction_timeout * 3) / 2) );
+
+	// milliseconds to timeout for DMA transfer
+	open_settings = (u8)(UMP_DMA_MODE_CONTINOUS | 
+			     UMP_PIPE_TRANS_TIMEOUT_ENA | 
+			     (transaction_timeout << 2));
+
+	dbg ("%s - Sending UMPC_OPEN_PORT", __FUNCTION__);
+
+	/* Tell TI to open and start the port */
+	status = TIWriteCommandSync (dev,
+					UMPC_OPEN_PORT,
+					(u8)(UMPM_UART1_PORT + port_number),
+					open_settings,
+					NULL,
+					0);
+	if (status)
+		return status;
+
+	/* Start the DMA? */
+	status = TIWriteCommandSync (dev,
+					UMPC_START_PORT,
+					(u8)(UMPM_UART1_PORT + port_number),
+					0,
+					NULL,
+					0);
+	if (status)
+		return status;
+
+	/* Clear TX and RX buffers in UMP */
+	status = TIPurgeDataSync (port, UMP_PORT_DIR_OUT | UMP_PORT_DIR_IN);
+	if (status)
+		return status;
+
+	/* Read Initial MSR */
+	status = TIReadVendorRequestSync (dev,
+					UMPC_READ_MSR,	// Request
+					0,		// wValue
+					(__u16)(UMPM_UART1_PORT + port_number),	// wIndex (Address)
+					&edge_port->shadow_msr,			// TransferBuffer
+					1);					// TransferBufferLength
+	if (status)
+		return status;
+
+	dbg ("ShadowMSR 0x%X", edge_port->shadow_msr);
+ 
+	edge_serial = edge_port->edge_serial;
+	if (edge_serial->num_ports_open == 0) {
+		dbg ("%s - setting up bulk in urb", __FUNCTION__);
+		/* we are the first port to be opened, let's post the interrupt urb */
+		urb = edge_serial->serial->port[0].interrupt_in_urb;
+		if (!urb) {
+			err ("%s - no interrupt urb present, exiting", __FUNCTION__);
+			return -EINVAL;
+		}
+		urb->complete = edge_interrupt_callback;
+		urb->context = edge_serial;
+		urb->dev = dev;
+		status = usb_submit_urb (urb);
+		if (status) {
+			err ("%s - usb_submit_urb failed with value %d", __FUNCTION__, status);
+			return status;
+		}
+	}
+
+	/*
+	 * reset the data toggle on the bulk endpoints to work around bug in
+	 * host controllers where things get out of sync some times
+	 */
+	usb_clear_halt (dev, port->write_urb->pipe);
+	usb_clear_halt (dev, port->read_urb->pipe);
+
+	/* start up our bulk read urb */
+	urb = port->read_urb;
+	if (!urb) {
+		err ("%s - no read urb present, exiting", __FUNCTION__);
+		return -EINVAL;
+	}
+	urb->complete = edge_bulk_in_callback;
+	urb->context = edge_port;
+	urb->dev = dev;
+	status = usb_submit_urb (urb);
+	if (status) {
+		err ("%s - read bulk usb_submit_urb failed with value %d", __FUNCTION__, status);
+		return status;
+	}
+
+	++edge_serial->num_ports_open;
+
+	dbg("%s - exited", __FUNCTION__);
+
+	return 0;
+}
+
+static void edge_close (struct usb_serial_port *port, struct file * filp)
+{
+	struct usb_serial *serial;
+	struct edgeport_serial *edge_serial;
+	struct edgeport_port *edge_port;
+	int port_number;
+	int status;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return;
+	
+	dbg("%s - port %d", __FUNCTION__, port->number);
+			 
+	serial = get_usb_serial (port, __FUNCTION__);
+	if (!serial)
+		return;
+	
+	edge_serial = (struct edgeport_serial *)serial->private;
+	edge_port = (struct edgeport_port *)port->private;
+	if ((edge_serial == NULL) || (edge_port == NULL))
+		return;
+	
+	if (serial->dev) {
+		/* The bulkreadcompletion routine will check 
+		 * this flag and dump add read data */
+		edge_port->close_pending = 1;
+
+		/* chase the port close */
+		TIChasePort (edge_port);
+
+		usb_unlink_urb (port->read_urb);
+
+		/* assuming we can still talk to the device,
+		 * send a close port command to it */
+		dbg("%s - send umpc_close_port", __FUNCTION__);
+		port_number = port->number - port->serial->minor;
+		status = TIWriteCommandSync (port->serial->dev,
+					     UMPC_CLOSE_PORT,
+					     (__u8)(UMPM_UART1_PORT + port_number),
+					     0,
+					     NULL,
+					     0);
+		--edge_port->edge_serial->num_ports_open;
+		if (edge_port->edge_serial->num_ports_open <= 0) {
+			/* last port is now closed, let's shut down our interrupt urb */
+			usb_unlink_urb (serial->port[0].interrupt_in_urb);
+			edge_port->edge_serial->num_ports_open = 0;
+		}
+	edge_port->close_pending = 0;
+	}
+
+	dbg("%s - exited", __FUNCTION__);
+}
+
+static int edge_write (struct usb_serial_port *port, int from_user, const unsigned char *data, int count)
+{
+	struct usb_serial *serial = port->serial;
+	struct edgeport_port *edge_port = port->private;
+	int result;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (count == 0) {
+		dbg("%s - write request of 0 bytes", __FUNCTION__);
+		return 0;
+	}
+
+	if (edge_port == NULL)
+		return -ENODEV;
+	if (edge_port->close_pending == 1)
+		return -ENODEV;
+	
+	if (port->write_urb->status == -EINPROGRESS) {
+		dbg ("%s - already writing", __FUNCTION__);
+		return 0;
+	}
+
+	count = min (count, port->bulk_out_size);
+
+	if (from_user) {
+		if (copy_from_user(port->write_urb->transfer_buffer, data, count))
+			return -EFAULT;
+	} else {
+		memcpy (port->write_urb->transfer_buffer, data, count);
+	}
+
+	usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer);
+
+	/* set up our urb */
+	usb_fill_bulk_urb (port->write_urb, serial->dev,
+			   usb_sndbulkpipe (serial->dev,
+					    port->bulk_out_endpointAddress),
+			   port->write_urb->transfer_buffer, count,
+			   edge_bulk_out_callback,
+			   port);
+
+	/* send the data out the bulk port */
+	result = usb_submit_urb(port->write_urb);
+	if (result)
+		err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
+	else
+		result = count;
+
+	if (result > 0)
+		edge_port->icount.tx += count;
+
+	return result;
+}
+
+static int edge_write_room (struct usb_serial_port *port)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	int room = 0;
+
+	dbg("%s", __FUNCTION__);
+
+	if (edge_port == NULL)
+		return -ENODEV;
+	if (edge_port->close_pending == 1)
+		return -ENODEV;
+	
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (port->write_urb->status != -EINPROGRESS)
+		room = port->bulk_out_size;
+
+	dbg("%s - returns %d", __FUNCTION__, room);
+	return room;
+}
+
+static int edge_chars_in_buffer (struct usb_serial_port *port)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	int chars = 0;
+
+	dbg("%s", __FUNCTION__);
+
+	if (edge_port == NULL)
+		return -ENODEV;
+	if (edge_port->close_pending == 1)
+		return -ENODEV;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (port->write_urb->status == -EINPROGRESS)
+		chars = port->write_urb->transfer_buffer_length;
+
+	dbg ("%s - returns %d", __FUNCTION__, chars);
+	return chars;
+}
+
+static void edge_throttle (struct usb_serial_port *port)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	struct tty_struct *tty;
+	int status;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (edge_port == NULL)
+		return;
+
+	tty = port->tty;
+	if (!tty) {
+		dbg ("%s - no tty available", __FUNCTION__);
+		return;
+	}
+	/* if we are implementing XON/XOFF, send the stop character */
+	if (I_IXOFF(tty)) {
+		unsigned char stop_char = STOP_CHAR(tty);
+		status = edge_write (port, 0, &stop_char, 1);
+		if (status <= 0) {
+			return;
+		}
+	}
+
+	/* if we are implementing RTS/CTS, toggle that line */
+	if (tty->termios->c_cflag & CRTSCTS) {
+		status = TIClearRts (edge_port);
+	}
+
+	usb_unlink_urb (port->read_urb);
+}
+
+static void edge_unthrottle (struct usb_serial_port *port)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	struct tty_struct *tty;
+	int status;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (edge_port == NULL)
+		return;
+
+	tty = port->tty;
+	if (!tty) {
+		dbg ("%s - no tty available", __FUNCTION__);
+		return;
+	}
+
+	/* if we are implementing XON/XOFF, send the start character */
+	if (I_IXOFF(tty)) {
+		unsigned char start_char = START_CHAR(tty);
+		status = edge_write (port, 0, &start_char, 1);
+		if (status <= 0) {
+			return;
+		}
+	}
+
+	/* if we are implementing RTS/CTS, toggle that line */
+	if (tty->termios->c_cflag & CRTSCTS) {
+		status = TISetRts (edge_port);
+	}
+
+	port->read_urb->dev = port->serial->dev;
+	status = usb_submit_urb (port->read_urb);
+	if (status) {
+		err ("%s - usb_submit_urb failed with value %d", __FUNCTION__, status);
+	}
+}
+
+
+static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios)
+{
+	struct ump_uart_config *config;
+	struct tty_struct *tty;
+	int baud;
+	int round;
+	unsigned cflag;
+	int status;
+	int port_number = edge_port->port->number - edge_port->port->serial->minor;
+
+	dbg("%s - port %d", __FUNCTION__, edge_port->port->number);
+
+	tty = edge_port->port->tty;
+	if ((!tty) ||
+	    (!tty->termios)) {
+		dbg("%s - no tty structures", __FUNCTION__);
+		return;
+	}
+
+	config = kmalloc (sizeof (*config), GFP_KERNEL);
+	if (!config) {
+		err ("%s - out of memory", __FUNCTION__);
+		return;
+	}
+
+	cflag = tty->termios->c_cflag;
+
+	config->wFlags = 0;
+
+	/* These flags must be set */
+	config->wFlags |= UMP_MASK_UART_FLAGS_RECEIVE_MS_INT;
+	config->wFlags |= UMP_MASK_UART_FLAGS_AUTO_START_ON_ERR;
+	config->bUartMode = 0;
+
+	switch (cflag & CSIZE) {
+		case CS5:
+			    config->bDataBits = UMP_UART_CHAR5BITS;
+			    dbg ("%s - data bits = 5", __FUNCTION__);
+			    break;
+		case CS6:
+			    config->bDataBits = UMP_UART_CHAR6BITS;
+			    dbg ("%s - data bits = 6", __FUNCTION__);
+			    break;
+		case CS7:
+			    config->bDataBits = UMP_UART_CHAR7BITS;
+			    dbg ("%s - data bits = 7", __FUNCTION__);
+			    break;
+		default:
+		case CS8:
+			    config->bDataBits = UMP_UART_CHAR8BITS;
+			    dbg ("%s - data bits = 8", __FUNCTION__);
+			    break;
+	}
+
+	if (cflag & PARENB) {
+		if (cflag & PARODD) {
+			config->wFlags |= UMP_MASK_UART_FLAGS_PARITY;
+			config->bParity = UMP_UART_ODDPARITY;
+			dbg("%s - parity = odd", __FUNCTION__);
+		} else {
+			config->wFlags |= UMP_MASK_UART_FLAGS_PARITY;
+			config->bParity = UMP_UART_EVENPARITY;
+			dbg("%s - parity = even", __FUNCTION__);
+		}
+	} else {
+		config->bParity = UMP_UART_NOPARITY; 	
+		dbg("%s - parity = none", __FUNCTION__);
+	}
+
+	if (cflag & CSTOPB) {
+		config->bStopBits = UMP_UART_STOPBIT2;
+		dbg("%s - stop bits = 2", __FUNCTION__);
+	} else {
+		config->bStopBits = UMP_UART_STOPBIT1;
+		dbg("%s - stop bits = 1", __FUNCTION__);
+	}
+
+	/* figure out the flow control settings */
+	if (cflag & CRTSCTS) {
+		config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X_CTS_FLOW;
+		config->wFlags |= UMP_MASK_UART_FLAGS_RTS_FLOW;
+		dbg("%s - RTS/CTS is enabled", __FUNCTION__);
+	} else {
+		dbg("%s - RTS/CTS is disabled", __FUNCTION__);
+	}
+
+	/* if we are implementing XON/XOFF, set the start and stop character in the device */
+	if (I_IXOFF(tty) || I_IXON(tty)) {
+		config->cXon  = START_CHAR(tty);
+		config->cXoff = STOP_CHAR(tty);
+
+		/* if we are implementing INBOUND XON/XOFF */
+		if (I_IXOFF(tty)) {
+			config->wFlags |= UMP_MASK_UART_FLAGS_IN_X;
+			dbg ("%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x",
+			     __FUNCTION__, config->cXon, config->cXoff);
+		} else {
+			dbg ("%s - INBOUND XON/XOFF is disabled", __FUNCTION__);
+		}
+
+		/* if we are implementing OUTBOUND XON/XOFF */
+		if (I_IXON(tty)) {
+			config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X;
+			dbg ("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x",
+			     __FUNCTION__, config->cXon, config->cXoff);
+		} else {
+			dbg ("%s - OUTBOUND XON/XOFF is disabled", __FUNCTION__);
+		}
+	}
+
+	/* Round the baud rate */
+	baud = tty_get_baud_rate(tty);
+	if (!baud) {
+		/* pick a default, any default... */
+		baud = 9600;
+	}
+	config->wBaudRate = (__u16)(461550L / baud);
+	round = 4615500L / baud;
+	if ((round - (config->wBaudRate * 10)) >= 5)
+		config->wBaudRate++;
+
+	dbg ("%s - baud rate = %d, wBaudRate = %d", __FUNCTION__, baud, config->wBaudRate);
+
+	dbg ("wBaudRate:   %d", (int)(461550L / config->wBaudRate));
+	dbg ("wFlags:    0x%x", config->wFlags);
+	dbg ("bDataBits:   %d", config->bDataBits);
+	dbg ("bParity:     %d", config->bParity);
+	dbg ("bStopBits:   %d", config->bStopBits);
+	dbg ("cXon:        %d", config->cXon);
+	dbg ("cXoff:       %d", config->cXoff);
+	dbg ("bUartMode:   %d", config->bUartMode);
+
+	/* move the word values into big endian mode */
+	cpu_to_be16s (&config->wFlags);
+	cpu_to_be16s (&config->wBaudRate);
+
+	status = TIWriteCommandSync (edge_port->port->serial->dev,
+				UMPC_SET_CONFIG,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				0,
+				(__u8 *)config,
+				sizeof(*config));
+	if (status) {
+		dbg ("%s - error %d when trying to write config to device",
+		     __FUNCTION__, status);
+	}
+
+	kfree (config);
+	
+	return;
+}
+
+static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	struct tty_struct *tty = port->tty;
+	unsigned int cflag;
+
+	if (!port->tty || !port->tty->termios) {
+		dbg ("%s - no tty or termios", __FUNCTION__);
+		return;
+	}
+
+	cflag = tty->termios->c_cflag;
+	/* check that they really want us to change something */
+	if (old_termios) {
+		if ((cflag == old_termios->c_cflag) &&
+		    (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+			dbg ("%s - nothing to change", __FUNCTION__);
+			return;
+		}
+	}
+
+	dbg("%s - clfag %08x iflag %08x", __FUNCTION__, 
+	    tty->termios->c_cflag,
+	    RELEVANT_IFLAG(tty->termios->c_iflag));
+	if (old_termios) {
+		dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+		    old_termios->c_cflag,
+		    RELEVANT_IFLAG(old_termios->c_iflag));
+	}
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (edge_port == NULL)
+		return;
+
+	/* change the port settings to the new ones specified */
+	change_port_settings (edge_port, old_termios);
+
+	return;
+}
+
+static int set_modem_info (struct edgeport_port *edge_port, unsigned int cmd, unsigned int *value)
+{
+	unsigned int mcr = edge_port->shadow_mcr;
+	unsigned int arg;
+
+	if (copy_from_user(&arg, value, sizeof(int)))
+		return -EFAULT;
+
+	switch (cmd) {
+		case TIOCMBIS:
+			if (arg & TIOCM_RTS)
+				mcr |= MCR_RTS;
+			if (arg & TIOCM_DTR)
+				mcr |= MCR_RTS;
+			if (arg & TIOCM_LOOP)
+				mcr |= MCR_LOOPBACK;
+			break;
+
+		case TIOCMBIC:
+			if (arg & TIOCM_RTS)
+				mcr &= ~MCR_RTS;
+			if (arg & TIOCM_DTR)
+				mcr &= ~MCR_RTS;
+			if (arg & TIOCM_LOOP)
+				mcr &= ~MCR_LOOPBACK;
+			break;
+
+		case TIOCMSET:
+			/* turn off the RTS and DTR and LOOPBACK 
+			 * and then only turn on what was asked to */
+			mcr &=  ~(MCR_RTS | MCR_DTR | MCR_LOOPBACK);
+			mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0);
+			mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0);
+			mcr |= ((arg & TIOCM_LOOP) ? MCR_LOOPBACK : 0);
+			break;
+	}
+
+	edge_port->shadow_mcr = mcr;
+
+	TIRestoreMCR (edge_port, mcr);
+
+	return 0;
+}
+
+static int get_modem_info (struct edgeport_port *edge_port, unsigned int *value)
+{
+	unsigned int result = 0;
+	unsigned int msr = edge_port->shadow_msr;
+	unsigned int mcr = edge_port->shadow_mcr;
+
+	result = ((mcr & MCR_DTR)	? TIOCM_DTR: 0)	  /* 0x002 */
+		  | ((mcr & MCR_RTS)	? TIOCM_RTS: 0)   /* 0x004 */
+		  | ((msr & MSR_CTS)	? TIOCM_CTS: 0)   /* 0x020 */
+		  | ((msr & MSR_CD)	? TIOCM_CAR: 0)   /* 0x040 */
+		  | ((msr & MSR_RI)	? TIOCM_RI:  0)   /* 0x080 */
+		  | ((msr & MSR_DSR)	? TIOCM_DSR: 0);  /* 0x100 */
+
+
+	dbg("%s -- %x", __FUNCTION__, result);
+
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	return 0;
+}
+
+static int get_serial_info (struct edgeport_port *edge_port, struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+
+	if (!retinfo)
+		return -EFAULT;
+
+	memset(&tmp, 0, sizeof(tmp));
+
+	tmp.type		= PORT_16550A;
+	tmp.line		= edge_port->port->serial->minor;
+	tmp.port		= edge_port->port->number;
+	tmp.irq			= 0;
+	tmp.flags		= ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
+	tmp.xmit_fifo_size	= edge_port->port->bulk_out_size;
+	tmp.baud_base		= 9600;
+	tmp.close_delay		= 5*HZ;
+	tmp.closing_wait	= 30*HZ;
+//	tmp.custom_divisor	= state->custom_divisor;
+//	tmp.hub6		= state->hub6;
+//	tmp.io_type		= state->io_type;
+
+
+	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+}
+
+static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	struct async_icount cnow;
+	struct async_icount cprev;
+
+	dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
+
+	switch (cmd) {
+		case TIOCINQ:
+			dbg("%s - (%d) TIOCINQ", __FUNCTION__, port->number);
+//			return get_number_bytes_avail(edge_port, (unsigned int *) arg);
+			break;
+
+		case TIOCSERGETLSR:
+			dbg("%s - (%d) TIOCSERGETLSR", __FUNCTION__, port->number);
+//			return get_lsr_info(edge_port, (unsigned int *) arg);
+			break;
+
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			dbg("%s - (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__, port->number);
+			return set_modem_info(edge_port, cmd, (unsigned int *) arg);
+			break;
+
+		case TIOCMGET:  
+			dbg("%s - (%d) TIOCMGET", __FUNCTION__, port->number);
+			return get_modem_info(edge_port, (unsigned int *) arg);
+			break;
+
+		case TIOCGSERIAL:
+			dbg("%s - (%d) TIOCGSERIAL", __FUNCTION__, port->number);
+			return get_serial_info(edge_port, (struct serial_struct *) arg);
+			break;
+
+		case TIOCSSERIAL:
+			dbg("%s - (%d) TIOCSSERIAL", __FUNCTION__, port->number);
+			break;
+
+		case TIOCMIWAIT:
+			dbg("%s - (%d) TIOCMIWAIT", __FUNCTION__, port->number);
+			cprev = edge_port->icount;
+			while (1) {
+				interruptible_sleep_on(&edge_port->delta_msr_wait);
+				/* see if a signal did it */
+				if (signal_pending(current))
+					return -ERESTARTSYS;
+				cnow = edge_port->icount;
+				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+					return -EIO; /* no change => error */
+				if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+				    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+				    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+				    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+					return 0;
+				}
+				cprev = cnow;
+			}
+			/* not reached */
+			break;
+
+		case TIOCGICOUNT:
+			dbg ("%s - (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__,
+			     port->number, edge_port->icount.rx, edge_port->icount.tx);
+			if (copy_to_user((void *)arg, &edge_port->icount, sizeof(edge_port->icount)))
+				return -EFAULT;
+			return 0;
+	}
+
+	return -ENOIOCTLCMD;
+}
+
+static void edge_break (struct usb_serial_port *port, int break_state)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	int status;
+
+	dbg ("%s - state = %d", __FUNCTION__, break_state);
+
+	/* chase the port close */
+	TIChasePort (edge_port);
+
+	if (break_state == -1) {
+		status = TISetBreak (edge_port);
+	} else {
+		status = TIClearBreak (edge_port);
+	}
+	if (status) {
+		dbg ("%s - error %d sending break set/clear command.",
+		     __FUNCTION__, status);
+	}
+}
+
+static int edge_startup (struct usb_serial *serial)
+{
+	struct edgeport_serial *edge_serial;
+	struct edgeport_port *edge_port;
+	struct usb_device *dev;
+	int status;
+	int i;
+
+	dev = serial->dev;
+
+	/* create our private serial structure */
+	edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL);
+	if (edge_serial == NULL) {
+		err("%s - Out of memory", __FUNCTION__);
+		return -ENOMEM;
+	}
+	memset (edge_serial, 0, sizeof(struct edgeport_serial));
+	edge_serial->serial = serial;
+	serial->private = edge_serial;
+
+	status = TIDownloadFirmware (edge_serial);
+	if (status) {
+		kfree (edge_serial);
+		return status;
+	}
+
+	/* set up our port private structures */
+	for (i = 0; i < serial->num_ports; ++i) {
+		edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL);
+		if (edge_port == NULL) {
+			err("%s - Out of memory", __FUNCTION__);
+			return -ENOMEM;
+		}
+		memset (edge_port, 0, sizeof(struct edgeport_port));
+		edge_port->port = &serial->port[i];
+		edge_port->edge_serial = edge_serial;
+		serial->port[i].private = edge_port;
+	}
+	
+	return 0;
+}
+
+static void edge_shutdown (struct usb_serial *serial)
+{
+	int i;
+
+	dbg ("%s", __FUNCTION__);
+
+	for (i=0; i < serial->num_ports; ++i) {
+		kfree (serial->port[i].private);
+		serial->port[i].private = NULL;
+	}
+	kfree (serial->private);
+	serial->private = NULL;
+}
+
+
+static struct usb_serial_device_type edgeport_1port_device = {
+	owner:			THIS_MODULE,
+	name:			"Edgeport TI 1 port adapter",
+	id_table:		edgeport_1port_id_table,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+static struct usb_serial_device_type edgeport_2port_device = {
+	owner:			THIS_MODULE,
+	name:			"Edgeport TI 2 port adapter",
+	id_table:		edgeport_2port_id_table,
+	num_interrupt_in:	1,
+	num_bulk_in:		2,
+	num_bulk_out:		2,
+	num_ports:		2,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+
+static int __init edgeport_init(void)
+{
+	usb_serial_register (&edgeport_1port_device);
+	usb_serial_register (&edgeport_2port_device);
+	info(DRIVER_DESC " " DRIVER_VERSION);
+	return 0;
+}
+
+static void __exit edgeport_exit (void)
+{
+	usb_serial_deregister (&edgeport_1port_device);
+	usb_serial_deregister (&edgeport_2port_device);
+}
+
+module_init(edgeport_init);
+module_exit(edgeport_exit);
+
+/* Module information */
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+MODULE_PARM(ignore_cpu_rev, "i");
+MODULE_PARM_DESC(ignore_cpu_rev, "Ignore the cpu revision when connecting to a device");
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/io_ti.h linux-2.4.20/drivers/usb/serial/io_ti.h
--- linux-2.4.19/drivers/usb/serial/io_ti.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/io_ti.h	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,180 @@
+/*****************************************************************************  
+ *
+ *	Copyright (c) 1997-2002 Inside Out Networks, 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.
+ *
+ *
+ *	Feb-16-2001	DMI	Added I2C structure definitions
+ *	May-29-2002	gkh	Ported to Linux
+ *
+ *
+ ******************************************************************************/
+
+#ifndef _IO_TI_H_
+#define _IO_TI_H_
+
+/* Address Space */
+#define DTK_ADDR_SPACE_XDATA		0x03	/* Addr is placed in XDATA space */
+#define DTK_ADDR_SPACE_I2C_TYPE_II	0x82	/* Addr is placed in I2C area */
+#define DTK_ADDR_SPACE_I2C_TYPE_III	0x83	/* Addr is placed in I2C area */
+
+// UART Defines
+#define UMPMEM_BASE_UART1		0xFFA0  /* UMP UART1 base address          */
+#define UMPMEM_BASE_UART2		0xFFB0  /* UMP UART2 base address          */
+#define UMPMEM_OFFS_UART_LSR		0x05    /* UMP UART LSR register offset    */
+
+/* Bits per character */
+#define UMP_UART_CHAR5BITS		0x00
+#define UMP_UART_CHAR6BITS		0x01
+#define UMP_UART_CHAR7BITS		0x02
+#define UMP_UART_CHAR8BITS		0x03
+
+/* Parity */
+#define UMP_UART_NOPARITY		0x00
+#define UMP_UART_ODDPARITY		0x01
+#define UMP_UART_EVENPARITY		0x02
+#define UMP_UART_MARKPARITY		0x03
+#define UMP_UART_SPACEPARITY		0x04
+
+/* Stop bits */
+#define UMP_UART_STOPBIT1		0x00
+#define UMP_UART_STOPBIT15		0x01
+#define UMP_UART_STOPBIT2		0x02
+
+/* Line status register masks */
+#define UMP_UART_LSR_OV_MASK		0x01
+#define UMP_UART_LSR_PE_MASK		0x02
+#define UMP_UART_LSR_FE_MASK		0x04
+#define UMP_UART_LSR_BR_MASK		0x08
+#define UMP_UART_LSR_ER_MASK		0x0F
+#define UMP_UART_LSR_RX_MASK		0x10
+#define UMP_UART_LSR_TX_MASK		0x20
+
+#define UMP_UART_LSR_DATA_MASK		( LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK )
+
+/* Port Settings Constants) */
+#define UMP_MASK_UART_FLAGS_RTS_FLOW		0x0001
+#define UMP_MASK_UART_FLAGS_RTS_DISABLE		0x0002
+#define UMP_MASK_UART_FLAGS_PARITY		0x0008
+#define UMP_MASK_UART_FLAGS_OUT_X_DSR_FLOW	0x0010
+#define UMP_MASK_UART_FLAGS_OUT_X_CTS_FLOW	0x0020
+#define UMP_MASK_UART_FLAGS_OUT_X		0x0040
+#define UMP_MASK_UART_FLAGS_OUT_XA		0x0080
+#define UMP_MASK_UART_FLAGS_IN_X		0x0100
+#define UMP_MASK_UART_FLAGS_DTR_FLOW		0x0800
+#define UMP_MASK_UART_FLAGS_DTR_DISABLE		0x1000
+#define UMP_MASK_UART_FLAGS_RECEIVE_MS_INT	0x2000
+#define UMP_MASK_UART_FLAGS_AUTO_START_ON_ERR	0x4000
+
+#define UMP_DMA_MODE_CONTINOUS			0x01
+#define UMP_PIPE_TRANS_TIMEOUT_ENA		0x80
+#define UMP_PIPE_TRANSFER_MODE_MASK		0x03
+#define UMP_PIPE_TRANS_TIMEOUT_MASK		0x7C
+
+/* Purge port Direction Mask Bits */
+#define UMP_PORT_DIR_OUT			0x01
+#define UMP_PORT_DIR_IN				0x02
+
+// Address of Port 0
+#define UMPM_UART1_PORT  			0x03
+
+// Commands
+#define	UMPC_SET_CONFIG 		0x05
+#define	UMPC_OPEN_PORT  		0x06
+#define	UMPC_CLOSE_PORT 		0x07
+#define	UMPC_START_PORT 		0x08
+#define	UMPC_STOP_PORT  		0x09
+#define	UMPC_TEST_PORT  		0x0A
+#define	UMPC_PURGE_PORT 		0x0B
+
+#define	UMPC_COMPLETE_READ		0x80	// Force the Firmware to complete the current Read
+#define	UMPC_HARDWARE_RESET		0x81	// Force UMP back into BOOT Mode
+#define	UMPC_COPY_DNLD_TO_I2C		0x82	// Copy current download image to type 0xf2 record in 16k I2C
+						// firmware will change 0xff record to type 2 record when complete
+
+	// Special function register commands
+	// wIndex is register address
+	// wValue is MSB/LSB mask/data
+#define	UMPC_WRITE_SFR	  		0x83	// Write SFR Register
+
+	// wIndex is register address
+#define	UMPC_READ_SFR	  		0x84	// Read SRF Register
+
+	// Set or Clear DTR (wValue bit 0 Set/Clear)		wIndex ModuleID (port)
+#define	UMPC_SET_CLR_DTR		0x85
+
+	// Set or Clear RTS (wValue bit 0 Set/Clear)		wIndex ModuleID (port)
+#define	UMPC_SET_CLR_RTS		0x86
+
+	// Set or Clear LOOPBACK (wValue bit 0 Set/Clear)	wIndex ModuleID (port)
+#define	UMPC_SET_CLR_LOOPBACK		0x87
+
+	// Set or Clear BREAK (wValue bit 0 Set/Clear)		wIndex ModuleID (port)
+#define	UMPC_SET_CLR_BREAK		0x88
+
+	// Read MSR wIndex ModuleID (port)
+#define	UMPC_READ_MSR			0x89
+
+	/* Toolkit commands */
+	/* Read-write group */
+#define	UMPC_MEMORY_READ   		0x92
+#define	UMPC_MEMORY_WRITE  		0x93
+
+/*
+ *	UMP DMA Definitions
+ */
+#define UMPD_OEDB1_ADDRESS		0xFF08
+#define UMPD_OEDB2_ADDRESS		0xFF10
+
+struct out_endpoint_desc_block
+{
+	__u8 Configuration;
+	__u8 XBufAddr;
+	__u8 XByteCount;
+	__u8 Unused1;
+	__u8 Unused2;
+	__u8 YBufAddr;
+	__u8 YByteCount;
+	__u8 BufferSize;
+} __attribute__((packed));
+
+
+/*
+ * TYPE DEFINITIONS
+ * Structures for Firmware commands
+ */
+struct ump_uart_config		/* UART settings                    */
+{
+	__u16 wBaudRate;	/* Baud rate                        */
+	__u16 wFlags;		/* Bitmap mask of flags             */
+	__u8 bDataBits;		/* 5..8 - data bits per character   */
+	__u8 bParity;		/* Parity settings                  */
+	__u8 bStopBits;		/* Stop bits settings               */
+	char cXon;		/* XON character                    */
+	char cXoff;		/* XOFF character                   */
+	__u8 bUartMode;		/* Will be updated when a user      */
+				/* interface is defined             */
+} __attribute__((packed));
+
+
+/*
+ * TYPE DEFINITIONS
+ * Structures for USB interrupts
+ */
+struct ump_interrupt			/* Interrupt packet structure       */
+{
+	__u8 bICode;			/* Interrupt code (interrupt num)   */
+	__u8 bIInfo;			/* Interrupt information            */
+}  __attribute__((packed));
+
+
+#define TIUMP_GET_PORT_FROM_CODE(c)	(((c) >> 4) - 3)
+#define TIUMP_GET_FUNC_FROM_CODE(c)	((c) & 0x0f)
+#define TIUMP_INTERRUPT_CODE_LSR	0x03
+#define TIUMP_INTERRUPT_CODE_MSR	0x04
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/io_usbvend.h linux-2.4.20/drivers/usb/serial/io_usbvend.h
--- linux-2.4.19/drivers/usb/serial/io_usbvend.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/io_usbvend.h	2002-10-29 11:18:34.000000000 +0000
@@ -106,11 +106,23 @@
 #define ION_DEVICE_ID_BB_EDGEPORT_4_DIN		0x011	// Edgeport/4 RS232 with Apple DIN connector
 #define ION_DEVICE_ID_BB_EDGEPORT_16_DUAL_CPU	0x012	// Half of an Edgeport/16 (the kind with 2 EP/8s)
 #define ION_DEVICE_ID_BB_EDGEPORT_8I		0x014	// Edgeport/8 RS422 (single-CPU)
-// These IDs are used by the Edgeport.exe program for uninstalling.
-// 
-#define EDGEPORT_DEVICE_IDS	{0x001, 0x003, 0x004, 0x005, 0x006, 0x007, 0x00B, \
-				 0x00C, 0x00D, 0x00E, 0x00F, 0x010, 0x011, 0x012, \
-				 0x013, 0x014 }
+
+
+/* Edgeport TI based devices */
+#define ION_DEVICE_ID_TI_EDGEPORT_4		0x0201	/* Edgeport/4 RS232 */
+#define ION_DEVICE_ID_TI_EDGEPORT_2		0x0205	/* Edgeport/2 RS232 */
+#define ION_DEVICE_ID_TI_EDGEPORT_4I		0x0206	/* Edgeport/4i RS422 */
+#define ION_DEVICE_ID_TI_EDGEPORT_2I		0x0207	/* Edgeport/2i RS422/RS485 */
+#define ION_DEVICE_ID_TI_EDGEPORT_421		0x020C	/* Edgeport/421 4 hub 2 RS232 + Parallel (lucent on a different hub port) */
+#define ION_DEVICE_ID_TI_EDGEPORT_21		0x020D	/* Edgeport/21 2 RS232 + Parallel (lucent on a different hub port) */
+#define ION_DEVICE_ID_TI_EDGEPORT_1		0x0215	/* Edgeport/1 RS232 */
+#define ION_DEVICE_ID_TI_EDGEPORT_42		0x0217	/* Edgeport/42 4 hub 2 RS232 */
+#define ION_DEVICE_ID_TI_EDGEPORT_22		0x021A	/* Edgeport/22  Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232 */
+
+#define ION_DEVICE_ID_TI_EDGEPORT_421_BOOT	0x0240	/* Edgeport/421 in boot mode */
+#define ION_DEVICE_ID_TI_EDGEPORT_421_DOWN	0x0241	/* Edgeport/421 in download mode first interface is 2 RS232 (Note that the second interface of this multi interface device should be a standard USB class 7 printer port) */
+#define ION_DEVICE_ID_TI_EDGEPORT_21_BOOT	0x0242	/* Edgeport/21 in boot mode */
+#define ION_DEVICE_ID_TI_EDGEPORT_21_DOWN	0x0243	/*Edgeport/42 in download mode: first interface is 2 RS232 (Note that the second interface of this multi interface device should be a standard USB class 7 printer port) */
 
 
 #define	MAKE_USB_PRODUCT_ID( OemId, DeviceId )					\
@@ -196,11 +208,11 @@
 // Version 2 format of DeviceParams. This format is longer (3C0h)
 // and starts lower in memory, at the uppermost 1K in ROM.
 #define	EDGE_MANUF_DESC_ADDR		0x00FF7C00
-#define	EDGE_MANUF_DESC_LEN		sizeof(EDGE_MANUF_DESCRIPTOR)
+#define	EDGE_MANUF_DESC_LEN		sizeof(struct edge_manuf_descriptor)
 
 // Boot params descriptor
 #define	EDGE_BOOT_DESC_ADDR		0x00FF7FC0
-#define	EDGE_BOOT_DESC_LEN		sizeof(EDGE_BOOT_DESCRIPTOR)
+#define	EDGE_BOOT_DESC_LEN		sizeof(struct edge_boot_descriptor)
 
 // Define the max block size that may be read or written
 // in a read/write RAM/ROM command.
@@ -217,7 +229,7 @@
 //		descriptor format, so that they may be separately retrieved,
 //		if necessary, with a minimum of work on the 930. This also
 //		requires them to be in UNICODE format, which, for English at
-//		least, simply means extending each UCHAR into a USHORT.
+//		least, simply means extending each __u8 into a __u16.
 //	3.	For all fields, 00 means 'uninitialized'.
 //	4.	All unused areas should be set to 00 for future expansion.
 //
@@ -241,7 +253,7 @@
 #define MAX_SERIALNUMBER_LEN	12
 #define MAX_ASSEMBLYNUMBER_LEN	14
 
-typedef struct _EDGE_MANUF_DESCRIPTOR {
+struct edge_manuf_descriptor {
 
 	__u16	RootDescTable[0x10];			// C00 Root of descriptor tables (just a placeholder)
 	__u8	DescriptorArea[0x2E0];			// C20 Descriptors go here, up to 2E0h (just a placeholder)
@@ -286,7 +298,7 @@
 	__u8	IonConfig;				// FBF Config byte for ION manufacturing use
 							// FBF end of structure, total len = 3C0h
 
-} EDGE_MANUF_DESCRIPTOR, *PEDGE_MANUF_DESCRIPTOR;
+};
 
 
 #define MANUF_DESC_VER_1	1	// Original definition of MANUF_DESC
@@ -331,10 +343,10 @@
 
 
 
-#define	MANUF_SERNUM_LENGTH		sizeof(((PEDGE_MANUF_DESCRIPTOR)0)->SerialNumber)
-#define	MANUF_ASSYNUM_LENGTH		sizeof(((PEDGE_MANUF_DESCRIPTOR)0)->AssemblyNumber)
-#define	MANUF_OEMASSYNUM_LENGTH		sizeof(((PEDGE_MANUF_DESCRIPTOR)0)->OemAssyNumber)
-#define	MANUF_MANUFDATE_LENGTH		sizeof(((PEDGE_MANUF_DESCRIPTOR)0)->ManufDate)
+#define	MANUF_SERNUM_LENGTH		sizeof(((struct edge_manuf_descriptor *)0)->SerialNumber)
+#define	MANUF_ASSYNUM_LENGTH		sizeof(((struct edge_manuf_descriptor *)0)->AssemblyNumber)
+#define	MANUF_OEMASSYNUM_LENGTH		sizeof(((struct edge_manuf_descriptor *)0)->OemAssyNumber)
+#define	MANUF_MANUFDATE_LENGTH		sizeof(((struct edge_manuf_descriptor *)0)->ManufDate)
 
 #define	MANUF_ION_CONFIG_MASTER		0x80	// 1=Master mode, 0=Normal
 #define	MANUF_ION_CONFIG_DIAG		0x40	// 1=Run h/w diags, 0=norm
@@ -349,7 +361,7 @@
 // - FF:xFFF. Note that the 930-mandated UCONFIG bytes are
 // included in this structure.
 //
-typedef struct _EDGE_BOOT_DESCRIPTOR {
+struct edge_boot_descriptor {
 	__u8		Length;			// C0 Desc length, per USB (= 40h)
 	__u8		DescType;		// C1 Desc type, per USB (= DEVICE type)
 	__u8		DescVer;		// C2 Desc version/format
@@ -373,8 +385,7 @@
 	__u8		UConfig1;		// F9 930-defined CPU configuration byte 1
 	__u8		Reserved3[6];		// FA -- unused, set to 0 --
 						// FF end of structure, total len = 80
-
-} EDGE_BOOT_DESCRIPTOR, *PEDGE_BOOT_DESCRIPTOR;
+};
 
 
 #define BOOT_DESC_VER_1		1	// Original definition of BOOT_PARAMS
@@ -385,5 +396,92 @@
 
 #define	BOOT_CAP_RESET_CMD	0x0001	// If set, boot correctly supports ION_RESET_DEVICE
 
-#endif	// if !defined()
 
+
+/************************************************************************
+                 T I   U M P   D E F I N I T I O N S
+ ***********************************************************************/
+
+//************************************************************************
+//	TI I2C Format Definitions
+//************************************************************************
+#define I2C_DESC_TYPE_INFO_BASIC	1
+#define I2C_DESC_TYPE_FIRMWARE_BASIC	2
+#define I2C_DESC_TYPE_DEVICE		3
+#define I2C_DESC_TYPE_CONFIG		4
+#define I2C_DESC_TYPE_STRING		5
+#define I2C_DESC_TYPE_FIRMWARE_BLANK 	0xf2
+
+#define I2C_DESC_TYPE_MAX		5
+// 3410 may define types 6, 7 for other firmware downloads
+
+// Special section defined by ION
+#define I2C_DESC_TYPE_ION		0	// Not defined by TI
+
+
+struct ti_i2c_desc
+{
+	__u8	Type;			// Type of descriptor
+	__u16	Size;			// Size of data only not including header
+	__u8	CheckSum;		// Checksum (8 bit sum of data only)
+	__u8	Data[0];		// Data starts here
+}__attribute__((packed));
+
+struct ti_i2c_firmware_rec 
+{
+	__u8	Ver_Major;		// Firmware Major version number
+	__u8	Ver_Minor;		// Firmware Minor version number
+	__u8	Data[0];		// Download starts here
+}__attribute__((packed));
+
+
+// Structure of header of download image in fw_down.h
+struct ti_i2c_image_header
+{
+	__u16	Length;
+	__u8	CheckSum;
+}__attribute__((packed));
+
+struct ti_basic_descriptor
+{
+	__u8	Power;		// Self powered
+				// bit 7: 1 - power switching supported
+				//        0 - power switching not supported
+				//
+				// bit 0: 1 - self powered
+				//        0 - bus powered
+				//
+				//
+	__u16	HubVid;		// VID HUB
+	__u16	HubPid;		// PID HUB
+	__u16	DevPid;		// PID Edgeport
+	__u8	HubTime;	// Time for power on to power good
+	__u8	HubCurrent;	// HUB Current = 100ma
+} __attribute__((packed));
+
+
+#define TI_GET_CPU_REVISION(x)		(__u8)((((x)>>4)&0x0f))
+#define TI_GET_BOARD_REVISION(x)	(__u8)(((x)&0x0f))
+
+#define TI_I2C_SIZE_MASK		0x1f  // 5 bits
+#define TI_GET_I2C_SIZE(x)		((((x) & TI_I2C_SIZE_MASK)+1)*256)
+
+#define TI_MAX_I2C_SIZE			( 16 * 1024 )
+
+/* TI USB 5052 definitions */
+struct edge_ti_manuf_descriptor
+{
+	__u8 IonConfig;		//  Config byte for ION manufacturing use
+	__u8 IonConfig2;	//  Expansion
+	__u8 Version;		//  Verqsion
+	__u8 CpuRev_BoardRev;	//  CPU revision level (0xF0) and Board Rev Level (0x0F)
+	__u8 NumPorts;		//  Number of ports	for this UMP
+	__u8 NumVirtualPorts;	//  Number of Virtual ports
+	__u8 HubConfig1;	//  Used to configure the Hub
+	__u8 HubConfig2;	//  Used to configure the Hub
+	__u8 TotalPorts;	//  Total Number of Com Ports for the entire device (All UMPs)
+	__u8 Reserved;
+}__attribute__((packed));
+
+
+#endif		// if !defined()
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/ipaq.c linux-2.4.20/drivers/usb/serial/ipaq.c
--- linux-2.4.19/drivers/usb/serial/ipaq.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/ipaq.c	2002-10-29 11:18:48.000000000 +0000
@@ -9,6 +9,10 @@
  *	the Free Software Foundation; either version 2 of the License, or
  *	(at your option) any later version.
  *
+ * (26/7/2002) ganesh
+ * 	Fixed up broken error handling in ipaq_open. Retry the "kickstart"
+ * 	packet much harder - this drastically reduces connection failures.
+ *
  * (30/4/2002) ganesh
  * 	Added support for the Casio EM500. Completely untested. Thanks
  * 	to info from Nathan <wfilardo@fuse.net>
@@ -34,18 +38,15 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <asm/uaccess.h>
 #include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
@@ -57,6 +58,8 @@
 #include "usb-serial.h"
 #include "ipaq.h"
 
+#define KP_RETRIES	100
+
 /*
  * Version Information
  */
@@ -81,7 +84,7 @@
 static void ipaq_destroy_lists(struct usb_serial_port *port);
 
 
-static __devinitdata struct usb_device_id ipaq_id_table [] = {
+static struct usb_device_id ipaq_id_table [] = {
 	{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) },
@@ -93,24 +96,22 @@
 
 /* All of the device info needed for the Compaq iPAQ */
 struct usb_serial_device_type ipaq_device = {
-	name:			"Compaq iPAQ",
-	id_table:		ipaq_id_table,
-	needs_interrupt_in:	DONT_CARE,
-	needs_bulk_in:		MUST_HAVE,
-	needs_bulk_out:		MUST_HAVE,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		1,
-	num_bulk_out:		1,
-	num_ports:		1,
-	open:			ipaq_open,
-	close:			ipaq_close,
-	startup:		ipaq_startup,
-	shutdown:		ipaq_shutdown,
-	write:			ipaq_write,
-	write_room:		ipaq_write_room,
-	chars_in_buffer:	ipaq_chars_in_buffer,
-	read_bulk_callback:	ipaq_read_bulk_callback,
-	write_bulk_callback:	ipaq_write_bulk_callback,
+	.owner =		THIS_MODULE,
+	.name =			"Compaq iPAQ",
+	.id_table =		ipaq_id_table,
+	.num_interrupt_in =	NUM_DONT_CARE,
+	.num_bulk_in =		1,
+	.num_bulk_out =		1,
+	.num_ports =		1,
+	.open =			ipaq_open,
+	.close =		ipaq_close,
+	.startup =		ipaq_startup,
+	.shutdown =		ipaq_shutdown,
+	.write =		ipaq_write,
+	.write_room =		ipaq_write_room,
+	.chars_in_buffer =	ipaq_chars_in_buffer,
+	.read_bulk_callback =	ipaq_read_bulk_callback,
+	.write_bulk_callback =	ipaq_write_bulk_callback,
 };
 
 static spinlock_t	write_list_lock;
@@ -123,115 +124,110 @@
 	struct ipaq_private	*priv;
 	struct ipaq_packet	*pkt;
 	int			i, result = 0;
+	int			retries = KP_RETRIES;
 
 	if (port_paranoia_check(port, __FUNCTION__)) {
 		return -ENODEV;
 	}
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	down(&port->sem);
-	
-	++port->open_count;
-	MOD_INC_USE_COUNT;
-	
-	if (!port->active) {
-		port->active = 1;
-		bytes_in = 0;
-		bytes_out = 0;
-		priv = (struct ipaq_private *)kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
-		if (priv == NULL) {
-			err(__FUNCTION__ " - Out of memory");
-			return -ENOMEM;
-		}
-		port->private = (void *)priv;
-		priv->active = 0;
-		priv->queue_len = 0;
-		INIT_LIST_HEAD(&priv->queue);
-		INIT_LIST_HEAD(&priv->freelist);
-
-		for (i = 0; i < URBDATA_QUEUE_MAX / PACKET_SIZE; i++) {
-			pkt = kmalloc(sizeof(struct ipaq_packet), GFP_KERNEL);
-			if (pkt == NULL) {
-				goto enomem;
-			}
-			pkt->data = kmalloc(PACKET_SIZE, GFP_KERNEL);
-			if (pkt->data == NULL) {
-				kfree(pkt);
-				goto enomem;
-			}
-			pkt->len = 0;
-			pkt->written = 0;
-			INIT_LIST_HEAD(&pkt->list);
-			list_add(&pkt->list, &priv->freelist);
-			priv->free_len += PACKET_SIZE;
-		}
-
-		/*
-		 * Force low latency on. This will immediately push data to the line
-		 * discipline instead of queueing.
-		 */
-
-		port->tty->low_latency = 1;
-		port->tty->raw = 1;
-		port->tty->real_raw = 1;
-
-		/*
-		 * Lose the small buffers usbserial provides. Make larger ones.
-		 */
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
-		kfree(port->bulk_in_buffer);
-		kfree(port->bulk_out_buffer);
-		port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
-		if (port->bulk_in_buffer == NULL) {
+	bytes_in = 0;
+	bytes_out = 0;
+	priv = (struct ipaq_private *)kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
+	if (priv == NULL) {
+		err("%s - Out of memory", __FUNCTION__);
+		return -ENOMEM;
+	}
+	port->private = (void *)priv;
+	priv->active = 0;
+	priv->queue_len = 0;
+	INIT_LIST_HEAD(&priv->queue);
+	INIT_LIST_HEAD(&priv->freelist);
+
+	for (i = 0; i < URBDATA_QUEUE_MAX / PACKET_SIZE; i++) {
+		pkt = kmalloc(sizeof(struct ipaq_packet), GFP_KERNEL);
+		if (pkt == NULL) {
 			goto enomem;
 		}
-		port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
-		if (port->bulk_out_buffer == NULL) {
-			kfree(port->bulk_in_buffer);
+		pkt->data = kmalloc(PACKET_SIZE, GFP_KERNEL);
+		if (pkt->data == NULL) {
+			kfree(pkt);
 			goto enomem;
 		}
-		port->read_urb->transfer_buffer = port->bulk_in_buffer;
-		port->write_urb->transfer_buffer = port->bulk_out_buffer;
-		port->read_urb->transfer_buffer_length = URBDATA_SIZE;
-		port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE;
-		
-		/* Start reading from the device */
-		FILL_BULK_URB(port->read_urb, serial->dev, 
-			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-			      ipaq_read_bulk_callback, port);
-		result = usb_submit_urb(port->read_urb);
-		if (result) {
-			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
-		}
-
-		/*
-		 * Send out two control messages observed in win98 sniffs. Not sure what
-		 * they do.
-		 */
-
-		result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
-				0x1, 0, NULL, 0, 5 * HZ);
-		if (result < 0) {
-			err(__FUNCTION__ " - failed doing control urb, error %d", result);
-		}
-		result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
-				0x1, 0, NULL, 0, 5 * HZ);
-		if (result < 0) {
-			err(__FUNCTION__ " - failed doing control urb, error %d", result);
-		}
+		pkt->len = 0;
+		pkt->written = 0;
+		INIT_LIST_HEAD(&pkt->list);
+		list_add(&pkt->list, &priv->freelist);
+		priv->free_len += PACKET_SIZE;
+	}
+
+	/*
+	 * Force low latency on. This will immediately push data to the line
+	 * discipline instead of queueing.
+	 */
+
+	port->tty->low_latency = 1;
+	port->tty->raw = 1;
+	port->tty->real_raw = 1;
+
+	/*
+	 * Lose the small buffers usbserial provides. Make larger ones.
+	 */
+
+	kfree(port->bulk_in_buffer);
+	kfree(port->bulk_out_buffer);
+	port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
+	if (port->bulk_in_buffer == NULL) {
+		goto enomem;
 	}
+	port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
+	if (port->bulk_out_buffer == NULL) {
+		kfree(port->bulk_in_buffer);
+		goto enomem;
+	}
+	port->read_urb->transfer_buffer = port->bulk_in_buffer;
+	port->write_urb->transfer_buffer = port->bulk_out_buffer;
+	port->read_urb->transfer_buffer_length = URBDATA_SIZE;
+	port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE;
 	
-	up(&port->sem);
-	
-	return result;
+	/* Start reading from the device */
+	FILL_BULK_URB(port->read_urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+		      ipaq_read_bulk_callback, port);
+	result = usb_submit_urb(port->read_urb);
+	if (result) {
+		err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+		goto error;
+	}
+
+	/*
+	 * Send out control message observed in win98 sniffs. Not sure what
+	 * it does, but from empirical observations, it seems that the device
+	 * will start the chat sequence once one of these messages gets
+	 * through. Since this has a reasonably high failure rate, we retry
+	 * several times.
+	 */
+
+	while (retries--) {
+		result = usb_control_msg(serial->dev,
+				usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
+				0x1, 0, NULL, 0, HZ / 10 + 1);
+		if (result == 0) {
+			return 0;
+		}
+	}
+	err("%s - failed doing control urb, error %d", __FUNCTION__, result);
+	goto error;
 
 enomem:
+	result = -ENOMEM;
+	err("%s - Out of memory", __FUNCTION__);
+error:
 	ipaq_destroy_lists(port);
 	kfree(priv);
-	err(__FUNCTION__ " - Out of memory");
-	return -ENOMEM;
+	return result;
 }
 
 
@@ -244,37 +240,24 @@
 		return; 
 	}
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 			 
 	serial = get_usb_serial(port, __FUNCTION__);
 	if (!serial)
 		return;
-	
-	down (&port->sem);
-
-	--port->open_count;
 
-	if (port->open_count <= 0) {
+	/*
+	 * shut down bulk read and write
+	 */
 
-		/*
-		 * shut down bulk read and write
-		 */
-
-		usb_unlink_urb(port->write_urb);
-		usb_unlink_urb(port->read_urb);
-		ipaq_destroy_lists(port);
-		kfree(priv);
-		port->private = NULL;
-		port->active = 0;
-		port->open_count = 0;
-
-	}
-	up (&port->sem);
+	usb_unlink_urb(port->write_urb);
+	usb_unlink_urb(port->read_urb);
+	ipaq_destroy_lists(port);
+	kfree(priv);
+	port->private = NULL;
 
 	/* Uncomment the following line if you want to see some statistics in your syslog */
 	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
-
-	MOD_DEC_USE_COUNT;
 }
 
 static void ipaq_read_bulk_callback(struct urb *urb)
@@ -288,15 +271,15 @@
 	if (port_paranoia_check(port, __FUNCTION__))
 		return;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
@@ -323,7 +306,7 @@
 		      ipaq_read_bulk_callback, port);
 	result = usb_submit_urb(port->read_urb);
 	if (result)
-		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+		err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
 	return;
 }
 
@@ -334,7 +317,7 @@
 	int			bytes_sent = 0;
 	int			transfer_size;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	usb_serial_debug_data(__FILE__, __FUNCTION__, count, buf);
 	
@@ -361,7 +344,7 @@
 	unsigned long		flags;
 
 	if (priv->free_len <= 0) {
-		dbg(__FUNCTION__ " - we're stuffed");
+		dbg("%s - we're stuffed", __FUNCTION__);
 		return -EAGAIN;
 	}
 
@@ -373,12 +356,13 @@
 	}
 	spin_unlock_irqrestore(&write_list_lock, flags);
 	if (pkt == NULL) {
-		dbg(__FUNCTION__ " - we're stuffed");
+		dbg("%s - we're stuffed", __FUNCTION__);
 		return -EAGAIN;
 	}
 
 	if (from_user) {
-		copy_from_user(pkt->data, buf, count);
+		if (copy_from_user(pkt->data, buf, count))
+			return -EFAULT;
 	} else {
 		memcpy(pkt->data, buf, count);
 	}
@@ -395,7 +379,7 @@
 		spin_unlock_irqrestore(&write_list_lock, flags);
 		result = usb_submit_urb(port->write_urb);
 		if (result) {
-			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+			err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 		}
 	} else {
 		spin_unlock_irqrestore(&write_list_lock, flags);
@@ -414,7 +398,7 @@
 
 	if (urb->status == -EINPROGRESS) {
 		/* Should never happen */
-		err(__FUNCTION__ " - flushing while urb is active !");
+		err("%s - flushing while urb is active !", __FUNCTION__);
 		return;
 	}
 	room = URBDATA_SIZE;
@@ -456,10 +440,10 @@
 		return;
 	}
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 	}
 
 	spin_lock_irqsave(&write_list_lock, flags);
@@ -468,7 +452,7 @@
 		spin_unlock_irqrestore(&write_list_lock, flags);
 		result = usb_submit_urb(port->write_urb);
 		if (result) {
-			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+			err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 		}
 	} else {
 		priv->active = 0;
@@ -484,7 +468,7 @@
 {
 	struct ipaq_private	*priv = (struct ipaq_private *)port->private;
 
-	dbg(__FUNCTION__ " - freelen %d", priv->free_len);
+	dbg("%s - freelen %d", __FUNCTION__, priv->free_len);
 	return priv->free_len;
 }
 
@@ -492,7 +476,7 @@
 {
 	struct ipaq_private	*priv = (struct ipaq_private *)port->private;
 
-	dbg(__FUNCTION__ " - queuelen %d", priv->queue_len);
+	dbg("%s - queuelen %d", __FUNCTION__, priv->queue_len);
 	return priv->queue_len;
 }
 
@@ -520,23 +504,14 @@
 
 static int ipaq_startup(struct usb_serial *serial)
 {
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 	usb_set_configuration(serial->dev, 1);
 	return 0;
 }
 
 static void ipaq_shutdown(struct usb_serial *serial)
 {
-	int i;
-
-	dbg (__FUNCTION__);
-
-	/* stop reads and writes on all ports */
-	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
-			ipaq_close(&serial->port[i], NULL);
-		}
-	}
+	dbg("%s", __FUNCTION__);
 }
 
 static int __init ipaq_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/ipaq.h linux-2.4.20/drivers/usb/serial/ipaq.h
--- linux-2.4.19/drivers/usb/serial/ipaq.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/ipaq.h	2002-10-29 11:18:35.000000000 +0000
@@ -19,7 +19,7 @@
 #define COMPAQ_VENDOR_ID	0x049f
 #define COMPAQ_IPAQ_ID		0x0003
 
-#define HP_VENDOR_ID		0x003f
+#define HP_VENDOR_ID		0x03f0
 #define HP_JORNADA_548_ID	0x1016
 #define HP_JORNADA_568_ID	0x1116
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/ir-usb.c linux-2.4.20/drivers/usb/serial/ir-usb.c
--- linux-2.4.19/drivers/usb/serial/ir-usb.c	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/ir-usb.c	2002-10-29 11:18:40.000000000 +0000
@@ -1,8 +1,8 @@
 /*
  * USB IR Dongle driver
  *
- *	Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
- *	Copyright (C) 2002 Gary Brubaker (xavyer@ix.netcom.com)
+ *	Copyright (C) 2001-2002	Greg Kroah-Hartman (greg@kroah.com)
+ *	Copyright (C) 2002	Gary Brubaker (xavyer@ix.netcom.com)
  *
  *	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
@@ -21,6 +21,11 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * 2002_Mar_07	greg kh
+ *	moved some needed structures and #define values from the
+ *	net/irda/irda-usb.h file into our file, as we don't want to depend on
+ *	that codebase compiling correctly :)
+ *
  * 2002_Jan_14  gb
  *	Added module parameter to force specific number of XBOFs.
  *	Added ir_xbof_change().
@@ -43,20 +48,16 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <asm/uaccess.h>
 #include <linux/usb.h>
-#include <net/irda/irda-usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
 	static int debug = 1;
@@ -73,6 +74,33 @@
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC "USB IR Dongle driver"
 
+/* USB IrDA class spec information */
+#define USB_CLASS_IRDA		0x02
+#define USB_DT_IRDA		0x21
+#define IU_REQ_GET_CLASS_DESC	0x06
+#define SPEED_2400		0x01
+#define SPEED_9600		0x02
+#define SPEED_19200		0x03
+#define SPEED_38400		0x04
+#define SPEED_57600		0x05
+#define SPEED_115200		0x06
+#define SPEED_576000		0x07
+#define SPEED_1152000		0x08
+#define SPEED_4000000		0x09
+
+struct irda_class_desc {
+	u8	bLength;
+	u8	bDescriptorType;
+	u16	bcdSpecRevision;
+	u8	bmDataSize;
+	u8	bmWindowSize;
+	u8	bmMinTurnaroundTime;
+	u16	wBaudRate;
+	u8	bmAdditionalBOFs;
+	u8	bIrdaRateSniff;
+	u8	bMaxUnicastList;
+} __attribute__ ((packed));
+
 /* if overridden by the user, then use their value for the size of the read and
  * write urbs */
 static int buffer_size = 0;
@@ -91,7 +119,7 @@
 static u8 ir_xbof = 0;
 static u8 ir_add_bof = 0;
 
-static __devinitdata struct usb_device_id id_table [] = {
+static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(0x050f, 0x0180) },		/* KC Technology, KC-180 */
 	{ USB_DEVICE(0x08e9, 0x0100) },		/* XTNDAccess */
 	{ USB_DEVICE(0x09c4, 0x0011) },		/* ACTiSys ACT-IR2000U */
@@ -103,22 +131,20 @@
 
 
 struct usb_serial_device_type ir_device = {
-	name:			"IR Dongle",
-	id_table:		id_table,
-	needs_interrupt_in:	MUST_HAVE,
-	needs_bulk_in:		MUST_HAVE,
-	needs_bulk_out:		MUST_HAVE,
-	num_interrupt_in:	1,
-	num_bulk_in:		1,
-	num_bulk_out:		1,
-	num_ports:		1,
-	set_termios:		ir_set_termios,
-	startup:		ir_startup,
-	open:			ir_open,
-	close:			ir_close,
-	write:			ir_write,
-	write_bulk_callback:	ir_write_bulk_callback,
-	read_bulk_callback:	ir_read_bulk_callback,
+	.owner =		THIS_MODULE,
+	.name =			"IR Dongle",
+	.id_table =		id_table,
+	.num_interrupt_in =	1,
+	.num_bulk_in =		1,
+	.num_bulk_out =		1,
+	.num_ports =		1,
+	.set_termios =		ir_set_termios,
+	.startup =		ir_startup,
+	.open =			ir_open,
+	.close =		ir_close,
+	.write =		ir_write,
+	.write_bulk_callback =	ir_write_bulk_callback,
+	.read_bulk_callback =	ir_read_bulk_callback,
 };
 
 static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc)
@@ -160,7 +186,7 @@
 	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
 			IU_REQ_GET_CLASS_DESC,
 			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-			0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500));
+			0, ifnum, desc, sizeof(*desc), HZ);
 	
 	dbg("%s -  ret=%d", __FUNCTION__, ret);
 	if (ret < sizeof(*desc)) {
@@ -235,7 +261,7 @@
 		case 0x20: ir_add_bof =  2; break;
 		case 0x40: ir_add_bof =  1; break;
 		case 0x80: ir_add_bof =  0; break;
-		default:
+		default:;
 	}
 
 	kfree (irda_desc);
@@ -254,53 +280,42 @@
 	
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	down (&port->sem);
-	
-	++port->open_count;
-	MOD_INC_USE_COUNT;
-	
-	if (!port->active) {
-		port->active = 1;
-
-		if (buffer_size) {
-			/* override the default buffer sizes */
-			buffer = kmalloc (buffer_size, GFP_KERNEL);
-			if (!buffer) {
-				err ("%s - out of memory.", __FUNCTION__);
-				return -ENOMEM;
-			}
-			kfree (port->read_urb->transfer_buffer);
-			port->read_urb->transfer_buffer = buffer;
-			port->read_urb->transfer_buffer_length = buffer_size;
-
-			buffer = kmalloc (buffer_size, GFP_KERNEL);
-			if (!buffer) {
-				err ("%s - out of memory.", __FUNCTION__);
-				return -ENOMEM;
-			}
-			kfree (port->write_urb->transfer_buffer);
-			port->write_urb->transfer_buffer = buffer;
-			port->write_urb->transfer_buffer_length = buffer_size;
-			port->bulk_out_size = buffer_size;
+	if (buffer_size) {
+		/* override the default buffer sizes */
+		buffer = kmalloc (buffer_size, GFP_KERNEL);
+		if (!buffer) {
+			err ("%s - out of memory.", __FUNCTION__);
+			return -ENOMEM;
 		}
-
-		/* Start reading from the device */
-		usb_fill_bulk_urb (
-			port->read_urb,
-			serial->dev, 
-			usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-			port->read_urb->transfer_buffer,
-			port->read_urb->transfer_buffer_length,
-			ir_read_bulk_callback,
-			port);
-		port->read_urb->transfer_flags = USB_QUEUE_BULK;
-		result = usb_submit_urb(port->read_urb);
-		if (result)
-			err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+		kfree (port->read_urb->transfer_buffer);
+		port->read_urb->transfer_buffer = buffer;
+		port->read_urb->transfer_buffer_length = buffer_size;
+
+		buffer = kmalloc (buffer_size, GFP_KERNEL);
+		if (!buffer) {
+			err ("%s - out of memory.", __FUNCTION__);
+			return -ENOMEM;
+		}
+		kfree (port->write_urb->transfer_buffer);
+		port->write_urb->transfer_buffer = buffer;
+		port->write_urb->transfer_buffer_length = buffer_size;
+		port->bulk_out_size = buffer_size;
 	}
-	
-	up (&port->sem);
-	
+
+	/* Start reading from the device */
+	usb_fill_bulk_urb (
+		port->read_urb,
+		serial->dev, 
+		usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+		port->read_urb->transfer_buffer,
+		port->read_urb->transfer_buffer_length,
+		ir_read_bulk_callback,
+		port);
+	port->read_urb->transfer_flags = USB_QUEUE_BULK;
+	result = usb_submit_urb(port->read_urb);
+	if (result)
+		err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+
 	return result;
 }
 
@@ -317,21 +332,10 @@
 	if (!serial)
 		return;
 	
-	down (&port->sem);
-
-	--port->open_count;
-
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			/* shutdown our bulk read */
-			usb_unlink_urb (port->read_urb);
-		}
-		port->active = 0;
-		port->open_count = 0;
-
+	if (serial->dev) {
+		/* shutdown our bulk read */
+		usb_unlink_urb (port->read_urb);
 	}
-	up (&port->sem);
-	MOD_DEC_USE_COUNT;
 }
 
 static int ir_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
@@ -442,7 +446,7 @@
 		return;
 	}
 
-	if (!port->active) {
+	if (!port->open_count) {
 		dbg("%s - port closed.", __FUNCTION__);
 		return;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/keyspan.c linux-2.4.20/drivers/usb/serial/keyspan.c
--- linux-2.4.19/drivers/usb/serial/keyspan.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/keyspan.c	2002-10-29 11:18:33.000000000 +0000
@@ -1,8 +1,8 @@
 /*
   Keyspan USB to Serial Converter driver
  
-  (C) Copyright (C) 2000-2001
-      Hugh Blemings <hugh@misc.nu>
+  (C) Copyright (C) 2000-2001	Hugh Blemings <hugh@blemings.org>
+  (C) Copyright (C) 2002	Greg Kroah-Hartman <greg@kroah.com>
    
   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
@@ -28,6 +28,17 @@
 
   Change History
 
+    Wed Apr 25 12:00:00 PST 2002 (Keyspan)
+      Started with Hugh Blemings' code dated Jan 17, 2002.  All adapters
+      now supported (including QI and QW).  Modified port open, port
+      close, and send setup() logic to fix various data and endpoint
+      synchronization bugs and device LED status bugs.  Changed keyspan_
+      write_room() to accurately return transmit buffer availability.
+      Changed forwardingLength from 1 to 16 for all adapters.
+
+    Fri Oct 12 16:45:00 EST 2001
+      Preliminary USA-19QI and USA-28 support (both test OK for me, YMMV)
+
     Mon Oct  8 14:29:00 EST 2001 hugh
       Fixed bug that prevented mulitport devices operating correctly
       if they weren't the first unit attached.
@@ -65,19 +76,15 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
-#include <linux/usb.h>
+#include <asm/uaccess.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
 	static int debug = 1;
@@ -95,7 +102,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.1.1"
+#define DRIVER_VERSION "v1.1.3"
 #define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
 #define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
 
@@ -107,13 +114,13 @@
 	/* number of active ports */
 	atomic_t	active_count;
 
-	const keyspan_device_details	*device_details;
+	const struct keyspan_device_details	*device_details;
 
-	urb_t		*instat_urb;
+	struct urb	*instat_urb;
 	char		instat_buf[INSTAT_BUFLEN];
 
 	/* XXX this one probably will need a lock */
-	urb_t		*glocont_urb;
+	struct urb	*glocont_urb;
 	char		glocont_buf[GLOCONT_BUFLEN];
 };
 
@@ -125,21 +132,21 @@
 	/* Keep duplicate of device details in each port
 	   structure as well - simplifies some of the
 	   callback functions etc. */
-	const keyspan_device_details	*device_details;
+	const struct keyspan_device_details	*device_details;
 
 	/* Input endpoints and buffer for this port */
-	urb_t		*in_urbs[2];
+	struct urb	*in_urbs[2];
 	char		in_buffer[2][64];
 	/* Output endpoints and buffer for this port */
-	urb_t		*out_urbs[2];
+	struct urb	*out_urbs[2];
 	char		out_buffer[2][64];
 
 	/* Input ack endpoint */
-	urb_t		*inack_urb;
+	struct urb	*inack_urb;
 	char		inack_buffer[1];
 
 	/* Output control endpoint */
-	urb_t		*outcont_urb;
+	struct urb	*outcont_urb;
 	char		outcont_buffer[64];
 
 	/* Settings for the port */
@@ -167,34 +174,14 @@
 #include "keyspan_usa28msg.h"
 #include "keyspan_usa49msg.h"
 	
-/* If you don't get debugging output, uncomment the following
-   two lines to enable cheat. */
-#if 0
-  #undef 	dbg 
-  #define	dbg	printk 
-#endif
-
 
 /* Functions used by new usb-serial code. */
 static int __init keyspan_init (void)
 {
-	usb_serial_register (&keyspan_usa18x_pre_device);
-	usb_serial_register (&keyspan_usa19_pre_device);
-	usb_serial_register (&keyspan_usa19w_pre_device);
-	usb_serial_register (&keyspan_usa28_pre_device);
-	usb_serial_register (&keyspan_usa28x_pre_device);
-	usb_serial_register (&keyspan_usa28xa_pre_device);
-	usb_serial_register (&keyspan_usa28xb_pre_device);
-	usb_serial_register (&keyspan_usa49w_pre_device);
-
-	usb_serial_register (&keyspan_usa18x_device);
-	usb_serial_register (&keyspan_usa19_device);
-	usb_serial_register (&keyspan_usa19w_device);
-	usb_serial_register (&keyspan_usa28_device);
-	usb_serial_register (&keyspan_usa28x_device);
-	usb_serial_register (&keyspan_usa28xa_device);
-	/* We don't need a separate entry for the usa28xb as it appears as a 28x anyway */
-	usb_serial_register (&keyspan_usa49w_device);
+	usb_serial_register (&keyspan_pre_device);
+	usb_serial_register (&keyspan_1port_device);
+	usb_serial_register (&keyspan_2port_device);
+	usb_serial_register (&keyspan_4port_device);
 
 	info(DRIVER_VERSION ":" DRIVER_DESC);
 
@@ -203,23 +190,10 @@
 
 static void __exit keyspan_exit (void)
 {
-	usb_serial_deregister (&keyspan_usa18x_pre_device);
-	usb_serial_deregister (&keyspan_usa19_pre_device);
-	usb_serial_deregister (&keyspan_usa19w_pre_device);
-	usb_serial_deregister (&keyspan_usa28_pre_device);
-	usb_serial_deregister (&keyspan_usa28x_pre_device);
-	usb_serial_deregister (&keyspan_usa28xa_pre_device);
-	usb_serial_deregister (&keyspan_usa28xb_pre_device);
-	usb_serial_deregister (&keyspan_usa49w_pre_device);
-
-	usb_serial_deregister (&keyspan_usa18x_device);
-	usb_serial_deregister (&keyspan_usa19_device);
-	usb_serial_deregister (&keyspan_usa19w_device);
-	usb_serial_deregister (&keyspan_usa28_device);
-	usb_serial_deregister (&keyspan_usa28x_device);
-	usb_serial_deregister (&keyspan_usa28xa_device);
-	/* We don't need a separate entry for the usa28xb as it appears as a 28x anyway */
-	usb_serial_deregister (&keyspan_usa49w_device);
+	usb_serial_deregister (&keyspan_pre_device);
+	usb_serial_deregister (&keyspan_1port_device);
+	usb_serial_deregister (&keyspan_2port_device);
+	usb_serial_deregister (&keyspan_4port_device);
 }
 
 module_init(keyspan_init);
@@ -227,13 +201,13 @@
 
 static void keyspan_rx_throttle (struct usb_serial_port *port)
 {
-	dbg("keyspan_rx_throttle port %d\n", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 }
 
 
 static void keyspan_rx_unthrottle (struct usb_serial_port *port)
 {
-	dbg("keyspan_rx_unthrottle port %d\n", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 }
 
 
@@ -241,7 +215,7 @@
 {
 	struct keyspan_port_private 	*p_priv;
 
- 	dbg("keyspan_break_ctl\n");
+ 	dbg("%s", __FUNCTION__);
 
 	p_priv = (struct keyspan_port_private *)port->private;
 
@@ -257,16 +231,17 @@
 static void keyspan_set_termios (struct usb_serial_port *port, 
 				     struct termios *old_termios)
 {
-	int				baud_rate;
+	int				baud_rate, device_port;
 	struct keyspan_port_private 	*p_priv;
-	const keyspan_device_details	*d_details;
+	const struct keyspan_device_details	*d_details;
 	unsigned int 			cflag;
 
-	dbg(__FUNCTION__ ".\n"); 
+	dbg("%s", __FUNCTION__); 
 
 	p_priv = (struct keyspan_port_private *)(port->private);
 	d_details = p_priv->device_details;
 	cflag = port->tty->termios->c_cflag;
+	device_port = port->number - port->serial->minor;
 
 	/* Baud rate calculation takes baud rate as an integer
 	   so other rates can be generated if desired. */
@@ -274,7 +249,7 @@
 	/* If no match or invalid, don't change */		
 	if (baud_rate >= 0
 	    && d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
-				NULL, NULL, NULL) == KEYSPAN_BAUD_RATE_OK) {
+				NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
 		/* FIXME - more to do here to ensure rate changes cleanly */
 		p_priv->baud = baud_rate;
 	}
@@ -337,19 +312,17 @@
 			 const unsigned char *buf, int count)
 {
 	struct keyspan_port_private 	*p_priv;
-	const keyspan_device_details	*d_details;
+	const struct keyspan_device_details	*d_details;
 	int				flip;
 	int 				left, todo;
-	urb_t 				*this_urb;
+	struct urb			*this_urb;
 	int 				err;
 
 	p_priv = (struct keyspan_port_private *)(port->private);
 	d_details = p_priv->device_details;
 
-#if 0
-	dbg(__FUNCTION__ " for port %d (%d chars [%x]), flip=%d\n",
-	    port->number, count, buf[0], p_priv->out_flip);
-#endif
+	dbg("%s - for port %d (%d chars [%x]), flip=%d",
+	    __FUNCTION__, port->number, count, buf[0], p_priv->out_flip);
 
 	for (left = count; left > 0; left -= todo) {
 		todo = left;
@@ -361,11 +334,11 @@
 		/* Check we have a valid urb/endpoint before we use it... */
 		if ((this_urb = p_priv->out_urbs[flip]) == 0) {
 			/* no bulk out, so return 0 bytes written */
-			dbg(__FUNCTION__ " no output urb :(\n");
+			dbg("%s - no output urb :(", __FUNCTION__);
 			return count;
 		}
 
-		dbg(__FUNCTION__ " endpoint %d\n", usb_pipeendpoint(this_urb->pipe));
+		dbg("%s - endpoint %d flip %d", __FUNCTION__, usb_pipeendpoint(this_urb->pipe), flip);
 
 		if (this_urb->status == -EINPROGRESS) {
 			if (this_urb->transfer_flags & USB_ASYNC_UNLINK)
@@ -395,7 +368,7 @@
 		this_urb->transfer_flags &= ~USB_ASYNC_UNLINK;
 		this_urb->dev = port->serial->dev;
 		if ((err = usb_submit_urb(this_urb)) != 0) {
-			dbg("usb_submit_urb(write bulk) failed (%d)\n", err);
+			dbg("usb_submit_urb(write bulk) failed (%d)", err);
 		}
 		p_priv->tx_start_time[flip] = jiffies;
 
@@ -415,26 +388,28 @@
 	struct tty_struct	*tty;
 	unsigned char 		*data = urb->transfer_buffer;
 
-	dbg ("%s\n", __FUNCTION__); 
+	dbg ("%s", __FUNCTION__); 
 
 	endpoint = usb_pipeendpoint(urb->pipe);
 
 	if (urb->status) {
-		dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.\n",
-			      		urb->status, endpoint);
+		dbg("%s - nonzero status: %x on endpoint %d.",
+		    __FUNCTION__, urb->status, endpoint);
 		return;
 	}
 
 	port = (struct usb_serial_port *) urb->context;
 	tty = port->tty;
 	if (urb->actual_length) {
-		if (data[0] == 0) {
+		/* 0x80 bit is error flag */
+		if ((data[0] & 0x80) == 0) {
 			/* no error on any byte */
 			for (i = 1; i < urb->actual_length ; ++i) {
 				tty_insert_flip_char(tty, data[i], 0);
 			}
 		} else {
 			/* some bytes had errors, every byte has status */
+			dbg("%s - RX error!!!!", __FUNCTION__);
 			for (i = 0; i + 1 < urb->actual_length; i += 2) {
 				int stat = data[i], flag = 0;
 				if (stat & RXERROR_OVERRUN)
@@ -452,9 +427,10 @@
 				
 		/* Resubmit urb so we continue receiving */
 	urb->dev = port->serial->dev;
-	if ((err = usb_submit_urb(urb)) != 0) {
-		dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err);
-	}
+	if (port->open_count)
+		if ((err = usb_submit_urb(urb)) != 0) {
+			dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+		}
 	return;
 }
 
@@ -466,9 +442,9 @@
 
 	port = (struct usb_serial_port *) urb->context;
 	p_priv = (struct keyspan_port_private *)(port->private);
-	dbg (__FUNCTION__ " urb %d\n", urb == p_priv->out_urbs[1]); 
+	dbg ("%s - urb %d", __FUNCTION__, urb == p_priv->out_urbs[1]); 
 
-	if (port->active) {
+	if (port->open_count) {
 		queue_task(&port->tqueue, &tq_immediate);
 		mark_bh(IMMEDIATE_BH);
 	}
@@ -476,7 +452,7 @@
 
 static void	usa26_inack_callback(struct urb *urb)
 {
-	dbg ("%s\n", __FUNCTION__); 
+	dbg ("%s", __FUNCTION__); 
 	
 }
 
@@ -489,15 +465,15 @@
 	p_priv = (struct keyspan_port_private *)(port->private);
 
 	if (p_priv->resend_cont) {
-		dbg (__FUNCTION__ " sending setup\n"); 
-		keyspan_usa26_send_setup(port->serial, port, 0);
+		dbg ("%s - sending setup", __FUNCTION__); 
+		keyspan_usa26_send_setup(port->serial, port, p_priv->resend_cont - 1);
 	}
 }
 
 static void	usa26_instat_callback(struct urb *urb)
 {
 	unsigned char 				*data = urb->transfer_buffer;
-	keyspan_usa26_portStatusMessage		*msg;
+	struct keyspan_usa26_portStatusMessage	*msg;
 	struct usb_serial			*serial;
 	struct usb_serial_port			*port;
 	struct keyspan_port_private	 	*p_priv;
@@ -506,19 +482,19 @@
 	serial = (struct usb_serial *) urb->context;
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " nonzero status: %x\n", urb->status);
+		dbg("%s - nonzero status: %x", __FUNCTION__, urb->status);
 		return;
 	}
 	if (urb->actual_length != 9) {
-		dbg(__FUNCTION__ " %d byte report??\n", urb->actual_length);
+		dbg("%s - %d byte report??", __FUNCTION__, urb->actual_length);
 		goto exit;
 	}
 
-	msg = (keyspan_usa26_portStatusMessage *)data;
+	msg = (struct keyspan_usa26_portStatusMessage *)data;
 
 #if 0
-	dbg(__FUNCTION__ " port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d\n",
-	    msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr, msg->ri, msg->_txOff,
+	dbg("%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
+	    __FUNCTION__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr, msg->ri, msg->_txOff,
 	    msg->_txXoff, msg->rxEnabled, msg->controlResponse);
 #endif
 
@@ -527,7 +503,7 @@
 
 	/* Check port number from message and retrieve private data */	
 	if (msg->port >= serial->num_ports) {
-		dbg ("Unexpected port number %d\n", msg->port);
+		dbg ("%s - Unexpected port number %d", __FUNCTION__, msg->port);
 		goto exit;
 	}
 	port = &serial->port[msg->port];
@@ -548,17 +524,17 @@
 		/*	wake_up_interruptible(&p_priv->open_wait); */
 	}
 	
-exit:
 	/* Resubmit urb so we continue receiving */
 	urb->dev = serial->dev;
 	if ((err = usb_submit_urb(urb)) != 0) {
-		dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err);
+		dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
 	}
+exit:
 }
 
 static void	usa26_glocont_callback(struct urb *urb)
 {
-	dbg ("%s\n", __FUNCTION__);
+	dbg ("%s", __FUNCTION__);
 	
 }
 
@@ -571,7 +547,7 @@
 	unsigned char           *data;
 	struct keyspan_port_private             *p_priv;
 
-	dbg ("%s\n", __FUNCTION__);
+	dbg ("%s", __FUNCTION__);
 
 	port = (struct usb_serial_port *) urb->context;
 	p_priv = (struct keyspan_port_private *)(port->private);
@@ -582,9 +558,8 @@
 
 	do {
 		if (urb->status) {
-			dbg(__FUNCTION__ "nonzero status: %x on endpoint
-%d.\n",
-			    urb->status, usb_pipeendpoint(urb->pipe));
+			dbg("%s - nonzero status: %x on endpoint %d.",
+			    __FUNCTION__, urb->status, usb_pipeendpoint(urb->pipe));
 			return;
 		}
 
@@ -602,10 +577,10 @@
 
 		/* Resubmit urb so we continue receiving */
 		urb->dev = port->serial->dev;
-		if ((err = usb_submit_urb(urb)) != 0) {
-			dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n",
-err);
-		}
+		if (port->open_count)
+			if ((err = usb_submit_urb(urb)) != 0) {
+				dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+			}
 		p_priv->in_flip ^= 1;
 
 		urb = p_priv->in_urbs[p_priv->in_flip];
@@ -614,7 +589,7 @@
 
 static void	usa28_inack_callback(struct urb *urb)
 {
-	dbg ("%s\n", __FUNCTION__);
+	dbg ("%s", __FUNCTION__);
 }
 
 static void	usa28_outcont_callback(struct urb *urb)
@@ -626,8 +601,8 @@
 	p_priv = (struct keyspan_port_private *)(port->private);
 
 	if (p_priv->resend_cont) {
-		dbg (__FUNCTION__ " sending setup\n");
-		keyspan_usa28_send_setup(port->serial, port, 0);
+		dbg ("%s - sending setup", __FUNCTION__);
+		keyspan_usa28_send_setup(port->serial, port, p_priv->resend_cont - 1);
 	}
 }
 
@@ -635,7 +610,7 @@
 {
 	int					err;
 	unsigned char 				*data = urb->transfer_buffer;
-	keyspan_usa28_portStatusMessage		*msg;
+	struct keyspan_usa28_portStatusMessage	*msg;
 	struct usb_serial			*serial;
 	struct usb_serial_port			*port;
 	struct keyspan_port_private	 	*p_priv;
@@ -644,26 +619,26 @@
 	serial = (struct usb_serial *) urb->context;
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " nonzero status: %x\n", urb->status);
+		dbg("%s - nonzero status: %x", __FUNCTION__, urb->status);
 		return;
 	}
 
 	if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
-		dbg(__FUNCTION__ " bad length %d\n", urb->actual_length);
+		dbg("%s - bad length %d", __FUNCTION__, urb->actual_length);
 		goto exit;
 	}
 
-	/*dbg(__FUNCTION__ " %x %x %x %x %x %x %x %x %x %x %x %x\n",
+	/*dbg("%s %x %x %x %x %x %x %x %x %x %x %x %x", __FUNCTION__
 	    data[0], data[1], data[2], data[3], data[4], data[5],
 	    data[6], data[7], data[8], data[9], data[10], data[11]);*/
 	
 		/* Now do something useful with the data */
-	msg = (keyspan_usa28_portStatusMessage *)data;
+	msg = (struct keyspan_usa28_portStatusMessage *)data;
 
 
 		/* Check port number from message and retrieve private data */	
 	if (msg->port >= serial->num_ports) {
-		dbg ("Unexpected port number %d\n", msg->port);
+		dbg ("%s - Unexpected port number %d", __FUNCTION__, msg->port);
 		goto exit;
 	}
 	port = &serial->port[msg->port];
@@ -684,17 +659,17 @@
 		/*	wake_up_interruptible(&p_priv->open_wait); */
 	}
 
-exit:	
 		/* Resubmit urb so we continue receiving */
 	urb->dev = serial->dev;
 	if ((err = usb_submit_urb(urb)) != 0) {
-		dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err);
+		dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
 	}
+exit:	
 }
 
 static void	usa28_glocont_callback(struct urb *urb)
 {
-	dbg ("%s\n", __FUNCTION__);
+	dbg ("%s", __FUNCTION__);
 }
 
 
@@ -705,7 +680,7 @@
 	struct keyspan_port_private *p_priv;
 	int i;
 
-	dbg ("%s\n", __FUNCTION__);
+	dbg ("%s", __FUNCTION__);
 
 	serial = (struct usb_serial *) urb->context;
 	for (i = 0; i < serial->num_ports; ++i) {
@@ -713,8 +688,8 @@
 		p_priv = (struct keyspan_port_private *)(port->private);
 
 		if (p_priv->resend_cont) {
-			dbg (__FUNCTION__ " sending setup\n"); 
-			keyspan_usa49_send_setup(serial, port, 0);
+			dbg ("%s - sending setup", __FUNCTION__); 
+			keyspan_usa49_send_setup(serial, port, p_priv->resend_cont - 1);
 			break;
 		}
 	}
@@ -726,36 +701,36 @@
 {
 	int					err;
 	unsigned char 				*data = urb->transfer_buffer;
-	keyspan_usa49_portStatusMessage		*msg;
+	struct keyspan_usa49_portStatusMessage	*msg;
 	struct usb_serial			*serial;
 	struct usb_serial_port			*port;
 	struct keyspan_port_private	 	*p_priv;
 	int old_dcd_state;
 
-	dbg ("%s\n", __FUNCTION__);
+	dbg ("%s", __FUNCTION__);
 
 	serial = (struct usb_serial *) urb->context;
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " nonzero status: %x\n", urb->status);
+		dbg("%s - nonzero status: %x", __FUNCTION__, urb->status);
 		return;
 	}
 
 	if (urb->actual_length != sizeof(struct keyspan_usa49_portStatusMessage)) {
-		dbg(__FUNCTION__ " bad length %d\n", urb->actual_length);
+		dbg("%s - bad length %d", __FUNCTION__, urb->actual_length);
 		goto exit;
 	}
 
-	/*dbg(__FUNCTION__ " %x %x %x %x %x %x %x %x %x %x %x\n",
+	/*dbg(" %x %x %x %x %x %x %x %x %x %x %x", __FUNCTION__, 
 	    data[0], data[1], data[2], data[3], data[4], data[5],
 	    data[6], data[7], data[8], data[9], data[10]);*/
 	
 		/* Now do something useful with the data */
-	msg = (keyspan_usa49_portStatusMessage *)data;
+	msg = (struct keyspan_usa49_portStatusMessage *)data;
 
 		/* Check port number from message and retrieve private data */	
 	if (msg->portNumber >= serial->num_ports) {
-		dbg ("Unexpected port number %d\n", msg->portNumber);
+		dbg ("%s - Unexpected port number %d", __FUNCTION__, msg->portNumber);
 		goto exit;
 	}
 	port = &serial->port[msg->portNumber];
@@ -776,18 +751,18 @@
 		/*	wake_up_interruptible(&p_priv->open_wait); */
 	}
 
-exit:	
 		/* Resubmit urb so we continue receiving */
 	urb->dev = serial->dev;
 
 	if ((err = usb_submit_urb(urb)) != 0) {
-		dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err);
+		dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
 	}
+exit:	
 }
 
 static void	usa49_inack_callback(struct urb *urb)
 {
-	dbg ("%s\n", __FUNCTION__);
+	dbg ("%s", __FUNCTION__);
 }
 
 static void	usa49_indat_callback(struct urb *urb)
@@ -798,20 +773,21 @@
 	struct tty_struct	*tty;
 	unsigned char 		*data = urb->transfer_buffer;
 
-	dbg ("%s\n", __FUNCTION__);
+	dbg ("%s", __FUNCTION__);
 
 	endpoint = usb_pipeendpoint(urb->pipe);
 
 	if (urb->status) {
-		dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.\n",
-			      		urb->status, endpoint);
+		dbg("%s - nonzero status: %x on endpoint %d.", __FUNCTION__,
+		    urb->status, endpoint);
 		return;
 	}
 
 	port = (struct usb_serial_port *) urb->context;
 	tty = port->tty;
 	if (urb->actual_length) {
-		if (data[0] == 0) {
+		/* 0x80 bit is error flag */
+		if ((data[0] & 0x80) == 0) {
 			/* no error on any byte */
 			for (i = 1; i < urb->actual_length ; ++i) {
 				tty_insert_flip_char(tty, data[i], 0);
@@ -835,24 +811,43 @@
 				
 		/* Resubmit urb so we continue receiving */
 	urb->dev = port->serial->dev;
-	if ((err = usb_submit_urb(urb)) != 0) {
-		dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err);
-	}
+	if (port->open_count)
+		if ((err = usb_submit_urb(urb)) != 0) {
+			dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+		}
 }
 
 /* not used, usa-49 doesn't have per-port control endpoints */
 static void	usa49_outcont_callback(struct urb *urb)
 {
-	dbg ("%s\n", __FUNCTION__);
+	dbg ("%s", __FUNCTION__);
 }
 
 
 
 static int keyspan_write_room (struct usb_serial_port *port)
 {
-	dbg("keyspan_write_room called\n");
-	return (32);
+	struct keyspan_port_private	*p_priv;
+	const struct keyspan_device_details	*d_details;
+	int				flip;
+	struct urb			*this_urb;
 
+	dbg("%s", __FUNCTION__);
+	p_priv = (struct keyspan_port_private *)(port->private);
+	d_details = p_priv->device_details;
+
+	flip = p_priv->out_flip;
+
+	/* Check both endpoints to see if any are available. */
+	if ((this_urb = p_priv->out_urbs[flip]) != 0) {
+		if (this_urb->status != -EINPROGRESS)
+			return (63);
+		flip = (flip + 1) & d_details->outdat_endp_flip;        
+		if ((this_urb = p_priv->out_urbs[flip]) != 0) 
+			if (this_urb->status != -EINPROGRESS)
+				return (63);
+	}
+	return (0);
 }
 
 
@@ -867,26 +862,15 @@
 	struct keyspan_port_private 	*p_priv;
 	struct keyspan_serial_private 	*s_priv;
 	struct usb_serial 		*serial = port->serial;
-	const keyspan_device_details	*d_details;
-	int				i, already_active, err;
-	urb_t *urb;
+	const struct keyspan_device_details	*d_details;
+	int				i, err;
+	struct urb			*urb;
 
 	s_priv = (struct keyspan_serial_private *)(serial->private);
 	p_priv = (struct keyspan_port_private *)(port->private);
 	d_details = s_priv->device_details;
 	
-	dbg("keyspan_open called for port%d.\n", port->number); 
-
-	MOD_INC_USE_COUNT;
-
-	down (&port->sem);
-	++port->open_count;
-	already_active = port->active;
-	port->active = 1;
-	up (&port->sem);
-
-	if (already_active)
-		return 0;
+	dbg("%s - port%d.", __FUNCTION__, port->number); 
 
 	p_priv = (struct keyspan_port_private *)(port->private);
 	
@@ -894,22 +878,37 @@
 	p_priv->rts_state = 1;
 	p_priv->dtr_state = 1;
 
-	/* Start reading from endpoints */
+	p_priv->out_flip = 0;
+	p_priv->in_flip = 0;
+
+	/* Reset low level data toggle and start reading from endpoints */
 	for (i = 0; i < 2; i++) {
 		if ((urb = p_priv->in_urbs[i]) == NULL)
 			continue;
 		urb->dev = serial->dev;
+		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 0);
+
 		if ((err = usb_submit_urb(urb)) != 0) {
-			dbg(__FUNCTION__ " submit urb %d failed (%d)\n", i, err);
+			dbg("%s - submit urb %d failed (%d)", __FUNCTION__, i, err);
 		}
 	}
 
+	/* Reset low level data toggle on out endpoints */
+	for (i = 0; i < 2; i++) {
+		if ((urb = p_priv->out_urbs[i]) == NULL)
+			continue;
+		urb->dev = serial->dev;
+		/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 0); */
+	}
+
+	keyspan_send_setup(port, 1);
+	//mdelay(100);
 	keyspan_set_termios(port, NULL);
 
 	return (0);
 }
 
-static inline void stop_urb(urb_t *urb)
+static inline void stop_urb(struct urb *urb)
 {
 	if (urb && urb->status == -EINPROGRESS) {
 		urb->transfer_flags &= ~USB_ASYNC_UNLINK;
@@ -928,44 +927,37 @@
 	if (!serial)
 		return;
 
-	dbg("keyspan_close called\n");
+	dbg("%s", __FUNCTION__);
 	s_priv = (struct keyspan_serial_private *)(serial->private);
 	p_priv = (struct keyspan_port_private *)(port->private);
 	
 	p_priv->rts_state = 0;
 	p_priv->dtr_state = 0;
 	
-	if (serial->dev)
-		keyspan_send_setup(port, 1);
+	if (serial->dev) {
+		keyspan_send_setup(port, 2);
+		/* pilot-xfer seems to work best with this delay */
+		mdelay(100);
+		keyspan_set_termios(port, NULL);
+	}
 
 	/*while (p_priv->outcont_urb->status == -EINPROGRESS) {
-		dbg("close - urb in progress\n");
+		dbg("%s - urb in progress", __FUNCTION__);
 	}*/
 
 	p_priv->out_flip = 0;
 	p_priv->in_flip = 0;
 
-	down (&port->sem);
-
-	if (--port->open_count <= 0) {
-		if (port->active) {
-			if (serial->dev) {
-				/* Stop reading/writing urbs */
-				stop_urb(p_priv->inack_urb);
-				stop_urb(p_priv->outcont_urb);
-				for (i = 0; i < 2; i++) {
-					stop_urb(p_priv->in_urbs[i]);
-					stop_urb(p_priv->out_urbs[i]);
-				}
-			}
+	if (serial->dev) {
+		/* Stop reading/writing urbs */
+		stop_urb(p_priv->inack_urb);
+		/* stop_urb(p_priv->outcont_urb); */
+		for (i = 0; i < 2; i++) {
+			stop_urb(p_priv->in_urbs[i]);
+			stop_urb(p_priv->out_urbs[i]);
 		}
-		port->active = 0;
-		port->open_count = 0;
-		port->tty = 0;
 	}
-	up (&port->sem);
-
-	MOD_DEC_USE_COUNT;
+	port->tty = 0;
 }
 
 
@@ -976,12 +968,12 @@
 	const struct ezusb_hex_record 	*record;
 	char				*fw_name;
 
-	dbg("Keyspan startup version %04x product %04x\n",
+	dbg("Keyspan startup version %04x product %04x",
 	    serial->dev->descriptor.bcdDevice,
 	    serial->dev->descriptor.idProduct); 
 	
 	if ((serial->dev->descriptor.bcdDevice & 0x8000) != 0x8000) {
-		dbg("Firmware already loaded.  Quitting.\n");
+		dbg("Firmware already loaded.  Quitting.");
 		return(1);
 	}
 
@@ -1012,6 +1004,16 @@
 		fw_name = "USA19";
 		break;
 			     
+	case keyspan_usa19qi_pre_product_id:
+		record = &keyspan_usa19qi_firmware[0];
+		fw_name = "USA19QI";
+		break;
+			     
+	case keyspan_usa19qw_pre_product_id:
+		record = &keyspan_usa19qw_firmware[0];
+		fw_name = "USA19QI";
+		break;
+			     
 	case keyspan_usa18x_pre_product_id:
 		record = &keyspan_usa18x_firmware[0];
 		fw_name = "USA18X";
@@ -1038,7 +1040,7 @@
 		return(1);
 	}
 
-	dbg("Uploading Keyspan %s firmware.\n", fw_name);
+	dbg("Uploading Keyspan %s firmware.", fw_name);
 
 		/* download the firmware image */
 	response = ezusb_set_reset(serial, 1);
@@ -1065,19 +1067,19 @@
 }
 
 /* Helper functions used by keyspan_setup_urbs */
-static urb_t *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
-				int dir, void *ctx, char *buf, int len,
-				void (*callback)(urb_t *))
+static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
+				      int dir, void *ctx, char *buf, int len,
+				      void (*callback)(struct urb *))
 {
-	urb_t *urb;
+	struct urb *urb;
 
 	if (endpoint == -1)
 		return NULL;		/* endpoint not needed */
 
-	dbg (__FUNCTION__ " alloc for endpoint %d.\n", endpoint);
+	dbg ("%s - alloc for endpoint %d.", __FUNCTION__, endpoint);
 	urb = usb_alloc_urb(0);		/* No ISO */
 	if (urb == NULL) {
-		dbg (__FUNCTION__ " alloc for endpoint %d failed.\n", endpoint);
+		dbg ("%s - alloc for endpoint %d failed.", __FUNCTION__, endpoint);
 		return NULL;
 	}
 
@@ -1090,37 +1092,37 @@
 }
 
 static struct callbacks {
-	void	(*instat_callback)(urb_t *);
-	void	(*glocont_callback)(urb_t *);
-	void	(*indat_callback)(urb_t *);
-	void	(*outdat_callback)(urb_t *);
-	void	(*inack_callback)(urb_t *);
-	void	(*outcont_callback)(urb_t *);
+	void	(*instat_callback)(struct urb *);
+	void	(*glocont_callback)(struct urb *);
+	void	(*indat_callback)(struct urb *);
+	void	(*outdat_callback)(struct urb *);
+	void	(*inack_callback)(struct urb *);
+	void	(*outcont_callback)(struct urb *);
 } keyspan_callbacks[] = {
 	{
 		/* msg_usa26 callbacks */
-		instat_callback: usa26_instat_callback,
-		glocont_callback: usa26_glocont_callback,
-		indat_callback: usa26_indat_callback,
-		outdat_callback: usa2x_outdat_callback,
-		inack_callback: usa26_inack_callback,
-		outcont_callback: usa26_outcont_callback,
+		.instat_callback =	usa26_instat_callback,
+		.glocont_callback =	usa26_glocont_callback,
+		.indat_callback =	usa26_indat_callback,
+		.outdat_callback =	usa2x_outdat_callback,
+		.inack_callback =	usa26_inack_callback,
+		.outcont_callback =	usa26_outcont_callback,
 	}, {
 		/* msg_usa28 callbacks */
-		instat_callback: usa28_instat_callback,
-		glocont_callback: usa28_glocont_callback,
-		indat_callback: usa28_indat_callback,
-		outdat_callback: usa2x_outdat_callback,
-		inack_callback: usa28_inack_callback,
-		outcont_callback: usa28_outcont_callback,
+		.instat_callback =	usa28_instat_callback,
+		.glocont_callback =	usa28_glocont_callback,
+		.indat_callback =	usa28_indat_callback,
+		.outdat_callback =	usa2x_outdat_callback,
+		.inack_callback =	usa28_inack_callback,
+		.outcont_callback =	usa28_outcont_callback,
 	}, {
 		/* msg_usa49 callbacks */
-		instat_callback: usa49_instat_callback,
-		glocont_callback: usa49_glocont_callback,
-		indat_callback: usa49_indat_callback,
-		outdat_callback: usa2x_outdat_callback,
-		inack_callback: usa49_inack_callback,
-		outcont_callback: usa49_outcont_callback,
+		.instat_callback =	usa49_instat_callback,
+		.glocont_callback =	usa49_glocont_callback,
+		.indat_callback =	usa49_indat_callback,
+		.outdat_callback =	usa2x_outdat_callback,
+		.inack_callback =	usa49_inack_callback,
+		.outcont_callback =	usa49_outcont_callback,
 	}
 };
 
@@ -1130,13 +1132,13 @@
 {
 	int				i, j;
 	struct keyspan_serial_private 	*s_priv;
-	const keyspan_device_details	*d_details;
+	const struct keyspan_device_details	*d_details;
 	struct usb_serial_port		*port;
 	struct keyspan_port_private	*p_priv;
 	struct callbacks		*cback;
 	int				endp;
 
-	dbg ("%s\n", __FUNCTION__);
+	dbg ("%s", __FUNCTION__);
 
 	s_priv = (struct keyspan_serial_private *)(serial->private);
 	d_details = s_priv->device_details;
@@ -1198,13 +1200,14 @@
 }
 
 /* usa19 function doesn't require prescaler */
-static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk,
-				   u8 *rate_hi, u8 *rate_low, u8 *prescaler)
+static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
+				   u8 *rate_low, u8 *prescaler, int portnum)
 {
 	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
 		div,	/* divisor */	
 		cnt;	/* inverse of divisor (programmed into 8051) */
 		
+	dbg ("%s - %d.", __FUNCTION__, baud_rate);
 
 		/* prevent divide by zero...  */
 	if( (b16 = (baud_rate * 16L)) == 0) {
@@ -1237,14 +1240,14 @@
 		*rate_hi = (u8) ((cnt >> 8) & 0xff);
 	}
 	if (rate_low && rate_hi) {
-		dbg (__FUNCTION__ " %d %02x %02x.", baud_rate, *rate_hi, *rate_low);
+		dbg ("%s - %d %02x %02x.", __FUNCTION__, baud_rate, *rate_hi, *rate_low);
 	}
 	
 	return (KEYSPAN_BAUD_RATE_OK);
 }
 
-static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk,
-				    u8 *rate_hi, u8 *rate_low, u8 *prescaler)
+static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
+				    u8 *rate_low, u8 *prescaler, int portnum)
 {
 	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
 		clk,	/* clock with 13/8 prescaler */
@@ -1255,7 +1258,7 @@
 	u8	best_prescaler;
 	int	i;
 
-	dbg (__FUNCTION__ " %d.\n", baud_rate);
+	dbg ("%s - %d.", __FUNCTION__, baud_rate);
 
 		/* prevent divide by zero */
 	if( (b16 = baud_rate * 16L) == 0) {
@@ -1271,8 +1274,7 @@
 		/* 0 is an invalid prescaler, used as a flag */
 	best_prescaler = 0;
 
-	for(i = 8; i <= 0xff; ++i)
-	{
+	for(i = 8; i <= 0xff; ++i) {
 		clk = (baudclk * 8) / (u32) i;
 		
 		if( (div = clk / b16) == 0) {
@@ -1282,8 +1284,7 @@
 		res = clk / div;
 		diff= (res > b16) ? (res-b16) : (b16-res);
 
-		if(diff < smallest_diff)
-		{
+		if(diff < smallest_diff) {
 			best_prescaler = i;
 			smallest_diff = diff;
 		}
@@ -1305,8 +1306,59 @@
 	}
 	if (prescaler) {
 		*prescaler = best_prescaler;
-		/*  dbg(__FUNCTION__ " %d %d", *prescaler, div); */
+		/*  dbg("%s - %d %d", __FUNCTION__, *prescaler, div); */
+	}
+	return (KEYSPAN_BAUD_RATE_OK);
+}
+
+	/* USA-28 supports different maximum baud rates on each port */
+static int keyspan_usa28_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
+				    u8 *rate_low, u8 *prescaler, int portnum)
+{
+	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
+		div,	/* divisor */	
+		cnt;	/* inverse of divisor (programmed into 8051) */
+
+	dbg ("%s - %d.", __FUNCTION__, baud_rate);
+
+		/* prevent divide by zero */
+	if ((b16 = baud_rate * 16L) == 0)
+		return (KEYSPAN_INVALID_BAUD_RATE);
+
+		/* calculate the divisor and the counter (its inverse) */
+	if ((div = (KEYSPAN_USA28_BAUDCLK / b16)) == 0) {
+		return (KEYSPAN_INVALID_BAUD_RATE);
+	}
+	else {
+		cnt = 0 - div;
+	}
+
+		/* check for out of range, based on portnum, 
+		   and return result */
+	if(portnum == 0) {
+		if(div > 0xffff)
+			return (KEYSPAN_INVALID_BAUD_RATE);
+	}
+	else {
+		if(portnum == 1) {
+			if(div > 0xff) {
+				return (KEYSPAN_INVALID_BAUD_RATE);
+			}
+		}
+		else {
+			return (KEYSPAN_INVALID_BAUD_RATE);
+		}
+	}
+
+		/* return the counter values if not NULL
+		   (port 1 will ignore retHi) */
+	if (rate_low) {
+		*rate_low = (u8) (cnt & 0xff);
+	}
+	if (rate_hi) {
+		*rate_hi = (u8) ((cnt >> 8) & 0xff);
 	}
+	dbg ("%s - %d OK.", __FUNCTION__, baud_rate);
 	return (KEYSPAN_BAUD_RATE_OK);
 }
 
@@ -1317,31 +1369,35 @@
 	struct keyspan_usa26_portControlMessage	msg;		
 	struct keyspan_serial_private 		*s_priv;
 	struct keyspan_port_private 		*p_priv;
-	const  keyspan_device_details		*d_details;
+	const struct keyspan_device_details	*d_details;
 	int 					outcont_urb;
-	urb_t *this_urb;
-	int err;
+	struct urb				*this_urb;
+	int 					device_port, err;
 
-	dbg ("%s reset=%d\n", __FUNCTION__, reset_port); 
+	dbg ("%s reset=%d", __FUNCTION__, reset_port); 
 
 	s_priv = (struct keyspan_serial_private *)(serial->private);
 	p_priv = (struct keyspan_port_private *)(port->private);
 	d_details = s_priv->device_details;
+	device_port = port->number - port->serial->minor;
 
 	outcont_urb = d_details->outcont_endpoints[port->number];
 	this_urb = p_priv->outcont_urb;
 
-	dbg(__FUNCTION__ " endpoint %d\n", usb_pipeendpoint(this_urb->pipe));
+	dbg("%s - endpoint %d", __FUNCTION__, usb_pipeendpoint(this_urb->pipe));
 
 		/* Make sure we have an urb then send the message */
 	if (this_urb == NULL) {
-		dbg(__FUNCTION__ " oops no urb.\n");
+		dbg("%s - oops no urb.", __FUNCTION__);
 		return -1;
 	}
 
-	p_priv->resend_cont = 1;
+	/* Save reset port val for resend.
+	Don't overwrite resend for close condition. */
+	if (p_priv->resend_cont != 3)
+		p_priv->resend_cont = reset_port + 1;
 	if (this_urb->status == -EINPROGRESS) {
-		/*  dbg (__FUNCTION__ " already writing"); */
+		/*  dbg ("%s - already writing", __FUNCTION__); */
 		return(-1);
 	}
 
@@ -1353,8 +1409,8 @@
 		msg.setClocking = 0xff;
 		if (d_details->calculate_baud_rate
 		    (p_priv->baud, d_details->baudclk, &msg.baudHi,
-		     &msg.baudLo, &msg.prescaler) == KEYSPAN_INVALID_BAUD_RATE ) {
-			dbg(__FUNCTION__ "Invalid baud rate %d requested, using 9600.\n",
+		     &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE ) {
+			dbg("%s - Invalid baud rate %d requested, using 9600.", __FUNCTION__,
 			    p_priv->baud);
 			msg.baudLo = 0;
 			msg.baudHi = 125;	/* Values for 9600 baud */
@@ -1388,12 +1444,26 @@
 	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
 	msg.xonFlowControl = 0;
 	msg.setFlowControl = 0xff;
-	
-	msg.forwardingLength = 1;
+	msg.forwardingLength = 16;
 	msg.xonChar = 17;
 	msg.xoffChar = 19;
 
-	if (reset_port) {
+	/* Opening port */
+	if (reset_port == 1) {
+		msg._txOn = 1;
+		msg._txOff = 0;
+		msg.txFlush = 0;
+		msg.txBreak = 0;
+		msg.rxOn = 1;
+		msg.rxOff = 0;
+		msg.rxFlush = 1;
+		msg.rxForward = 0;
+		msg.returnStatus = 0;
+		msg.resetDataToggle = 0xff;
+	}
+
+	/* Closing port */
+	else if (reset_port == 2) {
 		msg._txOn = 0;
 		msg._txOff = 1;
 		msg.txFlush = 0;
@@ -1403,14 +1473,16 @@
 		msg.rxFlush = 1;
 		msg.rxForward = 0;
 		msg.returnStatus = 0;
-		msg.resetDataToggle = 0xff;
+		msg.resetDataToggle = 0;
 	}
+
+	/* Sending intermediate configs */
 	else {
 		msg._txOn = (! p_priv->break_on);
 		msg._txOff = 0;
 		msg.txFlush = 0;
 		msg.txBreak = (p_priv->break_on);
-		msg.rxOn = 1;
+		msg.rxOn = 0;
 		msg.rxOff = 0;
 		msg.rxFlush = 0;
 		msg.rxForward = 0;
@@ -1433,11 +1505,11 @@
 
 	this_urb->dev = serial->dev;
 	if ((err = usb_submit_urb(this_urb)) != 0) {
-		dbg(__FUNCTION__ " usb_submit_urb(setup) failed (%d)\n", err);
+		dbg("%s - usb_submit_urb(setup) failed (%d)", __FUNCTION__, err);
 	}
 #if 0
 	else {
-		dbg(__FUNCTION__ " usb_submit_urb(%d) OK %d bytes (end %d)",
+		dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __FUNCTION__
 		    outcont_urb, this_urb->transfer_buffer_length,
 		    usb_pipeendpoint(this_urb->pipe));
 	}
@@ -1453,32 +1525,38 @@
 	struct keyspan_usa28_portControlMessage	msg;		
 	struct keyspan_serial_private	 	*s_priv;
 	struct keyspan_port_private 		*p_priv;
-	const  keyspan_device_details		*d_details;
-	urb_t *this_urb;
-	int err;
+	const struct keyspan_device_details	*d_details;
+	struct urb				*this_urb;
+	int 					device_port, err;
+
+	dbg ("%s", __FUNCTION__);
 
 	s_priv = (struct keyspan_serial_private *)(serial->private);
 	p_priv = (struct keyspan_port_private *)(port->private);
 	d_details = s_priv->device_details;
+	device_port = port->number - port->serial->minor;
 
 	/* only do something if we have a bulk out endpoint */
 	if ((this_urb = p_priv->outcont_urb) == NULL) {
-		dbg(__FUNCTION__ " oops no urb.\n");
+		dbg("%s - oops no urb.", __FUNCTION__);
 		return -1;
 	}
 
-	p_priv->resend_cont = 1;
+	/* Save reset port val for resend.
+	   Don't overwrite resend for close condition. */
+	if (p_priv->resend_cont != 3)
+		p_priv->resend_cont = reset_port + 1;
 	if (this_urb->status == -EINPROGRESS) {
-		dbg (__FUNCTION__ " already writing\n");
+		dbg ("%s already writing", __FUNCTION__);
 		return(-1);
 	}
 
 	memset(&msg, 0, sizeof (struct keyspan_usa28_portControlMessage));
 
 	msg.setBaudRate = 1;
-	if (keyspan_usa19_calc_baud(p_priv->baud, d_details->baudclk,
-		&msg.baudHi, &msg.baudLo, NULL) == KEYSPAN_INVALID_BAUD_RATE ) {
-		dbg(__FUNCTION__ "Invalid baud rate requested %d.", p_priv->baud);
+	if (d_details->calculate_baud_rate(p_priv->baud, d_details->baudclk,
+		&msg.baudHi, &msg.baudLo, NULL, device_port) == KEYSPAN_INVALID_BAUD_RATE ) {
+		dbg("%s - Invalid baud rate requested %d.", __FUNCTION__, p_priv->baud);
 		msg.baudLo = 0xff;
 		msg.baudHi = 0xb2;	/* Values for 9600 baud */
 	}
@@ -1493,23 +1571,56 @@
 	msg.rts = p_priv->rts_state;
 	msg.dtr = p_priv->dtr_state;
 
-	msg.forwardingLength = 1;
+	msg.forwardingLength = 16;
 	msg.forwardMs = 10;
 	msg.breakThreshold = 45;
 	msg.xonChar = 17;
 	msg.xoffChar = 19;
 
-	msg._txOn = 1;
-	msg._txOff = 0;
-	msg.txFlush = 0;
-	msg.txForceXoff = 0;
-	msg.txBreak = 0;
-	msg.rxOn = 1;
-	msg.rxOff = 0;
-	msg.rxFlush = 0;
-	msg.rxForward = 0;
 	/*msg.returnStatus = 1;
 	msg.resetDataToggle = 0xff;*/
+	/* Opening port */
+	if (reset_port == 1) {
+		msg._txOn = 1;
+		msg._txOff = 0;
+		msg.txFlush = 0;
+		msg.txForceXoff = 0;
+		msg.txBreak = 0;
+		msg.rxOn = 1;
+		msg.rxOff = 0;
+		msg.rxFlush = 1;
+		msg.rxForward = 0;
+		msg.returnStatus = 0;
+		msg.resetDataToggle = 0xff;
+	}
+	/* Closing port */
+	else if (reset_port == 2) {
+		msg._txOn = 0;
+		msg._txOff = 1;
+		msg.txFlush = 0;
+		msg.txForceXoff = 0;
+		msg.txBreak = 0;
+		msg.rxOn = 0;
+		msg.rxOff = 1;
+		msg.rxFlush = 1;
+		msg.rxForward = 0;
+		msg.returnStatus = 0;
+		msg.resetDataToggle = 0;
+	}
+	/* Sending intermediate configs */
+	else {
+		msg._txOn = (! p_priv->break_on);
+		msg._txOff = 0;
+		msg.txFlush = 0;
+		msg.txForceXoff = 0;
+		msg.txBreak = (p_priv->break_on);
+		msg.rxOn = 0;
+		msg.rxOff = 0;
+		msg.rxFlush = 0;
+		msg.rxForward = 0;
+		msg.returnStatus = 0;
+		msg.resetDataToggle = 0x0;
+	}
 
 	p_priv->resend_cont = 0;
 	memcpy (this_urb->transfer_buffer, &msg, sizeof(msg));
@@ -1519,11 +1630,11 @@
 
 	this_urb->dev = serial->dev;
 	if ((err = usb_submit_urb(this_urb)) != 0) {
-		dbg(__FUNCTION__ " usb_submit_urb(setup) failed\n");
+		dbg("%s - usb_submit_urb(setup) failed", __FUNCTION__);
 	}
 #if 0
 	else {
-		dbg(__FUNCTION__ " usb_submit_urb(setup) OK %d bytes",
+		dbg("%s - usb_submit_urb(setup) OK %d bytes", __FUNCTION__,
 		    this_urb->transfer_buffer_length);
 	}
 #endif
@@ -1538,13 +1649,12 @@
 	struct keyspan_usa49_portControlMessage	msg;		
 	struct keyspan_serial_private 		*s_priv;
 	struct keyspan_port_private 		*p_priv;
-	const  keyspan_device_details		*d_details;
+	const struct keyspan_device_details	*d_details;
 	int 					glocont_urb;
-	urb_t 					*this_urb;
-	int 					err;
-	int					device_port;
+	struct urb				*this_urb;
+	int 					err, device_port;
 
-	dbg ("%s\n", __FUNCTION__);
+	dbg ("%s", __FUNCTION__);
 
 	s_priv = (struct keyspan_serial_private *)(serial->private);
 	p_priv = (struct keyspan_port_private *)(port->private);
@@ -1556,17 +1666,20 @@
 		/* Work out which port within the device is being setup */
 	device_port = port->number - port->serial->minor;
 
-	dbg(__FUNCTION__ " endpoint %d port %d (%d)\n", usb_pipeendpoint(this_urb->pipe), port->number, device_port);
+	dbg("%s - endpoint %d port %d (%d)",__FUNCTION__, usb_pipeendpoint(this_urb->pipe), port->number, device_port);
 
 		/* Make sure we have an urb then send the message */
 	if (this_urb == NULL) {
-		dbg(__FUNCTION__ " oops no urb for port %d.\n", port->number);
+		dbg("%s - oops no urb for port %d.", __FUNCTION__, port->number);
 		return -1;
 	}
 
-	p_priv->resend_cont = 1;
+	/* Save reset port val for resend.
+	   Don't overwrite resend for close condition. */
+	if (p_priv->resend_cont != 3)
+		p_priv->resend_cont = reset_port + 1;
 	if (this_urb->status == -EINPROGRESS) {
-		/*  dbg (__FUNCTION__ " already writing"); */
+		/*  dbg ("%s - already writing", __FUNCTION__); */
 		return(-1);
 	}
 
@@ -1581,8 +1694,8 @@
 		msg.setClocking = 0xff;
 		if (d_details->calculate_baud_rate
 		    (p_priv->baud, d_details->baudclk, &msg.baudHi,
-		     &msg.baudLo, &msg.prescaler) == KEYSPAN_INVALID_BAUD_RATE ) {
-			dbg(__FUNCTION__ "Invalid baud rate %d requested, using 9600.\n",
+		     &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE ) {
+			dbg("%s - Invalid baud rate %d requested, using 9600.", __FUNCTION__,
 			    p_priv->baud);
 			msg.baudLo = 0;
 			msg.baudHi = 125;	/* Values for 9600 baud */
@@ -1617,20 +1730,55 @@
 	msg.xonFlowControl = 0;
 	msg.setFlowControl = 0xff;
 	
-	msg.forwardingLength = 1;
+	msg.forwardingLength = 16;
 	msg.xonChar = 17;
 	msg.xoffChar = 19;
-	
-	msg._txOn = 1;
-	msg._txOff = 0;
-	msg.txFlush = 0;
-	msg.txBreak = 0;
-	msg.rxOn = 1;
-	msg.rxOff = 0;
-	msg.rxFlush = 0;
-	msg.rxForward = 0;
-	msg.enablePort = 0xff;
-	msg.disablePort = 0;
+
+	/* Opening port */ 
+	if (reset_port == 1) {
+		msg._txOn = 1;
+		msg._txOff = 0;
+		msg.txFlush = 0;
+		msg.txBreak = 0;
+		msg.rxOn = 1;
+		msg.rxOff = 0;
+		msg.rxFlush = 1;
+		msg.rxForward = 0;
+		msg.returnStatus = 0;
+		msg.resetDataToggle = 0xff;
+		msg.enablePort = 1;
+		msg.disablePort = 0;
+	}
+	/* Closing port */
+	else if (reset_port == 2) {
+		msg._txOn = 0;
+		msg._txOff = 1;
+		msg.txFlush = 0;
+		msg.txBreak = 0;
+		msg.rxOn = 0;
+		msg.rxOff = 1;
+		msg.rxFlush = 1;
+		msg.rxForward = 0;
+		msg.returnStatus = 0;
+		msg.resetDataToggle = 0;
+		msg.enablePort = 0;
+		msg.disablePort = 1;
+	}
+	/* Sending intermediate configs */
+	else {
+		msg._txOn = (! p_priv->break_on);
+		msg._txOff = 0;
+		msg.txFlush = 0;
+		msg.txBreak = (p_priv->break_on);
+		msg.rxOn = 0;
+		msg.rxOff = 0;
+		msg.rxFlush = 0;
+		msg.rxForward = 0;
+		msg.returnStatus = 0;
+		msg.resetDataToggle = 0x0;
+		msg.enablePort = 0;
+		msg.disablePort = 0;
+	}
 
 		/* Do handshaking outputs */	
 	msg.setRts = 0xff;
@@ -1647,11 +1795,11 @@
 
 	this_urb->dev = serial->dev;
 	if ((err = usb_submit_urb(this_urb)) != 0) {
-		dbg(__FUNCTION__ " usb_submit_urb(setup) failed (%d)\n", err);
+		dbg("%s - usb_submit_urb(setup) failed (%d)", __FUNCTION__, err);
 	}
 #if 0
 	else {
-		dbg(__FUNCTION__ " usb_submit_urb(%d) OK %d bytes (end %d)",
+		dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __FUNCTION__,
 		    outcont_urb, this_urb->transfer_buffer_length,
 		    usb_pipeendpoint(this_urb->pipe));
 	}
@@ -1663,8 +1811,10 @@
 static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
 {
 	struct usb_serial *serial = port->serial;
-	struct keyspan_serial_private 	*s_priv;
-	const keyspan_device_details	*d_details;
+	struct keyspan_serial_private *s_priv;
+	const struct keyspan_device_details *d_details;
+
+	dbg ("%s", __FUNCTION__);
 
 	s_priv = (struct keyspan_serial_private *)(serial->private);
 	d_details = s_priv->device_details;
@@ -1690,16 +1840,15 @@
 	struct usb_serial_port		*port;
 	struct keyspan_serial_private 	*s_priv;
 	struct keyspan_port_private	*p_priv;
-	const keyspan_device_details	*d_details;
+	const struct keyspan_device_details	*d_details;
 
-	dbg("keyspan_startup called.\n");
+	dbg("%s", __FUNCTION__);
 
 	for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
 		if (d_details->product_id == serial->dev->descriptor.idProduct)
 			break;
 	if (d_details == NULL) {
-		printk(KERN_ERR __FUNCTION__ ": unknown product id %x\n",
-		       serial->dev->descriptor.idProduct);
+		err("%s - unknown product id %x", __FUNCTION__, serial->dev->descriptor.idProduct);
 		return 1;
 	}
 
@@ -1707,7 +1856,7 @@
 	serial->private = kmalloc(sizeof(struct keyspan_serial_private),
 				  GFP_KERNEL);
 	if (!serial->private) {
-		dbg(__FUNCTION__ "kmalloc for keyspan_serial_private failed.\n");
+		dbg("%s - kmalloc for keyspan_serial_private failed.", __FUNCTION__);
 		return (1);
 	}
 	memset(serial->private, 0, sizeof(struct keyspan_serial_private));
@@ -1721,7 +1870,7 @@
 		port->private = kmalloc(sizeof(struct keyspan_port_private),
 					GFP_KERNEL);
 		if (!port->private) {
-			dbg(__FUNCTION__ "kmalloc for keyspan_port_private (%d) failed!.\n", i);
+			dbg("%s - kmalloc for keyspan_port_private (%d) failed!.", __FUNCTION__, i);
 			return (1);
 		}
 		memset(port->private, 0, sizeof(struct keyspan_port_private));
@@ -1733,7 +1882,7 @@
 
 	s_priv->instat_urb->dev = serial->dev;
 	if ((err = usb_submit_urb(s_priv->instat_urb)) != 0) {
-		dbg(__FUNCTION__ " submit instat urb failed %d\n", err);
+		dbg("%s - submit instat urb failed %d", __FUNCTION__, err);
 	}
 			
 	return (0);
@@ -1746,7 +1895,7 @@
 	struct keyspan_serial_private 	*s_priv;
 	struct keyspan_port_private	*p_priv;
 
-	dbg("keyspan_shutdown called\n");
+	dbg("%s", __FUNCTION__);
 
 	s_priv = (struct keyspan_serial_private *)(serial->private);
 
@@ -1791,10 +1940,6 @@
 	/* Now free per port private data */
 	for (i = 0; i < serial->num_ports; i++) {
 		port = &serial->port[i];
-		while (port->open_count > 0) {
-			--port->open_count;
-			MOD_DEC_USE_COUNT;
-		}
 		kfree(port->private);
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/keyspan.h linux-2.4.20/drivers/usb/serial/keyspan.h
--- linux-2.4.19/drivers/usb/serial/keyspan.h	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/keyspan.h	2002-10-29 11:18:49.000000000 +0000
@@ -2,7 +2,7 @@
   Keyspan USB to Serial Converter driver
  
   (C) Copyright (C) 2000-2001
-      Hugh Blemings <hugh@misc.nu>
+      Hugh Blemings <hugh@blemings.org>
    
   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
@@ -33,9 +33,8 @@
 #ifndef __LINUX_USB_SERIAL_KEYSPAN_H
 #define __LINUX_USB_SERIAL_KEYSPAN_H
 
-#include <linux/config.h>
 
-	/* Function prototypes for Keyspan serial converter */
+/* Function prototypes for Keyspan serial converter */
 static int  keyspan_open		(struct usb_serial_port *port,
 					 struct file *filp);
 static void keyspan_close		(struct usb_serial_port *port,
@@ -54,12 +53,7 @@
 static void keyspan_send_setup		(struct usb_serial_port *port,
 					 int reset_port);
 
-#if 0
-static void keyspan_write_bulk_callback (struct urb *urb);
-#endif
 
-//static void keyspan_usa26_read_int_callback  (struct urb *urb);
-//static void keyspan_usa28_read_int_callback  (struct urb *urb);
 static int  keyspan_chars_in_buffer 	(struct usb_serial_port *port);
 static int  keyspan_ioctl		(struct usb_serial_port *port,
 					 struct file *file,
@@ -72,12 +66,16 @@
 static int  keyspan_fake_startup	(struct usb_serial *serial);
 
 static int  keyspan_usa19_calc_baud	(u32 baud_rate, u32 baudclk, 
-					 u8 *rate_hi, u8 *rate_low, u8 *prescaler);
+					 u8 *rate_hi, u8 *rate_low,
+					 u8 *prescaler, int portnum);
 
 static int  keyspan_usa19w_calc_baud	(u32 baud_rate, u32 baudclk,
-					 u8 *rate_hi, u8 *rate_low, u8 *prescaler);
+					 u8 *rate_hi, u8 *rate_low,
+					 u8 *prescaler, int portnum);
 
-//static void keyspan_usa19_setup_urbs	(struct usb_serial *serial);
+static int  keyspan_usa28_calc_baud	(u32 baud_rate, u32 baudclk,
+					 u8 *rate_hi, u8 *rate_low,
+					 u8 *prescaler, int portnum);
 
 static int  keyspan_usa28_send_setup	(struct usb_serial *serial,
 					 struct usb_serial_port *port,
@@ -89,91 +87,102 @@
 					 struct usb_serial_port *port,
 					 int reset_port);
 
-	/* Functions from usbserial.c for ezusb firmware handling */
-extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
-extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest);
 
-	/* Struct used for firmware - increased size of data section
-	   to allow Keyspan's 'C' firmware struct to be used unmodified */
+/* Struct used for firmware - increased size of data section
+   to allow Keyspan's 'C' firmware struct to be used unmodified */
 struct ezusb_hex_record {
 	__u16 address;
 	__u8 data_size;
 	__u8 data[64];
 };
-	/* Conditionally include firmware images, if they aren't
-	   included create a null pointer instead.  Current 
-	   firmware images aren't optimised to remove duplicate
-	   addresses in the image itself. */
+
+/* Conditionally include firmware images, if they aren't
+   included create a null pointer instead.  Current 
+   firmware images aren't optimised to remove duplicate
+   addresses in the image itself. */
 #ifdef CONFIG_USB_SERIAL_KEYSPAN_USA28
-        #include "keyspan_usa28_fw.h"
+	#include "keyspan_usa28_fw.h"
 #else
 	static const struct ezusb_hex_record *keyspan_usa28_firmware = NULL;
 #endif
 
 #ifdef CONFIG_USB_SERIAL_KEYSPAN_USA28X
-        #include "keyspan_usa28x_fw.h"
+	#include "keyspan_usa28x_fw.h"
 #else
 	static const struct ezusb_hex_record *keyspan_usa28x_firmware = NULL;
 #endif
 
 #ifdef CONFIG_USB_SERIAL_KEYSPAN_USA28XA
-        #include "keyspan_usa28xa_fw.h"
+	#include "keyspan_usa28xa_fw.h"
 #else
 	static const struct ezusb_hex_record *keyspan_usa28xa_firmware = NULL;
 #endif
 
 #ifdef CONFIG_USB_SERIAL_KEYSPAN_USA28XB
-        #include "keyspan_usa28xb_fw.h"
+	#include "keyspan_usa28xb_fw.h"
 #else
 	static const struct ezusb_hex_record *keyspan_usa28xb_firmware = NULL;
 #endif
 
 #ifdef CONFIG_USB_SERIAL_KEYSPAN_USA19
-        #include "keyspan_usa19_fw.h"
+	#include "keyspan_usa19_fw.h"
 #else
 	static const struct ezusb_hex_record *keyspan_usa19_firmware = NULL;
 #endif
 
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA19QI
+	#include "keyspan_usa19qi_fw.h"
+#else
+	static const struct ezusb_hex_record *keyspan_usa19qi_firmware = NULL;
+#endif
+
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA19QW
+	#include "keyspan_usa19qw_fw.h"
+#else
+	static const struct ezusb_hex_record *keyspan_usa19qw_firmware = NULL;
+#endif
+
 #ifdef CONFIG_USB_SERIAL_KEYSPAN_USA18X
-        #include "keyspan_usa18x_fw.h"
+	#include "keyspan_usa18x_fw.h"
 #else
 	static const struct ezusb_hex_record *keyspan_usa18x_firmware = NULL;
 #endif
 
 #ifdef CONFIG_USB_SERIAL_KEYSPAN_USA19W
-        #include "keyspan_usa19w_fw.h"
+	#include "keyspan_usa19w_fw.h"
 #else
 	static const struct ezusb_hex_record *keyspan_usa19w_firmware = NULL;
 #endif
 
 #ifdef CONFIG_USB_SERIAL_KEYSPAN_USA49W
-        #include "keyspan_usa49w_fw.h"
+	#include "keyspan_usa49w_fw.h"
 #else
 	static const struct ezusb_hex_record *keyspan_usa49w_firmware = NULL;
 #endif
-	
-	/* Values used for baud rate calculation - device specific */
+
+/* Values used for baud rate calculation - device specific */
 #define	KEYSPAN_INVALID_BAUD_RATE		(-1)
 #define	KEYSPAN_BAUD_RATE_OK			(0)
 #define	KEYSPAN_USA18X_BAUDCLK			(12000000L)	/* a guess */
 #define	KEYSPAN_USA19_BAUDCLK			(12000000L)
 #define	KEYSPAN_USA19W_BAUDCLK			(24000000L)
+#define	KEYSPAN_USA28_BAUDCLK			(1843200L)
 #define	KEYSPAN_USA28X_BAUDCLK			(12000000L)
 #define	KEYSPAN_USA49W_BAUDCLK			(48000000L)
 
-	/* Some constants used to characterise each device. 
-	   There is a four port device due later in the year,
-	   we allow for it now in the following */
+/* Some constants used to characterise each device.  */
 #define		KEYSPAN_MAX_NUM_PORTS		(4)
 #define		KEYSPAN_MAX_FLIPS		(2)
-	
-	/* Device info for the Keyspan serial converter, used
-	   by the overall usb-serial probe function */
+
+/* Device info for the Keyspan serial converter, used
+   by the overall usb-serial probe function */
 #define KEYSPAN_VENDOR_ID			(0x06cd)
 
-	/* Product IDs for the eight products supported, pre-renumeration */
+/* Product IDs for the products supported, pre-renumeration */
 #define	keyspan_usa18x_pre_product_id		0x0105
 #define	keyspan_usa19_pre_product_id		0x0103
+#define	keyspan_usa19qi_pre_product_id		0x010b
+#define	keyspan_usa19qw_pre_product_id		0x0118
 #define	keyspan_usa19w_pre_product_id		0x0106
 #define	keyspan_usa28_pre_product_id		0x0101
 #define	keyspan_usa28x_pre_product_id		0x0102
@@ -181,11 +190,13 @@
 #define	keyspan_usa28xb_pre_product_id		0x0113
 #define	keyspan_usa49w_pre_product_id		0x0109
 
-	/* Product IDs post-renumeration.  Note that the 28x and 28xb
-	   have the same id's post-renumeration but behave identically
-	   so it's not an issue. */
+/* Product IDs post-renumeration.  Note that the 28x and 28xb
+   have the same id's post-renumeration but behave identically
+   so it's not an issue. */
 #define	keyspan_usa18x_product_id		0x0112
 #define	keyspan_usa19_product_id		0x0107
+#define	keyspan_usa19qi_product_id		0x010c
+#define	keyspan_usa19qw_product_id		0x0119
 #define	keyspan_usa19w_product_id		0x0108
 #define	keyspan_usa28_product_id		0x010f
 #define	keyspan_usa28x_product_id		0x0110
@@ -194,10 +205,10 @@
 #define	keyspan_usa49w_product_id		0x010a
 
 
-typedef struct {
+struct keyspan_device_details {
 	/* product ID value */
 	int	product_id;
-	
+
 	enum	{msg_usa26, msg_usa28, msg_usa49} msg_format;
 
 		/* Number of physical ports */
@@ -219,137 +230,190 @@
 		/* Input acknowledge endpoints */
 	int	inack_endpoints[KEYSPAN_MAX_NUM_PORTS];
 
-		/* Output control endpoints */	
+		/* Output control endpoints */
 	int	outcont_endpoints[KEYSPAN_MAX_NUM_PORTS];
 
 		/* Endpoint used for input status */
 	int	instat_endpoint;
 
 		/* Endpoint used for global control functions */
-	int	glocont_endpoint;	
-	
+	int	glocont_endpoint;
+
 	int	(*calculate_baud_rate) (u32 baud_rate, u32 baudclk,
-			u8 *rate_hi, u8 *rate_low, u8 *prescaler);
+			u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum);
 	u32	baudclk;
+}; 
+
+/* Now for each device type we setup the device detail
+   structure with the appropriate information (provided
+   in Keyspan's documentation) */
+
+static const struct keyspan_device_details usa18x_device_details = {
+	product_id:		keyspan_usa18x_product_id,
+	msg_format:		msg_usa26,
+	num_ports:		1,
+	indat_endp_flip:	0,
+	outdat_endp_flip:	1,
+	indat_endpoints:	{0x81},
+	outdat_endpoints:	{0x01},
+	inack_endpoints:	{0x85},
+	outcont_endpoints:	{0x05},
+	instat_endpoint:	0x87,
+	glocont_endpoint:	0x07,
+	calculate_baud_rate:	keyspan_usa19w_calc_baud,
+	baudclk:		KEYSPAN_USA18X_BAUDCLK,
+};
+
+static const struct keyspan_device_details usa19_device_details = {
+	product_id:		keyspan_usa19_product_id,
+	msg_format:		msg_usa28,
+	num_ports:		1,
+	indat_endp_flip:	1,
+	outdat_endp_flip:	1,
+	indat_endpoints:	{0x81},
+	outdat_endpoints:	{0x01},
+	inack_endpoints:	{0x83},
+	outcont_endpoints:	{0x03},
+	instat_endpoint:	0x84,
+	glocont_endpoint:	-1,
+	calculate_baud_rate:	keyspan_usa19_calc_baud,
+	baudclk:		KEYSPAN_USA19_BAUDCLK,
+};
+
+static const struct keyspan_device_details usa19qi_device_details = {
+	product_id:		keyspan_usa19qi_product_id,
+	msg_format:		msg_usa28,
+	num_ports:		1,
+	indat_endp_flip:	1,
+	outdat_endp_flip:	1,
+	indat_endpoints:	{0x81},
+	outdat_endpoints:	{0x01},
+	inack_endpoints:	{0x83},
+	outcont_endpoints:	{0x03},
+	instat_endpoint:	0x84,
+	glocont_endpoint:	-1,
+	calculate_baud_rate:	keyspan_usa28_calc_baud,
+	baudclk:		KEYSPAN_USA19_BAUDCLK,
+};
+
+static const struct keyspan_device_details usa19qw_device_details = {
+	product_id:		keyspan_usa19qw_product_id,
+	msg_format:		msg_usa26,
+	num_ports:		1,
+	indat_endp_flip:	0,
+	outdat_endp_flip:	1,
+	indat_endpoints:	{0x81},
+	outdat_endpoints:	{0x01},
+	inack_endpoints:	{0x85},
+	outcont_endpoints:	{0x05},
+	instat_endpoint:	0x87,
+	glocont_endpoint:	0x07,
+	calculate_baud_rate:	keyspan_usa19w_calc_baud,
+	baudclk:		KEYSPAN_USA19W_BAUDCLK,
+};
+
+static const struct keyspan_device_details usa19w_device_details = {
+	product_id:		keyspan_usa19w_product_id,
+	msg_format:		msg_usa26,
+	num_ports:		1,
+	indat_endp_flip:	0,
+	outdat_endp_flip:	1,
+	indat_endpoints:	{0x81},
+	outdat_endpoints:	{0x01},
+	inack_endpoints:	{0x85},
+	outcont_endpoints:	{0x05},
+	instat_endpoint:	0x87,
+	glocont_endpoint:	0x07,
+	calculate_baud_rate:	keyspan_usa19w_calc_baud,
+	baudclk:		KEYSPAN_USA19W_BAUDCLK,
+};
+
+static const struct keyspan_device_details usa28_device_details = {
+	product_id:		keyspan_usa28_product_id,
+	msg_format:		msg_usa28,
+	num_ports:		2,
+	indat_endp_flip:	1,
+	outdat_endp_flip:	1,
+	indat_endpoints:	{0x81, 0x83},
+	outdat_endpoints:	{0x01, 0x03},
+	inack_endpoints:	{0x85, 0x86},
+	outcont_endpoints:	{0x05, 0x06},
+	instat_endpoint:	0x87,
+	glocont_endpoint:	0x07,
+	calculate_baud_rate:	keyspan_usa28_calc_baud,
+	baudclk:		KEYSPAN_USA28_BAUDCLK,		
+};
 
-} keyspan_device_details; 
+static const struct keyspan_device_details usa28x_device_details = {
+	product_id:		keyspan_usa28x_product_id,
+	msg_format:		msg_usa26,
+	num_ports:		2,
+	indat_endp_flip:	0,
+	outdat_endp_flip:	1,
+	indat_endpoints:	{0x81, 0x83},
+	outdat_endpoints:	{0x01, 0x03},
+	inack_endpoints:	{0x85, 0x86},
+	outcont_endpoints:	{0x05, 0x06},
+	instat_endpoint:	0x87,
+	glocont_endpoint:	0x07,
+	calculate_baud_rate:	keyspan_usa19w_calc_baud,
+	baudclk:		KEYSPAN_USA28X_BAUDCLK,
+};
 
-	/* Now for each device type we setup the device detail
-	   structure with the appropriate information (provided
-	   in Keyspan's documentation) */
-
-static const keyspan_device_details usa18x_device_details = {
-	keyspan_usa18x_product_id,	/* product ID */
-       	msg_usa26, 			/* msg type*/
-	1,				/* num ports */
-	0,				/* indat endpoint flip */
-	1,				/* outdat endpoint flip */
-  	{0x81},				/* per port indat */
-  	{0x01},				/* per port outdat */
-	{0x85},				/* per port inack */
-	{0x05},				/* per port outcont */
-	0x87,				/* instat endpoint */
-	0x07,				/* glocont endpoint */
-	keyspan_usa19w_calc_baud,	/* calc baud rate */
-	KEYSPAN_USA18X_BAUDCLK		/* base baud clock */
-};
-
-static const keyspan_device_details usa19_device_details = {
-	keyspan_usa19_product_id,	/* product ID */
-       	msg_usa28, 			/* msg type*/
-	1,				/* num ports */
-	1,				/* indat endpoint flip */
-	1,				/* outdat endpoint flip */
-  	{0x81},				/* per port indat */
-  	{0x01},				/* per port outdat */
-	{0x83},				/* per port inack */
-	{0x03},				/* per port outcont */
-	0x84,				/* instat endpoint */
-	-1,				/* glocont endpoint */
-	keyspan_usa19_calc_baud,	/* calc baud rate */
-	KEYSPAN_USA19_BAUDCLK		/* base baud clock */
-};
-
-static const keyspan_device_details usa19w_device_details = {
-	keyspan_usa19w_product_id,	/* product ID */
-       	msg_usa26, 			/* msg type*/
-	1,				/* num ports */
-	0,				/* indat endpoint flip */
-	1,				/* outdat endpoint flip */
-  	{0x81},				/* per port indat */
-  	{0x01},				/* per port outdat */
-	{0x85},				/* per port inack */
-	{0x05},				/* per port outcont */
-	0x87,				/* instat endpoint */
-	0x07,				/* glocont endpoint */
-	keyspan_usa19w_calc_baud,	/* calc baud rate */
-	KEYSPAN_USA19W_BAUDCLK		/* base baud clock */
-};
-
-static const keyspan_device_details usa28x_device_details = {
-	keyspan_usa28x_product_id,	/* product ID */
-       	msg_usa26, 			/* msg type*/
-	2,				/* num ports */
-	0,				/* indat endpoint flip */
-	1,				/* outdat endpoint flip */
-  	{0x81, 0x83},			/* per port indat */
-  	{0x01, 0x03},			/* per port outdat */
-	{0x85, 0x86},			/* per port inack */
-	{0x05, 0x06},			/* per port outcont */
-	0x87,				/* instat endpoint */
-	0x07,				/* glocont endpoint */
-	keyspan_usa19w_calc_baud,	/* calc baud rate */
-	KEYSPAN_USA28X_BAUDCLK
-};
-
-static const keyspan_device_details usa28xa_device_details = {
-	keyspan_usa28xa_product_id,	/* product ID */
-       	msg_usa26, 			/* msg type*/
-	2,				/* num ports */
-	0,				/* indat endpoint flip */
-	1,				/* outdat endpoint flip */
-  	{0x81, 0x83},			/* per port indat */
-  	{0x01, 0x03},			/* per port outdat */
-	{0x85, 0x86},			/* per port inack */
-	{0x05, 0x06},			/* per port outcont */
-	0x87,				/* instat endpoint */
-	0x07,				/* glocont endpoint */
-	keyspan_usa19w_calc_baud,	/* calc baud rate */
-	KEYSPAN_USA28X_BAUDCLK
-};
-
-	/* We don't need a separate entry for the usa28xb as it appears as a 28x anyway */
-
-static const keyspan_device_details usa49w_device_details = {
-	keyspan_usa49w_product_id,	/* product ID */
-       	msg_usa49, 			/* msg type*/
-	4,				/* num ports */
-	0,				/* indat endpoint flip */
-	0,				/* outdat endpoint flip */
-  	{ 0x81, 0x82, 0x83, 0x84},	/* per port indat */
-  	{ 0x01, 0x02, 0x03, 0x04},	/* per port outdat */
-	{-1, -1, -1, -1},		/* per port inack */
-	{-1, -1, -1, -1},		/* per port outcont */
-	0x87,				/* instat endpoint */
-	0x07,				/* glocont endpoint */
-	keyspan_usa19w_calc_baud,	/* calc baud rate */
-	KEYSPAN_USA49W_BAUDCLK
+static const struct keyspan_device_details usa28xa_device_details = {
+	product_id:		keyspan_usa28xa_product_id,
+	msg_format:		msg_usa26,
+	num_ports:		2,
+	indat_endp_flip:	0,
+	outdat_endp_flip:	1,
+	indat_endpoints:	{0x81, 0x83},
+	outdat_endpoints:	{0x01, 0x03},
+	inack_endpoints:	{0x85, 0x86},
+	outcont_endpoints:	{0x05, 0x06},
+	instat_endpoint:	0x87,
+	glocont_endpoint:	0x07,
+	calculate_baud_rate:	keyspan_usa19w_calc_baud,
+	baudclk:		KEYSPAN_USA28X_BAUDCLK,
+};
+
+/* We don't need a separate entry for the usa28xb as it appears as a 28x anyway */
+
+static const struct keyspan_device_details usa49w_device_details = {
+	product_id:		keyspan_usa49w_product_id,
+	msg_format:		msg_usa49,
+	num_ports:		4,
+	indat_endp_flip:	0,
+	outdat_endp_flip:	0,
+	indat_endpoints:	{0x81, 0x82, 0x83, 0x84},
+	outdat_endpoints:	{0x01, 0x02, 0x03, 0x04},
+	inack_endpoints:	{-1, -1, -1, -1},
+	outcont_endpoints:	{-1, -1, -1, -1},
+	instat_endpoint:	0x87,
+	glocont_endpoint:	0x07,
+	calculate_baud_rate:	keyspan_usa19w_calc_baud,
+	baudclk:		KEYSPAN_USA49W_BAUDCLK,
 };
 
-static const keyspan_device_details *keyspan_devices[] = {
+static const struct keyspan_device_details *keyspan_devices[] = {
 	&usa18x_device_details,
 	&usa19_device_details,
+	&usa19qi_device_details,
+	&usa19qw_device_details,
 	&usa19w_device_details,
+	&usa28_device_details,
 	&usa28x_device_details,
 	&usa28xa_device_details,
+	/* 28xb not required as it renumerates as a 28x */
 	&usa49w_device_details,
-	NULL
+	NULL,
 };
 
 static __devinitdata struct usb_device_id keyspan_ids_combined[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) },
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) },
@@ -358,6 +422,8 @@
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) },
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) },
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
@@ -368,224 +434,58 @@
 
 MODULE_DEVICE_TABLE(usb, keyspan_ids_combined);
 
-/* Eventually, we will not need separate id tables for each USB
-   ID pattern.  But, for now, it looks like we need slightly different
-   behavior for each match. */
-
-static __devinitdata struct usb_device_id keyspan_usa18x_pre_ids[] = {
+/* usb_device_id table for the pre-firmware download keyspan devices */
+static struct usb_device_id keyspan_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
-	{ }	/* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa19_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa19w_pre_ids[] = {
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) },
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28x_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28xa_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28xb_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa49w_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) },
 	{ } /* Terminating entry */
 };
 
-static __devinitdata struct usb_device_id keyspan_usa18x_ids[] = {
+static struct usb_device_id keyspan_1port_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa19_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa19w_ids[] = {
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) },
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) },
 	{ } /* Terminating entry */
 };
 
-static __devinitdata struct usb_device_id keyspan_usa28_ids[] = {
+static struct usb_device_id keyspan_2port_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28x_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28xa_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
 	{ } /* Terminating entry */
 };
 
-static __devinitdata struct usb_device_id keyspan_usa49w_ids[] = {
+static struct usb_device_id keyspan_4port_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id) },
 	{ } /* Terminating entry */
 };
 
-    /* Structs for the devices, pre and post renumeration. */
-static struct usb_serial_device_type keyspan_usa18x_pre_device = {
-	name:			"Keyspan USA18X - (without firmware)",
-	id_table:		keyspan_usa18x_pre_ids,
-	needs_interrupt_in:	DONT_CARE,
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		DONT_CARE,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		1,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa19_pre_device = {
-	name:			"Keyspan USA19 - (without firmware)",
-	id_table:		keyspan_usa19_pre_ids,
-	needs_interrupt_in:	DONT_CARE,
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		DONT_CARE,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		1,
-	startup:		keyspan_fake_startup	
-};
-
-
-static struct usb_serial_device_type keyspan_usa19w_pre_device = {
-	name:			"Keyspan USA19W - (without firmware)",
-	id_table:		keyspan_usa19w_pre_ids,
-	needs_interrupt_in:	DONT_CARE,
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		DONT_CARE,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		1,
-	startup:		keyspan_fake_startup	
-};
-
-
-static struct usb_serial_device_type keyspan_usa28_pre_device = {
-	name:			"Keyspan USA28 - (without firmware)",
-	id_table:		keyspan_usa28_pre_ids,
-	needs_interrupt_in:	DONT_CARE,
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		DONT_CARE,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa28x_pre_device = {
-	name:			"Keyspan USA28X - (without firmware)",
-	id_table:		keyspan_usa28x_pre_ids,
-	needs_interrupt_in:	DONT_CARE,
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		DONT_CARE,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa28xa_pre_device = {
-	name:			"Keyspan USA28XA - (without firmware)",
-	id_table:		keyspan_usa28xa_pre_ids,
-	needs_interrupt_in:	DONT_CARE,
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		DONT_CARE,
+/* Structs for the devices, pre and post renumeration. */
+static struct usb_serial_device_type keyspan_pre_device = {
+	owner:			THIS_MODULE,
+	name:			"Keyspan - (without firmware)",
+	id_table:		keyspan_pre_ids,
 	num_interrupt_in:	NUM_DONT_CARE,
 	num_bulk_in:		NUM_DONT_CARE,
 	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa28xb_pre_device = {
-	name:			"Keyspan USA28XB - (without firmware)",
-	id_table:		keyspan_usa28xb_pre_ids,
-	needs_interrupt_in:	DONT_CARE,
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		DONT_CARE,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa49w_pre_device = {
-	name:			"Keyspan USA49W - (without firmware)",
-	id_table:		keyspan_usa49w_pre_ids,
-	needs_interrupt_in:	DONT_CARE,
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		DONT_CARE,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		4,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa18x_device = {
-	name:			"Keyspan USA18X",
-	id_table:		keyspan_usa18x_ids,
-	needs_interrupt_in:	DONT_CARE,	
-	needs_bulk_in:		MUST_HAVE,
-	needs_bulk_out:		MUST_HAVE,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		3,
-	num_bulk_out:		4,
 	num_ports:		1,
-	open:			keyspan_open,
-	close:			keyspan_close,
-	write:			keyspan_write,
-	write_room:		keyspan_write_room,
-	//write_bulk_callback: 	Not used - we define our own herbs
-	//read_int_callback:	keyspan_usa26_read_int_callback,
-	chars_in_buffer:	keyspan_chars_in_buffer,
-	throttle:		keyspan_rx_throttle,
-	unthrottle:		keyspan_rx_unthrottle,
-	ioctl:			keyspan_ioctl,
-	set_termios:		keyspan_set_termios,
-	break_ctl:		keyspan_break_ctl,
-	startup:		keyspan_startup,
-	shutdown:		keyspan_shutdown,
+	startup:		keyspan_fake_startup,
 };
 
-static struct usb_serial_device_type keyspan_usa19_device = {
-	name:			"Keyspan USA19",
-	id_table:		keyspan_usa19_ids,
-	needs_interrupt_in:	DONT_CARE,	
-	needs_bulk_in:		MUST_HAVE,
-	needs_bulk_out:		MUST_HAVE,
+static struct usb_serial_device_type keyspan_1port_device = {
+	owner:			THIS_MODULE,
+	name:			"Keyspan 1 port adapter",
+	id_table:		keyspan_1port_ids,
 	num_interrupt_in:	NUM_DONT_CARE,
 	num_bulk_in:		3,
 	num_bulk_out:		4,
@@ -594,8 +494,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-//	write_bulk_callback: 	keyspan_write_bulk_callback,
-//	read_int_callback:	keyspan_usa28_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -606,85 +504,10 @@
 	shutdown:		keyspan_shutdown,
 };
 
-
-static struct usb_serial_device_type keyspan_usa19w_device = {
-	name:			"Keyspan USA19W",
-	id_table:		keyspan_usa19w_ids,
-	needs_interrupt_in:	DONT_CARE,	
-	needs_bulk_in:		MUST_HAVE,
-	needs_bulk_out:		MUST_HAVE,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		3,
-	num_bulk_out:		4,
-	num_ports:		1,
-	open:			keyspan_open,
-	close:			keyspan_close,
-	write:			keyspan_write,
-	write_room:		keyspan_write_room,
-	//write_bulk_callback: 	Not used - we define our own herbs
-	//read_int_callback:	keyspan_usa26_read_int_callback,
-	chars_in_buffer:	keyspan_chars_in_buffer,
-	throttle:		keyspan_rx_throttle,
-	unthrottle:		keyspan_rx_unthrottle,
-	ioctl:			keyspan_ioctl,
-	set_termios:		keyspan_set_termios,
-	break_ctl:		keyspan_break_ctl,
-	startup:		keyspan_startup,
-	shutdown:		keyspan_shutdown,
-};
-
-
-static struct usb_serial_device_type keyspan_usa28_device = {
-	name:			"Keyspan USA28",
-	id_table:		keyspan_usa28_ids,
-	needs_interrupt_in:	DONT_CARE,	
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		DONT_CARE,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	open:			keyspan_open,
-	close:			keyspan_close,
-	throttle:		keyspan_rx_throttle,
-	unthrottle:		keyspan_rx_unthrottle,
-	set_termios:		keyspan_set_termios,
-};
-
-
-static struct usb_serial_device_type keyspan_usa28x_device = {
-	name:			"Keyspan USA28X/XB",
-	id_table:		keyspan_usa28x_ids,
-	needs_interrupt_in:	DONT_CARE,	
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		DONT_CARE,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	open:			keyspan_open,
-	close:			keyspan_close,
-	write:			keyspan_write,
-	write_room:		keyspan_write_room,
-//	write_bulk_callback: 	keyspan_write_bulk_callback,
-//	read_int_callback:	keyspan_usa26_read_int_callback,
-	chars_in_buffer:	keyspan_chars_in_buffer,
-	throttle:		keyspan_rx_throttle,
-	unthrottle:		keyspan_rx_unthrottle,
-	ioctl:			keyspan_ioctl,
-	set_termios:		keyspan_set_termios,
-	break_ctl:		keyspan_break_ctl,
-	startup:		keyspan_startup,
-	shutdown:		keyspan_shutdown,
-
-};
-
-static struct usb_serial_device_type keyspan_usa28xa_device = {
-	name:			"Keyspan USA28XA",
-	id_table:		keyspan_usa28xa_ids,
-	needs_interrupt_in:	DONT_CARE,	
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		DONT_CARE,
+static struct usb_serial_device_type keyspan_2port_device = {
+	owner:			THIS_MODULE,
+	name:			"Keyspan 2 port adapter",
+	id_table:		keyspan_2port_ids,
 	num_interrupt_in:	NUM_DONT_CARE,
 	num_bulk_in:		NUM_DONT_CARE,
 	num_bulk_out:		NUM_DONT_CARE,
@@ -693,8 +516,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-//	write_bulk_callback: 	keyspan_write_bulk_callback,
-//	read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -703,15 +524,12 @@
 	break_ctl:		keyspan_break_ctl,
 	startup:		keyspan_startup,
 	shutdown:		keyspan_shutdown,
-
 };
 
-static struct usb_serial_device_type keyspan_usa49w_device = {
-	name:			"Keyspan USA49W",
-	id_table:		keyspan_usa49w_ids,
-	needs_interrupt_in:	DONT_CARE,	
-	needs_bulk_in:		MUST_HAVE,
-	needs_bulk_out:		MUST_HAVE,
+static struct usb_serial_device_type keyspan_4port_device = {
+	owner:			THIS_MODULE,
+	name:			"Keyspan 4 port adapter",
+	id_table:		keyspan_4port_ids,
 	num_interrupt_in:	NUM_DONT_CARE,
 	num_bulk_in:		5,
 	num_bulk_out:		5,
@@ -720,8 +538,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-	//write_bulk_callback: 	Not used - we define our own herbs
-	//read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -732,5 +548,4 @@
 	shutdown:		keyspan_shutdown,
 };
 
-
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/keyspan_pda.c linux-2.4.20/drivers/usb/serial/keyspan_pda.c
--- linux-2.4.19/drivers/usb/serial/keyspan_pda.c	2001-10-11 06:42:47.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/keyspan_pda.c	2002-10-29 11:18:49.000000000 +0000
@@ -68,19 +68,16 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/tqueue.h>
+#include <asm/uaccess.h>
 #include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
@@ -157,25 +154,21 @@
 
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
-static __devinitdata struct usb_device_id id_table_std [] = {
+static struct usb_device_id id_table_std [] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) },
 	{ }						/* Terminating entry */
 };
 
 #ifdef KEYSPAN
-static __devinitdata struct usb_device_id id_table_fake [] = {
+static struct usb_device_id id_table_fake [] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) },
 	{ }						/* Terminating entry */
 };
 #endif
 
 #ifdef XIRCOM
-static __devinitdata struct usb_device_id id_table_fake_xircom [] = {
+static struct usb_device_id id_table_fake_xircom [] = {
         { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
-        { }                                             
-};
-
-static __devinitdata struct usb_device_id id_table_fake_entregra [] = {
         { USB_DEVICE(ENTREGRA_VENDOR_ID, ENTREGRA_FAKE_ID) },
         { }                                             
 };
@@ -197,26 +190,28 @@
 	/* wake up other tty processes */
 	wake_up_interruptible( &tty->write_wait );
 	/* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */
-	MOD_DEC_USE_COUNT;
 }
 
 static void keyspan_pda_request_unthrottle( struct usb_serial *serial )
 {
+	int result;
 
 	dbg(" request_unthrottle");
 	/* ask the device to tell us when the tx buffer becomes
 	   sufficiently empty */
-	usb_control_msg(serial->dev, 
-			     usb_sndctrlpipe(serial->dev, 0),
-			     7, /* request_unthrottle */
-			     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
-			     | USB_DIR_OUT,
-			     16, /* value: threshold */
-			     0, /* index */
-			     NULL,
-			     0,
-			     2*HZ);
-	MOD_DEC_USE_COUNT;
+	result = usb_control_msg(serial->dev, 
+				 usb_sndctrlpipe(serial->dev, 0),
+				 7, /* request_unthrottle */
+				 USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+				 | USB_DIR_OUT,
+				 16, /* value: threshold */
+				 0, /* index */
+				 NULL,
+				 0,
+				 2*HZ);
+	if (result < 0)
+		dbg("%s - error %d from usb_control_msg", 
+		    __FUNCTION__, result);
 }
 
 
@@ -265,9 +260,7 @@
 			tty = serial->port[0].tty;
 			priv->tx_throttled = 0;
 			/* queue up a wakeup at scheduler time */
-			MOD_INC_USE_COUNT;
-			if (schedule_task(&priv->wakeup_task) == 0)
-				MOD_DEC_USE_COUNT;
+			schedule_task(&priv->wakeup_task);
 			break;
 		default:
 			break;
@@ -345,14 +338,19 @@
 {
 	struct usb_serial *serial = port->serial;
 	int value;
+	int result;
+
 	if (break_state == -1)
 		value = 1; /* start break */
 	else
 		value = 0; /* clear break */
-	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			4, /* set break */
-			USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
-			value, 0, NULL, 0, 2*HZ);
+	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+				4, /* set break */
+				USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
+				value, 0, NULL, 0, 2*HZ);
+	if (result < 0)
+		dbg("%s - error %d from usb_control_msg", 
+		    __FUNCTION__, result);
 	/* there is something funky about this.. the TCSBRK that 'cu' performs
 	   ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4
 	   seconds apart, but it feels like the break sent isn't as long as it
@@ -606,9 +604,7 @@
 
 	if (request_unthrottle) {
 		priv->tx_throttled = 1; /* block writers */
-		MOD_INC_USE_COUNT;
-		if (schedule_task(&priv->unthrottle_task) == 0)
-			MOD_DEC_USE_COUNT;
+		schedule_task(&priv->unthrottle_task);
 	}
 
 	rc = count;
@@ -635,9 +631,7 @@
 	}
 	
 	/* queue up a wakeup at scheduler time */
-	MOD_INC_USE_COUNT;
-	if (schedule_task(&priv->wakeup_task) == 0)
-		MOD_DEC_USE_COUNT;
+	schedule_task(&priv->wakeup_task);
 }
 
 
@@ -674,62 +668,45 @@
 	int rc = 0;
 	struct keyspan_pda_private *priv;
 
-	down (&port->sem);
-
-	MOD_INC_USE_COUNT;
-	++port->open_count;
-
-	if (!port->active) {
-		port->active = 1;
- 
-		/* find out how much room is in the Tx ring */
-		rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
-				     6, /* write_room */
-				     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
-				     | USB_DIR_IN,
-				     0, /* value */
-				     0, /* index */
-				     &room,
-				     1,
-				     2*HZ);
-		if (rc < 0) {
-			dbg(__FUNCTION__" - roomquery failed");
-			goto error;
-		}
-		if (rc == 0) {
-			dbg(__FUNCTION__" - roomquery returned 0 bytes");
-			rc = -EIO;
-			goto error;
-		}
-		priv = (struct keyspan_pda_private *)(port->private);
-		priv->tx_room = room;
-		priv->tx_throttled = room ? 0 : 1;
-
-		/* the normal serial device seems to always turn on DTR and RTS here,
-		   so do the same */
-		if (port->tty->termios->c_cflag & CBAUD)
-			keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );
-		else
-			keyspan_pda_set_modem_info(serial, 0);
+	/* find out how much room is in the Tx ring */
+	rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+			     6, /* write_room */
+			     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+			     | USB_DIR_IN,
+			     0, /* value */
+			     0, /* index */
+			     &room,
+			     1,
+			     2*HZ);
+	if (rc < 0) {
+		dbg("%s - roomquery failed", __FUNCTION__);
+		goto error;
+	}
+	if (rc == 0) {
+		dbg("%s - roomquery returned 0 bytes", __FUNCTION__);
+		rc = -EIO;
+		goto error;
+	}
+	priv = (struct keyspan_pda_private *)(port->private);
+	priv->tx_room = room;
+	priv->tx_throttled = room ? 0 : 1;
 
-		/*Start reading from the device*/
-		port->interrupt_in_urb->dev = serial->dev;
-		rc = usb_submit_urb(port->interrupt_in_urb);
-		if (rc) {
-			dbg(__FUNCTION__" - usb_submit_urb(read int) failed");
-			goto error;
-		}
+	/* the normal serial device seems to always turn on DTR and RTS here,
+	   so do the same */
+	if (port->tty->termios->c_cflag & CBAUD)
+		keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );
+	else
+		keyspan_pda_set_modem_info(serial, 0);
 
+	/*Start reading from the device*/
+	port->interrupt_in_urb->dev = serial->dev;
+	rc = usb_submit_urb(port->interrupt_in_urb);
+	if (rc) {
+		dbg("%s - usb_submit_urb(read int) failed", __FUNCTION__);
+		goto error;
 	}
 
-
-	up (&port->sem);
-	return rc;
 error:
-	--port->open_count;
-	port->active = 0;
-	MOD_DEC_USE_COUNT;
-	up (&port->sem);
 	return rc;
 }
 
@@ -738,26 +715,15 @@
 {
 	struct usb_serial *serial = port->serial;
 
-	down (&port->sem);
-
-	--port->open_count;
+	if (serial->dev) {
+		/* the normal serial device seems to always shut off DTR and RTS now */
+		if (port->tty->termios->c_cflag & HUPCL)
+			keyspan_pda_set_modem_info(serial, 0);
 
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			/* the normal serial device seems to always shut off DTR and RTS now */
-			if (port->tty->termios->c_cflag & HUPCL)
-				keyspan_pda_set_modem_info(serial, 0);
-
-			/* shutdown our bulk reads and writes */
-			usb_unlink_urb (port->write_urb);
-			usb_unlink_urb (port->interrupt_in_urb);
-		}
-		port->active = 0;
-		port->open_count = 0;
+		/* shutdown our bulk reads and writes */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->interrupt_in_urb);
 	}
-
-	up (&port->sem);
-	MOD_DEC_USE_COUNT;
 }
 
 
@@ -780,7 +746,7 @@
 		record = &xircom_pgs_firmware[0];
 #endif
 	if (record == NULL) {
-		err(__FUNCTION__": unknown vendor, aborting.");
+		err("%s: unknown vendor, aborting.", __FUNCTION__);
 		return -ENODEV;
 	}
 
@@ -831,81 +797,59 @@
 
 static void keyspan_pda_shutdown (struct usb_serial *serial)
 {
-	dbg (__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 	
-	while (serial->port[0].open_count > 0) {
-		keyspan_pda_close (&serial->port[0], NULL);
-	}
 	kfree(serial->port[0].private);
 }
 
 #ifdef KEYSPAN
 static struct usb_serial_device_type keyspan_pda_fake_device = {
-	name:			"Keyspan PDA - (prerenumeration)",
-	id_table:		id_table_fake,
-	needs_interrupt_in:	DONT_CARE,
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		DONT_CARE,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		1,
-	startup:		keyspan_pda_fake_startup,
+	.owner =		THIS_MODULE,
+	.name =			"Keyspan PDA - (prerenumeration)",
+	.id_table =		id_table_fake,
+	.num_interrupt_in =	NUM_DONT_CARE,
+	.num_bulk_in =		NUM_DONT_CARE,
+	.num_bulk_out =		NUM_DONT_CARE,
+	.num_ports =		1,
+	.startup =		keyspan_pda_fake_startup,
 };
 #endif
 
 #ifdef XIRCOM
 static struct usb_serial_device_type xircom_pgs_fake_device = {
-        name:                   "Xircom PGS - (prerenumeration)",
-        id_table:               id_table_fake_xircom,
-        needs_interrupt_in:     DONT_CARE,
-        needs_bulk_in:          DONT_CARE,
-        needs_bulk_out:         DONT_CARE,
-        num_interrupt_in:       NUM_DONT_CARE,
-        num_bulk_in:            NUM_DONT_CARE,
-        num_bulk_out:           NUM_DONT_CARE,
-        num_ports:              1,
-        startup:                keyspan_pda_fake_startup,
-};
-
-static struct usb_serial_device_type entregra_pgs_fake_device = {
-        name:                   "Entregra PGS - (prerenumeration)",
-        id_table:               id_table_fake_entregra,
-        needs_interrupt_in:     DONT_CARE,
-        needs_bulk_in:          DONT_CARE,
-        needs_bulk_out:         DONT_CARE,
-        num_interrupt_in:       NUM_DONT_CARE,
-        num_bulk_in:            NUM_DONT_CARE,
-        num_bulk_out:           NUM_DONT_CARE,
-        num_ports:              1,
-        startup:                keyspan_pda_fake_startup,
+	.owner =		THIS_MODULE,
+	.name =			"Xircom / Entregra PGS - (prerenumeration)",
+	.id_table =		id_table_fake_xircom,
+	.num_interrupt_in =	NUM_DONT_CARE,
+	.num_bulk_in =		NUM_DONT_CARE,
+	.num_bulk_out =		NUM_DONT_CARE,
+	.num_ports =		1,
+	.startup =		keyspan_pda_fake_startup,
 };
 #endif
 
 static struct usb_serial_device_type keyspan_pda_device = {
-	name:			"Keyspan PDA",
-	id_table:		id_table_std,
-	needs_interrupt_in:	MUST_HAVE,
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		MUST_HAVE,
-	num_interrupt_in:	1,
-	num_bulk_in:		0,
-	num_bulk_out:		1,
-	num_ports:		1,
-	open:			keyspan_pda_open,
-	close:			keyspan_pda_close,
-	write:			keyspan_pda_write,
-	write_room:		keyspan_pda_write_room,
-	write_bulk_callback: 	keyspan_pda_write_bulk_callback,
-	read_int_callback:	keyspan_pda_rx_interrupt,
-	chars_in_buffer:	keyspan_pda_chars_in_buffer,
-	throttle:		keyspan_pda_rx_throttle,
-	unthrottle:		keyspan_pda_rx_unthrottle,
-	ioctl:			keyspan_pda_ioctl,
-	set_termios:		keyspan_pda_set_termios,
-	break_ctl:		keyspan_pda_break_ctl,
-	startup:		keyspan_pda_startup,
-	shutdown:		keyspan_pda_shutdown,
+	.owner =		THIS_MODULE,
+	.name =			"Keyspan PDA",
+	.id_table =		id_table_std,
+	.num_interrupt_in =	1,
+	.num_bulk_in =		0,
+	.num_bulk_out =		1,
+	.num_ports =		1,
+	.open =			keyspan_pda_open,
+	.close =		keyspan_pda_close,
+	.write =		keyspan_pda_write,
+	.write_room =		keyspan_pda_write_room,
+	.write_bulk_callback = 	keyspan_pda_write_bulk_callback,
+	.read_int_callback =	keyspan_pda_rx_interrupt,
+	.chars_in_buffer =	keyspan_pda_chars_in_buffer,
+	.throttle =		keyspan_pda_rx_throttle,
+	.unthrottle =		keyspan_pda_rx_unthrottle,
+	.ioctl =		keyspan_pda_ioctl,
+	.set_termios =		keyspan_pda_set_termios,
+	.break_ctl =		keyspan_pda_break_ctl,
+	.startup =		keyspan_pda_startup,
+	.shutdown =		keyspan_pda_shutdown,
 };
 
 
@@ -917,7 +861,6 @@
 #endif
 #ifdef XIRCOM
 	usb_serial_register (&xircom_pgs_fake_device);
-	usb_serial_register (&entregra_pgs_fake_device);
 #endif
 	info(DRIVER_DESC " " DRIVER_VERSION);
 	return 0;
@@ -931,7 +874,6 @@
 	usb_serial_deregister (&keyspan_pda_fake_device);
 #endif
 #ifdef XIRCOM
-	usb_serial_deregister (&entregra_pgs_fake_device);
 	usb_serial_deregister (&xircom_pgs_fake_device);
 #endif
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/keyspan_usa18x_fw.h linux-2.4.20/drivers/usb/serial/keyspan_usa18x_fw.h
--- linux-2.4.19/drivers/usb/serial/keyspan_usa18x_fw.h	2001-10-09 22:15:02.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/keyspan_usa18x_fw.h	2002-10-29 11:18:40.000000000 +0000
@@ -1,341 +1,345 @@
 /* keyspan_usa18x_fw.h
-  
-   Generated from Keyspan firmware image usa16code.h Sat Oct  6 12:16:35 EST 2001
-   This firmware is for the Keyspan USA-18X Serial Adaptor
 
-   "The firmware contained herein as keyspan_usa18x_fw.h is
-   Copyright (C) 1999-2001 Keyspan, A division of InnoSys Incorporated
-   ("Keyspan"), as an unpublished work.  This notice does not imply
-   unrestricted or public access to this firmware which is a trade secret of
-   Keyspan, and which may not be reproduced, used, sold or transferred to any
-   third party without Keyspan's prior written consent.  All Rights Reserved.
+	The firmware contained herein as keyspan_usa18x_fw.h is
 
-   This firmware may not be modified and may only be used with the Keyspan 
-   USA-18X Serial Adapter.  Distribution and/or Modification of the
-   keyspan.c driver which includes this firmware, in whole or in part,
-   requires the inclusion of this statement."
+		Copyright (C) 1999-2001
+		Keyspan, A division of InnoSys Incorporated ("Keyspan")
+		
+	as an unpublished work. This notice does not imply unrestricted or
+	public access to the source code from which this firmware image is
+	derived.  Except as noted below this firmware image may not be 
+	reproduced, used, sold or transferred to any third party without 
+	Keyspan's prior written consent.  All Rights Reserved.
 
+	Permission is hereby granted for the distribution of this firmware 
+	image as part of a Linux or other Open Source operating system kernel 
+	in text or binary form as required. 
+
+	This firmware may not be modified and may only be used with  
+	Keyspan hardware.  Distribution and/or Modification of the 
+	keyspan.c driver which includes this firmware, in whole or in 
+	part, requires the inclusion of this statement."
 */
 
 static const struct ezusb_hex_record keyspan_usa18x_firmware[] = {
- {0x0033,  3, { 0x02, 0x13, 0xab}},
+ {0x0033,  3, { 0x02, 0x12, 0xf7}},
  {0x0003, 16, { 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0}},
  {0x0013, 16, { 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90}},
  {0x0023, 15, { 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x07, 0xf0, 0xe4, 0x90, 0x7f, 0x98, 0xf0, 0x22}},
- {0x0046, 16, { 0x30, 0x09, 0x18, 0x12, 0x13, 0x33, 0xef, 0xc3, 0x95, 0x3c, 0x40, 0x03, 0x02, 0x00, 0xd8, 0x90}},
+ {0x0046, 16, { 0x30, 0x09, 0x18, 0x12, 0x13, 0x1b, 0xef, 0xc3, 0x95, 0x3c, 0x40, 0x03, 0x02, 0x00, 0xd8, 0x90}},
  {0x0056, 16, { 0x7f, 0xbf, 0x74, 0x01, 0xf0, 0xc2, 0x09, 0xc2, 0x00, 0x80, 0x77, 0x30, 0x03, 0x3b, 0x90, 0x7f}},
- {0x0066, 16, { 0xc6, 0xe0, 0x20, 0xe1, 0x6d, 0x12, 0x13, 0x33, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x64, 0x90, 0x7e}},
+ {0x0066, 16, { 0xc6, 0xe0, 0x20, 0xe1, 0x6d, 0x12, 0x13, 0x1b, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x64, 0x90, 0x7e}},
  {0x0076, 16, { 0x40, 0xe0, 0x13, 0x92, 0x09, 0x90, 0x7f, 0xc7, 0xe0, 0x14, 0xf5, 0x19, 0x20, 0x00, 0x11, 0x60}},
- {0x0086, 16, { 0x0f, 0xf5, 0x08, 0x7e, 0x7e, 0x7f, 0x41, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x41, 0x12, 0x0c, 0xca}},
+ {0x0086, 16, { 0x0f, 0xf5, 0x08, 0x7e, 0x7e, 0x7f, 0x41, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x41, 0x12, 0x0c, 0xba}},
  {0x0096, 16, { 0xc2, 0x03, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0x80, 0x39, 0x90, 0x7f, 0xc8, 0xe0, 0x20, 0xe1, 0x32}},
- {0x00a6, 16, { 0x12, 0x13, 0x33, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x29, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x09}},
+ {0x00a6, 16, { 0x12, 0x13, 0x1b, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x29, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x09}},
  {0x00b6, 16, { 0x90, 0x7f, 0xc9, 0xe0, 0x14, 0xf5, 0x19, 0x20, 0x00, 0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7d}},
- {0x00c6, 16, { 0x7f, 0xc1, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0xc1, 0x12, 0x0c, 0xca, 0xd2, 0x03, 0xe4, 0x90, 0x7f}},
- {0x00d6, 16, { 0xc9, 0xf0, 0x90, 0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x01, 0x66, 0x53, 0x36, 0x80, 0x12}},
- {0x00e6, 16, { 0x13, 0x3f, 0xef, 0x42, 0x36, 0x12, 0x11, 0xed, 0x8f, 0x19, 0xef, 0xc3, 0x95, 0x3a, 0x50, 0x0f}},
- {0x00f6, 16, { 0x12, 0x13, 0x1b, 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x36, 0x20, 0xe7, 0x03, 0x30, 0x0b, 0x61, 0xc2}},
+ {0x00c6, 16, { 0x7f, 0xc1, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0xc1, 0x12, 0x0c, 0xba, 0xd2, 0x03, 0xe4, 0x90, 0x7f}},
+ {0x00d6, 16, { 0xc9, 0xf0, 0x90, 0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x01, 0x60, 0x12, 0x11, 0xd6, 0x8f}},
+ {0x00e6, 16, { 0x19, 0x12, 0x13, 0x27, 0x8f, 0x36, 0xe5, 0x19, 0xc3, 0x95, 0x3a, 0x50, 0x0f, 0x12, 0x12, 0xeb}},
+ {0x00f6, 16, { 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x36, 0x20, 0xe7, 0x03, 0x30, 0x0b, 0x5e, 0xc2, 0x0b, 0xe5, 0x19}},
  {0x0036, 12, { 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22}},
  {0x0043,  3, { 0x02, 0x13, 0x00}},
- {0x0000,  3, { 0x02, 0x0e, 0x10}},
- {0x0106, 64, { 0x0b, 0xe5, 0x19, 0x70, 0x04, 0xf5, 0x36, 0x80, 0x57, 0x12, 0x13, 0x3f, 0xef, 0x42, 0x36, 0xe5, 0x36,
-  0x30, 0xe7, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08,
-  0x7e, 0x7e, 0x7f, 0x80, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x80, 0xaf, 0x36, 0x12, 0x0f, 0x5b, 0xe5,
-  0x19, 0x25, 0xe0, 0x90, 0x7f, 0xb7, 0xf0, 0x80, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40}},
- {0x0146, 64, { 0x03, 0x75, 0x19, 0x3f, 0x85, 0x19, 0x08, 0xe4, 0x90, 0x7e, 0x80, 0xf0, 0x7e, 0x7e, 0x7f, 0x81, 0x75,
-  0x0c, 0x7e, 0x75, 0x0d, 0x81, 0x12, 0x0c, 0xef, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xb7, 0xf0, 0x90,
-  0x7f, 0xce, 0xe0, 0x30, 0xe1, 0x06, 0x20, 0x05, 0x03, 0x02, 0x03, 0xc5, 0xc2, 0x05, 0xe4, 0xf5,
-  0x18, 0x74, 0x40, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xff, 0xe5}},
- {0x0186, 64, { 0x18, 0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e, 0x79, 0x00, 0x24, 0x00, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef,
-  0x12, 0x0e, 0xe2, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x00, 0xe0, 0x60, 0x68,
-  0x90, 0x7e, 0x03, 0xe0, 0x60, 0x24, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x11, 0xc8, 0x7f, 0x03, 0x7d,
-  0xcd, 0x12, 0x11, 0xc8, 0x43, 0x46, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0}},
- {0x01c6, 64, { 0x00, 0xe5, 0x46, 0xf0, 0xe4, 0x90, 0x7e, 0x13, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x01, 0xe0, 0xff, 0x12,
-  0x10, 0x4c, 0x90, 0x7e, 0x02, 0xe0, 0xff, 0x12, 0x10, 0x72, 0x7f, 0x01, 0x90, 0x7e, 0x11, 0xe0,
-  0xfd, 0x12, 0x11, 0xc8, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x11, 0xc8, 0x43, 0x46, 0x80, 0x90, 0x7f,
-  0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12}},
- {0x0206, 64, { 0xf0, 0xe5, 0x40, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x03, 0xe0, 0x70, 0x06, 0x90, 0x7e,
-  0x13, 0xe0, 0x70, 0x08, 0xe4, 0x90, 0x7e, 0x13, 0xf0, 0x75, 0x25, 0xff, 0x90, 0x7e, 0x05, 0xe0,
-  0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f, 0xf5, 0x44, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0,
-  0x00, 0xe5, 0x44, 0xf0, 0x90, 0x7e, 0x07, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43}},
- {0x0246, 64, { 0x42, 0x80, 0x80, 0x03, 0x53, 0x42, 0x7f, 0x53, 0x42, 0xfc, 0x90, 0x7e, 0x09, 0xe0, 0x60, 0x11, 0x43,
-  0x42, 0x02, 0xa3, 0xe0, 0xff, 0x12, 0x10, 0xbe, 0x90, 0x7e, 0x0b, 0xe0, 0xff, 0x12, 0x10, 0xe4,
-  0xaf, 0x42, 0x12, 0x10, 0x98, 0x90, 0x7e, 0x03, 0xe0, 0x60, 0x08, 0x53, 0x42, 0x7f, 0xaf, 0x42,
-  0x12, 0x10, 0x98, 0x90, 0x7e, 0x0c, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46}},
- {0x0286, 64, { 0x02, 0x80, 0x03, 0x53, 0x46, 0xfd, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46,
-  0xf0, 0x90, 0x7e, 0x0e, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x01, 0x80, 0x03,
-  0x53, 0x46, 0xfe, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90,
-  0x7e, 0x12, 0xe0, 0xf5, 0x3a, 0xa3, 0xe0, 0x13, 0x92, 0x0d, 0xa3, 0xe0, 0xf5, 0x3c, 0xa3}},
- {0x02c6, 64, { 0xe0, 0x60, 0x05, 0x43, 0x46, 0x10, 0x80, 0x03, 0x53, 0x46, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0,
-  0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x16, 0xe0, 0x60, 0x32, 0x53, 0x44, 0xbf, 0x90,
-  0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98,
-  0x74, 0x11, 0xf0, 0x12, 0x13, 0x0f, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3e}},
- {0x0306, 64, { 0xfd, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xc8, 0xe4, 0xf5, 0x2a, 0xf5, 0x29, 0xd2, 0x07, 0x90, 0x7e,
-  0x17, 0xe0, 0x60, 0x0f, 0x43, 0x3e, 0x02, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xc8, 0x75, 0x29,
-  0x01, 0xd2, 0x07, 0x90, 0x7e, 0x18, 0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5,
-  0x40, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0, 0xd2, 0x00, 0x90, 0x7e, 0x19, 0xe0, 0x60, 0x11}},
- {0x0346, 64, { 0x43, 0x44, 0x40, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0,
-  0x90, 0x7e, 0x1a, 0xe0, 0x60, 0x0f, 0x53, 0x3e, 0xfe, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xc8,
-  0x75, 0x2b, 0x01, 0xd2, 0x07, 0x90, 0x7e, 0x1b, 0xe0, 0x60, 0x0f, 0x43, 0x3e, 0x01, 0xe4, 0xff,
-  0xad, 0x3e, 0x12, 0x11, 0xc8, 0xe4, 0xf5, 0x2b, 0xd2, 0x07, 0x90, 0x7e, 0x1c, 0xe0, 0x60}},
- {0x0386, 64, { 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e,
-  0x1d, 0xe0, 0x60, 0x02, 0xd2, 0x0b, 0x90, 0x7e, 0x1e, 0xe0, 0x60, 0x08, 0x75, 0x2c, 0x01, 0xe4,
-  0xf5, 0x38, 0xd2, 0x07, 0x90, 0x7e, 0x1f, 0xe0, 0x60, 0x0f, 0x90, 0x7f, 0xd7, 0x74, 0x11, 0xf0,
-  0x74, 0x31, 0xf0, 0x74, 0x15, 0xf0, 0x74, 0x35, 0xf0, 0xe4, 0x90, 0x7f, 0xcf, 0xf0, 0x30}},
- {0x03c6, 64, { 0x1a, 0x52, 0xe5, 0x38, 0x60, 0x02, 0x15, 0x38, 0x20, 0x13, 0x49, 0xe5, 0x13, 0xd3, 0x94, 0x00, 0x40,
-  0x04, 0x15, 0x13, 0x80, 0x3e, 0x75, 0x13, 0x0a, 0x30, 0x1b, 0x02, 0xd2, 0x13, 0x12, 0x13, 0x0f,
-  0xef, 0x54, 0x01, 0xf5, 0x19, 0x65, 0x2a, 0x60, 0x05, 0x85, 0x19, 0x2a, 0xd2, 0x07, 0x12, 0x13,
-  0x4b, 0xef, 0x54, 0x80, 0xf5, 0x19, 0x65, 0x26, 0x60, 0x05, 0x85, 0x19, 0x26, 0xd2, 0x07}},
- {0x0406, 64, { 0x30, 0x0d, 0x11, 0x12, 0x13, 0x4b, 0xef, 0x54, 0x10, 0xf5, 0x19, 0x65, 0x25, 0x60, 0x05, 0x85, 0x19,
-  0x25, 0xd2, 0x07, 0x20, 0x1b, 0x03, 0x02, 0x07, 0xf4, 0x30, 0x0a, 0x18, 0x12, 0x13, 0x87, 0xef,
-  0xc3, 0x95, 0x3d, 0x40, 0x03, 0x02, 0x04, 0xb2, 0x90, 0x7f, 0xc1, 0x74, 0x01, 0xf0, 0xc2, 0x0a,
-  0xc2, 0x00, 0x80, 0x77, 0x30, 0x04, 0x3b, 0x90, 0x7f, 0xca, 0xe0, 0x20, 0xe1, 0x6d, 0x12}},
- {0x0446, 64, { 0x13, 0x87, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x64, 0x90, 0x7d, 0x40, 0xe0, 0x13, 0x92, 0x0a, 0x90, 0x7f,
-  0xcb, 0xe0, 0x14, 0xf5, 0x19, 0x20, 0x00, 0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7d, 0x7f, 0x41,
-  0x75, 0x0c, 0x7d, 0x75, 0x0d, 0x41, 0x12, 0x0d, 0x14, 0xc2, 0x04, 0xe4, 0x90, 0x7f, 0xcb, 0xf0,
-  0x80, 0x39, 0x90, 0x7f, 0xcc, 0xe0, 0x20, 0xe1, 0x32, 0x12, 0x13, 0x87, 0xef, 0xc3, 0x94}},
- {0x0486, 64, { 0x40, 0x50, 0x29, 0x90, 0x7c, 0xc0, 0xe0, 0x13, 0x92, 0x0a, 0x90, 0x7f, 0xcd, 0xe0, 0x14, 0xf5, 0x19,
-  0x20, 0x00, 0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7c, 0x7f, 0xc1, 0x75, 0x0c, 0x7c, 0x75, 0x0d,
-  0xc1, 0x12, 0x0d, 0x14, 0xd2, 0x04, 0xe4, 0x90, 0x7f, 0xcd, 0xf0, 0x90, 0x7f, 0xba, 0xe0, 0x30,
-  0xe1, 0x03, 0x02, 0x05, 0x40, 0x53, 0x37, 0x80, 0x12, 0x13, 0x93, 0xef, 0x42, 0x37, 0x12}},
- {0x04c6, 64, { 0x12, 0x37, 0x8f, 0x19, 0xef, 0xc3, 0x95, 0x3b, 0x50, 0x0f, 0x12, 0x13, 0x6f, 0xef, 0x30, 0xe0, 0x08,
-  0xe5, 0x37, 0x20, 0xe7, 0x03, 0x30, 0x0c, 0x61, 0xc2, 0x0c, 0xe5, 0x19, 0x70, 0x04, 0xf5, 0x37,
-  0x80, 0x57, 0x12, 0x13, 0x93, 0xef, 0x42, 0x37, 0xe5, 0x37, 0x30, 0xe7, 0x26, 0xe5, 0x19, 0xd3,
-  0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08, 0x7e, 0x7d, 0x7f, 0x80, 0x75}},
- {0x0506, 64, { 0x0c, 0x7d, 0x75, 0x0d, 0x80, 0xaf, 0x37, 0x12, 0x0f, 0x94, 0xe5, 0x19, 0x25, 0xe0, 0x90, 0x7f, 0xbb,
-  0xf0, 0x80, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75, 0x19, 0x3f, 0x85, 0x19, 0x08,
-  0xe4, 0x90, 0x7d, 0x80, 0xf0, 0x7e, 0x7d, 0x7f, 0x81, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0x81, 0x12,
-  0x0d, 0x39, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xbb, 0xf0, 0x90, 0x7f, 0xd0, 0xe0, 0x30, 0xe1}},
- {0x0546, 64, { 0x06, 0x20, 0x06, 0x03, 0x02, 0x07, 0x9f, 0xc2, 0x06, 0xe4, 0xf5, 0x18, 0x74, 0xc0, 0x25, 0x18, 0xf5,
-  0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18, 0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e,
-  0x79, 0x20, 0x24, 0x20, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef, 0x12, 0x0e, 0xe2, 0x05, 0x18, 0xe5,
-  0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x20, 0xe0, 0x60, 0x68, 0x90, 0x7e, 0x23, 0xe0, 0x60}},
- {0x0586, 64, { 0x24, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x12, 0x12, 0x7f, 0x03, 0x7d, 0xcd, 0x12, 0x12, 0x12, 0x43, 0x47,
-  0x80, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0xe4, 0x90, 0x7e,
-  0x33, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x21, 0xe0, 0xff, 0x12, 0x11, 0x30, 0x90, 0x7e, 0x22, 0xe0,
-  0xff, 0x12, 0x11, 0x56, 0x7f, 0x01, 0x90, 0x7e, 0x31, 0xe0, 0xfd, 0x12, 0x12, 0x12, 0x7f}},
- {0x05c6, 64, { 0x03, 0x7d, 0x07, 0x12, 0x12, 0x12, 0x43, 0x47, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0,
-  0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0xe5, 0x41, 0x44, 0x06, 0x90, 0xc0,
-  0x00, 0xf0, 0x90, 0x7e, 0x23, 0xe0, 0x70, 0x06, 0x90, 0x7e, 0x33, 0xe0, 0x70, 0x08, 0xe4, 0x90,
-  0x7e, 0x33, 0xf0, 0x75, 0x2e, 0xff, 0x90, 0x7e, 0x25, 0xe0, 0x60, 0x12, 0xa3, 0xe0, 0x54}},
- {0x0606, 64, { 0x3f, 0xf5, 0x45, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x45, 0xf0, 0x90, 0x7e,
-  0x27, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x43, 0x80, 0x80, 0x03, 0x53, 0x43, 0x7f,
-  0x53, 0x43, 0xfc, 0x90, 0x7e, 0x29, 0xe0, 0x60, 0x11, 0x43, 0x43, 0x02, 0xa3, 0xe0, 0xff, 0x12,
-  0x11, 0x7c, 0x90, 0x7e, 0x2b, 0xe0, 0xff, 0x12, 0x11, 0xa2, 0xaf, 0x43, 0x12, 0x11, 0x0a}},
- {0x0646, 64, { 0x90, 0x7e, 0x23, 0xe0, 0x60, 0x08, 0x53, 0x43, 0x7f, 0xaf, 0x43, 0x12, 0x11, 0x0a, 0x90, 0x7e, 0x2c,
-  0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x02, 0x80, 0x03, 0x53, 0x47, 0xfd, 0x90,
-  0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7e, 0x2e, 0xe0, 0x60,
-  0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x01, 0x80, 0x03, 0x53, 0x47, 0xfe, 0x90, 0x7f}},
- {0x0686, 64, { 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7e, 0x32, 0xe0, 0xf5, 0x3b, 0xa3,
-  0xe0, 0x13, 0x92, 0x0e, 0xa3, 0xe0, 0xf5, 0x3d, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x10, 0x80,
-  0x03, 0x53, 0x47, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0,
-  0x90, 0x7e, 0x36, 0xe0, 0x60, 0x32, 0x53, 0x45, 0xbf, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0}},
- {0x06c6, 64, { 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x12, 0x13, 0x63,
-  0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3f, 0xfd, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12,
-  0x12, 0xe4, 0xf5, 0x33, 0xf5, 0x32, 0xd2, 0x08, 0x90, 0x7e, 0x37, 0xe0, 0x60, 0x0f, 0x43, 0x3f,
-  0x02, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x12, 0x75, 0x32, 0x01, 0xd2, 0x08, 0x90, 0x7e}},
- {0x0706, 64, { 0x38, 0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0xe5, 0x41, 0x44, 0x04, 0x90, 0xc0, 0x00,
-  0xf0, 0xd2, 0x00, 0x90, 0x7e, 0x39, 0xe0, 0x60, 0x11, 0x43, 0x45, 0x40, 0x90, 0x7f, 0x98, 0x74,
-  0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x3a, 0xe0, 0x60, 0x0f,
-  0x53, 0x3f, 0xfe, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x12, 0x75, 0x34, 0x01, 0xd2, 0x08}},
- {0x0746, 64, { 0x90, 0x7e, 0x3b, 0xe0, 0x60, 0x0f, 0x43, 0x3f, 0x01, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x12, 0xe4,
-  0xf5, 0x34, 0xd2, 0x08, 0x90, 0x7e, 0x3c, 0xe0, 0x60, 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0,
-  0xe5, 0x41, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x3d, 0xe0, 0x60, 0x02, 0xd2, 0x0c,
-  0x90, 0x7e, 0x3e, 0xe0, 0x60, 0x08, 0x75, 0x35, 0x01, 0xe4, 0xf5, 0x39, 0xd2, 0x08, 0x90}},
- {0x0786, 64, { 0x7e, 0x3f, 0xe0, 0x60, 0x0f, 0x90, 0x7f, 0xd7, 0x74, 0x13, 0xf0, 0x74, 0x33, 0xf0, 0x74, 0x16, 0xf0,
-  0x74, 0x36, 0xf0, 0xe4, 0x90, 0x7f, 0xd1, 0xf0, 0x30, 0x1a, 0x52, 0xe5, 0x39, 0x60, 0x02, 0x15,
-  0x39, 0x30, 0x13, 0x49, 0xe5, 0x13, 0xd3, 0x94, 0x00, 0x40, 0x04, 0x15, 0x13, 0x80, 0x3e, 0x75,
-  0x13, 0x0a, 0x30, 0x1b, 0x02, 0xc2, 0x13, 0x12, 0x13, 0x63, 0xef, 0x54, 0x01, 0xf5, 0x19}},
- {0x07c6, 64, { 0x65, 0x33, 0x60, 0x05, 0x85, 0x19, 0x33, 0xd2, 0x08, 0x12, 0x13, 0x9f, 0xef, 0x54, 0x80, 0xf5, 0x19,
-  0x65, 0x2f, 0x60, 0x05, 0x85, 0x19, 0x2f, 0xd2, 0x08, 0x30, 0x0e, 0x11, 0x12, 0x13, 0x9f, 0xef,
-  0x54, 0x10, 0xf5, 0x19, 0x65, 0x2e, 0x60, 0x05, 0x85, 0x19, 0x2e, 0xd2, 0x08, 0x30, 0x1a, 0x2a,
-  0x90, 0x7f, 0xd2, 0xe0, 0x20, 0xe1, 0x23, 0x90, 0x7b, 0x40, 0xe0, 0x60, 0x09, 0xe0, 0xf5}},
- {0x0806, 64, { 0x15, 0x90, 0x7b, 0x42, 0xe0, 0xf5, 0x16, 0x90, 0x7b, 0x41, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7, 0x74,
-  0x17, 0xf0, 0x74, 0x37, 0xf0, 0xe4, 0x90, 0x7f, 0xd3, 0xf0, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1,
-  0x03, 0x02, 0x09, 0x28, 0xe5, 0x0a, 0x70, 0x40, 0x30, 0x07, 0x39, 0xe5, 0x38, 0x70, 0x35, 0xc2,
-  0x07, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00}},
- {0x0846, 64, { 0xfa, 0x12, 0x0e, 0x9c, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef,
-  0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x09, 0xf0, 0x75, 0x38,
-  0x10, 0xe4, 0xf5, 0x2c, 0x75, 0x0a, 0x01, 0x22, 0xe5, 0x0a, 0x64, 0x01, 0x70, 0x40, 0x30, 0x08,
-  0x39, 0xe5, 0x39, 0x70, 0x35, 0xc2, 0x08, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x2d}},
- {0x0886, 64, { 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0x9c, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82,
-  0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb, 0x90, 0x7f,
-  0xc3, 0x74, 0x09, 0xf0, 0x75, 0x39, 0x10, 0xe4, 0xf5, 0x35, 0x75, 0x0a, 0x02, 0x22, 0xe5, 0x0a,
-  0x64, 0x02, 0x70, 0x36, 0x30, 0x14, 0x2f, 0xc2, 0x14, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00}},
- {0x08c6, 64, { 0x74, 0x0e, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0x9c, 0xff, 0x74, 0x80, 0x25, 0x18,
-  0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x05, 0xdb,
-  0x90, 0x7f, 0xc3, 0x74, 0x05, 0xf0, 0x75, 0x0a, 0x03, 0x22, 0xe5, 0x15, 0x60, 0x30, 0x15, 0x15,
-  0xe4, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x14, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00}},
- {0x0906, 64, { 0xfa, 0x12, 0x0e, 0x9c, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef,
-  0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4, 0xf5,
-  0x0a, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x0e, 0xf4, 0x0a, 0x10, 0x00, 0x0a, 0x84, 0x01, 0x0a,
-  0xf0, 0x03, 0x09, 0x4c, 0x06, 0x0a, 0x03, 0x08, 0x09, 0xfd, 0x09, 0x09, 0xe5, 0x0a, 0x09}},
- {0x0946, 64, { 0xf4, 0x0b, 0x00, 0x00, 0x0b, 0x3f, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x19, 0x14, 0x60, 0x61,
-  0x24, 0x02, 0x60, 0x03, 0x02, 0x09, 0xdb, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90,
-  0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x04, 0x7f, 0x02, 0x80, 0x02,
-  0x7f, 0x03, 0x75, 0x82, 0x82, 0x75, 0x83, 0x19, 0xef, 0xf0, 0x75, 0x82, 0x7b, 0x75, 0x83}},
- {0x0986, 64, { 0x19, 0xf0, 0x75, 0x82, 0x74, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x66, 0x75, 0x83, 0x19, 0xf0, 0x75,
-  0x82, 0x58, 0x75, 0x83, 0x19, 0xf0, 0x90, 0x7f, 0xea, 0xe0, 0x04, 0x75, 0x82, 0x17, 0x75, 0x83,
-  0x19, 0xf0, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x12, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b,
-  0x46, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0f, 0x1a, 0xea, 0x49, 0x60, 0x0d, 0xea, 0x90}},
- {0x09c6, 64, { 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01,
-  0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f,
-  0x00, 0xe5, 0x09, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xea,
-  0xe0, 0xf5, 0x09, 0x02, 0x0b, 0x46, 0x12, 0x0b, 0x4e, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0x00}},
- {0x0a06, 64, { 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60,
-  0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2, 0x10, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff,
-  0xa2, 0x16, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74,
-  0x02, 0xf0, 0x02, 0x0b, 0x46, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5}},
- {0x0a46, 64, { 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f,
-  0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83,
-  0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0,
-  0x02, 0x0b, 0x46, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f}},
- {0x0a86, 64, { 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xea, 0xe0,
-  0xb4, 0x01, 0x05, 0xc2, 0x10, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02,
-  0x0b, 0x46, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff,
-  0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4}},
- {0x0ac6, 64, { 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54,
-  0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x5f,
-  0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60,
-  0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x10, 0x80}},
- {0x0b06, 64, { 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90,
-  0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25,
-  0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90,
-  0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0}},
- {0x0b46, 64, { 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74,
-  0x30, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0xc0, 0xf0, 0x90, 0x7f, 0x9e,
-  0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x18, 0xf0, 0xe4, 0xf5, 0x8e, 0x90, 0x7f, 0xdf, 0x74,
-  0xff, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0xe4, 0xf5, 0x24, 0x75, 0x18, 0x01, 0x7b, 0x00, 0x74}},
- {0x0b86, 64, { 0x24, 0x25, 0x18, 0xf9, 0xe4, 0x34, 0x00, 0xfa, 0xe4, 0x12, 0x0e, 0xe2, 0x05, 0x18, 0xe5, 0x18, 0xb4,
-  0x09, 0xea, 0x75, 0x3a, 0x01, 0xe4, 0xf5, 0x38, 0xf5, 0x13, 0xf5, 0x36, 0xc2, 0x07, 0xc2, 0x0b,
-  0xc2, 0x05, 0xc2, 0x00, 0xc2, 0x09, 0xc2, 0x13, 0xd2, 0x03, 0xd2, 0x01, 0x90, 0x7f, 0x98, 0x74,
-  0x13, 0xf0, 0x75, 0x44, 0x03, 0x90, 0xc0, 0x00, 0x74, 0x03, 0xf0, 0x7f, 0x0c, 0xe4, 0xfd}},
- {0x0bc6, 64, { 0x12, 0x11, 0xc8, 0x7f, 0x10, 0x8f, 0x42, 0x12, 0x10, 0x98, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x7f,
-  0x01, 0x8f, 0x40, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0,
-  0x75, 0x46, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0x0f, 0xe4, 0xfd, 0x12, 0x11, 0xc8, 0xe4,
-  0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3e, 0x12, 0x11, 0xc8, 0x90, 0x7f, 0x98, 0x74, 0x11}},
- {0x0c06, 64, { 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x11, 0xc8, 0x7f, 0x01, 0x12, 0x12,
-  0x81, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x11, 0xc8, 0x20, 0x1b, 0x03, 0x02, 0x0c, 0xc7, 0x75, 0x2d,
-  0x01, 0x75, 0x18, 0x01, 0x7b, 0x00, 0x74, 0x2d, 0x25, 0x18, 0xf9, 0xe4, 0x34, 0x00, 0xfa, 0xe4,
-  0x12, 0x0e, 0xe2, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xea, 0x75, 0x3b, 0x01, 0xe4, 0xf5}},
- {0x0c46, 64, { 0x39, 0xf5, 0x13, 0xf5, 0x37, 0xc2, 0x08, 0xc2, 0x0c, 0xc2, 0x06, 0xc2, 0x00, 0xc2, 0x0a, 0xc2, 0x13,
-  0xd2, 0x04, 0xd2, 0x02, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x75, 0x45, 0x03, 0x90, 0xc0, 0x00,
-  0x74, 0x03, 0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x12, 0x12, 0x7f, 0x10, 0x8f, 0x43, 0x12, 0x11,
-  0x0a, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x7f, 0x01, 0x8f, 0x41, 0xef, 0x44, 0x06, 0x90}},
- {0x0c86, 64, { 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x75, 0x47, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80,
-  0xf0, 0x0f, 0xe4, 0xfd, 0x12, 0x12, 0x12, 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3f, 0x12,
-  0x12, 0x12, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d,
-  0x7f, 0x12, 0x12, 0x12, 0x7f, 0x01, 0x12, 0x12, 0xa2, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x12}},
- {0x0cc6, 64, { 0x12, 0xd2, 0x12, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5,
-  0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86,
+ {0x0000,  3, { 0x02, 0x0e, 0x00}},
+ {0x0106, 64, { 0x60, 0x58, 0xb4, 0x80, 0x03, 0x43, 0x36, 0x02, 0xe5, 0x36, 0x30, 0xe7, 0x26, 0xe5, 0x19, 0xd3, 0x94,
+  0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08, 0x7e, 0x7e, 0x7f, 0x80, 0x75, 0x0c, 0x7e,
+  0x75, 0x0d, 0x80, 0xaf, 0x36, 0x12, 0x0f, 0x4b, 0xe5, 0x19, 0x25, 0xe0, 0x90, 0x7f, 0xb7, 0xf0,
+  0x80, 0x27, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75, 0x19, 0x3f, 0x85, 0x19, 0x08}},
+ {0x0146, 64, { 0x90, 0x7e, 0x80, 0xe5, 0x36, 0xf0, 0x7e, 0x7e, 0x7f, 0x81, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x81, 0x12,
+  0x0c, 0xdf, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xb7, 0xf0, 0x90, 0x7f, 0xce, 0xe0, 0x30, 0xe1, 0x06,
+  0x20, 0x05, 0x03, 0x02, 0x03, 0xc1, 0xc2, 0x05, 0xe4, 0xf5, 0x18, 0x74, 0x40, 0x25, 0x18, 0xf5,
+  0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18, 0x7c, 0x00, 0x7b, 0x01, 0x7a}},
+ {0x0186, 64, { 0x7e, 0x79, 0x00, 0x24, 0x00, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef, 0x12, 0x0e, 0xd2, 0x05, 0x18, 0xe5,
+  0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x00, 0xe0, 0x60, 0x68, 0x90, 0x7e, 0x03, 0xe0, 0x60, 0x24,
+  0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x11, 0xb1, 0x7f, 0x03, 0x7d, 0xcd, 0x12, 0x11, 0xb1, 0x43, 0x46,
+  0x80, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0xe4, 0x90}},
+ {0x01c6, 64, { 0x7e, 0x13, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x01, 0xe0, 0xff, 0x12, 0x10, 0x35, 0x90, 0x7e, 0x02, 0xe0,
+  0xff, 0x12, 0x10, 0x5b, 0x7f, 0x01, 0x90, 0x7e, 0x11, 0xe0, 0xfd, 0x12, 0x11, 0xb1, 0x7f, 0x03,
+  0x7d, 0x07, 0x12, 0x11, 0xb1, 0x43, 0x46, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0,
+  0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40, 0x44, 0x06, 0x90}},
+ {0x0206, 64, { 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x03, 0xe0, 0x70, 0x06, 0x90, 0x7e, 0x13, 0xe0, 0x70, 0x08, 0xe4, 0x90,
+  0x7e, 0x13, 0xf0, 0x75, 0x25, 0xff, 0x90, 0x7e, 0x05, 0xe0, 0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f,
+  0xf5, 0x44, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x44, 0xf0, 0x90, 0x7e,
+  0x07, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x42, 0x80, 0x80, 0x03, 0x53, 0x42}},
+ {0x0246, 64, { 0x7f, 0x53, 0x42, 0xfc, 0x90, 0x7e, 0x09, 0xe0, 0x60, 0x11, 0x43, 0x42, 0x02, 0xa3, 0xe0, 0xff, 0x12,
+  0x10, 0xa7, 0x90, 0x7e, 0x0b, 0xe0, 0xff, 0x12, 0x10, 0xcd, 0xaf, 0x42, 0x12, 0x10, 0x81, 0x90,
+  0x7e, 0x03, 0xe0, 0x60, 0x08, 0x53, 0x42, 0x7f, 0xaf, 0x42, 0x12, 0x10, 0x81, 0x90, 0x7e, 0x0c,
+  0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x02, 0x80, 0x03, 0x53, 0x46, 0xfd}},
+ {0x0286, 64, { 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x0e, 0xe0, 0x60,
+  0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x01, 0x80, 0x03, 0x53, 0x46, 0xfe, 0x90, 0x7f, 0x98,
+  0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x12, 0xe0, 0xf5, 0x3a, 0xa3,
+  0xe0, 0x13, 0x92, 0x0d, 0xa3, 0xe0, 0xf5, 0x3c, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x10}},
+ {0x02c6, 64, { 0x80, 0x03, 0x53, 0x46, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0,
+  0x90, 0x7e, 0x16, 0xe0, 0x60, 0x32, 0x53, 0x44, 0xbf, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5,
+  0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x12, 0x12, 0xdf,
+  0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3e, 0xfd, 0xe4, 0xff, 0xad, 0x3e, 0x12}},
+ {0x0306, 64, { 0x11, 0xb1, 0xe4, 0xf5, 0x2a, 0xf5, 0x29, 0xd2, 0x07, 0x90, 0x7e, 0x17, 0xe0, 0x60, 0x0f, 0x43, 0x3e,
+  0x02, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xb1, 0x75, 0x29, 0x01, 0xd2, 0x07, 0x90, 0x7e, 0x18,
+  0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40, 0x44, 0x04, 0x90, 0xc0, 0x00,
+  0xf0, 0xd2, 0x00, 0x90, 0x7e, 0x19, 0xe0, 0x60, 0x11, 0x43, 0x44, 0x40, 0x90, 0x7f, 0x98}},
+ {0x0346, 64, { 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1a, 0xe0, 0x60, 0x0f,
+  0x53, 0x3e, 0xfe, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xb1, 0x75, 0x2b, 0x01, 0xd2, 0x07, 0x90,
+  0x7e, 0x1b, 0xe0, 0x60, 0x0f, 0x43, 0x3e, 0x01, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xb1, 0xe4,
+  0xf5, 0x2b, 0xd2, 0x07, 0x90, 0x7e, 0x1c, 0xe0, 0x60, 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x12}},
+ {0x0386, 64, { 0xf0, 0xe5, 0x40, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1d, 0xe0, 0x60, 0x02, 0xd2, 0x0b,
+  0x90, 0x7e, 0x1e, 0xe0, 0x60, 0x08, 0x75, 0x2c, 0x01, 0xe4, 0xf5, 0x38, 0xd2, 0x07, 0x90, 0x7e,
+  0x1f, 0xe0, 0x60, 0x11, 0x90, 0x7f, 0xd7, 0x74, 0x11, 0xf0, 0x74, 0x31, 0xf0, 0x74, 0x15, 0xf0,
+  0x74, 0x35, 0xf0, 0xd2, 0x03, 0xe4, 0x90, 0x7f, 0xcf, 0xf0, 0x30, 0x1a, 0x52, 0xe5, 0x38}},
+ {0x03c6, 64, { 0x60, 0x02, 0x15, 0x38, 0x20, 0x13, 0x49, 0xe5, 0x13, 0xd3, 0x94, 0x00, 0x40, 0x04, 0x15, 0x13, 0x80,
+  0x3e, 0x75, 0x13, 0x0a, 0x30, 0x1b, 0x02, 0xd2, 0x13, 0x12, 0x12, 0xdf, 0xef, 0x54, 0x01, 0xf5,
+  0x19, 0x65, 0x2a, 0x60, 0x05, 0x85, 0x19, 0x2a, 0xd2, 0x07, 0x12, 0x13, 0x33, 0xef, 0x54, 0x80,
+  0xf5, 0x19, 0x65, 0x26, 0x60, 0x05, 0x85, 0x19, 0x26, 0xd2, 0x07, 0x30, 0x0d, 0x11, 0x12}},
+ {0x0406, 64, { 0x13, 0x33, 0xef, 0x54, 0x10, 0xf5, 0x19, 0x65, 0x25, 0x60, 0x05, 0x85, 0x19, 0x25, 0xd2, 0x07, 0x20,
+  0x1b, 0x03, 0x02, 0x07, 0xec, 0x30, 0x0a, 0x18, 0x12, 0x13, 0x6f, 0xef, 0xc3, 0x95, 0x3d, 0x40,
+  0x03, 0x02, 0x04, 0xae, 0x90, 0x7f, 0xc1, 0x74, 0x01, 0xf0, 0xc2, 0x0a, 0xc2, 0x00, 0x80, 0x77,
+  0x30, 0x04, 0x3b, 0x90, 0x7f, 0xca, 0xe0, 0x20, 0xe1, 0x6d, 0x12, 0x13, 0x6f, 0xef, 0xc3}},
+ {0x0446, 64, { 0x94, 0x40, 0x50, 0x64, 0x90, 0x7d, 0x40, 0xe0, 0x13, 0x92, 0x0a, 0x90, 0x7f, 0xcb, 0xe0, 0x14, 0xf5,
+  0x19, 0x20, 0x00, 0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7d, 0x7f, 0x41, 0x75, 0x0c, 0x7d, 0x75,
+  0x0d, 0x41, 0x12, 0x0d, 0x04, 0xc2, 0x04, 0xe4, 0x90, 0x7f, 0xcb, 0xf0, 0x80, 0x39, 0x90, 0x7f,
+  0xcc, 0xe0, 0x20, 0xe1, 0x32, 0x12, 0x13, 0x6f, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x29, 0x90}},
+ {0x0486, 64, { 0x7c, 0xc0, 0xe0, 0x13, 0x92, 0x0a, 0x90, 0x7f, 0xcd, 0xe0, 0x14, 0xf5, 0x19, 0x20, 0x00, 0x11, 0x60,
+  0x0f, 0xf5, 0x08, 0x7e, 0x7c, 0x7f, 0xc1, 0x75, 0x0c, 0x7c, 0x75, 0x0d, 0xc1, 0x12, 0x0d, 0x04,
+  0xd2, 0x04, 0xe4, 0x90, 0x7f, 0xcd, 0xf0, 0x90, 0x7f, 0xba, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x05,
+  0x36, 0x12, 0x12, 0x20, 0x8f, 0x19, 0x12, 0x13, 0x7b, 0x8f, 0x37, 0xe5, 0x19, 0xc3, 0x95}},
+ {0x04c6, 64, { 0x3b, 0x50, 0x0f, 0x12, 0x13, 0x57, 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x37, 0x20, 0xe7, 0x03, 0x30, 0x0c,
+  0x5e, 0xc2, 0x0c, 0xe5, 0x19, 0x60, 0x58, 0xb4, 0x80, 0x03, 0x43, 0x37, 0x02, 0xe5, 0x37, 0x30,
+  0xe7, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08, 0x7e,
+  0x7d, 0x7f, 0x80, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0x80, 0xaf, 0x37, 0x12, 0x0f, 0x84, 0xe5}},
+ {0x0506, 64, { 0x19, 0x25, 0xe0, 0x90, 0x7f, 0xbb, 0xf0, 0x80, 0x27, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75,
+  0x19, 0x3f, 0x85, 0x19, 0x08, 0x90, 0x7d, 0x80, 0xe5, 0x37, 0xf0, 0x7e, 0x7d, 0x7f, 0x81, 0x75,
+  0x0c, 0x7d, 0x75, 0x0d, 0x81, 0x12, 0x0d, 0x29, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xbb, 0xf0, 0x90,
+  0x7f, 0xd0, 0xe0, 0x30, 0xe1, 0x06, 0x20, 0x06, 0x03, 0x02, 0x07, 0x97, 0xc2, 0x06, 0xe4}},
+ {0x0546, 64, { 0xf5, 0x18, 0x74, 0xc0, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18,
+  0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e, 0x79, 0x20, 0x24, 0x20, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef,
+  0x12, 0x0e, 0xd2, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x20, 0xe0, 0x60, 0x68,
+  0x90, 0x7e, 0x23, 0xe0, 0x60, 0x24, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x11, 0xfb, 0x7f, 0x03}},
+ {0x0586, 64, { 0x7d, 0xcd, 0x12, 0x11, 0xfb, 0x43, 0x47, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00,
+  0xe5, 0x47, 0xf0, 0xe4, 0x90, 0x7e, 0x33, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x21, 0xe0, 0xff, 0x12,
+  0x11, 0x19, 0x90, 0x7e, 0x22, 0xe0, 0xff, 0x12, 0x11, 0x3f, 0x7f, 0x01, 0x90, 0x7e, 0x31, 0xe0,
+  0xfd, 0x12, 0x11, 0xfb, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x11, 0xfb, 0x43, 0x47, 0x80, 0x90}},
+ {0x05c6, 64, { 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0,
+  0xe5, 0x41, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x23, 0xe0, 0x70, 0x06, 0x90, 0x7e,
+  0x33, 0xe0, 0x70, 0x08, 0xe4, 0x90, 0x7e, 0x33, 0xf0, 0x75, 0x2e, 0xff, 0x90, 0x7e, 0x25, 0xe0,
+  0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f, 0xf5, 0x45, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90}},
+ {0x0606, 64, { 0xc0, 0x00, 0xe5, 0x45, 0xf0, 0x90, 0x7e, 0x27, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x43,
+  0x80, 0x80, 0x03, 0x53, 0x43, 0x7f, 0x53, 0x43, 0xfc, 0x90, 0x7e, 0x29, 0xe0, 0x60, 0x11, 0x43,
+  0x43, 0x02, 0xa3, 0xe0, 0xff, 0x12, 0x11, 0x65, 0x90, 0x7e, 0x2b, 0xe0, 0xff, 0x12, 0x11, 0x8b,
+  0xaf, 0x43, 0x12, 0x10, 0xf3, 0x90, 0x7e, 0x23, 0xe0, 0x60, 0x08, 0x53, 0x43, 0x7f, 0xaf}},
+ {0x0646, 64, { 0x43, 0x12, 0x10, 0xf3, 0x90, 0x7e, 0x2c, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x02,
+  0x80, 0x03, 0x53, 0x47, 0xfd, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47,
+  0xf0, 0x90, 0x7e, 0x2e, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x01, 0x80, 0x03,
+  0x53, 0x47, 0xfe, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0}},
+ {0x0686, 64, { 0x90, 0x7e, 0x32, 0xe0, 0xf5, 0x3b, 0xa3, 0xe0, 0x13, 0x92, 0x0e, 0xa3, 0xe0, 0xf5, 0x3d, 0xa3, 0xe0,
+  0x60, 0x05, 0x43, 0x47, 0x10, 0x80, 0x03, 0x53, 0x47, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0,
+  0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7e, 0x36, 0xe0, 0x60, 0x32, 0x53, 0x45, 0xbf, 0x90,
+  0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f}},
+ {0x06c6, 64, { 0x98, 0x74, 0x09, 0xf0, 0x12, 0x13, 0x4b, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3f, 0xfd,
+  0xe4, 0xff, 0xad, 0x3f, 0x12, 0x11, 0xfb, 0xe4, 0xf5, 0x33, 0xf5, 0x32, 0xd2, 0x08, 0x90, 0x7e,
+  0x37, 0xe0, 0x60, 0x0f, 0x43, 0x3f, 0x02, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x11, 0xfb, 0x75, 0x32,
+  0x01, 0xd2, 0x08, 0x90, 0x7e, 0x38, 0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0}},
+ {0x0706, 64, { 0xe5, 0x41, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0, 0xd2, 0x00, 0x90, 0x7e, 0x39, 0xe0, 0x60, 0x11, 0x43,
+  0x45, 0x40, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0,
+  0x90, 0x7e, 0x3a, 0xe0, 0x60, 0x0f, 0x53, 0x3f, 0xfe, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x11, 0xfb,
+  0x75, 0x34, 0x01, 0xd2, 0x08, 0x90, 0x7e, 0x3b, 0xe0, 0x60, 0x0f, 0x43, 0x3f, 0x01, 0xe4}},
+ {0x0746, 64, { 0xff, 0xad, 0x3f, 0x12, 0x11, 0xfb, 0xe4, 0xf5, 0x34, 0xd2, 0x08, 0x90, 0x7e, 0x3c, 0xe0, 0x60, 0x0e,
+  0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0xe5, 0x41, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e,
+  0x3d, 0xe0, 0x60, 0x02, 0xd2, 0x0c, 0x90, 0x7e, 0x3e, 0xe0, 0x60, 0x08, 0x75, 0x35, 0x01, 0xe4,
+  0xf5, 0x39, 0xd2, 0x08, 0x90, 0x7e, 0x3f, 0xe0, 0x60, 0x11, 0x90, 0x7f, 0xd7, 0x74, 0x13}},
+ {0x0786, 64, { 0xf0, 0x74, 0x33, 0xf0, 0x74, 0x16, 0xf0, 0x74, 0x36, 0xf0, 0xd2, 0x04, 0xe4, 0x90, 0x7f, 0xd1, 0xf0,
+  0x30, 0x1a, 0x52, 0xe5, 0x39, 0x60, 0x02, 0x15, 0x39, 0x30, 0x13, 0x49, 0xe5, 0x13, 0xd3, 0x94,
+  0x00, 0x40, 0x04, 0x15, 0x13, 0x80, 0x3e, 0x75, 0x13, 0x0a, 0x30, 0x1b, 0x02, 0xc2, 0x13, 0x12,
+  0x13, 0x4b, 0xef, 0x54, 0x01, 0xf5, 0x19, 0x65, 0x33, 0x60, 0x05, 0x85, 0x19, 0x33, 0xd2}},
+ {0x07c6, 64, { 0x08, 0x12, 0x13, 0x87, 0xef, 0x54, 0x80, 0xf5, 0x19, 0x65, 0x2f, 0x60, 0x05, 0x85, 0x19, 0x2f, 0xd2,
+  0x08, 0x30, 0x0e, 0x11, 0x12, 0x13, 0x87, 0xef, 0x54, 0x10, 0xf5, 0x19, 0x65, 0x2e, 0x60, 0x05,
+  0x85, 0x19, 0x2e, 0xd2, 0x08, 0x30, 0x1a, 0x2a, 0x90, 0x7f, 0xd2, 0xe0, 0x20, 0xe1, 0x23, 0x90,
+  0x7b, 0x40, 0xe0, 0x60, 0x09, 0xe0, 0xf5, 0x15, 0x90, 0x7b, 0x42, 0xe0, 0xf5, 0x16, 0x90}},
+ {0x0806, 64, { 0x7b, 0x41, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7, 0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0xe4, 0x90, 0x7f,
+  0xd3, 0xf0, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x09, 0x20, 0xe5, 0x0a, 0x70, 0x40,
+  0x30, 0x07, 0x39, 0xe5, 0x38, 0x70, 0x35, 0xc2, 0x07, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74,
+  0x24, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0x8c, 0xff, 0x74, 0x80, 0x25}},
+ {0x0846, 64, { 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb,
+  0x90, 0x7f, 0xc3, 0x74, 0x09, 0xf0, 0x75, 0x38, 0x10, 0xe4, 0xf5, 0x2c, 0x75, 0x0a, 0x01, 0x22,
+  0xe5, 0x0a, 0x64, 0x01, 0x70, 0x40, 0x30, 0x08, 0x39, 0xe5, 0x39, 0x70, 0x35, 0xc2, 0x08, 0xf5,
+  0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x2d, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12}},
+ {0x0886, 64, { 0x0e, 0x8c, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05,
+  0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x09, 0xf0, 0x75, 0x39, 0x10, 0xe4,
+  0xf5, 0x35, 0x75, 0x0a, 0x02, 0x22, 0xe5, 0x0a, 0x64, 0x02, 0x70, 0x36, 0x30, 0x14, 0x2f, 0xc2,
+  0x14, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x0e, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00}},
+ {0x08c6, 64, { 0xfa, 0x12, 0x0e, 0x8c, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef,
+  0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x05, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x05, 0xf0, 0x75, 0x0a,
+  0x03, 0x22, 0xe5, 0x15, 0x60, 0x30, 0x15, 0x15, 0xe4, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74,
+  0x14, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0x8c, 0xff, 0x74, 0x80, 0x25}},
+ {0x0906, 64, { 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x03, 0xdb,
+  0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4, 0xf5, 0x0a, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x0e,
+  0xe4, 0x0a, 0x08, 0x00, 0x0a, 0x7c, 0x01, 0x0a, 0xe8, 0x03, 0x09, 0x44, 0x06, 0x09, 0xfb, 0x08,
+  0x09, 0xf5, 0x09, 0x09, 0xdd, 0x0a, 0x09, 0xec, 0x0b, 0x00, 0x00, 0x0b, 0x37, 0x90, 0x7f}},
+ {0x0946, 64, { 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x19, 0x14, 0x60, 0x61, 0x24, 0x02, 0x60, 0x03, 0x02, 0x09, 0xd3, 0x74,
+  0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f,
+  0xea, 0xe0, 0x70, 0x04, 0x7f, 0x02, 0x80, 0x02, 0x7f, 0x03, 0x75, 0x82, 0x82, 0x75, 0x83, 0x19,
+  0xef, 0xf0, 0x75, 0x82, 0x7b, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x74, 0x75, 0x83, 0x19}},
+ {0x0986, 64, { 0xf0, 0x75, 0x82, 0x66, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x58, 0x75, 0x83, 0x19, 0xf0, 0x90, 0x7f,
+  0xea, 0xe0, 0x04, 0x75, 0x82, 0x17, 0x75, 0x83, 0x19, 0xf0, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0,
+  0x74, 0x12, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0f,
+  0x0a, 0xea, 0x49, 0x60, 0x0d, 0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0}},
+ {0x09c6, 64, { 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xb4, 0xe0,
+  0x44, 0x01, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0x00, 0xe5, 0x09, 0xf0, 0x90, 0x7f, 0xb5, 0x74,
+  0x01, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x09, 0x02, 0x0b, 0x3e, 0x12, 0x0b,
+  0x46, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02}},
+ {0x0a06, 64, { 0x0b, 0x3e, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b,
+  0xa2, 0x10, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x16, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00,
+  0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x3e, 0xe4, 0x90, 0x7f,
+  0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f}},
+ {0x0a46, 64, { 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24,
+  0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4,
+  0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xb4, 0xe0, 0x44,
+  0x01, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02}},
+ {0x0a86, 64, { 0x60, 0x03, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x10, 0x02, 0x0b, 0x3e,
+  0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38,
+  0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f,
+  0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f}},
+ {0x0ac6, 64, { 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f,
+  0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80,
+  0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea,
+  0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x10, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0}},
+ {0x0b06, 64, { 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4,
+  0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f,
+  0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07,
+  0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22}},
+ {0x0b46, 64, { 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0, 0x90,
+  0x7f, 0x95, 0x74, 0xc0, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x18,
+  0xf0, 0xe4, 0xf5, 0x8e, 0x90, 0x7f, 0xdf, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0xe4, 0xf5,
+  0x24, 0x75, 0x18, 0x01, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x18, 0xf9, 0xe4, 0x34, 0x00, 0xfa}},
+ {0x0b86, 64, { 0xe4, 0x12, 0x0e, 0xd2, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xea, 0x75, 0x3a, 0x01, 0xe4, 0xf5, 0x38,
+  0xf5, 0x13, 0xf5, 0x36, 0xc2, 0x07, 0xc2, 0x0b, 0xc2, 0x05, 0xc2, 0x00, 0xc2, 0x09, 0xc2, 0x13,
+  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x75, 0x44, 0x03, 0x90, 0xc0, 0x00, 0x74, 0x03, 0xf0, 0x7f,
+  0x0c, 0xe4, 0xfd, 0x12, 0x11, 0xb1, 0x7f, 0x10, 0x8f, 0x42, 0x12, 0x10, 0x81, 0x90, 0x7f}},
+ {0x0bc6, 64, { 0x98, 0x74, 0x12, 0xf0, 0x7f, 0x01, 0x8f, 0x40, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f,
+  0x98, 0x74, 0x14, 0xf0, 0x75, 0x46, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0x0f, 0xe4, 0xfd,
+  0x12, 0x11, 0xb1, 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3e, 0x12, 0x11, 0xb1, 0x90, 0x7f,
+  0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x11}},
+ {0x0c06, 64, { 0xb1, 0x7f, 0x01, 0x12, 0x12, 0x6a, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x11, 0xb1, 0x20, 0x1b, 0x03, 0x02,
+  0x0c, 0xb7, 0x75, 0x2d, 0x01, 0x75, 0x18, 0x01, 0x7b, 0x00, 0x74, 0x2d, 0x25, 0x18, 0xf9, 0xe4,
+  0x34, 0x00, 0xfa, 0xe4, 0x12, 0x0e, 0xd2, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xea, 0x75, 0x3b,
+  0x01, 0xe4, 0xf5, 0x39, 0xf5, 0x13, 0xf5, 0x37, 0xc2, 0x08, 0xc2, 0x0c, 0xc2, 0x06, 0xc2}},
+ {0x0c46, 64, { 0x00, 0xc2, 0x0a, 0xc2, 0x13, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x75, 0x45, 0x03, 0x90, 0xc0, 0x00,
+  0x74, 0x03, 0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x11, 0xfb, 0x7f, 0x10, 0x8f, 0x43, 0x12, 0x10,
+  0xf3, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x7f, 0x01, 0x8f, 0x41, 0xef, 0x44, 0x06, 0x90, 0xc0,
+  0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x75, 0x47, 0x80, 0x90, 0xc0, 0x00, 0x74}},
+ {0x0c86, 64, { 0x80, 0xf0, 0x0f, 0xe4, 0xfd, 0x12, 0x11, 0xfb, 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3f, 0x12,
+  0x11, 0xfb, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d,
+  0x7f, 0x12, 0x11, 0xfb, 0x7f, 0x01, 0x12, 0x12, 0x8b, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x11, 0xfb,
+  0xd2, 0x12, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82}},
+ {0x0cc6, 64, { 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86,
   0xf0, 0x05, 0x86, 0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x08,
-  0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00}},
- {0x0d06, 64, { 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98,
-  0x74, 0x08, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05,
+  0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0,
+  0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x90, 0x7f}},
+ {0x0d06, 64, { 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05,
   0x86, 0x90, 0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05, 0x86, 0xdf, 0xf7, 0xd2,
-  0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5}},
- {0x0d46, 64, { 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86,
-  0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05,
+  0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c,
+  0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05}},
+ {0x0d46, 64, { 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05,
   0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43,
-  0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xd2, 0x19, 0x90, 0x7f, 0x92, 0xe0, 0x44}},
- {0x0d86, 64, { 0x02, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92, 0x10, 0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0, 0xd2,
-  0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f,
+  0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xd2, 0x19, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02,
+  0xf0, 0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92, 0x10, 0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0}},
+ {0x0d86, 64, { 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f,
   0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90,
-  0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x0d, 0xf0, 0xd2, 0xaf}},
- {0x0dc6, 64, { 0xd2, 0x1a, 0x12, 0x12, 0x5c, 0xc2, 0x11, 0xe4, 0xf5, 0x0b, 0xf5, 0x13, 0xc2, 0x17, 0xc2, 0x12, 0x90,
-  0x7f, 0xa1, 0x04, 0xf0, 0x90, 0x7f, 0xd8, 0xe0, 0x65, 0x17, 0x60, 0x10, 0x30, 0x12, 0x05, 0xd2,
+  0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2,
+  0x1a, 0x12, 0x12, 0x45, 0xc2, 0x11, 0xe4, 0xf5, 0x0b, 0xf5, 0x13, 0xc2, 0x17, 0xc2, 0x12}},
+ {0x0dc6, 64, { 0x90, 0x7f, 0xa1, 0x04, 0xf0, 0x90, 0x7f, 0xd8, 0xe0, 0x65, 0x17, 0x60, 0x10, 0x30, 0x12, 0x05, 0xd2,
   0x1a, 0x12, 0x00, 0x46, 0x90, 0x7f, 0xd8, 0xe0, 0xf5, 0x17, 0x80, 0x08, 0x30, 0x12, 0x05, 0xc2,
-  0x1a, 0x12, 0x00, 0x46, 0x30, 0x11, 0x07, 0xc2, 0x11, 0x12, 0x09, 0x29, 0x80, 0xd6, 0x30}},
- {0x0e06, 64, { 0x18, 0xd3, 0xc2, 0x18, 0x12, 0x12, 0xf6, 0x80, 0xcc, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75,
-  0x81, 0x47, 0x02, 0x0e, 0x57, 0x02, 0x0d, 0x7f, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40,
+  0x1a, 0x12, 0x00, 0x46, 0x30, 0x11, 0x07, 0xc2, 0x11, 0x12, 0x09, 0x21, 0x80, 0xd6, 0x30, 0x18,
+  0xd3, 0xc2, 0x18, 0x12, 0x13, 0x93, 0x80, 0xcc, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd}},
+ {0x0e06, 64, { 0x75, 0x81, 0x47, 0x02, 0x0e, 0x47, 0x02, 0x0d, 0x6f, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40,
   0x03, 0xf6, 0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07,
-  0x24, 0x0c, 0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4}},
- {0x0e46, 64, { 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
-  0x90, 0x12, 0xc3, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09,
+  0x24, 0x0c, 0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56,
+  0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40}},
+ {0x0e46, 64, { 0x80, 0x90, 0x12, 0xac, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09,
   0x54, 0x1f, 0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8,
-  0x40, 0xb8, 0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5}},
- {0x0e86, 64, { 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf,
-  0xe9, 0xde, 0xe7, 0x80, 0xbe, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02,
+  0x40, 0xb8, 0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82,
+  0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca}},
+ {0x0e86, 64, { 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02,
   0xe7, 0x22, 0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01,
-  0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06}},
- {0x0ec6, 64, { 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82,
-  0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82,
+  0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9,
+  0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5}},
+ {0x0ec6, 64, { 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82,
   0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xd0, 0x83, 0xd0,
-  0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8}},
- {0x0f06, 64, { 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3,
-  0xa3, 0x80, 0xdf, 0x8f, 0x18, 0xe4, 0xf5, 0x19, 0x75, 0x1a, 0xff, 0x75, 0x1b, 0x19, 0x75, 0x1c,
-  0x86, 0xab, 0x1a, 0xaa, 0x1b, 0xa9, 0x1c, 0x90, 0x00, 0x01, 0x12, 0x0e, 0xb5, 0xb4, 0x03, 0x1d,
-  0xaf, 0x19, 0x05, 0x19, 0xef, 0xb5, 0x18, 0x01, 0x22, 0x12, 0x0e, 0x9c, 0x7e, 0x00, 0x29}},
- {0x0f46, 64, { 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75, 0x1a, 0xff, 0xf5, 0x1b, 0x89, 0x1c, 0x80, 0xd4, 0x7b, 0x00, 0x7a,
-  0x00, 0x79, 0x00, 0x22, 0x8f, 0x1a, 0x05, 0x0d, 0xe5, 0x0d, 0xae, 0x0c, 0x70, 0x02, 0x05, 0x0c,
+  0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74,
+  0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3}},
+ {0x0f06, 64, { 0xa3, 0xa3, 0x80, 0xdf, 0x8f, 0x18, 0xe4, 0xf5, 0x19, 0x75, 0x1a, 0xff, 0x75, 0x1b, 0x19, 0x75, 0x1c,
+  0x86, 0xab, 0x1a, 0xaa, 0x1b, 0xa9, 0x1c, 0x90, 0x00, 0x01, 0x12, 0x0e, 0xa5, 0xb4, 0x03, 0x1d,
+  0xaf, 0x19, 0x05, 0x19, 0xef, 0xb5, 0x18, 0x01, 0x22, 0x12, 0x0e, 0x8c, 0x7e, 0x00, 0x29, 0xff,
+  0xee, 0x3a, 0xa9, 0x07, 0x75, 0x1a, 0xff, 0xf5, 0x1b, 0x89, 0x1c, 0x80, 0xd4, 0x7b, 0x00}},
+ {0x0f46, 64, { 0x7a, 0x00, 0x79, 0x00, 0x22, 0x8f, 0x1a, 0x05, 0x0d, 0xe5, 0x0d, 0xae, 0x0c, 0x70, 0x02, 0x05, 0x0c,
   0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x1a, 0xf0, 0x12, 0x00, 0x36, 0x05, 0x0d, 0xe5, 0x0d, 0xac,
-  0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5}},
- {0x0f86, 64, { 0x08, 0x60, 0x0a, 0x12, 0x13, 0x3f, 0x8f, 0x1a, 0xef, 0x42, 0x36, 0x80, 0xca, 0x22, 0x8f, 0x1a, 0x05,
-  0x0d, 0xe5, 0x0d, 0xae, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x1a,
-  0xf0, 0x12, 0x13, 0x57, 0x05, 0x0d, 0xe5, 0x0d, 0xac, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5,
-  0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x0a, 0x12, 0x13, 0x93, 0x8f}},
- {0x0fc6, 64, { 0x1a, 0xef, 0x42, 0x37, 0x80, 0xca, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84,
-  0xc0, 0x86, 0x75, 0x86, 0x00, 0x30, 0x15, 0x04, 0xc2, 0x15, 0x80, 0x02, 0xd2, 0x18, 0x53, 0x91,
-  0xef, 0x90, 0x7f, 0xab, 0x74, 0x08, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0,
-  0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0}},
- {0x1006, 64, { 0x86, 0x75, 0x86, 0x00, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04,
-  0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0,
-  0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x11, 0x53,
-  0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0}},
- {0x1046, 64, { 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf,
-  0xf0, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74,
-  0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13,
-  0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0}},
- {0x1086, 64, { 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0,
-  0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98,
-  0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44,
-  0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0}},
- {0x10c6, 64, { 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f,
-  0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98,
-  0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90,
-  0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90}},
- {0x1106, 64, { 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90,
-  0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0,
-  0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90,
-  0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0x90, 0xc0, 0x00, 0xef}},
- {0x1146, 64, { 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90,
-  0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x09,
-  0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f,
-  0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74}},
- {0x1186, 64, { 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74,
-  0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b,
-  0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0e, 0xf0, 0x90, 0xc0, 0x00,
-  0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00}},
- {0x11c6, 64, { 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90,
-  0x7f, 0x98, 0x74, 0x17, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0,
-  0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22, 0x12, 0x13, 0x27, 0x8f, 0x1a, 0x12, 0x13, 0x27, 0x8f, 0x1b,
-  0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x12, 0x12, 0x13, 0x27, 0x8f, 0x1a, 0xe5, 0x1a, 0x65, 0x1b}},
- {0x1206, 64, { 0x60, 0x07, 0x12, 0x13, 0x27, 0x8f, 0x1b, 0x80, 0xe8, 0xaf, 0x1a, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b,
-  0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0f, 0xf0, 0x90,
-  0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22,
-  0x12, 0x13, 0x7b, 0x8f, 0x1a, 0x12, 0x13, 0x7b, 0x8f, 0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60}},
- {0x1246, 64, { 0x12, 0x12, 0x13, 0x7b, 0x8f, 0x1a, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x07, 0x12, 0x13, 0x7b, 0x8f, 0x1b,
-  0x80, 0xe8, 0xaf, 0x1a, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0,
-  0x30, 0x1a, 0x04, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x12, 0xdf, 0x90, 0x7f,
-  0xd6, 0xe0, 0x54, 0xf7, 0xf0, 0xe0, 0x44, 0x04, 0xf0, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5}},
- {0x1286, 64, { 0x3e, 0x54, 0x7f, 0xfd, 0x12, 0x11, 0xc8, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xee,
-  0xf0, 0xe4, 0xe5, 0x3e, 0x44, 0x80, 0xfd, 0x12, 0x11, 0xc8, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5,
-  0x3f, 0x54, 0x7f, 0xfd, 0x12, 0x12, 0x12, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00,
-  0xee, 0xf0, 0xe4, 0xe5, 0x3f, 0x44, 0x80, 0xfd, 0x12, 0x12, 0x12, 0x22, 0x05, 0x0e, 0x02}},
- {0x12c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x03, 0x14, 0x03, 0x00, 0x00, 0xc1, 0x11, 0xc1, 0x18, 0xc1, 0x95, 0xc1, 0x10,
-  0xc1, 0x16, 0x01, 0x0a, 0x00, 0xc1, 0x1b, 0x00, 0x8e, 0x18, 0x8f, 0x19, 0xe5, 0x19, 0x15, 0x19,
-  0xae, 0x18, 0x70, 0x02, 0x15, 0x18, 0x4e, 0x60, 0x05, 0x12, 0x0d, 0x5e, 0x80, 0xee, 0x22, 0x12,
-  0x00, 0x03, 0x12, 0x0d, 0x6f, 0x12, 0x0b, 0x4e, 0x22, 0x02, 0x10, 0x25, 0x00, 0x02, 0x13}},
- {0x1306, 64, { 0x04, 0x00, 0x02, 0x0f, 0xfb, 0x00, 0x02, 0x0f, 0xcd, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0,
+  0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08,
+  0x60, 0x0a, 0x12, 0x13, 0x27, 0x8f, 0x1a, 0xef, 0x42, 0x36, 0x80, 0xca, 0x22, 0x8f, 0x1a}},
+ {0x0f86, 64, { 0x05, 0x0d, 0xe5, 0x0d, 0xae, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x1a,
+  0xf0, 0x12, 0x13, 0x3f, 0x05, 0x0d, 0xe5, 0x0d, 0xac, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5,
+  0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x0a, 0x12, 0x13, 0x7b, 0x8f, 0x1a,
+  0xef, 0x42, 0x37, 0x80, 0xca, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0}},
+ {0x0fc6, 64, { 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab,
+  0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32,
+  0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2,
+  0x11, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0}},
+ {0x1006, 64, { 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0,
+  0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x18, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08,
+  0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7f,
+  0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x10}},
+ {0x1046, 64, { 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90,
+  0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0,
+  0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13,
+  0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13}},
+ {0x1086, 64, { 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00, 0xef,
+  0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22,
+  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74,
+  0x14, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44}},
+ {0x10c6, 64, { 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74,
+  0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98,
+  0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74,
+  0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x90}},
+ {0x1106, 64, { 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00,
+  0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f,
+  0x98, 0x74, 0x08, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5,
+  0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90}},
+ {0x1146, 64, { 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90,
+  0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f,
+  0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0,
+  0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f}},
+ {0x1186, 64, { 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0,
+  0x90, 0x7f, 0x98, 0x74, 0x0e, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b,
+  0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0,
+  0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x17, 0xf0, 0x90}},
+ {0x11c6, 64, { 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22, 0x12,
+  0x13, 0x0f, 0x8f, 0x1a, 0x12, 0x13, 0x0f, 0x8f, 0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x12, 0x12,
+  0x13, 0x0f, 0x8f, 0x1a, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x07, 0x12, 0x13, 0x0f, 0x8f, 0x1b, 0x80,
+  0xe8, 0xaf, 0x1a, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90}},
+ {0x1206, 64, { 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0f, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98,
+  0x74, 0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22, 0x12, 0x13, 0x63, 0x8f, 0x1a, 0x12, 0x13,
+  0x63, 0x8f, 0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x12, 0x12, 0x13, 0x63, 0x8f, 0x1a, 0xe5, 0x1a,
+  0x65, 0x1b, 0x60, 0x07, 0x12, 0x13, 0x63, 0x8f, 0x1b, 0x80, 0xe8, 0xaf, 0x1a, 0x22, 0x90}},
+ {0x1246, 64, { 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x1a, 0x04, 0xe0, 0x44, 0x02, 0xf0,
+  0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x12, 0xc8, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0, 0xe0, 0x44,
+  0x04, 0xf0, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5, 0x3e, 0x54, 0x7f, 0xfd, 0x12, 0x11, 0xb1, 0x90,
+  0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x3e, 0x44, 0x80}},
+ {0x1286, 64, { 0xfd, 0x12, 0x11, 0xb1, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5, 0x3f, 0x54, 0x7f, 0xfd, 0x12, 0x11, 0xfb,
+  0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x3f, 0x44, 0x80,
+  0xfd, 0x12, 0x11, 0xfb, 0x22, 0x05, 0x0e, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x14, 0x03, 0x00,
+  0x00, 0xc1, 0x11, 0xc1, 0x18, 0xc1, 0x95, 0xc1, 0x10, 0xc1, 0x16, 0x01, 0x0a, 0x00, 0xc1}},
+ {0x12c6, 64, { 0x1b, 0x00, 0x8e, 0x18, 0x8f, 0x19, 0xe5, 0x19, 0x15, 0x19, 0xae, 0x18, 0x70, 0x02, 0x15, 0x18, 0x4e,
+  0x60, 0x05, 0x12, 0x0d, 0x4e, 0x80, 0xee, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0,
   0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22,
-  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74,
-  0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90}},
- {0x1346, 64, { 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22,
-  0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74,
-  0x09, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x90, 0xc0,
-  0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff}},
- {0x1386, 64, { 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74,
-  0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0e, 0xf0, 0x90, 0xc0,
-  0x00, 0xe0, 0xff, 0x22, 0x53, 0xd8, 0xef, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x53, 0xd8, 0xef, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0xe7, 0x00, 0x02, 0x13}},
+ {0x1306, 64, { 0x04, 0x00, 0x02, 0x0f, 0xbd, 0x00, 0x02, 0x10, 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0,
+  0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22,
+  0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74,
+  0x16, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0x90}},
+ {0x1346, 64, { 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22,
+  0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74,
+  0x0b, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0,
+  0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff}},
+ {0x1386, 64, { 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0e, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x12, 0x00, 0x03, 0x12,
+  0x0d, 0x5f, 0x12, 0x0b, 0x46, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
  {0x13c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -420,13 +424,13 @@
  {0x18c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x01, 0xff, 0x00}},
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x10, 0x01, 0xff, 0x00}},
  {0x1906, 64, { 0x00, 0x40, 0xcd, 0x06, 0x12, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x02, 0x09, 0x02, 0x74, 0x00, 0x01,
   0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e, 0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01,
   0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40,
   0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x05, 0x02, 0x40, 0x00}},
  {0x1946, 64, { 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x07, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05,
-  0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x83, 0x02,
+  0x81, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x83, 0x02,
   0x40, 0x00, 0x01, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00,
   0x01, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x87, 0x02, 0x40, 0x00, 0x01}},
  {0x1986, 64, { 0x04, 0x03, 0x09, 0x04, 0x48, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61,
@@ -439,5 +443,5 @@
   0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x61, 0x00, 0x70, 0x00, 0x74, 0x00, 0x65, 0x00}},
  {0x1a06, 20, { 0x72, 0x00, 0x10, 0x03, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30,
   0x00, 0x00, 0x00}},
- { 0xffff,	0,	{0x00} }
+ {0xffff,	0,	{0x00} }
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/keyspan_usa19_fw.h linux-2.4.20/drivers/usb/serial/keyspan_usa19_fw.h
--- linux-2.4.19/drivers/usb/serial/keyspan_usa19_fw.h	2001-10-09 22:15:02.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/keyspan_usa19_fw.h	2002-10-29 11:18:49.000000000 +0000
@@ -1,28 +1,33 @@
 /* keyspan_usa19_fw.h
-  
-   Generated from Keyspan firmware image usa19code.h Sat Oct  6 12:14:44 EST 2001
-   This firmware is for the Keyspan USA-19 Serial Adaptor
+ 
+	The firmware contained herein as keyspan_usa19_fw.h is
 
-   "The firmware contained herein as keyspan_usa19_fw.h is
-   Copyright (C) 1999-2001 Keyspan, A division of InnoSys Incorporated
-   ("Keyspan"), as an unpublished work.  This notice does not imply
-   unrestricted or public access to this firmware which is a trade secret of
-   Keyspan, and which may not be reproduced, used, sold or transferred to any
-   third party without Keyspan's prior written consent.  All Rights Reserved.
+		Copyright (C) 1999-2001
+		Keyspan, A division of InnoSys Incorporated ("Keyspan")
+		
+	as an unpublished work. This notice does not imply unrestricted or
+	public access to the source code from which this firmware image is
+	derived.  Except as noted below this firmware image may not be 
+	reproduced, used, sold or transferred to any third party without 
+	Keyspan's prior written consent.  All Rights Reserved.
 
-   This firmware may not be modified and may only be used with the Keyspan 
-   USA-19 Serial Adapter.  Distribution and/or Modification of the
-   keyspan.c driver which includes this firmware, in whole or in part,
-   requires the inclusion of this statement."
+	Permission is hereby granted for the distribution of this firmware 
+	image as part of a Linux or other Open Source operating system kernel 
+	in text or binary form as required. 
 
+	This firmware may not be modified and may only be used with  
+	Keyspan hardware.  Distribution and/or Modification of the 
+	keyspan.c driver which includes this firmware, in whole or in 
+	part, requires the inclusion of this statement."
 */
 
+
 static const struct ezusb_hex_record keyspan_usa19_firmware[] = {
- {0x0026, 10, { 0x12, 0x0d, 0xbb, 0x12, 0x0e, 0xee, 0x12, 0x0d, 0x67, 0x22}},
+ {0x0026, 10, { 0x12, 0x0d, 0xbf, 0x12, 0x0f, 0x47, 0x12, 0x0d, 0x6b, 0x22}},
  {0x0033,  3, { 0x02, 0x00, 0x1a}},
  {0x001a,  4, { 0x53, 0xd8, 0xef, 0x32}},
  {0x0003, 16, { 0x8e, 0x13, 0x8f, 0x14, 0xe5, 0x14, 0x15, 0x14, 0xae, 0x13, 0x70, 0x02, 0x15, 0x13, 0x4e, 0x60}},
- {0x0013,  7, { 0x05, 0x12, 0x0e, 0xdd, 0x80, 0xee, 0x22}},
+ {0x0013,  7, { 0x05, 0x12, 0x0f, 0x36, 0x80, 0xee, 0x22}},
  {0x0023,  3, { 0x02, 0x00, 0x46}},
  {0x0046, 16, { 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0, 0xd0, 0x75, 0xd0, 0x08}},
  {0x0056, 16, { 0x30, 0x99, 0x0e, 0x30, 0x08, 0x07, 0xa2, 0x0b, 0x92, 0x9b, 0x85, 0x35, 0x99, 0xc2, 0x99, 0xd2}},
@@ -37,7 +42,7 @@
  {0x00e6, 16, { 0xf5, 0x50, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x0a, 0x20, 0x09, 0x2d, 0x20, 0x06, 0x2a, 0x90}},
  {0x00f6, 16, { 0x7f, 0x9b, 0xe0, 0x30, 0xe3, 0x03, 0x20, 0x0e, 0x20, 0x30, 0x0d, 0x11, 0x90, 0x7d, 0xc1, 0xe0}},
  {0x0043,  3, { 0x02, 0x0f, 0x00}},
- {0x0000,  3, { 0x02, 0x0c, 0x5d}},
+ {0x0000,  3, { 0x02, 0x0c, 0x61}},
  {0x0106, 64, { 0x13, 0x92, 0x0b, 0xa3, 0xe0, 0xf5, 0x35, 0x75, 0x37, 0x03, 0x02, 0x04, 0x2f, 0x75, 0x37, 0x02, 0x90,
   0x7d, 0xc1, 0xe0, 0xf5, 0x35, 0x02, 0x04, 0x2f, 0x75, 0x37, 0x01, 0xc2, 0x08, 0x02, 0x04, 0x2f,
   0xe5, 0x37, 0xc3, 0x95, 0x50, 0x50, 0x03, 0x02, 0x01, 0xcf, 0x90, 0x7f, 0xc6, 0xe0, 0x30, 0xe1,
@@ -110,9 +115,9 @@
   0x15, 0x36, 0x05, 0x2b, 0x43, 0x33, 0x01, 0x80, 0x0b, 0x90, 0x7f, 0xb9, 0xe5, 0x36, 0xf0, 0x75,
   0x36, 0x00, 0xd2, 0x01, 0xd2, 0x12, 0x30, 0x12, 0x05, 0xc2, 0x12, 0x02, 0x00, 0x56, 0xd0, 0xd0,
   0xd0, 0x86, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7f, 0xca, 0xe0, 0x30, 0xe1}},
- {0x0586, 64, { 0x03, 0x02, 0x06, 0xa7, 0xe4, 0xf5, 0x13, 0x74, 0x40, 0x25, 0x13, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5,
+ {0x0586, 64, { 0x03, 0x02, 0x06, 0xab, 0xe4, 0xf5, 0x13, 0x74, 0x40, 0x25, 0x13, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5,
   0x83, 0xe0, 0xff, 0xe5, 0x13, 0x7c, 0x00, 0x7b, 0x00, 0x24, 0x38, 0xf9, 0xec, 0x34, 0x00, 0xfa,
-  0xef, 0x12, 0x0d, 0x2f, 0x05, 0x13, 0xe5, 0x13, 0xb4, 0x18, 0xdb, 0xe5, 0x38, 0x60, 0x0c, 0x75,
+  0xef, 0x12, 0x0d, 0x33, 0x05, 0x13, 0xe5, 0x13, 0xb4, 0x18, 0xdb, 0xe5, 0x38, 0x60, 0x0c, 0x75,
   0xc9, 0x20, 0x75, 0xc8, 0x34, 0x85, 0x39, 0xca, 0x85, 0x3a, 0xcb, 0xe5, 0x3b, 0x13, 0x92}},
  {0x05c6, 64, { 0x0d, 0x92, 0x9f, 0xe5, 0x3c, 0x13, 0x92, 0x0e, 0xe5, 0x3d, 0x13, 0x92, 0x11, 0xe5, 0x3e, 0x60, 0x09,
   0x90, 0x7f, 0x98, 0xe0, 0x54, 0xfb, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0x98, 0xe0, 0x44, 0x04, 0xf0,
@@ -125,149 +130,149 @@
  {0x0646, 64, { 0x90, 0x7f, 0x98, 0xe0, 0x54, 0xfd, 0xf0, 0xe5, 0x4a, 0x60, 0x0a, 0xd2, 0x9c, 0xc2, 0x98, 0x75, 0x2c,
   0x01, 0x75, 0x31, 0x1e, 0xe5, 0x4b, 0x60, 0x07, 0xc2, 0x9c, 0xe4, 0xf5, 0x36, 0xf5, 0x2c, 0xe5,
   0x4c, 0x60, 0x03, 0xe4, 0xf5, 0x36, 0xe5, 0x4d, 0x60, 0x02, 0xd2, 0x04, 0xe5, 0x4e, 0x60, 0x0a,
-  0xe5, 0x4a, 0x70, 0x02, 0xf5, 0x31, 0xe5, 0x4e, 0x42, 0x33, 0xe5, 0x4f, 0x60, 0x1b, 0x90}},
+  0xe5, 0x4a, 0x70, 0x02, 0xf5, 0x31, 0xe5, 0x4e, 0x42, 0x33, 0xe5, 0x4f, 0x60, 0x1f, 0x90}},
  {0x0686, 64, { 0x7f, 0xd7, 0x74, 0x11, 0xf0, 0x74, 0x31, 0xf0, 0x74, 0x12, 0xf0, 0x74, 0x32, 0xf0, 0x74, 0x13, 0xf0,
-  0x74, 0x33, 0xf0, 0x74, 0x14, 0xf0, 0x74, 0x34, 0xf0, 0xd2, 0x05, 0xe4, 0x90, 0x7f, 0xcb, 0xf0,
-  0xa2, 0x09, 0xe4, 0x33, 0xff, 0x65, 0x29, 0x60, 0x05, 0x8f, 0x29, 0x43, 0x33, 0x01, 0xa2, 0x06,
-  0xe4, 0x33, 0xff, 0x65, 0x2a, 0x60, 0x05, 0x8f, 0x2a, 0x43, 0x33, 0x01, 0x90, 0x7f, 0x9b}},
- {0x06c6, 64, { 0xe0, 0x54, 0x08, 0xb5, 0x25, 0x0a, 0xe0, 0x54, 0x08, 0x64, 0x08, 0xf5, 0x25, 0x43, 0x33, 0x01, 0x90,
-  0x7f, 0x9b, 0xe0, 0x54, 0x10, 0xb5, 0x26, 0x0a, 0xe0, 0x54, 0x10, 0x64, 0x10, 0xf5, 0x26, 0x43,
-  0x33, 0x01, 0x90, 0x7f, 0x9b, 0xe0, 0x54, 0x40, 0xb5, 0x27, 0x0a, 0xe0, 0x54, 0x40, 0x64, 0x40,
-  0xf5, 0x27, 0x43, 0x33, 0x01, 0x90, 0x7f, 0x9b, 0xe0, 0x54, 0x20, 0xb5, 0x28, 0x0a, 0xe0}},
- {0x0706, 64, { 0x54, 0x20, 0x64, 0x20, 0xf5, 0x28, 0x43, 0x33, 0x01, 0x30, 0x04, 0x35, 0xc2, 0xaf, 0x30, 0x01, 0x18,
-  0x90, 0x7f, 0xb8, 0xe0, 0x20, 0xe1, 0x27, 0xe5, 0x36, 0x60, 0x09, 0x90, 0x7f, 0xb7, 0xf0, 0xe4,
-  0xf5, 0x36, 0xc2, 0x01, 0xc2, 0x04, 0x80, 0x16, 0x90, 0x7f, 0xb6, 0xe0, 0x20, 0xe1, 0x0f, 0xe5,
-  0x36, 0x60, 0x09, 0x90, 0x7f, 0xb9, 0xf0, 0xe4, 0xf5, 0x36, 0xd2, 0x01, 0xc2, 0x04, 0xd2}},
- {0x0746, 64, { 0xaf, 0x20, 0x03, 0x37, 0x30, 0x02, 0x1b, 0x90, 0x7f, 0xc6, 0xe0, 0x20, 0xe1, 0x2d, 0x90, 0x7e, 0x40,
-  0xe0, 0x13, 0x92, 0x0a, 0x75, 0x37, 0x01, 0x90, 0x7f, 0xc7, 0xe0, 0xf5, 0x50, 0xd2, 0x03, 0x80,
-  0x19, 0x90, 0x7f, 0xc8, 0xe0, 0x20, 0xe1, 0x12, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x0a, 0x75,
-  0x37, 0x01, 0x90, 0x7f, 0xc9, 0xe0, 0xf5, 0x50, 0xd2, 0x03, 0x20, 0x10, 0x33, 0x20, 0x00}},
- {0x0786, 64, { 0x06, 0xe5, 0x37, 0x65, 0x50, 0x70, 0x2a, 0x30, 0x03, 0x1a, 0x30, 0x02, 0x09, 0xe4, 0x90, 0x7f, 0xc7,
-  0xf0, 0xc2, 0x02, 0x80, 0x07, 0xe4, 0x90, 0x7f, 0xc9, 0xf0, 0xd2, 0x02, 0xc2, 0x03, 0xe4, 0xf5,
-  0x50, 0xf5, 0x37, 0x30, 0x0a, 0x0a, 0xc2, 0x0a, 0xc2, 0x00, 0x90, 0x7f, 0xbb, 0x74, 0x01, 0xf0,
-  0x30, 0x10, 0x03, 0x02, 0x08, 0xc1, 0x20, 0x03, 0x03, 0x02, 0x08, 0xc1, 0x30, 0x0e, 0x0a}},
- {0x07c6, 64, { 0x90, 0x7f, 0x9b, 0xe0, 0x30, 0xe3, 0x03, 0x02, 0x08, 0xc1, 0x30, 0x06, 0x03, 0x02, 0x08, 0xc1, 0x30,
-  0x09, 0x03, 0x02, 0x08, 0xc1, 0x30, 0x02, 0x62, 0x30, 0x0d, 0x12, 0xaf, 0x37, 0x05, 0x37, 0x74,
-  0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x19, 0xaf, 0x37, 0x05,
-  0x37, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5, 0x14, 0xe5}},
- {0x0806, 64, { 0x37, 0xc3, 0x95, 0x50, 0x50, 0x2a, 0x30, 0x0d, 0x12, 0xaf, 0x37, 0x05, 0x37, 0x74, 0x40, 0x2f, 0xf5,
-  0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x0b, 0xaf, 0x37, 0x05, 0x37, 0x74, 0x40,
-  0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5, 0x35, 0xd2, 0x08, 0x80, 0x6b, 0xc2,
-  0x08, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0xc2, 0x02, 0x80, 0x60, 0x30, 0x0d, 0x12, 0xaf, 0x37}},
- {0x0846, 64, { 0x05, 0x37, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x19, 0xaf,
-  0x37, 0x05, 0x37, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x14,
-  0xe5, 0x37, 0xc3, 0x95, 0x50, 0x50, 0x2a, 0x30, 0x0d, 0x12, 0xaf, 0x37, 0x05, 0x37, 0x74, 0xc0,
-  0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x0b, 0xaf, 0x37, 0x05}},
- {0x0886, 64, { 0x37, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x35, 0xd2, 0x08, 0x80,
-  0x09, 0xc2, 0x08, 0xe4, 0x90, 0x7f, 0xc9, 0xf0, 0xd2, 0x02, 0x30, 0x0d, 0x04, 0xa2, 0x19, 0x92,
-  0x9b, 0xd2, 0x10, 0xc2, 0xaf, 0x85, 0x14, 0x99, 0x20, 0x08, 0x0d, 0x30, 0x0a, 0x0a, 0xc2, 0x0a,
-  0xc2, 0x00, 0x90, 0x7f, 0xbb, 0x74, 0x01, 0xf0, 0xd2, 0xaf, 0x90, 0x7f, 0xbc, 0xe0, 0x20}},
- {0x08c6, 64, { 0xe1, 0x51, 0xe5, 0x33, 0x60, 0x4d, 0xe5, 0x31, 0x70, 0x49, 0xe5, 0x33, 0x30, 0xe1, 0x08, 0xe4, 0xf5,
-  0x2f, 0x75, 0x33, 0x01, 0x80, 0x0b, 0xa2, 0x05, 0xe4, 0x33, 0xf5, 0x2f, 0xc2, 0x05, 0xe4, 0xf5,
-  0x33, 0xe4, 0xf5, 0x13, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x13, 0xf9, 0xee, 0x34, 0x00,
-  0xfa, 0x12, 0x0c, 0xe9, 0xff, 0x74, 0x00, 0x25, 0x13, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5}},
- {0x0906, 64, { 0x83, 0xef, 0xf0, 0x05, 0x13, 0xe5, 0x13, 0xb4, 0x0c, 0xdb, 0x90, 0x7f, 0xbd, 0x74, 0x0c, 0xf0, 0x75,
-  0x31, 0x10, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x0d, 0x41, 0x09, 0xff, 0x00, 0x0a, 0x73, 0x01,
-  0x0a, 0xdf, 0x03, 0x09, 0x3d, 0x06, 0x09, 0xf0, 0x08, 0x09, 0xe4, 0x09, 0x09, 0xcc, 0x0a, 0x09,
-  0xdb, 0x0b, 0x00, 0x00, 0x0b, 0x2e, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14}},
- {0x0946, 64, { 0x60, 0x57, 0x24, 0x02, 0x70, 0x76, 0x74, 0x0f, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x64, 0x90, 0x7f, 0xd5,
-  0xf0, 0x02, 0x0b, 0x35, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x04, 0x7f, 0x02, 0x80, 0x02, 0x7f, 0x03,
-  0x75, 0x82, 0xb5, 0x75, 0x83, 0x0f, 0xef, 0xf0, 0x75, 0x82, 0xae, 0x75, 0x83, 0x0f, 0xf0, 0x75,
-  0x82, 0xa7, 0x75, 0x83, 0x0f, 0xf0, 0x75, 0x82, 0xa0, 0x75, 0x83, 0x0f, 0xf0, 0x90, 0x7f}},
- {0x0986, 64, { 0xea, 0xe0, 0x04, 0x75, 0x82, 0x7b, 0x75, 0x83, 0x0f, 0xf0, 0x74, 0x0f, 0x90, 0x7f, 0xd4, 0xf0, 0x74,
-  0x76, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x35, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0e, 0x44,
-  0xea, 0x49, 0x60, 0x0d, 0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b,
-  0x35, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x35, 0x90, 0x7f, 0xb4, 0xe0}},
- {0x09c6, 64, { 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x35, 0x90, 0x7f, 0x00, 0xe5, 0x19, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01,
-  0xf0, 0x02, 0x0b, 0x35, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x19, 0x02, 0x0b, 0x35, 0x90, 0x7f, 0xea,
-  0xe0, 0xf5, 0x18, 0x12, 0x0d, 0x67, 0x02, 0x0b, 0x35, 0x90, 0x7f, 0x00, 0xe5, 0x18, 0xf0, 0x90,
-  0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x0b, 0x35, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60}},
- {0x0a06, 64, { 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2, 0x13, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2,
-  0x17, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02,
-  0xf0, 0x02, 0x0b, 0x35, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02,
-  0xf0, 0x02, 0x0b, 0x35, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f}},
- {0x0a46, 64, { 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0,
-  0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02,
-  0x0b, 0x35, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x35, 0x90, 0x7f, 0xe8, 0xe0,
-  0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0b, 0x35, 0x90, 0x7f, 0xea, 0xe0}},
- {0x0a86, 64, { 0xb4, 0x01, 0x05, 0xc2, 0x13, 0x02, 0x0b, 0x35, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b,
-  0x35, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4,
-  0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f,
-  0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54}},
- {0x0ac6, 64, { 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x5f, 0x90,
-  0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x18,
-  0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x13, 0x80, 0x3f, 0x90,
-  0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90}},
- {0x0b06, 64, { 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0,
-  0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f,
-  0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f,
-  0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22, 0x20, 0x15, 0x03, 0x02, 0x0b, 0xcf, 0xe5, 0x31, 0x60}},
- {0x0b46, 64, { 0x02, 0x15, 0x31, 0xe5, 0x36, 0x60, 0x4f, 0x65, 0x34, 0x70, 0x45, 0xe5, 0x32, 0xf4, 0x60, 0x02, 0x05,
-  0x32, 0xe5, 0x32, 0xc3, 0x95, 0x41, 0x40, 0x3d, 0xc2, 0xaf, 0x30, 0x01, 0x18, 0x90, 0x7f, 0xb8,
-  0xe0, 0x20, 0xe1, 0x27, 0x90, 0x7f, 0xb7, 0xe5, 0x36, 0xf0, 0xc2, 0x01, 0xe4, 0xf5, 0x36, 0xf5,
-  0x32, 0xf5, 0x34, 0x80, 0x16, 0x90, 0x7f, 0xb6, 0xe0, 0x20, 0xe1, 0x0f, 0x90, 0x7f, 0xb9}},
- {0x0b86, 64, { 0xe5, 0x36, 0xf0, 0xd2, 0x01, 0xe4, 0xf5, 0x36, 0xf5, 0x32, 0xf5, 0x34, 0xd2, 0xaf, 0x80, 0x06, 0x85,
-  0x36, 0x34, 0xe4, 0xf5, 0x32, 0xe5, 0x2c, 0x60, 0x2f, 0x20, 0x0c, 0x07, 0x90, 0x7f, 0x9b, 0xe0,
-  0x30, 0xe0, 0x0f, 0xe5, 0x2d, 0x60, 0x06, 0xe4, 0xf5, 0x2d, 0x43, 0x33, 0x01, 0xe4, 0xf5, 0x30,
-  0x80, 0x14, 0xe5, 0x30, 0xd3, 0x95, 0x42, 0x50, 0x0d, 0xe5, 0x30, 0xb5, 0x42, 0x06, 0x75}},
- {0x0bc6, 64, { 0x2d, 0x01, 0x43, 0x33, 0x01, 0x05, 0x30, 0xc2, 0x0c, 0x22, 0x75, 0x12, 0x01, 0xc2, 0x14, 0xc2, 0x18,
-  0xc2, 0x13, 0xc2, 0x17, 0xc2, 0x15, 0xc2, 0x12, 0xd2, 0x16, 0xe4, 0xf5, 0x18, 0x90, 0x7f, 0x92,
-  0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92, 0x13, 0xe4, 0x33, 0xfe, 0xef,
-  0x4e, 0xf0, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f}},
- {0x0c06, 64, { 0xdf, 0xf0, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53,
-  0x91, 0xef, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x0d, 0xf0,
-  0xd2, 0xaf, 0xd2, 0xbc, 0xd2, 0x19, 0x12, 0x0f, 0x36, 0xc2, 0x14, 0x30, 0x15, 0x03, 0x12, 0x05,
-  0x80, 0x90, 0x7f, 0xd8, 0xe0, 0x65, 0x11, 0x60, 0x08, 0xe0, 0xf5, 0x11, 0x12, 0x0b, 0x3d}},
- {0x0c46, 64, { 0x80, 0xea, 0x30, 0x14, 0x07, 0xc2, 0x14, 0x12, 0x09, 0x1a, 0x80, 0xe0, 0x30, 0x18, 0xdd, 0xc2, 0x18,
-  0x12, 0x00, 0x26, 0x80, 0xd6, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x50, 0x02,
-  0x0c, 0xa4, 0x02, 0x0b, 0xd0, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80,
-  0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c}},
- {0x0c86, 64, { 0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46,
-  0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x0e, 0x00,
-  0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe,
-  0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8}},
- {0x0cc6, 64, { 0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5,
-  0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7,
-  0x80, 0xbe, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb,
-  0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x0c, 0xe5}},
- {0x0d06, 64, { 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, 0xf8,
-  0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82, 0x29, 0xf5, 0x82,
-  0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0,
-  0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xd0, 0x83, 0xd0, 0x82, 0xf8}},
- {0x0d46, 64, { 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5,
-  0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf,
-  0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0x90, 0x7f, 0x96, 0x74, 0x10,
-  0xf0, 0x90, 0x7f, 0x94, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0x9d, 0x04, 0xf0, 0x90, 0x7f, 0x97}},
- {0x0d86, 64, { 0x74, 0x20, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0x03, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x84, 0xf0, 0xe4, 0x90,
-  0x7f, 0x98, 0xf0, 0x90, 0x7f, 0xc7, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0x90, 0x7f, 0xcb, 0xf0, 0x75,
-  0x98, 0x40, 0x43, 0xa8, 0x10, 0x90, 0x7f, 0xde, 0x74, 0x1f, 0xf0, 0x90, 0x7f, 0xdf, 0x74, 0x0f,
-  0xf0, 0xd2, 0x15, 0x22, 0xe4, 0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f}},
- {0x0dc6, 64, { 0x93, 0xf0, 0x90, 0x7f, 0x9d, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0x7f, 0x97, 0xe0, 0x44, 0x02, 0xf0, 0x90,
-  0x7f, 0x9d, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x20, 0xf0, 0xe4, 0x90, 0x7f, 0x96,
-  0xf0, 0x90, 0x7f, 0x9d, 0xe0, 0x44, 0xfd, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90, 0x7f, 0x9e,
-  0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x98, 0xf0, 0x22, 0x0c, 0x24, 0x00, 0x00, 0x00, 0x00}},
- {0x0e06, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30, 0x00, 0x01, 0x33, 0x01, 0x01, 0x32, 0x00,
-  0x01, 0x37, 0x00, 0x01, 0x50, 0x00, 0x01, 0x36, 0x00, 0x01, 0x34, 0x00, 0xc1, 0x05, 0xc1, 0x0c,
-  0xc1, 0x03, 0xc1, 0x0f, 0xc1, 0x04, 0xc1, 0x0e, 0xc1, 0x11, 0xc1, 0x0a, 0xc1, 0x10, 0xc1, 0x08,
-  0xc1, 0x09, 0xc1, 0x06, 0xc1, 0x00, 0xc1, 0x0d, 0xc1, 0x81, 0xc1, 0x82, 0x00, 0x8f, 0x13}},
- {0x0e46, 64, { 0xe4, 0xf5, 0x14, 0x75, 0x15, 0xff, 0x75, 0x16, 0x0f, 0x75, 0x17, 0xb9, 0xab, 0x15, 0xaa, 0x16, 0xa9,
-  0x17, 0x90, 0x00, 0x01, 0x12, 0x0d, 0x02, 0xb4, 0x03, 0x1d, 0xaf, 0x14, 0x05, 0x14, 0xef, 0xb5,
-  0x13, 0x01, 0x22, 0x12, 0x0c, 0xe9, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75, 0x15,
-  0xff, 0xf5, 0x16, 0x89, 0x17, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x22, 0xc0}},
- {0x0e86, 64, { 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x30, 0x16, 0x04,
-  0xc2, 0x16, 0x80, 0x02, 0xd2, 0x18, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08, 0xf0, 0xd0,
+  0x74, 0x33, 0xf0, 0x74, 0x14, 0xf0, 0x74, 0x34, 0xf0, 0xd2, 0x02, 0xd2, 0x01, 0xd2, 0x05, 0xe4,
+  0x90, 0x7f, 0xcb, 0xf0, 0xa2, 0x09, 0xe4, 0x33, 0xff, 0x65, 0x29, 0x60, 0x05, 0x8f, 0x29, 0x43,
+  0x33, 0x01, 0xa2, 0x06, 0xe4, 0x33, 0xff, 0x65, 0x2a, 0x60, 0x05, 0x8f, 0x2a, 0x43, 0x33}},
+ {0x06c6, 64, { 0x01, 0x90, 0x7f, 0x9b, 0xe0, 0x54, 0x08, 0xb5, 0x25, 0x0a, 0xe0, 0x54, 0x08, 0x64, 0x08, 0xf5, 0x25,
+  0x43, 0x33, 0x01, 0x90, 0x7f, 0x9b, 0xe0, 0x54, 0x10, 0xb5, 0x26, 0x0a, 0xe0, 0x54, 0x10, 0x64,
+  0x10, 0xf5, 0x26, 0x43, 0x33, 0x01, 0x90, 0x7f, 0x9b, 0xe0, 0x54, 0x40, 0xb5, 0x27, 0x0a, 0xe0,
+  0x54, 0x40, 0x64, 0x40, 0xf5, 0x27, 0x43, 0x33, 0x01, 0x90, 0x7f, 0x9b, 0xe0, 0x54, 0x20}},
+ {0x0706, 64, { 0xb5, 0x28, 0x0a, 0xe0, 0x54, 0x20, 0x64, 0x20, 0xf5, 0x28, 0x43, 0x33, 0x01, 0x30, 0x04, 0x35, 0xc2,
+  0xaf, 0x30, 0x01, 0x18, 0x90, 0x7f, 0xb8, 0xe0, 0x20, 0xe1, 0x27, 0xe5, 0x36, 0x60, 0x09, 0x90,
+  0x7f, 0xb7, 0xf0, 0xe4, 0xf5, 0x36, 0xc2, 0x01, 0xc2, 0x04, 0x80, 0x16, 0x90, 0x7f, 0xb6, 0xe0,
+  0x20, 0xe1, 0x0f, 0xe5, 0x36, 0x60, 0x09, 0x90, 0x7f, 0xb9, 0xf0, 0xe4, 0xf5, 0x36, 0xd2}},
+ {0x0746, 64, { 0x01, 0xc2, 0x04, 0xd2, 0xaf, 0x20, 0x03, 0x37, 0x30, 0x02, 0x1b, 0x90, 0x7f, 0xc6, 0xe0, 0x20, 0xe1,
+  0x2d, 0x90, 0x7e, 0x40, 0xe0, 0x13, 0x92, 0x0a, 0x75, 0x37, 0x01, 0x90, 0x7f, 0xc7, 0xe0, 0xf5,
+  0x50, 0xd2, 0x03, 0x80, 0x19, 0x90, 0x7f, 0xc8, 0xe0, 0x20, 0xe1, 0x12, 0x90, 0x7d, 0xc0, 0xe0,
+  0x13, 0x92, 0x0a, 0x75, 0x37, 0x01, 0x90, 0x7f, 0xc9, 0xe0, 0xf5, 0x50, 0xd2, 0x03, 0x20}},
+ {0x0786, 64, { 0x10, 0x33, 0x20, 0x00, 0x06, 0xe5, 0x37, 0x65, 0x50, 0x70, 0x2a, 0x30, 0x03, 0x1a, 0x30, 0x02, 0x09,
+  0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0xc2, 0x02, 0x80, 0x07, 0xe4, 0x90, 0x7f, 0xc9, 0xf0, 0xd2, 0x02,
+  0xc2, 0x03, 0xe4, 0xf5, 0x50, 0xf5, 0x37, 0x30, 0x0a, 0x0a, 0xc2, 0x0a, 0xc2, 0x00, 0x90, 0x7f,
+  0xbb, 0x74, 0x01, 0xf0, 0x30, 0x10, 0x03, 0x02, 0x08, 0xc5, 0x20, 0x03, 0x03, 0x02, 0x08}},
+ {0x07c6, 64, { 0xc5, 0x30, 0x0e, 0x0a, 0x90, 0x7f, 0x9b, 0xe0, 0x30, 0xe3, 0x03, 0x02, 0x08, 0xc5, 0x30, 0x06, 0x03,
+  0x02, 0x08, 0xc5, 0x30, 0x09, 0x03, 0x02, 0x08, 0xc5, 0x30, 0x02, 0x62, 0x30, 0x0d, 0x12, 0xaf,
+  0x37, 0x05, 0x37, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92,
+  0x19, 0xaf, 0x37, 0x05, 0x37, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83}},
+ {0x0806, 64, { 0xe0, 0xf5, 0x14, 0xe5, 0x37, 0xc3, 0x95, 0x50, 0x50, 0x2a, 0x30, 0x0d, 0x12, 0xaf, 0x37, 0x05, 0x37,
+  0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x0b, 0xaf, 0x37,
+  0x05, 0x37, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5, 0x35, 0xd2,
+  0x08, 0x80, 0x6b, 0xc2, 0x08, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0xc2, 0x02, 0x80, 0x60, 0x30}},
+ {0x0846, 64, { 0x0d, 0x12, 0xaf, 0x37, 0x05, 0x37, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0,
+  0x13, 0x92, 0x19, 0xaf, 0x37, 0x05, 0x37, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5,
+  0x83, 0xe0, 0xf5, 0x14, 0xe5, 0x37, 0xc3, 0x95, 0x50, 0x50, 0x2a, 0x30, 0x0d, 0x12, 0xaf, 0x37,
+  0x05, 0x37, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92}},
+ {0x0886, 64, { 0x0b, 0xaf, 0x37, 0x05, 0x37, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5,
+  0x35, 0xd2, 0x08, 0x80, 0x09, 0xc2, 0x08, 0xe4, 0x90, 0x7f, 0xc9, 0xf0, 0xd2, 0x02, 0x30, 0x0d,
+  0x04, 0xa2, 0x19, 0x92, 0x9b, 0xd2, 0x10, 0xc2, 0xaf, 0x85, 0x14, 0x99, 0x20, 0x08, 0x0d, 0x30,
+  0x0a, 0x0a, 0xc2, 0x0a, 0xc2, 0x00, 0x90, 0x7f, 0xbb, 0x74, 0x01, 0xf0, 0xd2, 0xaf, 0x90}},
+ {0x08c6, 64, { 0x7f, 0xbc, 0xe0, 0x20, 0xe1, 0x51, 0xe5, 0x33, 0x60, 0x4d, 0xe5, 0x31, 0x70, 0x49, 0xe5, 0x33, 0x30,
+  0xe1, 0x08, 0xe4, 0xf5, 0x2f, 0x75, 0x33, 0x01, 0x80, 0x0b, 0xa2, 0x05, 0xe4, 0x33, 0xf5, 0x2f,
+  0xc2, 0x05, 0xe4, 0xf5, 0x33, 0xe4, 0xf5, 0x13, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x13,
+  0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0c, 0xed, 0xff, 0x74, 0x00, 0x25, 0x13, 0xf5, 0x82}},
+ {0x0906, 64, { 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x13, 0xe5, 0x13, 0xb4, 0x0c, 0xdb, 0x90, 0x7f, 0xbd,
+  0x74, 0x0c, 0xf0, 0x75, 0x31, 0x10, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x0d, 0x45, 0x0a, 0x03,
+  0x00, 0x0a, 0x77, 0x01, 0x0a, 0xe3, 0x03, 0x09, 0x41, 0x06, 0x09, 0xf4, 0x08, 0x09, 0xe8, 0x09,
+  0x09, 0xd0, 0x0a, 0x09, 0xdf, 0x0b, 0x00, 0x00, 0x0b, 0x32, 0x90, 0x7f, 0xeb, 0xe0, 0x24}},
+ {0x0946, 64, { 0xfe, 0x60, 0x16, 0x14, 0x60, 0x57, 0x24, 0x02, 0x70, 0x76, 0x74, 0x0f, 0x90, 0x7f, 0xd4, 0xf0, 0x74,
+  0x64, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x39, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x04, 0x7f, 0x02,
+  0x80, 0x02, 0x7f, 0x03, 0x75, 0x82, 0xb5, 0x75, 0x83, 0x0f, 0xef, 0xf0, 0x75, 0x82, 0xae, 0x75,
+  0x83, 0x0f, 0xf0, 0x75, 0x82, 0xa7, 0x75, 0x83, 0x0f, 0xf0, 0x75, 0x82, 0xa0, 0x75, 0x83}},
+ {0x0986, 64, { 0x0f, 0xf0, 0x90, 0x7f, 0xea, 0xe0, 0x04, 0x75, 0x82, 0x7b, 0x75, 0x83, 0x0f, 0xf0, 0x74, 0x0f, 0x90,
+  0x7f, 0xd4, 0xf0, 0x74, 0x76, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x39, 0x90, 0x7f, 0xea, 0xe0,
+  0xff, 0x12, 0x0e, 0x48, 0xea, 0x49, 0x60, 0x0d, 0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f,
+  0xd5, 0xf0, 0x02, 0x0b, 0x39, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x39}},
+ {0x09c6, 64, { 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x39, 0x90, 0x7f, 0x00, 0xe5, 0x19, 0xf0, 0x90,
+  0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x0b, 0x39, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x19, 0x02, 0x0b,
+  0x39, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x18, 0x12, 0x0d, 0x6b, 0x02, 0x0b, 0x39, 0x90, 0x7f, 0x00,
+  0xe5, 0x18, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x0b, 0x39, 0x90, 0x7f, 0xe8}},
+ {0x0a06, 64, { 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2, 0x13, 0xe4, 0x33, 0xff,
+  0x25, 0xe0, 0xff, 0xa2, 0x17, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90,
+  0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x39, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90,
+  0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x39, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80}},
+ {0x0a46, 64, { 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34,
+  0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5,
+  0x74, 0x02, 0xf0, 0x02, 0x0b, 0x39, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x39,
+  0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0b, 0x39}},
+ {0x0a86, 64, { 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x13, 0x02, 0x0b, 0x39, 0x90, 0x7f, 0xb4, 0xe0, 0x44,
+  0x01, 0xf0, 0x02, 0x0b, 0x39, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4,
+  0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5,
+  0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff}},
+ {0x0ac6, 64, { 0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20,
+  0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0,
+  0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2,
+  0x13, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea}},
+ {0x0b06, 64, { 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54,
+  0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0,
+  0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44,
+  0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22, 0x20, 0x15, 0x03, 0x02, 0x0b}},
+ {0x0b46, 64, { 0xd3, 0xe5, 0x31, 0x60, 0x02, 0x15, 0x31, 0xe5, 0x36, 0x60, 0x4f, 0x65, 0x34, 0x70, 0x45, 0xe5, 0x32,
+  0xf4, 0x60, 0x02, 0x05, 0x32, 0xe5, 0x32, 0xc3, 0x95, 0x41, 0x40, 0x3d, 0xc2, 0xaf, 0x30, 0x01,
+  0x18, 0x90, 0x7f, 0xb8, 0xe0, 0x20, 0xe1, 0x27, 0x90, 0x7f, 0xb7, 0xe5, 0x36, 0xf0, 0xc2, 0x01,
+  0xe4, 0xf5, 0x36, 0xf5, 0x32, 0xf5, 0x34, 0x80, 0x16, 0x90, 0x7f, 0xb6, 0xe0, 0x20, 0xe1}},
+ {0x0b86, 64, { 0x0f, 0x90, 0x7f, 0xb9, 0xe5, 0x36, 0xf0, 0xd2, 0x01, 0xe4, 0xf5, 0x36, 0xf5, 0x32, 0xf5, 0x34, 0xd2,
+  0xaf, 0x80, 0x06, 0x85, 0x36, 0x34, 0xe4, 0xf5, 0x32, 0xe5, 0x2c, 0x60, 0x2f, 0x20, 0x0c, 0x07,
+  0x90, 0x7f, 0x9b, 0xe0, 0x30, 0xe0, 0x0f, 0xe5, 0x2d, 0x60, 0x06, 0xe4, 0xf5, 0x2d, 0x43, 0x33,
+  0x01, 0xe4, 0xf5, 0x30, 0x80, 0x14, 0xe5, 0x30, 0xd3, 0x95, 0x42, 0x50, 0x0d, 0xe5, 0x30}},
+ {0x0bc6, 64, { 0xb5, 0x42, 0x06, 0x75, 0x2d, 0x01, 0x43, 0x33, 0x01, 0x05, 0x30, 0xc2, 0x0c, 0x22, 0x75, 0x12, 0x01,
+  0xc2, 0x14, 0xc2, 0x18, 0xc2, 0x13, 0xc2, 0x17, 0xc2, 0x15, 0xc2, 0x12, 0xd2, 0x16, 0xe4, 0xf5,
+  0x18, 0x90, 0x7f, 0x92, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92, 0x13,
+  0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74}},
+ {0x0c06, 64, { 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90,
+  0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae,
+  0xe0, 0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0xbc, 0xd2, 0x19, 0x12, 0x0e, 0xda, 0xc2, 0x14, 0x30,
+  0x15, 0x03, 0x12, 0x05, 0x80, 0x90, 0x7f, 0xd8, 0xe0, 0x65, 0x11, 0x60, 0x08, 0xe0, 0xf5}},
+ {0x0c46, 64, { 0x11, 0x12, 0x0b, 0x41, 0x80, 0xea, 0x30, 0x14, 0x07, 0xc2, 0x14, 0x12, 0x09, 0x1e, 0x80, 0xe0, 0x30,
+  0x18, 0xdd, 0xc2, 0x18, 0x12, 0x00, 0x26, 0x80, 0xd6, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd,
+  0x75, 0x81, 0x50, 0x02, 0x0c, 0xa8, 0x02, 0x0b, 0xd4, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3,
+  0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8}},
+ {0x0c86, 64, { 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4,
+  0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
+  0x80, 0x90, 0x0e, 0x04, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5,
+  0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0}},
+ {0x0cc6, 64, { 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5,
+  0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca,
+  0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50,
+  0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22}},
+ {0x0d06, 64, { 0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06,
+  0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5,
+  0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89,
+  0x82, 0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xd0}},
+ {0x0d46, 64, { 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8,
+  0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3,
+  0xa3, 0xa3, 0x80, 0xdf, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0x90,
+  0x7f, 0x96, 0x74, 0x10, 0xf0, 0x90, 0x7f, 0x94, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0x9d, 0x04}},
+ {0x0d86, 64, { 0xf0, 0x90, 0x7f, 0x97, 0x74, 0x20, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0x03, 0xf0, 0x90, 0x7f, 0x9e, 0x74,
+  0x84, 0xf0, 0xe4, 0x90, 0x7f, 0x98, 0xf0, 0x90, 0x7f, 0xc7, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0x90,
+  0x7f, 0xcb, 0xf0, 0x75, 0x98, 0x40, 0x43, 0xa8, 0x10, 0x90, 0x7f, 0xde, 0x74, 0x1f, 0xf0, 0x90,
+  0x7f, 0xdf, 0x74, 0x0f, 0xf0, 0xd2, 0x15, 0x22, 0xe4, 0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f}},
+ {0x0dc6, 64, { 0x94, 0xf0, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9d, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0x7f, 0x97, 0xe0,
+  0x44, 0x02, 0xf0, 0x90, 0x7f, 0x9d, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x20, 0xf0,
+  0xe4, 0x90, 0x7f, 0x96, 0xf0, 0x90, 0x7f, 0x9d, 0xe0, 0x44, 0xfd, 0xf0, 0xe4, 0x90, 0x7f, 0x97,
+  0xf0, 0x90, 0x7f, 0x9e, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x98, 0xf0, 0x22, 0x0c, 0x24}},
+ {0x0e06, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30, 0x00, 0x01, 0x33,
+  0x01, 0x01, 0x32, 0x00, 0x01, 0x37, 0x00, 0x01, 0x50, 0x00, 0x01, 0x36, 0x00, 0x01, 0x34, 0x00,
+  0xc1, 0x05, 0xc1, 0x0c, 0xc1, 0x03, 0xc1, 0x0f, 0xc1, 0x04, 0xc1, 0x0e, 0xc1, 0x11, 0xc1, 0x0a,
+  0xc1, 0x10, 0xc1, 0x08, 0xc1, 0x09, 0xc1, 0x06, 0xc1, 0x00, 0xc1, 0x0d, 0xc1, 0x81, 0xc1}},
+ {0x0e46, 64, { 0x82, 0x00, 0x8f, 0x13, 0xe4, 0xf5, 0x14, 0x75, 0x15, 0xff, 0x75, 0x16, 0x0f, 0x75, 0x17, 0xb9, 0xab,
+  0x15, 0xaa, 0x16, 0xa9, 0x17, 0x90, 0x00, 0x01, 0x12, 0x0d, 0x06, 0xb4, 0x03, 0x1d, 0xaf, 0x14,
+  0x05, 0x14, 0xef, 0xb5, 0x13, 0x01, 0x22, 0x12, 0x0c, 0xed, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a,
+  0xa9, 0x07, 0x75, 0x15, 0xff, 0xf5, 0x16, 0x89, 0x17, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00}},
+ {0x0e86, 64, { 0x79, 0x00, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86,
+  0x00, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0,
   0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83,
-  0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90, 0x7f, 0xc4, 0xe4}},
- {0x0ec6, 64, { 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0,
-  0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3,
-  0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x02, 0x0f, 0x0f, 0x00, 0x02, 0x0f}},
- {0x0f06, 64, { 0x04, 0x00, 0x02, 0x0e, 0xb3, 0x00, 0x02, 0x0e, 0x85, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85,
-  0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x14, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74,
-  0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90,
-  0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x19, 0x04, 0xe0, 0x44}},
- {0x0f46, 64, { 0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x00, 0x03, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0, 0xe0,
-  0x44, 0x04, 0xf0, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00,
+  0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x14, 0x53, 0x91}},
+ {0x0ec6, 64, { 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83,
+  0xd0, 0xe0, 0x32, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x19,
+  0x04, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x00, 0x03, 0x90, 0x7f, 0xd6, 0xe0,
+  0x54, 0xf7, 0xf0, 0xe0, 0x44, 0x04, 0xf0, 0x22, 0x00, 0x02, 0x0e, 0xb3, 0x00, 0x02, 0x0f}},
+ {0x0f06, 64, { 0x04, 0x00, 0x02, 0x0e, 0x89, 0x00, 0x02, 0x0f, 0x0f, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85,
+  0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x18, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74,
+  0x08, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x74,
+  0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9}},
+ {0x0f46, 64, { 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x10,
   0x01, 0xff, 0x00, 0x00, 0x40, 0xcd, 0x06, 0x07, 0x01, 0x01, 0x00, 0x01, 0x02, 0x00, 0x02, 0x09,
   0x02, 0x43, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00, 0x00, 0x07, 0xff, 0x00}},
  {0x0f86, 64, { 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07,
@@ -276,5 +281,5 @@
   0x00, 0x01, 0x04, 0x03, 0x09, 0x04, 0x10, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x73}},
  {0x0fc6, 23, { 0x00, 0x70, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x0e, 0x03, 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00,
   0x61, 0x00, 0x6c, 0x00, 0x00, 0x00}},
-{ 0xffff,	0,	{0x00} }
+ {0xffff,	0,	{0x00} }
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/keyspan_usa19qi_fw.h linux-2.4.20/drivers/usb/serial/keyspan_usa19qi_fw.h
--- linux-2.4.19/drivers/usb/serial/keyspan_usa19qi_fw.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/keyspan_usa19qi_fw.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,284 @@
+/* keyspan_usa19qi_fw.h
+ 
+	The firmware contained herein as keyspn_usa19qi_fw.h is
+
+		Copyright (C) 1999-2001
+		Keyspan, A division of InnoSys Incorporated ("Keyspan")
+		
+	as an unpublished work. This notice does not imply unrestricted or
+	public access to the source code from which this firmware image is
+	derived.  Except as noted below this firmware image may not be 
+	reproduced, used, sold or transferred to any third party without 
+	Keyspan's prior written consent.  All Rights Reserved.
+
+	Permission is hereby granted for the distribution of this firmware 
+	image as part of a Linux or other Open Source operating system kernel 
+	in text or binary form as required. 
+
+	This firmware may not be modified and may only be used with  
+	Keyspan hardware.  Distribution and/or Modification of the 
+	keyspan.c driver which includes this firmware, in whole or in 
+	part, requires the inclusion of this statement."
+
+*/
+
+static const struct ezusb_hex_record keyspan_usa19qi_firmware[] = {
+ {0x0033,  3, { 0x02, 0x00, 0x1a}},
+ {0x001a,  4, { 0x53, 0xd8, 0xef, 0x32}},
+ {0x0003, 16, { 0x8e, 0x11, 0x8f, 0x12, 0xe5, 0x12, 0x15, 0x12, 0xae, 0x11, 0x70, 0x02, 0x15, 0x11, 0x4e, 0x60}},
+ {0x0013,  7, { 0x05, 0x12, 0x0f, 0x84, 0x80, 0xee, 0x22}},
+ {0x0023,  3, { 0x02, 0x00, 0x46}},
+ {0x0046, 16, { 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0, 0xd0, 0x75, 0xd0, 0x08}},
+ {0x0056, 16, { 0x30, 0x99, 0x0e, 0x30, 0x0b, 0x07, 0xa2, 0x0e, 0x92, 0x9b, 0x85, 0x36, 0x99, 0xc2, 0x99, 0xd2}},
+ {0x0066, 16, { 0x12, 0x20, 0x12, 0x03, 0x02, 0x04, 0x1e, 0xc2, 0x12, 0x20, 0x03, 0x03, 0x02, 0x02, 0x4e, 0x20}},
+ {0x0076, 16, { 0x0b, 0x03, 0x02, 0x01, 0x26, 0xe5, 0x3a, 0xc3, 0x95, 0x53, 0x50, 0x3c, 0x20, 0x0c, 0x34, 0x20}},
+ {0x0086, 16, { 0x09, 0x31, 0x90, 0x7f, 0x9b, 0xe0, 0x55, 0x38, 0x70, 0x29, 0x30, 0x10, 0x12, 0xaf, 0x3a, 0x05}},
+ {0x0096, 16, { 0x3a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x0e, 0xaf}},
+ {0x00a6, 16, { 0x3a, 0x05, 0x3a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5, 0x36}},
+ {0x00b6, 16, { 0x02, 0x04, 0x1c, 0xc2, 0x0b, 0x02, 0x04, 0x1c, 0x90, 0x7f, 0xc7, 0xe4, 0xf0, 0xc2, 0x03, 0x30}},
+ {0x00c6, 16, { 0x0d, 0x0c, 0xc2, 0x0d, 0x90, 0x7f, 0xbb, 0x04, 0xf0, 0xc2, 0x0b, 0x02, 0x04, 0x1c, 0x90, 0x7f}},
+ {0x00d6, 16, { 0xc8, 0xe0, 0x30, 0xe1, 0x05, 0xc2, 0x0b, 0x02, 0x04, 0x1c, 0x90, 0x7f, 0xc9, 0xe0, 0xf5, 0x53}},
+ {0x00e6, 16, { 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x0d, 0x75, 0x16, 0xff, 0x20, 0x0c, 0x2b, 0x20, 0x09, 0x28}},
+ {0x00f6, 16, { 0x90, 0x7f, 0x9b, 0xe0, 0x55, 0x38, 0x70, 0x20, 0x30, 0x10, 0x11, 0x90, 0x7d, 0xc1, 0xe0, 0x13}},
+ {0x0043,  3, { 0x02, 0x0e, 0x00}},
+ {0x0000,  3, { 0x02, 0x00, 0x26}},
+ {0x0026, 12, { 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x54, 0x02, 0x0b, 0x28}},
+ {0x0106, 64, { 0x92, 0x0e, 0xa3, 0xe0, 0xf5, 0x36, 0x75, 0x3a, 0x03, 0x02, 0x04, 0x1c, 0x75, 0x3a, 0x02, 0x90, 0x7d,
+  0xc1, 0xe0, 0xf5, 0x36, 0x02, 0x04, 0x1c, 0x75, 0x3a, 0x01, 0xc2, 0x0b, 0x02, 0x04, 0x1c, 0xe5,
+  0x3a, 0xc3, 0x95, 0x53, 0x50, 0x03, 0x02, 0x01, 0xc9, 0x90, 0x7f, 0xc6, 0xe0, 0x30, 0xe1, 0x07,
+  0xc2, 0x14, 0xc2, 0x05, 0x02, 0x04, 0x1c, 0x90, 0x7f, 0xc7, 0xe0, 0xf5, 0x53, 0x90, 0x7e}},
+ {0x0146, 64, { 0x40, 0xe0, 0x13, 0x92, 0x0d, 0x75, 0x16, 0xff, 0x20, 0x0c, 0x70, 0x20, 0x09, 0x6d, 0x90, 0x7f, 0x9b,
+  0xe0, 0x55, 0x38, 0x70, 0x65, 0x30, 0x10, 0x10, 0x90, 0x7e, 0x41, 0xe0, 0x13, 0x92, 0x9b, 0xa3,
+  0xe0, 0xf5, 0x99, 0x75, 0x3a, 0x03, 0x80, 0x09, 0x90, 0x7e, 0x41, 0xe0, 0xf5, 0x99, 0x75, 0x3a,
+  0x02, 0xe5, 0x3a, 0xc3, 0x95, 0x53, 0x40, 0x17, 0x90, 0x7f, 0xc7, 0xe4, 0xf0, 0xc2, 0x03}},
+ {0x0186, 64, { 0x20, 0x0d, 0x03, 0x02, 0x04, 0x1c, 0xc2, 0x0d, 0x90, 0x7f, 0xbb, 0x04, 0xf0, 0x02, 0x04, 0x1c, 0x30,
+  0x10, 0x12, 0xaf, 0x3a, 0x05, 0x3a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83,
+  0xe0, 0x13, 0x92, 0x0e, 0xaf, 0x3a, 0x05, 0x3a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e,
+  0xf5, 0x83, 0xe0, 0xf5, 0x36, 0xd2, 0x0b, 0x02, 0x04, 0x1c, 0x75, 0x3a, 0x01, 0xc2, 0x14}},
+ {0x01c6, 64, { 0x02, 0x04, 0x1c, 0x30, 0x0c, 0x03, 0x02, 0x02, 0x49, 0x20, 0x09, 0x77, 0x90, 0x7f, 0x9b, 0xe0, 0x55,
+  0x38, 0x70, 0x6f, 0x30, 0x10, 0x12, 0xaf, 0x3a, 0x05, 0x3a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4,
+  0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x9b, 0xaf, 0x3a, 0x05, 0x3a, 0x74, 0x40, 0x2f, 0xf5,
+  0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5, 0x99, 0xe5, 0x3a, 0xc3, 0x95, 0x53, 0x40}},
+ {0x0206, 64, { 0x17, 0x90, 0x7f, 0xc7, 0xe4, 0xf0, 0xc2, 0x03, 0x20, 0x0d, 0x03, 0x02, 0x04, 0x1c, 0xc2, 0x0d, 0x90,
+  0x7f, 0xbb, 0x04, 0xf0, 0x02, 0x04, 0x1c, 0x30, 0x10, 0x12, 0xaf, 0x3a, 0x05, 0x3a, 0x74, 0x40,
+  0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x0e, 0xaf, 0x3a, 0x05, 0x3a,
+  0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5, 0x36, 0xd2, 0x0b}},
+ {0x0246, 64, { 0x02, 0x04, 0x1c, 0xc2, 0x14, 0x02, 0x04, 0x1c, 0x20, 0x0b, 0x03, 0x02, 0x02, 0xff, 0xe5, 0x3a, 0xc3,
+  0x95, 0x53, 0x50, 0x3c, 0x20, 0x0c, 0x34, 0x20, 0x09, 0x31, 0x90, 0x7f, 0x9b, 0xe0, 0x55, 0x38,
+  0x70, 0x29, 0x30, 0x10, 0x12, 0xaf, 0x3a, 0x05, 0x3a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34,
+  0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x0e, 0xaf, 0x3a, 0x05, 0x3a, 0x74, 0xc0, 0x2f, 0xf5}},
+ {0x0286, 64, { 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x36, 0x02, 0x04, 0x1c, 0xc2, 0x0b, 0x02, 0x04, 0x1c,
+  0x90, 0x7f, 0xc9, 0xe4, 0xf0, 0xd2, 0x03, 0x30, 0x0d, 0x0c, 0xc2, 0x0d, 0x90, 0x7f, 0xbb, 0x04,
+  0xf0, 0xc2, 0x0b, 0x02, 0x04, 0x1c, 0x90, 0x7f, 0xc6, 0xe0, 0x30, 0xe1, 0x05, 0xc2, 0x0b, 0x02,
+  0x04, 0x1c, 0x90, 0x7f, 0xc7, 0xe0, 0xf5, 0x53, 0x90, 0x7e, 0x40, 0xe0, 0x13, 0x92, 0x0d}},
+ {0x02c6, 64, { 0x75, 0x16, 0xff, 0x20, 0x0c, 0x2b, 0x20, 0x09, 0x28, 0x90, 0x7f, 0x9b, 0xe0, 0x55, 0x38, 0x70, 0x20,
+  0x30, 0x10, 0x11, 0x90, 0x7e, 0x41, 0xe0, 0x13, 0x92, 0x0e, 0xa3, 0xe0, 0xf5, 0x36, 0x75, 0x3a,
+  0x03, 0x02, 0x04, 0x1c, 0x75, 0x3a, 0x02, 0x90, 0x7e, 0x41, 0xe0, 0xf5, 0x36, 0x02, 0x04, 0x1c,
+  0x75, 0x3a, 0x01, 0xc2, 0x0b, 0x02, 0x04, 0x1c, 0xe5, 0x3a, 0xc3, 0x95, 0x53, 0x50, 0x03}},
+ {0x0306, 64, { 0x02, 0x03, 0xa2, 0x90, 0x7f, 0xc8, 0xe0, 0x30, 0xe1, 0x07, 0xc2, 0x14, 0xc2, 0x05, 0x02, 0x04, 0x1c,
+  0x90, 0x7f, 0xc9, 0xe0, 0xf5, 0x53, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x0d, 0x75, 0x16, 0xff,
+  0x20, 0x0c, 0x70, 0x20, 0x09, 0x6d, 0x90, 0x7f, 0x9b, 0xe0, 0x55, 0x38, 0x70, 0x65, 0x30, 0x10,
+  0x10, 0x90, 0x7d, 0xc1, 0xe0, 0x13, 0x92, 0x9b, 0xa3, 0xe0, 0xf5, 0x99, 0x75, 0x3a, 0x03}},
+ {0x0346, 64, { 0x80, 0x09, 0x90, 0x7d, 0xc1, 0xe0, 0xf5, 0x99, 0x75, 0x3a, 0x02, 0xe5, 0x3a, 0xc3, 0x95, 0x53, 0x40,
+  0x17, 0x90, 0x7f, 0xc9, 0xe4, 0xf0, 0xd2, 0x03, 0x20, 0x0d, 0x03, 0x02, 0x04, 0x1c, 0xc2, 0x0d,
+  0x90, 0x7f, 0xbb, 0x04, 0xf0, 0x02, 0x04, 0x1c, 0x30, 0x10, 0x12, 0xaf, 0x3a, 0x05, 0x3a, 0x74,
+  0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x0e, 0xaf, 0x3a}},
+ {0x0386, 64, { 0x05, 0x3a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x36, 0xd2, 0x0b,
+  0x02, 0x04, 0x1c, 0x75, 0x3a, 0x01, 0xc2, 0x14, 0x02, 0x04, 0x1c, 0x20, 0x0c, 0x75, 0x20, 0x09,
+  0x72, 0x90, 0x7f, 0x9b, 0xe0, 0x55, 0x38, 0x70, 0x6a, 0x30, 0x10, 0x12, 0xaf, 0x3a, 0x05, 0x3a,
+  0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x9b, 0xaf}},
+ {0x03c6, 64, { 0x3a, 0x05, 0x3a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x99, 0xe5,
+  0x3a, 0xc3, 0x95, 0x53, 0x40, 0x13, 0x90, 0x7f, 0xc9, 0xe4, 0xf0, 0xd2, 0x03, 0x30, 0x0d, 0x35,
+  0xc2, 0x0d, 0x90, 0x7f, 0xbb, 0x04, 0xf0, 0x80, 0x2c, 0x30, 0x10, 0x12, 0xaf, 0x3a, 0x05, 0x3a,
+  0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x0e, 0xaf}},
+ {0x0406, 64, { 0x3a, 0x05, 0x3a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x36, 0xd2,
+  0x0b, 0x80, 0x02, 0xc2, 0x14, 0xd2, 0x01, 0x20, 0x98, 0x03, 0x02, 0x05, 0x5a, 0xc2, 0x98, 0x20,
+  0x02, 0x03, 0x02, 0x04, 0xc7, 0x20, 0x16, 0x27, 0xaf, 0x39, 0x05, 0x39, 0x74, 0x80, 0x2f, 0xf5,
+  0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x99, 0xf0, 0x30, 0x10, 0x4d, 0xaf, 0x39, 0x05}},
+ {0x0446, 64, { 0x39, 0x74, 0x80, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x98, 0xf0, 0x80, 0x3a, 0x85,
+  0x99, 0x10, 0xe5, 0x10, 0xb5, 0x47, 0x04, 0xd2, 0x09, 0x80, 0x2e, 0xe5, 0x10, 0xb5, 0x46, 0x04,
+  0xc2, 0x09, 0x80, 0x25, 0xaf, 0x39, 0x05, 0x39, 0x74, 0x80, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e,
+  0xf5, 0x83, 0xe5, 0x10, 0xf0, 0x30, 0x10, 0x11, 0xaf, 0x39, 0x05, 0x39, 0x74, 0x80, 0x2f}},
+ {0x0486, 64, { 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x98, 0xf0, 0xd2, 0x0f, 0xe5, 0x39, 0xc3, 0x95, 0x43,
+  0x50, 0x03, 0x02, 0x05, 0x58, 0x90, 0x7f, 0xb8, 0xe0, 0x30, 0xe1, 0x16, 0xe5, 0x39, 0xc3, 0x94,
+  0x40, 0x50, 0x03, 0x02, 0x05, 0x58, 0x15, 0x39, 0x15, 0x39, 0x05, 0x2b, 0x43, 0x34, 0x01, 0x02,
+  0x05, 0x58, 0x90, 0x7f, 0xb7, 0xe5, 0x39, 0xf0, 0x75, 0x39, 0x00, 0xc2, 0x02, 0x02, 0x05}},
+ {0x04c6, 64, { 0x58, 0x20, 0x16, 0x27, 0xaf, 0x39, 0x05, 0x39, 0x74, 0x00, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5,
+  0x83, 0xe5, 0x99, 0xf0, 0x30, 0x10, 0x4d, 0xaf, 0x39, 0x05, 0x39, 0x74, 0x00, 0x2f, 0xf5, 0x82,
+  0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x98, 0xf0, 0x80, 0x3a, 0x85, 0x99, 0x10, 0xe5, 0x10, 0xb5,
+  0x47, 0x04, 0xd2, 0x09, 0x80, 0x2e, 0xe5, 0x10, 0xb5, 0x46, 0x04, 0xc2, 0x09, 0x80, 0x25}},
+ {0x0506, 64, { 0xaf, 0x39, 0x05, 0x39, 0x74, 0x00, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x10, 0xf0,
+  0x30, 0x10, 0x11, 0xaf, 0x39, 0x05, 0x39, 0x74, 0x00, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5,
+  0x83, 0xe5, 0x98, 0xf0, 0xd2, 0x0f, 0xe5, 0x39, 0xc3, 0x95, 0x43, 0x40, 0x24, 0x90, 0x7f, 0xb6,
+  0xe0, 0x30, 0xe1, 0x12, 0xe5, 0x39, 0xc3, 0x94, 0x40, 0x40, 0x16, 0x15, 0x39, 0x15, 0x39}},
+ {0x0546, 64, { 0x05, 0x2b, 0x43, 0x34, 0x01, 0x80, 0x0b, 0x90, 0x7f, 0xb9, 0xe5, 0x39, 0xf0, 0x75, 0x39, 0x00, 0xd2,
+  0x02, 0xd2, 0x01, 0x30, 0x01, 0x05, 0xc2, 0x01, 0x02, 0x00, 0x56, 0xd0, 0xd0, 0xd0, 0x86, 0xd0,
+  0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7f, 0xbc, 0xe0, 0x20, 0xe1, 0x51, 0xe5, 0x34, 0x60,
+  0x4d, 0xe5, 0x31, 0x70, 0x49, 0xe5, 0x34, 0x30, 0xe1, 0x08, 0xe4, 0xf5, 0x2f, 0x75, 0x34}},
+ {0x0586, 64, { 0x01, 0x80, 0x0b, 0xa2, 0x08, 0xe4, 0x33, 0xf5, 0x2f, 0xc2, 0x08, 0xe4, 0xf5, 0x34, 0xe4, 0xf5, 0x11,
+  0x7e, 0x00, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x11, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0d, 0x06,
+  0xff, 0x74, 0x00, 0x25, 0x11, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x11,
+  0xe5, 0x11, 0xb4, 0x0c, 0xdb, 0x90, 0x7f, 0xbd, 0x74, 0x0c, 0xf0, 0x75, 0x31, 0x10, 0x90}},
+ {0x05c6, 64, { 0x7f, 0xca, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x06, 0xf3, 0xe4, 0xf5, 0x11, 0x74, 0x40, 0x25, 0x11, 0xf5,
+  0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x11, 0x7c, 0x00, 0x7b, 0x00, 0x24, 0x3b,
+  0xf9, 0xec, 0x34, 0x00, 0xfa, 0xef, 0x12, 0x0d, 0x1f, 0x05, 0x11, 0xe5, 0x11, 0xb4, 0x18, 0xdb,
+  0xe5, 0x3b, 0x60, 0x11, 0x75, 0xc9, 0x20, 0x75, 0xc8, 0x36, 0x85, 0x3c, 0xca, 0x85, 0x3d}},
+ {0x0606, 64, { 0xcb, 0xe4, 0x90, 0x7f, 0x9f, 0xf0, 0xe5, 0x3e, 0x13, 0x92, 0x10, 0x92, 0x9f, 0x85, 0x3f, 0x38, 0xe5,
+  0x40, 0x13, 0x92, 0x16, 0xe5, 0x41, 0x60, 0x09, 0x90, 0x7f, 0x98, 0xe0, 0x54, 0xfb, 0xf0, 0x80,
+  0x07, 0x90, 0x7f, 0x98, 0xe0, 0x44, 0x04, 0xf0, 0xe5, 0x42, 0x60, 0x09, 0x90, 0x7f, 0x98, 0xe0,
+  0x54, 0x7f, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0x98, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x48, 0x60}},
+ {0x0646, 64, { 0x0b, 0xc2, 0x0c, 0xc2, 0x09, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x49, 0x60, 0x0c, 0xd2,
+  0x09, 0x43, 0x34, 0x01, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x4a, 0x60, 0x0d, 0xc2,
+  0xaf, 0xc2, 0x0b, 0xd2, 0x00, 0xe4, 0xf5, 0x53, 0xf5, 0x3a, 0xd2, 0xaf, 0xe5, 0x4b, 0x60, 0x05,
+  0x30, 0x16, 0x02, 0xd2, 0x09, 0xe5, 0x4c, 0x60, 0x15, 0x90, 0x7f, 0x95, 0xe0, 0x54, 0xfd}},
+ {0x0686, 64, { 0xf0, 0x90, 0x7f, 0x9e, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0x7f, 0x98, 0xe0, 0x54, 0xfd, 0xf0, 0xe5, 0x4d,
+  0x60, 0x0a, 0xd2, 0x9c, 0xc2, 0x98, 0x75, 0x2c, 0x01, 0x75, 0x31, 0x1e, 0xe5, 0x4e, 0x60, 0x07,
+  0xc2, 0x9c, 0xe4, 0xf5, 0x39, 0xf5, 0x2c, 0xe5, 0x4f, 0x60, 0x03, 0xe4, 0xf5, 0x39, 0xe5, 0x50,
+  0x60, 0x02, 0xd2, 0x07, 0xe5, 0x51, 0x60, 0x0a, 0xe5, 0x4d, 0x70, 0x02, 0xf5, 0x31, 0xe5}},
+ {0x06c6, 64, { 0x51, 0x42, 0x34, 0xe5, 0x52, 0x60, 0x1f, 0x90, 0x7f, 0xd7, 0x74, 0x11, 0xf0, 0x74, 0x31, 0xf0, 0x74,
+  0x12, 0xf0, 0x74, 0x32, 0xf0, 0x74, 0x13, 0xf0, 0x74, 0x33, 0xf0, 0x74, 0x14, 0xf0, 0x74, 0x34,
+  0xf0, 0xd2, 0x03, 0xd2, 0x02, 0xd2, 0x08, 0xe4, 0x90, 0x7f, 0xcb, 0xf0, 0xa2, 0x0c, 0xe4, 0x33,
+  0xff, 0x65, 0x29, 0x60, 0x05, 0x8f, 0x29, 0x43, 0x34, 0x01, 0xa2, 0x09, 0xe4, 0x33, 0xff}},
+ {0x0706, 64, { 0x65, 0x2a, 0x60, 0x05, 0x8f, 0x2a, 0x43, 0x34, 0x01, 0x90, 0x7f, 0x9b, 0xe0, 0xff, 0x54, 0x08, 0x64,
+  0x08, 0xfe, 0x65, 0x25, 0x60, 0x05, 0x8e, 0x25, 0x43, 0x34, 0x01, 0xef, 0x54, 0x10, 0x64, 0x10,
+  0xfe, 0x65, 0x26, 0x60, 0x05, 0x8e, 0x26, 0x43, 0x34, 0x01, 0xef, 0x54, 0x40, 0x64, 0x40, 0xfe,
+  0x65, 0x27, 0x60, 0x05, 0x8e, 0x27, 0x43, 0x34, 0x01, 0xef, 0x54, 0x20, 0x64, 0x20, 0xfe}},
+ {0x0746, 64, { 0x65, 0x28, 0x60, 0x05, 0x8e, 0x28, 0x43, 0x34, 0x01, 0x90, 0x7f, 0x9a, 0xe0, 0x54, 0x40, 0x64, 0x40,
+  0xfe, 0x65, 0x2e, 0x60, 0x05, 0x8e, 0x2e, 0x43, 0x34, 0x01, 0x30, 0x07, 0x35, 0xc2, 0xaf, 0x30,
+  0x02, 0x18, 0x90, 0x7f, 0xb8, 0xe0, 0x20, 0xe1, 0x27, 0xe5, 0x39, 0x60, 0x09, 0x90, 0x7f, 0xb7,
+  0xf0, 0xe4, 0xf5, 0x39, 0xc2, 0x02, 0xc2, 0x07, 0x80, 0x16, 0x90, 0x7f, 0xb6, 0xe0, 0x20}},
+ {0x0786, 64, { 0xe1, 0x0f, 0xe5, 0x39, 0x60, 0x09, 0x90, 0x7f, 0xb9, 0xf0, 0xe4, 0xf5, 0x39, 0xd2, 0x02, 0xc2, 0x07,
+  0xd2, 0xaf, 0x20, 0x05, 0x3d, 0x30, 0x03, 0x1e, 0x90, 0x7f, 0xc6, 0xe0, 0x20, 0xe1, 0x33, 0x90,
+  0x7e, 0x40, 0xe0, 0x13, 0x92, 0x0d, 0x75, 0x3a, 0x01, 0x90, 0x7f, 0xc7, 0xe0, 0xf5, 0x53, 0xd2,
+  0x05, 0x75, 0x16, 0xff, 0x80, 0x1c, 0x90, 0x7f, 0xc8, 0xe0, 0x20, 0xe1, 0x15, 0x90, 0x7d}},
+ {0x07c6, 64, { 0xc0, 0xe0, 0x13, 0x92, 0x0d, 0x75, 0x3a, 0x01, 0x90, 0x7f, 0xc9, 0xe0, 0xf5, 0x53, 0xd2, 0x05, 0x75,
+  0x16, 0xff, 0x20, 0x14, 0x33, 0x20, 0x00, 0x06, 0xe5, 0x3a, 0x65, 0x53, 0x70, 0x2a, 0x30, 0x05,
+  0x1a, 0x30, 0x03, 0x09, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0xc2, 0x03, 0x80, 0x07, 0xe4, 0x90, 0x7f,
+  0xc9, 0xf0, 0xd2, 0x03, 0xc2, 0x05, 0xe4, 0xf5, 0x53, 0xf5, 0x3a, 0x30, 0x0d, 0x0a, 0xc2}},
+ {0x0806, 64, { 0x0d, 0xc2, 0x00, 0x90, 0x7f, 0xbb, 0x74, 0x01, 0xf0, 0x30, 0x14, 0x03, 0x02, 0x09, 0x14, 0x20, 0x05,
+  0x03, 0x02, 0x09, 0x14, 0x30, 0x0c, 0x03, 0x02, 0x09, 0x14, 0x30, 0x09, 0x03, 0x02, 0x09, 0x14,
+  0x90, 0x7f, 0x9b, 0xe0, 0x55, 0x38, 0x60, 0x03, 0x02, 0x09, 0x14, 0x30, 0x03, 0x61, 0x30, 0x10,
+  0x12, 0xaf, 0x3a, 0x05, 0x3a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83}},
+ {0x0846, 64, { 0xe0, 0x13, 0x92, 0x1b, 0xaf, 0x3a, 0x05, 0x3a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5,
+  0x83, 0xe0, 0xfe, 0xe5, 0x3a, 0xc3, 0x95, 0x53, 0x50, 0x2a, 0x30, 0x10, 0x12, 0xaf, 0x3a, 0x05,
+  0x3a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x0e, 0xaf,
+  0x3a, 0x05, 0x3a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5}},
+ {0x0886, 64, { 0x36, 0xd2, 0x0b, 0x80, 0x6a, 0xc2, 0x0b, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0xc2, 0x03, 0x80, 0x5f, 0x30,
+  0x10, 0x12, 0xaf, 0x3a, 0x05, 0x3a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83,
+  0xe0, 0x13, 0x92, 0x1b, 0xaf, 0x3a, 0x05, 0x3a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d,
+  0xf5, 0x83, 0xe0, 0xfe, 0xe5, 0x3a, 0xc3, 0x95, 0x53, 0x50, 0x2a, 0x30, 0x10, 0x12, 0xaf}},
+ {0x08c6, 64, { 0x3a, 0x05, 0x3a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x0e,
+  0xaf, 0x3a, 0x05, 0x3a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5,
+  0x36, 0xd2, 0x0b, 0x80, 0x09, 0xc2, 0x0b, 0xe4, 0x90, 0x7f, 0xc9, 0xf0, 0xd2, 0x03, 0x30, 0x10,
+  0x04, 0xa2, 0x1b, 0x92, 0x9b, 0xd2, 0x14, 0xc2, 0xaf, 0x8e, 0x99, 0x20, 0x0b, 0x0d, 0x30}},
+ {0x0906, 64, { 0x0d, 0x0a, 0xc2, 0x0d, 0xc2, 0x00, 0x90, 0x7f, 0xbb, 0x74, 0x01, 0xf0, 0xd2, 0xaf, 0x22, 0x90, 0x7f,
+  0xe9, 0xe0, 0x12, 0x0d, 0x31, 0x0a, 0x11, 0x00, 0x0a, 0x7e, 0x01, 0x0a, 0xdb, 0x03, 0x09, 0x38,
+  0x06, 0x0a, 0x02, 0x08, 0x09, 0xf6, 0x09, 0x09, 0xde, 0x0a, 0x09, 0xed, 0x0b, 0x00, 0x00, 0x0b,
+  0x19, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x19, 0x14, 0x60, 0x5a, 0x24, 0x02, 0x60}},
+ {0x0946, 64, { 0x03, 0x02, 0x0b, 0x19, 0x74, 0x0d, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x87, 0x90, 0x7f, 0xd5, 0xf0, 0x02,
+  0x0b, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x04, 0x7f, 0x02, 0x80, 0x02, 0x7f, 0x03, 0x75, 0x82,
+  0xd8, 0x75, 0x83, 0x0d, 0xef, 0xf0, 0x75, 0x82, 0xd1, 0x75, 0x83, 0x0d, 0xf0, 0x75, 0x82, 0xca,
+  0x75, 0x83, 0x0d, 0xf0, 0x75, 0x82, 0xc3, 0x75, 0x83, 0x0d, 0xf0, 0x90, 0x7f, 0xea, 0xe0}},
+ {0x0986, 64, { 0x04, 0x75, 0x82, 0x9e, 0x75, 0x83, 0x0d, 0xf0, 0x74, 0x0d, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x99, 0x90,
+  0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x0b, 0x75, 0x11, 0xff, 0x75,
+  0x12, 0x0d, 0x75, 0x13, 0xdc, 0x80, 0x1b, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x0b, 0x75, 0x11,
+  0xff, 0x75, 0x12, 0x0d, 0x75, 0x13, 0xe0, 0x80, 0x09, 0x75, 0x11, 0xff, 0x75, 0x12, 0x0d}},
+ {0x09c6, 64, { 0x75, 0x13, 0xf0, 0xaa, 0x12, 0xa9, 0x13, 0xae, 0x02, 0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef,
+  0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x20, 0x90, 0x7f, 0x00, 0xe5, 0x15, 0xf0, 0x90, 0x7f, 0xb5,
+  0x74, 0x01, 0xf0, 0x02, 0x0b, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x15, 0x02, 0x0b, 0x20, 0x12,
+  0x0c, 0xb1, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x14, 0x02, 0x0b, 0x20, 0x90, 0x7f, 0x00, 0xe5}},
+ {0x0a06, 64, { 0x14, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x0b, 0x20, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f,
+  0x60, 0x27, 0x14, 0x60, 0x34, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0b, 0x19, 0xa2, 0x17, 0xe4, 0x33,
+  0xff, 0x25, 0xe0, 0xff, 0xa2, 0x19, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0,
+  0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x20, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0xa3}},
+ {0x0a46, 64, { 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80,
+  0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4,
+  0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f,
+  0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x20, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x17}},
+ {0x0a86, 64, { 0x24, 0x02, 0x60, 0x03, 0x02, 0x0b, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0b,
+  0x19, 0xc2, 0x17, 0x02, 0x0b, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x76, 0x90, 0x7f, 0xec, 0xe0,
+  0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4,
+  0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80}},
+ {0x0ac6, 64, { 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44,
+  0x20, 0xf0, 0x80, 0x45, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x10, 0x24, 0x02, 0x70, 0x39,
+  0x90, 0x7f, 0xea, 0xe0, 0x64, 0x01, 0x70, 0x2a, 0xd2, 0x17, 0x80, 0x2d, 0x90, 0x7f, 0xea, 0xe0,
+  0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0}},
+ {0x0b06, 64, { 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0,
+  0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0,
+  0x22, 0xc2, 0x10, 0xe4, 0xf5, 0x14, 0xf5, 0x34, 0xc2, 0x09, 0xc2, 0x0c, 0xc2, 0x0b, 0xc2, 0x14,
+  0xc2, 0x0d, 0xc2, 0x16, 0xc2, 0x11, 0xc2, 0x07, 0xc2, 0x12, 0xc2, 0x0f, 0xc2, 0x08, 0xf5}},
+ {0x0b46, 64, { 0x35, 0xf5, 0x39, 0xf5, 0x53, 0xf5, 0x3a, 0xf5, 0x33, 0xf5, 0x30, 0xf5, 0x2f, 0xf5, 0x2e, 0xf5, 0x2d,
+  0xf5, 0x2c, 0xf5, 0x2b, 0xf5, 0x2a, 0xf5, 0x29, 0xf5, 0x28, 0xf5, 0x27, 0xf5, 0x26, 0xf5, 0x25,
+  0xf5, 0x24, 0xc2, 0x05, 0xc2, 0x18, 0xc2, 0x1a, 0xc2, 0x17, 0xc2, 0x19, 0xc2, 0x15, 0xc2, 0x04,
+  0xd2, 0x13, 0xc2, 0x06, 0xc2, 0x01, 0x90, 0x7f, 0x92, 0xe0, 0x54, 0xfd, 0xf0, 0xd2, 0xe8}},
+ {0x0b86, 64, { 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab, 0x74,
+  0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaf,
+  0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x0f, 0xf0, 0x90, 0x7f, 0xac, 0x74, 0x0e,
+  0xf0, 0xd2, 0xaf, 0xd2, 0xbc, 0xd2, 0x1b, 0x12, 0x0f, 0x5f, 0xc2, 0x18, 0x30, 0x04, 0x03}},
+ {0x0bc6, 64, { 0x12, 0x05, 0x6d, 0x30, 0x04, 0x2a, 0x30, 0x06, 0x27, 0xc2, 0x06, 0xe5, 0x16, 0x60, 0x16, 0x15, 0x16,
+  0x90, 0x7f, 0xd8, 0xe0, 0x30, 0xe6, 0x04, 0x7f, 0x00, 0x80, 0x02, 0x7f, 0x20, 0x90, 0x7f, 0x96,
+  0xef, 0xf0, 0x80, 0x06, 0x90, 0x7f, 0x96, 0x74, 0x20, 0xf0, 0x12, 0x0c, 0x0b, 0x80, 0xcd, 0x30,
+  0x18, 0x07, 0xc2, 0x18, 0x12, 0x09, 0x15, 0x80, 0xc3, 0x30, 0x1a, 0xc0, 0xc2, 0x1a, 0x12}},
+ {0x0c06, 64, { 0x0f, 0xbb, 0x80, 0xb9, 0x22, 0xe5, 0x31, 0x60, 0x02, 0x15, 0x31, 0xe5, 0x39, 0x60, 0x55, 0x65, 0x35,
+  0x70, 0x4b, 0xe5, 0x33, 0xf4, 0x60, 0x02, 0x05, 0x33, 0xe5, 0x33, 0xc3, 0x95, 0x44, 0x40, 0x43,
+  0xc2, 0xaf, 0x30, 0x02, 0x1b, 0x90, 0x7f, 0xb8, 0xe0, 0x20, 0xe1, 0x2d, 0x90, 0x7f, 0xb7, 0xe5,
+  0x39, 0xf0, 0xc2, 0x02, 0xe4, 0xf5, 0x39, 0xf5, 0x33, 0xf5, 0x35, 0x75, 0x16, 0xff, 0x80}},
+ {0x0c46, 64, { 0x19, 0x90, 0x7f, 0xb6, 0xe0, 0x20, 0xe1, 0x12, 0x90, 0x7f, 0xb9, 0xe5, 0x39, 0xf0, 0xd2, 0x02, 0xe4,
+  0xf5, 0x39, 0xf5, 0x33, 0xf5, 0x35, 0x75, 0x16, 0xff, 0xd2, 0xaf, 0x80, 0x06, 0x85, 0x39, 0x35,
+  0xe4, 0xf5, 0x33, 0xe5, 0x2c, 0x60, 0x30, 0x20, 0x0f, 0x07, 0x90, 0x7f, 0x9b, 0xe0, 0x30, 0xe0,
+  0x0f, 0xe5, 0x2d, 0x60, 0x06, 0xe4, 0xf5, 0x2d, 0x43, 0x34, 0x01, 0xe4, 0xf5, 0x30, 0x80}},
+ {0x0c86, 64, { 0x14, 0xe5, 0x30, 0xd3, 0x95, 0x45, 0x50, 0x0d, 0xe5, 0x30, 0xb5, 0x45, 0x06, 0x75, 0x2d, 0x01, 0x43,
+  0x34, 0x01, 0x05, 0x30, 0xc2, 0x0f, 0x22, 0x90, 0x7f, 0xd9, 0xe0, 0x30, 0xe2, 0x04, 0x7f, 0x00,
+  0x80, 0x02, 0x7f, 0x20, 0x90, 0x7f, 0x96, 0xef, 0xf0, 0x22, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90,
+  0x7f, 0x9c, 0x74, 0x30, 0xf0, 0x90, 0x7f, 0x96, 0x74, 0x20, 0xf0, 0x90, 0x7f, 0x94, 0x74}},
+ {0x0cc6, 64, { 0x01, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x97, 0x74, 0x86, 0xf0, 0x90, 0x7f, 0x95,
+  0x74, 0x03, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x84, 0xf0, 0x90, 0x7f, 0x98, 0xf0, 0xe4, 0x90, 0x7f,
+  0xc7, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0x90, 0x7f, 0xcb, 0xf0, 0x75, 0x98, 0x40, 0x43, 0xa8, 0x10,
+  0x90, 0x7f, 0xde, 0x74, 0x1f, 0xf0, 0x90, 0x7f, 0xdf, 0x74, 0x0f, 0xf0, 0xd2, 0x04, 0x22}},
+ {0x0d06, 64, { 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02, 0xe3,
+  0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0,
+  0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4,
+  0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01, 0x93}},
+ {0x0d46, 64, { 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf,
+  0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90,
+  0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0,
+  0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x0d86, 64, { 0x00, 0x12, 0x01, 0x10, 0x01, 0xff, 0x00, 0x00, 0x40, 0xcd, 0x06, 0x0c, 0x01, 0x01, 0x00, 0x01, 0x02,
+  0x00, 0x02, 0x09, 0x02, 0x43, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00, 0x00, 0x07,
+  0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40,
+  0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00}},
+ {0x0dc6, 64, { 0x01, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05,
+  0x84, 0x02, 0x40, 0x00, 0x01, 0x04, 0x03, 0x09, 0x04, 0x10, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79,
+  0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x0e, 0x03, 0x53, 0x00, 0x65, 0x00, 0x72,
+  0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x02, 0x0e, 0xa2, 0x00, 0x02, 0x0e}},
+ {0x0e06, 64, { 0x7b, 0x00, 0x02, 0x0d, 0x57, 0x00, 0x02, 0x0e, 0xc9, 0x00, 0x02, 0x0e, 0x10, 0x00, 0x02, 0x0e, 0x14,
+  0x00, 0x02, 0x0e, 0x18, 0x00, 0x02, 0x0e, 0x1c, 0x00, 0x02, 0x0e, 0xf0, 0x00, 0x02, 0x0e, 0x24,
+  0x00, 0x02, 0x0f, 0x15, 0x00, 0x02, 0x0e, 0x2c, 0x00, 0x02, 0x0f, 0x3a, 0xe4, 0x90, 0x7f, 0x95,
+  0xf0, 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9d, 0xe0, 0x44, 0x02}},
+ {0x0e46, 64, { 0xf0, 0x90, 0x7f, 0x97, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x10, 0xf0, 0xe4, 0x90, 0x7f,
+  0x96, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xfe, 0xf0, 0x30, 0x17, 0x04, 0x7f, 0x80, 0x80, 0x02, 0x7f,
+  0x00, 0x90, 0x7f, 0x97, 0xef, 0xf0, 0xe4, 0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0xf0, 0x90,
+  0x7f, 0x98, 0xf0, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0}},
+ {0x0e86, 64, { 0x86, 0x75, 0x86, 0x00, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0xd2, 0x06, 0xd0, 0x86,
+  0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0,
+  0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x18, 0x53, 0x91, 0xef, 0x90,
+  0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83}},
+ {0x0ec6, 64, { 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86,
+  0x00, 0xd2, 0x1a, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08, 0xf0, 0xd0, 0x86, 0xd0, 0x84,
+  0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0,
+  0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74}},
+ {0x0f06, 64, { 0x02, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0,
+  0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53, 0x91, 0xef,
+  0x90, 0x7f, 0xa9, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83,
+  0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86}},
+ {0x0f46, 64, { 0x75, 0x86, 0x00, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x08, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0,
+  0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0,
+  0x44, 0x08, 0xf0, 0x30, 0x1b, 0x04, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x00,
+  0x03, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0, 0xe0, 0x44, 0x04, 0xf0, 0x22, 0x74, 0x00}},
+ {0x0f86, 64, { 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9, 0x22, 0x90, 0x7f,
+  0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x90, 0x7f,
+  0xd6, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x0d, 0x7e, 0x00, 0x12, 0x00, 0x03, 0x90, 0x7f, 0xd6, 0xe0,
+  0x54, 0xfe, 0xf0, 0x22, 0x12, 0x0e, 0x33, 0x12, 0x0f, 0x95, 0x90, 0x7f, 0xd6, 0xe0, 0x30}},
+ {0x0fc6,  9, { 0xe7, 0x03, 0x12, 0x0f, 0xa5, 0x12, 0x0c, 0xb1, 0x22}},
+ {0xffff,	0,	{0x00}}
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/keyspan_usa19qw_fw.h linux-2.4.20/drivers/usb/serial/keyspan_usa19qw_fw.h
--- linux-2.4.19/drivers/usb/serial/keyspan_usa19qw_fw.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/keyspan_usa19qw_fw.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,448 @@
+/* keyspan_usa19qw_fw.h
+
+	The firmware contained herein as keyspan_usa19wq_fw.h is
+
+		Copyright (C) 1999-2001
+		Keyspan, A division of InnoSys Incorporated ("Keyspan")
+		
+	as an unpublished work. This notice does not imply unrestricted or
+	public access to the source code from which this firmware image is
+	derived.  Except as noted below this firmware image may not be 
+	reproduced, used, sold or transferred to any third party without 
+	Keyspan's prior written consent.  All Rights Reserved.
+
+	Permission is hereby granted for the distribution of this firmware 
+	image as part of a Linux or other Open Source operating system kernel 
+	in text or binary form as required. 
+
+	This firmware may not be modified and may only be used with  
+	Keyspan hardware.  Distribution and/or Modification of the 
+	keyspan.c driver which includes this firmware, in whole or in 
+	part, requires the inclusion of this statement."
+
+*/
+
+static const struct ezusb_hex_record keyspan_usa19qw_firmware[] = {
+ {0x0033,  3, { 0x02, 0x00, 0x2d}},
+ {0x002d,  4, { 0x53, 0xd8, 0xef, 0x32}},
+ {0x0046, 16, { 0x30, 0x10, 0x19, 0x12, 0x0e, 0x0f, 0xef, 0xc3, 0x95, 0x14, 0x40, 0x03, 0x02, 0x00, 0xdf, 0x90}},
+ {0x0056, 16, { 0x7f, 0xbf, 0x74, 0x01, 0xf0, 0xc2, 0x10, 0xc2, 0x0b, 0x02, 0x00, 0xdf, 0x30, 0x0d, 0x3e, 0x90}},
+ {0x0066, 16, { 0x7f, 0xc6, 0xe0, 0x20, 0xe1, 0x73, 0x12, 0x0e, 0x0f, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x6a, 0x90}},
+ {0x0076, 16, { 0x7e, 0x40, 0xe0, 0x13, 0x92, 0x10, 0x90, 0x7f, 0xc7, 0xe0, 0x14, 0xf5, 0x36, 0x20, 0x0b, 0x11}},
+ {0x0086, 16, { 0x60, 0x0f, 0xf5, 0x24, 0x7e, 0x7e, 0x7f, 0x41, 0x75, 0x29, 0x7e, 0x75, 0x2a, 0x41, 0x12, 0x09}},
+ {0x0096, 16, { 0x10, 0xc2, 0x0d, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0x75, 0x26, 0xff, 0x80, 0x3c, 0x90, 0x7f, 0xc8}},
+ {0x00a6, 16, { 0xe0, 0x20, 0xe1, 0x35, 0x12, 0x0e, 0x0f, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x2c, 0x90, 0x7d, 0xc0}},
+ {0x00b6, 16, { 0xe0, 0x13, 0x92, 0x10, 0x90, 0x7f, 0xc9, 0xe0, 0x14, 0xf5, 0x36, 0x20, 0x0b, 0x11, 0x60, 0x0f}},
+ {0x00c6, 16, { 0xf5, 0x24, 0x7e, 0x7d, 0x7f, 0xc1, 0x75, 0x29, 0x7d, 0x75, 0x2a, 0xc1, 0x12, 0x09, 0x10, 0xd2}},
+ {0x00d6, 16, { 0x0d, 0xe4, 0x90, 0x7f, 0xc9, 0xf0, 0x75, 0x26, 0xff, 0x90, 0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x03}},
+ {0x00e6, 16, { 0x02, 0x01, 0x68, 0x12, 0x0c, 0xff, 0x8f, 0x36, 0x12, 0x0e, 0x1b, 0x8f, 0x11, 0xe5, 0x36, 0xc3}},
+ {0x00f6, 16, { 0x95, 0x13, 0x50, 0x0f, 0x12, 0x0d, 0xde, 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x11, 0x20, 0xe7, 0x03}},
+ {0x0036, 12, { 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22}},
+ {0x0043,  3, { 0x02, 0x0e, 0x00}},
+ {0x0003, 16, { 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90}},
+ {0x0013, 16, { 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0}},
+ {0x0023, 10, { 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32}},
+ {0x0000,  3, { 0x02, 0x09, 0xc5}},
+ {0x0106, 64, { 0x30, 0x13, 0x5f, 0xc2, 0x13, 0xe5, 0x36, 0x60, 0x59, 0xb4, 0x80, 0x03, 0x43, 0x11, 0x02, 0xe5, 0x11,
+  0x30, 0xe7, 0x24, 0xe5, 0x36, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x36, 0x20, 0x85, 0x36, 0x24,
+  0x7e, 0x7e, 0x7f, 0x80, 0x75, 0x29, 0x7e, 0x75, 0x2a, 0x80, 0x12, 0x0b, 0x9a, 0xe5, 0x36, 0x25,
+  0xe0, 0x90, 0x7f, 0xb7, 0xf0, 0x80, 0x2a, 0xe5, 0x36, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75}},
+ {0x0146, 64, { 0x36, 0x3f, 0x85, 0x36, 0x24, 0x90, 0x7e, 0x80, 0xe5, 0x11, 0xf0, 0x7e, 0x7e, 0x7f, 0x81, 0x75, 0x29,
+  0x7e, 0x75, 0x2a, 0x81, 0x12, 0x09, 0x35, 0xe5, 0x36, 0x04, 0x90, 0x7f, 0xb7, 0xf0, 0x75, 0x26,
+  0xff, 0x90, 0x7f, 0xce, 0xe0, 0x30, 0xe1, 0x06, 0x20, 0x0e, 0x03, 0x02, 0x03, 0xc4, 0xe4, 0xf5,
+  0x35, 0x74, 0x40, 0x25, 0x35, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xff, 0xe5}},
+ {0x0186, 64, { 0x35, 0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e, 0x79, 0x00, 0x24, 0x00, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef,
+  0x12, 0x0a, 0x97, 0x05, 0x35, 0xe5, 0x35, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x00, 0xe0, 0x60, 0x6e,
+  0x7f, 0x01, 0x90, 0x7e, 0x11, 0xe0, 0xfd, 0x12, 0x0c, 0xda, 0x90, 0x7e, 0x01, 0xe0, 0xff, 0x12,
+  0x0c, 0x1c, 0x90, 0x7e, 0x02, 0xe0, 0xff, 0x12, 0x0c, 0x42, 0xd2, 0x11, 0xd2, 0x12, 0x75}},
+ {0x01c6, 64, { 0x36, 0x04, 0x90, 0x7e, 0x03, 0xe0, 0x60, 0x05, 0xc2, 0x12, 0x43, 0x36, 0xc0, 0x90, 0x7e, 0x04, 0xe0,
+  0xb4, 0x01, 0x07, 0xc2, 0x12, 0x43, 0x36, 0x0b, 0x80, 0x10, 0x90, 0x7e, 0x04, 0xe0, 0x60, 0x07,
+  0xc2, 0x11, 0x43, 0x36, 0x09, 0x80, 0x03, 0x43, 0x36, 0x02, 0x7f, 0x03, 0xad, 0x36, 0x12, 0x0c,
+  0xda, 0x43, 0x1a, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x1a}},
+ {0x0206, 64, { 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x17, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e,
+  0x05, 0xe0, 0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f, 0xf5, 0x19, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0,
+  0x90, 0xc0, 0x00, 0xe5, 0x19, 0xf0, 0x90, 0x7e, 0x07, 0xe0, 0x60, 0x42, 0x90, 0x7e, 0x13, 0xe0,
+  0x60, 0x05, 0x43, 0x16, 0x04, 0x80, 0x03, 0x53, 0x16, 0xfb, 0xe4, 0xff, 0xad, 0x16, 0x12}},
+ {0x0246, 64, { 0x0c, 0xda, 0x90, 0x7e, 0x08, 0xe0, 0x60, 0x05, 0x43, 0x18, 0x80, 0x80, 0x03, 0x53, 0x18, 0x7f, 0x53,
+  0x18, 0xfc, 0x90, 0x7e, 0x09, 0xe0, 0x60, 0x11, 0x43, 0x18, 0x02, 0xa3, 0xe0, 0xff, 0x12, 0x0c,
+  0x8e, 0x90, 0x7e, 0x0b, 0xe0, 0xff, 0x12, 0x0c, 0xb4, 0xaf, 0x18, 0x12, 0x0c, 0x68, 0x90, 0x7e,
+  0x0e, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x1a, 0x01, 0x80, 0x03, 0x53, 0x1a}},
+ {0x0286, 64, { 0xfe, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x1a, 0xf0, 0x90, 0x7e, 0x0c, 0xe0,
+  0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x1a, 0x02, 0x80, 0x03, 0x53, 0x1a, 0xfd, 0x90, 0x7f,
+  0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x1a, 0xf0, 0x90, 0x7e, 0x12, 0xe0, 0xf5, 0x13,
+  0xa3, 0xe0, 0x13, 0x92, 0x14, 0xa3, 0xe0, 0xf5, 0x14, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x1a}},
+ {0x02c6, 64, { 0x10, 0x80, 0x03, 0x53, 0x1a, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x1a,
+  0xf0, 0x90, 0x7e, 0x16, 0xe0, 0x60, 0x32, 0x53, 0x19, 0xbf, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0,
+  0xe5, 0x19, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x12, 0x0d,
+  0xd2, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x16, 0xfd, 0xe4, 0xff, 0xad, 0x16}},
+ {0x0306, 64, { 0x12, 0x0c, 0xda, 0xe4, 0xf5, 0x0e, 0xf5, 0x0d, 0xd2, 0x0f, 0x90, 0x7e, 0x17, 0xe0, 0x60, 0x0f, 0x43,
+  0x16, 0x02, 0xe4, 0xff, 0xad, 0x16, 0x12, 0x0c, 0xda, 0x75, 0x0d, 0x01, 0xd2, 0x0f, 0x90, 0x7e,
+  0x18, 0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x17, 0x44, 0x04, 0x90, 0xc0,
+  0x00, 0xf0, 0xd2, 0x0b, 0x90, 0x7e, 0x19, 0xe0, 0x60, 0x11, 0x43, 0x19, 0x40, 0x90, 0x7f}},
+ {0x0346, 64, { 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x19, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1a, 0xe0, 0x60,
+  0x0f, 0x53, 0x16, 0xfe, 0xe4, 0xff, 0xad, 0x16, 0x12, 0x0c, 0xda, 0x75, 0x0f, 0x01, 0xd2, 0x0f,
+  0x90, 0x7e, 0x1b, 0xe0, 0x60, 0x0f, 0x43, 0x16, 0x01, 0xe4, 0xff, 0xad, 0x16, 0x12, 0x0c, 0xda,
+  0xe4, 0xf5, 0x0f, 0xd2, 0x0f, 0x90, 0x7e, 0x1c, 0xe0, 0x60, 0x0e, 0x90, 0x7f, 0x98, 0x74}},
+ {0x0386, 64, { 0x12, 0xf0, 0xe5, 0x17, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1d, 0xe0, 0x60, 0x02, 0xd2,
+  0x13, 0x90, 0x7e, 0x1e, 0xe0, 0x60, 0x08, 0x75, 0x10, 0x01, 0xe4, 0xf5, 0x12, 0xd2, 0x0f, 0x90,
+  0x7e, 0x1f, 0xe0, 0x60, 0x11, 0x90, 0x7f, 0xd7, 0x74, 0x11, 0xf0, 0x74, 0x31, 0xf0, 0x74, 0x15,
+  0xf0, 0x74, 0x35, 0xf0, 0xd2, 0x0d, 0xc2, 0x0e, 0xe4, 0x90, 0x7f, 0xcf, 0xf0, 0x30, 0x16}},
+ {0x03c6, 64, { 0x71, 0xe5, 0x12, 0x60, 0x02, 0x15, 0x12, 0xe5, 0x30, 0xd3, 0x94, 0x00, 0x40, 0x04, 0x15, 0x30, 0x80,
+  0x60, 0x75, 0x30, 0x0a, 0x12, 0x0d, 0xd2, 0xef, 0x54, 0x01, 0xf5, 0x36, 0x65, 0x0e, 0x60, 0x07,
+  0x85, 0x36, 0x0e, 0xd2, 0x0f, 0x80, 0x11, 0x12, 0x0e, 0x27, 0xef, 0x54, 0x10, 0xf5, 0x36, 0x65,
+  0x09, 0x60, 0x05, 0x85, 0x36, 0x09, 0xd2, 0x0f, 0x12, 0x0e, 0x27, 0xef, 0x54, 0x80, 0xf5}},
+ {0x0406, 64, { 0x36, 0x65, 0x0a, 0x60, 0x05, 0x85, 0x36, 0x0a, 0xd2, 0x0f, 0x12, 0x0e, 0x27, 0xef, 0x54, 0x20, 0xf5,
+  0x36, 0x65, 0x0b, 0x60, 0x08, 0x85, 0x36, 0x0b, 0x30, 0x11, 0x02, 0xd2, 0x0f, 0x12, 0x0e, 0x27,
+  0xef, 0x54, 0x40, 0xf5, 0x36, 0x65, 0x0c, 0x60, 0x08, 0x85, 0x36, 0x0c, 0x30, 0x12, 0x02, 0xd2,
+  0x0f, 0x30, 0x16, 0x2a, 0x90, 0x7f, 0xd2, 0xe0, 0x20, 0xe1, 0x23, 0x90, 0x7b, 0x40, 0xe0}},
+ {0x0446, 64, { 0x60, 0x09, 0xe0, 0xf5, 0x32, 0x90, 0x7b, 0x42, 0xe0, 0xf5, 0x33, 0x90, 0x7b, 0x41, 0xe0, 0x60, 0x09,
+  0x90, 0x7f, 0xd7, 0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0xe4, 0x90, 0x7f, 0xd3, 0xf0, 0x90, 0x7f,
+  0xc2, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x05, 0x29, 0xe5, 0x27, 0x70, 0x40, 0x30, 0x0f, 0x39, 0xe5,
+  0x12, 0x70, 0x35, 0xc2, 0x0f, 0xf5, 0x35, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x08, 0x25, 0x35}},
+ {0x0486, 64, { 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0a, 0x51, 0xff, 0x74, 0x80, 0x25, 0x35, 0xf5, 0x82, 0xe4, 0x34,
+  0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x35, 0xe5, 0x35, 0xb4, 0x09, 0xdb, 0x90, 0x7f, 0xc3, 0x74,
+  0x09, 0xf0, 0x75, 0x12, 0x10, 0xe4, 0xf5, 0x10, 0x75, 0x27, 0x02, 0x22, 0xe5, 0x27, 0x64, 0x02,
+  0x70, 0x36, 0x30, 0x05, 0x2f, 0xc2, 0x05, 0xf5, 0x35, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x2b}},
+ {0x04c6, 64, { 0x25, 0x35, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0a, 0x51, 0xff, 0x74, 0x80, 0x25, 0x35, 0xf5, 0x82,
+  0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x35, 0xe5, 0x35, 0xb4, 0x05, 0xdb, 0x90, 0x7f,
+  0xc3, 0x74, 0x05, 0xf0, 0x75, 0x27, 0x03, 0x22, 0xe5, 0x32, 0x60, 0x33, 0x75, 0x31, 0x03, 0x15,
+  0x32, 0xe4, 0xf5, 0x35, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x31, 0x25, 0x35, 0xf9, 0xee, 0x34}},
+ {0x0506, 64, { 0x00, 0xfa, 0x12, 0x0a, 0x51, 0xff, 0x74, 0x80, 0x25, 0x35, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83,
+  0xef, 0xf0, 0x05, 0x35, 0xe5, 0x35, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4,
+  0xf5, 0x27, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x0a, 0xa9, 0x06, 0x08, 0x00, 0x06, 0x7c, 0x01,
+  0x06, 0xe9, 0x03, 0x05, 0x4d, 0x06, 0x05, 0xf9, 0x08, 0x05, 0xed, 0x09, 0x05, 0xd5, 0x0a}},
+ {0x0546, 64, { 0x05, 0xe4, 0x0b, 0x00, 0x00, 0x07, 0x39, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60,
+  0x50, 0x24, 0x02, 0x70, 0x6f, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5,
+  0xf0, 0x02, 0x07, 0x40, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x04, 0x7f, 0x02, 0x80, 0x02, 0x7f, 0x03,
+  0x75, 0x82, 0x82, 0x75, 0x83, 0x19, 0xef, 0xf0, 0x75, 0x82, 0x74, 0x75, 0x83, 0x19, 0xf0}},
+ {0x0586, 64, { 0x75, 0x82, 0x58, 0x75, 0x83, 0x19, 0xf0, 0x90, 0x7f, 0xea, 0xe0, 0x04, 0x75, 0x82, 0x17, 0x75, 0x83,
+  0x19, 0xf0, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x12, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x07,
+  0x40, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0b, 0x1c, 0xea, 0x49, 0x60, 0x0d, 0xea, 0x90, 0x7f,
+  0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x07, 0x40, 0x90, 0x7f, 0xb4, 0xe0, 0x44}},
+ {0x05c6, 64, { 0x01, 0xf0, 0x02, 0x07, 0x40, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x07, 0x40, 0x90, 0x7f,
+  0x00, 0xe5, 0x25, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x07, 0x40, 0x90, 0x7f, 0xea,
+  0xe0, 0xf5, 0x25, 0x02, 0x07, 0x40, 0x12, 0x07, 0x48, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x23, 0x02,
+  0x07, 0x40, 0x90, 0x7f, 0x00, 0xe5, 0x23, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02}},
+ {0x0606, 64, { 0x07, 0x40, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b,
+  0xa2, 0x01, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x07, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00,
+  0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x07, 0x40, 0xe4, 0x90, 0x7f,
+  0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x07, 0x40, 0x90, 0x7f}},
+ {0x0646, 64, { 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24,
+  0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4,
+  0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x07, 0x40, 0x90, 0x7f, 0xb4, 0xe0, 0x44,
+  0x01, 0xf0, 0x02, 0x07, 0x40, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1e, 0x24, 0x02}},
+ {0x0686, 64, { 0x60, 0x03, 0x02, 0x07, 0x40, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x06, 0x12, 0x0d, 0xf9, 0x02, 0x07,
+  0x40, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x07, 0x40, 0x90, 0x7f, 0xea, 0xe0, 0x70,
+  0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07,
+  0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90}},
+ {0x06c6, 64, { 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90,
+  0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x60, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0,
+  0x80, 0x57, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x19, 0x24, 0x02, 0x70, 0x4b, 0x90, 0x7f,
+  0xea, 0xe0, 0xb4, 0x01, 0x05, 0x12, 0x0d, 0xf6, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44}},
+ {0x0706, 64, { 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80,
+  0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4,
+  0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0,
+  0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02}},
+ {0x0746, 64, { 0xf0, 0x22, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0x90, 0x7f, 0x96, 0x74,
+  0x20, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0xc0, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f,
+  0x98, 0x74, 0x10, 0xf0, 0xe4, 0xf5, 0x8e, 0x90, 0x7f, 0xdf, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xde,
+  0xf0, 0xe4, 0xf5, 0x08, 0x7f, 0x01, 0x7b, 0x00, 0x74, 0x08, 0x2f, 0xf9, 0xe4, 0x34, 0x00}},
+ {0x0786, 64, { 0xfa, 0xe4, 0x12, 0x0a, 0x97, 0x0f, 0xbf, 0x09, 0xee, 0x75, 0x13, 0x01, 0xe4, 0xf5, 0x12, 0xf5, 0x30,
+  0xf5, 0x11, 0xc2, 0x0f, 0xc2, 0x13, 0xc2, 0x0e, 0xc2, 0x0b, 0xc2, 0x10, 0xc2, 0x04, 0x90, 0x7f,
+  0x98, 0x74, 0x13, 0xf0, 0x75, 0x19, 0x03, 0x90, 0xc0, 0x00, 0x74, 0x03, 0xf0, 0x7f, 0x0c, 0xe4,
+  0xfd, 0x12, 0x0c, 0xda, 0x7f, 0x10, 0x8f, 0x18, 0x12, 0x0c, 0x68, 0x90, 0x7f, 0x98, 0x74}},
+ {0x07c6, 64, { 0x12, 0xf0, 0x7f, 0x01, 0x8f, 0x17, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x0f, 0xe4, 0xfd, 0x12,
+  0x0c, 0xda, 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x16, 0x12, 0x0c, 0xda, 0x90, 0x7f, 0x98,
+  0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x0c, 0xda, 0x7f,
+  0x01, 0x12, 0x0d, 0x6a, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x0c, 0xda, 0xe4, 0xff, 0xe5, 0x16}},
+ {0x0806, 64, { 0x54, 0x7f, 0xfd, 0x12, 0x0c, 0xda, 0x12, 0x0e, 0x0f, 0x8f, 0x15, 0xe4, 0xff, 0xe5, 0x16, 0x44, 0x80,
+  0xfd, 0x12, 0x0c, 0xda, 0xe5, 0x15, 0x30, 0xe7, 0x04, 0xc2, 0x08, 0x80, 0x02, 0xd2, 0x08, 0x90,
+  0x7f, 0x98, 0x74, 0x14, 0xf0, 0x75, 0x1a, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0xd2, 0x03,
+  0x22, 0xd2, 0x15, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02, 0xf0, 0x12, 0x0d, 0xf9, 0xd2, 0xe8}},
+ {0x0846, 64, { 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab, 0x74,
+  0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaf,
+  0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0x74, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0x16, 0x12, 0x0d,
+  0x24, 0xc2, 0x02, 0xe4, 0xf5, 0x28, 0xf5, 0x30, 0xc2, 0x09, 0xf5, 0x23, 0xc2, 0x03, 0x90}},
+ {0x0886, 64, { 0x7f, 0xa1, 0x04, 0xf0, 0x90, 0x7f, 0xd8, 0xe0, 0x65, 0x34, 0x60, 0x48, 0x30, 0x03, 0x05, 0xd2, 0x16,
+  0x12, 0x00, 0x46, 0xe5, 0x0f, 0x60, 0x22, 0xe5, 0x26, 0x60, 0x16, 0x15, 0x26, 0x90, 0x7f, 0xd8,
+  0xe0, 0x30, 0xe6, 0x04, 0x7f, 0x20, 0x80, 0x02, 0x7f, 0x30, 0x90, 0x7f, 0x96, 0xef, 0xf0, 0x80,
+  0x1a, 0x90, 0x7f, 0x96, 0x74, 0x30, 0xf0, 0x80, 0x12, 0x90, 0x7f, 0xd9, 0xe0, 0x30, 0xe2}},
+ {0x08c6, 64, { 0x04, 0x7f, 0x30, 0x80, 0x02, 0x7f, 0x20, 0x90, 0x7f, 0x96, 0xef, 0xf0, 0x90, 0x7f, 0xd8, 0xe0, 0xf5,
+  0x34, 0x80, 0x20, 0x30, 0x03, 0x07, 0xc2, 0x16, 0x12, 0x00, 0x46, 0x80, 0x16, 0xe5, 0x0f, 0x70,
+  0x12, 0x90, 0x7f, 0xd9, 0xe0, 0x30, 0xe2, 0x04, 0x7f, 0x30, 0x80, 0x02, 0x7f, 0x20, 0x90, 0x7f,
+  0x96, 0xef, 0xf0, 0x30, 0x02, 0x07, 0xc2, 0x02, 0x12, 0x05, 0x2a, 0x80, 0x86, 0x30, 0x0a}},
+ {0x0906, 64, { 0x83, 0xc2, 0x0a, 0x12, 0x0b, 0x5d, 0x02, 0x08, 0x8a, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf,
+  0x24, 0xe5, 0x2a, 0xf5, 0x82, 0xe5, 0x29, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00,
+  0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05, 0x86, 0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90, 0x7f,
+  0x98, 0x74, 0x10, 0xf0, 0xaf, 0x24, 0xe5, 0x2a, 0xf5, 0x82, 0xe5, 0x29, 0xf5, 0x83, 0xc2}},
+ {0x0946, 64, { 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86,
+  0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x24, 0xe5, 0x2a, 0xf5, 0x82, 0xe5,
+  0x29, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86,
+  0xf0, 0x05, 0x86, 0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf}},
+ {0x0986, 64, { 0x24, 0xe5, 0x2a, 0xf5, 0x82, 0xe5, 0x29, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0,
+  0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x74, 0x00, 0xf5,
+  0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9, 0x22, 0x90, 0x7f,
+  0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x78}},
+ {0x09c6, 64, { 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x39, 0x02, 0x0a, 0x0c, 0x02, 0x08, 0x38, 0xe4, 0x93, 0xa3,
+  0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4,
+  0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8,
+  0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02}},
+ {0x0a06, 64, { 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x0d, 0x8b, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff,
+  0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54,
+  0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4,
+  0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82}},
+ {0x0a46, 64, { 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a,
+  0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83,
+  0xe4, 0x93, 0x22, 0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83,
+  0xe0, 0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25}},
+ {0x0a86, 64, { 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22,
+  0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01,
+  0xf3, 0x22, 0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d,
+  0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02}},
+ {0x0ac6, 64, { 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c,
+  0x74, 0x20, 0xf0, 0x30, 0x01, 0x03, 0xff, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x7f, 0x96, 0xef, 0xf0,
+  0xe4, 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0,
+  0x30, 0x08, 0x11, 0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0xff, 0xf0, 0x90, 0x7f}},
+ {0x0b06, 64, { 0x98, 0x74, 0x20, 0xf0, 0x22, 0xe4, 0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0xdf, 0xf0, 0xe4,
+  0x90, 0x7f, 0x98, 0xf0, 0x22, 0x8f, 0x35, 0xe4, 0xf5, 0x36, 0x75, 0x37, 0xff, 0x75, 0x38, 0x19,
+  0x75, 0x39, 0x86, 0xab, 0x37, 0xaa, 0x38, 0xa9, 0x39, 0x90, 0x00, 0x01, 0x12, 0x0a, 0x6a, 0xb4,
+  0x03, 0x1d, 0xaf, 0x36, 0x05, 0x36, 0xef, 0xb5, 0x35, 0x01, 0x22, 0x12, 0x0a, 0x51, 0x7e}},
+ {0x0b46, 64, { 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75, 0x37, 0xff, 0xf5, 0x38, 0x89, 0x39, 0x80, 0xd4, 0x7b,
+  0x00, 0x7a, 0x00, 0x79, 0x00, 0x22, 0x90, 0x7f, 0xd8, 0xe0, 0xf5, 0x35, 0x12, 0x0a, 0xcf, 0x20,
+  0x08, 0x07, 0x90, 0x7f, 0x92, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0,
+  0x12, 0x09, 0xb5, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x0e, 0x30, 0x01, 0x05, 0x12, 0x0d}},
+ {0x0b86, 64, { 0xbc, 0x80, 0x06, 0x12, 0x0d, 0x49, 0xef, 0x60, 0xe1, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02, 0xf0, 0x12,
+  0x07, 0x48, 0x22, 0x05, 0x2a, 0xe5, 0x2a, 0xae, 0x29, 0x70, 0x02, 0x05, 0x29, 0x14, 0xf5, 0x82,
+  0x8e, 0x83, 0xe5, 0x11, 0xf0, 0x12, 0x00, 0x36, 0x05, 0x2a, 0xe5, 0x2a, 0xac, 0x29, 0x70, 0x02,
+  0x05, 0x29, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x24, 0xe5, 0x24, 0x60, 0x07}},
+ {0x0bc6, 64, { 0x12, 0x0e, 0x1b, 0x8f, 0x11, 0x80, 0xcd, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0,
+  0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x02, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01,
+  0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0,
+  0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x0a}},
+ {0x0c06, 64, { 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82,
+  0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf,
+  0xf0, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74,
+  0x13, 0xf0, 0xe5, 0x19, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74}},
+ {0x0c46, 64, { 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00,
+  0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x19, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0,
+  0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98,
+  0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5}},
+ {0x0c86, 64, { 0x19, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00,
+  0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f,
+  0x98, 0x74, 0x13, 0xf0, 0xe5, 0x19, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98,
+  0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0}},
+ {0x0cc6, 64, { 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x19, 0x54, 0x7f, 0x90, 0xc0,
+  0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x19, 0x54, 0x7f, 0x90, 0xc0, 0x00,
+  0xf0, 0x90, 0x7f, 0x98, 0x74, 0x17, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74,
+  0x15, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22, 0x12, 0x0d, 0xea, 0x8f, 0x37, 0x12, 0x0d}},
+ {0x0d06, 64, { 0xea, 0x8f, 0x38, 0xe5, 0x37, 0x65, 0x38, 0x60, 0x12, 0x12, 0x0d, 0xea, 0x8f, 0x37, 0xe5, 0x37, 0x65,
+  0x38, 0x60, 0x07, 0x12, 0x0d, 0xea, 0x8f, 0x38, 0x80, 0xe8, 0xaf, 0x37, 0x22, 0x90, 0x7f, 0xd6,
+  0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x16, 0x04, 0xe0, 0x44, 0x02, 0xf0, 0x7f,
+  0xf4, 0x7e, 0x01, 0x12, 0x0d, 0xa5, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0, 0xe0, 0x44}},
+ {0x0d46, 64, { 0x04, 0xf0, 0x22, 0x90, 0x7f, 0xd8, 0xe0, 0xf5, 0x36, 0x12, 0x07, 0x48, 0x12, 0x0e, 0x27, 0xef, 0x30,
+  0xe6, 0x0b, 0x90, 0x7f, 0xd8, 0xe0, 0x65, 0x36, 0x60, 0xf1, 0x7f, 0x01, 0x22, 0x12, 0x0a, 0xcf,
+  0x7f, 0x00, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5, 0x16, 0x54, 0x7f, 0xfd, 0x12, 0x0c, 0xda, 0x90,
+  0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x16, 0x44, 0x80}},
+ {0x0d86, 64, { 0xfd, 0x12, 0x0c, 0xda, 0x22, 0x05, 0x2b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x31, 0x03, 0x00, 0x00,
+  0xc1, 0x86, 0xc1, 0x02, 0xc1, 0x0a, 0xc1, 0x01, 0xc1, 0x07, 0x01, 0x27, 0x00, 0x00, 0x8e, 0x36,
+  0x8f, 0x37, 0xe5, 0x37, 0x15, 0x37, 0xae, 0x36, 0x70, 0x02, 0x15, 0x36, 0x4e, 0x60, 0x05, 0x12,
+  0x09, 0xa4, 0x80, 0xee, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x0d, 0x7e}},
+ {0x0dc6, 64, { 0x00, 0x12, 0x0d, 0xa5, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x11,
+  0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00,
+  0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0xd2,
+  0x01, 0x22, 0xc2, 0x01, 0x22, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0b, 0xce, 0x00, 0x02, 0x0e}},
+ {0x0e06, 64, { 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x0b, 0xf5, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0,
+  0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22,
+  0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x0e46, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x0e86, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x0ec6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x0f06, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x0f46, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x0f86, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x0fc6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1006, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1046, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1086, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x10c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1106, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1146, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1186, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x11c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1206, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1246, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1286, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x12c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1306, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1346, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1386, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x13c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1406, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1446, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1486, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x14c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1506, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1546, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1586, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x15c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1606, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1646, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1686, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x16c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1706, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1746, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1786, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x17c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1806, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1846, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1886, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x18c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x10, 0x01, 0xff, 0x00}},
+ {0x1906, 64, { 0x00, 0x40, 0xcd, 0x06, 0x19, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x02, 0x09, 0x02, 0x74, 0x00, 0x01,
+  0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e, 0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01,
+  0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40,
+  0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x05, 0x02, 0x40, 0x00}},
+ {0x1946, 64, { 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x07, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05,
+  0x81, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x83, 0x02,
+  0x40, 0x00, 0x01, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00,
+  0x01, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x87, 0x02, 0x40, 0x00, 0x01}},
+ {0x1986, 64, { 0x04, 0x03, 0x09, 0x04, 0x48, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61,
+  0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x61, 0x00, 0x20, 0x00, 0x64, 0x00, 0x69, 0x00, 0x76,
+  0x00, 0x69, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66,
+  0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x53, 0x00, 0x79, 0x00}},
+ {0x19c6, 64, { 0x73, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x36, 0x03, 0x4b, 0x00, 0x65,
+  0x00, 0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53,
+  0x00, 0x42, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c,
+  0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x61, 0x00, 0x70, 0x00, 0x74, 0x00, 0x65, 0x00}},
+ {0x1a06,  4, { 0x72, 0x00, 0x00, 0x00}},
+ {0xffff, 0,	{0x00}}
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/keyspan_usa19w_fw.h linux-2.4.20/drivers/usb/serial/keyspan_usa19w_fw.h
--- linux-2.4.19/drivers/usb/serial/keyspan_usa19w_fw.h	2001-10-09 22:15:02.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/keyspan_usa19w_fw.h	2002-10-29 11:18:50.000000000 +0000
@@ -1,108 +1,112 @@
 /* keyspan_usa19w_fw.h
-  
-   Generated from Keyspan firmware image usa17code.h Sat Oct  6 12:13:03 EST 2001
-   This firmware is for the Keyspan USA-19W Serial Adaptor
 
-   "The firmware contained herein as keyspan_usa19w_fw.h is
-   Copyright (C) 1999-2001 Keyspan, A division of InnoSys Incorporated
-   ("Keyspan"), as an unpublished work.  This notice does not imply
-   unrestricted or public access to this firmware which is a trade secret of
-   Keyspan, and which may not be reproduced, used, sold or transferred to any
-   third party without Keyspan's prior written consent.  All Rights Reserved.
+	The firmware contained herein as keyspan_usa19w_fw.h is
 
-   This firmware may not be modified and may only be used with the Keyspan 
-   USA-19W Serial Adapter.  Distribution and/or Modification of the
-   keyspan.c driver which includes this firmware, in whole or in part,
-   requires the inclusion of this statement."
+		Copyright (C) 1999-2001
+		Keyspan, A division of InnoSys Incorporated ("Keyspan")
+		
+	as an unpublished work. This notice does not imply unrestricted or
+	public access to the source code from which this firmware image is
+	derived.  Except as noted below this firmware image may not be 
+	reproduced, used, sold or transferred to any third party without 
+	Keyspan's prior written consent.  All Rights Reserved.
 
+	Permission is hereby granted for the distribution of this firmware 
+	image as part of a Linux or other Open Source operating system kernel 
+	in text or binary form as required. 
+
+	This firmware may not be modified and may only be used with  
+	Keyspan hardware.  Distribution and/or Modification of the 
+	keyspan.c driver which includes this firmware, in whole or in 
+	part, requires the inclusion of this statement."
 */
 
 static const struct ezusb_hex_record keyspan_usa19w_firmware[] = {
- {0x0033,  3, { 0x02, 0x0d, 0x6c}},
+ {0x0033,  3, { 0x02, 0x0d, 0x5c}},
  {0x0003, 16, { 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0}},
  {0x0013, 16, { 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90}},
  {0x0023, 15, { 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x17, 0xf0, 0xe4, 0x90, 0x7f, 0x98, 0xf0, 0x22}},
- {0x0046, 16, { 0x30, 0x0f, 0x18, 0x12, 0x0d, 0x48, 0xef, 0xc3, 0x95, 0x14, 0x40, 0x03, 0x02, 0x00, 0xd8, 0x90}},
+ {0x0046, 16, { 0x30, 0x0f, 0x18, 0x12, 0x0d, 0x38, 0xef, 0xc3, 0x95, 0x14, 0x40, 0x03, 0x02, 0x00, 0xd8, 0x90}},
  {0x0056, 16, { 0x7f, 0xbf, 0x74, 0x01, 0xf0, 0xc2, 0x0f, 0xc2, 0x0a, 0x80, 0x77, 0x30, 0x0c, 0x3b, 0x90, 0x7f}},
- {0x0066, 16, { 0xc6, 0xe0, 0x20, 0xe1, 0x6d, 0x12, 0x0d, 0x48, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x64, 0x90, 0x7e}},
+ {0x0066, 16, { 0xc6, 0xe0, 0x20, 0xe1, 0x6d, 0x12, 0x0d, 0x38, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x64, 0x90, 0x7e}},
  {0x0076, 16, { 0x40, 0xe0, 0x13, 0x92, 0x0f, 0x90, 0x7f, 0xc7, 0xe0, 0x14, 0xf5, 0x1c, 0x20, 0x0a, 0x11, 0x60}},
- {0x0086, 16, { 0x0f, 0xf5, 0x23, 0x7e, 0x7e, 0x7f, 0x41, 0x75, 0x27, 0x7e, 0x75, 0x28, 0x41, 0x12, 0x08, 0x05}},
+ {0x0086, 16, { 0x0f, 0xf5, 0x23, 0x7e, 0x7e, 0x7f, 0x41, 0x75, 0x27, 0x7e, 0x75, 0x28, 0x41, 0x12, 0x08, 0x01}},
  {0x0096, 16, { 0xc2, 0x0c, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0x80, 0x39, 0x90, 0x7f, 0xc8, 0xe0, 0x20, 0xe1, 0x32}},
- {0x00a6, 16, { 0x12, 0x0d, 0x48, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x29, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x0f}},
+ {0x00a6, 16, { 0x12, 0x0d, 0x38, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x29, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x0f}},
  {0x00b6, 16, { 0x90, 0x7f, 0xc9, 0xe0, 0x14, 0xf5, 0x1c, 0x20, 0x0a, 0x11, 0x60, 0x0f, 0xf5, 0x23, 0x7e, 0x7d}},
- {0x00c6, 16, { 0x7f, 0xc1, 0x75, 0x27, 0x7d, 0x75, 0x28, 0xc1, 0x12, 0x08, 0x05, 0xd2, 0x0c, 0xe4, 0x90, 0x7f}},
- {0x00d6, 16, { 0xc9, 0xf0, 0x90, 0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x01, 0x60, 0x53, 0x11, 0x80, 0x12}},
- {0x00e6, 16, { 0x0d, 0x54, 0xef, 0x42, 0x11, 0x12, 0x0c, 0x51, 0x8f, 0x1c, 0xef, 0xc3, 0x95, 0x13, 0x50, 0x0f}},
- {0x00f6, 16, { 0x12, 0x0d, 0x30, 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x11, 0x20, 0xe7, 0x03, 0x30, 0x12, 0x5b, 0xc2}},
+ {0x00c6, 16, { 0x7f, 0xc1, 0x75, 0x27, 0x7d, 0x75, 0x28, 0xc1, 0x12, 0x08, 0x01, 0xd2, 0x0c, 0xe4, 0x90, 0x7f}},
+ {0x00d6, 16, { 0xc9, 0xf0, 0x90, 0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x01, 0x5e, 0x12, 0x0c, 0x41, 0x8f}},
+ {0x00e6, 16, { 0x1c, 0x12, 0x0d, 0x44, 0x8f, 0x11, 0xe5, 0x1c, 0xc3, 0x95, 0x13, 0x50, 0x0f, 0x12, 0x0d, 0x20}},
+ {0x00f6, 16, { 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x11, 0x20, 0xe7, 0x03, 0x30, 0x12, 0x5c, 0xc2, 0x12, 0xe5, 0x1c}},
  {0x0036, 12, { 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22}},
  {0x0043,  3, { 0x02, 0x0e, 0x00}},
- {0x0000,  3, { 0x02, 0x08, 0xba}},
- {0x0106, 64, { 0x12, 0xe5, 0x1c, 0x70, 0x04, 0xf5, 0x11, 0x80, 0x51, 0xe5, 0x11, 0x30, 0xe7, 0x26, 0xe5, 0x1c, 0xd3,
-  0x94, 0x20, 0x40, 0x03, 0x75, 0x1c, 0x20, 0x85, 0x1c, 0x23, 0x7e, 0x7e, 0x7f, 0x80, 0x75, 0x27,
-  0x7e, 0x75, 0x28, 0x80, 0xaf, 0x11, 0x12, 0x0a, 0x8a, 0xe5, 0x1c, 0x25, 0xe0, 0x90, 0x7f, 0xb7,
-  0xf0, 0x80, 0x26, 0xe5, 0x1c, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75, 0x1c, 0x3f, 0x85, 0x1c}},
- {0x0146, 64, { 0x23, 0xe4, 0x90, 0x7e, 0x80, 0xf0, 0x7e, 0x7e, 0x7f, 0x81, 0x75, 0x27, 0x7e, 0x75, 0x28, 0x81, 0x12,
-  0x08, 0x2a, 0xe5, 0x1c, 0x04, 0x90, 0x7f, 0xb7, 0xf0, 0x90, 0x7f, 0xce, 0xe0, 0x30, 0xe1, 0x06,
-  0x20, 0x0d, 0x03, 0x02, 0x03, 0xba, 0xe4, 0xf5, 0x1b, 0x74, 0x40, 0x25, 0x1b, 0xf5, 0x82, 0xe4,
-  0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x1b, 0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e, 0x79}},
- {0x0186, 64, { 0x00, 0x24, 0x00, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef, 0x12, 0x0a, 0x11, 0x05, 0x1b, 0xe5, 0x1b, 0xb4,
-  0x20, 0xd7, 0x90, 0x7e, 0x00, 0xe0, 0x60, 0x6e, 0x7f, 0x01, 0x90, 0x7e, 0x11, 0xe0, 0xfd, 0x12,
-  0x0c, 0x2c, 0x90, 0x7e, 0x01, 0xe0, 0xff, 0x12, 0x0b, 0x6e, 0x90, 0x7e, 0x02, 0xe0, 0xff, 0x12,
-  0x0b, 0x94, 0xd2, 0x10, 0xd2, 0x11, 0x75, 0x1c, 0x04, 0x90, 0x7e, 0x03, 0xe0, 0x60, 0x05}},
- {0x01c6, 64, { 0xc2, 0x11, 0x43, 0x1c, 0xc0, 0x90, 0x7e, 0x04, 0xe0, 0xb4, 0x01, 0x07, 0xc2, 0x11, 0x43, 0x1c, 0x0b,
-  0x80, 0x10, 0x90, 0x7e, 0x04, 0xe0, 0x60, 0x07, 0xc2, 0x10, 0x43, 0x1c, 0x09, 0x80, 0x03, 0x43,
-  0x1c, 0x02, 0x7f, 0x03, 0xad, 0x1c, 0x12, 0x0c, 0x2c, 0x43, 0x19, 0x80, 0x90, 0x7f, 0x98, 0x74,
-  0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x19, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5}},
- {0x0206, 64, { 0x16, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x05, 0xe0, 0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f,
-  0xf5, 0x18, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x18, 0xf0, 0x90, 0x7e,
-  0x07, 0xe0, 0x60, 0x42, 0x90, 0x7e, 0x13, 0xe0, 0x60, 0x05, 0x43, 0x15, 0x04, 0x80, 0x03, 0x53,
-  0x15, 0xfb, 0xe4, 0xff, 0xad, 0x15, 0x12, 0x0c, 0x2c, 0x90, 0x7e, 0x08, 0xe0, 0x60, 0x05}},
- {0x0246, 64, { 0x43, 0x17, 0x80, 0x80, 0x03, 0x53, 0x17, 0x7f, 0x53, 0x17, 0xfc, 0x90, 0x7e, 0x09, 0xe0, 0x60, 0x11,
-  0x43, 0x17, 0x02, 0xa3, 0xe0, 0xff, 0x12, 0x0b, 0xe0, 0x90, 0x7e, 0x0b, 0xe0, 0xff, 0x12, 0x0c,
-  0x06, 0xaf, 0x17, 0x12, 0x0b, 0xba, 0x90, 0x7e, 0x0e, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05,
-  0x43, 0x19, 0x01, 0x80, 0x03, 0x53, 0x19, 0xfe, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90}},
- {0x0286, 64, { 0xc0, 0x00, 0xe5, 0x19, 0xf0, 0x90, 0x7e, 0x0c, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x19,
-  0x02, 0x80, 0x03, 0x53, 0x19, 0xfd, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5,
-  0x19, 0xf0, 0x90, 0x7e, 0x12, 0xe0, 0xf5, 0x13, 0xa3, 0xe0, 0x13, 0x92, 0x13, 0xa3, 0xe0, 0xf5,
-  0x14, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x19, 0x10, 0x80, 0x03, 0x53, 0x19, 0xef, 0x90, 0x7f}},
- {0x02c6, 64, { 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x19, 0xf0, 0x90, 0x7e, 0x16, 0xe0, 0x60, 0x32, 0x53,
-  0x18, 0xbf, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0,
-  0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x12, 0x0d, 0x24, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0,
-  0x53, 0x15, 0xfd, 0xe4, 0xff, 0xad, 0x15, 0x12, 0x0c, 0x2c, 0xe4, 0xf5, 0x0e, 0xf5, 0x0d}},
- {0x0306, 64, { 0xd2, 0x0e, 0x90, 0x7e, 0x17, 0xe0, 0x60, 0x0f, 0x43, 0x15, 0x02, 0xe4, 0xff, 0xad, 0x15, 0x12, 0x0c,
-  0x2c, 0x75, 0x0d, 0x01, 0xd2, 0x0e, 0x90, 0x7e, 0x18, 0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74,
-  0x12, 0xf0, 0xe5, 0x16, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0, 0xd2, 0x0a, 0x90, 0x7e, 0x19, 0xe0,
-  0x60, 0x11, 0x43, 0x18, 0x40, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54, 0x7f}},
- {0x0346, 64, { 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1a, 0xe0, 0x60, 0x0f, 0x53, 0x15, 0xfe, 0xe4, 0xff, 0xad, 0x15,
-  0x12, 0x0c, 0x2c, 0x75, 0x0f, 0x01, 0xd2, 0x0e, 0x90, 0x7e, 0x1b, 0xe0, 0x60, 0x0f, 0x43, 0x15,
-  0x01, 0xe4, 0xff, 0xad, 0x15, 0x12, 0x0c, 0x2c, 0xe4, 0xf5, 0x0f, 0xd2, 0x0e, 0x90, 0x7e, 0x1c,
-  0xe0, 0x60, 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x16, 0x44, 0x02, 0x90, 0xc0}},
- {0x0386, 64, { 0x00, 0xf0, 0x90, 0x7e, 0x1d, 0xe0, 0x60, 0x02, 0xd2, 0x12, 0x90, 0x7e, 0x1e, 0xe0, 0x60, 0x08, 0x75,
-  0x10, 0x01, 0xe4, 0xf5, 0x12, 0xd2, 0x0e, 0x90, 0x7e, 0x1f, 0xe0, 0x60, 0x0f, 0x90, 0x7f, 0xd7,
-  0x74, 0x11, 0xf0, 0x74, 0x31, 0xf0, 0x74, 0x15, 0xf0, 0x74, 0x35, 0xf0, 0xc2, 0x0d, 0xe4, 0x90,
+ {0x0000,  3, { 0x02, 0x08, 0xb6}},
+ {0x0106, 64, { 0x60, 0x56, 0xb4, 0x80, 0x03, 0x43, 0x11, 0x02, 0xe5, 0x11, 0x30, 0xe7, 0x24, 0xe5, 0x1c, 0xd3, 0x94,
+  0x20, 0x40, 0x03, 0x75, 0x1c, 0x20, 0x85, 0x1c, 0x23, 0x7e, 0x7e, 0x7f, 0x80, 0x75, 0x27, 0x7e,
+  0x75, 0x28, 0x80, 0x12, 0x0a, 0x86, 0xe5, 0x1c, 0x25, 0x1c, 0x90, 0x7f, 0xb7, 0xf0, 0x80, 0x27,
+  0xe5, 0x1c, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75, 0x1c, 0x3f, 0x85, 0x1c, 0x23, 0x90, 0x7e}},
+ {0x0146, 64, { 0x80, 0xe5, 0x11, 0xf0, 0x7e, 0x7e, 0x7f, 0x81, 0x75, 0x27, 0x7e, 0x75, 0x28, 0x81, 0x12, 0x08, 0x26,
+  0xe5, 0x1c, 0x04, 0x90, 0x7f, 0xb7, 0xf0, 0x90, 0x7f, 0xce, 0xe0, 0x30, 0xe1, 0x06, 0x20, 0x0d,
+  0x03, 0x02, 0x03, 0xba, 0xe4, 0xf5, 0x1b, 0x74, 0x40, 0x25, 0x1b, 0xf5, 0x82, 0xe4, 0x34, 0x7c,
+  0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x1b, 0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e, 0x79, 0x00, 0x24}},
+ {0x0186, 64, { 0x00, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef, 0x12, 0x0a, 0x0d, 0x05, 0x1b, 0xe5, 0x1b, 0xb4, 0x20, 0xd7,
+  0x90, 0x7e, 0x00, 0xe0, 0x60, 0x6e, 0x7f, 0x01, 0x90, 0x7e, 0x11, 0xe0, 0xfd, 0x12, 0x0c, 0x1c,
+  0x90, 0x7e, 0x01, 0xe0, 0xff, 0x12, 0x0b, 0x5e, 0x90, 0x7e, 0x02, 0xe0, 0xff, 0x12, 0x0b, 0x84,
+  0xd2, 0x10, 0xd2, 0x11, 0x75, 0x1c, 0x04, 0x90, 0x7e, 0x03, 0xe0, 0x60, 0x05, 0xc2, 0x11}},
+ {0x01c6, 64, { 0x43, 0x1c, 0xc0, 0x90, 0x7e, 0x04, 0xe0, 0xb4, 0x01, 0x07, 0xc2, 0x11, 0x43, 0x1c, 0x0b, 0x80, 0x10,
+  0x90, 0x7e, 0x04, 0xe0, 0x60, 0x07, 0xc2, 0x10, 0x43, 0x1c, 0x09, 0x80, 0x03, 0x43, 0x1c, 0x02,
+  0x7f, 0x03, 0xad, 0x1c, 0x12, 0x0c, 0x1c, 0x43, 0x19, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0,
+  0x90, 0xc0, 0x00, 0xe5, 0x19, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x16, 0x44}},
+ {0x0206, 64, { 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x05, 0xe0, 0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f, 0xf5, 0x18,
+  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x18, 0xf0, 0x90, 0x7e, 0x07, 0xe0,
+  0x60, 0x42, 0x90, 0x7e, 0x13, 0xe0, 0x60, 0x05, 0x43, 0x15, 0x04, 0x80, 0x03, 0x53, 0x15, 0xfb,
+  0xe4, 0xff, 0xad, 0x15, 0x12, 0x0c, 0x1c, 0x90, 0x7e, 0x08, 0xe0, 0x60, 0x05, 0x43, 0x17}},
+ {0x0246, 64, { 0x80, 0x80, 0x03, 0x53, 0x17, 0x7f, 0x53, 0x17, 0xfc, 0x90, 0x7e, 0x09, 0xe0, 0x60, 0x11, 0x43, 0x17,
+  0x02, 0xa3, 0xe0, 0xff, 0x12, 0x0b, 0xd0, 0x90, 0x7e, 0x0b, 0xe0, 0xff, 0x12, 0x0b, 0xf6, 0xaf,
+  0x17, 0x12, 0x0b, 0xaa, 0x90, 0x7e, 0x0e, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x19,
+  0x01, 0x80, 0x03, 0x53, 0x19, 0xfe, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00}},
+ {0x0286, 64, { 0xe5, 0x19, 0xf0, 0x90, 0x7e, 0x0c, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x19, 0x02, 0x80,
+  0x03, 0x53, 0x19, 0xfd, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x19, 0xf0,
+  0x90, 0x7e, 0x12, 0xe0, 0xf5, 0x13, 0xa3, 0xe0, 0x13, 0x92, 0x13, 0xa3, 0xe0, 0xf5, 0x14, 0xa3,
+  0xe0, 0x60, 0x05, 0x43, 0x19, 0x10, 0x80, 0x03, 0x53, 0x19, 0xef, 0x90, 0x7f, 0x98, 0x74}},
+ {0x02c6, 64, { 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x19, 0xf0, 0x90, 0x7e, 0x16, 0xe0, 0x60, 0x32, 0x53, 0x18, 0xbf,
+  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f,
+  0x98, 0x74, 0x11, 0xf0, 0x12, 0x0d, 0x14, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x15,
+  0xfd, 0xe4, 0xff, 0xad, 0x15, 0x12, 0x0c, 0x1c, 0xe4, 0xf5, 0x0e, 0xf5, 0x0d, 0xd2, 0x0e}},
+ {0x0306, 64, { 0x90, 0x7e, 0x17, 0xe0, 0x60, 0x0f, 0x43, 0x15, 0x02, 0xe4, 0xff, 0xad, 0x15, 0x12, 0x0c, 0x1c, 0x75,
+  0x0d, 0x01, 0xd2, 0x0e, 0x90, 0x7e, 0x18, 0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0,
+  0xe5, 0x16, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0, 0xd2, 0x0a, 0x90, 0x7e, 0x19, 0xe0, 0x60, 0x11,
+  0x43, 0x18, 0x40, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54, 0x7f, 0x90, 0xc0}},
+ {0x0346, 64, { 0x00, 0xf0, 0x90, 0x7e, 0x1a, 0xe0, 0x60, 0x0f, 0x53, 0x15, 0xfe, 0xe4, 0xff, 0xad, 0x15, 0x12, 0x0c,
+  0x1c, 0x75, 0x0f, 0x01, 0xd2, 0x0e, 0x90, 0x7e, 0x1b, 0xe0, 0x60, 0x0f, 0x43, 0x15, 0x01, 0xe4,
+  0xff, 0xad, 0x15, 0x12, 0x0c, 0x1c, 0xe4, 0xf5, 0x0f, 0xd2, 0x0e, 0x90, 0x7e, 0x1c, 0xe0, 0x60,
+  0x0e, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x16, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0}},
+ {0x0386, 64, { 0x90, 0x7e, 0x1d, 0xe0, 0x60, 0x02, 0xd2, 0x12, 0x90, 0x7e, 0x1e, 0xe0, 0x60, 0x08, 0x75, 0x10, 0x01,
+  0xe4, 0xf5, 0x12, 0xd2, 0x0e, 0x90, 0x7e, 0x1f, 0xe0, 0x60, 0x11, 0x90, 0x7f, 0xd7, 0x74, 0x11,
+  0xf0, 0x74, 0x31, 0xf0, 0x74, 0x15, 0xf0, 0x74, 0x35, 0xf0, 0xd2, 0x0c, 0xc2, 0x0d, 0xe4, 0x90,
   0x7f, 0xcf, 0xf0, 0x30, 0x15, 0x71, 0xe5, 0x12, 0x60, 0x02, 0x15, 0x12, 0xe5, 0x2e, 0xd3}},
- {0x03c6, 64, { 0x94, 0x00, 0x40, 0x04, 0x15, 0x2e, 0x80, 0x60, 0x75, 0x2e, 0x0a, 0x12, 0x0d, 0x24, 0xef, 0x54, 0x01,
-  0xf5, 0x1c, 0x65, 0x0e, 0x60, 0x07, 0x85, 0x1c, 0x0e, 0xd2, 0x0e, 0x80, 0x11, 0x12, 0x0d, 0x60,
+ {0x03c6, 64, { 0x94, 0x00, 0x40, 0x04, 0x15, 0x2e, 0x80, 0x60, 0x75, 0x2e, 0x0a, 0x12, 0x0d, 0x14, 0xef, 0x54, 0x01,
+  0xf5, 0x1c, 0x65, 0x0e, 0x60, 0x07, 0x85, 0x1c, 0x0e, 0xd2, 0x0e, 0x80, 0x11, 0x12, 0x0d, 0x50,
   0xef, 0x54, 0x10, 0xf5, 0x1c, 0x65, 0x09, 0x60, 0x05, 0x85, 0x1c, 0x09, 0xd2, 0x0e, 0x12, 0x0d,
-  0x60, 0xef, 0x54, 0x80, 0xf5, 0x1c, 0x65, 0x0a, 0x60, 0x05, 0x85, 0x1c, 0x0a, 0xd2, 0x0e}},
- {0x0406, 64, { 0x12, 0x0d, 0x60, 0xef, 0x54, 0x20, 0xf5, 0x1c, 0x65, 0x0b, 0x60, 0x08, 0x85, 0x1c, 0x0b, 0x30, 0x10,
-  0x02, 0xd2, 0x0e, 0x12, 0x0d, 0x60, 0xef, 0x54, 0x40, 0xf5, 0x1c, 0x65, 0x0c, 0x60, 0x08, 0x85,
+  0x50, 0xef, 0x54, 0x80, 0xf5, 0x1c, 0x65, 0x0a, 0x60, 0x05, 0x85, 0x1c, 0x0a, 0xd2, 0x0e}},
+ {0x0406, 64, { 0x12, 0x0d, 0x50, 0xef, 0x54, 0x20, 0xf5, 0x1c, 0x65, 0x0b, 0x60, 0x08, 0x85, 0x1c, 0x0b, 0x30, 0x10,
+  0x02, 0xd2, 0x0e, 0x12, 0x0d, 0x50, 0xef, 0x54, 0x40, 0xf5, 0x1c, 0x65, 0x0c, 0x60, 0x08, 0x85,
   0x1c, 0x0c, 0x30, 0x11, 0x02, 0xd2, 0x0e, 0x30, 0x15, 0x2a, 0x90, 0x7f, 0xd2, 0xe0, 0x20, 0xe1,
   0x23, 0x90, 0x7b, 0x40, 0xe0, 0x60, 0x09, 0xe0, 0xf5, 0x30, 0x90, 0x7b, 0x42, 0xe0, 0xf5}},
  {0x0446, 64, { 0x31, 0x90, 0x7b, 0x41, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7, 0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0xe4,
   0x90, 0x7f, 0xd3, 0xf0, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x05, 0x1f, 0xe5, 0x25,
   0x70, 0x40, 0x30, 0x0e, 0x39, 0xe5, 0x12, 0x70, 0x35, 0xc2, 0x0e, 0xf5, 0x1b, 0x7e, 0x00, 0x7b,
-  0x00, 0x74, 0x08, 0x25, 0x1b, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x09, 0xcb, 0xff, 0x74}},
+  0x00, 0x74, 0x08, 0x25, 0x1b, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x09, 0xc7, 0xff, 0x74}},
  {0x0486, 64, { 0x80, 0x25, 0x1b, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x1b, 0xe5, 0x1b, 0xb4,
   0x09, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x09, 0xf0, 0x75, 0x12, 0x10, 0xe4, 0xf5, 0x10, 0x75, 0x25,
   0x02, 0x22, 0xe5, 0x25, 0x64, 0x02, 0x70, 0x36, 0x30, 0x05, 0x2f, 0xc2, 0x05, 0xf5, 0x1b, 0x7e,
-  0x00, 0x7b, 0x00, 0x74, 0x29, 0x25, 0x1b, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x09, 0xcb}},
+  0x00, 0x7b, 0x00, 0x74, 0x29, 0x25, 0x1b, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x09, 0xc7}},
  {0x04c6, 64, { 0xff, 0x74, 0x80, 0x25, 0x1b, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x1b, 0xe5,
   0x1b, 0xb4, 0x05, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x05, 0xf0, 0x75, 0x25, 0x03, 0x22, 0xe5, 0x30,
   0x60, 0x33, 0x75, 0x2f, 0x03, 0x15, 0x30, 0xe4, 0xf5, 0x1b, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x2f,
-  0x25, 0x1b, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x09, 0xcb, 0xff, 0x74, 0x80, 0x25, 0x1b}},
+  0x25, 0x1b, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x09, 0xc7, 0xff, 0x74, 0x80, 0x25, 0x1b}},
  {0x0506, 64, { 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x1b, 0xe5, 0x1b, 0xb4, 0x03, 0xdb, 0x90,
-  0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4, 0xf5, 0x25, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x0a, 0x23,
+  0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4, 0xf5, 0x25, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x0a, 0x1f,
   0x05, 0xf6, 0x00, 0x06, 0x6a, 0x01, 0x06, 0xd7, 0x03, 0x05, 0x43, 0x06, 0x05, 0xe9, 0x08, 0x05,
   0xe3, 0x09, 0x05, 0xcb, 0x0a, 0x05, 0xda, 0x0b, 0x00, 0x00, 0x07, 0x27, 0x90, 0x7f, 0xeb}},
  {0x0546, 64, { 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60, 0x50, 0x24, 0x02, 0x70, 0x6f, 0x74, 0x19, 0x90, 0x7f, 0xd4,
@@ -110,7 +114,7 @@
   0x7f, 0x02, 0x80, 0x02, 0x7f, 0x03, 0x75, 0x82, 0x82, 0x75, 0x83, 0x19, 0xef, 0xf0, 0x75, 0x82,
   0x74, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x58, 0x75, 0x83, 0x19, 0xf0, 0x90, 0x7f, 0xea}},
  {0x0586, 64, { 0xe0, 0x04, 0x75, 0x82, 0x17, 0x75, 0x83, 0x19, 0xf0, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x12,
-  0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x07, 0x2e, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0a, 0x49, 0xea,
+  0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x07, 0x2e, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0a, 0x45, 0xea,
   0x49, 0x60, 0x0d, 0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x07, 0x2e,
   0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x07, 0x2e, 0x90, 0x7f, 0xb4, 0xe0, 0x44}},
  {0x05c6, 64, { 0x01, 0xf0, 0x02, 0x07, 0x2e, 0x90, 0x7f, 0x00, 0xe5, 0x24, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0,
@@ -124,14 +128,14 @@
  {0x0646, 64, { 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0,
   0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x07, 0x2e, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0,
   0x02, 0x07, 0x2e, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1e, 0x24, 0x02, 0x60, 0x03, 0x02,
-  0x07, 0x2e, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x06, 0x12, 0x0d, 0x73, 0x02, 0x07, 0x2e}},
+  0x07, 0x2e, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x06, 0x12, 0x0d, 0x63, 0x02, 0x07, 0x2e}},
  {0x0686, 64, { 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x07, 0x2e, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90,
   0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25,
   0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0,
   0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f}},
  {0x06c6, 64, { 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x60, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x57,
   0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x19, 0x24, 0x02, 0x70, 0x4b, 0x90, 0x7f, 0xea, 0xe0,
-  0xb4, 0x01, 0x05, 0x12, 0x0d, 0x70, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80,
+  0xb4, 0x01, 0x05, 0x12, 0x0d, 0x60, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80,
   0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff}},
  {0x0706, 64, { 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f,
   0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07,
@@ -140,102 +144,102 @@
  {0x0746, 64, { 0x90, 0x7f, 0x95, 0x74, 0xc0, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x18,
   0xf0, 0xe4, 0xf5, 0x8e, 0x90, 0x7f, 0xdf, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0xe4, 0xf5,
   0x08, 0x7f, 0x01, 0x7b, 0x00, 0x74, 0x08, 0x2f, 0xf9, 0xe4, 0x34, 0x00, 0xfa, 0xe4, 0x12, 0x0a,
-  0x11, 0x0f, 0xbf, 0x09, 0xee, 0x75, 0x13, 0x01, 0xe4, 0xf5, 0x12, 0xf5, 0x2e, 0xf5, 0x11}},
- {0x0786, 64, { 0xc2, 0x0e, 0xc2, 0x12, 0xc2, 0x0d, 0xc2, 0x0a, 0xc2, 0x0f, 0xc2, 0x04, 0xd2, 0x0c, 0xd2, 0x0b, 0x90,
-  0x7f, 0x98, 0x74, 0x13, 0xf0, 0x75, 0x18, 0x03, 0x90, 0xc0, 0x00, 0x74, 0x03, 0xf0, 0x7f, 0x0c,
-  0xe4, 0xfd, 0x12, 0x0c, 0x2c, 0x7f, 0x10, 0x8f, 0x17, 0x12, 0x0b, 0xba, 0x90, 0x7f, 0x98, 0x74,
-  0x12, 0xf0, 0x7f, 0x01, 0x8f, 0x16, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f}},
- {0x07c6, 64, { 0x98, 0x74, 0x14, 0xf0, 0x75, 0x19, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0x0f, 0xe4, 0xfd, 0x12,
-  0x0c, 0x2c, 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x15, 0x12, 0x0c, 0x2c, 0x90, 0x7f, 0x98,
-  0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x0c, 0x2c, 0x7f,
-  0x01, 0x12, 0x0c, 0xbc, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x0c, 0x2c, 0xd2, 0x03, 0x22, 0x90}},
- {0x0806, 64, { 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x23, 0xe5, 0x28, 0xf5, 0x82, 0xe5, 0x27, 0xf5, 0x83, 0xc2, 0xaf,
-  0x05, 0x86, 0x90, 0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05, 0x86, 0xdf, 0xf7,
-  0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x23, 0xe5, 0x28, 0xf5, 0x82, 0xe5,
-  0x27, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3}},
- {0x0846, 64, { 0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x23,
-  0xe5, 0x28, 0xf5, 0x82, 0xe5, 0x27, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0x05,
-  0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05, 0x86, 0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98,
-  0x74, 0x08, 0xf0, 0xaf, 0x23, 0xe5, 0x28, 0xf5, 0x82, 0xe5, 0x27, 0xf5, 0x83, 0xc2, 0xaf}},
- {0x0886, 64, { 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2,
-  0xaf, 0x22, 0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83,
-  0x70, 0xf9, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x31, 0x02, 0x09, 0x01}},
- {0x08c6, 64, { 0x02, 0x09, 0x46, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2, 0x08,
-  0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33, 0xc4,
-  0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4,
-  0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x0c, 0xdd, 0xe4, 0x7e}},
- {0x0906, 64, { 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93, 0xa3,
-  0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3, 0xfa,
-  0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0,
-  0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe}},
- {0x0946, 64, { 0xd2, 0x14, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02, 0xf0, 0x12, 0x0d, 0x73, 0xd2, 0xe8, 0x43, 0xd8, 0x20,
-  0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0,
-  0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaf, 0xe0, 0x44,
-  0x01, 0xf0, 0x90, 0x7f, 0xae, 0x74, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0x15, 0x12, 0x0c, 0x76}},
- {0x0986, 64, { 0xc2, 0x02, 0xe4, 0xf5, 0x26, 0xf5, 0x2e, 0xc2, 0x08, 0xc2, 0x03, 0x90, 0x7f, 0xa1, 0x04, 0xf0, 0x90,
-  0x7f, 0xd8, 0xe0, 0x65, 0x1a, 0x60, 0x10, 0x30, 0x03, 0x05, 0xd2, 0x15, 0x12, 0x00, 0x46, 0x90,
-  0x7f, 0xd8, 0xe0, 0xf5, 0x1a, 0x80, 0x08, 0x30, 0x03, 0x05, 0xc2, 0x15, 0x12, 0x00, 0x46, 0x30,
-  0x02, 0x07, 0xc2, 0x02, 0x12, 0x05, 0x20, 0x80, 0xd6, 0x30, 0x09, 0xd3, 0xc2, 0x09, 0x12}},
- {0x09c6, 64, { 0x0a, 0xf1, 0x80, 0xcc, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7,
-  0x22, 0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x0c,
-  0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9, 0x25,
-  0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82}},
- {0x0a06, 64, { 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a,
-  0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xd0, 0x83, 0xd0, 0x82,
-  0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01,
-  0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3}},
- {0x0a46, 64, { 0xa3, 0x80, 0xdf, 0x8f, 0x1b, 0xe4, 0xf5, 0x1c, 0x75, 0x1d, 0xff, 0x75, 0x1e, 0x19, 0x75, 0x1f, 0x86,
-  0xab, 0x1d, 0xaa, 0x1e, 0xa9, 0x1f, 0x90, 0x00, 0x01, 0x12, 0x09, 0xe4, 0xb4, 0x03, 0x1d, 0xaf,
-  0x1c, 0x05, 0x1c, 0xef, 0xb5, 0x1b, 0x01, 0x22, 0x12, 0x09, 0xcb, 0x7e, 0x00, 0x29, 0xff, 0xee,
-  0x3a, 0xa9, 0x07, 0x75, 0x1d, 0xff, 0xf5, 0x1e, 0x89, 0x1f, 0x80, 0xd4, 0x7b, 0x00, 0x7a}},
- {0x0a86, 64, { 0x00, 0x79, 0x00, 0x22, 0x8f, 0x1d, 0x05, 0x28, 0xe5, 0x28, 0xae, 0x27, 0x70, 0x02, 0x05, 0x27, 0x14,
-  0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x1d, 0xf0, 0x12, 0x00, 0x36, 0x05, 0x28, 0xe5, 0x28, 0xac, 0x27,
-  0x70, 0x02, 0x05, 0x27, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x23, 0xe5, 0x23, 0x60,
-  0x0a, 0x12, 0x0d, 0x54, 0x8f, 0x1d, 0xef, 0x42, 0x11, 0x80, 0xca, 0x22, 0xc0, 0xe0, 0xc0}},
- {0x0ac6, 64, { 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x30, 0x06, 0x04, 0xc2, 0x06,
-  0x80, 0x02, 0xd2, 0x09, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08, 0xf0, 0xd0, 0x86, 0xd0,
-  0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7f, 0xd8, 0xe0, 0xf5, 0x1b,
-  0x12, 0x00, 0x03, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x08, 0xaa, 0x90, 0x7f}},
- {0x0b06, 64, { 0xd6, 0xe0, 0x30, 0xe7, 0x0e, 0x30, 0x01, 0x05, 0x12, 0x0d, 0x0e, 0x80, 0x06, 0x12, 0x0c, 0x9b, 0xef,
-  0x60, 0xe1, 0x12, 0x07, 0x36, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84,
-  0xc0, 0x86, 0x75, 0x86, 0x00, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab,
-  0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0}},
- {0x0b46, 64, { 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2,
-  0x02, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85,
+  0x0d, 0x0f, 0xbf, 0x09, 0xee, 0x75, 0x13, 0x01, 0xe4, 0xf5, 0x12, 0xf5, 0x2e, 0xf5, 0x11}},
+ {0x0786, 64, { 0xc2, 0x0e, 0xc2, 0x12, 0xc2, 0x0d, 0xc2, 0x0a, 0xc2, 0x0f, 0xc2, 0x04, 0x90, 0x7f, 0x98, 0x74, 0x13,
+  0xf0, 0x75, 0x18, 0x03, 0x90, 0xc0, 0x00, 0x74, 0x03, 0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x0c,
+  0x1c, 0x7f, 0x10, 0x8f, 0x17, 0x12, 0x0b, 0xaa, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x7f, 0x01,
+  0x8f, 0x16, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x0f, 0xe4, 0xfd, 0x12, 0x0c, 0x1c}},
+ {0x07c6, 64, { 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x15, 0x12, 0x0c, 0x1c, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0,
+  0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x0c, 0x1c, 0x7f, 0x01, 0x12, 0x0c,
+  0xac, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x0c, 0x1c, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x75, 0x19,
+  0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0xd2, 0x03, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10}},
+ {0x0806, 64, { 0xf0, 0xaf, 0x23, 0xe5, 0x28, 0xf5, 0x82, 0xe5, 0x27, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0,
+  0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05, 0x86, 0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90,
+  0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x23, 0xe5, 0x28, 0xf5, 0x82, 0xe5, 0x27, 0xf5, 0x83, 0xc2,
+  0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7}},
+ {0x0846, 64, { 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x23, 0xe5, 0x28, 0xf5, 0x82,
+  0xe5, 0x27, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05,
+  0x86, 0xf0, 0x05, 0x86, 0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf,
+  0x23, 0xe5, 0x28, 0xf5, 0x82, 0xe5, 0x27, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0}},
+ {0x0886, 64, { 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x74, 0x00,
+  0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9, 0x22, 0x90,
+  0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x78,
+  0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x31, 0x02, 0x08, 0xfd, 0x02, 0x09, 0x42, 0xe4}},
+ {0x08c6, 64, { 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29,
+  0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20,
+  0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02,
+  0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x0c, 0xcd, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc}},
+ {0x0906, 64, { 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf,
+  0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8,
+  0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82,
+  0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe, 0xd2, 0x14, 0x90, 0x7f}},
+ {0x0946, 64, { 0x92, 0xe0, 0x44, 0x02, 0xf0, 0x12, 0x0d, 0x63, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74,
+  0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0,
+  0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f,
+  0xae, 0x74, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0x15, 0x12, 0x0c, 0x66, 0xc2, 0x02, 0xe4, 0xf5}},
+ {0x0986, 64, { 0x26, 0xf5, 0x2e, 0xc2, 0x08, 0xc2, 0x03, 0x90, 0x7f, 0xa1, 0x04, 0xf0, 0x90, 0x7f, 0xd8, 0xe0, 0x65,
+  0x1a, 0x60, 0x10, 0x30, 0x03, 0x05, 0xd2, 0x15, 0x12, 0x00, 0x46, 0x90, 0x7f, 0xd8, 0xe0, 0xf5,
+  0x1a, 0x80, 0x08, 0x30, 0x03, 0x05, 0xc2, 0x15, 0x12, 0x00, 0x46, 0x30, 0x02, 0x07, 0xc2, 0x02,
+  0x12, 0x05, 0x20, 0x80, 0xd6, 0x30, 0x09, 0xd3, 0xc2, 0x09, 0x12, 0x0a, 0xba, 0x80, 0xcc}},
+ {0x09c6, 64, { 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02,
+  0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5,
+  0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22,
+  0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5}},
+ {0x0a06, 64, { 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0x22, 0x50,
+  0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70,
+  0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88,
+  0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0x8f}},
+ {0x0a46, 64, { 0x1b, 0xe4, 0xf5, 0x1c, 0x75, 0x1d, 0xff, 0x75, 0x1e, 0x19, 0x75, 0x1f, 0x86, 0xab, 0x1d, 0xaa, 0x1e,
+  0xa9, 0x1f, 0x90, 0x00, 0x01, 0x12, 0x09, 0xe0, 0xb4, 0x03, 0x1d, 0xaf, 0x1c, 0x05, 0x1c, 0xef,
+  0xb5, 0x1b, 0x01, 0x22, 0x12, 0x09, 0xc7, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75,
+  0x1d, 0xff, 0xf5, 0x1e, 0x89, 0x1f, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x22}},
+ {0x0a86, 64, { 0x05, 0x28, 0xe5, 0x28, 0xae, 0x27, 0x70, 0x02, 0x05, 0x27, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x11,
+  0xf0, 0x12, 0x00, 0x36, 0x05, 0x28, 0xe5, 0x28, 0xac, 0x27, 0x70, 0x02, 0x05, 0x27, 0x14, 0xf5,
+  0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x23, 0xe5, 0x23, 0x60, 0x07, 0x12, 0x0d, 0x44, 0x8f, 0x11,
+  0x80, 0xcd, 0x22, 0x90, 0x7f, 0xd8, 0xe0, 0xf5, 0x1b, 0x12, 0x00, 0x03, 0x90, 0x7f, 0xd6}},
+ {0x0ac6, 64, { 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x08, 0xa6, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x0e, 0x30, 0x01, 0x05,
+  0x12, 0x0c, 0xfe, 0x80, 0x06, 0x12, 0x0c, 0x8b, 0xef, 0x60, 0xe1, 0x12, 0x07, 0x36, 0x22, 0xc0,
+  0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90, 0x7f,
+  0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0}},
+ {0x0b06, 64, { 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0,
+  0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x02, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab,
+  0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32,
+  0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00}},
+ {0x0b46, 64, { 0xd2, 0x09, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85,
   0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00,
-  0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90}},
- {0x0b86, 64, { 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98,
-  0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90,
+  0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f,
+  0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f}},
+ {0x0b86, 64, { 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90,
   0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54, 0x7f, 0x90, 0xc0,
-  0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0}},
- {0x0bc6, 64, { 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0,
-  0xe5, 0x18, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90,
+  0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90,
+  0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13}},
+ {0x0bc6, 64, { 0xf0, 0xe5, 0x18, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90,
   0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0,
-  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22}},
- {0x0c06, 64, { 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x16,
-  0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54, 0x7f,
+  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90,
+  0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74}},
+ {0x0c06, 64, { 0x16, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54, 0x7f,
   0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54, 0x7f, 0x90,
-  0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x17, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90}},
- {0x0c46, 64, { 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22, 0x12, 0x0d, 0x3c, 0x8f, 0x1d, 0x12,
-  0x0d, 0x3c, 0x8f, 0x1e, 0xe5, 0x1d, 0x65, 0x1e, 0x60, 0x12, 0x12, 0x0d, 0x3c, 0x8f, 0x1d, 0xe5,
-  0x1d, 0x65, 0x1e, 0x60, 0x07, 0x12, 0x0d, 0x3c, 0x8f, 0x1e, 0x80, 0xe8, 0xaf, 0x1d, 0x22, 0x90,
-  0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x15, 0x04, 0xe0, 0x44}},
- {0x0c86, 64, { 0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x0c, 0xf7, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0, 0xe0,
-  0x44, 0x04, 0xf0, 0x22, 0x90, 0x7f, 0xd8, 0xe0, 0xf5, 0x1c, 0x12, 0x07, 0x36, 0x12, 0x0d, 0x60,
+  0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x17, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f,
+  0x98, 0x74, 0x15, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22, 0x12, 0x0d, 0x2c, 0x8f, 0x1d}},
+ {0x0c46, 64, { 0x12, 0x0d, 0x2c, 0x8f, 0x1e, 0xe5, 0x1d, 0x65, 0x1e, 0x60, 0x12, 0x12, 0x0d, 0x2c, 0x8f, 0x1d, 0xe5,
+  0x1d, 0x65, 0x1e, 0x60, 0x07, 0x12, 0x0d, 0x2c, 0x8f, 0x1e, 0x80, 0xe8, 0xaf, 0x1d, 0x22, 0x90,
+  0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x15, 0x04, 0xe0, 0x44, 0x02,
+  0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x0c, 0xe7, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0}},
+ {0x0c86, 64, { 0xe0, 0x44, 0x04, 0xf0, 0x22, 0x90, 0x7f, 0xd8, 0xe0, 0xf5, 0x1c, 0x12, 0x07, 0x36, 0x12, 0x0d, 0x50,
   0xef, 0x30, 0xe6, 0x0b, 0x90, 0x7f, 0xd8, 0xe0, 0x65, 0x1c, 0x60, 0xf1, 0x7f, 0x01, 0x22, 0x12,
-  0x00, 0x03, 0x7f, 0x00, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5, 0x15, 0x54, 0x7f, 0xfd, 0x12}},
- {0x0cc6, 64, { 0x0c, 0x2c, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x15, 0x44,
-  0x80, 0xfd, 0x12, 0x0c, 0x2c, 0x22, 0x05, 0x29, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x2f, 0x03,
+  0x00, 0x03, 0x7f, 0x00, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5, 0x15, 0x54, 0x7f, 0xfd, 0x12, 0x0c,
+  0x1c, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x15}},
+ {0x0cc6, 64, { 0x44, 0x80, 0xfd, 0x12, 0x0c, 0x1c, 0x22, 0x05, 0x29, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x2f, 0x03,
   0x00, 0x00, 0xc1, 0x86, 0xc1, 0x02, 0xc1, 0x09, 0xc1, 0x01, 0xc1, 0x07, 0x01, 0x25, 0x00, 0x00,
-  0x8e, 0x1c, 0x8f, 0x1d, 0xe5, 0x1d, 0x15, 0x1d, 0xae, 0x1c, 0x70, 0x02, 0x15, 0x1c, 0x4e}},
- {0x0d06, 64, { 0x60, 0x05, 0x12, 0x08, 0x99, 0x80, 0xee, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x0d,
-  0x7e, 0x00, 0x12, 0x0c, 0xf7, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22, 0x90, 0x7f, 0x98,
+  0x8e, 0x1c, 0x8f, 0x1d, 0xe5, 0x1d, 0x15, 0x1d, 0xae, 0x1c, 0x70, 0x02, 0x15, 0x1c, 0x4e, 0x60,
+  0x05, 0x12, 0x08, 0x95, 0x80, 0xee, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x01, 0xf0, 0x7f}},
+ {0x0d06, 64, { 0x0d, 0x7e, 0x00, 0x12, 0x0c, 0xe7, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22, 0x90, 0x7f, 0x98,
   0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90,
-  0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe0}},
- {0x0d46, 64, { 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98,
-  0x74, 0x15, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90,
+  0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff,
+  0x22, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f}},
+ {0x0d46, 64, { 0x98, 0x74, 0x15, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90,
   0xc0, 0x00, 0xe0, 0xff, 0x22, 0x53, 0xd8, 0xef, 0x32, 0xd2, 0x01, 0x22, 0xc2, 0x01, 0x22, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
  {0x0d86, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -244,8 +248,8 @@
  {0x0dc6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0b, 0x47, 0x00, 0x02, 0x0e}},
- {0x0e06, 64, { 0x04, 0x00, 0x02, 0x0b, 0x1d, 0x00, 0x02, 0x0a, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0b, 0x10, 0x00, 0x02, 0x0e}},
+ {0x0e06, 64, { 0x04, 0x00, 0x02, 0x0a, 0xe6, 0x00, 0x02, 0x0b, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
@@ -420,15 +424,15 @@
  {0x18c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x01, 0xff, 0x00}},
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x10, 0x01, 0xff, 0x00}},
  {0x1906, 64, { 0x00, 0x40, 0xcd, 0x06, 0x08, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x02, 0x09, 0x02, 0x74, 0x00, 0x01,
   0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e, 0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01,
   0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40,
   0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x05, 0x02, 0x40, 0x00}},
  {0x1946, 64, { 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x07, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05,
-  0x81, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x83, 0x02,
-  0x40, 0x00, 0x00, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00,
-  0x01, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x87, 0x02, 0x40, 0x00, 0x01}},
+  0x81, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x83, 0x02,
+  0x40, 0x00, 0x01, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00,
+  0x01, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x87, 0x02, 0x40, 0x00, 0x01}},
  {0x1986, 64, { 0x04, 0x03, 0x09, 0x04, 0x48, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61,
   0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x61, 0x00, 0x20, 0x00, 0x64, 0x00, 0x69, 0x00, 0x76,
   0x00, 0x69, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66,
@@ -438,5 +442,5 @@
   0x00, 0x42, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c,
   0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x61, 0x00, 0x70, 0x00, 0x74, 0x00, 0x65, 0x00}},
  {0x1a06,  4, { 0x72, 0x00, 0x00, 0x00}},
-{ 0xffff,	0,	{0x00} }
+ {0xffff,	0,	{0x00} }
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/keyspan_usa26msg.h linux-2.4.20/drivers/usb/serial/keyspan_usa26msg.h
--- linux-2.4.19/drivers/usb/serial/keyspan_usa26msg.h	2001-10-09 22:15:02.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/keyspan_usa26msg.h	2002-10-29 11:18:31.000000000 +0000
@@ -44,7 +44,7 @@
 	Buffer formats for RX/TX data messages are not defined by
 	a structure, but are described here:
 
-	USB OUT (host -> USA26, transmit) messages contain a 
+	USB OUT (host -> USAxx, transmit) messages contain a 
 	REQUEST_ACK indicator (set to 0xff to request an ACK at the 
 	completion of transmit; 0x00 otherwise), followed by data:
 
@@ -52,25 +52,48 @@
 
 	with a total data length of 63.
 
-	USB IN (USA26 -> host, receive) messages contain either a zero
-	flag (indicating no error in any data bytes):
+	USB IN (USAxx -> host, receive) messages begin with a status
+	byte in which the 0x80 bit is either:
 
-		00 DAT DAT DAT ...
+		(a)	0x80 bit clear
+			indicates that the bytes following it are all data
+			bytes:
 
-	for a total of 63 data bytes, or a non-zero status flag (indicating 
-	that all data bytes will be preceded by status flag):
+				STAT DATA DATA DATA DATA DATA ...
 
-		STAT DAT STAT DAT STAT DAT ...
+			for a total of up to 63 DATA bytes,
 
-	for a total of 32 data bytes.  The valid bits in the STAT bytes are:
+	or:
+
+		(b)	0x80 bit set
+			indiates that the bytes following alternate data and
+			status bytes:
+
+				STAT DATA STAT DATA STAT DATA STAT DATA ...
+
+			for a total of up to 32 DATA bytes.
+
+	The valid bits in the STAT bytes are:
 
 		OVERRUN	0x02
 		PARITY	0x04
 		FRAMING	0x08
 		BREAK	0x10
 
-	Note: a "no status" RX data message (first byte zero) can serve as
-	a "break off" indicator.
+	Notes:
+
+	(1) The OVERRUN bit can appear in either (a) or (b) format
+		messages, but the but the PARITY/FRAMING/BREAK bits
+		only appear in (b) format messages.
+	(2) For the host to determine the exact point at which the
+		overrun occurred (to identify the point in the data
+		stream at which the data was lost), it needs to count
+		128 characters, starting at the first character of the
+		message in which OVERRUN was reported; the lost character(s)
+		would have been received between the 128th and 129th
+		characters.
+	(3)	An RX data message in which the first byte has 0x80 clear
+		serves as a "break off" indicator.
 
 	revision history:
 
@@ -80,6 +103,7 @@
 	1999apr14	add resetDataToggle to control message
 	2000jan04	merge with usa17msg.h
 	2000jun01	add extended BSD-style copyright text
+	2001jul05	change message format to improve OVERRUN case
 
 	Note on shared names:
 
@@ -93,7 +117,7 @@
 #define	__USA26MSG__
 
 
-typedef struct keyspan_usa26_portControlMessage
+struct keyspan_usa26_portControlMessage
 {
 	/*
 		there are three types of "commands" sent in the control message:
@@ -164,7 +188,7 @@
 		returnStatus,	// BOTH: return current status (even if it hasn't changed)
 		resetDataToggle;// BOTH: reset data toggle state to DATA0
 	
-} keyspan_usa26_portControlMessage;
+};
 
 // defines for bits in lcr
 #define	USA_DATABITS_5		0x00
@@ -182,7 +206,7 @@
 
 // all things called "StatusMessage" are sent on the status endpoint
 
-typedef struct keyspan_usa26_portStatusMessage	// one for each port
+struct keyspan_usa26_portStatusMessage	// one for each port
 {
 	u8	port,			// BOTH: 0=first, 1=second, other=see below
 		hskia_cts,		// USA26: reports HSKIA pin
@@ -195,7 +219,7 @@
 		_txXoff,		// port is in XOFF state (either host or RX XOFF)
 		rxEnabled,		// as configured by rxOn/rxOff 1=on, 0=off
 		controlResponse;// 1=a control message has been processed
-} keyspan_usa26_portStatusMessage;
+};
 
 // bits in RX data message when STAT byte is included
 #define	RXERROR_OVERRUN	0x02
@@ -203,28 +227,28 @@
 #define	RXERROR_FRAMING	0x08
 #define	RXERROR_BREAK	0x10
 
-typedef struct keyspan_usa26_globalControlMessage
+struct keyspan_usa26_globalControlMessage
 {
 	u8	sendGlobalStatus,	// 2=request for two status responses
 		resetStatusToggle,	// 1=reset global status toggle
 		resetStatusCount;	// a cycling value
-} keyspan_usa26_globalControlMessage;
+};
 
-typedef struct keyspan_usa26_globalStatusMessage
+struct keyspan_usa26_globalStatusMessage
 {
 	u8	port,				// 3
 		sendGlobalStatus,	// from request, decremented
 		resetStatusCount;	// as in request
-} keyspan_usa26_globalStatusMessage;
+};
 
-typedef struct keyspan_usa26_globalDebugMessage
+struct keyspan_usa26_globalDebugMessage
 {
 	u8	port,				// 2
 		a,
 		b,
 		c,
 		d;
-} keyspan_usa26_globalDebugMessage;
+};
 
 // ie: the maximum length of an EZUSB endpoint buffer
 #define	MAX_DATA_LEN			64
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/keyspan_usa28_fw.h linux-2.4.20/drivers/usb/serial/keyspan_usa28_fw.h
--- linux-2.4.19/drivers/usb/serial/keyspan_usa28_fw.h	2001-10-09 22:15:02.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/keyspan_usa28_fw.h	2002-10-29 11:18:40.000000000 +0000
@@ -1,28 +1,33 @@
 /* keyspan_usa28_fw.h
-  
-   Generated from Keyspan firmware image usa28code.h Sat Oct  6 12:11:26 EST 2001
-   This firmware is for the Keyspan USA-28 Serial Adaptor
 
-   "The firmware contained herein as keyspan_usa28_fw.h is
-   Copyright (C) 1999-2001 Keyspan, A division of InnoSys Incorporated
-   ("Keyspan"), as an unpublished work.  This notice does not imply
-   unrestricted or public access to this firmware which is a trade secret of
-   Keyspan, and which may not be reproduced, used, sold or transferred to any
-   third party without Keyspan's prior written consent.  All Rights Reserved.
+	The firmware contained herein as keyspan_usa28_fw.h is
 
-   This firmware may not be modified and may only be used with the Keyspan 
-   USA-28 Serial Adapter.  Distribution and/or Modification of the
-   keyspan.c driver which includes this firmware, in whole or in part,
-   requires the inclusion of this statement."
+		Copyright (C) 1999-2001
+		Keyspan, A division of InnoSys Incorporated ("Keyspan")
+		
+	as an unpublished work. This notice does not imply unrestricted or
+	public access to the source code from which this firmware image is
+	derived.  Except as noted below this firmware image may not be 
+	reproduced, used, sold or transferred to any third party without 
+	Keyspan's prior written consent.  All Rights Reserved.
+
+	Permission is hereby granted for the distribution of this firmware 
+	image as part of a Linux or other Open Source operating system kernel 
+	in text or binary form as required. 
+
+	This firmware may not be modified and may only be used with  
+	Keyspan hardware.  Distribution and/or Modification of the 
+	keyspan.c driver which includes this firmware, in whole or in 
+	part, requires the inclusion of this statement."
 
 */
 
 static const struct ezusb_hex_record keyspan_usa28_firmware[] = {
- {0x0026, 10, { 0x12, 0x18, 0x09, 0x12, 0x18, 0xbc, 0x12, 0x14, 0xbb, 0x22}},
+ {0x0026, 10, { 0x12, 0x17, 0xdb, 0x12, 0x18, 0xb5, 0x12, 0x14, 0xc3, 0x22}},
  {0x0033,  3, { 0x02, 0x00, 0x1d}},
  {0x001d,  4, { 0x53, 0xd8, 0xef, 0x32}},
  {0x0006, 16, { 0x8e, 0x12, 0x8f, 0x13, 0xe5, 0x13, 0x15, 0x13, 0xae, 0x12, 0x70, 0x02, 0x15, 0x12, 0x4e, 0x60}},
- {0x0016,  7, { 0x05, 0x12, 0x18, 0xab, 0x80, 0xee, 0x22}},
+ {0x0016,  7, { 0x05, 0x12, 0x18, 0xa4, 0x80, 0xee, 0x22}},
  {0x0003,  3, { 0x02, 0x00, 0x46}},
  {0x0046, 16, { 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0, 0xd0, 0x75, 0xd0, 0x08}},
  {0x0056, 16, { 0x30, 0x99, 0x0e, 0x30, 0x11, 0x07, 0xa2, 0x17, 0x92, 0x9b, 0x85, 0x46, 0x99, 0xc2, 0x99, 0xd2}},
@@ -192,7 +197,7 @@
   0x40, 0x15, 0x15, 0x49, 0x15, 0x49, 0x05, 0x39, 0xd2, 0x0e, 0x80, 0x0b, 0x90, 0x7f, 0xbd, 0xe5,
   0x49, 0xf0, 0x75, 0x49, 0x00, 0xd2, 0x02, 0xd2, 0x25, 0x30, 0x25, 0x05, 0xc2, 0x25, 0x02, 0x00,
   0x56, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7f, 0xce}},
- {0x0a86, 64, { 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x0b, 0xa1, 0xe4, 0xf5, 0x12, 0x74, 0x40, 0x25, 0x12, 0xf5, 0x82, 0xe4,
+ {0x0a86, 64, { 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x0b, 0xa5, 0xe4, 0xf5, 0x12, 0x74, 0x40, 0x25, 0x12, 0xf5, 0x82, 0xe4,
   0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x12, 0x7c, 0x00, 0x7b, 0x00, 0x24, 0x4c, 0xf9, 0xec,
   0x34, 0x00, 0xfa, 0xef, 0x12, 0x15, 0xcd, 0x05, 0x12, 0xe5, 0x12, 0xb4, 0x18, 0xdb, 0xe5, 0x4c,
   0x60, 0x0c, 0x75, 0xc9, 0x20, 0x75, 0xc8, 0x36, 0x85, 0x4d, 0xca, 0x85, 0x4e, 0xcb, 0xe5}},
@@ -207,166 +212,166 @@
  {0x0b46, 64, { 0x02, 0xf0, 0x90, 0x7f, 0x98, 0xe0, 0x54, 0xfd, 0xf0, 0xe5, 0x5e, 0x60, 0x0a, 0xd2, 0x9c, 0xc2, 0x98,
   0x75, 0x2e, 0x01, 0x75, 0x40, 0x28, 0xe5, 0x5f, 0x60, 0x07, 0xc2, 0x9c, 0xe4, 0xf5, 0x48, 0xf5,
   0x2e, 0xe5, 0x60, 0x60, 0x03, 0xe4, 0xf5, 0x48, 0xe5, 0x61, 0x60, 0x02, 0xd2, 0x07, 0xe5, 0x62,
-  0x60, 0x08, 0xe5, 0x5e, 0x70, 0x02, 0xf5, 0x40, 0xd2, 0x0c, 0xe5, 0x63, 0x60, 0x15, 0x90}},
+  0x60, 0x08, 0xe5, 0x5e, 0x70, 0x02, 0xf5, 0x40, 0xd2, 0x0c, 0xe5, 0x63, 0x60, 0x19, 0x90}},
  {0x0b86, 64, { 0x7f, 0xd7, 0x74, 0x11, 0xf0, 0x74, 0x31, 0xf0, 0x74, 0x12, 0xf0, 0x74, 0x32, 0xf0, 0x74, 0x15, 0xf0,
-  0x74, 0x35, 0xf0, 0xd2, 0x09, 0xe4, 0x90, 0x7f, 0xcf, 0xf0, 0xa2, 0x13, 0xe4, 0x33, 0xff, 0x65,
-  0x2b, 0x60, 0x04, 0x8f, 0x2b, 0xd2, 0x0c, 0xa2, 0x0b, 0xe4, 0x33, 0xff, 0x65, 0x2c, 0x60, 0x04,
-  0x8f, 0x2c, 0xd2, 0x0c, 0x90, 0x7f, 0x9b, 0xe0, 0x54, 0x08, 0x65, 0x27, 0x60, 0x07, 0xe0}},
- {0x0bc6, 64, { 0x54, 0x08, 0xf5, 0x27, 0xd2, 0x0c, 0x90, 0x7f, 0x9b, 0xe0, 0x54, 0x40, 0xb5, 0x29, 0x09, 0xe0, 0x54,
-  0x40, 0x64, 0x40, 0xf5, 0x29, 0xd2, 0x0c, 0x30, 0x07, 0x35, 0xc2, 0xaf, 0x30, 0x01, 0x18, 0x90,
-  0x7f, 0xb8, 0xe0, 0x20, 0xe1, 0x27, 0xe5, 0x48, 0x60, 0x09, 0x90, 0x7f, 0xb7, 0xf0, 0xe4, 0xf5,
-  0x48, 0xc2, 0x01, 0xc2, 0x07, 0x80, 0x16, 0x90, 0x7f, 0xb6, 0xe0, 0x20, 0xe1, 0x0f, 0xe5}},
- {0x0c06, 64, { 0x48, 0x60, 0x09, 0x90, 0x7f, 0xb9, 0xf0, 0xe4, 0xf5, 0x48, 0xd2, 0x01, 0xc2, 0x07, 0xd2, 0xaf, 0x20,
-  0x05, 0x37, 0x30, 0x03, 0x1b, 0x90, 0x7f, 0xc6, 0xe0, 0x20, 0xe1, 0x2d, 0x90, 0x7e, 0x40, 0xe0,
-  0x13, 0x92, 0x15, 0x75, 0x4a, 0x01, 0x90, 0x7f, 0xc7, 0xe0, 0xf5, 0x7c, 0xd2, 0x05, 0x80, 0x19,
-  0x90, 0x7f, 0xc8, 0xe0, 0x20, 0xe1, 0x12, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x15, 0x75}},
- {0x0c46, 64, { 0x4a, 0x01, 0x90, 0x7f, 0xc9, 0xe0, 0xf5, 0x7c, 0xd2, 0x05, 0x20, 0x21, 0x33, 0x20, 0x00, 0x06, 0xe5,
-  0x4a, 0x65, 0x7c, 0x70, 0x2a, 0x30, 0x05, 0x1a, 0x30, 0x03, 0x09, 0xe4, 0x90, 0x7f, 0xc7, 0xf0,
-  0xc2, 0x03, 0x80, 0x07, 0xe4, 0x90, 0x7f, 0xc9, 0xf0, 0xd2, 0x03, 0xc2, 0x05, 0xe4, 0xf5, 0x7c,
-  0xf5, 0x4a, 0x30, 0x15, 0x0a, 0xc2, 0x15, 0xc2, 0x00, 0x90, 0x7f, 0xbf, 0x74, 0x01, 0xf0}},
- {0x0c86, 64, { 0x30, 0x21, 0x03, 0x02, 0x0d, 0x90, 0x20, 0x05, 0x03, 0x02, 0x0d, 0x90, 0x30, 0x1c, 0x0a, 0x90, 0x7f,
-  0x9b, 0xe0, 0x20, 0xe3, 0x03, 0x02, 0x0d, 0x90, 0x30, 0x0b, 0x03, 0x02, 0x0d, 0x90, 0x30, 0x13,
-  0x03, 0x02, 0x0d, 0x90, 0x30, 0x03, 0x62, 0x30, 0x1b, 0x12, 0xaf, 0x4a, 0x05, 0x4a, 0x74, 0x40,
-  0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x2d, 0xaf, 0x4a, 0x05}},
- {0x0cc6, 64, { 0x4a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5, 0x13, 0xe5, 0x4a, 0xc3,
-  0x95, 0x7c, 0x50, 0x2a, 0x30, 0x1b, 0x12, 0xaf, 0x4a, 0x05, 0x4a, 0x74, 0x40, 0x2f, 0xf5, 0x82,
-  0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x17, 0xaf, 0x4a, 0x05, 0x4a, 0x74, 0x40, 0x2f,
-  0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5, 0x46, 0xd2, 0x11, 0x80, 0x6b, 0xc2}},
- {0x0d06, 64, { 0x11, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0xc2, 0x03, 0x80, 0x60, 0x30, 0x1b, 0x12, 0xaf, 0x4a, 0x05, 0x4a,
-  0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x2d, 0xaf, 0x4a,
-  0x05, 0x4a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x13, 0xe5,
-  0x4a, 0xc3, 0x95, 0x7c, 0x50, 0x2a, 0x30, 0x1b, 0x12, 0xaf, 0x4a, 0x05, 0x4a, 0x74, 0xc0}},
- {0x0d46, 64, { 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x17, 0xaf, 0x4a, 0x05, 0x4a, 0x74,
-  0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x46, 0xd2, 0x11, 0x80, 0x09,
-  0xc2, 0x11, 0xe4, 0x90, 0x7f, 0xc9, 0xf0, 0xd2, 0x03, 0x30, 0x1b, 0x04, 0xa2, 0x2d, 0x92, 0x9b,
-  0xd2, 0x21, 0xc2, 0xaf, 0x85, 0x13, 0x99, 0x20, 0x11, 0x0d, 0x30, 0x15, 0x0a, 0xc2, 0x15}},
- {0x0d86, 64, { 0xc2, 0x00, 0x90, 0x7f, 0xbf, 0x74, 0x01, 0xf0, 0xd2, 0xaf, 0x90, 0x7f, 0xd0, 0xe0, 0x30, 0xe1, 0x03,
-  0x02, 0x0e, 0xad, 0xe4, 0xf5, 0x12, 0x74, 0xc0, 0x25, 0x12, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5,
-  0x83, 0xe0, 0xff, 0xe5, 0x12, 0x7c, 0x00, 0x7b, 0x00, 0x24, 0x64, 0xf9, 0xec, 0x34, 0x00, 0xfa,
-  0xef, 0x12, 0x15, 0xcd, 0x05, 0x12, 0xe5, 0x12, 0xb4, 0x18, 0xdb, 0xe5, 0x64, 0x60, 0x0b}},
- {0x0dc6, 64, { 0x75, 0x89, 0x60, 0x75, 0x88, 0x40, 0xd2, 0xdf, 0x85, 0x65, 0x8d, 0xe5, 0x67, 0x13, 0x92, 0x1d, 0x92,
-  0xc7, 0xe5, 0x68, 0x13, 0x92, 0x1e, 0xe5, 0x69, 0x13, 0x92, 0x24, 0xe5, 0x6a, 0x60, 0x09, 0x90,
-  0x7f, 0x97, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0x97, 0xe0, 0x44, 0x10, 0xf0, 0xe5,
-  0x6b, 0x60, 0x09, 0x90, 0x7f, 0x97, 0xe0, 0x54, 0x7f, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0x97}},
- {0x0e06, 64, { 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x71, 0x60, 0x0b, 0xc2, 0x14, 0xc2, 0x0d, 0x90, 0x7f, 0x94, 0xe0, 0x44,
-  0x08, 0xf0, 0xe5, 0x72, 0x60, 0x0b, 0xd2, 0x0d, 0xd2, 0x0e, 0x90, 0x7f, 0x94, 0xe0, 0x44, 0x08,
-  0xf0, 0xe5, 0x73, 0x60, 0x0d, 0xc2, 0xaf, 0xc2, 0x12, 0xd2, 0x00, 0xe4, 0xf5, 0x7d, 0xf5, 0x4b,
-  0xd2, 0xaf, 0xe5, 0x74, 0x60, 0x05, 0x30, 0x24, 0x02, 0xd2, 0x0d, 0xe5, 0x75, 0x60, 0x15}},
- {0x0e46, 64, { 0x90, 0x7f, 0x94, 0xe0, 0x54, 0xf7, 0xf0, 0x90, 0x7f, 0x9d, 0xe0, 0x44, 0x08, 0xf0, 0x90, 0x7f, 0x97,
-  0xe0, 0x54, 0xf7, 0xf0, 0xe5, 0x76, 0x60, 0x0a, 0xd2, 0xc4, 0xc2, 0xc0, 0x75, 0x3a, 0x01, 0x75,
-  0x41, 0x28, 0xe5, 0x77, 0x60, 0x07, 0xc2, 0xc4, 0xe4, 0xf5, 0x49, 0xf5, 0x3a, 0xe5, 0x78, 0x60,
-  0x03, 0xe4, 0xf5, 0x49, 0xe5, 0x79, 0x60, 0x02, 0xd2, 0x08, 0xe5, 0x7a, 0x60, 0x08, 0xe5}},
- {0x0e86, 64, { 0x76, 0x70, 0x02, 0xf5, 0x41, 0xd2, 0x0e, 0xe5, 0x7b, 0x60, 0x15, 0x90, 0x7f, 0xd7, 0x74, 0x13, 0xf0,
-  0x74, 0x33, 0xf0, 0x74, 0x14, 0xf0, 0x74, 0x34, 0xf0, 0x74, 0x16, 0xf0, 0x74, 0x36, 0xf0, 0xd2,
-  0x0a, 0xe4, 0x90, 0x7f, 0xd1, 0xf0, 0xa2, 0x14, 0xe4, 0x33, 0xff, 0x65, 0x37, 0x60, 0x04, 0x8f,
-  0x37, 0xd2, 0x0e, 0xa2, 0x0d, 0xe4, 0x33, 0xff, 0x65, 0x38, 0x60, 0x04, 0x8f, 0x38, 0xd2}},
- {0x0ec6, 64, { 0x0e, 0x90, 0x7f, 0x9a, 0xe0, 0x54, 0x20, 0x65, 0x33, 0x60, 0x07, 0xe0, 0x54, 0x20, 0xf5, 0x33, 0xd2,
-  0x0e, 0x90, 0x7f, 0x9a, 0xe0, 0x54, 0x40, 0xb5, 0x35, 0x09, 0xe0, 0x54, 0x40, 0x64, 0x40, 0xf5,
-  0x35, 0xd2, 0x0e, 0x30, 0x08, 0x35, 0xc2, 0xaf, 0x30, 0x02, 0x18, 0x90, 0x7f, 0xbc, 0xe0, 0x20,
-  0xe1, 0x27, 0xe5, 0x49, 0x60, 0x09, 0x90, 0x7f, 0xbb, 0xf0, 0xe4, 0xf5, 0x49, 0xc2, 0x02}},
- {0x0f06, 64, { 0xc2, 0x08, 0x80, 0x16, 0x90, 0x7f, 0xba, 0xe0, 0x20, 0xe1, 0x0f, 0xe5, 0x49, 0x60, 0x09, 0x90, 0x7f,
-  0xbd, 0xf0, 0xe4, 0xf5, 0x49, 0xd2, 0x02, 0xc2, 0x08, 0xd2, 0xaf, 0x20, 0x06, 0x37, 0x30, 0x04,
-  0x1b, 0x90, 0x7f, 0xca, 0xe0, 0x20, 0xe1, 0x2d, 0x90, 0x7d, 0x40, 0xe0, 0x13, 0x92, 0x16, 0x75,
-  0x4b, 0x01, 0x90, 0x7f, 0xcb, 0xe0, 0xf5, 0x7d, 0xd2, 0x06, 0x80, 0x19, 0x90, 0x7f, 0xcc}},
- {0x0f46, 64, { 0xe0, 0x20, 0xe1, 0x12, 0x90, 0x7c, 0xc0, 0xe0, 0x13, 0x92, 0x16, 0x75, 0x4b, 0x01, 0x90, 0x7f, 0xcd,
-  0xe0, 0xf5, 0x7d, 0xd2, 0x06, 0x20, 0x22, 0x33, 0x20, 0x00, 0x06, 0xe5, 0x4b, 0x65, 0x7d, 0x70,
-  0x2a, 0x30, 0x06, 0x1a, 0x30, 0x04, 0x09, 0xe4, 0x90, 0x7f, 0xcb, 0xf0, 0xc2, 0x04, 0x80, 0x07,
-  0xe4, 0x90, 0x7f, 0xcd, 0xf0, 0xd2, 0x04, 0xc2, 0x06, 0xe4, 0xf5, 0x7d, 0xf5, 0x4b, 0x30}},
- {0x0f86, 64, { 0x16, 0x0a, 0xc2, 0x16, 0xc2, 0x00, 0x90, 0x7f, 0xc1, 0x74, 0x01, 0xf0, 0x30, 0x22, 0x03, 0x02, 0x10,
-  0x9c, 0x20, 0x06, 0x03, 0x02, 0x10, 0x9c, 0x30, 0x1e, 0x0a, 0x90, 0x7f, 0x9a, 0xe0, 0x20, 0xe5,
-  0x03, 0x02, 0x10, 0x9c, 0x30, 0x0d, 0x03, 0x02, 0x10, 0x9c, 0x30, 0x14, 0x03, 0x02, 0x10, 0x9c,
-  0x30, 0x04, 0x62, 0x30, 0x1d, 0x12, 0xaf, 0x4b, 0x05, 0x4b, 0x74, 0x40, 0x2f, 0xf5, 0x82}},
- {0x0fc6, 64, { 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x2d, 0xaf, 0x4b, 0x05, 0x4b, 0x74, 0x40, 0x2f, 0xf5,
-  0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x13, 0xe5, 0x4b, 0xc3, 0x95, 0x7d, 0x50, 0x2a,
-  0x30, 0x1d, 0x12, 0xaf, 0x4b, 0x05, 0x4b, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5,
-  0x83, 0xe0, 0x13, 0x92, 0x18, 0xaf, 0x4b, 0x05, 0x4b, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4}},
- {0x1006, 64, { 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x47, 0xd2, 0x12, 0x80, 0x6b, 0xc2, 0x12, 0xe4, 0x90, 0x7f, 0xcb,
-  0xf0, 0xc2, 0x04, 0x80, 0x60, 0x30, 0x1d, 0x12, 0xaf, 0x4b, 0x05, 0x4b, 0x74, 0xc0, 0x2f, 0xf5,
-  0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x2d, 0xaf, 0x4b, 0x05, 0x4b, 0x74, 0xc0,
-  0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xf5, 0x13, 0xe5, 0x4b, 0xc3, 0x95}},
- {0x1046, 64, { 0x7d, 0x50, 0x2a, 0x30, 0x1d, 0x12, 0xaf, 0x4b, 0x05, 0x4b, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34,
-  0x7c, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x18, 0xaf, 0x4b, 0x05, 0x4b, 0x74, 0xc0, 0x2f, 0xf5, 0x82,
-  0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xf5, 0x47, 0xd2, 0x12, 0x80, 0x09, 0xc2, 0x12, 0xe4, 0x90,
-  0x7f, 0xcd, 0xf0, 0xd2, 0x04, 0x30, 0x1d, 0x04, 0xa2, 0x2d, 0x92, 0xc3, 0xd2, 0x22, 0xc2}},
- {0x1086, 64, { 0xaf, 0x85, 0x13, 0xc1, 0x20, 0x12, 0x0d, 0x30, 0x16, 0x0a, 0xc2, 0x16, 0xc2, 0x00, 0x90, 0x7f, 0xc1,
-  0x74, 0x01, 0xf0, 0xd2, 0xaf, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x11, 0x72, 0xe5,
-  0x1a, 0x70, 0x46, 0x30, 0x0c, 0x3f, 0xe5, 0x40, 0x70, 0x3b, 0xa2, 0x09, 0x33, 0xf5, 0x31, 0xc2,
-  0x09, 0xc2, 0x0c, 0xe4, 0xf5, 0x12, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x26, 0x25, 0x12, 0xf9}},
- {0x10c6, 64, { 0xee, 0x34, 0x00, 0xfa, 0x12, 0x15, 0x87, 0xff, 0x74, 0x80, 0x25, 0x12, 0xf5, 0x82, 0xe4, 0x34, 0x7b,
-  0xf5, 0x83, 0xef, 0xf0, 0x05, 0x12, 0xe5, 0x12, 0xb4, 0x0c, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x0c,
-  0xf0, 0x75, 0x40, 0x10, 0x22, 0x75, 0x1a, 0x01, 0x22, 0xe5, 0x1a, 0x64, 0x01, 0x70, 0x45, 0x30,
-  0x0e, 0x3e, 0xe5, 0x41, 0x70, 0x3a, 0xa2, 0x0a, 0x33, 0xf5, 0x3d, 0xc2, 0x0a, 0xc2, 0x0e}},
- {0x1106, 64, { 0xe4, 0xf5, 0x12, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x32, 0x25, 0x12, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12,
-  0x15, 0x87, 0xff, 0x74, 0x80, 0x25, 0x12, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0,
-  0x05, 0x12, 0xe5, 0x12, 0xb4, 0x0c, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x0c, 0xf0, 0x75, 0x41, 0x10,
-  0x75, 0x1a, 0x02, 0x22, 0xe5, 0x1c, 0x60, 0x30, 0x15, 0x1c, 0xe4, 0xf5, 0x12, 0x7e, 0x00}},
- {0x1146, 64, { 0x7b, 0x00, 0x74, 0x1b, 0x25, 0x12, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x15, 0x87, 0xff, 0x74, 0x80,
-  0x25, 0x12, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x12, 0xe5, 0x12, 0xb4,
-  0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4, 0xf5, 0x1a, 0x22, 0x90, 0x7f, 0xe9, 0xe0,
-  0x12, 0x16, 0x17, 0x12, 0x38, 0x00, 0x12, 0xac, 0x01, 0x13, 0x18, 0x03, 0x11, 0x96, 0x06}},
- {0x1186, 64, { 0x12, 0x2b, 0x08, 0x12, 0x25, 0x09, 0x12, 0x18, 0x0a, 0x13, 0x6e, 0x0b, 0x00, 0x00, 0x13, 0x67, 0x90,
-  0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60, 0x40, 0x24, 0x02, 0x70, 0x69, 0x74, 0x19,
-  0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x13, 0x6e, 0x90, 0x7f, 0xea,
-  0xe0, 0xff, 0x12, 0x17, 0x4b, 0x8b, 0x12, 0x8a, 0x13, 0x89, 0x14, 0xea, 0x49, 0x60, 0x11}},
- {0x11c6, 64, { 0xae, 0x02, 0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x13, 0x6e,
-  0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x13, 0x6e, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12,
-  0x17, 0x9a, 0x8b, 0x12, 0x8a, 0x13, 0x89, 0x14, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02, 0xee, 0x90,
-  0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x13, 0x6e, 0x90, 0x7f}},
- {0x1206, 64, { 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x13, 0x6e, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x13,
-  0x6e, 0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x13, 0x6e, 0x12, 0x14,
-  0xbb, 0x02, 0x13, 0x6e, 0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x13,
-  0x6e, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70}},
- {0x1246, 64, { 0x5b, 0xa2, 0x26, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x2b, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00,
-  0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x13, 0x6e, 0xe4, 0x90, 0x7f,
-  0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x13, 0x6e, 0x90, 0x7f, 0xec,
-  0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0}},
- {0x1286, 64, { 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4,
-  0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x13, 0x6e, 0x90, 0x7f, 0xb4, 0xe0, 0x44,
-  0x01, 0xf0, 0x02, 0x13, 0x6e, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60,
-  0x03, 0x02, 0x13, 0x6e, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x26, 0x02, 0x13}},
- {0x12c6, 64, { 0x6e, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x13, 0x6e, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38,
-  0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f,
-  0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec,
-  0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90}},
- {0x1306, 64, { 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80,
-  0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea,
-  0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x26, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80,
-  0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff}},
- {0x1346, 64, { 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f,
-  0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07,
-  0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22, 0x20,
-  0x28, 0x03, 0x02, 0x14, 0xba, 0xe5, 0x40, 0x60, 0x02, 0x15, 0x40, 0xe5, 0x48, 0x60, 0x4f}},
- {0x1386, 64, { 0x65, 0x44, 0x70, 0x45, 0xe5, 0x42, 0xf4, 0x60, 0x02, 0x05, 0x42, 0xe5, 0x42, 0xc3, 0x95, 0x55, 0x40,
-  0x3d, 0xc2, 0xaf, 0x30, 0x01, 0x18, 0x90, 0x7f, 0xb8, 0xe0, 0x20, 0xe1, 0x27, 0x90, 0x7f, 0xb7,
-  0xe5, 0x48, 0xf0, 0xc2, 0x01, 0xe4, 0xf5, 0x48, 0xf5, 0x42, 0xf5, 0x44, 0x80, 0x16, 0x90, 0x7f,
-  0xb6, 0xe0, 0x20, 0xe1, 0x0f, 0x90, 0x7f, 0xb9, 0xe5, 0x48, 0xf0, 0xd2, 0x01, 0xe4, 0xf5}},
- {0x13c6, 64, { 0x48, 0xf5, 0x42, 0xf5, 0x44, 0xd2, 0xaf, 0x80, 0x06, 0x85, 0x48, 0x44, 0xe4, 0xf5, 0x42, 0xe5, 0x2e,
-  0x60, 0x2d, 0x20, 0x19, 0x07, 0x90, 0x7f, 0x9b, 0xe0, 0x30, 0xe0, 0x0e, 0xe5, 0x2f, 0x60, 0x05,
-  0xe4, 0xf5, 0x2f, 0xd2, 0x0c, 0xe4, 0xf5, 0x3e, 0x80, 0x13, 0xe5, 0x3e, 0xd3, 0x95, 0x56, 0x50,
-  0x0c, 0xe5, 0x3e, 0xb5, 0x56, 0x05, 0x75, 0x2f, 0x01, 0xd2, 0x0c, 0x05, 0x3e, 0xc2, 0x19}},
- {0x1406, 64, { 0xe5, 0x41, 0x60, 0x02, 0x15, 0x41, 0xe5, 0x49, 0x60, 0x4f, 0x65, 0x45, 0x70, 0x45, 0xe5, 0x43, 0xf4,
-  0x60, 0x02, 0x05, 0x43, 0xe5, 0x43, 0xc3, 0x95, 0x6d, 0x40, 0x3d, 0xc2, 0xaf, 0x30, 0x02, 0x18,
-  0x90, 0x7f, 0xbc, 0xe0, 0x20, 0xe1, 0x27, 0x90, 0x7f, 0xbb, 0xe5, 0x49, 0xf0, 0xc2, 0x02, 0xe4,
-  0xf5, 0x49, 0xf5, 0x43, 0xf5, 0x45, 0x80, 0x16, 0x90, 0x7f, 0xba, 0xe0, 0x20, 0xe1, 0x0f}},
- {0x1446, 64, { 0x90, 0x7f, 0xbd, 0xe5, 0x49, 0xf0, 0xd2, 0x02, 0xe4, 0xf5, 0x49, 0xf5, 0x43, 0xf5, 0x45, 0xd2, 0xaf,
-  0x80, 0x06, 0x85, 0x49, 0x45, 0xe4, 0xf5, 0x43, 0xe5, 0x3a, 0x60, 0x2d, 0x20, 0x1a, 0x07, 0x90,
-  0x7f, 0x9a, 0xe0, 0x30, 0xe2, 0x0e, 0xe5, 0x3b, 0x60, 0x05, 0xe4, 0xf5, 0x3b, 0xd2, 0x0e, 0xe4,
-  0xf5, 0x3f, 0x80, 0x13, 0xe5, 0x3f, 0xd3, 0x95, 0x6e, 0x50, 0x0c, 0xe5, 0x3f, 0xb5, 0x6e}},
- {0x1486, 64, { 0x05, 0x75, 0x3b, 0x01, 0xd2, 0x0e, 0x05, 0x3f, 0xc2, 0x1a, 0x90, 0x7f, 0xd2, 0xe0, 0x20, 0xe1, 0x23,
-  0x90, 0x7b, 0x40, 0xe0, 0x60, 0x09, 0xe0, 0xf5, 0x1c, 0x90, 0x7b, 0x42, 0xe0, 0xf5, 0x1d, 0x90,
-  0x7b, 0x41, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7, 0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0xe4, 0x90,
-  0x7f, 0xd3, 0xf0, 0x22, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0}},
- {0x14c6, 64, { 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x10, 0xf0, 0x90, 0x7f, 0x94, 0x74, 0x0d, 0xf0, 0x90, 0x7f, 0x9d, 0x74,
-  0x9a, 0xf0, 0x90, 0x7f, 0x97, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0x23, 0xf0, 0x90,
-  0x7f, 0x9e, 0x74, 0x84, 0xf0, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0x90, 0x7f,
-  0xcf, 0xf0, 0x75, 0x98, 0x40, 0x43, 0xa8, 0x10, 0xc2, 0x1b, 0xc2, 0x05, 0xc2, 0x21, 0xc2}},
- {0x1506, 64, { 0x0b, 0xc2, 0x13, 0xf5, 0x7c, 0xf5, 0x4a, 0xc2, 0x11, 0xc2, 0x15, 0xf5, 0x42, 0xc2, 0x19, 0xf5, 0x44,
-  0xf5, 0x48, 0xc2, 0x23, 0xc2, 0x1c, 0xf5, 0x2d, 0xf5, 0x2f, 0xc2, 0x07, 0xc2, 0x00, 0xc2, 0x1f,
-  0xf5, 0x3e, 0xc2, 0x09, 0xd2, 0x01, 0xd2, 0x03, 0xd2, 0x0c, 0xf5, 0x26, 0x90, 0x7f, 0xcb, 0xf0,
-  0x90, 0x7f, 0xcd, 0xf0, 0x90, 0x7f, 0xd1, 0xf0, 0x75, 0xc0, 0x40, 0x43, 0xa8, 0x40, 0xc2}},
- {0x1546, 64, { 0x1d, 0xc2, 0x06, 0xc2, 0x22, 0xc2, 0x0d, 0xc2, 0x14, 0xf5, 0x7d, 0xf5, 0x4b, 0xc2, 0x12, 0xc2, 0x16,
-  0xf5, 0x43, 0xc2, 0x1a, 0xf5, 0x45, 0xf5, 0x49, 0xc2, 0x24, 0xc2, 0x1e, 0xf5, 0x39, 0xf5, 0x3b,
-  0xc2, 0x08, 0xc2, 0x00, 0xc2, 0x20, 0xf5, 0x3f, 0xc2, 0x0a, 0xd2, 0x02, 0xd2, 0x04, 0xd2, 0x0e,
+  0x74, 0x35, 0xf0, 0xd2, 0x03, 0xd2, 0x01, 0xd2, 0x09, 0xe4, 0x90, 0x7f, 0xcf, 0xf0, 0xa2, 0x13,
+  0xe4, 0x33, 0xff, 0x65, 0x2b, 0x60, 0x04, 0x8f, 0x2b, 0xd2, 0x0c, 0xa2, 0x0b, 0xe4, 0x33, 0xff,
+  0x65, 0x2c, 0x60, 0x04, 0x8f, 0x2c, 0xd2, 0x0c, 0x90, 0x7f, 0x9b, 0xe0, 0x54, 0x08, 0x65}},
+ {0x0bc6, 64, { 0x27, 0x60, 0x07, 0xe0, 0x54, 0x08, 0xf5, 0x27, 0xd2, 0x0c, 0x90, 0x7f, 0x9b, 0xe0, 0x54, 0x40, 0xb5,
+  0x29, 0x09, 0xe0, 0x54, 0x40, 0x64, 0x40, 0xf5, 0x29, 0xd2, 0x0c, 0x30, 0x07, 0x35, 0xc2, 0xaf,
+  0x30, 0x01, 0x18, 0x90, 0x7f, 0xb8, 0xe0, 0x20, 0xe1, 0x27, 0xe5, 0x48, 0x60, 0x09, 0x90, 0x7f,
+  0xb7, 0xf0, 0xe4, 0xf5, 0x48, 0xc2, 0x01, 0xc2, 0x07, 0x80, 0x16, 0x90, 0x7f, 0xb6, 0xe0}},
+ {0x0c06, 64, { 0x20, 0xe1, 0x0f, 0xe5, 0x48, 0x60, 0x09, 0x90, 0x7f, 0xb9, 0xf0, 0xe4, 0xf5, 0x48, 0xd2, 0x01, 0xc2,
+  0x07, 0xd2, 0xaf, 0x20, 0x05, 0x37, 0x30, 0x03, 0x1b, 0x90, 0x7f, 0xc6, 0xe0, 0x20, 0xe1, 0x2d,
+  0x90, 0x7e, 0x40, 0xe0, 0x13, 0x92, 0x15, 0x75, 0x4a, 0x01, 0x90, 0x7f, 0xc7, 0xe0, 0xf5, 0x7c,
+  0xd2, 0x05, 0x80, 0x19, 0x90, 0x7f, 0xc8, 0xe0, 0x20, 0xe1, 0x12, 0x90, 0x7d, 0xc0, 0xe0}},
+ {0x0c46, 64, { 0x13, 0x92, 0x15, 0x75, 0x4a, 0x01, 0x90, 0x7f, 0xc9, 0xe0, 0xf5, 0x7c, 0xd2, 0x05, 0x20, 0x21, 0x33,
+  0x20, 0x00, 0x06, 0xe5, 0x4a, 0x65, 0x7c, 0x70, 0x2a, 0x30, 0x05, 0x1a, 0x30, 0x03, 0x09, 0xe4,
+  0x90, 0x7f, 0xc7, 0xf0, 0xc2, 0x03, 0x80, 0x07, 0xe4, 0x90, 0x7f, 0xc9, 0xf0, 0xd2, 0x03, 0xc2,
+  0x05, 0xe4, 0xf5, 0x7c, 0xf5, 0x4a, 0x30, 0x15, 0x0a, 0xc2, 0x15, 0xc2, 0x00, 0x90, 0x7f}},
+ {0x0c86, 64, { 0xbf, 0x74, 0x01, 0xf0, 0x30, 0x21, 0x03, 0x02, 0x0d, 0x94, 0x20, 0x05, 0x03, 0x02, 0x0d, 0x94, 0x30,
+  0x1c, 0x0a, 0x90, 0x7f, 0x9b, 0xe0, 0x20, 0xe3, 0x03, 0x02, 0x0d, 0x94, 0x30, 0x0b, 0x03, 0x02,
+  0x0d, 0x94, 0x30, 0x13, 0x03, 0x02, 0x0d, 0x94, 0x30, 0x03, 0x62, 0x30, 0x1b, 0x12, 0xaf, 0x4a,
+  0x05, 0x4a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92}},
+ {0x0cc6, 64, { 0x2d, 0xaf, 0x4a, 0x05, 0x4a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5,
+  0x13, 0xe5, 0x4a, 0xc3, 0x95, 0x7c, 0x50, 0x2a, 0x30, 0x1b, 0x12, 0xaf, 0x4a, 0x05, 0x4a, 0x74,
+  0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x17, 0xaf, 0x4a, 0x05,
+  0x4a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5, 0x46, 0xd2}},
+ {0x0d06, 64, { 0x11, 0x80, 0x6b, 0xc2, 0x11, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0xc2, 0x03, 0x80, 0x60, 0x30, 0x1b, 0x12,
+  0xaf, 0x4a, 0x05, 0x4a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13,
+  0x92, 0x2d, 0xaf, 0x4a, 0x05, 0x4a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83,
+  0xe0, 0xf5, 0x13, 0xe5, 0x4a, 0xc3, 0x95, 0x7c, 0x50, 0x2a, 0x30, 0x1b, 0x12, 0xaf, 0x4a}},
+ {0x0d46, 64, { 0x05, 0x4a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x17, 0xaf,
+  0x4a, 0x05, 0x4a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x46,
+  0xd2, 0x11, 0x80, 0x09, 0xc2, 0x11, 0xe4, 0x90, 0x7f, 0xc9, 0xf0, 0xd2, 0x03, 0x30, 0x1b, 0x04,
+  0xa2, 0x2d, 0x92, 0x9b, 0xd2, 0x21, 0xc2, 0xaf, 0x85, 0x13, 0x99, 0x20, 0x11, 0x0d, 0x30}},
+ {0x0d86, 64, { 0x15, 0x0a, 0xc2, 0x15, 0xc2, 0x00, 0x90, 0x7f, 0xbf, 0x74, 0x01, 0xf0, 0xd2, 0xaf, 0x90, 0x7f, 0xd0,
+  0xe0, 0x30, 0xe1, 0x03, 0x02, 0x0e, 0xb5, 0xe4, 0xf5, 0x12, 0x74, 0xc0, 0x25, 0x12, 0xf5, 0x82,
+  0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x12, 0x7c, 0x00, 0x7b, 0x00, 0x24, 0x64, 0xf9,
+  0xec, 0x34, 0x00, 0xfa, 0xef, 0x12, 0x15, 0xcd, 0x05, 0x12, 0xe5, 0x12, 0xb4, 0x18, 0xdb}},
+ {0x0dc6, 64, { 0xe5, 0x64, 0x60, 0x0b, 0x75, 0x89, 0x60, 0x75, 0x88, 0x40, 0xd2, 0xdf, 0x85, 0x65, 0x8d, 0xe5, 0x67,
+  0x13, 0x92, 0x1d, 0x92, 0xc7, 0xe5, 0x68, 0x13, 0x92, 0x1e, 0xe5, 0x69, 0x13, 0x92, 0x24, 0xe5,
+  0x6a, 0x60, 0x09, 0x90, 0x7f, 0x97, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0x97, 0xe0,
+  0x44, 0x10, 0xf0, 0xe5, 0x6b, 0x60, 0x09, 0x90, 0x7f, 0x97, 0xe0, 0x54, 0x7f, 0xf0, 0x80}},
+ {0x0e06, 64, { 0x07, 0x90, 0x7f, 0x97, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x71, 0x60, 0x0b, 0xc2, 0x14, 0xc2, 0x0d, 0x90,
+  0x7f, 0x94, 0xe0, 0x44, 0x08, 0xf0, 0xe5, 0x72, 0x60, 0x0b, 0xd2, 0x0d, 0xd2, 0x0e, 0x90, 0x7f,
+  0x94, 0xe0, 0x44, 0x08, 0xf0, 0xe5, 0x73, 0x60, 0x0d, 0xc2, 0xaf, 0xc2, 0x12, 0xd2, 0x00, 0xe4,
+  0xf5, 0x7d, 0xf5, 0x4b, 0xd2, 0xaf, 0xe5, 0x74, 0x60, 0x05, 0x30, 0x24, 0x02, 0xd2, 0x0d}},
+ {0x0e46, 64, { 0xe5, 0x75, 0x60, 0x15, 0x90, 0x7f, 0x94, 0xe0, 0x54, 0xf7, 0xf0, 0x90, 0x7f, 0x9d, 0xe0, 0x44, 0x08,
+  0xf0, 0x90, 0x7f, 0x97, 0xe0, 0x54, 0xf7, 0xf0, 0xe5, 0x76, 0x60, 0x0a, 0xd2, 0xc4, 0xc2, 0xc0,
+  0x75, 0x3a, 0x01, 0x75, 0x41, 0x28, 0xe5, 0x77, 0x60, 0x07, 0xc2, 0xc4, 0xe4, 0xf5, 0x49, 0xf5,
+  0x3a, 0xe5, 0x78, 0x60, 0x03, 0xe4, 0xf5, 0x49, 0xe5, 0x79, 0x60, 0x02, 0xd2, 0x08, 0xe5}},
+ {0x0e86, 64, { 0x7a, 0x60, 0x08, 0xe5, 0x76, 0x70, 0x02, 0xf5, 0x41, 0xd2, 0x0e, 0xe5, 0x7b, 0x60, 0x19, 0x90, 0x7f,
+  0xd7, 0x74, 0x13, 0xf0, 0x74, 0x33, 0xf0, 0x74, 0x14, 0xf0, 0x74, 0x34, 0xf0, 0x74, 0x16, 0xf0,
+  0x74, 0x36, 0xf0, 0xd2, 0x04, 0xd2, 0x02, 0xd2, 0x0a, 0xe4, 0x90, 0x7f, 0xd1, 0xf0, 0xa2, 0x14,
+  0xe4, 0x33, 0xff, 0x65, 0x37, 0x60, 0x04, 0x8f, 0x37, 0xd2, 0x0e, 0xa2, 0x0d, 0xe4, 0x33}},
+ {0x0ec6, 64, { 0xff, 0x65, 0x38, 0x60, 0x04, 0x8f, 0x38, 0xd2, 0x0e, 0x90, 0x7f, 0x9a, 0xe0, 0x54, 0x20, 0x65, 0x33,
+  0x60, 0x07, 0xe0, 0x54, 0x20, 0xf5, 0x33, 0xd2, 0x0e, 0x90, 0x7f, 0x9a, 0xe0, 0x54, 0x40, 0xb5,
+  0x35, 0x09, 0xe0, 0x54, 0x40, 0x64, 0x40, 0xf5, 0x35, 0xd2, 0x0e, 0x30, 0x08, 0x35, 0xc2, 0xaf,
+  0x30, 0x02, 0x18, 0x90, 0x7f, 0xbc, 0xe0, 0x20, 0xe1, 0x27, 0xe5, 0x49, 0x60, 0x09, 0x90}},
+ {0x0f06, 64, { 0x7f, 0xbb, 0xf0, 0xe4, 0xf5, 0x49, 0xc2, 0x02, 0xc2, 0x08, 0x80, 0x16, 0x90, 0x7f, 0xba, 0xe0, 0x20,
+  0xe1, 0x0f, 0xe5, 0x49, 0x60, 0x09, 0x90, 0x7f, 0xbd, 0xf0, 0xe4, 0xf5, 0x49, 0xd2, 0x02, 0xc2,
+  0x08, 0xd2, 0xaf, 0x20, 0x06, 0x37, 0x30, 0x04, 0x1b, 0x90, 0x7f, 0xca, 0xe0, 0x20, 0xe1, 0x2d,
+  0x90, 0x7d, 0x40, 0xe0, 0x13, 0x92, 0x16, 0x75, 0x4b, 0x01, 0x90, 0x7f, 0xcb, 0xe0, 0xf5}},
+ {0x0f46, 64, { 0x7d, 0xd2, 0x06, 0x80, 0x19, 0x90, 0x7f, 0xcc, 0xe0, 0x20, 0xe1, 0x12, 0x90, 0x7c, 0xc0, 0xe0, 0x13,
+  0x92, 0x16, 0x75, 0x4b, 0x01, 0x90, 0x7f, 0xcd, 0xe0, 0xf5, 0x7d, 0xd2, 0x06, 0x20, 0x22, 0x33,
+  0x20, 0x00, 0x06, 0xe5, 0x4b, 0x65, 0x7d, 0x70, 0x2a, 0x30, 0x06, 0x1a, 0x30, 0x04, 0x09, 0xe4,
+  0x90, 0x7f, 0xcb, 0xf0, 0xc2, 0x04, 0x80, 0x07, 0xe4, 0x90, 0x7f, 0xcd, 0xf0, 0xd2, 0x04}},
+ {0x0f86, 64, { 0xc2, 0x06, 0xe4, 0xf5, 0x7d, 0xf5, 0x4b, 0x30, 0x16, 0x0a, 0xc2, 0x16, 0xc2, 0x00, 0x90, 0x7f, 0xc1,
+  0x74, 0x01, 0xf0, 0x30, 0x22, 0x03, 0x02, 0x10, 0xa4, 0x20, 0x06, 0x03, 0x02, 0x10, 0xa4, 0x30,
+  0x1e, 0x0a, 0x90, 0x7f, 0x9a, 0xe0, 0x20, 0xe5, 0x03, 0x02, 0x10, 0xa4, 0x30, 0x0d, 0x03, 0x02,
+  0x10, 0xa4, 0x30, 0x14, 0x03, 0x02, 0x10, 0xa4, 0x30, 0x04, 0x62, 0x30, 0x1d, 0x12, 0xaf}},
+ {0x0fc6, 64, { 0x4b, 0x05, 0x4b, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x2d,
+  0xaf, 0x4b, 0x05, 0x4b, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5,
+  0x13, 0xe5, 0x4b, 0xc3, 0x95, 0x7d, 0x50, 0x2a, 0x30, 0x1d, 0x12, 0xaf, 0x4b, 0x05, 0x4b, 0x74,
+  0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x18, 0xaf, 0x4b}},
+ {0x1006, 64, { 0x05, 0x4b, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x47, 0xd2, 0x12,
+  0x80, 0x6b, 0xc2, 0x12, 0xe4, 0x90, 0x7f, 0xcb, 0xf0, 0xc2, 0x04, 0x80, 0x60, 0x30, 0x1d, 0x12,
+  0xaf, 0x4b, 0x05, 0x4b, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0x13,
+  0x92, 0x2d, 0xaf, 0x4b, 0x05, 0x4b, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5}},
+ {0x1046, 64, { 0x83, 0xe0, 0xf5, 0x13, 0xe5, 0x4b, 0xc3, 0x95, 0x7d, 0x50, 0x2a, 0x30, 0x1d, 0x12, 0xaf, 0x4b, 0x05,
+  0x4b, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x18, 0xaf,
+  0x4b, 0x05, 0x4b, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xf5, 0x47,
+  0xd2, 0x12, 0x80, 0x09, 0xc2, 0x12, 0xe4, 0x90, 0x7f, 0xcd, 0xf0, 0xd2, 0x04, 0x30, 0x1d}},
+ {0x1086, 64, { 0x04, 0xa2, 0x2d, 0x92, 0xc3, 0xd2, 0x22, 0xc2, 0xaf, 0x85, 0x13, 0xc1, 0x20, 0x12, 0x0d, 0x30, 0x16,
+  0x0a, 0xc2, 0x16, 0xc2, 0x00, 0x90, 0x7f, 0xc1, 0x74, 0x01, 0xf0, 0xd2, 0xaf, 0x90, 0x7f, 0xc2,
+  0xe0, 0x30, 0xe1, 0x03, 0x02, 0x11, 0x7a, 0xe5, 0x1a, 0x70, 0x46, 0x30, 0x0c, 0x3f, 0xe5, 0x40,
+  0x70, 0x3b, 0xa2, 0x09, 0x33, 0xf5, 0x31, 0xc2, 0x09, 0xc2, 0x0c, 0xe4, 0xf5, 0x12, 0x7e}},
+ {0x10c6, 64, { 0x00, 0x7b, 0x00, 0x74, 0x26, 0x25, 0x12, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x15, 0x87, 0xff, 0x74,
+  0x80, 0x25, 0x12, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x12, 0xe5, 0x12,
+  0xb4, 0x0c, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x0c, 0xf0, 0x75, 0x40, 0x10, 0x22, 0x75, 0x1a, 0x01,
+  0x22, 0xe5, 0x1a, 0x64, 0x01, 0x70, 0x45, 0x30, 0x0e, 0x3e, 0xe5, 0x41, 0x70, 0x3a, 0xa2}},
+ {0x1106, 64, { 0x0a, 0x33, 0xf5, 0x3d, 0xc2, 0x0a, 0xc2, 0x0e, 0xe4, 0xf5, 0x12, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x32,
+  0x25, 0x12, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x15, 0x87, 0xff, 0x74, 0x80, 0x25, 0x12, 0xf5,
+  0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x12, 0xe5, 0x12, 0xb4, 0x0c, 0xdb, 0x90,
+  0x7f, 0xc3, 0x74, 0x0c, 0xf0, 0x75, 0x41, 0x10, 0x75, 0x1a, 0x02, 0x22, 0xe5, 0x1c, 0x60}},
+ {0x1146, 64, { 0x30, 0x15, 0x1c, 0xe4, 0xf5, 0x12, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x1b, 0x25, 0x12, 0xf9, 0xee, 0x34,
+  0x00, 0xfa, 0x12, 0x15, 0x87, 0xff, 0x74, 0x80, 0x25, 0x12, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5,
+  0x83, 0xef, 0xf0, 0x05, 0x12, 0xe5, 0x12, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0,
+  0xe4, 0xf5, 0x1a, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x16, 0x17, 0x12, 0x40, 0x00, 0x12}},
+ {0x1186, 64, { 0xb4, 0x01, 0x13, 0x20, 0x03, 0x11, 0x9e, 0x06, 0x12, 0x33, 0x08, 0x12, 0x2d, 0x09, 0x12, 0x20, 0x0a,
+  0x13, 0x76, 0x0b, 0x00, 0x00, 0x13, 0x6f, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14,
+  0x60, 0x40, 0x24, 0x02, 0x70, 0x69, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f,
+  0xd5, 0xf0, 0x02, 0x13, 0x76, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x17, 0x4b, 0x8b, 0x12}},
+ {0x11c6, 64, { 0x8a, 0x13, 0x89, 0x14, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02, 0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01,
+  0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x13, 0x76, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02,
+  0x13, 0x76, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x17, 0x9a, 0x8b, 0x12, 0x8a, 0x13, 0x89, 0x14,
+  0xea, 0x49, 0x60, 0x11, 0xae, 0x02, 0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90}},
+ {0x1206, 64, { 0x7f, 0xd5, 0xf0, 0x02, 0x13, 0x76, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x13, 0x76, 0x90,
+  0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x13, 0x76, 0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90,
+  0x7f, 0xb5, 0xf0, 0x02, 0x13, 0x76, 0x12, 0x14, 0xc3, 0x02, 0x13, 0x76, 0x90, 0x7f, 0x00, 0x74,
+  0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x13, 0x76, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f}},
+ {0x1246, 64, { 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2, 0x26, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff,
+  0xa2, 0x2b, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74,
+  0x02, 0xf0, 0x02, 0x13, 0x76, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74,
+  0x02, 0xf0, 0x02, 0x13, 0x76, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54}},
+ {0x1286, 64, { 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83,
+  0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0,
+  0x02, 0x13, 0x76, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x13, 0x76, 0x90, 0x7f, 0xe8,
+  0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x13, 0x76, 0x90, 0x7f, 0xea}},
+ {0x12c6, 64, { 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x26, 0x02, 0x13, 0x76, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02,
+  0x13, 0x76, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff,
+  0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34,
+  0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13}},
+ {0x1306, 64, { 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x5f,
+  0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60,
+  0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x26, 0x80, 0x3f,
+  0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20}},
+ {0x1346, 64, { 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25,
+  0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90,
+  0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90,
+  0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22, 0x20, 0x28, 0x03, 0x02, 0x14, 0xc2, 0xe5, 0x40}},
+ {0x1386, 64, { 0x60, 0x02, 0x15, 0x40, 0xe5, 0x48, 0x60, 0x4f, 0x65, 0x44, 0x70, 0x45, 0xe5, 0x42, 0xf4, 0x60, 0x02,
+  0x05, 0x42, 0xe5, 0x42, 0xc3, 0x95, 0x55, 0x40, 0x3d, 0xc2, 0xaf, 0x30, 0x01, 0x18, 0x90, 0x7f,
+  0xb8, 0xe0, 0x20, 0xe1, 0x27, 0x90, 0x7f, 0xb7, 0xe5, 0x48, 0xf0, 0xc2, 0x01, 0xe4, 0xf5, 0x48,
+  0xf5, 0x42, 0xf5, 0x44, 0x80, 0x16, 0x90, 0x7f, 0xb6, 0xe0, 0x20, 0xe1, 0x0f, 0x90, 0x7f}},
+ {0x13c6, 64, { 0xb9, 0xe5, 0x48, 0xf0, 0xd2, 0x01, 0xe4, 0xf5, 0x48, 0xf5, 0x42, 0xf5, 0x44, 0xd2, 0xaf, 0x80, 0x06,
+  0x85, 0x48, 0x44, 0xe4, 0xf5, 0x42, 0xe5, 0x2e, 0x60, 0x2d, 0x20, 0x19, 0x07, 0x90, 0x7f, 0x9b,
+  0xe0, 0x30, 0xe0, 0x0e, 0xe5, 0x2f, 0x60, 0x05, 0xe4, 0xf5, 0x2f, 0xd2, 0x0c, 0xe4, 0xf5, 0x3e,
+  0x80, 0x13, 0xe5, 0x3e, 0xd3, 0x95, 0x56, 0x50, 0x0c, 0xe5, 0x3e, 0xb5, 0x56, 0x05, 0x75}},
+ {0x1406, 64, { 0x2f, 0x01, 0xd2, 0x0c, 0x05, 0x3e, 0xc2, 0x19, 0xe5, 0x41, 0x60, 0x02, 0x15, 0x41, 0xe5, 0x49, 0x60,
+  0x4f, 0x65, 0x45, 0x70, 0x45, 0xe5, 0x43, 0xf4, 0x60, 0x02, 0x05, 0x43, 0xe5, 0x43, 0xc3, 0x95,
+  0x6d, 0x40, 0x3d, 0xc2, 0xaf, 0x30, 0x02, 0x18, 0x90, 0x7f, 0xbc, 0xe0, 0x20, 0xe1, 0x27, 0x90,
+  0x7f, 0xbb, 0xe5, 0x49, 0xf0, 0xc2, 0x02, 0xe4, 0xf5, 0x49, 0xf5, 0x43, 0xf5, 0x45, 0x80}},
+ {0x1446, 64, { 0x16, 0x90, 0x7f, 0xba, 0xe0, 0x20, 0xe1, 0x0f, 0x90, 0x7f, 0xbd, 0xe5, 0x49, 0xf0, 0xd2, 0x02, 0xe4,
+  0xf5, 0x49, 0xf5, 0x43, 0xf5, 0x45, 0xd2, 0xaf, 0x80, 0x06, 0x85, 0x49, 0x45, 0xe4, 0xf5, 0x43,
+  0xe5, 0x3a, 0x60, 0x2d, 0x20, 0x1a, 0x07, 0x90, 0x7f, 0x9a, 0xe0, 0x30, 0xe2, 0x0e, 0xe5, 0x3b,
+  0x60, 0x05, 0xe4, 0xf5, 0x3b, 0xd2, 0x0e, 0xe4, 0xf5, 0x3f, 0x80, 0x13, 0xe5, 0x3f, 0xd3}},
+ {0x1486, 64, { 0x95, 0x6e, 0x50, 0x0c, 0xe5, 0x3f, 0xb5, 0x6e, 0x05, 0x75, 0x3b, 0x01, 0xd2, 0x0e, 0x05, 0x3f, 0xc2,
+  0x1a, 0x90, 0x7f, 0xd2, 0xe0, 0x20, 0xe1, 0x23, 0x90, 0x7b, 0x40, 0xe0, 0x60, 0x09, 0xe0, 0xf5,
+  0x1c, 0x90, 0x7b, 0x42, 0xe0, 0xf5, 0x1d, 0x90, 0x7b, 0x41, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7,
+  0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0xe4, 0x90, 0x7f, 0xd3, 0xf0, 0x22, 0xe4, 0x90, 0x7f}},
+ {0x14c6, 64, { 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x10, 0xf0, 0x90, 0x7f,
+  0x94, 0x74, 0x0d, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0x9a, 0xf0, 0x90, 0x7f, 0x97, 0xe0, 0x54, 0xfd,
+  0xf0, 0x90, 0x7f, 0x95, 0x74, 0x23, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x84, 0xf0, 0xe4, 0x90, 0x7f,
+  0xc7, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0x90, 0x7f, 0xcf, 0xf0, 0x75, 0x98, 0x40, 0x43, 0xa8}},
+ {0x1506, 64, { 0x10, 0xc2, 0x1b, 0xc2, 0x05, 0xc2, 0x21, 0xc2, 0x0b, 0xc2, 0x13, 0xf5, 0x7c, 0xf5, 0x4a, 0xc2, 0x11,
+  0xc2, 0x15, 0xf5, 0x42, 0xc2, 0x19, 0xf5, 0x44, 0xf5, 0x48, 0xc2, 0x23, 0xc2, 0x1c, 0xf5, 0x2d,
+  0xf5, 0x2f, 0xc2, 0x07, 0xc2, 0x00, 0xc2, 0x1f, 0xf5, 0x3e, 0xc2, 0x09, 0xd2, 0x0c, 0xf5, 0x26,
+  0x90, 0x7f, 0xcb, 0xf0, 0x90, 0x7f, 0xcd, 0xf0, 0x90, 0x7f, 0xd1, 0xf0, 0x75, 0xc0, 0x40}},
+ {0x1546, 64, { 0x43, 0xa8, 0x40, 0xc2, 0x1d, 0xc2, 0x06, 0xc2, 0x22, 0xc2, 0x0d, 0xc2, 0x14, 0xf5, 0x7d, 0xf5, 0x4b,
+  0xc2, 0x12, 0xc2, 0x16, 0xf5, 0x43, 0xc2, 0x1a, 0xf5, 0x45, 0xf5, 0x49, 0xc2, 0x24, 0xc2, 0x1e,
+  0xf5, 0x39, 0xf5, 0x3b, 0xc2, 0x08, 0xc2, 0x00, 0xc2, 0x20, 0xf5, 0x3f, 0xc2, 0x0a, 0xd2, 0x0e,
   0x75, 0x32, 0x01, 0x90, 0x7f, 0xdf, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0xd2, 0x28}},
  {0x1586, 64, { 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02,
   0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5,
@@ -384,7 +389,7 @@
   0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8,
   0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46,
   0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x18}},
- {0x1686, 64, { 0xcc, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe,
+ {0x1686, 64, { 0xc5, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe,
   0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4,
   0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5,
   0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde}},
@@ -393,9 +398,9 @@
   0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90,
   0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaf, 0xe0, 0x44}},
  {0x1706, 64, { 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0xbc, 0xd2, 0xbe, 0xd2, 0x2d,
-  0x12, 0x18, 0x86, 0xc2, 0x27, 0xc2, 0x25, 0xc2, 0x28, 0x30, 0x28, 0x03, 0x12, 0x0a, 0x83, 0x90,
-  0x7f, 0xd8, 0xe0, 0x65, 0x10, 0x60, 0x08, 0xe0, 0xf5, 0x10, 0x12, 0x13, 0x76, 0x80, 0xea, 0x30,
-  0x27, 0x07, 0xc2, 0x27, 0x12, 0x11, 0x73, 0x80, 0xe0, 0x30, 0x2c, 0xdd, 0xc2, 0x2c, 0x12}},
+  0x12, 0x18, 0x7f, 0xc2, 0x27, 0xc2, 0x25, 0xc2, 0x28, 0x30, 0x28, 0x03, 0x12, 0x0a, 0x83, 0x90,
+  0x7f, 0xd8, 0xe0, 0x65, 0x10, 0x60, 0x08, 0xe0, 0xf5, 0x10, 0x12, 0x13, 0x7e, 0x80, 0xea, 0x30,
+  0x27, 0x07, 0xc2, 0x27, 0x12, 0x11, 0x7b, 0x80, 0xe0, 0x30, 0x2c, 0xdd, 0xc2, 0x2c, 0x12}},
  {0x1746, 64, { 0x00, 0x26, 0x80, 0xd6, 0x22, 0xe4, 0xfe, 0x75, 0x17, 0xff, 0x75, 0x18, 0x19, 0x75, 0x19, 0x12, 0xab,
   0x17, 0xaa, 0x18, 0xa9, 0x19, 0x90, 0x00, 0x01, 0x12, 0x15, 0xa0, 0x64, 0x02, 0x70, 0x2d, 0xad,
   0x06, 0x0e, 0xed, 0xb5, 0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x15, 0xdf, 0x85, 0xf0, 0x15,
@@ -405,33 +410,33 @@
   0x86, 0xab, 0x17, 0xaa, 0x18, 0xa9, 0x19, 0x90, 0x00, 0x01, 0x12, 0x15, 0xa0, 0xb4, 0x03, 0x1d,
   0xaf, 0x16, 0x05, 0x16, 0xef, 0xb5, 0x15, 0x01, 0x22, 0x12, 0x15, 0x87, 0x7e, 0x00, 0x29}},
  {0x17c6, 64, { 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75, 0x17, 0xff, 0xf5, 0x18, 0x89, 0x19, 0x80, 0xd4, 0x7b, 0x00, 0x7a,
-  0x00, 0x79, 0x00, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86,
-  0x75, 0x86, 0x00, 0x30, 0x2a, 0x04, 0xc2, 0x2a, 0x80, 0x02, 0xd2, 0x2c, 0x53, 0x91, 0xef, 0x90,
-  0x7f, 0xab, 0x74, 0x08, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83}},
- {0x1806, 64, { 0xd0, 0xe0, 0x32, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0xf0, 0x90, 0x7f, 0x94, 0xf0, 0x90,
-  0x7f, 0x9d, 0x74, 0x02, 0xf0, 0x90, 0x7f, 0x97, 0xf0, 0xe4, 0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f,
-  0x9e, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x98, 0xf0, 0x90, 0x7f, 0x9d, 0xf0, 0x22, 0xc0, 0xe0,
-  0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90, 0x7f}},
- {0x1846, 64, { 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0,
-  0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85,
-  0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x27, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74,
-  0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32}},
- {0x1886, 64, { 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x2d, 0x04, 0xe0, 0x44, 0x02,
-  0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x00, 0x06, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0, 0xe0,
-  0x44, 0x04, 0xf0, 0x22, 0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82,
-  0x45, 0x83, 0x70, 0xf9, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01}},
- {0x18c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xc1, 0xaa, 0x01, 0x1a, 0x00, 0x03, 0x1b, 0x03, 0x00, 0x00, 0xc1,
-  0x27, 0xc1, 0x2c, 0xc1, 0x26, 0xc1, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x79, 0x00, 0x22, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0xf0, 0x90, 0x7f, 0x94,
+  0xf0, 0x90, 0x7f, 0x9d, 0x74, 0x02, 0xf0, 0x90, 0x7f, 0x97, 0xf0, 0xe4, 0x90, 0x7f, 0x95, 0xf0,
+  0x90, 0x7f, 0x9e, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x98, 0xf0, 0x90, 0x7f, 0x9d, 0xf0}},
+ {0x1806, 64, { 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90,
+  0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0,
+  0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82,
+  0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x27, 0x53, 0x91, 0xef, 0x90}},
+ {0x1846, 64, { 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0,
+  0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00,
+  0xd2, 0x2c, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0,
+  0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0}},
+ {0x1886, 64, { 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x2d, 0x04, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x00,
+  0x06, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0, 0xe0, 0x44, 0x04, 0xf0, 0x22, 0x74, 0x00, 0xf5,
+  0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9, 0x22, 0x90, 0x7f,
+  0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xc1}},
+ {0x18c6, 64, { 0xaa, 0x01, 0x1a, 0x00, 0x03, 0x1b, 0x03, 0x00, 0x00, 0xc1, 0x27, 0xc1, 0x2c, 0xc1, 0x26, 0xc1, 0x2b,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x01, 0xff, 0x00}},
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x10, 0x01, 0xff, 0x00}},
  {0x1906, 64, { 0x00, 0x40, 0xcd, 0x06, 0x0f, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x01, 0x09, 0x02, 0x74, 0x00, 0x01,
   0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e, 0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01,
   0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40,
   0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x05, 0x02, 0x40, 0x00}},
  {0x1946, 64, { 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x07, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05,
-  0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x83, 0x02,
-  0x40, 0x00, 0x00, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00,
-  0x00, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x87, 0x02, 0x40, 0x00, 0x00}},
+  0x81, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x83, 0x02,
+  0x40, 0x00, 0x01, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00,
+  0x01, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x87, 0x02, 0x40, 0x00, 0x01}},
  {0x1986, 64, { 0x04, 0x03, 0x09, 0x04, 0x48, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61,
   0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x61, 0x00, 0x20, 0x00, 0x64, 0x00, 0x69, 0x00, 0x76,
   0x00, 0x69, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66,
@@ -455,7 +460,7 @@
  {0x1ac6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x18, 0x5f, 0x00, 0x02, 0x1b}},
- {0x1b06,  9, { 0x04, 0x00, 0x02, 0x18, 0x35, 0x00, 0x02, 0x17, 0xdb}},
-{ 0xffff,	0,	{0x00} }
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x18, 0x31, 0x00, 0x02, 0x1b}},
+ {0x1b06,  9, { 0x04, 0x00, 0x02, 0x18, 0x07, 0x00, 0x02, 0x18, 0x58}},
+ {0xffff,  0, {0x00}}
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/keyspan_usa28msg.h linux-2.4.20/drivers/usb/serial/keyspan_usa28msg.h
--- linux-2.4.19/drivers/usb/serial/keyspan_usa28msg.h	2001-10-09 22:15:02.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/keyspan_usa28msg.h	2002-10-29 11:18:33.000000000 +0000
@@ -95,7 +95,7 @@
 #define	__USA28MSG__
 
 
-typedef struct keyspan_usa28_portControlMessage
+struct keyspan_usa28_portControlMessage
 {
 	/*
 		there are four types of "commands" sent in the control message:
@@ -146,9 +146,9 @@
 		returnStatus,	// return current status n times (1 or 2)
 		resetDataToggle;// reset data toggle state to DATA0
 	
-} keyspan_usa28_portControlMessage;
+};
 
-typedef struct keyspan_usa28_portStatusMessage
+struct keyspan_usa28_portStatusMessage
 {
 	u8	port,			// 0=first, 1=second, 2=global (see below)
 		cts,
@@ -164,32 +164,32 @@
 		rxBreak,		// 1=we're in break state
 		rs232invalid,	// 1=no valid signals on rs-232 inputs
 		controlResponse;// 1=a control messages has been processed
-} keyspan_usa28_portStatusMessage;
+};
 
 // bit defines in txState
 #define	TX_OFF			0x01	// requested by host txOff command
 #define	TX_XOFF			0x02	// either real, or simulated by host
 
-typedef struct keyspan_usa28_globalControlMessage
+struct keyspan_usa28_globalControlMessage
 {
 	u8	sendGlobalStatus,	// 2=request for two status responses
 		resetStatusToggle,	// 1=reset global status toggle
 		resetStatusCount;	// a cycling value
-} keyspan_usa28_globalControlMessage;
+};
 
-typedef struct keyspan_usa28_globalStatusMessage
+struct keyspan_usa28_globalStatusMessage
 {
 	u8	port,				// 3
 		sendGlobalStatus,	// from request, decremented
 		resetStatusCount;	// as in request
-} keyspan_usa28_globalStatusMessage;
+};
 
-typedef struct keyspan_usa28_globalDebugMessage
+struct keyspan_usa28_globalDebugMessage
 {
 	u8	port,				// 2
 		n,					// typically a count/status byte
 		b;					// typically a data byte
-} keyspan_usa28_globalDebugMessage;
+};
 
 // ie: the maximum length of an EZUSB endpoint buffer
 #define	MAX_DATA_LEN			64
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/keyspan_usa28x_fw.h linux-2.4.20/drivers/usb/serial/keyspan_usa28x_fw.h
--- linux-2.4.19/drivers/usb/serial/keyspan_usa28x_fw.h	2001-10-09 22:15:02.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/keyspan_usa28x_fw.h	2002-10-29 11:18:35.000000000 +0000
@@ -1,341 +1,346 @@
 /* keyspan_usa28x_fw.h
-  
-   Generated from Keyspan firmware image usa26code.h Sat Oct  6 12:08:55 EST 2001
-   This firmware is for the Keyspan USA-28X Serial Adaptor
 
-   "The firmware contained herein as keyspan_usa28x_fw.h is
-   Copyright (C) 1999-2001 Keyspan, A division of InnoSys Incorporated
-   ("Keyspan"), as an unpublished work.  This notice does not imply
-   unrestricted or public access to this firmware which is a trade secret of
-   Keyspan, and which may not be reproduced, used, sold or transferred to any
-   third party without Keyspan's prior written consent.  All Rights Reserved.
+	The firmware contained herein as keyspan_usa28x_fw.h is
 
-   This firmware may not be modified and may only be used with the Keyspan 
-   USA-28X Serial Adapter.  Distribution and/or Modification of the
-   keyspan.c driver which includes this firmware, in whole or in part,
-   requires the inclusion of this statement."
+		Copyright (C) 1999-2001
+		Keyspan, A division of InnoSys Incorporated ("Keyspan")
+		
+	as an unpublished work. This notice does not imply unrestricted or
+	public access to the source code from which this firmware image is
+	derived.  Except as noted below this firmware image may not be 
+	reproduced, used, sold or transferred to any third party without 
+	Keyspan's prior written consent.  All Rights Reserved.
+
+	Permission is hereby granted for the distribution of this firmware 
+	image as part of a Linux or other Open Source operating system kernel 
+	in text or binary form as required. 
+
+	This firmware may not be modified and may only be used with  
+	Keyspan hardware.  Distribution and/or Modification of the 
+	keyspan.c driver which includes this firmware, in whole or in 
+	part, requires the inclusion of this statement."
 
 */
 
 static const struct ezusb_hex_record keyspan_usa28x_firmware[] = {
- {0x0033,  3, { 0x02, 0x13, 0xab}},
+ {0x0033,  3, { 0x02, 0x12, 0xf7}},
  {0x0003, 16, { 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0}},
  {0x0013, 16, { 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90}},
  {0x0023, 15, { 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x07, 0xf0, 0xe4, 0x90, 0x7f, 0x98, 0xf0, 0x22}},
- {0x0046, 16, { 0x30, 0x09, 0x18, 0x12, 0x13, 0x33, 0xef, 0xc3, 0x95, 0x3c, 0x40, 0x03, 0x02, 0x00, 0xd8, 0x90}},
+ {0x0046, 16, { 0x30, 0x09, 0x18, 0x12, 0x13, 0x1b, 0xef, 0xc3, 0x95, 0x3c, 0x40, 0x03, 0x02, 0x00, 0xd8, 0x90}},
  {0x0056, 16, { 0x7f, 0xbf, 0x74, 0x01, 0xf0, 0xc2, 0x09, 0xc2, 0x00, 0x80, 0x77, 0x30, 0x03, 0x3b, 0x90, 0x7f}},
- {0x0066, 16, { 0xc6, 0xe0, 0x20, 0xe1, 0x6d, 0x12, 0x13, 0x33, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x64, 0x90, 0x7e}},
+ {0x0066, 16, { 0xc6, 0xe0, 0x20, 0xe1, 0x6d, 0x12, 0x13, 0x1b, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x64, 0x90, 0x7e}},
  {0x0076, 16, { 0x40, 0xe0, 0x13, 0x92, 0x09, 0x90, 0x7f, 0xc7, 0xe0, 0x14, 0xf5, 0x19, 0x20, 0x00, 0x11, 0x60}},
- {0x0086, 16, { 0x0f, 0xf5, 0x08, 0x7e, 0x7e, 0x7f, 0x41, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x41, 0x12, 0x0c, 0xca}},
+ {0x0086, 16, { 0x0f, 0xf5, 0x08, 0x7e, 0x7e, 0x7f, 0x41, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x41, 0x12, 0x0c, 0xba}},
  {0x0096, 16, { 0xc2, 0x03, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0x80, 0x39, 0x90, 0x7f, 0xc8, 0xe0, 0x20, 0xe1, 0x32}},
- {0x00a6, 16, { 0x12, 0x13, 0x33, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x29, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x09}},
+ {0x00a6, 16, { 0x12, 0x13, 0x1b, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x29, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x09}},
  {0x00b6, 16, { 0x90, 0x7f, 0xc9, 0xe0, 0x14, 0xf5, 0x19, 0x20, 0x00, 0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7d}},
- {0x00c6, 16, { 0x7f, 0xc1, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0xc1, 0x12, 0x0c, 0xca, 0xd2, 0x03, 0xe4, 0x90, 0x7f}},
- {0x00d6, 16, { 0xc9, 0xf0, 0x90, 0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x01, 0x66, 0x53, 0x36, 0x80, 0x12}},
- {0x00e6, 16, { 0x13, 0x3f, 0xef, 0x42, 0x36, 0x12, 0x11, 0xed, 0x8f, 0x19, 0xef, 0xc3, 0x95, 0x3a, 0x50, 0x0f}},
- {0x00f6, 16, { 0x12, 0x13, 0x1b, 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x36, 0x20, 0xe7, 0x03, 0x30, 0x0b, 0x61, 0xc2}},
+ {0x00c6, 16, { 0x7f, 0xc1, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0xc1, 0x12, 0x0c, 0xba, 0xd2, 0x03, 0xe4, 0x90, 0x7f}},
+ {0x00d6, 16, { 0xc9, 0xf0, 0x90, 0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x01, 0x60, 0x12, 0x11, 0xd6, 0x8f}},
+ {0x00e6, 16, { 0x19, 0x12, 0x13, 0x27, 0x8f, 0x36, 0xe5, 0x19, 0xc3, 0x95, 0x3a, 0x50, 0x0f, 0x12, 0x12, 0xeb}},
+ {0x00f6, 16, { 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x36, 0x20, 0xe7, 0x03, 0x30, 0x0b, 0x5e, 0xc2, 0x0b, 0xe5, 0x19}},
  {0x0036, 12, { 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22}},
  {0x0043,  3, { 0x02, 0x13, 0x00}},
- {0x0000,  3, { 0x02, 0x0e, 0x10}},
- {0x0106, 64, { 0x0b, 0xe5, 0x19, 0x70, 0x04, 0xf5, 0x36, 0x80, 0x57, 0x12, 0x13, 0x3f, 0xef, 0x42, 0x36, 0xe5, 0x36,
-  0x30, 0xe7, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08,
-  0x7e, 0x7e, 0x7f, 0x80, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x80, 0xaf, 0x36, 0x12, 0x0f, 0x5b, 0xe5,
-  0x19, 0x25, 0xe0, 0x90, 0x7f, 0xb7, 0xf0, 0x80, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40}},
- {0x0146, 64, { 0x03, 0x75, 0x19, 0x3f, 0x85, 0x19, 0x08, 0xe4, 0x90, 0x7e, 0x80, 0xf0, 0x7e, 0x7e, 0x7f, 0x81, 0x75,
-  0x0c, 0x7e, 0x75, 0x0d, 0x81, 0x12, 0x0c, 0xef, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xb7, 0xf0, 0x90,
-  0x7f, 0xce, 0xe0, 0x30, 0xe1, 0x06, 0x20, 0x05, 0x03, 0x02, 0x03, 0xc5, 0xc2, 0x05, 0xe4, 0xf5,
-  0x18, 0x74, 0x40, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xff, 0xe5}},
- {0x0186, 64, { 0x18, 0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e, 0x79, 0x00, 0x24, 0x00, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef,
-  0x12, 0x0e, 0xe2, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x00, 0xe0, 0x60, 0x68,
-  0x90, 0x7e, 0x03, 0xe0, 0x60, 0x24, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x11, 0xc8, 0x7f, 0x03, 0x7d,
-  0xcd, 0x12, 0x11, 0xc8, 0x43, 0x46, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0}},
- {0x01c6, 64, { 0x00, 0xe5, 0x46, 0xf0, 0xe4, 0x90, 0x7e, 0x13, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x01, 0xe0, 0xff, 0x12,
-  0x10, 0x4c, 0x90, 0x7e, 0x02, 0xe0, 0xff, 0x12, 0x10, 0x72, 0x7f, 0x01, 0x90, 0x7e, 0x11, 0xe0,
-  0xfd, 0x12, 0x11, 0xc8, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x11, 0xc8, 0x43, 0x46, 0x80, 0x90, 0x7f,
-  0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12}},
- {0x0206, 64, { 0xf0, 0xe5, 0x40, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x03, 0xe0, 0x70, 0x06, 0x90, 0x7e,
-  0x13, 0xe0, 0x70, 0x08, 0xe4, 0x90, 0x7e, 0x13, 0xf0, 0x75, 0x25, 0xff, 0x90, 0x7e, 0x05, 0xe0,
-  0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f, 0xf5, 0x44, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0,
-  0x00, 0xe5, 0x44, 0xf0, 0x90, 0x7e, 0x07, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43}},
- {0x0246, 64, { 0x42, 0x80, 0x80, 0x03, 0x53, 0x42, 0x7f, 0x53, 0x42, 0xfc, 0x90, 0x7e, 0x09, 0xe0, 0x60, 0x11, 0x43,
-  0x42, 0x02, 0xa3, 0xe0, 0xff, 0x12, 0x10, 0xbe, 0x90, 0x7e, 0x0b, 0xe0, 0xff, 0x12, 0x10, 0xe4,
-  0xaf, 0x42, 0x12, 0x10, 0x98, 0x90, 0x7e, 0x03, 0xe0, 0x60, 0x08, 0x53, 0x42, 0x7f, 0xaf, 0x42,
-  0x12, 0x10, 0x98, 0x90, 0x7e, 0x0c, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46}},
- {0x0286, 64, { 0x02, 0x80, 0x03, 0x53, 0x46, 0xfd, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46,
-  0xf0, 0x90, 0x7e, 0x0e, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x01, 0x80, 0x03,
-  0x53, 0x46, 0xfe, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90,
-  0x7e, 0x12, 0xe0, 0xf5, 0x3a, 0xa3, 0xe0, 0x13, 0x92, 0x0d, 0xa3, 0xe0, 0xf5, 0x3c, 0xa3}},
- {0x02c6, 64, { 0xe0, 0x60, 0x05, 0x43, 0x46, 0x10, 0x80, 0x03, 0x53, 0x46, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0,
-  0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x16, 0xe0, 0x60, 0x32, 0x53, 0x44, 0xbf, 0x90,
-  0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98,
-  0x74, 0x11, 0xf0, 0x12, 0x13, 0x0f, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3e}},
- {0x0306, 64, { 0xfd, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xc8, 0xe4, 0xf5, 0x2a, 0xf5, 0x29, 0xd2, 0x07, 0x90, 0x7e,
-  0x17, 0xe0, 0x60, 0x0f, 0x43, 0x3e, 0x02, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xc8, 0x75, 0x29,
-  0x01, 0xd2, 0x07, 0x90, 0x7e, 0x18, 0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5,
-  0x40, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0, 0xd2, 0x00, 0x90, 0x7e, 0x19, 0xe0, 0x60, 0x11}},
- {0x0346, 64, { 0x43, 0x44, 0x40, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0,
-  0x90, 0x7e, 0x1a, 0xe0, 0x60, 0x0f, 0x53, 0x3e, 0xfe, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xc8,
-  0x75, 0x2b, 0x01, 0xd2, 0x07, 0x90, 0x7e, 0x1b, 0xe0, 0x60, 0x0f, 0x43, 0x3e, 0x01, 0xe4, 0xff,
-  0xad, 0x3e, 0x12, 0x11, 0xc8, 0xe4, 0xf5, 0x2b, 0xd2, 0x07, 0x90, 0x7e, 0x1c, 0xe0, 0x60}},
- {0x0386, 64, { 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e,
-  0x1d, 0xe0, 0x60, 0x02, 0xd2, 0x0b, 0x90, 0x7e, 0x1e, 0xe0, 0x60, 0x08, 0x75, 0x2c, 0x01, 0xe4,
-  0xf5, 0x38, 0xd2, 0x07, 0x90, 0x7e, 0x1f, 0xe0, 0x60, 0x0f, 0x90, 0x7f, 0xd7, 0x74, 0x11, 0xf0,
-  0x74, 0x31, 0xf0, 0x74, 0x15, 0xf0, 0x74, 0x35, 0xf0, 0xe4, 0x90, 0x7f, 0xcf, 0xf0, 0x30}},
- {0x03c6, 64, { 0x1a, 0x52, 0xe5, 0x38, 0x60, 0x02, 0x15, 0x38, 0x20, 0x13, 0x49, 0xe5, 0x13, 0xd3, 0x94, 0x00, 0x40,
-  0x04, 0x15, 0x13, 0x80, 0x3e, 0x75, 0x13, 0x0a, 0x30, 0x1b, 0x02, 0xd2, 0x13, 0x12, 0x13, 0x0f,
-  0xef, 0x54, 0x01, 0xf5, 0x19, 0x65, 0x2a, 0x60, 0x05, 0x85, 0x19, 0x2a, 0xd2, 0x07, 0x12, 0x13,
-  0x4b, 0xef, 0x54, 0x80, 0xf5, 0x19, 0x65, 0x26, 0x60, 0x05, 0x85, 0x19, 0x26, 0xd2, 0x07}},
- {0x0406, 64, { 0x30, 0x0d, 0x11, 0x12, 0x13, 0x4b, 0xef, 0x54, 0x10, 0xf5, 0x19, 0x65, 0x25, 0x60, 0x05, 0x85, 0x19,
-  0x25, 0xd2, 0x07, 0x20, 0x1b, 0x03, 0x02, 0x07, 0xf4, 0x30, 0x0a, 0x18, 0x12, 0x13, 0x87, 0xef,
-  0xc3, 0x95, 0x3d, 0x40, 0x03, 0x02, 0x04, 0xb2, 0x90, 0x7f, 0xc1, 0x74, 0x01, 0xf0, 0xc2, 0x0a,
-  0xc2, 0x00, 0x80, 0x77, 0x30, 0x04, 0x3b, 0x90, 0x7f, 0xca, 0xe0, 0x20, 0xe1, 0x6d, 0x12}},
- {0x0446, 64, { 0x13, 0x87, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x64, 0x90, 0x7d, 0x40, 0xe0, 0x13, 0x92, 0x0a, 0x90, 0x7f,
-  0xcb, 0xe0, 0x14, 0xf5, 0x19, 0x20, 0x00, 0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7d, 0x7f, 0x41,
-  0x75, 0x0c, 0x7d, 0x75, 0x0d, 0x41, 0x12, 0x0d, 0x14, 0xc2, 0x04, 0xe4, 0x90, 0x7f, 0xcb, 0xf0,
-  0x80, 0x39, 0x90, 0x7f, 0xcc, 0xe0, 0x20, 0xe1, 0x32, 0x12, 0x13, 0x87, 0xef, 0xc3, 0x94}},
- {0x0486, 64, { 0x40, 0x50, 0x29, 0x90, 0x7c, 0xc0, 0xe0, 0x13, 0x92, 0x0a, 0x90, 0x7f, 0xcd, 0xe0, 0x14, 0xf5, 0x19,
-  0x20, 0x00, 0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7c, 0x7f, 0xc1, 0x75, 0x0c, 0x7c, 0x75, 0x0d,
-  0xc1, 0x12, 0x0d, 0x14, 0xd2, 0x04, 0xe4, 0x90, 0x7f, 0xcd, 0xf0, 0x90, 0x7f, 0xba, 0xe0, 0x30,
-  0xe1, 0x03, 0x02, 0x05, 0x40, 0x53, 0x37, 0x80, 0x12, 0x13, 0x93, 0xef, 0x42, 0x37, 0x12}},
- {0x04c6, 64, { 0x12, 0x37, 0x8f, 0x19, 0xef, 0xc3, 0x95, 0x3b, 0x50, 0x0f, 0x12, 0x13, 0x6f, 0xef, 0x30, 0xe0, 0x08,
-  0xe5, 0x37, 0x20, 0xe7, 0x03, 0x30, 0x0c, 0x61, 0xc2, 0x0c, 0xe5, 0x19, 0x70, 0x04, 0xf5, 0x37,
-  0x80, 0x57, 0x12, 0x13, 0x93, 0xef, 0x42, 0x37, 0xe5, 0x37, 0x30, 0xe7, 0x26, 0xe5, 0x19, 0xd3,
-  0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08, 0x7e, 0x7d, 0x7f, 0x80, 0x75}},
- {0x0506, 64, { 0x0c, 0x7d, 0x75, 0x0d, 0x80, 0xaf, 0x37, 0x12, 0x0f, 0x94, 0xe5, 0x19, 0x25, 0xe0, 0x90, 0x7f, 0xbb,
-  0xf0, 0x80, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75, 0x19, 0x3f, 0x85, 0x19, 0x08,
-  0xe4, 0x90, 0x7d, 0x80, 0xf0, 0x7e, 0x7d, 0x7f, 0x81, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0x81, 0x12,
-  0x0d, 0x39, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xbb, 0xf0, 0x90, 0x7f, 0xd0, 0xe0, 0x30, 0xe1}},
- {0x0546, 64, { 0x06, 0x20, 0x06, 0x03, 0x02, 0x07, 0x9f, 0xc2, 0x06, 0xe4, 0xf5, 0x18, 0x74, 0xc0, 0x25, 0x18, 0xf5,
-  0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18, 0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e,
-  0x79, 0x20, 0x24, 0x20, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef, 0x12, 0x0e, 0xe2, 0x05, 0x18, 0xe5,
-  0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x20, 0xe0, 0x60, 0x68, 0x90, 0x7e, 0x23, 0xe0, 0x60}},
- {0x0586, 64, { 0x24, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x12, 0x12, 0x7f, 0x03, 0x7d, 0xcd, 0x12, 0x12, 0x12, 0x43, 0x47,
-  0x80, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0xe4, 0x90, 0x7e,
-  0x33, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x21, 0xe0, 0xff, 0x12, 0x11, 0x30, 0x90, 0x7e, 0x22, 0xe0,
-  0xff, 0x12, 0x11, 0x56, 0x7f, 0x01, 0x90, 0x7e, 0x31, 0xe0, 0xfd, 0x12, 0x12, 0x12, 0x7f}},
- {0x05c6, 64, { 0x03, 0x7d, 0x07, 0x12, 0x12, 0x12, 0x43, 0x47, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0,
-  0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0xe5, 0x41, 0x44, 0x06, 0x90, 0xc0,
-  0x00, 0xf0, 0x90, 0x7e, 0x23, 0xe0, 0x70, 0x06, 0x90, 0x7e, 0x33, 0xe0, 0x70, 0x08, 0xe4, 0x90,
-  0x7e, 0x33, 0xf0, 0x75, 0x2e, 0xff, 0x90, 0x7e, 0x25, 0xe0, 0x60, 0x12, 0xa3, 0xe0, 0x54}},
- {0x0606, 64, { 0x3f, 0xf5, 0x45, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x45, 0xf0, 0x90, 0x7e,
-  0x27, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x43, 0x80, 0x80, 0x03, 0x53, 0x43, 0x7f,
-  0x53, 0x43, 0xfc, 0x90, 0x7e, 0x29, 0xe0, 0x60, 0x11, 0x43, 0x43, 0x02, 0xa3, 0xe0, 0xff, 0x12,
-  0x11, 0x7c, 0x90, 0x7e, 0x2b, 0xe0, 0xff, 0x12, 0x11, 0xa2, 0xaf, 0x43, 0x12, 0x11, 0x0a}},
- {0x0646, 64, { 0x90, 0x7e, 0x23, 0xe0, 0x60, 0x08, 0x53, 0x43, 0x7f, 0xaf, 0x43, 0x12, 0x11, 0x0a, 0x90, 0x7e, 0x2c,
-  0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x02, 0x80, 0x03, 0x53, 0x47, 0xfd, 0x90,
-  0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7e, 0x2e, 0xe0, 0x60,
-  0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x01, 0x80, 0x03, 0x53, 0x47, 0xfe, 0x90, 0x7f}},
- {0x0686, 64, { 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7e, 0x32, 0xe0, 0xf5, 0x3b, 0xa3,
-  0xe0, 0x13, 0x92, 0x0e, 0xa3, 0xe0, 0xf5, 0x3d, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x10, 0x80,
-  0x03, 0x53, 0x47, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0,
-  0x90, 0x7e, 0x36, 0xe0, 0x60, 0x32, 0x53, 0x45, 0xbf, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0}},
- {0x06c6, 64, { 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x12, 0x13, 0x63,
-  0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3f, 0xfd, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12,
-  0x12, 0xe4, 0xf5, 0x33, 0xf5, 0x32, 0xd2, 0x08, 0x90, 0x7e, 0x37, 0xe0, 0x60, 0x0f, 0x43, 0x3f,
-  0x02, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x12, 0x75, 0x32, 0x01, 0xd2, 0x08, 0x90, 0x7e}},
- {0x0706, 64, { 0x38, 0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0xe5, 0x41, 0x44, 0x04, 0x90, 0xc0, 0x00,
-  0xf0, 0xd2, 0x00, 0x90, 0x7e, 0x39, 0xe0, 0x60, 0x11, 0x43, 0x45, 0x40, 0x90, 0x7f, 0x98, 0x74,
-  0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x3a, 0xe0, 0x60, 0x0f,
-  0x53, 0x3f, 0xfe, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x12, 0x75, 0x34, 0x01, 0xd2, 0x08}},
- {0x0746, 64, { 0x90, 0x7e, 0x3b, 0xe0, 0x60, 0x0f, 0x43, 0x3f, 0x01, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x12, 0xe4,
-  0xf5, 0x34, 0xd2, 0x08, 0x90, 0x7e, 0x3c, 0xe0, 0x60, 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0,
-  0xe5, 0x41, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x3d, 0xe0, 0x60, 0x02, 0xd2, 0x0c,
-  0x90, 0x7e, 0x3e, 0xe0, 0x60, 0x08, 0x75, 0x35, 0x01, 0xe4, 0xf5, 0x39, 0xd2, 0x08, 0x90}},
- {0x0786, 64, { 0x7e, 0x3f, 0xe0, 0x60, 0x0f, 0x90, 0x7f, 0xd7, 0x74, 0x13, 0xf0, 0x74, 0x33, 0xf0, 0x74, 0x16, 0xf0,
-  0x74, 0x36, 0xf0, 0xe4, 0x90, 0x7f, 0xd1, 0xf0, 0x30, 0x1a, 0x52, 0xe5, 0x39, 0x60, 0x02, 0x15,
-  0x39, 0x30, 0x13, 0x49, 0xe5, 0x13, 0xd3, 0x94, 0x00, 0x40, 0x04, 0x15, 0x13, 0x80, 0x3e, 0x75,
-  0x13, 0x0a, 0x30, 0x1b, 0x02, 0xc2, 0x13, 0x12, 0x13, 0x63, 0xef, 0x54, 0x01, 0xf5, 0x19}},
- {0x07c6, 64, { 0x65, 0x33, 0x60, 0x05, 0x85, 0x19, 0x33, 0xd2, 0x08, 0x12, 0x13, 0x9f, 0xef, 0x54, 0x80, 0xf5, 0x19,
-  0x65, 0x2f, 0x60, 0x05, 0x85, 0x19, 0x2f, 0xd2, 0x08, 0x30, 0x0e, 0x11, 0x12, 0x13, 0x9f, 0xef,
-  0x54, 0x10, 0xf5, 0x19, 0x65, 0x2e, 0x60, 0x05, 0x85, 0x19, 0x2e, 0xd2, 0x08, 0x30, 0x1a, 0x2a,
-  0x90, 0x7f, 0xd2, 0xe0, 0x20, 0xe1, 0x23, 0x90, 0x7b, 0x40, 0xe0, 0x60, 0x09, 0xe0, 0xf5}},
- {0x0806, 64, { 0x15, 0x90, 0x7b, 0x42, 0xe0, 0xf5, 0x16, 0x90, 0x7b, 0x41, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7, 0x74,
-  0x17, 0xf0, 0x74, 0x37, 0xf0, 0xe4, 0x90, 0x7f, 0xd3, 0xf0, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1,
-  0x03, 0x02, 0x09, 0x28, 0xe5, 0x0a, 0x70, 0x40, 0x30, 0x07, 0x39, 0xe5, 0x38, 0x70, 0x35, 0xc2,
-  0x07, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00}},
- {0x0846, 64, { 0xfa, 0x12, 0x0e, 0x9c, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef,
-  0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x09, 0xf0, 0x75, 0x38,
-  0x10, 0xe4, 0xf5, 0x2c, 0x75, 0x0a, 0x01, 0x22, 0xe5, 0x0a, 0x64, 0x01, 0x70, 0x40, 0x30, 0x08,
-  0x39, 0xe5, 0x39, 0x70, 0x35, 0xc2, 0x08, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x2d}},
- {0x0886, 64, { 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0x9c, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82,
-  0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb, 0x90, 0x7f,
-  0xc3, 0x74, 0x09, 0xf0, 0x75, 0x39, 0x10, 0xe4, 0xf5, 0x35, 0x75, 0x0a, 0x02, 0x22, 0xe5, 0x0a,
-  0x64, 0x02, 0x70, 0x36, 0x30, 0x14, 0x2f, 0xc2, 0x14, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00}},
- {0x08c6, 64, { 0x74, 0x0e, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0x9c, 0xff, 0x74, 0x80, 0x25, 0x18,
-  0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x05, 0xdb,
-  0x90, 0x7f, 0xc3, 0x74, 0x05, 0xf0, 0x75, 0x0a, 0x03, 0x22, 0xe5, 0x15, 0x60, 0x30, 0x15, 0x15,
-  0xe4, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x14, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00}},
- {0x0906, 64, { 0xfa, 0x12, 0x0e, 0x9c, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef,
-  0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4, 0xf5,
-  0x0a, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x0e, 0xf4, 0x0a, 0x10, 0x00, 0x0a, 0x84, 0x01, 0x0a,
-  0xf0, 0x03, 0x09, 0x4c, 0x06, 0x0a, 0x03, 0x08, 0x09, 0xfd, 0x09, 0x09, 0xe5, 0x0a, 0x09}},
- {0x0946, 64, { 0xf4, 0x0b, 0x00, 0x00, 0x0b, 0x3f, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x19, 0x14, 0x60, 0x61,
-  0x24, 0x02, 0x60, 0x03, 0x02, 0x09, 0xdb, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90,
-  0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x04, 0x7f, 0x02, 0x80, 0x02,
-  0x7f, 0x03, 0x75, 0x82, 0x82, 0x75, 0x83, 0x19, 0xef, 0xf0, 0x75, 0x82, 0x7b, 0x75, 0x83}},
- {0x0986, 64, { 0x19, 0xf0, 0x75, 0x82, 0x74, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x66, 0x75, 0x83, 0x19, 0xf0, 0x75,
-  0x82, 0x58, 0x75, 0x83, 0x19, 0xf0, 0x90, 0x7f, 0xea, 0xe0, 0x04, 0x75, 0x82, 0x17, 0x75, 0x83,
-  0x19, 0xf0, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x12, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b,
-  0x46, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0f, 0x1a, 0xea, 0x49, 0x60, 0x0d, 0xea, 0x90}},
- {0x09c6, 64, { 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01,
-  0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f,
-  0x00, 0xe5, 0x09, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xea,
-  0xe0, 0xf5, 0x09, 0x02, 0x0b, 0x46, 0x12, 0x0b, 0x4e, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0x00}},
- {0x0a06, 64, { 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60,
-  0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2, 0x10, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff,
-  0xa2, 0x16, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74,
-  0x02, 0xf0, 0x02, 0x0b, 0x46, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5}},
- {0x0a46, 64, { 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f,
-  0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83,
-  0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0,
-  0x02, 0x0b, 0x46, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f}},
- {0x0a86, 64, { 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xea, 0xe0,
-  0xb4, 0x01, 0x05, 0xc2, 0x10, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02,
-  0x0b, 0x46, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff,
-  0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4}},
- {0x0ac6, 64, { 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54,
-  0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x5f,
-  0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60,
-  0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x10, 0x80}},
- {0x0b06, 64, { 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90,
-  0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25,
-  0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90,
-  0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0}},
- {0x0b46, 64, { 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74,
-  0x30, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0xc0, 0xf0, 0x90, 0x7f, 0x9e,
-  0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x18, 0xf0, 0xe4, 0xf5, 0x8e, 0x90, 0x7f, 0xdf, 0x74,
-  0xff, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0xe4, 0xf5, 0x24, 0x75, 0x18, 0x01, 0x7b, 0x00, 0x74}},
- {0x0b86, 64, { 0x24, 0x25, 0x18, 0xf9, 0xe4, 0x34, 0x00, 0xfa, 0xe4, 0x12, 0x0e, 0xe2, 0x05, 0x18, 0xe5, 0x18, 0xb4,
-  0x09, 0xea, 0x75, 0x3a, 0x01, 0xe4, 0xf5, 0x38, 0xf5, 0x13, 0xf5, 0x36, 0xc2, 0x07, 0xc2, 0x0b,
-  0xc2, 0x05, 0xc2, 0x00, 0xc2, 0x09, 0xc2, 0x13, 0xd2, 0x03, 0xd2, 0x01, 0x90, 0x7f, 0x98, 0x74,
-  0x13, 0xf0, 0x75, 0x44, 0x03, 0x90, 0xc0, 0x00, 0x74, 0x03, 0xf0, 0x7f, 0x0c, 0xe4, 0xfd}},
- {0x0bc6, 64, { 0x12, 0x11, 0xc8, 0x7f, 0x10, 0x8f, 0x42, 0x12, 0x10, 0x98, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x7f,
-  0x01, 0x8f, 0x40, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0,
-  0x75, 0x46, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0x0f, 0xe4, 0xfd, 0x12, 0x11, 0xc8, 0xe4,
-  0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3e, 0x12, 0x11, 0xc8, 0x90, 0x7f, 0x98, 0x74, 0x11}},
- {0x0c06, 64, { 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x11, 0xc8, 0x7f, 0x01, 0x12, 0x12,
-  0x81, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x11, 0xc8, 0x20, 0x1b, 0x03, 0x02, 0x0c, 0xc7, 0x75, 0x2d,
-  0x01, 0x75, 0x18, 0x01, 0x7b, 0x00, 0x74, 0x2d, 0x25, 0x18, 0xf9, 0xe4, 0x34, 0x00, 0xfa, 0xe4,
-  0x12, 0x0e, 0xe2, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xea, 0x75, 0x3b, 0x01, 0xe4, 0xf5}},
- {0x0c46, 64, { 0x39, 0xf5, 0x13, 0xf5, 0x37, 0xc2, 0x08, 0xc2, 0x0c, 0xc2, 0x06, 0xc2, 0x00, 0xc2, 0x0a, 0xc2, 0x13,
-  0xd2, 0x04, 0xd2, 0x02, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x75, 0x45, 0x03, 0x90, 0xc0, 0x00,
-  0x74, 0x03, 0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x12, 0x12, 0x7f, 0x10, 0x8f, 0x43, 0x12, 0x11,
-  0x0a, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x7f, 0x01, 0x8f, 0x41, 0xef, 0x44, 0x06, 0x90}},
- {0x0c86, 64, { 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x75, 0x47, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80,
-  0xf0, 0x0f, 0xe4, 0xfd, 0x12, 0x12, 0x12, 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3f, 0x12,
-  0x12, 0x12, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d,
-  0x7f, 0x12, 0x12, 0x12, 0x7f, 0x01, 0x12, 0x12, 0xa2, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x12}},
- {0x0cc6, 64, { 0x12, 0xd2, 0x12, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5,
-  0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86,
+ {0x0000,  3, { 0x02, 0x0e, 0x00}},
+ {0x0106, 64, { 0x60, 0x58, 0xb4, 0x80, 0x03, 0x43, 0x36, 0x02, 0xe5, 0x36, 0x30, 0xe7, 0x26, 0xe5, 0x19, 0xd3, 0x94,
+  0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08, 0x7e, 0x7e, 0x7f, 0x80, 0x75, 0x0c, 0x7e,
+  0x75, 0x0d, 0x80, 0xaf, 0x36, 0x12, 0x0f, 0x4b, 0xe5, 0x19, 0x25, 0xe0, 0x90, 0x7f, 0xb7, 0xf0,
+  0x80, 0x27, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75, 0x19, 0x3f, 0x85, 0x19, 0x08}},
+ {0x0146, 64, { 0x90, 0x7e, 0x80, 0xe5, 0x36, 0xf0, 0x7e, 0x7e, 0x7f, 0x81, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x81, 0x12,
+  0x0c, 0xdf, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xb7, 0xf0, 0x90, 0x7f, 0xce, 0xe0, 0x30, 0xe1, 0x06,
+  0x20, 0x05, 0x03, 0x02, 0x03, 0xc1, 0xc2, 0x05, 0xe4, 0xf5, 0x18, 0x74, 0x40, 0x25, 0x18, 0xf5,
+  0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18, 0x7c, 0x00, 0x7b, 0x01, 0x7a}},
+ {0x0186, 64, { 0x7e, 0x79, 0x00, 0x24, 0x00, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef, 0x12, 0x0e, 0xd2, 0x05, 0x18, 0xe5,
+  0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x00, 0xe0, 0x60, 0x68, 0x90, 0x7e, 0x03, 0xe0, 0x60, 0x24,
+  0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x11, 0xb1, 0x7f, 0x03, 0x7d, 0xcd, 0x12, 0x11, 0xb1, 0x43, 0x46,
+  0x80, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0xe4, 0x90}},
+ {0x01c6, 64, { 0x7e, 0x13, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x01, 0xe0, 0xff, 0x12, 0x10, 0x35, 0x90, 0x7e, 0x02, 0xe0,
+  0xff, 0x12, 0x10, 0x5b, 0x7f, 0x01, 0x90, 0x7e, 0x11, 0xe0, 0xfd, 0x12, 0x11, 0xb1, 0x7f, 0x03,
+  0x7d, 0x07, 0x12, 0x11, 0xb1, 0x43, 0x46, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0,
+  0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40, 0x44, 0x06, 0x90}},
+ {0x0206, 64, { 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x03, 0xe0, 0x70, 0x06, 0x90, 0x7e, 0x13, 0xe0, 0x70, 0x08, 0xe4, 0x90,
+  0x7e, 0x13, 0xf0, 0x75, 0x25, 0xff, 0x90, 0x7e, 0x05, 0xe0, 0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f,
+  0xf5, 0x44, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x44, 0xf0, 0x90, 0x7e,
+  0x07, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x42, 0x80, 0x80, 0x03, 0x53, 0x42}},
+ {0x0246, 64, { 0x7f, 0x53, 0x42, 0xfc, 0x90, 0x7e, 0x09, 0xe0, 0x60, 0x11, 0x43, 0x42, 0x02, 0xa3, 0xe0, 0xff, 0x12,
+  0x10, 0xa7, 0x90, 0x7e, 0x0b, 0xe0, 0xff, 0x12, 0x10, 0xcd, 0xaf, 0x42, 0x12, 0x10, 0x81, 0x90,
+  0x7e, 0x03, 0xe0, 0x60, 0x08, 0x53, 0x42, 0x7f, 0xaf, 0x42, 0x12, 0x10, 0x81, 0x90, 0x7e, 0x0c,
+  0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x02, 0x80, 0x03, 0x53, 0x46, 0xfd}},
+ {0x0286, 64, { 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x0e, 0xe0, 0x60,
+  0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x01, 0x80, 0x03, 0x53, 0x46, 0xfe, 0x90, 0x7f, 0x98,
+  0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x12, 0xe0, 0xf5, 0x3a, 0xa3,
+  0xe0, 0x13, 0x92, 0x0d, 0xa3, 0xe0, 0xf5, 0x3c, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x10}},
+ {0x02c6, 64, { 0x80, 0x03, 0x53, 0x46, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0,
+  0x90, 0x7e, 0x16, 0xe0, 0x60, 0x32, 0x53, 0x44, 0xbf, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5,
+  0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x12, 0x12, 0xdf,
+  0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3e, 0xfd, 0xe4, 0xff, 0xad, 0x3e, 0x12}},
+ {0x0306, 64, { 0x11, 0xb1, 0xe4, 0xf5, 0x2a, 0xf5, 0x29, 0xd2, 0x07, 0x90, 0x7e, 0x17, 0xe0, 0x60, 0x0f, 0x43, 0x3e,
+  0x02, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xb1, 0x75, 0x29, 0x01, 0xd2, 0x07, 0x90, 0x7e, 0x18,
+  0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40, 0x44, 0x04, 0x90, 0xc0, 0x00,
+  0xf0, 0xd2, 0x00, 0x90, 0x7e, 0x19, 0xe0, 0x60, 0x11, 0x43, 0x44, 0x40, 0x90, 0x7f, 0x98}},
+ {0x0346, 64, { 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1a, 0xe0, 0x60, 0x0f,
+  0x53, 0x3e, 0xfe, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xb1, 0x75, 0x2b, 0x01, 0xd2, 0x07, 0x90,
+  0x7e, 0x1b, 0xe0, 0x60, 0x0f, 0x43, 0x3e, 0x01, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xb1, 0xe4,
+  0xf5, 0x2b, 0xd2, 0x07, 0x90, 0x7e, 0x1c, 0xe0, 0x60, 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x12}},
+ {0x0386, 64, { 0xf0, 0xe5, 0x40, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1d, 0xe0, 0x60, 0x02, 0xd2, 0x0b,
+  0x90, 0x7e, 0x1e, 0xe0, 0x60, 0x08, 0x75, 0x2c, 0x01, 0xe4, 0xf5, 0x38, 0xd2, 0x07, 0x90, 0x7e,
+  0x1f, 0xe0, 0x60, 0x11, 0x90, 0x7f, 0xd7, 0x74, 0x11, 0xf0, 0x74, 0x31, 0xf0, 0x74, 0x15, 0xf0,
+  0x74, 0x35, 0xf0, 0xd2, 0x03, 0xe4, 0x90, 0x7f, 0xcf, 0xf0, 0x30, 0x1a, 0x52, 0xe5, 0x38}},
+ {0x03c6, 64, { 0x60, 0x02, 0x15, 0x38, 0x20, 0x13, 0x49, 0xe5, 0x13, 0xd3, 0x94, 0x00, 0x40, 0x04, 0x15, 0x13, 0x80,
+  0x3e, 0x75, 0x13, 0x0a, 0x30, 0x1b, 0x02, 0xd2, 0x13, 0x12, 0x12, 0xdf, 0xef, 0x54, 0x01, 0xf5,
+  0x19, 0x65, 0x2a, 0x60, 0x05, 0x85, 0x19, 0x2a, 0xd2, 0x07, 0x12, 0x13, 0x33, 0xef, 0x54, 0x80,
+  0xf5, 0x19, 0x65, 0x26, 0x60, 0x05, 0x85, 0x19, 0x26, 0xd2, 0x07, 0x30, 0x0d, 0x11, 0x12}},
+ {0x0406, 64, { 0x13, 0x33, 0xef, 0x54, 0x10, 0xf5, 0x19, 0x65, 0x25, 0x60, 0x05, 0x85, 0x19, 0x25, 0xd2, 0x07, 0x20,
+  0x1b, 0x03, 0x02, 0x07, 0xec, 0x30, 0x0a, 0x18, 0x12, 0x13, 0x6f, 0xef, 0xc3, 0x95, 0x3d, 0x40,
+  0x03, 0x02, 0x04, 0xae, 0x90, 0x7f, 0xc1, 0x74, 0x01, 0xf0, 0xc2, 0x0a, 0xc2, 0x00, 0x80, 0x77,
+  0x30, 0x04, 0x3b, 0x90, 0x7f, 0xca, 0xe0, 0x20, 0xe1, 0x6d, 0x12, 0x13, 0x6f, 0xef, 0xc3}},
+ {0x0446, 64, { 0x94, 0x40, 0x50, 0x64, 0x90, 0x7d, 0x40, 0xe0, 0x13, 0x92, 0x0a, 0x90, 0x7f, 0xcb, 0xe0, 0x14, 0xf5,
+  0x19, 0x20, 0x00, 0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7d, 0x7f, 0x41, 0x75, 0x0c, 0x7d, 0x75,
+  0x0d, 0x41, 0x12, 0x0d, 0x04, 0xc2, 0x04, 0xe4, 0x90, 0x7f, 0xcb, 0xf0, 0x80, 0x39, 0x90, 0x7f,
+  0xcc, 0xe0, 0x20, 0xe1, 0x32, 0x12, 0x13, 0x6f, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x29, 0x90}},
+ {0x0486, 64, { 0x7c, 0xc0, 0xe0, 0x13, 0x92, 0x0a, 0x90, 0x7f, 0xcd, 0xe0, 0x14, 0xf5, 0x19, 0x20, 0x00, 0x11, 0x60,
+  0x0f, 0xf5, 0x08, 0x7e, 0x7c, 0x7f, 0xc1, 0x75, 0x0c, 0x7c, 0x75, 0x0d, 0xc1, 0x12, 0x0d, 0x04,
+  0xd2, 0x04, 0xe4, 0x90, 0x7f, 0xcd, 0xf0, 0x90, 0x7f, 0xba, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x05,
+  0x36, 0x12, 0x12, 0x20, 0x8f, 0x19, 0x12, 0x13, 0x7b, 0x8f, 0x37, 0xe5, 0x19, 0xc3, 0x95}},
+ {0x04c6, 64, { 0x3b, 0x50, 0x0f, 0x12, 0x13, 0x57, 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x37, 0x20, 0xe7, 0x03, 0x30, 0x0c,
+  0x5e, 0xc2, 0x0c, 0xe5, 0x19, 0x60, 0x58, 0xb4, 0x80, 0x03, 0x43, 0x37, 0x02, 0xe5, 0x37, 0x30,
+  0xe7, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08, 0x7e,
+  0x7d, 0x7f, 0x80, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0x80, 0xaf, 0x37, 0x12, 0x0f, 0x84, 0xe5}},
+ {0x0506, 64, { 0x19, 0x25, 0xe0, 0x90, 0x7f, 0xbb, 0xf0, 0x80, 0x27, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75,
+  0x19, 0x3f, 0x85, 0x19, 0x08, 0x90, 0x7d, 0x80, 0xe5, 0x37, 0xf0, 0x7e, 0x7d, 0x7f, 0x81, 0x75,
+  0x0c, 0x7d, 0x75, 0x0d, 0x81, 0x12, 0x0d, 0x29, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xbb, 0xf0, 0x90,
+  0x7f, 0xd0, 0xe0, 0x30, 0xe1, 0x06, 0x20, 0x06, 0x03, 0x02, 0x07, 0x97, 0xc2, 0x06, 0xe4}},
+ {0x0546, 64, { 0xf5, 0x18, 0x74, 0xc0, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18,
+  0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e, 0x79, 0x20, 0x24, 0x20, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef,
+  0x12, 0x0e, 0xd2, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x20, 0xe0, 0x60, 0x68,
+  0x90, 0x7e, 0x23, 0xe0, 0x60, 0x24, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x11, 0xfb, 0x7f, 0x03}},
+ {0x0586, 64, { 0x7d, 0xcd, 0x12, 0x11, 0xfb, 0x43, 0x47, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00,
+  0xe5, 0x47, 0xf0, 0xe4, 0x90, 0x7e, 0x33, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x21, 0xe0, 0xff, 0x12,
+  0x11, 0x19, 0x90, 0x7e, 0x22, 0xe0, 0xff, 0x12, 0x11, 0x3f, 0x7f, 0x01, 0x90, 0x7e, 0x31, 0xe0,
+  0xfd, 0x12, 0x11, 0xfb, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x11, 0xfb, 0x43, 0x47, 0x80, 0x90}},
+ {0x05c6, 64, { 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0,
+  0xe5, 0x41, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x23, 0xe0, 0x70, 0x06, 0x90, 0x7e,
+  0x33, 0xe0, 0x70, 0x08, 0xe4, 0x90, 0x7e, 0x33, 0xf0, 0x75, 0x2e, 0xff, 0x90, 0x7e, 0x25, 0xe0,
+  0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f, 0xf5, 0x45, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90}},
+ {0x0606, 64, { 0xc0, 0x00, 0xe5, 0x45, 0xf0, 0x90, 0x7e, 0x27, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x43,
+  0x80, 0x80, 0x03, 0x53, 0x43, 0x7f, 0x53, 0x43, 0xfc, 0x90, 0x7e, 0x29, 0xe0, 0x60, 0x11, 0x43,
+  0x43, 0x02, 0xa3, 0xe0, 0xff, 0x12, 0x11, 0x65, 0x90, 0x7e, 0x2b, 0xe0, 0xff, 0x12, 0x11, 0x8b,
+  0xaf, 0x43, 0x12, 0x10, 0xf3, 0x90, 0x7e, 0x23, 0xe0, 0x60, 0x08, 0x53, 0x43, 0x7f, 0xaf}},
+ {0x0646, 64, { 0x43, 0x12, 0x10, 0xf3, 0x90, 0x7e, 0x2c, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x02,
+  0x80, 0x03, 0x53, 0x47, 0xfd, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47,
+  0xf0, 0x90, 0x7e, 0x2e, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x01, 0x80, 0x03,
+  0x53, 0x47, 0xfe, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0}},
+ {0x0686, 64, { 0x90, 0x7e, 0x32, 0xe0, 0xf5, 0x3b, 0xa3, 0xe0, 0x13, 0x92, 0x0e, 0xa3, 0xe0, 0xf5, 0x3d, 0xa3, 0xe0,
+  0x60, 0x05, 0x43, 0x47, 0x10, 0x80, 0x03, 0x53, 0x47, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0,
+  0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7e, 0x36, 0xe0, 0x60, 0x32, 0x53, 0x45, 0xbf, 0x90,
+  0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f}},
+ {0x06c6, 64, { 0x98, 0x74, 0x09, 0xf0, 0x12, 0x13, 0x4b, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3f, 0xfd,
+  0xe4, 0xff, 0xad, 0x3f, 0x12, 0x11, 0xfb, 0xe4, 0xf5, 0x33, 0xf5, 0x32, 0xd2, 0x08, 0x90, 0x7e,
+  0x37, 0xe0, 0x60, 0x0f, 0x43, 0x3f, 0x02, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x11, 0xfb, 0x75, 0x32,
+  0x01, 0xd2, 0x08, 0x90, 0x7e, 0x38, 0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0}},
+ {0x0706, 64, { 0xe5, 0x41, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0, 0xd2, 0x00, 0x90, 0x7e, 0x39, 0xe0, 0x60, 0x11, 0x43,
+  0x45, 0x40, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0,
+  0x90, 0x7e, 0x3a, 0xe0, 0x60, 0x0f, 0x53, 0x3f, 0xfe, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x11, 0xfb,
+  0x75, 0x34, 0x01, 0xd2, 0x08, 0x90, 0x7e, 0x3b, 0xe0, 0x60, 0x0f, 0x43, 0x3f, 0x01, 0xe4}},
+ {0x0746, 64, { 0xff, 0xad, 0x3f, 0x12, 0x11, 0xfb, 0xe4, 0xf5, 0x34, 0xd2, 0x08, 0x90, 0x7e, 0x3c, 0xe0, 0x60, 0x0e,
+  0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0xe5, 0x41, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e,
+  0x3d, 0xe0, 0x60, 0x02, 0xd2, 0x0c, 0x90, 0x7e, 0x3e, 0xe0, 0x60, 0x08, 0x75, 0x35, 0x01, 0xe4,
+  0xf5, 0x39, 0xd2, 0x08, 0x90, 0x7e, 0x3f, 0xe0, 0x60, 0x11, 0x90, 0x7f, 0xd7, 0x74, 0x13}},
+ {0x0786, 64, { 0xf0, 0x74, 0x33, 0xf0, 0x74, 0x16, 0xf0, 0x74, 0x36, 0xf0, 0xd2, 0x04, 0xe4, 0x90, 0x7f, 0xd1, 0xf0,
+  0x30, 0x1a, 0x52, 0xe5, 0x39, 0x60, 0x02, 0x15, 0x39, 0x30, 0x13, 0x49, 0xe5, 0x13, 0xd3, 0x94,
+  0x00, 0x40, 0x04, 0x15, 0x13, 0x80, 0x3e, 0x75, 0x13, 0x0a, 0x30, 0x1b, 0x02, 0xc2, 0x13, 0x12,
+  0x13, 0x4b, 0xef, 0x54, 0x01, 0xf5, 0x19, 0x65, 0x33, 0x60, 0x05, 0x85, 0x19, 0x33, 0xd2}},
+ {0x07c6, 64, { 0x08, 0x12, 0x13, 0x87, 0xef, 0x54, 0x80, 0xf5, 0x19, 0x65, 0x2f, 0x60, 0x05, 0x85, 0x19, 0x2f, 0xd2,
+  0x08, 0x30, 0x0e, 0x11, 0x12, 0x13, 0x87, 0xef, 0x54, 0x10, 0xf5, 0x19, 0x65, 0x2e, 0x60, 0x05,
+  0x85, 0x19, 0x2e, 0xd2, 0x08, 0x30, 0x1a, 0x2a, 0x90, 0x7f, 0xd2, 0xe0, 0x20, 0xe1, 0x23, 0x90,
+  0x7b, 0x40, 0xe0, 0x60, 0x09, 0xe0, 0xf5, 0x15, 0x90, 0x7b, 0x42, 0xe0, 0xf5, 0x16, 0x90}},
+ {0x0806, 64, { 0x7b, 0x41, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7, 0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0xe4, 0x90, 0x7f,
+  0xd3, 0xf0, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x09, 0x20, 0xe5, 0x0a, 0x70, 0x40,
+  0x30, 0x07, 0x39, 0xe5, 0x38, 0x70, 0x35, 0xc2, 0x07, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74,
+  0x24, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0x8c, 0xff, 0x74, 0x80, 0x25}},
+ {0x0846, 64, { 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb,
+  0x90, 0x7f, 0xc3, 0x74, 0x09, 0xf0, 0x75, 0x38, 0x10, 0xe4, 0xf5, 0x2c, 0x75, 0x0a, 0x01, 0x22,
+  0xe5, 0x0a, 0x64, 0x01, 0x70, 0x40, 0x30, 0x08, 0x39, 0xe5, 0x39, 0x70, 0x35, 0xc2, 0x08, 0xf5,
+  0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x2d, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12}},
+ {0x0886, 64, { 0x0e, 0x8c, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05,
+  0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x09, 0xf0, 0x75, 0x39, 0x10, 0xe4,
+  0xf5, 0x35, 0x75, 0x0a, 0x02, 0x22, 0xe5, 0x0a, 0x64, 0x02, 0x70, 0x36, 0x30, 0x14, 0x2f, 0xc2,
+  0x14, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x0e, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00}},
+ {0x08c6, 64, { 0xfa, 0x12, 0x0e, 0x8c, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef,
+  0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x05, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x05, 0xf0, 0x75, 0x0a,
+  0x03, 0x22, 0xe5, 0x15, 0x60, 0x30, 0x15, 0x15, 0xe4, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74,
+  0x14, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0x8c, 0xff, 0x74, 0x80, 0x25}},
+ {0x0906, 64, { 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x03, 0xdb,
+  0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4, 0xf5, 0x0a, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x0e,
+  0xe4, 0x0a, 0x08, 0x00, 0x0a, 0x7c, 0x01, 0x0a, 0xe8, 0x03, 0x09, 0x44, 0x06, 0x09, 0xfb, 0x08,
+  0x09, 0xf5, 0x09, 0x09, 0xdd, 0x0a, 0x09, 0xec, 0x0b, 0x00, 0x00, 0x0b, 0x37, 0x90, 0x7f}},
+ {0x0946, 64, { 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x19, 0x14, 0x60, 0x61, 0x24, 0x02, 0x60, 0x03, 0x02, 0x09, 0xd3, 0x74,
+  0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f,
+  0xea, 0xe0, 0x70, 0x04, 0x7f, 0x02, 0x80, 0x02, 0x7f, 0x03, 0x75, 0x82, 0x82, 0x75, 0x83, 0x19,
+  0xef, 0xf0, 0x75, 0x82, 0x7b, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x74, 0x75, 0x83, 0x19}},
+ {0x0986, 64, { 0xf0, 0x75, 0x82, 0x66, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x58, 0x75, 0x83, 0x19, 0xf0, 0x90, 0x7f,
+  0xea, 0xe0, 0x04, 0x75, 0x82, 0x17, 0x75, 0x83, 0x19, 0xf0, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0,
+  0x74, 0x12, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0f,
+  0x0a, 0xea, 0x49, 0x60, 0x0d, 0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0}},
+ {0x09c6, 64, { 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xb4, 0xe0,
+  0x44, 0x01, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0x00, 0xe5, 0x09, 0xf0, 0x90, 0x7f, 0xb5, 0x74,
+  0x01, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x09, 0x02, 0x0b, 0x3e, 0x12, 0x0b,
+  0x46, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02}},
+ {0x0a06, 64, { 0x0b, 0x3e, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b,
+  0xa2, 0x10, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x16, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00,
+  0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x3e, 0xe4, 0x90, 0x7f,
+  0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f}},
+ {0x0a46, 64, { 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24,
+  0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4,
+  0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xb4, 0xe0, 0x44,
+  0x01, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02}},
+ {0x0a86, 64, { 0x60, 0x03, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x10, 0x02, 0x0b, 0x3e,
+  0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38,
+  0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f,
+  0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f}},
+ {0x0ac6, 64, { 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f,
+  0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80,
+  0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea,
+  0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x10, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0}},
+ {0x0b06, 64, { 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4,
+  0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f,
+  0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07,
+  0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22}},
+ {0x0b46, 64, { 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0, 0x90,
+  0x7f, 0x95, 0x74, 0xc0, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x18,
+  0xf0, 0xe4, 0xf5, 0x8e, 0x90, 0x7f, 0xdf, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0xe4, 0xf5,
+  0x24, 0x75, 0x18, 0x01, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x18, 0xf9, 0xe4, 0x34, 0x00, 0xfa}},
+ {0x0b86, 64, { 0xe4, 0x12, 0x0e, 0xd2, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xea, 0x75, 0x3a, 0x01, 0xe4, 0xf5, 0x38,
+  0xf5, 0x13, 0xf5, 0x36, 0xc2, 0x07, 0xc2, 0x0b, 0xc2, 0x05, 0xc2, 0x00, 0xc2, 0x09, 0xc2, 0x13,
+  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x75, 0x44, 0x03, 0x90, 0xc0, 0x00, 0x74, 0x03, 0xf0, 0x7f,
+  0x0c, 0xe4, 0xfd, 0x12, 0x11, 0xb1, 0x7f, 0x10, 0x8f, 0x42, 0x12, 0x10, 0x81, 0x90, 0x7f}},
+ {0x0bc6, 64, { 0x98, 0x74, 0x12, 0xf0, 0x7f, 0x01, 0x8f, 0x40, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f,
+  0x98, 0x74, 0x14, 0xf0, 0x75, 0x46, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0x0f, 0xe4, 0xfd,
+  0x12, 0x11, 0xb1, 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3e, 0x12, 0x11, 0xb1, 0x90, 0x7f,
+  0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x11}},
+ {0x0c06, 64, { 0xb1, 0x7f, 0x01, 0x12, 0x12, 0x6a, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x11, 0xb1, 0x20, 0x1b, 0x03, 0x02,
+  0x0c, 0xb7, 0x75, 0x2d, 0x01, 0x75, 0x18, 0x01, 0x7b, 0x00, 0x74, 0x2d, 0x25, 0x18, 0xf9, 0xe4,
+  0x34, 0x00, 0xfa, 0xe4, 0x12, 0x0e, 0xd2, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xea, 0x75, 0x3b,
+  0x01, 0xe4, 0xf5, 0x39, 0xf5, 0x13, 0xf5, 0x37, 0xc2, 0x08, 0xc2, 0x0c, 0xc2, 0x06, 0xc2}},
+ {0x0c46, 64, { 0x00, 0xc2, 0x0a, 0xc2, 0x13, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x75, 0x45, 0x03, 0x90, 0xc0, 0x00,
+  0x74, 0x03, 0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x11, 0xfb, 0x7f, 0x10, 0x8f, 0x43, 0x12, 0x10,
+  0xf3, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x7f, 0x01, 0x8f, 0x41, 0xef, 0x44, 0x06, 0x90, 0xc0,
+  0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x75, 0x47, 0x80, 0x90, 0xc0, 0x00, 0x74}},
+ {0x0c86, 64, { 0x80, 0xf0, 0x0f, 0xe4, 0xfd, 0x12, 0x11, 0xfb, 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3f, 0x12,
+  0x11, 0xfb, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d,
+  0x7f, 0x12, 0x11, 0xfb, 0x7f, 0x01, 0x12, 0x12, 0x8b, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x11, 0xfb,
+  0xd2, 0x12, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82}},
+ {0x0cc6, 64, { 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86,
   0xf0, 0x05, 0x86, 0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x08,
-  0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00}},
- {0x0d06, 64, { 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98,
-  0x74, 0x08, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05,
+  0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0,
+  0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x90, 0x7f}},
+ {0x0d06, 64, { 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05,
   0x86, 0x90, 0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05, 0x86, 0xdf, 0xf7, 0xd2,
-  0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5}},
- {0x0d46, 64, { 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86,
-  0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05,
+  0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c,
+  0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05}},
+ {0x0d46, 64, { 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05,
   0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43,
-  0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xd2, 0x19, 0x90, 0x7f, 0x92, 0xe0, 0x44}},
- {0x0d86, 64, { 0x02, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92, 0x10, 0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0, 0xd2,
-  0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f,
+  0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xd2, 0x19, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02,
+  0xf0, 0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92, 0x10, 0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0}},
+ {0x0d86, 64, { 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f,
   0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90,
-  0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x0d, 0xf0, 0xd2, 0xaf}},
- {0x0dc6, 64, { 0xd2, 0x1a, 0x12, 0x12, 0x5c, 0xc2, 0x11, 0xe4, 0xf5, 0x0b, 0xf5, 0x13, 0xc2, 0x17, 0xc2, 0x12, 0x90,
-  0x7f, 0xa1, 0x04, 0xf0, 0x90, 0x7f, 0xd8, 0xe0, 0x65, 0x17, 0x60, 0x10, 0x30, 0x12, 0x05, 0xd2,
+  0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2,
+  0x1a, 0x12, 0x12, 0x45, 0xc2, 0x11, 0xe4, 0xf5, 0x0b, 0xf5, 0x13, 0xc2, 0x17, 0xc2, 0x12}},
+ {0x0dc6, 64, { 0x90, 0x7f, 0xa1, 0x04, 0xf0, 0x90, 0x7f, 0xd8, 0xe0, 0x65, 0x17, 0x60, 0x10, 0x30, 0x12, 0x05, 0xd2,
   0x1a, 0x12, 0x00, 0x46, 0x90, 0x7f, 0xd8, 0xe0, 0xf5, 0x17, 0x80, 0x08, 0x30, 0x12, 0x05, 0xc2,
-  0x1a, 0x12, 0x00, 0x46, 0x30, 0x11, 0x07, 0xc2, 0x11, 0x12, 0x09, 0x29, 0x80, 0xd6, 0x30}},
- {0x0e06, 64, { 0x18, 0xd3, 0xc2, 0x18, 0x12, 0x12, 0xf6, 0x80, 0xcc, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75,
-  0x81, 0x47, 0x02, 0x0e, 0x57, 0x02, 0x0d, 0x7f, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40,
+  0x1a, 0x12, 0x00, 0x46, 0x30, 0x11, 0x07, 0xc2, 0x11, 0x12, 0x09, 0x21, 0x80, 0xd6, 0x30, 0x18,
+  0xd3, 0xc2, 0x18, 0x12, 0x13, 0x93, 0x80, 0xcc, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd}},
+ {0x0e06, 64, { 0x75, 0x81, 0x47, 0x02, 0x0e, 0x47, 0x02, 0x0d, 0x6f, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40,
   0x03, 0xf6, 0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07,
-  0x24, 0x0c, 0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4}},
- {0x0e46, 64, { 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
-  0x90, 0x12, 0xc3, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09,
+  0x24, 0x0c, 0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56,
+  0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40}},
+ {0x0e46, 64, { 0x80, 0x90, 0x12, 0xac, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09,
   0x54, 0x1f, 0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8,
-  0x40, 0xb8, 0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5}},
- {0x0e86, 64, { 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf,
-  0xe9, 0xde, 0xe7, 0x80, 0xbe, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02,
+  0x40, 0xb8, 0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82,
+  0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca}},
+ {0x0e86, 64, { 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02,
   0xe7, 0x22, 0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01,
-  0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06}},
- {0x0ec6, 64, { 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82,
-  0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82,
+  0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9,
+  0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5}},
+ {0x0ec6, 64, { 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82,
   0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xd0, 0x83, 0xd0,
-  0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8}},
- {0x0f06, 64, { 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3,
-  0xa3, 0x80, 0xdf, 0x8f, 0x18, 0xe4, 0xf5, 0x19, 0x75, 0x1a, 0xff, 0x75, 0x1b, 0x19, 0x75, 0x1c,
-  0x86, 0xab, 0x1a, 0xaa, 0x1b, 0xa9, 0x1c, 0x90, 0x00, 0x01, 0x12, 0x0e, 0xb5, 0xb4, 0x03, 0x1d,
-  0xaf, 0x19, 0x05, 0x19, 0xef, 0xb5, 0x18, 0x01, 0x22, 0x12, 0x0e, 0x9c, 0x7e, 0x00, 0x29}},
- {0x0f46, 64, { 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75, 0x1a, 0xff, 0xf5, 0x1b, 0x89, 0x1c, 0x80, 0xd4, 0x7b, 0x00, 0x7a,
-  0x00, 0x79, 0x00, 0x22, 0x8f, 0x1a, 0x05, 0x0d, 0xe5, 0x0d, 0xae, 0x0c, 0x70, 0x02, 0x05, 0x0c,
+  0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74,
+  0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3}},
+ {0x0f06, 64, { 0xa3, 0xa3, 0x80, 0xdf, 0x8f, 0x18, 0xe4, 0xf5, 0x19, 0x75, 0x1a, 0xff, 0x75, 0x1b, 0x19, 0x75, 0x1c,
+  0x86, 0xab, 0x1a, 0xaa, 0x1b, 0xa9, 0x1c, 0x90, 0x00, 0x01, 0x12, 0x0e, 0xa5, 0xb4, 0x03, 0x1d,
+  0xaf, 0x19, 0x05, 0x19, 0xef, 0xb5, 0x18, 0x01, 0x22, 0x12, 0x0e, 0x8c, 0x7e, 0x00, 0x29, 0xff,
+  0xee, 0x3a, 0xa9, 0x07, 0x75, 0x1a, 0xff, 0xf5, 0x1b, 0x89, 0x1c, 0x80, 0xd4, 0x7b, 0x00}},
+ {0x0f46, 64, { 0x7a, 0x00, 0x79, 0x00, 0x22, 0x8f, 0x1a, 0x05, 0x0d, 0xe5, 0x0d, 0xae, 0x0c, 0x70, 0x02, 0x05, 0x0c,
   0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x1a, 0xf0, 0x12, 0x00, 0x36, 0x05, 0x0d, 0xe5, 0x0d, 0xac,
-  0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5}},
- {0x0f86, 64, { 0x08, 0x60, 0x0a, 0x12, 0x13, 0x3f, 0x8f, 0x1a, 0xef, 0x42, 0x36, 0x80, 0xca, 0x22, 0x8f, 0x1a, 0x05,
-  0x0d, 0xe5, 0x0d, 0xae, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x1a,
-  0xf0, 0x12, 0x13, 0x57, 0x05, 0x0d, 0xe5, 0x0d, 0xac, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5,
-  0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x0a, 0x12, 0x13, 0x93, 0x8f}},
- {0x0fc6, 64, { 0x1a, 0xef, 0x42, 0x37, 0x80, 0xca, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84,
-  0xc0, 0x86, 0x75, 0x86, 0x00, 0x30, 0x15, 0x04, 0xc2, 0x15, 0x80, 0x02, 0xd2, 0x18, 0x53, 0x91,
-  0xef, 0x90, 0x7f, 0xab, 0x74, 0x08, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0,
-  0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0}},
- {0x1006, 64, { 0x86, 0x75, 0x86, 0x00, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04,
-  0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0,
-  0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x11, 0x53,
-  0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0}},
- {0x1046, 64, { 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf,
-  0xf0, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74,
-  0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13,
-  0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0}},
- {0x1086, 64, { 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0,
-  0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98,
-  0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44,
-  0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0}},
- {0x10c6, 64, { 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f,
-  0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98,
-  0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90,
-  0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90}},
- {0x1106, 64, { 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90,
-  0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0,
-  0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90,
-  0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0x90, 0xc0, 0x00, 0xef}},
- {0x1146, 64, { 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90,
-  0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x09,
-  0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f,
-  0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74}},
- {0x1186, 64, { 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74,
-  0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b,
-  0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0e, 0xf0, 0x90, 0xc0, 0x00,
-  0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00}},
- {0x11c6, 64, { 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90,
-  0x7f, 0x98, 0x74, 0x17, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0,
-  0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22, 0x12, 0x13, 0x27, 0x8f, 0x1a, 0x12, 0x13, 0x27, 0x8f, 0x1b,
-  0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x12, 0x12, 0x13, 0x27, 0x8f, 0x1a, 0xe5, 0x1a, 0x65, 0x1b}},
- {0x1206, 64, { 0x60, 0x07, 0x12, 0x13, 0x27, 0x8f, 0x1b, 0x80, 0xe8, 0xaf, 0x1a, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b,
-  0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0f, 0xf0, 0x90,
-  0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22,
-  0x12, 0x13, 0x7b, 0x8f, 0x1a, 0x12, 0x13, 0x7b, 0x8f, 0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60}},
- {0x1246, 64, { 0x12, 0x12, 0x13, 0x7b, 0x8f, 0x1a, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x07, 0x12, 0x13, 0x7b, 0x8f, 0x1b,
-  0x80, 0xe8, 0xaf, 0x1a, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0,
-  0x30, 0x1a, 0x04, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x12, 0xdf, 0x90, 0x7f,
-  0xd6, 0xe0, 0x54, 0xf7, 0xf0, 0xe0, 0x44, 0x04, 0xf0, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5}},
- {0x1286, 64, { 0x3e, 0x54, 0x7f, 0xfd, 0x12, 0x11, 0xc8, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xee,
-  0xf0, 0xe4, 0xe5, 0x3e, 0x44, 0x80, 0xfd, 0x12, 0x11, 0xc8, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5,
-  0x3f, 0x54, 0x7f, 0xfd, 0x12, 0x12, 0x12, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00,
-  0xee, 0xf0, 0xe4, 0xe5, 0x3f, 0x44, 0x80, 0xfd, 0x12, 0x12, 0x12, 0x22, 0x05, 0x0e, 0x02}},
- {0x12c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x03, 0x14, 0x03, 0x00, 0x00, 0xc1, 0x11, 0xc1, 0x18, 0xc1, 0x95, 0xc1, 0x10,
-  0xc1, 0x16, 0x01, 0x0a, 0x00, 0xc1, 0x9b, 0x00, 0x8e, 0x18, 0x8f, 0x19, 0xe5, 0x19, 0x15, 0x19,
-  0xae, 0x18, 0x70, 0x02, 0x15, 0x18, 0x4e, 0x60, 0x05, 0x12, 0x0d, 0x5e, 0x80, 0xee, 0x22, 0x12,
-  0x00, 0x03, 0x12, 0x0d, 0x6f, 0x12, 0x0b, 0x4e, 0x22, 0x02, 0x10, 0x25, 0x00, 0x02, 0x13}},
- {0x1306, 64, { 0x04, 0x00, 0x02, 0x0f, 0xfb, 0x00, 0x02, 0x0f, 0xcd, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0,
+  0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08,
+  0x60, 0x0a, 0x12, 0x13, 0x27, 0x8f, 0x1a, 0xef, 0x42, 0x36, 0x80, 0xca, 0x22, 0x8f, 0x1a}},
+ {0x0f86, 64, { 0x05, 0x0d, 0xe5, 0x0d, 0xae, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x1a,
+  0xf0, 0x12, 0x13, 0x3f, 0x05, 0x0d, 0xe5, 0x0d, 0xac, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5,
+  0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x0a, 0x12, 0x13, 0x7b, 0x8f, 0x1a,
+  0xef, 0x42, 0x37, 0x80, 0xca, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0}},
+ {0x0fc6, 64, { 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab,
+  0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32,
+  0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2,
+  0x11, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0}},
+ {0x1006, 64, { 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0,
+  0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x18, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08,
+  0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7f,
+  0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x10}},
+ {0x1046, 64, { 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90,
+  0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0,
+  0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13,
+  0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13}},
+ {0x1086, 64, { 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00, 0xef,
+  0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22,
+  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74,
+  0x14, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44}},
+ {0x10c6, 64, { 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74,
+  0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98,
+  0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74,
+  0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x90}},
+ {0x1106, 64, { 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00,
+  0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f,
+  0x98, 0x74, 0x08, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5,
+  0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90}},
+ {0x1146, 64, { 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90,
+  0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f,
+  0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0,
+  0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f}},
+ {0x1186, 64, { 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0,
+  0x90, 0x7f, 0x98, 0x74, 0x0e, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b,
+  0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0,
+  0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x17, 0xf0, 0x90}},
+ {0x11c6, 64, { 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22, 0x12,
+  0x13, 0x0f, 0x8f, 0x1a, 0x12, 0x13, 0x0f, 0x8f, 0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x12, 0x12,
+  0x13, 0x0f, 0x8f, 0x1a, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x07, 0x12, 0x13, 0x0f, 0x8f, 0x1b, 0x80,
+  0xe8, 0xaf, 0x1a, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90}},
+ {0x1206, 64, { 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0f, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98,
+  0x74, 0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22, 0x12, 0x13, 0x63, 0x8f, 0x1a, 0x12, 0x13,
+  0x63, 0x8f, 0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x12, 0x12, 0x13, 0x63, 0x8f, 0x1a, 0xe5, 0x1a,
+  0x65, 0x1b, 0x60, 0x07, 0x12, 0x13, 0x63, 0x8f, 0x1b, 0x80, 0xe8, 0xaf, 0x1a, 0x22, 0x90}},
+ {0x1246, 64, { 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x1a, 0x04, 0xe0, 0x44, 0x02, 0xf0,
+  0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x12, 0xc8, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0, 0xe0, 0x44,
+  0x04, 0xf0, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5, 0x3e, 0x54, 0x7f, 0xfd, 0x12, 0x11, 0xb1, 0x90,
+  0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x3e, 0x44, 0x80}},
+ {0x1286, 64, { 0xfd, 0x12, 0x11, 0xb1, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5, 0x3f, 0x54, 0x7f, 0xfd, 0x12, 0x11, 0xfb,
+  0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x3f, 0x44, 0x80,
+  0xfd, 0x12, 0x11, 0xfb, 0x22, 0x05, 0x0e, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x14, 0x03, 0x00,
+  0x00, 0xc1, 0x11, 0xc1, 0x18, 0xc1, 0x95, 0xc1, 0x10, 0xc1, 0x16, 0x01, 0x0a, 0x00, 0xc1}},
+ {0x12c6, 64, { 0x9b, 0x00, 0x8e, 0x18, 0x8f, 0x19, 0xe5, 0x19, 0x15, 0x19, 0xae, 0x18, 0x70, 0x02, 0x15, 0x18, 0x4e,
+  0x60, 0x05, 0x12, 0x0d, 0x4e, 0x80, 0xee, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0,
   0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22,
-  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74,
-  0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90}},
- {0x1346, 64, { 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22,
-  0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74,
-  0x09, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x90, 0xc0,
-  0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff}},
- {0x1386, 64, { 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74,
-  0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0e, 0xf0, 0x90, 0xc0,
-  0x00, 0xe0, 0xff, 0x22, 0x53, 0xd8, 0xef, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x53, 0xd8, 0xef, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0xe7, 0x00, 0x02, 0x13}},
+ {0x1306, 64, { 0x04, 0x00, 0x02, 0x0f, 0xbd, 0x00, 0x02, 0x10, 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0,
+  0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22,
+  0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74,
+  0x16, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0x90}},
+ {0x1346, 64, { 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22,
+  0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74,
+  0x0b, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0,
+  0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff}},
+ {0x1386, 64, { 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0e, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x12, 0x00, 0x03, 0x12,
+  0x0d, 0x5f, 0x12, 0x0b, 0x46, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
  {0x13c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -420,7 +425,7 @@
  {0x18c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x01, 0xff, 0x00}},
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x10, 0x01, 0xff, 0x00}},
  {0x1906, 64, { 0x00, 0x40, 0xcd, 0x06, 0x10, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x02, 0x09, 0x02, 0x74, 0x00, 0x01,
   0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e, 0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01,
   0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40,
@@ -438,5 +443,5 @@
   0x00, 0x42, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c,
   0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x61, 0x00, 0x70, 0x00, 0x74, 0x00, 0x65, 0x00}},
  {0x1a06,  4, { 0x72, 0x00, 0x00, 0x00}},
-{ 0xffff,	0,	{0x00} }
+ {0xffff,  0,  {0x00}}
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/keyspan_usa28xa_fw.h linux-2.4.20/drivers/usb/serial/keyspan_usa28xa_fw.h
--- linux-2.4.19/drivers/usb/serial/keyspan_usa28xa_fw.h	2001-10-09 22:15:03.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/keyspan_usa28xa_fw.h	2002-10-29 11:18:33.000000000 +0000
@@ -1,351 +1,354 @@
 /* keyspan_usa28xa_fw.h
 
-   Generated from Keyspan firmware image usa44code.h Sat Oct  6 12:08:02 EST 2001
-   This firmware is for the Keyspan USA-28XA Serial Adaptor
+	The firmware contained herein as keyspan_usa28xa.h is
 
-   "The firmware contained herein as keyspan_usa28xa_fw.h is
-   Copyright (C) 1999-2001 Keyspan, A division of InnoSys Incorporated
-   ("Keyspan"), as an unpublished work.  This notice does not imply
-   unrestricted or public access to this firmware which is a trade secret of
-   Keyspan, and which may not be reproduced, used, sold or transferred to any
-   third party without Keyspan's prior written consent.  All Rights Reserved.
+		Copyright (C) 1999-2001
+		Keyspan, A division of InnoSys Incorporated ("Keyspan")
+		
+	as an unpublished work. This notice does not imply unrestricted or
+	public access to the source code from which this firmware image is
+	derived.  Except as noted below this firmware image may not be 
+	reproduced, used, sold or transferred to any third party without 
+	Keyspan's prior written consent.  All Rights Reserved.
+
+	Permission is hereby granted for the distribution of this firmware 
+	image as part of a Linux or other Open Source operating system kernel 
+	in text or binary form as required. 
+
+	This firmware may not be modified and may only be used with  
+	Keyspan hardware.  Distribution and/or Modification of the 
+	keyspan.c driver which includes this firmware, in whole or in 
+	part, requires the inclusion of this statement."
 
-   Permission is hereby granted for the distribution of this firmware image
-   as part of a Linux or other Open Source operating system kernel in 
-   text or binary form as required.
 
-   This firmware may not be modified and may only be used with the Keyspan 
-   USA-28XA Serial Adapter.  Distribution and/or Modification of the
-   keyspan.c driver which includes this firmware, in whole or in part,
-   requires the inclusion of this statement."
 
 */
 
 static const struct ezusb_hex_record keyspan_usa28xa_firmware[] = {
- {0x0033,  3, { 0x02, 0x13, 0xaa}},
+ {0x0033,  3, { 0x02, 0x12, 0xf9}},
  {0x0003, 16, { 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0}},
  {0x0013, 16, { 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90}},
  {0x0023, 15, { 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x07, 0xf0, 0xe4, 0x90, 0x7f, 0x98, 0xf0, 0x22}},
- {0x0046, 16, { 0x30, 0x09, 0x18, 0x12, 0x13, 0x28, 0xef, 0xc3, 0x95, 0x3c, 0x40, 0x03, 0x02, 0x00, 0xd8, 0x90}},
+ {0x0046, 16, { 0x30, 0x09, 0x18, 0x12, 0x13, 0x27, 0xef, 0xc3, 0x95, 0x3c, 0x40, 0x03, 0x02, 0x00, 0xd8, 0x90}},
  {0x0056, 16, { 0x7f, 0xbf, 0x74, 0x01, 0xf0, 0xc2, 0x09, 0xc2, 0x00, 0x80, 0x77, 0x30, 0x03, 0x3b, 0x90, 0x7f}},
- {0x0066, 16, { 0xc6, 0xe0, 0x20, 0xe1, 0x6d, 0x12, 0x13, 0x28, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x64, 0x90, 0x7e}},
+ {0x0066, 16, { 0xc6, 0xe0, 0x20, 0xe1, 0x6d, 0x12, 0x13, 0x27, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x64, 0x90, 0x7e}},
  {0x0076, 16, { 0x40, 0xe0, 0x13, 0x92, 0x09, 0x90, 0x7f, 0xc7, 0xe0, 0x14, 0xf5, 0x19, 0x20, 0x00, 0x11, 0x60}},
- {0x0086, 16, { 0x0f, 0xf5, 0x08, 0x7e, 0x7e, 0x7f, 0x41, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x41, 0x12, 0x0c, 0xd8}},
+ {0x0086, 16, { 0x0f, 0xf5, 0x08, 0x7e, 0x7e, 0x7f, 0x41, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x41, 0x12, 0x0c, 0xc8}},
  {0x0096, 16, { 0xc2, 0x03, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0x80, 0x39, 0x90, 0x7f, 0xc8, 0xe0, 0x20, 0xe1, 0x32}},
- {0x00a6, 16, { 0x12, 0x13, 0x28, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x29, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x09}},
+ {0x00a6, 16, { 0x12, 0x13, 0x27, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x29, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x09}},
  {0x00b6, 16, { 0x90, 0x7f, 0xc9, 0xe0, 0x14, 0xf5, 0x19, 0x20, 0x00, 0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7d}},
- {0x00c6, 16, { 0x7f, 0xc1, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0xc1, 0x12, 0x0c, 0xd8, 0xd2, 0x03, 0xe4, 0x90, 0x7f}},
- {0x00d6, 16, { 0xc9, 0xf0, 0x90, 0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x01, 0x66, 0x53, 0x36, 0x80, 0x12}},
- {0x00e6, 16, { 0x13, 0x34, 0xef, 0x42, 0x36, 0x12, 0x11, 0xfb, 0x8f, 0x19, 0xef, 0xc3, 0x95, 0x3a, 0x50, 0x0f}},
- {0x00f6, 16, { 0x12, 0x13, 0x10, 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x36, 0x20, 0xe7, 0x03, 0x30, 0x0b, 0x61, 0xc2}},
+ {0x00c6, 16, { 0x7f, 0xc1, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0xc1, 0x12, 0x0c, 0xc8, 0xd2, 0x03, 0xe4, 0x90, 0x7f}},
+ {0x00d6, 16, { 0xc9, 0xf0, 0x90, 0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x01, 0x60, 0x12, 0x11, 0xe4, 0x8f}},
+ {0x00e6, 16, { 0x19, 0x12, 0x13, 0x33, 0x8f, 0x36, 0xe5, 0x19, 0xc3, 0x95, 0x3a, 0x50, 0x0f, 0x12, 0x13, 0x0f}},
+ {0x00f6, 16, { 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x36, 0x20, 0xe7, 0x03, 0x30, 0x0b, 0x5e, 0xc2, 0x0b, 0xe5, 0x19}},
  {0x0036, 12, { 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22}},
- {0x0043,  3, { 0x02, 0x14, 0x00}},
- {0x0000,  3, { 0x02, 0x0e, 0x1e}},
- {0x0106, 64, { 0x0b, 0xe5, 0x19, 0x70, 0x04, 0xf5, 0x36, 0x80, 0x57, 0x12, 0x13, 0x34, 0xef, 0x42, 0x36, 0xe5, 0x36,
-  0x30, 0xe7, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08,
-  0x7e, 0x7e, 0x7f, 0x80, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x80, 0xaf, 0x36, 0x12, 0x0f, 0x69, 0xe5,
-  0x19, 0x25, 0xe0, 0x90, 0x7f, 0xb7, 0xf0, 0x80, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40}},
- {0x0146, 64, { 0x03, 0x75, 0x19, 0x3f, 0x85, 0x19, 0x08, 0xe4, 0x90, 0x7e, 0x80, 0xf0, 0x7e, 0x7e, 0x7f, 0x81, 0x75,
-  0x0c, 0x7e, 0x75, 0x0d, 0x81, 0x12, 0x0c, 0xfd, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xb7, 0xf0, 0x90,
-  0x7f, 0xce, 0xe0, 0x30, 0xe1, 0x06, 0x20, 0x05, 0x03, 0x02, 0x03, 0xc5, 0xc2, 0x05, 0xe4, 0xf5,
-  0x18, 0x74, 0x40, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xff, 0xe5}},
- {0x0186, 64, { 0x18, 0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e, 0x79, 0x00, 0x24, 0x00, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef,
-  0x12, 0x0e, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x00, 0xe0, 0x60, 0x68,
-  0x90, 0x7e, 0x03, 0xe0, 0x60, 0x24, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x11, 0xd6, 0x7f, 0x03, 0x7d,
-  0xcd, 0x12, 0x11, 0xd6, 0x43, 0x46, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0}},
- {0x01c6, 64, { 0x00, 0xe5, 0x46, 0xf0, 0xe4, 0x90, 0x7e, 0x13, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x01, 0xe0, 0xff, 0x12,
-  0x10, 0x5a, 0x90, 0x7e, 0x02, 0xe0, 0xff, 0x12, 0x10, 0x80, 0x7f, 0x01, 0x90, 0x7e, 0x11, 0xe0,
-  0xfd, 0x12, 0x11, 0xd6, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x11, 0xd6, 0x43, 0x46, 0x80, 0x90, 0x7f,
-  0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12}},
- {0x0206, 64, { 0xf0, 0xe5, 0x40, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x03, 0xe0, 0x70, 0x06, 0x90, 0x7e,
-  0x13, 0xe0, 0x70, 0x08, 0xe4, 0x90, 0x7e, 0x13, 0xf0, 0x75, 0x25, 0xff, 0x90, 0x7e, 0x05, 0xe0,
-  0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f, 0xf5, 0x44, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0,
-  0x00, 0xe5, 0x44, 0xf0, 0x90, 0x7e, 0x07, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43}},
- {0x0246, 64, { 0x42, 0x80, 0x80, 0x03, 0x53, 0x42, 0x7f, 0x53, 0x42, 0xfc, 0x90, 0x7e, 0x09, 0xe0, 0x60, 0x11, 0x43,
-  0x42, 0x02, 0xa3, 0xe0, 0xff, 0x12, 0x10, 0xcc, 0x90, 0x7e, 0x0b, 0xe0, 0xff, 0x12, 0x10, 0xf2,
-  0xaf, 0x42, 0x12, 0x10, 0xa6, 0x90, 0x7e, 0x03, 0xe0, 0x60, 0x08, 0x53, 0x42, 0x7f, 0xaf, 0x42,
-  0x12, 0x10, 0xa6, 0x90, 0x7e, 0x0c, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46}},
- {0x0286, 64, { 0x02, 0x80, 0x03, 0x53, 0x46, 0xfd, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46,
-  0xf0, 0x90, 0x7e, 0x0e, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x01, 0x80, 0x03,
-  0x53, 0x46, 0xfe, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90,
-  0x7e, 0x12, 0xe0, 0xf5, 0x3a, 0xa3, 0xe0, 0x13, 0x92, 0x0d, 0xa3, 0xe0, 0xf5, 0x3c, 0xa3}},
- {0x02c6, 64, { 0xe0, 0x60, 0x05, 0x43, 0x46, 0x10, 0x80, 0x03, 0x53, 0x46, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0,
-  0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x16, 0xe0, 0x60, 0x32, 0x53, 0x44, 0xbf, 0x90,
-  0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98,
-  0x74, 0x11, 0xf0, 0x12, 0x13, 0x04, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3e}},
- {0x0306, 64, { 0xfd, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xd6, 0xe4, 0xf5, 0x2a, 0xf5, 0x29, 0xd2, 0x07, 0x90, 0x7e,
-  0x17, 0xe0, 0x60, 0x0f, 0x43, 0x3e, 0x02, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xd6, 0x75, 0x29,
-  0x01, 0xd2, 0x07, 0x90, 0x7e, 0x18, 0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5,
-  0x40, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0, 0xd2, 0x00, 0x90, 0x7e, 0x19, 0xe0, 0x60, 0x11}},
- {0x0346, 64, { 0x43, 0x44, 0x40, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0,
-  0x90, 0x7e, 0x1a, 0xe0, 0x60, 0x0f, 0x53, 0x3e, 0xfe, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xd6,
-  0x75, 0x2b, 0x01, 0xd2, 0x07, 0x90, 0x7e, 0x1b, 0xe0, 0x60, 0x0f, 0x43, 0x3e, 0x01, 0xe4, 0xff,
-  0xad, 0x3e, 0x12, 0x11, 0xd6, 0xe4, 0xf5, 0x2b, 0xd2, 0x07, 0x90, 0x7e, 0x1c, 0xe0, 0x60}},
- {0x0386, 64, { 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e,
-  0x1d, 0xe0, 0x60, 0x02, 0xd2, 0x0b, 0x90, 0x7e, 0x1e, 0xe0, 0x60, 0x08, 0x75, 0x2c, 0x01, 0xe4,
-  0xf5, 0x38, 0xd2, 0x07, 0x90, 0x7e, 0x1f, 0xe0, 0x60, 0x0f, 0x90, 0x7f, 0xd7, 0x74, 0x11, 0xf0,
-  0x74, 0x31, 0xf0, 0x74, 0x15, 0xf0, 0x74, 0x35, 0xf0, 0xe4, 0x90, 0x7f, 0xcf, 0xf0, 0x30}},
- {0x03c6, 64, { 0x1a, 0x52, 0xe5, 0x38, 0x60, 0x02, 0x15, 0x38, 0x20, 0x13, 0x49, 0xe5, 0x13, 0xd3, 0x94, 0x00, 0x40,
-  0x04, 0x15, 0x13, 0x80, 0x3e, 0x75, 0x13, 0x0a, 0x30, 0x1b, 0x02, 0xd2, 0x13, 0x12, 0x13, 0x04,
-  0xef, 0x54, 0x01, 0xf5, 0x19, 0x65, 0x2a, 0x60, 0x05, 0x85, 0x19, 0x2a, 0xd2, 0x07, 0x12, 0x13,
-  0x40, 0xef, 0x54, 0x80, 0xf5, 0x19, 0x65, 0x26, 0x60, 0x05, 0x85, 0x19, 0x26, 0xd2, 0x07}},
- {0x0406, 64, { 0x30, 0x0d, 0x11, 0x12, 0x13, 0x40, 0xef, 0x54, 0x10, 0xf5, 0x19, 0x65, 0x25, 0x60, 0x05, 0x85, 0x19,
-  0x25, 0xd2, 0x07, 0x20, 0x1b, 0x03, 0x02, 0x07, 0xf4, 0x30, 0x0a, 0x18, 0x12, 0x13, 0x7c, 0xef,
-  0xc3, 0x95, 0x3d, 0x40, 0x03, 0x02, 0x04, 0xb2, 0x90, 0x7f, 0xc1, 0x74, 0x01, 0xf0, 0xc2, 0x0a,
-  0xc2, 0x00, 0x80, 0x77, 0x30, 0x04, 0x3b, 0x90, 0x7f, 0xca, 0xe0, 0x20, 0xe1, 0x6d, 0x12}},
- {0x0446, 64, { 0x13, 0x7c, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x64, 0x90, 0x7d, 0x40, 0xe0, 0x13, 0x92, 0x0a, 0x90, 0x7f,
-  0xcb, 0xe0, 0x14, 0xf5, 0x19, 0x20, 0x00, 0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7d, 0x7f, 0x41,
-  0x75, 0x0c, 0x7d, 0x75, 0x0d, 0x41, 0x12, 0x0d, 0x22, 0xc2, 0x04, 0xe4, 0x90, 0x7f, 0xcb, 0xf0,
-  0x80, 0x39, 0x90, 0x7f, 0xcc, 0xe0, 0x20, 0xe1, 0x32, 0x12, 0x13, 0x7c, 0xef, 0xc3, 0x94}},
- {0x0486, 64, { 0x40, 0x50, 0x29, 0x90, 0x7c, 0xc0, 0xe0, 0x13, 0x92, 0x0a, 0x90, 0x7f, 0xcd, 0xe0, 0x14, 0xf5, 0x19,
-  0x20, 0x00, 0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7c, 0x7f, 0xc1, 0x75, 0x0c, 0x7c, 0x75, 0x0d,
-  0xc1, 0x12, 0x0d, 0x22, 0xd2, 0x04, 0xe4, 0x90, 0x7f, 0xcd, 0xf0, 0x90, 0x7f, 0xba, 0xe0, 0x30,
-  0xe1, 0x03, 0x02, 0x05, 0x40, 0x53, 0x37, 0x80, 0x12, 0x13, 0x88, 0xef, 0x42, 0x37, 0x12}},
- {0x04c6, 64, { 0x12, 0x45, 0x8f, 0x19, 0xef, 0xc3, 0x95, 0x3b, 0x50, 0x0f, 0x12, 0x13, 0x64, 0xef, 0x30, 0xe0, 0x08,
-  0xe5, 0x37, 0x20, 0xe7, 0x03, 0x30, 0x0c, 0x61, 0xc2, 0x0c, 0xe5, 0x19, 0x70, 0x04, 0xf5, 0x37,
-  0x80, 0x57, 0x12, 0x13, 0x88, 0xef, 0x42, 0x37, 0xe5, 0x37, 0x30, 0xe7, 0x26, 0xe5, 0x19, 0xd3,
-  0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08, 0x7e, 0x7d, 0x7f, 0x80, 0x75}},
- {0x0506, 64, { 0x0c, 0x7d, 0x75, 0x0d, 0x80, 0xaf, 0x37, 0x12, 0x0f, 0xa2, 0xe5, 0x19, 0x25, 0xe0, 0x90, 0x7f, 0xbb,
-  0xf0, 0x80, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75, 0x19, 0x3f, 0x85, 0x19, 0x08,
-  0xe4, 0x90, 0x7d, 0x80, 0xf0, 0x7e, 0x7d, 0x7f, 0x81, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0x81, 0x12,
-  0x0d, 0x47, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xbb, 0xf0, 0x90, 0x7f, 0xd0, 0xe0, 0x30, 0xe1}},
- {0x0546, 64, { 0x06, 0x20, 0x06, 0x03, 0x02, 0x07, 0x9f, 0xc2, 0x06, 0xe4, 0xf5, 0x18, 0x74, 0xc0, 0x25, 0x18, 0xf5,
-  0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18, 0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e,
-  0x79, 0x20, 0x24, 0x20, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef, 0x12, 0x0e, 0xf0, 0x05, 0x18, 0xe5,
-  0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x20, 0xe0, 0x60, 0x68, 0x90, 0x7e, 0x23, 0xe0, 0x60}},
- {0x0586, 64, { 0x24, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x12, 0x20, 0x7f, 0x03, 0x7d, 0xcd, 0x12, 0x12, 0x20, 0x43, 0x47,
-  0x80, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0xe4, 0x90, 0x7e,
-  0x33, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x21, 0xe0, 0xff, 0x12, 0x11, 0x3e, 0x90, 0x7e, 0x22, 0xe0,
-  0xff, 0x12, 0x11, 0x64, 0x7f, 0x01, 0x90, 0x7e, 0x31, 0xe0, 0xfd, 0x12, 0x12, 0x20, 0x7f}},
- {0x05c6, 64, { 0x03, 0x7d, 0x07, 0x12, 0x12, 0x20, 0x43, 0x47, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0,
-  0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0xe5, 0x41, 0x44, 0x06, 0x90, 0xc0,
-  0x00, 0xf0, 0x90, 0x7e, 0x23, 0xe0, 0x70, 0x06, 0x90, 0x7e, 0x33, 0xe0, 0x70, 0x08, 0xe4, 0x90,
-  0x7e, 0x33, 0xf0, 0x75, 0x2e, 0xff, 0x90, 0x7e, 0x25, 0xe0, 0x60, 0x12, 0xa3, 0xe0, 0x54}},
- {0x0606, 64, { 0x3f, 0xf5, 0x45, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x45, 0xf0, 0x90, 0x7e,
-  0x27, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x43, 0x80, 0x80, 0x03, 0x53, 0x43, 0x7f,
-  0x53, 0x43, 0xfc, 0x90, 0x7e, 0x29, 0xe0, 0x60, 0x11, 0x43, 0x43, 0x02, 0xa3, 0xe0, 0xff, 0x12,
-  0x11, 0x8a, 0x90, 0x7e, 0x2b, 0xe0, 0xff, 0x12, 0x11, 0xb0, 0xaf, 0x43, 0x12, 0x11, 0x18}},
- {0x0646, 64, { 0x90, 0x7e, 0x23, 0xe0, 0x60, 0x08, 0x53, 0x43, 0x7f, 0xaf, 0x43, 0x12, 0x11, 0x18, 0x90, 0x7e, 0x2c,
-  0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x02, 0x80, 0x03, 0x53, 0x47, 0xfd, 0x90,
-  0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7e, 0x2e, 0xe0, 0x60,
-  0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x01, 0x80, 0x03, 0x53, 0x47, 0xfe, 0x90, 0x7f}},
- {0x0686, 64, { 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7e, 0x32, 0xe0, 0xf5, 0x3b, 0xa3,
-  0xe0, 0x13, 0x92, 0x0e, 0xa3, 0xe0, 0xf5, 0x3d, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x10, 0x80,
-  0x03, 0x53, 0x47, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0,
-  0x90, 0x7e, 0x36, 0xe0, 0x60, 0x32, 0x53, 0x45, 0xbf, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0}},
- {0x06c6, 64, { 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x12, 0x13, 0x58,
-  0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3f, 0xfd, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12,
-  0x20, 0xe4, 0xf5, 0x33, 0xf5, 0x32, 0xd2, 0x08, 0x90, 0x7e, 0x37, 0xe0, 0x60, 0x0f, 0x43, 0x3f,
-  0x02, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x20, 0x75, 0x32, 0x01, 0xd2, 0x08, 0x90, 0x7e}},
- {0x0706, 64, { 0x38, 0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0xe5, 0x41, 0x44, 0x04, 0x90, 0xc0, 0x00,
-  0xf0, 0xd2, 0x00, 0x90, 0x7e, 0x39, 0xe0, 0x60, 0x11, 0x43, 0x45, 0x40, 0x90, 0x7f, 0x98, 0x74,
-  0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x3a, 0xe0, 0x60, 0x0f,
-  0x53, 0x3f, 0xfe, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x20, 0x75, 0x34, 0x01, 0xd2, 0x08}},
- {0x0746, 64, { 0x90, 0x7e, 0x3b, 0xe0, 0x60, 0x0f, 0x43, 0x3f, 0x01, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x20, 0xe4,
-  0xf5, 0x34, 0xd2, 0x08, 0x90, 0x7e, 0x3c, 0xe0, 0x60, 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0,
-  0xe5, 0x41, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x3d, 0xe0, 0x60, 0x02, 0xd2, 0x0c,
-  0x90, 0x7e, 0x3e, 0xe0, 0x60, 0x08, 0x75, 0x35, 0x01, 0xe4, 0xf5, 0x39, 0xd2, 0x08, 0x90}},
- {0x0786, 64, { 0x7e, 0x3f, 0xe0, 0x60, 0x0f, 0x90, 0x7f, 0xd7, 0x74, 0x13, 0xf0, 0x74, 0x33, 0xf0, 0x74, 0x16, 0xf0,
-  0x74, 0x36, 0xf0, 0xe4, 0x90, 0x7f, 0xd1, 0xf0, 0x30, 0x1a, 0x52, 0xe5, 0x39, 0x60, 0x02, 0x15,
-  0x39, 0x30, 0x13, 0x49, 0xe5, 0x13, 0xd3, 0x94, 0x00, 0x40, 0x04, 0x15, 0x13, 0x80, 0x3e, 0x75,
-  0x13, 0x0a, 0x30, 0x1b, 0x02, 0xc2, 0x13, 0x12, 0x13, 0x58, 0xef, 0x54, 0x01, 0xf5, 0x19}},
- {0x07c6, 64, { 0x65, 0x33, 0x60, 0x05, 0x85, 0x19, 0x33, 0xd2, 0x08, 0x12, 0x13, 0x94, 0xef, 0x54, 0x80, 0xf5, 0x19,
-  0x65, 0x2f, 0x60, 0x05, 0x85, 0x19, 0x2f, 0xd2, 0x08, 0x30, 0x0e, 0x11, 0x12, 0x13, 0x94, 0xef,
-  0x54, 0x10, 0xf5, 0x19, 0x65, 0x2e, 0x60, 0x05, 0x85, 0x19, 0x2e, 0xd2, 0x08, 0x30, 0x1a, 0x2a,
-  0x90, 0x7f, 0xd2, 0xe0, 0x20, 0xe1, 0x23, 0x90, 0x7b, 0x40, 0xe0, 0x60, 0x09, 0xe0, 0xf5}},
- {0x0806, 64, { 0x15, 0x90, 0x7b, 0x42, 0xe0, 0xf5, 0x16, 0x90, 0x7b, 0x41, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7, 0x74,
-  0x17, 0xf0, 0x74, 0x37, 0xf0, 0xe4, 0x90, 0x7f, 0xd3, 0xf0, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1,
-  0x03, 0x02, 0x09, 0x28, 0xe5, 0x0a, 0x70, 0x40, 0x30, 0x07, 0x39, 0xe5, 0x38, 0x70, 0x35, 0xc2,
-  0x07, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00}},
- {0x0846, 64, { 0xfa, 0x12, 0x0e, 0xaa, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef,
-  0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x09, 0xf0, 0x75, 0x38,
-  0x10, 0xe4, 0xf5, 0x2c, 0x75, 0x0a, 0x01, 0x22, 0xe5, 0x0a, 0x64, 0x01, 0x70, 0x40, 0x30, 0x08,
-  0x39, 0xe5, 0x39, 0x70, 0x35, 0xc2, 0x08, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x2d}},
- {0x0886, 64, { 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0xaa, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82,
-  0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb, 0x90, 0x7f,
-  0xc3, 0x74, 0x09, 0xf0, 0x75, 0x39, 0x10, 0xe4, 0xf5, 0x35, 0x75, 0x0a, 0x02, 0x22, 0xe5, 0x0a,
-  0x64, 0x02, 0x70, 0x36, 0x30, 0x14, 0x2f, 0xc2, 0x14, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00}},
- {0x08c6, 64, { 0x74, 0x0e, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0xaa, 0xff, 0x74, 0x80, 0x25, 0x18,
-  0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x05, 0xdb,
-  0x90, 0x7f, 0xc3, 0x74, 0x05, 0xf0, 0x75, 0x0a, 0x03, 0x22, 0xe5, 0x15, 0x60, 0x30, 0x15, 0x15,
-  0xe4, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x14, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00}},
- {0x0906, 64, { 0xfa, 0x12, 0x0e, 0xaa, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef,
-  0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4, 0xf5,
-  0x0a, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x0f, 0x02, 0x0a, 0x10, 0x00, 0x0a, 0x84, 0x01, 0x0a,
-  0xf0, 0x03, 0x09, 0x4c, 0x06, 0x0a, 0x03, 0x08, 0x09, 0xfd, 0x09, 0x09, 0xe5, 0x0a, 0x09}},
- {0x0946, 64, { 0xf4, 0x0b, 0x00, 0x00, 0x0b, 0x3f, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x19, 0x14, 0x60, 0x61,
-  0x24, 0x02, 0x60, 0x03, 0x02, 0x09, 0xdb, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90,
-  0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x04, 0x7f, 0x02, 0x80, 0x02,
-  0x7f, 0x03, 0x75, 0x82, 0x82, 0x75, 0x83, 0x19, 0xef, 0xf0, 0x75, 0x82, 0x7b, 0x75, 0x83}},
- {0x0986, 64, { 0x19, 0xf0, 0x75, 0x82, 0x74, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x66, 0x75, 0x83, 0x19, 0xf0, 0x75,
-  0x82, 0x58, 0x75, 0x83, 0x19, 0xf0, 0x90, 0x7f, 0xea, 0xe0, 0x04, 0x75, 0x82, 0x17, 0x75, 0x83,
-  0x19, 0xf0, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x12, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b,
-  0x46, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0f, 0x28, 0xea, 0x49, 0x60, 0x0d, 0xea, 0x90}},
- {0x09c6, 64, { 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01,
-  0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f,
-  0x00, 0xe5, 0x09, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xea,
-  0xe0, 0xf5, 0x09, 0x02, 0x0b, 0x46, 0x12, 0x0b, 0x4e, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0x00}},
- {0x0a06, 64, { 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60,
-  0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2, 0x10, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff,
-  0xa2, 0x16, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74,
-  0x02, 0xf0, 0x02, 0x0b, 0x46, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5}},
- {0x0a46, 64, { 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f,
-  0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83,
-  0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0,
-  0x02, 0x0b, 0x46, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x46, 0x90, 0x7f}},
- {0x0a86, 64, { 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xea, 0xe0,
-  0xb4, 0x01, 0x05, 0xc2, 0x10, 0x02, 0x0b, 0x46, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02,
-  0x0b, 0x46, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff,
-  0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4}},
- {0x0ac6, 64, { 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54,
-  0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x5f,
-  0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60,
-  0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x10, 0x80}},
- {0x0b06, 64, { 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90,
-  0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25,
-  0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90,
-  0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0}},
- {0x0b46, 64, { 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74,
-  0x30, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0xc0, 0xf0, 0x90, 0x7f, 0x9e,
-  0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x18, 0xf0, 0xe4, 0xf5, 0x8e, 0x90, 0x7f, 0xdf, 0x74,
-  0xff, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0xe4, 0xf5, 0x24, 0x75, 0x18, 0x01, 0x7b, 0x00, 0x74}},
- {0x0b86, 64, { 0x24, 0x25, 0x18, 0xf9, 0xe4, 0x34, 0x00, 0xfa, 0xe4, 0x12, 0x0e, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4,
-  0x09, 0xea, 0x75, 0x3a, 0x01, 0xe4, 0xf5, 0x38, 0xf5, 0x13, 0xf5, 0x36, 0xc2, 0x07, 0xc2, 0x0b,
-  0xc2, 0x05, 0xc2, 0x00, 0xc2, 0x09, 0xc2, 0x13, 0xd2, 0x03, 0xd2, 0x01, 0x90, 0x7f, 0x98, 0x74,
-  0x13, 0xf0, 0x75, 0x44, 0x03, 0x90, 0xc0, 0x00, 0x74, 0x03, 0xf0, 0x7f, 0x0c, 0xe4, 0xfd}},
- {0x0bc6, 64, { 0x12, 0x11, 0xd6, 0x7f, 0x10, 0x8f, 0x42, 0x12, 0x10, 0xa6, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x7f,
-  0x01, 0x8f, 0x40, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0,
-  0x75, 0x46, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0x0f, 0xe4, 0xfd, 0x12, 0x11, 0xd6, 0xe4,
-  0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3e, 0x12, 0x11, 0xd6, 0x90, 0x7f, 0x98, 0x74, 0x11}},
- {0x0c06, 64, { 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x11, 0xd6, 0x7f, 0x01, 0x12, 0x12,
-  0x8f, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x11, 0xd6, 0x7f, 0x13, 0x7d, 0x01, 0x12, 0x11, 0xd6, 0x20,
-  0x1b, 0x03, 0x02, 0x0c, 0xd5, 0x75, 0x2d, 0x01, 0x75, 0x18, 0x01, 0x7b, 0x00, 0x74, 0x2d, 0x25,
-  0x18, 0xf9, 0xe4, 0x34, 0x00, 0xfa, 0xe4, 0x12, 0x0e, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4}},
- {0x0c46, 64, { 0x09, 0xea, 0x75, 0x3b, 0x01, 0xe4, 0xf5, 0x39, 0xf5, 0x13, 0xf5, 0x37, 0xc2, 0x08, 0xc2, 0x0c, 0xc2,
-  0x06, 0xc2, 0x00, 0xc2, 0x0a, 0xc2, 0x13, 0xd2, 0x04, 0xd2, 0x02, 0x90, 0x7f, 0x98, 0x74, 0x0b,
+ {0x0043,  3, { 0x02, 0x13, 0x00}},
+ {0x0000,  3, { 0x02, 0x0e, 0x0e}},
+ {0x0106, 64, { 0x60, 0x58, 0xb4, 0x80, 0x03, 0x43, 0x36, 0x02, 0xe5, 0x36, 0x30, 0xe7, 0x26, 0xe5, 0x19, 0xd3, 0x94,
+  0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08, 0x7e, 0x7e, 0x7f, 0x80, 0x75, 0x0c, 0x7e,
+  0x75, 0x0d, 0x80, 0xaf, 0x36, 0x12, 0x0f, 0x59, 0xe5, 0x19, 0x25, 0xe0, 0x90, 0x7f, 0xb7, 0xf0,
+  0x80, 0x27, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75, 0x19, 0x3f, 0x85, 0x19, 0x08}},
+ {0x0146, 64, { 0x90, 0x7e, 0x80, 0xe5, 0x36, 0xf0, 0x7e, 0x7e, 0x7f, 0x81, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x81, 0x12,
+  0x0c, 0xed, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xb7, 0xf0, 0x90, 0x7f, 0xce, 0xe0, 0x30, 0xe1, 0x06,
+  0x20, 0x05, 0x03, 0x02, 0x03, 0xc1, 0xc2, 0x05, 0xe4, 0xf5, 0x18, 0x74, 0x40, 0x25, 0x18, 0xf5,
+  0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18, 0x7c, 0x00, 0x7b, 0x01, 0x7a}},
+ {0x0186, 64, { 0x7e, 0x79, 0x00, 0x24, 0x00, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef, 0x12, 0x0e, 0xe0, 0x05, 0x18, 0xe5,
+  0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x00, 0xe0, 0x60, 0x68, 0x90, 0x7e, 0x03, 0xe0, 0x60, 0x24,
+  0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x11, 0xbf, 0x7f, 0x03, 0x7d, 0xcd, 0x12, 0x11, 0xbf, 0x43, 0x46,
+  0x80, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0xe4, 0x90}},
+ {0x01c6, 64, { 0x7e, 0x13, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x01, 0xe0, 0xff, 0x12, 0x10, 0x43, 0x90, 0x7e, 0x02, 0xe0,
+  0xff, 0x12, 0x10, 0x69, 0x7f, 0x01, 0x90, 0x7e, 0x11, 0xe0, 0xfd, 0x12, 0x11, 0xbf, 0x7f, 0x03,
+  0x7d, 0x07, 0x12, 0x11, 0xbf, 0x43, 0x46, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0,
+  0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40, 0x44, 0x06, 0x90}},
+ {0x0206, 64, { 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x03, 0xe0, 0x70, 0x06, 0x90, 0x7e, 0x13, 0xe0, 0x70, 0x08, 0xe4, 0x90,
+  0x7e, 0x13, 0xf0, 0x75, 0x25, 0xff, 0x90, 0x7e, 0x05, 0xe0, 0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f,
+  0xf5, 0x44, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x44, 0xf0, 0x90, 0x7e,
+  0x07, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x42, 0x80, 0x80, 0x03, 0x53, 0x42}},
+ {0x0246, 64, { 0x7f, 0x53, 0x42, 0xfc, 0x90, 0x7e, 0x09, 0xe0, 0x60, 0x11, 0x43, 0x42, 0x02, 0xa3, 0xe0, 0xff, 0x12,
+  0x10, 0xb5, 0x90, 0x7e, 0x0b, 0xe0, 0xff, 0x12, 0x10, 0xdb, 0xaf, 0x42, 0x12, 0x10, 0x8f, 0x90,
+  0x7e, 0x03, 0xe0, 0x60, 0x08, 0x53, 0x42, 0x7f, 0xaf, 0x42, 0x12, 0x10, 0x8f, 0x90, 0x7e, 0x0c,
+  0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x02, 0x80, 0x03, 0x53, 0x46, 0xfd}},
+ {0x0286, 64, { 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x0e, 0xe0, 0x60,
+  0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x01, 0x80, 0x03, 0x53, 0x46, 0xfe, 0x90, 0x7f, 0x98,
+  0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x12, 0xe0, 0xf5, 0x3a, 0xa3,
+  0xe0, 0x13, 0x92, 0x0d, 0xa3, 0xe0, 0xf5, 0x3c, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x10}},
+ {0x02c6, 64, { 0x80, 0x03, 0x53, 0x46, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0,
+  0x90, 0x7e, 0x16, 0xe0, 0x60, 0x32, 0x53, 0x44, 0xbf, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5,
+  0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x12, 0x12, 0xed,
+  0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3e, 0xfd, 0xe4, 0xff, 0xad, 0x3e, 0x12}},
+ {0x0306, 64, { 0x11, 0xbf, 0xe4, 0xf5, 0x2a, 0xf5, 0x29, 0xd2, 0x07, 0x90, 0x7e, 0x17, 0xe0, 0x60, 0x0f, 0x43, 0x3e,
+  0x02, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xbf, 0x75, 0x29, 0x01, 0xd2, 0x07, 0x90, 0x7e, 0x18,
+  0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40, 0x44, 0x04, 0x90, 0xc0, 0x00,
+  0xf0, 0xd2, 0x00, 0x90, 0x7e, 0x19, 0xe0, 0x60, 0x11, 0x43, 0x44, 0x40, 0x90, 0x7f, 0x98}},
+ {0x0346, 64, { 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1a, 0xe0, 0x60, 0x0f,
+  0x53, 0x3e, 0xfe, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xbf, 0x75, 0x2b, 0x01, 0xd2, 0x07, 0x90,
+  0x7e, 0x1b, 0xe0, 0x60, 0x0f, 0x43, 0x3e, 0x01, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xbf, 0xe4,
+  0xf5, 0x2b, 0xd2, 0x07, 0x90, 0x7e, 0x1c, 0xe0, 0x60, 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x12}},
+ {0x0386, 64, { 0xf0, 0xe5, 0x40, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1d, 0xe0, 0x60, 0x02, 0xd2, 0x0b,
+  0x90, 0x7e, 0x1e, 0xe0, 0x60, 0x08, 0x75, 0x2c, 0x01, 0xe4, 0xf5, 0x38, 0xd2, 0x07, 0x90, 0x7e,
+  0x1f, 0xe0, 0x60, 0x11, 0x90, 0x7f, 0xd7, 0x74, 0x11, 0xf0, 0x74, 0x31, 0xf0, 0x74, 0x15, 0xf0,
+  0x74, 0x35, 0xf0, 0xd2, 0x03, 0xe4, 0x90, 0x7f, 0xcf, 0xf0, 0x30, 0x1a, 0x52, 0xe5, 0x38}},
+ {0x03c6, 64, { 0x60, 0x02, 0x15, 0x38, 0x20, 0x13, 0x49, 0xe5, 0x13, 0xd3, 0x94, 0x00, 0x40, 0x04, 0x15, 0x13, 0x80,
+  0x3e, 0x75, 0x13, 0x0a, 0x30, 0x1b, 0x02, 0xd2, 0x13, 0x12, 0x12, 0xed, 0xef, 0x54, 0x01, 0xf5,
+  0x19, 0x65, 0x2a, 0x60, 0x05, 0x85, 0x19, 0x2a, 0xd2, 0x07, 0x12, 0x13, 0x3f, 0xef, 0x54, 0x80,
+  0xf5, 0x19, 0x65, 0x26, 0x60, 0x05, 0x85, 0x19, 0x26, 0xd2, 0x07, 0x30, 0x0d, 0x11, 0x12}},
+ {0x0406, 64, { 0x13, 0x3f, 0xef, 0x54, 0x10, 0xf5, 0x19, 0x65, 0x25, 0x60, 0x05, 0x85, 0x19, 0x25, 0xd2, 0x07, 0x20,
+  0x1b, 0x03, 0x02, 0x07, 0xec, 0x30, 0x0a, 0x18, 0x12, 0x13, 0x7b, 0xef, 0xc3, 0x95, 0x3d, 0x40,
+  0x03, 0x02, 0x04, 0xae, 0x90, 0x7f, 0xc1, 0x74, 0x01, 0xf0, 0xc2, 0x0a, 0xc2, 0x00, 0x80, 0x77,
+  0x30, 0x04, 0x3b, 0x90, 0x7f, 0xca, 0xe0, 0x20, 0xe1, 0x6d, 0x12, 0x13, 0x7b, 0xef, 0xc3}},
+ {0x0446, 64, { 0x94, 0x40, 0x50, 0x64, 0x90, 0x7d, 0x40, 0xe0, 0x13, 0x92, 0x0a, 0x90, 0x7f, 0xcb, 0xe0, 0x14, 0xf5,
+  0x19, 0x20, 0x00, 0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7d, 0x7f, 0x41, 0x75, 0x0c, 0x7d, 0x75,
+  0x0d, 0x41, 0x12, 0x0d, 0x12, 0xc2, 0x04, 0xe4, 0x90, 0x7f, 0xcb, 0xf0, 0x80, 0x39, 0x90, 0x7f,
+  0xcc, 0xe0, 0x20, 0xe1, 0x32, 0x12, 0x13, 0x7b, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x29, 0x90}},
+ {0x0486, 64, { 0x7c, 0xc0, 0xe0, 0x13, 0x92, 0x0a, 0x90, 0x7f, 0xcd, 0xe0, 0x14, 0xf5, 0x19, 0x20, 0x00, 0x11, 0x60,
+  0x0f, 0xf5, 0x08, 0x7e, 0x7c, 0x7f, 0xc1, 0x75, 0x0c, 0x7c, 0x75, 0x0d, 0xc1, 0x12, 0x0d, 0x12,
+  0xd2, 0x04, 0xe4, 0x90, 0x7f, 0xcd, 0xf0, 0x90, 0x7f, 0xba, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x05,
+  0x36, 0x12, 0x12, 0x2e, 0x8f, 0x19, 0x12, 0x13, 0x87, 0x8f, 0x37, 0xe5, 0x19, 0xc3, 0x95}},
+ {0x04c6, 64, { 0x3b, 0x50, 0x0f, 0x12, 0x13, 0x63, 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x37, 0x20, 0xe7, 0x03, 0x30, 0x0c,
+  0x5e, 0xc2, 0x0c, 0xe5, 0x19, 0x60, 0x58, 0xb4, 0x80, 0x03, 0x43, 0x37, 0x02, 0xe5, 0x37, 0x30,
+  0xe7, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08, 0x7e,
+  0x7d, 0x7f, 0x80, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0x80, 0xaf, 0x37, 0x12, 0x0f, 0x92, 0xe5}},
+ {0x0506, 64, { 0x19, 0x25, 0xe0, 0x90, 0x7f, 0xbb, 0xf0, 0x80, 0x27, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75,
+  0x19, 0x3f, 0x85, 0x19, 0x08, 0x90, 0x7d, 0x80, 0xe5, 0x37, 0xf0, 0x7e, 0x7d, 0x7f, 0x81, 0x75,
+  0x0c, 0x7d, 0x75, 0x0d, 0x81, 0x12, 0x0d, 0x37, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xbb, 0xf0, 0x90,
+  0x7f, 0xd0, 0xe0, 0x30, 0xe1, 0x06, 0x20, 0x06, 0x03, 0x02, 0x07, 0x97, 0xc2, 0x06, 0xe4}},
+ {0x0546, 64, { 0xf5, 0x18, 0x74, 0xc0, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18,
+  0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e, 0x79, 0x20, 0x24, 0x20, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef,
+  0x12, 0x0e, 0xe0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x20, 0xe0, 0x60, 0x68,
+  0x90, 0x7e, 0x23, 0xe0, 0x60, 0x24, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x12, 0x09, 0x7f, 0x03}},
+ {0x0586, 64, { 0x7d, 0xcd, 0x12, 0x12, 0x09, 0x43, 0x47, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00,
+  0xe5, 0x47, 0xf0, 0xe4, 0x90, 0x7e, 0x33, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x21, 0xe0, 0xff, 0x12,
+  0x11, 0x27, 0x90, 0x7e, 0x22, 0xe0, 0xff, 0x12, 0x11, 0x4d, 0x7f, 0x01, 0x90, 0x7e, 0x31, 0xe0,
+  0xfd, 0x12, 0x12, 0x09, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x12, 0x09, 0x43, 0x47, 0x80, 0x90}},
+ {0x05c6, 64, { 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0,
+  0xe5, 0x41, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x23, 0xe0, 0x70, 0x06, 0x90, 0x7e,
+  0x33, 0xe0, 0x70, 0x08, 0xe4, 0x90, 0x7e, 0x33, 0xf0, 0x75, 0x2e, 0xff, 0x90, 0x7e, 0x25, 0xe0,
+  0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f, 0xf5, 0x45, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90}},
+ {0x0606, 64, { 0xc0, 0x00, 0xe5, 0x45, 0xf0, 0x90, 0x7e, 0x27, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x43,
+  0x80, 0x80, 0x03, 0x53, 0x43, 0x7f, 0x53, 0x43, 0xfc, 0x90, 0x7e, 0x29, 0xe0, 0x60, 0x11, 0x43,
+  0x43, 0x02, 0xa3, 0xe0, 0xff, 0x12, 0x11, 0x73, 0x90, 0x7e, 0x2b, 0xe0, 0xff, 0x12, 0x11, 0x99,
+  0xaf, 0x43, 0x12, 0x11, 0x01, 0x90, 0x7e, 0x23, 0xe0, 0x60, 0x08, 0x53, 0x43, 0x7f, 0xaf}},
+ {0x0646, 64, { 0x43, 0x12, 0x11, 0x01, 0x90, 0x7e, 0x2c, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x02,
+  0x80, 0x03, 0x53, 0x47, 0xfd, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47,
+  0xf0, 0x90, 0x7e, 0x2e, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x01, 0x80, 0x03,
+  0x53, 0x47, 0xfe, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0}},
+ {0x0686, 64, { 0x90, 0x7e, 0x32, 0xe0, 0xf5, 0x3b, 0xa3, 0xe0, 0x13, 0x92, 0x0e, 0xa3, 0xe0, 0xf5, 0x3d, 0xa3, 0xe0,
+  0x60, 0x05, 0x43, 0x47, 0x10, 0x80, 0x03, 0x53, 0x47, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0,
+  0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7e, 0x36, 0xe0, 0x60, 0x32, 0x53, 0x45, 0xbf, 0x90,
+  0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f}},
+ {0x06c6, 64, { 0x98, 0x74, 0x09, 0xf0, 0x12, 0x13, 0x57, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3f, 0xfd,
+  0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x09, 0xe4, 0xf5, 0x33, 0xf5, 0x32, 0xd2, 0x08, 0x90, 0x7e,
+  0x37, 0xe0, 0x60, 0x0f, 0x43, 0x3f, 0x02, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x09, 0x75, 0x32,
+  0x01, 0xd2, 0x08, 0x90, 0x7e, 0x38, 0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0}},
+ {0x0706, 64, { 0xe5, 0x41, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0, 0xd2, 0x00, 0x90, 0x7e, 0x39, 0xe0, 0x60, 0x11, 0x43,
+  0x45, 0x40, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0,
+  0x90, 0x7e, 0x3a, 0xe0, 0x60, 0x0f, 0x53, 0x3f, 0xfe, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x09,
+  0x75, 0x34, 0x01, 0xd2, 0x08, 0x90, 0x7e, 0x3b, 0xe0, 0x60, 0x0f, 0x43, 0x3f, 0x01, 0xe4}},
+ {0x0746, 64, { 0xff, 0xad, 0x3f, 0x12, 0x12, 0x09, 0xe4, 0xf5, 0x34, 0xd2, 0x08, 0x90, 0x7e, 0x3c, 0xe0, 0x60, 0x0e,
+  0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0xe5, 0x41, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e,
+  0x3d, 0xe0, 0x60, 0x02, 0xd2, 0x0c, 0x90, 0x7e, 0x3e, 0xe0, 0x60, 0x08, 0x75, 0x35, 0x01, 0xe4,
+  0xf5, 0x39, 0xd2, 0x08, 0x90, 0x7e, 0x3f, 0xe0, 0x60, 0x11, 0x90, 0x7f, 0xd7, 0x74, 0x13}},
+ {0x0786, 64, { 0xf0, 0x74, 0x33, 0xf0, 0x74, 0x16, 0xf0, 0x74, 0x36, 0xf0, 0xd2, 0x04, 0xe4, 0x90, 0x7f, 0xd1, 0xf0,
+  0x30, 0x1a, 0x52, 0xe5, 0x39, 0x60, 0x02, 0x15, 0x39, 0x30, 0x13, 0x49, 0xe5, 0x13, 0xd3, 0x94,
+  0x00, 0x40, 0x04, 0x15, 0x13, 0x80, 0x3e, 0x75, 0x13, 0x0a, 0x30, 0x1b, 0x02, 0xc2, 0x13, 0x12,
+  0x13, 0x57, 0xef, 0x54, 0x01, 0xf5, 0x19, 0x65, 0x33, 0x60, 0x05, 0x85, 0x19, 0x33, 0xd2}},
+ {0x07c6, 64, { 0x08, 0x12, 0x13, 0x93, 0xef, 0x54, 0x80, 0xf5, 0x19, 0x65, 0x2f, 0x60, 0x05, 0x85, 0x19, 0x2f, 0xd2,
+  0x08, 0x30, 0x0e, 0x11, 0x12, 0x13, 0x93, 0xef, 0x54, 0x10, 0xf5, 0x19, 0x65, 0x2e, 0x60, 0x05,
+  0x85, 0x19, 0x2e, 0xd2, 0x08, 0x30, 0x1a, 0x2a, 0x90, 0x7f, 0xd2, 0xe0, 0x20, 0xe1, 0x23, 0x90,
+  0x7b, 0x40, 0xe0, 0x60, 0x09, 0xe0, 0xf5, 0x15, 0x90, 0x7b, 0x42, 0xe0, 0xf5, 0x16, 0x90}},
+ {0x0806, 64, { 0x7b, 0x41, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7, 0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0xe4, 0x90, 0x7f,
+  0xd3, 0xf0, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x09, 0x20, 0xe5, 0x0a, 0x70, 0x40,
+  0x30, 0x07, 0x39, 0xe5, 0x38, 0x70, 0x35, 0xc2, 0x07, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74,
+  0x24, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0x9a, 0xff, 0x74, 0x80, 0x25}},
+ {0x0846, 64, { 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb,
+  0x90, 0x7f, 0xc3, 0x74, 0x09, 0xf0, 0x75, 0x38, 0x10, 0xe4, 0xf5, 0x2c, 0x75, 0x0a, 0x01, 0x22,
+  0xe5, 0x0a, 0x64, 0x01, 0x70, 0x40, 0x30, 0x08, 0x39, 0xe5, 0x39, 0x70, 0x35, 0xc2, 0x08, 0xf5,
+  0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x2d, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12}},
+ {0x0886, 64, { 0x0e, 0x9a, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05,
+  0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x09, 0xf0, 0x75, 0x39, 0x10, 0xe4,
+  0xf5, 0x35, 0x75, 0x0a, 0x02, 0x22, 0xe5, 0x0a, 0x64, 0x02, 0x70, 0x36, 0x30, 0x14, 0x2f, 0xc2,
+  0x14, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x0e, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00}},
+ {0x08c6, 64, { 0xfa, 0x12, 0x0e, 0x9a, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef,
+  0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x05, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x05, 0xf0, 0x75, 0x0a,
+  0x03, 0x22, 0xe5, 0x15, 0x60, 0x30, 0x15, 0x15, 0xe4, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74,
+  0x14, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0x9a, 0xff, 0x74, 0x80, 0x25}},
+ {0x0906, 64, { 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x03, 0xdb,
+  0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4, 0xf5, 0x0a, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x0e,
+  0xf2, 0x0a, 0x08, 0x00, 0x0a, 0x7c, 0x01, 0x0a, 0xe8, 0x03, 0x09, 0x44, 0x06, 0x09, 0xfb, 0x08,
+  0x09, 0xf5, 0x09, 0x09, 0xdd, 0x0a, 0x09, 0xec, 0x0b, 0x00, 0x00, 0x0b, 0x37, 0x90, 0x7f}},
+ {0x0946, 64, { 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x19, 0x14, 0x60, 0x61, 0x24, 0x02, 0x60, 0x03, 0x02, 0x09, 0xd3, 0x74,
+  0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f,
+  0xea, 0xe0, 0x70, 0x04, 0x7f, 0x02, 0x80, 0x02, 0x7f, 0x03, 0x75, 0x82, 0x82, 0x75, 0x83, 0x19,
+  0xef, 0xf0, 0x75, 0x82, 0x7b, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x74, 0x75, 0x83, 0x19}},
+ {0x0986, 64, { 0xf0, 0x75, 0x82, 0x66, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x58, 0x75, 0x83, 0x19, 0xf0, 0x90, 0x7f,
+  0xea, 0xe0, 0x04, 0x75, 0x82, 0x17, 0x75, 0x83, 0x19, 0xf0, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0,
+  0x74, 0x12, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0f,
+  0x18, 0xea, 0x49, 0x60, 0x0d, 0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0}},
+ {0x09c6, 64, { 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xb4, 0xe0,
+  0x44, 0x01, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0x00, 0xe5, 0x09, 0xf0, 0x90, 0x7f, 0xb5, 0x74,
+  0x01, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x09, 0x02, 0x0b, 0x3e, 0x12, 0x0b,
+  0x46, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02}},
+ {0x0a06, 64, { 0x0b, 0x3e, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b,
+  0xa2, 0x10, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x16, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00,
+  0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x3e, 0xe4, 0x90, 0x7f,
+  0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f}},
+ {0x0a46, 64, { 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24,
+  0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4,
+  0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xb4, 0xe0, 0x44,
+  0x01, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02}},
+ {0x0a86, 64, { 0x60, 0x03, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x10, 0x02, 0x0b, 0x3e,
+  0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x3e, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38,
+  0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f,
+  0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f}},
+ {0x0ac6, 64, { 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f,
+  0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80,
+  0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea,
+  0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x10, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0}},
+ {0x0b06, 64, { 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4,
+  0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f,
+  0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07,
+  0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22}},
+ {0x0b46, 64, { 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0, 0x90,
+  0x7f, 0x95, 0x74, 0xc0, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x18,
+  0xf0, 0xe4, 0xf5, 0x8e, 0x90, 0x7f, 0xdf, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0xe4, 0xf5,
+  0x24, 0x75, 0x18, 0x01, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x18, 0xf9, 0xe4, 0x34, 0x00, 0xfa}},
+ {0x0b86, 64, { 0xe4, 0x12, 0x0e, 0xe0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xea, 0x75, 0x3a, 0x01, 0xe4, 0xf5, 0x38,
+  0xf5, 0x13, 0xf5, 0x36, 0xc2, 0x07, 0xc2, 0x0b, 0xc2, 0x05, 0xc2, 0x00, 0xc2, 0x09, 0xc2, 0x13,
+  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x75, 0x44, 0x03, 0x90, 0xc0, 0x00, 0x74, 0x03, 0xf0, 0x7f,
+  0x0c, 0xe4, 0xfd, 0x12, 0x11, 0xbf, 0x7f, 0x10, 0x8f, 0x42, 0x12, 0x10, 0x8f, 0x90, 0x7f}},
+ {0x0bc6, 64, { 0x98, 0x74, 0x12, 0xf0, 0x7f, 0x01, 0x8f, 0x40, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f,
+  0x98, 0x74, 0x14, 0xf0, 0x75, 0x46, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0x0f, 0xe4, 0xfd,
+  0x12, 0x11, 0xbf, 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3e, 0x12, 0x11, 0xbf, 0x90, 0x7f,
+  0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x11}},
+ {0x0c06, 64, { 0xbf, 0x7f, 0x01, 0x12, 0x12, 0x78, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x11, 0xbf, 0x7f, 0x13, 0x7d, 0x01,
+  0x12, 0x11, 0xbf, 0x20, 0x1b, 0x03, 0x02, 0x0c, 0xc5, 0x75, 0x2d, 0x01, 0x75, 0x18, 0x01, 0x7b,
+  0x00, 0x74, 0x2d, 0x25, 0x18, 0xf9, 0xe4, 0x34, 0x00, 0xfa, 0xe4, 0x12, 0x0e, 0xe0, 0x05, 0x18,
+  0xe5, 0x18, 0xb4, 0x09, 0xea, 0x75, 0x3b, 0x01, 0xe4, 0xf5, 0x39, 0xf5, 0x13, 0xf5, 0x37}},
+ {0x0c46, 64, { 0xc2, 0x08, 0xc2, 0x0c, 0xc2, 0x06, 0xc2, 0x00, 0xc2, 0x0a, 0xc2, 0x13, 0x90, 0x7f, 0x98, 0x74, 0x0b,
   0xf0, 0x75, 0x45, 0x03, 0x90, 0xc0, 0x00, 0x74, 0x03, 0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x12,
-  0x20, 0x7f, 0x10, 0x8f, 0x43, 0x12, 0x11, 0x18, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x7f}},
- {0x0c86, 64, { 0x01, 0x8f, 0x41, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x75,
-  0x47, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0x0f, 0xe4, 0xfd, 0x12, 0x12, 0x20, 0xe4, 0xff,
-  0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3f, 0x12, 0x12, 0x20, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90,
-  0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x12, 0x20, 0x7f, 0x01, 0x12, 0x12}},
- {0x0cc6, 64, { 0xb0, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x12, 0x20, 0x7f, 0x13, 0x7d, 0x01, 0x12, 0x12, 0x20, 0xd2, 0x12,
-  0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5,
+  0x09, 0x7f, 0x10, 0x8f, 0x43, 0x12, 0x11, 0x01, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x7f, 0x01,
+  0x8f, 0x41, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0}},
+ {0x0c86, 64, { 0x75, 0x47, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0x0f, 0xe4, 0xfd, 0x12, 0x12, 0x09, 0xe4, 0xff,
+  0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3f, 0x12, 0x12, 0x09, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90,
+  0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x12, 0x09, 0x7f, 0x01, 0x12, 0x12, 0x99,
+  0x7f, 0x03, 0x7d, 0x07, 0x12, 0x12, 0x09, 0x7f, 0x13, 0x7d, 0x01, 0x12, 0x12, 0x09, 0xd2}},
+ {0x0cc6, 64, { 0x12, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5,
   0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05,
-  0x86, 0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x08, 0xe5}},
- {0x0d06, 64, { 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86,
-  0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08,
+  0x86, 0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x08, 0xe5, 0x0d,
+  0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05}},
+ {0x0d06, 64, { 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08,
   0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90,
-  0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05, 0x86, 0xdf, 0xf7, 0xd2, 0xaf}},
- {0x0d46, 64, { 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83,
-  0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7,
+  0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05, 0x86, 0xdf, 0xf7, 0xd2, 0xaf, 0x22,
+  0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5}},
+ {0x0d46, 64, { 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7,
   0x05, 0x86, 0xd2, 0xaf, 0x22, 0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5,
-  0x82, 0x45, 0x83, 0x70, 0xf9, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87}},
- {0x0d86, 64, { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xd2, 0x19, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02, 0xf0, 0x90,
-  0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92, 0x10, 0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0, 0xd2, 0xe8, 0x43,
+  0x82, 0x45, 0x83, 0x70, 0xf9, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xd2, 0x19, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02, 0xf0}},
+ {0x0d86, 64, { 0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92, 0x10, 0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0, 0xd2, 0xe8, 0x43,
   0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab, 0x74,
-  0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f}},
- {0x0dc6, 64, { 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0x1a, 0x12,
-  0x12, 0x6a, 0xc2, 0x11, 0xe4, 0xf5, 0x0b, 0xf5, 0x13, 0xc2, 0x17, 0xc2, 0x12, 0x90, 0x7f, 0xa1,
+  0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaf,
+  0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0x1a}},
+ {0x0dc6, 64, { 0x12, 0x12, 0x53, 0xc2, 0x11, 0xe4, 0xf5, 0x0b, 0xf5, 0x13, 0xc2, 0x17, 0xc2, 0x12, 0x90, 0x7f, 0xa1,
   0x04, 0xf0, 0x90, 0x7f, 0xd8, 0xe0, 0x65, 0x17, 0x60, 0x10, 0x30, 0x12, 0x05, 0xd2, 0x1a, 0x12,
-  0x00, 0x46, 0x90, 0x7f, 0xd8, 0xe0, 0xf5, 0x17, 0x80, 0x08, 0x30, 0x12, 0x05, 0xc2, 0x1a}},
- {0x0e06, 64, { 0x12, 0x00, 0x46, 0x30, 0x11, 0x07, 0xc2, 0x11, 0x12, 0x09, 0x29, 0x80, 0xd6, 0x30, 0x18, 0xd3, 0xc2,
-  0x18, 0x12, 0x13, 0xa0, 0x80, 0xcc, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x47,
-  0x02, 0x0e, 0x65, 0x02, 0x0d, 0x8d, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6,
-  0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24}},
- {0x0e46, 64, { 0x0c, 0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01,
-  0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x12,
-  0xd1, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f,
-  0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40}},
- {0x0e86, 64, { 0xb8, 0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca,
-  0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde,
+  0x00, 0x46, 0x90, 0x7f, 0xd8, 0xe0, 0xf5, 0x17, 0x80, 0x08, 0x30, 0x12, 0x05, 0xc2, 0x1a, 0x12,
+  0x00, 0x46, 0x30, 0x11, 0x07, 0xc2, 0x11, 0x12, 0x09, 0x21, 0x80, 0xd6, 0x30, 0x18, 0xd3}},
+ {0x0e06, 64, { 0xc2, 0x18, 0x12, 0x13, 0x9f, 0x80, 0xcc, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x47,
+  0x02, 0x0e, 0x55, 0x02, 0x0d, 0x7d, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6,
+  0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c,
+  0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80}},
+ {0x0e46, 64, { 0x01, 0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x12,
+  0xba, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f,
+  0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8,
+  0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8}},
+ {0x0e86, 64, { 0xca, 0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde,
   0xe7, 0x80, 0xbe, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22,
-  0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x0c}},
- {0x0ec6, 64, { 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9, 0x25, 0x82,
-  0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82, 0x29, 0xf5,
+  0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x0c, 0xe5,
+  0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9, 0x25}},
+ {0x0ec6, 64, { 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82, 0x29, 0xf5,
   0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83,
-  0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xd0, 0x83, 0xd0, 0x82}},
- {0x0f06, 64, { 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01, 0x93,
-  0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3, 0x80,
+  0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xd0, 0x83, 0xd0, 0x82, 0xf8,
+  0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01}},
+ {0x0f06, 64, { 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3, 0x80,
   0xdf, 0x8f, 0x18, 0xe4, 0xf5, 0x19, 0x75, 0x1a, 0xff, 0x75, 0x1b, 0x19, 0x75, 0x1c, 0x86, 0xab,
-  0x1a, 0xaa, 0x1b, 0xa9, 0x1c, 0x90, 0x00, 0x01, 0x12, 0x0e, 0xc3, 0xb4, 0x03, 0x1d, 0xaf}},
- {0x0f46, 64, { 0x19, 0x05, 0x19, 0xef, 0xb5, 0x18, 0x01, 0x22, 0x12, 0x0e, 0xaa, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a,
-  0xa9, 0x07, 0x75, 0x1a, 0xff, 0xf5, 0x1b, 0x89, 0x1c, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79,
+  0x1a, 0xaa, 0x1b, 0xa9, 0x1c, 0x90, 0x00, 0x01, 0x12, 0x0e, 0xb3, 0xb4, 0x03, 0x1d, 0xaf, 0x19,
+  0x05, 0x19, 0xef, 0xb5, 0x18, 0x01, 0x22, 0x12, 0x0e, 0x9a, 0x7e, 0x00, 0x29, 0xff, 0xee}},
+ {0x0f46, 64, { 0x3a, 0xa9, 0x07, 0x75, 0x1a, 0xff, 0xf5, 0x1b, 0x89, 0x1c, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79,
   0x00, 0x22, 0x8f, 0x1a, 0x05, 0x0d, 0xe5, 0x0d, 0xae, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5,
-  0x82, 0x8e, 0x83, 0xe5, 0x1a, 0xf0, 0x12, 0x00, 0x36, 0x05, 0x0d, 0xe5, 0x0d, 0xac, 0x0c}},
- {0x0f86, 64, { 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x0a,
-  0x12, 0x13, 0x34, 0x8f, 0x1a, 0xef, 0x42, 0x36, 0x80, 0xca, 0x22, 0x8f, 0x1a, 0x05, 0x0d, 0xe5,
+  0x82, 0x8e, 0x83, 0xe5, 0x1a, 0xf0, 0x12, 0x00, 0x36, 0x05, 0x0d, 0xe5, 0x0d, 0xac, 0x0c, 0x70,
+  0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60}},
+ {0x0f86, 64, { 0x0a, 0x12, 0x13, 0x33, 0x8f, 0x1a, 0xef, 0x42, 0x36, 0x80, 0xca, 0x22, 0x8f, 0x1a, 0x05, 0x0d, 0xe5,
   0x0d, 0xae, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x1a, 0xf0, 0x12,
-  0x13, 0x4c, 0x05, 0x0d, 0xe5, 0x0d, 0xac, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82}},
- {0x0fc6, 64, { 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x0a, 0x12, 0x13, 0x88, 0x8f, 0x1a, 0xef, 0x42,
-  0x37, 0x80, 0xca, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86,
-  0x75, 0x86, 0x00, 0x30, 0x15, 0x04, 0xc2, 0x15, 0x80, 0x02, 0xd2, 0x18, 0x53, 0x91, 0xef, 0x90,
-  0x7f, 0xab, 0x74, 0x08, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83}},
- {0x1006, 64, { 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86,
-  0x00, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0,
-  0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83,
-  0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x11, 0x53, 0x91}},
- {0x1046, 64, { 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83,
-  0xd0, 0xe0, 0x32, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90,
-  0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0,
-  0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0}},
- {0x1086, 64, { 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0,
-  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90,
-  0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12,
-  0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54}},
- {0x10c6, 64, { 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf,
-  0xf0, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74,
-  0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13,
-  0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90, 0xc0}},
- {0x1106, 64, { 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0,
-  0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98,
-  0x74, 0x0a, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45,
-  0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0}},
- {0x1146, 64, { 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f,
-  0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98,
-  0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90,
-  0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90}},
- {0x1186, 64, { 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90,
-  0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0,
-  0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90,
-  0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0e, 0xf0, 0x90, 0xc0, 0x00, 0xef}},
- {0x11c6, 64, { 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90,
-  0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98,
-  0x74, 0x17, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90, 0xc0,
-  0x00, 0xed, 0xf0, 0x22, 0x12, 0x13, 0x1c, 0x8f, 0x1a, 0x12, 0x13, 0x1c, 0x8f, 0x1b, 0xe5}},
- {0x1206, 64, { 0x1a, 0x65, 0x1b, 0x60, 0x12, 0x12, 0x13, 0x1c, 0x8f, 0x1a, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x07, 0x12,
-  0x13, 0x1c, 0x8f, 0x1b, 0x80, 0xe8, 0xaf, 0x1a, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5,
-  0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0f, 0xf0, 0x90, 0xc0, 0x00,
-  0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22, 0x12}},
- {0x1246, 64, { 0x13, 0x70, 0x8f, 0x1a, 0x12, 0x13, 0x70, 0x8f, 0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x12, 0x12, 0x13,
-  0x70, 0x8f, 0x1a, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x07, 0x12, 0x13, 0x70, 0x8f, 0x1b, 0x80, 0xe8,
-  0xaf, 0x1a, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x1a,
-  0x04, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x12, 0xed, 0x90, 0x7f, 0xd6}},
- {0x1286, 64, { 0xe0, 0x54, 0xf7, 0xf0, 0xe0, 0x44, 0x04, 0xf0, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5, 0x3e, 0x54, 0x7f,
-  0xfd, 0x12, 0x11, 0xd6, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4,
-  0xe5, 0x3e, 0x44, 0x80, 0xfd, 0x12, 0x11, 0xd6, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5, 0x3f, 0x54,
-  0x7f, 0xfd, 0x12, 0x12, 0x20, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xee}},
- {0x12c6, 64, { 0xf0, 0xe4, 0xe5, 0x3f, 0x44, 0x80, 0xfd, 0x12, 0x12, 0x20, 0x22, 0x05, 0x0e, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x03, 0x14, 0x03, 0x00, 0x00, 0xc1, 0x11, 0xc1, 0x18, 0xc1, 0x95, 0xc1, 0x10, 0xc1, 0x16,
-  0x01, 0x0a, 0x00, 0xc1, 0x9b, 0x00, 0x8e, 0x18, 0x8f, 0x19, 0xe5, 0x19, 0x15, 0x19, 0xae, 0x18,
-  0x70, 0x02, 0x15, 0x18, 0x4e, 0x60, 0x05, 0x12, 0x0d, 0x6c, 0x80, 0xee, 0x22, 0x90, 0x7f}},
- {0x1306, 64, { 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90,
-  0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff,
-  0x22, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98,
-  0x74, 0x15, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0}},
- {0x1346, 64, { 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff,
-  0x22, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98,
-  0x74, 0x0a, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90,
-  0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe0}},
- {0x1386, 64, { 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98,
-  0x74, 0x0e, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x12, 0x00, 0x03, 0x12, 0x0d, 0x7d, 0x12,
-  0x0b, 0x4e, 0x22, 0x53, 0xd8, 0xef, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x13, 0x4b, 0x05, 0x0d, 0xe5, 0x0d, 0xac, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8c,
+  0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x0a, 0x12, 0x13, 0x87, 0x8f, 0x1a, 0xef}},
+ {0x0fc6, 64, { 0x42, 0x37, 0x80, 0xca, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86,
+  0x75, 0x86, 0x00, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04,
+  0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0,
+  0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x11}},
+ {0x1006, 64, { 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82,
+  0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0,
+  0x86, 0x75, 0x86, 0x00, 0xd2, 0x18, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08, 0xf0, 0xd0,
+  0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7f, 0x98}},
+ {0x1046, 64, { 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90, 0xc0,
+  0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00,
+  0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f,
+  0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0}},
+ {0x1086, 64, { 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0,
+  0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90,
+  0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f,
+  0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x14}},
+ {0x10c6, 64, { 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90,
+  0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0,
+  0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13,
+  0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b}},
+ {0x1106, 64, { 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x90, 0xc0, 0x00, 0xef,
+  0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22,
+  0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74,
+  0x08, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45}},
+ {0x1146, 64, { 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74,
+  0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98,
+  0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74,
+  0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90}},
+ {0x1186, 64, { 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00,
+  0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f,
+  0x98, 0x74, 0x0e, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5,
+  0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5}},
+ {0x11c6, 64, { 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x17, 0xf0, 0x90, 0xc0, 0x00, 0xef,
+  0xf0, 0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22, 0x12, 0x13, 0x1b,
+  0x8f, 0x1a, 0x12, 0x13, 0x1b, 0x8f, 0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x12, 0x12, 0x13, 0x1b,
+  0x8f, 0x1a, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x07, 0x12, 0x13, 0x1b, 0x8f, 0x1b, 0x80, 0xe8}},
+ {0x1206, 64, { 0xaf, 0x1a, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0,
+  0x90, 0x7f, 0x98, 0x74, 0x0f, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0d,
+  0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22, 0x12, 0x13, 0x6f, 0x8f, 0x1a, 0x12, 0x13, 0x6f, 0x8f,
+  0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x12, 0x12, 0x13, 0x6f, 0x8f, 0x1a, 0xe5, 0x1a, 0x65}},
+ {0x1246, 64, { 0x1b, 0x60, 0x07, 0x12, 0x13, 0x6f, 0x8f, 0x1b, 0x80, 0xe8, 0xaf, 0x1a, 0x22, 0x90, 0x7f, 0xd6, 0xe0,
+  0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x1a, 0x04, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xf4,
+  0x7e, 0x01, 0x12, 0x12, 0xd6, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0, 0xe0, 0x44, 0x04, 0xf0,
+  0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5, 0x3e, 0x54, 0x7f, 0xfd, 0x12, 0x11, 0xbf, 0x90, 0x7f}},
+ {0x1286, 64, { 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x3e, 0x44, 0x80, 0xfd, 0x12, 0x11,
+  0xbf, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5, 0x3f, 0x54, 0x7f, 0xfd, 0x12, 0x12, 0x09, 0x90, 0x7f,
+  0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x3f, 0x44, 0x80, 0xfd, 0x12,
+  0x12, 0x09, 0x22, 0x05, 0x0e, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x14, 0x03, 0x00, 0x00}},
+ {0x12c6, 64, { 0xc1, 0x11, 0xc1, 0x18, 0xc1, 0x95, 0xc1, 0x10, 0xc1, 0x16, 0x01, 0x0a, 0x00, 0xc1, 0x9b, 0x00, 0x8e,
+  0x18, 0x8f, 0x19, 0xe5, 0x19, 0x15, 0x19, 0xae, 0x18, 0x70, 0x02, 0x15, 0x18, 0x4e, 0x60, 0x05,
+  0x12, 0x0d, 0x5c, 0x80, 0xee, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xe0,
+  0xff, 0x22, 0x53, 0xd8, 0xef, 0x32, 0x00, 0x00, 0x00, 0x02, 0x0f, 0xf5, 0x00, 0x02, 0x13}},
+ {0x1306, 64, { 0x04, 0x00, 0x02, 0x0f, 0xcb, 0x00, 0x02, 0x10, 0x1c, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90, 0xc0,
+  0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22,
+  0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74,
+  0x15, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90}},
+ {0x1346, 64, { 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22,
+  0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74,
+  0x0a, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0,
+  0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff}},
+ {0x1386, 64, { 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74,
+  0x0e, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x12, 0x00, 0x03, 0x12, 0x0d, 0x6d, 0x12, 0x0b,
+  0x46, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
  {0x13c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x33, 0x00, 0x02, 0x14}},
- {0x1406, 64, { 0x04, 0x00, 0x02, 0x10, 0x09, 0x00, 0x02, 0x0f, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1406, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
@@ -424,13 +427,13 @@
  {0x18c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x01, 0xff, 0x00}},
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x10, 0x01, 0xff, 0x00}},
  {0x1906, 64, { 0x00, 0x40, 0xcd, 0x06, 0x15, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x02, 0x09, 0x02, 0x74, 0x00, 0x01,
   0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e, 0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01,
   0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40,
   0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x05, 0x02, 0x40, 0x00}},
  {0x1946, 64, { 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x07, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05,
-  0x81, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x83, 0x02,
+  0x81, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x83, 0x02,
   0x40, 0x00, 0x01, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00,
   0x01, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x87, 0x02, 0x40, 0x00, 0x01}},
  {0x1986, 64, { 0x04, 0x03, 0x09, 0x04, 0x48, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61,
@@ -442,5 +445,5 @@
   0x00, 0x42, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c,
   0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x61, 0x00, 0x70, 0x00, 0x74, 0x00, 0x65, 0x00}},
  {0x1a06,  4, { 0x72, 0x00, 0x00, 0x00}},
- { 0xffff,	0,	{0x00} }
+ {0xffff,  0, {0x00}}
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/keyspan_usa28xb_fw.h linux-2.4.20/drivers/usb/serial/keyspan_usa28xb_fw.h
--- linux-2.4.19/drivers/usb/serial/keyspan_usa28xb_fw.h	2001-10-09 22:15:03.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/keyspan_usa28xb_fw.h	2002-10-29 11:18:39.000000000 +0000
@@ -1,352 +1,353 @@
 /* keyspan_usa28xb_fw.h
 
-   Generated from Keyspan firmware image usacode36.h Sat Oct  6 12:07:38 EST 2001
-   This firmware is for the Keyspan USA-28XA Serial Adaptor
+	The firmware contained herein as keyspan_usa29xb_fw.h is
 
-   "The firmware contained herein as keyspan_usa28xb_fw.h is
-   Copyright (C) 1999-2001 Keyspan, A division of InnoSys Incorporated
-   ("Keyspan"), as an unpublished work.  This notice does not imply
-   unrestricted or public access to the source code from which this 
-   firmware image is derived.  Except as noted below this firmware image
-   may not be reproduced, used, sold or transferred to any third party
-   without Keyspan's prior written consent.  All Rights Reserved.
+		Copyright (C) 1999-2001
+		Keyspan, A division of InnoSys Incorporated ("Keyspan")
+		
+	as an unpublished work. This notice does not imply unrestricted or
+	public access to the source code from which this firmware image is
+	derived.  Except as noted below this firmware image may not be 
+	reproduced, used, sold or transferred to any third party without 
+	Keyspan's prior written consent.  All Rights Reserved.
 
-   Permission is hereby granted for the distribution of this firmware image
-   as part of a Linux or other Open Source operating system kernel in 
-   text or binary form as required.
+	Permission is hereby granted for the distribution of this firmware 
+	image as part of a Linux or other Open Source operating system kernel 
+	in text or binary form as required. 
 
-   This firmware may not be modified and may only be used with the Keyspan 
-   USA-28 Serial Adapter.  Distribution and/or Modification of the
-   keyspan.c driver which includes this firmware, in whole or in part,
-   requires the inclusion of this statement."
+	This firmware may not be modified and may only be used with  
+	Keyspan hardware.  Distribution and/or Modification of the 
+	keyspan.c driver which includes this firmware, in whole or in 
+	part, requires the inclusion of this statement."
 
 */
 
 static const struct ezusb_hex_record keyspan_usa28xb_firmware[] = {
- {0x0033,  3, { 0x02, 0x13, 0xb7}},
- {0x0046, 16, { 0x30, 0x09, 0x18, 0x12, 0x13, 0x35, 0xef, 0xc3, 0x95, 0x3c, 0x40, 0x03, 0x02, 0x00, 0xd8, 0x90}},
+ {0x0033,  3, { 0x02, 0x00, 0x2d}},
+ {0x002d,  4, { 0x53, 0xd8, 0xef, 0x32}},
+ {0x0046, 16, { 0x30, 0x09, 0x18, 0x12, 0x13, 0x33, 0xef, 0xc3, 0x95, 0x3c, 0x40, 0x03, 0x02, 0x00, 0xd8, 0x90}},
  {0x0056, 16, { 0x7f, 0xbf, 0x74, 0x01, 0xf0, 0xc2, 0x09, 0xc2, 0x00, 0x80, 0x77, 0x30, 0x03, 0x3b, 0x90, 0x7f}},
- {0x0066, 16, { 0xc6, 0xe0, 0x20, 0xe1, 0x6d, 0x12, 0x13, 0x35, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x64, 0x90, 0x7e}},
+ {0x0066, 16, { 0xc6, 0xe0, 0x20, 0xe1, 0x6d, 0x12, 0x13, 0x33, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x64, 0x90, 0x7e}},
  {0x0076, 16, { 0x40, 0xe0, 0x13, 0x92, 0x09, 0x90, 0x7f, 0xc7, 0xe0, 0x14, 0xf5, 0x19, 0x20, 0x00, 0x11, 0x60}},
- {0x0086, 16, { 0x0f, 0xf5, 0x08, 0x7e, 0x7e, 0x7f, 0x41, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x41, 0x12, 0x0c, 0xdc}},
+ {0x0086, 16, { 0x0f, 0xf5, 0x08, 0x7e, 0x7e, 0x7f, 0x41, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x41, 0x12, 0x0c, 0xcc}},
  {0x0096, 16, { 0xc2, 0x03, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0x80, 0x39, 0x90, 0x7f, 0xc8, 0xe0, 0x20, 0xe1, 0x32}},
- {0x00a6, 16, { 0x12, 0x13, 0x35, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x29, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x09}},
+ {0x00a6, 16, { 0x12, 0x13, 0x33, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x29, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x09}},
  {0x00b6, 16, { 0x90, 0x7f, 0xc9, 0xe0, 0x14, 0xf5, 0x19, 0x20, 0x00, 0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7d}},
- {0x00c6, 16, { 0x7f, 0xc1, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0xc1, 0x12, 0x0c, 0xdc, 0xd2, 0x03, 0xe4, 0x90, 0x7f}},
- {0x00d6, 16, { 0xc9, 0xf0, 0x90, 0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x01, 0x66, 0x53, 0x36, 0x80, 0x12}},
- {0x00e6, 16, { 0x13, 0x41, 0xef, 0x42, 0x36, 0x12, 0x12, 0x08, 0x8f, 0x19, 0xef, 0xc3, 0x95, 0x3a, 0x50, 0x0f}},
- {0x00f6, 16, { 0x12, 0x13, 0x1d, 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x36, 0x20, 0xe7, 0x03, 0x30, 0x0b, 0x61, 0xc2}},
+ {0x00c6, 16, { 0x7f, 0xc1, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0xc1, 0x12, 0x0c, 0xcc, 0xd2, 0x03, 0xe4, 0x90, 0x7f}},
+ {0x00d6, 16, { 0xc9, 0xf0, 0x90, 0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x01, 0x60, 0x12, 0x11, 0xf5, 0x8f}},
+ {0x00e6, 16, { 0x19, 0x12, 0x13, 0x3f, 0x8f, 0x36, 0xe5, 0x19, 0xc3, 0x95, 0x3a, 0x50, 0x0f, 0x12, 0x13, 0x1b}},
+ {0x00f6, 16, { 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x36, 0x20, 0xe7, 0x03, 0x30, 0x0b, 0x5e, 0xc2, 0x0b, 0xe5, 0x19}},
  {0x0036, 12, { 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22}},
- {0x0043,  3, { 0x02, 0x14, 0x00}},
- {0x0003, 16, { 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x30}},
- {0x0013, 16, { 0x15, 0x04, 0xc2, 0x15, 0x80, 0x02, 0xd2, 0x18, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08}},
- {0x0023, 14, { 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32}},
- {0x0000,  3, { 0x02, 0x0e, 0x22}},
- {0x0106, 64, { 0x0b, 0xe5, 0x19, 0x70, 0x04, 0xf5, 0x36, 0x80, 0x57, 0x12, 0x13, 0x41, 0xef, 0x42, 0x36, 0xe5, 0x36,
-  0x30, 0xe7, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08,
-  0x7e, 0x7e, 0x7f, 0x80, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x80, 0xaf, 0x36, 0x12, 0x0f, 0x6d, 0xe5,
-  0x19, 0x25, 0xe0, 0x90, 0x7f, 0xb7, 0xf0, 0x80, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40}},
- {0x0146, 64, { 0x03, 0x75, 0x19, 0x3f, 0x85, 0x19, 0x08, 0xe4, 0x90, 0x7e, 0x80, 0xf0, 0x7e, 0x7e, 0x7f, 0x81, 0x75,
-  0x0c, 0x7e, 0x75, 0x0d, 0x81, 0x12, 0x0d, 0x01, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xb7, 0xf0, 0x90,
-  0x7f, 0xce, 0xe0, 0x30, 0xe1, 0x06, 0x20, 0x05, 0x03, 0x02, 0x03, 0xc5, 0xe4, 0xf5, 0x18, 0x74,
-  0x40, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18, 0x7c}},
- {0x0186, 64, { 0x00, 0x7b, 0x01, 0x7a, 0x7e, 0x79, 0x00, 0x24, 0x00, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef, 0x12, 0x0e,
-  0xf4, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x00, 0xe0, 0x60, 0x68, 0x90, 0x7e,
-  0x03, 0xe0, 0x60, 0x24, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x11, 0xe3, 0x7f, 0x03, 0x7d, 0xcd, 0x12,
-  0x11, 0xe3, 0x43, 0x46, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5}},
- {0x01c6, 64, { 0x46, 0xf0, 0xe4, 0x90, 0x7e, 0x13, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x01, 0xe0, 0xff, 0x12, 0x10, 0x67,
-  0x90, 0x7e, 0x02, 0xe0, 0xff, 0x12, 0x10, 0x8d, 0x7f, 0x01, 0x90, 0x7e, 0x11, 0xe0, 0xfd, 0x12,
-  0x11, 0xe3, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x11, 0xe3, 0x43, 0x46, 0x80, 0x90, 0x7f, 0x98, 0x74,
-  0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5}},
- {0x0206, 64, { 0x40, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x03, 0xe0, 0x70, 0x06, 0x90, 0x7e, 0x13, 0xe0,
-  0x70, 0x08, 0xe4, 0x90, 0x7e, 0x13, 0xf0, 0x75, 0x25, 0xff, 0x90, 0x7e, 0x05, 0xe0, 0x60, 0x12,
-  0xa3, 0xe0, 0x54, 0x3f, 0xf5, 0x44, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe5,
-  0x44, 0xf0, 0x90, 0x7e, 0x07, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x42, 0x80}},
- {0x0246, 64, { 0x80, 0x03, 0x53, 0x42, 0x7f, 0x53, 0x42, 0xfc, 0x90, 0x7e, 0x09, 0xe0, 0x60, 0x11, 0x43, 0x42, 0x02,
-  0xa3, 0xe0, 0xff, 0x12, 0x10, 0xd9, 0x90, 0x7e, 0x0b, 0xe0, 0xff, 0x12, 0x10, 0xff, 0xaf, 0x42,
-  0x12, 0x10, 0xb3, 0x90, 0x7e, 0x03, 0xe0, 0x60, 0x08, 0x53, 0x42, 0x7f, 0xaf, 0x42, 0x12, 0x10,
-  0xb3, 0x90, 0x7e, 0x0c, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x02, 0x80}},
- {0x0286, 64, { 0x03, 0x53, 0x46, 0xfd, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90,
-  0x7e, 0x0e, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x01, 0x80, 0x03, 0x53, 0x46,
-  0xfe, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x12,
-  0xe0, 0xf5, 0x3a, 0xa3, 0xe0, 0x13, 0x92, 0x0d, 0xa3, 0xe0, 0xf5, 0x3c, 0xa3, 0xe0, 0x60}},
- {0x02c6, 64, { 0x05, 0x43, 0x46, 0x10, 0x80, 0x03, 0x53, 0x46, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0,
-  0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x16, 0xe0, 0x60, 0x32, 0x53, 0x44, 0xbf, 0x90, 0x7f, 0x98,
-  0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x11,
-  0xf0, 0x12, 0x13, 0x11, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3e, 0xfd, 0xe4}},
- {0x0306, 64, { 0xff, 0xad, 0x3e, 0x12, 0x11, 0xe3, 0xe4, 0xf5, 0x2a, 0xf5, 0x29, 0xd2, 0x07, 0x90, 0x7e, 0x17, 0xe0,
-  0x60, 0x0f, 0x43, 0x3e, 0x02, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xe3, 0x75, 0x29, 0x01, 0xd2,
-  0x07, 0x90, 0x7e, 0x18, 0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40, 0x44,
-  0x04, 0x90, 0xc0, 0x00, 0xf0, 0xd2, 0x00, 0x90, 0x7e, 0x19, 0xe0, 0x60, 0x11, 0x43, 0x44}},
- {0x0346, 64, { 0x40, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e,
-  0x1a, 0xe0, 0x60, 0x0f, 0x53, 0x3e, 0xfe, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xe3, 0x75, 0x2b,
-  0x01, 0xd2, 0x07, 0x90, 0x7e, 0x1b, 0xe0, 0x60, 0x0f, 0x43, 0x3e, 0x01, 0xe4, 0xff, 0xad, 0x3e,
-  0x12, 0x11, 0xe3, 0xe4, 0xf5, 0x2b, 0xd2, 0x07, 0x90, 0x7e, 0x1c, 0xe0, 0x60, 0x0e, 0x90}},
- {0x0386, 64, { 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1d, 0xe0,
-  0x60, 0x02, 0xd2, 0x0b, 0x90, 0x7e, 0x1e, 0xe0, 0x60, 0x08, 0x75, 0x2c, 0x01, 0xe4, 0xf5, 0x38,
-  0xd2, 0x07, 0x90, 0x7e, 0x1f, 0xe0, 0x60, 0x0f, 0x90, 0x7f, 0xd7, 0x74, 0x11, 0xf0, 0x74, 0x31,
-  0xf0, 0x74, 0x15, 0xf0, 0x74, 0x35, 0xf0, 0xc2, 0x05, 0xe4, 0x90, 0x7f, 0xcf, 0xf0, 0x30}},
- {0x03c6, 64, { 0x1a, 0x54, 0xe5, 0x38, 0x60, 0x02, 0x15, 0x38, 0x20, 0x13, 0x4b, 0xe5, 0x13, 0xd3, 0x94, 0x00, 0x40,
-  0x04, 0x15, 0x13, 0x80, 0x40, 0x75, 0x13, 0x0a, 0x30, 0x1b, 0x02, 0xd2, 0x13, 0x12, 0x13, 0x11,
-  0xef, 0x54, 0x01, 0xf5, 0x19, 0x65, 0x2a, 0x60, 0x05, 0x85, 0x19, 0x2a, 0xd2, 0x07, 0x12, 0x13,
-  0x4d, 0xef, 0x54, 0x80, 0x64, 0x80, 0xf5, 0x19, 0x65, 0x26, 0x60, 0x05, 0x85, 0x19, 0x26}},
- {0x0406, 64, { 0xd2, 0x07, 0x30, 0x0d, 0x11, 0x12, 0x13, 0x4d, 0xef, 0x54, 0x10, 0xf5, 0x19, 0x65, 0x25, 0x60, 0x05,
-  0x85, 0x19, 0x25, 0xd2, 0x07, 0x20, 0x1b, 0x03, 0x02, 0x07, 0xf8, 0x30, 0x0a, 0x18, 0x12, 0x13,
-  0x89, 0xef, 0xc3, 0x95, 0x3d, 0x40, 0x03, 0x02, 0x04, 0xb4, 0x90, 0x7f, 0xc1, 0x74, 0x01, 0xf0,
-  0xc2, 0x0a, 0xc2, 0x00, 0x80, 0x77, 0x30, 0x04, 0x3b, 0x90, 0x7f, 0xca, 0xe0, 0x20, 0xe1}},
- {0x0446, 64, { 0x6d, 0x12, 0x13, 0x89, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x64, 0x90, 0x7d, 0x40, 0xe0, 0x13, 0x92, 0x0a,
-  0x90, 0x7f, 0xcb, 0xe0, 0x14, 0xf5, 0x19, 0x20, 0x00, 0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7d,
-  0x7f, 0x41, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0x41, 0x12, 0x0d, 0x26, 0xc2, 0x04, 0xe4, 0x90, 0x7f,
-  0xcb, 0xf0, 0x80, 0x39, 0x90, 0x7f, 0xcc, 0xe0, 0x20, 0xe1, 0x32, 0x12, 0x13, 0x89, 0xef}},
- {0x0486, 64, { 0xc3, 0x94, 0x40, 0x50, 0x29, 0x90, 0x7c, 0xc0, 0xe0, 0x13, 0x92, 0x0a, 0x90, 0x7f, 0xcd, 0xe0, 0x14,
-  0xf5, 0x19, 0x20, 0x00, 0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7c, 0x7f, 0xc1, 0x75, 0x0c, 0x7c,
-  0x75, 0x0d, 0xc1, 0x12, 0x0d, 0x26, 0xd2, 0x04, 0xe4, 0x90, 0x7f, 0xcd, 0xf0, 0x90, 0x7f, 0xba,
-  0xe0, 0x30, 0xe1, 0x03, 0x02, 0x05, 0x42, 0x53, 0x37, 0x80, 0x12, 0x13, 0x95, 0xef, 0x42}},
- {0x04c6, 64, { 0x37, 0x12, 0x12, 0x52, 0x8f, 0x19, 0xef, 0xc3, 0x95, 0x3b, 0x50, 0x0f, 0x12, 0x13, 0x71, 0xef, 0x30,
-  0xe0, 0x08, 0xe5, 0x37, 0x20, 0xe7, 0x03, 0x30, 0x0c, 0x61, 0xc2, 0x0c, 0xe5, 0x19, 0x70, 0x04,
-  0xf5, 0x37, 0x80, 0x57, 0x12, 0x13, 0x95, 0xef, 0x42, 0x37, 0xe5, 0x37, 0x30, 0xe7, 0x26, 0xe5,
-  0x19, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08, 0x7e, 0x7d, 0x7f}},
- {0x0506, 64, { 0x80, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0x80, 0xaf, 0x37, 0x12, 0x0f, 0xa6, 0xe5, 0x19, 0x25, 0xe0, 0x90,
-  0x7f, 0xbb, 0xf0, 0x80, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75, 0x19, 0x3f, 0x85,
-  0x19, 0x08, 0xe4, 0x90, 0x7d, 0x80, 0xf0, 0x7e, 0x7d, 0x7f, 0x81, 0x75, 0x0c, 0x7d, 0x75, 0x0d,
-  0x81, 0x12, 0x0d, 0x4b, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xbb, 0xf0, 0x90, 0x7f, 0xd0, 0xe0}},
- {0x0546, 64, { 0x30, 0xe1, 0x06, 0x20, 0x06, 0x03, 0x02, 0x07, 0xa1, 0xe4, 0xf5, 0x18, 0x74, 0xc0, 0x25, 0x18, 0xf5,
-  0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18, 0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e,
-  0x79, 0x20, 0x24, 0x20, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef, 0x12, 0x0e, 0xf4, 0x05, 0x18, 0xe5,
-  0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x20, 0xe0, 0x60, 0x68, 0x90, 0x7e, 0x23, 0xe0, 0x60}},
- {0x0586, 64, { 0x24, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x12, 0x2d, 0x7f, 0x03, 0x7d, 0xcd, 0x12, 0x12, 0x2d, 0x43, 0x47,
-  0x80, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0xe4, 0x90, 0x7e,
-  0x33, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x21, 0xe0, 0xff, 0x12, 0x11, 0x4b, 0x90, 0x7e, 0x22, 0xe0,
-  0xff, 0x12, 0x11, 0x71, 0x7f, 0x01, 0x90, 0x7e, 0x31, 0xe0, 0xfd, 0x12, 0x12, 0x2d, 0x7f}},
- {0x05c6, 64, { 0x03, 0x7d, 0x07, 0x12, 0x12, 0x2d, 0x43, 0x47, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0,
-  0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0xe5, 0x41, 0x44, 0x06, 0x90, 0xc0,
-  0x00, 0xf0, 0x90, 0x7e, 0x23, 0xe0, 0x70, 0x06, 0x90, 0x7e, 0x33, 0xe0, 0x70, 0x08, 0xe4, 0x90,
-  0x7e, 0x33, 0xf0, 0x75, 0x2e, 0xff, 0x90, 0x7e, 0x25, 0xe0, 0x60, 0x12, 0xa3, 0xe0, 0x54}},
- {0x0606, 64, { 0x3f, 0xf5, 0x45, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x45, 0xf0, 0x90, 0x7e,
-  0x27, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x43, 0x80, 0x80, 0x03, 0x53, 0x43, 0x7f,
-  0x53, 0x43, 0xfc, 0x90, 0x7e, 0x29, 0xe0, 0x60, 0x11, 0x43, 0x43, 0x02, 0xa3, 0xe0, 0xff, 0x12,
-  0x11, 0x97, 0x90, 0x7e, 0x2b, 0xe0, 0xff, 0x12, 0x11, 0xbd, 0xaf, 0x43, 0x12, 0x11, 0x25}},
- {0x0646, 64, { 0x90, 0x7e, 0x23, 0xe0, 0x60, 0x08, 0x53, 0x43, 0x7f, 0xaf, 0x43, 0x12, 0x11, 0x25, 0x90, 0x7e, 0x2c,
-  0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x02, 0x80, 0x03, 0x53, 0x47, 0xfd, 0x90,
-  0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7e, 0x2e, 0xe0, 0x60,
-  0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x01, 0x80, 0x03, 0x53, 0x47, 0xfe, 0x90, 0x7f}},
- {0x0686, 64, { 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7e, 0x32, 0xe0, 0xf5, 0x3b, 0xa3,
-  0xe0, 0x13, 0x92, 0x0e, 0xa3, 0xe0, 0xf5, 0x3d, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x10, 0x80,
-  0x03, 0x53, 0x47, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0,
-  0x90, 0x7e, 0x36, 0xe0, 0x60, 0x32, 0x53, 0x45, 0xbf, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0}},
- {0x06c6, 64, { 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x12, 0x13, 0x65,
-  0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3f, 0xfd, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12,
-  0x2d, 0xe4, 0xf5, 0x33, 0xf5, 0x32, 0xd2, 0x08, 0x90, 0x7e, 0x37, 0xe0, 0x60, 0x0f, 0x43, 0x3f,
-  0x02, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x2d, 0x75, 0x32, 0x01, 0xd2, 0x08, 0x90, 0x7e}},
- {0x0706, 64, { 0x38, 0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0xe5, 0x41, 0x44, 0x04, 0x90, 0xc0, 0x00,
-  0xf0, 0xd2, 0x00, 0x90, 0x7e, 0x39, 0xe0, 0x60, 0x11, 0x43, 0x45, 0x40, 0x90, 0x7f, 0x98, 0x74,
-  0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x3a, 0xe0, 0x60, 0x0f,
-  0x53, 0x3f, 0xfe, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x2d, 0x75, 0x34, 0x01, 0xd2, 0x08}},
- {0x0746, 64, { 0x90, 0x7e, 0x3b, 0xe0, 0x60, 0x0f, 0x43, 0x3f, 0x01, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x2d, 0xe4,
-  0xf5, 0x34, 0xd2, 0x08, 0x90, 0x7e, 0x3c, 0xe0, 0x60, 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0,
-  0xe5, 0x41, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x3d, 0xe0, 0x60, 0x02, 0xd2, 0x0c,
-  0x90, 0x7e, 0x3e, 0xe0, 0x60, 0x08, 0x75, 0x35, 0x01, 0xe4, 0xf5, 0x39, 0xd2, 0x08, 0x90}},
- {0x0786, 64, { 0x7e, 0x3f, 0xe0, 0x60, 0x0f, 0x90, 0x7f, 0xd7, 0x74, 0x13, 0xf0, 0x74, 0x33, 0xf0, 0x74, 0x16, 0xf0,
-  0x74, 0x36, 0xf0, 0xc2, 0x06, 0xe4, 0x90, 0x7f, 0xd1, 0xf0, 0x30, 0x1a, 0x54, 0xe5, 0x39, 0x60,
-  0x02, 0x15, 0x39, 0x30, 0x13, 0x4b, 0xe5, 0x13, 0xd3, 0x94, 0x00, 0x40, 0x04, 0x15, 0x13, 0x80,
-  0x40, 0x75, 0x13, 0x0a, 0x30, 0x1b, 0x02, 0xc2, 0x13, 0x12, 0x13, 0x65, 0xef, 0x54, 0x01}},
- {0x07c6, 64, { 0xf5, 0x19, 0x65, 0x33, 0x60, 0x05, 0x85, 0x19, 0x33, 0xd2, 0x08, 0x12, 0x13, 0xa1, 0xef, 0x54, 0x80,
-  0x64, 0x80, 0xf5, 0x19, 0x65, 0x2f, 0x60, 0x05, 0x85, 0x19, 0x2f, 0xd2, 0x08, 0x30, 0x0e, 0x11,
-  0x12, 0x13, 0xa1, 0xef, 0x54, 0x10, 0xf5, 0x19, 0x65, 0x2e, 0x60, 0x05, 0x85, 0x19, 0x2e, 0xd2,
-  0x08, 0x30, 0x1a, 0x2a, 0x90, 0x7f, 0xd2, 0xe0, 0x20, 0xe1, 0x23, 0x90, 0x7b, 0x40, 0xe0}},
- {0x0806, 64, { 0x60, 0x09, 0xe0, 0xf5, 0x15, 0x90, 0x7b, 0x42, 0xe0, 0xf5, 0x16, 0x90, 0x7b, 0x41, 0xe0, 0x60, 0x09,
-  0x90, 0x7f, 0xd7, 0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0xe4, 0x90, 0x7f, 0xd3, 0xf0, 0x90, 0x7f,
-  0xc2, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x09, 0x2c, 0xe5, 0x0a, 0x70, 0x40, 0x30, 0x07, 0x39, 0xe5,
-  0x38, 0x70, 0x35, 0xc2, 0x07, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x18}},
- {0x0846, 64, { 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0xae, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34,
-  0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb, 0x90, 0x7f, 0xc3, 0x74,
-  0x09, 0xf0, 0x75, 0x38, 0x10, 0xe4, 0xf5, 0x2c, 0x75, 0x0a, 0x01, 0x22, 0xe5, 0x0a, 0x64, 0x01,
-  0x70, 0x40, 0x30, 0x08, 0x39, 0xe5, 0x39, 0x70, 0x35, 0xc2, 0x08, 0xf5, 0x18, 0x7e, 0x00}},
- {0x0886, 64, { 0x7b, 0x00, 0x74, 0x2d, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0xae, 0xff, 0x74, 0x80,
-  0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4,
-  0x09, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x09, 0xf0, 0x75, 0x39, 0x10, 0xe4, 0xf5, 0x35, 0x75, 0x0a,
-  0x02, 0x22, 0xe5, 0x0a, 0x64, 0x02, 0x70, 0x36, 0x30, 0x14, 0x2f, 0xc2, 0x14, 0xf5, 0x18}},
- {0x08c6, 64, { 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x0e, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0xae, 0xff,
-  0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5,
-  0x18, 0xb4, 0x05, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x05, 0xf0, 0x75, 0x0a, 0x03, 0x22, 0xe5, 0x15,
-  0x60, 0x30, 0x15, 0x15, 0xe4, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x14, 0x25, 0x18}},
- {0x0906, 64, { 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0xae, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34,
-  0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74,
-  0x03, 0xf0, 0xe4, 0xf5, 0x0a, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x0f, 0x06, 0x0a, 0x14, 0x00,
-  0x0a, 0x88, 0x01, 0x0a, 0xf4, 0x03, 0x09, 0x50, 0x06, 0x0a, 0x07, 0x08, 0x0a, 0x01, 0x09}},
- {0x0946, 64, { 0x09, 0xe9, 0x0a, 0x09, 0xf8, 0x0b, 0x00, 0x00, 0x0b, 0x43, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60,
-  0x19, 0x14, 0x60, 0x61, 0x24, 0x02, 0x60, 0x03, 0x02, 0x09, 0xdf, 0x74, 0x19, 0x90, 0x7f, 0xd4,
-  0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x04,
-  0x7f, 0x02, 0x80, 0x02, 0x7f, 0x03, 0x75, 0x82, 0x82, 0x75, 0x83, 0x19, 0xef, 0xf0, 0x75}},
- {0x0986, 64, { 0x82, 0x7b, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x74, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x66, 0x75,
-  0x83, 0x19, 0xf0, 0x75, 0x82, 0x58, 0x75, 0x83, 0x19, 0xf0, 0x90, 0x7f, 0xea, 0xe0, 0x04, 0x75,
-  0x82, 0x17, 0x75, 0x83, 0x19, 0xf0, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x12, 0x90, 0x7f,
-  0xd5, 0xf0, 0x02, 0x0b, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0f, 0x2c, 0xea, 0x49}},
- {0x09c6, 64, { 0x60, 0x0d, 0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x4a, 0x90, 0x7f,
-  0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x4a, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02,
-  0x0b, 0x4a, 0x90, 0x7f, 0x00, 0xe5, 0x09, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x0b,
-  0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x09, 0x02, 0x0b, 0x4a, 0x12, 0x0b, 0x52, 0x02, 0x0b}},
- {0x0a06, 64, { 0x4a, 0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x0b, 0x4a, 0x90, 0x7f, 0xe8,
-  0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2, 0x10, 0xe4, 0x33,
-  0xff, 0x25, 0xe0, 0xff, 0xa2, 0x16, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0,
-  0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x4a, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0xa3}},
- {0x0a46, 64, { 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x4a, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80,
-  0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4,
-  0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f,
-  0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x4a, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02}},
- {0x0a86, 64, { 0x0b, 0x4a, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0b, 0x4a,
-  0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x10, 0x02, 0x0b, 0x4a, 0x90, 0x7f, 0xb4, 0xe0,
-  0x44, 0x01, 0xf0, 0x02, 0x0b, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0,
-  0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24}},
- {0x0ac6, 64, { 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff,
-  0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44,
-  0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8,
-  0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01}},
- {0x0b06, 64, { 0x04, 0xd2, 0x10, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea,
-  0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0,
-  0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01,
-  0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4}},
- {0x0b46, 64, { 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22, 0xe4, 0x90, 0x7f, 0x93, 0xf0,
-  0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0xc0,
-  0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x18, 0xf0, 0xe4, 0xf5, 0x8e,
-  0x90, 0x7f, 0xdf, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0xe4, 0xf5, 0x24, 0x75, 0x18}},
- {0x0b86, 64, { 0x01, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x18, 0xf9, 0xe4, 0x34, 0x00, 0xfa, 0xe4, 0x12, 0x0e, 0xf4, 0x05,
-  0x18, 0xe5, 0x18, 0xb4, 0x09, 0xea, 0x75, 0x3a, 0x01, 0xe4, 0xf5, 0x38, 0xf5, 0x13, 0xf5, 0x36,
-  0xc2, 0x07, 0xc2, 0x0b, 0xc2, 0x05, 0xc2, 0x00, 0xc2, 0x09, 0xc2, 0x13, 0xd2, 0x03, 0xd2, 0x01,
-  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x75, 0x44, 0x03, 0x90, 0xc0, 0x00, 0x74, 0x03, 0xf0}},
- {0x0bc6, 64, { 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x11, 0xe3, 0x7f, 0x10, 0x8f, 0x42, 0x12, 0x10, 0xb3, 0x90, 0x7f, 0x98,
-  0x74, 0x12, 0xf0, 0x7f, 0x01, 0x8f, 0x40, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f,
-  0x98, 0x74, 0x14, 0xf0, 0x75, 0x46, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0x0f, 0xe4, 0xfd,
-  0x12, 0x11, 0xe3, 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3e, 0x12, 0x11, 0xe3, 0x90}},
- {0x0c06, 64, { 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x11, 0xe3,
-  0x7f, 0x01, 0x12, 0x12, 0x9c, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x11, 0xe3, 0x7f, 0x13, 0x7d, 0x09,
-  0x12, 0x11, 0xe3, 0x20, 0x1b, 0x03, 0x02, 0x0c, 0xd9, 0x75, 0x2d, 0x01, 0x75, 0x18, 0x01, 0x7b,
-  0x00, 0x74, 0x2d, 0x25, 0x18, 0xf9, 0xe4, 0x34, 0x00, 0xfa, 0xe4, 0x12, 0x0e, 0xf4, 0x05}},
- {0x0c46, 64, { 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xea, 0x75, 0x3b, 0x01, 0xe4, 0xf5, 0x39, 0xf5, 0x13, 0xf5, 0x37, 0xc2,
-  0x08, 0xc2, 0x0c, 0xc2, 0x06, 0xc2, 0x00, 0xc2, 0x0a, 0xc2, 0x13, 0xd2, 0x04, 0xd2, 0x02, 0x90,
+ {0x0043,  3, { 0x02, 0x13, 0x00}},
+ {0x0003, 16, { 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90}},
+ {0x0013, 16, { 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0}},
+ {0x0023, 10, { 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32}},
+ {0x0000,  3, { 0x02, 0x0e, 0x12}},
+ {0x0106, 64, { 0x60, 0x58, 0xb4, 0x80, 0x03, 0x43, 0x36, 0x02, 0xe5, 0x36, 0x30, 0xe7, 0x26, 0xe5, 0x19, 0xd3, 0x94,
+  0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08, 0x7e, 0x7e, 0x7f, 0x80, 0x75, 0x0c, 0x7e,
+  0x75, 0x0d, 0x80, 0xaf, 0x36, 0x12, 0x0f, 0x5d, 0xe5, 0x19, 0x25, 0xe0, 0x90, 0x7f, 0xb7, 0xf0,
+  0x80, 0x27, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75, 0x19, 0x3f, 0x85, 0x19, 0x08}},
+ {0x0146, 64, { 0x90, 0x7e, 0x80, 0xe5, 0x36, 0xf0, 0x7e, 0x7e, 0x7f, 0x81, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x81, 0x12,
+  0x0c, 0xf1, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xb7, 0xf0, 0x90, 0x7f, 0xce, 0xe0, 0x30, 0xe1, 0x06,
+  0x20, 0x05, 0x03, 0x02, 0x03, 0xc1, 0xe4, 0xf5, 0x18, 0x74, 0x40, 0x25, 0x18, 0xf5, 0x82, 0xe4,
+  0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18, 0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e, 0x79}},
+ {0x0186, 64, { 0x00, 0x24, 0x00, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef, 0x12, 0x0e, 0xe4, 0x05, 0x18, 0xe5, 0x18, 0xb4,
+  0x20, 0xd7, 0x90, 0x7e, 0x00, 0xe0, 0x60, 0x68, 0x90, 0x7e, 0x03, 0xe0, 0x60, 0x24, 0x7f, 0x01,
+  0xe4, 0xfd, 0x12, 0x11, 0xd0, 0x7f, 0x03, 0x7d, 0xcd, 0x12, 0x11, 0xd0, 0x43, 0x46, 0x80, 0x90,
+  0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0xe4, 0x90, 0x7e, 0x13}},
+ {0x01c6, 64, { 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x01, 0xe0, 0xff, 0x12, 0x10, 0x54, 0x90, 0x7e, 0x02, 0xe0, 0xff, 0x12,
+  0x10, 0x7a, 0x7f, 0x01, 0x90, 0x7e, 0x11, 0xe0, 0xfd, 0x12, 0x11, 0xd0, 0x7f, 0x03, 0x7d, 0x07,
+  0x12, 0x11, 0xd0, 0x43, 0x46, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5,
+  0x46, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40, 0x44, 0x06, 0x90, 0xc0, 0x00}},
+ {0x0206, 64, { 0xf0, 0x90, 0x7e, 0x03, 0xe0, 0x70, 0x06, 0x90, 0x7e, 0x13, 0xe0, 0x70, 0x08, 0xe4, 0x90, 0x7e, 0x13,
+  0xf0, 0x75, 0x25, 0xff, 0x90, 0x7e, 0x05, 0xe0, 0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f, 0xf5, 0x44,
+  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x44, 0xf0, 0x90, 0x7e, 0x07, 0xe0,
+  0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x42, 0x80, 0x80, 0x03, 0x53, 0x42, 0x7f, 0x53}},
+ {0x0246, 64, { 0x42, 0xfc, 0x90, 0x7e, 0x09, 0xe0, 0x60, 0x11, 0x43, 0x42, 0x02, 0xa3, 0xe0, 0xff, 0x12, 0x10, 0xc6,
+  0x90, 0x7e, 0x0b, 0xe0, 0xff, 0x12, 0x10, 0xec, 0xaf, 0x42, 0x12, 0x10, 0xa0, 0x90, 0x7e, 0x03,
+  0xe0, 0x60, 0x08, 0x53, 0x42, 0x7f, 0xaf, 0x42, 0x12, 0x10, 0xa0, 0x90, 0x7e, 0x0c, 0xe0, 0x60,
+  0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x02, 0x80, 0x03, 0x53, 0x46, 0xfd, 0x90, 0x7f}},
+ {0x0286, 64, { 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x0e, 0xe0, 0x60, 0x18, 0xa3,
+  0xe0, 0x60, 0x05, 0x43, 0x46, 0x01, 0x80, 0x03, 0x53, 0x46, 0xfe, 0x90, 0x7f, 0x98, 0x74, 0x14,
+  0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x12, 0xe0, 0xf5, 0x3a, 0xa3, 0xe0, 0x13,
+  0x92, 0x0d, 0xa3, 0xe0, 0xf5, 0x3c, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x10, 0x80, 0x03}},
+ {0x02c6, 64, { 0x53, 0x46, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e,
+  0x16, 0xe0, 0x60, 0x32, 0x53, 0x44, 0xbf, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54,
+  0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x12, 0x13, 0x0f, 0xef, 0x54,
+  0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3e, 0xfd, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xd0}},
+ {0x0306, 64, { 0xe4, 0xf5, 0x2a, 0xf5, 0x29, 0xd2, 0x07, 0x90, 0x7e, 0x17, 0xe0, 0x60, 0x0f, 0x43, 0x3e, 0x02, 0xe4,
+  0xff, 0xad, 0x3e, 0x12, 0x11, 0xd0, 0x75, 0x29, 0x01, 0xd2, 0x07, 0x90, 0x7e, 0x18, 0xe0, 0x60,
+  0x10, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0, 0xd2,
+  0x00, 0x90, 0x7e, 0x19, 0xe0, 0x60, 0x11, 0x43, 0x44, 0x40, 0x90, 0x7f, 0x98, 0x74, 0x13}},
+ {0x0346, 64, { 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1a, 0xe0, 0x60, 0x0f, 0x53, 0x3e,
+  0xfe, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xd0, 0x75, 0x2b, 0x01, 0xd2, 0x07, 0x90, 0x7e, 0x1b,
+  0xe0, 0x60, 0x0f, 0x43, 0x3e, 0x01, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x11, 0xd0, 0xe4, 0xf5, 0x2b,
+  0xd2, 0x07, 0x90, 0x7e, 0x1c, 0xe0, 0x60, 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5}},
+ {0x0386, 64, { 0x40, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1d, 0xe0, 0x60, 0x02, 0xd2, 0x0b, 0x90, 0x7e,
+  0x1e, 0xe0, 0x60, 0x08, 0x75, 0x2c, 0x01, 0xe4, 0xf5, 0x38, 0xd2, 0x07, 0x90, 0x7e, 0x1f, 0xe0,
+  0x60, 0x11, 0x90, 0x7f, 0xd7, 0x74, 0x11, 0xf0, 0x74, 0x31, 0xf0, 0x74, 0x15, 0xf0, 0x74, 0x35,
+  0xf0, 0xd2, 0x03, 0xc2, 0x05, 0xe4, 0x90, 0x7f, 0xcf, 0xf0, 0x30, 0x1a, 0x54, 0xe5, 0x38}},
+ {0x03c6, 64, { 0x60, 0x02, 0x15, 0x38, 0x20, 0x13, 0x4b, 0xe5, 0x13, 0xd3, 0x94, 0x00, 0x40, 0x04, 0x15, 0x13, 0x80,
+  0x40, 0x75, 0x13, 0x0a, 0x30, 0x1b, 0x02, 0xd2, 0x13, 0x12, 0x13, 0x0f, 0xef, 0x54, 0x01, 0xf5,
+  0x19, 0x65, 0x2a, 0x60, 0x05, 0x85, 0x19, 0x2a, 0xd2, 0x07, 0x12, 0x13, 0x4b, 0xef, 0x54, 0x80,
+  0x64, 0x80, 0xf5, 0x19, 0x65, 0x26, 0x60, 0x05, 0x85, 0x19, 0x26, 0xd2, 0x07, 0x30, 0x0d}},
+ {0x0406, 64, { 0x11, 0x12, 0x13, 0x4b, 0xef, 0x54, 0x10, 0xf5, 0x19, 0x65, 0x25, 0x60, 0x05, 0x85, 0x19, 0x25, 0xd2,
+  0x07, 0x20, 0x1b, 0x03, 0x02, 0x07, 0xf0, 0x30, 0x0a, 0x18, 0x12, 0x13, 0x87, 0xef, 0xc3, 0x95,
+  0x3d, 0x40, 0x03, 0x02, 0x04, 0xb0, 0x90, 0x7f, 0xc1, 0x74, 0x01, 0xf0, 0xc2, 0x0a, 0xc2, 0x00,
+  0x80, 0x77, 0x30, 0x04, 0x3b, 0x90, 0x7f, 0xca, 0xe0, 0x20, 0xe1, 0x6d, 0x12, 0x13, 0x87}},
+ {0x0446, 64, { 0xef, 0xc3, 0x94, 0x40, 0x50, 0x64, 0x90, 0x7d, 0x40, 0xe0, 0x13, 0x92, 0x0a, 0x90, 0x7f, 0xcb, 0xe0,
+  0x14, 0xf5, 0x19, 0x20, 0x00, 0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7d, 0x7f, 0x41, 0x75, 0x0c,
+  0x7d, 0x75, 0x0d, 0x41, 0x12, 0x0d, 0x16, 0xc2, 0x04, 0xe4, 0x90, 0x7f, 0xcb, 0xf0, 0x80, 0x39,
+  0x90, 0x7f, 0xcc, 0xe0, 0x20, 0xe1, 0x32, 0x12, 0x13, 0x87, 0xef, 0xc3, 0x94, 0x40, 0x50}},
+ {0x0486, 64, { 0x29, 0x90, 0x7c, 0xc0, 0xe0, 0x13, 0x92, 0x0a, 0x90, 0x7f, 0xcd, 0xe0, 0x14, 0xf5, 0x19, 0x20, 0x00,
+  0x11, 0x60, 0x0f, 0xf5, 0x08, 0x7e, 0x7c, 0x7f, 0xc1, 0x75, 0x0c, 0x7c, 0x75, 0x0d, 0xc1, 0x12,
+  0x0d, 0x16, 0xd2, 0x04, 0xe4, 0x90, 0x7f, 0xcd, 0xf0, 0x90, 0x7f, 0xba, 0xe0, 0x30, 0xe1, 0x03,
+  0x02, 0x05, 0x38, 0x12, 0x12, 0x3f, 0x8f, 0x19, 0x12, 0x13, 0x93, 0x8f, 0x37, 0xe5, 0x19}},
+ {0x04c6, 64, { 0xc3, 0x95, 0x3b, 0x50, 0x0f, 0x12, 0x13, 0x6f, 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x37, 0x20, 0xe7, 0x03,
+  0x30, 0x0c, 0x5e, 0xc2, 0x0c, 0xe5, 0x19, 0x60, 0x58, 0xb4, 0x80, 0x03, 0x43, 0x37, 0x02, 0xe5,
+  0x37, 0x30, 0xe7, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19,
+  0x08, 0x7e, 0x7d, 0x7f, 0x80, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0x80, 0xaf, 0x37, 0x12, 0x0f}},
+ {0x0506, 64, { 0x96, 0xe5, 0x19, 0x25, 0xe0, 0x90, 0x7f, 0xbb, 0xf0, 0x80, 0x27, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40,
+  0x03, 0x75, 0x19, 0x3f, 0x85, 0x19, 0x08, 0x90, 0x7d, 0x80, 0xe5, 0x37, 0xf0, 0x7e, 0x7d, 0x7f,
+  0x81, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0x81, 0x12, 0x0d, 0x3b, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xbb,
+  0xf0, 0x90, 0x7f, 0xd0, 0xe0, 0x30, 0xe1, 0x06, 0x20, 0x06, 0x03, 0x02, 0x07, 0x99, 0xe4}},
+ {0x0546, 64, { 0xf5, 0x18, 0x74, 0xc0, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18,
+  0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e, 0x79, 0x20, 0x24, 0x20, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef,
+  0x12, 0x0e, 0xe4, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x20, 0xe0, 0x60, 0x68,
+  0x90, 0x7e, 0x23, 0xe0, 0x60, 0x24, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x12, 0x1a, 0x7f, 0x03}},
+ {0x0586, 64, { 0x7d, 0xcd, 0x12, 0x12, 0x1a, 0x43, 0x47, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00,
+  0xe5, 0x47, 0xf0, 0xe4, 0x90, 0x7e, 0x33, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x21, 0xe0, 0xff, 0x12,
+  0x11, 0x38, 0x90, 0x7e, 0x22, 0xe0, 0xff, 0x12, 0x11, 0x5e, 0x7f, 0x01, 0x90, 0x7e, 0x31, 0xe0,
+  0xfd, 0x12, 0x12, 0x1a, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x12, 0x1a, 0x43, 0x47, 0x80, 0x90}},
+ {0x05c6, 64, { 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0,
+  0xe5, 0x41, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x23, 0xe0, 0x70, 0x06, 0x90, 0x7e,
+  0x33, 0xe0, 0x70, 0x08, 0xe4, 0x90, 0x7e, 0x33, 0xf0, 0x75, 0x2e, 0xff, 0x90, 0x7e, 0x25, 0xe0,
+  0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f, 0xf5, 0x45, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90}},
+ {0x0606, 64, { 0xc0, 0x00, 0xe5, 0x45, 0xf0, 0x90, 0x7e, 0x27, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x43,
+  0x80, 0x80, 0x03, 0x53, 0x43, 0x7f, 0x53, 0x43, 0xfc, 0x90, 0x7e, 0x29, 0xe0, 0x60, 0x11, 0x43,
+  0x43, 0x02, 0xa3, 0xe0, 0xff, 0x12, 0x11, 0x84, 0x90, 0x7e, 0x2b, 0xe0, 0xff, 0x12, 0x11, 0xaa,
+  0xaf, 0x43, 0x12, 0x11, 0x12, 0x90, 0x7e, 0x23, 0xe0, 0x60, 0x08, 0x53, 0x43, 0x7f, 0xaf}},
+ {0x0646, 64, { 0x43, 0x12, 0x11, 0x12, 0x90, 0x7e, 0x2c, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x02,
+  0x80, 0x03, 0x53, 0x47, 0xfd, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47,
+  0xf0, 0x90, 0x7e, 0x2e, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x01, 0x80, 0x03,
+  0x53, 0x47, 0xfe, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0}},
+ {0x0686, 64, { 0x90, 0x7e, 0x32, 0xe0, 0xf5, 0x3b, 0xa3, 0xe0, 0x13, 0x92, 0x0e, 0xa3, 0xe0, 0xf5, 0x3d, 0xa3, 0xe0,
+  0x60, 0x05, 0x43, 0x47, 0x10, 0x80, 0x03, 0x53, 0x47, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0,
+  0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7e, 0x36, 0xe0, 0x60, 0x32, 0x53, 0x45, 0xbf, 0x90,
+  0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f}},
+ {0x06c6, 64, { 0x98, 0x74, 0x09, 0xf0, 0x12, 0x13, 0x63, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3f, 0xfd,
+  0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x1a, 0xe4, 0xf5, 0x33, 0xf5, 0x32, 0xd2, 0x08, 0x90, 0x7e,
+  0x37, 0xe0, 0x60, 0x0f, 0x43, 0x3f, 0x02, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x1a, 0x75, 0x32,
+  0x01, 0xd2, 0x08, 0x90, 0x7e, 0x38, 0xe0, 0x60, 0x10, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0}},
+ {0x0706, 64, { 0xe5, 0x41, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0, 0xd2, 0x00, 0x90, 0x7e, 0x39, 0xe0, 0x60, 0x11, 0x43,
+  0x45, 0x40, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0,
+  0x90, 0x7e, 0x3a, 0xe0, 0x60, 0x0f, 0x53, 0x3f, 0xfe, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x1a,
+  0x75, 0x34, 0x01, 0xd2, 0x08, 0x90, 0x7e, 0x3b, 0xe0, 0x60, 0x0f, 0x43, 0x3f, 0x01, 0xe4}},
+ {0x0746, 64, { 0xff, 0xad, 0x3f, 0x12, 0x12, 0x1a, 0xe4, 0xf5, 0x34, 0xd2, 0x08, 0x90, 0x7e, 0x3c, 0xe0, 0x60, 0x0e,
+  0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0xe5, 0x41, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e,
+  0x3d, 0xe0, 0x60, 0x02, 0xd2, 0x0c, 0x90, 0x7e, 0x3e, 0xe0, 0x60, 0x08, 0x75, 0x35, 0x01, 0xe4,
+  0xf5, 0x39, 0xd2, 0x08, 0x90, 0x7e, 0x3f, 0xe0, 0x60, 0x11, 0x90, 0x7f, 0xd7, 0x74, 0x13}},
+ {0x0786, 64, { 0xf0, 0x74, 0x33, 0xf0, 0x74, 0x16, 0xf0, 0x74, 0x36, 0xf0, 0xd2, 0x04, 0xc2, 0x06, 0xe4, 0x90, 0x7f,
+  0xd1, 0xf0, 0x30, 0x1a, 0x54, 0xe5, 0x39, 0x60, 0x02, 0x15, 0x39, 0x30, 0x13, 0x4b, 0xe5, 0x13,
+  0xd3, 0x94, 0x00, 0x40, 0x04, 0x15, 0x13, 0x80, 0x40, 0x75, 0x13, 0x0a, 0x30, 0x1b, 0x02, 0xc2,
+  0x13, 0x12, 0x13, 0x63, 0xef, 0x54, 0x01, 0xf5, 0x19, 0x65, 0x33, 0x60, 0x05, 0x85, 0x19}},
+ {0x07c6, 64, { 0x33, 0xd2, 0x08, 0x12, 0x13, 0x9f, 0xef, 0x54, 0x80, 0x64, 0x80, 0xf5, 0x19, 0x65, 0x2f, 0x60, 0x05,
+  0x85, 0x19, 0x2f, 0xd2, 0x08, 0x30, 0x0e, 0x11, 0x12, 0x13, 0x9f, 0xef, 0x54, 0x10, 0xf5, 0x19,
+  0x65, 0x2e, 0x60, 0x05, 0x85, 0x19, 0x2e, 0xd2, 0x08, 0x30, 0x1a, 0x2a, 0x90, 0x7f, 0xd2, 0xe0,
+  0x20, 0xe1, 0x23, 0x90, 0x7b, 0x40, 0xe0, 0x60, 0x09, 0xe0, 0xf5, 0x15, 0x90, 0x7b, 0x42}},
+ {0x0806, 64, { 0xe0, 0xf5, 0x16, 0x90, 0x7b, 0x41, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7, 0x74, 0x17, 0xf0, 0x74, 0x37,
+  0xf0, 0xe4, 0x90, 0x7f, 0xd3, 0xf0, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x09, 0x24,
+  0xe5, 0x0a, 0x70, 0x40, 0x30, 0x07, 0x39, 0xe5, 0x38, 0x70, 0x35, 0xc2, 0x07, 0xf5, 0x18, 0x7e,
+  0x00, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0x9e}},
+ {0x0846, 64, { 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5,
+  0x18, 0xb4, 0x09, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x09, 0xf0, 0x75, 0x38, 0x10, 0xe4, 0xf5, 0x2c,
+  0x75, 0x0a, 0x01, 0x22, 0xe5, 0x0a, 0x64, 0x01, 0x70, 0x40, 0x30, 0x08, 0x39, 0xe5, 0x39, 0x70,
+  0x35, 0xc2, 0x08, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x2d, 0x25, 0x18, 0xf9, 0xee}},
+ {0x0886, 64, { 0x34, 0x00, 0xfa, 0x12, 0x0e, 0x9e, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5,
+  0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x09, 0xf0,
+  0x75, 0x39, 0x10, 0xe4, 0xf5, 0x35, 0x75, 0x0a, 0x02, 0x22, 0xe5, 0x0a, 0x64, 0x02, 0x70, 0x36,
+  0x30, 0x14, 0x2f, 0xc2, 0x14, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x0e, 0x25, 0x18}},
+ {0x08c6, 64, { 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0x9e, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34,
+  0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x05, 0xdb, 0x90, 0x7f, 0xc3, 0x74,
+  0x05, 0xf0, 0x75, 0x0a, 0x03, 0x22, 0xe5, 0x15, 0x60, 0x30, 0x15, 0x15, 0xe4, 0xf5, 0x18, 0x7e,
+  0x00, 0x7b, 0x00, 0x74, 0x14, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0e, 0x9e}},
+ {0x0906, 64, { 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5,
+  0x18, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4, 0xf5, 0x0a, 0x22, 0x90, 0x7f,
+  0xe9, 0xe0, 0x12, 0x0e, 0xf6, 0x0a, 0x0c, 0x00, 0x0a, 0x80, 0x01, 0x0a, 0xec, 0x03, 0x09, 0x48,
+  0x06, 0x09, 0xff, 0x08, 0x09, 0xf9, 0x09, 0x09, 0xe1, 0x0a, 0x09, 0xf0, 0x0b, 0x00, 0x00}},
+ {0x0946, 64, { 0x0b, 0x3b, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x19, 0x14, 0x60, 0x61, 0x24, 0x02, 0x60, 0x03,
+  0x02, 0x09, 0xd7, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02,
+  0x0b, 0x42, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x04, 0x7f, 0x02, 0x80, 0x02, 0x7f, 0x03, 0x75, 0x82,
+  0x82, 0x75, 0x83, 0x19, 0xef, 0xf0, 0x75, 0x82, 0x7b, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82}},
+ {0x0986, 64, { 0x74, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x66, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x58, 0x75, 0x83,
+  0x19, 0xf0, 0x90, 0x7f, 0xea, 0xe0, 0x04, 0x75, 0x82, 0x17, 0x75, 0x83, 0x19, 0xf0, 0x74, 0x19,
+  0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x12, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x42, 0x90, 0x7f, 0xea,
+  0xe0, 0xff, 0x12, 0x0f, 0x1c, 0xea, 0x49, 0x60, 0x0d, 0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9}},
+ {0x09c6, 64, { 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b, 0x42, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x42,
+  0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x42, 0x90, 0x7f, 0x00, 0xe5, 0x09, 0xf0,
+  0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x0b, 0x42, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x09, 0x02,
+  0x0b, 0x42, 0x12, 0x0b, 0x4a, 0x02, 0x0b, 0x42, 0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90}},
+ {0x0a06, 64, { 0x7f, 0xb5, 0xf0, 0x02, 0x0b, 0x42, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31,
+  0x24, 0x02, 0x70, 0x5b, 0xa2, 0x10, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x16, 0xe4, 0x33,
+  0x4f, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b,
+  0x42, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02}},
+ {0x0a46, 64, { 0x0b, 0x42, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07,
+  0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90,
+  0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x42, 0x90,
+  0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x42, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe}},
+ {0x0a86, 64, { 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0b, 0x42, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2,
+  0x10, 0x02, 0x0b, 0x42, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x42, 0x90, 0x7f,
+  0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff,
+  0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83}},
+ {0x0ac6, 64, { 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54,
+  0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0,
+  0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70,
+  0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x10, 0x80, 0x3f, 0x90, 0x7f, 0xb4}},
+ {0x0b06, 64, { 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4,
+  0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5,
+  0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44,
+  0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0}},
+ {0x0b46, 64, { 0x44, 0x02, 0xf0, 0x22, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0xe4, 0x90,
+  0x7f, 0x96, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0xc0, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90,
+  0x7f, 0x98, 0x74, 0x18, 0xf0, 0xe4, 0xf5, 0x8e, 0x90, 0x7f, 0xdf, 0x74, 0xff, 0xf0, 0x90, 0x7f,
+  0xde, 0xf0, 0xe4, 0xf5, 0x24, 0x75, 0x18, 0x01, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x18, 0xf9}},
+ {0x0b86, 64, { 0xe4, 0x34, 0x00, 0xfa, 0xe4, 0x12, 0x0e, 0xe4, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xea, 0x75, 0x3a,
+  0x01, 0xe4, 0xf5, 0x38, 0xf5, 0x13, 0xf5, 0x36, 0xc2, 0x07, 0xc2, 0x0b, 0xc2, 0x05, 0xc2, 0x00,
+  0xc2, 0x09, 0xc2, 0x13, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x75, 0x44, 0x03, 0x90, 0xc0, 0x00,
+  0x74, 0x03, 0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x11, 0xd0, 0x7f, 0x10, 0x8f, 0x42, 0x12}},
+ {0x0bc6, 64, { 0x10, 0xa0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x7f, 0x01, 0x8f, 0x40, 0xef, 0x44, 0x06, 0x90, 0xc0,
+  0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x75, 0x46, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80,
+  0xf0, 0x0f, 0xe4, 0xfd, 0x12, 0x11, 0xd0, 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3e, 0x12,
+  0x11, 0xd0, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05}},
+ {0x0c06, 64, { 0x7d, 0x7f, 0x12, 0x11, 0xd0, 0x7f, 0x01, 0x12, 0x12, 0x89, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x11, 0xd0,
+  0x7f, 0x13, 0x7d, 0x09, 0x12, 0x11, 0xd0, 0x20, 0x1b, 0x03, 0x02, 0x0c, 0xc9, 0x75, 0x2d, 0x01,
+  0x75, 0x18, 0x01, 0x7b, 0x00, 0x74, 0x2d, 0x25, 0x18, 0xf9, 0xe4, 0x34, 0x00, 0xfa, 0xe4, 0x12,
+  0x0e, 0xe4, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xea, 0x75, 0x3b, 0x01, 0xe4, 0xf5, 0x39}},
+ {0x0c46, 64, { 0xf5, 0x13, 0xf5, 0x37, 0xc2, 0x08, 0xc2, 0x0c, 0xc2, 0x06, 0xc2, 0x00, 0xc2, 0x0a, 0xc2, 0x13, 0x90,
   0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x75, 0x45, 0x03, 0x90, 0xc0, 0x00, 0x74, 0x03, 0xf0, 0x7f, 0x0c,
-  0xe4, 0xfd, 0x12, 0x12, 0x2d, 0x7f, 0x10, 0x8f, 0x43, 0x12, 0x11, 0x25, 0x90, 0x7f, 0x98}},
- {0x0c86, 64, { 0x74, 0x0a, 0xf0, 0x7f, 0x01, 0x8f, 0x41, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98,
-  0x74, 0x0c, 0xf0, 0x75, 0x47, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0x0f, 0xe4, 0xfd, 0x12,
-  0x12, 0x2d, 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3f, 0x12, 0x12, 0x2d, 0x90, 0x7f, 0x98,
-  0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x12, 0x2d}},
- {0x0cc6, 64, { 0x7f, 0x01, 0x12, 0x12, 0xbd, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x12, 0x2d, 0x7f, 0x13, 0x7d, 0x09, 0x12,
-  0x12, 0x2d, 0xd2, 0x12, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5,
+  0xe4, 0xfd, 0x12, 0x12, 0x1a, 0x7f, 0x10, 0x8f, 0x43, 0x12, 0x11, 0x12, 0x90, 0x7f, 0x98, 0x74,
+  0x0a, 0xf0, 0x7f, 0x01, 0x8f, 0x41, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f}},
+ {0x0c86, 64, { 0x98, 0x74, 0x0c, 0xf0, 0x75, 0x47, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0x0f, 0xe4, 0xfd, 0x12,
+  0x12, 0x1a, 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3f, 0x12, 0x12, 0x1a, 0x90, 0x7f, 0x98,
+  0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x12, 0x1a, 0x7f,
+  0x01, 0x12, 0x12, 0xaa, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x12, 0x1a, 0x7f, 0x13, 0x7d, 0x09}},
+ {0x0cc6, 64, { 0x12, 0x12, 0x1a, 0xd2, 0x12, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5,
   0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3,
-  0x05, 0x86, 0xf0, 0x05, 0x86, 0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10}},
- {0x0d06, 64, { 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0,
-  0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x90,
+  0x05, 0x86, 0xf0, 0x05, 0x86, 0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0,
+  0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90}},
+ {0x0d06, 64, { 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x90,
   0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2,
-  0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05, 0x86}},
- {0x0d46, 64, { 0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82,
-  0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3,
+  0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05, 0x86, 0xdf,
+  0xf7, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5}},
+ {0x0d46, 64, { 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3,
   0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5,
-  0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44}},
- {0x0d86, 64, { 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xd2, 0x19, 0x90, 0x7f, 0x92, 0xe0,
-  0x44, 0x02, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92, 0x10, 0xe4, 0x33, 0xfe, 0xef, 0x4e,
+  0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80,
+  0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xd2, 0x19, 0x90, 0x7f, 0x92}},
+ {0x0d86, 64, { 0xe0, 0x44, 0x02, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92, 0x10, 0xe4, 0x33, 0xfe, 0xef, 0x4e,
   0xf0, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0,
-  0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53}},
- {0x0dc6, 64, { 0x91, 0xef, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x0d, 0xf0, 0xd2,
-  0xaf, 0xd2, 0x1a, 0x12, 0x12, 0x77, 0xc2, 0x11, 0xe4, 0xf5, 0x0b, 0xf5, 0x13, 0xc2, 0x17, 0xc2,
+  0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91,
+  0xef, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x0d, 0xf0}},
+ {0x0dc6, 64, { 0xd2, 0xaf, 0xd2, 0x1a, 0x12, 0x12, 0x64, 0xc2, 0x11, 0xe4, 0xf5, 0x0b, 0xf5, 0x13, 0xc2, 0x17, 0xc2,
   0x12, 0x90, 0x7f, 0xa1, 0x04, 0xf0, 0x90, 0x7f, 0xd8, 0xe0, 0x65, 0x17, 0x60, 0x10, 0x30, 0x12,
-  0x05, 0xd2, 0x1a, 0x12, 0x00, 0x46, 0x90, 0x7f, 0xd8, 0xe0, 0xf5, 0x17, 0x80, 0x08, 0x30}},
- {0x0e06, 64, { 0x12, 0x05, 0xc2, 0x1a, 0x12, 0x00, 0x46, 0x30, 0x11, 0x07, 0xc2, 0x11, 0x12, 0x09, 0x2d, 0x80, 0xd6,
-  0x30, 0x18, 0xd3, 0xc2, 0x18, 0x12, 0x13, 0xad, 0x80, 0xcc, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8,
-  0xfd, 0x75, 0x81, 0x47, 0x02, 0x0e, 0x69, 0x02, 0x0d, 0x91, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93,
-  0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3}},
- {0x0e46, 64, { 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04,
-  0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
-  0x40, 0x80, 0x90, 0x12, 0xde, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30,
-  0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25}},
- {0x0e86, 64, { 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8,
-  0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83,
+  0x05, 0xd2, 0x1a, 0x12, 0x00, 0x46, 0x90, 0x7f, 0xd8, 0xe0, 0xf5, 0x17, 0x80, 0x08, 0x30, 0x12,
+  0x05, 0xc2, 0x1a, 0x12, 0x00, 0x46, 0x30, 0x11, 0x07, 0xc2, 0x11, 0x12, 0x09, 0x25, 0x80}},
+ {0x0e06, 64, { 0xd6, 0x30, 0x18, 0xd3, 0xc2, 0x18, 0x12, 0x13, 0xab, 0x80, 0xcc, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8,
+  0xfd, 0x75, 0x81, 0x47, 0x02, 0x0e, 0x59, 0x02, 0x0d, 0x81, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93,
+  0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8,
+  0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40}},
+ {0x0e46, 64, { 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
+  0x40, 0x80, 0x90, 0x12, 0xcb, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30,
+  0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0,
+  0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3}},
+ {0x0e86, 64, { 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83,
   0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22,
-  0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93}},
- {0x0ec6, 64, { 0x22, 0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50,
-  0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22,
+  0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22,
+  0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22}},
+ {0x0ec6, 64, { 0x50, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22,
   0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06,
-  0x89, 0x82, 0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22}},
- {0x0f06, 64, { 0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93,
-  0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef,
+  0x89, 0x82, 0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xd0,
+  0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3}},
+ {0x0f06, 64, { 0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef,
   0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0x8f, 0x18, 0xe4, 0xf5, 0x19, 0x75, 0x1a, 0xff, 0x75, 0x1b, 0x19,
-  0x75, 0x1c, 0x86, 0xab, 0x1a, 0xaa, 0x1b, 0xa9, 0x1c, 0x90, 0x00, 0x01, 0x12, 0x0e, 0xc7}},
- {0x0f46, 64, { 0xb4, 0x03, 0x1d, 0xaf, 0x19, 0x05, 0x19, 0xef, 0xb5, 0x18, 0x01, 0x22, 0x12, 0x0e, 0xae, 0x7e, 0x00,
-  0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75, 0x1a, 0xff, 0xf5, 0x1b, 0x89, 0x1c, 0x80, 0xd4, 0x7b,
+  0x75, 0x1c, 0x86, 0xab, 0x1a, 0xaa, 0x1b, 0xa9, 0x1c, 0x90, 0x00, 0x01, 0x12, 0x0e, 0xb7, 0xb4,
+  0x03, 0x1d, 0xaf, 0x19, 0x05, 0x19, 0xef, 0xb5, 0x18, 0x01, 0x22, 0x12, 0x0e, 0x9e, 0x7e}},
+ {0x0f46, 64, { 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75, 0x1a, 0xff, 0xf5, 0x1b, 0x89, 0x1c, 0x80, 0xd4, 0x7b,
   0x00, 0x7a, 0x00, 0x79, 0x00, 0x22, 0x8f, 0x1a, 0x05, 0x0d, 0xe5, 0x0d, 0xae, 0x0c, 0x70, 0x02,
-  0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x1a, 0xf0, 0x12, 0x00, 0x36, 0x05, 0x0d}},
- {0x0f86, 64, { 0xe5, 0x0d, 0xac, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08,
-  0xe5, 0x08, 0x60, 0x0a, 0x12, 0x13, 0x41, 0x8f, 0x1a, 0xef, 0x42, 0x36, 0x80, 0xca, 0x22, 0x8f,
+  0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x1a, 0xf0, 0x12, 0x00, 0x36, 0x05, 0x0d, 0xe5,
+  0x0d, 0xac, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15}},
+ {0x0f86, 64, { 0x08, 0xe5, 0x08, 0x60, 0x0a, 0x12, 0x13, 0x3f, 0x8f, 0x1a, 0xef, 0x42, 0x36, 0x80, 0xca, 0x22, 0x8f,
   0x1a, 0x05, 0x0d, 0xe5, 0x0d, 0xae, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8e, 0x83,
-  0xe5, 0x1a, 0xf0, 0x12, 0x13, 0x59, 0x05, 0x0d, 0xe5, 0x0d, 0xac, 0x0c, 0x70, 0x02, 0x05}},
- {0x0fc6, 64, { 0x0c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x0a, 0x12, 0x13, 0x95,
-  0x8f, 0x1a, 0xef, 0x42, 0x37, 0x80, 0xca, 0x22, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c,
+  0xe5, 0x1a, 0xf0, 0x12, 0x13, 0x57, 0x05, 0x0d, 0xe5, 0x0d, 0xac, 0x0c, 0x70, 0x02, 0x05, 0x0c,
+  0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x0a, 0x12, 0x13}},
+ {0x0fc6, 64, { 0x93, 0x8f, 0x1a, 0xef, 0x42, 0x37, 0x80, 0xca, 0x22, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c,
   0x74, 0x30, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0, 0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74,
-  0x27, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x20, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x07, 0xf0, 0xe4}},
- {0x1006, 64, { 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x22, 0xc0,
-  0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90, 0x7f,
-  0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0, 0x84,
-  0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82}},
- {0x1046, 64, { 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x11, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab,
-  0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32,
-  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74,
-  0x10, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44}},
- {0x1086, 64, { 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74,
-  0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98,
-  0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74,
-  0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90}},
- {0x10c6, 64, { 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00,
-  0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f,
-  0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5,
-  0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90}},
- {0x1106, 64, { 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90,
-  0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f,
-  0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0,
-  0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f}},
- {0x1146, 64, { 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0,
-  0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b,
-  0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0,
-  0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00}},
- {0x1186, 64, { 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22,
-  0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74,
-  0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54,
-  0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00}},
- {0x11c6, 64, { 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0e, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98,
-  0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74,
-  0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x17, 0xf0,
-  0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90, 0xc0, 0x00, 0xed}},
- {0x1206, 64, { 0xf0, 0x22, 0x12, 0x13, 0x29, 0x8f, 0x1a, 0x12, 0x13, 0x29, 0x8f, 0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60,
-  0x12, 0x12, 0x13, 0x29, 0x8f, 0x1a, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x07, 0x12, 0x13, 0x29, 0x8f,
-  0x1b, 0x80, 0xe8, 0xaf, 0x1a, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f,
-  0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0f, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0}},
- {0x1246, 64, { 0x90, 0x7f, 0x98, 0x74, 0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22, 0x12, 0x13, 0x7d, 0x8f, 0x1a,
-  0x12, 0x13, 0x7d, 0x8f, 0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x12, 0x12, 0x13, 0x7d, 0x8f, 0x1a,
-  0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x07, 0x12, 0x13, 0x7d, 0x8f, 0x1b, 0x80, 0xe8, 0xaf, 0x1a, 0x22,
-  0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x1a, 0x04, 0xe0}},
- {0x1286, 64, { 0x44, 0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x12, 0xfa, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0,
-  0xe0, 0x44, 0x04, 0xf0, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5, 0x3e, 0x54, 0x7f, 0xfd, 0x12, 0x11,
-  0xe3, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x3e, 0x44,
-  0x80, 0xfd, 0x12, 0x11, 0xe3, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5, 0x3f, 0x54, 0x7f, 0xfd}},
- {0x12c6, 64, { 0x12, 0x12, 0x2d, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x3f,
-  0x44, 0x80, 0xfd, 0x12, 0x12, 0x2d, 0x22, 0x05, 0x0e, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x14,
-  0x03, 0x00, 0x00, 0xc1, 0x11, 0xc1, 0x18, 0xc1, 0x95, 0xc1, 0x10, 0xc1, 0x16, 0x01, 0x0a, 0x00,
-  0xc1, 0x9b, 0x00, 0x8e, 0x18, 0x8f, 0x19, 0xe5, 0x19, 0x15, 0x19, 0xae, 0x18, 0x70, 0x02}},
- {0x1306, 64, { 0x15, 0x18, 0x4e, 0x60, 0x05, 0x12, 0x0d, 0x70, 0x80, 0xee, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0,
-  0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00, 0xe0,
-  0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f,
-  0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x15}},
- {0x1346, 64, { 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90, 0xc0, 0x00, 0xe0,
-  0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f,
-  0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0,
-  0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00}},
- {0x1386, 64, { 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f,
-  0x98, 0x74, 0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0e, 0xf0,
-  0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x12, 0x0f, 0xdf, 0x12, 0x0d, 0x81, 0x12, 0x0b, 0x52, 0x22,
-  0x53, 0xd8, 0xef, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+  0x27, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x20, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x07, 0xf0, 0xe4, 0x90,
+  0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x22}},
+ {0x1006, 64, { 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x11,
+  0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0,
+  0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84,
+  0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x18, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08}},
+ {0x1046, 64, { 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7f, 0x98,
+  0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90,
+  0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0,
+  0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0}},
+ {0x1086, 64, { 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0,
+  0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90,
+  0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0,
+  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22}},
+ {0x10c6, 64, { 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x14,
+  0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f,
+  0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf,
+  0xf0, 0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98}},
+ {0x1106, 64, { 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b,
+  0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x90, 0xc0, 0x00,
+  0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0,
+  0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f}},
+ {0x1146, 64, { 0x98, 0x74, 0x08, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45,
+  0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00,
+  0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f,
+  0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f}},
+ {0x1186, 64, { 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90,
+  0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0,
+  0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90,
+  0x7f, 0x98, 0x74, 0x0e, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b}},
+ {0x11c6, 64, { 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5,
+  0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x17, 0xf0, 0x90, 0xc0, 0x00,
+  0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22, 0x12, 0x13,
+  0x27, 0x8f, 0x1a, 0x12, 0x13, 0x27, 0x8f, 0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x12, 0x12}},
+ {0x1206, 64, { 0x13, 0x27, 0x8f, 0x1a, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x07, 0x12, 0x13, 0x27, 0x8f, 0x1b, 0x80, 0xe8,
+  0xaf, 0x1a, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00,
+  0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0f, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74,
+  0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22, 0x12, 0x13, 0x7b, 0x8f, 0x1a, 0x12, 0x13}},
+ {0x1246, 64, { 0x7b, 0x8f, 0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x12, 0x12, 0x13, 0x7b, 0x8f, 0x1a, 0xe5, 0x1a, 0x65,
+  0x1b, 0x60, 0x07, 0x12, 0x13, 0x7b, 0x8f, 0x1b, 0x80, 0xe8, 0xaf, 0x1a, 0x22, 0x90, 0x7f, 0xd6,
+  0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x1a, 0x04, 0xe0, 0x44, 0x02, 0xf0, 0x7f,
+  0xf4, 0x7e, 0x01, 0x12, 0x12, 0xe7, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0, 0xe0, 0x44}},
+ {0x1286, 64, { 0x04, 0xf0, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5, 0x3e, 0x54, 0x7f, 0xfd, 0x12, 0x11, 0xd0, 0x90, 0x7f,
+  0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x3e, 0x44, 0x80, 0xfd, 0x12,
+  0x11, 0xd0, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5, 0x3f, 0x54, 0x7f, 0xfd, 0x12, 0x12, 0x1a, 0x90,
+  0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x3f, 0x44, 0x80}},
+ {0x12c6, 64, { 0xfd, 0x12, 0x12, 0x1a, 0x22, 0x05, 0x0e, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x14, 0x03, 0x00, 0x00,
+  0xc1, 0x11, 0xc1, 0x18, 0xc1, 0x95, 0xc1, 0x10, 0xc1, 0x16, 0x01, 0x0a, 0x00, 0xc1, 0x9b, 0x00,
+  0x8e, 0x18, 0x8f, 0x19, 0xe5, 0x19, 0x15, 0x19, 0xae, 0x18, 0x70, 0x02, 0x15, 0x18, 0x4e, 0x60,
+  0x05, 0x12, 0x0d, 0x60, 0x80, 0xee, 0x22, 0x00, 0x00, 0x02, 0x10, 0x06, 0x00, 0x02, 0x13}},
+ {0x1306, 64, { 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x10, 0x2d, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0,
+  0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22,
+  0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74,
+  0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90}},
+ {0x1346, 64, { 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22,
+  0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74,
+  0x09, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x90, 0xc0,
+  0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff}},
+ {0x1386, 64, { 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74,
+  0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x0e, 0xf0, 0x90, 0xc0,
+  0x00, 0xe0, 0xff, 0x22, 0x12, 0x0f, 0xcf, 0x12, 0x0d, 0x71, 0x12, 0x0b, 0x4a, 0x22, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
  {0x13c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x40, 0x00, 0x02, 0x14}},
- {0x1406, 64, { 0x04, 0x00, 0x02, 0x10, 0x16, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1406, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
@@ -425,7 +426,7 @@
  {0x18c6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x01, 0xff, 0x00}},
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x10, 0x01, 0xff, 0x00}},
  {0x1906, 64, { 0x00, 0x40, 0xcd, 0x06, 0x10, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x02, 0x09, 0x02, 0x74, 0x00, 0x01,
   0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e, 0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01,
   0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40,
@@ -443,5 +444,5 @@
   0x00, 0x42, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c,
   0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x61, 0x00, 0x70, 0x00, 0x74, 0x00, 0x65, 0x00}},
  {0x1a06,  4, { 0x72, 0x00, 0x00, 0x00}},
- {0xffff,	0,	{0x00} }
+ {0xffff,  0, {0x00}}
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/keyspan_usa49msg.h linux-2.4.20/drivers/usb/serial/keyspan_usa49msg.h
--- linux-2.4.19/drivers/usb/serial/keyspan_usa49msg.h	2001-10-09 22:15:03.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/keyspan_usa49msg.h	2002-10-29 11:18:34.000000000 +0000
@@ -41,14 +41,10 @@
 
 	4th revision: USA49W version
 
-	See usa26msg.h for description of message formats
-
-	Third revision: USA28X version (aka USA26)
-
 	Buffer formats for RX/TX data messages are not defined by
 	a structure, but are described here:
 
-	USB OUT (host -> USA26, transmit) messages contain a 
+	USB OUT (host -> USAxx, transmit) messages contain a 
 	REQUEST_ACK indicator (set to 0xff to request an ACK at the 
 	completion of transmit; 0x00 otherwise), followed by data:
 
@@ -56,17 +52,28 @@
 
 	with a total data length of 63.
 
-	USB IN (USA26 -> host, receive) messages contain either a zero
-	flag (indicating no error in any data bytes):
+	USB IN (USAxx -> host, receive) messages begin with a status
+	byte in which the 0x80 bit is either:
+				   	
+		(a)	0x80 bit clear
+			indicates that the bytes following it are all data
+			bytes:
+
+				STAT DATA DATA DATA DATA DATA ...
+
+			for a total of up to 63 DATA bytes,
+
+	or:
 
-		00 DAT DAT DAT ...
+		(b)	0x80 bit set
+			indiates that the bytes following alternate data and
+			status bytes:
 
-	for a total of 63 data bytes, or a non-zero status flag (indicating 
-	that all data bytes will be preceded by status flag):
+				STAT DATA STAT DATA STAT DATA STAT DATA ...
 
-		STAT DAT STAT DAT STAT DAT ...
+			for a total of up to 32 DATA bytes.
 
-	for a total of 32 data bytes.  The valid bits in the STAT bytes are:
+	The valid bits in the STAT bytes are:
 
 		OVERRUN	0x02
 		PARITY	0x04
@@ -75,9 +82,19 @@
 
 	Notes:
 	
-	1.	a "no status" RX data message (first byte zero) can serve as
-		a "break off" indicator.
-	2.	a control message specifying disablePort will be answered
+	(1) The OVERRUN bit can appear in either (a) or (b) format
+		messages, but the but the PARITY/FRAMING/BREAK bits
+		only appear in (b) format messages.
+	(2) For the host to determine the exact point at which the
+		overrun occurred (to identify the point in the data
+		stream at which the data was lost), it needs to count
+		128 characters, starting at the first character of the
+		message in which OVERRUN was reported; the lost character(s)
+		would have been received between the 128th and 129th
+		characters.
+	(3)	An RX data message in which the first byte has 0x80 clear
+		serves as a "break off" indicator.
+	(4)	a control message specifying disablePort will be answered
 		with a status message, but no further status will be sent
 		until a control messages with enablePort is sent
 
@@ -92,6 +109,7 @@
 	2000mar09	change to support 4 ports
 	2000may03	change external clocking to match USA-49W hardware
 	2000jun01	add extended BSD-style copyright text
+	2001jul05	change message format to improve OVERRUN case
 */
 
 #ifndef	__USA49MSG__
@@ -107,7 +125,7 @@
 	0x80		globalControlMessage
 */
 
-typedef struct keyspan_usa49_portControlMessage
+struct keyspan_usa49_portControlMessage
 {
 	/*
 		0.	0/1/2/3 	port control message follows
@@ -173,7 +191,7 @@
 		enablePort,		// start servicing port (move data, check status)
 		disablePort;	// stop servicing port (does implicit tx/rx flush/off)
 	
-} keyspan_usa49_portControlMessage;
+};
 
 // defines for bits in lcr
 #define	USA_DATABITS_5		0x00
@@ -201,7 +219,7 @@
 	sends any control message (either global or port-specific).
 */
 
-typedef struct keyspan_usa49_globalControlMessage
+struct keyspan_usa49_globalControlMessage
 {
 	u8	portNumber,			// 0x80
 		sendGlobalStatus,	// 1/2=number of status responses requested
@@ -209,7 +227,7 @@
 		resetStatusCount,	// a cycling value
 		remoteWakeupEnable,		// 0x10=P1, 0x20=P2, 0x40=P3, 0x80=P4
 		disableStatusMessages;	// 1=send no status until host talks
-} keyspan_usa49_globalControlMessage;
+};
 
 /*
 	Device->host messages send on the global status endpoint
@@ -221,7 +239,7 @@
 	0x81				globalDebugMessage
 */
 
-typedef struct keyspan_usa49_portStatusMessage	// one for each port
+struct keyspan_usa49_portStatusMessage	// one for each port
 {
 	u8	portNumber,		// 0,1,2,3
 		cts,			// reports CTS pin
@@ -234,7 +252,7 @@
 		controlResponse,// 1=a control message has been processed
 		txAck,			// ACK (data TX complete)
 		rs232valid;		// RS-232 signal valid
-} keyspan_usa49_portStatusMessage;
+};
 
 // bits in RX data message when STAT byte is included
 #define	RXERROR_OVERRUN	0x02
@@ -242,19 +260,19 @@
 #define	RXERROR_FRAMING	0x08
 #define	RXERROR_BREAK	0x10
 
-typedef struct keyspan_usa49_globalStatusMessage
+struct keyspan_usa49_globalStatusMessage
 {
 	u8	portNumber,			// 0x80=globalStatusMessage
 		sendGlobalStatus,	// from request, decremented
 		resetStatusCount;	// as in request
-} keyspan_usa49_globalStatusMessage;
+};
 
-typedef struct keyspan_usa49_globalDebugMessage
+struct keyspan_usa49_globalDebugMessage
 {
 	u8	portNumber,			// 0x81=globalDebugMessage
 		n,					// typically a count/status byte
 		b;					// typically a data byte
-} keyspan_usa49_globalDebugMessage;
+};
 
 // ie: the maximum length of an EZUSB endpoint buffer
 #define	MAX_DATA_LEN			64
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/keyspan_usa49w_fw.h linux-2.4.20/drivers/usb/serial/keyspan_usa49w_fw.h
--- linux-2.4.19/drivers/usb/serial/keyspan_usa49w_fw.h	2001-10-09 22:15:03.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/keyspan_usa49w_fw.h	2002-10-29 11:18:34.000000000 +0000
@@ -1,43 +1,47 @@
 /* keyspan_usa49w_fw.h
-  
-   Generated from Keyspan firmware image usa49code.h Sat Oct  6 12:06:59 EST 2001
-   This firmware is for the Keyspan USA-49W Serial Adaptor
 
-   "The firmware contained herein as keyspan_usa49w_fw.h is
-   Copyright (C) 1999-2001 Keyspan, A division of InnoSys Incorporated
-   ("Keyspan"), as an unpublished work.  This notice does not imply
-   unrestricted or public access to this firmware which is a trade secret of
-   Keyspan, and which may not be reproduced, used, sold or transferred to any
-   third party without Keyspan's prior written consent.  All Rights Reserved.
+	The firmware contained herein as keyspan_usa49w_fw.h is
 
-   This firmware may not be modified and may only be used with the Keyspan 
-   USA-49W Serial Adapter.  Distribution and/or Modification of the
-   keyspan.c driver which includes this firmware, in whole or in part,
-   requires the inclusion of this statement."
+		Copyright (C) 1999-2001
+		Keyspan, A division of InnoSys Incorporated ("Keyspan")
+		
+	as an unpublished work. This notice does not imply unrestricted or
+	public access to the source code from which this firmware image is
+	derived.  Except as noted below this firmware image may not be 
+	reproduced, used, sold or transferred to any third party without 
+	Keyspan's prior written consent.  All Rights Reserved.
+
+	Permission is hereby granted for the distribution of this firmware 
+	image as part of a Linux or other Open Source operating system kernel 
+	in text or binary form as required. 
+
+	This firmware may not be modified and may only be used with  
+	Keyspan hardware.  Distribution and/or Modification of the 
+	keyspan.c driver which includes this firmware, in whole or in 
+	part, requires the inclusion of this statement."
 
 */
 
 static const struct ezusb_hex_record keyspan_usa49w_firmware[] = {
- {0x7f92,  1, { 0x01}},
- {0x0033,  3, { 0x02, 0x18, 0xfc}},
+ {0x0033,  3, { 0x02, 0x18, 0xfb}},
  {0x0036, 12, { 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22}},
  {0x0046, 16, { 0xe4, 0xff, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xfe, 0xe5, 0x15}},
  {0x0056, 16, { 0x24, 0x04, 0xfd, 0xe4, 0x35, 0x14, 0xfa, 0xa9, 0x05, 0x7b, 0x01, 0xef, 0x7c, 0x00, 0x29, 0xf9}},
- {0x0066, 16, { 0xec, 0x3a, 0xfa, 0xee, 0x12, 0x11, 0xf6, 0x0f, 0xbf, 0x22, 0xd7, 0xe5, 0x15, 0x24, 0x05, 0xf5}},
+ {0x0066, 16, { 0xec, 0x3a, 0xfa, 0xee, 0x12, 0x11, 0xf1, 0x0f, 0xbf, 0x22, 0xd7, 0xe5, 0x15, 0x24, 0x05, 0xf5}},
  {0x0076, 16, { 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x70, 0x03, 0x02, 0x01, 0x34, 0xe5, 0x15, 0x24, 0x09}},
  {0x0086, 16, { 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x70, 0x0e, 0xe5, 0x15, 0x24, 0x0a, 0xf5, 0x82}},
- {0x0096, 16, { 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x18, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x16, 0x4c, 0xe5}},
+ {0x0096, 16, { 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x18, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x16, 0x47, 0xe5}},
  {0x00a6, 16, { 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0xcf, 0xf0, 0x80, 0x41}},
- {0x00b6, 16, { 0xe5, 0x15, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x16, 0x7b}},
+ {0x00b6, 16, { 0xe5, 0x15, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x16, 0x76}},
  {0x00c6, 16, { 0xe5, 0x15, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x00, 0x03}},
  {0x00d6, 16, { 0x7f, 0x01, 0xe5, 0x15, 0x24, 0x08, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xfd, 0x12}},
- {0x00e6, 16, { 0x16, 0x4c, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x30}},
+ {0x00e6, 16, { 0x16, 0x47, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x30}},
  {0x00f6, 16, { 0xf0, 0xe5, 0x15, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0}},
  {0x0003, 16, { 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74}},
  {0x0013, 16, { 0x01, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x15, 0x24}},
  {0x0023, 16, { 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22}},
  {0x0043,  3, { 0x02, 0x1b, 0x00}},
- {0x0000,  3, { 0x02, 0x10, 0x9a}},
+ {0x0000,  3, { 0x02, 0x10, 0x95}},
  {0x0106, 64, { 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5, 0x15, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83,
   0xe0, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0, 0xe5, 0x15, 0x24, 0x36, 0xf5,
   0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x15, 0x24,
@@ -49,16 +53,16 @@
  {0x0186, 64, { 0x15, 0x24, 0x17, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x15, 0x24, 0x32,
   0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x04, 0xf0, 0x80, 0x0f, 0xe5, 0x15, 0x24,
   0x32, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0xfb, 0xf0, 0xe4, 0xff, 0xe5, 0x15,
-  0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xfd, 0x12, 0x16, 0x4c, 0xe5}},
+  0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xfd, 0x12, 0x16, 0x47, 0xe5}},
  {0x01c6, 64, { 0x15, 0x24, 0x0e, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x15, 0x24, 0x33,
   0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x0f, 0xe5, 0x15, 0x24,
   0x33, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0xe5, 0x15, 0x24, 0x33,
   0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xe5, 0x15, 0x24, 0x0f}},
  {0x0206, 64, { 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x2f, 0xe5, 0x15, 0x24, 0x33, 0xf5, 0x82, 0xe4,
   0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x15, 0x24, 0x10, 0xf5, 0x82, 0xe4, 0x35,
-  0x14, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x15, 0xec, 0xe5, 0x15, 0x24, 0x11, 0xf5, 0x82, 0xe4, 0x35,
-  0x14, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x16, 0x1c, 0xe5, 0x15, 0x24, 0x33, 0xf5, 0x82, 0xe4}},
- {0x0246, 64, { 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x15, 0xbc, 0xe5, 0x15, 0x24, 0x14, 0xf5, 0x82, 0xe4, 0x35,
+  0x14, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x15, 0xe7, 0xe5, 0x15, 0x24, 0x11, 0xf5, 0x82, 0xe4, 0x35,
+  0x14, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x16, 0x17, 0xe5, 0x15, 0x24, 0x33, 0xf5, 0x82, 0xe4}},
+ {0x0246, 64, { 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x15, 0xb7, 0xe5, 0x15, 0x24, 0x14, 0xf5, 0x82, 0xe4, 0x35,
   0x14, 0xf5, 0x83, 0xe0, 0x60, 0x44, 0xe5, 0x15, 0x24, 0x15, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5,
   0x83, 0xe0, 0x60, 0x11, 0xe5, 0x15, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0,
   0x44, 0x01, 0xf0, 0x80, 0x0f, 0xe5, 0x15, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5}},
@@ -84,12 +88,12 @@
   0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14}},
  {0x03c6, 64, { 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x12, 0x00,
   0x36, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x15, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35,
-  0x14, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x16, 0x4c, 0xe5, 0x15,
+  0x14, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x16, 0x47, 0xe5, 0x15,
   0x24, 0x2c, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x15, 0x24, 0x2b}},
  {0x0406, 64, { 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x16, 0x42, 0x13, 0xe5, 0x15, 0x24, 0x1b,
   0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x70, 0x0e, 0xe5, 0x15, 0x24, 0x25, 0xf5, 0x82,
   0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x28, 0xe5, 0x15, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35,
-  0x14, 0xf5, 0x83, 0xe0, 0x44, 0x02, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x16, 0x4c, 0xe5}},
+  0x14, 0xf5, 0x83, 0xe0, 0x44, 0x02, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x16, 0x47, 0xe5}},
  {0x0446, 64, { 0x15, 0x24, 0x2b, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5, 0x16, 0x42, 0x13,
   0xe5, 0x15, 0x24, 0x1c, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0x70, 0x0e, 0xe5,
   0x15, 0x24, 0x25, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x2a, 0x90, 0x78, 0x41,
@@ -100,12 +104,12 @@
   0xe0, 0x44, 0x40, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x15, 0x24, 0x37, 0xf5}},
  {0x04c6, 64, { 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x15, 0x24, 0x1e,
   0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x28, 0xe5, 0x15, 0x24, 0x32, 0xf5, 0x82,
-  0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x16, 0x4c,
+  0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x16, 0x47,
   0xe5, 0x15, 0x24, 0x2d, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5}},
  {0x0506, 64, { 0x16, 0x42, 0x13, 0xe5, 0x15, 0x24, 0x1f, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x70, 0x0e,
   0xe5, 0x15, 0x24, 0x25, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x27, 0xe5, 0x15,
   0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xff, 0xf0, 0xfd, 0xe4,
-  0xff, 0x12, 0x16, 0x4c, 0xe5, 0x15, 0x24, 0x2d, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83}},
+  0xff, 0x12, 0x16, 0x47, 0xe5, 0x15, 0x24, 0x2d, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83}},
  {0x0546, 64, { 0xe4, 0xf0, 0xe5, 0x16, 0x42, 0x13, 0xe5, 0x15, 0x24, 0x20, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83,
   0xe0, 0x70, 0x0e, 0xe5, 0x15, 0x24, 0x25, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60,
   0x18, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0, 0xe5, 0x15, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x14,
@@ -115,12 +119,12 @@
   0x83, 0xe0, 0x60, 0x1f, 0xe5, 0x15, 0x24, 0x2e, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74,
   0x01, 0xf0, 0xe5, 0x15, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe4, 0xf0}},
  {0x05c6, 64, { 0xe5, 0x16, 0x42, 0x13, 0xe5, 0x15, 0x24, 0x23, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60,
-  0x03, 0x12, 0x18, 0x91, 0xe5, 0x15, 0x24, 0x24, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0,
+  0x03, 0x12, 0x18, 0x85, 0xe5, 0x15, 0x24, 0x24, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0,
   0x60, 0x1b, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x08,
   0xf0, 0x90, 0x7f, 0x98, 0xe0, 0xff, 0xe5, 0x16, 0xf4, 0xfe, 0xef, 0x5e, 0xf0, 0xe5, 0x15}},
  {0x0606, 64, { 0x24, 0x25, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x16, 0xe5, 0x15, 0x24, 0x31, 0xf5,
   0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0x90, 0x7f, 0x98, 0xe0, 0x45, 0x16,
-  0xf0, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x12, 0x08, 0x07, 0x83, 0x00, 0x07, 0xf7, 0x01, 0x08,
+  0xf0, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x12, 0x03, 0x07, 0x83, 0x00, 0x07, 0xf7, 0x01, 0x08,
   0x63, 0x03, 0x06, 0x4c, 0x06, 0x07, 0x74, 0x08, 0x07, 0x68, 0x09, 0x07, 0x50, 0x0a, 0x07}},
  {0x0646, 64, { 0x5f, 0x0b, 0x00, 0x00, 0x08, 0xb2, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x1c, 0x14, 0x70, 0x03,
   0x02, 0x06, 0xfe, 0x24, 0x02, 0x60, 0x03, 0x02, 0x07, 0x46, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0,
@@ -133,14 +137,14 @@
  {0x06c6, 64, { 0xfe, 0x90, 0x7f, 0xee, 0xe0, 0x7c, 0x00, 0x24, 0x00, 0xf5, 0x19, 0xec, 0x3e, 0xf5, 0x18, 0x75, 0x33,
   0x19, 0x75, 0x34, 0x12, 0x75, 0x82, 0x14, 0x75, 0x83, 0x19, 0xe0, 0x75, 0x27, 0x00, 0xf5, 0x28,
   0xd3, 0xe5, 0x28, 0x95, 0x19, 0xe5, 0x27, 0x95, 0x18, 0x40, 0x06, 0x85, 0x18, 0x27, 0x85, 0x19,
-  0x28, 0x12, 0x13, 0x17, 0x02, 0x08, 0xb9, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x14, 0x30}},
+  0x28, 0x12, 0x13, 0x12, 0x02, 0x08, 0xb9, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x14, 0x2b}},
  {0x0706, 64, { 0xea, 0x49, 0x60, 0x32, 0x90, 0x7f, 0xee, 0xe0, 0x75, 0x18, 0x00, 0xf5, 0x19, 0xae, 0x02, 0xaf, 0x01,
   0x8e, 0x33, 0x8f, 0x34, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xfe, 0xa3, 0xe0, 0x8e, 0x27, 0xf5, 0x28,
   0xd3, 0x95, 0x19, 0xe5, 0x27, 0x95, 0x18, 0x40, 0x06, 0x85, 0x18, 0x27, 0x85, 0x19, 0x28, 0x12,
-  0x13, 0x17, 0x02, 0x08, 0xb9, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x08, 0xb9}},
+  0x13, 0x12, 0x02, 0x08, 0xb9, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x08, 0xb9}},
  {0x0746, 64, { 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x08, 0xb9, 0x90, 0x7f, 0x00, 0xe5, 0x25, 0xf0, 0x90,
   0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x08, 0xb9, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x25, 0x02, 0x08,
-  0xb9, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x22, 0x12, 0x0a, 0xbd, 0x02, 0x08, 0xb9, 0x90, 0x7f, 0x00,
+  0xb9, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x22, 0x12, 0x0a, 0xb8, 0x02, 0x08, 0xb9, 0x90, 0x7f, 0x00,
   0xe5, 0x22, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x08, 0xb9, 0x90, 0x7f, 0xe8}},
  {0x0786, 64, { 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2, 0x00, 0xe4, 0x33, 0xff,
   0x25, 0xe0, 0xff, 0xa2, 0x06, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90,
@@ -162,266 +166,266 @@
   0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0,
   0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44,
   0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22, 0xe5, 0x11, 0x54, 0x0f, 0x70}},
- {0x08c6, 64, { 0x03, 0x02, 0x09, 0xb2, 0x12, 0x16, 0xaa, 0xef, 0x20, 0xe1, 0x75, 0x12, 0x17, 0x08, 0xef, 0x14, 0xf5,
-  0x19, 0x12, 0x18, 0xd8, 0xef, 0x25, 0x19, 0xff, 0xe4, 0x33, 0xfe, 0xc3, 0xef, 0x94, 0x80, 0xee,
+ {0x08c6, 64, { 0x03, 0x02, 0x09, 0xb2, 0x12, 0x16, 0xa5, 0xef, 0x20, 0xe1, 0x75, 0x12, 0x17, 0x03, 0xef, 0x14, 0xf5,
+  0x19, 0x12, 0x18, 0xcc, 0xef, 0x25, 0x19, 0xff, 0xe4, 0x33, 0xfe, 0xc3, 0xef, 0x94, 0x80, 0xee,
   0x64, 0x80, 0x94, 0x80, 0x50, 0x59, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0xe0, 0xfe, 0xa3, 0xe0,
   0xff, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0x30, 0xe0, 0x11, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82}},
  {0x0906, 64, { 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x0f, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82,
   0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4,
   0x35, 0x14, 0xf5, 0x83, 0xe0, 0x20, 0xe2, 0x12, 0xe5, 0x19, 0x60, 0x0e, 0xf5, 0x23, 0xef, 0x24,
-  0x01, 0xf5, 0x2d, 0xe4, 0x3e, 0xf5, 0x2c, 0x12, 0x14, 0xb2, 0xe4, 0xff, 0x12, 0x14, 0xe8}},
+  0x01, 0xf5, 0x2d, 0xe4, 0x3e, 0xf5, 0x2c, 0x12, 0x14, 0xad, 0xe4, 0xff, 0x12, 0x14, 0xe3}},
  {0x0946, 64, { 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x30, 0xe7, 0x5d, 0x12, 0x18,
-  0xd8, 0xe5, 0x15, 0x24, 0x3b, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xfe, 0xef, 0xc3,
+  0xcc, 0xe5, 0x15, 0x24, 0x3b, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xfe, 0xef, 0xc3,
   0x9e, 0x50, 0x48, 0xe5, 0x15, 0x24, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x01,
   0xf0, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7b}},
  {0x0986, 64, { 0xf0, 0xe5, 0x15, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x16, 0x42,
   0x13, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1, 0x10, 0xe5, 0x15, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35,
-  0x14, 0xf5, 0x83, 0xe0, 0xf5, 0x24, 0x80, 0x03, 0x12, 0x12, 0xa6, 0x12, 0x16, 0xd9, 0xef, 0x30,
-  0xe1, 0x03, 0x02, 0x0a, 0xbc, 0xe5, 0x15, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5}},
- {0x09c6, 64, { 0x83, 0xe0, 0x54, 0x80, 0xf0, 0xe5, 0x15, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xc0,
-  0x83, 0xc0, 0x82, 0xe0, 0xfe, 0x12, 0x18, 0xe4, 0xee, 0x4f, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x12,
-  0x17, 0xde, 0x8f, 0x19, 0xe5, 0x15, 0x24, 0x35, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0,
-  0xfe, 0xef, 0xc3, 0x9e, 0x50, 0x28, 0x12, 0x18, 0xc0, 0xef, 0x30, 0xe0, 0x21, 0xe5, 0x15}},
- {0x0a06, 64, { 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x20, 0xe7, 0x12, 0xe5, 0x15, 0x24, 0x31,
-  0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x20, 0xe1, 0x03, 0x02, 0x0a, 0xbc, 0xe5, 0x15,
-  0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0xf0, 0xe5, 0x19, 0x70,
-  0x0e, 0xe5, 0x15, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe4, 0xf0, 0x22}},
- {0x0a46, 64, { 0xe5, 0x15, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0x30, 0xe7, 0x29, 0xe5,
-  0x19, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x23, 0x85, 0x15, 0x82, 0x85,
-  0x14, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0x8c, 0x2c, 0xf5, 0x2d, 0x12, 0x13, 0xe2, 0xe5,
-  0x19, 0x25, 0xe0, 0xff, 0x12, 0x15, 0x1e, 0x22, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03}},
- {0x0a86, 64, { 0x75, 0x19, 0x3f, 0x85, 0x19, 0x23, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0xa3, 0xa3, 0xe0, 0xfe, 0xa3,
-  0xe0, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0xa3, 0xa3, 0xe0,
-  0xfe, 0xa3, 0xe0, 0x24, 0x01, 0xf5, 0x2d, 0xe4, 0x3e, 0xf5, 0x2c, 0x12, 0x14, 0x71, 0xe5, 0x19,
-  0x04, 0xff, 0x12, 0x15, 0x1e, 0x22, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74}},
- {0x0ac6, 64, { 0xf0, 0xf0, 0x90, 0x7f, 0x96, 0xf0, 0xe4, 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x78, 0x4a, 0x04, 0xf0, 0xf5,
-  0x8e, 0x90, 0x7f, 0x95, 0x74, 0xc0, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98,
-  0x74, 0x1f, 0xf0, 0x90, 0x78, 0x43, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0x7f,
-  0xdf, 0x74, 0x9f, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02, 0xf0}},
- {0x0b06, 64, { 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x14, 0x7b, 0x75, 0x15, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75,
-  0x16, 0x01, 0x12, 0x0f, 0x17, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x14, 0x7b, 0x75, 0x15, 0xc0, 0x90,
-  0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x16, 0x01, 0xe5, 0x15, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35,
-  0x14, 0xf5, 0x83, 0xe4, 0xf0, 0x7e, 0x7e, 0x7f, 0x40, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83}},
- {0x0b46, 64, { 0x74, 0x7e, 0xf0, 0xa3, 0x74, 0x40, 0xf0, 0x7e, 0x7e, 0x7f, 0x80, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83,
-  0xa3, 0xa3, 0x74, 0x7e, 0xf0, 0xa3, 0x74, 0x80, 0xf0, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x14, 0x7c,
-  0x75, 0x15, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x16, 0x02, 0x12, 0x0f, 0x17, 0x7e,
-  0x7c, 0x7f, 0x00, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0}},
- {0x0b86, 64, { 0x75, 0x16, 0x02, 0xe5, 0x15, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x01, 0xf0,
-  0x7e, 0x7d, 0x7f, 0xc0, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0xc0,
-  0xf0, 0x7e, 0x7e, 0x7f, 0x00, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0xa3, 0xa3, 0x74, 0x7e, 0xf0,
-  0xa3, 0x74, 0x00, 0xf0, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x40, 0x90}},
- {0x0bc6, 64, { 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x16, 0x04, 0x12, 0x0f, 0x17, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x14,
-  0x7c, 0x75, 0x15, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x16, 0x04, 0xe5, 0x15, 0x24,
-  0x26, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x02, 0xf0, 0x7e, 0x7d, 0x7f, 0x40, 0x85,
-  0x15, 0x82, 0x85, 0x14, 0x83, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0x40, 0xf0, 0x7e, 0x7d, 0x7f}},
- {0x0c06, 64, { 0x80, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0xa3, 0xa3, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0x80, 0xf0, 0x7e,
-  0x7c, 0x7f, 0x80, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75,
-  0x16, 0x08, 0x12, 0x0f, 0x17, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x80, 0x90,
-  0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75, 0x16, 0x08, 0xe5, 0x15, 0x24, 0x26, 0xf5, 0x82, 0xe4}},
- {0x0c46, 64, { 0x35, 0x14, 0xf5, 0x83, 0x74, 0x03, 0xf0, 0x7e, 0x7c, 0x7f, 0xc0, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83,
-  0x74, 0x7c, 0xf0, 0xa3, 0x74, 0xc0, 0xf0, 0x7e, 0x7d, 0x7f, 0x00, 0x85, 0x15, 0x82, 0x85, 0x14,
-  0x83, 0xa3, 0xa3, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0x00, 0xf0, 0xc2, 0x0a, 0xc2, 0x09, 0xd2, 0x02,
-  0x22, 0xe5, 0x10, 0x04, 0x54, 0x03, 0xf5, 0x10, 0x14, 0x60, 0x1f, 0x14, 0x60, 0x31, 0x14}},
- {0x0c86, 64, { 0x60, 0x43, 0x24, 0x03, 0x70, 0x52, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x14, 0x7b, 0x75, 0x15, 0xc0, 0x90,
-  0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x16, 0x01, 0x80, 0x3d, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x14,
-  0x7c, 0x75, 0x15, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x16, 0x02, 0x80, 0x28, 0x7e,
+  0x14, 0xf5, 0x83, 0xe0, 0xf5, 0x24, 0x80, 0x03, 0x12, 0x12, 0xa1, 0x12, 0x16, 0xd4, 0xef, 0x30,
+  0xe1, 0x03, 0x02, 0x0a, 0xb7, 0x12, 0x17, 0xd2, 0x8f, 0x19, 0x12, 0x18, 0xd8, 0xe5, 0x15}},
+ {0x09c6, 64, { 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x15, 0x24, 0x35, 0xf5, 0x82,
+  0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x19, 0xc3, 0x9f, 0x50, 0x28, 0x12, 0x18, 0xb4,
+  0xef, 0x30, 0xe0, 0x21, 0xe5, 0x15, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0,
+  0x20, 0xe7, 0x12, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0}},
+ {0x0a06, 64, { 0x20, 0xe1, 0x03, 0x02, 0x0a, 0xb7, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83,
+  0xe0, 0x54, 0xfd, 0xf0, 0xe5, 0x19, 0x70, 0x03, 0x02, 0x0a, 0xb7, 0xb4, 0x80, 0x0f, 0xe5, 0x15,
+  0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x15, 0x24,
+  0x38, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0x30, 0xe7, 0x29, 0xe5, 0x19}},
+ {0x0a46, 64, { 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x23, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83,
+  0xa3, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0x8c, 0x2c, 0xf5, 0x2d, 0x12, 0x13, 0xdd, 0xe5, 0x19, 0x25,
+  0xe0, 0xff, 0x12, 0x15, 0x19, 0x22, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75, 0x19, 0x3f,
+  0x85, 0x19, 0x23, 0xe5, 0x15, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0}},
+ {0x0a86, 64, { 0xff, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0xf5, 0x82, 0x8c, 0x83,
+  0xef, 0xf0, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0x24, 0x01,
+  0xf5, 0x2d, 0xe4, 0x3e, 0xf5, 0x2c, 0x12, 0x14, 0x6c, 0xe5, 0x19, 0x04, 0xff, 0x12, 0x15, 0x19,
+  0x22, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xf0, 0xf0, 0x90, 0x7f, 0x96}},
+ {0x0ac6, 64, { 0xf0, 0xe4, 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x78, 0x4a, 0x04, 0xf0, 0xf5, 0x8e, 0x90, 0x7f, 0x95, 0x74,
+  0xc0, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x1f, 0xf0, 0x90, 0x78,
+  0x43, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0x7f, 0xdf, 0x74, 0x9f, 0xf0, 0x90,
+  0x7f, 0xde, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02, 0xf0, 0x7e, 0x7b, 0x7f, 0xc0, 0x75}},
+ {0x0b06, 64, { 0x14, 0x7b, 0x75, 0x15, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x16, 0x01, 0x12, 0x0f, 0x12,
+  0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x14, 0x7b, 0x75, 0x15, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0,
+  0x75, 0x16, 0x01, 0xe5, 0x15, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe4, 0xf0,
+  0x7e, 0x7e, 0x7f, 0x40, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0x74, 0x7e, 0xf0, 0xa3, 0x74}},
+ {0x0b46, 64, { 0x40, 0xf0, 0x7e, 0x7e, 0x7f, 0x80, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0xa3, 0xa3, 0x74, 0x7e, 0xf0,
+  0xa3, 0x74, 0x80, 0xf0, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x00, 0x90, 0x7f,
+  0x96, 0x74, 0xdf, 0xf0, 0x75, 0x16, 0x02, 0x12, 0x0f, 0x12, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x14,
+  0x7c, 0x75, 0x15, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x16, 0x02, 0xe5, 0x15}},
+ {0x0b86, 64, { 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x7e, 0x7d, 0x7f, 0xc0, 0x85,
+  0x15, 0x82, 0x85, 0x14, 0x83, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0xc0, 0xf0, 0x7e, 0x7e, 0x7f, 0x00,
+  0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0xa3, 0xa3, 0x74, 0x7e, 0xf0, 0xa3, 0x74, 0x00, 0xf0, 0x7e,
   0x7c, 0x7f, 0x40, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0}},
- {0x0cc6, 64, { 0x75, 0x16, 0x04, 0x80, 0x13, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x80, 0x90, 0x7f,
-  0x96, 0x74, 0x7f, 0xf0, 0x75, 0x16, 0x08, 0xe5, 0x32, 0x55, 0x16, 0x70, 0x03, 0x02, 0x0e, 0x16,
-  0xe5, 0x16, 0xf4, 0xff, 0x52, 0x32, 0xe5, 0x26, 0x54, 0x7f, 0xfe, 0x70, 0x0f, 0xe5, 0x2a, 0x55,
-  0x16, 0x60, 0x24, 0x90, 0x7f, 0x98, 0xe0, 0x45, 0x16, 0xf0, 0x80, 0x1b, 0xbe, 0x20, 0x18}},
- {0x0d06, 64, { 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x30, 0xe3, 0x09, 0xe4, 0xf5,
-  0x2a, 0x90, 0x7f, 0x98, 0xe0, 0x5f, 0xf0, 0xe5, 0x15, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x14,
-  0xf5, 0x83, 0xe0, 0x60, 0x03, 0xe0, 0x14, 0xf0, 0xe5, 0x15, 0x24, 0x34, 0xf5, 0x82, 0xe4, 0x35,
-  0x14, 0xf5, 0x83, 0xe0, 0x60, 0x03, 0xe0, 0x14, 0xf0, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0x16}},
- {0x0d46, 64, { 0x74, 0x0a, 0xf0, 0x12, 0x00, 0x36, 0xef, 0x54, 0x01, 0xff, 0xf5, 0x19, 0xe5, 0x15, 0x24, 0x2c, 0xf5,
-  0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x07, 0xe5, 0x19, 0xf0, 0xe5, 0x16, 0x42,
-  0x13, 0x12, 0x18, 0xf0, 0x8f, 0x19, 0xe5, 0x15, 0x24, 0x27, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5,
-  0x83, 0xe0, 0xff, 0xe5, 0x19, 0x54, 0x10, 0xfe, 0x6f, 0x60, 0x06, 0xee, 0xf0, 0xe5, 0x16}},
- {0x0d86, 64, { 0x42, 0x13, 0xe5, 0x15, 0x24, 0x28, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x19,
-  0x54, 0x80, 0xfe, 0x6f, 0x60, 0x06, 0xee, 0xf0, 0xe5, 0x16, 0x42, 0x13, 0xe5, 0x15, 0x24, 0x29,
-  0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x19, 0x54, 0x20, 0xfe, 0x6f, 0x60,
-  0x15, 0xee, 0xf0, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0}},
- {0x0dc6, 64, { 0x30, 0xe4, 0x04, 0xe5, 0x16, 0x42, 0x13, 0xe5, 0x12, 0x55, 0x16, 0xff, 0xf5, 0x19, 0xe5, 0x15, 0x24,
-  0x2a, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x16, 0xe5, 0x19, 0xf0, 0xe5,
-  0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x30, 0xe5, 0x04, 0xe5, 0x16,
-  0x42, 0x13, 0xe5, 0x17, 0x55, 0x16, 0xff, 0xf5, 0x19, 0xe5, 0x15, 0x24, 0x30, 0xf5, 0x82}},
- {0x0e06, 64, { 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x07, 0xe5, 0x19, 0xf0, 0xe5, 0x16, 0x42, 0x13, 0x22,
-  0x30, 0x09, 0x03, 0x02, 0x0f, 0x16, 0xe5, 0x24, 0x14, 0x60, 0x2a, 0x14, 0x60, 0x41, 0x14, 0x60,
-  0x58, 0x14, 0x60, 0x6f, 0x24, 0x04, 0x60, 0x03, 0x02, 0x0e, 0xd4, 0x7e, 0x7b, 0x7f, 0xc0, 0x75,
-  0x14, 0x7b, 0x75, 0x15, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x16, 0x01, 0x12}},
- {0x0e46, 64, { 0x12, 0xa6, 0x75, 0x24, 0x01, 0x22, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x00, 0x90,
-  0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x16, 0x02, 0x12, 0x12, 0xa6, 0x75, 0x24, 0x02, 0x22, 0x7e,
-  0x7c, 0x7f, 0x40, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75,
-  0x16, 0x04, 0x12, 0x12, 0xa6, 0x75, 0x24, 0x03, 0x22, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x14}},
- {0x0e86, 64, { 0x7c, 0x75, 0x15, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75, 0x16, 0x08, 0x12, 0x12, 0xa6, 0x75,
-  0x24, 0x04, 0x22, 0x30, 0x04, 0x33, 0xc2, 0x04, 0x53, 0x13, 0xdf, 0xe4, 0xf5, 0x19, 0x7e, 0x00,
-  0x7b, 0x00, 0x74, 0x2e, 0x25, 0x19, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x11, 0xb0, 0xff, 0x74,
-  0x80, 0x25, 0x19, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x19, 0xe5}},
- {0x0ec6, 64, { 0x19, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0x75, 0x24, 0x05, 0x22, 0xe5, 0x36, 0x60,
-  0x3b, 0xd5, 0x36, 0x0a, 0x53, 0x13, 0xef, 0x30, 0x0a, 0x04, 0xd2, 0x09, 0xc2, 0x0a, 0xe4, 0xf5,
-  0x19, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x35, 0x25, 0x19, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x11,
-  0xb0, 0xff, 0x74, 0x80, 0x25, 0x19, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0}},
- {0x0f06, 64, { 0x05, 0x19, 0xe5, 0x19, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4, 0xf5, 0x24, 0x22,
-  0xe4, 0xf5, 0x1a, 0x7e, 0x00, 0x7b, 0x01, 0xe5, 0x15, 0x25, 0x1a, 0xf9, 0xee, 0x35, 0x14, 0xfa,
-  0xe4, 0x12, 0x11, 0xf6, 0x05, 0x1a, 0xe5, 0x1a, 0xb4, 0x3c, 0xe8, 0xe5, 0x15, 0x24, 0x35, 0xf5,
-  0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0}},
- {0x0f46, 64, { 0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00,
-  0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x16, 0x4c, 0x7f, 0x10, 0xe5, 0x15, 0x24, 0x33, 0xf5, 0x82,
-  0xe4, 0x35, 0x14, 0xf5, 0x83, 0xef, 0xf0, 0x12, 0x15, 0xbc, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0,
-  0x7f, 0x01, 0xe5, 0x15, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xef, 0xf0}},
- {0x0f86, 64, { 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5, 0x15, 0x24, 0x39, 0xf5,
-  0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x80, 0xf0, 0x90, 0xc0, 0x00, 0xf0, 0x0f, 0xe4, 0xfd,
-  0x12, 0x16, 0x4c, 0xe4, 0xff, 0x7e, 0xa3, 0xe5, 0x15, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x14,
-  0xf5, 0x83, 0xee, 0xf0, 0xfd, 0x12, 0x16, 0x4c, 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x90}},
- {0x0fc6, 64, { 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x16, 0x4c, 0x7f, 0x01, 0x12, 0x15, 0x54, 0x7f,
-  0x03, 0x7d, 0x07, 0x12, 0x16, 0x4c, 0x22, 0x53, 0x13, 0x3f, 0x90, 0x7b, 0xf1, 0xe0, 0x30, 0xe3,
-  0x16, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x14, 0x7b, 0x75, 0x15, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef,
-  0xf0, 0x75, 0x16, 0x01, 0x12, 0x08, 0xc1, 0x90, 0x7c, 0x31, 0xe0, 0x30, 0xe3, 0x16, 0x7e}},
- {0x1006, 64, { 0x7c, 0x7f, 0x00, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x16,
-  0x02, 0x12, 0x08, 0xc1, 0x90, 0x7c, 0x71, 0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7c, 0x7f, 0x40, 0x75,
-  0x14, 0x7c, 0x75, 0x15, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x16, 0x04, 0x12, 0x08,
-  0xc1, 0x90, 0x7c, 0xb1, 0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x14, 0x7c}},
- {0x1046, 64, { 0x75, 0x15, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75, 0x16, 0x08, 0x12, 0x08, 0xc1, 0x05, 0x11,
-  0xe5, 0x11, 0x54, 0x0f, 0xf5, 0x18, 0x70, 0x1f, 0x90, 0x78, 0x41, 0xe0, 0x54, 0xf7, 0xf0, 0x90,
-  0x7f, 0x99, 0xe0, 0xf5, 0x17, 0x90, 0x78, 0x41, 0xe0, 0x44, 0x08, 0xf0, 0x90, 0x7f, 0x99, 0xe0,
-  0xf4, 0xf5, 0x12, 0x12, 0x11, 0x26, 0x22, 0xe5, 0x18, 0xb4, 0x01, 0x04, 0x12, 0x0c, 0x78}},
- {0x1086, 64, { 0x22, 0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x08, 0xe5, 0x13, 0x60, 0x04, 0x12, 0x0e, 0x17, 0x22, 0x12,
-  0x0c, 0x78, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x37, 0x02, 0x10, 0xe1, 0x02,
-  0x12, 0x2e, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2, 0x08,
-  0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33}},
- {0x10c6, 64, { 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4,
-  0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x18, 0x5c, 0xe4, 0x7e, 0x01,
-  0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93, 0xa3,
-  0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3}},
- {0x1106, 64, { 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0,
-  0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe, 0x90,
-  0x7f, 0xd2, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x11, 0xaf, 0xc2, 0x09, 0x90, 0x7b, 0x40, 0xe0, 0x14,
-  0x60, 0x26, 0x14, 0x60, 0x3b, 0x14, 0x60, 0x50, 0x24, 0x83, 0x60, 0x64, 0x24, 0x80, 0x70}},
- {0x1146, 64, { 0x63, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x14, 0x7b, 0x75, 0x15, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0,
-  0x75, 0x16, 0x01, 0x12, 0x00, 0x46, 0x80, 0x4b, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x14, 0x7c, 0x75,
-  0x15, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x16, 0x02, 0x12, 0x00, 0x46, 0x80, 0x33,
-  0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf}},
- {0x1186, 64, { 0xf0, 0x75, 0x16, 0x04, 0x12, 0x00, 0x46, 0x80, 0x1b, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x14, 0x7c, 0x75,
-  0x15, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75, 0x16, 0x08, 0x12, 0x00, 0x46, 0x80, 0x03,
-  0x12, 0x17, 0x8f, 0xe4, 0x90, 0x7f, 0xd3, 0xf0, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83,
-  0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83}},
- {0x11c6, 64, { 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0,
-  0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8,
-  0xe2, 0x22, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb,
-  0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01}},
- {0x1206, 64, { 0xf3, 0x22, 0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3,
-  0xa3, 0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68,
-  0x60, 0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92, 0x00, 0xe4,
-  0x33, 0xfe, 0xef, 0x4e, 0xf0, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74, 0x01}},
- {0x1246, 64, { 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f,
-  0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaf, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0x74, 0x0d,
-  0xf0, 0xd2, 0xaf, 0xd2, 0x0b, 0x12, 0x18, 0x20, 0xc2, 0x01, 0xe4, 0xf5, 0x2b, 0xf5, 0x31, 0xc2,
-  0x07, 0xc2, 0x02, 0x75, 0x29, 0xf0, 0x90, 0x7f, 0xd8, 0xe0, 0x65, 0x26, 0x60, 0x06, 0x75}},
- {0x1286, 64, { 0x32, 0x0f, 0xe0, 0xf5, 0x26, 0x30, 0x02, 0x03, 0x12, 0x0f, 0xde, 0x30, 0x01, 0x07, 0xc2, 0x01, 0x12,
-  0x06, 0x29, 0x80, 0xe2, 0x30, 0x08, 0xdf, 0xc2, 0x08, 0x12, 0x18, 0x41, 0x80, 0xd8, 0x22, 0xe5,
-  0x13, 0x55, 0x16, 0x60, 0x6a, 0xe5, 0x15, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83,
-  0xe0, 0x70, 0x5c, 0xe5, 0x16, 0xf4, 0x52, 0x13, 0xe5, 0x15, 0x24, 0x26, 0xff, 0xe4, 0x35}},
- {0x12c6, 64, { 0x14, 0xfe, 0xe4, 0xfd, 0x0f, 0xef, 0xaa, 0x06, 0x70, 0x01, 0x0e, 0x14, 0xf5, 0x82, 0x8a, 0x83, 0xe0,
-  0xfc, 0x74, 0x80, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xec, 0xf0, 0x0d, 0xbd, 0x0b,
-  0xe2, 0x90, 0x7f, 0xc3, 0x74, 0x0b, 0xf0, 0xe5, 0x15, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x14,
-  0xf5, 0x83, 0x74, 0x10, 0xf0, 0xe5, 0x15, 0x24, 0x2e, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5}},
- {0x1306, 64, { 0x83, 0xe4, 0xf0, 0xe5, 0x15, 0x24, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe4, 0xf0, 0x22,
-  0xe5, 0x28, 0x45, 0x27, 0x60, 0x57, 0xae, 0x27, 0xaf, 0x28, 0xd3, 0xef, 0x94, 0x40, 0xee, 0x94,
-  0x00, 0x40, 0x04, 0x7e, 0x00, 0x7f, 0x40, 0xc3, 0xe5, 0x28, 0x9f, 0xf5, 0x28, 0xe5, 0x27, 0x9e,
-  0xf5, 0x27, 0xe4, 0xfd, 0xed, 0xc3, 0x9f, 0xe4, 0x9e, 0x50, 0x1f, 0x85, 0x34, 0x82, 0x85}},
- {0x1346, 64, { 0x33, 0x83, 0xe0, 0xfc, 0x74, 0x00, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xec, 0xf0, 0x0d,
-  0x05, 0x34, 0xe5, 0x34, 0x70, 0x02, 0x05, 0x33, 0x80, 0xda, 0x90, 0x7f, 0xa9, 0x74, 0x01, 0xf0,
-  0x90, 0x7f, 0xac, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xef, 0xf0, 0x22, 0x90, 0x7f, 0xac,
-  0xe0, 0x54, 0xfe, 0xf0, 0xe4, 0x90, 0x7f, 0xb5, 0xf0, 0x22, 0xe4, 0x90, 0x7f, 0x93, 0xf0}},
- {0x1386, 64, { 0x90, 0x7f, 0x9c, 0x74, 0xf0, 0xf0, 0x90, 0x7f, 0x96, 0xf0, 0xe4, 0x90, 0x78, 0x4a, 0xf0, 0x90, 0x7f,
-  0x94, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x30, 0x00, 0x07,
-  0xe5, 0x29, 0x54, 0xf0, 0xff, 0x80, 0x02, 0x7f, 0x00, 0xef, 0x44, 0x08, 0x90, 0x78, 0x41, 0xf0,
-  0xe4, 0x90, 0x7f, 0x98, 0xf0, 0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0xff, 0xf0}},
- {0x13c6, 64, { 0xe4, 0x90, 0x7f, 0x98, 0xf0, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xf0, 0xf0, 0xe4, 0x90,
-  0x7f, 0x96, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0x54, 0xfd, 0xf0, 0x22, 0x8f, 0x1a, 0x05, 0x2d, 0xe5,
-  0x2d, 0xae, 0x2c, 0x70, 0x02, 0x05, 0x2c, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x1a, 0xf0, 0x12,
-  0x1a, 0x08, 0x05, 0x2d, 0xe5, 0x2d, 0xac, 0x2c, 0x70, 0x02, 0x05, 0x2c, 0x14, 0xf5, 0x82}},
- {0x1406, 64, { 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x23, 0xe5, 0x23, 0x60, 0x1f, 0xe5, 0x15, 0x24, 0x38, 0xf5, 0x82, 0xe4,
-  0x35, 0x14, 0xf5, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfe, 0x12, 0x18, 0xe4, 0x8f, 0x1a, 0xee,
-  0x4f, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x80, 0xb5, 0x22, 0x8f, 0x1a, 0xe4, 0xf5, 0x1b, 0x75, 0x1c,
-  0xff, 0x75, 0x1d, 0x19, 0x75, 0x1e, 0x86, 0xab, 0x1c, 0xaa, 0x1d, 0xa9, 0x1e, 0x90, 0x00}},
- {0x1446, 64, { 0x01, 0x12, 0x11, 0xc9, 0xb4, 0x03, 0x1d, 0xaf, 0x1b, 0x05, 0x1b, 0xef, 0xb5, 0x1a, 0x01, 0x22, 0x12,
-  0x11, 0xb0, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75, 0x1c, 0xff, 0xf5, 0x1d, 0x89,
-  0x1e, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x22, 0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90,
-  0x78, 0x4f, 0x74, 0xc0, 0xf0, 0xe4, 0x90, 0x78, 0x50, 0xf0, 0xe5, 0x2c, 0x90, 0x78, 0x51}},
- {0x1486, 64, { 0xf0, 0xae, 0x2c, 0xe5, 0x2d, 0x90, 0x78, 0x52, 0xf0, 0x90, 0x78, 0x54, 0xe5, 0x23, 0xf0, 0x90, 0x78,
-  0x57, 0x74, 0x04, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x10, 0xf0, 0xe0, 0x54, 0xf7, 0xf0, 0xe4,
-  0x90, 0x78, 0x55, 0xf0, 0x90, 0x78, 0x55, 0xe0, 0x60, 0xfa, 0x22, 0xe4, 0x90, 0x78, 0x41, 0xf0,
-  0xe5, 0x2c, 0x90, 0x78, 0x4f, 0xf0, 0xae, 0x2c, 0xe5, 0x2d, 0x90, 0x78, 0x50, 0xf0, 0x90}},
- {0x14c6, 64, { 0x78, 0x51, 0x74, 0xc0, 0xf0, 0xe4, 0x90, 0x78, 0x52, 0xf0, 0x90, 0x78, 0x54, 0xe5, 0x23, 0xf0, 0x90,
-  0x78, 0x57, 0x74, 0x04, 0xf0, 0xe4, 0x90, 0x78, 0x55, 0xf0, 0x90, 0x78, 0x55, 0xe0, 0x60, 0xfa,
-  0x22, 0xe5, 0x15, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0f,
-  0x14, 0x60, 0x13, 0x14, 0x60, 0x17, 0x80, 0x00, 0x90, 0x7f, 0xc7, 0xef, 0xf0, 0x80, 0x13}},
- {0x1506, 64, { 0x90, 0x7f, 0xc9, 0xef, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xcb, 0xef, 0xf0, 0x80, 0x05, 0x90, 0x7f, 0xcd,
-  0xef, 0xf0, 0xe5, 0x16, 0x42, 0x2a, 0x22, 0xe5, 0x15, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x14,
-  0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0f, 0x14, 0x60, 0x13, 0x14, 0x60, 0x17, 0x80, 0x00, 0x90, 0x7f,
-  0xb7, 0xef, 0xf0, 0x80, 0x13, 0x90, 0x7f, 0xb9, 0xef, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xbb}},
- {0x1546, 64, { 0xef, 0xf0, 0x80, 0x05, 0x90, 0x7f, 0xbd, 0xef, 0xf0, 0xe5, 0x16, 0x42, 0x2a, 0x22, 0xae, 0x07, 0xe4,
-  0xff, 0xe5, 0x15, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0xfd,
-  0x12, 0x16, 0x4c, 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5,
-  0x15, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xfd, 0x12}},
- {0x1586, 64, { 0x16, 0x4c, 0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86,
-  0x75, 0x86, 0x00, 0xc0, 0xd0, 0x75, 0xd0, 0x08, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x01,
-  0xf0, 0x12, 0x13, 0x17, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83,
-  0xd0, 0xf0, 0xd0, 0xe0, 0x32, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74}},
- {0x15c6, 64, { 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74,
-  0x03, 0xf0, 0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f,
-  0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf,
-  0xf0, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41}},
- {0x1606, 64, { 0x74, 0x03, 0xf0, 0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f,
-  0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf,
-  0xf0, 0x90, 0x78, 0x41, 0x74, 0x06, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74,
-  0x03, 0xf0, 0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54}},
- {0x1646, 64, { 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x15, 0x24, 0x37, 0xf5,
-  0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41,
-  0x74, 0x07, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x05, 0xf0, 0x90, 0xc0,
-  0x00, 0xed, 0xf0, 0x22, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf}},
- {0x1686, 64, { 0xf0, 0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0,
-  0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0,
-  0x00, 0xf0, 0x22, 0xe5, 0x15, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x14,
-  0x60, 0x0e, 0x14, 0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xc6, 0xe0, 0xff}},
- {0x16c6, 64, { 0x22, 0x90, 0x7f, 0xc8, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xca, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcc, 0xe0,
-  0xff, 0x22, 0xe5, 0x15, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x14, 0x60,
-  0x0e, 0x14, 0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xb6, 0xe0, 0xff, 0x22, 0x90,
-  0x7f, 0xb8, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xba, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xbc, 0xe0}},
- {0x1706, 64, { 0xff, 0x22, 0xe5, 0x15, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0e,
-  0x14, 0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xc7, 0xe0, 0xff, 0x22, 0x90, 0x7f,
-  0xc9, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcb, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcd, 0xe0, 0xff, 0x22,
-  0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00}},
- {0x1746, 64, { 0x30, 0x05, 0x04, 0xc2, 0x05, 0x80, 0x02, 0xd2, 0x08, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08,
-  0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0,
-  0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90, 0x7f, 0xc4,
-  0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0, 0x84}},
- {0x1786, 64, { 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7b, 0x41, 0xe0, 0xf5, 0x36, 0x43, 0x13,
-  0x10, 0xa3, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7, 0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0x90, 0x7b,
-  0x43, 0xe0, 0xf5, 0x37, 0xa3, 0xe0, 0x54, 0xf0, 0xf5, 0x29, 0xe0, 0x60, 0x02, 0xd2, 0x0a, 0x22,
-  0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00}},
- {0x17c6, 64, { 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85,
-  0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x12, 0x18, 0xcc, 0xae, 0x07, 0x12, 0x18, 0xcc, 0xad,
-  0x07, 0xee, 0x6d, 0x60, 0x10, 0x12, 0x18, 0xcc, 0xae, 0x07, 0xee, 0x6d, 0x60, 0x07, 0x12, 0x18,
-  0xcc, 0xad, 0x07, 0x80, 0xec, 0xaf, 0x06, 0x22, 0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5}},
- {0x1806, 64, { 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0,
-  0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x04, 0xf0,
-  0xe0, 0x44, 0x08, 0xf0, 0x30, 0x0b, 0x04, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12,
-  0x18, 0x77, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0, 0x22, 0x12, 0x13, 0x81, 0x12, 0x18}},
- {0x1846, 64, { 0x10, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x0a, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x18, 0x77, 0x12, 0x18,
-  0xaa, 0x12, 0x0a, 0xbd, 0x22, 0x03, 0x35, 0x80, 0x00, 0x00, 0x03, 0x2e, 0x81, 0x00, 0x00, 0xc1,
-  0x85, 0xc1, 0x81, 0xc1, 0x08, 0xc1, 0x00, 0xc1, 0x06, 0x01, 0x22, 0x00, 0x01, 0x24, 0x00, 0x00,
-  0x8e, 0x18, 0x8f, 0x19, 0xe5, 0x19, 0x15, 0x19, 0xae, 0x18, 0x70, 0x02, 0x15, 0x18, 0x4e}},
- {0x1886, 64, { 0x60, 0x08, 0x12, 0x17, 0xff, 0x12, 0x17, 0xff, 0x80, 0xeb, 0x22, 0xe5, 0x15, 0x24, 0x04, 0xf5, 0x82,
-  0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x04, 0xff, 0x44, 0x10, 0x90, 0x7f, 0xd7, 0xf0, 0xef, 0x44,
-  0x30, 0xf0, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x0d, 0x7e, 0x00, 0x12, 0x18,
-  0x77, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0}},
- {0x18c6, 64, { 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff,
-  0x22, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x78, 0x41,
-  0x74, 0x05, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x78, 0x41, 0x74, 0x06, 0xf0, 0x90,
-  0xc0, 0x00, 0xe0, 0xff, 0x22, 0x53, 0xd8, 0xef, 0x32, 0x12, 0x01, 0x00, 0x01, 0xff, 0x00}},
+ {0x0bc6, 64, { 0x75, 0x16, 0x04, 0x12, 0x0f, 0x12, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x40, 0x90,
+  0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x16, 0x04, 0xe5, 0x15, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35,
+  0x14, 0xf5, 0x83, 0x74, 0x02, 0xf0, 0x7e, 0x7d, 0x7f, 0x40, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83,
+  0x74, 0x7d, 0xf0, 0xa3, 0x74, 0x40, 0xf0, 0x7e, 0x7d, 0x7f, 0x80, 0x85, 0x15, 0x82, 0x85}},
+ {0x0c06, 64, { 0x14, 0x83, 0xa3, 0xa3, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0x80, 0xf0, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x14,
+  0x7c, 0x75, 0x15, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75, 0x16, 0x08, 0x12, 0x0f, 0x12,
+  0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0,
+  0x75, 0x16, 0x08, 0xe5, 0x15, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74}},
+ {0x0c46, 64, { 0x03, 0xf0, 0x7e, 0x7c, 0x7f, 0xc0, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0x74, 0x7c, 0xf0, 0xa3, 0x74,
+  0xc0, 0xf0, 0x7e, 0x7d, 0x7f, 0x00, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0xa3, 0xa3, 0x74, 0x7d,
+  0xf0, 0xa3, 0x74, 0x00, 0xf0, 0xc2, 0x0a, 0xc2, 0x09, 0xd2, 0x02, 0x22, 0xe5, 0x10, 0x04, 0x54,
+  0x03, 0xf5, 0x10, 0x14, 0x60, 0x1f, 0x14, 0x60, 0x31, 0x14, 0x60, 0x43, 0x24, 0x03, 0x70}},
+ {0x0c86, 64, { 0x52, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x14, 0x7b, 0x75, 0x15, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0,
+  0x75, 0x16, 0x01, 0x80, 0x3d, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x00, 0x90,
+  0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x16, 0x02, 0x80, 0x28, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x14,
+  0x7c, 0x75, 0x15, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x16, 0x04, 0x80, 0x13}},
+ {0x0cc6, 64, { 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75,
+  0x16, 0x08, 0xe5, 0x32, 0x55, 0x16, 0x70, 0x03, 0x02, 0x0e, 0x11, 0xe5, 0x16, 0xf4, 0xff, 0x52,
+  0x32, 0xe5, 0x26, 0x54, 0x7f, 0xfe, 0x70, 0x0f, 0xe5, 0x2a, 0x55, 0x16, 0x60, 0x24, 0x90, 0x7f,
+  0x98, 0xe0, 0x45, 0x16, 0xf0, 0x80, 0x1b, 0xbe, 0x20, 0x18, 0xe5, 0x15, 0x24, 0x31, 0xf5}},
+ {0x0d06, 64, { 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x30, 0xe3, 0x09, 0xe4, 0xf5, 0x2a, 0x90, 0x7f, 0x98, 0xe0,
+  0x5f, 0xf0, 0xe5, 0x15, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x03,
+  0xe0, 0x14, 0xf0, 0xe5, 0x15, 0x24, 0x34, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60,
+  0x03, 0xe0, 0x14, 0xf0, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0x11, 0x74, 0x0a, 0xf0, 0x12, 0x00}},
+ {0x0d46, 64, { 0x36, 0xef, 0x54, 0x01, 0xff, 0xf5, 0x19, 0xe5, 0x15, 0x24, 0x2c, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5,
+  0x83, 0xe0, 0x6f, 0x60, 0x07, 0xe5, 0x19, 0xf0, 0xe5, 0x16, 0x42, 0x13, 0x12, 0x18, 0xe4, 0x8f,
+  0x19, 0xe5, 0x15, 0x24, 0x27, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x19,
+  0x54, 0x10, 0xfe, 0x6f, 0x60, 0x06, 0xee, 0xf0, 0xe5, 0x16, 0x42, 0x13, 0xe5, 0x15, 0x24}},
+ {0x0d86, 64, { 0x28, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x19, 0x54, 0x80, 0xfe, 0x6f, 0x60,
+  0x06, 0xee, 0xf0, 0xe5, 0x16, 0x42, 0x13, 0xe5, 0x15, 0x24, 0x29, 0xf5, 0x82, 0xe4, 0x35, 0x14,
+  0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x19, 0x54, 0x20, 0xfe, 0x6f, 0x60, 0x15, 0xee, 0xf0, 0xe5, 0x15,
+  0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x30, 0xe4, 0x04, 0xe5, 0x16}},
+ {0x0dc6, 64, { 0x42, 0x13, 0xe5, 0x12, 0x55, 0x16, 0xff, 0xf5, 0x19, 0xe5, 0x15, 0x24, 0x2a, 0xf5, 0x82, 0xe4, 0x35,
+  0x14, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x16, 0xe5, 0x19, 0xf0, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82,
+  0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x30, 0xe5, 0x04, 0xe5, 0x16, 0x42, 0x13, 0xe5, 0x17, 0x55,
+  0x16, 0xff, 0xf5, 0x19, 0xe5, 0x15, 0x24, 0x30, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83}},
+ {0x0e06, 64, { 0xe0, 0x6f, 0x60, 0x07, 0xe5, 0x19, 0xf0, 0xe5, 0x16, 0x42, 0x13, 0x22, 0x30, 0x09, 0x03, 0x02, 0x0f,
+  0x11, 0xe5, 0x24, 0x14, 0x60, 0x2a, 0x14, 0x60, 0x41, 0x14, 0x60, 0x58, 0x14, 0x60, 0x6f, 0x24,
+  0x04, 0x60, 0x03, 0x02, 0x0e, 0xcf, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x14, 0x7b, 0x75, 0x15, 0xc0,
+  0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x16, 0x01, 0x12, 0x12, 0xa1, 0x75, 0x24, 0x01}},
+ {0x0e46, 64, { 0x22, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0,
+  0x75, 0x16, 0x02, 0x12, 0x12, 0xa1, 0x75, 0x24, 0x02, 0x22, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x14,
+  0x7c, 0x75, 0x15, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x16, 0x04, 0x12, 0x12, 0xa1,
+  0x75, 0x24, 0x03, 0x22, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x80, 0x90}},
+ {0x0e86, 64, { 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75, 0x16, 0x08, 0x12, 0x12, 0xa1, 0x75, 0x24, 0x04, 0x22, 0x30, 0x04,
+  0x33, 0xc2, 0x04, 0x53, 0x13, 0xdf, 0xe4, 0xf5, 0x19, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x2e, 0x25,
+  0x19, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x11, 0xab, 0xff, 0x74, 0x80, 0x25, 0x19, 0xf5, 0x82,
+  0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x19, 0xe5, 0x19, 0xb4, 0x03, 0xdb, 0x90}},
+ {0x0ec6, 64, { 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0x75, 0x24, 0x05, 0x22, 0xe5, 0x36, 0x60, 0x3b, 0xd5, 0x36, 0x0a, 0x53,
+  0x13, 0xef, 0x30, 0x0a, 0x04, 0xd2, 0x09, 0xc2, 0x0a, 0xe4, 0xf5, 0x19, 0x7e, 0x00, 0x7b, 0x00,
+  0x74, 0x35, 0x25, 0x19, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x11, 0xab, 0xff, 0x74, 0x80, 0x25,
+  0x19, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x19, 0xe5, 0x19, 0xb4}},
+ {0x0f06, 64, { 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4, 0xf5, 0x24, 0x22, 0xe4, 0xf5, 0x1a, 0x7e, 0x00,
+  0x7b, 0x01, 0xe5, 0x15, 0x25, 0x1a, 0xf9, 0xee, 0x35, 0x14, 0xfa, 0xe4, 0x12, 0x11, 0xf1, 0x05,
+  0x1a, 0xe5, 0x1a, 0xb4, 0x3c, 0xe8, 0xe5, 0x15, 0x24, 0x35, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5,
+  0x83, 0x74, 0x01, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x15, 0x24, 0x37, 0xf5}},
+ {0x0f46, 64, { 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0xf0, 0x7f, 0x0c, 0xe4, 0xfd,
+  0x12, 0x16, 0x47, 0x7f, 0x10, 0xe5, 0x15, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83,
+  0xef, 0xf0, 0x12, 0x15, 0xb7, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0, 0x7f, 0x01, 0xe5, 0x15, 0x24,
+  0x36, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xef, 0xf0, 0x44, 0x06, 0x90, 0xc0, 0x00}},
+ {0x0f86, 64, { 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5, 0x15, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5,
+  0x83, 0x74, 0x80, 0xf0, 0x90, 0xc0, 0x00, 0xf0, 0x0f, 0xe4, 0xfd, 0x12, 0x16, 0x47, 0xe4, 0xff,
+  0x7e, 0xa3, 0xe5, 0x15, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xee, 0xf0, 0xfd,
+  0x12, 0x16, 0x47, 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f}},
+ {0x0fc6, 64, { 0x05, 0x7d, 0x7f, 0x12, 0x16, 0x47, 0x7f, 0x01, 0x12, 0x15, 0x4f, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x16,
+  0x47, 0x22, 0x53, 0x13, 0x3f, 0x90, 0x7b, 0xf1, 0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7b, 0x7f, 0xc0,
+  0x75, 0x14, 0x7b, 0x75, 0x15, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x16, 0x01, 0x12,
+  0x08, 0xc1, 0x90, 0x7c, 0x31, 0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x14}},
+ {0x1006, 64, { 0x7c, 0x75, 0x15, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x16, 0x02, 0x12, 0x08, 0xc1, 0x90,
+  0x7c, 0x71, 0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x40,
+  0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x16, 0x04, 0x12, 0x08, 0xc1, 0x90, 0x7c, 0xb1, 0xe0,
+  0x30, 0xe3, 0x16, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x80, 0x90, 0x7f}},
+ {0x1046, 64, { 0x96, 0x74, 0x7f, 0xf0, 0x75, 0x16, 0x08, 0x12, 0x08, 0xc1, 0x05, 0x11, 0xe5, 0x11, 0x54, 0x0f, 0xf5,
+  0x18, 0x70, 0x1f, 0x90, 0x78, 0x41, 0xe0, 0x54, 0xf7, 0xf0, 0x90, 0x7f, 0x99, 0xe0, 0xf5, 0x17,
+  0x90, 0x78, 0x41, 0xe0, 0x44, 0x08, 0xf0, 0x90, 0x7f, 0x99, 0xe0, 0xf4, 0xf5, 0x12, 0x12, 0x11,
+  0x21, 0x22, 0xe5, 0x18, 0xb4, 0x01, 0x04, 0x12, 0x0c, 0x73, 0x22, 0x90, 0x7f, 0xc2, 0xe0}},
+ {0x1086, 64, { 0x20, 0xe1, 0x08, 0xe5, 0x13, 0x60, 0x04, 0x12, 0x0e, 0x12, 0x22, 0x12, 0x0c, 0x73, 0x22, 0x78, 0x7f,
+  0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x37, 0x02, 0x10, 0xdc, 0x02, 0x12, 0x29, 0xe4, 0x93, 0xa3,
+  0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4,
+  0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20}},
+ {0x10c6, 64, { 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04,
+  0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x18, 0x50, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff,
+  0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54,
+  0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8}},
+ {0x1106, 64, { 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8,
+  0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe, 0x90, 0x7f, 0xd2, 0xe0, 0x30, 0xe1,
+  0x03, 0x02, 0x11, 0xaa, 0xc2, 0x09, 0x90, 0x7b, 0x40, 0xe0, 0x14, 0x60, 0x26, 0x14, 0x60, 0x3b,
+  0x14, 0x60, 0x50, 0x24, 0x83, 0x60, 0x64, 0x24, 0x80, 0x70, 0x63, 0x7e, 0x7b, 0x7f, 0xc0}},
+ {0x1146, 64, { 0x75, 0x14, 0x7b, 0x75, 0x15, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x16, 0x01, 0x12, 0x00,
+  0x46, 0x80, 0x4b, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x00, 0x90, 0x7f, 0x96,
+  0x74, 0xdf, 0xf0, 0x75, 0x16, 0x02, 0x12, 0x00, 0x46, 0x80, 0x33, 0x7e, 0x7c, 0x7f, 0x40, 0x75,
+  0x14, 0x7c, 0x75, 0x15, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x16, 0x04, 0x12}},
+ {0x1186, 64, { 0x00, 0x46, 0x80, 0x1b, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x80, 0x90, 0x7f, 0x96,
+  0x74, 0x7f, 0xf0, 0x75, 0x16, 0x08, 0x12, 0x00, 0x46, 0x80, 0x03, 0x12, 0x17, 0x5c, 0xe4, 0x90,
+  0x7f, 0xd3, 0xf0, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7,
+  0x22, 0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01}},
+ {0x11c6, 64, { 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9, 0x25,
+  0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82, 0x29,
+  0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a,
+  0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xd0, 0x83, 0xd0}},
+ {0x1206, 64, { 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01,
+  0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3,
+  0x80, 0xdf, 0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92, 0x00, 0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0,
+  0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0}},
+ {0x1246, 64, { 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef,
+  0x90, 0x7f, 0xaf, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0x74, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0x0b,
+  0x12, 0x18, 0x14, 0xc2, 0x01, 0xe4, 0xf5, 0x2b, 0xf5, 0x31, 0xc2, 0x07, 0xc2, 0x02, 0x75, 0x29,
+  0xf0, 0x90, 0x7f, 0xd8, 0xe0, 0x65, 0x26, 0x60, 0x06, 0x75, 0x32, 0x0f, 0xe0, 0xf5, 0x26}},
+ {0x1286, 64, { 0x30, 0x02, 0x03, 0x12, 0x0f, 0xd9, 0x30, 0x01, 0x07, 0xc2, 0x01, 0x12, 0x06, 0x29, 0x80, 0xe2, 0x30,
+  0x08, 0xdf, 0xc2, 0x08, 0x12, 0x18, 0x35, 0x80, 0xd8, 0x22, 0xe5, 0x13, 0x55, 0x16, 0x60, 0x6a,
+  0xe5, 0x15, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x70, 0x5c, 0xe5, 0x16,
+  0xf4, 0x52, 0x13, 0xe5, 0x15, 0x24, 0x26, 0xff, 0xe4, 0x35, 0x14, 0xfe, 0xe4, 0xfd, 0x0f}},
+ {0x12c6, 64, { 0xef, 0xaa, 0x06, 0x70, 0x01, 0x0e, 0x14, 0xf5, 0x82, 0x8a, 0x83, 0xe0, 0xfc, 0x74, 0x80, 0x2d, 0xf5,
+  0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xec, 0xf0, 0x0d, 0xbd, 0x0b, 0xe2, 0x90, 0x7f, 0xc3, 0x74,
+  0x0b, 0xf0, 0xe5, 0x15, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x10, 0xf0,
+  0xe5, 0x15, 0x24, 0x2e, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x15}},
+ {0x1306, 64, { 0x24, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe4, 0xf0, 0x22, 0xe5, 0x28, 0x45, 0x27, 0x60,
+  0x57, 0xae, 0x27, 0xaf, 0x28, 0xd3, 0xef, 0x94, 0x40, 0xee, 0x94, 0x00, 0x40, 0x04, 0x7e, 0x00,
+  0x7f, 0x40, 0xc3, 0xe5, 0x28, 0x9f, 0xf5, 0x28, 0xe5, 0x27, 0x9e, 0xf5, 0x27, 0xe4, 0xfd, 0xed,
+  0xc3, 0x9f, 0xe4, 0x9e, 0x50, 0x1f, 0x85, 0x34, 0x82, 0x85, 0x33, 0x83, 0xe0, 0xfc, 0x74}},
+ {0x1346, 64, { 0x00, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xec, 0xf0, 0x0d, 0x05, 0x34, 0xe5, 0x34, 0x70,
+  0x02, 0x05, 0x33, 0x80, 0xda, 0x90, 0x7f, 0xa9, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xac, 0xe0, 0x44,
+  0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xef, 0xf0, 0x22, 0x90, 0x7f, 0xac, 0xe0, 0x54, 0xfe, 0xf0, 0xe4,
+  0x90, 0x7f, 0xb5, 0xf0, 0x22, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xf0}},
+ {0x1386, 64, { 0xf0, 0x90, 0x7f, 0x96, 0xf0, 0xe4, 0x90, 0x78, 0x4a, 0xf0, 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x9d,
+  0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x30, 0x00, 0x07, 0xe5, 0x29, 0x54, 0xf0, 0xff,
+  0x80, 0x02, 0x7f, 0x00, 0xef, 0x44, 0x08, 0x90, 0x78, 0x41, 0xf0, 0xe4, 0x90, 0x7f, 0x98, 0xf0,
+  0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x98, 0xf0}},
+ {0x13c6, 64, { 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xf0, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0, 0x90, 0x7f,
+  0x92, 0xe0, 0x54, 0xfd, 0xf0, 0x22, 0x8f, 0x1a, 0x05, 0x2d, 0xe5, 0x2d, 0xae, 0x2c, 0x70, 0x02,
+  0x05, 0x2c, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x1a, 0xf0, 0x12, 0x18, 0xf0, 0x05, 0x2d, 0xe5,
+  0x2d, 0xac, 0x2c, 0x70, 0x02, 0x05, 0x2c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15}},
+ {0x1406, 64, { 0x23, 0xe5, 0x23, 0x60, 0x1f, 0xe5, 0x15, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xc0,
+  0x83, 0xc0, 0x82, 0xe0, 0xfe, 0x12, 0x18, 0xd8, 0x8f, 0x1a, 0xee, 0x4f, 0xd0, 0x82, 0xd0, 0x83,
+  0xf0, 0x80, 0xb5, 0x22, 0x8f, 0x1a, 0xe4, 0xf5, 0x1b, 0x75, 0x1c, 0xff, 0x75, 0x1d, 0x19, 0x75,
+  0x1e, 0x86, 0xab, 0x1c, 0xaa, 0x1d, 0xa9, 0x1e, 0x90, 0x00, 0x01, 0x12, 0x11, 0xc4, 0xb4}},
+ {0x1446, 64, { 0x03, 0x1d, 0xaf, 0x1b, 0x05, 0x1b, 0xef, 0xb5, 0x1a, 0x01, 0x22, 0x12, 0x11, 0xab, 0x7e, 0x00, 0x29,
+  0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75, 0x1c, 0xff, 0xf5, 0x1d, 0x89, 0x1e, 0x80, 0xd4, 0x7b, 0x00,
+  0x7a, 0x00, 0x79, 0x00, 0x22, 0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0x78, 0x4f, 0x74, 0xc0, 0xf0,
+  0xe4, 0x90, 0x78, 0x50, 0xf0, 0xe5, 0x2c, 0x90, 0x78, 0x51, 0xf0, 0xae, 0x2c, 0xe5, 0x2d}},
+ {0x1486, 64, { 0x90, 0x78, 0x52, 0xf0, 0x90, 0x78, 0x54, 0xe5, 0x23, 0xf0, 0x90, 0x78, 0x57, 0x74, 0x04, 0xf0, 0x90,
+  0x7f, 0xe2, 0xe0, 0x44, 0x10, 0xf0, 0xe0, 0x54, 0xf7, 0xf0, 0xe4, 0x90, 0x78, 0x55, 0xf0, 0x90,
+  0x78, 0x55, 0xe0, 0x60, 0xfa, 0x22, 0xe4, 0x90, 0x78, 0x41, 0xf0, 0xe5, 0x2c, 0x90, 0x78, 0x4f,
+  0xf0, 0xae, 0x2c, 0xe5, 0x2d, 0x90, 0x78, 0x50, 0xf0, 0x90, 0x78, 0x51, 0x74, 0xc0, 0xf0}},
+ {0x14c6, 64, { 0xe4, 0x90, 0x78, 0x52, 0xf0, 0x90, 0x78, 0x54, 0xe5, 0x23, 0xf0, 0x90, 0x78, 0x57, 0x74, 0x04, 0xf0,
+  0xe4, 0x90, 0x78, 0x55, 0xf0, 0x90, 0x78, 0x55, 0xe0, 0x60, 0xfa, 0x22, 0xe5, 0x15, 0x24, 0x04,
+  0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0f, 0x14, 0x60, 0x13, 0x14, 0x60,
+  0x17, 0x80, 0x00, 0x90, 0x7f, 0xc7, 0xef, 0xf0, 0x80, 0x13, 0x90, 0x7f, 0xc9, 0xef, 0xf0}},
+ {0x1506, 64, { 0x80, 0x0c, 0x90, 0x7f, 0xcb, 0xef, 0xf0, 0x80, 0x05, 0x90, 0x7f, 0xcd, 0xef, 0xf0, 0xe5, 0x16, 0x42,
+  0x2a, 0x22, 0xe5, 0x15, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x14, 0x60,
+  0x0f, 0x14, 0x60, 0x13, 0x14, 0x60, 0x17, 0x80, 0x00, 0x90, 0x7f, 0xb7, 0xef, 0xf0, 0x80, 0x13,
+  0x90, 0x7f, 0xb9, 0xef, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xbb, 0xef, 0xf0, 0x80, 0x05, 0x90}},
+ {0x1546, 64, { 0x7f, 0xbd, 0xef, 0xf0, 0xe5, 0x16, 0x42, 0x2a, 0x22, 0xae, 0x07, 0xe4, 0xff, 0xe5, 0x15, 0x24, 0x32,
+  0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0xfd, 0x12, 0x16, 0x47, 0x90, 0x78,
+  0x41, 0x74, 0x01, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x15, 0x24, 0x32, 0xf5, 0x82,
+  0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xfd, 0x12, 0x16, 0x47, 0x22, 0xc0, 0xe0}},
+ {0x1586, 64, { 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0, 0xd0,
+  0x75, 0xd0, 0x08, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x01, 0xf0, 0x12, 0x13, 0x12, 0xd0,
+  0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32,
+  0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41}},
+ {0x15c6, 64, { 0x74, 0x02, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x15, 0x24,
+  0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22,
+  0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74,
+  0x04, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x15}},
+ {0x1606, 64, { 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22,
+  0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74,
+  0x06, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x15, 0x24,
+  0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0}},
+ {0x1646, 64, { 0x22, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5,
+  0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x07, 0xf0, 0x90, 0xc0,
+  0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x05, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22, 0x90,
+  0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0xe4, 0x90, 0x78, 0x41}},
+ {0x1686, 64, { 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x15, 0x24, 0x37, 0xf5,
+  0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22, 0xe5, 0x15,
+  0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0e, 0x14, 0x60, 0x11,
+  0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xc6, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xc8, 0xe0}},
+ {0x16c6, 64, { 0xff, 0x22, 0x90, 0x7f, 0xca, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcc, 0xe0, 0xff, 0x22, 0xe5, 0x15, 0x24,
+  0x04, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0e, 0x14, 0x60, 0x11, 0x14,
+  0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xb6, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xb8, 0xe0, 0xff, 0x22,
+  0x90, 0x7f, 0xba, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xbc, 0xe0, 0xff, 0x22, 0xe5, 0x15, 0x24}},
+ {0x1706, 64, { 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0e, 0x14, 0x60, 0x11, 0x14, 0x60,
+  0x14, 0x80, 0x00, 0x90, 0x7f, 0xc7, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xc9, 0xe0, 0xff, 0x22, 0x90,
+  0x7f, 0xcb, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcd, 0xe0, 0xff, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0,
+  0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90, 0x7f, 0xc4, 0xe4, 0xf0}},
+ {0x1746, 64, { 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82,
+  0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7b, 0x41, 0xe0, 0xf5, 0x36, 0x43, 0x13, 0x10, 0xa3, 0xe0,
+  0x60, 0x09, 0x90, 0x7f, 0xd7, 0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0x90, 0x7b, 0x43, 0xe0, 0xf5,
+  0x37, 0xa3, 0xe0, 0x54, 0xf0, 0xf5, 0x29, 0xe0, 0x60, 0x02, 0xd2, 0x0a, 0x22, 0xc0, 0xe0}},
+ {0x1786, 64, { 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x01, 0x53, 0x91,
+  0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0,
+  0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86,
+  0x75, 0x86, 0x00, 0xd2, 0x08, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08, 0xf0, 0xd0}},
+ {0x17c6, 64, { 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x12, 0x18, 0xc0, 0xae, 0x07,
+  0x12, 0x18, 0xc0, 0xad, 0x07, 0xee, 0x6d, 0x60, 0x10, 0x12, 0x18, 0xc0, 0xae, 0x07, 0xee, 0x6d,
+  0x60, 0x07, 0x12, 0x18, 0xc0, 0xad, 0x07, 0x80, 0xec, 0xaf, 0x06, 0x22, 0x74, 0x00, 0xf5, 0x86,
+  0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9, 0x22, 0x90, 0x7f}},
+ {0x1806, 64, { 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x90, 0x7f, 0xd6,
+  0xe0, 0x44, 0x04, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x0b, 0x04, 0xe0, 0x44, 0x02, 0xf0, 0x7f,
+  0xf4, 0x7e, 0x01, 0x12, 0x18, 0x6b, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0, 0x22, 0x12, 0x13,
+  0x7c, 0x12, 0x18, 0x04, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x0a, 0x7f, 0x05, 0x7e, 0x00}},
+ {0x1846, 64, { 0x12, 0x18, 0x6b, 0x12, 0x18, 0x9e, 0x12, 0x0a, 0xb8, 0x22, 0x03, 0x35, 0x80, 0x00, 0x00, 0x03, 0x2e,
+  0x81, 0x00, 0x00, 0xc1, 0x85, 0xc1, 0x81, 0xc1, 0x08, 0xc1, 0x00, 0xc1, 0x06, 0x01, 0x22, 0x00,
+  0x01, 0x24, 0x00, 0x00, 0x8e, 0x18, 0x8f, 0x19, 0xe5, 0x19, 0x15, 0x19, 0xae, 0x18, 0x70, 0x02,
+  0x15, 0x18, 0x4e, 0x60, 0x08, 0x12, 0x17, 0xf3, 0x12, 0x17, 0xf3, 0x80, 0xeb, 0x22, 0xe5}},
+ {0x1886, 64, { 0x15, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x04, 0xff, 0x44, 0x10, 0x90, 0x7f,
+  0xd7, 0xf0, 0xef, 0x44, 0x30, 0xf0, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x0d,
+  0x7e, 0x00, 0x12, 0x18, 0x6b, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22, 0x90, 0x78, 0x41,
+  0x74, 0x02, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0}},
+ {0x18c6, 64, { 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff,
+  0x22, 0x90, 0x78, 0x41, 0x74, 0x05, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x78, 0x41,
+  0x74, 0x06, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0xc0,
+  0x00, 0xe0, 0xff, 0x22, 0x53, 0xd8, 0xef, 0x32, 0x00, 0x12, 0x01, 0x10, 0x01, 0xff, 0x00}},
  {0x1906, 64, { 0x00, 0x40, 0xcd, 0x06, 0x0a, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x04, 0x09, 0x02, 0x74, 0x00, 0x01,
   0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e, 0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01,
   0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40,
@@ -438,7 +442,7 @@
   0x00, 0x42, 0x00, 0x20, 0x00, 0x34, 0x00, 0x2d, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x74,
   0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20,
   0x00, 0x41, 0x00, 0x64, 0x00, 0x61, 0x00, 0x70, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00}},
- {0x1a06, 64, { 0x00, 0x00, 0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x00, 0x00, 0x00, 0x00,
+ {0x1a06, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
@@ -453,8 +457,8 @@
  {0x1ac6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x17, 0xb7, 0x00, 0x02, 0x1b}},
- {0x1b06, 21, { 0x04, 0x00, 0x02, 0x17, 0x65, 0x00, 0x02, 0x17, 0x37, 0x00, 0x02, 0x1b, 0x10, 0x00, 0x02, 0x1b, 0x14,
-  0x00, 0x02, 0x15, 0x89}},
-{ 0xffff,	0,	{0x00} }
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x17, 0x84, 0x00, 0x02, 0x1b}},
+ {0x1b06, 21, { 0x04, 0x00, 0x02, 0x17, 0x32, 0x00, 0x02, 0x17, 0xab, 0x00, 0x02, 0x1b, 0x10, 0x00, 0x02, 0x1b, 0x14,
+  0x00, 0x02, 0x15, 0x84}},
+ {0xffff, 0, {0x00}}
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/kl5kusb105.c linux-2.4.20/drivers/usb/serial/kl5kusb105.c
--- linux-2.4.19/drivers/usb/serial/kl5kusb105.c	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/kl5kusb105.c	2002-10-29 11:18:48.000000000 +0000
@@ -47,18 +47,14 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-/*#include <linux/fcntl.h>*/
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
-/*#include <linux/spinlock.h>*/
+#include <asm/uaccess.h>
 #include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
@@ -111,81 +107,41 @@
  */
 
 /*
- * All of the device info needed for the MCT USB-RS232 converter.
+ * All of the device info needed for the KLSI converters.
  */
-static __devinitdata struct usb_device_id id_table_combined [] = {
+static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) },
 	{ USB_DEVICE(KLSI_VID, KLSI_KL5KUSB105D_PID) },
 	{ }		/* Terminating entry */
 };
 
-static __devinitdata struct usb_device_id palmconnect_table [] = {
-        { USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) },
-        { }                        /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id kl5kusb105d_table [] = {
-        { USB_DEVICE(KLSI_VID, KLSI_KL5KUSB105D_PID) },
-        { }                        /* Terminating entry */
-};
-
+MODULE_DEVICE_TABLE (usb, id_table);
 
-MODULE_DEVICE_TABLE (usb, id_table_combined);
-
-
-static struct usb_serial_device_type palmconnect_device = {
-	name:		     "PalmConnect USB Serial",
-	id_table:	     palmconnect_table,
-	needs_interrupt_in:  MUST_HAVE,	  /* 1 interrupt-in endpoints */
-	needs_bulk_in:	     MUST_HAVE,   /* 1 bulk-in endpoint */
-	needs_bulk_out:	     MUST_HAVE,	  /* 1 bulk-out endpoint */
-	num_interrupt_in:    1,
-	num_bulk_in:	     1,
-	num_bulk_out:	     1,
-	num_ports:	     1,
-	open:		     klsi_105_open,
-	close:		     klsi_105_close,
-	write:		     klsi_105_write,
-	write_bulk_callback: klsi_105_write_bulk_callback,
-	chars_in_buffer:     klsi_105_chars_in_buffer,
-	write_room:          klsi_105_write_room,
-	read_bulk_callback:  klsi_105_read_bulk_callback,
-	ioctl:		     klsi_105_ioctl,
-	set_termios:	     klsi_105_set_termios,
-	/*break_ctl:	     klsi_105_break_ctl,*/
-	startup:	     klsi_105_startup,
-	shutdown:	     klsi_105_shutdown,
-	throttle:	     klsi_105_throttle,
-	unthrottle:	     klsi_105_unthrottle,
-};
 
 static struct usb_serial_device_type kl5kusb105d_device = {
-	name:		     "generic KL5KUSB105D USB->Serial",
-	id_table:	     kl5kusb105d_table,
-	needs_interrupt_in:  MUST_HAVE,	 /* 1 interrupt-in endpoints */
-	needs_bulk_in:	     MUST_HAVE,  /* 1 bulk-in endpoint */
-	needs_bulk_out:	     MUST_HAVE,	 /* 1 bulk-out endpoint */
-	num_interrupt_in:    1,
-	num_bulk_in:	     1,
-	num_bulk_out:	     1,
-	num_ports:	     1,
-	open:		     klsi_105_open,
-	close:		     klsi_105_close,
-	write:		     klsi_105_write,
-	write_bulk_callback: klsi_105_write_bulk_callback,
-	chars_in_buffer:     klsi_105_chars_in_buffer,
-	write_room:          klsi_105_write_room,
-	read_bulk_callback:  klsi_105_read_bulk_callback,
-	ioctl:		     klsi_105_ioctl,
-	set_termios:	     klsi_105_set_termios,
-	/*break_ctl:	     klsi_105_break_ctl,*/
-	startup:	     klsi_105_startup,
-	shutdown:	     klsi_105_shutdown,
-	throttle:	     klsi_105_throttle,
-	unthrottle:	     klsi_105_unthrottle,
+	.owner =             THIS_MODULE,
+	.name =		     "KL5KUSB105D / PalmConnect",
+	.id_table =	     id_table,
+	.num_interrupt_in =  1,
+	.num_bulk_in =	     1,
+	.num_bulk_out =	     1,
+	.num_ports =	     1,
+	.open =		     klsi_105_open,
+	.close =	     klsi_105_close,
+	.write =	     klsi_105_write,
+	.write_bulk_callback = klsi_105_write_bulk_callback,
+	.chars_in_buffer =   klsi_105_chars_in_buffer,
+	.write_room =        klsi_105_write_room,
+	.read_bulk_callback =klsi_105_read_bulk_callback,
+	.ioctl =	     klsi_105_ioctl,
+	.set_termios =	     klsi_105_set_termios,
+	/*.break_ctl =	     klsi_105_break_ctl,*/
+	.startup =	     klsi_105_startup,
+	.shutdown =	     klsi_105_shutdown,
+	.throttle =	     klsi_105_throttle,
+	.unthrottle =	     klsi_105_unthrottle,
 };
 
-
 struct klsi_105_port_settings {
 	__u8	pktlen;		/* always 5, it seems */
 	__u8	baudrate;
@@ -231,7 +187,8 @@
 			     KLSI_TIMEOUT);
 	if (rc < 0)
 		err("Change port settings failed (error = %d)", rc);
-	info(__FUNCTION__ " - %d byte block, baudrate %x, databits %d, u1 %d, u2 %d",
+	info("%s - %d byte block, baudrate %x, databits %d, u1 %d, u2 %d",
+	    __FUNCTION__,
 	    settings->pktlen,
 	    settings->baudrate, settings->databits,
 	    settings->unknown1, settings->unknown2);
@@ -262,7 +219,7 @@
 	__u8 status_buf[KLSI_STATUSBUF_LEN] = { -1,-1};
 	__u16 status;
 
-	info(__FUNCTION__ " - sending SIO Poll request");
+	info("%s - sending SIO Poll request", __FUNCTION__);
         rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
 			     KL5KUSB105A_SIO_POLL,
                              USB_TYPE_VENDOR | USB_DIR_IN,
@@ -276,7 +233,7 @@
 	else {
 		status = status_buf[0] + (status_buf[1]<<8);
 
-		info(__FUNCTION__ " - read status %x %x",
+		info("%s - read status %x %x", __FUNCTION__,
 		     status_buf[0], status_buf[1]);
 
 		*line_state_p = klsi_105_status2linestate(status);
@@ -304,7 +261,7 @@
 		serial->port[i].private = kmalloc(sizeof(struct klsi_105_private),
 						   GFP_KERNEL);
 		if (!serial->port[i].private) {
-			dbg(__FUNCTION__ "kmalloc for klsi_105_private failed.");
+			dbg("%skmalloc for klsi_105_private failed.", __FUNCTION__);
 			return (-1); /* error */
 		}
 		priv = (struct klsi_105_private *)serial->port[i].private;
@@ -334,8 +291,7 @@
 			urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE,
 							GFP_KERNEL);
 			if (!urb->transfer_buffer) {
-				err (__FUNCTION__ 
-				     " - out of memory for urb buffers.");
+				err("%s - out of memory for urb buffers.", __FUNCTION__);
 				continue;
 			}
 		}
@@ -352,16 +308,13 @@
 {
 	int i;
 	
-	dbg (__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	/* stop reads and writes on all ports */
 	for (i=0; i < serial->num_ports; ++i) {
 		struct klsi_105_private *priv = 
 			(struct klsi_105_private*) serial->port[i].private;
 		unsigned long flags;
-		while (serial->port[i].open_count > 0) {
-			klsi_105_close (&serial->port[i], NULL);
-		}
 
 		if (priv) {
 			/* kill our write urb pool */
@@ -397,92 +350,79 @@
 	struct usb_serial *serial = port->serial;
 	struct klsi_105_private *priv = (struct klsi_105_private *)port->private;
 	int retval = 0;
+	int rc;
+	int i;
+	unsigned long line_state;
 
-	dbg(__FUNCTION__" port %d", port->number);
+	dbg("%s port %d", __FUNCTION__, port->number);
 
-	down (&port->sem);
+	/* force low_latency on so that our tty_push actually forces
+	 * the data through
+	 * port->tty->low_latency = 1; */
+
+	/* Do a defined restart:
+	 * Set up sane default baud rate and send the 'READ_ON'
+	 * vendor command. 
+	 * FIXME: set modem line control (how?)
+	 * Then read the modem line control and store values in
+	 * priv->line_state.
+	 */
+	priv->cfg.pktlen   = 5;
+	priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+	priv->cfg.databits = kl5kusb105a_dtb_8;
+	priv->cfg.unknown1 = 0;
+	priv->cfg.unknown2 = 1;
+	klsi_105_chg_port_settings(serial, &(priv->cfg));
 	
-	++port->open_count;
-	MOD_INC_USE_COUNT;
+	/* set up termios structure */
+	priv->termios.c_iflag = port->tty->termios->c_iflag;
+	priv->termios.c_oflag = port->tty->termios->c_oflag;
+	priv->termios.c_cflag = port->tty->termios->c_cflag;
+	priv->termios.c_lflag = port->tty->termios->c_lflag;
+	for (i=0; i<NCCS; i++)
+		priv->termios.c_cc[i] = port->tty->termios->c_cc[i];
 
-	if (!port->active) {
-		int rc;
-		int i;
-		unsigned long line_state;
-		port->active = 1;
-
-		/* force low_latency on so that our tty_push actually forces
-		 * the data through
-		 * port->tty->low_latency = 1; */
-
-		/* Do a defined restart:
-		 * Set up sane default baud rate and send the 'READ_ON'
-		 * vendor command. 
-		 * FIXME: set modem line control (how?)
-		 * Then read the modem line control and store values in
-		 * priv->line_state.
-		 */
-		priv->cfg.pktlen   = 5;
-		priv->cfg.baudrate = kl5kusb105a_sio_b9600;
-		priv->cfg.databits = kl5kusb105a_dtb_8;
-		priv->cfg.unknown1 = 0;
-		priv->cfg.unknown2 = 1;
-		klsi_105_chg_port_settings(serial, &(priv->cfg));
-		
-		/* set up termios structure */
-		priv->termios.c_iflag = port->tty->termios->c_iflag;
-		priv->termios.c_oflag = port->tty->termios->c_oflag;
-		priv->termios.c_cflag = port->tty->termios->c_cflag;
-		priv->termios.c_lflag = port->tty->termios->c_lflag;
-		for (i=0; i<NCCS; i++)
-			priv->termios.c_cc[i] = port->tty->termios->c_cc[i];
-
-
-		/* READ_ON and urb submission */
-		FILL_BULK_URB(port->read_urb, serial->dev, 
-			      usb_rcvbulkpipe(serial->dev,
-					      port->bulk_in_endpointAddress),
-			      port->read_urb->transfer_buffer,
-			      port->read_urb->transfer_buffer_length,
-			      klsi_105_read_bulk_callback,
-			      port);
-		port->read_urb->transfer_flags |= USB_QUEUE_BULK;
-
-		rc = usb_submit_urb(port->read_urb);
-		if (rc) {
-			err(__FUNCTION__ 
-			    " - failed submitting read urb, error %d", rc);
-			retval = rc;
-			goto exit;
-		}
 
-		rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),
-				     KL5KUSB105A_SIO_CONFIGURE,
-				     USB_TYPE_VENDOR|USB_DIR_OUT|USB_RECIP_INTERFACE,
-				     KL5KUSB105A_SIO_CONFIGURE_READ_ON,
-				     0, /* index */
-				     NULL,
-				     0,
-				     KLSI_TIMEOUT);
-		if (rc < 0) {
-			err("Enabling read failed (error = %d)", rc);
-			retval = rc;
-		} else 
-			dbg(__FUNCTION__ " - enabled reading");
+	/* READ_ON and urb submission */
+	FILL_BULK_URB(port->read_urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev,
+				      port->bulk_in_endpointAddress),
+		      port->read_urb->transfer_buffer,
+		      port->read_urb->transfer_buffer_length,
+		      klsi_105_read_bulk_callback,
+		      port);
+	port->read_urb->transfer_flags |= USB_QUEUE_BULK;
 
-		rc = klsi_105_get_line_state(serial, &line_state);
-		if (rc >= 0) {
-			priv->line_state = line_state;
-			dbg(__FUNCTION__ 
-			    " - read line state 0x%lx", line_state);
-			retval = 0;
-		} else
-			retval = rc;
+	rc = usb_submit_urb(port->read_urb);
+	if (rc) {
+		err("%s - failed submitting read urb, error %d", __FUNCTION__, rc);
+		retval = rc;
+		goto exit;
 	}
 
+	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),
+			     KL5KUSB105A_SIO_CONFIGURE,
+			     USB_TYPE_VENDOR|USB_DIR_OUT|USB_RECIP_INTERFACE,
+			     KL5KUSB105A_SIO_CONFIGURE_READ_ON,
+			     0, /* index */
+			     NULL,
+			     0,
+			     KLSI_TIMEOUT);
+	if (rc < 0) {
+		err("Enabling read failed (error = %d)", rc);
+		retval = rc;
+	} else 
+		dbg("%s - enabled reading", __FUNCTION__);
+
+	rc = klsi_105_get_line_state(serial, &line_state);
+	if (rc >= 0) {
+		priv->line_state = line_state;
+		dbg("%s - read line state 0x%lx", __FUNCTION__, line_state);
+		retval = 0;
+	} else
+		retval = rc;
+
 exit:
-	up (&port->sem);
-	
 	return retval;
 } /* klsi_105_open */
 
@@ -492,43 +432,35 @@
 	struct usb_serial *serial;
 	struct klsi_105_private *priv 
 		= (struct klsi_105_private *)port->private;
-	dbg(__FUNCTION__" port %d", port->number);
+	int rc;
+
+	dbg("%s port %d", __FUNCTION__, port->number);
 
 	serial = get_usb_serial (port, __FUNCTION__);
 
 	if(!serial)
 		return;
 
-	down (&port->sem);
-
-	--port->open_count;
+	/* send READ_OFF */
+	rc = usb_control_msg (serial->dev,
+			      usb_sndctrlpipe(serial->dev, 0),
+			      KL5KUSB105A_SIO_CONFIGURE,
+			      USB_TYPE_VENDOR | USB_DIR_OUT,
+			      KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
+			      0, /* index */
+			      NULL, 0,
+			      KLSI_TIMEOUT);
+	if (rc < 0)
+		    err("Disabling read failed (error = %d)", rc);
 
-	if (port->open_count <= 0) {
-		/* send READ_OFF */
-		int rc = usb_control_msg(serial->dev,
-					 usb_sndctrlpipe(serial->dev, 0),
-					 KL5KUSB105A_SIO_CONFIGURE,
-					 USB_TYPE_VENDOR | USB_DIR_OUT,
-					 KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
-					 0, /* index */
-					 NULL, 0,
-					 KLSI_TIMEOUT);
-		if (rc < 0)
-			    err("Disabling read failed (error = %d)", rc);
-
-		/* shutdown our bulk reads and writes */
-		usb_unlink_urb (port->write_urb);
-		usb_unlink_urb (port->read_urb);
-		/* unlink our write pool */
-		/* FIXME */
-		/* wgg - do I need this? I think so. */
-		usb_unlink_urb (port->interrupt_in_urb);
-		port->active = 0;
-		info("kl5kusb105 port stats: %ld bytes in, %ld bytes out", priv->bytes_in, priv->bytes_out);
-	}
-	
-	up (&port->sem);
-	MOD_DEC_USE_COUNT;
+	/* shutdown our bulk reads and writes */
+	usb_unlink_urb (port->write_urb);
+	usb_unlink_urb (port->read_urb);
+	/* unlink our write pool */
+	/* FIXME */
+	/* wgg - do I need this? I think so. */
+	usb_unlink_urb (port->interrupt_in_urb);
+	info("kl5kusb105 port stats: %ld bytes in, %ld bytes out", priv->bytes_in, priv->bytes_out);
 } /* klsi_105_close */
 
 
@@ -538,6 +470,7 @@
  */
 #define KLSI_105_DATA_OFFSET	2   /* in the bulk urb data block */
 
+
 static int klsi_105_write (struct usb_serial_port *port, int from_user,
 			   const unsigned char *buf, int count)
 {
@@ -547,10 +480,7 @@
 	int result, size;
 	int bytes_sent=0;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	down (&port->sem);	/* to lock against someone else trying to
-				   take an URB we just selected from the pool */
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	while (count > 0) {
 		/* try to find a free urb (write 0 bytes if none) */
@@ -562,21 +492,21 @@
 		for (i=0; i<NUM_URBS; i++) {
 			if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
 				urb = priv->write_urb_pool[i];
-				dbg(__FUNCTION__ " - using pool URB %d", i);
+				dbg("%s - using pool URB %d", __FUNCTION__, i);
 				break;
 			}
 		}
 		spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
 
 		if (urb==NULL) {
-			dbg (__FUNCTION__ " - no more free urbs");
+			dbg("%s - no more free urbs", __FUNCTION__);
 			goto exit;
 		}
 
 		if (urb->transfer_buffer == NULL) {
 			urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
 			if (urb->transfer_buffer == NULL) {
-				err(__FUNCTION__ " - no more kernel memory...");
+				err("%s - no more kernel memory...", __FUNCTION__);
 				goto exit;
 			}
 		}
@@ -587,7 +517,6 @@
 		if (from_user) {
 			if (copy_from_user(urb->transfer_buffer
 					   + KLSI_105_DATA_OFFSET, buf, size)) {
-				up (&port->sem);
 				return -EFAULT;
 			}
 		} else {
@@ -613,8 +542,7 @@
 		/* send the data out the bulk port */
 		result = usb_submit_urb(urb);
 		if (result) {
-			err(__FUNCTION__
-			    " - failed submitting write urb, error %d", result);
+			err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 			goto exit;
 		}
 		buf += size;
@@ -622,7 +550,6 @@
 		count -= size;
 	}
 exit:
-	up (&port->sem);
 	priv->bytes_out+=bytes_sent;
 
 	return bytes_sent;	/* that's how much we wrote */
@@ -633,15 +560,15 @@
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct usb_serial *serial = port->serial;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero write bulk status received: %d",
+		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__,
 		    urb->status);
 		return;
 	}
@@ -673,7 +600,7 @@
 
 	spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
 
-	dbg (__FUNCTION__ " - returns %d", chars);
+	dbg("%s - returns %d", __FUNCTION__, chars);
 	return (chars);
 }
 
@@ -694,7 +621,7 @@
 
 	spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
 
-	dbg(__FUNCTION__ " - returns %d", room);
+	dbg("%s - returns %d", __FUNCTION__, room);
 	return (room);
 }
 
@@ -710,16 +637,16 @@
 	unsigned char *data = urb->transfer_buffer;
 	int rc;
 
-        dbg(__FUNCTION__ " - port %d", port->number);
+        dbg("%s - port %d", __FUNCTION__, port->number);
 
 	/* The urb might have been killed. */
         if (urb->status) {
-                dbg(__FUNCTION__ " - nonzero read bulk status received: %d",
+                dbg("%s - nonzero read bulk status received: %d", __FUNCTION__,
 		    urb->status);
                 return;
         }
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 	
@@ -728,10 +655,10 @@
 	 */
 	if (urb->actual_length == 0) {
 		/* empty urbs seem to happen, we ignore them */
-		/* dbg(__FUNCTION__ " - emtpy URB"); */
+		/* dbg("%s - emtpy URB", __FUNCTION__); */
 	       ;
 	} else if (urb->actual_length <= 2) {
-		dbg(__FUNCTION__ " - size %d URB not understood",
+		dbg("%s - size %d URB not understood", __FUNCTION__,
 		    urb->actual_length);
 		usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
 	} else {
@@ -749,9 +676,8 @@
 				       urb->actual_length, data);
 
 		if (bytes_sent + 2 > urb->actual_length) {
-			dbg(__FUNCTION__ 
-			    " - trying to read more data than available"
-			    " (%d vs. %d)",
+			dbg("%s - trying to read more data than available"
+			    " (%d vs. %d)", __FUNCTION__,
 			    bytes_sent+2, urb->actual_length);
 			/* cap at implied limit */
 			bytes_sent = urb->actual_length - 2;
@@ -780,8 +706,7 @@
 		      port);
 	rc = usb_submit_urb(port->read_urb);
 	if (rc)
-		err(__FUNCTION__ 
-		    " - failed resubmitting read urb, error %d", rc);
+		err("%s - failed resubmitting read urb, error %d", __FUNCTION__, rc);
 } /* klsi_105_read_bulk_callback */
 
 
@@ -801,7 +726,7 @@
 	if( (cflag & CBAUD) != (old_cflag & CBAUD) ) {
 	        /* reassert DTR and (maybe) RTS on transition from B0 */
 		if( (old_cflag & CBAUD) == B0 ) {
-			dbg(__FUNCTION__ ": baud was B0");
+			dbg("%s: baud was B0", __FUNCTION__);
 #if 0
 			priv->control_state |= TIOCM_DTR;
 			/* don't set RTS if using hardware flow control */
@@ -839,7 +764,7 @@
 			break;
 		}
 		if ((cflag & CBAUD) == B0 ) {
-			dbg(__FUNCTION__ ": baud is B0");
+			dbg("%s: baud is B0", __FUNCTION__);
 			/* Drop RTS and DTR */
 			/* maybe this should be simulated by sending read
 			 * disable and read enable messages?
@@ -856,10 +781,10 @@
 		/* set the number of data bits */
 		switch (cflag & CSIZE) {
 		case CS5:
-			dbg(__FUNCTION__ " - 5 bits/byte not supported");
+			dbg("%s - 5 bits/byte not supported", __FUNCTION__);
 			return ;
 		case CS6:
-			dbg(__FUNCTION__ " - 6 bits/byte not supported");
+			dbg("%s - 6 bits/byte not supported", __FUNCTION__);
 			return ;
 		case CS7:
 			priv->cfg.databits = kl5kusb105a_dtb_7;
@@ -930,7 +855,7 @@
 	struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
 	unsigned char lcr = priv->last_lcr;
 
-	dbg (__FUNCTION__ "state=%d", break_state);
+	dbg("%sstate=%d", __FUNCTION__, break_state);
 
 	if (break_state)
 		lcr |= MCT_U232_SET_BREAK;
@@ -946,14 +871,14 @@
 	struct klsi_105_private *priv = (struct klsi_105_private *)port->private;
 	int mask;
 	
-	dbg (__FUNCTION__ "cmd=0x%x", cmd);
+	dbg("%scmd=0x%x", __FUNCTION__, cmd);
 
 	/* Based on code from acm.c and others */
 	switch (cmd) {
 	case TIOCMGET: {
 		int rc;
 		unsigned long line_state;
-		dbg (__FUNCTION__ " - TIOCMGET request, just guessing");
+		dbg("%s - TIOCMGET request, just guessing", __FUNCTION__);
 
 		rc = klsi_105_get_line_state(serial, &line_state);
 		if (rc < 0) {
@@ -962,7 +887,7 @@
 			return -ENOIOCTLCMD;
 		} else {
 			priv->line_state = line_state;
-			dbg(__FUNCTION__ " - read line state 0x%lx", line_state);
+			dbg("%s - read line state 0x%lx", __FUNCTION__, line_state);
 		}
 		return put_user(priv->line_state, (unsigned long *) arg); 
 	       };
@@ -977,10 +902,10 @@
 			/* RTS needs set */
 			if( ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) ||
 			    (cmd == TIOCMBIS) )
-				dbg (__FUNCTION__ " - set RTS not handled");
+				dbg("%s - set RTS not handled", __FUNCTION__);
 				/* priv->control_state |=  TIOCM_RTS; */
 			else
-				dbg (__FUNCTION__ " - clear RTS not handled");
+				dbg("%s - clear RTS not handled", __FUNCTION__);
 				/* priv->control_state &= ~TIOCM_RTS; */
 		}
 
@@ -988,10 +913,10 @@
 			/* DTR needs set */
 			if( ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) ||
 			    (cmd == TIOCMBIS) )
-				dbg (__FUNCTION__ " - set DTR not handled");
+				dbg("%s - set DTR not handled", __FUNCTION__);
 			/*	priv->control_state |=  TIOCM_DTR; */
 			else
-				dbg (__FUNCTION__ " - clear DTR not handled");
+				dbg("%s - clear DTR not handled", __FUNCTION__);
 				/* priv->control_state &= ~TIOCM_DTR; */
 		}
 		/*
@@ -1002,19 +927,19 @@
 	case TIOCMIWAIT:
 		/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
 		/* TODO */
-		dbg (__FUNCTION__ " - TIOCMIWAIT not handled");
+		dbg("%s - TIOCMIWAIT not handled", __FUNCTION__);
 		return -ENOIOCTLCMD;
 
 	case TIOCGICOUNT:
 		/* return count of modemline transitions */
 		/* TODO */
-		dbg (__FUNCTION__ " - TIOCGICOUNT not handled");
+		dbg("%s - TIOCGICOUNT not handled", __FUNCTION__);
 		return -ENOIOCTLCMD;
 	case TCGETS: {
 	     /* return current info to caller */
 	     int retval;
 
-	     dbg (__FUNCTION__ " - TCGETS data faked/incomplete");
+	     dbg("%s - TCGETS data faked/incomplete", __FUNCTION__);
 
 	     retval = verify_area(VERIFY_WRITE, (void *)arg,
 				  sizeof(struct termios));
@@ -1030,7 +955,7 @@
 		/* set port termios to the one given by the user */
 		int retval;
 
-		dbg (__FUNCTION__ " - TCSETS not handled");
+		dbg("%s - TCSETS not handled", __FUNCTION__);
 
 		retval = verify_area(VERIFY_READ, (void *)arg,
 				     sizeof(struct termios));
@@ -1056,7 +981,7 @@
 		return -ENOIOCTLCMD;
 		      }
 	default:
-		dbg(__FUNCTION__ ": arg not supported - 0x%04x",cmd);
+		dbg("%s: arg not supported - 0x%04x", __FUNCTION__,cmd);
 		return(-ENOIOCTLCMD);
 		break;
 	}
@@ -1065,41 +990,27 @@
 
 static void klsi_105_throttle (struct usb_serial_port *port)
 {
-
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	down (&port->sem);
-
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	usb_unlink_urb (port->read_urb);
-
-	up (&port->sem);
-
-	return;
 }
+
 static void klsi_105_unthrottle (struct usb_serial_port *port)
 {
 	int result;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	down (&port->sem);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	port->read_urb->dev = port->serial->dev;
 	result = usb_submit_urb(port->read_urb);
 	if (result)
-		err(__FUNCTION__ " - failed submitting read urb, error %d",
+		err("%s - failed submitting read urb, error %d", __FUNCTION__,
 		    result);
-
-	up (&port->sem);
-
-	return;
 }
 
 
 
 static int __init klsi_105_init (void)
 {
-	usb_serial_register (&palmconnect_device);
 	usb_serial_register (&kl5kusb105d_device);
 
 	info(DRIVER_DESC " " DRIVER_VERSION);
@@ -1109,7 +1020,6 @@
 
 static void __exit klsi_105_exit (void)
 {
-	usb_serial_deregister (&palmconnect_device);
 	usb_serial_deregister (&kl5kusb105d_device);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/kl5kusb105.h linux-2.4.20/drivers/usb/serial/kl5kusb105.h
--- linux-2.4.19/drivers/usb/serial/kl5kusb105.h	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/kl5kusb105.h	2002-10-29 11:18:49.000000000 +0000
@@ -16,7 +16,7 @@
 
 /* baud rates */
 
-typedef enum {
+enum {
   kl5kusb105a_sio_b115200 = 0,
   kl5kusb105a_sio_b57600  = 1,
   kl5kusb105a_sio_b38400  = 2,
@@ -27,7 +27,7 @@
   kl5kusb105a_sio_b2400   = 9,   /* unchecked */
   kl5kusb105a_sio_b1200   = 0xa,  /* unchecked */
   kl5kusb105a_sio_b600    = 0xb   /* unchecked */
-} KL5KUSB105A_SIO_baudrate_t;
+};
 
 /* data bits */
 #define kl5kusb105a_dtb_7   7
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/mct_u232.c linux-2.4.20/drivers/usb/serial/mct_u232.c
--- linux-2.4.19/drivers/usb/serial/mct_u232.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/mct_u232.c	2002-10-29 11:18:49.000000000 +0000
@@ -61,18 +61,15 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <asm/uaccess.h>
 #include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
@@ -132,7 +129,7 @@
 /*
  * All of the device info needed for the MCT USB-RS232 converter.
  */
-static __devinitdata struct usb_device_id id_table_combined [] = {
+static struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(MCT_U232_VID, MCT_U232_PID) },
 	{ USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) },
 	{ USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) },
@@ -140,99 +137,31 @@
 	{ }		/* Terminating entry */
 };
 
-static __devinitdata struct usb_device_id mct_u232_table [] = {
-        { USB_DEVICE(MCT_U232_VID, MCT_U232_PID) },
-	{ USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) },
-        { }                        /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id mct_u232_sitecom_table [] = {
-        { USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) },
-        { }                        /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id mct_u232_du_h3sp_table [] = {
-        { USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) },
-        { }                        /* Terminating entry */
-};
-
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
 
 static struct usb_serial_device_type mct_u232_device = {
-	name:		     "Magic Control Technology USB-RS232",
-	id_table:	     mct_u232_table,
-	needs_interrupt_in:  MUST_HAVE,	 /* 2 interrupt-in endpoints */
-	needs_bulk_in:	     MUST_HAVE_NOT,   /* no bulk-in endpoint */
-	needs_bulk_out:	     MUST_HAVE,	      /* 1 bulk-out endpoint */
-	num_interrupt_in:    2,
-	num_bulk_in:	     0,
-	num_bulk_out:	     1,
-	num_ports:	     1,
-	open:		     mct_u232_open,
-	close:		     mct_u232_close,
+	.owner =	     THIS_MODULE,
+	.name =		     "Magic Control Technology USB-RS232",
+	.id_table =	     id_table_combined,
+	.num_interrupt_in =  2,
+	.num_bulk_in =	     0,
+	.num_bulk_out =	     1,
+	.num_ports =	     1,
+	.open =		     mct_u232_open,
+	.close =	     mct_u232_close,
 #ifdef FIX_WRITE_RETURN_CODE_PROBLEM
-	write:		     mct_u232_write,
-	write_bulk_callback: mct_u232_write_bulk_callback,
+	.write =	     mct_u232_write,
+	.write_bulk_callback = mct_u232_write_bulk_callback,
 #endif
-	read_int_callback:   mct_u232_read_int_callback,
-	ioctl:		     mct_u232_ioctl,
-	set_termios:	     mct_u232_set_termios,
-	break_ctl:	     mct_u232_break_ctl,
-	startup:	     mct_u232_startup,
-	shutdown:	     mct_u232_shutdown,
+	.read_int_callback = mct_u232_read_int_callback,
+	.ioctl =	     mct_u232_ioctl,
+	.set_termios =	     mct_u232_set_termios,
+	.break_ctl =	     mct_u232_break_ctl,
+	.startup =	     mct_u232_startup,
+	.shutdown =	     mct_u232_shutdown,
 };
 
-static struct usb_serial_device_type mct_u232_sitecom_device = {
-	name:		     "MCT/Sitecom USB-RS232",
-	id_table:	     mct_u232_sitecom_table,
-	needs_interrupt_in:  MUST_HAVE,	 /* 2 interrupt-in endpoints */
-	needs_bulk_in:	     MUST_HAVE_NOT,   /* no bulk-in endpoint */
-	needs_bulk_out:	     MUST_HAVE,	      /* 1 bulk-out endpoint */
-	num_interrupt_in:    2,
-	num_bulk_in:	     0,
-	num_bulk_out:	     1,
-	num_ports:	     1,
-	open:		     mct_u232_open,
-	close:		     mct_u232_close,
-#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
-	write:		     mct_u232_write,
-	write_bulk_callback: mct_u232_write_bulk_callback,
-#endif
-	read_int_callback:   mct_u232_read_int_callback,
-	ioctl:		     mct_u232_ioctl,
-	set_termios:	     mct_u232_set_termios,
-	break_ctl:	     mct_u232_break_ctl,
-	startup:	     mct_u232_startup,
-	shutdown:	     mct_u232_shutdown,
-};
-
-static struct usb_serial_device_type mct_u232_du_h3sp_device = {
-        name:                "MCT/D-Link DU-H3SP USB BAY",
-        id_table:            mct_u232_du_h3sp_table,
-        needs_interrupt_in:  MUST_HAVE,  /* 2 interrupt-in endpoints */
-        needs_bulk_in:       MUST_HAVE_NOT,   /* no bulk-in endpoint */
-        needs_bulk_out:      MUST_HAVE,       /* 1 bulk-out endpoint */
-        num_interrupt_in:    2,
-        num_bulk_in:         0,
-        num_bulk_out:        1,
-        num_ports:           1,
-        open:                mct_u232_open,
-        close:               mct_u232_close,
-#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
-        write:               mct_u232_write,
-        write_bulk_callback: mct_u232_write_bulk_callback,
-#endif
-        read_int_callback:   mct_u232_read_int_callback,
-        ioctl:               mct_u232_ioctl,
-        set_termios:         mct_u232_set_termios,
-        break_ctl:           mct_u232_break_ctl,
-        startup:             mct_u232_startup,
-        shutdown:            mct_u232_shutdown,
-};
-
-
-
 
 struct mct_u232_private {
 	unsigned long	     control_state; /* Modem Line Setting (TIOCM) */
@@ -388,13 +317,10 @@
 {
 	int i;
 	
-	dbg (__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	/* stop reads and writes on all ports */
 	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
-			mct_u232_close (&serial->port[i], NULL);
-		}
 		/* My special items, the standard routines free my urbs */
 		if (serial->port[i].private)
 			kfree(serial->port[i].private);
@@ -407,94 +333,72 @@
 	struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
 	int retval = 0;
 
-	dbg(__FUNCTION__" port %d", port->number);
+	dbg("%s port %d", __FUNCTION__, port->number);
 
-	down (&port->sem);
-	
-	++port->open_count;
-	MOD_INC_USE_COUNT;
+	/* Compensate for a hardware bug: although the Sitecom U232-P25
+	 * device reports a maximum output packet size of 32 bytes,
+	 * it seems to be able to accept only 16 bytes (and that's what
+	 * SniffUSB says too...)
+	 */
+	if (serial->dev->descriptor.idProduct == MCT_U232_SITECOM_PID)
+		port->bulk_out_size = 16;
 
-	if (!port->active) {
-		port->active = 1;
-
-		/* Compensate for a hardware bug: although the Sitecom U232-P25
-		 * device reports a maximum output packet size of 32 bytes,
-		 * it seems to be able to accept only 16 bytes (and that's what
-		 * SniffUSB says too...)
-		 */
-		if (serial->dev->descriptor.idProduct == MCT_U232_SITECOM_PID)
-			port->bulk_out_size = 16;
-
-		/* Do a defined restart: the normal serial device seems to 
-		 * always turn on DTR and RTS here, so do the same. I'm not
-		 * sure if this is really necessary. But it should not harm
-		 * either.
-		 */
-		if (port->tty->termios->c_cflag & CBAUD)
-			priv->control_state = TIOCM_DTR | TIOCM_RTS;
-		else
-			priv->control_state = 0;
-		mct_u232_set_modem_ctrl(serial, priv->control_state);
-		
-		priv->last_lcr = (MCT_U232_DATA_BITS_8 | 
-				  MCT_U232_PARITY_NONE |
-				  MCT_U232_STOP_BITS_1);
-		mct_u232_set_line_ctrl(serial, priv->last_lcr);
+	/* Do a defined restart: the normal serial device seems to 
+	 * always turn on DTR and RTS here, so do the same. I'm not
+	 * sure if this is really necessary. But it should not harm
+	 * either.
+	 */
+	if (port->tty->termios->c_cflag & CBAUD)
+		priv->control_state = TIOCM_DTR | TIOCM_RTS;
+	else
+		priv->control_state = 0;
+	mct_u232_set_modem_ctrl(serial, priv->control_state);
+	
+	priv->last_lcr = (MCT_U232_DATA_BITS_8 | 
+			  MCT_U232_PARITY_NONE |
+			  MCT_U232_STOP_BITS_1);
+	mct_u232_set_line_ctrl(serial, priv->last_lcr);
 
-		/* Read modem status and update control state */
-		mct_u232_get_modem_stat(serial, &priv->last_msr);
-		mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
-
-		{
-			/* Puh, that's dirty */
-			struct usb_serial_port *rport;	
-			rport = &serial->port[1];
-			rport->tty = port->tty;
-			rport->private = port->private;
-			port->read_urb = rport->interrupt_in_urb;
-		}
-
-		port->read_urb->dev = port->serial->dev;
-		retval = usb_submit_urb(port->read_urb);
-		if (retval) {
-			err("usb_submit_urb(read bulk) failed");
-			goto exit;
-		}
-
-		port->interrupt_in_urb->dev = port->serial->dev;
-		retval = usb_submit_urb(port->interrupt_in_urb);
-		if (retval)
-			err(" usb_submit_urb(read int) failed");
+	/* Read modem status and update control state */
+	mct_u232_get_modem_stat(serial, &priv->last_msr);
+	mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
 
-	}
+	{
+		/* Puh, that's dirty */
+		struct usb_serial_port *rport;	
+		rport = &serial->port[1];
+		rport->tty = port->tty;
+		rport->private = port->private;
+		port->read_urb = rport->interrupt_in_urb;
+	}
+
+	port->read_urb->dev = port->serial->dev;
+	retval = usb_submit_urb(port->read_urb);
+	if (retval) {
+		err("usb_submit_urb(read bulk) failed");
+		goto exit;
+	}
+
+	port->interrupt_in_urb->dev = port->serial->dev;
+	retval = usb_submit_urb(port->interrupt_in_urb);
+	if (retval)
+		err(" usb_submit_urb(read int) failed");
 
 exit:
-	up (&port->sem);
-	
 	return 0;
 } /* mct_u232_open */
 
 
 static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
 {
-	dbg(__FUNCTION__" port %d", port->number);
-
-	down (&port->sem);
+	dbg("%s port %d", __FUNCTION__, port->number);
 
-	--port->open_count;
-
-	if (port->open_count <= 0) {
-		if (port->serial->dev) {
-			/* shutdown our urbs */
-			usb_unlink_urb (port->write_urb);
-			usb_unlink_urb (port->read_urb);
-			usb_unlink_urb (port->interrupt_in_urb);
-		}
-		port->active = 0;
+	if (port->serial->dev) {
+		/* shutdown our urbs */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->read_urb);
+		usb_unlink_urb (port->interrupt_in_urb);
 	}
-	
-	up (&port->sem);
-	MOD_DEC_USE_COUNT;
 } /* mct_u232_close */
 
 
@@ -507,10 +411,10 @@
 	struct usb_serial *serial = port->serial;
 	int result, bytes_sent, size;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (count == 0) {
-		dbg(__FUNCTION__ " - write request of 0 bytes");
+		dbg("%s - write request of 0 bytes", __FUNCTION__);
 		return (0);
 	}
 
@@ -520,22 +424,18 @@
 	
 	/* another write is still pending? */
 	if (port->write_urb->status == -EINPROGRESS) {
-		dbg (__FUNCTION__ " - already writing");
+		dbg("%s - already writing", __FUNCTION__);
 		return (0);
 	}
 		
 	bytes_sent = 0;
 	while (count > 0) {
-		
-		down (&port->sem);
-		
 		size = (count > port->bulk_out_size) ? port->bulk_out_size : count;
 		
 		usb_serial_debug_data (__FILE__, __FUNCTION__, size, buf);
 		
 		if (from_user) {
 			if (copy_from_user(port->write_urb->transfer_buffer, buf, size)) {
-				up (&port->sem);
 				return -EFAULT;
 			}
 		}
@@ -556,14 +456,10 @@
 		/* send the data out the bulk port */
 		result = usb_submit_urb(port->write_urb);
 		if (result) {
-			err(__FUNCTION__
-			    " - failed submitting write urb, error %d", result);
-			up (&port->sem);
+			err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 			return result;
 		}
 
-		up (&port->sem);
-
 		bytes_sent += size;
 		if (write_blocking)
 			interruptible_sleep_on(&port->write_wait);
@@ -583,15 +479,15 @@
 	struct usb_serial *serial = port->serial;
        	struct tty_struct *tty = port->tty;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero write bulk status received: %d",
+		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__,
 		    urb->status);
 		return;
 	}
@@ -621,16 +517,16 @@
 	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
 
-        dbg(__FUNCTION__ " - port %d", port->number);
+        dbg("%s - port %d", __FUNCTION__, port->number);
 
 	/* The urb might have been killed. */
         if (urb->status) {
-                dbg(__FUNCTION__ " - nonzero read bulk status received: %d",
+                dbg("%s - nonzero read bulk status received: %d", __FUNCTION__,
 		    urb->status);
                 return;
         }
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 	
@@ -707,7 +603,7 @@
 	if( (cflag & CBAUD) != (old_cflag & CBAUD) ) {
 	        /* reassert DTR and (maybe) RTS on transition from B0 */
 		if( (old_cflag & CBAUD) == B0 ) {
-			dbg(__FUNCTION__ ": baud was B0");
+			dbg("%s: baud was B0", __FUNCTION__);
 			priv->control_state |= TIOCM_DTR;
 			/* don't set RTS if using hardware flow control */
 			if (!(old_cflag & CRTSCTS)) {
@@ -743,7 +639,7 @@
 			mct_u232_set_baud_rate(serial, 9600); break;
 		}
 		if ((cflag & CBAUD) == B0 ) {
-			dbg(__FUNCTION__ ": baud is B0");
+			dbg("%s: baud is B0", __FUNCTION__);
 			/* Drop RTS and DTR */
 			priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
         		mct_u232_set_modem_ctrl(serial, priv->control_state);
@@ -814,7 +710,7 @@
 	struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
 	unsigned char lcr = priv->last_lcr;
 
-	dbg (__FUNCTION__ "state=%d", break_state);
+	dbg("%sstate=%d", __FUNCTION__, break_state);
 
 	if (break_state)
 		lcr |= MCT_U232_SET_BREAK;
@@ -830,7 +726,7 @@
 	struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
 	int mask;
 	
-	dbg (__FUNCTION__ "cmd=0x%x", cmd);
+	dbg("%scmd=0x%x", __FUNCTION__, cmd);
 
 	/* Based on code from acm.c and others */
 	switch (cmd) {
@@ -875,7 +771,7 @@
 		return 0;
 
 	default:
-		dbg(__FUNCTION__ ": arg not supported - 0x%04x",cmd);
+		dbg("%s: arg not supported - 0x%04x", __FUNCTION__,cmd);
 		return(-ENOIOCTLCMD);
 		break;
 	}
@@ -886,9 +782,7 @@
 static int __init mct_u232_init (void)
 {
 	usb_serial_register (&mct_u232_device);
-	usb_serial_register (&mct_u232_sitecom_device);
-	usb_serial_register (&mct_u232_du_h3sp_device);
-	info(DRIVER_VERSION ":" DRIVER_DESC);
+	info(DRIVER_DESC " " DRIVER_VERSION);
 	return 0;
 }
 
@@ -896,8 +790,6 @@
 static void __exit mct_u232_exit (void)
 {
 	usb_serial_deregister (&mct_u232_device);
-	usb_serial_deregister (&mct_u232_sitecom_device);
-	usb_serial_deregister (&mct_u232_du_h3sp_device);
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/omninet.c linux-2.4.20/drivers/usb/serial/omninet.c
--- linux-2.4.19/drivers/usb/serial/omninet.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/omninet.c	2002-10-29 11:18:36.000000000 +0000
@@ -37,18 +37,15 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <asm/uaccess.h>
 #include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
@@ -79,7 +76,7 @@
 static int  omninet_write_room		(struct usb_serial_port *port);
 static void omninet_shutdown		(struct usb_serial *serial);
 
-static __devinitdata struct usb_device_id id_table [] = {
+static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) },
 	{ }						/* Terminating entry */
 };
@@ -88,22 +85,20 @@
 
 
 static struct usb_serial_device_type zyxel_omninet_device = {
-	name:			"ZyXEL - omni.net lcd plus usb",
-	id_table:		id_table,
-	needs_interrupt_in:	MUST_HAVE,
-	needs_bulk_in:		MUST_HAVE,
-	needs_bulk_out:		MUST_HAVE,
-	num_interrupt_in:	1,
-	num_bulk_in:		1,
-	num_bulk_out:		2,
-	num_ports:		1,
-	open:			omninet_open,
-	close:			omninet_close,
-	write:			omninet_write,
-	write_room:		omninet_write_room,
-	read_bulk_callback:	omninet_read_bulk_callback,
-	write_bulk_callback:	omninet_write_bulk_callback,
-	shutdown:		omninet_shutdown,
+	.owner =		THIS_MODULE,
+	.name =			"ZyXEL - omni.net lcd plus usb",
+	.id_table =		id_table,
+	.num_interrupt_in =	1,
+	.num_bulk_in =		1,
+	.num_bulk_out =		2,
+	.num_ports =		1,
+	.open =			omninet_open,
+	.close =		omninet_close,
+	.write =		omninet_write,
+	.write_room =		omninet_write_room,
+	.read_bulk_callback =	omninet_read_bulk_callback,
+	.write_bulk_callback =	omninet_write_bulk_callback,
+	.shutdown =		omninet_shutdown,
 };
 
 
@@ -153,45 +148,30 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return -ENODEV;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	serial = get_usb_serial (port, __FUNCTION__);
 	if (!serial)
 		return -ENODEV;
 
-	down (&port->sem);
-
-	MOD_INC_USE_COUNT;
-	++port->open_count;
-
-	if (!port->active) {
-		port->active = 1;
-
-		od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
-		if( !od ) {
-			err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct omninet_data));
-			--port->open_count;
-			port->active = 0;
-			up (&port->sem);
-			MOD_DEC_USE_COUNT;
-			return -ENOMEM;
-		}
-
-		port->private = od;
-		wport = &serial->port[1];
-		wport->tty = port->tty;
-
-		/* Start reading from the device */
-		FILL_BULK_URB(port->read_urb, serial->dev, 
-			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-			      omninet_read_bulk_callback, port);
-		result = usb_submit_urb(port->read_urb);
-		if (result)
-			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+	od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
+	if( !od ) {
+		err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data));
+		return -ENOMEM;
 	}
 
-	up (&port->sem);
+	port->private = od;
+	wport = &serial->port[1];
+	wport->tty = port->tty;
+
+	/* Start reading from the device */
+	FILL_BULK_URB(port->read_urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+		      omninet_read_bulk_callback, port);
+	result = usb_submit_urb(port->read_urb);
+	if (result)
+		err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
 
 	return result;
 }
@@ -205,32 +185,21 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	serial = get_usb_serial (port, __FUNCTION__);
 	if (!serial)
 		return;
 
-	down (&port->sem);
-
-	--port->open_count;
-
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			wport = &serial->port[1];
-			usb_unlink_urb (wport->write_urb);
-			usb_unlink_urb (port->read_urb);
-		}
-
-		port->active = 0;
-		port->open_count = 0;
-		od = (struct omninet_data *)port->private;
-		if (od)
-			kfree(od);
+	if (serial->dev) {
+		wport = &serial->port[1];
+		usb_unlink_urb (wport->write_urb);
+		usb_unlink_urb (port->read_urb);
 	}
 
-	up (&port->sem);
-	MOD_DEC_USE_COUNT;
+	od = (struct omninet_data *)port->private;
+	if (od)
+		kfree(od);
 }
 
 
@@ -252,12 +221,12 @@
 //	dbg("omninet_read_bulk_callback");
 
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
@@ -285,7 +254,7 @@
 		      omninet_read_bulk_callback, port);
 	result = usb_submit_urb(urb);
 	if (result)
-		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+		err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
 
 	return;
 }
@@ -303,11 +272,11 @@
 //	dbg("omninet_write port %d", port->number);
 
 	if (count == 0) {
-		dbg(__FUNCTION__" - write request of 0 bytes");
+		dbg("%s - write request of 0 bytes", __FUNCTION__);
 		return (0);
 	}
 	if (wport->write_urb->status == -EINPROGRESS) {
-		dbg (__FUNCTION__" - already writing");
+		dbg("%s - already writing", __FUNCTION__);
 		return (0);
 	}
 
@@ -336,7 +305,7 @@
 	wport->write_urb->dev = serial->dev;
 	result = usb_submit_urb(wport->write_urb);
 	if (result)
-		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+		err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 	else
 		result = count;
 
@@ -379,7 +348,7 @@
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__" - nonzero write bulk status received: %d", urb->status);
+		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
@@ -394,11 +363,7 @@
 
 static void omninet_shutdown (struct usb_serial *serial)
 {
-	dbg (__FUNCTION__);
-
-	while (serial->port[0].open_count > 0) {
-		omninet_close (&serial->port[0], NULL);
-	}
+	dbg ("%s", __FUNCTION__);
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/pl2303.c linux-2.4.20/drivers/usb/serial/pl2303.c
--- linux-2.4.19/drivers/usb/serial/pl2303.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/pl2303.c	2002-10-29 11:18:40.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * Prolific PL2303 USB to serial adaptor driver
  *
- * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
  *
  * Original driver for 2.2.x by anonymous
  *
@@ -32,19 +32,16 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <asm/uaccess.h>
 #include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
@@ -64,11 +61,14 @@
 
 
 
-static __devinitdata struct usb_device_id id_table [] = {
+static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
 	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
 	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
+	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
+	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
+	{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -116,26 +116,24 @@
 
 /* All of the device info needed for the PL2303 SIO serial converter */
 static struct usb_serial_device_type pl2303_device = {
-	name:			"PL-2303",
-	id_table:		id_table,
-	needs_interrupt_in:	DONT_CARE,		/* this device must have an interrupt in endpoint */
-	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
-	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		1,
-	num_bulk_out:		1,
-	num_ports:		1,
-	open:			pl2303_open,
-	close:			pl2303_close,
-	write:			pl2303_write,
-	ioctl:			pl2303_ioctl,
-	break_ctl:		pl2303_break_ctl,
-	set_termios:		pl2303_set_termios,
-	read_bulk_callback:	pl2303_read_bulk_callback,
-	read_int_callback:	pl2303_read_int_callback,
-	write_bulk_callback:	pl2303_write_bulk_callback,
-	startup:		pl2303_startup,
-	shutdown:		pl2303_shutdown,
+	.owner =		THIS_MODULE,
+	.name =			"PL-2303",
+	.id_table =		id_table,
+	.num_interrupt_in =	NUM_DONT_CARE,
+	.num_bulk_in =		1,
+	.num_bulk_out =		1,
+	.num_ports =		1,
+	.open =			pl2303_open,
+	.close =		pl2303_close,
+	.write =		pl2303_write,
+	.ioctl =		pl2303_ioctl,
+	.break_ctl =		pl2303_break_ctl,
+	.set_termios =		pl2303_set_termios,
+	.read_bulk_callback =	pl2303_read_bulk_callback,
+	.read_int_callback =	pl2303_read_int_callback,
+	.write_bulk_callback =	pl2303_write_bulk_callback,
+	.startup =		pl2303_startup,
+	.shutdown =		pl2303_shutdown,
 };
 
 struct pl2303_private { 
@@ -166,7 +164,7 @@
 	retval = usb_control_msg (dev, usb_sndctrlpipe (dev, 0),
 				  SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
 				  value, 0, NULL, 0, 100);
-	dbg (__FUNCTION__" - value = %d, retval = %d", value, retval);
+	dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval);
 	return retval;
 }
 
@@ -174,15 +172,10 @@
 {
 	int result;
 
-	dbg (__FUNCTION__ " - port %d, %d bytes", port->number, count);
-
-	if (!port->tty) {
-		err (__FUNCTION__ " - no tty???");
-		return 0;
-	}
+	dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
 
 	if (port->write_urb->status == -EINPROGRESS) {
-		dbg (__FUNCTION__ " - already writing");
+		dbg("%s - already writing", __FUNCTION__);
 		return 0;
 	}
 
@@ -200,7 +193,7 @@
 	port->write_urb->dev = port->serial->dev;
 	result = usb_submit_urb (port->write_urb);
 	if (result)
-		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+		err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 	else
 		result = count;
 
@@ -218,15 +211,15 @@
 	int baud;
 	int i;
 
-	dbg (__FUNCTION__ " -  port %d, initialized = %d", port->number, 
+	dbg("%s -  port %d, initialized = %d", __FUNCTION__, port->number, 
 	     ((struct pl2303_private *) port->private)->termios_initialized);
 
 	if ((!port->tty) || (!port->tty->termios)) {
-		dbg(__FUNCTION__" - no tty structures");
+		dbg("%s - no tty structures", __FUNCTION__);
 		return;
 	}
 
-	if (!(((struct pl2303_private *)port->private)->termios_initialized)) {
+	if (!(((struct pl2303_private *) port->private)->termios_initialized)) {
 		*(port->tty->termios) = tty_std_termios;
 		port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
 		((struct pl2303_private *) port->private)->termios_initialized = 1;
@@ -236,14 +229,14 @@
 	if (old_termios) {
 		if ((cflag == old_termios->c_cflag) &&
 		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
-		    dbg(__FUNCTION__ " - nothing to change...");
+		    dbg("%s - nothing to change...", __FUNCTION__);
 		    return;
 		}
 	}
 
 	buf = kmalloc (7, GFP_KERNEL);
 	if (!buf) {
-		err(__FUNCTION__ " - out of memory.");
+		err("%s - out of memory.", __FUNCTION__);
 		return;
 	}
 	memset (buf, 0x00, 0x07);
@@ -269,7 +262,7 @@
 			default:
 			case CS8:	buf[6] = 8;	break;
 		}
-		dbg (__FUNCTION__ " - data bits = %d", buf[6]);
+		dbg("%s - data bits = %d", __FUNCTION__, buf[6]);
 	}
 
 	baud = 0;
@@ -294,7 +287,7 @@
 			err ("pl2303 driver does not support the baudrate requested (fix it)");
 			break;
 	}
-	dbg (__FUNCTION__ " - baud = %d", baud);
+	dbg("%s - baud = %d", __FUNCTION__, baud);
 	if (baud) {
 		buf[0] = baud & 0xff;
 		buf[1] = (baud >> 8) & 0xff;
@@ -307,10 +300,10 @@
 	/* For reference buf[4]=2 is 2 stop bits */
 	if (cflag & CSTOPB) {
 		buf[4] = 2;
-		dbg(__FUNCTION__ " - stop bits = 2");
+		dbg("%s - stop bits = 2", __FUNCTION__);
 	} else {
 		buf[4] = 0;
-		dbg(__FUNCTION__ " - stop bits = 1");
+		dbg("%s - stop bits = 1", __FUNCTION__);
 	}
 
 	if (cflag & PARENB) {
@@ -321,14 +314,14 @@
 		/* For reference buf[5]=4 is space parity */
 		if (cflag & PARODD) {
 			buf[5] = 1;
-			dbg(__FUNCTION__ " - parity = odd");
+			dbg("%s - parity = odd", __FUNCTION__);
 		} else {
 			buf[5] = 2;
-			dbg(__FUNCTION__ " - parity = even");
+			dbg("%s - parity = even", __FUNCTION__);
 		}
 	} else {
 		buf[5] = 0;
-		dbg(__FUNCTION__ " - parity = none");
+		dbg("%s - parity = none", __FUNCTION__);
 	}
 
 	i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
@@ -355,7 +348,7 @@
 
 	if (cflag & CRTSCTS) {
 		i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
-				     VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST_TYPE,
+				     VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
 				     0x0, 0x41, NULL, 0, 100);
 		dbg ("0x40:0x1:0x0:0x41  %d", i);
 	}
@@ -374,64 +367,54 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return -ENODEV;
 		
-	dbg (__FUNCTION__ " -  port %d", port->number);
+	dbg("%s -  port %d", __FUNCTION__, port->number);
 
-	down (&port->sem);
+#define FISH(a,b,c,d)								\
+	result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0),	\
+			       b, a, c, d, buf, 1, 100);			\
+	dbg("0x%x:0x%x:0x%x:0x%x  %d - %x",a,b,c,d,result,buf[0]);
+
+#define SOUP(a,b,c,d)								\
+	result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),	\
+			       b, a, c, d, NULL, 0, 100);			\
+	dbg("0x%x:0x%x:0x%x:0x%x  %d",a,b,c,d,result);
+
+	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
+	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0);
+	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
+	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
+	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
+	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
+	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
+	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
+	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1);
+	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0xc0);
+	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 4);
 
-	++port->open_count;
-	MOD_INC_USE_COUNT;
-
-	if (!port->active) {
-		port->active = 1;
-
-#define FISH(a,b,c,d)									\
-		result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0),	\
-				       b, a, c, d, buf, 1, 100);			\
-		dbg("0x%x:0x%x:0x%x:0x%x  %d - %x",a,b,c,d,result,buf[0]);
-
-#define SOUP(a,b,c,d)									\
-		result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),	\
-				       b, a, c, d, NULL, 0, 100);			\
-		dbg("0x%x:0x%x:0x%x:0x%x  %d",a,b,c,d,result);
-
-		FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
-		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0);
-		FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
-		FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
-		FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
-		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
-		FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
-		FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
-		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1);
-		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0xc0);
-		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 4);
-
-		/* Setup termios */
+	/* Setup termios */
+	if (port->tty) {
 		pl2303_set_termios (port, &tmp_termios);
+	}
 
-		//FIXME: need to assert RTS and DTR if CRTSCTS off
-
-		dbg (__FUNCTION__ " - submitting read urb");
-		port->read_urb->dev = serial->dev;
-		result = usb_submit_urb (port->read_urb);
-		if (result) {
-			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
-			up (&port->sem);
-			pl2303_close (port, NULL);
-			return -EPROTO;
-		}
+	//FIXME: need to assert RTS and DTR if CRTSCTS off
 
-		dbg (__FUNCTION__ " - submitting interrupt urb");
-		port->interrupt_in_urb->dev = serial->dev;
-		result = usb_submit_urb (port->interrupt_in_urb);
-		if (result) {
-			err(__FUNCTION__ " - failed submitting interrupt urb, error %d", result);
-			up (&port->sem);
-			pl2303_close (port, NULL);
-			return -EPROTO;
-		}
+	dbg("%s - submitting read urb", __FUNCTION__);
+	port->read_urb->dev = serial->dev;
+	result = usb_submit_urb (port->read_urb);
+	if (result) {
+		err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+		pl2303_close (port, NULL);
+		return -EPROTO;
+	}
+
+	dbg("%s - submitting interrupt urb", __FUNCTION__);
+	port->interrupt_in_urb->dev = serial->dev;
+	result = usb_submit_urb (port->interrupt_in_urb);
+	if (result) {
+		err("%s - failed submitting interrupt urb, error %d", __FUNCTION__, result);
+		pl2303_close (port, NULL);
+		return -EPROTO;
 	}
-	up (&port->sem);
 	return 0;
 }
 
@@ -449,13 +432,10 @@
 	if (!serial)
 		return;
 	
-	dbg (__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	down (&port->sem);
-
-	--port->open_count;
-	if (port->open_count <= 0) {
-		if (serial->dev) {
+	if (serial->dev) {
+		if (port->tty) {
 			c_cflag = port->tty->termios->c_cflag;
 			if (c_cflag & HUPCL) {
 				/* drop DTR and RTS */
@@ -464,34 +444,28 @@
 				set_control_lines (port->serial->dev,
 						   priv->line_control);
 			}
+		}
 
-			/* shutdown our urbs */
-			dbg (__FUNCTION__ " - shutting down urbs");
-			result = usb_unlink_urb (port->write_urb);
-			if (result)
-				dbg (__FUNCTION__ " - usb_unlink_urb "
-				     "(write_urb) failed with reason: %d",
-				     result);
-
-			result = usb_unlink_urb (port->read_urb);
-			if (result)
-				dbg (__FUNCTION__ " - usb_unlink_urb "
-				     "(read_urb) failed with reason: %d",
-				     result);
+		/* shutdown our urbs */
+		dbg("%s - shutting down urbs", __FUNCTION__);
+		result = usb_unlink_urb (port->write_urb);
+		if (result)
+			dbg("%s - usb_unlink_urb (write_urb)"
+			    " failed with reason: %d", __FUNCTION__,
+			     result);
 
-			result = usb_unlink_urb (port->interrupt_in_urb);
-			if (result)
-				dbg (__FUNCTION__ " - usb_unlink_urb "
-				     "(interrupt_in_urb) failed with reason: %d",
-				     result);
-		}
+		result = usb_unlink_urb (port->read_urb);
+		if (result)
+			dbg("%s - usb_unlink_urb (read_urb) "
+			    "failed with reason: %d", __FUNCTION__,
+			     result);
 
-		port->active = 0;
-		port->open_count = 0;
+		result = usb_unlink_urb (port->interrupt_in_urb);
+		if (result)
+			dbg("%s - usb_unlink_urb (interrupt_in_urb)"
+			    " failed with reason: %d", __FUNCTION__,
+			     result);
 	}
-
-	up (&port->sem);
-	MOD_DEC_USE_COUNT;
 }
 
 static int set_modem_info (struct usb_serial_port *port, unsigned int cmd, unsigned int *value)
@@ -538,7 +512,7 @@
 	result = ((mcr & CONTROL_DTR)		? TIOCM_DTR : 0)
 		  | ((mcr & CONTROL_RTS)	? TIOCM_RTS : 0);
 
-	dbg (__FUNCTION__ " - result = %x", result);
+	dbg("%s - result = %x", __FUNCTION__, result);
 
 	if (copy_to_user(value, &result, sizeof(int)))
 		return -EFAULT;
@@ -547,22 +521,22 @@
 
 static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	dbg (__FUNCTION__" (%d) cmd = 0x%04x", port->number, cmd);
+	dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
 
 	switch (cmd) {
 		
 		case TIOCMGET:
-			dbg (__FUNCTION__" (%d) TIOCMGET", port->number);
+			dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number);
 			return get_modem_info (port, (unsigned int *)arg);
 
 		case TIOCMBIS:
 		case TIOCMBIC:
 		case TIOCMSET:
-			dbg(__FUNCTION__" (%d) TIOCMSET/TIOCMBIC/TIOCMSET",  port->number);
+			dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__,  port->number);
 			return set_modem_info(port, cmd, (unsigned int *) arg);
 
 		default:
-			dbg (__FUNCTION__" not supported = 0x%04x", cmd);
+			dbg("%s not supported = 0x%04x", __FUNCTION__, cmd);
 			break;
 	}
 
@@ -576,19 +550,19 @@
 	u16 state;
 	int result;
 
-	dbg (__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (break_state == 0)
 		state = BREAK_OFF;
 	else
 		state = BREAK_ON;
-	dbg (__FUNCTION__" - turning break %s", state==BREAK_OFF ? "off" : "on");
+	dbg("%s - turning break %s", state==BREAK_OFF ? "off" : "on", __FUNCTION__);
 
 	result = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
 				  BREAK_REQUEST, BREAK_REQUEST_TYPE, state, 
 				  0, NULL, 0, 100);
 	if (result)
-		dbg (__FUNCTION__" - error sending break = %d", result);
+		dbg("%s - error sending break = %d", __FUNCTION__, result);
 }
 
 
@@ -596,14 +570,10 @@
 {
 	int i;
 
-	dbg (__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
-	/* stop everything on all ports */
 	for (i = 0; i < serial->num_ports; ++i)
-		while (serial->port[i].open_count > 0) {
-			pl2303_close (&serial->port[i], NULL);
-			kfree (serial->port[i].private);
-		}
+		kfree (serial->port[i].private);
 }
 
 
@@ -646,37 +616,37 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 
 	if (urb->status) {
-		dbg (__FUNCTION__ " - urb->status = %d", urb->status);
-		if (!port->active) {
-			dbg (__FUNCTION__ " - port is closed, exiting.");
+		dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+		if (!port->open_count) {
+			dbg("%s - port is closed, exiting.", __FUNCTION__);
 			return;
 		}
 		if (urb->status == -EPROTO) {
 			/* PL2303 mysteriously fails with -EPROTO reschedule the read */
-			dbg (__FUNCTION__ " - caught -EPROTO, resubmitting the urb");
+			dbg("%s - caught -EPROTO, resubmitting the urb", __FUNCTION__);
 			urb->status = 0;
 			urb->dev = serial->dev;
 			result = usb_submit_urb(urb);
 			if (result)
-				err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+				err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
 			return;
 		}
-		dbg (__FUNCTION__ " - unable to handle the error, exiting.");
+		dbg("%s - unable to handle the error, exiting.", __FUNCTION__);
 		return;
 	}
 
 	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
 
 	tty = port->tty;
-	if (urb->actual_length) {
+	if (tty && urb->actual_length) {
 		for (i = 0; i < urb->actual_length; ++i) {
 			if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
 				tty_flip_buffer_push(tty);
@@ -687,11 +657,11 @@
 	}
 
 	/* Schedule the next read _if_ we are still open */
-	if (port->active) {
+	if (port->open_count) {
 		urb->dev = serial->dev;
 		result = usb_submit_urb(urb);
 		if (result)
-			err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+			err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
 	}
 
 	return;
@@ -707,20 +677,20 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	
 	if (urb->status) {
 		/* error in the urb, so we have to resubmit it */
 		if (serial_paranoia_check (port->serial, __FUNCTION__)) {
 			return;
 		}
-		dbg (__FUNCTION__ " - Overflow in write");
-		dbg (__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+		dbg("%s - Overflow in write", __FUNCTION__);
+		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 		port->write_urb->transfer_buffer_length = 1;
 		port->write_urb->dev = port->serial->dev;
 		result = usb_submit_urb (port->write_urb);
 		if (result)
-			err(__FUNCTION__ " - failed resubmitting write urb, error %d", result);
+			err("%s - failed resubmitting write urb, error %d", __FUNCTION__, result);
 
 		return;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/pl2303.h linux-2.4.20/drivers/usb/serial/pl2303.h
--- linux-2.4.19/drivers/usb/serial/pl2303.h	2001-10-09 22:15:02.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/pl2303.h	2002-10-29 11:18:48.000000000 +0000
@@ -16,3 +16,12 @@
 
 #define IODATA_VENDOR_ID	0x04bb
 #define IODATA_PRODUCT_ID	0x0a03
+
+#define ELCOM_VENDOR_ID		0x056e
+#define ELCOM_PRODUCT_ID	0x5003
+
+#define ITEGNO_VENDOR_ID	0x0eba
+#define ITEGNO_PRODUCT_ID	0x1080
+
+#define MA620_VENDOR_ID		0x0df7
+#define MA620_PRODUCT_ID	0x0620
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/usb-serial.h linux-2.4.20/drivers/usb/serial/usb-serial.h
--- linux-2.4.19/drivers/usb/serial/usb-serial.h	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/usb-serial.h	2002-10-29 11:18:48.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * USB Serial Converter driver
  *
- *	Copyright (C) 1999 - 2001
+ *	Copyright (C) 1999 - 2002
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -11,6 +11,10 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * (12/03/2001) gkh
+ *	removed active from the port structure.
+ *	added documentation to the usb_serial_device_type structure
+ *
  * (10/10/2001) gkh
  *	added vendor and product to serial structure.  Needed to determine device
  *	owner when the device is disconnected.
@@ -59,13 +63,41 @@
 /* parity check flag */
 #define RELEVANT_IFLAG(iflag)	(iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
 
-
+/**
+ * usb_serial_port: structure for the specific ports of a device.
+ * @magic: magic number for internal validity of this pointer.
+ * @serial: pointer back to the struct usb_serial owner of this port.
+ * @tty: pointer to the coresponding tty for this port.
+ * @number: the number of the port (the minor number).
+ * @interrupt_in_buffer: pointer to the interrupt in buffer for this port.
+ * @interrupt_in_urb: pointer to the interrupt in struct urb for this port.
+ * @interrupt_in_endpointAddress: endpoint address for the interrupt in pipe
+ *	for this port.
+ * @bulk_in_buffer: pointer to the bulk in buffer for this port.
+ * @read_urb: pointer to the bulk in struct urb for this port.
+ * @bulk_in_endpointAddress: endpoint address for the bulk in pipe for this
+ *	port.
+ * @bulk_out_buffer: pointer to the bulk out buffer for this port.
+ * @bulk_out_size: the size of the bulk_out_buffer, in bytes.
+ * @write_urb: pointer to the bulk out struct urb for this port.
+ * @bulk_out_endpointAddress: endpoint address for the bulk out pipe for this
+ *	port.
+ * @write_wait: a wait_queue_head_t used by the port.
+ * @tqueue: task queue for the line discipline waking up.
+ * @open_count: number of times this port has been opened.
+ * @sem: struct semaphore used to lock this structure.
+ * @private: place to put any driver specific information that is needed.  The
+ *	usb-serial driver is required to manage this data, the usb-serial core
+ *	will not touch this.
+ *
+ * This structure is used by the usb-serial core and drivers for the specific
+ * ports of a device.
+ */
 struct usb_serial_port {
 	int			magic;
-	struct usb_serial	*serial;	/* pointer back to the owner of this port */
-	struct tty_struct *	tty;		/* the coresponding tty for this port */
+	struct usb_serial	*serial;
+	struct tty_struct *	tty;
 	unsigned char		number;
-	char			active;		/* someone has this device open */
 
 	unsigned char *		interrupt_in_buffer;
 	struct urb *		interrupt_in_urb;
@@ -81,63 +113,92 @@
 	__u8			bulk_out_endpointAddress;
 
 	wait_queue_head_t	write_wait;
-
-	struct tq_struct	tqueue;		/* task queue for line discipline waking up */
-	int			open_count;	/* number of times this port has been opened */
-	struct semaphore	sem;		/* locks this structure */
-	
-	void *			private;	/* data private to the specific port */
+	struct tq_struct	tqueue;
+	int			open_count;
+	struct semaphore	sem;
+	void *			private;
 };
 
+/**
+ * usb_serial - structure used by the usb-serial core for a device
+ * @magic: magic number for internal validity of this pointer.
+ * @dev: pointer to the struct usb_device for this device
+ * @type: pointer to the struct usb_serial_device_type for this device
+ * @interface: pointer to the struct usb_interface for this device
+ * @minor: the starting minor number for this device
+ * @num_ports: the number of ports this device has
+ * @num_interrupt_in: number of interrupt in endpoints we have
+ * @num_bulk_in: number of bulk in endpoints we have
+ * @num_bulk_out: number of bulk out endpoints we have
+ * @vendor: vendor id of this device
+ * @product: product id of this device
+ * @port: array of struct usb_serial_port structures for the different ports.
+ * @private: place to put any driver specific information that is needed.  The
+ *	usb-serial driver is required to manage this data, the usb-serial core
+ *	will not touch this.
+ */
 struct usb_serial {
 	int				magic;
 	struct usb_device *		dev;
-	struct usb_serial_device_type *	type;			/* the type of usb serial device this is */
-	struct usb_interface *		interface;		/* the interface for this device */
-	struct tty_driver *		tty_driver;		/* the tty_driver for this device */
-	unsigned char			minor;			/* the starting minor number for this device */
-	unsigned char			num_ports;		/* the number of ports this device has */
-	char				num_interrupt_in;	/* number of interrupt in endpoints we have */
-	char				num_bulk_in;		/* number of bulk in endpoints we have */
-	char				num_bulk_out;		/* number of bulk out endpoints we have */
-	__u16				vendor;			/* vendor id of this device */
-	__u16				product;		/* product id of this device */
+	struct usb_serial_device_type *	type;
+	struct usb_interface *		interface;
+	unsigned char			minor;
+	unsigned char			num_ports;
+	char				num_interrupt_in;
+	char				num_bulk_in;
+	char				num_bulk_out;
+	__u16				vendor;
+	__u16				product;
 	struct usb_serial_port		port[MAX_NUM_PORTS];
-
-	void *			private;		/* data private to the specific driver */
+	void *				private;
 };
 
 
-#define MUST_HAVE_NOT	0x01
-#define MUST_HAVE	0x02
-#define DONT_CARE	0x03
-
-#define	HAS		0x02
-#define HAS_NOT		0x01
-
 #define NUM_DONT_CARE	(-1)
 
 
-/* This structure defines the individual serial converter. */
+/**
+ * usb_serial_device_type - a structure that defines a usb serial device
+ * @owner: pointer to the module that owns this device.
+ * @name: pointer to a string that describes this device.  This string used
+ *	in the syslog messages when a device is inserted or removed.
+ * @id_table: pointer to a list of usb_device_id structures that define all
+ *	of the devices this structure can support.
+ * @num_interrupt_in: the number of interrupt in endpoints this device will
+ *	have.
+ * @num_bulk_in: the number of bulk in endpoints this device will have.
+ * @num_bulk_out: the number of bulk out endpoints this device will have.
+ * @num_ports: the number of different ports this device will have.
+ * @calc_num_ports: pointer to a function to determine how many ports this
+ *	device has dynamically.  It will be called after the probe()
+ *	callback is called, but before attach()
+ * @startup: pointer to the driver's startup function.
+ *	This will be called when the device is inserted into the system,
+ *	but before the device has been fully initialized by the usb_serial
+ *	subsystem.  Use this function to download any firmware to the device,
+ *	or any other early initialization that might be needed.
+ *	Return 0 to continue on with the initialization sequence.  Anything 
+ *	else will abort it.
+ * @shutdown: pointer to the driver's shutdown function.  This will be
+ *	called when the device is removed from the system.
+ *
+ * This structure is defines a USB Serial device.  It provides all of
+ * the information that the USB serial core code needs.  If the function
+ * pointers are defined, then the USB serial core code will call them when
+ * the corresponding tty port functions are called.  If they are not
+ * called, the generic serial function will be used instead.
+ */
 struct usb_serial_device_type {
+	struct module *owner;
 	char	*name;
 	const struct usb_device_id *id_table;
-	char	needs_interrupt_in;
-	char	needs_bulk_in;
-	char	needs_bulk_out;
 	char	num_interrupt_in;
 	char	num_bulk_in;
 	char	num_bulk_out;
-	char	num_ports;		/* number of serial ports this device has */
+	char	num_ports;
 
 	struct list_head	driver_list;
 	
-	/* function call to make before accepting driver
-	 * return 0 to continue initialization,
-	 * < 0 aborts startup,
-	 * > 0 does not set up anything else and is useful for devices that have
-	 * downloaded firmware, and will reset themselves shortly.
-	 */
 	int (*startup) (struct usb_serial *serial);
 	
 	void (*shutdown) (struct usb_serial *serial);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/usbserial.c linux-2.4.20/drivers/usb/serial/usbserial.c
--- linux-2.4.19/drivers/usb/serial/usbserial.c	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/usbserial.c	2002-10-29 11:18:39.000000000 +0000
@@ -1,14 +1,13 @@
 /*
  * USB Serial Converter driver
  *
- * Copyright (C) 1999 - 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
  * Copyright (c) 2000 Peter Berger (pberger@brimson.com)
  * Copyright (c) 2000 Al Borchers (borchers@steinerpoint.com)
  *
- *	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 free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License version
+ *	2 as published by the Free Software Foundation.
  *
  * This driver was originally based on the ACM driver by Armin Fuerst (which was 
  * based on a driver by Brad Keryan)
@@ -337,24 +336,15 @@
 
 /* All of the device info needed for the Generic Serial Converter */
 static struct usb_serial_device_type generic_device = {
-	name:			"Generic",
-	id_table:		generic_device_ids,
-	needs_interrupt_in:	DONT_CARE,		/* don't have to have an interrupt in endpoint */
-	needs_bulk_in:		DONT_CARE,		/* don't have to have a bulk in endpoint */
-	needs_bulk_out:		DONT_CARE,		/* don't have to have a bulk out endpoint */
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		1,
-	shutdown:		generic_shutdown,
+	.owner =		THIS_MODULE,
+	.name =			"Generic",
+	.id_table =		generic_device_ids,
+	.num_interrupt_in =	NUM_DONT_CARE,
+	.num_bulk_in =		NUM_DONT_CARE,
+	.num_bulk_out =		NUM_DONT_CARE,
+	.num_ports =		1,
+	.shutdown =		generic_shutdown,
 };
-
-#define if_generic_do(x)			\
-	if ((serial->vendor == vendor) &&	\
-	    (serial->product == product))	\
-	                x
-#else
-#define if_generic_do(x)
 #endif
 
 
@@ -375,10 +365,10 @@
 static void usb_serial_disconnect(struct usb_device *dev, void *ptr);
 
 static struct usb_driver usb_serial_driver = {
-	name:		"serial",
-	probe:		usb_serial_probe,
-	disconnect:	usb_serial_disconnect,
-	id_table:	NULL, 			/* check all devices */
+	.name =		"serial",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	NULL, 			/* check all devices */
 };
 
 /* There is no MODULE_DEVICE_TABLE for usbserial.c.  Instead
@@ -387,7 +377,7 @@
    via modprobe, and modprobe will load usbserial because the serial
    drivers depend on it.
 */
-   
+
 
 static int			serial_refcount;
 static struct tty_driver	serial_tty_driver;
@@ -400,7 +390,7 @@
 static LIST_HEAD(usb_serial_driver_list);
 
 
-static struct usb_serial *get_serial_by_minor (int minor)
+static struct usb_serial *get_serial_by_minor (unsigned int minor)
 {
 	return serial_table[minor];
 }
@@ -412,7 +402,7 @@
 	int i, j;
 	int good_spot;
 
-	dbg(__FUNCTION__ " %d", num_ports);
+	dbg("%s %d", __FUNCTION__, num_ports);
 
 	*minor = 0;
 	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
@@ -427,14 +417,14 @@
 			continue;
 			
 		if (!(serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL))) {
-			err(__FUNCTION__ " - Out of memory");
+			err("%s - Out of memory", __FUNCTION__);
 			return NULL;
 		}
 		memset(serial, 0, sizeof(struct usb_serial));
 		serial->magic = USB_SERIAL_MAGIC;
 		serial_table[i] = serial;
 		*minor = i;
-		dbg(__FUNCTION__ " - minor base = %d", *minor);
+		dbg("%s - minor base = %d", __FUNCTION__, *minor);
 		for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
 			serial_table[i] = serial;
 		return serial;
@@ -442,12 +432,11 @@
 	return NULL;
 }
 
-
 static void return_serial (struct usb_serial *serial)
 {
 	int i;
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	if (serial == NULL)
 		return;
@@ -459,7 +448,6 @@
 	return;
 }
 
-
 #ifdef USES_EZUSB_FUNCTIONS
 /* EZ-USB Control and Status Register.  Bit 0 controls 8051 reset */
 #define CPUCS_REG    0x7F92
@@ -471,36 +459,34 @@
 
 	/* dbg("ezusb_writememory %x, %d", address, length); */
 	if (!serial->dev) {
-		dbg(__FUNCTION__ " - no physical device present, failing.");
+		dbg("%s - no physical device present, failing.", __FUNCTION__);
 		return -ENODEV;
 	}
 
 	transfer_buffer =  kmalloc (length, GFP_KERNEL);
 	if (!transfer_buffer) {
-		err(__FUNCTION__ " - kmalloc(%d) failed.", length);
+		err("%s - kmalloc(%d) failed.", __FUNCTION__, length);
 		return -ENOMEM;
 	}
 	memcpy (transfer_buffer, data, length);
-	result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 300);
+	result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 3*HZ);
 	kfree (transfer_buffer);
 	return result;
 }
 
-
 int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
 {
 	int	response;
-	dbg(__FUNCTION__ " - %d", reset_bit);
+	dbg("%s - %d", __FUNCTION__, reset_bit);
 	response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0);
 	if (response < 0) {
-		err(__FUNCTION__ "- %d failed", reset_bit);
+		err("%s- %d failed", __FUNCTION__, reset_bit);
 	}
 	return response;
 }
 
 #endif	/* USES_EZUSB_FUNCTIONS */
 
-
 /*****************************************************************************
  * Driver tty interface functions
  *****************************************************************************/
@@ -508,9 +494,10 @@
 {
 	struct usb_serial *serial;
 	struct usb_serial_port *port;
-	int portNumber;
+	unsigned int portNumber;
+	int retval = 0;
 	
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	/* initialize the pointer incase something fails */
 	tty->driver_data = NULL;
@@ -518,257 +505,350 @@
 	/* get the serial object associated with this tty pointer */
 	serial = get_serial_by_minor (MINOR(tty->device));
 
-	if (serial_paranoia_check (serial, __FUNCTION__)) {
+	if (serial_paranoia_check (serial, __FUNCTION__))
 		return -ENODEV;
-	}
 
 	/* set up our port structure making the tty driver remember our port object, and us it */
 	portNumber = MINOR(tty->device) - serial->minor;
 	port = &serial->port[portNumber];
 	tty->driver_data = port;
+
+	down (&port->sem);
 	port->tty = tty;
 	 
-	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->open) {
-		return (serial->type->open(port, filp));
-	} else {
-		return (generic_open(port, filp));
+	/* lock this module before we call it */
+	if (serial->type->owner)
+		__MOD_INC_USE_COUNT(serial->type->owner);
+
+	++port->open_count;
+	if (port->open_count == 1) {
+		/* only call the device specific open if this 
+		 * is the first time the port is opened */
+		if (serial->type->open)
+			retval = serial->type->open(port, filp);
+		else
+			retval = generic_open(port, filp);
 	}
+
+	if (retval) {
+		port->open_count = 0;
+		if (serial->type->owner)
+			__MOD_DEC_USE_COUNT(serial->type->owner);
+	}
+
+	up (&port->sem);
+	return retval;
 }
 
+static void __serial_close(struct usb_serial_port *port, struct file *filp)
+{
+	if (!port->open_count) {
+		dbg ("%s - port not opened", __FUNCTION__);
+		return;
+	}
+
+	--port->open_count;
+	if (port->open_count <= 0) {
+		/* only call the device specific close if this 
+		 * port is being closed by the last owner */
+		if (port->serial->type->close)
+			port->serial->type->close(port, filp);
+		else
+			generic_close(port, filp);
+		port->open_count = 0;
+	}
+
+	if (port->serial->type->owner)
+		__MOD_DEC_USE_COUNT(port->serial->type->owner);
+}
 
 static void serial_close(struct tty_struct *tty, struct file * filp)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
-	if (!serial) {
+	if (!serial)
 		return;
-	}
 
-	dbg(__FUNCTION__ " - port %d", port->number);
-	
-	if (!port->active) {
-		dbg (__FUNCTION__ " - port not opened");
-		return;
-	}
+	down (&port->sem);
 
-	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->close) {
-		serial->type->close(port, filp);
-	} else {
-		generic_close(port, filp);
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	/* if disconnect beat us to the punch here, there's nothing to do */
+	if (tty->driver_data) {
+		__serial_close(port, filp);
 	}
-}	
 
+	up (&port->sem);
+}
 
 static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
-	
-	if (!serial) {
+	int retval = -EINVAL;
+
+	if (!serial)
 		return -ENODEV;
-	}
-	
-	dbg(__FUNCTION__ " - port %d, %d byte(s)", port->number, count);
 
-	if (!port->active) {
-		dbg (__FUNCTION__ " - port not opened");
-		return -EINVAL;
+	down (&port->sem);
+
+	dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
+
+	if (!port->open_count) {
+		dbg("%s - port not opened", __FUNCTION__);
+		goto exit;
 	}
-	
+
 	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->write) {
-		return (serial->type->write(port, from_user, buf, count));
-	} else {
-		return (generic_write(port, from_user, buf, count));
-	}
-}
+	if (serial->type->write)
+		retval = serial->type->write(port, from_user, buf, count);
+	else
+		retval = generic_write(port, from_user, buf, count);
 
+exit:
+	up (&port->sem);
+	return retval;
+}
 
 static int serial_write_room (struct tty_struct *tty) 
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+	int retval = -EINVAL;
 
-	if (!serial) {
+	if (!serial)
 		return -ENODEV;
-	}
 
-	dbg(__FUNCTION__ " - port %d", port->number);
-	
-	if (!port->active) {
-		dbg (__FUNCTION__ " - port not open");
-		return -EINVAL;
+	down (&port->sem);
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (!port->open_count) {
+		dbg("%s - port not open", __FUNCTION__);
+		goto exit;
 	}
 
 	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->write_room) {
-		return (serial->type->write_room(port));
-	} else {
-		return (generic_write_room(port));
-	}
-}
+	if (serial->type->write_room)
+		retval = serial->type->write_room(port);
+	else
+		retval = generic_write_room(port);
 
+exit:
+	up (&port->sem);
+	return retval;
+}
 
 static int serial_chars_in_buffer (struct tty_struct *tty) 
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+	int retval = -EINVAL;
 
-	if (!serial) {
+	if (!serial)
 		return -ENODEV;
-	}
 
-	if (!port->active) {
-		dbg (__FUNCTION__ " - port not open");
-		return -EINVAL;
+	down (&port->sem);
+
+	dbg("%s = port %d", __FUNCTION__, port->number);
+
+	if (!port->open_count) {
+		dbg("%s - port not open", __FUNCTION__);
+		goto exit;
 	}
 
 	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->chars_in_buffer) {
-		return (serial->type->chars_in_buffer(port));
-	} else {
-		return (generic_chars_in_buffer(port));
-	}
-}
+	if (serial->type->chars_in_buffer)
+		retval = serial->type->chars_in_buffer(port);
+	else
+		retval = generic_chars_in_buffer(port);
 
+exit:
+	up (&port->sem);
+	return retval;
+}
 
 static void serial_throttle (struct tty_struct * tty)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
-	if (!serial) {
+	if (!serial)
 		return;
-	}
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	down (&port->sem);
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	if (!port->active) {
-		dbg (__FUNCTION__ " - port not open");
-		return;
+	if (!port->open_count) {
+		dbg ("%s - port not open", __FUNCTION__);
+		goto exit;
 	}
 
 	/* pass on to the driver specific version of this function */
-	if (serial->type->throttle) {
+	if (serial->type->throttle)
 		serial->type->throttle(port);
-	}
 
-	return;
+exit:
+	up (&port->sem);
 }
 
-
 static void serial_unthrottle (struct tty_struct * tty)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
-	if (!serial) {
+	if (!serial)
 		return;
-	}
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	down (&port->sem);
 
-	if (!port->active) {
-		dbg (__FUNCTION__ " - port not open");
-		return;
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (!port->open_count) {
+		dbg("%s - port not open", __FUNCTION__);
+		goto exit;
 	}
 
 	/* pass on to the driver specific version of this function */
-	if (serial->type->unthrottle) {
+	if (serial->type->unthrottle)
 		serial->type->unthrottle(port);
-	}
 
-	return;
+exit:
+	up (&port->sem);
 }
 
-
 static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+	int retval = -ENODEV;
 
-	if (!serial) {
+	if (!serial)
 		return -ENODEV;
-	}
 
-	dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
+	down (&port->sem);
 
-	if (!port->active) {
-		dbg (__FUNCTION__ " - port not open");
-		return -ENODEV;
+	dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
+
+	if (!port->open_count) {
+		dbg ("%s - port not open", __FUNCTION__);
+		goto exit;
 	}
 
 	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->ioctl) {
-		return (serial->type->ioctl(port, file, cmd, arg));
-	} else {
-		return -ENOIOCTLCMD;
-	}
-}
+	if (serial->type->ioctl)
+		retval = serial->type->ioctl(port, file, cmd, arg);
+	else
+		retval = -ENOIOCTLCMD;
 
+exit:
+	up (&port->sem);
+	return retval;
+}
 
 static void serial_set_termios (struct tty_struct *tty, struct termios * old)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
-	if (!serial) {
+	if (!serial)
 		return;
-	}
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	down (&port->sem);
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	if (!port->active) {
-		dbg (__FUNCTION__ " - port not open");
-		return;
+	if (!port->open_count) {
+		dbg("%s - port not open", __FUNCTION__);
+		goto exit;
 	}
 
 	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->set_termios) {
+	if (serial->type->set_termios)
 		serial->type->set_termios(port, old);
-	}
-	
-	return;
-}
 
+exit:
+	up (&port->sem);
+}
 
 static void serial_break (struct tty_struct *tty, int break_state)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
-	if (!serial) {
+	if (!serial)
 		return;
-	}
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	down (&port->sem);
 
-	if (!port->active) {
-		dbg (__FUNCTION__ " - port not open");
-		return;
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (!port->open_count) {
+		dbg("%s - port not open", __FUNCTION__);
+		goto exit;
 	}
 
-	/* pass on to the driver specific version of this function if it is
-           available */
-	if (serial->type->break_ctl) {
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->break_ctl)
 		serial->type->break_ctl(port, break_state);
-	}
-}
 
+exit:
+	up (&port->sem);
+}
 
 static void serial_shutdown (struct usb_serial *serial)
 {
-	if (serial->type->shutdown) {
+	dbg ("%s", __FUNCTION__);
+
+	if (serial->type->shutdown)
 		serial->type->shutdown(serial);
-	} else {
+	else
 		generic_shutdown(serial);
-	}
 }
 
+static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct usb_serial *serial;
+	int length = 0;
+	int i;
+	off_t begin = 0;
+	char tmp[40];
+
+	dbg("%s", __FUNCTION__);
+	length += sprintf (page, "usbserinfo:1.0 driver:%s\n", DRIVER_VERSION);
+	for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
+		serial = get_serial_by_minor(i);
+		if (serial == NULL)
+			continue;
 
+		length += sprintf (page+length, "%d:", i);
+		if (serial->type->owner)
+			length += sprintf (page+length, " module:%s", serial->type->owner->name);
+		length += sprintf (page+length, " name:\"%s\"", serial->type->name);
+		length += sprintf (page+length, " vendor:%04x product:%04x", serial->vendor, serial->product);
+		length += sprintf (page+length, " num_ports:%d", serial->num_ports);
+		length += sprintf (page+length, " port:%d", i - serial->minor + 1);
+
+		usb_make_path(serial->dev, tmp, sizeof(tmp));
+		length += sprintf (page+length, " path:%s", tmp);
+			
+		length += sprintf (page+length, "\n");
+		if ((length + begin) > (off + count))
+			goto done;
+		if ((length + begin) < off) {
+			begin += length;
+			length = 0;
+		}
+	}
+	*eof = 1;
+done:
+	if (off >= (length + begin))
+		return 0;
+	*start = page + (off-begin);
+	return ((count < begin+length-off) ? count : begin+length-off);
+}
 
 /*****************************************************************************
  * generic devices specific driver functions
@@ -781,91 +861,70 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return -ENODEV;
 
-	/* only increment our usage count, if this device is _really_ a generic device */
-	if_generic_do(MOD_INC_USE_COUNT);
-
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	down (&port->sem);
-	
-	++port->open_count;
-	
-	if (!port->active) {
-		port->active = 1;
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
-		/* force low_latency on so that our tty_push actually forces the data through, 
-		   otherwise it is scheduled, and with high data rates (like with OHCI) data
-		   can get lost. */
+	/* force low_latency on so that our tty_push actually forces the data through, 
+	   otherwise it is scheduled, and with high data rates (like with OHCI) data
+	   can get lost. */
+	if (port->tty)
 		port->tty->low_latency = 1;
-		
-		/* if we have a bulk interrupt, start reading from it */
-		if (serial->num_bulk_in) {
-			/* Start reading from the device */
-			FILL_BULK_URB(port->read_urb, serial->dev, 
-				      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-				      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-				      ((serial->type->read_bulk_callback) ?
-				       serial->type->read_bulk_callback :
-				       generic_read_bulk_callback), 
-				      port);
-			result = usb_submit_urb(port->read_urb);
-			if (result)
-				err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
-		}
+
+	/* if we have a bulk interrupt, start reading from it */
+	if (serial->num_bulk_in) {
+		/* Start reading from the device */
+		usb_fill_bulk_urb (port->read_urb, serial->dev,
+				   usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+				   port->read_urb->transfer_buffer,
+				   port->read_urb->transfer_buffer_length,
+				   ((serial->type->read_bulk_callback) ?
+				     serial->type->read_bulk_callback :
+				     generic_read_bulk_callback),
+				   port);
+		result = usb_submit_urb(port->read_urb);
+		if (result)
+			err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
 	}
-	
-	up (&port->sem);
-	
+
 	return result;
 }
 
-
-static void generic_close (struct usb_serial_port *port, struct file * filp)
+static void generic_cleanup (struct usb_serial_port *port)
 {
 	struct usb_serial *serial = port->serial;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	down (&port->sem);
-
-	--port->open_count;
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			/* shutdown any bulk reads that might be going on */
-			if (serial->num_bulk_out)
-				usb_unlink_urb (port->write_urb);
-			if (serial->num_bulk_in)
-				usb_unlink_urb (port->read_urb);
-		}
-		
-		port->active = 0;
-		port->open_count = 0;
+	if (serial->dev) {
+		/* shutdown any bulk reads that might be going on */
+		if (serial->num_bulk_out)
+			usb_unlink_urb (port->write_urb);
+		if (serial->num_bulk_in)
+			usb_unlink_urb (port->read_urb);
 	}
-
-	up (&port->sem);
-
-	/* only decrement our usage count, if this device is _really_ a generic device */
-	if_generic_do(MOD_DEC_USE_COUNT);
 }
 
+static void generic_close (struct usb_serial_port *port, struct file * filp)
+{
+	dbg("%s - port %d", __FUNCTION__, port->number);
+	generic_cleanup (port);
+}
 
 static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
 {
 	struct usb_serial *serial = port->serial;
 	int result;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (count == 0) {
-		dbg(__FUNCTION__ " - write request of 0 bytes");
+		dbg("%s - write request of 0 bytes", __FUNCTION__);
 		return (0);
 	}
 
 	/* only do something if we have a bulk out endpoint */
 	if (serial->num_bulk_out) {
 		if (port->write_urb->status == -EINPROGRESS) {
-			dbg (__FUNCTION__ " - already writing");
+			dbg("%s - already writing", __FUNCTION__);
 			return (0);
 		}
 
@@ -877,68 +936,65 @@
 		}
 		else {
 			memcpy (port->write_urb->transfer_buffer, buf, count);
-		}  
+		}
 
 		usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer);
 
 		/* set up our urb */
-		FILL_BULK_URB(port->write_urb, serial->dev, 
-			      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
-			      port->write_urb->transfer_buffer, count,
-			      ((serial->type->write_bulk_callback) ? 
-			       serial->type->write_bulk_callback : 
-			       generic_write_bulk_callback), 
-			      port);
+		usb_fill_bulk_urb (port->write_urb, serial->dev,
+				   usb_sndbulkpipe (serial->dev,
+						    port->bulk_out_endpointAddress),
+				   port->write_urb->transfer_buffer, count,
+				   ((serial->type->write_bulk_callback) ? 
+				     serial->type->write_bulk_callback :
+				     generic_write_bulk_callback), port);
 
 		/* send the data out the bulk port */
 		result = usb_submit_urb(port->write_urb);
 		if (result)
-			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+			err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 		else
 			result = count;
 
 		return result;
 	}
-	
+
 	/* no bulk out, so return 0 bytes written */
 	return (0);
-} 
-
+}
 
 static int generic_write_room (struct usb_serial_port *port)
 {
 	struct usb_serial *serial = port->serial;
 	int room = 0;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	
 	if (serial->num_bulk_out) {
 		if (port->write_urb->status != -EINPROGRESS)
 			room = port->bulk_out_size;
 	}
-	
-	dbg(__FUNCTION__ " - returns %d", room);
+
+	dbg("%s - returns %d", __FUNCTION__, room);
 	return (room);
 }
 
-
 static int generic_chars_in_buffer (struct usb_serial_port *port)
 {
 	struct usb_serial *serial = port->serial;
 	int chars = 0;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
-	
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
 	if (serial->num_bulk_out) {
 		if (port->write_urb->status == -EINPROGRESS)
 			chars = port->write_urb->transfer_buffer_length;
 	}
 
-	dbg (__FUNCTION__ " - returns %d", chars);
+	dbg("%s - returns %d", __FUNCTION__, chars);
 	return (chars);
 }
 
-
 static void generic_read_bulk_callback (struct urb *urb)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -948,22 +1004,22 @@
 	int i;
 	int result;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
-	
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
 	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
 
 	tty = port->tty;
-	if (urb->actual_length) {
+	if (tty && urb->actual_length) {
 		for (i = 0; i < urb->actual_length ; ++i) {
 			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
 			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
@@ -976,73 +1032,71 @@
 	}
 
 	/* Continue trying to always read  */
-	FILL_BULK_URB(port->read_urb, serial->dev, 
-		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-		      ((serial->type->read_bulk_callback) ?
-		       serial->type->read_bulk_callback :
-		       generic_read_bulk_callback), 
-		      port);
+	usb_fill_bulk_urb (port->read_urb, serial->dev,
+			   usb_rcvbulkpipe (serial->dev,
+				   	    port->bulk_in_endpointAddress),
+			   port->read_urb->transfer_buffer,
+			   port->read_urb->transfer_buffer_length,
+			   ((serial->type->read_bulk_callback) ? 
+			     serial->type->read_bulk_callback : 
+			     generic_read_bulk_callback), port);
 	result = usb_submit_urb(port->read_urb);
 	if (result)
-		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+		err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
 }
 
-
 static void generic_write_bulk_callback (struct urb *urb)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
-	dbg(__FUNCTION__ " - port %d", port->number);
-	
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
 	queue_task(&port->tqueue, &tq_immediate);
 	mark_bh(IMMEDIATE_BH);
-	
+
 	return;
 }
 
-
 static void generic_shutdown (struct usb_serial *serial)
 {
 	int i;
 
-	dbg (__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	/* stop reads and writes on all ports */
 	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
-			generic_close (&serial->port[i], NULL);
-		}
+		generic_cleanup (&serial->port[i]);
 	}
 }
 
-
 static void port_softint(void *private)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)private;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 	struct tty_struct *tty;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	
-	if (!serial) {
+	if (!serial)
 		return;
-	}
- 	
+
 	tty = port->tty;
+	if (!tty)
+		return;
+
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
-		dbg(__FUNCTION__ " - write wakeup call.");
+		dbg("%s - write wakeup call.", __FUNCTION__);
 		(tty->ldisc.write_wakeup)(tty);
 	}
 
@@ -1068,9 +1122,6 @@
 	int minor;
 	int buffer_size;
 	int i;
-	char interrupt_pipe;
-	char bulk_in_pipe;
-	char bulk_out_pipe;
 	int num_interrupt_in = 0;
 	int num_bulk_in = 0;
 	int num_bulk_out = 0;
@@ -1078,7 +1129,6 @@
 	int max_endpoints;
 	const struct usb_device_id *id_pattern = NULL;
 
-	
 	/* loop through our list of known serial converters, and see if this
 	   device matches. */
 	found = 0;
@@ -1099,8 +1149,6 @@
 	}
 	
 	/* descriptor matches, let's find the endpoints needed */
-	interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
-			
 	/* check out the endpoints */
 	iface_desc = &interface->altsetting[0];
 	for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
@@ -1110,7 +1158,6 @@
 		    ((endpoint->bmAttributes & 3) == 0x02)) {
 			/* we found a bulk in endpoint */
 			dbg("found bulk in");
-			bulk_in_pipe = HAS;
 			bulk_in_endpoint[num_bulk_in] = endpoint;
 			++num_bulk_in;
 		}
@@ -1119,7 +1166,6 @@
 		    ((endpoint->bmAttributes & 3) == 0x02)) {
 			/* we found a bulk out endpoint */
 			dbg("found bulk out");
-			bulk_out_pipe = HAS;
 			bulk_out_endpoint[num_bulk_out] = endpoint;
 			++num_bulk_out;
 		}
@@ -1128,20 +1174,19 @@
 		    ((endpoint->bmAttributes & 3) == 0x03)) {
 			/* we found a interrupt in endpoint */
 			dbg("found interrupt in");
-			interrupt_pipe = HAS;
 			interrupt_in_endpoint[num_interrupt_in] = endpoint;
 			++num_interrupt_in;
 		}
 	}
-	
+
 #if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
 	/* BEGIN HORRIBLE HACK FOR PL2303 */ 
 	/* this is needed due to the looney way its endpoints are set up */
-	if (ifnum == 1) {
-		if (((dev->descriptor.idVendor == PL2303_VENDOR_ID) &&
-		     (dev->descriptor.idProduct == PL2303_PRODUCT_ID)) ||
-		    ((dev->descriptor.idVendor == ATEN_VENDOR_ID) &&
-		     (dev->descriptor.idProduct == ATEN_PRODUCT_ID))) {
+	if (((dev->descriptor.idVendor == PL2303_VENDOR_ID) &&
+	     (dev->descriptor.idProduct == PL2303_PRODUCT_ID)) ||
+	    ((dev->descriptor.idVendor == ATEN_VENDOR_ID) &&
+	     (dev->descriptor.idProduct == ATEN_PRODUCT_ID))) {
+		if (ifnum == 1) {
 			/* check out the endpoints of the other interface*/
 			interface = &dev->actconfig->interface[ifnum ^ 1];
 			iface_desc = &interface->altsetting[0];
@@ -1151,24 +1196,23 @@
 				    ((endpoint->bmAttributes & 3) == 0x03)) {
 					/* we found a interrupt in endpoint */
 					dbg("found interrupt in for Prolific device on separate interface");
-					interrupt_pipe = HAS;
 					interrupt_in_endpoint[num_interrupt_in] = endpoint;
 					++num_interrupt_in;
 				}
 			}
 		}
+
+		/* Now make sure the PL-2303 is configured correctly.
+		 * If not, give up now and hope this hack will work
+		 * properly during a later invocation of usb_serial_probe
+		 */
+		if (num_bulk_in == 0 || num_bulk_out == 0) {
+			info("PL-2303 hack: descriptors matched but endpoints did not");
+			return NULL;
+		}
 	}
 	/* END HORRIBLE HACK FOR PL2303 */
 #endif
-	
-	/* verify that we found all of the endpoints that we need */
-	if (!((interrupt_pipe & type->needs_interrupt_in) &&
-	      (bulk_in_pipe & type->needs_bulk_in) &&
-	      (bulk_out_pipe & type->needs_bulk_out))) {
-		/* nope, they don't match what we expected */
-		info("descriptors matched, but endpoints did not");
-		return NULL;
-	}
 
 	/* found all that we need */
 	info("%s converter detected", type->name);
@@ -1189,7 +1233,7 @@
 		err("No more free serial devices");
 		return NULL;
 	}
-	
+
 	serial->dev = dev;
 	serial->type = type;
 	serial->interface = interface;
@@ -1201,15 +1245,6 @@
 	serial->vendor = dev->descriptor.idVendor;
 	serial->product = dev->descriptor.idProduct;
 
-	/* if this device type has a startup function, call it */
-	if (type->startup) {
-		i = type->startup (serial);
-		if (i < 0)
-			goto probe_error;
-		if (i > 0)
-			return serial;
-	}
-
 	/* set up the endpoint information */
 	for (i = 0; i < num_bulk_in; ++i) {
 		endpoint = bulk_in_endpoint[i];
@@ -1226,13 +1261,14 @@
 			err("Couldn't allocate bulk_in_buffer");
 			goto probe_error;
 		}
-		FILL_BULK_URB(port->read_urb, dev, 
-			      usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
-			      port->bulk_in_buffer, buffer_size, 
-			      ((serial->type->read_bulk_callback) ?
-			       serial->type->read_bulk_callback :
-			       generic_read_bulk_callback), 
-			      port);
+		usb_fill_bulk_urb (port->read_urb, dev,
+				   usb_rcvbulkpipe (dev,
+					   	    endpoint->bEndpointAddress),
+				   port->bulk_in_buffer, buffer_size,
+				   ((serial->type->read_bulk_callback) ? 
+				     serial->type->read_bulk_callback : 
+				     generic_read_bulk_callback),
+				   port);
 	}
 
 	for (i = 0; i < num_bulk_out; ++i) {
@@ -1251,13 +1287,14 @@
 			err("Couldn't allocate bulk_out_buffer");
 			goto probe_error;
 		}
-		FILL_BULK_URB(port->write_urb, dev, 
-			      usb_sndbulkpipe(dev, endpoint->bEndpointAddress),
-			      port->bulk_out_buffer, buffer_size,
-			      ((serial->type->write_bulk_callback) ? 
-			       serial->type->write_bulk_callback : 
-			       generic_write_bulk_callback), 
-			      port);
+		usb_fill_bulk_urb (port->write_urb, dev,
+				   usb_sndbulkpipe (dev,
+						    endpoint->bEndpointAddress),
+				   port->bulk_out_buffer, buffer_size, 
+				   ((serial->type->write_bulk_callback) ? 
+				     serial->type->write_bulk_callback : 
+				     generic_write_bulk_callback),
+				   port);
 	}
 
 	for (i = 0; i < num_interrupt_in; ++i) {
@@ -1275,12 +1312,12 @@
 			err("Couldn't allocate interrupt_in_buffer");
 			goto probe_error;
 		}
-		FILL_INT_URB(port->interrupt_in_urb, dev, 
-			     usb_rcvintpipe(dev, endpoint->bEndpointAddress),
-			     port->interrupt_in_buffer, buffer_size, 
-			     serial->type->read_int_callback,
-			     port, 
-			     endpoint->bInterval);
+		usb_fill_int_urb (port->interrupt_in_urb, dev, 
+				  usb_rcvintpipe (dev,
+						  endpoint->bEndpointAddress),
+				  port->interrupt_in_buffer, buffer_size, 
+				  serial->type->read_int_callback, port, 
+				  endpoint->bInterval);
 	}
 
 	/* initialize some parts of the port structures */
@@ -1288,7 +1325,7 @@
 	max_endpoints = max(num_bulk_in, num_bulk_out);
 	max_endpoints = max(max_endpoints, num_interrupt_in);
 	max_endpoints = max(max_endpoints, (int)serial->num_ports);
-	dbg (__FUNCTION__ " - setting up %d port structures for this device", max_endpoints);
+	dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
 	for (i = 0; i < max_endpoints; ++i) {
 		port = &serial->port[i];
 		port->number = i + serial->minor;
@@ -1298,14 +1335,23 @@
 		port->tqueue.data = port;
 		init_MUTEX (&port->sem);
 	}
-	
+
+	/* if this device type has a startup function, call it */
+	if (type->startup) {
+		i = type->startup (serial);
+		if (i < 0)
+			goto probe_error;
+		if (i > 0)
+			return serial;
+	}
+
 	/* initialize the devfs nodes for this device and let the user know what ports we are bound to */
 	for (i = 0; i < serial->num_ports; ++i) {
 		tty_register_devfs (&serial_tty_driver, 0, serial->port[i].number);
 		info("%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)", 
 		     type->name, serial->port[i].number, serial->port[i].number);
 	}
-	
+
 	return serial; /* success */
 
 
@@ -1331,7 +1377,7 @@
 		if (port->interrupt_in_buffer)
 			kfree (port->interrupt_in_buffer);
 	}
-		
+
 	/* return the minor range that this device had */
 	return_serial (serial);
 
@@ -1340,25 +1386,32 @@
 	return NULL;
 }
 
-
 static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct usb_serial *serial = (struct usb_serial *) ptr;
 	struct usb_serial_port *port;
 	int i;
 
+	dbg ("%s", __FUNCTION__);
 	if (serial) {
 		/* fail all future close/read/write/ioctl/etc calls */
 		for (i = 0; i < serial->num_ports; ++i) {
-			if (serial->port[i].tty != NULL)
-				serial->port[i].tty->driver_data = NULL;
+			port = &serial->port[i];
+			down (&port->sem);
+			if (port->tty != NULL) {
+				while (port->open_count > 0) {
+					__serial_close(port, NULL);
+				}
+				port->tty->driver_data = NULL;
+			}
+			up (&port->sem);
 		}
 
 		serial->dev = NULL;
 		serial_shutdown (serial);
 
 		for (i = 0; i < serial->num_ports; ++i)
-			serial->port[i].active = 0;
+			serial->port[i].open_count = 0;
 
 		for (i = 0; i < serial->num_bulk_in; ++i) {
 			port = &serial->port[i];
@@ -1402,36 +1455,41 @@
 	} else {
 		info("device disconnected");
 	}
-	
+
 }
 
 
 static struct tty_driver serial_tty_driver = {
-	magic:			TTY_DRIVER_MAGIC,
-	driver_name:		"usb-serial",
-	name:			"usb/tts/%d",
-	major:			SERIAL_TTY_MAJOR,
-	minor_start:		0,
-	num:			SERIAL_TTY_MINORS,
-	type:			TTY_DRIVER_TYPE_SERIAL,
-	subtype:		SERIAL_TYPE_NORMAL,
-	flags:			TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
-	
-	refcount:		&serial_refcount,
-	table:			serial_tty,
-	termios:		serial_termios,
-	termios_locked:		serial_termios_locked,
-	
-	open:			serial_open,
-	close:			serial_close,
-	write:			serial_write,
-	write_room:		serial_write_room,
-	ioctl:			serial_ioctl,
-	set_termios:		serial_set_termios,
-	throttle:		serial_throttle,
-	unthrottle:		serial_unthrottle,
-	break_ctl:		serial_break,
-	chars_in_buffer:	serial_chars_in_buffer,
+	.magic =		TTY_DRIVER_MAGIC,
+	.driver_name =		"usb-serial",
+#ifndef CONFIG_DEVFS_FS
+	.name =			"ttyUSB",
+#else
+	.name =			"usb/tts/%d",
+#endif
+	.major =		SERIAL_TTY_MAJOR,
+	.minor_start =		0,
+	.num =			SERIAL_TTY_MINORS,
+	.type =			TTY_DRIVER_TYPE_SERIAL,
+	.subtype =		SERIAL_TYPE_NORMAL,
+	.flags =		TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+
+	.refcount =		&serial_refcount,
+	.table =		serial_tty,
+	.termios =		serial_termios,
+	.termios_locked =	serial_termios_locked,
+
+	.open =			serial_open,
+	.close =		serial_close,
+	.write =		serial_write,
+	.write_room =		serial_write_room,
+	.ioctl =		serial_ioctl,
+	.set_termios =		serial_set_termios,
+	.throttle =		serial_throttle,
+	.unthrottle =		serial_unthrottle,
+	.break_ctl =		serial_break,
+	.chars_in_buffer =	serial_chars_in_buffer,
+	.read_proc =		serial_read_proc,
 };
 
 
@@ -1449,7 +1507,7 @@
 	serial_tty_driver.init_termios          = tty_std_termios;
 	serial_tty_driver.init_termios.c_cflag  = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
 	if (tty_register_driver (&serial_tty_driver)) {
-		err(__FUNCTION__ " - failed to register tty driver");
+		err("%s - failed to register tty driver", __FUNCTION__);
 		return -1;
 	}
 
@@ -1526,7 +1584,7 @@
 
 
 
-/* If the usb-serial core is build into the core, the usb-serial drivers
+/* If the usb-serial core is built into the core, the usb-serial drivers
    need these symbols to load properly as modules. */
 EXPORT_SYMBOL(usb_serial_register);
 EXPORT_SYMBOL(usb_serial_deregister);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/visor.c linux-2.4.20/drivers/usb/serial/visor.c
--- linux-2.4.19/drivers/usb/serial/visor.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/visor.c	2002-10-29 11:18:36.000000000 +0000
@@ -123,18 +123,15 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <asm/uaccess.h>
 #include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
@@ -149,7 +146,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.5"
+#define DRIVER_VERSION "v1.6"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC "USB HandSpring Visor, Palm m50x, Sony Cli driver"
 
@@ -170,41 +167,35 @@
 static int  clie_3_5_startup	(struct usb_serial *serial);
 
 
-static __devinitdata struct usb_device_id visor_id_table [] = {
-	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
-	{ }					/* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id palm_4_0_id_table [] = {
+static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
-	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
+	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
 	{ }					/* Terminating entry */
 };
 
-static __devinitdata struct usb_device_id clie_id_3_5_table [] = {
+static struct usb_device_id clie_id_3_5_table [] = {
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
 	{ }					/* Terminating entry */
 };
 
-static __devinitdata struct usb_device_id clie_id_4_0_table [] = {
-	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
-	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
-	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
-	{ }					/* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id id_table [] = {
+static __devinitdata struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
-	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
@@ -212,113 +203,57 @@
 	{ }					/* Terminating entry */
 };
 
-MODULE_DEVICE_TABLE (usb, id_table);
+MODULE_DEVICE_TABLE (usb, id_table_combined);
 
 
 
-/* All of the device info needed for the Handspring Visor */
+/* All of the device info needed for the Handspring Visor, and Palm 4.0 devices */
 static struct usb_serial_device_type handspring_device = {
-	name:			"Handspring Visor",
-	id_table:		visor_id_table,
-	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
-	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
-	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
-	num_interrupt_in:	0,
-	num_bulk_in:		2,
-	num_bulk_out:		2,
-	num_ports:		2,
-	open:			visor_open,
-	close:			visor_close,
-	throttle:		visor_throttle,
-	unthrottle:		visor_unthrottle,
-	startup:		visor_startup,
-	shutdown:		visor_shutdown,
-	ioctl:			visor_ioctl,
-	set_termios:		visor_set_termios,
-	write:			visor_write,
-	write_room:		visor_write_room,
-	chars_in_buffer:	visor_chars_in_buffer,
-	write_bulk_callback:	visor_write_bulk_callback,
-	read_bulk_callback:	visor_read_bulk_callback,
+	.owner =		THIS_MODULE,
+	.name =			"Handspring Visor / Palm 4.0 / Cli 4.x",
+	.id_table =		id_table,
+	.num_interrupt_in =	0,
+	.num_bulk_in =		2,
+	.num_bulk_out =		2,
+	.num_ports =		2,
+	.open =			visor_open,
+	.close =		visor_close,
+	.throttle =		visor_throttle,
+	.unthrottle =		visor_unthrottle,
+	.startup =		visor_startup,
+	.shutdown =		visor_shutdown,
+	.ioctl =		visor_ioctl,
+	.set_termios =		visor_set_termios,
+	.write =		visor_write,
+	.write_room =		visor_write_room,
+	.chars_in_buffer =	visor_chars_in_buffer,
+	.write_bulk_callback =	visor_write_bulk_callback,
+	.read_bulk_callback =	visor_read_bulk_callback,
 };
 
-/* device info for the Palm 4.0 devices */
-static struct usb_serial_device_type palm_4_0_device = {
-	name:			"Palm 4.0",
-	id_table:		palm_4_0_id_table,
-	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
-	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
-	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
-	num_interrupt_in:	0,
-	num_bulk_in:		2,
-	num_bulk_out:		2,
-	num_ports:		2,
-	open:			visor_open,
-	close:			visor_close,
-	throttle:		visor_throttle,
-	unthrottle:		visor_unthrottle,
-	startup:		visor_startup,
-	shutdown:		visor_shutdown,
-	ioctl:			visor_ioctl,
-	set_termios:		visor_set_termios,
-	write:			visor_write,
-	write_room:		visor_write_room,
-	chars_in_buffer:	visor_chars_in_buffer,
-	write_bulk_callback:	visor_write_bulk_callback,
-	read_bulk_callback:	visor_read_bulk_callback,
-};
-
-
 /* device info for the Sony Clie OS version 3.5 */
 static struct usb_serial_device_type clie_3_5_device = {
-	name:			"Sony Cli 3.5",
-	id_table:		clie_id_3_5_table,
-	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
-	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
-	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
-	num_interrupt_in:	0,
-	num_bulk_in:		1,
-	num_bulk_out:		1,
-	num_ports:		1,
-	open:			visor_open,
-	close:			visor_close,
-	throttle:		visor_throttle,
-	unthrottle:		visor_unthrottle,
-	startup:		clie_3_5_startup,
-	ioctl:			visor_ioctl,
-	set_termios:		visor_set_termios,
-	write:			visor_write,
-	write_room:		visor_write_room,
-	chars_in_buffer:	visor_chars_in_buffer,
-	write_bulk_callback:	visor_write_bulk_callback,
-	read_bulk_callback:	visor_read_bulk_callback,
+	.owner =		THIS_MODULE,
+	.name =			"Sony Cli 3.5",
+	.id_table =		clie_id_3_5_table,
+	.num_interrupt_in =	0,
+	.num_bulk_in =		1,
+	.num_bulk_out =		1,
+	.num_ports =		1,
+	.open =			visor_open,
+	.close =		visor_close,
+	.throttle =		visor_throttle,
+	.unthrottle =		visor_unthrottle,
+	.startup =		clie_3_5_startup,
+	.ioctl =		visor_ioctl,
+	.set_termios =		visor_set_termios,
+	.write =		visor_write,
+	.write_room =		visor_write_room,
+	.chars_in_buffer =	visor_chars_in_buffer,
+	.write_bulk_callback =	visor_write_bulk_callback,
+	.read_bulk_callback =	visor_read_bulk_callback,
 };
 
-/* device info for the Sony Clie OS version 4.0 */
-static struct usb_serial_device_type clie_4_0_device = {
-	name:			"Sony Cli 4.x",
-	id_table:		clie_id_4_0_table,
-	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
-	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
-	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
-	num_interrupt_in:	0,
-	num_bulk_in:		2,
-	num_bulk_out:		2,
-	num_ports:		2,
-	open:			visor_open,
-	close:			visor_close,
-	throttle:		visor_throttle,
-	unthrottle:		visor_unthrottle,
-	startup:		visor_startup,
-	shutdown:		visor_shutdown,
-	ioctl:			visor_ioctl,
-	set_termios:		visor_set_termios,
-	write:			visor_write,
-	write_room:		visor_write_room,
-	chars_in_buffer:	visor_chars_in_buffer,
-	write_bulk_callback:	visor_write_bulk_callback,
-	read_bulk_callback:	visor_read_bulk_callback,
-};
 
 #define NUM_URBS			24
 #define URB_TRANSFER_BUFFER_SIZE	768
@@ -339,39 +274,35 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return -ENODEV;
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (!port->read_urb) {
+		/* this is needed for some brain dead Sony devices */
 		err ("Device lied about number of ports, please use a lower one.");
 		return -ENODEV;
 	}
 
-	down (&port->sem);
-	
-	++port->open_count;
-	MOD_INC_USE_COUNT;
-	
-	if (!port->active) {
-		port->active = 1;
-		bytes_in = 0;
-		bytes_out = 0;
-
-		/* force low_latency on so that our tty_push actually forces the data through, 
-		   otherwise it is scheduled, and with high data rates (like with OHCI) data
-		   can get lost. */
+	bytes_in = 0;
+	bytes_out = 0;
+
+	/*
+	 * Force low_latency on so that our tty_push actually forces the data
+	 * through, otherwise it is scheduled, and with high data rates (like
+	 * with OHCI) data can get lost.
+	 */
+	if (port->tty)
 		port->tty->low_latency = 1;
-		
-		/* Start reading from the device */
-		FILL_BULK_URB(port->read_urb, serial->dev, 
-			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-			      visor_read_bulk_callback, port);
-		result = usb_submit_urb(port->read_urb);
-		if (result)
-			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
-	}
-	
-	up (&port->sem);
+
+	/* Start reading from the device */
+	usb_fill_bulk_urb (port->read_urb, serial->dev,
+			   usb_rcvbulkpipe (serial->dev, 
+					    port->bulk_in_endpointAddress),
+			   port->read_urb->transfer_buffer,
+			   port->read_urb->transfer_buffer_length,
+			   visor_read_bulk_callback, port);
+	result = usb_submit_urb(port->read_urb);
+	if (result)
+		err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
 	
 	return result;
 }
@@ -385,44 +316,32 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 			 
 	serial = get_usb_serial (port, __FUNCTION__);
 	if (!serial)
 		return;
 	
-	down (&port->sem);
-
-	--port->open_count;
-
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			/* only send a shutdown message if the 
-			 * device is still here */
-			transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
-			if (!transfer_buffer) {
-				err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
-			} else {
-				/* send a shutdown message to the device */
-				usb_control_msg (serial->dev,
-						 usb_rcvctrlpipe(serial->dev, 0),
-						 VISOR_CLOSE_NOTIFICATION, 0xc2,
-						 0x0000, 0x0000, 
-						 transfer_buffer, 0x12, 300);
-				kfree (transfer_buffer);
-			}
-			/* shutdown our bulk read */
-			usb_unlink_urb (port->read_urb);
+	if (serial->dev) {
+		/* only send a shutdown message if the 
+		 * device is still here */
+		transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
+		if (!transfer_buffer) {
+			err("%s - kmalloc(%d) failed.", __FUNCTION__, 0x12);
+		} else {
+			/* send a shutdown message to the device */
+			usb_control_msg (serial->dev,
+					 usb_rcvctrlpipe(serial->dev, 0),
+					 VISOR_CLOSE_NOTIFICATION, 0xc2,
+					 0x0000, 0x0000, 
+					 transfer_buffer, 0x12, 300);
+			kfree (transfer_buffer);
 		}
-		port->active = 0;
-		port->open_count = 0;
+		/* shutdown our bulk read */
+		usb_unlink_urb (port->read_urb);
 	}
-	up (&port->sem);
-
 	/* Uncomment the following line if you want to see some statistics in your syslog */
 	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
-
-	MOD_DEC_USE_COUNT;
 }
 
 
@@ -437,7 +356,7 @@
 	int bytes_sent = 0;
 	int transfer_size;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	while (count > 0) {
 		/* try to find a free urb in our list of them */
@@ -451,13 +370,13 @@
 		}
 		spin_unlock_irqrestore (&write_urb_pool_lock, flags);
 		if (urb == NULL) {
-			dbg (__FUNCTION__ " - no more free urbs");
+			dbg("%s - no more free urbs", __FUNCTION__);
 			goto exit;
 		}
 		if (urb->transfer_buffer == NULL) {
 			urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
 			if (urb->transfer_buffer == NULL) {
-				err(__FUNCTION__" no more kernel memory...");
+				err("%s no more kernel memory...", __FUNCTION__);
 				goto exit;
 			}
 		}
@@ -482,7 +401,7 @@
 		/* send it down the pipe */
 		status = usb_submit_urb(urb);
 		if (status) {
-			err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
+			err("%s - usb_submit_urb(write bulk) failed with status = %d", __FUNCTION__, status);
 			bytes_sent = status;
 			break;
 		}
@@ -504,7 +423,7 @@
 	int i;
 	int room = 0;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	
 	spin_lock_irqsave (&write_urb_pool_lock, flags);
 
@@ -516,7 +435,7 @@
 	
 	spin_unlock_irqrestore (&write_urb_pool_lock, flags);
 	
-	dbg(__FUNCTION__ " - returns %d", room);
+	dbg("%s - returns %d", __FUNCTION__, room);
 	return (room);
 }
 
@@ -527,7 +446,7 @@
 	int i;
 	int chars = 0;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	
 	spin_lock_irqsave (&write_urb_pool_lock, flags);
 
@@ -539,7 +458,7 @@
 	
 	spin_unlock_irqrestore (&write_urb_pool_lock, flags);
 
-	dbg (__FUNCTION__ " - returns %d", chars);
+	dbg("%s - returns %d", __FUNCTION__, chars);
 	return (chars);
 }
 
@@ -551,16 +470,16 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
 	queue_task(&port->tqueue, &tq_immediate);
 	mark_bh(IMMEDIATE_BH);
-	
+
 	return;
 }
 
@@ -577,22 +496,22 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
 	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
 
 	tty = port->tty;
-	if (urb->actual_length) {
+	if (tty && urb->actual_length) {
 		for (i = 0; i < urb->actual_length ; ++i) {
 			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
 			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
@@ -606,29 +525,23 @@
 	}
 
 	/* Continue trying to always read  */
-	FILL_BULK_URB(port->read_urb, serial->dev, 
-		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-		      visor_read_bulk_callback, port);
+	usb_fill_bulk_urb (port->read_urb, serial->dev,
+			   usb_rcvbulkpipe (serial->dev,
+					    port->bulk_in_endpointAddress),
+			   port->read_urb->transfer_buffer,
+			   port->read_urb->transfer_buffer_length,
+			   visor_read_bulk_callback, port);
 	result = usb_submit_urb(port->read_urb);
 	if (result)
-		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+		err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
 	return;
 }
 
 
 static void visor_throttle (struct usb_serial_port *port)
 {
-
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	down (&port->sem);
-
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	usb_unlink_urb (port->read_urb);
-
-	up (&port->sem);
-
-	return;
 }
 
 
@@ -636,42 +549,35 @@
 {
 	int result;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
-
-	down (&port->sem);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	port->read_urb->dev = port->serial->dev;
 	result = usb_submit_urb(port->read_urb);
 	if (result)
-		err(__FUNCTION__ " - failed submitting read urb, error %d", result);
-
-	up (&port->sem);
-
-	return;
+		err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
 }
 
-
-static int  visor_startup (struct usb_serial *serial)
+static int visor_startup (struct usb_serial *serial)
 {
 	int response;
 	int i;
 	unsigned char *transfer_buffer =  kmalloc (256, GFP_KERNEL);
 
 	if (!transfer_buffer) {
-		err(__FUNCTION__ " - kmalloc(%d) failed.", 256);
+		err("%s - kmalloc(%d) failed.", __FUNCTION__, 256);
 		return -ENOMEM;
 	}
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
-	dbg(__FUNCTION__ " - Set config to 1");
+	dbg("%s - Set config to 1", __FUNCTION__);
 	usb_set_configuration (serial->dev, 1);
 
 	/* send a get connection info request */
 	response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_GET_CONNECTION_INFORMATION,
 					0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
 	if (response < 0) {
-		err(__FUNCTION__ " - error getting connection information");
+		err("%s - error getting connection information", __FUNCTION__);
 	} else {
 		struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer;
 		char *string;
@@ -699,7 +605,8 @@
 					string = "unknown";
 					break;	
 			}
-			info("%s: port %d, is for %s use and is bound to ttyUSB%d", serial->type->name, connection_info->connections[i].port, string, serial->minor + i);
+			info("%s: port %d, is for %s use and is bound to ttyUSB%d", serial->type->name,
+			     connection_info->connections[i].port, string, serial->minor + i);
 		}
 	}
 
@@ -712,7 +619,7 @@
 					    0xc2, 0x0000, 0x0000, transfer_buffer, 
 					    0x14, 300);
 		if (response < 0) {
-			err(__FUNCTION__ " - error getting first unknown palm command");
+			err("%s - error getting first unknown palm command", __FUNCTION__);
 		} else {
 			usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, transfer_buffer);
 		}
@@ -721,7 +628,7 @@
 					    0xc2, 0x0000, 0x0000, transfer_buffer, 
 					    0x14, 300);
 		if (response < 0) {
-			err(__FUNCTION__ " - error getting second unknown palm command");
+			err("%s - error getting second unknown palm command", __FUNCTION__);
 		} else {
 			usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, transfer_buffer);
 		}
@@ -731,7 +638,7 @@
 	response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE,
 					0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300);
 	if (response < 0) {
-		err(__FUNCTION__ " - error getting bytes available request");
+		err("%s - error getting bytes available request", __FUNCTION__);
 	}
 
 	kfree (transfer_buffer);
@@ -745,7 +652,7 @@
 	int result;
 	u8 data;
 
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	/*
 	 * Note that PEG-300 series devices expect the following two calls.
@@ -756,11 +663,11 @@
 				  USB_REQ_GET_CONFIGURATION, USB_DIR_IN,
 				  0, 0, &data, 1, HZ * 3);
 	if (result < 0) {
-		err(__FUNCTION__ ": get config number failed: %d", result);
+		err("%s: get config number failed: %d", __FUNCTION__, result);
 		return result;
 	}
 	if (result != 1) {
-		err(__FUNCTION__ ": get config number bad return length: %d", result);
+		err("%s: get config number bad return length: %d", __FUNCTION__, result);
 		return -EIO;
 	}
 
@@ -770,11 +677,11 @@
 				  USB_DIR_IN | USB_DT_DEVICE,
 				  0, 0, &data, 1, HZ * 3);
 	if (result < 0) {
-		err(__FUNCTION__ ": get interface number failed: %d", result);
+		err("%s: get interface number failed: %d", __FUNCTION__, result);
 		return result;
 	}
 	if (result != 1) {
-		err(__FUNCTION__ ": get interface number bad return length: %d", result);
+		err("%s: get interface number bad return length: %d", __FUNCTION__, result);
 		return -EIO;
 	}
 
@@ -783,21 +690,12 @@
 
 static void visor_shutdown (struct usb_serial *serial)
 {
-	int i;
-
-	dbg (__FUNCTION__);
-
-	/* stop reads and writes on all ports */
-	for (i=0; i < serial->num_ports; ++i) {
-		serial->port[i].active = 0;
-		serial->port[i].open_count = 0;
-	}
+	dbg("%s", __FUNCTION__);
 }
 
-
 static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
 {
-	dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
+	dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
 
 	return -ENOIOCTLCMD;
 }
@@ -808,10 +706,10 @@
 {
 	unsigned int cflag;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if ((!port->tty) || (!port->tty->termios)) {
-		dbg(__FUNCTION__" - no tty structures");
+		dbg("%s - no tty structures", __FUNCTION__);
 		return;
 	}
 
@@ -820,50 +718,51 @@
 	if (old_termios) {
 		if ((cflag == old_termios->c_cflag) &&
 		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
-			dbg(__FUNCTION__ " - nothing to change...");
+			dbg("%s - nothing to change...", __FUNCTION__);
 			return;
 		}
 	}
 
 	/* get the byte size */
 	switch (cflag & CSIZE) {
-		case CS5:	dbg(__FUNCTION__ " - data bits = 5");   break;
-		case CS6:	dbg(__FUNCTION__ " - data bits = 6");   break;
-		case CS7:	dbg(__FUNCTION__ " - data bits = 7");   break;
+		case CS5:	dbg("%s - data bits = 5", __FUNCTION__);   break;
+		case CS6:	dbg("%s - data bits = 6", __FUNCTION__);   break;
+		case CS7:	dbg("%s - data bits = 7", __FUNCTION__);   break;
 		default:
-		case CS8:	dbg(__FUNCTION__ " - data bits = 8");   break;
+		case CS8:	dbg("%s - data bits = 8", __FUNCTION__);   break;
 	}
 	
 	/* determine the parity */
 	if (cflag & PARENB)
 		if (cflag & PARODD)
-			dbg(__FUNCTION__ " - parity = odd");
+			dbg("%s - parity = odd", __FUNCTION__);
 		else
-			dbg(__FUNCTION__ " - parity = even");
+			dbg("%s - parity = even", __FUNCTION__);
 	else
-		dbg(__FUNCTION__ " - parity = none");
+		dbg("%s - parity = none", __FUNCTION__);
 
 	/* figure out the stop bits requested */
 	if (cflag & CSTOPB)
-		dbg(__FUNCTION__ " - stop bits = 2");
+		dbg("%s - stop bits = 2", __FUNCTION__);
 	else
-		dbg(__FUNCTION__ " - stop bits = 1");
+		dbg("%s - stop bits = 1", __FUNCTION__);
 
 	
 	/* figure out the flow control settings */
 	if (cflag & CRTSCTS)
-		dbg(__FUNCTION__ " - RTS/CTS is enabled");
+		dbg("%s - RTS/CTS is enabled", __FUNCTION__);
 	else
-		dbg(__FUNCTION__ " - RTS/CTS is disabled");
+		dbg("%s - RTS/CTS is disabled", __FUNCTION__);
 	
 	/* determine software flow control */
 	if (I_IXOFF(port->tty))
-		dbg(__FUNCTION__ " - XON/XOFF is enabled, XON = %2x, XOFF = %2x", START_CHAR(port->tty), STOP_CHAR(port->tty));
+		dbg("%s - XON/XOFF is enabled, XON = %2x, XOFF = %2x",
+		    __FUNCTION__, START_CHAR(port->tty), STOP_CHAR(port->tty));
 	else
-		dbg(__FUNCTION__ " - XON/XOFF is disabled");
+		dbg("%s - XON/XOFF is disabled", __FUNCTION__);
 
 	/* get the baud rate wanted */
-	dbg(__FUNCTION__ " - baud rate = %d", tty_get_baud_rate(port->tty));
+	dbg("%s - baud rate = %d", __FUNCTION__, tty_get_baud_rate(port->tty));
 
 	return;
 }
@@ -875,9 +774,7 @@
 	int i;
 
 	usb_serial_register (&handspring_device);
-	usb_serial_register (&palm_4_0_device);
 	usb_serial_register (&clie_3_5_device);
-	usb_serial_register (&clie_4_0_device);
 	
 	/* create our write urb pool and transfer buffers */ 
 	spin_lock_init (&write_urb_pool_lock);
@@ -892,7 +789,7 @@
 		urb->transfer_buffer = NULL;
 		urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
 		if (!urb->transfer_buffer) {
-			err (__FUNCTION__ " - out of memory for urb buffers.");
+			err("%s - out of memory for urb buffers.", __FUNCTION__);
 			continue;
 		}
 	}
@@ -909,9 +806,7 @@
 	unsigned long flags;
 
 	usb_serial_deregister (&handspring_device);
-	usb_serial_deregister (&palm_4_0_device);
 	usb_serial_deregister (&clie_3_5_device);
-	usb_serial_deregister (&clie_4_0_device);
 
 	spin_lock_irqsave (&write_urb_pool_lock, flags);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/visor.h linux-2.4.20/drivers/usb/serial/visor.h
--- linux-2.4.19/drivers/usb/serial/visor.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/visor.h	2002-10-29 11:18:35.000000000 +0000
@@ -27,6 +27,7 @@
 #define PALM_I705_ID			0x0020
 #define PALM_M125_ID			0x0040
 #define PALM_M130_ID			0x0050
+#define PALM_ZIRE_ID			0x0070
 
 #define SONY_VENDOR_ID			0x054C
 #define SONY_CLIE_3_5_ID		0x0038
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/serial/whiteheat.c linux-2.4.20/drivers/usb/serial/whiteheat.c
--- linux-2.4.19/drivers/usb/serial/whiteheat.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/serial/whiteheat.c	2002-10-29 11:18:36.000000000 +0000
@@ -61,18 +61,15 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <asm/uaccess.h>
 #include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
@@ -103,12 +100,12 @@
    separate ID tables, and then a third table that combines them
    just for the purpose of exporting the autoloading information.
 */
-static __devinitdata struct usb_device_id id_table_std [] = {
+static struct usb_device_id id_table_std [] = {
 	{ USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) },
 	{ }						/* Terminating entry */
 };
 
-static __devinitdata struct usb_device_id id_table_prerenumeration [] = {
+static struct usb_device_id id_table_prerenumeration [] = {
 	{ USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) },
 	{ }						/* Terminating entry */
 };
@@ -133,36 +130,32 @@
 static void whiteheat_real_shutdown	(struct usb_serial *serial);
 
 static struct usb_serial_device_type whiteheat_fake_device = {
-	name:			"Connect Tech - WhiteHEAT - (prerenumeration)",
-	id_table:		id_table_prerenumeration,
-	needs_interrupt_in:	DONT_CARE,				/* don't have to have an interrupt in endpoint */
-	needs_bulk_in:		DONT_CARE,				/* don't have to have a bulk in endpoint */
-	needs_bulk_out:		DONT_CARE,				/* don't have to have a bulk out endpoint */
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		1,
-	startup:		whiteheat_fake_startup,
+	.owner =		THIS_MODULE,
+	.name =			"Connect Tech - WhiteHEAT - (prerenumeration)",
+	.id_table =		id_table_prerenumeration,
+	.num_interrupt_in =	NUM_DONT_CARE,
+	.num_bulk_in =		NUM_DONT_CARE,
+	.num_bulk_out =		NUM_DONT_CARE,
+	.num_ports =		1,
+	.startup =		whiteheat_fake_startup,
 };
 
 static struct usb_serial_device_type whiteheat_device = {
-	name:			"Connect Tech - WhiteHEAT",
-	id_table:		id_table_std,
-	needs_interrupt_in:	DONT_CARE,				/* don't have to have an interrupt in endpoint */
-	needs_bulk_in:		DONT_CARE,				/* don't have to have a bulk in endpoint */
-	needs_bulk_out:		DONT_CARE,				/* don't have to have a bulk out endpoint */
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		4,
-	open:			whiteheat_open,
-	close:			whiteheat_close,
-	throttle:		whiteheat_throttle,
-	unthrottle:		whiteheat_unthrottle,
-	ioctl:			whiteheat_ioctl,
-	set_termios:		whiteheat_set_termios,
-	startup:		whiteheat_real_startup,
-	shutdown:		whiteheat_real_shutdown,
+	.owner =		THIS_MODULE,
+	.name =			"Connect Tech - WhiteHEAT",
+	.id_table =		id_table_std,
+	.num_interrupt_in =	NUM_DONT_CARE,
+	.num_bulk_in =		NUM_DONT_CARE,
+	.num_bulk_out =		NUM_DONT_CARE,
+	.num_ports =		4,
+	.open =			whiteheat_open,
+	.close =		whiteheat_close,
+	.throttle =		whiteheat_throttle,
+	.unthrottle =		whiteheat_unthrottle,
+	.ioctl =		whiteheat_ioctl,
+	.set_termios =		whiteheat_set_termios,
+	.startup =		whiteheat_real_startup,
+	.shutdown =		whiteheat_real_shutdown,
 };
 
 struct whiteheat_private {
@@ -186,7 +179,7 @@
  *****************************************************************************/
 static void command_port_write_callback (struct urb *urb)
 {
-	dbg (__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	if (urb->status) {
 		dbg ("nonzero urb status: %d", urb->status);
@@ -207,15 +200,15 @@
 	unsigned char *data = urb->transfer_buffer;
 	int result;
 
-	dbg (__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 
 	if (urb->status) {
-		dbg (__FUNCTION__ " - nonzero urb status: %d", urb->status);
+		dbg("%s - nonzero urb status: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 	
@@ -223,7 +216,7 @@
 
 	info = (struct whiteheat_private *)port->private;
 	if (!info) {
-		dbg (__FUNCTION__ " - info is NULL, exiting.");
+		dbg("%s - info is NULL, exiting.", __FUNCTION__);
 		return;
 	}
 
@@ -246,7 +239,7 @@
 		      command_port_read_callback, port);
 	result = usb_submit_urb(port->read_urb);
 	if (result)
-		dbg(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+		dbg("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
 }
 
 
@@ -258,7 +251,7 @@
 	__u8 *transfer_buffer;
 	int retval = 0;
 
-	dbg(__FUNCTION__" - command %d", command);
+	dbg("%s - command %d", __FUNCTION__, command);
 
 	port = &serial->port[COMMAND_PORT];
 	info = (struct whiteheat_private *)port->private;
@@ -271,7 +264,7 @@
 	port->write_urb->dev = serial->dev;
 	retval = usb_submit_urb (port->write_urb);
 	if (retval) {
-		dbg (__FUNCTION__" - submit urb failed");
+		dbg("%s - submit urb failed", __FUNCTION__);
 		goto exit;
 	}
 
@@ -282,19 +275,19 @@
 	}
 
 	if (info->command_finished == FALSE) {
-		dbg (__FUNCTION__ " - command timed out.");
+		dbg("%s - command timed out.", __FUNCTION__);
 		retval = -ETIMEDOUT;
 		goto exit;
 	}
 
 	if (info->command_finished == WHITEHEAT_CMD_FAILURE) {
-		dbg (__FUNCTION__ " - command failed.");
+		dbg("%s - command failed.", __FUNCTION__);
 		retval = -EIO;
 		goto exit;
 	}
 
 	if (info->command_finished == WHITEHEAT_CMD_COMPLETE)
-		dbg (__FUNCTION__ " - command completed.");
+		dbg("%s - command completed.", __FUNCTION__);
 
 exit:
 	return retval;
@@ -308,70 +301,51 @@
 	struct whiteheat_private	*info;
 	int				retval = 0;
 
-	dbg(__FUNCTION__" - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	down (&port->sem);
-
-	++port->open_count;
-	MOD_INC_USE_COUNT;
-	
-	if (!port->active) {
-		port->active = 1;
-
-		/* set up some stuff for our command port */
-		command_port = &port->serial->port[COMMAND_PORT];
-		if (command_port->private == NULL) {
-			info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL);
-			if (info == NULL) {
-				err(__FUNCTION__ " - out of memory");
-				retval = -ENOMEM;
-				goto error_exit;
-			}
-			
-			init_waitqueue_head(&info->wait_command);
-			command_port->private = info;
-			command_port->write_urb->complete = command_port_write_callback;
-			command_port->read_urb->complete = command_port_read_callback;
-			command_port->read_urb->dev = port->serial->dev;
-			command_port->tty = port->tty;		/* need this to "fake" our our sanity check macros */
-			retval = usb_submit_urb (command_port->read_urb);
-			if (retval) {
-				err(__FUNCTION__ " - failed submitting read urb, error %d", retval);
-				goto error_exit;
-			}
+	/* set up some stuff for our command port */
+	command_port = &port->serial->port[COMMAND_PORT];
+	if (command_port->private == NULL) {
+		info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL);
+		if (info == NULL) {
+			err("%s - out of memory", __FUNCTION__);
+			retval = -ENOMEM;
+			goto exit;
 		}
 		
-		/* Start reading from the device */
-		port->read_urb->dev = port->serial->dev;
-		retval = usb_submit_urb(port->read_urb);
+		init_waitqueue_head(&info->wait_command);
+		command_port->private = info;
+		command_port->write_urb->complete = command_port_write_callback;
+		command_port->read_urb->complete = command_port_read_callback;
+		command_port->read_urb->dev = port->serial->dev;
+		command_port->tty = port->tty;		/* need this to "fake" our our sanity check macros */
+		retval = usb_submit_urb (command_port->read_urb);
 		if (retval) {
-			err(__FUNCTION__ " - failed submitting read urb, error %d", retval);
-			goto error_exit;
+			err("%s - failed submitting read urb, error %d", __FUNCTION__, retval);
+			goto exit;
 		}
+	}
 	
-		/* send an open port command */
-		/* firmware uses 1 based port numbering */
-		open_command.port = port->number - port->serial->minor + 1;
-		retval = whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command));
-		if (retval)
-			goto error_exit;
-	
-		/* Need to do device specific setup here (control lines, baud rate, etc.) */
-		/* FIXME!!! */
+	/* Start reading from the device */
+	port->read_urb->dev = port->serial->dev;
+	retval = usb_submit_urb(port->read_urb);
+	if (retval) {
+		err("%s - failed submitting read urb, error %d", __FUNCTION__, retval);
+		goto exit;
 	}
 
-	dbg(__FUNCTION__ " - exit");
-	up (&port->sem);
-	
-	return retval;
+	/* send an open port command */
+	/* firmware uses 1 based port numbering */
+	open_command.port = port->number - port->serial->minor + 1;
+	retval = whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command));
+	if (retval)
+		goto exit;
 
-error_exit:
-	--port->open_count;
-	MOD_DEC_USE_COUNT;
+	/* Need to do device specific setup here (control lines, baud rate, etc.) */
+	/* FIXME!!! */
 
-	dbg(__FUNCTION__ " - error_exit");
-	up (&port->sem);
-	
+exit:
+	dbg("%s - exit, retval = %d", __FUNCTION__, retval);
 	return retval;
 }
 
@@ -380,33 +354,25 @@
 {
 	struct whiteheat_min_set	close_command;
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	
-	down (&port->sem);
-	--port->open_count;
+	/* send a close command to the port */
+	/* firmware uses 1 based port numbering */
+	close_command.port = port->number - port->serial->minor + 1;
+	whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command));
 
-	if (port->open_count <= 0) {
-		/* send a close command to the port */
-		/* firmware uses 1 based port numbering */
-		close_command.port = port->number - port->serial->minor + 1;
-		whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command));
+	/* Need to change the control lines here */
+	/* FIXME */
 	
-		/* Need to change the control lines here */
-		/* FIXME */
-		
-		/* shutdown our bulk reads and writes */
-		usb_unlink_urb (port->write_urb);
-		usb_unlink_urb (port->read_urb);
-		port->active = 0;
-	}
-	MOD_DEC_USE_COUNT;
-	up (&port->sem);
+	/* shutdown our bulk reads and writes */
+	usb_unlink_urb (port->write_urb);
+	usb_unlink_urb (port->read_urb);
 }
 
 
 static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
 {
-	dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
+	dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
 
 	return -ENOIOCTLCMD;
 }
@@ -417,12 +383,10 @@
 	unsigned int cflag;
 	struct whiteheat_port_settings port_settings;
 
-	dbg(__FUNCTION__ " -port %d", port->number);
-
-	down (&port->sem);
+	dbg("%s -port %d", __FUNCTION__, port->number);
 
 	if ((!port->tty) || (!port->tty->termios)) {
-		dbg(__FUNCTION__" - no tty structures");
+		dbg("%s - no tty structures", __FUNCTION__);
 		goto exit;
 	}
 	
@@ -431,7 +395,7 @@
 	if (old_termios) {
 		if ((cflag == old_termios->c_cflag) &&
 		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
-			dbg(__FUNCTION__ " - nothing to change...");
+			dbg("%s - nothing to change...", __FUNCTION__);
 			goto exit;
 		}
 	}
@@ -448,7 +412,7 @@
 		default:
 		case CS8:	port_settings.bits = 8;   break;
 	}
-	dbg(__FUNCTION__ " - data bits = %d", port_settings.bits);
+	dbg("%s - data bits = %d", __FUNCTION__, port_settings.bits);
 	
 	/* determine the parity */
 	if (cflag & PARENB)
@@ -458,14 +422,14 @@
 			port_settings.parity = 'e';
 	else
 		port_settings.parity = 'n';
-	dbg(__FUNCTION__ " - parity = %c", port_settings.parity);
+	dbg("%s - parity = %c", __FUNCTION__, port_settings.parity);
 
 	/* figure out the stop bits requested */
 	if (cflag & CSTOPB)
 		port_settings.stop = 2;
 	else
 		port_settings.stop = 1;
-	dbg(__FUNCTION__ " - stop bits = %d", port_settings.stop);
+	dbg("%s - stop bits = %d", __FUNCTION__, port_settings.stop);
 
 	
 	/* figure out the flow control settings */
@@ -473,7 +437,7 @@
 		port_settings.hflow = (WHITEHEAT_CTS_FLOW | WHITEHEAT_RTS_FLOW);
 	else
 		port_settings.hflow = 0;
-	dbg(__FUNCTION__ " - hardware flow control = %s %s %s %s",
+	dbg("%s - hardware flow control = %s %s %s %s", __FUNCTION__,
 	    (port_settings.hflow & WHITEHEAT_CTS_FLOW) ? "CTS" : "",
 	    (port_settings.hflow & WHITEHEAT_RTS_FLOW) ? "RTS" : "",
 	    (port_settings.hflow & WHITEHEAT_DSR_FLOW) ? "DSR" : "",
@@ -484,15 +448,15 @@
 		port_settings.sflow = 'b';
 	else
 		port_settings.sflow = 'n';
-	dbg(__FUNCTION__ " - software flow control = %c", port_settings.sflow);
+	dbg("%s - software flow control = %c", __FUNCTION__, port_settings.sflow);
 	
 	port_settings.xon = START_CHAR(port->tty);
 	port_settings.xoff = STOP_CHAR(port->tty);
-	dbg(__FUNCTION__ " - XON = %2x, XOFF = %2x", port_settings.xon, port_settings.xoff);
+	dbg("%s - XON = %2x, XOFF = %2x", __FUNCTION__, port_settings.xon, port_settings.xoff);
 
 	/* get the baud rate wanted */
 	port_settings.baud = tty_get_baud_rate(port->tty);
-	dbg(__FUNCTION__ " - baud rate = %d", port_settings.baud);
+	dbg("%s - baud rate = %d", __FUNCTION__, port_settings.baud);
 
 	/* handle any settings that aren't specified in the tty structure */
 	port_settings.lloop = 0;
@@ -501,14 +465,13 @@
 	whiteheat_send_cmd (port->serial, WHITEHEAT_SETUP_PORT, (__u8 *)&port_settings, sizeof(port_settings));
 	
 exit:
-	up (&port->sem);
 	return;
 }
 
 
 static void whiteheat_throttle (struct usb_serial_port *port)
 {
-	dbg(__FUNCTION__" - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	/* Change the control signals */
 	/* FIXME!!! */
@@ -519,7 +482,7 @@
 
 static void whiteheat_unthrottle (struct usb_serial_port *port)
 {
-	dbg(__FUNCTION__" - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	/* Change the control signals */
 	/* FIXME!!! */
@@ -541,12 +504,12 @@
  - device renumerated itself and comes up as new device id with all
    firmware download completed.
 */
-static int  whiteheat_fake_startup (struct usb_serial *serial)
+static int whiteheat_fake_startup (struct usb_serial *serial)
 {
 	int response;
 	const struct whiteheat_hex_record *record;
 	
-	dbg(__FUNCTION__);
+	dbg("%s", __FUNCTION__);
 	
 	response = ezusb_set_reset (serial, 1);
 
@@ -555,8 +518,8 @@
 		response = ezusb_writememory (serial, record->address, 
 				(unsigned char *)record->data, record->data_size, 0xa0);
 		if (response < 0) {
-			err(__FUNCTION__ " - ezusb_writememory failed for loader (%d %04X %p %d)", 
-				response, record->address, record->data, record->data_size);
+			err("%s - ezusb_writememory failed for loader (%d %04X %p %d)",
+				__FUNCTION__, response, record->address, record->data, record->data_size);
 			break;
 		}
 		++record;
@@ -572,8 +535,8 @@
 		response = ezusb_writememory (serial, record->address, 
 				(unsigned char *)record->data, record->data_size, 0xa3);
 		if (response < 0) {
-			err(__FUNCTION__ " - ezusb_writememory failed for first firmware step (%d %04X %p %d)", 
-				response, record->address, record->data, record->data_size);
+			err("%s - ezusb_writememory failed for first firmware step (%d %04X %p %d)", 
+				__FUNCTION__, response, record->address, record->data, record->data_size);
 			break;
 		}
 		++record;
@@ -586,8 +549,8 @@
 		response = ezusb_writememory (serial, record->address, 
 				(unsigned char *)record->data, record->data_size, 0xa0);
 		if (response < 0) {
-			err(__FUNCTION__" - ezusb_writememory failed for second firmware step (%d %04X %p %d)", 
-				response, record->address, record->data, record->data_size);
+			err("%s - ezusb_writememory failed for second firmware step (%d %04X %p %d)", 
+				__FUNCTION__, response, record->address, record->data, record->data_size);
 			break;
 		}
 		++record;
@@ -662,16 +625,8 @@
 static void whiteheat_real_shutdown (struct usb_serial *serial)
 {
 	struct usb_serial_port *command_port;
-	int i;
-
-	dbg(__FUNCTION__);
 
-	/* stop reads and writes on all ports */
-	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
-			whiteheat_close (&serial->port[i], NULL);
-		}
-	}
+	dbg("%s", __FUNCTION__);
 
 	/* free up our private data for our command port */
 	command_port = &serial->port[COMMAND_PORT];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/storage/Makefile linux-2.4.20/drivers/usb/storage/Makefile
--- linux-2.4.19/drivers/usb/storage/Makefile	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/storage/Makefile	2002-10-29 11:18:49.000000000 +0000
@@ -15,6 +15,7 @@
 usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG)	+= debug.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_HP8200e)	+= shuttle_usbat.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR09)	+= sddr09.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR55)	+= sddr55.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_FREECOM)	+= freecom.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM)	+= dpcm.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_ISD200)	+= isd200.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/storage/freecom.c linux-2.4.20/drivers/usb/storage/freecom.c
--- linux-2.4.19/drivers/usb/storage/freecom.c	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.20/drivers/usb/storage/freecom.c	2002-10-29 11:18:40.000000000 +0000
@@ -34,7 +34,7 @@
 #include "usb.h"
 #include "debug.h"
 #include "freecom.h"
-#include "linux/hdreg.h"
+#include <linux/hdreg.h>
 
 #ifdef CONFIG_USB_STORAGE_DEBUG
 static void pdump (void *, int);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/storage/scsiglue.c linux-2.4.20/drivers/usb/storage/scsiglue.c
--- linux-2.4.19/drivers/usb/storage/scsiglue.c	2001-11-11 18:01:32.000000000 +0000
+++ linux-2.4.20/drivers/usb/storage/scsiglue.c	2002-10-29 11:18:47.000000000 +0000
@@ -190,7 +190,7 @@
 	}
 
 	/* if we have an urb pending, let's wake the control thread up */
-	if (us->current_urb->status == -EINPROGRESS) {
+	if (!us->current_done.done) {
 		/* cancel the URB -- this will automatically wake the thread */
 		usb_unlink_urb(us->current_urb);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/storage/sddr55.c linux-2.4.20/drivers/usb/storage/sddr55.c
--- linux-2.4.19/drivers/usb/storage/sddr55.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/storage/sddr55.c	2002-10-29 11:18:47.000000000 +0000
@@ -0,0 +1,1134 @@
+/* Driver for SanDisk SDDR-55 SmartMedia reader
+ *
+ * $Id:$
+ *
+ * SDDR55 driver v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2002 Simon Munton
+ *
+ * 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, 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "transport.h"
+#include "protocol.h"
+#include "usb.h"
+#include "debug.h"
+#include "sddr55.h"
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
+#define LSB_of(s) ((s)&0xFF)
+#define MSB_of(s) ((s)>>8)
+#define PAGESIZE  512
+
+#define set_sense_info(sk, asc, ascq)	\
+    do {				\
+	info->sense_data[2] = sk;	\
+	info->sense_data[12] = asc;	\
+	info->sense_data[13] = ascq;	\
+	} while (0)
+
+
+struct sddr55_card_info {
+	unsigned long	capacity;	/* Size of card in bytes */
+	int		max_log_blks;	/* maximum number of logical blocks */
+	int		pageshift;	/* log2 of pagesize */
+	int		smallpageshift;	/* 1 if pagesize == 256 */
+	int		blocksize;	/* Size of block in pages */
+	int		blockshift;	/* log2 of blocksize */
+	int		blockmask;	/* 2^blockshift - 1 */
+	int		read_only;	/* non zero if card is write protected */
+	int		force_read_only;	/* non zero if we find a map error*/
+	int		*lba_to_pba;	/* logical to physical map */
+	int		*pba_to_lba;	/* physical to logical map */
+	int		fatal_error;	/* set if we detect something nasty */
+	unsigned long 	last_access;	/* number of jiffies since we last talked to device */
+	unsigned char   sense_data[18];
+};
+
+
+#define NOT_ALLOCATED		0xffffffff
+#define BAD_BLOCK		0xffff
+#define CIS_BLOCK		0x400
+#define UNUSED_BLOCK		0x3ff
+
+
+
+static int sddr55_raw_bulk(struct us_data *us, 
+		int direction,
+		unsigned char *data,
+		unsigned int len) {
+
+	int result;
+	int act_len;
+	int pipe;
+
+	if (direction == SCSI_DATA_READ)
+		pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+	else
+		pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+	result = usb_stor_bulk_msg(us, data, pipe, len, &act_len);
+
+	/* if we stall, we need to clear it before we go on */
+	if (result == -EPIPE) {
+		US_DEBUGP("EPIPE: clearing endpoint halt for"
+			" pipe 0x%x, stalled at %d bytes\n",
+			pipe, act_len);
+		usb_clear_halt(us->pusb_dev, pipe);
+	}
+
+	if (result) {
+
+		/* NAK - that means we've retried a few times already */
+		if (result == -ETIMEDOUT) {
+			US_DEBUGP("usbat_raw_bulk():"
+				" device NAKed\n");
+
+			return US_BULK_TRANSFER_FAILED;
+		}
+
+		/* -ENOENT -- we canceled this transfer */
+		if (result == -ENOENT) {
+			US_DEBUGP("usbat_raw_bulk():"
+				" transfer aborted\n");
+			return US_BULK_TRANSFER_ABORTED;
+		}
+
+		if (result == -EPIPE) {
+			US_DEBUGP("usbat_raw_bulk():"
+				" output pipe stalled\n");
+			return US_BULK_TRANSFER_FAILED;
+		}
+
+		/* the catch-all case */
+		US_DEBUGP("us_transfer_partial(): unknown error\n");
+		return US_BULK_TRANSFER_FAILED;
+	}
+
+	if (act_len != len) {
+		US_DEBUGP("Warning: Transferred only %d bytes\n",
+			act_len);
+		return US_BULK_TRANSFER_SHORT;
+	}
+
+	US_DEBUGP("Transferred %d of %d bytes\n", act_len, len);
+
+	return US_BULK_TRANSFER_GOOD;
+}
+
+/*
+ * Note: direction must be set if command_len == 0.
+ */
+
+static int sddr55_bulk_transport(struct us_data *us,
+			  int direction,
+			  unsigned char *data,
+			  unsigned int len) {
+
+	int result = USB_STOR_TRANSPORT_GOOD;
+	struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
+
+	if (len==0)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	info->last_access = jiffies;
+
+#ifdef CONFIG_USB_STORAGE_DEBUG
+	if (direction == SCSI_DATA_WRITE) {
+		int i;
+		char string[64];
+
+		/* Debug-print the first 48 bytes of the write transfer */
+
+		strcpy(string, "wr: ");
+		for (i=0; i<len && i<48; i++) {
+			sprintf(string+strlen(string), "%02X ",
+			  data[i]);
+			if ((i%16)==15) {
+				US_DEBUGP("%s\n", string);
+				strcpy(string, "wr: ");
+			}
+		}
+		if ((i%16)!=0)
+			US_DEBUGP("%s\n", string);
+	}
+#endif
+
+	/* transfer the data */
+
+	US_DEBUGP("SCM data %s transfer %d\n",
+		  ( direction==SCSI_DATA_READ ? "in" : "out"),
+		  len);
+
+	result = sddr55_raw_bulk(us, direction, data, len);
+
+#ifdef CONFIG_USB_STORAGE_DEBUG
+	if (direction == SCSI_DATA_READ) {
+		int i;
+		char string[64];
+
+		/* Debug-print the first 48 bytes of the read transfer */
+
+		strcpy(string, "rd: ");
+		for (i=0; i<len && i<48; i++) {
+			sprintf(string+strlen(string), "%02X ",
+			  data[i]);
+			if ((i%16)==15) {
+				US_DEBUGP("%s\n", string);
+				strcpy(string, "rd: ");
+			}
+		}
+		if ((i%16)!=0)
+			US_DEBUGP("%s\n", string);
+	}
+#endif
+
+	return result;
+}
+
+
+/* check if card inserted, if there is, update read_only status
+ * return non zero if no card
+ */
+
+static int sddr55_status(struct us_data *us)
+{
+	int result;
+	unsigned char command[8] = {
+		0, 0, 0, 0, 0, 0xb0, 0, 0x80
+	};
+	unsigned char status[8];
+	struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
+
+	/* send command */
+	result = sddr55_bulk_transport(us,
+		SCSI_DATA_WRITE, command, 8);
+
+	US_DEBUGP("Result for send_command in status %d\n",
+		result);
+
+	if (result != US_BULK_TRANSFER_GOOD) {
+		set_sense_info (4, 0, 0);	/* hardware error */
+		return result;
+	}
+
+	result = sddr55_bulk_transport(us,
+		SCSI_DATA_READ, status,	4);
+
+	/* expect to get short transfer if no card fitted */
+	if (result == US_BULK_TRANSFER_SHORT) {
+		/* had a short transfer, no card inserted, free map memory */
+		if (info->lba_to_pba)
+			kfree(info->lba_to_pba);
+		if (info->pba_to_lba)
+			kfree(info->pba_to_lba);
+		info->lba_to_pba = NULL;
+		info->pba_to_lba = NULL;
+
+		info->fatal_error = 0;
+		info->force_read_only = 0;
+
+		set_sense_info (2, 0x3a, 0);	/* not ready, medium not present */
+		return result;
+	}
+
+	if (result != US_BULK_TRANSFER_GOOD) {
+		set_sense_info (4, 0, 0);	/* hardware error */
+		return result;
+	}
+	
+	/* check write protect status */
+	info->read_only = (status[0] & 0x20);
+
+	/* now read status */
+	result = sddr55_bulk_transport(us,
+		SCSI_DATA_READ, status,	2);
+
+	if (result != US_BULK_TRANSFER_GOOD) {
+		set_sense_info (4, 0, 0);	/* hardware error */
+	}
+
+	return result;
+}
+
+
+static int sddr55_read_data(struct us_data *us,
+		unsigned int lba,
+		unsigned int page,
+		unsigned short sectors,
+		unsigned char *content,
+		int use_sg) {
+
+	int result;
+	unsigned char command[8] = {
+		0, 0, 0, 0, 0, 0xb0, 0, 0x85
+	};
+	unsigned char status[8];
+	struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
+
+	unsigned int pba;
+	unsigned long address;
+
+	unsigned short pages;
+	unsigned char *buffer = NULL;
+	unsigned char *ptr;
+	struct scatterlist *sg = NULL;
+	int i;
+	int len;
+	int transferred;
+
+	// If we're using scatter-gather, we have to create a new
+	// buffer to read all of the data in first, since a
+	// scatter-gather buffer could in theory start in the middle
+	// of a page, which would be bad. A developer who wants a
+	// challenge might want to write a limited-buffer
+	// version of this code.
+
+	len = sectors * PAGESIZE;
+
+	if (use_sg) {
+		sg = (struct scatterlist *)content;
+		buffer = kmalloc(len, GFP_NOIO);
+		if (buffer == NULL)
+			return USB_STOR_TRANSPORT_ERROR;
+		ptr = buffer;
+	} else
+		ptr = content;
+
+	// This could be made much more efficient by checking for
+	// contiguous LBA's. Another exercise left to the student.
+
+	while (sectors>0) {
+
+		/* have we got to end? */
+		if (lba >= info->max_log_blks)
+			break;
+
+		pba = info->lba_to_pba[lba];
+
+		// Read as many sectors as possible in this block
+
+		pages = info->blocksize - page;
+		if (pages > (sectors << info->smallpageshift))
+			pages = (sectors << info->smallpageshift);
+
+		US_DEBUGP("Read %02X pages, from PBA %04X"
+			" (LBA %04X) page %02X\n",
+			pages, pba, lba, page);
+
+		if (pba == NOT_ALLOCATED) {
+			/* no pba for this lba, fill with zeroes */
+			memset (ptr, 0, pages << info->pageshift);
+		} else {
+
+			address = (pba << info->blockshift) + page;
+
+			command[1] = LSB_of(address>>16);
+			command[2] = LSB_of(address>>8);
+			command[3] = LSB_of(address);
+
+			command[6] = LSB_of(pages << (1 - info->smallpageshift));
+
+			/* send command */
+			result = sddr55_bulk_transport(us,
+				SCSI_DATA_WRITE, command, 8);
+
+			US_DEBUGP("Result for send_command in read_data %d\n",
+				result);
+
+			if (result != US_BULK_TRANSFER_GOOD) {
+				if (use_sg)
+					kfree(buffer);
+				return result;
+			}
+
+			/* read data */
+			result = sddr55_bulk_transport(us,
+				SCSI_DATA_READ, ptr,
+				pages<<info->pageshift);
+
+			if (result != US_BULK_TRANSFER_GOOD) {
+				if (use_sg)
+					kfree(buffer);
+				return result;
+			}
+
+			/* now read status */
+			result = sddr55_bulk_transport(us,
+				SCSI_DATA_READ, status, 2);
+
+			if (result != US_BULK_TRANSFER_GOOD) {
+				if (use_sg)
+					kfree(buffer);
+				return result;
+			}
+
+			/* check status for error */
+			if (status[0] == 0xff && status[1] == 0x4) {
+				set_sense_info (3, 0x11, 0);
+				if (use_sg)
+					kfree(buffer);
+
+				return USB_STOR_TRANSPORT_FAILED;
+			}
+
+		}
+
+		page = 0;
+		lba++;
+		sectors -= pages >> info->smallpageshift;
+		ptr += (pages << info->pageshift);
+	}
+
+	if (use_sg) {
+		transferred = 0;
+		for (i=0; i<use_sg && transferred<len; i++) {
+			memcpy(sg[i].address, buffer+transferred,
+				len-transferred > sg[i].length ?
+					sg[i].length : len-transferred);
+			transferred += sg[i].length;
+		}
+		kfree(buffer);
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int sddr55_write_data(struct us_data *us,
+		unsigned int lba,
+		unsigned int page,
+		unsigned short sectors,
+		unsigned char *content,
+		int use_sg) {
+
+	int result;
+	unsigned char command[8] = {
+		0, 0, 0, 0, 0, 0xb0, 0, 0x86
+	};
+	unsigned char status[8];
+	struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
+
+	unsigned int pba;
+	unsigned int new_pba;
+	unsigned long address;
+
+	unsigned short pages;
+	unsigned char *buffer = NULL;
+	unsigned char *ptr;
+	struct scatterlist *sg = NULL;
+	int i;
+	int len;
+	int transferred;
+
+	/* check if we are allowed to write */
+	if (info->read_only || info->force_read_only) {
+		set_sense_info (7, 0x27, 0);	/* read only */
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	// If we're using scatter-gather, we have to create a new
+	// buffer to write all of the data in first, since a
+	// scatter-gather buffer could in theory start in the middle
+	// of a page, which would be bad. A developer who wants a
+	// challenge might want to write a limited-buffer
+	// version of this code.
+
+	len = sectors * PAGESIZE;
+
+	if (use_sg) {
+		sg = (struct scatterlist *)content;
+		buffer = kmalloc(len, GFP_NOIO);
+		if (buffer == NULL)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		transferred = 0;
+		for (i=0; i<use_sg && transferred<len; i++) {
+			memcpy(buffer+transferred, sg[i].address,
+				len-transferred > sg[i].length ?
+					sg[i].length : len-transferred);
+			transferred += sg[i].length;
+		}
+
+		ptr = buffer;
+	} else
+		ptr = content;
+
+	while (sectors > 0) {
+
+		/* have we got to end? */
+		if (lba >= info->max_log_blks)
+			break;
+
+		pba = info->lba_to_pba[lba];
+
+		// Write as many sectors as possible in this block
+
+		pages = info->blocksize - page;
+		if (pages > (sectors << info->smallpageshift))
+			pages = (sectors << info->smallpageshift);
+
+		US_DEBUGP("Write %02X pages, to PBA %04X"
+			" (LBA %04X) page %02X\n",
+			pages, pba, lba, page);
+			
+		command[4] = 0;
+
+		if (pba == NOT_ALLOCATED) {
+			/* no pba allocated for this lba, find a free pba to use */
+
+			int max_pba = (info->max_log_blks / 250 ) * 256;
+			int found_count = 0;
+			int found_pba = -1;
+
+			/* set pba to first block in zone lba is in */
+			pba = (lba / 1000) * 1024;
+
+			US_DEBUGP("No PBA for LBA %04X\n",lba);
+
+			if (max_pba > 1024)
+				max_pba = 1024;
+
+			/* scan through the map lookiong for an unused block
+			 * leave 16 unused blocks at start (or as many as possible)
+			 * since the sddr55 seems to reuse a used block when it shouldn't
+			 * if we don't leave space */
+			for (i = 0; i < max_pba; i++, pba++) {
+				if (info->pba_to_lba[pba] == UNUSED_BLOCK) {
+					found_pba = pba;
+					if (found_count++ > 16)
+						break;
+				}
+			}
+
+			pba = found_pba;
+
+			if (pba == -1) {
+				/* oh dear, couldn't find an unallocated block */
+				US_DEBUGP("Couldn't find unallocated block\n");
+
+				set_sense_info (3, 0x31, 0);	/* medium error */
+
+				if (use_sg)
+					kfree(buffer);
+
+				return USB_STOR_TRANSPORT_FAILED;
+			}
+
+			US_DEBUGP("Allocating PBA %04X for LBA %04X\n", pba, lba);
+
+			/* set writing to unallocated block flag */
+			command[4] = 0x40;
+		}
+
+		address = (pba << info->blockshift) + page;
+
+		command[1] = LSB_of(address>>16);
+		command[2] = LSB_of(address>>8); 
+		command[3] = LSB_of(address);
+
+		/* set the lba into the command, modulo 1000 */
+		command[0] = LSB_of(lba % 1000);
+		command[6] = MSB_of(lba % 1000);
+
+		command[4] |= LSB_of(pages >> info->smallpageshift);
+
+		/* send command */
+		result = sddr55_bulk_transport(us,
+			SCSI_DATA_WRITE, command, 8);
+
+		if (result != US_BULK_TRANSFER_GOOD) {
+			US_DEBUGP("Result for send_command in write_data %d\n",
+			result);
+
+			set_sense_info (3, 0x3, 0);	/* peripheral write error */
+			
+			if (use_sg)
+				kfree(buffer);
+			return result;
+		}
+
+		/* send the data */
+		result = sddr55_bulk_transport(us,
+			SCSI_DATA_WRITE, ptr,
+			pages<<info->pageshift);
+
+		if (result != US_BULK_TRANSFER_GOOD) {
+			US_DEBUGP("Result for send_data in write_data %d\n",
+			result);
+
+			set_sense_info (3, 0x3, 0);	/* peripheral write error */
+
+			if (use_sg)
+				kfree(buffer);
+			return result;
+		}
+
+		/* now read status */
+		result = sddr55_bulk_transport(us,
+			SCSI_DATA_READ, status,	6);
+
+		if (result != US_BULK_TRANSFER_GOOD) {
+			US_DEBUGP("Result for get_status in write_data %d\n",
+			result);
+
+			set_sense_info (3, 0x3, 0);	/* peripheral write error */
+
+			if (use_sg)
+				kfree(buffer);
+			return result;
+		}
+
+		new_pba = (status[3] + (status[4] << 8) + (status[5] << 16)) >> info->blockshift;
+
+		/* check status for error */
+		if (status[0] == 0xff && status[1] == 0x4) {
+			set_sense_info (3, 0x0c, 0);
+			if (use_sg)
+				kfree(buffer);
+
+			info->pba_to_lba[new_pba] = BAD_BLOCK;
+
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		US_DEBUGP("Updating maps for LBA %04X: old PBA %04X, new PBA %04X\n",
+			lba, pba, new_pba);
+
+		/* update the lba<->pba maps, note new_pba might be the same as pba */
+		info->lba_to_pba[lba] = new_pba;
+		info->pba_to_lba[pba] = UNUSED_BLOCK;
+
+		/* check that new_pba wasn't already being used */
+		if (info->pba_to_lba[new_pba] != UNUSED_BLOCK) {
+			printk(KERN_ERR "sddr55 error: new PBA %04X already in use for LBA %04X\n",
+				new_pba, info->pba_to_lba[new_pba]);
+			info->fatal_error = 1;
+			set_sense_info (3, 0x31, 0);
+			if (use_sg)
+				kfree(buffer);
+
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		/* update the pba<->lba maps for new_pba */
+		info->pba_to_lba[new_pba] = lba % 1000;
+
+		page = 0;
+		lba++;
+		sectors -= pages >> info->smallpageshift;
+		ptr += (pages << info->pageshift);
+	}
+
+	if (use_sg) {
+		kfree(buffer);
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int sddr55_read_deviceID(struct us_data *us,
+		unsigned char *manufacturerID,
+		unsigned char *deviceID) {
+
+	int result;
+	unsigned char command[8] = {
+		0, 0, 0, 0, 0, 0xb0, 0, 0x84
+	};
+	unsigned char content[64];
+
+	result = sddr55_bulk_transport(us, SCSI_DATA_WRITE, command, 8);
+
+	US_DEBUGP("Result of send_control for device ID is %d\n",
+		result);
+
+	if (result != US_BULK_TRANSFER_GOOD)
+		return result;
+
+	result = sddr55_bulk_transport(us,
+		SCSI_DATA_READ, content, 4);
+
+	if (result != US_BULK_TRANSFER_GOOD)
+		return result;
+
+	*manufacturerID = content[0];
+	*deviceID = content[1];
+
+	if (content[0] != 0xff)	{
+    		result = sddr55_bulk_transport(us,
+			SCSI_DATA_READ, content, 2);
+	}
+
+	return result;
+}
+
+
+int sddr55_reset(struct us_data *us) {
+	return 0;
+}
+
+
+static unsigned long sddr55_get_capacity(struct us_data *us) {
+
+	unsigned char manufacturerID;
+	unsigned char deviceID;
+	int result;
+	struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
+
+	US_DEBUGP("Reading capacity...\n");
+
+	result = sddr55_read_deviceID(us,
+		&manufacturerID,
+		&deviceID);
+
+	US_DEBUGP("Result of read_deviceID is %d\n",
+		result);
+
+	if (result != US_BULK_TRANSFER_GOOD)
+		return 0;
+
+	US_DEBUGP("Device ID = %02X\n", deviceID);
+	US_DEBUGP("Manuf  ID = %02X\n", manufacturerID);
+
+	info->pageshift = 9;
+	info->smallpageshift = 0;
+	info->blocksize = 16;
+	info->blockshift = 4;
+	info->blockmask = 15;
+
+	switch (deviceID) {
+
+	case 0x6e: // 1MB
+	case 0xe8:
+	case 0xec:
+		info->pageshift = 8;
+		info->smallpageshift = 1;
+		return 0x00100000;
+
+	case 0xea: // 2MB
+	case 0x64:
+		info->pageshift = 8;
+		info->smallpageshift = 1;
+	case 0x5d: // 5d is a ROM card with pagesize 512.
+		return 0x00200000;
+
+	case 0xe3: // 4MB
+	case 0xe5:
+	case 0x6b:
+	case 0xd5:
+		return 0x00400000;
+
+	case 0xe6: // 8MB
+	case 0xd6:
+		return 0x00800000;
+
+	case 0x73: // 16MB
+		info->blocksize = 32;
+		info->blockshift = 5;
+		info->blockmask = 31;
+		return 0x01000000;
+
+	case 0x75: // 32MB
+		info->blocksize = 32;
+		info->blockshift = 5;
+		info->blockmask = 31;
+		return 0x02000000;
+
+	case 0x76: // 64MB
+		info->blocksize = 32;
+		info->blockshift = 5;
+		info->blockmask = 31;
+		return 0x04000000;
+
+	case 0x79: // 128MB
+		info->blocksize = 32;
+		info->blockshift = 5;
+		info->blockmask = 31;
+		return 0x08000000;
+
+	default: // unknown
+		return 0;
+
+	}
+}
+
+static int sddr55_read_map(struct us_data *us) {
+
+	struct sddr55_card_info *info = (struct sddr55_card_info *)(us->extra);
+	int numblocks;
+	unsigned char *buffer;
+	unsigned char command[8] = { 0, 0, 0, 0, 0, 0xb0, 0, 0x8a};	
+	int i;
+	unsigned short lba;
+	unsigned short max_lba;
+	int result;
+
+	if (!info->capacity)
+		return -1;
+
+	numblocks = info->capacity >> (info->blockshift + info->pageshift);
+	
+	buffer = kmalloc( numblocks * 2, GFP_NOIO );
+	
+	if (!buffer)
+		return -1;
+
+	command[6] = numblocks * 2 / 256;
+
+	result = sddr55_bulk_transport(us, SCSI_DATA_WRITE, command, 8);
+
+	if ( result != US_BULK_TRANSFER_GOOD) {
+		kfree (buffer);
+		return -1;
+	}
+
+	result = sddr55_bulk_transport(us, SCSI_DATA_READ, buffer, numblocks * 2);
+
+	if ( result != US_BULK_TRANSFER_GOOD) {
+		kfree (buffer);
+		return -1;
+	}
+
+	result = sddr55_bulk_transport(us, SCSI_DATA_READ, command, 2);
+
+	if ( result != US_BULK_TRANSFER_GOOD) {
+		kfree (buffer);
+		return -1;
+	}
+
+	if (info->lba_to_pba)
+		kfree(info->lba_to_pba);
+	if (info->pba_to_lba)
+		kfree(info->pba_to_lba);
+	info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
+	info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
+
+	if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) {
+		if (info->lba_to_pba != NULL)
+			kfree(info->lba_to_pba);
+		if (info->pba_to_lba != NULL)
+			kfree(info->pba_to_lba);
+		info->lba_to_pba = NULL;
+		info->pba_to_lba = NULL;
+		kfree(buffer);
+		return -1;
+	}
+
+	memset(info->lba_to_pba, 0xff, numblocks*sizeof(int));
+	memset(info->pba_to_lba, 0xff, numblocks*sizeof(int));
+
+	/* set maximum lba */
+	max_lba = info->max_log_blks;
+	if (max_lba > 1000)
+		max_lba = 1000;
+
+	// Each block is 64 bytes of control data, so block i is located in
+	// scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11)
+
+	for (i=0; i<numblocks; i++) {
+		int zone = i / 1024;
+
+		lba = short_pack(buffer[i * 2], buffer[i * 2 + 1]);
+
+			/* Every 1024 physical blocks ("zone"), the LBA numbers
+			 * go back to zero, but are within a higher
+			 * block of LBA's. Also, there is a maximum of
+			 * 1000 LBA's per zone. In other words, in PBA
+			 * 1024-2047 you will find LBA 0-999 which are
+			 * really LBA 1000-1999. Yes, this wastes 24
+			 * physical blocks per zone. Go figure. 
+			 * These devices can have blocks go bad, so there
+			 * are 24 spare blocks to use when blocks do go bad.
+			 */
+
+			/* SDDR55 returns 0xffff for a bad block, and 0x400 for the 
+			 * CIS block. (Is this true for cards 8MB or less??)
+			 * Record these in the physical to logical map
+			 */ 
+
+		info->pba_to_lba[i] = lba;
+
+		if (lba >= max_lba) {
+			continue;
+		}
+		
+		if (info->lba_to_pba[lba + zone * 1000] != NOT_ALLOCATED &&
+		    !info->force_read_only) {
+			printk("sddr55: map inconsistency at LBA %04X\n", lba + zone * 1000);
+			info->force_read_only = 1;
+		}
+
+		if (lba<0x10 || (lba>=0x3E0 && lba<0x3EF))
+			US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i);
+
+		info->lba_to_pba[lba + zone * 1000] = i;
+	}
+
+	kfree(buffer);
+	return 0;
+}
+
+
+static void sddr55_card_info_destructor(void *extra) {
+	struct sddr55_card_info *info = (struct sddr55_card_info *)extra;
+
+	if (!extra)
+		return;
+
+	if (info->lba_to_pba)
+		kfree(info->lba_to_pba);
+	if (info->pba_to_lba)
+		kfree(info->pba_to_lba);
+}
+
+
+/*
+ * Transport for the Sandisk SDDR-55
+ */
+int sddr55_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+	int result;
+	int i;
+	unsigned char inquiry_response[36] = {
+		0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00
+	};
+	unsigned char mode_page_01[16] = { // write-protected for now
+		0x03, 0x00, 0x80, 0x00,
+		0x01, 0x0A,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
+	unsigned char *ptr;
+	unsigned long capacity;
+	unsigned int lba;
+	unsigned int pba;
+	unsigned int page;
+	unsigned short pages;
+	struct sddr55_card_info *info;
+
+	if (!us->extra) {
+		us->extra = kmalloc(
+			sizeof(struct sddr55_card_info), GFP_NOIO);
+		if (!us->extra)
+			return USB_STOR_TRANSPORT_ERROR;
+		memset(us->extra, 0, sizeof(struct sddr55_card_info));
+		us->extra_destructor = sddr55_card_info_destructor;
+	}
+
+	info = (struct sddr55_card_info *)(us->extra);
+
+	ptr = (unsigned char *)srb->request_buffer;
+
+	if (srb->cmnd[0] == REQUEST_SENSE) {
+		i = srb->cmnd[4];
+
+		if (i > sizeof info->sense_data)
+			i = sizeof info->sense_data;
+
+
+		US_DEBUGP("SDDR55: request sense %02x/%02x/%02x\n", info->sense_data[2], info->sense_data[12], info->sense_data[13]);
+
+		info->sense_data[0] = 0x70;
+		info->sense_data[7] = 10;
+
+		memcpy (ptr, info->sense_data, i);
+		memset (info->sense_data, 0, sizeof info->sense_data);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	memset (info->sense_data, 0, sizeof info->sense_data);
+
+	/* Dummy up a response for INQUIRY since SDDR55 doesn't
+	   respond to INQUIRY commands */
+
+	if (srb->cmnd[0] == INQUIRY) {
+		memset(inquiry_response+8, 0, 28);
+		fill_inquiry_response(us, inquiry_response, 36);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	/* only check card status if the map isn't allocated, ie no card seen yet
+	 * or if it's been over half a second since we last accessed it
+	 */
+	if (info->lba_to_pba == NULL || time_after(jiffies, info->last_access + HZ/2)) {
+
+		/* check to see if a card is fitted */
+		result = sddr55_status (us);
+		if (result) {
+			result = sddr55_status (us);
+			if (!result) {
+			set_sense_info (6, 0x28, 0);	/* new media, set unit attention, not ready to ready */
+			}
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+	}
+
+	/* if we detected a problem with the map when writing, don't allow any more access */
+	if (info->fatal_error) {
+
+		set_sense_info (3, 0x31, 0);
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	if (srb->cmnd[0] == READ_CAPACITY) {
+
+		capacity = sddr55_get_capacity(us);
+
+		if (!capacity) {
+			set_sense_info (3, 0x30, 0);	/* incompatible medium */
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		info->capacity = capacity;
+
+                /* figure out the maximum logical block number, allowing for the fact
+                 * that only 250 out of every 256 are used */
+		info->max_log_blks = ((info->capacity >> (info->pageshift + info->blockshift)) / 256) * 250;
+
+		/* Last page in the card, adjust as we only use 250 out of every 256 pages */
+		capacity = (capacity / 256) * 250;
+
+		capacity /= PAGESIZE;
+		capacity--;
+
+		ptr[0] = MSB_of(capacity>>16);
+		ptr[1] = LSB_of(capacity>>16);
+		ptr[2] = MSB_of(capacity&0xFFFF);
+		ptr[3] = LSB_of(capacity&0xFFFF);
+
+		// The page size
+
+		ptr[4] = MSB_of(PAGESIZE>>16);
+		ptr[5] = LSB_of(PAGESIZE>>16);
+		ptr[6] = MSB_of(PAGESIZE&0xFFFF);
+		ptr[7] = LSB_of(PAGESIZE&0xFFFF);
+
+		sddr55_read_map(us);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE) {
+
+		mode_page_01[2] = (info->read_only || info->force_read_only) ? 0x80 : 0;
+
+		if ( (srb->cmnd[2] & 0x3F) == 0x01 ) {
+
+			US_DEBUGP(
+			  "SDDR55: Dummy up request for mode page 1\n");
+
+			if (ptr==NULL || 
+			  srb->request_bufflen<sizeof(mode_page_01)) {
+				set_sense_info (5, 0x24, 0);	/* invalid field in command */
+				return USB_STOR_TRANSPORT_FAILED;
+			}
+
+			memcpy(ptr, mode_page_01, sizeof(mode_page_01));
+			return USB_STOR_TRANSPORT_GOOD;
+
+		} else if ( (srb->cmnd[2] & 0x3F) == 0x3F ) {
+
+			US_DEBUGP(
+			  "SDDR55: Dummy up request for all mode pages\n");
+
+			if (ptr==NULL || 
+			  srb->request_bufflen<sizeof(mode_page_01)) {
+				set_sense_info (5, 0x24, 0);	/* invalid field in command */
+				return USB_STOR_TRANSPORT_FAILED;
+			}
+
+			memcpy(ptr, mode_page_01, sizeof(mode_page_01));
+			return USB_STOR_TRANSPORT_GOOD;
+		}
+
+		set_sense_info (5, 0x24, 0);	/* invalid field in command */
+
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+
+		US_DEBUGP(
+		  "SDDR55: %s medium removal. Not that I can do"
+		  " anything about it...\n",
+		  (srb->cmnd[4]&0x03) ? "Prevent" : "Allow");
+
+		return USB_STOR_TRANSPORT_GOOD;
+
+	}
+
+	if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10) {
+
+		page = short_pack(srb->cmnd[3], srb->cmnd[2]);
+		page <<= 16;
+		page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
+		pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
+
+		page <<= info->smallpageshift;
+
+		// convert page to block and page-within-block
+
+		lba = page >> info->blockshift;
+		page = page & info->blockmask;
+
+		// locate physical block corresponding to logical block
+
+		if (lba >= info->max_log_blks) {
+
+			US_DEBUGP("Error: Requested LBA %04X exceeds maximum "
+			  "block %04X\n", lba, info->max_log_blks-1);
+
+			set_sense_info (5, 0x24, 0);	/* invalid field in command */
+
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		pba = info->lba_to_pba[lba];
+
+		if (srb->cmnd[0] == WRITE_10) {
+			US_DEBUGP("WRITE_10: write block %04X (LBA %04X) page %01X"
+			        " pages %d\n",
+			        pba, lba, page, pages);
+
+			return sddr55_write_data(us, lba, page, pages, ptr, srb->use_sg);
+		} else {
+			US_DEBUGP("READ_10: read block %04X (LBA %04X) page %01X"
+			        " pages %d\n",
+			        pba, lba, page, pages);
+
+			return sddr55_read_data(us, lba, page, pages, ptr, srb->use_sg);
+		}
+	}
+
+
+	if (srb->cmnd[0] == TEST_UNIT_READY) {
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == START_STOP) {
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	set_sense_info (5, 0x20, 0);	/* illegal command */
+
+	return USB_STOR_TRANSPORT_FAILED; // FIXME: sense buffer?
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/storage/sddr55.h linux-2.4.20/drivers/usb/storage/sddr55.h
--- linux-2.4.19/drivers/usb/storage/sddr55.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/storage/sddr55.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,34 @@
+/* Driver for SanDisk SDDR-55 SmartMedia reader
+ * Header File
+ *
+ * $Id:$
+ *
+ * Current development and maintenance by:
+ *   (c) 2002 Simon Munton
+ *
+ * See sddr55.c for more explanation
+ *
+ * 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, 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _USB_SHUTTLE_EUSB_SDDR55_H
+#define _USB_SHUTTLE_EUSB_SDDR55_H
+
+/* Sandisk SDDR-55 stuff */
+
+extern int sddr55_transport(Scsi_Cmnd *srb, struct us_data *us);
+extern int sddr55_reset(struct us_data *us);
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/storage/transport.c linux-2.4.20/drivers/usb/storage/transport.c
--- linux-2.4.19/drivers/usb/storage/transport.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/storage/transport.c	2002-10-29 11:18:38.000000000 +0000
@@ -346,7 +346,7 @@
 /* This is the completion handler which will wake us up when an URB
  * completes.
  */
-static void usb_stor_blocking_completion(urb_t *urb)
+static void usb_stor_blocking_completion(struct urb *urb)
 {
 	struct completion *urb_done_ptr = (struct completion *)urb->context;
 
@@ -360,24 +360,23 @@
 			 u8 request, u8 requesttype, u16 value, u16 index, 
 			 void *data, u16 size)
 {
-	struct completion urb_done;
 	int status;
-	devrequest *dr;
+	struct usb_ctrlrequest *dr;
 
 	/* allocate the device request structure */
-	dr = kmalloc(sizeof(devrequest), GFP_NOIO);
+	dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
 	if (!dr)
 		return -ENOMEM;
 
 	/* fill in the structure */
-	dr->requesttype = requesttype;
-	dr->request = request;
-	dr->value = cpu_to_le16(value);
-	dr->index = cpu_to_le16(index);
-	dr->length = cpu_to_le16(size);
+	dr->bRequestType = requesttype;
+	dr->bRequest = request;
+	dr->wValue = cpu_to_le16(value);
+	dr->wIndex = cpu_to_le16(index);
+	dr->wLength = cpu_to_le16(size);
 
 	/* set up data structures for the wakeup system */
-	init_completion(&urb_done);
+	init_completion(&us->current_done);
 
 	/* lock the URB */
 	down(&(us->current_urb_sem));
@@ -385,7 +384,7 @@
 	/* fill the URB */
 	FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe, 
 			 (unsigned char*) dr, data, size, 
-			 usb_stor_blocking_completion, &urb_done);
+			 usb_stor_blocking_completion, &us->current_done);
 	us->current_urb->actual_length = 0;
 	us->current_urb->error_count = 0;
 	us->current_urb->transfer_flags = USB_ASYNC_UNLINK;
@@ -401,7 +400,7 @@
 
 	/* wait for the completion of the URB */
 	up(&(us->current_urb_sem));
-	wait_for_completion(&urb_done);
+	wait_for_completion(&us->current_done);
 	down(&(us->current_urb_sem));
 
 	/* return the actual length of the data transferred if no error*/
@@ -421,18 +420,17 @@
 int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
 		      unsigned int len, unsigned int *act_len)
 {
-	struct completion urb_done;
 	int status;
 
 	/* set up data structures for the wakeup system */
-	init_completion(&urb_done);
+	init_completion(&us->current_done);
 
 	/* lock the URB */
 	down(&(us->current_urb_sem));
 
 	/* fill the URB */
 	FILL_BULK_URB(us->current_urb, us->pusb_dev, pipe, data, len,
-		      usb_stor_blocking_completion, &urb_done);
+		      usb_stor_blocking_completion, &us->current_done);
 	us->current_urb->actual_length = 0;
 	us->current_urb->error_count = 0;
 	us->current_urb->transfer_flags = USB_ASYNC_UNLINK;
@@ -447,7 +445,7 @@
 
 	/* wait for the completion of the URB */
 	up(&(us->current_urb_sem));
-	wait_for_completion(&urb_done);
+	wait_for_completion(&us->current_done);
 	down(&(us->current_urb_sem));
 
 	/* return the actual length of the data transferred */
@@ -1040,10 +1038,15 @@
 /* Determine what the maximum LUN supported is */
 int usb_stor_Bulk_max_lun(struct us_data *us)
 {
-	unsigned char data;
+	unsigned char *data;
 	int result;
 	int pipe;
 
+	data = kmalloc(sizeof *data, GFP_KERNEL);
+	if (!data) {
+		return 0;
+	}
+
 	/* issue the command -- use usb_control_msg() because
 	 *  the state machine is not yet alive */
 	pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
@@ -1051,14 +1054,19 @@
 				 US_BULK_GET_MAX_LUN, 
 				 USB_DIR_IN | USB_TYPE_CLASS | 
 				 USB_RECIP_INTERFACE,
-				 0, us->ifnum, &data, sizeof(data), HZ);
+				 0, us->ifnum, data, sizeof(data), HZ);
 
 	US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", 
-		  result, data);
+		  result, *data);
 
 	/* if we have a successful request, return the result */
-	if (result == 1)
-		return data;
+	if (result == 1) {
+		result = *data;
+		kfree(data);
+		return result;
+	} else {
+		kfree(data);
+	}
 
 	/* if we get a STALL, clear the stall */
 	if (result == -EPIPE) {
@@ -1077,41 +1085,54 @@
 
 int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
 {
-	struct bulk_cb_wrap bcb;
-	struct bulk_cs_wrap bcs;
+	struct bulk_cb_wrap *bcb;
+	struct bulk_cs_wrap *bcs;
 	int result;
 	int pipe;
 	int partial;
+	int ret = USB_STOR_TRANSPORT_ERROR;
+
+	bcb = kmalloc(sizeof *bcb, in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
+	if (!bcb) {
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+	bcs = kmalloc(sizeof *bcs, in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
+	if (!bcs) {
+		kfree(bcb);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
 
 	/* set up the command wrapper */
-	bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
-	bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb));
-	bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
-	bcb.Tag = srb->serial_number;
-	bcb.Lun = srb->cmnd[1] >> 5;
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb));
+	bcb->Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
+	bcb->Tag = srb->serial_number;
+	bcb->Lun = srb->cmnd[1] >> 5;
 	if (us->flags & US_FL_SCM_MULT_TARG)
-		bcb.Lun |= srb->target << 4;
-	bcb.Length = srb->cmd_len;
+		bcb->Lun |= srb->target << 4;
+	bcb->Length = srb->cmd_len;
 
 	/* construct the pipe handle */
 	pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
 
 	/* copy the command payload */
-	memset(bcb.CDB, 0, sizeof(bcb.CDB));
-	memcpy(bcb.CDB, srb->cmnd, bcb.Length);
+	memset(bcb->CDB, 0, sizeof(bcb->CDB));
+	memcpy(bcb->CDB, srb->cmnd, bcb->Length);
 
 	/* send it to out endpoint */
 	US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n",
-		  le32_to_cpu(bcb.Signature), bcb.Tag,
-		  (bcb.Lun >> 4), (bcb.Lun & 0x0F), 
-		  bcb.DataTransferLength, bcb.Flags, bcb.Length);
-	result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, 
+		  le32_to_cpu(bcb->Signature), bcb->Tag,
+		  (bcb->Lun >> 4), (bcb->Lun & 0x0F), 
+		  bcb->DataTransferLength, bcb->Flags, bcb->Length);
+	result = usb_stor_bulk_msg(us, bcb, pipe, US_BULK_CB_WRAP_LEN, 
 				   &partial);
 	US_DEBUGP("Bulk command transfer result=%d\n", result);
 
 	/* if the command was aborted, indicate that */
-	if (result == -ENOENT)
-		return USB_STOR_TRANSPORT_ABORTED;
+	if (result == -ENOENT) {
+		ret = USB_STOR_TRANSPORT_ABORTED;
+		goto out;
+	}
 
 	/* if we stall, we need to clear it before we go on */
 	if (result == -EPIPE) {
@@ -1119,25 +1140,30 @@
 		result = usb_stor_clear_halt(us, pipe);
 
 		/* if the command was aborted, indicate that */
-		if (result == -ENOENT)
-			return USB_STOR_TRANSPORT_ABORTED;
+		if (result == -ENOENT) {
+			ret = USB_STOR_TRANSPORT_ABORTED;
+			goto out;
+		}
 		result = -EPIPE;
 	} else if (result) {
 		/* unknown error -- we've got a problem */
-		return USB_STOR_TRANSPORT_ERROR;
+		ret = USB_STOR_TRANSPORT_ERROR;
+		goto out;
 	}
 
 	/* if the command transfered well, then we go to the data stage */
 	if (result == 0) {
 		/* send/receive data payload, if there is any */
-		if (bcb.DataTransferLength) {
+		if (bcb->DataTransferLength) {
 			usb_stor_transfer(srb, us);
 			result = srb->result;
 			US_DEBUGP("Bulk data transfer result 0x%x\n", result);
 
 			/* if it was aborted, we need to indicate that */
-			if (result == US_BULK_TRANSFER_ABORTED)
-				return USB_STOR_TRANSPORT_ABORTED;
+			if (result == US_BULK_TRANSFER_ABORTED) {
+				ret = USB_STOR_TRANSPORT_ABORTED;
+				goto out;
+			}
 		}
 	}
 
@@ -1150,12 +1176,14 @@
 
 	/* get CSW for device status */
 	US_DEBUGP("Attempting to get CSW...\n");
-	result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, 
+	result = usb_stor_bulk_msg(us, bcs, pipe, US_BULK_CS_WRAP_LEN, 
 				   &partial);
 
 	/* if the command was aborted, indicate that */
-	if (result == -ENOENT)
-		return USB_STOR_TRANSPORT_ABORTED;
+	if (result == -ENOENT) {
+		ret = USB_STOR_TRANSPORT_ABORTED;
+		goto out;
+	}
 
 	/* did the attempt to read the CSW fail? */
 	if (result == -EPIPE) {
@@ -1163,17 +1191,21 @@
 		result = usb_stor_clear_halt(us, pipe);
 
 		/* if the command was aborted, indicate that */
-		if (result == -ENOENT)
-			return USB_STOR_TRANSPORT_ABORTED;
+		if (result == -ENOENT) {
+			ret = USB_STOR_TRANSPORT_ABORTED;
+			goto out;
+		}
 
 		/* get the status again */
 		US_DEBUGP("Attempting to get CSW (2nd try)...\n");
-		result = usb_stor_bulk_msg(us, &bcs, pipe,
+		result = usb_stor_bulk_msg(us, bcs, pipe,
 					   US_BULK_CS_WRAP_LEN, &partial);
 
 		/* if the command was aborted, indicate that */
-		if (result == -ENOENT)
-			return USB_STOR_TRANSPORT_ABORTED;
+		if (result == -ENOENT) {
+			ret = USB_STOR_TRANSPORT_ABORTED;
+			goto out;
+		}
 
 		/* if it fails again, we need a reset and return an error*/
 		if (result == -EPIPE) {
@@ -1181,48 +1213,60 @@
 			result = usb_stor_clear_halt(us, pipe);
 
 			/* if the command was aborted, indicate that */
-			if (result == -ENOENT)
-				return USB_STOR_TRANSPORT_ABORTED;
-			return USB_STOR_TRANSPORT_ERROR;
+			if (result == -ENOENT) {
+				ret = USB_STOR_TRANSPORT_ABORTED;
+			} else {
+				ret = USB_STOR_TRANSPORT_ERROR;
+			}
+			goto out;
 		}
 	}
 
 	/* if we still have a failure at this point, we're in trouble */
 	US_DEBUGP("Bulk status result = %d\n", result);
 	if (result) {
-		return USB_STOR_TRANSPORT_ERROR;
+		ret = USB_STOR_TRANSPORT_ERROR;
+		goto out;
 	}
 
 	/* check bulk status */
 	US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n",
-		  le32_to_cpu(bcs.Signature), bcs.Tag, 
-		  bcs.Residue, bcs.Status);
-	if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || 
-	    bcs.Tag != bcb.Tag || 
-	    bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
+		  le32_to_cpu(bcs->Signature), bcs->Tag, 
+		  bcs->Residue, bcs->Status);
+	if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) || 
+	    bcs->Tag != bcb->Tag || 
+	    bcs->Status > US_BULK_STAT_PHASE || partial != 13) {
 		US_DEBUGP("Bulk logical error\n");
-		return USB_STOR_TRANSPORT_ERROR;
+		ret = USB_STOR_TRANSPORT_ERROR;
+		goto out;
 	}
 
 	/* based on the status code, we report good or bad */
-	switch (bcs.Status) {
+	switch (bcs->Status) {
 		case US_BULK_STAT_OK:
 			/* command good -- note that data could be short */
-			return USB_STOR_TRANSPORT_GOOD;
+			ret = USB_STOR_TRANSPORT_GOOD;
+			goto out;
 
 		case US_BULK_STAT_FAIL:
 			/* command failed */
-			return USB_STOR_TRANSPORT_FAILED;
+			ret = USB_STOR_TRANSPORT_FAILED;
+			goto out;
 
 		case US_BULK_STAT_PHASE:
 			/* phase error -- note that a transport reset will be
 			 * invoked by the invoke_transport() function
 			 */
-			return USB_STOR_TRANSPORT_ERROR;
+			ret = USB_STOR_TRANSPORT_ERROR;
+			goto out;
 	}
 
 	/* we should never get here, but if we do, we're in trouble */
-	return USB_STOR_TRANSPORT_ERROR;
+
+ out:
+	kfree(bcb);
+	kfree(bcs);
+	return ret;
 }
 
 /***********************************************************************
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/storage/transport.h linux-2.4.20/drivers/usb/storage/transport.h
--- linux-2.4.19/drivers/usb/storage/transport.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/storage/transport.h	2002-10-29 11:18:39.000000000 +0000
@@ -58,6 +58,9 @@
 #define US_PR_EUSB_SDDR09	0x81	/* SCM-SCSI bridge for
 						SDDR-09 */
 #endif
+#ifdef CONFIG_USB_STORAGE_SDDR55
+#define US_PR_SDDR55	0x82		/* SDDR-55 (made up) */
+#endif
 #define US_PR_DPCM_USB  0xf0		/* Combination CB/SDDR09 */
 
 #ifdef CONFIG_USB_STORAGE_FREECOM
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/storage/unusual_devs.h linux-2.4.20/drivers/usb/storage/unusual_devs.h
--- linux-2.4.19/drivers/usb/storage/unusual_devs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/storage/unusual_devs.h	2002-10-29 11:18:34.000000000 +0000
@@ -65,6 +65,17 @@
 		US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0), 
 #endif
 
+/* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+ * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
+ * always fails and confuses drive; without US_FL_START_STOP, drive accesses
+ * (read or write) all fail.
+ */
+UNUSUAL_DEV(  0x0411, 0x001c, 0x0113, 0x0113,
+		"Buffalo",
+		"DUB-P40G HDD",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY | US_FL_START_STOP),
+
 #ifdef CONFIG_USB_STORAGE_DPCM
 UNUSUAL_DEV(  0x0436, 0x0005, 0x0100, 0x0100,
 		"Microtech",
@@ -292,6 +303,13 @@
 		US_FL_MODE_XLATE ),
 #endif
 
+/* Reported by Blake Matheny <bmatheny@purdue.edu> */
+UNUSUAL_DEV(  0x05dc, 0xb002, 0x0000, 0x0113,
+		"Lexar",
+		"USB CF Reader",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY ),
+
 /* Reported by Carlos Villegas <cav@uniscope.co.jp>
  * This device needs an INQUIRY of exactly 36-bytes to function.
  * That is the only reason this entry is needed.
@@ -306,8 +324,10 @@
  * Like the SIIG unit above, this unit needs an INQUIRY to ask for exactly
  * 36 bytes of data.  No more, no less. That is the only reason this entry
  * is needed.
- */
-UNUSUAL_DEV(  0x05e3, 0x0702, 0x0000, 0xffff,
+ *
+ * ST818 slim drives (rev 0.02) don't need special care.
+*/
+UNUSUAL_DEV(  0x05e3, 0x0702, 0x0000, 0x0001,
 		"EagleTec",
 		"External Hard Disk",
 		US_SC_SCSI, US_PR_BULK, NULL,
@@ -342,6 +362,12 @@
                 US_SC_SCSI, US_PR_BULK, NULL,
                 US_FL_START_STOP ),
 
+UNUSUAL_DEV( 0x0686, 0x400b, 0x0001, 0x0001, 
+		"Minolta", 
+		"Dimage 7i", 
+		US_SC_SCSI, US_PR_BULK, NULL, 
+		US_FL_START_STOP ),
+
 UNUSUAL_DEV(  0x0693, 0x0002, 0x0100, 0x0100, 
 		"Hagiwara",
 		"FlashGate SmartMedia",
@@ -488,17 +514,22 @@
                 0 ),
 #endif
 
-/* Submitted by Brian Hall <brihall@bigfoot.com>
+/* Submitted by Brian Hall <brihall@pcisys.net>
  * Needed for START_STOP flag */
 UNUSUAL_DEV(  0x0c76, 0x0003, 0x0100, 0x0100,
 		"JMTek",
 		"USBDrive",
 		US_SC_SCSI, US_PR_BULK, NULL,
 		US_FL_START_STOP ),
+UNUSUAL_DEV(  0x0c76, 0x0005, 0x0100, 0x0100,
+		"JMTek",
+		"USBDrive",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_START_STOP ),
 
 /* Reported by Dan Pilone <pilone@slac.com>
  * The device needs the flags only.
- * Also reported by Brian Hall <brihall@bigfoot.com>, again for flags.
+ * Also reported by Brian Hall <brihall@pcisys.net>, again for flags.
  * I also suspect this device may have a broken serial number.
  */
 UNUSUAL_DEV(  0x1065, 0x2136, 0x0000, 0x9999,
@@ -506,3 +537,11 @@
 		"EasyDisk Portable Device",
 		US_SC_SCSI, US_PR_BULK, NULL,
 		US_FL_MODE_XLATE | US_FL_START_STOP),
+
+#ifdef CONFIG_USB_STORAGE_SDDR55
+UNUSUAL_DEV(  0x55aa, 0xa103, 0x0000, 0x9999, 
+		"Sandisk",
+		"ImageMate SDDR55",
+		US_SC_SCSI, US_PR_SDDR55, NULL,
+		US_FL_SINGLE_LUN),
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/storage/usb.c linux-2.4.20/drivers/usb/storage/usb.c
--- linux-2.4.19/drivers/usb/storage/usb.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/storage/usb.c	2002-10-29 11:18:35.000000000 +0000
@@ -60,6 +60,9 @@
 #ifdef CONFIG_USB_STORAGE_SDDR09
 #include "sddr09.h"
 #endif
+#ifdef CONFIG_USB_STORAGE_SDDR55
+#include "sddr55.h"
+#endif
 #ifdef CONFIG_USB_STORAGE_DPCM
 #include "dpcm.h"
 #endif
@@ -864,6 +867,15 @@
 			break;
 #endif
 
+#ifdef CONFIG_USB_STORAGE_SDDR55
+		case US_PR_SDDR55:
+			ss->transport_name = "SDDR55";
+			ss->transport = sddr55_transport;
+			ss->transport_reset = sddr55_reset;
+			ss->max_lun = 0;
+			break;
+#endif
+
 #ifdef CONFIG_USB_STORAGE_DPCM
 		case US_PR_DPCM_USB:
 			ss->transport_name = "Control/Bulk-EUSB/SDDR09";
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/storage/usb.h linux-2.4.20/drivers/usb/storage/usb.h
--- linux-2.4.19/drivers/usb/storage/usb.h	2001-11-22 19:49:34.000000000 +0000
+++ linux-2.4.20/drivers/usb/storage/usb.h	2002-10-29 11:18:49.000000000 +0000
@@ -166,6 +166,7 @@
 	/* control and bulk communications data */
 	struct semaphore	current_urb_sem; /* to protect irq_urb	 */
 	struct urb		*current_urb;	 /* non-int USB requests */
+	struct completion	current_done;	 /* the done flag        */
 
 	/* the semaphore for sleeping the control thread */
 	struct semaphore	sema;		 /* to sleep thread on   */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/stv680.c linux-2.4.20/drivers/usb/stv680.c
--- linux-2.4.19/drivers/usb/stv680.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/stv680.c	2002-10-29 11:18:34.000000000 +0000
@@ -86,7 +86,7 @@
 #define PDEBUG(level, fmt, args...) \
 	do { \
 	if (debug >= level)	\
-		info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args);	\
+		info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args);	\
 	} while (0)
 
 
@@ -111,67 +111,27 @@
  *
  * Memory management
  *
- * This is a shameless copy from the USB-cpia driver (linux kernel
- * version 2.3.29 or so, I have no idea what this code actually does ;).
- * Actually it seems to be a copy of a shameless copy of the bttv-driver.
- * Or that is a copy of a shameless copy of ... (To the powers: is there
- * no generic kernel-function to do this sort of stuff?)
- *
- * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
- * there will be one, but apparentely not yet -jerdfelt
- *
- * So I copied it again for the ov511 driver -claudio
- *
- * Same for the se401 driver -Jeroen
- *
- * And the STV0680 driver - Kevin
  ********************************************************************/
 
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline unsigned long uvirt_to_kva (pgd_t * pgd, unsigned long adr)
-{
-	unsigned long ret = 0UL;
-	pmd_t *pmd;
-	pte_t *ptep, pte;
-
-	if (!pgd_none (*pgd)) {
-		pmd = pmd_offset (pgd, adr);
-		if (!pmd_none (*pmd)) {
-			ptep = pte_offset (pmd, adr);
-			pte = *ptep;
-			if (pte_present (pte)) {
-				ret = (unsigned long) page_address (pte_page (pte));
-				ret |= (adr & (PAGE_SIZE - 1));
-			}
-		}
-	}
-	return ret;
-}
-
-/* Here we want the physical address of the memory. This is used when 
- * initializing the contents of the area and marking the pages as reserved.
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the area.
  */
 static inline unsigned long kvirt_to_pa (unsigned long adr)
 {
-	unsigned long va, kva, ret;
+	unsigned long kva, ret;
 
-	va = VMALLOC_VMADDR (adr);
-	kva = uvirt_to_kva (pgd_offset_k (va), va);
-	ret = __pa (kva);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+	ret = __pa(kva);
 	return ret;
 }
 
 static void *rvmalloc (unsigned long size)
 {
 	void *mem;
-	unsigned long adr, page;
-
-	/* Round it off to PAGE_SIZE */
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
+	unsigned long adr;
 
+	size = PAGE_ALIGN(size);
 	mem = vmalloc_32 (size);
 	if (!mem)
 		return NULL;
@@ -179,36 +139,25 @@
 	memset (mem, 0, size);	/* Clear the ram out, no junk to the user */
 	adr = (unsigned long) mem;
 	while (size > 0) {
-		page = kvirt_to_pa (adr);
-		mem_map_reserve (virt_to_page (__va (page)));
+		mem_map_reserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 	return mem;
 }
 
 static void rvfree (void *mem, unsigned long size)
 {
-	unsigned long adr, page;
+	unsigned long adr;
 
 	if (!mem)
 		return;
 
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
-
 	adr = (unsigned long) mem;
-	while (size > 0) {
-		page = kvirt_to_pa (adr);
-		mem_map_unreserve (virt_to_page (__va (page)));
+	while ((long) size > 0) {
+		mem_map_unreserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 	vfree (mem);
 }
@@ -772,7 +721,7 @@
 
 static int stv680_start_stream (struct usb_stv *stv680)
 {
-	urb_t *urb;
+	struct urb *urb;
 	int err = 0, i;
 
 	stv680->streaming = 1;
@@ -1123,6 +1072,9 @@
 			errors++;
 		}
 		wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY));
+		
+		if (stv680->removed)
+			return -ENODEV;
 
 		if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
 			stv680->nullpackets = 0;
@@ -1191,10 +1143,10 @@
 
 	for (i = 0; i < STV680_NUMFRAMES; i++)
 		stv680->frame[i].grabstate = FRAME_UNUSED;
-	if (stv680->streaming)
+	if (stv680->streaming && !stv680->removed)
 		stv680_stop_stream (stv680);
 
-	if ((i = stv_stop_video (stv680)) < 0)
+	if ((!stv680->removed) && (i = stv_stop_video (stv680)) < 0)
 		PDEBUG (1, "STV(e): stop_video failed in stv_close");
 
 	rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES);
@@ -1220,6 +1172,9 @@
 
 	if (!stv680->udev)
 		return -EIO;
+		
+	if (stv680->removed)
+		return -ENODEV;
 
 	switch (cmd) {
 	case VIDIOCGCAP:{
@@ -1545,7 +1500,7 @@
 	initialize:	stv_init_done,
 };
 
-static void *__devinit stv680_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
+static void *stv680_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
 {
 	struct usb_interface_descriptor *interface;
 	struct usb_stv *stv680;
@@ -1629,6 +1584,7 @@
 static void stv680_disconnect (struct usb_device *dev, void *ptr)
 {
 	struct usb_stv *stv680 = (struct usb_stv *) ptr;
+	int i;
 
 	lock_kernel ();
 	/* We don't want people trying to open up the device */
@@ -1637,6 +1593,9 @@
 		usb_stv680_remove_disconnected (stv680);
 	} else {
 		stv680->removed = 1;
+		for( i = 0; i < STV680_NUMSBUF; i++)
+			usb_unlink_urb(stv680->urb[i]);
+		wake_up_interruptible (&stv680->wq);
 	}
 	unlock_kernel ();
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/stv680.h linux-2.4.20/drivers/usb/stv680.h
--- linux-2.4.19/drivers/usb/stv680.h	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.20/drivers/usb/stv680.h	2002-10-29 11:18:34.000000000 +0000
@@ -45,7 +45,7 @@
 /* fmt 4 */
 #define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
 
-static __devinitdata struct usb_device_id device_table[] = {
+static struct usb_device_id device_table[] = {
 	{USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
 	{}
 };
@@ -118,7 +118,7 @@
 	int removed;		/* device disconnected */
 	int streaming;		/* Are we streaming video? */
 	char *fbuf;		/* Videodev buffer area */
-	urb_t *urb[STV680_NUMSBUF];	/* # of queued bulk transfers */
+	struct urb *urb[STV680_NUMSBUF];	/* # of queued bulk transfers */
 	int curframe;		/* Current receiving frame */
 	struct stv680_frame frame[STV680_NUMFRAMES];	/* # frames supported by v4l part */
 	int readcount;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/tiglusb.c linux-2.4.20/drivers/usb/tiglusb.c
--- linux-2.4.19/drivers/usb/tiglusb.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/tiglusb.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,514 @@
+/* Hey EMACS -*- linux-c -*-
+ *
+ * tiglusb -- Texas Instruments' USB GraphLink (aka SilverLink) driver.
+ * Target: Texas Instruments graphing calculators (http://lpg.ticalc.org).
+ *
+ * Copyright (C) 2001-2002:
+ *   Romain Lievin <roms@lpg.ticalc.org>
+ *   Julien BLACHE <jb@technologeek.org>
+ * under the terms of the GNU General Public License.
+ *
+ * Based on dabusb.c, printer.c & scanner.c
+ *
+ * Please see the file: linux/Documentation/usb/SilverLink.txt
+ * and the website at:  http://lpg.ticalc.org/prj_usb/
+ * for more info.
+ *
+ * History :
+ *  16/07/2002 : v1.04 -- Julien BLACHE <jb@jblache.org>
+ *    + removed useless usblp_cleanup()
+ *    + removed {un,}lock_kernel() as suggested on lkml
+ *    + inlined clear_pipes() (used once)
+ *    + inlined clear_device() (small, used twice)
+ *    + removed tiglusb_find_struct() (used once, simple code)
+ *    + replaced down() with down_interruptible() wherever possible
+ *    + fixed double unregistering wrt devfs, causing devfs
+ *      to force an oops when the device is deconnected
+ *    + removed unused fields from struct tiglusb_t
+ */
+
+#include <linux/module.h>
+#include <linux/socket.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+#include <linux/usb.h>
+#include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
+
+#include <linux/ticable.h>
+#include "tiglusb.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "1.04"
+#define DRIVER_AUTHOR  "Romain Lievin <roms@lpg.ticalc.org> & Julien Blache <jb@jblache.org>"
+#define DRIVER_DESC    "TI-GRAPH LINK USB (aka SilverLink) driver"
+#define DRIVER_LICENSE "GPL"
+
+/* ----- global variables --------------------------------------------- */
+
+static tiglusb_t tiglusb[MAXTIGL];
+static int timeout = TIMAXTIME;	/* timeout in tenth of seconds     */
+
+static devfs_handle_t devfs_handle;
+
+/*---------- misc functions ------------------------------------------- */
+
+/*
+ * Re-initialize device
+ */
+static inline int
+clear_device (struct usb_device *dev)
+{
+	if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
+		err ("clear_device failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* 
+ * Clear input & output pipes (endpoints)
+ */
+static inline int
+clear_pipes (struct usb_device *dev)
+{
+	unsigned int pipe;
+
+	pipe = usb_sndbulkpipe (dev, 1);
+	if (usb_clear_halt (dev, usb_pipeendpoint (pipe))) {
+		err ("clear_pipe (r), request failed");
+		return -1;
+	}
+
+	pipe = usb_sndbulkpipe (dev, 2);
+	if (usb_clear_halt (dev, usb_pipeendpoint (pipe))) {
+		err ("clear_pipe (w), request failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* ----- file operations functions--------------------------------------- */
+
+static int
+tiglusb_open (struct inode *inode, struct file *filp)
+{
+	int devnum = minor (inode->i_rdev);
+	ptiglusb_t s;
+
+	if (devnum < TIUSB_MINOR || devnum >= (TIUSB_MINOR + MAXTIGL))
+		return -EIO;
+
+	s = &tiglusb[devnum - TIUSB_MINOR];
+
+	if (down_interruptible (&s->mutex)) {
+		return -ERESTARTSYS;
+	}
+
+	while (!s->dev || s->opened) {
+		up (&s->mutex);
+
+		if (filp->f_flags & O_NONBLOCK) {
+			return -EBUSY;
+		}
+
+		schedule_timeout (HZ / 2);
+
+		if (signal_pending (current)) {
+			return -EAGAIN;
+		}
+
+		if (down_interruptible (&s->mutex)) {
+			return -ERESTARTSYS;
+		}
+	}
+
+	s->opened = 1;
+	up (&s->mutex);
+
+	filp->f_pos = 0;
+	filp->private_data = s;
+
+	return 0;
+}
+
+static int
+tiglusb_release (struct inode *inode, struct file *filp)
+{
+	ptiglusb_t s = (ptiglusb_t) filp->private_data;
+
+	if (down_interruptible (&s->mutex)) {
+		return -ERESTARTSYS;
+	}
+
+	s->state = _stopped;
+	up (&s->mutex);
+
+	if (!s->remove_pending)
+		clear_device (s->dev);
+	else
+		wake_up (&s->remove_ok);
+
+	s->opened = 0;
+
+	return 0;
+}
+
+static ssize_t
+tiglusb_read (struct file *filp, char *buf, size_t count, loff_t * f_pos)
+{
+	ptiglusb_t s = (ptiglusb_t) filp->private_data;
+	ssize_t ret = 0;
+	int bytes_to_read = 0;
+	int bytes_read = 0;
+	int result = 0;
+	char buffer[BULK_RCV_MAX];
+	unsigned int pipe;
+
+	if (*f_pos)
+		return -ESPIPE;
+
+	if (s->remove_pending)
+		return -EIO;
+
+	if (!s->dev)
+		return -EIO;
+
+	bytes_to_read = (count >= BULK_RCV_MAX) ? BULK_RCV_MAX : count;
+
+	pipe = usb_rcvbulkpipe (s->dev, 1);
+	result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_read,
+			       &bytes_read, HZ / (timeout / 10));
+	if (result == -ETIMEDOUT) {	/* NAK */
+		ret = result;
+		if (!bytes_read) {
+			dbg ("quirk !");
+		}
+		warn ("tiglusb_read, NAK received.");
+		goto out;
+	} else if (result == -EPIPE) {	/* STALL -- shouldn't happen */
+		warn ("clear_halt request to remove STALL condition.");
+		if (usb_clear_halt (s->dev, usb_pipeendpoint (pipe)))
+			err ("clear_halt, request failed");
+		clear_device (s->dev);
+		ret = result;
+		goto out;
+	} else if (result < 0) {	/* We should not get any I/O errors */
+		err ("funky result: %d. Please notify maintainer.", result);
+		ret = -EIO;
+		goto out;
+	}
+
+	if (copy_to_user (buf, buffer, bytes_read)) {
+		ret = -EFAULT;
+	}
+
+      out:
+	return ret ? ret : bytes_read;
+}
+
+static ssize_t
+tiglusb_write (struct file *filp, const char *buf, size_t count, loff_t * f_pos)
+{
+	ptiglusb_t s = (ptiglusb_t) filp->private_data;
+	ssize_t ret = 0;
+	int bytes_to_write = 0;
+	int bytes_written = 0;
+	int result = 0;
+	char buffer[BULK_SND_MAX];
+	unsigned int pipe;
+
+	if (*f_pos)
+		return -ESPIPE;
+
+	if (s->remove_pending)
+		return -EIO;
+
+	if (!s->dev)
+		return -EIO;
+
+	bytes_to_write = (count >= BULK_SND_MAX) ? BULK_SND_MAX : count;
+	if (copy_from_user (buffer, buf, bytes_to_write)) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	pipe = usb_sndbulkpipe (s->dev, 2);
+	result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_write,
+			       &bytes_written, HZ / (timeout / 10));
+
+	if (result == -ETIMEDOUT) {	/* NAK */
+		warn ("tiglusb_write, NAK received.");
+		ret = result;
+		goto out;
+	} else if (result == -EPIPE) {	/* STALL -- shouldn't happen */
+		warn ("clear_halt request to remove STALL condition.");
+		if (usb_clear_halt (s->dev, usb_pipeendpoint (pipe)))
+			err ("clear_halt, request failed");
+		clear_device (s->dev);
+		ret = result;
+		goto out;
+	} else if (result < 0) {	/* We should not get any I/O errors */
+		warn ("funky result: %d. Please notify maintainer.", result);
+		ret = -EIO;
+		goto out;
+	}
+
+	if (bytes_written != bytes_to_write) {
+		ret = -EIO;
+	}
+
+      out:
+	return ret ? ret : bytes_written;
+}
+
+static int
+tiglusb_ioctl (struct inode *inode, struct file *filp,
+	       unsigned int cmd, unsigned long arg)
+{
+	ptiglusb_t s = (ptiglusb_t) filp->private_data;
+	int ret = 0;
+
+	if (s->remove_pending)
+		return -EIO;
+
+	if (down_interruptible (&s->mutex)) {
+		return -ERESTARTSYS;
+	}
+
+	if (!s->dev) {
+		up (&s->mutex);
+		return -EIO;
+	}
+
+	switch (cmd) {
+	case IOCTL_TIUSB_TIMEOUT:
+		timeout = arg;	// timeout value in tenth of seconds
+		break;
+	case IOCTL_TIUSB_RESET_DEVICE:
+		dbg ("IOCTL_TIGLUSB_RESET_DEVICE");
+		if (clear_device (s->dev))
+			ret = -EIO;
+		break;
+	case IOCTL_TIUSB_RESET_PIPES:
+		dbg ("IOCTL_TIGLUSB_RESET_PIPES");
+		if (clear_pipes (s->dev))
+			ret = -EIO;
+		break;
+	default:
+		ret = -ENOTTY;
+		break;
+	}
+
+	up (&s->mutex);
+
+	return ret;
+}
+
+/* ----- kernel module registering ------------------------------------ */
+
+static struct file_operations tiglusb_fops = {
+	.llseek =	no_llseek,
+	.read =		tiglusb_read,
+	.write =	tiglusb_write,
+	.ioctl =	tiglusb_ioctl,
+	.open =		tiglusb_open,
+	.release =	tiglusb_release,
+};
+
+/* --- initialisation code ------------------------------------- */
+
+static void *
+tiglusb_probe (struct usb_device *dev, unsigned int ifnum,
+	       const struct usb_device_id *id)
+{
+	int minor = -1;
+	int i;
+	ptiglusb_t s;
+	char name[8];
+
+	dbg ("probing vendor id 0x%x, device id 0x%x ifnum:%d",
+	     dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
+
+	/*
+	 * We don't handle multiple configurations. As of version 0x0103 of
+	 * the TIGL hardware, there's only 1 configuration.
+	 */
+
+	if (dev->descriptor.bNumConfigurations != 1)
+		return NULL;
+
+	if ((dev->descriptor.idProduct != 0xe001)
+	    && (dev->descriptor.idVendor != 0x451))
+		return NULL;
+
+	if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
+		err ("tiglusb_probe: set_configuration failed");
+		return NULL;
+	}
+
+	/*
+	 * Find a tiglusb struct
+	 */
+	for (i = 0; i < MAXTIGL; i++) {
+		ptiglusb_t s = &tiglusb[i];
+		if (!s->dev) {
+			minor = i;
+			break;
+		}
+	}
+
+	if (minor == -1)
+		return NULL;
+
+	s = &tiglusb[minor];
+
+	down (&s->mutex);
+	s->remove_pending = 0;
+	s->dev = dev;
+	up (&s->mutex);
+	dbg ("bound to interface: %d", ifnum);
+
+	sprintf (name, "%d", s->minor);
+	dbg ("registering to devfs : major = %d, minor = %d, node = %s",
+	     TIUSB_MAJOR, (TIUSB_MINOR + s->minor), name);
+	s->devfs =
+	    devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT, TIUSB_MAJOR,
+			    TIUSB_MINOR + s->minor, S_IFCHR | S_IRUGO | S_IWUGO,
+			    &tiglusb_fops, NULL);
+
+	/* Display firmware version */
+	info ("link cable version %i.%02x",
+		dev->descriptor.bcdDevice >> 8,
+		dev->descriptor.bcdDevice & 0xff);
+
+	return s;
+}
+
+static void
+tiglusb_disconnect (struct usb_device *dev, void *drv_context)
+{
+	ptiglusb_t s = (ptiglusb_t) drv_context;
+
+	if (!s || !s->dev)
+		info ("bogus disconnect");
+
+	s->remove_pending = 1;
+	wake_up (&s->wait);
+	if (s->state == _started)
+		sleep_on (&s->remove_ok);
+	down (&s->mutex);
+	s->dev = NULL;
+	s->opened = 0;
+
+	devfs_unregister (s->devfs);
+	s->devfs = NULL;
+
+	info ("device %d removed", s->minor);
+
+	up (&s->mutex);
+}
+
+static struct usb_device_id tiglusb_ids[] = {
+	{USB_DEVICE (0x0451, 0xe001)},
+	{}
+};
+
+MODULE_DEVICE_TABLE (usb, tiglusb_ids);
+
+static struct usb_driver tiglusb_driver = {
+	.name =		"tiglusb",
+	.probe =	tiglusb_probe,
+	.disconnect =	tiglusb_disconnect,
+	.id_table =	tiglusb_ids,
+};
+
+/* --- initialisation code ------------------------------------- */
+
+#ifndef MODULE
+/*
+ * You can use 'tiusb=timeout'
+ */
+static int __init
+tiglusb_setup (char *str)
+{
+	int ints[2];
+
+	str = get_options (str, ARRAY_SIZE (ints), ints);
+
+	if (ints[0] > 0) {
+		timeout = ints[1];
+	}
+
+	return 1;
+}
+#endif
+
+static int __init
+tiglusb_init (void)
+{
+	unsigned u;
+	int result;
+
+	/* initialize struct */
+	for (u = 0; u < MAXTIGL; u++) {
+		ptiglusb_t s = &tiglusb[u];
+		memset (s, 0, sizeof (tiglusb_t));
+		init_MUTEX (&s->mutex);
+		s->dev = NULL;
+		s->minor = u;
+		s->opened = 0;
+		init_waitqueue_head (&s->wait);
+		init_waitqueue_head (&s->remove_ok);
+	}
+
+	/* register device */
+	if (devfs_register_chrdev (TIUSB_MAJOR, "tiglusb", &tiglusb_fops)) {
+		err ("unable to get major %d", TIUSB_MAJOR);
+		return -EIO;
+	}
+
+	/* Use devfs, tree: /dev/ticables/usb/[0..3] */
+	devfs_handle = devfs_mk_dir (NULL, "ticables/usb", NULL);
+
+	/* register USB module */
+	result = usb_register (&tiglusb_driver);
+	if (result < 0) {
+		devfs_unregister_chrdev (TIUSB_MAJOR, "tiglusb");
+		return -1;
+	}
+
+	info (DRIVER_DESC ", " DRIVER_VERSION);
+
+	return 0;
+}
+
+static void __exit
+tiglusb_cleanup (void)
+{
+	usb_deregister (&tiglusb_driver);
+	devfs_unregister (devfs_handle);
+	devfs_unregister_chrdev (TIUSB_MAJOR, "tiglusb");
+}
+
+/* --------------------------------------------------------------------- */
+
+__setup ("tiusb=", tiglusb_setup);
+module_init (tiglusb_init);
+module_exit (tiglusb_cleanup);
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_LICENSE (DRIVER_LICENSE);
+
+MODULE_PARM (timeout, "i");
+MODULE_PARM_DESC (timeout, "Timeout (default=1.5 seconds)");
+
+/* --------------------------------------------------------------------- */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/tiglusb.h linux-2.4.20/drivers/usb/tiglusb.h
--- linux-2.4.19/drivers/usb/tiglusb.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/tiglusb.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,48 @@
+/* Hey EMACS -*- linux-c -*-
+ *
+ * tiglusb - low level driver for SilverLink cable
+ *
+ * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org>
+ * under the terms of the GNU General Public License.
+ *
+ * Redistribution of this file is permitted under the terms of the GNU
+ * Public License (GPL)
+ */
+
+#ifndef _TIGLUSB_H
+#define _TIGLUSB_H
+
+/*
+ * Max. number of devices supported
+ */
+#define MAXTIGL		16
+
+/*
+ * Max. packetsize for IN and OUT pipes
+ */
+#define BULK_RCV_MAX	32
+#define BULK_SND_MAX	32
+
+/*
+ * The driver context...
+ */
+
+typedef enum { _stopped=0, _started } driver_state_t;
+
+typedef struct
+{
+	struct usb_device	*dev;		/* USB device handle */
+	struct semaphore	mutex;		/* locks this struct */
+
+	wait_queue_head_t	wait;		/* for timed waits */
+	wait_queue_head_t	remove_ok;
+
+	int		minor;			/* which minor dev #? */
+	devfs_handle_t	devfs;			/* devfs device */
+
+	driver_state_t	state;			/* started/stopped */
+	int		opened;			/* tru if open */
+	int	remove_pending;
+} tiglusb_t, *ptiglusb_t;
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/uhci.c linux-2.4.20/drivers/usb/uhci.c
--- linux-2.4.19/drivers/usb/uhci.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/uhci.c	2002-10-29 11:18:35.000000000 +0000
@@ -57,6 +57,8 @@
 
 #include <linux/pm.h>
 
+#include "hcd.h"
+
 /*
  * Version Information
  */
@@ -100,6 +102,11 @@
 #define IDLE_TIMEOUT	(HZ / 20)	/* 50 ms */
 #define FSBR_DELAY	(HZ / 20)	/* 50 ms */
 
+/* When we timeout an idle transfer for FSBR, we'll switch it over to */
+/* depth first traversal. We'll do it in groups of this number of TD's */
+/* to make sure it doesn't hog all of the bandwidth */
+#define DEPTH_INTERVAL	5
+
 #define MAX_URB_LOOP	2048		/* Maximum number of linked URB's */
 
 /*
@@ -115,12 +122,20 @@
 	return 0;
 }
 
+/*
+ * Technically, updating td->status here is a race, but it's not really a
+ * problem. The worst that can happen is that we set the IOC bit again
+ * generating a spurios interrupt. We could fix this by creating another
+ * QH and leaving the IOC bit always set, but then we would have to play
+ * games with the FSBR code to make sure we get the correct order in all
+ * the cases. I don't think it's worth the effort
+ */
 static inline void uhci_set_next_interrupt(struct uhci *uhci)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	set_bit(TD_CTRL_IOC_BIT, &uhci->skel_term_td->status);
+	uhci->skel_term_td->status |= TD_CTRL_IOC;
 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
@@ -129,7 +144,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	clear_bit(TD_CTRL_IOC_BIT, &uhci->skel_term_td->status);
+	uhci->skel_term_td->status &= ~TD_CTRL_IOC;
 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
@@ -474,9 +489,9 @@
 		tmp = tmp->next;
 
 		if (toggle)
-			set_bit(TD_TOKEN_TOGGLE, &td->info);
+			td->info |= TD_TOKEN_TOGGLE;
 		else
-			clear_bit(TD_TOKEN_TOGGLE, &td->info);
+			td->info &= ~TD_TOKEN_TOGGLE;
 
 		toggle ^= 1;
 	}
@@ -649,7 +664,7 @@
 
 		if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) {
 			urbp->setup_packet_dma_handle = pci_map_single(uhci->dev,
-				urb->setup_packet, sizeof(devrequest),
+				urb->setup_packet, sizeof(struct usb_ctrlrequest),
 				PCI_DMA_TODEVICE);
 			if (!urbp->setup_packet_dma_handle)
 				return NULL;
@@ -724,7 +739,7 @@
 
 	if (urbp->setup_packet_dma_handle) {
 		pci_unmap_single(uhci->dev, urbp->setup_packet_dma_handle,
-			sizeof(devrequest), PCI_DMA_TODEVICE);
+			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
 		urbp->setup_packet_dma_handle = 0;
 	}
 
@@ -857,7 +872,7 @@
 			return -ENOMEM;
 
 		/* Alternate Data0/1 (start with Data1) */
-		destination ^= 1 << TD_TOKEN_TOGGLE;
+		destination ^= TD_TOKEN_TOGGLE;
 	
 		uhci_add_td_to_urb(urb, td);
 		uhci_fill_td(td, status, destination | ((pktsze - 1) << 21),
@@ -884,7 +899,7 @@
 	else
 		destination |= USB_PID_OUT;
 
-	destination |= 1 << TD_TOKEN_TOGGLE;		/* End in Data1 */
+	destination |= TD_TOKEN_TOGGLE;		/* End in Data1 */
 
 	status &= ~TD_CTRL_SPD;
 
@@ -953,14 +968,6 @@
 
 		tmp = tmp->next;
 
-		if (urbp->fsbr_timeout && (td->status & TD_CTRL_IOC) &&
-		    !(td->status & TD_CTRL_ACTIVE)) {
-			uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
-			urbp->fsbr_timeout = 0;
-			urbp->fsbrtime = jiffies;
-			clear_bit(TD_CTRL_IOC_BIT, &td->status);
-		}
-
 		status = uhci_status_bits(td->status);
 		if (status & TD_CTRL_ACTIVE)
 			return -EINPROGRESS;
@@ -1097,7 +1104,7 @@
 	if (!td)
 		return -ENOMEM;
 
-	destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
+	destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
 	destination |= ((urb->transfer_buffer_length - 1) << 21);
 
 	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
@@ -1127,14 +1134,6 @@
 
 		tmp = tmp->next;
 
-		if (urbp->fsbr_timeout && (td->status & TD_CTRL_IOC) &&
-		    !(td->status & TD_CTRL_ACTIVE)) {
-			uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
-			urbp->fsbr_timeout = 0;
-			urbp->fsbrtime = jiffies;
-			clear_bit(TD_CTRL_IOC_BIT, &td->status);
-		}
-
 		status = uhci_status_bits(td->status);
 		if (status & TD_CTRL_ACTIVE)
 			return -EINPROGRESS;
@@ -1198,8 +1197,8 @@
 	td = list_entry(urbp->td_list.next, struct uhci_td, list);
 
 	td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
-	td->info &= ~(1 << TD_TOKEN_TOGGLE);
-	td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
+	td->info &= ~TD_TOKEN_TOGGLE;
+	td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
 	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
 
 out:
@@ -1255,7 +1254,7 @@
 		uhci_fill_td(td, status, destination |
 			(((pktsze - 1) & UHCI_NULL_DATA_SIZE) << 21) |
 			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE),
+			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
 			data);
 
 		data += pktsze;
@@ -1283,7 +1282,7 @@
 		uhci_fill_td(td, status, destination |
 			(UHCI_NULL_DATA_SIZE << 21) |
 			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE),
+			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
 			data);
 
 		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
@@ -1830,11 +1829,18 @@
 {
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	struct list_head *head, *tmp;
+	int count = 0;
 
 	uhci_dec_fsbr(uhci, urb);
 
 	urbp->fsbr_timeout = 1;
 
+	/*
+	 * Ideally we would want to fix qh->element as well, but it's
+	 * read/write by the HC, so that can introduce a race. It's not
+	 * really worth the hassle
+	 */
+
 	head = &urbp->td_list;
 	tmp = head->next;
 	while (tmp != head) {
@@ -1842,10 +1848,15 @@
 
 		tmp = tmp->next;
 
-		if (td->status & TD_CTRL_ACTIVE) {
-			set_bit(TD_CTRL_IOC_BIT, &td->status);
-			break;
-		}
+		/*
+		 * Make sure we don't do the last one (since it'll have the
+		 * TERM bit set) as well as we skip every so many TD's to
+		 * make sure it doesn't hog the bandwidth
+		 */
+		if (tmp != head && (count % DEPTH_INTERVAL) == (DEPTH_INTERVAL - 1))
+			td->link |= UHCI_PTR_DEPTH;
+
+		count++;
 	}
 
 	return 0;
@@ -2073,7 +2084,7 @@
 {
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
 	unsigned int pipe = urb->pipe;
-	devrequest *cmd = (devrequest *)urb->setup_packet;
+	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *)urb->setup_packet;
 	void *data = urb->transfer_buffer;
 	int leni = urb->transfer_buffer_length;
 	int len = 0;
@@ -2096,10 +2107,10 @@
 		return -EINPROGRESS;
 	}
 
-	bmRType_bReq = cmd->requesttype | cmd->request << 8;
-	wValue = le16_to_cpu(cmd->value);
-	wIndex = le16_to_cpu(cmd->index);
-	wLength = le16_to_cpu(cmd->length);
+	bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8;
+	wValue = le16_to_cpu(cmd->wValue);
+	wIndex = le16_to_cpu(cmd->wIndex);
+	wLength = le16_to_cpu(cmd->wLength);
 
 	for (i = 0; i < 8; i++)
 		uhci->rh.c_p_r[i] = 0;
@@ -2340,7 +2351,7 @@
 
 	if (urbp->setup_packet_dma_handle)
 		pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle,
-			sizeof(devrequest), PCI_DMA_TODEVICE);
+			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
 
 	status = urbp->status;
 	if (!resubmit_interrupt || killed)
@@ -2788,6 +2799,7 @@
 	}
 
 	uhci->bus = bus;
+	bus->bus_name = dev->slot_name;
 	bus->hcpriv = uhci;
 
 	usb_register_bus(uhci->bus);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/uhci.h linux-2.4.20/drivers/usb/uhci.h
--- linux-2.4.19/drivers/usb/uhci.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/uhci.h	2002-10-29 11:18:33.000000000 +0000
@@ -100,7 +100,6 @@
 #define TD_CTRL_C_ERR_SHIFT	27
 #define TD_CTRL_LS		(1 << 26)	/* Low Speed Device */
 #define TD_CTRL_IOS		(1 << 25)	/* Isochronous Select */
-#define TD_CTRL_IOC_BIT		24
 #define TD_CTRL_IOC		(1 << 24)	/* Interrupt on Complete */
 #define TD_CTRL_ACTIVE		(1 << 23)	/* TD Active */
 #define TD_CTRL_STALLED		(1 << 22)	/* TD Stalled */
@@ -120,13 +119,14 @@
 /*
  * for TD <info>: (a.k.a. Token)
  */
-#define TD_TOKEN_TOGGLE		19
+#define TD_TOKEN_TOGGLE_SHIFT	19
+#define TD_TOKEN_TOGGLE		(1 << 19)
 #define TD_TOKEN_PID_MASK	0xFF
 #define TD_TOKEN_EXPLEN_MASK	0x7FF		/* expected length, encoded as n - 1 */
 
 #define uhci_maxlen(token)	((token) >> 21)
 #define uhci_expected_length(info) (((info >> 21) + 1) & TD_TOKEN_EXPLEN_MASK) /* 1-based */
-#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE) & 1)
+#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE_SHIFT) & 1)
 #define uhci_endpoint(token)	(((token) >> 15) & 0xf)
 #define uhci_devaddr(token)	(((token) >> 8) & 0x7f)
 #define uhci_devep(token)	(((token) >> 8) & 0x7ff)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/usb-debug.c linux-2.4.20/drivers/usb/usb-debug.c
--- linux-2.4.19/drivers/usb/usb-debug.c	2001-02-09 19:30:23.000000000 +0000
+++ linux-2.4.20/drivers/usb/usb-debug.c	2002-10-29 11:18:39.000000000 +0000
@@ -181,23 +181,23 @@
 	kfree(buf);
 }
 
-void usb_dump_urb (purb_t purb)
+void usb_dump_urb (struct urb *urb)
 {
-	printk ("urb                   :%p\n", purb);
-	printk ("next                  :%p\n", purb->next);
-	printk ("dev                   :%p\n", purb->dev);
-	printk ("pipe                  :%08X\n", purb->pipe);
-	printk ("status                :%d\n", purb->status);
-	printk ("transfer_flags        :%08X\n", purb->transfer_flags);
-	printk ("transfer_buffer       :%p\n", purb->transfer_buffer);
-	printk ("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
-	printk ("actual_length         :%d\n", purb->actual_length);
-	printk ("setup_packet          :%p\n", purb->setup_packet);
-	printk ("start_frame           :%d\n", purb->start_frame);
-	printk ("number_of_packets     :%d\n", purb->number_of_packets);
-	printk ("interval              :%d\n", purb->interval);
-	printk ("error_count           :%d\n", purb->error_count);
-	printk ("context               :%p\n", purb->context);
-	printk ("complete              :%p\n", purb->complete);
+	printk ("urb                   :%p\n", urb);
+	printk ("next                  :%p\n", urb->next);
+	printk ("dev                   :%p\n", urb->dev);
+	printk ("pipe                  :%08X\n", urb->pipe);
+	printk ("status                :%d\n", urb->status);
+	printk ("transfer_flags        :%08X\n", urb->transfer_flags);
+	printk ("transfer_buffer       :%p\n", urb->transfer_buffer);
+	printk ("transfer_buffer_length:%d\n", urb->transfer_buffer_length);
+	printk ("actual_length         :%d\n", urb->actual_length);
+	printk ("setup_packet          :%p\n", urb->setup_packet);
+	printk ("start_frame           :%d\n", urb->start_frame);
+	printk ("number_of_packets     :%d\n", urb->number_of_packets);
+	printk ("interval              :%d\n", urb->interval);
+	printk ("error_count           :%d\n", urb->error_count);
+	printk ("context               :%p\n", urb->context);
+	printk ("complete              :%p\n", urb->complete);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/usb-midi.c linux-2.4.20/drivers/usb/usb-midi.c
--- linux-2.4.19/drivers/usb/usb-midi.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/usb-midi.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,2228 @@
+/*
+  usb-midi.c  --  USB-MIDI driver
+
+  Copyright (C) 2001 
+      NAGANO Daisuke <breeze.nagano@nifty.ne.jp>
+
+  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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+  This driver is based on:
+    - 'Universal Serial Bus Device Class Definition for MIDI Device'
+    - linux/drivers/sound/es1371.c, linux/drivers/usb/audio.c
+    - alsa/lowlevel/pci/cs64xx.c
+    - umidi.c for NetBSD
+ */
+
+/* ------------------------------------------------------------------------- */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/wrapper.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+#include <linux/sound.h>
+#include <linux/init.h>
+#include <asm/semaphore.h>
+
+/** This declaration is missing from linux/usb.h **/
+extern int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size);
+
+#include "usb-midi.h"
+
+/* ------------------------------------------------------------------------- */
+
+/* More verbose on syslog */
+#undef MIDI_DEBUG
+
+#define MIDI_IN_BUFSIZ 1024
+
+#define HAVE_SUPPORT_USB_MIDI_CLASS
+
+#undef HAVE_SUPPORT_ALSA
+
+#undef MOD_INC_EACH_PROBE
+
+/* ------------------------------------------------------------------------- */
+
+static int singlebyte = 0;
+MODULE_PARM(singlebyte,"i");
+MODULE_PARM_DESC(singlebyte,"Enable sending MIDI messages with single message packet");
+
+static int maxdevices = 4;
+MODULE_PARM(maxdevices,"i");
+MODULE_PARM_DESC(maxdevices,"Max number of allocatable MIDI device");
+
+static int uvendor     = -1;
+MODULE_PARM(uvendor,"i");
+MODULE_PARM_DESC(uvendor, "The USB Vendor ID of a semi-compliant interface");
+
+static int uproduct    = -1;
+MODULE_PARM(uproduct,"i");
+MODULE_PARM_DESC(uproduct, "The USB Product ID of a semi-compliant interface");
+
+static int uinterface  = -1;
+MODULE_PARM(uinterface,"i");
+MODULE_PARM_DESC(uinterface, "The Interface number of a semi-compliant interface");
+
+static int ualt        = -1;
+MODULE_PARM(ualt,"i");
+MODULE_PARM_DESC(ualt, "The optional alternative setting of a semi-compliant interface");
+
+static int umin        = -1;
+MODULE_PARM(umin,"i");
+MODULE_PARM_DESC(umin, "The input endpoint of a semi-compliant interface");
+
+static int umout       = -1;
+MODULE_PARM(umout,"i");
+MODULE_PARM_DESC(umout, "The output endpoint of a semi-compliant interface");
+
+static int ucable      = -1;
+MODULE_PARM(ucable,"i");
+MODULE_PARM_DESC(ucable, "The cable number used for a semi-compliant interface");
+
+/** Note -- the usb_string() returns only Latin-1 characters.
+ * (unicode chars <= 255). To support Japanese, a unicode16LE-to-EUC or
+ * unicode16LE-to-JIS routine is needed to wrap around usb_get_string().
+ **/
+static unsigned short ulangid      = 0x0409; /** 0x0411 for Japanese **/
+MODULE_PARM(ulangid,"h");
+MODULE_PARM_DESC(ulangid, "The optional preferred USB Language ID for all devices");
+
+MODULE_AUTHOR("NAGANO Daisuke <breeze.nagano@nifty.ne.jp>");
+MODULE_DESCRIPTION("USB-MIDI driver");
+#if LINUX_VERSION_CODE  >= KERNEL_VERSION(2,4,14)
+MODULE_LICENSE("GPL");
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+/** MIDIStreaming Class-Specific Interface Descriptor Subtypes **/
+
+#define MS_DESCRIPTOR_UNDEFINED	0
+#define MS_HEADER		1
+#define MIDI_IN_JACK		2
+#define MIDI_OUT_JACK		3
+/* Spec reads: ELEMENT */
+#define ELEMENT_DESCRIPTOR   	4
+
+#define MS_HEADER_LENGTH	7
+
+/** MIDIStreaming Class-Specific Endpoint Descriptor Subtypes **/
+
+#define DESCRIPTOR_UNDEFINED	0
+/* Spec reads: MS_GENERAL */
+#define MS_GENERAL_ENDPOINT	1
+
+/** MIDIStreaming MIDI IN and OUT Jack Types **/
+
+#define JACK_TYPE_UNDEFINED	0
+/* Spec reads: EMBEDDED */
+#define EMBEDDED_JACK		1
+/* Spec reads: EXTERNAL */
+#define EXTERNAL_JACK		2
+
+
+/* structure summary
+  
+      usb_midi_state     usb_device
+       |         |
+      *|        *|       per ep
+     in_ep     out_ep
+       |         |
+      *|        *|       per cable
+      min       mout
+       |         |       (cable to device pairing magic)
+       |         |
+       usb_midi_dev      dev_id (major,minor) == file->private_data
+
+*/
+
+/* usb_midi_state: corresponds to a USB-MIDI module */
+struct usb_midi_state {
+	struct list_head   mididev;
+	
+	struct usb_device *usbdev;
+	
+	struct list_head   midiDevList;
+	struct list_head   inEndpointList;
+	struct list_head   outEndpointList;
+	
+	spinlock_t         lock;
+	
+	unsigned int       count; /* usage counter */
+};
+
+/* midi_out_endpoint: corresponds to an output endpoint */
+struct midi_out_endpoint {
+	struct list_head  list;
+	
+	struct usb_device *usbdev;
+	int                endpoint;
+	spinlock_t         lock;
+	wait_queue_head_t  wait;
+	
+	unsigned char     *buf;
+	int                bufWrPtr;
+	int                bufSize;
+	
+	struct urb       *urb;
+};
+
+/* midi_in_endpoint: corresponds to an input endpoint */
+struct midi_in_endpoint {
+	struct list_head   list;
+
+	struct usb_device *usbdev;
+	int                endpoint;
+	spinlock_t         lock;
+	wait_queue_head_t  wait;
+
+	struct usb_mididev *cables[16];	// cables open for read
+	int                 readers;	// number of cables open for read
+
+	struct urb        *urb;
+	unsigned char     *recvBuf;
+	int                recvBufSize;
+	int                urbSubmitted;	//FIXME: == readers > 0
+};
+
+/* usb_mididev: corresponds to a logical device */
+struct usb_mididev {
+	struct list_head       list;
+
+	struct usb_midi_state *midi;
+	int                    dev_midi;
+	mode_t                 open_mode;
+
+	struct {
+		struct midi_in_endpoint *ep;
+		int              cableId;
+		
+// as we are pushing data from usb_bulk_read to usb_midi_read,
+// we need a larger, cyclic buffer here.
+		unsigned char    buf[MIDI_IN_BUFSIZ];
+		int              bufRdPtr;
+		int              bufWrPtr;
+		int              bufRemains;
+	} min;
+
+	struct {
+		struct midi_out_endpoint *ep;
+		int              cableId;
+		
+		unsigned char    buf[3];
+		int              bufPtr;
+		int              bufRemains;
+		
+		int              isInExclusive;
+		unsigned char    lastEvent;
+	} mout;
+
+	int singlebyte;
+};
+
+/** Map the high nybble of MIDI voice messages to number of Message bytes.
+ * High nyble ranges from 0x8 to 0xe
+ */
+
+static int remains_80e0[] = {
+	3,	/** 0x8X Note Off **/
+	3,	/** 0x9X Note On **/
+	3,	/** 0xAX Poly-key pressure **/
+	3,	/** 0xBX Control Change **/
+	2,	/** 0xCX Program Change **/
+	2,	/** 0xDX Channel pressure **/
+	3 	/** 0xEX PitchBend Change **/
+};
+
+/** Map the messages to a number of Message bytes.
+ *
+ **/
+static int remains_f0f6[] = {
+	0,	/** 0xF0 **/
+	2,	/** 0XF1 **/
+	3,	/** 0XF2 **/
+	2,	/** 0XF3 **/
+	2,	/** 0XF4 (Undefined by MIDI Spec, and subject to change) **/
+	2,	/** 0XF5 (Undefined by MIDI Spec, and subject to change) **/
+	1	/** 0XF6 **/
+};
+
+/** Map the messages to a CIN (Code Index Number).
+ *
+ **/
+static int cin_f0ff[] = {
+	4,	/** 0xF0 System Exclusive Message Start (special cases may be 6 or 7) */
+	2,	/** 0xF1 **/
+	3,	/** 0xF2 **/
+	2,	/** 0xF3 **/
+	2,	/** 0xF4 **/
+	2,	/** 0xF5 **/
+	5,	/** 0xF6 **/
+	5,	/** 0xF7 End of System Exclusive Message (May be 6 or 7) **/
+	5,	/** 0xF8 **/
+	5,	/** 0xF9 **/
+	5,	/** 0xFA **/
+	5,	/** 0xFB **/
+	5,	/** 0xFC **/
+	5,	/** 0xFD **/
+	5,	/** 0xFE **/
+	5	/** 0xFF **/
+};
+
+/** Map MIDIStreaming Event packet Code Index Number (low nybble of byte 0)
+ * to the number of bytes of valid MIDI data.
+ *
+ * CIN of 0 and 1 are NOT USED in MIDIStreaming 1.0.
+ *
+ **/
+static int cin_to_len[] = {
+	0, 0, 2, 3,
+	3, 1, 2, 3,
+	3, 3, 3, 3,
+	2, 2, 3, 1
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+static struct list_head mididevs = LIST_HEAD_INIT(mididevs);
+
+static DECLARE_MUTEX(open_sem);
+static DECLARE_WAIT_QUEUE_HEAD(open_wait);
+
+
+/* ------------------------------------------------------------------------- */
+
+static void usb_write_callback(struct urb *urb)
+{
+	struct midi_out_endpoint *ep = (struct midi_out_endpoint *)urb->context;
+
+	if ( waitqueue_active( &ep->wait ) )
+		wake_up_interruptible( &ep->wait );
+}
+
+
+static int usb_write( struct midi_out_endpoint *ep, unsigned char *buf, int len )
+{
+	struct usb_device *d;
+	int pipe;
+	int ret = 0;
+	int status;
+	int maxretry = 50;
+	
+	DECLARE_WAITQUEUE(wait,current);
+	init_waitqueue_head(&ep->wait);
+
+	d = ep->usbdev;
+	pipe = usb_sndbulkpipe(d, ep->endpoint);
+	FILL_BULK_URB( ep->urb, d, pipe, (unsigned char*)buf, len,
+		       (usb_complete_t)usb_write_callback, ep );
+
+	status = usb_submit_urb(ep->urb);
+    
+	if (status) {
+		printk(KERN_ERR "usbmidi: Cannot submit urb (%d)\n",status);
+		ret = -EFAULT;
+	}
+
+	add_wait_queue( &ep->wait, &wait );
+	set_current_state( TASK_INTERRUPTIBLE );
+
+	while( ep->urb->status == -EINPROGRESS ) {
+		if ( maxretry-- < 0 ) {
+			printk(KERN_ERR "usbmidi: usb_bulk_msg timed out\n");
+			ret = -ETIME;
+			break;
+		}
+		interruptible_sleep_on_timeout( &ep->wait, 10 );
+	}
+	set_current_state( TASK_RUNNING );
+	remove_wait_queue( &ep->wait, &wait );
+
+	return ret;
+}
+
+
+/** Copy data from URB to In endpoint buf.
+ * Discard if CIN == 0 or CIN = 1.
+ *
+ *
+ **/
+
+static void usb_bulk_read(struct urb *urb)
+{
+	struct midi_in_endpoint *ep = (struct midi_in_endpoint *)(urb->context);
+	unsigned char *data = urb->transfer_buffer;
+	int i, l, wake;
+	unsigned long int flags;
+
+	if ( !ep->urbSubmitted ) {
+		return;
+	}
+
+	if ( (urb->status == 0) && (urb->actual_length > 0) ) {
+		wake = 0;
+		spin_lock_irqsave( &ep->lock, flags );
+
+		for(l = 0; l < urb->actual_length; l += 4) {
+			int cin = (data[l]>>0)&0xf;
+			int cab = (data[l]>>4)&0xf;
+			struct usb_mididev *cable = ep->cables[cab];
+			if ( cable ) {
+				int len = cin_to_len[cin]; /** length of MIDI data **/
+				for (i = 0; i < len; i++) {
+					cable->min.buf[cable->min.bufWrPtr] = data[1+i];
+					cable->min.bufWrPtr = (cable->min.bufWrPtr+1)%MIDI_IN_BUFSIZ;
+					if (cable->min.bufRemains < MIDI_IN_BUFSIZ)
+						cable->min.bufRemains += 1;
+					else /** need to drop data **/
+						cable->min.bufRdPtr += (cable->min.bufRdPtr+1)%MIDI_IN_BUFSIZ;
+					wake = 1;
+				}
+			}
+		}
+
+		spin_unlock_irqrestore( &ep->lock, flags );
+		if ( wake ) {
+			wake_up( &ep->wait );
+		}
+	}
+
+	/* urb->dev must be reinitialized on 2.4.x kernels */
+	urb->dev = ep->usbdev;
+
+	urb->actual_length = 0;
+	usb_submit_urb(urb);
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+
+/* This routine must be called with spin_lock */
+
+/** Wrapper around usb_write().
+ *  This routine must be called with spin_lock held on ep.
+ *  Called by midiWrite(), putOneMidiEvent(), and  usb_midi_write();
+ **/
+static int flush_midi_buffer( struct midi_out_endpoint *ep )
+{
+	int ret=0;
+
+	if ( ep->bufWrPtr > 0 ) {
+		ret = usb_write( ep, ep->buf, ep->bufWrPtr );
+		ep->bufWrPtr = 0;
+	}
+
+	return ret;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/** Given a MIDI Event, determine size of data to be attached to 
+ * USB-MIDI packet.
+ * Returns 1, 2 or 3.
+ * Called by midiWrite();
+ * Uses remains_80e0 and remains_f0f6;
+ **/
+static int get_remains(int event)
+{
+	int ret;
+
+	if ( event  < 0x80 ) {
+		ret = 1;
+	} else if ( event < 0xf0 ) {
+		ret = remains_80e0[((event-0x80)>>4)&0x0f];
+	} else if ( event < 0xf7 ) {
+		ret = remains_f0f6[event-0xf0];
+	} else {
+		ret = 1;
+	}
+
+	return ret;
+}
+
+/** Given the output MIDI data in the output buffer, computes a reasonable 
+ * CIN.
+ * Called by putOneMidiEvent().
+ **/
+static int get_CIN( struct usb_mididev *m )
+{
+	int cin;
+
+	if ( m->mout.buf[0] == 0xf7 ) {
+		cin = 5;
+	}
+	else if ( m->mout.buf[1] == 0xf7 ) {
+		cin = 6;
+	}
+	else if ( m->mout.buf[2] == 0xf7 ) {
+		cin = 7;
+	}
+	else {
+		if ( m->mout.isInExclusive == 1 ) {
+			cin = 4;
+		} else if ( m->mout.buf[0] < 0x80 ) {
+			/** One byte that we know nothing about. **/
+			cin = 0xF; 
+		} else if ( m->mout.buf[0] < 0xf0 ) {
+			/** MIDI Voice messages 0x8X to 0xEX map to cin 0x8 to 0xE. **/
+			cin = (m->mout.buf[0]>>4)&0x0f; 
+		}
+		else {
+			/** Special lookup table exists for real-time events. **/
+			cin = cin_f0ff[m->mout.buf[0]-0xf0];
+		}
+	}
+
+	return cin;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+
+/** Move data to USB endpoint buffer.
+ *
+ **/
+static int put_one_midi_event(struct usb_mididev *m)
+{
+	int cin;
+	unsigned long flags;
+	struct midi_out_endpoint *ep = m->mout.ep;
+	int ret=0;
+
+	cin = get_CIN( m );
+	if ( cin > 0x0f || cin < 0 ) {
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave( &ep->lock, flags );
+	ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) | cin;
+	ep->buf[ep->bufWrPtr++] = m->mout.buf[0];
+	ep->buf[ep->bufWrPtr++] = m->mout.buf[1];
+	ep->buf[ep->bufWrPtr++] = m->mout.buf[2];
+	if ( ep->bufWrPtr >= ep->bufSize ) {
+		ret = flush_midi_buffer( ep );
+	}
+	spin_unlock_irqrestore( &ep->lock, flags);
+
+	m->mout.buf[0] = m->mout.buf[1] = m->mout.buf[2] = 0;
+	m->mout.bufPtr = 0;
+
+	return ret;
+}
+
+/** Write the MIDI message v on the midi device.
+ *  Called by usb_midi_write();
+ *  Responsible for packaging a MIDI data stream into USB-MIDI packets.
+ **/
+
+static int midi_write( struct usb_mididev *m, int v )
+{
+	unsigned long flags;
+	struct midi_out_endpoint *ep = m->mout.ep;
+	int ret=0;
+	unsigned char c = (unsigned char)v;
+	unsigned char sysrt_buf[4];
+
+	if ( m->singlebyte != 0 ) {
+		/** Simple code to handle the single-byte USB-MIDI protocol. */
+		spin_lock_irqsave( &ep->lock, flags );
+		if ( ep->bufWrPtr+4 > ep->bufSize ) {
+			ret = flush_midi_buffer( ep );
+			if ( !ret ) {
+				spin_unlock_irqrestore( &ep->lock, flags );
+				return ret;
+			}
+		}
+		ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) |  0x0f; /* single byte */
+		ep->buf[ep->bufWrPtr++] = c;
+		ep->buf[ep->bufWrPtr++] = 0;
+		ep->buf[ep->bufWrPtr++] = 0;
+		if ( ep->bufWrPtr >= ep->bufSize ) {
+			ret = flush_midi_buffer( ep );
+		}
+		spin_unlock_irqrestore( &ep->lock, flags );
+
+		return ret;
+	}
+	/** Normal USB-MIDI protocol begins here. */
+
+	if ( c > 0xf7 ) {	/* system: Realtime messages */
+		/** Realtime messages are written IMMEDIATELY. */
+		sysrt_buf[0] = (m->mout.cableId<<4) | 0x0f;
+		sysrt_buf[1] = c;
+		sysrt_buf[2] = 0;
+		sysrt_buf[3] = 0;
+		spin_lock_irqsave( &ep->lock, flags );
+		ret = usb_write( ep, sysrt_buf, 4 );
+		spin_unlock_irqrestore( &ep->lock, flags );
+		/* m->mout.lastEvent = 0; */
+
+		return ret;
+	}
+
+	if ( c >= 0x80 ) {
+		if ( c < 0xf0 ) {
+			m->mout.lastEvent = c;
+			m->mout.isInExclusive = 0;
+			m->mout.bufRemains = get_remains(c);
+		} else if ( c == 0xf0 ) {
+			/* m->mout.lastEvent = 0; */
+			m->mout.isInExclusive = 1;
+			m->mout.bufRemains = get_remains(c);
+		} else if ( c == 0xf7 && m->mout.isInExclusive == 1 ) {
+			/* m->mout.lastEvent = 0; */
+			m->mout.isInExclusive = 0;
+			m->mout.bufRemains = 1;
+		} else if ( c > 0xf0 ) {
+			/* m->mout.lastEvent = 0; */
+			m->mout.isInExclusive = 0;
+			m->mout.bufRemains = get_remains(c);
+		}
+    
+	} else if ( m->mout.bufRemains == 0 && m->mout.isInExclusive == 0 ) {
+		if ( m->mout.lastEvent == 0 ) {
+			return 0; /* discard, waiting for the first event */
+		}
+		/** track status **/
+		m->mout.buf[0] = m->mout.lastEvent;
+		m->mout.bufPtr = 1;
+		m->mout.bufRemains = get_remains(m->mout.lastEvent)-1;
+	}
+  
+	m->mout.buf[m->mout.bufPtr++] = c;
+	m->mout.bufRemains--;
+	if ( m->mout.bufRemains == 0 || m->mout.bufPtr >= 3) {
+		ret = put_one_midi_event(m);
+	}
+
+	return ret;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ *  Basic contract: Used to change the current read/write position in a file.
+ *  On success, the non-negative position is reported.
+ *  On failure, the negative of an error code is reported.
+ *
+ *  Because a MIDIStream is not a file, all seek operations are doomed to fail.
+ *
+ **/
+static loff_t usb_midi_llseek(struct file *file, loff_t offset, int origin)
+{
+	/** Tell user you cannot seek on a PIPE-like device. **/
+	return -ESPIPE;
+}
+
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ * Basic contract: Block until count bytes have been read or an error occurs.
+ *
+ **/
+
+static ssize_t usb_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
+	struct midi_in_endpoint *ep = m->min.ep;
+	ssize_t ret;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if ( ppos != &file->f_pos ) {
+		return -ESPIPE;
+	}
+	if ( !access_ok(VERIFY_READ, buffer, count) ) {
+		return -EFAULT;
+	}
+	if ( count == 0 ) {
+		return 0;
+	}
+
+	add_wait_queue( &ep->wait, &wait );
+	ret = 0;
+	while( count > 0 ) {
+		int cnt;
+		int d = (int)count;
+
+		cnt = m->min.bufRemains;
+		if ( cnt > d ) {
+			cnt = d;
+		}
+
+		if ( cnt <= 0 ) {
+			if ( file->f_flags & O_NONBLOCK ) {
+				if (!ret) 
+					ret = -EAGAIN;
+				break;
+			}
+			__set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			if (signal_pending(current)) {
+				if(!ret)
+					ret=-ERESTARTSYS;
+				break;
+			}
+			continue;
+		}
+
+		{
+			int i;
+			unsigned long flags; /* used to synchronize access to the endpoint */
+			spin_lock_irqsave( &ep->lock, flags );
+			for (i = 0; i < cnt; i++) {
+				if ( copy_to_user( buffer+i, m->min.buf+m->min.bufRdPtr, 1 ) ) {
+					if ( !ret )
+						ret = -EFAULT;
+					break;
+				}
+				m->min.bufRdPtr = (m->min.bufRdPtr+1)%MIDI_IN_BUFSIZ;
+				m->min.bufRemains -= 1;
+			}
+			spin_unlock_irqrestore( &ep->lock, flags );
+		}
+
+		count-=cnt;
+		buffer+=cnt;
+		ret+=cnt;
+
+		break;
+	}
+
+	remove_wait_queue( &ep->wait, &wait );
+	set_current_state(TASK_RUNNING);
+
+	return ret;
+}
+
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ *  Basic Contract: Take MIDI data byte-by-byte and pass it to
+ *  writeMidi() which packages MIDI data into USB-MIDI stream.
+ *  Then flushMidiData() is called to ensure all bytes have been written
+ *  in a timely fashion.
+ *
+ **/
+
+static ssize_t usb_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
+	ssize_t ret;
+	unsigned long int flags;
+
+	if ( ppos != &file->f_pos ) {
+		return -ESPIPE;
+	}
+	if ( !access_ok(VERIFY_READ, buffer, count) ) {
+		return -EFAULT;
+	}
+	if ( count == 0 ) {
+		return 0;
+	}
+
+	ret = 0;
+	while( count > 0 ) {
+		unsigned char c;
+
+		if (copy_from_user((unsigned char *)&c, buffer, 1)) {
+			if ( ret == 0 )
+				ret = -EFAULT;
+			break;
+		}
+		if( midi_write(m, (int)c) ) {
+			if ( ret == 0 )
+				ret = -EFAULT;
+			break;
+		}
+		count--;
+		buffer++;
+		ret++;
+	}
+
+	spin_lock_irqsave( &m->mout.ep->lock, flags );
+	if ( flush_midi_buffer(m->mout.ep) < 0 ) {
+		ret = -EFAULT;
+	}
+	spin_unlock_irqrestore( &m->mout.ep->lock, flags );
+
+	return ret;
+}
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ * Basic contract:  Wait (spin) until ready to read or write on the file.
+ *
+ **/
+static unsigned int usb_midi_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
+	struct midi_in_endpoint *iep = m->min.ep;
+	struct midi_out_endpoint *oep = m->mout.ep;
+	unsigned long flags;
+	unsigned int mask = 0;
+  
+	if ( file->f_mode & FMODE_READ ) {
+		poll_wait( file, &iep->wait, wait );
+		spin_lock_irqsave( &iep->lock, flags );
+		if ( m->min.bufRemains > 0 )
+			mask |= POLLIN | POLLRDNORM;
+		spin_unlock_irqrestore( &iep->lock, flags );
+	}
+
+	if ( file->f_mode & FMODE_WRITE ) {
+		poll_wait( file, &oep->wait, wait );
+		spin_lock_irqsave( &oep->lock, flags );
+		if ( oep->bufWrPtr < oep->bufSize )
+			mask |= POLLOUT | POLLWRNORM;
+		spin_unlock_irqrestore( &oep->lock, flags );
+	}
+
+	return mask;
+}
+
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ * Basic contract: This is always the first operation performed on the
+ * device node. If no method is defined, the open succeeds without any
+ * notification given to the module.
+ *
+ **/
+
+static int usb_midi_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	DECLARE_WAITQUEUE(wait, current);
+	struct list_head      *devs, *mdevs;
+	struct usb_midi_state *s;
+	struct usb_mididev    *m;
+	int flags;
+	int succeed = 0;
+
+#if 0
+	printk(KERN_INFO "usb-midi: Open minor= %d.\n", minor);
+#endif
+
+	for(;;) {
+		down(&open_sem);
+		for (devs = mididevs.next; devs != &mididevs; devs = devs->next) {
+			s = list_entry(devs, struct usb_midi_state, mididev);
+			for (mdevs = s->midiDevList.next; mdevs != &s->midiDevList; mdevs = mdevs->next) {
+				m = list_entry(mdevs, struct usb_mididev, list);
+				if ( !((m->dev_midi ^ minor) & ~0xf) )
+					goto device_found;
+			}
+		}
+		up(&open_sem);
+		return -ENODEV;
+
+	device_found:
+		if ( !s->usbdev ) {
+			up(&open_sem);
+			return -EIO;
+		}
+		if ( !(m->open_mode & file->f_mode) ) {
+			break;
+		}
+		if ( file->f_flags & O_NONBLOCK ) {
+			up(&open_sem);
+			return -EBUSY;
+		}
+		__set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue( &open_wait, &wait );
+		up(&open_sem);
+		schedule();
+		__set_current_state(TASK_RUNNING);
+		remove_wait_queue( &open_wait, &wait );
+		if ( signal_pending(current) ) {
+			return -ERESTARTSYS;
+		}
+	}
+
+	file->private_data = m;
+	spin_lock_irqsave( &s->lock, flags );
+
+	if ( !(m->open_mode & (FMODE_READ | FMODE_WRITE)) ) {
+		//FIXME: intented semantics unclear here
+		m->min.bufRdPtr       = 0;
+		m->min.bufWrPtr       = 0;
+		m->min.bufRemains     = 0;
+		spin_lock_init(&m->min.ep->lock);
+
+		m->mout.bufPtr        = 0;
+		m->mout.bufRemains    = 0;
+		m->mout.isInExclusive = 0;
+		m->mout.lastEvent     = 0;
+		spin_lock_init(&m->mout.ep->lock);
+	}
+
+	if ( (file->f_mode & FMODE_READ) && m->min.ep != NULL ) {
+		unsigned long int flagsep;
+		spin_lock_irqsave( &m->min.ep->lock, flagsep );
+		m->min.ep->cables[m->min.cableId] = m;
+		m->min.ep->readers += 1;
+		m->min.bufRdPtr       = 0;
+		m->min.bufWrPtr       = 0;
+		m->min.bufRemains     = 0;
+		spin_unlock_irqrestore( &m->min.ep->lock, flagsep );
+
+		if ( !(m->min.ep->urbSubmitted)) {
+
+			/* urb->dev must be reinitialized on 2.4.x kernels */
+			m->min.ep->urb->dev = m->min.ep->usbdev;
+
+			if ( usb_submit_urb(m->min.ep->urb) ) {
+				printk(KERN_ERR "usbmidi: Cannot submit urb for MIDI-IN\n");
+			}
+			m->min.ep->urbSubmitted = 1;
+		}
+		m->open_mode |= FMODE_READ;
+		succeed = 1;
+	}
+
+	if ( (file->f_mode & FMODE_WRITE) && m->mout.ep != NULL ) {
+		m->mout.bufPtr        = 0;
+		m->mout.bufRemains    = 0;
+		m->mout.isInExclusive = 0;
+		m->mout.lastEvent     = 0;
+		m->open_mode |= FMODE_WRITE;
+		succeed = 1;
+	}
+
+	spin_unlock_irqrestore( &s->lock, flags );
+
+	s->count++;
+	up(&open_sem);
+
+	/** Changed to prevent extra increments to USE_COUNT. **/
+	if (!succeed) {
+		return -EBUSY;
+	}
+
+#if 0
+	printk(KERN_INFO "usb-midi: Open Succeeded. minor= %d.\n", minor);
+#endif
+
+	/** Side-effect: module cannot be removed until USE_COUNT is 0. **/
+#ifndef MOD_INC_EACH_PROBE
+	MOD_INC_USE_COUNT;
+#endif
+
+	return 0; /** Success. **/
+}
+
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ *  Basic contract: Close an opened file and deallocate anything we allocated.
+ *  Like open(), this can be missing. If open set file->private_data,
+ *  release() must clear it.
+ *
+ **/
+
+static int usb_midi_release(struct inode *inode, struct file *file)
+{
+	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
+	struct usb_midi_state *s = (struct usb_midi_state *)m->midi;
+
+#if 0
+	printk(KERN_INFO "usb-midi: Close.\n");
+#endif
+
+	down(&open_sem);
+
+	if ( m->open_mode & FMODE_WRITE ) {
+		m->open_mode &= ~FMODE_WRITE;
+		usb_unlink_urb( m->mout.ep->urb );
+	}
+
+	if ( m->open_mode & FMODE_READ ) {
+	        unsigned long int flagsep;
+	        spin_lock_irqsave( &m->min.ep->lock, flagsep );
+                m->min.ep->cables[m->min.cableId] = 0; // discard cable
+                m->min.ep->readers -= 1;
+		m->open_mode &= ~FMODE_READ;
+		if ( m->min.ep->readers == 0 &&
+                     m->min.ep->urbSubmitted ) {
+			m->min.ep->urbSubmitted = 0;
+			usb_unlink_urb(m->min.ep->urb);
+		}
+	        spin_unlock_irqrestore( &m->min.ep->lock, flagsep );
+	}
+
+	s->count--;
+
+	up(&open_sem);
+	wake_up(&open_wait);
+
+	file->private_data = 0;
+	/** Sideeffect: Module cannot be removed until usecount is 0. */
+#ifndef MOD_INC_EACH_PROBE
+	MOD_DEC_USE_COUNT;
+#endif
+
+	return 0;
+}
+
+static struct file_operations usb_midi_fops = {
+	llseek:		usb_midi_llseek,
+	read:		usb_midi_read,
+	write:		usb_midi_write,
+	poll:		usb_midi_poll,
+	open:		usb_midi_open,
+	release:	usb_midi_release,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/** Returns filled midi_in_endpoint structure or null on failure.
+ *
+ * Parameters:
+ *	d        - a usb_device
+ *	endPoint - An usb endpoint in the range 0 to 15.
+ * Called by allocUsbMidiDev();
+ *
+ **/
+
+static struct midi_in_endpoint *alloc_midi_in_endpoint( struct usb_device *d, int endPoint )
+{
+	struct midi_in_endpoint *ep;
+	int bufSize;
+	int pipe;
+
+	endPoint &= 0x0f; /* Silently force endPoint to lie in range 0 to 15. */
+
+	pipe =  usb_rcvbulkpipe( d, endPoint );
+	bufSize = usb_maxpacket( d, pipe, usb_pipein(pipe) );
+	/* usb_pipein() = ! usb_pipeout() = true for an in Endpoint */
+
+	ep = (struct midi_in_endpoint *)kmalloc(sizeof(struct midi_in_endpoint), GFP_KERNEL);
+	if ( !ep ) {
+		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint\n");
+		return NULL;
+	}
+	memset( ep, 0, sizeof(struct midi_in_endpoint) );
+//      this sets cables[] and readers to 0, too.
+//      for (i=0; i<16; i++) ep->cables[i] = 0; // discard cable
+//      ep->readers = 0;
+
+	ep->endpoint = endPoint;
+
+	ep->recvBuf = (unsigned char *)kmalloc(sizeof(unsigned char)*(bufSize), GFP_KERNEL);
+	if ( !ep->recvBuf ) {
+		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint buffer\n");
+		kfree(ep);
+		return NULL;
+	}
+
+	ep->urb = usb_alloc_urb(0); /* no ISO */
+	if ( !ep->urb ) {
+		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint urb\n");
+		kfree(ep->recvBuf);
+		kfree(ep);
+		return NULL;
+	}
+	FILL_BULK_URB( ep->urb, d, 
+		       usb_rcvbulkpipe(d, endPoint),
+		       (unsigned char *)ep->recvBuf, bufSize,
+		       (usb_complete_t)usb_bulk_read, ep );
+
+	/* ep->bufRdPtr     = 0; */
+	/* ep->bufWrPtr     = 0; */
+	/* ep->bufRemains   = 0; */
+	/* ep->urbSubmitted = 0; */
+	ep->recvBufSize  = bufSize;
+
+	init_waitqueue_head(&ep->wait);
+
+	return ep;
+}
+
+static int remove_midi_in_endpoint( struct midi_in_endpoint *min )
+{
+	usb_unlink_urb( min->urb );
+	usb_free_urb( min->urb );
+	kfree( min->recvBuf );
+	kfree( min );
+
+	return 0;
+}
+
+/** Returns filled midi_out_endpoint structure or null on failure.
+ *
+ * Parameters:
+ *	d        - a usb_device
+ *	endPoint - An usb endpoint in the range 0 to 15.
+ * Called by allocUsbMidiDev();
+ *
+ **/
+static struct midi_out_endpoint *alloc_midi_out_endpoint( struct usb_device *d, int endPoint )
+{
+	struct midi_out_endpoint *ep = NULL;
+	int pipe;
+	int bufSize;
+
+	endPoint &= 0x0f;
+	pipe =  usb_sndbulkpipe( d, endPoint );
+	bufSize = usb_maxpacket( d, pipe, usb_pipeout(pipe) );
+
+	ep = (struct midi_out_endpoint *)kmalloc(sizeof(struct midi_out_endpoint), GFP_KERNEL);
+	if ( !ep ) {
+		printk(KERN_ERR "usbmidi: no memory for midi out-endpoint\n");
+		return NULL;
+	}
+	memset( ep, 0, sizeof(struct midi_out_endpoint) );
+
+	ep->endpoint = endPoint;
+	ep->buf = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);
+	if ( !ep->buf ) {
+		printk(KERN_ERR "usbmidi: no memory for midi out-endpoint buffer\n");
+		kfree(ep);
+		return NULL;
+	}
+
+	ep->urb = usb_alloc_urb(0); /* no ISO */
+	if ( !ep->urb ) {
+		printk(KERN_ERR "usbmidi: no memory for midi out-endpoint urb\n");
+		kfree(ep->buf);
+		kfree(ep);
+		return NULL;
+	}
+
+	ep->bufSize       = bufSize;
+	/* ep->bufWrPtr      = 0; */
+
+	init_waitqueue_head(&ep->wait);
+
+	return ep;
+}
+
+
+static int remove_midi_out_endpoint( struct midi_out_endpoint *mout )
+{
+	usb_unlink_urb( mout->urb );
+	usb_free_urb( mout->urb );
+	kfree( mout->buf );
+	kfree( mout );
+
+	return 0;
+}
+
+
+/** Returns a filled usb_mididev structure, registered as a Linux MIDI device.
+ *
+ * Returns null if memory is not available or the device cannot be registered.
+ * Called by allocUsbMidiDev();
+ *
+ **/
+static struct usb_mididev *allocMidiDev(
+	struct usb_midi_state *s,
+	struct midi_in_endpoint *min,
+	struct midi_out_endpoint *mout,
+	int inCableId,
+	int outCableId )
+{
+	struct usb_mididev *m;
+
+	m = (struct usb_mididev *)kmalloc(sizeof(struct usb_mididev), GFP_KERNEL);
+	if (!m) {
+		printk(KERN_ERR "usbmidi: no memory for midi device\n");
+		return NULL;
+	}
+
+	memset(m, 0, sizeof(struct usb_mididev));
+
+	if ((m->dev_midi = register_sound_midi(&usb_midi_fops, -1)) < 0) {
+		printk(KERN_ERR "usbmidi: cannot register midi device\n");
+		kfree(m);
+		return NULL;
+	}
+
+	m->midi               = s;
+	/* m->open_mode          = 0; */
+
+	if ( min ) {
+		m->min.ep             = min;
+		m->min.ep->usbdev     = s->usbdev;
+		m->min.cableId        = inCableId;
+	}
+	/* m->min.bufPtr         = 0; */
+	/* m->min.bufRemains     = 0; */
+
+	if ( mout ) {
+		m->mout.ep            = mout;
+		m->mout.ep->usbdev    = s->usbdev;
+		m->mout.cableId       = outCableId;
+	}
+	/* m->mout.bufPtr        = 0; */
+	/* m->mout.bufRemains    = 0; */
+	/* m->mout.isInExclusive = 0; */
+	/* m->mout.lastEvent     = 0; */
+
+	m->singlebyte         = singlebyte;
+
+	return m;
+}
+
+
+static void release_midi_device( struct usb_midi_state *s )
+{
+	struct usb_mididev *m;
+	struct midi_in_endpoint *min;
+	struct midi_out_endpoint *mout;
+
+	if ( s->count > 0 ) {
+		up(&open_sem);
+		return;
+	}
+	up( &open_sem );
+	wake_up( &open_wait );
+
+	while(!list_empty(&s->inEndpointList)) {
+		min = list_entry(s->inEndpointList.next, struct midi_in_endpoint, list);
+		list_del(&min->list);
+		remove_midi_in_endpoint(min);
+	}
+
+	while(!list_empty(&s->outEndpointList)) {
+		mout = list_entry(s->outEndpointList.next, struct midi_out_endpoint, list);
+		list_del(&mout->list);
+		remove_midi_out_endpoint(mout);
+	}
+
+	while(!list_empty(&s->midiDevList)) {
+		m = list_entry(s->midiDevList.next, struct usb_mididev, list);
+		list_del(&m->list);
+		kfree(m);
+	}
+
+	kfree(s);
+
+	return;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+/** Utility routine to find a descriptor in a dump of many descriptors.
+ * Returns start of descriptor or NULL if not found. 
+ * descStart pointer to list of interfaces.
+ * descLength length (in bytes) of dump
+ * after (ignored if NULL) this routine returns only descriptors after "after"
+ * dtype (mandatory) The descriptor type.
+ * iface (ignored if -1) returns descriptor at/following given interface
+ * altSetting (ignored if -1) returns descriptor at/following given altSetting
+ *
+ *
+ *  Called by parseDescriptor(), find_csinterface_descriptor();
+ *
+ */
+static void *find_descriptor( void *descStart, unsigned int descLength, void *after, unsigned char dtype, int iface, int altSetting )
+{
+	unsigned char *p, *end, *next;
+	int interfaceNumber = -1, altSet = -1;
+
+	p = descStart;
+	end = p + descLength;
+	for( ; p < end; ) {
+		if ( p[0] < 2 )
+			return NULL;
+		next = p + p[0];
+		if ( next > end )
+			return NULL;
+		if ( p[1] == USB_DT_INTERFACE ) {
+			if ( p[0] < USB_DT_INTERFACE_SIZE )
+				return NULL;
+			interfaceNumber = p[2];
+			altSet = p[3];
+		}
+		if ( p[1] == dtype &&
+		     ( !after || ( p > (unsigned char *)after) ) &&
+		     ( ( iface == -1) || (iface == interfaceNumber) ) &&
+		     ( (altSetting == -1) || (altSetting == altSet) )) {
+			return p;
+		}
+		p = next;
+	}
+	return NULL;
+}
+
+/** Utility to find a class-specfic interface descriptor.
+ *  dsubtype is a descriptor subtype
+ *  Called by parseDescriptor();
+ **/
+static void *find_csinterface_descriptor(void *descStart, unsigned int descLength, void *after, u8 dsubtype, int iface, int altSetting)
+{
+	unsigned char *p;
+  
+	p = find_descriptor( descStart, descLength, after, USB_DT_CS_INTERFACE, iface, altSetting );
+	while ( p ) {
+		if ( p[0] >= 3 && p[2] == dsubtype )
+			return p;
+		p = find_descriptor( descStart, descLength, p, USB_DT_CS_INTERFACE, 
+				     iface, altSetting );
+	}
+	return NULL;
+}
+
+
+/** The magic of making a new usb_midi_device from config happens here.
+ *
+ * The caller is responsible for free-ing this return value (if not NULL).
+ *
+ **/
+static struct usb_midi_device *parse_descriptor( struct usb_device *d, unsigned char *buffer, int bufSize, unsigned int ifnum , unsigned int altSetting, int quirks)
+{
+	struct usb_midi_device *u;
+	unsigned char *p1;
+	unsigned char *p2;
+	unsigned char *next;
+	int iep, oep;
+	int length;
+	unsigned long longBits;
+	int pins, nbytes, offset, shift, jack;
+#ifdef HAVE_JACK_STRINGS
+	/** Jacks can have associated names.  **/
+	unsigned char jack2string[256];
+#endif
+
+	u = 0;
+	/* find audiocontrol interface */
+	p1 = find_csinterface_descriptor( buffer, bufSize, NULL,
+					  MS_HEADER, ifnum, altSetting);
+
+	if ( !p1 ) {
+		goto error_end;
+	}
+
+	if ( p1[0] < MS_HEADER_LENGTH ) {
+		goto error_end;
+	}
+
+	/* Assume success. Since the device corresponds to USB-MIDI spec, we assume
+	   that the rest of the USB 2.0 spec is obeyed. */
+
+	u = (struct usb_midi_device *)kmalloc( sizeof(struct usb_midi_device), GFP_KERNEL );
+	if ( !u ) {
+		return NULL;
+	}
+	u->deviceName = 0;
+	u->idVendor = d->descriptor.idVendor;
+	u->idProduct = d->descriptor.idProduct;
+	u->interface = ifnum;
+	u->altSetting = altSetting;
+	u->in[0].endpoint = -1;
+	u->in[0].cableId = -1;
+	u->out[0].endpoint = -1;
+	u->out[0].cableId = -1;
+
+
+	printk(KERN_INFO "usb-midi: Found MIDIStreaming device corresponding to Release %d.%02d of spec.\n",
+	       (p1[4] >> 4) * 10 + (p1[4] & 0x0f ),
+	       (p1[3] >> 4) * 10 + (p1[3] & 0x0f )
+		);
+
+	length = p1[5] | (p1[6] << 8);
+
+#ifdef HAVE_JACK_STRINGS
+	memset(jack2string, 0, sizeof(unsigned char) * 256);
+#endif
+
+	length -= p1[0];
+	for (p2 = p1 + p1[0]; length > 0; p2 = next) {
+		next = p2 + p2[0];
+		length -= p2[0];
+
+		if (p2[0] < 2 ) break;
+		if (p2[1] != USB_DT_CS_INTERFACE) break;
+		if (p2[2] == MIDI_IN_JACK && p2[0] >= 6 ) {
+			jack = p2[4];
+#ifdef HAVE_JACK_STRINGS
+			jack2string[jack] = p2[5];
+#endif
+			printk(KERN_INFO "usb-midi: Found IN Jack 0x%02x %s\n",
+			       jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL" );
+		} else if ( p2[2] == MIDI_OUT_JACK && p2[0] >= 6) {
+			pins = p2[5];
+			if ( p2[0] < (6 + 2 * pins) ) continue;
+			jack = p2[4];
+#ifdef HAVE_JACK_STRINGS
+			jack2string[jack] = p2[5 + 2 * pins];
+#endif
+			printk(KERN_INFO "usb-midi: Found OUT Jack 0x%02x %s, %d pins\n",
+			       jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL", pins );
+		} else if ( p2[2] == ELEMENT_DESCRIPTOR  && p2[0]  >= 10) {
+			pins = p2[4];
+			if ( p2[0] < (9 + 2 * pins ) ) continue;
+			nbytes = p2[8 + 2 * pins ];
+			if ( p2[0] < (10 + 2 * pins + nbytes) ) continue;
+			longBits = 0L;
+			for ( offset = 0, shift = 0; offset < nbytes && offset < 8; offset ++, shift += 8) {
+				longBits |= ((long)(p2[9 + 2 * pins + offset])) << shift;
+			}
+			jack = p2[3];
+#ifdef HAVE_JACK_STRINGS
+			jack2string[jack] = p2[9 + 2 * pins + nbytes];
+#endif
+			printk(KERN_INFO "usb-midi: Found ELEMENT 0x%02x, %d/%d pins in/out, bits: 0x%016lx\n",
+			       jack, pins, (int)(p2[5 + 2 * pins]), (long)longBits );
+		} else {
+		}
+	}
+
+	iep=0;
+	oep=0;
+
+	if (quirks==0) {
+		/* MIDISTREAM */
+		p2 = 0;
+		for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT,
+					  ifnum, altSetting ); p1; p1 = next ) {
+			next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT,
+					       ifnum, altSetting ); 
+			p2 = find_descriptor(buffer, bufSize, p1, USB_DT_CS_ENDPOINT,
+					     ifnum, altSetting ); 
+
+			if ( p2 && next && ( p2 > next ) )
+				p2 = 0;
+
+			if ( p1[0] < 9 || !p2 || p2[0] < 4 ) continue;
+
+			if ( (p1[2] & 0x80) == 0x80 ) {
+				if ( iep < 15 ) {
+					pins = p2[3]; /* not pins -- actually "cables" */
+					if ( pins > 16 )
+						pins = 16;
+					u->in[iep].endpoint = p1[2];
+					u->in[iep].cableId = ( 1 << pins ) - 1;
+					if ( u->in[iep].cableId ) iep ++;
+					if ( iep < 15 ) {
+						u->in[iep].endpoint = -1;
+						u->in[iep].cableId = -1;
+					}
+				}
+			} else {
+				if ( oep < 15 ) {
+					pins = p2[3]; /* not pins -- actually "cables" */
+					if ( pins > 16 )
+						pins = 16;
+					u->out[oep].endpoint = p1[2];
+					u->out[oep].cableId = ( 1 << pins ) - 1;
+					if ( u->out[oep].cableId ) oep ++;
+					if ( oep < 15 ) {
+						u->out[oep].endpoint = -1;
+						u->out[oep].cableId = -1;
+					}
+				}
+			}
+	
+		}
+	} else if (quirks==1) {
+		/* YAMAHA quirks */
+		for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT,
+					  ifnum, altSetting ); p1; p1 = next ) {
+			next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT,
+					       ifnum, altSetting ); 
+	
+			if ( p1[0] < 7 ) continue;
+
+			if ( (p1[2] & 0x80) == 0x80 ) {
+				if ( iep < 15 ) {
+					pins = iep+1;
+					if ( pins > 16 )
+						pins = 16;
+					u->in[iep].endpoint = p1[2];
+					u->in[iep].cableId = ( 1 << pins ) - 1;
+					if ( u->in[iep].cableId ) iep ++;
+					if ( iep < 15 ) {
+						u->in[iep].endpoint = -1;
+						u->in[iep].cableId = -1;
+					}
+				}
+			} else {
+				if ( oep < 15 ) {
+					pins = oep+1;
+					if ( pins > 16 )
+						pins = 16;
+					u->out[oep].endpoint = p1[2];
+					u->out[oep].cableId = ( 1 << pins ) - 1;
+					if ( u->out[oep].cableId ) oep ++;
+					if ( oep < 15 ) {
+						u->out[oep].endpoint = -1;
+						u->out[oep].cableId = -1;
+					}
+				}
+			}
+	
+		}
+	}
+
+	if ( !iep && ! oep ) {
+		goto error_end;
+	}
+
+	return u;
+
+error_end:
+	if ( u ) kfree(u);
+	return NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/** Returns number between 0 and 16.
+ *
+ **/
+static int on_bits( unsigned short v )
+{
+	int i;
+	int ret=0;
+
+	for ( i=0 ; i<16 ; i++ ) {
+		if ( v & (1<<i) ) ret++;
+	}
+
+	return ret;
+}
+
+
+/** USB-device will be interrogated for altSetting.
+ *
+ * Returns negative on error.
+ * Called by allocUsbMidiDev();
+ *
+ **/
+
+static int get_alt_setting( struct usb_device *d, int ifnum )
+{
+	int alts, alt=0;
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *ep;
+	int epin, epout;
+	int i;
+
+	alts = d->actconfig->interface[ifnum].num_altsetting;
+
+	for ( alt=0 ; alt<alts ; alt++ ) {
+		interface = &d->actconfig->interface[ifnum].altsetting[alt];
+		epin = -1;
+		epout = -1;
+
+		for ( i=0 ; i<interface->bNumEndpoints ; i++ ) {
+			ep = &interface->endpoint[i];
+			if ( (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ) {
+				continue;
+			}
+			if ( (ep->bEndpointAddress & USB_DIR_IN) && epin < 0 ) {
+				epin = i;
+			} else if ( epout < 0 ) {
+				epout = i;
+			}
+			if ( epin >= 0 && epout >= 0 ) {
+				return alt;
+			}
+		}
+	}
+
+	return -ENODEV;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/** Returns 0 if successful in allocating and registering internal structures.
+ * Returns negative on failure.
+ * Calls allocMidiDev which additionally registers /dev/midiXX devices.
+ * Writes messages on success to indicate which /dev/midiXX is which physical
+ * endpoint.
+ *
+ **/
+static int alloc_usb_midi_device( struct usb_device *d, struct usb_midi_state *s, struct usb_midi_device *u )
+{
+	struct usb_mididev **mdevs=NULL;
+	struct midi_in_endpoint *mins[15], *min;
+	struct midi_out_endpoint *mouts[15], *mout;
+	int inDevs=0, outDevs=0;
+	int inEndpoints=0, outEndpoints=0;
+	int inEndpoint, outEndpoint;
+	int inCableId, outCableId;
+	int i;
+	int devices = 0;
+	int alt = 0;
+
+	/* Obtain altSetting or die.. */
+	alt = u->altSetting;
+	if ( alt < 0 ) {
+		alt = get_alt_setting( d, u->interface );
+	}
+	if ( alt < 0 ) { return -ENXIO; }
+
+	/* Configure interface */
+	if ( usb_set_interface( d, u->interface, alt ) < 0 ) {
+		return -ENXIO;
+	}
+
+	for ( i = 0 ; i < 15 ; i++ ) {
+		mins[i] = NULL;
+		mouts[i] = NULL;
+	}
+
+	/* Begin Allocation */
+	while( inEndpoints < 15
+	       && inDevs < maxdevices
+	       && u->in[inEndpoints].cableId >= 0 ) {
+		inDevs += on_bits((unsigned short)u->in[inEndpoints].cableId);
+		mins[inEndpoints] = alloc_midi_in_endpoint( d, u->in[inEndpoints].endpoint );
+		if ( mins[inEndpoints] == NULL ) { goto error_end; }
+		inEndpoints++;
+	}
+
+	while( outEndpoints < 15
+	       && outDevs < maxdevices
+	       && u->out[outEndpoints].cableId >= 0 ) {
+		outDevs += on_bits((unsigned short)u->out[outEndpoints].cableId);
+		mouts[outEndpoints] = alloc_midi_out_endpoint( d, u->out[outEndpoints].endpoint );
+		if ( mouts[outEndpoints] == NULL ) { goto error_end; }
+		outEndpoints++;
+	}
+
+	devices = inDevs > outDevs ? inDevs : outDevs;
+	devices = maxdevices > devices ? devices : maxdevices;
+
+	/* obtain space for device name (iProduct) if not known. */
+	if ( ! u->deviceName ) {
+		mdevs = (struct usb_mididev **)
+			kmalloc(sizeof(struct usb_mididevs *)*devices
+				+ sizeof(char) * 256, GFP_KERNEL);
+	} else {
+		mdevs = (struct usb_mididev **)
+			kmalloc(sizeof(struct usb_mididevs *)*devices, GFP_KERNEL);
+	}
+
+	if ( !mdevs ) {
+		/* devices = 0; */
+		/* mdevs = NULL; */
+		goto error_end;
+	}
+	for ( i=0 ; i<devices ; i++ ) {
+		mdevs[i] = NULL;
+	}
+
+	/* obtain device name (iProduct) if not known. */
+	if ( ! u->deviceName ) {
+		u->deviceName = (char *) (mdevs + devices);
+		if ( ! d->have_langid && d->descriptor.iProduct) {
+			alt = usb_get_string(d, 0, 0, u->deviceName, 250);
+			if (alt < 0) {
+				printk(KERN_INFO "error getting string descriptor 0 (error=%d)\n", alt);
+			} else if (u->deviceName[0] < 4) {
+				printk(KERN_INFO "string descriptor 0 too short (length = %d)\n", alt);
+			} else {
+				printk(KERN_INFO "string descriptor 0 found (length = %d)\n", alt);
+				for(; alt >= 4; alt -= 2) {
+					i = u->deviceName[alt-2] | (u->deviceName[alt-1]<< 8);
+					printk(KERN_INFO "usb-midi: langid(%d) 0x%04x\n",
+					       (alt-4) >> 1, i);
+					if ( ( ( i ^ ulangid ) & 0xff ) == 0 ) {
+						d->have_langid = 1;
+						d->string_langid = i;
+						printk(KERN_INFO "usb-midi: langid(match) 0x%04x\n", i);
+						if ( i == ulangid )
+							break;
+					}
+				}
+			}
+		}
+		u->deviceName[0] = (char) 0;
+		if (d->descriptor.iProduct) {
+			printk(KERN_INFO "usb-midi: fetchString(%d)\n", d->descriptor.iProduct);
+			alt = usb_string(d, d->descriptor.iProduct, u->deviceName, 255);
+			if( alt < 0 ) {
+				u->deviceName[0] = (char) 0;
+			}
+			printk(KERN_INFO "usb-midi: fetchString = %d\n", alt);
+		} 
+		/* Failsafe */
+		if ( !u->deviceName[0] ) {
+			if ( d->descriptor.idVendor == USB_VENDOR_ID_ROLAND ) {
+				strcpy(u->deviceName, "Unknown Roland");
+			} else if ( d->descriptor.idVendor == USB_VENDOR_ID_STEINBERG  ) {
+				strcpy(u->deviceName, "Unknown Steinberg");
+			} else if ( d->descriptor.idVendor == USB_VENDOR_ID_YAMAHA ) {
+				strcpy(u->deviceName, "Unknown Yamaha");
+			} else {
+				strcpy(u->deviceName, "Unknown");
+			}
+		}
+	}
+
+	inEndpoint  = 0; inCableId  = -1;
+	outEndpoint = 0; outCableId = -1;
+
+	for ( i=0 ; i<devices ; i++ ) {
+		for ( inCableId ++ ;
+		      inEndpoint <15
+			      && mins[inEndpoint] 
+			      && !(u->in[inEndpoint].cableId & (1<<inCableId)) ;
+		      inCableId++ ) {
+			if ( inCableId >= 16 ) {
+				inEndpoint  ++;
+				inCableId  = 0;
+			}
+		}
+		min  = mins[inEndpoint];
+		for ( outCableId ++ ;
+		      outEndpoint <15
+			      && mouts[outEndpoint] 
+			      && !(u->out[outEndpoint].cableId & (1<<outCableId)) ;
+		      outCableId++ ) {
+			if ( outCableId >= 16 ) {
+				outEndpoint  ++;
+				outCableId  = 0;
+			}
+		}
+		mout = mouts[outEndpoint];
+
+		mdevs[i] = allocMidiDev( s, min, mout, inCableId, outCableId );
+		if ( mdevs[i] == NULL ) { goto error_end; }
+
+	}
+
+	/* Success! */
+	for ( i=0 ; i<devices ; i++ ) {
+		list_add_tail( &mdevs[i]->list, &s->midiDevList );
+	}
+	for ( i=0 ; i<inEndpoints ; i++ ) {
+		list_add_tail( &mins[i]->list, &s->inEndpointList );
+	}
+	for ( i=0 ; i<outEndpoints ; i++ ) {
+		list_add_tail( &mouts[i]->list, &s->outEndpointList );
+	}
+
+	printk(KERN_INFO "usbmidi: found [ %s ] (0x%04x:0x%04x), attached:\n", u->deviceName, u->idVendor, u->idProduct );
+	for ( i=0 ; i<devices ; i++ ) {
+		int dm = (mdevs[i]->dev_midi-2)>>4;
+		if ( mdevs[i]->mout.ep != NULL && mdevs[i]->min.ep != NULL ) {
+			printk(KERN_INFO "usbmidi: /dev/midi%02d: in (ep:%02x cid:%2d bufsiz:%2d) out (ep:%02x cid:%2d bufsiz:%2d)\n", 
+			       dm,
+			       mdevs[i]->min.ep->endpoint|USB_DIR_IN, mdevs[i]->min.cableId, mdevs[i]->min.ep->recvBufSize,
+			       mdevs[i]->mout.ep->endpoint, mdevs[i]->mout.cableId, mdevs[i]->mout.ep->bufSize);
+		} else if ( mdevs[i]->min.ep != NULL ) {
+			printk(KERN_INFO "usbmidi: /dev/midi%02d: in (ep:%02x cid:%2d bufsiz:%02d)\n", 
+			       dm,
+			       mdevs[i]->min.ep->endpoint|USB_DIR_IN, mdevs[i]->min.cableId, mdevs[i]->min.ep->recvBufSize);
+		} else if ( mdevs[i]->mout.ep != NULL ) {
+			printk(KERN_INFO "usbmidi: /dev/midi%02d: out (ep:%02x cid:%2d bufsiz:%02d)\n", 
+			       dm,
+			       mdevs[i]->mout.ep->endpoint, mdevs[i]->mout.cableId, mdevs[i]->mout.ep->bufSize);
+		}
+	}
+
+	kfree(mdevs);
+	return 0;
+
+ error_end:
+	if ( mdevs != NULL && devices > 0 ) {
+		for ( i=0 ; i<devices ; i++ ) {
+			if ( mdevs[i] != NULL ) {
+				unregister_sound_midi( mdevs[i]->dev_midi );
+				kfree(mdevs[i]);
+			}
+		}
+		kfree(mdevs);
+	}
+
+	for ( i=0 ; i<15 ; i++ ) {
+		if ( mins[i] != NULL ) {
+			remove_midi_in_endpoint( mins[i] );
+		}
+		if ( mouts[i] != NULL ) {
+			remove_midi_out_endpoint( mouts[i] );
+		}
+	}
+
+	return -ENOMEM;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/** Attempt to scan YAMAHA's device descriptor and detect correct values of
+ *  them.
+ *  Return 0 on succes, negative on failure.
+ *  Called by usb_midi_probe();
+ **/
+
+static int detect_yamaha_device( struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s)
+{
+	struct usb_config_descriptor    *c = d->actconfig;
+	struct usb_interface_descriptor *interface;
+	struct usb_midi_device *u;
+	unsigned char buf[USB_DT_CONFIG_SIZE], *buffer;
+	int bufSize;
+	int i;
+	int alts=-1;
+	int ret;
+
+	if (d->descriptor.idVendor != USB_VENDOR_ID_YAMAHA) {
+		return -EINVAL;
+	}
+
+	for ( i=0 ; i < c->interface[ifnum].num_altsetting; i++ ) {
+		interface = c->interface[ifnum].altsetting + i;
+
+		if ( interface->bInterfaceClass != 255 ||
+		     interface->bInterfaceSubClass != 0 )
+			continue;
+		alts = i;
+	}
+	if ( alts == -1 ) {
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "usb-midi: Found YAMAHA USB-MIDI device on dev %04x:%04x, iface %d\n",
+	       d->descriptor.idVendor, d->descriptor.idProduct, ifnum);
+
+	for ( i=0 ; i < d->descriptor.bNumConfigurations ; i++ ) {
+		if ( d->config+i == c ) goto configfound;
+	}
+
+	printk(KERN_INFO "usb-midi: Config not found.\n");
+
+	return -EINVAL;
+
+ configfound:
+
+	/* this may not be necessary. */
+	if ( usb_set_configuration( d, c->bConfigurationValue ) < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not set config.\n");
+		return -EINVAL;
+	}
+
+	ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buf, USB_DT_CONFIG_SIZE );
+	if ( ret < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not get config (error=%d).\n", ret);
+		return -EINVAL;
+	}
+	if ( buf[1] != USB_DT_CONFIG || buf[0] < USB_DT_CONFIG_SIZE ) {
+		printk(KERN_INFO "usb-midi: config not as expected.\n");
+		return -EINVAL;
+	}
+	bufSize = buf[2] | buf[3]<<8;
+	buffer = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);
+	if ( !buffer ) {
+		printk(KERN_INFO "usb-midi: Could not allocate memory.\n");
+		return -EINVAL;
+	}
+	ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buffer, bufSize );
+	if ( ret < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not get full config (error=%d).\n", ret);
+		kfree(buffer);
+		return -EINVAL;
+	}
+
+	u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 1);
+	kfree(buffer);
+	if ( u == NULL ) {
+		return -EINVAL;
+	}
+
+	ret = alloc_usb_midi_device( d, s, u );
+
+	kfree(u);
+
+	return ret;
+}
+
+
+/** Scan table of known devices which are only partially compliant with 
+ * the MIDIStreaming specification.
+ * Called by usb_midi_probe();
+ *
+ **/
+
+static int detect_vendor_specific_device( struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s )
+{
+	struct usb_midi_device *u;
+	int i;
+	int ret = -ENXIO;
+
+	for ( i=0; i<VENDOR_SPECIFIC_USB_MIDI_DEVICES ; i++ ) {
+		u=&(usb_midi_devices[i]);
+    
+		if ( d->descriptor.idVendor != u->idVendor ||
+		     d->descriptor.idProduct != u->idProduct ||
+		     ifnum != u->interface )
+			continue;
+
+		ret = alloc_usb_midi_device( d, s, u );
+		break;
+	}
+
+	return ret;
+}
+
+
+/** Attempt to match any config of an interface to a MIDISTREAMING interface.
+ *  Returns 0 on success, negative on failure.
+ * Called by usb_midi_probe();
+ **/
+static int detect_midi_subclass(struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s)
+{
+	struct usb_config_descriptor    *c = d->actconfig;
+	struct usb_interface_descriptor *interface;
+	struct usb_midi_device *u;
+	unsigned char buf[USB_DT_CONFIG_SIZE], *buffer;
+	int bufSize;
+	int i;
+	int alts=-1;
+	int ret;
+
+	for ( i=0 ; i < c->interface[ifnum].num_altsetting; i++ ) {
+		interface = c->interface[ifnum].altsetting + i;
+
+		if ( interface->bInterfaceClass != USB_CLASS_AUDIO ||
+		     interface->bInterfaceSubClass != USB_SUBCLASS_MIDISTREAMING )
+			continue;
+		alts = i;
+	}
+	if ( alts == -1 ) {
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "usb-midi: Found MIDISTREAMING on dev %04x:%04x, iface %d\n",
+	       d->descriptor.idVendor, d->descriptor.idProduct, ifnum);
+
+	for ( i=0 ; i < d->descriptor.bNumConfigurations ; i++ ) {
+		if ( d->config+i == c ) goto configfound;
+	}
+
+	printk(KERN_INFO "usb-midi: Config not found.\n");
+
+	return -EINVAL;
+
+ configfound:
+
+	/* this may not be necessary. */
+	if ( usb_set_configuration( d, c->bConfigurationValue ) < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not set config.\n");
+		return -EINVAL;
+	}
+
+	/* From USB Spec v2.0, Section 9.5.
+	   If the class or vendor specific descriptors use the same format
+	   as standard descriptors (e.g., start with a length byte and
+	   followed by a type byte), they must be returned interleaved with
+	   standard descriptors in the configuration information returned by
+	   a GetDescriptor(Configuration) request. In this case, the class
+	   or vendor-specific descriptors must follow a related standard
+	   descriptor they modify or extend.
+	*/
+
+	ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buf, USB_DT_CONFIG_SIZE );
+	if ( ret < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not get config (error=%d).\n", ret);
+		return -EINVAL;
+	}
+	if ( buf[1] != USB_DT_CONFIG || buf[0] < USB_DT_CONFIG_SIZE ) {
+		printk(KERN_INFO "usb-midi: config not as expected.\n");
+		return -EINVAL;
+	}
+	bufSize = buf[2] | buf[3]<<8;
+	buffer = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);
+	if ( !buffer ) {
+		printk(KERN_INFO "usb-midi: Could not allocate memory.\n");
+		return -EINVAL;
+	}
+	ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buffer, bufSize );
+	if ( ret < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not get full config (error=%d).\n", ret);
+		kfree(buffer);
+		return -EINVAL;
+	}
+
+	u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 0);
+	kfree(buffer);
+	if ( u == NULL ) {
+		return -EINVAL;
+	}
+
+	ret = alloc_usb_midi_device( d, s, u );
+
+	kfree(u);
+
+	return ret;
+}
+
+
+/** When user has requested a specific device, match it exactly.
+ *
+ * Uses uvendor, uproduct, uinterface, ualt, umin, umout and ucable.
+ * Called by usb_midi_probe();
+ *
+ **/
+static int detect_by_hand(struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s)
+{
+	struct usb_midi_device u;
+
+	if ( d->descriptor.idVendor != uvendor ||
+	     d->descriptor.idProduct != uproduct ||
+	     ifnum != uinterface ) {
+		return -EINVAL;
+	}
+
+	if ( ualt < 0 ) { ualt = -1; }
+
+	if ( umin   < 0 || umin   > 15 ) { umin   = 0x01 | USB_DIR_IN; }
+	if ( umout  < 0 || umout  > 15 ) { umout  = 0x01; }
+	if ( ucable < 0 || ucable > 15 ) { ucable = 0; }
+
+	u.deviceName = 0; /* A flag for alloc_usb_midi_device to get device name
+			     from device. */
+	u.idVendor   = uvendor;
+	u.idProduct  = uproduct;
+	u.interface  = uinterface;
+	u.altSetting = ualt;
+
+	u.in[0].endpoint    = umin;
+	u.in[0].cableId     = (1<<ucable);
+
+	u.out[0].endpoint   = umout;
+	u.out[0].cableId    = (1<<ucable);
+
+	return alloc_usb_midi_device( d, s, &u );
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+
+static void *usb_midi_probe(struct usb_device *dev, unsigned int ifnum,
+			    const struct usb_device_id *id)
+{
+	struct usb_midi_state *s;
+
+	s = (struct usb_midi_state *)kmalloc(sizeof(struct usb_midi_state), GFP_KERNEL);
+	if ( !s ) { return NULL; }
+
+	memset( s, 0, sizeof(struct usb_midi_state) );
+	INIT_LIST_HEAD(&s->midiDevList);
+	INIT_LIST_HEAD(&s->inEndpointList);
+	INIT_LIST_HEAD(&s->outEndpointList);
+	s->usbdev = dev;
+	s->count  = 0;
+	spin_lock_init(&s->lock);
+
+	if (
+		detect_by_hand( dev, ifnum, s ) &&
+		detect_midi_subclass( dev, ifnum, s ) &&
+		detect_vendor_specific_device( dev, ifnum, s ) &&
+		detect_yamaha_device( dev, ifnum, s) ) {
+		kfree(s);
+		return NULL;
+	}
+
+	down(&open_sem);
+	list_add_tail(&s->mididev, &mididevs);
+	up(&open_sem);
+
+#ifdef MOD_INC_EACH_PROBE
+	MOD_INC_USE_COUNT;
+#endif
+
+	return s;
+}
+
+
+static void usb_midi_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct usb_midi_state *s = (struct usb_midi_state *)ptr;
+	struct list_head      *list;
+	struct usb_mididev    *m;
+
+	if ( s == (struct usb_midi_state *)-1 ) {
+		return;
+	}
+	if ( !s->usbdev ) {
+		return;
+	}
+	down(&open_sem);
+	list_del(&s->mididev);
+	INIT_LIST_HEAD(&s->mididev);
+	s->usbdev = NULL;
+
+	for ( list = s->midiDevList.next; list != &s->midiDevList; list = list->next ) {
+		m = list_entry(list, struct usb_mididev, list);
+		wake_up(&(m->min.ep->wait));
+		wake_up(&(m->mout.ep->wait));
+		if ( m->dev_midi >= 0 ) {
+			unregister_sound_midi(m->dev_midi);
+		}
+		m->dev_midi = -1;
+	}
+	release_midi_device(s);
+	wake_up(&open_wait);
+#ifdef MOD_INC_EACH_PROBE
+	MOD_DEC_USE_COUNT;
+#endif
+
+	return;
+}
+
+
+
+static struct usb_driver usb_midi_driver = {
+	name: "midi",
+	probe: usb_midi_probe,
+	disconnect: usb_midi_disconnect,
+	id_table:	NULL, 			/* check all devices */
+	driver_list: LIST_HEAD_INIT(usb_midi_driver.driver_list)
+};
+
+/* ------------------------------------------------------------------------- */
+
+int __init usb_midi_init(void)
+{
+	if ( usb_register(&usb_midi_driver) < 0 )
+		return -1;
+
+	return 0;
+
+}
+
+void __exit usb_midi_exit(void)
+{
+	usb_deregister(&usb_midi_driver);
+}
+
+module_init(usb_midi_init) ;
+module_exit(usb_midi_exit) ;
+
+#ifdef HAVE_ALSA_SUPPORT
+#define SNDRV_MAIN_OBJECT_FILE
+#include "../../include/driver.h"
+#include "../../include/control.h"
+#include "../../include/info.h"
+#include "../../include/cs46xx.h"
+
+/* ------------------------------------------------------------------------- */
+
+static int snd_usbmidi_input_close(snd_rawmidi_substream_t * substream)
+{
+	return 0;
+}
+
+static int snd_usbmidi_input_open(snd_rawmidi_substream_t * substream )
+{
+	return 0;
+}
+
+static void snd_usbmidi_input_trigger(snd_rawmidi_substream_t * substream, int up)
+{
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+static int snd_usbmidi_output_close(snd_rawmidi_substream_t * substream)
+{
+	return 0;
+}
+
+static int snd_usbmidi_output_open(snd_rawmidi_substream_t * substream)
+{
+	return 0;
+}
+
+static void snd_usb_midi_output_trigger(snd_rawmidi_substream_t * substream,
+					int up)
+{
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static snd_rawmidi_ops_t snd_usbmidi_output =
+{
+        open:           snd_usbmidi_output_open,
+        close:          snd_usbmidi_output_close,
+        trigger:        snd_usbmidi_output_trigger,
+};
+static snd_rawmidi_ops_t snd_usbmidi_input =
+{
+        open:           snd_usbmidi_input_open,
+        close:          snd_usbmidi_input_close,
+        trigger:        snd_usbmidi_input_trigger,
+};
+
+int snd_usbmidi_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rrawmidi)
+{
+	snd_rawmidi_t *rmidi;
+	int err;
+
+	if (rrawmidi)
+		*rrawmidi = NULL;
+	if ((err = snd_rawmidi_new(chip->card, "USB-MIDI", device, 1, 1, &rmidi)) < 0)
+		return err;
+	strcpy(rmidi->name, "USB-MIDI");
+
+	snd_rawmidi_set_ops( rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usbmidi_output );
+	snd_rawmidi_set_ops( rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_usbmidi_input );
+
+	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
+
+	rmidi->private_data = chip;
+	chip->rmidi = rmidi;
+	if (rrawmidi)
+		*rrawmidi = NULL;
+
+	return 0;
+}
+
+int snd_usbmidi_create( snd_card_t * card,
+			struct pci_dev * pci,
+			usbmidi_t ** rchip )
+{
+	usbmidi_t *chip;
+	int err, idx;
+	snd_region_t *region;
+	static snd_device_opt_t ops = {
+		dev_free: snd_usbmidi_dev_free,
+	};
+
+	*rchip = NULL;
+	chip = snd_magic_kcalloc( usbmidi_t, 0, GFP_KERNEL );
+	if ( chip == NULL )
+		return -ENOMEM;
+}
+
+EXPORT_SYMBOL(snd_usbmidi_create);
+EXPORT_SYMBOL(snd_usbmidi_midi);
+#endif /* HAVE_ALSA_SUPPORT */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/usb-midi.h linux-2.4.20/drivers/usb/usb-midi.h
--- linux-2.4.19/drivers/usb/usb-midi.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/usb-midi.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,143 @@
+/*
+  usb-midi.h  --  USB-MIDI driver
+
+  Copyright (C) 2001
+      NAGANO Daisuke <breeze.nagano@nifty.ne.jp>
+
+  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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* ------------------------------------------------------------------------- */
+
+#ifndef _USB_MIDI_H_
+#define _USB_MIDI_H_
+
+#ifndef USB_SUBCLASS_MIDISTREAMING
+#define USB_SUBCLASS_MIDISTREAMING	3
+#endif
+
+#define USB_DT_CS_DEVICE		0x21
+#define USB_DT_CS_CONFIG		0x22
+#define USB_DT_CS_STRING		0x23
+#define USB_DT_CS_INTERFACE		0x24
+#define USB_DT_CS_ENDPOINT		0x25
+
+/* ------------------------------------------------------------------------- */
+/* Roland MIDI Devices */
+
+#define USB_VENDOR_ID_ROLAND		0x0582
+#define USBMIDI_ROLAND_UA100G		0x0000
+#define USBMIDI_ROLAND_MPU64		0x0002
+#define USBMIDI_ROLAND_SC8850		0x0003
+#define USBMIDI_ROLAND_UM2		0x0005
+#define USBMIDI_ROLAND_UM1		0x0009
+#define USBMIDI_ROLAND_PC300		0x0008
+
+/* YAMAHA MIDI Devices */
+#define USB_VENDOR_ID_YAMAHA		0x0499
+#define USBMIDI_YAMAHA_MU1000		0x1001
+
+/* Steinberg MIDI Devices */
+#define USB_VENDOR_ID_STEINBERG		0x0763
+#define USBMIDI_STEINBERG_USB2MIDI	0x1001
+
+/* ------------------------------------------------------------------------- */
+/* Supported devices */
+
+struct usb_midi_endpoint {
+	int  endpoint;
+	int  cableId; /* if bit-n == 1 then cableId-n is enabled (n: 0 - 15) */
+};
+
+struct usb_midi_device {
+	char  *deviceName;
+
+	int    idVendor;
+	int    idProduct;
+	int    interface;
+	int    altSetting; /* -1: auto detect */
+
+	struct usb_midi_endpoint in[15];
+	struct usb_midi_endpoint out[15];
+};
+
+static struct usb_midi_device usb_midi_devices[] = {
+  { /* Roland UM-1 */
+    "Roland UM-1",
+    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1, 2, -1,
+    { { 0x81, 1 }, {-1, -1} },
+    { { 0x01, 1,}, {-1, -1} },
+  },
+
+  { /* Roland UM-2 */
+    "Roland UM-2" ,
+    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2, 2, -1,
+    { { 0x81, 3 }, {-1, -1} },
+    { { 0x01, 3,}, {-1, -1} },
+  },
+
+/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/
+  { /* Roland UA-100 */
+    "Roland UA-100",
+    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G, 2, -1,
+    { { 0x82, 7 }, {-1, -1} }, /** cables 0,1 and 2 for SYSEX **/
+    { { 0x02, 7 }, {-1, -1} },
+  },
+
+/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/
+  { /* Roland SC8850 */
+    "Roland SC8850",
+    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850, 2, -1,
+    { { 0x81, 15 }, {-1, -1} }, /** cables 0,1,2, and 3 **/
+    { { 0x01, 15 }, {-1, -1} },
+  },
+
+  { /* YAMAHA MU1000 */
+    "YAMAHA MU1000",
+    USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000, 0, -1, 
+    { { 0x81, 1 }, {-1, -1} },
+    { { 0x01, 15 }, {-1, -1} },
+  },
+  { /* Roland PC-300 */
+    "Roland PC-300",
+    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300, 2, -1, 
+    { { 0x81, 1 }, {-1, -1} },
+    { { 0x01, 1 }, {-1, -1} },
+  }
+};
+
+#define VENDOR_SPECIFIC_USB_MIDI_DEVICES (sizeof(usb_midi_devices)/sizeof(struct usb_midi_device))
+
+/* for Hot-Plugging */
+
+static struct usb_device_id usb_midi_ids [] = {
+	{ match_flags: (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
+	  bInterfaceClass: USB_CLASS_AUDIO, bInterfaceSubClass: USB_SUBCLASS_MIDISTREAMING},
+	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1    ) },
+	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2    ) },
+	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G ) },
+	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300 ) },
+	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850 ) },
+	{ USB_DEVICE( USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000 ) },
+/*	{ USB_DEVICE( USB_VENDOR_ID_STEINBERG, USBMIDI_STEINBERG_USB2MIDI ) },*/
+	{ } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_midi_ids);
+
+/* ------------------------------------------------------------------------- */
+#endif /* _USB_MIDI_H_ */
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/usb-ohci.c linux-2.4.20/drivers/usb/usb-ohci.c
--- linux-2.4.19/drivers/usb/usb-ohci.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/usb-ohci.c	2002-10-29 11:18:34.000000000 +0000
@@ -78,6 +78,7 @@
 
 #include "usb-ohci.h"
 
+#include "hcd.h"
 
 #ifdef CONFIG_PMAC_PBOOK
 #include <asm/machdep.h>
@@ -178,7 +179,7 @@
 	kfree (urb_priv);
 }
  
-static void urb_rm_priv_locked (urb_t * urb) 
+static void urb_rm_priv_locked (struct urb * urb) 
 {
 	urb_priv_t * urb_priv = urb->hcpriv;
 	
@@ -212,7 +213,7 @@
 	}
 }
 
-static void urb_rm_priv (urb_t * urb)
+static void urb_rm_priv (struct urb * urb)
 {
 	unsigned long flags;
 
@@ -229,7 +230,7 @@
 /* debug| print the main components of an URB     
  * small: 0) header + data packets 1) just header */
  
-static void urb_print (urb_t * urb, char * str, int small)
+static void urb_print (struct urb * urb, char * str, int small)
 {
 	unsigned int pipe= urb->pipe;
 	
@@ -384,6 +385,8 @@
 	__u32			temp, ndp, i;
 
 	temp = roothub_a (controller);
+	if (temp == ~(u32)0)
+		return;
 	ndp = (temp & RH_A_NDP);
 
 	if (verbose) {
@@ -458,10 +461,10 @@
 
 /* return a request to the completion handler */
  
-static int sohci_return_urb (struct ohci *hc, urb_t * urb)
+static int sohci_return_urb (struct ohci *hc, struct urb * urb)
 {
 	urb_priv_t * urb_priv = urb->hcpriv;
-	urb_t * urbt;
+	struct urb * urbt;
 	unsigned long flags;
 	int i;
 	
@@ -536,7 +539,7 @@
 
 /* get a transfer request */
  
-static int sohci_submit_urb (urb_t * urb)
+static int sohci_submit_urb (struct urb * urb)
 {
 	ohci_t * ohci;
 	ed_t * ed;
@@ -720,7 +723,7 @@
 /* deactivate all TDs and remove the private part of the URB */
 /* interrupt callers must use async unlink mode */
 
-static int sohci_unlink_urb (urb_t * urb)
+static int sohci_unlink_urb (struct urb * urb)
 {
 	unsigned long flags;
 	ohci_t * ohci;
@@ -1295,7 +1298,7 @@
 static void
 td_fill (ohci_t * ohci, unsigned int info,
 	dma_addr_t data, int len,
-	urb_t * urb, int index)
+	struct urb * urb, int index)
 {
 	volatile td_t  * td, * td_pt;
 	urb_priv_t * urb_priv = urb->hcpriv;
@@ -1344,7 +1347,7 @@
  
 /* prepare all TDs of a transfer */
 
-static void td_submit_urb (urb_t * urb)
+static void td_submit_urb (struct urb * urb)
 { 
 	urb_priv_t * urb_priv = urb->hcpriv;
 	ohci_t * ohci = (ohci_t *) urb->dev->bus->hcpriv;
@@ -1457,7 +1460,7 @@
 {
 	__u32 tdINFO, tdBE, tdCBP;
  	__u16 tdPSW;
- 	urb_t * urb = td->urb;
+ 	struct urb * urb = td->urb;
  	urb_priv_t * urb_priv = urb->hcpriv;
 	int dlen = 0;
 	int cc = 0;
@@ -1498,7 +1501,7 @@
 
 /* handle an urb that is being unlinked */
 
-static void dl_del_urb (urb_t * urb)
+static void dl_del_urb (struct urb * urb)
 {
 	wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait;
 
@@ -1510,6 +1513,8 @@
 			urb->complete (urb);
 	} else {
 		urb->status = -ENOENT;
+		if (urb->complete)
+			urb->complete (urb);
 
 		/* unblock sohci_unlink_urb */
 		if (wait_head)
@@ -1587,7 +1592,7 @@
 		td_p = &ed->hwHeadP;
 
 		for (td = tdHeadP; td != tdTailP; td = td_next) { 
-			urb_t * urb = td->urb;
+			struct urb * urb = td->urb;
 			urb_priv_t * urb_priv = td->urb->hcpriv;
 			
 			td_next = dma_to_td (ohci, le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
@@ -1626,11 +1631,6 @@
 			if (tdHeadP == tdTailP) {
 				if (ed->state == ED_OPER)
 					ep_unlink(ohci, ed);
-				td_free (ohci, tdTailP);
-				ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP);
-				ed->state = ED_NEW;
-				hash_free_ed(ohci, ed);
-				--(usb_to_ohci (ohci->dev[edINFO & 0x7F]))->ed_cnt;
 			} else
    	 			ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
    	 	}
@@ -1675,7 +1675,7 @@
   	td_t * td_list_next = NULL;
 	ed_t * ed;
 	int cc = 0;
-	urb_t * urb;
+	struct urb * urb;
 	urb_priv_t * urb_priv;
  	__u32 tdINFO, edHeadP, edTailP;
  	
@@ -1851,7 +1851,7 @@
 {
 	int len; 
 
-	urb_t * urb = (urb_t *) ptr;
+	struct urb * urb = (struct urb *) ptr;
 	ohci_t * ohci = urb->dev->bus->hcpriv;
 
 	if (ohci->disabled)
@@ -1880,7 +1880,7 @@
 
 /* Root Hub INTs are polled by this timer */
 
-static int rh_init_int_timer (urb_t * urb) 
+static int rh_init_int_timer (struct urb * urb) 
 {
 	ohci_t * ohci = urb->dev->bus->hcpriv;
 
@@ -1905,12 +1905,12 @@
 
 /* request to virtual root hub */
 
-static int rh_submit_urb (urb_t * urb)
+static int rh_submit_urb (struct urb * urb)
 {
 	struct usb_device * usb_dev = urb->dev;
 	ohci_t * ohci = usb_dev->bus->hcpriv;
 	unsigned int pipe = urb->pipe;
-	devrequest * cmd = (devrequest *) urb->setup_packet;
+	struct usb_ctrlrequest * cmd = (struct usb_ctrlrequest *) urb->setup_packet;
 	void * data = urb->transfer_buffer;
 	int leni = urb->transfer_buffer_length;
 	int len = 0;
@@ -1934,10 +1934,10 @@
 		return 0;
 	}
 
-	bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
-	wValue        = le16_to_cpu (cmd->value);
-	wIndex        = le16_to_cpu (cmd->index);
-	wLength       = le16_to_cpu (cmd->length);
+	bmRType_bReq  = cmd->bRequestType | (cmd->bRequest << 8);
+	wValue        = le16_to_cpu (cmd->wValue);
+	wIndex        = le16_to_cpu (cmd->wIndex);
+	wLength       = le16_to_cpu (cmd->wLength);
 
 	switch (bmRType_bReq) {
 	/* Request Destination:
@@ -2111,7 +2111,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-static int rh_unlink_urb (urb_t * urb)
+static int rh_unlink_urb (struct urb * urb)
 {
 	ohci_t * ohci = urb->dev->bus->hcpriv;
  
@@ -2144,6 +2144,8 @@
 	int timeout = 30;
 	int smm_timeout = 50; /* 0,5 sec */
 	 	
+#ifndef __hppa__
+	/* PA-RISC doesn't have SMM, but PDC might leave IR set */
 	if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
 		writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
 		dbg("USB HC TakeOver from SMM");
@@ -2154,7 +2156,8 @@
 				return -1;
 			}
 		}
-	}	
+	}
+#endif	
 		
 	/* Disable HC interrupts */
 	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
@@ -2218,9 +2221,19 @@
 	writel (mask, &ohci->regs->intrstatus);
 
 #ifdef	OHCI_USE_NPS
-	/* required for AMD-756 and some Mac platforms */
-	writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
-		&ohci->regs->roothub.a);
+	if(ohci->flags & OHCI_QUIRK_SUCKYIO)
+	{
+		/* NSC 87560 at least requires different setup .. */
+		writel ((roothub_a (ohci) | RH_A_NOCP) &
+			~(RH_A_OCPM | RH_A_POTPGT | RH_A_PSM | RH_A_NPS),
+			&ohci->regs->roothub.a);
+	}
+	else
+	{
+		/* required for AMD-756 and some Mac platforms */
+		writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
+			&ohci->regs->roothub.a);
+	}
 	writel (RH_HS_LPSC, &ohci->regs->roothub.status);
 #endif	/* OHCI_USE_NPS */
 
@@ -2288,9 +2301,19 @@
 	struct ohci_regs * regs = ohci->regs;
  	int ints; 
 
-	if ((ohci->hcca->done_head != 0) && !(le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
+	/* avoid (slow) readl if only WDH happened */
+	if ((ohci->hcca->done_head != 0)
+			&& !(le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
 		ints =  OHCI_INTR_WDH;
-	} else if ((ints = (readl (&regs->intrstatus) & readl (&regs->intrenable))) == 0) {
+
+	/* cardbus/... hardware gone before remove() */
+	} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+		ohci->disabled++;
+		err ("%s device removed!", ohci->ohci_dev->slot_name);
+		return;
+
+	/* interrupt for some other device? */
+	} else if ((ints &= readl (&regs->intrenable)) == 0) {
 		return;
 	} 
 
@@ -2391,6 +2414,7 @@
 		kfree (ohci);
 		return NULL;
 	}
+	ohci->bus->bus_name = dev->slot_name;
 	ohci->bus->hcpriv = (void *) ohci;
 
 	return ohci;
@@ -2418,8 +2442,9 @@
 	}
 	pci_set_drvdata(ohci->ohci_dev, NULL);
 	if (ohci->bus) {
-		if (ohci->bus->busnum)
+		if (ohci->bus->busnum != -1)
 			usb_deregister_bus (ohci->bus);
+
 		usb_free_bus (ohci->bus);
 	}
 
@@ -2448,7 +2473,6 @@
 	void *mem_base, const struct pci_device_id *id)
 {
 	ohci_t * ohci;
-	u8 latency, limit;
 	char buf[8], *bufp = buf;
 	int ret;
 
@@ -2470,23 +2494,24 @@
 		return ret;
 	}
 	ohci->flags = id->driver_data;
+	
+	/* Check for NSC87560. We have to look at the bridge (fn1) to identify
+	   the USB (fn2). This quirk might apply to more or even all NSC stuff
+	   I don't know.. */
+	   
+	if(dev->vendor == PCI_VENDOR_ID_NS)
+	{
+		struct pci_dev *fn1  = pci_find_slot(dev->bus->number, PCI_DEVFN(PCI_SLOT(dev->devfn), 1));
+		if(fn1 && fn1->vendor == PCI_VENDOR_ID_NS && fn1->device == PCI_DEVICE_ID_NS_87560_LIO)
+			ohci->flags |= OHCI_QUIRK_SUCKYIO;
+		
+	}
+	
+	if (ohci->flags & OHCI_QUIRK_SUCKYIO)
+		printk (KERN_INFO __FILE__ ": Using NSC SuperIO setup\n");
 	if (ohci->flags & OHCI_QUIRK_AMD756)
 		printk (KERN_INFO __FILE__ ": AMD756 erratum 4 workaround\n");
 
-	/* bad pci latencies can contribute to overruns */ 
-	pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
-	if (latency) {
-		pci_read_config_byte (dev, PCI_MAX_LAT, &limit);
-		if (limit && limit < latency) {
-			dbg ("PCI latency reduced to max %d", limit);
-			pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit);
-			ohci->pci_latency = limit;
-		} else {
-			/* it might already have been reduced */
-			ohci->pci_latency = latency;
-		}
-	}
-
 	if (hc_reset (ohci) < 0) {
 		hc_release_ohci (ohci);
 		return -ENODEV;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/usb-ohci.h linux-2.4.20/drivers/usb/usb-ohci.h
--- linux-2.4.19/drivers/usb/usb-ohci.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/usb-ohci.h	2002-10-29 11:18:34.000000000 +0000
@@ -111,7 +111,7 @@
   	__u8 index;
   	struct ed * ed;
   	struct td * next_dl_td;
-  	urb_t * urb;
+  	struct urb * urb;
 
 	dma_addr_t td_dma;
 	dma_addr_t data_dma;
@@ -381,6 +381,7 @@
 	atomic_t resume_count;		/* defending against multiple resumes */
 	unsigned long flags;		/* for HC bugs */
 #define	OHCI_QUIRK_AMD756	0x01		/* erratum #4 */
+#define OHCI_QUIRK_SUCKYIO	0x02		/* NSC superio */
 
 	struct ohci_regs * regs;	/* OHCI controller's memory */
 	struct list_head ohci_hcd_list;	/* list of all ohci_hcd */
@@ -430,12 +431,12 @@
 static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load, int mem_flags);
 static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed);
 /* td */
-static void td_fill(ohci_t * ohci, unsigned int info, dma_addr_t data, int len, urb_t * urb, int index);
-static void td_submit_urb(urb_t * urb);
+static void td_fill(ohci_t * ohci, unsigned int info, dma_addr_t data, int len, struct urb * urb, int index);
+static void td_submit_urb(struct urb * urb);
 /* root hub */
-static int rh_submit_urb(urb_t * urb);
-static int rh_unlink_urb(urb_t * urb);
-static int rh_init_int_timer(urb_t * urb);
+static int rh_submit_urb(struct urb * urb);
+static int rh_unlink_urb(struct urb * urb);
+static int rh_init_int_timer(struct urb * urb);
 
 /*-------------------------------------------------------------------------*/
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/usb-uhci.c linux-2.4.20/drivers/usb/usb-uhci.c
--- linux-2.4.19/drivers/usb/usb-uhci.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/usb-uhci.c	2002-10-29 11:18:40.000000000 +0000
@@ -59,6 +59,8 @@
 #include "usb-uhci.h"
 #include "usb-uhci-debug.h"
 
+#include "hcd.h"
+
 /*
  * Version Information
  */
@@ -117,12 +119,12 @@
 // Suppress HC interrupt error messages for 5s
 #define ERROR_SUPPRESSION_TIME (HZ*5)
 
-_static int rh_submit_urb (urb_t *urb);
-_static int rh_unlink_urb (urb_t *urb);
+_static int rh_submit_urb (struct urb *urb);
+_static int rh_unlink_urb (struct urb *urb);
 _static int delete_qh (uhci_t *s, uhci_desc_t *qh);
-_static int process_transfer (uhci_t *s, urb_t *urb, int mode);
-_static int process_interrupt (uhci_t *s, urb_t *urb);
-_static int process_iso (uhci_t *s, urb_t *urb, int force);
+_static int process_transfer (uhci_t *s, struct urb *urb, int mode);
+_static int process_interrupt (uhci_t *s, struct urb *urb);
+_static int process_iso (uhci_t *s, struct urb *urb, int force);
 
 // How much URBs with ->next are walked
 #define MAX_NEXT_COUNT 2048
@@ -168,7 +170,7 @@
 }
 /*-------------------------------------------------------------------*/
 #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-_static void enable_desc_loop(uhci_t *s, urb_t *urb)
+_static void enable_desc_loop(uhci_t *s, struct urb *urb)
 {
 	unsigned long flags;
 
@@ -183,7 +185,7 @@
 	spin_unlock_irqrestore (&s->qh_lock, flags);
 }
 /*-------------------------------------------------------------------*/
-_static void disable_desc_loop(uhci_t *s, urb_t *urb)
+_static void disable_desc_loop(uhci_t *s, struct urb *urb)
 {
 	unsigned long flags;
 
@@ -204,7 +206,7 @@
 }
 #endif
 /*-------------------------------------------------------------------*/
-_static void queue_urb_unlocked (uhci_t *s, urb_t *urb)
+_static void queue_urb_unlocked (uhci_t *s, struct urb *urb)
 {
 	struct list_head *p=&urb->urb_list;
 #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
@@ -224,7 +226,7 @@
 	uhci_switch_timer_int(s);
 }
 /*-------------------------------------------------------------------*/
-_static void queue_urb (uhci_t *s, urb_t *urb)
+_static void queue_urb (uhci_t *s, struct urb *urb)
 {
 	unsigned long flags=0;
 
@@ -233,7 +235,7 @@
 	spin_unlock_irqrestore (&s->urb_list_lock, flags);
 }
 /*-------------------------------------------------------------------*/
-_static void dequeue_urb (uhci_t *s, urb_t *urb)
+_static void dequeue_urb (uhci_t *s, struct urb *urb)
 {
 #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
 	int type;
@@ -698,7 +700,7 @@
 //                         LOW LEVEL STUFF
 //          assembles QHs und TDs for control, bulk and iso
 /*-------------------------------------------------------------------*/
-_static int uhci_submit_control_urb (urb_t *urb)
+_static int uhci_submit_control_urb (struct urb *urb)
 {
 	uhci_desc_t *qh, *td;
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
@@ -815,7 +817,7 @@
 // For queued bulk transfers, two additional QH helpers are allocated (nqh, bqh)
 // Due to the linking with other bulk urbs, it has to be locked with urb_list_lock!
 
-_static int uhci_submit_bulk_urb (urb_t *urb, urb_t *bulk_urb)
+_static int uhci_submit_bulk_urb (struct urb *urb, struct urb *bulk_urb)
 {
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
 	urb_priv_t *urb_priv = urb->hcpriv, *upriv, *bpriv=NULL;
@@ -977,7 +979,7 @@
  looks a bit complicated because of all the bulk queueing goodies
 */
 
-_static void uhci_clean_transfer (uhci_t *s, urb_t *urb, uhci_desc_t *qh, int mode)
+_static void uhci_clean_transfer (uhci_t *s, struct urb *urb, uhci_desc_t *qh, int mode)
 {
 	uhci_desc_t *bqh, *nqh, *prevqh, *prevtd;
 	int now;
@@ -1031,7 +1033,7 @@
 		       urb, priv->prev_queued_urb,  priv->next_queued_urb, qh, bqh, priv->next_qh);	
        	
 		if (mode != CLEAN_TRANSFER_DELETION_MARK) {	// no work for cleanup at unlink-completion
-			urb_t *nurb;
+			struct urb *nurb;
 			unsigned long flags;
 
 			nurb = priv->next_queued_urb;
@@ -1069,7 +1071,7 @@
 }
 /*-------------------------------------------------------------------*/
 // Release bandwidth for Interrupt or Isoc. transfers 
-_static void uhci_release_bandwidth(urb_t *urb)
+_static void uhci_release_bandwidth(struct urb *urb)
 {       
 	if (urb->bandwidth) {
 		switch (usb_pipetype(urb->pipe)) {
@@ -1085,11 +1087,11 @@
 	}	
 }
 
-_static void uhci_urb_dma_sync(uhci_t *s, urb_t *urb, urb_priv_t *urb_priv)
+_static void uhci_urb_dma_sync(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
 {
 	if (urb_priv->setup_packet_dma)
 		pci_dma_sync_single(s->uhci_pci, urb_priv->setup_packet_dma,
-				    sizeof(devrequest), PCI_DMA_TODEVICE);
+				    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
 
 	if (urb_priv->transfer_buffer_dma)
 		pci_dma_sync_single(s->uhci_pci, urb_priv->transfer_buffer_dma,
@@ -1099,11 +1101,11 @@
 				    PCI_DMA_TODEVICE);
 }
 
-_static void uhci_urb_dma_unmap(uhci_t *s, urb_t *urb, urb_priv_t *urb_priv)
+_static void uhci_urb_dma_unmap(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
 {
 	if (urb_priv->setup_packet_dma) {
 		pci_unmap_single(s->uhci_pci, urb_priv->setup_packet_dma,
-				 sizeof(devrequest), PCI_DMA_TODEVICE);
+				 sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
 		urb_priv->setup_packet_dma = 0;
 	}
 	if (urb_priv->transfer_buffer_dma) {
@@ -1120,7 +1122,7 @@
    mode: UNLINK_ASYNC_STORE_URB: unlink and move URB into unlinked list
          UNLINK_ASYNC_DONT_STORE: unlink, don't move URB into unlinked list
 */
-_static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb, int mode)
+_static int uhci_unlink_urb_async (uhci_t *s,struct urb *urb, int mode)
 {
 	uhci_desc_t *qh;
 	urb_priv_t *urb_priv;
@@ -1165,7 +1167,7 @@
 }
 /*-------------------------------------------------------------------*/
 // kills an urb by unlinking descriptors and waiting for at least one frame
-_static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
+_static int uhci_unlink_urb_sync (uhci_t *s, struct urb *urb)
 {
 	uhci_desc_t *qh;
 	urb_priv_t *urb_priv;
@@ -1176,7 +1178,7 @@
 
 	if (urb->status == -EINPROGRESS) {
 
-		// move descriptors out the the running chains, dequeue urb
+		// move descriptors out of the running chains, dequeue urb
 		uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_DONT_STORE);
 
 		urb_priv = urb->hcpriv;
@@ -1229,7 +1231,7 @@
 _static void uhci_cleanup_unlink(uhci_t *s, int force)
 {
 	struct list_head *q;
-	urb_t *urb;
+	struct urb *urb;
 	struct usb_device *dev;
 	int now, type;
 	urb_priv_t *urb_priv;
@@ -1239,7 +1241,7 @@
 
 	while (q != &s->urb_unlinked) {
 
-		urb = list_entry (q, urb_t, urb_list);
+		urb = list_entry (q, struct urb, urb_list);
 
 		urb_priv = (urb_priv_t*)urb->hcpriv;
 		q = urb->urb_list.next;
@@ -1308,7 +1310,7 @@
 }
  
 /*-------------------------------------------------------------------*/
-_static int uhci_unlink_urb (urb_t *urb)
+_static int uhci_unlink_urb (struct urb *urb)
 {
 	uhci_t *s;
 	unsigned long flags=0;
@@ -1341,9 +1343,9 @@
 // In case of ASAP iso transfer, search the URB-list for already queued URBs
 // for this EP and calculate the earliest start frame for the new
 // URB (easy seamless URB continuation!)
-_static int find_iso_limits (urb_t *urb, unsigned int *start, unsigned int *end)
+_static int find_iso_limits (struct urb *urb, unsigned int *start, unsigned int *end)
 {
-	urb_t *u, *last_urb = NULL;
+	struct urb *u, *last_urb = NULL;
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
 	struct list_head *p;
 	int ret=-1;
@@ -1353,7 +1355,7 @@
 	p=s->urb_list.prev;
 
 	for (; p != &s->urb_list; p = p->prev) {
-		u = list_entry (p, urb_t, urb_list);
+		u = list_entry (p, struct urb, urb_list);
 		// look for pending URBs with identical pipe handle
 		// works only because iso doesn't toggle the data bit!
 		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && (u->status == -EINPROGRESS)) {
@@ -1375,7 +1377,7 @@
 /*-------------------------------------------------------------------*/
 // adjust start_frame according to scheduling constraints (ASAP etc)
 
-_static int iso_find_start (urb_t *urb)
+_static int iso_find_start (struct urb *urb)
 {
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
 	unsigned int now;
@@ -1433,7 +1435,7 @@
 // ASAP-flag set implicitely
 // if period==0, the transfer is only done once
 
-_static int uhci_submit_int_urb (urb_t *urb)
+_static int uhci_submit_int_urb (struct urb *urb)
 {
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
 	urb_priv_t *urb_priv = urb->hcpriv;
@@ -1493,7 +1495,7 @@
 	return 0;
 }
 /*-------------------------------------------------------------------*/
-_static int uhci_submit_iso_urb (urb_t *urb)
+_static int uhci_submit_iso_urb (struct urb *urb)
 {
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
 	urb_priv_t *urb_priv = urb->hcpriv;
@@ -1586,10 +1588,10 @@
 /*-------------------------------------------------------------------*/
 // returns: 0 (no transfer queued), urb* (this urb already queued)
  
-_static urb_t* search_dev_ep (uhci_t *s, urb_t *urb)
+_static struct urb* search_dev_ep (uhci_t *s, struct urb *urb)
 {
 	struct list_head *p;
-	urb_t *tmp;
+	struct urb *tmp;
 	unsigned int mask = usb_pipecontrol(urb->pipe) ? (~USB_DIR_IN) : (~0);
 
 	dbg("search_dev_ep:");
@@ -1597,7 +1599,7 @@
 	p=s->urb_list.next;
 
 	for (; p != &s->urb_list; p = p->next) {
-		tmp = list_entry (p, urb_t, urb_list);
+		tmp = list_entry (p, struct urb, urb_list);
 		dbg("urb: %p", tmp);
 		// we can accept this urb if it is not queued at this time 
 		// or if non-iso transfer requests should be scheduled for the same device and pipe
@@ -1610,13 +1612,13 @@
 	return 0;
 }
 /*-------------------------------------------------------------------*/
-_static int uhci_submit_urb (urb_t *urb)
+_static int uhci_submit_urb (struct urb *urb)
 {
 	uhci_t *s;
 	urb_priv_t *urb_priv;
 	int ret = 0, type;
 	unsigned long flags;
-	urb_t *queued_urb=NULL;
+	struct urb *queued_urb=NULL;
 	int bustime;
 		
 	if (!urb->dev || !urb->dev->bus)
@@ -1683,7 +1685,7 @@
 	
 	if (type == PIPE_CONTROL)
 		urb_priv->setup_packet_dma = pci_map_single(s->uhci_pci, urb->setup_packet,
-							    sizeof(devrequest), PCI_DMA_TODEVICE);
+							    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
 
 	if (urb->transfer_buffer_length)
 		urb_priv->transfer_buffer_dma = pci_map_single(s->uhci_pci,
@@ -1770,7 +1772,7 @@
 _static void uhci_check_timeouts(uhci_t *s)
 {
 	struct list_head *p,*p2;
-	urb_t *urb;
+	struct urb *urb;
 	int type;	
 
 	p = s->urb_list.prev;	
@@ -1780,7 +1782,7 @@
 
 		p2 = p;
 		p = p->prev;
-		urb = list_entry (p2, urb_t, urb_list);
+		urb = list_entry (p2, struct urb, urb_list);
 		type = usb_pipetype (urb->pipe);
 
 		hcpriv = (urb_priv_t*)urb->hcpriv;
@@ -1878,7 +1880,7 @@
 
 /*-------------------------------------------------------------------------*/
 /* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
-_static int rh_send_irq (urb_t *urb)
+_static int rh_send_irq (struct urb *urb)
 {
 	int len = 1;
 	int i;
@@ -1905,12 +1907,12 @@
 
 /*-------------------------------------------------------------------------*/
 /* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
-_static int rh_init_int_timer (urb_t *urb);
+_static int rh_init_int_timer (struct urb *urb);
 
 _static void rh_int_timer_do (unsigned long ptr)
 {
 	int len;
-	urb_t *urb = (urb_t*) ptr;
+	struct urb *urb = (struct urb*) ptr;
 	uhci_t *uhci = urb->dev->bus->hcpriv;
 
 	if (uhci->rh.send) {
@@ -1927,7 +1929,7 @@
 /*-------------------------------------------------------------------------*/
 /* Root Hub INTs are polled by this timer, polling interval 20ms */
 
-_static int rh_init_int_timer (urb_t *urb)
+_static int rh_init_int_timer (struct urb *urb)
 {
 	uhci_t *uhci = urb->dev->bus->hcpriv;
 
@@ -1961,12 +1963,12 @@
  *************************/
 
 
-_static int rh_submit_urb (urb_t *urb)
+_static int rh_submit_urb (struct urb *urb)
 {
 	struct usb_device *usb_dev = urb->dev;
 	uhci_t *uhci = usb_dev->bus->hcpriv;
 	unsigned int pipe = urb->pipe;
-	devrequest *cmd = (devrequest *) urb->setup_packet;
+	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
 	void *data = urb->transfer_buffer;
 	int leni = urb->transfer_buffer_length;
 	int len = 0;
@@ -1992,10 +1994,10 @@
 	}
 
 
-	bmRType_bReq = cmd->requesttype | cmd->request << 8;
-	wValue = le16_to_cpu (cmd->value);
-	wIndex = le16_to_cpu (cmd->index);
-	wLength = le16_to_cpu (cmd->length);
+	bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8;
+	wValue = le16_to_cpu (cmd->wValue);
+	wIndex = le16_to_cpu (cmd->wIndex);
+	wLength = le16_to_cpu (cmd->wLength);
 
 	for (i = 0; i < 8; i++)
 		uhci->rh.c_p_r[i] = 0;
@@ -2162,7 +2164,7 @@
 }
 /*-------------------------------------------------------------------------*/
 
-_static int rh_unlink_urb (urb_t *urb)
+_static int rh_unlink_urb (struct urb *urb)
 {
 	uhci_t *uhci = urb->dev->bus->hcpriv;
 
@@ -2220,14 +2222,14 @@
 	unsigned long flags;
 	struct list_head *p;
 	struct list_head *p2;
-	urb_t *urb;
+	struct urb *urb;
 
 	spin_lock_irqsave (&s->urb_list_lock, flags);
 	p = s->urb_list.prev;	
 	while (p != &s->urb_list) {
 		p2 = p;
 		p = p->prev ;
-		urb = list_entry (p2, urb_t, urb_list);
+		urb = list_entry (p2, struct urb, urb_list);
 		dbg("urb: %p, dev %p, %p", urb, usb_dev,urb->dev);
 		
 		//urb->transfer_flags |=USB_ASYNC_UNLINK; 
@@ -2277,7 +2279,7 @@
 	uhci_unlink_urb
 };
 
-_static void correct_data_toggles(urb_t *urb)
+_static void correct_data_toggles(struct urb *urb)
 {
 	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), 
 		       !usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)));
@@ -2307,7 +2309,7 @@
  *       PROCESS_TRANSFER_DONT_UNLINK: QHs already unlinked (for async unlink_urb)
  */
 
-_static int process_transfer (uhci_t *s, urb_t *urb, int mode)
+_static int process_transfer (uhci_t *s, struct urb *urb, int mode)
 {
 	int ret = 0;
 	urb_priv_t *urb_priv = urb->hcpriv;
@@ -2395,7 +2397,7 @@
 	if (usb_pipetype (urb->pipe) == PIPE_BULK ) {  /* toggle correction for short bulk transfers (nonqueued/queued) */
 
 		urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
-		urb_t *next_queued_urb=priv->next_queued_urb;
+		struct urb *next_queued_urb=priv->next_queued_urb;
 
 		if (next_queued_urb) {
 			urb_priv_t *next_priv=(urb_priv_t*)next_queued_urb->hcpriv;
@@ -2426,7 +2428,7 @@
 	return ret;
 }
 
-_static int process_interrupt (uhci_t *s, urb_t *urb)
+_static int process_interrupt (uhci_t *s, struct urb *urb)
 {
 	int i, ret = -EINPROGRESS;
 	urb_priv_t *urb_priv = urb->hcpriv;
@@ -2525,7 +2527,7 @@
 // mode: PROCESS_ISO_REGULAR: processing only for done TDs, unlink TDs
 // mode: PROCESS_ISO_FORCE: force processing, don't unlink TDs (already unlinked)
 
-_static int process_iso (uhci_t *s, urb_t *urb, int mode)
+_static int process_iso (uhci_t *s, struct urb *urb, int mode)
 {
 	int i;
 	int ret = 0;
@@ -2594,9 +2596,9 @@
 _static int process_urb (uhci_t *s, struct list_head *p)
 {
 	int ret = 0;
-	urb_t *urb;
+	struct urb *urb;
 
-	urb=list_entry (p, urb_t, urb_list);
+	urb=list_entry (p, struct urb, urb_list);
 	//dbg("process_urb: found queued urb: %p", urb);
 
 	switch (usb_pipetype (urb->pipe)) {
@@ -2645,7 +2647,7 @@
 #endif
 
 		if ((usb_pipetype (urb->pipe) != PIPE_INTERRUPT)) {  // process_interrupt does completion on its own		
-			urb_t *next_urb = urb->next;
+			struct urb *next_urb = urb->next;
 			int is_ring = 0;
 			int contains_killed = 0;
 			int loop_count=0;
@@ -2952,6 +2954,7 @@
 	}
 
 	s->bus = bus;
+	bus->bus_name = dev->slot_name;
 	bus->hcpriv = s;
 
 	/* UHCI specs says devices must have 2 ports, but goes on to say */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/usb-uhci.h linux-2.4.20/drivers/usb/usb-uhci.h
--- linux-2.4.19/drivers/usb/usb-uhci.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/usb-uhci.h	2002-10-29 11:18:32.000000000 +0000
@@ -158,8 +158,8 @@
 	dma_addr_t setup_packet_dma;
 	dma_addr_t transfer_buffer_dma;
 	unsigned long started;
-	urb_t *next_queued_urb;         // next queued urb for this EP
-	urb_t *prev_queued_urb;
+	struct urb *next_queued_urb;	// next queued urb for this EP
+	struct urb *prev_queued_urb;
 	uhci_desc_t *bottom_qh;
 	uhci_desc_t *next_qh;       	// next helper QH
 	char use_loop;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/usb.c linux-2.4.20/drivers/usb/usb.c
--- linux-2.4.19/drivers/usb/usb.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/usb.c	2002-10-29 11:18:48.000000000 +0000
@@ -38,6 +38,8 @@
 #endif
 #include <linux/usb.h>
 
+#include "hcd.h"
+
 static const int usb_bandwidth_option =
 #ifdef CONFIG_USB_BANDWIDTH
 				1;
@@ -218,42 +220,51 @@
 }
 
 /*
- * usb_calc_bus_time:
- *
- * returns (approximate) USB bus time in nanoseconds for a USB transaction.
+ * usb_calc_bus_time - approximate periodic transaction time in nanoseconds
+ * @speed: from dev->speed; USB_SPEED_{LOW,FULL,HIGH}
+ * @is_input: true iff the transaction sends data to the host
+ * @isoc: true for isochronous transactions, false for interrupt ones
+ * @bytecount: how many bytes in the transaction.
+ *
+ * Returns approximate bus time in nanoseconds for a periodic transaction.
+ * See USB 2.0 spec section 5.11.3; only periodic transfers need to be
+ * scheduled in software, this function is only used for such scheduling.
  */
-static long usb_calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount)
+long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
 {
 	unsigned long	tmp;
 
-	if (low_speed)		/* no isoc. here */
-	{
-		if (input_dir)
-		{
+	switch (speed) {
+	case USB_SPEED_LOW: 	/* INTR only */
+		if (is_input) {
 			tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L;
 			return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
-		}
-		else
-		{
+		} else {
 			tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L;
 			return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
 		}
+	case USB_SPEED_FULL:	/* ISOC or INTR */
+		if (isoc) {
+			tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
+			return (((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp);
+		} else {
+			tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
+			return (9107L + BW_HOST_DELAY + tmp);
+		}
+	case USB_SPEED_HIGH:	/* ISOC or INTR */
+		// FIXME adjust for input vs output
+		if (isoc)
+			tmp = HS_USECS (bytecount);
+		else
+			tmp = HS_USECS_ISO (bytecount);
+		return tmp;
+	default:
+		dbg ("bogus device speed!");
+		return -1;
 	}
-
-	/* for full-speed: */
-
-	if (!isoc)		/* Input or Output */
-	{
-		tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
-		return (9107L + BW_HOST_DELAY + tmp);
-	} /* end not Isoc */
-
-	/* for isoc: */
-
-	tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
-	return (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp);
 }
 
+
 /*
  * usb_check_bandwidth():
  *
@@ -285,7 +296,7 @@
 	unsigned int	pipe = urb->pipe;
 	long		bustime;
 
-	bustime = usb_calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe),
+	bustime = usb_calc_bus_time (dev->speed, usb_pipein(pipe),
 			usb_pipeisoc(pipe), usb_maxpacket(dev, pipe, usb_pipeout(pipe)));
 	if (usb_pipeisoc(pipe))
 		bustime = NS_TO_US(bustime) / urb->number_of_packets;
@@ -457,12 +468,11 @@
 	 */
 	down (&usb_bus_list_lock);
 	list_del(&bus->bus_list);
+	clear_bit(bus->busnum, busmap.busmap);
 	up (&usb_bus_list_lock);
 
 	usbdevfs_remove_bus(bus);
 
-	clear_bit(bus->busnum, busmap.busmap);
-
 	usb_bus_put(bus);
 }
 
@@ -939,6 +949,9 @@
 
 	usb_bus_get(bus);
 
+	if (!parent)
+		dev->devpath [0] = '0';
+
 	dev->bus = bus;
 	dev->parent = parent;
 	atomic_set(&dev->refcnt, 1);
@@ -985,11 +998,11 @@
  *
  *	The driver should call usb_free_urb() when it is finished with the urb.
  */
-urb_t *usb_alloc_urb(int iso_packets)
+struct urb *usb_alloc_urb(int iso_packets)
 {
-	urb_t *urb;
+	struct urb *urb;
 
-	urb = (urb_t *)kmalloc(sizeof(urb_t) + iso_packets * sizeof(iso_packet_descriptor_t),
+	urb = (struct urb *)kmalloc(sizeof(struct urb) + iso_packets * sizeof(struct iso_packet_descriptor),
 	      in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
 	if (!urb) {
 		err("alloc_urb: kmalloc failed");
@@ -1011,13 +1024,13 @@
  *	cleaned up with a call to usb_free_urb() when the driver is finished
  *	with it.
  */
-void usb_free_urb(urb_t* urb)
+void usb_free_urb(struct urb* urb)
 {
 	if (urb)
 		kfree(urb);
 }
 /*-------------------------------------------------------------------*/
-int usb_submit_urb(urb_t *urb)
+int usb_submit_urb(struct urb *urb)
 {
 	if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op)
 		return urb->dev->bus->op->submit_urb(urb);
@@ -1026,7 +1039,7 @@
 }
 
 /*-------------------------------------------------------------------*/
-int usb_unlink_urb(urb_t *urb)
+int usb_unlink_urb(struct urb *urb)
 {
 	if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op)
 		return urb->dev->bus->op->unlink_urb(urb);
@@ -1040,7 +1053,7 @@
 /*-------------------------------------------------------------------*
  * completion handler for compatibility wrappers (sync control/bulk) *
  *-------------------------------------------------------------------*/
-static void usb_api_blocking_completion(urb_t *urb)
+static void usb_api_blocking_completion(struct urb *urb)
 {
 	struct usb_api_data *awd = (struct usb_api_data *)urb->context;
 
@@ -1054,7 +1067,7 @@
  *-------------------------------------------------------------------*/
 
 // Starts urb and waits for completion or timeout
-static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
+static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
 { 
 	DECLARE_WAITQUEUE(wait, current);
 	struct usb_api_data awd;
@@ -1110,9 +1123,9 @@
 /*-------------------------------------------------------------------*/
 // returns status (negative) or length (positive)
 int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, 
-			    devrequest *cmd,  void *data, int len, int timeout)
+			    struct usb_ctrlrequest *cmd,  void *data, int len, int timeout)
 {
-	urb_t *urb;
+	struct urb *urb;
 	int retv;
 	int length;
 
@@ -1145,7 +1158,8 @@
  *	This function sends a simple control message to a specified endpoint
  *	and waits for the message to complete, or timeout.
  *	
- *	If successful, it returns 0, othwise a negative error number.
+ *	If successful, it returns the number of bytes transferred; 
+ *	otherwise, it returns a negative error number.
  *
  *	Don't use this function from within an interrupt context, like a
  *	bottom half handler.  If you need a asyncronous message, or need to send
@@ -1154,17 +1168,17 @@
 int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
 			 __u16 value, __u16 index, void *data, __u16 size, int timeout)
 {
-	devrequest *dr = kmalloc(sizeof(devrequest), GFP_KERNEL);
+	struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
 	int ret;
 	
 	if (!dr)
 		return -ENOMEM;
 
-	dr->requesttype = requesttype;
-	dr->request = request;
-	dr->value = cpu_to_le16p(&value);
-	dr->index = cpu_to_le16p(&index);
-	dr->length = cpu_to_le16p(&size);
+	dr->bRequestType = requesttype;
+	dr->bRequest = request;
+	dr->wValue = cpu_to_le16p(&value);
+	dr->wIndex = cpu_to_le16p(&index);
+	dr->wLength = cpu_to_le16p(&size);
 
 	//dbg("usb_control_msg");	
 
@@ -1188,9 +1202,9 @@
  *	This function sends a simple bulk message to a specified endpoint
  *	and waits for the message to complete, or timeout.
  *	
- *	If successful, it returns 0, othwise a negative error number.
- *	The number of actual bytes transferred will be plaed in the 
- *	actual_timeout paramater.
+ *	If successful, it returns 0, otherwise a negative error number.
+ *	The number of actual bytes transferred will be stored in the 
+ *	actual_length paramater.
  *
  *	Don't use this function from within an interrupt context, like a
  *	bottom half handler.  If you need a asyncronous message, or need to
@@ -1199,7 +1213,7 @@
 int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, 
 			void *data, int len, int *actual_length, int timeout)
 {
-	urb_t *urb;
+	struct urb *urb;
 
 	if (len < 0)
 		return -EINVAL;
@@ -1698,7 +1712,8 @@
 
 	*pdev = NULL;
 
-	info("USB disconnect on device %d", dev->devnum);
+	info("USB disconnect on device %s-%s address %d",
+			dev->bus->bus_name, dev->devpath, dev->devnum);
 
 	if (dev->actconfig) {
 		for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
@@ -2392,6 +2407,7 @@
 EXPORT_SYMBOL(usb_connect);
 EXPORT_SYMBOL(usb_disconnect);
 
+EXPORT_SYMBOL(usb_calc_bus_time);
 EXPORT_SYMBOL(usb_check_bandwidth);
 EXPORT_SYMBOL(usb_claim_bandwidth);
 EXPORT_SYMBOL(usb_release_bandwidth);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/usbkbd.c linux-2.4.20/drivers/usb/usbkbd.c
--- linux-2.4.19/drivers/usb/usbkbd.c	2001-09-14 21:04:07.000000000 +0000
+++ linux-2.4.20/drivers/usb/usbkbd.c	2002-10-29 11:18:39.000000000 +0000
@@ -71,7 +71,7 @@
 	unsigned char new[8];
 	unsigned char old[8];
 	struct urb irq, led;
-	devrequest dr;
+	struct usb_ctrlrequest dr;
 	unsigned char leds, newleds;
 	char name[128];
 	int open;
@@ -215,11 +215,11 @@
 	FILL_INT_URB(&kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp,
 		usb_kbd_irq, kbd, endpoint->bInterval);
 
-	kbd->dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-	kbd->dr.request = USB_REQ_SET_REPORT;
-	kbd->dr.value = 0x200;
-	kbd->dr.index = interface->bInterfaceNumber;
-	kbd->dr.length = 1;
+	kbd->dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+	kbd->dr.bRequest = USB_REQ_SET_REPORT;
+	kbd->dr.wValue = 0x200;
+	kbd->dr.wIndex = interface->bInterfaceNumber;
+	kbd->dr.wLength = 1;
 
 	kbd->dev.name = kbd->name;
 	kbd->dev.idbus = BUS_USB;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/usblcd.c linux-2.4.20/drivers/usb/usblcd.c
--- linux-2.4.19/drivers/usb/usblcd.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/usb/usblcd.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,347 @@
+/***************************************************************************** 
+ *                          USBLCD Kernel Driver                             *
+ *        See http://www.usblcd.de for Hardware and Documentation.           *
+ *                            Version 1.03                                   *
+ *             (C) 2002 Adams IT Services <info@usblcd.de>                   *
+ *                                                                           *
+ *     This file is licensed under the GPL. See COPYING in the package.      *
+ * Based on rio500.c by Cesar Miquel (miquel@df.uba.ar) which is based on    *
+ * hp_scanner.c by David E. Nelson (dnelson@jump.net)                        *
+ *                                                                           *
+ * 23.7.02 RA changed minor device number to the official assigned one       *
+ * 18.9.02 RA Vendor ID change, longer timeouts                              *
+ *****************************************************************************/
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <linux/usb.h>
+
+#define DRIVER_VERSION "USBLCD Driver Version 1.03"
+
+#define USBLCD_MINOR		144
+
+#define IOCTL_GET_HARD_VERSION	1
+#define IOCTL_GET_DRV_VERSION	2
+
+/* stall/wait timeout for USBLCD */
+#define NAK_TIMEOUT	(10*HZ)
+
+#define IBUF_SIZE	0x1000
+#define OBUF_SIZE	0x10000
+
+struct lcd_usb_data {
+	struct usb_device *lcd_dev;	/* init: probe_lcd */
+	unsigned int ifnum;		/* Interface number of the USB device */
+	int isopen;			/* nz if open */
+	int present;			/* Device is present on the bus */
+	char *obuf, *ibuf;		/* transfer buffers */
+	char bulk_in_ep, bulk_out_ep;	/* Endpoint assignments */
+	wait_queue_head_t wait_q;	/* for timeouts */
+};
+
+static struct lcd_usb_data lcd_instance;
+
+static int open_lcd(struct inode *inode, struct file *file)
+{
+	struct lcd_usb_data *lcd = &lcd_instance;
+
+	if (lcd->isopen || !lcd->present) {
+		return -EBUSY;
+	}
+	lcd->isopen = 1;
+
+	init_waitqueue_head(&lcd->wait_q);
+
+	info("USBLCD opened.");
+
+	return 0;
+}
+
+static int close_lcd(struct inode *inode, struct file *file)
+{
+	struct lcd_usb_data *lcd = &lcd_instance;
+
+	lcd->isopen = 0;
+
+	info("USBLCD closed.");
+	return 0;
+}
+
+static int
+ioctl_lcd(struct inode *inode, struct file *file, unsigned int cmd,
+	  unsigned long arg)
+{
+	struct lcd_usb_data *lcd = &lcd_instance;
+	int i;
+	char buf[30];
+
+	/* Sanity check to make sure lcd is connected, powered, etc */
+	if (lcd == NULL ||
+	    lcd->present == 0 ||
+	    lcd->lcd_dev == NULL)
+		return -1;
+
+	switch (cmd) {
+	case IOCTL_GET_HARD_VERSION:
+		i = (lcd->lcd_dev)->descriptor.bcdDevice;
+		sprintf(buf,"%1d%1d.%1d%1d",(i & 0xF000)>>12,(i & 0xF00)>>8,
+			(i & 0xF0)>>4,(i & 0xF));
+		if (copy_to_user((void *)arg,buf,strlen(buf))!=0)
+			return -EFAULT;
+		break;
+	case IOCTL_GET_DRV_VERSION:
+		sprintf(buf,DRIVER_VERSION);
+		if (copy_to_user((void *)arg,buf,strlen(buf))!=0)
+			return -EFAULT;
+		break;
+	default:
+		return -ENOIOCTLCMD;
+		break;
+	}
+
+	return 0;
+}
+
+static ssize_t
+write_lcd(struct file *file, const char *buffer,
+	  size_t count, loff_t * ppos)
+{
+	struct lcd_usb_data *lcd = &lcd_instance;
+
+	unsigned long copy_size;
+	unsigned long bytes_written = 0;
+	unsigned int partial;
+
+	int result = 0;
+	int maxretry;
+
+	/* Sanity check to make sure lcd is connected, powered, etc */
+	if (lcd == NULL ||
+	    lcd->present == 0 ||
+	    lcd->lcd_dev == NULL)
+		return -1;
+
+	do {
+		unsigned long thistime;
+		char *obuf = lcd->obuf;
+
+		thistime = copy_size =
+		    (count >= OBUF_SIZE) ? OBUF_SIZE : count;
+		if (copy_from_user(lcd->obuf, buffer, copy_size))
+			return -EFAULT;
+		maxretry = 5;
+		while (thistime) {
+			if (!lcd->lcd_dev)
+				return -ENODEV;
+			if (signal_pending(current)) {
+				return bytes_written ? bytes_written : -EINTR;
+			}
+
+			result = usb_bulk_msg(lcd->lcd_dev,
+					 usb_sndbulkpipe(lcd->lcd_dev, 1),
+					 obuf, thistime, &partial, 10 * HZ);
+
+			dbg("write stats: result:%d thistime:%lu partial:%u",
+			     result, thistime, partial);
+
+			if (result == USB_ST_TIMEOUT) {	/* NAK - so hold for a while */
+				if (!maxretry--) {
+					return -ETIME;
+				}
+				interruptible_sleep_on_timeout(&lcd-> wait_q, NAK_TIMEOUT);
+				continue;
+			} else if (!result & partial) {
+				obuf += partial;
+				thistime -= partial;
+			} else
+				break;
+		};
+		if (result) {
+			err("Write Whoops - %x", result);
+			return -EIO;
+		}
+		bytes_written += copy_size;
+		count -= copy_size;
+		buffer += copy_size;
+	} while (count > 0);
+
+	return bytes_written ? bytes_written : -EIO;
+}
+
+static ssize_t
+read_lcd(struct file *file, char *buffer, size_t count, loff_t * ppos)
+{
+	struct lcd_usb_data *lcd = &lcd_instance;
+	ssize_t read_count;
+	unsigned int partial;
+	int this_read;
+	int result;
+	int maxretry = 10;
+	char *ibuf = lcd->ibuf;
+
+	/* Sanity check to make sure lcd is connected, powered, etc */
+	if (lcd == NULL ||
+	    lcd->present == 0 ||
+	    lcd->lcd_dev == NULL)
+		return -1;
+
+	read_count = 0;
+
+	while (count > 0) {
+		if (signal_pending(current)) {
+			return read_count ? read_count : -EINTR;
+		}
+		if (!lcd->lcd_dev)
+			return -ENODEV;
+		this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
+
+		result = usb_bulk_msg(lcd->lcd_dev,
+				      usb_rcvbulkpipe(lcd->lcd_dev, 0),
+				      ibuf, this_read, &partial,
+				      (int) (HZ * 8));
+
+		dbg(KERN_DEBUG "read stats: result:%d this_read:%u partial:%u",
+		       result, this_read, partial);
+
+		if (partial) {
+			count = this_read = partial;
+		} else if (result == USB_ST_TIMEOUT || result == 15) {	/* FIXME: 15 ??? */
+			if (!maxretry--) {
+				err("read_lcd: maxretry timeout");
+				return -ETIME;
+			}
+			interruptible_sleep_on_timeout(&lcd->wait_q,
+						       NAK_TIMEOUT);
+			continue;
+		} else if (result != USB_ST_DATAUNDERRUN) {
+			err("Read Whoops - result:%u partial:%u this_read:%u",
+			     result, partial, this_read);
+			return -EIO;
+		} else {
+			return (0);
+		}
+
+		if (this_read) {
+			if (copy_to_user(buffer, ibuf, this_read))
+				return -EFAULT;
+			count -= this_read;
+			read_count += this_read;
+			buffer += this_read;
+		}
+	}
+	return read_count;
+}
+
+static void *probe_lcd(struct usb_device *dev, unsigned int ifnum)
+{
+	struct lcd_usb_data *lcd = &lcd_instance;
+	int i;
+	
+	if (dev->descriptor.idProduct != 0x0001  ) {
+		warn(KERN_INFO "USBLCD model not supported.");
+		return NULL;
+	}
+
+	if (lcd->present == 1) {
+		warn(KERN_INFO "Multiple USBLCDs are not supported!");
+		return NULL;
+	}
+
+	i = dev->descriptor.bcdDevice;
+
+	info("USBLCD Version %1d%1d.%1d%1d found at address %d",
+		(i & 0xF000)>>12,(i & 0xF00)>>8,(i & 0xF0)>>4,(i & 0xF),
+		dev->devnum);
+
+	lcd->present = 1;
+	lcd->lcd_dev = dev;
+
+	if (!(lcd->obuf = (char *) kmalloc(OBUF_SIZE, GFP_KERNEL))) {
+		err("probe_lcd: Not enough memory for the output buffer");
+		return NULL;
+	}
+	dbg("probe_lcd: obuf address:%p", lcd->obuf);
+
+	if (!(lcd->ibuf = (char *) kmalloc(IBUF_SIZE, GFP_KERNEL))) {
+		err("probe_lcd: Not enough memory for the input buffer");
+		kfree(lcd->obuf);
+		return NULL;
+	}
+	dbg("probe_lcd: ibuf address:%p", lcd->ibuf);
+
+	return lcd;
+}
+
+static void disconnect_lcd(struct usb_device *dev, void *ptr)
+{
+	struct lcd_usb_data *lcd = (struct lcd_usb_data *) ptr;
+
+	if (lcd->isopen) {
+		lcd->isopen = 0;
+		/* better let it finish - the release will do whats needed */
+		lcd->lcd_dev = NULL;
+		return;
+	}
+	kfree(lcd->ibuf);
+	kfree(lcd->obuf);
+
+	info("USBLCD disconnected.");
+
+	lcd->present = 0;
+}
+
+static struct usb_device_id id_table [] = {
+	{ .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
+	{},
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+static struct
+file_operations usb_lcd_fops = {
+	.owner =	THIS_MODULE,
+	.read =		read_lcd,
+	.write =	write_lcd,
+	.ioctl =	ioctl_lcd,
+	.open =		open_lcd,
+	.release =	close_lcd,
+};
+
+static struct
+usb_driver lcd_driver = {
+	.name =		"usblcd",
+	.probe =	(void *)probe_lcd,
+	.disconnect =	disconnect_lcd,
+	.id_table =	id_table,
+	.fops =		&usb_lcd_fops,
+	.minor =	USBLCD_MINOR,
+};
+
+int usb_lcd_init(void)
+{
+	if (usb_register(&lcd_driver) < 0)
+		return -1;
+
+	info("%s (C) Adams IT Services http://www.usblcd.de", DRIVER_VERSION);
+	info("USBLCD support registered.");
+	return 0;
+}
+
+
+void usb_lcd_cleanup(void)
+{
+	struct lcd_usb_data *lcd = &lcd_instance;
+
+	lcd->present = 0;
+	usb_deregister(&lcd_driver);
+}
+
+module_init(usb_lcd_init);
+module_exit(usb_lcd_cleanup);
+
+MODULE_AUTHOR("Adams IT Services <info@usblcd.de>");
+MODULE_DESCRIPTION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/usbnet.c linux-2.4.20/drivers/usb/usbnet.c
--- linux-2.4.19/drivers/usb/usbnet.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/usbnet.c	2002-10-29 11:18:31.000000000 +0000
@@ -1,6 +1,6 @@
 /*
  * USB Host-to-Host Links
- * Copyright (C) 2000-2001 by David Brownell <dbrownell@users.sourceforge.net>
+ * Copyright (C) 2000-2002 by David Brownell <dbrownell@users.sourceforge.net>
  */
 
 /*
@@ -16,6 +16,7 @@
  *
  *	- AnchorChip 2720
  *	- Belkin, eTEK (interops with Win32 drivers)
+ *	- EPSON USB clients
  *	- GeneSys GL620USB-A
  *	- "Linux Devices" (like iPaq and similar SA-1100 based PDAs)
  *	- NetChip 1080 (interoperates with NetChip Win32 drivers)
@@ -23,33 +24,41 @@
  *
  * USB devices can implement their side of this protocol at the cost
  * of two bulk endpoints; it's not restricted to "cable" applications.
- * See the LINUXDEV support.
+ * See the LINUXDEV or EPSON device/client support.
  *
  * 
- * TODO:
+ * Status:
  *
- * This needs to be retested for bulk queuing problems ... earlier versions
- * seemed to find different types of problems in each HCD.  Once they're fixed,
- * re-enable queues to get higher bandwidth utilization (without needing
- * to tweak MTU for larger packets).
- *
- * Add support for more "network cable" chips; interop with their Win32
- * drivers may be a good thing.  Test the AnchorChip 2720 support..
- * Figure out the initialization protocol used by the Prolific chips,
- * for better robustness ... there's some powerup/reset handshake that's
- * needed when only one end reboots.
- *
- * Use interrupt on PL230x to detect peer connect/disconnect, and call
- * netif_carrier_{on,off} (?) appropriately.  For Net1080, detect peer
- * connect/disconnect with async control messages.
- *
- * Find some way to report "peer connected" network hotplug events; it'll
- * likely mean updating the networking layer.  (This has been discussed
- * on the netdev list...)
+ * - AN2720 ... not widely available, but reportedly works well
  *
- * Craft smarter hotplug policy scripts ... ones that know how to arrange
+ * - Belkin/eTEK ... no known issues
+ *
+ * - Both GeneSys and PL-230x use interrupt transfers for driver-to-driver
+ *   handshaking; it'd be worth implementing those as "carrier detect".
+ *   Prefer generic hooks, not minidriver-specific hacks.
+ *
+ * - Linux devices ... the www.handhelds.org SA-1100 support works nicely,
+ *   but the Sharp Zaurus uses an incompatible protocol (extra checksums).
+ *   No reason not to merge the Zaurus protocol here too (got patch? :)
+ *
+ * - For Netchip, should use keventd to poll via control requests to detect
+ *   hardware level "carrier detect". 
+ *
+ * - PL-230x ... the initialization protocol doesn't seem to match chip data
+ *   sheets, sometimes it's not needed and sometimes it hangs.  Prolific has
+ *   not responded to repeated support/information requests.
+ *
+ * Interop with more Win32 drivers may be a good thing.
+ *
+ * Seems like reporting "peer connected" (carrier present) events may end
+ * up going through the netlink event system, not hotplug ... that may be
+ * awkward in terms of automatic configuration though.
+ *
+ * There are reports that bridging gives lower-than-usual throughput.
+ *
+ * Need smarter hotplug policy scripts ... ones that know how to arrange
  * bridging with "brctl", and can handle static and dynamic ("pump") setups.
- * Use those "peer connected" events.
+ * Use those eventual "peer connected" events, and zeroconf.
  *
  *
  * CHANGELOG:
@@ -62,6 +71,7 @@
  * 18-dec-2000	(db) tx watchdog, "net1080" renaming to "usbnet", device_info
  *		and prolific support, isolate net1080-specific bits, cleanup.
  *		fix unlink_urbs oops in D3 PM resume code path.
+ *
  * 02-feb-2001	(db) fix tx skb sharing, packet length, match_flags, ...
  * 08-feb-2001	stubbed in "linuxdev", maybe the SA-1100 folk can use it;
  *		AnchorChips 2720 support (from spec) for testing;
@@ -83,6 +93,14 @@
  *		tie mostly to (sub)driver info.  Workaround some PL-2302
  *		chips that seem to reject SET_INTERFACE requests.
  *
+ * 06-apr-2002	Added ethtool support, based on a patch from Brad Hards.
+ *		Level of diagnostics is more configurable; they use device
+ *		location (usb_device->devpath) instead of address (2.5).
+ *		For tx_fixup, memflags can't be NOIO.
+ * 07-may-2002	Generalize/cleanup keventd support, handling rx stalls (mostly
+ *		for USB 2.0 TTs) and memory shortages (potential) too. (db)
+ *		Use "locally assigned" IEEE802 address space. (Brad Hards)
+ *
  *-------------------------------------------------------------------------*/
 
 #include <linux/config.h>
@@ -93,6 +111,9 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/random.h>
+#include <linux/ethtool.h>
+#include <linux/tqueue.h>
+#include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
 // #define	DEBUG			// error path messages, extra info
@@ -104,15 +125,27 @@
 #endif
 #include <linux/usb.h>
 
+/* in 2.5 these standard usb ops take mem_flags */
+#define ALLOC_URB(n,flags)	usb_alloc_urb(n)
+#define SUBMIT_URB(u,flags)	usb_submit_urb(u)
+
+/* and these got renamed (may move to usb.h) */
+#define usb_get_dev		usb_inc_dev_use
+#define usb_put_dev		usb_dec_dev_use
 
+
+/* minidrivers _could_ be individually configured */
 #define	CONFIG_USB_AN2720
 #define	CONFIG_USB_BELKIN
+#define	CONFIG_USB_EPSON2888
 #define	CONFIG_USB_GENESYS
 #define	CONFIG_USB_LINUXDEV
 #define	CONFIG_USB_NET1080
 #define	CONFIG_USB_PL2301
 
 
+#define DRIVER_VERSION		"17-Jul-2002"
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -164,6 +197,7 @@
 	// protocol/interface state
 	struct net_device	net;
 	struct net_device_stats	stats;
+	int			msg_level;
 
 #ifdef CONFIG_USB_NET1080
 	u16			packet_id;
@@ -174,7 +208,12 @@
 	struct sk_buff_head	txq;
 	struct sk_buff_head	done;
 	struct tasklet_struct	bh;
-	struct tq_struct	ctrl_task;
+
+	struct tq_struct	kevent;
+	unsigned long		flags;
+#		define EVENT_TX_HALT	0
+#		define EVENT_RX_HALT	1
+#		define EVENT_RX_MEMORY	2
 };
 
 // device-specific info used by the driver
@@ -224,6 +263,13 @@
 	size_t			length;
 };
 
+static const char driver_name [] = "usbnet";
+
+/* use ethtool to change the level for any given device */
+static int msg_level = 1;
+MODULE_PARM (msg_level, "i");
+MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)");
+
 
 #define	mutex_lock(x)	down(x)
 #define	mutex_unlock(x)	up(x)
@@ -241,7 +287,9 @@
 #endif
 
 #define devinfo(usbnet, fmt, arg...) \
-	printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net.name, ## arg)
+	do { if ((usbnet)->msg_level >= 1) \
+	printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net.name, ## arg); \
+	} while (0)
 
 
 #ifdef	CONFIG_USB_AN2720
@@ -258,12 +306,12 @@
  *-------------------------------------------------------------------------*/
 
 static const struct driver_info	an2720_info = {
-	description:	"AnchorChips/Cypress 2720",
+	.description =	"AnchorChips/Cypress 2720",
 	// no reset available!
 	// no check_connect available!
 
-	in: 2, out: 2,		// direction distinguishes these
-	epsize:	64,
+	.in = 2, .out = 2,		// direction distinguishes these
+	.epsize =64,
 };
 
 #endif	/* CONFIG_USB_AN2720 */
@@ -281,16 +329,39 @@
  *-------------------------------------------------------------------------*/
 
 static const struct driver_info	belkin_info = {
-	description:	"Belkin, eTEK, or compatible",
+	.description =	"Belkin, eTEK, or compatible",
 
-	in: 1, out: 1,		// direction distinguishes these
-	epsize:	64,
+	.in = 1, .out = 1,		// direction distinguishes these
+	.epsize =64,
 };
 
 #endif	/* CONFIG_USB_BELKIN */
 
 
 
+#ifdef	CONFIG_USB_EPSON2888
+
+/*-------------------------------------------------------------------------
+ *
+ * EPSON USB clients
+ *
+ * This is the same idea as "linuxdev" (below) except the firmware in the
+ * device might not be Tux-powered.  Epson provides reference firmware that
+ * implements this interface.  Product developers can reuse or modify that
+ * code, such as by using their own product and vendor codes.
+ *
+ *-------------------------------------------------------------------------*/
+
+static const struct driver_info	epson2888_info = {
+	.description =	"Epson USB Device",
+
+	.in = 4, .out = 3,
+	.epsize = 64,
+};
+
+#endif	/* CONFIG_USB_EPSON2888 */
+
+
 #ifdef CONFIG_USB_GENESYS
 
 /*-------------------------------------------------------------------------
@@ -300,6 +371,15 @@
  * ... should partially interop with the Win32 driver for this hardware
  * The GeneSys docs imply there's some NDIS issue motivating this framing.
  *
+ * Some info from GeneSys:
+ *  - GL620USB-A is full duplex; GL620USB is only half duplex for bulk.
+ *    (Some cables, like the BAFO-100c, use the half duplex version.)
+ *  - For the full duplex model, the low bit of the version code says
+ *    which side is which ("left/right").
+ *  - For the half duplex type, a control/interrupt handshake settles
+ *    the transfer direction.  (That's disabled here, partially coded.)
+ *    A control URB would block until other side writes an interrupt.
+ *
  *-------------------------------------------------------------------------*/
 
 // control msg write command
@@ -373,7 +453,7 @@
 	// issue usb interrupt read
 	if (priv && priv->irq_urb) {
 		// submit urb
-		if ((retval = usb_submit_urb (priv->irq_urb)) != 0)
+		if ((retval = SUBMIT_URB (priv->irq_urb, GFP_KERNEL)) != 0)
 			dbg ("gl_interrupt_read: submit fail - %X...", retval);
 		else
 			dbg ("gl_interrupt_read: submit success...");
@@ -420,7 +500,7 @@
 	}
 
 	// allocate irq urb
-	if ((priv->irq_urb = usb_alloc_urb (0)) == 0) {
+	if ((priv->irq_urb = ALLOC_URB (0, GFP_KERNEL)) == 0) {
 		dbg ("%s: cannot allocate private irq urb per device",
 			dev->net.name);
 		kfree (priv);
@@ -464,23 +544,8 @@
 	return 0;
 }
 
-#else
-
-static int genelink_check_connect (struct usbnet *dev)
-{
-	dbg ("%s: assuming peer is connected", dev->net.name);
-	return 0;
-}
-
 #endif
 
-// reset the device status
-static int genelink_reset (struct usbnet *dev)
-{
-	// we don't need to reset, just return 0
-	return 0;
-}
-
 static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
 {
 	struct gl_header	*header;
@@ -600,15 +665,17 @@
 }
 
 static const struct driver_info	genelink_info = {
-	description:	"Genesys GeneLink",
-	flags:		FLAG_FRAMING_GL | FLAG_NO_SETINT,
-	reset:		genelink_reset,
-	check_connect:	genelink_check_connect,
-	rx_fixup:	genelink_rx_fixup,
-	tx_fixup:	genelink_tx_fixup,
+	.description =	"Genesys GeneLink",
+	.flags =	FLAG_FRAMING_GL | FLAG_NO_SETINT,
+	.rx_fixup =	genelink_rx_fixup,
+	.tx_fixup =	genelink_tx_fixup,
+
+	.in = 1, .out = 2,
+	.epsize =64,
 
-	in: 1, out: 2,
-	epsize:	64,
+#ifdef	GENELINK_ACK
+	.check_connect =genelink_check_connect,
+#endif
 };
 
 #endif /* CONFIG_USB_GENESYS */
@@ -629,21 +696,19 @@
  *
  * One example is Intel's SA-1100 chip, which integrates basic USB
  * support (arch/arm/sa1100/usb-eth.c); it's used in the iPaq PDA.
+ * And others too, like the Yopy.
  *
  *-------------------------------------------------------------------------*/
 
-
 static const struct driver_info	linuxdev_info = {
-	description:	"Linux Device",
-	// no reset defined (yet?)
-	// no check_connect needed!
-	in: 2, out: 1,
-	epsize:	64,
+	.description =	"Linux Device",
+
+	.in = 2, .out = 1,
+	.epsize = 64,
 };
 
 #endif	/* CONFIG_USB_LINUXDEV */
 
-
 
 #ifdef	CONFIG_USB_NET1080
 
@@ -814,10 +879,10 @@
 static inline void nc_dump_usbctl (struct usbnet *dev, u16 usbctl)
 {
 #ifdef DEBUG
-	devdbg (dev, "net1080 %03d/%03d usbctl 0x%x:%s%s%s%s%s;"
+	devdbg (dev, "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s;"
 			" this%s%s;"
 			" other%s%s; r/o 0x%x",
-		dev->udev->bus->busnum, dev->udev->devnum,
+		dev->udev->bus->bus_name, dev->udev->devpath,
 		usbctl,
 		(usbctl & USBCTL_ENABLE_LANG) ? " lang" : "",
 		(usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "",
@@ -859,10 +924,10 @@
 static inline void nc_dump_status (struct usbnet *dev, u16 status)
 {
 #ifdef DEBUG
-	devdbg (dev, "net1080 %03d/%03d status 0x%x:"
+	devdbg (dev, "net1080 %s-%s status 0x%x:"
 			" this (%c) PKT=%d%s%s%s;"
 			" other PKT=%d%s%s%s; unspec 0x%x",
-		dev->udev->bus->busnum, dev->udev->devnum,
+		dev->udev->bus->bus_name, dev->udev->devpath,
 		status,
 
 		// XXX the packet counts don't seem right
@@ -897,8 +962,8 @@
 static inline void nc_dump_ttl (struct usbnet *dev, u16 ttl)
 {
 #ifdef DEBUG
-	devdbg (dev, "net1080 %03d/%03d ttl 0x%x this = %d, other = %d",
-		dev->udev->bus->busnum, dev->udev->devnum,
+	devdbg (dev, "net1080 %s-%s ttl 0x%x this = %d, other = %d",
+		dev->udev->bus->bus_name, dev->udev->devpath,
 		ttl,
 
 		TTL_THIS (ttl),
@@ -921,7 +986,8 @@
 	// nc_dump_registers (dev);
 
 	if ((retval = nc_register_read (dev, REG_STATUS, vp)) < 0) {
-		dbg ("can't read dev %d status: %d", dev->udev->devnum, retval);
+		dbg ("can't read %s-%s status: %d",
+			dev->udev->bus->bus_name, dev->udev->devpath, retval);
 		goto done;
 	}
 	status = *vp;
@@ -948,10 +1014,11 @@
 			MK_TTL (NC_READ_TTL_MS, TTL_OTHER (ttl)) );
 	dbg ("%s: assigned TTL, %d ms", dev->net.name, NC_READ_TTL_MS);
 
-	devdbg (dev, "port %c, peer %sconnected",
-		(status & STATUS_PORT_A) ? 'A' : 'B',
-		(status & STATUS_CONN_OTHER) ? "" : "dis"
-		);
+	if (dev->msg_level >= 2)
+		devinfo (dev, "port %c, peer %sconnected",
+			(status & STATUS_PORT_A) ? 'A' : 'B',
+			(status & STATUS_CONN_OTHER) ? "" : "dis"
+			);
 	retval = 0;
 
 done:
@@ -1079,15 +1146,15 @@
 }
 
 static const struct driver_info	net1080_info = {
-	description:	"NetChip TurboCONNECT",
-	flags:		FLAG_FRAMING_NC,
-	reset:		net1080_reset,
-	check_connect:	net1080_check_connect,
-	rx_fixup:	net1080_rx_fixup,
-	tx_fixup:	net1080_tx_fixup,
+	.description =	"NetChip TurboCONNECT",
+	.flags =	FLAG_FRAMING_NC,
+	.reset =	net1080_reset,
+	.check_connect =net1080_check_connect,
+	.rx_fixup =	net1080_rx_fixup,
+	.tx_fixup =	net1080_tx_fixup,
 
-	in: 1, out: 1,		// direction distinguishes these
-	epsize:	64,
+	.in = 1, .out = 1,		// direction distinguishes these
+	.epsize =64,
 };
 
 #endif /* CONFIG_USB_NET1080 */
@@ -1147,24 +1214,14 @@
 		PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E);
 }
 
-static int pl_check_connect (struct usbnet *dev)
-{
-	// FIXME test interrupt data PL_PEER_E bit
-	// plus, there's some handshake done by
-	// the prolific win32 driver... 
-	dbg ("%s: assuming peer is connected", dev->net.name);
-	return 0;
-}
-
 static const struct driver_info	prolific_info = {
-	description:	"Prolific PL-2301/PL-2302",
-	flags:		FLAG_NO_SETINT,
+	.description =	"Prolific PL-2301/PL-2302",
+	.flags =	FLAG_NO_SETINT,
 		/* some PL-2302 versions seem to fail usb_set_interface() */
-	reset:		pl_reset,
-	check_connect:	pl_check_connect,
+	.reset =	pl_reset,
 
-	in: 3, out: 2,
-	epsize:	64,
+	.in = 3, .out = 2,
+	.epsize =64,
 };
 
 #endif /* CONFIG_USB_PL2301 */
@@ -1227,6 +1284,21 @@
 	spin_unlock_irqrestore (&dev->done.lock, flags);
 }
 
+/* some work can't be done in tasklets, so we use keventd
+ *
+ * NOTE:  annoying asymmetry:  if it's active, schedule_task() fails,
+ * but tasklet_schedule() doesn't.  hope the failure is rare.
+ */
+static void defer_kevent (struct usbnet *dev, int work)
+{
+	set_bit (work, &dev->flags);
+	if (!schedule_task (&dev->kevent))
+		err ("%s: kevent %d may have been dropped",
+			dev->net.name, work);
+	else
+		dbg ("%s: kevent %d scheduled", dev->net.name, work);
+}
+
 /*-------------------------------------------------------------------------*/
 
 static void rx_complete (struct urb *urb);
@@ -1253,7 +1325,7 @@
 
 	if ((skb = alloc_skb (size, flags)) == 0) {
 		dbg ("no rx skb");
-		tasklet_schedule (&dev->bh);
+		defer_kevent (dev, EVENT_RX_MEMORY);
 		usb_free_urb (urb);
 		return;
 	}
@@ -1268,9 +1340,6 @@
 		usb_rcvbulkpipe (dev->udev, dev->driver_info->in),
 		skb->data, size, rx_complete, skb);
 	urb->transfer_flags |= USB_ASYNC_UNLINK;
-#ifdef	REALLY_QUEUE
-	urb->transfer_flags |= USB_QUEUE_BULK;
-#endif
 #if 0
 	// Idle-but-posted reads with UHCI really chew up
 	// PCI bandwidth unless FSBR is disabled
@@ -1279,11 +1348,20 @@
 
 	spin_lock_irqsave (&dev->rxq.lock, lockflags);
 
-	if (netif_running (&dev->net)) {
-		if ((retval = usb_submit_urb (urb)) != 0) {
+	if (netif_running (&dev->net)
+			&& !test_bit (EVENT_RX_HALT, &dev->flags)) {
+		switch (retval = SUBMIT_URB (urb, GFP_ATOMIC)){ 
+		case -EPIPE:
+			defer_kevent (dev, EVENT_RX_HALT);
+			break;
+		case -ENOMEM:
+			defer_kevent (dev, EVENT_RX_MEMORY);
+			break;
+		default:
 			dbg ("%s rx submit, %d", dev->net.name, retval);
 			tasklet_schedule (&dev->bh);
-		} else {
+			break;
+		case 0:
 			__skb_queue_tail (&dev->rxq, skb);
 		}
 	} else {
@@ -1357,12 +1435,20 @@
 		}
 		break;
 
+	    // stalls need manual reset. this is rare ... except that
+	    // when going through USB 2.0 TTs, unplug appears this way.
+	    // we avoid the highspeed version of the ETIMEOUT/EILSEQ
+	    // storm, recovering as needed.
+	    case -EPIPE:
+		defer_kevent (dev, EVENT_RX_HALT);
+		// FALLTHROUGH
+
 	    // software-driven interface shutdown
-	    case -ECONNRESET:		// usb-ohci, usb-uhci
-	    case -ECONNABORTED:		// uhci ... for usb-uhci, INTR
-		dbg ("%s shutdown, code %d", dev->net.name, urb_status);
+	    case -ECONNRESET:		// according to API spec
+	    case -ECONNABORTED:		// some (now fixed?) UHCI bugs
+		dbg ("%s rx shutdown, code %d", dev->net.name, urb_status);
 		entry->state = rx_cleanup;
-		// do urb frees only in the tasklet
+		// do urb frees only in the tasklet (UHCI has oopsed ...)
 		entry->urb = urb;
 		urb = 0;
 		break;
@@ -1373,8 +1459,9 @@
 		// FALLTHROUGH
 	    
 	    default:
-		// on unplug we'll get a burst of ETIMEDOUT/EILSEQ
-		// till the khubd gets and handles its interrupt.
+		// on unplug we get ETIMEDOUT (ohci) or EILSEQ (uhci)
+		// until khubd sees its interrupt and disconnects us.
+		// that can easily be hundreds of passes through here.
 		entry->state = rx_cleanup;
 		dev->stats.rx_errors++;
 		dbg ("%s rx: status %d", dev->net.name, urb_status);
@@ -1384,10 +1471,12 @@
 	defer_bh (dev, skb);
 
 	if (urb) {
-		if (netif_running (&dev->net)) {
+		if (netif_running (&dev->net)
+				&& !test_bit (EVENT_RX_HALT, &dev->flags)) {
 			rx_submit (dev, urb, GFP_ATOMIC);
 			return;
 		}
+		usb_free_urb (urb);
 	}
 #ifdef	VERBOSE
 	dbg ("no read resubmitted");
@@ -1417,7 +1506,7 @@
 		// during some PM-driven resume scenarios,
 		// these (async) unlinks complete immediately
 		retval = usb_unlink_urb (urb);
-		if (retval < 0)
+		if (retval != -EINPROGRESS && retval != 0)
 			dbg ("unlink urb err, %d", retval);
 		else
 			count++;
@@ -1441,10 +1530,11 @@
 	mutex_lock (&dev->mutex);
 	netif_stop_queue (net);
 
-	devdbg (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld",
-		dev->stats.rx_packets, dev->stats.tx_packets, 
-		dev->stats.rx_errors, dev->stats.tx_errors
-		);
+	if (dev->msg_level >= 2)
+		devinfo (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld",
+			dev->stats.rx_packets, dev->stats.tx_packets, 
+			dev->stats.rx_errors, dev->stats.tx_errors
+			);
 
 	// ensure there are no more active urbs
 	add_wait_queue (&unlink_wakeup, &wait);
@@ -1482,9 +1572,9 @@
 
 	// put into "known safe" state
 	if (info->reset && (retval = info->reset (dev)) < 0) {
-		devinfo (dev, "open reset fail (%d) usbnet %03d/%03d, %s",
+		devinfo (dev, "open reset fail (%d) usbnet usb-%s-%s, %s",
 			retval,
-			dev->udev->bus->busnum, dev->udev->devnum,
+			dev->udev->bus->bus_name, dev->udev->devpath,
 			info->description);
 		goto done;
 	}
@@ -1496,14 +1586,16 @@
 	}
 
 	netif_start_queue (net);
-	devdbg (dev, "open: enable queueing (rx %d, tx %d) mtu %d %s framing",
-		RX_QLEN, TX_QLEN, dev->net.mtu,
-		(info->flags & (FLAG_FRAMING_NC | FLAG_FRAMING_GL))
-		    ? ((info->flags & FLAG_FRAMING_NC)
-			? "NetChip"
-			: "GeneSys")
-		    : "raw"
-		);
+	if (dev->msg_level >= 2)
+		devinfo (dev, "open: enable queueing "
+				"(rx %d, tx %d) mtu %d %s framing",
+			RX_QLEN, TX_QLEN, dev->net.mtu,
+			(info->flags & (FLAG_FRAMING_NC | FLAG_FRAMING_GL))
+			    ? ((info->flags & FLAG_FRAMING_NC)
+				? "NetChip"
+				: "GeneSys")
+			    : "raw"
+			);
 
 	// delay posting reads until we're fully open
 	tasklet_schedule (&dev->bh);
@@ -1514,16 +1606,134 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* usb_clear_halt cannot be called in interrupt context */
+static int usbnet_ethtool_ioctl (struct net_device *net, void *useraddr)
+{
+	struct usbnet	*dev = (struct usbnet *) net->priv;
+	u32		cmd;
+
+	if (get_user (cmd, (u32 *)useraddr))
+		return -EFAULT;
+	switch (cmd) {
+
+	case ETHTOOL_GDRVINFO: {	/* get driver info */
+		struct ethtool_drvinfo		info;
+
+		memset (&info, 0, sizeof info);
+		info.cmd = ETHTOOL_GDRVINFO;
+		strncpy (info.driver, driver_name, sizeof info.driver);
+		strncpy (info.version, DRIVER_VERSION, sizeof info.version);
+		strncpy (info.fw_version, dev->driver_info->description,
+			sizeof info.fw_version);
+		usb_make_path (dev->udev, info.bus_info, sizeof info.bus_info);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+		}
+
+	case ETHTOOL_GLINK: 		/* get link status */
+		if (dev->driver_info->check_connect) {
+			struct ethtool_value	edata = { ETHTOOL_GLINK };
+
+			edata.data = dev->driver_info->check_connect (dev) == 0;
+			if (copy_to_user (useraddr, &edata, sizeof (edata)))
+				return -EFAULT;
+			return 0;
+		}
+		break;
 
+	case ETHTOOL_GMSGLVL: {		/* get message-level */
+		struct ethtool_value	edata = {ETHTOOL_GMSGLVL};
+
+		edata.data = dev->msg_level;
+		if (copy_to_user (useraddr, &edata, sizeof (edata)))
+			return -EFAULT;
+		return 0;
+		}
+
+	case ETHTOOL_SMSGLVL: {		/* set message-level */
+		struct ethtool_value	edata;
+
+		if (copy_from_user (&edata, useraddr, sizeof (edata)))
+			return -EFAULT;
+		dev->msg_level = edata.data;
+		return 0;
+		}
+	
+	/* could also map RINGPARAM to RX/TX QLEN */
+
+	}
+        /* Note that the ethtool user space code requires EOPNOTSUPP */
+	return -EOPNOTSUPP;
+}
+
+static int usbnet_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
+{
+	switch (cmd) {
+	case SIOCETHTOOL:
+		return usbnet_ethtool_ioctl (net, (void *)rq->ifr_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* work that cannot be done in interrupt context uses keventd.
+ *
+ * NOTE:  "uhci" and "usb-uhci" may have trouble with this since they don't
+ * queue control transfers to individual devices, and other threads could
+ * trigger control requests concurrently.  hope that's rare.
+ */
 static void
-tx_clear_halt (void *data)
+kevent (void *data)
 {
 	struct usbnet		*dev = data;
+	int			status;
 
-	usb_clear_halt (dev->udev,
-		usb_sndbulkpipe (dev->udev, dev->driver_info->out));
-	netif_wake_queue (&dev->net);
+	/* usb_clear_halt() needs a thread context */
+	if (test_bit (EVENT_TX_HALT, &dev->flags)) {
+		unlink_urbs (&dev->txq);
+		status = usb_clear_halt (dev->udev,
+			usb_sndbulkpipe (dev->udev, dev->driver_info->out));
+		if (status < 0)
+			err ("%s: can't clear tx halt, status %d",
+				dev->net.name, status);
+		else {
+			clear_bit (EVENT_TX_HALT, &dev->flags);
+			netif_wake_queue (&dev->net);
+		}
+	}
+	if (test_bit (EVENT_RX_HALT, &dev->flags)) {
+		unlink_urbs (&dev->rxq);
+		status = usb_clear_halt (dev->udev,
+			usb_rcvbulkpipe (dev->udev, dev->driver_info->in));
+		if (status < 0)
+			err ("%s: can't clear rx halt, status %d",
+				dev->net.name, status);
+		else {
+			clear_bit (EVENT_RX_HALT, &dev->flags);
+			tasklet_schedule (&dev->bh);
+		}
+	}
+
+	/* tasklet could resubmit itself forever if memory is tight */
+	if (test_bit (EVENT_RX_MEMORY, &dev->flags)) {
+		struct urb	*urb = 0;
+
+		if (netif_running (&dev->net))
+			urb = ALLOC_URB (0, GFP_KERNEL);
+		else
+			clear_bit (EVENT_RX_MEMORY, &dev->flags);
+		if (urb != 0) {
+			clear_bit (EVENT_RX_MEMORY, &dev->flags);
+			rx_submit (dev, urb, GFP_KERNEL);
+			tasklet_schedule (&dev->bh);
+		}
+	}
+
+	if (dev->flags)
+		dbg ("%s: kevent done, flags = 0x%lx",
+			dev->net.name, dev->flags);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1534,15 +1744,8 @@
 	struct skb_data		*entry = (struct skb_data *) skb->cb;
 	struct usbnet		*dev = entry->dev;
 
-	if (urb->status == USB_ST_STALL) {
-		if (dev->ctrl_task.sync == 0) {
-			dev->ctrl_task.routine = tx_clear_halt;
-			dev->ctrl_task.data = dev;
-			schedule_task (&dev->ctrl_task);
-		} else {
-			dbg ("Cannot clear TX stall");
-		}
-	}
+	if (urb->status == -EPIPE)
+		defer_kevent (dev, EVENT_TX_HALT);
 	urb->dev = 0;
 	entry->state = tx_done;
 	defer_bh (dev, skb);
@@ -1576,19 +1779,17 @@
 	struct nc_trailer	*trailer = 0;
 #endif	/* CONFIG_USB_NET1080 */
 
-	flags = in_interrupt () ? GFP_ATOMIC : GFP_NOIO; /* might be used for nfs */
-
 	// some devices want funky USB-level framing, for
 	// win32 driver (usually) and/or hardware quirks
 	if (info->tx_fixup) {
-		skb = info->tx_fixup (dev, skb, flags);
+		skb = info->tx_fixup (dev, skb, GFP_ATOMIC);
 		if (!skb) {
 			dbg ("can't tx_fixup skb");
 			goto drop;
 		}
 	}
 
-	if (!(urb = usb_alloc_urb (0))) {
+	if (!(urb = ALLOC_URB (0, GFP_ATOMIC))) {
 		dbg ("no urb");
 		goto drop;
 	}
@@ -1621,9 +1822,6 @@
 			usb_sndbulkpipe (dev->udev, info->out),
 			skb->data, skb->len, tx_complete, skb);
 	urb->transfer_flags |= USB_ASYNC_UNLINK;
-#ifdef	REALLY_QUEUE
-	urb->transfer_flags |= USB_QUEUE_BULK;
-#endif
 	// FIXME urb->timeout = ... jiffies ... ;
 
 	spin_lock_irqsave (&dev->txq.lock, flags);
@@ -1640,15 +1838,19 @@
 	}
 #endif	/* CONFIG_USB_NET1080 */
 
-	netif_stop_queue (net);
-	if ((retval = usb_submit_urb (urb)) != 0) {
-		netif_start_queue (net);
+	switch ((retval = SUBMIT_URB (urb, GFP_ATOMIC))) {
+	case -EPIPE:
+		netif_stop_queue (net);
+		defer_kevent (dev, EVENT_TX_HALT);
+		break;
+	default:
 		dbg ("%s tx: submit urb err %d", net->name, retval);
-	} else {
+		break;
+	case 0:
 		net->trans_start = jiffies;
 		__skb_queue_tail (&dev->txq, skb);
-		if (dev->txq.qlen < TX_QLEN)
-			netif_start_queue (net);
+		if (dev->txq.qlen >= TX_QLEN)
+			netif_stop_queue (net);
 	}
 	spin_unlock_irqrestore (&dev->txq.lock, flags);
 
@@ -1715,14 +1917,15 @@
 		}
 
 	// or are we maybe short a few urbs?
-	} else if (netif_running (&dev->net)) {
+	} else if (netif_running (&dev->net)
+			&& !test_bit (EVENT_RX_HALT, &dev->flags)) {
 		int	temp = dev->rxq.qlen;
 
 		if (temp < RX_QLEN) {
 			struct urb	*urb;
 			int		i;
 			for (i = 0; i < 3 && dev->rxq.qlen < RX_QLEN; i++) {
-				if ((urb = usb_alloc_urb (0)) != 0)
+				if ((urb = ALLOC_URB (0, GFP_ATOMIC)) != 0)
 					rx_submit (dev, urb, GFP_ATOMIC);
 			}
 			if (temp != dev->rxq.qlen)
@@ -1750,8 +1953,8 @@
 {
 	struct usbnet	*dev = (struct usbnet *) ptr;
 
-	devinfo (dev, "unregister usbnet %03d/%03d, %s",
-		udev->bus->busnum, udev->devnum,
+	devinfo (dev, "unregister usbnet usb-%s-%s, %s",
+		udev->bus->bus_name, udev->devpath,
 		dev->driver_info->description);
 	
 	unregister_netdev (&dev->net);
@@ -1761,8 +1964,11 @@
 	list_del (&dev->dev_list);
 	mutex_unlock (&usbnet_mutex);
 
+	// assuming we used keventd, it must quiesce too
+	flush_scheduled_tasks ();
+
 	kfree (dev);
-	usb_dec_dev_use (udev);
+	usb_put_dev (udev);
 }
 
 
@@ -1808,15 +2014,17 @@
 	memset (dev, 0, sizeof *dev);
 
 	init_MUTEX_LOCKED (&dev->mutex);
-	usb_inc_dev_use (udev);
+	usb_get_dev (udev);
 	dev->udev = udev;
 	dev->driver_info = info;
+	dev->msg_level = msg_level;
 	INIT_LIST_HEAD (&dev->dev_list);
 	skb_queue_head_init (&dev->rxq);
 	skb_queue_head_init (&dev->txq);
 	skb_queue_head_init (&dev->done);
 	dev->bh.func = usbnet_bh;
 	dev->bh.data = (unsigned long) dev;
+	INIT_TQUEUE (&dev->kevent, kevent, dev);
 
 	// set up network interface records
 	net = &dev->net;
@@ -1836,10 +2044,11 @@
 	net->stop = usbnet_stop;
 	net->watchdog_timeo = TX_TIMEOUT_JIFFIES;
 	net->tx_timeout = usbnet_tx_timeout;
+	net->do_ioctl = usbnet_ioctl;
 
 	register_netdev (&dev->net);
-	devinfo (dev, "register usbnet %03d/%03d, %s",
-		udev->bus->busnum, udev->devnum,
+	devinfo (dev, "register usbnet usb-%s-%s, %s",
+		udev->bus->bus_name, udev->devpath,
 		dev->driver_info->description);
 
 	// ok, it's ready to go.
@@ -1867,33 +2076,41 @@
 #ifdef	CONFIG_USB_AN2720
 {
 	USB_DEVICE (0x0547, 0x2720),	// AnchorChips defaults
-	driver_info:	(unsigned long) &an2720_info,
-},
-
-{
+	.driver_info =	(unsigned long) &an2720_info,
+}, {
 	USB_DEVICE (0x0547, 0x2727),	// Xircom PGUNET
-	driver_info:	(unsigned long) &an2720_info,
+	.driver_info =	(unsigned long) &an2720_info,
 },
 #endif
 
 #ifdef	CONFIG_USB_BELKIN
 {
 	USB_DEVICE (0x050d, 0x0004),	// Belkin
-	driver_info:	(unsigned long) &belkin_info,
+	.driver_info =	(unsigned long) &belkin_info,
 }, {
 	USB_DEVICE (0x056c, 0x8100),	// eTEK
-	driver_info:	(unsigned long) &belkin_info,
+	.driver_info =	(unsigned long) &belkin_info,
 }, {
 	USB_DEVICE (0x0525, 0x9901),	// Advance USBNET (eTEK)
-	driver_info:	(unsigned long) &belkin_info,
+	.driver_info =	(unsigned long) &belkin_info,
+},
+#endif
+
+#ifdef	CONFIG_USB_EPSON2888
+{
+	USB_DEVICE (0x0525, 0x2888),	// EPSON USB client
+	driver_info:	(unsigned long) &epson2888_info,
 },
 #endif
 
 #ifdef	CONFIG_USB_GENESYS
 {
 	USB_DEVICE (0x05e3, 0x0502),	// GL620USB-A
-	driver_info:	(unsigned long) &genelink_info,
+	.driver_info =	(unsigned long) &genelink_info,
 },
+	/* NOT: USB_DEVICE (0x05e3, 0x0501),	// GL620USB
+	 * that's half duplex, not currently supported
+	 */
 #endif
 
 #ifdef	CONFIG_USB_LINUXDEV
@@ -1904,28 +2121,32 @@
 {
 	// 1183 = 0x049F, both used as hex values?
 	USB_DEVICE (0x049F, 0x505A),	// Compaq "Itsy"
-	driver_info:	(unsigned long) &linuxdev_info,
+	.driver_info =	(unsigned long) &linuxdev_info,
+}, {
+	USB_DEVICE (0x0E7E, 0x1001),	// G.Mate "Yopy"
+	.driver_info =	(unsigned long) &linuxdev_info,
 },
+	// NOTE:  the Sharp Zaurus uses a modified version of
+	// this driver, which is not interoperable with this.
 #endif
 
 #ifdef	CONFIG_USB_NET1080
 {
 	USB_DEVICE (0x0525, 0x1080),	// NetChip ref design
-	driver_info:	(unsigned long) &net1080_info,
-},
-{
+	.driver_info =	(unsigned long) &net1080_info,
+}, {
 	USB_DEVICE (0x06D0, 0x0622),	// Laplink Gold
-	driver_info:	(unsigned long) &net1080_info,
+	.driver_info =	(unsigned long) &net1080_info,
 },
 #endif
 
 #ifdef CONFIG_USB_PL2301
 {
 	USB_DEVICE (0x067b, 0x0000),	// PL-2301
-	driver_info:	(unsigned long) &prolific_info,
+	.driver_info =	(unsigned long) &prolific_info,
 }, {
 	USB_DEVICE (0x067b, 0x0001),	// PL-2302
-	driver_info:	(unsigned long) &prolific_info,
+	.driver_info =	(unsigned long) &prolific_info,
 },
 #endif
 
@@ -1936,10 +2157,10 @@
 MODULE_DEVICE_TABLE (usb, products);
 
 static struct usb_driver usbnet_driver = {
-	name:		"usbnet",
-	id_table:	products,
-	probe:		usbnet_probe,
-	disconnect:	usbnet_disconnect,
+	.name =		driver_name,
+	.id_table =	products,
+	.probe =	usbnet_probe,
+	.disconnect =	usbnet_disconnect,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -1952,6 +2173,7 @@
 
 	get_random_bytes (node_id, sizeof node_id);
 	node_id [0] &= 0xfe;	// clear multicast bit
+	node_id [0] |= 0x02;    // set local assignment bit (IEEE802)
 
  	if (usb_register (&usbnet_driver) < 0)
  		return -1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/usbvideo.c linux-2.4.20/drivers/usb/usbvideo.c
--- linux-2.4.19/drivers/usb/usbvideo.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/usbvideo.c	2002-10-29 11:18:40.000000000 +0000
@@ -58,57 +58,26 @@
 /* Memory management functions */
 /*******************************/
 
-#define MDEBUG(x)	do { } while(0)		/* Debug memory management */
-
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-unsigned long usbvideo_uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
-	unsigned long ret = 0UL;
-	pmd_t *pmd;
-	pte_t *ptep, pte;
-
-	if (!pgd_none(*pgd)) {
-		pmd = pmd_offset(pgd, adr);
-		if (!pmd_none(*pmd)) {
-			ptep = pte_offset(pmd, adr);
-			pte = *ptep;
-			if (pte_present(pte)) {
-				ret = (unsigned long) page_address(pte_page(pte));
-				ret |= (adr & (PAGE_SIZE-1));
-			}
-		}
-	}
-	MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
-	return ret;
-}
-
 /*
  * Here we want the physical address of the memory.
- * This is used when initializing the contents of the
- * area and marking the pages as reserved.
+ * This is used when initializing the contents of the area.
  */
 unsigned long usbvideo_kvirt_to_pa(unsigned long adr)
 {
-	unsigned long va, kva, ret;
+	unsigned long kva, ret;
 
-	va = VMALLOC_VMADDR(adr);
-	kva = usbvideo_uvirt_to_kva(pgd_offset_k(va), va);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
 	ret = __pa(kva);
-	MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
 	return ret;
 }
 
 void *usbvideo_rvmalloc(unsigned long size)
 {
 	void *mem;
-	unsigned long adr, page;
-
-	/* Round it off to PAGE_SIZE */
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
+	unsigned long adr;
 
+	size = PAGE_ALIGN(size);
 	mem = vmalloc_32(size);
 	if (!mem)
 		return NULL;
@@ -116,13 +85,9 @@
 	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
 	adr = (unsigned long) mem;
 	while (size > 0) {
-		page = usbvideo_kvirt_to_pa(adr);
-		mem_map_reserve(virt_to_page(__va(page)));
+		mem_map_reserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 
 	return mem;
@@ -130,23 +95,16 @@
 
 void usbvideo_rvfree(void *mem, unsigned long size)
 {
-	unsigned long adr, page;
+	unsigned long adr;
 
 	if (!mem)
 		return;
 
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
-
-	adr=(unsigned long) mem;
-	while (size > 0) {
-		page = usbvideo_kvirt_to_pa(adr);
-		mem_map_unreserve(virt_to_page(__va(page)));
+	adr = (unsigned long) mem;
+	while ((long) size > 0) {
+		mem_map_unreserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 	vfree(mem);
 }
@@ -1782,7 +1740,7 @@
 /*
  * Make all of the blocks of data contiguous
  */
-static int usbvideo_CompressIsochronous(uvd_t *uvd, urb_t *urb)
+static int usbvideo_CompressIsochronous(uvd_t *uvd, struct urb *urb)
 {
 	char *cdata;
 	int i, totlen = 0;
@@ -1897,7 +1855,7 @@
 	/* We double buffer the Iso lists */
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		int j, k;
-		urb_t *urb = uvd->sbuf[i].urb;
+		struct urb *urb = uvd->sbuf[i].urb;
 		urb->dev = dev;
 		urb->context = uvd;
 		urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/usbvideo.h linux-2.4.20/drivers/usb/usbvideo.h
--- linux-2.4.19/drivers/usb/usbvideo.h	2001-10-11 06:42:46.000000000 +0000
+++ linux-2.4.20/drivers/usb/usbvideo.h	2002-10-29 11:18:39.000000000 +0000
@@ -165,7 +165,7 @@
 /* This structure represents one Isoc request - URB and buffer */
 typedef struct {
 	char *data;
-	urb_t *urb;
+	struct urb *urb;
 } usbvideo_sbuf_t;
 
 typedef struct {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/vicam.c linux-2.4.20/drivers/usb/vicam.c
--- linux-2.4.19/drivers/usb/vicam.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/vicam.c	2002-10-29 11:18:34.000000000 +0000
@@ -91,80 +91,25 @@
  *
  ******************************************************************************/
 
-/* [DaveM] I've recoded most of this so that:
- * 1) It's easier to tell what is happening
- * 2) It's more portable, especially for translating things
- *    out of vmalloc mapped areas in the kernel.
- * 3) Less unnecessary translations happen.
- *
- * The code used to assume that the kernel vmalloc mappings
- * existed in the page tables of every process, this is simply
- * not guarenteed.  We now use pgd_offset_k which is the
- * defined way to get at the kernel page tables.
- */
-
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
-	unsigned long ret = 0UL;
-	pmd_t *pmd;
-	pte_t *ptep, pte;
-
-	if (!pgd_none(*pgd)) {
-		pmd = pmd_offset(pgd, adr);
-		if (!pmd_none(*pmd)) {
-			ptep = pte_offset(pmd, adr);
-			pte = *ptep;
-			if(pte_present(pte)) {
-				ret  = (unsigned long) page_address(pte_page(pte));
-				ret |= (adr & (PAGE_SIZE - 1));
-
-			}
-		}
-	}
-	return ret;
-}
-
-static inline unsigned long uvirt_to_bus(unsigned long adr)
-{
-	unsigned long kva, ret;
-
-	kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
-	ret = virt_to_bus((void *)kva);
-	return ret;
-}
-
-static inline unsigned long kvirt_to_bus(unsigned long adr)
-{
-	unsigned long va, kva, ret;
-
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
-	ret = virt_to_bus((void *)kva);
-	return ret;
-}
-
 /* Here we want the physical address of the memory.
- * This is used when initializing the contents of the
- * area and marking the pages as reserved.
+ * This is used when initializing the contents of the area.
  */
 static inline unsigned long kvirt_to_pa(unsigned long adr)
 {
-	unsigned long va, kva, ret;
+	unsigned long kva, ret;
 
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
 	ret = __pa(kva);
 	return ret;
 }
 
-static void * rvmalloc(signed long size)
+static void * rvmalloc(unsigned long size)
 {
 	void * mem;
-	unsigned long adr, page;
+	unsigned long adr;
 
+	size=PAGE_ALIGN(size);
 	mem=vmalloc_32(size);
 	if (mem)
 	{
@@ -172,8 +117,7 @@
 		adr=(unsigned long) mem;
 		while (size > 0)
 		{
-			page = kvirt_to_pa(adr);
-			mem_map_reserve(virt_to_page(__va(page)));
+			mem_map_reserve(vmalloc_to_page((void *)adr));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -181,17 +125,16 @@
 	return mem;
 }
 
-static void rvfree(void * mem, signed long size)
+static void rvfree(void * mem, unsigned long size)
 {
-	unsigned long adr, page;
+	unsigned long adr;
 
 	if (mem)
 	{
 		adr=(unsigned long) mem;
-		while (size > 0)
+		while ((long) size > 0)
 		{
-			page = kvirt_to_pa(adr);
-			mem_map_unreserve(virt_to_page(__va(page)));
+			mem_map_unreserve(vmalloc_to_page((void *)adr));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -532,7 +475,9 @@
 
 	if (!vdev || !buf)
 		return -EFAULT;
-
+	
+	if(buflen > 0x1e480)
+		buflen = 0x1e480;
 	if (copy_to_user(user_buf, buf2, buflen))
 		return -EFAULT;
 	return buflen;
@@ -866,7 +811,7 @@
 	return 1;
 }
 
-static void * __devinit vicam_probe(struct usb_device *udev, unsigned int ifnum,
+static void * vicam_probe(struct usb_device *udev, unsigned int ifnum,
 	const struct usb_device_id *id)
 {
 	struct usb_vicam *vicam;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/vicam.h linux-2.4.20/drivers/usb/vicam.h
--- linux-2.4.19/drivers/usb/vicam.h	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.20/drivers/usb/vicam.h	2002-10-29 11:18:39.000000000 +0000
@@ -68,7 +68,7 @@
 	/* v4l stuff */
 	char *camera_name;
 	char *fbuf;
-	urb_t *urb[VICAM_NUMSBUF];
+	struct urb *urb[VICAM_NUMSBUF];
 	int sizes;
 	int *width;
 	int *height;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/vicamurbs.h linux-2.4.20/drivers/usb/vicamurbs.h
--- linux-2.4.19/drivers/usb/vicamurbs.h	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.20/drivers/usb/vicamurbs.h	2002-10-29 11:18:36.000000000 +0000
@@ -17,12 +17,6 @@
 
 /* Request 0x51 Image Setup */
 
-/* 128x98 ? 0x3180 size */
-static unsigned char s128x98bw[] = {
-  0,    0x34, 0xC4, 0x00, 0x00, 0x00, 0,    0,
-  0x18, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
-};
-
 /* 128x122 3D80 size */
 static unsigned char s128x122bw[] = {
   0,    0x34, 0xF4, 0x00, 0x00, 0x00, 0,    0,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/usb/wacom.c linux-2.4.20/drivers/usb/wacom.c
--- linux-2.4.19/drivers/usb/wacom.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/usb/wacom.c	2002-10-29 11:18:32.000000000 +0000
@@ -111,7 +111,6 @@
 	struct wacom_features *features;
 	int tool[2];
 	int open;
-	int x, y;
 	__u32 serial[2];
 };
 
@@ -209,16 +208,16 @@
 			input_report_abs(dev, ABS_DISTANCE, data[7]);
 			input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
 
-			input_report_abs(dev, ABS_X, wacom->x = x);
-			input_report_abs(dev, ABS_Y, wacom->y = y);
+			input_report_abs(dev, ABS_X, x);
+			input_report_abs(dev, ABS_Y, y);
 
 			input_event(dev, EV_MSC, MSC_SERIAL, data[1] & 0x01);
 			return;
 	}
 
 	if (data[1] & 0x80) {
-		input_report_abs(dev, ABS_X, wacom->x = x);
-		input_report_abs(dev, ABS_Y, wacom->y = y);
+		input_report_abs(dev, ABS_X, x);
+		input_report_abs(dev, ABS_Y, y);
 	}
 
 	input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
@@ -236,7 +235,6 @@
 	struct input_dev *dev = &wacom->dev;
 	unsigned int t;
 	int idx;
-	int x, y; 
 
 	if (urb->status) return;
 
@@ -285,11 +283,8 @@
 		return;
 	}
 
-	x = ((__u32)data[2] << 8) | data[3];
-	y = ((__u32)data[4] << 8) | data[5];
-	
-	input_report_abs(dev, ABS_X, wacom->x);
-	input_report_abs(dev, ABS_Y, wacom->y);
+	input_report_abs(dev, ABS_X, ((__u32)data[2] << 8) | data[3]);
+	input_report_abs(dev, ABS_Y, ((__u32)data[4] << 8) | data[5]);
 	input_report_abs(dev, ABS_DISTANCE, data[9] >> 4);
 	
 	if ((data[1] & 0xb8) == 0xa0) {						/* general pen packet */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/Config.in linux-2.4.20/drivers/video/Config.in
--- linux-2.4.19/drivers/video/Config.in	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/Config.in	2002-10-29 11:18:48.000000000 +0000
@@ -90,7 +90,7 @@
    if [ "$ARCH" = "alpha" ]; then
       tristate '  TGA framebuffer support' CONFIG_FB_TGA
    fi
-   if [ "$ARCH" = "i386" ]; then
+   if [ "$CONFIG_X86" = "y" ]; then
       bool '  VESA VGA graphics console' CONFIG_FB_VESA
       tristate '  VGA 16-color graphics console' CONFIG_FB_VGA16
       tristate '  Hercules mono graphics console (EXPERIMENTAL)' CONFIG_FB_HGA
@@ -150,18 +150,37 @@
 	 tristate '  3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
 	 tristate '  3Dfx Voodoo Graphics (sst1) support (EXPERIMENTAL)' CONFIG_FB_VOODOO1
 	 tristate '  Trident support (EXPERIMENTAL)' CONFIG_FB_TRIDENT
+	 if [ "$CONFIG_MIPS" = "y" ]; then
+	   tristate '  Epson SED1356 framebuffer support' CONFIG_FB_E1356
+	   if [ "$CONFIG_MIPS_PB1000" = "y" -a "$CONFIG_FB_E1356" != "n" ]; then
+	     bool '    Use CRT on Pb1000 (J65)' CONFIG_PB1000_CRT
+	     bool '    Use Compsite NTSC on Pb1000 (J63)' CONFIG_PB1000_NTSC
+	     bool '    Use TFT Panel on Pb1000 (J64)' CONFIG_PB1000_TFT
+	   fi
+           if [ "$CONFIG_MIPS_PB1500" = "y" -a "$CONFIG_FB_E1356" != "n" ]; then
+	     bool '    Use CRT on Pb1500 ' CONFIG_PB1500_CRT
+	     bool '    Use TFT Panel on Pb1500 ' CONFIG_PB1500_TFT
+           fi
+           if [ "$CONFIG_MIPS_PB1100" = "y" -a "$CONFIG_FB_E1356" != "n" ]; then
+	     bool '    Use CRT on Pb1100 ' CONFIG_PB1500_CRT
+	     bool '    Use TFT Panel on Pb1100 ' CONFIG_PB1500_TFT
+           fi
+           if [ "$CONFIG_MIPS_PB1100" = "y" ]; then
+	     bool '    Au1100 LCD Driver' CONFIG_FB_AU1100
+           fi
+	 fi
       fi
    fi
-   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
       bool '  SBUS and UPA framebuffers' CONFIG_FB_SBUS
       if [ "$CONFIG_FB_SBUS" != "n" ]; then
-	 if [ "$ARCH" = "sparc64" ]; then
+	 if [ "$CONFIG_SPARC64" = "y" ]; then
 	    bool '    Creator/Creator3D support' CONFIG_FB_CREATOR
 	 fi
 	 bool '    CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
 	 bool '    BWtwo support' CONFIG_FB_BWTWO
 	 bool '    CGthree support' CONFIG_FB_CGTHREE
-	 if [ "$ARCH" = "sparc" ]; then
+	 if [ "$CONFIG_SPARC32" = "y" ]; then
 	    bool '    TCX (SS4/SS5 only) support' CONFIG_FB_TCX
 	    bool '    CGfourteen (SX) support' CONFIG_FB_CGFOURTEEN
 	    bool '    P9100 (Sparcbook 3 only) support' CONFIG_FB_P9100
@@ -169,7 +188,7 @@
 	 bool '    Leo (ZX) support' CONFIG_FB_LEO
       fi
    fi
-   if [ "$ARCH" = "sparc" ]; then
+   if [ "$CONFIG_SPARC32" = "y" ]; then
       if [ "$CONFIG_PCI" != "n" ]; then
 	 bool '  PCI framebuffers' CONFIG_FB_PCI
 	 if [ "$CONFIG_FB_PCI" != "n" ]; then
@@ -177,7 +196,7 @@
 	 fi
       fi
    fi
-   if [ "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC64" = "y" ]; then
       if [ "$CONFIG_PCI" != "n" ]; then
 	 bool '  PCI framebuffers' CONFIG_FB_PCI
 	 if [ "$CONFIG_FB_PCI" != "n" ]; then
@@ -192,17 +211,15 @@
       tristate '  HD64461 Frame Buffer support' CONFIG_FB_HIT
    fi
    if [ "$CONFIG_DECSTATION" = "y" ]; then
-     if [ "$CONFIG_TC" = "y" ]; then
-       bool '  PMAG-BA TURBOchannel framebuffer support' CONFIG_FB_PMAG_BA
-       bool '  PMAGB-B TURBOchannel framebuffer spport' CONFIG_FB_PMAGB_B
-       bool '  Maxine (Personal DECstation) onboard framebuffer spport' CONFIG_FB_MAXINE
-     fi
+      dep_bool '  PMAG-BA TURBOchannel framebuffer support' CONFIG_FB_PMAG_BA $CONFIG_TC
+      dep_bool '  PMAGB-B TURBOchannel framebuffer support' CONFIG_FB_PMAGB_B $CONFIG_TC
+      bool '  Maxine (Personal DECstation) onboard framebuffer support' CONFIG_FB_MAXINE
    fi
    if [ "$CONFIG_NINO" = "y" ]; then
       bool '  TMPTX3912/PR31700 frame buffer support' CONFIG_FB_TX3912
    fi
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate '  Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL
+      tristate '  Virtual Frame Buffer support (ONLY FOR TESTING!) (EXPERIMENTAL)' CONFIG_FB_VIRTUAL
    fi
 
    bool '  Advanced low level driver options' CONFIG_FBCON_ADVANCED
@@ -267,14 +284,15 @@
 	   "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
            "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
 	   "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
-           "$CONFIG_FB_PM3" = "y" -o \
+           "$CONFIG_FB_PM3" = "y" -o "$CONFIG_FB_TRIDENT" = "y" -o \
 	   "$CONFIG_FB_P9100" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
 	   "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
 	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \
 	   "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \
 	   "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \
-	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
+	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \
+	   "$CONFIG_FB_STI" = "y" -o "$CONFIG_FB_HP300" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB8 y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
@@ -288,14 +306,15 @@
 	      "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
               "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
 	      "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
-              "$CONFIG_FB_PM3" = "m" -o \
+              "$CONFIG_FB_PM3" = "m" -o "$CONFIG_FB_TRIDENT" = "y" -o \
 	      "$CONFIG_FB_P9100" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_3DFX" = "m" -o \
 	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \
 	      "$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \
 	      "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
-	      "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" ]; then
+	      "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" -o \
+	      "$CONFIG_FB_STI" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB8 m
 	 fi
       fi
@@ -308,7 +327,7 @@
 	   "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
 	   "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
 	   "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
-           "$CONFIG_FB_PM3" = "y" -o \
+           "$CONFIG_FB_PM3" = "y" -o "$CONFIG_FB_TRIDENT" = "y" -o \
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y"  -o \
 	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
@@ -325,7 +344,7 @@
 	      "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
 	      "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
 	      "$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" -o \
-              "$CONFIG_FB_PM3" = "m" -o \
+              "$CONFIG_FB_PM3" = "m" -o "$CONFIG_FB_TRIDENT" = "y" -o \
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
 	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
@@ -356,12 +375,13 @@
 	   "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
 	   "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
 	   "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
-           "$CONFIG_FB_PM3" = "y" -o \
+           "$CONFIG_FB_PM3" = "y" -o "$CONFIG_FB_TRIDENT" = "y" -o \
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
 	   "$CONFIG_FB_RADEON" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \
 	   "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" -o \
-	   "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_CYBER2000" = "y" ]; then
+	   "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
+	   "$CONFIG_FB_STI" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB32 y
       else
 	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
@@ -369,12 +389,12 @@
 	      "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
 	      "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
 	      "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
-              "$CONFIG_FB_PM3" = "m" -o \
+              "$CONFIG_FB_PM3" = "m" -o "$CONFIG_FB_TRIDENT" = "y" -o \
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	      "$CONFIG_FB_3DFX" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
 	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
-	      "$CONFIG_FB_CYBER2000" = "m" ]; then
+	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_STI" = "y" ]; then
 	    define_tristate CONFIG_FBCON_CFB32 m
 	 fi
       fi
@@ -426,7 +446,7 @@
       fi
    fi
    bool '  Support only 8 pixels wide fonts' CONFIG_FBCON_FONTWIDTH8_ONLY
-   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
       bool '  Sparc console 8x16 font' CONFIG_FONT_SUN8x16
       if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
 	 bool '  Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/Makefile linux-2.4.20/drivers/video/Makefile
--- linux-2.4.19/drivers/video/Makefile	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/Makefile	2002-10-29 11:18:33.000000000 +0000
@@ -4,7 +4,7 @@
 
 O_TARGET := video.o
 
-mod-subdirs	:= matrox
+mod-subdirs	:= matrox sti
 
 # All of the (potential) objects that export symbols.
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
@@ -22,7 +22,6 @@
 obj-$(CONFIG_DUMMY_CONSOLE)       += dummycon.o
 obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o
 obj-$(CONFIG_PROM_CONSOLE)        += promcon.o promcon_tbl.o
-obj-$(CONFIG_STI_CONSOLE)         += sticon.o sticon-bmode.o sticore.o
 obj-$(CONFIG_VGA_CONSOLE)         += vgacon.o
 obj-$(CONFIG_MDA_CONSOLE)         += mdacon.o
 
@@ -82,12 +81,21 @@
 obj-$(CONFIG_FB_CGFOURTEEN)       += cgfourteenfb.o sbusfb.o
 obj-$(CONFIG_FB_P9100)            += p9100fb.o sbusfb.o
 obj-$(CONFIG_FB_LEO)              += leofb.o sbusfb.o
-obj-$(CONFIG_FB_STI)	          += stifb.o sticore.o fbgen.o
 obj-$(CONFIG_FB_PMAG_BA)          += pmag-ba-fb.o
 obj-$(CONFIG_FB_PMAGB_B)          += pmagb-b-fb.o
 obj-$(CONFIG_FB_MAXINE)           += maxinefb.o
 obj-$(CONFIG_FB_TX3912)           += tx3912fb.o
+obj-$(CONFIG_FB_AU1100)		  += au1100fb.o fbgen.o
 
+subdir-$(CONFIG_STI_CONSOLE)      += sti
+ifeq ($(CONFIG_STI_CONSOLE),y)
+obj-y                             += sti/sti.o fonts.o
+endif
+
+subdir-$(CONFIG_FB_STI)           += sti
+ifeq ($(CONFIG_FB_STI),y)
+obj-y                             += sti/sti.o fbgen.o
+endif
 
 subdir-$(CONFIG_FB_MATROX)	  += matrox
 ifeq ($(CONFIG_FB_MATROX),y)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/aty/atyfb.h linux-2.4.20/drivers/video/aty/atyfb.h
--- linux-2.4.19/drivers/video/aty/atyfb.h	2001-07-31 21:43:29.000000000 +0000
+++ linux-2.4.20/drivers/video/aty/atyfb.h	2002-10-29 11:18:49.000000000 +0000
@@ -174,10 +174,10 @@
 {
     /* Hack for bloc 1, should be cleanly optimized by compiler */
     if (regindex >= 0x400)
-    	regindex -= 0x800;
+	regindex -= 0x800;
 
-#if defined(__mc68000__)
-    return le32_to_cpu(*((volatile u32 *)(info->ati_regbase+regindex)));
+#ifdef CONFIG_ATARI
+    return in_le32((volatile u32 *)(info->ati_regbase+regindex));
 #else
     return readl (info->ati_regbase + regindex);
 #endif
@@ -188,10 +188,10 @@
 {
     /* Hack for bloc 1, should be cleanly optimized by compiler */
     if (regindex >= 0x400)
-    	regindex -= 0x800;
+	regindex -= 0x800;
 
-#if defined(__mc68000__)
-    *((volatile u32 *)(info->ati_regbase+regindex)) = cpu_to_le32(val);
+#ifdef CONFIG_ATARI
+    out_le32 (info->ati_regbase+regindex, val);
 #else
     writel (val, info->ati_regbase + regindex);
 #endif
@@ -202,9 +202,13 @@
 {
     /* Hack for bloc 1, should be cleanly optimized by compiler */
     if (regindex >= 0x400)
-    	regindex -= 0x800;
+	regindex -= 0x800;
 
+#ifdef CONFIG_ATARI
+    return in_8 (info->ati_regbase + regindex);
+#else
     return readb (info->ati_regbase + regindex);
+#endif
 }
 
 static inline void aty_st_8(int regindex, u8 val,
@@ -212,9 +216,13 @@
 {
     /* Hack for bloc 1, should be cleanly optimized by compiler */
     if (regindex >= 0x400)
-    	regindex -= 0x800;
+	regindex -= 0x800;
 
+#ifdef CONFIG_ATARI
+    out_8 (info->ati_regbase + regindex, val);
+#else
     writeb (val, info->ati_regbase + regindex);
+#endif
 }
 
 static inline u8 aty_ld_pll(int offset, const struct fb_info_aty *info)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/aty/atyfb_base.c linux-2.4.20/drivers/video/aty/atyfb_base.c
--- linux-2.4.19/drivers/video/aty/atyfb_base.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/aty/atyfb_base.c	2002-10-29 11:18:33.000000000 +0000
@@ -2516,9 +2516,11 @@
 	 *  Map the video memory (physical address given) to somewhere in the
 	 *  kernel address space.
 	 */
-	info->frame_buffer = ioremap(phys_vmembase[m64_num], phys_size[m64_num]);
+	info->frame_buffer = (unsigned long)ioremap(phys_vmembase[m64_num],
+						    phys_size[m64_num]);
 	info->frame_buffer_phys = info->frame_buffer;  /* Fake! */
-	info->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000)+0xFC00ul;
+	info->ati_regbase = (unsigned long)ioremap(phys_guiregbase[m64_num],
+						   0x10000)+0xFC00ul;
 	info->ati_regbase_phys = info->ati_regbase;  /* Fake! */
 
 	aty_st_le32(CLOCK_CNTL, 0x12345678, info);
@@ -2796,10 +2798,17 @@
     aty_st_8(DAC_CNTL, i, info);
     aty_st_8(DAC_MASK, 0xff, info);
     scale = (M64_HAS(INTEGRATED) && info->current_par.crtc.bpp == 16) ? 3 : 0;
+#ifdef CONFIG_ATARI
+    out_8(&info->aty_cmap_regs->windex, regno << scale);
+    out_8(&info->aty_cmap_regs->lut, red);
+    out_8(&info->aty_cmap_regs->lut, green);
+    out_8(&info->aty_cmap_regs->lut, blue);
+#else
     writeb(regno << scale, &info->aty_cmap_regs->windex);
     writeb(red, &info->aty_cmap_regs->lut);
     writeb(green, &info->aty_cmap_regs->lut);
     writeb(blue, &info->aty_cmap_regs->lut);
+#endif
     if (regno < 16)
 	switch (info->current_par.crtc.bpp) {
 #ifdef FBCON_HAS_CFB16
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/aty128fb.c linux-2.4.20/drivers/video/aty128fb.c
--- linux-2.4.19/drivers/video/aty128fb.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/aty128fb.c	2002-10-29 11:18:40.000000000 +0000
@@ -2080,7 +2080,7 @@
 					"Guessing...\n");
 	else {
 		printk(KERN_INFO "aty128fb: Rage128 BIOS located at "
-				"segment %4.4X\n", (unsigned int)bios_seg);
+				"segment %4.4lX\n", (unsigned long)bios_seg);
 		aty128_get_pllinfo(info, bios_seg);
 	}
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/au1100fb.c linux-2.4.20/drivers/video/au1100fb.c
--- linux-2.4.19/drivers/video/au1100fb.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/video/au1100fb.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,647 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Au1100 LCD Driver.
+ *
+ * Copyright 2002 MontaVista Software
+ * Author: MontaVista Software, Inc.
+ *		ppopov@mvista.com or source@mvista.com
+ *
+ * Copyright 2002 Alchemy Semiconductor
+ * Author: Alchemy Semiconductor
+ *
+ * Based on:
+ * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
+ *  Created 28 Dec 1997 by Geert Uytterhoeven
+ *
+ *  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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/au1000.h>
+#include <asm/pb1100.h>
+#include "au1100fb.h"
+
+#include <video/fbcon.h>
+#include <video/fbcon-mfb.h>
+#include <video/fbcon-cfb2.h>
+#include <video/fbcon-cfb4.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+
+/* 
+ * Sanity check. If this is a new Au1100 based board, search for
+ * the PB1100 ifdefs to make sure you modify the code accordingly.
+ */
+#ifndef CONFIG_MIPS_PB1100
+error Unknown Au1100 board
+#endif
+
+#define CMAPSIZE 16
+
+static int my_lcd_index; /* default is zero */
+struct known_lcd_panels *p_lcd;
+AU1100_LCD *p_lcd_reg = (AU1100_LCD *)AU1100_LCD_ADDR;
+
+struct au1100fb_info {
+	struct fb_info_gen gen;
+	unsigned long fb_virt_start;
+	unsigned long fb_size;
+	unsigned long fb_phys;
+	int mmaped;
+	int nohwcursor;
+
+	struct { unsigned red, green, blue, pad; } palette[256];
+
+#if defined(FBCON_HAS_CFB16)
+	u16 fbcon_cmap16[16];
+#endif
+};
+
+
+struct au1100fb_par {
+        struct fb_var_screeninfo var;
+	
+	int line_length;  // in bytes
+	int cmap_len;     // color-map length
+};
+
+
+static struct au1100fb_info fb_info;
+static struct au1100fb_par current_par;
+static struct display disp;
+
+int au1100fb_init(void);
+void au1100fb_setup(char *options, int *ints);
+static int au1100fb_mmap(struct fb_info *fb, struct file *file, 
+		struct vm_area_struct *vma);
+static int au1100_blank(int blank_mode, struct fb_info_gen *info);
+static int au1100fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+			  u_long arg, int con, struct fb_info *info);
+
+void au1100_nocursor(struct display *p, int mode, int xx, int yy){};
+
+static struct fb_ops au1100fb_ops = {
+	owner:		THIS_MODULE,
+	fb_get_fix:	fbgen_get_fix,
+	fb_get_var:	fbgen_get_var,
+	fb_set_var:	fbgen_set_var,
+	fb_get_cmap:	fbgen_get_cmap,
+	fb_set_cmap:	fbgen_set_cmap,
+	fb_pan_display: fbgen_pan_display,
+        fb_ioctl:       au1100fb_ioctl,
+	fb_mmap:        au1100fb_mmap,
+};
+
+static void au1100_detect(void)
+{
+	/*
+	 *  This function should detect the current video mode settings 
+	 *  and store it as the default video mode
+	 */
+
+	/*
+	 * Yeh, well, we're not going to change any settings so we're
+	 * always stuck with the default ...
+	 */
+
+}
+
+static int au1100_encode_fix(struct fb_fix_screeninfo *fix, 
+		const void *_par, struct fb_info_gen *_info)
+{
+        struct au1100fb_info *info = (struct au1100fb_info *) _info;
+        struct au1100fb_par *par = (struct au1100fb_par *) _par;
+	struct fb_var_screeninfo *var = &par->var;
+
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+	fix->smem_start = info->fb_phys;
+	fix->smem_len = info->fb_size;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->type_aux = 0;
+        fix->visual = (var->bits_per_pixel == 8) ?
+	       	FB_VISUAL_PSEUDOCOLOR	: FB_VISUAL_TRUECOLOR;
+	fix->ywrapstep = 0;
+	fix->xpanstep = 1;
+	fix->ypanstep = 1;
+	fix->line_length = current_par.line_length;
+	return 0;
+}
+
+static void set_color_bitfields(struct fb_var_screeninfo *var)
+{
+	switch (var->bits_per_pixel) {
+	case 8:
+		var->red.offset = 0;
+		var->red.length = 8;
+		var->green.offset = 0;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	case 16:	/* RGB 565 */
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	}
+
+	var->red.msb_right = 0;
+	var->green.msb_right = 0;
+	var->blue.msb_right = 0;
+	var->transp.msb_right = 0;
+}
+
+static int au1100_decode_var(const struct fb_var_screeninfo *var, 
+		void *_par, struct fb_info_gen *_info)
+{
+
+	struct au1100fb_par *par = (struct au1100fb_par *)_par;
+
+	/*
+	 * Don't allow setting any of these yet: xres and yres don't
+	 * make sense for LCD panels.
+	 */
+	if (var->xres != p_lcd->xres ||
+	    var->yres != p_lcd->yres ||
+	    var->xres != p_lcd->xres ||
+	    var->yres != p_lcd->yres) {
+		return -EINVAL;
+	}
+	if(var->bits_per_pixel != p_lcd->bpp) {
+		return -EINVAL;
+	}
+
+	memset(par, 0, sizeof(struct au1100fb_par));
+	par->var = *var;
+	
+	/* FIXME */
+	switch (var->bits_per_pixel) {
+		case 8:
+			par->var.bits_per_pixel = 8;
+			break;
+		case 16:
+			par->var.bits_per_pixel = 16;
+			break;
+		default:
+			printk("color depth %d bpp not supported\n",
+					var->bits_per_pixel);
+			return -EINVAL;
+
+	}
+	set_color_bitfields(&par->var);
+	par->cmap_len = (par->var.bits_per_pixel == 8) ? 256 : 16;
+	return 0;
+}
+
+static int au1100_encode_var(struct fb_var_screeninfo *var, 
+		const void *par, struct fb_info_gen *_info)
+{
+
+	*var = ((struct au1100fb_par *)par)->var;
+	return 0;
+}
+
+static void 
+au1100_get_par(void *_par, struct fb_info_gen *_info)
+{
+	*(struct au1100fb_par *)_par = current_par;
+}
+
+static void au1100_set_par(const void *par, struct fb_info_gen *info)
+{
+	/* nothing to do: we don't change any settings */
+}
+
+static int au1100_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			 unsigned *blue, unsigned *transp,
+			 struct fb_info *info)
+{
+
+	struct au1100fb_info* i = (struct au1100fb_info*)info;
+
+	if (regno > 255)
+		return 1;
+   
+	*red    = i->palette[regno].red; 
+	*green  = i->palette[regno].green; 
+	*blue   = i->palette[regno].blue; 
+	*transp = 0;
+
+	return 0;
+}
+
+static int au1100_setcolreg(unsigned regno, unsigned red, unsigned green,
+			 unsigned blue, unsigned transp,
+			 struct fb_info *info)
+{
+	struct au1100fb_info* i = (struct au1100fb_info *)info;
+	u32 rgbcol;
+
+	if (regno > 255)
+		return 1;
+
+	i->palette[regno].red    = red;
+	i->palette[regno].green  = green;
+	i->palette[regno].blue   = blue;
+   
+	switch(p_lcd->bpp) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		red >>= 10;
+		green >>= 10;
+		blue >>= 10;
+		p_lcd_reg->lcd_pallettebase[regno] = (blue&0x1f) | 
+			((green&0x3f)<<5) | ((red&0x1f)<<11);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		i->fbcon_cmap16[regno] =
+			((red & 0xf800) >> 0) |
+			((green & 0xfc00) >> 5) |
+			((blue & 0xf800) >> 11);
+		break;
+#endif
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+
+static int  au1100_blank(int blank_mode, struct fb_info_gen *_info)
+{
+
+	switch (blank_mode) {
+	case VESA_NO_BLANKING:
+		/* turn on panel */
+		//printk("turn on panel\n");
+#ifdef CONFIG_MIPS_PB1100
+		p_lcd_reg->lcd_control |= LCD_CONTROL_GO;
+		au_writew(au_readw(PB1100_G_CONTROL) | p_lcd->mode_backlight, 
+			PB1100_G_CONTROL);
+		au_sync();
+#endif
+		break;
+
+	case VESA_VSYNC_SUSPEND:
+	case VESA_HSYNC_SUSPEND:
+	case VESA_POWERDOWN:
+		/* turn off panel */
+		//printk("turn off panel\n");
+#ifdef CONFIG_MIPS_PB1100
+		p_lcd_reg->lcd_control &= ~LCD_CONTROL_GO;
+		au_writew(au_readw(PB1100_G_CONTROL) & ~p_lcd->mode_backlight, 
+			PB1100_G_CONTROL);
+		au_sync();
+#endif
+		break;
+	default: 
+		break;
+
+	}
+	return 0;
+}
+
+static void au1100_set_disp(const void *unused, struct display *disp,
+			 struct fb_info_gen *info)
+{
+	disp->screen_base = (char *)fb_info.fb_virt_start;
+
+	switch (disp->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		disp->dispsw = &fbcon_cfb8;
+		if (fb_info.nohwcursor)
+			fbcon_cfb8.cursor = au1100_nocursor;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		disp->dispsw = &fbcon_cfb16;
+		disp->dispsw_data = fb_info.fbcon_cmap16;
+		if (fb_info.nohwcursor)
+			fbcon_cfb16.cursor = au1100_nocursor;
+		break;
+#endif
+	default:
+		disp->dispsw = &fbcon_dummy;
+		disp->dispsw_data = NULL;
+		break;
+	}
+}
+
+static int
+au1100fb_mmap(struct fb_info *_fb,
+	     struct file *file,
+	     struct vm_area_struct *vma)
+{
+	unsigned int len;
+	unsigned long start=0, off;
+	struct au1100fb_info *fb = (struct au1100fb_info *)_fb;
+
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
+		return -EINVAL;
+	}
+    
+	start = fb_info.fb_phys & PAGE_MASK;
+	len = PAGE_ALIGN((start & ~PAGE_MASK) + fb_info.fb_size);
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+
+	if ((vma->vm_end - vma->vm_start + off) > len) {
+		return -EINVAL;
+	}
+
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+
+	pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
+	pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT;
+
+	/* This is an IO map - tell maydump to skip this VMA */
+	vma->vm_flags |= VM_IO;
+    
+	if (io_remap_page_range(vma->vm_start, off,
+				vma->vm_end - vma->vm_start,
+				vma->vm_page_prot)) {
+		return -EAGAIN;
+	}
+
+	fb->mmaped = 1;
+	return 0;
+}
+
+int au1100_pan_display(const struct fb_var_screeninfo *var,
+		       struct fb_info_gen *info)
+{
+	return 0;
+}
+
+static int au1100fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+			  u_long arg, int con, struct fb_info *info)
+{
+	/* nothing to do yet */
+	return -EINVAL;
+}
+
+static struct fbgen_hwswitch au1100_switch = {
+	au1100_detect, 
+	au1100_encode_fix, 
+	au1100_decode_var, 
+	au1100_encode_var, 
+	au1100_get_par, 
+	au1100_set_par, 
+	au1100_getcolreg, 
+	au1100_setcolreg, 
+	au1100_pan_display, 
+	au1100_blank, 
+	au1100_set_disp
+};
+
+
+int au1100_setmode(void) 
+{
+	int words;
+
+	/* FIXME Need to accomodate for swivel mode and 12bpp, <8bpp*/
+	switch (p_lcd->mode_control & LCD_CONTROL_SM)
+	{
+		case LCD_CONTROL_SM_0:
+		case LCD_CONTROL_SM_180:
+		words = (p_lcd->xres * p_lcd->yres * p_lcd->bpp) / 32;
+			break;
+		case LCD_CONTROL_SM_90:
+		case LCD_CONTROL_SM_270:
+			/* is this correct? */
+		words = (p_lcd->xres * p_lcd->bpp) / 8;
+			break;
+		default:
+			printk("mode_control reg not initialized\n");
+			return -EINVAL;
+	}
+
+	/*
+	 * Setup LCD controller
+	 */
+
+	p_lcd_reg->lcd_control = p_lcd->mode_control;
+	p_lcd_reg->lcd_intstatus = 0;
+	p_lcd_reg->lcd_intenable = 0;
+	p_lcd_reg->lcd_horztiming = p_lcd->mode_horztiming;
+	p_lcd_reg->lcd_verttiming = p_lcd->mode_verttiming;
+	p_lcd_reg->lcd_clkcontrol = p_lcd->mode_clkcontrol;
+	p_lcd_reg->lcd_words = words - 1;
+	p_lcd_reg->lcd_dmaaddr0 = fb_info.fb_phys;
+
+#ifdef CONFIG_MIPS_PB1100
+	/* turn on panel */
+	au_writew(au_readw(PB1100_G_CONTROL) | p_lcd->mode_backlight, 
+			PB1100_G_CONTROL);
+	p_lcd_reg->lcd_control |= LCD_CONTROL_GO;
+#endif
+
+	return 0;
+}
+
+
+int __init au1100fb_init(void)
+{
+	uint32 sys_clksrc;
+	unsigned long page;
+
+	/*
+	* Get the panel information/display mode and update the registry
+	*/
+	p_lcd = &panels[my_lcd_index];
+
+	switch (p_lcd->mode_control & LCD_CONTROL_SM)
+	{
+		case LCD_CONTROL_SM_0:
+		case LCD_CONTROL_SM_180:
+		p_lcd->xres = 
+			(p_lcd->mode_horztiming & LCD_HORZTIMING_PPL) + 1;
+		p_lcd->yres = 
+			(p_lcd->mode_verttiming & LCD_VERTTIMING_LPP) + 1;
+			break;
+		case LCD_CONTROL_SM_90:
+		case LCD_CONTROL_SM_270:
+		p_lcd->yres = 
+			(p_lcd->mode_horztiming & LCD_HORZTIMING_PPL) + 1;
+		p_lcd->xres = 
+			(p_lcd->mode_verttiming & LCD_VERTTIMING_LPP) + 1;
+			break;
+	}
+
+	/*
+	 * Panel dimensions x bpp must be divisible by 32
+	 */
+	if (((p_lcd->yres * p_lcd->bpp) % 32) != 0) 
+		printk("VERT %% 32\n");
+	if (((p_lcd->xres * p_lcd->bpp) % 32) != 0) 
+		printk("HORZ %% 32\n");
+
+	/*
+	 * Allocate LCD framebuffer from system memory
+	 */
+	fb_info.fb_size = (p_lcd->xres * p_lcd->yres * p_lcd->bpp) / 8;
+	
+	current_par.var.xres = p_lcd->xres;
+	current_par.var.xres_virtual = p_lcd->xres;
+	current_par.var.yres = p_lcd->yres;
+	current_par.var.yres_virtual = p_lcd->yres;
+	current_par.var.bits_per_pixel = p_lcd->bpp;
+
+	/* FIX!!! only works for 8/16 bpp */
+	current_par.line_length = p_lcd->xres * p_lcd->bpp / 8; /* in bytes */
+	fb_info.fb_virt_start = (unsigned long )
+		__get_free_pages(GFP_ATOMIC | GFP_DMA, 
+				get_order(fb_info.fb_size + 0x1000));
+	if (!fb_info.fb_virt_start) {
+		printk("Unable to allocate fb memory\n");
+		return -ENOMEM;
+	}
+	fb_info.fb_phys = virt_to_bus((void *)fb_info.fb_virt_start);
+
+	/*
+	 * Set page reserved so that mmap will work. This is necessary
+	 * since we'll be remapping normal memory.
+	 */
+	for (page = fb_info.fb_virt_start;
+	     page < PAGE_ALIGN(fb_info.fb_virt_start + fb_info.fb_size); 
+	     page += PAGE_SIZE) {
+		SetPageReserved(virt_to_page(page));
+	}
+
+	memset((void *)fb_info.fb_virt_start, 0, fb_info.fb_size);
+
+	/* set freqctrl now to allow more time to stabilize */
+	/* zero-out out LCD bits */
+	sys_clksrc = au_readl(SYS_CLKSRC) & ~0x000003e0; 
+	sys_clksrc |= p_lcd->mode_toyclksrc;
+	au_writel(sys_clksrc, SYS_CLKSRC);
+
+	/* FIXME add check to make sure auxpll is what is expected! */
+	au1100_setmode();
+
+	fb_info.gen.parsize = sizeof(struct au1100fb_par);
+	fb_info.gen.fbhw = &au1100_switch;
+
+	strcpy(fb_info.gen.info.modename, "Au1100 LCD");
+	fb_info.gen.info.changevar = NULL;
+	fb_info.gen.info.node = -1;
+
+	fb_info.gen.info.fbops = &au1100fb_ops;
+	fb_info.gen.info.disp = &disp;
+	fb_info.gen.info.switch_con = &fbgen_switch;
+	fb_info.gen.info.updatevar = &fbgen_update_var;
+	fb_info.gen.info.blank = &fbgen_blank;
+	fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
+
+	/* This should give a reasonable default video mode */
+	fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
+	fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
+	fbgen_set_disp(-1, &fb_info.gen);
+	fbgen_install_cmap(0, &fb_info.gen);
+	if (register_framebuffer(&fb_info.gen.info) < 0)
+		return -EINVAL;
+	printk(KERN_INFO "fb%d: %s frame buffer device\n", 
+			GET_FB_IDX(fb_info.gen.info.node), 
+			fb_info.gen.info.modename);
+
+	/* uncomment this if your driver cannot be unloaded */
+	/* MOD_INC_USE_COUNT; */
+	return 0;
+}
+
+
+void au1100fb_cleanup(struct fb_info *info)
+{
+	unregister_framebuffer(info);
+}
+
+
+void au1100fb_setup(char *options, int *ints)
+{
+	char* this_opt;
+	int i;
+	int num_panels = sizeof(panels)/sizeof(struct known_lcd_panels);
+
+    
+	if (!options || !*options)
+		return;
+
+	for(this_opt=strtok(options, ","); this_opt;
+	    this_opt=strtok(NULL, ",")) {
+		if (!strncmp(this_opt, "panel:", 6)) {
+			/* Get the panel name, everything else if fixed */
+			for (i=0; i<num_panels; i++) {
+				if (!strncmp(this_opt+6, panels[i].panel_name, 
+							strlen(this_opt))) {
+					my_lcd_index = i;
+					break;
+				}
+			}
+		}
+		else if (!strncmp(this_opt, "nohwcursor", 10)) {
+			printk("nohwcursor\n");
+			fb_info.nohwcursor = 1;
+		}
+	} 
+}
+
+
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+int init_module(void)
+{
+	return au1100fb_init();
+}
+
+void cleanup_module(void)
+{
+	au1100fb_cleanup(void);
+}
+
+MODULE_AUTHOR("Pete Popov <ppopov@mvista.com>");
+MODULE_DESCRIPTION("Au1100 LCD framebuffer device driver");
+#endif /* MODULE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/au1100fb.h linux-2.4.20/drivers/video/au1100fb.h
--- linux-2.4.19/drivers/video/au1100fb.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/video/au1100fb.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,381 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Hardware definitions for the Au1100 LCD controller
+ *
+ * Copyright 2002 MontaVista Software
+ * Copyright 2002 Alchemy Semiconductor
+ * Author:	Alchemy Semiconductor, MontaVista Software
+ *
+ *  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.
+ */
+
+#ifndef _AU1100LCD_H
+#define _AU1100LCD_H
+
+/********************************************************************/
+#define uint32 unsigned long
+typedef volatile struct
+{
+	uint32	lcd_control;
+	uint32	lcd_intstatus;
+	uint32	lcd_intenable;
+	uint32	lcd_horztiming;
+	uint32	lcd_verttiming;
+	uint32	lcd_clkcontrol;
+	uint32	lcd_dmaaddr0;
+	uint32	lcd_dmaaddr1;
+	uint32	lcd_words;
+	uint32	lcd_pwmdiv;
+	uint32	lcd_pwmhi;
+	uint32	reserved[(0x0400-0x002C)/4];
+	uint32	lcd_pallettebase[256];
+
+} AU1100_LCD;
+
+/********************************************************************/
+
+#define AU1100_LCD_ADDR		0xB5000000
+
+/*
+ * Register bit definitions
+ */
+
+/* lcd_control */
+#define LCD_CONTROL_SBPPF		(7<<18)
+#define LCD_CONTROL_SBPPF_655	(0<<18)
+#define LCD_CONTROL_SBPPF_565	(1<<18)
+#define LCD_CONTROL_SBPPF_556	(2<<18)
+#define LCD_CONTROL_SBPPF_1555	(3<<18)
+#define LCD_CONTROL_SBPPF_5551	(4<<18)
+#define LCD_CONTROL_WP			(1<<17)
+#define LCD_CONTROL_WD			(1<<16)
+#define LCD_CONTROL_C			(1<<15)
+#define LCD_CONTROL_SM			(3<<13)
+#define LCD_CONTROL_SM_0		(0<<13)
+#define LCD_CONTROL_SM_90		(1<<13)
+#define LCD_CONTROL_SM_180		(2<<13)
+#define LCD_CONTROL_SM_270		(3<<13)
+#define LCD_CONTROL_DB			(1<<12)
+#define LCD_CONTROL_CCO			(1<<11)
+#define LCD_CONTROL_DP			(1<<10)
+#define LCD_CONTROL_PO			(3<<8)
+#define LCD_CONTROL_PO_00		(0<<8)
+#define LCD_CONTROL_PO_01		(1<<8)
+#define LCD_CONTROL_PO_10		(2<<8)
+#define LCD_CONTROL_PO_11		(3<<8)
+#define LCD_CONTROL_MPI			(1<<7)
+#define LCD_CONTROL_PT			(1<<6)
+#define LCD_CONTROL_PC			(1<<5)
+#define LCD_CONTROL_BPP			(7<<1)
+#define LCD_CONTROL_BPP_1		(0<<1)
+#define LCD_CONTROL_BPP_2		(1<<1)
+#define LCD_CONTROL_BPP_4		(2<<1)
+#define LCD_CONTROL_BPP_8		(3<<1)
+#define LCD_CONTROL_BPP_12		(4<<1)
+#define LCD_CONTROL_BPP_16		(5<<1)
+#define LCD_CONTROL_GO			(1<<0)
+
+/* lcd_intstatus, lcd_intenable */
+#define LCD_INT_SD				(1<<7)
+#define LCD_INT_OF				(1<<6)
+#define LCD_INT_UF				(1<<5)
+#define LCD_INT_SA				(1<<3)
+#define LCD_INT_SS				(1<<2)
+#define LCD_INT_S1				(1<<1)
+#define LCD_INT_S0				(1<<0)
+
+/* lcd_horztiming */
+#define LCD_HORZTIMING_HN2		(255<<24)
+#define LCD_HORZTIMING_HN2_N(N)	(((N)-1)<<24)
+#define LCD_HORZTIMING_HN1		(255<<16)
+#define LCD_HORZTIMING_HN1_N(N)	(((N)-1)<<16)
+#define LCD_HORZTIMING_HPW		(63<<10)
+#define LCD_HORZTIMING_HPW_N(N)	(((N)-1)<<10)
+#define LCD_HORZTIMING_PPL		(1023<<0)
+#define LCD_HORZTIMING_PPL_N(N)	(((N)-1)<<0)
+
+/* lcd_verttiming */
+#define LCD_VERTTIMING_VN2		(255<<24)
+#define LCD_VERTTIMING_VN2_N(N)	(((N)-1)<<24)
+#define LCD_VERTTIMING_VN1		(255<<16)
+#define LCD_VERTTIMING_VN1_N(N)	(((N)-1)<<16)
+#define LCD_VERTTIMING_VPW		(63<<10)
+#define LCD_VERTTIMING_VPW_N(N)	(((N)-1)<<10)
+#define LCD_VERTTIMING_LPP		(1023<<0)
+#define LCD_VERTTIMING_LPP_N(N)	(((N)-1)<<0)
+
+/* lcd_clkcontrol */
+#define LCD_CLKCONTROL_IB		(1<<18)
+#define LCD_CLKCONTROL_IC		(1<<17)
+#define LCD_CLKCONTROL_IH		(1<<16)
+#define LCD_CLKCONTROL_IV		(1<<15)
+#define LCD_CLKCONTROL_BF		(31<<10)
+#define LCD_CLKCONTROL_BF_N(N)	(((N)-1)<<10)
+#define LCD_CLKCONTROL_PCD		(1023<<0)
+#define LCD_CLKCONTROL_PCD_N(N)	((N)<<0)
+
+/* lcd_pwmdiv */
+#define LCD_PWMDIV_EN			(1<<12)
+#define LCD_PWMDIV_PWMDIV		(2047<<0)
+#define LCD_PWMDIV_PWMDIV_N(N)	(((N)-1)<<0)
+
+/* lcd_pwmhi */
+#define LCD_PWMHI_PWMHI1		(2047<<12)
+#define LCD_PWMHI_PWMHI1_N(N)	((N)<<12)
+#define LCD_PWMHI_PWMHI0		(2047<<0)
+#define LCD_PWMHI_PWMHI0_N(N)	((N)<<0)
+
+/* lcd_pallettebase - MONOCHROME */
+#define LCD_PALLETTE_MONO_MI		(15<<0)
+#define LCD_PALLETTE_MONO_MI_N(N)	((N)<<0)
+
+/* lcd_pallettebase - COLOR */
+#define LCD_PALLETTE_COLOR_BI		(15<<8)
+#define LCD_PALLETTE_COLOR_BI_N(N)	((N)<<8)
+#define LCD_PALLETTE_COLOR_GI		(15<<4)
+#define LCD_PALLETTE_COLOR_GI_N(N)	((N)<<4)
+#define LCD_PALLETTE_COLOR_RI		(15<<0)
+#define LCD_PALLETTE_COLOR_RI_N(N)	((N)<<0)
+
+/* lcd_palletebase - COLOR TFT PALLETIZED */
+#define LCD_PALLETTE_TFT_DC			(65535<<0)
+#define LCD_PALLETTE_TFT_DC_N(N)	((N)<<0)
+
+/********************************************************************/
+
+struct known_lcd_panels
+{
+	uint32 xres;
+	uint32 yres;
+	uint32 bpp;
+	unsigned char  panel_name[256];
+	uint32 mode_control;
+	uint32 mode_horztiming;
+	uint32 mode_verttiming;
+	uint32 mode_clkcontrol;
+	uint32 mode_pwmdiv;
+	uint32 mode_pwmhi;
+	uint32 mode_toyclksrc;
+	uint32 mode_backlight;
+
+};
+
+#if defined(__BIG_ENDIAN)
+#define LCD_DEFAULT_PIX_FORMAT LCD_CONTROL_PO_11
+#else
+#define LCD_DEFAULT_PIX_FORMAT LCD_CONTROL_PO_00
+#endif
+
+/*
+ * The fb driver assumes that AUX PLL is at 48MHz.  That can
+ * cover up to 800x600 resolution; if you need higher resolution,
+ * you should modify the driver as needed, not just this structure.
+ */
+struct known_lcd_panels panels[] =
+{
+	{ /* 0: Pb1100 LCDA: Sharp 320x240 TFT panel */
+		320, /* xres */
+		240, /* yres */
+		16,  /* bpp  */
+		
+		"Sharp_320x240_16",
+		/* mode_control */
+		( LCD_CONTROL_SBPPF_565
+		/*LCD_CONTROL_WP*/
+		/*LCD_CONTROL_WD*/
+		| LCD_CONTROL_C
+		| LCD_CONTROL_SM_0
+		/*LCD_CONTROL_DB*/
+		/*LCD_CONTROL_CCO*/
+		/*LCD_CONTROL_DP*/
+		| LCD_DEFAULT_PIX_FORMAT
+		/*LCD_CONTROL_MPI*/
+		| LCD_CONTROL_PT
+		| LCD_CONTROL_PC
+		| LCD_CONTROL_BPP_16 ),
+
+		/* mode_horztiming */
+		( LCD_HORZTIMING_HN2_N(8)
+		| LCD_HORZTIMING_HN1_N(60)
+		| LCD_HORZTIMING_HPW_N(12)
+		| LCD_HORZTIMING_PPL_N(320) ),
+
+		/* mode_verttiming */
+		( LCD_VERTTIMING_VN2_N(5)
+		| LCD_VERTTIMING_VN1_N(17)
+		| LCD_VERTTIMING_VPW_N(1)
+		| LCD_VERTTIMING_LPP_N(240) ),
+
+		/* mode_clkcontrol */
+		( 0
+		/*LCD_CLKCONTROL_IB*/
+		/*LCD_CLKCONTROL_IC*/
+		/*LCD_CLKCONTROL_IH*/
+		/*LCD_CLKCONTROL_IV*/
+		| LCD_CLKCONTROL_PCD_N(1) ),
+
+		/* mode_pwmdiv */
+		0,
+
+		/* mode_pwmhi */
+		0,
+
+		/* mode_toyclksrc */
+		((1<<7) | (1<<6) | (1<<5)),
+
+		/* mode_backlight */
+		6
+	},
+
+	{ /* 1: Pb1100 LCDC 640x480 TFT panel */
+		640, /* xres */
+		480, /* yres */
+		16,  /* bpp  */
+
+		"Generic_640x480_16",
+
+		/* mode_control */
+		0x004806a | LCD_DEFAULT_PIX_FORMAT,
+
+		/* mode_horztiming */
+		0x3434d67f,
+
+		/* mode_verttiming */
+		0x0e0e39df,
+
+		/* mode_clkcontrol */
+		( 0
+		/*LCD_CLKCONTROL_IB*/
+		/*LCD_CLKCONTROL_IC*/
+		/*LCD_CLKCONTROL_IH*/
+		/*LCD_CLKCONTROL_IV*/
+		| LCD_CLKCONTROL_PCD_N(1) ),
+
+		/* mode_pwmdiv */
+		0,
+
+		/* mode_pwmhi */
+		0,
+
+		/* mode_toyclksrc */
+		((1<<7) | (1<<6) | (0<<5)),
+
+		/* mode_backlight */
+		7
+	},
+
+	{ /* 2: Pb1100 LCDB 640x480 PrimeView TFT panel */
+		640, /* xres */
+		480, /* yres */
+		16,  /* bpp  */
+
+		"PrimeView_640x480_16",
+
+		/* mode_control */
+		0x0004886a | LCD_DEFAULT_PIX_FORMAT,
+
+		/* mode_horztiming */
+		0x0e4bfe7f,
+
+		/* mode_verttiming */
+		0x210805df,
+
+		/* mode_clkcontrol */
+		0x00038001,
+
+		/* mode_pwmdiv */
+		0,
+
+		/* mode_pwmhi */
+		0,
+
+		/* mode_toyclksrc */
+		((1<<7) | (1<<6) | (0<<5)),
+
+		/* mode_backlight */
+		7
+	},
+
+	{ /* 3: Pb1100 800x600x16bpp NEON CRT */
+		800, /* xres */
+		600, /* yres */
+		16,  /* bpp */
+
+		"NEON_800x600_16",
+
+		/* mode_control */
+		0x0004886A | LCD_DEFAULT_PIX_FORMAT,
+
+		/* mode_horztiming */
+		0x005AFF1F,
+
+		/* mode_verttiming */
+		0x16000E57,
+
+		/* mode_clkcontrol */
+		0x00020000,
+
+		/* mode_pwmdiv */
+		0,
+
+		/* mode_pwmhi */
+		0,
+
+		/* mode_toyclksrc */
+		((1<<7) | (1<<6) | (0<<5)),
+
+		/* mode_backlight */
+		7
+	},
+
+	{ /* 4: Pb1100 640x480x16bpp NEON CRT */
+		640, /* xres */
+		480, /* yres */
+		16,  /* bpp */
+
+		"NEON_640x480_16",
+
+		/* mode_control */
+		0x0004886A | LCD_DEFAULT_PIX_FORMAT,
+
+		/* mode_horztiming */
+		0x0052E27F,
+
+		/* mode_verttiming */
+		0x18000DDF,
+
+		/* mode_clkcontrol */
+		0x00020000,
+
+		/* mode_pwmdiv */
+		0,
+
+		/* mode_pwmhi */
+		0,
+
+		/* mode_toyclksrc */
+		((1<<7) | (1<<6) | (0<<5)),
+
+		/* mode_backlight */
+		7
+	},
+};
+#endif /* _AU1100LCD_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/clgenfb.c linux-2.4.20/drivers/video/clgenfb.c
--- linux-2.4.19/drivers/video/clgenfb.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/clgenfb.c	2002-10-29 11:18:36.000000000 +0000
@@ -280,6 +280,7 @@
 	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5434_4 },
 	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5430 }, /* GD-5440 has identical id */
 	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_7543 },
+	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_7548 },
 	{ BT_GD5480, NULL, PCI_DEVICE_ID_CIRRUS_5480 }, /* MacPicasso probably */
 	{ BT_PICASSO4, NULL, PCI_DEVICE_ID_CIRRUS_5446 }, /* Picasso 4 is a GD5446 */
 	{ BT_LAGUNA, "CL Laguna", PCI_DEVICE_ID_CIRRUS_5462 },
@@ -3089,7 +3090,7 @@
 *********************************************************************/
 
 /* FIXME: use interrupts instead */
-extern inline void clgen_WaitBLT (caddr_t regbase)
+static inline void clgen_WaitBLT (caddr_t regbase)
 {
 	/* now busy-wait until we're done */
 	while (vga_rgfx (regbase, CL_GR31) & 0x08)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/dnfb.c linux-2.4.20/drivers/video/dnfb.c
--- linux-2.4.19/drivers/video/dnfb.c	2001-09-13 23:04:43.000000000 +0000
+++ linux-2.4.20/drivers/video/dnfb.c	2002-10-29 11:18:35.000000000 +0000
@@ -489,7 +489,7 @@
 	fbcon_mfb_putc(conp,p,c,yy,xx);
 }
 
-static void putcs_apollofb(struct vc_data *conp, struct display *p, const char *s,
+static void putcs_apollofb(struct vc_data *conp, struct display *p, const unsigned short *s,
 		      int count, int yy, int xx)
 {
 	fbcon_mfb_putcs(conp,p,s,count,yy,xx);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/epson1356fb.c linux-2.4.20/drivers/video/epson1356fb.c
--- linux-2.4.19/drivers/video/epson1356fb.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/video/epson1356fb.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,3117 @@
+/*
+ *      epson1356fb.c  --  Epson SED1356 Framebuffer Driver
+ *
+ * Copyright 2001, 2002 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	stevel@mvista.com or source@mvista.com
+ *
+ *  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.
+ *
+ * 
+ * TODO:
+ *
+ *  Revision history
+ *    03.12.2001  0.1   Initial release
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/selection.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/nvram.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/timer.h>
+#include <linux/pagemap.h>
+
+#include <asm/pgalloc.h>
+#include <asm/uaccess.h>
+#include <asm/tlb.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#include <linux/spinlock.h>
+
+#include <linux/e1356fb.h>
+
+#ifdef CONFIG_MIPS_AU1000
+#include <asm/au1000.h>
+#endif
+
+#define E1356FB_DEBUG 1
+#undef E1356FB_VERBOSE_DEBUG
+#undef SHADOW_FRAME_BUFFER
+#include "epson1356fb.h"
+
+static char *options;
+MODULE_PARM(options, "s");
+
+/*
+ *  Frame buffer device API
+ */
+static int e1356fb_open(struct fb_info *fb, int user);
+static int e1356fb_release(struct fb_info *fb, int user);
+static int e1356fb_get_fix(struct fb_fix_screeninfo* fix, 
+			   int con,
+			   struct fb_info* fb);
+static int e1356fb_get_var(struct fb_var_screeninfo* var, 
+			   int con,
+			   struct fb_info* fb);
+static int e1356fb_set_var(struct fb_var_screeninfo* var,
+			   int con,
+			   struct fb_info* fb);
+static int e1356fb_pan_display(struct fb_var_screeninfo* var, 
+			       int con,
+			       struct fb_info* fb);
+static int e1356fb_get_cmap(struct fb_cmap *cmap, 
+			    int kspc, 
+			    int con,
+			    struct fb_info* info);
+static int e1356fb_set_cmap(struct fb_cmap* cmap, 
+			    int kspc, 
+			    int con,
+			    struct fb_info* info);
+static int e1356fb_ioctl(struct inode* inode, 
+			 struct file* file, 
+			 u_int cmd,
+			 u_long arg, 
+			 int con, 
+			 struct fb_info* info);
+static int e1356fb_mmap(struct fb_info *info,
+			struct file *file,
+			struct vm_area_struct *vma);
+
+/*
+ *  Interface to the low level console driver
+ */
+static int  e1356fb_switch_con(int con, 
+			       struct fb_info* fb);
+static int  e1356fb_updatevar(int con, 
+			      struct fb_info* fb);
+static void e1356fb_blank(int blank, 
+			  struct fb_info* fb);
+
+/*
+ *  Internal routines
+ */
+static void e1356fb_set_par(const struct e1356fb_par* par,
+			    struct fb_info_e1356* 
+			    info);
+static int  e1356fb_var_to_par(const struct fb_var_screeninfo *var,
+			       struct e1356fb_par* par,
+			       const struct fb_info_e1356* info);
+static int  e1356fb_par_to_var(struct fb_var_screeninfo* var,
+			       struct e1356fb_par* par,
+			       const struct fb_info_e1356* info);
+static int  e1356fb_encode_fix(struct fb_fix_screeninfo* fix,
+			       const struct e1356fb_par* par,
+			       const struct fb_info_e1356* info);
+static void e1356fb_set_dispsw(struct display* disp, 
+			       struct fb_info_e1356* info,
+			       int bpp, 
+			       int accel);
+static int  e1356fb_getcolreg(u_int regno,
+			      u_int* red, 
+			      u_int* green, 
+			      u_int* blue,
+			      u_int* transp, 
+			      struct fb_info* fb);
+static int  e1356fb_setcolreg(u_int regno, 
+			      u_int red, 
+			      u_int green, 
+			      u_int blue,
+			      u_int transp, 
+			      struct fb_info* fb);
+static void  e1356fb_install_cmap(struct display *d, 
+				  struct fb_info *info);
+
+static void e1356fb_hwcursor_init(struct fb_info_e1356* info);
+static void e1356fb_createcursorshape(struct display* p);
+static void e1356fb_createcursor(struct display * p);  
+
+/*
+ * do_xxx: Hardware-specific functions
+ */
+static void  do_pan_var(struct fb_var_screeninfo* var,
+			struct fb_info_e1356* i);
+static void  do_flashcursor(unsigned long ptr);
+static void  doBlt_Move(const struct e1356fb_par* par,
+			struct fb_info_e1356* i,
+			blt_info_t* blt);
+static void  doBlt_SolidFill(const struct e1356fb_par* par,
+			     struct fb_info_e1356* i,
+			     blt_info_t* blt);
+
+/*
+ *  Interface used by the world
+ */
+int e1356fb_init(void);
+void e1356fb_setup(char *options, int *ints);
+
+static int currcon = 0;
+
+static struct fb_ops e1356fb_ops = {
+	owner:	THIS_MODULE,
+	fb_open:        e1356fb_open,
+	fb_release:     e1356fb_release,
+	fb_get_fix:	e1356fb_get_fix,
+	fb_get_var:	e1356fb_get_var,
+	fb_set_var:	e1356fb_set_var,
+	fb_get_cmap:    e1356fb_get_cmap,
+	fb_set_cmap:    e1356fb_set_cmap,
+	fb_pan_display: e1356fb_pan_display,
+	fb_mmap:        e1356fb_mmap,
+};
+
+#define PCI_VENDOR_ID_EPSON         0x10f4
+#define PCI_DEVICE_ID_EPSON_SDU1356 0x1300
+
+
+static struct fb_info_e1356 fb_info;
+static struct e1356fb_fix boot_fix; // boot options
+static struct e1356fb_par boot_par; // boot options
+
+static int e1356_remap_page_range(unsigned long from, phys_t phys_addr, unsigned long size, pgprot_t prot);
+
+
+/* ------------------------------------------------------------------------- 
+ *                      Hardware-specific funcions
+ * ------------------------------------------------------------------------- */
+
+/*
+ * The SED1356 has only a 16-bit wide data bus, so some embedded
+ * implementations with 32-bit CPU's (Alchemy Pb1000) may not
+ * correctly emulate a 32-bit write to the framebuffer by splitting
+ * the write into two seperate 16-bit writes. So it is safest to
+ * only do byte or half-word writes to the fb. This routine assumes
+ * fbaddr is atleast aligned on a half-word boundary.
+ */
+static inline void
+fbfill(u16* fbaddr, u8 val, int size)
+{
+	u16 valw = (u16)val | ((u16)val << 8);
+	for ( ; size >= 2; size -= 2)
+		writew(valw, fbaddr++);
+	if (size)
+		writeb(val, (u8*)fbaddr);
+}
+
+static inline int
+e1356_wait_bitclr(u8* reg, u8 bit, int timeout)
+{
+	while (readb(reg) & bit) {
+		udelay(10);
+		if (!--timeout)
+			break;
+	}
+	return timeout;
+}
+
+static inline int
+e1356_wait_bitset(u8* reg, u8 bit, int timeout)
+{
+	while (!(readb(reg) & bit)) {
+		udelay(10);
+		if (!--timeout)
+			break;
+	}
+	return timeout;
+}
+
+
+static struct fb_videomode panel_modedb[] = {
+	{
+		/* 320x240 @ 109 Hz, 33.3 kHz hsync */
+		NULL, 109, 320, 240, KHZ2PICOS(MAX_PIXCLOCK/3),
+		16, 16, 32, 24, 48, 8,
+		0, FB_VMODE_NONINTERLACED
+	}, {
+		/* 640x480 @ 84 Hz, 48.1 kHz hsync */
+		NULL, 84, 640, 480, KHZ2PICOS(MAX_PIXCLOCK/1),
+		96, 32, 32, 48, 64, 8,
+		0, FB_VMODE_NONINTERLACED
+	}, {
+		/* 800x600 @ 76 Hz, 46.3 kHz hsync */
+		NULL, 76, 800, 600, KHZ2PICOS(MAX_PIXCLOCK/1),
+		32, 10, 1, 1, 22, 1,
+		0, FB_VMODE_NONINTERLACED
+	}
+};
+static struct fb_videomode crt_modedb[] = {
+	{
+		/* 320x240 @ 84 Hz, 31.25 kHz hsync */
+		NULL, 84, 320, 240, KHZ2PICOS(MAX_PIXCLOCK/2),
+		128, 128, 60, 60, 64, 8,
+		0, FB_VMODE_NONINTERLACED
+	}, {
+		/* 320x240 @ 109 Hz, 33.3 kHz hsync */
+		NULL, 109, 320, 240, KHZ2PICOS(MAX_PIXCLOCK/3),
+		16, 16, 32, 24, 48, 8,
+		0, FB_VMODE_NONINTERLACED
+	}, {
+		/* 512x384 @ 77 Hz, 31.25 kHz hsync */
+		NULL, 77, 512, 384, KHZ2PICOS(MAX_PIXCLOCK/2),
+		48, 16, 16, 1, 64, 3,
+		0, FB_VMODE_NONINTERLACED
+	}, {
+		/* 640x400 @ 88 Hz, 43.1 kHz hsync */
+		NULL, 88, 640, 400, KHZ2PICOS(MAX_PIXCLOCK/1),
+		128, 96, 32, 48, 64, 8,
+		0, FB_VMODE_NONINTERLACED
+	}, {
+		/* 640x480 @ 84 Hz, 48.1 kHz hsync */
+		NULL, 84, 640, 480, KHZ2PICOS(MAX_PIXCLOCK/1),
+		96, 32, 32, 48, 64, 8,
+		0, FB_VMODE_NONINTERLACED
+	}, {
+		/* 768x576 @ 62 Hz, 38.5 kHz hsync */
+		NULL, 62, 768, 576, KHZ2PICOS(MAX_PIXCLOCK/1),
+		144, 16, 28, 6, 112, 4,
+		0, FB_VMODE_NONINTERLACED
+	}, {
+		/* 800x600 @ 60 Hz, 37.9 kHz hsync */
+		NULL, 60, 800, 600, KHZ2PICOS(MAX_PIXCLOCK/1),
+		88, 40, 23, 1, 128, 4,
+		FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+		FB_VMODE_NONINTERLACED
+	}
+};
+
+static struct fb_videomode ntsc_modedb[] = {
+	{
+		/* 640x480 @ 62 Hz, requires flicker filter */
+		//NULL, 62, 640, 480, 34921, 213, 57, 20, 2, 0, 0,
+		NULL, 62, 640, 480, KHZ2PICOS(2*NTSC_PIXCLOCK),
+		200, 70, 15, 7, 0, 0,
+		FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+	}
+};
+static struct fb_videomode pal_modedb[] = {
+	{
+		/* 640x480 @ 56 Hz, requires flicker filter */
+		NULL, 56, 640, 480, KHZ2PICOS(2*PAL_PIXCLOCK),
+		350, 145, 49, 23, 0, 0,
+		FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+	}
+};
+
+
+static inline void
+fb_videomode_to_var(struct fb_videomode* mode,
+		    struct fb_var_screeninfo*var)
+{
+	var->xres = mode->xres;
+	var->yres = mode->yres;
+	var->pixclock = mode->pixclock;
+	var->left_margin = mode->left_margin;
+	var->right_margin = mode->right_margin;
+	var->upper_margin = mode->upper_margin;
+	var->lower_margin = mode->lower_margin;
+	var->hsync_len = mode->hsync_len;
+	var->vsync_len = mode->vsync_len;
+	var->sync = mode->sync;
+	var->vmode = mode->vmode;
+}
+
+
+static int
+e1356fb_get_mode(const struct fb_info_e1356 *info,
+		 int xres,
+		 int yres,
+		 struct fb_videomode ** modedb,
+		 struct fb_videomode ** mode)
+{
+	struct fb_videomode * ret;
+	int i, dbsize;
+
+	if (IS_PANEL(info->fix.disp_type)) {
+		ret = panel_modedb;
+		dbsize = sizeof(panel_modedb)/sizeof(struct fb_videomode);
+	} else if (info->fix.disp_type == DISP_TYPE_CRT) {
+		ret = crt_modedb;
+		dbsize = sizeof(crt_modedb)/sizeof(struct fb_videomode);
+	} else if (info->fix.disp_type == DISP_TYPE_NTSC) {
+		ret = ntsc_modedb;
+		dbsize = sizeof(ntsc_modedb)/sizeof(struct fb_videomode);
+	} else {
+		ret = pal_modedb;
+		dbsize = sizeof(pal_modedb)/sizeof(struct fb_videomode);
+	}
+	
+	if (modedb)
+		*modedb = ret;
+	for (i=0; i<dbsize; i++) {
+		if (xres == ret[i].xres && yres == ret[i].yres) {
+			*mode = &ret[i];
+			break;
+		}
+	}
+	if (i == dbsize)
+		return -EINVAL;
+	return dbsize;
+}
+
+
+
+#ifdef E1356FB_VERBOSE_DEBUG
+static void
+dump_par(const struct e1356fb_par* par)
+{
+	DPRINTK("width:       %d\n", par->width);
+	DPRINTK("height:      %d\n", par->height);
+	DPRINTK("width_virt:  %d\n", par->width_virt);
+	DPRINTK("height_virt: %d\n", par->height_virt);
+	DPRINTK("bpp:         %d\n", par->bpp);
+	DPRINTK("pixclock:    %d\n", par->ipclk.pixclk);
+	DPRINTK("horiz_ndp:   %d\n", par->horiz_ndp);
+	DPRINTK("vert_ndp:    %d\n", par->vert_ndp);
+	DPRINTK("hsync_pol:   %d\n", par->hsync_pol);
+	DPRINTK("hsync_start: %d\n", par->hsync_start);
+	DPRINTK("hsync_width: %d\n", par->hsync_width);
+	DPRINTK("vsync_pol:   %d\n", par->vsync_pol);
+	DPRINTK("vsync_start: %d\n", par->vsync_start);
+	DPRINTK("vsync_width: %d\n", par->vsync_width);
+	DPRINTK("cmap_len:    %d\n", par->cmap_len);
+}
+
+static void
+dump_display_regs(reg_dispcfg_t* dispcfg, reg_dispmode_t* dispmode)
+{
+	DPRINTK("hdw:            0x%02x\n", readb(&dispcfg->hdw));
+	DPRINTK("hndp:           0x%02x\n", readb(&dispcfg->hndp));
+	DPRINTK("hsync_start:    0x%02x\n", readb(&dispcfg->hsync_start));
+	DPRINTK("hsync_pulse:    0x%02x\n", readb(&dispcfg->hsync_pulse));
+	DPRINTK("vdh0:           0x%02x\n", readb(&dispcfg->vdh0));
+	DPRINTK("vdh1:           0x%02x\n", readb(&dispcfg->vdh1));
+	DPRINTK("vndp:           0x%02x\n", readb(&dispcfg->vndp));
+	DPRINTK("vsync_start:    0x%02x\n", readb(&dispcfg->vsync_start));
+	DPRINTK("vsync_pulse:    0x%02x\n", readb(&dispcfg->vsync_pulse));
+	DPRINTK("tv_output_ctrl: 0x%02x\n\n", readb(&dispcfg->tv_output_ctrl));
+
+	DPRINTK("disp_mode:        0x%02x\n", readb(&dispmode->disp_mode));
+	DPRINTK("lcd_misc:         0x%02x\n", readb(&dispmode->lcd_misc));
+	DPRINTK("start_addr0:      0x%02x\n", readb(&dispmode->start_addr0));
+	DPRINTK("start_addr1:      0x%02x\n", readb(&dispmode->start_addr1));
+	DPRINTK("start_addr2:      0x%02x\n", readb(&dispmode->start_addr2));
+	DPRINTK("mem_addr_offset0: 0x%02x\n", readb(&dispmode->mem_addr_offset0));
+	DPRINTK("mem_addr_offset1: 0x%02x\n", readb(&dispmode->mem_addr_offset1));
+	DPRINTK("pixel_panning:    0x%02x\n", readb(&dispmode->pixel_panning));
+	DPRINTK("fifo_high_thresh: 0x%02x\n", readb(&dispmode->fifo_high_thresh));
+	DPRINTK("fifo_low_thresh:  0x%02x\n", readb(&dispmode->fifo_low_thresh));
+}
+
+static void
+dump_fb(u8* base, int len)
+{
+	int i;
+	DPRINTK("FB memory dump, start 0x%p, len %d", base, len);
+	for (i=0; i<len; i++) {
+		if (!(i%16))
+			printk("\n%p: %02x ", &base[i], readb(&base[i]));
+		else
+			printk("%02x ", readb(&base[i]));
+	}
+	printk("\n");
+}
+
+#endif // E1356FB_VERBOSE_DEBUG
+
+
+
+// Input:  ipclk->clksrc, ipclk->pixclk_d
+// Output: ipclk->pixclk, ipclk->error, and ipclk->divisor
+static int
+get_nearest_pixclk_div(pixclock_info_t* ipclk, int x2)
+{
+	int pixclk_d = ipclk->pixclk_d;
+	int clksrc = ipclk->clksrc;
+
+	if (x2) clksrc *= 2;
+
+	if (clksrc < (3*pixclk_d+1)/2)
+		ipclk->divisor = 1;
+	else if (clksrc < (5*pixclk_d+1)/2)
+		ipclk->divisor = 2;
+	else if (clksrc < (7*pixclk_d+1)/2)
+		ipclk->divisor = 3;
+	else if (clksrc < (9*pixclk_d+1)/2)
+		ipclk->divisor = 4;
+	else
+		return -ENXIO;
+
+	ipclk->pixclk = clksrc / ipclk->divisor;
+	ipclk->error = (100*(pixclk_d - ipclk->pixclk)) / pixclk_d;
+	return 0;
+}
+
+static int
+e1356_calc_pixclock(const struct fb_info_e1356 *info,
+		    pixclock_info_t* ipclk)
+{
+	int src_sel=-1, flicker_mult=0;
+	pixclock_info_t test, ret;
+    
+	if (ipclk->pixclk > info->max_pixclock)
+		return -ENXIO;
+
+	test.pixclk_d = ipclk->pixclk_d;
+	ret.error = 100;
+	
+	if (IS_TV(info->fix.disp_type) &&
+	    (info->fix.tv_filt & TV_FILT_FLICKER))
+		flicker_mult = 0x80;
+	
+	test.clksrc = info->fix.busclk;
+	if (get_nearest_pixclk_div(&test, flicker_mult != 0) == 0 &&
+	    abs(test.error) < abs(ret.error)) {
+		ret = test;
+		src_sel = 0x01;
+	}
+
+	test.clksrc = info->fix.mclk;
+	if (get_nearest_pixclk_div(&test, flicker_mult != 0) == 0 &&
+	    abs(test.error) < abs(ret.error)) {
+		ret = test;
+		src_sel = 0x03;
+	}
+
+	test.clksrc = info->fix.clki;
+	if (get_nearest_pixclk_div(&test, flicker_mult != 0) == 0 &&
+	    abs(test.error) < abs(ret.error)) {
+		ret = test;
+		src_sel = 0x00;
+	}
+
+	test.clksrc = info->fix.clki2;
+	if (get_nearest_pixclk_div(&test, flicker_mult != 0) == 0 &&
+	    abs(test.error) < abs(ret.error)) {
+		ret = test;
+		src_sel = 0x02;
+	}
+
+	if (ret.error > MAX_PCLK_ERROR_LOWER ||
+	    ret.error < MAX_PCLK_ERROR_HIGHER)
+		return -ENXIO;
+    
+	ret.pixclk_bits = flicker_mult | ((ret.divisor-1)<<4) | src_sel;
+	*ipclk = ret;
+	return 0;
+}
+
+static inline int
+e1356_engine_wait_complete(reg_bitblt_t* bltreg)
+{
+	return e1356_wait_bitclr(&bltreg->ctrl0, 0x80, 5000);
+}
+static inline int
+e1356_engine_wait_busy(reg_bitblt_t* bltreg)
+{
+	return e1356_wait_bitset(&bltreg->ctrl0, 0x80, 5000);
+}
+
+static void
+e1356fb_engine_init(const struct e1356fb_par* par,
+		    struct fb_info_e1356* info)
+{
+	reg_bitblt_t* bltreg = info->reg.bitblt;
+    
+	e1356_engine_wait_complete(bltreg);
+
+	writeb(0, &bltreg->ctrl0);
+	writeb(0, &bltreg->ctrl1);
+	writeb(0, &bltreg->rop_code);
+	writeb(0, &bltreg->operation);
+	writeb(0, &bltreg->src_start_addr0);
+	writeb(0, &bltreg->src_start_addr1);
+	writeb(0, &bltreg->src_start_addr2);
+	writeb(0, &bltreg->dest_start_addr0);
+	writeb(0, &bltreg->dest_start_addr1);
+	writeb(0, &bltreg->dest_start_addr2);
+	writew(0, &bltreg->mem_addr_offset0);
+	writew(0, &bltreg->width0);
+	writew(0, &bltreg->height0);
+	writew(0, &bltreg->bg_color0);
+	writew(0, &bltreg->fg_color0);
+}
+
+
+static void doBlt_Write(const struct e1356fb_par* par,
+			struct fb_info_e1356* info,
+			blt_info_t* blt)
+{
+	reg_bitblt_t* bltreg = info->reg.bitblt;
+	int nWords, nTotalWords;
+	u32 srcphase, dstAddr;
+	u16* w16;
+	u32 stride = par->width_virt * par->Bpp;
+
+	dstAddr = blt->dst_x * par->Bpp + blt->dst_y * stride;
+	srcphase = (u32)blt->src & 1;
+    
+	if (blt->attribute & BLT_ATTR_TRANSPARENT)
+		writew(blt->bg_color, &bltreg->bg_color0);
+	else
+		writeb(blt->rop, &bltreg->rop_code);
+    
+	writeb(blt->operation, &bltreg->operation);
+	writeb((u8)srcphase, &bltreg->src_start_addr0);
+	writew(stride/2, &bltreg->mem_addr_offset0);
+
+	writeb(dstAddr, &bltreg->dest_start_addr0);
+	writeb(dstAddr>>8, &bltreg->dest_start_addr1);
+	writeb(dstAddr>>16, &bltreg->dest_start_addr2);
+
+	writew(blt->dst_width-1, &bltreg->width0);
+	writew(blt->dst_height-1, &bltreg->height0);
+
+	// program color format operation
+	writeb(par->bpp == 8 ? 0x00 : 0x01, &bltreg->ctrl1);
+
+	// start it up
+	writeb(0x80, &bltreg->ctrl0);
+
+	// wait for it to actually start
+	e1356_engine_wait_busy(bltreg);
+
+	// calculate the number of 16 bit words per one blt line
+
+	nWords = srcphase + ((blt->dst_width - srcphase)*par->Bpp + 1) / 2;
+	nTotalWords = nWords*blt->dst_height;
+	w16 = (u16*)((u32)blt->src & 0xfffffffe);   // Word aligned
+
+	while (nTotalWords > 0) {
+		int j, nFIFO;
+		u8 ctrl0;
+
+		// read the FIFO status
+		ctrl0 = readb(&bltreg->ctrl0);
+
+		if ((ctrl0 & 0x30) == 0x20)
+			// FIFO is at least half full, but not full
+			nFIFO = 1;
+		else if ((ctrl0 & 0x40) == 0)
+			// FIFO is empty
+			nFIFO = 16;
+		else
+			// FIFO is full
+			continue;
+
+		for (j = 0; j < nFIFO && nTotalWords > 0; j++,nTotalWords--)
+			writew(*w16++, info->reg.bitblt_data);
+	}
+
+	e1356_engine_wait_complete(bltreg);
+}
+
+
+static void
+doBlt_SolidFill(const struct e1356fb_par* par,
+		struct fb_info_e1356* info,
+		blt_info_t* blt)
+{
+	reg_bitblt_t* bltreg = info->reg.bitblt;
+	u32 width = blt->dst_width, height = blt->dst_height;
+	u32 stride = par->width_virt * par->Bpp;
+	u32 dest_addr = (blt->dst_y * stride) + (blt->dst_x * par->Bpp);
+
+	if (width == 0 || height == 0)
+		return;
+
+	// program dest address
+	writeb(dest_addr & 0x00ff, &bltreg->dest_start_addr0);
+	writeb((dest_addr>>8) & 0x00ff, &bltreg->dest_start_addr1);
+	writeb((dest_addr>>16) & 0x00ff, &bltreg->dest_start_addr2);
+
+	// program width and height of solid-fill blit
+	writew(width-1, &bltreg->width0);
+	writew(height-1, &bltreg->height0);
+
+	// program color of fill
+	writew(blt->fg_color, &bltreg->fg_color0);
+	// select solid-fill BLIT
+	writeb(BLT_SOLID_FILL, &bltreg->operation);
+	// program color format operation
+	writeb(par->bpp == 8 ? 0x00 : 0x01, &bltreg->ctrl1);
+	// program BLIT memory offset
+	writew(stride/2, &bltreg->mem_addr_offset0);
+
+	// start it up (self completes)
+	writeb(0x80, &bltreg->ctrl0);
+
+	e1356_engine_wait_complete(bltreg);
+}
+
+
+static void
+doBlt_Move(const struct e1356fb_par* par,
+	   struct fb_info_e1356* info,
+	   blt_info_t* blt)
+{
+	reg_bitblt_t* bltreg = info->reg.bitblt;
+	int neg_dir=0;
+	u32 dest_addr, src_addr;
+	u32 bpp = par->bpp;
+	u32 stride = par->width_virt * par->Bpp; // virt line length in bytes
+	u32 srcx = blt->src_x, srcy = blt->src_y;
+	u32 dstx = blt->dst_x, dsty = blt->dst_y;
+	u32 width = blt->dst_width, height = blt->dst_height;
+    
+	if (width == 0 || height == 0)
+		return;
+   
+	src_addr = srcx*par->Bpp + srcy*stride;
+	dest_addr = dstx*par->Bpp + dsty*stride;
+
+	/*
+	 * See if regions overlap and dest region is beyond source region.
+	 * If so, we need to do a move BLT in negative direction. Only applies
+	 * if the BLT is not transparent.
+	 */
+	if (!(blt->attribute & BLT_ATTR_TRANSPARENT)) {
+		if ((srcx + width  > dstx) && (srcx < dstx + width) &&
+		    (srcy + height > dsty) && (srcy < dsty + height) &&
+		    (dest_addr > src_addr)) {
+			neg_dir = 1;
+			// negative direction : get the coords of lower right corner
+			src_addr += stride * (height-1) + par->Bpp * (width-1);
+			dest_addr += stride * (height-1) + par->Bpp * (width-1);
+		}
+	}
+    
+	// program BLIT memory offset
+	writew(stride/2, &bltreg->mem_addr_offset0);
+
+	// program src and dest addresses
+	writeb(src_addr & 0x00ff, &bltreg->src_start_addr0);
+	writeb((src_addr>>8) & 0x00ff, &bltreg->src_start_addr1);
+	writeb((src_addr>>16) & 0x00ff, &bltreg->src_start_addr2);
+	writeb(dest_addr & 0x00ff, &bltreg->dest_start_addr0);
+	writeb((dest_addr>>8) & 0x00ff, &bltreg->dest_start_addr1);
+	writeb((dest_addr>>16) & 0x00ff, &bltreg->dest_start_addr2);
+
+	// program width and height of blit
+	writew(width-1, &bltreg->width0);
+	writew(height-1, &bltreg->height0);
+
+	// program color format operation
+	writeb(bpp == 8 ? 0x00 : 0x01, &bltreg->ctrl1);
+
+	// set the blt type
+	if (blt->attribute & BLT_ATTR_TRANSPARENT) {
+		writew(blt->bg_color, &bltreg->bg_color0);
+		writeb(BLT_MOVE_POS_TRANSP, &bltreg->operation); 
+	} else {
+		writeb(blt->rop, &bltreg->rop_code);
+		// select pos/neg move BLIT
+		writeb(neg_dir ? BLT_MOVE_NEG_ROP : BLT_MOVE_POS_ROP,
+		       &bltreg->operation); 
+	}
+
+	// start it up (self completes)
+	writeb(0x80, &bltreg->ctrl0);
+
+	e1356_engine_wait_complete(bltreg);
+}
+
+
+static void doBlt_ColorExpand(const struct e1356fb_par* par,
+			      struct fb_info_e1356* info,
+			      blt_info_t* blt)
+{
+	reg_bitblt_t* bltreg = info->reg.bitblt;
+	int i, j, nWords, Sx, Sy;
+	u32 dstAddr;
+	u16* wpt, *wpt1;
+	u32 stride = par->width_virt * par->Bpp;
+
+	if (blt->dst_width == 0 || blt->dst_height == 0)
+		return;
+
+	Sx = blt->src_x;
+	Sy = blt->src_y;
+
+	writeb((7 - Sx%8), &bltreg->rop_code);
+
+	writeb(blt->operation, &bltreg->operation);
+
+	writeb((u8)(Sx & 1), &bltreg->src_start_addr0);
+
+	dstAddr = blt->dst_x*par->Bpp + blt->dst_y * stride;
+	writeb(dstAddr, &bltreg->dest_start_addr0);
+	writeb(dstAddr>>8, &bltreg->dest_start_addr1);
+	writeb(dstAddr>>16, &bltreg->dest_start_addr2);
+
+	// program color format operation
+	writeb(par->bpp == 8 ? 0x00 : 0x01, &bltreg->ctrl1);
+	writew(stride/2, &bltreg->mem_addr_offset0);
+	writew(blt->dst_width-1, &bltreg->width0);
+	writew(blt->dst_height-1, &bltreg->height0);
+	writew(blt->bg_color, &bltreg->bg_color0);
+	writew(blt->fg_color, &bltreg->fg_color0);
+
+	// start it up
+	writeb(0x80, &bltreg->ctrl0);
+
+	// wait for it to actually start
+	e1356_engine_wait_busy(bltreg);
+
+	// calculate the number of 16 bit words per one blt line
+
+	nWords = (Sx%16 + blt->dst_width + 15)/16;
+
+	wpt = blt->src + (Sy*blt->srcstride + Sx/16)/2;
+
+	for (i = 0; i < blt->dst_height; i++) {
+		wpt1 = wpt;
+
+		for (j = 0; j < nWords; j++) {
+			// loop until FIFO becomes empty...
+			e1356_wait_bitclr(&bltreg->ctrl0, 0x40, 10000);
+			writew(*wpt1++, info->reg.bitblt_data);
+		}
+	
+		wpt += blt->srcstride/2;
+	}
+
+	e1356_engine_wait_complete(bltreg);
+}
+
+
+/*
+ * The BitBLT operation dispatcher
+ */
+static int
+doBlt(const struct e1356fb_par* par,
+      struct fb_info_e1356* info,
+      blt_info_t* blt)
+{
+	/*
+	 * Make sure we're not reentering in the middle of an
+	 * active BitBLT operation. ALWAYS call this dispatcher
+	 * and not one of the above BLT routines directly, or you
+	 * run the risk of overlapping BLT operations, which can
+	 * cause complete system hangs.
+     */
+	if (readb(&info->reg.bitblt->ctrl0) & 0x80)
+		return -ENXIO;
+    
+	switch (blt->operation) {
+	case BLT_MOVE_POS_ROP:
+	case BLT_MOVE_NEG_ROP:
+	case BLT_MOVE_POS_TRANSP:
+		doBlt_Move(par, info, blt);
+		break;
+	case BLT_COLOR_EXP:
+	case BLT_COLOR_EXP_TRANSP:
+		doBlt_ColorExpand(par, info, blt);
+		break;
+	case BLT_SOLID_FILL:
+		doBlt_SolidFill(par, info, blt);
+		break;
+	case BLT_WRITE_ROP:
+	case BLT_WRITE_TRANSP:
+		doBlt_Write(par, info, blt);
+		break;
+	case BLT_READ:
+	case BLT_PAT_FILL_ROP:
+	case BLT_PAT_FILL_TRANSP:
+	case BLT_MOVE_COLOR_EXP:
+	case BLT_MOVE_COLOR_EXP_TRANSP:
+		DPRINTK("BitBLT operation 0x%02x not implemented yet\n",
+			blt->operation);
+		return -ENXIO;
+	default:
+		DPRINTK("Unknown BitBLT operation 0x%02x\n", blt->operation);
+		return -ENXIO;
+	}
+    
+	return 0;
+}
+
+
+// Initializes blt->src and blt->srcstride
+static void fill_putcs_buffer(struct display *p,
+			      blt_info_t* blt,
+			      const unsigned short* str,
+			      int count)
+{   
+	int row, i, j;
+	u8* b1, *b2;
+	u32 fw = fontwidth(p);
+	u32 fwb = (fw + 7) >> 3;
+	u32 fh = fontheight(p);
+	int bytesPerChar = fwb * fh;
+
+	if (count*bytesPerChar > PAGE_SIZE) {
+		// Truncate the string if it overflows putcs_buffer, which is
+		// one page in size.
+		count = PAGE_SIZE/bytesPerChar - 1;
+	}
+
+	blt->srcstride = (fwb*count + 1) & ~1; //round up to be even
+	
+	b1 = (u8*)blt->src;
+
+	for (row = 0; row < fh; row++) {
+		b2 = b1;
+		for (i = 0; i < count; i++) {
+			for (j=0; j<fwb; j++)
+				*b2++ = p->fontdata[(str[i] & p->charmask) *
+						   bytesPerChar +
+						   row*fwb + j];
+		}
+		b1 += blt->srcstride;
+	}
+}
+
+
+/*
+ * Set the color of a palette entry in 8bpp mode 
+ */
+static inline void
+do_setpalentry(reg_lut_t* lut, unsigned regno,
+	       u8 r, u8 g, u8 b)
+{
+	writeb(0x00, &lut->mode);
+	writeb((u8)regno, &lut->addr);
+	writeb(r&0xf0, &lut->data);
+	writeb(g&0xf0, &lut->data);
+	writeb(b&0xf0, &lut->data);
+}
+
+   
+static void
+do_pan_var(struct fb_var_screeninfo* var, struct fb_info_e1356* info)
+{
+	u32 pixel_start, start_addr;
+	u8 pixel_pan;
+	struct e1356fb_par* par = &info->current_par;
+	reg_misc_t* misc = info->reg.misc;
+	reg_dispmode_t* dispmode = (IS_PANEL(info->fix.disp_type)) ?
+		info->reg.lcd_mode : info->reg.crttv_mode;
+	
+	pixel_start = var->yoffset * par->width_virt + var->xoffset;
+	start_addr = (pixel_start * par->Bpp) / 2;
+	pixel_pan = (par->bpp == 8) ? (u8)(pixel_start & 1) : 0;
+    
+	if (readb(&misc->disp_mode) != 0) {
+		reg_dispcfg_t* dispcfg = (IS_PANEL(info->fix.disp_type)) ?
+			info->reg.lcd_cfg : info->reg.crttv_cfg;
+
+		// wait for the end of the current VNDP
+		e1356_wait_bitclr(&dispcfg->vndp, 0x80, 5000);
+		// now wait for the start of a new VNDP
+		e1356_wait_bitset(&dispcfg->vndp, 0x80, 5000);
+	}
+    
+	writeb((u8)(start_addr & 0xff), &dispmode->start_addr0);
+	writeb((u8)((start_addr>>8) & 0xff), &dispmode->start_addr1);
+	writeb((u8)((start_addr>>16) & 0xff), &dispmode->start_addr2);
+	writeb(pixel_pan, &dispmode->pixel_panning);
+}
+
+
+/*
+ * Invert the hardware cursor image (timerfunc)  
+ */
+static void
+do_flashcursor(unsigned long ptr)
+{
+	u8 curs_ctrl;
+	struct fb_info_e1356* info = (struct fb_info_e1356 *)ptr;
+	reg_inkcurs_t* inkcurs = (IS_PANEL(info->fix.disp_type)) ?
+		info->reg.lcd_inkcurs : info->reg.crttv_inkcurs;
+
+	spin_lock(&info->cursor.lock);
+	// toggle cursor enable bit
+	curs_ctrl = readb(&inkcurs->ctrl);
+	writeb((curs_ctrl ^ 0x01) & 0x01, &inkcurs->ctrl);
+	info->cursor.timer.expires = jiffies+HZ/2;
+	add_timer(&info->cursor.timer);
+	spin_unlock(&info->cursor.lock);
+}
+
+#ifdef SHADOW_FRAME_BUFFER
+/*
+ * Write BLT the shadow frame buffer to the real fb (timerfunc)  
+ */
+static void
+do_write_shadow_fb(unsigned long ptr)
+{
+	blt_info_t blt;
+	struct fb_info_e1356 *info = (struct fb_info_e1356*)ptr;
+	struct fb_info* fb = &info->fb_info;
+	struct e1356fb_par* par = &info->current_par;
+	u32 stride = par->width_virt * par->Bpp;
+
+	unsigned long j_start = jiffies;
+    
+	blt.src_x = blt.src_y = 0;
+	blt.attribute = 0;
+	blt.dst_width = par->width;
+	blt.dst_height = par->height;
+	blt.dst_y = fb->var.yoffset;
+	blt.dst_x = fb->var.xoffset;
+	blt.operation = BLT_WRITE_ROP;
+	blt.rop = 0x0c; // ROP: destination = source
+	blt.src = (u16*)(info->shadow.fb + blt.dst_x * par->Bpp +
+			 blt.dst_y * stride);
+
+	doBlt(par, info, &blt);
+    
+	info->shadow.timer.expires = jiffies+HZ/2;
+	add_timer(&info->shadow.timer);
+
+	//DPRINTK("delta jiffies = %ld\n", jiffies - j_start);
+}
+#endif
+
+
+/* ------------------------------------------------------------------------- 
+ *              Hardware independent part, interface to the world
+ * ------------------------------------------------------------------------- */
+
+static void
+e1356_cfbX_clear_margins(struct vc_data* conp, struct display* p,
+			 int bottom_only)
+{
+	blt_info_t blt;
+	unsigned int cw=fontwidth(p);
+	unsigned int ch=fontheight(p);
+	unsigned int rw=p->var.xres % cw;
+	unsigned int bh=p->var.yres % ch;
+	unsigned int rs=p->var.xres - rw;
+	unsigned int bs=p->var.yres - bh;
+
+	//DPRINTK("\n");
+
+	if (!bottom_only && rw) { 
+		blt.dst_x = p->var.xoffset+rs;
+		blt.dst_y = p->var.yoffset;
+		blt.dst_height = p->var.yres;
+		blt.dst_width = rw;
+		blt.attribute = 0;
+		blt.fg_color = 0;
+		blt.operation = BLT_SOLID_FILL;
+		doBlt (&fb_info.current_par, &fb_info, &blt);
+	}
+    
+	if (bh) { 
+		blt.dst_x = p->var.xoffset;
+		blt.dst_y = p->var.yoffset+bs;
+		blt.dst_height = bh;
+		blt.dst_width = rs;
+		blt.attribute = 0;
+		blt.fg_color = 0;
+		blt.operation = BLT_SOLID_FILL;
+		doBlt (&fb_info.current_par, &fb_info, &blt);
+	}
+}
+
+static void
+e1356_cfbX_bmove(struct display* p, 
+		 int sy, 
+		 int sx, 
+		 int dy,
+		 int dx, 
+		 int height, 
+		 int width)
+{
+	blt_info_t blt;
+    
+	//DPRINTK("(%d,%d) to (%d,%d) size (%d,%d)\n", sx,sy,dx,dy,width,height);
+
+	blt.src_x = fontwidth_x8(p)*sx;
+	blt.src_y = fontheight(p)*sy;
+	blt.dst_x = fontwidth_x8(p)*dx;
+	blt.dst_y = fontheight(p)*dy;
+	blt.src_height = blt.dst_height = fontheight(p)*height;
+	blt.src_width = blt.dst_width = fontwidth_x8(p)*width;
+	blt.attribute = 0;
+	blt.rop = 0x0c;
+	/*
+	 * The move BLT routine will actually decide between a pos/neg
+	 * move BLT. This is just so that the BLT dispatcher knows to
+	 * call the move BLT routine.
+	 */
+	blt.operation = BLT_MOVE_POS_ROP;
+
+	doBlt (&fb_info.current_par, &fb_info, &blt);
+}
+
+static void
+e1356_cfb8_putc(struct vc_data* conp,
+		struct display* p,
+		int c, int yy,int xx)
+{   
+	blt_info_t blt;
+	u32 fgx,bgx;
+	u32 fw = fontwidth_x8(p);
+	u32 fh = fontheight(p);
+	u16 cs = (u16)c;
+
+	fgx = attr_fgcol(p, c);
+	bgx = attr_bgcol(p, c);
+
+	blt.src_x = blt.src_y = 0;
+	blt.attribute = 0;
+	blt.dst_width = fw;
+	blt.dst_height = fh;
+	blt.dst_y = yy * fh;
+	blt.dst_x = xx * fw;
+	blt.bg_color = bgx;
+	blt.fg_color = fgx;
+	blt.operation = BLT_COLOR_EXP;
+	blt.src = fb_info.putcs_buffer;
+	fill_putcs_buffer(p, &blt, &cs, 1);
+
+	doBlt(&fb_info.current_par, &fb_info, &blt);
+
+}
+
+static void
+e1356_cfb16_putc(struct vc_data* conp,
+		 struct display* p,
+		 int c, int yy,int xx)
+{   
+	blt_info_t blt;
+	u32 fgx,bgx;
+	u32 fw = fontwidth_x8(p);
+	u32 fh = fontheight(p);
+	u16 cs = (u16)c;
+    
+	fgx = ((u16*)p->dispsw_data)[attr_fgcol(p,c)];
+	bgx = ((u16*)p->dispsw_data)[attr_bgcol(p,c)];
+
+	blt.src_x = blt.src_y = 0;
+	blt.attribute = 0;
+	blt.dst_width = fw;
+	blt.dst_height = fh;
+	blt.dst_y = yy * fh;
+	blt.dst_x = xx * fw;
+	blt.bg_color = bgx;
+	blt.fg_color = fgx;
+	blt.operation = BLT_COLOR_EXP;
+	blt.src = fb_info.putcs_buffer;
+	fill_putcs_buffer(p, &blt, &cs, 1);
+
+	doBlt(&fb_info.current_par, &fb_info, &blt);
+}
+
+
+static void
+e1356_cfb8_putcs(struct vc_data* conp,
+		 struct display* p,
+		 const unsigned short *s,int count,int yy,int xx)
+{
+	blt_info_t blt;
+	u32 fgx,bgx;
+	u32 fw = fontwidth_x8(p);
+	u32 fh = fontheight(p);
+
+	//DPRINTK("\n");
+
+	fgx=attr_fgcol(p, *s);
+	bgx=attr_bgcol(p, *s);
+
+	blt.src_x = blt.src_y = 0;
+	blt.attribute = 0;
+	blt.dst_width = count * fw;
+	blt.dst_height = fh;
+	blt.dst_y = yy * fh;
+	blt.dst_x = xx * fw;
+	blt.bg_color = bgx;
+	blt.fg_color = fgx;
+	blt.operation = BLT_COLOR_EXP;
+	blt.src = fb_info.putcs_buffer;
+	fill_putcs_buffer(p, &blt, s, count);
+
+	doBlt(&fb_info.current_par, &fb_info, &blt);
+}
+
+static void
+e1356_cfb16_putcs(struct vc_data* conp,
+		  struct display* p,
+		  const unsigned short *s,int count,int yy,int xx)
+{
+	blt_info_t blt;
+	u32 fgx,bgx;
+	u32 fw = fontwidth_x8(p);
+	u32 fh = fontheight(p);
+
+	//DPRINTK("\n");
+
+	fgx=((u16*)p->dispsw_data)[attr_fgcol(p,*s)];
+	bgx=((u16*)p->dispsw_data)[attr_bgcol(p,*s)];
+
+	blt.src_x = blt.src_y = 0;
+	blt.attribute = 0;
+	blt.dst_width = count * fw;
+	blt.dst_height = fh;
+	blt.dst_y = yy * fh;
+	blt.dst_x = xx * fw;
+	blt.bg_color = bgx;
+	blt.fg_color = fgx;
+	blt.operation = BLT_COLOR_EXP;
+	blt.src = fb_info.putcs_buffer;
+	fill_putcs_buffer(p, &blt, s, count);
+
+	doBlt(&fb_info.current_par, &fb_info, &blt);
+}
+
+
+static void
+e1356_cfb8_clear(struct vc_data* conp, 
+		 struct display* p, 
+		 int sy,
+		 int sx, 
+		 int height, 
+		 int width)
+{
+	blt_info_t blt;
+	u32 bg = attr_bgcol_ec(p,conp);
+
+	//DPRINTK("(%d,%d) size (%d,%d)\n", sx,sy,width,height);
+
+	blt.dst_x = fontwidth_x8(p)*sx;
+	blt.dst_y = fontheight(p)*sy;
+	blt.dst_height = fontheight(p)*height;
+	blt.dst_width = fontwidth_x8(p)*width;
+	blt.attribute = 0;
+	blt.fg_color = bg;
+	blt.operation = BLT_SOLID_FILL;
+
+	doBlt (&fb_info.current_par, &fb_info, &blt);
+}
+
+static void
+e1356_cfb16_clear(struct vc_data* conp, 
+		  struct display* p, 
+		  int sy,
+		  int sx, 
+		  int height, 
+		  int width)
+{
+	blt_info_t blt;
+	u32 bg = ((u16*)p->dispsw_data)[attr_bgcol_ec(p,conp)];
+
+	//DPRINTK("(%d,%d) size (%d,%d)\n", sx,sy,width,height);
+
+	blt.dst_x = fontwidth_x8(p)*sx;
+	blt.dst_y = fontheight(p)*sy;
+	blt.dst_height = fontheight(p)*height;
+	blt.dst_width = fontwidth_x8(p)*width;
+	blt.attribute = 0;
+	blt.fg_color = bg;
+	blt.operation = BLT_SOLID_FILL;
+
+	doBlt (&fb_info.current_par, &fb_info, &blt);
+}
+
+
+static void
+e1356_cfbX_revc(struct display *p, int xx, int yy)
+{
+	// not used if h/w cursor
+	//DPRINTK("\n");
+}
+
+static void
+e1356_cfbX_cursor(struct display *p, int mode, int x, int y) 
+{
+	unsigned long flags;
+	struct fb_info_e1356 *info=(struct fb_info_e1356 *)p->fb_info;
+	reg_inkcurs_t* inkcurs = (IS_PANEL(info->fix.disp_type)) ?
+		info->reg.lcd_inkcurs : info->reg.crttv_inkcurs;
+    
+	//DPRINTK("\n");
+
+	if (mode == CM_ERASE) {
+		if (info->cursor.state != CM_ERASE) {
+			spin_lock_irqsave(&info->cursor.lock,flags);
+			info->cursor.state = CM_ERASE;
+			del_timer(&(info->cursor.timer));
+			writeb(0x00, &inkcurs->ctrl);
+			spin_unlock_irqrestore(&info->cursor.lock,flags);
+		}
+		return;
+	}
+    
+	if ((p->conp->vc_cursor_type & CUR_HWMASK) != info->cursor.type)
+		e1356fb_createcursor(p);
+    
+	x *= fontwidth_x8(p);
+	y *= fontheight(p);
+	x -= p->var.xoffset;
+	y -= p->var.yoffset;
+    
+	spin_lock_irqsave(&info->cursor.lock,flags);
+	if ((x != info->cursor.x) || (y != info->cursor.y) ||
+	    (info->cursor.redraw)) {
+		info->cursor.x = x;
+		info->cursor.y = y;
+		info->cursor.redraw = 0;
+		writeb(0x01, &inkcurs->ctrl);
+		writew(x, &inkcurs->x_pos0);
+		writew(y, &inkcurs->y_pos0);
+		/* fix cursor color - XFree86 forgets to restore it properly */
+		writeb(0x00, &inkcurs->blue0);
+		writeb(0x00, &inkcurs->green0);
+		writeb(0x00, &inkcurs->red0);
+		writeb(0x1f, &inkcurs->blue1);
+		writeb(0x3f, &inkcurs->green1);
+		writeb(0x1f, &inkcurs->red1);
+	}
+
+	info->cursor.state = CM_DRAW;
+	mod_timer(&info->cursor.timer, jiffies+HZ/2);
+	spin_unlock_irqrestore(&info->cursor.lock,flags);
+}
+
+#ifdef FBCON_HAS_CFB8
+static struct display_switch fbcon_e1356_8 = {
+	setup:		fbcon_cfb8_setup, 
+	bmove:		e1356_cfbX_bmove, 
+	clear:		e1356_cfb8_clear, 
+	putc:		e1356_cfb8_putc,
+	putcs:		e1356_cfb8_putcs, 
+	revc:		e1356_cfbX_revc,   
+	cursor:		e1356_cfbX_cursor, 
+	clear_margins:	e1356_cfbX_clear_margins,
+	fontwidthmask:	FONTWIDTHRANGE(6,16)
+};
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static struct display_switch fbcon_e1356_16 = {
+	setup:		fbcon_cfb16_setup, 
+	bmove:		e1356_cfbX_bmove, 
+	clear:		e1356_cfb16_clear, 
+	putc:		e1356_cfb16_putc,
+	putcs:		e1356_cfb16_putcs, 
+	revc:		e1356_cfbX_revc, 
+	cursor:		e1356_cfbX_cursor, 
+	clear_margins:	e1356_cfbX_clear_margins,
+	fontwidthmask:	FONTWIDTHRANGE(6,16)
+};
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+static void
+e1356fb_set_par(const struct e1356fb_par* par,
+		struct fb_info_e1356* info)
+{
+	reg_dispcfg_t* dispcfg=NULL;
+	reg_dispmode_t* dispmode=NULL;
+	u8* pclk_cfg=NULL;
+	u8 width, hndp=0, hsync_start=0, hsync_width=0;
+	u8 vndp, vsync_start, vsync_width=0, display_mode;
+	u8 main_display_mode=0;
+	u16 height, addr_offset;
+	int disp_type = info->fix.disp_type;
+
+	DPRINTK("%dx%d-%dbpp @ %d Hz, %d kHz hsync\n",
+		par->width, par->height, par->bpp,
+		par->vsync_freq, (((2*par->hsync_freq)/1000)+1)/2);
+#ifdef E1356FB_VERBOSE_DEBUG
+	dump_par(par);
+#endif
+    
+	info->current_par = *par;
+
+	width = (par->width >> 3) - 1;
+	display_mode = (par->bpp == 8) ? 0x03 : 0x05;
+	addr_offset = (par->width_virt * par->Bpp) / 2;
+	vsync_start = (disp_type == DISP_TYPE_LCD) ? 0 : par->vsync_start - 1;
+	height = par->height - 1;
+	vndp = par->vert_ndp - 1;
+
+	switch (disp_type) {
+	case DISP_TYPE_LCD:
+		dispcfg = info->reg.lcd_cfg;
+		dispmode = info->reg.lcd_mode;
+		pclk_cfg = &info->reg.clk_cfg->lcd_pclk_cfg;
+		hndp = (par->horiz_ndp >> 3) - 1;
+		hsync_start = 0;
+		hsync_width = par->hsync_pol ? 0x00 : 0x80;
+		vsync_width = par->vsync_pol ? 0x00 : 0x80;
+		main_display_mode = 0x01;
+		break;
+	case DISP_TYPE_TFT:
+		dispcfg = info->reg.lcd_cfg;
+		dispmode = info->reg.lcd_mode;
+		pclk_cfg = &info->reg.clk_cfg->lcd_pclk_cfg;
+		hndp = (par->horiz_ndp >> 3) - 1;
+		hsync_start = (par->bpp == 8) ?
+			(par->hsync_start - 4) >> 3 :
+				(par->hsync_start - 6) >> 3;
+		hsync_width =
+			(par->hsync_pol ? 0x80 : 0x00) |
+			((par->hsync_width >> 3) - 1);
+		vsync_width =
+			(par->vsync_pol ? 0x80 : 0x00) |
+			(par->vsync_width - 1);
+		main_display_mode = 0x01;
+		break;
+	case DISP_TYPE_CRT:
+		dispcfg = info->reg.crttv_cfg;
+		dispmode = info->reg.crttv_mode;
+		pclk_cfg = &info->reg.clk_cfg->crttv_pclk_cfg;
+		hndp = (par->horiz_ndp >> 3) - 1;
+		hsync_start = (par->bpp == 8) ?
+			(par->hsync_start - 3) >> 3 :
+				(par->hsync_start - 5) >> 3;
+		hsync_width =
+			(par->hsync_pol ? 0x80 : 0x00) |
+			((par->hsync_width >> 3) - 1);
+		vsync_width =
+			(par->vsync_pol ? 0x80 : 0x00) |
+			(par->vsync_width - 1);
+		main_display_mode = 0x02;
+		break;
+	case DISP_TYPE_NTSC:
+	case DISP_TYPE_PAL:
+		dispcfg = info->reg.crttv_cfg;
+		dispmode = info->reg.crttv_mode;
+		pclk_cfg = &info->reg.clk_cfg->crttv_pclk_cfg;
+		hndp = (disp_type == DISP_TYPE_PAL) ?
+			(par->horiz_ndp - 7) >> 3 :
+				(par->horiz_ndp - 6) >> 3;
+		hsync_start = (par->bpp == 8) ?
+			(par->hsync_start + 7) >> 3 :
+				(par->hsync_start + 5) >> 3;
+		hsync_width = 0;
+		vsync_width = 0;
+		main_display_mode = (info->fix.tv_filt & TV_FILT_FLICKER) ?
+			0x06 : 0x04;
+		break;
+	}
+
+	// Blast the regs!
+	// note: reset panning/scrolling (set start-addr and
+	// pixel pan regs to 0). Panning is handled by pan_display.
+
+	e1356_engine_wait_complete(info->reg.bitblt);
+
+	// disable display while initializing
+	writeb(0, &info->reg.misc->disp_mode);
+
+	writeb(par->ipclk.pixclk_bits, pclk_cfg);
+
+	writeb(width, &dispcfg->hdw);
+	writeb(hndp, &dispcfg->hndp);
+	writeb(hsync_start, &dispcfg->hsync_start);
+	writeb(hsync_width, &dispcfg->hsync_pulse);
+	writew(height, &dispcfg->vdh0);
+	writeb(vndp, &dispcfg->vndp);
+	writeb(vsync_start, &dispcfg->vsync_start);
+	writeb(vsync_width, &dispcfg->vsync_pulse);
+
+	writeb(display_mode, &dispmode->disp_mode);
+	if (info->fix.mmunalign && info->mmaped)
+		writeb(1, &dispmode->start_addr0);
+	else
+		writeb(0, &dispmode->start_addr0);
+	writeb(0, &dispmode->start_addr1);
+	writeb(0, &dispmode->start_addr2);
+	writew(addr_offset, &dispmode->mem_addr_offset0);
+	writeb(0, &dispmode->pixel_panning);
+
+	// reset BitBlt engine
+	e1356fb_engine_init(par, info);
+
+#ifdef E1356FB_VERBOSE_DEBUG
+	dump_display_regs(dispcfg, dispmode);
+#endif
+
+	/* clear out framebuffer memory */
+	fbfill(fb_info.membase_virt, 0, fb_info.fb_size);
+	// finally, enable display!
+	writeb(main_display_mode, &info->reg.misc->disp_mode); 
+}
+
+
+static int
+e1356fb_verify_timing(struct e1356fb_par* par,
+		      const struct fb_info_e1356* info)
+{
+	int disp_type = info->fix.disp_type;
+
+	// timing boundary checks
+	if (par->horiz_ndp > max_hndp[disp_type]) {
+		DPRINTK("horiz_ndp too big: %d\n", par->horiz_ndp);
+		return -EINVAL;
+	}
+	if (par->vert_ndp > max_vndp[disp_type]) {
+		DPRINTK("vert_ndp too big: %d\n", par->vert_ndp);
+		return -EINVAL;
+	}
+
+	if (disp_type != DISP_TYPE_LCD) {
+		if (par->hsync_start >
+		    max_hsync_start[(par->bpp==16)][disp_type]) {
+			DPRINTK("hsync_start too big: %d\n",
+				par->hsync_start);
+			return -EINVAL;
+		}
+		if (par->vsync_start > max_vsync_start[disp_type]) {
+			DPRINTK("vsync_start too big: %d\n",
+				par->vsync_start);
+			return -EINVAL;
+		}
+		if (!IS_TV(disp_type)) {
+			if (par->hsync_width > max_hsync_width[disp_type]) {
+				DPRINTK("hsync_width too big: %d\n",
+					par->hsync_width);
+				return -EINVAL;
+			}
+			if (par->vsync_width > max_vsync_width[disp_type]) {
+				DPRINTK("vsync_width too big: %d\n",
+					par->vsync_width);
+				return -EINVAL;
+			}
+		}
+	}
+
+	if (IS_TV(disp_type)) {
+		int tv_pixclk = (disp_type == DISP_TYPE_NTSC) ?
+			NTSC_PIXCLOCK : PAL_PIXCLOCK;
+		if (info->fix.tv_filt & TV_FILT_FLICKER)
+			tv_pixclk *= 2;
+		
+		if (par->ipclk.pixclk_d != tv_pixclk) {
+			DPRINTK("invalid TV pixel clock %u kHz\n",
+				par->ipclk.pixclk_d);
+			return -EINVAL;
+		}
+	}
+	
+	if (e1356_calc_pixclock(info, &par->ipclk) < 0) {
+		DPRINTK("can't set pixel clock %u kHz\n",
+			par->ipclk.pixclk_d);
+		return -EINVAL;
+	}
+ 
+#ifdef E1356FB_VERBOSE_DEBUG
+	DPRINTK("desired pixclock = %d kHz, actual = %d kHz, error = %d%%\n",
+		par->ipclk.pixclk_d, par->ipclk.pixclk, par->ipclk.error);
+#endif
+    
+	if (disp_type != DISP_TYPE_LCD) {
+		if (par->horiz_ndp < par->hsync_start + par->hsync_width) {
+			DPRINTK("invalid horiz. timing\n");
+			return -EINVAL;
+		}
+		if (par->vert_ndp < par->vsync_start + par->vsync_width) {
+			DPRINTK("invalid vert. timing\n");
+			return -EINVAL;
+		}
+
+		// SED1356 Hardware Functional Spec, section 13.5
+		if (disp_type == DISP_TYPE_NTSC &&
+		    ((par->width + par->horiz_ndp != 910) ||
+		     (par->height + 2*par->vert_ndp+1 != 525))) {
+			DPRINTK("invalid NTSC timing\n");
+			return -EINVAL;
+		} else if (disp_type == DISP_TYPE_PAL &&
+			   ((par->width + par->horiz_ndp != 1135) ||
+			    (par->height + 2*par->vert_ndp+1 != 625))) {
+			DPRINTK("invalid PAL timing\n");
+			return -EINVAL;
+		}
+	}
+    
+	par->hsync_freq = (1000 * par->ipclk.pixclk) /
+		(par->width + par->horiz_ndp);
+	par->vsync_freq = par->hsync_freq / (par->height + par->vert_ndp);
+	
+	if (par->hsync_freq < 30000 || par->hsync_freq > 90000) {
+		DPRINTK("hsync freq too %s: %u Hz\n",
+			par->hsync_freq < 30000 ? "low" : "high",
+			par->hsync_freq);
+		return -EINVAL;
+	}
+	if (par->vsync_freq < 50 || par->vsync_freq > 110) {
+		DPRINTK("vsync freq too %s: %u Hz\n",
+			par->vsync_freq < 50 ? "low" : "high",
+			par->vsync_freq);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+e1356fb_verify_par(struct e1356fb_par* par,
+		   const struct fb_info_e1356* info)
+{
+	int disp_type = info->fix.disp_type;
+    
+	if (par->bpp != 8 && par->bpp != 16) {
+		DPRINTK("depth not supported: %u bpp\n", par->bpp);
+		return -EINVAL;
+	}
+
+	if (par->width > par->width_virt) {
+		DPRINTK("virtual x resolution < physical x resolution not possible\n");
+		return -EINVAL;
+	}
+
+	if (par->height > par->height_virt) {
+		DPRINTK("virtual y resolution < physical y resolution not possible\n");
+		return -EINVAL;
+	}
+
+	if (par->width < 320 || par->width > 1024) {
+		DPRINTK("width not supported: %u\n", par->width);
+		return -EINVAL;
+	}
+
+	if ((disp_type == DISP_TYPE_LCD && (par->width % 16)) ||
+	    (disp_type == DISP_TYPE_TFT && (par->width % 8))) {
+		DPRINTK("invalid width for panel type: %u\n", par->width);
+		return -EINVAL;
+	}
+
+	if (par->height < 200 || par->height > 1024) {
+		DPRINTK("height not supported: %u\n", par->height);
+		return -EINVAL;
+	}
+
+	if (par->width_virt * par->height_virt * par->Bpp >
+	    info->fb_size) {
+		DPRINTK("not enough memory for virtual screen (%ux%ux%u)\n",
+			par->width_virt, par->height_virt, par->bpp);
+		return -EINVAL;
+	}
+
+	return e1356fb_verify_timing(par, info);
+}
+
+
+static int
+e1356fb_var_to_par(const struct fb_var_screeninfo* var,
+		   struct e1356fb_par* par,
+		   const struct fb_info_e1356* info)
+{
+	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+		DPRINTK("interlace not supported\n");
+		return -EINVAL;
+	}
+
+	memset(par, 0, sizeof(struct e1356fb_par));
+
+	par->width       = (var->xres + 15) & ~15; /* could sometimes be 8 */
+	par->width_virt  = var->xres_virtual;
+	par->height      = var->yres;
+	par->height_virt = var->yres_virtual;
+	par->bpp         = var->bits_per_pixel;
+	par->Bpp         = (par->bpp + 7) >> 3;
+
+	par->ipclk.pixclk_d = PICOS2KHZ(var->pixclock);
+
+	par->hsync_start = var->right_margin;
+	par->hsync_width = var->hsync_len;
+
+	par->vsync_start = var->lower_margin;
+	par->vsync_width = var->vsync_len;
+
+	par->horiz_ndp = var->left_margin + var->right_margin + var->hsync_len;
+	par->vert_ndp = var->upper_margin + var->lower_margin + var->vsync_len;
+
+	par->hsync_pol = (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 1 : 0;
+	par->vsync_pol = (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 1 : 0;
+
+	par->cmap_len  = (par->bpp == 8) ? 256 : 16;
+
+	return e1356fb_verify_par(par, info);
+}
+
+static int
+e1356fb_par_to_var(struct fb_var_screeninfo* var,
+		   struct e1356fb_par* par,
+		   const struct fb_info_e1356* info)
+{
+	struct fb_var_screeninfo v;
+	int ret;
+    
+	// First, make sure par is valid.
+	if ((ret = e1356fb_verify_par(par, info)))
+		return ret;
+
+	memset(&v, 0, sizeof(struct fb_var_screeninfo));
+	v.xres_virtual   = par->width_virt;
+	v.yres_virtual   = par->height_virt;
+	v.xres           = par->width;
+	v.yres           = par->height;
+	v.right_margin   = par->hsync_start;
+	v.hsync_len      = par->hsync_width;
+	v.left_margin    = par->horiz_ndp - par->hsync_start - par->hsync_width;
+	v.lower_margin   = par->vsync_start;
+	v.vsync_len      = par->vsync_width;
+	v.upper_margin   = par->vert_ndp - par->vsync_start - par->vsync_width;
+	v.bits_per_pixel = par->bpp;
+
+	switch(par->bpp) {
+	case 8:
+		v.red.offset = v.green.offset = v.blue.offset = 0;
+		v.red.length = v.green.length = v.blue.length = 4;
+		break;
+	case 16:
+		v.red.offset   = 11;
+		v.red.length   = 5;
+		v.green.offset = 5;
+		v.green.length = 6;
+		v.blue.offset  = 0;
+		v.blue.length  = 5;
+		break;
+	}
+
+	v.height = v.width = -1;
+	v.pixclock = KHZ2PICOS(par->ipclk.pixclk);
+
+	if (par->hsync_pol)
+		v.sync |= FB_SYNC_HOR_HIGH_ACT;
+	if (par->vsync_pol)
+		v.sync |= FB_SYNC_VERT_HIGH_ACT;
+
+	*var = v;
+	return 0;
+}
+
+static int
+e1356fb_encode_fix(struct fb_fix_screeninfo*  fix,
+		   const struct e1356fb_par*   par,
+		   const struct fb_info_e1356* info)
+{
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+    
+	strcpy(fix->id, "Epson SED1356");
+	fix->smem_start  = info->fix.membase_phys;
+	fix->smem_len    = info->fb_size;
+	fix->mmio_start  = info->fix.regbase_phys;
+	fix->mmio_len    = info->regbase_size;
+	fix->accel       = FB_ACCEL_EPSON_SED1356;
+	fix->type        = FB_TYPE_PACKED_PIXELS;
+	fix->type_aux    = 0;
+	fix->line_length = par->width_virt * par->Bpp;
+	fix->visual      =
+		(par->bpp == 8) ? FB_VISUAL_PSEUDOCOLOR	: FB_VISUAL_TRUECOLOR;
+    
+	fix->xpanstep    = info->fix.nopan ? 0 : 1;
+	fix->ypanstep    = info->fix.nopan ? 0 : 1;
+	fix->ywrapstep   = 0;
+    
+	return 0;
+}
+
+static int e1356fb_open(struct fb_info *fb, int user)
+{
+	struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
+        if (user) {
+                info->open++;
+	}
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int e1356fb_release(struct fb_info *fb, int user)
+{
+	struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
+        if (user && info->open) {
+                info->open--;
+		if (info->open == 0)
+                        info->mmaped = 0;
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int
+e1356fb_get_fix(struct fb_fix_screeninfo *fix, 
+		int con,
+		struct fb_info *fb)
+{
+	const struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
+	struct e1356fb_par par;
+
+	//DPRINTK("\n");
+
+	if (con == -1)
+		par = info->current_par;
+	else
+		e1356fb_var_to_par(&fb_display[con].var, &par, info);
+	e1356fb_encode_fix(fix, &par, info);
+	return 0;
+}
+
+static int
+e1356fb_get_var(struct fb_var_screeninfo *var, 
+		int con,
+		struct fb_info *fb)
+{
+	struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
+
+	//DPRINTK("\n");
+
+	if (con == -1)
+		e1356fb_par_to_var(var, &info->current_par, info);
+	else
+		*var = fb_display[con].var;
+	return 0;
+}
+ 
+static void
+e1356fb_set_dispsw(struct display *disp, 
+		   struct fb_info_e1356 *info,
+		   int bpp, 
+		   int accel)
+{
+	struct e1356fb_fix* fix = &info->fix;
+	//DPRINTK("\n");
+
+	if (disp->dispsw && disp->conp) 
+		fb_con.con_cursor(disp->conp, CM_ERASE);
+	switch (bpp) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		disp->dispsw = fix->noaccel ? &fbcon_cfb8 : &fbcon_e1356_8;
+		if (fix->nohwcursor)
+			fbcon_e1356_8.cursor = NULL;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		disp->dispsw = fix->noaccel ? &fbcon_cfb16 : &fbcon_e1356_16;
+		disp->dispsw_data = info->fbcon_cmap16;
+		if (fix->nohwcursor)
+			fbcon_e1356_16.cursor = NULL;
+		break;
+#endif
+	default:
+		disp->dispsw = &fbcon_dummy;
+	}
+   
+}
+
+static int
+e1356fb_set_var(struct fb_var_screeninfo *var, 
+		int con,
+		struct fb_info *fb)
+{
+	struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
+	struct e1356fb_par par;
+	struct display *display;
+	int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err;
+	int activate = var->activate;
+	int j,k;
+    
+	DPRINTK("\n");
+	
+	if (con >= 0)
+		display = &fb_display[con];
+	else
+		display = fb->disp;	/* used during initialization */
+   
+	if ((err = e1356fb_var_to_par(var, &par, info))) {
+		struct fb_videomode *dm;
+		/*
+		 * this mode didn't pass the tests. Try the
+		 * corresponding mode from our own modedb.
+		 */
+		DPRINTK("req mode failed, trying SED1356 %dx%d mode\n",
+			var->xres, var->yres);
+		if (e1356fb_get_mode(info, var->xres,
+				     var->yres, NULL, &dm) < 0) {
+			DPRINTK("no SED1356 %dx%d mode found, failed\n",
+				var->xres, var->yres);
+			return err;
+		}
+		fb_videomode_to_var(dm, var);
+		if ((err = e1356fb_var_to_par(var, &par, info))) {
+			DPRINTK("SED1356 %dx%d mode failed\n",
+				var->xres, var->yres);
+			return err;
+		}
+	}
+	
+	if (info->fix.tv_filt & TV_FILT_FLICKER)
+		printk("e1356fb: TV flicker filter enabled\n");
+    
+	e1356fb_par_to_var(var, &par, info);
+   
+	if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+		oldxres  = display->var.xres;
+		oldyres  = display->var.yres;
+		oldvxres = display->var.xres_virtual;
+		oldvyres = display->var.yres_virtual;
+		oldbpp   = display->var.bits_per_pixel;
+		oldaccel = display->var.accel_flags;
+		display->var = *var;
+		if (con < 0                         ||
+		    oldxres  != var->xres           || 
+		    oldyres  != var->yres           ||
+		    oldvxres != var->xres_virtual   || 
+		    oldvyres != var->yres_virtual   ||
+		    oldbpp   != var->bits_per_pixel || 
+		    oldaccel != var->accel_flags) {
+			struct fb_fix_screeninfo fix;
+	    
+			e1356fb_encode_fix(&fix, &par, info);
+			display->screen_base    = info->membase_virt;
+			display->visual         = fix.visual;
+			display->type           = fix.type;
+			display->type_aux       = fix.type_aux;
+			display->ypanstep       = fix.ypanstep;
+			display->ywrapstep      = fix.ywrapstep;
+			display->line_length    = fix.line_length;
+			display->next_line      = fix.line_length;
+			display->can_soft_blank = 1;
+			display->inverse        = 0;
+			accel = var->accel_flags & FB_ACCELF_TEXT;
+			e1356fb_set_dispsw(display, info, par.bpp, accel);
+	 
+			if (info->fix.nopan)
+				display->scrollmode = SCROLL_YREDRAW;
+	
+			if (info->fb_info.changevar)
+				(*info->fb_info.changevar)(con);
+		}
+		if (var->bits_per_pixel==8)
+			for(j = 0; j < 16; j++) {
+				k = color_table[j];
+				fb_info.palette[j].red   = default_red[k];
+				fb_info.palette[j].green = default_grn[k];
+				fb_info.palette[j].blue  = default_blu[k];
+			}
+      
+		del_timer(&(info->cursor.timer)); 
+		fb_info.cursor.state=CM_ERASE;
+	
+		if (!info->fb_info.display_fg ||
+		    info->fb_info.display_fg->vc_num == con || con < 0)
+			e1356fb_set_par(&par, info);
+
+		if (!info->fix.nohwcursor) 
+			if (display && display->conp)
+				e1356fb_createcursor( display );
+		info->cursor.redraw = 1;
+
+		if (oldbpp != var->bits_per_pixel || con < 0) {
+			if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
+				return err;
+			e1356fb_install_cmap(display, &(info->fb_info));
+		}
+	}
+  
+	return 0;
+}
+
+static int
+e1356fb_pan_display(struct fb_var_screeninfo* var, 
+		    int con,
+		    struct fb_info* fb)
+{
+	struct fb_info_e1356* info = (struct fb_info_e1356*)fb;
+	struct e1356fb_par* par = &info->current_par;
+    
+	//DPRINTK("\n");
+
+	if (info->fix.nopan)
+		return -EINVAL;
+
+	if ((int)var->xoffset < 0 ||
+	    var->xoffset + par->width > par->width_virt ||
+	    (int)var->yoffset < 0 ||
+	    var->yoffset + par->height > par->height_virt)
+		return -EINVAL;
+    
+	if (con == currcon)
+		do_pan_var(var, info);
+    
+	fb_display[con].var.xoffset = var->xoffset;
+	fb_display[con].var.yoffset = var->yoffset; 
+
+	return 0;
+}
+
+static int
+e1356fb_get_cmap(struct fb_cmap *cmap, 
+		 int kspc, 
+		 int con,
+		 struct fb_info *fb)
+{
+	struct fb_info_e1356* info = (struct fb_info_e1356*)fb;
+	struct display *d = (con<0) ? fb->disp : fb_display + con;
+   
+	//DPRINTK("\n");
+
+	if (con == currcon) {
+		/* current console? */
+		return fb_get_cmap(cmap, kspc, e1356fb_getcolreg, fb);
+	} else if (d->cmap.len) {
+		/* non default colormap? */
+		fb_copy_cmap(&d->cmap, cmap, kspc ? 0 : 2);
+	} else {
+		fb_copy_cmap(fb_default_cmap(info->current_par.cmap_len),
+			     cmap, kspc ? 0 : 2);
+	}
+	return 0;
+}
+
+static int
+e1356fb_set_cmap(struct fb_cmap *cmap, 
+		 int kspc, 
+		 int con,
+		 struct fb_info *fb)
+{
+	struct display *d = (con<0) ? fb->disp : fb_display + con;
+	struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
+	int cmap_len = (info->current_par.bpp == 8) ? 256 : 16;
+
+	//DPRINTK("\n");
+
+	if (d->cmap.len!=cmap_len) {
+		int err;
+		if ((err = fb_alloc_cmap(&d->cmap, cmap_len, 0)))
+			return err;
+	}
+    
+	if (con == currcon) {
+		/* current console? */
+		return fb_set_cmap(cmap, kspc, e1356fb_setcolreg, fb);
+	} else {
+		fb_copy_cmap(cmap, &d->cmap, kspc ? 0 : 1);
+	}
+	return 0;
+}
+
+static int
+e1356fb_mmap(struct fb_info *fb,
+	     struct file *file,
+	     struct vm_area_struct *vma)
+{
+	struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
+	unsigned int len;
+#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
+	u64 start=0, off;
+#else
+	unsigned long start=0, off;
+#endif
+
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
+		DPRINTK("invalid vma->vm_pgoff\n");
+		return -EINVAL;
+	}
+    
+#ifdef SHADOW_FRAME_BUFFER
+	if (!info->shadow.fb) {
+		int order = 0;
+		while (info->fb_size > (PAGE_SIZE * (1 << order)))
+			order++;
+		info->shadow.fb = (void*)__get_free_pages(GFP_KERNEL, order);
+		if (!info->shadow.fb) {
+			DPRINTK("shadow fb alloc failed\n");
+			return -ENXIO;
+		}
+		memset(info->shadow.fb, 0, info->fb_size);
+		init_timer(&info->shadow.timer);
+		info->shadow.timer.function = do_write_shadow_fb;
+		info->shadow.timer.data = (unsigned long)info;
+	}
+	mod_timer(&info->shadow.timer, jiffies+HZ/2);
+	start = virt_to_phys(info->shadow.fb) & PAGE_MASK;
+#else
+	start = info->fix.membase_phys & PAGE_MASK;
+#endif
+
+	len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fb_size);
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+    
+	if ((vma->vm_end - vma->vm_start + off) > len) {
+		DPRINTK("invalid vma\n");
+		return -EINVAL;
+	}
+
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+
+	pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
+#ifdef SHADOW_FRAME_BUFFER
+	vma->vm_flags |= VM_RESERVED;
+	pgprot_val(vma->vm_page_prot) &= ~_CACHE_UNCACHED;
+#else
+	pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
+#endif
+
+	/* This is an IO map - tell maydump to skip this VMA */
+	vma->vm_flags |= VM_IO;
+	// FIXME: shouldn't have to do this. If the pages are marked writeable,
+	// the TLB fault handlers should set these.
+	pgprot_val(vma->vm_page_prot) |= (_PAGE_DIRTY | _PAGE_VALID);
+    
+	/*
+	 * The SED1356 has only a 16-bit wide data bus, and some
+	 * embedded platforms, such as the Pb1000, do not automatically
+	 * split 32-bit word accesses to the framebuffer into
+	 * seperate half-word accesses. Hence the upper half-word
+	 * never gets to the framebuffer. The following solution is
+	 * to intentionally return a non-32-bit-aligned VA. As long
+	 * as the user app assumes (and doesn't check) that the returned
+	 * VA is 32-bit aligned, all (assumed aligned) 32-bit accesses
+	 * will actually be unaligned and will get trapped by the MIPS
+	 * unaligned exception handler. This handler will emulate the
+	 * load/store instructions by splitting up the load/store
+	 * into two 16-bit load/stores. (This emulation is currently
+	 * enabled by default, but may be disabled in the future, when
+	 * alignment problems in user-level programs get fixed. When
+	 * that happens, this solution won't work anymore, unless the
+	 * process that mmap's the fb also calls sysmips(MIPS_FIXADE, 1),
+	 * which turns address-error emulation back on).
+	 *
+	 * Furthermore, this solution only seems to work for TinyX
+	 * (Xfbdev). Others, like Qt/E, do snoop the returned VA
+	 * and compensate, or do originally unaligned 32-bit accesses
+	 * which then become aligned, hence breaking this solution.
+	 */
+	if (info->fix.mmunalign)
+		vma->vm_start += 2;
+	
+#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
+	if (e1356_remap_page_range(vma->vm_start, off,
+				vma->vm_end - vma->vm_start,
+				vma->vm_page_prot))
+		return -EAGAIN;
+#else
+	if (io_remap_page_range(vma->vm_start, off,
+				vma->vm_end - vma->vm_start,
+				vma->vm_page_prot))
+		return -EAGAIN;
+#endif
+
+	info->mmaped = 1;
+	return 0;
+}
+
+
+int __init
+e1356fb_init(void)
+{
+	struct fb_var_screeninfo var;
+	struct e1356fb_fix * epfix = &fb_info.fix;
+	e1356_reg_t* reg;
+	void* regbase;
+	char* name = "SED1356";
+	int periodMCLK, periodBCLK;
+	int dram_timing, rr_div, mclk_src;
+	u8 rev_code, btmp, mclk_cfg;
+
+	if (options) {
+		e1356fb_setup(options, 0);
+	}
+
+	// clear out fb_info
+	memset(&fb_info, 0, sizeof(struct fb_info_e1356));
+
+	// copy boot options
+	fb_info.fix = boot_fix;
+	fb_info.default_par = boot_par;
+
+	fb_info.regbase_size = E1356_REG_SIZE;
+
+	if (!epfix->system) {
+		printk(KERN_ERR "e1356/86fb: no valid system found\n");
+		return -ENODEV;
+	}
+
+	if (epfix->system == SYS_SDU1356) {
+		// it's the SDU1356B0C PCI eval card.
+		struct pci_dev *pdev = NULL;
+		if (!pci_present())   /* No PCI bus in this machine! */
+			return -ENODEV;
+		if (!(pdev = pci_find_device(PCI_VENDOR_ID_EPSON,
+					     PCI_DEVICE_ID_EPSON_SDU1356, pdev)))
+			return -ENODEV;
+		if (pci_enable_device(pdev))
+			return -ENODEV;
+		epfix->regbase_phys = pci_resource_start(pdev, 0);
+		epfix->membase_phys = epfix->regbase_phys + E1356_REG_SIZE;
+	}
+	
+	fb_info.regbase_virt = ioremap_nocache(epfix->regbase_phys,
+					       E1356_REG_SIZE);
+
+	if (!fb_info.regbase_virt) {
+		printk("e1356fb: Can't remap %s register area.\n", name);
+		return -ENXIO;
+	}
+
+	regbase = fb_info.regbase_virt;
+	reg = &fb_info.reg;
+    
+	// Initialize the register pointers
+	reg->basic =         (reg_basic_t*)   (regbase + REG_BASE_BASIC);
+	reg->genio =         (reg_genio_t*)   (regbase + REG_BASE_GENIO);
+	reg->md_cfg =        (reg_mdcfg_t*)   (regbase + REG_BASE_MDCFG);
+	reg->clk_cfg =       (reg_clkcfg_t*)  (regbase + REG_BASE_CLKCFG);
+	reg->mem_cfg =       (reg_memcfg_t*)  (regbase + REG_BASE_MEMCFG);
+	reg->panel_cfg =     (reg_panelcfg_t*)(regbase + REG_BASE_PANELCFG);
+	reg->lcd_cfg =       (reg_dispcfg_t*) (regbase + REG_BASE_LCD_DISPCFG);
+	reg->crttv_cfg =     (reg_dispcfg_t*) (regbase + REG_BASE_CRTTV_DISPCFG);
+	reg->lcd_mode =      (reg_dispmode_t*)(regbase + REG_BASE_LCD_DISPMODE);
+	reg->crttv_mode =    (reg_dispmode_t*)(regbase + REG_BASE_CRTTV_DISPMODE);
+	reg->lcd_inkcurs =   (reg_inkcurs_t*) (regbase + REG_BASE_LCD_INKCURS);
+	reg->crttv_inkcurs = (reg_inkcurs_t*) (regbase + REG_BASE_CRTTV_INKCURS);
+	reg->bitblt =        (reg_bitblt_t*)  (regbase + REG_BASE_BITBLT);
+	reg->lut =           (reg_lut_t*)     (regbase + REG_BASE_LUT);
+	reg->pwr_save =      (reg_pwrsave_t*) (regbase + REG_BASE_PWRSAVE);
+	reg->misc =          (reg_misc_t*)    (regbase + REG_BASE_MISC);
+	reg->mediaplug =     (reg_mediaplug_t*)(regbase + REG_BASE_MEDIAPLUG);
+	reg->bitblt_data =   (u16*)           (regbase + REG_BASE_BITBLT_DATA);
+    
+	// Enable all register access
+	writeb(0, &reg->basic->misc);
+
+	rev_code = readb(&reg->basic->rev_code);
+	if ((rev_code >> 2) == 0x04) {
+		printk("Found EPSON1356 Display Controller\n");
+	}
+	else if ((rev_code >> 2) == 0x07) {
+		printk("Found EPSON13806 Display Controller\n");
+	}
+	else {
+		iounmap(fb_info.regbase_virt);
+		printk("e1356/806fb: %s not found, rev_code=0x%02x.\n",
+		       name, rev_code);
+		return -ENODEV;
+	}
+
+	fb_info.chip_rev = rev_code & 0x03;
+
+	// Determine frame-buffer size
+	switch (readb(&reg->md_cfg->md_cfg_stat0) >> 6) {
+	case 0:
+	case 2:
+		fb_info.fb_size = 0x80000;   /* 512K bytes */
+		break;
+	case 1:
+		if ((rev_code >> 2) == 7) /* 806 */
+			fb_info.fb_size = 0x140000;  /* 1.2M bytes */
+		else
+			fb_info.fb_size = 0x200000;  /* 2M bytes */
+		break;
+	default:
+		fb_info.fb_size = 0x200000;  /* 2M bytes */
+		break;
+	}
+
+	fb_info.membase_virt = ioremap_nocache(epfix->membase_phys,
+					       fb_info.fb_size);
+    
+	if (!fb_info.membase_virt) {
+		printk("e1356fb: Can't remap %s framebuffer.\n", name);
+		iounmap(fb_info.regbase_virt);
+		return -ENXIO;
+	}
+    
+	printk("e1356/806fb: Detected  %dKB framebuffer\n", 
+			(unsigned)fb_info.fb_size/1000);
+
+#ifdef CONFIG_MTRR
+	if (!epfix->nomtrr) {
+		fb_info.mtrr_idx = mtrr_add(epfix->membase_phys, fb_info.fb_size,
+					    MTRR_TYPE_WRCOMB, 1);
+		printk("e1356fb: MTRR's turned on\n");
+	}
+#endif
+    
+	if (!boot_fix.noaccel) {
+		/*
+		  Allocate a page for string BLTs. A 4K page is
+		  enough for a 256 character string at an 8x16 font.
+		*/
+		fb_info.putcs_buffer = (void*)__get_free_pages(GFP_KERNEL, 0);
+		if (fb_info.putcs_buffer == NULL) {
+			printk("e1356fb: Can't allocate putcs buffer\n");
+			goto unmap_ret_enxio;
+		}
+	}
+
+	// Begin SED1356 initialization
+
+	// disable display while initializing
+	writeb(0, &reg->misc->disp_mode);
+	// Set the GPIO1 and 2 to inputs
+	writeb(0, &reg->genio->gpio_cfg);
+	writeb(0, &reg->genio->gpio_ctrl);
+	if (fb_info.chip_rev == 7) /* 806 */
+		writeb(0, &reg->genio->gpio_ctrl2);
+
+	/*
+	 * Program the clocks
+	 */
+
+#ifdef CONFIG_MIPS_AU1000
+	if ((epfix->system == SYS_PB1000) || (epfix->system == SYS_PB1500))
+		epfix->busclk = get_au1000_lcd_clock();
+#endif
+	
+	if (epfix->busclk > 80000) {
+		printk("e1356fb: specified busclk too high\n");
+		goto ret_enxio;
+	}
+
+	epfix->mclk = mclk_cfg = 0;
+	if (epfix->system == SYS_PB1500) {
+		epfix->mclk = epfix->busclk;
+		mclk_cfg = 0x01;
+	}
+	else {
+		// Find the highest allowable MCLK
+		if (epfix->busclk <= MAX_PIXCLOCK && 
+				epfix->busclk > epfix->mclk) {
+			epfix->mclk = epfix->busclk;
+			mclk_cfg = 0x01;
+		}
+		if (epfix->clki <= MAX_PIXCLOCK && epfix->clki > epfix->mclk) {
+			epfix->mclk = epfix->clki;
+			mclk_cfg = 0x00;
+		}
+		if (epfix->busclk/2 <= MAX_PIXCLOCK && 
+				epfix->busclk/2 > epfix->mclk) {
+			epfix->mclk = epfix->busclk/2;
+			mclk_cfg = 0x11;
+		}
+		if (epfix->clki/2 <= MAX_PIXCLOCK && 
+				epfix->clki/2 > epfix->mclk) {
+			epfix->mclk = epfix->clki/2;
+			mclk_cfg = 0x10;
+		}
+	}
+	
+	if (!epfix->mclk) {
+		printk("e1356fb: couldn't find an allowable MCLK!\n");
+		goto ret_enxio;
+	}
+
+	// When changing mclk src, you must first set bit 4 to 1.
+	writeb(readb(&reg->clk_cfg->mem_clk_cfg) | 0x10,
+	       &reg->clk_cfg->mem_clk_cfg);
+	writeb(mclk_cfg, &reg->clk_cfg->mem_clk_cfg);
+
+	printk("e1356fb: clocks (kHz): busclk=%d mclk=%d clki=%d clki2=%d\n",
+	       epfix->busclk, epfix->mclk, epfix->clki, epfix->clki2);
+
+	// Set max pixel clock
+	switch (epfix->disp_type) {
+	case DISP_TYPE_LCD:
+	case DISP_TYPE_TFT:
+	case DISP_TYPE_CRT:
+		fb_info.max_pixclock = epfix->mclk;
+		break;
+	case DISP_TYPE_NTSC:
+	case DISP_TYPE_PAL:
+		fb_info.max_pixclock = (epfix->disp_type == DISP_TYPE_NTSC) ?
+			NTSC_PIXCLOCK : PAL_PIXCLOCK;
+		if (epfix->tv_filt & TV_FILT_FLICKER)
+			fb_info.max_pixclock *= 2;
+		break;
+	default:
+		printk("e1356fb: invalid specified display type\n");
+		goto ret_enxio;
+	}
+
+	periodMCLK = 1000000L / epfix->mclk;   // in nano-seconds
+	periodBCLK = 1000000L / epfix->busclk; // in nano-seconds
+	if (readb(&reg->md_cfg->md_cfg_stat1) & (1<<4))
+		periodBCLK *= 2;
+    
+	if ((epfix->system == SYS_PB1000) || (epfix->system == SYS_PB1500))
+		writeb(0x00, &reg->clk_cfg->cpu2mem_wait_sel);
+	else if (periodMCLK - 4 > periodBCLK)
+		writeb(0x02, &reg->clk_cfg->cpu2mem_wait_sel);
+	else if (2*periodMCLK - 4 > periodBCLK)
+		writeb(0x01, &reg->clk_cfg->cpu2mem_wait_sel);
+	else
+		writeb(0x00, &reg->clk_cfg->cpu2mem_wait_sel);
+
+	// Program memory config
+	if (epfix->mem_type < MEM_TYPE_EDO_2CAS ||
+	    epfix->mem_type > MEM_TYPE_EMBEDDED_SDRAM) {
+		printk("e1356fb: bad memory type specified\n");
+		goto ret_enxio;
+	}
+	writeb((u8)epfix->mem_type, &reg->mem_cfg->mem_cfg);
+
+	// calc closest refresh rate
+	rr_div = 7;
+	mclk_src = (mclk_cfg & 1) ? epfix->busclk : epfix->clki;
+	while ((mclk_src >> (6 + rr_div)) < epfix->mem_refresh)
+		if (--rr_div < 0) {
+			printk("e1356fb: can't set specified refresh rate\n");
+			goto ret_enxio;
+		}
+    
+	DPRINTK("refresh rate = %d kHz\n", (mclk_src >> (6 + rr_div)));
+
+	// add Suspend-Mode Refresh bits
+	if (epfix->mem_smr < MEM_SMR_CBR || epfix->mem_smr > MEM_SMR_NONE) {
+		printk("e1356fb: invalid specified suspend-mode refresh type\n");
+		goto ret_enxio;
+	}
+	writeb(rr_div | (epfix->mem_smr << 6), &reg->mem_cfg->dram_refresh);
+
+	// set DRAM speed
+	switch (epfix->mem_speed) {
+	case 50:
+		dram_timing = epfix->mclk >= 33000 ? 0x0101 : 0x0212;
+		break;
+	case 60:
+		if (epfix->mclk >= 30000)
+			dram_timing = 0x0101;
+		else if (epfix->mclk >= 25000)
+			dram_timing =
+				(epfix->mem_type == MEM_TYPE_EDO_2CAS ||
+				 epfix->mem_type == MEM_TYPE_EDO_2WE) ?
+				0x0212 : 0x0101;
+		else
+			dram_timing = 0x0212;
+		break;
+	case 70:
+		if (epfix->mclk >= 30000)
+			dram_timing = 0x0000;
+		else if (epfix->mclk >= 25000)
+			dram_timing = 0x0101;
+		else
+			dram_timing =
+				(epfix->mem_type == MEM_TYPE_EDO_2CAS ||
+				 epfix->mem_type == MEM_TYPE_EDO_2WE) ?
+				0x0212 : 0x0211;
+		break;
+	case 80:
+		if (epfix->mclk >= 25000)
+			dram_timing = 0x0100;
+		else
+			dram_timing = 0x0101;
+		break;
+	default:
+		printk("e1356fb: invalid specified memory speed\n");
+		goto ret_enxio;
+	}
+
+	writew(dram_timing, &reg->mem_cfg->dram_timings_ctrl0);
+    
+	currcon = -1;
+	if (!epfix->nohwcursor)
+		e1356fb_hwcursor_init(&fb_info);
+    
+	init_timer(&fb_info.cursor.timer);
+	fb_info.cursor.timer.function = do_flashcursor; 
+	fb_info.cursor.timer.data = (unsigned long)(&fb_info);
+	fb_info.cursor.state = CM_ERASE;
+	spin_lock_init(&fb_info.cursor.lock);
+    
+	strcpy(fb_info.fb_info.modename, "Epson "); 
+	strcat(fb_info.fb_info.modename, name);
+	fb_info.fb_info.changevar  = NULL;
+	fb_info.fb_info.node       = -1;
+
+	fb_info.fb_info.fbops      = &e1356fb_ops;
+	fb_info.fb_info.disp       = &fb_info.disp;
+	strcpy(fb_info.fb_info.fontname, epfix->fontname);
+	fb_info.fb_info.switch_con = &e1356fb_switch_con;
+	fb_info.fb_info.updatevar  = &e1356fb_updatevar;
+	fb_info.fb_info.blank      = &e1356fb_blank;
+	fb_info.fb_info.flags      = FBINFO_FLAG_DEFAULT;
+    
+	// Set-up display
+	// clear out unused stuff
+	writeb(0, &reg->panel_cfg->mod_rate);
+	writeb(0x01, &reg->lcd_mode->lcd_misc);
+	writeb(0, &reg->lcd_mode->fifo_high_thresh);
+	writeb(0, &reg->lcd_mode->fifo_low_thresh);
+	writeb(0, &reg->crttv_mode->fifo_high_thresh);
+	writeb(0, &reg->crttv_mode->fifo_low_thresh);
+    
+	switch (epfix->disp_type) {
+	case DISP_TYPE_LCD:
+		switch (epfix->panel_width) {
+		case 4: btmp = (u8)(((epfix->panel_el & 1)<<7) | 0x04); break;
+		case 8: btmp = (u8)(((epfix->panel_el & 1)<<7) | 0x14); break;
+		case 16: btmp = (u8)(((epfix->panel_el & 1)<<7) | 0x24); break;
+		default:
+			printk("e1356fb: invalid specified LCD panel data width\n");
+			goto ret_enxio;
+		}
+		writeb(btmp, &reg->panel_cfg->panel_type);
+		break;
+	case DISP_TYPE_TFT:
+		switch (epfix->panel_width) {
+		case 9: btmp = (u8)(((epfix->panel_el & 1)<<7) | 0x05); break;
+		case 12: btmp = (u8)(((epfix->panel_el & 1)<<7) | 0x15); break;
+		case 18: btmp = (u8)(((epfix->panel_el & 1)<<7) | 0x25); break;
+		default:
+			printk("e1356fb: invalid specified TFT panel data width\n");
+			goto ret_enxio;
+		}
+		writeb(btmp, &reg->panel_cfg->panel_type);
+		break;
+	case DISP_TYPE_CRT:
+		writeb(0x00, &reg->crttv_cfg->tv_output_ctrl);
+		break;
+	case DISP_TYPE_NTSC:
+	case DISP_TYPE_PAL:
+		if (epfix->tv_fmt < TV_FMT_COMPOSITE ||
+		    epfix->tv_fmt > TV_FMT_S_VIDEO) {
+			printk("e1356fb: invalid specified TV output format\n");
+			goto ret_enxio;
+		}
+		btmp = epfix->disp_type == DISP_TYPE_PAL ? 0x01 : 0x00;
+		btmp |= (epfix->tv_fmt == TV_FMT_S_VIDEO ? 0x02 : 0x00);
+		btmp |= ((epfix->tv_filt & TV_FILT_LUM) ? 0x10 : 0x00);
+		btmp |= ((epfix->tv_filt & TV_FILT_CHROM) ? 0x20 : 0x00);
+		writeb(btmp, &reg->crttv_cfg->tv_output_ctrl);
+		break;
+	}
+
+	memset(&var, 0, sizeof(var));
+	/*
+	 * If mode_option wasn't given at boot, assume all the boot
+	 * option timing parameters were specified individually, in
+	 * which case we convert par_to_var instead of calling
+	 * fb_find_mode.
+	 */
+	if (epfix->mode_option) {
+		struct fb_videomode* modedb, *dm;
+		int dbsize = e1356fb_get_mode(&fb_info, 640, 480, &modedb, &dm);
+
+		// first try the generic modedb
+		if (!fb_find_mode(&var, &fb_info.fb_info, epfix->mode_option,
+				  NULL, 0, NULL, boot_par.bpp)) {
+			printk("e1356fb: mode %s failed, trying e1356 modedb\n",
+			       epfix->mode_option);
+			// didn't work in generic modedb, try ours
+			if (!fb_find_mode(&var, &fb_info.fb_info,
+					  epfix->mode_option,
+					  modedb, dbsize, dm, boot_par.bpp)) {
+				printk("e1356fb: mode %s failed e1356 modedb too, sorry\n",
+				       epfix->mode_option);
+				
+				goto ret_enxio;
+			}
+		}
+
+		var.xres_virtual = boot_par.width_virt ?
+			boot_par.width_virt : boot_par.width;
+		var.yres_virtual = boot_par.height_virt ?
+			boot_par.height_virt : boot_par.height;
+	} else {
+		if (e1356fb_par_to_var(&var, &fb_info.default_par, &fb_info)) {
+			printk("e1356fb: boot option mode failed\n");
+			goto ret_enxio;
+		}
+	}
+    
+	if (boot_fix.noaccel)
+		var.accel_flags &= ~FB_ACCELF_TEXT;
+	else
+		var.accel_flags |= FB_ACCELF_TEXT;
+    
+	if (e1356fb_var_to_par(&var, &fb_info.default_par, &fb_info)) {
+		/*
+		 * Can't use the mode from the mode db or the default
+		 * mode or the boot options - give up
+		 */
+		printk("e1356fb: mode failed var_to_par\n");
+		goto ret_enxio;
+	}
+    
+	fb_info.disp.screen_base    = fb_info.membase_virt;
+	fb_info.disp.var            = var; // struct copy
+    
+	// here's where the screen is actually initialized and enabled
+	if (e1356fb_set_var(&var, -1, &fb_info.fb_info)) {
+		printk("e1356fb: can't set video mode\n");
+		goto ret_enxio;
+	}
+    
+	writeb(0, &reg->pwr_save->cfg);     // disable power-save mode
+	writeb(0, &reg->misc->cpu2mem_watchdog); // disable watchdog timer
+
+#ifdef E1356FB_VERBOSE_DEBUG
+	dump_fb(fb_info.membase_virt + 0x100000, 512);
+#endif
+
+	if (register_framebuffer(&fb_info.fb_info) < 0) {
+		writeb(0, &reg->misc->disp_mode); 
+		printk("e1356fb: can't register framebuffer\n");
+		goto ret_enxio;
+	}
+    
+	printk("fb%d: %s frame buffer device\n", 
+	       GET_FB_IDX(fb_info.fb_info.node),
+	       fb_info.fb_info.modename);
+    
+    
+	return 0;
+
+ ret_enxio:
+	free_pages((unsigned long)fb_info.putcs_buffer, 0);
+ unmap_ret_enxio:
+	iounmap(fb_info.regbase_virt);
+	iounmap(fb_info.membase_virt);
+	return -ENXIO;
+}
+
+/**
+ *	e1356fb_exit - Driver cleanup
+ *
+ *	Releases all resources allocated during the
+ *	course of the driver's lifetime.
+ *
+ *	FIXME - do results of fb_alloc_cmap need disposal?
+ */
+static void __exit
+e1356fb_exit (void)
+{
+	unregister_framebuffer(&fb_info.fb_info);
+	del_timer_sync(&fb_info.cursor.timer);
+
+#ifdef CONFIG_MTRR
+	if (!fb_info.fix.nomtrr) {
+		mtrr_del(fb_info.mtrr_idx, fb_info.fix.membase_phys,
+			 fb_info.fb_size);
+		printk("fb: MTRR's  turned off\n");
+	}
+#endif
+
+	free_pages((unsigned long)fb_info.putcs_buffer, 0);
+	iounmap(fb_info.regbase_virt);
+	iounmap(fb_info.membase_virt);
+}
+
+MODULE_AUTHOR("Steve Longerbeam <stevel@mvista.com>");
+MODULE_DESCRIPTION("SED1356 framebuffer device driver");
+
+#ifdef MODULE
+module_init(e1356fb_init);
+#endif
+module_exit(e1356fb_exit);
+
+
+void
+e1356fb_setup(char *options, int *ints)
+{
+	char* this_opt;
+    
+	memset(&boot_fix, 0, sizeof(struct e1356fb_fix));
+	memset(&boot_par, 0, sizeof(struct e1356fb_par));
+	boot_fix.system = -1;
+    
+	if (!options || !*options)
+		return;
+    
+	for(this_opt=strtok(options, ","); this_opt;
+	    this_opt=strtok(NULL, ",")) {
+		if (!strncmp(this_opt, "noaccel", 7)) {
+			boot_fix.noaccel = 1;
+		} else if (!strncmp(this_opt, "nopan", 5)) {
+			boot_fix.nopan = 1;
+		} else if (!strncmp(this_opt, "nohwcursor", 10)) {
+			boot_fix.nohwcursor = 1;
+		} else if (!strncmp(this_opt, "mmunalign:", 10)) {
+			boot_fix.mmunalign = simple_strtoul(this_opt+10,
+							    NULL, 0);
+#ifdef CONFIG_MTRR
+		} else if (!strncmp(this_opt, "nomtrr", 6)) {
+			boot_fix.nomtrr = 1;
+#endif
+		} else if (!strncmp(this_opt, "font:", 5)) {
+			strncpy(boot_fix.fontname, this_opt+5,
+				sizeof(boot_fix.fontname)-1);
+		} else if (!strncmp(this_opt, "regbase:", 8)) {
+			boot_fix.regbase_phys = simple_strtoul(this_opt+8,
+							       NULL, 0);
+		} else if (!strncmp(this_opt, "membase:", 8)) {
+			boot_fix.membase_phys = simple_strtoul(this_opt+8,
+							       NULL, 0);
+		} else if (!strncmp(this_opt, "memsp:", 6)) {
+			boot_fix.mem_speed = simple_strtoul(this_opt+6,
+							    NULL, 0);
+		} else if (!strncmp(this_opt, "memtyp:", 7)) {
+			boot_fix.mem_type = simple_strtoul(this_opt+7,
+							   NULL, 0);
+		} else if (!strncmp(this_opt, "memref:", 7)) {
+			boot_fix.mem_refresh = simple_strtoul(this_opt+7,
+							      NULL, 0);
+		} else if (!strncmp(this_opt, "memsmr:", 7)) {
+			boot_fix.mem_smr = simple_strtoul(this_opt+7, NULL, 0);
+		} else if (!strncmp(this_opt, "busclk:", 7)) {
+			boot_fix.busclk = simple_strtoul(this_opt+7, NULL, 0);
+		} else if (!strncmp(this_opt, "clki:", 5)) {
+			boot_fix.clki = simple_strtoul(this_opt+5, NULL, 0);
+		} else if (!strncmp(this_opt, "clki2:", 6)) {
+			boot_fix.clki2 = simple_strtoul(this_opt+6, NULL, 0);
+		} else if (!strncmp(this_opt, "display:", 8)) {
+			if (!strncmp(this_opt+8, "lcd", 3))
+				boot_fix.disp_type = DISP_TYPE_LCD;
+			else if (!strncmp(this_opt+8, "tft", 3))
+				boot_fix.disp_type = DISP_TYPE_TFT;
+			else if (!strncmp(this_opt+8, "crt", 3))
+				boot_fix.disp_type = DISP_TYPE_CRT;
+			else if (!strncmp(this_opt+8, "pal", 3))
+				boot_fix.disp_type = DISP_TYPE_PAL;
+			else if (!strncmp(this_opt+8, "ntsc", 4))
+				boot_fix.disp_type = DISP_TYPE_NTSC;
+		} else if (!strncmp(this_opt, "width:", 6)) {
+			boot_par.width = simple_strtoul(this_opt+6, NULL, 0);
+		} else if (!strncmp(this_opt, "height:", 7)) {
+			boot_par.height = simple_strtoul(this_opt+7, NULL, 0);
+		} else if (!strncmp(this_opt, "bpp:", 4)) {
+			boot_par.bpp = simple_strtoul(this_opt+4, NULL, 0);
+			boot_par.cmap_len = (boot_par.bpp == 8) ? 256 : 16;
+		} else if (!strncmp(this_opt, "elpanel:", 8)) {
+			boot_fix.panel_el = simple_strtoul(this_opt+8,
+							   NULL, 0);
+		} else if (!strncmp(this_opt, "pdataw:", 7)) {
+			boot_fix.panel_width = simple_strtoul(this_opt+7,
+							      NULL, 0);
+		} else if (!strncmp(this_opt, "hndp:", 5)) {
+			boot_par.horiz_ndp = simple_strtoul(this_opt+5,
+							    NULL, 0);
+		} else if (!strncmp(this_opt, "vndp:", 5)) {
+			boot_par.vert_ndp = simple_strtoul(this_opt+5,
+							   NULL, 0);
+		} else if (!strncmp(this_opt, "hspol:", 6)) {
+			boot_par.hsync_pol = simple_strtoul(this_opt+6,
+							    NULL, 0);
+		} else if (!strncmp(this_opt, "vspol:", 6)) {
+			boot_par.vsync_pol = simple_strtoul(this_opt+6,
+							    NULL, 0);
+		} else if (!strncmp(this_opt, "hsstart:", 8)) {
+			boot_par.hsync_start = simple_strtoul(this_opt+8,
+							      NULL, 0);
+		} else if (!strncmp(this_opt, "hswidth:", 8)) {
+			boot_par.hsync_width = simple_strtoul(this_opt+8,
+							      NULL, 0);
+		} else if (!strncmp(this_opt, "vsstart:", 8)) {
+			boot_par.vsync_start = simple_strtoul(this_opt+8,
+							      NULL, 0);
+		} else if (!strncmp(this_opt, "vswidth:", 8)) {
+			boot_par.vsync_width = simple_strtoul(this_opt+8,
+							      NULL, 0);
+		} else if (!strncmp(this_opt, "tvfilt:", 7)) {
+			boot_fix.tv_filt = simple_strtoul(this_opt+7, NULL, 0);
+		} else if (!strncmp(this_opt, "tvfmt:", 6)) {
+			boot_fix.tv_fmt = simple_strtoul(this_opt+6, NULL, 0);
+		} else if (!strncmp(this_opt, "system:", 7)) {
+			if (!strncmp(this_opt+7, "pb1000", 10)) {
+				boot_fix = systems[SYS_PB1000].fix;
+				boot_par = systems[SYS_PB1000].par;
+			} else if (!strncmp(this_opt+7, "pb1500", 7)) {
+				boot_fix = systems[SYS_PB1500].fix;
+				boot_par = systems[SYS_PB1500].par;
+			} else if (!strncmp(this_opt+7, "sdu1356", 7)) {
+				boot_fix = systems[SYS_SDU1356].fix;
+				boot_par = systems[SYS_SDU1356].par;
+			} else if (!strncmp(this_opt+7, "clio1050", 7)) {
+				boot_fix = systems[SYS_CLIO1050].fix;
+				boot_par = systems[SYS_CLIO1050].par;
+			}
+		} else {
+			boot_fix.mode_option = this_opt;
+		}
+	} 
+}
+
+
+/*
+ * FIXME: switching consoles could be dangerous. What if switching
+ * from a panel to a CRT/TV, or vice versa? More needs to be
+ * done here.
+ */
+static int
+e1356fb_switch_con(int con, struct fb_info *fb)
+{
+	struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
+	struct e1356fb_par par;
+	int old_con = currcon;
+	int set_par = 1;
+
+	//DPRINTK("\n");
+
+	/* Do we have to save the colormap? */
+	if (currcon>=0)
+		if (fb_display[currcon].cmap.len)
+			fb_get_cmap(&fb_display[currcon].cmap, 1,
+				    e1356fb_getcolreg, fb);
+   
+	currcon = con;
+	fb_display[currcon].var.activate = FB_ACTIVATE_NOW; 
+	e1356fb_var_to_par(&fb_display[con].var, &par, info);
+	if (old_con>=0 && vt_cons[old_con]->vc_mode!=KD_GRAPHICS) {
+		/* check if we have to change video registers */
+		struct e1356fb_par old_par;
+		e1356fb_var_to_par(&fb_display[old_con].var, &old_par, info);
+		if (!memcmp(&par,&old_par,sizeof(par)))
+			set_par = 0;	/* avoid flicker */
+	}
+	if (set_par)
+		e1356fb_set_par(&par, info);
+    
+	if (fb_display[con].dispsw && fb_display[con].conp)
+		fb_con.con_cursor(fb_display[con].conp, CM_ERASE);
+   
+	del_timer(&(info->cursor.timer));
+	fb_info.cursor.state=CM_ERASE; 
+   
+	if (!info->fix.nohwcursor) 
+		if (fb_display[con].conp)
+			e1356fb_createcursor( &fb_display[con] );
+   
+	info->cursor.redraw=1;
+   
+	e1356fb_set_dispsw(&fb_display[con], 
+			   info, 
+			   par.bpp,
+			   fb_display[con].var.accel_flags & FB_ACCELF_TEXT);
+   
+	e1356fb_install_cmap(&fb_display[con], fb);
+	e1356fb_updatevar(con, fb);
+   
+	return 1;
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+static void
+e1356fb_blank(int blank, struct fb_info *fb)
+{
+	struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
+	reg_dispmode_t* dispmode = (IS_PANEL(info->fix.disp_type)) ?
+		info->reg.lcd_mode : info->reg.crttv_mode;
+	reg_pwrsave_t* pwrsave = info->reg.pwr_save;
+
+	//DPRINTK("\n");
+
+	switch (blank) {
+	case 0:
+		// Get out of power save mode
+		writeb(0x00, &pwrsave->cfg);
+		writeb(readb(&dispmode->disp_mode) & ~0x80,
+		       &dispmode->disp_mode);
+		break;
+	case 1:
+		// Get out of power save mode
+		writeb(0x00, &pwrsave->cfg);
+		writeb(readb(&dispmode->disp_mode) | 0x80,
+		       &dispmode->disp_mode);
+		break;
+		// No support for turning off horiz or vert sync, so just treat
+		// it as a power off.
+	case 2:
+	case 3:
+	case 4:
+		writeb(0x01, &pwrsave->cfg);
+		break;
+	}
+}
+
+
+static int
+e1356fb_updatevar(int con, struct fb_info* fb)
+{
+	struct fb_info_e1356* i = (struct fb_info_e1356*)fb;
+
+	//DPRINTK("\n");
+
+	if ((con==currcon) && (!i->fix.nopan)) 
+		do_pan_var(&fb_display[con].var,i);
+	return 0;
+}
+
+static int
+e1356fb_getcolreg(unsigned        regno, 
+		  unsigned*       red, 
+		  unsigned*       green,
+		  unsigned*       blue, 
+		  unsigned*       transp,
+		  struct fb_info* fb)
+{
+	struct fb_info_e1356* i = (struct fb_info_e1356*)fb;
+
+	if (regno > i->current_par.cmap_len)
+		return 1;
+   
+	*red    = i->palette[regno].red; 
+	*green  = i->palette[regno].green; 
+	*blue   = i->palette[regno].blue; 
+	*transp = 0;
+   
+	return 0;
+}
+
+static int
+e1356fb_setcolreg(unsigned        regno, 
+		  unsigned        red, 
+		  unsigned        green,
+		  unsigned        blue, 
+		  unsigned        transp,
+		  struct fb_info* info)
+{
+	struct fb_info_e1356* i = (struct fb_info_e1356*)info;
+
+	if (regno > 255)
+		return 1;
+
+	i->palette[regno].red    = red;
+	i->palette[regno].green  = green;
+	i->palette[regno].blue   = blue;
+   
+	switch(i->current_par.bpp) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		do_setpalentry(i->reg.lut, regno,
+			       (u8)(red>>8), (u8)(green>>8), (u8)(blue>>8));
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		i->fbcon_cmap16[regno] = (regno << 10) | (regno << 5) | regno;
+		break;
+#endif
+	default:
+		DPRINTK("bad depth %u\n", i->current_par.bpp);
+		break;
+	}
+	return 0;
+}
+
+static void
+e1356fb_install_cmap(struct display *d, struct fb_info *info) 
+{
+	struct fb_info_e1356* i = (struct fb_info_e1356*)info;
+
+	//DPRINTK("\n");
+
+	if (d->cmap.len) {
+		fb_set_cmap(&(d->cmap), 1, e1356fb_setcolreg, info);
+	} else {
+		fb_set_cmap(fb_default_cmap(i->current_par.cmap_len), 1,
+			    e1356fb_setcolreg, info);
+	}
+}
+
+static void
+e1356fb_createcursorshape(struct display* p) 
+{
+	int h,u;
+   
+	h = fontheight(p);
+
+	fb_info.cursor.type = p->conp->vc_cursor_type & CUR_HWMASK;
+
+	switch (fb_info.cursor.type) {
+	case CUR_NONE: 
+		u = h; 
+		break;
+	case CUR_UNDERLINE: 
+		u = h - 2; 
+		break;
+	case CUR_LOWER_THIRD: 
+		u = (h * 2) / 3; 
+		break;
+	case CUR_LOWER_HALF: 
+		u = h / 2; 
+		break;
+	case CUR_TWO_THIRDS: 
+		u = h / 3; 
+		break;
+	case CUR_BLOCK:
+	default:
+		u = 0;
+		break;
+	}
+    
+	fb_info.cursor.w = fontwidth_x8(p);
+	fb_info.cursor.u = u;
+	fb_info.cursor.h = h;
+}
+   
+static void
+e1356fb_createcursor(struct display *p)
+{
+	void* memcursor;
+	int y, w, h, u;
+    
+	e1356fb_createcursorshape(p);
+
+	h = fb_info.cursor.h;
+	w = fb_info.cursor.w;
+	u = fb_info.cursor.u;
+	memcursor = fb_info.membase_virt + fb_info.fb_size;
+
+	// write cursor to display memory
+	for (y=0; y<64; y++) {
+		if (y >= h || y < u) {
+			fbfill((u16*)memcursor, 0xaa, 16); // b/g
+		} else {
+			fbfill((u16*)memcursor, 0xff, w/4); // inverted b/g
+			fbfill((u16*)memcursor + w/4, 0xaa, (64 - w)/4); // b/g
+		}
+		memcursor += 16;
+	}
+}
+   
+static void
+e1356fb_hwcursor_init(struct fb_info_e1356* info)
+{
+	reg_inkcurs_t* inkcurs = (IS_PANEL(info->fix.disp_type)) ?
+		info->reg.lcd_inkcurs : info->reg.crttv_inkcurs;
+
+	fb_info.fb_size -= 1024;
+	// program cursor base address
+	writeb(0x00, &inkcurs->start_addr);
+	printk("e1356fb: reserving 1024 bytes for the hwcursor at %p\n",
+	       fb_info.membase_virt + fb_info.fb_size);
+}
+
+#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
+
+/*
+ * Return indicates whether a page was freed so caller can adjust rss
+ */
+static inline void forget_pte(pte_t page)
+{
+	if (!pte_none(page)) {
+		printk("forget_pte: old mapping existed!\n");
+		BUG();
+	}
+}
+
+/*
+ * maps a range of physical memory into the requested pages. the old
+ * mappings are removed. any references to nonexistent pages results
+ * in null mappings (currently treated as "copy-on-access")
+ */
+static inline void e1356_remap_pte_range(pte_t * pte, unsigned long address, unsigned long size,
+	phys_t phys_addr, pgprot_t prot)
+{
+	unsigned long end;
+
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	do {
+		struct page *page;
+		pte_t oldpage;
+		oldpage = ptep_get_and_clear(pte);
+
+		page = virt_to_page(__va(phys_addr));
+		if ((!VALID_PAGE(page)) || PageReserved(page))
+ 			set_pte(pte, mk_pte_phys(phys_addr, prot));
+		forget_pte(oldpage);
+		address += PAGE_SIZE;
+		phys_addr += PAGE_SIZE;
+		pte++;
+	} while (address && (address < end));
+}
+
+static inline int e1356_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
+	phys_t phys_addr, pgprot_t prot)
+{
+	unsigned long end;
+
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	phys_addr -= address;
+	do {
+		pte_t * pte = pte_alloc(mm, pmd, address);
+		if (!pte)
+			return -ENOMEM;
+		e1356_remap_pte_range(pte, address, end - address, address + phys_addr, prot);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address && (address < end));
+	return 0;
+}
+
+/*  Note: this is only safe if the mm semaphore is held when called. */
+static int e1356_remap_page_range(unsigned long from, phys_t phys_addr, unsigned long size, pgprot_t prot)
+{
+	int error = 0;
+	pgd_t * dir;
+	phys_t beg = from;
+	phys_t end = from + size;
+	struct mm_struct *mm = current->mm;
+
+	phys_addr -= from;
+	dir = pgd_offset(mm, from);
+	flush_cache_range(mm, beg, end);
+	if (from >= end)
+		BUG();
+
+	spin_lock(&mm->page_table_lock);
+	do {
+		pmd_t *pmd = pmd_alloc(mm, dir, from);
+		error = -ENOMEM;
+		if (!pmd)
+			break;
+		error = e1356_remap_pmd_range(mm, pmd, from, end - from, phys_addr + from, prot);
+		if (error)
+			break;
+		from = (from + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	} while (from && (from < end));
+	spin_unlock(&mm->page_table_lock);
+	flush_tlb_range(mm, beg, end);
+	return error;
+}
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/epson1356fb.h linux-2.4.20/drivers/video/epson1356fb.h
--- linux-2.4.19/drivers/video/epson1356fb.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/video/epson1356fb.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,646 @@
+/*
+ *      epson1356fb.h  --  Epson SED1356 Framebuffer Driver
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	stevel@mvista.com or source@mvista.com
+ *
+ *  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.
+ */
+
+#ifdef E1356FB_DEBUG
+#define DPRINTK(a,b...) printk(KERN_DEBUG "e1356fb: %s: " a, __FUNCTION__ , ## b)
+#else
+#define DPRINTK(a,b...)
+#endif 
+
+#define E1356_REG_SIZE  0x200000
+
+#define PICOS2KHZ(a) (1000000000UL/(a))
+#define KHZ2PICOS(a) (1000000000UL/(a))
+
+#define MAX_PIXCLOCK  40000 // KHz
+#define NTSC_PIXCLOCK 14318 // KHz
+#define PAL_PIXCLOCK  17734 // KHz
+
+/*
+ * Maximum percent errors between desired pixel clock and
+ * supported pixel clock. Lower-than and higher-than desired
+ * clock percent errors.
+ */
+#define MAX_PCLK_ERROR_LOWER  10
+#define MAX_PCLK_ERROR_HIGHER -1
+
+#define fontwidth_x8(p) (((fontwidth(p) + 7) >> 3) << 3)
+
+/*
+ * Register Structures
+ */
+
+// Basic
+#define REG_BASE_BASIC     0x00
+typedef struct {
+	u8 rev_code;           // 00
+	u8 misc;               // 01
+} reg_basic_t;
+
+// General IO Pins
+#define REG_BASE_GENIO     0x04
+typedef struct {
+	u8 gpio_cfg;           // 04
+	u8 gpio_cfg2;          // 05 SED13806
+	u8 spacer[2];          // 06
+	u8 gpio_ctrl;          // 08
+	u8 gpio_ctrl2;         // 09 SED13806
+} reg_genio_t;
+
+// MD Config Readback
+#define REG_BASE_MDCFG     0x0c
+typedef struct {
+	u8 md_cfg_stat0;       // 0C
+	u8 md_cfg_stat1;       // 0D
+} reg_mdcfg_t;
+
+// Clock Config
+#define REG_BASE_CLKCFG    0x10
+typedef struct {
+	u8 mem_clk_cfg;        // 10
+	u8 spacer1[3];         // 11
+	u8 lcd_pclk_cfg;       // 14
+	u8 spacer2[3];         // 15
+	u8 crttv_pclk_cfg;     // 18
+	u8 spacer3[3];         // 19
+	u8 mpclk_cfg;          // 1C
+	u8 spacer4;            // 1D
+	u8 cpu2mem_wait_sel;   // 1E
+} reg_clkcfg_t;
+
+// Memory Config
+#define REG_BASE_MEMCFG    0x20
+typedef struct {
+	u8 mem_cfg;            // 20
+	u8 dram_refresh;       // 21
+	u8 spacer[8];          // 22
+	u8 dram_timings_ctrl0; // 2A
+	u8 dram_timings_ctrl1; // 2B
+} reg_memcfg_t;
+
+// Panel Config
+#define REG_BASE_PANELCFG  0x30
+typedef struct {
+	u8 panel_type;         // 30
+	u8 mod_rate;           // 31
+} reg_panelcfg_t;
+
+// LCD and CRTTV Display Config
+#define REG_BASE_LCD_DISPCFG   0x32
+#define REG_BASE_CRTTV_DISPCFG 0x50
+typedef struct {
+	u8 hdw;                // 32 or 50
+	u8 spacer1;            // 33 or 51
+	u8 hndp;               // 34 or 52
+	u8 hsync_start;        // 35 or 53
+	u8 hsync_pulse;        // 36 or 54
+	u8 spacer2;            // 37 or 55
+	u8 vdh0;               // 38 or 56
+	u8 vdh1;               // 39 or 57
+	u8 vndp;               // 3A or 58
+	u8 vsync_start;        // 3B or 59
+	u8 vsync_pulse;        // 3C or 5A
+	u8 tv_output_ctrl;     // 5B (TV only)
+} reg_dispcfg_t;
+
+// LCD and CRTTV Display Mode
+#define REG_BASE_LCD_DISPMODE   0x40
+#define REG_BASE_CRTTV_DISPMODE 0x60
+typedef struct {
+	u8 disp_mode;          // 40 or 60
+	u8 lcd_misc;           // 41 (LCD only)
+	u8 start_addr0;        // 42 or 62
+	u8 start_addr1;        // 43 or 63
+	u8 start_addr2;        // 44 or 64
+	u8 spacer1;            // 45 or 65
+	u8 mem_addr_offset0;   // 46 or 66
+	u8 mem_addr_offset1;   // 47 or 67
+	u8 pixel_panning;      // 48 or 68
+	u8 spacer2;            // 49 or 69
+	u8 fifo_high_thresh;   // 4A or 6A
+	u8 fifo_low_thresh;    // 4B or 6B
+} reg_dispmode_t;
+
+// LCD and CRTTV Ink/Cursor
+#define REG_BASE_LCD_INKCURS   0x70
+#define REG_BASE_CRTTV_INKCURS 0x80
+typedef struct {
+	u8 ctrl;               // 70 or 80
+	u8 start_addr;         // 71 or 81
+	u8 x_pos0;             // 72 or 82
+	u8 x_pos1;             // 73 or 83
+	u8 y_pos0;             // 74 or 84
+	u8 y_pos1;             // 75 or 85
+	u8 blue0;              // 76 or 86
+	u8 green0;             // 77 or 87
+	u8 red0;               // 78 or 88
+	u8 spacer1;            // 79 or 89
+	u8 blue1;              // 7A or 8A
+	u8 green1;             // 7B or 8B
+	u8 red1;               // 7C or 8C
+	u8 spacer2;            // 7D or 8D
+	u8 fifo;               // 7E or 8E
+} reg_inkcurs_t;
+
+// BitBlt Config
+#define REG_BASE_BITBLT        0x100
+typedef struct {
+	u8 ctrl0;              // 100
+	u8 ctrl1;              // 101
+	u8 rop_code;           // 102
+	u8 operation;          // 103
+	u8 src_start_addr0;    // 104
+	u8 src_start_addr1;    // 105
+	u8 src_start_addr2;    // 106
+	u8 spacer1;            // 107
+	u8 dest_start_addr0;   // 108
+	u8 dest_start_addr1;   // 109
+	u8 dest_start_addr2;   // 10A
+	u8 spacer2;            // 10B
+	u8 mem_addr_offset0;   // 10C
+	u8 mem_addr_offset1;   // 10D
+	u8 spacer3[2];         // 10E
+	u8 width0;             // 110
+	u8 width1;             // 111
+	u8 height0;            // 112
+	u8 height1;            // 113
+	u8 bg_color0;          // 114
+	u8 bg_color1;          // 115
+	u8 spacer4[2];         // 116
+	u8 fg_color0;          // 118
+	u8 fg_color1;          // 119
+} reg_bitblt_t;
+
+// LUT
+#define REG_BASE_LUT           0x1e0
+typedef struct {
+	u8 mode;               // 1E0
+	u8 spacer1;            // 1E1
+	u8 addr;               // 1E2
+	u8 spacer2;            // 1E3
+	u8 data;               // 1E4
+} reg_lut_t;
+
+// Power Save Config
+#define REG_BASE_PWRSAVE       0x1f0
+typedef struct {
+	u8 cfg;                // 1F0
+	u8 status;             // 1F1
+} reg_pwrsave_t;
+
+// Misc
+#define REG_BASE_MISC          0x1f4
+typedef struct {
+	u8 cpu2mem_watchdog;   // 1F4
+	u8 spacer[7];          // 1F5
+	u8 disp_mode;          // 1FC
+} reg_misc_t;
+
+// MediaPlug
+#define REG_BASE_MEDIAPLUG     0x1000
+typedef struct {
+	u8 lcmd;               // 1000
+	u8 spacer1;            // 1001
+	u8 reserved_lcmd;      // 1002
+	u8 spacer2;            // 1003
+	u8 cmd;                // 1004
+	u8 spacer3;            // 1005
+	u8 reserved_cmd;       // 1006
+	u8 spacer4;            // 1007
+	u8 data;               // 1008
+} reg_mediaplug_t;
+
+// BitBlt data register. 16-bit access only
+#define REG_BASE_BITBLT_DATA   0x100000
+
+typedef struct {
+	reg_basic_t* basic;
+	reg_genio_t* genio;
+	reg_mdcfg_t* md_cfg;
+	reg_clkcfg_t* clk_cfg;
+	reg_memcfg_t* mem_cfg;
+	reg_panelcfg_t* panel_cfg;
+	reg_dispcfg_t* lcd_cfg;
+	reg_dispcfg_t* crttv_cfg;
+	reg_dispmode_t* lcd_mode;
+	reg_dispmode_t* crttv_mode;
+	reg_inkcurs_t* lcd_inkcurs;
+	reg_inkcurs_t* crttv_inkcurs;
+	reg_bitblt_t* bitblt;
+	reg_lut_t* lut;
+	reg_pwrsave_t* pwr_save;
+	reg_misc_t* misc;
+	reg_mediaplug_t* mediaplug;
+	u16* bitblt_data;
+} e1356_reg_t;
+
+
+/*--------------------------------------------------------*/
+
+enum mem_type_t {
+	MEM_TYPE_EDO_2CAS = 0,
+	MEM_TYPE_FPM_2CAS,
+	MEM_TYPE_EDO_2WE,
+	MEM_TYPE_FPM_2WE,
+	MEM_TYPE_EMBEDDED_SDRAM = 0x80
+};
+
+enum mem_smr_t {
+	MEM_SMR_CBR = 0,
+	MEM_SMR_SELF,
+	MEM_SMR_NONE
+};
+
+enum disp_type_t {
+	DISP_TYPE_LCD = 0,
+	DISP_TYPE_TFT,
+	DISP_TYPE_CRT,
+	DISP_TYPE_PAL,
+	DISP_TYPE_NTSC
+};
+
+/*
+ * Maximum timing values, as determined by the SED1356 register
+ * field sizes. All are indexed by display type, except
+ * max_hsync_start which is first indexed by color depth,
+ * then by display type.
+ */
+static const int max_hndp[5] = {256, 256, 512, 511, 510};
+static const int max_hsync_start[2][5] = {
+	{0, 252, 507, 505, 505}, // 8 bpp
+	{0, 254, 509, 507, 507}  // 16 bpp
+};
+static const int max_hsync_width[5] = {0, 128, 128, 0, 0};
+static const int max_vndp[5] = {64, 64, 128, 128, 128};
+static const int max_vsync_start[5] = {0, 64, 128, 128, 128};
+static const int max_vsync_width[5] = {0, 8, 8, 0, 0};
+
+#define IS_PANEL(disp_type) \
+    (disp_type == DISP_TYPE_LCD || disp_type == DISP_TYPE_TFT)
+#define IS_CRT(disp_type) (disp_type == DISP_TYPE_CRT)
+#define IS_TV(disp_type) \
+    (disp_type == DISP_TYPE_NTSC || disp_type == DISP_TYPE_PAL)
+
+
+enum tv_filters_t {
+	TV_FILT_LUM = 1,
+	TV_FILT_CHROM = 2,
+	TV_FILT_FLICKER = 4
+};
+
+enum tv_format_t {
+	TV_FMT_COMPOSITE = 0,
+	TV_FMT_S_VIDEO
+};
+
+
+struct e1356fb_fix {
+	int system;       // the number of a pre-packaged system
+	u64 regbase_phys; // phys start address of registers
+	u64 membase_phys; // phys start address of fb memory
+
+	// Memory parameters
+	int mem_speed;    // speed: 50, 60, 70, or 80 (nsec)
+	int mem_type;     // mem type: EDO-2CAS, FPM-2CAS, EDO-2WE, FPM-2WE
+	int mem_refresh;  // refresh rate in KHz
+	int mem_smr;      // suspend mode refresh: CAS_BEFORE_RAS, SELF, or NONE
+	// Clocks
+	int busclk;       // BUSCLK frequency, in KHz
+	int mclk;         // MCLK freq, in KHz, will either be BUSCLK or BUSCLK/2
+	int clki;         // CLKI frequency, in KHz
+	int clki2;        // CLKI2 frequency, in KHz
+
+	int disp_type;    // LCD, TFT, CRT, PAL, or NTSC
+
+	// TV Options
+	u8  tv_filt;      // TV Filter mask, LUM, CHROM, and FLICKER
+	int tv_fmt;       // TV output format, COMPOSITE or S_VIDEO
+    
+	// Panel (LCD,TFT) Options
+	int panel_el;     // enable support for EL-type panels
+	int panel_width;  // Panel data width: LCD: 4/8/16, TFT: 9/12/18
+    
+	// Misc
+	int noaccel;
+	int nopan;
+#ifdef CONFIG_MTRR
+	int nomtrr;
+#endif
+	int nohwcursor;
+	int mmunalign;    // force unaligned returned VA in mmap()
+	char fontname[40];
+
+	char *mode_option;
+};
+
+
+typedef struct {
+	int pixclk_d;     // Desired Pixel Clock, KHz
+	int pixclk;       // Closest supported clock to desired clock, KHz
+	int error;        // percent error between pixclock and pixclock_d
+	int clksrc;       // equal to busclk, mclk, clki, or clki2, KHz
+	int divisor;      // pixclk = clksrc/divisor, where divisor = 1,2,3, or 4
+	u8  pixclk_bits;  // pixclock register value for above settings
+} pixclock_info_t;
+
+
+struct e1356fb_par {
+	int width;
+	int height;
+	int width_virt;   // Width in pixels
+	int height_virt;  // Height in lines
+	int bpp;          // bits-per-pixel
+	int Bpp;          // Bytes-per-pixel
+
+	// Timing
+	pixclock_info_t ipclk;
+	int horiz_ndp;    // Horiz. Non-Display Period, pixels
+	int vert_ndp;     // Vert. Non-Display Period, lines
+	int hsync_pol;    // Polarity of horiz. sync signal (HRTC for CRT/TV,
+	// FPLINE for TFT). 0=active lo, 1=active hi
+	int hsync_start;  // Horiz. Sync Start position, pixels
+	int hsync_width;  // Horiz. Sync Pulse width, pixels
+	int hsync_freq;   // calculated horizontal sync frequency
+	int vsync_pol;    // Polarity of vert. sync signal (VRTC for CRT/TV,
+	// FPFRAME for TFT). 0=active lo, 1=active hi
+	int vsync_start;  // Vert. Sync Start position, lines
+	int vsync_width;  // Vert. Sync Pulse width, lines
+	int vsync_freq;   // calculated vertical sync frequency
+
+	int cmap_len;     // color-map length
+};
+
+
+
+struct fb_info_e1356 {
+	struct fb_info fb_info;
+
+	void *regbase_virt;
+	unsigned long regbase_size;
+	void *membase_virt;
+	unsigned long fb_size;
+
+	e1356_reg_t reg;
+
+	void* putcs_buffer;
+    
+	int max_pixclock;   // Max supported pixel clock, KHz
+	int open, mmaped;   // open count, is mmap'ed
+	
+	u8 chip_rev;
+    
+#ifdef CONFIG_MTRR
+	int mtrr_idx;
+#endif
+
+#ifdef SHADOW_FRAME_BUFFER
+	struct {
+		void* fb;
+		struct timer_list timer;
+	} shadow;
+#endif
+
+	struct { unsigned red, green, blue, pad; } palette[256];
+	struct display disp;
+
+#if defined(FBCON_HAS_CFB16)
+	u16 fbcon_cmap16[16];
+#endif
+    
+	struct {
+		int type;
+		int state;
+		int w,h,u;
+		int x,y,redraw;
+		unsigned long enable,disable;
+		struct timer_list timer;
+		spinlock_t lock; 
+	} cursor;
+ 
+	struct e1356fb_fix fix;
+	struct e1356fb_par default_par;
+	struct e1356fb_par current_par;
+};
+
+
+// The following are boot options for particular SED1356-based target systems
+
+enum {
+	SYS_NULL,
+	SYS_PB1000,
+	SYS_PB1500,
+	SYS_SDU1356,
+	SYS_CLIO1050,
+	NUM_SYSTEMS // must be last
+};
+
+static struct {
+	struct e1356fb_fix fix;
+	struct e1356fb_par par;
+} systems[NUM_SYSTEMS] = {
+
+	/*
+	 * NULL system to help us detect missing options
+ 	 * when the driver is compiled as a module.
+	 */
+	{
+		{   // fix
+			SYS_NULL,
+		},
+		{   // par
+		}
+	},
+
+	/*
+	 * Alchemy Pb1000 evaluation board, SED1356
+	 */
+	{
+		{   // fix
+			SYS_PB1000,
+			/*
+			 * Note!: these are "pseudo" physical addresses;
+			 * the SED1356 is not actually mapped here, but rather
+			 * at the 36-bit address of 0xE 0000 0000. There is an
+			 * ugly hack in the Au1000 TLB refill handler that will
+			 * translate pte_t's in the range 0xE000 0000 -->
+			 * 0xEFFF FFFF to the 36-bit range 0xE 0000 0000 -->
+			 * 0xE 0FFF FFFF. The long-term solution is to support
+			 * 36-bit physical addresses in linux-mips32 mm, since
+			 * the mips32 specification specifically supports this.
+			 */
+			0xE00000000, 0xE00200000,
+			60, MEM_TYPE_EDO_2CAS, 64, MEM_SMR_CBR,
+			0, 0,   // BUSCLK and MCLK are calculated at run-time
+			40000, 14318, // CLKI, CLKI2
+#ifdef CONFIG_PB1000_CRT
+			DISP_TYPE_CRT,
+			0, 0, // TV Options
+			0, 0, // Panel options
+#elif defined (CONFIG_PB1000_NTSC)
+			DISP_TYPE_NTSC,
+			TV_FILT_FLICKER|TV_FILT_LUM|TV_FILT_CHROM,
+			TV_FMT_COMPOSITE,
+			0, 0, // Panel options
+#elif defined (CONFIG_PB1000_TFT)
+			DISP_TYPE_TFT,
+			0, 0, // TV Options
+			0, 12, // Panel options, EL panel?, data width?
+#else
+			DISP_TYPE_PAL,
+			TV_FILT_FLICKER|TV_FILT_LUM|TV_FILT_CHROM,
+			TV_FMT_COMPOSITE,
+			0, 0, // Panel options
+#endif
+			0, 0,
+#ifdef CONFIG_MTRR
+			0,
+#endif
+			0,
+			0,
+			{0},
+			"800x600@60"
+		},
+		{   // par
+			0, 0, 800, 600, 8, 1,
+			// timings will be set by modedb
+			{0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+			256
+		}
+	},
+
+	/*
+	 * Alchemy Pb1500 evaluation board, SED13806
+	 */
+	{
+		{   // fix
+			SYS_PB1500,
+			/*
+			 * Note!: these are "pseudo" physical addresses;
+			 * the SED1356 is not actually mapped here, but rather
+			 * at the 36-bit address of 0xE 0000 0000. There is an
+			 * ugly hack in the Au1000 TLB refill handler that will
+			 * translate pte_t's in the range 0xE000 0000 -->
+			 * 0xEFFF FFFF to the 36-bit range 0xE 0000 0000 -->
+			 * 0xE 0FFF FFFF. The long-term solution is to support
+			 * 36-bit physical addresses in linux-mips32 mm, since
+			 * the mips32 specification specifically supports this.
+			 */
+			0xE1B000000, 0xE1B200000,
+			50, MEM_TYPE_EMBEDDED_SDRAM, 64, MEM_SMR_CBR,
+			0, 0,   // BUSCLK and MCLK are calculated at run-time
+			40000, 14318, // CLKI, CLKI2
+#ifdef CONFIG_PB1500_CRT
+			DISP_TYPE_CRT,
+			0, 0, // TV Options
+			0, 0, // Panel options
+#else
+			DISP_TYPE_TFT,
+			0, 0, // TV Options
+			0, 12, // Panel options, EL panel?, data width?
+#endif
+			0, 0,
+#ifdef CONFIG_MTRR
+			0,
+#endif
+			0,
+			0,
+			{0},
+			"800x600@60"
+		},
+		{   // par
+			0, 0, 800, 600, 8, 1,
+			// timings will be set by modedb
+			{0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+			256
+		}
+	},
+
+	/*
+	 * Epson SDU1356B0C PCI eval card. These settings assume the
+	 * card is configured for PCI, the MediaPlug is disabled,
+	 * and the onboard clock synthesizer is at the power-up
+	 * clock settings.
+	 */
+	{
+		{   // fix
+			SYS_SDU1356,
+			0x0, 0x0,  // addresses obtained from PCI config space
+			// FIXME: just guess for now
+			60, MEM_TYPE_EDO_2CAS, 64, MEM_SMR_CBR,
+			33000, 0, 40000, 25175, // BUSCLK, MCLK, CLKI, CLKI2
+			DISP_TYPE_CRT,
+			0, 0,
+			0, 0,
+			0, 0,
+#ifdef CONFIG_MTRR
+			0,
+#endif
+			0,
+			0,
+			{0},
+			"800x600@60"
+		},
+		{   // par
+			0, 0, 1024, 768, 8, 1,
+			// timings will be set by modedb
+			{0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+			256
+		}
+	},
+
+	/*
+	 * Vadem Clio 1050 - this is for the benefit of the Linux-VR project.
+	 * FIXME: Most of these settings are just guesses, until I can get a
+	 * Clio 1050 and dump the registers that WinCE has setup.
+	 */
+	{
+		{   // fix
+			SYS_CLIO1050,
+			0x0a000000, 0x0a200000,
+			60, MEM_TYPE_EDO_2CAS, 64, MEM_SMR_CBR,
+			40000, 40000, 14318, 14318,
+			DISP_TYPE_TFT,
+			0, 0,
+			0, 16,
+			0, 0,
+#ifdef CONFIG_MTRR
+			0,
+#endif
+			0,
+			0,
+			{0},
+			"640x480@85"
+		},
+		{   // par
+			0, 0, 1024, 768, 16, 2,
+			// timings will be set by modedb
+			{0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+			16
+		}
+	}
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/fbcon-sti.c linux-2.4.20/drivers/video/fbcon-sti.c
--- linux-2.4.19/drivers/video/fbcon-sti.c	2001-10-15 20:47:13.000000000 +0000
+++ linux-2.4.20/drivers/video/fbcon-sti.c	2002-10-29 11:18:48.000000000 +0000
@@ -17,12 +17,13 @@
 #include <linux/string.h>
 #include <linux/fb.h>
 #include <linux/delay.h>
+#include <asm/gsc.h>		/* for gsc_read/write */
 #include <asm/types.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-mfb.h>
 
-#include "sti.h"
+#include "sti/sticore.h"
 
 /* Translate an address as it would be found in a 2048x2048x1 bit frame
  * buffer into a logical address Artist actually expects.  Addresses fed
@@ -39,10 +40,13 @@
 static inline u32
 ram2log(void * addr)
 {
+#if 1
+	return (unsigned long) addr;
+#else	
 	u32 a = (unsigned long) addr;
 	u32 r;
 
-#if 0
+#if 1 
 	r  =   a & 0xff000000;		/* fixed part */
 	r += ((a & 0x000000ff) << 5);
 	r += ((a & 0x00ffff00) << 3);
@@ -53,6 +57,7 @@
 #endif
 
 	return r;
+#endif
 }
 
 /* All those functions need better names. */
@@ -74,30 +79,6 @@
 	}
 }
 
-static void
-memcpy_tohp(void *dest, void *src, int count)
-{
-	unsigned long d = (unsigned long) dest;
-	u32 *s = (u32 *)src;
-
-	count += 3;
-	count &= ~3; /* XXX */
-
-	d = ram2log(dest);
-
-	while(count) {
-		count--;
-		gsc_writel(*s++, d);
-		d += 32*4;
-	}
-}
-
-static void
-memcopy_fromhp(void *dest, void *src, int count)
-{
-	/* FIXME */
-	printk("uhm ...\n");
-}
 
 static void
 memset_tohp(void *dest, u32 word, int count)
@@ -152,7 +133,7 @@
 		int height, int width)
 {
 #if 0 /* Unfortunately, still broken */
-	sti_bmove(&default_sti /* FIXME */, sy, sx, dy, dx, height, width);
+	sti_bmove(default_sti /* FIXME */, sy, sx, dy, dx, height, width);
 #else
 	u8 *src, *dest;
 	u_int rows;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/fbcon.c linux-2.4.20/drivers/video/fbcon.c
--- linux-2.4.19/drivers/video/fbcon.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/fbcon.c	2002-10-29 11:18:33.000000000 +0000
@@ -637,7 +637,7 @@
     }
     
     if (!fontwidthvalid(p,fontwidth(p))) {
-#ifdef CONFIG_MAC
+#if defined(CONFIG_FBCON_MAC) && defined(CONFIG_MAC)
 	if (MACH_IS_MAC)
 	    /* ++Geert: hack to make 6x11 fonts work on mac */
 	    p->dispsw = &fbcon_mac;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/fbmem.c linux-2.4.20/drivers/video/fbmem.c
--- linux-2.4.19/drivers/video/fbmem.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/fbmem.c	2002-10-29 11:18:30.000000000 +0000
@@ -132,6 +132,8 @@
 extern int radeonfb_setup(char*);
 extern int e1355fb_init(void);
 extern int e1355fb_setup(char*);
+extern int au1100fb_init(void);
+extern int au1100fb_setup(char*);
 extern int pvr2fb_init(void);
 extern int pvr2fb_setup(char*);
 extern int sstfb_init(void);
@@ -310,6 +312,9 @@
 #ifdef CONFIG_FB_MAXINE
 	{ "maxinefb", maxinefb_init, NULL },
 #endif
+#ifdef CONFIG_FB_AU1100
+	{ "au1100fb", au1100fb_init, au1100fb_setup },
+#endif 
 
 
 	/*
@@ -644,6 +649,8 @@
 	pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;
 #elif defined(__ia64__)
 	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+#elif defined(__hppa__)
+	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; 
 #else
 #warning What do we have to do here??
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/hpfb.c linux-2.4.20/drivers/video/hpfb.c
--- linux-2.4.19/drivers/video/hpfb.c	2001-09-13 23:04:43.000000000 +0000
+++ linux-2.4.20/drivers/video/hpfb.c	2002-10-29 11:18:48.000000000 +0000
@@ -145,16 +145,16 @@
 	unsigned int i;
 	for (i = 0; i < cmap->len; i++)
 	{
-		while (readw(fb_regs + 0x6002) & 0x4) udelay(1);
-		writew(0, fb_regs + 0x60f0);
-		writew(cmap->start + i, fb_regs + 0x60b8);
-		writew(cmap->red[i], fb_regs + 0x60b2);
-		writew(cmap->green[i], fb_regs + 0x60b4);
-		writew(cmap->blue[i], fb_regs + 0x60b6);
-		writew(0xff, fb_regs + 0x60f0);
+		while (in_be16(fb_regs + 0x6002) & 0x4) udelay(1);
+		out_be16(fb_regs + 0x60f0, 0);
+		out_be16(fb_regs + 0x60b8, cmap->start + i);
+		out_be16(fb_regs + 0x60b2, cmap->red[i]);
+		out_be16(fb_regs + 0x60b4, cmap->green[i]);
+		out_be16(fb_regs + 0x60b6, cmap->blue[i]);
+		out_be16(fb_regs + 0x60f0, 0xff);
 		udelay(100);
 	}
-	writew(0xffff, fb_regs + 0x60ba);
+	out_be16(fb_regs + 0x60ba, 0xffff);
 	return 0;
 }
 
@@ -212,15 +212,15 @@
 
 static void topcat_blit(int x0, int y0, int x1, int y1, int w, int h)
 {
-	while (readb(fb_regs + BUSY) & fb_bitmask);
-	writeb(0x3, fb_regs + WMRR);
-	writew(x0, fb_regs + SOURCE_X);
-	writew(y0, fb_regs + SOURCE_Y);
-	writew(x1, fb_regs + DEST_X);
-	writew(y1, fb_regs + DEST_Y);
-	writew(h, fb_regs + WHEIGHT);
-	writew(w, fb_regs + WWIDTH);
-	writeb(fb_bitmask, fb_regs + WMOVE);
+	while (in_8(fb_regs + BUSY) & fb_bitmask);
+	out_8(fb_regs + WMRR, 0x3);
+	out_be16(fb_regs + SOURCE_X, x0);
+	out_be16(fb_regs + SOURCE_Y, y0);
+	out_be16(fb_regs + DEST_X, x1);
+	out_be16(fb_regs + DEST_Y, y1);
+	out_be16(fb_regs + WHEIGHT, h);
+	out_be16(fb_regs + WWIDTH, w);
+	out_8(fb_regs + WMOVE, fb_bitmask);
 }
 
 static int hpfb_switch(int con, struct fb_info *info)
@@ -249,7 +249,7 @@
 
 	hpfb_get_fix(&fix, con, 0);
 
-	display->screen_base = fix.smem_start;
+	display->screen_base = (char *)fix.smem_start;
 	display->visual = fix.visual;
 	display->type = fix.type;
 	display->type_aux = fix.type_aux;
@@ -260,7 +260,11 @@
 	display->can_soft_blank = 0;
 	display->inverse = 0;
 
+#ifdef FBCON_HAS_CFB8
 	display->dispsw = &fbcon_cfb8;
+#else
+	display->dispsw = &fbcon_dummy;
+#endif
 }
 
 static struct fb_ops hpfb_ops = {
@@ -279,20 +283,19 @@
 {
 	unsigned long fboff;
 
-	fboff = (readb(base + TOPCAT_FBOMSB) << 8) 
-		| readb(base + TOPCAT_FBOLSB);
+	fboff = (in_8(base + TOPCAT_FBOMSB) << 8) | in_8(base + TOPCAT_FBOLSB);
 
-	fb_start = 0xf0000000 | (readb(base + fboff) << 16);
+	fb_start = 0xf0000000 | (in_8(base + fboff) << 16);
 	fb_regs = base;
 
 #if 0
 	/* This is the magic incantation NetBSD uses to make Catseye boards work. */
-	writeb(0, base+0x4800);
-	writeb(0, base+0x4510);
-	writeb(0, base+0x4512);
-	writeb(0, base+0x4514);
-	writeb(0, base+0x4516);
-	writeb(0x90, base+0x4206);
+	out_8(base+0x4800, 0);
+	out_8(base+0x4510, 0);
+	out_8(base+0x4512, 0);
+	out_8(base+0x4514, 0);
+	out_8(base+0x4516, 0);
+	out_8(base+0x4206, 0x90);
 #endif
 
 	/*
@@ -310,18 +313,18 @@
 	 *	pixel are supported.
 	 */
 	
-	writeb(0xff, base + TC_WEN);
-	writeb(0xff, base + TC_FBEN);
-	writeb(0xff, fb_start);
-	fb_bitmask = readb(fb_start);
+	out_8(base + TC_WEN, 0xff);
+	out_8(base + TC_FBEN, 0xff);
+	out_8(fb_start, 0xff);
+	fb_bitmask = in_8(fb_start);
 
 	/*
 	 *	Enable reading/writing of all the planes.
 	 */
-	writeb(fb_bitmask, base + TC_WEN);
-	writeb(fb_bitmask, base + TC_REN);
-	writeb(fb_bitmask, base + TC_FBEN);
-	writeb(0x1, base + TC_NBLANK);
+	out_8(base + TC_WEN, fb_bitmask);
+	out_8(base + TC_REN, fb_bitmask);
+	out_8(base + TC_FBEN, fb_bitmask);
+	out_8(base + TC_NBLANK, 0x1);
 
 	/*
 	 *	Let there be consoles..
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/macfb.c linux-2.4.20/drivers/video/macfb.c
--- linux-2.4.19/drivers/video/macfb.c	2001-11-14 22:52:20.000000000 +0000
+++ linux-2.4.20/drivers/video/macfb.c	2002-10-29 11:18:33.000000000 +0000
@@ -155,7 +155,7 @@
 
 #define PIXEL_TO_MM(a)	(((a)*10)/28)	/* width in mm at 72 dpi */	
 
-static char* video_base;
+static unsigned long video_base;
 static int   video_size;
 static char* video_vbase;        /* mapped */
 
@@ -351,15 +351,15 @@
 	cli();
 	
 	/* tell clut which address to fill */
-	writeb(regno, &valkyrie_cmap_regs->addr);
+	nubus_writeb(regno, &valkyrie_cmap_regs->addr);
 	nop();
 
 	/* send one color channel at a time */
-	writeb(red, &valkyrie_cmap_regs->lut);
+	nubus_writeb(red, &valkyrie_cmap_regs->lut);
 	nop();
-	writeb(green, &valkyrie_cmap_regs->lut);
+	nubus_writeb(green, &valkyrie_cmap_regs->lut);
 	nop();
-	writeb(blue, &valkyrie_cmap_regs->lut);
+	nubus_writeb(blue, &valkyrie_cmap_regs->lut);
 
 	restore_flags(flags);
 
@@ -391,25 +391,25 @@
 		int i;
 		
 		/* Stab in the dark trying to reset the CLUT pointer */
-		writel(0, &dafb_cmap_regs->reset);
+		nubus_writel(0, &dafb_cmap_regs->reset);
 		nop();
 		
 		/* Loop until we get to the register we want */
 		for (i = 0; i < regno; i++) {
-			writeb(palette[i].red >> 8, &dafb_cmap_regs->lut);
+			nubus_writeb(palette[i].red >> 8, &dafb_cmap_regs->lut);
 			nop();
-			writeb(palette[i].green >> 8, &dafb_cmap_regs->lut);
+			nubus_writeb(palette[i].green >> 8, &dafb_cmap_regs->lut);
 			nop();
-			writeb(palette[i].blue >> 8, &dafb_cmap_regs->lut);
+			nubus_writeb(palette[i].blue >> 8, &dafb_cmap_regs->lut);
 			nop();
 		}
 	}
 		
-	writeb(red, &dafb_cmap_regs->lut);
+	nubus_writeb(red, &dafb_cmap_regs->lut);
 	nop();
-	writeb(green, &dafb_cmap_regs->lut);
+	nubus_writeb(green, &dafb_cmap_regs->lut);
 	nop();
-	writeb(blue, &dafb_cmap_regs->lut);
+	nubus_writeb(blue, &dafb_cmap_regs->lut);
 	
 	restore_flags(flags);
 	
@@ -441,12 +441,12 @@
 	   
 	   In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff */
   	_regno = (regno<<(8-video_bpp)) | (0xFF>>video_bpp);
-	writeb(_regno, &v8_brazil_cmap_regs->addr); nop();
+	nubus_writeb(_regno, &v8_brazil_cmap_regs->addr); nop();
 
 	/* send one color channel at a time */
-	writeb(_red, &v8_brazil_cmap_regs->lut); nop();
-	writeb(_green, &v8_brazil_cmap_regs->lut); nop();
-	writeb(_blue, &v8_brazil_cmap_regs->lut);
+	nubus_writeb(_red, &v8_brazil_cmap_regs->lut); nop();
+	nubus_writeb(_green, &v8_brazil_cmap_regs->lut); nop();
+	nubus_writeb(_blue, &v8_brazil_cmap_regs->lut);
 
 	restore_flags(flags);
 	
@@ -475,15 +475,15 @@
 	_regno = regno + (256-(1<<video_bpp));
 
 	/* reset clut? (VideoToolbox sez "not necessary") */
-	writeb(0xFF, &rbv_cmap_regs->cntl); nop();
+	nubus_writeb(0xFF, &rbv_cmap_regs->cntl); nop();
 	
 	/* tell clut which address to use. */
-	writeb(_regno, &rbv_cmap_regs->addr); nop();
+	nubus_writeb(_regno, &rbv_cmap_regs->addr); nop();
 	
 	/* send one color channel at a time. */
-	writeb(_red,   &rbv_cmap_regs->lut); nop();
-	writeb(_green, &rbv_cmap_regs->lut); nop();
-	writeb(_blue,  &rbv_cmap_regs->lut);
+	nubus_writeb(_red,   &rbv_cmap_regs->lut); nop();
+	nubus_writeb(_green, &rbv_cmap_regs->lut); nop();
+	nubus_writeb(_blue,  &rbv_cmap_regs->lut);
 	
 	restore_flags(flags);
 	/* done. */
@@ -507,10 +507,10 @@
 	cli();
 	
 	/* the nop's are there to order writes. */
-	writeb(_regno, &cmap_regs->addr); nop();
-	writeb(_red, &cmap_regs->lut);    nop();
-	writeb(_green, &cmap_regs->lut);  nop();
-	writeb(_blue, &cmap_regs->lut);
+	nubus_writeb(_regno, &cmap_regs->addr); nop();
+	nubus_writeb(_red, &cmap_regs->lut);    nop();
+	nubus_writeb(_green, &cmap_regs->lut);  nop();
+	nubus_writeb(_blue, &cmap_regs->lut);
 
 	restore_flags(flags);
 	return 0;
@@ -532,10 +532,10 @@
 	save_flags(flags);
 	cli();
 	
-	writeb(_regno, &cmap_regs->addr); nop();
-	writeb(_red, &cmap_regs->lut);    nop();
-	writeb(_green, &cmap_regs->lut);  nop();
-	writeb(_blue, &cmap_regs->lut);
+	nubus_writeb(_regno, &cmap_regs->addr); nop();
+	nubus_writeb(_red, &cmap_regs->lut);    nop();
+	nubus_writeb(_green, &cmap_regs->lut);  nop();
+	nubus_writeb(_blue, &cmap_regs->lut);
 
 	restore_flags(flags);
 	return 0;
@@ -556,10 +556,10 @@
 	save_flags(flags);
 	cli();
 	
-	writeb(regno, &cmap_regs->addr); nop();
-	writeb(_red, &cmap_regs->lut); nop();
-	writeb(_green, &cmap_regs->lut); nop();
-	writeb(_blue, &cmap_regs->lut);
+	nubus_writeb(regno, &cmap_regs->addr); nop();
+	nubus_writeb(_red, &cmap_regs->lut); nop();
+	nubus_writeb(_green, &cmap_regs->lut); nop();
+	nubus_writeb(_blue, &cmap_regs->lut);
 
 	restore_flags(flags);
 	return 0;
@@ -595,7 +595,7 @@
 	/*
 	 * Set the register address
 	 */
-	writeb(regno, &civic_cmap_regs->addr); nop();
+	nubus_writeb(regno, &civic_cmap_regs->addr); nop();
 
 	/*
 	 * Wait for VBL interrupt here;
@@ -604,7 +604,7 @@
 #if 0
 	{
 #define CIVIC_VBL_OFFSET	0x120
-		volatile unsigned long *vbl = readl(civic_cmap_regs->vbl_addr + CIVIC_VBL_OFFSET);
+		volatile unsigned long *vbl = nubus_readl(civic_cmap_regs->vbl_addr + CIVIC_VBL_OFFSET);
 		/* do interrupt setup stuff here? */
 		*vbl = 0L; nop();	/* clear */
 		*vbl = 1L; nop();	/* set */
@@ -620,42 +620,42 @@
 	 * Grab a status word and do some checking;
 	 * Then finally write the clut!
 	 */
-	clut_status =  readb(&civic_cmap_regs->status2);
+	clut_status =  nubus_readb(&civic_cmap_regs->status2);
 
 	if ((clut_status & 0x0008) == 0)
 	{
 #if 0
 		if ((clut_status & 0x000D) != 0)
 		{
-			writeb(0x00, &civic_cmap_regs->lut); nop();
-			writeb(0x00, &civic_cmap_regs->lut); nop();
+			nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
+			nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
 		}
 #endif
 
-		writeb(  red, &civic_cmap_regs->lut); nop();
-		writeb(green, &civic_cmap_regs->lut); nop();
-		writeb( blue, &civic_cmap_regs->lut); nop();
-		writeb( 0x00, &civic_cmap_regs->lut); nop();
+		nubus_writeb(  red, &civic_cmap_regs->lut); nop();
+		nubus_writeb(green, &civic_cmap_regs->lut); nop();
+		nubus_writeb( blue, &civic_cmap_regs->lut); nop();
+		nubus_writeb( 0x00, &civic_cmap_regs->lut); nop();
 	}
 	else
 	{
 		unsigned char junk;
 
-		junk = readb(&civic_cmap_regs->lut); nop();
-		junk = readb(&civic_cmap_regs->lut); nop();
-		junk = readb(&civic_cmap_regs->lut); nop();
-		junk = readb(&civic_cmap_regs->lut); nop();
+		junk = nubus_readb(&civic_cmap_regs->lut); nop();
+		junk = nubus_readb(&civic_cmap_regs->lut); nop();
+		junk = nubus_readb(&civic_cmap_regs->lut); nop();
+		junk = nubus_readb(&civic_cmap_regs->lut); nop();
 
 		if ((clut_status & 0x000D) != 0)
 		{
-			writeb(0x00, &civic_cmap_regs->lut); nop();
-			writeb(0x00, &civic_cmap_regs->lut); nop();
+			nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
+			nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
 		}
 
-		writeb(  red, &civic_cmap_regs->lut); nop();
-		writeb(green, &civic_cmap_regs->lut); nop();
-		writeb( blue, &civic_cmap_regs->lut); nop();
-		writeb( junk, &civic_cmap_regs->lut); nop();
+		nubus_writeb(  red, &civic_cmap_regs->lut); nop();
+		nubus_writeb(green, &civic_cmap_regs->lut); nop();
+		nubus_writeb( blue, &civic_cmap_regs->lut); nop();
+		nubus_writeb( junk, &civic_cmap_regs->lut); nop();
 	}
 
 	restore_flags(flags);
@@ -896,7 +896,7 @@
 	video_linelength = mac_bi_data.videorow;
 	video_size       = video_linelength * video_height;
 	/* Note: physical address (since 2.1.127) */
-	video_base       = (void*) mac_bi_data.videoaddr;
+	video_base       = mac_bi_data.videoaddr;
 	/* This is actually redundant with the initial mappings.
 	   However, there are some non-obvious aspects to the way
 	   those mappings are set up, so this is in fact the safest
@@ -904,7 +904,7 @@
 	   Mac */
 	video_vbase	 = ioremap(mac_bi_data.videoaddr, video_size);
 	
-	printk("macfb: framebuffer at 0x%p, mapped to 0x%p, size %dk\n",
+	printk("macfb: framebuffer at 0x%08lx, mapped to 0x%p, size %dk\n",
 	       video_base, video_vbase, video_size/1024);
 	printk("macfb: mode is %dx%dx%d, linelength=%d\n",
 	       video_width, video_height, video_bpp, video_linelength);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/newport_con.c linux-2.4.20/drivers/video/newport_con.c
--- linux-2.4.19/drivers/video/newport_con.c	2001-10-15 20:47:24.000000000 +0000
+++ linux-2.4.20/drivers/video/newport_con.c	2002-10-29 11:18:49.000000000 +0000
@@ -36,6 +36,7 @@
 #define LOGO_H		80
 
 extern struct fbcon_font_desc font_vga_8x16;
+extern unsigned long sgi_gfxaddr;
 
 #define FONT_DATA ((unsigned char *)font_vga_8x16.data)
 
@@ -290,8 +291,9 @@
 	int i;
 	struct newport_regs *p;
 
-	npregs = (struct newport_regs *) (KSEG1 + 0x1f0f0000);
-
+	if (!sgi_gfxaddr)
+		return NULL;
+	npregs = (struct newport_regs *) (KSEG1 + sgi_gfxaddr);
 	p = npregs;
 	p->cset.config = NPORT_CFG_GD0;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/pm3fb.h linux-2.4.20/drivers/video/pm3fb.h
--- linux-2.4.19/drivers/video/pm3fb.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/pm3fb.h	2002-10-29 11:18:33.000000000 +0000
@@ -1283,4 +1283,4 @@
     } \
 } while (0)
 
-#endif PM3FB_H
+#endif /* PM3FB_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/q40fb.c linux-2.4.20/drivers/video/q40fb.c
--- linux-2.4.19/drivers/video/q40fb.c	2001-09-13 23:04:43.000000000 +0000
+++ linux-2.4.20/drivers/video/q40fb.c	2002-10-29 11:18:35.000000000 +0000
@@ -187,8 +187,7 @@
 }
 
 static int q40_setcolreg(unsigned regno, unsigned red, unsigned green,
-			 unsigned blue, unsigned transp,
-			 const struct fb_info *info)
+			 unsigned blue, unsigned transp, struct fb_info *info)
 {
     /*
      *  Set a single color register. The values supplied have a 16 bit
@@ -293,7 +292,7 @@
 
   if (con<0) con=0;
 
-   display->screen_base = fix.smem_start;
+   display->screen_base = (char *)fix.smem_start;
    display->visual = fix.visual;
    display->type = fix.type;
    display->type_aux = fix.type_aux;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/radeon.h linux-2.4.20/drivers/video/radeon.h
--- linux-2.4.19/drivers/video/radeon.h	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.20/drivers/video/radeon.h	2002-10-29 11:18:51.000000000 +0000
@@ -12,6 +12,7 @@
 #define PCI_DEVICE_ID_RADEON_LW		0x4c57
 #define PCI_DEVICE_ID_RADEON_LY		0x4c59
 #define PCI_DEVICE_ID_RADEON_LZ		0x4c5a
+#define PCI_DEVICE_ID_RADEON_PM		0x4c52
 #define PCI_DEVICE_ID_RADEON_QL		0x514c
 #define PCI_DEVICE_ID_RADEON_QW		0x5157
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/radeonfb.c linux-2.4.20/drivers/video/radeonfb.c
--- linux-2.4.19/drivers/video/radeonfb.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/radeonfb.c	2002-10-29 11:18:50.000000000 +0000
@@ -100,7 +100,8 @@
 	RADEON_QW,	/* Radeon RV200 (7500) */
 	RADEON_LW,	/* Radeon Mobility M7 */
 	RADEON_LY,	/* Radeon Mobility M6 */
-	RADEON_LZ	/* Radeon Mobility M6 */
+	RADEON_LZ,	/* Radeon Mobility M6 */
+	RADEON_PM	/* Radeon Mobility P/M */
 };
 
 
@@ -127,6 +128,7 @@
 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_LW, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LW},
 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_LY, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LY},
 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_LZ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LZ},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_PM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_PM},
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, radeonfb_pci_table);
@@ -258,8 +260,8 @@
 	u32 mmio_base_phys;
 	u32 fb_base_phys;
 
-	u32 mmio_base;
-	u32 fb_base;
+	unsigned long mmio_base;
+	unsigned long fb_base;
 
 	struct pci_dev *pdev;
 
@@ -361,7 +363,7 @@
 	} while (0)
 
 
-static __inline__ u32 _INPLL(struct radeonfb_info *rinfo, u32 addr)
+static __inline__ u32 _INPLL(struct radeonfb_info *rinfo, unsigned long addr)
 {
 	OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000001f);
 	return (INREG(CLOCK_CNTL_DATA));
@@ -800,7 +802,7 @@
 	}
 
 	/* map the regions */
-	rinfo->mmio_base = (u32) ioremap (rinfo->mmio_base_phys,
+	rinfo->mmio_base = (unsigned long)ioremap (rinfo->mmio_base_phys,
 				    		    RADEON_REGSIZE);
 	if (!rinfo->mmio_base) {
 		printk ("radeonfb: cannot map MMIO\n");
@@ -856,6 +858,9 @@
 			strcpy(rinfo->name, "Radeon M6 LZ ");
 			rinfo->hasCRTC2 = 1;
 			break;
+	        case PCI_DEVICE_ID_RADEON_PM:
+			strcpy(rinfo->name, "Radeon P/M ");
+			rinfo->hasCRTC2 = 1;
 		default:
 			return -ENODEV;
 	}
@@ -924,6 +929,7 @@
 		case PCI_DEVICE_ID_RADEON_LW:
 		case PCI_DEVICE_ID_RADEON_LY:
 		case PCI_DEVICE_ID_RADEON_LZ:
+		case PCI_DEVICE_ID_RADEON_PM:
 			rinfo->dviDisp_type = MT_LCD;
 			break;
 		default:
@@ -947,7 +953,7 @@
 		}
 	}
 
-	rinfo->fb_base = (u32) ioremap (rinfo->fb_base_phys,
+	rinfo->fb_base = (unsigned long) ioremap (rinfo->fb_base_phys,
 				  		  rinfo->video_ram);
 	if (!rinfo->fb_base) {
 		printk ("radeonfb: cannot map FB\n");
@@ -2864,6 +2870,7 @@
 			case PCI_DEVICE_ID_RADEON_LW:
 			case PCI_DEVICE_ID_RADEON_LY:
 			case PCI_DEVICE_ID_RADEON_LZ:
+			case PCI_DEVICE_ID_RADEON_PM:
 				break;
 			default:
 				return PBOOK_SLEEP_REFUSE;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/300vtbl.h linux-2.4.20/drivers/video/sis/300vtbl.h
--- linux-2.4.19/drivers/video/sis/300vtbl.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/300vtbl.h	2002-10-29 11:18:34.000000000 +0000
@@ -1,5 +1,7 @@
 
-/* Comments and changes marked with "TW" by Thomas Winischhofer <thomas@winischhofer.net> */
+
+/* Register settings for SiS 300 series */
+
 
 typedef struct _SiS300_StStruct
 {
@@ -12,7 +14,8 @@
 	UCHAR VB_StTVEdgeIndex;
 	UCHAR VB_StTVYFilterIndex;
 } SiS300_StStruct;
-SiS300_StStruct  SiS300_SModeIDTable[]=
+
+static const SiS300_StStruct  SiS300_SModeIDTable[]=
 {
 	{0x01,0x9208,0x01,0x00,0x00,0x00,0x00,0x00},
 	{0x01,0x1210,0x14,0x01,0x01,0x00,0x00,0x00},
@@ -50,7 +53,7 @@
 	UCHAR GRC[9];
 } SiS300_StandTableStruct;
 
-SiS300_StandTableStruct  SiS300_StandTable[]=
+static const SiS300_StandTableStruct  SiS300_StandTable[]=
 { /* TW: @ 0x38d4 in BIOS */
  {0x28,0x18,0x08,0x0800,
   {0x09,0x03,0x00,0x02},
@@ -421,62 +424,62 @@
 	UCHAR REFindex;
 } SiS300_ExtStruct;
 
-SiS300_ExtStruct  SiS300_EModeIDTable[]=
-{ /* TW: Table is identical to BIOS */		/* TW: BIOS offset to Ext2Struct: */
- {0x6a,0x2212,0x47,0x3563,0x0102,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */
- {0x2e,0x0a1b,0x36,0x3539,0x0101,0x08,0x06,0x00,0x00,0x00,0x08},  /* 37c3 */ /* 8bpp bug? */
- /* {0x2e,0x021b,0x36,0x3539,0x0101,0x08,0x06,0x00,0x00,0x00,0x08},  */ /* 37c3 */
- {0x2f,0x021b,0x35,0x3532,0x0100,0x08,0x05,0x00,0x00,0x00,0x10},  /* 37bc */
- {0x30,0x2a1b,0x47,0x3563,0x0103,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */ /* 8bpp bug? */
- /* {0x30,0x221b,0x47,0x3563,0x0103,0x08,0x07,0x00,0x00,0x00,0x00}, */ /* 37ed */
- {0x31,0x0a1b,0xad,0x3630,0x0000,0x08,0x0c,0x00,0x00,0x00,0x11},  /* 38ba */
- {0x32,0x2a1b,0xae,0x3637,0x0000,0x08,0x0d,0x00,0x00,0x00,0x12},  /* 38c1 */
- {0x33,0x0a1d,0xad,0x3630,0x0000,0x08,0x0c,0x00,0x00,0x00,0x11},  /* 38ba */
- {0x34,0x2a1d,0xae,0x3637,0x0000,0x08,0x0d,0x00,0x00,0x00,0x12},  /* 38c1 */
- {0x35,0x0a1f,0xad,0x3630,0x0000,0x08,0x0c,0x00,0x00,0x00,0x11},  /* 38ba */
- {0x36,0x2a1f,0xae,0x3637,0x0000,0x08,0x0d,0x00,0x00,0x00,0x12},  /* 38c1 */
- {0x37,0x0212,0x58,0x358d,0x0104,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */
- {0x38,0x0a1b,0x58,0x358d,0x0105,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */ /* 8bpp bug? */
- /* {0x38,0x021b,0x58,0x358d,0x0105,0x08,0x08,0x00,0x00,0x00,0x13}, */ /* 3817 */
- {0x3a,0x0e3b,0x69,0x35be,0x0107,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 3848 */ /* 8bpp bug? */
- /* {0x3a,0x063b,0x69,0x35be,0x0107,0x08,0x09,0x00,0x00,0x00,0x1a}, */ /* 3848 */
- {0x3c,0x063b,0x7a,0x35d4,0x0130,0x08,0x0a,0x00,0x00,0x00,0x1e},  /* 385e */
- {0x3d,0x067d,0x7a,0x35d4,0x0131,0x08,0x0a,0x00,0x00,0x00,0x1e},  /* 385e */
- {0x40,0x921c,0x00,0x3516,0x010d,0x08,0x00,0x00,0x00,0x00,0x23},  /* 37a0 */
- {0x41,0x921d,0x00,0x3516,0x010e,0x08,0x00,0x00,0x00,0x00,0x23},  /* 37a0 */
- {0x43,0x0a1c,0x36,0x3539,0x0110,0x08,0x06,0x00,0x00,0x00,0x08},  /* 37c3 */
- {0x44,0x0a1d,0x36,0x3539,0x0111,0x08,0x06,0x00,0x00,0x00,0x08},  /* 37c3 */
- {0x46,0x2a1c,0x47,0x3563,0x0113,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */
- {0x47,0x2a1d,0x47,0x3563,0x0114,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */
- {0x49,0x0a3c,0x58,0x358d,0x0116,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */
- {0x4a,0x0a3d,0x58,0x358d,0x0117,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */
- {0x4c,0x0e7c,0x69,0x35be,0x0119,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 3848 */
- {0x4d,0x0e7d,0x69,0x35be,0x011a,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 3848 */
- {0x50,0x921b,0x01,0x351d,0x0132,0x08,0x01,0x00,0x00,0x00,0x24},  /* 37a7 */
- {0x51,0x921b,0x13,0x3524,0x0133,0x08,0x03,0x00,0x00,0x00,0x25},  /* 37ae */
- {0x52,0x921b,0x24,0x352b,0x0134,0x08,0x04,0x00,0x00,0x00,0x26},  /* 37b5 */
- {0x56,0x921d,0x01,0x351d,0x0135,0x08,0x01,0x00,0x00,0x00,0x24},  /* 37a7 */
- {0x57,0x921d,0x13,0x3524,0x0136,0x08,0x03,0x00,0x00,0x00,0x25},  /* 37ae */
- {0x58,0x921d,0x24,0x352b,0x0137,0x08,0x04,0x00,0x00,0x00,0x26},  /* 37b5 */
- {0x59,0x921b,0x00,0x3516,0x0138,0x08,0x00,0x00,0x00,0x00,0x23},  /* 37a0 */
- {0x5d,0x021d,0x35,0x3532,0x0139,0x08,0x05,0x00,0x00,0x00,0x10},  /* 37bc */
- {0x62,0x0a3f,0x36,0x3539,0x013a,0x08,0x06,0x00,0x00,0x00,0x08},  /* 37c3 */
- {0x63,0x2a3f,0x47,0x3563,0x013b,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */
- {0x64,0x0a7f,0x58,0x358d,0x013c,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */
- {0x65,0x0eff,0x69,0x35be,0x013d,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 3848 */
- {0x66,0x06ff,0x7a,0x35d4,0x013e,0x08,0x0a,0x00,0x00,0x00,0x1e},  /* 385e */
- {0x68,0x067b,0x8b,0x35ef,0x013f,0x08,0x0b,0x00,0x00,0x00,0x27},  /* 3879 */
- {0x69,0x06fd,0x8b,0x35ef,0x0140,0x08,0x0b,0x00,0x00,0x00,0x27},  /* 3879 */
- {0x6b,0x07ff,0x8b,0x35ef,0x0000,0x10,0x0b,0x00,0x00,0x00,0x27},  /* 3879 */
- {0x6c,0x067b,0x9c,0x35f6,0x0000,0x08,0x0c,0x00,0x00,0x00,0x28},  /* 3880 */
- {0x6d,0x06fd,0x9c,0x35f6,0x0000,0x10,0x0c,0x00,0x00,0x00,0x28},  /* 3880 */
- {0x6e,0x0e3b,0x6f,0x35b2,0x0000,0x08,0x0e,0x00,0x00,0x00,0x29},  /* 383c */
- {0x6f,0x0e7d,0x6f,0x35b2,0x0000,0x08,0x0e,0x00,0x00,0x00,0x29},  /* 383c */
- {0x7b,0x0eff,0x6f,0x35b2,0x0000,0x08,0x0e,0x00,0x00,0x00,0x29},  /* 383c */
- {0x7c,0x221b,0xb3,0x363e,0x0000,0x08,0x0f,0x00,0x00,0x00,0x2b},  /* 38c8 */
- {0x7d,0x221d,0xb3,0x363e,0x0000,0x08,0x0f,0x00,0x00,0x00,0x2b},  /* 38c8 */
- {0x7e,0x223f,0xb3,0x363e,0x0000,0x08,0x0f,0x00,0x00,0x00,0x2b},  /* 38c8 */
- {0xff,0x0000,0x00,0x0000,0xffff,0x00,0x00,0x00,0x00,0x00,0x00}
+static const SiS300_ExtStruct  SiS300_EModeIDTable[]=
+{
+	{0x6a,0x2212,0x47,0x3563,0x0102,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */  /* 800x600x? */
+	{0x2e,0x0a1b,0x36,0x3539,0x0101,0x08,0x06,0x00,0x00,0x00,0x08},  /* 37c3 */
+	{0x2f,0x021b,0x35,0x3532,0x0100,0x08,0x05,0x00,0x00,0x00,0x10},  /* 37bc */
+	{0x30,0x2a1b,0x47,0x3563,0x0103,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */
+	{0x31,0x0a1b,0xad,0x3630,0x0000,0x08,0x0c,0x00,0x00,0x00,0x11},  /* 38ba */ /* 720x480x8 */
+	{0x32,0x2a1b,0xae,0x3637,0x0000,0x08,0x0d,0x00,0x00,0x00,0x12},  /* 38c1 */ /* 720x576x8 */
+	{0x33,0x0a1d,0xad,0x3630,0x0000,0x08,0x0c,0x00,0x00,0x00,0x11},  /* 38ba */ /* 720x480x16 */
+	{0x34,0x2a1d,0xae,0x3637,0x0000,0x08,0x0d,0x00,0x00,0x00,0x12},  /* 38c1 */ /* 720x576x16 */
+	{0x35,0x0a1f,0xad,0x3630,0x0000,0x08,0x0c,0x00,0x00,0x00,0x11},  /* 38ba */ /* 720x480x32 */
+	{0x36,0x2a1f,0xae,0x3637,0x0000,0x08,0x0d,0x00,0x00,0x00,0x12},  /* 38c1 */ /* 720x576x32 */
+	{0x37,0x0212,0x58,0x358d,0x0104,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */ /* 1024x768x? */
+	{0x38,0x0a1b,0x58,0x358d,0x0105,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */ /* 1024x768x8 */
+	{0x3a,0x0e3b,0x69,0x35be,0x0107,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 3848 */ /* 1280x1024x8 */
+	{0x3c,0x063b,0x7a,0x35d4,0x0130,0x08,0x0a,0x00,0x00,0x00,0x1e},  /* 385e */
+	{0x3d,0x067d,0x7a,0x35d4,0x0131,0x08,0x0a,0x00,0x00,0x00,0x1e},  /* 385e */
+	{0x40,0x921c,0x00,0x3516,0x010d,0x08,0x00,0x00,0x00,0x00,0x23},  /* 37a0 */
+	{0x41,0x921d,0x00,0x3516,0x010e,0x08,0x00,0x00,0x00,0x00,0x23},  /* 37a0 */
+	{0x43,0x0a1c,0x36,0x3539,0x0110,0x08,0x06,0x00,0x00,0x00,0x08},  /* 37c3 */
+	{0x44,0x0a1d,0x36,0x3539,0x0111,0x08,0x06,0x00,0x00,0x00,0x08},  /* 37c3 */
+	{0x46,0x2a1c,0x47,0x3563,0x0113,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */ /* 800x600 */
+	{0x47,0x2a1d,0x47,0x3563,0x0114,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */ /* 800x600 */
+	{0x49,0x0a3c,0x58,0x358d,0x0116,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */
+	{0x4a,0x0a3d,0x58,0x358d,0x0117,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */
+	{0x4c,0x0e7c,0x69,0x35be,0x0119,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 3848 */
+	{0x4d,0x0e7d,0x69,0x35be,0x011a,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 3848 */
+	{0x50,0x921b,0x01,0x351d,0x0132,0x08,0x01,0x00,0x00,0x00,0x24},  /* 37a7 */
+	{0x51,0xb21b,0x13,0x3524,0x0133,0x08,0x03,0x00,0x00,0x00,0x25},  /* 37ae */ /* 400x300 */
+	{0x52,0x921b,0x24,0x352b,0x0134,0x08,0x04,0x00,0x00,0x00,0x26},  /* 37b5 */
+	{0x56,0x921d,0x01,0x351d,0x0135,0x08,0x01,0x00,0x00,0x00,0x24},  /* 37a7 */
+	{0x57,0xb21d,0x13,0x3524,0x0136,0x08,0x03,0x00,0x00,0x00,0x25},  /* 37ae */ /* 400x300 */
+	{0x58,0x921d,0x24,0x352b,0x0137,0x08,0x04,0x00,0x00,0x00,0x26},  /* 37b5 */
+	{0x59,0x921b,0x00,0x3516,0x0138,0x08,0x00,0x00,0x00,0x00,0x23},  /* 37a0 */
+	{0x5c,0x921f,0x24,0x352b,0x0000,0x08,0x04,0x00,0x00,0x00,0x26},  /* TW: inserted 512x384x32 */
+	{0x5d,0x021d,0x35,0x3532,0x0139,0x08,0x05,0x00,0x00,0x00,0x10},  /* 37bc */
+	{0x62,0x0a3f,0x36,0x3539,0x013a,0x08,0x06,0x00,0x00,0x00,0x08},  /* 37c3 */
+	{0x63,0x2a3f,0x47,0x3563,0x013b,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */  /* 800x600 */
+	{0x64,0x0a7f,0x58,0x358d,0x013c,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */
+	{0x65,0x0eff,0x69,0x35be,0x013d,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 3848 */
+	{0x66,0x06ff,0x7a,0x35d4,0x013e,0x08,0x0a,0x00,0x00,0x00,0x1e},  /* 385e */
+	{0x68,0x067b,0x8b,0x35ef,0x013f,0x08,0x0b,0x00,0x00,0x00,0x27},  /* 3879 */
+	{0x69,0x06fd,0x8b,0x35ef,0x0140,0x08,0x0b,0x00,0x00,0x00,0x27},  /* 3879 */
+	{0x6b,0x07ff,0x8b,0x35ef,0x0000,0x10,0x0b,0x00,0x00,0x00,0x27},  /* 3879 */
+	{0x6c,0x067b,0x9c,0x35f6,0x0000,0x08,0x0c,0x00,0x00,0x00,0x28},  /* 3880 */
+	{0x6d,0x06fd,0x9c,0x35f6,0x0000,0x10,0x0c,0x00,0x00,0x00,0x28},  /* 3880 */
+	{0x6e,0x0e3b,0x6f,0x35b2,0x0000,0x08,0x0e,0x00,0x00,0x00,0x29},  /* 383c */  /* 1280x960x8 */
+	{0x6f,0x0e7d,0x6f,0x35b2,0x0000,0x08,0x0e,0x00,0x00,0x00,0x29},  /* 383c */  /* 1280x960x16 */
+	{0x7b,0x0eff,0x6f,0x35b2,0x0000,0x08,0x0e,0x00,0x00,0x00,0x29},  /* 383c */  /* 1280x960x32 */
+	{0x20,0x0a1b,0x54,0x0000,0x0000,0x08,0x0f,0x00,0x00,0x00,0x2b},              /* 1024x600 */
+	{0x21,0x0a3d,0x54,0x0000,0x0000,0x08,0x0f,0x00,0x00,0x00,0x2b},
+	{0x22,0x0a7f,0x54,0x0000,0x0000,0x08,0x0f,0x00,0x00,0x00,0x2b},
+	{0x23,0x0a1b,0xc5,0x0000,0x0000,0x08,0x10,0x00,0x00,0x00,0x2c},              /* 1152x768 */
+	{0x24,0x0a3d,0xc5,0x431d,0x0000,0x08,0x10,0x00,0x00,0x00,0x2c},
+	{0x25,0x0a7f,0xc5,0x431d,0x0000,0x08,0x10,0x00,0x00,0x00,0x2c},
+	{0xff,0x0000,0x00,0x0000,0xffff,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
 typedef struct _SiS300_Ext2Struct
@@ -491,82 +494,55 @@
 	USHORT ROM_OFFSET;
 } SiS300_Ext2Struct;
 
-SiS300_Ext2Struct  SiS300_RefIndex[]=
+static const SiS300_Ext2Struct  SiS300_RefIndex[]=
 { /* TW: Don't ever insert anything here, table is indexed */
- {0x085f,0x0d,0x03,0x05,0x6a, 800, 600,0x3563},
- {0x0467,0x0e,0x44,0x05,0x6a, 800, 600,0x3568},
- {0x0067,0x4f,0x07,0x48,0x6a, 800, 600,0x356d},
- {0x0067,0x10,0x06,0x8b,0x6a, 800, 600,0x3572},
- {0x0147,0x11,0x08,0x00,0x6a, 800, 600,0x3577},
- {0x0147,0x12,0x0c,0x00,0x6a, 800, 600,0x357c},
- {0x0047,0x51,0x4e,0x00,0x6a, 800, 600,0x3581},
- {0x0047,0x11,0x13,0x00,0x6a, 800, 600,0x3586},
- {0xc85f,0x05,0x00,0x04,0x2e, 640, 480,0x3539},
- {0xc067,0x06,0x02,0x04,0x2e, 640, 480,0x353e},
- {0xc067,0x07,0x02,0x47,0x2e, 640, 480,0x3543},
- {0xc067,0x08,0x03,0x8a,0x2e, 640, 480,0x3548},
- {0xc047,0x09,0x05,0x00,0x2e, 640, 480,0x354d},
- {0xc047,0x0a,0x08,0x00,0x2e, 640, 480,0x3552},
- {0xc047,0x0b,0x0a,0x00,0x2e, 640, 480,0x3557},
- {0xc047,0x0c,0x10,0x00,0x2e, 640, 480,0x355c},
- {0x487f,0x04,0x00,0x00,0x2f, 640, 400,0x3532},
- {0xc00f,0x31,0x01,0x06,0x31,2048,1536,0x3630},
- {0x000f,0x32,0x03,0x06,0x32, 720, 480,0x3637},
- {0x0187,0x15,0x05,0x00,0x37,1024, 768,0x358d},
- /* {0xc877,0x16,0x09,0x06,0x37,1024, 768,0x3592}, <--- different in BIOS */
- {0xc077,0x16,0x09,0x06,0x37,1024, 768,0x3592},
- {0xc067,0x97,0x0b,0x49,0x37,1024, 768,0x3597},
- {0x0267,0x18,0x0d,0x00,0x37,1024, 768,0x359c},
- {0x0047,0x59,0x11,0x8c,0x37,1024, 768,0x35a1},
- {0x0047,0x1a,0x52,0x00,0x37,1024, 768,0x35a6},
- {0x0047,0x5b,0x16,0x00,0x37,1024, 768,0x35ab},
- {0x0387,0x5c,0x4d,0x00,0x3a,1280,1024,0x35be},
- {0x0077,0x1d,0x14,0x07,0x3a,1280,1024,0x35c3},
- {0x0047,0x1e,0x17,0x00,0x3a,1280,1024,0x35c8},
- {0x0007,0x1f,0x98,0x00,0x3a,1280,1024,0x35cd},
- {0x0007,0x60,0x59,0x00,0x3c,1600,1200,0x35d4},
- {0x0007,0x21,0x5a,0x00,0x3c,1600,1200,0x35d9},
- {0x0007,0x22,0x1b,0x00,0x3c,1600,1200,0x35de},
- {0x0007,0x63,0x1d,0x00,0x3c,1600,1200,0x35e3},
- {0x0007,0x24,0x1e,0x00,0x3c,1600,1200,0x35e8},
- /* TW: No 1600x1200 LCD mode? */
- {0x407f,0x00,0x00,0x00,0x40, 320, 200,0x3516},
- {0xc07f,0x01,0x00,0x04,0x50, 320, 240,0x351d},
- {0x0077,0x02,0x04,0x05,0x51, 400, 300,0x3524},
- {0xc077,0x03,0x09,0x06,0x52, 512, 384,0x352b},
- {0x8207,0x25,0x1f,0x00,0x68,1920,1440,0x35ef},
- {0x0007,0x26,0x20,0x00,0x6c,2048,1536,0x35f6},
- {0x0027,0x27,0x14,0x08,0x6e, 720, 576,0x35b2},
- {0x0027,0x27,0x14,0x08,0x6e, 720, 576,0x35b7},
- /* TW: 1280x960 identical to BIOS */
- /* TW:              v--- I doubt this - no CRT2? */
- {0x00df,0x33,0x28,0x00,0x7c,1280, 960,0x363e},
- {0xc05f,0x34,0x28,0x00,0x7c,1280, 960,0x3643},
-#if 0
- /* TW: The LCD modes for 1280x960 are missing! */
- /*     Values guessed! */
- {0x00a7,0x33,0x28,0x08,0x7c,1280, 960,0xDEAD},  /* Do we need an interlace mode? */
- {0xc027,0x34,0x28,0x08,0x7c,1280, 960,0xBEEF},
- /* TW:    |         |---- This is either 0x07 or 0x08  */
-#endif /*  +---- Same as for the non-interlace mode */
- {0xffff,0,0,0,0,0,0,0}
-};
-
-/* TW: These entries are contained in the BIOS but missing in table above: (resolution unknown) */
-#if 0
- /* at 0x3887: (not indexed by EModeIDTable in BIOS either) */
- {0x0057,0x28,0x27,0x08,... }
- {0x0047,0x29,0x06,0x08,... }
- {0x0047,0x2a,0x08,0x08,... } /* table end */
- /* at 0x3898: (not indexed by EModeIDTable in BIOS either)*/
- {0x0057,0x2b,0x09,0x09,... }
- {0x0047,0x2c,0x0d,0x09,... }
- {0x0047,0x2d,0x11,0x09,... } /* table end */
- /* at 0x38a9: (not indexed by EModeIDTable in BIOS either) */
- {0x0057,0x2e,0x14,0x0a,... }
- {0x0047,0x2f,0x17,0x0a,... }
- {0x0047,0x30,0x18,0x0a,... } /* table end */
-#endif
+	{0x085f,0x0d,0x03,0x05,0x6a, 800, 600,0x3563}, /* 00 */
+	{0x0467,0x0e,0x44,0x05,0x6a, 800, 600,0x3568}, /* 01 */
+	{0x0067,0x4f,0x07,0x48,0x6a, 800, 600,0x356d}, /* 02 */
+	{0x0067,0x10,0x06,0x8b,0x6a, 800, 600,0x3572}, /* 03 */
+	{0x0147,0x11,0x08,0x00,0x6a, 800, 600,0x3577}, /* 04 */
+	{0x0147,0x12,0x0c,0x00,0x6a, 800, 600,0x357c}, /* 05 */
+	{0x0047,0x51,0x4e,0x00,0x6a, 800, 600,0x3581}, /* 06 */
+	{0x0047,0x11,0x13,0x00,0x6a, 800, 600,0x3586}, /* 07 */
+	{0xc85f,0x05,0x00,0x04,0x2e, 640, 480,0x3539}, /* 08 */
+	{0xc067,0x06,0x02,0x04,0x2e, 640, 480,0x353e}, /* 09 */
+	{0xc067,0x07,0x02,0x47,0x2e, 640, 480,0x3543}, /* 0a */
+	{0xc067,0x08,0x03,0x8a,0x2e, 640, 480,0x3548}, /* 0b */
+	{0xc047,0x09,0x05,0x00,0x2e, 640, 480,0x354d}, /* 0c */
+	{0xc047,0x0a,0x08,0x00,0x2e, 640, 480,0x3552}, /* 0d */
+	{0xc047,0x0b,0x0a,0x00,0x2e, 640, 480,0x3557}, /* 0e */
+	{0xc047,0x0c,0x10,0x00,0x2e, 640, 480,0x355c}, /* 0f */
+	{0x487f,0x04,0x00,0x00,0x2f, 640, 400,0x3532}, /* 10 */
+	{0xc00f,0x31,0x01,0x06,0x31, 720, 480,0x3630}, /* 11 */
+	{0x000f,0x32,0x03,0x06,0x32, 720, 576,0x3637}, /* 12 */
+	{0x0187,0x15,0x05,0x00,0x37,1024, 768,0x358d}, /* 13 */
+        {0xc877,0x16,0x09,0x06,0x37,1024, 768,0x3592}, /* 14 */
+	{0xc067,0x97,0x0b,0x49,0x37,1024, 768,0x3597}, /* 15 */
+	{0x0267,0x18,0x0d,0x00,0x37,1024, 768,0x359c}, /* 16 */
+	{0x0047,0x59,0x11,0x8c,0x37,1024, 768,0x35a1}, /* 17 */
+	{0x0047,0x1a,0x52,0x00,0x37,1024, 768,0x35a6}, /* 18 */
+	{0x0047,0x5b,0x16,0x00,0x37,1024, 768,0x35ab}, /* 19 */
+	{0x0387,0x5c,0x4d,0x00,0x3a,1280,1024,0x35be}, /* 1a */
+	{0x0077,0x1d,0x14,0x07,0x3a,1280,1024,0x35c3}, /* 1b */
+	{0x0047,0x1e,0x17,0x00,0x3a,1280,1024,0x35c8}, /* 1c */
+	{0x0007,0x1f,0x98,0x00,0x3a,1280,1024,0x35cd}, /* 1d */
+	{0x0007,0x60,0x59,0x00,0x3c,1600,1200,0x35d4}, /* 1e */
+	{0x0007,0x21,0x5a,0x00,0x3c,1600,1200,0x35d9}, /* 1f */
+	{0x0007,0x22,0x1b,0x00,0x3c,1600,1200,0x35de}, /* 20 */
+	{0x0007,0x63,0x1d,0x00,0x3c,1600,1200,0x35e3}, /* 21 */
+	{0x0007,0x24,0x1e,0x00,0x3c,1600,1200,0x35e8}, /* 22 */
+	{0x407f,0x00,0x00,0x00,0x40, 320, 200,0x3516}, /* 23 */
+	{0xc07f,0x01,0x00,0x04,0x50, 320, 240,0x351d}, /* 24 */
+	{0x0077,0x02,0x04,0x05,0x51, 400, 300,0x3524}, /* 25 */
+	{0xc877,0x03,0x09,0x06,0x52, 512, 384,0x352b}, /* 26 */  /* was c077 */
+	{0x8207,0x25,0x1f,0x00,0x68,1920,1440,0x35ef}, /* 27 */
+	{0x0007,0x26,0x20,0x00,0x6c, 720, 480,0x35f6}, /* 28 */
+	{0x0027,0x27,0x14,0x08,0x6e,1280, 960,0x35b2}, /* 29 */
+	{0x0027,0x27,0x14,0x08,0x6e,1280, 960,0x35b7}, /* 2a */
+	{0xc077,0x33,0x09,0x06,0x20,1024, 600,0x0000}, /* 2b */
+	{0xc077,0x34,0x09,0x06,0x23,1152, 768,0x0000}, /* 2c */
+	{0xffff,0,0,0,0,0,0,0}
+};
 
 /*add for 300 oem util*/
 typedef struct _SiS_VBModeIDTableStruct
@@ -581,9 +557,9 @@
 	UCHAR  _VB_LCDVIndex;
 }SiS_VBModeIDTableStruct;
 
-SiS_VBModeIDTableStruct  SiS300_VBModeIDTable[]=
+static const SiS_VBModeIDTableStruct  SiS300_VBModeIDTable[]=
 {
-	{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+	{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /* TW: Identical to 630/301B 2.04.50 BIOS */
 	{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01},
 	{0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x02},
 	{0x03,0x00,0x00,0x00,0x02,0x00,0x02,0x00},
@@ -633,22 +609,22 @@
 	{0x65,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
 	{0x6e,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
 	{0x6f,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
-	{0x7b,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d}
+	{0x7b,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
+	{0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00}  /* TW: added! */
 };
 /*end*/
 
-/* TW: The following table is (now) identical to BIOS */
 typedef struct _SiS300_CRT1TableStruct
 {
 	UCHAR CR[17];
 } SiS300_CRT1TableStruct;
 
-SiS300_CRT1TableStruct  SiS300_CRT1Table[]=
-{ /* at 0x4014 in BIOS */
- {{0x2d,0x27,0x28,0x90,/*0x2b*/ 0x2c,0x80,0xbf,0x1f,  /* <--- was different to BIOS */
+static const SiS300_CRT1TableStruct  SiS300_CRT1Table[]=
+{
+ {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,    /* 0x00 */
   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
   0x00}},
- {{0x2d,0x27,0x28,0x90,/*0x2b*/ 0x2c,0x80,0x0b,0x3e,  /* <--- was different to BIOS */
+ {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
   0x00}},
  {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
@@ -675,7 +651,7 @@
  {{0x66,0x4f,0x4f,0x86,0x56,0x9e,0x03,0x3e,
   0xe4,0x87,0xdf,0xdf,0x04,0x00,0x00,0x01,
   0x00}},
- {{0x6c,0x4f,0x4f,0x83,0x59,0x9e,0x00,0x3e,    /* 10 */
+ {{0x6c,0x4f,0x4f,0x83,0x59,0x9e,0x00,0x3e,    /* 0x0a */
   0xe5,0x8d,0xdf,0xdf,0x01,0x00,0x00,0x01,
   0x00}},
  {{0x63,0x4f,0x4f,0x87,0x56,0x9d,0xfb,0x1f,
@@ -705,7 +681,7 @@
  {{0x7e,0x63,0x63,0x82,0x6c,0x14,0x75,0xe0,
   0x58,0x0b,0x57,0x57,0x76,0x20,0x00,0x06,
   0x01}},
- {{0x7e,0x63,0x63,0x82,0x6c,0x14,0x75,0xe0,   /* 20 */
+ {{0x7e,0x63,0x63,0x82,0x6c,0x14,0x75,0xe0,   /* 0x14 */
   0x58,0x0b,0x57,0x57,0x76,0x20,0x00,0x06,
   0x01}},
  {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
@@ -735,7 +711,7 @@
  {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
   0x01}},
- {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,  /* 30 */
+ {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,  /* 0x1e */
   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
   0x01}},
  {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
@@ -758,14 +734,14 @@
   0x00}},
  {{0x3f,0xef,0xef,0x83,0xfd,0x1a,0xda,0x1f,  /* 37: 1920x1440x60Hz */
   0xa0,0x84,0x9f,0x9f,0xdb,0x1f,0x01,0x01,
-  0x00}},  /* TW: TEST, should be 0x30? */
+  0x00}},
  {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
   0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
   0x00}},
  {{0xdc,0x9f,0x9f,0x00,0xab,0x19,0xe6,0xef,
   0xc0,0xc3,0xbf,0xbf,0xe7,0x10,0x00,0x07,
   0x01}},
- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,
+ {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,  /* 0x28 */
   0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
   0x01}},
  {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
@@ -795,16 +771,15 @@
  {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
   0x00}},
- {{0x7b,0x59,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
+ {{0x7b,0x59,0x63,0x9f,0x6a,0x93,0x6f,0xf0,  /* 0x32 */
   0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05,
   0x01}},
- {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15,	/* 1280x960 */
-  0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02,
-  0x00}},
- {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,	/* 1280x960 */
-  0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
-  0x00}}
-  /* end @ 0x4399 */
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,  /* 0x33 - 1024x600 */
+  0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
+  0x01}},
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,  /* 0x34 - 1152x768 */
+  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+  0x01}}
 };
 
 typedef struct _SiS300_MCLKDataStruct
@@ -813,7 +788,7 @@
 	USHORT CLOCK;
 } SiS300_MCLKDataStruct;
 
-SiS300_MCLKDataStruct  SiS300_MCLKData[]=
+static const SiS300_MCLKDataStruct  SiS300_MCLKData_630[] =	/* 630 */
 { /* TW: at 0x54 in BIOS */
 	{ 0x5a,0x64,0x80, 66},
 	{ 0xb3,0x45,0x80, 83},
@@ -825,14 +800,26 @@
 	{ 0x37,0x61,0x80,100}
 };
 
+static const SiS300_MCLKDataStruct  SiS300_MCLKData_300[] =  /* 300 */
+{ /* TW: at 0x54 in BIOS */
+	{ 0x68,0x43,0x80,125},
+	{ 0x68,0x43,0x80,125},
+	{ 0x68,0x43,0x80,125},
+	{ 0x37,0x61,0x80,100},
+	{ 0x37,0x61,0x80,100},
+	{ 0x37,0x61,0x80,100},
+	{ 0x37,0x61,0x80,100},
+	{ 0x37,0x61,0x80,100}
+};
+
 typedef struct _SiS300_ECLKDataStruct
 {
 	UCHAR SR2E,SR2F,SR30;
 	USHORT CLOCK;
 } SiS300_ECLKDataStruct;
 
-SiS300_ECLKDataStruct  SiS300_ECLKData[]=
-{ /* TW: at 0x7c in BIOS */
+static const SiS300_ECLKDataStruct  SiS300_ECLKData[]=
+{
 	{ 0x54,0x43,0x80,100},
 	{ 0x53,0x43,0x80,100},
 	{ 0x55,0x43,0x80,100},
@@ -849,8 +836,8 @@
 	USHORT CLOCK;
 } SiS300_VCLKDataStruct;
 
-SiS300_VCLKDataStruct  SiS300_VCLKData[]=
-{ /* TW: At 0x484e in BIOS */
+static const SiS300_VCLKDataStruct  SiS300_VCLKData[]=
+{
 	{ 0x1b,0xe1, 25},
 	{ 0x4e,0xe4, 28},
 	{ 0x57,0xe4, 32},
@@ -863,11 +850,11 @@
 	{ 0x5a,0x64, 65},
 	{ 0x46,0x44, 68},
 	{ 0x3e,0x43, 75},
-	{ 0x6d,0x46, 76},
+	{ 0x6d,0x46, 76}, /* 0x0c: 800x600 | LVDS_2(CH), MITAC(CH);  - LVDS2(CH), A901(301B): 0xb1,0x46, 76 */
 	{ 0x41,0x43, 79},
 	{ 0x31,0x42, 79},
 	{ 0x46,0x25, 85},
-	{ 0x78,0x29, 87},
+	{ 0x78,0x29, 87}, /* 0x10 */
 	{ 0x62,0x44, 95},
 	{ 0x2b,0x22,105},
 	{ 0x49,0x24,106},
@@ -882,37 +869,91 @@
 	{ 0xde,0x26,194},
 	{ 0x54,0x05,203},
 	{ 0x3f,0x03,230},
-	{ 0x30,0x02,234},  /* 0x1f - 1920x1440 */
-	{ 0x24,0x01,266},  /* 0x20 - 2048x1536 */
-	{ 0x52,0x2a, 54},
-	{ 0x52,0x6a, 27},
-	{ 0x62,0x24, 70},
-	{ 0x62,0x64, 70},
-	{ 0xa8,0x4c, 30},
-	{ 0x20,0x26, 33},
+	{ 0x30,0x02,234},
+	{ 0x24,0x01,266},  /* 0x20 */
+	{ 0x52,0x2a, 54},  /* 301 TV */
+	{ 0x52,0x6a, 27},  /* 301 TV */
+	{ 0x62,0x24, 70},  /* 301 TV */
+	{ 0x62,0x64, 70},  /* 301 TV */
+	{ 0xa8,0x4c, 30},  /* 301 TV */
+	{ 0x20,0x26, 33},  /* 301 TV */
 	{ 0x31,0xc2, 39},
-	{ 0xbf,0xc8, 35},  /* 0x28 - 1280x960 ??? that can't be right */
-	{ 0x60,0x36, 30},
+	{ 0xbf,0xc8, 35},  /* 0x28 */
+	{ 0x60,0x36, 30},  /* 0x29  CH/UNTSC TEXT | LVDS_2(CH) - LVDS2(CH), A901(301B), Mitac(CH): 0xe0, 0xb6, 30 */
 	{ 0x40,0x4a, 28},
 	{ 0x9f,0x46, 44},
 	{ 0x97,0x2c, 26},
 	{ 0x44,0xe4, 25},
 	{ 0x7e,0x32, 47},
-	{ 0x8a,0x24, 31},
+	{ 0x8a,0x24, 31},  /* 0x2f  CH/PAL TEXT | LVDS_2(CH), Mitac(CH) -  LVDS2(CH), A901(301B): 0x57, 0xe4, 31 */
 	{ 0x97,0x2c, 26},
 	{ 0xce,0x3c, 39},
 	{ 0x52,0x4a, 36},
 	{ 0x34,0x61, 95},
 	{ 0x78,0x27,108},
-	{ 0xce,0x25,189},  /* TW: This was missing */
-	{ 0xff,0x1b,6625}
+	{ 0xce,0x25,189},
+	{ 0x45,0x6b, 21},  /* 0x36 */  /* TW: Added from Mitac */
+	{ 0xff,0x00,  0}
+};
+
+#if 0 /* TW: This table is in all BIOSes, but not used */
+static const SiS300_VCLKDataStruct  SiS300_VBVCLKData[]=
+{
+	{ 0x1b,0xe1, 25},
+	{ 0x4e,0xe4, 28},
+	{ 0x57,0xe4, 31},
+	{ 0xc3,0xc8, 36},
+	{ 0x42,0x47, 40},
+	{ 0x5d,0xc4, 44},
+	{ 0x52,0x47, 49},
+	{ 0x53,0x47, 50},
+	{ 0x6d,0x66, 56},
+	{ 0x5a,0x64, 65},
+	{ 0x46,0x44, 67},
+	{ 0x29,0x61, 75},
+	{ 0x6d,0x46, 75},
+	{ 0x41,0x43, 78},
+	{ 0x31,0x42, 79},
+	{ 0x46,0x25, 84},
+	{ 0x78,0x29, 86}, /* 0x10 */
+	{ 0x62,0x44, 94},
+	{ 0x2b,0x22,104},
+	{ 0x49,0x24,105},
+	{ 0x43,0x42,108},
+	{ 0x3c,0x23,109},
+	{ 0xe0,0x46,132},
+	{ 0x70,0x25,135},
+	{ 0x41,0x22,157},
+	{ 0x43,0x22,162},
+	{ 0x30,0x21,175},
+	{ 0xc1,0x24,189},
+	{ 0xde,0x26,194},
+	{ 0x70,0x07,202},
+	{ 0x3f,0x03,229},
+	{ 0x30,0x02,234},  /* 0x1f */
+	{ 0x24,0x01,265},  /* 0x20 */
+	{ 0x52,0x2a, 54},
+	{ 0x52,0x6a, 27},
+	{ 0x62,0x24, 70},
+	{ 0x62,0x64, 70},
+	{ 0xa8,0x4c, 30},
+	{ 0x20,0x26, 33},
+	{ 0x31,0xc2, 39},
+	{ 0x2e,0x48, 25},  /* 0x28 */
+	{ 0x24,0x46, 25},  /* 0x29 */
+	{ 0x26,0x64, 28},
+	{ 0x37,0x64, 40},
+	{ 0xa1,0x42,108},
+	{ 0x37,0x61,100},
+	{ 0x78,0x27,108},
+	{ 0xff,0x00,  0}
 };
+#endif
 
-/* TW: at 0x377d in BIOS */
-UCHAR SiS300_ScreenOffset[]=
+static const UCHAR  SiS300_ScreenOffset[] =
 {
 	0x14,0x19,0x20,0x28,0x32,0x40,0x50,
-        0x64,0x78,0x80,0x2d,0x35,0xff
+        0x64,0x78,0x80,0x2d,0x35,0x48,0xff
 };
 
 typedef struct _SiS300_StResInfoStruct
@@ -921,7 +962,7 @@
 	USHORT VTotal;
 } SiS300_StResInfoStruct;
 
-SiS300_StResInfoStruct  SiS300_StResInfo[]=
+static const SiS300_StResInfoStruct  SiS300_StResInfo[] =
 {
 	{ 640,400},
 	{ 640,350},
@@ -938,76 +979,91 @@
 	UCHAR  YChar;
 } SiS300_ModeResInfoStruct;
 
-SiS300_ModeResInfoStruct  SiS300_ModeResInfo[]=
-{ /* TW: At 0x5957 in BIOS */
-	{  320, 200, 8, 8},
-	{  320, 240, 8, 8},
-	{  320, 400, 8, 8},
-	{  400, 300, 8, 8},
-	{  512, 384, 8, 8},
-	{  640, 400, 8,16},
-	{  640, 480, 8,16},
-	{  800, 600, 8,16},
-	{ 1024, 768, 8,16},
-	{ 1280,1024, 8,16},
-	{ 1600,1200, 8,16},
-	{ 1920,1440, 8,16},
-	{ 2048,1536, 8,16},   /* TW: this was missing here, wasn't it? (not in BIOS) */
-	{  720, 480, 8,16},   /*     (otherwise RESINFO index is wrong!) */
-	{  720, 576, 8,16},
-	{ 1280, 960, 8,16}
-};
-
-UCHAR SiS300_OutputSelect =0x40;
-UCHAR SiS300_SoftSetting = 30;
-UCHAR SiS300_SR07=0x10;
-UCHAR SiS300_SR15[8][4]={
-	{0x1,0x9,0xa3,0x0},
-	{0x43,0x43,0x43,0x0},
-	{0x1e,0x1e,0x1e,0x0},
-	{0x2a,0x2a,0x2a,0x0},
-	{0x6,0x6,0x6,0x0},
-	{0x0,0x0,0x0,0x0},
-	{0x0,0x0,0x0,0x0},
-	{0x0,0x0,0x0,0x0}
-};
-UCHAR SiS300_SR1F=0x0;
-UCHAR SiS300_SR21=0x16;
-UCHAR SiS300_SR22=0xb2;
-UCHAR SiS300_SR23=0xf6;
-UCHAR SiS300_SR24=0xd;
-UCHAR SiS300_SR25[]={0x0,0x0};
-UCHAR SiS300_SR31=0x0;
-UCHAR SiS300_SR32=0x11;
-UCHAR SiS300_SR33=0x0;
-UCHAR SiS300_CRT2Data_1_2 = 0x40;
-UCHAR SiS300_CRT2Data_4_D = 0x0;
-UCHAR SiS300_CRT2Data_4_E = 0x0;
-UCHAR SiS300_CRT2Data_4_10 = 0x80;
-USHORT SiS300_RGBSenseData = 0xd1;
-USHORT SiS300_VideoSenseData = 0xb3;
-USHORT SiS300_YCSenseData = 0xb9;
-USHORT SiS300_RGBSenseData2 = 0x0190;     /*301b*/
-USHORT SiS300_VideoSenseData2 = 0x0174;
-USHORT SiS300_YCSenseData2 = 0x016b;
-
-UCHAR SiS300_CR40[5][4];
-UCHAR SiS300_CR49[2];
-UCHAR SiS300_NTSCPhase[]  = {0x21,0xed,0x8a,0x08};
-UCHAR SiS300_PALPhase[]   = {0x2a,0x05,0xd3,0x00};
-UCHAR SiS300_NTSCPhase2[] = {0x21,0xF0,0x7B,0xD6};/*301b*/
-UCHAR SiS300_PALPhase2[]  = {0x2a,0x09,0x86,0xe9};
-UCHAR SiS300_PALMPhase[]  = {0x21,0xE4,0x2E,0x9B};   /*palmn*/
-UCHAR SiS300_PALNPhase[]  = {0x21,0xF4,0x3E,0xBA};
+static const SiS300_ModeResInfoStruct  SiS300_ModeResInfo[] =
+{
+	{  320, 200, 8, 8},  /* 0x00 */
+	{  320, 240, 8, 8},  /* 0x01 */
+	{  320, 400, 8, 8},  /* 0x02 */
+	{  400, 300, 8, 8},  /* 0x03 */
+	{  512, 384, 8, 8},  /* 0x04 */
+	{  640, 400, 8,16},  /* 0x05 */
+	{  640, 480, 8,16},  /* 0x06 */
+	{  800, 600, 8,16},  /* 0x07 */
+	{ 1024, 768, 8,16},  /* 0x08 */
+	{ 1280,1024, 8,16},  /* 0x09 */
+	{ 1600,1200, 8,16},  /* 0x0a */
+	{ 1920,1440, 8,16},  /* 0x0b */
+	{  720, 480, 8,16},  /* 0x0c */
+	{  720, 576, 8,16},  /* 0x0d */
+	{ 1280, 960, 8,16},  /* 0x0e */
+	{ 1024, 600, 8,16},  /* 0x0f */
+	{ 1152, 768, 8,16}   /* 0x10 */
+};
+
+static const UCHAR SiS300_OutputSelect = 0x40;
+
+static const UCHAR SiS300_SoftSetting = 30;
+
+#ifndef LINUX_XF86
+static UCHAR SiS300_SR07 = 0x10;
+#endif
+
+static const UCHAR  SiS300_SR15[8][4] =
+{
+	{0x01,0x09,0xa3,0x00},
+	{0x43,0x43,0x43,0x00},
+	{0x1e,0x1e,0x1e,0x00},
+	{0x2a,0x2a,0x2a,0x00},
+	{0x06,0x06,0x06,0x00},
+	{0x00,0x00,0x00,0x00},
+	{0x00,0x00,0x00,0x00},
+	{0x00,0x00,0x00,0x00}
+};
+
+#ifndef LINUX_XF86
+static UCHAR SiS300_SR1F = 0x00;
+static UCHAR SiS300_SR21 = 0x16;
+static UCHAR SiS300_SR22 = 0xb2;
+static UCHAR SiS300_SR23 = 0xf6;
+static UCHAR SiS300_SR24 = 0x0d;
+static UCHAR SiS300_SR25[] = {0x0,0x0};
+static UCHAR SiS300_SR31 = 0x00;
+static UCHAR SiS300_SR32 = 0x11;
+static UCHAR SiS300_SR33 = 0x00;
+static UCHAR SiS300_CRT2Data_1_2 = 0x40;
+static UCHAR SiS300_CRT2Data_4_D = 0x00;
+static UCHAR SiS300_CRT2Data_4_E = 0x00;
+static UCHAR SiS300_CRT2Data_4_10 = 0x80;
+
+static const USHORT SiS300_RGBSenseData = 0xd1;
+static const USHORT SiS300_VideoSenseData = 0xb3;
+static const USHORT SiS300_YCSenseData = 0xb9;
+static const USHORT SiS300_RGBSenseData2 = 0x0190;     /*301b*/
+static const USHORT SiS300_VideoSenseData2 = 0x0174;
+static const USHORT SiS300_YCSenseData2 = 0x016b;
+
+static const UCHAR SiS300_CR40[5][4];
+
+static UCHAR SiS300_CR49[2];
+#endif
+
+static const UCHAR SiS300_NTSCPhase[]  = {0x21,0xed,0xba,0x08};  /* TW: Was {0x21,0xed,0x8a,0x08}; */
+static const UCHAR SiS300_PALPhase[]   = {0x2a,0x05,0xe3,0x00};  /* TW: Was {0x2a,0x05,0xd3,0x00};  */
+static const UCHAR SiS300_PALMPhase[]  = {0x21,0xE4,0x2E,0x9B};  /* palmn */
+static const UCHAR SiS300_PALNPhase[]  = {0x21,0xF4,0x3E,0xBA};
+static const UCHAR SiS300_NTSCPhase2[] = {0x21,0xF0,0x7B,0xD6};  /* 301b */
+static const UCHAR SiS300_PALPhase2[]  = {0x2a,0x09,0x86,0xe9};  /* 301b */
+static const UCHAR SiS300_PALMPhase2[] = {0x21,0xE6,0xEF,0xA4}; /* TW: palm 301b*/
+static const UCHAR SiS300_PALNPhase2[] = {0x21,0xF6,0x94,0x46}; /* TW: paln 301b*/
 
 typedef struct _SiS300_PanelDelayTblStruct
 {
 	UCHAR timer[2];
 } SiS300_PanelDelayTblStruct;
 
-SiS300_PanelDelayTblStruct SiS300_PanelDelayTbl[]=
+static const SiS300_PanelDelayTblStruct  SiS300_PanelDelayTbl[] =
 {
-	{{0x05,0xaa}},
+	{{0x05,0xaa}}, /* TW: From 2.04.5a */
 	{{0x05,0x14}},
 	{{0x05,0x36}},
 	{{0x05,0x14}},
@@ -1019,10 +1075,30 @@
 	{{0x05,0x14}},
 	{{0x05,0x14}},
 	{{0x05,0x14}},
-	{{0x05,0x64}},
+	{{0x20,0x80}},
+	{{0x05,0x14}},
+	{{0x05,0x40}},
+	{{0x05,0x60}}
+};
+
+static const SiS300_PanelDelayTblStruct  SiS300_PanelDelayTblLVDS[] =
+{
+	{{0x05,0xaa}},
+	{{0x05,0x14}},
+	{{0x05,0x36}},
+	{{0x05,0x14}},
+	{{0x05,0x14}},
+	{{0x05,0x14}},
+	{{0x05,0x90}},
+	{{0x05,0x90}},
 	{{0x05,0x14}},
 	{{0x05,0x14}},
-	{{0x05,0x14}}
+	{{0x05,0x14}},
+	{{0x05,0x14}},  /* 2.07a (JVC): 14,96 */
+	{{0x05,0x28}},  /* 2.04.5c: 20, 80 - Clevo (2.04.2c): 05, 28 */
+	{{0x05,0x14}},
+	{{0x05,0x14}},  /* Some BIOSes: 05, 40 */
+	{{0x05,0x60}}
 };
 
 typedef struct _SiS300_LCDDataStruct
@@ -1035,7 +1111,7 @@
 	USHORT LCDVT;
 } SiS300_LCDDataStruct;
 
-SiS300_LCDDataStruct  SiS300_StLCD1024x768Data[]=
+static const SiS300_LCDDataStruct  SiS300_StLCD1024x768Data[]=
 {
 	{   66,  31, 992, 510,1320, 816},
 	{   66,  31, 992, 510,1320, 816},
@@ -1046,7 +1122,7 @@
 	{    1,   1,1344, 806,1344, 806}
 };
 
-SiS300_LCDDataStruct  SiS300_ExtLCD1024x768Data[]=
+static const SiS300_LCDDataStruct  SiS300_ExtLCD1024x768Data[]=
 {
 	{   12,   5, 896, 512,1344, 806},
 	{   12,   5, 896, 510,1344, 806},
@@ -1063,7 +1139,7 @@
 	{    1,   1,1344, 806,1344, 806}
 };
 
-SiS300_LCDDataStruct  SiS300_St2LCD1024x768Data[]=
+static const SiS300_LCDDataStruct  SiS300_St2LCD1024x768Data[]=
 {
 	{   62,  25, 800, 546,1344, 806},
 	{   32,  15, 930, 546,1344, 806},
@@ -1074,7 +1150,7 @@
 	{    1,   1,1344, 806,1344, 806}
 };
 
-SiS300_LCDDataStruct  SiS300_StLCD1280x1024Data[]=
+static const SiS300_LCDDataStruct  SiS300_StLCD1280x1024Data[]=
 {
 	{    4,   1, 880, 510,1650,1088},
 	{    4,   1, 880, 510,1650,1088},
@@ -1086,7 +1162,7 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-SiS300_LCDDataStruct  SiS300_ExtLCD1280x1024Data[]=
+static const SiS300_LCDDataStruct  SiS300_ExtLCD1280x1024Data[]=
 {
 	{  211,  60,1024, 501,1688,1066},
 	{  211,  60,1024, 508,1688,1066},
@@ -1098,7 +1174,7 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-SiS300_LCDDataStruct  SiS300_St2LCD1280x1024Data[]=
+static const SiS300_LCDDataStruct  SiS300_St2LCD1280x1024Data[]=
 {
 	{   22,   5, 800, 510,1650,1088},
 	{   22,   5, 800, 510,1650,1088},
@@ -1110,7 +1186,19 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-SiS300_LCDDataStruct  SiS300_NoScaleData[]=
+static const SiS300_LCDDataStruct  SiS300_NoScaleData1024x768[]=
+{
+	{    1,   1, 800, 449, 800, 449},
+	{    1,   1, 800, 449, 800, 449},
+	{    1,   1, 900, 449, 900, 449},
+	{    1,   1, 900, 449, 900, 449},
+	{    1,   1, 800, 525, 800, 525},
+	{    1,   1,1056, 628,1056, 628},
+	{    1,   1,1344, 806,1344, 806},
+	{    1,   1,1688,1066,1688,1066}
+};
+
+static const SiS300_LCDDataStruct  SiS300_NoScaleData1280x1024[]=  /* TW: Fake */
 {
 	{    1,   1, 800, 449, 800, 449},
 	{    1,   1, 800, 449, 800, 449},
@@ -1122,7 +1210,7 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-SiS300_LCDDataStruct  SiS300_LCD1280x960Data[]=
+static const SiS300_LCDDataStruct  SiS300_LCD1280x960Data[]=
 {
 	{    9,   2, 800, 500,1800,1000},
 	{    9,   2, 800, 500,1800,1000},
@@ -1135,6 +1223,91 @@
 	{    1,   1,1800,1000,1800,1000}
 };
 
+static const SiS300_LCDDataStruct  SiS300_ExtLCD1400x1050Data[] =  /* TW: New */
+{
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS300_LCDDataStruct  SiS300_ExtLCD1600x1200Data[] =  /* TW: New */
+{
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS300_LCDDataStruct  SiS300_StLCD1400x1050Data[] =  /* TW: New */
+{
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS300_LCDDataStruct  SiS300_StLCD1600x1200Data[] =  /* TW: New */
+{
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS300_LCDDataStruct  SiS300_NoScaleData1400x1050[] =  /* TW: New */
+{
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS300_LCDDataStruct  SiS300_NoScaleData1600x1200[] =  /* TW: New */
+{
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+
 typedef struct _SiS300_TVDataStruct
 {
 	USHORT RVBHCMAX;
@@ -1152,7 +1325,7 @@
 	UCHAR RY4COE;
 } SiS300_TVDataStruct;
 
-SiS300_TVDataStruct  SiS300_StPALData[]=
+static const SiS300_TVDataStruct  SiS300_StPALData[]=
 {
 	{    1,   1, 864, 525,1270, 400, 100,   0, 760,0xf4,0xff,0x1c,0x22},
 	{    1,   1, 864, 525,1270, 350, 100,   0, 760,0xf4,0xff,0x1c,0x22},
@@ -1162,7 +1335,7 @@
 	{    1,   1, 864, 525,1270, 600,  50,   0,   0,0xf4,0xff,0x1c,0x22}
 };
 
-SiS300_TVDataStruct  SiS300_ExtPALData[]=
+static const SiS300_TVDataStruct  SiS300_ExtPALData[]=
 {
 	{   27,  10, 848, 448,1270, 530,  50,   0,  50,0xf4,0xff,0x1c,0x22},
 	{  108,  35, 848, 398,1270, 530,  50,   0,  50,0xf4,0xff,0x1c,0x22},
@@ -1171,11 +1344,11 @@
 	{    9,   4, 848, 528,1270, 530,   0,   0,  50,0xf5,0xfb,0x1b,0x2a},
 	{   36,  25,1060, 648,1316, 530, 438,   0, 438,0xeb,0x05,0x25,0x16},
 	{    3,   2,1080, 619,1270, 540, 438,   0, 438,0xf3,0x00,0x1d,0x20},
-	{    1,   1,1170, 821,1270, 520, 686,   0, 686,0xF3,0x00,0x1D,0x20}     /*301b*/
+	{    1,   1,1170, 821,1270, 520, 686,   0, 686,0xF3,0x00,0x1D,0x20}
 
 };
 
-SiS300_TVDataStruct  SiS300_StNTSCData[]=
+static const SiS300_TVDataStruct  SiS300_StNTSCData[]=
 {
 	{    1,   1, 858, 525,1270, 400,  50,   0, 760,0xf1,0x04,0x1f,0x18},
 	{    1,   1, 858, 525,1270, 350,  50,   0, 640,0xf1,0x04,0x1f,0x18},
@@ -1184,7 +1357,7 @@
 	{    1,   1, 858, 525,1270, 480,   0,   0, 760,0xf1,0x04,0x1f,0x18}
 };
 
-SiS300_TVDataStruct  SiS300_ExtNTSCData[]=
+static const SiS300_TVDataStruct  SiS300_ExtNTSCData[]=
 {
 	{  143,  65, 858, 443,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},
 	{   88,  35, 858, 393,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},
@@ -1193,59 +1366,128 @@
 	{  143,  76, 836, 523,1270, 440, 224,   0,   0,0xf1,0x05,0x1f,0x16},
 	{  143, 120,1056, 643,1270, 440,   0, 128,   0,0xf4,0x10,0x1c,0x00},
 	{  143,  76, 836, 523,1270, 440,   0, 128,   0,0xee,0x0c,0x22,0x08},
-	{   65,  64,1056, 791,1270, 480, 638,   0,   0,0xf1,0x04,0x1f,0x18} /*301b*/
+	{   65,  64,1056, 791,1270, 480, 638,   0,   0,0xf1,0x04,0x1f,0x18}
 };
 
-SiS_TVDataStruct  SiS300_St1HiTVData[]=
+static const SiS_TVDataStruct  SiS300_St1HiTVData[]=
 {
  	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
-SiS_TVDataStruct  SiS300_St2HiTVData[]=
+static const SiS_TVDataStruct  SiS300_St2HiTVData[]=
 {
  	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
-SiS_TVDataStruct  SiS300_ExtHiTVData[]=
+static const SiS_TVDataStruct  SiS300_ExtHiTVData[]=
 {
  	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
-UCHAR SiS300_NTSCTiming[] = {
+static const UCHAR SiS300_NTSCTiming[] = {
 	0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c,
 	0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a,
 	0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b,
-	0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17,
-	0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02,
+/*	0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17,   - old */
+	0x0c,0x50,0x00,0x99,0x00,0xec,0x4a,0x17,  /* new (2.04.5a) */
+/*	0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02,   - old */
+	0x88,0x00,0x4b,0x00,0x00,0xe2,0x00,0x02,  /* new */
 	0x03,0x0a,0x65,0x9d,0x08,0x92,0x8f,0x40,
 	0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x50,
 	0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00
 };
 
-UCHAR SiS300_PALTiming[] = {
+static const UCHAR SiS300_PALTiming[] = {
 	0x19,0x52,0x35,0x6e,0x04,0x38,0x3d,0x70,
 	0x94,0x49,0x01,0x12,0x06,0x3e,0x35,0x6d,
 	0x06,0x14,0x3e,0x35,0x6d,0x00,0x45,0x2b,
-	0x70,0x50,0x00,0x9b,0x00,0xd9,0x5d,0x17,
-	0x7d,0x05,0x45,0x00,0x00,0xe8,0x00,0x02,
+/*      0x70,0x50,0x00,0x9b,0x00,0xd9,0x5d,0x17,   - old */
+	0x70,0x50,0x00,0x97,0x00,0xd7,0x5d,0x17,  /* new */
+/*	0x7d,0x05,0x45,0x00,0x00,0xe8,0x00,0x02,   -old */
+	0x88,0x00,0x45,0x00,0x00,0xe8,0x00,0x02,  /* new */
 	0x0d,0x00,0x68,0xb0,0x0b,0x92,0x8f,0x40,
 	0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x63,
 	0x00,0x40,0x3e,0x00,0xe1,0x02,0x28,0x00
 };
 
-UCHAR SiS300_HiTVExtTiming[] = {0x00};
-
-UCHAR SiS300_HiTVSt1Timing[] = {0x00};
-
-UCHAR SiS300_HiTVSt2Timing[] = {0x00};
-
-UCHAR SiS300_HiTVTextTiming[] = {0x00};
-
-UCHAR SiS300_HiTVGroup3Data[] = {0x00};
-
-UCHAR SiS300_HiTVGroup3Simu[] = {0x00};
-
-UCHAR SiS300_HiTVGroup3Text[] = {0x00};
+#ifdef oldHV
+static const UCHAR SiS300_HiTVExtTiming[] = {   /* TW: New */
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x64,0x90,0x33,0x8c,0x18,0x36,0x3e,0x13,
+	0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40,
+	0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d,
+	0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00
+};
+
+static const UCHAR SiS300_HiTVSt1Timing[] = {   /* TW: New */
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x65,0x90,0x7b,0xa8,0x03,0xf0,0x87,0x03,
+	0x11,0x15,0x11,0xcf,0x10,0x11,0xcf,0x10,
+	0x35,0x35,0x3b,0x69,0x1d,0x92,0x0f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x86,
+	0xaf,0x5d,0x0e,0x00,0xfc,0xff,0x2d,0x00
+};
+
+static const UCHAR SiS300_HiTVSt2Timing[] = {   /* TW: New */
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x64,0x90,0x33,0x8c,0x18,0x36,0x3e,0x13,
+	0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40,
+	0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d,
+	0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00
+};
+
+static const UCHAR SiS300_HiTVTextTiming[] = {   /* TW: New */
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x65,0x90,0xe7,0xbc,0x03,0x0c,0x97,0x03,
+	0x14,0x78,0x14,0x08,0x20,0x14,0x08,0x20,
+	0xc8,0xc8,0x3b,0xd2,0x26,0x92,0x0f,0x40,
+        0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x96,
+	0x72,0x5c,0x11,0x00,0xfc,0xff,0x32,0x00
+};
+
+static const UCHAR SiS300_HiTVGroup3Data[] = {   /* TW: New */
+        0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x5f,
+	0x05,0x21,0xb2,0xb2,0x55,0x77,0x2a,0xa6,
+	0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20,
+	0x8c,0x6e,0x60,0x2e,0x58,0x48,0x72,0x44,
+	0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+	0x4f,0x7f,0x03,0xa8,0x7d,0x20,0x1a,0xa9,
+	0x14,0x05,0x03,0x7e,0x64,0x31,0x14,0x75,
+	0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+};
+
+static const UCHAR SiS300_HiTVGroup3Simu[] = {   /* TW: New */
+        0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x95,
+	0xdb,0x20,0xb8,0xb8,0x55,0x47,0x2a,0xa6,
+	0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20,
+	0x8c,0x6e,0x60,0x15,0x26,0xd3,0xe4,0x11,
+	0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+	0x67,0x36,0x01,0x47,0x0e,0x10,0xbe,0xb4,
+	0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75,
+	0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+};
+
+static const UCHAR SiS300_HiTVGroup3Text[] = {   /* TW: New */
+        0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0xa7,
+	0xf5,0x20,0xce,0xce,0x55,0x47,0x2a,0xa6,
+	0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20,
+	0x8c,0x6e,0x60,0x18,0x2c,0x0c,0x20,0x22,
+	0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+	0x93,0x3c,0x01,0x50,0x2f,0x10,0xf4,0xca,
+	0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75,
+	0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+};
+#endif
 
 typedef struct _SiS300_LVDSDataStruct
 {
@@ -1255,7 +1497,20 @@
 	USHORT LCDVT;
 } SiS300_LVDSDataStruct;
 
-SiS300_LVDSDataStruct  SiS300_LVDS800x600Data_1[]=
+static const SiS300_LVDSDataStruct  SiS300_LVDS320x480Data_1[]=
+{
+	{848, 433,400, 525},
+	{848, 389,400, 525},
+	{848, 433,400, 525},
+	{848, 389,400, 525},
+	{848, 518,400, 525},
+	{1056,628,400, 525},
+	{400, 525,400, 525},
+	{800, 449,1000, 644},
+	{800, 525,1000, 635}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LVDS800x600Data_1[]=
 {
 	{848, 433,1060, 629},
 	{848, 389,1060, 629},
@@ -1268,7 +1523,7 @@
 	{800, 525,1000, 635}
 };
 
-SiS300_LVDSDataStruct  SiS300_LVDS800x600Data_2[]=
+static const SiS300_LVDSDataStruct  SiS300_LVDS800x600Data_2[]=
 {
 	{1056, 628,1056, 628},
 	{1056, 628,1056, 628},
@@ -1281,7 +1536,33 @@
 	{800, 525,1000, 635}
 };
 
-SiS300_LVDSDataStruct  SiS300_LVDS1024x768Data_1[]=
+static const SiS300_LVDSDataStruct  SiS300_LVDS1024x768Data_1[]=
+{
+	{840, 438,1344, 806},
+	{840, 409,1344, 806},
+	{840, 438,1344, 806},
+	{840, 409,1344, 806},
+	{840, 518,1344, 806},
+	{1050, 638,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LVDS1024x768Data_2[]=
+{
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LVDS1280x1024Data_1[]=
 {
 	{840, 438,1344, 806},
 	{840, 409,1344, 806},
@@ -1294,7 +1575,7 @@
 	{800, 525,1280, 813}
 };
 
-SiS300_LVDSDataStruct  SiS300_LVDS1024x768Data_2[]=
+static const SiS300_LVDSDataStruct  SiS300_LVDS1280x1024Data_2[]=
 {
 	{1344, 806,1344, 806},
 	{1344, 806,1344, 806},
@@ -1307,7 +1588,62 @@
 	{800, 525,1280, 813}
 };
 
-SiS300_LVDSDataStruct  SiS300_LVDS1280x1024Data_1[]=
+static const SiS300_LVDSDataStruct  SiS300_LVDS1400x1050Data_1[]=   /* TW: New */
+{
+        {928, 416, 1688, 1066},
+	{928, 366, 1688, 1066},
+	{928, 416, 1688, 1066},
+	{928, 366, 1688, 1066},
+	{928, 496, 1688, 1066},
+	{1088, 616, 1688, 1066},
+	{1312, 784, 1688, 1066},
+	{1568, 1040, 1688, 1066},
+	{1688, 1066, 1688, 1066}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LVDS1400x1050Data_2[]=   /* TW: New */
+{
+        {1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+};
+
+/* TW: New: */
+static const SiS300_LVDSDataStruct  SiS300_LVDS1024x600Data_1[]=
+{
+	{840, 604,1344, 800},
+	{840, 560,1344, 800},
+	{840, 604,1344, 800},
+	{840, 560,1344, 800},
+	{840, 689,1344, 800},
+	{1050, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{800, 449,1280, 789},
+	{800, 525,1280, 785}
+};
+
+/* TW: New: */
+static const SiS300_LVDSDataStruct  SiS300_LVDS1024x600Data_2[]=
+{
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+/* TW: New: */
+static const SiS300_LVDSDataStruct  SiS300_LVDS1152x768Data_1[]=
 {
 	{840, 438,1344, 806},
 	{840, 409,1344, 806},
@@ -1320,7 +1656,8 @@
 	{800, 525,1280, 813}
 };
 
-SiS300_LVDSDataStruct  SiS300_LVDS1280x1024Data_2[]=
+/* TW: New: */
+static const SiS300_LVDSDataStruct  SiS300_LVDS1152x768Data_2[]=
 {
 	{1344, 806,1344, 806},
 	{1344, 806,1344, 806},
@@ -1333,7 +1670,20 @@
 	{800, 525,1280, 813}
 };
 
-SiS300_LVDSDataStruct  SiS300_LVDS640x480Data_1[]=
+/* TW: New in 650/LVDS BIOS - resolution unknown */
+static const SiS300_LVDSDataStruct  SiS300_LVDSXXXxXXXData_1[]=   /* TW: New */
+{
+        { 800, 449, 800, 449},
+	{ 800, 449, 800, 449},
+	{ 900, 449, 900, 449},
+	{ 900, 449, 900, 449},
+	{ 800, 525, 800, 525},
+	{1056, 628,1056, 628},
+	{1344, 806,1344, 806},
+	{1688, 806,1688, 806}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LVDS640x480Data_1[]=
 {
 	{800, 449, 800, 449},
 	{800, 449, 800, 449},
@@ -1346,8 +1696,90 @@
 	{1056, 628,1056, 628}
 };
 
+static const SiS300_LVDSDataStruct  SiS300_LVDS1280x960Data_1[]=   /* TW: New */
+{
+	{840, 438,1344, 806},
+	{840, 409,1344, 806},
+	{840, 438,1344, 806},
+	{840, 409,1344, 806},
+	{840, 518,1344, 806},
+	{1050, 638,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LVDS1280x960Data_2[]=   /* TW: New */
+{
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LCDA1400x1050Data_1[]=   /* TW: New */
+{	/* TW: Might be temporary (invalid) data */
+        {928, 416, 1688, 1066},
+	{928, 366, 1688, 1066},
+	{1008, 416, 1688, 1066},
+	{1008, 366, 1688, 1066},
+	{1200, 530, 1688, 1066},
+	{1088, 616, 1688, 1066},
+	{1312, 784, 1688, 1066},
+	{1568, 1040, 1688, 1066},
+	{1688, 1066, 1688, 1066}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LCDA1400x1050Data_2[]=   /* TW: New */
+{	/* TW: Temporary data. Not valid */
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LCDA1600x1200Data_1[]=   /* TW: New */
+{	/* TW: Temporary data. Not valid */
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LCDA1600x1200Data_2[]=   /* TW: New */
+{	/* TW: Temporary data. Not valid */
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0}
+};
+
+
 /* TW: New: */
-SiS300_LVDSDataStruct  SiS300_CHTVUNTSCData[]=
+static const SiS300_LVDSDataStruct  SiS300_CHTVUNTSCData[]=
 {
 	{840, 600, 840, 600},
 	{840, 600, 840, 600},
@@ -1357,7 +1789,7 @@
 	{1064, 750,1064, 750}
 };
 
-SiS300_LVDSDataStruct  SiS300_CHTVONTSCData[]=
+static const SiS300_LVDSDataStruct  SiS300_CHTVONTSCData[]=
 {
 	{840, 525, 840, 525},
 	{840, 525, 840, 525},
@@ -1367,7 +1799,7 @@
 	{1040, 700,1040, 700}
 };
 
-SiS300_LVDSDataStruct  SiS300_CHTVUPALData[]=
+static const SiS300_LVDSDataStruct  SiS300_CHTVUPALData[]=
 {
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
@@ -1377,7 +1809,7 @@
 	{936, 836, 936, 836}
 };
 
-SiS300_LVDSDataStruct  SiS300_CHTVOPALData[]=
+static const SiS300_LVDSDataStruct  SiS300_CHTVOPALData[]=
 {
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
@@ -1394,7 +1826,7 @@
 	USHORT LCDVDES;
 } SiS300_LVDSDesStruct;
 
-SiS300_LVDSDesStruct  SiS300_PanelType00_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType00_1[]=
 {
 	{0, 626},
 	{0, 624},
@@ -1407,7 +1839,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType01_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType01_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1420,7 +1852,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType02_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType02_1[]=
 {
 	{0, 626},
 	{0, 624},
@@ -1433,7 +1865,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType03_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType03_1[]=
 {
 	{ 8, 436},
 	{ 8, 440},
@@ -1446,7 +1878,7 @@
 	{1343, 794}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType04_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType04_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1459,7 +1891,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType05_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType05_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1472,7 +1904,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType06_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType06_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1485,7 +1917,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType07_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType07_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1498,7 +1930,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType08_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType08_1[]=
 {
 	{1059, 626},
 	{1059, 624},
@@ -1511,7 +1943,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType09_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType09_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1524,7 +1956,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0a_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0a_1[]=
 {
 	{1059, 626},
 	{1059, 624},
@@ -1537,20 +1969,20 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0b_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0b_1[]=
 {
-	{1343, 798},
-	{1343, 794},
-	{1343, 798},
-	{1343, 794},
-	{1343,   0},
-	{1343,   0},
-	{ 0, 805},
-	{ 0, 794},
-	{ 0,   0}
+	{1343, 0},
+	{1343, 0},
+	{1343, 0},
+	{1343, 0},
+	{1343, 0},   /* 640x480 - BIOS 1343, 0 */
+	{1343, 0},
+	{ 0, 799},
+	{ 0, 0},
+	{ 0, 0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0c_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0c_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1563,7 +1995,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0d_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0d_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1576,20 +2008,20 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0e_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0e_1[]=
 {
 	{1343, 798},
 	{1343, 794},
 	{1343, 798},
 	{1343, 794},
-	{1343,   0},
-	{1343,   0},
-	{ 0, 805},
-	{ 0, 794},
-	{ 0,   0}
+	{1343,   0},  /* 640x480 */
+	{1343,   0},  /* 800x600 */
+	{ 0, 805},    /* 1024x768 */
+	{ 0, 794},    /* 1280x1024 */
+	{ 0,   0}     /* 1280x960 - not applicable */
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0f_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0f_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1602,7 +2034,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType00_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType00_2[]=
 {
 	{976, 527},
 	{976, 502},
@@ -1615,7 +2047,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType01_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType01_2[]=
 {
 	{1152, 622},
 	{1152, 597},
@@ -1628,7 +2060,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType02_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType02_2[]=
 {
 	{976, 527},
 	{976, 502},
@@ -1641,7 +2073,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType03_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType03_2[]=
 {
 	{1152, 622},
 	{1152, 597},
@@ -1654,7 +2086,7 @@
 	{1152, 597}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType04_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType04_2[]=
 {
 	{1152, 622},
 	{1152, 597},
@@ -1667,7 +2099,7 @@
 	{   0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType05_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType05_2[]=
 {
 	{1152, 622},
 	{1152, 597},
@@ -1680,7 +2112,7 @@
 	{   0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType06_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType06_2[]=
 {
 	{1152, 622},
 	{1152, 597},
@@ -1693,7 +2125,7 @@
 	{   0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType07_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType07_2[]=
 {
  	{1152, 622},
  	{1152, 597},
@@ -1706,7 +2138,7 @@
 	{   0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType08_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType08_2[]=
 {
  	{976, 527},
  	{976, 502},
@@ -1719,7 +2151,7 @@
  	{  0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType09_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType09_2[]=
 {
  	{1152, 622},
  	{1152, 597},
@@ -1732,7 +2164,7 @@
  	{   0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0a_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0a_2[]=
 {
  	{976, 527},
  	{976, 502},
@@ -1745,20 +2177,20 @@
  	{  0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0b_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0b_2[]=
 {
- 	{1152, 622},
- 	{1152, 597},
- 	{1152, 622},
- 	{1152, 597},
- 	{1152, 662},
- 	{1232, 722},
- 	{   0, 805},
- 	{   0, 794},
- 	{   0,   0}
+ 	{ 1152, 700},
+ 	{ 1152, 675},
+ 	{ 1152, 700},
+ 	{ 1152, 675},
+ 	{ 1152, 740},
+ 	{ 1232, 799},
+ 	{    0, 799},
+ 	{    0,   0},
+ 	{    0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0c_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0c_2[]=
 {
  	{1152, 622},
  	{1152, 597},
@@ -1771,7 +2203,7 @@
  	{   0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0d_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0d_2[]=
 {
  	{1152, 622},
  	{1152, 597},
@@ -1784,7 +2216,7 @@
  	{   0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0e_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0e_2[]=
 {
  	{1152, 622},
  	{1152, 597},
@@ -1797,7 +2229,7 @@
  	{   0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0f_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0f_2[]=
 {
  	{1152, 622},
  	{1152, 597},
@@ -1810,35 +2242,87 @@
  	{   0,   0}
 };
 
-/*301b*/
-SiS300_LVDSDesStruct SiS300_PanelType1076_1[]=
+static const SiS300_LVDSDesStruct SiS300_PanelType1076_1[]=   /* TW: New */
 {
-	{0x00,0x00}
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS300_LVDSDesStruct SiS300_PanelType1076_2[]=   /* TW: New */
+{
+	{ 1152, 622 },
+	{ 1152, 597 },
+	{ 1152, 622 },
+	{ 1152, 597 },
+	{ 1152, 622 },
+	{ 1232, 722 },
+	{    0, 0   },
+	{    0, 794 },
+	{    0, 0   }
+};
+
+static const SiS300_LVDSDesStruct SiS300_PanelType1210_1[]=   /* TW: New */
+{
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS300_LVDSDesStruct SiS300_PanelType1210_2[]=   /* TW: New */
+{
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS300_LVDSDesStruct SiS300_PanelType1296_1[]=   /* TW: New */
+{
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS300_LVDSDesStruct SiS300_PanelType1296_2[]=   /* TW: New */
+{
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
 };
-SiS300_LVDSDesStruct SiS300_PanelType1210_1[]=
-{
-	{0x00,0x00}
-};
-SiS300_LVDSDesStruct SiS300_PanelType1296_1[]=
-{
-	{0x00,0x00}
-};
-SiS300_LVDSDesStruct SiS300_PanelType1076_2[]=
-{
-	{0x00,0x00}
-};
-SiS300_LVDSDesStruct SiS300_PanelType1210_2[]=
-{
-	{0x00,0x00}
-};
-SiS300_LVDSDesStruct SiS300_PanelType1296_2[]=
-{
-	{0x00,0x00}
-};
-/*end 301b*/
+
 
 /* TW: New */
-SiS300_LVDSDesStruct  SiS300_CHTVUNTSCDesData[]=
+static const SiS300_LVDSDesStruct  SiS300_CHTVUNTSCDesData[]=
 {
  	{ 0,   0},
  	{ 0,   0},
@@ -1848,7 +2332,7 @@
  	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_CHTVONTSCDesData[]=
+static const SiS300_LVDSDesStruct  SiS300_CHTVONTSCDesData[]=
 {
  	{ 0,   0},
  	{ 0,   0},
@@ -1858,7 +2342,7 @@
  	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_CHTVUPALDesData[]=
+static const SiS300_LVDSDesStruct  SiS300_CHTVUPALDesData[]=
 {
  	{256,   0},
  	{256,   0},
@@ -1868,7 +2352,7 @@
  	{  0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_CHTVOPALDesData[]=
+static const SiS300_LVDSDesStruct  SiS300_CHTVOPALDesData[]=
 {
  	{256,   0},
  	{256,   0},
@@ -1884,7 +2368,7 @@
 UCHAR CR[15];
 } SiS300_LVDSCRT1DataStruct;
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_1[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_1[]=
 {
 	{{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
 	  0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
@@ -1906,7 +2390,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_1[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_1[]=
 { 
 	{{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f,
 	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
@@ -1931,7 +2415,7 @@
 	  0x01} }
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_1[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_1[]=
 {
 	{{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
 	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
@@ -1956,7 +2440,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_1_H[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_1_H[]=
 {
 	{{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
 	  0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
@@ -1978,7 +2462,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_1_H[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_1_H[]=
 {
 	{{0x37,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
 	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
@@ -2003,7 +2487,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_1_H[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_1_H[]=
 {
 	{{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
 	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
@@ -2028,7 +2512,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_2[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_2[]=
 {
 	{{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
 	  0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
@@ -2050,7 +2534,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2[]=
 {
 	{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
 	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
@@ -2075,7 +2559,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_2[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_2[]=
 {
 	{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
 	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
@@ -2100,7 +2584,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_2_H[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_2_H[]=
 {
 	{{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
 	  0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
@@ -2122,7 +2606,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2_H[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2_H[]=
 {
 	{{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
 	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
@@ -2147,7 +2631,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_2_H[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_2_H[]=
 {
 	{{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
 	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
@@ -2172,8 +2656,208 @@
 	  0x01}}
 };
 
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x600_1[] =
+{
+        {{0x64,0x4f,0x88,0x54,0x9f,0x5a,0x3e,
+	  0xe8,0x8f,0x8f,0x5b,0x00,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x2e,0x3e,
+	  0xb9,0x80,0x5d,0x2f,0x00,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x5a,0x3e,
+	  0xe8,0x8f,0x8f,0x5b,0x00,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x2e,0x3e,
+	  0xb9,0x80,0x5d,0x2f,0x00,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0xaf,0xba,
+	  0x3b,0x82,0xdf,0xb0,0x00,0x00,0x01,
+	  0x00}},
+        {{0x7e,0x63,0x82,0x68,0x15,0x1e,0xf1,
+	  0xae,0x85,0x57,0x1f,0x30,0x00,0x26,
+	  0x01}},
+        {{0xa3,0x7f,0x87,0x86,0x97,0x1e,0xf1,
+	  0xae,0x85,0x57,0x1f,0x30,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x600_1_H[] =
+{
+        {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+          0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
+	  0xe2,0x89,0xdf,0x05,0x00,0x00,0x44,
+	  0x00}},
+        {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
+	  0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
+	  0x01}},
+        {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x600_2[] =
+{
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+          0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+	  0x01}},
+        {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x600_2_H[] =
+{
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+	  0x01}},
+        {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11152x768_1[] =
+{
+        {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x04,0x3e,
+	  0xe2,0x89,0xdf,0x05,0x00,0x00,0x01,
+	  0x00}},
+        {{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0,
+	  0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26,
+	  0x01}},
+        {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11152x768_1_H[] =
+{
+        {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
+	  0xe2,0x89,0xdf,0x05,0x00,0x00,0x44,
+	  0x00}},
+        {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
+	  0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
+	  0x01}},
+        {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11152x768_2[] =
+{
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+	  0x01}},
+        {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11152x768_2_H[] =
+{
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+	  0x01}},
+        {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
 /* TW: New */
-SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1UNTSC[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1UNTSC[]=
 {
 	{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
 	  0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
@@ -2195,7 +2879,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1ONTSC[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1ONTSC[]=
 {
 	{{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
 	  0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
@@ -2217,7 +2901,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1UPAL[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1UPAL[]=
 {
 	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
 	  0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
@@ -2239,7 +2923,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1OPAL[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1OPAL[]=
 {
 	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
 	  0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
@@ -2265,58 +2949,58 @@
 /* TW: New */
 typedef struct _SiS300_CHTVRegDataStruct
 {
-	UCHAR Reg[5];
+	UCHAR Reg[16];
 } SiS300_CHTVRegDataStruct;
 
-SiS300_CHTVRegDataStruct SiS300_CHTVReg_UNTSC[] = {
-	{{0x4a,0x94,0x00,0x48,0xfe}},
-	{{0x4a,0x94,0x00,0x48,0xfe}},
-	{{0x4a,0x94,0x00,0x48,0xfe}},
-	{{0x4a,0x94,0x00,0x48,0xfe}},
-	{{0x6a,0x6a,0x00,0x2d,0xfa}}, /* Mode 17: 640x480 NTSC 7/8  */
-	{{0x8d,0xc4,0x00,0x3b,0xfb}}  /* Mode 24: 800x600 NTSC 7/10 */
-};
-
-SiS300_CHTVRegDataStruct SiS300_CHTVReg_ONTSC[] = {
-	{{0x49,0x94,0x00,0x34,0xfe}},
-	{{0x49,0x94,0x00,0x34,0xfe}},
-	{{0x49,0x94,0x00,0x34,0xfe}},
-	{{0x49,0x94,0x00,0x34,0xfe}},
-	{{0x69,0x6a,0x00,0x1e,0xfd}}, /* Mode 16: 640x480 NTSC 1/1 */
-	{{0x8c,0xb4,0x00,0x32,0xf9}}  /* Mode 23: 800x600 NTSC 3/4 */
-};
-
-SiS300_CHTVRegDataStruct SiS300_CHTVReg_UPAL[] = {
-	{{0x41,0x12,0x01,0x50,0x34}},
-	{{0x41,0x12,0x00,0x50,0x00}},
-	{{0x41,0x12,0x01,0x50,0x34}},
-	{{0x41,0x12,0x00,0x50,0x00}},
-	{{0x63,0x94,0x01,0x50,0x30}}, /* Mode 15: 640x480 PAL 5/6 */
+static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_UNTSC[] = {
+	{{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x6a,0x6a,0x00,0x2d,0xfa,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 17: 640x480 NTSC 7/8  */
+	{{0x8d,0xc4,0x00,0x3b,0xfb,0,0,0,0,0,0,0,0,0,0,0}}  /* Mode 24: 800x600 NTSC 7/10 */
+};
+
+static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_ONTSC[] = {
+	{{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x69,0x6a,0x00,0x1e,0xfd,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 16: 640x480 NTSC 1/1 */
+	{{0x8c,0xb4,0x00,0x32,0xf9,0,0,0,0,0,0,0,0,0,0,0}}  /* Mode 23: 800x600 NTSC 3/4 */
+};
+
+static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_UPAL[] = {
+	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x63,0x94,0x01,0x50,0x30,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 15: 640x480 PAL 5/6 */
 	/* TW: For 800x600, 3/4 is VERY underscan */
-	{{0x84,0x64,0x01,0x4e,0x2f}}  /* Mode 21: 800x600 PAL 3/4 */
+	{{0x84,0x64,0x01,0x4e,0x2f,0,0,0,0,0,0,0,0,0,0,0}}  /* Mode 21: 800x600 PAL 3/4 */
 	/* TW: Mode 20 is still underscan, use it instead? */
 	/* {{0x83,0x76,0x01,0x40,0x31}} */ /* Mode 20: 800x600 PAL 5/6 */
 };
 
-SiS300_CHTVRegDataStruct SiS300_CHTVReg_OPAL[] = {
-	{{0x41,0x12,0x01,0x50,0x34}}, /* Mode 9: 640x400 PAL 1/1 */
-	{{0x41,0x12,0x00,0x50,0x00}},
-	{{0x41,0x12,0x01,0x50,0x34}},
-	{{0x41,0x12,0x00,0x50,0x00}},
-	{{0x61,0x94,0x01,0x36,0x30}}, /* Mode 14: 640x480 PAL 1/1 */
-	{{0x83,0x76,0x01,0x40,0x31}}  /* Mode 20: 800x600 PAL 5/6 */
+static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_OPAL[] = {
+	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 9: 640x400 PAL 1/1 */
+	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x61,0x94,0x01,0x36,0x30,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 14: 640x480 PAL 1/1 */
+	{{0x83,0x76,0x01,0x40,0x31,0,0,0,0,0,0,0,0,0,0,0}}  /* Mode 20: 800x600 PAL 5/6 */
 	/* {{0x81,0x12,0x01,0x50,0x34}}  */ /* TW: (test) Mode 19: 800x600 PAL 1/1 */
 };
 /* TW: New end */
 
 /* TW: New */
-UCHAR SiS300_CHTVVCLKUNTSC[] = {0x29,0x29,0x29,0x29,0x2a,0x2e};
+static const UCHAR SiS300_CHTVVCLKUNTSC[] = {0x29,0x29,0x29,0x29,0x2a,0x2e};
 
-UCHAR SiS300_CHTVVCLKONTSC[] = {0x2c,0x2c,0x2c,0x2c,0x2d,0x2b};
+static const UCHAR SiS300_CHTVVCLKONTSC[] = {0x2c,0x2c,0x2c,0x2c,0x2d,0x2b};
 
-UCHAR SiS300_CHTVVCLKUPAL[]  = {0x2f,0x2f,0x2f,0x2f,0x2f,0x31};
+static const UCHAR SiS300_CHTVVCLKUPAL[]  = {0x2f,0x2f,0x2f,0x2f,0x2f,0x31};
 
-UCHAR SiS300_CHTVVCLKOPAL[]  = {0x2f,0x2f,0x2f,0x2f,0x30,0x32};
+static const UCHAR SiS300_CHTVVCLKOPAL[]  = {0x2f,0x2f,0x2f,0x2f,0x30,0x32};
 /* TW: New end */
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/310vtbl.h linux-2.4.20/drivers/video/sis/310vtbl.h
--- linux-2.4.19/drivers/video/sis/310vtbl.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/310vtbl.h	2002-10-29 11:18:32.000000000 +0000
@@ -1,3 +1,8 @@
+
+
+/* Register settings for SiS 310/325 series */
+
+
 typedef struct _SiS310_StStruct
 {
 	UCHAR St_ModeID;
@@ -10,7 +15,7 @@
 	UCHAR VB_StTVYFilterIndex;
 } SiS310_StStruct;
 
-SiS310_StStruct SiS310_SModeIDTable[]=
+static const SiS310_StStruct SiS310_SModeIDTable[]=
 {
 	{0x01,0x9208,0x01,0x00,0x00,0x00,0x01,0x00},
 	{0x01,0x1210,0x14,0x01,0x01,0x00,0x01,0x00},
@@ -47,7 +52,7 @@
 	UCHAR GRC[9];
 } SiS310_StandTableStruct;
 
-SiS310_StandTableStruct SiS310_StandTable[]=
+static const SiS310_StandTableStruct SiS310_StandTable[]=
 {
 /* MD_0_200 */
  {
@@ -490,7 +495,7 @@
 	UCHAR Ext_ModeID;
 	USHORT Ext_ModeFlag;
 	USHORT Ext_ModeInfo;
-	USHORT Ext_Point;
+	USHORT Ext_Point;    /* TW: Address of table entry in (older) BIOS image */
 	USHORT Ext_VESAID;
 	UCHAR Ext_VESAMEMSize;
 	UCHAR Ext_RESINFO;
@@ -500,66 +505,89 @@
 	UCHAR REFindex;
 } SiS310_ExtStruct;
 
-SiS310_ExtStruct  SiS310_EModeIDTable[]=
+/* TW: Checked with 650/LVDS and 650/301LVx 1.10.6s */
+static const SiS310_ExtStruct  SiS310_EModeIDTable[]=
 {
-	{0x6a,0x2212,0x0407,0x3a81,0x0102,0x08,0x07,0x00,0x00,0x07,0x00},
-	{0x2e,0x0a1b,0x0306,0x3a57,0x0101,0x08,0x06,0x00,0x00,0x05,0x08},
-	{0x2f,0x0a1b,0x0305,0x3a50,0x0100,0x08,0x05,0x00,0x00,0x05,0x10},
-	{0x30,0x2a1b,0x0407,0x3a81,0x0103,0x08,0x07,0x00,0x00,0x07,0x00},
-	{0x31,0x0a1b,0x030d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},
-	{0x32,0x0a1b,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},
-	{0x33,0x0a1d,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},
-	{0x34,0x2a1d,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},
-	{0x35,0x0a1f,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},
-	{0x36,0x2a1f,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},
-	{0x37,0x0212,0x0508,0x3aab,0x0104,0x08,0x08,0x00,0x00,0x00,0x13},
-	{0x38,0x0a1b,0x0508,0x3aab,0x0105,0x08,0x08,0x00,0x00,0x00,0x13},
-	{0x3a,0x0e3b,0x0609,0x3adc,0x0107,0x08,0x09,0x00,0x00,0x00,0x1a},
-	{0x3c,0x063b,0x070a,0x3af2,0x0130,0x08,0x0a,0x00,0x00,0x00,0x1e},
-	{0x3d,0x067d,0x070a,0x3af2,0x0131,0x08,0x0a,0x00,0x00,0x00,0x1e},
+	{0x6a,0x2212,0x0407,0x3a81,0x0102,0x08,0x07,0x00,0x00,0x07,0x00},          /* 800x600x? */
+	{0x2e,0x0a1b,0x0306,0x3a57,0x0101,0x08,0x06,0x00,0x00,0x05,0x08},          /* 640x480x8 */
+/*	{0x2e,0x021b,0x0306,0x3a57,0x0101,0x08,0x06,0x00,0x00,0x05,0x08},    */    /* 640x480x8 - 650/LVDS BIOS (no CRt2Mode) */
+	{0x2f,0x0a1b,0x0305,0x3a50,0x0100,0x08,0x05,0x00,0x00,0x05,0x10},          /* 640x400x8 */
+/*	{0x2f,0x021b,0x0305,0x3a50,0x0100,0x08,0x05,0x00,0x00,0x05,0x10},    */    /* 640x400x8 - 650/LVDS BIOS (no CRt2Mode) */
+	{0x30,0x2a1b,0x0407,0x3a81,0x0103,0x08,0x07,0x00,0x00,0x07,0x00},          /* 800x600x8 */
+/*	{0x30,0x221b,0x0407,0x3a81,0x0103,0x08,0x07,0x00,0x00,0x07,0x00},    */    /* 800x600x8 - 650/LVDS BIOS (no CRt2Mode) */
+/*      {0x31,0x0a1b,0x030d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},    */    /* 720x480x8 */
+        {0x31,0x0a1b,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},          /* 720x480x8 BIOS (301/LVDS) */
+	{0x32,0x0a1b,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},          /* 720x576x8 */
+	{0x33,0x0a1d,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},          /* 720x480x16 */
+	{0x34,0x2a1d,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},          /* 720x576x16 */
+	{0x35,0x0a1f,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},          /* 720x480x32 */
+	{0x36,0x2a1f,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},          /* 720x576x32 */
+	{0x37,0x0212,0x0508,0x3aab,0x0104,0x08,0x08,0x00,0x00,0x00,0x13},          /* 1024x768x? */
+	{0x38,0x0a1b,0x0508,0x3aab,0x0105,0x08,0x08,0x00,0x00,0x00,0x13},          /* 1024x768x8 */
+/*	{0x38,0x021b,0x0508,0x3aab,0x0105,0x08,0x08,0x00,0x00,0x00,0x13},    */    /* 1024x768x8 - 650/LVDS BIOS (no CRt2Mode)  */
+	{0x3a,0x0e3b,0x0609,0x3adc,0x0107,0x08,0x09,0x00,0x00,0x00,0x1a},          /* 1280x1024x8 */
+/*	{0x3a,0x063b,0x0609,0x3adc,0x0107,0x08,0x09,0x00,0x00,0x00,0x1a},    */    /* 1280x1024x8 - 650/LVDS BIOS*/
+	{0x3c,0x0e3b,0x070a,0x3af2,0x0130,0x08,0x0a,0x00,0x00,0x00,0x1e},          /* 1600x1200x8 */
+/*	{0x3c,0x063b,0x070a,0x3af2,0x0130,0x08,0x0a,0x00,0x00,0x00,0x1e},    */    /* 1600x1200x8 - 650/LVDS BIOS */
+	{0x3d,0x067d,0x070a,0x3af2,0x0131,0x08,0x0a,0x00,0x00,0x00,0x1e},          /* 1600x1200x16 - 650/301LVx - no CRT2Mode? */
 	{0x40,0x9a1c,0x0000,0x3a34,0x010d,0x08,0x00,0x00,0x00,0x04,0x25},
 	{0x41,0x9a1d,0x0000,0x3a34,0x010e,0x08,0x00,0x00,0x00,0x04,0x25},
 	{0x43,0x0a1c,0x0306,0x3a57,0x0110,0x08,0x06,0x00,0x00,0x05,0x08},
-	{0x44,0x0a1d,0x0306,0x3a57,0x0111,0x08,0x06,0x00,0x00,0x05,0x08},
+	{0x44,0x0a1d,0x0306,0x3a57,0x0111,0x08,0x06,0x00,0x00,0x05,0x08},          /* 640x480x16 */
 	{0x46,0x2a1c,0x0407,0x3a81,0x0113,0x08,0x07,0x00,0x00,0x07,0x00},
-	{0x47,0x2a1d,0x0407,0x3a81,0x0114,0x08,0x07,0x00,0x00,0x07,0x00},
+	{0x47,0x2a1d,0x0407,0x3a81,0x0114,0x08,0x07,0x00,0x00,0x07,0x00},          /* 800x600x16 */
 	{0x49,0x0a3c,0x0508,0x3aab,0x0116,0x08,0x08,0x00,0x00,0x00,0x13},
-	{0x4a,0x0a3d,0x0508,0x3aab,0x0117,0x08,0x08,0x00,0x00,0x00,0x13},
+	{0x4a,0x0a3d,0x0508,0x3aab,0x0117,0x08,0x08,0x00,0x00,0x00,0x13},          /* 1024x768x16 */
 	{0x4c,0x0e7c,0x0609,0x3adc,0x0119,0x08,0x09,0x00,0x00,0x00,0x1a},
-	{0x4d,0x0e7d,0x0609,0x3adc,0x011a,0x08,0x09,0x00,0x00,0x00,0x1a},
+	{0x4d,0x0e7d,0x0609,0x3adc,0x011a,0x08,0x09,0x00,0x00,0x00,0x1a},          /* 1280x1024x16 */
 	{0x50,0x9a1b,0x0001,0x3a3b,0x0132,0x08,0x01,0x00,0x00,0x04,0x26},
+/*	{0x50,0x921b,0x0001,0x3a3b,0x0132,0x08,0x01,0x00,0x00,0x04,0x26},     */   /* 650/LVDS BIOS */
 	{0x51,0xba1b,0x0103,0x3a42,0x0133,0x08,0x03,0x00,0x00,0x07,0x27},
-	{0x52,0x9a1b,0x0204,0x3a49,0x0134,0x08,0x04,0x00,0x00,0x00,0x28},
+/*	{0x52,0x9a1b,0x0204,0x3a49,0x0134,0x08,0x04,0x00,0x00,0x00,0x28},  */
+  	{0x52,0xba1b,0x0204,0x3a49,0x0134,0x08,0x04,0x00,0x00,0x00,0x28},          /* 650/301 BIOS */
+/*	{0x52,0xb21b,0x0204,0x3a49,0x0134,0x08,0x04,0x00,0x00,0x00,0x28},     */   /* 650/LVDS BIOS (no CRT2Mode) */
 	{0x56,0x9a1d,0x0001,0x3a3b,0x0135,0x08,0x01,0x00,0x00,0x04,0x26},
 	{0x57,0xba1d,0x0103,0x3a42,0x0136,0x08,0x03,0x00,0x00,0x07,0x27},
-	{0x58,0x9a1d,0x0204,0x3a49,0x0137,0x08,0x04,0x00,0x00,0x00,0x28},
+/*	{0x58,0x9a1d,0x0204,0x3a49,0x0137,0x08,0x04,0x00,0x00,0x00,0x28},  */
+ 	{0x58,0xba1d,0x0204,0x3a49,0x0137,0x08,0x04,0x00,0x00,0x00,0x28},          /* BIOS (301+LVDS) */
 	{0x59,0x9a1b,0x0000,0x3a34,0x0138,0x08,0x00,0x00,0x00,0x04,0x25},
-	{0x5A,0x021b,0x0014,0x3b83,0x0138,0x08,0x01,0x00,0x00,0x04,0x3f}, /*fstn add new mode*/
-	{0x5B,0x0a1d,0x0014,0x3b83,0x0135,0x08,0x01,0x00,0x00,0x04,0x3f}, /*fstn add new mode*/
+/*	{0x59,0x921b,0x0000,0x3a34,0x0138,0x08,0x00,0x00,0x00,0x04,0x25},     */   /* 650/LVDS BIOS (no CRT2Mode) */
+	{0x5A,0x021b,0x0014,0x3b83,0x0138,0x08,0x01,0x00,0x00,0x04,0x3f},          /* 320x480x8 fstn add new mode*/
+	{0x5B,0x0a1d,0x0014,0x3b83,0x0135,0x08,0x01,0x00,0x00,0x04,0x3f},          /* 320x480x16 fstn add new mode*/
+	{0x5c,0xba1f,0x0204,0x3a49,0x0000,0x08,0x04,0x00,0x00,0x00,0x28},          /* TW: inserted 512x384x32 */
 	{0x5d,0x0a1d,0x0305,0x3a50,0x0139,0x08,0x05,0x00,0x00,0x07,0x10},
-	{0x62,0x0a3f,0x0306,0x3a57,0x013a,0x08,0x06,0x00,0x00,0x05,0x08},
-	{0x63,0x2a3f,0x0407,0x3a81,0x013b,0x08,0x07,0x00,0x00,0x07,0x00},
-	{0x64,0x0a7f,0x0508,0x3aab,0x013c,0x08,0x08,0x00,0x00,0x00,0x13},
-	{0x65,0x0eff,0x0609,0x3adc,0x013d,0x08,0x09,0x00,0x00,0x00,0x1a},
-	{0x66,0x06ff,0x070a,0x3af2,0x013e,0x08,0x0a,0x00,0x00,0x00,0x1e},
-	{0x68,0x067b,0x080b,0x3b17,0x013f,0x08,0x0b,0x00,0x00,0x00,0x29},
-	{0x69,0x06fd,0x080b,0x3b17,0x0140,0x08,0x0b,0x00,0x00,0x00,0x29},
-	{0x6b,0x07ff,0x080b,0x3b17,0x0141,0x10,0x0b,0x00,0x00,0x00,0x29},
-	{0x6c,0x067b,0x090c,0x3b37,0x0000,0x08,0x0c,0x00,0x00,0x00,0x2f},
-	{0x6d,0x06fd,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f},
-	{0x6e,0x07ff,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f},
-	{0x70,0x2a1b,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},
-	{0x71,0x0a1b,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},
-	{0x74,0x0a1d,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},
-	{0x75,0x0a3d,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},
-	{0x76,0x2a1f,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},
-	{0x77,0x0a1f,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},
-	{0x78,0x0a3f,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},
-	{0x79,0x0a3b,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},
-	{0x7a,0x2a1d,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},
-	{0x7b,0x0e3b,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},
-	{0x7c,0x0e7d,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},
-	{0x7d,0x0eff,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},
+	{0x62,0x0a3f,0x0306,0x3a57,0x013a,0x08,0x06,0x00,0x00,0x05,0x08},          /* 640x480x32 */
+	{0x63,0x2a3f,0x0407,0x3a81,0x013b,0x08,0x07,0x00,0x00,0x07,0x00},          /* 800x600x32 */
+	{0x64,0x0a7f,0x0508,0x3aab,0x013c,0x08,0x08,0x00,0x00,0x00,0x13},          /* 1024x768x32 */
+	{0x65,0x0eff,0x0609,0x3adc,0x013d,0x08,0x09,0x00,0x00,0x00,0x1a},          /* 1280x1024x32 */
+	{0x66,0x06ff,0x070a,0x3af2,0x013e,0x08,0x0a,0x00,0x00,0x00,0x1e},          /* 1600x1200x32 */
+	{0x68,0x067b,0x080b,0x3b17,0x013f,0x08,0x0b,0x00,0x00,0x00,0x29},          /* 1920x1440x8 */
+	{0x69,0x06fd,0x080b,0x3b17,0x0140,0x08,0x0b,0x00,0x00,0x00,0x29},          /* 1920x1440x16 */
+	{0x6b,0x07ff,0x080b,0x3b17,0x0141,0x10,0x0b,0x00,0x00,0x00,0x29},          /* 1920x1440x32 */
+	{0x6c,0x067b,0x090c,0x3b37,0x0000,0x08,0x0c,0x00,0x00,0x00,0x2f},          /* 2048x1536x8 */
+	{0x6d,0x06fd,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f},          /* 2048x1536x16 */
+	{0x6e,0x07ff,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f},          /* 2048x1536x32 */
+	{0x70,0x2a1b,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},          /* 800x480x8 */
+	{0x71,0x0a1b,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},          /* 1024x576x8 */
+	{0x74,0x0a1d,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},          /* 1024x576x16 */
+	{0x75,0x0a3d,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},	   /* 1280x720x16 */
+	{0x76,0x2a1f,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},          /* 800x480x32 */
+	{0x77,0x0a1f,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},	   /* 1024x576x32 */
+	{0x78,0x0a3f,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},	   /* 1280x720x32 */
+	{0x79,0x0a3b,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},	   /* 1280x720x8 */
+	{0x7a,0x2a1d,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},          /* 800x480x16 */
+	{0x7c,0x0e3b,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},          /* 1280x960x8 - TW */
+	{0x7d,0x0e7d,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},          /* 1280x960x16 - TW */
+	{0x7e,0x0eff,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},          /* 1280x960x32 - TW */
+        /* TW: 650/LVDS BIOS new modes */
+/*	{0x23,0x063b,0x0614,0x36f7,0x0000,0x08,0x14,0x00,0x00,0x00,0x40},  */      /* 1280x768x8 - 650/LVDS BIOS */
+	{0x23,0x0e3b,0x0614,0x36f7,0x0000,0x08,0x14,0x00,0x00,0x00,0x40},          /* 1280x768x8 */
+	{0x24,0x0e7d,0x0614,0x36f7,0x0000,0x08,0x14,0x00,0x00,0x00,0x40},          /* 1280x768x16 */
+	{0x25,0x0eff,0x0614,0x36f7,0x0000,0x08,0x14,0x00,0x00,0x00,0x40},          /* 1280x768x32 */
+	{0x26,0x0e3b,0x0c15,0x36fe,0x0000,0x08,0x15,0x00,0x00,0x00,0x41},          /* 1400x1050x8 */
+/*	{0x26,0x063b,0x0c15,0x36fe,0x0000,0x08,0x15,0x00,0x00,0x00,0x41},    */    /* 1400x1050x8 - 650/LVDS BIOS */
+	{0x27,0x0e7d,0x0c15,0x36fe,0x0000,0x08,0x15,0x00,0x00,0x00,0x41},          /* 1400x1050x16 */
+	{0x28,0x0eff,0x0c15,0x36fe,0x0000,0x08,0x15,0x00,0x00,0x00,0x41},          /* 1400x1050x32*/
 	{0xff,0x0000,0x0000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
@@ -575,9 +603,10 @@
 	USHORT ROM_OFFSET;
 } SiS310_Ext2Struct;
 
-SiS310_Ext2Struct SiS310_RefIndex[]=
+static const SiS310_Ext2Struct SiS310_RefIndex[]=
 {
-	{0x005f,0x0d,0x03,0x05,0x6a, 800, 600,0x3a81}, /* 0x0 */
+/*	{0x005f,0x0d,0x03,0x05,0x6a, 800, 600,0x3a81},    0x0 - TW: Patch for Chrontel 7019  */
+	{0x085f,0x0d,0x03,0x05,0x6a, 800, 600,0x3a81}, /* 0x0 */
 	{0x0467,0x0e,0x04,0x05,0x6a, 800, 600,0x3a86}, /* 0x1 */
 	{0x0067,0x0f,0x08,0x48,0x6a, 800, 600,0x3a8b}, /* 0x2 */
 	{0x0067,0x10,0x07,0x8b,0x6a, 800, 600,0x3a90}, /* 0x3 */
@@ -585,7 +614,8 @@
 	{0x4147,0x12,0x0d,0x00,0x6a, 800, 600,0x3a9a}, /* 0x5 */
 	{0x4047,0x13,0x13,0x00,0x6a, 800, 600,0x3a9f}, /* 0x6 */
 	{0x4047,0x14,0x1c,0x00,0x6a, 800, 600,0x3aa4}, /* 0x7 */
-	{0xc05f,0x05,0x00,0x04,0x2e, 640, 480,0x3a57}, /* 0x8 */
+/*	{0xc05f,0x05,0x00,0x04,0x2e, 640, 480,0x3a57},    0x8 - TW: Patch for Chrontel 7019  */
+	{0xc85f,0x05,0x00,0x04,0x2e, 640, 480,0x3a57}, /* 0x8 */
 	{0xc067,0x06,0x02,0x04,0x2e, 640, 480,0x3a5c}, /* 0x9 */
 	{0xc067,0x07,0x02,0x47,0x2e, 640, 480,0x3a61}, /* 0xa */
 	{0xc067,0x08,0x03,0x8a,0x2e, 640, 480,0x3a66}, /* 0xb */
@@ -638,9 +668,11 @@
 	{0x0057,0x38,0x19,0x0a,0x75,1280, 720,0x3b74}, /* 0x3a */
 	{0x0047,0x39,0x1e,0x0a,0x75,1280, 720,0x3b79}, /* 0x3b */
 	{0x0047,0x3a,0x20,0x0a,0x75,1280, 720,0x3b7e}, /* 0x3c */
-	{0x0027,0x3b,0x19,0x08,0x7b,1280, 960,0x3ad0}, /* 0x3d */
-	{0x0027,0x3b,0x19,0x08,0x7b,1280, 960,0x3ad5}, /* 0x3e */
-	{0xc07f,0x01,0x00,0x06,0x5a, 320, 480,0x3b83}, /* 0x3f */    /*fstn add new mode */
+	{0x0027,0x3b,0x19,0x08,0x7c,1280, 960,0x3ad0}, /* 0x3d */
+	{0x0027,0x3b,0x19,0x08,0x7c,1280, 960,0x3ad5}, /* 0x3e */
+	{0xc07f,0x01,0x00,0x06,0x5a, 320, 480,0x3b83}, /* 0x3f */    /* FSTN mode */
+        {0x0077,0x42,0x12,0x07,0x23,1280, 768,0x0000}, /* 0x40 */    /* TW: 650/LVDS/301LVx new mode */
+	{0x0067,0x43,0x4d,0x08,0x26,1400,1050,0x0000}, /* 0x41 */    /* TW: 650/LVDS/301LVx new mode */
 	{0xffff,0x00,0x00,0x00,0x00,0000,0000,0x0000}
 };
 
@@ -648,203 +680,214 @@
 {
  	UCHAR CR[17];
 } SiS310_CRT1TableStruct;
-SiS310_CRT1TableStruct SiS310_CRT1Table[]=
+
+static const SiS310_CRT1TableStruct SiS310_CRT1Table[]=
 {
  {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
-  0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
-  0x00}}, /* 0x0 */
+   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
+   0x00}}, /* 0x0 */
  {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
-  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
-  0x00}}, /* 0x1 */
+   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
+   0x00}}, /* 0x1 */
  {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
-  0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
-  0x01}}, /* 0x2 */
+   0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
+   0x01}}, /* 0x2 */
  {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
-  0x01}}, /* 0x3 */
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
+   0x01}}, /* 0x3 */
  {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-  0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
-  0x00}}, /* 0x4 */
+   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
+   0x00}}, /* 0x4 */
  {{0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
-  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
-  0x00}}, /* 0x5 */
+   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
+   0x00}}, /* 0x5 */
  {{0x63,0x4f,0x50,0x86,0x56,0x9b,0x06,0x3e,
-  0xe8,0x8b,0xdf,0xe7,0xff,0x10,0x00,0x01,
-  0x00}}, /* 0x6 */
+   0xe8,0x8b,0xdf,0xe7,0xff,0x10,0x00,0x01,
+   0x00}}, /* 0x6 */
  {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f,
-  0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
-  0x00}}, /* 0x7 */
+   0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
+   0x00}}, /* 0x7 */
  {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f,
-  0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
-  0x00}}, /* 0x8 */
+   0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
+   0x00}}, /* 0x8 */
  {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f,
-  0xe0,0x83,0xdf,0xdf,0xfc,0x00,0x00,0x05,
-  0x61}}, /* 0x9 */
+   0xe0,0x83,0xdf,0xdf,0xfc,0x00,0x00,0x05,
+   0x61}}, /* 0x9 */
  {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e,
-  0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
-  0x61}}, /* 0xa */
+   0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
+   0x61}}, /* 0xa */
  {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e,
-  0xe0,0x83,0xdf,0xdf,0x0e,0x10,0x00,0x05,
-  0x61}}, /* 0xb */
+   0xe0,0x83,0xdf,0xdf,0x0e,0x10,0x00,0x05,
+   0x61}}, /* 0xb */
  {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f,
-  0xe6,0x8a,0xe5,0xe5,0xfc,0x00,0x00,0x01,
-  0x00}}, /* 0xc */
+   0xe6,0x8a,0xe5,0xe5,0xfc,0x00,0x00,0x01,
+   0x00}}, /* 0xc */
  {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
-  0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
-  0x01}}, /* 0xd */
+   0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
+   0x01}}, /* 0xd */
  {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-  0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
-  0x01}}, /* 0xe */
+   0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
+   0x01}}, /* 0xe */
  {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0,
-  0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
-  0x01}}, /* 0xf */
+   0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
+   0x01}}, /* 0xf */
  {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0,
-  0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
-  0x01}}, /* 0x10 */
+   0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
+   0x01}}, /* 0x10 */
  {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0,
-  0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
-  0x01}}, /* 0x11 */
+   0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
+   0x01}}, /* 0x11 */
  {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0,
-  0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06,
-  0x61}}, /* 0x12 */
+   0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06,
+   0x61}}, /* 0x12 */
  {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0,
-  0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06,
-  0x61}}, /* 0x13 */
+   0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06,
+   0x61}}, /* 0x13 */
  {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0,
-  0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06,
-  0x61}}, /* 0x14 */
+   0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06,
+   0x61}}, /* 0x14 */
  {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
-  0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
-  0x00}}, /* 0x15 */
+   0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
+   0x00}}, /* 0x15 */
  {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-  0x01}}, /* 0x16 */
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+   0x01}}, /* 0x16 */
  {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5,
-  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-  0x01}}, /* 0x17 */
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+   0x01}}, /* 0x17 */
  {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5,
-  0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
-  0x01}}, /* 0x18 */
+   0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
+   0x01}}, /* 0x18 */
  {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5,
-  0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
-  0x01}}, /* 0x19 */
+   0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
+   0x01}}, /* 0x19 */
  {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5,
-  0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02,
-  0x62}}, /* 0x1a */
+   0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02,
+   0x62}}, /* 0x1a */
  {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5,
-  0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02,
-  0x62}}, /* 0x1b */
+   0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02,
+   0x62}}, /* 0x1b */
  {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba,
-  0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
-  0x00}}, /* 0x1c */
+   0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
+   0x00}}, /* 0x1c */
  {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
-  0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
-  0x01}}, /* 0x1d */
+   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
+   0x01}}, /* 0x1d */
  {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,
-  0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
-  0x01}}, /* 0x1e */
+   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
+   0x01}}, /* 0x1e */
  {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
-  0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
-  0x01}}, /* 0x1f */
+   0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
+   0x01}}, /* 0x1f */
  {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}}, /* 0x20 */
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x20 */
  {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}}, /* 0x21 */
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x21 @ 4084 */
  {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}}, /* 0x22 */
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x22 */
  {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}}, /* 0x23 */
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x23 */
  {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}}, /* 0x24 */
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x24 */
  {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}}, /* 0x25 */
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x25 */
  {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}}, /* 0x26 */
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x26 */
  {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-  0x00}}, /* 0x27 */
+   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
+   0x00}}, /* 0x27 */
  {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05,
-  0x63}}, /* 0x28 */
+   0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05,
+   0x63}}, /* 0x28 */
  {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05,
-  0x63}}, /* 0x29 */
+   0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05,
+   0x63}}, /* 0x29 */
  {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-  0x00}}, /* 0x2a */
+   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
+   0x00}}, /* 0x2a */
  {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-  0x00}}, /* 0x2b */
+   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
+   0x00}}, /* 0x2b */
  {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-  0x00}}, /* 0x2c */
+   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
+   0x00}}, /* 0x2c */
  {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba,
-  0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05,
-  0x44}}, /* 0x2d */
+   0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05,
+   0x44}}, /* 0x2d */
  {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba,
-  0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05,
-  0x44}}, /* 0x2e */
+   0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05,
+   0x44}}, /* 0x2e */
  {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba,
-  0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05,
-  0x44}}, /* 0x2f */
+   0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05,
+   0x44}}, /* 0x2f */
  {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba,
-  0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05,
-  0x44}}, /* 0x30 */
+   0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05,
+   0x44}}, /* 0x30 */
  {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
-  0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
-  0x00}}, /* 0x31 */
+   0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
+   0x00}}, /* 0x31 */
  {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,
-  0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
-  0x01}}, /* 0x32 */
+   0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
+   0x01}}, /* 0x32 */
  {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
-  0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
-  0x01}}, /* 0x33 */
+   0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
+   0x01}}, /* 0x33 */
  {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba,
-  0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
-  0x01}}, /* 0x34 */
+   0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
+   0x01}}, /* 0x34 */
  {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1,
-  0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
-  0x01}}, /* 0x35 */
+   0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
+   0x01}}, /* 0x35 */
  {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
-  0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
-  0x01}}, /* 0x36 */
+   0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
+   0x01}}, /* 0x36 */
  {{0xa7,0x7f,0x7f,0x88,0x89,0x15,0x26,0xf1,
-  0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
-  0x01}}, /* 0x37 */
+   0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
+   0x01}}, /* 0x37 */
  {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
-  0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
-  0x01}}, /* 0x38 */
+   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
+   0x01}}, /* 0x38 */
  {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4,
-  0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
-  0x01}}, /* 0x39 */
+   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
+   0x01}}, /* 0x39 */
  {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
-  0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
-  0x01}}, /* 0x3a */
+   0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
+   0x01}}, /* 0x3a */
  {{0xdc,0x9f,0x9f,0x00,0xab,0x19,0xe6,0xef,
-  0xc0,0xc3,0xbf,0xbf,0xe7,0x10,0x00,0x07,
-  0x01}}, /* 0x3b */
+   0xc0,0xc3,0xbf,0xbf,0xe7,0x10,0x00,0x07,
+   0x01}}, /* 0x3b */
  {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
-  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
-  0x00}}, /* 0x3c */
+   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
+   0x00}}, /* 0x3c */
  {{0x7b,0x59,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
-  0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05,
-  0x01}}, /* 0x3d */
+   0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05,
+   0x01}}, /* 0x3d */
  {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15,
-  0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02,
-  0x00}},/*3e*/
-  {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,
-  0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
-  0x00}} ,/*3f*/
-  {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
-  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
-  0x00}}/*40*/ 
+   0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02,
+   0x00}}, /* 0x3e */
+ {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,
+   0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
+   0x00}}, /* 0x3f */
+ /* TW: New from 650/LVDS BIOS */
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,
+   0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
+   0x01}},  /* 0x40 */
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+   0x01}},  /* 0x41 */
+ {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5,
+   0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07,
+   0x01}},  /* 0x42 */
+ {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10,
+   0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03,
+   0x00}}   /* 0x43 */
 };
 
 typedef struct _SiS310_MCLKDataStruct
@@ -853,20 +896,49 @@
 	USHORT CLOCK;
 } SiS310_MCLKDataStruct;
 
-SiS310_MCLKDataStruct SiS310_MCLKData[]=
+static const SiS310_MCLKDataStruct SiS310_MCLKData_0_315[] =
 {
+	{ 0x3b,0x22,0x01,143},   /* TW: Was { 0x5c,0x23,0x01,166}, */
+	{ 0x5c,0x23,0x01,166},
+	{ 0x5c,0x23,0x01,166},
+	{ 0x5c,0x23,0x01,166},
 	{ 0x5c,0x23,0x01,166},
 	{ 0x5c,0x23,0x01,166},
 	{ 0x5c,0x23,0x01,166},
 	{ 0x5c,0x23,0x01,166}
 };
 
+static const SiS310_MCLKDataStruct SiS310_MCLKData_0_650[] =	/* @ 0x54 */
+{
+	{ 0x5a,0x64,0x82, 66},
+	{ 0xb3,0x45,0x82, 83},
+	{ 0x37,0x61,0x82,100},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x61,0x82,100},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x22,0x82,133}
+};
+
+static const SiS310_MCLKDataStruct SiS310_MCLKData_1[] =	/* @ 0x155 */
+{
+        { 0x29,0x21,0x82,150},
+	{ 0x5c,0x23,0x82,166},
+	{ 0x65,0x23,0x82,183},
+	{ 0x37,0x21,0x82,200},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x22,0x82,133}
+};
+
 typedef struct _SiS310_ECLKDataStruct
 {
  	UCHAR SR2E,SR2F,SR30;
  	USHORT CLOCK;
 } SiS310_ECLKDataStruct;
-SiS310_ECLKDataStruct SiS310_ECLKData[]=
+
+static const SiS310_ECLKDataStruct SiS310_ECLKData[]=
 {
 	{ 0x5c,0x23,0x01,166},
 	{ 0x5c,0x23,0x01,166},
@@ -880,9 +952,9 @@
 	USHORT CLOCK;
 } SiS310_VCLKDataStruct;
 
-SiS310_VCLKDataStruct SiS310_VCLKData[]=
+static const SiS310_VCLKDataStruct SiS310_VCLKData[]=
 {
-	{ 0x1b,0xe1, 25}, /* 0x0 */
+	{ 0x1b,0xe1, 25}, /* 0x0 */   /* 650/LVDS BIOS: @ 0x5647 */
 	{ 0x4e,0xe4, 28}, /* 0x1 */
 	{ 0x57,0xe4, 31}, /* 0x2 */
 	{ 0xc3,0xc8, 36}, /* 0x3 */
@@ -893,7 +965,7 @@
 	{ 0x53,0xe2, 50}, /* 0x8 */
 	{ 0x74,0x67, 52}, /* 0x9 */
 	{ 0x6d,0x66, 56}, /* 0xa */
-	{ 0x6c,0xc3, 65}, /* 0xb */
+	{ 0x5a,0x64, 65}, /* 0xb */   /* TW: was 6c c3 - WRONG */
 	{ 0x46,0x44, 67}, /* 0xc */
 	{ 0xb1,0x46, 68}, /* 0xd */
 	{ 0xd3,0x4a, 72}, /* 0xe */
@@ -946,7 +1018,28 @@
 	{ 0x62,0x64, 70}, /* 0x3d */
 	{ 0xa8,0x4c, 30}, /* 0x3e */
 	{ 0x20,0x26, 33}, /* 0x3f */
-	{ 0x31,0xc2, 39}  /* 0x40 */
+	{ 0x31,0xc2, 39}, /* 0x40 */
+	/* TW: 650/LVDS BIOS @ 0x574b new: */
+	{ 0x60,0x36, 30}, /* 0x41 */  /* Chrontel */
+	{ 0x40,0x4a, 28}, /* 0x42 */  /* Chrontel */
+	{ 0x9f,0x46, 44}, /* 0x43 */  /* Chrontel */
+	{ 0x97,0x2c, 26}, /* 0x44 */
+	{ 0x44,0xe4, 25}, /* 0x45 */  /* Chrontel */
+	{ 0x7e,0x32, 47}, /* 0x46 */  /* Chrontel */
+	{ 0x8a,0x24, 31}, /* 0x47 */  /* Chrontel */
+	{ 0x97,0x2c, 26}, /* 0x48 */  /* Chrontel */
+	{ 0xce,0x3c, 39}, /* 0x49 */
+	{ 0x52,0x4a, 36}, /* 0x4a */  /* Chrontel */
+	{ 0x34,0x61, 95}, /* 0x4b */
+	{ 0x78,0x27,108}, /* 0x4c - was 102 */  /* TW: Last entry in 650/301 BIOS */
+	{ 0x66,0x43,123}, /* 0x4d */  /* Modes 0x26-0x28 (1400x1050) */
+	{ 0x41,0x4e, 21}, /* 0x4e */
+	{ 0xa1,0x4a, 29}, /* 0x4f */  /* Chrontel */
+	{ 0x19,0x42, 42}, /* 0x50 */
+	{ 0x54,0x46, 58}, /* 0x51 */  /* Chrontel */
+	{ 0x25,0x42, 61}, /* 0x52 */
+	{ 0x44,0x44, 66}, /* 0x53 */  /* Chrontel */
+	{ 0x3a,0x62, 70}  /* 0x54 */  /* Chrontel */
 };
 
 typedef struct _SiS310_VBVCLKDataStruct
@@ -955,9 +1048,9 @@
 	USHORT CLOCK;
 } SiS310_VBVCLKDataStruct;
 
-SiS310_VBVCLKDataStruct SiS310_VBVCLKData[]=
+static const SiS310_VBVCLKDataStruct SiS310_VBVCLKData[]=
 {
-	{ 0x1b,0xe1, 25}, /* 0x0 */
+	{ 0x1b,0xe1, 25}, /* 0x0 */   /* 650/LVDS BIOS: @ 0x579c */
 	{ 0x4e,0xe4, 28}, /* 0x1 */
 	{ 0x57,0xe4, 31}, /* 0x2 */
 	{ 0xc3,0xc8, 36}, /* 0x3 */
@@ -968,7 +1061,7 @@
 	{ 0x53,0x47, 50}, /* 0x8 */
 	{ 0x74,0x67, 52}, /* 0x9 */
 	{ 0x6d,0x66, 56}, /* 0xa */
-	{ 0x5a,0x64, 65}, /* 0xb */
+	{ 0x35,0x62, 65}, /* 0xb */  /* Was 0x5a,0x64 - 650/LVDS+301 bios: 35,62  */
 	{ 0x46,0x44, 67}, /* 0xc */
 	{ 0xb1,0x46, 68}, /* 0xd */
 	{ 0xd3,0x4a, 72}, /* 0xe */
@@ -1021,11 +1114,21 @@
 	{ 0x62,0x64, 70}, /* 0x3d */
 	{ 0xa8,0x4c, 30}, /* 0x3e */
 	{ 0x20,0x26, 33}, /* 0x3f */
-	{ 0x31,0xc2, 39}  /* 0x40 */
+	{ 0x31,0xc2, 39}, /* 0x40 */
+	/* TW: 650/LVDS+301 BIOS (@ 0x58a0 in LVDS) new: */
+	{ 0x2e,0x48, 25}, /* 0x41 */
+	{ 0x24,0x46, 25}, /* 0x42 */
+	{ 0x26,0x64, 28}, /* 0x43 */
+	{ 0x37,0x64, 40}, /* 0x44 */
+	{ 0xa1,0x42,108}, /* 0x45 */
+	{ 0x37,0x61,100}, /* 0x46 */
+	{ 0x78,0x27,108}  /* 0x47 */
+	/* --- 0x58bc --- */
 };
 
-UCHAR SiS310_ScreenOffset[]= { 0x14,0x19,0x20,0x28,0x32,0x40,
-                               0x50,0x64,0x78,0x80,0x2d,0x35};
+static const UCHAR SiS310_ScreenOffset[]=
+         { 0x14,0x19,0x20,0x28,0x32,0x40,
+           0x50,0x64,0x78,0x80,0x2d,0x35,0x57};  /* TW: Added 1400x1050 offset */
 
 typedef struct _SiS310_StResInfoStruct
 {
@@ -1033,7 +1136,7 @@
 	USHORT VTotal;
 } SiS310_StResInfoStruct;
 
-SiS310_StResInfoStruct SiS310_StResInfo[]=
+static const SiS310_StResInfoStruct SiS310_StResInfo[]=
 {
 	{ 640,400},
 	{ 640,350},
@@ -1050,47 +1153,52 @@
 	UCHAR  YChar;
 } SiS310_ModeResInfoStruct;
 
-SiS310_ModeResInfoStruct SiS310_ModeResInfo[]=
+static const SiS310_ModeResInfoStruct SiS310_ModeResInfo[]=
 {
-	{  320, 200, 8, 8},
-	{  320, 240, 8, 8},
-	{  320, 400, 8, 8},
-	{  400, 300, 8, 8},
-	{  512, 384, 8, 8},
-	{  640, 400, 8,16},
-	{  640, 480, 8,16},
-	{  800, 600, 8,16},
-	{ 1024, 768, 8,16},
-	{ 1280,1024, 8,16},
-	{ 1600,1200, 8,16},
-	{ 1920,1440, 8,16},
-	{ 2048,1536, 8,16},
-	{  720, 480, 8,16},
-	{  720, 576, 8,16},
-	{ 1280, 960, 8,16},
-	{  800, 480, 8,16},
-	{ 1024, 576, 8,16},
-	{ 1280, 720, 8,16}
+	{  320, 200, 8, 8},   /* 0x00 */
+	{  320, 240, 8, 8},   /* 0x01 */
+	{  320, 400, 8, 8},   /* 0x02 */
+	{  400, 300, 8, 8},   /* 0x03 */
+	{  512, 384, 8, 8},   /* 0x04 */
+	{  640, 400, 8,16},   /* 0x05 */
+	{  640, 480, 8,16},   /* 0x06 */
+	{  800, 600, 8,16},   /* 0x07 */
+	{ 1024, 768, 8,16},   /* 0x08 */
+	{ 1280,1024, 8,16},   /* 0x09 */
+	{ 1600,1200, 8,16},   /* 0x0a */
+	{ 1920,1440, 8,16},   /* 0x0b */
+	{ 2048,1536, 8,16},   /* 0x0c */
+	{  720, 480, 8,16},   /* 0x0d */
+	{  720, 576, 8,16},   /* 0x0e */
+	{ 1280, 960, 8,16},   /* 0x0f */
+	{  800, 480, 8,16},   /* 0x10 */
+	{ 1024, 576, 8,16},   /* 0x11 */
+	{ 1280, 720, 8,16},   /* 0x12 */
+	{  856, 480, 8,16},   /* 0x13 19; TW: New */
+	{ 1280, 768, 8,16},   /* 0x14 20; TW: New */
+	{ 1400,1050, 8,16}    /* 0x15 21; TW: New */
 };
 
-UCHAR SiS310_OutputSelect =0x40;
-
-UCHAR SiS310_SoftSetting = 30;
+static const UCHAR SiS310_OutputSelect = 0x40;
 
-UCHAR SiS310_SR07=0x18;
+static const UCHAR SiS310_SoftSetting  = 0x30;   /* TW: RAM setting */
 
-UCHAR SiS310_SR15[8][4]={
+static const UCHAR SiS310_SR15[8][4]={
 	{0x00,0x04,0x60,0x60},
 	{0x0f,0x0f,0x0f,0x0f},
 	{0xba,0xba,0xba,0xba},
 	{0xa9,0xa9,0xac,0xac},
 	{0xa0,0xa0,0xa0,0xa8},
 	{0x00,0x00,0x02,0x02},
-	{0x30,0x30,0x40,0x40},
+ 	{0x30,0x30,0x40,0x40},
 	{0x00,0xa5,0xfb,0xf6}
 };
 
-UCHAR SiS310_CR40[5][4]={
+#ifndef LINUX_XF86
+
+static UCHAR SiS310_SR07 = 0x18;
+
+static const UCHAR SiS310_CR40[5][4]={
 	{0x77,0x77,0x33,0x33},
 	{0x77,0x77,0x33,0x33},
 	{0x00,0x00,0x00,0x00},
@@ -1098,32 +1206,37 @@
 	{0x00,0x00,0xf0,0xf8}
 };
 
-UCHAR SiS310_CR49[]={0xaa,0x88};
-UCHAR SiS310_SR1F=0x0;
-UCHAR SiS310_SR21=0xa5;
-UCHAR SiS310_SR22=0xfb;
-UCHAR SiS310_SR23=0xf6;
-UCHAR SiS310_SR24=0xd;
-UCHAR SiS310_SR25[]={0x33,0x3};
-UCHAR SiS310_SR31=0x0;
-UCHAR SiS310_SR32=0x11;
-UCHAR SiS310_SR33=0x0;
-UCHAR SiS310_CRT2Data_1_2 = 0x0;
-UCHAR SiS310_CRT2Data_4_D = 0x0;
-UCHAR SiS310_CRT2Data_4_E = 0x0;
-UCHAR SiS310_CRT2Data_4_10 = 0x80;
-USHORT SiS310_RGBSenseData = 0xd1;
-USHORT SiS310_VideoSenseData = 0xb9;
-USHORT SiS310_YCSenseData = 0xb3;
-USHORT SiS310_RGBSenseData2 = 0x0190;     /*301b*/
-USHORT SiS310_VideoSenseData2 = 0x0174;
-USHORT SiS310_YCSenseData2 = 0x016b;
-UCHAR SiS310_NTSCPhase[] = {0x21,0xed,0x8a,0x8};
-UCHAR SiS310_PALPhase[] = {0x2a,0x5,0xd3,0x0};
-UCHAR SiS310_NTSCPhase2[] = {0x21,0xF0,0x7B,0xD6};/*301b*/
-UCHAR SiS310_PALPhase2[] = {0x2a,0x09,0x86,0xe9};
-UCHAR SiS310_PALMPhase[] = {0x21,0xE4,0x2E,0x9B};   /*palmn*/
-UCHAR SiS310_PALNPhase[] = {0x21,0xF4,0x3E,0xBA};
+static UCHAR SiS310_CR49[] = {0xaa,0x88};
+static UCHAR SiS310_SR1F = 0x00;
+static UCHAR SiS310_SR21 = 0xa5;
+static UCHAR SiS310_SR22 = 0xfb;
+static UCHAR SiS310_SR23 = 0xf6;
+static UCHAR SiS310_SR24 = 0x0d;
+static UCHAR SiS310_SR25[] = {0x33,0x3};
+static UCHAR SiS310_SR31 = 0x00;
+static UCHAR SiS310_SR32 = 0x11;
+static UCHAR SiS310_SR33 = 0x00;
+static UCHAR SiS310_CRT2Data_1_2  = 0x00;
+static UCHAR SiS310_CRT2Data_4_D  = 0x00;
+static UCHAR SiS310_CRT2Data_4_E  = 0x00;
+static UCHAR SiS310_CRT2Data_4_10 = 0x80;
+static const USHORT SiS310_RGBSenseData    = 0xd1;
+static const USHORT SiS310_VideoSenseData  = 0xb9;
+static const USHORT SiS310_YCSenseData     = 0xb3;
+static const USHORT SiS310_RGBSenseData2   = 0x0190;     /*301b*/
+static const USHORT SiS310_VideoSenseData2 = 0x0174;
+static const USHORT SiS310_YCSenseData2    = 0x016b;
+#endif
+
+static const UCHAR SiS310_NTSCPhase[]    = {0x21,0xed,0xba,0x08};  /* TW: Was {0x21,0xed,0x8a,0x08}; */
+static const UCHAR SiS310_PALPhase[]     = {0x2a,0x05,0xe3,0x00};  /* TW: Was {0x2a,0x05,0xd3,0x00}; */
+static const UCHAR SiS310_PALMPhase[]    = {0x21,0xE4,0x2E,0x9B};  /* TW: palm*/
+static const UCHAR SiS310_PALNPhase[]    = {0x21,0xF4,0x3E,0xBA};  /* TW: paln*/
+static const UCHAR SiS310_NTSCPhase2[]   = {0x21,0xF0,0x7B,0xD6};
+static const UCHAR SiS310_PALPhase2[]    = {0x2a,0x09,0x86,0xe9};
+static const UCHAR SiS310_PALMPhase2[]   = {0x21,0xE6,0xEF,0xA4};  /* TW: palm 301b*/
+static const UCHAR SiS310_PALNPhase2[]   = {0x21,0xF6,0x94,0x46};  /* TW: paln 301b*/
+static const UCHAR SiS310_SpecialPhase[] = {0x1e,0x8c,0x5c,0x7a};
 
 typedef struct _SiS310_LCDDataStruct
 {
@@ -1135,7 +1248,7 @@
 	USHORT LCDVT;
 } SiS310_LCDDataStruct;
 
-SiS310_LCDDataStruct  SiS310_StLCD1024x768Data[]=
+static const SiS310_LCDDataStruct  SiS310_StLCD1024x768Data[]=
 {
 	{   62,  25, 800, 546,1344, 806},
 	{   32,  15, 930, 546,1344, 806},
@@ -1146,7 +1259,7 @@
 	{    1,   1,1344, 806,1344, 806}
 };
 
-SiS310_LCDDataStruct  SiS310_ExtLCD1024x768Data[]=
+static const SiS310_LCDDataStruct  SiS310_ExtLCD1024x768Data[] =   /* TW: Checked */
 {
 	{   12,   5, 896, 512,1344, 806},
 	{   12,   5, 896, 510,1344, 806},
@@ -1163,18 +1276,19 @@
 	{    1,   1,1344, 806,1344, 806}
 };
 
-SiS310_LCDDataStruct  SiS310_St2LCD1024x768Data[]=
+static const SiS310_LCDDataStruct  SiS310_St2LCD1024x768Data[] =  /* TW: Checked */
 {
 	{   62,  25, 800, 546,1344, 806},
 	{   32,  15, 930, 546,1344, 806},
-	{   32,  15, 930, 546,1344, 806},
+/*	{   32,  15, 930, 546,1344, 806},   */
+        {   62,  25, 800, 546,1344, 806},    /* TW: Different in 650/301LV BIOS */
 	{  104,  45, 945, 496,1344, 806},
 	{   62,  25, 800, 546,1344, 806},
 	{   31,  18,1008, 624,1344, 806},
 	{    1,   1,1344, 806,1344, 806}
 };
 
-SiS310_LCDDataStruct  SiS310_StLCD1280x1024Data[]=
+static const SiS310_LCDDataStruct  SiS310_StLCD1280x1024Data[] =
 {
 	{   22,   5, 800, 510,1650,1088},
 	{   22,   5, 800, 510,1650,1088},
@@ -1186,7 +1300,7 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-SiS310_LCDDataStruct  SiS310_ExtLCD1280x1024Data[]=
+static const SiS310_LCDDataStruct  SiS310_ExtLCD1280x1024Data[] =  /* TW: Checked */
 {
 	{  211,  60,1024, 501,1688,1066},
 	{  211,  60,1024, 508,1688,1066},
@@ -1198,7 +1312,7 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-SiS310_LCDDataStruct  SiS310_St2LCD1280x1024Data[]=
+static const SiS310_LCDDataStruct  SiS310_St2LCD1280x1024Data[] =
 {
 	{   22,   5, 800, 510,1650,1088},
 	{   22,   5, 800, 510,1650,1088},
@@ -1210,8 +1324,17 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-SiS310_LCDDataStruct  SiS310_NoScaleData[]=
+static const SiS310_LCDDataStruct  SiS310_NoScaleData1024x768[] =  /* TW: Checked */
 {
+        {    1,   1,1344, 806,1344, 806},
+	{    1,   1,1344, 806,1344, 806},
+	{    1,   1,1344, 806,1344, 806},
+	{    1,   1,1344, 806,1344, 806},
+	{    1,   1,1344, 806,1344, 806},
+	{    1,   1,1344, 806,1344, 806},
+	{    1,   1,1344, 806,1344, 806},
+	{    1,   1,1344, 806,1344, 806}
+#if 0
 	{    1,   1, 800, 449, 800, 449},
 	{    1,   1, 800, 449, 800, 449},
 	{    1,   1, 900, 449, 900, 449},
@@ -1220,9 +1343,22 @@
 	{    1,   1,1056, 628,1056, 628},
 	{    1,   1,1344, 806,1344, 806},
 	{    1,   1,1688,1066,1688,1066}
+#endif
 };
 
-SiS310_LCDDataStruct  SiS310_LCD1280x960Data[]=
+static const SiS310_LCDDataStruct  SiS310_NoScaleData1280x1024[] =  /* TW: New; Checked */
+{
+        {    1,   1,1688,1066,1688,1066},
+	{    1,   1,1688,1066,1688,1066},
+	{    1,   1,1688,1066,1688,1066},
+	{    1,   1,1688,1066,1688,1066},
+	{    1,   1,1688,1066,1688,1066},
+	{    1,   1,1688,1066,1688,1066},
+	{    1,   1,1688,1066,1688,1066},
+	{    1,   1,1688,1066,1688,1066}
+};
+
+static const SiS310_LCDDataStruct  SiS310_LCD1280x960Data[] =
 {
 	{    9,   2, 800, 500,1800,1000},
 	{    9,   2, 800, 500,1800,1000},
@@ -1235,6 +1371,90 @@
 	{    1,   1,1800,1000,1800,1000}
 };
 
+static const SiS310_LCDDataStruct  SiS310_ExtLCD1400x1050Data[] =  /* TW: New */
+{  /* TODO */
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS310_LCDDataStruct  SiS310_ExtLCD1600x1200Data[] =  /* TW: New */
+{  /* TODO */
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS310_LCDDataStruct  SiS310_StLCD1400x1050Data[] =  /* TW: New */
+{  /* TODO */
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS310_LCDDataStruct  SiS310_StLCD1600x1200Data[] =  /* TW: New */
+{  /* TODO */
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS310_LCDDataStruct  SiS310_NoScaleData1400x1050[] =  /* TW: New */
+{  /* TODO */
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS310_LCDDataStruct  SiS310_NoScaleData1600x1200[] =  /* TW: New */
+{  /* TODO */
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
 typedef struct _SiS310_TVDataStruct
 {
 	USHORT RVBHCMAX;
@@ -1252,7 +1472,7 @@
 	UCHAR RY4COE;
 } SiS310_TVDataStruct;
 
-SiS310_TVDataStruct  SiS310_StPALData[]=
+static const SiS310_TVDataStruct  SiS310_StPALData[]=
 {
  {    1,   1, 864, 525,1270, 400, 100,   0, 760,0xf4,0xff,0x1c,0x22},
  {    1,   1, 864, 525,1270, 350, 100,   0, 760,0xf4,0xff,0x1c,0x22},
@@ -1262,19 +1482,19 @@
  {    1,   1, 864, 525,1270, 600,  50,   0,   0,0xf4,0xff,0x1c,0x22}
 };
 
-SiS310_TVDataStruct  SiS310_ExtPALData[]=
+static const SiS310_TVDataStruct  SiS310_ExtPALData[]=
 {
  {   27,  10, 848, 448,1270, 530,  50,   0,  50,0xf4,0xff,0x1c,0x22},
  {  108,  35, 848, 398,1270, 530,  50,   0,  50,0xf4,0xff,0x1c,0x22},
  {   12,   5, 954, 448,1270, 530,  50,   0,  50,0xf1,0x04,0x1f,0x18},
  {    9,   4, 960, 463,1644, 438,  50,   0,  50,0xf4,0x0b,0x1c,0x0a},
  {    9,   4, 848, 528,1270, 530,   0,   0,  50,0xf5,0xfb,0x1b,0x2a},
- {   36,  25,1060, 648,1316, 530, 438,   0, 438,0xeb,0x05,0x25,0x16},
+ {   36,  25,1060, 648,1316, 530, 438,   0, 438,0xeb,0x05,0x25,0x16},  /* 800x600 */
  {    3,   2,1080, 619,1270, 540, 438,   0, 438,0xf3,0x00,0x1d,0x20},
  {    1,   1,1170, 821,1270, 520, 686,   0, 686,0xF3,0x00,0x1D,0x20}     /*301b*/
 };
 
-SiS310_TVDataStruct  SiS310_StNTSCData[]=
+static const SiS310_TVDataStruct  SiS310_StNTSCData[]=
 {
  {    1,   1, 858, 525,1270, 400,  50,   0, 760,0xf1,0x04,0x1f,0x18},
  {    1,   1, 858, 525,1270, 350,  50,   0, 640,0xf1,0x04,0x1f,0x18},
@@ -1283,34 +1503,35 @@
  {    1,   1, 858, 525,1270, 480,   0,   0, 760,0xf1,0x04,0x1f,0x18}
 };
 
-SiS310_TVDataStruct  SiS310_ExtNTSCData[]=
+static const SiS310_TVDataStruct  SiS310_ExtNTSCData[]=
 {
  {  143,  65, 858, 443,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},
  {   88,  35, 858, 393,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},
  {  143,  70, 924, 443,1270, 440,  92,   0,  92,0xf1,0x04,0x1f,0x18},
  {  143,  70, 924, 393,1270, 440,  92,   0,  92,0xf4,0x0b,0x1c,0x0a},
  {  143,  76, 836, 523,1270, 440, 224,   0,   0,0xf1,0x05,0x1f,0x16},
- {  143, 120,1056, 643,1270, 440,   0, 128,   0,0xf4,0x10,0x1c,0x00},
+ {  143, 120,1056, 643,1270, 440,   0, 128,   0,0xf4,0x10,0x1c,0x00},  /* 800x600 */
  {    2,   1, 858, 503,1270, 480,   0, 128,   0,0xee,0x0c,0x22,0x08},
  {   65,  64,1056, 791,1270, 480, 638,   0,   0,0xEE,0x0C,0x22,0x08} /*301b*/     
 };
 
-SiS310_TVDataStruct  SiS310_St1HiTVData[]=
+/* TW: These tables will need data ! */
+static const SiS310_TVDataStruct  SiS310_St1HiTVData[]=
 {
-	{0x00}
+   	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
-SiS310_TVDataStruct  SiS310_St2HiTVData[]=
+static const SiS310_TVDataStruct  SiS310_St2HiTVData[]=
 {
-	{0x00}
+	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
-SiS310_TVDataStruct  SiS310_ExtHiTVData[]=
+static const SiS310_TVDataStruct  SiS310_ExtHiTVData[]=
 {
-	{0x00}
+	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
-UCHAR SiS310_NTSCTiming[] = {
+static const UCHAR SiS310_NTSCTiming[] = {   /* TW: New (checked 1.09, 1.10.6s) */
 	0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c,
 	0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a,
 	0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b,
@@ -1321,7 +1542,7 @@
 	0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00
 };
 
-UCHAR SiS310_PALTiming[] = {
+static const UCHAR SiS310_PALTiming[] = {   /* TW: New (checked 1.09, 1.10.6s) */
 	0x19,0x52,0x35,0x6e,0x04,0x38,0x3d,0x70,
 	0x94,0x49,0x01,0x12,0x06,0x3e,0x35,0x6d,
 	0x06,0x14,0x3e,0x35,0x6d,0x00,0x45,0x2b,
@@ -1332,43 +1553,146 @@
 	0x00,0x40,0x3e,0x00,0xe1,0x02,0x28,0x00
 };
 
-UCHAR SiS310_HiTVExtTiming[] = {0x00};
-
-UCHAR SiS310_HiTVSt1Timing[] = {0x00};
-
-UCHAR SiS310_HiTVSt2Timing[] = {0x00};
-
-UCHAR SiS310_HiTVTextTiming[] = {0x00};
-
-UCHAR SiS310_HiTVGroup3Data[] = {0x00};
-
-UCHAR SiS310_HiTVGroup3Simu[] = {0x00};
-
-UCHAR SiS310_HiTVGroup3Text[] = {0x00};
+#ifdef oldHV
+static const UCHAR SiS310_HiTVExtTiming[] = {   /* TW: New */
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x64,0x90,0x33,0x8c,0x18,0x36,0x3e,0x13,
+	0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40,
+	0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d,
+	0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00
+};
+
+static const UCHAR SiS310_HiTVSt1Timing[] = {   /* TW: New */
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x65,0x90,0x7b,0xa8,0x03,0xf0,0x87,0x03,
+	0x11,0x15,0x11,0xcf,0x10,0x11,0xcf,0x10,
+	0x35,0x35,0x3b,0x69,0x1d,0x92,0x0f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x86,
+	0xaf,0x5d,0x0e,0x00,0xfc,0xff,0x2d,0x00
+};
+
+static const UCHAR SiS310_HiTVSt2Timing[] = {   /* TW: New */
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x64,0x90,0x33,0x8c,0x18,0x36,0x3e,0x13,
+	0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40,
+	0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d,
+	0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00
+};
+
+static const UCHAR SiS310_HiTVTextTiming[] = {   /* TW: New */
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x65,0x90,0xe7,0xbc,0x03,0x0c,0x97,0x03,
+	0x14,0x78,0x14,0x08,0x20,0x14,0x08,0x20,
+	0xc8,0xc8,0x3b,0xd2,0x26,0x92,0x0f,0x40,
+        0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x96,
+	0x72,0x5c,0x11,0x00,0xfc,0xff,0x32,0x00
+};
+
+static const UCHAR SiS310_HiTVGroup3Data[] = {   /* TW: New */
+        0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x5f,
+	0x05,0x21,0xb2,0xb2,0x55,0x77,0x2a,0xa6,
+	0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20,
+	0x8c,0x6e,0x60,0x2e,0x58,0x48,0x72,0x44,
+	0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+	0x4f,0x7f,0x03,0xa8,0x7d,0x20,0x1a,0xa9,
+	0x14,0x05,0x03,0x7e,0x64,0x31,0x14,0x75,
+	0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+};
+
+static const UCHAR SiS310_HiTVGroup3Simu[] = {   /* TW: New */
+        0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x95,
+	0xdb,0x20,0xb8,0xb8,0x55,0x47,0x2a,0xa6,
+	0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20,
+	0x8c,0x6e,0x60,0x15,0x26,0xd3,0xe4,0x11,
+	0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+	0x67,0x36,0x01,0x47,0x0e,0x10,0xbe,0xb4,
+	0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75,
+	0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+};
+
+static const UCHAR SiS310_HiTVGroup3Text[] = {   /* TW: New */
+        0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0xa7,
+	0xf5,0x20,0xce,0xce,0x55,0x47,0x2a,0xa6,
+	0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20,
+	0x8c,0x6e,0x60,0x18,0x2c,0x0c,0x20,0x22,
+	0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+	0x93,0x3c,0x01,0x50,0x2f,0x10,0xf4,0xca,
+	0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75,
+	0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+};
+#endif
 
 typedef struct _SiS310_PanelDelayTblStruct
 {
  	UCHAR timer[2];
 } SiS310_PanelDelayTblStruct;
 
-SiS310_PanelDelayTblStruct SiS310_PanelDelayTbl[]=
+static const SiS310_PanelDelayTblStruct SiS310_PanelDelayTbl[]=  /* TW: New */
 {
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}}
+        {{0x10,0x40}},		/* TW: from 650/301LVx 1.10.6s BIOS */
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}}
+#if 0
+	{{0x28,0xc8}},		/* TW: from 650/301LV BIOS */
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}}
+#endif
+};
+
+static const SiS310_PanelDelayTblStruct SiS310_PanelDelayTblLVDS[]=
+{
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}}
 };
 
 typedef struct _SiS310_LVDSDataStruct
@@ -1379,19 +1703,20 @@
 	USHORT LCDVT;
 } SiS310_LVDSDataStruct;
 
-SiS310_LVDSDataStruct  SiS310_LVDS320x480Data_1[]=
+static const SiS310_LVDSDataStruct  SiS310_LVDS320x480Data_1[]=
 {
-	{848, 433,400,525},
-	{848, 389,400,525},
-	{848, 433,400,525},
-	{848, 389,400,525},
+	{848, 433,400, 525},
+	{848, 389,400, 525},
+	{848, 433,400, 525},
+	{848, 389,400, 525},
 	{848, 518,400, 525},
-	{1056, 628,400,525},
-	{400, 525,400,525},
+	{1056,628,400, 525},
+	{400, 525,400, 525},
 	{800, 449,1000, 644},
 	{800, 525,1000, 635}
 };
-SiS310_LVDSDataStruct  SiS310_LVDS800x600Data_1[]=
+
+static const SiS310_LVDSDataStruct  SiS310_LVDS800x600Data_1[]=   /* TW: New */
 {
 	{848, 433,1060, 629},
 	{848, 389,1060, 629},
@@ -1404,7 +1729,7 @@
 	{800, 525,1000, 635}
 };
 
-SiS310_LVDSDataStruct  SiS310_LVDS800x600Data_2[]=
+static const SiS310_LVDSDataStruct  SiS310_LVDS800x600Data_2[]=   /* TW: New */
 {
 	{1056, 628,1056, 628},
 	{1056, 628,1056, 628},
@@ -1417,7 +1742,33 @@
 	{800, 525,1000, 635}
 };
 
-SiS310_LVDSDataStruct  SiS310_LVDS1024x768Data_1[]=
+static const SiS310_LVDSDataStruct  SiS310_LVDS1024x768Data_1[]=   /* TW: New */
+{
+	{840, 438,1344, 806},
+	{840, 409,1344, 806},
+	{840, 438,1344, 806},
+	{840, 409,1344, 806},
+	{840, 518,1344, 806},    /* 640x480 */
+	{1050, 638,1344, 806},   /* 800x600 */
+	{1344, 806,1344, 806},   /* 1024x768 */
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS310_LVDSDataStruct  SiS310_LVDS1024x768Data_2[]=   /* TW: New */
+{
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS310_LVDSDataStruct  SiS310_LVDS1280x1024Data_1[]=   /* TW: New */
 {
 	{840, 438,1344, 806},
 	{840, 409,1344, 806},
@@ -1430,7 +1781,7 @@
 	{800, 525,1280, 813}
 };
 
-SiS310_LVDSDataStruct  SiS310_LVDS1024x768Data_2[]=
+static const SiS310_LVDSDataStruct  SiS310_LVDS1280x1024Data_2[]=   /* TW: New */
 {
 	{1344, 806,1344, 806},
 	{1344, 806,1344, 806},
@@ -1443,7 +1794,62 @@
 	{800, 525,1280, 813}
 };
 
-SiS310_LVDSDataStruct  SiS310_LVDS1280x1024Data_1[]=
+static const SiS310_LVDSDataStruct  SiS310_LVDS1400x1050Data_1[]=   /* TW: New */
+{
+        {928, 416, 1688, 1066},
+	{928, 366, 1688, 1066},
+	{928, 416, 1688, 1066},
+	{928, 366, 1688, 1066},
+	{928, 496, 1688, 1066},
+	{1088, 616, 1688, 1066},
+	{1312, 784, 1688, 1066},
+	{1568, 1040, 1688, 1066},
+	{1688, 1066, 1688, 1066}
+};
+
+static const SiS310_LVDSDataStruct  SiS310_LVDS1400x1050Data_2[]=   /* TW: New */
+{
+        {1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+};
+
+/* TW: New: - from 300 series */
+static const SiS310_LVDSDataStruct  SiS310_LVDS1024x600Data_1[]=
+{
+	{840, 604,1344, 800},
+	{840, 560,1344, 800},
+	{840, 604,1344, 800},
+	{840, 560,1344, 800},
+	{840, 689,1344, 800},
+	{1050, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+/* TW: New: - from 300 series */
+static const SiS310_LVDSDataStruct  SiS310_LVDS1024x600Data_2[]=
+{
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+/* TW: New: - from 300 series */
+static const SiS310_LVDSDataStruct  SiS310_LVDS1152x768Data_1[]=
 {
 	{840, 438,1344, 806},
 	{840, 409,1344, 806},
@@ -1456,7 +1862,8 @@
 	{800, 525,1280, 813}
 };
 
-SiS310_LVDSDataStruct  SiS310_LVDS1280x1024Data_2[]=
+/* TW: New: - from 300 series */
+static const SiS310_LVDSDataStruct  SiS310_LVDS1152x768Data_2[]=
 {
 	{1344, 806,1344, 806},
 	{1344, 806,1344, 806},
@@ -1469,7 +1876,20 @@
 	{800, 525,1280, 813}
 };
 
-SiS310_LVDSDataStruct  SiS310_LVDS640x480Data_1[]=
+/* TW: New in 650/LVDS BIOS - pass 1:1 data */
+static const SiS310_LVDSDataStruct  SiS310_LVDSXXXxXXXData_1[]=   /* TW: New */
+{
+        { 800, 449, 800, 449},
+	{ 800, 449, 800, 449},
+	{ 900, 449, 900, 449},
+	{ 900, 449, 900, 449},
+	{ 800, 525, 800, 525},
+	{1056, 628,1056, 628},
+	{1344, 806,1344, 806},
+	{1688, 806,1688, 806}
+};
+
+static const SiS310_LVDSDataStruct  SiS310_LVDS640x480Data_1[]=   /* TW: New */
 {
 	{800, 449, 800, 449},
 	{800, 449, 800, 449},
@@ -1482,44 +1902,129 @@
 	{1056, 628,1056, 628}
 };
 
-SiS310_LVDSDataStruct  SiS310_CHTVUNTSCData[]=
+static const SiS310_LVDSDataStruct  SiS310_LVDS1280x960Data_1[]=   /* TW: New */
 {
-	{840, 600, 840, 600},
-	{840, 600, 840, 600},
-	{840, 600, 840, 600},
-	{840, 600, 840, 600},
-	{784, 600, 784, 600},
-	{1064, 750,1064, 750}
+	{840, 438,1344, 806},
+	{840, 409,1344, 806},
+	{840, 438,1344, 806},
+	{840, 409,1344, 806},
+	{840, 518,1344, 806},
+	{1050, 638,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
 };
 
-SiS310_LVDSDataStruct  SiS310_CHTVONTSCData[]=
+static const SiS310_LVDSDataStruct  SiS310_LVDS1280x960Data_2[]=   /* TW: New */
 {
-	{840, 525, 840, 525},
-	{840, 525, 840, 525},
-	{840, 525, 840, 525},
-	{840, 525, 840, 525},
-	{784, 525, 784, 525},
-	{1040, 700,1040, 700}
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS310_LVDSDataStruct  SiS310_LCDA1400x1050Data_1[]=   /* TW: New */
+{	/* TW: Might be temporary (invalid) data */
+        {928, 416, 1688, 1066},
+	{928, 366, 1688, 1066},
+	{1008, 416, 1688, 1066},
+	{1008, 366, 1688, 1066},
+	{1200, 530, 1688, 1066},
+	{1088, 616, 1688, 1066},
+	{1312, 784, 1688, 1066},
+	{1568, 1040, 1688, 1066},
+	{1688, 1066, 1688, 1066}
+};
+
+static const SiS310_LVDSDataStruct  SiS310_LCDA1400x1050Data_2[]=   /* TW: New */
+{	/* TW: Temporary data. Not valid */
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS310_LVDSDataStruct  SiS310_LCDA1600x1200Data_1[]=   /* TW: New */
+{	/* TW: Temporary data. Not valid */
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
 };
 
-SiS310_LVDSDataStruct  SiS310_CHTVUPALData[]=
+static const SiS310_LVDSDataStruct  SiS310_LCDA1600x1200Data_2[]=   /* TW: New */
+{	/* TW: Temporary data. Not valid */
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0}
+};
+
+static const SiS310_LVDSDataStruct  SiS310_CHTVUNTSCData[]=   /* TW: New */
+{
+	{ 840, 600, 840, 600},
+	{ 840, 600, 840, 600},
+	{ 840, 600, 840, 600},
+	{ 840, 600, 840, 600},
+	{ 784, 600, 784, 600},
+	{1064, 750,1064, 750},
+        {1160, 945,1160, 945}           /* TW: For Ch7019 1024 */
+};
+
+static const SiS310_LVDSDataStruct  SiS310_CHTVONTSCData[]=   /* TW: New */
+{
+	{ 840, 525, 840, 525},
+	{ 840, 525, 840, 525},
+	{ 840, 525, 840, 525},
+	{ 840, 525, 840, 525},
+	{ 784, 525, 784, 525},
+	{1040, 700,1040, 700},
+        {1160, 840,1160, 840}          	/* TW: For Ch7019 1024 */
+};
+
+static const SiS310_LVDSDataStruct  SiS310_CHTVUPALData[]=   /* TW: New */
 {
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
-	{840, 750, 840, 750},
-	{936, 836, 936, 836}
+	{ 840, 625, 840, 625},
+	{ 960, 750, 960, 750},
+	{1400,1000,1400,1000}   	/*  TW: For Ch7019 1024 */
 };
 
-SiS310_LVDSDataStruct  SiS310_CHTVOPALData[]=
+static const SiS310_LVDSDataStruct  SiS310_CHTVOPALData[]=   /* TW: New */
 {
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
-	{840, 625, 840, 625},
-	{960, 750, 960, 750}
+	{ 840, 625, 840, 625},
+	{ 944, 625, 944, 625},
+        {1400, 875,1400, 875}       	/*  TW: For Ch7019 1024 */
 };
 
 typedef struct _SiS310_LVDSDesStruct
@@ -1528,60 +2033,63 @@
 	USHORT LCDVDES;
 } SiS310_LVDSDesStruct;
 
-SiS310_LVDSDesStruct  SiS310_PanelType00_1[]=
-{
-	{0, 626},
-	{0, 624},
-	{0, 626},
-	{0, 624},
-	{0, 624},
-	{ 0, 627},
-	{ 0, 627},
-	{ 0,   0},
-	{ 0,   0}
-};
+/* TW: PanelType arrays taken from 650/LVDS BIOS 1.10.0 */
 
-SiS310_LVDSDesStruct  SiS310_PanelType01_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType00_1[]=   /* TW: New */
 {
-	{1343, 798},
-	{1343, 794},
-	{1343, 798},
-	{1343, 794},
-	{1343,   0},
-	{1343,   0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0}
+};
+
+static const SiS310_LVDSDesStruct  SiS310_PanelType01_1[]=   /* TW: New */
+{
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
 	{ 0, 805},
-	{ 0, 794},
-	{ 0,   0}
+	{ 0, 0},
+	{ 0, 0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType02_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType02_1[]=   /* TW: New */
 {
-	{0, 626},
-	{0, 624},
-	{0, 626},
-	{0, 624},
-	{0, 624},
-	{ 0, 627},
-	{ 8, 523},
-	{ 0,   0},
-	{ 0,   0}
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 1065},
+	{ 0, 0},
+	{ 0, 0}
 };
 
 
-SiS310_LVDSDesStruct  SiS310_PanelType03_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType03_1[]=   /* TW: New */
 {
-	{ 8, 436},
-	{ 8, 440},
-	{ 8, 436},
-	{ 8, 440},
-	{ 8, 512},
-	{1343, 798},
-	{1343, 794},
-	{1343, 798},
-	{1343, 794}
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType04_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType04_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1594,7 +2102,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType05_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType05_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1607,7 +2115,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType06_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType06_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1620,7 +2128,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType07_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType07_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1633,33 +2141,34 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType08_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType08_1[]=   /* TW: New */
 {
-	{1059, 626},
-	{1059, 624},
-	{1059, 626},
-	{1059, 624},
-	{1059, 624},
-	{ 0, 627},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0}
+};
+
+static const SiS310_LVDSDesStruct  SiS310_PanelType09_1[]=   /* TW: New */
+{
+	{ 0, 448},
+	{ 0, 448},
+	{ 0, 448},
+	{ 0, 448},
+	{ 0, 524},
 	{ 0, 627},
-	{ 0,   0},
-	{ 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType09_1[]=
-{
-	{1343, 798},
-	{1343, 794},
-	{1343, 798},
-	{1343, 794},
-	{1343,   0},
-	{1343,   0},
 	{ 0, 805},
-	{ 0, 794},
-	{ 0,   0}
+	{ 0, 805},
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0a_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0a_1[]=   /* TW: New */
 {
 	{1059, 626},
 	{1059, 624},
@@ -1672,7 +2181,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0b_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0b_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1685,7 +2194,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0c_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0c_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1698,7 +2207,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0d_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0d_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1711,7 +2220,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0e_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0e_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1724,7 +2233,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0f_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0f_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1737,20 +2246,20 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType00_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType00_2[]=   /* TW: New */
 {
-	{976, 527},
-	{976, 502},
-	{976, 527},
-	{976, 502},
-	{976, 567},
-	{ 0, 627},
-	{ 0, 627},
+	{980, 528},
+	{980, 503},
+	{980, 528},
+	{980, 503},
+	{980, 568},
+	{ 0, 628},
+	{ 0,   0},
 	{ 0,   0},
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType01_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType01_2[]=   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1758,51 +2267,51 @@
 	{1152, 597},
 	{1152, 662},
 	{1232, 722},
-	{ 0, 805},
-	{ 0, 794},
+	{ 0, 806},
+	{ 0,   0},
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType02_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType02_2[]=   /* TW: New */
 {
-	{976, 527},
-	{976, 502},
-	{976, 527},
-	{976, 502},
-	{976, 567},
-	{ 0, 627},
-	{ 0, 627},
+	{1368, 754},
+	{1368, 729},
+	{1368, 754},
+	{1368, 729},
+	{1368, 794},
+	{1448, 854},
+	{1560, 938},
+	{   0,1066},
+	{ 0,   0},
 	{ 0,   0},
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType03_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType03_2[]=   /* TW: New */
 {
-	{1152, 622},
-	{1152, 597},
-	{1152, 622},
-	{1152, 597},
-	{1152, 662},
-	{1232, 722},
-	{ 0, 805},
-	{1152, 622},
-	{1152, 597}
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType04_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType04_2[]=   /* TW: New */
 {
-	{1152, 622},
-	{1152, 597},
-	{1152, 622},
-	{1152, 597},
-	{1152, 662},
-	{1232, 722},
-	{ 0, 805},
-	{ 0, 794},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType05_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType05_2[]=   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1815,7 +2324,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType06_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType06_2[]=   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1828,7 +2337,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType07_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType07_2[]=   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1841,7 +2350,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType08_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType08_2[]=   /* TW: New */
 {
 	{976, 527},
 	{976, 502},
@@ -1854,20 +2363,19 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType09_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType09_2[]=   /* TW: New */
 {
-	{1152, 622},
-	{1152, 597},
-	{1152, 622},
-	{1152, 597},
-	{1152, 662},
-	{1232, 722},
-	{ 0, 805},
-	{ 0, 794},
- 	{ 0,   0}
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0a_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0a_2[]=   /* TW: New */
 {
 	{976, 527},
 	{976, 502},
@@ -1880,7 +2388,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0b_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0b_2[]=   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1893,7 +2401,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0c_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0c_2[]=   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1906,7 +2414,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0d_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0d_2[]=   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1919,7 +2427,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0e_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0e_2[]=   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1932,7 +2440,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0f_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0f_2[] =   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1944,104 +2452,365 @@
 	{ 0, 794},
 	{ 0,   0}
 };
-/*301b*/
-SiS310_LVDSDesStruct SiS310_PanelType1076_1[]=
-{
-	{0x00,0x00}
-};
-SiS310_LVDSDesStruct SiS310_PanelType1210_1[]=
-{
-	{0x00,0x00}
-};
-SiS310_LVDSDesStruct SiS310_PanelType1296_1[]=
-{
-	{0x00,0x00}
-};
-SiS310_LVDSDesStruct SiS310_PanelType1076_2[]=
-{
-	{0x00,0x00}
-};
-SiS310_LVDSDesStruct SiS310_PanelType1210_2[]=
-{
-	{0x00,0x00}
-};
-SiS310_LVDSDesStruct SiS310_PanelType1296_2[]=
-{
-	{0x00,0x00}
+
+static const SiS310_LVDSDesStruct SiS310_PanelType1076_1[]=   /* TW: New */
+{  /* 1024x768 - Checked (1.10.6s) */
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS310_LVDSDesStruct SiS310_PanelType1076_2[]=   /* TW: New */
+{  /* 1024x768 - Checked (1.10.6s) */
+	{ 1184, 622 },
+	{ 1184, 597 },
+	{ 1184, 622 },
+	{ 1184, 597 },
+	{ 1152, 622 },
+	{ 1232, 722 },
+	{    0, 0   },
+	{    0, 794 },
+	{    0, 0   }
+};
+
+static const SiS310_LVDSDesStruct SiS310_PanelType1210_1[]=   /* TW: New */
+{  /* 1280x1024 - Checked (1.10.6s) */
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS310_LVDSDesStruct SiS310_PanelType1210_2[]=   /* TW: New */
+{  /* 1280x1024 - Checked (1.10.6s) */
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS310_LVDSDesStruct SiS310_PanelType1296_1[]=   /* TW: New */
+{  /* 1400x1050 - Checked (1.10.6s) */
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS310_LVDSDesStruct SiS310_PanelType1296_2[]=   /* TW: New */
+{  /* 1400x1050 - Checked (1.10.6s) - looks heavily invalid */
+	{ 808 , 740},
+	{ 0   , 715},
+	{ 632 , 740},
+	{ 632 , 715},
+	{ 1307, 780},
+	{ 1387,1157},
+	{ 1499, 924},
+	{ 1627,1052},
+	{ 0 , 0}
+};
+
+static const SiS310_LVDSDesStruct SiS310_PanelType1600_1[]=   /* TW: New */
+{  /* 1600x1200 - Checked (1.10.6s) */
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS310_LVDSDesStruct SiS310_PanelType1600_2[]=   /* TW: New */
+{  /* 1600x1200 - Checked (1.10.6s) - looks heavily invalid */
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
 };
-/*end 301b*/
 
-SiS310_LVDSDesStruct  SiS310_CHTVUNTSCDesData[]=
+static const SiS310_LVDSDesStruct  SiS310_CHTVUNTSCDesData[]=
 {
 	{ 0,   0},
 	{ 0,   0},
 	{ 0,   0},
 	{ 0,   0},
 	{ 0,   0},
+	{ 0,   0},
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_CHTVONTSCDesData[]=
+static const SiS310_LVDSDesStruct  SiS310_CHTVONTSCDesData[]=
 {
 	{ 0,   0},
 	{ 0,   0},
 	{ 0,   0},
 	{ 0,   0},
 	{ 0,   0},
+	{ 0,   0},
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_CHTVUPALDesData[]=
+static const SiS310_LVDSDesStruct  SiS310_CHTVUPALDesData[]=
 {
 	{256,   0},
 	{256,   0},
 	{256,   0},
 	{256,   0},
 	{ 0,   0},
+	{ 0,   0},
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_CHTVOPALDesData[]=
+static const SiS310_LVDSDesStruct  SiS310_CHTVOPALDesData[]=
 {
 	{256,   0},
 	{256,   0},
 	{256,   0},
 	{256,   0},
 	{ 0,   0},
+	{ 0,   0},
 	{ 0,   0}
 };
 
-/*add for LCDA*/
+typedef struct _SiS310_Part2PortTblStruct
+{
+ 	UCHAR CR[12];
+} SiS310_Part2PortTblStruct;
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1024x768_1[] =
+{
+ {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x2c,0x12,0x9a,0xae,0x88,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x38,0x13,0x16,0x0c,0xe6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1280x1024_1[] =
+{	/* TW: Temporary data, invalid */
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1400x1050_1[] =
+{	/* TW: Temporary data, invalid */
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_1[] =
+{	/* TW: Temporary data, invalid */
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1024x768_2[] =
+{
+ {{0x25,0x12,0x51,0x6e,0x48,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}},
+ {{0x2c,0x12,0x38,0x55,0x2f,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}},
+ {{0x25,0x12,0x51,0x6e,0x48,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}},
+ {{0x2c,0x12,0x38,0x55,0x2f,0xc1,0x35,0xb1,0x47,0xe9,0x71,0x33}},
+ {{0x2d,0x12,0x79,0x96,0x70,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}},
+ {{0x29,0x12,0xb5,0xd2,0xac,0xe9,0x35,0xd9,0x47,0x11,0x99,0x33}},
+ {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1280x1024_2[] =
+{
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1400x1050_2[] =
+{
+ {{0x2b,0x12,0xd9,0xe5,0xd5,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x22,0x12,0xc0,0xcc,0xbc,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x2b,0x12,0xd9,0xe5,0xd5,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x22,0x12,0xc0,0xcc,0xbc,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x33,0x13,0x01,0x0d,0xfd,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x3f,0x1b,0x3d,0x49,0x39,0x54,0x23,0xc0,0x27,0x66,0x30,0x42}},
+ {{0x33,0x1b,0x91,0x9d,0x8d,0x8c,0x23,0xf8,0x27,0x9e,0x68,0x42}},
+ {{0x43,0x24,0x11,0x1d,0x0d,0xcc,0x23,0x38,0x37,0xde,0xa8,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_2[] =
+{	/* TW: Temporary data, invalid */
+ {{0x2b,0x12,0xd9,0xe5,0xd5,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x22,0x12,0xc0,0xcc,0xbc,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x2b,0x12,0xd9,0xe5,0xd5,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x22,0x12,0xc0,0xcc,0xbc,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x33,0x13,0x01,0x0d,0xfd,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x3f,0x1b,0x3d,0x49,0x39,0x54,0x23,0xc0,0x27,0x66,0x30,0x42}},
+ {{0x33,0x1b,0x91,0x9d,0x8d,0x8c,0x23,0xf8,0x27,0x9e,0x68,0x42}},
+ {{0x43,0x24,0x11,0x1d,0x0d,0xcc,0x23,0x38,0x37,0xde,0xa8,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
+};
+
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1024x768_3[] =
+{	/* TW: Data from 650/301LVx 1.10.6s */
+ {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x2c,0x13,0x9a,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x25,0x13,0xc9,0x24,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x38,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x25,0x13,0xc9,0x25,0xff,0xf9,0x45,0x09,0x07,0xf9,0x09,0x24}}
+#if 0	/* TW: Data from 650/301LV */
+ {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x2c,0x12,0x9a,0xae,0x88,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x38,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
+#endif
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1280x1024_3[] =
+{	/* TW: Temporary data, invalid */
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1400x1050_3[] =
+{	/* TW: Temporary data, invalid */
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_3[] =
+{	/* TW: Temporary data, invalid */
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}
+};
+
 typedef struct _SiS310_LCDACRT1DataStruct
 {
  	UCHAR CR[17];
 }SiS310_LCDACRT1DataStruct;
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT1800x600_1[]=
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT1800x600_1[] =
 {
-{{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x65,0x4f,0x89,0x56,0x83,0x04,0x3e,
-   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
-   0x01}}
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_1[]=
-{
-{{0x73,0x4f,0x4f,0x97,0x55,0x86,0xc4,0x1f,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_1[]=
+{  /* TW: Checked (1.10.6s) */
+ {{0x73,0x4f,0x4f,0x97,0x55,0x86,0xc4,0x1f,
    0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05,
    0x00}},
  {{0x73,0x4f,0x4f,0x97,0x55,0x86,0x97,0x1f,
@@ -2064,255 +2833,536 @@
    0x01}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_1[]=
-{
-{{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_1[]=
+{  /* Checked (1.10.6s) */
+ {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0xb8,0x1f,
+   0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x06,
    0x00}},
- {{0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+ {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0x86,0x1f,
+   0x5e,0x82,0x5d,0x5d,0x87,0x10,0x00,0x06,
    0x00}},
- {{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+ {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0xb8,0x1f,
+   0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x06,
    0x00}},
- {{0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+ {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0x86,0x1f,
+   0x5e,0x82,0x5d,0x5d,0x87,0x10,0x00,0x06,
    0x00}},
- {{0x63,0x4f,0x87,0x54,0x9f,0x04,0x3e,
-   0xe2,0x89,0xdf,0x05,0x00,0x00,0x01,
+ {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0x08,0x3e,
+   0xe0,0x84,0xdf,0xdf,0x09,0x00,0x00,0x06,
    0x00}},
- {{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0,
-   0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26,
+ {{0x92,0x63,0x63,0x96,0x6c,0x1a,0x80,0xf0,
+   0x58,0x8c,0x57,0x57,0x81,0x20,0x00,0x06,
    0x01}},
- {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+ {{0xae,0x7f,0x7f,0x92,0x88,0x96,0x28,0xf5,
+   0x00,0x84,0xff,0xff,0x29,0x10,0x00,0x02,
+   0x01}},
+ {{0xce,0x9f,0x9f,0x92,0xa8,0x16,0x28,0x5a,
+   0x00,0x84,0xff,0xff,0x29,0x01,0x00,0x07,
    0x01}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT1800x600_1_H[]=
-{
-{{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11400x1050_1[]=
+{    /* Checked (1.10.6s) */
+ {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+   0x93,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05,
    0x00}},
- {{0x30,0x27,0x94,0x2c,0x92,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x04,
+ {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
+   0x60,0x84,0x5d,0x5d,0x6d,0x10,0x00,0x05,
    0x00}},
- {{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
+ {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+   0x93,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05,
    0x00}},
- {{0x30,0x27,0x94,0x2c,0x92,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x04,
+ {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
+   0x60,0x84,0x5d,0x5d,0x6d,0x10,0x00,0x05,
    0x00}},
- {{0x30,0x27,0x94,0x2c,0x92,0x04,0x3e,
-   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x04,
+ {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0xee,0x1f,
+   0xe2,0x86,0xdf,0xdf,0xef,0x10,0x00,0x05,
    0x00}},
- {{0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x05,
-   0x01}}
+ {{0x83,0x63,0x63,0x87,0x68,0x16,0x66,0xf0,
+   0x5a,0x8e,0x57,0x57,0x67,0x20,0x00,0x06,
+   0x01}},
+ {{0x9f,0x7f,0x7f,0x83,0x84,0x92,0x0e,0xf5,
+   0x02,0x86,0xff,0xff,0x0f,0x10,0x00,0x02,
+   0x01}},
+ {{0xbf,0x9f,0x9f,0x83,0xa4,0x12,0x0e,0x5a,
+   0x02,0x86,0xff,0xff,0x0f,0x09,0x00,0x07,
+   0x01}},
+ {{0xce,0xae,0xae,0x92,0xb3,0x01,0x28,0x10,
+   0x1a,0x80,0x19,0x19,0x29,0x0f,0x00,0x03,
+   0x00}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_1_H[]=
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11600x1200_1[]=
+{   /* MISSING */
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}}
+};
+
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT1800x600_1_H[]=
 {
-{{0x37,0x27,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}}
+};
+
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_1_H[]=
+{  /* TW: Checked (1.10.6s) */
+ {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0xc4,0x1f,
    0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x44,
    0x00}},
- {{0x37,0x27,0x27,0x9B,0x2b,0x94,0x97,0x1f,
+ {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0x97,0x1f,
    0x60,0x87,0x5D,0x5D,0x83,0x01,0x00,0x44,
    0x00}},
- {{0x37,0x27,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
+ {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0xc4,0x1f,
    0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x44,
    0x00}},
- {{0x37,0x27,0x27,0x9B,0x2b,0x94,0x97,0x1f,
+ {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0x97,0x1f,
    0x60,0x87,0x5D,0x5D,0x83,0x01,0x00,0x44,
    0x00}},
- {{0x37,0x27,0x27,0x9B,0x2b,0x94,0x04,0x3e,
-   0xE2,0x89,0xDf,0xDf,0x05,0x00,0x00,0x44,
+ {{0x4b,0x27,0x27,0x8f,0x32,0x1b,0x04,0x3e,
+   0xE2,0x89,0xDf,0xDf,0x05,0x00,0x00,0x45,
    0x00}},
- {{0x41,0x31,0x31,0x85,0x35,0x1d,0x7c,0xf0,
+ {{0x55,0x31,0x31,0x99,0x46,0x1d,0x7c,0xf0,
    0x5A,0x8F,0x57,0x57,0x7D,0x20,0x00,0x55,
    0x01}},
- {{0x4f,0x3F,0x3F,0x93,0x45,0x0D,0x24,0xf5,
+ {{0x63,0x3F,0x3F,0x87,0x4a,0x93,0x24,0xf5,
    0x02,0x88,0xFf,0xFf,0x25,0x10,0x00,0x01,
    0x01}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_1_H[]=
-{
-{{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_1_H[]=
+{   /* Checked (1.10.6s) */
+ {{0x56,0x27,0x27,0x9a,0x30,0x1e,0xb8,0x1f,
+   0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x05,
    0x00}},
-{{0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x04,
-   0x00}},
- {{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
-   0x00}},
- {{0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x04,
+ {{0x3c,0x4f,0x4f,0x82,0x58,0x06,0x86,0xd1,    /* <-- Invalid data - one byte missing in BIOS */
+   0xbc,0x80,0xbb,0xbb,0xe5,0x00,0x00,0x06,
+   0x01}},
+ {{0x56,0x27,0x27,0x9a,0x30,0x1e,0xb8,0x1f,
+   0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x05,
    0x00}},
- {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
-   0xe2,0x89,0xdf,0x05,0x00,0x00,0x04,
+ {{0x3c,0x4f,0x4f,0x82,0x58,0x06,0x86,0xd1,
+   0xbc,0x80,0xbb,0xbb,0xe5,0x00,0x00,0x06,
+   0x01}},
+ {{0x56,0x27,0x27,0x9a,0x30,0x1e,0x08,0x3e,
+   0xe0,0x84,0xdf,0xdf,0x09,0x00,0x00,0x05,
    0x00}},
- {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
-   0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
+ {{0x60,0x31,0x31,0x84,0x3a,0x88,0x80,0xf0,
+   0x58,0x8c,0x57,0x57,0x81,0x20,0x00,0x01,
    0x01}},
- {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+ {{0x6e,0x3f,0x3f,0x92,0x48,0x96,0x28,0xf5,
+   0x00,0x84,0xff,0xff,0x29,0x10,0x00,0x01,
    0x01}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT1800x600_2[]=
-{ 
-{{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11400x1050_1_H[]=
+{   /* Checked (1.10.6s) */
+  {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0x9e,0x1f,
+    0x93,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05,
+    0x00}},
+  {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+    0x60,0x84,0x5d,0x5d,0x6d,0x10,0x00,0x05,
+    0x00}},
+  {{0x47,0x27,0x27,0x8b,0x30,0x1e,0x9e,0x1f,
+    0x92,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05,
+    0x00}},
+  {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+    0x60,0x84,0x5d,0x5d,0x6d,0x10,0x00,0x05,
+    0x00}},
+  {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0xee,0x1f,
+    0xe2,0x86,0xdf,0xdf,0xef,0x10,0x00,0x05,
+    0x00}},
+  {{0x51,0x31,0x31,0x95,0x36,0x04,0x66,0xf0,
+    0x5a,0x8e,0x57,0x57,0x67,0x20,0x00,0x01,
+    0x01}},
+  {{0x5f,0x3f,0x3f,0x83,0x44,0x92,0x0e,0xf5,
+    0x02,0x86,0xff,0xff,0x0f,0x10,0x00,0x01,
+    0x01}},
+  {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x0e,0x5a,
+    0x02,0x86,0xff,0xff,0x0f,0x09,0x00,0x05,
+    0x01}},
+  {{0x76,0x56,0x56,0x9a,0x5b,0x89,0x28,0x10,
+    0x1c,0x80,0x19,0x19,0x29,0x0b,0x00,0x05,
+    0x00}}
+};
+
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11600x1200_1_H[]=
+{   /* MISSING */
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x7f,0x4f,0x83,0x62,0x12,0x72,0xba,
-   0x1c,0x80,0xdf,0x73,0x00,0x00,0x06,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
-   0x01}}
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_2[]=
-{ 
-{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT1800x600_2[]=
+{
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}}
+};
+
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_2[]=
+{   /* Checked (1.10.6s) */
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x72,0x88,0xdf,0xdf,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x63,0x63,0x87,0x78,0x89,0x24,0xf1,
+   0xae,0x84,0x57,0x57,0x25,0x30,0x00,0x02,
    0x01}},
- {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
    0x01}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_2[]=
-{
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_2[]=
+{   /* Checked (1.10.6s) */
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06,
    0x00}},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x06,
    0x00}},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06,
    0x00}},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x06,
    0x00}},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x72,0x88,0xdf,0xdf,0x25,0x30,0x00,0x06,
    0x00}},
- {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+ {{0xa3,0x63,0x63,0x87,0x78,0x89,0x24,0xf1,
+   0xae,0x84,0x57,0x57,0x25,0x30,0x00,0x02,
    0x01}},
- {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
    0x01}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT1800x600_2_H[]=
-{ 
-{{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11400x1050_2[]=
+{    /* Checked (1.10.6s) */
+ {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x03,
    0x00}},
- {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05,
+ {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xc2,0x86,0x5d,0x5d,0x29,0x01,0x00,0x03,
+   0x01}},
+ {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x03,
    0x00}},
- {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
+ {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xc2,0x86,0x5d,0x5d,0x29,0x01,0x00,0x03,
    0x00}},
- {{0x3d,0x27,0x81,0x3a,0x1a,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05,
+ {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9e,
+   0x03,0x87,0xdf,0xdf,0x29,0x01,0x00,0x03,
    0x00}},
- {{0x3d,0x27,0x81,0x32,0x1a,0x72,0xba,
-   0x1c,0x80,0xdf,0x73,0x00,0x00,0x05,
+ {{0xce,0x63,0x63,0x92,0x96,0x04,0x28,0xd4,
+   0x3f,0x83,0x57,0x57,0x29,0x01,0x00,0x07,
+   0x01}},
+ {{0xce,0x7f,0x7f,0x92,0xa4,0x12,0x28,0xd4,
+   0x93,0x87,0xff,0xff,0x29,0x21,0x00,0x07,
+   0x01}},
+ {{0xce,0x9f,0x9f,0x92,0xb4,0x02,0x28,0x5a,
+   0x13,0x87,0xff,0xff,0x29,0x29,0x00,0x03,
+   0x01}},
+ {{0xce,0xae,0xae,0x92,0xbc,0x0a,0x28,0x10,
+   0x20,0x84,0x19,0x19,0x29,0x0f,0x00,0x03,
+   0x00}}
+};
+
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11600x1200_2[]=
+{    /* MISSING */
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x05,
-   0x01}}
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_2_H[]=
-{ 
-{{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT1800x600_2_H[]=
+{
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}}
+};
+
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_2_H[]=
+{   /* Checked (1.10.6s) */
+ {{0x4f,0x27,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+ {{0x4f,0x27,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x31,0x87,0x8d,0x5d,0x25,0x30,0x00,0x01,   /* <-- invalid data */
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+ {{0x4f,0x27,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+ {{0x4f,0x27,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+ {{0x4f,0x27,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x72,0x88,0xdf,0xdf,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+ {{0x4f,0x31,0x31,0x93,0x3e,0x06,0x24,0xf1,
+   0xae,0x84,0x57,0x57,0x25,0x30,0x00,0x01,  /* <-- invalid data */
    0x01 }},
- {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+ {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
    0x01 }}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_2_H[]=
-{ 
-{{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_2_H[]=
+{   /* Checked (1.10.6s) */
+ {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb,
+   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+ {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb,
+   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+ {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb,
+   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+ {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb,
+   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+ {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb,
+   0x72,0x88,0xdf,0xdf,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x31,0x93,0x3e,0x86,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+ {{0x4f,0x31,0x31,0x93,0x3e,0x86,0x24,0xf1,
+   0xae,0x84,0x57,0x57,0x25,0x30,0x00,0x01,
    0x01 }},
- {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+ {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
    0x01 }}
 };
 
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11400x1050_2_H[]=
+{  /* Checked (1.10.6s) */
+ {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xc2,0x86,0x5d,0x5d,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xc2,0x86,0x5d,0x5d,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9e,
+   0x03,0x87,0xdf,0xdf,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0x9c,0x31,0x31,0x80,0x64,0x92,0x28,0xd4,
+   0x3f,0x83,0x57,0x57,0x29,0x01,0x00,0x06,
+   0x01}},
+ {{0x8e,0x3f,0x3f,0x92,0x64,0x12,0x28,0xd4,
+   0x93,0x87,0xff,0xff,0x29,0x21,0x00,0x06,
+   0x01}},
+ {{0x7e,0x4f,0x4f,0x82,0x64,0x12,0x28,0x5a,
+   0x13,0x87,0xff,0xff,0x29,0x29,0x00,0x06,
+   0x01}},
+ {{0x76,0x56,0x56,0x9a,0x64,0x92,0x28,0x10,
+   0x20,0x84,0x19,0x19,0x29,0x0f,0x00,0x05,
+   0x00}}
+};
+
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11600x1200_2_H[]=
+{  /* MISSING */
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}}
+};
+
 typedef struct _SiS310_LVDSCRT1DataStruct
 {
  	UCHAR CR[15];
 } SiS310_LVDSCRT1DataStruct;
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1320x480_1[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1320x480_1[] =
 {
-{{0x65,0x4f,0x89,0x56,0x83,0xaa,0x1f,
+ {{0x65,0x4f,0x89,0x56,0x83,0xaa,0x1f,
    0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
    0x00 }},
  {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
@@ -2330,412 +3380,958 @@
  {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
    0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
    0x01 }},
-{{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e,
+ {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e,
    0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
    0x00 }}
 };
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1[]=
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1[] =   /* TW: New */
 {
-{{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
+ {{0x6b,0x4f,0x8f,0x55,0x85,0xaa,0x1f,
    0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
    0x00 }},
- {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
+ {{0x6b,0x4f,0x8f,0x55,0x85,0x78,0x1f,
    0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
    0x00 }},
- {{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
+ {{0x6b,0x4f,0x8f,0x55,0x85,0xaa,0x1f,
    0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
    0x00 }},
- {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
+ {{0x6b,0x4f,0x8f,0x55,0x85,0x78,0x1f,
    0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
    0x00 }},
- {{0x65,0x4f,0x89,0x56,0x83,0x04,0x3e,
+ {{0x6b,0x4f,0x8f,0x55,0x85,0xfa,0x1f,
    0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
    0x00 }},
- {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+ {{0x7f,0x63,0x83,0x69,0x19,0x72,0xf0,
    0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
    0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1[] =    /* TW: New */
 {
-{{0x73,0x4f,0x97,0x55,0x86,0xc4,0x1f,
+ {{0x73,0x4f,0x97,0x53,0x84,0xb4,0x1f,
    0x92,0x89,0x8f,0xb5,0x30,0x00,0x05,
    0x00}},
- {{0x73,0x4f,0x97,0x55,0x86,0x97,0x1f,
+ {{0x73,0x4f,0x97,0x53,0x84,0x82,0x1f,
    0x60,0x87,0x5d,0x83,0x10,0x00,0x05,
    0x00}},
- {{0x73,0x4f,0x97,0x55,0x86,0xc4,0x1f,
+ {{0x73,0x4f,0x97,0x53,0x84,0xb4,0x1f,
    0x92,0x89,0x8f,0xb5,0x30,0x00,0x05,
    0x00}},
- {{0x73,0x4f,0x97,0x55,0x86,0x97,0x1f,
+ {{0x73,0x4f,0x97,0x53,0x84,0x82,0x1f,
    0x60,0x87,0x5d,0x83,0x10,0x00,0x05,
    0x00}},
- {{0x73,0x4f,0x97,0x55,0x86,0x04,0x3e,
+ {{0x73,0x4f,0x97,0x53,0x84,0x04,0x3e,
    0xE2,0x89,0xDf,0x05,0x00,0x00,0x05,
    0x00}},
- {{0x87,0x63,0x8B,0x69,0x1A,0x7c,0xf0,
-   0x5A,0x8F,0x57,0x7D,0x20,0x00,0x26,
+ {{0x87,0x63,0x8B,0x67,0x18,0x7c,0xf0,
+   0x5A,0x81,0x57,0x7D,0x00,0x00,0x06,
    0x01}},
- {{0xA3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xFf,0x25,0x10,0x00,0x02,
+ {{0xA3,0x7f,0x87,0x83,0x94,0x24,0xf5,
+   0x02,0x89,0xFf,0x25,0x10,0x00,0x02,
    0x01}}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1[] =    /* TW: New */
 {
-{{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+ {{0x7e,0x4f,0x82,0x56,0x04,0xb8,0x1f,
+   0x90,0x84,0x8f,0xb9,0x30,0x00,0x06,
    0x00 }},
- {{0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+ {{0x7e,0x4f,0x82,0x56,0x04,0x86,0x1f,
+   0x5e,0x82,0x5d,0x87,0x10,0x00,0x06,
    0x00 }},
- {{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+ {{0x7e,0x4f,0x82,0x56,0x04,0xb8,0x1f,
+   0x90,0x84,0x8f,0xb9,0x30,0x00,0x06,
    0x00 }},
- {{0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+ {{0x7e,0x4f,0x82,0x56,0x04,0x86,0x1f,
+   0x5e,0x82,0x5d,0x87,0x10,0x00,0x06,
    0x00 }},
- {{0x63,0x4f,0x87,0x54,0x9f,0x04,0x3e,
-   0xe2,0x89,0xdf,0x05,0x00,0x00,0x01,
+ {{0x7e,0x4f,0x82,0x56,0x04,0x08,0x3e,
+   0xe0,0x84,0xdf,0x09,0x00,0x00,0x06,
    0x00 }},
- {{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0,
-   0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26,
+ {{0x92,0x63,0x96,0x6a,0x18,0x80,0xf0,
+   0x58,0x8c,0x57,0x81,0x20,0x00,0x06,
    0x01 }},
- {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
-   0x01 }}
+ {{0xae,0x7f,0x92,0x86,0x94,0x28,0xf5,
+   0x00,0x84,0xff,0x29,0x10,0x00,0x02,
+   0x01 }},
+ {{0xce,0x9f,0x92,0xa6,0x14,0x28,0x5a,
+   0x00,0x84,0xff,0x29,0x09,0x00,0x07,
+   0x01}}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1_H[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1_H[] =    /* TW: New */
 {
-{{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
+ {{0x43,0x27,0x87,0x2d,0x1d,0xaa,0x1f,
+   0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
    0x00 }},
- {{0x30,0x27,0x94,0x2c,0x92,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x04,
+ {{0x43,0x27,0x87,0x2d,0x1d,0x78,0x1f,
+   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
    0x00 }},
- {{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
+ {{0x43,0x27,0x87,0x2d,0x1d,0xfa,0x1f,
+   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
    0x00 }},
- {{0x30,0x27,0x94,0x2c,0x92,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x04,
+ {{0x43,0x27,0x87,0x2d,0x1d,0x78,0x1f,
+   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
    0x00 }},
- {{0x30,0x27,0x94,0x2c,0x92,0x04,0x3e,
-   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x04,
+ {{0x43,0x27,0x87,0x2d,0x1d,0xfa,0x1f,
+   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
    0x00 }},
- {{0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x05,
+ {{0x4d,0x31,0x91,0x37,0x07,0x72,0xf0,
+   0x58,0x8d,0x57,0x73,0x20,0x00,0x01,
    0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1_H[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1_H[] =    /* TW: New */
 {
-{{0x37,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+ {{0x4b,0x27,0x8f,0x2b,0x1c,0xb4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x05,
    0x00 }},
- {{0x37,0x27,0x9B,0x2b,0x94,0x97,0x1f,
-   0x60,0x87,0x5D,0x83,0x01,0x00,0x44,
+ {{0x4b,0x27,0x8f,0x2b,0x1c,0x82,0x1f,
+   0x60,0x87,0x5D,0x83,0x01,0x00,0x05,
    0x00}},
- {{0x37,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+ {{0x4b,0x27,0x8f,0x2b,0x1c,0xb4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x05,
    0x00}},
- {{0x37,0x27,0x9B,0x2b,0x94,0x97,0x1f,
-   0x60,0x87,0x5D,0x83,0x01,0x00,0x44,
+ {{0x4b,0x27,0x8f,0x2b,0x1c,0x82,0x1f,
+   0x60,0x87,0x5D,0x83,0x01,0x00,0x05,
    0x00}},
- {{0x37,0x27,0x9B,0x2b,0x94,0x04,0x3e,
-   0xE2,0x89,0xDf,0x05,0x00,0x00,0x44,
+ {{0x4b,0x27,0x8f,0x2b,0x1c,0x04,0x3e,
+   0xE2,0x89,0xDf,0x05,0x00,0x00,0x05,
    0x00}},
- {{0x41,0x31,0x85,0x35,0x1d,0x7c,0xf0,
-   0x5A,0x8F,0x57,0x7D,0x20,0x00,0x55,
+ {{0x55,0x31,0x99,0x35,0x06,0x7c,0xf0,
+   0x5A,0x81,0x57,0x7D,0x00,0x00,0x01,
    0x01}},
- {{0x4f,0x3F,0x93,0x45,0x0D,0x24,0xf5,
-   0x02,0x88,0xFf,0x25,0x10,0x00,0x01,
+ {{0x63,0x3F,0x87,0x43,0x94,0x24,0xf5,
+   0x02,0x89,0xFf,0x25,0x10,0x00,0x01,
    0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1_H[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1_H[] =   /* TW: New */
 {
-{{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
+ {{0x56,0x27,0x9a,0x2e,0x1c,0xb8,0x1f,
+   0x90,0x84,0x8f,0xb9,0x30,0x00,0x05,
    0x00 }},
- {{0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x04,
+ {{0x56,0x27,0x9a,0x2e,0x1c,0x86,0x1f,
+   0x5e,0x82,0x5d,0x87,0x10,0x00,0x05,
    0x00 }},
- {{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
+ {{0x56,0x27,0x9a,0x2e,0x1c,0xb8,0x1f,
+   0x90,0x84,0x8f,0xb9,0x30,0x00,0x05,
    0x00 }},
- {{0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x04,
-   0x00 }},
- {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
-   0xe2,0x89,0xdf,0x05,0x00,0x00,0x04,
+ {{0x56,0x27,0x9a,0x2e,0x1c,0x86,0x1f,
+   0x5e,0x82,0x5d,0x87,0x10,0x00,0x05,
+   0x01 }},
+ {{0x56,0x27,0x9a,0x2e,0x1c,0x08,0x3e,
+   0xe0,0x84,0xdf,0x09,0x00,0x00,0x05,
    0x00 }},
- {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
-   0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
+ {{0x60,0x31,0x84,0x38,0x86,0x80,0xf0,
+   0x58,0x8c,0x57,0x81,0x20,0x00,0x01,
    0x01 }},
- {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+ {{0x6e,0x3f,0x92,0x46,0x94,0x28,0xf5,
+   0x00,0x84,0xff,0x29,0x10,0x00,0x01,
    0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2[]=
-{ 
-{{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2[]=   /* TW: New */
+{
+ {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
+   0xff,0x84,0x8f,0x73,0x00,0x00,0x06,
    0x00 }},
  {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06,
+   0xe6,0x8b,0x5d,0x73,0x00,0x00,0x06,
    0x00 }},
  {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
+   0xff,0x84,0x8f,0x73,0x00,0x00,0x06,
    0x00 }},
  {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06,
+   0xe6,0x8b,0x5d,0x73,0x00,0x00,0x06,
    0x00 }},
  {{0x7f,0x4f,0x83,0x62,0x12,0x72,0xba,
-   0x1c,0x80,0xdf,0x73,0x00,0x00,0x06,
+   0x27,0x8c,0xdf,0x73,0x00,0x00,0x06,
    0x00 }},
- {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+ {{0x7f,0x63,0x83,0x69,0x19,0x72,0xf0,
+   0x58,0x8d,0x57,0x73,0x20,0x00,0x06,
    0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2[] =   /* TW: New */
 { 
-{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
-   0x00 }},
  {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+   0x57,0x8e,0x8f,0x25,0x30,0x00,0x06,
    0x00 }},
  {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+   0x3e,0x85,0x5d,0x25,0x10,0x00,0x06,
    0x00 }},
  {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+   0x57,0x8e,0x8f,0x25,0x30,0x00,0x06,
    0x00 }},
  {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+   0x3e,0x85,0x5d,0x25,0x10,0x00,0x06,
+   0x01 }},
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x7f,0x86,0xdf,0x25,0x10,0x00,0x06,
    0x00 }},
  {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+   0xbb,0x82,0x57,0x25,0x10,0x00,0x02,
    0x01 }},
- {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+ {{0xa3,0x7f,0x87,0x83,0x94,0x24,0xf5,
+   0x02,0x89,0xff,0x25,0x10,0x00,0x02,
    0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2[]=
-{ 
-{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2[] =  /* TW: New */
+{
+ {{0xce,0x4f,0x92,0x81,0x0f,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03,
    0x00 }},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+ {{0xce,0x4f,0x92,0x81,0x0f,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x03,
    0x00 }},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+ {{0xce,0x4f,0x92,0x81,0x0f,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03,
    0x00 }},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+ {{0xce,0x4f,0x92,0x81,0x0f,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x03,
    0x00 }},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+ {{0xce,0x4f,0x92,0x81,0x0f,0x28,0x9e,
+   0x03,0x87,0xdf,0x29,0x01,0x00,0x03,
    0x00 }},
- {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+ {{0xce,0x63,0x92,0x8b,0x19,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x03,
    0x01 }},
- {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
-   0x01 }}
+ {{0xce,0x7f,0x92,0x99,0x07,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x07,
+   0x01 }},
+ {{0xce,0x9f,0x92,0xa6,0x14,0x28,0x5a,
+   0x00,0x84,0xff,0x29,0x09,0x00,0x07,
+   0x01}}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2_H[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2_H[] =   /* TW: New */
 { 
-{{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
+ {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e,
+   0xff,0x84,0x8f,0x73,0x00,0x00,0x01,
    0x00 }},
- {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05,
+ {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e,
+   0xd6,0x8b,0x5d,0x73,0x00,0x00,0x01,
    0x00 }},
- {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
+ {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e,
+   0xff,0x84,0x8f,0x73,0x00,0x00,0x01,
    0x00 }},
- {{0x3d,0x27,0x81,0x3a,0x1a,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05,
+ {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e,
+   0xd6,0x8b,0x5d,0x73,0x00,0x00,0x01,
    0x00 }},
- {{0x3d,0x27,0x81,0x32,0x1a,0x72,0xba,
-   0x1c,0x80,0xdf,0x73,0x00,0x00,0x05,
+ {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0xba,
+   0x27,0x8c,0xdf,0x73,0x00,0x00,0x01,
    0x00 }},
- {{0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x05,
+ {{0x4d,0x31,0x91,0x3a,0x0a,0x72,0xf0,
+   0x63,0x88,0x57,0x73,0x00,0x00,0x01,
    0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2_H[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2_H[] =   /* TW: New */
 { 
-{{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+ {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb,
+   0x57,0x8e,0x8f,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+ {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb,
+   0x3e,0x85,0x5d,0x25,0x10,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+ {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb,
+   0x57,0x8e,0x8f,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+ {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb,
+   0x3e,0x85,0x5d,0x25,0x10,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+ {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb,
+   0x7f,0x86,0xdf,0x25,0x10,0x00,0x01,
    0x00 }},
- {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+ {{0x71,0x31,0x95,0x46,0x97,0x24,0xf1,
+   0xbb,0x82,0x57,0x25,0x10,0x00,0x01,
    0x01 }},
- {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+ {{0x63,0x3f,0x87,0x46,0x97,0x24,0xf5,
+   0x0f,0x86,0xff,0x25,0x30,0x00,0x01,
    0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2_H[]=
-{ 
-{{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2_H[] =   /* TW: New */
+{
+ {{0xa6,0x27,0x8a,0x59,0x87,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+ {{0xa6,0x27,0x8a,0x59,0x87,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x06,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+ {{0xa6,0x27,0x8a,0x59,0x87,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+ {{0xa6,0x27,0x8a,0x59,0x87,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x06,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+ {{0xa6,0x27,0x8a,0x59,0x87,0x28,0x9e,
+   0x03,0x87,0xdf,0x29,0x01,0x00,0x06,
    0x00 }},
- {{0x4f,0x31,0x93,0x3e,0x86,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+ {{0x9c,0x31,0x80,0x59,0x87,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x06,
    0x01 }},
- {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+ {{0x8e,0x3f,0x92,0x79,0x07,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x06,
+   0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1XXXxXXX_1[] =   /* TW: New */
+{
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x05,
+   0x00}},
+ {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+   0x01}},
+ {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+   0x01}},
+ {{0xce,0x9f,0x92,0xa9,0x17,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x07,
+   0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1XXXxXXX_1_H[] =   /* TW: New */
+{
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
+   0x00}},
+ {{0x4d,0x31,0x91,0x3b,0x03,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x01,
+   0x01}},
+ {{0x63,0x3f,0x87,0x4a,0x92,0x24,0xf5,
    0x02,0x88,0xff,0x25,0x10,0x00,0x01,
    0x01}}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1UNTSC[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_1[] =   /* TW: New */
+{
+ {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+   0x93,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+   0x93,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0xee,0x1f,
+   0xe2,0x86,0xdf,0xef,0x10,0x00,0x05,
+   0x00}},
+ {{0x83,0x63,0x87,0x68,0x16,0x66,0xf0,
+   0x5a,0x8e,0x57,0x67,0x20,0x00,0x06,
+   0x01}},
+ {{0x9f,0x7f,0x83,0x84,0x92,0x0e,0xf5,
+   0x02,0x86,0xff,0x0f,0x10,0x00,0x02,
+   0x01}},
+ {{0xbf,0x9f,0x83,0xa4,0x12,0x0e,0x5a,
+   0x02,0x86,0xff,0x0f,0x09,0x00,0x07,
+   0x01}},
+ {{0xce,0xae,0x92,0xb3,0x01,0x28,0x10,
+   0x1a,0x80,0x19,0x29,0x0f,0x00,0x03,
+   0x00}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_1_H[] =   /* TW: New */
+{
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x9e,0x1f,
+   0x93,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x30,0x1e,0x9e,0x1f,
+   0x92,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0xee,0x1f,
+   0xe2,0x86,0xdf,0xef,0x10,0x00,0x05,
+   0x00}},
+ {{0x51,0x31,0x95,0x36,0x04,0x66,0xf0,
+   0x5a,0x8e,0x57,0x67,0x20,0x00,0x01,
+   0x01}},
+ {{0x5f,0x3f,0x83,0x44,0x92,0x0e,0xf5,
+   0x02,0x86,0xff,0x0f,0x10,0x00,0x01,
+   0x01}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a,
+   0x02,0x86,0xff,0x0f,0x09,0x00,0x05,
+   0x01}},
+ {{0x76,0x56,0x9a,0x5b,0x89,0x28,0x10,
+   0x1c,0x80,0x19,0x29,0x0b,0x00,0x05,
+   0x00}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_2[] =    /* TW: New */
+{
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03,
+   0x00}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x03,
+   0x01}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03,
+   0x00}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x03,
+   0x00}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9e,
+   0x03,0x87,0xdf,0x29,0x01,0x00,0x03,
+   0x00}},
+ {{0xce,0x63,0x92,0x96,0x04,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x07,
+   0x01}},
+ {{0xce,0x7f,0x92,0xa4,0x12,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x07,
+   0x01}},
+ {{0xce,0x9f,0x92,0xb4,0x02,0x28,0x5a,
+   0x13,0x87,0xff,0x29,0x29,0x00,0x03,
+   0x01}},
+ {{0xce,0xae,0x92,0xbc,0x0a,0x28,0x10,
+   0x20,0x84,0x19,0x29,0x0f,0x00,0x03,
+   0x00}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_2_H[] =    /* TW: New */
+{
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9e,
+   0x03,0x87,0xdf,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0x9c,0x31,0x80,0x64,0x92,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x06,
+   0x01}},
+ {{0x8e,0x3f,0x92,0x64,0x12,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x06,
+   0x01}},
+ {{0x7e,0x4f,0x82,0x64,0x12,0x28,0x5a,
+   0x13,0x87,0xff,0x29,0x29,0x00,0x06,
+   0x01}},
+ {{0x76,0x56,0x9a,0x64,0x92,0x28,0x10,
+   0x20,0x84,0x19,0x29,0x0f,0x00,0x05,
+   0x00}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x600_1[] =
+{
+        {{0x64,0x4f,0x88,0x54,0x9f,0x5a,0x3e,
+	  0xe8,0x8f,0x8f,0x5b,0x00,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x2e,0x3e,
+	  0xb9,0x80,0x5d,0x2f,0x00,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x5a,0x3e,
+	  0xe8,0x8f,0x8f,0x5b,0x00,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x2e,0x3e,
+	  0xb9,0x80,0x5d,0x2f,0x00,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0xaf,0xba,
+	  0x3b,0x82,0xdf,0xb0,0x00,0x00,0x01,
+	  0x00}},
+        {{0x7e,0x63,0x82,0x68,0x15,0x1e,0xf1,
+	  0xae,0x85,0x57,0x1f,0x30,0x00,0x26,
+	  0x01}},
+        {{0xa3,0x7f,0x87,0x86,0x97,0x1e,0xf1,
+	  0xae,0x85,0x57,0x1f,0x30,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x600_1_H[] =
+{
+        {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+          0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
+	  0xe2,0x89,0xdf,0x05,0x00,0x00,0x44,
+	  0x00}},
+        {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
+	  0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
+	  0x01}},
+        {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x600_2[] =
+{
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+          0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+	  0x01}},
+        {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x600_2_H[] =
+{
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+	  0x01}},
+        {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11152x768_1[] =
+{
+        {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x04,0x3e,
+	  0xe2,0x89,0xdf,0x05,0x00,0x00,0x01,
+	  0x00}},
+        {{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0,
+	  0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26,
+	  0x01}},
+        {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11152x768_1_H[] =
+{
+        {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
+	  0xe2,0x89,0xdf,0x05,0x00,0x00,0x44,
+	  0x00}},
+        {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
+	  0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
+	  0x01}},
+        {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11152x768_2[] =
+{
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+	  0x01}},
+        {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11152x768_2_H[] =
+{
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+	  0x01}},
+        {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_1[] =  
+{    /* TW: Temporary data - invalid */
+ {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+   0x93,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+   0x93,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0xee,0x1f,
+   0xe2,0x86,0xdf,0xef,0x10,0x00,0x05,
+   0x00}},
+ {{0x83,0x63,0x87,0x68,0x16,0x66,0xf0,
+   0x5a,0x8e,0x57,0x67,0x20,0x00,0x06,
+   0x01}},
+ {{0x9f,0x7f,0x83,0x84,0x92,0x0e,0xf5,
+   0x02,0x86,0xff,0x0f,0x10,0x00,0x02,
+   0x01}},
+ {{0xbf,0x9f,0x83,0xa4,0x12,0x0e,0x5a,
+   0x02,0x86,0xff,0x0f,0x09,0x00,0x07,
+   0x01}},
+ {{0xce,0xae,0x92,0xb3,0x01,0x28,0x10,
+   0x1a,0x80,0x19,0x29,0x0f,0x00,0x03,
+   0x00}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_1_H[] =
+{    /* TW: Temporary data - invalid */
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x9e,0x1f,
+   0x93,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x30,0x1e,0x9e,0x1f,
+   0x92,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0xee,0x1f,
+   0xe2,0x86,0xdf,0xef,0x10,0x00,0x05,
+   0x00}},
+ {{0x51,0x31,0x95,0x36,0x04,0x66,0xf0,
+   0x5a,0x8e,0x57,0x67,0x20,0x00,0x01,
+   0x01}},
+ {{0x5f,0x3f,0x83,0x44,0x92,0x0e,0xf5,
+   0x02,0x86,0xff,0x0f,0x10,0x00,0x01,
+   0x01}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a,
+   0x02,0x86,0xff,0x0f,0x09,0x00,0x05,
+   0x01}},
+ {{0x76,0x56,0x9a,0x5b,0x89,0x28,0x10,
+   0x1c,0x80,0x19,0x29,0x0b,0x00,0x05,
+   0x00}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_2[] =
+{    /* TW: Temporary data - invalid */
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03,
+   0x00}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x03,
+   0x01}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03,
+   0x00}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x03,
+   0x00}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9e,
+   0x03,0x87,0xdf,0x29,0x01,0x00,0x03,
+   0x00}},
+ {{0xce,0x63,0x92,0x96,0x04,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x07,
+   0x01}},
+ {{0xce,0x7f,0x92,0xa4,0x12,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x07,
+   0x01}},
+ {{0xce,0x9f,0x92,0xb4,0x02,0x28,0x5a,
+   0x13,0x87,0xff,0x29,0x29,0x00,0x03,
+   0x01}},
+ {{0xce,0xae,0x92,0xbc,0x0a,0x28,0x10,
+   0x20,0x84,0x19,0x29,0x0f,0x00,0x03,
+   0x00}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_2_H[] =    /* TW: New */
+{    /* TW: Temporary data - invalid */
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9e,
+   0x03,0x87,0xdf,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0x9c,0x31,0x80,0x64,0x92,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x06,
+   0x01}},
+ {{0x8e,0x3f,0x92,0x64,0x12,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x06,
+   0x01}},
+ {{0x7e,0x4f,0x82,0x64,0x12,0x28,0x5a,
+   0x13,0x87,0xff,0x29,0x29,0x00,0x06,
+   0x01}},
+ {{0x76,0x56,0x9a,0x64,0x92,0x28,0x10,
+   0x20,0x84,0x19,0x29,0x0f,0x00,0x05,
+   0x00}}
+};
+
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1UNTSC[] =    /* TW: New */
 { 
-{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
-   0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
-   0x00 }},
- {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
-   0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,
-   0x00 }},
- {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
-   0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
-   0x00 }},
- {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
-   0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,
-   0x00 }},
- {{0x5d,0x4f,0x81,0x53,0x9c,0x56,0xba,
-   0x18,0x84,0xdf,0x57,0x00,0x00,0x01,
-   0x00 }},
- {{0x80,0x63,0x84,0x6c,0x17,0xec,0xf0,
-   0x90,0x8c,0x57,0xed,0x20,0x00,0x06,
-   0x01 }}
+	{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+	  0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+	  0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+	  0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+	  0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x5d,0x4f,0x81,0x56,0x99,0x56,0xba,
+	  0x0a,0x84,0xdf,0x57,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x80,0x63,0x84,0x6d,0x0f,0xec,0xf0,
+	  0x7a,0x8f,0x57,0xed,0x20,0x00,0x06,
+	  0x01 }},
+	{{0x8c,0x7f,0x90,0x86,0x09,0xaf,0xf5,  /* TW: 1024x768 */
+	  0x36,0x88,0xff,0xb0,0x10,0x00,0x02,
+	  0x01}}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1ONTSC[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1ONTSC[] =    /* TW: New */
 { 
-{{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
-   0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
-   0x00 }},
- {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
-   0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,
-   0x00 }},
- {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
-   0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
-   0x00 }},
- {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
-   0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,
-   0x00 }},
- {{0x5d,0x4f,0x81,0x56,0x9c,0x0b,0x3e,
-   0xe8,0x84,0xdf,0x0c,0x00,0x00,0x01,
-   0x00 }},
- {{0x7d,0x63,0x81,0x6a,0x16,0xba,0xf0,
-   0x7f,0x86,0x57,0xbb,0x00,0x00,0x06,
-   0x01 }}
+	{{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e,
+	  0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
+	  0x00 }},
+	{{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e,
+	  0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e,
+	  0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
+	  0x00 }},
+	{{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e,
+	  0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x5d,0x4f,0x81,0x58,0x9d,0x0b,0x3e,
+	  0xe8,0x84,0xdf,0x0c,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x7d,0x63,0x81,0x68,0x0e,0xba,0xf0,
+	  0x78,0x8a,0x57,0xbb,0x20,0x00,0x06,
+	  0x01 }},
+	{{0x8c,0x7f,0x90,0x82,0x06,0x46,0xf5,   /* TW: 1024x768 */
+	  0x15,0x88,0xff,0x47,0x70,0x00,0x02,
+	  0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1UPAL[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1UPAL[] =    /* TW: New */
 { 
-{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
-   0x00 }},
- {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
-   0x00 }},
- {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
-   0x00 }},
- {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
-   0x00 }},
- {{0x64,0x4f,0x88,0x55,0x80,0xec,0xba,
-   0x50,0x84,0xdf,0xed,0x00,0x00,0x05,
-   0x00 }},
- {{0x70,0x63,0x94,0x68,0x8d,0x42,0xf1,
-   0xc8,0x8c,0x57,0xe9,0x20,0x00,0x05,
-   0x01 }}
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x5a,0x9f,0x6f,0xba,
+	  0x15,0x83,0xdf,0x70,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x73,0x63,0x97,0x69,0x8b,0xec,0xf0,
+	  0x90,0x8c,0x57,0xed,0x20,0x00,0x05,
+	  0x01 }},
+	{{0xaa,0x7f,0x8e,0x8e,0x96,0xe6,0xf5,   /* TW: 1024x768 */
+	  0x50,0x88,0xff,0xe7,0x10,0x00,0x02,
+	  0x01}}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1OPAL[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1OPAL[] =    /* TW: New */
 { 
-{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
-   0x00 }},
- {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
-   0x00 }},
- {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
-   0x00 }},
- {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
-   0x00 }},
- {{0x64,0x4f,0x88,0x55,0x80,0x6f,0xba,
-   0x20,0x83,0xdf,0x70,0x00,0x00,0x05,
-   0x00 }},
- {{0x73,0x63,0x97,0x69,0x8e,0xec,0xf0,
-   0x90,0x8c,0x57,0xed,0x20,0x00,0x05,
-   0x01 }}
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x58,0x9d,0x6f,0xba,
+	  0x15,0x83,0xdf,0x70,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x71,0x63,0x95,0x69,0x8c,0x6f,0xf0,
+	  0x5a,0x8b,0x57,0x70,0x20,0x00,0x05,
+	  0x01 }},
+	{{0xaa,0x7f,0x8e,0x8f,0x96,0x69,0xf5,   /* TW:  1024x768 */
+	  0x28,0x88,0xff,0x6a,0x10,0x00,0x02,
+	  0x01 }}
 };
 
+/* TW: New data for Chrontel 7019 (From 650/LVDS BIOS 1.10.0) */
 typedef struct _SiS310_CHTVRegDataStruct
 {
- 	UCHAR Reg[5];
+ 	UCHAR Reg[16];
 } SiS310_CHTVRegDataStruct;
 
-SiS310_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] = {
-	{{0x00}}
- };
-
-SiS310_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] = {
-	{{0x00}}
- };
-
-SiS310_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] = {
-	{{0x00}}
- };
-
-SiS310_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] = {
-	{{0x00}}
- };
-
-UCHAR SiS310_CHTVVCLKUNTSC[]={0x00 };
+static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] = {
+	{{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x6a,0x77,0xbb,0x6e,0x84,0x2e,0x02,0x5a,0x04,0x00,0x80,0x20,0x7e,0x80,0x98,0x00}},
+	{{0xcf,0x77,0xb7,0xc8,0x84,0x3b,0x02,0x5a,0x04,0x00,0x80,0x19,0x88,0x30,0x7f,0x00}},
+	{{0xee,0x77,0xbb,0x66,0x87,0x32,0x01,0x5a,0x04,0x00,0x80,0x1b,0xd3,0xf2,0x36,0x00}}
+};
+
+static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] = {
+	{{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x69,0x77,0xbb,0x6e,0x84,0x1e,0x00,0x5a,0x04,0x00,0x80,0x25,0x1a,0x43,0x04,0x00}},
+	{{0xce,0x77,0xb7,0xb6,0x83,0x2c,0x02,0x5a,0x04,0x00,0x80,0x1c,0x00,0x82,0x97,0x00}},
+	{{0xed,0x77,0xbb,0x66,0x8c,0x21,0x02,0x5a,0x04,0x00,0x80,0x1f,0x9f,0xc1,0x0c,0x00}}
+};
+
+static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] = {
+	{{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x41,0x7f,0xb7,0x80,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x41,0x7f,0xb7,0x12,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x5a,0x05,0x00,0x80,0x26,0x2a,0x55,0x5d,0x00}},
+	{{0xc3,0x7f,0xb7,0x7a,0x84,0x40,0x02,0x5a,0x05,0x00,0x80,0x1f,0x84,0x3d,0x28,0x00}},
+	{{0xe5,0x7f,0xb7,0x1d,0xa7,0x3e,0x04,0x5a,0x05,0x00,0x80,0x20,0x3e,0xe4,0x22,0x00}}
+};
+
+static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] = {
+	{{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x5a,0x05,0x00,0x80,0x26,0x2a,0x55,0x5d,0x00}},
+	{{0xc1,0x7f,0xb7,0x4d,0x8c,0x1e,0x31,0x5a,0x05,0x00,0x80,0x26,0x78,0x19,0x34,0x00}},
+	{{0xe4,0x7f,0xb7,0x1e,0xaf,0x29,0x37,0x5a,0x05,0x00,0x80,0x25,0x8c,0xb2,0x2a,0x00}}
+};
 
-UCHAR SiS310_CHTVVCLKONTSC[]={0x00 };
+static const UCHAR SiS310_CHTVVCLKUNTSC[] = {0x41,0x41,0x41,0x41,0x42,0x46,0x53};
 
-UCHAR SiS310_CHTVVCLKUPAL[]={0x00 };
+static const UCHAR SiS310_CHTVVCLKONTSC[] = {0x48,0x48,0x48,0x48,0x45,0x43,0x51};
 
-UCHAR SiS310_CHTVVCLKOPAL[]={0x00 };
+static const UCHAR SiS310_CHTVVCLKUPAL[]  = {0x47,0x47,0x47,0x47,0x48,0x4a,0x54};
 
+static const UCHAR SiS310_CHTVVCLKOPAL[]  = {0x47,0x47,0x47,0x47,0x48,0x4f,0x52};
+/* TW: New end */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/325vtbl.h linux-2.4.20/drivers/video/sis/325vtbl.h
--- linux-2.4.19/drivers/video/sis/325vtbl.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/325vtbl.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,2323 +0,0 @@
-typedef struct _SiS310_StStruct
-{
- UCHAR St_ModeID;
- USHORT St_ModeFlag;
- UCHAR St_StTableIndex;
- UCHAR St_CRT2CRTC;
- UCHAR St_ResInfo;
- UCHAR VB_StTVFlickerIndex;
- UCHAR VB_StTVEdgeIndex;
- UCHAR VB_StTVYFilterIndex;
-} SiS310_StStruct;
-SiS310_StStruct SiS310_SModeIDTable[]=
-{ {0x01,0x9208,0x01,0x00,0x00,0x00,0x01,0x00},
- {0x01,0x1210,0x14,0x01,0x01,0x00,0x01,0x00},
- {0x01,0x1010,0x17,0x02,0x02,0x00,0x01,0x01},
- {0x03,0x8208,0x03,0x00,0x00,0x00,0x01,0x02},
- {0x03,0x0210,0x16,0x01,0x01,0x00,0x01,0x02},
- {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03},
- {0x05,0x9209,0x05,0x00,0x00,0x00,0x00,0x04},
- {0x06,0x8209,0x06,0x00,0x00,0x00,0x00,0x05},
- {0x07,0x0000,0x07,0x03,0x03,0x00,0x01,0x03},
- {0x07,0x0000,0x19,0x02,0x02,0x00,0x01,0x03},
- {0x0d,0x920a,0x0d,0x00,0x00,0x00,0x00,0x04},
- {0x0e,0x820a,0x0e,0x00,0x00,0x00,0x00,0x05},
- {0x0f,0x0202,0x11,0x01,0x01,0x00,0x00,0x05},
- {0x10,0x0212,0x12,0x01,0x01,0x00,0x00,0x05},
- {0x11,0x0212,0x1a,0x04,0x04,0x00,0x00,0x05},
- {0x12,0x0212,0x1b,0x04,0x04,0x00,0x00,0x05},
- {0x13,0x021b,0x1c,0x00,0x00,0x00,0x00,0x04},
- {0x12,0x0010,0x18,0x02,0x02,0x00,0x00,0x05},
- {0x12,0x0210,0x18,0x01,0x01,0x00,0x00,0x05},
- {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00}
-};
-
-typedef struct _SiS310_StandTableStruct
-{
- UCHAR CRT_COLS;
- UCHAR ROWS;
- UCHAR CHAR_HEIGHT;
- USHORT CRT_LEN;
- UCHAR SR[4];
- UCHAR MISC;
- UCHAR CRTC[0x19];
- UCHAR ATTR[0x14];
- UCHAR GRC[9];
-} SiS310_StandTableStruct;
-SiS310_StandTableStruct SiS310_StandTable[]=
-{
-/* MD_0_200 */
- {
-  0x28,0x18,0x08,0x0800,
-  {0x09,0x03,0x00,0x02},
-  0x63,
-  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
-   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
-   0x08,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_1_200 */
- {
-  0x28,0x18,0x08,0x0800,
-  {0x09,0x03,0x00,0x02},
-  0x63,
-  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
-   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
-   0x08,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_2_200 */
- {
-  0x50,0x18,0x08,0x1000,
-  {0x01,0x03,0x00,0x02},
-  0x63,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
-   0x08,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_3_200 */
- {
-  0x50,0x18,0x08,0x1000,
-  {0x01,0x03,0x00,0x02},
-  0x63,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
-   0x08,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_4 */
- {
-  0x28,0x18,0x08,0x4000,
-  {0x09,0x03,0x00,0x02},
-  0x63,
-  {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
-   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,
-   0xff},
-  {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,
-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
-   0x01,0x00,0x03,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00,
-   0xff}
- },
-/* MD_5 */
- {
-  0x28,0x18,0x08,0x4000,
-  {0x09,0x03,0x00,0x02},
-  0x63,
-  {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
-   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,
-   0xff},
-  {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,
-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
-   0x01,0x00,0x03,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00,
-   0xff}
- },
-/* MD_6 */
- {
-  0x50,0x18,0x08,0x4000,
-  {0x01,0x01,0x00,0x06},
-  0x63,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xc2,
-   0xff},
-  {0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
-   0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
-   0x01,0x00,0x01,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x00,
-   0xff}
- },
-/* MD_7 */
- {
-  0x50,0x18,0x0e,0x1000,
-  {0x00,0x03,0x00,0x03},
-  0xa6,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
-   0x83,0x85,0x5d,0x28,0x0d,0x63,0xba,0xa3,
-   0xff},
-  {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
-   0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-   0x0e,0x00,0x0f,0x08},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00,
-   0xff}
- },
-/* MDA_DAC */
- {
-  0x00,0x00,0x00,0x0000,
-  {0x00,0x00,0x00,0x15},
-  0x15,
-  {0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-   0x15,0x15,0x15,0x15,0x15,0x15,0x3f,0x3f,
-   0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x00,0x00,
-   0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x15,0x15,0x15,
-   0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-   0x15,0x15,0x15,0x15},
-  {0x15,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
-   0x3f}
- },
-/* CGA_DAC */
- {
-  0x00,0x10,0x04,0x0114,
-  {0x11,0x09,0x15,0x00},
-  0x10,
-  {0x04,0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,
-   0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x2a,0x3a,
-   0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x10,
-   0x04},
-  {0x14,0x01,0x11,0x09,0x15,0x00,0x10,0x04,
-   0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,0x2e,
-   0x3e,0x2b,0x3b,0x2f},
-  {0x3f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f,
-   0x3f}
- },
-/* EGA_DAC */
- {
-  0x00,0x10,0x04,0x0114,
-  {0x11,0x05,0x15,0x20},
-  0x30,
-  {0x24,0x34,0x21,0x31,0x25,0x35,0x08,0x18,
-   0x0c,0x1c,0x09,0x19,0x0d,0x1d,0x28,0x38,
-   0x2c,0x3c,0x29,0x39,0x2d,0x3d,0x02,0x12,
-   0x06},
-  {0x16,0x03,0x13,0x07,0x17,0x22,0x32,0x26,
-   0x36,0x23,0x33,0x27,0x37,0x0a,0x1a,0x0e,
-   0x1e,0x0b,0x1b,0x0f},
-  {0x1f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f,
-   0x3f}
- },
-/* VGA_DAC */
- {
-  0x00,0x10,0x04,0x0114,
-  {0x11,0x09,0x15,0x2a},
-  0x3a,
-  {0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x05,
-   0x08,0x0b,0x0e,0x11,0x14,0x18,0x1c,0x20,
-   0x24,0x28,0x2d,0x32,0x38,0x3f,0x00,0x10,
-   0x1f},
-  {0x2f,0x3f,0x1f,0x27,0x2f,0x37,0x3f,0x2d,
-   0x31,0x36,0x3a,0x3f,0x00,0x07,0x0e,0x15,
-   0x1c,0x0e,0x11,0x15},
-  {0x18,0x1c,0x14,0x16,0x18,0x1a,0x1c,0x00,
-   0x04}
- },
- {
-  0x08,0x0c,0x10,0x0a08,
-  {0x0c,0x0e,0x10,0x0b},
-  0x0c,
-  {0x0d,0x0f,0x10,0x10,0x01,0x08,0x00,0x00,
-   0x00,0x00,0x01,0x00,0x02,0x02,0x01,0x00,
-   0x04,0x04,0x01,0x00,0x05,0x02,0x05,0x00,
-   0x06},
-  {0x01,0x06,0x05,0x06,0x00,0x08,0x01,0x08,
-   0x00,0x07,0x02,0x07,0x06,0x07,0x00,0x00,
-   0x00,0x00,0x00,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x00}
- },
-/* MD_D */
- {
-  0x28,0x18,0x08,0x2000,
-  {0x09,0x0f,0x00,0x06},
-  0x63,
-  {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
-   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xe3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
-   0x01,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
-   0xff}
- },
-/* MD_E */
- {
-  0x50,0x18,0x08,0x4000,
-  {0x01,0x0f,0x00,0x06},
-  0x63,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xe3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
-   0x01,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
-   0xff}
- },
-/* ExtVGATable */
- {
-  0x00,0x00,0x00,0x0000,
-  {0x01,0x0f,0x00,0x0e},
-  0x23,
-  {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-   0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-   0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
-   0x01,0x00,0x00,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
-   0xff}
- },
-/* ROM_SAVEPTR */
- {
-  0x9f,0x3b,0x00,0x00c0,
-  {0x00,0x00,0x00,0x00},
-  0x00,
-  {0x00,0x00,0x00,0x00,0x00,0x00,0xbb,0x3f,
-   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x00,0x00,0x1a,0x00,0xac,0x3e,0x00,0xc0,
-   0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x00,0x00,0x00,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x00}
- },
-/* MD_F */
- {
-  0x50,0x18,0x0e,0x8000,
-  {0x01,0x0f,0x00,0x06},
-  0xa2,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3,
-   0xff},
-  {0x00,0x08,0x00,0x00,0x18,0x18,0x00,0x00,
-   0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,
-   0x0b,0x00,0x05,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x05,
-   0xff}
- },
-/* MD_10 */
- {
-  0x50,0x18,0x0e,0x8000,
-  {0x01,0x0f,0x00,0x06},
-  0xa3,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-   0x01,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
-   0xff}
- },
-/* MD_0_350 */
- {
-  0x28,0x18,0x0e,0x0800,
-  {0x09,0x03,0x00,0x02},
-  0xa3,
-  {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f,
-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
-   0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-   0x08,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_1_350 */
- {
-  0x28,0x18,0x0e,0x0800,
-  {0x09,0x03,0x00,0x02},
-  0xa3,
-  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
-   0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-   0x08,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_2_350 */
- {
-  0x50,0x18,0x0e,0x1000,
-  {0x01,0x03,0x00,0x02},
-  0xa3,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
-   0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-   0x08,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_3_350 */
- {
-  0x50,0x18,0x0e,0x1000,
-  {0x01,0x03,0x00,0x02},
-  0xa3,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
-   0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-   0x08,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_0_1_400 */
- {
-  0x28,0x18,0x10,0x0800,
-  {0x08,0x03,0x00,0x02},
-  0x67,
-  {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f,
-   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-   0x0c,0x00,0x0f,0x08},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_2_3_400 */
- {
-  0x50,0x18,0x10,0x1000,
-  {0x00,0x03,0x00,0x02},
-  0x67,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-   0x0c,0x00,0x0f,0x08},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_7_400 */
- {
-  0x50,0x18,0x10,0x1000,
-  {0x00,0x03,0x00,0x02},
-  0x66,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x28,0x0f,0x96,0xb9,0xa3,
-   0xff},
-  {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
-   0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-   0x0e,0x00,0x0f,0x08},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00,
-   0xff}
- },
-/* MD_11 */
- {
-  0x50,0x1d,0x10,0xa000,
-  {0x01,0x0f,0x00,0x06},
-  0xe3,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-   0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xc3,
-   0xff},
-  {0x00,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
-   0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
-   0x01,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x01,
-   0xff}
- },
-/* ExtEGATable */
- {
-  0x50,0x1d,0x10,0xa000,
-  {0x01,0x0f,0x00,0x06},
-  0xe3,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-   0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xe3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-   0x01,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
-   0xff}
- },
-/* MD_13 */
- {
-  0x28,0x18,0x08,0x2000,
-  {0x01,0x0f,0x00,0x0e},
-  0x63,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x28,0x40,0x96,0xb9,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-   0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
-   0x41,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
-   0xff}
- }
-};
-
-typedef struct _SiS310_ExtStruct
-{
- UCHAR Ext_ModeID;
- USHORT Ext_ModeFlag;
- USHORT Ext_ModeInfo;
- USHORT Ext_Point;
- USHORT Ext_VESAID;
- UCHAR Ext_VESAMEMSize;
- UCHAR Ext_RESINFO;
- UCHAR VB_ExtTVFlickerIndex;
- UCHAR VB_ExtTVEdgeIndex;
- UCHAR VB_ExtTVYFilterIndex;
- UCHAR REFindex;
-} SiS310_ExtStruct;
-SiS310_ExtStruct  SiS310_EModeIDTable[]=
-{
- {0x6a,0x2212,0x0407,0x3a81,0x0102,0x08,0x07,0x00,0x00,0x07,0x00},
- {0x2e,0x0a1b,0x0306,0x3a57,0x0101,0x08,0x06,0x00,0x00,0x05,0x08},
- {0x2f,0x0a1b,0x0305,0x3a50,0x0100,0x08,0x05,0x00,0x00,0x05,0x10},
- {0x30,0x2a1b,0x0407,0x3a81,0x0103,0x08,0x07,0x00,0x00,0x07,0x00},
- {0x31,0x0a1b,0x030d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},
- {0x32,0x0a1b,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},
- {0x33,0x0a1d,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},
- {0x34,0x2a1d,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},
- {0x35,0x0a1f,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},
- {0x36,0x2a1f,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},
- {0x37,0x0212,0x0508,0x3aab,0x0104,0x08,0x08,0x00,0x00,0x00,0x13},
- {0x38,0x0a1b,0x0508,0x3aab,0x0105,0x08,0x08,0x00,0x00,0x00,0x13},
- {0x3a,0x0e3b,0x0609,0x3adc,0x0107,0x08,0x09,0x00,0x00,0x00,0x1a},
- {0x3c,0x063b,0x070a,0x3af2,0x0130,0x08,0x0a,0x00,0x00,0x00,0x1e},
- {0x3d,0x067d,0x070a,0x3af2,0x0131,0x08,0x0a,0x00,0x00,0x00,0x1e},
- {0x40,0x9a1c,0x0000,0x3a34,0x010d,0x08,0x00,0x00,0x00,0x04,0x25},
- {0x41,0x9a1d,0x0000,0x3a34,0x010e,0x08,0x00,0x00,0x00,0x04,0x25},
- {0x43,0x0a1c,0x0306,0x3a57,0x0110,0x08,0x06,0x00,0x00,0x05,0x08},
- {0x44,0x0a1d,0x0306,0x3a57,0x0111,0x08,0x06,0x00,0x00,0x05,0x08},
- {0x46,0x2a1c,0x0407,0x3a81,0x0113,0x08,0x07,0x00,0x00,0x07,0x00},
- {0x47,0x2a1d,0x0407,0x3a81,0x0114,0x08,0x07,0x00,0x00,0x07,0x00},
- {0x49,0x0a3c,0x0508,0x3aab,0x0116,0x08,0x08,0x00,0x00,0x00,0x13},
- {0x4a,0x0a3d,0x0508,0x3aab,0x0117,0x08,0x08,0x00,0x00,0x00,0x13},
- {0x4c,0x0e7c,0x0609,0x3adc,0x0119,0x08,0x09,0x00,0x00,0x00,0x1a},
- {0x4d,0x0e7d,0x0609,0x3adc,0x011a,0x08,0x09,0x00,0x00,0x00,0x1a},
- {0x50,0x9a1b,0x0001,0x3a3b,0x0132,0x08,0x01,0x00,0x00,0x04,0x26},
- {0x51,0xba1b,0x0103,0x3a42,0x0133,0x08,0x03,0x00,0x00,0x07,0x27},
- {0x52,0x9a1b,0x0204,0x3a49,0x0134,0x08,0x04,0x00,0x00,0x00,0x28},
- {0x56,0x9a1d,0x0001,0x3a3b,0x0135,0x08,0x01,0x00,0x00,0x04,0x26},
- {0x57,0xba1d,0x0103,0x3a42,0x0136,0x08,0x03,0x00,0x00,0x07,0x27},
- {0x58,0x9a1d,0x0204,0x3a49,0x0137,0x08,0x04,0x00,0x00,0x00,0x28},
- {0x59,0x9a1b,0x0000,0x3a34,0x0138,0x08,0x00,0x00,0x00,0x04,0x25},
- {0x5d,0x0a1d,0x0305,0x3a50,0x0139,0x08,0x05,0x00,0x00,0x07,0x10},
- {0x62,0x0a3f,0x0306,0x3a57,0x013a,0x08,0x06,0x00,0x00,0x05,0x08},
- {0x63,0x2a3f,0x0407,0x3a81,0x013b,0x08,0x07,0x00,0x00,0x07,0x00},
- {0x64,0x0a7f,0x0508,0x3aab,0x013c,0x08,0x08,0x00,0x00,0x00,0x13},
- {0x65,0x0eff,0x0609,0x3adc,0x013d,0x08,0x09,0x00,0x00,0x00,0x1a},
- {0x66,0x06ff,0x070a,0x3af2,0x013e,0x08,0x0a,0x00,0x00,0x00,0x1e},
- {0x68,0x067b,0x080b,0x3b17,0x013f,0x08,0x0b,0x00,0x00,0x00,0x29},
- {0x69,0x06fd,0x080b,0x3b17,0x0140,0x08,0x0b,0x00,0x00,0x00,0x29},
- {0x6b,0x07ff,0x080b,0x3b17,0x0141,0x10,0x0b,0x00,0x00,0x00,0x29},
- {0x6c,0x067b,0x090c,0x3b37,0x0000,0x08,0x0c,0x00,0x00,0x00,0x2f},
- {0x6d,0x06fd,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f},
- {0x6e,0x07ff,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f},
- {0x70,0x2a1b,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},
- {0x71,0x0a1b,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},
- {0x74,0x0a1d,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},
- {0x75,0x0a3d,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},
- {0x76,0x2a1f,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},
- {0x77,0x0a1f,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},
- {0x78,0x0a3f,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},
- {0x79,0x0a3b,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},
- {0x7a,0x2a1d,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},
- {0x7b,0x0e3b,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},
- {0x7c,0x0e7d,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},
- {0x7d,0x0eff,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},
- {0xff,0x0000,0x0000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00}
-};
-
-typedef struct _SiS310_Ext2Struct
-{
- USHORT Ext_InfoFlag;
- UCHAR Ext_CRT1CRTC;
- UCHAR Ext_CRTVCLK;
- UCHAR Ext_CRT2CRTC;
- UCHAR  ModeID;
- USHORT XRes;
- USHORT YRes;
- USHORT ROM_OFFSET;
-} SiS310_Ext2Struct;
-SiS310_Ext2Struct SiS310_RefIndex[]=
-{
- {0x005f,0x0d,0x03,0x05,0x6a, 800, 600,0x3a81}, /* 0x0 */
- {0x0467,0x0e,0x04,0x05,0x6a, 800, 600,0x3a86}, /* 0x1 */
- {0x0067,0x0f,0x08,0x48,0x6a, 800, 600,0x3a8b}, /* 0x2 */
- {0x0067,0x10,0x07,0x8b,0x6a, 800, 600,0x3a90}, /* 0x3 */
- {0x0147,0x11,0x0a,0x00,0x6a, 800, 600,0x3a95}, /* 0x4 */
- {0x4147,0x12,0x0d,0x00,0x6a, 800, 600,0x3a9a}, /* 0x5 */
- {0x4047,0x13,0x13,0x00,0x6a, 800, 600,0x3a9f}, /* 0x6 */
- {0x4047,0x14,0x1c,0x00,0x6a, 800, 600,0x3aa4}, /* 0x7 */
- {0xc05f,0x05,0x00,0x04,0x2e, 640, 480,0x3a57}, /* 0x8 */
- {0xc067,0x06,0x02,0x04,0x2e, 640, 480,0x3a5c}, /* 0x9 */
- {0xc067,0x07,0x02,0x47,0x2e, 640, 480,0x3a61}, /* 0xa */
- {0xc067,0x08,0x03,0x8a,0x2e, 640, 480,0x3a66}, /* 0xb */
- {0x4047,0x09,0x05,0x00,0x2e, 640, 480,0x3a6b}, /* 0xc */
- {0x4047,0x0a,0x09,0x00,0x2e, 640, 480,0x3a70}, /* 0xd */
- {0x4047,0x0b,0x0e,0x00,0x2e, 640, 480,0x3a75}, /* 0xe */
- {0xc047,0x0c,0x15,0x00,0x2e, 640, 480,0x3a7a}, /* 0xf */
- {0x407f,0x04,0x00,0x00,0x2f, 640, 400,0x3a50}, /* 0x10 */
- {0xc00f,0x3c,0x01,0x06,0x31, 720, 480,0x3b85}, /* 0x11 */
- {0x000f,0x3d,0x03,0x06,0x32, 720, 576,0x3b8c}, /* 0x12 */
- {0x0187,0x15,0x06,0x00,0x37,1024, 768,0x3aab}, /* 0x13 */
- {0xc877,0x16,0x0b,0x06,0x37,1024, 768,0x3ab0}, /* 0x14 301b TV1024x768*/
- {0xc067,0x17,0x0f,0x49,0x37,1024, 768,0x3ab5}, /* 0x15 */
- {0x0267,0x18,0x11,0x00,0x37,1024, 768,0x3aba}, /* 0x16 */
- {0x0047,0x19,0x16,0x8c,0x37,1024, 768,0x3abf}, /* 0x17 */
- {0x4047,0x1a,0x1b,0x00,0x37,1024, 768,0x3ac4}, /* 0x18 */
- {0x4047,0x1b,0x1f,0x00,0x37,1024, 768,0x3ac9}, /* 0x19 */
- {0x0387,0x1c,0x11,0x00,0x3a,1280,1024,0x3adc}, /* 0x1a */
- {0x0077,0x1d,0x19,0x07,0x3a,1280,1024,0x3ae1}, /* 0x1b */
- {0x0047,0x1e,0x1e,0x00,0x3a,1280,1024,0x3ae6}, /* 0x1c */
- {0x0007,0x1f,0x20,0x00,0x3a,1280,1024,0x3aeb}, /* 0x1d */
- {0x0007,0x20,0x21,0x00,0x3c,1600,1200,0x3af2}, /* 0x1e */
- {0x0007,0x21,0x22,0x00,0x3c,1600,1200,0x3af7}, /* 0x1f */
- {0x0007,0x22,0x23,0x00,0x3c,1600,1200,0x3afc}, /* 0x20 */
- {0x0007,0x23,0x25,0x00,0x3c,1600,1200,0x3b01}, /* 0x21 */
- {0x0007,0x24,0x26,0x00,0x3c,1600,1200,0x3b06}, /* 0x22 */
- {0x0007,0x25,0x2c,0x00,0x3c,1600,1200,0x3b0b}, /* 0x23 */
- {0x0007,0x26,0x34,0x00,0x3c,1600,1200,0x3b10}, /* 0x24 */
- {0x407f,0x00,0x00,0x00,0x40, 320, 200,0x3a34}, /* 0x25 */
- {0xc07f,0x01,0x00,0x04,0x50, 320, 240,0x3a3b}, /* 0x26 */
- {0x007f,0x02,0x04,0x05,0x51, 400, 300,0x3a42}, /* 0x27 */
- {0xc077,0x03,0x0b,0x06,0x52, 512, 384,0x3a49}, /* 0x28 */
- {0x8007,0x27,0x27,0x00,0x68,1920,1440,0x3b17}, /* 0x29 */
- {0x4007,0x28,0x29,0x00,0x68,1920,1440,0x3b1c}, /* 0x2a */
- {0x4007,0x29,0x2e,0x00,0x68,1920,1440,0x3b21}, /* 0x2b */
- {0x4007,0x2a,0x30,0x00,0x68,1920,1440,0x3b26}, /* 0x2c */
- {0x4007,0x2b,0x35,0x00,0x68,1920,1440,0x3b2b}, /* 0x2d */
- {0x4005,0x2c,0x39,0x00,0x68,1920,1440,0x3b30}, /* 0x2e */
- {0x4007,0x2d,0x2b,0x00,0x6c,2048,1536,0x3b37}, /* 0x2f */
- {0x4007,0x2e,0x31,0x00,0x6c,2048,1536,0x3b3c}, /* 0x30 */
- {0x4007,0x2f,0x33,0x00,0x6c,2048,1536,0x3b41}, /* 0x31 */
- {0x4007,0x30,0x37,0x00,0x6c,2048,1536,0x3b46}, /* 0x32 */
- {0x4005,0x31,0x38,0x00,0x6c,2048,1536,0x3b4b}, /* 0x33 */
- {0x0057,0x32,0x40,0x08,0x70, 800, 480,0x3b52}, /* 0x34 */
- {0x0047,0x33,0x07,0x08,0x70, 800, 480,0x3b57}, /* 0x35 */
- {0x0047,0x34,0x0a,0x08,0x70, 800, 480,0x3b5c}, /* 0x36 */
- {0x0057,0x35,0x0b,0x09,0x71,1024, 576,0x3b63}, /* 0x37 */
- {0x0047,0x36,0x11,0x09,0x71,1024, 576,0x3b68}, /* 0x38 */
- {0x0047,0x37,0x16,0x09,0x71,1024, 576,0x3b6d}, /* 0x39 */
- {0x0057,0x38,0x19,0x0a,0x75,1280, 720,0x3b74}, /* 0x3a */
- {0x0047,0x39,0x1e,0x0a,0x75,1280, 720,0x3b79}, /* 0x3b */
- {0x0047,0x3a,0x20,0x0a,0x75,1280, 720,0x3b7e}, /* 0x3c */
- {0x0027,0x3b,0x19,0x08,0x7b,1280, 960,0x3ad0}, /* 0x3d */
- {0x0027,0x3b,0x19,0x08,0x7b,1280, 960,0x3ad5}, /* 0x3e */
- {0xffff,0x00,0x00,0x00,0x00,0000,0000,0x0000}
-};
-
-typedef struct _SiS310_CRT1TableStruct
-{
- UCHAR CR[17];
-} SiS310_CRT1TableStruct;
-SiS310_CRT1TableStruct SiS310_CRT1Table[]=
-{
- {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
-  0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
-  0x00}, /* 0x0 */
- {0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
-  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
-  0x00}, /* 0x1 */
- {0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
-  0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
-  0x01}, /* 0x2 */
- {0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
-  0x01}, /* 0x3 */
- {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-  0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
-  0x00}, /* 0x4 */
- {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
-  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
-  0x00}, /* 0x5 */
- {0x63,0x4f,0x50,0x86,0x56,0x9b,0x06,0x3e,
-  0xe8,0x8b,0xdf,0xe7,0xff,0x10,0x00,0x01,
-  0x00}, /* 0x6 */
- {0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f,
-  0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
-  0x00}, /* 0x7 */
- {0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f,
-  0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
-  0x00}, /* 0x8 */
- {0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f,
-  0xe0,0x83,0xdf,0xdf,0xfc,0x00,0x00,0x05,
-  0x61}, /* 0x9 */
- {0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e,
-  0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
-  0x61}, /* 0xa */
- {0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e,
-  0xe0,0x83,0xdf,0xdf,0x0e,0x10,0x00,0x05,
-  0x61}, /* 0xb */
- {0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f,
-  0xe6,0x8a,0xe5,0xe5,0xfc,0x00,0x00,0x01,
-  0x00}, /* 0xc */
- {0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
-  0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
-  0x01}, /* 0xd */
- {0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-  0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
-  0x01}, /* 0xe */
- {0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0,
-  0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
-  0x01}, /* 0xf */
- {0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0,
-  0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
-  0x01}, /* 0x10 */
- {0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0,
-  0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
-  0x01}, /* 0x11 */
- {0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0,
-  0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06,
-  0x61}, /* 0x12 */
- {0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0,
-  0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06,
-  0x61}, /* 0x13 */
- {0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0,
-  0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06,
-  0x61}, /* 0x14 */
- {0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
-  0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
-  0x00}, /* 0x15 */
- {0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-  0x01}, /* 0x16 */
- {0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5,
-  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-  0x01}, /* 0x17 */
- {0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5,
-  0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
-  0x01}, /* 0x18 */
- {0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5,
-  0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
-  0x01}, /* 0x19 */
- {0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5,
-  0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02,
-  0x62}, /* 0x1a */
- {0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5,
-  0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02,
-  0x62}, /* 0x1b */
- {0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba,
-  0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
-  0x00}, /* 0x1c */
- {0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
-  0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
-  0x01}, /* 0x1d */
- {0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,
-  0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
-  0x01}, /* 0x1e */
- {0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
-  0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
-  0x01}, /* 0x1f */
- {0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}, /* 0x20 */
- {0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}, /* 0x21 */
- {0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}, /* 0x22 */
- {0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}, /* 0x23 */
- {0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}, /* 0x24 */
- {0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}, /* 0x25 */
- {0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}, /* 0x26 */
- {0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-  0x00}, /* 0x27 */
- {0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05,
-  0x63}, /* 0x28 */
- {0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05,
-  0x63}, /* 0x29 */
- {0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-  0x00}, /* 0x2a */
- {0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-  0x00}, /* 0x2b */
- {0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-  0x00}, /* 0x2c */
- {0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba,
-  0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05,
-  0x44}, /* 0x2d */
- {0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba,
-  0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05,
-  0x44}, /* 0x2e */
- {0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba,
-  0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05,
-  0x44}, /* 0x2f */
- {0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba,
-  0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05,
-  0x44}, /* 0x30 */
- {0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
-  0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
-  0x00}, /* 0x31 */
- {0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,
-  0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
-  0x01}, /* 0x32 */
- {0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
-  0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
-  0x01}, /* 0x33 */
- {0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba,
-  0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
-  0x01}, /* 0x34 */
- {0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1,
-  0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
-  0x01}, /* 0x35 */
- {0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
-  0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
-  0x01}, /* 0x36 */
- {0xa7,0x7f,0x7f,0x88,0x89,0x15,0x26,0xf1,
-  0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
-  0x01}, /* 0x37 */
- {0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
-  0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
-  0x01}, /* 0x38 */
- {0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4,
-  0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
-  0x01}, /* 0x39 */
- {0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
-  0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
-  0x01}, /* 0x3a */
- {0xdc,0x9f,0x9f,0x00,0xab,0x19,0xe6,0xef,
-  0xc0,0xc3,0xbf,0xbf,0xe7,0x10,0x00,0x07,
-  0x01}, /* 0x3b */
- {0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
-  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
-  0x00}, /* 0x3c */
- {0x7b,0x59,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
-  0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05,
-  0x01} /* 0x3d */
-};
-
-typedef struct _SiS310_MCLKDataStruct
-{
- UCHAR SR28,SR29,SR2A;
- USHORT CLOCK;
-} SiS310_MCLKDataStruct;
-SiS310_MCLKDataStruct SiS310_MCLKData[]=
-{
- { 0x5c,0x23,0x01,166},
- { 0x5c,0x23,0x01,166},
- { 0x5c,0x23,0x01,166},
- { 0x5c,0x23,0x01,166}
-};
-
-typedef struct _SiS310_ECLKDataStruct
-{
- UCHAR SR2E,SR2F,SR30;
- USHORT CLOCK;
-} SiS310_ECLKDataStruct;
-SiS310_ECLKDataStruct SiS310_ECLKData[]=
-{
- { 0x5c,0x23,0x01,166},
- { 0x5c,0x23,0x01,166},
- { 0x5c,0x23,0x01,166},
- { 0x5c,0x23,0x01,166}
-};
-
-typedef struct _SiS310_VCLKDataStruct
-{
- UCHAR SR2B,SR2C;
- USHORT CLOCK;
-} SiS310_VCLKDataStruct;
-SiS310_VCLKDataStruct SiS310_VCLKData[]=
-{
- { 0x1b,0xe1, 25}, /* 0x0 */
- { 0x4e,0xe4, 28}, /* 0x1 */
- { 0x57,0xe4, 31}, /* 0x2 */
- { 0xc3,0xc8, 36}, /* 0x3 */
- { 0x42,0xe2, 40}, /* 0x4 */
- { 0xfe,0xcd, 43}, /* 0x5 */
- { 0x5d,0xc4, 44}, /* 0x6 */
- { 0x52,0xe2, 49}, /* 0x7 */
- { 0x53,0xe2, 50}, /* 0x8 */
- { 0x74,0x67, 52}, /* 0x9 */
- { 0x6d,0x66, 56}, /* 0xa */
- { 0x6c,0xc3, 65}, /* 0xb */
- { 0x46,0x44, 67}, /* 0xc */
- { 0xb1,0x46, 68}, /* 0xd */
- { 0xd3,0x4a, 72}, /* 0xe */
- { 0x29,0x61, 75}, /* 0xf */
- { 0x6e,0x46, 76}, /* 0x10 */
- { 0x2b,0x61, 78}, /* 0x11 */
- { 0x31,0x42, 79}, /* 0x12 */
- { 0xab,0x44, 83}, /* 0x13 */
- { 0x46,0x25, 84}, /* 0x14 */
- { 0x78,0x29, 86}, /* 0x15 */
- { 0x62,0x44, 94}, /* 0x16 */
- { 0x2b,0x41,104}, /* 0x17 */
- { 0x3a,0x23,105}, /* 0x18 */
- { 0x70,0x44,108}, /* 0x19 */
- { 0x3c,0x23,109}, /* 0x1a */
- { 0x5e,0x43,113}, /* 0x1b */
- { 0xbc,0x44,116}, /* 0x1c */
- { 0xe0,0x46,132}, /* 0x1d */
- { 0x54,0x42,135}, /* 0x1e */
- { 0xea,0x2a,139}, /* 0x1f */
- { 0x41,0x22,157}, /* 0x20 */
- { 0x70,0x24,162}, /* 0x21 */
- { 0x30,0x21,175}, /* 0x22 */
- { 0x4e,0x22,189}, /* 0x23 */
- { 0xde,0x26,194}, /* 0x24 */
- { 0x62,0x06,202}, /* 0x25 */
- { 0x3f,0x03,229}, /* 0x26 */
- { 0xb8,0x06,234}, /* 0x27 */
- { 0x34,0x02,253}, /* 0x28 */
- { 0x58,0x04,255}, /* 0x29 */
- { 0x24,0x01,265}, /* 0x2a */
- { 0x9b,0x02,267}, /* 0x2b */
- { 0x70,0x05,270}, /* 0x2c */
- { 0x25,0x01,272}, /* 0x2d */
- { 0x9c,0x02,277}, /* 0x2e */
- { 0x27,0x01,286}, /* 0x2f */
- { 0x3c,0x02,291}, /* 0x30 */
- { 0xef,0x0a,292}, /* 0x31 */
- { 0xf6,0x0a,310}, /* 0x32 */
- { 0x95,0x01,315}, /* 0x33 */
- { 0xf0,0x09,324}, /* 0x34 */
- { 0xfe,0x0a,331}, /* 0x35 */
- { 0xf3,0x09,332}, /* 0x36 */
- { 0xea,0x08,340}, /* 0x37 */
- { 0xe8,0x07,376}, /* 0x38 */
- { 0xde,0x06,389}, /* 0x39 */
- { 0x52,0x2a, 54}, /* 0x3a */
- { 0x52,0x6a, 27}, /* 0x3b */
- { 0x62,0x24, 70}, /* 0x3c */
- { 0x62,0x64, 70}, /* 0x3d */
- { 0xa8,0x4c, 30}, /* 0x3e */
- { 0x20,0x26, 33}, /* 0x3f */
- { 0x31,0xc2, 39} /* 0x40 */
-};
-
-typedef struct _SiS310_VBVCLKDataStruct
-{
- UCHAR Part4_A,Part4_B;
- USHORT CLOCK;
-} SiS310_VBVCLKDataStruct;
-SiS310_VBVCLKDataStruct SiS310_VBVCLKData[]=
-{
- { 0x1b,0xe1, 25}, /* 0x0 */
- { 0x4e,0xe4, 28}, /* 0x1 */
- { 0x57,0xe4, 31}, /* 0x2 */
- { 0xc3,0xc8, 36}, /* 0x3 */
- { 0x42,0x47, 40}, /* 0x4 */
- { 0xfe,0xcd, 43}, /* 0x5 */
- { 0x5d,0xc4, 44}, /* 0x6 */
- { 0x52,0x47, 49}, /* 0x7 */
- { 0x53,0x47, 50}, /* 0x8 */
- { 0x74,0x67, 52}, /* 0x9 */
- { 0x6d,0x66, 56}, /* 0xa */
- { 0x5a,0x64, 65}, /* 0xb */
- { 0x46,0x44, 67}, /* 0xc */
- { 0xb1,0x46, 68}, /* 0xd */
- { 0xd3,0x4a, 72}, /* 0xe */
- { 0x29,0x61, 75}, /* 0xf */
- { 0x6d,0x46, 75}, /* 0x10 */
- { 0x41,0x43, 78}, /* 0x11 */
- { 0x31,0x42, 79}, /* 0x12 */
- { 0xab,0x44, 83}, /* 0x13 */
- { 0x46,0x25, 84}, /* 0x14 */
- { 0x78,0x29, 86}, /* 0x15 */
- { 0x62,0x44, 94}, /* 0x16 */
- { 0x2b,0x22,104}, /* 0x17 */
- { 0x49,0x24,105}, /* 0x18 */
- { 0xf8,0x2f,108}, /* 0x19 */
- { 0x3c,0x23,109}, /* 0x1a */
- { 0x5e,0x43,113}, /* 0x1b */
- { 0xbc,0x44,116}, /* 0x1c */
- { 0xe0,0x46,132}, /* 0x1d */
- { 0xd4,0x28,135}, /* 0x1e */
- { 0xea,0x2a,139}, /* 0x1f */
- { 0x41,0x22,157}, /* 0x20 */
- { 0x70,0x24,162}, /* 0x21 */
- { 0x30,0x21,175}, /* 0x22 */
- { 0x4e,0x22,189}, /* 0x23 */
- { 0xde,0x26,194}, /* 0x24 */
- { 0x70,0x07,202}, /* 0x25 */
- { 0x3f,0x03,229}, /* 0x26 */
- { 0xb8,0x06,234}, /* 0x27 */
- { 0x34,0x02,253}, /* 0x28 */
- { 0x58,0x04,255}, /* 0x29 */
- { 0x24,0x01,265}, /* 0x2a */
- { 0x9b,0x02,267}, /* 0x2b */
- { 0x70,0x05,270}, /* 0x2c */
- { 0x25,0x01,272}, /* 0x2d */
- { 0x9c,0x02,277}, /* 0x2e */
- { 0x27,0x01,286}, /* 0x2f */
- { 0x3c,0x02,291}, /* 0x30 */
- { 0xef,0x0a,292}, /* 0x31 */
- { 0xf6,0x0a,310}, /* 0x32 */
- { 0x95,0x01,315}, /* 0x33 */
- { 0xf0,0x09,324}, /* 0x34 */
- { 0xfe,0x0a,331}, /* 0x35 */
- { 0xf3,0x09,332}, /* 0x36 */
- { 0xea,0x08,340}, /* 0x37 */
- { 0xe8,0x07,376}, /* 0x38 */
- { 0xde,0x06,389}, /* 0x39 */
- { 0x52,0x2a, 54}, /* 0x3a */
- { 0x52,0x6a, 27}, /* 0x3b */
- { 0x62,0x24, 70}, /* 0x3c */
- { 0x62,0x64, 70}, /* 0x3d */
- { 0xa8,0x4c, 30}, /* 0x3e */
- { 0x20,0x26, 33}, /* 0x3f */
- { 0x31,0xc2, 39} /* 0x40 */
-};
-
-UCHAR SiS310_ScreenOffset[]={ 0x14,0x19,0x20,0x28,0x32,0x40,0x50,0x64,0x78,0x80,0x2d,0x35 };
-
-typedef struct _SiS310_StResInfoStruct
-{
- USHORT HTotal;
- USHORT VTotal;
-} SiS310_StResInfoStruct;
-SiS310_StResInfoStruct SiS310_StResInfo[]=
-{
- { 640,400},
- { 640,350},
- { 720,400},
- { 720,350},
- { 640,480}
-};
-
-typedef struct _SiS310_ModeResInfoStruct
-{
- USHORT HTotal;
- USHORT VTotal;
- UCHAR  XChar;
- UCHAR  YChar;
-} SiS310_ModeResInfoStruct;
-SiS310_ModeResInfoStruct SiS310_ModeResInfo[]=
-{
- {  320, 200, 8, 8},
- {  320, 240, 8, 8},
- {  320, 400, 8, 8},
- {  400, 300, 8, 8},
- {  512, 384, 8, 8},
- {  640, 400, 8,16},
- {  640, 480, 8,16},
- {  800, 600, 8,16},
- { 1024, 768, 8,16},
- { 1280,1024, 8,16},
- { 1600,1200, 8,16},
- { 1920,1440, 8,16},
- { 2048,1536, 8,16},
- {  720, 480, 8,16},
- {  720, 576, 8,16},
- { 1280, 960, 8,16},
- {  800, 480, 8,16},
- { 1024, 576, 8,16},
- { 1280, 720, 8,16}
-};
-
-UCHAR SiS310_OutputSelect = 0;
-UCHAR SiS310_SoftSetting = 30;
-UCHAR SiS310_SR07=0x18;
-UCHAR SiS310_SR15[8][4]={
-{0x0,0x4,0x60,0x60},
-{0xf,0xf,0xf,0xf},
-{0xba,0xba,0xba,0xba},
-{0xa9,0xa9,0xac,0xac},
-{0xa0,0xa0,0xa0,0xa8},
-{0x0,0x0,0x2,0x2},
-{0x30,0x30,0x40,0x40},
-{0x0,0xa5,0xfb,0xf6}
-};
-UCHAR SiS310_CR40[5][4]={
-{0x77,0x77,0x33,0x33},
-{0x77,0x77,0x33,0x33},
-{0x0,0x0,0x0,0x0},
-{0x5b,0x5b,0x3,0x3},
-{0x0,0x0,0xf0,0xf8}
-};
-UCHAR SiS310_CR49[]={0xaa,0x88};
-UCHAR SiS310_SR1F=0x0;
-UCHAR SiS310_SR21=0xa5;
-UCHAR SiS310_SR22=0xfb;
-UCHAR SiS310_SR23=0xf6;
-UCHAR SiS310_SR24=0xd;
-UCHAR SiS310_SR25[]={0x33,0x3};
-UCHAR SiS310_SR31=0x0;
-UCHAR SiS310_SR32=0x11;
-UCHAR SiS310_SR33=0x0;
-UCHAR SiS310_CRT2Data_1_2 = 0x0;
-UCHAR SiS310_CRT2Data_4_D = 0x0;
-UCHAR SiS310_CRT2Data_4_E = 0x0;
-UCHAR SiS310_CRT2Data_4_10 = 0x80;
-USHORT SiS310_RGBSenseData = 0xd1;
-USHORT SiS310_VideoSenseData = 0xb9;
-USHORT SiS310_YCSenseData = 0xb3;
-USHORT SiS310_RGBSenseData2 = 0x0190;     /*301b*/
-USHORT SiS310_VideoSenseData2 = 0x0174;
-USHORT SiS310_YCSenseData2 = 0x016b;
-UCHAR SiS310_NTSCPhase[] = {0x21,0xed,0x8a,0x8};
-
-UCHAR SiS310_PALPhase[] = {0x2a,0x5,0xd3,0x0};
-
-typedef struct _SiS310_LCDDataStruct
-{
- USHORT RVBHCMAX;
- USHORT RVBHCFACT;
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT LCDHT;
- USHORT LCDVT;
-} SiS310_LCDDataStruct;
-SiS310_LCDDataStruct  SiS310_StLCD1024x768Data[]=
-{
- {   62,  25, 800, 546,1344, 806},
- {   32,  15, 930, 546,1344, 806},
- {   32,  15, 930, 546,1344, 806},
- {  104,  45, 945, 496,1344, 806},
- {   62,  25, 800, 546,1344, 806},
- {   31,  18,1008, 624,1344, 806},
- {    1,   1,1344, 806,1344, 806}
-};
-
-SiS310_LCDDataStruct  SiS310_ExtLCD1024x768Data[]=
-{
- {   12,   5, 896, 512,1344, 806},
- {   12,   5, 896, 510,1344, 806},
- {   32,  15,1008, 505,1344, 806},
- {   32,  15,1008, 514,1344, 806},
- {   12,   5, 896, 500,1344, 806},
- {   42,  25,1024, 625,1344, 806},
- {    1,   1,1344, 806,1344, 806},
- {   12,   5, 896, 500,1344, 806},
- {   42,  25,1024, 625,1344, 806},
- {    1,   1,1344, 806,1344, 806},
- {   12,   5, 896, 500,1344, 806},
- {   42,  25,1024, 625,1344, 806},
- {    1,   1,1344, 806,1344, 806}
-};
-
-SiS310_LCDDataStruct  SiS310_St2LCD1024x768Data[]=
-{
- {   62,  25, 800, 546,1344, 806},
- {   32,  15, 930, 546,1344, 806},
- {   32,  15, 930, 546,1344, 806},
- {  104,  45, 945, 496,1344, 806},
- {   62,  25, 800, 546,1344, 806},
- {   31,  18,1008, 624,1344, 806},
- {    1,   1,1344, 806,1344, 806}
-};
-
-SiS310_LCDDataStruct  SiS310_StLCD1280x1024Data[]=
-{
- {   22,   5, 800, 510,1650,1088},
- {   22,   5, 800, 510,1650,1088},
- {  176,  45, 900, 510,1650,1088},
- {  176,  45, 900, 510,1650,1088},
- {   22,   5, 800, 510,1650,1088},
- {   13,   5,1024, 675,1560,1152},
- {   16,   9,1266, 804,1688,1072},
- {    1,   1,1688,1066,1688,1066}
-};
-
-SiS310_LCDDataStruct  SiS310_ExtLCD1280x1024Data[]=
-{
- {  211,  60,1024, 501,1688,1066},
- {  211,  60,1024, 508,1688,1066},
- {  211,  60,1024, 501,1688,1066},
- {  211,  60,1024, 508,1688,1066},
- {  211,  60,1024, 500,1688,1066},
- {  211,  75,1024, 625,1688,1066},
- {  211, 120,1280, 798,1688,1066},
- {    1,   1,1688,1066,1688,1066}
-};
-
-SiS310_LCDDataStruct  SiS310_St2LCD1280x1024Data[]=
-{
- {   22,   5, 800, 510,1650,1088},
- {   22,   5, 800, 510,1650,1088},
- {  176,  45, 900, 510,1650,1088},
- {  176,  45, 900, 510,1650,1088},
- {   22,   5, 800, 510,1650,1088},
- {   13,   5,1024, 675,1560,1152},
- {   16,   9,1266, 804,1688,1072},
- {    1,   1,1688,1066,1688,1066}
-};
-
-SiS310_LCDDataStruct  SiS310_NoScaleData[]=
-{
- {    1,   1, 800, 449, 800, 449},
- {    1,   1, 800, 449, 800, 449},
- {    1,   1, 900, 449, 900, 449},
- {    1,   1, 900, 449, 900, 449},
- {    1,   1, 800, 525, 800, 525},
- {    1,   1,1056, 628,1056, 628},
- {    1,   1,1344, 806,1344, 806},
- {    1,   1,1688,1066,1688,1066}
-};
-
-SiS310_LCDDataStruct  SiS310_LCD1280x960Data[]=
-{
- {    9,   2, 800, 500,1800,1000},
- {    9,   2, 800, 500,1800,1000},
- {    4,   1, 900, 500,1800,1000},
- {    4,   1, 900, 500,1800,1000},
- {    9,   2, 800, 500,1800,1000},
- {   30,  11,1056, 625,1800,1000},
- {    5,   3,1350, 800,1800,1000},
- {    1,   1,1576,1050,1576,1050},
- {    1,   1,1800,1000,1800,1000}
-};
-
-typedef struct _SiS310_TVDataStruct
-{
- USHORT RVBHCMAX;
- USHORT RVBHCFACT;
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT TVHDE;
- USHORT TVVDE;
- USHORT RVBHRS;
- UCHAR FlickerMode;
- USHORT HALFRVBHRS;
- UCHAR RY1COE;
- UCHAR RY2COE;
- UCHAR RY3COE;
- UCHAR RY4COE;
-} SiS310_TVDataStruct;
-SiS310_TVDataStruct  SiS310_StPALData[]=
-{
- {    1,   1, 864, 525,1270, 400, 100,   0, 760,0xf4,0xff,0x1c,0x22},
- {    1,   1, 864, 525,1270, 350, 100,   0, 760,0xf4,0xff,0x1c,0x22},
- {    1,   1, 864, 525,1270, 400,   0,   0, 720,0xf1,0x04,0x1f,0x18},
- {    1,   1, 864, 525,1270, 350,   0,   0, 720,0xf4,0x0b,0x1c,0x0a},
- {    1,   1, 864, 525,1270, 480,  50,   0, 760,0xf4,0xff,0x1c,0x22},
- {    1,   1, 864, 525,1270, 600,  50,   0,   0,0xf4,0xff,0x1c,0x22}
-};
-
-SiS310_TVDataStruct  SiS310_ExtPALData[]=
-{
- {   27,  10, 848, 448,1270, 530,  50,   0,  50,0xf4,0xff,0x1c,0x22},
- {  108,  35, 848, 398,1270, 530,  50,   0,  50,0xf4,0xff,0x1c,0x22},
- {   12,   5, 954, 448,1270, 530,  50,   0,  50,0xf1,0x04,0x1f,0x18},
- {    9,   4, 960, 463,1644, 438,  50,   0,  50,0xf4,0x0b,0x1c,0x0a},
- {    9,   4, 848, 528,1270, 530,   0,   0,  50,0xf5,0xfb,0x1b,0x2a},
- {   36,  25,1060, 648,1316, 530, 438,   0, 438,0xeb,0x05,0x25,0x16},
- {    3,   2,1080, 619,1270, 540, 438,   0, 438,0xf3,0x00,0x1d,0x20},
- {    1,   1,1170, 821,1270, 520, 686,   0, 686,0xF3,0x00,0x1D,0x20}     /*301b*/
-};
-
-SiS310_TVDataStruct  SiS310_StNTSCData[]=
-{
- {    1,   1, 858, 525,1270, 400,  50,   0, 760,0xf1,0x04,0x1f,0x18},
- {    1,   1, 858, 525,1270, 350,  50,   0, 640,0xf1,0x04,0x1f,0x18},
- {    1,   1, 858, 525,1270, 400,   0,   0, 720,0xf1,0x04,0x1f,0x18},
- {    1,   1, 858, 525,1270, 350,   0,   0, 720,0xf4,0x0b,0x1c,0x0a},
- {    1,   1, 858, 525,1270, 480,   0,   0, 760,0xf1,0x04,0x1f,0x18}
-};
-
-SiS310_TVDataStruct  SiS310_ExtNTSCData[]=
-{
- {  143,  65, 858, 443,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},
- {   88,  35, 858, 393,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},
- {  143,  70, 924, 443,1270, 440,  92,   0,  92,0xf1,0x04,0x1f,0x18},
- {  143,  70, 924, 393,1270, 440,  92,   0,  92,0xf4,0x0b,0x1c,0x0a},
- {  143,  76, 836, 523,1270, 440, 224,   0,   0,0xf1,0x05,0x1f,0x16},
- {  143, 120,1056, 643,1288, 440,   0, 128,   0,0xf4,0x10,0x1c,0x00},
- {    2,   1, 858, 503,1270, 480,   0, 128,   0,0xee,0x0c,0x22,0x08},
- {   65,  64,1056, 791,1270, 480, 638,   0,   0,0xEE,0x0C,0x22,0x08} /*301b*/     
-};
-
-SiS310_TVDataStruct  SiS310_St1HiTVData[]=
-{
-0x00};
-
-SiS310_TVDataStruct  SiS310_St2HiTVData[]=
-{
-0x00};
-
-SiS310_TVDataStruct  SiS310_ExtHiTVData[]=
-{
-0x00};
-
-UCHAR SiS310_NTSCTiming[] = {
-  0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c,
-  0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a,
-  0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b,
-  0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17,
-  0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02,
-  0x03,0x0a,0x65,0x9d,0x08,0x92,0x8f,0x40,
-  0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x50,
-  0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00};
-
-UCHAR SiS310_PALTiming[] = {
-  0x19,0x52,0x35,0x6e,0x04,0x38,0x3d,0x70,
-  0x94,0x49,0x01,0x12,0x06,0x3e,0x35,0x6d,
-  0x06,0x14,0x3e,0x35,0x6d,0x00,0x45,0x2b,
-  0x70,0x50,0x00,0x9b,0x00,0xd9,0x5d,0x17,
-  0x7d,0x05,0x45,0x00,0x00,0xe8,0x00,0x02,
-  0x0d,0x00,0x68,0xb0,0x0b,0x92,0x8f,0x40,
-  0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x63,
-  0x00,0x40,0x3e,0x00,0xe1,0x02,0x28,0x00};
-
-UCHAR SiS310_HiTVExtTiming[] = {0x00};
-
-UCHAR SiS310_HiTVSt1Timing[] = {0x00};
-
-UCHAR SiS310_HiTVSt2Timing[] = {0x00};
-
-UCHAR SiS310_HiTVTextTiming[] = {0x00};
-
-UCHAR SiS310_HiTVGroup3Data[] = {0x00};
-
-UCHAR SiS310_HiTVGroup3Simu[] = {0x00};
-
-UCHAR SiS310_HiTVGroup3Text[] = {0x00};
-
-typedef struct _SiS310_PanelDelayTblStruct
-{
- UCHAR timer[2];
-} SiS310_PanelDelayTblStruct;
-SiS310_PanelDelayTblStruct SiS310_PanelDelayTbl[]=
-{{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00}};
-
-typedef struct _SiS310_LVDSDataStruct
-{
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT LCDHT;
- USHORT LCDVT;
-} SiS310_LVDSDataStruct;
-SiS310_LVDSDataStruct  SiS310_LVDS800x600Data_1[]=
-{
- {848, 433,1060, 629},
- {848, 389,1060, 629},
- {848, 433,1060, 629},
- {848, 389,1060, 629},
- {848, 518,1060, 629},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {800, 449,1000, 644},
- {800, 525,1000, 635}
-};
-
-SiS310_LVDSDataStruct  SiS310_LVDS800x600Data_2[]=
-{
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {800, 449,1000, 644},
- {800, 525,1000, 635}
-};
-
-SiS310_LVDSDataStruct  SiS310_LVDS1024x768Data_1[]=
-{
- {840, 438,1344, 806},
- {840, 409,1344, 806},
- {840, 438,1344, 806},
- {840, 409,1344, 806},
- {840, 518,1344, 806},
- {1050, 638,1344, 806},
- {1344, 806,1344, 806},
- {800, 449,1280, 801},
- {800, 525,1280, 813}
-};
-
-SiS310_LVDSDataStruct  SiS310_LVDS1024x768Data_2[]=
-{
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {800, 449,1280, 801},
- {800, 525,1280, 813}
-};
-
-SiS310_LVDSDataStruct  SiS310_LVDS1280x1024Data_1[]=
-{
- {840, 438,1344, 806},
- {840, 409,1344, 806},
- {840, 438,1344, 806},
- {840, 409,1344, 806},
- {840, 518,1344, 806},
- {1050, 638,1344, 806},
- {1344, 806,1344, 806},
- {800, 449,1280, 801},
- {800, 525,1280, 813}
-};
-
-SiS310_LVDSDataStruct  SiS310_LVDS1280x1024Data_2[]=
-{
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {800, 449,1280, 801},
- {800, 525,1280, 813}
-};
-
-SiS310_LVDSDataStruct  SiS310_LVDS640x480Data_1[]=
-{
- {800, 449, 800, 449},
- {800, 449, 800, 449},
- {800, 449, 800, 449},
- {800, 449, 800, 449},
- {800, 525, 800, 525},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628}
-};
-
-SiS310_LVDSDataStruct  SiS310_CHTVUNTSCData[]=
-{
- {840, 600, 840, 600},
- {840, 600, 840, 600},
- {840, 600, 840, 600},
- {840, 600, 840, 600},
- {784, 600, 784, 600},
- {1064, 750,1064, 750}
-};
-
-SiS310_LVDSDataStruct  SiS310_CHTVONTSCData[]=
-{
- {840, 525, 840, 525},
- {840, 525, 840, 525},
- {840, 525, 840, 525},
- {840, 525, 840, 525},
- {784, 525, 784, 525},
- {1040, 700,1040, 700}
-};
-
-SiS310_LVDSDataStruct  SiS310_CHTVUPALData[]=
-{
- {1008, 625,1008, 625},
- {1008, 625,1008, 625},
- {1008, 625,1008, 625},
- {1008, 625,1008, 625},
- {840, 750, 840, 750},
- {936, 836, 936, 836}
-};
-
-SiS310_LVDSDataStruct  SiS310_CHTVOPALData[]=
-{
- {1008, 625,1008, 625},
- {1008, 625,1008, 625},
- {1008, 625,1008, 625},
- {1008, 625,1008, 625},
- {840, 625, 840, 625},
- {960, 750, 960, 750}
-};
-
-typedef struct _SiS310_LVDSDesStruct
-{
- USHORT LCDHDES;
- USHORT LCDVDES;
-} SiS310_LVDSDesStruct;
-SiS310_LVDSDesStruct  SiS310_PanelType00_1[]=
-{
- {1059, 626},
- {1059, 624},
- {1059, 626},
- {1059, 624},
- {1059, 624},
- { 0, 627},
- { 0, 627},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType01_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType02_1[]=
-{
- {1059, 626},
- {1059, 624},
- {1059, 626},
- {1059, 624},
- {1059, 624},
- { 0, 627},
- { 0, 627},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType03_1[]=
-{
- { 8, 436},
- { 8, 440},
- { 8, 436},
- { 8, 440},
- { 8, 512},
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType04_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType05_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType06_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType07_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType08_1[]=
-{
- {1059, 626},
- {1059, 624},
- {1059, 626},
- {1059, 624},
- {1059, 624},
- { 0, 627},
- { 0, 627},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType09_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0a_1[]=
-{
- {1059, 626},
- {1059, 624},
- {1059, 626},
- {1059, 624},
- {1059, 624},
- { 0, 627},
- { 0, 627},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0b_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0c_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0d_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0e_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0f_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType00_2[]=
-{
- {976, 527},
- {976, 502},
- {976, 527},
- {976, 502},
- {976, 567},
- { 0, 627},
- { 0, 627},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType01_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType02_2[]=
-{
- {976, 527},
- {976, 502},
- {976, 527},
- {976, 502},
- {976, 567},
- { 0, 627},
- { 0, 627},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType03_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- {1152, 622},
- {1152, 597}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType04_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType05_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType06_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType07_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType08_2[]=
-{
- {976, 527},
- {976, 502},
- {976, 527},
- {976, 502},
- {976, 567},
- { 0, 627},
- { 0, 627},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType09_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0a_2[]=
-{
- {976, 527},
- {976, 502},
- {976, 527},
- {976, 502},
- {976, 567},
- { 0, 627},
- { 0, 627},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0b_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0c_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0d_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0e_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0f_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-/*301b*/
-SiS310_LVDSDesStruct SiS310_PanelType1076_1[]=
-{
-0x00,0x00};
-SiS310_LVDSDesStruct SiS310_PanelType1210_1[]=
-{
-0x00,0x00};
-SiS310_LVDSDesStruct SiS310_PanelType1296_1[]=
-{
-0x00,0x00};
-SiS310_LVDSDesStruct SiS310_PanelType1076_2[]=
-{
-0x00,0x00};
-SiS310_LVDSDesStruct SiS310_PanelType1210_2[]=
-{
-0x00,0x00};
-SiS310_LVDSDesStruct SiS310_PanelType1296_2[]=
-{
-0x00,0x00};
-/*end 301b*/
-
-SiS310_LVDSDesStruct  SiS310_CHTVUNTSCDesData[]=
-{
- { 0,   0},
- { 0,   0},
- { 0,   0},
- { 0,   0},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_CHTVONTSCDesData[]=
-{
- { 0,   0},
- { 0,   0},
- { 0,   0},
- { 0,   0},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_CHTVUPALDesData[]=
-{
- {256,   0},
- {256,   0},
- {256,   0},
- {256,   0},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_CHTVOPALDesData[]=
-{
- {256,   0},
- {256,   0},
- {256,   0},
- {256,   0},
- { 0,   0},
- { 0,   0}
-};
-
-typedef struct _SiS310_LVDSCRT1DataStruct
-{
- UCHAR CR[17];
-} SiS310_LVDSCRT1DataStruct;
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1[]=
-{{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
-   0x00 },
- {0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
-   0x00 },
- {0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
-   0x00 },
- {0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
-   0x00 },
- {0x65,0x4f,0x89,0x56,0x83,0x04,0x3e,
-   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
-   0x00 },
- {0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1[]=
-{{0x73,0x4f,0x4f,0x97,0x55,0x86,0xc4,0x1f,
-   0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05,
-   0x00 },
- {0x73,0x4f,0x4f,0x97,0x55,0x86,0x97,0x1f,
-   0x60,0x87,0x5d,0x5d,0x83,0x10,0x00,0x05,
-   0x00 },
- {0x73,0x4f,0x4f,0x97,0x55,0x86,0xc4,0x1f,
-   0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05,
-   0x00},
- {0x73,0x4f,0x4f,0x97,0x55,0x86,0x97,0x1f,
-   0x60,0x87,0x5d,0x5d,0x83,0x10,0x00,0x05,
-   0x00 },
- {0x73,0x4f,0x4f,0x97,0x55,0x86,0x04,0x3e,
-   0xE2,0x89,0xDf,0xDf,0x05,0x00,0x00,0x05,
-   0x00},
- {0x87,0x63,0x63,0x8B,0x69,0x1A,0x7c,0xf0,
-   0x5A,0x8F,0x57,0x57,0x7D,0x20,0x00,0x26,
-   0x01},
- {0xA3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xFf,0xFf,0x25,0x10,0x00,0x02,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1[]=
-{{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
-   0x00 },
- {0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
-   0x00 },
- {0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
-   0x00 },
- {0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
-   0x00 },
- {0x63,0x4f,0x87,0x54,0x9f,0x04,0x3e,
-   0xe2,0x89,0xdf,0x05,0x00,0x00,0x01,
-   0x00 },
- {0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0,
-   0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26,
-   0x01 },
- {0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1_H[]=
-{{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
-   0x00 },
- {0x30,0x27,0x94,0x2c,0x92,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x04,
-   0x00 },
- {0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
-   0x00 },
- {0x30,0x27,0x94,0x2c,0x92,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x04,
-   0x00 },
- {0x30,0x27,0x94,0x2c,0x92,0x04,0x3e,
-   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x04,
-   0x00 },
- {0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x05,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1_H[]=
-{{0x37,0x27,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
-   0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x44,
-   0x00 },
- {0x37,0x27,0x27,0x9B,0x2b,0x94,0x97,0x1f,
-   0x60,0x87,0x5D,0x5D,0x83,0x01,0x00,0x44,
-   0x00},
- {0x37,0x27,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
-   0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x44,
-   0x00},
- {0x37,0x27,0x27,0x9B,0x2b,0x94,0x97,0x1f,
-   0x60,0x87,0x5D,0x5D,0x83,0x01,0x00,0x44,
-   0x00},
- {0x37,0x27,0x27,0x9B,0x2b,0x94,0x04,0x3e,
-   0xE2,0x89,0xDf,0xDf,0x05,0x00,0x00,0x44,
-   0x00},
- {0x41,0x31,0x31,0x85,0x35,0x1d,0x7c,0xf0,
-   0x5A,0x8F,0x57,0x57,0x7D,0x20,0x00,0x55,
-   0x01},
- {0x4f,0x3F,0x3F,0x93,0x45,0x0D,0x24,0xf5,
-   0x02,0x88,0xFf,0xFf,0x25,0x10,0x00,0x01,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1_H[]=
-{{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
-   0x00 },
- {0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x04,
-   0x00 },
- {0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
-   0x00 },
- {0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x04,
-   0x00 },
- {0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
-   0xe2,0x89,0xdf,0x05,0x00,0x00,0x04,
-   0x00 },
- {0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
-   0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
-   0x01 },
- {0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2[]=
-{ {0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
-   0x00 },
- {0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06,
-   0x00 },
- {0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
-   0x00 },
- {0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06,
-   0x00 },
- {0x7f,0x4f,0x83,0x62,0x12,0x72,0xba,
-   0x1c,0x80,0xdf,0x73,0x00,0x00,0x06,
-   0x00 },
- {0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2[]=
-{ {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x02,
-   0x01 },
- {0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2[]=
-{ {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x02,
-   0x01 },
- {0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2_H[]=
-{ {0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
-   0x00 },
- {0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05,
-   0x00 },
- {0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
-   0x00 },
- {0x3d,0x27,0x81,0x3a,0x1a,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05,
-   0x00 },
- {0x3d,0x27,0x81,0x32,0x1a,0x72,0xba,
-   0x1c,0x80,0xdf,0x73,0x00,0x00,0x05,
-   0x00 },
- {0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x05,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2_H[]=
-{ {0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x01,
-   0x01 },
- {0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2_H[]=
-{ {0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x31,0x93,0x3e,0x86,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x01,
-   0x01 },
- {0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1UNTSC[]=
-{ {0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
-   0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
-   0x00 },
- {0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
-   0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,
-   0x00 },
- {0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
-   0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
-   0x00 },
- {0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
-   0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,
-   0x00 },
- {0x5d,0x4f,0x81,0x53,0x9c,0x56,0xba,
-   0x18,0x84,0xdf,0x57,0x00,0x00,0x01,
-   0x00 },
- {0x80,0x63,0x84,0x6c,0x17,0xec,0xf0,
-   0x90,0x8c,0x57,0xed,0x20,0x00,0x06,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1ONTSC[]=
-{ {0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
-   0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
-   0x00 },
- {0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
-   0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,
-   0x00 },
- {0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
-   0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
-   0x00 },
- {0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
-   0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,
-   0x00 },
- {0x5d,0x4f,0x81,0x56,0x9c,0x0b,0x3e,
-   0xe8,0x84,0xdf,0x0c,0x00,0x00,0x01,
-   0x00 },
- {0x7d,0x63,0x81,0x6a,0x16,0xba,0xf0,
-   0x7f,0x86,0x57,0xbb,0x00,0x00,0x06,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1UPAL[]=
-{ {0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
-   0x00 },
- {0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
-   0x00 },
- {0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
-   0x00 },
- {0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
-   0x00 },
- {0x64,0x4f,0x88,0x55,0x80,0xec,0xba,
-   0x50,0x84,0xdf,0xed,0x00,0x00,0x05,
-   0x00 },
- {0x70,0x63,0x94,0x68,0x8d,0x42,0xf1,
-   0xc8,0x8c,0x57,0xe9,0x20,0x00,0x05,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1OPAL[]=
-{ {0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
-   0x00 },
- {0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
-   0x00 },
- {0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
-   0x00 },
- {0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
-   0x00 },
- {0x64,0x4f,0x88,0x55,0x80,0x6f,0xba,
-   0x20,0x83,0xdf,0x70,0x00,0x00,0x05,
-   0x00 },
- {0x73,0x63,0x97,0x69,0x8e,0xec,0xf0,
-   0x90,0x8c,0x57,0xed,0x20,0x00,0x05,
-   0x01 }};
-
-typedef struct _SiS310_CHTVRegDataStruct
-{
- UCHAR Reg[5];
-} SiS310_CHTVRegDataStruct;
-SiS310_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] = {
-0x00 };
-
-SiS310_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] = {
-0x00 };
-
-SiS310_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] = {
-0x00 };
-
-SiS310_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] = {
-0x00 };
-
-UCHAR SiS310_CHTVVCLKUNTSC[]={0x00 };
-
-UCHAR SiS310_CHTVVCLKONTSC[]={0x00 };
-
-UCHAR SiS310_CHTVVCLKUPAL[]={0x00 };
-
-UCHAR SiS310_CHTVVCLKOPAL[]={0x00 };
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/Makefile linux-2.4.20/drivers/video/sis/Makefile
--- linux-2.4.19/drivers/video/sis/Makefile	2001-11-09 22:11:14.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/Makefile	2002-10-29 11:18:39.000000000 +0000
@@ -6,7 +6,7 @@
 
 export-objs := sis_main.o
 
-obj-y  := sis_main.o init.o init301.o
+obj-y  := sis_main.o init.o init301.o sis_accel.o
 obj-m  := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/init.c linux-2.4.20/drivers/video/sis/init.c
--- linux-2.4.19/drivers/video/sis/init.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/init.c	2002-10-29 11:18:35.000000000 +0000
@@ -1,69 +1,69 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init.c,v 1.3 2000/12/02 01:16:16 dawes Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init.c,v 1.3 2002/24/04 01:16:16 dawes Exp $ */
 /*
  * Mode switching code (CRT1 section) for SiS 300/540/630/730/315/550/650/740
- * (Universal module for Linux kernel framebuffer, XFree86 4.x)
+ * (Universal module for Linux kernel framebuffer and XFree86 4.x)
  *
- * Comments and changes marked with "TW" by Thomas Winischhofer <thomer@winischhofer.net>
+ * Assembler-To-C translation
+ * Parts Copyright 2002 by Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ * Based on BIOS
+ *     1.10.07 (1.10a) for SiS650/LVDS+CH7019
+ *     1.07.1b for SiS650/301(B/LV)
+ *     2.04.50 (I) and 2.04.5c (II), 2.07a for SiS630/301(B)
+ *     2.02.3b, 2.03.02 and 2.04.5c for 630/LVDS/LVDS+CH7005
+ *     1.09b for 315/301(B)
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holder not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  The copyright holder makes no representations
+ * about the suitability of this software for any purpose.  It is provided
+ * "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  *
- * (Version : V 0.80      [ynlai] 04/12/98)
  */
 
-/*
-#ifdef WINCE_HEADER
-*/
-/*
-#include "precomp.h"
-*/
-/*
-#endif
-*/
 #include "init.h"
 
-#ifdef TC
-#include <stdio.h>
-#include <string.h>
-#include <conio.h>
-#include <dos.h>
-#endif
-
-#ifdef WIN2000
-#include <miniport.h>
-#include "dderror.h"
-#include "devioctl.h"
-#include "miniport.h"
-#include "ntddvdeo.h"
-#include "video.h"
-#include "sisv.h"
-#include "tools.h"
-#endif
-
 #ifdef SIS300
 #include "300vtbl.h"
 #endif
+
 #ifdef SIS315H
 #include "310vtbl.h"
 #endif
 
 #ifdef LINUX_XF86
-BOOLEAN SiSBIOSSetMode(PSIS_HW_DEVICE_INFO HwDeviceExtension,
+BOOLEAN SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
                        ScrnInfoPtr pScrn, DisplayModePtr mode);
 #ifdef SISDUALHEAD /* TW: For dual head */
-BOOLEAN SiSBIOSSetModeCRT1(PSIS_HW_DEVICE_INFO HwDeviceExtension,
+BOOLEAN SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
                        ScrnInfoPtr pScrn, DisplayModePtr mode);
-BOOLEAN SiSBIOSSetModeCRT2(PSIS_HW_DEVICE_INFO HwDeviceExtension,
+BOOLEAN SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
                        ScrnInfoPtr pScrn, DisplayModePtr mode);
 #endif /* dual head */
 #endif /* linux_xf86 */
 
-#ifndef LINUX_XF86
-BOOLEAN SiSInit(PSIS_HW_DEVICE_INFO HwDeviceExtension);
+#ifdef LINUXBIOS
+BOOLEAN SiSInit(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
 #endif
 
 #ifdef LINUX_XF86
-BOOLEAN SiSSetMode(PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                   ScrnInfoPtr pScrn,USHORT ModeNo);
+BOOLEAN SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                   ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch);
 #else
-BOOLEAN SiSSetMode(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo);
+BOOLEAN SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                   USHORT ModeNo);
 #endif
 
 #if defined(ALLOC_PRAGMA)
@@ -71,29 +71,31 @@
 #pragma alloc_text(PAGE,SiSInit)
 #endif
 
-void SiS_SetReg1(USHORT, USHORT, USHORT);
-void SiS_SetReg2(USHORT, USHORT, USHORT);
-void SiS_SetReg3(USHORT, USHORT);
-void SiS_SetReg4(USHORT, ULONG);
-UCHAR SiS_GetReg1(USHORT, USHORT);
-UCHAR SiS_GetReg2(USHORT);
-ULONG SiS_GetReg3(USHORT);
-void SiS_ClearDAC(ULONG);
-
 void DelaySeconds(int seconds);
-void DebugCode(UCHAR code);
+void DebugCode(SiS_Private *SiS_Pr, UCHAR code);
 
 #ifdef LINUX_XF86
 /* TW: Mode table for X driver */
-UShort  ModeIndex_640x480[]   = {0x2E, 0x44, 0x45, 0x62};
-UShort  ModeIndex_720x480[]   = {0x31, 0x33, 0x00, 0x35};
-UShort  ModeIndex_720x576[]   = {0x32, 0x34, 0x00, 0x36};
-UShort  ModeIndex_800x600[]   = {0x30, 0x47, 0x48, 0x63};
-UShort  ModeIndex_1024x768[]  = {0x38, 0x4A, 0x4B, 0x64};
-UShort  ModeIndex_1280x1024[] = {0x3A, 0x4D, 0x4E, 0x65};
-UShort  ModeIndex_1280x960[]  = {0x7C, 0x7D, 0x00, 0x7E};
-UShort  ModeIndex_1600x1200[] = {0x3C, 0x3D, 0x3E, 0x66};
-UShort  ModeIndex_1920x1440[] = {0x68, 0x69, 0x6A, 0x6B};
+const UShort  ModeIndex_320x480[]      = {0x5A, 0x5B, 0x00, 0x00};  /* DSTN/FSTN */
+const UShort  ModeIndex_512x384[]      = {0x52, 0x58, 0x00, 0x5c};
+const UShort  ModeIndex_640x480[]      = {0x2E, 0x44, 0x00, 0x62};
+const UShort  ModeIndex_720x480[]      = {0x31, 0x33, 0x00, 0x35};
+const UShort  ModeIndex_720x576[]      = {0x32, 0x34, 0x00, 0x36};
+const UShort  ModeIndex_800x480[]      = {0x70, 0x7a, 0x00, 0x76};  /* 310/325 series only */
+const UShort  ModeIndex_800x600[]      = {0x30, 0x47, 0x00, 0x63};
+const UShort  ModeIndex_1024x768[]     = {0x38, 0x4A, 0x00, 0x64};
+const UShort  ModeIndex_1024x576[]     = {0x71, 0x74, 0x00, 0x77};  /* 310/325 series only */
+const UShort  ModeIndex_1024x600[]     = {0x20, 0x21, 0x00, 0x22};  /* 300 series only */
+const UShort  ModeIndex_1280x1024[]    = {0x3A, 0x4D, 0x00, 0x65};
+const UShort  ModeIndex_300_1280x960[] = {0x6e, 0x6f, 0x00, 0x7b};
+const UShort  ModeIndex_310_1280x960[] = {0x7C, 0x7D, 0x00, 0x7E};
+const UShort  ModeIndex_1152x768[]     = {0x23, 0x24, 0x00, 0x25};  /* 300 series only */
+const UShort  ModeIndex_1280x768[]     = {0x23, 0x24, 0x00, 0x25};  /* 310/325 series only */
+const UShort  ModeIndex_1280x720[]     = {0x79, 0x75, 0x00, 0x78};  /* 310/325 series only */
+const UShort  ModeIndex_1400x1050[]    = {0x26, 0x27, 0x00, 0x28};  /* 310/325 series only */
+const UShort  ModeIndex_1600x1200[]    = {0x3C, 0x3D, 0x00, 0x66};
+const UShort  ModeIndex_1920x1440[]    = {0x68, 0x69, 0x00, 0x6B};
+const UShort  ModeIndex_2048x1536[]    = {0x6c, 0x6d, 0x00, 0x6e};  /* 310/325 series only */
 #endif
 
 void
@@ -104,8 +106,7 @@
   int j;
 #endif
 
-  for (i=0;i<seconds;i++)
-  {
+  for (i=0;i<seconds;i++) {
 #ifdef TC
     delay(1000);
 #endif
@@ -124,359 +125,524 @@
 }
 
 void
-DebugCode(UCHAR code)
+DebugCode(SiS_Private *SiS_Pr, UCHAR code)
 {
-  OutPortByte ( 0x80, code);
-  /*OutPortByte ( 0x300, code);*/
+  OutPortByte(0x80, code);
   DelaySeconds(0x3);
 }
 
 #ifdef SIS300
 void
-InitTo300Pointer(void)
+InitTo300Pointer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-   SiS_SModeIDTable = (SiS_StStruct *) SiS300_SModeIDTable;
-   SiS_VBModeIDTable = (SiS_VBModeStruct *) SiS300_VBModeIDTable;	/*add for 300 oem util*/
-   SiS_StandTable = (SiS_StandTableStruct *) SiS300_StandTable;
-   SiS_EModeIDTable = (SiS_ExtStruct *) SiS300_EModeIDTable;
-   SiS_RefIndex = (SiS_Ext2Struct *) SiS300_RefIndex;
-   SiS_CRT1Table = (SiS_CRT1TableStruct *) SiS300_CRT1Table;
-   SiS_MCLKData = (SiS_MCLKDataStruct *) SiS300_MCLKData;
-   SiS_ECLKData = (SiS_ECLKDataStruct *) SiS300_ECLKData;
-   SiS_VCLKData = (SiS_VCLKDataStruct *) SiS300_VCLKData;
-   SiS_VBVCLKData = (SiS_VBVCLKDataStruct *) SiS300_VCLKData;
-   SiS_ScreenOffset = SiS300_ScreenOffset;
-   SiS_StResInfo = (SiS_StResInfoStruct *) SiS300_StResInfo;
-   SiS_ModeResInfo = (SiS_ModeResInfoStruct *) SiS300_ModeResInfo;
-
-   pSiS_OutputSelect = &SiS300_OutputSelect;
-   pSiS_SoftSetting = &SiS300_SoftSetting;
-   pSiS_SR07 = &SiS300_SR07;
-   SiS_SR15 = SiS300_SR15;
-   SiS_CR40 = SiS300_CR40;
-   SiS_CR49 = SiS300_CR49;
-   pSiS_SR1F = &SiS300_SR1F;
-   pSiS_SR21 = &SiS300_SR21;
-   pSiS_SR22 = &SiS300_SR22;
-   pSiS_SR23 = &SiS300_SR23;
-   pSiS_SR24 = &SiS300_SR24;
-   SiS_SR25 = SiS300_SR25;
-   pSiS_SR31 = &SiS300_SR31;
-   pSiS_SR32 = &SiS300_SR32;
-   pSiS_SR33 = &SiS300_SR33;
-   pSiS_CRT2Data_1_2 = &SiS300_CRT2Data_1_2;
-   pSiS_CRT2Data_4_D = &SiS300_CRT2Data_4_D;
-   pSiS_CRT2Data_4_E = &SiS300_CRT2Data_4_E;
-   pSiS_CRT2Data_4_10 = &SiS300_CRT2Data_4_10;
-   pSiS_RGBSenseData = &SiS300_RGBSenseData;
-   pSiS_VideoSenseData = &SiS300_VideoSenseData;
-   pSiS_YCSenseData = &SiS300_YCSenseData;
-   pSiS_RGBSenseData2 = &SiS300_RGBSenseData2;
-   pSiS_VideoSenseData2 = &SiS300_VideoSenseData2;
-   pSiS_YCSenseData2 = &SiS300_YCSenseData2;
-
-   SiS_NTSCPhase = SiS300_NTSCPhase;
-   SiS_PALPhase = SiS300_PALPhase;
-   SiS_NTSCPhase2 = SiS300_NTSCPhase2;
-   SiS_PALPhase2 = SiS300_PALPhase2;
-   SiS_PALMPhase = SiS300_PALMPhase;  /*add for PALMN*/
-   SiS_PALNPhase = SiS300_PALNPhase;
-   
-   SiS_StLCD1024x768Data = (SiS_LCDDataStruct *) SiS300_StLCD1024x768Data;
-   SiS_ExtLCD1024x768Data = (SiS_LCDDataStruct *) SiS300_ExtLCD1024x768Data;
-   SiS_St2LCD1024x768Data = (SiS_LCDDataStruct *) SiS300_St2LCD1024x768Data;
-   SiS_StLCD1280x1024Data = (SiS_LCDDataStruct *) SiS300_StLCD1280x1024Data;
-   SiS_ExtLCD1280x1024Data = (SiS_LCDDataStruct *) SiS300_ExtLCD1280x1024Data;
-   SiS_St2LCD1280x1024Data = (SiS_LCDDataStruct *) SiS300_St2LCD1280x1024Data;
-   SiS_NoScaleData = (SiS_LCDDataStruct *) SiS300_NoScaleData;
-   SiS_LCD1280x960Data = (SiS_LCDDataStruct *) SiS300_LCD1280x960Data;
-   SiS_StPALData = (SiS_TVDataStruct *) SiS300_StPALData;
-   SiS_ExtPALData = (SiS_TVDataStruct *) SiS300_ExtPALData;
-   SiS_StNTSCData = (SiS_TVDataStruct *) SiS300_StNTSCData;
-   SiS_ExtNTSCData = (SiS_TVDataStruct *) SiS300_ExtNTSCData;
-   SiS_St1HiTVData = (SiS_TVDataStruct *) SiS300_St1HiTVData;
-   SiS_St2HiTVData = (SiS_TVDataStruct *) SiS300_St2HiTVData;
-   SiS_ExtHiTVData = (SiS_TVDataStruct *) SiS300_ExtHiTVData;
-   SiS_NTSCTiming = SiS300_NTSCTiming;
-   SiS_PALTiming = SiS300_PALTiming;
-   SiS_HiTVSt1Timing = SiS300_HiTVSt1Timing;
-   SiS_HiTVSt2Timing = SiS300_HiTVSt2Timing;
-   SiS_HiTVTextTiming = SiS300_HiTVTextTiming;
-   SiS_HiTVGroup3Data = SiS300_HiTVGroup3Data;
-   SiS_HiTVGroup3Simu = SiS300_HiTVGroup3Simu;
-   SiS_HiTVGroup3Text = SiS300_HiTVGroup3Text;
-
-   SiS_PanelDelayTbl = (SiS_PanelDelayTblStruct *) SiS300_PanelDelayTbl;
-   SiS_LVDS800x600Data_1 = (SiS_LVDSDataStruct *) SiS300_LVDS800x600Data_1;
-   SiS_LVDS800x600Data_2 = (SiS_LVDSDataStruct *) SiS300_LVDS800x600Data_2;
-   SiS_LVDS1024x768Data_1 = (SiS_LVDSDataStruct *) SiS300_LVDS1024x768Data_1;
-   SiS_LVDS1024x768Data_2 = (SiS_LVDSDataStruct *) SiS300_LVDS1024x768Data_2;
-   SiS_LVDS1280x1024Data_1 = (SiS_LVDSDataStruct *) SiS300_LVDS1280x1024Data_1;
-   SiS_LVDS1280x1024Data_2 = (SiS_LVDSDataStruct *) SiS300_LVDS1280x1024Data_2;
-   SiS_LVDS640x480Data_1 = (SiS_LVDSDataStruct *) SiS300_LVDS640x480Data_1;
-   SiS_CHTVUNTSCData = (SiS_LVDSDataStruct *) SiS300_CHTVUNTSCData;
-   SiS_CHTVONTSCData = (SiS_LVDSDataStruct *) SiS300_CHTVONTSCData;
-   SiS_CHTVUPALData = (SiS_LVDSDataStruct *) SiS300_CHTVUPALData;
-   SiS_CHTVOPALData = (SiS_LVDSDataStruct *) SiS300_CHTVOPALData;
-   SiS_PanelType00_1 = (SiS_LVDSDesStruct *) SiS300_PanelType00_1;
-   SiS_PanelType01_1 = (SiS_LVDSDesStruct *) SiS300_PanelType01_1;
-   SiS_PanelType02_1 = (SiS_LVDSDesStruct *) SiS300_PanelType02_1;
-   SiS_PanelType03_1 = (SiS_LVDSDesStruct *) SiS300_PanelType03_1;
-   SiS_PanelType04_1 = (SiS_LVDSDesStruct *) SiS300_PanelType04_1;
-   SiS_PanelType05_1 = (SiS_LVDSDesStruct *) SiS300_PanelType05_1;
-   SiS_PanelType06_1 = (SiS_LVDSDesStruct *) SiS300_PanelType06_1;
-   SiS_PanelType07_1 = (SiS_LVDSDesStruct *) SiS300_PanelType07_1;
-   SiS_PanelType08_1 = (SiS_LVDSDesStruct *) SiS300_PanelType08_1;
-   SiS_PanelType09_1 = (SiS_LVDSDesStruct *) SiS300_PanelType09_1;
-   SiS_PanelType0a_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0a_1;
-   SiS_PanelType0b_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0b_1;
-   SiS_PanelType0c_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0c_1;
-   SiS_PanelType0d_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0d_1;
-   SiS_PanelType0e_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0e_1;
-   SiS_PanelType0f_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0f_1;
-   SiS_PanelType00_2 = (SiS_LVDSDesStruct *) SiS300_PanelType00_2;
-   SiS_PanelType01_2 = (SiS_LVDSDesStruct *) SiS300_PanelType01_2;
-   SiS_PanelType02_2 = (SiS_LVDSDesStruct *) SiS300_PanelType02_2;
-   SiS_PanelType03_2 = (SiS_LVDSDesStruct *) SiS300_PanelType03_2;
-   SiS_PanelType04_2 = (SiS_LVDSDesStruct *) SiS300_PanelType04_2;
-   SiS_PanelType05_2 = (SiS_LVDSDesStruct *) SiS300_PanelType05_2;
-   SiS_PanelType06_2 = (SiS_LVDSDesStruct *) SiS300_PanelType06_2;
-   SiS_PanelType07_2 = (SiS_LVDSDesStruct *) SiS300_PanelType07_2;
-   SiS_PanelType08_2 = (SiS_LVDSDesStruct *) SiS300_PanelType08_2;
-   SiS_PanelType09_2 = (SiS_LVDSDesStruct *) SiS300_PanelType09_2;
-   SiS_PanelType0a_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0a_2;
-   SiS_PanelType0b_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0b_2;
-   SiS_PanelType0c_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0c_2;
-   SiS_PanelType0d_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0d_2;
-   SiS_PanelType0e_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0e_2;
-   SiS_PanelType0f_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0f_2;
-   SiS_CHTVUNTSCDesData = (SiS_LVDSDesStruct *) SiS300_CHTVUNTSCDesData;
-   SiS_CHTVONTSCDesData = (SiS_LVDSDesStruct *) SiS300_CHTVONTSCDesData;
-   SiS_CHTVUPALDesData = (SiS_LVDSDesStruct *) SiS300_CHTVUPALDesData;
-   SiS_CHTVOPALDesData = (SiS_LVDSDesStruct *) SiS300_CHTVOPALDesData;
-   SiS_LVDSCRT1800x600_1 = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT1800x600_1;
-   SiS_LVDSCRT11024x768_1 = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11024x768_1;
-   SiS_LVDSCRT11280x1024_1 = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11280x1024_1;
-   SiS_LVDSCRT1800x600_1_H = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT1800x600_1_H;
-   SiS_LVDSCRT11024x768_1_H = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11024x768_1_H;
-   SiS_LVDSCRT11280x1024_1_H = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11280x1024_1_H;
-   SiS_LVDSCRT1800x600_2 = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT1800x600_2;
-   SiS_LVDSCRT11024x768_2 = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11024x768_2;
-   SiS_LVDSCRT11280x1024_2 = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11280x1024_2;
-   SiS_LVDSCRT1800x600_2_H = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT1800x600_2_H;
-   SiS_LVDSCRT11024x768_2_H = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11024x768_2_H;
-   SiS_LVDSCRT11280x1024_2_H = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11280x1024_2_H;
-   SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *) SiS300_CHTVCRT1UNTSC;
-   SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *) SiS300_CHTVCRT1ONTSC;
-   SiS_CHTVCRT1UPAL = (SiS_LVDSCRT1DataStruct *) SiS300_CHTVCRT1UPAL;
-   SiS_CHTVCRT1OPAL = (SiS_LVDSCRT1DataStruct *) SiS300_CHTVCRT1OPAL;
-   SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *) SiS300_CHTVReg_UNTSC;
-   SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *) SiS300_CHTVReg_ONTSC;
-   SiS_CHTVReg_UPAL = (SiS_CHTVRegDataStruct *) SiS300_CHTVReg_UPAL;
-   SiS_CHTVReg_OPAL = (SiS_CHTVRegDataStruct *) SiS300_CHTVReg_OPAL;
-   SiS_CHTVVCLKUNTSC = SiS300_CHTVVCLKUNTSC;
-   SiS_CHTVVCLKONTSC = SiS300_CHTVVCLKONTSC;
-   SiS_CHTVVCLKUPAL = SiS300_CHTVVCLKUPAL;
-   SiS_CHTVVCLKOPAL = SiS300_CHTVVCLKOPAL;
-   /* 300 customization related */
+   SiS_Pr->SiS_SModeIDTable  = (SiS_StStruct *)SiS300_SModeIDTable;
+   SiS_Pr->SiS_VBModeIDTable = (SiS_VBModeStruct *)SiS300_VBModeIDTable;
+   SiS_Pr->SiS_StandTable    = (SiS_StandTableStruct *)SiS300_StandTable;
+   SiS_Pr->SiS_EModeIDTable  = (SiS_ExtStruct *)SiS300_EModeIDTable;
+   SiS_Pr->SiS_RefIndex      = (SiS_Ext2Struct *)SiS300_RefIndex;
+   SiS_Pr->SiS_CRT1Table     = (SiS_CRT1TableStruct *)SiS300_CRT1Table;
+   if(HwDeviceExtension->jChipType == SIS_300) {
+      SiS_Pr->SiS_MCLKData_0    = (SiS_MCLKDataStruct *)SiS300_MCLKData_300; /* 300 */
+   } else {
+      SiS_Pr->SiS_MCLKData_0    = (SiS_MCLKDataStruct *)SiS300_MCLKData_630; /* 630 */
+   }
+   SiS_Pr->SiS_ECLKData      = (SiS_ECLKDataStruct *)SiS300_ECLKData;
+   SiS_Pr->SiS_VCLKData      = (SiS_VCLKDataStruct *)SiS300_VCLKData;
+   SiS_Pr->SiS_VBVCLKData    = (SiS_VBVCLKDataStruct *)SiS300_VCLKData;
+   SiS_Pr->SiS_ScreenOffset  = SiS300_ScreenOffset;
+   SiS_Pr->SiS_StResInfo     = (SiS_StResInfoStruct *)SiS300_StResInfo;
+   SiS_Pr->SiS_ModeResInfo   = (SiS_ModeResInfoStruct *)SiS300_ModeResInfo;
+
+   SiS_Pr->pSiS_OutputSelect = &SiS300_OutputSelect;
+   SiS_Pr->pSiS_SoftSetting  = &SiS300_SoftSetting;
+
+   SiS_Pr->SiS_SR15  = SiS300_SR15;
+
+#ifndef LINUX_XF86
+   SiS_Pr->pSiS_SR07 = &SiS300_SR07;
+   SiS_Pr->SiS_CR40  = SiS300_CR40;
+   SiS_Pr->SiS_CR49  = SiS300_CR49;
+   SiS_Pr->pSiS_SR1F = &SiS300_SR1F;
+   SiS_Pr->pSiS_SR21 = &SiS300_SR21;
+   SiS_Pr->pSiS_SR22 = &SiS300_SR22;
+   SiS_Pr->pSiS_SR23 = &SiS300_SR23;
+   SiS_Pr->pSiS_SR24 = &SiS300_SR24;
+   SiS_Pr->SiS_SR25  = SiS300_SR25;
+   SiS_Pr->pSiS_SR31 = &SiS300_SR31;
+   SiS_Pr->pSiS_SR32 = &SiS300_SR32;
+   SiS_Pr->pSiS_SR33 = &SiS300_SR33;
+   SiS_Pr->pSiS_CRT2Data_1_2  = &SiS300_CRT2Data_1_2;
+   SiS_Pr->pSiS_CRT2Data_4_D  = &SiS300_CRT2Data_4_D;
+   SiS_Pr->pSiS_CRT2Data_4_E  = &SiS300_CRT2Data_4_E;
+   SiS_Pr->pSiS_CRT2Data_4_10 = &SiS300_CRT2Data_4_10;
+   SiS_Pr->pSiS_RGBSenseData    = &SiS300_RGBSenseData;
+   SiS_Pr->pSiS_VideoSenseData  = &SiS300_VideoSenseData;
+   SiS_Pr->pSiS_YCSenseData     = &SiS300_YCSenseData;
+   SiS_Pr->pSiS_RGBSenseData2   = &SiS300_RGBSenseData2;
+   SiS_Pr->pSiS_VideoSenseData2 = &SiS300_VideoSenseData2;
+   SiS_Pr->pSiS_YCSenseData2    = &SiS300_YCSenseData2;
+#endif
+
+   SiS_Pr->SiS_NTSCPhase  = SiS300_NTSCPhase;
+   SiS_Pr->SiS_PALPhase   = SiS300_PALPhase;
+   SiS_Pr->SiS_NTSCPhase2 = SiS300_NTSCPhase2;
+   SiS_Pr->SiS_PALPhase2  = SiS300_PALPhase2;
+   SiS_Pr->SiS_PALMPhase  = SiS300_PALMPhase;
+   SiS_Pr->SiS_PALNPhase  = SiS300_PALNPhase;
+   SiS_Pr->SiS_PALMPhase2 = SiS300_PALMPhase2;
+   SiS_Pr->SiS_PALNPhase2 = SiS300_PALNPhase2;
+
+   SiS_Pr->SiS_StLCD1024x768Data    = (SiS_LCDDataStruct *)SiS300_StLCD1024x768Data;
+   SiS_Pr->SiS_ExtLCD1024x768Data   = (SiS_LCDDataStruct *)SiS300_ExtLCD1024x768Data;
+   SiS_Pr->SiS_St2LCD1024x768Data   = (SiS_LCDDataStruct *)SiS300_St2LCD1024x768Data;
+   SiS_Pr->SiS_StLCD1280x1024Data   = (SiS_LCDDataStruct *)SiS300_StLCD1280x1024Data;
+   SiS_Pr->SiS_ExtLCD1280x1024Data  = (SiS_LCDDataStruct *)SiS300_ExtLCD1280x1024Data;
+   SiS_Pr->SiS_St2LCD1280x1024Data  = (SiS_LCDDataStruct *)SiS300_St2LCD1280x1024Data;
+   SiS_Pr->SiS_NoScaleData1024x768  = (SiS_LCDDataStruct *)SiS300_NoScaleData1024x768;
+   SiS_Pr->SiS_NoScaleData1280x1024 = (SiS_LCDDataStruct *)SiS300_NoScaleData1280x1024;
+   SiS_Pr->SiS_LCD1280x960Data      = (SiS_LCDDataStruct *)SiS300_LCD1280x960Data;
+   SiS_Pr->SiS_ExtLCD1400x1050Data  = (SiS_LCDDataStruct *)SiS300_ExtLCD1400x1050Data;
+   SiS_Pr->SiS_ExtLCD1600x1200Data  = (SiS_LCDDataStruct *)SiS300_ExtLCD1600x1200Data;
+   SiS_Pr->SiS_StLCD1400x1050Data   = (SiS_LCDDataStruct *)SiS300_StLCD1400x1050Data;
+   SiS_Pr->SiS_StLCD1600x1200Data   = (SiS_LCDDataStruct *)SiS300_StLCD1600x1200Data;
+   SiS_Pr->SiS_NoScaleData1400x1050 = (SiS_LCDDataStruct *)SiS300_NoScaleData1400x1050;
+   SiS_Pr->SiS_NoScaleData1600x1200 = (SiS_LCDDataStruct *)SiS300_NoScaleData1600x1200;
+
+   SiS_Pr->SiS_StPALData   = (SiS_TVDataStruct *)SiS300_StPALData;
+   SiS_Pr->SiS_ExtPALData  = (SiS_TVDataStruct *)SiS300_ExtPALData;
+   SiS_Pr->SiS_StNTSCData  = (SiS_TVDataStruct *)SiS300_StNTSCData;
+   SiS_Pr->SiS_ExtNTSCData = (SiS_TVDataStruct *)SiS300_ExtNTSCData;
+#ifdef oldHV
+   SiS_Pr->SiS_St1HiTVData = (SiS_TVDataStruct *)SiS300_St1HiTVData;
+   SiS_Pr->SiS_St2HiTVData = (SiS_TVDataStruct *)SiS300_St2HiTVData;
+   SiS_Pr->SiS_ExtHiTVData = (SiS_TVDataStruct *)SiS300_ExtHiTVData;
+#endif
+
+   SiS_Pr->SiS_NTSCTiming     = SiS300_NTSCTiming;
+   SiS_Pr->SiS_PALTiming      = SiS300_PALTiming;
+#ifdef oldHV
+   SiS_Pr->SiS_HiTVSt1Timing  = SiS300_HiTVSt1Timing;
+   SiS_Pr->SiS_HiTVSt2Timing  = SiS300_HiTVSt2Timing;
+   SiS_Pr->SiS_HiTVTextTiming = SiS300_HiTVTextTiming;
+   SiS_Pr->SiS_HiTVGroup3Data = SiS300_HiTVGroup3Data;
+   SiS_Pr->SiS_HiTVGroup3Simu = SiS300_HiTVGroup3Simu;
+   SiS_Pr->SiS_HiTVGroup3Text = SiS300_HiTVGroup3Text;
+#endif
+
+   SiS_Pr->SiS_PanelDelayTbl     = (SiS_PanelDelayTblStruct *)SiS300_PanelDelayTbl;
+   SiS_Pr->SiS_PanelDelayTblLVDS = (SiS_PanelDelayTblStruct *)SiS300_PanelDelayTblLVDS;
+
+   SiS_Pr->SiS_LVDS800x600Data_1   = (SiS_LVDSDataStruct *)SiS300_LVDS800x600Data_1;
+   SiS_Pr->SiS_LVDS800x600Data_2   = (SiS_LVDSDataStruct *)SiS300_LVDS800x600Data_2;
+   SiS_Pr->SiS_LVDS1024x768Data_1  = (SiS_LVDSDataStruct *)SiS300_LVDS1024x768Data_1;
+   SiS_Pr->SiS_LVDS1024x768Data_2  = (SiS_LVDSDataStruct *)SiS300_LVDS1024x768Data_2;
+   SiS_Pr->SiS_LVDS1280x1024Data_1 = (SiS_LVDSDataStruct *)SiS300_LVDS1280x1024Data_1;
+   SiS_Pr->SiS_LVDS1280x1024Data_2 = (SiS_LVDSDataStruct *)SiS300_LVDS1280x1024Data_2;
+   SiS_Pr->SiS_LVDS1280x960Data_1  = (SiS_LVDSDataStruct *)SiS300_LVDS1280x1024Data_1;
+   SiS_Pr->SiS_LVDS1280x960Data_2  = (SiS_LVDSDataStruct *)SiS300_LVDS1280x1024Data_2;
+   SiS_Pr->SiS_LVDS1400x1050Data_1 = (SiS_LVDSDataStruct *)SiS300_LVDS1400x1050Data_1;
+   SiS_Pr->SiS_LVDS1400x1050Data_2 = (SiS_LVDSDataStruct *)SiS300_LVDS1400x1050Data_2;
+   SiS_Pr->SiS_LVDS1024x600Data_1  = (SiS_LVDSDataStruct *)SiS300_LVDS1024x600Data_1;
+   SiS_Pr->SiS_LVDS1024x600Data_2  = (SiS_LVDSDataStruct *)SiS300_LVDS1024x600Data_2;
+   SiS_Pr->SiS_LVDS1152x768Data_1  = (SiS_LVDSDataStruct *)SiS300_LVDS1152x768Data_1;
+   SiS_Pr->SiS_LVDS1152x768Data_2  = (SiS_LVDSDataStruct *)SiS300_LVDS1152x768Data_2;
+   SiS_Pr->SiS_LVDSXXXxXXXData_1   = (SiS_LVDSDataStruct *)SiS300_LVDSXXXxXXXData_1;
+   SiS_Pr->SiS_LVDS320x480Data_1   = (SiS_LVDSDataStruct *)SiS300_LVDS320x480Data_1;
+   SiS_Pr->SiS_LVDS640x480Data_1   = (SiS_LVDSDataStruct *)SiS300_LVDS640x480Data_1;
+   SiS_Pr->SiS_LCDA1400x1050Data_1 = (SiS_LVDSDataStruct *)SiS300_LCDA1400x1050Data_1;
+   SiS_Pr->SiS_LCDA1400x1050Data_2 = (SiS_LVDSDataStruct *)SiS300_LCDA1400x1050Data_2;
+   SiS_Pr->SiS_LCDA1600x1200Data_1 = (SiS_LVDSDataStruct *)SiS300_LCDA1600x1200Data_1;
+   SiS_Pr->SiS_LCDA1600x1200Data_2 = (SiS_LVDSDataStruct *)SiS300_LCDA1600x1200Data_2;
+   SiS_Pr->SiS_CHTVUNTSCData = (SiS_LVDSDataStruct *)SiS300_CHTVUNTSCData;
+   SiS_Pr->SiS_CHTVONTSCData = (SiS_LVDSDataStruct *)SiS300_CHTVONTSCData;
+   SiS_Pr->SiS_CHTVUPALData  = (SiS_LVDSDataStruct *)SiS300_CHTVUPALData;
+   SiS_Pr->SiS_CHTVOPALData  = (SiS_LVDSDataStruct *)SiS300_CHTVOPALData;
+   SiS_Pr->SiS_PanelType00_1 = (SiS_LVDSDesStruct *)SiS300_PanelType00_1;
+   SiS_Pr->SiS_PanelType01_1 = (SiS_LVDSDesStruct *)SiS300_PanelType01_1;
+   SiS_Pr->SiS_PanelType02_1 = (SiS_LVDSDesStruct *)SiS300_PanelType02_1;
+   SiS_Pr->SiS_PanelType03_1 = (SiS_LVDSDesStruct *)SiS300_PanelType03_1;
+   SiS_Pr->SiS_PanelType04_1 = (SiS_LVDSDesStruct *)SiS300_PanelType04_1;
+   SiS_Pr->SiS_PanelType05_1 = (SiS_LVDSDesStruct *)SiS300_PanelType05_1;
+   SiS_Pr->SiS_PanelType06_1 = (SiS_LVDSDesStruct *)SiS300_PanelType06_1;
+   SiS_Pr->SiS_PanelType07_1 = (SiS_LVDSDesStruct *)SiS300_PanelType07_1;
+   SiS_Pr->SiS_PanelType08_1 = (SiS_LVDSDesStruct *)SiS300_PanelType08_1;
+   SiS_Pr->SiS_PanelType09_1 = (SiS_LVDSDesStruct *)SiS300_PanelType09_1;
+   SiS_Pr->SiS_PanelType0a_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0a_1;
+   SiS_Pr->SiS_PanelType0b_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0b_1;
+   SiS_Pr->SiS_PanelType0c_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0c_1;
+   SiS_Pr->SiS_PanelType0d_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0d_1;
+   SiS_Pr->SiS_PanelType0e_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0e_1;
+   SiS_Pr->SiS_PanelType0f_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0f_1;
+   SiS_Pr->SiS_PanelType00_2 = (SiS_LVDSDesStruct *)SiS300_PanelType00_2;
+   SiS_Pr->SiS_PanelType01_2 = (SiS_LVDSDesStruct *)SiS300_PanelType01_2;
+   SiS_Pr->SiS_PanelType02_2 = (SiS_LVDSDesStruct *)SiS300_PanelType02_2;
+   SiS_Pr->SiS_PanelType03_2 = (SiS_LVDSDesStruct *)SiS300_PanelType03_2;
+   SiS_Pr->SiS_PanelType04_2 = (SiS_LVDSDesStruct *)SiS300_PanelType04_2;
+   SiS_Pr->SiS_PanelType05_2 = (SiS_LVDSDesStruct *)SiS300_PanelType05_2;
+   SiS_Pr->SiS_PanelType06_2 = (SiS_LVDSDesStruct *)SiS300_PanelType06_2;
+   SiS_Pr->SiS_PanelType07_2 = (SiS_LVDSDesStruct *)SiS300_PanelType07_2;
+   SiS_Pr->SiS_PanelType08_2 = (SiS_LVDSDesStruct *)SiS300_PanelType08_2;
+   SiS_Pr->SiS_PanelType09_2 = (SiS_LVDSDesStruct *)SiS300_PanelType09_2;
+   SiS_Pr->SiS_PanelType0a_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0a_2;
+   SiS_Pr->SiS_PanelType0b_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0b_2;
+   SiS_Pr->SiS_PanelType0c_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0c_2;
+   SiS_Pr->SiS_PanelType0d_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0d_2;
+   SiS_Pr->SiS_PanelType0e_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0e_2;
+   SiS_Pr->SiS_PanelType0f_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0f_2;
+   SiS_Pr->SiS_CHTVUNTSCDesData = (SiS_LVDSDesStruct *)SiS300_CHTVUNTSCDesData;
+   SiS_Pr->SiS_CHTVONTSCDesData = (SiS_LVDSDesStruct *)SiS300_CHTVONTSCDesData;
+   SiS_Pr->SiS_CHTVUPALDesData  = (SiS_LVDSDesStruct *)SiS300_CHTVUPALDesData;
+   SiS_Pr->SiS_CHTVOPALDesData  = (SiS_LVDSDesStruct *)SiS300_CHTVOPALDesData;
+   SiS_Pr->SiS_LVDSCRT1800x600_1     = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_1;
+   SiS_Pr->SiS_LVDSCRT11024x768_1    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_1;
+   SiS_Pr->SiS_LVDSCRT11280x1024_1   = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_1;
+   SiS_Pr->SiS_LVDSCRT11024x600_1    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x600_1;
+   SiS_Pr->SiS_LVDSCRT11152x768_1    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11152x768_1;
+   SiS_Pr->SiS_LVDSCRT1800x600_1_H   = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_1_H;
+   SiS_Pr->SiS_LVDSCRT11024x768_1_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_1_H;
+   SiS_Pr->SiS_LVDSCRT11280x1024_1_H = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_1_H;
+   SiS_Pr->SiS_LVDSCRT11024x600_1_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x600_1_H;
+   SiS_Pr->SiS_LVDSCRT11152x768_1_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11152x768_1_H;
+   SiS_Pr->SiS_LVDSCRT1800x600_2     = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_2;
+   SiS_Pr->SiS_LVDSCRT11024x768_2    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_2;
+   SiS_Pr->SiS_LVDSCRT11280x1024_2   = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_2;
+   SiS_Pr->SiS_LVDSCRT11024x600_2    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x600_2;
+   SiS_Pr->SiS_LVDSCRT11152x768_2    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11152x768_2;
+   SiS_Pr->SiS_LVDSCRT1800x600_2_H   = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_2_H;
+   SiS_Pr->SiS_LVDSCRT11024x768_2_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_2_H;
+   SiS_Pr->SiS_LVDSCRT11280x1024_2_H = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_2_H;
+   SiS_Pr->SiS_LVDSCRT11024x600_2_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x600_2_H;
+   SiS_Pr->SiS_LVDSCRT11152x768_2_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11152x768_2_H;
+   SiS_Pr->SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1UNTSC;
+   SiS_Pr->SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1ONTSC;
+   SiS_Pr->SiS_CHTVCRT1UPAL  = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1UPAL;
+   SiS_Pr->SiS_CHTVCRT1OPAL  = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1OPAL;
+   SiS_Pr->SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_UNTSC;
+   SiS_Pr->SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_ONTSC;
+   SiS_Pr->SiS_CHTVReg_UPAL  = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_UPAL;
+   SiS_Pr->SiS_CHTVReg_OPAL  = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_OPAL;
+   SiS_Pr->SiS_CHTVVCLKUNTSC = SiS300_CHTVVCLKUNTSC;
+   SiS_Pr->SiS_CHTVVCLKONTSC = SiS300_CHTVVCLKONTSC;
+   SiS_Pr->SiS_CHTVVCLKUPAL  = SiS300_CHTVVCLKUPAL;
+   SiS_Pr->SiS_CHTVVCLKOPAL  = SiS300_CHTVVCLKOPAL;
+
+   /* TW: LCDResInfo will on 300 series be translated to 310/325 series definitions */
+   SiS_Pr->SiS_Panel320x480   = Panel_320x480;
+   SiS_Pr->SiS_Panel640x480   = Panel_640x480;
+   SiS_Pr->SiS_Panel800x600   = Panel_800x600;
+   SiS_Pr->SiS_Panel1024x768  = Panel_1024x768;
+   SiS_Pr->SiS_Panel1280x1024 = Panel_1280x1024;
+   SiS_Pr->SiS_Panel1280x960  = Panel_1280x960;
+   SiS_Pr->SiS_Panel1024x600  = Panel_1024x600;
+   SiS_Pr->SiS_Panel1152x768  = Panel_1152x768;
+   SiS_Pr->SiS_Panel1600x1200 = 16;  		/* TW: Something illegal */
+   SiS_Pr->SiS_Panel1400x1050 = 16;  		/* TW: Something illegal */
+   SiS_Pr->SiS_Panel1152x864  = 16;   		/* TW: Something illegal */
+   SiS_Pr->SiS_Panel1280x768  = 16;   		/* TW: Something illegal */
+   SiS_Pr->SiS_PanelMax       = Panel_320x480;     /* TW: highest value */
+   SiS_Pr->SiS_PanelMinLVDS   = Panel_800x600;     /* TW: Lowest value LVDS */
+   SiS_Pr->SiS_PanelMin301    = Panel_1024x768;    /* TW: lowest value 301 */
 }
 #endif
 
 #ifdef SIS315H
 void
-InitTo310Pointer(void)
-{
-   SiS_SModeIDTable = (SiS_StStruct *) SiS310_SModeIDTable;
-   SiS_StandTable = (SiS_StandTableStruct *) SiS310_StandTable;
-   SiS_EModeIDTable = (SiS_ExtStruct *) SiS310_EModeIDTable;
-   SiS_RefIndex = (SiS_Ext2Struct *) SiS310_RefIndex;
-   SiS_CRT1Table = (SiS_CRT1TableStruct *) SiS310_CRT1Table;
-   SiS_MCLKData = (SiS_MCLKDataStruct *) SiS310_MCLKData;
-   SiS_ECLKData = (SiS_ECLKDataStruct *) SiS310_ECLKData;
-   SiS_VCLKData = (SiS_VCLKDataStruct *) SiS310_VCLKData;
-   SiS_VBVCLKData = (SiS_VBVCLKDataStruct *) SiS310_VBVCLKData;
-   SiS_ScreenOffset = SiS310_ScreenOffset;
-   SiS_StResInfo = (SiS_StResInfoStruct *) SiS310_StResInfo;
-   SiS_ModeResInfo = (SiS_ModeResInfoStruct *) SiS310_ModeResInfo;
-
-   pSiS_OutputSelect = &SiS310_OutputSelect;
-   pSiS_SoftSetting = &SiS310_SoftSetting;
-   pSiS_SR07 = &SiS310_SR07;
-   SiS_SR15 = SiS310_SR15;
-   SiS_CR40 = SiS310_CR40;
-   SiS_CR49 = SiS310_CR49;
-   pSiS_SR1F = &SiS310_SR1F;
-   pSiS_SR21 = &SiS310_SR21;
-   pSiS_SR22 = &SiS310_SR22;
-   pSiS_SR23 = &SiS310_SR23;
-   pSiS_SR24 = &SiS310_SR24;
-   SiS_SR25 = SiS310_SR25;
-   pSiS_SR31 = &SiS310_SR31;
-   pSiS_SR32 = &SiS310_SR32;
-   pSiS_SR33 = &SiS310_SR33;
-   pSiS_CRT2Data_1_2 = &SiS310_CRT2Data_1_2;
-   pSiS_CRT2Data_4_D = &SiS310_CRT2Data_4_D;
-   pSiS_CRT2Data_4_E = &SiS310_CRT2Data_4_E;
-   pSiS_CRT2Data_4_10 = &SiS310_CRT2Data_4_10;
-   pSiS_RGBSenseData = &SiS310_RGBSenseData;
-   pSiS_VideoSenseData = &SiS310_VideoSenseData;
-   pSiS_YCSenseData = &SiS310_YCSenseData;
-   pSiS_RGBSenseData2 = &SiS310_RGBSenseData2;
-   pSiS_VideoSenseData2 = &SiS310_VideoSenseData2;
-   pSiS_YCSenseData2 = &SiS310_YCSenseData2;
-   SiS_NTSCPhase = SiS310_NTSCPhase;
-   SiS_PALPhase = SiS310_PALPhase;
-   SiS_NTSCPhase2 = SiS310_NTSCPhase2;
-   SiS_PALPhase2 = SiS310_PALPhase2;
-   SiS_PALMPhase = SiS310_PALMPhase;  /*add for PALMN*/
-   SiS_PALNPhase = SiS310_PALNPhase;
-
-   SiS_StLCD1024x768Data = (SiS_LCDDataStruct *) SiS310_StLCD1024x768Data;
-   SiS_ExtLCD1024x768Data = (SiS_LCDDataStruct *) SiS310_ExtLCD1024x768Data;
-   SiS_St2LCD1024x768Data = (SiS_LCDDataStruct *) SiS310_St2LCD1024x768Data;
-   SiS_StLCD1280x1024Data = (SiS_LCDDataStruct *) SiS310_StLCD1280x1024Data;
-   SiS_ExtLCD1280x1024Data = (SiS_LCDDataStruct *) SiS310_ExtLCD1280x1024Data;
-   SiS_St2LCD1280x1024Data = (SiS_LCDDataStruct *) SiS310_St2LCD1280x1024Data;
-   SiS_NoScaleData = (SiS_LCDDataStruct *) SiS310_NoScaleData;
-   SiS_LCD1280x960Data = (SiS_LCDDataStruct *) SiS310_LCD1280x960Data;
-   SiS_StPALData = (SiS_TVDataStruct *) SiS310_StPALData;
-   SiS_ExtPALData = (SiS_TVDataStruct *) SiS310_ExtPALData;
-   SiS_StNTSCData = (SiS_TVDataStruct *) SiS310_StNTSCData;
-   SiS_ExtNTSCData = (SiS_TVDataStruct *) SiS310_ExtNTSCData;
-   SiS_St1HiTVData = (SiS_TVDataStruct *) SiS310_St1HiTVData;
-   SiS_St2HiTVData = (SiS_TVDataStruct *) SiS310_St2HiTVData;
-   SiS_ExtHiTVData = (SiS_TVDataStruct *) SiS310_ExtHiTVData;
-   SiS_NTSCTiming = SiS310_NTSCTiming;
-   SiS_PALTiming = SiS310_PALTiming;
-   SiS_HiTVSt1Timing = SiS310_HiTVSt1Timing;
-   SiS_HiTVSt2Timing = SiS310_HiTVSt2Timing;
-   SiS_HiTVTextTiming = SiS310_HiTVTextTiming;
-   SiS_HiTVGroup3Data = SiS310_HiTVGroup3Data;
-   SiS_HiTVGroup3Simu = SiS310_HiTVGroup3Simu;
-   SiS_HiTVGroup3Text = SiS310_HiTVGroup3Text;
-
-   SiS_PanelDelayTbl = (SiS_PanelDelayTblStruct *) SiS310_PanelDelayTbl;
-   SiS_LVDS320x480Data_1 = (SiS_LVDSDataStruct *) SiS310_LVDS320x480Data_1;
-   SiS_LVDS800x600Data_1 = (SiS_LVDSDataStruct *) SiS310_LVDS800x600Data_1;
-   SiS_LVDS800x600Data_2 = (SiS_LVDSDataStruct *) SiS310_LVDS800x600Data_2;
-   SiS_LVDS1024x768Data_1 = (SiS_LVDSDataStruct *) SiS310_LVDS1024x768Data_1;
-   SiS_LVDS1024x768Data_2 = (SiS_LVDSDataStruct *) SiS310_LVDS1024x768Data_2;
-   SiS_LVDS1280x1024Data_1 = (SiS_LVDSDataStruct *) SiS310_LVDS1280x1024Data_1;
-   SiS_LVDS1280x1024Data_2 = (SiS_LVDSDataStruct *) SiS310_LVDS1280x1024Data_2;
-   SiS_LVDS640x480Data_1 = (SiS_LVDSDataStruct *) SiS310_LVDS640x480Data_1;
-   SiS_CHTVUNTSCData = (SiS_LVDSDataStruct *) SiS310_CHTVUNTSCData;
-   SiS_CHTVONTSCData = (SiS_LVDSDataStruct *) SiS310_CHTVONTSCData;
-   SiS_CHTVUPALData = (SiS_LVDSDataStruct *) SiS310_CHTVUPALData;
-   SiS_CHTVOPALData = (SiS_LVDSDataStruct *) SiS310_CHTVOPALData;
-   SiS_PanelType00_1 = (SiS_LVDSDesStruct *) SiS310_PanelType00_1;
-   SiS_PanelType01_1 = (SiS_LVDSDesStruct *) SiS310_PanelType01_1;
-   SiS_PanelType02_1 = (SiS_LVDSDesStruct *) SiS310_PanelType02_1;
-   SiS_PanelType03_1 = (SiS_LVDSDesStruct *) SiS310_PanelType03_1;
-   SiS_PanelType04_1 = (SiS_LVDSDesStruct *) SiS310_PanelType04_1;
-   SiS_PanelType05_1 = (SiS_LVDSDesStruct *) SiS310_PanelType05_1;
-   SiS_PanelType06_1 = (SiS_LVDSDesStruct *) SiS310_PanelType06_1;
-   SiS_PanelType07_1 = (SiS_LVDSDesStruct *) SiS310_PanelType07_1;
-   SiS_PanelType08_1 = (SiS_LVDSDesStruct *) SiS310_PanelType08_1;
-   SiS_PanelType09_1 = (SiS_LVDSDesStruct *) SiS310_PanelType09_1;
-   SiS_PanelType0a_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0a_1;
-   SiS_PanelType0b_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0b_1;
-   SiS_PanelType0c_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0c_1;
-   SiS_PanelType0d_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0d_1;
-   SiS_PanelType0e_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0e_1;
-   SiS_PanelType0f_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0f_1;
-   SiS_PanelType00_2 = (SiS_LVDSDesStruct *) SiS310_PanelType00_2;
-   SiS_PanelType01_2 = (SiS_LVDSDesStruct *) SiS310_PanelType01_2;
-   SiS_PanelType02_2 = (SiS_LVDSDesStruct *) SiS310_PanelType02_2;
-   SiS_PanelType03_2 = (SiS_LVDSDesStruct *) SiS310_PanelType03_2;
-   SiS_PanelType04_2 = (SiS_LVDSDesStruct *) SiS310_PanelType04_2;
-   SiS_PanelType05_2 = (SiS_LVDSDesStruct *) SiS310_PanelType05_2;
-   SiS_PanelType06_2 = (SiS_LVDSDesStruct *) SiS310_PanelType06_2;
-   SiS_PanelType07_2 = (SiS_LVDSDesStruct *) SiS310_PanelType07_2;
-   SiS_PanelType08_2 = (SiS_LVDSDesStruct *) SiS310_PanelType08_2;
-   SiS_PanelType09_2 = (SiS_LVDSDesStruct *) SiS310_PanelType09_2;
-   SiS_PanelType0a_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0a_2;
-   SiS_PanelType0b_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0b_2;
-   SiS_PanelType0c_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0c_2;
-   SiS_PanelType0d_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0d_2;
-   SiS_PanelType0e_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0e_2;
-   SiS_PanelType0f_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0f_2;
-   /*301b*/
-   LVDS1024x768Des_1= (SiS_LVDSDesStruct *) SiS310_PanelType1076_1;
-   LVDS1280x1024Des_1= (SiS_LVDSDesStruct *)SiS310_PanelType1210_1;
-   LVDS1280x960Des_1= (SiS_LVDSDesStruct *)SiS310_PanelType1296_1 ;
-   LVDS1024x768Des_2= (SiS_LVDSDesStruct *) SiS310_PanelType1076_2;
-   LVDS1280x1024Des_2= (SiS_LVDSDesStruct *) SiS310_PanelType1210_2;
-   LVDS1280x960Des_2= (SiS_LVDSDesStruct *) SiS310_PanelType1296_2;
-   /*end 301b*/
-   
-   SiS_CHTVUNTSCDesData = (SiS_LVDSDesStruct *) SiS310_CHTVUNTSCDesData;
-   SiS_CHTVONTSCDesData = (SiS_LVDSDesStruct *) SiS310_CHTVONTSCDesData;
-   SiS_CHTVUPALDesData = (SiS_LVDSDesStruct *) SiS310_CHTVUPALDesData;
-   SiS_CHTVOPALDesData = (SiS_LVDSDesStruct *) SiS310_CHTVOPALDesData;
-   SiS_LVDSCRT1800x600_1 = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1800x600_1;
-   SiS_LVDSCRT11024x768_1 = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11024x768_1;
-   SiS_LVDSCRT11280x1024_1 = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11280x1024_1;
-   SiS_LVDSCRT1800x600_1_H = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1800x600_1_H;
-   SiS_LVDSCRT11024x768_1_H = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11024x768_1_H;
-   SiS_LVDSCRT11280x1024_1_H = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11280x1024_1_H;
-   SiS_LVDSCRT1800x600_2 = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1800x600_2;
-   SiS_LVDSCRT11024x768_2 = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11024x768_2;
-   SiS_LVDSCRT11280x1024_2 = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11280x1024_2;
-   SiS_LVDSCRT1800x600_2_H = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1800x600_2_H;
-   SiS_LVDSCRT11024x768_2_H = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11024x768_2_H;
-   SiS_LVDSCRT11280x1024_2_H = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11280x1024_2_H;
-   SiS_LVDSCRT1320x480_1 = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1320x480_1;   /*fstn*/
-   SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *) SiS310_CHTVCRT1UNTSC;
-   SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *) SiS310_CHTVCRT1ONTSC;
-   SiS_CHTVCRT1UPAL = (SiS_LVDSCRT1DataStruct *) SiS310_CHTVCRT1UPAL;
-   SiS_CHTVCRT1OPAL = (SiS_LVDSCRT1DataStruct *) SiS310_CHTVCRT1OPAL;
-   SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *) SiS310_CHTVReg_UNTSC;
-   SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *) SiS310_CHTVReg_ONTSC;
-   SiS_CHTVReg_UPAL = (SiS_CHTVRegDataStruct *) SiS310_CHTVReg_UPAL;
-   SiS_CHTVReg_OPAL = (SiS_CHTVRegDataStruct *) SiS310_CHTVReg_OPAL;
-   /*add for LCDA*/
-   SiS_LCDACRT1800x600_1 = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT1800x600_1;
-   SiS_LCDACRT11024x768_1 = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11024x768_1;
-   SiS_LCDACRT11280x1024_1 = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11280x1024_1;
-   SiS_LCDACRT1800x600_1_H = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT1800x600_1_H;
-   SiS_LCDACRT11024x768_1_H = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11024x768_1_H;
-   SiS_LCDACRT11280x1024_1_H = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11280x1024_1_H;
-   SiS_LCDACRT1800x600_2 = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT1800x600_2;
-   SiS_LCDACRT11024x768_2 = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11024x768_2;
-   SiS_LCDACRT11280x1024_2 = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11280x1024_2;
-   SiS_LCDACRT1800x600_2_H = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT1800x600_2_H;
-   SiS_LCDACRT11024x768_2_H = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11024x768_2_H;
-   SiS_LCDACRT11280x1024_2_H = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11280x1024_2_H;
-   /*end for 301b*/
-
-   SiS_CHTVVCLKUNTSC = SiS310_CHTVVCLKUNTSC;
-   SiS_CHTVVCLKONTSC = SiS310_CHTVVCLKONTSC;
-   SiS_CHTVVCLKUPAL = SiS310_CHTVVCLKUPAL;
-   SiS_CHTVVCLKOPAL = SiS310_CHTVVCLKOPAL;
-   /* 310 customization related */
+InitTo310Pointer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+   SiS_Pr->SiS_SModeIDTable  = (SiS_StStruct *)SiS310_SModeIDTable;
+   SiS_Pr->SiS_StandTable    = (SiS_StandTableStruct *)SiS310_StandTable;
+   SiS_Pr->SiS_EModeIDTable  = (SiS_ExtStruct *)SiS310_EModeIDTable;
+   SiS_Pr->SiS_RefIndex      = (SiS_Ext2Struct *)SiS310_RefIndex;
+   SiS_Pr->SiS_CRT1Table     = (SiS_CRT1TableStruct *)SiS310_CRT1Table;
+   /* TW: MCLK is different */
+   if(HwDeviceExtension->jChipType > SIS_315PRO) {
+      SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_650;  /* 550, 650 */
+   } else {
+      SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_315;  /* 315 */
+   }
+   SiS_Pr->SiS_MCLKData_1    = (SiS_MCLKDataStruct *)SiS310_MCLKData_1;
+   SiS_Pr->SiS_ECLKData      = (SiS_ECLKDataStruct *)SiS310_ECLKData;
+   SiS_Pr->SiS_VCLKData      = (SiS_VCLKDataStruct *)SiS310_VCLKData;
+   SiS_Pr->SiS_VBVCLKData    = (SiS_VBVCLKDataStruct *)SiS310_VBVCLKData;
+   SiS_Pr->SiS_ScreenOffset  = SiS310_ScreenOffset;
+   SiS_Pr->SiS_StResInfo     = (SiS_StResInfoStruct *)SiS310_StResInfo;
+   SiS_Pr->SiS_ModeResInfo   = (SiS_ModeResInfoStruct *)SiS310_ModeResInfo;
+
+   SiS_Pr->pSiS_OutputSelect = &SiS310_OutputSelect;
+   SiS_Pr->pSiS_SoftSetting  = &SiS310_SoftSetting;
+
+   SiS_Pr->SiS_SR15  = SiS310_SR15;
+
+#ifndef LINUX_XF86
+   SiS_Pr->pSiS_SR07 = &SiS310_SR07;
+   SiS_Pr->SiS_CR40  = SiS310_CR40;
+   SiS_Pr->SiS_CR49  = SiS310_CR49;
+   SiS_Pr->pSiS_SR1F = &SiS310_SR1F;
+   SiS_Pr->pSiS_SR21 = &SiS310_SR21;
+   SiS_Pr->pSiS_SR22 = &SiS310_SR22;
+   SiS_Pr->pSiS_SR23 = &SiS310_SR23;
+   SiS_Pr->pSiS_SR24 = &SiS310_SR24;
+   SiS_Pr->SiS_SR25  = SiS310_SR25;
+   SiS_Pr->pSiS_SR31 = &SiS310_SR31;
+   SiS_Pr->pSiS_SR32 = &SiS310_SR32;
+   SiS_Pr->pSiS_SR33 = &SiS310_SR33;
+   SiS_Pr->pSiS_CRT2Data_1_2  = &SiS310_CRT2Data_1_2;
+   SiS_Pr->pSiS_CRT2Data_4_D  = &SiS310_CRT2Data_4_D;
+   SiS_Pr->pSiS_CRT2Data_4_E  = &SiS310_CRT2Data_4_E;
+   SiS_Pr->pSiS_CRT2Data_4_10 = &SiS310_CRT2Data_4_10;
+   SiS_Pr->pSiS_RGBSenseData    = &SiS310_RGBSenseData;
+   SiS_Pr->pSiS_VideoSenseData  = &SiS310_VideoSenseData;
+   SiS_Pr->pSiS_YCSenseData     = &SiS310_YCSenseData;
+   SiS_Pr->pSiS_RGBSenseData2   = &SiS310_RGBSenseData2;
+   SiS_Pr->pSiS_VideoSenseData2 = &SiS310_VideoSenseData2;
+   SiS_Pr->pSiS_YCSenseData2    = &SiS310_YCSenseData2;
+#endif
+
+   SiS_Pr->SiS_NTSCPhase    = SiS310_NTSCPhase;
+   SiS_Pr->SiS_PALPhase     = SiS310_PALPhase;
+   SiS_Pr->SiS_NTSCPhase2   = SiS310_NTSCPhase2;
+   SiS_Pr->SiS_PALPhase2    = SiS310_PALPhase2;
+   SiS_Pr->SiS_PALMPhase    = SiS310_PALMPhase;
+   SiS_Pr->SiS_PALNPhase    = SiS310_PALNPhase;
+   SiS_Pr->SiS_PALMPhase2   = SiS310_PALMPhase2;
+   SiS_Pr->SiS_PALNPhase2   = SiS310_PALNPhase2;
+   SiS_Pr->SiS_SpecialPhase = SiS310_SpecialPhase;
+
+   SiS_Pr->SiS_StLCD1024x768Data    = (SiS_LCDDataStruct *)SiS310_StLCD1024x768Data;
+   SiS_Pr->SiS_ExtLCD1024x768Data   = (SiS_LCDDataStruct *)SiS310_ExtLCD1024x768Data;
+   SiS_Pr->SiS_St2LCD1024x768Data   = (SiS_LCDDataStruct *)SiS310_St2LCD1024x768Data;
+   SiS_Pr->SiS_StLCD1280x1024Data   = (SiS_LCDDataStruct *)SiS310_StLCD1280x1024Data;
+   SiS_Pr->SiS_ExtLCD1280x1024Data  = (SiS_LCDDataStruct *)SiS310_ExtLCD1280x1024Data;
+   SiS_Pr->SiS_St2LCD1280x1024Data  = (SiS_LCDDataStruct *)SiS310_St2LCD1280x1024Data;
+   SiS_Pr->SiS_NoScaleData1024x768  = (SiS_LCDDataStruct *)SiS310_NoScaleData1024x768;
+   SiS_Pr->SiS_NoScaleData1280x1024 = (SiS_LCDDataStruct *)SiS310_NoScaleData1280x1024;
+   SiS_Pr->SiS_LCD1280x960Data      = (SiS_LCDDataStruct *)SiS310_LCD1280x960Data;
+   SiS_Pr->SiS_ExtLCD1400x1050Data  = (SiS_LCDDataStruct *)SiS310_ExtLCD1400x1050Data;
+   SiS_Pr->SiS_ExtLCD1600x1200Data  = (SiS_LCDDataStruct *)SiS310_ExtLCD1600x1200Data;
+   SiS_Pr->SiS_StLCD1400x1050Data   = (SiS_LCDDataStruct *)SiS310_StLCD1400x1050Data;
+   SiS_Pr->SiS_StLCD1600x1200Data   = (SiS_LCDDataStruct *)SiS310_StLCD1600x1200Data;
+   SiS_Pr->SiS_NoScaleData1400x1050 = (SiS_LCDDataStruct *)SiS310_NoScaleData1400x1050;
+   SiS_Pr->SiS_NoScaleData1600x1200 = (SiS_LCDDataStruct *)SiS310_NoScaleData1600x1200;
+
+   SiS_Pr->SiS_StPALData   = (SiS_TVDataStruct *)SiS310_StPALData;
+   SiS_Pr->SiS_ExtPALData  = (SiS_TVDataStruct *)SiS310_ExtPALData;
+   SiS_Pr->SiS_StNTSCData  = (SiS_TVDataStruct *)SiS310_StNTSCData;
+   SiS_Pr->SiS_ExtNTSCData = (SiS_TVDataStruct *)SiS310_ExtNTSCData;
+#ifdef oldHV
+   SiS_Pr->SiS_St1HiTVData = (SiS_TVDataStruct *)SiS310_St1HiTVData;
+   SiS_Pr->SiS_St2HiTVData = (SiS_TVDataStruct *)SiS310_St2HiTVData;
+   SiS_Pr->SiS_ExtHiTVData = (SiS_TVDataStruct *)SiS310_ExtHiTVData;
+#endif
+
+   SiS_Pr->SiS_NTSCTiming     = SiS310_NTSCTiming;
+   SiS_Pr->SiS_PALTiming      = SiS310_PALTiming;
+#ifdef oldHV
+   SiS_Pr->SiS_HiTVSt1Timing  = SiS310_HiTVSt1Timing;
+   SiS_Pr->SiS_HiTVSt2Timing  = SiS310_HiTVSt2Timing;
+   SiS_Pr->SiS_HiTVTextTiming = SiS310_HiTVTextTiming;
+   SiS_Pr->SiS_HiTVExtTiming  = SiS310_HiTVExtTiming;
+   SiS_Pr->SiS_HiTVGroup3Data = SiS310_HiTVGroup3Data;
+   SiS_Pr->SiS_HiTVGroup3Simu = SiS310_HiTVGroup3Simu;
+   SiS_Pr->SiS_HiTVGroup3Text = SiS310_HiTVGroup3Text;
+#endif
+
+   SiS_Pr->SiS_PanelDelayTbl = (SiS_PanelDelayTblStruct *)SiS310_PanelDelayTbl;
+   SiS_Pr->SiS_PanelDelayTblLVDS = (SiS_PanelDelayTblStruct *)SiS310_PanelDelayTblLVDS;
+
+   SiS_Pr->SiS_LVDS800x600Data_1   = (SiS_LVDSDataStruct *)SiS310_LVDS800x600Data_1;
+   SiS_Pr->SiS_LVDS800x600Data_2   = (SiS_LVDSDataStruct *)SiS310_LVDS800x600Data_2;
+   SiS_Pr->SiS_LVDS1024x768Data_1  = (SiS_LVDSDataStruct *)SiS310_LVDS1024x768Data_1;
+   SiS_Pr->SiS_LVDS1024x768Data_2  = (SiS_LVDSDataStruct *)SiS310_LVDS1024x768Data_2;
+   SiS_Pr->SiS_LVDS1280x1024Data_1 = (SiS_LVDSDataStruct *)SiS310_LVDS1280x1024Data_1;
+   SiS_Pr->SiS_LVDS1280x1024Data_2 = (SiS_LVDSDataStruct *)SiS310_LVDS1280x1024Data_2;
+   SiS_Pr->SiS_LVDS1280x960Data_1  = (SiS_LVDSDataStruct *)SiS310_LVDS1280x960Data_1;
+   SiS_Pr->SiS_LVDS1280x960Data_2  = (SiS_LVDSDataStruct *)SiS310_LVDS1280x960Data_2;
+   SiS_Pr->SiS_LVDS1400x1050Data_1 = (SiS_LVDSDataStruct *)SiS310_LVDS1400x1050Data_1;
+   SiS_Pr->SiS_LVDS1400x1050Data_2 = (SiS_LVDSDataStruct *)SiS310_LVDS1400x1050Data_2;
+   SiS_Pr->SiS_LVDS1024x600Data_1  = (SiS_LVDSDataStruct *)SiS310_LVDS1024x600Data_1;
+   SiS_Pr->SiS_LVDS1024x600Data_2  = (SiS_LVDSDataStruct *)SiS310_LVDS1024x600Data_2;
+   SiS_Pr->SiS_LVDS1152x768Data_1  = (SiS_LVDSDataStruct *)SiS310_LVDS1152x768Data_1;
+   SiS_Pr->SiS_LVDS1152x768Data_2  = (SiS_LVDSDataStruct *)SiS310_LVDS1152x768Data_2;
+   SiS_Pr->SiS_LVDSXXXxXXXData_1   = (SiS_LVDSDataStruct *)SiS310_LVDSXXXxXXXData_1;
+   SiS_Pr->SiS_LVDS320x480Data_1   = (SiS_LVDSDataStruct *)SiS310_LVDS320x480Data_1;
+   SiS_Pr->SiS_LVDS640x480Data_1   = (SiS_LVDSDataStruct *)SiS310_LVDS640x480Data_1;
+   SiS_Pr->SiS_LCDA1400x1050Data_1  = (SiS_LVDSDataStruct *)SiS310_LCDA1400x1050Data_1;
+   SiS_Pr->SiS_LCDA1400x1050Data_2  = (SiS_LVDSDataStruct *)SiS310_LCDA1400x1050Data_2;
+   SiS_Pr->SiS_LCDA1600x1200Data_1  = (SiS_LVDSDataStruct *)SiS310_LCDA1600x1200Data_1;
+   SiS_Pr->SiS_LCDA1600x1200Data_2  = (SiS_LVDSDataStruct *)SiS310_LCDA1600x1200Data_2;
+   SiS_Pr->SiS_CHTVUNTSCData = (SiS_LVDSDataStruct *)SiS310_CHTVUNTSCData;
+   SiS_Pr->SiS_CHTVONTSCData = (SiS_LVDSDataStruct *)SiS310_CHTVONTSCData;
+   SiS_Pr->SiS_CHTVUPALData  = (SiS_LVDSDataStruct *)SiS310_CHTVUPALData;
+   SiS_Pr->SiS_CHTVOPALData  = (SiS_LVDSDataStruct *)SiS310_CHTVOPALData;
+   SiS_Pr->SiS_PanelType00_1 = (SiS_LVDSDesStruct *)SiS310_PanelType00_1;
+   SiS_Pr->SiS_PanelType01_1 = (SiS_LVDSDesStruct *)SiS310_PanelType01_1;
+   SiS_Pr->SiS_PanelType02_1 = (SiS_LVDSDesStruct *)SiS310_PanelType02_1;
+   SiS_Pr->SiS_PanelType03_1 = (SiS_LVDSDesStruct *)SiS310_PanelType03_1;
+   SiS_Pr->SiS_PanelType04_1 = (SiS_LVDSDesStruct *)SiS310_PanelType04_1;
+   SiS_Pr->SiS_PanelType05_1 = (SiS_LVDSDesStruct *)SiS310_PanelType05_1;
+   SiS_Pr->SiS_PanelType06_1 = (SiS_LVDSDesStruct *)SiS310_PanelType06_1;
+   SiS_Pr->SiS_PanelType07_1 = (SiS_LVDSDesStruct *)SiS310_PanelType07_1;
+   SiS_Pr->SiS_PanelType08_1 = (SiS_LVDSDesStruct *)SiS310_PanelType08_1;
+   SiS_Pr->SiS_PanelType09_1 = (SiS_LVDSDesStruct *)SiS310_PanelType09_1;
+   SiS_Pr->SiS_PanelType0a_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0a_1;
+   SiS_Pr->SiS_PanelType0b_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0b_1;
+   SiS_Pr->SiS_PanelType0c_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0c_1;
+   SiS_Pr->SiS_PanelType0d_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0d_1;
+   SiS_Pr->SiS_PanelType0e_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0e_1;
+   SiS_Pr->SiS_PanelType0f_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0f_1;
+   SiS_Pr->SiS_PanelType00_2 = (SiS_LVDSDesStruct *)SiS310_PanelType00_2;
+   SiS_Pr->SiS_PanelType01_2 = (SiS_LVDSDesStruct *)SiS310_PanelType01_2;
+   SiS_Pr->SiS_PanelType02_2 = (SiS_LVDSDesStruct *)SiS310_PanelType02_2;
+   SiS_Pr->SiS_PanelType03_2 = (SiS_LVDSDesStruct *)SiS310_PanelType03_2;
+   SiS_Pr->SiS_PanelType04_2 = (SiS_LVDSDesStruct *)SiS310_PanelType04_2;
+   SiS_Pr->SiS_PanelType05_2 = (SiS_LVDSDesStruct *)SiS310_PanelType05_2;
+   SiS_Pr->SiS_PanelType06_2 = (SiS_LVDSDesStruct *)SiS310_PanelType06_2;
+   SiS_Pr->SiS_PanelType07_2 = (SiS_LVDSDesStruct *)SiS310_PanelType07_2;
+   SiS_Pr->SiS_PanelType08_2 = (SiS_LVDSDesStruct *)SiS310_PanelType08_2;
+   SiS_Pr->SiS_PanelType09_2 = (SiS_LVDSDesStruct *)SiS310_PanelType09_2;
+   SiS_Pr->SiS_PanelType0a_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0a_2;
+   SiS_Pr->SiS_PanelType0b_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0b_2;
+   SiS_Pr->SiS_PanelType0c_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0c_2;
+   SiS_Pr->SiS_PanelType0d_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0d_2;
+   SiS_Pr->SiS_PanelType0e_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0e_2;
+   SiS_Pr->SiS_PanelType0f_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0f_2;
+
+   SiS_Pr->LVDS1024x768Des_1  = (SiS_LVDSDesStruct *)SiS310_PanelType1076_1;
+   SiS_Pr->LVDS1280x1024Des_1 = (SiS_LVDSDesStruct *)SiS310_PanelType1210_1;
+   SiS_Pr->LVDS1400x1050Des_1 = (SiS_LVDSDesStruct *)SiS310_PanelType1296_1 ;
+   SiS_Pr->LVDS1600x1200Des_1 = (SiS_LVDSDesStruct *)SiS310_PanelType1600_1 ;
+   SiS_Pr->LVDS1024x768Des_2  = (SiS_LVDSDesStruct *)SiS310_PanelType1076_2;
+   SiS_Pr->LVDS1280x1024Des_2 = (SiS_LVDSDesStruct *)SiS310_PanelType1210_2;
+   SiS_Pr->LVDS1400x1050Des_2 = (SiS_LVDSDesStruct *)SiS310_PanelType1296_2;
+   SiS_Pr->LVDS1600x1200Des_2 = (SiS_LVDSDesStruct *)SiS310_PanelType1600_2 ;
+
+   /* TW: New from 650/301LV BIOS */
+   SiS_Pr->SiS_CRT2Part2_1024x768_1  = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1024x768_1;
+   SiS_Pr->SiS_CRT2Part2_1280x1024_1 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1280x1024_1;
+   SiS_Pr->SiS_CRT2Part2_1400x1050_1 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1400x1050_1;
+   SiS_Pr->SiS_CRT2Part2_1600x1200_1 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1600x1200_1;
+   SiS_Pr->SiS_CRT2Part2_1024x768_2  = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1024x768_2;
+   SiS_Pr->SiS_CRT2Part2_1280x1024_2 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1280x1024_2;
+   SiS_Pr->SiS_CRT2Part2_1400x1050_2 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1400x1050_2;
+   SiS_Pr->SiS_CRT2Part2_1600x1200_2 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1600x1200_2;
+   SiS_Pr->SiS_CRT2Part2_1024x768_3  = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1024x768_3;
+   SiS_Pr->SiS_CRT2Part2_1280x1024_3 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1280x1024_3;
+   SiS_Pr->SiS_CRT2Part2_1400x1050_3 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1400x1050_3;
+   SiS_Pr->SiS_CRT2Part2_1600x1200_3 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1600x1200_3;
+
+   SiS_Pr->SiS_CHTVUNTSCDesData = (SiS_LVDSDesStruct *)SiS310_CHTVUNTSCDesData;
+   SiS_Pr->SiS_CHTVONTSCDesData = (SiS_LVDSDesStruct *)SiS310_CHTVONTSCDesData;
+   SiS_Pr->SiS_CHTVUPALDesData  = (SiS_LVDSDesStruct *)SiS310_CHTVUPALDesData;
+   SiS_Pr->SiS_CHTVOPALDesData  = (SiS_LVDSDesStruct *)SiS310_CHTVOPALDesData;
+
+   SiS_Pr->SiS_LVDSCRT1800x600_1     = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_1;
+   SiS_Pr->SiS_LVDSCRT11024x768_1    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_1;
+   SiS_Pr->SiS_LVDSCRT11280x1024_1   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_1;
+   SiS_Pr->SiS_LVDSCRT11400x1050_1   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_1;
+   SiS_Pr->SiS_LVDSCRT11024x600_1    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x600_1;
+   SiS_Pr->SiS_LVDSCRT11152x768_1    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11152x768_1;
+   SiS_Pr->SiS_LVDSCRT11600x1200_1   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_1;
+   SiS_Pr->SiS_LVDSCRT1800x600_1_H   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_1_H;
+   SiS_Pr->SiS_LVDSCRT11024x768_1_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_1_H;
+   SiS_Pr->SiS_LVDSCRT11280x1024_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_1_H;
+   SiS_Pr->SiS_LVDSCRT11400x1050_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_1_H;
+   SiS_Pr->SiS_LVDSCRT11024x600_1_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x600_1_H;
+   SiS_Pr->SiS_LVDSCRT11152x768_1_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11152x768_1_H;
+   SiS_Pr->SiS_LVDSCRT11600x1200_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_1_H;
+   SiS_Pr->SiS_LVDSCRT1800x600_2     = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_2;
+   SiS_Pr->SiS_LVDSCRT11024x768_2    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_2;
+   SiS_Pr->SiS_LVDSCRT11280x1024_2   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_2;
+   SiS_Pr->SiS_LVDSCRT11400x1050_2   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_2;
+   SiS_Pr->SiS_LVDSCRT11024x600_2    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x600_2;
+   SiS_Pr->SiS_LVDSCRT11152x768_2    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11152x768_2;
+   SiS_Pr->SiS_LVDSCRT11600x1200_2   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_2;
+   SiS_Pr->SiS_LVDSCRT1800x600_2_H   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_2_H;
+   SiS_Pr->SiS_LVDSCRT11024x768_2_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_2_H;
+   SiS_Pr->SiS_LVDSCRT11280x1024_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_2_H;
+   SiS_Pr->SiS_LVDSCRT11400x1050_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_2_H;
+   SiS_Pr->SiS_LVDSCRT11024x600_2_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x600_2_H;
+   SiS_Pr->SiS_LVDSCRT11152x768_2_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11152x768_2_H;
+   SiS_Pr->SiS_LVDSCRT11600x1200_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_2_H;
+   SiS_Pr->SiS_LVDSCRT1XXXxXXX_1     = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1XXXxXXX_1;
+   SiS_Pr->SiS_LVDSCRT1320x480_1     = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1320x480_1;
+   SiS_Pr->SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1UNTSC;
+   SiS_Pr->SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1ONTSC;
+   SiS_Pr->SiS_CHTVCRT1UPAL  = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1UPAL;
+   SiS_Pr->SiS_CHTVCRT1OPAL  = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1OPAL;
+   SiS_Pr->SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UNTSC;
+   SiS_Pr->SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_ONTSC;
+   SiS_Pr->SiS_CHTVReg_UPAL  = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UPAL;
+   SiS_Pr->SiS_CHTVReg_OPAL  = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_OPAL;
+   SiS_Pr->SiS_LCDACRT1800x600_1     = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT1800x600_1;
+   SiS_Pr->SiS_LCDACRT11024x768_1    = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_1;
+   SiS_Pr->SiS_LCDACRT11280x1024_1   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_1;
+   SiS_Pr->SiS_LCDACRT11400x1050_1   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_1;
+   SiS_Pr->SiS_LCDACRT11600x1200_1   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_1;
+   SiS_Pr->SiS_LCDACRT1800x600_1_H   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT1800x600_1_H;
+   SiS_Pr->SiS_LCDACRT11024x768_1_H  = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_1_H;
+   SiS_Pr->SiS_LCDACRT11280x1024_1_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_1_H;
+   SiS_Pr->SiS_LCDACRT11400x1050_1_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_1_H;
+   SiS_Pr->SiS_LCDACRT11600x1200_1_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_1_H;
+   SiS_Pr->SiS_LCDACRT1800x600_2     = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT1800x600_2;
+   SiS_Pr->SiS_LCDACRT11024x768_2    = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_2;
+   SiS_Pr->SiS_LCDACRT11280x1024_2   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_2;
+   SiS_Pr->SiS_LCDACRT11400x1050_2   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_2;
+   SiS_Pr->SiS_LCDACRT11600x1200_2   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_2;
+   SiS_Pr->SiS_LCDACRT1800x600_2_H   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT1800x600_2_H;
+   SiS_Pr->SiS_LCDACRT11024x768_2_H  = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_2_H;
+   SiS_Pr->SiS_LCDACRT11280x1024_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_2_H;
+   SiS_Pr->SiS_LCDACRT11400x1050_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_2_H;
+   SiS_Pr->SiS_LCDACRT11600x1200_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_2_H;
+   SiS_Pr->SiS_CHTVVCLKUNTSC = SiS310_CHTVVCLKUNTSC;
+   SiS_Pr->SiS_CHTVVCLKONTSC = SiS310_CHTVVCLKONTSC;
+   SiS_Pr->SiS_CHTVVCLKUPAL  = SiS310_CHTVVCLKUPAL;
+   SiS_Pr->SiS_CHTVVCLKOPAL  = SiS310_CHTVVCLKOPAL;
+
+   SiS_Pr->SiS_Panel320x480   = Panel_320x480;
+   SiS_Pr->SiS_Panel640x480   = Panel_640x480;
+   SiS_Pr->SiS_Panel800x600   = Panel_800x600;
+   SiS_Pr->SiS_Panel1024x768  = Panel_1024x768;
+   SiS_Pr->SiS_Panel1280x1024 = Panel_1280x1024;
+   SiS_Pr->SiS_Panel1280x960  = Panel_1280x960;
+   SiS_Pr->SiS_Panel1600x1200 = Panel_1600x1200;
+   SiS_Pr->SiS_Panel1400x1050 = Panel_1400x1050;
+   SiS_Pr->SiS_Panel1152x768  = Panel_1152x768;
+   SiS_Pr->SiS_Panel1152x864  = Panel_1152x864;
+   SiS_Pr->SiS_Panel1280x768  = Panel_1280x768;
+   SiS_Pr->SiS_Panel1024x600  = Panel_1024x600;
+   SiS_Pr->SiS_PanelMax       = Panel_320x480;    /* TW: highest value */
+   SiS_Pr->SiS_PanelMinLVDS   = Panel_800x600;    /* TW: lowest value LVDS/LCDA */
+   SiS_Pr->SiS_PanelMin301    = Panel_1024x768;   /* TW: lowest value 301 */
 }
 #endif
 
-#ifndef LINUX_XF86
+#ifdef LINUXBIOS
 /* -------------- SiSInit -----------------*/
+/* TW: I degraded this for LINUXBIOS only, because we
+ *     don't need this otherwise
+ */
 BOOLEAN
-SiSInit(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiSInit(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-   ULONG   ROMAddr  = (ULONG)HwDeviceExtension->pjVirtualRomBase;
+   UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
    ULONG   FBAddr   = (ULONG)HwDeviceExtension->pjVideoMemoryAddress;
    USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
-   UCHAR   i,temp=0;
+   UCHAR   i, temp=0;
    UCHAR   SR11;
 #ifdef LINUX_KERNEL
    UCHAR   temp1;
    ULONG   base;
 #endif
-   UCHAR   SR12=0,SR13=0,SR14=0,SR16=0,SR17=0,SR18=0,SR19=0,SR1A=0;
-
+   UCHAR   SR13=0, SR14=0, SR16=0
+   UCHAR   SR17=0, SR19=0, SR1A=0;
+#ifdef SIS300
+   UCHAR   SR18=0, SR12=0;
+#endif
 #ifdef SIS315H
-   UCHAR   CR37=0,CR38=0,CR79=0,CR7A=0,CR7B=0,CR7C=0;
-   UCHAR   SR1B=0,SR15=0;
-   PSIS_DSReg  pSR;
+   UCHAR   CR37=0, CR38=0, CR79=0,
+   UCHAR   CR7A=0, CR7B=0, CR7C=0;
+   UCHAR   SR1B=0, SR15=0;
+   PSIS_DSReg pSR;
    ULONG   Temp;
 #endif
    UCHAR   VBIOSVersion[5];
@@ -484,118 +650,115 @@
    if(FBAddr==0)    return (FALSE);
    if(BaseAddr==0)  return (FALSE);
 
-   SiS_SetReg3((USHORT)(BaseAddr+0x12),  0x67);  /* 3c2 <- 67 ,ynlai */
+   SiS_SetReg3((USHORT)(BaseAddr+0x12),  0x67);  /* Misc */
 
 #ifdef SIS315H
-   /*if(HwDeviceExtension->jChipType > SIS_315H)*/
    if(HwDeviceExtension->jChipType > SIS_315PRO) {
      if(!HwDeviceExtension->bIntegratedMMEnabled)
-     	return (FALSE);  /* alan  */
+     	return (FALSE);
    }
 #endif
 
    SiS_MemoryCopy(VBIOSVersion,HwDeviceExtension->szVBIOSVer,4);
-   VBIOSVersion[4]= 0x0;
-   /* 09/07/99 modify by domao */
+   VBIOSVersion[4]= 0x00;
 
+   SiSDetermineROMUsage(SiS_Pr, HwDeviceExtension, ROMAddr);
+
+   /* TW: Init pointers */
 #ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_315H)||
-      (HwDeviceExtension->jChipType == SIS_315PRO)||
-      (HwDeviceExtension->jChipType == SIS_550)||   /* 05/02/01 ynlai for 550 */
-      (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_650))    /* 09/03/01 chiawen for 650 */
-     InitTo310Pointer();
+   if((HwDeviceExtension->jChipType == SIS_315H) ||
+      (HwDeviceExtension->jChipType == SIS_315PRO) ||
+      (HwDeviceExtension->jChipType == SIS_550) ||
+      (HwDeviceExtension->jChipType == SIS_640) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
+      (HwDeviceExtension->jChipType == SIS_650))
+     InitTo310Pointer(SiS_Pr, HwDeviceExtension);
 #endif
 
 #ifdef SIS300
-   if ((HwDeviceExtension->jChipType == SIS_540)||
-       (HwDeviceExtension->jChipType == SIS_630)||
-       (HwDeviceExtension->jChipType == SIS_730)||
-       (HwDeviceExtension->jChipType == SIS_300))
-     InitTo300Pointer();
+   if((HwDeviceExtension->jChipType == SIS_540) ||
+      (HwDeviceExtension->jChipType == SIS_630) ||
+      (HwDeviceExtension->jChipType == SIS_730) ||
+      (HwDeviceExtension->jChipType == SIS_300))
+     InitTo300Pointer(SiS_Pr, HwDeviceExtension);
 #endif
 
-   /* TW: Set SiS Register globals */
-   SiSRegInit(BaseAddr);
+   /* TW: Set SiS Register definitions */
+   SiSRegInit(SiS_Pr, BaseAddr);
 
-   /* TW: Determine LVDS/CH7005/TRUMPION */
-   SiS_Set_LVDS_TRUMPION(HwDeviceExtension);
+   /* TW: Determine LVDS/CH70xx/TRUMPION */
+   SiS_Set_LVDS_TRUMPION(SiS_Pr, HwDeviceExtension);
 
-   SiS_SetReg1(SiS_P3c4,0x05,0x86);                     /* 1.Openkey - unlock registers */
+   /* TW: Unlock registers */
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
 
 #ifdef LINUX_KERNEL
 
-#ifdef SIS300                                         	/* add to set SR14*/
-   if((HwDeviceExtension->jChipType==SIS_540)||
-      (HwDeviceExtension->jChipType==SIS_630)||
+#ifdef SIS300                                         	/* Set SR14 */
+   if((HwDeviceExtension->jChipType==SIS_540) ||
+      (HwDeviceExtension->jChipType==SIS_630) ||
       (HwDeviceExtension->jChipType==SIS_730)) {
      base=0x80000060;
      OutPortLong(base,0xcf8);
-     temp1=InPortLong(0xcfc);
-     temp1=temp1>>(16+8+4);
-     temp1=temp1&(0x07);
-     temp1=temp1+1;
-     temp1=1<<temp1;
-     SR14=temp1-1;
-     base=0x80000064;
+     temp1 = InPortLong(0xcfc);
+     temp1 >>= (16+8+4);
+     temp1 &= 0x07;
+     temp1++;
+     temp1 = 1 << temp1;
+     SR14 = temp1 - 1;
+     base = 0x80000064;
      OutPortLong(base,0xcf8);
-     temp1=InPortLong(0xcfc);
-     temp1=temp1&(0x00000020);
-     if(temp1)
-      	SR14=(0x10000000)|SR14;
-     else
-      	SR14=(0x01000000)|SR14;
+     temp1 = InPortLong(0xcfc);
+     temp1 &= 0x00000020;
+     if(temp1) 	SR14 |= 0x80;
+     else      	SR14 |= 0x40;
    }
 #endif
 
-#ifdef SIS315H                                         /* add to set SR14*/
+#ifdef SIS315H                                          /* Set SR14 */
    if(HwDeviceExtension->jChipType==SIS_550) {
-     base=0x80000060;
+     base = 0x80000060;
      OutPortLong(base,0xcf8);
-     temp1=InPortLong(0xcfc);
-     temp1=temp1>>(16+8+4);
-     temp1=temp1&(0x07);
-     temp1=temp1+1;
-     temp1=1<<temp1;
-     SR14=temp1-1;
-     base=0x80000064;
+     temp1 = InPortLong(0xcfc);
+     temp1 >>= (16+8+4);
+     temp1 &= 0x07;
+     temp1++;
+     temp1 = 1 << temp1;
+     SR14 = temp1 - 1;
+     base = 0x80000064;
      OutPortLong(base,0xcf8);
-     temp1=InPortLong(0xcfc);
-     temp1=temp1&(0x00000020);
-     if(temp1)
-      SR14=(0x10000000)|SR14;
-     else
-      SR14=(0x01000000)|SR14;
+     temp1 = InPortLong(0xcfc);
+     temp1 &= 0x00000020;
+     if(temp1)  SR14 |= 0x80;
+     else       SR14 |= 0x40;
    }
 
-   if((HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_650)) {  /* 09/03/01 chiawen for 650 */
-     base=0x80000064;
+   if((HwDeviceExtension->jChipType == SIS_640) ||      /* Set SR14 */
+      (HwDeviceExtension->jChipType == SIS_740) ||
+      (HwDeviceExtension->jChipType == SIS_650)) {
+     base = 0x80000064;
      OutPortLong(base,0xcf8);
      temp1=InPortLong(0xcfc);
-     temp1=temp>>4;
-     temp1=temp1&(0x07);
-     if(temp1 > 2 ) {
+     temp1 >>= 4;
+     temp1 &= 0x07;
+     if(temp1 > 2) {
        temp = temp1;
        switch(temp) {
-        case 3: temp1=0x07;  break;
-        case 4: temp1=0x0F;  break;
-        case 5: temp1=0x1F;  break;
-        case 6: temp1=0x05;  break;
-        case 7: temp1=0x17;  break;
+        case 3: temp1 = 0x07;  break;
+        case 4: temp1 = 0x0F;  break;
+        case 5: temp1 = 0x1F;  break;
+        case 6: temp1 = 0x05;  break;
+        case 7: temp1 = 0x17;  break;
         case 8: break;
         case 9: break;
        }
      }
-     SR14=temp1;
-     base=0x8000007C;
+     SR14 = temp1;
+     base = 0x8000007C;
      OutPortLong(base,0xcf8);
-     temp1=InPortLong(0xcfc);
-     temp1=temp1&(0x00000020);
-     if(temp1)
-       SR14=(0x10000000)|SR14;
+     temp1 = InPortLong(0xcfc);
+     temp1 &= 0x00000020;
+     if(temp1)  SR14 |= 0x80;
    }
 #endif
 
@@ -605,25 +768,25 @@
    if((HwDeviceExtension->jChipType == SIS_540)||
       (HwDeviceExtension->jChipType == SIS_630)||
       (HwDeviceExtension->jChipType == SIS_730)) {
-     SR12 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x12);
-     SR13 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x13);
-     SR14 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x14);
-     SR16 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x16);
-     SR17 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x17);
-     SR18 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x18);
-     SR19 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x19);
-     SR1A = (UCHAR)SiS_GetReg1(SiS_P3c4,0x1A);
+     SR12 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x12);
+     SR13 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13);
+     SR14 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+     SR16 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
+     SR17 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17);
+     SR18 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x18);
+     SR19 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x19);
+     SR1A = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
    } else if(HwDeviceExtension->jChipType == SIS_300){
-     SR13 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x13);
-     SR14 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x14);
+     SR13 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13);
+     SR14 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
    }
 #endif
 #ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_550)||
-      (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_650)) {  /* 09/03/01 chiawen for 650 */
-     SR19 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x19);
+   if((HwDeviceExtension->jChipType == SIS_550) ||
+      (HwDeviceExtension->jChipType == SIS_640) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
+      (HwDeviceExtension->jChipType == SIS_650)) {
+     SR19 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x19);
      SR19 = (SR19)||0x01;  /* TW: ??? || ??? */
      if(SR19==0x00) {
      	SR13 = 0x22;
@@ -640,399 +803,411 @@
      	CR7B = 0x00;
      	CR7C = 0x00;
      } else {
-     	SR13 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x13);
-     	SR14 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x14);
-     	SR15 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x15);
-     	SR16 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x16);
-     	SR17 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x17);
-     	SR1A = (UCHAR)SiS_GetReg1(SiS_P3c4,0x1A);
-     	SR1B = (UCHAR)SiS_GetReg1(SiS_P3c4,0x1B);
-     	CR37 = 0x02;/*(UCHAR)SiS_GetReg1(SiS_P3d4,0x37);*/
-     	CR38 = (UCHAR)SiS_GetReg1(SiS_P3d4,0x38);
-     	CR79 = (UCHAR)SiS_GetReg1(SiS_P3d4,0x79);
-     	CR7A = (UCHAR)SiS_GetReg1(SiS_P3d4,0x7A);
-     	CR7B = (UCHAR)SiS_GetReg1(SiS_P3d4,0x7B);
-     	CR7C = (UCHAR)SiS_GetReg1(SiS_P3d4,0x7C);
+     	SR13 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13);
+     	SR14 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+     	SR15 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x15);
+     	SR16 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
+     	SR17 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17);
+     	SR1A = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
+     	SR1B = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1B);
+     	CR37 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);  /* TW: Was 0x02 - why? */
+     	CR38 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+     	CR79 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x79);
+     	CR7A = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x7A);
+     	CR7B = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x7B);
+     	CR7C = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x7C);
      }
    }
 #endif
 
-/* ResetExtReg begin: Reset extended registers */
-
-   for(i=0x06;i< 0x20;i++) SiS_SetReg1(SiS_P3c4,i,0);   /* 2.Reset Extended register */
-   for(i=0x21;i<=0x27;i++) SiS_SetReg1(SiS_P3c4,i,0);   /*   Reset Extended register */
-   for(i=0x31;i<=0x3D;i++) SiS_SetReg1(SiS_P3c4,i,0);
+   /* Reset extended registers */
+
+   for(i=0x06; i< 0x20; i++) SiS_SetReg1(SiS_Pr->SiS_P3c4,i,0);
+   for(i=0x21; i<=0x27; i++) SiS_SetReg1(SiS_Pr->SiS_P3c4,i,0);
+   for(i=0x31; i<=0x3D; i++) SiS_SetReg1(SiS_Pr->SiS_P3c4,i,0);
 
 #ifdef SIS300
-   if((HwDeviceExtension->jChipType == SIS_540)||
-      (HwDeviceExtension->jChipType == SIS_630)||
-      (HwDeviceExtension->jChipType == SIS_730)||
+   if((HwDeviceExtension->jChipType == SIS_540) ||
+      (HwDeviceExtension->jChipType == SIS_630) ||
+      (HwDeviceExtension->jChipType == SIS_730) ||
       (HwDeviceExtension->jChipType == SIS_300)) {
-     	for(i=0x38;i<=0x3F;i++) SiS_SetReg1(SiS_P3d4,i,0);
+     	for(i=0x38; i<=0x3F; i++) SiS_SetReg1(SiS_Pr->SiS_P3d4,i,0);
    }
 #endif
 
 #ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_315H)||
-      (HwDeviceExtension->jChipType == SIS_315PRO)||
-      (HwDeviceExtension->jChipType == SIS_550)||   /* 05/02/01 ynlai for 550 */
-      (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
+   if((HwDeviceExtension->jChipType == SIS_315H) ||
+      (HwDeviceExtension->jChipType == SIS_315PRO) ||
+      (HwDeviceExtension->jChipType == SIS_550) ||
+      (HwDeviceExtension->jChipType == SIS_640) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
       (HwDeviceExtension->jChipType == SIS_650)) {
-   	for(i=0x12;i<=0x1B;i++) SiS_SetReg1(SiS_P3c4,i,0);
-   	for(i=0x79;i<=0x7C;i++) SiS_SetReg1(SiS_P3d4,i,0);
+   	for(i=0x12; i<=0x1B; i++) SiS_SetReg1(SiS_Pr->SiS_P3c4,i,0);
+   	for(i=0x79; i<=0x7C; i++) SiS_SetReg1(SiS_Pr->SiS_P3d4,i,0);
    }
 #endif
-/* ResetExtReg end */
+
+   /* Restore Extended Registers */
 
 #ifdef SIS300
-   if((HwDeviceExtension->jChipType == SIS_540)||
-      (HwDeviceExtension->jChipType == SIS_630)||
+   if((HwDeviceExtension->jChipType == SIS_540) ||
+      (HwDeviceExtension->jChipType == SIS_630) ||
       (HwDeviceExtension->jChipType == SIS_730)) {
-     SiS_SetReg1(SiS_P3c4,0x12,SR12);
-     SiS_SetReg1(SiS_P3c4,0x13,SR13);
-     SiS_SetReg1(SiS_P3c4,0x14,SR14);
-     SiS_SetReg1(SiS_P3c4,0x16,SR16);
-     SiS_SetReg1(SiS_P3c4,0x17,SR17);
-     SiS_SetReg1(SiS_P3c4,0x18,SR18);
-     SiS_SetReg1(SiS_P3c4,0x19,SR19);
-     SiS_SetReg1(SiS_P3c4,0x1A,SR1A);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x12,SR12);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,SR16);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,SR17);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x18,SR18);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x19,SR19);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1A,SR1A);
    }
 #endif
 
 #ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_550)||
-      (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_650)) {  /* 09/03/01 chiawen for 650 */
-     SiS_SetReg1(SiS_P3c4,0x13,SR13);
-     SiS_SetReg1(SiS_P3c4,0x14,SR14);
-     SiS_SetReg1(SiS_P3c4,0x15,SR15);
-     SiS_SetReg1(SiS_P3c4,0x16,SR16);
-     SiS_SetReg1(SiS_P3c4,0x17,SR17);
-     SiS_SetReg1(SiS_P3c4,0x19,SR19);
-     SiS_SetReg1(SiS_P3c4,0x1A,SR1A);
-     SiS_SetReg1(SiS_P3c4,0x1B,SR1B);
-     SiS_SetReg1(SiS_P3d4,0x37,CR37);
-     SiS_SetReg1(SiS_P3d4,0x38,CR38);
-     SiS_SetReg1(SiS_P3d4,0x79,CR79);
-     SiS_SetReg1(SiS_P3d4,0x7A,CR7A);
-     SiS_SetReg1(SiS_P3d4,0x7B,CR7B);
-     SiS_SetReg1(SiS_P3d4,0x7C,CR7C);
+   if((HwDeviceExtension->jChipType == SIS_550) ||
+      (HwDeviceExtension->jChipType == SIS_640) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
+      (HwDeviceExtension->jChipType == SIS_650)) {
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x15,SR15);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,SR16);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,SR17);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x19,SR19);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1A,SR1A);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1B,SR1B);
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x37,CR37);
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x38,CR38);
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x79,CR79);
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x7A,CR7A);
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x7B,CR7B);
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x7C,CR7C);
    }
 #endif
 
 #ifdef SIS300
-   if((HwDeviceExtension->jChipType==SIS_540)||
-      (HwDeviceExtension->jChipType==SIS_630)||
+   if((HwDeviceExtension->jChipType==SIS_540) ||
+      (HwDeviceExtension->jChipType==SIS_630) ||
       (HwDeviceExtension->jChipType==SIS_730)) {
-     	temp=(UCHAR)SR1A;
+     	temp = (UCHAR)SR1A & 0x03;
    } else if(HwDeviceExtension->jChipType==SIS_300) {
         /* TW: Nothing */
-   } else
+   }
 #endif
-   {
-      	if((*pSiS_SoftSetting&SoftDRAMType)==0){
-          	temp=(UCHAR)SiS_GetReg1(SiS_P3c4,0x3A);
+#ifdef SIS315H
+   if((HwDeviceExtension->jChipType == SIS_315H )||
+      (HwDeviceExtension->jChipType == SIS_315PRO)) {
+      	if((*SiS_Pr->pSiS_SoftSetting & SoftDRAMType) == 0){
+          	temp = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3A) & 0x03;
+        }
+   }
+   if((HwDeviceExtension->jChipType == SIS_550) ||
+      (HwDeviceExtension->jChipType == SIS_640) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
+      (HwDeviceExtension->jChipType == SIS_650)) {
+        if((*SiS_Pr->pSiS_SoftSetting & SoftDRAMType) == 0){
+          	temp = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x07;
         }
    }
+#endif
 
-   SiS_RAMType=temp&0x03;
-   SiS_SetMemoryClock(ROMAddr);
+   SiS_Pr->SiS_RAMType = temp;
+   SiS_SetMemoryClock(SiS_Pr, ROMAddr, HwDeviceExtension);
 
-/* SetDefExt1Regs begin: Set default register contents */
+   /* Set default register contents */
 
-   SiS_SetReg1(SiS_P3c4,0x07,*pSiS_SR07); 		/* DAC speed */
-   if((HwDeviceExtension->jChipType != SIS_540)&&
-      (HwDeviceExtension->jChipType != SIS_630)&&
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x07,*SiS_Pr->pSiS_SR07); 		/* DAC speed */
+
+   if((HwDeviceExtension->jChipType != SIS_540) &&
+      (HwDeviceExtension->jChipType != SIS_630) &&
       (HwDeviceExtension->jChipType != SIS_730)){
      	for(i=0x15;i<0x1C;i++) {
-       		SiS_SetReg1(SiS_P3c4,i,SiS_SR15[i-0x15][SiS_RAMType]);
+       	    SiS_SetReg1(SiS_Pr->SiS_P3c4,i,SiS_Pr->SiS_SR15[i-0x15][SiS_Pr->SiS_RAMType]);
      	}
    }
 
 #ifdef SIS315H
-   if ((HwDeviceExtension->jChipType == SIS_315H )||
+   if ((HwDeviceExtension->jChipType == SIS_315H ) ||
        (HwDeviceExtension->jChipType == SIS_315PRO)) {
      	for(i=0x40;i<=0x44;i++) {
-       		SiS_SetReg1(SiS_P3d4,i,SiS_CR40[i-0x40][SiS_RAMType]);
+       	    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,SiS_Pr->SiS_CR40[i-0x40][SiS_Pr->SiS_RAMType]);
      	}
-     	SiS_SetReg1(SiS_P3d4,0x48,0x23);
-     	SiS_SetReg1(SiS_P3d4,0x49,SiS_CR49[0]);
-    	/* /SiS_SetReg1(SiS_P3c4,0x25,SiS_SR25[0]);  */
+     	SiS_SetReg1(SiS_Pr->SiS_P3d4,0x48,0x23);
+     	SiS_SetReg1(SiS_Pr->SiS_P3d4,0x49,SiS_Pr->SiS_CR49[0]);
+    /*  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x25,SiS_Pr->SiS_SR25[0]);  */
    }
 #endif
 
-   SiS_SetReg1(SiS_P3c4,0x1F,*pSiS_SR1F); 	/* DAC pedestal */
-   /*SiS_SetReg1(SiS_P3c4,0x20,0x20);*/
-   SiS_SetReg1(SiS_P3c4,0x20,0xA0); /* alan, 2001/6/26 Frame buffer can read/write*/
-   SiS_SetReg1(SiS_P3c4,0x23,*pSiS_SR23);
-   SiS_SetReg1(SiS_P3c4,0x24,*pSiS_SR24);
-   SiS_SetReg1(SiS_P3c4,0x25,SiS_SR25[0]);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1F,*SiS_Pr->pSiS_SR1F); 	/* DAC pedestal */
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x20,0xA0);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x23,*SiS_Pr->pSiS_SR23);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x24,*SiS_Pr->pSiS_SR24);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x25,SiS_Pr->SiS_SR25[0]);
 
 #ifdef SIS300
-   if(HwDeviceExtension->jChipType==SIS_300) {
-     	SiS_SetReg1(SiS_P3c4,0x21,0x84);
-     	SiS_SetReg1(SiS_P3c4,0x22,0x00);
+   if(HwDeviceExtension->jChipType == SIS_300) {
+     	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x21,0x84);
+     	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x22,0x00);
    }
 #endif
 
-   SR11=0x0F;
-   SiS_SetReg1(SiS_P3c4,0x11,SR11);	/* Power Management */
+   SR11 = 0x0F;
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x11,SR11);		/* Power Management & DDC port */
 
-   SiS_UnLockCRT2(HwDeviceExtension, BaseAddr);
-   SiS_SetReg1(SiS_Part1Port,0x00,0x00);
-   SiS_SetReg1(SiS_Part1Port,0x02,*pSiS_CRT2Data_1_2);
+   SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x00,0x00);
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x02,*SiS_Pr->pSiS_CRT2Data_1_2);
 
-#ifdef SIS315H                            /* 05/02/01 ynlai  for sis550 */
+#ifdef SIS315H
    if((HwDeviceExtension->jChipType == SIS_315H) ||
       (HwDeviceExtension->jChipType == SIS_315PRO) ||
-      (HwDeviceExtension->jChipType == SIS_550)||
-      (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_650))    /* 09/03/01 chiawen for 650 */
-     	SiS_SetReg1(SiS_Part1Port,0x2E,0x08); /* use VB */
+      (HwDeviceExtension->jChipType == SIS_550) ||
+      (HwDeviceExtension->jChipType == SIS_640) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
+      (HwDeviceExtension->jChipType == SIS_650))
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2E,0x08);    /* use VB */
 #endif
 
-   temp=*pSiS_SR32;
-   if(!SiS_BridgeIsOn(BaseAddr)) {
-     	temp=temp&0xEF;
+   temp = *SiS_Pr->pSiS_SR32;
+   if(SiS_BridgeIsOn(SiS_Pr, BaseAddr)) {
+     	temp &= 0xEF;
    }
-   SiS_SetReg1(SiS_P3c4,0x32,temp);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
 
 #ifdef SIS315H
-   if ((HwDeviceExtension->jChipType == SIS_315H) ||
-       (HwDeviceExtension->jChipType == SIS_315PRO)) {
-     HwDeviceExtension->pQueryVGAConfigSpace(HwDeviceExtension,0x50,0,&Temp);  /* Get */
+   if((HwDeviceExtension->jChipType == SIS_315H) ||
+      (HwDeviceExtension->jChipType == SIS_315PRO)) {
+     HwDeviceExtension->pQueryVGAConfigSpace(HwDeviceExtension,0x50,0,&Temp);
      Temp >>= 20;
      Temp &= 0xF;
-     if (Temp!=1) {
-     	SiS_SetReg1(SiS_P3c4,0x25,SiS_SR25[1]);
-     	SiS_SetReg1(SiS_P3d4,0x49,SiS_CR49[1]);
+     if (Temp != 1) {
+     	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x25,SiS_Pr->SiS_SR25[1]);
+     	SiS_SetReg1(SiS_Pr->SiS_P3d4,0x49,SiS_Pr->SiS_CR49[1]);
      }
 
-     SiS_SetReg1(SiS_P3c4,0x27,0x1F);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x27,0x1F);
 
-     SiS_SetReg1(SiS_P3c4,0x31,*pSiS_SR31);
-     SiS_SetReg1(SiS_P3c4,0x32,*pSiS_SR32);
-     SiS_SetReg1(SiS_P3c4,0x33,*pSiS_SR33);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,*SiS_Pr->pSiS_SR31);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,*SiS_Pr->pSiS_SR32);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x33,*SiS_Pr->pSiS_SR33);
    }
 #endif
 
-   if (SiS_BridgeIsOn(BaseAddr)==1) {
-     	if(SiS_IF_DEF_LVDS==0) {
-       		SiS_SetReg1(SiS_Part2Port,0x00,0x1C);
-       		SiS_SetReg1(SiS_Part4Port,0x0D,*pSiS_CRT2Data_4_D);
-       		SiS_SetReg1(SiS_Part4Port,0x0E,*pSiS_CRT2Data_4_E);
-       		SiS_SetReg1(SiS_Part4Port,0x10,*pSiS_CRT2Data_4_10);
-       		SiS_SetReg1(SiS_Part4Port,0x0F,0x3F);
+   if (SiS_BridgeIsOn(SiS_Pr, BaseAddr) == 0) {
+     	if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+       		SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x00,0x1C);
+       		SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0D,*SiS_Pr->pSiS_CRT2Data_4_D);
+       		SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0E,*SiS_Pr->pSiS_CRT2Data_4_E);
+       		SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x10,*SiS_Pr->pSiS_CRT2Data_4_10);
+       		SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0F,0x3F);
      	}
-     	SiS_LockCRT2(HwDeviceExtension, BaseAddr);
+     	SiS_LockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
    }
-   SiS_SetReg1(SiS_P3d4,0x83,0x00);
-/*   SetDefExt1Regs end */
+   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x83,0x00);
 
 #ifdef SIS315H
-   if ((HwDeviceExtension->jChipType==SIS_315H)||
-       (HwDeviceExtension->jChipType==SIS_315PRO)) { /* 05/02/01 ynlai */
+   if ((HwDeviceExtension->jChipType==SIS_315H) ||
+       (HwDeviceExtension->jChipType==SIS_315PRO)) {
        	if (HwDeviceExtension->bSkipDramSizing==TRUE) {
-         	SiS_SetDRAMModeRegister(ROMAddr);
+         	SiS_SetDRAMModeRegister(SiS_Pr, ROMAddr,HwDeviceExtension);
          	pSR = HwDeviceExtension->pSR;
          	if (pSR!=NULL) {
            		while (pSR->jIdx!=0xFF) {
-             			SiS_SetReg1(SiS_P3c4,pSR->jIdx,pSR->jVal);
+             			SiS_SetReg1(SiS_Pr->SiS_P3c4,pSR->jIdx,pSR->jVal);
              			pSR++;
            		}
          	}
-       } else SiS_SetDRAMSize_310(HwDeviceExtension);
+       } else SiS_SetDRAMSize_310(SiS_Pr, HwDeviceExtension);
    }
 #endif
 
 #ifdef SIS315H
-   if((HwDeviceExtension->jChipType==SIS_550)){ /* 05/02/01 ynlai For SiS 550 */
+   if((HwDeviceExtension->jChipType==SIS_550)){
        /* SetDRAMConfig begin */
-/*     SiS_SetReg1(SiS_P3c4,0x12,SR12);
-       SiS_SetReg1(SiS_P3c4,0x13,SR13);
-       SiS_SetReg1(SiS_P3c4,0x14,SR14);
-       SiS_SetReg1(SiS_P3c4,0x16,SR16);
-       SiS_SetReg1(SiS_P3c4,0x17,SR17);
-       SiS_SetReg1(SiS_P3c4,0x18,SR18);
-       SiS_SetReg1(SiS_P3c4,0x19,SR19);
-       SiS_SetReg1(SiS_P3c4,0x1A,SR1A);   */
+/*     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x12,SR12);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,SR16);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,SR17);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x18,SR18);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x19,SR19);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1A,SR1A);   */
        /* SetDRAMConfig end */
    }
 #endif
 
 #ifdef SIS300
-   if( HwDeviceExtension->jChipType==SIS_300) {       /* For SiS 300 Chip  */
-       	if (HwDeviceExtension->bSkipDramSizing==TRUE) {
-/*       	SiS_SetDRAMModeRegister(ROMAddr);
+   if(HwDeviceExtension->jChipType == SIS_300) {
+       	if (HwDeviceExtension->bSkipDramSizing == TRUE) {
+/*       	SiS_SetDRAMModeRegister(ROMAddr,HwDeviceExtension);
          	temp = (HwDeviceExtension->pSR)->jVal;
-         	SiS_SetReg1(SiS_P3c4,0x13,temp);
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,temp);
          	temp = (HwDeviceExtension->pSR)->jVal;
-         	SiS_SetReg1(SiS_P3c4,0x14,temp);   */
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,temp);   */
        } else {
 #ifdef TC
-         	SiS_SetReg1(SiS_P3c4,0x13,SR13);
-         	SiS_SetReg1(SiS_P3c4,0x14,SR14);
-         	SiS_SetRegANDOR(SiS_P3c4,0x15,0xFF,0x04);
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
+         	SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x15,0xFF,0x04);
 #else
-         	SiS_SetDRAMSize_300(HwDeviceExtension);
-         	SiS_SetDRAMSize_300(HwDeviceExtension);
+         	SiS_SetDRAMSize_300(SiS_Pr, HwDeviceExtension);
+         	SiS_SetDRAMSize_300(SiS_Pr, HwDeviceExtension);
 #endif
        }
    }
-   if((HwDeviceExtension->jChipType==SIS_540)||       /* For SiS 630/540/730 Chip  */
+   if((HwDeviceExtension->jChipType==SIS_540)||
       (HwDeviceExtension->jChipType==SIS_630)||
-      (HwDeviceExtension->jChipType==SIS_730)){
-       	/* SetDRAMConfig begin */
+      (HwDeviceExtension->jChipType==SIS_730)) {
 #if 0
-     	SiS_SetReg1(SiS_P3c4,0x12,SR12);
-       	SiS_SetReg1(SiS_P3c4,0x13,SR13);
-       	SiS_SetReg1(SiS_P3c4,0x14,SR14);
-       	SiS_SetReg1(SiS_P3c4,0x16,SR16);
-       	SiS_SetReg1(SiS_P3c4,0x17,SR17);
-       	SiS_SetReg1(SiS_P3c4,0x18,SR18);
-       	SiS_SetReg1(SiS_P3c4,0x19,SR19);
-       	SiS_SetReg1(SiS_P3c4,0x1A,SR1A);
+     	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x12,SR12);
+       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
+       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
+       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,SR16);
+       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,SR17);
+       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x18,SR18);
+       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x19,SR19);
+       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1A,SR1A);
 #endif
-       	/* SetDRAMConfig end */
    }
 /* SetDRAMSize end */
 #endif /* SIS300 */
 
-/*   SetDefExt2Regs begin  */
+   /* Set default Ext2Regs */
 #if 0
    AGP=1;
-   temp=(UCHAR)SiS_GetReg1(SiS_P3c4,0x3A);
-   temp=temp&0x30;
-   if(temp==0x30) AGP=0;
-   if(AGP==0) *pSiS_SR21=*pSiS_SR21&0xEF;
-   SiS_SetReg1(SiS_P3c4,0x21,*pSiS_SR21);
-   if(AGP==1) *pSiS_SR22=*pSiS_SR22&0x20;
-   SiS_SetReg1(SiS_P3c4,0x22,*pSiS_SR22);
-#endif
-   SiS_SetReg1(SiS_P3c4,0x21,*pSiS_SR21);
-   SiS_SetReg1(SiS_P3c4,0x22,*pSiS_SR22);
-/*   SetDefExt2Regs end  */
+   temp=(UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3A);
+   temp &= 0x30;
+   if(temp == 0x30) AGP=0;
+   if(AGP == 0) *SiS_Pr->pSiS_SR21 &= 0xEF;
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x21,*SiS_Pr->pSiS_SR21);
+   if(AGP == 1) *SiS_Pr->pSiS_SR22 &= 0x20;
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x22,*SiS_Pr->pSiS_SR22);
+#endif
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x21,*SiS_Pr->pSiS_SR21);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x22,*SiS_Pr->pSiS_SR22);
 
 #if 0
-   SiS_SetReg3(SiS_P3c6,0xff);
-   SiS_ClearDAC(SiS_P3c8);        /* [ynlai] 05/22/01 */
+   SiS_SetReg3(SiS_Pr->SiS_P3c6,0xff);
+   SiS_ClearDAC(SiS_Pr, SiS_Pr->SiS_P3c8);
 #endif
 
-   SiS_DetectMonitor(HwDeviceExtension,BaseAddr);
-   SiS_GetSenseStatus(HwDeviceExtension,ROMAddr);      /* sense CRT2 */
+#ifdef LINUXBIOS   /* TW: This is not needed for our purposes */
+   SiS_DetectMonitor(SiS_Pr, HwDeviceExtension,BaseAddr);    /* Sense CRT1 */
+   SiS_GetSenseStatus(SiS_Pr, HwDeviceExtension,ROMAddr);    /* Sense CRT2 */
+#endif
 
    return(TRUE);
 }
 
 void
-SiS_Set_LVDS_TRUMPION(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_Set_LVDS_TRUMPION(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT temp=0;
+  USHORT temp = 0;
 
 #ifdef SiS300
-  if ((HwDeviceExtension->jChipType == SIS_540)||
-      (HwDeviceExtension->jChipType == SIS_630)||
-      (HwDeviceExtension->jChipType == SIS_730)) {
+  if((HwDeviceExtension->jChipType == SIS_540) ||
+     (HwDeviceExtension->jChipType == SIS_630) ||
+     (HwDeviceExtension->jChipType == SIS_730)) {
         /* TW: Read POWER_ON_TRAP and copy to CR37 */
-    	temp = (UCHAR)SiS_GetReg1(SiS_P3c4,0x1A);
-    	temp=(temp&0xE0)>>4;
-   	SiS_SetRegANDOR(SiS_P3d4,0x37,0xF1,temp);
-   }
+    	temp = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
+    	temp = (temp & 0xE0) >> 4;
+   	SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,0xF1,temp);
+  }
+#endif
+#ifdef SIS315H
+  if((HwDeviceExtension->jChipType == SIS_640) ||
+     (HwDeviceExtension->jChipType == SIS_740) ||
+     (HwDeviceExtension->jChipType == SIS_650)) {
+#if 0 /* TW: This is not required */
+        /* TW: Read POWER_ON_TRAP and copy to CR37 */
+    	temp = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
+    	temp = (temp & 0xE0) >> 4;
+   	SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,0xF1,temp);
+#endif
+  }
 #endif
 
-   /* Set globals SiS_IF_DEF... */
-   SiSSetLVDSetc(HwDeviceExtension, 0);
+   SiSSetLVDSetc(SiS_Pr, HwDeviceExtension, 0);
 }
 
-/* ===============  for 300 dram sizing begin  =============== */
+/* ===============  SiS 300 dram sizing begin  =============== */
 #ifdef SIS300
 void
-SiS_SetDRAMSize_300(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_SetDRAMSize_300(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-   /*ULONG   ROMAddr  = (ULONG)HwDeviceExtension->pjVirtualRomBase;*/
-   ULONG   FBAddr   = (ULONG)HwDeviceExtension->pjVideoMemoryAddress;
-   /*USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;*/
-   USHORT  SR13,SR14=0,buswidth,Done;
-   SHORT   i,j,k;
+   ULONG   FBAddr = (ULONG)HwDeviceExtension->pjVideoMemoryAddress;
+   USHORT  SR13, SR14=0, buswidth, Done;
+   SHORT   i, j, k;
    USHORT  data, TotalCapacity, PhysicalAdrOtherPage=0;
    ULONG   Addr;
    UCHAR   temp;
-
-   int PseudoRankCapacity,PseudoTotalCapacity,PseudoAdrPinCount;
-   int RankCapacity,AdrPinCount,BankNumHigh,BankNumMid,MB2Bank;
-   /*int PageCapacity,PhysicalAdrHigh,PhysicalAdrHalfPage,PhysicalAdrAnotherPage;*/
-   int PageCapacity,PhysicalAdrHigh,PhysicalAdrHalfPage;
-
-   SiSSetMode(HwDeviceExtension,0x2e);
-
-   data=SiS_GetReg1(SiS_P3c4,0x1);
-   data=data|0x20;
-   SiS_SetReg1(SiS_P3c4,0x01,data);                    /* Turn OFF Display  */
-
-   SiS_SetReg1(SiS_P3c4,0x13,0x00);
-   SiS_SetReg1(SiS_P3c4,0x14,0xBF);
-   buswidth=SiS_ChkBUSWidth_300(FBAddr);
-
-   MB2Bank=16;
-   Done=0;
-   for(i=6;i>=0;i--) {
-      if(Done==1) break;
-      PseudoRankCapacity=1<<i;
-      for(j=4;j>=1;j--) {
-         if(Done==1) break;
-         PseudoTotalCapacity=PseudoRankCapacity*j;
-         PseudoAdrPinCount=15-j;
+   int     PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount;
+   int     RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank;
+   int     PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage;
+
+   SiSSetMode(SiS_Pr, HwDeviceExtension, 0x2e);
+
+   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x20);        /* Turn OFF Display  */
+
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,0x00);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0xBF);
+
+   buswidth = SiS_ChkBUSWidth_300(SiS_Pr, FBAddr);
+
+   MB2Bank = 16;
+   Done = 0;
+   for(i=6; i>=0; i--) {
+      if(Done == 1) break;
+      PseudoRankCapacity = 1 << i;
+      for(j=4; j>=1; j--) {
+         if(Done == 1) break;
+         PseudoTotalCapacity = PseudoRankCapacity * j;
+         PseudoAdrPinCount = 15 - j;
          if(PseudoTotalCapacity <= 64) {
-            for(k=0;k<=16;k++) {
-               if(Done==1) break;
-               RankCapacity=buswidth*SiS_DRAMType[k][3];
-               AdrPinCount=SiS_DRAMType[k][2]+SiS_DRAMType[k][0];
-               if(RankCapacity==PseudoRankCapacity)
-                 if(AdrPinCount<=PseudoAdrPinCount) {
-                    if(j==3) {             /* Rank No */
-                       BankNumHigh=RankCapacity*MB2Bank*3-1;
-                       BankNumMid=RankCapacity*MB2Bank*1-1;
+            for(k=0; k<=16; k++) {
+               if(Done == 1) break;
+               RankCapacity = buswidth * SiS_DRAMType[k][3];
+               AdrPinCount = SiS_DRAMType[k][2] + SiS_DRAMType[k][0];
+               if(RankCapacity == PseudoRankCapacity)
+                 if(AdrPinCount <= PseudoAdrPinCount) {
+                    if(j == 3) {             /* Rank No */
+                       BankNumHigh = RankCapacity * MB2Bank * 3 - 1;
+                       BankNumMid = RankCapacity * MB2Bank * 1 - 1;
+                    } else {
+                       BankNumHigh = RankCapacity * MB2Bank * j - 1;
+                       BankNumMid = RankCapacity * MB2Bank * j / 2 - 1;
                     }
-                    else {
-                       BankNumHigh=RankCapacity*MB2Bank*j-1;
-                       BankNumMid=RankCapacity*MB2Bank*j/2-1;
-                    }
-                    PageCapacity=(1<<SiS_DRAMType[k][1])*buswidth*4;
-                    PhysicalAdrHigh =BankNumHigh;
-                    PhysicalAdrHalfPage=(PageCapacity/2+PhysicalAdrHigh)%PageCapacity;
-                    PhysicalAdrOtherPage=PageCapacity*SiS_DRAMType[k][2]+PhysicalAdrHigh;
+                    PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
+                    PhysicalAdrHigh = BankNumHigh;
+                    PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
+                    PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
                     /* Write data */
-                    /*Test */
-                    temp=(UCHAR)SiS_GetReg1(SiS_P3c4,0x15);
-                    SiS_SetReg1(SiS_P3c4,0x15,(USHORT)(temp&0xFB));
-
-                    temp=(UCHAR)SiS_GetReg1(SiS_P3c4,0x15);
-                    SiS_SetReg1(SiS_P3c4,0x15,(USHORT)(temp|0x04));
-                    /*Test */
-                    TotalCapacity=SiS_DRAMType[k][3]*buswidth;
-                    SR13=SiS_DRAMType[k][4];
-                    if(buswidth==4) SR14=(TotalCapacity-1)|0x80;
-                    if(buswidth==2) SR14=(TotalCapacity-1)|0x40;
-                    if(buswidth==1) SR14=(TotalCapacity-1)|0x00;
-                    SiS_SetReg1(SiS_P3c4,0x13,SR13);
-                    SiS_SetReg1(SiS_P3c4,0x14,SR14);
-
-                    Addr=FBAddr+(BankNumHigh)*64*1024+PhysicalAdrHigh;
-                    *((USHORT *)(Addr)) = (USHORT) PhysicalAdrHigh;
-                    Addr=FBAddr+(BankNumMid)*64*1024+PhysicalAdrHigh;
-                    *((USHORT *)(Addr)) = (USHORT) BankNumMid;
-                    Addr=FBAddr+(BankNumHigh)*64*1024+PhysicalAdrHalfPage;
-                    *((USHORT *)(Addr)) = (USHORT) PhysicalAdrHalfPage;
-                    Addr=FBAddr+(BankNumHigh)*64*1024+PhysicalAdrOtherPage;
-                    *((USHORT *)(Addr))=PhysicalAdrOtherPage;
+                    /*Test*/
+                    SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x15,0xFB);
+                    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x15,0x04);
+                    /*/Test*/
+                    TotalCapacity = SiS_DRAMType[k][3] * buswidth;
+                    SR13 = SiS_DRAMType[k][4];
+                    if(buswidth == 4) SR14 = (TotalCapacity - 1) | 0x80;
+                    if(buswidth == 2) SR14 = (TotalCapacity - 1) | 0x40;
+                    if(buswidth == 1) SR14 = (TotalCapacity - 1) | 0x00;
+                    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
+                    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
+
+                    Addr = FBAddr + (BankNumHigh) * 64 * 1024 + PhysicalAdrHigh;
+                    *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh;
+                    Addr = FBAddr + (BankNumMid) * 64 * 1024 + PhysicalAdrHigh;
+                    *((USHORT *)(Addr)) = (USHORT)BankNumMid;
+                    Addr = FBAddr + (BankNumHigh) * 64 * 1024 + PhysicalAdrHalfPage;
+                    *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage;
+                    Addr = FBAddr + (BankNumHigh) * 64 * 1024 + PhysicalAdrOtherPage;
+                    *((USHORT *)(Addr)) = PhysicalAdrOtherPage;
 
                     /* Read data */
-                    Addr=FBAddr+(BankNumHigh)*64*1024+PhysicalAdrHigh;
-                    data=*((USHORT *)(Addr));
-                    if(data==PhysicalAdrHigh) Done=1;
+                    Addr = FBAddr + (BankNumHigh) * 64 * 1024 + PhysicalAdrHigh;
+                    data = *((USHORT *)(Addr));
+                    if(data == PhysicalAdrHigh) Done = 1;
                  }  /* if struct */
             }  /* for loop (k) */
          }  /* if struct */
@@ -1041,168 +1216,149 @@
 }
 
 USHORT
-SiS_ChkBUSWidth_300(ULONG FBAddress)
+SiS_ChkBUSWidth_300(SiS_Private *SiS_Pr, ULONG FBAddress)
 {
-   /*USHORT  data;*/
    PULONG  pVideoMemory;
 
-   pVideoMemory = (PULONG) FBAddress;
+   pVideoMemory = (PULONG)FBAddress;
 
    pVideoMemory[0] = 0x01234567L;
    pVideoMemory[1] = 0x456789ABL;
    pVideoMemory[2] = 0x89ABCDEFL;
    pVideoMemory[3] = 0xCDEF0123L;
-   if (pVideoMemory[3]==0xCDEF0123L) { /*ChannelA128Bit */
+   if (pVideoMemory[3]==0xCDEF0123L) {  /* Channel A 128bit */
      return(4);
    }
-   if (pVideoMemory[1]==0x456789ABL) {  /*ChannelB64Bit */
+   if (pVideoMemory[1]==0x456789ABL) {  /* Channel B 64bit */
      return(2);
    }
    return(1);
 }
 #endif
+/* ===============  SiS 300 dram sizing end    =============== */
 
-/* ===============  for 300 dram sizing end    =============== */
-
-/* ===============  310 dram sizing begin ==================== */
+/* ============  SiS 310/325 dram sizing begin  ============== */
 #ifdef SIS315H
 
 /* TW: Moved Get310DRAMType further down */
 
 void
-SiS_Delay15us(ULONG ulMicrsoSec)
+SiS_Delay15us(SiS_Private *SiS_Pr, ULONG ulMicrsoSec)
 {
 }
 
 void
-SiS_SDR_MRS(void)
+SiS_SDR_MRS(SiS_Private *SiS_Pr, )
 {
    USHORT  data;
 
-   data=SiS_GetReg1(SiS_P3c4,0x16);
-   data=data & 0x3F;          /*/ SR16 D7=0,D6=0 */
-   SiS_SetReg1(SiS_P3c4,0x16,data);   /*/ enable mode register set(MRS) low */
-   SiS_Delay15us(0x100);
-   data=data | 0x80;          /*/ SR16 D7=1,D6=0 */
-   SiS_SetReg1(SiS_P3c4,0x16,data);   /*/ enable mode register set(MRS) high */
-   SiS_Delay15us(0x100);
+   data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
+   data &= 0x3F;          		        /* SR16 D7=0, D6=0 */
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);   	/* enable mode register set(MRS) low */
+   SiS_Delay15us(SiS_Pr, 0x100);
+   data |= 0x80;          		        /* SR16 D7=1, D6=0 */
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);   	/* enable mode register set(MRS) high */
+   SiS_Delay15us(SiS_Pr, 0x100);
 }
 
 void
-SiS_DDR_MRS(void)
+SiS_DDR_MRS(SiS_Private *SiS_Pr)
 {
    USHORT  data;
 
    /* SR16 <- 1F,DF,2F,AF */
 
    /* enable DLL of DDR SD/SGRAM , SR16 D4=1 */
-   data=SiS_GetReg1(SiS_P3c4,0x16);
+   data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
    data &= 0x0F;
    data |= 0x10;
-   SiS_SetReg1(SiS_P3c4,0x16,data);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);
 
-   if (!(SiS_SR15[1][SiS_RAMType] & 0x10))
-   {
+   if (!(SiS_Pr->SiS_SR15[1][SiS_Pr->SiS_RAMType] & 0x10))
      data &= 0x0F;
-   }
+
    /* SR16 D7=1,D6=1 */
    data |= 0xC0;
-   SiS_SetReg1(SiS_P3c4,0x16,data);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);
    
    /* SR16 D7=1,D6=0,D5=1,D4=0 */
    data &= 0x0F;
    data |= 0x20;
-   SiS_SetReg1(SiS_P3c4,0x16,data);
-   if (!(SiS_SR15[1][SiS_RAMType] & 0x10)) {
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);
+   if (!(SiS_Pr->SiS_SR15[1][SiS_Pr->SiS_RAMType] & 0x10))
      data &= 0x0F;
-   }
+
    /* SR16 D7=1 */
    data |= 0x80;
-   SiS_SetReg1(SiS_P3c4,0x16,data);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);
 }
 
 void
-SiS_SetDRAMModeRegister(ULONG ROMAddr)
+SiS_SetDRAMModeRegister(SiS_Private *SiS_Pr, UCHAR *ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-
-    if (SiS_Get310DRAMType(ROMAddr)<2) {
-      SiS_SDR_MRS();
-    } else {
-      /* SR16 <- 0F,CF,0F,8F */
-      SiS_DDR_MRS();
-    }
+    if (SiS_Get310DRAMType(ROMAddr,HwDeviceExtension) < 2)
+        SiS_SDR_MRS(SiS_Pr);
+    else
+        /* SR16 <- 0F,CF,0F,8F */
+        SiS_DDR_MRS(SiS_Pr);
 }
 
 void
-SiS_DisableRefresh(void)
+SiS_DisableRefresh(SiS_Private *SiS_Pr)
 {
-   USHORT  data;
-
-   data=SiS_GetReg1(SiS_P3c4,0x17);
-   data &= 0xF8;
-   SiS_SetReg1(SiS_P3c4,0x17,data);
-
-   data=SiS_GetReg1(SiS_P3c4,0x19);
-   data |= 0x03;
-   SiS_SetReg1(SiS_P3c4,0x19,data);
-
+   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x17,0xF8);
+   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x19,0x03);
 }
 
 void
-SiS_EnableRefresh(ULONG ROMAddr)
+SiS_EnableRefresh(SiS_Private *SiS_Pr, UCHAR *ROMAddr)
 {
-   SiS_SetReg1(SiS_P3c4,0x17,SiS_SR15[2][SiS_RAMType]);  /* SR17 */
-   SiS_SetReg1(SiS_P3c4,0x19,SiS_SR15[4][SiS_RAMType]);  /* SR19 */
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,SiS_Pr->SiS_SR15[2][SiS_Pr->SiS_RAMType]);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x19,SiS_Pr->SiS_SR15[4][SiS_Pr->SiS_RAMType]);
 }
 
 void
-SiS_DisableChannelInterleaving(int index,USHORT SiS_DDRDRAM_TYPE[][5])
+SiS_DisableChannelInterleaving(SiS_Private *SiS_Pr, int index,
+                               USHORT SiS_DDRDRAM_TYPE[][5])
 {
    USHORT  data;
 
-   data=SiS_GetReg1(SiS_P3c4,0x15);
+   data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x15);
    data &= 0x1F;
    switch (SiS_DDRDRAM_TYPE[index][3])
    {
-     case 64: data |= 0;
-              break;
-     case 32: data |= 0x20;
-              break;
-     case 16: data |= 0x40;
-              break;
-     case 4:  data |= 0x60;
-              break;
+     case 64: data |= 0; 	break;
+     case 32: data |= 0x20;	break;
+     case 16: data |= 0x40;     break;
+     case 4:  data |= 0x60;     break;
    }
-   SiS_SetReg1(SiS_P3c4,0x15,data);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x15,data);
 }
 
 void
-SiS_SetDRAMSizingType(int index,USHORT DRAMTYPE_TABLE[][5])
+SiS_SetDRAMSizingType(SiS_Private *SiS_Pr, int index, USHORT DRAMTYPE_TABLE[][5])
 {
-   USHORT  data;
-
-   data = DRAMTYPE_TABLE[index][4];
-   SiS_SetReg1(SiS_P3c4,0x13,data);
-
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,DRAMTYPE_TABLE[index][4]);
    /* should delay 50 ns */
 }
 
 void
-SiS_CheckBusWidth_310(ULONG ROMAddress,ULONG FBAddress)
+SiS_CheckBusWidth_310(SiS_Private *SiS_Pr, UCHAR *ROMAddress,ULONG FBAddress,
+                      PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
    USHORT  data;
    PULONG volatile pVideoMemory;
 
-   pVideoMemory = (PULONG) FBAddress;
-   if (SiS_Get310DRAMType(ROMAddress)<2) {
+   pVideoMemory = (PULONG)FBAddress;
+   if(SiS_Get310DRAMType(ROMAddress,HwDeviceExtension) < 2) {
 
-     SiS_SetReg1(SiS_P3c4,0x13,0x00);
-     SiS_SetReg1(SiS_P3c4,0x14,0x12);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,0x00);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0x12);
      /* should delay */
-     SiS_SDR_MRS();
+     SiS_SDR_MRS(SiS_Pr);
 
-     SiS_ChannelAB = 0;
-     SiS_DataBusWidth = 128;
+     SiS_Pr->SiS_ChannelAB = 0;
+     SiS_Pr->SiS_DataBusWidth = 128;
      pVideoMemory[0] = 0x01234567L;
      pVideoMemory[1] = 0x456789ABL;
      pVideoMemory[2] = 0x89ABCDEFL;
@@ -1212,31 +1368,31 @@
      pVideoMemory[6] = 0xFFFFFFFFL;
      pVideoMemory[7] = 0xFFFFFFFFL;
      if ((pVideoMemory[3]!=0xCDEF0123L) || (pVideoMemory[2] != 0x89ABCDEFL)) {
-       /*ChannelA64Bit */
-       SiS_DataBusWidth = 64;
-       SiS_ChannelAB = 0;
-       data=SiS_GetReg1(SiS_P3c4,0x14);
-       SiS_SetReg1(SiS_P3c4,  0x14, (USHORT) (data & 0xFD));
+       /*Channel A 64Bit */
+       SiS_Pr->SiS_DataBusWidth = 64;
+       SiS_Pr->SiS_ChannelAB = 0;
+       data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,(USHORT)(data & 0xFD));
      }
 
      if ((pVideoMemory[1]!=0x456789ABL) || (pVideoMemory[0] != 0x01234567L)) {
-       /*ChannelB64Bit */
-       SiS_DataBusWidth = 64;
-       SiS_ChannelAB = 1;
-       data=SiS_GetReg1(SiS_P3c4,0x14);
-       SiS_SetReg1(SiS_P3c4,0x14,(USHORT)((data&0xFD)|0x01));
+       /*Channel B 64Bit */
+       SiS_Pr->SiS_DataBusWidth = 64;
+       SiS_Pr->SiS_ChannelAB = 1;
+       data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,(USHORT)((data&0xFD)|0x01));
      }
      return;
 
    } else {
      /* DDR Dual channel */
-     SiS_SetReg1(SiS_P3c4,0x13,0x00);
-     SiS_SetReg1(SiS_P3c4,0x14,0x02); /* Channel A, 64bit */
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,0x00);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0x02); /* Channel A, 64bit */
      /* should delay */
-     SiS_DDR_MRS();
+     SiS_DDR_MRS(SiS_Pr);
 
-     SiS_ChannelAB = 0;
-     SiS_DataBusWidth = 64;
+     SiS_Pr->SiS_ChannelAB = 0;
+     SiS_Pr->SiS_DataBusWidth = 64;
      pVideoMemory[0] = 0x01234567L;
      pVideoMemory[1] = 0x456789ABL;
      pVideoMemory[2] = 0x89ABCDEFL;
@@ -1254,17 +1410,17 @@
      } else {
        if (pVideoMemory[0] == 0x01234567L) {
          /* Channel A 32bit */
-         SiS_DataBusWidth = 32;
-         SiS_SetReg1(SiS_P3c4,0x14,0x00);
+         SiS_Pr->SiS_DataBusWidth = 32;
+         SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0x00);
          return;
        }
      }
 
-     SiS_SetReg1(SiS_P3c4,0x14,0x03); /* Channel B, 64bit */
-     SiS_DDR_MRS();
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0x03); /* Channel B, 64bit */
+     SiS_DDR_MRS(SiS_Pr);
 
-     SiS_ChannelAB = 1;
-     SiS_DataBusWidth = 64;
+     SiS_Pr->SiS_ChannelAB = 1;
+     SiS_Pr->SiS_DataBusWidth = 64;
      pVideoMemory[0] = 0x01234567L;
      pVideoMemory[1] = 0x456789ABL;
      pVideoMemory[2] = 0x89ABCDEFL;
@@ -1284,8 +1440,8 @@
      } else {
        if (pVideoMemory[0] == 0x01234567L) {
          /* Channel B 32 */
-         SiS_DataBusWidth = 32;
-         SiS_SetReg1(SiS_P3c4,0x14,0x01);
+         SiS_Pr->SiS_DataBusWidth = 32;
+         SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0x01);
        } else {
          /* error */
        }
@@ -1294,7 +1450,7 @@
 }
 
 int
-SiS_SetRank(int index,UCHAR RankNo,UCHAR SiS_ChannelAB,USHORT DRAMTYPE_TABLE[][5])
+SiS_SetRank(SiS_Private *SiS_Pr, int index,UCHAR RankNo,USHORT DRAMTYPE_TABLE[][5])
 {
   USHORT  data;
   int RankSize;
@@ -1302,68 +1458,66 @@
   if ((RankNo==2)&&(DRAMTYPE_TABLE[index][0]==2))
          return 0;
 
-  RankSize = DRAMTYPE_TABLE[index][3]/2 * SiS_DataBusWidth/32;
+  RankSize = DRAMTYPE_TABLE[index][3]/2 * SiS_Pr->SiS_DataBusWidth / 32;
 
-  if (RankNo*RankSize<=128) {
+  if (RankNo * RankSize <= 128) {
     data = 0;
-    while ((RankSize>>=1)>0) {
-      data+=0x10;
+    while((RankSize >>= 1) > 0) {
+      data += 0x10;
     }
-    data |= (RankNo-1)<<2;
-    data |= (SiS_DataBusWidth/64)&2;
-    data |= SiS_ChannelAB;
-    SiS_SetReg1(SiS_P3c4,0x14,data);
+    data |= (RankNo - 1) << 2;
+    data |= (SiS_Pr->SiS_DataBusWidth / 64) & 2;
+    data |= SiS_Pr->SiS_ChannelAB;
+    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,data);
     /* should delay */
-    SiS_SDR_MRS();
+    SiS_SDR_MRS(SiS_Pr);
     return 1;
   } else
     return 0;
 }
 
 int
-SiS_SetDDRChannel(int index,UCHAR ChannelNo,UCHAR SiS_ChannelAB,
+SiS_SetDDRChannel(SiS_Private *SiS_Pr, int index,UCHAR ChannelNo,
                   USHORT DRAMTYPE_TABLE[][5])
 {
   USHORT  data;
   int RankSize;
 
-  RankSize = DRAMTYPE_TABLE[index][3]/2 * SiS_DataBusWidth/32;
+  RankSize = DRAMTYPE_TABLE[index][3]/2 * SiS_Pr->SiS_DataBusWidth / 32;
   /* RankSize = DRAMTYPE_TABLE[index][3]; */
-  if (ChannelNo*RankSize<=128) {
+  if (ChannelNo * RankSize <= 128) {
     data = 0;
-    while ((RankSize>>=1)>0) {
-      data+=0x10;
+    while((RankSize >>= 1) > 0) {
+      data += 0x10;
     }
-    if (ChannelNo==2)
-      data |= 0x0C;
-
-    data |= (SiS_DataBusWidth/32)&2;
-    data |= SiS_ChannelAB;
-    SiS_SetReg1(SiS_P3c4,0x14,data);
+    if(ChannelNo == 2) data |= 0x0C;
+    data |= (SiS_Pr->SiS_DataBusWidth / 32) & 2;
+    data |= SiS_Pr->SiS_ChannelAB;
+    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,data);
     /* should delay */
-    SiS_DDR_MRS();
+    SiS_DDR_MRS(SiS_Pr);
     return 1;
   } else
     return 0;
 }
 
 int
-SiS_CheckColumn(int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
+SiS_CheckColumn(SiS_Private *SiS_Pr, int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
 {
   int i;
   ULONG Increment,Position;
 
-  /*Increment = 1<<(DRAMTYPE_TABLE[index][2] + SiS_DataBusWidth / 64 + 1); */
-  Increment = 1<<(10 + SiS_DataBusWidth / 64);
+  /*Increment = 1<<(DRAMTYPE_TABLE[index][2] + SiS_Pr->SiS_DataBusWidth / 64 + 1); */
+  Increment = 1 << (10 + SiS_Pr->SiS_DataBusWidth / 64);
 
   for (i=0,Position=0;i<2;i++) {
-         *((PULONG)(FBAddress+Position))=Position;
+         *((PULONG)(FBAddress + Position)) = Position;
          Position += Increment;
   }
 
   for (i=0,Position=0;i<2;i++) {
 /*    if (FBAddress[Position]!=Position) */
-         if ( (*(PULONG) (FBAddress + Position)) !=Position)
+         if((*(PULONG)(FBAddress + Position)) != Position)
                 return 0;
          Position += Increment;
   }
@@ -1371,21 +1525,21 @@
 }
 
 int
-SiS_CheckBanks(int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
+SiS_CheckBanks(SiS_Private *SiS_Pr, int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
 {
   int i;
   ULONG Increment,Position;
-  Increment = 1<<(DRAMTYPE_TABLE[index][2] + SiS_DataBusWidth / 64 + 2);
+  Increment = 1 << (DRAMTYPE_TABLE[index][2] + SiS_Pr->SiS_DataBusWidth / 64 + 2);
 
   for (i=0,Position=0;i<4;i++) {
 /*    FBAddress[Position]=Position; */
-    *((PULONG)(FBAddress+Position))=Position;
+    *((PULONG)(FBAddress + Position)) = Position;
     Position += Increment;
   }
 
   for (i=0,Position=0;i<4;i++) {
 /*    if (FBAddress[Position]!=Position) */
-    if ( (*(PULONG) (FBAddress + Position)) !=Position)
+    if((*(PULONG)(FBAddress + Position)) != Position)
       return 0;
     Position += Increment;
   }
@@ -1393,12 +1547,12 @@
 }
 
 int
-SiS_CheckRank(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
+SiS_CheckRank(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
 {
   int i;
   ULONG Increment,Position;
   Increment = 1<<(DRAMTYPE_TABLE[index][2] + DRAMTYPE_TABLE[index][1] +
-                  DRAMTYPE_TABLE[index][0] + SiS_DataBusWidth / 64 + RankNo);
+                  DRAMTYPE_TABLE[index][0] + SiS_Pr->SiS_DataBusWidth / 64 + RankNo);
 
   for (i=0,Position=0;i<2;i++) {
 /*    FBAddress[Position]=Position; */
@@ -1418,88 +1572,91 @@
 }
 
 int
-SiS_CheckDDRRank(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
+SiS_CheckDDRRank(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
 {
   ULONG Increment,Position;
   USHORT  data;
-  
+
   Increment = 1<<(DRAMTYPE_TABLE[index][2] + DRAMTYPE_TABLE[index][1] +
-                  DRAMTYPE_TABLE[index][0] + SiS_DataBusWidth / 64 + RankNo);
+                  DRAMTYPE_TABLE[index][0] + SiS_Pr->SiS_DataBusWidth / 64 + RankNo);
 
   Increment += Increment/2;
-  
+
   Position =0;
-  *((PULONG)(FBAddress+Position+0))=0x01234567;
-  *((PULONG)(FBAddress+Position+1))=0x456789AB;
-  *((PULONG)(FBAddress+Position+2))=0x55555555;
-  *((PULONG)(FBAddress+Position+3))=0x55555555;
-  *((PULONG)(FBAddress+Position+4))=0xAAAAAAAA;
-  *((PULONG)(FBAddress+Position+5))=0xAAAAAAAA;
+  *((PULONG)(FBAddress+Position + 0)) = 0x01234567;
+  *((PULONG)(FBAddress+Position + 1)) = 0x456789AB;
+  *((PULONG)(FBAddress+Position + 2)) = 0x55555555;
+  *((PULONG)(FBAddress+Position + 3)) = 0x55555555;
+  *((PULONG)(FBAddress+Position + 4)) = 0xAAAAAAAA;
+  *((PULONG)(FBAddress+Position + 5)) = 0xAAAAAAAA;
 
-  if ( (*(PULONG) (FBAddress + 1))==0x456789AB)
+  if ( (*(PULONG) (FBAddress + 1)) == 0x456789AB)
     return 1;
 
-  if ( (*(PULONG) (FBAddress + 0))==0x01234567)
+  if ( (*(PULONG) (FBAddress + 0)) == 0x01234567)
     return 0;
 
-  data=SiS_GetReg1(SiS_P3c4,0x14);
+  data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
   data &= 0xF3;
   data |= 0x08;
-  SiS_SetReg1(SiS_P3c4,0x14,data);
-  data=SiS_GetReg1(SiS_P3c4,0x15);
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,data);
+  data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x15);
   data += 0x20;
-  SiS_SetReg1(SiS_P3c4,0x15,data);
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x15,data);
 
   return 1;
 }
 
 int
-SiS_CheckRanks(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
+SiS_CheckRanks(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
 {
   int r;
 
   for (r=RankNo;r>=1;r--) {
-    if (!SiS_CheckRank(r,index,DRAMTYPE_TABLE,FBAddress))
+    if (!SiS_CheckRank(SiS_Pr, r, index, DRAMTYPE_TABLE, FBAddress))
       return 0;
   }
-  if (!SiS_CheckBanks(index,DRAMTYPE_TABLE,FBAddress))
+  if (!SiS_CheckBanks(SiS_Pr, index, DRAMTYPE_TABLE, FBAddress))
     return 0;
 
-  if (!SiS_CheckColumn(index,DRAMTYPE_TABLE,FBAddress))
+  if (!SiS_CheckColumn(SiS_Pr, index, DRAMTYPE_TABLE, FBAddress))
     return 0;
+
   return 1;
 }
 
 int
-SiS_CheckDDRRanks(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
+SiS_CheckDDRRanks(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],
+                  ULONG FBAddress)
 {
   int r;
 
   for (r=RankNo;r>=1;r--) {
-    if (!SiS_CheckDDRRank(r,index,DRAMTYPE_TABLE,FBAddress))
+    if (!SiS_CheckDDRRank(SiS_Pr, r,index,DRAMTYPE_TABLE,FBAddress))
       return 0;
   }
-  if (!SiS_CheckBanks(index,DRAMTYPE_TABLE,FBAddress))
+  if (!SiS_CheckBanks(SiS_Pr, index,DRAMTYPE_TABLE,FBAddress))
     return 0;
 
-  if (!SiS_CheckColumn(index,DRAMTYPE_TABLE,FBAddress))
+  if (!SiS_CheckColumn(SiS_Pr, index,DRAMTYPE_TABLE,FBAddress))
     return 0;
+
   return 1;
 }
 
 int
-SiS_SDRSizing(ULONG FBAddress)
+SiS_SDRSizing(SiS_Private *SiS_Pr, ULONG FBAddress)
 {
   int    i;
   UCHAR  j;
 
   for (i=0;i<13;i++) {
-    SiS_SetDRAMSizingType(i, SiS_SDRDRAM_TYPE);
+    SiS_SetDRAMSizingType(SiS_Pr, i, SiS_SDRDRAM_TYPE);
     for (j=2;j>0;j--) {
-      if (!SiS_SetRank(i,(UCHAR) j, SiS_ChannelAB,SiS_SDRDRAM_TYPE))
+      if (!SiS_SetRank(SiS_Pr, i,(UCHAR) j, SiS_SDRDRAM_TYPE))
         continue;
       else {
-        if (SiS_CheckRanks(j,i,SiS_SDRDRAM_TYPE, FBAddress))
+        if (SiS_CheckRanks(SiS_Pr, j,i,SiS_SDRDRAM_TYPE, FBAddress))
           return 1;
       }
     }
@@ -1508,21 +1665,21 @@
 }
 
 int
-SiS_DDRSizing(ULONG FBAddress)
+SiS_DDRSizing(SiS_Private *SiS_Pr, ULONG FBAddress)
 {
 
   int    i;
   UCHAR  j;
 
-  for (i=0;i<4;i++){
-    SiS_SetDRAMSizingType(i,SiS_DDRDRAM_TYPE);
-    SiS_DisableChannelInterleaving(i,SiS_DDRDRAM_TYPE);
-    for (j=2;j>0;j--) {
-      SiS_SetDDRChannel(i, j, SiS_ChannelAB, SiS_DDRDRAM_TYPE);
-      if (!SiS_SetRank(i,(UCHAR) j, SiS_ChannelAB,SiS_DDRDRAM_TYPE))
+  for (i=0; i<4; i++){
+    SiS_SetDRAMSizingType(SiS_Pr, i, SiS_DDRDRAM_TYPE);
+    SiS_DisableChannelInterleaving(SiS_Pr, i, SiS_DDRDRAM_TYPE);
+    for (j=2; j>0; j--) {
+      SiS_SetDDRChannel(SiS_Pr, i, j, SiS_DDRDRAM_TYPE);
+      if (!SiS_SetRank(SiS_Pr, i, (UCHAR) j, SiS_DDRDRAM_TYPE))
         continue;
       else {
-        if (SiS_CheckDDRRanks(j,i,SiS_DDRDRAM_TYPE, FBAddress))
+        if (SiS_CheckDDRRanks(SiS_Pr, j, i, SiS_DDRDRAM_TYPE, FBAddress))
           return 1;
       }
     }
@@ -1534,32 +1691,31 @@
  check if read cache pointer is correct
 */
 void
-SiS_VerifyMclk(ULONG FBAddr)
+SiS_VerifyMclk(SiS_Private *SiS_Pr, ULONG FBAddr)
 {
    PUCHAR  pVideoMemory = (PUCHAR) FBAddr;
-   UCHAR i,j;
-   USHORT Temp,SR21;
+   UCHAR   i, j;
+   USHORT  Temp,SR21;
 
+   pVideoMemory[0] = 0xaa;  /* alan */
+   pVideoMemory[16] = 0x55; /* note: PCI read cache is off */
 
-   pVideoMemory[0]=0xaa; /* alan */
-   pVideoMemory[16]=0x55; /* note: PCI read cache is off */
-
-   if ((pVideoMemory[0]!=0xaa)||(pVideoMemory[16]!=0x55)) {
-     for (i=0,j=16;i<2;i++,j+=16)  {
-       SR21 = SiS_GetReg1(SiS_P3c4, 0x21);
-       Temp = SR21 & 0xFB;     /* disable PCI post write buffer empty gating */
-       SiS_SetReg1(SiS_P3c4, 0x21, Temp);
-
-       Temp = SiS_GetReg1(SiS_P3c4, 0x3C);
-       Temp = Temp | 0x01;                 /*MCLK reset */
-       SiS_SetReg1(SiS_P3c4, 0x3C, Temp);
-       Temp = SiS_GetReg1(SiS_P3c4, 0x3C);
-       Temp = Temp & 0xFE;                 /* MCLK normal operation */
-       SiS_SetReg1(SiS_P3c4, 0x3C, Temp);
-       SiS_SetReg1(SiS_P3c4, 0x21, SR21);
+   if((pVideoMemory[0] != 0xaa) || (pVideoMemory[16] != 0x55)) {
+     for (i=0,j=16; i<2; i++,j+=16)  {
+       SR21 = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x21);
+       Temp = SR21 & 0xFB;           /* disable PCI post write buffer empty gating */
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x21,Temp);
+
+       Temp = SiS_GetReg1(SiS_Pr->SiS_P3c4, 0x3C);
+       Temp |= 0x01;                 /* MCLK reset */
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x3C,Temp);
+       Temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3C);
+       Temp &= 0xFE;                 /* MCLK normal operation */
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x3C,Temp);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x21,SR21);
 
        pVideoMemory[16+j] = j;
-       if (pVideoMemory[16+j]==j)  {
+       if(pVideoMemory[16+j] == j) {
          pVideoMemory[j] = j;
          break;
        }
@@ -1569,113 +1725,107 @@
 
 /* TW: Is this a 315E? */
 int
-Is315E(void)
+Is315E(SiS_Private *SiS_Pr)
 {
    USHORT  data;
-  	
-   data=SiS_GetReg1(SiS_P3d4,0x5F);
-   if (data&0x10) return 1;
+
+   data = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5F);
+   if(data & 0x10) return 1;
    else return 0;
 }
 
 /* TW: For 315 only */
 void
-SiS_SetDRAMSize_310(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_SetDRAMSize_310(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-   ULONG   ROMAddr  = (ULONG)HwDeviceExtension->pjVirtualRomBase;
+   UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
    ULONG   FBAddr   = (ULONG)HwDeviceExtension->pjVideoMemoryAddress;
-   /*USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;*/
    USHORT  data;
 
 #ifdef SIS301	/* TW: SIS301 ??? */
-   /*SiS_SetReg1(SiS_P3d4,0x30,0x40);   */
+   /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x30,0x40);   */
 #endif
 #ifdef SIS302   /* TW: SIS302 ??? */
-   SiS_SetReg1(SiS_P3d4,0x30,0x4D);  /* alan,should change value */
-   SiS_SetReg1(SiS_P3d4,0x31,0xc0);  /* alan,should change value */
-   SiS_SetReg1(SiS_P3d4,0x34,0x3F);  /* alan,should change value */
+   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x30,0x4D);  /* alan,should change value */
+   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x31,0xc0);  /* alan,should change value */
+   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x34,0x3F);  /* alan,should change value */
 #endif
 
-   SiSSetMode(HwDeviceExtension,0x2e);
+   SiSSetMode(SiS_Pr, HwDeviceExtension, 0x2e);
 
-   data=SiS_GetReg1(SiS_P3c4,0x21);
-   SiS_SetReg1(SiS_P3c4,0x21,(USHORT) (data&0xDF));      /* disable read cache */
+   data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x21);
+   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x21,0xDF);                 /* disable read cache */
 
-   data=SiS_GetReg1(SiS_P3c4,0x1);
-   data=data|0x20;
-   SiS_SetReg1(SiS_P3c4,0x01,data);                    /* Turn OFF Display */
+   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x20);                  /* Turn OFF Display */
 
-   data=SiS_GetReg1(SiS_P3c4,0x16);
-   SiS_SetReg1(SiS_P3c4,0x16,(USHORT) (data|0x0F));      /* assume lowest speed DRAM */
+   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x16,0x0F);                  /* assume lowest speed DRAM */
 
-   SiS_SetDRAMModeRegister(ROMAddr);
-   SiS_DisableRefresh();
-   SiS_CheckBusWidth_310(ROMAddr,FBAddr);
+   SiS_SetDRAMModeRegister(SiS_Pr, ROMAddr, HwDeviceExtension);
+   SiS_DisableRefresh(SiS_Pr);
+   SiS_CheckBusWidth_310(SiS_Pr, ROMAddr, FBAddr, HwDeviceExtension);
 
-   SiS_VerifyMclk(FBAddr); /* alan 2000/7/3 */
+   SiS_VerifyMclk(SiS_Pr, FBAddr);
 
-   if (SiS_Get310DRAMType(ROMAddr)<2) {
-     SiS_SDRSizing(FBAddr);
-   } else {
-     SiS_DDRSizing(FBAddr);
-   }
-   
-   if (Is315E()) {
-     data=SiS_GetReg1(SiS_P3c4,0x14);
-     if ((data&0x0C)==0x0C) /* dual channel */
-     {
-     	if ((data&0xF0)>0x40)
+   if(SiS_Get310DRAMType(SiS_Pr, ROMAddr, HwDeviceExtension) < 2)
+     SiS_SDRSizing(SiS_Pr, FBAddr);
+   else
+     SiS_DDRSizing(SiS_Pr, FBAddr);
+
+   if(Is315E(SiS_Pr)) {
+     data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+     if((data & 0x0C) == 0x0C) { 	/* dual channel */
+     	if((data & 0xF0) > 0x40)
      	  data = (data & 0x0F) | 0x40;
-     } else { /* single channel */
-     	if ((data&0xF0)>0x50)
+     } else { 				/* single channel */
+     	if((data & 0xF0) > 0x50)
      	  data = (data & 0x0F) | 0x50;
      }
    }
-   
-   SiS_SetReg1(SiS_P3c4,0x16,SiS_SR15[1][SiS_RAMType]);  /* restore SR16 */
 
-   SiS_EnableRefresh(ROMAddr);
-   data=SiS_GetReg1(SiS_P3c4,0x21);
-   SiS_SetReg1(SiS_P3c4,0x21,(USHORT) (data|0x20));      /* enable read cache */
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,SiS_Pr->SiS_SR15[1][SiS_Pr->SiS_RAMType]);  /* restore SR16 */
+
+   SiS_EnableRefresh(SiS_Pr, ROMAddr);
+   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x21,0x20);      	/* enable read cache */
 }
 #endif
 
 void
-SiS_SetMemoryClock(ULONG ROMAddr)
+SiS_SetMemoryClock(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-   SiS_SetReg1(SiS_P3c4,0x28,SiS_MCLKData[SiS_RAMType].SR28);
-   SiS_SetReg1(SiS_P3c4,0x29,SiS_MCLKData[SiS_RAMType].SR29);
-   SiS_SetReg1(SiS_P3c4,0x2A,SiS_MCLKData[SiS_RAMType].SR2A);
-   SiS_SetReg1(SiS_P3c4,0x2E,SiS_ECLKData[SiS_RAMType].SR2E);
-   SiS_SetReg1(SiS_P3c4,0x2F,SiS_ECLKData[SiS_RAMType].SR2F);
-   SiS_SetReg1(SiS_P3c4,0x30,SiS_ECLKData[SiS_RAMType].SR30);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x28,SiS_Pr->SiS_MCLKData_0[SiS_Pr->SiS_RAMType].SR28);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x29,SiS_Pr->SiS_MCLKData_0[SiS_Pr->SiS_RAMType].SR29);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2A,SiS_Pr->SiS_MCLKData_0[SiS_Pr->SiS_RAMType].SR2A);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2E,SiS_Pr->SiS_ECLKData[SiS_Pr->SiS_RAMType].SR2E);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2F,SiS_Pr->SiS_ECLKData[SiS_Pr->SiS_RAMType].SR2F);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x30,SiS_Pr->SiS_ECLKData[SiS_Pr->SiS_RAMType].SR30);
 
 #ifdef SIS315H
-   if (Is315E()) {
-     SiS_SetReg1(SiS_P3c4,0x28,0x3B); /* 143 */
-     SiS_SetReg1(SiS_P3c4,0x29,0x22);
-     SiS_SetReg1(SiS_P3c4,0x2E,0x3B); /* 143 */
-     SiS_SetReg1(SiS_P3c4,0x2F,0x22);
+   if (Is315E(SiS_Pr)) {
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x28,0x3B); /* 143 */
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x29,0x22);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2E,0x3B); /* 143 */
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2F,0x22);
    }
 #endif
 }
 
-#endif /* ifndef LINUX_XF86 */
+#endif /* ifdef LINUXBIOS */
 
 #ifdef SIS315H
 UCHAR
-SiS_Get310DRAMType(ULONG   ROMAddr)
+SiS_Get310DRAMType(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
    UCHAR   data;
 
-   /*
-   index=SiS_GetReg1(SiS_P3c4,0x1A);
-   index=index&07;
-   */
-   if (*pSiS_SoftSetting&SoftDRAMType)
-     data = *pSiS_SoftSetting & 0x03;
-   else
-     data=SiS_GetReg1(SiS_P3c4,0x3a) & 0x03;
+   if(*SiS_Pr->pSiS_SoftSetting & SoftDRAMType) {
+     data = *SiS_Pr->pSiS_SoftSetting & 0x03;
+   } else {
+     if(HwDeviceExtension->jChipType > SIS_315PRO) {
+        data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x07;
+     } else {	/* TW: 315 */
+        data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3a) & 0x03;
+     }
+   }
 
    return data;
 }
@@ -1685,31 +1835,31 @@
 
 /* ----------------------------------------- */
 
-void SiSRegInit(USHORT BaseAddr)
+void SiSRegInit(SiS_Private *SiS_Pr, USHORT BaseAddr)
 {
-   SiS_P3c4=BaseAddr+0x14;
-   SiS_P3d4=BaseAddr+0x24;
-   SiS_P3c0=BaseAddr+0x10;
-   SiS_P3ce=BaseAddr+0x1e;
-   SiS_P3c2=BaseAddr+0x12;
-   SiS_P3ca=BaseAddr+0x1a;
-   SiS_P3c6=BaseAddr+0x16;
-   SiS_P3c7=BaseAddr+0x17;
-   SiS_P3c8=BaseAddr+0x18;
-   SiS_P3c9=BaseAddr+0x19;
-   SiS_P3da=BaseAddr+0x2A;
-   SiS_Part1Port=BaseAddr+SIS_CRT2_PORT_04;
-   SiS_Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-   SiS_Part3Port=BaseAddr+SIS_CRT2_PORT_12;
-   SiS_Part4Port=BaseAddr+SIS_CRT2_PORT_14;
-   SiS_Part5Port=BaseAddr+SIS_CRT2_PORT_14+2;
-   SiS_DDC_Port=BaseAddr+0x14;  /* 0x3c4; */
+   SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
+   SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
+   SiS_Pr->SiS_P3c0 = BaseAddr + 0x10;
+   SiS_Pr->SiS_P3ce = BaseAddr + 0x1e;
+   SiS_Pr->SiS_P3c2 = BaseAddr + 0x12;
+   SiS_Pr->SiS_P3ca = BaseAddr + 0x1a;
+   SiS_Pr->SiS_P3c6 = BaseAddr + 0x16;
+   SiS_Pr->SiS_P3c7 = BaseAddr + 0x17;
+   SiS_Pr->SiS_P3c8 = BaseAddr + 0x18;
+   SiS_Pr->SiS_P3c9 = BaseAddr + 0x19;
+   SiS_Pr->SiS_P3da = BaseAddr + 0x2A;
+   SiS_Pr->SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04;   /* Digital video interface registers (LCD) */
+   SiS_Pr->SiS_Part2Port = BaseAddr + SIS_CRT2_PORT_10;   /* 301 TV Encoder registers */
+   SiS_Pr->SiS_Part3Port = BaseAddr + SIS_CRT2_PORT_12;   /* 301 Macrovision registers */
+   SiS_Pr->SiS_Part4Port = BaseAddr + SIS_CRT2_PORT_14;   /* 301 VGA2 (and LCD) registers */
+   SiS_Pr->SiS_Part5Port = BaseAddr + SIS_CRT2_PORT_14+2; /* 301 palette address port registers */
+   SiS_Pr->SiS_DDC_Port = BaseAddr + 0x14;                /* DDC Port ( = P3C4, SR11/0A) */
 }
 
 void
-SiSInitPCIetc(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiSInitPCIetc(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-#ifdef LINUX_XF86
+/* #ifdef LINUX_XF86 */
    if ((HwDeviceExtension->jChipType == SIS_540)||
        (HwDeviceExtension->jChipType == SIS_630)||
        (HwDeviceExtension->jChipType == SIS_730)||
@@ -1718,9 +1868,9 @@
 		  - PCI IO ENABLE  (0x20)
 		  - MMIO ENABLE (0x1)
   	*/
-       SiS_SetReg1(SiS_P3c4,0x20,0xa1);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x20,0xa1);
        /* TW: Enable 2D (0x42) & 3D accelerator (0x18) */
-       SiS_SetReg1(SiS_P3c4,0x1E,0x5A);
+       SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x1E,0xFF,0x5A);
    }
    if((HwDeviceExtension->jChipType == SIS_315H)||
       (HwDeviceExtension->jChipType == SIS_315PRO)||
@@ -1729,106 +1879,144 @@
       (HwDeviceExtension->jChipType == SIS_740)||
       (HwDeviceExtension->jChipType == SIS_650)) {
       /* TW: This seems to be done the same way on these chipsets */
-      SiS_SetReg1(SiS_P3c4,0x20,0xa1);
-      SiS_SetReg1(SiS_P3c4,0x1E,0x5A);
+      SiS_SetReg1(SiS_Pr->SiS_P3c4,0x20,0xa1);
+      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x1E,0xFF,0x5A);
    }
-#endif
+/* #endif */
 }
 
 void
-SiSSetLVDSetc(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo)
+SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo)
 {
    ULONG   temp;
 
-   SiS_IF_DEF_LVDS=0;
-   SiS_IF_DEF_CH7005=0;
-   SiS_IF_DEF_HiVision=0;
-   SiS_IF_DEF_DSTN=0;
-   SiS_IF_DEF_FSTN=0;
-   if((ModeNo==0x5a)||(ModeNo==0x5b)) {
-   	SiS_IF_DEF_DSTN=1;   /* for 550 dstn */
-   	SiS_IF_DEF_FSTN=1;   /* for fstn */
+   SiS_Pr->SiS_IF_DEF_LVDS = 0;
+   SiS_Pr->SiS_IF_DEF_TRUMPION = 0;
+   SiS_Pr->SiS_IF_DEF_CH70xx = 0;
+   SiS_Pr->SiS_IF_DEF_HiVision = 0;
+   SiS_Pr->SiS_IF_DEF_DSTN = 0;
+   SiS_Pr->SiS_IF_DEF_FSTN = 0;
+
+   SiS_Pr->SiS_ChrontelInit = 0;
+
+   if((ModeNo == 0x5a) || (ModeNo == 0x5b)) {
+   	SiS_Pr->SiS_IF_DEF_DSTN = 1;   /* for 550 dstn */
+   	SiS_Pr->SiS_IF_DEF_FSTN = 1;   /* for fstn */
    }
-   if((HwDeviceExtension->jChipType == SIS_540)||
-      (HwDeviceExtension->jChipType == SIS_630)||
-      (HwDeviceExtension->jChipType == SIS_730)||
-      (HwDeviceExtension->jChipType == SIS_550)||
-      (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_650))    /* 09/03/01 chiawen for 650 */
+
+#ifdef SIS300
+   if((HwDeviceExtension->jChipType == SIS_540) ||
+      (HwDeviceExtension->jChipType == SIS_630) ||
+      (HwDeviceExtension->jChipType == SIS_730))
     {
-      	if (SiS_IF_DEF_FSTN) {                               /*fstn setCR37=0x04;*/
-        	SiS_SetReg1(SiS_P3d4,0x37,0x04);
-      	}
-      	temp=SiS_GetReg1(SiS_P3d4,0x37);
-      	temp=(temp&0x0E)>>1;
-      	if((temp==0)||(temp==1)) {   /* for 301 */
-        	SiS_IF_DEF_LVDS=0;
-        	SiS_IF_DEF_CH7005=0;
-        	SiS_IF_DEF_TRUMPION=0;
-      	}
-      	if((temp>=2)&&(temp<=5)) SiS_IF_DEF_LVDS=1;
-      	if(temp==3) SiS_IF_DEF_TRUMPION=1;
-      	if((temp==4)||(temp==5)) {
-		/* TW: Save power status */
-		SiS_Backup7005 = SiS_GetCH7005(0x0e);
-		SiS_IF_DEF_CH7005=1;
+        /* TW: Check for SiS30x first */
+        temp = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x00);
+	if((temp == 1) || (temp == 2)) return;
+      	temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
+      	temp = (temp & 0x0E) >> 1;
+      	if((temp >= 2) && (temp <= 5)) SiS_Pr->SiS_IF_DEF_LVDS = 1;
+      	if(temp == 3)   SiS_Pr->SiS_IF_DEF_TRUMPION = 1;
+      	if((temp == 4) || (temp == 5)) {
+		/* TW: Save power status (and error check) */
+		SiS_Pr->SiS_Backup70xx = SiS_GetCH700x(SiS_Pr, 0x0e);
+		SiS_Pr->SiS_IF_DEF_CH70xx = 1;
         }
    }
+#endif
+#ifdef SIS315H
+   if((HwDeviceExtension->jChipType == SIS_550) ||
+      (HwDeviceExtension->jChipType == SIS_640) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
+      (HwDeviceExtension->jChipType == SIS_650))
+    {
+        /* TW: CR37 is different on 310/325 series */
+        if (SiS_Pr->SiS_IF_DEF_FSTN)                       /* fstn: set CR37=0x04 */
+             SiS_SetReg1(SiS_Pr->SiS_P3d4,0x37,0x04);      /* (fake LVDS bridge) */
+
+	temp=SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
+      	temp = (temp & 0x0E) >> 1;
+      	if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1;
+      	if(temp == 3)  {
+			SiS_Pr->SiS_IF_DEF_CH70xx = 2;
+        }
+	/* SiS_Pr->SiS_IF_DEF_HiVision = 1; */
+    }
+#endif
 }
 
 void
-SiSInitPtr(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiSInitPtr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
 #ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_315H)||  /* 05/02/01 ynlai for sis550 */
-      (HwDeviceExtension->jChipType == SIS_315PRO)||
-      (HwDeviceExtension->jChipType == SIS_550)||
-      (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_650))    /* 09/03/01 chiawen for 650 */
-     InitTo310Pointer();
+   if((HwDeviceExtension->jChipType == SIS_315H) ||
+      (HwDeviceExtension->jChipType == SIS_315PRO) ||
+      (HwDeviceExtension->jChipType == SIS_550) ||
+      (HwDeviceExtension->jChipType == SIS_640) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
+      (HwDeviceExtension->jChipType == SIS_650))
+     InitTo310Pointer(SiS_Pr, HwDeviceExtension);
 #endif
 
 #ifdef SIS300
-   if ((HwDeviceExtension->jChipType == SIS_540)||
-       (HwDeviceExtension->jChipType == SIS_630)||
-       (HwDeviceExtension->jChipType == SIS_730)||
+   if ((HwDeviceExtension->jChipType == SIS_540) ||
+       (HwDeviceExtension->jChipType == SIS_630) ||
+       (HwDeviceExtension->jChipType == SIS_730) ||
        (HwDeviceExtension->jChipType == SIS_300))
-     InitTo300Pointer();
+     InitTo300Pointer(SiS_Pr, HwDeviceExtension);
 #endif
 }
 
+void
+SiSDetermineROMUsage(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, UCHAR *ROMAddr)
+{
+   if((ROMAddr) && (HwDeviceExtension->UseROM)) {
+     if((ROMAddr[0x00] != 0x55) || (ROMAddr[0x01] != 0xAA)) {
+        SiS_Pr->SiS_UseROM = FALSE;
+     } else if(HwDeviceExtension->jChipType < SIS_315H) {
+        /* TW: We don't use the ROM image if BIOS version < 2.0.0 as
+         *     such old BIOSes don't have the needed data at the
+	 *     expected locations
+	 */
+        if(ROMAddr[0x06] < '2')  SiS_Pr->SiS_UseROM = FALSE;
+	else                     SiS_Pr->SiS_UseROM = TRUE;
+     } else {
+        /* TW: TODO: Check this for 310/325 series */
+	SiS_Pr->SiS_UseROM = TRUE;
+     }
+   } else SiS_Pr->SiS_UseROM = FALSE;
+
+}
+
 /*
  	=========================================
- 	======== SiS SetMode Function  ==========
+ 	======== SiS SetMode Functions ==========
  	=========================================
 */
 #ifdef LINUX_XF86
 /* TW: This is used for non-Dual-Head mode from X */
 BOOLEAN
-SiSBIOSSetMode(PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
+SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
                DisplayModePtr mode)
 {
    UShort  ModeNo=0;
 
    ModeNo = SiS_CalcModeIndex(pScrn, mode);
-   if (!ModeNo) return FALSE;
+   if(!ModeNo) return FALSE;
 
-   xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Setting mode 0x%x\n", ModeNo);
+   xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode 0x%x\n", ModeNo);
 
-   return(SiSSetMode(HwDeviceExtension, pScrn, ModeNo));
+   return(SiSSetMode(SiS_Pr, HwDeviceExtension, pScrn, ModeNo, TRUE));
 }
 
 #ifdef SISDUALHEAD
 /* TW: Set CRT1 mode (used for dual head) */
 BOOLEAN
-SiSBIOSSetModeCRT1(PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
+SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
                DisplayModePtr mode)
 {
    ULONG   temp;
-   USHORT  ModeIdIndex,KeepLockReg;
-   ULONG   ROMAddr  = (ULONG)HwDeviceExtension->pjVirtualRomBase;
+   USHORT  ModeIdIndex;
+   UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
    USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
    SISPtr  pSiS = SISPTR(pScrn);
    SISEntPtr pSiSEnt = pSiS->entityPrivate;
@@ -1836,139 +2024,190 @@
    UShort  ModeNo=0;
 
    ModeNo = SiS_CalcModeIndex(pScrn, mode);
-   if (!ModeNo) return FALSE;
+   if(!ModeNo) return FALSE;
+
+   xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode 0x%x on CRT1\n", ModeNo);
 
-   xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Setting mode 0x%x on CRT1\n", ModeNo);
+   SiSInitPtr(SiS_Pr, HwDeviceExtension);
 
-   SiSInitPtr(HwDeviceExtension);
+   SiSRegInit(SiS_Pr, BaseAddr);
 
-   SiSRegInit(BaseAddr);
+   SiS_Pr->SiS_VGAINFO = SiS_GetSetMMIOReg(pScrn, 0x489, 0xff);
 
-   SiSInitPCIetc(HwDeviceExtension);
+   SiSInitPCIetc(SiS_Pr, HwDeviceExtension);
 
-   SiSSetLVDSetc(HwDeviceExtension, ModeNo);
+   SiSSetLVDSetc(SiS_Pr, HwDeviceExtension, ModeNo);
+
+   SiSDetermineROMUsage(SiS_Pr, HwDeviceExtension, ROMAddr);
 
    /* TW: We don't clear the buffer under X */
-   flag_clearbuffer=0;
+   SiS_Pr->SiS_flag_clearbuffer=0;
+
+   /* 1.Openkey */
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
 
-   /* SiS_PresetScratchregister(SiS_P3d4,HwDeviceExtension);  */      		/* add for CRT2  */
-   KeepLockReg = SiS_GetReg1(SiS_P3c4,0x05);
-   SiS_SetReg1(SiS_P3c4,0x05,0x86);                             		/* 1.Openkey */
+   SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
 
-   temp = SiS_SearchModeID(ROMAddr,ModeNo,&ModeIdIndex);        		/* 2.Get ModeID Table  */
-   if(temp==0)  return(0);
+   /* 2.Get ModeID Table  */
+   temp = SiS_SearchModeID(SiS_Pr, ROMAddr,&ModeNo,&ModeIdIndex);
+   if(temp == 0)  return(0);
 
    /* TW: Determine VBType (301,301B,301LV,302B,302LV) */
-   SiS_GetVBType(BaseAddr);
+   SiS_GetVBType(SiS_Pr, BaseAddr,HwDeviceExtension);
 
-   SiS_GetVBInfo301(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);   	/*add for CRT2 */
-   SiS_GetLCDResInfo301(ROMAddr,SiS_P3d4,ModeNo,ModeIdIndex);   		/*add for CRT2 */
+   /* TW: Get VB information (connectors, connected devices) */
+   SiS_GetVBInfo(SiS_Pr, BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+   SiS_SetHiVision(SiS_Pr, BaseAddr,HwDeviceExtension);
+   SiS_GetLCDResInfo(SiS_Pr, ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
 
-   SiS_SetCRT1Group(ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex);
+   /* TW: I am not sure the flag's name is correct */
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
+          if(ModeNo != 0x10)  SiS_Pr->SiS_SetFlag |= CRT2IsVGA;
+      }
+   }
+
+   /* TW: Set mode on CRT1 */
+   SiS_SetCRT1Group(SiS_Pr, ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex,BaseAddr);
 
    pSiSEnt->CRT1ModeNo = ModeNo;
    pSiSEnt->CRT1DMode = mode;
 
    /* TW: SetPitch: Adapt to virtual size & position */
-   SiS_SetPitchCRT1(pScrn, BaseAddr);
+   if(ModeNo > 0x13) {
+      SiS_SetPitchCRT1(SiS_Pr, pScrn, BaseAddr);
+   }
 
    /* We have to reset CRT2 if changing mode on CRT1 */
-   if (pSiSEnt->CRT2ModeNo != -1) {
-        xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "(Re-)Setting mode 0x%x on CRT2\n",
+   if(pSiSEnt->CRT2ModeNo != -1) {
+        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "(Re-)Setting mode 0x%x on CRT2\n",
 				pSiSEnt->CRT2ModeNo);
-	SiSBIOSSetModeCRT2(HwDeviceExtension, pSiSEnt->pScrn_1,
+	SiSBIOSSetModeCRT2(SiS_Pr, HwDeviceExtension, pSiSEnt->pScrn_1,
 				pSiSEnt->CRT2DMode);
    }
 
-   /* Backup/Set ModeNo in MMIO */
-   /* SiS_GetSetModeID(pScrn,ModeNo); */
+   if((HwDeviceExtension->jChipType > SIS_315PRO) && (SiS_Pr->SiS_IF_DEF_LVDS == 0)) {
+      /* TW: *** For 650 only! *** */
+      SiS_HandleCRT1(SiS_Pr);
+   }
+
+   SiS_DisplayOn(SiS_Pr);
+   SiS_SetReg3(SiS_Pr->SiS_P3c6,0xFF);
 
-   if(KeepLockReg==0xA1) SiS_SetReg1(SiS_P3c4,0x05,0x86); /* 05/02/01 ynlai */
-   else SiS_SetReg1(SiS_P3c4,0x05,0x00);
+   if((HwDeviceExtension->jChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 0)) {
+      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+          SiS_Handle301B_1400x1050(SiS_Pr, ModeNo);
+      }
+   }
+
+   /* Backup/Set ModeNo in MMIO */
+   SiS_GetSetModeID(pScrn,ModeNo);
 
    return TRUE;
 }
 
 /* TW: Set CRT2 mode (used for dual head) */
 BOOLEAN
-SiSBIOSSetModeCRT2(PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
+SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
                DisplayModePtr mode)
 {
    ULONG   temp;
-   USHORT  ModeIdIndex,KeepLockReg;
-   ULONG   ROMAddr  = (ULONG)HwDeviceExtension->pjVirtualRomBase;
+   USHORT  ModeIdIndex;
+   UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
    USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
-   UShort  ModeNo=0;
-   SISPtr  pSiS = SISPTR(pScrn);
+   UShort  ModeNo   = 0;
+   SISPtr  pSiS     = SISPTR(pScrn);
    SISEntPtr pSiSEnt = pSiS->entityPrivate;
 
    ModeNo = SiS_CalcModeIndex(pScrn, mode);
-   if (!ModeNo) return FALSE;
+   if(!ModeNo) return FALSE;
 
-   SiSInitPtr(HwDeviceExtension);
+   SiSInitPtr(SiS_Pr, HwDeviceExtension);
 
-   SiSRegInit(BaseAddr);
+   SiSRegInit(SiS_Pr, BaseAddr);
 
-   SiSInitPCIetc(HwDeviceExtension);
+   SiS_Pr->SiS_VGAINFO = SiS_GetSetMMIOReg(pScrn, 0x489, 0xff);
 
-   SiSSetLVDSetc(HwDeviceExtension, ModeNo);
+   SiSInitPCIetc(SiS_Pr, HwDeviceExtension);
+
+   SiSSetLVDSetc(SiS_Pr, HwDeviceExtension, ModeNo);
+
+   SiSDetermineROMUsage(SiS_Pr, HwDeviceExtension, ROMAddr);
 
    /* TW: We don't clear the buffer under X */
-   flag_clearbuffer=0;
+   SiS_Pr->SiS_flag_clearbuffer=0;
 
    /* TW: Save ModeNo so we can set it from within SetMode for CRT1 */
    pSiSEnt->CRT2ModeNo = ModeNo;
    pSiSEnt->CRT2DMode = mode;
 
    /* TW: We can't set CRT2 mode before CRT1 mode is set */
-   if (pSiSEnt->CRT1ModeNo == -1) {
-   	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+   if(pSiSEnt->CRT1ModeNo == -1) {
+   	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 		"Setting CRT2 mode delayed until after setting CRT1 mode\n");
    	return TRUE;
    }
 
-   xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Setting mode 0x%x on CRT2\n", ModeNo);
+   xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode 0x%x on CRT2\n", ModeNo);
 
-   /* SiS_PresetScratchregister(SiS_P3d4,HwDeviceExtension);      */  		/* add for CRT2  */
-   KeepLockReg = SiS_GetReg1(SiS_P3c4,0x05);
-   SiS_SetReg1(SiS_P3c4,0x05,0x86);                             		/* 1.Openkey */
+   /* 1.Openkey */
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
 
-   temp = SiS_SearchModeID(ROMAddr,ModeNo,&ModeIdIndex);        		/* 2.Get ModeID Table  */
-   if(temp==0)  return(0);
+   SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
+
+   /* 2.Get ModeID */
+   temp = SiS_SearchModeID(SiS_Pr, ROMAddr,&ModeNo,&ModeIdIndex);
+   if(temp == 0)  return(0);
 
    /* TW: Determine VBType (301,301B,301LV,302B,302LV) */
-   SiS_GetVBType(BaseAddr);
+   SiS_GetVBType(SiS_Pr, BaseAddr,HwDeviceExtension);
+
+   /* TW: Get VB information (connectors, connected devices) */
+   SiS_GetVBInfo(SiS_Pr, BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+   SiS_SetHiVision(SiS_Pr, BaseAddr,HwDeviceExtension);
+   SiS_GetLCDResInfo(SiS_Pr, ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
 
-   SiS_GetVBInfo301(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);   	/*add for CRT2 */
-   SiS_GetLCDResInfo301(ROMAddr,SiS_P3d4,ModeNo,ModeIdIndex);   		/*add for CRT2 */
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
+          /* TW: I am not sure the flag's name is correct */
+          if(ModeNo != 0x10)  SiS_Pr->SiS_SetFlag |= CRT2IsVGA;
+      }
+   }
 
+   /* Set mode on CRT2 */
    switch (HwDeviceExtension->ujVBChipID) {
      case VB_CHIP_301:
-     case VB_CHIP_301B:    /*for Linux & WinCE to open*/
-        SiS_SetCRT2Group301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);         /*add for CRT2 */
-        break;
+     case VB_CHIP_301B:
+     case VB_CHIP_301LV:
+     case VB_CHIP_301LVX:
      case VB_CHIP_302:
-        SiS_SetCRT2Group301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
+     case VB_CHIP_302B:
+     case VB_CHIP_302LV:
+     case VB_CHIP_302LVX:
+        SiS_SetCRT2Group301(SiS_Pr, BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
         break;
      case VB_CHIP_303:
-/*      SetCRT2Group302(BaseAddr,ROMAddr,ModeNo, HwDeviceExtension);            add for CRT2   */
         break;
-     case VB_CHIP_UNKNOWN:                                                                                                 /*add for lvds ch7005*/
-        temp=SiS_GetReg1(SiS_P3d4,0x37);
-        if(temp&(ExtChipLVDS|ExtChipTrumpion|ExtChipCH7005)){
-             	SiS_SetCRT2Group301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
-        }
+     case VB_CHIP_UNKNOWN:
+        if (SiS_Pr->SiS_IF_DEF_LVDS == 1 || SiS_Pr->SiS_IF_DEF_CH70xx == 1 ||
+	                                               SiS_Pr->SiS_IF_DEF_TRUMPION != 0)
+             	SiS_SetCRT2Group301(SiS_Pr,BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
         break;
    }
 
-   /* TW: SetPitch: Adapt to virtual size & position */
-   SiS_SetPitchCRT2(pScrn, BaseAddr);
+   SiS_DisplayOn(SiS_Pr);
+   SiS_SetReg3(SiS_Pr->SiS_P3c6,0xFF);
 
-   /* Backup/Set ModeNo in MMIO */
-   /* SiS_GetSetModeID(pScrn,ModeNo); */
+   if((HwDeviceExtension->jChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 0)) {
+      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+          SiS_Handle301B_1400x1050(SiS_Pr, ModeNo);
+      }
+   }
 
-   if(KeepLockReg==0xA1) SiS_SetReg1(SiS_P3c4,0x05,0x86); /* 05/02/01 ynlai */
-   else SiS_SetReg1(SiS_P3c4,0x05,0x00);
+   /* TW: SetPitch: Adapt to virtual size & position */
+   if(ModeNo > 0x13) {
+       SiS_SetPitchCRT2(SiS_Pr, pScrn, BaseAddr);
+   }
 
    return TRUE;
 }
@@ -1978,1440 +2217,1662 @@
 #ifdef LINUX_XF86
 /* TW: We need pScrn for setting the pitch correctly */
 BOOLEAN
-SiSSetMode(PSIS_HW_DEVICE_INFO HwDeviceExtension,ScrnInfoPtr pScrn,USHORT ModeNo)
+SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch)
 #else
 BOOLEAN
-SiSSetMode(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo)
+SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo)
 #endif
 {
    ULONG   temp;
    USHORT  ModeIdIndex,KeepLockReg;
-   ULONG   ROMAddr  = (ULONG)HwDeviceExtension->pjVirtualRomBase;
+   UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
    USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
 
-   SiSInitPtr(HwDeviceExtension);
+   SiSInitPtr(SiS_Pr, HwDeviceExtension);
+
+   SiSRegInit(SiS_Pr, BaseAddr);
 
-   SiSRegInit(BaseAddr);
+#ifdef LINUX_XF86
+   if(pScrn) SiS_Pr->SiS_VGAINFO = SiS_GetSetMMIOReg(pScrn, 0x489, 0xff);
+   else
+#endif
+         SiS_Pr->SiS_VGAINFO = 0x11;
+
+   SiSInitPCIetc(SiS_Pr, HwDeviceExtension);
 
-   SiSInitPCIetc(HwDeviceExtension);
+   SiSSetLVDSetc(SiS_Pr, HwDeviceExtension, ModeNo);
 
-   SiSSetLVDSetc(HwDeviceExtension, ModeNo);
+   SiSDetermineROMUsage(SiS_Pr, HwDeviceExtension, ROMAddr);
+
+   /* TW: Shift the clear-buffer-bit away */
+   ModeNo = ((ModeNo & 0x80) << 8) | (ModeNo & 0x7f);
 
 #ifdef LINUX_XF86
-   /* TW: We don't clear the buffer under X */
-   ModeNo |= 0x80;
+   /* TW: We never clear the buffer in X */
+   ModeNo |= 0x8000;
 #endif
 
-   if(ModeNo&0x80) {
-     	ModeNo=ModeNo&0x7F;
-     	flag_clearbuffer=0;
+   if(ModeNo & 0x8000) {
+     	ModeNo &= 0x007F;
+     	SiS_Pr->SiS_flag_clearbuffer = 0;
    } else {
-     	flag_clearbuffer=1;
+     	SiS_Pr->SiS_flag_clearbuffer = 1;
    }
 
-   SiS_PresetScratchregister(SiS_P3d4,HwDeviceExtension);       		/* add for CRT2  */
-   KeepLockReg = SiS_GetReg1(SiS_P3c4,0x05);
-   SiS_SetReg1(SiS_P3c4,0x05,0x86);                             		/* 1.Openkey */
+   /* 1.Openkey */
+   KeepLockReg = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x05);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
 
-   temp = SiS_SearchModeID(ROMAddr,ModeNo,&ModeIdIndex);        		/* 2.Get ModeID Table  */
-   if(temp==0)  return(0);
+   SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
+
+   /* 2.Get ModeID Table  */
+   temp = SiS_SearchModeID(SiS_Pr,ROMAddr,&ModeNo,&ModeIdIndex);
+   if(temp == 0) return(0);
 
    /* TW: Determine VBType (301,301B,301LV,302B,302LV) */
-   SiS_GetVBType(BaseAddr);
+   SiS_GetVBType(SiS_Pr,BaseAddr,HwDeviceExtension);
+
+   /* TW: Init/restore some VB registers */
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+         if(ROMAddr && SiS_Pr->SiS_UseROM) {
+           temp = ROMAddr[VB310Data_1_2_Offset];
+	   temp |= 0x40;
+           SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x02,temp);
+	   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10);
+         }
+      }
+   }
 
-   SiS_GetVBInfo301(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);   	/*add for CRT2 */
-   SiS_GetLCDResInfo301(ROMAddr,SiS_P3d4,ModeNo,ModeIdIndex);   		/*add for CRT2 */
+   /* TW: Get VB information (connectors, connected devices) */
+   SiS_GetVBInfo(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+   SiS_SetHiVision(SiS_Pr,BaseAddr,HwDeviceExtension);
+   SiS_GetLCDResInfo(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+
+   /* 3. Check memory size */
+   temp = SiS_CheckMemorySize(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex);
+   if(!temp) return(0);
+
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
+          /* TW: I am not sure the flag's name is correct */
+          if(ModeNo != 0x10)  SiS_Pr->SiS_SetFlag |= CRT2IsVGA;
+      }
+   }
 
-   temp=SiS_CheckMemorySize(ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex);    	/*3.Check memory size */
-   if(temp==0) return(0);
-   if(SiS_VBInfo&(SetSimuScanMode|SetCRT2ToLCDA)) {				/*301b*/
-   	SiS_SetCRT1Group(ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex);
+   /* TW: Set mode on CRT1 */
+   if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SetCRT2ToLCDA)) {
+   	SiS_SetCRT1Group(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex,BaseAddr);
    } else {
-     if(!(SiS_VBInfo&SwitchToCRT2)) {
-       	SiS_SetCRT1Group(ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex);
+     if(!(SiS_Pr->SiS_VBInfo & SwitchToCRT2)) {
+       	SiS_SetCRT1Group(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex,BaseAddr);
      }
    }
 
-   if(SiS_VBInfo&(SetSimuScanMode|SwitchToCRT2|SetCRT2ToLCDA)) {		/*301b*/
+   /* TW: Set mode on CRT2 */
+   if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2 | SetCRT2ToLCDA)) {
      switch (HwDeviceExtension->ujVBChipID) {
      case VB_CHIP_301:
-     case VB_CHIP_301B:    /*for Linux & WinCE to open*/
-        SiS_SetCRT2Group301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);        /*add for CRT2 */
-        break;
+     case VB_CHIP_301B:
+     case VB_CHIP_301LV:
+     case VB_CHIP_301LVX:
      case VB_CHIP_302:
-        SiS_SetCRT2Group301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
+     case VB_CHIP_302B:
+     case VB_CHIP_302LV:
+     case VB_CHIP_302LVX:
+        SiS_SetCRT2Group301(SiS_Pr,BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
         break;
      case VB_CHIP_303:
-/*      SetCRT2Group302(BaseAddr,ROMAddr,ModeNo, HwDeviceExtension);             add for CRT2   */
         break;
-     case VB_CHIP_UNKNOWN:                                                                                                 /*add for lvds ch7005*/
-        temp=SiS_GetReg1(SiS_P3d4,0x37);
-        if(temp&(ExtChipLVDS|ExtChipTrumpion|ExtChipCH7005)){
-             	SiS_SetCRT2Group301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
-        }
+     case VB_CHIP_UNKNOWN:
+	if(SiS_Pr->SiS_IF_DEF_LVDS == 1   ||
+	   SiS_Pr->SiS_IF_DEF_CH70xx != 0 ||
+	   SiS_Pr->SiS_IF_DEF_TRUMPION != 0)
+             	SiS_SetCRT2Group301(SiS_Pr,BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
         break;
      }
    }
 
+
+   if((HwDeviceExtension->jChipType > SIS_315PRO) && (SiS_Pr->SiS_IF_DEF_LVDS == 0)) {
+      /* TW: For 650 only! */
+      SiS_HandleCRT1(SiS_Pr);
+   }
+
+   SiS_DisplayOn(SiS_Pr);
+   SiS_SetReg3(SiS_Pr->SiS_P3c6,0xFF);
+
+   if((HwDeviceExtension->jChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 0)) {
+      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+          SiS_Handle301B_1400x1050(SiS_Pr, ModeNo);
+      }
+   }
+
 #ifdef LINUX_XF86
-   /* TW: SetPitch: Adapt to virtual size & position */
-   SiS_SetPitch(pScrn, BaseAddr);
-   /* Backup/Set ModeNo in MMIO */
-   SiS_GetSetModeID(pScrn,ModeNo);
+   if(pScrn) {
+      /* TW: SetPitch: Adapt to virtual size & position */
+      if((ModeNo > 0x13) && (dosetpitch)) {
+         SiS_SetPitch(SiS_Pr, pScrn, BaseAddr);
+      }
+
+      /* Backup/Set ModeNo in MMIO */
+      SiS_GetSetModeID(pScrn, ModeNo);
+   }
 #endif
 
 #ifndef LINUX_XF86  /* TW: We never lock registers in XF86 */
-   if(KeepLockReg==0xA1) SiS_SetReg1(SiS_P3c4,0x05,0x86);
-   else SiS_SetReg1(SiS_P3c4,0x05,0x00);
+   if(KeepLockReg == 0xA1) SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
+   else SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x00);
 #endif
 
    return TRUE;
 }
 
 void
-SetEnableDstn()		/* TW: Called from sis_main.c */
+SetEnableDstn(SiS_Private *SiS_Pr)	/* TW: Called from sis_main.c */
 {
-   SiS_IF_DEF_DSTN=1;   /*for 550 dstn*/
+   /* For 550 dstn */
+   SiS_Pr->SiS_IF_DEF_DSTN = 1;
 }
 
 void
-SiS_SetCRT1Group(ULONG ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                 USHORT ModeNo,USHORT ModeIdIndex)
+SiS_HandleCRT1(SiS_Private *SiS_Pr)
 {
-  USHORT  StandTableIndex,RefreshRateTableIndex;
-  USHORT  temp;
+  /* TW: Do this on 650 only! */
 
-  /*SiS_SetReg1(SiS_P3d4,0x34,ModeNo);*/
-  SiS_CRT1Mode = ModeNo;
-  /* set CR34->CRT1 ModeNo for CRT2 FIFO */
-  StandTableIndex = SiS_GetModePtr(ROMAddr,ModeNo,ModeIdIndex); /* 4.GetModePtr  */
-  SiS_SetSeqRegs(ROMAddr,StandTableIndex);                      /* 5.SetSeqRegs  */
-  SiS_SetMiscRegs(ROMAddr,StandTableIndex);                     /* 6.SetMiscRegs */
-  SiS_SetCRTCRegs(ROMAddr,HwDeviceExtension,StandTableIndex);   /* 7.SetCRTCRegs */
-  SiS_SetATTRegs(ROMAddr,StandTableIndex);                      /* 8.SetATTRegs  */
-  SiS_SetGRCRegs(ROMAddr,StandTableIndex);                      /* 9.SetGRCRegs  */
-  SiS_ClearExt1Regs();                                          /* 10.Clear Ext1Regs */
-  temp=~ProgrammingCRT2;                                        /* 11.GetRatePtr  */
-  SiS_SetFlag=SiS_SetFlag&temp;
-  SiS_SelectCRT2Rate=0;
+  /* TW: No, we don't do this at all. There is a new
+   * CRT1-is-connected-at-boot-time logic in the 650, which
+   * confuses our own. So just clear the bit and skip the rest.
+   */
 
-#ifdef LINUX_XF86
-  xf86DrvMsg(0, X_INFO, "VBType = %x, LVDS=%d, VBInfo=%x\n",
-                    SiS_VBType, SiS_IF_DEF_LVDS, SiS_VBInfo);
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x63,0xbf);
+
+#if 0
+  if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x15) & 0x01))
+     SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x63,0x40);
+  }
 #endif
+}
 
-  /*301b*/
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))) {
-      if(SiS_VBInfo&SetCRT2ToLCDA) {
-	 SiS_SetFlag=SiS_SetFlag|ProgrammingCRT2;
-      }
+void
+SiS_Handle301B_1400x1050(SiS_Private *SiS_Pr, USHORT ModeNo)
+{
+  if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30) & SetCRT2ToLCD) {
+     if(ModeNo <= 0x13) {
+        if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & (SetNotSimuMode >> 8)) {
+	   SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xFC);
+	}
+     }
   }
-  /*end 301b*/
+}
 
-  RefreshRateTableIndex=SiS_GetRatePtrCRT2(ROMAddr,ModeNo,ModeIdIndex);   /* 11.GetRatePtr */
+void
+SiS_SetCRT1Group(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                 USHORT ModeNo,USHORT ModeIdIndex,USHORT BaseAddr)
+{
+  USHORT  StandTableIndex,RefreshRateTableIndex;
 
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))) {
-      if(!(SiS_VBInfo&SetCRT2ToLCDA)) {
-	 SiS_SetFlag=SiS_SetFlag&(~ProgrammingCRT2);
-      }
+  SiS_Pr->SiS_CRT1Mode = ModeNo;
+  StandTableIndex = SiS_GetModePtr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
+  if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+    if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2)) {
+       SiS_DisableBridge(SiS_Pr,HwDeviceExtension,BaseAddr);
+    }
   }
 
-  if (RefreshRateTableIndex!=0xFFFF) {
-    SiS_SetSync(ROMAddr,RefreshRateTableIndex);                          /* 12.SetSync */
-    SiS_SetCRT1CRTC(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);   /* 13.SetCRT1CRTC  */
-    SiS_SetCRT1Offset(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwDeviceExtension);   /* 14.SetCRT1Offset */
-    SiS_SetCRT1VCLK(ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension,RefreshRateTableIndex);     /* 15.SetCRT1VCLK  */
+  SiS_SetSeqRegs(SiS_Pr,ROMAddr,StandTableIndex);
+  SiS_SetMiscRegs(SiS_Pr,ROMAddr,StandTableIndex);
+  SiS_SetCRTCRegs(SiS_Pr,ROMAddr,HwDeviceExtension,StandTableIndex);
+  SiS_SetATTRegs(SiS_Pr,ROMAddr,StandTableIndex,ModeNo,HwDeviceExtension);
+  SiS_SetGRCRegs(SiS_Pr,ROMAddr,StandTableIndex);
+  SiS_ClearExt1Regs(SiS_Pr,HwDeviceExtension);
+  SiS_ResetCRT1VCLK(SiS_Pr,ROMAddr,HwDeviceExtension);
+
+  SiS_Pr->SiS_SelectCRT2Rate = 0;
+  SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
+
+#ifdef LINUX_XF86
+  xf86DrvMsg(0, X_PROBED, "(init: VBType=0x%04x, VBInfo=0x%04x)\n",
+                    SiS_Pr->SiS_VBType, SiS_Pr->SiS_VBInfo);
+#endif
+
+  if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) {
+     if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+        SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+     }
+  }
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+	SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+  }
+
+  RefreshRateTableIndex = SiS_GetRatePtrCRT2(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+	SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
   }
+
+  if (RefreshRateTableIndex != 0xFFFF) {
+    	SiS_SetSync(SiS_Pr,ROMAddr,RefreshRateTableIndex);
+    	SiS_SetCRT1CRTC(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwDeviceExtension);
+    	SiS_SetCRT1Offset(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwDeviceExtension);
+    	SiS_SetCRT1VCLK(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension,RefreshRateTableIndex);
+  }
+
 #ifdef SIS300
+  if(HwDeviceExtension->jChipType == SIS_300){
+     	SiS_SetCRT1FIFO_300(SiS_Pr,ROMAddr,ModeNo,HwDeviceExtension,RefreshRateTableIndex);
+  }
   if((HwDeviceExtension->jChipType == SIS_630)||
+     (HwDeviceExtension->jChipType == SIS_730)||
      (HwDeviceExtension->jChipType == SIS_540)) {
-     	SiS_SetCRT1FIFO2(ROMAddr,ModeNo,HwDeviceExtension,RefreshRateTableIndex);
+     	SiS_SetCRT1FIFO_630(SiS_Pr,ROMAddr,ModeNo,HwDeviceExtension,RefreshRateTableIndex);
   }
 #endif
 #ifdef SIS315H
   if(HwDeviceExtension->jChipType >= SIS_315H) {
-     	SiS_SetCRT1FIFO(ROMAddr,ModeNo,HwDeviceExtension);
+     	SiS_SetCRT1FIFO_310(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
   }
 #endif
-  SiS_SetCRT1ModeRegs(ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex,RefreshRateTableIndex);
-  SiS_SetVCLKState(ROMAddr,HwDeviceExtension,ModeNo,RefreshRateTableIndex);
-#ifdef SIS315H
-  if(HwDeviceExtension->jChipType > SIS_315H) {
-    if (RefreshRateTableIndex!=0xFFFF)
-      	SiS_SetInterlace(ROMAddr,ModeNo,RefreshRateTableIndex);
+
+  SiS_SetCRT1ModeRegs(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex,RefreshRateTableIndex);
+
+  SiS_LoadDAC(SiS_Pr,HwDeviceExtension,ROMAddr,ModeNo,ModeIdIndex);
+
+#ifndef LINUX_XF86
+  if(SiS_Pr->SiS_flag_clearbuffer) {
+        SiS_ClearBuffer(SiS_Pr,HwDeviceExtension,ModeNo);
   }
 #endif
-  SiS_LoadDAC(ROMAddr,ModeNo,ModeIdIndex);
-  if(flag_clearbuffer) SiS_ClearBuffer(HwDeviceExtension,ModeNo);
 
-  if(!(SiS_VBInfo&(SetSimuScanMode|SwitchToCRT2|SetCRT2ToLCDA))) {   /*301b*/
-    SiS_LongWait();
-    SiS_DisplayOn();
+  if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2 | SetCRT2ToLCDA))) {
+        SiS_LongWait(SiS_Pr);
+        SiS_DisplayOn(SiS_Pr);
   }
 }
 
 #ifdef LINUX_XF86
 void
-SiS_SetPitch(ScrnInfoPtr pScrn, UShort BaseAddr)
+SiS_SetPitch(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr)
 {
    SISPtr pSiS = SISPTR(pScrn);
 
-   if (pSiS->VBFlags & DISPTYPE_DISP1) {
-   	SiS_SetPitchCRT1(pScrn, BaseAddr);
+   /* TW: We need to set pitch for CRT1 if bridge is in SlaveMode, too */
+   if( (pSiS->VBFlags & DISPTYPE_DISP1) ||
+       ( (pSiS->VBFlags & VB_VIDEOBRIDGE) &&
+         ( ((pSiS->VGAEngine == SIS_300_VGA) && (SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0xa0) == 0x20) ||
+           ((pSiS->VGAEngine == SIS_315_VGA) && (SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x50) == 0x10) ) ) ) {
+   	SiS_SetPitchCRT1(SiS_Pr, pScrn, BaseAddr);
    }
    if (pSiS->VBFlags & DISPTYPE_DISP2) {
-   	SiS_SetPitchCRT2(pScrn, BaseAddr);
+   	SiS_SetPitchCRT2(SiS_Pr, pScrn, BaseAddr);
    }
 }
 
 void
-SiS_SetPitchCRT1(ScrnInfoPtr pScrn, UShort BaseAddr)
+SiS_SetPitchCRT1(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr)
 {
     SISPtr pSiS = SISPTR(pScrn);
     ULong  HDisplay,temp;
 
-    HDisplay = pSiS->scrnOffset / 8;
-    SiS_SetReg1(SiS_P3d4, 0x13, (HDisplay & 0xFF));
-    temp = (SiS_GetReg1(SiS_P3c4, 0x0E) & 0xF0) | (HDisplay>>8);
-    SiS_SetReg1(SiS_P3c4, 0x0E, temp);
+    HDisplay = pSiS->scrnPitch / 8;
+    SiS_SetReg1(SiS_Pr->SiS_P3d4, 0x13, (HDisplay & 0xFF));
+    temp = (SiS_GetReg1(SiS_Pr->SiS_P3c4, 0x0E) & 0xF0) | (HDisplay>>8);
+    SiS_SetReg1(SiS_Pr->SiS_P3c4, 0x0E, temp);
 }
 
 void
-SiS_SetPitchCRT2(ScrnInfoPtr pScrn, UShort BaseAddr)
+SiS_SetPitchCRT2(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr)
 {
     SISPtr pSiS = SISPTR(pScrn);
     ULong  HDisplay,temp;
 
-    HDisplay = pSiS->scrnOffset / 8;
-    SiS_SetReg1(SiS_Part1Port, 0x24, 1);
-    SiS_SetReg1(SiS_Part1Port, 0x07, HDisplay);
-    temp = (SiS_GetReg1(SiS_Part1Port, 0x09) & 0xF0) | (HDisplay>>8);
-    SiS_SetReg1(SiS_Part1Port, 0x09, temp);
+    HDisplay = pSiS->scrnPitch / 8;
+
+    /* Unlock CRT2 */
+    if (pSiS->VGAEngine == SIS_315_VGA)
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2F, 0xFF, 0x01);
+    else
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x24, 0xFF, 0x01);
+
+    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07, (HDisplay & 0xFF));
+    temp = (SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x09) & 0xF0) | ((HDisplay >> 8) & 0xFF);
+    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x09, temp);
 }
 #endif
 
+/* TW: Checked against 650/301 and 630/301B BIOS */
+/* TW: Re-written for 650/301LVx 1.10.6s BIOS */
 void
-SiS_GetVBType(USHORT BaseAddr)
+SiS_GetVBType(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT flag;
+  USHORT flag=0, rev=0, nolcd=0;
+
+  SiS_Pr->SiS_VBType = 0;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) return;
+
+  flag = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x00);
+
+  /* TW: Illegal values not welcome... */
+  if(flag > 10) return;
+
+  rev = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x01);
 
-  flag=SiS_GetReg1(SiS_Part4Port,0x00);
-  /* TW: On pure LVDS, Part4 is not assigned and returns 0xff */
-  if (flag >= 4) return;
-  /* TW end */
   if (flag >= 2) {
-  	flag=SiS_GetReg1(SiS_Part4Port,0x01);
-        if(flag>=0xB0){
-            	SiS_VBType=VB_SIS302B;
-            	if(flag>=0xD0)
-               		SiS_VBType=VB_SIS302LV;
+        SiS_Pr->SiS_VBType = VB_SIS302B;
+  } else if (flag == 1) {
+        SiS_Pr->SiS_VBType = VB_SIS301;
+        if(rev >= 0xB0) {
+            	SiS_Pr->SiS_VBType = VB_SIS301B;
+		if(HwDeviceExtension->jChipType >= SIS_315H) {
+    		    nolcd = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x23);
+                    if(!(nolcd & 0x02))
+       	                SiS_Pr->SiS_VBType |= VB_NoLCD;
+		}
         }
-  } else {
-        flag=SiS_GetReg1(SiS_Part4Port,0x01);
-        if(flag>=0xB0){
-            	SiS_VBType=VB_SIS301B;
-            	if(flag>=0xD0)
-               		SiS_VBType=VB_SIS301LV;
-        } else
-            SiS_VBType=VB_SIS301;
-  }
-  flag=SiS_GetReg1(SiS_Part4Port,0x23);       /*301dlvds*/
-  if(!(flag&0x02))
-      	SiS_VBType=SiS_VBType|VB_NoLCD;
+  }
+  if(SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS302B)) {
+        if(rev >= 0xD0) {
+	        SiS_Pr->SiS_VBType &= ~(VB_SIS301B | VB_SIS302B);
+          	SiS_Pr->SiS_VBType |= VB_SIS30xLV;
+		SiS_Pr->SiS_VBType &= ~(VB_NoLCD);
+		if(rev >= 0xE0) {
+		    SiS_Pr->SiS_VBType &= ~(VB_SIS30xLV);
+		    SiS_Pr->SiS_VBType |= VB_SIS30xNEW;
+		}
+        }
+  }
 }
 
-/* win2000 MM adapter not support standard mode  */
+/* TW: Checked against 650/301LVx 1.10.6s */
 BOOLEAN
-SiS_SearchModeID(ULONG ROMAddr, USHORT ModeNo,USHORT  *ModeIdIndex)
+SiS_SearchModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT *ModeNo,USHORT *ModeIdIndex)
 {
-#ifndef LINUX_XF86
-   PUCHAR VGA_INFO="\0x11";
-#endif
-   
-   if (ModeNo<=5) ModeNo |= 1;
-   if (ModeNo<=0x13) {
-     /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(SiS_SModeIDTable)/sizeof(SiS_StStruct);(*ModeIdIndex)++) */
-     for (*ModeIdIndex=0;;(*ModeIdIndex)++)
-     {
-       if (SiS_SModeIDTable[*ModeIdIndex].St_ModeID==ModeNo) break;
-       if (SiS_SModeIDTable[*ModeIdIndex].St_ModeID==0xFF)  return FALSE;
-     }
-#ifndef LINUX_XF86
-#ifdef TC
-     VGA_INFO = (PUCHAR) MK_FP(0,0x489);
-#endif
-     if (ModeNo==0x07) {
-        if ((*VGA_INFO&0x10)!=0) (*ModeIdIndex)++; /* 400 lines */
-        /* else 350 lines */
-     }
-     if (ModeNo<=3) {
-       if ((*VGA_INFO&0x80)==0) {
-         (*ModeIdIndex)++;
-         if ((*VGA_INFO&0x10)!=0)
-           (*ModeIdIndex)++;; /* 400 lines  */
+   UCHAR VGAINFO = SiS_Pr->SiS_VGAINFO;
+
+   if(*ModeNo <= 0x13) {
+
+      if((*ModeNo) <= 5) (*ModeNo) |= 1;
+
+      for (*ModeIdIndex=0;;(*ModeIdIndex)++) {
+         if (SiS_Pr->SiS_SModeIDTable[*ModeIdIndex].St_ModeID == (*ModeNo)) break;
+         if (SiS_Pr->SiS_SModeIDTable[*ModeIdIndex].St_ModeID == 0xFF)   return FALSE;
+      }
+
+      if(*ModeNo == 0x07) {
+          if(VGAINFO & 0x10) (*ModeIdIndex)++;   /* 400 lines */
+          /* else 350 lines */
+      }
+      if(*ModeNo <= 3) {
+         if(!(VGAINFO & 0x80)) (*ModeIdIndex)++;
+         if(VGAINFO & 0x10)    (*ModeIdIndex)++; /* 400 lines  */
          /* else 350 lines  */
-       }
-       /* else 200 lines  */
-     }
-#endif  /* NOT X86 */
-   }
-   else 
-   {
-     /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(SiS_EModeIDTable)/sizeof(SiS_ExtStruct);(*ModeIdIndex)++) */
-     for (*ModeIdIndex=0;;(*ModeIdIndex)++)
-     {
-       if (SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID==ModeNo) break;
-       if (SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID==0xFF) return FALSE;
-     }
+      }
+      /* else 200 lines  */
+
+   } else {
+
+      for (*ModeIdIndex=0;;(*ModeIdIndex)++) {
+         if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo)) break;
+         if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)   return FALSE;
+      }
+
    }
    return TRUE;
 }
 
-/*add for 300 oem util for search VBModeID*/
+/* For SiS 300 oem util: Search VBModeID */
 BOOLEAN
-SiS_SearchVBModeID(ULONG ROMAddr, USHORT ModeNo)
+SiS_SearchVBModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT *ModeNo)
 {
    USHORT ModeIdIndex;
-#ifdef TC
-   PUCHAR VGA_INFO;
-#endif
-   
-   if (ModeNo<=5) ModeNo |= 1;
-    /* for (ModeIdIndex=0;ModeIdIndex<sizeof(SiS_SModeIDTable)/sizeof(SiS_StStruct);(*ModeIdIndex)++) */
-     for (ModeIdIndex=0;;(ModeIdIndex)++)
-     {
-       if (SiS_VBModeIDTable[ModeIdIndex].ModeID==ModeNo) break;
-       if (SiS_VBModeIDTable[ModeIdIndex].ModeID==0xFF)  return FALSE;
-     }
-#ifdef TC
-     VGA_INFO = (PUCHAR) MK_FP(0,0x489);
-     if (ModeNo==0x07) {
-	if ((*VGA_INFO&0x10)!=0) (ModeIdIndex)++; /* 400 lines */
-	/* else 350 lines */
-     }
-     if (ModeNo<=3) {
-       if ((*VGA_INFO&0x80)==0) {
-	 (ModeIdIndex)++;
-         if ((*VGA_INFO&0x10)!=0)
-	   (ModeIdIndex)++;; /* 400 lines  */
-	 /* else 350 lines  */
-       }
-       /* else 200 lines  */
-     }
-#endif
-  return ((BOOLEAN)ModeIdIndex);
+   UCHAR VGAINFO = SiS_Pr->SiS_VGAINFO;
+
+   if(*ModeNo <= 5) *ModeNo |= 1;
+
+   for(ModeIdIndex=0; ; ModeIdIndex++) {
+       if (SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].ModeID == *ModeNo) break;
+       if (SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].ModeID == 0xFF)   return FALSE;
+   }
+
+   if(*ModeNo != 0x07) {
+        if(*ModeNo > 0x03) return ((BOOLEAN)ModeIdIndex);
+	if(VGAINFO & 0x80) return ((BOOLEAN)ModeIdIndex);
+	ModeIdIndex++;
+   }
+   if(VGAINFO & 0x10) ModeIdIndex++;   /* 400 lines */
+	                               /* else 350 lines */
+   return ((BOOLEAN)ModeIdIndex);
 }
-/*end oem util */
 
+/* TW: Checked against 630/301B, 315 1.09 and 650/301LVx 1.10.6s BIOS */
+/* TW: Modified */
 BOOLEAN
-SiS_CheckMemorySize(ULONG ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+SiS_CheckMemorySize(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
                     USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT memorysize,modeflag,temp;
-
-  if((HwDeviceExtension->jChipType == SIS_550)||   /* 05/02/01 ynlai for sis550 */
-     (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-     (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-     (HwDeviceExtension->jChipType == SIS_650))    /* 09/03/01 chiawen for 650 */
-    return(TRUE);
+  USHORT memorysize,modeflag;
+  ULONG  temp;
 
   if (ModeNo<=0x13) {
-    modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
   } else {
-    modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+      modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
   }
 
-/*  ModeType=modeflag&ModeInfoFlag;                           	   Get mode type  */
-
-  memorysize=modeflag&MemoryInfoFlag;
-  memorysize=memorysize>MemorySizeShift;
-  memorysize++;                                        		/* Get memory size */
+  memorysize = modeflag & MemoryInfoFlag;
+  memorysize >>= MemorySizeShift;			/* Get required memory size */
+  memorysize++;
 
-  temp=SiS_GetReg1(SiS_P3c4,0x14);                             	/* Get DRAM Size    */
-  if((HwDeviceExtension->jChipType == SIS_315H)||
-     (HwDeviceExtension->jChipType == SIS_315PRO)) {
-    temp= 1 << ((temp&0x0F0)>>4);				/* 315 */
-    if ((temp&0x0c)==0x08) { /* DDR asymetric */
-      temp += temp/2;
-    } else {
-      if ((temp&0x0c)!=0) temp <<= 1;
-    }
-  } else { 							/* 300, 540, 630, 730 */
-    temp=temp&0x3F;
-    temp++;
-  }
+  temp = GetDRAMSize(SiS_Pr, HwDeviceExtension);       	/* Get adapter memory size */
+  temp /= (1024*1024);   				/* (in MB) */
 
-  if(temp<memorysize) return(FALSE);
+  if(temp < memorysize) return(FALSE);
   else return(TRUE);
 }
 
 UCHAR
-SiS_GetModePtr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SiS_GetModePtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
    UCHAR index;
 
    if(ModeNo<=0x13) {
-     	index = SiS_SModeIDTable[ModeIdIndex].St_StTableIndex;
+     	index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_StTableIndex;
    } else {
-     	if(SiS_ModeType <= 0x02) index=0x1B;    /* 02 -> ModeEGA  */
+     	if(SiS_Pr->SiS_ModeType <= 0x02) index=0x1B;    /* 02 -> ModeEGA  */
      	else index=0x0F;
    }
-   return index;       /* Get SiS_StandTable index  */
+   return index;
 }
 
+/* TW: Checked against 300, 650/LVDS (1.10.07, 1.10a) and 650/301LV BIOS */
 void
-SiS_SetSeqRegs(ULONG ROMAddr,USHORT StandTableIndex)
+SiS_SetSeqRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex)
 {
    UCHAR SRdata;
    USHORT i;
 
-   SiS_SetReg1(SiS_P3c4,0x00,0x03);           /* Set SR0  */
-   SRdata=SiS_StandTable[StandTableIndex].SR[0];
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x00,0x03);           	/* Set SR0  */
 
-   if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-      	if(SiS_VBInfo&SetCRT2ToLCDA) {
-        	SRdata=SRdata|0x01;
+   SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0];
+
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      	if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+        	SRdata |= 0x01;
         }
    }
-
-   if(SiS_IF_DEF_LVDS==1) {
-     if(SiS_IF_DEF_CH7005==1) {
-       if(SiS_VBInfo&SetCRT2ToTV) {
-         if(SiS_VBInfo&SetInSlaveMode) {
-           SRdata=SRdata|0x01;        					/* 8 dot clock  */
+   if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+     if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+       if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+         if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+           SRdata |= 0x01;        			/* 8 dot clock  */
          }
        }
      }
-     if(SiS_VBInfo&SetCRT2ToLCD) {
-       if(SiS_VBInfo&SetInSlaveMode) {
-         SRdata=SRdata|0x01;          					/* 8 dot clock  */
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+       if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+         SRdata |= 0x01;          			/* 8 dot clock  */
        }
      }
    }
 
-   SRdata=SRdata|0x20;                					/* screen off  */
-   SiS_SetReg1(SiS_P3c4,0x01,SRdata);         				/* Set SR1 */
+   SRdata |= 0x20;                			/* screen off  */
+
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x01,SRdata);
+
    for(i=02;i<=04;i++) {
-     	SRdata=SiS_StandTable[StandTableIndex].SR[i-1];   		/* Get SR2,3,4 from file */
-     	SiS_SetReg1(SiS_P3c4,i,SRdata);                       		/* Set SR2 3 4 */
+       	SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1];
+     	SiS_SetReg1(SiS_Pr->SiS_P3c4,i,SRdata);
    }
 }
 
+/* Checked against 300, 650/301LVx 1.10.6s and 650/LVDS 1.10.07 BIOS */
 void
-SiS_SetMiscRegs(ULONG ROMAddr,USHORT StandTableIndex)
+SiS_SetMiscRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex)
 {
    UCHAR Miscdata;
 
-   Miscdata = SiS_StandTable[StandTableIndex].MISC;    /* Get Misc from file */
-   if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))) {
-      if(SiS_VBInfo&SetCRT2ToLCDA) {
-        Miscdata=Miscdata|0x0C;
+   Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC;
+
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+        Miscdata |= 0x0C;
       }
     }
-   SiS_SetReg3(SiS_P3c2,Miscdata);                         /* Set Misc(3c2) */
+
+   SiS_SetReg3(SiS_Pr->SiS_P3c2,Miscdata);
 }
 
+/* Checked against 300, 650/LVDS (1.10.07) and 650/301LVx (1.10.6s) BIOS (630 code still there!) */
 void
-SiS_SetCRTCRegs(ULONG ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+SiS_SetCRTCRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
                 USHORT StandTableIndex)
 {
   UCHAR CRTCdata;
   USHORT i;
 
-  CRTCdata=(UCHAR)SiS_GetReg1(SiS_P3d4,0x11);
-  CRTCdata=CRTCdata&0x7f;
-  SiS_SetReg1(SiS_P3d4,0x11,CRTCdata);                     /* Unlock CRTC */
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);                       /* Unlock CRTC */
 
   for(i=0;i<=0x18;i++) {
-     CRTCdata=SiS_StandTable[StandTableIndex].CRTC[i];     /* Get CRTC from file */
-     SiS_SetReg1(SiS_P3d4,i,CRTCdata);                     /* Set CRTC(3d4) */
+     CRTCdata=SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,i,CRTCdata);                     /* Set CRTC(3d4) */
   }
-  if((HwDeviceExtension->jChipType==SIS_630)&&
-     (HwDeviceExtension->jChipRevision==0x30)) {           /* for 630S0 */
-    if(SiS_VBInfo&SetInSlaveMode) {
-      if(SiS_VBInfo&(SetCRT2ToLCD|SetCRT2ToTV)) {
-        SiS_SetReg1(SiS_P3d4,0x18,0xFE);
+  if( ( (HwDeviceExtension->jChipType == SIS_630) ||
+        (HwDeviceExtension->jChipType == SIS_730) )  &&
+      (HwDeviceExtension->jChipRevision >= 0x30) ) {       	   /* for 630S0 */
+    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+      if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) {
+        SiS_SetReg1(SiS_Pr->SiS_P3d4,0x18,0xFE);
       }
     }
   }
 }
 
+/* TW: Checked against 300, 650/LVDS (1.10.07), 650/301LVx (1.10.6s) and 630/301B BIOS */
 void
-SiS_SetATTRegs(ULONG ROMAddr,USHORT StandTableIndex)
+SiS_SetATTRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex,USHORT ModeNo,
+               PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
    UCHAR ARdata;
    USHORT i;
 
    for(i=0;i<=0x13;i++) {
-    ARdata = SiS_StandTable[StandTableIndex].ATTR[i];     /* Get AR for file  */
-    if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-      if(SiS_VBInfo&SetCRT2ToLCDA) {
-         if(i==0x13) ARdata=0;
+    ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
+#if 0
+    if((i <= 0x0f) || (i == 0x11)) {
+        if(ds:489 & 0x08) {
+	   continue;
+        }
+    }
+#endif
+    if(i == 0x13) {
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)  ARdata=0;
+      }
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+        if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+          if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+            if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0;
+          }
+        }
+      }
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+        if(HwDeviceExtension->jChipType >= SIS_315H) {
+	  /* TW: From 650/LVDS 1.10.07, 1.10a; 650/301LVx 1.10.6s */
+	  ARdata = 0;
+	} else {
+          if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+	     ARdata=0;
+          }
+	}
       }
     }
-    if (SiS_IF_DEF_LVDS==1) {                             /*for LVDS  */
-       if(SiS_IF_DEF_CH7005==1) {
-         if(SiS_VBInfo&SetCRT2ToTV) {
-           if(SiS_VBInfo&SetInSlaveMode) {
-             if(i==0x13) ARdata=0;
-           }
-         }
-       }
-       if(SiS_VBInfo&SetCRT2ToLCD) {
-         if(SiS_VBInfo&SetInSlaveMode) {
-           if(SiS_LCDInfo&LCDNonExpanding) {
-             if(i==0x13) ARdata=0;
-           }
-         }
-       }
-     }
-     SiS_GetReg2(SiS_P3da);                              /* reset 3da  */
-     SiS_SetReg3(SiS_P3c0,i);                            /* set index  */
-     SiS_SetReg3(SiS_P3c0,ARdata);                       /* set data   */
+    SiS_GetReg2(SiS_Pr->SiS_P3da);                              /* reset 3da  */
+    SiS_SetReg3(SiS_Pr->SiS_P3c0,i);                            /* set index  */
+    SiS_SetReg3(SiS_Pr->SiS_P3c0,ARdata);                       /* set data   */
    }
-   SiS_GetReg2(SiS_P3da);                                /* reset 3da  */
-   SiS_SetReg3(SiS_P3c0,0x14);                           /* set index  */
-   SiS_SetReg3(SiS_P3c0,0x00);                           /* set data   */
+   SiS_GetReg2(SiS_Pr->SiS_P3da);                               /* reset 3da  */
+   SiS_SetReg3(SiS_Pr->SiS_P3c0,0x14);                          /* set index  */
+   SiS_SetReg3(SiS_Pr->SiS_P3c0,0x00);                          /* set data   */
 
-   SiS_GetReg2(SiS_P3da);                                /* Enable Attribute  */
-   SiS_SetReg3(SiS_P3c0,0x20);
+   SiS_GetReg2(SiS_Pr->SiS_P3da);                               /* Enable Attribute  */
+   SiS_SetReg3(SiS_Pr->SiS_P3c0,0x20);
 }
 
+/* TW: Checked against 300, 650/LVDS (1.10.07, 1.10a) and 650/301LV BIOS */
 void
-SiS_SetGRCRegs(ULONG ROMAddr,USHORT StandTableIndex)
+SiS_SetGRCRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex)
 {
    UCHAR GRdata;
    USHORT i;
 
    for(i=0;i<=0x08;i++) {
-     GRdata = SiS_StandTable[StandTableIndex].GRC[i]; 	  /* Get GR from file */
-     SiS_SetReg1(SiS_P3ce,i,GRdata);                      /* Set GR(3ce) */
+     GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i]; 	  	/* Get GR from file */
+     SiS_SetReg1(SiS_Pr->SiS_P3ce,i,GRdata);                    /* Set GR(3ce) */
    }
 
-   if(SiS_ModeType>ModeVGA) {
-     GRdata=(UCHAR)SiS_GetReg1(SiS_P3ce,0x05);
-     GRdata=GRdata&0xBF;                                  /* 256 color disable */
-     SiS_SetReg1(SiS_P3ce,0x05,GRdata);
+   if(SiS_Pr->SiS_ModeType > ModeVGA) {
+     SiS_SetRegAND(SiS_Pr->SiS_P3ce,0x05,0xBF);			/* 256 color disable */
    }
 }
 
+/* TW: Checked against 650/LVDS (1.10.07, 1.10a), 650/301LVx (1.10.6s) and 630/301B BIOS */
 void
-SiS_ClearExt1Regs()
+SiS_ClearExt1Regs(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT i;
 
-  for(i=0x0A;i<=0x0E;i++) SiS_SetReg1(SiS_P3c4,i,0x00);      /* Clear SR0A-SR0E */
+  for(i=0x0A;i<=0x0E;i++) SiS_SetReg1(SiS_Pr->SiS_P3c4,i,0x00);      /* Clear SR0A-SR0E */
+
+  /* TW: New from 650/LVDS/301LV BIOSes: */
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x37,0xFE);
+  }
 }
 
+/* TW: Checked against 300, 650/LVDS (1.10.07) and 650/301LV BIOS */
 void
-SiS_SetSync(ULONG ROMAddr,USHORT RefreshRateTableIndex)
+SiS_SetSync(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT RefreshRateTableIndex)
 {
   USHORT sync;
   USHORT temp;
 
-  sync = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag >> 8;  /* di+0x00 */
+  sync = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag >> 8;
 
-  sync=sync&0xC0;
-  temp=0x2F;
-  temp=temp|sync;
-  SiS_SetReg3(SiS_P3c2,temp);                                 /* Set Misc(3c2) */
+  sync &= 0xC0;
+  temp = 0x2F | sync;
+  SiS_SetReg3(SiS_Pr->SiS_P3c2,temp);                                 /* Set Misc(3c2) */
 }
 
+/* TW: Checked against 300, 650/LVDS (1.10.07) and 650/301LVx (1.10.6s) BIOS */
 void
-SiS_SetCRT1CRTC(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                USHORT RefreshRateTableIndex)
+SiS_SetCRT1CRTC(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                USHORT RefreshRateTableIndex,
+		PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   UCHAR  index;
-  UCHAR  data;
-  USHORT temp,tempah,i,modeflag,j;
+  USHORT tempah,i,modeflag,j;
+#ifdef SIS315H
+  USHORT temp;
   USHORT ResInfo,DisplayType;
-  SiS_LCDACRT1DataStruct *LCDACRT1Ptr=NULL;
+  const SiS_LCDACRT1DataStruct *LCDACRT1Ptr = NULL;
+#endif
+
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);		/*unlock cr0-7  */
+
+  if(ModeNo<=0x13) {
+        modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else {
+        modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  }
+
+  if((SiS_Pr->SiS_IF_DEF_LVDS == 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+
+#ifdef SIS315H
+
+     /* LCDA */
+
+     temp = SiS_GetLCDACRT1Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+                       RefreshRateTableIndex,&ResInfo,&DisplayType);
 
-  if((SiS_VBType&VB_SIS302B)&&(SiS_VBInfo&SetCRT2ToLCDA)
-  	&& (SiS_IF_DEF_LVDS==0) ) { /* TW: Added LVDS check */
-     /*add crt1ptr*/
-     if(ModeNo<=0x13) {
-       modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-     } else {
-       modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-     }
-     temp= SiS_GetLCDACRT1Ptr(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                       &ResInfo,&DisplayType);
-  
      switch(DisplayType) {
-      case 0 : LCDACRT1Ptr = SiS_LCDACRT1800x600_1;           break;
-      case 1 : LCDACRT1Ptr = SiS_LCDACRT11024x768_1;          break;
-      case 2 : LCDACRT1Ptr = SiS_LCDACRT11280x1024_1;         break;
-      case 3 : LCDACRT1Ptr = SiS_LCDACRT1800x600_1_H;         break;
-      case 4 : LCDACRT1Ptr = SiS_LCDACRT11024x768_1_H;        break;
-      case 5 : LCDACRT1Ptr = SiS_LCDACRT11280x1024_1_H;       break;
-      case 6 : LCDACRT1Ptr = SiS_LCDACRT1800x600_2;           break;
-      case 7 : LCDACRT1Ptr = SiS_LCDACRT11024x768_2;          break;
-      case 8 : LCDACRT1Ptr = SiS_LCDACRT11280x1024_2;         break;
-      case 9 : LCDACRT1Ptr = SiS_LCDACRT1800x600_2_H;         break;
-      case 10: LCDACRT1Ptr = SiS_LCDACRT11024x768_2_H;        break;
-      case 11: LCDACRT1Ptr = SiS_LCDACRT11280x1024_2_H;       break;
-      /*case 12: LCDACRT1Ptr = SiS_CHTVCRT1UNTSC;             break;
-      case 13: LCDACRT1Ptr = SiS_CHTVCRT1ONTSC;               break;
-      case 14: LCDACRT1Ptr = SiS_CHTVCRT1UPAL;                break;
-      case 15: LCDACRT1Ptr = SiS_CHTVCRT1OPAL;                break;*/
-     }
-
-     tempah=(UCHAR)SiS_GetReg1(SiS_P3d4,0x11);                        /*unlock cr0-7  */
-     tempah=tempah&0x7F;
-     SiS_SetReg1(SiS_P3d4,0x11,tempah);
+      case Panel_800x600       : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT1800x600_1;           break;
+      case Panel_1024x768      : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1;          break;
+      case Panel_1280x1024     : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_1;         break;
+      case Panel_1400x1050     : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_1;         break;
+      case Panel_1600x1200     : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_1;         break;
+      case Panel_800x600 + 16  : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT1800x600_1_H;         break;
+      case Panel_1024x768 + 16 : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1_H;        break;
+      case Panel_1280x1024 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_1_H;       break;
+      case Panel_1400x1050 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_1_H;       break;
+      case Panel_1600x1200 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_1_H;       break;
+      case Panel_800x600 + 32  : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT1800x600_2;           break;
+      case Panel_1024x768 + 32 : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_2;          break;
+      case Panel_1280x1024 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2;         break;
+      case Panel_1400x1050 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_2;         break;
+      case Panel_1600x1200 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_2;         break;
+      case Panel_800x600 + 48  : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT1800x600_2_H;         break;
+      case Panel_1024x768 + 48 : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_2_H;        break;
+      case Panel_1280x1024 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2_H;       break;
+      case Panel_1400x1050 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_2_H;       break;
+      case Panel_1600x1200 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_2_H;       break;
+      default:                   LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1;          break;
+     }
+
      tempah = (LCDACRT1Ptr+ResInfo)->CR[0];
-     SiS_SetReg1(SiS_P3d4,0x0,tempah);
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x00,tempah);
      for(i=0x01,j=1;i<=0x07;i++,j++){
        tempah = (LCDACRT1Ptr+ResInfo)->CR[j];
-       SiS_SetReg1(SiS_P3d4,i,tempah);
+       SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
      }
-     /* for(i=0x06,j=5;i<=0x07;i++,j++){
-       tempah = (LCDACRT1Ptr+ResInfo)->CR[j];
-       SiS_SetReg1(SiS_P3d4,i,tempah);
-     }*/
      for(i=0x10,j=8;i<=0x12;i++,j++){
        tempah = (LCDACRT1Ptr+ResInfo)->CR[j];
-       SiS_SetReg1(SiS_P3d4,i,tempah);
+       SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
      }
      for(i=0x15,j=11;i<=0x16;i++,j++){
        tempah =(LCDACRT1Ptr+ResInfo)->CR[j];
-       SiS_SetReg1(SiS_P3d4,i,tempah);
+       SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
      }
      for(i=0x0A,j=13;i<=0x0C;i++,j++){
        tempah = (LCDACRT1Ptr+ResInfo)->CR[j];
-       SiS_SetReg1(SiS_P3c4,i,tempah);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,i,tempah);
      }
-  
+
      tempah = (LCDACRT1Ptr+ResInfo)->CR[16];
-     tempah=tempah&0x0E0;
-     SiS_SetReg1(SiS_P3c4,0x0E,tempah);
-  
+     tempah &= 0x0E0;
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x0E,tempah);
+
      tempah = (LCDACRT1Ptr+ResInfo)->CR[16];
-     tempah=tempah&0x01;
-     tempah=tempah<<5;
-     if(modeflag&DoubleScanMode){
-       tempah=tempah|0x080;
-     }
-     SiS_SetRegANDOR(SiS_P3d4,0x09,~0x020,tempah);
-     if(SiS_ModeType>0x03) SiS_SetReg1(SiS_P3d4,0x14,0x4F);
-  /*end 301b*/
-  }
-  else {  /* LVDS */
-     index=SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;  		/* Get index */
-     index=index&0x3F;
-
-     if(SiS_IF_DEF_FSTN) {						/*fstn*/
-        index=index&0x7F;	/* TW: First AND it with 3F, now with 7F ??? */
-     }
-     data=(UCHAR)SiS_GetReg1(SiS_P3d4,0x11);
-     data=data&0x7F;
-     SiS_SetReg1(SiS_P3d4,0x11,data);                             	/* Unlock CRTC */
+     tempah &= 0x01;
+     tempah <<= 5;
+     if(modeflag & DoubleScanMode)  tempah |= 0x080;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,~0x020,tempah);
+
+#endif
+
+  } else {
+
+     /* LVDS, 301, 301B, 301LV, 302LV, ... (non-LCDA) */
+
+     index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;  	/* Get index */
+     if(HwDeviceExtension->jChipType < SIS_315H) {
+        index &= 0x3F;
+     }
 
      for(i=0,j=0;i<=07;i++,j++) {
-       data=SiS_CRT1Table[index].CR[i];
-       SiS_SetReg1(SiS_P3d4,j,data);
+       tempah=SiS_Pr->SiS_CRT1Table[index].CR[i];
+       SiS_SetReg1(SiS_Pr->SiS_P3d4,j,tempah);
      }
      for(j=0x10;i<=10;i++,j++) {
-       data=SiS_CRT1Table[index].CR[i];
-       SiS_SetReg1(SiS_P3d4,j,data);
+       tempah=SiS_Pr->SiS_CRT1Table[index].CR[i];
+       SiS_SetReg1(SiS_Pr->SiS_P3d4,j,tempah);
      }
      for(j=0x15;i<=12;i++,j++) {
-       data=SiS_CRT1Table[index].CR[i];
-       SiS_SetReg1(SiS_P3d4,j,data);
+       tempah=SiS_Pr->SiS_CRT1Table[index].CR[i];
+       SiS_SetReg1(SiS_Pr->SiS_P3d4,j,tempah);
      }
      for(j=0x0A;i<=15;i++,j++) {
-       data=SiS_CRT1Table[index].CR[i];
-       SiS_SetReg1(SiS_P3c4,j,data);
+       tempah=SiS_Pr->SiS_CRT1Table[index].CR[i];
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,j,tempah);
      }
 
-     data=SiS_CRT1Table[index].CR[16];
-     data=data&0xE0;
-     SiS_SetReg1(SiS_P3c4,0x0E,data);
+     tempah = SiS_Pr->SiS_CRT1Table[index].CR[16];
+     tempah &= 0xE0;
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x0E,tempah);
 
-     data=(UCHAR)SiS_GetReg1(SiS_P3d4,0x09);
-     data=data&0xDF;                                      /* clear CR9 D[5] */
-     i=SiS_CRT1Table[index].CR[16];
-     i=i&0x01;
-     i=i<<5;
-     data=data|i;
+     tempah = SiS_Pr->SiS_CRT1Table[index].CR[16];
+     tempah &= 0x01;
+     tempah <<= 5;
+     if(modeflag & DoubleScanMode)  tempah |= 0x80;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0xDF,tempah);
 
-     if (ModeNo<=0x13)
-       i = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-     else
-       i = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  }
 
-     i=i&DoubleScanMode;
-     if(i) data=data|0x80;
-     SiS_SetReg1(SiS_P3d4,0x09,data);
+  if(SiS_Pr->SiS_ModeType > ModeVGA) SiS_SetReg1(SiS_Pr->SiS_P3d4,0x14,0x4F);
+}
 
-     if(SiS_ModeType>0x03) SiS_SetReg1(SiS_P3d4,0x14,0x4F);
+BOOLEAN
+SiS_GetLCDACRT1Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+		   USHORT RefreshRateTableIndex,USHORT *ResInfo,
+		   USHORT *DisplayType)
+ {
+  USHORT tempbx=0,modeflag=0;
+  USHORT CRT2CRTC=0;
+
+  if(ModeNo<=0x13) {
+  	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  	CRT2CRTC = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else {
+  	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  	CRT2CRTC = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
   }
+
+  tempbx = SiS_Pr->SiS_LCDResInfo;
+
+  if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx += 32;
+  if(modeflag & HalfDCLK)                   tempbx += 16;
+
+  *ResInfo = CRT2CRTC & 0x3F;
+  *DisplayType = tempbx;
+
+  return 1;
 }
 
-/* TW: Set offset ("pitch") - overruled by SetPitch in XF86 */
+/* TW: Set offset and pitch - partly overruled by SetPitch() in XF86 */
+/* TW: Checked against 650/LVDS (1.10.07), 650/301LV and 315 BIOS */
 void
-SiS_SetCRT1Offset(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+SiS_SetCRT1Offset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                   USHORT RefreshRateTableIndex,
 		  PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-   USHORT temp,ah,al;
-   USHORT temp2,i;
-   USHORT DisplayUnit;
+   USHORT temp, DisplayUnit, infoflag;
+
+   infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+
+   DisplayUnit = SiS_GetOffset(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+                     RefreshRateTableIndex,HwDeviceExtension);
+
+   temp = (DisplayUnit >> 8) & 0x0f;
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,temp);
 
-   /* Alan */
-   temp = SiS_EModeIDTable[ModeIdIndex].Ext_ModeInfo;
+   temp = DisplayUnit & 0xFF;
+   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x13,temp);
+
+   if(infoflag & InterlaceMode) DisplayUnit >>= 1;
+
+   DisplayUnit <<= 5;
+   temp = (DisplayUnit & 0xff00) >> 8;
+   if (DisplayUnit & 0xff) temp++;
+   temp++;
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x10,temp);
+}
+
+/* TW: New from 650/LVDS 1.10.07, 630/301B and 630/LVDS BIOS */
+void
+SiS_ResetCRT1VCLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+   USHORT index;
+
+   /* TW: We only need to do this if Panel Link is to be
+    *     initialized, thus on 630/LVDS/301B, and 650/LVDS
+    */
    if(HwDeviceExtension->jChipType >= SIS_315H) {
-     temp=temp>>8;         /* sis310 */
+       if (SiS_Pr->SiS_IF_DEF_LVDS == 0)  return;
    } else {
-     temp=temp>>4;         /* sis300 */
+       if( (SiS_Pr->SiS_IF_DEF_LVDS == 0) &&
+           (!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) ) {
+	   return;
+      }
    }
-   temp=SiS_ScreenOffset[temp];
 
-   if((ModeNo>=0x7C)&&(ModeNo<=0x7E)) {
-     /* TW: 1280x960 */
-     temp=0x6B;  /* TW: Why? Offset for 1280 is normally 0x50! */
-     temp2=ModeNo-0x7C;
-     /* TW: SiS_ModeType-ModeEGA (below) is 1,3 or 5, not 0,1,or 2 */
-     temp2=(temp2*2)+1; /* TW: Maybe this is more correct? */
-   }
-   else {
-     temp2 = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
-     temp2=temp2&InterlaceMode;
-     if(temp2) temp=temp<<1;
-     temp2=SiS_ModeType-ModeEGA;
-   }
-
-   switch (temp2) {
-     case 0 : temp2=1; break;
-     case 1 : temp2=2; break;
-     case 2 : temp2=4; break;
-     case 3 : temp2=4; break;
-     case 4 : temp2=6; break;
-     case 5 : temp2=8; break;
-   }
-   temp=temp*temp2;
-   DisplayUnit=temp;
-
-   temp2=temp;
-   temp=temp>>8;                                         /* ah */
-   temp=temp&0x0F;
-   i=SiS_GetReg1(SiS_P3c4,0x0E);
-   i=i&0xF0;
-   i=i|temp;
-   SiS_SetReg1(SiS_P3c4,0x0E,i);
-
-   temp=(UCHAR)temp2;
-   temp=temp&0xFF;                                        /* al */
-   SiS_SetReg1(SiS_P3d4,0x13,temp);
-
-   temp2 = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
-   temp2=temp2&InterlaceMode;
-   if(temp2) DisplayUnit>>=1;
-
-   DisplayUnit=DisplayUnit<<5;
-   ah=(DisplayUnit&0xff00)>>8;
-   al=DisplayUnit&0x00ff;
-   if(al==0) ah=ah+1;
-   else ah=ah+2;
-   SiS_SetReg1(SiS_P3c4,0x10,ah);
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+   	SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xCF,0x20);
+   } else {
+   	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x20);
+   }
+   index = 1;
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[index].SR2B);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[index].SR2C);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x80);
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+   	SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xcf,0x10);
+   } else {
+   	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x10);
+   }
+   index = 0;
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[index].SR2B);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[index].SR2C);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x80);
 }
 
+/* TW: Checked against 300, 650/LVDS, 650/301LVx, 315, 630/301B, 630/LVDS BIOS */
 void
-SiS_SetCRT1VCLK(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+SiS_SetCRT1VCLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                 PSIS_HW_DEVICE_INFO HwDeviceExtension,
 		USHORT RefreshRateTableIndex)
 {
-  UCHAR  index,data;
-  USHORT vclkindex;
-
-  /* TW: Now I'm confused. Is IF_DEF_LVDS 1 even for 301B/302B/301LV/302lV?
-   *     This functions could make one believe that LVDS is 0 for these. But
-   *     in this case SetGroup1_LVDS doesn't make sense (see init301.c)
-   *     So my conclusion is that LVDS = 1 for some of the SiS bridges as
-   *     well, i just don't know which ones...
-   */
+  USHORT  index;
 
-  if(SiS_IF_DEF_LVDS==1) {
+  index = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+	                  RefreshRateTableIndex,HwDeviceExtension);
 
-        /* TW: Do this if IF_DEF_LVDS is 1 */
+  if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
+                       && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) ){
 
-    	index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+    	SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xCF);
 
-    	/*if(HwDeviceExtension->jChipType < SIS_315H) { */
-    	index=index&0x3F;
-    	/*}*/
-    	data = SiS_GetReg1(SiS_P3c4,0x31) & 0xCF;
-	SiS_SetReg1(SiS_P3c4,0x31,data);
-	/* SiS_SetReg1(SiS_P3c4,0x31,0x00); 	     */                 /* for300 */
-
-    	SiS_SetReg1(SiS_P3c4,0x2B,SiS_VCLKData[index].SR2B);
-    	SiS_SetReg1(SiS_P3c4,0x2C,SiS_VCLKData[index].SR2C);
-	
-    	if(HwDeviceExtension->jChipType < SIS_315H)
-      		SiS_SetReg1(SiS_P3c4,0x2D,0x80);                        /* for300 series */
-   	else
-      		SiS_SetReg1(SiS_P3c4,0x2D,0x01);                        /* for310 series */
-  }
-
-  else if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-               && (SiS_VBInfo&SetCRT2ToLCDA)
-	       && (SiS_IF_DEF_LVDS==0) ){  /* TW: I did NOT include this here */
+    	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VBVCLKData[index].Part4_A);
+    	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VBVCLKData[index].Part4_B);
 
-        /* TW: Do this if bridge type is 301B/302B/301LV/302LV
-	 *     (This can only be called if LVDS is 0...)
-	 */
-	 
-    	vclkindex = SiS_GetVCLK2Ptr(ROMAddr,ModeNo,ModeIdIndex,
-	                     RefreshRateTableIndex,HwDeviceExtension);
-    	data = SiS_GetReg1(SiS_P3c4,0x31) & 0xCF;
-    	SiS_SetReg1(SiS_P3c4,0x31,data);
-
-    	data = SiS_VBVCLKData[vclkindex].Part4_A;
-    	SiS_SetReg1(SiS_P3c4,0x2B,data);
-    	data = SiS_VBVCLKData[vclkindex].Part4_B;
-    	SiS_SetReg1(SiS_P3c4,0x2C,data);
-
-    	if(HwDeviceExtension->jChipType < SIS_315H)
-    		SiS_SetReg1(SiS_P3c4,0x2D,0x80);                        /* for300 series */
-    	else
-    		SiS_SetReg1(SiS_P3c4,0x2D,0x01);
-  }
-  else {
-
-	/* TW: Do this if LVDS is 0 and the brigde type is NOT
-	 *     301B/302B/301LV/302LV. This leaves only 301...
-	 *     (or 301B/.. if not LCDA)
-	 */
+    	if(HwDeviceExtension->jChipType >= SIS_315H) {
+		SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x01);
+   	} else {
+    		SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x80);
+    	}
 
-    	index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
-    	/*if(HwDeviceExtension->jChipType < SIS_315H) { */
-    	index=index&0x3F;
-    	/*}*/
-    	data = SiS_GetReg1(SiS_P3c4,0x31) & 0xCF;
-	SiS_SetReg1(SiS_P3c4,0x31,data);
-	/*SiS_SetReg1(SiS_P3c4,0x31,0x00); */                       	/* for300 */
+  } else {
 
-    	SiS_SetReg1(SiS_P3c4,0x2B,SiS_VCLKData[index].SR2B);
-    	SiS_SetReg1(SiS_P3c4,0x2C,SiS_VCLKData[index].SR2C);
-    	if(HwDeviceExtension->jChipType < SIS_315H)
-      		SiS_SetReg1(SiS_P3c4,0x2D,0x80);                        /* for300 series */
-    	else
-      		SiS_SetReg1(SiS_P3c4,0x2D,0x01);                        /* for310 series */
+	if(HwDeviceExtension->jChipType >= SIS_315H) {
+	    SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xCF);
+	} else {
+	    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x00);
+	}
+
+    	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[index].SR2B);
+    	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[index].SR2C);
+
+    	if(HwDeviceExtension->jChipType >= SIS_315H) {
+	    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x01);
+	} else {
+      	    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x80);
+        }
   }
 }
 
+#if 0  /* TW: Not used */
 void
-SiS_IsLowResolution(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SiS_IsLowResolution(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT data;
   USHORT ModeFlag;
 
-  data = SiS_GetReg1(SiS_P3c4,0x0F);
-  data = data&0x7F;
-  SiS_SetReg1(SiS_P3c4,0x0F,data);
+  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0x7F);
 
-  if (ModeNo>0x13) {
-    ModeFlag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  if(ModeNo > 0x13) {
+    ModeFlag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
     if ((ModeFlag & HalfDCLK) && (ModeFlag & DoubleScanMode)) {
-      data = SiS_GetReg1(SiS_P3c4,0x0F);
-      data = data|0x80;
-      SiS_SetReg1(SiS_P3c4,0x0F,data);
-      data = SiS_GetReg1(SiS_P3c4,0x01);
-      data = data&0xF7;
-      SiS_SetReg1(SiS_P3c4,0x01,data);
+      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x80);
+      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x01,0xF7);
     }
   }
 }
+#endif
 
+/* TW: Checked against 300, 630/LVDS, 650/LVDS and 315 BIOS */
 void
-SiS_SetCRT1ModeRegs(ULONG ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+SiS_SetCRT1ModeRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
                     USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex)
 {
   USHORT data,data2,data3;
   USHORT infoflag=0,modeflag;
   USHORT resindex,xres;
 
-  if (ModeNo>0x13) {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-    	infoflag = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+  if(ModeNo > 0x13) {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
   } else {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;    /* si+St_ModeFlag */
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
   }
 
-  SiS_SetRegANDOR(SiS_P3c4,0x1F,0x3F,0x00); 	/* DAC pedestal */
+  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1F,0x3F); 		/* DAC pedestal */
 
-  if(ModeNo>0x13) data=infoflag;
-  else data=0;
-  data2=SiS_GetReg1(SiS_P3c4,0x06) & 0xC0;  /* TW: Preserve Xv display mode!!! */
-  if(ModeNo>0x13) {
-    if(SiS_ModeType>0x02) {
-       data2=data2|0x02;
-       data3=SiS_ModeType-ModeVGA;
-       data3=data3<<2;
-       data2=data2|data3;
-    }
-  }
-  data=data&InterlaceMode;
-  if(data) data2=data2|0x20;
-  SiS_SetReg1(SiS_P3c4,0x06,data2);
-
-  if((HwDeviceExtension->jChipType==SIS_630)||
-     (HwDeviceExtension->jChipType==SIS_540)||
-     (HwDeviceExtension->jChipType==SIS_730)) {
-    resindex=SiS_GetResInfo(ROMAddr,ModeNo,ModeIdIndex);
-    if(ModeNo<=0x13)
-      	xres=SiS_StResInfo[resindex].HTotal;
-    else
-      	xres=SiS_ModeResInfo[resindex].HTotal;                         /* xres->ax */
-    data=0x0000;
-    if(infoflag&InterlaceMode) {
-      if(xres==1024) data=0x0035;
-      if(xres==1280) data=0x0048;
-    }
-    data2=data&0x00FF;
-    SiS_SetRegANDOR(SiS_P3d4,0x19,0xFF,data2);
-    data2=(data&0xFF00)>>8;
-    SiS_SetRegANDOR(SiS_P3d4,0x19,0xFC,data2);
-  }
-
-  if(modeflag&HalfDCLK) {
-    SiS_SetRegANDOR(SiS_P3c4,0x01,0xFF,0x01);
-  }
-
-  if((HwDeviceExtension->jChipType==SIS_630)||
-     (HwDeviceExtension->jChipType==SIS_540)||
-     (HwDeviceExtension->jChipType==SIS_730)){
-     /* TW: This was missing here for modes > 1024x768: */
-    if(modeflag&LineCompareOff) {
-      SiS_SetRegANDOR(SiS_P3c4,0x0F,0xF7,0x08);
-    } else {
-      SiS_SetRegANDOR(SiS_P3c4,0x0F,0xF7,0x00);
+  if(ModeNo > 0x13) data = infoflag;
+  else data = 0;
+
+  data2 = 0;
+  if(ModeNo > 0x13) {
+    if(SiS_Pr->SiS_ModeType > 0x02) {
+       data2 |= 0x02;
+       data3 = (SiS_Pr->SiS_ModeType - ModeVGA) << 2;
+       data2 |= data3;
     }
+  }
+  if(data & InterlaceMode) data2 |= 0x20;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x06,0xC0, data2);
+
+  resindex = SiS_GetResInfo(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
+  if(ModeNo <= 0x13) {
+      	xres = SiS_Pr->SiS_StResInfo[resindex].HTotal;
   } else {
-    if(modeflag&LineCompareOff) {
-      SiS_SetRegANDOR(SiS_P3c4,0x0F,0xF7,0x08);
-    } else {
-      SiS_SetRegANDOR(SiS_P3c4,0x0F,0xF7,0x00);
-    }
+      	xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal;
+  }
+
+  if(HwDeviceExtension->jChipType != SIS_300) {
+     data = 0x0000;
+     if(infoflag & InterlaceMode) {
+        if(xres == 1024) data = 0x0035;
+        else data = 0x0048;
+     }
+     data2 = data & 0x00FF;
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x19,data2);
+     data2 = (data & 0xFF00) >> 8;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x1a,0xFC,data2);
+  }
+
+  if(modeflag & HalfDCLK) {
+     SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x08);
+  }
+
+  if(HwDeviceExtension->jChipType == SIS_300) {
+     if(modeflag & LineCompareOff) {
+        SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x08);
+     } else {
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0xF7);
+     }
+  } else if(HwDeviceExtension->jChipType < SIS_315H) {
+     if(modeflag & LineCompareOff) {
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,0x08);
+     } else {
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0xB7);
+     }
+     /* 630 BIOS does something for mode 0x12 here */
+  } else {
+     if(modeflag & LineCompareOff) {
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,0x08);
+     } else {
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0xB7);
+     }
+  }
+
+  if(HwDeviceExtension->jChipType != SIS_300) {
+     if(SiS_Pr->SiS_ModeType == ModeEGA) {
+        if(ModeNo > 0x13) {
+  	   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x40);
+        }
+     }
   }
 
-  data=0x60;
-  if(SiS_ModeType!=ModeText) {
-      data=data^0x60;
-      if(SiS_ModeType!=ModeEGA) {
-        data=data^0xA0;
+#ifdef SIS315H
+  /* TW: 315 BIOS sets SR17 at this point */
+  if(HwDeviceExtension->jChipType == SIS_315PRO) {
+      data = SiS_Get310DRAMType(SiS_Pr,ROMAddr,HwDeviceExtension);
+      data = SiS_Pr->SiS_SR15[2][data];
+      if(SiS_Pr->SiS_ModeType == ModeText) {
+          data &= 0xc7;
+      } else {
+          data2 = SiS_GetOffset(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+                                RefreshRateTableIndex,HwDeviceExtension);
+	  data2 >>= 1;
+	  if(infoflag & InterlaceMode) data2 >>= 1;
+	  data3 = SiS_GetColorDepth(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
+	  data3 >>= 1;
+	  if(data3 == 0) data3++;
+	  data2 /= data3;
+	  if(data2 >= 0x50) {
+	      data &= 0x0f;
+	      data |= 0x50;
+	  }
+      }
+      SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,data);
+  }
+#endif
+
+  data = 0x60;
+  if(SiS_Pr->SiS_ModeType != ModeText) {
+      data ^= 0x60;
+      if(SiS_Pr->SiS_ModeType != ModeEGA) {
+        data ^= 0xA0;
       }
   }
-  SiS_SetRegANDOR(SiS_P3c4,0x21,0x1F,data);
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x21,0x1F,data);
+
+  SiS_SetVCLKState(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,RefreshRateTableIndex,ModeIdIndex);
+
+#ifdef SIS315H
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+    if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x40) {
+        SiS_SetReg1(SiS_Pr->SiS_P3d4,0x52,0x2c);
+    } else {
+        SiS_SetReg1(SiS_Pr->SiS_P3d4,0x52,0x6c);
+    }
+  }
+#endif
 }
 
+/* TW: Checked against 300, 315, 650/LVDS, 650/301LVx, 630/301B and 630/LVDS BIOS */
 void
-SiS_SetVCLKState(ULONG ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                 USHORT ModeNo,USHORT RefreshRateTableIndex)
+SiS_SetVCLKState(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                 USHORT ModeNo,USHORT RefreshRateTableIndex,
+                 USHORT ModeIdIndex)
 {
-   USHORT data,data2=0;
-   USHORT VCLK;
-   UCHAR  index=0;
+  USHORT data, data2=0;
+  USHORT VCLK, index=0;
 
-  if (ModeNo<=0x13) VCLK=0;
+  if (ModeNo <= 0x13) VCLK = 0;
   else {
-    index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
-    /*if(HwDeviceExtension->jChipType < SIS_315H) { */
-    index=index&0x3F;
-    /*}*/
-    VCLK = SiS_VCLKData[index].CLOCK;
+     index = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+	               RefreshRateTableIndex,HwDeviceExtension);
+     VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
   }
 
-  if(HwDeviceExtension->jChipType < SIS_315H) {
-    data2=0x00;
-    if(VCLK>150) data2=data2|0x80;
-    SiS_SetRegANDOR(SiS_P3c4,0x07,0x7B,data2); 	/* DAC speed */
-
-    data2=0x00;
-    if(VCLK>=150) data2=data2|0x08;       	/* VCLK > 150 */
-    SiS_SetRegANDOR(SiS_P3c4,0x32,0xF7,data2);
-  } else { /* 310 series */
-    data=SiS_GetReg1(SiS_P3c4,0x32);
-    data=data&0xf3;
-    if(VCLK>=200) data=data|0x0c;         	/* VCLK > 200 */
-    SiS_SetReg1(SiS_P3c4,0x32,data);
-    data=SiS_GetReg1(SiS_P3c4,0x1F);	  	/* DAC pedestal */
+  if(HwDeviceExtension->jChipType < SIS_315H) {		/* 300 series */
+
+    data2 = 0x00;
+    if(VCLK > 150) data2 |= 0x80;
+    SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data2); 	/* DAC speed */
+
+    data2 = 0x00;
+    if(VCLK >= 150) data2 |= 0x08;       	/* VCLK > 150 */
+    SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data2);
+
+  } else { 						/* 310/325 series */
+
+    data = 0;
+    if(VCLK >= 166) data |= 0x0c;         	/* TW: Was 200; is 166 in 650 and 315 BIOSes */
+    SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data);
+
+    if(VCLK >= 166) {				/* TW: Was 200, is 166 in 650 and 315 BIOSes */
+       SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1f,0xe7);
+    }
+#if 0 /* Not done in 315 and 650/301LV/LVDS BIOSes: */
+    data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1F);	  	/* DAC pedestal */
     data &= 0xE7;
     if(VCLK<200) data |= 0x10;
-    SiS_SetReg1(SiS_P3c4,0x1F,data);	  	/* DAC pedestal */
+    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1F,data);	  	/* DAC pedestal */
+#endif
   }
 
-  if(VCLK<135) data2=0x03;
-  if((VCLK>=135)&&(VCLK<160)) data2=0x02;
-  if((VCLK>=160)&&(VCLK<260)) data2=0x01;
-  if(VCLK>260) data2=0x00;
+  data2 = 0x03;
+  if((VCLK >= 135) && (VCLK < 160)) data2 = 0x02;
+  if((VCLK >= 160) && (VCLK < 260)) data2 = 0x01;
+  if(VCLK >= 260) data2 = 0x00;
   /* disable 24bit palette RAM gamma correction  */
-  if(HwDeviceExtension->jChipType==SIS_540) {
-    	if((VCLK==203)||(VCLK<234)) data2=0x02;
+  if(HwDeviceExtension->jChipType == SIS_540) {
+    	if((VCLK == 203) || (VCLK < 234)) data2 = 0x02;
+  }
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xFC,data2);  	/* DAC speed */
+  } else {
+      if(HwDeviceExtension->jChipType > SIS_315PRO) {
+         /* TW: This "if" is done in 650/LVDS/301LV BIOSes; Not in 315 BIOS */
+         if(ModeNo > 0x13) data2 &= 0xfc;
+      }
+      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xF8,data2);  	/* DAC speed */
   }
-  SiS_SetRegANDOR(SiS_P3c4,0x07,0xFC,data2);  	/* DAC speed */
 }
 
+/* TW: Checked against 650/301LVx 1.10.6s, 315, 630/301B BIOS */
 void
-SiS_LoadDAC(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SiS_LoadDAC(SiS_Private *SiS_Pr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+            UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
    USHORT data,data2;
    USHORT time,i,j,k;
    USHORT m,n,o;
    USHORT si,di,bx,dl;
    USHORT al,ah,dh;
-   USHORT *table=NULL;
+   USHORT DACAddr, DACData, shiftflag;
+   const USHORT *table = NULL;
+#if 0
+   USHORT tempah,tempch,tempcl,tempdh,tempal,tempbx;
+#endif
 
    if (ModeNo<=0x13)
-        data = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+        data = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
    else
-        data = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+        data = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
-   data=data&DACInfoFlag;
-   time=64;
-   if(data==0x00) table=SiS_MDA_DAC;
-   if(data==0x08) table=SiS_CGA_DAC;
-   if(data==0x10) table=SiS_EGA_DAC;
-   if(data==0x18) {
-     time=256;
-     table=SiS_VGA_DAC;
-   }
-   if(time==256) j=16;
-   else j=time;
-
-   SiS_SetReg3(SiS_P3c6,0xFF);
-   SiS_SetReg3(SiS_P3c8,0x00);
-
-   for(i=0;i<j;i++) {
-      data=table[i];
-      for(k=0;k<3;k++) {
-        data2=0;
-        if(data&0x01) data2=0x2A;
-        if(data&0x02) data2=data2+0x15;
-        SiS_SetReg3(SiS_P3c9,data2);
-        data=data>>2;
-      }
-   }
+#if 0
+   if(!(ds:489 & 0x08)) {
+#endif
 
-   if(time==256) {
-      for(i=16;i<32;i++) {
-         data=table[i];
-         for(k=0;k<3;k++) SiS_SetReg3(SiS_P3c9,data);
-      }
-      si=32;
-      for(m=0;m<9;m++) {
-         di=si;
-         bx=si+0x04;
-         dl=0;
-         for(n=0;n<3;n++) {
-            for(o=0;o<5;o++) {
-              dh=table[si];
-              ah=table[di];
-              al=table[bx];
-              si++;
-              SiS_WriteDAC(dl,ah,al,dh);
-            }         /* for 5 */
-            si=si-2;
-            for(o=0;o<3;o++) {
-              dh=table[bx];
-              ah=table[di];
-              al=table[si];
-              si--;
-              SiS_WriteDAC(dl,ah,al,dh);
-            }         /* for 3 */
-            dl++;
-         }            /* for 3 */
-         si=si+5;
-      }               /* for 9 */
-   }
+	data &= DACInfoFlag;
+	time = 64;
+	if(data == 0x00) table = SiS_MDA_DAC;
+	if(data == 0x08) table = SiS_CGA_DAC;
+	if(data == 0x10) table = SiS_EGA_DAC;
+	if(data == 0x18) {
+	   time = 256;
+	   table = SiS_VGA_DAC;
+	}
+	if(time == 256) j = 16;
+	else            j = time;
+
+	if( ( (HwDeviceExtension->jChipType < SIS_315H) &&         /* 630/301B */
+	      (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
+	      (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) )         ||
+	    (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)            ||     /* LCDA */
+	    (!(SiS_Pr->SiS_SetFlag & ProgrammingCRT2)) ) {         /* Programming CRT1 */
+	   DACAddr = SiS_Pr->SiS_P3c8;
+	   DACData = SiS_Pr->SiS_P3c9;
+	   shiftflag = 0;
+	   SiS_SetReg3(SiS_Pr->SiS_P3c6,0xFF);
+	} else {
+	   shiftflag = 1;
+	   DACAddr = SiS_Pr->SiS_Part5Port;
+	   DACData = SiS_Pr->SiS_Part5Port + 1;
+	}
+
+	SiS_SetReg3(DACAddr,0x00);
+
+	for(i=0; i<j; i++) {
+	   data = table[i];
+	   for(k=0; k<3; k++) {
+		data2 = 0;
+		if(data & 0x01) data2 = 0x2A;
+		if(data & 0x02) data2 += 0x15;
+		if(shiftflag) data2 <<= 2;
+		SiS_SetReg3(DACData,data2);
+		data >>= 2;
+	   }
+	}
+
+	if(time == 256) {
+	   for(i = 16; i < 32; i++) {
+		data = table[i];
+		if(shiftflag) data <<= 2;
+		for(k=0; k<3; k++) SiS_SetReg3(DACData,data);
+	   }
+	   si = 32;
+	   for(m = 0; m < 9; m++) {
+	      di = si;
+	      bx = si + 4;
+	      dl = 0;
+	      for(n = 0; n < 3; n++) {
+		 for(o = 0; o < 5; o++) {
+		    dh = table[si];
+		    ah = table[di];
+		    al = table[bx];
+		    si++;
+		    SiS_WriteDAC(SiS_Pr,DACData,shiftflag,dl,ah,al,dh);
+		 }
+		 si -= 2;
+		 for(o = 0; o < 3; o++) {
+		    dh = table[bx];
+		    ah = table[di];
+		    al = table[si];
+		    si--;
+		    SiS_WriteDAC(SiS_Pr,DACData,shiftflag,dl,ah,al,dh);
+		 }
+		 dl++;
+	      }            /* for n < 3 */
+	      si += 5;
+	   }               /* for m < 9 */
+	}
+#if 0
+    }  /* ds:489 & 0x08 */
+#endif
+
+#if 0
+    if((!(ds:489 & 0x08)) && (ds:489 & 0x06)) {
+           tempbx = 0;
+	   for(i=0; i< 256; i++) {
+               SiS_SetReg3(SiS_Pr->SiS_P3c8-1,tempbx);    	/* 7f87 */
+               tempah = SiS_GetReg3(SiS_Pr->SiS_P3c8+1);  	/* 7f83 */
+	       tempch = SiS_GetReg3(SiS_Pr->SiS_P3c8+1);
+	       tempcl = SiS_GetReg3(SiS_Pr->SiS_P3c8+1);
+	       tempdh = tempah;
+	       tempal = 0x4d * tempdh;          	/* 7fb8 */
+	       tempbx += tempal;
+	       tempal = 0x97 * tempch;
+	       tempbx += tempal;
+	       tempal = 0x1c * tempcl;
+	       tempbx += tempal;
+	       if((tempbx & 0x00ff) > 0x80) tempbx += 0x100;
+	       tempdh = (tempbx & 0x00ff) >> 8;
+	       tempch = tempdh;
+	       tempcl = tempdh;
+	       SiS_SetReg3(SiS_Pr->SiS_P3c8,(tempbx & 0xff));  	/* 7f7c */
+	       SiS_SetReg3(SiS_Pr->SiS_P3c8+1,tempdh);          /* 7f92 */
+	       SiS_SetReg3(SiS_Pr->SiS_P3c8+1,tempch);
+	       SiS_SetReg3(SiS_Pr->SiS_P3c8+1,tempcl);
+           }
+    }
+#endif
 }
 
 void
-SiS_WriteDAC(USHORT dl, USHORT ah, USHORT al, USHORT dh)
+SiS_WriteDAC(SiS_Private *SiS_Pr, USHORT DACData, USHORT shiftflag,
+             USHORT dl, USHORT ah, USHORT al, USHORT dh)
 {
   USHORT temp;
   USHORT bh,bl;
 
-  bh=ah;
-  bl=al;
-  if(dl!=0) {
-    temp=bh;
-    bh=dh;
-    dh=temp;
-    if(dl==1) {
-       temp=bl;
-       bl=dh;
-       dh=temp;
+  bh = ah;
+  bl = al;
+  if(dl != 0) {
+    temp = bh;
+    bh = dh;
+    dh = temp;
+    if(dl == 1) {
+       temp = bl;
+       bl = dh;
+       dh = temp;
     } else {
-       temp=bl;
-       bl=bh;
-       bh=temp;
+       temp = bl;
+       bl = bh;
+       bh = temp;
     }
   }
-  SiS_SetReg3(SiS_P3c9,(USHORT)dh);
-  SiS_SetReg3(SiS_P3c9,(USHORT)bh);
-  SiS_SetReg3(SiS_P3c9,(USHORT)bl);
+  if(shiftflag) {
+     dh <<= 2;
+     bh <<= 2;
+     bl <<= 2;
+  }
+  SiS_SetReg3(DACData,(USHORT)dh);
+  SiS_SetReg3(DACData,(USHORT)bh);
+  SiS_SetReg3(DACData,(USHORT)bl);
 }
 
 ULONG
-GetDRAMSize(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+GetDRAMSize(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  ULONG   AdapterMemorySize=0;
+  ULONG   AdapterMemorySize = 0;
 #ifdef SIS315H
   USHORT  counter;
 #endif
-  
+
 #ifdef SIS315H
-  if ((HwDeviceExtension->jChipType == SIS_315H)||
+  if ((HwDeviceExtension->jChipType == SIS_315H) ||
       (HwDeviceExtension->jChipType == SIS_315PRO)) {
-    	counter = SiS_GetReg1(SiS_P3c4,0x14)&0xF0; 	/*get memory size*/
-    	counter >>= 4;
-    	AdapterMemorySize= 1 << counter;
-    	AdapterMemorySize *= 1024*1024;
-  } else {
-    	if ((HwDeviceExtension->jChipType == SIS_550)||
-            (HwDeviceExtension->jChipType == SIS_640)||
-            (HwDeviceExtension->jChipType == SIS_740)||
+    	counter = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+	AdapterMemorySize = 1 << ((counter & 0xF0) >> 4);
+	counter >>= 2;
+	counter &= 0x03;
+	if(counter == 0x02) {
+		AdapterMemorySize += (AdapterMemorySize / 2);      /* DDR asymetric */
+	} else if(counter != 0) {
+		AdapterMemorySize <<= 1;                           /* SINGLE_CHANNEL_2_RANK or DUAL_CHANNEL_1_RANK */
+	}
+	AdapterMemorySize *= (1024*1024);
+
+  } else if((HwDeviceExtension->jChipType == SIS_550) ||
+            (HwDeviceExtension->jChipType == SIS_640) ||
+            (HwDeviceExtension->jChipType == SIS_740) ||
             (HwDeviceExtension->jChipType == SIS_650)) {
-      		counter = SiS_GetReg1(SiS_P3c4,0x14)&0x3F; /*get memory size*/
+      		counter = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14) & 0x3F;
       		counter++;
       		AdapterMemorySize = counter * 4;
-      		AdapterMemorySize *= 1024*1024;
-		/* TW: FIXME: Some 550 BIOSes don't set up SR14 correctly. We
-		 * will have to read PCI configuration for a correct memory
-		 * size. (However, this is checked in framebuffer driver;
-		 * X does not use this function but if it ever will, this will
-		 * become an issue.)
-		 */
-    	}
+      		AdapterMemorySize *= (1024*1024);
   }
 #endif
 
 #ifdef SIS300
-  if ((HwDeviceExtension->jChipType==SIS_300)||
-      (HwDeviceExtension->jChipType==SIS_540)||
-      (HwDeviceExtension->jChipType==SIS_630)||
+  if ((HwDeviceExtension->jChipType==SIS_300) ||
+      (HwDeviceExtension->jChipType==SIS_540) ||
+      (HwDeviceExtension->jChipType==SIS_630) ||
       (HwDeviceExtension->jChipType==SIS_730)) {
-      	AdapterMemorySize = SiS_GetReg1(SiS_P3c4,0x14); /*get memory size*/
-      	AdapterMemorySize = AdapterMemorySize&0x3F;
+      	AdapterMemorySize = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14) & 0x3F;
       	AdapterMemorySize++;
-      	AdapterMemorySize *= 1024*1024;
+      	AdapterMemorySize *= (1024*1024);
   }
 #endif
 
   return AdapterMemorySize;
 }
 
+#ifndef LINUX_XF86
 void
-SiS_ClearBuffer(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo)
+SiS_ClearBuffer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo)
 {
   PVOID   VideoMemoryAddress = (PVOID)HwDeviceExtension->pjVideoMemoryAddress;
   ULONG   AdapterMemorySize  = (ULONG)HwDeviceExtension->ulVideoMemorySize;
   PUSHORT pBuffer;
   int i;
 
-  if (SiS_ModeType>=ModeEGA) {
-    if (ModeNo>0x13) {
-      AdapterMemorySize=GetDRAMSize(HwDeviceExtension);
+  if (SiS_Pr->SiS_ModeType>=ModeEGA) {
+    if(ModeNo > 0x13) {
+      AdapterMemorySize = GetDRAMSize(SiS_Pr, HwDeviceExtension);
       SiS_SetMemory(VideoMemoryAddress,AdapterMemorySize,0);
     } else {
       pBuffer = VideoMemoryAddress;
-      for (i=0;i<0x4000;i++)
-        pBuffer[i]=0x0000;
+      for(i=0; i<0x4000; i++)
+         pBuffer[i] = 0x0000;
     }
   } else {
     pBuffer = VideoMemoryAddress;
-    if (SiS_ModeType<ModeCGA) {
-      for (i=0;i<0x4000;i++)
-        pBuffer[i]=0x0720;
+    if (SiS_Pr->SiS_ModeType < ModeCGA) {
+      for(i=0; i<0x4000; i++)
+         pBuffer[i] = 0x0720;
     } else {
       SiS_SetMemory(VideoMemoryAddress,0x8000,0);
     }
   }
 }
+#endif
 
 void
-SiS_DisplayOn(void)
+SiS_DisplayOn(SiS_Private *SiS_Pr)
 {
-   SiS_SetRegANDOR(SiS_P3c4,0x01,0xDF,0x00);
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x01,0xDF,0x00);
 }
 
 void
-SiS_DisplayOff(void)
+SiS_DisplayOff(SiS_Private *SiS_Pr)
 {
-   SiS_SetRegANDOR(SiS_P3c4,0x01,0xDF,0x20);
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x01,0xDF,0x20);
 }
 
 
 /* ========================================== */
 /*  SR CRTC GR */
 void
-SiS_SetReg1(
-   USHORT  port,
-   USHORT  index,
-   USHORT  data
-   )
+SiS_SetReg1(USHORT port, USHORT index, USHORT data)
 {
    OutPortByte(port,index);
    OutPortByte(port+1,data);
-   
-   /*
-   _asm
-   {
-         mov      dx, port                      
-         mov      ax, index                     
-         mov      bx, data                      
-         out      dx, al
-         mov      ax, bx
-         inc      dx
-         out      dx, al
-   }
-   */
-
 }
 
 /* ========================================== */
 /*  AR(3C0) */
 void
-SiS_SetReg2(
-   USHORT  port,
-   USHORT  index,
-   USHORT  data
-   )
+SiS_SetReg2(SiS_Private *SiS_Pr, USHORT port, USHORT index, USHORT data)
 {
-
    InPortByte(port+0x3da-0x3c0);
-   OutPortByte(SiS_P3c0,index);
-   OutPortByte(SiS_P3c0,data);
-   OutPortByte(SiS_P3c0,0x20);
-
-   /*
-   _asm
-   {
-         mov      dx, port                      
-         mov      cx, index                     
-         mov      bx, data                      
-
-         add      dx, 3dah-3c0h
-         in       al, dx
-
-         mov      ax, cx
-         mov      dx, 3c0h
-         out      dx, al
-         mov      ax, bx
-         out      dx, al
-
-         mov      ax, 20h
-         out      dx, al
-   }
-   */
-
+   OutPortByte(SiS_Pr->SiS_P3c0,index);
+   OutPortByte(SiS_Pr->SiS_P3c0,data);
+   OutPortByte(SiS_Pr->SiS_P3c0,0x20);
 }
 
-/* ========================================== */
 void
-SiS_SetReg3(
-   USHORT  port,
-   USHORT  data
-   )
+SiS_SetReg3(USHORT port, USHORT data)
 {
-
    OutPortByte(port,data);
-   
-   /*
-   _asm
-   {
-         mov      dx, port                      
-         mov      ax, data                      
-         out      dx, al
-
-   }
-   */
-
 }
 
-/* ========================================== */
 void
-SiS_SetReg4(
-   USHORT  port,
-   ULONG   data
-   )
+SiS_SetReg4(USHORT port, ULONG data)
 {
-
    OutPortLong(port,data);
-
-   /*
-   _asm
-   {
-         mov      dx, port                      ;; port
-         mov      eax, data                      ;; data
-         out      dx, eax
-
-   }
-   */
 }
 
-/* ========================================= */
-UCHAR
-SiS_GetReg1(
-   USHORT  port,
-   USHORT  index
-   )
+UCHAR SiS_GetReg1(USHORT port, USHORT index)
 {
    UCHAR   data;
 
-
    OutPortByte(port,index);
    data = InPortByte(port+1);
 
-   /*
-   _asm
-   {
-         mov      dx, port                      ;; port
-         mov      ax, index                     ;; index
-
-         out      dx, al
-         mov      ax, bx
-         inc      dx
-         xor      eax, eax
-         in       al, dx
-         mov      data, al
-   }
-   */
    return(data);
 }
-/* ========================================== */
+
 UCHAR
-SiS_GetReg2(
-   USHORT  port
-   )
+SiS_GetReg2(USHORT port)
 {
    UCHAR   data;
 
    data= InPortByte(port);
 
-   /*
-   _asm
-   {
-         mov      dx, port                      ;; port
-         xor      eax, eax
-         in       al, dx
-         mov      data, al
-   }
-   */
    return(data);
 }
 
-/* ========================================== */
 ULONG
-SiS_GetReg3(
-   USHORT  port
-   )
+SiS_GetReg3(USHORT port)
 {
    ULONG   data;
 
-
    data = InPortLong(port);
 
-   /*
-   _asm
-   {
-         mov      dx, port                      ;; port
-         xor      eax, eax
-         in       eax, dx
-         mov      data, eax
-   }
-   */
    return(data);
 }
 
-/* ========================================== */
 void
-SiS_ClearDAC(ULONG   port)
+SiS_ClearDAC(SiS_Private *SiS_Pr, ULONG port)
 {
    int i;
 
    OutPortByte(port, 0);
    port++;
-   for (i=0;i<256*3;i++) {
+   for (i=0; i < (256 * 3); i++) {
       OutPortByte(port, 0);
    }
 
 }
-/* ========================================== */
 
+#if 0  /* TW: Unused */
 void
-SiS_SetInterlace(ULONG ROMAddr, USHORT ModeNo,USHORT RefreshRateTableIndex)
+SiS_SetInterlace(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT RefreshRateTableIndex)
 {
   ULONG Temp;
   USHORT data,Temp2;
 
   if (ModeNo<=0x13) return;
-  Temp = (ULONG)SiS_GetReg1(SiS_P3d4, 0x01);
+
+  Temp = (ULONG)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x01);
   Temp++;
-  Temp=Temp*8;
+  Temp <<= 3;
 
-  if(Temp==1024) data=0x0035;
-  else if(Temp==1280) data=0x0048;
-  else data=0x0000;
+  if(Temp == 1024) data = 0x0035;
+  else if(Temp == 1280) data = 0x0048;
+  else data = 0x0000;
 
-  Temp2 = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+  Temp2 = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
   Temp2 &= InterlaceMode;
   if(Temp2 == 0) data=0x0000;
 
-  SiS_SetReg1(SiS_P3d4,0x19,data);
+  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x19,data);
 
-  Temp = (ULONG)SiS_GetReg1(SiS_P3d4, 0x1A);
-  Temp2= (USHORT)(Temp & 0xFC);
-  SiS_SetReg1(SiS_P3d4,0x1A,(USHORT)Temp);
+  Temp = (ULONG)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x1A);
+  Temp = (USHORT)(Temp & 0xFC);
+  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x1A,(USHORT)Temp);
 
-  Temp = (ULONG)SiS_GetReg1(SiS_P3c4, 0x0f);
-  Temp2= (USHORT)Temp & 0xBF;
-  if(ModeNo==0x37) Temp2=Temp2|0x40;
-  SiS_SetReg1(SiS_P3d4,0x1A,(USHORT)Temp2);
+  Temp = (ULONG)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x0f);
+  Temp2 = (USHORT)Temp & 0xBF;
+  if(ModeNo==0x37) Temp2 |= 0x40;
+  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x1A,(USHORT)Temp2);
 }
+#endif
 
+/* TW: Checked against 650/LVDS (1.10.07), 650/301LVx (1.10.6s) and 315 BIOS */
+#ifdef SIS315H
 void
-SiS_SetCRT1FIFO(ULONG ROMAddr,USHORT ModeNo,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_SetCRT1FIFO_310(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT  data;
+  USHORT modeflag;
+
+  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x3D,0xFE);  /* disable auto-threshold */
 
-  data=SiS_GetReg1(SiS_P3c4,0x3D);
-  data &= 0xfe;
-  SiS_SetReg1(SiS_P3c4,0x3D,data);  /* diable auto-threshold */
-  if (ModeNo>0x13) {
-    SiS_SetReg1(SiS_P3c4,0x08,0x34);
-    data=SiS_GetReg1(SiS_P3c4,0x09);
-    data &= 0xF0;
-    SiS_SetReg1(SiS_P3c4,0x09,data);
-
-    data=SiS_GetReg1(SiS_P3c4,0x3D);
-    data |= 0x01;
-    SiS_SetReg1(SiS_P3c4,0x3D,data);
+  if(ModeNo > 0x13) {
+    modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    if( (!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) {
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x08,0x34);
+       SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
+       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01);
+    } else {
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x08,0xAE);
+       SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
+    }
   } else {
-    SiS_SetReg1(SiS_P3c4,0x08,0xAE);
-    data=SiS_GetReg1(SiS_P3c4,0x09);
-    data &= 0xF0;
-    SiS_SetReg1(SiS_P3c4,0x09,data);
+    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x08,0xAE);
+    SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
   }
 }
+#endif
+
+#ifdef SIS300
+void
+SiS_SetCRT1FIFO_300(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                    USHORT RefreshRateTableIndex)
+{
+  USHORT  ThresholdLow = 0;
+  USHORT  index, VCLK, MCLK, colorth=0;
+  USHORT  tempah, temp;
+
+  if(ModeNo > 0x13) {
+
+     index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+     index &= 0x3F;
+     VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;             /* Get VCLK  */
+
+     switch (SiS_Pr->SiS_ModeType - ModeEGA) {     /* Get half colordepth */
+        case 0 : colorth = 1; break;
+        case 1 : colorth = 1; break;
+        case 2 : colorth = 2; break;
+        case 3 : colorth = 2; break;
+        case 4 : colorth = 3; break;
+        case 5 : colorth = 4; break;
+     }
+
+     index = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3A);
+     index &= 0x07;
+     MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK;           /* Get MCLK  */
+
+     tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x35);
+     tempah &= 0xc3;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3c,tempah);
+
+     do {
+        ThresholdLow = SiS_CalcDelay(SiS_Pr, ROMAddr, VCLK, colorth, MCLK);
+        ThresholdLow++;
+        if(ThresholdLow < 0x13) break;
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x16,0xfc);
+        ThresholdLow = 0x13;
+        tempah = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
+        tempah >>= 6;
+        if(!(tempah)) break;
+        tempah--;
+        tempah <<= 6;
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3f,tempah);
+     } while(0);
+
+  } else ThresholdLow = 2;
+
+  /* Write CRT/CPU threshold low, CRT/Engine threshold high */
+  temp = (ThresholdLow << 4) | 0x0f;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x08,temp);
+
+  temp = (ThresholdLow & 0x10) << 1;
+  if(ModeNo > 0x13) temp |= 0x40;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0f,0x9f,temp);
+
+  /* What is this? */
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x3B,0x09);
+
+  /* Write CRT/CPU threshold high */
+  temp = ThresholdLow + 3;
+  if(temp > 0x0f) temp = 0x0f;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x09,temp);
+}
+
+USHORT
+SiS_CalcDelay(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT VCLK, USHORT colordepth, USHORT MCLK)
+{
+  USHORT tempax, tempbx;
+
+  tempbx = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 0);
+  tempax = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 1);
+  if(tempax < 4) tempax = 4;
+  tempax -= 4;
+  if(tempbx < tempax) tempbx = tempax;
+  return(tempbx);
+}
+
+USHORT
+SiS_DoCalcDelay(SiS_Private *SiS_Pr, USHORT MCLK, USHORT VCLK, USHORT colordepth, USHORT key)
+{
+  const UCHAR ThLowA[]   = { 61, 3,52, 5,68, 7,100,11,
+                             43, 3,42, 5,54, 7, 78,11,
+                             34, 3,37, 5,47, 7, 67,11 };
+
+  const UCHAR ThLowB[]   = { 81, 4,72, 6,88, 8,120,12,
+                             55, 4,54, 6,66, 8, 90,12,
+                             42, 4,45, 6,55, 8, 75,12 };
+
+  const UCHAR ThTiming[] = {  1, 2, 2, 3, 0, 1,  1, 2 };
+
+  USHORT tempah, tempal, tempcl, tempbx, temp;
+  ULONG  longtemp;
+
+  tempah = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x18);
+  tempah &= 0x62;
+  tempah >>= 1;
+  tempal = tempah;
+  tempah >>= 3;
+  tempal |= tempah;
+  tempal &= 0x07;
+  tempcl = ThTiming[tempal];
+  tempbx = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
+  tempbx >>= 6;
+  tempah = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+  tempah >>= 4;
+  tempah &= 0x0c;
+  tempbx |= tempah;
+  tempbx <<= 1;
+  if(key == 0) {
+     tempal = ThLowA[tempbx + 1];
+     tempal *= tempcl;
+     tempal += ThLowA[tempbx];
+  } else {
+     tempal = ThLowB[tempbx + 1];
+     tempal *= tempcl;
+     tempal += ThLowB[tempbx];
+  }
+  longtemp = tempal * VCLK * colordepth;
+  temp = longtemp % (MCLK * 16);
+  longtemp /= (MCLK * 16);
+  if(temp) longtemp++;
+  return((USHORT)longtemp);
+}
 
+#if 0  /* TW: Old fragment, unused */
 USHORT
-SiS_CalcDelay(ULONG ROMAddr,USHORT key)
+SiS_CalcDelay(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT key)
 {
   USHORT data,data2,temp0,temp1;
   UCHAR   ThLowA[]=   {61,3,52,5,68,7,100,11,
                        43,3,42,5,54,7, 78,11,
                        34,3,37,5,47,7, 67,11};
+
   UCHAR   ThLowB[]=   {81,4,72,6,88,8,120,12,
                        55,4,54,6,66,8, 90,12,
                        42,4,45,6,55,8, 75,12};
+
   UCHAR   ThTiming[]= {1,2,2,3,0,1,1,2};
 
-  data=SiS_GetReg1(SiS_P3c4,0x16);
+  data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
   data=data>>6;
-  data2=SiS_GetReg1(SiS_P3c4,0x14);
+  data2=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
   data2=(data2>>4)&0x0C;
   data=data|data2;
   data=data<1;
@@ -3424,7 +3885,7 @@
   }
 
   data2=0;
-  data=SiS_GetReg1(SiS_P3c4,0x18);
+  data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x18);
   if(data&0x02) data2=data2|0x01;
   if(data&0x20) data2=data2|0x02;
   if(data&0x40) data2=data2|0x04;
@@ -3432,97 +3893,110 @@
   data=temp1*ThTiming[data2]+temp0;
   return(data);
 }
+#endif
 
 void
-SiS_SetCRT1FIFO2(ULONG ROMAddr,USHORT ModeNo,PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                 USHORT RefreshRateTableIndex)
+SiS_SetCRT1FIFO_630(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                    USHORT RefreshRateTableIndex)
 {
-  USHORT  i,index,data,VCLK,data2,MCLK,colorth=0;
-  ULONG   B,eax,ah,bl;
+  USHORT  i,index,data,VCLK,MCLK,colorth=0;
+  ULONG   B,eax,bl,data2;
   USHORT  ThresholdLow=0;
-  UCHAR   FQBQData[]= { 0x01,0x21,0x41,0x61,0x81,  /* TW: in BIOS at 0xf85 - identical */
+  UCHAR   FQBQData[]= { 0x01,0x21,0x41,0x61,0x81,
                         0x31,0x51,0x71,0x91,0xb1,
                         0x00,0x20,0x40,0x60,0x80,
                         0x30,0x50,0x70,0x90,0xb0,0xFF};
 
-  if(ModeNo>=0x13) {
-    index=SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
-    if(HwDeviceExtension->jChipType < SIS_315H) { /* for300 series */
-      index=index&0x3F;
-    }
-    VCLK=SiS_VCLKData[index].CLOCK;           /* Get VCLK  */
-    index=SiS_GetReg1(SiS_P3c4,0x1A);
-    index=index&07;
-    MCLK=SiS_MCLKData[index].CLOCK;           /* Get MCLK  */
-
-    data2=SiS_ModeType-0x02;
-      switch (data2) {
-        case 0 : colorth=1; break;  /* 1 */
-        case 1 : colorth=1; break;  /* 2 */
-        case 2 : colorth=2; break;  /* 4 */
-        case 3 : colorth=2; break;  /* 4 */
-        case 4 : colorth=3; break;  /* 6 */
-        case 5 : colorth=4; break;  /* 8 */
-      }
+  i=0;
+  if(ModeNo >= 0x13) {
+    index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+    index &= 0x3F;
+    VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;             /* Get VCLK  */
+
+    index = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
+    index &= 0x07;
+    MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK;           /* Get MCLK  */
+
+    data2 = SiS_Pr->SiS_ModeType - ModeEGA;	  /* Get half colordepth */
+    switch (data2) {
+        case 0 : colorth = 1; break;
+        case 1 : colorth = 1; break;
+        case 2 : colorth = 2; break;
+        case 3 : colorth = 2; break;
+        case 4 : colorth = 3; break;
+        case 5 : colorth = 4; break;
+    }
 
-    i=0;
     do{
-       B=(SiS_CalcDelay2(ROMAddr,FQBQData[i])*VCLK*colorth);
+       B = SiS_CalcDelay2(SiS_Pr, ROMAddr, FQBQData[i]) * VCLK * colorth;
+       bl = B / (MCLK * 16);
 
-       bl=B/(16*MCLK);
        if (B==bl*16*MCLK) {
-         bl=bl+1;
+         bl = bl + 1;
        } else {
-         bl=bl+2;  /* TW: was +1 */
+         bl = bl + 2;
        }
 
-       if(bl>0x13) {
-          if(FQBQData[i+1]==0xFF) {
-             ThresholdLow=0x13;
+       if(bl > 0x13) {
+          if(FQBQData[i+1] == 0xFF) {
+             ThresholdLow = 0x13;
              break;
           }
           i++;
        } else {
-          ThresholdLow=bl;
+          ThresholdLow = bl;
           break;
        }
-    } while(FQBQData[i]!=0xFF);
+    } while(FQBQData[i] != 0xFF);
   }
   else {
-    ThresholdLow=0x02;
+    ThresholdLow = 0x02;
   }
 
-  data2=FQBQData[i];
-  data2=(data2&0xf0)>>4;
-  data2=data2<<24;
+  /* Write foreground and background queue */
+  data2 = FQBQData[i];
+  data2 = (data2 & 0xf0)>>4;
+  data2 <<= 24;
 
+#ifndef LINUX_XF86
   SiS_SetReg4(0xcf8,0x80000050);
-  eax=SiS_GetReg3(0xcfc);
-  eax=eax&0xf0ffffff;
-  eax=eax|data2;
+  eax = SiS_GetReg3(0xcfc);
+  eax &= 0xf0ffffff;
+  eax |= data2;
   SiS_SetReg4(0xcfc,eax);
+#else
+  /* We use pci functions X offers. We use pcitag 0, because
+   * we want to read/write to the host bridge (which is always
+   * 00:00.0 on 630, 730 and 540), not the VGA device.
+   */
+  eax = pciReadLong(0x00000000, 0x50);
+  eax &= 0xf0ffffff;
+  eax |= data2;
+  pciWriteLong(0x00000000, 0x50, eax);
+#endif
+
+  /* TODO: write GUI grant timer (PCI config 0xA3) */
+
+  /* Write CRT/CPU threshold low, CRT/Engine threshold high */
+  data = ((ThresholdLow & 0x0f) << 4) | 0x0f;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x08,data);
+
+  data = (ThresholdLow & 0x10) << 1;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xDF,data);
+
+  /* What is this? */
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x3B,0x09);
 
-  ah=ThresholdLow;
-  ah=ah<<4;
-  ah=ah|0x0f;
-  SiS_SetReg1(SiS_P3c4,0x08,ah);
-
-  data=ThresholdLow;
-  data=data&0x10;
-  data=data<<1;
-  SiS_SetRegANDOR(SiS_P3c4,0x0F,0xDF,data);
-
-  SiS_SetReg1(SiS_P3c4,0x3B,0x09);
-
-  data=ThresholdLow+3;
-  if(data>0x0f) data=0x0f;
-  SiS_SetRegANDOR(SiS_P3c4,0x09,0x80,data);
+  /* Write CRT/CPU threshold high (gap = 3) */
+  data = ThresholdLow + 3;
+  if(data > 0x0f) data = 0x0f;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x09,0x80,data);
 }
 
 USHORT
-SiS_CalcDelay2(ULONG ROMAddr,UCHAR key)
+SiS_CalcDelay2(SiS_Private *SiS_Pr, UCHAR *ROMAddr,UCHAR key)
 {
-  USHORT data,index;	   /* TW: in BIOS at 0x1029 - identical */
+  USHORT data,index;
   UCHAR  LatencyFactor[] ={ 97, 88, 86, 79, 77, 00,       /*; 64  bit    BQ=2   */
                             00, 87, 85, 78, 76, 54,       /*; 64  bit    BQ=1   */
                             97, 88, 86, 79, 77, 00,       /*; 128 bit    BQ=2   */
@@ -3532,174 +4006,246 @@
                             86, 77, 75, 68, 66, 00,       /*; 128 bit    BQ=2   */
                             00, 68, 66, 59, 57, 37};      /*; 128 bit    BQ=1   */
 
-  index=(key&0xE0)>>5;
-  if(key&0x10) index=index+6;
-  if(!(key&0x01)) index=index+24;
-  data=SiS_GetReg1(SiS_P3c4,0x14);
-  if(data&0x0080) index=index+12;
+  index = (key & 0xE0) >> 5;
+  if(key & 0x10) index +=6;
+  if(!(key & 0x01)) index += 24;
+  data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+  if(data & 0x0080) index += 12;
 
-  data=LatencyFactor[index];
+  data = LatencyFactor[index];
   return(data);
 }
+#endif
 
-void
-SiS_CRT2AutoThreshold(USHORT  BaseAddr)
+/* =============== Autodetection ================ */
+/*             I N C O M P L E T E                */
+
+BOOLEAN
+SiS_GetPanelID(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT  temp1;
-  USHORT  Part1Port;
-  Part1Port=BaseAddr+SIS_CRT2_PORT_04;
-  temp1=SiS_GetReg1(SiS_Part1Port,0x01);
-  temp1 |= 0x40;
-  SiS_SetReg1(SiS_Part1Port,0x01,temp1);
+  const USHORT PanelTypeTable300[16] = {
+      0xc101, 0xc117, 0x0121, 0xc135, 0xc142, 0xc152, 0xc162, 0xc072,
+      0xc181, 0xc192, 0xc1a1, 0xc1b6, 0xc1c2, 0xc0d2, 0xc1e2, 0xc1f2
+  };
+  const USHORT PanelTypeTable31030x[16] = {
+      0xc102, 0xc112, 0x0122, 0xc132, 0xc142, 0xc152, 0xc169, 0xc179,
+      0x0189, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+  };
+  const USHORT PanelTypeTable310LVDS[16] = {
+      0xc111, 0xc122, 0xc133, 0xc144, 0xc155, 0xc166, 0xc177, 0xc188,
+      0xc199, 0xc0aa, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+  };
+  USHORT tempax,tempbx,tempah,temp;
+
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+
+    tempax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x18);
+    tempbx = tempax & 0x0F;
+    if(!(tempax & 0x10)){
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 1){
+        tempbx = 0;
+        temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x38);
+        if(temp & 0x40) tempbx |= 0x08;
+        if(temp & 0x20) tempbx |= 0x02;
+        if(temp & 0x01) tempbx |= 0x01;
+        temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x39);
+        if(temp & 0x80) tempbx |= 0x04;
+      } else {
+        return 0;
+      }
+    }
+    tempbx = PanelTypeTable300[tempbx];
+    tempbx |= LCDSync;
+    temp = tempbx & 0x00FF;
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,0x36,temp);
+    temp = (tempbx & 0xFF00) >> 8;
+    SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),temp);
+
+  } else {
+
+    tempax = tempah = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1a);
+    tempax &= 0x1e;
+    tempax >>= 1;
+    if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+       if(tempax == 0) {
+           /* TODO: Include HUGE detection routine
+	            (Probably not worth bothering)
+	    */
+           return 0;
+       }
+       temp = tempax & 0xff;
+       tempax--;
+       tempbx = PanelTypeTable310LVDS[tempax];
+    } else {
+       tempbx = PanelTypeTable31030x[tempax];
+       temp = tempbx & 0xff;
+    }
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,0x36,temp);
+    tempbx = (tempbx & 0xff00) >> 8;
+    temp = tempbx & 0xc1;
+    SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),temp);
+    if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+       temp = tempbx & 0x04;
+       SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x39,0xfb,temp);
+    }
+
+  }
+  return 1;
 }
 
-/* =============  ynlai ============== */
+
+#ifdef LINUXBIOS
+
 void
-SiS_DetectMonitor(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
+SiS_DetectMonitor(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
 {
-  UCHAR  DAC_TEST_PARMS[]={0x0F,0x0F,0x0F};
-  UCHAR  DAC_CLR_PARMS[]={0x00,0x00,0x00};
+  UCHAR  DAC_TEST_PARMS[] = {0x0F,0x0F,0x0F};
+  UCHAR  DAC_CLR_PARMS[]  = {0x00,0x00,0x00};
   USHORT SR1F;
 
-  SR1F=SiS_GetReg1(SiS_P3c4,0x1F);		/* DAC pedestal */
-  SiS_SetRegANDOR(SiS_P3c4,0x1F,0xFF,0x04);
-  if(SiS_IF_DEF_LVDS==0) {
-    if(SiS_BridgeIsOn(BaseAddr)) {
-      SiS_SetReg1(SiS_P3d4,0x30,0x41);
+  SR1F = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1F);		/* backup DAC pedestal */
+  SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1F,0x04);
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+    if(!(SiS_BridgeIsOn(SiS_Pr, BaseAddr))) {
+      SiS_SetReg1(SiS_Pr->SiS_P3d4,0x30,0x41);
     }
   }
-  /*SiSSetMode(HwDeviceExtension,0x03);  */ /* ynlai InitMode */
 
-#ifdef LINUX_XF86
-  SiSSetMode(HwDeviceExtension,NULL,0x2E); 
-#else
-  SiSSetMode(HwDeviceExtension,0x2E);   /* alan */
-#endif
-  SiS_SetReg3(SiS_P3c6,0xff);
-  SiS_ClearDAC(SiS_P3c8);
-  SiS_LongWait();
-  SiS_LongWait();
-  SiS_SetRegANDOR(SiS_P3d4,0x32,0xDF,0x00);
-  if(SiS_TestMonitorType(DAC_TEST_PARMS[0],DAC_TEST_PARMS[1],DAC_TEST_PARMS[2])) {
-    SiS_SetRegANDOR(SiS_P3d4,0x32,0xDF,0x20);
-  }
-  if(SiS_TestMonitorType(DAC_TEST_PARMS[0],DAC_TEST_PARMS[1],DAC_TEST_PARMS[2])) {
-    SiS_SetRegANDOR(SiS_P3d4,0x32,0xDF,0x20);
+  SiSSetMode(SiS_Pr,HwDeviceExtension,0x2E);
+  if(HwDeviceExtension->jChipType > SIS_315PRO) {
+     /* TW: On 650 only - enable CRT1 */
+     SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x63,0xbf);
+  }
+  SiS_SetReg3(SiS_Pr->SiS_P3c6,0xff);
+  SiS_ClearDAC(SiS_Pr, SiS_Pr->SiS_P3c8);
+  SiS_LongWait(SiS_Pr);
+  SiS_LongWait(SiS_Pr);
+  SiS_LongWait(SiS_Pr);
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,0xDF,0x00);
+  if(SiS_TestMonitorType(SiS_Pr, DAC_TEST_PARMS[0],DAC_TEST_PARMS[1],DAC_TEST_PARMS[2])) {
+    SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,0xDF,0x20);
+  } else if(SiS_TestMonitorType(SiS_Pr, DAC_TEST_PARMS[0],DAC_TEST_PARMS[1],DAC_TEST_PARMS[2])) {
+    SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,0xDF,0x20);
   }
-  SiS_TestMonitorType(DAC_CLR_PARMS[0],DAC_CLR_PARMS[1],DAC_CLR_PARMS[2]);
-  SiS_SetReg1(SiS_P3c4,0x1F,SR1F);
+  SiS_TestMonitorType(SiS_Pr, DAC_CLR_PARMS[0],DAC_CLR_PARMS[1],DAC_CLR_PARMS[2]);
+
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1F,SR1F);
 }
 
 USHORT
-SiS_TestMonitorType(UCHAR R_DAC,UCHAR G_DAC,UCHAR B_DAC)
+SiS_TestMonitorType(SiS_Private *SiS_Pr, UCHAR R_DAC,UCHAR G_DAC,UCHAR B_DAC)
 {
    USHORT temp,tempbx;
 
-   tempbx=R_DAC*0x4d+G_DAC*0x97+B_DAC*0x1c;
-   if(tempbx>0x80) tempbx=tempbx+0x100;
-   tempbx = (tempbx&0xFF00)>>8;
+   tempbx = R_DAC * 0x4d + G_DAC * 0x97 + B_DAC * 0x1c;
+   if((tempbx & 0x00ff) > 0x80) tempbx += 0x100;
+   tempbx = (tempbx & 0xFF00) >> 8;
    R_DAC = (UCHAR) tempbx;
    G_DAC = (UCHAR) tempbx;
    B_DAC = (UCHAR) tempbx;
 
-   SiS_SetReg3(SiS_P3c8,0x00);
-   SiS_SetReg3(SiS_P3c9,R_DAC);
-   SiS_SetReg3(SiS_P3c9,G_DAC);
-   SiS_SetReg3(SiS_P3c9,B_DAC);
-   SiS_LongWait();
-   temp=SiS_GetReg2(SiS_P3c2);
-   if(temp&0x10) return(1);
+   SiS_SetReg3(SiS_Pr->SiS_P3c8,0x00);
+   SiS_SetReg3(SiS_Pr->SiS_P3c9,R_DAC);
+   SiS_SetReg3(SiS_Pr->SiS_P3c9,G_DAC);
+   SiS_SetReg3(SiS_Pr->SiS_P3c9,B_DAC);
+   SiS_LongWait(SiS_Pr);
+   temp=SiS_GetReg2(SiS_Pr->SiS_P3c2);
+   if(temp & 0x10) return(1);
    else return(0);
 }
 
-/* ---- test ----- */
 void
-SiS_GetSenseStatus(PSIS_HW_DEVICE_INFO HwDeviceExtension,ULONG ROMAddr)
+SiS_GetSenseStatus(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,UCHAR *ROMAddr)
 {
   USHORT tempax=0,tempbx,tempcx,temp;
-  USHORT P2reg0=0,SenseModeNo=0,OutputSelect=*pSiS_OutputSelect;
+  USHORT P2reg0=0,SenseModeNo=0,OutputSelect=*SiS_Pr->pSiS_OutputSelect;
   USHORT ModeIdIndex,i;
   USHORT BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
 
-  if(SiS_IF_DEF_LVDS==1){
-    SiS_GetPanelID();
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1){
+    SiS_GetPanelID(SiS_Pr);
     temp=LCDSense;
-    temp=temp|SiS_SenseCHTV();
+    temp=temp|SiS_SenseCHTV(SiS_Pr);
     tempbx=~(LCDSense|AVIDEOSense|SVIDEOSense);
-    SiS_SetRegANDOR(SiS_P3d4,0x32,tempbx,temp);
+    SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,tempbx,temp);
   } else {       /* for 301 */
-    if(SiS_IF_DEF_HiVision==1) {  /* for HiVision */
-      tempax=SiS_GetReg1(SiS_P3c4,0x38);
+    if(SiS_Pr->SiS_IF_DEF_HiVision==1) {  /* for HiVision */
+      tempax=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x38);
       temp=tempax&0x01;
-      tempax=SiS_GetReg1(SiS_P3c4,0x3A);
+      tempax=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3A);
       temp=temp|(tempax&0x02);
-      SiS_SetRegANDOR(SiS_P3d4,0x32,0xA0,temp);
+      SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,0xA0,temp);
     } else {
-      if(SiS_BridgeIsOn(BaseAddr)) {
-        P2reg0 = SiS_GetReg1(SiS_Part2Port,0x00);
-        if(!SiS_BridgeIsEnable(BaseAddr,HwDeviceExtension)) {
+      if(SiS_BridgeIsOn(SiS_Pr, BaseAddr)==0) {    /* TW: Inserted "==0" */
+        P2reg0 = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x00);
+        if(!(SiS_BridgeIsEnable(SiS_Pr, BaseAddr,HwDeviceExtension))) {
           SenseModeNo=0x2e;
-          temp = SiS_SearchModeID(ROMAddr,SenseModeNo,&ModeIdIndex);
-          SiS_SetFlag = 0x00;
-          SiS_ModeType = ModeVGA;
-          SiS_VBInfo = SetCRT2ToRAMDAC |LoadDACFlag |SetInSlaveMode;
-          SiS_SetCRT2Group301(BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension);
+          temp = SiS_SearchModeID(SiS_Pr, ROMAddr,&SenseModeNo,&ModeIdIndex);
+          SiS_Pr->SiS_SetFlag = 0x00;
+          SiS_Pr->SiS_ModeType = ModeVGA;
+          SiS_Pr->SiS_VBInfo = SetCRT2ToRAMDAC |LoadDACFlag |SetInSlaveMode;
+          SiS_SetCRT2Group301(SiS_Pr, BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension);
           for(i=0;i<20;i++) {
-            SiS_LongWait();
+            SiS_LongWait(SiS_Pr);
           }
         }
-        SiS_SetReg1(SiS_Part2Port,0x00,0x1c);
+        SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x00,0x1c);
         tempax=0;
-        tempbx=*pSiS_RGBSenseData;
-        /*301b*/
-	if(!(SiS_Is301B(BaseAddr))){
-                tempbx=*pSiS_RGBSenseData2;
+        tempbx=*SiS_Pr->pSiS_RGBSenseData;
+	if(SiS_Is301B(SiS_Pr, BaseAddr)){
+                tempbx=*SiS_Pr->pSiS_RGBSenseData2;
         }
-        /*end 301b*/	
         tempcx=0x0E08;
-        if(SiS_Sense(SiS_Part4Port,tempbx,tempcx)){
-          if(SiS_Sense(SiS_Part4Port,tempbx,tempcx)){
+        if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
+          if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
             tempax=tempax|Monitor2Sense;
           }
         }
-
-        tempbx=*pSiS_YCSenseData;
-         /*301b*/
-        if(!(SiS_Is301B(BaseAddr))){
-               tempbx=*pSiS_YCSenseData2;  
+        tempbx=*SiS_Pr->pSiS_YCSenseData;
+        if(SiS_Is301B(SiS_Pr, BaseAddr)){
+               tempbx=*SiS_Pr->pSiS_YCSenseData2;
         }
-        /*301b*/
         tempcx=0x0604;
-        if(SiS_Sense(SiS_Part4Port,tempbx,tempcx)){
-          if(SiS_Sense(SiS_Part4Port,tempbx,tempcx)){
+        if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
+          if(SiS_Sense(SiS_Pr,tempbx,tempcx)){
             tempax=tempax|SVIDEOSense;
           }
         }
 
-        if(OutputSelect&BoardTVType){
-          tempbx=*pSiS_VideoSenseData;
-        /*301b*/
-        if(!(SiS_Is301B(BaseAddr))){
-             tempbx=*pSiS_VideoSenseData2;
+	if(ROMAddr && SiS_Pr->SiS_UseROM) {
+#ifdef SIS300
+	   if((HwDeviceExtension->jChipType==SIS_630)||
+              (HwDeviceExtension->jChipType==SIS_730)) {
+		OutputSelect = ROMAddr[0xfe];
+	   }
+#endif
+#ifdef SIS315H
+	   if(HwDeviceExtension->jChipType >= SIS_315H) {
+	        OutputSelect = ROMAddr[0xf3];
+	   }
+#endif
         }
-        /*end 301b*/
+        if(OutputSelect&BoardTVType){
+          tempbx=*SiS_Pr->pSiS_VideoSenseData;
+          if(SiS_Is301B(SiS_Pr, BaseAddr)){
+             tempbx=*SiS_Pr->pSiS_VideoSenseData2;
+          }
           tempcx=0x0804;
-          if(SiS_Sense(SiS_Part4Port,tempbx,tempcx)){
-            if(SiS_Sense(SiS_Part4Port,tempbx,tempcx)){
+          if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
+            if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
               tempax=tempax|AVIDEOSense;
             }
           }
         } else {
           if(!(tempax&SVIDEOSense)){
-            tempbx=*pSiS_VideoSenseData;
-            /*301b*/
-            if(!(SiS_Is301B(BaseAddr))){
-              tempbx=*pSiS_VideoSenseData2;
+            tempbx=*SiS_Pr->pSiS_VideoSenseData;
+            if(SiS_Is301B(SiS_Pr, BaseAddr)){
+              tempbx=*SiS_Pr->pSiS_VideoSenseData2;
             }
-            /*end 301b*/
             tempcx=0x0804;
-            if(SiS_Sense(SiS_Part4Port,tempbx,tempcx)){
-              if(SiS_Sense(SiS_Part4Port,tempbx,tempcx)){
+            if(SiS_Sense(SiS_Pr,tempbx,tempcx)){
+              if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
                 tempax=tempax|AVIDEOSense;
               }
             }
@@ -3707,61 +4253,60 @@
         }
       }
 
-      if(SiS_SenseLCD(HwDeviceExtension)){
+      if(SiS_SenseLCD(SiS_Pr, HwDeviceExtension)){
         tempax=tempax|LCDSense;
       }
 
       tempbx=0;
       tempcx=0;
-      SiS_Sense(SiS_Part4Port,tempbx,tempcx);
-  
-      if((SiS_VBType&VB_SIS301LV)||(SiS_VBType&VB_SIS302LV)){
-         tempax=tempax&0x00ef;   				/* 301lv to disable CRT2*/
+      SiS_Sense(SiS_Pr, tempbx,tempcx);
+
+      if(SiS_Pr->SiS_VBType & (VB_SIS30xLV|VB_SIS30xLVX)){   /* TW: prev. 301LV|302LV */
+         tempax &= 0x00ef;   /* 301lv to disable CRT2*/
       }
-      SiS_SetRegANDOR(SiS_P3d4,0x32,~0xDF,tempax);
-      SiS_SetReg1(SiS_Part2Port,0x00,P2reg0);
+      SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,~0xDF,tempax);
+      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x00,P2reg0);
       if(!(P2reg0&0x20)) {
-        SiS_VBInfo = DisableCRT2Display;
-        SiS_SetCRT2Group301(BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension);
+        SiS_Pr->SiS_VBInfo = DisableCRT2Display;
+        SiS_SetCRT2Group301(SiS_Pr,BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension);
       }
     }
   }
 }
 
 BOOLEAN
-SiS_Sense(USHORT Part4Port,USHORT tempbx,USHORT tempcx)
+SiS_Sense(SiS_Private *SiS_Pr, USHORT tempbx,USHORT tempcx)
 {
   USHORT temp,i,tempch;
 
-  temp=tempbx&0xFF;
-  SiS_SetReg1(SiS_Part4Port,0x11,temp);
-  temp=(tempbx&0xFF00)>>8;
-  temp=temp|(tempcx&0x00FF);
-  SiS_SetRegANDOR(SiS_Part4Port,0x10,~0x1F,temp);
-
-  for(i=0;i<10;i++) SiS_LongWait();
-
-  tempch=(tempcx&0x7F00)>>8;      /*   ynlai [05/22/2001]  */
-  temp=SiS_GetReg1(SiS_Part4Port,0x03);
-  temp=temp^(0x0E);
-  temp=temp&tempch;               /*   ynlai [05/22/2001]  */
+  temp = tempbx & 0xFF;
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x11,temp);
+  temp = (tempbx & 0xFF00) >> 8;
+  temp |= (tempcx & 0x00FF);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x10,~0x1F,temp);
+
+  for(i=0; i<10; i++) SiS_LongWait(SiS_Pr);
+
+  tempch = (tempcx & 0x7F00) >> 8;
+  temp = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x03);
+  temp ^= 0x0E;
+  temp &= tempch;
   if(temp>0) return 1;
   else return 0;
 }
 
 USHORT
-SiS_SenseLCD(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_SenseLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-/*  USHORT SoftSetting; */
   USHORT temp;
 
-  temp=SiS_GetPanelID();
-  if(!temp)  temp=SiS_GetLCDDDCInfo(HwDeviceExtension);
+  temp=SiS_GetPanelID(SiS_Pr);
+  if(!temp)  temp=SiS_GetLCDDDCInfo(SiS_Pr, HwDeviceExtension);
   return(temp);
 }
 
 BOOLEAN
-SiS_GetLCDDDCInfo(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_GetLCDDDCInfo(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT temp;
   /*add lcd sense*/
@@ -3769,79 +4314,32 @@
     	return 0;
   else{
      	temp=(USHORT)HwDeviceExtension->ulCRT2LCDType;
-     	SiS_SetReg1(SiS_P3d4,0x36,temp);
+     	SiS_SetReg1(SiS_Pr->SiS_P3d4,0x36,temp);
   	return 1;
   }
 }
 
-BOOLEAN
-SiS_GetPanelID(void)
-{
-  USHORT PanelTypeTable[16]={ SyncNN | PanelRGB18Bit | Panel800x600  | _PanelType00,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType01,
-                              SyncPP | PanelRGB18Bit | Panel800x600  | _PanelType02,
-                              SyncNN | PanelRGB18Bit | Panel640x480  | _PanelType03,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType04,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType05,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType06,
-                              SyncNN | PanelRGB24Bit | Panel1024x768 | _PanelType07,
-                              SyncNN | PanelRGB18Bit | Panel800x600  | _PanelType08,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType09,
-                              SyncNN | PanelRGB18Bit | Panel800x600  | _PanelType0A,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0B,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0C,
-                              SyncNN | PanelRGB24Bit | Panel1024x768 | _PanelType0D,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0E,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0F
-                              };
-  USHORT tempax,tempbx,temp;
-/*  USHORT return_flag; */
-
-  tempax=SiS_GetReg1(SiS_P3c4,0x18);
-  tempbx=tempax&0x0F;
-  if(!(tempax&0x10)){
-    if(SiS_IF_DEF_LVDS==1){
-      tempbx=0;
-      temp=SiS_GetReg1(SiS_P3c4,0x38);
-      if(temp&0x40) tempbx=tempbx|0x08;
-      if(temp&0x20) tempbx=tempbx|0x02;
-      if(temp&0x01) tempbx=tempbx|0x01;
-      temp=SiS_GetReg1(SiS_P3c4,0x39);
-      if(temp&0x80) tempbx=tempbx|0x04;
-    }else{
-      return 0;
-    }
-  }
-
-  tempbx=tempbx<<1;
-  tempbx=PanelTypeTable[tempbx];
-  tempbx=tempbx|LCDSync;
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_P3d4,0x36,temp);
-  temp=(tempbx&0xFF00)>>8;
-  SiS_SetRegANDOR(SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),temp);
-  return 1;
-}
-
 USHORT
-SiS_SenseCHTV(void)
+SiS_SenseCHTV(SiS_Private *SiS_Pr)
 {
   USHORT temp,push0e,status;
 
   status=0;
-  push0e=SiS_GetCH7005(0x0e);
-  push0e=(push0e<<8)|0x0e;
-  SiS_SetCH7005(0x0b0e);
-  SiS_SetCH7005(0x0110);
-  SiS_SetCH7005(0x0010);
-  temp=SiS_GetCH7005(0x10);
-  if(temp&0x08) status=status|SVIDEOSense;
-  if(temp&0x02) status=status|AVIDEOSense;
-  SiS_SetCH7005(push0e);
+  push0e = SiS_GetCH700x(SiS_Pr, 0x0e);
+  push0e = (push0e << 8) | 0x0e;
+  SiS_SetCH700x(SiS_Pr, 0x0b0e);
+  SiS_SetCH700x(SiS_Pr, 0x0110);
+  SiS_SetCH700x(SiS_Pr, 0x0010);
+  temp = SiS_GetCH700x(SiS_Pr, 0x10);
+  if(temp & 0x08) status |= SVIDEOSense;
+  if(temp & 0x02) status |= AVIDEOSense;
+  SiS_SetCH700x(SiS_Pr, push0e);
   return(status);
 }
+#endif /* LINUXBIOS */
+
+/*  ================ for TC only =================  */
 
-/*  ================for TC only =================  */
 #ifdef TC
 
 int
@@ -3940,74 +4438,418 @@
     /*ModeNo=0x4A; *//* 1024x768x 16bpp */
     /*ModeNo=0x47;*/ /* 800x600x 16bpp */
   }
- /* SiSInit(&HwDeviceExtension);*/
-#ifdef LINUX_XF86
-  SiSSetMode(&HwDeviceExtension,NULL, ModeNo);
-#else
-  SiSSetMode(&HwDeviceExtension,ModeNo);
-#endif
+ /* SiSInit(SiS_Pr, &HwDeviceExtension);*/
+  SiSSetMode(SiS_Pr, &HwDeviceExtension, ModeNo);
 }
-#endif /* TC */
+#endif /* TC END */
+
+/* ================ LINUX XFREE86 ====================== */
+
+/* Helper functions */
 
-/* TW: New for Linux XF86 */
 #ifdef LINUX_XF86
 USHORT
 SiS_CalcModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode)
 {
-   UShort i = (pScrn->bitsPerPixel+7)/8 - 1;
+   SISPtr pSiS = SISPTR(pScrn);
+   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
    UShort ModeIndex = 0;
+
    switch(mode->HDisplay)
    {
+     case 320:
+          if(mode->VDisplay == 480) {
+                ModeIndex = ModeIndex_320x480[i];
+	  }
+          break;
+     case 512:
+          if(mode->VDisplay == 384) {
+             ModeIndex = ModeIndex_512x384[i];
+	  }
+          break;
      case 640:
-          ModeIndex = ModeIndex_640x480[i];
+          if(mode->VDisplay == 480) {
+             ModeIndex = ModeIndex_640x480[i];
+	  }
           break;
      case 720:
-          if(mode->VDisplay == 480)
-            ModeIndex = ModeIndex_720x480[i];
-          else
-            ModeIndex = ModeIndex_720x576[i];
+          if(mode->VDisplay == 480) {
+                ModeIndex = ModeIndex_720x480[i];
+          } else if(mode->VDisplay == 576) {
+                ModeIndex = ModeIndex_720x576[i];
+          }
           break;
      case 800:
-          ModeIndex = ModeIndex_800x600[i];
+	  if(mode->VDisplay == 600) {
+             ModeIndex = ModeIndex_800x600[i];
+	  } else if(pSiS->VGAEngine == SIS_315_VGA) {
+	     if(mode->VDisplay == 480) {
+	           ModeIndex = ModeIndex_800x480[i];
+             }
+	  }
           break;
      case 1024:
-          ModeIndex = ModeIndex_1024x768[i];
+          if(mode->VDisplay == 768) {
+	        ModeIndex = ModeIndex_1024x768[i];
+	  } else if(pSiS->VGAEngine == SIS_315_VGA) {
+	     if(mode->VDisplay == 576) {
+	        ModeIndex = ModeIndex_1024x576[i];
+             }
+	  } else if(pSiS->VGAEngine == SIS_300_VGA) {
+	     if(mode->VDisplay == 600) {
+	        ModeIndex = ModeIndex_1024x600[i];
+             }
+	  }
           break;
+     case 1152:
+          if(pSiS->VGAEngine == SIS_300_VGA) {
+	     if(mode->VDisplay == 768) {
+	        ModeIndex = ModeIndex_1152x768[i];
+             }
+	  }
+	  break;
      case 1280:
-          if(mode->VDisplay == 960)
-            ModeIndex = ModeIndex_1280x960[i];
-          else
-            ModeIndex = ModeIndex_1280x1024[i];
+          if(mode->VDisplay == 960) {
+             if(pSiS->VGAEngine == SIS_300_VGA) {
+	        ModeIndex = ModeIndex_300_1280x960[i];
+             } else {
+                ModeIndex = ModeIndex_310_1280x960[i];
+             }
+	  } else if (mode->VDisplay == 1024) {
+	     ModeIndex = ModeIndex_1280x1024[i];
+	  } else if(pSiS->VGAEngine == SIS_315_VGA) {
+	     if (mode->VDisplay == 768) {
+	        ModeIndex = ModeIndex_1280x768[i];
+	     } else if (mode->VDisplay == 720) {
+	        ModeIndex = ModeIndex_1280x720[i];
+             }
+	  }
+          break;
+     case 1400:
+          if(pSiS->VGAEngine == SIS_315_VGA) {
+	     if(mode->VDisplay == 1050) {
+	        ModeIndex = ModeIndex_1400x1050[i];
+             }
+	  }
           break;
      case 1600:
-          ModeIndex = ModeIndex_1600x1200[i];
+          if(mode->VDisplay == 1200) {
+             ModeIndex = ModeIndex_1600x1200[i];
+	  }
           break;
      case 1920:
-          ModeIndex = ModeIndex_1920x1440[i];
+          if(mode->VDisplay == 1440) {
+             ModeIndex = ModeIndex_1920x1440[i];
+	  }
+          break;
+     case 2048:
+          if(pSiS->VGAEngine == SIS_315_VGA) {
+	     if(mode->VDisplay == 1536) {
+	         ModeIndex = ModeIndex_2048x1536[i];
+             }
+	  }
           break;
    }
 
    return(ModeIndex);
 }
 
+USHORT
+SiS_CheckCalcModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode, int VBFlags)
+{
+   SISPtr pSiS = SISPTR(pScrn);
+   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;    
+   UShort ModeIndex = 0;
+
+   if(VBFlags & CRT2_LCD) {
+
+      if( (mode->HDisplay <= pSiS->LCDwidth) &&
+          (mode->VDisplay <= pSiS->LCDheight) ) {
+
+        if(VBFlags & VB_LVDS) {        		/* LCD on LVDS */
+
+          switch(mode->HDisplay)
+  	  {
+	  case 512:
+		if(mode->VDisplay == 384) {
+		   ModeIndex = ModeIndex_512x384[i];
+		}
+		break;
+	  case 640:
+		if(mode->VDisplay == 480) {
+		   ModeIndex = ModeIndex_640x480[i];
+		}
+		break;
+	  case 800:
+		if(mode->VDisplay == 600) {
+		   ModeIndex = ModeIndex_800x600[i];
+		}
+		break;
+	  case 1024:
+		if(mode->VDisplay == 768) {
+		   ModeIndex = ModeIndex_1024x768[i];
+		} else if(pSiS->VGAEngine == SIS_300_VGA) {
+		   if(mode->VDisplay == 600) {
+		      ModeIndex = ModeIndex_1024x600[i];
+		   }
+		}
+		break;
+	  case 1152:
+		if(pSiS->VGAEngine == SIS_300_VGA) {
+		   if(mode->VDisplay == 768) {
+			ModeIndex = ModeIndex_1152x768[i];
+		   }
+		}
+		break;
+	  case 1280:
+		if(mode->VDisplay == 1024) {
+		   ModeIndex = ModeIndex_1280x1024[i];
+		} else if(pSiS->VGAEngine == SIS_315_VGA) {
+		   if(mode->VDisplay == 768) {
+		      ModeIndex = ModeIndex_1280x768[i];
+		   }
+		}
+		break;
+	  case 1400:
+	        if(mode->VDisplay == 1050) {
+		   if(pSiS->VGAEngine == SIS_315_VGA) {
+		      ModeIndex = ModeIndex_1400x1050[i];
+		   }
+		}
+		break;
+          }
+
+        } else {                       	 	/* LCD on 301(B) */
+
+          switch(mode->HDisplay)
+	  {
+	  case 512:
+		if(mode->VDisplay == 384) {
+		   ModeIndex = ModeIndex_512x384[i];
+		}
+		break;
+	  case 640:
+		if(mode->VDisplay == 480) {
+		   ModeIndex = ModeIndex_640x480[i];
+		}
+		break;
+	  case 800:
+		if(mode->VDisplay == 600) {
+		   ModeIndex = ModeIndex_800x600[i];
+		}
+		break;
+	  case 1024:
+		if(mode->VDisplay == 768) {
+		   ModeIndex = ModeIndex_1024x768[i];
+		} /* else if(pSiS->VGAEngine == SIS_300_VGA) {  --  not supported on 301(B) --
+		   if(mode->VDisplay == 600) {
+			ModeIndex = ModeIndex_1024x600[i];
+		   }
+		} */
+		break;
+	  case 1152:  /* not supported on 301(B) */
+#if 0
+		if(pSiS->VGAEngine == SIS_300_VGA) {
+		   if(mode->VDisplay == 768) {
+			ModeIndex = ModeIndex_1152x768[i];
+		   }
+		}
+#endif
+		break;
+	  case 1280:
+		if(mode->VDisplay == 960) {
+		   if(pSiS->VGAEngine == SIS_300_VGA) {
+		      ModeIndex = ModeIndex_300_1280x960[i];
+		   } else {
+		      ModeIndex = ModeIndex_310_1280x960[i];
+		   }
+                } else if (mode->VDisplay == 1024) {
+	             ModeIndex = ModeIndex_1280x1024[i];
+	        }
+	  case 1600:
+		if(mode->VDisplay == 1200) {
+		   ModeIndex = ModeIndex_1600x1200[i];
+		}
+		break;
+	  }
+
+        }
+
+      }
+
+   } else if(VBFlags & CRT2_TV) {
+
+      if(VBFlags & VB_CHRONTEL) {		/* TV on Chrontel */
+
+        switch(mode->HDisplay)
+	{
+      	case 512:
+		if(mode->VDisplay == 384) {
+		   ModeIndex = ModeIndex_512x384[i];
+		}
+		break;
+	case 640:
+		if(mode->VDisplay == 480) {
+		   ModeIndex = ModeIndex_640x480[i];
+		}
+		break;
+	case 800:
+		if(mode->VDisplay == 600) {
+		   ModeIndex = ModeIndex_800x600[i];
+		}
+		break;
+	case 1024:
+		if(mode->VDisplay == 768) {
+		   if(pSiS->VGAEngine == SIS_315_VGA) {
+		      ModeIndex = ModeIndex_1024x768[i];
+		   }
+		}
+		break;
+        }
+
+      } else {				    /* TV on 301(B) */
+
+        switch(mode->HDisplay)
+	{
+      	case 512:
+		if(mode->VDisplay == 384) {
+		   ModeIndex = ModeIndex_512x384[i];
+		}
+		break;
+	case 640:
+		if(mode->VDisplay == 480) {
+		   ModeIndex = ModeIndex_640x480[i];
+		}
+		break;
+	case 720:
+                if(mode->VDisplay == 480) {
+                   ModeIndex = ModeIndex_720x480[i];
+                } else if(mode->VDisplay == 576) {
+                   ModeIndex = ModeIndex_720x576[i];
+                }
+                break;
+	case 800:
+		if(mode->VDisplay == 600) {
+		   ModeIndex = ModeIndex_800x600[i];
+		}
+		break;
+	case 1024:
+		if(mode->VDisplay == 768) {
+		   if(VBFlags & (VB_301B|VB_302B|VB_30xLV|VB_30xLVX)) {
+		      ModeIndex = ModeIndex_1024x768[i];
+		   }
+		}
+		break;
+        }
+
+      }
+
+   } else if(VBFlags & CRT2_VGA) {		/* CRT2 is VGA2 */
+
+	switch(mode->HDisplay)
+	{
+	case 512:
+		if(mode->VDisplay == 384) {
+		    ModeIndex = ModeIndex_512x384[i];
+		}
+		break;
+	case 640:
+		if(mode->VDisplay == 480) {
+		   ModeIndex = ModeIndex_640x480[i];
+		}
+		break;
+	case 800:
+		if(mode->VDisplay == 600) {
+		   ModeIndex = ModeIndex_800x600[i];
+		} else if(pSiS->VGAEngine == SIS_315_VGA) {
+		   if(mode->VDisplay == 480) {
+			ModeIndex = ModeIndex_800x480[i];
+		   }
+		}
+		break;
+	case 1024:
+		if(mode->VDisplay == 768) {
+			ModeIndex = ModeIndex_1024x768[i];
+		} else if(pSiS->VGAEngine == SIS_315_VGA) {
+		   if(mode->VDisplay == 576) {
+			ModeIndex = ModeIndex_1024x576[i];
+		   }
+		}
+		break;
+	case 1152:
+		if(pSiS->VGAEngine == SIS_300_VGA) {
+		   if(mode->VDisplay == 768) {
+			ModeIndex = ModeIndex_1152x768[i];
+		   }
+		}
+		break;
+	case 1280:
+		if (mode->VDisplay == 1024) {
+		   ModeIndex = ModeIndex_1280x1024[i];
+		} else if(pSiS->VGAEngine == SIS_315_VGA) {
+		   if (mode->VDisplay == 768) {
+			ModeIndex = ModeIndex_1280x768[i];
+		   } else if (mode->VDisplay == 720) {
+			ModeIndex = ModeIndex_1280x720[i];
+		   }
+		}
+		break;
+	case 1400:
+		if(pSiS->VGAEngine == SIS_315_VGA) {
+		   ModeIndex = ModeIndex_1400x1050[i];
+		}
+		break;
+	}
+
+   } else {				/* CRT1 only, no CRT2 */
+
+       ModeIndex = SiS_CalcModeIndex(pScrn, mode);
+
+   }
+
+   return(ModeIndex);
+}
+
 #define MODEID_OFF 0x449
 
 unsigned char
 SiS_GetSetModeID(ScrnInfoPtr pScrn, unsigned char id)
 {
+    return(SiS_GetSetMMIOReg(pScrn, MODEID_OFF, id));
+}
+
+unsigned char
+SiS_GetSetMMIOReg(ScrnInfoPtr pScrn, USHORT offset, unsigned char value)
+{
     unsigned char ret;
+    unsigned char *base;
+    SISPtr pSiS = SISPTR(pScrn);
+    BOOLEAN mapped;
 
-    unsigned char* base = xf86MapVidMem(pScrn->scrnIndex,
-					VIDMEM_MMIO, 0, 0x2000);
-    ret = *(base + MODEID_OFF);
-
-    /* id != 0xff means: set mode */
-    if (id != 0xff)
-	*(base + MODEID_OFF) = id;
-    xf86UnMapVidMem(pScrn->scrnIndex,base,0x2000);
+    if(pSiS->IOBase) {
+    	base = (unsigned char *)pSiS->IOBase;
+	mapped = FALSE;
+    } else {
+        base = xf86MapVidMem(pScrn->scrnIndex, VIDMEM_MMIO, 0, 0x2000);
+	if(!base) {
+	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+	          "(init.c: Could not MMIO area!)\n");
+	     return 0;
+	}
+	mapped = TRUE;
+    }
+
+    ret = *(base + offset);
+
+    /* value != 0xff means: set register */
+    if (value != 0xff)
+	*(base + offset) = value;
+
+    if(mapped) xf86UnMapVidMem(pScrn->scrnIndex, base, 0x2000);
 
     return ret;
 }
+
 #endif
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/init.h linux-2.4.20/drivers/video/sis/init.h
--- linux-2.4.19/drivers/video/sis/init.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/init.h	2002-10-29 11:18:35.000000000 +0000
@@ -16,6 +16,7 @@
 
 #ifdef LINUX_XF86
 #include "xf86.h"
+#include "xf86Pci.h"
 #include "xf86PciInfo.h"
 #include "xf86_OSproc.h"
 #include "sis.h"
@@ -35,246 +36,273 @@
 #include "dderror.h"
 #include "devioctl.h"
 #include "miniport.h"
-
 #include "ntddvdeo.h"
 #include "video.h"
 #include "sisv.h"
+#include "tools.h"
 #endif
 
-USHORT SiS_DRAMType[17][5]={{0x0C,0x0A,0x02,0x40,0x39},{0x0D,0x0A,0x01,0x40,0x48},
-                     {0x0C,0x09,0x02,0x20,0x35},{0x0D,0x09,0x01,0x20,0x44},
-                     {0x0C,0x08,0x02,0x10,0x31},{0x0D,0x08,0x01,0x10,0x40},
-                     {0x0C,0x0A,0x01,0x20,0x34},{0x0C,0x09,0x01,0x08,0x32},
-                     {0x0B,0x08,0x02,0x08,0x21},{0x0C,0x08,0x01,0x08,0x30},
-                     {0x0A,0x08,0x02,0x04,0x11},{0x0B,0x0A,0x01,0x10,0x28},
-                     {0x09,0x08,0x02,0x02,0x01},{0x0B,0x09,0x01,0x08,0x24},
-                     {0x0B,0x08,0x01,0x04,0x20},{0x0A,0x08,0x01,0x02,0x10},
-                     {0x09,0x08,0x01,0x01,0x00}};
+const USHORT SiS_DRAMType[17][5]={
+	{0x0C,0x0A,0x02,0x40,0x39},
+	{0x0D,0x0A,0x01,0x40,0x48},
+	{0x0C,0x09,0x02,0x20,0x35},
+	{0x0D,0x09,0x01,0x20,0x44},
+	{0x0C,0x08,0x02,0x10,0x31},
+	{0x0D,0x08,0x01,0x10,0x40},
+	{0x0C,0x0A,0x01,0x20,0x34},
+	{0x0C,0x09,0x01,0x08,0x32},
+	{0x0B,0x08,0x02,0x08,0x21},
+	{0x0C,0x08,0x01,0x08,0x30},
+	{0x0A,0x08,0x02,0x04,0x11},
+	{0x0B,0x0A,0x01,0x10,0x28},
+	{0x09,0x08,0x02,0x02,0x01},
+	{0x0B,0x09,0x01,0x08,0x24},
+	{0x0B,0x08,0x01,0x04,0x20},
+	{0x0A,0x08,0x01,0x02,0x10},
+	{0x09,0x08,0x01,0x01,0x00}
+};
 
-USHORT SiS_SDRDRAM_TYPE[13][5]=
+const USHORT SiS_SDRDRAM_TYPE[13][5] =
 {
-{ 2,12, 9,64,0x35},
-{ 1,13, 9,64,0x44},
-{ 2,12, 8,32,0x31},
-{ 2,11, 9,32,0x25},
-{ 1,12, 9,32,0x34},
-{ 1,13, 8,32,0x40},
-{ 2,11, 8,16,0x21},
-{ 1,12, 8,16,0x30},
-{ 1,11, 9,16,0x24},
-{ 1,11, 8, 8,0x20},
-{ 2, 9, 8, 4,0x01},
-{ 1,10, 8, 4,0x10},
-{ 1, 9, 8, 2,0x00}
+	{ 2,12, 9,64,0x35},
+	{ 1,13, 9,64,0x44},
+	{ 2,12, 8,32,0x31},
+	{ 2,11, 9,32,0x25},
+	{ 1,12, 9,32,0x34},
+	{ 1,13, 8,32,0x40},
+	{ 2,11, 8,16,0x21},
+	{ 1,12, 8,16,0x30},
+	{ 1,11, 9,16,0x24},
+	{ 1,11, 8, 8,0x20},
+	{ 2, 9, 8, 4,0x01},
+	{ 1,10, 8, 4,0x10},
+	{ 1, 9, 8, 2,0x00}
 };
 
-USHORT SiS_DDRDRAM_TYPE[4][5]=
+const USHORT SiS_DDRDRAM_TYPE[4][5] =
 {
-{ 2,12, 9,64,0x35},
-{ 2,12, 8,32,0x31},
-{ 2,11, 8,16,0x21},
-{ 2, 9, 8, 4,0x01}
+	{ 2,12, 9,64,0x35},
+	{ 2,12, 8,32,0x31},
+	{ 2,11, 8,16,0x21},
+	{ 2, 9, 8, 4,0x01}
 };
 
-UCHAR SiS_ChannelAB,SiS_DataBusWidth;
+const USHORT SiS_MDA_DAC[] =
+{
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+        0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
+        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+        0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F
+};
 
+const USHORT SiS_CGA_DAC[] =
+{
+        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+};
 
-USHORT SiS_MDA_DAC[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-               0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-               0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-               0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-               0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F};
-
-USHORT SiS_CGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-               0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-               0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-               0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-               0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-               0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-               0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-               0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F};
-
-USHORT SiS_EGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
-               0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
-               0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
-               0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
-               0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
-               0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
-               0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
-               0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F};
-
-USHORT SiS_VGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-               0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-               0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
-               0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
-
-               0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
-               0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
-               0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
-               0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
-               0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
-               0x0B,0x0C,0x0D,0x0F,0x10};
-
-USHORT      SiS_P3c4,SiS_P3d4,SiS_P3c0,SiS_P3ce,SiS_P3c2;
-USHORT      SiS_P3ca,SiS_P3c6,SiS_P3c7,SiS_P3c8,SiS_P3c9,SiS_P3da;
-USHORT      SiS_Part1Port,SiS_Part2Port;
-USHORT      SiS_Part3Port,SiS_Part4Port,SiS_Part5Port;
-USHORT      SiS_CRT1Mode;
-
-USHORT   flag_clearbuffer;         /*0: no clear frame buffer 1:clear frame buffer  */
-int      SiS_RAMType;              /*int      ModeIDOffset,StandTable,CRT1Table,ScreenOffset,REFIndex;*/
-USHORT   SiS_ModeType;
-USHORT   SiS_IF_DEF_LVDS,SiS_IF_DEF_TRUMPION,SiS_IF_DEF_DSTN,SiS_IF_DEF_FSTN;    /*add for dstn*/
-USHORT   SiS_IF_DEF_CH7005,SiS_IF_DEF_HiVision;
-USHORT	 SiS_Backup7005=0xff;	/* TW: Backup for power-status */
-USHORT   SiS_VBInfo,SiS_LCDResInfo,SiS_LCDTypeInfo,SiS_LCDInfo, SiS_VBType;/*301b*/
-USHORT   SiS_VBExtInfo;  /*301lv*/
-USHORT   SiS_SelectCRT2Rate;
-
-extern   USHORT   SiS_SetFlag;
-extern   USHORT   SiS_DDC_Port;
-
-void     SiS_SetMemoryClock(ULONG ROMAddr);
-void     SiS_SetDRAMModeRegister(ULONG   ROMAddr);
-void     SiS_SetDRAMSize_310(PSIS_HW_DEVICE_INFO);
-void     SiS_SetDRAMSize_300(PSIS_HW_DEVICE_INFO HwDeviceExtension);
-USHORT   SiS_ChkBUSWidth_300(ULONG FBAddress);
-UCHAR    SiS_Get310DRAMType(ULONG   ROMAddr);
-
-BOOLEAN SiS_SearchVBModeID(ULONG ROMAddr, USHORT ModeNo);
-void SiS_IsLowResolution(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-ULONG GetDRAMSize(PSIS_HW_DEVICE_INFO HwDeviceExtension);
+const USHORT SiS_EGA_DAC[] =
+{
+        0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
+        0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
+        0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
+        0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
+        0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
+        0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
+        0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+};
+
+const USHORT SiS_VGA_DAC[] =
+{
+	0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+	0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+	0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
+	0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
+	0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
+	0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
+	0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
+	0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
+	0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
+	0x0B,0x0C,0x0D,0x0F,0x10
+};
+
+void     SiS_SetReg1(USHORT, USHORT, USHORT);
+void     SiS_SetReg2(SiS_Private *, USHORT, USHORT, USHORT);
+void     SiS_SetReg3(USHORT, USHORT);
+void     SiS_SetReg4(USHORT, ULONG);
+UCHAR    SiS_GetReg1(USHORT, USHORT);
+UCHAR    SiS_GetReg2(USHORT);
+ULONG    SiS_GetReg3(USHORT);
+void     SiS_ClearDAC(SiS_Private *SiS_Pr, ULONG);
+void     SiS_SetMemoryClock(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetDRAMModeRegister(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+BOOLEAN  SiS_SearchVBModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT *ModeNo);
+void     SiS_IsLowResolution(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+ULONG    GetDRAMSize(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
 
 #ifdef SIS300
-void InitTo300Pointer(void);
-#endif
-#ifdef SIS315H
-void InitTo310Pointer(void);
+void     InitTo300Pointer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetDRAMSize_300(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+USHORT   SiS_ChkBUSWidth_300(SiS_Private *SiS_Pr, ULONG FBAddress);
 #endif
 
 #ifdef SIS315H
-void SiS_DDR_MRS(void);
-void SiS_SDR_MRS(void);
-void SiS_DisableRefresh(void);
-void SiS_EnableRefresh(ULONG ROMAddr);
-void SiS_DisableChannelInterleaving(int index,USHORT SiS_DDRDRAM_TYPE[][5]);
-void SiS_SetDRAMSizingType(int index,USHORT DRAMTYPE_TABLE[][5]);
-void SiS_CheckBusWidth_310(ULONG ROMAddress,ULONG FBAddress);
-int  SiS_SetRank(int index,UCHAR RankNo,UCHAR SiS_ChannelAB,USHORT DRAMTYPE_TABLE[][5]);
-int  SiS_SetDDRChannel(int index,UCHAR ChannelNo,UCHAR SiS_ChannelAB,USHORT DRAMTYPE_TABLE[][5]);
-int  SiS_CheckColumn(int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int  SiS_CheckBanks(int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int  SiS_CheckRank(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int  SiS_CheckDDRRank(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int  SiS_CheckRanks(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int  SiS_CheckDDRRanks(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int  SiS_SDRSizing(ULONG FBAddress);
-int  SiS_DDRSizing(ULONG FBAddress);
-int  Is315E(void);
-void SiS_VerifyMclk(ULONG FBAddr);
+void     InitTo310Pointer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+UCHAR    SiS_Get310DRAMType(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_DDR_MRS(SiS_Private *SiS_Pr);
+void     SiS_SDR_MRS(SiS_Private *SiS_Pr);
+void     SiS_DisableRefresh(SiS_Private *SiS_Pr);
+void     SiS_EnableRefresh(SiS_Private *SiS_Pr, UCHAR *ROMAddr);
+void     SiS_SetDRAMSize_310(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO);
+void     SiS_DisableChannelInterleaving(SiS_Private *SiS_Pr, int index,USHORT SiS_DDRDRAM_TYPE[][5]);
+void     SiS_SetDRAMSizingType(SiS_Private *SiS_Pr, int index,USHORT DRAMTYPE_TABLE[][5]);
+void     SiS_CheckBusWidth_310(SiS_Private *SiS_Pr, UCHAR *ROMAddress,ULONG FBAddress,
+                               PSIS_HW_DEVICE_INFO HwDeviceExtension);
+int      SiS_SetRank(SiS_Private *SiS_Pr, int index,UCHAR RankNo,USHORT DRAMTYPE_TABLE[][5]);
+int      SiS_SetDDRChannel(SiS_Private *SiS_Pr, int index,UCHAR ChannelNo,
+                           USHORT DRAMTYPE_TABLE[][5]);
+int      SiS_CheckColumn(SiS_Private *SiS_Pr, int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
+int      SiS_CheckBanks(SiS_Private *SiS_Pr, int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
+int      SiS_CheckRank(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
+int      SiS_CheckDDRRank(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
+int      SiS_CheckRanks(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
+int      SiS_CheckDDRRanks(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
+int      SiS_SDRSizing(SiS_Private *SiS_Pr, ULONG FBAddress);
+int      SiS_DDRSizing(SiS_Private *SiS_Pr, ULONG FBAddress);
+int      Is315E(SiS_Private *SiS_Pr);
+void     SiS_VerifyMclk(SiS_Private *SiS_Pr, ULONG FBAddr);
 #endif
 
-/*int    init300(int,int,int);  */
-/*extern      "C"    int     ChkBUSWidth(int);  */
-/*int    setmode(int,int,int,int);  */
-extern void SetEnableDstn(void);
-void     SiS_Delay15us(ULONG);
-BOOLEAN  SiS_SearchModeID(ULONG ROMAddr, USHORT ModeNo,USHORT  *ModeIdIndex);
-BOOLEAN  SiS_CheckMemorySize(ULONG ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+void     SiS_HandleCRT1(SiS_Private *SiS_Pr);
+void     SiS_Handle301B_1400x1050(SiS_Private *SiS_Pr, USHORT ModeNo);
+void     SetEnableDstn(SiS_Private *SiS_Pr);
+void     SiS_Delay15us(SiS_Private *SiS_Pr);
+BOOLEAN  SiS_SearchModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT *ModeNo,USHORT *ModeIdIndex);
+BOOLEAN  SiS_CheckMemorySize(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
                              USHORT ModeNo,USHORT ModeIdIndex);
-UCHAR    SiS_GetModePtr(ULONG ROMAddr, USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_SetSeqRegs(ULONG,USHORT StandTableIndex);
-void     SiS_SetMiscRegs(ULONG,USHORT StandTableIndex);
-void     SiS_SetCRTCRegs(ULONG,PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT StandTableIndex);
-void     SiS_SetATTRegs(ULONG,USHORT StandTableIndex);
-void     SiS_SetGRCRegs(ULONG,USHORT StandTableIndex);
-void     SiS_ClearExt1Regs(void);
-void     SiS_SetSync(ULONG ROMAddr,USHORT RefreshRateTableIndex);
-void     SiS_SetCRT1CRTC(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-void     SiS_SetCRT1VCLK(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO,
+UCHAR    SiS_GetModePtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex);
+void     SiS_SetSeqRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex);
+void     SiS_SetMiscRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex);
+void     SiS_SetCRTCRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                         USHORT StandTableIndex);
+void     SiS_SetATTRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex,USHORT ModeNo,
+                        PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetGRCRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex);
+void     SiS_ClearExt1Regs(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetSync(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT RefreshRateTableIndex);
+void     SiS_SetCRT1CRTC(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                         USHORT RefreshRateTableIndex,
+			 PSIS_HW_DEVICE_INFO HwDeviceExtension);
+BOOLEAN  SiS_GetLCDACRT1Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                            USHORT RefreshRateTableIndex,USHORT *ResInfo,USHORT *DisplayType);
+void     SiS_ResetCRT1VCLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetCRT1VCLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO,
                          USHORT RefreshRateTableIndex);
-void     SiS_SetVCLKState(ULONG ROMAddr,PSIS_HW_DEVICE_INFO, USHORT ModeNo,USHORT RefreshRateTableIndex);
-void     SiS_LoadDAC(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_DisplayOn(void);
-void 	 SiS_DisplayOff(void);
-void     SiS_SetCRT1ModeRegs(ULONG ROMAddr,PSIS_HW_DEVICE_INFO,USHORT ModeNo,
+void     SiS_SetVCLKState(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO, USHORT ModeNo,
+                          USHORT RefreshRateTableIndex, USHORT ModeIdIndex);
+void     SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void     SiS_WriteDAC(SiS_Private *SiS_Pr, USHORT, USHORT, USHORT, USHORT, USHORT, USHORT);
+void     SiS_DisplayOn(SiS_Private *SiS_Pr);
+void 	 SiS_DisplayOff(SiS_Private *SiS_Pr);
+void     SiS_SetCRT1ModeRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO,USHORT ModeNo,
                              USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-void     SiS_WriteDAC(USHORT, USHORT, USHORT, USHORT);
-void     SiS_GetVBType(USHORT BaseAddr);/*301b*/
-USHORT   SiS_ChkBUSWidth(ULONG);
-USHORT   SiS_GetModeIDLength(ULONG, USHORT);
-USHORT   SiS_GetRefindexLength(ULONG, USHORT);
-void     SiS_SetInterlace(ULONG ROMAddr,USHORT ModeNo,USHORT RefreshRateTableIndex);
-USHORT   SiS_CalcDelay2(ULONG ,UCHAR);
-USHORT   SiS_CalcDelay(ULONG ,USHORT);
-void     SiS_Set_LVDS_TRUMPION(PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetCRT1Offset(ULONG,USHORT,USHORT,USHORT,PSIS_HW_DEVICE_INFO);
-void     SiS_SetCRT1FIFO(ULONG,USHORT,PSIS_HW_DEVICE_INFO);
-void     SiS_SetCRT1FIFO2(ULONG,USHORT ModeNo,PSIS_HW_DEVICE_INFO,USHORT RefreshRateTableIndex);
-void     SiS_CRT2AutoThreshold(USHORT  BaseAddr);
-void     SiS_ClearBuffer(PSIS_HW_DEVICE_INFO,USHORT ModeNo);
-void     SiS_SetCRT1Group(ULONG ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                          USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_DetectMonitor(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
-void     SiS_GetSenseStatus(PSIS_HW_DEVICE_INFO HwDeviceExtension,ULONG ROMAddr);
-USHORT   SiS_TestMonitorType(UCHAR R_DAC,UCHAR G_DAC,UCHAR B_DAC);
-USHORT   SiS_SenseCHTV(VOID);
-BOOLEAN  SiS_Sense(USHORT Part4Port,USHORT tempbx,USHORT tempcx);
-BOOLEAN  SiS_GetPanelID(VOID);
-BOOLEAN  SiS_GetLCDDDCInfo(PSIS_HW_DEVICE_INFO);
-USHORT   SiS_SenseLCD(PSIS_HW_DEVICE_INFO);
-void     SiSRegInit(USHORT BaseAddr);
-void     SiSInitPtr(PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiSSetLVDSetc(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo);
-void     SiSInitPCIetc(PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_GetVBType(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO);
+USHORT   SiS_ChkBUSWidth(SiS_Private *SiS_Pr, UCHAR *ROMAddr);
+USHORT   SiS_GetModeIDLength(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT);
+USHORT   SiS_GetRefindexLength(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT);
+void     SiS_SetInterlace(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT RefreshRateTableIndex);
+void     SiS_Set_LVDS_TRUMPION(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetCRT1Offset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT,USHORT,USHORT,PSIS_HW_DEVICE_INFO);
+#ifdef SIS315H
+void     SiS_SetCRT1FIFO_310(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT,USHORT,PSIS_HW_DEVICE_INFO);
+#endif
+#ifdef SIS300
+void     SiS_SetCRT1FIFO_300(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,PSIS_HW_DEVICE_INFO,
+                             USHORT RefreshRateTableIndex);
+void     SiS_SetCRT1FIFO_630(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,PSIS_HW_DEVICE_INFO,
+                             USHORT RefreshRateTableIndex);
+USHORT   SiS_CalcDelay(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT VCLK,
+                       USHORT colordepth, USHORT MCLK);
+USHORT   SiS_DoCalcDelay(SiS_Private *SiS_Pr, USHORT MCLK, USHORT VCLK, USHORT colordepth, USHORT key);
+USHORT   SiS_CalcDelay2(SiS_Private *SiS_Pr, UCHAR *ROMAddr, UCHAR);
+#endif
+void     SiS_ClearBuffer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO,USHORT ModeNo);
+void     SiS_SetCRT1Group(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                          USHORT ModeNo,USHORT ModeIdIndex,USHORT BaseAddr);
+void     SiS_DetectMonitor(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
+void     SiS_GetSenseStatus(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,UCHAR *ROMAddr);
+USHORT   SiS_TestMonitorType(SiS_Private *SiS_Pr, UCHAR R_DAC,UCHAR G_DAC,UCHAR B_DAC);
+USHORT   SiS_SenseCHTV(SiS_Private *SiS_Pr);
+BOOLEAN  SiS_Sense(SiS_Private *SiS_Pr, USHORT tempbx,USHORT tempcx);
+BOOLEAN  SiS_GetPanelID(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO);
+BOOLEAN  SiS_GetLCDDDCInfo(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO);
+USHORT   SiS_SenseLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO);
+void     SiSRegInit(SiS_Private *SiS_Pr, USHORT BaseAddr);
+void     SiSInitPtr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo);
+void     SiSInitPCIetc(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiSDetermineROMUsage(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, UCHAR *ROMAddr);
 
 #ifdef LINUX_XF86
 USHORT  	SiS_CalcModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode);
-void    	SiS_SetPitch(ScrnInfoPtr pScrn, UShort BaseAddr);
-void    	SiS_SetPitchCRT1(ScrnInfoPtr pScrn, UShort BaseAddr);
-void    	SiS_SetPitchCRT2(ScrnInfoPtr pScrn, UShort BaseAddr);
+USHORT  	SiS_CheckCalcModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode, int VBFlags);
+void    	SiS_SetPitch(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr);
+void    	SiS_SetPitchCRT1(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr);
+void    	SiS_SetPitchCRT2(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr);
 unsigned char 	SiS_GetSetModeID(ScrnInfoPtr pScrn, unsigned char id);
+unsigned char 	SiS_GetSetMMIOReg(ScrnInfoPtr pScrn, USHORT offset, unsigned char value);
 #endif
 
-extern BOOLEAN   SiS_SetCRT2Group301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+extern USHORT    SiS_GetOffset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                       USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+extern USHORT    SiS_GetColorDepth(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+extern void      SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+extern BOOLEAN   SiS_SetCRT2Group301(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
                                      PSIS_HW_DEVICE_INFO HwDeviceExtension);
-extern void      SiS_PresetScratchregister(USHORT SiS_P3d4,
+extern void      SiS_PresetScratchregister(SiS_Private *SiS_Pr, USHORT SiS_P3d4,
                                            PSIS_HW_DEVICE_INFO HwDeviceExtension);
-extern void      SiS_UnLockCRT2(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
-extern void      SiS_LockCRT2(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
-extern BOOLEAN   SiS_BridgeIsOn(USHORT BaseAddr);
-extern BOOLEAN   SiS_BridgeIsEnable(USHORT BaseAddr,PSIS_HW_DEVICE_INFO );
-extern void      SiS_SetTVSystem301(VOID);
-extern BOOLEAN   SiS_GetLCDDDCInfo301(PSIS_HW_DEVICE_INFO HwDeviceExtension);
-extern BOOLEAN   SiS_GetSenseStatus301(PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                                       USHORT BaseAddr,ULONG ROMAddr);
-extern USHORT    SiS_GetVCLKLen(ULONG ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-extern BOOLEAN   SiS_SetCRT2Group302(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
-                                     PSIS_HW_DEVICE_INFO HwDeviceExtension);
-extern void      SiS_GetVBInfo301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
-                                  USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-extern BOOLEAN   SiS_GetLCDResInfo301(ULONG ROMAddr,USHORT P3d4,USHORT ModeNo,
-                                      USHORT ModeIdIndex);
-/* extern USHORT  SiS_VBInfo,LCDResInfo,LCDTypeInfo,LCDInfo; */  /* TW: redundant */
-extern USHORT    SiS_GetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo,USHORT ModeIdIndex);
-extern void      SiS_LongWait(VOID);
+extern void      SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
+extern void      SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
+extern BOOLEAN   SiS_BridgeIsOn(SiS_Private *SiS_Pr, USHORT BaseAddr);
+extern BOOLEAN   SiS_BridgeIsEnable(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO );
+extern void      SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+                               USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+extern BOOLEAN   SiS_GetLCDResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
+                                   USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+extern void      SiS_SetHiVision(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+extern USHORT    SiS_GetRatePtrCRT2(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex,
+                                    PSIS_HW_DEVICE_INFO HwDeviceExtension);
+extern void      SiS_LongWait(SiS_Private *SiS_Pr);
+extern void      SiS_SetRegOR(USHORT Port,USHORT Index,USHORT DataOR);
+extern void      SiS_SetRegAND(USHORT Port,USHORT Index,USHORT DataAND);
 extern void      SiS_SetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR);
-extern USHORT    SiS_GetResInfo(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-extern void      SiS_SetCH7005(USHORT tempax);
-extern USHORT    SiS_GetCH7005(USHORT tempax);
-extern BOOLEAN   SiS_GetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                                    USHORT RefreshRateTableIndex,
-		                    USHORT *ResInfo,USHORT *DisplayType);
-extern BOOLEAN   SiS_GetLCDACRT1Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+extern USHORT    SiS_GetResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+extern void      SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempax);
+extern USHORT    SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempax);
+extern void      SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempax);
+extern USHORT    SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempax);
+extern void      SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempax);
+extern USHORT    SiS_GetCH70xx(SiS_Private *SiS_Pr, USHORT tempax);
+extern BOOLEAN   SiS_GetLVDSCRT1Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                                     USHORT RefreshRateTableIndex,
 		                    USHORT *ResInfo,USHORT *DisplayType);
-extern USHORT    SiS_GetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+extern USHORT    SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                                  USHORT RefreshRateTableIndex,
 				 PSIS_HW_DEVICE_INFO HwDeviceExtension);
-extern BOOLEAN   SiS_Is301B(USHORT BaseAddr);/*301b*/
+extern BOOLEAN   SiS_Is301B(SiS_Private *SiS_Pr, USHORT BaseAddr);
+extern BOOLEAN   SiS_IsM650(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+extern BOOLEAN   SiS_LowModeStuff(SiS_Private *SiS_Pr, USHORT ModeNo,PSIS_HW_DEVICE_INFO HwDeviceExtension);
 
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/init301.c linux-2.4.20/drivers/video/sis/init301.c
--- linux-2.4.19/drivers/video/sis/init301.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/init301.c	2002-10-29 11:18:32.000000000 +0000
@@ -1,95 +1,165 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init301.c,v 1.3 2000/12/02 01:16:16 dawes Exp $ */
-
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init301.c,v 1.3 2002/22/04 01:16:16 dawes Exp $ */
 /*
  * Mode switching code (CRT2 section) for SiS 300/540/630/730/315/550/650/740
  * (Universal module for Linux kernel framebuffer, XFree86 4.x)
  *
- * Comments and changes marked with "TW" by Thomas Winischhofer <thomer@winischhofer.net>
+ * Assembler-To-C translation
+ * Parts Copyright 2002 by Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ * Based on BIOS
+ *     1.10.07, 1.10a for SiS650/LVDS+CH7019
+ *     1.07.1b, 1.10.6s for SiS650/301(B/LV), 650/301LVx
+ *     2.04.50 (I) and 2.04.5c (II) for SiS630/301(B)
+ *     2.02.3b, 2.03.02, 2.04.2c, 2.04.5c, 2.07a and 2.08.b3 for 630/LVDS/LVDS+CH7005
+ *     1.09b for 315/301(B)
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holder not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  The copyright holder makes no representations
+ * about the suitability of this software for any purpose.  It is provided
+ * "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  *
  */
 
-/* DEBUG: GetVCLK2Ptr (Mitac bug) - reverted */
+#include "init301.h"
 
-/*
-#ifdef WINCE_HEADER
-#include "precomp.h"
+#if 0
+#define TWNEWPANEL
+#endif
+
+#if 1   /* TW: Emulate 650/301LVx BIOS 1.10.6s (should be set) */
+#define SIS650301NEW
 #endif
-*/
-/*#include "precomp.h"*/
 
-#include "init301.h"
 #ifdef SIS300
 #include "oem300.h"
 #endif
+
 #ifdef SIS315H
 #include "oem310.h"
 #endif
 
+#define SiS_I2CDELAY      1000
+#define SiS_I2CDELAYSHORT  333
+
 BOOLEAN
-SiS_SetCRT2Group301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+SiS_SetCRT2Group301(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
                     PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
    USHORT ModeIdIndex;
    USHORT RefreshRateTableIndex;
 
-   SiS_SetFlag=SiS_SetFlag|ProgrammingCRT2;
-   SiS_SearchModeID(ROMAddr,ModeNo,&ModeIdIndex);
-   SiS_SelectCRT2Rate=4;
-   RefreshRateTableIndex = SiS_GetRatePtrCRT2(ROMAddr,ModeNo,ModeIdIndex);
-   SiS_SaveCRT2Info(ModeNo);
-   SiS_DisableBridge(HwDeviceExtension,BaseAddr);
-   SiS_UnLockCRT2(HwDeviceExtension, BaseAddr);
-   SiS_SetCRT2ModeRegs(BaseAddr,ModeNo,HwDeviceExtension);
-   if(SiS_VBInfo&DisableCRT2Display) {
-     SiS_LockCRT2(HwDeviceExtension, BaseAddr);
-     SiS_DisplayOn();
-     return(FALSE);
+   SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+
+   SiS_SearchModeID(SiS_Pr,ROMAddr,&ModeNo,&ModeIdIndex);
+
+   /* TW: Used for shifting CR33 */
+   SiS_Pr->SiS_SelectCRT2Rate = 4;
+
+   SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
+
+   RefreshRateTableIndex = SiS_GetRatePtrCRT2(SiS_Pr, ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+
+   SiS_SaveCRT2Info(SiS_Pr,ModeNo);
+
+   if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+      SiS_DisableBridge(SiS_Pr,HwDeviceExtension,BaseAddr);
+      SiS_SetCRT2ModeRegs(SiS_Pr,BaseAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+   }
+
+   if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) {
+      SiS_LockCRT2(SiS_Pr,HwDeviceExtension, BaseAddr);
+      SiS_DisplayOn(SiS_Pr);
+      return(FALSE);
    }
-   /* SetDefCRT2ExtRegs(BaseAddr);   */
-   SiS_GetCRT2Data(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
-   /*301b*/
-   if( ((SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS301LV))
-           && (SiS_VBInfo&SetCRT2ToLCDA)) ){
-	SiS_GetLVDSDesData(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
+
+   SiS_GetCRT2Data(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                   HwDeviceExtension);
+
+   /* LVDS, 650/301LV(LCDA) and 630/301B BIOS set up Panel Link */
+   if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+   	SiS_GetLVDSDesData(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+	                   HwDeviceExtension);
+   } else {
+        SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_LCDVDES = 0;
    }
-   /*end 301b*/
-   if(SiS_IF_DEF_LVDS==1) {
-   	SiS_GetLVDSDesData(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
+
+   if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+      SiS_SetGroup1(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+                    HwDeviceExtension,RefreshRateTableIndex);
    }
 
-   SiS_SetGroup1(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
-                 HwDeviceExtension,RefreshRateTableIndex);
+   if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+
+        if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+
+	   SiS_SetGroup2(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+	                 RefreshRateTableIndex,HwDeviceExtension);
+      	   SiS_SetGroup3(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+	                 HwDeviceExtension);
+      	   SiS_SetGroup4(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+	                 RefreshRateTableIndex,HwDeviceExtension);
+      	   SiS_SetGroup5(SiS_Pr,HwDeviceExtension, BaseAddr,ROMAddr,
+	                 ModeNo,ModeIdIndex);
+
+	   /* TW: 630/301B BIOS does all this: */
+	   if(HwDeviceExtension->jChipType < SIS_315H) {
+	      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	         if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+		    if(!((SiS_Pr->SiS_SetFlag & CRT2IsVGA) && ((ModeNo == 0x03) || (ModeNo = 0x10)))) {
+		       if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+		           SiS_ModCRT1CRTC(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+		                           RefreshRateTableIndex,HwDeviceExtension);
+		       }
+                    }
+		 }
+		 SiS_SetCRT2ECLK(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+		                 RefreshRateTableIndex,HwDeviceExtension);
+              }
+	   }
+
+        }
 
-   /*301b*/
-   if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS301LV))
-   		&& (SiS_VBInfo&SetCRT2ToLCDA)
-		&& (SiS_IF_DEF_LVDS == 0) ) {
-     	if( (SiS_VBType&(VB_SIS301LV|VB_SIS302LV)) && (SiS_VBInfo&SetCRT2ToLCDA) ){
-             	SiS_SetReg1(SiS_Part4Port,0x24,0x0e);
-    	}
-   /* end 301b */
-   } else if((SiS_IF_DEF_LVDS==0) && (!(SiS_VBInfo&SetCRT2ToLCDA))) {
-      	SiS_SetGroup2(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
-	              RefreshRateTableIndex,HwDeviceExtension);
-      	SiS_SetGroup3(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
-	              HwDeviceExtension);
-      	SiS_SetGroup4(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
-	              RefreshRateTableIndex,HwDeviceExtension);
-      	SiS_SetGroup5(BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
    } else {
-     	if(SiS_IF_DEF_CH7005==1) {
-	    if(SiS_VBInfo&SetCRT2ToTV)
+
+        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+	        if (SiS_Pr->SiS_IF_DEF_TRUMPION == 0) {
+    	 	        SiS_ModCRT1CRTC(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+		                        RefreshRateTableIndex,HwDeviceExtension);
+	        }
+	}
+        if(SiS_Pr->SiS_IF_DEF_FSTN == 0) {
+     	 	SiS_SetCRT2ECLK(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+		          RefreshRateTableIndex,HwDeviceExtension);
+	}
+	if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+     	  if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+	     /* TW: Inserted from 650/LVDS BIOS */
+	     if (SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+	        if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+		    SiS_SetCH701xForLCD(SiS_Pr,HwDeviceExtension,BaseAddr);
+		}
+	     }
+	     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
 	        /* TW: Set Chrontel registers only if CRT2 is TV */
-       		SiS_SetCHTVReg(ROMAddr,ModeNo,ModeIdIndex,
+       		SiS_SetCHTVReg(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
 		               RefreshRateTableIndex);
-     	}
-     	if(!(SiS_LCDResInfo==Panel640x480)){
-    	 	SiS_ModCRT1CRTC(ROMAddr,ModeNo,ModeIdIndex,
-		                RefreshRateTableIndex);
-         	if(!SiS_IF_DEF_FSTN)  /*fstn*/
-     	     		SiS_SetCRT2ECLK(ROMAddr,ModeNo,ModeIdIndex,
-			          RefreshRateTableIndex,HwDeviceExtension);
-     	}
+	     }
+     	  }
+	}
+
    }
 
 #ifdef SIS300
@@ -97,1241 +167,1901 @@
         (HwDeviceExtension->jChipType==SIS_630)||
         (HwDeviceExtension->jChipType==SIS_730)||
         (HwDeviceExtension->jChipType==SIS_300) )
-     	SiS_OEM300Setting(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
+    {
+	if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+       	   SiS_OEM300Setting(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
+	}
+    }
 #endif
 
 #ifdef SIS315H
-   if ( (HwDeviceExtension->jChipType==SIS_315H)||   /* 05/02/01 ynlai for sis550 */
+   if ( (HwDeviceExtension->jChipType==SIS_315H)||
         (HwDeviceExtension->jChipType==SIS_315PRO)||
-        (HwDeviceExtension->jChipType==SIS_550) ||   /* 05/02/01 ynlai for 550 */
-        (HwDeviceExtension->jChipType==SIS_640) ||   /* 08/20/01 chiawen for 640/740 */
-        (HwDeviceExtension->jChipType==SIS_740) ||   /* 09/03/01 chiawen for 640/740 */
-        (HwDeviceExtension->jChipType==SIS_650))     /* 09/03/01 chiawen for 650 */
+        (HwDeviceExtension->jChipType==SIS_550) ||
+        (HwDeviceExtension->jChipType==SIS_640) ||
+        (HwDeviceExtension->jChipType==SIS_740) ||
+        (HwDeviceExtension->jChipType==SIS_650))
    {
-        SiS_OEM310Setting(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
-        SiS_CRT2AutoThreshold(BaseAddr);
+        if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+#ifdef SIS650301NEW
+	   SiS_FinalizeLCD(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex, HwDeviceExtension);
+#else
+	   SiS_OEMLCD(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+#endif
+           SiS_OEM310Setting(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+           SiS_CRT2AutoThreshold(SiS_Pr,BaseAddr);
+        }
    }
 #endif
 
-   SiS_EnableBridge(HwDeviceExtension,BaseAddr);
-   if(SiS_IF_DEF_CH7005==1) {
-	if(SiS_VBInfo&SetCRT2ToTV) {
+   if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+      SiS_EnableBridge(SiS_Pr,HwDeviceExtension,BaseAddr);
+      SiS_DisplayOn(SiS_Pr);
+   }
+
+   if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+	if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
 	     /* TW: Disable LCD panel when using TV */
-	     SiS_SetRegANDOR(SiS_P3c4,0x11,0xFF,0x0C);
+	     SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x11,0x0C);
 	} else {
 	     /* TW: Disable TV when using LCD */
-	     SiS_SetCHTVRegANDOR(0x010E,0xF8);
+	     SiS_SetCH70xxANDOR(SiS_Pr,0x010E,0xF8);
 	}
    }
-   SiS_DisplayOn();
-   SiS_LockCRT2(HwDeviceExtension, BaseAddr);
+
+   SiS_DisplayOn(SiS_Pr);
+
+   if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+      SiS_LockCRT2(SiS_Pr,HwDeviceExtension, BaseAddr);
+   }
+
    return 1;
 }
 
-void
-SiS_SetGroup1(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-              PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex)
+/* TW: Checked with 650/LVDS (1.10.07) and 630+301B/LVDS BIOS */
+BOOLEAN
+SiS_LowModeStuff(SiS_Private *SiS_Pr, USHORT ModeNo,
+                 PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+    USHORT temp,temp1,temp2;
+
+    if((ModeNo != 0x03) && (ModeNo != 0x10) && (ModeNo != 0x12))
+         return(1);
+    temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x11);
+    SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x11,0x80);
+    temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x00);
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,0x00,0x55);
+    temp2 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x00);
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,0x00,temp1);
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,0x11,temp);
+    if(HwDeviceExtension->jChipType >= SIS_315H) {
+       if(temp2 == 0x55) return(0);
+       else return(1);
+    } else {
+       if(temp2 != 0x55) return(1);
+       else {
+          SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
+          return(0);
+       }
+    }
+}
+
+/* TW: Set Part1 registers */
+/* TW: Checked with 650/LVDS (1.10.07), 650/301LV (II) and 630/301B (II) BIOS */
+/* TW: Pass 2: Checked with 650/301LVx 1.10.6s, 630/301B 2.04.5a */
+void
+SiS_SetGroup1(SiS_Private *SiS_Pr,USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+              USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+	      USHORT RefreshRateTableIndex)
 {
-  USHORT  temp=0,tempax=0,tempbx=0,tempcx=0;
-  USHORT  pushbx=0,CRT1Index=0;
-  USHORT  modeflag,resinfo=0;
+  USHORT  temp=0, tempax=0, tempbx=0, tempcx=0, tempbl=0;
+  USHORT  pushbx=0, CRT1Index=0;
+#ifdef SIS315H
+  USHORT  pushcx=0;
+#endif
+  USHORT  modeflag, resinfo=0;
 
   if(ModeNo<=0x13) {
-  	/* TW: Do nothing for std modes */
+	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
   } else {
-    	CRT1Index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
-    	CRT1Index=CRT1Index&0x3F;
-    	resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+    	CRT1Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
   }
 
-  /*301b*/ 
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-         && (SiS_VBInfo&SetCRT2ToLCDA) ) {
-	   /* TW: Do nothing for these bridge types here */
+  /* TW: Removed 301B301LV.. check here; LCDA exists with LVDS as well */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+
+	   /* TW: From 650/LVDS BIOS; 301(B+LV) version does not set Sync  */
+	   if (SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+	       SiS_SetCRT2Sync(SiS_Pr,BaseAddr,ROMAddr,ModeNo,
+                               RefreshRateTableIndex,HwDeviceExtension);
+	   }
+
+	   SiS_SetGroup1_LCDA(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+     	                      HwDeviceExtension,RefreshRateTableIndex);
+
   } else {
-     SiS_SetCRT2Offset(SiS_Part1Port,ROMAddr,ModeNo,ModeIdIndex,
+
+     if( (HwDeviceExtension->jChipType >= SIS_315H) &&
+         (SiS_Pr->SiS_IF_DEF_LVDS == 1) &&
+	 (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+
+        SiS_SetCRT2Sync(SiS_Pr,BaseAddr,ROMAddr,ModeNo,
+                        RefreshRateTableIndex,HwDeviceExtension);
+
+     } else {
+
+        SiS_SetCRT2Offset(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
       		       RefreshRateTableIndex,HwDeviceExtension);
-     if (HwDeviceExtension->jChipType < SIS_315H ) /* 300 series */
-    	   SiS_SetCRT2FIFO(SiS_Part1Port,ROMAddr,ModeNo,
-	                   HwDeviceExtension);
-     else 					   /* 310 series */
-           SiS_SetCRT2FIFO2(SiS_Part1Port,ROMAddr,ModeNo,
-	                   HwDeviceExtension);
 
-     SiS_SetCRT2Sync(BaseAddr,ROMAddr,ModeNo,
-                     RefreshRateTableIndex);
-  }
+        if (HwDeviceExtension->jChipType < SIS_315H ) {
+#ifdef SIS300
+    	      SiS_SetCRT2FIFO_300(SiS_Pr,ROMAddr,ModeNo,HwDeviceExtension);
+#endif
+        } else {
+#ifdef SIS315H
+              SiS_SetCRT2FIFO_310(SiS_Pr,ROMAddr,ModeNo,HwDeviceExtension);
+#endif
+	}
 
-  if (ModeNo<=0x13)
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-  else
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+        SiS_SetCRT2Sync(SiS_Pr,BaseAddr,ROMAddr,ModeNo,
+                        RefreshRateTableIndex,HwDeviceExtension);
 
-  /*301b*/
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-   					&& (SiS_VBInfo&SetCRT2ToLCDA) ) {
-     	SiS_SetGroup1_LCDA(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
-     	                   HwDeviceExtension,RefreshRateTableIndex);
-  /*end 301b*/
-  } else if (HwDeviceExtension->jChipType < SIS_315H ) {
-    /* ------------- 300 series --------------*/
-    temp=(SiS_VGAHT-1)&0x0FF;   					/* BTVGA2HT 0x08,0x09 */
-    SiS_SetReg1(SiS_Part1Port,0x08,temp);
-    temp=(((SiS_VGAHT-1)&0xFF00)>>8)<<4;
-    SiS_SetRegANDOR(SiS_Part1Port,0x09,~0x0F0,temp); 	/* <------------------- */
-
-    temp=(SiS_VGAHDE+12)&0x0FF;                               		/* BTVGA2HDEE 0x0A,0x0C */
-    SiS_SetReg1(SiS_Part1Port,0x0A,temp); 		/* <------------------- */
-        
-    pushbx=SiS_VGAHDE+12;                                     		/* bx  BTVGA@HRS 0x0B,0x0C */
-    tempcx=(SiS_VGAHT-SiS_VGAHDE)>>2;                           	/* cx */
-    tempbx=pushbx+tempcx;
-    tempcx=tempcx<<1;
-    tempcx=tempcx+tempbx;
-    
-    if(SiS_IF_DEF_LVDS==0) {
-      if(SiS_VBInfo&SetCRT2ToRAMDAC){
-        tempbx = SiS_CRT1Table[CRT1Index].CR[4];
-        tempbx = tempbx|((SiS_CRT1Table[CRT1Index].CR[14]&0xC0)<<2);
-        tempbx = (tempbx-1)<<3;
-        tempcx = SiS_CRT1Table[CRT1Index].CR[5];
-        tempcx = tempcx&0x1F;
-        temp = SiS_CRT1Table[CRT1Index].CR[15];
-        temp = (temp&0x04)<<(6-2);
-        tempcx=((tempcx|temp)-1)<<3;
-      }
-    }
-   /*add for hardware request*/
-    if((SiS_VBInfo&SetCRT2ToTV)&&(resinfo==0x08)){
-        if(SiS_VBInfo&SetPALTV){
-      		tempbx=1040;
-      		tempcx=1042;
-      	} else {
-      		tempbx=1040;
-      		tempcx=1042;
-      	}
-    }
+	/* 1. Horizontal setup */
 
-    temp=tempbx&0x00FF;
-    SiS_SetReg1(SiS_Part1Port,0x0B,temp); 		/* <------------------- */
-    
-  } else {
-     /* ---------------------- 310 series ------------------*/
-     if (modeflag&HalfDCLK) { /* for low resolution mode */
-         temp=(SiS_VGAHT/2-1)&0x0FF;                             /* BTVGA2HT 0x08,0x09 */
-         SiS_SetReg1(SiS_Part1Port,0x08,temp);
-         temp=(((SiS_VGAHT/2-1)&0xFF00)>>8)<<4;
-         SiS_SetRegANDOR(SiS_Part1Port,0x09,~0x0F0,temp);
-         temp=(SiS_VGAHDE/2+16)&0x0FF;                           /* BTVGA2HDEE 0x0A,0x0C */
-         SiS_SetReg1(SiS_Part1Port,0x0A,temp);
-
-         pushbx=SiS_VGAHDE/2+16;
-         tempcx=((SiS_VGAHT-SiS_VGAHDE)/2)>>2;                   /* cx */
-         tempbx=pushbx+tempcx;                                   /* bx  BTVGA@HRS 0x0B,0x0C */
-         tempcx=tempcx+tempbx;
-
-         if(SiS_IF_DEF_LVDS==0) {
-             if(SiS_VBInfo&SetCRT2ToRAMDAC){
-                tempbx = SiS_CRT1Table[CRT1Index].CR[4];
-                tempbx = tempbx|((SiS_CRT1Table[CRT1Index].CR[14]&0xC0)<<2);
-                tempbx = (tempbx-3)<<3;         		/*(VGAHRS-3)*8 */
-                tempcx = SiS_CRT1Table[CRT1Index].CR[5];
-                tempcx = tempcx&0x1F;
-                temp = SiS_CRT1Table[CRT1Index].CR[15];
-                temp = (temp&0x04)<<(5-2);      		/*VGAHRE D[5]*/
-                tempcx=((tempcx|temp)-3)<<3;    		/* (VGAHRE-3)*8 */
-             }
-         }
-         tempbx += 4;
-         tempcx += 4;
-         if (tempcx>(SiS_VGAHT/2))
-              tempcx = SiS_VGAHT/2;
-         temp=tempbx&0x00FF;
-         SiS_SetReg1(SiS_Part1Port,0x0B,temp);
-    } else {
-         temp=(SiS_VGAHT-1)&0x0FF;                             	/* BTVGA2HT 0x08,0x09 */
-         SiS_SetReg1(SiS_Part1Port,0x08,temp);
-         temp=(((SiS_VGAHT-1)&0xFF00)>>8)<<4;
-         SiS_SetRegANDOR(SiS_Part1Port,0x09,~0x0F0,temp);
-         temp=(SiS_VGAHDE+16)&0x0FF;                            /* BTVGA2HDEE 0x0A,0x0C */
-         SiS_SetReg1(SiS_Part1Port,0x0A,temp);
-
-         pushbx=SiS_VGAHDE+16;
-         tempcx=(SiS_VGAHT-SiS_VGAHDE)>>2;                      /* cx */
-         tempbx=pushbx+tempcx;                                  /* bx  BTVGA@HRS 0x0B,0x0C */
-         tempcx=tempcx+tempbx;
-      
-         if(SiS_IF_DEF_LVDS==0) {
-             if(SiS_VBInfo&SetCRT2ToRAMDAC){
-                tempbx = SiS_CRT1Table[CRT1Index].CR[4];
-                tempbx = tempbx|((SiS_CRT1Table[CRT1Index].CR[14]&0xC0)<<2);
-                tempbx = (tempbx-3)<<3;         		/*(VGAHRS-3)*8 */
-                tempcx = SiS_CRT1Table[CRT1Index].CR[5];
-                tempcx = tempcx&0x1F;
-                temp = SiS_CRT1Table[CRT1Index].CR[15];
-                temp = (temp&0x04)<<(5-2);      		/*VGAHRE D[5]*/
-                tempcx=((tempcx|temp)-3)<<3;    		/* (VGAHRE-3)*8 */
-                tempbx += 16;
-                tempcx += 16;
-             }
-         }
-         if (tempcx>SiS_VGAHT)
-        	tempcx = SiS_VGAHT;
-        /*add for hardware request*/
-         if((SiS_VBInfo&SetCRT2ToTV)&&(resinfo==0x08)){
-             if(SiS_VBInfo&SetPALTV){
-      		 tempbx=1040;
-      		 tempcx=1042;
-      	     } else {
-      		 tempbx=1040;
-      		 tempcx=1042;
-      	     }
-         }
-         temp=tempbx&0x00FF;
-         SiS_SetReg1(SiS_Part1Port,0x0B,temp);
-     }
-  }
+        if (HwDeviceExtension->jChipType < SIS_315H ) {
+
+#ifdef SIS300
+                /* ------------- 300 series --------------*/
+
+    		temp = (SiS_Pr->SiS_VGAHT - 1) & 0x0FF;   			/* BTVGA2HT 0x08,0x09 */
+    		SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,temp);                   /* TW: CRT2 Horizontal Total */
+
+    		temp = (((SiS_Pr->SiS_VGAHT - 1) & 0xFF00) >> 8) << 4;
+    		SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0f,temp);          /* TW: CRT2 Horizontal Total Overflow [7:4] */
+
+    		temp = (SiS_Pr->SiS_VGAHDE + 12) & 0x0FF;                       /* BTVGA2HDEE 0x0A,0x0C */
+    		SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0A,temp);                   /* TW: CRT2 Horizontal Display Enable End */
+
+    		pushbx = SiS_Pr->SiS_VGAHDE + 12;                               /* bx  BTVGA@HRS 0x0B,0x0C */
+    		tempcx = (SiS_Pr->SiS_VGAHT - SiS_Pr->SiS_VGAHDE) >> 2;
+    		tempbx = pushbx + tempcx;
+    		tempcx <<= 1;
+    		tempcx += tempbx;
+
+    		if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+      			if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC){
+			        CRT1Index &= 0x3F;
+        			tempbx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4];
+        			tempbx |= ((SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14] & 0xC0) << 2);
+        			tempbx = (tempbx - 1) << 3;
+        			tempcx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5];
+        			tempcx &= 0x1F;
+        			temp = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15];
+        			temp = (temp & 0x04) << (6-2);
+        			tempcx = ((tempcx | temp) - 1) << 3;
+      			}
 
-  /* TW: The following is done for all bridge/chip types/series */
+    			if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (resinfo == 0x08)){
+        			if(!(SiS_Pr->SiS_VBInfo & SetPALTV)){
+      					tempbx = 1040;
+      					tempcx = 1042;
+      				}
+    			}
+	        }
 
-#if 1
-  tempax = (tempax&0x00FF)|(tempbx&0xFF00); /* TW: tempax not used above!!!*/
-  tempbx=pushbx;
-  tempbx=(tempbx&0x00FF)|((tempbx&0xFF00)<<4);
-  tempax=tempax|(tempbx&0xFF00);
-  temp=(tempax&0xFF00)>>8;
+    		temp = tempbx & 0x00FF;
+    		SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0B,temp);                   /* TW: CRT2 Horizontal Retrace Start */
 #endif
-#if 0
-  /* TW: new code: */
-  tempax=(tempbx&0xFF00)>>8;
-  tempbx=(((pushbx&0xFF00)>>8)<<4)&0xFF;
-  temp=tempax|tempbx;
-#endif
-  SiS_SetReg1(SiS_Part1Port,0x0C,temp); 		/* <------------------- */
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x0D,temp); 		/* <------------------- */
-  tempcx=SiS_VGAVT-1;
-  temp=tempcx&0x00FF;
-  if(SiS_IF_DEF_CH7005==1) {
-    	if(SiS_VBInfo&SetCRT2ToTV) {
-      		temp--;
-    	}
-  }
-  SiS_SetReg1(SiS_Part1Port,0x0E,temp); 		/* <------------------- */
-  tempbx=SiS_VGAVDE-1;
-  temp=tempbx&0x00FF;
-  /* [Do the same if CH7005==1 as above?] */
-  SiS_SetReg1(SiS_Part1Port,0x0F,temp); 		/* <------------------- */
-  temp=((tempbx&0xFF00)<<3)>>8;
-  temp=temp|((tempcx&0xFF00)>>8);
-  SiS_SetReg1(SiS_Part1Port,0x12,temp); 		/* <------------------- */
-
-  tempax=SiS_VGAVDE;
-  tempbx=SiS_VGAVDE;
-  tempcx=SiS_VGAVT;
-  tempbx=(SiS_VGAVT+SiS_VGAVDE)>>1;                     	/*  BTVGA2VRS     0x10,0x11   */
-  tempcx=((SiS_VGAVT-SiS_VGAVDE)>>4)+tempbx+1;          	/*  BTVGA2VRE     0x11        */
-  if(SiS_IF_DEF_LVDS==0) {
-    	if(SiS_VBInfo & SetCRT2ToRAMDAC){
-      		tempbx = SiS_CRT1Table[CRT1Index].CR[8];
-      		temp = SiS_CRT1Table[CRT1Index].CR[7];
-      		if(temp&0x04) tempbx=tempbx|0x0100;
-      		if(temp&0x80) tempbx=tempbx|0x0200;
-      		temp = SiS_CRT1Table[CRT1Index].CR[13];
-      		if(temp&0x08) tempbx=tempbx|0x0400;
-      		temp = SiS_CRT1Table[CRT1Index].CR[9];
-      		tempcx=(tempcx&0xFF00)|(temp&0x00FF);
-    	}
-  }
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x10,temp); 		/* <------------------- */
-  temp=((tempbx&0xFF00)>>8)<<4;
-  temp=((tempcx&0x000F)|(temp));
-  SiS_SetReg1(SiS_Part1Port,0x11,temp); 		/* <------------------- */
-  if(SiS_IF_DEF_LVDS==0) {
-    	temp=0x20;
-    	if(SiS_LCDResInfo==Panel1280x1024) temp=0x20;
-    	if(SiS_LCDResInfo==Panel1280x960) temp=0x24;
-    	if(SiS_VBInfo&SetCRT2ToTV) temp=0x08;
-    	if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-      		if(SiS_VBInfo&SetInSlaveMode) temp=0x2c;
-      		else temp=0x20;
-    	}
-  } else {
-    	temp=0x20;
-  }
 
-  if (HwDeviceExtension->jChipType < SIS_315H ) {
-    /* ---------- 300 series -------------- */
+ 	} else {
 
-    SiS_SetRegANDOR(SiS_Part1Port,0x13,~0x03C,temp); 	/* <----------------- */
-	/* TW: This register will be adapted according to LCD
-	 *     panel type later in the OEM setup functions.
-	 *     (Various panel types require a different delay
-	 *     such as Clevo 2202; however, on most panels,
-	 *     0x20 does nicely.)
-	 */
+#ifdef SIS315H
+     	   /* ---------------------- 310 series ------------------*/
 
-  } else {
-    /* ----------- 310 series ---------------*/
-    temp >>=2;    /* TW: This is typical SiS code: First calulate temp, then overwrite it... */
-    temp = 0x11;    						/*  ynlai 05/30/2001 for delay compenation  */
-    SiS_SetReg1(SiS_Part1Port,0x2D,temp);
-    /*SiS_SetRegANDOR(SiS_Part1Port,0x2D,~0x00F,temp);*/
-    SiS_SetRegAND(SiS_Part1Port,0x13,0xEF);  			/* BDirectLCD=0 for lcd ?? */
-    tempax=0;
+	        tempcx = SiS_Pr->SiS_VGAHT;				       /* BTVGA2HT 0x08,0x09 */
+		pushcx = tempcx;
+		if(modeflag & HalfDCLK)  tempcx >>= 1;
+		tempcx--;
+
+		temp = tempcx & 0xff;
+		SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,temp);                  /* TW: CRT2 Horizontal Total */
+
+		temp = ((tempcx & 0xff00) >> 8) << 4;
+		SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0F,temp);         /* TW: CRT2 Horizontal Total Overflow [7:4] */
+
+		tempcx = pushcx;					       /* BTVGA2HDEE 0x0A,0x0C */
+		tempbx = SiS_Pr->SiS_VGAHDE;
+		tempcx -= tempbx;
+		tempcx >>= 2;
+		if(modeflag & HalfDCLK) {
+		    tempbx >>= 1;
+		    tempcx >>= 1;
+		}
+		tempbx += 16;
+
+		temp = tempbx & 0xff;
+		SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0A,temp);                  /* TW: CRT2 Horizontal Display Enable End */
+
+		pushbx = tempbx;
+		tempcx >>= 1;
+		tempbx += tempcx;
+		tempcx += tempbx;
+
+		if(SiS_Pr->SiS_IF_DEF_LVDS==0) {
+             	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
+                	tempbx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4];
+                	tempbx |= ((SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14] & 0xC0) << 2);
+                	tempbx = (tempbx - 3) << 3;         		/*(VGAHRS-3)*8 */
+                	tempcx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5];
+               		tempcx &= 0x1F;
+                	temp = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15];
+                	temp = (temp & 0x04) << (5-2);      		/* VGAHRE D[5] */
+                	tempcx = ((tempcx | temp) - 3) << 3;    	/* (VGAHRE-3)*8 */
+                	tempbx += 16;
+                	tempcx += 16;
+			tempax = SiS_Pr->SiS_VGAHT;
+			if (modeflag & HalfDCLK)  tempax >>= 1;
+			tempax--;
+			if (tempcx > tempax)  tempcx = tempax;
+             	   }
+         	   if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (resinfo == 0x08)){
+             	      if(!(SiS_Pr->SiS_VBInfo & SetPALTV)){
+      		 	 tempbx = 1040;
+      		 	 tempcx = 1042;
+      	     	      }
+         	   }
+		   /* TW: Makes no sense, but is in 650/301LVx 1.10.6s */
+         	   if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (resinfo == 0x08)){
+		      if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)) {
+             	         if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+      		 	    tempbx = 1040;
+      		 	    tempcx = 1042;
+      	     	         }
+		      }
+         	   }
+                }
 
-    if (modeflag&DoubleScanMode) tempax |= 0x80;
-    if (modeflag&HalfDCLK) tempax |= 0x40;
-    SiS_SetRegANDOR(SiS_Part1Port,0x2C,~0x0C0,tempax);
-  }
+		temp = tempbx & 0xff;
+	 	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0B,temp);                 /* TW: CRT2 Horizontal Retrace Start */
 
-  if(SiS_IF_DEF_LVDS==0) {
-    	SiS_SetGroup1_301(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
-	                  HwDeviceExtension,RefreshRateTableIndex);
-  } else {
-    	SiS_SetGroup1_LVDS(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
-	                   HwDeviceExtension,RefreshRateTableIndex);
-  }
+#if 0      /* TW: Old code */
+     	   if (modeflag & HalfDCLK) {  /* for low resolution modes */
+
+         	temp = ((SiS_Pr->SiS_VGAHT / 2) - 1) & 0xFF;                    /* BTVGA2HT 0x08,0x09 */
+         	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,temp);                   /* TW: CRT2 Horizontal Total */
+
+		temp = ((((SiS_Pr->SiS_VGAHT / 2) - 1) & 0xFF00) >> 8) << 4;
+        	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0F,temp);        /* TW: CRT2 Horizontal Total Overflow [7:4] */
+
+         	temp = ((SiS_Pr->SiS_VGAHDE / 2) + 16) & 0xFF;                  /* BTVGA2HDEE 0x0A,0x0C */
+         	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0A,temp);                   /* TW: CRT2 Horizontal Display Enable End */
+
+         	pushbx = (SiS_Pr->SiS_VGAHDE / 2) + 16;
+         	tempcx = ((SiS_Pr->SiS_VGAHT - SiS_Pr->SiS_VGAHDE) / 2) >> 2;           /* cx */
+		if(SiS_Pr->SiS_IF_DEF_LVDS == 1)
+		           tempcx >>= 1;    /* TW: From LVDS 1.10.07; not done on 301(LV) */
+         	tempbx = pushbx + tempcx;                               /* bx  BTVGA@HRS 0x0B,0x0C */
+         	tempcx += tempbx;
+
+         	if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+                   if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC){
+                	tempbx = SiS_CRT1Table[CRT1Index].CR[4];
+                	tempbx |= ((SiS_CRT1Table[CRT1Index].CR[14] & 0xC0) << 2);
+                	tempbx = (tempbx - 3) << 3;         		/*(VGAHRS-3)*8 */
+                	tempcx = SiS_CRT1Table[CRT1Index].CR[5];
+               		tempcx &= 0x1F;
+                	temp = SiS_CRT1Table[CRT1Index].CR[15];
+                	temp = (temp & 0x04) << (5-2);      		/* VGAHRE D[5]  */
+                	tempcx =((tempcx | temp) - 3) << 3;    		/* (VGAHRE-3)*8 */
+             	   }
+                   /* TW: The following is not done in 650/LVDS BIOS  */
+         	   tempbx += 4;
+         	   tempcx += 4;
+
+         	   if (tempcx > (SiS_Pr->SiS_VGAHT / 2))
+              		   tempcx = SiS_Pr->SiS_VGAHT / 2;
+         	}
+
+                temp = tempbx & 0x00FF;
+         	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0B,temp);                  /* TW: CRT2 Horizontal Retrace Start */
+
+    	   } else {			/* for high resolution modes */
+
+         	temp = (SiS_Pr->SiS_VGAHT - 1) & 0xFF;                       	/* BTVGA2HT 0x08,0x09 */
+         	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,temp);                  /* TW: CRT2 Horizontal Total */
+
+         	temp = (((SiS_Pr->SiS_VGAHT - 1) & 0xFF00) >> 8 ) << 4;
+	 	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0F,temp);         /* TW: CRT2 Horizontal Total Overflow [7:4] */
+
+         	temp = (SiS_Pr->SiS_VGAHDE + 16) & 0xFF;                       /* BTVGA2HDEE 0x0A,0x0C */
+	 	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0A,temp);                  /* TW: CRT2 Horizontal Display Enable End */
+
+         	pushbx = SiS_Pr->SiS_VGAHDE + 16;
+         	tempcx = (SiS_Pr->SiS_VGAHT - SiS_Pr->SiS_VGAHDE) >> 2;                /* cx */
+
+                /* TW: Done in 650/301LVx 1.10.6s */
+		/* if(SiS_Pr->SiS_IF_DEF_LVDS == 1) */
+                    tempcx >>= 1;    /* TW: From LVDS 1.10.07; not done on 301(LV), done in 301LVx 1.10.6s */
+
+         	tempbx = pushbx + tempcx;                              /* bx  BTVGA@HRS 0x0B,0x0C */
+         	tempcx += tempbx;
+
+         	if(SiS_Pr->SiS_IF_DEF_LVDS==0) {
+             	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC){
+                	tempbx = SiS_CRT1Table[CRT1Index].CR[4];
+                	tempbx |= ((SiS_CRT1Table[CRT1Index].CR[14] & 0xC0) << 2);
+                	tempbx = (tempbx - 3) << 3;         		/*(VGAHRS-3)*8 */
+                	tempcx = SiS_CRT1Table[CRT1Index].CR[5];
+               		tempcx &= 0x1F;
+                	temp = SiS_CRT1Table[CRT1Index].CR[15];
+                	temp = (temp & 0x04) << (5-2);      		/* VGAHRE D[5] */
+                	tempcx = ((tempcx | temp) - 3) << 3;    	/* (VGAHRE-3)*8 */
+                	tempbx += 16;
+                	tempcx += 16;
+             	   }
+		   /* TW: The entire following section is not done in 650/LVDS BIOS */
+         	   if (tempcx > SiS_Pr->SiS_VGAHT)
+        		tempcx = SiS_Pr->SiS_VGAHT;
+
+         	   if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (resinfo == 0x08)){
+             	      if(!(SiS_Pr->SiS_VBInfo & SetPALTV)){
+      		 	 tempbx = 1040;
+      		 	 tempcx = 1042;
+      	     	      }
+         	   }
+                }
+
+         	temp = tempbx & 0x00FF;
+	 	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0B,temp);                 /* TW: CRT2 Horizontal Retrace Start */
+
+	   } /* halfdclk */
+#endif
+#endif  /* SIS315H */
+
+     	}  /* 310 series */
+
+  	/* TW: The following is done for all bridge/chip types/series */
+
+  	tempax = tempbx & 0xFF00;
+  	tempbx = pushbx;
+  	tempbx = (tempbx & 0x00FF) | ((tempbx & 0xFF00) << 4);
+  	tempax |= (tempbx & 0xFF00);
+  	temp = (tempax & 0xFF00) >> 8;
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0C,temp);                        /* TW: Overflow */
+
+  	temp = tempcx & 0x00FF;
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0D,temp);                        /* TW: CRT2 Horizontal Retrace End */
+
+  	/* 2. Vertical setup */
+
+  	tempcx = SiS_Pr->SiS_VGAVT - 1;
+  	temp = tempcx & 0x00FF;
+
+	/* TW: Matches 650/301LV, 650/LVDS, 630/LVDS(CLEVO), 630/LVDS(no-Ch7005) */
+        if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+	     if(HwDeviceExtension->jChipType < SIS_315H) {
+	          if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+		       if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO|SetCRT2ToAVIDEO)) {
+		           temp--;
+		       }
+                  }
+	     } else {
+	          if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+ 		      temp--;
+                  }
+             }
+        } else if(HwDeviceExtension->jChipType >= SIS_315H) {
+	    /* TW: Inserted from 650/301LVx 1.10.6s */
+	    temp--;
+	}
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0E,temp);                        /* TW: CRT2 Vertical Total */
+
+  	tempbx = SiS_Pr->SiS_VGAVDE - 1;
+  	temp = tempbx & 0x00FF;
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0F,temp);                        /* TW: CRT2 Vertical Display Enable End */
+
+  	temp = ((tempbx & 0xFF00) << 3) >> 8;
+  	temp |= ((tempcx & 0xFF00) >> 8);
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x12,temp);                        /* TW: Overflow (and HWCursor Test Mode) */
+
+	/* TW: For 650/LVDS (1.10.07), 650/301LVx (1.10.6s) */
+	if(HwDeviceExtension->jChipType >= SIS_315H) {
+           tempbx++;
+   	   tempax = tempbx;
+	   tempcx++;
+	   tempcx -= tempax;
+	   tempcx >>= 2;
+	   tempbx += tempcx;
+	   if(tempcx < 4) tempcx = 4;
+	   tempcx >>= 2;
+	   tempcx += tempbx;
+	   tempcx++;
+	} else {
+	   /* TW: For 630/LVDS/301B: */
+  	   tempbx = (SiS_Pr->SiS_VGAVT + SiS_Pr->SiS_VGAVDE) >> 1;                 /*  BTVGA2VRS     0x10,0x11   */
+  	   tempcx = ((SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) >> 4) + tempbx + 1;  /*  BTVGA2VRE     0x11        */
+	}
+
+  	if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+    	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC){
+      		tempbx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[8];
+      		temp = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7];
+      		if(temp & 0x04) tempbx |= 0x0100;
+      		if(temp & 0x80) tempbx |= 0x0200;
+      		temp = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13];
+      		if(temp & 0x08) tempbx |= 0x0400;
+      		temp = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[9];
+      		tempcx = (tempcx & 0xFF00) | (temp & 0x00FF);
+    	   }
+  	}
+  	temp = tempbx & 0x00FF;
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x10,temp);           /* TW: CRT2 Vertical Retrace Start */
+
+  	temp = ((tempbx & 0xFF00) >> 8) << 4;
+  	temp |= (tempcx & 0x000F);
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x11,temp);           /* TW: CRT2 Vert. Retrace End; Overflow; "Enable CRTC Check" */
+
+  	/* 3. Panel compensation delay */
+
+  	if (HwDeviceExtension->jChipType < SIS_315H ) {
+
+    	   /* ---------- 300 series -------------- */
+
+	   if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+	        temp = 0x20;
+#if 0           /* TW: Not in 630/301B BIOS */
+		if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) temp = 0x24;
+#endif
+		if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x08;
+#ifdef oldHV    /* TW: Not in 630/301B BIOS */
+		if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+      		    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) temp = 0x2c;
+      		    else temp = 0x20;
+    	        }
+#endif
+		if((ROMAddr) && (SiS_Pr->SiS_UseROM) && (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+		    if(ROMAddr[0x220] & 0x80) {
+		        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV-SetCRT2ToHiVisionTV))
+				temp = ROMAddr[0x221];
+			else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)
+				temp = ROMAddr[0x222];
+		        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)
+				temp = ROMAddr[0x223];
+			else
+				temp = ROMAddr[0x224];
+			temp &= 0x3c;
+		    }
+		}
+		if(HwDeviceExtension->pdc) {
+			temp = HwDeviceExtension->pdc & 0x3c;
+		}
+	   } else {
+	        temp = 0x20;
+		if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) temp = 0x04;
+		if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+		    if(ROMAddr[0x220] & 0x80) {
+		        temp = ROMAddr[0x220] & 0x3c;
+		    }
+		}
+		if(HwDeviceExtension->pdc) {
+			temp = HwDeviceExtension->pdc & 0x3c;
+		}
+	   }
+
+    	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x03C,temp);         /* TW: Panel Link Delay Compensation; (Software Command Reset; Power Saving) */
+
+  	} else {
+
+      	   /* ----------- 310/325 series ---------------*/
+
+	   if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+                temp = 0x10;
+                if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  temp = 0x2c;
+    	        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) temp = 0x20;
+    	        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960)  temp = 0x24;
+		if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)                     temp = 0x08;
+		tempbl = 0xF0;
+	   } else {
+	        temp = 0x00;
+		if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x0a;
+		tempbl = 0xF0;
+		if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempbl = 0x0F;
+	   }
+#if 0      /* TW: Not done in 650/301LVx 1.10.6s  */
+           if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+                 temp >>= 2;
+	   }
+#endif
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,tempbl,temp);	    /* TW: Panel Link Delay Compensation */
+
+    	   tempax = 0;
+    	   if (modeflag & DoubleScanMode) tempax |= 0x80;
+    	   if (modeflag & HalfDCLK)       tempax |= 0x40;
+    	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2C,0x3f,tempax);
+
+  	}
+
+     }  /* Slavemode */
+
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+
+        /* TW: 630/301B BIOS sets up Panel Link, too! (650/LV does not) */
+        if( (HwDeviceExtension->jChipType < SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
+	                       && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) ) {
+
+	    SiS_SetGroup1_LVDS(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+	                       HwDeviceExtension,RefreshRateTableIndex);
+
+        } else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {                             
+
+    	    SiS_SetGroup1_301(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+	                      HwDeviceExtension,RefreshRateTableIndex);
+        }
+
+     } else {
+
+        if(HwDeviceExtension->jChipType < SIS_315H) {
+	     SiS_SetGroup1_LVDS(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+	                        HwDeviceExtension,RefreshRateTableIndex);
+	} else {
+	    /* TW: For 650/LVDS */
+            if((!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) || (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+    	         SiS_SetGroup1_LVDS(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+	                            HwDeviceExtension,RefreshRateTableIndex);
+            }
+	}
+
+     }
+   } /* LCDA */
 }
 
+/* TW: Checked against 650/301LV and 630/301B (II) BIOS */
+/* TW: Pass 2: Checked with 650/301LVx (1.10.6s) and 630/301B (2.04.5a) */
 void
-SiS_SetGroup1_301(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+SiS_SetGroup1_301(SiS_Private *SiS_Pr, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                   PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex)
 {
   USHORT  push1,push2;
   USHORT  tempax,tempbx,tempcx,temp;
   USHORT  resinfo,modeflag;
-  USHORT  CRT1Index;
 
   if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-    	resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+    	resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
   } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-    	resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-    	CRT1Index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
-    	CRT1Index = CRT1Index &0x3F;
-  }
-
-  if(!(SiS_VBInfo&SetInSlaveMode))  return;
-
-  tempax=0xFFFF;
-  if(!(SiS_VBInfo&SetCRT2ToTV)) {
-    	tempax=SiS_GetVGAHT2();
-  }
-  if(modeflag&Charx8Dot) tempcx=0x08;
-  else tempcx=0x09;
-  if(tempax>=SiS_VGAHT) {
-    	tempax=SiS_VGAHT;
-  }
-  if(modeflag&HalfDCLK) {
-    	tempax=tempax>>1;
-  }
-  tempax=(tempax/tempcx)-5;
-  tempbx=tempax;
-  temp=0xFF;                                            	/* set MAX HT */
-  SiS_SetReg1(SiS_Part1Port,0x03,temp);
-
-  tempax=SiS_VGAHDE;                                           	/* 0x04 Horizontal Display End */
-  if(modeflag&HalfDCLK) tempax=tempax>>1;
-  tempax=(tempax/tempcx)-1;
-  tempbx=tempbx|((tempax&0x00FF)<<8);
-  temp=tempax&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x04,temp);
-
-  temp=(tempbx&0xFF00)>>8;
-  if(SiS_VBInfo&SetCRT2ToTV){
-    	temp=temp+2;
-    	if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-      		if(resinfo==7) temp=temp-2;
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+
+  /* TW: The following is only done if bridge is in slave mode: */
+
+  tempax = 0xFFFF;
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV))  tempax = SiS_GetVGAHT2(SiS_Pr);
+
+  /* TW: 630/301B does not check this flag, assumes it is set */
+  /*     650/LV and 650/301LVx BIOS do not check this either; so we set it... */
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+  	modeflag |= Charx8Dot;
+  }
+
+  if(modeflag & Charx8Dot) tempcx = 0x08;
+  else tempcx = 0x09;
+
+  if(tempax >= SiS_Pr->SiS_VGAHT) tempax = SiS_Pr->SiS_VGAHT;
+
+  if(modeflag & HalfDCLK) tempax >>= 1;
+
+  tempax = (tempax / tempcx) - 5;
+  tempbx = tempax & 0xFF;
+
+  temp = 0xFF;                                                  /* set MAX HT */
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x03,temp);
+
+  tempax = SiS_Pr->SiS_VGAHDE;                                 	/* 0x04 Horizontal Display End */
+  if(modeflag & HalfDCLK) tempax >>= 1;
+  tempax = (tempax / tempcx) - 1;
+  tempbx |= ((tempax & 0x00FF) << 8);
+  temp = tempax & 0xFF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x04,temp);
+
+  temp = (tempbx & 0xFF00) >> 8;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV){
+        if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {        
+    	    temp += 2;
+        }
+#ifdef oldHV
+    	if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+            if(resinfo == 7) temp -= 2;
     	}
+#endif
   }
-  SiS_SetReg1(SiS_Part1Port,0x05,temp);                         /* 0x05 Horizontal Display Start */
-  SiS_SetReg1(SiS_Part1Port,0x06,0x03);                       	/* 0x06 Horizontal Blank end     */
-                                                           	/* 0x07 horizontal Retrace Start */
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-    temp=(tempbx&0x00FF)-1;
-    if(!(modeflag&HalfDCLK)) {
-      temp=temp-6;
-      if(SiS_SetFlag&TVSimuMode) {
-        temp=temp-4;
-        if(ModeNo>0x13) temp=temp-10;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x05,temp);                 /* 0x05 Horizontal Display Start */
+
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x06,0x03);                 /* 0x06 Horizontal Blank end     */
+
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+    temp = (tempbx & 0x00FF) - 1;
+    if(!(modeflag & HalfDCLK)) {
+      temp -= 6;
+      if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+        temp -= 2;
+        if(ModeNo > 0x13) temp -= 10;
       }
     }
   } else {
-    tempcx=tempbx&0x00FF;
-    tempbx=(tempbx&0xFF00)>>8;
-    tempcx=(tempcx+tempbx)>>1;
-    temp=(tempcx&0x00FF)+2;
-    if(SiS_VBInfo&SetCRT2ToTV){
-       temp=temp-1;
-       if(!(modeflag&HalfDCLK)){
-          if((modeflag&Charx8Dot)){
-            temp=temp+4;
-            if(SiS_VGAHDE>=800){
-              temp=temp-6;
-            }
+#endif
+    tempcx = tempbx & 0x00FF;
+    tempbx = (tempbx & 0xFF00) >> 8;
+    tempcx = (tempcx + tempbx) >> 1;
+    temp = (tempcx & 0x00FF) + 2;
+    if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV){
+       temp--;
+       if(!(modeflag & HalfDCLK)){
+          if((modeflag & Charx8Dot)){
+             temp += 4;
+             if(SiS_Pr->SiS_VGAHDE >= 800) temp -= 6;
+	     /* TW: Inserted from 650/301 BIOS, 630/301B/301 don't do this */
+             if(HwDeviceExtension->jChipType >= SIS_315H) {
+	         if(SiS_Pr->SiS_VGAHDE == 800) temp += 2;
+             }
           }
-        }
+       }
     } else {
-       if(!(modeflag&HalfDCLK)){
-         temp=temp-4;
-         if(SiS_LCDResInfo!=Panel1280x960) {
-           if(SiS_VGAHDE>=800){
-             temp=temp-7;
-             if(SiS_ModeType==ModeEGA){
-               if(SiS_VGAVDE==1024){
-                 temp=temp+15;
-                 if(SiS_LCDResInfo!=Panel1280x1024){
-                    temp=temp+7;
+       if(!(modeflag & HalfDCLK)) {
+         temp -= 4;
+         if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x960) {
+           if(SiS_Pr->SiS_VGAHDE >= 800){
+             temp -= 7;
+	     if(HwDeviceExtension->jChipType < SIS_315H) {
+	       /* 650/301LV(x) does not do this, 630/301B does */
+               if(SiS_Pr->SiS_ModeType == ModeEGA){
+                 if(SiS_Pr->SiS_VGAVDE == 1024){
+                   temp += 15;
+                   if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024) temp += 7;
                  }
                }
-             }
-             if(SiS_VGAHDE>=1280){
-               if(SiS_LCDResInfo!=Panel1280x960) {
-                 if(SiS_LCDInfo&LCDNonExpanding) {
-                   temp=temp+28;
-                 }
+	     }
+             if(SiS_Pr->SiS_VGAHDE >= 1280){
+               if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x960) {
+                 if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) temp += 28;
                }
              }
            }
          }
        }
     }
+#ifdef oldHV
   }
- 
-  SiS_SetReg1(SiS_Part1Port,0x07,temp);                       	/* 0x07 Horizontal Retrace Start */
-  SiS_SetReg1(SiS_Part1Port,0x08,0);                            /* 0x08 Horizontal Retrace End   */
-  
-  if(SiS_VBInfo&SetCRT2ToTV) {
-        if(SiS_SetFlag&TVSimuMode) {
-            if((ModeNo==0x06)||(ModeNo==0x10)||(ModeNo==0x11)||(ModeNo==0x13)||(ModeNo==0x0F)){
-             	SiS_SetReg1(SiS_Part1Port,0x07,0x5b);
-             	SiS_SetReg1(SiS_Part1Port,0x08,0x03);
-            }
-            if((ModeNo==0x00)||(ModeNo==0x01)) {
-             	if(SiS_VBInfo&SetNTSCTV) {
-             		SiS_SetReg1(SiS_Part1Port,0x07,0x2A);
-             		SiS_SetReg1(SiS_Part1Port,0x08,0x61);
-              	} else {
-             		SiS_SetReg1(SiS_Part1Port,0x07,0x2A);
-             		SiS_SetReg1(SiS_Part1Port,0x08,0x41);
-             		SiS_SetReg1(SiS_Part1Port,0x0C,0xF0);
-            	}
-           }
-           if((ModeNo==0x02)||(ModeNo==0x03)||(ModeNo==0x07)){
-            	if(SiS_VBInfo&SetNTSCTV) {
-           		SiS_SetReg1(SiS_Part1Port,0x07,0x54);
-           		SiS_SetReg1(SiS_Part1Port,0x08,0x00);
-            	} else {
-           		SiS_SetReg1(SiS_Part1Port,0x07,0x55);
-           		SiS_SetReg1(SiS_Part1Port,0x08,0x00);
-           		SiS_SetReg1(SiS_Part1Port,0x0C,0xF0);
-           	}
-           }
-           if((ModeNo==0x04)||(ModeNo==0x05)||(ModeNo==0x0D)||(ModeNo==0x50)){
-            	if(SiS_VBInfo&SetNTSCTV) {
-            		SiS_SetReg1(SiS_Part1Port,0x07,0x30);
-            		SiS_SetReg1(SiS_Part1Port,0x08,0x03);
-            	} else {
-           		SiS_SetReg1(SiS_Part1Port,0x07,0x2f);
-           		SiS_SetReg1(SiS_Part1Port,0x08,0x02);
-                }
-           }
-       } 
+#endif
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,temp);               	/* 0x07 Horizontal Retrace Start */
+
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x00);                 /* 0x08 Horizontal Retrace End   */
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+     if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+            if(ModeNo <= 1) {
+	        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x2a);
+		if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x61);
+		} else {
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x41);
+		}
+	    } else if(SiS_Pr->SiS_ModeType == ModeText) {
+	        if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x54);
+		} else {
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x55);
+		}
+		SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x00);
+	    } else if(ModeNo <= 0x13) {
+	        if(modeflag & HalfDCLK) {
+		    if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+		        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x30);
+			SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x03);
+		    } else {
+		        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x2f);
+			SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x02);
+		    }
+		} else {
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x5b);
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x03);
+		}
+	    } else if( ((HwDeviceExtension->jChipType >= SIS_315H) && (ModeNo == 0x50)) ||
+	               ((HwDeviceExtension->jChipType < SIS_315H) && (resinfo == 0 || resinfo == 1)) ) {
+	        if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x30);
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x03);
+		} else {
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x2f);
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x03);
+		}
+	    }
+
+     }
   }
-  
-  SiS_SetReg1(SiS_Part1Port,0x18,0x03);                         	/* 0x18 SR08    */
-  SiS_SetRegANDOR(SiS_Part1Port,0x19,0xF0,0x00);
-  SiS_SetReg1(SiS_Part1Port,0x09,0xFF);                         	/* 0x09 Set Max VT    */
-
-  tempbx=SiS_VGAVT;
-  push1=tempbx;
-  tempcx=0x121;
-  tempbx=SiS_VGAVDE;                                        		/* 0x0E Virtical Display End */
-  if(tempbx==357) tempbx=350;
-  if(tempbx==360) tempbx=350;
-  if(tempbx==375) tempbx=350;
-  if(tempbx==405) tempbx=400;
-  if(tempbx==420) tempbx=400;
-  if(tempbx==525) tempbx=480;
-  push2=tempbx;
-  if(SiS_VBInfo&SetCRT2ToLCD) {
-    	if(SiS_LCDResInfo==Panel1024x768) {
-      		if(!(SiS_SetFlag&LCDVESATiming)) {
-        		if(tempbx==350) tempbx=tempbx+5;
-        		if(tempbx==480) tempbx=tempbx+5;
+
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,0x03);                	/* 0x18 SR08    */
+
+  SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x19,0xF0);
+
+  tempbx = SiS_Pr->SiS_VGAVT;
+  push1 = tempbx;
+
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x09,0xFF);                	/* 0x09 Set Max VT    */
+
+  tempcx = 0x121;
+  tempbx = SiS_Pr->SiS_VGAVDE;                               	/* 0x0E Vertical Display End */
+  if(tempbx == 357) tempbx = 350;
+  if(tempbx == 360) tempbx = 350;
+  if(tempbx == 375) tempbx = 350;
+  if(tempbx == 405) tempbx = 400;
+  if(tempbx == 420) tempbx = 400;
+  if(tempbx == 525) tempbx = 480;
+  push2 = tempbx;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+    	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+      		if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+        		if(tempbx == 350) tempbx += 5;
+        		if(tempbx == 480) tempbx += 5;
       		}
     	}
   }
   tempbx--;
-  temp=tempbx&0x00FF;
+  temp = tempbx & 0x00FF;
   tempbx--;
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x10,temp);                    		/* 0x10 vertical Blank Start */
-  tempbx=push2;
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x10,temp);        		/* 0x10 vertical Blank Start */
+
+  tempbx = push2;
   tempbx--;
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x0E,temp);
-  if(tempbx&0x0100){
-    	tempcx=tempcx|0x0002;
+  temp = tempbx & 0x00FF;
+#if 0
+  /* TW: Missing code from 630/301B 2.04.5a and 650/301LVx 1.10.6s (calles int 2f) */
+  if(xxx()) {
+      if(temp == 0xdf) temp = 0xda;
   }
-  tempax=0x000B;
-  if(modeflag&DoubleScanMode){
-    	tempax=tempax|0x08000;
+#endif
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0E,temp);
+
+  if(tempbx & 0x0100) {
+  	tempcx |= 0x0002;
+	if(SiS_Pr->SiS_VBType & VB_SIS301) tempcx |= 0x000a;
   }
-  if(tempbx&0x0200){
-    	tempcx=tempcx|0x0040;
+
+  tempax = 0x000B;
+  if(modeflag & DoubleScanMode) tempax |= 0x8000;
+
+  if(tempbx & 0x0200) {
+  	tempcx |= 0x0040;
+	if(SiS_Pr->SiS_VBType & VB_SIS301) tempax |= 0x2000;
   }
 
-  temp=(tempax&0xFF00)>>8;
-  SiS_SetReg1(SiS_Part1Port,0x0B,temp);
-  if(tempbx&0x0400){
-    	tempcx=tempcx|0x0600;
+  if(SiS_Pr->SiS_VBType & VB_SIS301) {
+        if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+	      if(SiS_Pr->SiS_VGAVDE == 480) {
+	             tempax = (tempax & 0x00ff) | 0x2000;
+		     if(modeflag & DoubleScanMode)  tempax |= 0x8000;
+	      }
+	}
   }
-  SiS_SetReg1(SiS_Part1Port,0x11,0x00);                         	/* 0x11 Vertival Blank End */
 
-  tempax=push1;
-  tempax=tempax-tempbx;                              			/* 0x0C Vertical Retrace Start */
-  tempax=tempax>>2;
-  push1=tempax;
+  temp = (tempax & 0xFF00) >> 8;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0B,temp);
 
-  if(resinfo!=0x09) {
-    	tempax=tempax<<1;
-    	tempbx=tempax+tempbx;
-  }
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-    	tempbx=tempbx-10;
-  } else {
-    	if(SiS_SetFlag&TVSimuMode) {
-      		if(SiS_VBInfo&SetPALTV) {
-        		tempbx=tempbx+40;
-      		}
+  if(tempbx & 0x0400) tempcx |= 0x0600;
+
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x11,0x00);                	/* 0x11 Vertical Blank End */
+
+  tempax = push1;
+  tempax -= tempbx;
+  tempax >>= 2;
+  push1 = tempax;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+        /* TW: Inserted from 650/301LVx 1.10.6s */
+        if(ModeNo > 0x13) {
+	    if(resinfo != 0x09) {
+	        tempax <<= 1;
+		tempbx += tempax;
+	    }
+	} else {
+	    if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1400x1050) {
+	        tempax <<= 1;
+		tempbx += tempax;
+	    }
+	}
+  } else if((resinfo != 0x09) || (SiS_Pr->SiS_VBType & VB_SIS301)) {
+    	tempax <<= 1;
+    	tempbx += tempax;
+  }
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+    	tempbx -= 10;
+  } else {
+#endif
+    	if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+      	   if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+	       if(!(SiS_Pr->SiS_HiVision & 0x03)) {
+                    tempbx += 40;
+		    if(HwDeviceExtension->jChipType >= SIS_315H) {
+		       if(SiS_Pr->SiS_VGAHDE == 800) tempbx += 10;
+		    }
+      	       }
+	   }
     	}
+#ifdef oldHV
   }
-  tempax=push1;
-  tempax=tempax>>2;
+#endif
+  tempax = push1;
+  tempax >>= 2;
   tempax++;
-  tempax=tempax+tempbx;
-  push1=tempax;
-  if((SiS_VBInfo&SetPALTV)) {
-    	if(tempbx<=513)  {
-      		if(tempax>=513) {
-        		tempbx=513;
-      		}
+  tempax += tempbx;
+  push1 = tempax;
+  if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+    	if(tempbx <= 513)  {
+      		if(tempax >= 513) tempbx = 513;
     	}
   }
-  temp=(tempbx&0x00FF);
-  SiS_SetReg1(SiS_Part1Port,0x0C,temp);
-  tempbx--;
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x10,temp);
-  if(tempbx&0x0100){
-    	tempcx=tempcx|0x0008;
-  }
-  if(tempbx&0x0200){
-    	SiS_SetRegANDOR(SiS_Part1Port,0x0B,0x0FF,0x20);
-  }
-  tempbx++;
-  if(tempbx&0x0100){
-    	tempcx=tempcx|0x0004;
-  }
-  if(tempbx&0x0200){
-    	tempcx=tempcx|0x0080;
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0C,temp);			/* 0x0C Vertical Retrace Start */
+
+  if(!(SiS_Pr->SiS_VBType & VB_SIS301)) {
+  	tempbx--;
+  	temp = tempbx & 0x00FF;
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x10,temp);
+
+	if(tempbx & 0x0100) tempcx |= 0x0008;
+
+  	if(tempbx & 0x0200) {
+    		SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x0B,0x20);
+	}
+
+  	tempbx++;
   }
-  if(tempbx&0x0400){
-    	tempcx=tempcx|0x0C00;
+  if(tempbx & 0x0100) tempcx |= 0x0004;
+  if(tempbx & 0x0200) tempcx |= 0x0080;
+  if(tempbx & 0x0400) {
+        if(SiS_Pr->SiS_VBType & VB_SIS301) tempcx |= 0x0800;
+  	else                               tempcx |= 0x0C00;
+  }
+
+  tempbx = push1;
+  temp = tempbx & 0x00FF;
+  temp &= 0x0F;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0D,temp);        		/* 0x0D vertical Retrace End */
+
+  if(tempbx & 0x0010) tempcx |= 0x2000;
+
+  temp = tempcx & 0x00FF;
+  if(SiS_Pr->SiS_VBType & VB_SIS301) {
+	if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+	      if(SiS_Pr->SiS_VGAVDE == 480)  temp = 0xa3;
+	}
   }
-  tempbx=push1;
-  temp=tempbx&0x00FF;
-  temp=temp&0x0F;
-  SiS_SetReg1(SiS_Part1Port,0x0D,temp);                    		/* 0x0D vertical Retrace End */
-  if(tempbx&0x0010) {
-    	tempcx=tempcx|0x2000;
-  }
-
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x0A,temp);                    		/* 0x0A CR07 */
-  temp=(tempcx&0x0FF00)>>8;
-  SiS_SetReg1(SiS_Part1Port,0x17,temp);                    		/* 0x17 SR0A */
-  tempax=modeflag;
-  temp=(tempax&0xFF00)>>8;
-
-  temp=(temp>>1)&0x09;
-  SiS_SetReg1(SiS_Part1Port,0x16,temp);                    		/* 0x16 SR01 */
-  SiS_SetReg1(SiS_Part1Port,0x0F,0);                         		/* 0x0F CR14 */
-  SiS_SetReg1(SiS_Part1Port,0x12,0);                         		/* 0x12 CR17 */
-  if(SiS_LCDInfo&LCDRGB18Bit) temp=0x80;
-  else temp=0x00;
-  SiS_SetReg1(SiS_Part1Port,0x1A,temp);                         	/* 0x1A SR0E */
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0A,temp);                    		/* 0x0A CR07 */
+
+  temp = (tempcx & 0xFF00) >> 8;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x17,temp);                    		/* 0x17 SR0A */
+
+  tempax = modeflag;
+  temp = (tempax & 0xFF00) >> 8;
+  temp = (temp >> 1) & 0x09;
+  /* TW: Inserted from 630/301B and 650/301(LV/LVX) BIOS; not in 630/301 BIOS */
+  if(!(SiS_Pr->SiS_VBType & VB_SIS301)) {
+       temp |= 0x01;
+  }
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x16,temp);                    		/* 0x16 SR01 */
+
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0F,0x00);                        		/* 0x0F CR14 */
+
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x12,0x00);                        		/* 0x12 CR17 */
+
+  if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+       if(HwDeviceExtension->jChipType >= SIS_315H) {
+           /* TW: Inserted from 650/301LVx 1.10.6s */
+           if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x01) {
+	       temp = 0x80;
+	   }
+       } else temp = 0x80;
+  } else  temp = 0x00;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1A,temp);                         	/* 0x1A SR0E */
+
   return;
 }
 
-/* TW: This seems to be for some of 301B/302B/301LV/302LV as well
- *     which confuses me. In init.c, there is code for these bridges
- *     which is executed ONLY if IF_DEF_LVDS is 0. The following
- *     is being called only if IF_DEF_LVDS is NOT 0, and it contains
- *     code for 301B et al as well. Is IF_DEF_LVDS now 0 or 1 on
- *     301B/302B/301LV/302LV?
- */
-void SiS_SetGroup1_LVDS(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,
-		        USHORT ModeIdIndex,
-                        PSIS_HW_DEVICE_INFO HwDeviceExtension,
-			USHORT RefreshRateTableIndex)
-{
-  USHORT modeflag,resinfo;
-  USHORT push1,push2,tempax,tempbx,tempcx,temp,pushcx;
-  ULONG tempeax=0,tempebx,tempecx,tempvcfact=0;
+/* TW: Checked against 650/LVDS 1.10.07, 630/301B (I,II) and 630/LVDS BIOS */
+void
+SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr,USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+		   USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+		   USHORT RefreshRateTableIndex)
+{
+  USHORT modeflag, resinfo;
+  USHORT push1, push2, tempax, tempbx, tempcx, temp, pushcx;
+  ULONG  tempeax=0, tempebx, tempecx, tempvcfact=0;
 
   if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      	/* si+St_ResInfo */
-    	resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+    	resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
   } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     	/* si+Ext_ResInfo */
-    	resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
   }
 
-  tempax=SiS_LCDHDES;
-  tempbx=SiS_HDE;
-  tempcx=SiS_HT;
-
-  tempcx=tempcx-tempbx;                                    		/* HT-HDE  */
-  if(SiS_LCDInfo&LCDNonExpanding) {
-    	if(SiS_LCDResInfo==Panel640x480)  tempbx=640;
-    	if(SiS_LCDResInfo==Panel800x600)  tempbx=800;
-    	if(SiS_LCDResInfo==Panel1024x768) tempbx=1024;
-  }
-  push1=tempax;
-  tempax=tempax+tempbx;                                    		/* lcdhdee  */
-  tempbx=SiS_HT;
-  if(tempax>=tempbx){
-    	tempax=tempax-tempbx;
-  }
-  push2=tempax;	                                                       	/* push ax   lcdhdee  */
-  tempcx=tempcx>>2;                                        		/* temp  */
-  tempcx=tempcx+tempax;                                    		/* lcdhrs  */
-  if(tempcx>=tempbx){
-    	tempcx=tempcx-tempbx;
-  }									/* v ah,cl  */
-  tempax=tempcx;
-  tempax=tempax>>3;                                        		/* BPLHRS */
-  temp=tempax&0x00FF;
-  if(SiS_LCDResInfo==Panel640x480){                         		/*adjust for panel 640x480*/
-      	temp=temp-4;
-  }
-  SiS_SetReg1(SiS_Part1Port,0x14,temp);		/* <------------------ */ 	/* Part1_14h  */
-  temp=(tempax&0x00FF)+10;
-  temp=temp&0x01F;
-  temp=temp|(((tempcx&0x00ff)&0x07)<<5);
-  /*fstn*/
-  if(SiS_IF_DEF_FSTN){
-      	temp=0x20;
-  }
-  SiS_SetReg1(SiS_Part1Port,0x15,temp);    	/* <------------------- */      /* Part1_15h  */
-  tempbx=push2;                                          			/* lcdhdee  */
-  tempcx=push1;                                         			/* lcdhdes  */
-  temp=(tempcx&0x00FF);
-  temp=temp&0x07;                                      				/* BPLHDESKEW  */
-  SiS_SetReg1(SiS_Part1Port,0x1A,temp);   	/* <------------------- */      /* Part1_1Ah  */
-  tempcx=tempcx>>3;                                        			/* BPLHDES */
-  temp=(tempcx&0x00FF);
-  if(ModeNo==0x5b){                            					/*fix fstn mode=5b*/
-      	temp--;
-  }
-  SiS_SetReg1(SiS_Part1Port,0x16,temp);    	/* <------------------- */      /* Part1_16h  */
-  if(tempbx&0x07) tempbx=tempbx+8;
-  tempbx=tempbx>>3;                                        			/* BPLHDEE  */
-  temp=tempbx&0x00FF;
-  if(ModeNo==0x5b){                            					/*fix fstn mode=5b*/
-      	temp--;
-  }
-  SiS_SetReg1(SiS_Part1Port,0x17,temp);   	/* <------------------- */      /* Part1_17h  */
-
-  tempcx=SiS_VGAVT;
-  tempbx=SiS_VGAVDE;
-  tempcx=tempcx-tempbx;                                    			/* GAVT-VGAVDE  */
-  tempbx=SiS_LCDVDES;			                    			/* VGAVDES  */
-
-  push1=tempbx;                                        				/* push bx temppush1 */
-  if(SiS_IF_DEF_TRUMPION==0){
-    	if(SiS_IF_DEF_CH7005==1) {
-      		if(SiS_VBInfo&SetCRT2ToTV) {
-        		tempax=SiS_VGAVDE;
-      		}
-    	}
-    	if(SiS_VBInfo&SetCRT2ToLCD) {
-      		if(SiS_LCDResInfo==Panel640x480)  tempax=480;
-      		if(SiS_LCDResInfo==Panel800x600)  tempax=600;
-      		if(SiS_LCDResInfo==Panel1024x768) tempax=768;
-      		if(SiS_LCDResInfo==Panel320x480)  tempax=480;
-    	}
-  } else tempax=SiS_VGAVDE;
+#ifdef LINUX_XF86
+#ifdef TWDEBUG
+  xf86DrvMsg(0, X_INFO, "(init301: LCDHDES 0x%03x LCDVDES 0x%03x)\n", SiS_Pr->SiS_LCDHDES, SiS_Pr->SiS_LCDVDES);
+  xf86DrvMsg(0, X_INFO, "(init301: HDE     0x%03x VDE     0x%03x)\n", SiS_Pr->SiS_HDE, SiS_Pr->SiS_VDE);
+  xf86DrvMsg(0, X_INFO, "(init301: VGAHDE  0x%03x VGAVDE  0x%03x)\n", SiS_Pr->SiS_VGAHDE, SiS_Pr->SiS_VGAVDE);
+  xf86DrvMsg(0, X_INFO, "(init301: HT      0x%03x VT      0x%03x)\n", SiS_Pr->SiS_HT, SiS_Pr->SiS_VT);
+  xf86DrvMsg(0, X_INFO, "(init301: VGAHT   0x%03x VGAVT   0x%03x)\n", SiS_Pr->SiS_VGAHT, SiS_Pr->SiS_VGAVT);
+#endif
+#endif
 
-  tempbx=tempbx+tempax;
-  tempax=SiS_VT;                                               			/* VT  */
-  if(tempbx>=SiS_VT){
-    	tempbx=tempbx-tempax;
-  }
-  push2=tempbx;                                        				/* push bx  temppush2  */
-  tempcx=tempcx>>1;
-  tempbx=tempbx+tempcx;
-  tempbx++;                                                			/* BPLVRS  */
-  if(tempbx>=tempax){
-    	tempbx=tempbx-tempax;
-  }
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x18,temp);       	/* <------------------- */      /* Part1_18h  */
-  tempcx=tempcx>>3;
-  tempcx=tempcx+tempbx;
-  tempcx++;                                                			/* BPLVRE  */
-  temp=tempcx&0x00FF;
-  temp=temp&0x0F;
-  SiS_SetRegANDOR(SiS_Part1Port,0x19,~0x00F,temp);   /* <-------------- */      /* Part1_19h  */
-
-  temp=(tempbx&0xFF00)>>8;
-  temp=temp&0x07;
-  temp=temp<<3;                                 				/* BPLDESKEW =0 */
-  tempbx=SiS_VGAVDE;
-  if(tempbx!=SiS_VDE){
-    	temp=temp|0x40;
-  }
-  if(SiS_SetFlag&EnableLVDSDDA) {
-    	temp=temp|0x40;
-  }
-  if(SiS_LCDInfo&LCDRGB18Bit) {
-    	temp=temp|0x80;
-  }
-  SiS_SetRegANDOR(SiS_Part1Port,0x1A,0x07,temp);  /* <----------------- */    	/* Part1_1Ah */
-
-  tempecx=SiS_VGAVT;
-  tempebx=SiS_VDE;
-  tempeax=SiS_VGAVDE;
-  tempecx=tempecx-tempeax;                                 			/* VGAVT-VGAVDE  */
-  tempeax=tempeax<<6;
-  temp=(USHORT)(tempeax%tempebx);
-  tempeax=tempeax/tempebx;
-  if(temp!=0){
-    	tempeax++;
-  }
-  tempebx=tempeax;                                        			/* BPLVCFACT  */
-
-  /* TW: Modified according to info from SiS - might be wrong */
-  /* if (!(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))) { */
-  if ((HwDeviceExtension->jChipType == SIS_540)||
-      (HwDeviceExtension->jChipType == SIS_630)||
-      (HwDeviceExtension->jChipType == SIS_730)||
-      (HwDeviceExtension->jChipType == SIS_300)) {
+  /* TW: Set up Panel Link */
 
-  	if(SiS_SetFlag&EnableLVDSDDA) {
-    		tempebx=tempebx&0x003F;
-  	}
-  	temp=(USHORT)(tempebx&0x00FF);
-  	SiS_SetReg1(SiS_Part1Port,0x1E,temp);                       		/* Part1_1Eh */
+  /* 1. Horizontal setup */
 
+  tempax = SiS_Pr->SiS_LCDHDES;
+
+  if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) && (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))) {
+  	tempax -= 8;
   }
-  /*add for 301b different 301*/
-  else if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-    	tempecx=SiS_VGAVT;
-    	tempebx=SiS_VDE;
-    	tempeax=SiS_VGAVDE;
-    	tempecx=tempecx-tempeax;                                 		/* VGAVT-VGAVDE  */
-    	tempeax=tempeax<<18;
-    	temp=(USHORT)(tempeax%tempebx);
-    	tempeax=tempeax/tempebx;
-    	if(temp!=0) tempeax++;
-    	tempebx=tempeax;                                        		/* BPLVCFACT  */
-    	tempvcfact=tempeax;       /*301b*/
-    	temp=(USHORT)(tempebx&0x00FF);
-    	SiS_SetReg1(SiS_Part1Port,0x37,temp);
-    	temp=(USHORT)((tempebx&0x00FF00)>>8);
-    	SiS_SetReg1(SiS_Part1Port,0x36,temp);
-    	temp=(USHORT)((tempebx&0x00030000)>>16);
-    	if(SiS_VDE==SiS_VGAVDE)	temp=temp|0x04;
-    	SiS_SetReg1(SiS_Part1Port,0x35,temp);
-  }
-  /*end for 301b*/
-  
-  tempbx=push2;                                        				/* p bx temppush2 BPLVDEE  */
-  tempcx=push1;			/* pop cx temppush1 NPLVDES */
-  push1=(USHORT)(tempeax&0xFFFF);
-  if(!(SiS_VBInfo&SetInSlaveMode)) {
-   	if(!SiS_IF_DEF_DSTN){
-    		if(SiS_LCDResInfo==Panel800x600) {
-      			if(resinfo==7) tempcx++;
-    		} else {
-      			if(SiS_LCDResInfo==Panel1024x768) {
-        			if(resinfo==8) tempcx++;
-       			}
-     		}
-   	}
-  }
-  temp=(tempbx&0xFF00)>>8;
-  temp=temp&0x07;
-  temp=temp<<3;
-  temp=temp|(((tempcx&0xFF00)>>8)&0x07);
-  SiS_SetReg1(SiS_Part1Port,0x1D,temp);     	/* <------------------- */     	/* Part1_1Dh */
-  temp=tempbx&0x00FF;
-  /*fstn*/
-  if(SiS_IF_DEF_FSTN){
-      	temp=temp+1;
-  }
-  SiS_SetReg1(SiS_Part1Port,0x1C,temp);      	/* <------------------- */   	/* Part1_1Ch  */
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x1B,temp);      	/* <------------------- */     	/* Part1_1Bh  */
-
-  tempecx=SiS_VGAHDE;
-  tempebx=SiS_HDE;
-  tempeax=tempecx;
-  tempeax=tempeax<<16;
-  tempeax=tempeax/tempebx;
-  if(tempebx==tempecx){
-    	tempeax=0xFFFF;
-  }
-  tempecx=tempeax;
-  tempeax=SiS_VGAHT; /* TW: Was SiS_VGAHDE;  - WRONG! - old (wrong) comment: "change VGAHT->VGAHDE"*/
-  tempeax=tempeax<<16;
-  tempeax=tempeax/tempecx;
-  tempecx=tempecx<<16;
-  tempeax=tempeax-1;
-  tempecx=tempecx|(tempeax&0x00FFFF);
-  temp=(USHORT)(tempecx&0x00FF);
-  SiS_SetReg1(SiS_Part1Port,0x1F,temp);  	/* <------------------- */    	/* Part1_1Fh  */
-
-  tempbx = SiS_VDE; /* TW: added this and if statement */
-  if (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-  	tempeax=SiS_VGAVDE;
-  	tempeax=tempeax<<18;          /*301b*/
-  	tempeax=tempeax/tempvcfact;
-  	tempbx=(USHORT) (tempeax&0x0FFFF);
-  }
-
-  if(SiS_LCDResInfo==Panel1024x768) tempbx--;
-
-  if(SiS_SetFlag&EnableLVDSDDA) tempbx=1;
-
-  temp=((tempbx&0xFF00)>>8)<<3;
-  temp=temp|(USHORT)(((tempecx&0x0000FF00)>>8)&0x07);
-  SiS_SetReg1(SiS_Part1Port,0x20,temp);  	/* <------------------- */    	/* Part1_20h */
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x21,temp);  	/* <------------------- */     	/* Part1_21h */
-  tempecx=tempecx>>16;                                     			/* BPLHCFACT  */
-  if(modeflag&HalfDCLK) {
-    	tempecx=tempecx>>1;
-  }
-  temp=(USHORT)((tempecx&0x0000FF00)>>8);
-  SiS_SetReg1(SiS_Part1Port,0x22,temp);     	/* <------------------- */      /* Part1_22h */
-  temp=(USHORT)(tempecx&0x000000FF);
-  SiS_SetReg1(SiS_Part1Port,0x23,temp); 	/* <------------------- */
- /*add dstn new register*/
-  if(SiS_IF_DEF_DSTN){
-     	SiS_SetReg1(SiS_Part1Port,0x1E,0x01);
-     	SiS_SetReg1(SiS_Part1Port,0x25,0x00);
-     	SiS_SetReg1(SiS_Part1Port,0x26,0x00);
-     	SiS_SetReg1(SiS_Part1Port,0x27,0x00);
-     	SiS_SetReg1(SiS_Part1Port,0x28,0x87);
-     	SiS_SetReg1(SiS_Part1Port,0x29,0x5A);
-     	SiS_SetReg1(SiS_Part1Port,0x2A,0x4B);
-     	SiS_SetRegANDOR(SiS_Part1Port,0x44,~0x007,0x03);
-     	tempbx=SiS_HDE;                              				/*Blps=lcdhdee(lcdhdes+HDE) +64*/
-     	tempbx=tempbx+64;
-     	temp=tempbx&0x00FF;
-     	SiS_SetReg1(SiS_Part1Port,0x38,temp);
-     	temp=((tempbx&0xFF00)>>8)<<3;
-     	SiS_SetRegANDOR(SiS_Part1Port,0x35,~0x078,temp);
-     	tempbx=tempbx+32;		       					/*Blpe=lBlps+32*/
-     	temp=tempbx&0x00FF;
-     	/*fstn*/
-     	if(SiS_IF_DEF_FSTN){
-         	temp=0;
-     	}
-     	SiS_SetReg1(SiS_Part1Port,0x39,temp);
-     	SiS_SetReg1(SiS_Part1Port,0x3A,0x00);  /*Bflml=0*/
-     	SiS_SetRegANDOR(SiS_Part1Port,0x3C,~0x007,0x00);
-     	tempbx=SiS_VDE;
-     	tempbx=tempbx/2;
-     	temp=tempbx&0x00FF;
-     	SiS_SetReg1(SiS_Part1Port,0x3B,temp);
-     	temp=((tempbx&0xFF00)>>8)<<3;
-     	SiS_SetRegANDOR(SiS_Part1Port,0x3C,~0x038,temp);
-     	tempeax=SiS_HDE;                       					/* BDxFIFOSTOP= (HDE*4)/128 */
-     	tempeax=tempeax*4;
-     	tempebx=128;
-     	temp=(USHORT)(tempeax%tempebx);
-     	tempeax=tempeax/tempebx;
-     	if(temp!=0){
-      		tempeax++;
-     	}
-     	temp=(USHORT)(tempeax&0x0000003F);
-     	SiS_SetRegANDOR(SiS_Part1Port,0x45,~0x0FF,temp);
-     	SiS_SetReg1(SiS_Part1Port,0x3F,0x00);           			/*BDxWadrst0*/
-     	SiS_SetReg1(SiS_Part1Port,0x3E,0x00);
-     	SiS_SetReg1(SiS_Part1Port,0x3D,0x10);
-     	SiS_SetRegANDOR(SiS_Part1Port,0x3C,~0x040,0x00);
-     	tempax=SiS_HDE;
-     	tempax=tempax>>4;                                			/*BDxWadroff = HDE*4/8/8  */
-     	pushcx=tempax;
-     	temp=tempax&0x00FF;
-     	SiS_SetReg1(SiS_Part1Port,0x43,temp);
-     	temp=((tempax&0xFF00)>>8)<<3;
-     	SiS_SetRegANDOR(SiS_Part1Port,0x44,~0x0F8,temp);
-     	tempax=SiS_VDE;                        					/*BDxWadrst1 = BDxWadrst0+BDxWadroff*VDE*/
-     	tempeax=(tempax*pushcx);
-     	tempebx=0x00100000+tempeax;
-     	temp=(USHORT)tempebx&0x000000FF;
-     	SiS_SetReg1(SiS_Part1Port,0x42,temp);
-     	temp=(USHORT)((tempebx&0x0000FF00)>>8);
-     	SiS_SetReg1(SiS_Part1Port,0x41,temp);
-     	temp=(USHORT)((tempebx&0x00FF0000)>>16);
-     	SiS_SetReg1(SiS_Part1Port,0x40,temp);
-     	temp=(USHORT)((tempebx&0x01000000)>>24);
-     	temp=temp<<7;
-     	SiS_SetRegANDOR(SiS_Part1Port,0x3C,~0x080,temp);
-     	SiS_SetReg1(SiS_Part1Port,0x2F,0x03);
-     	SiS_SetReg1(SiS_Part1Port,0x03,0x50);
-     	SiS_SetReg1(SiS_Part1Port,0x04,0x00);
-     	SiS_SetReg1(SiS_Part1Port,0x2F,0x01);
-     	SiS_SetReg1(SiS_Part1Port,0x13,0x00);
-     	SiS_SetReg1(SiS_P3c4,0x05,0x86);
-     	SiS_SetReg1(SiS_P3c4,0x1e,0x62);
-     	/*fstn*/
-     	if(SiS_IF_DEF_FSTN){
-         	SiS_SetReg1(SiS_P3c4,0x2b,0x1b);
-         	SiS_SetReg1(SiS_P3c4,0x2c,0xe3);
-         	SiS_SetReg1(SiS_P3c4,0x1e,0x62);
-         	SiS_SetReg1(SiS_P3c4,0x2e,0x04);
-         	SiS_SetReg1(SiS_P3c4,0x2f,0x42);
-         	SiS_SetReg1(SiS_P3c4,0x32,0x01);
-         	SiS_SetReg1(SiS_Part1Port,0x2b,0x02);
-         	SiS_SetReg1(SiS_Part1Port,0x2c,0x00);
-         	SiS_SetReg1(SiS_Part1Port,0x2d,0x00);
-     	}
-     	/*end add fstn*/
-     	SiS_SetRegANDOR(SiS_Part1Port,0x19,0x00f,0x30);
-     	SiS_SetReg1(SiS_Part1Port,0x1e,0x7d);
-     	SiS_SetReg1(SiS_Part1Port,0x2e,0xe0);
-  }
-  /*end add dstn*/
-  return;
-}
 
-/*301b*/
-void
-SiS_SetGroup1_LCDA(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                   PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex)
-{
-  USHORT modeflag,resinfo;
-  USHORT push1,push2,tempax,tempbx,tempcx,temp;
-  ULONG tempeax=0,tempebx,tempecx,tempvcfact;/*301b*/
+  tempcx = SiS_Pr->SiS_HT;    				  /* Horiz. Total */
 
-  SiS_SetRegOR(SiS_Part1Port,0x2D,0x20);
-  
-  if(ModeNo<=0x13) {
-    modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-    resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
-  } else {
-    modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-    resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  tempbx = SiS_Pr->SiS_HDE;                               /* Horiz. Display End */
+
+  if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) {
+    if(!SiS_Pr->SiS_IF_DEF_DSTN) {
+ 	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)        tempbx = 800;
+    	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  tempbx = 1024;
+	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)  tempbx = 1024;  /* TW: not done in BIOS */
+	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768)  tempbx = 1152;  /* TW: not done in BIOS */
+	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempbx = 1280;  /* TW */
+        else if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)   tempbx = 1400;  /* TW */
+    }
   }
+  tempcx = (tempcx - tempbx) >> 2;		 /* HT-HDE / 4 */
 
-  tempax=SiS_LCDHDES;
-  tempbx=SiS_HDE;
-  tempcx=SiS_HT;
-  
-  if(SiS_LCDInfo&LCDNonExpanding) {
-    	if(SiS_LCDResInfo==Panel1280x1024) tempbx=1280;
-    	if(SiS_LCDResInfo==Panel1024x768) tempbx=1024;
-  }
-  tempcx=tempcx-tempbx;                                    	/* HT-HDE  */
-  push1=tempax;
-  tempax=tempax+tempbx;                                    	/* lcdhdee  */
-  tempbx=SiS_HT;
-  if(tempax>=tempbx){
-   	tempax=tempax-tempbx;
-  }
-  push2=tempax;
-                                                           	/* push ax   lcdhdee  */
-  tempcx=tempcx>>2;                                        	/* temp  */
-  tempcx=tempcx+tempax;                                    	/* lcdhrs  */
-  if(tempcx>=tempbx){
-    	tempcx=tempcx-tempbx;
+  push1 = tempax;
+
+  tempax += tempbx;
+
+  if(tempax >= SiS_Pr->SiS_HT) tempax -= SiS_Pr->SiS_HT;
+
+  push2 = tempax;
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+       if(!SiS_Pr->SiS_IF_DEF_DSTN){
+     	  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)        tempcx = 0x0028;
+     	  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 0x0030;
+     	  else if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) ||
+		   (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) ) {
+	  	if(HwDeviceExtension->jChipType < SIS_315H) {
+		     if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+		           tempcx = 0x0017;
+#ifdef TWNEWPANEL
+			   tempcx = 0x0018;
+#endif
+		     } else {
+		           tempcx = 0x0017;  /* A901; other 301B BIOS 0x0018; */
+		     }
+		} else {
+		     tempcx = 0x0018;
+		}
+	  }
+	  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)  tempcx = 0x0018;
+     	  else if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)   tempcx = 0x0030;
+       }
   }
-                                                           	/* v ah,cl  */
-  tempax=tempcx;
-  tempax=tempax>>3;                                        	/* BPLHRS */
-  temp=tempax&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x14,temp);                         /* Part1_14h  */
-  temp=(tempax&0x00FF)+10;
-  temp=temp&0x01F;
-  temp=temp|(((tempcx&0x00ff)&0x07)<<5);
-  SiS_SetReg1(SiS_Part1Port,0x15,temp);                         /* Part1_15h  */
-  tempbx=push2;                                          	/* lcdhdee  */
-  tempcx=push1;                                          	/* lcdhdes  */
-  temp=(tempcx&0x00FF);
-  temp=temp&0x07;                                      		/* BPLHDESKEW  */
-  SiS_SetReg1(SiS_Part1Port,0x1A,temp);                         /* Part1_1Ah  */
-  tempcx=tempcx>>3;                                        	/* BPLHDES */
-  temp=(tempcx&0x00FF);
-  SiS_SetReg1(SiS_Part1Port,0x16,temp);                         /* Part1_16h  */
-  if(tempbx&0x07) tempbx=tempbx+8;
-  tempbx=tempbx>>3;                                        	/* BPLHDEE  */
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x17,temp);                        	/* Part1_17h  */
-
-  tempcx=SiS_VGAVT;
-  tempbx=SiS_VGAVDE;
-  tempcx=tempcx-tempbx;                                    	/* GAVT-VGAVDE  */
-  tempbx=SiS_LCDVDES;                                          	/* VGAVDES  */
-  push1=tempbx;                                        		/* push bx temppush1 */
-  if(SiS_IF_DEF_TRUMPION==0){
-    if(SiS_IF_DEF_CH7005==1) {
-      if(SiS_VBInfo&SetCRT2ToTV) {
-        tempax=SiS_VGAVDE;
-      }
-    }
-    if(SiS_LCDResInfo==Panel1024x768) tempax=768;
-    if(SiS_LCDResInfo==Panel1280x1024)  tempax=1024;
-  }
-  else tempax=SiS_VGAVDE;
-  tempbx=tempbx+tempax;
-  tempax=SiS_VT;                                               	/* VT  */
-  if(tempbx>=SiS_VT){
-    tempbx=tempbx-tempax;
-  }
-  push2=tempbx;                                        		/* push bx  temppush2  */
-  tempcx=tempcx>>1;
-  tempbx=tempbx+tempcx;
-  tempbx++;                                                	/* BPLVRS  */
-  if(tempbx>=tempax){
-    tempbx=tempbx-tempax;
+
+  tempcx += tempax;                              /* lcdhrs  */
+  if(tempcx >= SiS_Pr->SiS_HT) tempcx -= SiS_Pr->SiS_HT;
+
+  tempax = tempcx >> 3;                          /* BPLHRS */
+  temp = tempax & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x14,temp);		 /* Part1_14h; TW: Panel Link Horizontal Retrace Start  */
+
+  temp = (tempax & 0x00FF) + 10;
+
+  /* TW: Inserted this entire "if"-section from 650/LVDS BIOS */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+      if(!SiS_Pr->SiS_IF_DEF_DSTN){
+        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+	  temp += 6;
+          if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel800x600) {
+	    temp++;
+	    if(HwDeviceExtension->jChipType >= SIS_315H) {
+	       if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1024x768) {
+	          temp -= 3;
+	       }
+	    }
+	  }
+        }
+      }
   }
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x18,temp);                         /* Part1_18h  */
-  tempcx=tempcx>>3;
-  tempcx=tempcx+tempbx;
-  tempcx++;                                                	/* BPLVRE  */
-  temp=tempcx&0x00FF;
-  temp=temp&0x0F;
-  SiS_SetRegANDOR(SiS_Part1Port,0x19,~0x00F,temp);               /* Part1_19h  */
-  temp=(tempbx&0xFF00)>>8;
-  temp=temp&0x07;
-  temp=temp<<3;                                 		/* BPLDESKEW =0 */
-  tempbx=SiS_VGAVDE;
-  if(tempbx!=SiS_VDE){
-    temp=temp|0x40;
+
+  temp &= 0x1F;
+  temp |= ((tempcx & 0x0007) << 5);
+  if(SiS_Pr->SiS_IF_DEF_FSTN) temp = 0x20;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x15,temp);    	 /* Part1_15h; TW: Panel Link Horizontal Retrace End/Skew */
+
+  tempbx = push2;
+  tempcx = push1;                                /* lcdhdes  */
+
+  temp = (tempcx & 0x0007);                      /* BPLHDESKEW  */
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1A,temp);   	 /* Part1_1Ah; TW: Panel Link Vertical Retrace Start (2:0) */
+
+  tempcx >>= 3;                                  /* BPLHDES */
+  temp = (tempcx & 0x00FF);
+  if(ModeNo == 0x5b) temp--;                     /* fix fstn mode=5b */
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x16,temp);    	 /* Part1_16h; TW: Panel Link Horizontal Display Enable Start  */
+
+  if(HwDeviceExtension->jChipType < SIS_315H) {  /* TW: Not done in LVDS BIOS 1.10.07 */
+     if(tempbx & 0x07) tempbx += 8;              /* TW: Done in 630/301B and 630/LVDS BIOSes */
+  }
+  tempbx >>= 3;                                  /* BPLHDEE  */
+  temp = tempbx & 0x00FF;
+  if(ModeNo == 0x5b) temp--;			 /* fix fstn mode=5b */
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x17,temp);   	 /* Part1_17h; TW: Panel Link Horizontal Display Enable End  */
+
+  /* 2. Vertical setup */
+
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+
+      /* TW: This entire section from 630/301B and 630/LVDS/LVDS+CH BIOS */
+      tempcx = SiS_Pr->SiS_VGAVT;
+      tempbx = SiS_Pr->SiS_VGAVDE;
+      if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) {
+         if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+	    tempbx = 600;
+	    if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel800x600) {
+	       tempbx = 768;
+	       if( (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1024x768) &&
+	           (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1152x768) ) {
+	 	    tempbx = 600;
+	       }
+	    }
+         }
+      }
+      tempcx -= tempbx;
+
+  } else {
+
+      tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE;          /* VGAVT-VGAVDE  */
+
+  }
+
+  tempbx = SiS_Pr->SiS_LCDVDES;	   		 	 	/* VGAVDES  */
+  push1 = tempbx;
+
+  tempax = SiS_Pr->SiS_VGAVDE;
+
+  if((SiS_Pr->SiS_IF_DEF_TRUMPION == 0) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))
+                                && (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)) {
+    	if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	    if(!SiS_Pr->SiS_IF_DEF_DSTN){
+      		if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)        tempax = 600;
+      		else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  tempax = 768;
+		else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)  tempax = 600;   /* TW */
+      		else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768)  tempax = 768;   /* TW */
+		else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempax = 1024;  /* TW */
+		else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempax = 1050;  /* TW */
+		else                                                          tempax = 600;
+            }
+    	}
   }
-  if(SiS_SetFlag&EnableLVDSDDA) {
-    temp=temp|0x40;
+
+  tempbx += tempax;
+  if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT;
+
+  push2 = tempbx;
+
+  tempcx >>= 1;
+
+  if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)){
+     if(!SiS_Pr->SiS_IF_DEF_DSTN){
+     	if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) ||
+	    (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) ) {   /* TW: @@@ TEST - not in BIOS! */
+	     	tempcx = 0x0001;
+     	} else if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) ||
+	           (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) ) {
+		if(HwDeviceExtension->jChipType < SIS_315H) {
+		      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+			    tempcx = 0x0002;
+#ifdef TWNEWPANEL
+			    tempcx = 0x0003;
+#endif
+		      } else {
+		            tempcx = 0x0002;   /* TW: A901; other 301B BIOS sets 0x0003; */
+		      }
+		} else tempcx = 0x0003;
+        }
+     	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)  tempcx = 0x0003;
+     	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempcx = 0x0001;
+     	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 0x0001;
+     	else 				                              tempcx = 0x0057;
+     }
+  }
+
+  tempbx += tempcx;			 	/* BPLVRS  */
+
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+      tempbx++;
   }
-  if(SiS_LCDInfo&LCDRGB18Bit) {
-    temp=temp|0x80;
+
+  if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT;
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,temp);       	 /* Part1_18h; TW: Panel Link Vertical Retrace Start  */
+
+  tempcx >>= 3;
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+     if( (HwDeviceExtension->jChipType < SIS_315H) &&
+         (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) )     tempcx = 0x0001;
+     else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)  tempcx = 0x0002;
+     else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)    tempcx = 0x0003;
+     else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)   tempcx = 0x0005;
+     else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768)   tempcx = 0x0005;
+     else if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)  {
+     		if(HwDeviceExtension->jChipType < SIS_315H) {
+		        if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+				tempcx = 0x0004;
+#ifdef TWNEWPANEL
+				tempcx = 0x0005;
+#endif
+		        } else {
+				tempcx = 0x0004;   /* A901; Other BIOS sets 0x0005; */
+			}
+		} else {
+			tempcx = 0x0005;
+		}
+     }
   }
-  SiS_SetRegANDOR(SiS_Part1Port,0x1A,0x07,temp);             	/* Part1_1Ah */
-  
-  tempbx=push2;                                        		/* p bx temppush2 BPLVDEE  */
-  tempcx=push1;                                        		/* pop cx temppush1 NPLVDES */
-  push1=(USHORT)(tempeax&0xFFFF);
-    
-  if(!(SiS_VBInfo&SetInSlaveMode)) {
-    if(SiS_LCDResInfo==Panel800x600) {
-      if(resinfo==7) tempcx++;
-    } else {
-      if(SiS_LCDResInfo==Panel1024x768) {
-        if(resinfo==8) tempcx++;
+
+  tempcx = tempcx + tempbx + 1;                  /* BPLVRE  */
+  temp = tempcx & 0x000F;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xf0,temp); /* Part1_19h; TW: Panel Link Vertical Retrace End (3:0); Misc.  */
+
+  temp = ((tempbx & 0x0700) >> 8) << 3;          /* BPLDESKEW =0 */
+  if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE)  temp |= 0x40;
+  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA)    temp |= 0x40;
+  if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)   {
+      if(HwDeviceExtension->jChipType >= SIS_315H) {
+         if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x01) {	/* TW: Inserted from 650/LVDS 1.10.07 */
+            temp |= 0x80;
+         }
+      } else {
+	 if( (HwDeviceExtension->jChipType == SIS_630) ||
+	     (HwDeviceExtension->jChipType == SIS_730) ) {
+	    if(HwDeviceExtension->jChipRevision >= 0x30) {
+	       temp |= 0x80;
+	    }
+	 }
       }
-    }
+  }         /* TW: in follwing line, 0x87 was 0x07 (modified according to 650/LVDS BIOS) */
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,0x87,temp);  /* Part1_1Ah; TW: Panel Link Control Signal (7:3); Vertical Retrace Start (2:0) */
+
+  if (HwDeviceExtension->jChipType < SIS_315H) {
+
+        /* 300 series */
+
+        tempeax = SiS_Pr->SiS_VGAVDE << 6;
+        temp = (USHORT)(tempeax % (ULONG)SiS_Pr->SiS_VDE);
+        tempeax = tempeax / (ULONG)SiS_Pr->SiS_VDE;
+        if(temp != 0) tempeax++;
+        tempebx = tempeax;                         /* BPLVCFACT  */
+
+  	if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) {
+	     tempebx = 0x003F;
+	}
+
+  	temp = (USHORT)(tempebx & 0x00FF);
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1E,temp);      /* Part1_1Eh; TW: Panel Link Vertical Scaling Factor */
+
+  } else {
+
+        /* 310/325 series */
+
+	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1E,0x23);
+
+	tempeax = SiS_Pr->SiS_VGAVDE << 18;
+    	temp = (USHORT)(tempeax % (ULONG)SiS_Pr->SiS_VDE);
+    	tempeax = tempeax / SiS_Pr->SiS_VDE;
+    	if(temp != 0) tempeax++;
+    	tempebx = tempeax;                         /* BPLVCFACT  */
+        tempvcfact = tempeax;
+    	temp = (USHORT)(tempebx & 0x00FF);
+    	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x37,temp);      /* Part1_37h; TW: Panel Link Vertical Scaling Factor */
+    	temp = (USHORT)((tempebx & 0x00FF00) >> 8);
+    	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x36,temp);      /* Part1_36h; TW: Panel Link Vertical Scaling Factor */
+    	temp = (USHORT)((tempebx & 0x00030000) >> 16);
+    	if(SiS_Pr->SiS_VDE == SiS_Pr->SiS_VGAVDE) temp |= 0x04;
+    	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x35,temp);      /* Part1_35h; TW: Panel Link Vertical Scaling Factor */
+
   }
 
-  temp=(tempbx&0xFF00)>>8;
-  temp=temp&0x07;
-  temp=temp<<3;
-  temp=temp|(((tempcx&0xFF00)>>8)&0x07);
-  SiS_SetReg1(SiS_Part1Port,0x1D,temp);                          /* Part1_1Dh */
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x1C,temp);                          /* Part1_1Ch  */
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x1B,temp);                          /* Part1_1Bh  */ 
-
-  tempecx=SiS_VGAVT;
-  tempebx=SiS_VDE;
-  tempeax=SiS_VGAVDE;
-  tempecx=tempecx-tempeax;                                 	/* VGAVT-VGAVDE  */
-  tempeax=tempeax<<18;
-  temp=(USHORT)(tempeax%tempebx);
-  tempeax=tempeax/tempebx;
-  if(temp!=0){
-    tempeax++;
-  }
-  tempebx=tempeax;                                        	/* BPLVCFACT  */
-  tempvcfact=tempeax;       /*301b*/
-  temp=(USHORT)(tempebx&0x00FF);
-  SiS_SetReg1(SiS_Part1Port,0x37,temp);   
-  temp=(USHORT)((tempebx&0x00FF00)>>8);
-  SiS_SetReg1(SiS_Part1Port,0x36,temp);   
-  temp=(USHORT)((tempebx&0x00030000)>>16);
-  if(SiS_VDE==SiS_VGAVDE) {
-      temp=temp|0x04;
+  tempbx = push2;                                  /* p bx temppush1 BPLVDEE  */
+  tempcx = push1;
+
+  push1 = temp;					   /* TW: For 630/301B and 630/LVDS */
+
+  if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+   	if(!SiS_Pr->SiS_IF_DEF_DSTN){
+		if(HwDeviceExtension->jChipType < SIS_315H) {
+			if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+      				if(resinfo == 15) tempcx++;
+				if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) {
+					if(resinfo == 7) tempcx++;
+		    		}
+			} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+      				if(resinfo == 7) tempcx++;
+				if(resinfo == 8) tempcx++; /* TW: Doesnt make sense anyway... */
+			} else  if(resinfo == 8) tempcx++;
+		} else {
+			if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+      				if(resinfo == 7) tempcx++;
+			}
+		}
+	}
   }
-  
-  SiS_SetReg1(SiS_Part1Port,0x35,temp);   
-  
-  tempecx=SiS_VGAHDE;
-  tempebx=SiS_HDE;
-  tempeax=tempecx;
-  tempeax=tempeax<<6;
-  tempeax=tempeax<<10;
-  tempeax=tempeax/tempebx;
-  if(tempebx==tempecx){
-    	tempeax=0xFFFF;
-  }
-  tempecx=tempeax;
-  tempeax=SiS_VGAHDE;  /*301b to change HT->HDE*/
-  tempeax=tempeax<<6;
-  tempeax=tempeax<<10;
-  tempeax=tempeax/tempecx;
-  tempecx=tempecx<<16;
-  tempeax=tempeax-1;
-  tempecx=tempecx|(tempeax&0x00FFFF);
-  temp=(USHORT)(tempecx&0x00FF);
-  SiS_SetReg1(SiS_Part1Port,0x1F,temp);                          /* Part1_1Fh  */
-
-  tempeax=SiS_VGAVDE;
-  tempeax=tempeax<<18;          /*301b*/
-  tempeax=tempeax/tempvcfact;
-  tempbx=(USHORT) (tempeax&0x0FFFF);
-  if(SiS_LCDResInfo==Panel1024x768) tempbx--;
-  if(SiS_SetFlag&EnableLVDSDDA){
-    	tempbx=1;
-  }
-  temp=((tempbx&0xFF00)>>8)<<3;
-  temp=temp|(USHORT)(((tempecx&0x0000FF00)>>8)&0x07);
-  SiS_SetReg1(SiS_Part1Port,0x20,temp);                         /* Part1_20h */
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x21,temp);                         /* Part1_21h */
-  tempecx=tempecx>>16;                                     	/* BPLHCFACT  */
- 
-  temp=(USHORT)((tempecx&0x0000FF00)>>8);
-  SiS_SetReg1(SiS_Part1Port,0x22,temp);                         /* Part1_22h */
-  temp=(USHORT)(tempecx&0x000000FF);
-  SiS_SetReg1(SiS_Part1Port,0x23,temp);
-  
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-  	SiS_SetReg1(SiS_Part1Port,0x1e,0x20);  /* for 650 & 550 lvds part */
+
+  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+     tempcx = SiS_Pr->SiS_VGAVDE;
+     tempbx = SiS_Pr->SiS_VGAVDE - 1;
+  }
+
+  temp = ((tempbx & 0x0700) >> 8) << 3;
+  temp |= ((tempcx & 0x0700) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1D,temp);     	/* Part1_1Dh; TW: Vertical Display Overflow; Control Signal */
+
+  temp = tempbx & 0x00FF;
+  if(SiS_Pr->SiS_IF_DEF_FSTN) temp++;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1C,temp);      	/* Part1_1Ch; TW: Panel Link Vertical Display Enable End  */
+
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1B,temp);      	/* Part1_1Bh; TW: Panel Link Vertical Display Enable Start  */
+
+  /* 3. Additional horizontal setup (scaling, etc) */
+
+  tempecx = SiS_Pr->SiS_VGAHDE;
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     if(modeflag & HalfDCLK)
+        tempecx >>= 1;
+  }
+  tempebx = SiS_Pr->SiS_HDE;
+  if(tempecx == tempebx) tempeax = 0xFFFF;
+  else {
+     tempeax = tempecx;
+     tempeax <<= 16;
+     temp = (USHORT)(tempeax % tempebx);
+     tempeax = tempeax / tempebx;
+     if(HwDeviceExtension->jChipType >= SIS_315H) {
+         if(temp) tempeax++;
+     }
+  }
+  tempecx = tempeax;
+
+  if (HwDeviceExtension->jChipType >= SIS_315H) {
+      tempeax = SiS_Pr->SiS_VGAHDE;
+      if(modeflag & HalfDCLK)
+          tempeax >>= 1;
+      tempeax <<= 16;
+      tempeax = (tempeax / tempecx) - 1;
+  } else {
+      tempeax = ((SiS_Pr->SiS_VGAHT << 16) / tempecx) - 1;
+  }
+  tempecx <<= 16;
+  tempecx |= (tempeax & 0xFFFF);
+  temp = (USHORT)(tempecx & 0x00FF);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1F,temp);  	 /* Part1_1Fh; TW: Panel Link DDA Operational Number in each horiz. line */
+
+  tempbx = SiS_Pr->SiS_VDE;
+  if (HwDeviceExtension->jChipType >= SIS_315H) {
+      tempeax = (SiS_Pr->SiS_VGAVDE << 18) / tempvcfact;
+      tempbx = (USHORT)(tempeax & 0x0FFFF);
+  } else {
+      tempax = SiS_Pr->SiS_VGAVDE << 6;
+      tempbx = push1;
+      tempbx &= 0x3f;
+      if(tempbx == 0) tempbx = 64;
+      tempax = tempax / tempbx;
+      tempbx = tempax;
+  }
+  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) tempbx--;
+  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA)                 tempbx = 1;
+
+  temp = ((tempbx & 0xFF00) >> 8) << 3;
+  temp |= (USHORT)((tempecx & 0x0700) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x20,temp);  	/* Part1_20h; TW: Overflow register */
+
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x21,temp);  	/* Part1_21h; TW: Panel Link Vertical Accumulator Register */
+
+  tempecx >>= 16;                               /* BPLHCFACT  */
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+      if(modeflag & HalfDCLK) tempecx >>= 1;
+  }
+  temp = (USHORT)((tempecx & 0xFF00) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x22,temp);     	/* Part1_22h; TW: Panel Link Horizontal Scaling Factor High */
+
+  temp = (USHORT)(tempecx & 0x00FF);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x23,temp);         /* Part1_22h; TW: Panel Link Horizontal Scaling Factor Low */
+
+  /* 630/301B and 630/LVDS do something for 640x480 panels here */
+
+  /* TW: DSTN/FSTN initialisation - hardcoded for 320x480 panel */
+  if(SiS_Pr->SiS_IF_DEF_DSTN){
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1E,0x01);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x25,0x00);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x26,0x00);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x27,0x00);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x28,0x87);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x29,0x5A);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2A,0x4B);
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x007,0x03);
+     	tempbx = SiS_Pr->SiS_HDE + 64;                       	/*Blps = lcdhdee(lcdhdes+HDE) + 64*/
+     	temp = tempbx & 0x00FF;
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x38,temp);
+     	temp=((tempbx & 0xFF00) >> 8) << 3;
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,~0x078,temp);
+     	tempbx += 32;		                     		/*Blpe=lBlps+32*/
+     	temp = tempbx & 0x00FF;
+     	if(SiS_Pr->SiS_IF_DEF_FSTN)  temp=0;
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x39,temp);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3A,0x00);        	/*Bflml=0*/
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x007,0x00);
+     	tempbx = SiS_Pr->SiS_VDE / 2;
+     	temp = tempbx & 0x00FF;
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3B,temp);
+     	temp = ((tempbx & 0xFF00) >> 8) << 3;
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x038,temp);
+     	tempeax = SiS_Pr->SiS_HDE << 2;                       	/* BDxFIFOSTOP = (HDE*4)/128 */
+     	tempebx = 128;
+     	temp = (USHORT)(tempeax % tempebx);
+     	tempeax = tempeax / tempebx;
+     	if(temp != 0)  tempeax++;
+     	temp = (USHORT)(tempeax & 0x003F);
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x45,~0x0FF,temp);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3F,0x00);         	/* BDxWadrst0 */
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3E,0x00);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3D,0x10);
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x040,0x00);
+     	tempax = SiS_Pr->SiS_HDE >> 4;                        	/* BDxWadroff = HDE*4/8/8 */
+     	pushcx = tempax;
+     	temp = tempax & 0x00FF;
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x43,temp);
+     	temp = ((tempax & 0xFF00) >> 8) << 3;
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x0F8,temp);
+     	tempax = SiS_Pr->SiS_VDE;                             /*BDxWadrst1 = BDxWadrst0 + BDxWadroff * VDE */
+     	tempeax = (tempax * pushcx);
+     	tempebx = 0x00100000 + tempeax;
+     	temp = (USHORT)tempebx & 0x000000FF;
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x42,temp);
+     	temp = (USHORT)((tempebx & 0x0000FF00)>>8);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x41,temp);
+     	temp = (USHORT)((tempebx & 0x00FF0000)>>16);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x40,temp);
+     	temp = (USHORT)(((tempebx & 0x01000000)>>24) << 7);
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x080,temp);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2F,0x03);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x03,0x50);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x04,0x00);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2F,0x01);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x13,0x00);
+     	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);        /* Unlock */
+     	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1e,0x62);
+     	if(SiS_Pr->SiS_IF_DEF_FSTN){
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2b,0x1b);
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2c,0xe3);
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1e,0x62);
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2e,0x04);
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2f,0x42);
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,0x01);
+         	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2b,0x02);
+         	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2c,0x00);
+         	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2d,0x00);
+     	}
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0f,0x30);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1e,0x7d);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2e,0xe0);
   }
+
   return;
+
+}
+
+#ifdef SIS315H
+void
+SiS_CRT2AutoThreshold(SiS_Private *SiS_Pr, USHORT BaseAddr)
+{
+  SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x40);
 }
-/*end 301b*/
+#endif
 
-void SiS_SetTPData()
+
+/* TW: For LVDS / 302b/lv - LCDA (this must only be called on 310/325 series!) */
+/* TW: Double-checked against 650/LVDS and 650/301 BIOS */
+void
+SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                   PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex)
 {
+  USHORT modeflag,resinfo;
+  USHORT push1,push2,tempax,tempbx,tempcx,temp;
+  ULONG tempeax=0,tempebx,tempecx,tempvcfact;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1)					/* TW: From 650/LVDS BIOS */
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04);      	/* TW: From 650/LVDS BIOS */
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1)					/* TW: From 650/LVDS 1.10.07 */
+     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x00);			/* TW: From 650/LVDS 1.10.07 */
+  else
+     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2D,0x0f);			/* TW: From 650/301Lvx 1.10.6s */
+
+  if(ModeNo<=0x13) {
+    modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+    resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+  } else {
+    modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+
+  tempax = SiS_Pr->SiS_LCDHDES;
+  tempbx = SiS_Pr->SiS_HDE;
+  tempcx = SiS_Pr->SiS_HT;
+
+  if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) {
+        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)       tempbx = 1024;
+	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempbx = 1400;
+	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempbx = 1600;
+	else 							      tempbx = 1280;
+
+  }
+  tempcx -= tempbx;                        	            	/* HT-HDE  */
+  push1 = tempax;
+  tempax += tempbx;	                                    	/* lcdhdee  */
+  tempbx = SiS_Pr->SiS_HT;
+  if(tempax >= tempbx)	tempax -= tempbx;
+
+  push2 = tempax;						/* push ax   lcdhdee  */
+
+  tempcx >>= 2;
+
+  /* TW: Inserted from 650/301LVx 1.10.6s */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+          if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)        tempcx = 0x28;
+	  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 0x30;
+	  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  tempcx = 0x18;
+	  else                                                          tempcx = 0x30;
+      }
+  }
+
+  tempcx += tempax;  	                                  	/* lcdhrs  */
+  if(tempcx >= tempbx) tempcx -= tempbx;
+                                                           	/* v ah,cl  */
+  tempax = tempcx;
+  tempax >>= 3;   	                                     	/* BPLHRS */
+  temp = tempax & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x14,temp);                 	/* Part1_14h  */
+
+  temp += 10;
+  temp &= 0x1F;
+  temp |= ((tempcx & 0x07) << 5);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x15,temp);                         /* Part1_15h  */
+
+  tempbx = push2;                                          	/* lcdhdee  */
+  tempcx = push1;                                          	/* lcdhdes  */
+  temp = (tempcx & 0x00FF);
+  temp &= 0x07;                                  		/* BPLHDESKEW  */
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1A,temp);                         /* Part1_1Ah  */
+
+  tempcx >>= 3;   	                                     	/* BPLHDES */
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x16,temp);                         /* Part1_16h  */
+
+  if(tempbx & 0x07) tempbx += 8;
+  tempbx >>= 3;                                        		/* BPLHDEE  */
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x17,temp);                        	/* Part1_17h  */
+
+  tempcx = SiS_Pr->SiS_VGAVT;
+  tempbx = SiS_Pr->SiS_VGAVDE;
+  tempcx -= tempbx; 	                                   	/* GAVT-VGAVDE  */
+  tempbx = SiS_Pr->SiS_LCDVDES;                                	/* VGAVDES  */
+  push1 = tempbx;                                      		/* push bx temppush1 */
+  if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0){
+    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)        tempax = 768;
+    else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)  tempax = 1024;
+    else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)  tempax = 1050;
+    else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)  tempax = 1200;
+    else                                                           tempax = 960;
+#if 0   /* TW: Removed (650/LVDS BIOS) */
+    if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+        tempax = SiS_Pr->SiS_VGAVDE;
+      }
+    }
+#endif
+  } else tempax = SiS_Pr->SiS_VGAVDE;  /* Trumpion */
+
+  tempbx += tempax;
+  tempax = SiS_Pr->SiS_VT;                                    	/* VT  */
+  if(tempbx >= tempax)  tempbx -= tempax;
+
+  push2 = tempbx;                                      		/* push bx  temppush2  */
+  tempcx >>= 2;	/* TO CHECK - was 1 */
+
+  /* TW: Inserted from 650/301LVx 1.10.6s */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+          if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)         tempcx = 1;
+	  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)   tempcx = 3;
+	  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)   tempcx = 3;
+	  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)  tempcx = 1;
+	  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)  tempcx = 1;
+	  else                                                           tempcx = 0x0057;
+      }
+  }
+
+  tempbx += tempcx;
+  tempbx++;                                                	/* BPLVRS  */
+  if(tempbx >= tempax)   tempbx -= tempax;
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,temp);                         /* Part1_18h  */
+
+  tempcx >>= 3;
+  tempcx += tempbx;
+  tempcx++;                                                	/* BPLVRE  */
+  temp = tempcx & 0x00FF;
+  temp &= 0x0F;
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+     /* TW: Inserted from 650/LVDS BIOS */
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xf0,temp);
+  } else {
+     /* TW: Inserted from 650/301LVx 1.10.6s */
+     temp |= 0xC0;
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xF0,temp);             /* Part1_19h  */
+  }
+
+  temp = (tempbx & 0xFF00) >> 8;
+  temp &= 0x07;
+  temp <<= 3;  		                               		/* BPLDESKEW =0 */
+  tempbx = SiS_Pr->SiS_VGAVDE;
+  if(tempbx != SiS_Pr->SiS_VDE)              temp |= 0x40;
+  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA)    temp |= 0x40;
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+      /* TW: Inserted from 650/LVDS 1.10.07 */
+      if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)  temp |= 0x80;
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,0x87,temp);            /* Part1_1Ah */
+  } else {
+      /* TW: Inserted from 650/301LVx 1.10.6s */
+      if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+          if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x01) temp |= 0x80;
+      }
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,0x87,temp);            /* Part1_1Ah */
+  }
+
+  tempbx = push2;                                      		/* p bx temppush2 BPLVDEE  */
+  tempcx = push1;                                      		/* pop cx temppush1 NPLVDES */
+  push1 = (USHORT)(tempeax & 0xFFFF);
+
+  if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+      if(resinfo == 7) tempcx++;
+    }
+    /* TW: Inserted from 650/301LVx+LVDS BIOSes */
+    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+        tempbx = SiS_Pr->SiS_VGAVDE;
+	tempcx = tempbx;
+        tempbx--;
+    }
+  }
+
+  temp = (tempbx & 0xFF00) >> 8;
+  temp &= 0x07;
+  temp <<= 3;
+  temp = temp | (((tempcx & 0xFF00) >> 8) & 0x07);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1D,temp);                          /* Part1_1Dh */
+
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1C,temp);                          /* Part1_1Ch  */
+
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1B,temp);                          /* Part1_1Bh  */
+
+  tempecx = SiS_Pr->SiS_VGAVT;
+  tempebx = SiS_Pr->SiS_VDE;
+  tempeax = SiS_Pr->SiS_VGAVDE;
+  tempecx -= tempeax;    	                             	/* VGAVT-VGAVDE  */
+  tempeax <<= 18;
+  temp = (USHORT)(tempeax % tempebx);
+  tempeax = tempeax / tempebx;
+  if(temp != 0)  tempeax++;
+  tempebx = tempeax;                                        	/* BPLVCFACT  */
+  tempvcfact = tempeax;
+  temp = (USHORT)(tempebx & 0x00FF);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x37,temp);
+
+  temp = (USHORT)((tempebx & 0x00FF00) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x36,temp);
+
+  temp = (USHORT)((tempebx & 0x00030000) >> 16);
+  if(SiS_Pr->SiS_VDE == SiS_Pr->SiS_VGAVDE) temp |= 0x04;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x35,temp);
+
+  tempecx = SiS_Pr->SiS_VGAHDE;
+  tempebx = SiS_Pr->SiS_HDE;
+  tempeax = tempecx;
+  tempeax <<= 16;
+  temp = tempeax % tempebx;
+  tempeax = tempeax / tempebx;
+  if(temp) tempeax++;
+  if(tempebx == tempecx)  tempeax = 0xFFFF;
+  tempecx = tempeax;
+  tempeax = SiS_Pr->SiS_VGAHDE;
+  tempeax <<= 16;
+  tempeax = tempeax / tempecx;
+  tempecx <<= 16;
+  tempeax--;
+  tempecx = tempecx | (tempeax & 0xFFFF);
+  temp = (USHORT)(tempecx & 0x00FF);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1F,temp);                          /* Part1_1Fh  */
+
+  tempeax = SiS_Pr->SiS_VGAVDE;
+  tempeax <<= 18;
+  tempeax = tempeax / tempvcfact;
+  tempbx = (USHORT)(tempeax & 0x0FFFF);
+
+  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) tempbx--;
+
+  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA)  tempbx = 1;
+
+  temp = ((tempbx & 0xFF00) >> 8) << 3;
+  temp = temp | (USHORT)(((tempecx & 0x0000FF00) >> 8) & 0x07);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x20,temp);                         /* Part1_20h */
+
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x21,temp);                         /* Part1_21h */
+
+  tempecx >>= 16;   	                                  	/* BPLHCFACT  */
+  if(modeflag & HalfDCLK) tempecx >>= 1;
+  temp = (USHORT)((tempecx & 0x0000FF00) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x22,temp);                         /* Part1_22h */
+
+  temp=(USHORT)(tempecx & 0x000000FF);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x23,temp);
+
+#if 0
+  /* TW: Missing code (calles int 2f) (650/301LVx 1.10.6s) */
+  if(xxx()) {
+      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0e,0xda);
+  }
+#endif
+
+  /* TW: Only for 650/LVDS and 30xLV/30xLVX */
+  if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBInfo & (VB_SIS30xLV|VB_SIS30xNEW))){
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1e,0x20);
+  }
+
   return;
 }
 
-void SiS_SetCRT2Offset(USHORT SiS_Part1Port,ULONG ROMAddr,USHORT ModeNo,
+/* TW: Double-checked against 650/LVDS (1.10.07) and 650/301 BIOS */
+void SiS_SetCRT2Offset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
                        USHORT ModeIdIndex ,USHORT RefreshRateTableIndex,
 		       PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT offset;
   UCHAR temp;
 
-  if(SiS_VBInfo&SetInSlaveMode) return;
+  if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) return;
 
-  offset=SiS_GetOffset(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                       HwDeviceExtension);
-  temp=(UCHAR)(offset&0xFF);
-  SiS_SetReg1(SiS_Part1Port,0x07,temp);
-  temp=(UCHAR)((offset&0xFF00)>>8);
-  SiS_SetReg1(SiS_Part1Port,0x09,temp);
-  temp=(UCHAR)(((offset>>3)&0xFF)+1);
-  SiS_SetReg1(SiS_Part1Port,0x03,temp);
+  offset = SiS_GetOffset(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                         HwDeviceExtension);
+  temp = (UCHAR)(offset & 0xFF);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,temp);
+  temp = (UCHAR)((offset & 0xFF00) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x09,temp);
+  temp = (UCHAR)(((offset >> 3) & 0xFF) + 1);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x03,temp);
 }
 
+/* TW: Checked with 650/LVDS and 650/301 BIOS */
 USHORT
-SiS_GetOffset(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+SiS_GetOffset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
               USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT temp,colordepth;
   USHORT modeinfo,index,infoflag;
-  USHORT ColorDepth[]={0x02,0x04,0x08};  /* TW: Was 1,2,4 */
+#if 0
+  USHORT mode960low, mode960high;
+  USHORT ColorDepth[] = { 0x01, 0x02, 0x04 };
+#endif
 
-  modeinfo = SiS_EModeIDTable[ModeIdIndex].Ext_ModeInfo;
-  infoflag = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+  modeinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeInfo;
+  infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
   if (HwDeviceExtension->jChipType < SIS_315H ) {
-  	/* 300 series */
-    	index=(modeinfo>>4)&0xFF;
+    	index = (modeinfo >> 4) & 0xFF;
+#if 0   /* TW: Modes 1280x960 changed number, so this is redundant */
+	mode960low = 0x7c;
+	mode960high = 0x7e;
+#endif
+  } else {
+    	index = (modeinfo >> 8) & 0xFF;
+#if 0   /* TW: In 650 BIOS (LVDS AND 301), 1280x960 modes are 7b-7d! */
+	mode960low = 0x7c;                    /* TW: This is a bug in both BIOS versions ! */
+	mode960high = 0x7e;		      /* TW: Corrected here in LVDS BIOS 1.10.07, but not in tables! */
+#endif
+  }
+
+#if 0
+  /* TW: Not doing this strange stuff makes 1280x960 at least work on CRT1 */
+  if((ModeNo >= mode960low) && (ModeNo <= mode960high)) {
+    	temp = ModeNo - mode960low;
+    	colordepth = ColorDepth[temp];
+    	temp = 0x6b;  /* TW: Why the heck? */
   } else {
-  	/* 310 series */
-    	index=(modeinfo>>8)&0xFF;
+#endif
+        temp = SiS_Pr->SiS_ScreenOffset[index];
+        colordepth = SiS_GetColorDepth(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
+#if 0
   }
-  temp=SiS_ScreenOffset[index];
-  if(infoflag&InterlaceMode){
-    	temp=temp<<1;
-  }
-  colordepth=SiS_GetColorDepth(ROMAddr,ModeNo,ModeIdIndex);
-
-  if((ModeNo>=0x7C)&&(ModeNo<=0x7E)) {
-  	/* TW: For 1280x960 */
-    	temp=ModeNo-0x7C;
-    	colordepth=ColorDepth[temp];
-    	temp=0x6B;
-    	if(infoflag&InterlaceMode){
-      		temp=temp<<1;
-    	}
-   	return(temp*colordepth);
+#endif
+
+  if(infoflag & InterlaceMode) temp <<= 1;
+
+  temp *= colordepth;
+
+  /* TW: For 1400x1050 */
+  if((ModeNo >= 0x26) && (ModeNo <= 0x28)) {
+        colordepth >>= 1;
+	temp += colordepth;
   }
-  else return(temp*colordepth);
+
+  return(temp);
 }
 
+/* TW: Checked with 650/LVDS BIOS */
 USHORT
-SiS_GetColorDepth(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SiS_GetColorDepth(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT ColorDepth[6]={1,2,4,4,6,8};
+  USHORT ColorDepth[6] = { 1, 2, 4, 4, 6, 8};
   SHORT  index;
   USHORT modeflag;
 
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-  }
-  index=(modeflag&ModeInfoFlag)-ModeEGA;
-  if(index<0) index=0;
+  if(ModeNo <= 0x13)
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  else
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+
+  index = (modeflag & ModeInfoFlag) - ModeEGA;
+  if(index < 0) index = 0;
   return(ColorDepth[index]);
 }
 
+/* TW: Checked against 630/301/301B/LVDS, 650/301LVx/LVDS */
 void
-SiS_SetCRT2Sync(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
-                USHORT RefreshRateTableIndex)
+SiS_SetCRT2Sync(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+                USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT tempah=0,infoflag,flag;
+  USHORT tempah=0,tempbl,infoflag,flag;
+
+  flag = 0;
+  tempbl = 0xC0;
 
-  flag=0;
-  infoflag = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
-  if(SiS_IF_DEF_LVDS==1){
-    if(SiS_VBInfo&SetCRT2ToLCD){
-      tempah=SiS_LCDInfo;
-      if(tempah&LCDSync){
-        flag=1;
+  infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {					/* LVDS */
+
+    if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+      tempah = SiS_Pr->SiS_LCDInfo;
+      if(HwDeviceExtension->jChipType >= SIS_315H) {
+          tempbl = tempah & 0xc0;
+      }
+      if(SiS_Pr->SiS_LCDInfo & LCDSync) {
+          flag = 1;
       }
     }
-  }
-  if(flag!=1) tempah=infoflag>>8;
-  tempah=tempah&0xC0;
-  tempah=tempah|0x20;
-  if(!(SiS_LCDInfo&LCDRGB18Bit)) tempah=tempah|0x10;
-  if(SiS_IF_DEF_CH7005==1) tempah=tempah|0xC0;
-  SiS_SetRegANDOR(SiS_Part1Port,0x19,0x3F,tempah);
+    if(flag != 1) tempah = infoflag >> 8;
+    tempah &= 0xC0;
+    tempah |= 0x20;
+    if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
+
+    if (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+		/* TW: BIOS does something here @@@ */
+    }
+
+    tempah &= 0x3f;
+    tempah |= tempbl;
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+
+  } else {
+
+     if(HwDeviceExtension->jChipType < SIS_315H) {
+
+        if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {			/* 630 - 301B */
+
+            if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+               tempah = SiS_Pr->SiS_LCDInfo;
+	       if(SiS_Pr->SiS_LCDInfo & LCDSync) {
+                  flag = 1;
+               }
+            }
+            if(flag != 1) tempah = infoflag >> 8;
+            tempah &= 0xC0;
+            tempah |= 0x20;
+
+            if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
+
+            if (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+	       	/* TW: BIOS does something here @@@ */
+            }
+
+ 	    tempah &= 0x3f;
+  	    tempah |= tempbl;
+            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+
+         } else {							/* 630 - 301 */
+
+            if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+               tempah = SiS_Pr->SiS_LCDInfo;
+	       if(SiS_Pr->SiS_LCDInfo & LCDNonExpandingShift) { /* ! */
+	          flag = 1;
+	       }
+            }
+            if(flag != 1) tempah = infoflag >> 8;
+            tempah &= 0xC0;
+            tempah |= 0x30;
+            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x3F,tempah);
+
+         }
+
+      } else {
+
+         if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {			/* 310/325 - 301B et al */
+
+            tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
+            tempah &= 0xC0;
+            tempah |= 0x20;
+            if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
+            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+
+         } else {							/* 310/325 - 301 */
+
+            tempah = infoflag >> 8;
+            tempah &= 0xC0;
+            tempah |= 0x20;
+
+            if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
+
+            if (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+		/* TW: BIOS does something here @@@ */
+            }
+
+            tempah &= 0x3f;
+            tempah |= tempbl;
+            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+
+         }
+      }
+   }
 }
 
+/* TW: Set FIFO on 630/730 - not to be called on SiS300 */
+/* TW: Checked against 630/301B BIOS; does not set PCI registers */
 void
-SiS_SetCRT2FIFO(USHORT  SiS_Part1Port,ULONG ROMAddr,USHORT ModeNo,
-                PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
+                    PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT temp,index;
   USHORT modeidindex,refreshratetableindex;
   USHORT VCLK,MCLK,colorth=0,data2;
   ULONG  data,eax;
-  UCHAR  LatencyFactor[] ={
+  UCHAR  LatencyFactor[] = {
   	97, 88, 86, 79, 77, 00,       /*; 64  bit    BQ=2   */
         00, 87, 85, 78, 76, 54,       /*; 64  bit    BQ=1   */
         97, 88, 86, 79, 77, 00,       /*; 128 bit    BQ=2   */
@@ -1341,292 +2071,352 @@
         86, 77, 75, 68, 66, 00,       /*; 128 bit    BQ=2   */
         00, 68, 66, 59, 57, 37};      /*; 128 bit    BQ=1   */
 
-  SiS_SearchModeID(ROMAddr,ModeNo,&modeidindex);
-  SiS_SetFlag=SiS_SetFlag&(~ProgrammingCRT2);
-  SiS_SelectCRT2Rate=0;
-  refreshratetableindex=SiS_GetRatePtrCRT2(ROMAddr,ModeNo,modeidindex);   /* 11.GetRatePtr */
-  if(ModeNo>=0x13) {
-    index=SiS_RefIndex[refreshratetableindex].Ext_CRTVCLK;
-    index=index&0x3F;
-    VCLK=SiS_VCLKData[index].CLOCK;           /* Get VCLK  */
-    index=SiS_GetReg1(SiS_P3c4,0x1A);
-    index=index&07;
-    MCLK=SiS_MCLKData[index].CLOCK;           /* Get MCLK  */
-    data2=SiS_ModeType-0x02;
+  SiS_SearchModeID(SiS_Pr,ROMAddr,&ModeNo,&modeidindex);
+  SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
+  SiS_Pr->SiS_SelectCRT2Rate = 0;
+  refreshratetableindex = SiS_GetRatePtrCRT2(SiS_Pr,ROMAddr,ModeNo,modeidindex,HwDeviceExtension);
+
+  if(ModeNo >= 0x13) {
+    index = SiS_Pr->SiS_RefIndex[refreshratetableindex].Ext_CRTVCLK;
+    index &= 0x3F;
+    VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
+    index = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
+    index &= 0x07;
+    MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK;
+    data2 = SiS_Pr->SiS_ModeType - 0x02;
     switch (data2) {
-      case 0 : 	colorth=1; break;
-      case 1 : 	colorth=1; break;
-      case 2 : 	colorth=2; break;
-      case 3 : 	colorth=2; break;
-      case 4 : 	colorth=3; break;
-      case 5 : 	colorth=4; break;
+      case 0 : 	colorth = 1; break;
+      case 1 : 	colorth = 1; break;
+      case 2 : 	colorth = 2; break;
+      case 3 : 	colorth = 2; break;
+      case 4 : 	colorth = 3; break;
+      case 5 : 	colorth = 4; break;
     }
-    /* data2=(data2*VCLK)/MCLK;   */  /*  bx */
-    data2=(colorth*VCLK)/MCLK;  /* TW */
+    data2 = (colorth * VCLK) / MCLK;  
 
-    temp = SiS_GetReg1(SiS_P3c4,0x14);
+    temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
     temp = ((temp&0x00FF)>>6)<<1;
-    if(temp==0) temp=1;
-    temp=temp<<2;
+    if(temp == 0) temp=1;
+    temp <<= 2;
 
-    data2=temp-data2;
+    data2 = temp - data2;
 
-/*  if(data2%(28*16)) {		 TW: WRONG
-      	data2=data2/(28*16);
+    if((28*16) % data2) {
+      	data2 = (28 * 16) / data2;
       	data2++;
     } else {
-      	data2=data2/(28*16);
-    } */
-    if((28*16)%data2) {		/* TW */
-      	data2=(28*16)/data2;
-      	data2++;
-    } else {
-      	data2=(28*16)/data2;
+      	data2 = (28 * 16) / data2;
     }
 
-    index=0;
-    temp = SiS_GetReg1(SiS_P3c4,0x14);
-    if(temp&0x0080) index=index+12;
+    index = 0;
+    temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+    if(temp & 0x0080) index += 12;
 
+#ifndef LINUX_XF86
     SiS_SetReg4(0xcf8,0x800000A0);
     eax=SiS_GetReg3(0xcfc);
+#else
+  /* TW: We use pci functions X offers. We use tag 0, because
+   * we want to read/write to the host bridge (which is always
+   * 00:00.0 on 630, 730 and 540), not the VGA device.
+   */
+    eax = pciReadLong(0x00000000, 0xA0);
+#endif
     temp=(USHORT)(eax>>24);
-    if(!(temp&0x01)) index=index+24;
+    if(!(temp&0x01)) index += 24;
 
+#ifndef LINUX_XF86
     SiS_SetReg4(0xcf8,0x80000050);
     eax=SiS_GetReg3(0xcfc);
-    temp=(USHORT)(eax>>24);
-    if(temp&0x01) index=index+6;
+#else
+    eax = pciReadLong(0x00000000, 0x50);
+#endif
+    temp=(USHORT)(eax >> 24);
+    if(temp & 0x01) index += 6;
 
-    temp=(temp&0x0F)>>1;
-    index=index+temp;
-    data=LatencyFactor[index];
-    data=data+15;
-    temp = SiS_GetReg1(SiS_P3c4,0x14);
-    if(!(temp&0x80)) data=data+5;
-
-    data=data+data2;
-
-    SiS_SetFlag=SiS_SetFlag|ProgrammingCRT2;
-    data=data*VCLK*colorth;
-    if(data%(MCLK<<4)) {
-      	data=data/(MCLK<<4);
+    temp = (temp & 0x0F) >> 1;
+    index += temp;
+    data = LatencyFactor[index];
+    data += 15;
+    temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+    if(!(temp & 0x80)) data += 5;
+
+    data += data2;
+
+    SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+
+    data = data * VCLK * colorth;
+    if(data % (MCLK << 4)) {
+      	data = data / (MCLK << 4);
       	data++;
     } else {
-      	data=data/(MCLK<<4);
+      	data = data / (MCLK << 4);
     }
 
-/* TW: The following made all the calculations above void... */
-
-#if 0
-    temp=0x16;
-/*  Revision ID  */
-    temp=0x13;
-/*  Revision ID  */
-    SiS_SetRegANDOR(SiS_Part1Port,0x01,~0x01F,temp);
-    SiS_SetRegANDOR(SiS_Part1Port,0x02,~0x01F,temp);
-#endif
-
-   /* TW: We do this instead: */
-
-   temp = SiS_GetReg1(SiS_Part1Port,0x01);
-   if( (HwDeviceExtension->jChipType == SIS_630 ) &&
-	    ((HwDeviceExtension->jChipRevision & 0xf0) == 0x30) ) /* 630s */
-   {
-	temp = (temp & (~0x1F)) | 0x1b;  	/* TW: VESA sets 1b, prev. 0x19 */
-   } else {
+    /* TW: Inserted this entire section */
+    temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x01);
+    if( ( (HwDeviceExtension->jChipType == SIS_630) ||
+         (HwDeviceExtension->jChipType == SIS_730) ) &&
+       (HwDeviceExtension->jChipRevision >= 0x30) ) /* 630s or 730(s?) */
+    {
+	temp = (temp & (~0x1F)) | 0x1b;
+    } else {
 	temp = (temp & (~0x1F)) | 0x16;
-   }
-   SiS_SetReg1(SiS_Part1Port,0x01,temp);  	/* FIFO HIGH? */
+    }
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0xe0,temp);
 
-   if(data <= 6) data = 6;
-   if(data > 0x14) data = 0x14;
-   if (SiS_IF_DEF_LVDS==1) {			/* TW: LVDS doesn't like 0x14 */
-	if(data > 0x13) data = 0x13;
-   }
-   SiS_SetRegANDOR(SiS_Part1Port,0x02,~0x01F,data);  /* FIFO LOW? */
-  /* TW end */
+    if(data <= 6) data = 6;
+    if(data > 0x14) data = 0x14;
+    if( (HwDeviceExtension->jChipType == SIS_630) &&
+        (HwDeviceExtension->jChipRevision >= 0x30) ) /* 630s, NOT 730 */
+    {
+   	if(data > 0x13) data = 0x13;
+    }
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,~0x01F,data);
+   /* TW end */
   }
 }
 
+/* TW: Set FIFO on 310 series */
+#ifdef SIS315H
 void
-SiS_SetCRT2FIFO2(USHORT SiS_Part1Port,ULONG ROMAddr,USHORT ModeNo,
-                 PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
+                    PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-#ifdef SIS315H
- UCHAR CombCode[]={1,1,1,4,3,1,3,4,4,1,4,4,5,1,5,4};
- UCHAR CRT2ThLow[]={39,63,55,79,78,102,90,114,55,87,84,116,103,135,119,151};
-#endif
-  USHORT temp,temp1,temp2,temp3;
+
+  UCHAR CombCode[]  = { 1, 1, 1, 4, 3, 1, 3, 4,
+                        4, 1, 4, 4, 5, 1, 5, 4};
+  UCHAR CRT2ThLow[] = { 39, 63, 55, 79, 78,102, 90,114,
+                        55, 87, 84,116,103,135,119,151};
+  USHORT temp3,tempax,tempbx,tempcx;
+  USHORT tempcl, tempch;
   USHORT index;
   USHORT CRT1ModeNo,CRT2ModeNo;
   USHORT ModeIdIndex;
   USHORT RefreshRateTableIndex;
+  USHORT SelectRate_backup;
+
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x01,0x3B);
+
+  CRT1ModeNo = SiS_Pr->SiS_CRT1Mode;                             /* get CRT1 ModeNo */
+  SiS_SearchModeID(SiS_Pr,ROMAddr,&CRT1ModeNo,&ModeIdIndex);
 
-  SiS_SetReg1(SiS_Part1Port,0x1,0x3B);
-  /* CRT1ModeNo=(UCHAR)SiS_GetReg1(SiS_P3d4,0x34); *//* get CRT1 ModeNo */
-  CRT1ModeNo = SiS_CRT1Mode;
-  /* CRT1ModeNo =ModeNo; */
-  SiS_SearchModeID(ROMAddr,CRT1ModeNo,&ModeIdIndex);    /* Get ModeID Table */
-  SiS_SetFlag=SiS_SetFlag& (~ProgrammingCRT2);
-
-  RefreshRateTableIndex=SiS_GetRatePtrCRT2(ROMAddr,CRT1ModeNo,
-                            ModeIdIndex); /* Set REFIndex-> for crt1 refreshrate */
-  index = SiS_GetVCLK2Ptr(ROMAddr,CRT1ModeNo,ModeIdIndex,
+  SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
+  SelectRate_backup = SiS_Pr->SiS_SelectCRT2Rate;
+  SiS_Pr->SiS_SelectCRT2Rate = 0;
+
+  /* Set REFIndex for crt1 refreshrate */
+  RefreshRateTableIndex = SiS_GetRatePtrCRT2(SiS_Pr,ROMAddr,CRT1ModeNo,
+                                             ModeIdIndex,HwDeviceExtension);
+
+  index = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,CRT1ModeNo,ModeIdIndex,
                           RefreshRateTableIndex,HwDeviceExtension);
-  temp1=SiS_VCLKData[index].CLOCK;           /* Get VCLK  */
+  tempax = SiS_Pr->SiS_VCLKData[index].CLOCK;                         /* Get DCLK (VCLK?) */
 
-  temp2= SiS_GetColorDepth(ROMAddr,CRT1ModeNo,ModeIdIndex);
-#ifdef SIS315H
-  index = SiS_Get310DRAMType(ROMAddr);
+  tempbx = SiS_GetColorDepth(SiS_Pr,ROMAddr,CRT1ModeNo,ModeIdIndex); /* Get colordepth */
+  tempbx >>= 1;
+  if(!tempbx) tempbx++;
+
+  tempax *= tempbx;
+
+  tempbx = SiS_GetMCLK(SiS_Pr,ROMAddr, HwDeviceExtension);     /* Get MCLK */
+
+  tempax /= tempbx;
+
+  tempbx = tempax;
+
+#if 0 /* TW: BIOS code is skrewed */
+  if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14) & 0x02) {
+   	tempax = 16;
+  } else {
+    	tempax = 8;
+  }
 #endif
-  temp3=SiS_MCLKData[index].CLOCK;           /* Get MCLK  */
+  tempax = 16;
 
-  temp=SiS_GetReg1(SiS_P3c4,0x14);
-  if (temp&0x02)
-   	temp=16;
-  else
-    	temp=8;
+  tempax -= tempbx;
 
-  temp = temp - temp1*temp2/temp3; /* 16-DRamBus - DCLK*BytePerPixel/MCLK */
+  tempbx = tempax;    /* tempbx = 16-DRamBus - DCLK*BytePerPixel/MCLK */
 
-  if ((52*16 % temp)==0)
-    	temp = 52*16/temp +40;
-  else
-    	temp = 52*16/temp +40 + 1;
+  tempax = ((52 * 16) / tempbx);
+
+  if ((52*16 % tempbx) != 0) {
+    	tempax++;
+  }
+  tempcx = tempax;
+  tempcx += 40;
 
   /* get DRAM latency */
-  temp1=(SiS_GetReg1(SiS_P3c4,0x17)>>3)&0x7; /* SR17[5:3] DRAM Queue depth */
-  temp2=(SiS_GetReg1(SiS_P3c4,0x17)>>6)&0x3; /* SR17[7:6] DRAM Grant length */
+  tempcl = (SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) >> 3) & 0x7;     /* SR17[5:3] DRAM Queue depth */
+  tempch = (SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) >> 6) & 0x3;     /* SR17[7:6] DRAM Grant length */
 
-#ifdef SIS315H
-  if (SiS_Get310DRAMType(ROMAddr)<2)
-  {
-    for (temp3=0;temp3<16;temp3+=2)
-    {
-      if ((CombCode[temp3]==temp1) && (CombCode[temp3+1]==temp2))
-      {
-        temp3 = CRT2ThLow[temp3>>1];
-      }
-    }
-  }
-  else
-  {
-    for (temp3=0;temp3<16;temp3+=2)
-    {
-      if ((CombCode[temp3]==temp1) && (CombCode[temp3+1]==temp2))
-      {
-        temp3 = CRT2ThLow[8+(temp3>>1)];
-      }
+  for (temp3 = 0; temp3 < 16; temp3 += 2) {
+    if ((CombCode[temp3] == tempcl) && (CombCode[temp3+1] == tempch)) {
+      temp3 = CRT2ThLow[temp3 >> 1];
     }
   }
-#endif
 
-  temp +=  temp3; /* CRT1 Request Period */
+  tempcx +=  temp3;                                      /* CRT1 Request Period */
+
+  CRT2ModeNo = ModeNo;                                   /* get CRT2 ModeNo */
+  SiS_SearchModeID(SiS_Pr,ROMAddr,&CRT2ModeNo,&ModeIdIndex);    /* Get ModeID Table */
+
+  SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+  SiS_Pr->SiS_SelectCRT2Rate = SelectRate_backup;
+
+  RefreshRateTableIndex=SiS_GetRatePtrCRT2(SiS_Pr,ROMAddr,CRT1ModeNo,
+                                           ModeIdIndex,HwDeviceExtension);
 
-  CRT2ModeNo = ModeNo; /* get CRT2 ModeNo */
-  SiS_SearchModeID(ROMAddr,CRT2ModeNo,&ModeIdIndex);    /* Get ModeID Table */
-  SiS_SetFlag=SiS_SetFlag|ProgrammingCRT2;
-  RefreshRateTableIndex=SiS_GetRatePtrCRT2(ROMAddr,CRT1ModeNo,
-                        ModeIdIndex);/* Set REFIndex-> for crt1 refreshrate */
-  index = SiS_GetVCLK2Ptr(ROMAddr,CRT2ModeNo,ModeIdIndex,
+  index = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,CRT2ModeNo,ModeIdIndex,
                           RefreshRateTableIndex,HwDeviceExtension);
-  temp1=SiS_VCLKData[index].CLOCK;           /* Get VCLK  */
+  tempax = SiS_Pr->SiS_VCLKData[index].CLOCK;                          /* Get VCLK  */
 
-  temp2= SiS_GetColorDepth(ROMAddr,CRT2ModeNo,ModeIdIndex);
-#ifdef SIS315H
-  index = SiS_Get310DRAMType(ROMAddr);
-#endif
-  temp3=SiS_MCLKData[index].CLOCK;           /* Get MCLK  */
- 
-  if ((temp*temp1*temp2)%(16*temp3)==0)
-    temp = temp*temp1*temp2/(16*temp3);   /* CRT1 Request period * TCLK*BytePerPixel/(MCLK*16) */
-  else 
-    temp = temp*temp1*temp2/(16*temp3)+1; /* CRT1 Request period * TCLK*BytePerPixel/(MCLK*16) */
+  tempbx = SiS_GetColorDepth(SiS_Pr,ROMAddr,CRT2ModeNo,ModeIdIndex);  /* Get colordepth */
+  tempbx >>= 1;
+  if(!tempbx) tempbx++;
 
-  if (temp>0x37)
-    temp = 0x37;
+  tempax *= tempbx;
 
-  SiS_SetRegANDOR(SiS_Part1Port,0x02,~0x3F,temp);
-}
+  tempax *= tempcx;
 
-void
-SiS_GetLVDSDesData(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                   USHORT RefreshRateTableIndex)
+  tempbx = SiS_GetMCLK(SiS_Pr,ROMAddr, HwDeviceExtension);	       /* Get MCLK */
+  tempbx <<= 4;
+
+  tempcx = tempax;
+  tempax /= tempbx;
+  if(tempcx % tempbx) tempax++;		/* CRT1 Request period * TCLK * BytePerPixel / (MCLK*16) */
+
+  if (tempax > 0x37)  tempax = 0x37;
+
+  /* TW: 650/LVDS (1.10.07, 1.10.00), 650/301LV overrule calculated value; 315 does not */
+  if(HwDeviceExtension->jChipType == SIS_650) {
+  	tempax = 0x04;
+  }
+
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,~0x3F,tempax);
+}
+
+USHORT
+SiS_GetMCLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT index;
+
+  index = SiS_Get310DRAMType(SiS_Pr,ROMAddr,HwDeviceExtension);
+  if(index >= 4) {
+    index -= 4;
+    return(SiS_Pr->SiS_MCLKData_1[index].CLOCK);
+  } else {
+    return(SiS_Pr->SiS_MCLKData_0[index].CLOCK);
+  }
+}
+#endif
+
+/* TW: Checked against 650/LVDS 1.10.07 BIOS */
+void
+SiS_GetLVDSDesData(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                   USHORT RefreshRateTableIndex,
+		   PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT modeflag;
   USHORT PanelIndex,ResIndex;
-  SiS_LVDSDesStruct  *PanelDesPtr=NULL;
+  const  SiS_LVDSDesStruct *PanelDesPtr = NULL;
 
-  if((SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-       && (SiS_IF_DEF_LVDS == 0) ) {  /*301b*//*for test*/
-     SiS_GetLVDSDesPtrA(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+  if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) ) {
+
+     SiS_GetLVDSDesPtrA(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
                         &PanelIndex,&ResIndex);
      switch (PanelIndex)
      {
-     	case  0: PanelDesPtr = LVDS1024x768Des_1;   break;
-     	case  1: PanelDesPtr = LVDS1280x1024Des_1;  break;
-     	case  2: PanelDesPtr = LVDS1280x960Des_1;   break;
-     	case  3: PanelDesPtr = LVDS1024x768Des_2;   break;
-     	case  4: PanelDesPtr = LVDS1280x1024Des_2;  break;
-     	case  5: PanelDesPtr = LVDS1280x960Des_2;   break;
+     	case  0: PanelDesPtr = SiS_Pr->LVDS1024x768Des_1;   break;  /* --- expanding --- */
+     	case  1: PanelDesPtr = SiS_Pr->LVDS1280x1024Des_1;  break;
+	case  2: PanelDesPtr = SiS_Pr->LVDS1400x1050Des_1;  break;
+	case  3: PanelDesPtr = SiS_Pr->LVDS1600x1200Des_1;  break;
+     	case  4: PanelDesPtr = SiS_Pr->LVDS1024x768Des_2;   break;  /* --- non expanding --- */
+     	case  5: PanelDesPtr = SiS_Pr->LVDS1280x1024Des_2;  break;
+	case  6: PanelDesPtr = SiS_Pr->LVDS1400x1050Des_2;  break;
+	case  7: PanelDesPtr = SiS_Pr->LVDS1600x1200Des_2;  break;
      }
+
   } else {
-     SiS_GetLVDSDesPtr(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                       &PanelIndex,&ResIndex);
-#ifdef LINUX_KERNEL
-     if (PanelIndex < 32)	/* >=32 = TV */
-         printk(KERN_INFO "sisfb: LVDS-LCD panel type %d (Resindex %d)\n", PanelIndex, ResIndex);
-#endif
+
+     SiS_GetLVDSDesPtr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                       &PanelIndex,&ResIndex,HwDeviceExtension);
+
      switch (PanelIndex)
      {
-     	case  0: PanelDesPtr = SiS_PanelType00_1;   break;
-     	case  1: PanelDesPtr = SiS_PanelType01_1;   break;
-     	case  2: PanelDesPtr = SiS_PanelType02_1;   break;
-     	case  3: PanelDesPtr = SiS_PanelType03_1;   break;
-     	case  4: PanelDesPtr = SiS_PanelType04_1;   break;
-     	case  5: PanelDesPtr = SiS_PanelType05_1;   break;
-     	case  6: PanelDesPtr = SiS_PanelType06_1;   break;
-     	case  7: PanelDesPtr = SiS_PanelType07_1;   break;
-     	case  8: PanelDesPtr = SiS_PanelType08_1;   break;
-     	case  9: PanelDesPtr = SiS_PanelType09_1;   break;
-     	case 10: PanelDesPtr = SiS_PanelType0a_1;   break;
-     	case 11: PanelDesPtr = SiS_PanelType0b_1;   break;
-     	case 12: PanelDesPtr = SiS_PanelType0c_1;   break;	/* TW: Clevo 2202   */
-     	case 13: PanelDesPtr = SiS_PanelType0d_1;   break;
-     	case 14: PanelDesPtr = SiS_PanelType0e_1;   break;	/* TW: Uniwill N271S2 */
-     	case 15: PanelDesPtr = SiS_PanelType0f_1;   break;
-     	case 16: PanelDesPtr = SiS_PanelType00_2;   break;
-     	case 17: PanelDesPtr = SiS_PanelType01_2;   break;
-     	case 18: PanelDesPtr = SiS_PanelType02_2;   break;
-     	case 19: PanelDesPtr = SiS_PanelType03_2;   break;
-     	case 20: PanelDesPtr = SiS_PanelType04_2;   break;
-     	case 21: PanelDesPtr = SiS_PanelType05_2;   break;
-     	case 22: PanelDesPtr = SiS_PanelType06_2;   break;
-     	case 23: PanelDesPtr = SiS_PanelType07_2;   break;
-     	case 24: PanelDesPtr = SiS_PanelType08_2;   break;
-     	case 25: PanelDesPtr = SiS_PanelType09_2;   break;
-     	case 26: PanelDesPtr = SiS_PanelType0a_2;   break;
-     	case 27: PanelDesPtr = SiS_PanelType0b_2;   break;
-     	case 28: PanelDesPtr = SiS_PanelType0c_2;   break;
-     	case 29: PanelDesPtr = SiS_PanelType0d_2;   break;
-     	case 30: PanelDesPtr = SiS_PanelType0e_2;   break;
-     	case 31: PanelDesPtr = SiS_PanelType0f_2;   break;
-     	case 32: PanelDesPtr = SiS_CHTVUNTSCDesData;   break;
-     	case 33: PanelDesPtr = SiS_CHTVONTSCDesData;   break;
-     	case 34: PanelDesPtr = SiS_CHTVUPALDesData;    break;
-     	case 35: PanelDesPtr = SiS_CHTVOPALDesData;    break;
-     }
-  }
-  SiS_LCDHDES = (PanelDesPtr+ResIndex)->LCDHDES;
-  SiS_LCDVDES = (PanelDesPtr+ResIndex)->LCDVDES;
-
-  if(SiS_LCDInfo&LCDNonExpanding){
-    if(SiS_LCDResInfo>=Panel1024x768){
-      if(ModeNo<=0x13){
-        modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-        if(!(modeflag&HalfDCLK)) {
-          SiS_LCDHDES=320;
+     	case  0: PanelDesPtr = SiS_Pr->SiS_PanelType00_1;   break; /* --- expanding --- | Gericom 1st supersonic (310) */
+     	case  1: PanelDesPtr = SiS_Pr->SiS_PanelType01_1;   break;
+     	case  2: PanelDesPtr = SiS_Pr->SiS_PanelType02_1;   break;
+     	case  3: PanelDesPtr = SiS_Pr->SiS_PanelType03_1;   break;
+     	case  4: PanelDesPtr = SiS_Pr->SiS_PanelType04_1;   break;
+     	case  5: PanelDesPtr = SiS_Pr->SiS_PanelType05_1;   break;
+     	case  6: PanelDesPtr = SiS_Pr->SiS_PanelType06_1;   break;
+     	case  7: PanelDesPtr = SiS_Pr->SiS_PanelType07_1;   break;
+     	case  8: PanelDesPtr = SiS_Pr->SiS_PanelType08_1;   break;
+     	case  9: PanelDesPtr = SiS_Pr->SiS_PanelType09_1;   break;
+     	case 10: PanelDesPtr = SiS_Pr->SiS_PanelType0a_1;   break;
+     	case 11: PanelDesPtr = SiS_Pr->SiS_PanelType0b_1;   break;
+     	case 12: PanelDesPtr = SiS_Pr->SiS_PanelType0c_1;   break;	/* TW: Clevo 2202 (300)  */
+     	case 13: PanelDesPtr = SiS_Pr->SiS_PanelType0d_1;   break;
+     	case 14: PanelDesPtr = SiS_Pr->SiS_PanelType0e_1;   break;	/* TW: Uniwill N271S2 (300) */
+     	case 15: PanelDesPtr = SiS_Pr->SiS_PanelType0f_1;   break;
+     	case 16: PanelDesPtr = SiS_Pr->SiS_PanelType00_2;   break;  /* --- non-expanding --- */
+     	case 17: PanelDesPtr = SiS_Pr->SiS_PanelType01_2;   break;
+     	case 18: PanelDesPtr = SiS_Pr->SiS_PanelType02_2;   break;
+     	case 19: PanelDesPtr = SiS_Pr->SiS_PanelType03_2;   break;
+     	case 20: PanelDesPtr = SiS_Pr->SiS_PanelType04_2;   break;
+     	case 21: PanelDesPtr = SiS_Pr->SiS_PanelType05_2;   break;
+     	case 22: PanelDesPtr = SiS_Pr->SiS_PanelType06_2;   break;
+     	case 23: PanelDesPtr = SiS_Pr->SiS_PanelType07_2;   break;
+     	case 24: PanelDesPtr = SiS_Pr->SiS_PanelType08_2;   break;
+     	case 25: PanelDesPtr = SiS_Pr->SiS_PanelType09_2;   break;
+     	case 26: PanelDesPtr = SiS_Pr->SiS_PanelType0a_2;   break;
+     	case 27: PanelDesPtr = SiS_Pr->SiS_PanelType0b_2;   break;
+     	case 28: PanelDesPtr = SiS_Pr->SiS_PanelType0c_2;   break;     /* TW: Gericom 2200C (300) */
+     	case 29: PanelDesPtr = SiS_Pr->SiS_PanelType0d_2;   break;
+     	case 30: PanelDesPtr = SiS_Pr->SiS_PanelType0e_2;   break;
+     	case 31: PanelDesPtr = SiS_Pr->SiS_PanelType0f_2;   break;
+     	case 32: PanelDesPtr = SiS_Pr->SiS_CHTVUNTSCDesData;   break;
+     	case 33: PanelDesPtr = SiS_Pr->SiS_CHTVONTSCDesData;   break;
+     	case 34: PanelDesPtr = SiS_Pr->SiS_CHTVUPALDesData;    break;
+     	case 35: PanelDesPtr = SiS_Pr->SiS_CHTVOPALDesData;    break;
+     }
+  }
+  SiS_Pr->SiS_LCDHDES = (PanelDesPtr+ResIndex)->LCDHDES;
+  SiS_Pr->SiS_LCDVDES = (PanelDesPtr+ResIndex)->LCDVDES;
+
+  if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding){
+    if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+      if(ModeNo <= 0x13) {
+        modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+	if(!(modeflag & HalfDCLK)) {
+	  SiS_Pr->SiS_LCDHDES = 632;
+	}
+      }
+    } else {
+      if(!(SiS_Pr->SiS_SetFlag & CRT2IsVGA)) {
+        if((HwDeviceExtension->jChipType < SIS_315H) || (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024)) {  /* TW: New from 650/LVDS 1.10.07 */
+          if(SiS_Pr->SiS_LCDResInfo >= SiS_Pr->SiS_Panel1024x768){
+            if(ModeNo <= 0x13) {
+	      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+	      if(HwDeviceExtension->jChipType < SIS_315H) {
+	         if(!(modeflag & HalfDCLK)) {
+                     SiS_Pr->SiS_LCDHDES = 320;
+		 }
+	      } else {
+	         /* TW: New from 650/LVDS 1.10.07 */
+	         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)
+	             SiS_Pr->SiS_LCDHDES = 480;
+                 if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)
+	             SiS_Pr->SiS_LCDHDES = 804;
+                 if(!(modeflag & HalfDCLK)) {
+                     SiS_Pr->SiS_LCDHDES = 320;
+	             if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)
+	                SiS_Pr->SiS_LCDHDES = 632;
+                 }
+              }
+            }
+          }
         }
       }
     }
@@ -1634,3597 +2424,6375 @@
   return;
 }
 
+/* TW: Checked against 630/LVDS (2.04.5c) and 650/LVDS (1.10.07) BIOS */
 void
-SiS_GetLVDSDesPtr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+SiS_GetLVDSDesPtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                   USHORT RefreshRateTableIndex,USHORT *PanelIndex,
-		  USHORT *ResIndex)
+		  USHORT *ResIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT tempbx,tempal;
+  USHORT tempbx,tempal,modeflag;
+
+  if(ModeNo<=0x13) {
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+	tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+  }
+
+  tempbx = 0;
+  if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+    if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+      tempbx = 32;
+      if(SiS_Pr->SiS_VBInfo & SetPALTV) tempbx += 2;
+      if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
+    }
+  }
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+    tempbx = SiS_Pr->SiS_LCDTypeInfo;
+    if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx += 16;
+    /* TW: Inserted from 650/LVDS (1.10.07) BIOS */
+    if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+       if(modeflag & HalfDCLK) tempbx += 16;
+    }
+  }
+  /* TW: Inserted from 630/LVDS and 650/LVDS (1.10.07) BIOS */
+  if(SiS_Pr->SiS_SetFlag & CRT2IsVGA) {
+    if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)  {
+       tempal = 0x07;
+       if(HwDeviceExtension->jChipType < SIS_315H) {
+          if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x80) tempal++;
+       }
+    }
+  }
 
-  tempbx=0;
-  if(SiS_IF_DEF_CH7005==1) {
-    if(!(SiS_VBInfo&SetCRT2ToLCD)) {
-      tempbx=32;
-      if(SiS_VBInfo&SetPALTV) tempbx=tempbx+2;
-      if(SiS_VBInfo&SetCHTVOverScan) tempbx=tempbx+1;
-    }
-  } 
-  if(SiS_VBInfo&SetCRT2ToLCD) {
-    tempbx=SiS_LCDTypeInfo;
-    if(SiS_LCDInfo&LCDNonExpanding){
-      tempbx=tempbx+16;
-    }
-  }
-  if(ModeNo<=0x13){
-    	tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  }else{
-    	tempal = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-  }
-  tempal=tempal&0x1F;
-  *PanelIndex=tempbx;
-  *ResIndex=tempal;
+  *PanelIndex = tempbx;
+  *ResIndex = tempal & 0x1F;
 }
 
-/*301b*/
 void
-SiS_GetLVDSDesPtrA(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+SiS_GetLVDSDesPtrA(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                    USHORT RefreshRateTableIndex,USHORT *PanelIndex,
 		   USHORT *ResIndex)
 {
   USHORT tempbx=0,tempal;
 
-  tempbx=SiS_LCDResInfo-Panel1024x768;
-  if(SiS_LCDInfo&LCDNonExpanding){
-      tempbx=tempbx+3;
-  }
+  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+       tempbx = 3;
+  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
+       tempbx = 4;
+  } else tempbx = SiS_Pr->SiS_LCDResInfo - SiS_Pr->SiS_PanelMinLVDS;
 
-  if(ModeNo<=0x13){
-    	tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  } else {
-    	tempal = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-  }
-  tempal=tempal&0x1F;
-  *PanelIndex=tempbx;
-  *ResIndex=tempal;
+  if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)  tempbx += 4;
+
+  if(ModeNo<=0x13)
+    	tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  else
+    	tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+
+  *PanelIndex = tempbx;
+  *ResIndex = tempal & 0x1F;
 }
-/*end 301b*/
 
+/* TW: Checked against 650/LVDS (1.10.07), 650/301LV, 650/301LVx (!), 630/301 and 630/301B (II) BIOS */
 void
-SiS_SetCRT2ModeRegs(USHORT BaseAddr,USHORT ModeNo,
+SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT BaseAddr, USHORT ModeNo, USHORT ModeIdIndex,
                     PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT i,j;
-  USHORT tempcl,tempah;
+  USHORT i,j,modeflag;
+  USHORT tempcl,tempah,tempbl,temp;
+
+  if(ModeNo<=0x13) {
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  }
+  
+  /* TW: BIOS does not do this (neither 301 nor LVDS) */
+  /*     (But it's harmless; see SetCRT2Offset) */
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x03,0x00);   /* fix write part1 index 0  BTDRAM bit Bug */
 
-  SiS_SetReg1(SiS_Part1Port,0x03,0x00);   /*fix write part1 index 0  BTDRAM bit Bug*/
+  /* TW: Removed 301B302B301LV302LV check here to match 650/LVDS BIOS */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
 
-  /*301b*/
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-  				&& (SiS_VBInfo&SetCRT2ToLCDA) ) {
+	/* TW:   1. for LVDS/302B/302LV **LCDA** */
 
-	/* TW:   1. for 301B/302B/301LV/302LV (on some of which
-	 *          IF_DEF_LVDS seems to be 1 as well)
-	 */
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xAF,0x40); /* FUNCTION CONTROL */
+      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2E,0xF7);
 
-      SiS_SetRegANDOR(SiS_Part1Port,0x00,~0x050,0x40); /* FUNCTION CONTROL */
-      SiS_SetRegAND(SiS_Part1Port,0x2E,0xF7);
-      SiS_SetRegANDOR(SiS_Part1Port,0x13,0xFB,0x04);
-      SiS_SetRegANDOR(SiS_Part1Port,0x2c,0xCF,0x30);
-      SiS_SetRegANDOR(SiS_Part4Port,0x21,0x3F,0xC0);
-      SiS_SetRegANDOR(SiS_Part4Port,0x23,0x7F,0x00);
-  /*end 301b*/
   } else {
-    for(i=0,j=4;i<3;i++,j++) SiS_SetReg1(SiS_Part1Port,j,0);
 
-    tempcl=SiS_ModeType;
+    for(i=0,j=4; i<3; i++,j++) SiS_SetReg1(SiS_Pr->SiS_Part1Port,j,0);
+
+    tempcl = SiS_Pr->SiS_ModeType;
+
     if(HwDeviceExtension->jChipType < SIS_315H) {
+
       /* ---- 300 series ---- */
-      if(ModeNo>0x13){
-        tempcl=tempcl-ModeVGA;
-        if((tempcl>0)||(tempcl==0)){
-           tempah=((0x010>>tempcl)|0x080);
-        }
-      } else {
-        tempah=0x080;
-      }
-      if(SiS_VBInfo&SetInSlaveMode){
-         tempah=(tempah^0x0A0);
+
+      /* TW: Inserted entire if-section from 630/301B BIOS */
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	  temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32);
+	  temp &= 0xef;
+	  temp |= 0x02;
+	  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+	     temp |= 0x10;
+	     temp &= 0xfd;
+	  }
+	  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
       }
+
+      if(ModeNo > 0x13) {
+        tempcl -= ModeVGA;
+        if((tempcl > 0) || (tempcl == 0)) {      /* TW: tempcl is USHORT -> always true! */
+           tempah = ((0x10 >> tempcl) | 0x80);
+        }
+      } else  tempah = 0x80;
+
+      if(SiS_Pr->SiS_VBInfo & SetInSlaveMode)  tempah ^= 0xA0;
+
     } else {
+
     /* ---- 310 series ---- */
-      if(ModeNo>0x13) {
-        tempcl=tempcl-ModeVGA;
-        if((tempcl>0)||(tempcl==0)){
-           tempah=(0x008>>tempcl);
-           if (tempah==0) tempah=1;
-              tempah |= 0x040;
+
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        if(SiS_Pr->SiS_VBInfo & CRT2DisplayFlag) {
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x08);
         }
-      } else {
-       tempah=0x040;
-      }
-  
-      if(SiS_VBInfo&SetInSlaveMode){
-          tempah=(tempah^0x050);
       }
+
+      if(ModeNo > 0x13) {
+        tempcl -= ModeVGA;
+        if((tempcl > 0) || (tempcl == 0)) {  /* TW: tempcl is USHORT -> always true! */
+           tempah = (0x08 >> tempcl);
+           if (tempah == 0) tempah = 1;
+           tempah |= 0x40;
+        }
+      } else  tempah = 0x40;
+
+      if(SiS_Pr->SiS_VBInfo & SetInSlaveMode)  tempah ^= 0x50;
+
     }
 
-    if(SiS_VBInfo&CRT2DisplayFlag){
-      	tempah=0;
+    if(SiS_Pr->SiS_VBInfo & CRT2DisplayFlag)  tempah = 0;
+
+    if(HwDeviceExtension->jChipType < SIS_315H) {
+        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x00,tempah);  		/* FUNCTION CONTROL */
+    } else {
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xa0,tempah);  	/* FUNCTION CONTROL */
     }
-    SiS_SetReg1(SiS_Part1Port,0x00,tempah);  /* FUNCTION CONTROL */
 
-    if(SiS_IF_DEF_LVDS==0) {    /* ifdef 301*/
+    if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
 
-	/* TW:   2. for 301 */
+	/* TW:   2. for 301 (301B, 302B 301LV, 302LV non-LCDA) */
 
-    	tempah=0x01;
-    	if(!(SiS_VBInfo&SetInSlaveMode)) {
-      		tempah=(tempah|0x02);
+    	tempah = 0x01;
+    	if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+      		tempah |= 0x02;
     	}
-    	if(!(SiS_VBInfo&SetCRT2ToRAMDAC)) {
-      		tempah=(tempah^0x05);
-      		if(!(SiS_VBInfo&SetCRT2ToLCD)) {
-        		tempah=(tempah^0x01);
+    	if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) {
+      		tempah ^= 0x05;
+      		if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+        		tempah ^= 0x01;
       		}
     	}
 
-    	tempcl=tempah;     /* 05/03/01 ynlai for TV display bug */
+	if(SiS_Pr->SiS_VBInfo & CRT2DisplayFlag)  tempah = 0;
 
     	if(HwDeviceExtension->jChipType < SIS_315H) {
-      		/* 300 series */
-      		tempah=(tempah<<5)&0xFF;
-      		if(SiS_VBInfo&CRT2DisplayFlag){
-        		tempah=0;
-      		}
-      		SiS_SetReg1(SiS_Part1Port,0x01,tempah);
 
-      		tempah=tempah>>5;
+		/* --- 300 series --- */
+
+      		tempah = (tempah << 5) & 0xFF;
+      		SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x01,tempah);
+      		tempah = (tempah >> 5) & 0xFF;
+
     	} else {
-      		/* 310 series */
-      		if(SiS_VBInfo&CRT2DisplayFlag){
-        		tempah=0;
-      		}
-      		tempah = (SiS_GetReg1(SiS_Part1Port,0x2E)&0xF8)|tempah;
-      		SiS_SetReg1(SiS_Part1Port,0x2E,tempah);
-      		tempah=tempcl;
-    	}
 
-    	if((SiS_ModeType==ModeVGA)&&(!(SiS_VBInfo&SetInSlaveMode))){
-      		tempah=tempah|0x010;
-    	}
-      
-     	if(SiS_LCDResInfo==Panel1024x768)
-         	tempah=tempah|0x080;
-  
-    	if((SiS_LCDResInfo==Panel1280x1024)||(SiS_LCDResInfo==Panel1280x960)){
-      		tempah=tempah|0x080;
+		/* --- 310 series --- */
+
+      		SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2E,0xF8,tempah);
+
     	}
-    	if(SiS_VBInfo&SetCRT2ToTV){
-      		if(SiS_VBInfo&SetInSlaveMode){
-        		if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {   /*301b*/
-          			if(SiS_SetFlag&TVSimuMode)
-                			tempah=tempah|0x020;
-        		} else
-          			tempah=tempah|0x020;
+
+    	if((SiS_Pr->SiS_ModeType == ModeVGA) && (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))) {
+      		tempah |= 0x10;
+	}
+
+	/* TW: Inserted from 630/301 BIOS */
+	if((HwDeviceExtension->jChipType < SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301)) {
+		if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+			tempah |= 0x80;
+		}
+	} else {
+		tempah |= 0x80;
+	}
+
+    	if(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV - SetCRT2ToHiVisionTV)){
+      		if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+          		tempah |= 0x20;
       		}
     	}
-    	SiS_SetRegANDOR(SiS_Part4Port,0x0D,~0x0BF,tempah);
-    	tempah=0;
-    	if(SiS_VBInfo&SetCRT2ToTV) {
-      		if(SiS_VBInfo&SetInSlaveMode) {
-       			if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) { /*301b*/
-           		{
-            			SiS_SetFlag=SiS_SetFlag|RPLLDIV2XO;
-            			tempah=tempah|0x40;
-          		}
+
+    	SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0D,0x40,tempah);
+
+    	tempah = 0;
+    	if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+      		if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+       			if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+            			SiS_Pr->SiS_SetFlag |= RPLLDIV2XO;
+            			tempah |= 0x40;
        			} else {
-        			if(!(SiS_SetFlag&TVSimuMode)) {
-          				if(!(SiS_VBInfo&SetCRT2ToHiVisionTV)) {
-            					SiS_SetFlag=SiS_SetFlag|RPLLDIV2XO;
-            					tempah=tempah|0x40;
+        			if(!(SiS_Pr->SiS_SetFlag & TVSimuMode)) {
+#ifdef oldHV
+          				if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)) {
+#endif
+            					SiS_Pr->SiS_SetFlag |= RPLLDIV2XO;
+            					tempah |= 0x40;
+#ifdef oldHV
           				}
+#endif
         			}
       			}
-     		}
-      		else {
-        		SiS_SetFlag=SiS_SetFlag|RPLLDIV2XO;
-        		tempah=tempah|0x40;
+     		} else {
+        		SiS_Pr->SiS_SetFlag |= RPLLDIV2XO;
+        		tempah |= 0x40;
       		}
     	}
-    	if(SiS_LCDResInfo==Panel1280x1024) tempah=tempah|0x80;
-    	if(SiS_LCDResInfo==Panel1280x960) tempah=tempah|0x80;
-    	SiS_SetReg1(SiS_Part4Port,0x0C,tempah);
+	/* TW: Inserted from 630/301LVx BIOS 1.10.6s */
+	if(HwDeviceExtension->jChipType >= SIS_315H) {
+	    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	        if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04)
+		    tempah |= 0x40;
+	    }
+	}
+
+	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024 ||
+	            SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
+		tempah |= 0x80;
+	}
+
+    	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0C,tempah);
+
     } else {
 
-    	/* TW: 3. for LVDS, _not_ 301B/302B/301LV/302LV */
+    	/* TW: 3. for LVDS */
 
-    	tempah=0;
+	/* TW: Inserted if-statement - Part1Port 0x2e not assigned on 300 series */
+	if(HwDeviceExtension->jChipType >= SIS_315H) {
+
+	   /* TW: Inserted this entire section (BIOS 650/LVDS); added ModeType check
+	    *     (LVDS can only be slave in 8bpp modes)
+	    */
+	   tempah = 0x80;
+	   if( (modeflag & CRT2Mode) && (SiS_Pr->SiS_ModeType > ModeVGA) ) {
+	       if (SiS_Pr->SiS_VBInfo & DriverMode) {
+	           tempah |= 0x02;
+	       }
+	   }
+
+	   if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+               tempah |= 0x02;
+    	   }
+
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+	       tempah ^= 0x01;
+	   }
+
+	   if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) {
+	       tempah = 1;
+	   }
+
+    	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2e,0xF0,tempah);
+
+	} else {
+
+	   /* TW: Inserted entire section from 630/LVDS BIOS (added ModeType check) */
+	   tempah = 0;
+	   if( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) && (SiS_Pr->SiS_ModeType > ModeVGA) ) {
+               	  tempah |= 0x02;
+    	   }
+	   tempah <<= 5;
+
+	   if(SiS_Pr->SiS_VBInfo & DisableCRT2Display)  tempah = 0;
+
+	   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x01,tempah);
+
+	}
 
-    	if((!(SiS_VBInfo&SetInSlaveMode)) &&
-          	    (ModeNo!=0x2e)&&(ModeNo!=0x30)&&(ModeNo!=0x38)&&(ModeNo!=0x3A)) {
-      			tempah=tempah|0x02;
-    	}
-    	SiS_SetRegANDOR(SiS_Part1Port,0x2e,0xF0,tempah); /* <------------------- */
     }
+
   }
 
-  /*301b*/
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
- 				&& (!(SiS_VBInfo&SetCRT2ToLCDA))){
-      if(SiS_IsDualEdge(BaseAddr))
-         SiS_SetRegANDOR(SiS_Part1Port,0x13,0xFB,0x00);
-      else
-         SiS_SetRegANDOR(SiS_Part1Port,0x13,0xFF,0x00);
-      if(SiS_IsDualEdge(BaseAddr))
-         SiS_SetRegANDOR(SiS_Part1Port,0x2c,0xCF,0x00);
-      else
-         SiS_SetRegANDOR(SiS_Part1Port,0x2c,0xFF,0x00);
-      if(SiS_IsDualEdge(BaseAddr))
-         SiS_SetRegANDOR(SiS_Part4Port,0x21,0x3F,0x00);
-      else
-         SiS_SetRegANDOR(SiS_Part4Port,0x21,0xFF,0x00);
+  /* TW: Inserted the entire following section */
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+
+      if(HwDeviceExtension->jChipType >= SIS_315H) {
+
+#ifdef SIS650301NEW    /* TW: This is done in 650/301LVx 1.10.6s BIOS */
+         tempah = 0x04;
+         tempbl = 0xfb;
+         if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+            tempah = 0x00;
+	    if(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr))
+	       tempbl = 0xff;
+         }
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah);   
+
+	 /* TW: This in order to fix "TV-blue-bug" on 315+301 */
+         if(SiS_Pr->SiS_VBType & VB_SIS301) {
+	    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2c,0xCF);           /* RIGHT for 315+301 */
+	 } else {
+	    SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,0xCF,0x30);    /* WRONG for 315+301 */
+	 }
+
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0x3f,0xc0);
+
+	 tempah = 0x00;
+         tempbl = 0x7f;
+         if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+            tempbl = 0xff;
+	    if(!(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr)))
+	       tempah |= 0x80;
+         }
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,tempbl,tempah);
+
+#else
+         /* This is done in 650/301LV BIOS instead: */
+         tempah = 0x30;
+	 if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0;
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,0xcf,tempah);
+
+	 tempah = 0xc0;
+	 if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0;
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0x3f,tempah);
+
+	 tempah = 0x80;
+	 if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0;
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,0x7F,tempah);
+#endif
+
+      } else if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+
+         SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x21,0x3f);
+
+         if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | DisableCRT2Display))
+	    SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x23,0x7F);
+	 else
+	    SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x23,0x80);
+
+      }
+
+  } else {  /* LVDS */
+
+      if(HwDeviceExtension->jChipType >= SIS_315H) {
+         tempah = 0x04;
+	 tempbl = 0xfb;
+         if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+            tempah = 0x00;
+	    if(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr))
+	       tempbl = 0xff;
+         }
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah);
+
+	 if(SiS_Pr->SiS_VBInfo & DisableCRT2Display)
+	    SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x00);
+
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,0xcf,0x30);
+      }
 
-      if(SiS_IsDualEdge(BaseAddr))
-         SiS_SetRegANDOR(SiS_Part4Port,0x23,0xFF,0x80);
-       else
-         SiS_SetRegANDOR(SiS_Part4Port,0x23,0xFF,0x00);     
   }
-  /*end 301b*/
+
 }
 
 void
-SiS_GetCRT2Data(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                USHORT RefreshRateTableIndex)
-{
-  if(SiS_IF_DEF_LVDS==0) { /* 301  */
-     if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-        if(SiS_VBInfo&SetCRT2ToLCDA)
-          SiS_GetCRT2DataLVDS(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
-        else
-          SiS_GetCRT2Data301(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
+SiS_GetCRT2Data(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                USHORT RefreshRateTableIndex,
+		PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+          SiS_GetCRT2DataLVDS(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+	                      HwDeviceExtension);
+        } else {
+	  if((HwDeviceExtension->jChipType < SIS_315H) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)){
+              SiS_GetCRT2Data301(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+	                         HwDeviceExtension);
+	      /* TW: Need LVDS Data for LCD on 630/301B! */
+	      SiS_GetCRT2DataLVDS(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+	                          HwDeviceExtension);
+	  } else {
+	      SiS_GetCRT2Data301(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+	                         HwDeviceExtension);
+          }
+        }
      } else
-     	SiS_GetCRT2Data301(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
-     return;
-  } else {  /* LVDS */
-     SiS_GetCRT2DataLVDS(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
-     return;
+     	SiS_GetCRT2Data301(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+	                   HwDeviceExtension);
+  } else {
+     SiS_GetCRT2DataLVDS(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                         HwDeviceExtension);
   }
 }
 
+/* Checked with 650/LVDS 1.10.07 BIOS */
 void
-SiS_GetCRT2DataLVDS(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                    USHORT RefreshRateTableIndex)
+SiS_GetCRT2DataLVDS(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                    USHORT RefreshRateTableIndex,
+		    PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-   USHORT tempax,tempbx;
-   USHORT CRT2Index,ResIndex;
-   SiS_LVDSDataStruct *LVDSData=NULL;
-
-   SiS_GetCRT2ResInfo(ROMAddr,ModeNo,ModeIdIndex);
-   /*301b*/
-   if((SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-   	 && (SiS_VBInfo&SetCRT2ToLCDA)) {
-      SiS_GetCRT2PtrA(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+   USHORT CRT2Index, ResIndex;
+   const SiS_LVDSDataStruct *LVDSData = NULL;
+
+   SiS_GetCRT2ResInfo(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+
+   if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+
+      SiS_GetCRT2PtrA(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
                       &CRT2Index,&ResIndex);
+
       switch (CRT2Index) {
-      	case  0:  LVDSData=SiS_LVDS1024x768Data_1;    break;
-      	case  1:  LVDSData=SiS_LVDS1280x1024Data_1;   break;
-      	case  2:  LVDSData=SiS_LVDS1280x1024Data_1;   break;
-    	/*  case  2:  LVDSData=SiS_LVDS1280x960Data_1;  break;*/
-      	case  3:  LVDSData=SiS_LVDS1024x768Data_2;    break;
-      	case  4:  LVDSData=SiS_LVDS1280x1024Data_2;   break;
-      	case  5:  LVDSData=SiS_LVDS1280x1024Data_2;   break;
-    	/*  case  5:  LVDSData=SiS_LVDS1280x960Data_2;  break; */
-       }    
+      	case  0:  LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1;    break;
+      	case  1:  LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_1;   break;
+        case  2:  LVDSData = SiS_Pr->SiS_LVDS1280x960Data_1;    break;
+	case  3:  LVDSData = SiS_Pr->SiS_LCDA1400x1050Data_1;   break;
+	case  4:  LVDSData = SiS_Pr->SiS_LCDA1600x1200Data_1;   break;
+      	case  5:  LVDSData = SiS_Pr->SiS_LVDS1024x768Data_2;    break;
+      	case  6:  LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_2;   break;
+      	case  7:  LVDSData = SiS_Pr->SiS_LVDS1280x960Data_2;    break;
+	case  8:  LVDSData = SiS_Pr->SiS_LCDA1400x1050Data_2;   break;
+	case  9:  LVDSData = SiS_Pr->SiS_LCDA1600x1200Data_2;   break;
+      }
+
    } else {
-      SiS_GetCRT2Ptr(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,&CRT2Index,&ResIndex);
+
+      /* TW: SiS630/301B needs LVDS Data! */
+      if( (HwDeviceExtension->jChipType < SIS_315H) &&
+          (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
+	  (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) )
+              SiS_Pr->SiS_IF_DEF_LVDS = 1;
+
+      SiS_GetCRT2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                     &CRT2Index,&ResIndex,HwDeviceExtension);
+
+      /* TW: SiS630/301B needs LVDS Data! */
+      if( (HwDeviceExtension->jChipType < SIS_315H) &&
+          (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
+	  (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) )
+              SiS_Pr->SiS_IF_DEF_LVDS = 0;
+
       switch (CRT2Index) {
-      	case  0:  LVDSData=SiS_LVDS800x600Data_1;    break;
-      	case  1:  LVDSData=SiS_LVDS1024x768Data_1;   break;
-      	case  2:  LVDSData=SiS_LVDS1280x1024Data_1;  break;
-      	case  3:  LVDSData=SiS_LVDS800x600Data_2;    break;
-      	case  4:  LVDSData=SiS_LVDS1024x768Data_2;   break;
-      	case  5:  LVDSData=SiS_LVDS1280x1024Data_2;  break;
-      	case  6:  LVDSData=SiS_LVDS640x480Data_1;    break;
-      	case  7:  LVDSData=SiS_CHTVUNTSCData;        break;
-      	case  8:  LVDSData=SiS_CHTVONTSCData;        break;
-      	case  9:  LVDSData=SiS_CHTVUPALData;         break;
-      	case 10:  LVDSData=SiS_CHTVOPALData;         break;
-      	case 11:  LVDSData=SiS_LVDS320x480Data_1;    break;
+      	case  0:  LVDSData = SiS_Pr->SiS_LVDS800x600Data_1;    break;
+      	case  1:  LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1;   break;
+      	case  2:  LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_1;  break;
+      	case  3:  LVDSData = SiS_Pr->SiS_LVDS800x600Data_2;    break;
+      	case  4:  LVDSData = SiS_Pr->SiS_LVDS1024x768Data_2;   break;
+      	case  5:  LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_2;  break;
+	case  6:  LVDSData = SiS_Pr->SiS_LVDS640x480Data_1;    break;
+        case  7:  LVDSData = SiS_Pr->SiS_LVDSXXXxXXXData_1;    break;  /* TW: New */
+	case  8:  LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_1;  break;  /* TW: New */
+	case  9:  LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_2;  break;  /* TW: New */
+      	case 10:  LVDSData = SiS_Pr->SiS_CHTVUNTSCData;        break;
+      	case 11:  LVDSData = SiS_Pr->SiS_CHTVONTSCData;        break;
+      	case 12:  LVDSData = SiS_Pr->SiS_CHTVUPALData;         break;
+      	case 13:  LVDSData = SiS_Pr->SiS_CHTVOPALData;         break;
+      	case 14:  LVDSData = SiS_Pr->SiS_LVDS320x480Data_1;    break;
+	case 15:  LVDSData = SiS_Pr->SiS_LVDS1024x600Data_1;   break;  /* TW: New */
+	case 16:  LVDSData = SiS_Pr->SiS_LVDS1152x768Data_1;   break;  /* TW: New */
+	case 17:  LVDSData = SiS_Pr->SiS_LVDS1024x600Data_2;   break;  /* TW: New */
+	case 18:  LVDSData = SiS_Pr->SiS_LVDS1152x768Data_2;   break;  /* TW: New */
      }
    }
-   SiS_VGAHT = (LVDSData+ResIndex)->VGAHT;
-   SiS_VGAVT = (LVDSData+ResIndex)->VGAVT;
-   SiS_HT = (LVDSData+ResIndex)->LCDHT;
-   SiS_VT = (LVDSData+ResIndex)->LCDVT;
-
-  /*301b*/ /* TW: I have NOT added LVDS check here */
-  if( (SiS_IF_DEF_LVDS==0) &&
-      (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))) {/*for test*/
-    if(!(SiS_LCDInfo&LCDNonExpanding)){
-         if(SiS_LCDResInfo==Panel1024x768){
-           tempax=1024;
-           tempbx=768;
+
+   SiS_Pr->SiS_VGAHT = (LVDSData+ResIndex)->VGAHT;
+   SiS_Pr->SiS_VGAVT = (LVDSData+ResIndex)->VGAVT;
+   SiS_Pr->SiS_HT = (LVDSData+ResIndex)->LCDHT;
+   SiS_Pr->SiS_VT = (LVDSData+ResIndex)->LCDVT;
+
+  if((SiS_Pr->SiS_IF_DEF_LVDS == 0) && (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+
+    if(!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)){
+         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768){
+           SiS_Pr->SiS_HDE = 1024;
+           SiS_Pr->SiS_VDE = 768;
+         } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024){
+           SiS_Pr->SiS_HDE = 1280;
+           SiS_Pr->SiS_VDE = 1024;
+	 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050){
+           SiS_Pr->SiS_HDE = 1400;
+           SiS_Pr->SiS_VDE = 1050;
+	 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200){
+           SiS_Pr->SiS_HDE = 1600;
+           SiS_Pr->SiS_VDE = 1200;
          } else {
-           tempax=1280;
-           tempbx=1024;
-         }
-         SiS_HDE=tempax;
-         SiS_VDE=tempbx;
+	   SiS_Pr->SiS_HDE = 1280;
+	   SiS_Pr->SiS_VDE = 960;
+	 }
     }
+
   } else {
-   if(SiS_IF_DEF_TRUMPION==0){
-     if(SiS_VBInfo&SetCRT2ToLCD){
-       if(!(SiS_LCDInfo&LCDNonExpanding)){
-         if(SiS_LCDResInfo==Panel640x480){
-           tempax=640;
-           tempbx=480;
-         } else if(SiS_LCDResInfo==Panel800x600){
-           tempax=800;
-           tempbx=600;
-         } else if(SiS_LCDResInfo==Panel1024x768){
-           tempax=1024;
-           tempbx=768;
-         } else {
-           tempax=1280;
-           tempbx=1024;
-         }
-         if(SiS_IF_DEF_FSTN){           /*fstn*/
-           tempax=320;
-           tempbx=480;
-         }
-         SiS_HDE=tempax;
-         SiS_VDE=tempbx;
-       }
-     }
-   }
-  } 
-  return;
+
+    if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) {
+      if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+          if((!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) || (SiS_Pr->SiS_SetFlag & CRT2IsVGA)) {
+            if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+              SiS_Pr->SiS_HDE = 800;
+              SiS_Pr->SiS_VDE = 600;
+            } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+              SiS_Pr->SiS_HDE = 1024;
+              SiS_Pr->SiS_VDE = 768;
+            } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+              SiS_Pr->SiS_HDE = 1280;
+              SiS_Pr->SiS_VDE = 1024;
+            } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+	      SiS_Pr->SiS_HDE = 1024;
+              SiS_Pr->SiS_VDE = 600;
+	    } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+	      SiS_Pr->SiS_HDE = 1400;
+              SiS_Pr->SiS_VDE = 1050;
+	    } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
+	      SiS_Pr->SiS_HDE = 1152;
+	      SiS_Pr->SiS_VDE = 768;
+	    } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x864) {
+	      SiS_Pr->SiS_HDE = 1152;
+	      SiS_Pr->SiS_VDE = 864;
+	    } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
+	      SiS_Pr->SiS_HDE = 1280;
+	      SiS_Pr->SiS_VDE = 768;
+	    } else {
+	      SiS_Pr->SiS_HDE = 1600;
+	      SiS_Pr->SiS_VDE = 1200;
+	    }
+            if(SiS_Pr->SiS_IF_DEF_FSTN) {
+              SiS_Pr->SiS_HDE = 320;
+              SiS_Pr->SiS_VDE = 480;
+            }
+          }
+        }
+      }
+    }
+  }
 }
 
+/* TW: Checked against 630/301B BIOS; does not check VDE values for LCD */
 void
-SiS_GetCRT2Data301(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                        USHORT RefreshRateTableIndex)
+SiS_GetCRT2Data301(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                   USHORT RefreshRateTableIndex,
+		   PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT tempax,tempbx,modeflag;
   USHORT resinfo;
   USHORT CRT2Index,ResIndex;
-  SiS_LCDDataStruct *LCDPtr=NULL;
-  SiS_TVDataStruct  *TVPtr=NULL;
+  const SiS_LCDDataStruct *LCDPtr = NULL;
+  const SiS_TVDataStruct  *TVPtr  = NULL;
 
   if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-    	resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+    	resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
   } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-    	resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+  SiS_Pr->SiS_NewFlickerMode = 0;
+  SiS_Pr->SiS_RVBHRS = 50;
+  SiS_Pr->SiS_RY1COE = 0;
+  SiS_Pr->SiS_RY2COE = 0;
+  SiS_Pr->SiS_RY3COE = 0;
+  SiS_Pr->SiS_RY4COE = 0;
+
+  SiS_GetCRT2ResInfo(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+
+  /* TW: For VGA2 ("RAMDAC2") */
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC){
+     SiS_GetRAMDAC2DATA(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                        HwDeviceExtension);
+     return;
   }
-  SiS_NewFlickerMode=0;
-  SiS_RVBHRS=50;
-  SiS_RY1COE=0;
-  SiS_RY2COE=0;
-  SiS_RY3COE=0;
-  SiS_RY4COE=0;
-
-  SiS_GetCRT2ResInfo(ROMAddr,ModeNo,ModeIdIndex);
-  if(SiS_VBInfo&SetCRT2ToRAMDAC){
-    	SiS_GetRAMDAC2DATA(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
-    	return;
-  }
-
-  if(SiS_VBInfo&SetCRT2ToTV){
-    SiS_GetCRT2Ptr(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                   &CRT2Index,&ResIndex);
+
+  /* TW: For TV */
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+
+    SiS_GetCRT2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                   &CRT2Index,&ResIndex,HwDeviceExtension);
+
     switch (CRT2Index) {
-      case  2:  TVPtr=SiS_ExtHiTVData;   break;
-      case  3:  TVPtr=SiS_ExtPALData;    break;
-      case  4:  TVPtr=SiS_ExtNTSCData;   break;
-      case  7:  TVPtr=SiS_St1HiTVData;   break;
-      case  8:  TVPtr=SiS_StPALData;     break;
-      case  9:  TVPtr=SiS_StNTSCData;    break;
-      case 12:  TVPtr=SiS_St2HiTVData;   break;
-      default:  TVPtr=SiS_StPALData;     break;  /* TW: Just to avoid a crash */
-    }
-
-    SiS_RVBHCMAX = (TVPtr+ResIndex)->RVBHCMAX;
-    SiS_RVBHCFACT = (TVPtr+ResIndex)->RVBHCFACT;
-    SiS_VGAHT = (TVPtr+ResIndex)->VGAHT;
-    SiS_VGAVT = (TVPtr+ResIndex)->VGAVT;
-    SiS_HDE = (TVPtr+ResIndex)->TVHDE;
-    SiS_VDE = (TVPtr+ResIndex)->TVVDE;
-    SiS_RVBHRS = (TVPtr+ResIndex)->RVBHRS;
-    SiS_NewFlickerMode = (TVPtr+ResIndex)->FlickerMode;
-    if(SiS_VBInfo&SetCRT2ToHiVisionTV ) {
-      	if(resinfo==0x08) SiS_NewFlickerMode=0x40;
-      	if(resinfo==0x09) SiS_NewFlickerMode=0x40;
-	if(resinfo==0x10) SiS_NewFlickerMode=0x40;
-    }
-    if(SiS_VBInfo&SetCRT2ToHiVisionTV ) {
-      if(SiS_VGAVDE==350) SiS_SetFlag=SiS_SetFlag|TVSimuMode;
-      tempax=ExtHiTVHT;
-      tempbx=ExtHiTVVT;
-      if(SiS_VBInfo&SetInSlaveMode) {
-        if(SiS_SetFlag&TVSimuMode) {
-          tempax=StHiTVHT;
-          tempbx=StHiTVVT;
-          if(!(modeflag&Charx8Dot)){
-            tempax=StHiTextTVHT;
-            tempbx=StHiTextTVVT;
+#ifdef oldHV
+      case  2:  TVPtr = SiS_Pr->SiS_ExtHiTVData;   break;
+      case  7:  TVPtr = SiS_Pr->SiS_St1HiTVData;   break;
+      case 12:  TVPtr = SiS_Pr->SiS_St2HiTVData;   break;
+#endif
+      case  3:  TVPtr = SiS_Pr->SiS_ExtPALData;    break;
+      case  4:  TVPtr = SiS_Pr->SiS_ExtNTSCData;   break;
+      case  8:  TVPtr = SiS_Pr->SiS_StPALData;     break;
+      case  9:  TVPtr = SiS_Pr->SiS_StNTSCData;    break;
+      default:  TVPtr = SiS_Pr->SiS_StPALData;     break;  /* TW: Just to avoid a crash */
+    }
+
+    SiS_Pr->SiS_RVBHCMAX  = (TVPtr+ResIndex)->RVBHCMAX;
+    SiS_Pr->SiS_RVBHCFACT = (TVPtr+ResIndex)->RVBHCFACT;
+    SiS_Pr->SiS_VGAHT     = (TVPtr+ResIndex)->VGAHT;
+    SiS_Pr->SiS_VGAVT     = (TVPtr+ResIndex)->VGAVT;
+    SiS_Pr->SiS_HDE       = (TVPtr+ResIndex)->TVHDE;
+    SiS_Pr->SiS_VDE       = (TVPtr+ResIndex)->TVVDE;
+    SiS_Pr->SiS_RVBHRS    = (TVPtr+ResIndex)->RVBHRS;
+    SiS_Pr->SiS_NewFlickerMode = (TVPtr+ResIndex)->FlickerMode;
+
+    if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {   /* TW: NOT oldHV! */
+
+      	if(resinfo == 0x08) SiS_Pr->SiS_NewFlickerMode = 0x40;
+      	if(resinfo == 0x09) SiS_Pr->SiS_NewFlickerMode = 0x40;
+	if(resinfo == 0x12) SiS_Pr->SiS_NewFlickerMode = 0x40;
+
+        if(SiS_Pr->SiS_VGAVDE == 350) SiS_Pr->SiS_SetFlag |= TVSimuMode;
+
+        SiS_Pr->SiS_HT = ExtHiTVHT;
+        SiS_Pr->SiS_VT = ExtHiTVVT;
+        if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+          if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+            SiS_Pr->SiS_HT = StHiTVHT;
+            SiS_Pr->SiS_VT = StHiTVVT;
+            if(!(modeflag & Charx8Dot)){
+              SiS_Pr->SiS_HT = StHiTextTVHT;
+              SiS_Pr->SiS_VT = StHiTextTVVT;
+            }
           }
         }
+
+    } else {
+
+      SiS_Pr->SiS_RY1COE = (TVPtr+ResIndex)->RY1COE;
+      SiS_Pr->SiS_RY2COE = (TVPtr+ResIndex)->RY2COE;
+      SiS_Pr->SiS_RY3COE = (TVPtr+ResIndex)->RY3COE;
+      SiS_Pr->SiS_RY4COE = (TVPtr+ResIndex)->RY4COE;
+
+      if(modeflag & HalfDCLK) {
+         SiS_Pr->SiS_RY1COE = 0x00;
+         SiS_Pr->SiS_RY2COE = 0xf4;
+         SiS_Pr->SiS_RY3COE = 0x10;
+         SiS_Pr->SiS_RY4COE = 0x38;
       }
-    }
-    if(!(SiS_VBInfo&SetCRT2ToHiVisionTV)) {
-      SiS_RY1COE = (TVPtr+ResIndex)->RY1COE;
-      SiS_RY2COE = (TVPtr+ResIndex)->RY2COE;
-      if(modeflag&HalfDCLK) {
-        SiS_RY1COE = 0x00;
-        SiS_RY2COE = 0xf4;
-      }
-      SiS_RY3COE = (TVPtr+ResIndex)->RY3COE;
-      SiS_RY4COE = (TVPtr+ResIndex)->RY4COE;
-      if(modeflag&HalfDCLK) {
-        SiS_RY3COE = 0x10;
-        SiS_RY4COE = 0x38;
-      }
-      if(!(SiS_VBInfo&SetPALTV)){
-        tempax=NTSCHT;
-        tempbx=NTSCVT;
-      }
-      else{
-        tempax=PALHT;
-        tempbx=PALVT;
+
+      if(!(SiS_Pr->SiS_VBInfo & SetPALTV)){
+        SiS_Pr->SiS_HT = NTSCHT;
+#if 0   /* TW: Not in 650/301LVx 1.10.6s */
+	if((ModeNo == 0x4a) || (ModeNo == 0x38)) SiS_Pr->SiS_HT = NTSC2HT;
+#endif
+        SiS_Pr->SiS_VT = NTSCVT;
+      } else {
+        SiS_Pr->SiS_HT = PALHT;
+        SiS_Pr->SiS_VT = PALVT;
       }
+
     }
-    SiS_HT=tempax;
-    SiS_VT=tempbx;
+
     return;
   }
 
-  if(SiS_VBInfo&SetCRT2ToLCD){
-    SiS_GetCRT2Ptr(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                   &CRT2Index,&ResIndex);
+  /* TW: For LCD */
+  /* TW: Checked against 650/301LV; CRT2Index different (but does not matter) */
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+
+    SiS_GetCRT2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                   &CRT2Index,&ResIndex,HwDeviceExtension);
+
     switch (CRT2Index) {
-      case  0: LCDPtr = SiS_ExtLCD1024x768Data;        break;
-      case  1: LCDPtr = SiS_ExtLCD1280x1024Data;       break;
-      case  5: LCDPtr = SiS_StLCD1024x768Data;         break;
-      case  6: LCDPtr = SiS_StLCD1280x1024Data;        break;
-      case 10: LCDPtr = SiS_St2LCD1024x768Data;        break;
-      case 11: LCDPtr = SiS_St2LCD1280x1024Data;       break;
-      case 13: LCDPtr = SiS_NoScaleData;               break;
-      case 14: LCDPtr = SiS_LCD1280x960Data;           break;
-      default: LCDPtr = SiS_ExtLCD1024x768Data;	       break; /* TW: Just to avoid a crash */
-    }
-
-    SiS_RVBHCMAX = (LCDPtr+ResIndex)->RVBHCMAX;
-    SiS_RVBHCFACT = (LCDPtr+ResIndex)->RVBHCFACT;
-    SiS_VGAHT = (LCDPtr+ResIndex)->VGAHT;
-    SiS_VGAVT = (LCDPtr+ResIndex)->VGAVT;
-    SiS_HT = (LCDPtr+ResIndex)->LCDHT;
-    SiS_VT = (LCDPtr+ResIndex)->LCDVT;
-    tempax=1024;
-    if(SiS_SetFlag&LCDVESATiming) {
-      if(SiS_VGAVDE==350) tempbx=560;
-      else if(SiS_VGAVDE==400) tempbx=640;
-      else tempbx=768;
-    }
-    else {
-      if(SiS_VGAVDE==357) tempbx=527;
-      else if(SiS_VGAVDE==420) tempbx=620;
-      else if(SiS_VGAVDE==525) tempbx=775;
-      else if(SiS_VGAVDE==600) tempbx=775;
-      else if(SiS_VGAVDE==350) tempbx=560;
-      else if(SiS_VGAVDE==400) tempbx=640;
-      else tempbx=768;
-    }
-    if(SiS_LCDResInfo==Panel1280x1024){
-      tempax=1280;
-      if(SiS_VGAVDE==360) tempbx=768;
-      else if(SiS_VGAVDE==375) tempbx=800;
-           else if(SiS_VGAVDE==405) tempbx=864;
-                else tempbx=1024;
-    }
-    if(SiS_LCDResInfo==Panel1280x960){
-      tempax=1280;
-      if(SiS_VGAVDE==350) tempbx=700;
-      else if(SiS_VGAVDE==400) tempbx=800;
-           else if(SiS_VGAVDE==1024) tempbx=960;
-                else tempbx=960;
-    }
-    if(SiS_LCDInfo&LCDNonExpanding) {
-       tempax=SiS_VGAHDE;
-       tempbx=SiS_VGAVDE;
+      case  0: LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data;        break; /* VESA Timing */
+      case  1: LCDPtr = SiS_Pr->SiS_ExtLCD1280x1024Data;       break; /* VESA Timing */
+      case  5: LCDPtr = SiS_Pr->SiS_StLCD1024x768Data;         break; /* Obviously unused */
+      case  6: LCDPtr = SiS_Pr->SiS_StLCD1280x1024Data;        break; /* Obviously unused */
+      case 10: LCDPtr = SiS_Pr->SiS_St2LCD1024x768Data;        break; /* Non-VESA Timing */
+      case 11: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data;       break; /* Non-VESA Timing */
+      case 13: LCDPtr = SiS_Pr->SiS_NoScaleData1024x768;       break; /* Non-expanding */
+      case 14: LCDPtr = SiS_Pr->SiS_NoScaleData1280x1024;      break; /* Non-expanding */
+      case 15: LCDPtr = SiS_Pr->SiS_LCD1280x960Data;           break; /* 1280x960 */
+      case 20: LCDPtr = SiS_Pr->SiS_ExtLCD1400x1050Data;       break; /* VESA Timing */
+      case 21: LCDPtr = SiS_Pr->SiS_NoScaleData1400x1050;      break; /* Non-expanding */
+      case 22: LCDPtr = SiS_Pr->SiS_StLCD1400x1050Data;	       break; /* Non-VESA Timing */
+      case 23: LCDPtr = SiS_Pr->SiS_ExtLCD1600x1200Data;       break; /* VESA Timing */
+      case 24: LCDPtr = SiS_Pr->SiS_NoScaleData1600x1200;      break; /* Non-expanding */
+      case 25: LCDPtr = SiS_Pr->SiS_StLCD1600x1200Data;	       break; /* Non-VESA Timing */
+      default: LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data;	       break; /* Just to avoid a crash */
+    }
+
+    SiS_Pr->SiS_RVBHCMAX  = (LCDPtr+ResIndex)->RVBHCMAX;
+    SiS_Pr->SiS_RVBHCFACT = (LCDPtr+ResIndex)->RVBHCFACT;
+    SiS_Pr->SiS_VGAHT     = (LCDPtr+ResIndex)->VGAHT;
+    SiS_Pr->SiS_VGAVT     = (LCDPtr+ResIndex)->VGAVT;
+    SiS_Pr->SiS_HT        = (LCDPtr+ResIndex)->LCDHT;
+    SiS_Pr->SiS_VT        = (LCDPtr+ResIndex)->LCDVT;
+
+    tempax = 1024;
+    if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+      if     (SiS_Pr->SiS_VGAVDE == 350) tempbx = 560;
+      else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640;
+      else                               tempbx = 768;
+    } else {
+      if     (SiS_Pr->SiS_VGAVDE == 357) tempbx = 527;
+      else if(SiS_Pr->SiS_VGAVDE == 420) tempbx = 620;
+      else if(SiS_Pr->SiS_VGAVDE == 525) tempbx = 775;
+      else if(SiS_Pr->SiS_VGAVDE == 600) tempbx = 775;
+      else if(SiS_Pr->SiS_VGAVDE == 350) tempbx = 560;
+      else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640;
+      else                               tempbx = 768;
+    }
+    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024){
+      tempax = 1280;
+      if     (SiS_Pr->SiS_VGAVDE == 360) tempbx = 768;
+      else if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 800;
+      else if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 864;
+      else                               tempbx = 1024;
+    }
+    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960){
+      tempax = 1280;
+      if     (SiS_Pr->SiS_VGAVDE == 350)  tempbx = 700;
+      else if(SiS_Pr->SiS_VGAVDE == 400)  tempbx = 800;
+      else if(SiS_Pr->SiS_VGAVDE == 1024) tempbx = 960;
+      else                                tempbx = 960;
+    }
+    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050){
+      tempax = 1400;
+      tempbx = 1050;
+    }
+    if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) {
+       tempax = SiS_Pr->SiS_VGAHDE;
+       tempbx = SiS_Pr->SiS_VGAVDE;
     }
-    SiS_HDE=tempax;
-    SiS_VDE=tempbx;
+    SiS_Pr->SiS_HDE = tempax;
+    SiS_Pr->SiS_VDE = tempbx;
     return;
   }
 }
 
 USHORT
-SiS_GetResInfo(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SiS_GetResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
   USHORT resindex;
 
-  if(ModeNo<=0x13){
-    	resindex=SiS_SModeIDTable[ModeIdIndex].St_ResInfo;              /* si+St_ResInfo */
-  } else {
-    	resindex=SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;            	/* si+Ext_ResInfo */
-  }
+  if(ModeNo<=0x13)
+    	resindex=SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+  else
+    	resindex=SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+
   return(resindex);
 }
 
+/* TW: Checked against 650/301LV, 650/LVDS, 630/LVDS, 630/301 and 630/301B BIOS */
 void
-SiS_GetCRT2ResInfo(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SiS_GetCRT2ResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                   PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT xres,yres,modeflag,resindex;
+  USHORT xres,yres,modeflag=0,resindex;
 
-  resindex=SiS_GetResInfo(ROMAddr,ModeNo,ModeIdIndex);
-  if(ModeNo<=0x13){
-    	xres=SiS_StResInfo[resindex].HTotal;
-    	yres=SiS_StResInfo[resindex].VTotal;
-  } else {
-    	xres=SiS_ModeResInfo[resindex].HTotal;                         		/* xres->ax */
-    	yres=SiS_ModeResInfo[resindex].VTotal;                         		/* yres->bx */
-    	modeflag=SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;      		/* si+St_ModeFlag */
-    	if(SiS_IF_DEF_FSTN){							/*fstn*/
-       		xres=xres*2;
-       		yres=yres*2;
-    	} else {
-      		if(modeflag&HalfDCLK) { xres=xres*2;}
-      		if(modeflag&DoubleScanMode) {yres=yres*2;}
-    	}
+  resindex = SiS_GetResInfo(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
+
+  if(ModeNo <= 0x13) {
+    	xres = SiS_Pr->SiS_StResInfo[resindex].HTotal;
+    	yres = SiS_Pr->SiS_StResInfo[resindex].VTotal;
+  } else {
+	xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal;
+    	yres = SiS_Pr->SiS_ModeResInfo[resindex].VTotal;
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
   }
-  if(SiS_IF_DEF_LVDS==0) {
-    	if(SiS_LCDResInfo==Panel1280x1024) {
-      		if(yres==400) yres=405;
-      		if(yres==350) yres=360;
-      		if(SiS_SetFlag&LCDVESATiming) {
-        		if(yres==360) yres=375;
+
+  /* TW: Inserted entire if-section from 650/LVDS BIOS 1.10.07: */
+  if((HwDeviceExtension->jChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 1)) {
+      if((ModeNo != 0x03) && (SiS_Pr->SiS_SetFlag & CRT2IsVGA)) {
+          if(yres == 350) yres = 400;
+      }
+      if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x3a) & 0x01) {
+ 	  if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x34) == 0x12)
+	      yres = 400;
+      }
+  }
+
+  if(ModeNo > 0x13) {
+      if(SiS_Pr->SiS_IF_DEF_FSTN == 1){
+            xres *= 2;
+            yres *= 2;
+      } else {
+  	    if(modeflag & HalfDCLK)       xres *= 2;
+  	    if(modeflag & DoubleScanMode) yres *= 2;
+      }
+  }
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+        /* TW: Inserted from 650/301LV BIOS */
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+                if(xres == 720) xres = 640;
+	} else {
+	   if(xres == 720) xres = 640;
+    	   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+      		if(yres == 400) yres = 405;
+      		if(yres == 350) yres = 360;
+      		if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+        		if(yres == 360) yres = 375;
       		}
-   	 }
-    	if(SiS_LCDResInfo==Panel1024x768){
-      		if(!(SiS_SetFlag&LCDVESATiming)) {
-        		if(!(SiS_LCDInfo&LCDNonExpanding)) {
-          			if(yres==350) yres=357;
-          			if(yres==400) yres=420;
-/*          			if(!OldBios)             */
-            			if(yres==480) yres=525;
+   	   }
+    	   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768){
+      		if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+        		if(!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) {
+          			if(yres == 350) yres = 357;
+          			if(yres == 400) yres = 420;
+            			if(yres == 480) yres = 525;
         		}
       		}
-    	}
-  } else { /* LVDS - does not support 720x??? */
-    	if(xres==720) xres=640;
+    	   }
+	   /* TW: Inserted for 630/301B */
+	   if(HwDeviceExtension->jChipType < SIS_315H) {
+	      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+                  if(xres == 720) xres = 640;
+	      }
+	   }
+	}
+  } else {
+    	if(xres == 720) xres = 640;
+	/* TW: Inserted from 650/LVDS and 630/LVDS BIOS */
+	if(SiS_Pr->SiS_SetFlag & CRT2IsVGA) {
+	      yres = 400;
+	      if(HwDeviceExtension->jChipType >= SIS_315H) {
+	          if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x80) yres = 480;
+	      } else {
+	          if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x80) yres = 480;
+	      }
+	}
   }
-  SiS_VGAHDE=xres;
-  SiS_HDE=xres;
-  SiS_VGAVDE=yres;
-  SiS_VDE=yres;
+  SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = xres;
+  SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = yres;
 }
 
+/* TW: Checked against 650/301 and 650/LVDS (1.10.07) BIOS; modified for new panel resolutions */
+/* TW: Done differently in 630/301B BIOS; but same effect; checked against 630/301 */
 void
-SiS_GetCRT2Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-	       USHORT RefreshRateTableIndex,USHORT *CRT2Index,USHORT *ResIndex)
-{
-  USHORT tempbx,tempal=0;
-  USHORT Flag;
-  if(SiS_IF_DEF_LVDS==0) {
-    	if(SiS_VBInfo&SetCRT2ToLCD){              /* LCD */
-      		tempbx=SiS_LCDResInfo;
-      		tempbx=tempbx-Panel1024x768;
-      		if(!(SiS_SetFlag&LCDVESATiming)) {
-        		tempbx+=5;
-/*      		GetRevisionID();  */
-        		tempbx+=5;
-       		}
+SiS_GetCRT2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+	       USHORT RefreshRateTableIndex,USHORT *CRT2Index,USHORT *ResIndex,
+	       PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT tempbx=0,tempal=0;
+  USHORT Flag,resinfo=0;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+    	if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {                            /* LCD */
+	        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
+			tempbx = 15;
+		} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+		        tempbx = 20;
+			if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx = 21;
+			if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx = 22;
+		} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
+		        tempbx = 23;
+			if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx = 24;
+			if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx = 25;
+		} else if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) {
+			tempbx = 13;
+			if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempbx++;
+		} else {
+      		   tempbx = SiS_Pr->SiS_LCDResInfo - SiS_Pr->SiS_Panel1024x768;
+      		   if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+        		tempbx += 5;
+                        /* GetRevisionID();  */
+			/* TW: BIOS only adds 5 once */
+        		tempbx += 5;
+       		   }
+	        }
      	} else {
-       		if(SiS_VBInfo&SetCRT2ToHiVisionTV){              /* TV */
-         		if(SiS_VGAVDE>480) SiS_SetFlag=SiS_SetFlag&(!TVSimuMode);
-         		tempbx=2;
-         		if(SiS_VBInfo&SetInSlaveMode) {
-            			if(!(SiS_SetFlag&TVSimuMode)) tempbx=10;
+#ifdef oldHV					           /* TV */
+       		if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV){
+         		if(SiS_Pr->SiS_VGAVDE > 480) SiS_Pr->SiS_SetFlag &= (~TVSimuMode); /* TW: Was "(!TVSimuMode)" - WRONG */
+         		tempbx = 2;
+         		if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+            			if(!(SiS_Pr->SiS_SetFlag & TVSimuMode)) tempbx = 12;  /* TW: Was 10! - WRONG */
          		}
        		} else {
-         		if(SiS_VBInfo&SetPALTV){
-           			tempbx=3;
-         		} else {
-           			tempbx=4;
-         		}
-         		if(SiS_SetFlag&TVSimuMode){
-           			tempbx=tempbx+5;
-         		}
+#endif
+         		if(SiS_Pr->SiS_VBInfo & SetPALTV) tempbx = 3;
+         		else tempbx = 4;
+         		if(SiS_Pr->SiS_SetFlag & TVSimuMode) tempbx += 5;
+#ifdef oldHV
        		}
+#endif
      	}
 
-     	if(ModeNo<=0x13){
-       		tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-     	} else {
-       		tempal = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-     	}
-     	tempal=tempal&0x3F;
-     	/*301b*/
-      	if((SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-       					&& (SiS_VBInfo&SetCRT2ToTV)) {
-        	/*look*/
-      		if(tempal==0x06) tempal=0x07;
+     	if(ModeNo <= 0x13)
+       		tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+     	else
+       		tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+
+     	tempal &= 0x3F;
+
+      	if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
+                     && (SiS_Pr->SiS_VBInfo & (SetCRT2ToTV-SetCRT2ToHiVisionTV))) {  /* TW: Added -Hivision (BIOS) */
+      		if(tempal == 0x06) tempal = 0x07;
         }
-   	/*end 301b*/
-     	if((0x31<=ModeNo)&&(ModeNo<=0x35)) tempal=6;
-     	if(SiS_LCDInfo&LCDNonExpanding) tempbx=0x0D;
-     	if(SiS_LCDResInfo==Panel1280x960) tempbx=0x0E;	/* TW !!!! */
-     	*CRT2Index=tempbx;
-     	*ResIndex=tempal;
+
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+            if((ModeNo == 0x31) || (ModeNo == 0x32)) tempal = 6;
+	}
+
+     	*CRT2Index = tempbx;
+     	*ResIndex = tempal;
+
   } else {   /* LVDS */
-    	Flag=1;
-    	tempbx=0;
-    	if(SiS_IF_DEF_CH7005==1) {
-      		if(!(SiS_VBInfo&SetCRT2ToLCD)) {
-        		Flag=0;
-        		tempbx=7;
-        		if(SiS_VBInfo&SetPALTV) tempbx=tempbx+2;
-        		if(SiS_VBInfo&SetCHTVOverScan) tempbx=tempbx+1;
-      		}
-    	}
-    	if(Flag==1) {
-      		tempbx=SiS_LCDResInfo-Panel800x600;
-      		if(SiS_LCDInfo&LCDNonExpanding){
-        		tempbx=tempbx+3;
+
+    	Flag = 1;
+    	tempbx = 0;
+    	if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+      		if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+        		Flag = 0;
+        		tempbx = 10;
+        		if(SiS_Pr->SiS_VBInfo & SetPALTV)        tempbx += 2;
+        		if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
       		}
     	}
-     	if(SiS_LCDResInfo==Panel640x480){
-        	tempbx=6;
-      	}
-     	/*fstn*/
-     	if(SiS_IF_DEF_FSTN){
-       	 	if(SiS_LCDResInfo==Panel320x480){
-         		tempbx=11;                        /* not same with asmber code */
-         		tempal=6;	/* TW: That can't work - is being overwritten below... */
+
+    	if(Flag == 1) {
+      		tempbx = SiS_Pr->SiS_LCDResInfo - SiS_Pr->SiS_PanelMinLVDS;
+		if(SiS_Pr->SiS_LCDResInfo <= SiS_Pr->SiS_Panel1280x1024) {
+   	      	    if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)  tempbx += 3;
+		} else {
+		    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+			tempbx = 8;
+			if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)  tempbx++;
+		    }
+        	    if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+			tempbx = 7;
+        	    }
+
+     		    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480)  tempbx = 6;
+
+		    /* TW: Inserted from 630/LVDS 2.04.5c BIOS */
+		    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+			tempbx = 15;
+  		        if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)  tempbx += 2;
+		    }
+		    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
+		        tempbx = 16;
+			if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)  tempbx += 2;
+		    }
+		 }
+	}
+
+    	if(ModeNo <= 0x13)
+      		tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+    	else {
+      		tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+		resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+	}
+
+	if(SiS_Pr->SiS_IF_DEF_FSTN){
+       	 	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel320x480){
+         		tempbx = 14;
+         		tempal = 6;
         	}
     	}
 
-	else 				/* TW: .... unless I place an "else" here */
-     
-    	if(ModeNo<=0x13){
-      		tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-    	} else {
-      		tempal = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-    	}
-    	tempal=tempal&0x1F;
-    	*CRT2Index=tempbx;
-    	*ResIndex=tempal;
+	/* TW: Inserted from 650/LVDS BIOS */
+	if(SiS_Pr->SiS_SetFlag & CRT2IsVGA) {
+	        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) tempal = 7;
+		if(HwDeviceExtension->jChipType < SIS_315H) {
+		    /* TW: Inserted from 630/LVDS (2.04.5c) and 630/301B (II) BIOS */
+		    if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x80) tempal++;
+		}
+
+	}
+
+	/* TW: Inserted from 630/301B BIOS */
+	if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	    if(ModeNo > 0x13) {
+	        if((resinfo == 0x0c) || (resinfo == 0x0d))  /* 720 */
+		    tempal = 6;
+	    }
+	}
+
+    	*CRT2Index = tempbx;
+    	*ResIndex = tempal & 0x1F;
   }
 }
 
 void
-SiS_GetCRT2PtrA(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+SiS_GetCRT2PtrA(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
 		USHORT RefreshRateTableIndex,USHORT *CRT2Index,
 		USHORT *ResIndex)
 {
   USHORT tempbx,tempal;
 
-  tempbx=SiS_LCDResInfo-Panel1024x768;
-  if(SiS_LCDInfo&LCDNonExpanding){
-        tempbx=tempbx+3;
-  }
-  if(ModeNo<=0x13){
-      	tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  tempbx = SiS_Pr->SiS_LCDResInfo;
+
+  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
+       tempbx = 4;
+  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+       tempbx = 3;
   } else {
-      	tempal = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+       tempbx -= SiS_Pr->SiS_Panel1024x768;
   }
-  tempal=tempal&0x1F;
-  *CRT2Index=tempbx;
-  *ResIndex=tempal;
-}
-/*end 301b*/
 
-USHORT
-SiS_GetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex)
-{
-  /* TW: These tables are being indexed with SiS_LCDResInfo.
-   *     This is equal to the Panel???x??? constants in initdef.h
-   *     and is eg. 2 for 1024x768; these tables were each one
-   *     value too short!
-   */
-  SHORT  LCDRefreshIndex[]  = {0x00,0x00,0x03,0x01,0x01};
-  SHORT  LCDARefreshIndex[] = {0x00,0x00,0x03,0x01,0x01,0x01,0x01,0x01};
-  USHORT RefreshRateTableIndex,i,backup_i;
-  USHORT modeflag,index,temp;
+  if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)  tempbx += 5;
 
-  if (ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-  }else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-  }
+  if(ModeNo <= 0x13)
+      	tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  else
+      	tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+
+  *CRT2Index = tempbx;
+  *ResIndex = tempal & 0x1F;
+}
+
+/* TW: New from 650/301LVx BIOS */
+void
+SiS_GetCRT2Part2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+		    USHORT RefreshRateTableIndex,USHORT *CRT2Index,
+		    USHORT *ResIndex)
+{
+  USHORT tempbx,tempal;
+
+  if(ModeNo <= 0x13)
+      	tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  else
+      	tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+
+  tempbx = SiS_Pr->SiS_LCDResInfo;
+
+  if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)    tempbx += 16;
+  else if(SiS_Pr->SiS_SetFlag & LCDVESATiming) tempbx += 32;
+
+  *CRT2Index = tempbx;
+  *ResIndex = tempal & 0x3F;
+}
+
+/* TW: Checked against all (incl 650/LVDS (1.10.07), 630/301B, 630/301) BIOSes */
+USHORT
+SiS_GetRatePtrCRT2(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo, USHORT ModeIdIndex,
+                   PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  SHORT  LCDRefreshIndex[] = { 0x00, 0x00, 0x03, 0x01,
+                               0x01, 0x01, 0x01, 0x01,
+			       0x01, 0x01, 0x01, 0x01,
+			       0x01, 0x01, 0x01, 0x01 };
+  USHORT RefreshRateTableIndex,i,backup_i;
+  USHORT modeflag,index,temp,backupindex;
+
+  if (ModeNo <= 0x13)
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  else
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
-  if(SiS_IF_DEF_CH7005==1) {
-    	if(SiS_VBInfo&SetCRT2ToTV) {
-      		if(modeflag&HalfDCLK) return(0);
+  if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+    	if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+      		if(modeflag & HalfDCLK) return(0);
     	}
   }
 
-  if(ModeNo<0x14) return(0xFFFF);
+  if(ModeNo < 0x14) return(0xFFFF);
 
- /* TW: CR33 holds refresh rate index for CRT1 (0-3) and CRT2 (4-7).
+ /* TW: CR33 holds refresh rate index for CRT1 [3:0] and CRT2 [7:4].
   *     On LVDS machines, CRT2 index is always 0 and will be
   *     set to 0 by the following code; this causes the function
-  *     to take the first non-interlaced mode in SiS300_Ext2Struct
-  *     (which is the second 1024x768 mode in case the resolution
-  *     is 1024x768; the first mode in the list is interlaced and
-  *     therefore skipped).
+  *     to take the first non-interlaced mode in SiS_Ext2Struct
   */
 
-  index=SiS_GetReg1(SiS_P3d4,0x33);
-  index=index>>SiS_SelectCRT2Rate;
-  index=index&0x0F;
-  if(SiS_LCDInfo&LCDNonExpanding) index=0;
-  if(index>0) index--;
-
-  if(SiS_SetFlag & ProgrammingCRT2) {
-    	if(SiS_IF_DEF_CH7005==1) {
-      		if(SiS_VBInfo&SetCRT2ToTV) {
-        		index=0;
+  index = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x33);
+  index >>= SiS_Pr->SiS_SelectCRT2Rate;
+  index &= 0x0F;
+  backupindex = index;
+
+  if(index > 0) index--;
+
+  if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA))  index = 0;
+      } else {
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	    if(HwDeviceExtension->jChipType < SIS_315H)    index = 0;
+	    else if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) index = backupindex = 0;
+	}
+      }
+  }
+
+  if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {
+    	if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+      		if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+        		index = 0;
       		}
     	}
-    	if(SiS_VBInfo&(SetCRT2ToLCD|SetCRT2ToLCDA)) {
-      		if(SiS_IF_DEF_LVDS==0) {
-        		if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-           			temp=LCDARefreshIndex[SiS_LCDResInfo];     /* 301b */
-        		else
-           			temp=LCDRefreshIndex[SiS_LCDResInfo];	   /* 301  */
-        		if(index>temp){
-          			index=temp;
-        		}
-      		} else {  						   /* LVDS */
-        		index=0;
+    	if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+      		if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+		        /* TW: This is not done in 630/301B BIOS */
+           		temp = LCDRefreshIndex[SiS_Pr->SiS_LCDResInfo];
+        		if(index > temp) index = temp;
+      		} else {
+        		index = 0;
       		}
     	}
   }
 
-  RefreshRateTableIndex = SiS_EModeIDTable[ModeIdIndex].REFindex;
-  ModeNo = SiS_RefIndex[RefreshRateTableIndex].ModeID;
+  RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
+  ModeNo = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].ModeID;
+
+  /* TW: Inserted from 650/LVDS 1.10.07, 650/301LVx 1.10.6s */
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+    if(!(SiS_Pr->SiS_VBInfo & DriverMode)) {
+      if( (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x105) ||
+          (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x107) ) {
+            if(backupindex <= 1)
+	       RefreshRateTableIndex++;
+      }
+    }
+  }
 
-  i=0;
+  i = 0;
   do {
-    	if (SiS_RefIndex[RefreshRateTableIndex+i].ModeID!=ModeNo) break;
-    	temp = SiS_RefIndex[RefreshRateTableIndex+i].Ext_InfoFlag;
-    	temp=temp&ModeInfoFlag;
-    	if(temp<SiS_ModeType) break;
+    	if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + i].ModeID != ModeNo) break;
+    	temp = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + i].Ext_InfoFlag;
+    	temp &= ModeInfoFlag;
+    	if(temp < SiS_Pr->SiS_ModeType) break;
     	i++;
     	index--;
-  } while(index!=0xFFFF);
+  } while(index != 0xFFFF);
 
-  if(!(SiS_VBInfo&SetCRT2ToRAMDAC)) {
-    	if(SiS_VBInfo&SetInSlaveMode) {
-      		temp=SiS_RefIndex[RefreshRateTableIndex+i-1].Ext_InfoFlag;
-      			if(temp&InterlaceMode) {
-        			i++;
-      			}
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) {
+    	if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+      		temp = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + i - 1].Ext_InfoFlag;
+      		if(temp & InterlaceMode) {
+        		i++;
+      		}
     	}
   }
+
   i--;
 
-  if((SiS_SetFlag & ProgrammingCRT2) && (!(SiS_VBInfo & DisableCRT2Display))) {
+  if((SiS_Pr->SiS_SetFlag & ProgrammingCRT2) && (!(SiS_Pr->SiS_VBInfo & DisableCRT2Display))) {
     	backup_i = i;
-    	if (!(SiS_AdjustCRT2Rate(ROMAddr,ModeNo,ModeIdIndex,
-	                             RefreshRateTableIndex,&i))) {
+    	if (!(SiS_AdjustCRT2Rate(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+	                             RefreshRateTableIndex,&i,HwDeviceExtension))) {
 		/* TW: This is for avoiding random data to be used; i is
 		 *     in an undefined state if no matching CRT2 mode is
 		 *     found.
 		 */
 		i = backup_i;
-#ifdef LINUX_KERNEL
-		printk("sisfb: WARNING: No matching CRT2 mode found\n");
-#endif
 	}
   }
 
-  return(RefreshRateTableIndex+i);                			/*return(0x01|(temp1<<1));   */
+  return(RefreshRateTableIndex + i);
 }
 
+/* Checked against all (incl 650/LVDS (1.10.07), 630/301) BIOSes */
 BOOLEAN
-SiS_AdjustCRT2Rate(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                   USHORT RefreshRateTableIndex,USHORT *i)
+SiS_AdjustCRT2Rate(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                   USHORT RefreshRateTableIndex,USHORT *i,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT tempax,tempbx,resinfo;
   USHORT modeflag,infoflag;
 
-  if (ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;    	/* si+St_ModeFlag */
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-  }
+  if (ModeNo <= 0x13)
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  else
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
-  resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-  tempbx = SiS_RefIndex[RefreshRateTableIndex+(*i)].ModeID;
-  tempax=0;
-  if(SiS_IF_DEF_LVDS==0) {
-  	/* TW: For 301 (and which ones of 301B, 302B, 301LV, 302LV ?) */
-    	if(SiS_VBInfo&SetCRT2ToRAMDAC) {
-      		tempax=tempax|SupportRAMDAC2;
-    	}
-    	if(SiS_VBInfo&(SetCRT2ToLCD|SetCRT2ToLCDA)) {        /* 301b */
-      		tempax=tempax|SupportLCD;
-      		if(SiS_LCDResInfo!=Panel1280x1024) {
-        		if(SiS_LCDResInfo!=Panel1280x960) {
-           			if(SiS_LCDInfo&LCDNonExpanding) {
-             				if(resinfo>=9) {
-               					tempax=0;
-               					return(0);
-             				}
+  resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  tempbx = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID;
+
+  tempax = 0;
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+  	/* TW: For 301, 301B, 302B, 301LV, 302LV */
+    	if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
+      		tempax |= SupportRAMDAC2;
+		if(HwDeviceExtension->jChipType >= SIS_315H) {
+		    tempax |= SupportTV;
+		    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+		        if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+			    if(resinfo == 0x0a) tempax |= SupportTV1024;
+			}
+		    }
+		}
+    	}
+    	if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+      		tempax |= SupportLCD;
+		if(HwDeviceExtension->jChipType >= SIS_315H) {
+                   if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1600x1200) {
+		      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1400x1050) {
+		         if((resinfo == 6) && (SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) {
+			    tempax |= SupportAllCRT2;
+			    (*i) = 0;   /* TW: Restore RefreshTableIndex (BIOS 650/301LVx 1.10.6s) */
+                            return(1);
+		         } else {
+      		            if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024) {
+        		      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x960) {
+           			if((resinfo == 6) && (SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) {
+				    return(0);
+				} else {
+             			    if((resinfo >= 9) && (resinfo != 0x14)) {
+               				tempax = 0;
+               				return(0);
+             			    }
            			}
+        		      }
+		            }
+		         }
+		      }
+      		   }
+		} else {
+		  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+		     if((resinfo != 0x0f) && ((resinfo == 4) || (resinfo >= 8))) return(0);
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
+		     if((resinfo != 0x10) && (resinfo > 8)) return(0);
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
+		     if((resinfo != 0x0e) && (resinfo > 8)) return(0);
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+		     if(resinfo > 9) return(0);
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+		     if(resinfo > 8) return(0);
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+		     if((resinfo == 4) || (resinfo > 7)) return(0);
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+		     if((resinfo == 4) || (resinfo == 3) || (resinfo > 6)) return(0);
+		  }
+		}
+    	}
+#ifdef oldHV
+    	if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {    /* for HiTV */
+      		tempax |= SupportHiVisionTV;
+      		if(SiS_Pr->SiS_VBInfo & SetInSlaveMode){
+        		if(resinfo == 4) return(0);
+        		if(resinfo == 3) {
+          			if(SiS_Pr->SiS_SetFlag & TVSimuMode) return(0);
         		}
-      		}
-    	}
-    	if(SiS_VBInfo&SetCRT2ToHiVisionTV) {    /* for HiTV */
-      		tempax=tempax|SupportHiVisionTV;
-      		if(SiS_VBInfo&SetInSlaveMode){
-        		if(resinfo==4) return(0);
-        		if(resinfo==3) {
-          			if(SiS_SetFlag&TVSimuMode) return(0);
-        		}
-        		if(resinfo>7) return(0);
+        		if(resinfo > 7) return(0);
       		}
     	} else {
-      		if(SiS_VBInfo&(SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)) {
-        		tempax=tempax|SupportTV;
-       			/*301b*/
-         		if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-             			tempax=tempax|SupportTV1024;
-         		}
-        		/*end 301b*/
-       
-        		if(!(SiS_VBInfo&SetPALTV)) {
-          			if(modeflag&NoSupportSimuTV) {
-            				if(SiS_VBInfo&SetInSlaveMode) {
-              					if(!(SiS_VBInfo&SetNotSimuMode)) {
-                					return 0;
-              					}
-            				}
-          			}
-        		}
-      		}
+#endif
+      	if(SiS_Pr->SiS_VBInfo & (SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)) {
+        	tempax |= SupportTV;
+		tempax |= SupportTV1024;
+		if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+		    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+		        if((SiS_Pr->SiS_VBInfo & SetNotSimuMode) && (SiS_Pr->SiS_VBInfo & SetPALTV)) {
+			     if(resinfo != 8) {
+			         if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+				     ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 4)) ) {
+				     tempax &= ~(SupportTV1024);
+				     if(HwDeviceExtension->jChipType >= SIS_315H) {
+                                         if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+				             if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+			                         ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 7)) ) {
+			                         if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return(0);
+		                             }
+				         }
+		                     } else {
+				         if( (resinfo != 3) ||
+					     (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+					     (SiS_Pr->SiS_VBInfo & SetNotSimuMode) ) {
+					     if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+						 if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+						     if(resinfo == 3) return(0);
+						     if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return (0);
+						 }
+		                             }
+                                         } else return(0);
+				     }
+				 }
+			     }
+			} else {
+			    tempax &= ~(SupportTV1024);
+			    if(HwDeviceExtension->jChipType >= SIS_315H) {
+			        if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+			            if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+			                ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 7)) ) {
+			                if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return(0);
+		                    }
+		                }
+			    } else {
+			        if( (resinfo != 3) ||
+				    (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+				    (SiS_Pr->SiS_VBInfo & SetNotSimuMode) ) {
+				     if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+					 if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+					     if(resinfo == 3) return(0);
+					     if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return (0);
+					 }
+		                     }
+                                } else return(0);
+                            }
+			}
+		    } else {  /* slavemode */
+			if(resinfo != 8) {
+			    if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+			        ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 4) ) ) {
+				 tempax &= ~(SupportTV1024);
+				 if(HwDeviceExtension->jChipType >= SIS_315H) {
+				     if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+				         if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+			                     ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 7)) ) {
+			                     if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode))  return(0);
+		                         }
+		                     }
+			        } else {
+				    if( (resinfo != 3) ||
+				        (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+				        (SiS_Pr->SiS_VBInfo & SetNotSimuMode) ) {
+				         if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+					     if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+					         if(resinfo == 3) return(0);
+					         if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return (0);
+					     }
+		                         }
+                                    } else return(0);
+				}
+			    }
+			}
+		    }
+		} else {   /* 301 */
+		    tempax &= ~(SupportTV1024);
+		    if(HwDeviceExtension->jChipType >= SIS_315H) {
+		        if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+		            if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+			        ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 7)) ) {
+			        if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return(0);
+		            }
+		        }
+		    } else {
+		        if( (resinfo != 3) ||
+			    (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+			    (SiS_Pr->SiS_VBInfo & SetNotSimuMode) ) {
+			    if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+			        if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+				    if(resinfo == 3) return(0);
+				    if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return (0);
+				}
+		            }
+                        } else return(0);
+		    }
+		}
+        }
+#ifdef oldHV
     	}
-  } else {
-  	/* TW: for LVDS (and which ones of the SiS bridges?) */
-    	if(SiS_IF_DEF_CH7005==1) {
-      		if(SiS_VBInfo&SetCRT2ToTV) {
-        		tempax=tempax|SupportCHTV;
+#endif
+  } else {	/* TW: for LVDS  */
+
+    	if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+      		if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+        		tempax |= SupportCHTV;
       		}
     	}
-    	if(SiS_VBInfo&SetCRT2ToLCD) {
-      		tempax=tempax|SupportLCD;
-      		if(resinfo>0x08) return(0);       	  /* 1024x768  */
-      		if(SiS_LCDResInfo<Panel1024x768) {
-        		if(resinfo>0x07) return(0);       /*  800x600  */
-        		if(resinfo==0x04) return(0);      /*  512x384  */
-      		}
+    	if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+      		tempax |= SupportLCD;
+		if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
+		     if((resinfo != 0x14) && (resinfo > 0x09)) return(0);
+		} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+		     if((resinfo != 0x0f) && (resinfo > 0x08)) return(0);
+		} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
+		     if((resinfo != 0x10) && (resinfo > 0x08)) return(0);
+		} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+		     if((resinfo != 0x15) && (resinfo > 0x09)) return(0);
+		} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+                     if(resinfo > 0x09) return(0);
+                } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+		     if(resinfo > 0x08) return(0);
+		} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600){
+		     if(resinfo > 0x07) return(0);
+		     if(resinfo == 0x04) return(0);
+		}
     	}
   }
   /* TW: Look backwards in table for matching CRT2 mode */
-  for(;SiS_RefIndex[RefreshRateTableIndex+(*i)].ModeID==tempbx;(*i)--) {
-     	infoflag = SiS_RefIndex[RefreshRateTableIndex+(*i)].Ext_InfoFlag;
-     	if(infoflag&tempax) {
+  for(; SiS_Pr->SiS_RefIndex[RefreshRateTableIndex+(*i)].ModeID == tempbx; (*i)--) {
+     	infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].Ext_InfoFlag;
+     	if(infoflag & tempax) {
        		return(1);
      	}
-     	if ((*i)==0) break;
+     	if ((*i) == 0) break;
   }
   /* TW: Look through the whole mode-section of the table from the beginning
    *     for a matching CRT2 mode if no mode was found yet.
    */
-  for((*i)=0;;(*i)++) {
-     	infoflag = SiS_RefIndex[RefreshRateTableIndex+(*i)].Ext_InfoFlag;
-     	if(SiS_RefIndex[RefreshRateTableIndex+(*i)].ModeID!=tempbx) {
+  for((*i) = 0; ; (*i)++) {
+     	infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].Ext_InfoFlag;
+     	if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID != tempbx) {
        		return(0);
      	}
-     	if(infoflag&tempax) {
+     	if(infoflag & tempax) {
        		return(1);
      	}
   }
   return(1);
 }
 
+/* Checked against 650/LVDS (1.10.07) and 650/301LV BIOS */
 void
-SiS_SaveCRT2Info(USHORT ModeNo)
+SiS_SaveCRT2Info(SiS_Private *SiS_Pr, USHORT ModeNo)
 {
   USHORT temp1,temp2;
 
-  SiS_SetReg1(SiS_P3d4,0x34,ModeNo);  /* reserve CR34 for CRT1 Mode No */
-  temp1=(SiS_VBInfo&SetInSlaveMode)>>8;
-  temp2=~(SetInSlaveMode>>8);
-  SiS_SetRegANDOR(SiS_P3d4,0x31,temp2,temp1);
+  /* TW: We store CRT1 ModeNo in CR34 */
+  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x34,ModeNo);
+  temp1 = (SiS_Pr->SiS_VBInfo & SetInSlaveMode) >> 8;
+  temp2 = ~(SetInSlaveMode >> 8);
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x31,temp2,temp1);
 }
 
+/* TW: Checked against 650+301, 650/LVDS (1.10.07) and 650/301LVx (1.10.6s) BIOS */
 void
-SiS_GetVBInfo301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
-                 USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+              USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT tempax,tempbx,temp;
-  USHORT modeflag;
-  UCHAR  OutputSelect=*pSiS_OutputSelect;
+  USHORT modeflag, resinfo=0;
+  UCHAR  OutputSelect = *SiS_Pr->pSiS_OutputSelect;
 
-  if (ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-  } else {
-   	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  if (ModeNo<=0x13)
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  else {
+   	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
   }
-  SiS_SetFlag=0;
 
-  SiS_ModeType=modeflag&ModeInfoFlag;
-  
-  tempbx=0;
-  if(SiS_BridgeIsOn(BaseAddr)) {
-    	temp=SiS_GetReg1(SiS_P3d4,0x30);
-    	if((SiS_IF_DEF_LVDS==0) && (SiS_VBType&(VB_SIS301LV|VB_SIS302LV))) {
-       		temp=temp&0xbf;                                        	/*301lvds disable CRT2*/
-    	}
-    	if(SiS_IF_DEF_FSTN){                             		/*fstn must set CR30=0x21 */
-       		temp=0x21;
-       		SiS_SetReg1(SiS_P3d4,0x30,temp);
-    	}
-    	tempbx=tempbx|temp;
-    	temp=SiS_GetReg1(SiS_P3d4,0x31);
-    	tempax=temp<<8;
-    	tempbx=tempbx|tempax;
-    	temp=SetCHTVOverScan|SetInSlaveMode|DisableCRT2Display;  	/* ynlai */
-   	temp=0xFFFF^temp;
-    	tempbx=tempbx&temp;
+  SiS_Pr->SiS_SetFlag = 0;
+
+  SiS_Pr->SiS_ModeType = modeflag & ModeInfoFlag;
+
+  tempbx = 0;
+  if(SiS_BridgeIsOn(SiS_Pr,BaseAddr,HwDeviceExtension) == 0) {              /* TW: "== 0" inserted from 630/301B BIOS */
+    	temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+	if(SiS_Pr->SiS_HiVision & 0x03) {	/* TW: New from 650/301LVx 1.10.6s */
+	     temp &= (SetCRT2ToHiVisionTV | SwitchToCRT2 | SetSimuScanMode); 	/* 0x83 */
+	     temp |= SetCRT2ToHiVisionTV;   					/* 0x80 */
+	}
+	if(SiS_Pr->SiS_HiVision & 0x04) {	/* TW: New from 650/301LVx 1.10.6s */
+	     temp &= (SetCRT2ToHiVisionTV | SwitchToCRT2 | SetSimuScanMode); 	/* 0x83 */
+	     temp |= SetCRT2ToSVIDEO;  						/* 0x08 */
+	}
+#if 0   /* TW: Not in 650/301LVx 1.10.6s BIOS */
+    	if(SiS_Pr->SiS_VBType & VB_SIS30xLV) {
+       		temp &= 0xbf;   /* 301lvds disable CRT2RAMDAC */
+    	}
+#endif
+    	if(SiS_Pr->SiS_IF_DEF_FSTN) {   /* fstn must set CR30=0x21 */
+       		temp = (SetCRT2ToLCD | SetSimuScanMode);
+       		SiS_SetReg1(SiS_Pr->SiS_P3d4,0x30,temp);
+    	}
+    	tempbx |= temp;
+    	temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31);
+	tempax = temp << 8;
+        tempax &= (LoadDACFlag | DriverMode | SetDispDevSwitch |        /* TW: Inserted from 650/LVDS+301LV BIOS */
+		         SetNotSimuMode | SetPALTV);                    /* TW: Inserted from 650/LVDS+301LV BIOS */
+    	tempbx |= tempax;
+    	temp = SetCHTVOverScan | SetInSlaveMode | DisableCRT2Display;
+   	temp = 0xFFFF ^ temp;
+    	tempbx &= temp;
 #ifdef SIS315H
-     	/*301b*/
-    	if((SiS_IF_DEF_LVDS==0) && (SiS_VBType&(VB_SIS302B|VB_SIS302LV))){
-       		temp=SiS_GetReg1(SiS_P3d4,0x38);
-       		if(temp==0x03)
-          		tempbx=tempbx|(SetCRT2ToLCDA);
-    	}
-    	/*end301b*/
+	if(HwDeviceExtension->jChipType >= SIS_315H) {
+	   temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+    	   if(SiS_Pr->SiS_VBType & (VB_SIS302B | VB_SIS30xLV | VB_SIS30xNEW)) {
+                if((SiS_GetReg1(SiS_Pr->SiS_P3d4, 0x36) & 0x0f) == SiS_Pr->SiS_Panel1400x1050) {
+		    if(tempbx & SetCRT2ToLCD) {
+		        if(ModeNo <= 0x13) {
+			     if(SiS_CRT2IsLCD(SiS_Pr, BaseAddr)) {
+			          if(!(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & (SetNotSimuMode >> 8))) {
+				      SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x38,0x03);
+				  }
+			     }
+			}
+		    }
+		}
+       		if((temp & (EnableDualEdge | SetToLCDA))
+		          == (EnableDualEdge | SetToLCDA))   /* TW: BIOS only tests these bits, added "& ..." */
+          		tempbx |= SetCRT2ToLCDA;
+    	   }
+	   /* TW: Inserted from 650/LVDS 1.10.07 BIOS: */
+	   if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+	        if(temp & SetToLCDA)
+		        tempbx |= SetCRT2ToLCDA;
+	        if(temp & EnableLVDSHiVision)
+		        tempbx |= SetCRT2ToHiVisionTV;
+	   }
+	}
 #endif
-    	if(SiS_IF_DEF_LVDS==0) {
-      		if(SiS_IF_DEF_HiVision) temp=0x80FC;
-      		else temp=0x807C;
+    	if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+	        temp = SetCRT2ToLCDA   | SetCRT2ToSCART      | SetCRT2ToLCD |
+		       SetCRT2ToRAMDAC | SetCRT2ToSVIDEO     | SetCRT2ToAVIDEO; /* = 0x807C; */
+      		if(SiS_Pr->SiS_IF_DEF_HiVision == 1)
+                     temp |= SetCRT2ToHiVisionTV; /* = 0x80FC; */
     	} else {
-      		if(SiS_IF_DEF_CH7005==1) {
-        		temp = SetCRT2ToTV|SetCRT2ToLCD;
-      		} else {
+                if(HwDeviceExtension->jChipType >= SIS_315H) {
+                    if(SiS_Pr->SiS_IF_DEF_CH70xx != 0)
+        		temp = SetCRT2ToLCDA   | SetCRT2ToSCART |
+			       SetCRT2ToLCD    | SetCRT2ToHiVisionTV |
+			       SetCRT2ToAVIDEO | SetCRT2ToSVIDEO;  /* = 0x80bc */
+      		    else
+        		temp = SetCRT2ToLCDA | SetCRT2ToLCD;
+		} else {
+      		    if(SiS_Pr->SiS_IF_DEF_CH70xx != 0)
+        		temp = SetCRT2ToTV | SetCRT2ToLCD;
+      		    else
         		temp = SetCRT2ToLCD;
-      		}
-    	}
-    	if(!(tempbx&temp)) {
-      		tempax=tempax|DisableCRT2Display;
-      		tempbx=0;
+		}
     	}
-   
-   	if(SiS_IF_DEF_LVDS==0) {
-      		if(tempbx&SetCRT2ToLCDA) {                                    /*301b*/
-        		tempbx=tempbx&(0xFF00|SwitchToCRT2|SetSimuScanMode);
-      		} else if(tempbx&SetCRT2ToRAMDAC) {
-        		tempbx=tempbx&(0xFF00|SetCRT2ToRAMDAC|SwitchToCRT2|SetSimuScanMode);
-      		} else if((tempbx&SetCRT2ToLCD)&&(!(SiS_VBType&VB_NoLCD)) ){              /*301dlvds*/
-        		tempbx=tempbx&(0xFF00|SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode);
-      		} else if(tempbx&SetCRT2ToSCART){
-        		tempbx=tempbx&(0xFF00|SetCRT2ToSCART|SwitchToCRT2|SetSimuScanMode);
-        		tempbx=tempbx|SetPALTV;
-      		} else if(tempbx&SetCRT2ToHiVisionTV){
-        		tempbx=tempbx&(0xFF00|SetCRT2ToHiVisionTV|SwitchToCRT2|SetSimuScanMode);
-  			/* ynlai begin */
-        		tempbx=tempbx|SetPALTV;
-  			/* ynlai end */
+
+    	if(!(tempbx & temp)) {
+      		tempax = DisableCRT2Display;
+      		tempbx = 0;
+    	}
+
+   	if(SiS_Pr->SiS_IF_DEF_LVDS==0) {
+      		if(tempbx & SetCRT2ToLCDA) {
+        		tempbx &= (0xFF00|SwitchToCRT2|SetSimuScanMode);
+      		} else if(tempbx & SetCRT2ToRAMDAC) {
+        		tempbx &= (0xFF00|SetCRT2ToRAMDAC|SwitchToCRT2|SetSimuScanMode);
+      		} else if((tempbx & SetCRT2ToLCD) && (!(SiS_Pr->SiS_VBType & VB_NoLCD)) ){
+        		tempbx &= (0xFF00|SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode);
+      		} else if(tempbx & SetCRT2ToSCART){
+        		tempbx &= (0xFF00|SetCRT2ToSCART|SwitchToCRT2|SetSimuScanMode);
+        		tempbx |= SetPALTV;
+		}
+#if 0		/* TW: Not done in 650/301LVx 1.10.6s BIOS */
+      		} else if(tempbx & SetCRT2ToHiVisionTV){
+        		tempbx &= (0xFF00|SetCRT2ToHiVisionTV|SwitchToCRT2|SetSimuScanMode);
+        		tempbx |= SetPALTV;
       		}
+#endif
    	} else { /* LVDS */
-      		if(SiS_IF_DEF_CH7005==1) {
-        		if(tempbx&SetCRT2ToTV)
-          			tempbx=tempbx&(0xFF00|SetCRT2ToTV|SwitchToCRT2|SetSimuScanMode);
+	        if(HwDeviceExtension->jChipType >= SIS_315H) {
+		    if(tempbx & SetCRT2ToLCDA)
+		        tempbx &= (0xFF00|SwitchToCRT2|SetSimuScanMode);
+		}
+      		if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+        	    if(tempbx & SetCRT2ToTV)
+          		 tempbx &= (0xFF00|SetCRT2ToTV|SwitchToCRT2|SetSimuScanMode);
       		}
-      		if(tempbx&SetCRT2ToLCD)
-        		tempbx=tempbx&(0xFF00|SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode);
+      		if(tempbx & SetCRT2ToLCD) {
+        		tempbx &= (0xFF00|SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode);
+		}
+	        if(HwDeviceExtension->jChipType >= SIS_315H) {
+		    if(tempbx & SetCRT2ToLCDA)
+		        tempbx |= SetCRT2ToLCD;
+		}
 	}
-    	if(tempax&DisableCRT2Display) {
-      		if(!(tempbx&(SwitchToCRT2|SetSimuScanMode))) {
-        		tempbx=SetSimuScanMode|DisableCRT2Display;
+    	if(tempax & DisableCRT2Display) {
+      		if(!(tempbx & (SwitchToCRT2 | SetSimuScanMode))) {
+        		tempbx = SetSimuScanMode | DisableCRT2Display;
       		}
     	}
-    	if(!(tempbx&DriverMode)){
-      		tempbx=tempbx|SetSimuScanMode;
+    	if(!(tempbx & DriverMode)){
+      		tempbx |= SetSimuScanMode;
     	}
-	/* TW: LVDS bridge can only be slave in 8bpp modes */
-	if ((SiS_IF_DEF_LVDS==1) &&
-		(ModeNo == 0x2e || ModeNo == 0x30 ||
-			ModeNo == 0x38 || ModeNo == 0x3a)) {
-		tempbx=tempbx|SetSimuScanMode|SetInSlaveMode;
+
+	/* TW: LVDS (LCD/TV) and 630+301B (LCD) can only be slave in 8bpp modes */
+	if( (SiS_Pr->SiS_IF_DEF_LVDS == 1) && (SiS_Pr->SiS_ModeType <= ModeVGA) ) {
+		modeflag &= (~CRT2Mode);
+	}
+	if( (HwDeviceExtension->jChipType < SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+	        if(SiS_Pr->SiS_ModeType <= ModeVGA) {
+			if(tempbx & SetCRT2ToLCD) {
+		    		modeflag &= (~CRT2Mode);
+			}
+	        }
 	}
 	/* TW end */
-    	if(!(tempbx&SetSimuScanMode)){
-      		if(tempbx&SwitchToCRT2) {
-        		if(!(modeflag&CRT2Mode)) {
-            			tempbx=tempbx|SetSimuScanMode;
-        		}
 
+    	if(!(tempbx & SetSimuScanMode)){
+      		if(tempbx & SwitchToCRT2) {
+        	    if(!(modeflag & CRT2Mode)) {
+			if( (HwDeviceExtension->jChipType >= SIS_315H) &&
+			        (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) ) {
+			    if(resinfo != 0x0a)
+                                tempbx |= SetSimuScanMode;
+			} else {
+            			tempbx |= SetSimuScanMode;
+	                }
+        	    }
       		} else {
-        		if(!(SiS_BridgeIsEnable(BaseAddr,HwDeviceExtension))) {
-          			if(!(tempbx&DriverMode)) {
-            				if(SiS_BridgeInSlave()) {
-              					tempbx=tempbx|SetInSlaveMode;
-            				}
-          			}
-        		}
-      		}
-    	}
-    	if(!(tempbx&DisableCRT2Display)) {
-     		 if(tempbx&DriverMode) {
-        		if(tempbx&SetSimuScanMode) {
-          			if(!(modeflag&CRT2Mode)) {
-            				tempbx=tempbx|SetInSlaveMode;
-            				if(SiS_IF_DEF_LVDS==0) {
-              					if(tempbx&SetCRT2ToTV) {
-                					if(!(tempbx&SetNotSimuMode))
-								SiS_SetFlag=SiS_SetFlag|TVSimuMode;
-              					}
-            				}
-          			}
-        		}
-      		} else {
-        		tempbx=tempbx|SetInSlaveMode;
-        		if(SiS_IF_DEF_LVDS==0) {
-          			if(tempbx&SetCRT2ToTV) {
-            				if(!(tempbx&SetNotSimuMode))
-						SiS_SetFlag=SiS_SetFlag|TVSimuMode;
-          			}
-        		}
+        	    if(!(SiS_BridgeIsEnable(SiS_Pr,BaseAddr,HwDeviceExtension))) {
+          		if(!(tempbx & DriverMode)) {
+            		    if(SiS_BridgeInSlave(SiS_Pr)) {
+				tempbx |= SetSimuScanMode; /* TW: from BIOS 650/301/301LV/LVDS */
+            		    }
+                        }
+                    }
       		}
     	}
-    	if(SiS_IF_DEF_CH7005==1) {
-      		temp=SiS_GetReg1(SiS_P3d4,0x35);
-      		if(temp&TVOverScan) tempbx=tempbx|SetCHTVOverScan;
+
+    	if(!(tempbx & DisableCRT2Display)) {
+            if(tempbx & DriverMode) {
+                if(tempbx & SetSimuScanMode) {
+          	    if(!(modeflag & CRT2Mode)) {
+	                if( (HwDeviceExtension->jChipType >= SIS_315H) &&
+			       (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) ) {
+			     if(resinfo != 0x0a) {  /* TW: Inserted from 650/301 BIOS */
+			          tempbx |= SetInSlaveMode;
+            		          if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+              		 	     if(tempbx & SetCRT2ToTV) {
+                		         if(!(tempbx & SetNotSimuMode))
+					     SiS_Pr->SiS_SetFlag |= TVSimuMode;
+              			     }
+                                  }
+			     }                      /* TW: Inserted from 650/301 BIOS */
+		        } else {
+            		    tempbx |= SetInSlaveMode;
+            		    if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+              		        if(tempbx & SetCRT2ToTV) {
+                		    if(!(tempbx & SetNotSimuMode))
+					SiS_Pr->SiS_SetFlag |= TVSimuMode;
+              			}
+            		    }
+                        }
+	            }
+                }
+            } else {
+                tempbx |= SetInSlaveMode;
+        	if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+          	    if(tempbx & SetCRT2ToTV) {
+            		if(!(tempbx & SetNotSimuMode))
+			    SiS_Pr->SiS_SetFlag |= TVSimuMode;
+          	    }
+        	}
+      	    }
     	}
+	
+	if(SiS_Pr->SiS_CHOverScan) {
+    	   if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+      		temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x35);
+      		if((temp & TVOverScan) || (SiS_Pr->SiS_CHOverScan == 1) )
+		      tempbx |= SetCHTVOverScan;
+    	   }
+	   if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+      		temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x79);
+      		if( (temp & 0x80) || (SiS_Pr->SiS_CHOverScan == 1) )
+		      tempbx |= SetCHTVOverScan;
+    	   }
+	}
   }
-  /*add PALMN*/
-  if(SiS_IF_DEF_LVDS==0) {
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS==0) {
 #ifdef SIS300
      	if((HwDeviceExtension->jChipType==SIS_630)||
            (HwDeviceExtension->jChipType==SIS_730)) {
-           	if(!(OutputSelect&EnablePALMN))
-             		SiS_SetRegAND(SiS_P3d4,0x35,0x3F);
-           	if(tempbx&SetCRT2ToTV) {
-              		if(tempbx&SetPALTV) {
-                  		temp=SiS_GetReg1(SiS_P3d4,0x35);
-                  		temp=temp&0xC0;
-                  		if(temp==0x40)
-                    			tempbx=tempbx&(~SetPALTV);
+	   	if(ROMAddr && SiS_Pr->SiS_UseROM) {
+			OutputSelect = ROMAddr[0xfe];
+                }
+           	if(!(OutputSelect & EnablePALMN))
+             		SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0x3F);
+           	if(tempbx & SetCRT2ToTV) {
+              		if(tempbx & SetPALTV) {
+                  		temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x35);
+				/* temp &= 0xC0;  */ /* TW: BIOS only tests 0x40, not 0x80 */
+                  		if(temp & 0x40)
+                    			tempbx &= (~SetPALTV);
              		}
           	}
       	}
 #endif
 #ifdef SIS315H
-     	if((HwDeviceExtension->jChipType == SIS_315H)||
-           (HwDeviceExtension->jChipType == SIS_315PRO)||
-           (HwDeviceExtension->jChipType == SIS_550)||   /* 05/02/01 ynlai for 550 */
-           (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-           (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-           (HwDeviceExtension->jChipType == SIS_650)) {
-		if(!(OutputSelect&EnablePALMN))
-        		SiS_SetRegAND(SiS_P3d4,0x38,0x3F);
-   		if(tempbx&SetCRT2ToTV) {
-    			if(tempbx&SetPALTV) {
-               			temp=SiS_GetReg1(SiS_P3d4,0x38);
-               			temp=temp&0xC0;
-               			if(temp==0x40)
-               				tempbx=tempbx&(~SetPALTV);
+     	if(HwDeviceExtension->jChipType >= SIS_315H) {
+	        if(ROMAddr && SiS_Pr->SiS_UseROM) {
+			OutputSelect = ROMAddr[0xf3];
+                }
+		if(!(OutputSelect & EnablePALMN))
+        		SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0x3F);
+   		if(tempbx & SetCRT2ToTV) {
+    			if(tempbx & SetPALTV) {
+               			temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+               			if(temp & 0x40)
+               				tempbx &= (~SetPALTV);
               		}
         	}
   	}
 #endif
- /*end add*/
   }
-  SiS_VBInfo=tempbx;
+
+  SiS_Pr->SiS_VBInfo=tempbx;
+
+#ifdef TWDEBUG
 #ifdef LINUX_KERNEL
-  printk(KERN_INFO "sisfb: (VBInfo = %x)\n", SiS_VBInfo);
+  printk(KERN_INFO "sisfb: (VBInfo= 0x%04x, SetFlag=0x%04x)\n", SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag);
 #endif
 #ifdef LINUX_XF86
-  xf86DrvMsg(0, X_INFO, "(init301.c: VBInfo = %x)\n", SiS_VBInfo);
+  xf86DrvMsg(0, X_PROBED, "(init301: VBInfo=0x%04x, SetFlag=0x%04x)\n", SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag);
+#endif
+#endif
+
+#if 0  /* TW: Incomplete! (But does not seem to be required) */
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+     /* TW: From A901/630+301B BIOS */
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+         if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x80)
+     }
+     if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+         if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x80)
+	     if( [si] == 3) ModeIdIndex = 0x3f2b;
+	 }
+     }
+     SiS_SetRegAND(SiS_Pr->SiS_P3d4, 0x31, 0xF7);
+     if(ModeNo == 0x13) bp+4 = 0x03;
+  } else {
+     /* From 650/301LVx BIOS: */
+     SiS_SetRegAND(SiS_Pr->SiS_P3d4, 0x31, 0xF7);
+     if(ModeNo == 0x13) bp+4 = 0x03;
+     else bp+4 = ModeNo;
+  }
 #endif
+
+  /* TW: 630/301B and 650/301 (not 301LV!) BIOSes do more here, but this seems for DOS mode */
+
 }
 
 void
-SiS_GetRAMDAC2DATA(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                   USHORT RefreshRateTableIndex)
+SiS_GetRAMDAC2DATA(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                   USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT tempax,tempbx,temp;
   USHORT temp1,temp2,modeflag=0,tempcx;
   USHORT StandTableIndex,CRT1Index;
   USHORT ResInfo,DisplayType;
-  SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr=NULL;
+  const  SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr = NULL;
+
+  SiS_Pr->SiS_RVBHCMAX  = 1;
+  SiS_Pr->SiS_RVBHCFACT = 1;
+
+  if(ModeNo <= 0x13){
+
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+    	StandTableIndex = SiS_GetModePtr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
+    	tempax = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[0];
+    	tempbx = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[6];
+    	temp1 = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[7];
 
-  SiS_RVBHCMAX=1;
-  SiS_RVBHCFACT=1;
-  if(ModeNo<=0x13){
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-    	StandTableIndex = SiS_GetModePtr(ROMAddr,ModeNo,ModeIdIndex);
-    	tempax = SiS_StandTable[StandTableIndex].CRTC[0];
-    	tempbx = SiS_StandTable[StandTableIndex].CRTC[6];
-    	temp1=SiS_StandTable[StandTableIndex].CRTC[7];
-  } else {
-    if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-        			&& (SiS_VBInfo&SetCRT2ToLCDA) ) {
-    	/*add crt1ptr*/
-    	temp=SiS_GetLVDSCRT1Ptr(ROMAddr,ModeNo,ModeIdIndex,
+  } else {
+
+     if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) ) {
+
+    	temp = SiS_GetLVDSCRT1Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
 			RefreshRateTableIndex,&ResInfo,&DisplayType);
-    	if(temp==0){
-    		return;
-    	}
+
+    	if(temp == 0)  return;
+
     	switch(DisplayType) {
-    		case 0 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1;		break;
-    		case 1 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1;          break;
-    		case 2 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1;         break;
-    		case 3 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1_H;         break;
-    		case 4 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1_H;        break;
-    		case 5 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1_H;       break;
-    		case 6 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2;           break;
-    		case 7 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2;          break;
-    		case 8 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2;         break;
-    		case 9 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2_H;         break;
-    		case 10: LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2_H;        break;
-    		case 11: LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2_H;       break;
-    		case 12: LVDSCRT1Ptr = SiS_CHTVCRT1UNTSC;               break;
-    		case 13: LVDSCRT1Ptr = SiS_CHTVCRT1ONTSC;               break;
-    		case 14: LVDSCRT1Ptr = SiS_CHTVCRT1UPAL;                break;
-    		case 15: LVDSCRT1Ptr = SiS_CHTVCRT1OPAL;                break;
-    		case 16: LVDSCRT1Ptr = SiS_LVDSCRT1320x480_1;           break;
-    	}
-    	temp1=(LVDSCRT1Ptr+ResInfo)->CR[0];
-    	temp2=(LVDSCRT1Ptr+ResInfo)->CR[14];
-    	tempax=(temp1&0xFF)|((temp2&0x03)<<8);
-    	tempbx=(LVDSCRT1Ptr+ResInfo)->CR[6];
-    	tempcx=(LVDSCRT1Ptr+ResInfo)->CR[13]<<8;
-    	tempcx = tempcx&0x0100;
+    		case 0 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1;		break;
+    		case 1 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1;          break;
+    		case 2 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1;         break;
+    		case 3 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1_H;         break;
+    		case 4 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1_H;        break;
+    		case 5 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1_H;       break;
+    		case 6 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2;           break;
+    		case 7 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2;          break;
+    		case 8 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2;         break;
+    		case 9 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2_H;         break;
+    		case 10: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2_H;        break;
+    		case 11: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2_H;       break;
+		case 12: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1;           break;
+		case 13: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H;         break;
+		case 14: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1;         break;
+		case 15: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1_H;       break;
+		case 16: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2;         break;
+		case 17: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2_H;       break;
+    		case 18: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UNTSC;               break;
+    		case 19: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1ONTSC;               break;
+    		case 20: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UPAL;                break;
+    		case 21: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1OPAL;                break;
+    		case 22: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x480_1;           break;
+		case 23: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1;          break;
+    		case 24: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1_H;        break;
+    		case 25: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2;          break;
+    		case 26: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2_H;        break;
+    		case 27: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_1;          break;
+    		case 28: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_1_H;        break;
+    		case 29: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_2;          break;
+    		case 30: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_2_H;        break;
+		case 36: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_1;         break;
+		case 37: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_1_H;       break;
+		case 38: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_2;         break;
+		case 39: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_2_H;       break;
+    	}
+    	temp1  = (LVDSCRT1Ptr+ResInfo)->CR[0];
+    	temp2  = (LVDSCRT1Ptr+ResInfo)->CR[14];
+    	tempax = (temp1 & 0xFF) | ((temp2 & 0x03) << 8);
+    	tempbx = (LVDSCRT1Ptr+ResInfo)->CR[6];
+    	tempcx = (LVDSCRT1Ptr+ResInfo)->CR[13]<<8;
+    	tempcx = tempcx & 0x0100;
     	tempcx = tempcx << 2;
     	tempbx = tempbx | tempcx;
-    	temp1=(LVDSCRT1Ptr+ResInfo)->CR[7];
-    	/*add 301b*/
+    	temp1  = (LVDSCRT1Ptr+ResInfo)->CR[7];
+
     } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-    	CRT1Index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
-    	CRT1Index=CRT1Index&0x3F;
-    	temp1 = (USHORT)SiS_CRT1Table[CRT1Index].CR[0];
-    	temp2 = (USHORT)SiS_CRT1Table[CRT1Index].CR[14];
-    	tempax=(temp1&0xFF)|((temp2&0x03)<<8);
-    	tempbx = (USHORT)SiS_CRT1Table[CRT1Index].CR[6];
-    	tempcx = (USHORT)SiS_CRT1Table[CRT1Index].CR[13]<<8;
-    	tempcx = tempcx&0x0100;
+
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	CRT1Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+	if(HwDeviceExtension->jChipType < SIS_315H) {
+    	   CRT1Index &= 0x3F;
+	}
+    	temp1  = (USHORT)SiS_Pr->SiS_CRT1Table[CRT1Index].CR[0];
+    	temp2  = (USHORT)SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14];
+    	tempax = (temp1 & 0xFF) | ((temp2 & 0x03) << 8);
+    	tempbx = (USHORT)SiS_Pr->SiS_CRT1Table[CRT1Index].CR[6];
+    	tempcx = (USHORT)SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13]<<8;
+    	tempcx = tempcx & 0x0100;
     	tempcx = tempcx << 2;
     	tempbx = tempbx | tempcx;
-    	temp1 = (USHORT)SiS_CRT1Table[CRT1Index].CR[7];
-   }
+    	temp1  = (USHORT)SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7];
+
+    }
+
   }
-  if(temp1&0x01) tempbx=tempbx|0x0100;
-  if(temp1&0x20) tempbx=tempbx|0x0200;
-  tempax=tempax+5;
-  if(modeflag&Charx8Dot) tempax=tempax*8;
-  else tempax=tempax*9;
 
-  SiS_VGAHT=tempax;
-  SiS_HT=tempax;
+  if(temp1 & 0x01) tempbx |= 0x0100;
+  if(temp1 & 0x20) tempbx |= 0x0200;
+  tempax += 5;
+
+  /* Charx8Dot is no more used (and assumed), so we set it */
+  modeflag |= Charx8Dot;
+
+  if(modeflag & Charx8Dot) tempax *= 8;
+  else                     tempax *= 9;
+
+  /* TW: From 650/301LVx 1.10.6s */
+  if(modeflag & HalfDCLK)  tempax <<= 1;
+
+  SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = tempax;
   tempbx++;
-  SiS_VGAVT=tempbx;
-  SiS_VT=tempbx;
+  SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = tempbx;
 }
 
 void
-SiS_UnLockCRT2(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
+SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
 {
-  if(HwDeviceExtension->jChipType >= SIS_315H) {
-    	SiS_SetRegANDOR(SiS_Part1Port,0x2f,0xFF,0x01);
-  } else {
-    	SiS_SetRegANDOR(SiS_Part1Port,0x24,0xFF,0x01);
-  }
+  if(HwDeviceExtension->jChipType >= SIS_315H)
+    	SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2f,0x01);
+  else
+    	SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24,0x01);
 }
 
 void
-SiS_LockCRT2(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
+SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
 {
-  if(HwDeviceExtension->jChipType >= SIS_315H) {
-    	SiS_SetRegANDOR(SiS_Part1Port,0x2F,0xFE,0x00);
-  } else {
-     	SiS_SetRegANDOR(SiS_Part1Port,0x24,0xFE,0x00);
-  }
+  if(HwDeviceExtension->jChipType >= SIS_315H)
+    	SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2F,0xFE);
+  else
+     	SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x24,0xFE);
 }
 
 void
-SiS_EnableCRT2()
+SiS_EnableCRT2(SiS_Private *SiS_Pr)
 {
-  SiS_SetRegANDOR(SiS_P3c4,0x1E,0xFF,0x20);
+  SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
 }
 
+/* Checked against all BIOSes */
 void
-SiS_DisableBridge(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT  BaseAddr)
+SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
 {
-  USHORT temp1,tempah,temp;
+  USHORT tempah,pushax,temp=0;
+  UCHAR *ROMAddr = HwDeviceExtension->pjVirtualRomBase;
 
-  SiS_SetRegANDOR(SiS_P3c4,0x11,0xF7,0x08);
+  if (SiS_Pr->SiS_IF_DEF_LVDS == 0) {
 
-  /*SetPanelDelay(1); */
-  temp1=0x01;
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)))  {  /*301b*/
-    	if((SiS_IsVAMode(BaseAddr)))
-       		temp1=0x00;			/*no disable vb*/
-  }
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {   /* ===== TW: For 30xB/LV ===== */
 
-  if(SiS_IF_DEF_LVDS==0) {
-   if(!(temp1)){              /*301b*/
-    SiS_SetRegANDOR(SiS_Part2Port,0x00,0x0DF,0x00);   /* disable VB */
-    SiS_DisplayOff();
-    if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-      SiS_SetRegOR(SiS_Part1Port,0x00,0x80);  /* FUNCTION CTRL | alan,BScreenOff */
-    }
-    SiS_SetRegANDOR(SiS_P3c4,0x32,0xDF,0x00);
-    
-    temp = SiS_GetReg1(SiS_Part1Port,0); 
-    SiS_SetRegOR(SiS_Part1Port,0x00,0x10);  /* FUNCTION CTRL | alan,BScreenOff */
-/*
-     if(HwDeviceExtension->jChipType >= SIS_315H)
-     {
-      	SiS_SetRegAND(SiS_Part1Port,0x2E,0x7F);
-     }
-*/
-     SiS_SetRegANDOR(SiS_P3c4,0x1E,0xDF,0x00);
-     SiS_SetReg1(SiS_Part1Port,0,temp);
-    }
-    else {
-    if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))  /*301b*/
-      {
-        if(!(SiS_Is301B(BaseAddr))) {
-          SiS_SetRegAND(SiS_P3c4,0x32,0xDF);
-          if((!(SiS_IsDualEdge(BaseAddr)))&&(!(SiS_IsVAMode(BaseAddr))))
-            tempah=0x7F;
-          else if((!(SiS_IsDualEdge(BaseAddr)))&&(SiS_IsVAMode(BaseAddr)))
-            tempah=0xBF;
-          else
-            tempah=0x3F;
-          SiS_SetRegAND(SiS_Part4Port,0x1F,tempah);
-        }
-      }
-    }
-  }
-  else { /* LVDS */
-    if(SiS_IF_DEF_CH7005==1) {
-      SiS_Backup7005 = SiS_GetCH7005(0x0e);
-      SiS_SetCH7005(0x090E);
-    }
-    SiS_DisplayOff();
-    SiS_SetRegANDOR(SiS_P3c4,0x32,0xDF,0x00);
-    SiS_SetRegANDOR(SiS_P3c4,0x1E,0xDF,0x00);
-    SiS_UnLockCRT2(HwDeviceExtension,BaseAddr);
-    SiS_SetRegANDOR(SiS_Part1Port,0x01,0xFF,0x80);
-    SiS_SetRegANDOR(SiS_Part1Port,0x02,0xFF,0x40);
-  }
-  /*SetPanelDelay(0);  */
-  SiS_SetRegANDOR(SiS_P3c4,0x11,0xFB,0x04);
-}
+        if(HwDeviceExtension->jChipType < SIS_315H) {
 
-void
-SiS_EnableBridge(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT  BaseAddr)
-{
-  USHORT temp,tempah;
+	   /* 300 series */
 
-  SiS_SetRegANDOR(SiS_P3c4,0x11,0xFB,0x00);
+	   if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwDeviceExtension))) {
+	      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF7,0x08);
+	      SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+	   }
+	   if(SiS_Is301B(SiS_Pr,BaseAddr)) {
+	      SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0x3f);
+	      SiS_ShortDelay(SiS_Pr,1);
+	   }
+	   SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF);
+	   SiS_DisplayOff(SiS_Pr);
+	   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+	   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	   SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension,BaseAddr);
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80);
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40);
+	   if( (!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr))) ||
+	              (!(SiS_CR36BIOSWord23d(SiS_Pr,HwDeviceExtension))) ) {
+	      SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+              SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xFB,0x04);
+	   }
 
-  /*SetPanelDelay(0);        */
-  if(SiS_IF_DEF_LVDS==0) {
-    if( (!(SiS_IsVAMode(BaseAddr))) &&
-        (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))) {
-    		SiS_SetRegANDOR(SiS_Part2Port,0x00,0x1F,0x20);
-    } else {
-      temp=SiS_GetReg1(SiS_P3c4,0x32);
-      temp=temp&0xDF;
-      if(SiS_BridgeInSlave()) {
-        tempah=SiS_GetReg1(SiS_P3d4,0x30);
-        if(!(tempah&SetCRT2ToRAMDAC)) {
-         temp=temp|0x20;
-        }
-      }
-      SiS_SetReg1(SiS_P3c4,0x32,temp);
-      SiS_SetRegANDOR(SiS_P3c4,0x1E,0xFF,0x20);
+        } else {
 
-      if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-        temp=SiS_GetReg1(SiS_Part1Port,0x2E);
-        if (!(temp&0x80))
-          SiS_SetRegOR(SiS_Part1Port,0x2E,0x80);          /* by alan,BVBDOENABLE=1 */
-      }
-
-      SiS_SetRegANDOR(SiS_Part2Port,0x00,0x1F,0x20);
-
-      if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-      	temp=SiS_GetReg1(SiS_Part1Port,0x2E);
-     	if (!(temp&0x80))
-            SiS_SetRegOR(SiS_Part1Port,0x2E,0x80);          /* by alan,BVBDOENABLE=1 */
-      }
-   
-      SiS_SetRegANDOR(SiS_Part2Port,0x00,0x1F,0x20);
-      SiS_VBLongWait();
-      SiS_DisplayOn();
-      SiS_VBLongWait();
-    }  
-  /*add301b*/
-    if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-      if(!(SiS_Is301B(BaseAddr))){  
-        temp=SiS_GetReg1(SiS_Part1Port,0x2E);
-        if(!(temp&0x80))
-           SiS_SetRegOR(SiS_Part1Port,0x2E,0x80);
-        if((!(SiS_IsDualEdge(BaseAddr)))&&(!(SiS_IsVAMode(BaseAddr))))
-           tempah=0x80;
-        else if((!(SiS_IsDualEdge(BaseAddr)))&&(SiS_IsVAMode(BaseAddr)))
-           tempah=0x40;
-        else
-           tempah=0xC0;
-        SiS_SetRegOR(SiS_Part4Port,0x1F,tempah);
-      }
-     }  
-  /*end 301b*/
-  } else {                /*LVDS*/
-    SiS_EnableCRT2();
-    SiS_DisplayOn();
-    SiS_UnLockCRT2(HwDeviceExtension, BaseAddr);
-    SiS_SetRegANDOR(SiS_Part1Port,0x02,0xBF,0x00);
-    if(SiS_BridgeInSlave()) {
-      	SiS_SetRegANDOR(SiS_Part1Port,0x01,0x1F,0x00);
-    } else {
-      	SiS_SetRegANDOR(SiS_Part1Port,0x01,0x1F,0x40);
-    }
-    if(SiS_IF_DEF_CH7005) {
-        if (SiS_Backup7005 != 0xff) {
-		SiS_SetCH7005(((SiS_Backup7005<<8)|0x0E));
-		SiS_Backup7005 = 0xff;
-	} else SiS_SetCH7005(0x0B0E);
-    }
-  }
-  /*SetPanelDelay(1);  */
-  SiS_SetRegANDOR(SiS_P3c4,0x11,0xF7,0x00);
-}
+	   /* 310 series */
 
-void
-SiS_SetPanelDelay(USHORT DelayTime)
-{
-  USHORT PanelID;
+#ifdef SIS650301NEW  /* From 650/301LVx 1.10.6s */
+	   if(!(SiS_IsM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	       tempah = 0xef;
+	       if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	           tempah = 0xf7;
+               }
+	       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,tempah);
+	   }
 
-  PanelID=SiS_GetReg1(SiS_P3d4,0x36);
-  PanelID=PanelID>>4;
+	   SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
 
-  if(DelayTime==0) SiS_LCD_Wait_Time(SiS_PanelDelayTbl[PanelID].timer[0]);
-  else SiS_LCD_Wait_Time(SiS_PanelDelayTbl[PanelID].timer[1]);
-}
+	   if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	     	   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x00);
+	   } else if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+		   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x00);
+           }
 
-void
-SiS_LCD_Wait_Time(UCHAR DelayTime)
-{
-  USHORT i,j;
-  ULONG  temp,flag;
+	   SiS_SetReg3(SiS_Pr->SiS_P3c6,0x00);
 
-  flag=0;
-  for(i=0;i<DelayTime;i++) {
-    for(j=0;j<66;j++) {
-      temp=SiS_GetReg3(0x61);
-      temp=temp&0x10;
-      if(temp==flag) continue;
-      flag=temp;
-    }
-  }
-}
+           pushax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06);
 
-/*301b*/
-BOOLEAN
-SiS_Is301B(USHORT BaseAddr)
-{
-  USHORT flag;
+	   SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
 
-    flag=SiS_GetReg1(SiS_Part4Port,0x01);
-    if(flag>(0x0B0)) return(0); /*301b*/
-    else return(1);
- }
+           if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
 
-BOOLEAN
-SiS_IsDualEdge(USHORT BaseAddr)
-{
-#ifdef SIS315H
-    USHORT flag;
+	       SiS_DisplayOff(SiS_Pr);
+	       SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+	       SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+	       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1E,0xDF);
 
-     flag=SiS_GetReg1(SiS_P3d4,0x38);
-      if(flag&EnableDualEdge)
-        return (0);
-      else
-#endif
-      	return(1);
-}
+	   } else {
 
-BOOLEAN
-SiS_IsVAMode(USHORT BaseAddr)
-{
-  USHORT flag;
-         flag=SiS_GetReg1(SiS_P3d4,0x38);
-#ifdef SIS315H
-      if((flag&EnableDualEdge)&&(flag&SetToLCDA))
-        return (0);
-      else
-#endif
-      	return(1);
- }
+              SiS_DisplayOff(SiS_Pr);
+	      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
+	      SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+	      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+	      temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00);
+              SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10);
+	      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x00,temp);
 
-BOOLEAN
-SiS_IsDisableCRT2(USHORT BaseAddr)
-{
-  USHORT flag;
+	   }
 
-  flag=SiS_GetReg1(SiS_P3d4,0x30);
-  if(flag&0x20) return(0); /*301b*/
-  else return(1);
-}
-/*end 301b*/
+	   tempah = 0x3f;
+	   if(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	      tempah = 0x7f;
+	      if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		  tempah = 0xbf;
+              }
+	   }
+	   SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,tempah);
 
-BOOLEAN
-SiS_BridgeIsOn(USHORT BaseAddr)
-{
-  USHORT flag;
+	   SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
 
-  if(SiS_IF_DEF_LVDS==1){
-    return(1);
-  }
-  else {
-    flag=SiS_GetReg1(SiS_Part4Port,0x00);
-      if((flag==1)||(flag==2)) return(1); /*301b*/
-    else return(0);
-  }
-}
+	   if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	      SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xdf);
+	   }
+
+	   if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	      if(!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr))) {
+	         if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		    SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFD,0x00);
+                 }
+              }
+	   }
 
+	   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x06,pushax);
 
-BOOLEAN
-SiS_BridgeIsEnable(USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-  USHORT flag;
+#else	    /* TW: From 650/301LV BIOS */
 
-  if(SiS_BridgeIsOn(BaseAddr)==0) 
-  {
-    flag=SiS_GetReg1(SiS_Part1Port,0x0);
-    if(HwDeviceExtension->jChipType < SIS_315H) {
-      /* 300 series */
-      if(flag&0x0a0) return 1;
-      else	     return 0;
-    } else {
-      /* 310 series */
-      if(flag&0x050) return 1;
-      else           return 0;
-    }
-  }
-  return 0;
-}
+	   if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	     	   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x00);
+		   SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+	   } else if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+		   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x00);
+		   SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+           }
 
-BOOLEAN
-SiS_BridgeInSlave()
-{
-  USHORT flag1;
+           /* TW: 301B dependent code starts here in 650/301LV BIOS */
+	   if(SiS_Is301B(SiS_Pr,BaseAddr)) {
+	     tempah = 0x3f;
+             SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,tempah);
+           }
 
-  flag1=SiS_GetReg1(SiS_P3d4,0x31);
-  if(flag1&(SetInSlaveMode>>8)) return 1;
-  else  return 0;
-}
+           SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF);
+	   SiS_DisplayOff(SiS_Pr);
 
-BOOLEAN
-SiS_GetLCDResInfo301(ULONG ROMAddr,USHORT SiS_P3d4,
-                     USHORT ModeNo,USHORT ModeIdIndex)
-{
-  USHORT temp,modeflag,resinfo=0;
 
-  SiS_LCDResInfo=0;
-  SiS_LCDTypeInfo=0;
-  SiS_LCDInfo=0;
+           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
 
-  if (ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;  	/* si+St_ModeFlag  */
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-    	resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; 	/*si+Ext_ResInfo*/
-  }
+           SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
 
-  if(!(SiS_VBInfo&(SetCRT2ToLCD|SetCRT2ToLCDA))){
-    	return 0;
-  }
-  if(!(SiS_VBInfo&(SetSimuScanMode|SwitchToCRT2))) {
-    	return 0;
-  }
-  temp=SiS_GetReg1(SiS_P3d4,0x36);
-  /*fstn*/
-  if(SiS_IF_DEF_FSTN){
-   	temp=0x27;
-   	SiS_SetReg1(SiS_P3d4,0x36,temp);
-  } 
-  SiS_LCDTypeInfo=temp>>4;
-  SiS_LCDResInfo=temp&0x0F;
-  if(SiS_IF_DEF_LVDS==0) {
-    	if(SiS_LCDResInfo<Panel1024x768) SiS_LCDResInfo=Panel1024x768;
-  } else {
-    	if(SiS_LCDResInfo<Panel800x600) SiS_LCDResInfo=Panel800x600;
-  }
-#if 0
-  /* TW: No 1600x1200 panels? Don't think so... */
-  if(SiS_LCDResInfo>Panel640x480) SiS_LCDResInfo=Panel1024x768;
+	   temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00);
+           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10);
+	   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x00,temp);
+
+	   /* TW: Inserted from 650/301LV BIOS */
+	   if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	       if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	           if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		          SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+			  SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFD,0x00);
+			  SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 4);
+                   } else if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+                          SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+			  SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFD,0x00);
+			  SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 4);
+		   }
+	       }
+	    } else if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	       if(!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr))) {
+	            SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 2);
+		    SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFD,0x00);
+		    SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 4);
+               } else if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	           if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		          SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 2);
+			  SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFD,0x00);
+			  SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 4);
+                   } else if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+                          SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 2);
+			  SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFD,0x00);
+			  SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 4);
+		   }
+	       }
+	   } /* TW: 650/301LV end */
 #endif
-  if(SiS_LCDResInfo>Panel1600x1200) SiS_LCDResInfo=Panel1024x768;
-  /*fstn*/
-  if(SiS_IF_DEF_FSTN){
-       	SiS_LCDResInfo=Panel320x480;
-  }
-  temp=SiS_GetReg1(SiS_P3d4,0x37);
-  if(SiS_IF_DEF_FSTN){
-      	temp=0x04;
-      	SiS_SetReg1(SiS_P3d4,0x37,temp);
-  }
-  SiS_LCDInfo=temp;
 
-#ifdef LINUX_KERNEL
-  printk(KERN_INFO "sisfb: (LCDInfo = 0x%x LCDResInfo = 0x%x LCDTypeInfo = 0x%x)\n",
-                   SiS_LCDInfo, SiS_LCDResInfo, SiS_LCDTypeInfo);
-#endif
-#ifdef LINUX_XF86
-  xf86DrvMsg(0, X_INFO, "(init301.c: LCDInfo = 0x%x LCDResInfo = 0x%x LCDTypeInfo = 0x%x)\n",
-			SiS_LCDInfo, SiS_LCDResInfo, SiS_LCDTypeInfo);
-#endif
+	}
 
-  if(SiS_IF_DEF_LVDS==1){
-     if(modeflag&HalfDCLK){
-        if(SiS_IF_DEF_TRUMPION==0){
-            if(!(SiS_LCDInfo&LCDNonExpanding)){
-               if(ModeNo>0x13) {
-                  if(SiS_LCDResInfo==Panel1024x768){
-                      if(resinfo==4){                                /* 512x384  */
-                           SiS_SetFlag=SiS_SetFlag|EnableLVDSDDA;
-                      }
-                  } else {
-                      if(SiS_LCDResInfo==Panel800x600){
-                           if(resinfo==3){                             /*400x300  */
-                                SiS_SetFlag=SiS_SetFlag|EnableLVDSDDA;
-                           }
-                      }
-                  }
-               }
-           } else { /* NonExpanding */
-              SiS_SetFlag=SiS_SetFlag|EnableLVDSDDA;
-           }
-        } else { /* TRUMPION */
-          SiS_SetFlag=SiS_SetFlag|EnableLVDSDDA;
-        }
-     }
-  }
+      } else {     /* ============ TW: For 301 ================ */
 
-  if(SiS_VBInfo&SetInSlaveMode){
-    	if(SiS_VBInfo&SetNotSimuMode){
-      		SiS_SetFlag=SiS_SetFlag|LCDVESATiming;
-    	}
-  } else {
-    	SiS_SetFlag=SiS_SetFlag|LCDVESATiming;
-  }
-  return 1;
-}
+        if(HwDeviceExtension->jChipType < SIS_315H) {
+            if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) {
+                SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF0,0x0B);
+	        SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 1);
+	    }
+	}
 
-void
-SiS_PresetScratchregister(USHORT SiS_P3d4,PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-  /*SiS_SetReg1(SiS_P3d4,0x30,0x21);  */
-  /*SiS_SetReg1(SiS_P3d4,0x31,0x41);  */
-  /*SiS_SetReg1(SiS_P3d4,0x32,0x28);  */
-  /*SiS_SetReg1(SiS_P3d4,0x33,0x22);  */
-  /*SiS_SetReg1(SiS_P3d4,0x35,0x43);  */
-  /*SiS_SetReg1(SiS_P3d4,0x36,0x01);  */
-  /*SiS_SetReg1(SiS_P3d4,0x37,0x00);  */
-}
+        SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF);           /* disable VB */
+        SiS_DisplayOff(SiS_Pr);
 
-void
-SiS_LongWait()
-{
-  USHORT i;
+        if(HwDeviceExtension->jChipType >= SIS_315H) {
+            SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
+	}
 
-  i=SiS_GetReg1(SiS_P3c4,0x1F);
-  if(!(i&0xC0)) {
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);                /* disable lock mode */
 
+	if(HwDeviceExtension->jChipType >= SIS_315H) {
+            temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00);
+            SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10);
+	    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
+	    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x00,temp);
+	} else {
+            SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);            /* disable CRT2 */
+	}
+
+      }
+
+  } else {     /* ============ TW: For LVDS =============*/
+
+    if(HwDeviceExtension->jChipType < SIS_315H) {
+
+	/* 300 series */
+
+	if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+#if 0	/* TW: Implemented this for power saving, but it's not worth
+         *     the problems
+	 */
+	    if(SiS_Pr->SiS_Backup70xx == 0xff) {
+		SiS_Pr->SiS_Backup70xx = SiS_GetCH700x(SiS_Pr,0x0e);
+	    }
+#endif
+	    SiS_SetCH700x(SiS_Pr,0x090E);
+	}
+
+	if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x11) & 0x08)) {
+
+	    if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x40)) {
+
+	        if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwDeviceExtension))) {
+
+                     SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+
+		     if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06) & 0x1c)) {
+		         SiS_DisplayOff(SiS_Pr);
+	             }
+
+	             SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF7,0x08);
+	             SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+                }
+            }
+	}
+
+	SiS_DisplayOff(SiS_Pr);
+
+	SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+
+	SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension,BaseAddr);
+	SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80);
+	SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40);
+
+	if( (!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr))) ||
+	              (!(SiS_CR36BIOSWord23d(SiS_Pr,HwDeviceExtension))) ) {
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+		SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xFB,0x04);
+	}
+
+    } else {
+
+	/* 310 series */
+
+	if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+		if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+			SiS_Chrontel701xBLOff(SiS_Pr);
+			SiS_Chrontel701xOff(SiS_Pr);
+		} else if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+			SiS_Chrontel701xBLOff(SiS_Pr);
+			SiS_Chrontel701xOff(SiS_Pr);
+		}
+
+		if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+			SiS_SetCH701x(SiS_Pr,0x0149);
+		} else if(SiS_IsTVOrYPbPr(SiS_Pr,HwDeviceExtension, BaseAddr))  {
+			SiS_SetCH701x(SiS_Pr,0x0149);
+		}
+	}
+
+	if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		SiS_DisplayOff(SiS_Pr);
+	} else if(!(SiS_IsTVOrYPbPr(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		SiS_DisplayOff(SiS_Pr);
+	}
+
+	if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
+	} else if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
+	}
+
+	SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+
+	if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	} else if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	}
+
+	if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+		SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf);
+	}
+
+	if(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+		SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xff);
+	} else {
+		SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
+	}
+
+	SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension, BaseAddr);
+
+	if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7);
+	} else if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7);
+	}
+
+#if 0  /* TW: BIOS code makes no sense */
+       if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+           if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	        if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+		  /* Nothing there! */
+		}
+           }
+       }
+#endif
+
+    }  /* 310 series */
+
+  }  /* LVDS */
+
+}
+
+/* TW: Checked against all BIOSes */
+void
+SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+  USHORT temp=0,tempah,pushax,temp1;
+  UCHAR *ROMAddr = HwDeviceExtension->pjVirtualRomBase;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {   /* TW: ====== For 301B et al  ====== */
+
+      if(HwDeviceExtension->jChipType < SIS_315H) {
+
+         /* 300 series */
+
+	 if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) {
+	    SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xFB);
+	    if(!(SiS_CR36BIOSWord23d(SiS_Pr,HwDeviceExtension))) {
+	       SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 0);
+	    }
+	    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);   /* Enable CRT2 */
+/*	    DoSomeThingPCI_On(SiS_Pr) */
+            SiS_DisplayOn(SiS_Pr);
+	    SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension, BaseAddr);
+	    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF);
+	    if(SiS_BridgeInSlave(SiS_Pr)) {
+      		SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F);
+      	    } else {
+      		SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40);
+            }
+	    if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x40)) {
+	        if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16) & 0x10)) {
+		    if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwDeviceExtension))) {
+		        SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
+                    }
+		    SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+                    SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF7,0x00);
+                }
+	    }
+         } else {
+	   temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32) & 0xDF;             /* lock mode */
+           if(SiS_BridgeInSlave(SiS_Pr)) {
+              tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+              if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
+           }
+           SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
+	   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1F,0x20);        /* enable VB processor */
+	   if(SiS_Is301B(SiS_Pr,BaseAddr)) {
+              SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,0xC0);
+	      SiS_DisplayOn(SiS_Pr);
+	   } else {
+	      SiS_VBLongWait(SiS_Pr);
+	      SiS_DisplayOn(SiS_Pr);
+	      SiS_VBLongWait(SiS_Pr);
+	   }
+	 }
+
+      } else {
+
+         /* 310 series */
+
+#ifdef SIS650301NEW   /* TW: From 650/301LVx 1.10.6s */
+
+         if(!(SiS_IsM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	       tempah = 0x10;
+	       if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	           tempah = 0x08;
+               }
+	       SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,tempah);
+	 }
+
+	 SiS_SetReg3(SiS_Pr->SiS_P3c6,0x00);
+
+	 SiS_DisplayOff(SiS_Pr);
+
+	 pushax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06);
+
+	 if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
+	     (SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) ) {
+             if(!(SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) {
+	        SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
+	     }
+	 }
+
+	 if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+             temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32) & 0xDF;
+	     if(SiS_BridgeInSlave(SiS_Pr)) {
+                tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+                if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
+             }
+             SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
+
+	     SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                   /* enable CRT2 */
+	     SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+	 }
+
+	 if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x20);
+	 }
+
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20);
+
+	 tempah = 0xc0;
+	 if(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	     tempah = 0x80;
+	     if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	        tempah = 0x40;
+             }
+	 }
+         SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,tempah);
+
+	 SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
+
+	 if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	    if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
+	        ((SiS_CRT2IsLCD(SiS_Pr,BaseAddr))) ) {
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+                SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+		SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xfe,0x01);
+	    }
+	 }
+
+	 SiS_SetReg1(SiS_Pr->SiS_P3c4,0x06,pushax);
+	 SiS_DisplayOn(SiS_Pr);
+	 SiS_SetReg3(SiS_Pr->SiS_P3c6,0xff);
+
+	 if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+	 }
+
+         SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
+	 SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x0c);
+	 SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20);
+	 SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x05);
+	 SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0x60);
+	 SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x00);
+	 SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
+	 SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40);
+
+#else	 /* TW: From 650/301LV BIOS (different PanelDelay!) */
+
+	 if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	     SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xfd,0x02);
+	     SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 0);
+	 } else if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) {
+	     SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xfd,0x02);
+	     SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 0);
+	 }
+	 /* TW: --- end --- */
+
+         if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+            temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32) & 0xDF;
+	    if(SiS_BridgeInSlave(SiS_Pr)) {
+               tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+               if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
+            }
+            SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
+
+	    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                   /* enable CRT2 */
+
+/*          SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2E,0x7F);   */ 	/* TW: Not done in 650/301LV BIOS */
+            temp=SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2E);
+            if (!(temp & 0x80))
+                   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
+          }
+
+          SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1F,0x20);        /* enable VB processor */
+
+          if(SiS_Is301B(SiS_Pr,BaseAddr)) {
+
+             SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,0xc0);
+
+             if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)))   /* TW: "if" new from 650/301LV BIOS */
+	        SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7F);
+
+          } else {
+
+             SiS_VBLongWait(SiS_Pr);
+             SiS_DisplayOn(SiS_Pr);
+	     if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)))  {  /* TW: "if" new from 650/301LV BIOS */
+	        SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7F);
+                SiS_VBLongWait(SiS_Pr);
+	     }
+
+          }
+
+	  /* TW: Entire section from 650/301LV BIOS */
+	  if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	     if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+/*	        if (!(SiS_WeHaveBacklightCtrl(HwDeviceExtension, BaseAddr))) {  */ /* TW: BIOS code makes no sense */
+		   SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
+		   SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+		   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x01);
+/*              }   */
+             } else if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) {
+/*	        if (!(SiS_WeHaveBacklightCtrl(HwDeviceExtension, BaseAddr))) {  */ /* TW: BIOS code makes no sense */
+		   SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
+		   SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+		   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x01);
+/*              }   */
+	     }
+	  }
+
+#endif
+
+      }
+
+    } else {	/* ============  TW: For 301 ================ */
+
+       if(HwDeviceExtension->jChipType < SIS_315H) {
+            if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) {
+                SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF0,0x0B);
+	        SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 0);
+	    }
+       }
+
+       temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32) & 0xDF;          /* lock mode */
+       if(SiS_BridgeInSlave(SiS_Pr)) {
+         tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+         if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
+       }
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
+
+       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                  /* enable CRT2 */
+
+       if(HwDeviceExtension->jChipType >= SIS_315H) {
+         temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2E);
+         if(!(temp & 0x80))
+           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);         /* BVBDOENABLE=1 */
+       }
+
+       SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1F,0x20);     /* enable VB processor */
+
+       SiS_VBLongWait(SiS_Pr);
+       SiS_DisplayOn(SiS_Pr);
+       if(HwDeviceExtension->jChipType >= SIS_315H) {
+           SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+       }
+       SiS_VBLongWait(SiS_Pr);
+
+       if(HwDeviceExtension->jChipType < SIS_315H) {
+            if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) {
+	        SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 1);
+                SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF0,0x03);
+	    }
+       }
+
+    }
+
+  } else {   /* =================== TW: For LVDS ================== */
+
+    if(HwDeviceExtension->jChipType < SIS_315H) {
+
+      /* 300 series */
+
+      if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) {
+         SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xFB);
+	 if(!(SiS_CR36BIOSWord23d(SiS_Pr,HwDeviceExtension))) {
+	    SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 0);
+	 }
+      }
+
+      SiS_EnableCRT2(SiS_Pr);
+      SiS_DisplayOn(SiS_Pr);
+      SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension, BaseAddr);
+      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF);
+      if(SiS_BridgeInSlave(SiS_Pr)) {
+      	SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F);
+      } else {
+      	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40);
+      }
+
+      if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+        if(!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr))) {
+#if 0	/* TW: Implemented this for power saving, but it's not worth
+         *     the problems
+	 */
+           if(SiS_Pr->SiS_Backup70xx != 0xff) {
+		SiS_SetCH700x(SiS_Pr,((SiS_Pr->SiS_Backup70xx<<8)|0x0E));
+		SiS_Pr->SiS_Backup70xx = 0xff;
+	   } else
+#endif
+	        SiS_SetCH700x(SiS_Pr,0x0B0E);
+        }
+      }
+
+      if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) {
+          if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x40)) {
+              if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16) & 0x10)) {
+	          if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwDeviceExtension))) {
+			SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
+        		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
+		  }
+		  SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+                  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xF7);
+              }
+	  }
+      }
+
+    } else {
+
+       /* 310 series */
+
+#if 0  /* BIOS code makes no sense */
+       if(SiS_IsVAMode()) {
+          if(SiS_IsLCDOrLCDA()) {
+	  }
+       }
+#endif
+
+       SiS_EnableCRT2(SiS_Pr);
+       SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension, BaseAddr);
+
+       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7);
+
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+          temp = SiS_GetCH701x(SiS_Pr,0x66);
+	  temp &= 0x20;
+	  SiS_Chrontel701xBLOff(SiS_Pr);
+       }
+
+       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
+
+       temp1 = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2E);
+       if (!(temp1 & 0x80))
+           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
+
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+           if(temp) {
+	       SiS_Chrontel701xBLOn(SiS_Pr);
+	   }
+       }
+
+       if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20);
+       }
+
+       if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+           SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+       }
+
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+
+       		if(SiS_IsTVOrYPbPr(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+           		SiS_Chrontel701xOn(SiS_Pr,HwDeviceExtension, BaseAddr);
+         	}
+
+         	if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+           		SiS_ChrontelDoSomething1(SiS_Pr,HwDeviceExtension, BaseAddr);
+         	} else if(SiS_IsLCDOrLCDA(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+           		SiS_ChrontelDoSomething1(SiS_Pr,HwDeviceExtension, BaseAddr);
+        	}
+
+       }
+
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+       	 	if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+ 	   		if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	            		SiS_Chrontel701xBLOn(SiS_Pr);
+	            		SiS_ChrontelDoSomething4(SiS_Pr,HwDeviceExtension, BaseAddr);
+           		} else if(SiS_IsLCDOrLCDA(SiS_Pr,HwDeviceExtension, BaseAddr))  {
+/*	      			if(!SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)) {  */ /* TW: makes no sense */
+            				SiS_Chrontel701xBLOn(SiS_Pr);
+            				SiS_ChrontelDoSomething4(SiS_Pr,HwDeviceExtension, BaseAddr);
+/*            			}   */
+	   		}
+       		}
+       }
+
+    } /* 310 series */
+
+  }  /* LVDS */
+
+}
+
+void
+SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
+
+  /* TW: Switch on LCD backlight on SiS30x */
+  if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
+      (SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) ) {
+    if(!(SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) {
+	SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
+	SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+    }
+    if(!(SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x26) & 0x01)) {
+        SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01);
+    }
+  }
+}
+
+void
+SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
+
+  /* TW: Switch off LCD backlight on SiS30x */
+  if( (!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) ||
+      (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ) {
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x00);
+  }
+
+  if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+      if(!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr))) {
+          if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+  	      SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFD,0x00);
+          }
+      }
+  }
+}
+
+BOOLEAN
+SiS_CR36BIOSWord23b(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT temp,temp1;
+  UCHAR *ROMAddr;
+
+  if((ROMAddr = (UCHAR *)HwDeviceExtension->pjVirtualRomBase) && SiS_Pr->SiS_UseROM) {
+     temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0xff;
+     temp >>= 4;
+     temp = 1 << temp;
+     temp1 = (ROMAddr[0x23c] << 8) | ROMAddr[0x23b];
+     if(temp1 & temp) return(1);
+     else return(0);
+  } else {
+     return(0);
+  }
+}
+
+BOOLEAN
+SiS_CR36BIOSWord23d(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT temp,temp1;
+  UCHAR *ROMAddr;
+
+  if((ROMAddr = (UCHAR *)HwDeviceExtension->pjVirtualRomBase) && SiS_Pr->SiS_UseROM) {
+     temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0xff;
+     temp >>= 4;
+     temp = 1 << temp;
+     temp1 = (ROMAddr[0x23e] << 8) | ROMAddr[0x23d];
+     if(temp1 & temp) return(1);
+     else return(0);
+  } else {
+     return(0);
+  }
+}
+
+void
+SiS_SetPanelDelay(SiS_Private *SiS_Pr, UCHAR *ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                  USHORT DelayTime)
+{
+  USHORT PanelID, DelayIndex, Delay, temp;
+
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {			/* 300 series, LVDS */
+
+	  PanelID = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36);
+
+	  DelayIndex = PanelID >> 4;
+
+	  if((DelayTime >= 2) && ((PanelID & 0x0f) == 1))  {
+              Delay = 3;
+          } else {
+              if(DelayTime >= 2) DelayTime -= 2;
+
+              if(!(DelayTime & 0x01)) {
+       		  Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0];
+              } else {
+       		  Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1];
+              }
+	      if((ROMAddr) && (SiS_Pr->SiS_UseROM)) {
+                  if(ROMAddr[0x220] & 0x40) {
+                      if(!(DelayTime & 0x01)) {
+	    	          Delay = (USHORT)ROMAddr[0x225];
+                      } else {
+	    	          Delay = (USHORT)ROMAddr[0x226];
+                      }
+                  }
+              }
+          }
+	  SiS_ShortDelay(SiS_Pr,Delay);
+
+      } else {							/* 300 series, 301(B) */
+
+	  PanelID = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36);
+	  temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x18);
+          if(!(temp & 0x10))  PanelID = 0x12;
+
+          DelayIndex = PanelID >> 4;
+
+	  if((DelayTime >= 2) && ((PanelID & 0x0f) == 1))  {
+              Delay = 3;
+          } else {
+              if(DelayTime >= 2) DelayTime -= 2;
+
+              if(!(DelayTime & 0x01)) {
+       		  Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0];
+              } else {
+       		  Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1];
+              }
+	      if((ROMAddr) && (SiS_Pr->SiS_UseROM)) {
+                  if(ROMAddr[0x220] & 0x40) {
+                      if(!(DelayTime & 0x01)) {
+	    	          Delay = (USHORT)ROMAddr[0x225];
+                      } else {
+	    	          Delay = (USHORT)ROMAddr[0x226];
+                      }
+                  }
+              }
+          }
+	  SiS_ShortDelay(SiS_Pr,Delay);
+
+      }
+
+   } else {
+
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {			/* 310/325 series, LVDS */
+
+          /* TW: Not currently used */
+
+      } else {							/* 310/325 series, 301(B) */
+
+          PanelID = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36);
+	  DelayIndex = PanelID >> 4;
+          if(!(DelayTime & 0x01)) {
+       		Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0];
+          } else {
+       		Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1];
+          }
+	  SiS_DDC2Delay(SiS_Pr, Delay * 4);
+
+      }
+
+   }
+
+}
+
+void
+SiS_LongDelay(SiS_Private *SiS_Pr, USHORT delay)
+{
+  while(delay--) {
+    SiS_GenericDelay(SiS_Pr,0x19df);
+  }
+}
+
+void
+SiS_ShortDelay(SiS_Private *SiS_Pr, USHORT delay)
+{
+  while(delay--) {
+      SiS_GenericDelay(SiS_Pr,0x42);
+  }
+}
+
+void
+SiS_GenericDelay(SiS_Private *SiS_Pr, USHORT delay)
+{
+  USHORT temp,flag;
+
+  flag = SiS_GetReg3(0x61) & 0x10;
+
+  while(delay) {
+      temp = SiS_GetReg3(0x61) & 0x10;
+      if(temp == flag) continue;
+      flag = temp;
+      delay--;
+  }
+}
+
+BOOLEAN
+SiS_Is301B(SiS_Private *SiS_Pr, USHORT BaseAddr)
+{
+  USHORT flag;
+
+  flag = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x01);
+  if(flag >= 0x0B0) return(1);
+  else return(0);
+}
+
+BOOLEAN
+SiS_CRT2IsLCD(SiS_Private *SiS_Pr, USHORT BaseAddr)
+{
+  USHORT flag;
+
+  flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+  if(flag & 0x20) return(1);
+  else return(0);
+}
+
+BOOLEAN
+SiS_IsDualEdge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+#ifdef SIS315H
+  USHORT flag;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+     if(flag & EnableDualEdge)  return(1);
+     else  return(0);
+  } else
+#endif
+     return(0);
+}
+
+BOOLEAN
+SiS_IsVAMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+#ifdef SIS315H
+  USHORT flag;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+     if((flag & EnableDualEdge) && (flag & SetToLCDA))   return(1);
+#if 0 /* Not done in 650/301LVx 1.10.6s, but in 650/301LV */
+     else if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+       if(flag) return(1);
+       else     return(0);   			         
+     }
+#endif
+     else
+       return(0);
+  } else
+#endif
+     return(0);
+ }
+
+BOOLEAN
+SiS_WeHaveBacklightCtrl(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+#ifdef SIS315H
+  USHORT flag;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x79);
+     if(flag & 0x10)  return(1);
+     else             return(0);
+  } else
+#endif
+     return(0);
+ }
+
+#if 0
+BOOLEAN
+SiS_Is315E(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+#ifdef SIS315H
+  USHORT flag;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5f);
+     if(flag & 0x10)  return(1);
+     else      	      return(0);
+  } else
+#endif
+     return(0);
+}
+#endif
+
+BOOLEAN
+SiS_IsM650or651(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+#ifdef SIS315H
+  USHORT flag;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5f);
+     flag &= 0xF0;
+     if((flag == 0xb0) || (flag == 0x90)) return 0;
+     else return 1;
+  } else
+#endif
+    return 1;
+}
+
+BOOLEAN
+SiS_IsYPbPr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+#ifdef SIS315H
+  USHORT flag;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+     if(flag & 0x08)  return(1);
+     else      	      return(0);
+  } else
+#endif
+     return(0);
+}
+
+BOOLEAN
+SiS_IsTVOrYPbPr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+  USHORT flag;
+
+#ifdef SIS315H
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+     if(flag & SetCRT2ToTV) return(1);
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+     if(flag & 0x08)        return(1);
+     else                   return(0);
+  } else
+#endif
+  {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+     if(flag & SetCRT2ToTV) return(1);
+  }
+  return(0);
+}
+
+BOOLEAN
+SiS_IsLCDOrLCDA(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+  USHORT flag;
+
+#ifdef SIS315H
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+     if(flag & SetCRT2ToLCD) return(1);
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+     if(flag & SetToLCDA)    return(1);
+     else                    return(0);
+  } else
+#endif
+  {
+   flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+   if(flag & SetCRT2ToLCD)   return(1);
+  }
+  return(0);
+
+}
+
+BOOLEAN
+SiS_IsDisableCRT2(SiS_Private *SiS_Pr, USHORT BaseAddr)
+{
+  USHORT flag;
+
+  flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+  if(flag & 0x20) return(0);
+  else            return(1);
+}
+
+BOOLEAN
+SiS_BridgeIsOn(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT flag;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+     return(0);   					/* TW: Changed from 1 to 0! */
+  } else {
+#if 0   /* TW: Commented for test on bridge-less systems */
+     if(HwDeviceExtension->jChipType >= SIS_315H) {    	/* TW: New (from 630/301B BIOS - not done there) */
+#endif
+        flag = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x00);
+        if((flag == 1) || (flag == 2)) return(0);       /* TW: Changed from 1 to 0! */
+        else return(1);                                 /* TW: Changed from 0 to 1! */
+#if 0
+     } else  return(0);					/* TW: New (from 630/301B BIOS - always return 0) */
+#endif
+  }
+}
+
+BOOLEAN
+SiS_BridgeIsEnable(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT flag;
+
+  if(!(SiS_BridgeIsOn(SiS_Pr,BaseAddr,HwDeviceExtension))) {
+    flag = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00);
+    if(HwDeviceExtension->jChipType < SIS_315H) {
+      /* 300 series (630/301B 2.04.5a) */
+      flag &= 0xa0;
+      if((flag == 0x80) || (flag == 0x20)) return 0;
+      else	                           return 1;
+    } else {
+      /* 310/325 series (650/301LVx 1.10.6s) */
+      flag &= 0x50;
+      if((flag == 0x40) || (flag == 0x10)) return 0;
+      else                                 return 1;
+    }
+  }
+  return 1;
+}
+
+BOOLEAN
+SiS_BridgeInSlave(SiS_Private *SiS_Pr)
+{
+  USHORT flag1;
+
+  flag1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31);
+  if(flag1 & (SetInSlaveMode >> 8)) return 1;
+  else return 0;
+}
+
+/* TW: New from 650/301LV(x) 1.10.6s BIOS */
+void
+SiS_SetHiVision(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT temp;
+
+  SiS_Pr->SiS_HiVision = 0;
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+#if 0   /* TW: Old */
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+           SiS_Pr->SiS_HiVision = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+	   SiS_Pr->SiS_HiVision &= 0x38;
+	   SiS_Pr->SiS_HiVision >>= 3;
+        }
+#endif  /* TW: New from 650/301LVx BIOS 1.10.6s */
+        temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+	if(temp & 0x40) {
+	    temp &= 0x30;
+	    switch(temp) {
+	      case 0x00: SiS_Pr->SiS_HiVision = 4; break;
+	      case 0x10: SiS_Pr->SiS_HiVision = 1; break;
+	      case 0x20: SiS_Pr->SiS_HiVision = 2; break;
+	      default:   SiS_Pr->SiS_HiVision = 3; break;
+	    }
+	}
+     }
+  }
+}
+
+/* TW: Checked against 630/LVDS 2.08, 650/LVDS and 650/301LV BIOS */
+BOOLEAN
+SiS_GetLCDResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
+                  USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT temp,modeflag,resinfo=0;
+  const unsigned char SiS300SeriesLCDRes[] =
+         { 0, 1, 2, 3, 7, 4, 5, 8,
+	   0, 0, 0, 0, 0, 0, 0, 0 };
+
+  SiS_Pr->SiS_LCDResInfo = 0;
+  SiS_Pr->SiS_LCDTypeInfo = 0;
+  SiS_Pr->SiS_LCDInfo = 0;
+
+  if (ModeNo<=0x13) {
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+
+  if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)))   return 0;
+
+  if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2))) return 0;
+
+  temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36);
+
+  /* FSTN: Fake CR36 (TypeInfo 2, ResInfo SiS_Panel320x480) */
+  if(SiS_Pr->SiS_IF_DEF_FSTN){
+   	temp = 0x20 | SiS_Pr->SiS_Panel320x480;
+   	SiS_SetReg1(SiS_Pr->SiS_P3d4,0x36,temp);
+  }
+
+  SiS_Pr->SiS_LCDTypeInfo = temp >> 4;
+  temp &= 0x0f;
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+      /* TW: Translate 300 series LCDRes to 310/325 series for unified usage */
+      temp = SiS300SeriesLCDRes[temp];
+  }
+  SiS_Pr->SiS_LCDResInfo = temp;
+
+  if(SiS_Pr->SiS_IF_DEF_FSTN){
+       	SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_Panel320x480;
+  }
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+    	if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMin301)
+		SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMin301;
+  } else {
+    	if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMinLVDS)
+		SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMinLVDS;
+  }
+
+  if(SiS_Pr->SiS_LCDResInfo > SiS_Pr->SiS_PanelMax)
+  	SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_Panel1024x768;
+
+  temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
+  if(SiS_Pr->SiS_IF_DEF_FSTN){
+        /* TW: Fake LVDS bridge for FSTN */
+      	temp = 0x04;
+      	SiS_SetReg1(SiS_Pr->SiS_P3d4,0x37,temp);
+  }
+  SiS_Pr->SiS_LCDInfo = temp;
+
+  /* TW: Inserted entire 315-block from 650/LVDS/301+LVx BIOSes */
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+         if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+		 if(ModeNo == 0x3a || ModeNo == 0x4d || ModeNo == 0x65) {
+		     SiS_Pr->SiS_LCDInfo |= LCDNonExpanding;
+		 }
+	     }
+	 }
+     }
+     if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x01) {
+         SiS_Pr->SiS_LCDInfo &= 0xFFEF;    
+	 SiS_Pr->SiS_LCDInfo |= LCDPass11;
+     }
+  } else {
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+        if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+           if(!(ROMAddr[0x235] & 0x02)) {
+	      SiS_Pr->SiS_LCDInfo &= 0xEF;
+	   }
+        }
+     } else {
+        if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	   if((SiS_Pr->SiS_SetFlag & CRT2IsVGA) && ((ModeNo == 0x03) || (ModeNo == 0x10))) {
+               SiS_Pr->SiS_LCDInfo &= 0xEF;
+	   }
+	}
+     }
+  }
+
+#ifdef LINUX_KERNEL
+  printk(KERN_INFO "sisfb: (LCDInfo = 0x%x LCDResInfo = 0x%x LCDTypeInfo = 0x%x)\n",
+                   SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo);
+#endif
+#ifdef LINUX_XF86
+  xf86DrvMsg(0, X_PROBED, "(init301: LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x)\n",
+			SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo);
+#endif
+
+  /* TW: With Trumpion, always Expanding */
+  if(SiS_Pr->SiS_IF_DEF_TRUMPION != 0){
+       SiS_Pr->SiS_LCDInfo &= (~LCDNonExpanding);
+  }
+
+  if(!((HwDeviceExtension->jChipType < SIS_315H) && (SiS_Pr->SiS_SetFlag & CRT2IsVGA))) {
+
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+	   if(ModeNo > 0x13) {
+	      if(!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) {
+                 if((resinfo == 7) || (resinfo == 3)) {
+                    SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+		 }
+              }
+           }
+        }
+	if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+	   SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+	}
+     }
+
+     if(modeflag & HalfDCLK) {
+        if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) {
+           if(!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) {
+	      if(!(((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (HwDeviceExtension->jChipType < SIS_315H)) &&
+	                                      (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480))) {
+                 if(ModeNo > 0x13) {
+                    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+                       if(resinfo == 4) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;     /* 512x384  */
+                    } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+                       if(resinfo == 3) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;     /* 400x300  */
+                    }
+                 }
+	      } else SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+           } else SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+        } else SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+     }
+
+  }
+
+  /* TW: wdr: if (VBInfo & LCD) && (VBInfo & (SetSimuScanMode | SwitchToCRT2)) { */
+  if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+    	if(SiS_Pr->SiS_VBInfo & SetNotSimuMode) {
+      		SiS_Pr->SiS_SetFlag |= LCDVESATiming;
+    	}
+  } else {
+    	SiS_Pr->SiS_SetFlag |= LCDVESATiming;
+  }
+
+  /* TW: Inserted from 650/301LVx BIOS 1.10.6s */
+  if(SiS_Pr->SiS_VBType & VB_SIS30xNEW) {
+      temp = 0x00;
+      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) temp = 0x04;
+      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) temp = 0x04;
+      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) temp = 0x04;
+      SiS_SetReg1(SiS_Pr->SiS_P3d4,0x39,temp);
+  } else if((HwDeviceExtension->jChipType > SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 0)) {
+      SiS_SetReg1(SiS_Pr->SiS_P3d4,0x39,0x00);
+  }
+
+  return 1;
+}
+
+void
+SiS_PresetScratchregister(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  return;
+  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x30,0x21);  */
+  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x31,0x41);  */
+  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x32,0x28);  */
+  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x33,0x22);  */
+  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x35,0x43);  */
+  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x36,0x01);  */
+  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x37,0x00);  */
+}
+
+void
+SiS_LongWait(SiS_Private *SiS_Pr)
+{
+  USHORT i;
+
+  i = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1F);
+
+  if(!(i & 0xC0)) {
+    for(i=0; i<0xFFFF; i++) {
+       if(!(SiS_GetReg2(SiS_Pr->SiS_P3da) & 0x08))
+         break;
+    }
     for(i=0; i<0xFFFF; i++) {
-       if(!(SiS_GetReg2(SiS_P3da) & 0x08))
+       if((SiS_GetReg2(SiS_Pr->SiS_P3da) & 0x08))
          break;
     }
-    for(i=0; i<0xFFFF; i++) {
-       if((SiS_GetReg2(SiS_P3da) & 0x08))
-         break;
+  }
+}
+
+void
+SiS_VBLongWait(SiS_Private *SiS_Pr)
+{
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
+    SiS_VBWait(SiS_Pr);
+  } else {
+    SiS_LongWait(SiS_Pr);
+  }
+  return;
+}
+
+void
+SiS_VBWait(SiS_Private *SiS_Pr)
+{
+  USHORT tempal,temp,i,j;
+
+  temp = 0;
+  for(i=0; i<3; i++) {
+    for(j=0; j<100; j++) {
+       tempal = SiS_GetReg2(SiS_Pr->SiS_P3da);
+       if(temp & 0x01) {
+          if((tempal & 0x08))  continue;
+          if(!(tempal & 0x08)) break;
+       } else {
+          if(!(tempal & 0x08)) continue;
+          if((tempal & 0x08))  break;
+       }
+    }
+    temp ^= 0x01;
+  }
+}
+
+void
+SiS_WaitVBRetrace(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        if(!(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x20)) return;
+     }
+     if(!(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x80)) {
+        SiS_WaitRetrace1(SiS_Pr,HwDeviceExtension);
+     } else {
+        SiS_WaitRetrace2(SiS_Pr,HwDeviceExtension);
+     }
+  } else {
+     if(!(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x40)) {
+        SiS_WaitRetrace1(SiS_Pr,HwDeviceExtension);
+     } else {
+        SiS_WaitRetrace2(SiS_Pr,HwDeviceExtension);
+     }
+  }
+}
+
+void
+SiS_WaitRetrace1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT i,watchdog;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1f) & 0xc0) return;
+     watchdog = 65535;
+     while( (SiS_GetReg2(SiS_Pr->SiS_P3da) & 0x08) && --watchdog);
+     watchdog = 65535;
+     while( (!(SiS_GetReg2(SiS_Pr->SiS_P3da) & 0x08)) && --watchdog);
+  } else {
+#if 0  /* TW: Not done in A901 BIOS */
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1f) & 0xc0) return;
+     }
+#endif
+     for(i=0; i<10; i++) {
+        watchdog = 65535;
+        while( (SiS_GetReg2(SiS_Pr->SiS_P3da) & 0x08) && --watchdog);
+	if(watchdog) break;
+     }
+     for(i=0; i<10; i++) {
+        watchdog = 65535;
+        while( (!(SiS_GetReg2(SiS_Pr->SiS_P3da) & 0x08)) && --watchdog);
+	if(watchdog) break;
+     }
+  }
+}
+
+void
+SiS_WaitRetraceDDC(SiS_Private *SiS_Pr)
+{
+  USHORT watchdog;
+
+  if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1f) & 0xc0) return;
+  watchdog = 65535;
+  while( (SiS_GetReg2(SiS_Pr->SiS_P3da) & 0x08) && --watchdog);
+  watchdog = 65535;
+  while( (!(SiS_GetReg2(SiS_Pr->SiS_P3da) & 0x08)) && --watchdog);
+}
+
+void
+SiS_WaitRetrace2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT i,watchdog,temp;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     watchdog = 65535;
+     while( (SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x30) & 0x02) && --watchdog);
+     watchdog = 65535;
+     while( (!(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x30) & 0x02)) && --watchdog);
+  } else {
+     for(i=0; i<10; i++) {
+        watchdog = 65535;
+	while( (temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x25) & 0x02) && --watchdog);
+	if(watchdog) break;
+     }
+     for(i=0; i<10; i++) {
+        watchdog = 65535;
+	while( (!(temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x25) & 0x02)) && --watchdog);
+	if(watchdog) break;
+     }
+  }
+}
+
+/* =========== Set and Get register routines ========== */
+
+void
+SiS_SetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR)
+{
+  USHORT temp;
+
+  temp = SiS_GetReg1(Port,Index);     /* SiS_Pr->SiS_Part1Port index 02 */
+  temp = (temp & (DataAND)) | DataOR;
+  SiS_SetReg1(Port,Index,temp);
+}
+
+void
+SiS_SetRegAND(USHORT Port,USHORT Index,USHORT DataAND)
+{
+  USHORT temp;
+
+  temp = SiS_GetReg1(Port,Index);     /* SiS_Pr->SiS_Part1Port index 02 */
+  temp &= DataAND;
+  SiS_SetReg1(Port,Index,temp);
+}
+
+void SiS_SetRegOR(USHORT Port,USHORT Index,USHORT DataOR)
+{
+  USHORT temp;
+
+  temp = SiS_GetReg1(Port,Index);     /* SiS_Pr->SiS_Part1Port index 02 */
+  temp |= DataOR;
+  SiS_SetReg1(Port,Index,temp);
+}
+
+/* ========================================================= */
+
+/* TW: Set 301 TV Encoder (and some LCD relevant) registers */
+/* TW: Checked against 650/301LV, 650/301LVx and 630/301B (I+II) */
+void
+SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr, USHORT ModeNo,
+              USHORT ModeIdIndex,USHORT RefreshRateTableIndex,
+	      PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT      i, j, tempax, tempbx, tempcx, temp, temp1;
+  USHORT      push1, push2;
+  const       UCHAR *PhasePoint;
+  const       UCHAR *TimingPoint;
+  const       SiS_Part2PortTblStruct *CRT2Part2Ptr = NULL;
+  USHORT      modeflag, resinfo, crt2crtc, resindex, CRT2Index;
+  ULONG       longtemp, tempeax, tempebx, temp2, tempecx;
+  const UCHAR atable[] = {
+                 0xc3,0x9e,0xc3,0x9e,0x02,0x02,0x02,
+	         0xab,0x87,0xab,0x9e,0xe7,0x02,0x02
+  };
+
+  /* TW: Inserted from 650/301LV BIOS */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+     /* TW: Inserted from 650/301LVx 1.10.6s: (Is at end of SetGroup2!) */
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xfc,0x03);
+	   temp = 1;
+	   if(ModeNo<=0x13) temp = 3;
+	   SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x0b,temp);
+	}
+     }
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {    /* 650/301LV: (VB_SIS301LV | VB_SIS302LV)) */
+       if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+         if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+           if((ModeNo == 0x4a) || (ModeNo == 0x38)) {
+               SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1c,0xa7);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1d,0x07);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1e,0xf2);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1f,0x6e);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x20,0x17);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x21,0x8b);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x22,0x73);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x23,0x53);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x24,0x13);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x25,0x40);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x26,0x34);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x27,0xf4);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x28,0x63);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x29,0xbb);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2a,0xcc);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2b,0x7a);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2c,0x58);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2d,0xe4);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2e,0x73);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,0xda);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,0x13);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x43,0x72);
+           }
+         }
+       }
+     }
+     return;
+  }
+
+  if(ModeNo<=0x13) {
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
+    	resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+    	crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
+    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+    	crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+  }
+
+  tempcx = SiS_Pr->SiS_VBInfo;
+  tempax = (tempcx & 0x00FF) << 8;
+  tempbx = (tempcx & 0x00FF) | ((tempcx & 0x00FF) << 8);
+  tempbx &= 0x0410;
+  temp = (tempax & 0x0800) >> 8;
+  temp >>= 1;
+  temp |= (((tempbx & 0xFF00) >> 8) << 1);
+  temp |= ((tempbx & 0x00FF) >> 3);
+  temp ^= 0x0C;
+
+  PhasePoint  = SiS_Pr->SiS_PALPhase;
+  TimingPoint = SiS_Pr->SiS_PALTiming;
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {          /* PALPhase */
+    temp ^= 0x01;
+    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+      TimingPoint = SiS_Pr->SiS_HiTVSt2Timing;
+      if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+        if(modeflag & Charx8Dot) TimingPoint = SiS_Pr->SiS_HiTVSt1Timing;
+        else TimingPoint = SiS_Pr->SiS_HiTVTextTiming;
+      }
+    } else TimingPoint = SiS_Pr->SiS_HiTVExtTiming;
+  } else {
+#endif
+    if(SiS_Pr->SiS_VBInfo & SetPALTV){
+
+      TimingPoint = SiS_Pr->SiS_PALTiming;
+      PhasePoint  = SiS_Pr->SiS_PALPhase;
+
+      if( (SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS302B)) &&
+          ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+	    (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
+         PhasePoint = SiS_Pr->SiS_PALPhase2;
+      }
+
+    } else {
+
+        temp |= 0x10;
+	TimingPoint = SiS_Pr->SiS_NTSCTiming;
+	PhasePoint  = SiS_Pr->SiS_NTSCPhase;
+
+        if( (SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS302B)) &&
+	    ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+	      (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
+        	PhasePoint = SiS_Pr->SiS_NTSCPhase2;
+        }
+
+    }
+#ifdef oldHV
+  }
+#endif
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x00,temp);
+
+  temp = 0;
+  if((HwDeviceExtension->jChipType == SIS_630)||
+     (HwDeviceExtension->jChipType == SIS_730)) {
+     temp = 0x35;
+  }
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     temp = 0x38;
+  }
+  if(temp) {
+    if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+      if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x01) {
+          temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,temp);
+          if(temp1 & 0x40) {
+              	PhasePoint = SiS_Pr->SiS_PALMPhase;
+		if( (SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS302B)) &&
+		    ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+		      (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
+	           PhasePoint = SiS_Pr->SiS_PALMPhase2;
+		}
+	  }
+          if(temp1 & 0x80) {
+               	PhasePoint = SiS_Pr->SiS_PALNPhase;
+		if( (SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS302B)) &&
+		    ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+		      (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
+	           PhasePoint = SiS_Pr->SiS_PALNPhase2;
+		}
+	  }
+      }
+    }
+  }
+
+#ifdef SIS315H
+  /* TW: Inserted from 650/301LV BIOS */
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {  /* 650/301LV : 301LV | 302LV */
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+           if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+              if((ModeNo == 0x4a) || (ModeNo == 0x38)) {
+	         PhasePoint = SiS_Pr->SiS_SpecialPhase;
+	      }
+           }
+        }
+     }
+  }
+#endif
+
+  for(i=0x31, j=0; i<=0x34; i++, j++){
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,PhasePoint[j]);
+  }
+
+  for(i=0x01, j=0; i<=0x2D; i++, j++){
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]);
+  }
+  for(i=0x39; i<=0x45; i++, j++){
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]);
+  }
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+    if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(!(SiS_Pr->SiS_ModeType & 0x07))
+        SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x3A,0x1F);
+    } else {
+      SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x3A,0x1F);
+    }
+  }
+
+  SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x0A,SiS_Pr->SiS_NewFlickerMode);
+
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x35,SiS_Pr->SiS_RY1COE);
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x36,SiS_Pr->SiS_RY2COE);
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x37,SiS_Pr->SiS_RY3COE);
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x38,SiS_Pr->SiS_RY4COE);
+
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) tempax = 950;
+  else {
+#endif
+    if(SiS_Pr->SiS_VBInfo & SetPALTV) tempax = 520;
+    else tempax = 440;
+#ifdef oldHV
+  }
+#endif
+
+  if( ( ( (!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) || (SiS_Pr->SiS_HiVision == 3) ) && (SiS_Pr->SiS_VDE <= tempax) ) ||
+      ( (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (SiS_Pr->SiS_HiVision != 3) &&
+        ( (SiS_Pr->SiS_VGAHDE == 1024) || ((SiS_Pr->SiS_VGAHDE != 1024) && (SiS_Pr->SiS_VDE <= tempax)) ) ) ) {
+
+     tempax -= SiS_Pr->SiS_VDE;
+     tempax >>= 2;
+     tempax = (tempax & 0x00FF) | ((tempax & 0x00FF) << 8);
+
+     temp = (tempax & 0xFF00) >> 8;
+     temp += (USHORT)TimingPoint[0];
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,temp);
+
+     temp = (tempax & 0xFF00) >> 8;
+     temp += (USHORT)TimingPoint[1];
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,temp);
+
+     if( (SiS_Pr->SiS_VBInfo & (SetCRT2ToTV - SetCRT2ToHiVisionTV)) &&
+        (SiS_Pr->SiS_HiVision != 3) &&
+        (SiS_Pr->SiS_VGAHDE >= 1024) ) {
+        if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+           SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x19);
+           SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x52);
+        } else {
+           if(HwDeviceExtension->jChipType >= SIS_315H) {
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x17);
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x1d);
+	   } else {
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x0b);
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x11);
+	   }
+        }
+     }
+
+  }
+
+  tempcx = SiS_Pr->SiS_HT;
+
+  /* TW: Inserted from 650/301LVx 1.10.6s */
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) {
+      	   tempcx >>= 1;
+      }
+  }
+
+  tempcx--;
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        tempcx--;
+  }
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1B,temp);
+  temp = (tempcx & 0xFF00) >> 8;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0xF0,temp);
+
+  tempcx++;
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        tempcx++;
+  }
+  tempcx >>= 1;
+
+  push1 = tempcx;
+
+  tempcx += 7;
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)  tempcx -= 4;
+#endif
+  temp = (tempcx & 0x00FF) << 4;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x22,0x0F,temp);
+
+  tempbx = TimingPoint[j] | ((TimingPoint[j+1]) << 8);
+  tempbx += tempcx;
+
+  push2 = tempbx;
+
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x24,temp);
+  temp = ((tempbx & 0xFF00) >> 8) << 4;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0F,temp);
+
+  tempbx = push2;
+
+  tempbx += 8;
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+    tempbx -= 4;
+    tempcx = tempbx;
+  }
+#endif
+  temp = (tempbx & 0x00FF) << 4;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x29,0x0F,temp);
+
+  j += 2;
+  tempcx += ((TimingPoint[j] | ((TimingPoint[j+1]) << 8)));
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x27,temp);
+  temp = ((tempcx & 0xFF00) >> 8) << 4;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x28,0x0F,temp);
+
+  tempcx += 8;
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)  tempcx -= 4; 
+#endif
+  temp = (tempcx & 0xFF) << 4;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2A,0x0F,temp);
+
+  tempcx = push1;
+
+  j += 2;
+  tempcx -= (TimingPoint[j] | ((TimingPoint[j+1]) << 8));
+  temp = (tempcx & 0x00FF) << 4;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2D,0x0F,temp);
+
+  tempcx -= 11;
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
+    tempax = SiS_GetVGAHT2(SiS_Pr) - 1;
+    tempcx = tempax;
+  }
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2E,temp);
+
+  tempbx = SiS_Pr->SiS_VDE;
+  if(SiS_Pr->SiS_VGAVDE == 360) tempbx = 746;
+  if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 746;
+  if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 853;
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+  	if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) tempbx >>= 1;
+  } else {
+	if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (!(SiS_Pr->SiS_HiVision & 0x03))) {
+	   tempbx >>= 1;
+	   if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+	      if(ModeNo <= 0x13) {
+	         if(crt2crtc == 1) {
+	            tempbx++;
+                 }
+	      }
+	   } else {
+              if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+	         if(crt2crtc == 4)   /* TW: BIOS calls GetRatePtrCRT2 here - does not make sense */
+                    if(SiS_Pr->SiS_ModeType <= 3) tempbx++;
+	      }
+	   }
+        }
+  }
+  tempbx -= 2;
+  temp = tempbx & 0x00FF;
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+      if(ModeNo == 0x2f) temp++;
+    }
+  }
+#endif
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2F,temp);
+
+  tempax = (tempcx & 0xFF00) | (tempax & 0x00FF);
+  tempbx = ((tempbx & 0xFF00) << 6) | (tempbx & 0x00FF);
+  tempax |= (tempbx & 0xFF00);
+#ifdef oldHV
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)) {
+#endif
+    if(HwDeviceExtension->jChipType < SIS_315H) {
+      if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART)) {		/* TW: New from 630/301B (II) BIOS */
+         tempax |= 0x1000;
+         if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToSVIDEO))  tempax |= 0x2000;
+      }
+    } else {
+      tempax |= 0x1000;
+      if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToSVIDEO))  tempax |= 0x2000;
+    }
+#ifdef oldHV
+  }
+#endif
+  temp = (tempax & 0xFF00) >> 8;
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,temp);
+
+  /* TW: Inserted from 650/301LVx 1.10.6s */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+     if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) ||
+         (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) ) {
+         SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x10,0x60);
+     }
+  }
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {      /* tv gatingno */
+    tempbx = SiS_Pr->SiS_VDE;
+    if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (!(SiS_Pr->SiS_HiVision & 0x03))) {
+         tempbx >>= 1;
+    }
+    tempbx -= 3;
+    tempbx &= 0x03ff;
+    temp = ((tempbx & 0xFF00) >> 8) << 5;
+    temp |= 0x18;
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x46,temp);
+    temp = tempbx & 0x00FF;
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x47,temp);
+    if(HwDeviceExtension->jChipType >= SIS_315H) {	/* TW: Inserted from 650/301LVx 1.10.6s */
+       tempax = 0;
+       if(SiS_Pr->SiS_HiVision & 0x07) {
+          if(SiS_Pr->SiS_HiVision & 0x04) tempax = 0x1000;
+          else if(SiS_Pr->SiS_HiVision & 0x01) tempax = 0x3000;
+	  else tempax = 0x5000;
+       }
+       temp = (tempax & 0xFF00) >> 8;
+       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x4d,temp);
+    }
+  }
+
+  tempbx &= 0x00FF;
+  if(!(modeflag & HalfDCLK)) {
+    tempcx = SiS_Pr->SiS_VGAHDE;
+    if(tempcx >= SiS_Pr->SiS_HDE){
+      tempbx |= 0x2000;
+      tempax &= 0x00FF;
+    }
+  }
+
+  tempcx = 0x0101;
+  if(SiS_Pr->SiS_VBInfo & (SetPALTV | SetCRT2ToTV)) {   /*301b- TW: BIOS BUG? */
+    if(!(SiS_Pr->SiS_HiVision & 0x03)) {
+      if(SiS_Pr->SiS_VGAHDE >= 1024) {
+        if(!(modeflag & HalfDCLK)) {   /* TW: This check not in 630/301B */
+          tempcx = 0x1920;
+          if(SiS_Pr->SiS_VGAHDE >= 1280) {
+            tempcx = 0x1420;
+            tempbx &= 0xDFFF;
+          }
+        }
+      }
+    }
+  }
+
+  if(!(tempbx & 0x2000)){
+
+    if(modeflag & HalfDCLK) {
+         tempcx = (tempcx & 0xFF00) | (((tempcx & 0x00FF) << 1) & 0xff);
+    }
+    push1 = tempbx;
+    tempeax = SiS_Pr->SiS_VGAHDE;
+    tempebx = (tempcx & 0xFF00) >> 8;
+    longtemp = tempeax * tempebx;
+    tempecx = tempcx & 0x00FF;
+    longtemp /= tempecx;
+    longtemp <<= 0x0d;
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+     	longtemp <<= 3;
+    }
+    tempecx = SiS_Pr->SiS_HDE;
+    temp2 = longtemp % tempecx;
+    tempeax = longtemp / tempecx;
+    if(temp2 != 0) tempeax++;
+    tempax = (USHORT)tempeax;
+    tempbx = push1;
+    tempcx = (tempcx & 0xff00) | (((tempax & 0xFF00) >> 8) >> 5);
+    tempbx |= (tempax & 0x1F00);
+    tempax = ((tempax & 0x00FF) << 8) | (tempax & 0x00FF);
+  }
+
+  temp = (tempax & 0xFF00) >> 8;
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x44,temp);
+  temp = (tempbx & 0xFF00) >> 8;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x45,0xC0,temp);
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+       temp = tempcx & 0x00FF;
+       if(tempbx & 0x2000) temp = 0;
+       temp |= 0x18;
+       SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x46,0xE0,temp);
+       if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+             tempbx = 0x0382;    /* TW: BIOS; Was 0x0364; */
+             tempcx = 0x007e;    /* TW: BIOS; Was 0x009c; */
+       } else {
+             tempbx = 0x0369;    /* TW: BIOS; Was 0x0346; */
+             tempcx = 0x0061;    /* TW: BIOS; Was 0x0078; */
+       }
+       temp = (tempbx & 0x00FF) ;
+       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x4B,temp);
+       temp = (tempcx & 0x00FF) ;
+       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x4C,temp);
+       tempbx &= 0x0300;
+       temp = (tempcx & 0xFF00) >> 8;
+       temp = (temp & 0x0003) << 2;
+       temp |= (tempbx >> 8);
+       if(HwDeviceExtension->jChipType < SIS_315H) {
+          SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x4D,temp);
+       } else {
+          SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x4D,0xF0,temp);
+       }
+
+       temp = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x43);
+       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x43,(USHORT)(temp - 3));
+  }
+
+  temp = 0;
+  if((HwDeviceExtension->jChipType == SIS_630)||
+     (HwDeviceExtension->jChipType == SIS_730)) {
+     temp = 0x35;
+  } else if(HwDeviceExtension->jChipType >= SIS_315H) {
+     temp = 0x38;
+  }
+  if(temp) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+          if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x01) {
+               if(SiS_GetReg1(SiS_Pr->SiS_P3d4,temp) & 0x40) {
+                     SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xEF);
+                     temp = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x01);
+                     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,temp - 1);
+               }
+          }
+      }
+  }
+
+
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+    if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x0B,0x00);
+    }
+  }
+#endif
+
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)  return;
+  } else {
+     /* TW: !!! The following is a duplicate, done for LCDA as well (see above) */
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+       if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {    /* 650/301LV: (VB_SIS301LV | VB_SIS302LV)) */
+         if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+           if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+             if((ModeNo == 0x4a) || (ModeNo == 0x38)) {
+               SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1c,0xa7);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1d,0x07);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1e,0xf2);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1f,0x6e);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x20,0x17);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x21,0x8b);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x22,0x73);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x23,0x53);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x24,0x13);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x25,0x40);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x26,0x34);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x27,0xf4);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x28,0x63);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x29,0xbb);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2a,0xcc);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2b,0x7a);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2c,0x58);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2d,0xe4);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2e,0x73);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,0xda);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,0x13);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x43,0x72);
+	     }
+           }
+         }
+       }
+       return;
+     }
+  }
+
+  /* TW: From here: Part2 LCD setup */
+
+  tempbx = SiS_Pr->SiS_HDE;
+  /* TW: Inserted from 650/301LVx 1.10.6s */
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) tempbx >>= 1;
+  }
+  tempbx--;			         /* RHACTE=HDE-1 */
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2C,temp);
+  temp = (tempbx & 0xFF00) >> 8;
+  temp <<= 4;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2B,0x0F,temp);
+
+  temp = 0x01;
+  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+    if(SiS_Pr->SiS_ModeType == ModeEGA) {
+      if(SiS_Pr->SiS_VGAHDE >= 1024) {
+        temp = 0x02;
+	if(HwDeviceExtension->jChipType >= SIS_315H) {
+           if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+             temp = 0x01;
+	   }
+	}
+      }
+    }
+  }
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x0B,temp);
+
+  tempbx = SiS_Pr->SiS_VDE;         		/* RTVACTEO=(VDE-1)&0xFF */
+  push1 = tempbx;
+
+  tempbx--;
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x03,temp);
+  temp = ((tempbx & 0xFF00) >> 8) & 0x07;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0C,0xF8,temp);
+
+  tempcx = SiS_Pr->SiS_VT;
+  push2 = tempcx;
+
+  tempcx--;
+  temp = tempcx & 0x00FF;  			 /* RVTVT=VT-1 */
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x19,temp);
+
+  temp = (tempcx & 0xFF00) >> 8;
+  temp <<= 5;
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp |= 0x10;
+    else {
+      if(SiS_Pr->SiS_LCDInfo & LCDSync)       /* TW: 630/301 BIOS checks this */
+         temp |= 0x10;
     }
+  } else {
+      /* TW: Inserted from 630/301LVx 1.10.6s */
+      if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+         if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x01) {
+      	    temp |= 0x10;
+	 }
+      }
+  }
+
+  /* 630/301 does not do all this */
+  if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+      if(HwDeviceExtension->jChipType >= SIS_315H) {
+        /* TW: Inserted from 650/301LVx 1.10.6s */
+        temp |= (SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37) >> 6);
+      } else {
+        tempbx = (tempbx & 0xFF00) | (SiS_Pr->SiS_LCDInfo & 0x0FF);
+        if(tempbx & LCDSync) {
+          tempbx &= (0xFF00 | LCDSyncBit);
+          tempbx = (tempbx & 0xFF00) | ((tempbx & 0x00FF) >> LCDSyncShift);
+          temp |= (tempbx & 0x00FF);
+        }
+      }
   }
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1A,temp);
+
+  SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x09,0xF0);
+  SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x0A,0xF0);
+
+  SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x17,0xFB);
+  SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x18,0xDF);
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {   /* ------------- 310 series ------------ */
+
+      /* TW: Inserted this entire section from 650/301LV(x) BIOS */
+
+      SiS_GetCRT2Part2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                         &CRT2Index,&resindex);
+
+      switch(CRT2Index) {
+        case Panel_1024x768      : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1;  break;  /* "Normal" */
+        case Panel_1280x1024     : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1280x1024_1; break;
+	case Panel_1400x1050     : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1400x1050_1; break;
+	case Panel_1600x1200     : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1600x1200_1; break;
+        case Panel_1024x768 + 16 : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_2;  break;  /* Non-Expanding */
+        case Panel_1280x1024 + 16: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1280x1024_2; break;
+	case Panel_1400x1050 + 16: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1400x1050_2; break;
+	case Panel_1600x1200 + 16: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1600x1200_2; break;
+        case Panel_1024x768 + 32 : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_3;  break;  /* VESA Timing */
+        case Panel_1280x1024 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1280x1024_3; break;
+	case Panel_1400x1050 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1400x1050_3; break;
+	case Panel_1600x1200 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1600x1200_3; break;
+	default:                   CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_3;  break;
+      }
+
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,(CRT2Part2Ptr+resindex)->CR[0]);
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x02,0x80,(CRT2Part2Ptr+resindex)->CR[1]);
+      for(i = 2, j = 0x04; j <= 0x06; i++, j++ ) {
+        SiS_SetReg1(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]);
+      }
+      for(j = 0x1c; j <= 0x1d; i++, j++ ) {
+        SiS_SetReg1(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]);
+      }
+      for(j = 0x1f; j <= 0x21; i++, j++ ) {
+        SiS_SetReg1(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]);
+      }
+      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x23,(CRT2Part2Ptr+resindex)->CR[10]);
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0f,(CRT2Part2Ptr+resindex)->CR[11]);
+
+      if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+        if(SiS_Pr->SiS_VGAVDE == 0x20d) {
+	  temp = 0xc3;
+	  if(SiS_Pr->SiS_ModeType <= ModeVGA) {
+	     temp++;
+	     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp += 2;
+	  }
+	  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,temp);
+	  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,0xb3);
+	}
+	if(SiS_Pr->SiS_VGAVDE == 0x1a4) {
+	  temp = 0x4d;
+	  if(SiS_Pr->SiS_ModeType <= ModeVGA) {
+	     temp++;
+	     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp++;
+	  }
+	  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,temp);
+	}
+     }
+
+     /* TW: Inserted from 650/301LVx 1.10.6s: */
+     /* !!! This is a duplicate, done for LCDA as well - see above */
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xfc,0x03);
+	   temp = 1;
+	   if(ModeNo<=0x13) temp = 3;
+	   SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x0b,temp);
+	}
+     }
+
+  } else {   /* ------------- 300 series ----------- */
+
+    tempcx++;
+    tempbx = 768;
+    if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1024x768) {
+      tempbx = 1024;
+      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024) {
+         tempbx = 1200;
+         if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1600x1200) {
+            if(tempbx != SiS_Pr->SiS_VDE) {
+               tempbx = 960;
+            }
+         }
+      }
+    }
+    if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) {
+      tempbx = SiS_Pr->SiS_VDE - 1;
+      tempcx--;
+    }
+    tempax = 1;
+    if(!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) {
+      if(tempbx != SiS_Pr->SiS_VDE){
+        tempax = tempbx;
+        if(tempax < SiS_Pr->SiS_VDE) {
+          tempax = 0;
+          tempcx = 0;
+        } else {
+          tempax -= SiS_Pr->SiS_VDE;
+        }
+        tempax >>= 1;
+      }
+      tempcx -= tempax; /* lcdvdes */
+      tempbx -= tempax; /* lcdvdee */
+    } else {
+      tempax >>= 1;
+      tempcx -= tempax; /* lcdvdes */
+      tempbx -= tempax; /* lcdvdee */
+    }
+
+    temp = tempcx & 0x00FF;   				/* RVEQ1EQ=lcdvdes */
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x05,temp);
+    temp = tempbx & 0x00FF;   				/* RVEQ2EQ=lcdvdee */
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x06,temp);
+
+    temp = ((tempbx & 0xFF00) >> 8 ) << 3;
+    temp |= ((tempcx & 0xFF00) >> 8);
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,temp);
+
+    tempbx = push2;
+    tempax = push1;
+    tempcx = tempbx;
+    tempcx -= tempax;
+    tempcx >>= 4;
+    tempbx += tempax;
+    tempbx >>= 1;
+    if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)  tempbx -= 10;
+
+    temp = tempbx & 0x00FF;   				/* RTVACTEE=lcdvrs */
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,temp);
+
+    temp = ((tempbx & 0xFF00) >> 8) << 4;
+    tempbx += (tempcx + 1);
+    temp |= (tempbx & 0x000F);
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,temp);
+
+    /* TW: Code from 630/301B (I+II) BIOS */
+
+    if( ( ( (HwDeviceExtension->jChipType == SIS_630) ||
+            (HwDeviceExtension->jChipType == SIS_730) ) &&
+          (HwDeviceExtension->jChipRevision > 2) )  &&
+        (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) &&
+        (!(SiS_Pr->SiS_SetFlag & LCDVESATiming))  &&
+        (!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) ) {
+            if(ModeNo == 0x13) {
+              SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,0xB9);
+              SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x05,0xCC);
+              SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x06,0xA6);
+            } else {
+              if((crt2crtc & 0x3F) == 4) {
+                SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x2B);
+                SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x13);
+                SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,0xE5);
+                SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x05,0x08);
+                SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x06,0xE2);
+              }
+            }
+    }
+
+    /* TW: Inserted missing code from 630/301B BIOS: (II: 3258) */
+
+    if(SiS_Pr->SiS_LCDTypeInfo == 0x0c) {
+         crt2crtc &= 0x1f;
+         tempcx = 0;
+         if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) {
+           if (SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+              tempcx += 7;
+           }
+         }
+         tempcx += crt2crtc;
+         if (crt2crtc >= 4) {
+           SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x06,0xff);
+         }
+
+         if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) {
+           if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+             if(crt2crtc == 4) {
+                SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x28);
+             }
+           }
+         }
+         SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x18);
+         SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,atable[tempcx]);
+    }
+
+    tempcx = (SiS_Pr->SiS_HT - SiS_Pr->SiS_HDE) >> 2;     /* (HT-HDE)>>2     */
+    tempbx = SiS_Pr->SiS_HDE + 7;            		  /* lcdhdee         */
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+         tempbx += 2;
+    }
+    push1 = tempbx;
+    temp = tempbx & 0x00FF;    			          /* RHEQPLE=lcdhdee */
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x23,temp);
+    temp = (tempbx & 0xFF00) >> 8;
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0xF0,temp);
+
+    temp = 7;
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+         temp += 2;
+    }
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1F,temp);  	  /* RHBLKE=lcdhdes */
+
+    SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x20,0x0F);
+
+    tempbx += tempcx;
+    push2 = tempbx;
+    temp = tempbx & 0xFF;            		          /* RHBURSTS=lcdhrs */
+    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+      if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) {
+        if(SiS_Pr->SiS_HDE == 1280)  temp = 0x47;
+      }
+    }
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1C,temp);
+    temp = ((tempbx & 0xFF00) >> 8) << 4;
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0x0F,temp);
+
+    tempbx = push2;
+    tempcx <<= 1;
+    tempbx += tempcx;
+    temp = tempbx & 0x00FF;            		          /* RHSYEXP2S=lcdhre */
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x21,temp);
+
+    if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+      if(SiS_Pr->SiS_VGAVDE == 525) {
+        if(SiS_Pr->SiS_ModeType <= ModeVGA)
+    	   temp=0xC6;
+        else
+       	   temp=0xC3;
+        SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,temp);
+        SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,0xB3);
+      } else if(SiS_Pr->SiS_VGAVDE == 420) {
+        if(SiS_Pr->SiS_ModeType <= ModeVGA)
+	   temp=0x4F;
+        else
+       	   temp=0x4D;   /* 650: 4e */
+        SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,temp);
+      }
+    }
+
+  } /* HwDeviceExtension */
+}
+
+USHORT
+SiS_GetVGAHT2(SiS_Private *SiS_Pr)
+{
+  ULONG tempax,tempbx;
+
+  tempbx = ((SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) * SiS_Pr->SiS_RVBHCMAX) & 0xFFFF;
+  tempax = (SiS_Pr->SiS_VT - SiS_Pr->SiS_VDE) * SiS_Pr->SiS_RVBHCFACT;
+  tempax = (tempax * SiS_Pr->SiS_HT) / tempbx;
+  return((USHORT) tempax);
 }
 
+/* TW: Set 301 Macrovision(tm) registers */
+/* TW: Double-Checked against 650/301LV, 650/301LVx and 630/301B BIOS */
 void
-SiS_VBLongWait()
+SiS_SetGroup3(SiS_Private *SiS_Pr, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+              USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT tempal,temp,i,j;
+  USHORT temp;
+#ifdef oldHV
+  USHORT i;
+  const UCHAR  *tempdi;
+#endif
+  USHORT modeflag;
 
-  if(!(SiS_VBInfo&SetCRT2ToTV)) {
-    temp=0;
-    for(i=0;i<3;i++) {
-      for(j=0;j<100;j++) {
-        tempal=SiS_GetReg2(SiS_P3da);
-        if(temp&0x01) {        /* VBWaitMode2  */
-          if((tempal&0x08)) {
-            continue;
-          }
-          if(!(tempal&0x08)) {
-            break;
-          }
-        } else {                 /* VBWaitMode1  */
-          if(!(tempal&0x08)) {
-            continue;
-          }
-          if((tempal&0x08)) {
-            break;
+  /* TW: Inserted from 650/301LVx 1.10.6s */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return;
+
+  if(ModeNo<=0x13)
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  else
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+
+  SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x00,0x00);
+
+  if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+    SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x13,0xFA);
+    SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x14,0xC8);
+  } else {
+    if(HwDeviceExtension->jChipType >= SIS_315H) {
+      SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x13,0xF5);
+      SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x14,0xB7);
+    } else {
+      SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x13,0xF6);
+      SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x14,0xBf);
+    }
+  }
+
+  temp = 0;
+  if((HwDeviceExtension->jChipType == SIS_630)||
+     (HwDeviceExtension->jChipType == SIS_730)) {
+     temp = 0x35;
+  } else if(HwDeviceExtension->jChipType >= SIS_315H) {
+     temp = 0x38;
+  }
+  if(temp) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+          if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x01) {
+              if(SiS_GetReg1(SiS_Pr->SiS_P3d4,temp) & 0x40){
+                  SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x13,0xFA);
+                  SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x14,0xC8);
+                  SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x3D,0xA8);
+              }
           }
-        }
       }
-      temp=temp^0x01;
+  }
+
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+    tempdi = SiS_Pr->SiS_HiTVGroup3Data;
+    if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+      tempdi = SiS_Pr->SiS_HiTVGroup3Simu;
+      if(!(modeflag & Charx8Dot)) {
+        tempdi = SiS_Pr->SiS_HiTVGroup3Text;
+      }
+    }
+    for(i=0; i<=0x3E; i++){
+       SiS_SetReg1(SiS_Pr->SiS_Part3Port,i,tempdi[i]);
     }
-  } else {
-    SiS_LongWait();
   }
+#endif
+
   return;
 }
 
-BOOLEAN
-SiS_WaitVBRetrace(USHORT  BaseAddr)
+/* TW: Set 301 VGA2 registers */
+/* TW: Double-Checked against 650/301LV(x) and 630/301B BIOS */
+void
+SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+              USHORT ModeIdIndex,USHORT RefreshRateTableIndex,
+	      PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT temp;
+  USHORT tempax,tempcx,tempbx,modeflag,temp,temp2;
+  ULONG tempebx,tempeax,templong;
 
-return 0;
+  if(ModeNo<=0x13)
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  else
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
-  temp=SiS_GetReg1(SiS_Part1Port,0x00); /* FUNCTION CTRL */
-  if(!(temp&0x80)){
-    return 0;
+  /* TW: From 650/301LVx 1.10.6s BIOS */
+  if(SiS_Pr->SiS_VBType & (VB_SIS30xLV | VB_SIS30xNEW)) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+          SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x24,0x0e);
+      }
   }
 
-  for(temp=0;temp==0;){
-     temp=SiS_GetReg1(SiS_Part1Port,0x25);
-     temp=temp&0x01;
-  }
-  for(;temp>0;){
-     temp=SiS_GetReg1(SiS_Part1Port,0x25);
-     temp=temp&0x01;
+  if(SiS_Pr->SiS_VBType & VB_SIS30xNEW) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+          SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x10,0x9f);
+      }
   }
-  return 1;
+
+  /* TW: From 650/301LV BIOS */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+  	/* TW: This is a duplicate; done at the end, too */
+	if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) {
+		SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c);
+	}
+	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x2a,0x00);
+	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
+	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
+   	return;
+  }
+
+  temp = SiS_Pr->SiS_RVBHCFACT;
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x13,temp);
+
+  tempbx = SiS_Pr->SiS_RVBHCMAX;
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x14,temp);
+
+  temp2 = (((tempbx & 0xFF00) >> 8) << 7) & 0x00ff;
+
+  tempcx = SiS_Pr->SiS_VGAHT - 1;
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x16,temp);
+
+  temp = (((tempcx & 0xFF00) >> 8) << 3) & 0x00ff;
+  temp2 |= temp;
+
+  tempcx = SiS_Pr->SiS_VGAVT - 1;
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV))  tempcx -= 5;
+
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x17,temp);
+
+  temp = temp2 | ((tempcx & 0xFF00) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x15,temp);
+
+  tempcx = SiS_Pr->SiS_VBInfo;
+  tempbx = SiS_Pr->SiS_VGAHDE;
+  if(modeflag & HalfDCLK)  tempbx >>= 1;
+
+  /* TW: New for 650/301LV and 630/301B */
+  temp = 0xA0;
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+       temp = 0;
+       if(tempbx > 800) {
+          temp = 0xA0;
+          if(tempbx != 1024) {
+             temp = 0xC0;
+             if(tempbx != 1280) temp = 0;
+	  }
+       }
+  } else
+#endif
+    if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+      if(tempbx <= 800) {
+         temp = 0x80;
+	 if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD){
+            temp = 0;
+            if(tempbx > 800) temp = 0x60;
+         }
+      }
+  } else {
+      temp = 0x80;
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD){
+            temp = 0;
+            if(tempbx > 800) temp = 0x60;
+      }
+  }
+  if(SiS_Pr->SiS_HiVision & 0x03) {
+        temp = 0;
+	if(SiS_Pr->SiS_VGAHDE == 1024) temp = 0x20;
+  }
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+  	if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) temp = 0;
+  }
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301) {
+     if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024)
+        temp |= 0x0A;
+  }
+
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0E,0x10,temp);
+
+  tempebx = SiS_Pr->SiS_VDE;
+
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+     if(!(temp & 0xE0)) tempebx >>=1;
+  }
+#endif
+
+  tempcx = SiS_Pr->SiS_RVBHRS;
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x18,temp);
+
+  tempeax = SiS_Pr->SiS_VGAVDE;
+  tempcx |= 0x4000;
+  if(tempeax <= tempebx){
+    tempcx ^= 0x4000;
+  } else {
+    tempeax -= tempebx;
+  }
+
+  templong = (tempeax * 256 * 1024) % tempebx;
+  tempeax = (tempeax * 256 * 1024) / tempebx;
+  tempebx = tempeax;
+  if(templong != 0) tempebx++;
+
+  temp = (USHORT)(tempebx & 0x000000FF);
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x1B,temp);
+  temp = (USHORT)((tempebx & 0x0000FF00) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x1A,temp);
+
+  tempbx = (USHORT)(tempebx >> 16);
+  temp = tempbx & 0x00FF;
+  temp <<= 4;
+  temp |= ((tempcx & 0xFF00) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x19,temp);
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+
+         SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x1C,0x28);
+	 tempbx = 0;
+         tempax = SiS_Pr->SiS_VGAHDE;
+         if(modeflag & HalfDCLK) tempax >>= 1;
+         if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) || (SiS_Pr->SiS_HiVision & 0x03)) {
+	     if(HwDeviceExtension->jChipType >= SIS_315H) {
+	         if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) tempax >>= 1;
+		 else if(tempax > 800) tempax -= 800;
+	     } else {
+                 if(tempax > 800) tempax -= 800;
+             }
+         }
+
+         if((SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetPALTV)) && (!(SiS_Pr->SiS_HiVision & 0x03))) {
+           if(tempax > 800) {
+	      tempbx = 8;
+              if(tempax == 1024)
+	        tempax *= 25;
+              else
+	        tempax *= 20;
+
+	      temp = tempax % 32;
+	      tempax /= 32;
+	      tempax--;
+	      if (temp!=0) tempax++;
+           }
+         }
+	 tempax--;
+         temp = (tempax & 0xFF00) >> 8;
+         temp &= 0x03;
+	 SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x1D,tempax & 0x00FF);
+	 temp <<= 4;
+	 temp |= tempbx;
+	 SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x1E,temp);
+
+         temp = 0x0036;
+         if((SiS_Pr->SiS_VBInfo & (SetCRT2ToTV - SetCRT2ToHiVisionTV)) &&
+	                               (!(SiS_Pr->SiS_HiVision & 0x03))) {
+		temp |= 0x01;
+	        if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+	          if(!(SiS_Pr->SiS_SetFlag & TVSimuMode))
+  	                  temp &= 0xFE;
+		}
+         }
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x1F,0xC0,temp);
+
+	 tempbx = SiS_Pr->SiS_HT;
+	 if(HwDeviceExtension->jChipType >= SIS_315H) {
+	 	if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) tempbx >>= 1;
+	 }
+         tempbx >>= 1;
+	 tempbx -= 2;
+         temp = ((tempbx & 0x0700) >> 8) << 3;
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0xC0,temp);
+         temp = tempbx & 0x00FF;
+         SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x22,temp);
+         if( (SiS_Pr->SiS_VBType & (VB_SIS30xLV | VB_SIS30xNEW)) &&
+	                        (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) ) {
+             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x24,0x0e);
+	 }
+
+         /* TW: 650 BIOS does this for all bridge types - assumingly wrong */
+	 if(HwDeviceExtension->jChipType >= SIS_315H) {
+             /* TW: This is a duplicate; done for LCDA as well (see above) */
+	     if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) {
+		SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c);
+	     }
+	     SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x2a,0x00);
+	     SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
+	     SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
+         }
+
+  }  /* 301B */
+
+  SiS_SetCRT2VCLK(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+                  RefreshRateTableIndex,HwDeviceExtension);
 }
 
+/* TW: Double-Checked against 650/301LV(x) and 630/301B BIOS */
 void
-SiS_SetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR)
+SiS_SetCRT2VCLK(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                 USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT temp;
+  USHORT vclkindex;
+  USHORT tempah;
 
-  temp=SiS_GetReg1(Port,Index);     /* SiS_Part1Port index 02 */
-  temp=(temp&(DataAND))|DataOR;
-  SiS_SetReg1(Port,Index,temp);
+  vclkindex = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                              HwDeviceExtension);
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+   	tempah = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_A;
+   	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0A,tempah);
+   	tempah = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_B;
+   	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0B,tempah);
+	/* TW: New from 650/301LV, LVx BIOS */
+	if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {   /* 650/301LV: (VB_SIS301LV | VB_SIS302LV)) */
+           if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+	      if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+                 if((ModeNo == 0x4a) || (ModeNo == 0x38)) {
+		    SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0a,0x57);
+		    SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0b,0x46);
+		    SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x1f,0xf6);
+                 }
+              }
+           }
+	}
+  } else {	/* 650/301LVx does not do this anymore, jumps to SetRegs above - BUG? */
+   	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0A,0x01);
+   	tempah = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_B;
+   	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0B,tempah);
+   	tempah = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_A;
+   	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0A,tempah);
+  }
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x12,0x00);
+  tempah = 0x08;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
+    	tempah |= 0x20;
+  }
+  SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x12,tempah);
 }
 
-void
-SiS_SetRegAND(USHORT Port,USHORT Index,USHORT DataAND)
+/* TW: Double-checked against 650/LVDS (1.10.07), 630/301B/LVDS/LVDS+CH, 650/301LVx (1.10.6s) BIOS */
+USHORT
+SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT temp;
+  USHORT tempbx;
+#ifdef SIS300
+  const USHORT LCDXlat1VCLK300[4] = {VCLK65,   VCLK65,   VCLK65,   VCLK65};
+  const USHORT LCDXlat2VCLK300[4] = {VCLK108_2,VCLK108_2,VCLK108_2,VCLK108_2};
+  const USHORT LVDSXlat2VCLK300[4]= {VCLK65,   VCLK65,   VCLK65,   VCLK65};
+  const USHORT LVDSXlat3VCLK300[4]= {VCLK65,   VCLK65,   VCLK65,   VCLK65};
+#endif
+#ifdef SIS315H
+  const USHORT LCDXlat1VCLK310[4] = {VCLK65+2,   VCLK65+2,   VCLK65+2,   VCLK65+2};
+  const USHORT LCDXlat2VCLK310[4] = {VCLK108_2+5,VCLK108_2+5,VCLK108_2+5,VCLK108_2+5};
+  const USHORT LVDSXlat2VCLK310[4]= {VCLK65+2,   VCLK65+2,   VCLK65+2,   VCLK65+2};
+  const USHORT LVDSXlat3VCLK310[4]= {VCLK108_2+5,VCLK108_2+5,VCLK108_2+5,VCLK108_2+5};
+  			   /* {VCLK65+2,   VCLK65+2,   VCLK65+2,   VCLK65+2}; -  650/LVDS 1.10.07 */
+#endif
+  const USHORT LCDXlat0VCLK[4]    = {VCLK40, VCLK40, VCLK40, VCLK40};
+  const USHORT LVDSXlat1VCLK[4]   = {VCLK40, VCLK40, VCLK40, VCLK40};
+  USHORT CRT2Index,VCLKIndex=0;
+  USHORT modeflag,resinfo;
+  const UCHAR *CHTVVCLKPtr=NULL;
+  const USHORT *LCDXlatVCLK1 = NULL;
+  const USHORT *LCDXlatVCLK2 = NULL;
+  const USHORT *LVDSXlatVCLK2 = NULL;
+  const USHORT *LVDSXlatVCLK3 = NULL;
 
-  temp=SiS_GetReg1(Port,Index);     /* SiS_Part1Port index 02 */
-  temp=temp&DataAND;
-  SiS_SetReg1(Port,Index,temp);
+#ifdef SIS315H
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+		LCDXlatVCLK1 = LCDXlat1VCLK310;
+		LCDXlatVCLK2 = LCDXlat2VCLK310;
+		LVDSXlatVCLK2 = LVDSXlat2VCLK310;
+		LVDSXlatVCLK3 = LVDSXlat3VCLK310;
+  } else {
+#endif
+#ifdef SIS300
+		LCDXlatVCLK1 = LCDXlat1VCLK300;
+		LCDXlatVCLK2 = LCDXlat2VCLK300;
+		LVDSXlatVCLK2 = LVDSXlat2VCLK300;
+		LVDSXlatVCLK3 = LVDSXlat3VCLK300;
+#endif
+#ifdef SIS315H
+  }
+#endif
+
+  if(ModeNo<=0x13) {
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+    	resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+    	CRT2Index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+    	CRT2Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+  }
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {    /* 301 */
+
+     if (SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {
+
+        CRT2Index >>= 6;
+        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)){      /*  LCD */
+            if(HwDeviceExtension->jChipType < SIS_315H) {
+	       /* TW: Inserted from 630/301B BIOS */
+	       if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)
+	    		VCLKIndex = LCDXlat0VCLK[CRT2Index];
+	       else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)
+	    		VCLKIndex = LCDXlatVCLK1[CRT2Index];
+	       else
+	    		VCLKIndex = LCDXlatVCLK2[CRT2Index];
+	    } else {
+               /* TW: 650/301LV BIOS does not check expanding, 315 does  */
+	       if( (HwDeviceExtension->jChipType > SIS_315PRO) ||
+	           (!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) ) {
+      	          if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+		     VCLKIndex = 0x19;
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+		     VCLKIndex = 0x19;
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
+		     VCLKIndex = 0x21;
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+		     VCLKIndex = LCDXlatVCLK1[CRT2Index];
+                  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
+		     VCLKIndex = 0x45;
+		     if(resinfo == 0x09) VCLKIndex++;
+	          } else {
+		     VCLKIndex = LCDXlatVCLK2[CRT2Index];
+      	          }
+	       } else {
+                   VCLKIndex = (UCHAR)SiS_GetReg2((USHORT)(SiS_Pr->SiS_P3ca+0x02));  /*  Port 3cch */
+         	   VCLKIndex = ((VCLKIndex >> 2) & 0x03);
+        	   if(ModeNo > 0x13) {
+          		VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+        	   }
+		   if(ModeNo <= 0x13) {  /* TW: Inserted from 315 BIOS */
+		      if(SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC == 1) VCLKIndex = 0x42;
+		   }
+		   if(VCLKIndex == 0) VCLKIndex = 0x41;
+		   if(VCLKIndex == 1) VCLKIndex = 0x43;
+		   if(VCLKIndex == 4) VCLKIndex = 0x44;
+	       }
+	    }
+        } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {                 /*  TV */
+        	if((SiS_Pr->SiS_IF_DEF_HiVision == 1) && (SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)) {
+          		if(SiS_Pr->SiS_SetFlag & RPLLDIV2XO)  VCLKIndex = HiTVVCLKDIV2;
+     			else                                  VCLKIndex = HiTVVCLK;
+          		if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+            			if(modeflag & Charx8Dot)      VCLKIndex = HiTVSimuVCLK;
+            			else 			      VCLKIndex = HiTVTextVCLK;
+          		}
+        	} else {
+       			if(SiS_Pr->SiS_SetFlag & RPLLDIV2XO)  VCLKIndex = TVVCLKDIV2;
+            		else         		              VCLKIndex = TVVCLK;
+          	}
+		if(HwDeviceExtension->jChipType >= SIS_315H) {
+              		VCLKIndex += 25;
+  		}
+        } else {         					/* RAMDAC2 */
+        	VCLKIndex = (UCHAR)SiS_GetReg2((USHORT)(SiS_Pr->SiS_P3ca+0x02));
+        	VCLKIndex = ((VCLKIndex >> 2) & 0x03);
+        	if(ModeNo > 0x13) {
+          		VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+			if(HwDeviceExtension->jChipType < SIS_315H) {
+          			VCLKIndex &= 0x3f;
+				if( (HwDeviceExtension->jChipType == SIS_630) &&
+				    (HwDeviceExtension->jChipRevision >= 0x30)) {
+				     if(VCLKIndex == 0x14) VCLKIndex = 0x2e;
+				}
+			}
+        	}
+        }
+
+    } else {   /* If not programming CRT2 */
+
+        VCLKIndex = (UCHAR)SiS_GetReg2((USHORT)(SiS_Pr->SiS_P3ca+0x02));
+        VCLKIndex = ((VCLKIndex >> 2) & 0x03);
+        if(ModeNo > 0x13) {
+             VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+	     if(HwDeviceExtension->jChipType < SIS_315H) {
+                VCLKIndex &= 0x3f;
+		if( (HwDeviceExtension->jChipType != SIS_630) &&
+		    (HwDeviceExtension->jChipType != SIS_300) ) {
+		   if(VCLKIndex == 0x1b) VCLKIndex = 0x35;
+		}
+	     }
+        }
+    }
+
+  } else {       /*   LVDS  */
+
+    	VCLKIndex = CRT2Index;
+
+	if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {  /* programming CRT2 */
+
+	   if( (SiS_Pr->SiS_IF_DEF_CH70xx != 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) ) {
+
+		VCLKIndex &= 0x1f;
+        	tempbx = 0;
+        	if(SiS_Pr->SiS_VBInfo & SetPALTV) tempbx += 2;
+        	if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
+       		switch(tempbx) {
+          	   case 0: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUNTSC;  break;
+         	   case 1: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKONTSC;  break;
+                   case 2: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUPAL;   break;
+                   case 3: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPAL;   break;
+        	}
+        	VCLKIndex = CHTVVCLKPtr[VCLKIndex];
+
+	   } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+
+	        VCLKIndex >>= 6;
+     		if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) ||
+		                   (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel320x480))
+     			VCLKIndex = LVDSXlat1VCLK[VCLKIndex];
+     		else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)
+     			VCLKIndex = LVDSXlatVCLK2[VCLKIndex];
+		else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)
+                        VCLKIndex = LVDSXlatVCLK2[VCLKIndex];
+     		else    VCLKIndex = LVDSXlatVCLK3[VCLKIndex];
+
+	   } else {
+
+	        VCLKIndex = (UCHAR)SiS_GetReg2((USHORT)(SiS_Pr->SiS_P3ca+0x02));
+                VCLKIndex = ((VCLKIndex >> 2) & 0x03);
+                if(ModeNo > 0x13) {
+                     VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+		     if( (HwDeviceExtension->jChipType == SIS_630) &&
+                         (HwDeviceExtension->jChipRevision >= 0x30) ) {
+		         	if(VCLKIndex == 0x14) VCLKIndex = 0x2e;
+		     }
+	        }
+
+	   }
+
+	} else {  /* if not programming CRT2 */
+
+	   VCLKIndex = (UCHAR)SiS_GetReg2((USHORT)(SiS_Pr->SiS_P3ca+0x02));
+           VCLKIndex = ((VCLKIndex >> 2) & 0x03);
+           if(ModeNo > 0x13) {
+              VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+              if(HwDeviceExtension->jChipType < SIS_315H) {
+	         if( (HwDeviceExtension->jChipType != SIS_630) &&
+		     (HwDeviceExtension->jChipType != SIS_300) ) {
+		        if(VCLKIndex == 0x1b) VCLKIndex = 0x35;
+	         }
+	      }
+	   }
+
+	}
+
+  }
+
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+    	VCLKIndex &= 0x3F;
+  }
+  return (VCLKIndex);
 }
 
-void SiS_SetRegOR(USHORT Port,USHORT Index,USHORT DataOR)
+/* TW: Set 301 Palette address port registers */
+/* TW: Checked against 650/301LV BIOS */
+void
+SiS_SetGroup5(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr,
+              UCHAR *ROMAddr, USHORT ModeNo, USHORT ModeIdIndex)
 {
-  USHORT temp;
 
-  temp=SiS_GetReg1(Port,Index);     /* SiS_Part1Port index 02 */
-  temp=temp|DataOR;
-  SiS_SetReg1(Port,Index,temp);
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)  return;
+
+  if(SiS_Pr->SiS_ModeType == ModeVGA){
+    if(!(SiS_Pr->SiS_VBInfo & (SetInSlaveMode | LoadDACFlag))){
+      SiS_EnableCRT2(SiS_Pr);
+      SiS_LoadDAC(SiS_Pr,HwDeviceExtension,ROMAddr,ModeNo,ModeIdIndex);
+    }
+  }
+  return;
 }
 
+/* TW: Checked against 650/LVDS and 630/301B BIOS */
 void
-SiS_SetGroup2(USHORT BaseAddr,ULONG ROMAddr, USHORT ModeNo,
-                   USHORT ModeIdIndex,USHORT RefreshRateTableIndex,
-		   PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_ModCRT1CRTC(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT i,j,tempax,tempbx,tempcx,temp,temp3;
-  USHORT push1,push2,temp1;
-  UCHAR *PhasePoint;
-  UCHAR *TimingPoint;
-  USHORT  modeflag,resinfo,crt2crtc,resindex,xres;
-  ULONG longtemp,tempeax,tempebx,temp2,tempecx;
-  USHORT  SiS_RY1COE=0,SiS_RY2COE=0,SiS_RY3COE=0,SiS_RY4COE=0;
-  USHORT  SiS_RY5COE=0,SiS_RY6COE=0,SiS_RY7COE=0;
+  USHORT temp,tempah,i,modeflag,j;
+  USHORT ResInfo,DisplayType;
+  const SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr=NULL;
 
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-    	resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
-    	crt2crtc = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-    	resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-    	crt2crtc = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-  }
-
-  tempcx=SiS_VBInfo;
-  tempax=(tempcx&0x00FF)<<8;
-  tempbx=(tempcx&0x00FF)|((tempcx&0x00FF)<<8);
-  tempbx=tempbx&0x0410;
-  temp=(tempax&0x0800)>>8;
-  temp=temp>>1;
-  temp=temp|(((tempbx&0xFF00)>>8)<<1);
-  temp=temp|((tempbx&0x00FF)>>3);
-  temp=temp^0x0C;
-
-  PhasePoint = SiS_PALPhase;
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {        /* PALPhase */
-    temp=temp^0x01;
-    if(SiS_VBInfo&SetInSlaveMode) {
-      TimingPoint = SiS_HiTVSt2Timing;
-      if(SiS_SetFlag&TVSimuMode) {
-        if(modeflag&Charx8Dot) TimingPoint = SiS_HiTVSt1Timing;
-        else TimingPoint = SiS_HiTVTextTiming;
-      }
-    } else TimingPoint = SiS_HiTVExtTiming;
-  } else {
-    if(SiS_VBInfo&SetPALTV){
-      if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-         PhasePoint = SiS_PALPhase2;              /* PALPhase */
-      else 
-         PhasePoint = SiS_PALPhase;  
-     
-         TimingPoint = SiS_PALTiming;
-    } else {
-        temp=temp|0x10;
-        if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-        	PhasePoint = SiS_NTSCPhase2;             /* PALPhase */
-        else
-        	PhasePoint = SiS_NTSCPhase;
-      
-        TimingPoint = SiS_NTSCTiming;
-    }
+  if(ModeNo <= 0x13) {
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
   }
-  SiS_SetReg1(SiS_Part2Port,0x00,temp);
 
-#ifdef SIS300
-  /*add PALMN*/
-  if((HwDeviceExtension->jChipType==SIS_630)||
-     (HwDeviceExtension->jChipType==SIS_730)) {
-     	if(SiS_VBInfo&SetCRT2ToTV) {
-             temp=SiS_GetReg1(SiS_P3d4,0x31);   
-             temp=temp&0x01; 
-             if(temp) {
-                  temp1=SiS_GetReg1(SiS_P3d4,0x35);        
-                  temp1=temp1&0x40; 
-                  if(temp1)
-                     	PhasePoint = SiS_PALMPhase;
-                  temp1=SiS_GetReg1(SiS_P3d4,0x35);        
-                  temp1=temp1&0x80;
-                  if(temp1)
-                     	PhasePoint = SiS_PALNPhase;
-             }
-        }
+  temp = SiS_GetLVDSCRT1Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                            &ResInfo,&DisplayType);
+
+  if(temp == 0) return;
+
+  /* TW: Inserted from 630/LVDS BIOS */
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+     if(SiS_Pr->SiS_SetFlag & CRT2IsVGA) return;
   }
-  /*end add*/
-#endif
 
-#ifdef SIS315H
-  /*add PALMN*/
-  if ( (HwDeviceExtension->jChipType==SIS_315H)||
-       (HwDeviceExtension->jChipType==SIS_315PRO)||
-       (HwDeviceExtension->jChipType==SIS_550) ||
-       (HwDeviceExtension->jChipType==SIS_640) ||
-       (HwDeviceExtension->jChipType==SIS_740) ||
-       (HwDeviceExtension->jChipType==SIS_650)) {
-           if(SiS_VBInfo&SetCRT2ToTV) {
-              temp=SiS_GetReg1(SiS_P3d4,0x31);
-              temp=temp&0x01;
-              if(temp) {
-                  temp1=SiS_GetReg1(SiS_P3d4,0x38);
-                  temp1=temp1&0x40;
-                  if(temp1)
-                     PhasePoint = SiS_PALMPhase;
-                  temp1=SiS_GetReg1(SiS_P3d4,0x38);
-                  temp1=temp1&0x80;
-                  if(temp1)
-                     PhasePoint = SiS_PALNPhase;
-              }
-           }
+  switch(DisplayType) {
+    case 0 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1;           break;
+    case 1 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1;          break;
+    case 2 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1;         break;
+    case 3 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1_H;         break;
+    case 4 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1_H;        break;
+    case 5 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1_H;       break;
+    case 6 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2;           break;
+    case 7 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2;          break;
+    case 8 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2;         break;
+    case 9 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2_H;         break;
+    case 10: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2_H;        break;
+    case 11: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2_H;       break;
+    case 12: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1;           break;
+    case 13: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H;         break;
+    case 14: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1;         break;
+    case 15: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1_H;       break;
+    case 16: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2;         break;
+    case 17: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2_H;       break;
+    case 18: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UNTSC;               break;
+    case 19: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1ONTSC;               break;
+    case 20: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UPAL;                break;
+    case 21: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1OPAL;                break;
+    case 22: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x480_1;           break; /* FSTN */
+    case 23: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1;          break;
+    case 24: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1_H;        break;
+    case 25: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2;          break;
+    case 26: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2_H;        break;
+    case 27: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_1;          break;
+    case 28: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_1_H;        break;
+    case 29: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_2;          break;
+    case 30: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_2_H;        break;
+    case 36: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_1;         break;
+    case 37: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_1_H;       break;
+    case 38: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_2;         break;
+    case 39: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_2_H;       break;
   }
-  /*end add*/
-#endif
 
-  for(i=0x31,j=0;i<=0x34;i++,j++){
-     SiS_SetReg1(SiS_Part2Port,i,PhasePoint[j]);
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);                        /*unlock cr0-7  */
+
+  tempah = (LVDSCRT1Ptr+ResInfo)->CR[0];
+  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x00,tempah);
+
+  for(i=0x02,j=1;i<=0x05;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+  }
+  for(i=0x06,j=5;i<=0x07;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+  }
+  for(i=0x10,j=7;i<=0x11;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
   }
-  for(i=0x01,j=0;i<=0x2D;i++,j++){
-     SiS_SetReg1(SiS_Part2Port,i,TimingPoint[j]);
+  for(i=0x15,j=9;i<=0x16;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
   }
-  for(i=0x39;i<=0x45;i++,j++){
-     SiS_SetReg1(SiS_Part2Port,i,TimingPoint[j]);      /* di->temp2[j] */
+  for(i=0x0A,j=11;i<=0x0C;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3c4,i,tempah);
   }
-  if(SiS_VBInfo&SetCRT2ToTV) {
-    SiS_SetRegANDOR(SiS_Part2Port,0x3A,0x1F,0x00);
+
+  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
+  tempah &= 0xE0;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0x1f,tempah);     	/* TW: Modfied (650/LVDS); Was SetReg(tempah) */
+
+  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
+  tempah &= 0x01;
+  tempah <<= 5;
+  if(modeflag & DoubleScanMode){
+    	tempah |= 0x080;
+  }
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,~0x020,tempah);
+
+  /* TW: Inserted from 650/LVDS BIOS */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+     if(modeflag & HalfDCLK)
+        SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);
   }
-  temp=SiS_NewFlickerMode;
-  SiS_SetRegANDOR(SiS_Part2Port,0x0A,0xFF,temp);
 
-  SiS_SetReg1(SiS_Part2Port,0x35,0x00); /*301b*/
-  SiS_SetReg1(SiS_Part2Port,0x36,0x00);
-  SiS_SetReg1(SiS_Part2Port,0x37,0x00);
-  SiS_SetReg1(SiS_Part2Port,0x38,SiS_RY1COE);
-  SiS_SetReg1(SiS_Part2Port,0x48,SiS_RY2COE);
-  SiS_SetReg1(SiS_Part2Port,0x49,SiS_RY3COE);
-  SiS_SetReg1(SiS_Part2Port,0x4a,SiS_RY4COE);
+  return;
+}
+
+#if 0 /* TW: Unused */
+/*301b*/
+void
+SiS_CHACRT1CRTC(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                USHORT RefreshRateTableIndex)
+{
+  USHORT temp,tempah,i,modeflag,j;
+  USHORT ResInfo,DisplayType;
+  SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr=NULL;
 
-  /*add to change 630+301b filter*/
-  resindex=SiS_GetResInfo(ROMAddr,ModeNo,ModeIdIndex);
   if(ModeNo<=0x13) {
-      xres=SiS_StResInfo[resindex].HTotal;
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
   } else {
-      xres=SiS_ModeResInfo[resindex].HTotal;                         /* xres->ax */
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
   }
-  if(xres==640){SiS_RY1COE=0xFF;SiS_RY2COE=0x03;SiS_RY3COE=0x02;SiS_RY4COE=0xF6;
-                         SiS_RY5COE=0xFC;SiS_RY6COE=0x27;SiS_RY7COE=0x46;}
-  if(xres==800){SiS_RY1COE=0x01;SiS_RY2COE=0x01;SiS_RY3COE=0xFC;SiS_RY4COE=0xF8;
-                         SiS_RY5COE=0x08;SiS_RY6COE=0x26;SiS_RY7COE=0x38;}                        
-  if(xres==1024){SiS_RY1COE=0xFF;SiS_RY2COE=0xFF;SiS_RY3COE=0xFC;SiS_RY4COE=0x00;
-                         SiS_RY5COE=0x0F;SiS_RY6COE=0x22;SiS_RY7COE=0x28;}
-  if(xres==720){SiS_RY1COE=0x01;SiS_RY2COE=0x02;SiS_RY3COE=0xFE;SiS_RY4COE=0xF7;
-                         SiS_RY5COE=0x03;SiS_RY6COE=0x27;SiS_RY7COE=0x3c;}
-  SiS_SetReg1(SiS_Part2Port,0x35,SiS_RY1COE); /*301b*/
-  SiS_SetReg1(SiS_Part2Port,0x36,SiS_RY2COE);
-  SiS_SetReg1(SiS_Part2Port,0x37,SiS_RY3COE);
-  SiS_SetReg1(SiS_Part2Port,0x38,SiS_RY4COE);
-  SiS_SetReg1(SiS_Part2Port,0x48,SiS_RY5COE);
-  SiS_SetReg1(SiS_Part2Port,0x49,SiS_RY6COE);
-  SiS_SetReg1(SiS_Part2Port,0x4a,SiS_RY7COE);
-  /*end add*/
 
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) tempax=950;
-  else {
-    if(SiS_VBInfo&SetPALTV) tempax=520;
-    else tempax=440;
+  temp=SiS_GetLVDSCRT1Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                       &ResInfo,&DisplayType);
+  if(temp==0){
+    return;
   }
-  if(SiS_VDE<=tempax) {
-    tempax=tempax-SiS_VDE;
-    tempax=tempax>>2;
-    tempax=(tempax&0x00FF)|((tempax&0x00FF)<<8);
-    push1=tempax;
-    temp=(tempax&0xFF00)>>8;
-    temp=temp+(USHORT)TimingPoint[0];
-    SiS_SetReg1(SiS_Part2Port,0x01,temp);
-    tempax=push1;
-    temp=(tempax&0xFF00)>>8;
-    temp=temp+TimingPoint[1];
-    SiS_SetReg1(SiS_Part2Port,0x02,temp);
-  }
-  /*301b*/
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-        && (SiS_VBInfo&SetCRT2ToTV) && (SiS_VGAHDE==1024) ) {
-      if(SiS_VBInfo&SetPALTV) {
-       SiS_SetReg1(SiS_Part2Port,0x01,0x19);
-       SiS_SetReg1(SiS_Part2Port,0x02,0x52);
-      } else {
-       SiS_SetReg1(SiS_Part2Port,0x01,0x0B);
-       SiS_SetReg1(SiS_Part2Port,0x02,0x11);
-      } 
-    }
-    
-  tempcx=SiS_HT-1;
-  /*301b*/
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-     tempcx=tempcx-1;   
-  }
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part2Port,0x1B,temp);
-  temp=(tempcx&0xFF00)>>8;
-  SiS_SetRegANDOR(SiS_Part2Port,0x1D,~0x0F,temp);
-
-  tempcx=SiS_HT>>1;
-  push1=tempcx;                           /* push cx */
-  tempcx=tempcx+7;
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-    tempcx=tempcx-4;
-  }
-  temp=(tempcx&0x00FF);
-  temp=temp<<4;
-  SiS_SetRegANDOR(SiS_Part2Port,0x22,0x0F,temp);
-
-  tempbx=TimingPoint[j]|((TimingPoint[j+1])<<8);
-  tempbx=tempbx+tempcx;
-  push2=tempbx;
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part2Port,0x24,temp);
-  temp=(tempbx&0xFF00)>>8;
-  temp=temp<<4;
-  SiS_SetRegANDOR(SiS_Part2Port,0x25,0x0F,temp);
-
-  tempbx=push2;
-  tempbx=tempbx+8;
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-    tempbx=tempbx-4;
-    tempcx=tempbx;
-  }
-  temp=(tempbx&0x00FF)<<4;
-  SiS_SetRegANDOR(SiS_Part2Port,0x29,0x0F,temp);
-
-  j=j+2;
-  tempcx=tempcx+(TimingPoint[j]|((TimingPoint[j+1])<<8));
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part2Port,0x27,temp);
-  temp=((tempcx&0xFF00)>>8)<<4;
-  SiS_SetRegANDOR(SiS_Part2Port,0x28,0x0F,temp);
-
-  tempcx=tempcx+8;
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-    tempcx=tempcx-4;
-  }
-  temp=tempcx&0xFF;
-  temp=temp<<4;
-  SiS_SetRegANDOR(SiS_Part2Port,0x2A,0x0F,temp);
-
-  tempcx=push1;                                       /* pop cx */
-  j=j+2;
-  temp=TimingPoint[j]|((TimingPoint[j+1])<<8);
-  tempcx=tempcx-temp;
-  temp=tempcx&0x00FF;
-  temp=temp<<4;
-  SiS_SetRegANDOR(SiS_Part2Port,0x2D,0x0F,temp);
-
-  tempcx=tempcx-11;
-  if(!(SiS_VBInfo&SetCRT2ToTV)){
-    tempax=SiS_GetVGAHT2();
-    tempcx=tempax-1;
-  }
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part2Port,0x2E,temp);	/* TW: BIOS 0x48, here 0x3f @@@ */
-
-  tempbx=SiS_VDE;
-  if(SiS_VGAVDE==360) tempbx=746;
-  if(SiS_VGAVDE==375) tempbx=746;
-  if(SiS_VGAVDE==405) tempbx=853;
-  if(SiS_VBInfo&SetCRT2ToTV) {
-    tempbx=tempbx>>1;
-  }
-  tempbx=tempbx-2;
-  temp=tempbx&0x00FF;
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-    if(SiS_VBInfo&SetInSlaveMode) {
-      if(ModeNo==0x2f) temp=temp+1;
-    }
-  }
-  SiS_SetReg1(SiS_Part2Port,0x2F,temp);
-
-  temp=(tempcx&0xFF00)>>8;
-  temp=temp|(((tempbx&0xFF00)>>8)<<6);
-  if(!(SiS_VBInfo&SetCRT2ToHiVisionTV)) {
-    temp=temp|0x10;
-    if(!(SiS_VBInfo&SetCRT2ToSVIDEO)){
-      temp=temp|0x20;
-    }
-  }
-  SiS_SetReg1(SiS_Part2Port,0x30,temp);  /* TW: BIOS sets 0xb8, here (or somewhere else) 0xb5 */
-
-  /*301b*/
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {      /*tv gatingno*/
-    tempbx=SiS_VDE;
-    if(SiS_VBInfo&SetCRT2ToTV) {
-       tempbx=tempbx>>1;
-    }
-    temp=(((tempbx-3)&0x0300)>>8)<<5;
-    SiS_SetReg1(SiS_Part2Port,0x46,temp);
-    temp=(tempbx-3)&0x00FF;
-    SiS_SetReg1(SiS_Part2Port,0x47,temp);
-  }
-  /*end 301b*/
-
-  tempbx=tempbx&0x00FF;
-  if(!(modeflag&HalfDCLK)){
-    tempcx=SiS_VGAHDE;
-    if(tempcx>=SiS_HDE){
-      tempbx=tempbx|0x2000;
-      tempax=tempax&0x00FF;
-    }
-  }
-  tempcx=0x0101;
-
-  if(SiS_VBInfo&(SetCRT2ToHiVisionTV|SetCRT2ToTV)) { /*301b*/
-    if(SiS_VGAHDE>=1024) {
-      tempcx=0x1920;
-      if(SiS_VGAHDE>=1280) {
-        tempcx=0x1420;
-        tempbx=tempbx&0xDFFF;
-      }
-    }
-  }
-  if(!(tempbx&0x2000)){
-    if(modeflag&HalfDCLK){
-      tempcx=(tempcx&0xFF00)|((tempcx&0x00FF)<<1);
-    }
-    push1=tempbx;
-    tempeax=SiS_VGAHDE;
-    tempebx=(tempcx&0xFF00)>>8;
-    longtemp=tempeax*tempebx;
-    tempecx=tempcx&0x00FF;
-    longtemp=longtemp/tempecx;
-    /*301b*/
-    tempecx=8*1024;
-    if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-     	tempecx=tempecx*8;
-    }
-    longtemp=longtemp*tempecx;
-    tempecx=SiS_HDE;
-    temp2=longtemp%tempecx;
-    tempeax=longtemp/tempecx;
-    if(temp2!=0){
-      tempeax=tempeax+1;
-    }
-    tempax=(USHORT)tempeax;
-    /*301b*/
-    if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-     	tempcx=((tempax&0xFF00)>>5)>>8;
-    }
-    /*end 301b*/
-    tempbx=push1;
-    tempbx=(USHORT) ( ((tempeax&0x0000FF00)&0x1F00)|(tempbx&0x00FF) );
-    tempax=(USHORT) ( ((tempeax&0x000000FF)<<8)|(tempax&0x00FF) );
-    temp=(tempax&0xFF00)>>8;
-  } else {
-    temp=(tempax&0x00FF)>>8;
-  }
-  SiS_SetReg1(SiS_Part2Port,0x44,temp);
-  temp=(tempbx&0xFF00)>>8;
-  SiS_SetRegANDOR(SiS_Part2Port,0x45,~0x03F,temp);
-  /*301b*/
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-       if((tempcx&0x00FF)==0x01)
-    		tempcx=0x00;
-       SiS_SetRegANDOR(SiS_Part2Port,0x46,~0x007,tempcx);
-       SiS_SetRegOR(SiS_Part2Port,0x46,0x18);
-               if(SiS_VBInfo&SetPALTV) {
-                   tempbx=0x0364;
-                   tempcx=0x009c;
-               } else {
-                   tempbx=0x0346;
-                   tempcx=0x0078;
-               }
-       temp=(tempbx&0x00FF) ;
-       SiS_SetReg1(SiS_Part2Port,0x4B,temp);
-       temp=(tempcx&0x00FF) ;
-       SiS_SetReg1(SiS_Part2Port,0x4C,temp);
-       tempbx=(tempbx&0x0300);
-       temp=(tempcx&0xFF00)>>8 ;
-       temp=(temp&0x0003)<<2;
-       temp=temp|(tempbx>>8);
-       SiS_SetReg1(SiS_Part2Port,0x4D,temp);
 
-       temp=SiS_GetReg1(SiS_Part2Port,0x43); /*301b change */
-       SiS_SetReg1(SiS_Part2Port,0x43,(USHORT)(temp-3));
+  switch(DisplayType) {
+    case 0 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1;           break;
+    case 1 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1;          break;
+    case 2 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1;         break;
+    case 3 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1_H;         break;
+    case 4 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1_H;        break;
+    case 5 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1_H;       break;
+    case 6 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2;           break;
+    case 7 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2;          break;
+    case 8 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2;         break;
+    case 9 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2_H;         break;
+    case 10: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2_H;        break;
+    case 11: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2_H;       break;
+    case 12: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1;           break;
+    case 13: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H;         break;
+    case 14: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1;         break;
+    case 15: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1_H;       break;
+    case 16: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2;         break;
+    case 17: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2_H;       break;
+    case 18: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UNTSC;               break;
+    case 19: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1ONTSC;               break;
+    case 20: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UPAL;                break;
+    case 21: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1OPAL;                break;
+    case 22: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x480_1;           break; /* FSTN */
   }
-  /*end 301b*/
 
-#ifdef SIS300
-  /*add PALMN*/
-  if((HwDeviceExtension->jChipType==SIS_630)||
-     (HwDeviceExtension->jChipType==SIS_730)) {
-          if(SiS_VBInfo&SetCRT2ToTV) {
-             temp=SiS_GetReg1(SiS_P3d4,0x31);
-             temp=temp&0x01;
-             if(temp) {
-                  temp1=SiS_GetReg1(SiS_P3d4,0x35);
-                  temp1=temp1&0x40;
-                  if(temp1){
-                           SiS_SetRegANDOR(SiS_Part2Port,0x00,0xEF,0x00);
-                           temp3=SiS_GetReg1(SiS_Part2Port,0x01);
-                           temp3=temp3-1;
-                           SiS_SetReg1(SiS_Part2Port,0x01,temp3);
-                  }
-             }
-          }
+  tempah=(UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x11);                        /*unlock cr0-7  */
+  tempah=tempah&0x7F;
+  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x11,tempah);
+  tempah = (LVDSCRT1Ptr+ResInfo)->CR[0];
+  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x0,tempah);
+  for(i=0x02,j=1;i<=0x05;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+  }
+  for(i=0x06,j=5;i<=0x07;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+  }
+  for(i=0x10,j=7;i<=0x11;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+  }
+  for(i=0x15,j=9;i<=0x16;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+  }
+
+  for(i=0x0A,j=11;i<=0x0C;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3c4,i,tempah);
+  }
+
+  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
+  tempah=tempah&0x0E0;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x0E,tempah);
+
+  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
+  tempah=tempah&0x01;
+  tempah=tempah<<5;
+  if(modeflag&DoubleScanMode){
+    	tempah=tempah|0x080;
   }
-  /*end add*/
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,~0x020,tempah);
+  return;
+}
 #endif
 
-#ifdef SIS315H
-  /*add PALMN*/
-  if ( (HwDeviceExtension->jChipType==SIS_315H)||
-       (HwDeviceExtension->jChipType==SIS_315PRO)||
-       (HwDeviceExtension->jChipType==SIS_550) ||
-       (HwDeviceExtension->jChipType==SIS_640) ||
-       (HwDeviceExtension->jChipType==SIS_740) ||
-       (HwDeviceExtension->jChipType==SIS_650)) {
-        	if(SiS_VBInfo&SetCRT2ToTV) {
-             		temp=SiS_GetReg1(SiS_P3d4,0x31);
-            		temp=temp&0x01;
-              		if(temp) {
-                  		temp1=SiS_GetReg1(SiS_P3d4,0x38);
-                 		temp1=temp1&0x40;
-                   		if(temp1){
-                           		SiS_SetRegANDOR(SiS_Part2Port,0x00,0xEF,0x00);
-                           		temp3=SiS_GetReg1(SiS_Part2Port,0x01);
-                           		temp3=temp3-1;
-                           		SiS_SetReg1(SiS_Part2Port,0x01,temp3);
-                		}
-             		}
-          	}
+/* TW: Checked against 650/LVDS BIOS: modified for new panel resolutions */
+BOOLEAN
+SiS_GetLVDSCRT1Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+		   USHORT RefreshRateTableIndex,USHORT *ResInfo,
+		   USHORT *DisplayType)
+ {
+  USHORT tempbx,modeflag=0;
+  USHORT Flag,CRT2CRTC;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+      /* TW: Inserted from 650/LVDS BIOS */
+      if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+          if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) return 0;
+      }
   }
-  /*end add*/
-#endif
 
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-    if(!(SiS_VBInfo&SetInSlaveMode)) {
-      SiS_SetReg1(SiS_Part2Port,0x0B,0x00);
+  if(ModeNo <= 0x13) {
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+    	CRT2CRTC = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	CRT2CRTC = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+  }
+
+  Flag = 1;
+  tempbx = 0;
+  if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+    if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+      Flag = 0;
+      tempbx = 18;
+      if(SiS_Pr->SiS_VBInfo & SetPALTV) tempbx += 2;
+      if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx++;
     }
   }
-  if(SiS_VBInfo&SetCRT2ToTV){
-    return;
+  if(Flag) {
+    tempbx = SiS_Pr->SiS_LCDResInfo;
+    tempbx -= SiS_Pr->SiS_PanelMinLVDS;
+    if(SiS_Pr->SiS_LCDResInfo <= SiS_Pr->SiS_Panel1280x1024) {
+       if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx += 6;
+       if(modeflag & HalfDCLK) tempbx += 3;
+    } else {
+       if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+           tempbx = 14;
+	   if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx += 2;
+	   if(modeflag & HalfDCLK) tempbx++;
+       } else if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+           tempbx = 12;
+	   if(modeflag & HalfDCLK) tempbx++;
+       } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+           tempbx = 23;
+	   if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx += 2;
+	   if(modeflag & HalfDCLK) tempbx++;
+       } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
+           tempbx = 27;
+	   if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx += 2;
+	   if(modeflag & HalfDCLK) tempbx++;
+       } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
+           tempbx = 36;
+	   if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx += 2;
+	   if(modeflag & HalfDCLK) tempbx++;
+       }
+    }
   }
+  if(SiS_Pr->SiS_IF_DEF_FSTN){
+     if(SiS_Pr->SiS_LCDResInfo==SiS_Pr->SiS_Panel320x480){
+       tempbx=22;
+     }
+  }
+  *ResInfo = CRT2CRTC & 0x3F;
+  *DisplayType = tempbx;
+  return 1;
+}
 
-  /* TW: From here: LCD Part2 group */
+/* TW: Checked against 650/LVDS (1.10a, 1.10.07), 630/301B (I/II) and 630/LVDS BIOS */
+void
+SiS_SetCRT2ECLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex,
+           USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT tempah,tempal,pushax;
+  USHORT vclkindex=0;
 
-  tempbx=SiS_HDE-1;         /* RHACTE=HDE-1 */
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part2Port,0x2C,temp);
-  temp=(tempbx&0xFF00)>>8;
-  temp=temp<<4;
-  SiS_SetRegANDOR(SiS_Part2Port,0x2B,0x0F,temp);
-  temp=0x01;
-  if(SiS_LCDResInfo==Panel1280x1024) {
-    if(SiS_ModeType==ModeEGA) {
-      if(SiS_VGAHDE>=1024) {
-        temp=0x02;
-        if (SiS_SetFlag&LCDVESATiming)
-          temp=0x01;
-      }
-    }
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) return;
+     }
   }
-  SiS_SetReg1(SiS_Part2Port,0x0B,temp);
 
-  tempbx=SiS_VDE;         /* RTVACTEO=(VDE-1)&0xFF */
-  push1=tempbx;
-  tempbx--;
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part2Port,0x03,temp);
-  temp=((tempbx&0xFF00)>>8)&0x07;
-  SiS_SetRegANDOR(SiS_Part2Port,0x0C,~0x07,temp);
-
-  tempcx=SiS_VT-1;
-  push2=tempcx+1;
-  temp=tempcx&0x00FF;   /* RVTVT=VT-1 */
-  SiS_SetReg1(SiS_Part2Port,0x19,temp);
-  temp=(tempcx&0xFF00)>>8;
-  temp=temp<<5;
-  if(SiS_LCDInfo&LCDRGB18Bit){
-    temp=temp|0x10;
-  }
-  if(SiS_VBInfo&SetCRT2ToLCD) {
-    tempbx=(tempbx&0xFF00)|(SiS_LCDInfo&0x0FF);
-    if(tempbx&LCDSync) {
-      tempbx=tempbx&LCDSyncBit;
-      tempbx=(tempbx&0xFF00)|((tempbx&0x00FF)>>LCDSyncShift);
-      temp=temp|(tempbx&0x00FF);
-    }
+  if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) || (SiS_Pr->SiS_IF_DEF_TRUMPION == 1)) {
+	SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
+        tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+    	tempal &= 0x3F;
+	if(tempal == 2) RefreshRateTableIndex--;
+	vclkindex = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+                               RefreshRateTableIndex,HwDeviceExtension);
+	SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+  } else {
+        vclkindex = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+                               RefreshRateTableIndex,HwDeviceExtension);
   }
-  SiS_SetReg1(SiS_Part2Port,0x1A,temp);
 
-  tempcx++;
-  tempbx=768;
-  if(SiS_LCDResInfo!=Panel1024x768) {
-    tempbx=1024;
-    if(SiS_LCDResInfo!=Panel1280x1024) {
-         tempbx=1200;     /*301b */
-         if(SiS_LCDResInfo!=Panel1600x1200) {
-            if(tempbx!=SiS_VDE) {
-               tempbx=960;
-            }
-         }
-    }
+  tempal = 0x02B;
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+     if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+    	tempal += 3;
+     }
   }
-  if(SiS_LCDInfo&LCDNonExpanding) {
-    tempbx=SiS_VDE;
-    tempbx--;
-    tempcx--;
-  }
-  tempax=1;
-  if(!(SiS_LCDInfo&LCDNonExpanding)) {
-    if(tempbx!=SiS_VDE){
-      tempax=tempbx;
-      if(tempax<SiS_VDE) {
-        tempax=0;
-        tempcx=0;
-      } else {
-        tempax=tempax-SiS_VDE;
-      }
-      tempax=tempax>>1;
-    }
-    tempcx=tempcx-tempax; /* lcdvdes */
-    tempbx=tempbx-tempax; /* lcdvdee */
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
+  pushax = tempal;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x20);
+  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2B;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
+  tempal++;
+  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2C;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x10);
+  tempal = pushax;
+  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2B;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
+  tempal++;
+  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2C;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x00);
+  tempal = pushax;
+  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2B;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
+  tempal++;
+  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2C;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
+  return;
+}
+
+#if 0  /* TW: Not used */
+void
+SiS_SetDefCRT2ExtRegs(SiS_Private *SiS_Pr, USHORT BaseAddr)
+{
+  USHORT  temp;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS==0) {
+    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x02,0x40);
+    SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x10,0x80);
+    temp=(UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
+    temp &= 0xC3;
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,0x35,temp);
   } else {
-    tempax=tempax>>1;
-    tempcx=tempcx-tempax; /* lcdvdes */
-    tempbx=tempbx-tempax; /* lcdvdee */
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,0x32,0x02);
+    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x02,0x00);
   }
+}
+#endif
 
-  temp=tempcx&0x00FF;   /* RVEQ1EQ=lcdvdes */
-  SiS_SetReg1(SiS_Part2Port,0x05,temp);
-  temp=tempbx&0x00FF;   /* RVEQ2EQ=lcdvdee */
-  SiS_SetReg1(SiS_Part2Port,0x06,temp);
+/* TW: Start of Chrontel 70xx functions ---------------------- */
 
-  /* TW new @@@ */
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-        /* TW: BIOS sets Part2 0x02 to 0x18. The old caluculation (in else statement)
-	 *     resulted in 0x13. Do it this way for 301B?
-	 */
-        temp=(((tempcx&0xFF00)>>8)<<3);   /* 0x325 & ff00 = 300 >> 8 = 3 << 3 = 0x18 */
-	SiS_SetReg1(SiS_Part2Port,0x02,temp);
-  } else {
-  /* TW end */
-  	temp=(tempbx&0xFF00)>>8;
-  	temp=temp<<3;
-  	temp=temp|((tempcx&0xFF00)>>8);
-  	SiS_SetReg1(SiS_Part2Port,0x02,temp);
-  }
-
-  tempbx=push2;  	/* SiS_VT = 0x326  - - - (TW DEBUG REMARKS)*/
-  tempax=push1;  	/* SiS_VDE = 0x300 */
-  tempcx=tempbx;
-  tempcx=tempcx-tempax; /* -> 0x26 */
-  tempcx=tempcx>>4;     /* -> 0x02 */
-  tempbx=tempbx+tempax; /* -> 0x626 */
-  tempbx=tempbx>>1;     /* -> 0x313 */
-  if(SiS_LCDInfo&LCDNonExpanding) {
-     tempbx=tempbx-10;
-  }
-  /* TW new @@@ */
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-  	/* TW: BIOS sets Part2 0x04 to 0x02. The old caluculation (in else statement)
-	 *     resulted in 0x13. Do it this way for 301B?
-	 */
-        temp=tempcx&0x00FF;
-	SiS_SetReg1(SiS_Part2Port,0x04,temp);
-  } else {
-  /* TW end */
-    	temp=tempbx&0x00FF;   		/* RTVACTEE=lcdvrs */
-  	SiS_SetReg1(SiS_Part2Port,0x04,temp);   /* TW: BIOS: 0x02, here 0x13 */
-  }
-
- temp=(tempbx&0xFF00)>>8;
- temp=temp<<4;
- tempbx=tempbx+tempcx+1;
- temp=temp|(tempbx&0x000F);
- SiS_SetReg1(SiS_Part2Port,0x01,temp);
-
- if(SiS_LCDResInfo==Panel1024x768) {
-   if(!(SiS_SetFlag&LCDVESATiming)) {
-     if(!(SiS_LCDInfo&LCDNonExpanding)) {
-       if(ModeNo==0x13) {
-         SiS_SetReg1(SiS_Part2Port,0x04,0xB9);
-         SiS_SetReg1(SiS_Part2Port,0x05,0xCC);
-         SiS_SetReg1(SiS_Part2Port,0x06,0xA6);
+/* Set-up the Chrontel Registers */
+void
+SiS_SetCHTVReg(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+               USHORT RefreshRateTableIndex)
+{
+  USHORT temp, tempbx, tempcl;
+  USHORT TVType, resindex;
+  const SiS_CHTVRegDataStruct *CHTVRegData = NULL;
+
+  if(ModeNo <= 0x13)
+    	tempcl = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  else
+    	tempcl = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+
+  TVType = 0;
+  if(SiS_Pr->SiS_VBInfo & SetPALTV) TVType += 2;
+  if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) TVType += 1;
+  switch(TVType) {
+    	case 0: CHTVRegData = SiS_Pr->SiS_CHTVReg_UNTSC; break;
+    	case 1: CHTVRegData = SiS_Pr->SiS_CHTVReg_ONTSC; break;
+    	case 2: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPAL;  break;
+    	case 3: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL;  break;
+  }
+  resindex = tempcl & 0x3F;
+
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+
+     /* Chrontel 7005 */
+
+     /* TW: We don't support modes >800x600 */
+     if (resindex > 5) return;
+
+     if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+    	SiS_SetCH700x(SiS_Pr,0x4304);   /* TW: 0x40=76uA (PAL); 0x03=15bit non-multi RGB*/
+    	SiS_SetCH700x(SiS_Pr,0x6909);	/* TW: Black level for PAL (105)*/
+     } else {
+    	SiS_SetCH700x(SiS_Pr,0x0304);   /* TW: upper nibble=71uA (NTSC), 0x03=15bit non-multi RGB*/
+    	SiS_SetCH700x(SiS_Pr,0x7109);	/* TW: Black level for NTSC (113)*/
+     }
+
+     temp = CHTVRegData[resindex].Reg[0];
+     tempbx=((temp&0x00FF)<<8)|0x00;	/* TW: Mode register */
+     SiS_SetCH700x(SiS_Pr,tempbx);
+     temp = CHTVRegData[resindex].Reg[1];
+     tempbx=((temp&0x00FF)<<8)|0x07;	/* TW: Start active video register */
+     SiS_SetCH700x(SiS_Pr,tempbx);
+     temp = CHTVRegData[resindex].Reg[2];
+     tempbx=((temp&0x00FF)<<8)|0x08;	/* TW: Position overflow register */
+     SiS_SetCH700x(SiS_Pr,tempbx);
+     temp = CHTVRegData[resindex].Reg[3];
+     tempbx=((temp&0x00FF)<<8)|0x0A;	/* TW: Horiz Position register */
+     SiS_SetCH700x(SiS_Pr,tempbx);
+     temp = CHTVRegData[resindex].Reg[4];
+     tempbx=((temp&0x00FF)<<8)|0x0B;	/* TW: Vertical Position register */
+     SiS_SetCH700x(SiS_Pr,tempbx);
+
+     /* TW: Set minimum flicker filter for Luma channel (SR1-0=00),
+                minimum text enhancement (S3-2=10),
+   	        maximum flicker filter for Chroma channel (S5-4=10)
+	        =00101000=0x28 (When reading, S1-0->S3-2, and S3-2->S1-0!)
+      */
+     SiS_SetCH700x(SiS_Pr,0x2801);
+
+     /* TW: Set video bandwidth
+            High bandwith Luma composite video filter(S0=1)
+            low bandwith Luma S-video filter (S2-1=00)
+	    disable peak filter in S-video channel (S3=0)
+	    high bandwidth Chroma Filter (S5-4=11)
+	    =00110001=0x31
+     */
+     SiS_SetCH700x(SiS_Pr,0xb103);       /* old: 3103 */
+
+     /* TW: Register 0x3D does not exist in non-macrovision register map
+            (Maybe this is a macrovision register?)
+      */
+     /* SiS_SetCH70xx(SiS_Pr,0x003D); */
+
+     /* TW: Register 0x10 only contains 1 writable bit (S0) for sensing,
+            all other bits a read-only. Macrovision?
+      */
+     SiS_SetCH70xxANDOR(SiS_Pr,0x0010,0x1F);
+
+     /* TW: Register 0x11 only contains 3 writable bits (S0-S2) for
+            contrast enhancement (set to 010 -> gain 2 Yout = 9/8*(Yin-57) )
+      */
+     SiS_SetCH70xxANDOR(SiS_Pr,0x0211,0xF8);
+
+     /* TW: Clear DSEN
+      */
+     SiS_SetCH70xxANDOR(SiS_Pr,0x001C,0xEF);
+
+     if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {		/* ---- NTSC ---- */
+       if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) {
+         if(resindex == 0x04) {   			/* 640x480 overscan: Mode 16 */
+      	   SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF);   	/* loop filter off */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE);      /* ACIV on, no need to set FSCI */
+         } else {
+           if(resindex == 0x05) {    			/* 800x600 overscan: Mode 23 */
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0118,0xF0);	/* 0x18-0x1f: FSCI 469,762,048 */
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0C19,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x001A,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x001B,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x001C,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x001D,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x001E,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x001F,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0120,0xEF);     /* Loop filter on for mode 23 */
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0021,0xFE);     /* ACIV off, need to set FSCI */
+           }
+         }
        } else {
-         temp=crt2crtc&0x3F;
-         if(temp==4) {
-           SiS_SetReg1(SiS_Part2Port,0x01,0x2B);
-           SiS_SetReg1(SiS_Part2Port,0x02,0x13);
-           SiS_SetReg1(SiS_Part2Port,0x04,0xE5);
-           SiS_SetReg1(SiS_Part2Port,0x05,0x08);
-           SiS_SetReg1(SiS_Part2Port,0x06,0xE2);
+         if(resindex == 0x04) {     			 /* ----- 640x480 underscan; Mode 17 */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); 	 /* loop filter off */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE);
+         } else {
+           if(resindex == 0x05) {   			 /* ----- 800x600 underscan: Mode 24 */
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0118,0xF0);     /* (FSCI was 0x1f1c71c7 - this is for mode 22) */
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0919,0xF0);	 /* FSCI for mode 24 is 428,554,851 */
+             SiS_SetCH70xxANDOR(SiS_Pr,0x081A,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0b1B,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x031C,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0a1D,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x061E,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x031F,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF);     /* loop filter off for mode 24 */
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0021,0xFE);	 /* ACIV off, need to set FSCI */
+           }
          }
        }
+     } else {				/* ---- PAL ---- */
+           /* TW: We don't play around with FSCI in PAL mode */
+         if (resindex == 0x04) {
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); 	/* loop filter off */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE);      /* ACIV on */
+         } else {
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); 	/* loop filter off */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE);      /* ACIV on */
+         }
      }
-   }
- }
 
- SiS_SetRegANDOR(SiS_Part2Port,0x09,0xF0,0x00);
- SiS_SetRegANDOR(SiS_Part2Port,0x0A,0xF0,0x00);
+  } else {
 
- tempcx=(SiS_HT-SiS_HDE)>>2;    		/* (HT-HDE)>>2     */
- tempbx=(SiS_HDE+7);            		/* lcdhdee         */
- /*301b*/
- if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-    tempbx=tempbx+2;
- }
- push1=tempbx;
- temp=tempbx&0x00FF;    			/* RHEQPLE=lcdhdee */
- SiS_SetReg1(SiS_Part2Port,0x23,temp);
- temp=(tempbx&0xFF00)>>8;
- SiS_SetRegANDOR(SiS_Part2Port,0x25,~0x0F,temp);
- /*301b*/
- temp=7;
- if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-    temp=temp+2;
- }
- SiS_SetReg1(SiS_Part2Port,0x1F,temp);  	/* RHBLKE=lcdhdes */
- SiS_SetRegANDOR(SiS_Part2Port,0x20,0x0F,0x00);
+     /* Chrontel 7019 */
 
- tempbx=tempbx+tempcx;
- push2=tempbx;
- temp=tempbx&0xFF;            			/* RHBURSTS=lcdhrs */
- if(SiS_LCDResInfo==Panel1280x1024) {
-   if(!(SiS_LCDInfo&LCDNonExpanding)) {
-     if(SiS_HDE==1280) {
-       temp=0x47;
-     }
-   }
- }
- SiS_SetReg1(SiS_Part2Port,0x1C,temp);
- temp=(tempbx&0xFF00)>>8;
- temp=temp<<4;
- SiS_SetRegANDOR(SiS_Part2Port,0x1D,~0x0F0,temp);
-
- tempbx=push2;
- tempcx=tempcx<<1;
- tempbx=tempbx+tempcx;
- temp=tempbx&0x00FF;            		/* RHSYEXP2S=lcdhre */
- SiS_SetReg1(SiS_Part2Port,0x21,temp);
-
- SiS_SetRegANDOR(SiS_Part2Port,0x17,0xFB,0x00);
- SiS_SetRegANDOR(SiS_Part2Port,0x18,0xDF,0x00);
-
- if(!(SiS_SetFlag&LCDVESATiming)) {
-   if(SiS_VGAVDE==525) {
-     if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))   /*301b*/
-    	temp=0xC6;
-     else
-       	temp=0xC4;
-     SiS_SetReg1(SiS_Part2Port,0x2f,temp);
-     SiS_SetReg1(SiS_Part2Port,0x30,0xB3);
-   }
-   if(SiS_VGAVDE==420) {
-     if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-    	temp=0x4F;
-     else
-       	temp=0x4E;
-     SiS_SetReg1(SiS_Part2Port,0x2f,temp);
-   }
- }
-}
+     /* TW: We don't support modes >1024x768 */
+     if (resindex > 6) return;
 
-USHORT
-SiS_GetVGAHT2()
-{
-  ULONG tempax,tempbx;
+     temp = CHTVRegData[resindex].Reg[0];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x00;
+     SiS_SetCH701x(SiS_Pr,tempbx);
 
-  tempbx=((SiS_VGAVT-SiS_VGAVDE)*SiS_RVBHCMAX)&0xFFFF;
-  tempax=(SiS_VT-SiS_VDE)*SiS_RVBHCFACT;
-  tempax=(tempax*SiS_HT)/tempbx;
-  return((USHORT) tempax);
+     temp = CHTVRegData[resindex].Reg[1];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x01;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[2];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x02;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[3];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x04;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[4];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x03;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[5];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x05;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[6];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x06;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[7];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x07;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[8];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x08;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[9];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x15;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[10];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x1f;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[11];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x0c;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[12];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x0d;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[13];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x0e;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[14];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x0f;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[15];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x10;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+  }
 }
 
 void
-SiS_SetGroup3(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,
-              USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_SetCH701xForLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
 {
-  USHORT i;
-  UCHAR *tempdi;
-  USHORT  modeflag,temp,temp1;
-
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-  }
+  UCHAR regtable[]  = { 0x1c, 0x5f, 0x64, 0x6f, 0x70, 0x71,
+                        0x72, 0x73, 0x74, 0x76, 0x78, 0x7d };
+  UCHAR table28b4[] = { 0x60, 0x02, 0x00, 0x07, 0x40, 0xed,
+                        0xa3, 0xc8, 0xc7, 0xac, 0x60, 0x02 };
+  UCHAR table28c0[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xef,
+                        0xad, 0xdb, 0xf6, 0xac, 0x60, 0x02 };
+  UCHAR *tableptr = NULL;
+  USHORT tempbh;
+  int i;
 
-  SiS_SetReg1(SiS_Part3Port,0x00,0x00);
-  if(SiS_VBInfo&SetPALTV) {
-    SiS_SetReg1(SiS_Part3Port,0x13,0xFA);
-    SiS_SetReg1(SiS_Part3Port,0x14,0xC8);
+  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+      tableptr = table28c0;
   } else {
-    SiS_SetReg1(SiS_Part3Port,0x13,0xF6);
-    SiS_SetReg1(SiS_Part3Port,0x14,0xBF);
+      tableptr = table28b4;
   }
-#ifdef SIS300
-  /*add PALMN*/
-  if((HwDeviceExtension->jChipType==SIS_630)||
-     (HwDeviceExtension->jChipType==SIS_730)) {
-           if(SiS_VBInfo&SetCRT2ToTV) {
-              temp=SiS_GetReg1(SiS_P3d4,0x31);
-              temp=temp&0x01;
-              if(temp) {
-                  temp1=SiS_GetReg1(SiS_P3d4,0x35);
-                  temp1=temp1&0x40;
-                   if(temp1){
-                          SiS_SetReg1(SiS_Part3Port,0x13,0xFA);
-                          SiS_SetReg1(SiS_Part3Port,0x14,0xC8);
-                          SiS_SetReg1(SiS_Part3Port,0x3D,0xA8);
-                }
-             }
-          } 
-      }	
-    /*end add*/
-#endif
-#ifdef SIS315H
-/*add PALMN*/
-  if ( (HwDeviceExtension->jChipType==SIS_315H)||
-       (HwDeviceExtension->jChipType==SIS_315PRO)||
-       (HwDeviceExtension->jChipType==SIS_550) ||
-       (HwDeviceExtension->jChipType==SIS_640) ||
-       (HwDeviceExtension->jChipType==SIS_740) ||
-       (HwDeviceExtension->jChipType==SIS_650)) {
-         if(SiS_VBInfo&SetCRT2ToTV) {
-             temp=SiS_GetReg1(SiS_P3d4,0x31);   
-             temp=temp&0x01; 
-              if(temp) {
-                  temp1=SiS_GetReg1(SiS_P3d4,0x38);        
-                  temp1=temp1&0x40; 
-                   if(temp1){
-                          SiS_SetReg1(SiS_Part3Port,0x13,0xFA); 
-                          SiS_SetReg1(SiS_Part3Port,0x14,0xC8); 
-                          SiS_SetReg1(SiS_Part3Port,0x3D,0xA8);
-                   }
-              }
-         }
+  tempbh = SiS_GetCH701x(SiS_Pr,0x74);
+  if((tempbh == 0xf6) || (tempbh == 0xc7)) {
+     tempbh = SiS_GetCH701x(SiS_Pr,0x73);
+     if(tempbh == 0xc8) {
+        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1400x1050) return;
+     } else if(tempbh == 0xdb) {
+        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) return;
+     }
   }
- /*end add*/
-#endif
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-    tempdi=SiS_HiTVGroup3Data;
-    if(SiS_SetFlag&TVSimuMode) {
-      tempdi=SiS_HiTVGroup3Simu;
-      if(!(modeflag&Charx8Dot)) {
-        tempdi=SiS_HiTVGroup3Text;
-      }
-    }
-    for(i=0;i<=0x3E;i++){
-       SiS_SetReg1(SiS_Part3Port,i,tempdi[i]);
-    }
+  for(i=0; i<0x0c; i++) {
+     SiS_SetCH701x(SiS_Pr,(tableptr[i] << 8) | regtable[i]);
   }
-  return;
+  SiS_Chrontel19f2(SiS_Pr);
+  tempbh = SiS_GetCH701x(SiS_Pr,0x1e);
+  tempbh |= 0xc0;
+  SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x1e);	
 }
 
+/* TW: Chrontel 701x functions ================================= */
+
 void
-SiS_SetGroup4(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,
-              USHORT ModeIdIndex,USHORT RefreshRateTableIndex,
-	      PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_Chrontel19f2(SiS_Private *SiS_Pr)
 {
-  USHORT tempax,tempcx,tempbx,modeflag,temp,temp2,push1;
-  ULONG tempebx,tempeax,templong;
+  UCHAR regtable[]  = { 0x67, 0x68, 0x69, 0x6a, 0x6b };
+  UCHAR table19e8[] = { 0x01, 0x02, 0x01, 0x01, 0x02 };
+  UCHAR table19ed[] = { 0x01, 0x02, 0x01, 0x01, 0x02 };
+  UCHAR *tableptr = NULL;
+  int i;
 
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
+  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+      tableptr = table19ed;
   } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
+      tableptr = table19e8;
   }
-  temp=SiS_RVBHCFACT;
-  SiS_SetReg1(SiS_Part4Port,0x13,temp);
 
-  tempbx=SiS_RVBHCMAX;
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part4Port,0x14,temp);
-  temp2=((tempbx&0xFF00)>>8)<<7;
-  
-  tempcx=SiS_VGAHT-1;
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part4Port,0x16,temp);
-  temp=((tempcx&0xFF00)>>8)<<3;
-  temp2=temp|temp2;
-
-  tempcx=SiS_VGAVT-1;
-  if(!(SiS_VBInfo&SetCRT2ToTV)){
-    tempcx=tempcx-5;
-  }
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part4Port,0x17,temp);
-  temp=temp2|((tempcx&0xFF00)>>8);
-  SiS_SetReg1(SiS_Part4Port,0x15,temp);
-
-  tempcx=SiS_VBInfo;
-  tempbx=SiS_VGAHDE;
-  if(modeflag&HalfDCLK){
-    tempbx=tempbx>>1;
-  }
-  if(tempcx&SetCRT2ToHiVisionTV) {
-       temp=0xA0;
-       if(tempbx!=1024) {
-           temp=0xC0;
-           if(tempbx!=1280) temp=0;
-       }
-  } else if((tempcx&SetCRT2ToTV)&&(SiS_VGAHDE==1024)) {       /*301b*/
-       temp=0xA0;
-  } else {
-       temp=0x80;
-       if(SiS_VBInfo&SetCRT2ToLCD){
-          temp=0;
-          if(tempbx>800) temp=0x60;
-       }
+  for(i=0; i<5; i++) {
+     SiS_SetCH701x(SiS_Pr,(tableptr[i] << 8) | regtable[i]);
   }
-  if(SiS_LCDResInfo!=Panel1280x1024) temp=temp|0x0A;
-  SiS_SetRegANDOR(SiS_Part4Port,0x0E,~0xEF,temp);
-
-  tempebx=SiS_VDE;
-  if(tempcx&SetCRT2ToHiVisionTV) {
-    /* if(!(tempax&0xE000)) tempbx=tempbx>>1; */
-    if(!(temp&0xE000)) tempbx=tempbx>>1;               /* alan ???? */
+}
 
-  }
+void
+SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr)
+{
+  USHORT temp;
 
-  tempcx=SiS_RVBHRS;
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part4Port,0x18,temp);
-
-  tempebx=tempebx;
-  tempeax=SiS_VGAVDE;
-  tempcx=tempcx|0x04000;
-/*tempeax=tempeax-tempebx;  */
-  if(tempeax<=tempebx){
-    tempcx=((tempcx&0xFF00)^0x4000)|(tempcx&0x00ff);
-    tempeax=SiS_VGAVDE;
+  /* TW: Enable Chrontel 7019 LCD panel backlight */
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+        temp = SiS_GetCH701x(SiS_Pr,0x66);
+        temp |= 0x20;
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
   }
+}
 
-  else {
-    tempeax=tempeax-tempebx;
-  }
+void
+SiS_Chrontel701xOn(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
+{
+  USHORT temp;
 
-  push1=tempcx;
-  templong=(tempeax*256*1024)%tempebx;
-  tempeax=(tempeax*256*1024)/tempebx;
-  tempebx=tempeax;
-  if(templong!=0){
-    tempebx++;
-  }
-  tempcx=push1;
-  temp=(USHORT)(tempebx&0x000000FF);
-  SiS_SetReg1(SiS_Part4Port,0x1B,temp);
-  temp=(USHORT)((tempebx&0x0000FF00)>>8);
-  SiS_SetReg1(SiS_Part4Port,0x1A,temp);
-  tempbx=(USHORT) (tempebx>>16);
-  temp=tempbx&0x00FF;
-  temp=temp<<4;
-  temp=temp|((tempcx&0xFF00)>>8);
-  SiS_SetReg1(SiS_Part4Port,0x19,temp);
-
-  /*301b*/
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-         temp=0x0028;
-         SiS_SetReg1(SiS_Part4Port,0x1C,temp);
-         tempax=SiS_VGAHDE;
-          if(modeflag&HalfDCLK){
-           tempax=tempax>>1;
-           }
-          if(SiS_VBInfo&(SetCRT2ToLCD)) {
-             if(tempax>800)
-                tempax=tempax-800;
-          }
-          tempax=tempax-1;                
-                 
-         if(SiS_VBInfo&(SetCRT2ToTV|SetCRT2ToHiVisionTV)) {
-          if(SiS_VGAHDE>800)
-            {
-              if(SiS_VGAHDE==1024)
-                tempax=(tempax*25/32)-1;
-              else
-                  tempax=(tempax*20/32)-1;          
-            }
-         }
-         temp=(tempax&0xFF00)>>8;
-         temp=((temp&0x0003)<<4);
-         SiS_SetReg1(SiS_Part4Port,0x1E,temp);
-         temp=(tempax&0x00FF);
-         SiS_SetReg1(SiS_Part4Port,0x1D,temp);
-   
-         if(SiS_VBInfo&(SetCRT2ToTV|SetCRT2ToHiVisionTV)) {
-            if(SiS_VGAHDE>800){
-               SiS_SetRegOR(SiS_Part4Port,0x1E,0x08);
-            }
-         }
-         temp=0x0036;
-         if(SiS_VBInfo&SetCRT2ToTV) {
-             temp=temp|0x0001;
-         }
-         SiS_SetRegANDOR(SiS_Part4Port,0x1F,0x00C0,temp);
-         tempbx=(SiS_HT/2)-2;
-         temp=((tempbx&0x0700)>>8)<<3;
-         SiS_SetRegANDOR(SiS_Part4Port,0x21,0x00C0,temp);
-         temp=tempbx&0x00FF;
-         SiS_SetReg1(SiS_Part4Port,0x22,temp);
-         if( (SiS_VBType&(VB_SIS301LV|VB_SIS302LV)) && (SiS_VBInfo&SetCRT2ToLCD) ) {
-             SiS_SetReg1(SiS_Part4Port,0x24,0x0e);
-	 }
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+     if(SiS_IsYPbPr(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+        temp = SiS_GetCH701x(SiS_Pr,0x01);
+	temp &= 0x3f;
+	temp |= 0x80;
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x01);
+     }
+     SiS_SetCH701x(SiS_Pr,0x2049);   			/* TW: Enable TV path */
+     temp = SiS_GetCH701x(SiS_Pr,0x49);
+     if(SiS_IsYPbPr(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+        temp = SiS_GetCH701x(SiS_Pr,0x73);
+	temp |= 0x60;
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x73);
+     }
+     temp = SiS_GetCH701x(SiS_Pr,0x47);
+     temp &= 0x7f;
+     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
+     SiS_LongDelay(SiS_Pr,2);
+     temp = SiS_GetCH701x(SiS_Pr,0x47);
+     temp |= 0x80;
+     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
   }
-  /*end 301b*/
-
-  SiS_SetCRT2VCLK(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwDeviceExtension);
 }
 
 void
-SiS_SetCRT2VCLK(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                 USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr)
 {
-  USHORT vclkindex;
-  USHORT tempah,temp1;
+  USHORT temp;
 
-  vclkindex = SiS_GetVCLK2Ptr(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwDeviceExtension);
-  /*301b*/
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-   	tempah = SiS_VBVCLKData[vclkindex].Part4_A;
-   	SiS_SetReg1(SiS_Part4Port,0x0A,tempah);
-   	tempah = SiS_VBVCLKData[vclkindex].Part4_B;
-   	SiS_SetReg1(SiS_Part4Port,0x0B,tempah);
-  } else {
-   	SiS_SetReg1(SiS_Part4Port,0x0A,0x01);
-   	tempah = SiS_VBVCLKData[vclkindex].Part4_B;
-   	SiS_SetReg1(SiS_Part4Port,0x0B,tempah);
-   	tempah = SiS_VBVCLKData[vclkindex].Part4_A;
-   	SiS_SetReg1(SiS_Part4Port,0x0A,tempah);
-  }
-  SiS_SetReg1(SiS_Part4Port,0x12,0x00);
-  tempah=0x08;
-  if(SiS_VBInfo&SetCRT2ToRAMDAC){
-    	tempah=tempah|0x020;
-  }
-  temp1=SiS_GetReg1(SiS_Part4Port,0x12);
-  tempah=tempah|temp1;
-  SiS_SetReg1(SiS_Part4Port,0x12,tempah);
+  /* TW: Disable Chrontel 7019 LCD panel backlight */
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+        temp = SiS_GetCH701x(SiS_Pr,0x66);
+        temp &= 0xDF;
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
+  }
 }
 
-USHORT
-SiS_GetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-        USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+void
+SiS_Chrontel701xOff(SiS_Private *SiS_Pr)
 {
-  USHORT tempbx;
-#ifdef SIS300
-  USHORT LCDXlat1VCLK300[4] = {VCLK65,VCLK65,VCLK65,VCLK65};
-  USHORT LCDXlat2VCLK300[4] = {VCLK108_2,VCLK108_2,VCLK108_2,VCLK108_2};
-  USHORT LVDSXlat2VCLK300[4]= {VCLK65,VCLK65,VCLK65,VCLK65};
-  USHORT LVDSXlat3VCLK300[4]= {VCLK65,VCLK65,VCLK65,VCLK65};
-#endif
-#ifdef SIS315H
-  USHORT LCDXlat1VCLK310[4] = {VCLK65+2,VCLK65+2,VCLK65+2,VCLK65+2};
-  USHORT LCDXlat2VCLK310[4] = {VCLK108_2+5,VCLK108_2+5,VCLK108_2+5,VCLK108_2+5};
-  USHORT LVDSXlat2VCLK310[4]= {VCLK65+2,VCLK65+2,VCLK65+2,VCLK65+2};
-  USHORT LVDSXlat3VCLK310[4]= {VCLK65+2,VCLK65+2,VCLK65+2,VCLK65+2};
-#endif
-  USHORT LVDSXlat1VCLK[4]   = {VCLK40,VCLK40,VCLK40,VCLK40};
-  USHORT CRT2Index,VCLKIndex;
-  USHORT modeflag,resinfo;
-  UCHAR *CHTVVCLKPtr=NULL;
-  USHORT *LCDXlatVCLK1=NULL;
-  USHORT *LCDXlatVCLK2=NULL;
-  USHORT *LVDSXlatVCLK2=NULL;
-  USHORT *LVDSXlatVCLK3=NULL;
+  USHORT temp;
 
-#ifdef SIS315H
-  if ( (HwDeviceExtension->jChipType==SIS_315H)||   
-       (HwDeviceExtension->jChipType==SIS_315PRO)||
-       (HwDeviceExtension->jChipType==SIS_550) ||
-       (HwDeviceExtension->jChipType==SIS_640) ||
-       (HwDeviceExtension->jChipType==SIS_740) ||
-       (HwDeviceExtension->jChipType==SIS_650)) {
-		LCDXlatVCLK1 = LCDXlat1VCLK310;
-		LCDXlatVCLK2 = LCDXlat2VCLK310;
-		LVDSXlatVCLK2 = LVDSXlat2VCLK310;
-		LVDSXlatVCLK3 = LVDSXlat3VCLK310;
-  } else {
-#endif
-#ifdef SIS300
-		LCDXlatVCLK1 = LCDXlat1VCLK300;
-		LCDXlatVCLK2 = LCDXlat2VCLK300;
-		LVDSXlatVCLK2 = LVDSXlat2VCLK300;
-		LVDSXlatVCLK3 = LVDSXlat3VCLK300;
-#endif
-#ifdef SIS315H
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+        SiS_LongDelay(SiS_Pr,2);
+	/* TW: Complete power down of LVDS */
+	temp = SiS_GetCH701x(SiS_Pr,0x76);
+	temp &= 0xfc;
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76);
+	SiS_SetCH701x(SiS_Pr,0x0066);
   }
-#endif
-
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-    	resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
-    	CRT2Index = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-    	resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-    	CRT2Index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-  }
-
-  if(SiS_IF_DEF_LVDS==0) {
-     CRT2Index = CRT2Index>>6;        /*  for LCD */
-     if((SiS_VBInfo&SetCRT2ToLCD)||(SiS_VBInfo&SetCRT2ToLCDA)){   /*301b*/
-      	if(SiS_LCDResInfo!=Panel1024x768){
-        	VCLKIndex = LCDXlatVCLK2[CRT2Index];
-      	} else {
-        	VCLKIndex = LCDXlatVCLK1[CRT2Index];
-      	}
-     } else {        /* for TV */
-      	if(SiS_VBInfo&SetCRT2ToTV) {
-        	if(SiS_IF_DEF_HiVision==1) {
-          		if(SiS_SetFlag&RPLLDIV2XO) {
-            			VCLKIndex=HiTVVCLKDIV2;
-            			if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-					/* VCLKIndex += 11;    for chip310  0x2E */
-              				VCLKIndex += 25;    /* for chip315  */
-            			}
-     			} else {
-            			VCLKIndex=HiTVVCLK;
-            			if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-					/*  VCLKIndex += 11;    for chip310  0x2E */
-              				VCLKIndex += 25;    /* for chip315  */
-            			}
-          		}
-          		if(SiS_SetFlag&TVSimuMode) {
-            			if(modeflag&Charx8Dot) {
-              				VCLKIndex=HiTVSimuVCLK;
-              					if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-							/*  VCLKIndex += 11;    for chip310  0x2E */
-              						VCLKIndex += 25;    /* for chip315  */
-              					}
-            			} else {
-              				VCLKIndex=HiTVTextVCLK;
-              				if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-						/*  VCLKIndex += 11;    for chip310  0x2E */
-              					VCLKIndex += 25;    /* for chip315  */
-              				}
-            			}
-          		}
-        	} else {
-          		if(SiS_VBInfo&SetCRT2ToTV) {
-            			if(SiS_SetFlag&RPLLDIV2XO) {
-              				VCLKIndex=TVVCLKDIV2;
-              					if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-							/* VCLKIndex += 11;    for chip310  0x2E */
-              						VCLKIndex += 25;    /* for chip315  */
-              					}
-            			} else {
-              				VCLKIndex=TVVCLK;
-              				if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-						/* VCLKIndex += 11;    for chip310  0x2E */
-              					VCLKIndex += 25;    /* for chip315  */
-              				}
-            			}
-          		}
-        	}
-      } else {    /* for CRT2 */
-        	VCLKIndex = (UCHAR)SiS_GetReg2((USHORT)(SiS_P3ca+0x02));      /*  Port 3cch */
-        	VCLKIndex =((VCLKIndex>>2)&0x03);
-        	if(ModeNo>0x13) {
-          		VCLKIndex =
-			    SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;    /* di+Ext_CRTVCLK */
-          		VCLKIndex = VCLKIndex&0x3f;
-        	}
-      }
-    }
-  } else {       /*   LVDS  */
-    	if(ModeNo<=0x13) VCLKIndex = CRT2Index;
-    	else VCLKIndex = CRT2Index;
-#ifdef LINUX_XF86
-	xf86DrvMsg(0, X_INFO, "CRT2Index = %d\n", CRT2Index);
-#endif
-	/* TW: This does not make sense: If CH7005 is there but CRT2 is set to
-	 *     LCD, VCLKindex is returned untouched...
-	 *     (Inserted SlaveMode check for 8bpp modes later)
-	 */
+}
 
-#if 1
-    	if((SiS_IF_DEF_CH7005==1) && (!(SiS_VBInfo&SetInSlaveMode))) {
-      		if(!(SiS_VBInfo&SetCRT2ToLCD)) {
-#else
+void
+SiS_ChrontelResetDB(SiS_Private *SiS_Pr)
+{
+     /* TW: Reset Chrontel 7019 datapath */
+     SiS_SetCH701x(SiS_Pr,0x1048);
+     SiS_LongDelay(SiS_Pr,1);
+     SiS_SetCH701x(SiS_Pr,0x1848);
+}
 
-/* 	TW: If we do it this way instead, some machines (MITAC) have problems 		*/
-	if((SiS_IF_DEF_CH7005==1) && (SiS_VBInfo&SetCRT2ToTV)) {
-#endif
+void
+SiS_ChrontelDoSomething4(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+     USHORT temp;
 
-        		VCLKIndex = VCLKIndex&0x1f;
-        		tempbx=0;
-        		if(SiS_VBInfo&SetPALTV) tempbx=tempbx+2;
-        		if(SiS_VBInfo&SetCHTVOverScan) tempbx=tempbx+1;
-       			switch(tempbx) {
-          			case 0: CHTVVCLKPtr=SiS_CHTVVCLKUNTSC;
-					break;
-          			case 1: CHTVVCLKPtr=SiS_CHTVVCLKONTSC;
-					break;
-          			case 2: CHTVVCLKPtr=SiS_CHTVVCLKUPAL;
-					break;
-          			case 3: CHTVVCLKPtr=SiS_CHTVVCLKOPAL;
-					break;
-        		}
-        		VCLKIndex=CHTVVCLKPtr[VCLKIndex];
-      		}  
-    	} else {
-     		VCLKIndex = VCLKIndex>>6;
-     		if((SiS_LCDResInfo==Panel800x600)||(SiS_LCDResInfo==Panel320x480))
-     			VCLKIndex = LVDSXlat1VCLK[VCLKIndex]; /*fstn*/
-     		else if(SiS_LCDResInfo==Panel1024x768)
-     			VCLKIndex = LVDSXlatVCLK2[VCLKIndex];
-     		else 	VCLKIndex = LVDSXlatVCLK3[VCLKIndex];
-    	}
-  }
-  if(HwDeviceExtension->jChipType < SIS_315H) { /* for300 serial*/
-    	VCLKIndex=VCLKIndex&0x3F;
-  }
-  return (VCLKIndex);
+     SiS_SetCH701x(SiS_Pr,0xaf76);
+     temp = SiS_GetCH701x(SiS_Pr,0x49);
+     temp &= 1;
+     if(temp != 1) {
+	temp = SiS_GetCH701x(SiS_Pr,0x47);
+	temp &= 0x70;
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
+	SiS_LongDelay(SiS_Pr,3);
+	temp = SiS_GetCH701x(SiS_Pr,0x47);
+	temp |= 0x80;
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
+     }
 }
 
 void
-SiS_SetGroup5(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,
-              USHORT ModeIdIndex)
+SiS_ChrontelDoSomething3(SiS_Private *SiS_Pr, USHORT ModeNo,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                         USHORT BaseAddr)
 {
-  USHORT Pindex,Pdata;
+     USHORT temp,temp1;
 
-  Pindex=SiS_Part5Port;
-  Pdata=SiS_Part5Port+1;
-  if(SiS_ModeType==ModeVGA){
-    if(!(SiS_VBInfo&(SetInSlaveMode|LoadDACFlag|CRT2DisplayFlag))){
-      SiS_EnableCRT2();
-/*    LoadDAC2(ROMAddr,SiS_Part5Port,ModeNo,ModeIdIndex);  */
-    }
-  }
-  return;
+     temp1 = 0;
+     temp = SiS_GetCH701x(SiS_Pr,0x61);
+     if(temp < 2) {
+          temp++;
+	  SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x61);
+	  temp1 = 1;
+     }
+     SiS_SetCH701x(SiS_Pr,0xac76);
+     temp = SiS_GetCH701x(SiS_Pr,0x66);
+     temp |= 0x5f;
+     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
+     if(ModeNo > 0x13) {
+         if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	    SiS_GenericDelay(SiS_Pr,0x3ff);
+	 } else {
+	    SiS_GenericDelay(SiS_Pr,0x2ff);
+	 }
+     } else {
+         if(!temp1)
+	    SiS_GenericDelay(SiS_Pr,0x2ff);
+     }
+     temp = SiS_GetCH701x(SiS_Pr,0x76);
+     temp |= 0x03;
+     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76);
+     temp = SiS_GetCH701x(SiS_Pr,0x66);
+     temp &= 0x7f;
+     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
+     SiS_LongDelay(SiS_Pr,1);
 }
 
 void
-SiS_LoadDAC2(ULONG ROMAddr,USHORT SiS_Part5Port,
-             USHORT ModeNo,USHORT ModeIdIndex)
+SiS_ChrontelDoSomething2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
 {
-   USHORT data,data2;
-   USHORT time,i,j,k;
-   USHORT m,n,o;
-   USHORT si,di,bx,dl;
-   USHORT al,ah,dh;
-   USHORT *table=0;
-   USHORT Pindex,Pdata,modeflag;
+     USHORT temp,tempcl,tempch;
 
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-  }
+     SiS_LongDelay(SiS_Pr, 1);
+     tempcl = 3;
+     tempch = 0;
 
-   Pindex=SiS_Part5Port;
-   Pdata=SiS_Part5Port+1;
-   data=modeflag&DACInfoFlag;
-   time=64;
-   if(data==0x00) table=SiS_MDA_DAC;
-   if(data==0x08) table=SiS_CGA_DAC;
-   if(data==0x10) table=SiS_EGA_DAC;
-   if(data==0x18) {
-     time=256;
-     table=SiS_VGA_DAC;
-   }
-   if(time==256) j=16;
-   else j=time;
+     do {
+       temp = SiS_GetCH701x(SiS_Pr,0x66);
+       temp &= 0x04;
+       if(temp == 0x04) break;
 
-   SiS_SetReg3(Pindex,0x00);
+       SiS_SetCH701xForLCD(SiS_Pr,HwDeviceExtension, BaseAddr);
 
-   for(i=0;i<j;i++) {
-      data=table[i];
-      for(k=0;k<3;k++) {
-        data2=0;
-        if(data&0x01) data2=0x2A;
-        if(data&0x02) data2=data2+0x15;
-        SiS_SetReg3(Pdata,data2);
-        data=data>>2;
-      }
-   }
+       if(tempcl == 0) {
+           if(tempch == 3) break;
+	   SiS_ChrontelResetDB(SiS_Pr);
+	   tempcl = 3;
+	   tempch++;
+       }
+       tempcl--;
+       temp = SiS_GetCH701x(SiS_Pr,0x76);
+       temp &= 0xfb;
+       SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76);
+       SiS_LongDelay(SiS_Pr,2);
+       temp = SiS_GetCH701x(SiS_Pr,0x76);
+       temp |= 0x04;
+       SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76);
+       SiS_SetCH701x(SiS_Pr,0x6078);
+       SiS_LongDelay(SiS_Pr,2);
+    } while(0);
 
-   if(time==256) {
-      for(i=16;i<32;i++) {
-         data=table[i];
-         for(k=0;k<3;k++) SiS_SetReg3(Pdata,data);
-      }
-      si=32;
-      for(m=0;m<9;m++) {
-         di=si;
-         bx=si+0x04;
-         dl=0;
-         for(n=0;n<3;n++) {
-            for(o=0;o<5;o++) {
-              dh=table[si];
-              ah=table[di];
-              al=table[bx];
-              si++;
-              SiS_WriteDAC2(Pdata,dl,ah,al,dh);
-            }         /* for 5 */
-            si=si-2;
-            for(o=0;o<3;o++) {
-              dh=table[bx];
-              ah=table[di];
-              al=table[si];
-              si--;
-              SiS_WriteDAC2(Pdata,dl,ah,al,dh);
-            }         /* for 3 */
-            dl++;
-         }            /* for 3 */
-         si=si+5;
-      }               /* for 9 */
-   }
+    SiS_SetCH701x(SiS_Pr,0x0077);
 }
 
 void
-SiS_WriteDAC2(USHORT Pdata,USHORT dl, USHORT ah, USHORT al, USHORT dh)
+SiS_ChrontelDoSomething1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                         USHORT BaseAddr)
 {
-  USHORT temp;
-  USHORT bh,bl;
-
-  bh=ah;
-  bl=al;
-  if(dl!=0) {
-    temp=bh;
-    bh=dh;
-    dh=temp;
-    if(dl==1) {
-       temp=bl;
-       bl=dh;
-       dh=temp;
-    }
-    else {
-       temp=bl;
-       bl=bh;
-       bh=temp;
-    }
-  }
-  SiS_SetReg3(Pdata,(USHORT)dh);
-  SiS_SetReg3(Pdata,(USHORT)bh);
-  SiS_SetReg3(Pdata,(USHORT)bl);
-}
+     USHORT temp;
 
-/* TW: Start of Chrontel 7005 functions ---------------------------- */
+     temp = SiS_GetCH701x(SiS_Pr,0x03);
+     temp |= 0x80;
+     temp &= 0xbf;
+     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x03);
 
-void
-SiS_SetCHTVReg(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-               USHORT RefreshRateTableIndex)
-{
-  USHORT temp,tempbx,tempcl;
-/*  USHORT CRT2CRTC; */
-  USHORT TVType,resindex;
-  SiS_CHTVRegDataStruct *CHTVRegData=NULL;
-
-  if(ModeNo<=0x13){
-    	tempcl = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  }else{
-    	tempcl = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-  }
-  TVType = 0;
-  if(SiS_VBInfo&SetPALTV) TVType=TVType+2;
-  if(SiS_VBInfo&SetCHTVOverScan) TVType=TVType+1;
-  switch(TVType) {
-    	case 0: CHTVRegData = SiS_CHTVReg_UNTSC; break;
-    	case 1: CHTVRegData = SiS_CHTVReg_ONTSC; break;
-    	case 2: CHTVRegData = SiS_CHTVReg_UPAL;  break;
-    	case 3: CHTVRegData = SiS_CHTVReg_OPAL;  break;
-  }
-  resindex=tempcl&0x3F;
-
-  /* TW: We don't support modes >800x600 */
-  if (resindex > 5) return;
-
-  if(SiS_VBInfo&SetPALTV) {
-    	SiS_SetCH7005(0x4304);  /* TW: 0x40=76uA (PAL); 0x03=15bit non-multi RGB*/
-    	SiS_SetCH7005(0x6909);	/* TW: Black level for PAL (105)*/
-  } else {
-    	SiS_SetCH7005(0x0304);  /* TW: upper nibble=71uA (NTSC), 0x03=15bit non-multi RGB*/
-    	SiS_SetCH7005(0x7109);	/* TW: Black level for NTSC (113)*/
-  }
-
-  temp = CHTVRegData[resindex].Reg[0];
-  tempbx=((temp&0x00FF)<<8)|0x00;	/* TW: Mode register */
-  SiS_SetCH7005(tempbx);
-  temp = CHTVRegData[resindex].Reg[1];
-  tempbx=((temp&0x00FF)<<8)|0x07;	/* TW: Start active video register */
-  SiS_SetCH7005(tempbx);
-  temp = CHTVRegData[resindex].Reg[2];
-  tempbx=((temp&0x00FF)<<8)|0x08;	/* TW: Position overflow register */
-  SiS_SetCH7005(tempbx);
-  temp = CHTVRegData[resindex].Reg[3];
-  tempbx=((temp&0x00FF)<<8)|0x0A;	/* TW: Horiz Position register */
-  SiS_SetCH7005(tempbx);
-  temp = CHTVRegData[resindex].Reg[4];
-  tempbx=((temp&0x00FF)<<8)|0x0B;	/* TW: Vertical Position register */
-  SiS_SetCH7005(tempbx);
-
-  /* TW: Set minimum flicker filter for Luma channel (SR1-0=00),
-             minimum text enhancement (S3-2=10),
-	     maximum flicker filter for Chroma channel (S5-4=10)
-	     =00101000=0x28 (When reading, S1-0->S3-2, and S3-2->S1-0!)
-   */
-  SiS_SetCH7005(0x2801);
+     SiS_ChrontelResetDB(SiS_Pr);
 
-  /* TW: Set video bandwidth
-         High bandwith Luma composite video filter(S0=1)
-         low bandwith Luma S-video filter (S2-1=00)
-	 disable peak filter in S-video channel (S3=0)
-	 high bandwidth Chroma Filter (S5-4=11)
-	 =00110001=0x31
-  */
-  SiS_SetCH7005(0xb103);       /* old: 3103 */
+     SiS_ChrontelDoSomething2(SiS_Pr,HwDeviceExtension, BaseAddr);
 
-  /* TW: Register 0x3D does not exist in non-macrovision register map
-         (Maybe this is a macrovision register?)
-   */
-  /* SiS_SetCH7005(0x003D); */
+     temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x34);
+     SiS_ChrontelDoSomething3(SiS_Pr,temp, HwDeviceExtension, BaseAddr);
 
-  /* TW: Register 0x10 only contains 1 writable bit (S0) for sensing,
-         all other bits a read-only. Macrovision?
-   */
-  SiS_SetCHTVRegANDOR(0x0010,0x1F);
+     SiS_SetCH701x(SiS_Pr,0xaf76);
+}
 
-  /* TW: Register 0x11 only contains 3 writable bits (S0-S2) for
-         contrast enhancement (set to 010 -> gain 2 Yout = 9/8*(Yin-57) )
-   */
-  SiS_SetCHTVRegANDOR(0x0211,0xF8);
+/* TW: End of Chrontel 701x functions ==================================== */
 
-  /* TW: Clear DSEN
-   */
-  SiS_SetCHTVRegANDOR(0x001C,0xEF);
+/* TW: Generic Read/write routines for Chrontel ========================== */
 
-  if(!(SiS_VBInfo&SetPALTV)) {		/* ---- NTSC ---- */
-    tempcl=tempcl&0x3F;
-    if(SiS_VBInfo&SetCHTVOverScan) {
-      if(tempcl==0x04) {   			/* 640x480 overscan: Mode 16 */
-      	SiS_SetCHTVRegANDOR(0x0020,0xEF);   	/* loop filter off */
-        SiS_SetCHTVRegANDOR(0x0121,0xFE);       /* ACIV on, no need to set FSCI */
-      } else {
-        if(tempcl==0x05) {    			/* 800x600 overscan: Mode 23 */
-          SiS_SetCHTVRegANDOR(0x0118,0xF0);	/* 0x18-0x1f: FSCI 469,762,048 */
-          SiS_SetCHTVRegANDOR(0x0C19,0xF0);
-          SiS_SetCHTVRegANDOR(0x001A,0xF0);
-          SiS_SetCHTVRegANDOR(0x001B,0xF0);
-          SiS_SetCHTVRegANDOR(0x001C,0xF0);
-          SiS_SetCHTVRegANDOR(0x001D,0xF0);
-          SiS_SetCHTVRegANDOR(0x001E,0xF0);
-          SiS_SetCHTVRegANDOR(0x001F,0xF0);
-          SiS_SetCHTVRegANDOR(0x1020,0xEF);     /* Loop filter on for mode 23 */
-          SiS_SetCHTVRegANDOR(0x0021,0xFE);     /* ACIV off, need to set FSCI */
-        }
-      }
-    } else {
-      if(tempcl==0x04) {     			/* ----- 640x480 underscan; Mode 17 */
-        SiS_SetCHTVRegANDOR(0x0020,0xEF); 	/* loop filter off */
-        SiS_SetCHTVRegANDOR(0x0121,0xFE);
-      } else {
-        if(tempcl==0x05) {   			/* ----- 800x600 underscan: Mode 24 */
-          SiS_SetCHTVRegANDOR(0x0118,0xF0);     /* (FSCI was 0x1f1c71c7 - this is for mode 22) */
-          SiS_SetCHTVRegANDOR(0x0919,0xF0);	/* FSCI for mode 24 is 428,554,851 */
-          SiS_SetCHTVRegANDOR(0x081A,0xF0);
-          SiS_SetCHTVRegANDOR(0x0b1B,0xF0);
-          SiS_SetCHTVRegANDOR(0x031C,0xF0);
-          SiS_SetCHTVRegANDOR(0x0a1D,0xF0);
-          SiS_SetCHTVRegANDOR(0x061E,0xF0);
-          SiS_SetCHTVRegANDOR(0x031F,0xF0);
-          SiS_SetCHTVRegANDOR(0x0020,0xEF);     /* loop filter off for mode 24 */
-          SiS_SetCHTVRegANDOR(0x0021,0xFE);	/* ACIV off, need to set FSCI */
-        }
-      }
-    }
-  } else {				/* ---- PAL ---- */
-        /* TW: We don't play around with FSCI in PAL mode */
-      if (tempcl==0x04) {
-        SiS_SetCHTVRegANDOR(0x0020,0xEF); 	/* loop filter off */
-        SiS_SetCHTVRegANDOR(0x0121,0xFE);       /* ACIV on */
-      } else {
-        SiS_SetCHTVRegANDOR(0x0020,0xEF); 	/* loop filter off */
-        SiS_SetCHTVRegANDOR(0x0121,0xFE);       /* ACIV on */
-      }
-  }
+/* TW: The Chrontel is connected to the 630/730 via
+ * the 630/730's DDC/I2C port.
+ *
+ * On 630(S)T chipset, the index changed from 0x11 to 0x0a,
+ * possibly for working around the DDC problems
+ */
+
+void
+SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx)
+{
+   if (SiS_Pr->SiS_IF_DEF_CH70xx == 1)
+      SiS_SetCH700x(SiS_Pr,tempbx);
+   else
+      SiS_SetCH701x(SiS_Pr,tempbx);
 }
 
+/* TW: Write to Chrontel 700x */
+/* Parameter is [Data (S15-S8) | Register no (S7-S0)] */
 void
-SiS_SetCHTVRegANDOR(USHORT tempax,USHORT tempbh)
+SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempbx)
 {
-  USHORT tempal,tempah,tempbl;
+  USHORT tempah,temp,i;
+
+  if(!(SiS_Pr->SiS_ChrontelInit)) {
+     SiS_Pr->SiS_DDC_Index = 0x11;		   /* TW: Bit 0 = SC;  Bit 1 = SD */
+     SiS_Pr->SiS_DDC_Data  = 0x02;                 /* Bitmask in IndexReg for Data */
+     SiS_Pr->SiS_DDC_Clk   = 0x01;                 /* Bitmask in IndexReg for Clk */
+     SiS_Pr->SiS_DDC_DataShift = 0x00;
+     SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;  	   /* TW: DAB (Device Address Byte) */
+  }
+
+  for(i=0;i<10;i++) {	/* TW: Do only 10 attempts to write */
+    /* SiS_SetSwitchDDC2(SiS_Pr); */
+    if(SiS_SetStart(SiS_Pr)) continue;		/* TW: Set start condition */
+    tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write DAB (S0=0=write) */
+    if(temp) continue;				/* TW:    (ERROR: no ack) */
+    tempah = tempbx & 0x00FF;			/* TW: Write RAB */
+    tempah |= 0x80;                             /* TW: (set bit 7, see datasheet) */
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+    if(temp) continue;				/* TW:    (ERROR: no ack) */
+    tempah = (tempbx & 0xFF00) >> 8;
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write data */
+    if(temp) continue;				/* TW:    (ERROR: no ack) */
+    if(SiS_SetStop(SiS_Pr)) continue;		/* TW: Set stop condition */
+    SiS_Pr->SiS_ChrontelInit = 1;
+    return;
+  }
 
-  tempal=tempax&0x00FF;
-  tempah=(tempax>>8)&0x00FF;
-  tempbl=SiS_GetCH7005(tempal);
-  tempbl=(((tempbl&tempbh)|tempah)<<8|tempal);  
-  SiS_SetCH7005(tempbl);
+  /* TW: For 630ST */
+  if(!(SiS_Pr->SiS_ChrontelInit)) {
+     SiS_Pr->SiS_DDC_Index = 0x0a;		/* TW: Bit 7 = SC;  Bit 6 = SD */
+     SiS_Pr->SiS_DDC_Data  = 0x80;              /* Bitmask in IndexReg for Data */
+     SiS_Pr->SiS_DDC_Clk   = 0x40;              /* Bitmask in IndexReg for Clk */
+     SiS_Pr->SiS_DDC_DataShift = 0x00;
+     SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;  	/* TW: DAB (Device Address Byte) */
+
+     for(i=0;i<10;i++) {	/* TW: Do only 10 attempts to write */
+       /* SiS_SetSwitchDDC2(SiS_Pr); */
+       if (SiS_SetStart(SiS_Pr)) continue;	/* TW: Set start condition */
+       tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write DAB (S0=0=write) */
+       if(temp) continue;			/* TW:    (ERROR: no ack) */
+       tempah = tempbx & 0x00FF;		/* TW: Write RAB */
+       tempah |= 0x80;                          /* TW: (set bit 7, see datasheet) */
+       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+       if(temp) continue;			/* TW:    (ERROR: no ack) */
+       tempah = (tempbx & 0xFF00) >> 8;
+       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write data */
+       if(temp) continue;			/* TW:    (ERROR: no ack) */
+       if(SiS_SetStop(SiS_Pr)) continue;	/* TW: Set stop condition */
+       SiS_Pr->SiS_ChrontelInit = 1;
+       return;
+    }
+  }
 }
 
-/* TW: Write to Chrontel 7005 */
+/* TW: Write to Chrontel 701x */
 /* Parameter is [Data (S15-S8) | Register no (S7-S0)] */
 void
-SiS_SetCH7005(USHORT tempbx)
+SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempbx)
 {
   USHORT tempah,temp,i;
 
-  /* TW: This has to be relative to BaseAddr */
-  /* SiS_DDC_Port=0x3c4; */
-  SiS_DDC_Index=0x11;			/* TW: Bit 0 = SC;  Bit 1 = SD */
-  SiS_DDC_DataShift=0x00;
-  SiS_DDC_DeviceAddr=0xEA;  		/* TW: DAB (Device Address Byte) */
-
-  for(i=0;i<50;i++) {	/* TW: Do only 50 attempts to write */
-    SiS_SetSwitchDDC2();
-    SiS_SetStart();			/* TW: Set start condition */
-    tempah=SiS_DDC_DeviceAddr;
-    temp=SiS_WriteDDC2Data(tempah);	/* TW: Write DAB (S0=0=write) */
-    if(temp) continue;			/* TW:    (ERROR: no ack) */
-    tempah=tempbx&0x00FF;
-    temp=SiS_WriteDDC2Data(tempah);	/* TW: Write RAB */
-    if(temp) continue;			/* TW:    (ERROR: no ack) */
-    tempah=(tempbx&0xFF00)>>8;
-    temp=SiS_WriteDDC2Data(tempah);	/* TW: Write data */
-    if(temp) continue;			/* TW:    (ERROR: no ack) */
-    SiS_SetStop();			/* TW: Set stop condition */
+  SiS_Pr->SiS_DDC_Index = 0x11;			/* TW: Bit 0 = SC;  Bit 1 = SD */
+  SiS_Pr->SiS_DDC_Data  = 0x08;                 /* Bitmask in IndexReg for Data */
+  SiS_Pr->SiS_DDC_Clk   = 0x04;                 /* Bitmask in IndexReg for Clk */
+  SiS_Pr->SiS_DDC_DataShift = 0x00;
+  SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;  		/* TW: DAB (Device Address Byte) */
+
+  for(i=0;i<10;i++) {	/* TW: Do only 10 attempts to write */
+    if (SiS_SetStart(SiS_Pr)) continue;		/* TW: Set start condition */
+    tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write DAB (S0=0=write) */
+    if(temp) continue;				/* TW:    (ERROR: no ack) */
+    tempah = tempbx & 0x00FF;
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write RAB */
+    if(temp) continue;				/* TW:    (ERROR: no ack) */
+    tempah = (tempbx & 0xFF00) >> 8;
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write data */
+    if(temp) continue;				/* TW:    (ERROR: no ack) */
+    if(SiS_SetStop(SiS_Pr)) continue;		/* TW: Set stop condition */
     return;
   }
 }
 
+/* TW: Read from Chrontel 70xx */
+/* Parameter is [Register no (S7-S0)] */
+USHORT
+SiS_GetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx)
+{
+   if (SiS_Pr->SiS_IF_DEF_CH70xx == 1)
+      return(SiS_GetCH700x(SiS_Pr,tempbx));
+   else
+      return(SiS_GetCH701x(SiS_Pr,tempbx));
+}
+
+/* TW: Read from Chrontel 700x */
+/* Parameter is [Register no (S7-S0)] */
 USHORT
-SiS_GetCH7005(USHORT tempbx)
+SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempbx)
 {
   USHORT tempah,temp,i;
 
-  /* TW: This has to be relative to BaseAddr, set by RegInit */
-  /* SiS_DDC_Port=0x3c4; */
-  SiS_DDC_Index=0x11;			/* TW: Bit 0 = SC;  Bit 1 = SD */
-  SiS_DDC_DataShift=0x00;
-  SiS_DDC_DeviceAddr=0xEA;		/* TW: DAB */
-  SiS_DDC_ReadAddr=tempbx;
-
-  for(i=0;i<50;i++) {	/* TW: Do only 50 attempts to write */
-    SiS_SetSwitchDDC2();
-    SiS_SetStart();			/* TW: Set start condition */
-    tempah=SiS_DDC_DeviceAddr;
-    temp=SiS_WriteDDC2Data(tempah);	/* TW: Write DAB (S0=0=write) */
-    if(temp) continue;			/* TW:        (ERROR: no ack) */
-    tempah=SiS_DDC_ReadAddr;		/* TW: Write RAB */
-    temp=SiS_WriteDDC2Data(tempah);
-    if(temp) continue;			/* TW:        (ERROR: no ack) */
-    SiS_SetStart();			/* TW: Re-start */
-    tempah=SiS_DDC_DeviceAddr;
-    tempah=tempah|0x01;
-    temp=SiS_WriteDDC2Data(tempah);	/* TW: DAB (S0=1=read) */
-    if(temp) continue;			/* TW:        (ERROR: no ack) */
-    tempah=SiS_ReadDDC2Data(tempah);	/* TW: Read byte */
-    SiS_SetStop();			/* TW: Stop condition */
+  if(!(SiS_Pr->SiS_ChrontelInit)) {
+     SiS_Pr->SiS_DDC_Index = 0x11;		/* TW: Bit 0 = SC;  Bit 1 = SD */
+     SiS_Pr->SiS_DDC_Data  = 0x02;              /* Bitmask in IndexReg for Data */
+     SiS_Pr->SiS_DDC_Clk   = 0x01;              /* Bitmask in IndexReg for Clk */
+     SiS_Pr->SiS_DDC_DataShift = 0x00;
+     SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;		/* TW: DAB */
+  }
+
+  SiS_Pr->SiS_DDC_ReadAddr = tempbx;
+
+  for(i=0;i<20;i++) {	/* TW: Do only 20 attempts to read */
+    /* SiS_SetSwitchDDC2(SiS_Pr); */
+    if(SiS_SetStart(SiS_Pr)) continue;		/* TW: Set start condition */
+    tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write DAB (S0=0=write) */
+    if(temp) continue;				/* TW:        (ERROR: no ack) */
+    tempah = SiS_Pr->SiS_DDC_ReadAddr | 0x80;	/* TW: Write RAB | 0x80 */
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+    if(temp) continue;				/* TW:        (ERROR: no ack) */
+    if (SiS_SetStart(SiS_Pr)) continue;		/* TW: Re-start */
+    tempah = SiS_Pr->SiS_DDC_DeviceAddr | 0x01; /* DAB | 0x01 = Read */
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: DAB (S0=1=read) */
+    if(temp) continue;				/* TW:        (ERROR: no ack) */
+    tempah = SiS_ReadDDC2Data(SiS_Pr,tempah);	/* TW: Read byte */
+    if (SiS_SetStop(SiS_Pr)) continue;		/* TW: Stop condition */
+    SiS_Pr->SiS_ChrontelInit = 1;
     return(tempah);
   }
-  return(tempah);
+
+  /* TW: For 630ST */
+  if(!SiS_Pr->SiS_ChrontelInit) {
+     SiS_Pr->SiS_DDC_Index = 0x0a;		/* TW: Bit 0 = SC;  Bit 1 = SD */
+     SiS_Pr->SiS_DDC_Data  = 0x80;              /* Bitmask in IndexReg for Data */
+     SiS_Pr->SiS_DDC_Clk   = 0x40;              /* Bitmask in IndexReg for Clk */
+     SiS_Pr->SiS_DDC_DataShift = 0x00;
+     SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;  	/* TW: DAB (Device Address Byte) */
+
+     for(i=0;i<20;i++) {	/* TW: Do only 20 attempts to read */
+       /* SiS_SetSwitchDDC2(SiS_Pr); */
+       if(SiS_SetStart(SiS_Pr)) continue;		/* TW: Set start condition */
+       tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);		/* TW: Write DAB (S0=0=write) */
+       if(temp) continue;				/* TW:        (ERROR: no ack) */
+       tempah = SiS_Pr->SiS_DDC_ReadAddr | 0x80;	/* TW: Write RAB | 0x80 */
+       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+       if(temp) continue;				/* TW:        (ERROR: no ack) */
+       if (SiS_SetStart(SiS_Pr)) continue;		/* TW: Re-start */
+       tempah = SiS_Pr->SiS_DDC_DeviceAddr | 0x01; 	/* DAB | 0x01 = Read */
+       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);		/* TW: DAB (S0=1=read) */
+       if(temp) continue;				/* TW:        (ERROR: no ack) */
+       tempah = SiS_ReadDDC2Data(SiS_Pr,tempah);	/* TW: Read byte */
+       if (SiS_SetStop(SiS_Pr)) continue;		/* TW: Stop condition */
+       SiS_Pr->SiS_ChrontelInit = 1;
+       return(tempah);
+     }
+  }
+  return(0xFFFF);
 }
 
-void
-SiS_SetSwitchDDC2(void)
+/* TW: Read from Chrontel 701x */
+/* Parameter is [Register no (S7-S0)] */
+USHORT
+SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempbx)
 {
-  USHORT i;
+  USHORT tempah,temp,i;
 
-  SiS_SetSCLKHigh();
-  for(i=0;i<1000;i++) {
-    SiS_GetReg1(SiS_DDC_Port,0x05);
-  }
-  SiS_SetSCLKLow();
-  for(i=0;i<1000;i++) {
-    SiS_GetReg1(SiS_DDC_Port,0x05);
-  }
+  SiS_Pr->SiS_DDC_Index = 0x11;			/* TW: Bit 0 = SC;  Bit 1 = SD */
+  SiS_Pr->SiS_DDC_Data  = 0x08;                 /* Bitmask in IndexReg for Data */
+  SiS_Pr->SiS_DDC_Clk   = 0x04;                 /* Bitmask in IndexReg for Clk */
+  SiS_Pr->SiS_DDC_DataShift = 0x00;
+  SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;		/* TW: DAB */
+  SiS_Pr->SiS_DDC_ReadAddr = tempbx;
+
+   for(i=0;i<20;i++) {	/* TW: Do only 20 attempts to read */
+    if(SiS_SetStart(SiS_Pr)) continue;		/* TW: Set start condition */
+    tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write DAB (S0=0=write) */
+    if(temp) continue;				/* TW:        (ERROR: no ack) */
+    tempah = SiS_Pr->SiS_DDC_ReadAddr;		/* TW: Write RAB */
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+    if(temp) continue;				/* TW:        (ERROR: no ack) */
+    if (SiS_SetStart(SiS_Pr)) continue;		/* TW: Re-start */
+    tempah = SiS_Pr->SiS_DDC_DeviceAddr | 0x01; /* DAB | 0x01 = Read */
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: DAB (S0=1=read) */
+    if(temp) continue;				/* TW:        (ERROR: no ack) */
+    tempah = SiS_ReadDDC2Data(SiS_Pr,tempah);	/* TW: Read byte */
+    SiS_SetStop(SiS_Pr);			/* TW: Stop condition */
+    return(tempah);
+   }
+  return 0xFFFF;
 }
 
-/* TW: Set Chrontel 7005 start condition */
-/* TW: This is done by a SD high-to-low transition while SC is high */
-void
-SiS_SetStart(void)
+#ifdef LINUX_XF86
+/* TW: Our own DDC functions */
+USHORT
+SiS_InitDDCRegs(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT adaptnum, USHORT DDCdatatype)
 {
-  SiS_SetSCLKLow();					  /* TW: (SC->low)  */
-  SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFD,0x02);  /* TW: SD->high */
-  SiS_SetSCLKHigh();					  /* TW: SC->high */
-  SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFD,0x00);  /* TW: SD->low = start condition */
-  SiS_SetSCLKHigh();					  /* TW: (SC->low) */
+     unsigned char ddcdtype[] = { 0xa0, 0xa0, 0xa0, 0xa2, 0xa6};
+     unsigned char flag, cr32;
+     USHORT        temp = 0, myadaptnum = adaptnum;
+
+     SiS_Pr->SiS_ChrontelInit = 0;   /* force re-detection! */
+
+     SiS_Pr->SiS_DDC_SecAddr = 0;
+     SiS_Pr->SiS_DDC_DeviceAddr = ddcdtype[DDCdatatype];
+     SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_P3c4;
+     SiS_Pr->SiS_DDC_Index = 0x11;
+     flag = 0xff;
+
+     cr32 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x32);
+
+     if(pSiS->VGAEngine == SIS_300_VGA) {		/* 300 series */
+
+        if(pSiS->VBFlags & VB_SISBRIDGE) {
+	   if(myadaptnum == 0) {
+	      if(!(cr32 & 0x20)) {
+	         myadaptnum = 2;
+		 if(!(cr32 & 0x10)) {
+		    myadaptnum = 1;
+		    if(!(cr32 & 0x08)) {
+		       myadaptnum = 0;
+		    }
+		 }
+              }
+	   }
+	}
+
+        if(myadaptnum != 0) {
+	   flag = 0;
+	   if(pSiS->VBFlags & VB_SISBRIDGE) {
+	      SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_Part4Port;
+              SiS_Pr->SiS_DDC_Index = 0x0f;
+	   }
+        }
+
+	if(cr32 & 0x80) {
+           if(myadaptnum >= 1) {
+	      if(!(cr32 & 0x08)) {
+	          myadaptnum = 1;
+		  if(!(cr32 & 0x10)) return 0xFFFF;
+              }
+	   }
+	}
+
+	temp = 4 - (myadaptnum * 2);
+	if(flag) temp = 0;
+
+	SiS_Pr->SiS_DDC_Data = 0x02 << temp;
+        SiS_Pr->SiS_DDC_Clk  = 0x01 << temp;
+
+     } else {						/* 310/325 series */
+
+        if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) myadaptnum = 0;
+
+	if(pSiS->VBFlags & VB_SISBRIDGE) {
+	   if(myadaptnum == 0) {
+	      if(!(cr32 & 0x20)) {
+	         myadaptnum = 2;
+		 if(!(cr32 & 0x10)) {
+		    myadaptnum = 1;
+		    if(!(cr32 & 0x08)) {
+		       myadaptnum = 0;
+		    }
+		 }
+              }
+	   }
+	   if(myadaptnum == 2) {
+	      myadaptnum = 1;
+           }
+	}
+
+        if(myadaptnum == 1) {
+     	   flag = 0;
+	   if(pSiS->VBFlags & VB_SISBRIDGE) {
+	      SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_Part4Port;
+              SiS_Pr->SiS_DDC_Index = 0x0f;
+	   }
+        }
+
+        if(cr32 & 0x80) {
+           if(myadaptnum >= 1) {
+	      if(!(cr32 & 0x08)) {
+	         myadaptnum = 1;
+		 if(!(cr32 & 0x10)) return 0xFFFF;
+	      }
+	   }
+        }
+
+        temp = myadaptnum;
+        if(myadaptnum == 1) {
+           temp = 0;
+	   if(pSiS->VBFlags & VB_LVDS) flag = 0xff;
+        }
+
+	if(flag) temp = 0;
+
+        SiS_Pr->SiS_DDC_Data = 0x02 << temp;
+        SiS_Pr->SiS_DDC_Clk  = 0x01 << temp;
+
+    }
+    return 0;
 }
 
-/* TW: Set Chrontel 7005 stop condition */
-/* TW: This is done by a SD low-to-high transition while SC is high */
-void
-SiS_SetStop(void)
+USHORT
+SiS_WriteDABDDC(SiS_Private *SiS_Pr)
 {
-  SiS_SetSCLKLow();					  /* TW: (SC->low) */
-  SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFD,0x00);  /* TW: SD->low   */
-  SiS_SetSCLKHigh();					  /* TW: SC->high  */
-  SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFD,0x02);  /* TW: SD->high = stop condition */   
-  SiS_SetSCLKHigh();					  /* TW: (SC->high) */
+   SiS_SetStart(SiS_Pr);
+   if(SiS_WriteDDC2Data(SiS_Pr, SiS_Pr->SiS_DDC_DeviceAddr)) return 0xFFFF;
+   if(SiS_WriteDDC2Data(SiS_Pr, SiS_Pr->SiS_DDC_SecAddr)) return 0xFFFF;
+   return(0);
 }
 
-/* TW: Write 8 bits of data */
 USHORT
-SiS_WriteDDC2Data(USHORT tempax)
+SiS_PrepareReadDDC(SiS_Private *SiS_Pr)
 {
-  USHORT i,flag,temp;
-
-  flag=0x80;
-  for(i=0;i<8;i++) {
-    SiS_SetSCLKLow();					     /* TW: SC->low */
-    if(tempax&flag) {
-      SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFD,0x02); /* TW: Write bit (1) to SD */
-    } else {
-      SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFD,0x00); /* TW: Write bit (0) to SD */
-    }
-    SiS_SetSCLKHigh();					     /* TW: SC->high */
-    flag=flag>>1;
-  }
-  temp=SiS_CheckACK();					     /* TW: Check acknowledge */
-  return(temp);
+   SiS_SetStart(SiS_Pr);
+   if(SiS_WriteDDC2Data(SiS_Pr, (SiS_Pr->SiS_DDC_DeviceAddr | 0x01))) return 0xFFFF;
+   return(0);
 }
 
 USHORT
-SiS_ReadDDC2Data(USHORT tempax)
+SiS_PrepareDDC(SiS_Private *SiS_Pr)
 {
-  USHORT i,temp,getdata;
-
-  getdata=0;
-  for(i=0;i<8;i++) {
-    getdata=getdata<<1;
-    SiS_SetSCLKLow();
-    SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFD,0x02);
-    SiS_SetSCLKHigh();
-    temp=SiS_GetReg1(SiS_DDC_Port,SiS_DDC_Index);
-    if(temp&0x02) getdata=getdata|0x01;
-  }
-  return(getdata);
+   if(SiS_WriteDABDDC(SiS_Pr)) SiS_WriteDABDDC(SiS_Pr);
+   if(SiS_PrepareReadDDC(SiS_Pr)) return(SiS_PrepareReadDDC(SiS_Pr));
+   return(0);
 }
 
 void
-SiS_SetSCLKLow(void)
+SiS_SendACK(SiS_Private *SiS_Pr, USHORT yesno)
 {
-    USHORT temp;
-
-    SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFE,0x00);      /* SetSCLKLow()  */
-    do {
-      temp=SiS_GetReg1(SiS_DDC_Port,SiS_DDC_Index);
-    } while(temp&0x01);
-    SiS_DDC2Delay();
+   SiS_SetSCLKLow(SiS_Pr);
+   if(yesno) {
+      SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, SiS_Pr->SiS_DDC_Index,
+                      ~SiS_Pr->SiS_DDC_Data, SiS_Pr->SiS_DDC_Data);
+   } else {
+      SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, SiS_Pr->SiS_DDC_Index,
+                      ~SiS_Pr->SiS_DDC_Data, 0);
+   }
+   SiS_SetSCLKHigh(SiS_Pr);
 }
 
-void
-SiS_SetSCLKHigh(void)
+USHORT
+SiS_DoProbeDDC(SiS_Private *SiS_Pr)
 {
-  USHORT temp;
+    unsigned char mask, value;
+    USHORT  temp, ret;
 
-  SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFE,0x01);      /* SetSCLKHigh()  */
-  do {
-    temp=SiS_GetReg1(SiS_DDC_Port,SiS_DDC_Index);
-  } while(!(temp&0x01));
-  SiS_DDC2Delay();
+    SiS_SetSwitchDDC2(SiS_Pr);
+    if(SiS_PrepareDDC(SiS_Pr)) {
+         SiS_SetStop(SiS_Pr);
+         return(0xFFFF);
+    }
+    mask = 0xf0;
+    value = 0x20;
+    if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) {
+       temp = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0);
+       SiS_SendACK(SiS_Pr, 0);
+       if(temp == 0) {
+           mask = 0xff;
+	   value = 0xff;
+       }
+    }
+    temp = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0);
+    SiS_SendACK(SiS_Pr, 1);
+    temp &= mask;
+    if(temp == value) ret = 0;
+    else {
+       ret = 0xFFFF;
+       if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) {
+           if(value == 0x30) ret = 0;
+       }
+    }
+    SiS_SetStop(SiS_Pr);
+    return(ret);
 }
 
-void
-SiS_DDC2Delay(void)
+USHORT
+SiS_ProbeDDC(SiS_Private *SiS_Pr)
 {
-  USHORT i;
+   USHORT flag;
 
-   for(i=0;i<DDC2DelayTime;i++) {
-    SiS_GetReg1(SiS_P3c4,0x05);
-  }
+   flag = 0x180;
+   SiS_Pr->SiS_DDC_DeviceAddr = 0xa0;
+   if(!(SiS_DoProbeDDC(SiS_Pr))) flag |= 0x02;
+   SiS_Pr->SiS_DDC_DeviceAddr = 0xa2;
+   if(!(SiS_DoProbeDDC(SiS_Pr))) flag |= 0x08;
+   SiS_Pr->SiS_DDC_DeviceAddr = 0xa6;
+   if(!(SiS_DoProbeDDC(SiS_Pr))) flag |= 0x10;
+   if(!(flag & 0x1a)) flag = 0;
+   return(flag);
 }
 
-/* TW: Check acknowledge */
-/* Returns 0 if ack ok, non-0 if ack not ok */
 USHORT
-SiS_CheckACK(void)
+SiS_ReadDDC(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT DDCdatatype, unsigned char *buffer)
 {
-  USHORT tempah;
+   USHORT flag, length, i;
+   unsigned char chksum,gotcha;
 
-  SiS_SetSCLKLow();					  /* TW: (SC->low) */
-  SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFD,0x02);  /* TW: (SD->high) */
-  SiS_SetSCLKHigh();					  /* TW: SC->high = clock impulse for ack */
-  tempah=SiS_GetReg1(SiS_DDC_Port,SiS_DDC_Index);	  /* TW: Read SD */
-  SiS_SetSCLKLow();					  /* TW: SC->low = end of clock impulse */
-  if(tempah&0x02) return(1);				  /* TW: Ack OK if bit = 0 */
-  else return(0);
+   if(DDCdatatype > 3) return 0xFFFF;  /* incomplete! */
+
+   flag = 0;
+   SiS_SetSwitchDDC2(SiS_Pr);
+   if(!(SiS_PrepareDDC(SiS_Pr))) {
+      length = 127;
+      if(DDCdatatype != 1) length = 255;
+      chksum = 0;
+      gotcha = 0;
+      for(i=0; i<length; i++) {
+         buffer[i] = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0);
+	 chksum += buffer[i];
+	 gotcha |= buffer[i];
+	 SiS_SendACK(SiS_Pr, 0);
+      }
+      buffer[i] = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0);
+      chksum += buffer[i];
+      SiS_SendACK(SiS_Pr, 1);
+      if(gotcha) flag = (USHORT)chksum;
+      else flag = 0xFFFF;
+   } else {
+      flag = 0xFFFF;
+   }
+   SiS_SetStop(SiS_Pr);
+   return(flag);
 }
 
-/* TW: End of Chrontel 7005 functions ---------------------------- */
+/* TW: Our private DDC function
 
-void
-SiS_ModCRT1CRTC(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                USHORT RefreshRateTableIndex)
-{
-  USHORT temp,tempah,i,modeflag,j;
-  USHORT ResInfo,DisplayType;
-  SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr=NULL;
+   It complies somewhat with the corresponding VESA function
+   in arguments and return values.
 
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-  }
+   Since this is probably called before the mode is changed,
+   we use our pre-detected pSiS-values instead of SiS_Pr as
+   regards chipset and video bridge type.
 
-  temp= SiS_GetLVDSCRT1Ptr(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                       &ResInfo,&DisplayType);
-  if(temp==0){
-    return;
-  }
+   Arguments:
+       adaptnum: 0=CRT1, 1=CRT2
+                 CRT2 DDC is not supported in some cases.
+       DDCdatatype: 0=Probe, 1=EDID, 2=VDIF(not supported), 3=?, 4=?(not supported)
+       buffer: ptr to 256 data bytes which will be filled with read data.
 
-  switch(DisplayType) {
-    case 0 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1;           break;
-    case 1 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1;          break;
-    case 2 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1;         break;
-    case 3 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1_H;         break;
-    case 4 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1_H;        break;
-    case 5 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1_H;       break;
-    case 6 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2;           break;
-    case 7 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2;          break;
-    case 8 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2;         break;
-    case 9 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2_H;         break;
-    case 10: LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2_H;        break;
-    case 11: LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2_H;       break;
-    case 12: LVDSCRT1Ptr = SiS_CHTVCRT1UNTSC;               break;
-    case 13: LVDSCRT1Ptr = SiS_CHTVCRT1ONTSC;               break;
-    case 14: LVDSCRT1Ptr = SiS_CHTVCRT1UPAL;                break;
-    case 15: LVDSCRT1Ptr = SiS_CHTVCRT1OPAL;                break;
-    case 16: LVDSCRT1Ptr = SiS_LVDSCRT1320x480_1;           break;
-  }
+   Returns 0xFFFF if error, otherwise
+       if DDCdatatype > 0:  Returns 0 if reading OK (included a correct checksum)
+       if DDCdatatype = 0:  Returns supported DDC modes
 
-  tempah=(UCHAR)SiS_GetReg1(SiS_P3d4,0x11);                        /*unlock cr0-7  */
-  tempah=tempah&0x7F;
-  SiS_SetReg1(SiS_P3d4,0x11,tempah);
-  tempah = (LVDSCRT1Ptr+ResInfo)->CR[0];
-  SiS_SetReg1(SiS_P3d4,0x0,tempah);
-  for(i=0x02,j=1;i<=0x05;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3d4,i,tempah);
-  }
-  for(i=0x06,j=5;i<=0x07;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3d4,i,tempah);
-  }
-  for(i=0x10,j=7;i<=0x11;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3d4,i,tempah);
-  }
-  for(i=0x15,j=9;i<=0x16;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3d4,i,tempah);
-  }
-  for(i=0x0A,j=11;i<=0x0C;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3c4,i,tempah);
-  }
+ */
+USHORT
+SiS_HandleDDC(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT adaptnum,
+              USHORT DDCdatatype, unsigned char *buffer)
+{
+   if(DDCdatatype == 2) return 0xFFFF;
+   if(adaptnum > 2) return 0xFFFF;
+   if(pSiS->VGAEngine == SIS_300_VGA) {
+      if((adaptnum != 0) && (DDCdatatype != 0)) return 0xFFFF;
+   }
+   if((!(pSiS->VBFlags & VB_VIDEOBRIDGE)) && (adaptnum > 0)) return 0xFFFF;
+   if(SiS_InitDDCRegs(SiS_Pr, pSiS, adaptnum, DDCdatatype) == 0xFFFF) return 0xFFFF;
+   if(DDCdatatype == 0) {
+       return(SiS_ProbeDDC(SiS_Pr));
+   } else {
+       if(DDCdatatype > 4) return 0xFFFF;
+       return(SiS_ReadDDC(SiS_Pr, pSiS, DDCdatatype, buffer));
+   }
+}
 
-  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
-  tempah=tempah&0x0E0;
-  SiS_SetReg1(SiS_P3c4,0x0E,tempah);
+/* TW: Generic I2C functions (compliant to i2c library) */
 
-  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
-  tempah=tempah&0x01;
-  tempah=tempah<<5;
-  if(modeflag&DoubleScanMode){
-    	tempah=tempah|0x080;
-  }
-  SiS_SetRegANDOR(SiS_P3d4,0x09,~0x020,tempah);
-  return;
+#if 0
+USHORT
+SiS_I2C_GetByte(SiS_Private *SiS_Pr)
+{
+   return(SiS_ReadDDC2Data(SiS_Pr,0));
+}
+
+Bool
+SiS_I2C_PutByte(SiS_Private *SiS_Pr, USHORT data)
+{
+   if(SiS_WriteDDC2Data(SiS_Pr,data)) return FALSE;
+   return TRUE;
+}
+
+Bool
+SiS_I2C_Address(SiS_Private *SiS_Pr, USHORT addr)
+{
+   if(SiS_SetStart(SiS_Pr)) return FALSE;
+   if(SiS_WriteDDC2Data(SiS_Pr,addr)) return FALSE;
+   return TRUE;
 }
 
-/*301b*/
 void
-SiS_CHACRT1CRTC(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                USHORT RefreshRateTableIndex)
+SiS_I2C_Stop(SiS_Private *SiS_Pr)
 {
-  USHORT temp,tempah,i,modeflag,j;
-  USHORT ResInfo,DisplayType;
-  SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr=NULL;
+   SiS_SetStop(SiS_Pr);
+}
+#endif
 
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-  }
+#endif
 
-  temp= SiS_GetLVDSCRT1Ptr(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                       &ResInfo,&DisplayType);
-  if(temp==0){
-    return;
-  }
+void
+SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh)
+{
+  USHORT tempal,tempah,tempbl;
 
-  switch(DisplayType) {
-    case 0 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1;           break;
-    case 1 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1;          break;
-    case 2 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1;         break;
-    case 3 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1_H;         break;
-    case 4 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1_H;        break;
-    case 5 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1_H;       break;
-    case 6 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2;           break;
-    case 7 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2;          break;
-    case 8 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2;         break;
-    case 9 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2_H;         break;
-    case 10: LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2_H;        break;
-    case 11: LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2_H;       break;
-    case 12: LVDSCRT1Ptr = SiS_CHTVCRT1UNTSC;               break;
-    case 13: LVDSCRT1Ptr = SiS_CHTVCRT1ONTSC;               break;
-    case 14: LVDSCRT1Ptr = SiS_CHTVCRT1UPAL;                break;
-    case 15: LVDSCRT1Ptr = SiS_CHTVCRT1OPAL;                break;
-  }
+  tempal = tempax & 0x00FF;
+  tempah =(tempax >> 8) & 0x00FF;
+  tempbl = SiS_GetCH70xx(SiS_Pr,tempal);
+  tempbl = (((tempbl & tempbh) | tempah) << 8 | tempal);
+  SiS_SetCH70xx(SiS_Pr,tempbl);
+}
 
-  tempah=(UCHAR)SiS_GetReg1(SiS_P3d4,0x11);                        /*unlock cr0-7  */
-  tempah=tempah&0x7F;
-  SiS_SetReg1(SiS_P3d4,0x11,tempah);
-  tempah = (LVDSCRT1Ptr+ResInfo)->CR[0];
-  SiS_SetReg1(SiS_P3d4,0x0,tempah);
-  for(i=0x02,j=1;i<=0x05;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3d4,i,tempah);
-  }
-  for(i=0x06,j=5;i<=0x07;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3d4,i,tempah);
-  }
-  for(i=0x10,j=7;i<=0x11;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3d4,i,tempah);
-  }
-  for(i=0x15,j=9;i<=0x16;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3d4,i,tempah);
-  }
+/* TW: Generic I2C functions for Chrontel --------- */
 
-  for(i=0x0A,j=11;i<=0x0C;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3c4,i,tempah);
-  }
+void
+SiS_SetSwitchDDC2(SiS_Private *SiS_Pr)
+{
+  SiS_SetSCLKHigh(SiS_Pr);
+  /* SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAY); */
+  SiS_WaitRetraceDDC(SiS_Pr);
 
-  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
-  tempah=tempah&0x0E0;
-  SiS_SetReg1(SiS_P3c4,0x0E,tempah);
+  SiS_SetSCLKLow(SiS_Pr);
+  /* SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAY); */
+  SiS_WaitRetraceDDC(SiS_Pr);
+}
 
-  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
-  tempah=tempah&0x01;
-  tempah=tempah<<5;
-  if(modeflag&DoubleScanMode){
-    	tempah=tempah|0x080;
-  }
-  SiS_SetRegANDOR(SiS_P3d4,0x09,~0x020,tempah);
-  return;
+/* TW: Set I2C start condition */
+/* TW: This is done by a SD high-to-low transition while SC is high */
+USHORT
+SiS_SetStart(SiS_Private *SiS_Pr)
+{
+  if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF;			           /* TW: (SC->low)  */
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                  ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data);             /* TW: SD->high */
+  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;			           /* TW: SC->high */
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                  ~SiS_Pr->SiS_DDC_Data,0x00);                             /* TW: SD->low = start condition */
+  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;			           /* TW: (SC->low) */
+  return 0;
 }
-/*add for LCDA*/
 
-BOOLEAN
-SiS_GetLCDACRT1Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-		   USHORT RefreshRateTableIndex,USHORT *ResInfo,
-		   USHORT *DisplayType)
- {
-  USHORT tempbx=0,modeflag=0;
-  USHORT CRT2CRTC=0;
- /*301b*/
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-                    &&(SiS_VBInfo&SetCRT2ToLCDA) ) {
-    	tempbx = SiS_LCDResInfo;
-    	tempbx -= Panel800x600;
-    	if(SiS_LCDInfo&LCDNonExpanding) tempbx +=6;
-#if 0   /* TW: That can't work - test modeflag BEFORE reading it? */
-    	if(modeflag&HalfDCLK) tempbx +=+3;
-#endif
-    	if(ModeNo<=0x13) {
-    		modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-    		CRT2CRTC = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  	} else {
-    		modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-    		CRT2CRTC = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-  	}
-	/* TW: This belongs here I assume */
-	if(modeflag&HalfDCLK) tempbx +=+3;
-  }
-  *ResInfo = CRT2CRTC&0x3F;
-  *DisplayType = tempbx;
-  return 1;
+/* TW: Set I2C stop condition */
+/* TW: This is done by a SD low-to-high transition while SC is high */
+USHORT
+SiS_SetStop(SiS_Private *SiS_Pr)
+{
+  if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF;			           /* TW: (SC->low) */
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                  ~SiS_Pr->SiS_DDC_Data,0x00);          		   /* TW: SD->low   */
+  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;			           /* TW: SC->high  */
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                  ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data);  	   /* TW: SD->high = stop condition */
+  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;			           /* TW: (SC->high) */
+  return 0;
 }
-/*end for 301b*/
 
-BOOLEAN
-SiS_GetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-		USHORT RefreshRateTableIndex,USHORT *ResInfo,USHORT *DisplayType)
- {
-  USHORT tempbx,modeflag=0;
-  USHORT Flag,CRT2CRTC;
- 
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-    	CRT2CRTC = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-    	CRT2CRTC = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-  }
-  if(!(SiS_VBInfo&SetInSlaveMode)){
-     return 0;
-  }
-  Flag=1;
-  tempbx=0;
-  if(SiS_IF_DEF_CH7005==1) {
-    if(!(SiS_VBInfo&SetCRT2ToLCD)) {
-      Flag=0;
-      tempbx =12;
-      if(SiS_VBInfo&SetPALTV) tempbx +=2;
-      if(SiS_VBInfo&SetCHTVOverScan) tempbx +=1;
+/* TW: Write 8 bits of data */
+USHORT
+SiS_WriteDDC2Data(SiS_Private *SiS_Pr, USHORT tempax)
+{
+  USHORT i,flag,temp;
+
+  flag=0x80;
+  for(i=0;i<8;i++) {
+    SiS_SetSCLKLow(SiS_Pr);				                      /* TW: SC->low */
+    if(tempax & flag) {
+      SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                      ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data);            /* TW: Write bit (1) to SD */
+    } else {
+      SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                      ~SiS_Pr->SiS_DDC_Data,0x00);                            /* TW: Write bit (0) to SD */
     }
+    SiS_SetSCLKHigh(SiS_Pr);				                      /* TW: SC->high */
+    flag >>= 1;
   }
-  if(Flag) {
-    tempbx =SiS_LCDResInfo;
-    tempbx -=Panel800x600;
-    if(SiS_LCDInfo&LCDNonExpanding) tempbx +=6;
-    if(modeflag&HalfDCLK) tempbx +=+3;
-  }
-  /*fstn*/
-   if(SiS_IF_DEF_FSTN){
-     if(SiS_LCDResInfo==Panel320x480){
-       tempbx=0x10;         /*not same with asmber code */
-     }
-   }
-  *ResInfo = CRT2CRTC&0x3F;
-  *DisplayType = tempbx;
-  return 1;
+  temp = SiS_CheckACK(SiS_Pr);				                      /* TW: Check acknowledge */
+  return(temp);
+}
+
+USHORT
+SiS_ReadDDC2Data(SiS_Private *SiS_Pr, USHORT tempax)
+{
+  USHORT i,temp,getdata;
+
+  getdata=0;
+  for(i=0; i<8; i++) {
+    getdata <<= 1;
+    SiS_SetSCLKLow(SiS_Pr);
+    SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                    ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data);
+    SiS_SetSCLKHigh(SiS_Pr);
+    temp = SiS_GetReg1(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index);
+    if(temp & SiS_Pr->SiS_DDC_Data) getdata |= 0x01;
+  }
+  return(getdata);
+}
+
+USHORT
+SiS_SetSCLKLow(SiS_Private *SiS_Pr)
+{
+  USHORT temp, watchdog=50000;
+
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                  ~SiS_Pr->SiS_DDC_Clk,0x00);      		/* SetSCLKLow()  */
+  do {
+    temp = SiS_GetReg1(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index);
+  } while((temp & SiS_Pr->SiS_DDC_Clk) && --watchdog);
+  if (!watchdog) return 0xFFFF;
+  SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT);
+  return 0;
 }
 
-void
-SiS_SetCRT2ECLK(ULONG ROMAddr, USHORT ModeNo,USHORT ModeIdIndex,
-           USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+USHORT
+SiS_SetSCLKHigh(SiS_Private *SiS_Pr)
 {
-  USHORT tempah,tempal;
-  USHORT P3cc=SiS_P3c9+3;
-  USHORT vclkindex=0;
+  USHORT temp,watchdog=50000;
 
-  if(SiS_IF_DEF_TRUMPION==0){  /*no trumpion  */
-    	tempal=SiS_GetReg2(P3cc);
-    	tempal=tempal&0x0C;
-    	vclkindex=SiS_GetVCLK2Ptr(ROMAddr,ModeNo,ModeIdIndex,
-                               RefreshRateTableIndex,HwDeviceExtension);
-  } else {  			/*trumpion  */
-    	SiS_SetFlag=SiS_SetFlag&(~ProgrammingCRT2);
-/*  	tempal=*((UCHAR *)(ROMAddr+SiS_RefIndex+0x03));     &di+Ext_CRTVCLK  */
-    	tempal=tempal&0x03F;
-    	if(tempal==0x02){ /*31.5MHz  */
-/*      	SiS_RefIndex=SiS_RefIndex-Ext2StructSize;   */
-    	}
-/*    	SiS_RefIndex=GetVCLKPtr(ROMAddr,ModeNo);  */
-    	SiS_SetFlag=SiS_SetFlag|ProgrammingCRT2;
-  }
-  tempal=0x02B;
-  if(!(SiS_VBInfo&SetInSlaveMode)){
-    	tempal=tempal+3;
-  }
-  SiS_SetReg1(SiS_P3c4,0x05,0x86);
-  tempah = SiS_VCLKData[vclkindex].SR2B;
-  SiS_SetReg1(SiS_P3c4,tempal,tempah);
-  tempal++;
-  tempah = SiS_VCLKData[vclkindex].SR2C;
-  SiS_SetReg1(SiS_P3c4,tempal,tempah);
-  tempal++;
-  SiS_SetReg1(SiS_P3c4,tempal,0x80);
-  return;
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                  ~SiS_Pr->SiS_DDC_Clk,SiS_Pr->SiS_DDC_Clk);  	/* SetSCLKHigh()  */
+  do {
+    temp = SiS_GetReg1(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index);
+  } while((!(temp & SiS_Pr->SiS_DDC_Clk)) && --watchdog);
+  if (!watchdog) return 0xFFFF;
+  SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT);
+  return 0;
 }
 
 void
-SiS_SetDefCRT2ExtRegs(USHORT BaseAddr)
+SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime)
 {
-  USHORT  temp;
+  USHORT i;
 
-  if(SiS_IF_DEF_LVDS==0) {
-    SiS_SetReg1(SiS_Part1Port,0x02,0x40);
-    SiS_SetReg1(SiS_Part4Port,0x10,0x80);
-    temp=(UCHAR)SiS_GetReg1(SiS_P3c4,0x16);
-    temp=temp&0xC3;
-    SiS_SetReg1(SiS_P3d4,0x35,temp);
-  }
-  else {
-    SiS_SetReg1(SiS_P3d4,0x32,0x02);
-    SiS_SetReg1(SiS_Part1Port,0x02,0x00);
+  for(i=0; i<delaytime; i++) {
+    SiS_GetReg1(SiS_Pr->SiS_P3c4,0x05);
   }
 }
 
+/* TW: Check I2C acknowledge */
+/* Returns 0 if ack ok, non-0 if ack not ok */
+USHORT
+SiS_CheckACK(SiS_Private *SiS_Pr)
+{
+  USHORT tempah;
+
+  SiS_SetSCLKLow(SiS_Pr);				           /* TW: (SC->low) */
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                  ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data);     /* TW: (SD->high) */
+  SiS_SetSCLKHigh(SiS_Pr);				           /* TW: SC->high = clock impulse for ack */
+  tempah = SiS_GetReg1(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index);/* TW: Read SD */
+  SiS_SetSCLKLow(SiS_Pr);				           /* TW: SC->low = end of clock impulse */
+  if(tempah & SiS_Pr->SiS_DDC_Data) return(1);			   /* TW: Ack OK if bit = 0 */
+  else return(0);
+}
+
+/* TW: End of I2C functions ----------------------- */
+
+
+/* =============== SiS 310/325 O.E.M. ================= */
+
 #ifdef SIS315H
-/*
-    for SIS310 O.E.M.
-*/
-/*
----------------------------------------------------------
-   LCDResInfo 1 : 800x600
-              2 : 1024x768
-              3 : 1280x1024
-              4 : 1280x960
-              5 : 640x480
-              6 : 1600x1200
-              7 : 1920x1440
-   VESA
-   non-VESA
-   non-Expanding
----------------------------------------------------------
-*/
+
 USHORT
-GetLCDPtrIndex (void)
+GetLCDPtrIndex(SiS_Private *SiS_Pr)
 {
-   USHORT index;
+  USHORT index;
 
-   index = (SiS_LCDResInfo & 0x0F)-1;
-   index *= 3;
-   if (SiS_LCDInfo&LCDNonExpanding)
-      index += 2;
-   else
-   {
-     if (!(SiS_LCDInfo&LCDVESATiming))
-       index++;
-   }
+  index = SiS_Pr->SiS_LCDResInfo & 0x0F;
+  index--;
+  index *= 3;
+  if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) index += 2;
+  else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) index++;
 
   return index;
- }
-
+}
 
 /*
 ---------------------------------------------------------
@@ -5238,573 +8806,608 @@
 ---------------------------------------------------------
 */
 USHORT
-GetTVPtrIndex(void)
+GetTVPtrIndex(SiS_Private *SiS_Pr)
 {
   USHORT index;
 
   index = 0;
-  if (SiS_VBInfo&SetPALTV)
-    index++;
-  if (SiS_VBInfo&SetCRT2ToHiVisionTV)  /* Hivision TV use PAL */
-    index++;
-  index *= 2;
+  if(SiS_Pr->SiS_VBInfo & SetPALTV) index++;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) index++;  /* Hivision TV use PAL */
+
+  index <<= 1;
 
-  if ((SiS_VBInfo&SetInSlaveMode)&&(SiS_SetFlag&TVSimuMode))
+  if((SiS_Pr->SiS_VBInfo & SetInSlaveMode) && (SiS_Pr->SiS_SetFlag & TVSimuMode))
     index++;
 
   return index;
 }
 
+/* TW: Checked against 650/LVDS (1.10.07) and 650/301LVx (1.10.6s) BIOS (including data) */
 void
-SetDelayComp(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-             ULONG ROMAddr,USHORT ModeNo)
+SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+             UCHAR *ROMAddr,USHORT ModeNo)
 {
-  USHORT Part1Port;
   USHORT delay,index;
 
-  if (SiS_VBInfo&SetCRT2ToRAMDAC)
-  {
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
      delay = SiS310_CRT2DelayCompensation1;
-     if (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
+     if(SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS302B))
        delay = SiS310_CRT2DelayCompensation2;
-  }
-  else
-    if (SiS_VBInfo&SetCRT2ToLCD)
-    {
-       index = GetLCDPtrIndex();
-       delay = SiS310_LCDDelayCompensation1[index];
-       if (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-         delay = SiS310_LCDDelayCompensation2[index];
-    }
-    else
-    {
-       index = GetTVPtrIndex();
-       delay = SiS310_TVDelayCompensation1[index];
-       if (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-         delay = SiS310_TVDelayCompensation2[index];
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 1)
+       delay = SiS310_CRT2DelayCompensation3;
+  } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+     index = GetLCDPtrIndex(SiS_Pr);
+     delay = SiS310_LCDDelayCompensation1[index];
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
+       delay = SiS310_LCDDelayCompensation2[index];
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 1)
+       delay = SiS310_LCDDelayCompensation3[index];
+  } else {
+     index = GetTVPtrIndex(SiS_Pr);
+     delay = SiS310_TVDelayCompensation1[index];
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
+       delay = SiS310_TVDelayCompensation2[index];
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 1)
+       delay = SiS310_TVDelayCompensation3[index];
+  }
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+    if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+       SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0xF0,delay);
+    } else {
+       delay <<= 4;
+       SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0x0F,delay);
     }
-  Part1Port=BaseAddr+SIS_CRT2_PORT_04;
-  SiS_SetRegANDOR(Part1Port,0x2D,~0x0F,delay);  /* index 2D D[3:0] */
+  } else {
+     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2D,delay);  /* index 2D D[3:0] */
+  }
 }
 
-/*
-*/
+/* TW: Checked against 650/301LVx 1.10.6s BIOS (including data) */
 void
-SetAntiFlicker(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-               ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SetAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+               UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT Part2Port;
   USHORT index,temp;
 
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-  temp = GetTVPtrIndex();
-  temp = (temp>>1);  /* 0: NTSC, 1 :PAL, 2:HiTV */
+  temp = GetTVPtrIndex(SiS_Pr);
+  temp >>= 1;  	  /* 0: NTSC, 1: PAL, 2: HiTV */
+
   if (ModeNo<=0x13)
-  {
-    index = SiS_SModeIDTable[ModeIdIndex].VB_StTVFlickerIndex;
-  }
+    index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVFlickerIndex;
   else
-  {
-    index = SiS_EModeIDTable[ModeIdIndex].VB_ExtTVFlickerIndex;
-  }
-  temp = SiS310_TVAntiFlick1[temp][index];
-  temp  <<= 4;
+    index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVFlickerIndex;
 
-  SiS_SetRegANDOR(Part2Port,0x0A,~0x70,temp);  /* index 0A D[6:4] */
+  temp = SiS310_TVAntiFlick1[temp][index];
+  temp <<= 4;
 
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0A,0x8f,temp);  /* index 0A D[6:4] */
 }
 
+/* TW: Checked against 650/301LVx 1.10.6s BIOS (including data) */
 void
-SetEdgeEnhance (PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-                ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SetEdgeEnhance(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+               UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT Part2Port;
   USHORT index,temp;
 
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-  temp = GetTVPtrIndex();
-  temp = (temp>>1);   /* 0: NTSC, 1 :PAL, 2:HiTV */
+  temp = GetTVPtrIndex(SiS_Pr);
+  temp >>= 1;              	/* 0: NTSC, 1: PAL, 2: HiTV */
+
   if (ModeNo<=0x13)
-  {
-    index = SiS_SModeIDTable[ModeIdIndex].VB_StTVEdgeIndex;   /* si+VB_StTVEdgeIndex */
-  }
+    index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVEdgeIndex;
   else
-  {
-    index = SiS_EModeIDTable[ModeIdIndex].VB_ExtTVEdgeIndex;  /* si+VB_ExtTVEdgeIndex */
-  }
-  temp = SiS310_TVEdge1[temp][index];
-  temp  <<= 5;
-
-  SiS_SetRegANDOR(Part2Port,0x3A,~0xE0,temp);  /* index 0A D[7:5] */
+    index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVEdgeIndex;
 
+  temp = SiS310_TVEdge1[temp][index];
+  temp <<= 5;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x3A,0x1F,temp);  /* index 0A D[7:5] */
 }
 
+/* TW: Checked against 650/301LVx 1.10.6s BIOS (incl data) */
 void
-SetYFilter(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-           ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SetYFilter(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+           UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT Part2Port,temp1,temp2;
-  USHORT index,temp,i,index1;
-  UCHAR  OutputSelect=*pSiS_OutputSelect;
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-  temp = GetTVPtrIndex();
-  temp >>= 1;  /* 0: NTSC, 1 :PAL, 2:HiTV */
+  USHORT index, temp, i, j;
+  UCHAR  OutputSelect = *SiS_Pr->pSiS_OutputSelect;
 
-  if (ModeNo<=0x13)
-  {
-    index =  SiS_SModeIDTable[ModeIdIndex].VB_StTVYFilterIndex;
-  }
-  else
-  {
-    index =  SiS_EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex;
+  temp = GetTVPtrIndex(SiS_Pr);
+  temp >>= 1;  			/* 0: NTSC, 1: PAL, 2: HiTV */
+
+  if (ModeNo<=0x13) {
+    index =  SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVYFilterIndex;
+  } else {
+    index =  SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex;
   }
 
-  if (SiS_VBInfo&SetCRT2ToHiVisionTV)  /* Hivision TV use PAL */
-   temp = 0;
+  if(SiS_Pr->SiS_VBInfo&SetCRT2ToHiVisionTV)  temp = 1;  /* Hivision TV uses PAL */
 
-  /*301b*/
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-    for(i=0x35;i<=0x38;i++)
-   {
-     SiS_SetReg1(Part2Port,i,SiS310_TVYFilter2[temp][index][i-0x35]);
-   }
-   for(i=0x48;i<=0x4A;i++)
-   {
-     SiS_SetReg1(Part2Port,i,SiS310_TVYFilter2[temp][index][(i-0x48)+0x04]);
-   }
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+    for(i=0x35, j=0; i<=0x38; i++, j++) {
+       SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_TVYFilter2[temp][index][j]);
+    }
+    for(i=0x48; i<=0x4A; i++, j++) {
+       SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_TVYFilter2[temp][index][j]);
+    }
+  } else {
+    for(i=0x35, j=0; i<=0x38; i++, j++){
+       SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_TVYFilter1[temp][index][j]);
+    }
   }
-      /*end 301b*/
-  else{
-   for(i=0x35;i<=0x38;i++)
-   {
-     SiS_SetReg1(Part2Port,i,SiS310_TVYFilter1[temp][index][i-0x35]);
-   }
+  
+  if(ROMAddr && SiS_Pr->SiS_UseROM) {
+  	OutputSelect = ROMAddr[0xf3];
   }
-/*add PALMN*/
-    if(OutputSelect&EnablePALMN) {                  
-      index1=SiS_GetReg1(SiS_P3d4,0x31);
-      temp1=index1&0x01;
-      index1=SiS_GetReg1(SiS_P3d4,0x38);
-      temp2=index1&0xC0;
-      if(temp1){
-         if(temp2==0x40){
-              if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-                 for(i=0x35;i<=0x38;i++){
-                      SiS_SetReg1(Part2Port,i,SiS310_PALMFilter2[index][i-0x35]);
-                     }
-                 for(i=0x48;i<=0x4A;i++) {
-                       SiS_SetReg1(Part2Port,i,SiS310_PALMFilter2[index][(i-0x48)+0x04]);
-                     }
-                }
-              else{ 
-                 for(i=0x35;i<=0x38;i++)
-                 SiS_SetReg1(Part2Port,i,SiS310_PALMFilter[index][i-0x35]);
-                 } 
-             }
-         if(temp2==0x80){ 
-              if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-                 for(i=0x35;i<=0x38;i++){
-                      SiS_SetReg1(Part2Port,i,SiS310_PALNFilter2[index][i-0x35]);
-                     }
-                 for(i=0x48;i<=0x4A;i++) {
-                       SiS_SetReg1(Part2Port,i,SiS310_PALNFilter2[index][(i-0x48)+0x04]);
-                     }
+  if(OutputSelect & EnablePALMN) {
+      if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x01) {
+         temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+         temp &= (EnablePALMN | EnablePALN);
+         if(temp == EnablePALMN) {
+              if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+                 for(i=0x35, j=0; i<=0x38; i++, j++){
+                      SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_PALMFilter2[index][j]);
+                 }
+                 for(i=0x48; i<=0x4A; i++, j++) {
+                       SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_PALMFilter2[index][j]);
+                 }
+              } else {
+                 for(i=0x35, j=0; i<=0x38; i++, j++) {
+                       SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_PALMFilter[index][j]);
+                 }
+              }
+         }
+         if(temp == EnablePALN) {
+              if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+                 for(i=0x35, j=0; i<=0x38; i++, j++) {
+                      SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_PALNFilter2[index][j]);
+                 }
+                 for(i=0x48, j=0; i<=0x4A; i++, j++) {
+                       SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_PALNFilter2[index][j]);
+                 }
+             } else {
+                 for(i=0x35, j=0; i<=0x38; i++, j++)
+                       SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_PALNFilter[index][j]);
              }
-              else{
-                 for(i=0x35;i<=0x38;i++)
-                 SiS_SetReg1(Part2Port,i,SiS310_PALNFilter[index][i-0x35]);
-                }
-          }
+         }
       }
-    }
-    /*end PALMN*/
+  }
 }
 
+/* TW: Checked against 650/301LVx 1.10.6s BIOS (including data) */
 void
-SetPhaseIncr(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-             ULONG ROMAddr,USHORT ModeNo)
+SetPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+             UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT Part2Port;
-  USHORT index,temp,temp1,i;
+  USHORT index,temp,temp1,i,j,resinfo;
+
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) return;
 
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-  temp = GetTVPtrIndex();
-  /* 0: NTSC Graphics, 1: NTSC Text, 2 :PAL Graphics, 3 :PAL Text, 4:HiTV Graphics 5:HiTV Text */
+  temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);        /* if PALM/N not set */
+  temp1 &=  (EnablePALMN | EnablePALN);
+  if(temp1) return;
+
+
+  if (ModeNo<=0x13) {
+    resinfo =  SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+  } else {
+    resinfo =  SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+
+  temp = GetTVPtrIndex(SiS_Pr);
+  /* 0: NTSC Graphics, 1: NTSC Text,    2:PAL Graphics,
+   * 3: PAL Text,      4: HiTV Graphics 5:HiTV Text
+   */
   index = temp % 2;
-  temp >>= 1;   /* 0: NTSC, 1 :PAL, 2:HiTV */
-  temp1=SiS_GetReg1(SiS_P3d4,0x38);        /*if PALMN Not Set*/
-  temp1=temp1&0xC0; 
-  if(!temp1){
-  	for(i=0x31;i<=0x34;i++)
-  	{
-    		if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-     			SiS_SetReg1(Part2Port,i,SiS310_TVPhaseIncr2[temp][index][i-0x31]);
-    		else
-     			SiS_SetReg1(Part2Port,i,SiS310_TVPhaseIncr1[temp][index][i-0x31]);
-  	}
+  temp >>= 1;          /* 0:NTSC, 1:PAL, 2:HiTV */
+
+  for(j=0, i=0x31; i<=0x34; i++, j++) {
+     if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV))
+	  SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr1[temp][index][j]);
+     else if((!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || (SiS_Pr->SiS_SetFlag & TVSimuMode))
+          SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr2[temp][index][j]);
+     else
+          SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr1[temp][index][j]);
+  }
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {    /* TW: 650/301LV: (VB_SIS301LV | VB_SIS302LV)) */
+     if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+        if(resinfo == 6) {
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x31,0x21);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x32,0xf0);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x33,0xf5);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x34,0x7f);
+	} else if (resinfo == 7) {
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x31,0x21);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x32,0xf0);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x33,0xf5);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x34,0x7f);
+	} else if (resinfo == 8) {
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x31,0x1e);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x32,0x8b);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x33,0xfb);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x34,0x7b);
+	}
+     }
   }
 }
 
 void
-SiS_OEM310Setting(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-                  ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SiS_OEM310Setting(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                  UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-   SetDelayComp(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
-   if (SiS_VBInfo&SetCRT2ToTV) {
-       SetAntiFlicker(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
-       SetPhaseIncr(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
-       SetYFilter(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
-       SetEdgeEnhance(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+   SetDelayComp(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
+   /* TW: The TV funtions are not for LVDS */
+   if( (SiS_Pr->SiS_IF_DEF_LVDS == 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) ) {
+       SetAntiFlicker(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+       SetPhaseIncr(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+       SetYFilter(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+       if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+          SetEdgeEnhance(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+       }
    }
 }
 
+/* TW: New from 650/301LVx 1.10.6s - clashes with OEMLCD() */
+void
+SiS_FinalizeLCD(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+                USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT tempcl,tempch,tempbl,tempbh,tempbx,tempax,temp;
+  USHORT resinfo;
+
+  if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) return;
+
+  if(ModeNo<=0x13) {
+	resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+  } else {
+    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+        SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x2a,0x00);
+	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
+	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
+     }
+     tempch = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36);
+     tempch &= 0xf0;
+     tempch >>= 4;
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+	   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1f,0x76);
+	}
+     } else {
+        tempcl = tempbh = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x01);
+	tempcl &= 0x0f;
+	tempbh &= 0x70;
+	tempbh >>= 4;
+	tempbl = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x04);
+	tempbx = (tempbh << 8) | tempbl;
+	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+	   if((resinfo == 8) || (!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding))) {
+	      if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+	      	tempbx = 770;
+	      } else {
+	        if(tempbx > 770) tempbx = 770;
+		if(SiS_Pr->SiS_VGAVDE < 600) {                   /* Shouldn't that be <=? */
+		   tempax = 768 - SiS_Pr->SiS_VGAVDE;
+		   tempax >>= 3;
+		   if(SiS_Pr->SiS_VGAVDE < 480)  tempax >>= 1;   /* Shouldn't that be <=? */
+		   tempbx -= tempax;
+		}
+	      }
+	   } else return;
+	}
+#if 0
+	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+	}
+#endif
+	temp = tempbx & 0xff;
+	SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,temp);
+	temp = (tempbx & 0xff00) >> 8;
+	temp <<= 4;
+	temp |= tempcl;
+	SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,temp);
+     }
+  }
+}
+
+/* TW: New and checked from 650/301LV BIOS */
+/* This might clash with newer "FinalizeLCD()" function */
+void
+SiS_OEMLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                  UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+{
+   USHORT tempbx,tempah,tempbl,tempbh,tempcl;
+
+   if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) return;
+
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+      SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension,BaseAddr);
+      tempbh = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x1a);
+      tempbh &= 0x38;
+      tempbh >>= 3;
+      tempbl = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x18);
+      tempbx = (tempbh << 8) | tempbl;
+      if(SiS_Pr->SiS_LCDTypeInfo == 1)  tempbx -= 0x12;
+      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,tempbx & 0x00ff);
+      tempah = (tempbx & 0xff00) >> 8;
+      tempah &= 0x07;
+      tempah <<= 3;
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1a,0xc7,tempah);
+      tempah = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x19);
+      tempah &= 0x0f;
+      if(SiS_Pr->SiS_LCDTypeInfo == 1)  tempah -= 2;
+      tempah &= 0x0f;
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xF0,tempah);
+      tempah = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x14);
+      if(SiS_Pr->SiS_LCDTypeInfo == 1)  tempah++;
+      tempah -= 8;
+      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x14,tempah);
+   } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+      tempcl = tempbh = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x01);
+      tempbh &= 0x70;
+      tempbh >>= 4;
+      tempbl = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x04);
+      tempbx = (tempbh << 8) | tempbl;
+      if(SiS_Pr->SiS_LCDTypeInfo == 1)  {
+           tempbx -= 0x1e;
+	   tempcl &= 0x0f;
+	   tempcl -= 4;
+	   tempcl &= 0x0f;
+      }
+      tempbl = tempbx & 0x00ff;
+      tempbh = (tempbx >> 8) & 0x00ff;
+      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,tempbl);
+      tempbh <<= 4;
+      tempbh |= tempcl;
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,tempbh);
+   }
+}
 #endif
 
+
+/*  =================  SiS 300 O.E.M. ================== */
+
 #ifdef SIS300
-/*
-    for SIS300 O.E.M.
-*/
 
+#if 0   /* Not used */
 USHORT
-GetRevisionID(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+GetRevisionID(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-   ULONG temp1,base;
-   USHORT temp2=0; 
-   
+   ULONG temp1;
+#ifndef LINUX_XF86
+   ULONG base;
+#endif
+   USHORT temp2 = 0;
+
    if((HwDeviceExtension->jChipType==SIS_540)||
       (HwDeviceExtension->jChipType==SIS_630)||
       (HwDeviceExtension->jChipType==SIS_730)) {
-     	base=0x80000008;
+#ifndef LINUX_XF86
+     	base = 0x80000008;
      	OutPortLong(base,0xcf8);
-     	temp1=InPortLong(0xcfc);
-     	temp1=temp1&0x000000FF;
-     	temp2=(USHORT)(temp1);
+     	temp1 = InPortLong(0xcfc);
+#else
+	temp1=pciReadLong(0x00000000, 0x08);
+#endif
+     	temp1 &= 0x000000FF;
+     	temp2 = (USHORT)(temp1);
     	return temp2;
    }
    return 0;
 }
+#endif
 
+/* TW: Checked against 630/301B BIOS (incl data) */
 USHORT
-GetOEMTVPtr(void)
+GetOEMLCDPtr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, int Flag)
 {
-  USHORT index;
+  USHORT tempbx=0;
+  UCHAR customtable[] = {
+  	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+  };
 
-  index = 0;
-  if (!(SiS_VBInfo&SetInSlaveMode))
-      	index=index+4;
-  
-  if (SiS_VBInfo&SetCRT2ToSCART){
-      	index=index+2;
+  if(Flag) {
+      if(customtable[SiS_Pr->SiS_LCDTypeInfo] == 0xFF) return 0xFFFF;
+  }
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+        tempbx = SiS_Pr->SiS_LCDTypeInfo << 2;
+	if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempbx += 2;
+	if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx++;
   } else {
-     	if (SiS_VBInfo&SetCRT2ToHiVisionTV)
-       		index=index+3;
-     	else {
-          	if(SiS_VBInfo&SetPALTV)
-          		index=index+1;
-        }
+  	tempbx = SiS_Pr->SiS_LCDTypeInfo;
+	if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx += 16;
   }
-  return index;
+  return tempbx;
 }
 
-/* TW: This is not for LVDS/Chrontel */
+/* TW: Checked against 630/301B and 630/LVDS BIOS (incl data) */
 void
-SetOEMTVDelay(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-              ULONG ROMAddr,USHORT ModeNo)
-{
-  USHORT Part1Port;
-  USHORT index,temp,ModeIdIndex;
-
-  Part1Port=BaseAddr+SIS_CRT2_PORT_04;
-  ModeIdIndex=SiS_SearchVBModeID(ROMAddr,ModeNo);
-  temp = GetOEMTVPtr();
-  index = SiS_VBModeIDTable[ModeIdIndex].VB_TVDelayIndex;
-  temp = SiS300_OEMTVDelay[temp][index];
-  temp=temp&0x3c;
-  SiS_SetRegANDOR(Part1Port,0x13,~0x3C,temp);  /* index 0A D[6:4] */
-}
-
-USHORT
-GetOEMLCDPtr(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SetOEMLCDDelay(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+               UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  /* USHORT temp,tempax; */
-  USHORT tempbx=0;
+  USHORT index,temp;
 
-  if(SiS_IF_DEF_LVDS==0) {
+  /* TW: The Panel Compensation Delay should be set according to tables
+   *     here. Unfortunately, the different BIOS versions don't case about
+   *     a uniform way using eg. ROM byte 0x220, but use different
+   *     hard coded delays (0x04, 0x20, 0x18) in SetGroup1(). So we can't
+   *     rely on the other OEM bits in 0x237, 0x238 here either.
+   *     ROMAddr > 0x233 is even used for code (!) in newer BIOSes!
+   */
 #if 0
-  	tempax=tempbx=SiS_LCDResInfo;
-      	tempbx=tempbx-Panel1024x768;
-     	if(!(SiS_SetFlag&LCDVESATiming)) {
-        	tempbx+=4;
-        	temp=GetRevisionID(HwDeviceExtension);
-        	if((HwDeviceExtension->jChipType == SIS_540)&&(temp<1))
-        		tempbx+=4;
-        	if((HwDeviceExtension->jChipType == SIS_630)&&(temp<3))
-        		tempbx+=4;
-       	}
-     	if((tempax==Panel1024x768)&&(SiS_LCDInfo&LCDNonExpanding)){
-        	tempbx=tempbx+3;
-       	}
+  if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+     if(!(ROMAddr[0x237] & 0x01)) return;
+     if(!(ROMAddr[0x237] & 0x02)) return;
+  }
 #endif
+  /* TW: We just check if a non-standard delay has been set; if not,
+   * we use our tables. Otherwise don't do anything here.
+   */
+  if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+     if(ROMAddr[0x220] & 0x80) return;
+  }
+  /* TW: We don't need to set this if the user select a custom pdc */
+  if(HwDeviceExtension->pdc) return;
 
-	/* TW: This is total bullshit. First, we calculate tempbx, now
-	 *     we overwrite it?! (Therefore commented code above)
-	 */
+  temp = GetOEMLCDPtr(SiS_Pr,HwDeviceExtension, 0);
 
-     	/*add OEMLCDPanelIDSupport*/
-        tempbx=SiS_LCDTypeInfo;
+  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_LCDDelayIndex;
 
-#if 0   /* TW: Commented for DEBUG: */
-        tempbx=tempbx<<1;
-        if(!(SiS_SetFlag&LCDVESATiming))
-        	tempbx=tempbx+1;
-	tempbx*=2;
-	/* TW: The above code results in eg. 0xc * 2 * 2 = 48, but Delay2 table has
-	 *     only 32 entries. Thus, this can't work */
-#endif
-        /* TW: Don't think that 301(B) bridges need different LCD delay... */
-  	tempbx = SiS_LCDTypeInfo;
-	if(SiS_LCDInfo&LCDNonExpanding){
-      		tempbx=tempbx+16;
-	}
-  } else {  /* TW: Added LVDS code */
-  	tempbx = SiS_LCDTypeInfo;
-	if(SiS_LCDInfo&LCDNonExpanding){
-      		tempbx=tempbx+16;
-	}
+  if (SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+    	temp = SiS300_OEMLCDDelay2[temp][index];
+  } else {
+        temp = SiS300_OEMLCDDelay3[temp][index];
   }
-  return tempbx;
+  temp &= 0x3c;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp);  /* index 0A D[6:4] */
 }
 
-#if 0
-/* TW: Original code - can't work (eg. exceeds arrays by re-using temp,
-       writes to Part2(!)Port unlike TVDelay, etc...) */
-void
-SetOEMLCDDelay(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-               ULONG ROMAddr,USHORT ModeNo)
+/* TW: Checked against 630/301B 2.04.50 and 630/LVDS BIOS */
+USHORT
+GetOEMTVPtr(SiS_Private *SiS_Pr)
 {
-  USHORT Part2Port;
-  USHORT index,temp,ModeIdIndex;
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-  ModeIdIndex=SiS_SearchVBModeID(ROMAddr,ModeNo);
-  temp = GetOEMLCDPtr(HwDeviceExtension);
-  index = SiS_VBModeIDTable[ModeIdIndex].VB_LCDDelayIndex;
-  temp = SiS300_OEMLCDDelay1[temp][index];
-   /*add OEMLCDPanelIDSupport*/
-  temp = SiS300_OEMLCDDelay2[temp][index];
-  temp=temp&0x3c;
-  SiS_SetRegANDOR(Part2Port,0x13,~0x3C,temp);  /* index 0A D[6:4] */
+  USHORT index;
+
+  index = 0;
+  if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))  index += 4;
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART)  index += 2;
+     else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) index += 3;
+     else if(SiS_Pr->SiS_VBInfo & SetPALTV)   index += 1;
+  } else {
+     if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) index += 2;
+     if(SiS_Pr->SiS_VBInfo & SetPALTV)        index += 1;
+  }
+  return index;
 }
-#endif
 
-/* TW: Although I assume that the code above does not work correctly,
- *     I won't change it for non-LVDS machines until someone tells me so.
- */
+/* TW: Checked against 630/301B 2.04.50 and 630/LVDS BIOS (incl data) */
 void
-SetOEMLCDDelay(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-               ULONG ROMAddr,USHORT ModeNo)
+SetOEMTVDelay(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+              UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT Part1Port, Part2Port;
-  USHORT index,temp,ModeIdIndex;
-
-  Part1Port=BaseAddr+SIS_CRT2_PORT_04;
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
+  USHORT index,temp;
 
-  ModeIdIndex=SiS_SearchVBModeID(ROMAddr,ModeNo);
-  temp = GetOEMLCDPtr(HwDeviceExtension);
-  index = SiS_VBModeIDTable[ModeIdIndex].VB_LCDDelayIndex; /* TW: Always zero... */
-  if (SiS_IF_DEF_LVDS == 1) {
-  	/* TW: Added for LVDS: Assuming Part_1!!!_Port to be the correct one */
-    	temp = SiS300_OEMLCDDelay3[temp][index];
-	temp=temp&0x3c;
-  	SiS_SetRegANDOR(Part1Port,0x13,~0x3C,temp);  /* index 0A D[6:4] */
-  } else {
-        /* temp = SiS300_OEMLCDDelay1[temp][index];  */
-	/*  TW: This must be wrong: temp is eg. 48 and
-		thus exceeds array size of Delay2 table! */
-
-        /*add OEMLCDPanelIDSupport*/
-
-#if 0  /* TW: Commented for DEBUG */
-	temp = SiS300_OEMLCDDelay2[temp][index];
-	temp=temp&0x3c;
-  	SiS_SetRegANDOR(Part2Port,0x13,~0x3C,temp);  /* index 0A D[6:4] */
+#if 0  /* TW: Not used in newer BIOSes (2.04.5a) */
+  if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+     if(!(ROMAddr[0x238] & 0x01)) return;
+     if(!(ROMAddr[0x238] & 0x02)) return;
+  }
 #endif
+  temp = GetOEMTVPtr(SiS_Pr);
 
-        /* TW: 301B reported not working. Maybe because of the above bullshit? */
-	/*     Do it like for LVDS now. 0x13 seems to be the LCD delay anyway */
-        temp = SiS300_OEMLCDDelay3[temp][index];
-	temp=temp&0x3c;
-  	SiS_SetRegANDOR(Part1Port,0x13,~0x3C,temp);  /* index 0A D[6:4] */
+  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVDelayIndex;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+     temp = SiS300_OEMTVDelay301[temp][index];
+  } else {
+     temp = SiS300_OEMTVDelayLVDS[temp][index];
   }
+  temp &= 0x3c;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp);  /* index 0A D[6:4] */
 }
 
-/*
-*/
+/* TW: Checked against 630/301B 2.04.50 BIOS (incl data) */
 void
-SetOEMAntiFlicker(PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                  USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo)
+SetOEMAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                  USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+		  USHORT ModeIdIndex)
 {
-  USHORT Part2Port;
   USHORT index,temp;
-  USHORT ModeIdIndex;
 
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-  ModeIdIndex=SiS_SearchVBModeID(ROMAddr,ModeNo);
-  temp = GetOEMTVPtr();
-  index = SiS_VBModeIDTable[ModeIdIndex].VB_TVFlickerIndex;
+  temp = GetOEMTVPtr(SiS_Pr);
+
+  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVFlickerIndex;
+
   temp = SiS300_OEMTVFlicker[temp][index];
-  temp=temp&0x70;
-  SiS_SetRegANDOR(Part2Port,0x0A,~0x70,temp);  /* index 0A D[6:4] */
+  temp &= 0x70;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0A,0x8F,temp);  /* index 0A D[6:4] */
 }
 
+/* TW: Checked against 630/301B 2.04.50 BIOS (incl data) */
 void
-SetOEMPhaseIncr(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-                ULONG ROMAddr,USHORT ModeNo)
+SetOEMPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT Part2Port;
-  USHORT index,i,ModeIdIndex;
-
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-  /* temp = GetTVPtrIndex();*/
-  /* 0: NTSC Graphics, 1: NTSC Text, 2 :PAL Graphics, 3 :PAL Text, 4:HiTV Graphics 5:HiTV Text */
-  /* index = temp % 2;*/
-  /* temp >>= 1;   0: NTSC, 1 :PAL, 2:HiTV */
-  ModeIdIndex=SiS_SearchVBModeID(ROMAddr,ModeNo);
-  index = SiS_VBModeIDTable[ModeIdIndex].VB_TVPhaseIndex;
-  if (SiS_VBInfo&SetInSlaveMode){
-      if(SiS_VBInfo&SetPALTV){  
-         for(i=0x31;i<=0x34;i++)
-        	SiS_SetReg1(Part2Port,i,SiS300_StPALPhase[index][i-0x31]);
-      } else {
-          for(i=0x31;i<=0x34;i++)
-        	SiS_SetReg1(Part2Port,i,SiS300_StNTSCPhase[index][i-0x31]);
-      }
-      if(SiS_VBInfo&SetCRT2ToSCART){
-          for(i=0x31;i<=0x34;i++)
-        	SiS_SetReg1(Part2Port,i,SiS300_StSCARTPhase[index][i-0x31]);
-      }
-  } else {
-       if(SiS_VBInfo&SetPALTV){  
-          for(i=0x31;i<=0x34;i++)
-        	SiS_SetReg1(Part2Port,i,SiS300_ExtPALPhase[index][i-0x31]);
-       } else {
-          for(i=0x31;i<=0x34;i++)
-        	SiS_SetReg1(Part2Port,i,SiS300_ExtNTSCPhase[index][i-0x31]);
+  USHORT index,i,j,temp;
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) return;
+
+  temp = GetOEMTVPtr(SiS_Pr);
+
+  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVPhaseIndex;
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+       for(i=0x31, j=0; i<=0x34; i++, j++) {
+          SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS300_Phase2[temp][index][j]);
        }
-       if(SiS_VBInfo&SetCRT2ToSCART){
-          for(i=0x31;i<=0x34;i++)
-        	SiS_SetReg1(Part2Port,i,SiS300_ExtSCARTPhase[index][i-0x31]);
+  } else {
+       for(i=0x31, j=0; i<=0x34; i++, j++) {
+          SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS300_Phase1[temp][index][j]);
        }
   }
 }
 
+/* TW: Checked against 630/301B 2.04.50 BIOS (incl data) */
 void
-SetOEMYFilter(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-              ULONG ROMAddr,USHORT ModeNo)
+SetOEMYFilter(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+              UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT Part2Port;
-  USHORT index,temp1,temp2,i,ModeIdIndex,index1;
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-    /*301b*/
-  ModeIdIndex=SiS_SearchVBModeID(ROMAddr,ModeNo);
-  index = SiS_VBModeIDTable[ModeIdIndex].VB_TVYFilterIndex;
-  if (SiS_VBInfo&SetInSlaveMode){
-      if(SiS_VBInfo&SetPALTV){  
-        	for(i=0x35;i<=0x38;i++)
-        		SiS_SetReg1(Part2Port,i,SiS300_StPALFilter[index][i-0x35]);
-      } else {
-         	 for(i=0x35;i<=0x38;i++)
-        		SiS_SetReg1(Part2Port,i,SiS300_StNTSCFilter[index][i-0x35]);
-      }
-  } else{
-      if(SiS_VBInfo&SetPALTV) {
-         for(i=0x35;i<=0x38;i++)
-        	SiS_SetReg1(Part2Port,i,SiS300_ExtPALFilter[index][i-0x35]);
-      } else{
-          for(i=0x35;i<=0x38;i++)
-        	SiS_SetReg1(Part2Port,i,SiS300_ExtNTSCFilter[index][i-0x35]);
-      }
-  }
+  USHORT index,temp,temp1,i,j;
 
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-    if(SiS_VBInfo&SetPALTV){  
-    	for(i=0x35;i<=0x38;i++)
-    	{
-     		SiS_SetReg1(Part2Port,i,SiS300_PALFilter2[index][i-0x35]);
-    	}
-   	for(i=0x48;i<=0x4A;i++)
-    	{
-     		SiS_SetReg1(Part2Port,i,SiS300_PALFilter2[index][(i-0x48)+0x04]);
-    	}
-    } else {
-  	for(i=0x35;i<=0x38;i++)
-    	{
-     		SiS_SetReg1(Part2Port,i,SiS300_NTSCFilter2[index][i-0x35]);
-     	}
-   	for(i=0x48;i<=0x4A;i++)
-    	{
-     		SiS_SetReg1(Part2Port,i,SiS300_NTSCFilter2[index][(i-0x48)+0x04]);
-    	}
-    }
-  }
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSCART | SetCRT2ToHiVisionTV)) return;
 
-/*add PALMN*/
-  if((HwDeviceExtension->jChipType==SIS_630)||
-     (HwDeviceExtension->jChipType==SIS_730)) {
-      index1=SiS_GetReg1(SiS_P3d4,0x31);
-      temp1=index1&0x01;
-      index1=SiS_GetReg1(SiS_P3d4,0x35);
-      temp2=index1&0xC0;
-      if(temp1){
-         if(temp2==0x40){
-              if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-                 for(i=0x35;i<=0x38;i++){
-                      SiS_SetReg1(Part2Port,i,SiS300_PALMFilter2[index][i-0x35]);
-                 }
-                 for(i=0x48;i<=0x4A;i++) {
-                       SiS_SetReg1(Part2Port,i,SiS300_PALMFilter2[index][(i-0x48)+0x04]);
-                 }
-              } else {
-                 for(i=0x35;i<=0x38;i++)
-                 	SiS_SetReg1(Part2Port,i,SiS300_PALMFilter[index][i-0x35]);
-              }
-         }
-         if(temp2==0x80){ 
-              if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-                 for(i=0x35;i<=0x38;i++){
-                      SiS_SetReg1(Part2Port,i,SiS300_PALNFilter2[index][i-0x35]);
-                 }
-                 for(i=0x48;i<=0x4A;i++) {
-                       SiS_SetReg1(Part2Port,i,SiS300_PALNFilter2[index][(i-0x48)+0x04]);
-                 }
-             } else {
-                 for(i=0x35;i<=0x38;i++)
-                 	SiS_SetReg1(Part2Port,i,SiS300_PALNFilter[index][i-0x35]);
-             }
-          }
+  temp = GetOEMTVPtr(SiS_Pr);
+
+  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVYFilterIndex;
+
+  if(HwDeviceExtension->jChipType > SIS_300) {
+     if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x01) {
+       temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x35);
+       if(temp1 & (EnablePALMN | EnablePALN)) {
+          temp = 8;
+	  if(temp1 & EnablePALN) temp = 9;
+       }
+     }
+  }
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      for(i=0x35, j=0; i<=0x38; i++, j++) {
+       	SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS300_Filter2[temp][index][j]);
       }
-   }
-  /*end PALMN*/
+      for(i=0x48; i<=0x4A; i++, j++) {
+     	SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS300_Filter2[temp][index][j]);
+      }
+  } else {
+      for(i=0x35, j=0; i<=0x38; i++, j++) {
+       	SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS300_Filter1[temp][index][j]);
+      }
+  }
 }
 
 void
-SiS_OEM300Setting(PSIS_HW_DEVICE_INFO HwDeviceExtension,
-		  USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo)
+SiS_OEM300Setting(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+		  USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo)
 {
-  if (SiS_VBInfo & SetCRT2ToLCD) {
-       SetOEMLCDDelay(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
-  }
-  if (SiS_VBInfo & SetCRT2ToTV) {
-       /* TW: (Added LVDS check) - done this way now because LVDS
-        * seems to be 1 for some of the SiS bridges as well
-	*/
-       if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-       						|| (SiS_IF_DEF_LVDS==0))  {
-	        SetOEMTVDelay(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
-       		SetOEMAntiFlicker(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
-    		/* SetOEMPhaseIncr(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);*/
-       		SetOEMYFilter(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
+  USHORT ModeIdIndex;
+
+  ModeIdIndex = SiS_SearchVBModeID(SiS_Pr,ROMAddr,&ModeNo);
+  if(!(ModeIdIndex)) return;
+
+  if (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+       SetOEMLCDDelay(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+  }
+  if (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+       SetOEMTVDelay(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+       if(SiS_Pr->SiS_IF_DEF_LVDS==0) {
+       		SetOEMAntiFlicker(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+    		SetOEMPhaseIncr(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+       		SetOEMYFilter(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
        }
-    }
+  }
 }
 #endif
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/init301.h linux-2.4.20/drivers/video/sis/init301.h
--- linux-2.4.19/drivers/video/sis/init301.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/init301.h	2002-10-29 11:18:40.000000000 +0000
@@ -17,6 +17,7 @@
 
 #ifdef LINUX_XF86
 #include "xf86.h"
+#include "xf86Pci.h"
 #include "xf86PciInfo.h"
 #include "sis.h"
 #include "sis_regs.h"
@@ -35,202 +36,267 @@
 #include "dderror.h"
 #include "devioctl.h"
 #include "miniport.h"
-
 #include "ntddvdeo.h"
 #include "video.h"
 #include "sisv.h"
 #endif
 
-USHORT   SiS_SetFlag;
-USHORT   SiS_RVBHCFACT,SiS_RVBHCMAX,SiS_RVBHRS;
-USHORT   SiS_VGAVT,SiS_VGAHT;
-USHORT   SiS_VT,SiS_HT;
-USHORT   SiS_VGAVDE,SiS_VGAHDE;
-USHORT   SiS_VDE,SiS_HDE;
-USHORT   SiS_NewFlickerMode,SiS_RY1COE,SiS_RY2COE,SiS_RY3COE,SiS_RY4COE;
-USHORT   SiS_LCDHDES,SiS_LCDVDES;
-USHORT   SiS_DDC_Port;
-USHORT   SiS_DDC_Index;
-USHORT   SiS_DDC_DataShift;
-USHORT   SiS_DDC_DeviceAddr;
-USHORT   SiS_DDC_Flag;
-USHORT   SiS_DDC_ReadAddr;
-USHORT   SiS_DDC_Buffer;
-
-extern   USHORT   SiS_CRT1Mode;
-extern   USHORT   SiS_P3c4,SiS_P3d4;
-/*extern   USHORT      SiS_P3c0,SiS_P3ce,SiS_P3c2;*/
-extern   USHORT   SiS_P3ca;
-/*extern   USHORT      SiS_P3c6,SiS_P3c7,SiS_P3c8;*/
-extern   USHORT   SiS_P3c9;
-extern   USHORT   SiS_P3da;
-extern   USHORT   SiS_Part1Port,SiS_Part2Port;
-extern   USHORT   SiS_Part3Port,SiS_Part4Port,SiS_Part5Port;
-extern   USHORT   SiS_MDA_DAC[];
-extern   USHORT   SiS_CGA_DAC[];
-extern   USHORT   SiS_EGA_DAC[];
-extern   USHORT   SiS_VGA_DAC[];
-extern   USHORT   SiS_ModeType;
-extern   USHORT   SiS_SelectCRT2Rate;
-extern   USHORT   SiS_IF_DEF_LVDS;
-extern   USHORT   SiS_IF_DEF_TRUMPION;
-extern   USHORT   SiS_IF_DEF_CH7005;
-extern   USHORT   SiS_Backup7005;
-extern   USHORT   SiS_IF_DEF_HiVision;
-extern   USHORT   SiS_IF_DEF_DSTN;   /*add for dstn*/
-extern   USHORT   SiS_IF_DEF_FSTN;   /*add for fstn*/
-extern   USHORT   SiS_VBInfo;
-extern   USHORT   SiS_VBType;        /*301b*/
-extern   USHORT   SiS_VBExtInfo; /*301lv*/
-extern   USHORT   SiS_LCDResInfo;
-extern   USHORT   SiS_LCDTypeInfo;
-extern   USHORT   SiS_LCDInfo;
-extern   BOOLEAN  SiS_SearchVBModeID(ULONG, USHORT);
-extern   BOOLEAN  SiS_Is301B(USHORT BaseAddr);/*301b*/
-extern   BOOLEAN  SiS_IsDisableCRT2(USHORT BaseAddr);
-extern   BOOLEAN  SiS_IsVAMode(USHORT BaseAddr);
-extern   BOOLEAN  SiS_IsDualEdge(USHORT BaseAddr);
-/*end 301b*/
-
-void     SiS_SetDefCRT2ExtRegs(USHORT BaseAddr);
-USHORT   SiS_GetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo,USHORT ModeIdIndex);
-BOOLEAN  SiS_AdjustCRT2Rate(ULONG ROMAddr,USHORT ModeNo,USHORT MODEIdIndex,USHORT RefreshRateTableIndex,USHORT *i);
-void     SiS_SaveCRT2Info(USHORT ModeNo);
-void     SiS_GetCRT2Data(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-void     SiS_GetCRT2DataLVDS(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-void     SiS_GetCRT2PtrA(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, USHORT *CRT2Index,USHORT *ResIndex);/*301b*/
-void     SiS_GetCRT2Data301(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-USHORT   SiS_GetResInfo(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_GetCRT2ResInfo(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_GetRAMDAC2DATA(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-void     SiS_GetCRT2Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,
-		USHORT *CRT2Index,USHORT *ResIndex);
-void     SiS_SetCRT2ModeRegs(USHORT BaseAddr,USHORT ModeNo,PSIS_HW_DEVICE_INFO );
-
-
-void     SiS_GetLVDSDesData(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-void     SiS_SetCRT2Offset(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-USHORT   SiS_GetOffset(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-USHORT   SiS_GetColorDepth(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-USHORT   SiS_GetVCLK(ULONG ROMAddr,USHORT ModeNo);
-USHORT   SiS_GetVCLKPtr(ULONG ROMAddr,USHORT ModeNo);
-USHORT   SiS_GetColorTh(ULONG ROMAddr);
-USHORT   SiS_GetMCLK(ULONG ROMAddr);
-USHORT   SiS_GetMCLKPtr(ULONG ROMAddr);
-USHORT   SiS_GetDRAMType(ULONG ROMAddr);
-USHORT   SiS_CalcDelayVB(void);
-extern USHORT   SiS_GetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetCRT2Sync(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT RefreshRateTableIndex);
+#if 0
+extern   const USHORT   SiS_MDA_DAC[];
+extern   const USHORT   SiS_CGA_DAC[];
+extern   const USHORT   SiS_EGA_DAC[];
+extern   const USHORT   SiS_VGA_DAC[];
+#endif
+
+extern   BOOLEAN  SiS_SearchVBModeID(SiS_Private *SiS_Pr, UCHAR *RomAddr, USHORT *);
+
+BOOLEAN  SiS_Is301B(SiS_Private *SiS_Pr, USHORT BaseAddr);
+BOOLEAN  SiS_IsM650or651(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+BOOLEAN  SiS_IsDisableCRT2(SiS_Private *SiS_Pr, USHORT BaseAddr);
+BOOLEAN  SiS_IsVAMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+BOOLEAN  SiS_IsDualEdge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+BOOLEAN  SiS_CRT2IsLCD(SiS_Private *SiS_Pr, USHORT BaseAddr);
+void     SiS_SetDefCRT2ExtRegs(SiS_Private *SiS_Pr, USHORT BaseAddr);
+USHORT   SiS_GetRatePtrCRT2(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex,
+                            PSIS_HW_DEVICE_INFO HwDeviceExtension);
+BOOLEAN  SiS_AdjustCRT2Rate(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT MODEIdIndex,
+                            USHORT RefreshRateTableIndex,USHORT *i,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SaveCRT2Info(SiS_Private *SiS_Pr, USHORT ModeNo);
+void     SiS_GetCRT2Data(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+		         USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_GetCRT2DataLVDS(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                             USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_GetCRT2PtrA(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                         USHORT RefreshRateTableIndex,USHORT *CRT2Index,USHORT *ResIndex);
+void     SiS_GetCRT2Part2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+		             USHORT RefreshRateTableIndex,USHORT *CRT2Index, USHORT *ResIndex);
+void     SiS_GetCRT2Data301(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                            USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+USHORT   SiS_GetResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void     SiS_GetCRT2ResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                            PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_GetRAMDAC2DATA(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                            USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_GetCRT2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                        USHORT RefreshRateTableIndex,USHORT *CRT2Index,USHORT *ResIndex,
+			PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT BaseAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                             PSIS_HW_DEVICE_INFO );
+void     SiS_SetHiVision(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_GetLVDSDesData(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+			    USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetCRT2Offset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                           USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+USHORT   SiS_GetOffset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                       USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+USHORT   SiS_GetColorDepth(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+USHORT   SiS_GetMCLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+USHORT   SiS_CalcDelayVB(SiS_Private *SiS_Pr);
+USHORT   SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                         USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetCRT2Sync(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+                         USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
 void     SiS_SetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR);
 void     SiS_SetRegOR(USHORT Port,USHORT Index,USHORT DataOR);
 void     SiS_SetRegAND(USHORT Port,USHORT Index,USHORT DataAND);
-USHORT   SiS_GetVGAHT2(void);
-void     SiS_SetGroup2(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetGroup3(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetGroup4(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetGroup5(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_SetCRT2VCLK(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_EnableCRT2(void);
-void     SiS_LoadDAC2(ULONG ROMAddr,USHORT Part5Port,USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_WriteDAC2(USHORT Pdata,USHORT dl, USHORT ah, USHORT al, USHORT dh);
-void     SiS_GetVBInfo301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-BOOLEAN  SiS_GetLCDResInfo(ULONG ROMAddr,USHORT P3d4,USHORT ModeNo,USHORT ModeIdIndex);
-BOOLEAN  SiS_BridgeIsOn(USHORT BaseAddr);
-BOOLEAN  SiS_BridgeIsEnable(USHORT BaseAddr,PSIS_HW_DEVICE_INFO );
-BOOLEAN  SiS_BridgeInSlave(void);
-/*void     SiS_PresetScratchregister(USHORT P3d4);*/
-void     SiS_PresetScratchregister(USHORT SiS_P3d4,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetTVSystem(VOID);
-void     SiS_LongWait(VOID);
-USHORT   SiS_GetQueueConfig(VOID);
-void     SiS_VBLongWait(VOID);
-USHORT   SiS_GetVCLKLen(ULONG ROMAddr);
-BOOLEAN  SiS_WaitVBRetrace(USHORT  BaseAddr);
-void     SiS_SetCRT2ECLK(ULONG ROMAddr, USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_GetLVDSDesPtr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,USHORT *PanelIndex,USHORT *ResIndex);
-void     SiS_GetLVDSDesPtrA(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,USHORT *PanelIndex,USHORT *ResIndex);/*301b*/
-void     SiS_SetTPData(VOID);
-void     SiS_ModCRT1CRTC(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-extern BOOLEAN  SiS_GetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,
-		       USHORT *ResInfo,USHORT *DisplayType);
-void     SiS_SetCHTVReg(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-void     SiS_SetCHTVRegANDOR(USHORT tempax,USHORT tempbh);
-void     SiS_GetCHTVRegPtr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-void     SiS_SetCH7005(USHORT tempax);
-USHORT   SiS_GetCH7005(USHORT tempax);
-void     SiS_SetSwitchDDC2(void);
-void     SiS_SetStart(void);
-void     SiS_SetStop(void);
-void     SiS_DDC2Delay(void);
-void     SiS_SetSCLKLow(void);
-void     SiS_SetSCLKHigh(void);
-USHORT   SiS_ReadDDC2Data(USHORT tempax);
-USHORT   SiS_WriteDDC2Data(USHORT tempax);
-USHORT   SiS_CheckACK(void);
-void     SiS_OEM310Setting(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_OEM300Setting(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo);
-USHORT GetRevisionID(PSIS_HW_DEVICE_INFO HwDeviceExtension);
-
-BOOLEAN SiS_GetLCDResInfo301(ULONG ROMAddr,USHORT SiS_P3d4, USHORT ModeNo,USHORT ModeIdIndex);
-void    SiS_CHACRT1CRTC(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+USHORT   SiS_GetVGAHT2(SiS_Private *SiS_Pr);
+void     SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                       USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetGroup3(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                       PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                       USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetGroup5(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+                       USHORT ModeIdIndex);
+void     SiS_FinalizeLCD(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                         PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetCRT2VCLK(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                         USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_EnableCRT2(SiS_Private *SiS_Pr);
+void     SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                       PSIS_HW_DEVICE_INFO HwDeviceExtension);
+BOOLEAN  SiS_BridgeIsOn(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO);
+BOOLEAN  SiS_BridgeIsEnable(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO);
+BOOLEAN  SiS_BridgeInSlave(SiS_Private *SiS_Pr);
+void     SiS_PresetScratchregister(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetTVSystem(SiS_Private *SiS_Pr);
+void     SiS_LongWait(SiS_Private *SiS_Pr);
+USHORT   SiS_GetQueueConfig(SiS_Private *SiS_Pr);
+void     SiS_VBLongWait(SiS_Private *SiS_Pr);
+USHORT   SiS_GetVCLKLen(SiS_Private *SiS_Pr, UCHAR *ROMAddr);
+void     SiS_WaitVBRetrace(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_WaitRetrace1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_WaitRetrace2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_WaitRetraceDDC(SiS_Private *SiS_Pr);
+void     SiS_SetCRT2ECLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex,
+                         USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_GetLVDSDesPtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                           USHORT RefreshRateTableIndex,USHORT *PanelIndex,USHORT *ResIndex,
+			   PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_GetLVDSDesPtrA(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                            USHORT RefreshRateTableIndex,USHORT *PanelIndex,USHORT *ResIndex);
+void     SiS_SetTPData(SiS_Private *SiS_Pr);
+void     SiS_ModCRT1CRTC(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                         USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetCHTVReg(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                         USHORT RefreshRateTableIndex);
-BOOLEAN SiS_GetLCDACRT1Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-		   USHORT RefreshRateTableIndex,USHORT *ResInfo,
-		   USHORT *DisplayType);
-USHORT  GetTVPtrIndex(void);
-USHORT 	GetLCDPtrIndex (void);
-void    SetDelayComp(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-             	ULONG ROMAddr,USHORT ModeNo);
-void    SetAntiFlicker(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-               	ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-void    SetEdgeEnhance (PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-                ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-void    SetYFilter(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-           	ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-void	SetPhaseIncr(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-             	ULONG ROMAddr,USHORT ModeNo);
-USHORT 	GetOEMLCDPtr(PSIS_HW_DEVICE_INFO HwDeviceExtension);
-USHORT 	GetOEMTVPtr(void);
-void	SetOEMTVDelay(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-              	ULONG ROMAddr,USHORT ModeNo);
-void	SetOEMLCDDelay(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-               	ULONG ROMAddr,USHORT ModeNo);
-void	SetOEMAntiFlicker(PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo);
-void  	SetOEMPhaseIncr(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-                ULONG ROMAddr,USHORT ModeNo);
-void	SetOEMYFilter(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-              	ULONG ROMAddr,USHORT ModeNo);
+void     SiS_GetCHTVRegPtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                           USHORT RefreshRateTableIndex);
+void     SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempax);
+USHORT   SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempax);
+void     SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempax);
+USHORT   SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempax);
+void     SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempax);
+USHORT   SiS_GetCH70xx(SiS_Private *SiS_Pr, USHORT tempax);
+#ifdef LINUX_XF86
+USHORT   SiS_I2C_GetByte(SiS_Private *SiS_Pr);
+Bool     SiS_I2C_PutByte(SiS_Private *SiS_Pr, USHORT data);
+Bool     SiS_I2C_Address(SiS_Private *SiS_Pr, USHORT addr);
+void     SiS_I2C_Stop(SiS_Private *SiS_Pr);
+#endif
+void     SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh);
+void     SiS_SetSwitchDDC2(SiS_Private *SiS_Pr);
+USHORT   SiS_SetStart(SiS_Private *SiS_Pr);
+USHORT   SiS_SetStop(SiS_Private *SiS_Pr);
+void     SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime);
+USHORT   SiS_SetSCLKLow(SiS_Private *SiS_Pr);
+USHORT   SiS_SetSCLKHigh(SiS_Private *SiS_Pr);
+USHORT   SiS_ReadDDC2Data(SiS_Private *SiS_Pr, USHORT tempax);
+USHORT   SiS_WriteDDC2Data(SiS_Private *SiS_Pr, USHORT tempax);
+USHORT   SiS_CheckACK(SiS_Private *SiS_Pr);
+#ifdef SIS315H
+void     SiS_OEM310Setting(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                           UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void     SiS_OEMLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                    UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+USHORT 	 GetLCDPtrIndex(SiS_Private *SiS_Pr);
+USHORT   GetTVPtrIndex(SiS_Private *SiS_Pr);
+void     SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+             	     UCHAR *ROMAddr,USHORT ModeNo);
+void     SetAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+               	       UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void     SetEdgeEnhance(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                       UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void     SetYFilter(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+           	   UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void	 SetPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+             	     UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+#endif
+#ifdef SIS300
+void     SiS_OEM300Setting(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                           UCHAR *ROMAddr,USHORT ModeNo);
+USHORT 	 GetOEMLCDPtr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, int Flag);
+USHORT 	 GetOEMTVPtr(SiS_Private *SiS_Pr);
+void	 SetOEMTVDelay(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+              	      UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void	 SetOEMLCDDelay(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+               	       UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void	 SetOEMAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                          USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void  	 SetOEMPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                         UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void	 SetOEMYFilter(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+               	       UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+#endif
+USHORT   GetRevisionID(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+BOOLEAN  SiS_LowModeStuff(SiS_Private *SiS_Pr, USHORT ModeNo,PSIS_HW_DEVICE_INFO HwDeviceExtension);
 
+BOOLEAN  SiS_GetLCDResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo, USHORT ModeIdIndex,
+                           PSIS_HW_DEVICE_INFO HwDeviceExtension);
+/* void    SiS_CHACRT1CRTC(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                        USHORT RefreshRateTableIndex); */
+
+BOOLEAN  SiS_SetCRT2Group301(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+                             PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                       PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);
+void     SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                            PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);
+void     SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                            PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);
+void     SiS_SetGroup1_301(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                           PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);
+#ifdef SIS300
+void     SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
+                             PSIS_HW_DEVICE_INFO HwDeviceExtension);
+#endif
+#ifdef SIS315H
+void     SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
+                             PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_CRT2AutoThreshold(SiS_Private *SiS_Pr, USHORT  BaseAddr);
+#endif
+BOOLEAN  SiS_GetLCDDDCInfo(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO,USHORT BaseAddr);
+void     SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO,USHORT BaseAddr);
+void     SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO,USHORT  BaseAddr);
+void     SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO,USHORT BaseAddr);
+void     SiS_SetPanelDelay(SiS_Private *SiS_Pr, UCHAR* ROMAddr,PSIS_HW_DEVICE_INFO,USHORT DelayTime);
+void     SiS_ShortDelay(SiS_Private *SiS_Pr, USHORT delay);
+void     SiS_LongDelay(SiS_Private *SiS_Pr, USHORT delay);
+void     SiS_GenericDelay(SiS_Private *SiS_Pr, USHORT delay);
+void     SiS_VBWait(SiS_Private *SiS_Pr);
+
+void     SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+
+/* TW: New functions (with mostly temporary names) */
+void     SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr);
+void     SiS_Chrontel701xOn(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                            USHORT BaseAddr);
+void     SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr);
+void     SiS_Chrontel701xOff(SiS_Private *SiS_Pr);
+void     SiS_ChrontelResetDB(SiS_Private *SiS_Pr);
+void     SiS_ChrontelDoSomething4(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+void     SiS_ChrontelDoSomething3(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+void     SiS_ChrontelDoSomething2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+void     SiS_ChrontelDoSomething1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+BOOLEAN  SiS_WeHaveBacklightCtrl(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+#if 0
+BOOLEAN  SiS_IsSomethingCR5F(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+#endif
+BOOLEAN  SiS_IsYPbPr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+BOOLEAN  SiS_IsTVOrYPbPr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+BOOLEAN  SiS_IsLCDOrLCDA(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+void     SiS_SetCH701xForLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+void     SiS_Chrontel19f2(SiS_Private *SiS_Pr);
+BOOLEAN  SiS_CR36BIOSWord23b(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+BOOLEAN  SiS_CR36BIOSWord23d(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+BOOLEAN  SiS_IsSR13_CR30(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+/* TW end */
 
 extern   void     SiS_SetReg1(USHORT, USHORT, USHORT);
 extern   void     SiS_SetReg3(USHORT, USHORT);
 extern   UCHAR    SiS_GetReg1(USHORT, USHORT);
 extern   UCHAR    SiS_GetReg2(USHORT);
-extern   BOOLEAN  SiS_SearchModeID(ULONG ROMAddr, USHORT ModeNo,USHORT  *ModeIdIndex);
-extern   BOOLEAN  SiS_GetRatePtr(ULONG, USHORT);
+extern   BOOLEAN  SiS_SearchModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT *ModeNo,USHORT *ModeIdIndex);
+extern   BOOLEAN  SiS_GetRatePtr(SiS_Private *SiS_Pr, ULONG, USHORT);
 extern   void     SiS_SetReg4(USHORT, ULONG);
 extern   ULONG    SiS_GetReg3(USHORT);
-extern   void     SiS_DisplayOff(void);
-extern   void     SiS_CRT2AutoThreshold(USHORT  BaseAddr);
-extern   void     SiS_DisplayOn(void);
-extern   UCHAR    SiS_GetModePtr(ULONG ROMAddr, USHORT ModeNo,USHORT ModeIdIndex);
-extern   UCHAR    SiS_Get310DRAMType(ULONG   ROMAddr);
-
-
-BOOLEAN  SiS_SetCRT2Group301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetGroup1(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);
-void     SiS_SetGroup1_LVDS(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);
-void     SiS_SetGroup1_LCDA(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);/*301b*/
-void     SiS_SetGroup1_301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);
-void     SiS_SetCRT2FIFO(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo, PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetCRT2FIFO2(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo, PSIS_HW_DEVICE_INFO HwDeviceExtension);
-BOOLEAN  SiS_GetLCDDDCInfo(PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_UnLockCRT2(PSIS_HW_DEVICE_INFO,USHORT BaseAddr);
-void     SiS_LockCRT2(PSIS_HW_DEVICE_INFO,USHORT BaseAddr);
-void     SiS_DisableBridge(PSIS_HW_DEVICE_INFO,USHORT  BaseAddr);
-void     SiS_EnableBridge(PSIS_HW_DEVICE_INFO,USHORT BaseAddr);
-void     SiS_SetPanelDelay(USHORT DelayTime);
-void     SiS_LCD_Wait_Time(UCHAR DelayTime);
+extern   void     SiS_DisplayOff(SiS_Private *SiS_Pr);
+extern   void     SiS_DisplayOn(SiS_Private *SiS_Pr);
+extern   UCHAR    SiS_GetModePtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex);
+extern   BOOLEAN  SiS_GetLCDACRT1Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+		                     USHORT RefreshRateTableIndex,USHORT *ResInfo,USHORT *DisplayType);
+extern   BOOLEAN  SiS_GetLVDSCRT1Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                                     USHORT RefreshRateTableIndex,USHORT *ResInfo,USHORT *DisplayType);
+extern   void     SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO, UCHAR *ROMAddr,USHORT ModeNo,
+                              USHORT ModeIdIndex);
+#ifdef SIS315H
+extern   UCHAR    SiS_Get310DRAMType(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+#endif
+
+#ifdef LINUX_XF86
+/* DDC functions */
+USHORT   SiS_InitDDCRegs(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT adaptnum, USHORT DDCdatatype);
+USHORT   SiS_WriteDABDDC(SiS_Private *SiS_Pr);
+USHORT   SiS_PrepareReadDDC(SiS_Private *SiS_Pr);
+USHORT   SiS_PrepareDDC(SiS_Private *SiS_Pr);
+void     SiS_SendACK(SiS_Private *SiS_Pr, USHORT yesno);
+USHORT   SiS_DoProbeDDC(SiS_Private *SiS_Pr);
+USHORT   SiS_ProbeDDC(SiS_Private *SiS_Pr);
+USHORT   SiS_ReadDDC(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT DDCdatatype, unsigned char *buffer);
+USHORT   SiS_HandleDDC(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT adaptnum,
+                       USHORT DDCdatatype, unsigned char *buffer);
+#endif
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/initdef.h linux-2.4.20/drivers/video/sis/initdef.h
--- linux-2.4.19/drivers/video/sis/initdef.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/initdef.h	2002-10-29 11:18:48.000000000 +0000
@@ -1,6 +1,5 @@
 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/initdef.h,v 1.4 2000/12/02 01:16:17 dawes Exp $ */
 
-/* Comments and changes marked with "TW" by Thomas Winischhofer <thomas@winischhofer.net> */
 
 #ifndef _INITDEF_
 #define _INITDEF_
@@ -10,22 +9,20 @@
 #define SiS630                  0x6300
 #define SiS730                  0x6300
 
-/*301b*/
-/* VBType */
+/* SiS_VBType */
 #define VB_SIS301	      	0x0001
 #define VB_SIS301B        	0x0002
 #define VB_SIS302B        	0x0004
-#define VB_SIS301LV     	0x0008 /*301lv*/
-#define VB_SIS302LV     	0x0010
+#define VB_SIS30xLV     	0x0008
+#define VB_SIS30xNEW     	0x0010
 #define VB_NoLCD        	0x8000
-/*end 301b*/
+#define VB_SIS301BLV302BLV      (VB_SIS301B|VB_SIS302B|VB_SIS30xLV|VB_SIS30xNEW)
 
 #define CRT1Len                 17
 #define LVDSCRT1Len             15
 #define CHTVRegDataLen          5
 
-#define ModeInfoFlag            0x07
-#define IsTextMode              0x07
+/* SiS_ModeType */
 #define ModeText                0x00
 #define ModeCGA                 0x01
 #define ModeEGA                 0x02
@@ -35,10 +32,14 @@
 #define Mode24Bpp               0x06
 #define Mode32Bpp               0x07
 
+#define ModeInfoFlag            0x07
+#define IsTextMode              0x07
+
 #define DACInfoFlag             0x18
 #define MemoryInfoFlag          0x1E0
 #define MemorySizeShift         0x05
 
+/* modeflag */
 #define Charx8Dot               0x0200
 #define LineCompareOff          0x0400
 #define CRT2Mode                0x0800
@@ -69,7 +70,7 @@
 #define ECLKindex4              0x0400
 
 /* VBInfo */
-#define SetSimuScanMode         0x0001
+#define SetSimuScanMode         0x0001   /* CR 30 */
 #define SwitchToCRT2            0x0002
 #define SetCRT2ToTV             0x009C
 #define SetCRT2ToAVIDEO         0x0004
@@ -78,30 +79,93 @@
 #define SetCRT2ToLCD            0x0020
 #define SetCRT2ToRAMDAC         0x0040
 #define SetCRT2ToHiVisionTV     0x0080
-#define SetNTSCTV               0x0000
+#define SetNTSCTV               0x0000   /* CR 31 */
 #define SetPALTV                0x0100
 #define SetInSlaveMode          0x0200
 #define SetNotSimuMode          0x0400
 #define SetNotSimuTVMode        0x0400
 #define SetDispDevSwitch        0x0800
 #define LoadDACFlag             0x1000
+#define SetCHTVOverScan  	0x1000  /* TW: Re-defined (from 0x8000) */
 #define DisableCRT2Display      0x2000
+#define CRT2DisplayFlag         0x2000
 #define DriverMode              0x4000
-#define HotKeySwitch            0x8000
-#define SetCHTVOverScan  	0x8000
-#define SetCRT2ToLCDA           0x8000/*301b*/
+#define HotKeySwitch            0x8000  /* TW: ? */
+#define SetCRT2ToLCDA           0x8000
+
 #define PanelRGB18Bit           0x0100
 #define PanelRGB24Bit           0x0000
 
-#define TVOverScan              0x10
+#define TVOverScan              0x10    /* Bit in CR35 (300 series only) */
 #define TVOverScanShift         4
 #define ClearBufferFlag         0x20
-#define EnableDualEdge 		0x01		/*301b*/	
-#define SetToLCDA		0x02
+
+/* CR32 (Newer 630, and 310/325 series)
+
+   [0]   VB connected with CVBS
+   [1]   VB connected with SVHS
+   [2]   VB connected with SCART
+   [3]   VB connected with LCD
+   [4]   VB connected with CRT2 (secondary VGA)
+   [5]   CRT1 monitor is connected
+   [6]   VB connected with Hi-Vision TV
+   [7]   VB connected with DVI combo connector
+
+
+   CR37
+
+   [0]   Set 24/18 bit (0/1) RGB to LVDS/TMDS transmitter (set by BIOS)
+   [3:1] External chip
+         300 series:
+	    001   SiS301 (never seen)
+	    010   LVDS
+	    011   LVDS + Tumpion Zurac
+	    100   LVDS + Chrontel 7005
+	    110   Chrontel 7005
+	  310/325 series
+	    001   SiS30x (never seen)
+	    010   LVDS
+	    011   LVDS + Chrontel 7019
+	  All other combinations reserved
+   [4]    LVDS: Expanding(0)/Non-expanding(1) LCD display
+          30x:  SiS30x(0)/LCD monitor(1) scaling display
+   [5]    LCD polarity select
+          0: VESA DMT Standard
+	  1: EDID 2.x defined
+   [6]    LCD horizontal polarity select
+          0: High active
+	  1: Low active
+   [7]    LCD vertical polarity select
+          0: High active
+	  1: Low active
+*/
+
+#define EnableDualEdge 		0x01   /* CR38 (310/325 series) */
+/* #define PAL_NTSC             0x01      (only on 315PRO) */
+#define SetToLCDA		0x02   /* TW: LCD channel A (302B and 650+LVDS only) */
+#define EnableLVDSHiVision      0x08   /* TW: Only on 650/LVDS systems */
+#define SetYPbPr                0x10   /* TW: YPbPr color format */
+#define EnablePALMN             0x40
+#define EnablePALN              0x80
+
+/* CR79 (310/325 series only)
+   [3-0] Notify driver
+         0001 Mode Switch event (set by BIOS)
+	 0010 Epansion On/Off event
+	 0011 TV UnderScan/OverScan event
+	 0100 Set Brightness event
+	 0101 Set Contrast event
+	 0110 Set Mute event
+	 0111 Set Volume Up/Down event
+   [4]   Enable Backlight Control by BIOS/driver (set by driver)
+   [5]   PAL/NTSC (set by BIOS)
+   [6]   Expansion On/Off (set by BIOS)
+   [7]   TV UnderScan/OverScan (set by BIOS)
+*/
+
 
 #define SetSCARTOutput          0x01
 #define BoardTVType             0x02
-#define EnablePALMN             0x40
 
 /* SetFlag */
 #define ProgrammingCRT2         0x01
@@ -112,41 +176,69 @@
 #define SetDispDevSwitchFlag    0x20
 #define CheckWinDos             0x40
 #define SetJDOSMode             0x80
+#define CRT2IsVGA	        0x80  /* TW: Not sure about this name... */
 
 /* LCDResInfo */
-#define Panel800x600            0x01
-#define Panel1024x768           0x02
-#define Panel1280x1024          0x03
-#define Panel1280x960           0x04
-#define Panel640x480            0x05
-#define Panel1600x1200          0x06 /*301b*/
-#define Panel320x480            0x07 /*fstn*/
+#define Panel300_800x600        0x01	/* CR36 */
+#define Panel300_1024x768       0x02
+#define Panel300_1280x1024      0x03
+#define Panel300_1280x960       0x04
+#define Panel300_640x480        0x05
+#define Panel300_1024x600       0x06
+#define Panel300_1152x768       0x07
+#define Panel300_320x480        0x08 	/* fstn - TW: This is fake, can be any */
+
+#define Panel310_800x600        0x01
+#define Panel310_1024x768       0x02
+#define Panel310_1280x1024      0x03
+#define Panel310_640x480        0x04
+#define Panel310_1024x600       0x05
+#define Panel310_1152x864       0x06
+#define Panel310_1280x960       0x07
+#define Panel310_1152x768       0x08	/* TW: LVDS only */
+#define Panel310_1400x1050      0x09
+#define Panel310_1280x768       0x0a    /* TW: LVDS only */
+#define Panel310_1600x1200      0x0b
+#define Panel310_320x480        0x0c    /* fstn - TW: This is fake, can be any */
+
+#define Panel_800x600           0x01	/* Unified values */
+#define Panel_1024x768          0x02
+#define Panel_1280x1024         0x03
+#define Panel_640x480           0x04
+#define Panel_1024x600          0x05
+#define Panel_1152x864          0x06
+#define Panel_1280x960          0x07
+#define Panel_1152x768          0x08	/* TW: LVDS only */
+#define Panel_1400x1050         0x09
+#define Panel_1280x768          0x0a    /* TW: LVDS only */
+#define Panel_1600x1200         0x0b
+#define Panel_320x480           0x0c    /* fstn - TW: This is fake, can be any */
 
 #define ExtChipType             0x0e
 #define ExtChip301              0x02
 #define ExtChipLVDS             0x04
 #define ExtChipTrumpion         0x06
 #define ExtChipCH7005           0x08
-#define ExtChipMitacTV          0x0a
+#define ExtChipMitacTV          0x0a            /* TW: Incorrect, 0x0a = Chrontel 7005 only */
+
+#define IsM650                  0x80   		/* TW: CR5F */
 
 /* LCDInfo */
 #define LCDRGB18Bit             0x01
+#define LCDNonExpandingShift    0x04
 #define LCDNonExpanding         0x10
-
-#define LCDNonExpandingShift    4
 #define LCDSync                 0x20
+#define LCDPass11              0x100 
 #define LCDSyncBit              0xe0
 #define LCDSyncShift            6
 
-#define DDC2DelayTime           300     
-
-#define CRT2DisplayFlag         0x2000
 #define LCDDataLen              8
 #define HiTVDataLen             12
 #define TVDataLen               16
 #define SetPALTV                0x0100
-#define HalfDCLK                0x1000
+#define HalfDCLK                0x1000  /* modeflag */
 #define NTSCHT                  1716
+#define NTSC2HT                 1920
 #define NTSCVT                  525
 #define PALHT                   1728
 #define PALVT                   625
@@ -159,25 +251,23 @@
 
 #define VCLKStartFreq           25
 #define SoftDramType            0x80
-#define VCLK40                  0x04
-#define VCLK65                  0x09
-#define VCLK108_2               0x14
-#define LCDRGB18Bit             0x01
+
+#define VCLK40                  0x04   /* Index in VCLKData array */
+#define VCLK65                  0x09   /* Index in VCLKData array */
+#define VCLK108_2               0x14   /* Index in VCLKData array */
+#define TVVCLKDIV2              0x21   /* Indices in (VB)VCLKData arrays */
+#define TVVCLK                  0x22
+#define HiTVVCLKDIV2            0x23
+#define HiTVVCLK                0x24
+#define HiTVSimuVCLK            0x25
+#define HiTVTextVCLK            0x26
+
 #define LoadDACFlag             0x1000
 #define AfterLockCRT2           0x4000
 #define SetCRT2ToAVIDEO         0x0004
 #define SetCRT2ToSCART          0x0010
 #define Ext2StructSize          5
 
-#define TVVCLKDIV2              0x021
-#define TVVCLK                  0x022
-
-#define HiTVVCLKDIV2            0x023
-#define HiTVVCLK                0x024
-#define HiTVSimuVCLK            0x025
-#define HiTVTextVCLK            0x026
-#define SwitchToCRT2            0x0002
-#define LCDVESATiming           0x08
 #define SetSCARTOutput          0x01
 #define AVIDEOSense             0x01
 #define SVIDEOSense             0x02
@@ -190,14 +280,13 @@
 #define HotPlugFunction         0x08
 #define StStructSize            0x06
 
-#define SIS_CRT2_PORT_04        0x04 - 0x030
+#define SIS_CRT2_PORT_04        0x04 - 0x30
 #define SIS_CRT2_PORT_10        0x10 - 0x30
 #define SIS_CRT2_PORT_12        0x12 - 0x30
 #define SIS_CRT2_PORT_14        0x14 - 0x30
 
-#define LCDNonExpanding         0x10
 #define ADR_CRT2PtrData         0x20E
-#define offset_Zurac            0x210
+#define offset_Zurac            0x210   /* TW: Trumpion Zurac data pointer */
 #define ADR_LVDSDesPtrData      0x212
 #define ADR_LVDSCRT1DataPtr     0x214
 #define ADR_CHTVVCLKPtr         0x216
@@ -235,7 +324,7 @@
 #define _PanelType0F             0x78
 
 #define PRIMARY_VGA       	0     /* 1: SiS is primary vga 0:SiS is secondary vga */
-#define BIOSIDCodeAddr          0x235
+#define BIOSIDCodeAddr          0x235  /* TW: Offsets to ptrs in BIOS image */
 #define OEMUtilIDCodeAddr       0x237
 #define VBModeIDTableAddr       0x239
 #define OEMTVPtrAddr            0x241
@@ -276,9 +365,11 @@
 
 #define OEMLCDPanelIDSupport    0x0080
 
-/* =============================================================
-   			for 310
-============================================================== */
+/*
+  =============================================================
+   			for 310/325 series
+  =============================================================
+*/
 #define SoftDRAMType        0x80
 #define SoftSetting_OFFSET  0x52
 #define SR07_OFFSET  0x7C
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/oem300.h linux-2.4.20/drivers/video/sis/oem300.h
--- linux-2.4.19/drivers/video/sis/oem300.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/oem300.h	2002-10-29 11:18:35.000000000 +0000
@@ -1,5 +1,8 @@
 
-UCHAR SiS300_OEMTVDelay[8][4]={
+/* OEM Data for 300 series */
+
+const UCHAR SiS300_OEMTVDelay301[8][4] =
+{
 	{0x08,0x08,0x08,0x08},
 	{0x08,0x08,0x08,0x08},
 	{0x08,0x08,0x08,0x08},
@@ -10,7 +13,20 @@
 	{0x20,0x20,0x20,0x20}
 };
 
-UCHAR SiS300_OEMTVFlicker[8][4]={
+const UCHAR SiS300_OEMTVDelayLVDS[8][4] =
+{
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20}
+};
+
+const UCHAR SiS300_OEMTVFlicker[8][4] =
+{
 	{0x00,0x00,0x00,0x00},
 	{0x00,0x00,0x00,0x00},
 	{0x00,0x00,0x00,0x00},
@@ -21,7 +37,8 @@
 	{0x00,0x00,0x00,0x00}
 };
 
-UCHAR SiS300_OEMLCDDelay1[12][4]={
+#if 0   /* TW: Not used */
+const UCHAR SiS300_OEMLCDDelay1[12][4]={
 	{0x2c,0x2c,0x2c,0x2c},
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
@@ -35,9 +52,43 @@
 	{0x20,0x20,0x20,0x20},
 	{0x24,0x24,0x24,0x24}
 };
+#endif
 
-
-UCHAR SiS300_OEMLCDDelay2[32][4]={
+/* TW: From 630/301B BIOS */
+const UCHAR SiS300_OEMLCDDelay2[64][4] =		 /* for 301/301b/302b/301LV/302LV */
+{
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
@@ -73,7 +124,7 @@
 };
 
 /* TW: Added for LVDS */
-UCHAR SiS300_OEMLCDDelay3[32][4]={
+const UCHAR SiS300_OEMLCDDelay3[32][4] = {	/* For LVDS */
 	{0x20,0x20,0x20,0x20},  /* --- Expanding panels */
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
@@ -86,7 +137,7 @@
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
-	{0x04,0x04,0x04,0x04},		/* Clevo 2202, Mitac (PanelType 12)*/
+	{0x04,0x04,0x04,0x04},		/* Clevo 2202 (PanelType 12); Mitac needs 0x20! */
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},  	/* Uniwill N241S2 (PanelType 14)*/
 	{0x20,0x20,0x20,0x20},
@@ -102,146 +153,152 @@
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
-	{0x20,0x20,0x20,0x20},
+	{0x04,0x04,0x04,0x04},          /* Gericom 2200C (PanelType 28) */
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20}
 };
 
-/*
-UCHAR SiS300_StNTSCDelay[]={0x08,0x08,0x08,0x08,0xff};
-UCHAR SiS300_StPALDelay[]={0x08,0x08,0x08,0x08,0xff};
-UCHAR SiS300_StSCARTDelay[]={0x08,0x08,0x08,0x08,0xff};
-UCHAR SiS300_StHiTVDelay[]={0x2c,0x2c,0x2c,0x2c,0xff};
-UCHAR SiS300_ExtNTSCDelay[]={0x08,0x08,0x08,0x08,0xff};
-UCHAR SiS300_ExtPALDelay[]={0x08,0x08,0x08,0x08,0xff};
-UCHAR SiS300_ExtSCARTDelay[]={0x08,0x08,0x08,0x08,0xff};
-UCHAR SiS300_ExtHiTVDelay[]={0x20,0x20,0x20,0x20,0xff};
-UCHAR SiS300_StNTSCFlicker[]={0x00,0x00,0x00,0x00,0xff};
-UCHAR SiS300_StPALFlicker[]={0x00,0x00,0x00,0x00,0xff};
-UCHAR SiS300_StSCARTFlicker[]={0x00,0x00,0x00,0x00,0xff};
-UCHAR SiS300_StHiTVFlicker[]={0x00,0x00,0x00,0x00,0xff};
-UCHAR SiS300_ExtNTSCFlicker[]={0x00,0x00,0x00,0x00,0xff};
-UCHAR SiS300_ExtPALFlicker[]={0x00,0x00,0x00,0x00,0xff};
-UCHAR SiS300_ExtSCARTFlicker[]={0x00,0x00,0x00,0x00,0xff};
-UCHAR SiS300_ExtHiTVFlicker[]={0x00,0x00,0x00,0x00,0xff};
-*/
-
-#if 0
-//typedef struct _SiS_OEMTVPhasestruct  {
-//UCHAR Index[4];
-//} SiS_OEMTVPhasestruct;
-//SiS_OEMTVPhasestruct
-#endif
-
-UCHAR SiS300_StNTSCPhase[6][4]={
+const UCHAR SiS300_Phase1[8][6][4] =
+{
+    {
 	{0x21,0xed,0x00,0x08},
 	{0x21,0xed,0x8a,0x08},
 	{0x21,0xed,0x8a,0x08},
 	{0x21,0xed,0x8a,0x08},
 	{0x21,0xed,0x8a,0x08},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVPhasestruct
-#endif
-
-UCHAR SiS300_StPALPhase[6][4]={
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
+	{0xff,0xff,0xff,0xff}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVPhasestruct
-#endif
-
-UCHAR SiS300_StSCARTPhase[6][4]={
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
+	{0xff,0xff,0xff,0xff}
+    },
+    {
+        {0x21,0xed,0x00,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0xff,0xff,0xff,0xff}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVPhasestruct
-#endif
-
-UCHAR SiS300_StHiTVPhase[6][4]={
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
+	{0xff,0xff,0xff,0xff}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0xff,0xff,0xff,0xff}
+    }
 };
 
-#if 0
-//SiS_OEMTVPhasestruct
-#endif
 
-UCHAR SiS300_ExtNTSCPhase[6][4]={
-	{0x21,0xed,0x00,0x08},
+const UCHAR SiS300_Phase2[8][6][4] =
+{
+    {
+        {0x21,0xed,0x00,0x08},
 	{0x21,0xed,0x8a,0x08},
 	{0x21,0xed,0x8a,0x08},
 	{0x21,0xed,0x8a,0x08},
 	{0x21,0xed,0x8a,0x08},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVPhasestruct
-#endif
-
-UCHAR SiS300_ExtPALPhase[6][4]={
+    },
+    {
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVPhasestruct
-#endif
-
-UCHAR SiS300_ExtSCARTPhase[6][4]={
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
+	{0xff,0xff,0xff,0xff}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVPhasestruct
-#endif
-
-UCHAR SiS300_ExtHiTVPhase[6][4]={
+    },
+    {
+        {0x21,0xed,0x00,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0xff,0xff,0xff,0xff}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0xff,0xff,0xff,0xff}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
+	{0xff,0xff,0xff,0xff}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0xff,0xff,0xff,0xff}
+    }
 };
 
-#if 0
-//typedef struct _SiS_OEMTVFilterstruct{
-//UCHAR Index[4];
-//} SiS_OEMTVFilterstruct;
-//SiS_OEMTVFilterstruct
-#endif
-
-UCHAR SiS300_StNTSCFilter[17][4]={
+const UCHAR SiS300_Filter1[10][17][4] =
+{
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xeb,0x04,0x10,0x18},
@@ -259,13 +316,8 @@
 	{0xeb,0x04,0x25,0x18},
 	{0xeb,0x04,0x25,0x18},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVFilterstruct
-#endif
-
-UCHAR SiS300_StPALFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xf1,0xf7,0x10,0x32},
@@ -283,13 +335,8 @@
 	{0xf1,0xf7,0x1f,0x32},
 	{0xf1,0xf7,0x1f,0x32},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVFilterstruct
-#endif
-
-UCHAR SiS300_StSCARTFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xf1,0xf7,0x10,0x32},
@@ -307,13 +354,8 @@
 	{0xf1,0xf7,0x1f,0x32},
 	{0xf1,0xf7,0x1f,0x32},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVFilterstruct
-#endif
-
-UCHAR SiS300_StHiTVFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xf1,0xf7,0x10,0x32},
@@ -331,13 +373,8 @@
 	{0xf1,0xf7,0x1f,0x32},
 	{0xf1,0xf7,0x1f,0x32},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVFilterstruct
-#endif
-
-UCHAR SiS300_ExtNTSCFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xeb,0x04,0x10,0x18},
@@ -355,13 +392,8 @@
 	{0xeb,0x04,0x25,0x18},
 	{0xeb,0x04,0x25,0x18},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVFilterstruct
-#endif
-
-UCHAR SiS300_ExtPALFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xf1,0xf7,0x10,0x32},
@@ -379,13 +411,8 @@
 	{0xf1,0xf7,0x1f,0x32},
 	{0xf1,0xf7,0x1f,0x32},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVFilterstruct
-#endif
-
-UCHAR SiS300_ExtSCARTFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xf1,0xf7,0x10,0x32},
@@ -403,13 +430,8 @@
 	{0xf1,0xf7,0x1f,0x32},
 	{0xf1,0xf7,0x1f,0x32},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVFilterstruct
-#endif
-
-UCHAR SiS300_ExtHiTVFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xf1,0xf7,0x10,0x32},
@@ -427,44 +449,8 @@
 	{0xf1,0xf7,0x1f,0x32},
 	{0xf1,0xf7,0x1f,0x32},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//typedef struct _SiS_OEMTVFilter2struct{
-//UCHAR Index[7];
-//} SiS_OEMTVFilter2struct;
-//SiS_OEMTVFilter2struct
-#endif
-
-UCHAR SiS300_NTSCFilter2[9][7]={
-	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
-	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
-};
-
-#if 0
-//SiS_OEMTVFilter2struct
-#endif
-
-UCHAR SiS300_PALFilter2[9][7]={
-	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
-	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
-};
-
-UCHAR SiS300_PALMFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xeb,0x04,0x10,0x18},
@@ -482,9 +468,8 @@
 	{0xeb,0x04,0x25,0x18},
 	{0xeb,0x04,0x25,0x18},
 	{0xff,0xff,0xff,0xff}
-};
-
-UCHAR SiS300_PALNFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xeb,0x04,0x10,0x18},
@@ -502,10 +487,12 @@
 	{0xeb,0x04,0x25,0x18},
 	{0xeb,0x04,0x25,0x18},
 	{0xff,0xff,0xff,0xff}
+    },
 };
 
-
-UCHAR SiS300_PALMFilter2[9][7]={
+const UCHAR SiS300_Filter2[10][9][7] =
+{
+    {
 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
 	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
@@ -515,9 +502,96 @@
 	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
 	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
 	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
-};
-
-UCHAR SiS300_PALNFilter2[9][7]={
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
 	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
@@ -527,5 +601,6 @@
 	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
 	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
 	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    }
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/oem310.h linux-2.4.20/drivers/video/sis/oem310.h
--- linux-2.4.19/drivers/video/sis/oem310.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/oem310.h	2002-10-29 11:18:31.000000000 +0000
@@ -1,92 +1,181 @@
 
-UCHAR SiS310_CRT2DelayCompensation1=0x4; /* 301A */
-UCHAR SiS310_LCDDelayCompensation1[]=
-		{0x0,0x0,0x0,0xb,0xb,0xb,0x8,0x8,0x8,0x8,0x8,0x8,
-		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0};
-UCHAR SiS310_TVDelayCompensation1[]={0x2,0x2,0x2,0x2,0x8,0xb};
-UCHAR SiS310_CRT2DelayCompensation2=0xC; /* 301B */
-UCHAR SiS310_LCDDelayCompensation2[]=
-		{0x0,0x0,0x0,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x8,
-		 0x8,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0};
-UCHAR SiS310_TVDelayCompensation2[]={0x3,0x3,0x3,0x3,0x8,0xb};
-UCHAR SiS310_TVAntiFlick1[3][2]={{0x4,0x0},{0x4,0x8},{0x0,0x0}};
-
-UCHAR SiS310_TVEdge1[3][2]={{0x0,0x4},{0x0,0x4},{0x0,0x0}};
-
-UCHAR SiS310_TVYFilter1[3][8][4]=
-{
- {
-  {0x0,0xf4,0x10,0x38},
-  {0x0,0xf4,0x10,0x38},
-  {0xeb,0x4,0x25,0x18},
-  {0xf7,0x6,0x19,0x14},
-  {0x0,0xf4,0x10,0x38},
-  {0xeb,0x4,0x25,0x18},
-  {0xee,0xc,0x22,0x8},
-  {0xeb,0x15,0x25,0xf6}
- },
- {
-  {0x0,0xf4,0x10,0x38},
-  {0x0,0xf4,0x10,0x38},
-  {0xf1,0xf7,0x1f,0x32},
-  {0xf3,0x0,0x1d,0x20},
-  {0x0,0xf4,0x10,0x38},
-  {0xf1,0xf7,0x1f,0x32},
-  {0xf3,0x0,0x1d,0x20},
-  {0xfc,0xfb,0x14,0x2a}
- },
- {
-  {0x0,0x0,0x0,0x0},
-  {0x0,0xf4,0x10,0x38},
-  {0x0,0xf4,0x10,0x38},
-  {0xeb,0x4,0x25,0x18},
-  {0xf7,0x6,0x19,0x14},
-  {0x0,0xf4,0x10,0x38},
-  {0xeb,0x4,0x25,0x18},
-  {0xee,0xc,0x22,0x8}
+/* OEM Data for 310/325 series */
+
+const UCHAR SiS310_CRT2DelayCompensation1 = 0x04; /* 301A */
+
+const UCHAR SiS310_LCDDelayCompensation1[] =
+{
+		 0x00,0x00,0x00,    /*   800x600 */
+		 0x0b,0x0b,0x0b,    /*  1024x768 */
+		 0x08,0x08,0x08,    /* 1280x1024 */
+		 0x00,0x00,0x00,    /*   640x480 (unknown) */
+		 0x00,0x00,0x00,    /*  1024x600 (unknown) */
+		 0x00,0x00,0x00,    /*  1152x864 (unknown) */
+		 0x08,0x08,0x08,    /*  1280x960 (guessed) */
+		 0x00,0x00,0x00,    /*  1152x768 (unknown) */
+		 0x08,0x08,0x08,    /* 1400x1050 */
+		 0x08,0x08,0x08,    /*  1280x768  (guessed) */
+		 0x00,0x00,0x00,    /* 1600x1200 */
+		 0x00,0x00,0x00,    /*   320x480 (unknown) */
+		 0x00,0x00,0x00,
+		 0x00,0x00,0x00,
+		 0x00,0x00,0x00
+};
+
+const UCHAR SiS310_TVDelayCompensation1[] =
+{
+		  0x02,0x02,    /* NTSC Enhanced, Standard */
+                  0x02,0x02,    /* PAL */
+		  0x08,0x0b     /* HiVision */
+};
+
+const UCHAR SiS310_CRT2DelayCompensation2 = 0x00;   /* TW: From 650/301LV BIOS; was 0x0C; */      /* 301B */
+
+UCHAR SiS310_LCDDelayCompensation2[] =
+{
+		  0x01,0x01,0x01,    /*   800x600 */
+		  0x01,0x01,0x01,    /*  1024x768 */
+		  0x01,0x01,0x01,    /* 1280x1024 */
+                  0x01,0x01,0x01,    /*   640x480 (unknown) */
+		  0x01,0x01,0x01,    /*  1024x600 (unknown) */
+		  0x01,0x01,0x01,    /*  1152x864 (unknown) */
+		  0x01,0x01,0x01,    /*  1280x960 (guessed) */
+		  0x01,0x01,0x01,    /*  1152x768 (unknown) */
+		  0x01,0x01,0x01,    /* 1400x1050 */
+		  0x08,0x08,0x08,    /*  1280x768  (guessed) */
+		  0x01,0x01,0x01,    /* 1600x1200 */
+		  0x02,0x02,0x02,
+		  0x02,0x02,0x02,
+		  0x02,0x02,0x02,
+		  0x02,0x02,0x02
+};
+
+const UCHAR SiS310_TVDelayCompensation2[] =
+{
+		  0x03,0x03,        /* TW: From 650/301LVx 1.10.6s BIOS */
+		  0x03,0x03,
+		  0x03,0x03
+#if 0
+		  0x03,0x03,        /* NTSC Enhanced, Standard */
+                  0x03,0x03,        /* PAL */
+		  0x08,0x0b         /* HiVision */
+#endif
+};
+
+const UCHAR SiS310_CRT2DelayCompensation3 = 0x00;   /* LVDS */
+
+const UCHAR SiS310_LCDDelayCompensation3[] =
+{
+                   0x00,0x00,0x00,    /*   800x600 */
+		   0x00,0x00,0x00,    /*  1024x768 */
+		   0x00,0x00,0x00,    /* 1280x1024 */
+		   0x00,0x00,0x00,    /*   640x480 (unknown) */
+		   0x00,0x00,0x00,    /*  1024x600 (unknown) */
+		   0x00,0x00,0x00,    /*  1152x864 (unknown) */
+		   0x00,0x00,0x00,    /*  1280x960 (guessed) */
+		   0x00,0x00,0x00,    /*  1152x768 (unknown) */
+		   0x00,0x00,0x00,    /* 1400x1050 */
+		   0x00,0x00,0x00,    /*  1280x768  (guessed) */
+		   0x00,0x00,0x00,    /* 1600x1200 */
+		   0x00,0x00,0x00,
+		   0x00,0x00,0x00,
+		   0x00,0x00,0x00,
+		   0x00,0x00,0x00
+};
+
+const UCHAR SiS310_TVDelayCompensation3[] =
+{
+		   0x0a,0x0a,
+		   0x0a,0x0a,
+		   0x0a,0x0a
+};
+
+const UCHAR SiS310_TVAntiFlick1[3][2] =
+{
+            {0x4,0x0},
+	    {0x4,0x8},
+	    {0x0,0x0}
+};
+
+const UCHAR SiS310_TVEdge1[3][2] =
+{
+            {0x0,0x4},
+	    {0x0,0x4},
+	    {0x0,0x0}
+};
+
+const UCHAR SiS310_TVYFilter1[3][8][4] =
+{
+ {
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xf1,0x04,0x1f,0x18},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xee,0x0c,0x22,0x08},
+	{0xeb,0x15,0x25,0xf6}
+ },
+ {
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf3,0x00,0x1d,0x20},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf3,0x00,0x1d,0x20},
+	{0xfc,0xfb,0x14,0x2a}
+ },
+ {
+	{0x00,0x00,0x00,0x00},
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xf7,0x06,0x19,0x14},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xee,0x0c,0x22,0x08}
  }
 };
-/*301b*/
-UCHAR SiS310_TVYFilter2[3][9][7]=
+
+const UCHAR SiS310_TVYFilter2[3][9][7] =
 {
  {
-  {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-  {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-  {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-  {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-  {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-  {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-  {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-  {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
-  {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
- },
- {
-  {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-  {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-  {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-  {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-  {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-  {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-  {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-  {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
-  {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
- },
- {
-  
-  {0x0,0x0,0x0,0xF4,0xFF,0x1C,0x22},
-  {0x0,0x0,0x0,0xF4,0xFF,0x1C,0x22},
-  {0x0,0x0,0x0,0xF4,0xFF,0x1C,0x22},
-  {0x0,0x0,0x0,0xF4,0xFF,0x1C,0x22},
-  {0x0,0x0,0x0,0xF4,0xFF,0x1C,0x22},
-  {0x0,0x0,0x0,0xF4,0xFF,0x1C,0x22},
-  {0x0,0x0,0x0,0xF4,0xFF,0x1C,0x22},
-  {0x0,0x0,0x0,0xF4,0xFF,0x1C,0x22}
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+ },
+ {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+ },
+ {
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}
  }
 };
-/*end 301b*/
 
-/*add PALMN*/
-UCHAR SiS310_PALMFilter[17][4]={
+const UCHAR SiS310_PALMFilter[17][4] =
+{
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xeb,0x04,0x10,0x18},
@@ -106,7 +195,8 @@
 	{0xff,0xff,0xff,0xff}
 };
 
-UCHAR SiS310_PALNFilter[17][4]={
+const UCHAR SiS310_PALNFilter[17][4] =
+{
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xeb,0x04,0x10,0x18},
@@ -127,7 +217,8 @@
 };
 
 
-UCHAR SiS310_PALMFilter2[9][7]={
+const UCHAR SiS310_PALMFilter2[9][7] =
+{
 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
 	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
@@ -139,7 +230,8 @@
 	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
 };
 
-UCHAR SiS310_PALNFilter2[9][7]={
+const UCHAR SiS310_PALNFilter2[9][7] =
+{
 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
 	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
@@ -151,35 +243,37 @@
 	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
 };
 
-/*end PALMN*/
-UCHAR SiS310_TVPhaseIncr1[3][2][4]=
+const UCHAR SiS310_TVPhaseIncr1[3][2][4]=
 {
  {
-  {0x21,0xed,0x8a,0x8},
-  {0x21,0xed,0x8a,0x8}
+	{0x21,0xed,0xba,0x08},
+	{0x21,0xed,0xba,0x08}
  },
  {
-  {0x2a,0x5,0xd3,0x0},
-  {0x2a,0x5,0xd3,0x0}
+	{0x2a,0x05,0xe3,0x00},
+	{0x2a,0x05,0xe3,0x00}
  },
  {
-  {0x2a,0x5,0xd3,0x0},
-  {0x2a,0x5,0xd3,0x0}
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
  }
 };
 
-UCHAR SiS310_TVPhaseIncr2[3][2][4]=
+const UCHAR SiS310_TVPhaseIncr2[3][2][4]=
 {
  {
-  {0x21,0xF0,0x7b,0xd6},
-  {0x21,0xF0,0x7b,0xd6}
+	{0x1e,0x8b,0xda,0xa7},   /* {0x21,0xF1,0x37,0x56}, - new (1.10.6s) */
+	{0x1e,0x8b,0xda,0xa7}    /* {0x21,0xF1,0x37,0x56} */
  },
  {
-  {0x2a,0x09,0x86,0xe9},
-  {0x2a,0x09,0x86,0xe9}
+	{0x2a,0x0a,0x41,0xe9},   /* {0x2a,0x09,0x86,0xe9}, */
+	{0x2a,0x0a,0x41,0xe9}    /* {0x2a,0x09,0x86,0xe9} */
  },
  {
-  {0x2a,0x5,0xd3,0x0},
-  {0x2a,0x5,0xd3,0x0}
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
  }
 };
+
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/osdef.h linux-2.4.20/drivers/video/sis/osdef.h
--- linux-2.4.19/drivers/video/sis/osdef.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/osdef.h	2002-10-29 11:18:31.000000000 +0000
@@ -7,6 +7,7 @@
 /**********************************************************************/
 #ifdef LINUX_KERNEL
 	#include <linux/config.h>
+	#include <linux/version.h>
 	#ifdef CONFIG_FB_SIS_300
  		#define SIS300
 	#endif
@@ -14,6 +15,12 @@
 	#ifdef CONFIG_FB_SIS_315
 		#define SIS315H
 	#endif
+	#if 1
+		#define SISFBACCEL	/* Include 2D acceleration */
+	#endif
+	#if 1
+		#define SISFB_PAN	/* Include Y-Panning code */
+	#endif
 #else
 /*	#define SIS300*/
 	#define SIS315H
@@ -122,6 +129,10 @@
 #define InPortLong(p)    inl((CARD16)(p))
 #endif
 
+/**********************************************************************/
+/*  LINUX KERNEL                                                      */
+/**********************************************************************/
+
 #ifdef LINUX_KERNEL
 #define OutPortByte(p,v) outb((u8)(v),(u16)(p))
 #define OutPortWord(p,v) outw((u16)(v),(u16)(p))
@@ -146,7 +157,7 @@
 
 
 /**********************************************************************/
-/*  WIN CE                                                          */
+/*  WIN CE                                                            */
 /**********************************************************************/
 
 #ifdef WINCE_HEADER
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/sis.h linux-2.4.20/drivers/video/sis/sis.h
--- linux-2.4.19/drivers/video/sis/sis.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/sis.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,10 @@
+#ifndef _SIS_H
+#define _SIS_H
+
+#if 1
+#define TWDEBUG(x)
+#else
+#define TWDEBUG(x) printk(KERN_INFO x "\n");
+#endif
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/sis_accel.c linux-2.4.20/drivers/video/sis/sis_accel.c
--- linux-2.4.19/drivers/video/sis/sis_accel.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/sis_accel.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,508 @@
+/*
+ * SiS 300/630/730/540/315/550/650/740 frame buffer driver
+ * for Linux kernels 2.4.x and 2.5.x
+ *
+ * 2D acceleration part
+ *
+ * Based on the X driver's sis300_accel.c which is
+ *     Copyright Xavier Ducoin <x.ducoin@lectra.com>
+ *     Copyright 2002 by Thomas Winischhofer, Vienna, Austria
+ * and sis310_accel.c which is
+ *     Copyright 2002 by Thomas Winischhofer, Vienna, Austria
+ *
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ *			(see http://www.winischhofer.net/
+ *			for more information and updates)
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vt_kern.h>
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include <linux/agp_backend.h>
+
+#include <linux/types.h>
+#include <linux/sisfb.h>
+
+#include <asm/io.h>
+#include <asm/mtrr.h>
+
+#include <video/fbcon.h>
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+#endif
+
+#include "osdef.h"
+#include "vgatypes.h"
+#include "vstruct.h"
+#include "sis_accel.h"
+#include "sis.h"
+
+extern struct     video_info ivideo;
+extern VGA_ENGINE sisvga_engine;
+
+static const int sisALUConv[] =
+{
+    0x00,       /* dest = 0;            0,      GXclear,        0 */
+    0x88,       /* dest &= src;         DSa,    GXand,          0x1 */
+    0x44,       /* dest = src & ~dest;  SDna,   GXandReverse,   0x2 */
+    0xCC,       /* dest = src;          S,      GXcopy,         0x3 */
+    0x22,       /* dest &= ~src;        DSna,   GXandInverted,  0x4 */
+    0xAA,       /* dest = dest;         D,      GXnoop,         0x5 */
+    0x66,       /* dest = ^src;         DSx,    GXxor,          0x6 */
+    0xEE,       /* dest |= src;         DSo,    GXor,           0x7 */
+    0x11,       /* dest = ~src & ~dest; DSon,   GXnor,          0x8 */
+    0x99,       /* dest ^= ~src ;       DSxn,   GXequiv,        0x9 */
+    0x55,       /* dest = ~dest;        Dn,     GXInvert,       0xA */
+    0xDD,       /* dest = src|~dest ;   SDno,   GXorReverse,    0xB */
+    0x33,       /* dest = ~src;         Sn,     GXcopyInverted, 0xC */
+    0xBB,       /* dest |= ~src;        DSno,   GXorInverted,   0xD */
+    0x77,       /* dest = ~src|~dest;   DSan,   GXnand,         0xE */
+    0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
+};
+/* same ROP but with Pattern as Source */
+static const int sisPatALUConv[] =
+{
+    0x00,       /* dest = 0;            0,      GXclear,        0 */
+    0xA0,       /* dest &= src;         DPa,    GXand,          0x1 */
+    0x50,       /* dest = src & ~dest;  PDna,   GXandReverse,   0x2 */
+    0xF0,       /* dest = src;          P,      GXcopy,         0x3 */
+    0x0A,       /* dest &= ~src;        DPna,   GXandInverted,  0x4 */
+    0xAA,       /* dest = dest;         D,      GXnoop,         0x5 */
+    0x5A,       /* dest = ^src;         DPx,    GXxor,          0x6 */
+    0xFA,       /* dest |= src;         DPo,    GXor,           0x7 */
+    0x05,       /* dest = ~src & ~dest; DPon,   GXnor,          0x8 */
+    0xA5,       /* dest ^= ~src ;       DPxn,   GXequiv,        0x9 */
+    0x55,       /* dest = ~dest;        Dn,     GXInvert,       0xA */
+    0xF5,       /* dest = src|~dest ;   PDno,   GXorReverse,    0xB */
+    0x0F,       /* dest = ~src;         Pn,     GXcopyInverted, 0xC */
+    0xAF,       /* dest |= ~src;        DPno,   GXorInverted,   0xD */
+    0x5F,       /* dest = ~src|~dest;   DPan,   GXnand,         0xE */
+    0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+static const unsigned char myrops[] = {
+   	3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
+   };
+#endif
+
+/* 300 series */
+
+static void
+SiS300Sync(void)
+{
+	SiS300Idle
+}
+
+static void
+SiS310Sync(void)
+{
+	SiS310Idle
+}
+
+static void
+SiS300SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
+                                unsigned int planemask, int trans_color)
+{
+	SiS300SetupDSTColorDepth(ivideo.DstColor);
+	SiS300SetupSRCPitch(ivideo.video_linelength)
+	SiS300SetupDSTRect(ivideo.video_linelength, -1)
+
+	if(trans_color != -1) {
+		SiS300SetupROP(0x0A)
+		SiS300SetupSRCTrans(trans_color)
+		SiS300SetupCMDFlag(TRANSPARENT_BITBLT)
+	} else {
+	        SiS300SetupROP(sisALUConv[rop])
+	}
+	if(xdir > 0) {
+		SiS300SetupCMDFlag(X_INC)
+	}
+	if(ydir > 0) {
+		SiS300SetupCMDFlag(Y_INC)
+	}
+}
+
+static void
+SiS300SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
+                                int width, int height)
+{
+	long srcbase, dstbase;
+
+	srcbase = dstbase = 0;
+	if (src_y >= 2048) {
+		srcbase = ivideo.video_linelength * src_y;
+		src_y = 0;
+	}
+	if (dst_y >= 2048) {
+		dstbase = ivideo.video_linelength * dst_y;
+		dst_y = 0;
+	}
+
+	SiS300SetupSRCBase(srcbase);
+	SiS300SetupDSTBase(dstbase);
+
+	if(!(ivideo.CommandReg & X_INC))  {
+		src_x += width-1;
+		dst_x += width-1;
+	}
+	if(!(ivideo.CommandReg & Y_INC))  {
+		src_y += height-1;
+		dst_y += height-1;
+	}
+	SiS300SetupRect(width, height)
+	SiS300SetupSRCXY(src_x, src_y)
+	SiS300SetupDSTXY(dst_x, dst_y)
+	SiS300DoCMD
+}
+
+static void
+SiS300SetupForSolidFill(int color, int rop, unsigned int planemask)
+{
+	SiS300SetupPATFG(color)
+	SiS300SetupDSTRect(ivideo.video_linelength, -1)
+	SiS300SetupDSTColorDepth(ivideo.DstColor);
+	SiS300SetupROP(sisPatALUConv[rop])
+	SiS300SetupCMDFlag(PATFG)
+}
+
+static void
+SiS300SubsequentSolidFillRect(int x, int y, int w, int h)
+{
+	long dstbase;
+
+	dstbase = 0;
+	if(y >= 2048) {
+		dstbase = ivideo.video_linelength * y;
+		y = 0;
+	}
+	SiS300SetupDSTBase(dstbase)
+	SiS300SetupDSTXY(x,y)
+	SiS300SetupRect(w,h)
+	SiS300SetupCMDFlag(X_INC | Y_INC | BITBLT)
+	SiS300DoCMD
+}
+
+/* 310/325 series ------------------------------------------------ */
+
+static void
+SiS310SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
+                                unsigned int planemask, int trans_color)
+{
+	SiS310SetupDSTColorDepth(ivideo.DstColor);
+	SiS310SetupSRCPitch(ivideo.video_linelength)
+	SiS310SetupDSTRect(ivideo.video_linelength, -1)
+	if (trans_color != -1) {
+		SiS310SetupROP(0x0A)
+		SiS310SetupSRCTrans(trans_color)
+		SiS310SetupCMDFlag(TRANSPARENT_BITBLT)
+	} else {
+	        SiS310SetupROP(sisALUConv[rop])
+		/* Set command - not needed, both 0 */
+		/* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */
+	}
+	SiS310SetupCMDFlag(ivideo.SiS310_AccelDepth)
+	/* TW: The 310/325 series is smart enough to know the direction */
+}
+
+static void
+SiS310SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
+                                int width, int height)
+{
+	long srcbase, dstbase;
+
+	srcbase = dstbase = 0;
+	if (src_y >= 2048) {
+		srcbase = ivideo.video_linelength * src_y;
+		src_y = 0;
+	}
+	if (dst_y >= 2048) {
+		dstbase = ivideo.video_linelength * dst_y;
+		dst_y = 0;
+	}
+
+	SiS310SetupSRCBase(srcbase);
+	SiS310SetupDSTBase(dstbase);
+	SiS310SetupRect(width, height)
+	SiS310SetupSRCXY(src_x, src_y)
+	SiS310SetupDSTXY(dst_x, dst_y)
+	SiS310DoCMD
+}
+
+static void
+SiS310SetupForSolidFill(int color, int rop, unsigned int planemask)
+{
+	SiS310SetupPATFG(color)
+	SiS310SetupDSTRect(ivideo.video_linelength, -1)
+	SiS310SetupDSTColorDepth(ivideo.DstColor);
+	SiS310SetupROP(sisPatALUConv[rop])
+	SiS310SetupCMDFlag(PATFG | ivideo.SiS310_AccelDepth)
+}
+
+static void
+SiS310SubsequentSolidFillRect(int x, int y, int w, int h)
+{
+	long dstbase;
+
+	dstbase = 0;
+	if(y >= 2048) {
+		dstbase = ivideo.video_linelength * y;
+		y = 0;
+	}
+	SiS310SetupDSTBase(dstbase)
+	SiS310SetupDSTXY(x,y)
+	SiS310SetupRect(w,h)
+	SiS310SetupCMDFlag(BITBLT)
+	SiS310DoCMD
+}
+
+/* --------------------------------------------------------------------- */
+
+/* The exported routines */
+
+int sisfb_initaccel(void)
+{
+#ifdef SISFB_USE_SPINLOCKS
+    spin_lock_init(&ivideo.lockaccel);
+#endif
+    return(0);
+}
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)  /* --- KERNEL 2.5.34 and later --- */
+
+void fbcon_sis_fillrect(struct fb_info *info, struct fb_fillrect *rect)
+{
+   CRITFLAGS
+
+   TWDEBUG("Inside sis_fillrect");
+   if(!rect->width || !rect->height)
+   	return;
+
+   if(!sisfb_accel) {
+        cfb_fillrect(info, rect);
+	return;
+   }
+
+   if(sisvga_engine == SIS_300_VGA) {
+	   CRITBEGIN
+	   SiS300SetupForSolidFill(rect->color, myrops[rect->rop], 0);
+	   SiS300SubsequentSolidFillRect(rect->dx, rect->dy, rect->width, rect->height);
+	   CRITEND
+	   SiS300Sync();
+   } else {
+	   CRITBEGIN
+	   SiS310SetupForSolidFill(rect->color, myrops[rect->rop], 0);
+	   SiS310SubsequentSolidFillRect(rect->dx, rect->dy, rect->width, rect->height);
+	   CRITEND
+	   SiS310Sync();
+   }
+
+}
+
+void fbcon_sis_copyarea(struct fb_info *info, struct fb_copyarea *area)
+{
+   int xdir, ydir;
+   CRITFLAGS
+
+   TWDEBUG("Inside sis_copyarea");
+   if(!sisfb_accel) {
+   	cfb_copyarea(info, area);
+	return;
+   }
+
+   if(!area->width || !area->height)
+   	return;
+
+   if(area->sx < area->dx) xdir = 0;
+   else                    xdir = 1;
+   if(area->sy < area->dy) ydir = 0;
+   else                    ydir = 1;
+
+   if(sisvga_engine == SIS_300_VGA) {
+      CRITBEGIN
+      SiS300SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
+      SiS300SubsequentScreenToScreenCopy(area->sx, area->sy, area->dx, area->dy, area->width, area->height);
+      CRITEND
+      SiS300Sync();
+   } else {
+      CRITBEGIN
+      SiS310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
+      SiS310SubsequentScreenToScreenCopy(area->sx, area->sy, area->dx, area->dy, area->width, area->height);
+      CRITEND
+      SiS310Sync();
+   }
+}
+
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)  /* ------ KERNEL <2.5.34 ------ */
+
+void fbcon_sis_bmove(struct display *p, int srcy, int srcx,
+			    int dsty, int dstx, int height, int width)
+{
+        int xdir, ydir;
+	CRITFLAGS
+
+	srcx *= fontwidth(p);
+	srcy *= fontheight(p);
+	dstx *= fontwidth(p);
+	dsty *= fontheight(p);
+	width *= fontwidth(p);
+	height *= fontheight(p);
+
+
+	if(srcx < dstx) xdir = 0;
+	else            xdir = 1;
+	if(srcy < dsty) ydir = 0;
+	else            ydir = 1;
+
+	if(sisvga_engine == SIS_300_VGA) {
+	   CRITBEGIN
+	   SiS300SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
+	   SiS300SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height);
+	   CRITEND
+	   SiS300Sync();
+	} else {
+	   CRITBEGIN
+	   SiS310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
+	   SiS310SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height);
+	   CRITEND
+	   SiS310Sync();
+	}
+}
+
+
+static void fbcon_sis_clear(struct vc_data *conp, struct display *p,
+			int srcy, int srcx, int height, int width, int color)
+{
+	CRITFLAGS
+
+	srcx *= fontwidth(p);
+	srcy *= fontheight(p);
+	width *= fontwidth(p);
+	height *= fontheight(p);
+
+	if(sisvga_engine == SIS_300_VGA) {
+	   CRITBEGIN
+	   SiS300SetupForSolidFill(color, 3, 0);
+	   SiS300SubsequentSolidFillRect(srcx, srcy, width, height);
+	   CRITEND
+	   SiS300Sync();
+	} else {
+	   CRITBEGIN
+	   SiS310SetupForSolidFill(color, 3, 0);
+	   SiS310SubsequentSolidFillRect(srcx, srcy, width, height);
+	   CRITEND
+	   SiS310Sync();
+	}
+}
+
+void fbcon_sis_clear8(struct vc_data *conp, struct display *p,
+			int srcy, int srcx, int height, int width)
+{
+	u32 bgx;
+
+	bgx = attr_bgcol_ec(p, conp);
+	fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
+}
+
+void fbcon_sis_clear16(struct vc_data *conp, struct display *p,
+			int srcy, int srcx, int height, int width)
+{
+	u32 bgx;
+
+	bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+	fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
+}
+
+void fbcon_sis_clear32(struct vc_data *conp, struct display *p,
+			int srcy, int srcx, int height, int width)
+{
+	u32 bgx;
+
+	bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+	fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
+}
+
+void fbcon_sis_revc(struct display *p, int srcx, int srcy)
+{
+	CRITFLAGS
+
+	srcx *= fontwidth(p);
+	srcy *= fontheight(p);
+
+	if(sisvga_engine == SIS_300_VGA) {
+	   CRITBEGIN
+	   SiS300SetupForSolidFill(0, 0x0a, 0);
+	   SiS300SubsequentSolidFillRect(srcx, srcy, fontwidth(p), fontheight(p));
+	   CRITEND
+	   SiS300Sync();
+	} else {
+	   CRITBEGIN
+	   SiS310SetupForSolidFill(0, 0x0a, 0);
+	   SiS310SubsequentSolidFillRect(srcx, srcy, fontwidth(p), fontheight(p));
+	   CRITEND
+	   SiS310Sync();
+	}
+}
+
+#ifdef FBCON_HAS_CFB8
+struct display_switch fbcon_sis8 = {
+	setup:			fbcon_cfb8_setup,
+	bmove:			fbcon_sis_bmove,
+	clear:			fbcon_sis_clear8,
+	putc:			fbcon_cfb8_putc,
+	putcs:			fbcon_cfb8_putcs,
+	revc:			fbcon_cfb8_revc,
+	clear_margins:		fbcon_cfb8_clear_margins,
+	fontwidthmask:		FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+#ifdef FBCON_HAS_CFB16
+struct display_switch fbcon_sis16 = {
+	setup:			fbcon_cfb16_setup,
+	bmove:			fbcon_sis_bmove,
+	clear:			fbcon_sis_clear16,
+	putc:			fbcon_cfb16_putc,
+	putcs:			fbcon_cfb16_putcs,
+	revc:			fbcon_sis_revc,
+	clear_margins:		fbcon_cfb16_clear_margins,
+	fontwidthmask:		FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+#ifdef FBCON_HAS_CFB32
+struct display_switch fbcon_sis32 = {
+	setup:			fbcon_cfb32_setup,
+	bmove:			fbcon_sis_bmove,
+	clear:			fbcon_sis_clear32,
+	putc:			fbcon_cfb32_putc,
+	putcs:			fbcon_cfb32_putcs,
+	revc:			fbcon_sis_revc,
+	clear_margins:		fbcon_cfb32_clear_margins,
+	fontwidthmask:		FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+#endif /* KERNEL VERSION */
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/sis_accel.h linux-2.4.20/drivers/video/sis/sis_accel.h
--- linux-2.4.19/drivers/video/sis/sis_accel.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/sis_accel.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,508 @@
+/*
+ * SiS 300/630/730/540/315/550/650/740 frame buffer driver
+ * for Linux kernels 2.4.x and 2.5.x
+ *
+ * 2D acceleration part
+ *
+ * Based on the X driver's sis300_accel.h which is
+ *     Copyright Xavier Ducoin <x.ducoin@lectra.com>
+ *     Copyright 2002 by Thomas Winischhofer, Vienna, Austria
+ * and sis310_accel.h which is
+ *     Copyright 2002 by Thomas Winischhofer, Vienna, Austria
+ *
+ * Author:   Thomas Winischhofer <thomas@winischhofer.net>:
+ *			(see http://www.winischhofer.net/
+ *			for more information and updates)
+ */
+
+#ifndef _SISFB_ACCEL_H
+#define _SISFB_ACCEL_H
+
+/* Guard accelerator accesses with spin_lock_irqsave? Works well without. */
+#undef SISFB_USE_SPINLOCKS
+
+#ifdef SISFB_USE_SPINLOCKS
+#include <linux/spinlock.h>
+#define CRITBEGIN  spin_lock_irqsave(&ivideo.lockaccel), critflags);
+#define CRITEND	   spin_unlock_irqrestore(&ivideo.lockaccel), critflags);
+#define CRITFLAGS  unsigned long critflags;
+#else
+#define CRITBEGIN
+#define CRITEND
+#define CRITFLAGS
+#endif
+
+/* Definitions for the SIS engine communication. */
+
+#define PATREGSIZE      384  /* Pattern register size. 384 bytes @ 0x8300 */
+#define BR(x)   (0x8200 | (x) << 2)
+#define PBR(x)  (0x8300 | (x) << 2)
+
+/* SiS300 engine commands */
+#define BITBLT                  0x00000000  /* Blit */
+#define COLOREXP                0x00000001  /* Color expand */
+#define ENCOLOREXP              0x00000002  /* Enhanced color expand */
+#define MULTIPLE_SCANLINE       0x00000003  /* ? */
+#define LINE                    0x00000004  /* Draw line */
+#define TRAPAZOID_FILL          0x00000005  /* Fill trapezoid */
+#define TRANSPARENT_BITBLT      0x00000006  /* Transparent Blit */
+
+/* Additional engine commands for 310/325 */
+#define ALPHA_BLEND		0x00000007  /* Alpha blend ? */
+#define A3D_FUNCTION		0x00000008  /* 3D command ? */
+#define	CLEAR_Z_BUFFER		0x00000009  /* ? */
+#define GRADIENT_FILL		0x0000000A  /* Gradient fill */
+#define STRETCH_BITBLT		0x0000000B  /* Stretched Blit */
+
+/* source select */
+#define SRCVIDEO                0x00000000  /* source is video RAM */
+#define SRCSYSTEM               0x00000010  /* source is system memory */
+#define SRCCPUBLITBUF           SRCSYSTEM   /* source is CPU-driven BitBuffer (for color expand) */
+#define SRCAGP                  0x00000020  /* source is AGP memory (?) */
+
+/* Pattern flags */
+#define PATFG                   0x00000000  /* foreground color */
+#define PATPATREG               0x00000040  /* pattern in pattern buffer (0x8300) */
+#define PATMONO                 0x00000080  /* mono pattern */
+
+/* blitting direction (300 series only) */
+#define X_INC                   0x00010000
+#define X_DEC                   0x00000000
+#define Y_INC                   0x00020000
+#define Y_DEC                   0x00000000
+
+/* Clipping flags */
+#define NOCLIP                  0x00000000
+#define NOMERGECLIP             0x04000000
+#define CLIPENABLE              0x00040000
+#define CLIPWITHOUTMERGE        0x04040000
+
+/* Transparency */
+#define OPAQUE                  0x00000000
+#define TRANSPARENT             0x00100000
+
+/* ? */
+#define DSTAGP                  0x02000000
+#define DSTVIDEO                0x02000000
+
+/* Line */
+#define LINE_STYLE              0x00800000
+#define NO_RESET_COUNTER        0x00400000
+#define NO_LAST_PIXEL           0x00200000
+
+/* Subfunctions for Color/Enhanced Color Expansion (310/325 only) */
+#define COLOR_TO_MONO		0x00100000
+#define AA_TEXT			0x00200000
+
+/* Some general registers for 310/325 series */
+#define SRC_ADDR		0x8200
+#define SRC_PITCH		0x8204
+#define AGP_BASE		0x8206 /* color-depth dependent value */
+#define SRC_Y			0x8208
+#define SRC_X			0x820A
+#define DST_Y			0x820C
+#define DST_X			0x820E
+#define DST_ADDR		0x8210
+#define DST_PITCH		0x8214
+#define DST_HEIGHT		0x8216
+#define RECT_WIDTH		0x8218
+#define RECT_HEIGHT		0x821A
+#define PAT_FGCOLOR		0x821C
+#define PAT_BGCOLOR		0x8220
+#define SRC_FGCOLOR		0x8224
+#define SRC_BGCOLOR		0x8228
+#define MONO_MASK		0x822C
+#define LEFT_CLIP		0x8234
+#define TOP_CLIP		0x8236
+#define RIGHT_CLIP		0x8238
+#define BOTTOM_CLIP		0x823A
+#define COMMAND_READY		0x823C
+#define FIRE_TRIGGER      	0x8240
+
+#define PATTERN_REG		0x8300  /* 384 bytes pattern buffer */
+
+/* Line registers */
+#define LINE_X0			SRC_Y
+#define LINE_X1			DST_Y
+#define LINE_Y0			SRC_X
+#define LINE_Y1			DST_X
+#define LINE_COUNT		RECT_WIDTH
+#define LINE_STYLE_PERIOD	RECT_HEIGHT
+#define LINE_STYLE_0		MONO_MASK
+#define LINE_STYLE_1		0x8230
+#define LINE_XN			PATTERN_REG
+#define LINE_YN			PATTERN_REG+2
+
+/* Transparent bitblit registers */
+#define TRANS_DST_KEY_HIGH	PAT_FGCOLOR
+#define TRANS_DST_KEY_LOW	PAT_BGCOLOR
+#define TRANS_SRC_KEY_HIGH	SRC_FGCOLOR
+#define TRANS_SRC_KEY_LOW	SRC_BGCOLOR
+
+/* Queue */
+#define Q_BASE_ADDR		0x85C0  /* Base address of software queue (?) */
+#define Q_WRITE_PTR		0x85C4  /* Current write pointer (?) */
+#define Q_READ_PTR		0x85C8  /* Current read pointer (?) */
+#define Q_STATUS		0x85CC  /* queue status */
+
+
+#define MMIO_IN8(base, offset) \
+	*(volatile u8 *)(((u8*)(base)) + (offset))
+#define MMIO_IN16(base, offset) \
+	*(volatile u16 *)(void *)(((u8*)(base)) + (offset))
+#define MMIO_IN32(base, offset) \
+	*(volatile u32 *)(void *)(((u8*)(base)) + (offset))
+#define MMIO_OUT8(base, offset, val) \
+	*(volatile u8 *)(((u8*)(base)) + (offset)) = (val)
+#define MMIO_OUT16(base, offset, val) \
+	*(volatile u16 *)(void *)(((u8*)(base)) + (offset)) = (val)
+#define MMIO_OUT32(base, offset, val) \
+	*(volatile u32 *)(void *)(((u8*)(base)) + (offset)) = (val)
+
+/* ------------- SiS 300 series -------------- */
+
+/* Macros to do useful things with the SIS BitBLT engine */
+
+/* BR(16) (0x8420):
+
+   bit 31 2D engine: 1 is idle,
+   bit 30 3D engine: 1 is idle,
+   bit 29 Command queue: 1 is empty
+
+   bits 28:24: Current CPU driven BitBlt buffer stage bit[4:0]
+
+   bits 15:0:  Current command queue length
+
+*/
+
+/* TW: BR(16)+2 = 0x8242 */
+
+int     CmdQueLen;
+
+#define SiS300Idle \
+  { \
+  while( (MMIO_IN16(ivideo.mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
+  while( (MMIO_IN16(ivideo.mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
+  while( (MMIO_IN16(ivideo.mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
+  CmdQueLen=MMIO_IN16(ivideo.mmio_vbase, 0x8240); \
+  }
+/* TW: (do three times, because 2D engine seems quite unsure about whether or not it's idle) */
+
+#define SiS300SetupSRCBase(base) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(0), base);\
+                CmdQueLen --;
+
+#define SiS300SetupSRCPitch(pitch) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT16(ivideo.mmio_vbase, BR(1), pitch);\
+                CmdQueLen --;
+
+#define SiS300SetupSRCXY(x,y) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(2), (x)<<16 | (y) );\
+                CmdQueLen --;
+
+#define SiS300SetupDSTBase(base) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(4), base);\
+                CmdQueLen --;
+
+#define SiS300SetupDSTXY(x,y) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(3), (x)<<16 | (y) );\
+                CmdQueLen --;
+
+#define SiS300SetupDSTRect(x,y) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(5), (y)<<16 | (x) );\
+                CmdQueLen --;
+
+#define SiS300SetupDSTColorDepth(bpp) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT16(ivideo.mmio_vbase, BR(1)+2, bpp);\
+                CmdQueLen --;
+
+#define SiS300SetupRect(w,h) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(6), (h)<<16 | (w) );\
+                CmdQueLen --;
+
+#define SiS300SetupPATFG(color) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(7), color);\
+                CmdQueLen --;
+
+#define SiS300SetupPATBG(color) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(8), color);\
+                CmdQueLen --;
+
+#define SiS300SetupSRCFG(color) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(9), color);\
+                CmdQueLen --;
+
+#define SiS300SetupSRCBG(color) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(10), color);\
+                CmdQueLen --;
+
+/* 0x8224 src colorkey high */
+/* 0x8228 src colorkey low */
+/* 0x821c dest colorkey high */
+/* 0x8220 dest colorkey low */
+#define SiS300SetupSRCTrans(color) \
+                if (CmdQueLen <= 1)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, 0x8224, color);\
+		MMIO_OUT32(ivideo.mmio_vbase, 0x8228, color);\
+		CmdQueLen -= 2;
+
+#define SiS300SetupDSTTrans(color) \
+		if (CmdQueLen <= 1)  SiS300Idle;\
+		MMIO_OUT32(ivideo.mmio_vbase, 0x821C, color); \
+		MMIO_OUT32(ivideo.mmio_vbase, 0x8220, color); \
+                CmdQueLen -= 2;
+
+#define SiS300SetupMONOPAT(p0,p1) \
+                if (CmdQueLen <= 1)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(11), p0);\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(12), p1);\
+                CmdQueLen -= 2;
+
+#define SiS300SetupClipLT(left,top) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(13), ((left) & 0xFFFF) | (top)<<16 );\
+                CmdQueLen--;
+
+#define SiS300SetupClipRB(right,bottom) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(14), ((right) & 0xFFFF) | (bottom)<<16 );\
+                CmdQueLen--;
+
+/* General */
+#define SiS300SetupROP(rop) \
+                ivideo.CommandReg = (rop) << 8;
+
+#define SiS300SetupCMDFlag(flags) \
+                ivideo.CommandReg |= (flags);
+
+#define SiS300DoCMD \
+                if (CmdQueLen <= 1)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(15), ivideo.CommandReg); \
+                MMIO_OUT32(ivideo.mmio_vbase, BR(16), 0);\
+                CmdQueLen -= 2;
+
+/* Line */
+#define SiS300SetupX0Y0(x,y) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(2), (y)<<16 | (x) );\
+                CmdQueLen--;
+
+#define SiS300SetupX1Y1(x,y) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(3), (y)<<16 | (x) );\
+                CmdQueLen--;
+
+#define SiS300SetupLineCount(c) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT16(ivideo.mmio_vbase, BR(6), c);\
+                CmdQueLen--;
+
+#define SiS300SetupStylePeriod(p) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT16(ivideo.mmio_vbase, BR(6)+2, p);\
+                CmdQueLen--;
+
+#define SiS300SetupStyleLow(ls) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(11), ls);\
+                CmdQueLen--;
+
+#define SiS300SetupStyleHigh(ls) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(12), ls);\
+                CmdQueLen--;
+
+
+
+/* ----------- SiS 310/325 series --------------- */
+
+/* Q_STATUS:
+   bit 31 = 1: All engines idle and all queues empty
+   bit 30 = 1: Hardware Queue (=HW CQ, 2D queue, 3D queue) empty
+   bit 29 = 1: 2D engine is idle
+   bit 28 = 1: 3D engine is idle
+   bit 27 = 1: HW command queue empty
+   bit 26 = 1: 2D queue empty
+   bit 25 = 1: 3D queue empty
+   bit 24 = 1: SW command queue empty
+   bits 23:16: 2D counter 3
+   bits 15:8:  2D counter 2
+   bits 7:0:   2D counter 1
+
+   Where is the command queue length (current amount of commands the queue
+   can accept) on the 310/325 series? (The current implementation is taken
+   from 300 series and certainly wrong...)
+*/
+
+/* TW: FIXME: CmdQueLen is... where....? */
+#define SiS310Idle \
+  { \
+  while( (MMIO_IN16(ivideo.mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \
+  while( (MMIO_IN16(ivideo.mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \
+  CmdQueLen=MMIO_IN16(ivideo.mmio_vbase, Q_STATUS); \
+  }
+
+#define SiS310SetupSRCBase(base) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, SRC_ADDR, base);\
+      CmdQueLen--;
+
+#define SiS310SetupSRCPitch(pitch) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT16(ivideo.mmio_vbase, SRC_PITCH, pitch);\
+      CmdQueLen--;
+
+#define SiS310SetupSRCXY(x,y) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, SRC_Y, (x)<<16 | (y) );\
+      CmdQueLen--;
+
+#define SiS310SetupDSTBase(base) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, DST_ADDR, base);\
+      CmdQueLen--;
+
+#define SiS310SetupDSTXY(x,y) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, DST_Y, (x)<<16 | (y) );\
+      CmdQueLen--;
+
+#define SiS310SetupDSTRect(x,y) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, DST_PITCH, (y)<<16 | (x) );\
+      CmdQueLen--;
+
+#define SiS310SetupDSTColorDepth(bpp) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT16(ivideo.mmio_vbase, AGP_BASE, bpp);\
+      CmdQueLen--;
+
+#define SiS310SetupRect(w,h) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, RECT_WIDTH, (h)<<16 | (w) );\
+      CmdQueLen--;
+
+#define SiS310SetupPATFG(color) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, PAT_FGCOLOR, color);\
+      CmdQueLen--;
+
+#define SiS310SetupPATBG(color) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, PAT_BGCOLOR, color);\
+      CmdQueLen--;
+
+#define SiS310SetupSRCFG(color) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, SRC_FGCOLOR, color);\
+      CmdQueLen--;
+
+#define SiS310SetupSRCBG(color) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, SRC_BGCOLOR, color);\
+      CmdQueLen--;
+
+#define SiS310SetupSRCTrans(color) \
+      if (CmdQueLen <= 1)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, TRANS_SRC_KEY_HIGH, color);\
+      MMIO_OUT32(ivideo.mmio_vbase, TRANS_SRC_KEY_LOW, color);\
+      CmdQueLen -= 2;
+
+#define SiS310SetupDSTTrans(color) \
+      if (CmdQueLen <= 1)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, TRANS_DST_KEY_HIGH, color); \
+      MMIO_OUT32(ivideo.mmio_vbase, TRANS_DST_KEY_LOW, color); \
+      CmdQueLen -= 2;
+
+#define SiS310SetupMONOPAT(p0,p1) \
+      if (CmdQueLen <= 1)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, MONO_MASK, p0);\
+      MMIO_OUT32(ivideo.mmio_vbase, MONO_MASK+4, p1);\
+      CmdQueLen -= 2;
+
+#define SiS310SetupClipLT(left,top) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, LEFT_CLIP, ((left) & 0xFFFF) | (top)<<16 );\
+      CmdQueLen--;
+
+#define SiS310SetupClipRB(right,bottom) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, RIGHT_CLIP, ((right) & 0xFFFF) | (bottom)<<16 );\
+      CmdQueLen--;
+
+#define SiS310SetupROP(rop) \
+      ivideo.CommandReg = (rop) << 8;
+
+#define SiS310SetupCMDFlag(flags) \
+      ivideo.CommandReg |= (flags);
+
+#define SiS310DoCMD \
+      if (CmdQueLen <= 1)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, COMMAND_READY, ivideo.CommandReg); \
+      MMIO_OUT32(ivideo.mmio_vbase, FIRE_TRIGGER, 0); \
+      CmdQueLen -= 2;
+
+#define SiS310SetupX0Y0(x,y) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, LINE_X0, (y)<<16 | (x) );\
+      CmdQueLen--;
+
+#define SiS310SetupX1Y1(x,y) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, LINE_X1, (y)<<16 | (x) );\
+      CmdQueLen--;
+
+#define SiS310SetupLineCount(c) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT16(ivideo.mmio_vbase, LINE_COUNT, c);\
+      CmdQueLen--;
+
+#define SiS310SetupStylePeriod(p) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT16(ivideo.mmio_vbase, LINE_STYLE_PERIOD, p);\
+      CmdQueLen--;
+
+#define SiS310SetupStyleLow(ls) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, LINE_STYLE_0, ls);\
+      CmdQueLen--;
+
+#define SiS310SetupStyleHigh(ls) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, LINE_STYLE_1, ls);\
+      CmdQueLen--;
+
+int  sisfb_initaccel(void);
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+void fbcon_sis_bmove(struct display *p, int srcy, int srcx, int dsty,
+                     int dstx, int height, int width);
+void fbcon_sis_revc(struct display *p, int srcy, int srcx);
+void fbcon_sis_clear8(struct vc_data *conp, struct display *p, int srcy,
+                      int srcx, int height, int width);
+void fbcon_sis_clear16(struct vc_data *conp, struct display *p, int srcy,
+                       int srcx, int height, int width);
+void fbcon_sis_clear32(struct vc_data *conp, struct display *p, int srcy,
+                       int srcx, int height, int width);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+extern int sisfb_accel;
+void fbcon_sis_fillrect(struct fb_info *info, struct fb_fillrect *rect);
+void fbcon_sis_copyarea(struct fb_info *info, struct fb_copyarea *area);
+extern void cfb_fillrect(struct fb_info *info, struct fb_fillrect *rect);
+extern void cfb_copyarea(struct fb_info *info, struct fb_copyarea *area);
+#endif
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/sis_main.c linux-2.4.20/drivers/video/sis/sis_main.c
--- linux-2.4.19/drivers/video/sis/sis_main.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/sis_main.c	2002-10-29 11:18:49.000000000 +0000
@@ -8,11 +8,16 @@
  * Authors:   	SiS (www.sis.com.tw)
  *		(Various others)
  *		Thomas Winischhofer <thomas@winischhofer.net>:
- *			- many fixes and enhancements for 630 & 310 series,
- *			- extended bridge handling, TV output for Chrontel
+ *			- many fixes and enhancements for all chipset series,
+ *			- extended bridge handling, TV output for Chrontel 7005
+ *                      - 650/LVDS support (for LCD panels up to 1400x1050)
+ *                      - 650/Chrontel 7019 support
+ *                      - 301B/301LV(x)/302B/302LV(x) LCD and TV support
  *			- memory queue handling enhancements,
- *			- everything marked with "TW"
- *			(see http://www.winischhofer.net/linuxsis630.shtml
+ *                      - 2D acceleration and y-panning,
+ *                      - portation to 2.5 API (yet incomplete)
+ *			- everything marked with "TW" and more
+ *			(see http://www.winischhofer.net/
  *			for more information and updates)
  */
 
@@ -36,6 +41,11 @@
 #include <linux/capability.h>
 #include <linux/fs.h>
 #include <linux/agp_backend.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,33)
+#include <linux/spinlock.h>
+#endif
+
+#include "osdef.h"
 
 #include <linux/types.h>
 #include <linux/sisfb.h>
@@ -49,68 +59,52 @@
 #include <video/fbcon-cfb24.h>
 #include <video/fbcon-cfb32.h>
 
-#include "osdef.h"
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+#include "../fbcon-accel.h"
+#endif
+
 #include "vgatypes.h"
 #include "sis_main.h"
+#include "sis.h"
 //#ifdef LINUXBIOS
 //#include "bios.h"
 //#endif
 
 /* -------------------- Macro definitions ---------------------------- */
-// #define SISFBDEBUG
-#undef SISFBDEBUG /* TW */
+#undef SISFBDEBUG /* TW: no debugging */
+
 #ifdef SISFBDEBUG
 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
 #else
 #define DPRINTK(fmt, args...)
 #endif
 
-#define vgawb(reg,data) \
-           (outb(data, ivideo.vga_base+reg))
-#define vgaww(reg,data) \
-           (outw(data, ivideo.vga_base+reg))
-#define vgawl(reg,data) \
-           (outl(data, ivideo.vga_base+reg))
-#define vgarb(reg)      \
-           (inb(ivideo.vga_base+reg))
-
-/* --------------- Hardware Access Routines -------------------------- */
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+#ifdef SISFBACCEL
+#ifdef FBCON_HAS_CFB8
+extern struct display_switch fbcon_sis8;
+#endif
+#ifdef FBCON_HAS_CFB16
+extern struct display_switch fbcon_sis16;
+#endif
+#ifdef FBCON_HAS_CFB32
+extern struct display_switch fbcon_sis32;
+#endif
+#endif
+#endif
 
-void sisfb_set_reg1(u16 port, u16 index, u16 data)
-{
-	outb((u8) (index & 0xff), port);
-	port++;
-	outb((u8) (data & 0xff), port);
-}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+/* TEMP */
+void my_cfb_imageblit(struct fb_info *info, struct fb_image *image);
+#endif
 
-void sisfb_set_reg3(u16 port, u16 data)
-{
-	outb((u8) (data & 0xff), port);
-}
+/* --------------- Hardware Access Routines -------------------------- */
 
 void sisfb_set_reg4(u16 port, unsigned long data)
 {
 	outl((u32) (data & 0xffffffff), port);
 }
 
-u8 sisfb_get_reg1(u16 port, u16 index)
-{
-	u8 data;
-
-	outb((u8) (index & 0xff), port);
-	port += 1;
-	data = inb(port);
-	return (data);
-}
-
-u8 sisfb_get_reg2(u16 port)
-{
-	u8 data;
-
-	data = inb(port);
-	return (data);
-}
-
 u32 sisfb_get_reg3(u16 port)
 {
 	u32 data;
@@ -119,25 +113,7 @@
 	return (data);
 }
 
-// Eden Chen
-//void sisfb_clear_DAC(u16 port)
-//{
-//	int i,j;
-//
-//	vgawb(DAC_ADR, 0x00);
-//	for(i=0; i<256; i++)
-//		for(j=0; j<3; j++)
-//			vgawb(DAC_DATA, 0);
-//}
-
-//void sisfb_clear_buffer(PHW_DEVICE_EXTENSION psishw_ext)
-//{
-//	memset((char *) ivideo.video_vbase, 0,
-//		video_linelength * ivideo.video_height);
-//}
-// ~Eden Chen
-
-/* --------------- Interface to BIOS code ---------------------------- */
+/* -------------------- Interface to BIOS code -------------------- */
 
 BOOLEAN
 sisfb_query_VGA_config_space(PSIS_HW_DEVICE_INFO psishw_ext,
@@ -178,7 +154,7 @@
 	return TRUE;
 }
 
-BOOLEAN sisfb_query_north_bridge_space(PSIS_HW_DEVICE_INFO psishw_ext, 
+BOOLEAN sisfb_query_north_bridge_space(PSIS_HW_DEVICE_INFO psishw_ext,
 	unsigned long offset, unsigned long set, unsigned long *value)
 {
 	static struct pci_dev *pdev = NULL;
@@ -233,10 +209,13 @@
 	return TRUE;
 }
 
-/* -------------------- Export functions ----------------------------- */
+/* -------------------- Exported functions ----------------------------- */
 
-static void sis_get_glyph(SIS_GLYINFO *gly)
+static void sis_get_glyph(struct fb_info *info, SIS_GLYINFO *gly)
 {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
 	struct display *p = &fb_display[currcon];
 	u16 c;
 	u8 *cdat;
@@ -244,7 +223,7 @@
 	u8 *gbuf = gly->gmask;
 	int size;
 
-
+	TWDEBUG("Inside get_glyph");
 	gly->fontheight = fontheight(p);
 	gly->fontwidth = fontwidth(p);
 	widthb = (fontwidth(p) + 7) / 8;
@@ -258,10 +237,15 @@
 	size = fontheight(p) * widthb;
 	memcpy(gbuf, cdat, size);
 	gly->ngmask = size;
+	TWDEBUG("End of get_glyph");
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon 
+#endif
 }
 
 void sis_dispinfo(struct ap_data *rec)
 {
+        TWDEBUG("Inside dispinfo");
 	rec->minfo.bpp    = ivideo.video_bpp;
 	rec->minfo.xres   = ivideo.video_width;
 	rec->minfo.yres   = ivideo.video_height;
@@ -278,125 +262,175 @@
 	rec->TV_type      = ivideo.TV_type; 
 	rec->TV_plug      = ivideo.TV_plug; 
 	rec->chip         = ivideo.chip;
+	TWDEBUG("End of dispinfo");
 }
 
 /* ------------------ Internal Routines ------------------------------ */
 
 static void sisfb_search_mode(const char *name)
 {
-	int i = 0;
+	int i = 0, j = 0;
 
-	if (name == NULL)
+	if(name == NULL)
 		return;
 
-	while (sisbios_mode[i].mode_no != 0) {
+	while(sisbios_mode[i].mode_no != 0) {
 		if (!strcmp(name, sisbios_mode[i].name)) {
 			sisfb_mode_idx = i;
+			j = 1;
 			break;
 		}
 		i++;
 	}
-	if (sisfb_mode_idx < 0)
-		printk(KERN_INFO "sisfb: Invalid mode '%s'\n", name);
+	if(!j) printk(KERN_INFO "sisfb: Invalid mode '%s'\n", name);
 }
 
-static void sisfb_validate_mode(void)
+static void sisfb_search_vesamode(unsigned int vesamode)
 {
-	switch (ivideo.disp_state & DISPTYPE_DISP2) {
-	case DISPTYPE_LCD:
-	    switch (sishw_ext.ulCRT2LCDType) {
-		case LCD_1024x768:
-			if (sisbios_mode[sisfb_mode_idx].xres > 1024)
-				sisfb_mode_idx = -1;
-			break;
-		case LCD_1280x1024:
-		case LCD_1280x960:
-			if (sisbios_mode[sisfb_mode_idx].xres > 1280)
-				sisfb_mode_idx = -1;
-			break;
-		case LCD_2048x1536:
-			if (sisbios_mode[sisfb_mode_idx].xres > 2048)
-				sisfb_mode_idx = -1;
-			break;
-		case LCD_1920x1440:
-			if (sisbios_mode[sisfb_mode_idx].xres > 1920)
-				sisfb_mode_idx = -1;
-			break;
-		case LCD_1600x1200:
-			if (sisbios_mode[sisfb_mode_idx].xres > 1600)
-				sisfb_mode_idx = -1;
-			break;
-		case LCD_800x600:
-			if (sisbios_mode[sisfb_mode_idx].xres > 800)
-				sisfb_mode_idx = -1;
-			break;
-		case LCD_640x480:
-			if (sisbios_mode[sisfb_mode_idx].xres > 640)
-				sisfb_mode_idx = -1;
-			break;
-		case LCD_320x480:	/* TW: FSTN */
-			if (sisbios_mode[sisfb_mode_idx].xres > 320)
-				sisfb_mode_idx = -1;
+	int i = 0, j = 0;
+
+	if(vesamode == 0) {
+		sisfb_mode_idx = MODE_INDEX_NONE;
+		return;
+	}
+
+	vesamode &= 0x1dff;  /* Clean VESA mode number from other flags */
+
+	while(sisbios_mode[i].mode_no != 0) {
+		if( (sisbios_mode[i].vesa_mode_no_1 == vesamode) ||
+		    (sisbios_mode[i].vesa_mode_no_2 == vesamode) ) {
+			sisfb_mode_idx = i;
+			j = 1;
 			break;
-		default:
-			sisfb_mode_idx = -1;
 		}
-		if (sisbios_mode[sisfb_mode_idx].xres == 720)
-			sisfb_mode_idx = -1;
+		i++;
+	}
+	if(!j) printk(KERN_INFO "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
+}
+
+static int sisfb_validate_mode(int myindex)
+{
+   u16 xres, yres;
+
+#ifdef CONFIG_FB_SIS_300
+   if(sisvga_engine == SIS_300_VGA) {
+       if(!(sisbios_mode[sisfb_mode_idx].chipset & MD_SIS300)) {
+           return(-1);
+       }
+   }
+#endif
+#ifdef CONFIG_FB_SIS_315
+   if(sisvga_engine == SIS_315_VGA) {
+       if(!(sisbios_mode[myindex].chipset & MD_SIS315)) {
+	   return(-1);
+       }
+   }
+#endif
+
+   switch (ivideo.disp_state & DISPTYPE_DISP2) {
+     case DISPTYPE_LCD:
+	switch (sishw_ext.ulCRT2LCDType) {
+	case LCD_1024x768:
+	 	xres = 1024; yres =  768;  break;
+	case LCD_1280x1024:
+		xres = 1280; yres = 1024;  break;
+	case LCD_1280x960:
+	        xres = 1280; yres =  960;  break;
+	case LCD_2048x1536:
+		xres = 2048; yres = 1536;  break;
+	case LCD_1920x1440:
+		xres = 1920; yres = 1440;  break;
+	case LCD_1600x1200:
+		xres = 1600; yres = 1200;  break;
+	case LCD_800x600:
+		xres =  800; yres =  600;  break;
+	case LCD_640x480:
+		xres =  640; yres =  480;  break;
+	case LCD_320x480:				/* TW: FSTN */
+		xres =  320; yres =  480;  break;
+        case LCD_1024x600:
+		xres = 1024; yres =  600;  break;
+	case LCD_1152x864:
+		xres = 1152; yres =  864;  break;
+	case LCD_1152x768:
+		xres = 1152; yres =  768;  break;
+	case LCD_1280x768:
+		xres = 1280; yres =  768;  break;
+	case LCD_1400x1050:
+		xres = 1400; yres = 1050;  break;
+	default:
+	        xres =    0; yres =    0;  break;
+	}
+	if(sisbios_mode[myindex].xres > xres) {
+	        return(-1);
+	}
+        if(sisbios_mode[myindex].yres > yres) {
+	        return(-1);
+	}
+	if (sisbios_mode[myindex].xres == 720) {
+		return(-1);
+	}
+	break;
+     case DISPTYPE_TV:
+	switch (sisbios_mode[myindex].xres) {
+	case 512:
+	case 640:
+	case 800:
 		break;
-	case DISPTYPE_TV:
-	    switch (sisbios_mode[sisfb_mode_idx].xres) {
-		case 800:
-		case 640:
-			break;
-		case 720:
-			if (ivideo.TV_type == TVMODE_NTSC) {
-				if (sisbios_mode[sisfb_mode_idx].yres != 480)
-					sisfb_mode_idx = -1;
-			} else if (ivideo.TV_type == TVMODE_PAL) {
-				if (sisbios_mode[sisfb_mode_idx].yres != 576)
-					sisfb_mode_idx = -1;
-			}
-			/* TW: LVDS/CHRONTEL only supports 640 and 800 */
-			if (ivideo.hasVB == HASVB_LVDS_CHRONTEL ||
-						ivideo.hasVB == HASVB_CHRONTEL)
-					sisfb_mode_idx = -1;
-			break;
-		case 1024:
-			if (ivideo.TV_type == TVMODE_NTSC) {
-				if(sisbios_mode[sisfb_mode_idx].bpp == 32)
-				       sisfb_mode_idx = -1; /* TW; was -= 1 */
-				       /* TW: Should this mean a switch-back to
-				        *     16bpp or simply 'illegal mode'?
-					*/
-			}
-			/* TW: LVDS/CHRONTEL only supports 640 and 800 */
-			if (ivideo.hasVB == HASVB_LVDS_CHRONTEL ||
-						ivideo.hasVB == HASVB_CHRONTEL)
-					sisfb_mode_idx = -1;
-			break;
-		default:
-			sisfb_mode_idx = -1;
+	case 720:
+		if (ivideo.TV_type == TVMODE_NTSC) {
+			if (sisbios_mode[myindex].yres != 480) {
+				return(-1);
+			}
+		} else if (ivideo.TV_type == TVMODE_PAL) {
+			if (sisbios_mode[myindex].yres != 576) {
+				return(-1);
+			}
+		}
+		/* TW: LVDS/CHRONTEL does not support 720 */
+		if (ivideo.hasVB == HASVB_LVDS_CHRONTEL ||
+					ivideo.hasVB == HASVB_CHRONTEL) {
+				return(-1);
+		}
+		break;
+	case 1024:
+		if (ivideo.TV_type == TVMODE_NTSC) {
+			if(sisbios_mode[myindex].bpp == 32) {
+			       return(-1);
+			}
+		}
+		/* TW: LVDS/CHRONTEL only supports < 800 (1024 on 650/Ch7019)*/
+		if (ivideo.hasVB == HASVB_LVDS_CHRONTEL ||
+					ivideo.hasVB == HASVB_CHRONTEL) {
+		    if(ivideo.chip < SIS_315H) {
+				return(-1);
+		    }
 		}
 		break;
+	default:
+		return(-1);
 	}
+	break;
+     }
+     return(myindex);
 }
 
 static void sisfb_search_crt2type(const char *name)
 {
 	int i = 0;
 
-	if (name == NULL)
+	if(name == NULL)
 		return;
 
-	while (sis_crt2type[i].type_no != -1) {
+	while(sis_crt2type[i].type_no != -1) {
 		if (!strcmp(name, sis_crt2type[i].name)) {
 			sisfb_crt2type = sis_crt2type[i].type_no;
+			sisfb_tvplug = sis_crt2type[i].tvplug_no;
 			break;
 		}
 		i++;
 	}
-	if (sisfb_crt2type < 0)
+	if(sisfb_crt2type < 0)
 		printk(KERN_INFO "sisfb: Invalid CRT2 type: %s\n", name);
 }
 
@@ -404,7 +438,7 @@
 {
 	int i = 0;
 
-	if (name == NULL)
+	if(name == NULL)
 		return;
 
 	while (sis_queuemode[i].type_no != -1) {
@@ -459,50 +493,51 @@
 	}
 }
 
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
 static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
 			 unsigned *transp, struct fb_info *fb_info)
 {
-	if (regno >= video_cmap_len)
+	if (regno >= ivideo.video_cmap_len)
 		return 1;
 
-	*red = palette[regno].red;
-	*green = palette[regno].green;
-	*blue = palette[regno].blue;
+	*red = sis_palette[regno].red;
+	*green = sis_palette[regno].green;
+	*blue = sis_palette[regno].blue;
 	*transp = 0;
 	return 0;
 }
+#endif
 
-static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
-			 unsigned transp, struct fb_info *fb_info)
+static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
+                           unsigned transp, struct fb_info *fb_info)
 {
-	if (regno >= video_cmap_len)
+	if (regno >= ivideo.video_cmap_len)
 		return 1;
 
-	palette[regno].red = red;
-	palette[regno].green = green;
-	palette[regno].blue = blue;
+	sis_palette[regno].red = red;
+	sis_palette[regno].green = green;
+	sis_palette[regno].blue = blue;
 
 	switch (ivideo.video_bpp) {
 #ifdef FBCON_HAS_CFB8
 	case 8:
-		vgawb(DAC_ADR, regno);
-		vgawb(DAC_DATA, red >> 10);
-		vgawb(DAC_DATA, green >> 10);
-		vgawb(DAC_DATA, blue >> 10);
+	        outSISREG(SISDACA, regno);
+		outSISREG(SISDACD, (red >> 10));
+		outSISREG(SISDACD, (green >> 10));
+		outSISREG(SISDACD, (blue >> 10));
 		if (ivideo.disp_state & DISPTYPE_DISP2) {
-		 	vgawb(DAC2_ADR,  regno);
-			vgawb(DAC2_DATA, red >> 8);
-			vgawb(DAC2_DATA, green >> 8);
-			vgawb(DAC2_DATA, blue >> 8);
+		        outSISREG(SISDAC2A, regno);
+			outSISREG(SISDAC2D, (red >> 8));
+			outSISREG(SISDAC2D, (green >> 8));
+			outSISREG(SISDAC2D, (blue >> 8));
 		}
 		break;
 #endif
 #ifdef FBCON_HAS_CFB16
 	case 15:
 	case 16:
-		fbcon_cmap.cfb16[regno] =
-		    ((red & 0xf800)) |
-		    ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+		sis_fbcon_cmap.cfb16[regno] =
+		    ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
 		break;
 #endif
 #ifdef FBCON_HAS_CFB24
@@ -510,8 +545,7 @@
 		red >>= 8;
 		green >>= 8;
 		blue >>= 8;
-		fbcon_cmap.cfb24[regno] =
-		    (red << 16) | (green << 8) | (blue);
+		sis_fbcon_cmap.cfb24[regno] = (red << 16) | (green << 8) | (blue);
 		break;
 #endif
 #ifdef FBCON_HAS_CFB32
@@ -519,8 +553,7 @@
 		red >>= 8;
 		green >>= 8;
 		blue >>= 8;
-		fbcon_cmap.cfb32[regno] =
-		    (red << 16) | (green << 8) | (blue);
+		sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue);
 		break;
 #endif
 	}
@@ -540,22 +573,24 @@
 	int found_mode = 0;
 	int old_mode;
 
-	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
+	TWDEBUG("Inside do_set_var");
+
+	if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
 		vtotal = var->upper_margin + var->yres + var->lower_margin +
 		         var->vsync_len;   /* TW */
 		vtotal <<= 1;
-	} else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
 		vtotal = var->upper_margin + var->yres + var->lower_margin +
 		         var->vsync_len;   /* TW */
 		vtotal <<= 2;
-	} else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
 		vtotal = var->upper_margin + (var->yres/2) + var->lower_margin +
 		         var->vsync_len;   /* TW */
 		/* var->yres <<= 1; */ /* TW */
 	} else 	vtotal = var->upper_margin + var->yres + var->lower_margin +
 		         var->vsync_len;
 
-	if (!(htotal) || !(vtotal)) {
+	if(!(htotal) || !(vtotal)) {
 		DPRINTK("sisfb: Invalid 'var' information\n");
 		return -EINVAL;
 	}
@@ -564,17 +599,20 @@
 	hrate = drate / htotal;
 	ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
 
-	DPRINTK("sisfb: Change mode to %dx%dx%d-%dMHz\n",
+	/* TW: Calculation wrong for 1024x600 - force it to 60Hz */
+	if((var->xres == 1024) && (var->yres == 600)) ivideo.refresh_rate = 60;
+
+	printk("sisfb: Change mode to %dx%dx%d-%dHz\n",
 		var->xres,var->yres,var->bits_per_pixel,ivideo.refresh_rate);
 
 	old_mode = sisfb_mode_idx;
 	sisfb_mode_idx = 0;
 
-	while ((sisbios_mode[sisfb_mode_idx].mode_no != 0)
-	       && (sisbios_mode[sisfb_mode_idx].xres <= var->xres)) {
-		if ((sisbios_mode[sisfb_mode_idx].xres == var->xres)
-		    && (sisbios_mode[sisfb_mode_idx].yres == var->yres)
-		    && (sisbios_mode[sisfb_mode_idx].bpp == var->bits_per_pixel)) {
+	while( (sisbios_mode[sisfb_mode_idx].mode_no != 0) &&
+	       (sisbios_mode[sisfb_mode_idx].xres <= var->xres) ) {
+		if( (sisbios_mode[sisfb_mode_idx].xres == var->xres) &&
+		    (sisbios_mode[sisfb_mode_idx].yres == var->yres) &&
+		    (sisbios_mode[sisfb_mode_idx].bpp == var->bits_per_pixel)) {
 			sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no;
 			found_mode = 1;
 			break;
@@ -582,66 +620,97 @@
 		sisfb_mode_idx++;
 	}
 
-	if (found_mode)
-		sisfb_validate_mode();
+	if(found_mode)
+		sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx);
 	else
 		sisfb_mode_idx = -1;
 
-       	if (sisfb_mode_idx < 0) {
-		DPRINTK("sisfb: sisfb does not support mode %dx%d-%d\n", var->xres,
+       	if(sisfb_mode_idx < 0) {
+		printk("sisfb: Mode %dx%dx%d not supported\n", var->xres,
 		       var->yres, var->bits_per_pixel);
 		sisfb_mode_idx = old_mode;
 		return -EINVAL;
 	}
 
-	if (sisfb_search_refresh_rate(ivideo.refresh_rate) == 0) {
+	if(sisfb_search_refresh_rate(ivideo.refresh_rate) == 0) {
 		sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx;
 		ivideo.refresh_rate = 60;
 	}
 
-	if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
-
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+	if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
+#else
+	if(isactive) {
+#endif
 		sisfb_pre_setmode();
 
-		if (SiSSetMode(&sishw_ext, sisfb_mode_no) == 0) {
-			DPRINTK("sisfb: Setting mode[0x%x]: failed\n", sisfb_mode_no);
-			return -1;
+		if(SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) {
+			printk("sisfb: Setting mode[0x%x] failed\n", sisfb_mode_no);
+			return -EINVAL;
 		}
 
-		vgawb(SEQ_ADR, IND_SIS_PASSWORD);
-		vgawb(SEQ_DATA, SIS_PASSWORD);
+		outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 
 		sisfb_post_setmode();
 
-		DPRINTK("sisfb: Set new mode: %dx%dx%d-%d \n", sisbios_mode[sisfb_mode_idx].xres,
-			sisbios_mode[sisfb_mode_idx].yres, sisbios_mode[sisfb_mode_idx].bpp,
+		DPRINTK("sisfb: Set new mode: %dx%dx%d-%d \n",
+			sisbios_mode[sisfb_mode_idx].xres,
+			sisbios_mode[sisfb_mode_idx].yres,
+			sisbios_mode[sisfb_mode_idx].bpp,
 			ivideo.refresh_rate);
 
 		ivideo.video_bpp = sisbios_mode[sisfb_mode_idx].bpp;
 		ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres;
 		ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres;
 		ivideo.org_x = ivideo.org_y = 0;
-		video_linelength =
-		    ivideo.video_width * (ivideo.video_bpp >> 3);
+		ivideo.video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
+		switch(ivideo.video_bpp) {
+        	case 8:
+            		ivideo.DstColor = 0x0000;
+	    		ivideo.SiS310_AccelDepth = 0x00000000;
+			ivideo.video_cmap_len = 256;
+            		break;
+        	case 16:
+            		ivideo.DstColor = 0x8000;
+            		ivideo.SiS310_AccelDepth = 0x00010000;
+			ivideo.video_cmap_len = 16;
+            		break;
+        	case 32:
+            		ivideo.DstColor = 0xC000;
+	    		ivideo.SiS310_AccelDepth = 0x00020000;
+			ivideo.video_cmap_len = 16;
+            		break;
+		default:
+			ivideo.video_cmap_len = 16;
+		        printk(KERN_ERR "sisfb: Unsupported accel depth %d", ivideo.video_bpp);
+			break;
+    		}
 	}
+	TWDEBUG("End of do_set_var");
 	return 0;
 }
 
-static void sisfb_set_disp(int con, struct fb_var_screeninfo *var)
+/* ------ Internal functions only for 2.4 series ------- */
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+static void sisfb_set_disp(int con, struct fb_var_screeninfo *var,
+                           struct fb_info *info)
 {
 	struct fb_fix_screeninfo fix;
+	long   flags;
 	struct display *display;
 	struct display_switch *sw;
-	u32 flags;
 
-	if (con >= 0)
+	if(con >= 0)
 		display = &fb_display[con];
 	else
-		display = &disp;	
+		display = &sis_disp;
 
 	sisfb_get_fix(&fix, con, 0);
 
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,23)
 	display->screen_base = ivideo.video_vbase;
+#endif
 	display->visual = fix.visual;
 	display->type = fix.type;
 	display->type_aux = fix.type_aux;
@@ -654,29 +723,42 @@
 	display->var = *var;
 
 	save_flags(flags);
+
 	switch (ivideo.video_bpp) {
 #ifdef FBCON_HAS_CFB8
 	   case 8:
+#ifdef SISFBACCEL
+		sw = sisfb_accel ? &fbcon_sis8 : &fbcon_cfb8;
+#else
 		sw = &fbcon_cfb8;
+#endif
 		break;
 #endif
 #ifdef FBCON_HAS_CFB16
 	   case 15:
 	   case 16:
+#ifdef SISFBACCEL
+		sw = sisfb_accel ? &fbcon_sis16 : &fbcon_cfb16;
+#else
 		sw = &fbcon_cfb16;
-		display->dispsw_data = fbcon_cmap.cfb16;
+#endif
+		display->dispsw_data = sis_fbcon_cmap.cfb16;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB24
 	   case 24:
 		sw = &fbcon_cfb24;
-		display->dispsw_data = fbcon_cmap.cfb24;
+		display->dispsw_data = sis_fbcon_cmap.cfb24;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB32
 	   case 32:
+#ifdef SISFBACCEL
+		sw = sisfb_accel ? &fbcon_sis32 : &fbcon_cfb32;
+#else
 		sw = &fbcon_cfb32;
-		display->dispsw_data = fbcon_cmap.cfb32;
+#endif
+		display->dispsw_data = sis_fbcon_cmap.cfb32;
 		break;
 #endif
 	   default:
@@ -687,1922 +769,2349 @@
 	display->dispsw = &sisfb_sw;
 	restore_flags(flags);
 
+#ifdef SISFB_PAN
+        if(sisfb_ypan) {
+  	    /* display->scrollmode = SCROLL_YPAN; - not defined */
+	} else {
+	    display->scrollmode = SCROLL_YREDRAW;
+	    sisfb_sw.bmove = fbcon_redraw_bmove;
+	}
+#else
 	display->scrollmode = SCROLL_YREDRAW;
 	sisfb_sw.bmove = fbcon_redraw_bmove;
+#endif
 }
 
 static void sisfb_do_install_cmap(int con, struct fb_info *info)
 {
-	if (con != currcon)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+	if (con != info->currcon)
 		return;
 
-	if (fb_display[con].cmap.len)
-		fb_set_cmap(&fb_display[con].cmap, 1, sis_setcolreg, info);
-	else
-		fb_set_cmap(fb_default_cmap(video_cmap_len), 1,
-			    sis_setcolreg, info);
+        if (fb_display[con].cmap.len)
+                fb_set_cmap(&fb_display[con].cmap, 1, info);
+        else
+		fb_set_cmap(fb_default_cmap(ivideo.video_cmap_len), 1, info);
+#else
+        if (con != currcon)
+		return;
+
+        if (fb_display[con].cmap.len)
+		fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info);
+        else
+		fb_set_cmap(fb_default_cmap(ivideo.video_cmap_len), 1,
+			    sisfb_setcolreg, info);
+#endif
 }
+#endif
 
+/* ------ functions for all series ------ */
 
-/* --------------- Chip-dependent Routines --------------------------- */
+#ifdef SISFB_PAN
+static void sisfb_pan_var(struct fb_var_screeninfo *var)
+{
+	unsigned int base;
 
-#ifdef CONFIG_FB_SIS_300 /* for SiS 300/630/540/730 */
-static int sisfb_get_dram_size_300(void)
+	TWDEBUG("Inside pan_var");
+
+        base = var->yoffset * var->xres_virtual + var->xoffset;
+
+        /* calculate base bpp dep. */
+        switch(var->bits_per_pixel) {
+        case 16:
+        	base >>= 1;
+        	break;
+	case 32:
+            	break;
+	case 8:
+        default:
+        	base >>= 2;
+            	break;
+        }
+	
+	outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
+
+        outSISIDXREG(SISCR, 0x0D, base & 0xFF);
+	outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
+	outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
+	if(sisvga_engine == SIS_315_VGA) {
+		setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
+	}
+        if(ivideo.disp_state & DISPTYPE_DISP2) {
+		orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01);
+        	outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
+        	outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
+        	outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
+		if(sisvga_engine == SIS_315_VGA) {
+			setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
+		}
+        }
+	TWDEBUG("End of pan_var");
+}
+#endif
+
+static void sisfb_crtc_to_var(struct fb_var_screeninfo *var)
 {
-	struct pci_dev *pdev = NULL;
-	int pdev_valid = 0;
-	u8  pci_data, reg;
-	u16 nbridge_id;
+	u16 VRE, VBE, VRS, VBS, VDE, VT;
+	u16 HRE, HBE, HRS, HBS, HDE, HT;
+	u8  sr_data, cr_data, cr_data2, cr_data3, mr_data;
+	int A, B, C, D, E, F, temp;
+	double hrate, drate;
 
-	switch (ivideo.chip) {
-	   case SIS_540:
-		nbridge_id = PCI_DEVICE_ID_SI_540;
-		break;
-	   case SIS_630:
-		nbridge_id = PCI_DEVICE_ID_SI_630;
+	TWDEBUG("Inside crtc_to_var");
+	inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data);
+
+	if (sr_data & SIS_INTERLACED_MODE)
+		var->vmode = FB_VMODE_INTERLACED;
+	else
+		var->vmode = FB_VMODE_NONINTERLACED;
+
+	switch ((sr_data & 0x1C) >> 2) {
+	   case SIS_8BPP_COLOR_MODE:
+		var->bits_per_pixel = 8;
 		break;
-	   case SIS_730:
-		nbridge_id = PCI_DEVICE_ID_SI_730;
+	   case SIS_16BPP_COLOR_MODE:
+		var->bits_per_pixel = 16;
 		break;
-	   default:
-		nbridge_id = 0;
+	   case SIS_32BPP_COLOR_MODE:
+		var->bits_per_pixel = 32;
 		break;
 	}
 
-	if (nbridge_id == 0) {  /* 300 */
-		vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
-		ivideo.video_size =
-		        ((unsigned int) ((vgarb(SEQ_DATA) & SIS_DRAM_SIZE_MASK) + 1) << 20);
-	} else {		/* 540, 630, 730 */
-		pci_for_each_dev(pdev) {
-			if ((pdev->vendor == PCI_VENDOR_ID_SI) 
-				&& (pdev->device == nbridge_id)) {
-				pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data);
-				pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
-				ivideo.video_size = (unsigned int)(1 << (pci_data+21));
-				pdev_valid = 1;
-	
-				reg = SIS_DATA_BUS_64 << 6;
-				vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
-				switch (pci_data) {
-				   case BRI_DRAM_SIZE_2MB:
-					reg |= SIS_DRAM_SIZE_2MB;
-					break;
-				   case BRI_DRAM_SIZE_4MB:
-					reg |= SIS_DRAM_SIZE_4MB;
-					break;
-				   case BRI_DRAM_SIZE_8MB:
-					reg |= SIS_DRAM_SIZE_8MB;
-					break;
-				   case BRI_DRAM_SIZE_16MB:
-					reg |= SIS_DRAM_SIZE_16MB;
-					break;
-				   case BRI_DRAM_SIZE_32MB:
-					reg |= SIS_DRAM_SIZE_32MB;
-					break;
-				   case BRI_DRAM_SIZE_64MB:
-					reg |= SIS_DRAM_SIZE_64MB;
-					break;
-				}
-				vgawb(SEQ_DATA, reg);
-				break;
-			}  
-		}   
-	
-		if (!pdev_valid)
-			return -1;
+	switch (var->bits_per_pixel) {
+	   case 8:
+		var->red.length = 6;
+		var->green.length = 6;
+		var->blue.length = 6;
+		ivideo.video_cmap_len = 256;
+		break;
+	   case 16:
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		ivideo.video_cmap_len = 16;
+		break;
+	   case 24:
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		ivideo.video_cmap_len = 16;
+		break;
+	   case 32:
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		ivideo.video_cmap_len = 16;
+		break;
 	}
-	return 0;
-}
 
-static void sisfb_detect_VB_connect_300()
-{
-	u8 sr16, sr17, cr32, temp;
+	inSISIDXREG(SISSR, 0x0A, sr_data);
 
-	vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_17);
-	sr17 = vgarb(SEQ_DATA);
-	vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR32);
-	cr32 = vgarb(CRTC_DATA);
+        inSISIDXREG(SISCR, 0x06, cr_data);
 
-	ivideo.TV_plug = ivideo.TV_type = 0;
-	if ((sr17 & 0x0F) && (ivideo.chip != SIS_300)) {
-		if ((sr17 & 0x01) && !sisfb_crt1off)
-			sisfb_crt1off = 0;
-		else {
-			if (sr17 & 0x0E)
-				sisfb_crt1off = 1;
-			else
-				sisfb_crt1off = 0;
-		}
+        inSISIDXREG(SISCR, 0x07, cr_data2);
 
-		if (sisfb_crt2type != -1)
-			/* TW: override detected CRT2 type */
-			ivideo.disp_state = sisfb_crt2type;
-		else if (sr17 & 0x08 )
-			ivideo.disp_state = DISPTYPE_CRT2;
-		else if (sr17 & 0x02)
-			ivideo.disp_state = DISPTYPE_LCD;
-		else if (sr17 & 0x04)
-			ivideo.disp_state = DISPTYPE_TV;
-		else
-			ivideo.disp_state = 0;
+	VT = (cr_data & 0xFF) | ((u16) (cr_data2 & 0x01) << 8) |
+	     ((u16) (cr_data2 & 0x20) << 4) | ((u16) (sr_data & 0x01) << 10);
+	A = VT + 2;
 
-		if (sr17 & 0x20)
-			ivideo.TV_plug = TVPLUG_SVIDEO;
-		else if (sr17 & 0x10)
-			ivideo.TV_plug = TVPLUG_COMPOSITE;
+	inSISIDXREG(SISCR, 0x12, cr_data);
 
-		vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_16);
-		sr16 = vgarb(SEQ_DATA);
-		if (sr16 & 0x20)
-			ivideo.TV_type = TVMODE_PAL;
-		else
-			ivideo.TV_type = TVMODE_NTSC;
-	} else {
-		if ((cr32 & SIS_CRT1) && !sisfb_crt1off)
-			sisfb_crt1off = 0;
-		else {
-			if (cr32 & 0x5F)
-				sisfb_crt1off = 1;
-			else
-				sisfb_crt1off = 0;
-		}
+	VDE = (cr_data & 0xff) | ((u16) (cr_data2 & 0x02) << 7) |
+	      ((u16) (cr_data2 & 0x40) << 3) | ((u16) (sr_data & 0x02) << 9);
+	E = VDE + 1;
 
-		if (sisfb_crt2type != -1)
-			/* TW: override detected CRT2 type */
-			ivideo.disp_state = sisfb_crt2type;
-		else if (cr32 & SIS_VB_CRT2)
-			ivideo.disp_state = DISPTYPE_CRT2;
-		else if (cr32 & SIS_VB_LCD)
-			ivideo.disp_state = DISPTYPE_LCD;
-		else if (cr32 & SIS_VB_TV)
-			ivideo.disp_state = DISPTYPE_TV;
-		else
-			ivideo.disp_state = 0;
+	inSISIDXREG(SISCR, 0x10, cr_data);
 
-		/* TW: Detect TV plug & type anyway */
-		if (cr32 & SIS_VB_HIVISION) {
-			ivideo.TV_type = TVMODE_HIVISION;
-			ivideo.TV_plug = TVPLUG_SVIDEO;
-		}
-		else if (cr32 & SIS_VB_SVIDEO)
-			ivideo.TV_plug = TVPLUG_SVIDEO;
-		else if (cr32 & SIS_VB_COMPOSITE)
-			ivideo.TV_plug = TVPLUG_COMPOSITE;
-		else if (cr32 & SIS_VB_SCART)
-			ivideo.TV_plug = TVPLUG_SCART;
+	VRS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x04) << 6) |
+	      ((u16) (cr_data2 & 0x80) << 2) | ((u16) (sr_data & 0x08) << 7);
+	F = VRS + 1 - E;
 
-		if (ivideo.TV_type == 0) {
-			// Eden Chen
-			//temp = *((u8 *)(sishw_ext.VirtualRomBase+0x52));
-			//if (temp&0x40) {
-			//	temp=*((u8 *)(sishw_ext.VirtualRomBase+0x53));
-				//} else {
-			vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP);
-			temp = vgarb(SEQ_DATA);
-			//}
-			// ~Eden Chen
-			if (temp & 0x01)
-				ivideo.TV_type = TVMODE_PAL;
-			else
-				ivideo.TV_type = TVMODE_NTSC;
-		}
-	}
+	inSISIDXREG(SISCR, 0x15, cr_data);
 
-	/* TW: Copy forceCRT1 option to CRT1off if option is given */
-    	if (sisfb_forcecrt1 != -1) {
-		vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_17);
-    		sr17 = vgarb(SEQ_DATA);
-    		if (sisfb_forcecrt1) {
-			sisfb_crt1off=0;
-			sr17 |= 0x80;
-		} else {
-			sisfb_crt1off=1;
-			sr17 &= ~0x80;
-		}
-		vgawb(SEQ_DATA, sr17);
-    	}
-}
+	inSISIDXREG(SISCR, 0x09, cr_data3);
 
-static void sisfb_get_VB_type_300(void)
-{
-	u8 reg;
+	VBS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x08) << 5) |
+	      ((u16) (cr_data3 & 0x20) << 4) | ((u16) (sr_data & 0x04) << 8);
 
-	if (ivideo.chip != SIS_300) {
-		if (!sisfb_has_VB_300()) {
-			vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR37);
-			reg = vgarb(CRTC_DATA);
+	inSISIDXREG(SISCR, 0x16, cr_data);
 
-			switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) {
-			   case SIS_EXTERNAL_CHIP_SIS301:
-				ivideo.hasVB = HASVB_301;
-				break;
-			   case SIS_EXTERNAL_CHIP_LVDS:
-				ivideo.hasVB = HASVB_LVDS;
-				break;
-			   case SIS_EXTERNAL_CHIP_TRUMPION:
-				ivideo.hasVB = HASVB_TRUMPION;
-				break;
-			   case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
-				ivideo.hasVB = HASVB_LVDS_CHRONTEL;
-				break;
-			   case SIS_EXTERNAL_CHIP_CHRONTEL:
-				ivideo.hasVB = HASVB_CHRONTEL;
-				break;
-			   default:
-				break;
-			}
-		}
-	} else {
-		sisfb_has_VB_300();
+	VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4);
+	temp = VBE - ((E - 1) & 511);
+	B = (temp > 0) ? temp : (temp + 512);
+
+	inSISIDXREG(SISCR, 0x11, cr_data);
+
+	VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
+	temp = VRE - ((E + F - 1) & 31);
+	C = (temp > 0) ? temp : (temp + 32);
+
+	D = B - F - C;
+
+
+        var->yres = E;
+#ifndef SISFB_PAN
+	var->yres_virtual = E;
+#endif
+	/* TW: We have to report the physical dimension to the console! */
+	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+		var->yres <<= 1;
+#ifndef SISFB_PAN
+		var->yres_virtual <<= 1;
+#endif
 	}
-	//sishw_ext.hasVB = ivideo.hasVB;
+	/* TW end */
+	var->upper_margin = D;
+	var->lower_margin = F;
+	var->vsync_len = C;
+
+	inSISIDXREG(SISSR, 0x0b, sr_data);
+
+	inSISIDXREG(SISCR, 0x00, cr_data);
+
+	HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
+	A = HT + 5;
+
+	inSISIDXREG(SISCR, 0x01, cr_data);
+
+	HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6);
+	E = HDE + 1;
+
+	inSISIDXREG(SISCR, 0x04, cr_data);
+
+	HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2);
+	F = HRS - E - 3;
+
+	inSISIDXREG(SISCR, 0x02, cr_data);
+
+	HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
+
+	inSISIDXREG(SISSR, 0x0c, sr_data);
+
+	inSISIDXREG(SISCR, 0x03, cr_data);
+
+	inSISIDXREG(SISCR, 0x15, cr_data2);
+
+	HBE = (cr_data & 0x1f) | ((u16) (cr_data2 & 0x80) >> 2) |
+	      ((u16) (sr_data & 0x03) << 6);
+	HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
+
+	temp = HBE - ((E - 1) & 255);
+	B = (temp > 0) ? temp : (temp + 256);
+
+	temp = HRE - ((E + F + 3) & 63);
+	C = (temp > 0) ? temp : (temp + 64);
+
+	D = B - F - C;
+
+	var->xres = var->xres_virtual = E * 8;
+	var->left_margin = D * 8;
+	var->right_margin = F * 8;
+	var->hsync_len = C * 8;
+
+	var->activate = FB_ACTIVATE_NOW;
+
+	var->sync = 0;
+
+	mr_data = inSISREG(SISMISCR);
+#if 0
+	mr_data = vgarb(0x1C);
+#endif
+	if (mr_data & 0x80)
+		var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+	else
+		var->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+	if (mr_data & 0x40)
+		var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+	else
+		var->sync |= FB_SYNC_HOR_HIGH_ACT;
+
+	VT += 2;
+	VT <<= 1;
+	HT = (HT + 5) * 8;
+
+	hrate = (double) ivideo.refresh_rate * (double) VT / 2;
+	drate = hrate * HT;
+	var->pixclock = (u32) (1E12 / drate);
+
+#ifdef SISFB_PAN
+	if(sisfb_ypan) {
+	    var->yres_virtual = ivideo.heapstart / (var->xres * (var->bits_per_pixel >> 3));
+	    if(var->yres_virtual <= var->yres) {
+	        var->yres_virtual = var->yres;
+	    }
+	} else
+#endif
+	   var->yres_virtual = var->yres;
+
+        TWDEBUG("end of crtc_to_var");
 }
 
-static int sisfb_has_VB_300(void)
+/* ------------------ Public Routines -------------------------------- */
+
+/* -------- functions only for for 2.4 series ------- */
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info)
 {
-	// Eden Chen
-	//u8 sr38, sr39, vb_chipid;
-	u8 vb_chipid;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
+	int err;
+	unsigned int cols, rows;
 
-	//vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP);
-	//sr38 = vgarb(SEQ_DATA);
-	//vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP2);
-	//sr39 = vgarb(SEQ_DATA);
-	vgawb(VB_PART4_ADR, 0x0);
-	vb_chipid = vgarb(VB_PART4_DATA);
-        
-	switch (vb_chipid) {
-	   case 0x01:
-		ivideo.hasVB = HASVB_301;
-		break;
-	   case 0x02:
-		ivideo.hasVB = HASVB_302;
-		break;
-	   case 0x03:
-		ivideo.hasVB = HASVB_303;
-		break;
-	   default:
-		ivideo.hasVB = HASVB_NONE;
-		return FALSE;
+	fb_display[con].var.activate = FB_ACTIVATE_NOW;
+        if(sisfb_do_set_var(var, con == currcon, info)) {
+		sisfb_crtc_to_var(var);
+		return -EINVAL;
 	}
-	return TRUE;
 
-	//if (
-	//	( (ivideo.chip == SIS_300) && (sr38 & 0x20) )
-	//	||
-	//	( (ivideo.chip == SIS_540) && (sr38 & 0x20) && (!(sr39 & 0x80)) )
-	//	||
-	//	( (ivideo.chip == SIS_630 ) && (sr38 & 0x20) && (!(sr39 & 0x80)) && 
-	//		((ivideo.revision_id & 0xf0) < 0x30) && (vb_chipid == 1) ) 
-	//	||
-	//	( (ivideo.chip == SIS_630 ) && ((ivideo.revision_id & 0xf0) >= 0x30) && 
-	//		(vb_chipid == 1) ) 
-	//	||
-	//	( (ivideo.chip == SIS_730) && (vb_chipid == 1) ) /* 730 */
-	//) {
-	//	ivideo.hasVB = HASVB_301;
-	//	return TRUE;
-	//} else {
-	//	ivideo.hasVB = HASVB_NONE;
-	//	return FALSE;
-	//}
+	sisfb_crtc_to_var(var);
+
+	sisfb_set_disp(con, var, info);
+
+	if(info->changevar)
+		(*info->changevar) (con);
+
+	if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
+		return err;
+
+	sisfb_do_install_cmap(con, info);
+
+	cols = sisbios_mode[sisfb_mode_idx].cols;
+	rows = sisbios_mode[sisfb_mode_idx].rows;
+	vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
 
-	// ~Eden Chen
+	return 0;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon
+#endif
 }
-#endif  /* CONFIG_FB_SIS_300 */
 
-#ifdef CONFIG_FB_SIS_315    /* for SiS 315H/315PRO/550/650/740 */
-static int sisfb_get_dram_size_315(void)
+static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info)
 {
-	struct pci_dev *pdev = NULL;
-	int pdev_valid = 0;
-	u8  pci_data;
-	u8  reg = 0;
-
-	if (ivideo.chip == SIS_550 || ivideo.chip == SIS_650) {
-#ifdef LINUXBIOS
-		pci_for_each_dev(pdev) {
-			if ( (pdev->vendor == PCI_VENDOR_ID_SI)
-				&& ( (pdev->device == PCI_DEVICE_ID_SI_550)
-				  || (pdev->device == PCI_DEVICE_ID_SI_650))) {
-				pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS,
-				                     &pci_data);
-				pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
-				ivideo.video_size =
-				    (unsigned int)(1 << (pci_data+21));
-				pdev_valid = 1;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
+        if (con == currcon)
+		return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
 
-				/* TW: Initialize SR14 "by hand" */
-				vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
-				reg = vgarb(SEQ_DATA) & 0xC0;
+	else if (fb_display[con].cmap.len)
+		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+	else
+		fb_copy_cmap(fb_default_cmap(ivideo.video_cmap_len), cmap, kspc ? 0 : 2);
 
-				switch (pci_data) {
-				//case BRI_DRAM_SIZE_2MB:
-				//	reg |= (SIS315_DRAM_SIZE_2MB << 4); break;
-				   case BRI_DRAM_SIZE_4MB:
-					reg |= SIS550_DRAM_SIZE_4MB;
-					break;
-				   case BRI_DRAM_SIZE_8MB:
-					reg |= SIS550_DRAM_SIZE_8MB;
-					break;
-				   case BRI_DRAM_SIZE_16MB:
-					reg |= SIS550_DRAM_SIZE_16MB;
-					break;
-				   case BRI_DRAM_SIZE_32MB:
-					reg |= SIS550_DRAM_SIZE_32MB;
-					break;
-				   case BRI_DRAM_SIZE_64MB:
-					reg |= SIS550_DRAM_SIZE_64MB;
-					break;
-				   /* case BRI_DRAM_SIZE_128MB:
-					reg |= (SIS315_DRAM_SIZE_128MB << 4); break; */
-				}
+	return 0;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon
+#endif
+}
 
-			        /* TODO : set Dual channel and bus width bits here */
+static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info)
+{
+	int err;
 
-				vgawb(SEQ_DATA, reg);
-				break;
-			}  
-		}
-	
-		if (!pdev_valid)
-			return -1;
+	if (!fb_display[con].cmap.len) {
+		err = fb_alloc_cmap(&fb_display[con].cmap, ivideo.video_cmap_len, 0);
+		if (err)
+			return err;
+	}
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+	if (con == info->currcon)
+		return fb_set_cmap(cmap, kspc, info);
 #else
-		vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
-		reg = vgarb(SEQ_DATA);
-		switch (reg & SIS550_DRAM_SIZE_MASK) {
-		   case SIS550_DRAM_SIZE_4MB:
-			ivideo.video_size = 0x400000;   break;
-		   case SIS550_DRAM_SIZE_8MB:
-			ivideo.video_size = 0x800000;   break;
-		   case SIS550_DRAM_SIZE_16MB:
-			ivideo.video_size = 0x1000000;  break;
-		   case SIS550_DRAM_SIZE_24MB:
-			ivideo.video_size = 0x1800000;  break;
-		   case SIS550_DRAM_SIZE_32MB:
-			ivideo.video_size = 0x2000000;	break;
-		   case SIS550_DRAM_SIZE_64MB:
-			ivideo.video_size = 0x4000000;	break;
-		   case SIS550_DRAM_SIZE_96MB:
-			ivideo.video_size = 0x6000000;	break;
-		   case SIS550_DRAM_SIZE_128MB:
-			ivideo.video_size = 0x8000000;	break;
-		   case SIS550_DRAM_SIZE_256MB:
-			ivideo.video_size = 0x10000000;	break;
-		   default:
-		        /* TW: Some 550 BIOSes don't seem to initialize SR14 correctly (if at all),
-			 *     do it the hard way ourselves in this case. Unfortunately, we don't
-			 *     support 24, 48, 96 and other "odd" amounts here. I don't know if
-			 *     this work-around is required for 650/740 as well, but do it in case
-			 *     for now.
-			 */
-		        printk(KERN_INFO
-			       "sisfb: Warning: Could not determine memory size, "
-			       "now reading from PCI config\n");
-			pdev_valid = 0;
-			pci_for_each_dev(pdev) {
-			   if ( (pdev->vendor == PCI_VENDOR_ID_SI)
-			         && (    (pdev->device == PCI_DEVICE_ID_SI_550)
-				      || (pdev->device == PCI_DEVICE_ID_SI_650) ) ) {
-				pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS,
-				                     &pci_data);
-				pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
-				ivideo.video_size = (unsigned int)(1 << (pci_data+21));
-				pdev_valid = 1;
-				/* TW: Initialize SR14=IND_SIS_DRAM_SIZE */
-				vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
-				reg = vgarb(SEQ_DATA) & 0xC0;
-				switch (pci_data) {
-				   case BRI_DRAM_SIZE_4MB:
-					reg |= SIS550_DRAM_SIZE_4MB;  break;
-				   case BRI_DRAM_SIZE_8MB:
-					reg |= SIS550_DRAM_SIZE_8MB;  break;
-				   case BRI_DRAM_SIZE_16MB:
-					reg |= SIS550_DRAM_SIZE_16MB; break;
-				   case BRI_DRAM_SIZE_32MB:
-					reg |= SIS550_DRAM_SIZE_32MB; break;
-				   case BRI_DRAM_SIZE_64MB:
-					reg |= SIS550_DRAM_SIZE_64MB; break;
-				   /* case BRI_DRAM_SIZE_128MB:
-					reg |= (SIS315_DRAM_SIZE_128MB << 4); break; */
-				   default:
-				   	printk(KERN_INFO "sisfb: Unable to determine memory size, giving up.\n");
-					return -1;
-				}
-				vgawb(SEQ_DATA, reg);
-			   }
-			}
-			if (!pdev_valid) {
-				printk(KERN_INFO "sisfb: Total confusion - No SiS PCI VGA device found?!\n");
-				return -1;
-			}
-			return 0;
-		}
+        if (con == currcon)
+		return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info);
 #endif
-		return 0;
-	} else {	/* 315 */
-		vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
-		reg = vgarb(SEQ_DATA);
-		switch ((reg & SIS315_DRAM_SIZE_MASK) >> 4) {
-		   case SIS315_DRAM_SIZE_2MB:
-			ivideo.video_size = 0x200000;
-			break;
-		   case SIS315_DRAM_SIZE_4MB:
-			ivideo.video_size = 0x400000;
-			break;
-		   case SIS315_DRAM_SIZE_8MB:
-			ivideo.video_size = 0x800000;
-			break;
-		   case SIS315_DRAM_SIZE_16MB:
-			ivideo.video_size = 0x1000000;
-			break;
-		   case SIS315_DRAM_SIZE_32MB:
-			ivideo.video_size = 0x2000000;
-			break;
-		   case SIS315_DRAM_SIZE_64MB:
-			ivideo.video_size = 0x4000000;
-			break;
-		   case SIS315_DRAM_SIZE_128MB:
-			ivideo.video_size = 0x8000000;
+	else
+		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+	return 0;
+}
+#endif
+
+/* -------- functions only for 2.5 series ------- */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+static int sisfb_set_par(struct fb_info *info)
+{
+	int err;
+
+	TWDEBUG("inside set_par\n");
+        if((err = sisfb_do_set_var(&info->var, 1, info)))
+		return err;
+
+	sisfb_get_fix(&info->fix, info->currcon, info);
+
+	TWDEBUG("end of set_par");
+	return 0;
+}
+
+static int sisfb_check_var(struct fb_var_screeninfo *var,
+                            struct fb_info *info)
+{
+	unsigned int htotal =
+		var->left_margin + var->xres + var->right_margin +
+		var->hsync_len;
+	unsigned int vtotal = 0;
+	double drate = 0, hrate = 0;
+	int found_mode = 0;
+	int refresh_rate, search_idx;
+
+	TWDEBUG("Inside check_var");
+
+	if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
+		vtotal = var->upper_margin + var->yres + var->lower_margin +
+		         var->vsync_len;   /* TW */
+		vtotal <<= 1;
+	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+		vtotal = var->upper_margin + var->yres + var->lower_margin +
+		         var->vsync_len;   /* TW */
+		vtotal <<= 2;
+	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+		vtotal = var->upper_margin + (var->yres/2) + var->lower_margin +
+		         var->vsync_len;   /* TW */
+		/* var->yres <<= 1; */ /* TW */
+	} else 	vtotal = var->upper_margin + var->yres + var->lower_margin +
+		         var->vsync_len;
+
+	if(!(htotal) || !(vtotal)) {
+		SISFAIL("sisfb: no valid timing data");
+	}
+
+	drate = 1E12 / var->pixclock;
+	hrate = drate / htotal;
+	refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
+
+	/* TW: Calculation wrong for 1024x600 - force it to 60Hz */
+	if((var->xres == 1024) && (var->yres == 600)) refresh_rate = 60;
+
+	search_idx = 0;
+	while( (sisbios_mode[search_idx].mode_no != 0) &&
+	       (sisbios_mode[search_idx].xres <= var->xres) ) {
+		if( (sisbios_mode[search_idx].xres == var->xres) &&
+		    (sisbios_mode[search_idx].yres == var->yres) &&
+		    (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
+			found_mode = 1;
 			break;
-		   default:
-			return -1;
 		}
+		search_idx++;
 	}
 
-	reg &= SIS315_DUAL_CHANNEL_MASK;
-	reg >>= 2;
-	switch (reg) {
-	   case SIS315_SINGLE_CHANNEL_2_RANK:
-		ivideo.video_size <<= 1;
+	/* TW: TODO: Check the refresh rate */
+
+	if(found_mode)
+		search_idx = sisfb_validate_mode(search_idx);
+	else
+		SISFAIL("sisfb: no valid mode");
+
+       	if(sisfb_mode_idx < 0) {
+		SISFAIL("sisfb: mode not supported");
+	}
+
+	/* TW: Horiz-panning not supported */
+	if(var->xres != var->xres_virtual)
+		var->xres_virtual = var->xres;
+
+	if(!sisfb_ypan) {
+		if(var->yres != var->yres_virtual)
+			var->yres_virtual = var->yres;
+	} else {
+	   /* TW: Now patch yres_virtual if we use panning */
+	   /* *** May I do this? *** */
+	   var->yres_virtual = ivideo.heapstart / (var->xres * (var->bits_per_pixel >> 3));
+	    if(var->yres_virtual <= var->yres) {
+	    	/* TW: Paranoia check */
+	        var->yres_virtual = var->yres;
+	    }
+	}
+	TWDEBUG("end of check_var");
+	return 0;
+}
+#endif
+
+/* -------- functions for all series ------- */
+
+static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			 struct fb_info *info)
+{
+	TWDEBUG("inside get_fix");
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+	strcpy(fix->id, sis_fb_info.modename);
+
+	fix->smem_start = ivideo.video_base;
+
+        /* TW */
+        if((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
+	    if (ivideo.video_size > 0x1000000) {
+	        fix->smem_len = 0xc00000;
+	    } else if (ivideo.video_size > 0x800000)
+		fix->smem_len = 0x800000;
+	    else
+		fix->smem_len = 0x400000;
+        } else
+		fix->smem_len = sisfb_mem * 1024;
+
+	fix->type        = video_type;
+	fix->type_aux    = 0;
+	if(ivideo.video_bpp == 8)
+		fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	else
+		fix->visual = FB_VISUAL_TRUECOLOR;
+	fix->xpanstep    = 0;
+#ifdef SISFB_PAN
+        if(sisfb_ypan) 	 fix->ypanstep = 1;
+#endif
+	fix->ywrapstep   = 0;
+	fix->line_length = ivideo.video_linelength;
+	fix->mmio_start  = ivideo.mmio_base;
+	fix->mmio_len    = sisfb_mmio_size;
+	fix->accel       = FB_ACCEL_SIS_GLAMOUR;
+	fix->reserved[0] = ivideo.video_size & 0xFFFF;
+	fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
+	fix->reserved[2] = sisfb_caps;
+	TWDEBUG("end of get_fix");
+	return 0;
+}
+
+static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info)
+{
+	TWDEBUG("inside get_var");
+	if(con == -1)
+		memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
+	else
+		*var = fb_display[con].var;
+
+	/* JennyLee 2001126: for FSTN */
+	if (var->xres == 320 && var->yres == 480)
+		var->yres = 240;
+	/* ~JennyLee */
+	TWDEBUG("end of get_var");
+	return 0;
+}
+
+#ifdef SISFB_PAN
+static int sisfb_pan_display(struct fb_var_screeninfo *var, int con,
+		struct fb_info* info)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
+	TWDEBUG("inside pan_display");
+	if (var->vmode & FB_VMODE_YWRAP) {
+		if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
+			return -EINVAL;
+	} else {
+		if (var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
+		    var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+			return -EINVAL;
+	}
+
+        if (con == currcon)
+		sisfb_pan_var(var);
+
+	fb_display[con].var.xoffset = var->xoffset;
+	fb_display[con].var.yoffset = var->yoffset;
+	if (var->vmode & FB_VMODE_YWRAP)
+		fb_display[con].var.vmode |= FB_VMODE_YWRAP;
+	else
+		fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
+
+	TWDEBUG("end of pan_display");
+	return 0;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon
+#endif
+}
+#endif
+
+static int sisfb_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, unsigned long arg, int con,
+		       struct fb_info *info)
+{
+	TWDEBUG("inside ioctl");
+	switch (cmd) {
+	   case FBIO_ALLOC:
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		sis_malloc((struct sis_memreq *) arg);
 		break;
-	   case SIS315_DUAL_CHANNEL_1_RANK:
-		ivideo.video_size <<= 1;
+	   case FBIO_FREE:
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		sis_free(*(unsigned long *) arg);
 		break;
-	   case SIS315_ASYM_DDR:		/* TW: DDR asymentric */
-		ivideo.video_size += ivideo.video_size/2;
+	   case FBIOGET_GLYPH:
+                sis_get_glyph(info,(SIS_GLYINFO *) arg);
+		break;
+	   case FBIOGET_HWCINFO:
+		{
+			unsigned long *hwc_offset = (unsigned long *) arg;
+
+			if (sisfb_caps & HW_CURSOR_CAP)
+				*hwc_offset = sisfb_hwcursor_vbase -
+				    (unsigned long) ivideo.video_vbase;
+			else
+				*hwc_offset = 0;
+
+			break;
+		}
+	   case FBIOPUT_MODEINFO:
+		{
+			struct mode_info *x = (struct mode_info *)arg;
+
+			ivideo.video_bpp        = x->bpp;
+			ivideo.video_width      = x->xres;
+			ivideo.video_height     = x->yres;
+			ivideo.video_vwidth     = x->v_xres;
+			ivideo.video_vheight    = x->v_yres;
+			ivideo.org_x            = x->org_x;
+			ivideo.org_y            = x->org_y;
+			ivideo.refresh_rate     = x->vrate;
+			ivideo.video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
+			switch(ivideo.video_bpp) {
+        		case 8:
+            			ivideo.DstColor = 0x0000;
+	    			ivideo.SiS310_AccelDepth = 0x00000000;
+				ivideo.video_cmap_len = 256;
+            			break;
+        		case 16:
+            			ivideo.DstColor = 0x8000;
+            			ivideo.SiS310_AccelDepth = 0x00010000;
+				ivideo.video_cmap_len = 16;
+            			break;
+        		case 32:
+            			ivideo.DstColor = 0xC000;
+	    			ivideo.SiS310_AccelDepth = 0x00020000;
+				ivideo.video_cmap_len = 16;
+            			break;
+			default:
+				ivideo.video_cmap_len = 16;
+		       	 	printk(KERN_ERR "sisfb: Unsupported accel depth %d", ivideo.video_bpp);
+				break;
+    			}
+
+			break;
+		}
+	   case FBIOGET_DISPINFO:
+		sis_dispinfo((struct ap_data *)arg);
 		break;
+	   case SISFB_GET_INFO:  /* TW: New for communication with X driver */
+	        {
+			sisfb_info *x = (sisfb_info *)arg;
+
+			x->sisfb_id = SISFB_ID;
+			x->sisfb_version = VER_MAJOR;
+			x->sisfb_revision = VER_MINOR;
+			x->sisfb_patchlevel = VER_LEVEL;
+			x->chip_id = ivideo.chip_id;
+			x->memory = ivideo.video_size / 1024;
+			x->heapstart = ivideo.heapstart / 1024;
+			x->fbvidmode = sisfb_mode_no;
+			x->sisfb_caps = sisfb_caps;
+			x->sisfb_tqlen = 512; /* yet unused */
+	                break;
+		}
+	   default:
+		return -EINVAL;
 	}
+	TWDEBUG("end of ioctl");
+	return 0;
+
+}
 
+static int sisfb_mmap(struct fb_info *info, struct file *file,
+		      struct vm_area_struct *vma)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
+	struct fb_var_screeninfo var;
+	unsigned long start;
+	unsigned long off;
+	u32 len;
+
+	TWDEBUG("inside mmap");
+	if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT))  return -EINVAL;
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+
+	start = (unsigned long) ivideo.video_base;
+	len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
+
+	if (off >= len) {
+		off -= len;
+		sisfb_get_var(&var, currcon, info);
+		if(var.accel_flags) return -EINVAL;
+
+		start = (unsigned long) ivideo.mmio_base;
+		len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size);
+	}
+
+	start &= PAGE_MASK;
+	if((vma->vm_end - vma->vm_start + off) > len)	return -EINVAL;
+
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+
+#if defined(__i386__) || defined(__x86_64__)
+	if (boot_cpu_data.x86 > 3)
+		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
+				vma->vm_page_prot))
+#else	/* TW: 2.5 API */
+	if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start,
+				vma->vm_page_prot))
+#endif
+		return -EAGAIN;
+
+        TWDEBUG("end of mmap");
+	return 0;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon
+#endif
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+static struct fb_ops sisfb_ops = {
+	.owner        =	THIS_MODULE,
+	.fb_set_var   =	gen_set_var,
+	.fb_get_cmap  =	gen_get_cmap,
+	.fb_set_cmap  =	gen_set_cmap,
+
+	.fb_check_var = sisfb_check_var,
+	.fb_set_par   = sisfb_set_par,
+        .fb_setcolreg = sisfb_setcolreg,
+        .fb_blank     = sisfb_blank,
+#ifdef SISFB_PAN
+        .fb_pan_display = sisfb_pan_display,
+#endif
+        .fb_fillrect  = fbcon_sis_fillrect,
+	.fb_copyarea  = fbcon_sis_copyarea,
+	.fb_imageblit = my_cfb_imageblit,
+	.fb_ioctl     =	sisfb_ioctl,
+	.fb_mmap      =	sisfb_mmap,
+};
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+static struct fb_ops sisfb_ops = {
+	owner:		THIS_MODULE,
+	fb_get_fix:	sisfb_get_fix,
+	fb_get_var:	sisfb_get_var,
+	fb_set_var:	sisfb_set_var,
+	fb_get_cmap:	sisfb_get_cmap,
+	fb_set_cmap:	sisfb_set_cmap,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+        fb_setcolreg:   sisfb_setcolreg,
+        fb_blank:       sisfb_blank,
+#endif
+#ifdef SISFB_PAN
+        fb_pan_display:	sisfb_pan_display,
+#endif
+	fb_ioctl:	sisfb_ioctl,
+	fb_mmap:	sisfb_mmap,
+};
+#endif
+
+/* ------------ Interface to the low level console driver -------------*/
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)	/* --------- for 2.4 series --------- */
+static int sisfb_update_var(int con, struct fb_info *info)
+{
+#ifdef SISFB_PAN
+        sisfb_pan_var(&fb_display[con].var);
+#endif
 	return 0;
 }
 
-static void sisfb_detect_VB_connect_315(void)
-{
-	u8 sr17, cr32, temp;
+static int sisfb_switch(int con, struct fb_info *info)
+{
+	int cols, rows;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
+
+        if(fb_display[currcon].cmap.len)
+		fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);
+
+	fb_display[con].var.activate = FB_ACTIVATE_NOW;
+
+	if(!memcmp(&fb_display[con].var, &fb_display[currcon].var,
+	                           sizeof(struct fb_var_screeninfo))) {
+		currcon = con;
+		return 1;
+	}
+
+	currcon = con;
 
-	vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR32);
-	cr32 = vgarb(CRTC_DATA);
+	sisfb_do_set_var(&fb_display[con].var, 1, info);
 
-	ivideo.TV_plug = ivideo.TV_type = 0;
-	if ((cr32 & SIS_CRT1) && !sisfb_crt1off)
-		sisfb_crt1off = 0;
-	else {
-		if (cr32 & 0x5F)   
-			sisfb_crt1off = 1;
-		else
-			sisfb_crt1off = 0;
-	}
+	sisfb_set_disp(con, &fb_display[con].var, info);
 
-	if (sisfb_crt2type != -1)
-		/* TW: Override with option */
-		ivideo.disp_state = sisfb_crt2type;
-	else if (cr32 & SIS_VB_CRT2)
-		ivideo.disp_state = DISPTYPE_CRT2;
-	else if (cr32 & SIS_VB_LCD)
-		ivideo.disp_state = DISPTYPE_LCD;
-	else if (cr32 & SIS_VB_TV)
-		ivideo.disp_state = DISPTYPE_TV;
-	else
-		ivideo.disp_state = 0;
+	sisfb_do_install_cmap(con, info);
 
-	if (cr32 & SIS_VB_HIVISION) {
-		ivideo.TV_type = TVMODE_HIVISION;
-		ivideo.TV_plug = TVPLUG_SVIDEO;
-	} else if (cr32 & SIS_VB_SVIDEO)
-		ivideo.TV_plug = TVPLUG_SVIDEO;
-	else if (cr32 & SIS_VB_COMPOSITE)
-		ivideo.TV_plug = TVPLUG_COMPOSITE;
-	else if (cr32 & SIS_VB_SCART)
-		ivideo.TV_plug = TVPLUG_SCART;
+	cols = sisbios_mode[sisfb_mode_idx].cols;
+	rows = sisbios_mode[sisfb_mode_idx].rows;
+	vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
 
-	if (ivideo.TV_type == 0) {
-		vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP);
-		temp = vgarb(SEQ_DATA);
-		if (temp & 0x01)
-			ivideo.TV_type = TVMODE_PAL;
-		else
-			ivideo.TV_type = TVMODE_NTSC;
-	}
+	sisfb_update_var(con, info);
 
-	/* TW: Copy forceCRT1 option to CRT1off if option is given */
-    	if (sisfb_forcecrt1 != -1) {
-		vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_17);
-    		sr17 = vgarb(SEQ_DATA);
-    		if (sisfb_forcecrt1) {
-			sisfb_crt1off=0;
-			sr17 |= 0x80;
-		} else {
-			sisfb_crt1off=1;
-			sr17 &= ~0x80;
-		}
-		vgawb(SEQ_DATA, sr17);
-    	}
+	return 1;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon
+#endif
 }
 
-static void sisfb_get_VB_type_315(void)
+static void sisfb_blank(int blank, struct fb_info *info)
 {
 	u8 reg;
 
-	/* 550 has LVDS-like FSTN bridge (?) */
-	if (ivideo.chip == SIS_550) {
-		if (!sisfb_has_VB_315()) {
-			vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR37);
-			reg = vgarb(CRTC_DATA);
+	inSISIDXREG(SISCR, 0x17, reg);
 
-			switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) {
-			   case SIS_EXTERNAL_CHIP_SIS301:
-				ivideo.hasVB = HASVB_301;
-				break;
-			   case SIS_EXTERNAL_CHIP_LVDS:
-				ivideo.hasVB = HASVB_LVDS;
-				break;
-			   case SIS_EXTERNAL_CHIP_TRUMPION:
-				ivideo.hasVB = HASVB_TRUMPION;
-				break;
-			   case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
-				ivideo.hasVB = HASVB_LVDS_CHRONTEL;
-				break;
-			   case SIS_EXTERNAL_CHIP_CHRONTEL:
-				ivideo.hasVB = HASVB_CHRONTEL;
-				break;
-			   default:
-				break;
-			}
-		}
-	} else {
-		sisfb_has_VB_315();
-	}
+	if(blank > 0)
+		reg &= 0x7f;
+	else
+		reg |= 0x80;
+
+	outSISIDXREG(SISCR, 0x17, reg);
 }
+#endif
 
-static int sisfb_has_VB_315(void)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)	/* ---------- for 2.5 series -------- */
+static int sisfb_blank(int blank, struct fb_info *info)
 {
-	u8 vb_chipid;
-
-	vgawb(VB_PART4_ADR, 0x0);
-	vb_chipid = vgarb(VB_PART4_DATA);
+	u8 reg;
 
-	switch (vb_chipid) {
-	   case 0x01:
-		ivideo.hasVB = HASVB_301;
-		break;
-	   case 0x02:
-		ivideo.hasVB = HASVB_302;
-		break;
-	   case 0x03:
-		ivideo.hasVB = HASVB_303;
-		break;
-	   default:
-		ivideo.hasVB = HASVB_NONE;
-		return FALSE;
-	}
-	// Eden Chen
-	//sishw_ext.hasVB = ivideo.hasVB;
-	// ~Eden Chen
-	return TRUE;
-}
-#endif   /* CONFIG_FB_SIS_315 */
+	inSISIDXREG(SISCR, 0x17, reg);
 
-/* --------------------- Heap Routines ------------------------------- */
+	if(blank > 0)
+		reg &= 0x7f;
+	else
+		reg |= 0x80;
 
-static int sisfb_heap_init(void)
-{
-	SIS_OH *poh;
-	u8 temp=0;
-#ifdef CONFIG_FB_SIS_315
-	int            agp_enabled = 1;
-	u32            agp_size;
-	unsigned long *cmdq_baseport = 0;
-	unsigned long *read_port = 0;
-	unsigned long *write_port = 0;
-	SIS_CMDTYPE    cmd_type;
-#ifndef AGPOFF
-	agp_kern_info  *agp_info;
-	agp_memory     *agp;
-	u32            agp_phys;
-#endif
+	outSISIDXREG(SISCR, 0x17, reg);
+        return(0);
+}
 #endif
-/* TW: If more than 8MB videoRAM detected, let our heap start at 8MB. If
- *     there is less RAM available, let it start at 4MB. This can be overruled
- *     by mem parameter.
- *     This is for avoiding a clash with X driver which uses the beginning
- *     of the videoRAM. To limit size of X framebuffer, use Option MaxXFBMem
- *     in XF86Config-4.
- *     The heap start can also be specified by parameter "mem" when starting the sisfb
- *     driver. sisfb mem=1024 lets heap starts at 1MB, etc.
- */
-      /*karl:10/01/2001*/
-      if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
-	if (ivideo.video_size > 0x800000) {
-		sisfb_heap_start =
-		    (unsigned long) ivideo.video_vbase + 0x800000;
-		printk(KERN_INFO "sisfb: Memory heap starting at 8192K\n");
-	} else {
-		sisfb_heap_start =
-		    (unsigned long) ivideo.video_vbase + 0x400000;
-		printk(KERN_INFO "sisfb: Memory heap starting at 4096K\n");
-	}
-     } else {
-   	   sisfb_heap_start =
-	       (unsigned long) (ivideo.video_vbase + (sisfb_mem * 1024));
-	   printk(KERN_INFO "sisfb: Memory heap starting at %dK\n", sisfb_mem);
-     }
 
-     sisfb_heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;
-     sisfb_heap_size = sisfb_heap_end - sisfb_heap_start;
+/* --------------- Chip-dependent Routines --------------------------- */
 
-#ifdef CONFIG_FB_SIS_315
-     if (sisvga_engine == SIS_315_VGA) {
-        /* TW: Now initlalize the 310 series' command queue mode.
-	 * On 310, there are three queue modes available which
-	 *     are chosen by setting bits 7:5 in SR26:
-	 * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
-	 *    track of the queue, the FIFO, command parsing and so
-	 *    on. This is the one comparable to the 300 series.
-	 * 2. VRAM queue mode (bit 6, 0x40). In this case, one will
-	 *    have to do queue management himself. Register 0x85c4 will
-	 *    hold the location of the next free queue slot, 0x85c8
-	 *    is the "queue read pointer" whose way of working is
-	 *    unknown to me. Anyway, this mode would require a
-	 *    translation of the MMIO commands to some kind of
-	 *    accelerator assembly and writing these commands
-	 *    to the memory location pointed to by 0x85c4.
-	 *    We will not use this, as nobody knows how this
-	 *    "assembly" works, and as it would require a complete
-	 *    re-write of the accelerator code.
-	 * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the
-	 *    queue in AGP memory space.
-	 *
-	 * SR26 bit 4 is called "Bypass H/W queue".
-	 * SR26 bit 1 is called "Enable Command Queue Auto Correction"
-	 * SR26 bit 0 resets the queue
-	 * Size of queue memory is encoded in bits 3:2 like this:
-	 *    00  (0x00)  512K
-	 *    01  (0x04)  1M
-	 *    10  (0x08)  2M
-	 *    11  (0x0C)  4M
-	 * The queue location is to be written to 0x85C0.
-	 *
-         */
-	cmdq_baseport = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_PHYBASE);
-	write_port    = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_WRITEPORT);
-	read_port     = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_READPORT);
+#ifdef CONFIG_FB_SIS_300 /* for SiS 300/630/540/730 */
 
-	DPRINTK("AGP base: 0x%p, read: 0x%p, write: 0x%p\n", cmdq_baseport, read_port, write_port);
+static int sisfb_get_dram_size_300(void)
+{
+	struct pci_dev *pdev = NULL;
+	int pdev_valid = 0;
+	u8  pci_data, reg;
+	u16 nbridge_id;
 
-	agp_size  = COMMAND_QUEUE_AREA_SIZE;
+	switch (ivideo.chip) {
+	   case SIS_540:
+		nbridge_id = PCI_DEVICE_ID_SI_540;
+		break;
+	   case SIS_630:
+		nbridge_id = PCI_DEVICE_ID_SI_630;
+		break;
+	   case SIS_730:
+		nbridge_id = PCI_DEVICE_ID_SI_730;
+		break;
+	   default:
+		nbridge_id = 0;
+		break;
+	}
 
-#ifndef AGPOFF
-	if (sisfb_queuemode == AGP_CMD_QUEUE) {
-		agp_info = vmalloc(sizeof(agp_kern_info));
-		memset((void*)agp_info, 0x00, sizeof(agp_kern_info));
-		agp_copy_info(agp_info);
+	if (nbridge_id == 0) {  /* 300 */
 
-		agp_backend_acquire();
+	        inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE,reg);
+		ivideo.video_size =
+		        ((unsigned int) ((reg & SIS_DRAM_SIZE_MASK) + 1) << 20);
 
-		agp = agp_allocate_memory(COMMAND_QUEUE_AREA_SIZE/PAGE_SIZE,
-					  AGP_NORMAL_MEMORY);
-		if (agp == NULL) {
-			DPRINTK("sisfb: Allocating AGP buffer failed.\n");
-			agp_enabled = 0;
-		} else {
-			if (agp_bind_memory(agp, agp->pg_start) != 0) {
-				DPRINTK("sisfb: AGP: Failed to bind memory\n");
-				/* TODO: Free AGP memory here */
-				agp_enabled = 0;
-			} else {
-				agp_enable(0);
-			}
-		}
-	}
-#else
-	agp_enabled= 0;
-#endif
+	} else {		/* 540, 630, 730 */
 
-	/* TW: Now select the queue mode */
+		pci_for_each_dev(pdev) {
 
-	if ((agp_enabled) && (sisfb_queuemode == AGP_CMD_QUEUE)) {
-		cmd_type = AGP_CMD_QUEUE;
-		printk(KERN_INFO "sisfb: Using AGP queue mode\n");
-/*	} else if (sisfb_heap_size >= COMMAND_QUEUE_AREA_SIZE)  */
-        } else if (sisfb_queuemode == VM_CMD_QUEUE) {
-		cmd_type = VM_CMD_QUEUE;
-		printk(KERN_INFO "sisfb: Using VRAM queue mode\n");
-	} else {
-		printk(KERN_INFO "sisfb: Using MMIO queue mode\n");
-		cmd_type = MMIO_CMD;
+			if ((pdev->vendor == PCI_VENDOR_ID_SI) 
+				       && (pdev->device == nbridge_id)) {
+				pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data);
+				pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
+				ivideo.video_size = (unsigned int)(1 << (pci_data+21));
+				pdev_valid = 1;
+	
+				reg = SIS_DATA_BUS_64 << 6;
+				switch (pci_data) {
+				   case BRI_DRAM_SIZE_2MB:
+					reg |= SIS_DRAM_SIZE_2MB;
+					break;
+				   case BRI_DRAM_SIZE_4MB:
+					reg |= SIS_DRAM_SIZE_4MB;
+					break;
+				   case BRI_DRAM_SIZE_8MB:
+					reg |= SIS_DRAM_SIZE_8MB;
+					break;
+				   case BRI_DRAM_SIZE_16MB:
+					reg |= SIS_DRAM_SIZE_16MB;
+					break;
+				   case BRI_DRAM_SIZE_32MB:
+					reg |= SIS_DRAM_SIZE_32MB;
+					break;
+				   case BRI_DRAM_SIZE_64MB:
+					reg |= SIS_DRAM_SIZE_64MB;
+					break;
+				}
+				outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+				break;
+			}  
+		}   
+	
+		if (!pdev_valid)  return -1;
 	}
+	return 0;
+}
 
-	switch (agp_size) {
-	   case 0x80000:
-		temp = SIS_CMD_QUEUE_SIZE_512k;
-		break;
-	   case 0x100000:
-		temp = SIS_CMD_QUEUE_SIZE_1M;
-		break;
-	   case 0x200000:
-		temp = SIS_CMD_QUEUE_SIZE_2M;
-		break;
-	   case 0x400000:
-		temp = SIS_CMD_QUEUE_SIZE_4M;
-		break;
+static void sisfb_detect_VB_connect_300()
+{
+	u8 sr16, sr17, cr32, temp;
+
+	ivideo.TV_plug = ivideo.TV_type = 0;
+
+        switch(ivideo.hasVB) {
+	  case HASVB_LVDS_CHRONTEL:
+	  case HASVB_CHRONTEL:
+	     SiS_SenseCh();
+	     break;
+	  case HASVB_301:
+	  case HASVB_302:
+	     SiS_Sense30x();
+	     break;
 	}
 
-	switch (cmd_type) {
-	   case AGP_CMD_QUEUE:
-#ifndef AGPOFF
-		DPRINTK("sisfb: AGP buffer base:0x%lx, offset:0x%x, size: %dK\n",
-			agp_info->aper_base, agp->physical, agp_size/1024);
+	inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_17, sr17);
+        inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR32, cr32);
 
-		agp_phys = agp_info->aper_base + agp->physical;
+	if ((sr17 & 0x0F) && (ivideo.chip != SIS_300)) {
 
-		vgawb(CRTC_ADR, IND_SIS_AGP_IO_PAD);
-		vgawb(CRTC_DATA, 0);
-		vgawb(CRTC_DATA, SIS_AGP_2X);
+		if ((sr17 & 0x01) && !sisfb_crt1off)
+			sisfb_crt1off = 0;
+		else {
+			if (sr17 & 0x0E)
+				sisfb_crt1off = 1;
+			else
+				sisfb_crt1off = 0;
+		}
 
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD);
-		vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD);
+		if (sisfb_crt2type != -1)
+			/* TW: override detected CRT2 type */
+			ivideo.disp_state = sisfb_crt2type;
+		else if (sr17 & 0x08 )
+			ivideo.disp_state = DISPTYPE_CRT2;
+		else if (sr17 & 0x02)
+			ivideo.disp_state = DISPTYPE_LCD;
+		else if (sr17 & 0x04)
+			ivideo.disp_state = DISPTYPE_TV;
+		else
+			ivideo.disp_state = 0;
 
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
-		vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET);
+		if(sisfb_tvplug != -1)
+			/* PR/TW: override detected TV type */
+			ivideo.TV_plug = sisfb_tvplug;
+		else if (sr17 & 0x20)
+			ivideo.TV_plug = TVPLUG_SVIDEO;
+		else if (sr17 & 0x10)
+			ivideo.TV_plug = TVPLUG_COMPOSITE;
 
-		*write_port = *read_port;
+		inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_16, sr16);
+		if (sr16 & 0x20)
+			ivideo.TV_type = TVMODE_PAL;
+		else
+			ivideo.TV_type = TVMODE_NTSC;
 
-		temp |= SIS_AGP_CMDQUEUE_ENABLE;
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
-		vgawb(SEQ_DATA, temp);
+	} else {
 
-		*cmdq_baseport = agp_phys;
+		if ((cr32 & SIS_CRT1) && !sisfb_crt1off)
+			sisfb_crt1off = 0;
+		else {
+			if (cr32 & 0x5F)
+				sisfb_crt1off = 1;
+			else
+				sisfb_crt1off = 0;
+		}
 
-		sisfb_caps |= AGP_CMD_QUEUE_CAP;
-#endif
-		break;
+		if (sisfb_crt2type != -1)
+			/* TW: override detected CRT2 type */
+			ivideo.disp_state = sisfb_crt2type;
+		else if (cr32 & SIS_VB_CRT2)
+			ivideo.disp_state = DISPTYPE_CRT2;
+		else if (cr32 & SIS_VB_LCD)
+			ivideo.disp_state = DISPTYPE_LCD;
+		else if (cr32 & SIS_VB_TV)
+			ivideo.disp_state = DISPTYPE_TV;
+		else
+			ivideo.disp_state = 0;
 
-	   case VM_CMD_QUEUE:
-		sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
-		sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
+		/* TW: Detect TV plug & type */
+		if(sisfb_tvplug != -1)
+			/* PR/TW: override with option */
+		        ivideo.TV_plug = sisfb_tvplug;
+#ifdef oldHV
+		else if (cr32 & SIS_VB_HIVISION) {
+			ivideo.TV_type = TVMODE_HIVISION;
+			ivideo.TV_plug = TVPLUG_SVIDEO;
+		}
+#endif
+		else if (cr32 & SIS_VB_SVIDEO)
+			ivideo.TV_plug = TVPLUG_SVIDEO;
+		else if (cr32 & SIS_VB_COMPOSITE)
+			ivideo.TV_plug = TVPLUG_COMPOSITE;
+		else if (cr32 & SIS_VB_SCART)
+			ivideo.TV_plug = TVPLUG_SCART;
 
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD);
-		vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD);
+		if (ivideo.TV_type == 0) {
+		        inSISIDXREG(SISSR, IND_SIS_POWER_ON_TRAP, temp);
+			if (temp & 0x01)
+				ivideo.TV_type = TVMODE_PAL;
+			else
+				ivideo.TV_type = TVMODE_NTSC;
+		}
 
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
-		vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET);
+	}
 
-		*write_port = *read_port;
+	/* TW: Copy forceCRT1 option to CRT1off if option is given */
+    	if (sisfb_forcecrt1 != -1) {
+    		if(sisfb_forcecrt1) sisfb_crt1off = 0;
+		else                sisfb_crt1off = 1;
+    	}
+}
 
-		temp |= SIS_VRAM_CMDQUEUE_ENABLE;
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
-		vgawb(SEQ_DATA, temp);
+static void sisfb_get_VB_type_300(void)
+{
+	u8 reg;
 
-		*cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;
+	if(ivideo.chip != SIS_300) {
+		if(!sisfb_has_VB_300()) {
+		        inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR37, reg);
+			switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) {
+			   case SIS_EXTERNAL_CHIP_SIS301:
+				ivideo.hasVB = HASVB_301;
+				break;
+			   case SIS_EXTERNAL_CHIP_LVDS:
+				ivideo.hasVB = HASVB_LVDS;
+				break;
+			   case SIS_EXTERNAL_CHIP_TRUMPION:
+				ivideo.hasVB = HASVB_TRUMPION;
+				break;
+			   case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
+				ivideo.hasVB = HASVB_LVDS_CHRONTEL;
+				break;
+			   case SIS_EXTERNAL_CHIP_CHRONTEL:
+				ivideo.hasVB = HASVB_CHRONTEL;
+				break;
+			   default:
+				break;
+			}
+		}
+	} else {
+		sisfb_has_VB_300();
+	}
+}
 
-		sisfb_caps |= VM_CMD_QUEUE_CAP;
+static int sisfb_has_VB_300(void)
+{
+	u8 vb_chipid;
 
-		DPRINTK("sisfb: VM Cmd Queue offset = 0x%lx, size is %dK\n",
-			*cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
+	inSISIDXREG(SISPART4, 0x00, vb_chipid);
+	switch (vb_chipid) {
+	   case 0x01:
+		ivideo.hasVB = HASVB_301;
+		break;
+	   case 0x02:
+		ivideo.hasVB = HASVB_302;
 		break;
+	   case 0x03:
+		ivideo.hasVB = HASVB_303;
+		break;
+	   default:
+		ivideo.hasVB = HASVB_NONE;
+		return FALSE;
+	}
+	return TRUE;
 
-	   default:  /* MMIO */
-	   	/* TW: This previously only wrote SIS_MMIO_CMD_ENABLE
-		 * to IND_SIS_CMDQUEUE_SET. I doubt that this is
-		 * enough. Reserve memory in any way.
-		 */
-	   	sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
-		sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
+}
 
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD);
-		vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD);
+#endif  /* CONFIG_FB_SIS_300 */
 
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
-		vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET);
 
-		*write_port = *read_port;
+#ifdef CONFIG_FB_SIS_315    /* for SiS 315/550/650/740 */
 
-		/* TW: Set Auto_Correction bit; this works in sisfb lite,
-		 * so why not.
-		 */
-		temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
-		vgawb(SEQ_DATA, temp);
+static int sisfb_get_dram_size_315(void)
+{
+	struct pci_dev *pdev = NULL;
+	int pdev_valid = 0;
+	u8  pci_data;
+	u8  reg = 0;
 
-		*cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;
+	if (ivideo.chip == SIS_550 || ivideo.chip == SIS_650) {
 
-		DPRINTK("sisfb: MMIO Cmd Queue offset = 0x%lx, size is %dK\n",
-			*cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
-		break;
-	}
-     } /* sisvga_engine = 315 */
-#endif
+#ifdef LINUXBIOS
 
-#ifdef CONFIG_FB_SIS_300
-     if (sisvga_engine == SIS_300_VGA) {
-  	    /* TW: Now initialize TurboQueue. TB is always located at the very
-	     * top of the video RAM. */
-	    if (sisfb_heap_size >= TURBO_QUEUE_AREA_SIZE) {
-		unsigned int  tqueue_pos;
-		u8 tq_state;
+		pci_for_each_dev(pdev) {
 
-		tqueue_pos = (ivideo.video_size -
-		       TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
-		temp = (u8) (tqueue_pos & 0xff);
-		vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_SET);
-		tq_state = vgarb(SEQ_DATA);
-		tq_state |= 0xf0;
-		tq_state &= 0xfc;
-		tq_state |= (u8) (tqueue_pos >> 8);
-		vgawb(SEQ_DATA, tq_state);
-		vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_ADR);
-		vgawb(SEQ_DATA, temp);
+			if ( (pdev->vendor == PCI_VENDOR_ID_SI)
+				&& ( (pdev->device == PCI_DEVICE_ID_SI_550) ||
+				     (pdev->device == PCI_DEVICE_ID_SI_650))) {
+				pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS,
+				                     &pci_data);
+				pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
+				ivideo.video_size = (unsigned int)(1 << (pci_data + 21));
+				pdev_valid = 1;
+
+				/* TW: Initialize SR14 "by hand" */
+				inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+				reg &= 0xC0;
+				switch (pci_data) {
+				   case BRI_DRAM_SIZE_4MB:
+					reg |= SIS550_DRAM_SIZE_4MB;
+					break;
+				   case BRI_DRAM_SIZE_8MB:
+					reg |= SIS550_DRAM_SIZE_8MB;
+					break;
+				   case BRI_DRAM_SIZE_16MB:
+					reg |= SIS550_DRAM_SIZE_16MB;
+					break;
+				   case BRI_DRAM_SIZE_32MB:
+					reg |= SIS550_DRAM_SIZE_32MB;
+					break;
+				   case BRI_DRAM_SIZE_64MB:
+					reg |= SIS550_DRAM_SIZE_64MB;
+					break;
+				}
+
+			        /* TODO: set Dual channel and bus width bits here */
+
+				outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+				break;
+			}  
+		}
+	
+		if (!pdev_valid)  return -1;
+
+#else
+
+                inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+		switch (reg & SIS550_DRAM_SIZE_MASK) {
+		   case SIS550_DRAM_SIZE_4MB:
+			ivideo.video_size = 0x400000;   break;
+		   case SIS550_DRAM_SIZE_8MB:
+			ivideo.video_size = 0x800000;   break;
+		   case SIS550_DRAM_SIZE_16MB:
+			ivideo.video_size = 0x1000000;  break;
+		   case SIS550_DRAM_SIZE_24MB:
+			ivideo.video_size = 0x1800000;  break;
+		   case SIS550_DRAM_SIZE_32MB:
+			ivideo.video_size = 0x2000000;	break;
+		   case SIS550_DRAM_SIZE_64MB:
+			ivideo.video_size = 0x4000000;	break;
+		   case SIS550_DRAM_SIZE_96MB:
+			ivideo.video_size = 0x6000000;	break;
+		   case SIS550_DRAM_SIZE_128MB:
+			ivideo.video_size = 0x8000000;	break;
+		   case SIS550_DRAM_SIZE_256MB:
+			ivideo.video_size = 0x10000000;	break;
+		   default:
+		        /* TW: Some 550 BIOSes don't seem to initialize SR14 correctly (if at all),
+			 *     do it the hard way ourselves in this case. Unfortunately, we don't
+			 *     support 24, 48, 96 and other "odd" amounts here.
+			 */
+		        printk(KERN_INFO
+			       "sisfb: Warning: Could not determine memory size, "
+			       "now reading from PCI config\n");
+			pdev_valid = 0;
 
-		sisfb_caps |= TURBO_QUEUE_CAP;
+			pci_for_each_dev(pdev) {
 
-		sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
-		sisfb_heap_size -= TURBO_QUEUE_AREA_SIZE;
-		DPRINTK("sisfb: TurboQueue start at 0x%lx, size is %dK\n",
-			sisfb_heap_end, TURBO_QUEUE_AREA_SIZE/1024);
-	    }
-     }
+			   if ( (pdev->vendor == PCI_VENDOR_ID_SI)
+			         && (pdev->device == PCI_DEVICE_ID_SI_550) ) {
+
+				pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS,
+				                     &pci_data);
+				pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
+				ivideo.video_size = (unsigned int)(1 << (pci_data+21));
+				pdev_valid = 1;
+				/* TW: Initialize SR14=IND_SIS_DRAM_SIZE */
+				inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+				reg &= 0xC0;
+				switch (pci_data) {
+				   case BRI_DRAM_SIZE_4MB:
+					reg |= SIS550_DRAM_SIZE_4MB;  break;
+				   case BRI_DRAM_SIZE_8MB:
+					reg |= SIS550_DRAM_SIZE_8MB;  break;
+				   case BRI_DRAM_SIZE_16MB:
+					reg |= SIS550_DRAM_SIZE_16MB; break;
+				   case BRI_DRAM_SIZE_32MB:
+					reg |= SIS550_DRAM_SIZE_32MB; break;
+				   case BRI_DRAM_SIZE_64MB:
+					reg |= SIS550_DRAM_SIZE_64MB; break;
+				   default:
+				   	printk(KERN_INFO "sisfb: Unable to determine memory size, giving up.\n");
+					return -1;
+				}
+				outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+			   }
+			}
+			if (!pdev_valid) {
+				printk(KERN_INFO "sisfb: Total confusion - No SiS PCI VGA device found?!\n");
+				return -1;
+			}
+			return 0;
+		}
 #endif
-        /* TW: Now reserve memory for the HWCursor. It is always located at the very
-               top of the videoRAM, right below the TB memory area (if used). */
-	if (sisfb_heap_size >= sisfb_hwcursor_size) {
-		sisfb_heap_end -= sisfb_hwcursor_size;
-		sisfb_heap_size -= sisfb_hwcursor_size;
-		sisfb_hwcursor_vbase = sisfb_heap_end;
+		return 0;
 
-		sisfb_caps |= HW_CURSOR_CAP;
+	} else {	/* 315 */
 
-		DPRINTK("sisfb: Hardware Cursor start at 0x%lx, size is %dK\n",
-			sisfb_heap_end, sisfb_hwcursor_size/1024);
+	        inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+		switch ((reg & SIS315_DRAM_SIZE_MASK) >> 4) {
+		   case SIS315_DRAM_SIZE_2MB:
+			ivideo.video_size = 0x200000;
+			break;
+		   case SIS315_DRAM_SIZE_4MB:
+			ivideo.video_size = 0x400000;
+			break;
+		   case SIS315_DRAM_SIZE_8MB:
+			ivideo.video_size = 0x800000;
+			break;
+		   case SIS315_DRAM_SIZE_16MB:
+			ivideo.video_size = 0x1000000;
+			break;
+		   case SIS315_DRAM_SIZE_32MB:
+			ivideo.video_size = 0x2000000;
+			break;
+		   case SIS315_DRAM_SIZE_64MB:
+			ivideo.video_size = 0x4000000;
+			break;
+		   case SIS315_DRAM_SIZE_128MB:
+			ivideo.video_size = 0x8000000;
+			break;
+		   default:
+			return -1;
+		}
 	}
 
-	sisfb_heap.poha_chain = NULL;
-	sisfb_heap.poh_freelist = NULL;
-
-	poh = sisfb_poh_new_node();
-
-	if (poh == NULL)
-		return 1;
-	
-	poh->poh_next = &sisfb_heap.oh_free;
-	poh->poh_prev = &sisfb_heap.oh_free;
-	poh->size = sisfb_heap_end - sisfb_heap_start + 1;
-	poh->offset = sisfb_heap_start - (unsigned long) ivideo.video_vbase;
-
-	DPRINTK("sisfb: Heap start:0x%p, end:0x%p, len=%dk\n",
-		(char *) sisfb_heap_start, (char *) sisfb_heap_end,
-		(unsigned int) poh->size / 1024);
-
-	DPRINTK("sisfb: First Node offset:0x%x, size:%dk\n",
-		(unsigned int) poh->offset, (unsigned int) poh->size / 1024);
-	
-	sisfb_heap.oh_free.poh_next = poh;
-	sisfb_heap.oh_free.poh_prev = poh;
-	sisfb_heap.oh_free.size = 0;
-	sisfb_heap.max_freesize = poh->size;
-
-	sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
-	sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
-	sisfb_heap.oh_used.size = SENTINEL;
+	reg &= SIS315_DUAL_CHANNEL_MASK;
+	reg >>= 2;
+	switch (reg) {
+	   case SIS315_SINGLE_CHANNEL_2_RANK:
+		ivideo.video_size <<= 1;
+		break;
+	   case SIS315_DUAL_CHANNEL_1_RANK:
+		ivideo.video_size <<= 1;
+		break;
+	   case SIS315_ASYM_DDR:		/* TW: DDR asymentric */
+		ivideo.video_size += (ivideo.video_size/2);
+		break;
+	}
 
 	return 0;
 }
 
-static SIS_OH *sisfb_poh_new_node(void)
+static void sisfb_detect_VB_connect_315(void)
 {
-	int i;
-	unsigned long cOhs;
-	SIS_OHALLOC *poha;
-	SIS_OH *poh;
-
-	if (sisfb_heap.poh_freelist == NULL) {
-		poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
+	u8 cr32, temp=0;
 
-		poha->poha_next = sisfb_heap.poha_chain;
-		sisfb_heap.poha_chain = poha;
+	ivideo.TV_plug = ivideo.TV_type = 0;
 
-		cOhs =
-		    (OH_ALLOC_SIZE -
-		     sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
+        switch(ivideo.hasVB) {
+	  case HASVB_LVDS_CHRONTEL:
+	  case HASVB_CHRONTEL:
+	     SiS_SenseCh();
+	     break;
+	  case HASVB_301:
+	  case HASVB_302:
+	     SiS_Sense30x();
+	     break;
+	}
 
-		poh = &poha->aoh[0];
-		for (i = cOhs - 1; i != 0; i--) {
-			poh->poh_next = poh + 1;
-			poh = poh + 1;
-		}
+	inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR32, cr32);
 
-		poh->poh_next = NULL;
-		sisfb_heap.poh_freelist = &poha->aoh[0];
+	if ((cr32 & SIS_CRT1) && !sisfb_crt1off)
+		sisfb_crt1off = 0;
+	else {
+		if (cr32 & 0x5F)   
+			sisfb_crt1off = 1;
+		else
+			sisfb_crt1off = 0;
 	}
 
-	poh = sisfb_heap.poh_freelist;
-	sisfb_heap.poh_freelist = poh->poh_next;
+	if (sisfb_crt2type != -1)
+		/* TW: Override with option */
+		ivideo.disp_state = sisfb_crt2type;
+	else if (cr32 & SIS_VB_CRT2)
+		ivideo.disp_state = DISPTYPE_CRT2;
+	else if (cr32 & SIS_VB_LCD)
+		ivideo.disp_state = DISPTYPE_LCD;
+	else if (cr32 & SIS_VB_TV)
+		ivideo.disp_state = DISPTYPE_TV;
+	else
+		ivideo.disp_state = 0;
 
-	return (poh);
-}
+	if(sisfb_tvplug != -1)
+		/* PR/TW: Override with option */
+	        ivideo.TV_plug = sisfb_tvplug;
+#ifdef oldHV
+	else if (cr32 & SIS_VB_HIVISION) {
+		ivideo.TV_type = TVMODE_HIVISION;
+		ivideo.TV_plug = TVPLUG_SVIDEO;
+	}
+#endif
+	else if (cr32 & SIS_VB_SVIDEO)
+		ivideo.TV_plug = TVPLUG_SVIDEO;
+	else if (cr32 & SIS_VB_COMPOSITE)
+		ivideo.TV_plug = TVPLUG_COMPOSITE;
+	else if (cr32 & SIS_VB_SCART)
+		ivideo.TV_plug = TVPLUG_SCART;
 
-static SIS_OH *sisfb_poh_allocate(unsigned long size)
-{
-	SIS_OH *pohThis;
-	SIS_OH *pohRoot;
-	int bAllocated = 0;
+	if(ivideo.TV_type == 0) {
+	    /* TW: PAL/NTSC changed for 650 */
+	    if(ivideo.chip <= SIS_315PRO) {
 
-	if (size > sisfb_heap.max_freesize) {
-		DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
-			(unsigned int) size / 1024);
-		return (NULL);
-	}
+                inSISIDXREG(SISCR, 0x38, temp);
+		if(temp & 0x10)
+			ivideo.TV_type = TVMODE_PAL;
+		else
+			ivideo.TV_type = TVMODE_NTSC;
 
-	pohThis = sisfb_heap.oh_free.poh_next;
+	    } else {
 
-	while (pohThis != &sisfb_heap.oh_free) {
-		if (size <= pohThis->size) {
-			bAllocated = 1;
-			break;
-		}
-		pohThis = pohThis->poh_next;
+	        inSISIDXREG(SISCR, 0x79, temp);
+		if(temp & 0x20)
+			ivideo.TV_type = TVMODE_PAL;
+		else
+			ivideo.TV_type = TVMODE_NTSC;
+	    }
 	}
 
-	if (!bAllocated) {
-		DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
-			(unsigned int) size / 1024);
-		return (NULL);
-	}
+	/* TW: Copy forceCRT1 option to CRT1off if option is given */
+    	if (sisfb_forcecrt1 != -1) {
+    		if (sisfb_forcecrt1) sisfb_crt1off = 0;
+		else   	             sisfb_crt1off = 1;
+    	}
+}
 
-	if (size == pohThis->size) {
-		pohRoot = pohThis;
-		sisfb_delete_node(pohThis);
-	} else {
-		pohRoot = sisfb_poh_new_node();
+static void sisfb_get_VB_type_315(void)
+{
+	u8 reg;
 
-		if (pohRoot == NULL) {
-			return (NULL);
+		if (!sisfb_has_VB_315()) {
+		        inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR37, reg);
+			/* TW: CR37 changed on 310/325 series */
+			switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) {
+			   case SIS_EXTERNAL_CHIP_SIS301:
+				ivideo.hasVB = HASVB_301;
+				break;
+			   case SIS310_EXTERNAL_CHIP_LVDS:
+				ivideo.hasVB = HASVB_LVDS;
+				break;
+			   case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
+				ivideo.hasVB = HASVB_LVDS_CHRONTEL;
+				break;
+			   default:
+				break;
+			}
 		}
+}
 
-		pohRoot->offset = pohThis->offset;
-		pohRoot->size = size;
-
-		pohThis->offset += size;
-		pohThis->size -= size;
-	}
-
-	sisfb_heap.max_freesize -= size;
 
-	pohThis = &sisfb_heap.oh_used;
-	sisfb_insert_node(pohThis, pohRoot);
+static int sisfb_has_VB_315(void)
+{
+	u8 vb_chipid;
 
-	return (pohRoot);
+	inSISIDXREG(SISPART4, 0x00, vb_chipid);
+	switch (vb_chipid) {
+	   case 0x01:
+		ivideo.hasVB = HASVB_301;
+		break;
+	   case 0x02:
+		ivideo.hasVB = HASVB_302;
+		break;
+	   case 0x03:
+		ivideo.hasVB = HASVB_303;
+		break;
+	   default:
+		ivideo.hasVB = HASVB_NONE;
+		return FALSE;
+	}
+	return TRUE;
 }
 
-static void sisfb_delete_node(SIS_OH *poh)
-{
-	SIS_OH *poh_prev;
-	SIS_OH *poh_next;
+#endif   /* CONFIG_FB_SIS_315 */
 
+/* -------------- Sensing routines --------------- */
 
-	poh_prev = poh->poh_prev;
-	poh_next = poh->poh_next;
+/* TW: Determine and detect attached devices on SiS30x */
+int
+SISDoSense(int tempbl, int tempbh, int tempcl, int tempch)
+{
+    int temp,i;
+
+    outSISIDXREG(SISPART4,0x11,tempbl);
+    temp = tempbh | tempcl;
+    setSISIDXREG(SISPART4,0x10,0xe0,temp);
+    for(i=0; i<10; i++) SiS_LongWait(&SiS_Pr);
+    tempch &= 0x7f;
+    inSISIDXREG(SISPART4,0x03,temp);
+    temp ^= 0x0e;
+    temp &= tempch;
+    return(temp);
+}
+
+void
+SiS_Sense30x(void)
+{
+  u8 backupP4_0d;
+  u8 testsvhs_tempbl, testsvhs_tempbh;
+  u8 testsvhs_tempcl, testsvhs_tempch;
+  u8 testcvbs_tempbl, testcvbs_tempbh;
+  u8 testcvbs_tempcl, testcvbs_tempch;
+  int myflag, result;
+
+  inSISIDXREG(SISPART4,0x0d,backupP4_0d);
+  outSISIDXREG(SISPART4,0x0d,(backupP4_0d | 0x04));
+
+  if(sisvga_engine == SIS_300_VGA) {
+
+        testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xb9;
+	testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xb3;
+	if((sishw_ext.ujVBChipID != VB_CHIP_301) &&
+	   (sishw_ext.ujVBChipID != VB_CHIP_302) ) {
+	   testsvhs_tempbh = 0x01; testsvhs_tempbl = 0x6b;
+	   testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x74;
+	}
+	inSISIDXREG(SISPART4,0x01,myflag);
+	if(myflag & 0x04) {
+	   testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xdd;
+	   testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xee;
+	}
+	testsvhs_tempch = 0x06;	testsvhs_tempcl = 0x04;
+	testcvbs_tempch = 0x08; testcvbs_tempcl = 0x04;
+
+  } else if((ivideo.chip == SIS_315) ||
+    	    (ivideo.chip == SIS_315H) ||
+	    (ivideo.chip == SIS_315PRO)) {
+
+        testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xb9;
+	testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xb3;
+	if((sishw_ext.ujVBChipID != VB_CHIP_301) &&
+	   (sishw_ext.ujVBChipID != VB_CHIP_302) ) {
+	      testsvhs_tempbh = 0x01; testsvhs_tempbl = 0x6b;
+	      testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x74;
+	}
+	inSISIDXREG(SISPART4,0x01,myflag);
+	if(myflag & 0x04) {
+	   testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xdd;
+	   testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xee;
+	}
+	testsvhs_tempch = 0x06;	testsvhs_tempcl = 0x04;
+	testcvbs_tempch = 0x08; testcvbs_tempcl = 0x04;
+
+    } else {
+
+        testsvhs_tempbh = 0x02; testsvhs_tempbl = 0x00;
+	testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x00;
+
+	testsvhs_tempch = 0x04;	testsvhs_tempcl = 0x08;
+	testcvbs_tempch = 0x08; testcvbs_tempcl = 0x08;
+
+    }
+
+    result = SISDoSense(testsvhs_tempbl, testsvhs_tempbh,
+                        testsvhs_tempcl, testsvhs_tempch);
+    if(result) {
+        printk(KERN_INFO "sisfb: Detected TV connected to SVHS output\n");
+        /* TW: So we can be sure that there IS a SVHS output */
+	ivideo.TV_plug = TVPLUG_SVIDEO;
+	orSISIDXREG(SISCR, 0x32, 0x02);
+    }
+
+    if(!result) {
+        result = SISDoSense(testcvbs_tempbl, testcvbs_tempbh,
+	                    testcvbs_tempcl, testcvbs_tempch);
+	if(result) {
+	    printk(KERN_INFO "sisfb: Detected TV connected to CVBS output\n");
+	    /* TW: So we can be sure that there IS a CVBS output */
+	    ivideo.TV_plug = TVPLUG_COMPOSITE;
+	    orSISIDXREG(SISCR, 0x32, 0x01);
+	}
+    }
+    SISDoSense(0, 0, 0, 0);
+
+    outSISIDXREG(SISPART4,0x0d,backupP4_0d);
+}
+
+/* TW: Determine and detect attached TV's on Chrontel */
+void
+SiS_SenseCh(void)
+{
 
-	poh_prev->poh_next = poh_next;
-	poh_next->poh_prev = poh_prev;
+   u8 temp1;
+#ifdef CONFIG_FB_SIS_315
+   u8 temp2;
+#endif
 
-	return;
-}
+   if(ivideo.chip < SIS_315H) {
 
-static void sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
-{
-	SIS_OH *pohTemp;
+#ifdef CONFIG_FB_SIS_300
+       SiS_Pr.SiS_IF_DEF_CH70xx = 1;		/* TW: Chrontel 7005 */
+       temp1 = SiS_GetCH700x(&SiS_Pr, 0x25);
+       if ((temp1 >= 50) && (temp1 <= 100)) {
+	   /* TW: Read power status */
+	   temp1 = SiS_GetCH700x(&SiS_Pr, 0x0e);
+	   if((temp1 & 0x03) != 0x03) {
+     	        /* TW: Power all outputs */
+		SiS_SetCH70xxANDOR(&SiS_Pr, 0x030E,0xF8);
+	   }
+	   /* TW: Sense connected TV devices */
+	   SiS_SetCH700x(&SiS_Pr, 0x0110);
+	   SiS_SetCH700x(&SiS_Pr, 0x0010);
+	   temp1 = SiS_GetCH700x(&SiS_Pr, 0x10);
+	   if(!(temp1 & 0x08)) {
+		printk(KERN_INFO
+		   "sisfb: Chrontel: Detected TV connected to SVHS output\n");
+		/* TW: So we can be sure that there IS a SVHS output */
+		ivideo.TV_plug = TVPLUG_SVIDEO;
+		orSISIDXREG(SISCR, 0x32, 0x02);
+	   } else if (!(temp1 & 0x02)) {
+		printk(KERN_INFO
+		   "sisfb: Chrontel: Detected TV connected to CVBS output\n");
+		/* TW: So we can be sure that there IS a CVBS output */
+		ivideo.TV_plug = TVPLUG_COMPOSITE;
+		orSISIDXREG(SISCR, 0x32, 0x01);
+	   } else {
+ 		SiS_SetCH70xxANDOR(&SiS_Pr, 0x010E,0xF8);
+	   }
+       } else if(temp1 == 0) {
+	  SiS_SetCH70xxANDOR(&SiS_Pr, 0x010E,0xF8);
+       }
+#endif
 
-	pohTemp = pohList->poh_next;
+   } else {
 
-	pohList->poh_next = poh;
-	pohTemp->poh_prev = poh;
+#ifdef CONFIG_FB_SIS_315
+	SiS_Pr.SiS_IF_DEF_CH70xx = 2;		/* TW: Chrontel 7019 */
+        temp1 = SiS_GetCH701x(&SiS_Pr, 0x49);
+	SiS_SetCH701x(&SiS_Pr, 0x2049);
+	SiS_DDC2Delay(&SiS_Pr, 0x96);
+	temp2 = SiS_GetCH701x(&SiS_Pr, 0x20);
+	temp2 |= 0x01;
+	SiS_SetCH701x(&SiS_Pr, (temp2 << 8) | 0x20);
+	SiS_DDC2Delay(&SiS_Pr, 0x96);
+	temp2 ^= 0x01;
+	SiS_SetCH701x(&SiS_Pr, (temp2 << 8) | 0x20);
+	SiS_DDC2Delay(&SiS_Pr, 0x96);
+	temp2 = SiS_GetCH701x(&SiS_Pr, 0x20);
+	SiS_SetCH701x(&SiS_Pr, (temp1 << 8) | 0x49);
+        temp1 = 0;
+	if(temp2 & 0x02) temp1 |= 0x01;
+	if(temp2 & 0x10) temp1 |= 0x01;
+	if(temp2 & 0x04) temp1 |= 0x02;
+	if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
+	switch(temp1) {
+	case 0x01:
+	     printk(KERN_INFO
+		"sisfb: Chrontel: Detected TV connected to CVBS output\n");
+	     ivideo.TV_plug = TVPLUG_COMPOSITE;
+	     orSISIDXREG(SISCR, 0x32, 0x01);
+             break;
+	case 0x02:
+	     printk(KERN_INFO
+		"sisfb: Chrontel: Detected TV connected to SVHS output\n");
+	     ivideo.TV_plug = TVPLUG_SVIDEO;
+	     orSISIDXREG(SISCR, 0x32, 0x02);
+             break;
+	case 0x04:
+	     /* TW: This should not happen */
+	     printk(KERN_INFO
+		"sisfb: Chrontel: Detected TV connected to SCART output!?\n");
+             break;
+	}
+#endif
 
-	poh->poh_prev = pohList;
-	poh->poh_next = pohTemp;
+   }
 }
 
-static SIS_OH *sisfb_poh_free(unsigned long base)
-{
-	SIS_OH *pohThis;
-	SIS_OH *poh_freed;
-	SIS_OH *poh_prev;
-	SIS_OH *poh_next;
-	unsigned long ulUpper;
-	unsigned long ulLower;
-	int foundNode = 0;
-
-	poh_freed = sisfb_heap.oh_used.poh_next;
 
-	while (poh_freed != &sisfb_heap.oh_used) {
-		if (poh_freed->offset == base) {
-			foundNode = 1;
-			break;
-		}
+/* --------------------- Heap Routines ------------------------------- */
 
-		poh_freed = poh_freed->poh_next;
+static int sisfb_heap_init(void)
+{
+	SIS_OH *poh;
+	u8 temp=0;
+#ifdef CONFIG_FB_SIS_315
+	int            agp_enabled = 1;
+	u32            agp_size;
+	unsigned long *cmdq_baseport = 0;
+	unsigned long *read_port = 0;
+	unsigned long *write_port = 0;
+	SIS_CMDTYPE    cmd_type;
+#ifndef AGPOFF
+	agp_kern_info  *agp_info;
+	agp_memory     *agp;
+	u32            agp_phys;
+#endif
+#endif
+/* TW: The heap start is either set manually using the "mem" parameter, or
+ *     defaults as follows:
+ *     -) If more than 16MB videoRAM available, let our heap start at 12MB.
+ *     -) If more than  8MB videoRAM available, let our heap start at  8MB.
+ *     -) If 4MB or less is available, let it start at 4MB.
+ *     This is for avoiding a clash with X driver which uses the beginning
+ *     of the videoRAM. To limit size of X framebuffer, use Option MaxXFBMem
+ *     in XF86Config-4.
+ *     The heap start can also be specified by parameter "mem" when starting the sisfb
+ *     driver. sisfb mem=1024 lets heap starts at 1MB, etc.
+ */
+     if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
+        if (ivideo.video_size > 0x1000000) {
+	        ivideo.heapstart = 0xc00000;
+	} else if (ivideo.video_size > 0x800000) {
+	        ivideo.heapstart = 0x800000;
+	} else {
+		ivideo.heapstart = 0x400000;
 	}
+     } else {
+           ivideo.heapstart = sisfb_mem * 1024;
+     }
+     sisfb_heap_start =
+	       (unsigned long) (ivideo.video_vbase + ivideo.heapstart);
+     printk(KERN_INFO "sisfb: Memory heap starting at %dK\n",
+     					(int)(ivideo.heapstart / 1024));
 
-	if (!foundNode)
-		return (NULL);
+     sisfb_heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;
+     sisfb_heap_size = sisfb_heap_end - sisfb_heap_start;
 
-	sisfb_heap.max_freesize += poh_freed->size;
+#ifdef CONFIG_FB_SIS_315
+     if (sisvga_engine == SIS_315_VGA) {
+        /* TW: Now initialize the 310 series' command queue mode.
+	 * On 310/325, there are three queue modes available which
+	 * are chosen by setting bits 7:5 in SR26:
+	 * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
+	 *    track of the queue, the FIFO, command parsing and so
+	 *    on. This is the one comparable to the 300 series.
+	 * 2. VRAM queue mode (bit 6, 0x40). In this case, one will
+	 *    have to do queue management himself. Register 0x85c4 will
+	 *    hold the location of the next free queue slot, 0x85c8
+	 *    is the "queue read pointer" whose way of working is
+	 *    unknown to me. Anyway, this mode would require a
+	 *    translation of the MMIO commands to some kind of
+	 *    accelerator assembly and writing these commands
+	 *    to the memory location pointed to by 0x85c4.
+	 *    We will not use this, as nobody knows how this
+	 *    "assembly" works, and as it would require a complete
+	 *    re-write of the accelerator code.
+	 * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the
+	 *    queue in AGP memory space.
+	 *
+	 * SR26 bit 4 is called "Bypass H/W queue".
+	 * SR26 bit 1 is called "Enable Command Queue Auto Correction"
+	 * SR26 bit 0 resets the queue
+	 * Size of queue memory is encoded in bits 3:2 like this:
+	 *    00  (0x00)  512K
+	 *    01  (0x04)  1M
+	 *    10  (0x08)  2M
+	 *    11  (0x0C)  4M
+	 * The queue location is to be written to 0x85C0.
+	 *
+         */
+	cmdq_baseport = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_PHYBASE);
+	write_port    = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_WRITEPORT);
+	read_port     = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_READPORT);
 
-	poh_prev = poh_next = NULL;
-	ulUpper = poh_freed->offset + poh_freed->size;
-	ulLower = poh_freed->offset;
+	DPRINTK("AGP base: 0x%p, read: 0x%p, write: 0x%p\n", cmdq_baseport, read_port, write_port);
 
-	pohThis = sisfb_heap.oh_free.poh_next;
+	agp_size  = COMMAND_QUEUE_AREA_SIZE;
 
-	while (pohThis != &sisfb_heap.oh_free) {
-		if (pohThis->offset == ulUpper) {
-			poh_next = pohThis;
-		}
-			else if ((pohThis->offset + pohThis->size) ==
-				 ulLower) {
-			poh_prev = pohThis;
-		}
-		pohThis = pohThis->poh_next;
-	}
+#ifndef AGPOFF
+	if (sisfb_queuemode == AGP_CMD_QUEUE) {
+		agp_info = vmalloc(sizeof(agp_kern_info));
+		memset((void*)agp_info, 0x00, sizeof(agp_kern_info));
+		agp_copy_info(agp_info);
 
-	sisfb_delete_node(poh_freed);
+		agp_backend_acquire();
 
-	if (poh_prev && poh_next) {
-		poh_prev->size += (poh_freed->size + poh_next->size);
-		sisfb_delete_node(poh_next);
-		sisfb_free_node(poh_freed);
-		sisfb_free_node(poh_next);
-		return (poh_prev);
+		agp = agp_allocate_memory(COMMAND_QUEUE_AREA_SIZE/PAGE_SIZE,
+					  AGP_NORMAL_MEMORY);
+		if (agp == NULL) {
+			DPRINTK("sisfb: Allocating AGP buffer failed.\n");
+			agp_enabled = 0;
+		} else {
+			if (agp_bind_memory(agp, agp->pg_start) != 0) {
+				DPRINTK("sisfb: AGP: Failed to bind memory\n");
+				/* TODO: Free AGP memory here */
+				agp_enabled = 0;
+			} else {
+				agp_enable(0);
+			}
+		}
 	}
+#else
+	agp_enabled = 0;
+#endif
 
-	if (poh_prev) {
-		poh_prev->size += poh_freed->size;
-		sisfb_free_node(poh_freed);
-		return (poh_prev);
+	/* TW: Now select the queue mode */
+
+	if ((agp_enabled) && (sisfb_queuemode == AGP_CMD_QUEUE)) {
+		cmd_type = AGP_CMD_QUEUE;
+		printk(KERN_INFO "sisfb: Using AGP queue mode\n");
+/*	} else if (sisfb_heap_size >= COMMAND_QUEUE_AREA_SIZE)  */
+        } else if (sisfb_queuemode == VM_CMD_QUEUE) {
+		cmd_type = VM_CMD_QUEUE;
+		printk(KERN_INFO "sisfb: Using VRAM queue mode\n");
+	} else {
+		printk(KERN_INFO "sisfb: Using MMIO queue mode\n");
+		cmd_type = MMIO_CMD;
 	}
 
-	if (poh_next) {
-		poh_next->size += poh_freed->size;
-		poh_next->offset = poh_freed->offset;
-		sisfb_free_node(poh_freed);
-		return (poh_next);
+	switch (agp_size) {
+	   case 0x80000:
+		temp = SIS_CMD_QUEUE_SIZE_512k;
+		break;
+	   case 0x100000:
+		temp = SIS_CMD_QUEUE_SIZE_1M;
+		break;
+	   case 0x200000:
+		temp = SIS_CMD_QUEUE_SIZE_2M;
+		break;
+	   case 0x400000:
+		temp = SIS_CMD_QUEUE_SIZE_4M;
+		break;
 	}
 
-	sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
+	switch (cmd_type) {
+	   case AGP_CMD_QUEUE:
+#ifndef AGPOFF
+		DPRINTK("sisfb: AGP buffer base = 0x%lx, offset = 0x%x, size = %dK\n",
+			agp_info->aper_base, agp->physical, agp_size/1024);
 
-	return (poh_freed);
-}
+		agp_phys = agp_info->aper_base + agp->physical;
 
-static void sisfb_free_node(SIS_OH *poh)
-{
-	if (poh == NULL) {
-		return;
-	}
+		outSISIDXREG(SISCR,  IND_SIS_AGP_IO_PAD, 0);
+		outSISIDXREG(SISCR,  IND_SIS_AGP_IO_PAD, SIS_AGP_2X);
 
-	poh->poh_next = sisfb_heap.poh_freelist;
-	sisfb_heap.poh_freelist = poh;
+                outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
 
-	return;
-}
+		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
 
-void sis_malloc(struct sis_memreq *req)
-{
-	SIS_OH *poh;
+		*write_port = *read_port;
 
-	poh = sisfb_poh_allocate(req->size);
+		temp |= SIS_AGP_CMDQUEUE_ENABLE;
+		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
 
-	if (poh == NULL) {
-		req->offset = 0;
-		req->size = 0;
-		DPRINTK("sisfb: Video RAM allocation failed\n");
-	} else {
-		DPRINTK("sisfb: Video RAM allocation succeeded: 0x%p\n",
-			(char *) (poh->offset +
-				  (unsigned long) ivideo.video_vbase));
+		*cmdq_baseport = agp_phys;
 
-		req->offset = poh->offset;
-		req->size = poh->size;
-	}
+		sisfb_caps |= AGP_CMD_QUEUE_CAP;
+#endif
+		break;
 
-}
+	   case VM_CMD_QUEUE:
+		sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
+		sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
 
-void sis_free(unsigned long base)
-{
-	SIS_OH *poh;
+		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
 
-	poh = sisfb_poh_free(base);
+		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
 
-	if (poh == NULL) {
-		DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
-			(unsigned int) base);
-	}
-}
+		*write_port = *read_port;
 
-/* ------------------ SetMode Routines ------------------------------- */
+		temp |= SIS_VRAM_CMDQUEUE_ENABLE;
+		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
 
-static void sisfb_pre_setmode(void)
-{
-	u8 cr30 = 0, cr31 = 0;
+		*cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;
 
-	vgawb(CRTC_ADR, 0x31);
-	cr31 = vgarb(CRTC_DATA) & ~0x60;
+		sisfb_caps |= VM_CMD_QUEUE_CAP;
 
-	switch (ivideo.disp_state & DISPTYPE_DISP2) {
-	   case DISPTYPE_CRT2:
-		printk(KERN_INFO "sisfb: CRT2 type is VGA\n");
-		cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
-		cr31 |= SIS_DRIVER_MODE;
-		break;
-	   case DISPTYPE_LCD:
-		printk(KERN_INFO "sisfb: CRT2 type is LCD\n");
-		cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
-		cr31 |= SIS_DRIVER_MODE;
+		DPRINTK("sisfb: VM Cmd Queue offset = 0x%lx, size is %dK\n",
+			*cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
 		break;
-	   case DISPTYPE_TV:
-		printk(KERN_INFO "sisfb: CRT2 type is TV\n");
-		if (ivideo.TV_type == TVMODE_HIVISION)
-			cr30 = (SIS_VB_OUTPUT_HIVISION | SIS_SIMULTANEOUS_VIEW_ENABLE);
-		else if (ivideo.TV_plug == TVPLUG_SVIDEO)
-			cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
-		else if (ivideo.TV_plug == TVPLUG_COMPOSITE)
-			cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
-		else if (ivideo.TV_plug == TVPLUG_SCART)
-			cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
-		cr31 |= SIS_DRIVER_MODE;
-		cr31 &= ~0x04; /* TW: No Slavemode by default  */
-                /*karl*/
-	        if (sisfb_tvmode == 1 || ivideo.TV_type == TVMODE_PAL)
-			cr31 |= 0x1;
-                if (sisfb_tvmode == 2 || ivideo.TV_type == TVMODE_NTSC)
-                        cr31 &= ~0x1;
+
+	   default:  /* MMIO */
+	   	/* TW: This previously only wrote SIS_MMIO_CMD_ENABLE
+		 * to IND_SIS_CMDQUEUE_SET. I doubt that this is
+		 * enough. Reserve memory in any way.
+		 */
+	   	sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
+		sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
+
+		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
+		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
+
+		*write_port = *read_port;
+
+		/* TW: Set Auto_Correction bit */
+		temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
+		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
+
+		*cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;
+
+		sisfb_caps |= MMIO_CMD_QUEUE_CAP;
+
+		DPRINTK("sisfb: MMIO Cmd Queue offset = 0x%lx, size is %dK\n",
+			*cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
 		break;
-	   default:	/* CRT2 disable */
-		printk(KERN_INFO "sisfb: CRT2 is disabled\n");
-		cr30 = 0x00;
-		cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
 	}
+     } /* sisvga_engine = 315 */
+#endif
 
-	vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR30);
-	vgawb(CRTC_DATA, cr30);
-	vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR31);
-	vgawb(CRTC_DATA, cr31);
-	/* printk(KERN_INFO "sisfb: 0x30=%x 0x31=%x\n", cr30, cr31); */
-	vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR33);
-/*
-	if (ivideo.disp_state & DISPTYPE_CRT2) {
-		sisfb_rate_idx &= 0x0F;
-		sisfb_rate_idx |= (sisfb_rate_idx << 4);
-		vgawb(CRTC_DATA, sisfb_rate_idx);
-	} else {
-		vgawb(CRTC_DATA, sisfb_rate_idx & 0x0F);
-	}
-*/
-	vgawb(CRTC_DATA, sisfb_rate_idx & 0x0F);
-}
+#ifdef CONFIG_FB_SIS_300
+     if (sisvga_engine == SIS_300_VGA) {
+  	    /* TW: Now initialize TurboQueue. TB is always located at the very
+	     * top of the video RAM. */
+	    if (sisfb_heap_size >= TURBO_QUEUE_AREA_SIZE) {
+		unsigned int  tqueue_pos;
+		u8 tq_state;
 
-static void sisfb_post_setmode(void)
-{
-	u8 reg;
+		tqueue_pos = (ivideo.video_size -
+		       TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
 
-	vgawb(CRTC_ADR, 0x17);
-	reg = vgarb(CRTC_DATA);
+		temp = (u8) (tqueue_pos & 0xff);
 
-	if ((ivideo.hasVB == HASVB_LVDS) || (ivideo.hasVB == HASVB_LVDS_CHRONTEL))
-		if (ivideo.video_bpp == 8)   
-			sisfb_crt1off = 0;
+		inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
+		tq_state |= 0xf0;
+		tq_state &= 0xfc;
+		tq_state |= (u8) (tqueue_pos >> 8);
+		outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
 
-	if (sisfb_crt1off)	  
-		reg &= ~0x80;
-	else 	      
-		reg |= 0x80;
-	vgawb(CRTC_DATA, reg);
+		outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, temp);
+
+		sisfb_caps |= TURBO_QUEUE_CAP;
+
+		sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
+		sisfb_heap_size -= TURBO_QUEUE_AREA_SIZE;
+		DPRINTK("sisfb: TurboQueue start at 0x%lx, size is %dK\n",
+			sisfb_heap_end, TURBO_QUEUE_AREA_SIZE/1024);
+	    }
+     }
+#endif
+     /* TW: Now reserve memory for the HWCursor. It is always located at the very
+            top of the videoRAM, right below the TB memory area (if used). */
+     if (sisfb_heap_size >= sisfb_hwcursor_size) {
+		sisfb_heap_end -= sisfb_hwcursor_size;
+		sisfb_heap_size -= sisfb_hwcursor_size;
+		sisfb_hwcursor_vbase = sisfb_heap_end;
+
+		sisfb_caps |= HW_CURSOR_CAP;
+
+		DPRINTK("sisfb: Hardware Cursor start at 0x%lx, size is %dK\n",
+			sisfb_heap_end, sisfb_hwcursor_size/1024);
+     }
+
+     sisfb_heap.poha_chain = NULL;
+     sisfb_heap.poh_freelist = NULL;
+
+     poh = sisfb_poh_new_node();
+
+     if(poh == NULL)  return 1;
 	
-	vgawb(SEQ_ADR, IND_SIS_RAMDAC_CONTROL);
-	reg = vgarb(SEQ_DATA);
-	reg &= ~0x04;
-	vgawb(SEQ_DATA, reg);
-
-	if ((ivideo.disp_state & DISPTYPE_TV) && (ivideo.hasVB == HASVB_301)) {
-		/*karl*/
-		vgawb(VB_PART4_ADR,0x01);
-		reg = vgarb(VB_PART4_DATA);
-		
-	   if ((reg != 0xB1) && (reg != 0xB0)) /*301B Revision ID*/
-           {	
-		// Eden Chen
-		switch (ivideo.video_width) {
-		   case 320:
-			filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 4 : 12;
-			break;
-		   case 640:
-			filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 5 : 13;
-			break;
-		   case 720:
-			filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 6 : 14;
-			break;
-		   case 800:
-			filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 7 : 15;
-			break;
-		   default:
-			filter = -1;
-			break;
-		}
-		// ~Eden Chen
+     poh->poh_next = &sisfb_heap.oh_free;
+     poh->poh_prev = &sisfb_heap.oh_free;
+     poh->size = sisfb_heap_end - sisfb_heap_start + 1;
+     poh->offset = sisfb_heap_start - (unsigned long) ivideo.video_vbase;
 
-		// Eden Chen
-		//vgawb(VB_PART1_ADR,  0x24);
-		vgawb(VB_PART1_ADR,  sisfb_CRT2_write_enable);
-		// ~Eden Chen
-		vgawb(VB_PART1_DATA, 0x1);
-		
-		// Eden Chen for Debug
-/*
-		if (ivideo.chip == SIS_550 || ivideo.chip == SIS_650) {
-			vgawb(VB_PART1_ADR,  0x2D);
-			vgawb(VB_PART1_DATA, 0x11);
-
-			if (sisfb_mode_no == 0x63) {
-				vgawb(VB_PART2_ADR,  0x15);
-				vgawb(VB_PART2_DATA, 0x0A);
-				vgawb(VB_PART2_ADR,  0x28);
-				vgawb(VB_PART2_DATA, 0x62);
-				vgawb(VB_PART2_ADR,  0x2D);
-				vgawb(VB_PART2_DATA, 0xF8);
-				vgawb(VB_PART2_ADR,  0x2E);
-				vgawb(VB_PART2_DATA, 0x14);
-				vgawb(VB_PART2_ADR,  0x33);
-				vgawb(VB_PART2_DATA, 0x8A);
-
-				vgawb(VB_PART2_ADR,  0x35);
-				vgawb(VB_PART2_DATA, 0xF4);
-				vgawb(VB_PART2_ADR,  0x36);
-				vgawb(VB_PART2_DATA, 0x10);
-				vgawb(VB_PART2_ADR,  0x37);
-				vgawb(VB_PART2_DATA, 0x1C);
-				vgawb(VB_PART2_ADR,  0x38);
-				vgawb(VB_PART2_DATA, 0x00);
-				vgawb(VB_PART2_ADR,  0x44);
-				vgawb(VB_PART2_DATA, 0x29);
-				vgawb(VB_PART2_ADR,  0x45);
-				vgawb(VB_PART2_DATA, 0x54);
-
-				vgawb(VB_PART4_ADR,  0x0D);
-				vgawb(VB_PART4_DATA, 0x0F);
-				vgawb(VB_PART4_ADR,  0x0F);
-				vgawb(VB_PART4_DATA, 0x0F);
-				vgawb(VB_PART4_ADR,  0x10);
-				vgawb(VB_PART4_DATA, 0x83);
-				vgawb(VB_PART4_ADR,  0x11);
-				vgawb(VB_PART4_DATA, 0xFF);
-				vgawb(VB_PART4_ADR,  0x18);
-				vgawb(VB_PART4_DATA, 0x20);
-				vgawb(VB_PART4_ADR,  0x19);
-				vgawb(VB_PART4_DATA, 0x52);
-			}
-		}
-*/
-		// ~Eden Chen
+     DPRINTK("sisfb: Heap start:0x%p, end:0x%p, len=%dk\n",
+		(char *) sisfb_heap_start, (char *) sisfb_heap_end,
+		(unsigned int) poh->size / 1024);
 
-		if (ivideo.TV_type == TVMODE_NTSC) {
-			vgawb(VB_PART2_ADR, 0x3A);
-			reg = vgarb(VB_PART2_DATA);
-			reg &= 0x1F;
-			vgawb(VB_PART2_DATA, reg);
+     DPRINTK("sisfb: First Node offset:0x%x, size:%dk\n",
+		(unsigned int) poh->offset, (unsigned int) poh->size / 1024);
 
-			if (ivideo.TV_plug == TVPLUG_SVIDEO) {
-				vgawb(VB_PART2_ADR, 0x30);
-				reg = vgarb(VB_PART2_DATA);
-				reg &= 0xDF;
-				vgawb(VB_PART2_DATA, reg);
-			} else if (ivideo.TV_plug == TVPLUG_COMPOSITE) {
-				vgawb(VB_PART2_ADR, 0x30);
-				reg = vgarb(VB_PART2_DATA);
-				reg |= 0x20;
-				vgawb(VB_PART2_DATA, reg);
+     sisfb_heap.oh_free.poh_next = poh;
+     sisfb_heap.oh_free.poh_prev = poh;
+     sisfb_heap.oh_free.size = 0;
+     sisfb_heap.max_freesize = poh->size;
+
+     sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
+     sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
+     sisfb_heap.oh_used.size = SENTINEL;
 
-				switch (ivideo.video_width) {
-				case 640:
-					vgawb(VB_PART2_ADR,  0x35);
-					vgawb(VB_PART2_DATA, 0xEB);
-					vgawb(VB_PART2_ADR,  0x36);
-					vgawb(VB_PART2_DATA, 0x04);
-					vgawb(VB_PART2_ADR,  0x37);
-					vgawb(VB_PART2_DATA, 0x25);
-					vgawb(VB_PART2_ADR,  0x38);
-					vgawb(VB_PART2_DATA, 0x18);
-					break;
-				case 720:
-					vgawb(VB_PART2_ADR,  0x35);
-					vgawb(VB_PART2_DATA, 0xEE);
-					vgawb(VB_PART2_ADR,  0x36);
-					vgawb(VB_PART2_DATA, 0x0C);
-					vgawb(VB_PART2_ADR,  0x37);
-					vgawb(VB_PART2_DATA, 0x22);
-					vgawb(VB_PART2_ADR,  0x38);
-					vgawb(VB_PART2_DATA, 0x08);
-					break;
-				case 800:
-					vgawb(VB_PART2_ADR,  0x35);
-					vgawb(VB_PART2_DATA, 0xEB);
-					vgawb(VB_PART2_ADR,  0x36);
-					vgawb(VB_PART2_DATA, 0x15);
-					vgawb(VB_PART2_ADR,  0x37);
-					vgawb(VB_PART2_DATA, 0x25);
-					vgawb(VB_PART2_ADR,  0x38);
-					vgawb(VB_PART2_DATA, 0xF6);
-					break;
-				}
-			}
-		} else if (ivideo.TV_type == TVMODE_PAL) {
-			vgawb(VB_PART2_ADR, 0x3A);
-			reg = vgarb(VB_PART2_DATA);
-			reg &= 0x1F;
-			vgawb(VB_PART2_DATA, reg);
+     return 0;
+}
 
-			if (ivideo.TV_plug == TVPLUG_SVIDEO) {
-				vgawb(VB_PART2_ADR, 0x30);
-				reg = vgarb(VB_PART2_DATA);
-				reg &= 0xDF;
-				vgawb(VB_PART2_DATA, reg);
-			} else if (ivideo.TV_plug == TVPLUG_COMPOSITE) {
-				vgawb(VB_PART2_ADR, 0x30);
-				reg = vgarb(VB_PART2_DATA);
-				reg |= 0x20;
-				vgawb(VB_PART2_DATA, reg);
+static SIS_OH *sisfb_poh_new_node(void)
+{
+	int           i;
+	unsigned long cOhs;
+	SIS_OHALLOC   *poha;
+	SIS_OH        *poh;
 
-				switch (ivideo.video_width) {
-				case 640:
-					vgawb(VB_PART2_ADR,  0x35);
-					vgawb(VB_PART2_DATA, 0xF1);
-					vgawb(VB_PART2_ADR,  0x36);
-					vgawb(VB_PART2_DATA, 0xF7);
-					vgawb(VB_PART2_ADR,  0x37);
-					vgawb(VB_PART2_DATA, 0x1F);
-					vgawb(VB_PART2_ADR,  0x38);
-					vgawb(VB_PART2_DATA, 0x32);
-					break;
-				case 720:
-					vgawb(VB_PART2_ADR,  0x35);
-					vgawb(VB_PART2_DATA, 0xF3);
-					vgawb(VB_PART2_ADR,  0x36);
-					vgawb(VB_PART2_DATA, 0x00);
-					vgawb(VB_PART2_ADR,  0x37);
-					vgawb(VB_PART2_DATA, 0x1D);
-					vgawb(VB_PART2_ADR,  0x38);
-					vgawb(VB_PART2_DATA, 0x20);
-					break;
-				case 800:
-					vgawb(VB_PART2_ADR,  0x35);
-					vgawb(VB_PART2_DATA, 0xFC);
-					vgawb(VB_PART2_ADR,  0x36);
-					vgawb(VB_PART2_DATA, 0xFB);
-					vgawb(VB_PART2_ADR,  0x37);
-					vgawb(VB_PART2_DATA, 0x14);
-					vgawb(VB_PART2_ADR,  0x38);
-					vgawb(VB_PART2_DATA, 0x2A);
-					break;
-				}
-			}
-		}
+	if (sisfb_heap.poh_freelist == NULL) {
+		poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
+		if(!poha) return NULL;
 
-		// Eden 
-		if ((filter >= 0) && (filter <=7)) {
-			DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n", filter_tb, filter, 
-				sis_TV_filter[filter_tb].filter[filter][0],
-				sis_TV_filter[filter_tb].filter[filter][1],
-				sis_TV_filter[filter_tb].filter[filter][2],
-				sis_TV_filter[filter_tb].filter[filter][3]
-			);
-			vgawb(VB_PART2_ADR,  0x35);
-			vgawb(VB_PART2_DATA, sis_TV_filter[filter_tb].filter[filter][0]);
-			vgawb(VB_PART2_ADR,  0x36);
-			vgawb(VB_PART2_DATA, sis_TV_filter[filter_tb].filter[filter][1]);
-			vgawb(VB_PART2_ADR,  0x37);
-			vgawb(VB_PART2_DATA, sis_TV_filter[filter_tb].filter[filter][2]);
-			vgawb(VB_PART2_ADR,  0x38);
-			vgawb(VB_PART2_DATA, sis_TV_filter[filter_tb].filter[filter][3]);
+		poha->poha_next = sisfb_heap.poha_chain;
+		sisfb_heap.poha_chain = poha;
+
+		cOhs = (OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
+
+		poh = &poha->aoh[0];
+		for (i = cOhs - 1; i != 0; i--) {
+			poh->poh_next = poh + 1;
+			poh = poh + 1;
 		}
-		// ~Eden 
-	     } /*karl:endif (reg != 0xB1)*/
-	  
+
+		poh->poh_next = NULL;
+		sisfb_heap.poh_freelist = &poha->aoh[0];
 	}
 
+	poh = sisfb_heap.poh_freelist;
+	sisfb_heap.poh_freelist = poh->poh_next;
+
+	return (poh);
 }
 
-static void sisfb_crtc_to_var(struct fb_var_screeninfo *var)
+static SIS_OH *sisfb_poh_allocate(unsigned long size)
 {
-	u16 VRE, VBE, VRS, VBS, VDE, VT;
-	u16 HRE, HBE, HRS, HBS, HDE, HT;
-	u8  sr_data, cr_data, cr_data2, cr_data3, mr_data;
-	int A, B, C, D, E, F, temp;
-	double hrate, drate;
+	SIS_OH *pohThis;
+	SIS_OH *pohRoot;
+	int     bAllocated = 0;
 
-	vgawb(SEQ_ADR, IND_SIS_COLOR_MODE);
-	sr_data = vgarb(SEQ_DATA);
+	if (size > sisfb_heap.max_freesize) {
+		DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
+			(unsigned int) size / 1024);
+		return (NULL);
+	}
 
-	if (sr_data & SIS_INTERLACED_MODE)
-		var->vmode = FB_VMODE_INTERLACED;
-	else
-		var->vmode = FB_VMODE_NONINTERLACED;
+	pohThis = sisfb_heap.oh_free.poh_next;
 
-	switch ((sr_data & 0x1C) >> 2) {
-	   case SIS_8BPP_COLOR_MODE:
-		var->bits_per_pixel = 8;
-		break;
-	   case SIS_16BPP_COLOR_MODE:
-		var->bits_per_pixel = 16;
-		break;
-	   case SIS_32BPP_COLOR_MODE:
-		var->bits_per_pixel = 32;
-		break;
+	while (pohThis != &sisfb_heap.oh_free) {
+		if (size <= pohThis->size) {
+			bAllocated = 1;
+			break;
+		}
+		pohThis = pohThis->poh_next;
 	}
 
-	switch (var->bits_per_pixel) {
-	   case 8:
-		var->red.length = 6;
-		var->green.length = 6;
-		var->blue.length = 6;
-		video_cmap_len = 256;
-		break;
-	   case 16:
-		var->red.offset = 11;
-		var->red.length = 5;
-		var->green.offset = 5;
-		var->green.length = 6;
-		var->blue.offset = 0;
-		var->blue.length = 5;
-		var->transp.offset = 0;
-		var->transp.length = 0;
-		video_cmap_len = 16;
-		break;
-	   case 24:
-		var->red.offset = 16;
-		var->red.length = 8;
-		var->green.offset = 8;
-		var->green.length = 8;
-		var->blue.offset = 0;
-		var->blue.length = 8;
-		var->transp.offset = 0;
-		var->transp.length = 0;
-		video_cmap_len = 16;
-		break;
-	   case 32:
-		var->red.offset = 16;
-		var->red.length = 8;
-		var->green.offset = 8;
-		var->green.length = 8;
-		var->blue.offset = 0;
-		var->blue.length = 8;
-		var->transp.offset = 24;
-		var->transp.length = 8;
-		video_cmap_len = 16;
-		break;
+	if (!bAllocated) {
+		DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
+			(unsigned int) size / 1024);
+		return (NULL);
 	}
 
-	vgawb(SEQ_ADR, 0xA);
-	sr_data = vgarb(SEQ_DATA);
+	if (size == pohThis->size) {
+		pohRoot = pohThis;
+		sisfb_delete_node(pohThis);
+	} else {
+		pohRoot = sisfb_poh_new_node();
 
-	vgawb(CRTC_ADR, 0x6);
-	cr_data = vgarb(CRTC_DATA);
-	vgawb(CRTC_ADR, 0x7);
-	cr_data2 = vgarb(CRTC_DATA);
-	VT = (cr_data & 0xFF) | ((u16) (cr_data2 & 0x01) << 8) |
-	     ((u16) (cr_data2 & 0x20) << 4) | ((u16) (sr_data & 0x01) <<
-					      10);
-	A = VT + 2;
+		if (pohRoot == NULL) {
+			return (NULL);
+		}
 
-	vgawb(CRTC_ADR, 0x12);
-	cr_data = vgarb(CRTC_DATA);
-	VDE = (cr_data & 0xff) | ((u16) (cr_data2 & 0x02) << 7) |
-	      ((u16) (cr_data2 & 0x40) << 3) | ((u16) (sr_data & 0x02) << 9);
-	E = VDE + 1;
+		pohRoot->offset = pohThis->offset;
+		pohRoot->size = size;
 
-	vgawb(CRTC_ADR, 0x10);
-	cr_data = vgarb(CRTC_DATA);
-	VRS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x04) << 6) |
-	      ((u16) (cr_data2 & 0x80) << 2) | ((u16) (sr_data & 0x08) << 7);
-	F = VRS + 1 - E;
+		pohThis->offset += size;
+		pohThis->size -= size;
+	}
 
-	vgawb(CRTC_ADR, 0x15);
-	cr_data = vgarb(CRTC_DATA);
-	vgawb(CRTC_ADR, 0x9);
-	cr_data3 = vgarb(CRTC_DATA);
-	VBS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x08) << 5) |
-	      ((u16) (cr_data3 & 0x20) << 4) | ((u16) (sr_data & 0x04) << 8);
+	sisfb_heap.max_freesize -= size;
 
-	vgawb(CRTC_ADR, 0x16);
-	cr_data = vgarb(CRTC_DATA);
-	VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4);
-	temp = VBE - ((E - 1) & 511);
-	B = (temp > 0) ? temp : (temp + 512);
+	pohThis = &sisfb_heap.oh_used;
+	sisfb_insert_node(pohThis, pohRoot);
 
-	vgawb(CRTC_ADR, 0x11);
-	cr_data = vgarb(CRTC_DATA);
-	VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
-	temp = VRE - ((E + F - 1) & 31);
-	C = (temp > 0) ? temp : (temp + 32);
+	return (pohRoot);
+}
 
-	D = B - F - C;
+static void sisfb_delete_node(SIS_OH *poh)
+{
+	SIS_OH *poh_prev;
+	SIS_OH *poh_next;
 
-	var->yres = var->yres_virtual = E;
-	/* TW: We have to report the physical dimension to the console! */
-	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
-		var->yres <<= 1;
-		var->yres_virtual <<=1;
-	}
-	/* TW end */
-	var->upper_margin = D;
-	var->lower_margin = F;
-	var->vsync_len = C;
+	poh_prev = poh->poh_prev;
+	poh_next = poh->poh_next;
 
-	vgawb(SEQ_ADR, 0xb);
-	sr_data = vgarb(SEQ_DATA);
+	poh_prev->poh_next = poh_next;
+	poh_next->poh_prev = poh_prev;
 
-	vgawb(CRTC_ADR, 0x0);
-	cr_data = vgarb(CRTC_DATA);
-	HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
-	A = HT + 5;
+}
 
-	vgawb(CRTC_ADR, 0x1);
-	cr_data = vgarb(CRTC_DATA);
-	HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6);
-	E = HDE + 1;
+static void sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
+{
+	SIS_OH *pohTemp;
 
-	vgawb(CRTC_ADR, 0x4);
-	cr_data = vgarb(CRTC_DATA);
-	HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2);
-	F = HRS - E - 3;
+	pohTemp = pohList->poh_next;
 
-	vgawb(CRTC_ADR, 0x2);
-	cr_data = vgarb(CRTC_DATA);
-	HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
+	pohList->poh_next = poh;
+	pohTemp->poh_prev = poh;
 
-	vgawb(SEQ_ADR, 0xc);
-	sr_data = vgarb(SEQ_DATA);
-	vgawb(CRTC_ADR, 0x3);
-	cr_data = vgarb(CRTC_DATA);
-	vgawb(CRTC_ADR, 0x5);
-	cr_data2 = vgarb(CRTC_DATA);
-	HBE = (cr_data & 0x1f) | ((u16) (cr_data2 & 0x80) >> 2) |
-	      ((u16) (sr_data & 0x03) << 6);
-	HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
+	poh->poh_prev = pohList;
+	poh->poh_next = pohTemp;
+}
 
-	temp = HBE - ((E - 1) & 255);
-	B = (temp > 0) ? temp : (temp + 256);
+static SIS_OH *sisfb_poh_free(unsigned long base)
+{
+	SIS_OH *pohThis;
+	SIS_OH *poh_freed;
+	SIS_OH *poh_prev;
+	SIS_OH *poh_next;
+	unsigned long ulUpper;
+	unsigned long ulLower;
+	int foundNode = 0;
 
-	temp = HRE - ((E + F + 3) & 63);
-	C = (temp > 0) ? temp : (temp + 64);
+	poh_freed = sisfb_heap.oh_used.poh_next;
 
-	D = B - F - C;
+	while(poh_freed != &sisfb_heap.oh_used) {
+		if(poh_freed->offset == base) {
+			foundNode = 1;
+			break;
+		}
 
-	var->xres = var->xres_virtual = E * 8;
-	var->left_margin = D * 8;
-	var->right_margin = F * 8;
-	var->hsync_len = C * 8;
+		poh_freed = poh_freed->poh_next;
+	}
 
-	var->activate = FB_ACTIVATE_NOW;
+	if (!foundNode)  return (NULL);
 
-	var->sync = 0;
+	sisfb_heap.max_freesize += poh_freed->size;
 
-	mr_data = vgarb(0x1C);
-	if (mr_data & 0x80)
-		var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
-	else
-		var->sync |= FB_SYNC_VERT_HIGH_ACT;
+	poh_prev = poh_next = NULL;
+	ulUpper = poh_freed->offset + poh_freed->size;
+	ulLower = poh_freed->offset;
 
-	if (mr_data & 0x40)
-		var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
-	else
-		var->sync |= FB_SYNC_HOR_HIGH_ACT;
+	pohThis = sisfb_heap.oh_free.poh_next;
 
-	VT += 2;
-	VT <<= 1;
-	HT = (HT + 5) * 8;
+	while (pohThis != &sisfb_heap.oh_free) {
+		if (pohThis->offset == ulUpper) {
+			poh_next = pohThis;
+		}
+			else if ((pohThis->offset + pohThis->size) ==
+				 ulLower) {
+			poh_prev = pohThis;
+		}
+		pohThis = pohThis->poh_next;
+	}
 
-	hrate = (double) ivideo.refresh_rate * (double) VT / 2;
-	drate = hrate * HT;
-	var->pixclock = (u32) (1E12 / drate);
-}
+	sisfb_delete_node(poh_freed);
 
-/* ------------------ Public Routines -------------------------------- */
+	if (poh_prev && poh_next) {
+		poh_prev->size += (poh_freed->size + poh_next->size);
+		sisfb_delete_node(poh_next);
+		sisfb_free_node(poh_freed);
+		sisfb_free_node(poh_next);
+		return (poh_prev);
+	}
 
-static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info)
-{
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-	strcpy(fix->id, fb_info.modename);
+	if (poh_prev) {
+		poh_prev->size += poh_freed->size;
+		sisfb_free_node(poh_freed);
+		return (poh_prev);
+	}
 
-	fix->smem_start = ivideo.video_base;
-        
-        /*karl:10/01/2001*/ /* TW */
-        if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
-	    if (ivideo.video_size > 0x800000)
-		fix->smem_len = 0x800000;
-	    else
-		fix->smem_len = 0x400000;
-        } else
-		fix->smem_len = sisfb_mem * 1024;
+	if (poh_next) {
+		poh_next->size += poh_freed->size;
+		poh_next->offset = poh_freed->offset;
+		sisfb_free_node(poh_freed);
+		return (poh_next);
+	}
 
-	fix->type = video_type;
-	fix->type_aux = 0;
-	if (ivideo.video_bpp == 8)
-		fix->visual = FB_VISUAL_PSEUDOCOLOR;
-	else
-		fix->visual = FB_VISUAL_TRUECOLOR;
-	fix->xpanstep = 0;
-	fix->ypanstep = 0;
-	fix->ywrapstep = 0;
-	fix->line_length = video_linelength;
-	fix->mmio_start = ivideo.mmio_base;
-	fix->mmio_len = sisfb_mmio_size;
-	fix->accel = FB_ACCEL_SIS_GLAMOUR;
-	fix->reserved[0] = ivideo.video_size & 0xFFFF;
-	fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
-	fix->reserved[2] = sisfb_caps;	
+	sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
 
-	return 0;
+	return (poh_freed);
 }
 
-static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
+static void sisfb_free_node(SIS_OH *poh)
 {
-	if (con == -1)
-		memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
-	else
-		*var = fb_display[con].var;
+	if(poh == NULL) return;
 
-	/* JennyLee 2001126: for FSTN */
-	if (var->xres == 320 && var->yres == 480)
-		var->yres = 240;
-	/* ~JennyLee */
+	poh->poh_next = sisfb_heap.poh_freelist;
+	sisfb_heap.poh_freelist = poh;
 
-	return 0;
 }
 
-static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
+void sis_malloc(struct sis_memreq *req)
 {
-	int err;
-	unsigned int cols, rows;
-
-	fb_display[con].var.activate = FB_ACTIVATE_NOW;
-	if (sisfb_do_set_var(var, con == currcon, info)) {
-		sisfb_crtc_to_var(var);	
-		return -EINVAL;
-	}
-	
-	sisfb_crtc_to_var(var);
-	
-	sisfb_set_disp(con, var);
+	SIS_OH *poh;
 
-	if (info->changevar)
-		(*info->changevar) (con);
+	poh = sisfb_poh_allocate(req->size);
 
-	if ((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
-		return err;
+	if(poh == NULL) {
+		req->offset = 0;
+		req->size = 0;
+		DPRINTK("sisfb: Video RAM allocation failed\n");
+	} else {
+		DPRINTK("sisfb: Video RAM allocation succeeded: 0x%p\n",
+			(char *) (poh->offset + (unsigned long) ivideo.video_vbase));
 
-	sisfb_do_install_cmap(con, info);
-	
-	cols = sisbios_mode[sisfb_mode_idx].cols;
-	rows = sisbios_mode[sisfb_mode_idx].rows;
-	vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
+		req->offset = poh->offset;
+		req->size = poh->size;
+	}
 
-	return 0;
 }
 
-static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info)
+void sis_free(unsigned long base)
 {
-	if (con == currcon)
-		return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
-	else if (fb_display[con].cmap.len)	
-		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-	else
-		fb_copy_cmap(fb_default_cmap(video_cmap_len), cmap, kspc ? 0 : 2);
-
-	return 0;
-}
+	SIS_OH *poh;
 
-static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info)
-{
-	int err;
+	poh = sisfb_poh_free(base);
 
-	if (!fb_display[con].cmap.len) {	
-		err = fb_alloc_cmap(&fb_display[con].cmap, video_cmap_len, 0);
-		if (err)
-			return err;
+	if(poh == NULL) {
+		DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
+			(unsigned int) base);
 	}
-	if (con == currcon)	
-		return fb_set_cmap(cmap, kspc, sis_setcolreg, info);
-	else
-		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
-	return 0;
 }
 
-static int sisfb_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg, int con,
-		       struct fb_info *info)
+/* ------------------ SetMode Routines ------------------------------- */
+
+static void sisfb_pre_setmode(void)
 {
-	switch (cmd) {
-	   case FBIO_ALLOC:
-		if (!capable(CAP_SYS_RAWIO))
-			return -EPERM;
-		sis_malloc((struct sis_memreq *) arg);
+	u8 cr30 = 0, cr31 = 0;
+
+	inSISIDXREG(SISCR, 0x31, cr31);
+	cr31 &= ~0x60;
+
+	switch (ivideo.disp_state & DISPTYPE_DISP2) {
+	   case DISPTYPE_CRT2:
+		printk(KERN_INFO "sisfb: CRT2 type is VGA\n");
+		cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		cr31 |= SIS_DRIVER_MODE;
 		break;
-	   case FBIO_FREE:
-		if (!capable(CAP_SYS_RAWIO))
-			return -EPERM;
-		sis_free(*(unsigned long *) arg);
+	   case DISPTYPE_LCD:
+		printk(KERN_INFO "sisfb: CRT2 type is LCD\n");
+		cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		cr31 |= SIS_DRIVER_MODE;
 		break;
-	   case FBIOGET_GLYPH:
-		sis_get_glyph((SIS_GLYINFO *) arg);
+	   case DISPTYPE_TV:
+		printk(KERN_INFO "sisfb: CRT2 type is TV\n");
+		if (ivideo.TV_type == TVMODE_HIVISION)
+			cr30 = (SIS_VB_OUTPUT_HIVISION | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		else if (ivideo.TV_plug == TVPLUG_SVIDEO)
+			cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		else if (ivideo.TV_plug == TVPLUG_COMPOSITE)
+			cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		else if (ivideo.TV_plug == TVPLUG_SCART)
+			cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		cr31 |= SIS_DRIVER_MODE;
+
+	        if (sisfb_tvmode == 1 || ivideo.TV_type == TVMODE_PAL)
+			cr31 |= 0x01;
+                else   /* if (sisfb_tvmode == 2 || ivideo.TV_type == TVMODE_NTSC) - nonsense */
+                        cr31 &= ~0x01;
 		break;
-	   case FBIOGET_HWCINFO:
-		{
-			unsigned long *hwc_offset = (unsigned long *) arg;
+	   default:	/* CRT2 disable */
+		printk(KERN_INFO "sisfb: CRT2 is disabled\n");
+		cr30 = 0x00;
+		cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
+	}
 
-			if (sisfb_caps & HW_CURSOR_CAP)
-				*hwc_offset = sisfb_hwcursor_vbase -
-				    (unsigned long) ivideo.video_vbase;
-			else
-				*hwc_offset = 0;
+	outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR30, cr30);
+	outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR31, cr31);
 
-			break;
-		}
-	   case FBIOPUT_MODEINFO:
-		{
-			struct mode_info *x = (struct mode_info *)arg;
-			
-			ivideo.video_bpp      = x->bpp;
-			ivideo.video_width    = x->xres;
-			ivideo.video_height   = x->yres;
-			ivideo.video_vwidth   = x->v_xres;
-			ivideo.video_vheight  = x->v_yres;
-			ivideo.org_x          = x->org_x;
-			ivideo.org_y          = x->org_y;
-			ivideo.refresh_rate   = x->vrate;
-			
-			break;
+        outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR33, (sisfb_rate_idx & 0x0F));
+
+}
+
+static void sisfb_post_setmode(void)
+{
+	u8 reg;
+	BOOLEAN doit = TRUE;
+
+	/* TW: We can't switch off CRT1 on LVDS/Chrontel in 8bpp Modes */
+	if ((ivideo.hasVB == HASVB_LVDS) || (ivideo.hasVB == HASVB_LVDS_CHRONTEL)) {
+		if (ivideo.video_bpp == 8) {
+			doit = FALSE;
 		}
-	   case FBIOGET_DISPINFO:
-		sis_dispinfo((struct ap_data *)arg);
-		break;
-	   default:
-		return -EINVAL;
 	}
-	return 0;
 
-}
+	/* TW: We can't switch off CRT1 on 630+301B in 8bpp Modes */
+	if ( (sishw_ext.ujVBChipID == VB_CHIP_301B) && (sisvga_engine == SIS_300_VGA) &&
+	     (ivideo.disp_state & DISPTYPE_LCD) ) {
+	        if (ivideo.video_bpp == 8) {
+			doit = FALSE;
+	        }
+	}
+
+	/* TW: We can't switch off CRT1 if bridge is in slave mode */
+	if(ivideo.hasVB != HASVB_NONE) {
+		inSISIDXREG(SISPART1, 0x00, reg);
+		if(sisvga_engine == SIS_300_VGA) {
+			if((reg & 0xa0) == 0x20) {
+				doit = FALSE;
+			}
+		}
+		if(sisvga_engine == SIS_315_VGA) {
+			if((reg & 0x50) == 0x10) {
+				doit = FALSE;
+			}
+		}
+	} else sisfb_crt1off = 0;
+
+	inSISIDXREG(SISCR, 0x17, reg);
+	if((sisfb_crt1off) && (doit))
+		reg &= ~0x80;
+	else 	      
+		reg |= 0x80;
+	outSISIDXREG(SISCR, 0x17, reg);
 
-static int sisfb_mmap(struct fb_info *info, struct file *file,
-		      struct vm_area_struct *vma)
-{
-	struct fb_var_screeninfo var;
-	unsigned long start;
-	unsigned long off;
-	u32 len;
+        andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
 
-	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
-		return -EINVAL;
-	off = vma->vm_pgoff << PAGE_SHIFT;
-	
-	start = (unsigned long) ivideo.video_base;
-	len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
+	if((ivideo.disp_state & DISPTYPE_TV) && (ivideo.hasVB == HASVB_301)) {
 
-	if (off >= len) {
-		off -= len;
-		sisfb_get_var(&var, currcon, info);
-		if (var.accel_flags)
-			return -EINVAL;
-		start = (unsigned long) ivideo.mmio_base;
-		len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size);
-	}
+	   inSISIDXREG(SISPART4, 0x01, reg);
 
-	start &= PAGE_MASK;
-	if ((vma->vm_end - vma->vm_start + off) > len)
-		return -EINVAL;
-	off += start;
-	vma->vm_pgoff = off >> PAGE_SHIFT;
+	   if(reg < 0xB0) {        	/* Set filter for SiS301 */
 
-#if defined(__i386__)
-	if (boot_cpu_data.x86 > 3)
-		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
-				vma->vm_page_prot))
-#else	/* TW: 2.5 API */
-	if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start,
-				vma->vm_page_prot))
-#endif
-		return -EAGAIN;
-	return 0;
+		switch (ivideo.video_width) {
+		   case 320:
+			filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 4 : 12;
+			break;
+		   case 640:
+			filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 5 : 13;
+			break;
+		   case 720:
+			filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 6 : 14;
+			break;
+		   case 800:
+			filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 7 : 15;
+			break;
+		   default:
+			filter = -1;
+			break;
+		}
 
-}
+		orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01);
 
-static struct fb_ops sisfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	sisfb_get_fix,
-	fb_get_var:	sisfb_get_var,
-	fb_set_var:	sisfb_set_var,
-	fb_get_cmap:	sisfb_get_cmap,
-	fb_set_cmap:	sisfb_set_cmap,
-	fb_ioctl:	sisfb_ioctl,
-	fb_mmap:	sisfb_mmap,
-};
+		if(ivideo.TV_type == TVMODE_NTSC) {
 
-/* ------------ Interface to the low level console driver -------------*/
+		        andSISIDXREG(SISPART2, 0x3a, 0x1f);
 
-static int sisfb_update_var(int con, struct fb_info *info)
-{
-	return 0;
-}
+			if (ivideo.TV_plug == TVPLUG_SVIDEO) {
 
-static int sisfb_switch(int con, struct fb_info *info)
-{
-	int cols, rows;
+			        andSISIDXREG(SISPART2, 0x30, 0xdf);
 
-	if (fb_display[currcon].cmap.len)
-		fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);
+			} else if (ivideo.TV_plug == TVPLUG_COMPOSITE) {
 
-	fb_display[con].var.activate = FB_ACTIVATE_NOW;
+			        orSISIDXREG(SISPART2, 0x30, 0x20);
 
-	if (!memcmp(&fb_display[con].var, &fb_display[currcon].var,
-	                           sizeof(struct fb_var_screeninfo))) {
-		currcon = con;
-		return 1;
-	}
+				switch (ivideo.video_width) {
+				case 640:
+				        outSISIDXREG(SISPART2, 0x35, 0xEB);
+					outSISIDXREG(SISPART2, 0x36, 0x04);
+					outSISIDXREG(SISPART2, 0x37, 0x25);
+					outSISIDXREG(SISPART2, 0x38, 0x18);
+					break;
+				case 720:
+					outSISIDXREG(SISPART2, 0x35, 0xEE);
+					outSISIDXREG(SISPART2, 0x36, 0x0C);
+					outSISIDXREG(SISPART2, 0x37, 0x22);
+					outSISIDXREG(SISPART2, 0x38, 0x08);
+					break;
+				case 800:
+					outSISIDXREG(SISPART2, 0x35, 0xEB);
+					outSISIDXREG(SISPART2, 0x36, 0x15);
+					outSISIDXREG(SISPART2, 0x37, 0x25);
+					outSISIDXREG(SISPART2, 0x38, 0xF6);
+					break;
+				}
+			}
 
-	currcon = con;
+		} else if(ivideo.TV_type == TVMODE_PAL) {
 
-	sisfb_do_set_var(&fb_display[con].var, 1, info);
+			andSISIDXREG(SISPART2, 0x3A, 0x1F);
 
-	sisfb_set_disp(con, &fb_display[con].var);
-	
-	sisfb_do_install_cmap(con, info);
+			if (ivideo.TV_plug == TVPLUG_SVIDEO) {
 
-	cols = sisbios_mode[sisfb_mode_idx].cols;
-	rows = sisbios_mode[sisfb_mode_idx].rows;
-	vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
+			        andSISIDXREG(SISPART2, 0x30, 0xDF);
 
-	sisfb_update_var(con, info);
+			} else if (ivideo.TV_plug == TVPLUG_COMPOSITE) {
 
-	return 1;
-}
+			        orSISIDXREG(SISPART2, 0x30, 0x20);
 
-static void sisfb_blank(int blank, struct fb_info *info)
-{
-	u8 reg;
+				switch (ivideo.video_width) {
+				case 640:
+					outSISIDXREG(SISPART2, 0x35, 0xF1);
+					outSISIDXREG(SISPART2, 0x36, 0xF7);
+					outSISIDXREG(SISPART2, 0x37, 0x1F);
+					outSISIDXREG(SISPART2, 0x38, 0x32);
+					break;
+				case 720:
+					outSISIDXREG(SISPART2, 0x35, 0xF3);
+					outSISIDXREG(SISPART2, 0x36, 0x00);
+					outSISIDXREG(SISPART2, 0x37, 0x1D);
+					outSISIDXREG(SISPART2, 0x38, 0x20);
+					break;
+				case 800:
+					outSISIDXREG(SISPART2, 0x35, 0xFC);
+					outSISIDXREG(SISPART2, 0x36, 0xFB);
+					outSISIDXREG(SISPART2, 0x37, 0x14);
+					outSISIDXREG(SISPART2, 0x38, 0x2A);
+					break;
+				}
+			}
+		}
 
-	vgawb(CRTC_ADR, 0x17);
-	reg = vgarb(CRTC_DATA);
+		if ((filter >= 0) && (filter <=7)) {
+			DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n", filter_tb, filter, 
+				sis_TV_filter[filter_tb].filter[filter][0],
+				sis_TV_filter[filter_tb].filter[filter][1],
+				sis_TV_filter[filter_tb].filter[filter][2],
+				sis_TV_filter[filter_tb].filter[filter][3]
+			);
+			outSISIDXREG(SISPART2, 0x35, (sis_TV_filter[filter_tb].filter[filter][0]));
+			outSISIDXREG(SISPART2, 0x36, (sis_TV_filter[filter_tb].filter[filter][1]));
+			outSISIDXREG(SISPART2, 0x37, (sis_TV_filter[filter_tb].filter[filter][2]));
+			outSISIDXREG(SISPART2, 0x38, (sis_TV_filter[filter_tb].filter[filter][3]));
+		}
 
-	if (blank > 0)		
-		reg &= 0x7f;
-	else			
-		reg |= 0x80;
+	     }
+	  
+	}
 
-	vgawb(CRTC_ADR, 0x17);
-	vgawb(CRTC_DATA, reg);
 }
 
+#ifndef MODULE
 int sisfb_setup(char *options)
 {
 	char *this_opt;
 
-	fb_info.fontname[0] = '\0';
+	sis_fb_info.fontname[0] = '\0';
 	ivideo.refresh_rate = 0;
 
+        printk(KERN_INFO "sisfb: Options %s\n", options);
+
 	if (!options || !*options)
 		return 0;
 
-#if 0	/* TW (Alex Tribble): Change for 2.5 series */
-	for (this_opt = strtok(options, ","); this_opt;
-	     this_opt = strtok(NULL, ",")) {
-#endif
-	while((this_opt = strsep(&options, ","))) {
-		if (!*this_opt)
-			continue;
+	while((this_opt = strsep(&options, ",")) != NULL) {
+
+		if (!*this_opt)	continue;
 
 		if (!strcmp(this_opt, "inverse")) {
 			sisfb_inverse = 1;
-			fb_invert_cmaps();
+			/* fb_invert_cmaps(); */
 		} else if (!strncmp(this_opt, "font:", 5)) {
-			strcpy(fb_info.fontname, this_opt + 5);
+			strcpy(sis_fb_info.fontname, this_opt + 5);
 		} else if (!strncmp(this_opt, "mode:", 5)) {
 			sisfb_search_mode(this_opt + 5);
+		} else if (!strncmp(this_opt, "vesa:", 5)) {
+			sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0));
 		} else if (!strncmp(this_opt, "vrate:", 6)) {
 			ivideo.refresh_rate =
 			    simple_strtoul(this_opt + 6, NULL, 0);
@@ -2619,42 +3128,60 @@
 			sisfb_search_crt2type(this_opt + 14);
 		} else if (!strncmp(this_opt, "forcecrt1:", 10)) {
 			sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
-                  /*karl*/
                 } else if (!strncmp(this_opt, "tvmode:",7)) {
                         if (!strncmp(this_opt + 7, "pal",3))
                          	sisfb_tvmode = 1;
                         if (!strncmp(this_opt + 7, "ntsc",4))
                          	sisfb_tvmode = 2;
-                }
-                 /*karl:10/01/2001*/ 
-                else if (!strncmp(this_opt, "mem:",4)) {
+                } else if (!strncmp(this_opt, "tvstandard:",11)) {
+                        if (!strncmp(this_opt + 11, "pal",3))
+                         	sisfb_tvmode = 1;
+                        else if (!strncmp(this_opt + 11, "ntsc",4))
+                         	sisfb_tvmode = 2;
+                }else if (!strncmp(this_opt, "mem:",4)) {
 		        sisfb_mem = simple_strtoul(this_opt + 4, NULL, 0);
-                }
-		/* JennyLee 20011211 */
-		else if (!strncmp(this_opt, "dstn:", 5)) {
-			enable_dstn = simple_strtoul(this_opt + 5, NULL, 0);
-		}
-		/* ~JennyLee 20011211 */
-		else if (!strncmp(this_opt, "queuemode:", 10)) {
+                } else if (!strncmp(this_opt, "dstn", 4)) {
+			enable_dstn = 1;
+			/* TW: DSTN overrules forcecrt2type */
+			sisfb_crt2type = DISPTYPE_LCD;
+		} else if (!strncmp(this_opt, "queuemode:", 10)) {
 			sisfb_search_queuemode(this_opt + 10);
+		} else if (!strncmp(this_opt, "pdc:", 4)) {
+		        sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
+		        if(sisfb_pdc & ~0x3c) {
+			   printk(KERN_INFO "sisfb: Illegal pdc parameter\n");
+			   sisfb_pdc = 0;
+		        }
+		} else if (!strncmp(this_opt, "noaccel", 7)) {
+			sisfb_accel = 0;
+		} else if (!strncmp(this_opt, "noypan", 6)) {
+		        sisfb_ypan = 0;
+		} else {
+			printk(KERN_INFO "sisfb: Invalid parameter %s\n", this_opt);
 		}
 
-		else
-			printk(KERN_INFO "sisfb: Invalid parameter %s\n", this_opt);
+		/* TW: Acceleration only with MMIO mode */
+		if((sisfb_queuemode != -1) && (sisfb_queuemode != MMIO_CMD)) {
+			sisfb_ypan = 0;
+			sisfb_accel = 0;
+		}
+		/* TW: Panning only with acceleration */
+		if(sisfb_accel == 0) sisfb_ypan = 0;
+
 	}
 	return 0;
 }
+#endif
 
 int __init sisfb_init(void)
 {
 	struct pci_dev *pdev = NULL;
 	struct board *b;
 	int pdev_valid = 0;
-	//unsigned long rom_vbase;
+	/* unsigned long rom_vbase;  */
 	u32 reg32;
 	u16 reg16;
 	u8  reg;
-	int temp1, temp2;
 
 	outb(0x77, 0x80);
 
@@ -2670,25 +3197,24 @@
 	if (sisfb_off)
 		return -ENXIO;
 
-//	printk("20011213:enable_dstn=%d \n", enable_dstn);
 	if (enable_dstn)
-		SetEnableDstn();
+		SetEnableDstn(&SiS_Pr);
+
+	memset(&sis_fb_info, 0, sizeof(sis_fb_info));
+	memset(&sis_disp, 0, sizeof(sis_disp));
 
 	pci_for_each_dev(pdev) {
 		for (b = sisdev_list; b->vendor; b++) {
 			if ((b->vendor == pdev->vendor)
 			    && (b->device == pdev->device)) {
 				pdev_valid = 1;
-				strcpy(fb_info.modename, b->name);
+				strcpy(sis_fb_info.modename, b->name);
 				ivideo.chip_id = pdev->device;
 				pci_read_config_byte(pdev, PCI_REVISION_ID,
 				                     &ivideo.revision_id);
 				pci_read_config_word(pdev, PCI_COMMAND, &reg16);
-				// Eden Chen
-				//sishw_ext.uRevisionID = ivideo.revision_id;
 				sishw_ext.jChipRevision = ivideo.revision_id;
-				// ~Eden Chen
-				sisvga_enabled = reg16 & 0x1;
+				sisvga_enabled = reg16 & 0x01;
 				break;
 			}
 		}
@@ -2698,9 +3224,8 @@
 	}
 
 	if (!pdev_valid)
-		return -1;
+		return -ENODEV;
 
-// Eden Chen
 	switch (ivideo.chip_id) {
 	   case PCI_DEVICE_ID_SI_300:
 		ivideo.chip = SIS_300;
@@ -2712,9 +3237,9 @@
 		{
 			sisfb_set_reg4(0xCF8, 0x80000000);
 			reg32 = sisfb_get_reg3(0xCFC);
-			if (reg32 == 0x07301039) {
+			if(reg32 == 0x07301039) {
 				ivideo.chip = SIS_730;
-				strcpy(fb_info.modename, "SIS 730");
+				strcpy(sis_fb_info.modename, "SIS 730");
 			} else
 				ivideo.chip = SIS_630;
 
@@ -2760,31 +3285,28 @@
 		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
 		break;
 	}
-	// Eden Chen
-	//sishw_ext.jChipID = ivideo.chip;
 	sishw_ext.jChipType = ivideo.chip;
-	// for Debug
+
+	/* for Debug */
 	if ((sishw_ext.jChipType == SIS_315PRO) 
 	   || (sishw_ext.jChipType == SIS_315) )
 		sishw_ext.jChipType = SIS_315H;
-	// ~Eden Chen
 
-	DPRINTK("%s is used as %s device(VGA Engine %d).\n", 
-		fb_info.modename, sisvga_enabled ? "primary" : "secondary", sisvga_engine);
+	DPRINTK("%s is used as %s device (VGA Engine %d).\n",
+		sis_fb_info.modename, sisvga_enabled ? "primary" : "secondary", sisvga_engine);
 
 	ivideo.video_base = pci_resource_start(pdev, 0);
 	ivideo.mmio_base = pci_resource_start(pdev, 1);
-	// Eden Chen
-	//sishw_ext.IOAddress = (unsigned short) ivideo.vga_base 
-	//	= pci_resource_start(pdev, 2) + 0x30;
-	sishw_ext.ulIOAddress = (unsigned short) ivideo.vga_base
-		= pci_resource_start(pdev, 2) + 0x30;
-	// ~Eden Chen
+	sishw_ext.ulIOAddress = (unsigned short) ivideo.vga_base =
+	    (unsigned short) SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
 
 	sisfb_mmio_size =  pci_resource_len(pdev, 1);
 
-	if (!sisvga_enabled)
+	if(!sisvga_enabled) {
 		if (pci_enable_device(pdev))   return -EIO;
+	}
+
+	SiSRegInit(&SiS_Pr, (USHORT)sishw_ext.ulIOAddress);
 
 // Eden Eden
 //#ifdef LINUXBIOS
@@ -2799,37 +3321,30 @@
 //	}
 //#endif
 // ~Eden Chen
-	
-	vgawb(SEQ_ADR, IND_SIS_PASSWORD);
-	vgawb(SEQ_DATA, SIS_PASSWORD);
+
+        outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 
 #ifdef LINUXBIOS
+
 #ifdef CONFIG_FB_SIS_300
 	if (sisvga_engine == SIS_300_VGA) {
-		vgawb(SEQ_ADR, 0x28);
-		vgawb(SEQ_DATA, 0x37);
+	        outSISIDXREG(SISSR, 0x28, 0x37);
 
-		vgawb(SEQ_ADR, 0x29);
-		vgawb(SEQ_DATA, 0x61);
+                outSISIDXREG(SISSR, 0x29, 0x61);
 
-		vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_1A);
-		reg = vgarb(SEQ_DATA);
-		reg |= SIS_SCRATCH_REG_1A_MASK;
-		vgawb(SEQ_DATA, reg);
+                orSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_1A, SIS_SCRATCH_REG_1A_MASK);
 	}
 #endif
 #ifdef CONFIG_FB_SIS_315
 	if (ivideo.chip == SIS_550 || ivideo.chip == SIS_650) {
-		vgawb(SEQ_ADR,  0x28);
-		vgawb(SEQ_DATA, 0x5A);
+	        outSISIDXREG(SISSR, 0x28, 0x5a);
 
-		vgawb(SEQ_ADR,  0x29);
-		vgawb(SEQ_DATA, 0x64);
+                outSISIDXREG(SISSR, 0x29, 0x64);
 
-		vgawb(CRTC_ADR,  0x3A);
-		vgawb(CRTC_DATA, 0x00);
+                outSISIDXREG(SISCR, 0x3a, 0x00);
 	}
 #endif
+
 #endif /* LinuxBIOS */
 
 	if (sisvga_engine == SIS_315_VGA) {
@@ -2840,16 +3355,7 @@
 			break;
 		   case SIS_550:
 		   case SIS_650:
-			// Eden Chen
-			//vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_1A);
-			//reg = vgarb(SEQ_DATA);
-			//if (reg & SIS_SCRATCH_REG_1A_MASK)
-			//	sishw_ext.bIntegratedMMEnabled = TRUE;
-			//else
-			//	sishw_ext.bIntegratedMMEnabled = FALSE;
-			//for Debug
 			sishw_ext.bIntegratedMMEnabled = TRUE;
-			// ~Eden Chen
 			break;
 		   default:
 			break;
@@ -2858,8 +3364,7 @@
 		if (ivideo.chip == SIS_300) {
 			sishw_ext.bIntegratedMMEnabled = TRUE;
 		} else {
-			vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_1A);
-			reg = vgarb(SEQ_DATA);
+		        inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_1A, reg);
 			if (reg & SIS_SCRATCH_REG_1A_MASK)
 				sishw_ext.bIntegratedMMEnabled = TRUE;
 			else
@@ -2867,7 +3372,6 @@
 		}
 	}
 
-	// Eden Chen
 	sishw_ext.pDevice = NULL;
 	sishw_ext.pjVirtualRomBase = NULL;
 	sishw_ext.pjCustomizedROMImage = NULL;
@@ -2876,33 +3380,38 @@
 	sishw_ext.pQueryNorthBridgeSpace = &sisfb_query_north_bridge_space;
 	strcpy(sishw_ext.szVBIOSVer, "0.84");
 
+	/* TW: Mode numbers for 1280x960 are different for 300 and 310/325 series */
+	if(sisvga_engine == SIS_300_VGA) {
+		sisbios_mode[MODEINDEX_1280x960].mode_no = 0x6e;
+		sisbios_mode[MODEINDEX_1280x960+1].mode_no = 0x6f;
+		sisbios_mode[MODEINDEX_1280x960+2].mode_no = 0x7b;
+		sisbios_mode[MODEINDEX_1280x960+3].mode_no = 0x7b;
+	}
+
 	sishw_ext.pSR = vmalloc(sizeof(SIS_DSReg) * SR_BUFFER_SIZE);
 	if (sishw_ext.pSR == NULL) {
-		printk(KERN_INFO "sisfb: Fatal error: Allocating SRReg space failed.\n");
+		printk(KERN_ERR "sisfb: Fatal error: Allocating SRReg space failed.\n");
 		return -ENODEV;
 	}
 	sishw_ext.pSR[0].jIdx = sishw_ext.pSR[0].jVal = 0xFF;
 
 	sishw_ext.pCR = vmalloc(sizeof(SIS_DSReg) * CR_BUFFER_SIZE);
 	if (sishw_ext.pCR == NULL) {
-		printk(KERN_INFO "sisfb: Fatal error: Allocating CRReg space failed.\n");
+	        vfree(sishw_ext.pSR);
+		printk(KERN_ERR "sisfb: Fatal error: Allocating CRReg space failed.\n");
 		return -ENODEV;
 	}
 	sishw_ext.pCR[0].jIdx = sishw_ext.pCR[0].jVal = 0xFF;
-	// ~Eden Chen
 
 #ifdef CONFIG_FB_SIS_300
-	if (sisvga_engine == SIS_300_VGA) {
-		if (!sisvga_enabled) {
-			// Eden Chen
-			sishw_ext.pjVideoMemoryAddress 
+	if(sisvga_engine == SIS_300_VGA) {
+		if(!sisvga_enabled) {
+			sishw_ext.pjVideoMemoryAddress
 				= ioremap(ivideo.video_base, 0x2000000);
 			if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
-				//SiSInit300(&sishw_ext);
-				SiSInit(&sishw_ext);
-				vgawb(SEQ_ADR, IND_SIS_PASSWORD);
-				vgawb(SEQ_DATA, SIS_PASSWORD);
-				// ~Eden Chen
+			        /* TW: SiSInit now for LinuxBIOS only */
+				/* SiSInit(&SiS_Pr, &sishw_ext);  */
+				outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 			}
 		}
 #ifdef LINUXBIOS
@@ -2910,20 +3419,18 @@
 			sishw_ext.pjVideoMemoryAddress
 				= ioremap(ivideo.video_base, 0x2000000);
 			if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
-				SiSInit(&sishw_ext);
-				vgawb(SEQ_ADR, IND_SIS_PASSWORD);
-				vgawb(SEQ_DATA, SIS_PASSWORD);
+				SiSInit(&SiS_Pr, &sishw_ext);
+				outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 			}
 		}
-		if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
-			vgawb(SEQ_ADR, 0x7);
-			reg = vgarb(SEQ_DATA);
-			reg |= 0x10;
-			vgawb(SEQ_DATA, reg);
+		if((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
+		        orSISIDXREG(SISSR, 0x07, 0x10);
 		}
 #endif
-		if (sisfb_get_dram_size_300()) {
-			printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size\n");
+		if(sisfb_get_dram_size_300()) {
+		        vfree(sishw_ext.pSR);
+			vfree(sishw_ext.pCR);
+			printk(KERN_ERR "sisfb: Fatal error: Unable to determine RAM size\n");
 			return -ENODEV;
 		}
 	}
@@ -2938,19 +3445,17 @@
 			sishw_ext.pjVideoMemoryAddress 
 				= ioremap(ivideo.video_base, 0x8000000);
 			if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
-				SiSInit(&sishw_ext);
+			        /* TW: SISInit is now for LINUXBIOS only */
+				/* SiSInit(&SiS_Pr, &sishw_ext); */
 
-				vgawb(SEQ_ADR, IND_SIS_PASSWORD);
-				vgawb(SEQ_DATA, SIS_PASSWORD);
+				outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 
 				sishw_ext.bSkipDramSizing = TRUE;
-				vgawb(SEQ_ADR, 0x13);
 				sishw_ext.pSR[0].jIdx = 0x13;
-				sishw_ext.pSR[0].jVal = vgarb(SEQ_DATA);
-				vgawb(SEQ_ADR, 0x14);
 				sishw_ext.pSR[1].jIdx = 0x14;
-				sishw_ext.pSR[1].jVal = vgarb(SEQ_DATA);
 				sishw_ext.pSR[2].jIdx = 0xFF;
+				inSISIDXREG(SISSR, 0x13, sishw_ext.pSR[0].jVal);
+				inSISIDXREG(SISSR, 0x14, sishw_ext.pSR[1].jVal);
 				sishw_ext.pSR[2].jVal = 0xFF;
 			}
 		}
@@ -2959,123 +3464,130 @@
 			sishw_ext.pjVideoMemoryAddress
 				= ioremap(ivideo.video_base, 0x8000000);
 			if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
-				SiSInit(&sishw_ext);
-				vgawb(SEQ_ADR, IND_SIS_PASSWORD);
-				vgawb(SEQ_DATA, SIS_PASSWORD);
+
+				SiSInit(&SiS_Pr, &sishw_ext);
+
+				outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 
 				sishw_ext.bSkipDramSizing = TRUE;
-				vgawb(SEQ_ADR, 0x13);
 				sishw_ext.pSR[0].jIdx = 0x13;
-				sishw_ext.pSR[0].jVal = vgarb(SEQ_DATA);
-				vgawb(SEQ_ADR, 0x14);
 				sishw_ext.pSR[1].jIdx = 0x14;
-				sishw_ext.pSR[1].jVal = vgarb(SEQ_DATA);
 				sishw_ext.pSR[2].jIdx = 0xFF;
+				inSISIDXREG(SISSR, 0x13, sishw_ext.pSR[0].jVal);
+				inSISIDXREG(SISSR, 0x14, sishw_ext.pSR[1].jVal);
 				sishw_ext.pSR[2].jVal = 0xFF;
 			}
 		}
 #endif
 		if (sisfb_get_dram_size_315()) {
+			vfree(sishw_ext.pSR);
+			vfree(sishw_ext.pCR);
 			printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
 			return -ENODEV;
 		}
 	}
 #endif
+
 	if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
-		//Eden Chen
-		vgawb(SEQ_ADR, IND_SIS_PCI_ADDRESS_SET);
-		reg = vgarb(SEQ_DATA);
-		reg |= SIS_PCI_ADDR_ENABLE;    	/* Enable PCI_LINEAR_ADDRESSING */
-		reg |= SIS_MEM_MAP_IO_ENABLE;  	/* Enable MMIO_ENABLE */
-		vgawb(SEQ_DATA, reg);
-
-		vgawb(SEQ_ADR, IND_SIS_MODULE_ENABLE);
-		reg = vgarb(SEQ_DATA);
-		reg |= SIS_ENABLE_2D;		/* Enable 2D accelerator engine */
-		vgawb(SEQ_DATA, reg);
-		//~Eden Chen
+
+	        /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
+	        orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
+
+                /* Enable 2D accelerator engine */
+	        orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
+
 	}
 
-	// Eden Chen
 	sishw_ext.ulVideoMemorySize = ivideo.video_size;
-	// ~Eden Chen
+
+	if(sisfb_pdc) {
+	    sishw_ext.pdc = sisfb_pdc;
+	} else {
+	    sishw_ext.pdc = 0;
+	}
+
 	if (!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB")) {
 		printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
+		printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
+		vfree(sishw_ext.pSR);
+		vfree(sishw_ext.pCR);
 		return -ENODEV;
 	}
 
 	if (!request_mem_region(ivideo.mmio_base, sisfb_mmio_size, "sisfb MMIO")) {
 		printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
 		release_mem_region(ivideo.video_base, ivideo.video_size);
+		vfree(sishw_ext.pSR);
+		vfree(sishw_ext.pCR);
 		return -ENODEV;
 	}
-	// Eden Chen
-	//sishw_ext.VirtualVideoMemoryAddress = ivideo.video_vbase 
-	sishw_ext.pjVideoMemoryAddress = ivideo.video_vbase 
+
+	sishw_ext.pjVideoMemoryAddress = ivideo.video_vbase
 		= ioremap(ivideo.video_base, ivideo.video_size);
-	// Eden Chen
 	ivideo.mmio_vbase = ioremap(ivideo.mmio_base, sisfb_mmio_size);
 
-	printk(KERN_INFO
-	       "sisfb: Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
+	printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
 	       ivideo.video_base, ivideo.video_vbase,
 	       ivideo.video_size / 1024);
 
-	printk(KERN_INFO
-	       "sisfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
+	printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
 	       ivideo.mmio_base, ivideo.mmio_vbase,
 	       sisfb_mmio_size / 1024);
 
+	if(sisfb_heap_init()) {
+		printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
+	}
+
+	ivideo.mtrr = (unsigned int) 0;
+
 	if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
 
 #ifdef CONFIG_FB_SIS_300
 		if (sisvga_engine == SIS_300_VGA) {
 			sisfb_get_VB_type_300();
-			if (ivideo.hasVB != HASVB_NONE) {
-				sisfb_detect_VB_connect_300();
-			}
 		}
 #endif
 
 #ifdef CONFIG_FB_SIS_315
 		if (sisvga_engine == SIS_315_VGA) {
 			sisfb_get_VB_type_315();
-			if (ivideo.hasVB != HASVB_NONE) {
-				sisfb_detect_VB_connect_315();
-			}
 		}
 #endif
 
-		// Eden Chen
 		sishw_ext.ujVBChipID = VB_CHIP_UNKNOWN;
 		sishw_ext.usExternalChip = 0;
 
 		switch (ivideo.hasVB) {
 
 		case HASVB_301:
-			/*karl*/
-			vgawb(VB_PART4_ADR,0x01);
-			reg = vgarb(VB_PART4_DATA);
-			if (reg >= 0xD0) {
-				sishw_ext.ujVBChipID = VB_CHIP_301B;
-				printk(KERN_INFO "sisfb: SiS301LV bridge detected\n");
+		        inSISIDXREG(SISPART4, 0x01, reg);
+			if (reg >= 0xE0) {
+				sishw_ext.ujVBChipID = VB_CHIP_301LVX;
+				printk(KERN_INFO "sisfb: SiS301LVX bridge detected (revision 0x%02x)\n",reg);
+	  		} else if (reg >= 0xD0) {
+				sishw_ext.ujVBChipID = VB_CHIP_301LV;
+				printk(KERN_INFO "sisfb: SiS301LV bridge detected (revision 0x%02x)\n",reg);
 	  		} else if (reg >= 0xB0) {
 				sishw_ext.ujVBChipID = VB_CHIP_301B;
-				printk(KERN_INFO "sisfb: SiS301B bridge detected\n");
+				printk(KERN_INFO "sisfb: SiS301B bridge detected (revision 0x%02x\n",reg);
 			} else {
 				sishw_ext.ujVBChipID = VB_CHIP_301;
 				printk(KERN_INFO "sisfb: SiS301 bridge detected\n");
 			}
 			break;
 		case HASVB_302:
-			vgawb(VB_PART4_ADR,0x01);
-			reg = vgarb(VB_PART4_DATA);
-			sishw_ext.ujVBChipID = VB_CHIP_302;
-			if (reg >= 0xD0) {
-				printk(KERN_INFO "sisfb: SiS302LV bridge detected\n");
+		        inSISIDXREG(SISPART4, 0x01, reg);
+			if (reg >= 0xE0) {
+				sishw_ext.ujVBChipID = VB_CHIP_302LVX;
+				printk(KERN_INFO "sisfb: SiS302LVX bridge detected (revision 0x%02x)\n",reg);
+	  		} else if (reg >= 0xD0) {
+				sishw_ext.ujVBChipID = VB_CHIP_302LV;
+				printk(KERN_INFO "sisfb: SiS302LV bridge detected (revision 0x%02x)\n",reg);
 	  		} else if (reg >= 0xB0) {
-				printk(KERN_INFO "sisfb: SiS302B bridge detected\n");
+			        sishw_ext.ujVBChipID = VB_CHIP_302B;
+				printk(KERN_INFO "sisfb: SiS302B bridge detected (revision 0x%02x)\n",reg);
 			} else {
+			        sishw_ext.ujVBChipID = VB_CHIP_302;
 				printk(KERN_INFO "sisfb: SiS302 bridge detected\n");
 			}
 			break;
@@ -3085,108 +3597,64 @@
 			break;
 		case HASVB_LVDS:
 			sishw_ext.usExternalChip = 0x1;
-			printk(KERN_INFO "sisfb: LVDS bridge detected\n");
+			printk(KERN_INFO "sisfb: LVDS transmitter detected\n");
 			break;
 		case HASVB_TRUMPION:
 			sishw_ext.usExternalChip = 0x2;
-			printk(KERN_INFO "sisfb: TRUMPION TV converter detected\n");
+			printk(KERN_INFO "sisfb: Trumpion Zurac LVDS scaler detected\n");
 			break;
 		case HASVB_CHRONTEL:
 			sishw_ext.usExternalChip = 0x4;
-			printk(KERN_INFO "sisfb: Chrontel TV converter detected\n");
+			printk(KERN_INFO "sisfb: Chrontel TV encoder detected\n");
 			break;
 		case HASVB_LVDS_CHRONTEL:
 			sishw_ext.usExternalChip = 0x5;
-			printk(KERN_INFO "sisfb: LVDS bridge and Chrontel TV converter detected\n");
+			printk(KERN_INFO "sisfb: LVDS transmitter and Chrontel TV encoder detected\n");
 			break;
 		default:
 			printk(KERN_INFO "sisfb: No or unknown bridge type detected\n");
 			break;
 		}
-		// ~Eden Chen
 
-		/* TW: Determine and detect attached TV's on Chrontel */
-		if (sishw_ext.usExternalChip == 0x04 || sishw_ext.usExternalChip == 0x05) {
-		    SiSRegInit(sishw_ext.ulIOAddress);
-		    temp1=SiS_GetCH7005(0x25);
-		    if ((temp1 >= 50) && (temp1 <= 100)) {
-	    		/* TW: Read power status */
-	    		temp1 = SiS_GetCH7005(0x0e);
-	    		if ((temp1&0x03)!=0x03) {
-		        	/* TW: Power all outputs */
-	        		SiS_SetCHTVRegANDOR(0x030E,0xF8);
-	    		}
-			/* TW: Sense connected TV devices */
-	    		SiS_SetCH7005(0x0110);
-	    		SiS_SetCH7005(0x0010);
-	    		temp1 = SiS_GetCH7005(0x10);
-	    		if (!(temp1 & 0x08)) {
-				/* TW: So we can be sure that there IS a SVHS output */
-				printk(KERN_INFO
-				   "sisfb: Chrontel: Detected TV connected to SVHS output\n");
-				ivideo.TV_plug = TVPLUG_SVIDEO;
-				vgawb(CRTC_ADR, 0x32);
-				temp2 = vgarb(CRTC_DATA) | 0x02;
-				vgawb(CRTC_DATA, temp2);
-			} else if (!(temp1 & 0x02)) {
-				/* TW: So we can be sure that there IS a CVBS output */
-				printk(KERN_INFO
-				   "sisfb: Chrontel: Detected TV connected to CVBS output\n");
-				ivideo.TV_plug = TVPLUG_COMPOSITE;
-				vgawb(CRTC_ADR, 0x32);
-				temp2 = vgarb(CRTC_DATA) | 0x01;
-				vgawb(CRTC_DATA, temp2);
-	    		} else {
-		    		SiS_SetCHTVRegANDOR(0x010E,0xF8);
-	    		}
-		    } else if (temp1==0) {
-	    		        SiS_SetCHTVRegANDOR(0x010E,0xF8);
-	    	    }
-	    	}
+		if (ivideo.hasVB != HASVB_NONE) {
+#ifdef CONFIG_FB_SIS_300
+		      if (sisvga_engine == SIS_300_VGA) {
+				sisfb_detect_VB_connect_300();
+                      }
+#endif
+#ifdef CONFIG_FB_SIS_315
+		      if (sisvga_engine == SIS_315_VGA) {
+				sisfb_detect_VB_connect_315();
+                      }
+#endif
+		}
 
 		if (ivideo.disp_state & DISPTYPE_DISP2) {
 			if (sisfb_crt1off)
 				ivideo.disp_state |= DISPMODE_SINGLE;
 			else
 				ivideo.disp_state |= (DISPMODE_MIRROR | DISPTYPE_CRT1);
-		} else
+		} else {
 			ivideo.disp_state = DISPMODE_SINGLE | DISPTYPE_CRT1;
+		}
 
 		if (ivideo.disp_state & DISPTYPE_LCD) {
-			vgawb(CRTC_ADR, IND_SIS_LCD_PANEL);
-			reg = vgarb(CRTC_DATA);
-			// Eden Chen
-			switch (reg) {
-			   case SIS_LCD_PANEL_800X600:
-				sishw_ext.ulCRT2LCDType = LCD_800x600;
-				break;
-			   case SIS_LCD_PANEL_1024X768:
-				sishw_ext.ulCRT2LCDType = LCD_1024x768;
-				break;
-			   case SIS_LCD_PANEL_1280X1024:
-				sishw_ext.ulCRT2LCDType = LCD_1280x1024;
-				break;
-			   case SIS_LCD_PANEL_640X480:
-				sishw_ext.ulCRT2LCDType = LCD_640x480;
-				break;
-			   case SIS_LCD_PANEL_1280X960:
-				sishw_ext.ulCRT2LCDType = LCD_1280x960;
-				break;
-			   case SIS_LCD_PANEL_1600x1200: /* TW */
-				sishw_ext.ulCRT2LCDType = LCD_1600x1200;
-				break;
-			   case SIS_LCD_PANEL_320x480:   /* TW: FSTN */
-				sishw_ext.ulCRT2LCDType = LCD_320x480;
-				break;
-			   default:
-				sishw_ext.ulCRT2LCDType = LCD_1024x768;
-				break;
+		    if (!enable_dstn) {
+		        inSISIDXREG(SISCR, IND_SIS_LCD_PANEL, reg);
+			reg &= 0x0f;
+			if (sisvga_engine == SIS_300_VGA) {
+			    sishw_ext.ulCRT2LCDType = sis300paneltype[reg];
+			} else {
+			    sishw_ext.ulCRT2LCDType = sis310paneltype[reg];
 			}
-			// ~Eden Chen
+		    } else {
+		        /* TW: FSTN/DSTN */
+			sishw_ext.ulCRT2LCDType = LCD_320x480;
+		    }
 		}
 
 		if (sisfb_mode_idx >= 0)
-			sisfb_validate_mode();
+			sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx);
 
 		if (sisfb_mode_idx < 0) {
 			switch (ivideo.disp_state & DISPTYPE_DISP2) {
@@ -3216,195 +3684,404 @@
 		ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres;
 		ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres;
 		ivideo.org_x = ivideo.org_y = 0;
-		video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
+		ivideo.video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
+		switch(ivideo.video_bpp) {
+        	case 8:
+            		ivideo.DstColor = 0x0000;
+	    		ivideo.SiS310_AccelDepth = 0x00000000;
+			ivideo.video_cmap_len = 256;
+            		break;
+        	case 16:
+            		ivideo.DstColor = 0x8000;
+            		ivideo.SiS310_AccelDepth = 0x00010000;
+			ivideo.video_cmap_len = 16;
+            		break;
+        	case 32:
+            		ivideo.DstColor = 0xC000;
+	    		ivideo.SiS310_AccelDepth = 0x00020000;
+			ivideo.video_cmap_len = 16;
+            		break;
+		default:
+			ivideo.video_cmap_len = 16;
+		        printk(KERN_INFO "sisfb: Unsupported accel depth %d", ivideo.video_bpp);
+			sisfb_accel = 0;
+			break;
+    		}
 
-		printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz), linelength=%d\n",
+		printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
 	       		ivideo.video_width, ivideo.video_height, ivideo.video_bpp,
-			ivideo.refresh_rate, video_linelength);
-
-		// Eden Chen
-		// Check interface correction  For Debug
-		DPRINTK("VM Adr=0x%p\n", sishw_ext.pjVideoMemoryAddress);
-		DPRINTK("VM Size=%ldK\n", sishw_ext.ulVideoMemorySize/1024);
-		DPRINTK("IO Adr=0x%lx\n", sishw_ext.ulIOAddress);
-		DPRINTK("Chip=%d\n", sishw_ext.jChipType);
-		DPRINTK("ChipRevision=%d\n", sishw_ext.jChipRevision);
-		DPRINTK("VBChip=%d\n", sishw_ext.ujVBChipID);
-		DPRINTK("ExtVB=%d\n", sishw_ext.usExternalChip);
-		DPRINTK("LCD=%ld\n", sishw_ext.ulCRT2LCDType);
-		DPRINTK("bIntegratedMMEnabled=%d\n", sishw_ext.bIntegratedMMEnabled);
-		// ~Eden Chen
+			ivideo.refresh_rate);
 
 		sisfb_pre_setmode();
 
-		if (SiSSetMode(&sishw_ext, sisfb_mode_no) == 0) {
-			DPRINTK("set mode[0x%x]: failed\n", sisfb_mode_no);
+		if (SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) {
+			printk("sisfb: Setting mode[0x%x] failed, using default mode\n", sisfb_mode_no);
 			return -1;
 		}
 
-		vgawb(SEQ_ADR, IND_SIS_PASSWORD);
-		vgawb(SEQ_DATA, SIS_PASSWORD);
+		outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 
 		sisfb_post_setmode();
 
 		sisfb_crtc_to_var(&default_var);
 
-		fb_info.changevar = NULL;
+		if(sisfb_accel) {
+		   sisfb_initaccel();
+		}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)	/* ---- 2.4 series init ---- */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+		sis_fb_info.screen_base = ivideo.video_vbase;
+		sis_fb_info.currcon = -1;
+#endif
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-		fb_info.node = -1;
+		sis_fb_info.node = -1;
 #else
-		fb_info.node = NODEV;
+		sis_fb_info.node = NODEV;
+#endif
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,23)
+		sis_fb_info.blank = &sisfb_blank;
 #endif
-		fb_info.fbops = &sisfb_ops;
-		fb_info.disp = &disp;
-		fb_info.switch_con = &sisfb_switch;
-		fb_info.updatevar = &sisfb_update_var;
-		fb_info.blank = &sisfb_blank;
-		fb_info.flags = FBINFO_FLAG_DEFAULT;
+		sis_fb_info.fbops = &sisfb_ops;
+		sis_fb_info.switch_con = &sisfb_switch;
+		sis_fb_info.updatevar = &sisfb_update_var;
+		sis_fb_info.changevar = NULL;
+		sis_fb_info.disp = &sis_disp;
+		sis_fb_info.flags = FBINFO_FLAG_DEFAULT;
 
-		sisfb_set_disp(-1, &default_var);
+		sisfb_set_disp(-1, &default_var, &sis_fb_info);
+#endif
 
-	} /* TW: if mode = "none" */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)	/* ---- 2.5 series init ---- */
+		sis_fb_info.screen_base = ivideo.video_vbase;
+		sis_fb_info.node = NODEV;
+		sis_fb_info.fbops = &sisfb_ops;
+		sisfb_get_fix(&sis_fb_info.fix, -1, &sis_fb_info);
+		sis_fb_info.pseudo_palette = pseudo_palette;
+		sis_fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+		sis_fb_info.changevar = NULL;
+		sis_fb_info.currcon = -1;
+		sis_fb_info.disp = &sis_disp;
+		sis_fb_info.switch_con = gen_switch;
+		sis_fb_info.updatevar = gen_update_var;
 
-	if (sisfb_heap_init()) {
-		printk("sisfb: Failed to initialize offscreen memory heap\n");
-	}
+		fb_alloc_cmap(&sis_fb_info.cmap, 256, 0);
 
-        ivideo.mtrr = (unsigned int) 0;
-	if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
-         	/*H.C.*/
+		sis_fb_info.var = default_var;
+#endif
+
+#ifdef CONFIG_MTRR
 		ivideo.mtrr = mtrr_add((unsigned int) ivideo.video_base,
 				(unsigned int) ivideo.video_size,
 				MTRR_TYPE_WRCOMB, 1);
-      		/*
-			if (ivideo.mtrr >= 0) {
-           		printk(KERN_INFO "Succeed to turn on Write-Combining on VideoMemory %08XH, Size: %08XH\n",
-					ivideo.video_base, ivideo.video_size);
-      			} else	{
-           		printk(KERN_INFO "Fail to turn on Write-Combining on Video Memory 0x%08X, Size: 0x%08X\n",
-					ivideo.video_base, ivideo.video_size);
-      			}
-        	*/
-		vc_resize_con(1, 1, 0);
+		if(ivideo.mtrr) {
+			printk(KERN_INFO "sisfb: Added MTRRs\n");
+		}
+#endif
 
-		if (register_framebuffer(&fb_info) < 0)
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+		vc_resize_con(1, 1, 0);
+#endif
+		TWDEBUG("Before calling register_framebuffer");
+		if(register_framebuffer(&sis_fb_info) < 0)
 			return -EINVAL;
 
+		printk(KERN_INFO "sisfb: Installed SISFB_GET_INFO ioctl (%x)\n", SISFB_GET_INFO);
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+		printk(KERN_INFO "sisfb: 2D acceleration is %s, scrolling mode %s\n",
+		     sisfb_accel ? "enabled" : "disabled",
+		     sisfb_ypan  ? "ypan" : "redraw");
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+		printk(KERN_INFO "sisfb: 2D acceleration is %s\n",
+		     sisfb_accel ? "enabled" : "disabled");
+#endif
+
 		printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%02d\n",
-	       		GET_FB_IDX(fb_info.node), fb_info.modename, VER_MAJOR, VER_MINOR,
+	       		GET_FB_IDX(sis_fb_info.node), sis_fb_info.modename, VER_MAJOR, VER_MINOR,
 	       		VER_LEVEL);
 
+
 	}	/* TW: if mode = "none" */
 	return 0;
 }
 
+/* ------------------------------------------------------------------------------ */
+
+/* TW: As long as the generic framebuffer parts don't work as modules, we use
+   our own stuff here. I can't debug a fb driver if I need to compile the driver
+   into the kernel. It simply drives me nuts.
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,33)
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+
+#include <video/fbcon.h>
+
+void my_cfb_imageblit(struct fb_info *p, struct fb_image *image)
+{
+	int pad, ppw;
+	int x2, y2, n, i, j, k, l = 7;
+	unsigned long tmp = ~0 << (BITS_PER_LONG - p->var.bits_per_pixel);
+	unsigned long fgx, bgx, fgcolor, bgcolor, eorx;
+	unsigned long end_mask;
+	unsigned long *dst = NULL;
+	u8 *dst1;
+	u8 *src;
+
+	/*
+	 * We could use hardware clipping but on many cards you get around hardware
+	 * clipping by writing to framebuffer directly like we are doing here.
+	 */
+	x2 = image->dx + image->width;
+	y2 = image->dy + image->height;
+	image->dx = image->dx > 0 ? image->dx : 0;
+	image->dy = image->dy > 0 ? image->dy : 0;
+	x2 = x2 < p->var.xres_virtual ? x2 : p->var.xres_virtual;
+	y2 = y2 < p->var.yres_virtual ? y2 : p->var.yres_virtual;
+	image->width  = x2 - image->dx;
+	image->height = y2 - image->dy;
+
+	dst1 = p->screen_base + image->dy * p->fix.line_length +
+		((image->dx * p->var.bits_per_pixel) >> 3);
+
+	ppw = BITS_PER_LONG/p->var.bits_per_pixel;
+
+	src = image->data;
+
+	if (image->depth == 1) {
+
+		if (p->fix.visual == FB_VISUAL_TRUECOLOR) {
+			fgx = fgcolor = ((u32 *)(p->pseudo_palette))[image->fg_color];
+			bgx = bgcolor = ((u32 *)(p->pseudo_palette))[image->bg_color];
+		} else {
+			fgx = fgcolor = image->fg_color;
+			bgx = bgcolor = image->bg_color;
+		}
+
+		for (i = 0; i < ppw-1; i++) {
+			fgx <<= p->var.bits_per_pixel;
+			bgx <<= p->var.bits_per_pixel;
+			fgx |= fgcolor;
+			bgx |= bgcolor;
+		}
+		eorx = fgx ^ bgx;
+		n = ((image->width + 7) >> 3);
+		pad = (n << 3) - image->width;
+		n = image->width % ppw;
+
+		for (i = 0; i < image->height; i++) {
+			dst = (unsigned long *) dst1;
+
+			for (j = image->width/ppw; j > 0; j--) {
+				end_mask = 0;
+
+				for (k = ppw; k > 0; k--) {
+					if (test_bit(l, (unsigned long *) src))
+						end_mask |= (tmp >> (p->var.bits_per_pixel*(k-1)));
+					l--;
+					if (l < 0) { l = 7; src++; }
+				}
+				fb_writel((end_mask & eorx)^bgx, dst);
+				dst++;
+			}
+
+			if (n) {
+				end_mask = 0;
+				for (j = n; j > 0; j--) {
+					if (test_bit(l, (unsigned long *) src))
+						end_mask |= (tmp >> (p->var.bits_per_pixel*(j-1)));
+					l--;
+					if (l < 0) { l = 7; src++; }
+				}
+				fb_writel((end_mask & eorx)^bgx, dst);
+				dst++;
+			}
+			l -= pad;
+			dst1 += p->fix.line_length;
+		}
+	} else {
+		/* Draw the penguin */
+		n = ((image->width * p->var.bits_per_pixel) >> 3);
+		end_mask = 0;
+	}
+}
+#endif
+/* -------------------------------------------------------------------------------- */
+
+
 #ifdef MODULE
 
-static char *mode = NULL;
+static char         *mode = NULL;
+static int          vesa = -1;
 static unsigned int rate = 0;
 static unsigned int crt1off = 1;
 static unsigned int mem = 0;
 static unsigned int dstn = 0;
-static char *forcecrt2type = NULL;
-static int forcecrt1 = -1;
-static char *queuemode = NULL;
+static char         *forcecrt2type = NULL;
+static int          forcecrt1 = -1;
+static char         *queuemode = NULL;
+static int          pdc = 0;
+static int          noaccel = -1;
+static int          noypan  = -1;
+static int          inverse = 0;
 
 MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/650/740 framebuffer driver");
-MODULE_LICENSE("GPL");    /* TW (Code is officially open says SiS) */
-MODULE_AUTHOR("Various; SiS; Some parts by Thomas Winischhofer <thomas@winischhofer.net>");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Various; SiS; Thomas Winischhofer <thomas@winischhofer.net>");
 
 MODULE_PARM(mode, "s");
 MODULE_PARM_DESC(mode,
-       "Selects the desired display mode in the format [X]x[Y]x[Depth], eg. 800x600x16 "
-       "(default: none; this leaves the console untouched and the driver will only do "
-       "the video memory management for eg. DRM/DRI)");
+       "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
+         "800x600x16 (default: none if sisfb is a module; this leaves the\n"
+	 "console untouched and the driver will only do the video memory\n"
+	 "management for eg. DRM/DRI; 800x600x8 if sisfb is in the kernel)");
+
+MODULE_PARM(vesa, "i");
+MODULE_PARM_DESC(vesa,
+       "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
+         "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
+	 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
+	 "0x0103 if sisfb is in the kernel)");
 
 MODULE_PARM(rate, "i");
 MODULE_PARM_DESC(rate,
-	"Selects the desired vertical refresh rate for CRT1 (external VGA) in Hz. "
+	"\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
 	"(default: 60)");
 
 MODULE_PARM(crt1off,   "i");
 MODULE_PARM_DESC(crt1off,
-	"If this option is set, the driver will switch off CRT1 (external VGA). "
 	"(Deprecated, please use forcecrt1)");
 
 MODULE_PARM(filter, "i");
 MODULE_PARM_DESC(filter,
-	"Selects TV flicker filter type (only for SiS30x video bridges). "
-	"(Possible values 0-7, default: [no filter])");
+	"\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
+	  "(Possible values 0-7, default: [no filter])");
 
 MODULE_PARM(dstn,   "i"); /* JennyLee 20011211 */
 MODULE_PARM_DESC(dstn,
-	"Selects DSTN display mode (1=ON, 0=OFF) (default: 0)");
+	"\nSelects DSTN/FSTN display mode for SiS550. This sets CRT2 type to LCD and\n"
+	  "overrides forcecrt2type setting. (1=ON, 0=OFF) (default: 0)");
 
 MODULE_PARM(queuemode,   "s");
 MODULE_PARM_DESC(queuemode,
-	"Selects the queue mode on 315/550/650/740. Possible choices are AGP, VRAM "
-	"or MMIO. AGP is only available if the kernel has AGP support. "
-	"The queue mode is important to programs using the 2D/3D accelerator of "
-	"the SiS chip. The modes require a totally different way of programming "
-	"the engines. On 300/540/630/730, this option is ignored. (default: MMIO)");
+	"\nSelects the queue mode on 315/550/650/740. Possible choices are AGP, VRAM or\n"
+  	  "MMIO. AGP is only available if the kernel has AGP support. The queue mode is\n"
+	  "important to programs using the 2D/3D accelerator of the SiS chip. The modes\n"
+	  "require a totally different way of programming the engines. If any mode than\n"
+	  "MMIO is selected, sisfb will disable its own 2D acceleration. On\n"
+	  "300/540/630/730, this option is ignored. (default: MMIO)");
 
 /* TW: "Import" the options from the X driver */
 MODULE_PARM(mem,    "i");
 MODULE_PARM_DESC(mem,
-	"Determines the beginning of the video memory heap in KB. This heap is used for "
-	"video RAM management for eg. DRM/DRI. The default depends on the amount of video "
-	"memory available. If 8MB of video RAM or less is available, "
-	"the heap starts at 4096KB, otherwise at 8192KB. The value is to be specified "
-	"without 'KB' and should match MaxXFBMem setting for XFree 4.x (x>=2). "
-	"See http://www.winischhofer.net/linuxsis630.shtml for a closer description.");
+	"\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
+	  "for video RAM management for eg. DRM/DRI. The default depends on the amount\n"
+	  "of video RAM available. If 8MB of video RAM or less is available, the heap\n"
+	  "starts at 4096KB, if between 8 and 16MB are available at 8192KB, otherwise\n"
+	  "at 12288KB. The value is to be specified without 'KB' and should match\n"
+	  "the MaxXFBMem setting for XFree 4.x (x>=2).");
 
 MODULE_PARM(forcecrt2type, "s");
 MODULE_PARM_DESC(forcecrt2type,
-	"If this option is omitted, the driver autodetects CRT2 output devices, such as LCD, "
-	"TV or secondary VGA (in this order; so if eg. an LCD is there, it will be used regardless "
-	"of a connected TV set). With this option, this autodetection can be overridden. "
-	"Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2 and makes it "
-	"possible to use higher resolutions on CRT1 than eg. your LCD panel supports. TV "
-	"selects TV output (only resolutions 640x480 and 800x600 are supported for TV!). "
-	"VGA refers to _secondary_ VGA which is unlikely to be available; the VGA plug found "
-	"on most machines is CRT1. (default: [autodetected])");
+	"\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
+	  "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
+	  "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
+	  "On systems with a 301(B) bridge, parameters SVIDEO, COMPOSITE or SCART can be\n"
+	  "used instead of TV to override the TV detection. (default: [autodetected])");
 
 MODULE_PARM(forcecrt1, "i");
 MODULE_PARM_DESC(forcecrt1,
-	"Normally, the driver autodetects whether or not CRT1 (external VGA) is connected. "
-	"With this option, the detection can be overridden (1=CRT1 ON, 0=CRT1 off) "
-	"(default: [autodetected])");
+	"\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
+	  "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
+	  " 0=CRT1 off) (default: [autodetected])");
+
+MODULE_PARM(pdc, "i");
+MODULE_PARM_DESC(pdc,
+        "\n(300 series only) This is for manually selecting the LCD panel delay\n"
+	  "compensation. The driver should detect this correctly in most cases; however,\n"
+	  "sometimes this is not possible. If you see 'small waves' on the LCD, try\n"
+	  "setting this to 4, 32 or 24. If the problem persists, try other values\n"
+	  "between 4 and 60 in steps of 4. (default: [autodetected])");
+
+MODULE_PARM(noaccel, "i");
+MODULE_PARM_DESC(noaccel,
+        "\nIf set to anything other than 0, 2D acceleration and y-panning will be\n"
+	"disabled. (default: 0)");
+
+MODULE_PARM(noypan, "i");
+MODULE_PARM_DESC(noypan,
+        "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
+	"will be performed by redrawing the screen. This required 2D acceleration, so\n"
+	"if the option noaccel is set, y-panning will be disabled. (default: 0)");
+
+MODULE_PARM(inverse, "i");
+MODULE_PARM_DESC(inverse,
+        "\nSetting this to anything but 0 should invert the display colors, but this\n"
+	"does not seem to work. (default: 0)");
 
 int init_module(void)
 {
-	if (mode)
+	if(mode)
 		sisfb_search_mode(mode);
-	else  /* TW: set mode=none if no mode parameter is given */
+	else if(vesa != -1)
+		sisfb_search_vesamode(vesa);
+	else  /* TW: set mode=none if no mode is given - we do this only if we are a module */
 		sisfb_mode_idx = MODE_INDEX_NONE;
 
 	ivideo.refresh_rate = rate;
 
-	if (forcecrt2type)
+	if(forcecrt2type)
 		sisfb_search_crt2type(forcecrt2type);
 
-	if (crt1off == 0)
+	if(crt1off == 0)
 		sisfb_crt1off = 1;
 	else
 		sisfb_crt1off = 0;
 
 	sisfb_forcecrt1 = forcecrt1;
-	if (forcecrt1 == 1)
+	if(forcecrt1 == 1)
 		sisfb_crt1off = 0;
-	else if (forcecrt1 == 0)
+	else if(forcecrt1 == 0)
 		sisfb_crt1off = 1;
 
-	if (mem)
-		sisfb_mem = mem;
+	if(noaccel == 1)      sisfb_accel = 0;
+	else if(noaccel == 0) sisfb_accel = 1;
+
+	if(noypan == 1)       sisfb_ypan = 0;
+	else if(noypan == 0)  sisfb_ypan = 1;
+
+	/* TW: Panning only with acceleration */
+	if(sisfb_accel == 0)  sisfb_ypan = 0;
 
-	enable_dstn = dstn; /* JennyLee 20011211 */
+	if(inverse)           sisfb_inverse = 1;
 
-	if (queuemode)
-		sisfb_search_queuemode(queuemode);
+	if(mem)		      sisfb_mem = mem;
 
-	sisfb_init();
+	enable_dstn = dstn;
+
+	/* TW: DSTN overrules forcecrt2type */
+	if (enable_dstn)      sisfb_crt2type = DISPTYPE_LCD;
+
+	if (queuemode)        sisfb_search_queuemode(queuemode);
+	/* TW: If other queuemode than MMIO, disable 2D accel any ypan */
+	if((sisfb_queuemode != -1) && (sisfb_queuemode != MMIO_CMD)) {
+	        sisfb_accel = 0;
+		sisfb_ypan = 0;
+	}
+
+        if(pdc) {
+	   if(!(pdc & ~0x3c)) {
+	        sisfb_pdc = pdc & 0x3c;
+	   }
+	}
+
+	if(sisfb_init() < 0) return -ENODEV;
 
 	return 0;
 }
@@ -3414,14 +4091,17 @@
 	/* TW: Release mem regions */
 	release_mem_region(ivideo.video_base, ivideo.video_size);
 	release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
+#ifdef CONFIG_MTRR
 	/* TW: Release MTRR region */
-	if (ivideo.mtrr) mtrr_del(ivideo.mtrr, 
+	if(ivideo.mtrr) mtrr_del(ivideo.mtrr,
 			      (unsigned int)ivideo.video_base,
 	                      (unsigned int)ivideo.video_size);
+#endif
 	/* Unregister the framebuffer */
-	unregister_framebuffer(&fb_info);
+	unregister_framebuffer(&sis_fb_info);
 	printk(KERN_INFO "sisfb: Module unloaded\n");
 }
+
 #endif
 
 EXPORT_SYMBOL(sis_malloc);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/sis_main.h linux-2.4.20/drivers/video/sis/sis_main.h
--- linux-2.4.19/drivers/video/sis/sis_main.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/sis_main.h	2002-10-29 11:18:35.000000000 +0000
@@ -1,16 +1,22 @@
 #ifndef _SISFB_MAIN
 #define _SISFB_MAIN
 
-/* Comments and changes marked with "TW" by Thomas Winischhofer <tw@webit.com> */
+/* Comments and changes marked with "TW" by Thomas Winischhofer <thomas@winischhofer.net> */
+
+#include "vstruct.h"
 
 /* ------------------- Constant Definitions ------------------------- */
 
-#undef LINUXBIOS   /* turn on when use LINUXBIOS */
+#undef LINUXBIOS   /* turn this on when compiling for LINUXBIOS */
 #define AGPOFF     /* default is turn off AGP */
 
+#define SISFAIL(x) do { printk(x "\n"); return -EINVAL; } while(0)
+
 #define VER_MAJOR                 1
-#define VER_MINOR                 3
-#define VER_LEVEL                 13 
+#define VER_MINOR                 5
+#define VER_LEVEL                 7
+
+#include "sis.h"
 
 /* TW: To be included in pci_ids.h */
 #ifndef PCI_DEVICE_ID_SI_650_VGA
@@ -21,17 +27,13 @@
 #endif
 /* TW end */
 
-#define DEFAULT_MODE              3
-#define DEFAULT_LCDMODE           12
-#define DEFAULT_TVMODE            12
-#define MODE_INDEX_NONE           0 /* TW: index for mode=none */
-
 #define MAX_ROM_SCAN              0x10000
 
-#define TURBO_QUEUE_CAP           0x80
-#define HW_CURSOR_CAP             0x40
-#define AGP_CMD_QUEUE_CAP         0x80
-#define VM_CMD_QUEUE_CAP          0x20
+#define HW_CURSOR_CAP             0x80
+#define TURBO_QUEUE_CAP           0x40
+#define AGP_CMD_QUEUE_CAP         0x20
+#define VM_CMD_QUEUE_CAP          0x10
+#define MMIO_CMD_QUEUE_CAP        0x08
 
 /* For 300 series */
 #ifdef CONFIG_FB_SIS_300
@@ -68,6 +70,19 @@
 #define VB_PART4_ADR              (0x14-0x30)
 #define VB_PART4_DATA             (0x15-0x30)
 
+#define SISSR			  SiS_Pr.SiS_P3c4
+#define SISCR                     SiS_Pr.SiS_P3d4
+#define SISDACA                   SiS_Pr.SiS_P3c8
+#define SISDACD                   SiS_Pr.SiS_P3c9
+#define SISPART1                  SiS_Pr.SiS_Part1Port
+#define SISPART2                  SiS_Pr.SiS_Part2Port
+#define SISPART3                  SiS_Pr.SiS_Part3Port
+#define SISPART4                  SiS_Pr.SiS_Part4Port
+#define SISPART5                  SiS_Pr.SiS_Part5Port
+#define SISDAC2A                  SISPART5
+#define SISDAC2D                  (SISPART5 + 1)
+#define SISMISCR                  (SiS_Pr.RelIO + 0x1c)
+
 #define IND_SIS_PASSWORD          0x05  /* SRs */
 #define IND_SIS_COLOR_MODE        0x06
 #define IND_SIS_RAMDAC_CONTROL    0x07
@@ -92,16 +107,14 @@
 #define IND_SIS_SCRATCH_REG_CR37  0x37
 #define IND_SIS_AGP_IO_PAD        0x48
 
-#define IND_BRI_DRAM_STATUS       0x63 /* PCI memory size offset */
+#define IND_BRI_DRAM_STATUS       0x63 /* PCI config memory size offset */
 
 #define MMIO_QUEUE_PHYBASE        0x85C0
 #define MMIO_QUEUE_WRITEPORT      0x85C4
 #define MMIO_QUEUE_READPORT       0x85C8
 
-/* Eden Chen; TW */
 #define IND_SIS_CRT2_WRITE_ENABLE_300 0x24
 #define IND_SIS_CRT2_WRITE_ENABLE_315 0x2F
-/* ~Eden Chen; TW */
 
 #define SIS_PASSWORD              0x86  /* SR05 */
 #define SIS_INTERLACED_MODE       0x20  /* SR06 */
@@ -109,7 +122,7 @@
 #define SIS_15BPP_COLOR_MODE      0x1 
 #define SIS_16BPP_COLOR_MODE      0x2 
 #define SIS_32BPP_COLOR_MODE      0x4 
-#define SIS_DRAM_SIZE_MASK        0x3F  /* SR14 */
+#define SIS_DRAM_SIZE_MASK        0x3F  /* 300/630/730 SR14 */
 #define SIS_DRAM_SIZE_1MB         0x00
 #define SIS_DRAM_SIZE_2MB         0x01
 #define SIS_DRAM_SIZE_4MB         0x03
@@ -122,7 +135,7 @@
 #define SIS_DATA_BUS_64           0x01
 #define SIS_DATA_BUS_128          0x02
 
-#define SIS315_DRAM_SIZE_MASK     0xF0  /* 315/640?/740? SR14 */
+#define SIS315_DRAM_SIZE_MASK     0xF0  /* 315 SR14 */
 #define SIS315_DRAM_SIZE_2MB      0x01
 #define SIS315_DRAM_SIZE_4MB      0x02
 #define SIS315_DRAM_SIZE_8MB      0x03
@@ -139,7 +152,7 @@
 #define SIS315_ASYM_DDR		  	0x02
 #define SIS315_DUAL_CHANNEL_1_RANK    	0x3
 
-#define SIS550_DRAM_SIZE_MASK     0x3F  /* 550/650 SR14 */
+#define SIS550_DRAM_SIZE_MASK     0x3F  /* 550/650/740 SR14 */
 #define SIS550_DRAM_SIZE_4MB      0x00
 #define SIS550_DRAM_SIZE_8MB      0x01
 #define SIS550_DRAM_SIZE_16MB     0x03
@@ -157,7 +170,7 @@
 #define SIS_MEM_MAP_IO_ENABLE     0x01  /* SR20 */
 #define SIS_PCI_ADDR_ENABLE       0x80
 
-#define SIS_AGP_CMDQUEUE_ENABLE   0x80  /* 315 SR26 */
+#define SIS_AGP_CMDQUEUE_ENABLE   0x80  /* 315/650/740 SR26 */
 #define SIS_VRAM_CMDQUEUE_ENABLE  0x40
 #define SIS_MMIO_CMD_ENABLE       0x20
 #define SIS_CMD_QUEUE_SIZE_512k   0x00
@@ -175,8 +188,10 @@
 #define SIS_VB_OUTPUT_LCD         0x20
 #define SIS_VB_OUTPUT_CRT2        0x40
 #define SIS_VB_OUTPUT_HIVISION    0x80
+
 #define SIS_VB_OUTPUT_DISABLE     0x20  /* CR31 */
 #define SIS_DRIVER_MODE           0x40
+
 #define SIS_VB_COMPOSITE          0x01  /* CR32 */
 #define SIS_VB_SVIDEO             0x02
 #define SIS_VB_SCART              0x04
@@ -185,23 +200,21 @@
 #define SIS_CRT1                  0x20
 #define SIS_VB_HIVISION           0x40
 #define SIS_VB_DVI                0x80
-#define SIS_VB_TV                 (SIS_VB_COMPOSITE | SIS_VB_SVIDEO | SIS_VB_SCART | SIS_VB_HIVISION)
-#define SIS_LCD_PANEL_800X600     0x1   /* CR36 */
-#define SIS_LCD_PANEL_1024X768    0x2
-#define SIS_LCD_PANEL_1280X1024   0x3
-#define SIS_LCD_PANEL_1280X960    0x4
-#define SIS_LCD_PANEL_640X480     0x5
-#define SIS_LCD_PANEL_1600x1200   0x6  /* TW */
-#define SIS_LCD_PANEL_320x480	  0x7  /* TW: FSTN */
-#define SIS_EXTERNAL_CHIP_MASK    0x0E  /* CR37 */
-#define SIS_EXTERNAL_CHIP_SIS301        0x01
-#define SIS_EXTERNAL_CHIP_LVDS          0x02  
-#define SIS_EXTERNAL_CHIP_TRUMPION      0x03
-#define SIS_EXTERNAL_CHIP_LVDS_CHRONTEL 0x04
-#define SIS_EXTERNAL_CHIP_CHRONTEL      0x05
+#define SIS_VB_TV                 (SIS_VB_COMPOSITE | SIS_VB_SVIDEO | \
+                                   SIS_VB_SCART | SIS_VB_HIVISION)
+
+#define SIS_EXTERNAL_CHIP_MASK    	   0x0E  /* CR37 */
+#define SIS_EXTERNAL_CHIP_SIS301           0x01  /* in CR37 << 1 ! */
+#define SIS_EXTERNAL_CHIP_LVDS             0x02  /* in CR37 << 1 ! */
+#define SIS_EXTERNAL_CHIP_TRUMPION         0x03  /* in CR37 << 1 ! */
+#define SIS_EXTERNAL_CHIP_LVDS_CHRONTEL    0x04  /* in CR37 << 1 ! */
+#define SIS_EXTERNAL_CHIP_CHRONTEL         0x05  /* in CR37 << 1 ! */
+#define SIS310_EXTERNAL_CHIP_LVDS          0x02  /* in CR37 << 1 ! */
+#define SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL 0x03  /* in CR37 << 1 ! */
+
 #define SIS_AGP_2X                0x20  /* CR48 */
 
-#define BRI_DRAM_SIZE_MASK        0x70  /* PCI bridge */
+#define BRI_DRAM_SIZE_MASK        0x70  /* PCI bridge config data */
 #define BRI_DRAM_SIZE_2MB         0x00
 #define BRI_DRAM_SIZE_4MB         0x01
 #define BRI_DRAM_SIZE_8MB         0x02
@@ -209,44 +222,99 @@
 #define BRI_DRAM_SIZE_32MB        0x04
 #define BRI_DRAM_SIZE_64MB        0x05
 
-// Eden Chen
 #define HW_DEVICE_EXTENSION	  SIS_HW_DEVICE_INFO
 #define PHW_DEVICE_EXTENSION      PSIS_HW_DEVICE_INFO
 
 #define SR_BUFFER_SIZE            5
 #define CR_BUFFER_SIZE            5
-// ~Eden Chen
 
-int enable_dstn = 0;
+/* Useful macros */
+#define inSISREG(base)          inb(base)
+#define outSISREG(base,val)     outb(val,base)
+#define orSISREG(base,val)      do { \
+                                  unsigned char __Temp = inb(base); \
+                                  outSISREG(base, __Temp | (val)); \
+                                } while (0)
+#define andSISREG(base,val)     do { \
+                                  unsigned char __Temp = inb(base); \
+                                  outSISREG(base, __Temp & (val)); \
+                                } while (0)
+#define inSISIDXREG(base,idx,var)   do { \
+                                      outb(idx,base); var=inb((base)+1); \
+                                    } while (0)
+#define outSISIDXREG(base,idx,val)  do { \
+                                      outb(idx,base); outb((val),(base)+1); \
+                                    } while (0)
+#define orSISIDXREG(base,idx,val)   do { \
+                                      unsigned char __Temp; \
+                                      outb(idx,base);   \
+                                      __Temp = inb((base)+1)|(val); \
+                                      outSISIDXREG(base,idx,__Temp); \
+                                    } while (0)
+#define andSISIDXREG(base,idx,and)  do { \
+                                      unsigned char __Temp; \
+                                      outb(idx,base);   \
+                                      __Temp = inb((base)+1)&(and); \
+                                      outSISIDXREG(base,idx,__Temp); \
+                                    } while (0)
+#define setSISIDXREG(base,idx,and,or)   do { \
+                                          unsigned char __Temp; \
+                                          outb(idx,base);   \
+                                          __Temp = (inb((base)+1)&(and))|(or); \
+                                          outSISIDXREG(base,idx,__Temp); \
+                                        } while (0)
 
 /* ------------------- Global Variables ----------------------------- */
 
 /* Fbcon variables */
-static struct fb_info fb_info;
-static struct display disp;
-static int video_type = FB_TYPE_PACKED_PIXELS;
-static int video_linelength;
-static int video_cmap_len;
+static struct fb_info sis_fb_info;
+
+static struct display sis_disp;
+
+static int    video_type = FB_TYPE_PACKED_PIXELS;
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
 static struct display_switch sisfb_sw;
+#endif
+
 static struct fb_var_screeninfo default_var = {
-	0, 0, 0, 0,
-	0, 0,
-	0,
-	0,
-	{0, 8, 0},
-	{0, 8, 0},
-	{0, 8, 0},
-	{0, 0, 0},
-	0,
-	FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0,
-	0,
-	FB_VMODE_NONINTERLACED,
-	{0, 0, 0, 0, 0, 0}
+	xres:           0,
+	yres:           0,
+	xres_virtual:   0,
+	yres_virtual:   0,
+	xoffset:        0,
+	yoffset:        0,
+	bits_per_pixel: 0,
+	grayscale:      0,
+	red:            {0, 8, 0},
+	green:          {0, 8, 0},
+	blue:           {0, 8, 0},
+	transp:         {0, 0, 0},
+	nonstd:         0,
+	activate:       FB_ACTIVATE_NOW,
+	height:         -1,
+	width:          -1,
+	accel_flags:    0,
+	pixclock:       0,
+	left_margin:    0,
+	right_margin:   0,
+	upper_margin:   0,
+	lower_margin:   0,
+	hsync_len:      0,
+	vsync_len:      0,
+	sync:           0,
+	vmode:          FB_VMODE_NONINTERLACED,
+	reserved:       {0, 0, 0, 0, 0, 0}
 };
 
 static struct {
 	u16 blue, green, red, pad;
-} palette[256];
+} sis_palette[256];
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+static u32 pseudo_palette[17];
+#endif
+
 static union {
 #ifdef FBCON_HAS_CFB16
 	u16 cfb16[16];
@@ -257,7 +325,7 @@
 #ifdef FBCON_HAS_CFB32
 	u32 cfb32[16];
 #endif
-} fbcon_cmap;
+} sis_fbcon_cmap;
 
 /* display status */
 static int sisfb_off = 0;
@@ -265,45 +333,50 @@
 static int sisfb_forcecrt1 = -1;
 static int sisfb_inverse = 0;
 static int sisvga_enabled = 0;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,23)
 static int currcon = 0;
-/*karl*/
+#endif
+
+/* global flags */
 static int sisfb_tvmode = 0;
 static int sisfb_mem = 0;
+static int sisfb_pdc = 0;
+static int enable_dstn = 0;
+static int sisfb_accel = -1;
+static int sisfb_ypan = -1;
 
-static enum _VGA_ENGINE {
-	UNKNOWN_VGA = 0,
-	SIS_300_VGA,
-	SIS_315_VGA,
-} sisvga_engine = UNKNOWN_VGA;
+VGA_ENGINE sisvga_engine = UNKNOWN_VGA;
 
-/* TW: These are to adapted to VGA_ENGINE type */
+/* TW: These are to adapted according to VGA_ENGINE type */
 static int sisfb_hwcursor_size = 0;
 static int sisfb_CRT2_write_enable = 0;
 
-/* mode-related variables */
-int sisfb_mode_idx = MODE_INDEX_NONE;  /* (TW) was -1 */
-u8  sisfb_mode_no = 0;
-u8  sisfb_rate_idx = 0;
-
-int sisfb_crt2type = -1;	/* TW: CRT2 type (for overriding autodetection) */
+int sisfb_crt2type  = -1;	/* TW: CRT2 type (for overriding autodetection) */
+int sisfb_tvplug    = -1;	/* PR: Tv plug type (for overriding autodetection) */
 
-int sisfb_queuemode = -1; 	/* TW: Use MMIO queue mode by default (310 series only) */
+int sisfb_queuemode = -1; 	/* TW: Use MMIO queue mode by default (310/325 series only) */
 
-/* data for sis components*/
+/* data for sis components */
 struct video_info ivideo;
 
-// Eden Chen
+/* TW: For ioctl SISFB_GET_INFO */
+sisfb_info sisfbinfo;
+
+/* TW: Hardware extension; contains data on hardware */
 HW_DEVICE_EXTENSION sishw_ext = {
-	NULL, NULL, NULL, NULL,
+	NULL, NULL, FALSE, NULL, NULL,
 	0, 0, 0, 0, 0, 0, 0, 0, 0,
 	NULL, NULL, NULL, NULL,
-	{0, 0, 0, 0}
+	{0, 0, 0, 0},
+	0
 };
-// ~Eden Chen
+
+/* TW: SiS private structure */
+SiS_Private  SiS_Pr;
 
 /* card parameters */
 static unsigned long sisfb_mmio_size = 0;
-static u8 sisfb_caps = 0;
+static u8            sisfb_caps = 0;
 
 typedef enum _SIS_CMDTYPE {
 	MMIO_CMD = 0,
@@ -317,118 +390,203 @@
 	const char *name;
 } sisdev_list[] = {
 	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300,     "SIS 300"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630"},
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540 VGA"},
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630/730 VGA"},
 	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315H,    "SIS 315H"},
 	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315,     "SIS 315"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315PRO,  "SIS 315Pro"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550_VGA, "SIS 550"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, "SIS 650 VGA"},
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315PRO,  "SIS 315PRO"},
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550_VGA, "SIS 550 VGA"},
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, "SIS 650/M650/651/740 VGA"},
 	{0, 0, NULL}
 };
 
+#define MD_SIS300 1
+#define MD_SIS315 2
+
 /* mode table */
-static const struct _sisbios_mode {
+/* NOT const - will be patched for 1280x960 mode number chaos reasons */
+struct _sisbios_mode {
 	char name[15];
 	u8 mode_no;
+	u16 vesa_mode_no_1;  /* "SiS defined" VESA mode number */
+	u16 vesa_mode_no_2;  /* Real VESA mode numbers */
 	u16 xres;
 	u16 yres;
 	u16 bpp;
 	u16 rate_idx;
 	u16 cols;
 	u16 rows;
+	u8  chipset;
 } sisbios_mode[] = {
-	{"none", 0xFF, 0, 0, 0, 0, 0, 0}, 		    /* TW: for mode "none" */
-	{"320x240x16",   0x56,  320,  240, 16, 1,  40, 15},
-	{"320x480x8",    0x5A,  320,  480,  8, 1,  40, 30},
-	{"320x480x16",   0x5B,  320,  480, 16, 1,  40, 30},
-	{"640x480x8",    0x2E,  640,  480,  8, 1,  80, 30},
-	{"640x480x16",   0x44,  640,  480, 16, 1,  80, 30},
-	{"640x480x24",   0x62,  640,  480, 32, 1,  80, 30}, /* TW: That's for people who mix up color- and fb depth */
-	{"640x480x32",   0x62,  640,  480, 32, 1,  80, 30},
-	{"720x480x8",    0x31,  720,  480,  8, 1,  90, 30},
-	{"720x480x16",   0x33,  720,  480, 16, 1,  90, 30},
-	{"720x480x24",   0x35,  720,  480, 32, 1,  90, 30}, /* TW */
-	{"720x480x32",   0x35,  720,  480, 32, 1,  90, 30},
-	{"720x576x8",    0x32,  720,  576,  8, 1,  90, 36},
-	{"720x576x16",   0x34,  720,  576, 16, 1,  90, 36},
-	{"720x576x24",   0x36,  720,  576, 32, 1,  90, 36}, /* TW */
-	{"720x576x32",   0x36,  720,  576, 32, 1,  90, 36},
-	{"800x600x8",    0x30,  800,  600,  8, 2, 100, 37},
-	{"800x600x16",   0x47,  800,  600, 16, 2, 100, 37},
-	{"800x600x24",   0x63,  800,  600, 32, 2, 100, 37}, /* TW */
-	{"800x600x32",   0x63,  800,  600, 32, 2, 100, 37},
-	{"1024x768x8",   0x38, 1024,  768,  8, 2, 128, 48},
-	{"1024x768x16",  0x4A, 1024,  768, 16, 2, 128, 48},
-	{"1024x768x24",  0x64, 1024,  768, 32, 2, 128, 48}, /* TW */
-	{"1024x768x32",  0x64, 1024,  768, 32, 2, 128, 48},
-	{"1280x960x8",   0x7C, 1280,  960,  8, 1, 160, 60}, /* TW */
-	{"1280x960x16",  0x7D, 1280,  960, 16, 1, 160, 60}, /* TW */
-	{"1280x960x24",  0x7E, 1280,  960, 32, 1, 160, 60}, /* TW */
-	{"1280x960x32",  0x7E, 1280,  960, 32, 1, 160, 60}, /* TW */
-	{"1280x1024x8",  0x3A, 1280, 1024,  8, 2, 160, 64},
-	{"1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64},
-	{"1280x1024x24", 0x65, 1280, 1024, 32, 2, 160, 64}, /* TW */
-	{"1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64},
-	{"1600x1200x8",  0x3C, 1600, 1200,  8, 1, 200, 75},
-	{"1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75},
-	{"1600x1200x24", 0x66, 1600, 1200, 32, 1, 200, 75}, /* TW */
-	{"1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75},
-	{"1920x1440x8",  0x68, 1920, 1440,  8, 1, 240, 75},
-	{"1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75},
-	{"1920x1440x24", 0x6B, 1920, 1440, 32, 1, 240, 75}, /* TW */
-	{"1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75},
-	{"\0", 0x00, 0, 0, 0, 0, 0, 0}
+#define MODE_INDEX_NONE           0  /* TW: index for mode=none */
+	{"none",         0xFF, 0x0000, 0x0000,    0,    0,  0, 0,   0,  0, MD_SIS300|MD_SIS315},  /* TW: for mode "none" */
+	{"320x240x16",   0x56, 0x0000, 0x0000,  320,  240, 16, 1,  40, 15,           MD_SIS315},
+	{"320x480x8",    0x5A, 0x0000, 0x0000,  320,  480,  8, 1,  40, 30,           MD_SIS315},  /* TW: FSTN */
+	{"320x480x16",   0x5B, 0x0000, 0x0000,  320,  480, 16, 1,  40, 30,           MD_SIS315},  /* TW: FSTN */
+	{"640x480x8",    0x2E, 0x0101, 0x0101,  640,  480,  8, 1,  80, 30, MD_SIS300|MD_SIS315},
+	{"640x480x16",   0x44, 0x0111, 0x0111,  640,  480, 16, 1,  80, 30, MD_SIS300|MD_SIS315},
+	{"640x480x24",   0x62, 0x013a, 0x0112,  640,  480, 32, 1,  80, 30, MD_SIS300|MD_SIS315},  /* TW: That's for people who mix up color- and fb depth */
+	{"640x480x32",   0x62, 0x013a, 0x0112,  640,  480, 32, 1,  80, 30, MD_SIS300|MD_SIS315},
+	{"720x480x8",    0x31, 0x0000, 0x0000,  720,  480,  8, 1,  90, 30, MD_SIS300|MD_SIS315},
+	{"720x480x16",   0x33, 0x0000, 0x0000,  720,  480, 16, 1,  90, 30, MD_SIS300|MD_SIS315},
+	{"720x480x24",   0x35, 0x0000, 0x0000,  720,  480, 32, 1,  90, 30, MD_SIS300|MD_SIS315},
+	{"720x480x32",   0x35, 0x0000, 0x0000,  720,  480, 32, 1,  90, 30, MD_SIS300|MD_SIS315},
+	{"720x576x8",    0x32, 0x0000, 0x0000,  720,  576,  8, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"720x576x16",   0x34, 0x0000, 0x0000,  720,  576, 16, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"720x576x24",   0x36, 0x0000, 0x0000,  720,  576, 32, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"720x576x32",   0x36, 0x0000, 0x0000,  720,  576, 32, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"800x480x8",    0x70, 0x0000, 0x0000,  800,  480,  8, 1, 100, 30,           MD_SIS315},  /* TW: 310/325 series only */
+	{"800x480x16",   0x7a, 0x0000, 0x0000,  800,  480, 16, 1, 100, 30,           MD_SIS315},
+	{"800x480x24",   0x76, 0x0000, 0x0000,  800,  480, 32, 1, 100, 30,           MD_SIS315},
+	{"800x480x32",   0x76, 0x0000, 0x0000,  800,  480, 32, 1, 100, 30,           MD_SIS315},
+#define DEFAULT_MODE              20 /* TW: index for 800x600x8 */
+#define DEFAULT_LCDMODE           20 /* TW: index for 800x600x8 */
+#define DEFAULT_TVMODE            20 /* TW: index for 800x600x8 */
+	{"800x600x8",    0x30, 0x0103, 0x0103,  800,  600,  8, 2, 100, 37, MD_SIS300|MD_SIS315},
+	{"800x600x16",   0x47, 0x0114, 0x0114,  800,  600, 16, 2, 100, 37, MD_SIS300|MD_SIS315},
+	{"800x600x24",   0x63, 0x013b, 0x0115,  800,  600, 32, 2, 100, 37, MD_SIS300|MD_SIS315},
+	{"800x600x32",   0x63, 0x013b, 0x0115,  800,  600, 32, 2, 100, 37, MD_SIS300|MD_SIS315},
+	{"1024x576x8",   0x71, 0x0000, 0x0000, 1024,  576,  8, 1, 128, 36,           MD_SIS315},  /* TW: 310/325 series only */
+	{"1024x576x16",  0x74, 0x0000, 0x0000, 1024,  576, 16, 1, 128, 36,           MD_SIS315},
+	{"1024x576x24",  0x77, 0x0000, 0x0000, 1024,  576, 32, 1, 128, 36,           MD_SIS315},
+	{"1024x576x32",  0x77, 0x0000, 0x0000, 1024,  576, 32, 1, 128, 36,           MD_SIS315},
+	{"1024x600x8",   0x20, 0x0000, 0x0000, 1024,  600,  8, 1, 128, 37, MD_SIS300          },  /* TW: 300 series only */
+	{"1024x600x16",  0x21, 0x0000, 0x0000, 1024,  600, 16, 1, 128, 37, MD_SIS300          },
+	{"1024x600x24",  0x22, 0x0000, 0x0000, 1024,  600, 32, 1, 128, 37, MD_SIS300          },
+	{"1024x600x32",  0x22, 0x0000, 0x0000, 1024,  600, 32, 1, 128, 37, MD_SIS300          },
+	{"1024x768x8",   0x38, 0x0105, 0x0105, 1024,  768,  8, 2, 128, 48, MD_SIS300          },
+	{"1024x768x16",  0x4A, 0x0117, 0x0117, 1024,  768, 16, 2, 128, 48, MD_SIS300          },
+	{"1024x768x24",  0x64, 0x013c, 0x0118, 1024,  768, 32, 2, 128, 48, MD_SIS300          },
+	{"1024x768x32",  0x64, 0x013c, 0x0118, 1024,  768, 32, 2, 128, 48, MD_SIS300          },
+	{"1152x768x8",   0x23, 0x0000, 0x0000, 1152,  768,  8, 1, 144, 48, MD_SIS300          },  /* TW: 300 series only */
+	{"1152x768x16",  0x24, 0x0000, 0x0000, 1152,  768, 16, 1, 144, 48, MD_SIS300          },
+	{"1152x768x24",  0x25, 0x0000, 0x0000, 1152,  768, 32, 1, 144, 48, MD_SIS300          },
+	{"1152x768x32",  0x25, 0x0000, 0x0000, 1152,  768, 32, 1, 144, 48, MD_SIS300          },
+	{"1280x720x8",   0x79, 0x0000, 0x0000, 1280,  720,  8, 1, 160, 45,           MD_SIS315},  /* TW: 310/325 series only */
+	{"1280x720x16",  0x75, 0x0000, 0x0000, 1280,  720, 16, 1, 160, 45,           MD_SIS315},
+	{"1280x720x24",  0x78, 0x0000, 0x0000, 1280,  720, 32, 1, 160, 45,           MD_SIS315},
+	{"1280x720x32",  0x78, 0x0000, 0x0000, 1280,  720, 32, 1, 160, 45,           MD_SIS315},
+	{"1280x768x8",   0x23, 0x0000, 0x0000, 1280,  768,  8, 1, 160, 48,           MD_SIS315},  /* TW: 310/325 series only */
+	{"1280x768x16",  0x24, 0x0000, 0x0000, 1280,  768, 16, 1, 160, 48,           MD_SIS315},
+	{"1280x768x24",  0x25, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48,           MD_SIS315},
+	{"1280x768x32",  0x25, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48,           MD_SIS315},
+#define MODEINDEX_1280x960 48
+	{"1280x960x8",   0x7C, 0x0000, 0x0000, 1280,  960,  8, 1, 160, 60, MD_SIS300|MD_SIS315},  /* TW: Modenumbers being patched */
+	{"1280x960x16",  0x7D, 0x0000, 0x0000, 1280,  960, 16, 1, 160, 60, MD_SIS300|MD_SIS315},
+	{"1280x960x24",  0x7E, 0x0000, 0x0000, 1280,  960, 32, 1, 160, 60, MD_SIS300|MD_SIS315},
+	{"1280x960x32",  0x7E, 0x0000, 0x0000, 1280,  960, 32, 1, 160, 60, MD_SIS300|MD_SIS315},
+	{"1280x1024x8",  0x3A, 0x0107, 0x0107, 1280, 1024,  8, 2, 160, 64, MD_SIS300|MD_SIS315},
+	{"1280x1024x16", 0x4D, 0x011a, 0x011a, 1280, 1024, 16, 2, 160, 64, MD_SIS300|MD_SIS315},
+	{"1280x1024x24", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315},
+	{"1280x1024x32", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315},
+	{"1400x1050x8",  0x26, 0x0000, 0x0000, 1400, 1050,  8, 1, 175, 65,           MD_SIS315},  /* TW: 310/325 series only */
+	{"1400x1050x16", 0x27, 0x0000, 0x0000, 1400, 1050, 16, 1, 175, 65,           MD_SIS315},
+	{"1400x1050x24", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,           MD_SIS315},
+	{"1400x1050x32", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,           MD_SIS315},
+	{"1600x1200x8",  0x3C, 0x0130, 0x011c, 1600, 1200,  8, 1, 200, 75, MD_SIS300|MD_SIS315},
+	{"1600x1200x16", 0x3D, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75, MD_SIS300|MD_SIS315},
+	{"1600x1200x24", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315},
+	{"1600x1200x32", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315},
+	{"1920x1440x8",  0x68, 0x013f, 0x0000, 1920, 1440,  8, 1, 240, 75, MD_SIS300|MD_SIS315},
+	{"1920x1440x16", 0x69, 0x0140, 0x0000, 1920, 1440, 16, 1, 240, 75, MD_SIS300|MD_SIS315},
+	{"1920x1440x24", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315},
+	{"1920x1440x32", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315},
+	{"2048x1536x8",  0x6c, 0x0000, 0x0000, 2048, 1536,  8, 1, 256, 96,           MD_SIS315},  /* TW: 310/325 series only */
+	{"2048x1536x16", 0x6d, 0x0000, 0x0000, 2048, 1536, 16, 1, 256, 96,           MD_SIS315},
+	{"2048x1536x24", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,           MD_SIS315},
+	{"2048x1536x32", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,           MD_SIS315},
+	{"\0", 0x00, 0, 0, 0, 0, 0, 0, 0}
 };
 
+/* mode-related variables */
+#ifdef MODULE
+int sisfb_mode_idx = MODE_INDEX_NONE;  /* Don't use a mode by default if we are a module */
+#else
+int sisfb_mode_idx = -1;               /* Use a default mode if we are inside the kernel */
+#endif
+u8  sisfb_mode_no  = 0;
+u8  sisfb_rate_idx = 0;
+
+/* TW: CR36 evaluation */
+const USHORT sis300paneltype[] =
+    { LCD_UNKNOWN,   LCD_800x600,  LCD_1024x768,  LCD_1280x1024,
+      LCD_1280x960,  LCD_640x480,  LCD_1024x600,  LCD_1152x768,
+      LCD_320x480,   LCD_1024x768, LCD_1024x768,  LCD_1024x768,
+      LCD_1024x768,  LCD_1024x768, LCD_1024x768,  LCD_1024x768 };
+
+const USHORT sis310paneltype[] =
+    { LCD_UNKNOWN,   LCD_800x600,  LCD_1024x768,  LCD_1280x1024,
+      LCD_640x480,   LCD_1024x600, LCD_1152x864,  LCD_1280x960,
+      LCD_1152x768,  LCD_1400x1050,LCD_1280x768,  LCD_1600x1200,
+      LCD_320x480,   LCD_1024x768, LCD_1024x768,  LCD_1024x768 };
+
 static const struct _sis_crt2type {
-	char name[6];
+	char name[10];
 	int type_no;
+	int tvplug_no;
 } sis_crt2type[] = {
-	{"NONE", 0},
-	{"LCD",  DISPTYPE_LCD},
-	{"TV",   DISPTYPE_TV},
-	{"VGA",  DISPTYPE_CRT2},
-	{"none", 0},	/* TW: make it fool-proof */
-	{"lcd",  DISPTYPE_LCD},
-	{"tv",   DISPTYPE_TV},
-	{"vga",  DISPTYPE_CRT2},
-	{"\0",  -1}
+	{"NONE", 	0, 		-1},
+	{"LCD",  	DISPTYPE_LCD, 	-1},
+	{"TV",   	DISPTYPE_TV, 	-1},
+	{"VGA",  	DISPTYPE_CRT2, 	-1},
+	{"SVIDEO", 	DISPTYPE_TV, 	TVPLUG_SVIDEO},
+	{"COMPOSITE", 	DISPTYPE_TV, 	TVPLUG_COMPOSITE},
+	{"SCART", 	DISPTYPE_TV, 	TVPLUG_SCART},
+	{"none", 	0, 		-1},
+	{"lcd",  	DISPTYPE_LCD, 	-1},
+	{"tv",   	DISPTYPE_TV, 	-1},
+	{"vga",  	DISPTYPE_CRT2, 	-1},
+	{"svideo", 	DISPTYPE_TV, 	TVPLUG_SVIDEO},
+	{"composite", 	DISPTYPE_TV, 	TVPLUG_COMPOSITE},
+	{"scart", 	DISPTYPE_TV, 	TVPLUG_SCART},
+	{"\0",  	-1, 		-1}
 };
 
+/* Queue mode selection for 310 series */
 static const struct _sis_queuemode {
 	char name[6];
 	int type_no;
 } sis_queuemode[] = {
-	{"AGP",  AGP_CMD_QUEUE},
-	{"VRAM", VM_CMD_QUEUE},
-	{"MMIO", MMIO_CMD},
-	{"agp",  AGP_CMD_QUEUE},
-	{"vram", VM_CMD_QUEUE},
-	{"mmio", MMIO_CMD},
-	{"\0",  -1}
+	{"AGP",  	AGP_CMD_QUEUE},
+	{"VRAM", 	VM_CMD_QUEUE},
+	{"MMIO", 	MMIO_CMD},
+	{"agp",  	AGP_CMD_QUEUE},
+	{"vram", 	VM_CMD_QUEUE},
+	{"mmio", 	MMIO_CMD},
+	{"\0",   	-1}
 };
 
-static struct _sis_vrate {
+static const struct _sis_vrate {
 	u16 idx;
 	u16 xres;
 	u16 yres;
 	u16 refresh;
 } sisfb_vrate[] = {
-	{1,  640,  480,  60}, {2,  640, 480,  72}, {3,  640, 480,  75}, {4,  640, 480,  85},
-	{5,  640,  480, 100}, {6,  640, 480, 120}, {7,  640, 480, 160}, {8,  640, 480, 200},
-	{1,  720,  480,  60},
-	{1,  720,  576,  50},
-	{1,  800,  600,  56}, {2,  800, 600,  60}, {3,  800, 600,  72}, {4,  800, 600,  75},
-	{5,  800,  600,  85}, {6,  800, 600, 100}, {7,  800, 600, 120}, {8,  800, 600, 160},
-	{1, 1024,  768,  43}, {2, 1024, 768,  60}, {3, 1024, 768,  70}, {4, 1024, 768,  75},
-	{5, 1024,  768,  85}, {6, 1024, 768, 100}, {7, 1024, 768, 120},
-	{1, 1280, 1024,  43}, {2, 1280, 1024, 60}, {3, 1280, 1024, 75}, {4, 1280, 1024, 85},
-	/* TW: Values for 1280x960 guessed */
-	{1, 1280,  960,  43},  /* {1, 1280,  960, 60}, */
-	{1, 1600, 1200,  60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75},
-	{5, 1600, 1200,  85},
-	{1, 1920, 1440,  60},
+	{1,  640,  480, 60}, {2,  640,  480,  72}, {3, 640,   480,  75}, {4,  640, 480,  85},
+	{5,  640,  480,100}, {6,  640,  480, 120}, {7, 640,   480, 160}, {8,  640, 480, 200},
+	{1,  720,  480, 60},
+	{1,  720,  576, 58},
+	{1,  800,  480, 60}, {2,  800,  480,  75}, {3, 800,   480,  85},
+	{1,  800,  600, 56}, {2,  800,  600,  60}, {3, 800,   600,  72}, {4,  800, 600,  75},
+	{5,  800,  600, 85}, {6,  800,  600, 100}, {7, 800,   600, 120}, {8,  800, 600, 160},
+	{1, 1024,  768, 43}, {2, 1024,  768,  60}, {3, 1024,  768,  70}, {4, 1024, 768,  75},
+	{5, 1024,  768, 85}, {6, 1024,  768, 100}, {7, 1024,  768, 120},
+	{1, 1024,  576, 60}, {2, 1024,  576,  65}, {3, 1024,  576,  75},
+	{1, 1024,  600, 60},
+	{1, 1152,  768, 60},
+	{1, 1280,  720, 60}, {2, 1280,  720,  75}, {3, 1280,  720,  85},
+	{1, 1280,  768, 60},
+	{1, 1280, 1024, 43}, {2, 1280, 1024,  60}, {3, 1280, 1024,  75}, {4, 1280, 1024,  85},
+	{1, 1280,  960, 60},
+	{1, 1400, 1050, 60},
+	{1, 1600, 1200, 60}, {2, 1600, 1200,  65}, {3, 1600, 1200,  70}, {4, 1600, 1200,  75},
+	{5, 1600, 1200, 85}, {6, 1600, 1200, 100}, {7, 1600, 1200, 120},
+	/* TW: Clock values for 1920x1440 guessed (except for the first one) */
+	{1, 1920, 1440, 60}, {2, 1920, 1440,  70}, {3, 1920, 1440,  75}, {4, 1920, 1440,  85},
+	{5, 1920, 1440,100}, {6, 1920, 1440, 120},
+	/* TW: Clock values for 2048x1536 guessed */
+	{1, 2048, 1536, 60}, {2, 2048, 1536,  70}, {3, 2048, 1536,  75}, {4, 2048, 1536,  85},
+	{5, 2048, 1536,100},
 	{0, 0, 0, 0}
 };
 
@@ -466,10 +624,10 @@
 static unsigned long sisfb_heap_start;
 static unsigned long sisfb_heap_end;
 static unsigned long sisfb_heap_size;
-static SIS_HEAP sisfb_heap;
+static SIS_HEAP      sisfb_heap;
 
 // Eden Chen
-static struct _sis_TV_filter {
+static const struct _sis_TV_filter {
 	u8 filter[9][4];
 } sis_TV_filter[] = {
 	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_0 */
@@ -618,115 +776,134 @@
 	   {0xFF,0xFF,0xFF,0xFF} }}
 };
 
-static int filter = -1;
+static int           filter = -1;
 static unsigned char filter_tb;
 //~Eden Chen
 
-/* ---------------------- Routine Prototype ------------------------- */
+/* ---------------------- Routine prototypes ------------------------- */
 
 /* Interface used by the world */
-int sisfb_setup(char *options);
-static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info);
-static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info);
-static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info);
-static int sisfb_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg, int con,
-		       struct fb_info *info);
+#ifndef MODULE
+int             sisfb_setup(char *options);
+#endif
+
+static int      sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			struct fb_info *info);
+static int      sisfb_get_var(struct fb_var_screeninfo *var, int con,
+			struct fb_info *info);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+static int      sisfb_set_par(struct fb_info *info);
+#endif
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+static int      sisfb_set_var(struct fb_var_screeninfo *var, int con,
+			struct fb_info *info);
+static int      sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			struct fb_info *info);
+static int      sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			struct fb_info *info);
+#endif
+static int      sisfb_ioctl(struct inode *inode, struct file *file,
+		       	unsigned int cmd, unsigned long arg, int con,
+		       	struct fb_info *info);
 
 /* Interface to the low level console driver */
-int sisfb_init(void);
-static int sisfb_update_var(int con, struct fb_info *info);
-static int sisfb_switch(int con, struct fb_info *info);
-static void sisfb_blank(int blank, struct fb_info *info);
+int             sisfb_init(void);
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+static int      sisfb_update_var(int con, struct fb_info *info);
+static int      sisfb_switch(int con, struct fb_info *info);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+static int      sisfb_blank(int blank, struct fb_info *info);
+#else
+static void     sisfb_blank(int blank, struct fb_info *info);
+#endif
 
 /* hardware access routines */
-void sisfb_set_reg1(u16 port, u16 index, u16 data);
-void sisfb_set_reg3(u16 port, u16 data);
-void sisfb_set_reg4(u16 port, unsigned long data);
-u8   sisfb_get_reg1(u16 port, u16 index);
-u8   sisfb_get_reg2(u16 port);
-u32  sisfb_get_reg3(u16 port);
-// Eden Chen
-//void sisfb_clear_DAC(u16 port);
-//void sisfb_clear_buffer(PHW_DEVICE_EXTENSION psishw_ext);
-// ~Eden Chen
+void            sisfb_set_reg4(u16 port, unsigned long data);
+u32             sisfb_get_reg3(u16 port);
+
+/* 2D accelerator functions */
+extern int      sisfb_initaccel(void);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+extern void     fbcon_sis_fillrect(struct fb_info *info, struct fb_fillrect *rect);
+extern void     fbcon_sis_copyarea(struct fb_info *info, struct fb_copyarea *area);
+extern void     cfb_imageblit(struct fb_info *info, struct fb_image *image);
+#endif
 
 /* Internal routines */
-static void sisfb_search_mode(const char *name);
-static void sisfb_validate_mode(void);
-static u8   sisfb_search_refresh_rate(unsigned int rate);
-static int  sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,
-			 unsigned *blue, unsigned *transp,
-			 struct fb_info *fb_info);
-static int  sis_setcolreg(unsigned regno, unsigned red, unsigned green,
-			 unsigned blue, unsigned transp,
-			 struct fb_info *fb_info);
-static int  sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
-		      struct fb_info *info);
-static void sisfb_set_disp(int con, struct fb_var_screeninfo *var);
-static void sisfb_do_install_cmap(int con, struct fb_info *info);
+static void     sisfb_search_mode(const char *name);
+static int      sisfb_validate_mode(int modeindex);
+static u8       sisfb_search_refresh_rate(unsigned int rate);
+static int      sisfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			unsigned blue, unsigned transp,
+			struct fb_info *fb_info);
+static int      sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
+		      	struct fb_info *info);
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+static void     sisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info);
+static int      sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			unsigned *blue, unsigned *transp,
+			struct fb_info *fb_info);
+static void     sisfb_do_install_cmap(int con, struct fb_info *info);
+#endif
+static void     sisfb_pre_setmode(void);
+static void     sisfb_post_setmode(void);
+static void     sisfb_crtc_to_var(struct fb_var_screeninfo *var);
 
-/* Chip-dependent Routines */
+/* Chipset-dependent Routines */
 #ifdef CONFIG_FB_SIS_300
-static int sisfb_get_dram_size_300(void);
-//extern BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension);
-static void sisfb_detect_VB_connect_300(void);
-static void sisfb_get_VB_type_300(void);
-static int sisfb_has_VB_300(void);
-//extern BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT ModeNo);
+static int      sisfb_get_dram_size_300(void);
+static void     sisfb_detect_VB_connect_300(void);
+static void     sisfb_get_VB_type_300(void);
+static int      sisfb_has_VB_300(void);
 #endif
 #ifdef CONFIG_FB_SIS_315
-static int sisfb_get_dram_size_315(void);
-//extern BOOLEAN SiSInit310(PHW_DEVICE_EXTENSION HwDeviceExtension);
-static void sisfb_detect_VB_connect_315(void);
-static void sisfb_get_VB_type_315(void);
-static int sisfb_has_VB_315(void);
-//extern BOOLEAN SiSSetMode310(PHW_DEVICE_EXTENSION HwDeviceExtension, USHORT ModeNo);
+static int      sisfb_get_dram_size_315(void);
+static void     sisfb_detect_VB_connect_315(void);
+static void     sisfb_get_VB_type_315(void);
+static int      sisfb_has_VB_315(void);
 #endif
 
-/* SetMode routines */
-
-// Eden Chen
-extern BOOLEAN SiSSetMode(PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo);
-extern BOOLEAN SiSInit(PSIS_HW_DEVICE_INFO HwDeviceExtension);
-extern void SetEnableDstn(void);
-// ~Eden Chen
-
-extern void 	SiSRegInit(USHORT BaseAddr);
-extern USHORT 	SiS_GetCH7005(USHORT tempbx);
-extern void 	SiS_SetCH7005(USHORT tempbx);
-extern void     SiS_SetCHTVRegANDOR(USHORT tempax,USHORT tempbh);
-
-static void sisfb_pre_setmode(void);
-static void sisfb_post_setmode(void);
-static void sisfb_crtc_to_var(struct fb_var_screeninfo *var);
+/* TW: Sensing routines */
+void            SiS_Sense30x(void);
+int             SISDoSense(int tempbl, int tempbh, int tempcl, int tempch);
+void            SiS_SenseCh(void);
+
+/* Routines from init.c/init301.c */
+extern void 	SiSRegInit(SiS_Private *SiS_Pr, USHORT BaseAddr);
+extern BOOLEAN  SiSInit(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+extern BOOLEAN  SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo);
+extern void     SetEnableDstn(SiS_Private *SiS_Pr);
+extern void     SiS_LongWait(SiS_Private *SiS_Pr);
+
+/* TW: Chrontel TV functions */
+extern USHORT 	SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempbx);
+extern void 	SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempbx);
+extern USHORT 	SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempbx);
+extern void 	SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempbx);
+extern void     SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh);
+extern void     SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime);
 
 /* Export functions  */
-static void sis_get_glyph(SIS_GLYINFO *gly);
-void sis_dispinfo(struct ap_data *rec);
-void sis_malloc(struct sis_memreq *req);
-void sis_free(unsigned long base);
+static void     sis_get_glyph(struct fb_info *info, SIS_GLYINFO *gly);
+void            sis_dispinfo(struct ap_data *rec);
+void            sis_malloc(struct sis_memreq *req);
+void            sis_free(unsigned long base);
 
 /* heap routines */
-static int sisfb_heap_init(void);
-static SIS_OH *sisfb_poh_new_node(void);
-static SIS_OH *sisfb_poh_allocate(unsigned long size);
-static void sisfb_delete_node(SIS_OH *poh);
-static void sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh);
-static SIS_OH *sisfb_poh_free(unsigned long base);
-static void sisfb_free_node(SIS_OH *poh);
+static int      sisfb_heap_init(void);
+static SIS_OH   *sisfb_poh_new_node(void);
+static SIS_OH   *sisfb_poh_allocate(unsigned long size);
+static void     sisfb_delete_node(SIS_OH *poh);
+static void     sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh);
+static SIS_OH   *sisfb_poh_free(unsigned long base);
+static void     sisfb_free_node(SIS_OH *poh);
 
 /* routines to access PCI configuration space */
-BOOLEAN sisfb_query_VGA_config_space(PSIS_HW_DEVICE_INFO psishw_ext, 
-	unsigned long offset, unsigned long set, unsigned long *value);
-BOOLEAN sisfb_query_north_bridge_space(PSIS_HW_DEVICE_INFO psishw_ext, 
-	unsigned long offset, unsigned long set, unsigned long *value);
+BOOLEAN         sisfb_query_VGA_config_space(PSIS_HW_DEVICE_INFO psishw_ext,
+	          	unsigned long offset, unsigned long set, unsigned long *value);
+BOOLEAN         sisfb_query_north_bridge_space(PSIS_HW_DEVICE_INFO psishw_ext,
+	         	unsigned long offset, unsigned long set, unsigned long *value);
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/vgatypes.h linux-2.4.20/drivers/video/sis/vgatypes.h
--- linux-2.4.19/drivers/video/sis/vgatypes.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/vgatypes.h	2002-10-29 11:18:30.000000000 +0000
@@ -1,12 +1,18 @@
 #ifndef _VGATYPES_
 #define _VGATYPES_
 
+#ifdef LINUX_XF86
+#include "xf86Pci.h"
+#endif
+
+#ifdef LINUX_KERNEL  /* TW: We don't want the X driver to depend on kernel source */
+#include <linux/ioctl.h>
+#endif
 
 #ifndef TC
 #define far
 #endif
 
-
 #ifndef FALSE
 #define FALSE   0
 #endif
@@ -19,7 +25,7 @@
 #define NULL    0
 #endif
 
-#ifndef CHAR 
+#ifndef CHAR
 typedef char CHAR;
 #endif
 
@@ -43,7 +49,6 @@
 typedef unsigned long ULONG;
 #endif
 
-
 #ifndef PUCHAR
 typedef UCHAR far *PUCHAR;
 #endif
@@ -77,7 +82,7 @@
 #define VBIOS_VER_MAX_LENGTH         4
 #endif
 
-#ifndef LINUX_KERNEL
+#ifndef LINUX_KERNEL   /* For kernel, this is defined in sisfb.h */
 #ifndef WIN2000
 #ifndef SIS_CHIP_TYPE
 typedef enum _SIS_CHIP_TYPE {
@@ -109,13 +114,13 @@
 typedef enum _SIS_VB_CHIP_TYPE {
     VB_CHIP_Legacy = 0,
     VB_CHIP_301,
-    VB_CHIP_301B,
-    VB_CHIP_301BLCD,
-    VB_CHIP_301BTV,
+    VB_CHIP_301B,      
+    VB_CHIP_301LV,
+    VB_CHIP_301LVX,
     VB_CHIP_302,
     VB_CHIP_302B,
-    VB_CHIP_302BLCD,
-    VB_CHIP_302BTV, 
+    VB_CHIP_302LV,
+    VB_CHIP_302LVX,
     VB_CHIP_303,
     VB_CHIP_UNKNOWN, /* other video bridge or no video bridge */
     MAX_VB_CHIP
@@ -135,13 +140,18 @@
     LCD_1600x1200,
     LCD_1920x1440,
     LCD_2048x1536,
-    LCD_320x480,    /* TW: FSTN */
+    LCD_320x480,       /* TW: FSTN */
+    LCD_1400x1050,
+    LCD_1152x864,
+    LCD_1152x768,
+    LCD_1280x768,
+    LCD_1024x600,
     LCD_UNKNOWN
 } SIS_LCD_TYPE;
 #endif
 #endif
 
-#ifndef WIN2000 /* mark by Paul ,Move definition to sisv.h*/
+#ifndef WIN2000 /* mark by Paul, Move definition to sisv.h*/
 #ifndef PSIS_DSReg
 typedef struct _SIS_DSReg
 {
@@ -158,15 +168,15 @@
 
 
 struct _SIS_HW_DEVICE_INFO
-{   
+{
     PVOID  pDevice;              /* The pointer to the physical device data structure
                                     in each OS or NULL for unused. */
-    UCHAR  *pjVirtualRomBase;    /* Only for NT, NULL for WinCE & Linux. */
-                                 /* base virtual address of VBIOS ROM Space */
+    UCHAR  *pjVirtualRomBase;    /* base virtual address of VBIOS ROM Space */
                                  /* or base virtual address of ROM image file. */
                                  /* if NULL, then read from pjROMImage; */
                                  /* Note:ROM image file is the file of VBIOS ROM */
 
+    BOOLEAN UseROM;		 /* TW: Use the ROM image if provided */
  
     UCHAR  *pjCustomizedROMImage;/* base virtual address of ROM image file. */
                                  /* wincE:ROM image file is the file for OEM */
@@ -201,6 +211,7 @@
                                  /*             011:Trumpion LVDS Scaling Chip */
                                  /*             100:LVDS(LCD-out)+Chrontel 7005 */
                                  /*             101:Single Chrontel 7005 */
+				 /* TW: This has changed on 310/325 series! */
 
     ULONG  ulCRT2LCDType;        /* defined in the data structure type */
                                  /* "SIS_LCD_TYPE" */
@@ -217,7 +228,7 @@
                                  /* end data :(idx, val) =  (FF, FF) */
                                  /* Note : restore cR registers if  */
                                  /* bSkipDramSizing = TRUE */
-    
+
     PSIS_QUERYSPACE  pQueryVGAConfigSpace; /* Get/Set VGA Configuration  */
                                            /* space */
  
@@ -226,9 +237,48 @@
 
     UCHAR  szVBIOSVer[VBIOS_VER_MAX_LENGTH];
 
+    UCHAR  pdc;			/* TW: PanelDelayCompensation */
+
+#ifdef LINUX_XF86
+    PCITAG PciTag;		/* PCI Tag for Linux XF86 */
+#endif
+};
+#endif
+#endif 
+
+
+/* TW: Addtional IOCTL for communication sisfb <> X driver        */
+/*     If changing this, sisfb.h must also be changed (for sisfb) */
+
+#ifdef LINUX_XF86  /* We don't want the X driver to depend on the kernel source */
+
+/* TW: ioctl for identifying and giving some info (esp. memory heap start) */
+#define SISFB_GET_INFO    0x80046ef8  /* Wow, what a terrible hack... */
+
+/* TW: Structure argument for SISFB_GET_INFO ioctl  */
+typedef struct _SISFB_INFO sisfb_info, *psisfb_info;
+
+struct _SISFB_INFO {
+	unsigned long sisfb_id;         /* for identifying sisfb */
+#ifndef SISFB_ID
+#define SISFB_ID	  0x53495346    /* Identify myself with 'SISF' */
+#endif
+ 	int    chip_id;			/* PCI ID of detected chip */
+	int    memory;			/* video memory in KB which sisfb manages */
+	int    heapstart;               /* heap start (= sisfb "mem" argument) in KB */
+	unsigned char fbvidmode;	/* current sisfb mode */
+
+	unsigned char sisfb_version;
+	unsigned char sisfb_revision;
+	unsigned char sisfb_patchlevel;
+
+	unsigned char sisfb_caps;	/* sisfb's capabilities */
+
+	int    sisfb_tqlen;		/* turbo queue length (in KB) */
+
+	char reserved[249]; 		/* for future use */
 };
 #endif
-#endif/*~ mark by Paul ,Move definition to sisv.h*/
 
 #ifndef WIN2000
 #ifndef WINCE_HEADER
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sis/vstruct.h linux-2.4.20/drivers/video/sis/vstruct.h
--- linux-2.4.19/drivers/video/sis/vstruct.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sis/vstruct.h	2002-10-29 11:18:33.000000000 +0000
@@ -4,344 +4,516 @@
 #define EXTERN extern
 #endif /* _INIT_ */
 
+#ifndef _VSTRUCT_
+#define _VSTRUCT_
+
 typedef struct _SiS_PanelDelayTblStruct
 {
- UCHAR timer[2];
+ 	UCHAR timer[2];
 } SiS_PanelDelayTblStruct;
 
 typedef struct _SiS_LCDDataStruct
 {
- USHORT RVBHCMAX;
- USHORT RVBHCFACT;
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT LCDHT;
- USHORT LCDVT;
+	USHORT RVBHCMAX;
+	USHORT RVBHCFACT;
+	USHORT VGAHT;
+	USHORT VGAVT;
+	USHORT LCDHT;
+	USHORT LCDVT;
 } SiS_LCDDataStruct;
 
 typedef struct _SiS_TVDataStruct
 {
- USHORT RVBHCMAX;
- USHORT RVBHCFACT;
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT TVHDE;
- USHORT TVVDE;
- USHORT RVBHRS;
- UCHAR FlickerMode;
- USHORT HALFRVBHRS;
- UCHAR RY1COE;
- UCHAR RY2COE;
- UCHAR RY3COE;
- UCHAR RY4COE;
+	USHORT RVBHCMAX;
+	USHORT RVBHCFACT;
+	USHORT VGAHT;
+	USHORT VGAVT;
+	USHORT TVHDE;
+	USHORT TVVDE;
+	USHORT RVBHRS;
+	UCHAR  FlickerMode;
+	USHORT HALFRVBHRS;
+	UCHAR  RY1COE;
+	UCHAR  RY2COE;
+	UCHAR  RY3COE;
+	UCHAR  RY4COE;
 } SiS_TVDataStruct;
 
 typedef struct _SiS_LVDSDataStruct
 {
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT LCDHT;
- USHORT LCDVT;
+	USHORT VGAHT;
+	USHORT VGAVT;
+	USHORT LCDHT;
+	USHORT LCDVT;
 } SiS_LVDSDataStruct;
 
 typedef struct _SiS_LVDSDesStruct
 {
- USHORT LCDHDES;
- USHORT LCDVDES;
+	USHORT LCDHDES;
+	USHORT LCDVDES;
 } SiS_LVDSDesStruct;
 
 typedef struct _SiS_LVDSCRT1DataStruct
 {
- UCHAR CR[15];
+	UCHAR  CR[15];
 } SiS_LVDSCRT1DataStruct;
 
 /*add for LCDA*/
 typedef struct _SiS_LCDACRT1DataStruct
 {
- UCHAR CR[17];
+	UCHAR  CR[17];
 } SiS_LCDACRT1DataStruct;
 
 typedef struct _SiS_CHTVRegDataStruct
 {
- UCHAR Reg[5];
+	UCHAR  Reg[16];
 } SiS_CHTVRegDataStruct;
 
 typedef struct _SiS_StStruct
 {
- UCHAR St_ModeID;
- USHORT St_ModeFlag;
- UCHAR St_StTableIndex;
- UCHAR St_CRT2CRTC;
- UCHAR St_ResInfo;
- UCHAR VB_StTVFlickerIndex;
- UCHAR VB_StTVEdgeIndex;
- UCHAR VB_StTVYFilterIndex;
+	UCHAR  St_ModeID;
+	USHORT St_ModeFlag;
+	UCHAR  St_StTableIndex;
+	UCHAR  St_CRT2CRTC;
+	UCHAR  St_ResInfo;
+	UCHAR  VB_StTVFlickerIndex;
+	UCHAR  VB_StTVEdgeIndex;
+	UCHAR  VB_StTVYFilterIndex;
 } SiS_StStruct;
 
 typedef struct _SiS_VBModeStruct
 {
-UCHAR  ModeID;
-UCHAR  VB_TVDelayIndex;
-UCHAR  VB_TVFlickerIndex;
-UCHAR  VB_TVPhaseIndex;
-UCHAR  VB_TVYFilterIndex;
-UCHAR  VB_LCDDelayIndex;
-UCHAR  _VB_LCDHIndex;
-UCHAR  _VB_LCDVIndex;
+	UCHAR  ModeID;
+	UCHAR  VB_TVDelayIndex;
+	UCHAR  VB_TVFlickerIndex;
+	UCHAR  VB_TVPhaseIndex;
+	UCHAR  VB_TVYFilterIndex;
+	UCHAR  VB_LCDDelayIndex;
+	UCHAR  _VB_LCDHIndex;
+	UCHAR  _VB_LCDVIndex;
 } SiS_VBModeStruct;
 
 typedef struct _SiS_StandTableStruct
 {
- UCHAR CRT_COLS;
- UCHAR ROWS;
- UCHAR CHAR_HEIGHT;
- USHORT CRT_LEN;
- UCHAR SR[4];
- UCHAR MISC;
- UCHAR CRTC[0x19];
- UCHAR ATTR[0x14];
- UCHAR GRC[9];
+	UCHAR  CRT_COLS;
+	UCHAR  ROWS;
+	UCHAR  CHAR_HEIGHT;
+	USHORT CRT_LEN;
+	UCHAR  SR[4];
+	UCHAR  MISC;
+	UCHAR  CRTC[0x19];
+	UCHAR  ATTR[0x14];
+	UCHAR  GRC[9];
 } SiS_StandTableStruct;
 
 typedef struct _SiS_ExtStruct
 {
- UCHAR Ext_ModeID;
- USHORT Ext_ModeFlag;
- USHORT Ext_ModeInfo;
- USHORT Ext_Point;
- USHORT Ext_VESAID;
- UCHAR Ext_VESAMEMSize;
- UCHAR Ext_RESINFO;
- UCHAR VB_ExtTVFlickerIndex;
- UCHAR VB_ExtTVEdgeIndex;
- UCHAR VB_ExtTVYFilterIndex;
- UCHAR REFindex;
+	UCHAR  Ext_ModeID;
+	USHORT Ext_ModeFlag;
+	USHORT Ext_ModeInfo;
+	USHORT Ext_Point;
+	USHORT Ext_VESAID;
+	UCHAR  Ext_VESAMEMSize;
+	UCHAR  Ext_RESINFO;
+	UCHAR  VB_ExtTVFlickerIndex;
+	UCHAR  VB_ExtTVEdgeIndex;
+	UCHAR  VB_ExtTVYFilterIndex;
+	UCHAR  REFindex;
 } SiS_ExtStruct;
 
 typedef struct _SiS_Ext2Struct
 {
- USHORT Ext_InfoFlag;
- UCHAR Ext_CRT1CRTC;
- UCHAR Ext_CRTVCLK;
- UCHAR Ext_CRT2CRTC;
- UCHAR  ModeID;
- USHORT XRes;
- USHORT YRes;
- USHORT ROM_OFFSET;
+	USHORT Ext_InfoFlag;
+	UCHAR  Ext_CRT1CRTC;
+	UCHAR  Ext_CRTVCLK;
+	UCHAR  Ext_CRT2CRTC;
+	UCHAR  ModeID;
+	USHORT XRes;
+	USHORT YRes;
+	USHORT ROM_OFFSET;
 } SiS_Ext2Struct;
 
+typedef struct _SiS_Part2PortTblStruct
+{
+ 	UCHAR  CR[12];
+} SiS_Part2PortTblStruct;
+
 typedef struct _SiS_CRT1TableStruct
 {
- UCHAR CR[17];
+	UCHAR  CR[17];
 } SiS_CRT1TableStruct;
 
 typedef struct _SiS_MCLKDataStruct
 {
- UCHAR SR28,SR29,SR2A;
- USHORT CLOCK;
+	UCHAR  SR28,SR29,SR2A;
+	USHORT CLOCK;
 } SiS_MCLKDataStruct;
 
 typedef struct _SiS_ECLKDataStruct
 {
- UCHAR SR2E,SR2F,SR30;
- USHORT CLOCK;
+	UCHAR  SR2E,SR2F,SR30;
+	USHORT CLOCK;
 } SiS_ECLKDataStruct;
 
 typedef struct _SiS_VCLKDataStruct
 {
- UCHAR SR2B,SR2C;
- USHORT CLOCK;
+	UCHAR  SR2B,SR2C;
+	USHORT CLOCK;
 } SiS_VCLKDataStruct;
 
 typedef struct _SiS_VBVCLKDataStruct
 {
- UCHAR Part4_A,Part4_B;
- USHORT CLOCK;
+	UCHAR  Part4_A,Part4_B;
+	USHORT CLOCK;
 } SiS_VBVCLKDataStruct;
 
 typedef struct _SiS_StResInfoStruct
 {
- USHORT HTotal;
- USHORT VTotal;
+	USHORT HTotal;
+	USHORT VTotal;
 } SiS_StResInfoStruct;
 
 typedef struct _SiS_ModeResInfoStruct
 {
- USHORT HTotal;
- USHORT VTotal;
- UCHAR  XChar;
- UCHAR  YChar;
+	USHORT HTotal;
+	USHORT VTotal;
+	UCHAR  XChar;
+	UCHAR  YChar;
 } SiS_ModeResInfoStruct;
 
-EXTERN SiS_StStruct *SiS_SModeIDTable;
-EXTERN SiS_StandTableStruct *SiS_StandTable;
-EXTERN SiS_ExtStruct  *SiS_EModeIDTable;
-EXTERN SiS_Ext2Struct  *SiS_RefIndex;
-EXTERN SiS_VBModeStruct *SiS_VBModeIDTable;
-EXTERN SiS_CRT1TableStruct  *SiS_CRT1Table;
-EXTERN SiS_MCLKDataStruct  *SiS_MCLKData;
-EXTERN SiS_ECLKDataStruct  *SiS_ECLKData;
-EXTERN SiS_VCLKDataStruct  *SiS_VCLKData;
-EXTERN SiS_VBVCLKDataStruct  *SiS_VBVCLKData;
-EXTERN SiS_StResInfoStruct  *SiS_StResInfo;
-EXTERN SiS_ModeResInfoStruct  *SiS_ModeResInfo;
-EXTERN UCHAR *SiS_ScreenOffset;
-
-EXTERN UCHAR *pSiS_OutputSelect;
-EXTERN UCHAR *pSiS_SoftSetting;
-EXTERN UCHAR *pSiS_SR07;
-
 typedef UCHAR DRAM4Type[4];
-EXTERN DRAM4Type *SiS_SR15; /* pointer : point to array */
-EXTERN DRAM4Type *SiS_CR40; /* pointer : point to array */
-EXTERN UCHAR *SiS_CR49;
-EXTERN UCHAR *SiS_SR25;
-
-EXTERN UCHAR *pSiS_SR1F;
-EXTERN UCHAR *pSiS_SR21;
-EXTERN UCHAR *pSiS_SR22;
-EXTERN UCHAR *pSiS_SR23;
-EXTERN UCHAR *pSiS_SR24;
-EXTERN UCHAR *pSiS_SR31;
-EXTERN UCHAR *pSiS_SR32;
-EXTERN UCHAR *pSiS_SR33;
-EXTERN UCHAR *pSiS_CRT2Data_1_2;
-EXTERN UCHAR *pSiS_CRT2Data_4_D;
-EXTERN UCHAR *pSiS_CRT2Data_4_E;
-EXTERN UCHAR *pSiS_CRT2Data_4_10;
-EXTERN USHORT *pSiS_RGBSenseData;
-EXTERN USHORT *pSiS_VideoSenseData;
-EXTERN USHORT *pSiS_YCSenseData;
-EXTERN USHORT *pSiS_RGBSenseData2; /*301b*/
-EXTERN USHORT *pSiS_VideoSenseData2;
-EXTERN USHORT *pSiS_YCSenseData2;
-
-EXTERN UCHAR *SiS_NTSCPhase;
-EXTERN UCHAR *SiS_PALPhase;
-EXTERN UCHAR *SiS_NTSCPhase2;
-EXTERN UCHAR *SiS_PALPhase2;
-EXTERN UCHAR *SiS_PALMPhase;
-EXTERN UCHAR *SiS_PALNPhase;
-EXTERN SiS_LCDDataStruct  *SiS_StLCD1024x768Data;
-EXTERN SiS_LCDDataStruct  *SiS_ExtLCD1024x768Data;
-EXTERN SiS_LCDDataStruct  *SiS_St2LCD1024x768Data;
-EXTERN SiS_LCDDataStruct  *SiS_StLCD1280x1024Data;
-EXTERN SiS_LCDDataStruct  *SiS_ExtLCD1280x1024Data;
-EXTERN SiS_LCDDataStruct  *SiS_St2LCD1280x1024Data;
-EXTERN SiS_LCDDataStruct  *SiS_NoScaleData;
-EXTERN SiS_LCDDataStruct  *SiS_LCD1280x960Data;
-EXTERN SiS_TVDataStruct   *SiS_StPALData;
-EXTERN SiS_TVDataStruct   *SiS_ExtPALData;
-EXTERN SiS_TVDataStruct   *SiS_StNTSCData;
-EXTERN SiS_TVDataStruct   *SiS_ExtNTSCData;
-EXTERN SiS_TVDataStruct   *SiS_St1HiTVData;
-EXTERN SiS_TVDataStruct   *SiS_St2HiTVData;
-EXTERN SiS_TVDataStruct   *SiS_ExtHiTVData;
-EXTERN UCHAR *SiS_NTSCTiming;
-EXTERN UCHAR *SiS_PALTiming;
-EXTERN UCHAR *SiS_HiTVExtTiming;
-EXTERN UCHAR *SiS_HiTVSt1Timing;
-EXTERN UCHAR *SiS_HiTVSt2Timing;
-EXTERN UCHAR *SiS_HiTVTextTiming;
-EXTERN UCHAR *SiS_HiTVGroup3Data;
-EXTERN UCHAR *SiS_HiTVGroup3Simu;
-EXTERN UCHAR *SiS_HiTVGroup3Text;
-
-EXTERN SiS_PanelDelayTblStruct *SiS_PanelDelayTbl;
-EXTERN SiS_LVDSDataStruct  *SiS_LVDS800x600Data_1;
-EXTERN SiS_LVDSDataStruct  *SiS_LVDS800x600Data_2;
-EXTERN SiS_LVDSDataStruct  *SiS_LVDS1024x768Data_1;
-EXTERN SiS_LVDSDataStruct  *SiS_LVDS1024x768Data_2;
-EXTERN SiS_LVDSDataStruct  *SiS_LVDS1280x1024Data_1;
-EXTERN SiS_LVDSDataStruct  *SiS_LVDS1280x1024Data_2;
-EXTERN SiS_LVDSDataStruct  *SiS_LVDS640x480Data_1;
-EXTERN SiS_LVDSDataStruct  *SiS_LVDS320x480Data_1;  /*fstn*/
-EXTERN SiS_LVDSDataStruct  *SiS_CHTVUNTSCData;
-EXTERN SiS_LVDSDataStruct  *SiS_CHTVONTSCData;
-EXTERN SiS_LVDSDataStruct  *SiS_CHTVUPALData;
-EXTERN SiS_LVDSDataStruct  *SiS_CHTVOPALData;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType00_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType01_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType02_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType03_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType04_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType05_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType06_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType07_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType08_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType09_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0a_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0b_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0c_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0d_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0e_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0f_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType00_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType01_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType02_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType03_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType04_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType05_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType06_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType07_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType08_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType09_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0a_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0b_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0c_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0d_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0e_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0f_2;
-/*301b*/
-EXTERN SiS_LVDSDesStruct  *LVDS1024x768Des_1;
-EXTERN SiS_LVDSDesStruct  *LVDS1280x1024Des_1;
-EXTERN SiS_LVDSDesStruct  *LVDS1280x960Des_1;
-EXTERN SiS_LVDSDesStruct  *LVDS1024x768Des_2;
-EXTERN SiS_LVDSDesStruct  *LVDS1280x1024Des_2;
-EXTERN SiS_LVDSDesStruct  *LVDS1280x960Des_2;
-/*end 301b*/
-EXTERN SiS_LVDSDesStruct  *SiS_CHTVUNTSCDesData;
-EXTERN SiS_LVDSDesStruct  *SiS_CHTVONTSCDesData;
-EXTERN SiS_LVDSDesStruct  *SiS_CHTVUPALDesData;
-EXTERN SiS_LVDSDesStruct  *SiS_CHTVOPALDesData;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_1;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_1;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_1;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_1_H;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_1_H;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_1_H;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_2;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_2;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_2;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_2_H;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_2_H;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_2_H;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1UNTSC;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1ONTSC;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1UPAL;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1OPAL;
-/*fstn*/
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1320x480_1;
-/*add for  LCDA*/
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT1800x600_1;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_1;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_1;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT1800x600_1_H;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_1_H;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_1_H;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT1800x600_2;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_2;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_2;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT1800x600_2_H;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_2_H;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_2_H;
-/*end 301b*/
-
-EXTERN SiS_CHTVRegDataStruct *SiS_CHTVReg_UNTSC;
-EXTERN SiS_CHTVRegDataStruct *SiS_CHTVReg_ONTSC;
-EXTERN SiS_CHTVRegDataStruct *SiS_CHTVReg_UPAL;
-EXTERN SiS_CHTVRegDataStruct *SiS_CHTVReg_OPAL;
-EXTERN UCHAR *SiS_CHTVVCLKUNTSC;
-EXTERN UCHAR *SiS_CHTVVCLKONTSC;
-EXTERN UCHAR *SiS_CHTVVCLKUPAL;
-EXTERN UCHAR *SiS_CHTVVCLKOPAL;
+
+typedef struct _SiS_Private
+{
+#ifdef LINUX_KERNEL
+        USHORT RelIO;
+#endif
+	USHORT SiS_P3c4;
+	USHORT SiS_P3d4;
+	USHORT SiS_P3c0;
+	USHORT SiS_P3ce;
+	USHORT SiS_P3c2;
+	USHORT SiS_P3ca;
+	USHORT SiS_P3c6;
+	USHORT SiS_P3c7;
+	USHORT SiS_P3c8;
+	USHORT SiS_P3c9;
+	USHORT SiS_P3da;
+	USHORT SiS_Part1Port;
+	USHORT SiS_Part2Port;
+	USHORT SiS_Part3Port;
+	USHORT SiS_Part4Port;
+	USHORT SiS_Part5Port;
+	USHORT SiS_IF_DEF_LVDS;
+	USHORT SiS_IF_DEF_TRUMPION;
+	USHORT SiS_IF_DEF_DSTN;
+	USHORT SiS_IF_DEF_FSTN;
+	USHORT SiS_IF_DEF_CH70xx;
+	USHORT SiS_IF_DEF_HiVision;
+	UCHAR  SiS_VGAINFO;
+	BOOLEAN SiS_UseROM;
+	int    SiS_CHOverScan;
+	USHORT SiS_Backup70xx;
+	USHORT SiS_CRT1Mode;
+	USHORT SiS_flag_clearbuffer;
+	int    SiS_RAMType;
+	UCHAR  SiS_ChannelAB;
+	UCHAR  SiS_DataBusWidth;
+	USHORT SiS_ModeType;
+	USHORT SiS_VBInfo;
+	USHORT SiS_LCDResInfo;
+	USHORT SiS_LCDTypeInfo;
+	USHORT SiS_LCDInfo;
+	USHORT SiS_VBType;
+	USHORT SiS_VBExtInfo;
+	USHORT SiS_HiVision;
+	USHORT SiS_SelectCRT2Rate;
+	USHORT SiS_SetFlag;
+	USHORT SiS_RVBHCFACT;
+	USHORT SiS_RVBHCMAX;
+	USHORT SiS_RVBHRS;
+	USHORT SiS_VGAVT;
+	USHORT SiS_VGAHT;
+	USHORT SiS_VT;
+	USHORT SiS_HT;
+	USHORT SiS_VGAVDE;
+	USHORT SiS_VGAHDE;
+	USHORT SiS_VDE;
+	USHORT SiS_HDE;
+	USHORT SiS_NewFlickerMode;
+	USHORT SiS_RY1COE;
+	USHORT SiS_RY2COE;
+	USHORT SiS_RY3COE;
+	USHORT SiS_RY4COE;
+	USHORT SiS_LCDHDES;
+	USHORT SiS_LCDVDES;
+	USHORT SiS_DDC_Port;
+	USHORT SiS_DDC_Index;
+	USHORT SiS_DDC_Data;
+	USHORT SiS_DDC_Clk;
+	USHORT SiS_DDC_DataShift;
+	USHORT SiS_DDC_DeviceAddr;
+	USHORT SiS_DDC_ReadAddr;
+	USHORT SiS_DDC_SecAddr;
+	USHORT SiS_Panel800x600;
+	USHORT SiS_Panel1024x768;
+	USHORT SiS_Panel1280x1024;
+	USHORT SiS_Panel1600x1200;
+	USHORT SiS_Panel1280x960;
+	USHORT SiS_Panel1400x1050;
+	USHORT SiS_Panel320x480;
+	USHORT SiS_Panel1152x768;
+	USHORT SiS_Panel1280x768;
+	USHORT SiS_Panel1024x600;
+	USHORT SiS_Panel640x480;
+	USHORT SiS_Panel1152x864;
+	USHORT SiS_PanelMax;
+	USHORT SiS_PanelMinLVDS;
+	USHORT SiS_PanelMin301;
+	USHORT SiS_ChrontelInit;
+	
+	/* Pointers: */
+	const SiS_StStruct          *SiS_SModeIDTable;
+	const SiS_StandTableStruct  *SiS_StandTable;
+	const SiS_ExtStruct         *SiS_EModeIDTable;
+	const SiS_Ext2Struct        *SiS_RefIndex;
+	const SiS_VBModeStruct      *SiS_VBModeIDTable;
+	const SiS_CRT1TableStruct   *SiS_CRT1Table;
+	const SiS_MCLKDataStruct    *SiS_MCLKData_0;
+	const SiS_MCLKDataStruct    *SiS_MCLKData_1;
+	const SiS_ECLKDataStruct    *SiS_ECLKData;
+	const SiS_VCLKDataStruct    *SiS_VCLKData;
+	const SiS_VBVCLKDataStruct  *SiS_VBVCLKData;
+	const SiS_StResInfoStruct   *SiS_StResInfo;
+	const SiS_ModeResInfoStruct *SiS_ModeResInfo;
+	const UCHAR                 *SiS_ScreenOffset;
+
+	const UCHAR                 *pSiS_OutputSelect;
+	const UCHAR                 *pSiS_SoftSetting;
+
+	const DRAM4Type *SiS_SR15; /* pointer : point to array */
+#ifndef LINUX_XF86
+	UCHAR *pSiS_SR07;
+	const DRAM4Type *SiS_CR40; /* pointer : point to array */
+	UCHAR *SiS_CR49;
+	UCHAR *SiS_SR25;
+	UCHAR *pSiS_SR1F;
+	UCHAR *pSiS_SR21;
+	UCHAR *pSiS_SR22;
+	UCHAR *pSiS_SR23;
+	UCHAR *pSiS_SR24;
+	UCHAR *pSiS_SR31;
+	UCHAR *pSiS_SR32;
+	UCHAR *pSiS_SR33;
+	UCHAR *pSiS_CRT2Data_1_2;
+	UCHAR *pSiS_CRT2Data_4_D;
+	UCHAR *pSiS_CRT2Data_4_E;
+	UCHAR *pSiS_CRT2Data_4_10;
+	const USHORT *pSiS_RGBSenseData;
+	const USHORT *pSiS_VideoSenseData;
+	const USHORT *pSiS_YCSenseData;
+	const USHORT *pSiS_RGBSenseData2; /*301b*/
+	const USHORT *pSiS_VideoSenseData2;
+	const USHORT *pSiS_YCSenseData2;
+#endif
+	const UCHAR *SiS_NTSCPhase;
+	const UCHAR *SiS_PALPhase;
+	const UCHAR *SiS_NTSCPhase2;
+	const UCHAR *SiS_PALPhase2;
+	const UCHAR *SiS_PALMPhase;
+	const UCHAR *SiS_PALNPhase;
+	const UCHAR *SiS_PALMPhase2;
+	const UCHAR *SiS_PALNPhase2;
+	const UCHAR *SiS_SpecialPhase;
+	const SiS_LCDDataStruct  *SiS_StLCD1024x768Data;
+	const SiS_LCDDataStruct  *SiS_ExtLCD1024x768Data;
+	const SiS_LCDDataStruct  *SiS_St2LCD1024x768Data;
+	const SiS_LCDDataStruct  *SiS_StLCD1280x1024Data;
+	const SiS_LCDDataStruct  *SiS_ExtLCD1280x1024Data;
+	const SiS_LCDDataStruct  *SiS_St2LCD1280x1024Data;
+	const SiS_LCDDataStruct  *SiS_NoScaleData1024x768;
+	const SiS_LCDDataStruct  *SiS_NoScaleData1280x1024;
+	const SiS_LCDDataStruct  *SiS_LCD1280x960Data;
+	const SiS_LCDDataStruct  *SiS_NoScaleData1400x1050;
+	const SiS_LCDDataStruct  *SiS_NoScaleData1600x1200;
+	const SiS_LCDDataStruct  *SiS_StLCD1400x1050Data;
+	const SiS_LCDDataStruct  *SiS_StLCD1600x1200Data;
+	const SiS_LCDDataStruct  *SiS_ExtLCD1400x1050Data;
+	const SiS_LCDDataStruct  *SiS_ExtLCD1600x1200Data;
+	const SiS_TVDataStruct   *SiS_StPALData;
+	const SiS_TVDataStruct   *SiS_ExtPALData;
+	const SiS_TVDataStruct   *SiS_StNTSCData;
+	const SiS_TVDataStruct   *SiS_ExtNTSCData;
+#ifdef oldHV
+	const SiS_TVDataStruct   *SiS_St1HiTVData;
+	const SiS_TVDataStruct   *SiS_St2HiTVData;
+	const SiS_TVDataStruct   *SiS_ExtHiTVData;
+#endif
+	const UCHAR *SiS_NTSCTiming;
+	const UCHAR *SiS_PALTiming;
+#ifdef oldHV
+	const UCHAR *SiS_HiTVExtTiming;
+	const UCHAR *SiS_HiTVSt1Timing;
+	const UCHAR *SiS_HiTVSt2Timing;
+	const UCHAR *SiS_HiTVTextTiming;
+	const UCHAR *SiS_HiTVGroup3Data;
+	const UCHAR *SiS_HiTVGroup3Simu;
+	const UCHAR *SiS_HiTVGroup3Text;
+#endif
+	const SiS_PanelDelayTblStruct *SiS_PanelDelayTbl;
+	const SiS_PanelDelayTblStruct *SiS_PanelDelayTblLVDS;
+	const SiS_LVDSDataStruct  *SiS_LVDS800x600Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS800x600Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1024x768Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1024x768Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1280x1024Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1280x1024Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1280x960Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1280x960Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1400x1050Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1400x1050Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1024x600Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1024x600Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1152x768Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1152x768Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS640x480Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS320x480Data_1;
+	const SiS_LVDSDataStruct  *SiS_LCDA1400x1050Data_1;
+	const SiS_LVDSDataStruct  *SiS_LCDA1400x1050Data_2;
+	const SiS_LVDSDataStruct  *SiS_LCDA1600x1200Data_1;
+	const SiS_LVDSDataStruct  *SiS_LCDA1600x1200Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDSXXXxXXXData_1;
+	const SiS_LVDSDataStruct  *SiS_CHTVUNTSCData;
+	const SiS_LVDSDataStruct  *SiS_CHTVONTSCData;
+	const SiS_LVDSDataStruct  *SiS_CHTVUPALData;
+	const SiS_LVDSDataStruct  *SiS_CHTVOPALData;
+	const SiS_LVDSDesStruct  *SiS_PanelType00_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType01_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType02_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType03_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType04_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType05_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType06_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType07_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType08_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType09_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0a_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0b_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0c_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0d_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0e_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0f_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType00_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType01_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType02_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType03_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType04_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType05_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType06_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType07_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType08_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType09_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0a_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0b_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0c_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0d_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0e_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0f_2;
+
+	const SiS_LVDSDesStruct  *LVDS1024x768Des_1;
+	const SiS_LVDSDesStruct  *LVDS1280x1024Des_1;
+	const SiS_LVDSDesStruct  *LVDS1400x1050Des_1;
+	const SiS_LVDSDesStruct  *LVDS1600x1200Des_1;
+	const SiS_LVDSDesStruct  *LVDS1024x768Des_2;
+	const SiS_LVDSDesStruct  *LVDS1280x1024Des_2;
+	const SiS_LVDSDesStruct  *LVDS1400x1050Des_2;
+	const SiS_LVDSDesStruct  *LVDS1600x1200Des_2;
+
+	const SiS_LVDSDesStruct  *SiS_CHTVUNTSCDesData;
+	const SiS_LVDSDesStruct  *SiS_CHTVONTSCDesData;
+	const SiS_LVDSDesStruct  *SiS_CHTVUPALDesData;
+	const SiS_LVDSDesStruct  *SiS_CHTVOPALDesData;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11400x1050_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x600_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11152x768_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11600x1200_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11400x1050_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x600_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11152x768_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11600x1200_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11400x1050_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x600_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11152x768_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11600x1200_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11400x1050_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x600_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11152x768_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11600x1200_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1XXXxXXX_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1XXXxXXX_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1UNTSC;
+	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1ONTSC;
+	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1UPAL;
+	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1OPAL;
+
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1320x480_1;
+
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT1800x600_1;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_1;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_1;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11400x1050_1;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11600x1200_1;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT1800x600_1_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_1_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_1_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11400x1050_1_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11600x1200_1_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT1800x600_2;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_2;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_2;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11400x1050_2;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11600x1200_2;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT1800x600_2_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_2_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_2_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11400x1050_2_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11600x1200_2_H;
+
+	/* TW: New for 650/301LV */
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_1;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_1;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1400x1050_1;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1600x1200_1;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_2;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_2;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1400x1050_2;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1600x1200_2;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_3;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_3;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1400x1050_3;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1600x1200_3;
+
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_UNTSC;
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_ONTSC;
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_UPAL;
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_OPAL;
+	const UCHAR *SiS_CHTVVCLKUNTSC;
+	const UCHAR *SiS_CHTVVCLKONTSC;
+	const UCHAR *SiS_CHTVVCLKUPAL;
+	const UCHAR *SiS_CHTVVCLKOPAL;
+} SiS_Private;
+
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sstfb.c linux-2.4.20/drivers/video/sstfb.c
--- linux-2.4.19/drivers/video/sstfb.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sstfb.c	2002-10-29 11:18:48.000000000 +0000
@@ -11,6 +11,8 @@
  * 04/2001 Paul Mundt      <lethal@chaoticdreams.org>
  * 05/2001 Urs Ganse       <ursg@uni.de>
  *     (initial work on voodoo2 port, interlace)
+ * 09/2002 Helge Deller    <deller@gmx.de>
+ *     (enable driver on big-endian machines (hppa), ioctl fixes)
  *
  *
  * $Id: sstfb.c,v 1.26.4.1 2001/08/29 01:30:37 ghoz Exp $
@@ -30,8 +32,6 @@
 -ASK: I can choose different ordering for the color bitfields (rgba argb ...)
       wich one should i use ? is there any preferred one ? It seems ARGB is
       the one ...
--ASK: later: how to cope with endianness ? the fbi chip has builtin functions
-      to do byte swizling /swapping, maybe use that ...
 -TODO: check the error paths . if something get wrong, the error doesn't seem
       to be very well handled...if handled at all.. not good.
 -TODO: in  set_var check the validity of timings (hsync vsync)...
@@ -107,6 +107,7 @@
 
 #include <asm/io.h>
 #include <asm/ioctl.h>
+#include <asm/uaccess.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb16.h>
@@ -774,11 +775,17 @@
 {
 #define sst_info	((struct sstfb_info *) info)
 
-	struct fb_var_screeninfo *var;
+  	struct fb_var_screeninfo *var;
+ 	struct fb_var_screeninfo var2;
 
 	f_dprintk("sstfb_get_fix(con: %d)\n",con);
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	
 	if (con == -1)
-		sstfb_encode_var(var, &sst_info->current_par, sst_info);
+	{
+		sstfb_encode_var(&var2, &sst_info->current_par, sst_info);
+		var = &var2;
+	}
 	else
 		var = &fb_display[con].var;
 
@@ -789,6 +796,7 @@
 
 	fix->type        = FB_TYPE_PACKED_PIXELS;
 	fix->visual      = FB_VISUAL_TRUECOLOR;
+	fix->accel       = FB_ACCEL_NONE;
 	/*
 	 *   According to the specs, the linelength must be of 1024 *pixels*.
 	 * and the 24bpp mode is in fact a 32 bpp mode.
@@ -969,7 +977,7 @@
 #if (SST_DEBUG_IOCTL >0)
 	int i;
 	u_long p;
-	u32 tmp;
+	u32 tmp, val;
 	u32 fbiinit0;
 	struct pci_dev * sst_dev = sst_info->dev;
 #endif
@@ -988,20 +996,24 @@
 #  endif /* (SST_DEBUG_VAR >0) */
 /* fills the lfb up to *(u32*)arg */
 	case _IOW('F', 0xdc, u32):	/* 0x46dc */
-		if (*(u32*)arg > 0x400000 )
-			*(u32*) arg = 0x400000;
-		f_dprintk("filling %#x \n", *(u32*)arg);
-		for (p = 0 ; p < *(u32*)arg; p+=2)
+		if (copy_from_user(&val, (void *) arg, sizeof(val)))
+			return -EFAULT;
+		if (val > 0x400000 )
+			val = 0x400000;
+		f_dprintk("filling %#x \n", val);
+		for (p = 0 ; p < val; p+=2)
 			writew( p >> 6 , sst_info->video.vbase + p);
 		return 0;
 /* change VGA pass_through */
 	case _IOW('F', 0xdd, u32):	/* 0x46dd */
+		if (copy_from_user(&val, (void *) arg, sizeof(val)))
+			return -EFAULT;
 		f_dprintk("switch VGA pass-through\n");
 		pci_read_config_dword(sst_dev, PCI_INIT_ENABLE, &tmp);
 		pci_write_config_dword(sst_dev, PCI_INIT_ENABLE,
 				       tmp | PCI_EN_INIT_WR );
 		fbiinit0 = sst_read (FBIINIT0);
-		if (* (u32*)arg) {
+		if (val) {
 			sst_write(FBIINIT0, fbiinit0 & ~EN_VGA_PASSTHROUGH);
 			iprintk ( "Disabling VGA pass-through\n");
 		} else {
@@ -1494,7 +1506,7 @@
 	pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_FIFO_WR);
 
 	/* set lfbmode : set mode + front buffer for reads/writes
-	   + disable pipeline + disable byte swapping */
+	   + disable pipeline */
 	switch(par->bpp) {
 	case 16:
 		lfbmode = LFB_565;
@@ -1514,6 +1526,12 @@
 		break;
 	}
 
+#if defined(__BIG_ENDIAN)
+	/* enable byte-swizzle functionality in hardware */
+	lfbmode |= ( LFB_WORD_SWIZZLE_WR | LFB_BYTE_SWIZZLE_WR |
+		     LFB_WORD_SWIZZLE_RD | LFB_BYTE_SWIZZLE_RD );
+#endif
+	
 	if (clipping) {
 		sst_write(LFBMODE, lfbmode | EN_PXL_PIPELINE);
 	/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sstfb.h linux-2.4.20/drivers/video/sstfb.h
--- linux-2.4.19/drivers/video/sstfb.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/sstfb.h	2002-10-29 11:18:33.000000000 +0000
@@ -114,7 +114,11 @@
 #  define RD_BUFF_FRONT		  0		/* read buff select (front) */
 #  define RD_BUFF_BACK		  (1 << 6)	/* back */
 #  define EN_PXL_PIPELINE	  BIT(8)	/* pixel pipeline (clip..)*/
+#  define LFB_WORD_SWIZZLE_WR	  BIT(11)	/* enable write-wordswap (big-endian) */
+#  define LFB_BYTE_SWIZZLE_WR	  BIT(12)	/* enable write-byteswap (big-endian) */
 #  define LFB_INVERT_Y		  BIT(13)	/* invert Y origin (LFB) */
+#  define LFB_WORD_SWIZZLE_RD	  BIT(15)	/* enable read-wordswap (big-endian) */
+#  define LFB_BYTE_SWIZZLE_RD	  BIT(16)	/* enable read-byteswap (big-endian) */
 #define CLIP_LEFT_RIGHT		0x0118
 #define CLIP_LOWY_HIGHY		0x011c
 #define NOPCMD			0x0120
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sti/Makefile linux-2.4.20/drivers/video/sti/Makefile
--- linux-2.4.19/drivers/video/sti/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/video/sti/Makefile	2002-10-29 11:18:47.000000000 +0000
@@ -0,0 +1,20 @@
+# Makefile for the Linux video drivers.
+# 28 Jan 2001, Helge Deller, <mailto:hdeller@redhat.com>
+# Rewritten to use lists instead of if-statements.
+
+O_TARGET := sti.o
+
+# All of the (potential) objects that export symbols.
+# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
+
+export-objs := sticore.o sticon.o stifb.o
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_FB_STI)		+= sticore.o stifb.o
+obj-$(CONFIG_STI_CONSOLE)	+= sticore.o sticon.o
+
+include $(TOPDIR)/Rules.make
+
+clean:
+	rm -f core *.o *.a *.s
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sti/sticon.c linux-2.4.20/drivers/video/sti/sticon.c
--- linux-2.4.19/drivers/video/sti/sticon.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/video/sti/sticon.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,404 @@
+/*
+ *  linux/drivers/video/sti/sticon.c - console driver using HP's STI firmware
+ *
+ *	Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *	Copyright (C) 2001 Helge Deller <deller@gmx.de>
+ *
+ *  Based on linux/drivers/video/vgacon.c and linux/drivers/video/fbcon.c,
+ *  which were
+ *
+ *	Created 28 Sep 1997 by Geert Uytterhoeven
+ *	Rewritten by Martin Mares <mj@ucw.cz>, July 1998
+ *	Copyright (C) 1991, 1992  Linus Torvalds
+ *			    1995  Jay Estabrook
+ *	Copyright (C) 1995 Geert Uytterhoeven
+ *	Copyright (C) 1993 Bjoern Brauel
+ *			   Roman Hodek
+ *	Copyright (C) 1993 Hamish Macdonald
+ *			   Greg Harp
+ *	Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
+ *
+ *	      with work by William Rucklidge (wjr@cs.cornell.edu)
+ *			   Geert Uytterhoeven
+ *			   Jes Sorensen (jds@kom.auc.dk)
+ *			   Martin Apel
+ *	      with work by Guenther Kelleter
+ *			   Martin Schaller
+ *			   Andreas Schwab
+ *			   Emmanuel Marty (core@ggi-project.org)
+ *			   Jakub Jelinek (jj@ultra.linux.cz)
+ *			   Martin Mares <mj@ucw.cz>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/console_struct.h>
+#include <linux/errno.h>
+#include <linux/vt_kern.h>
+#include <linux/kd.h>
+#include <linux/selection.h>
+
+#include <asm/io.h>
+
+#include "sticore.h"
+
+/* switching to graphics mode */
+#define BLANK 0
+static int vga_is_gfx;
+
+
+/* Software scrollback */
+
+static unsigned long softback_buf, softback_curr;
+static unsigned long softback_in;
+static unsigned long /* softback_top, */ softback_end;
+static int softback_lines;
+
+
+/* software cursor */
+
+static int cursor_drawn;
+#define CURSOR_DRAW_DELAY		(1)
+#define DEFAULT_CURSOR_BLINK_RATE	(20)
+
+static int vbl_cursor_cnt;
+
+static inline void cursor_undrawn(void)
+{
+    vbl_cursor_cnt = 0;
+    cursor_drawn = 0;
+}
+
+
+static const char *__init sticon_startup(void)
+{
+    return "STI console";
+}
+
+static int sticon_set_palette(struct vc_data *c, unsigned char *table)
+{
+    return -EINVAL;
+}
+
+static int sticon_font_op(struct vc_data *c, struct console_font_op *op)
+{
+    return -ENOSYS;
+}
+
+static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos)
+{
+    int unit = conp->vc_num;
+    int redraw_cursor = 0;
+
+    if (vga_is_gfx || console_blanked)
+	    return;
+	    
+    if (vt_cons[unit]->vc_mode != KD_TEXT)
+    	    return;
+#if 0
+    if ((p->cursor_x == xpos) && (p->cursor_y == ypos)) {
+	    cursor_undrawn();
+	    redraw_cursor = 1;
+    }
+#endif
+
+    sti_putc(default_sti, c, ypos, xpos);
+
+    if (redraw_cursor)
+	    vbl_cursor_cnt = CURSOR_DRAW_DELAY;
+}
+
+static void sticon_putcs(struct vc_data *conp, const unsigned short *s,
+			 int count, int ypos, int xpos)
+{
+    int unit = conp->vc_num;
+    int redraw_cursor = 0;
+
+    if (vga_is_gfx || console_blanked)
+	    return;
+
+    if (vt_cons[unit]->vc_mode != KD_TEXT)
+    	    return;
+    
+#if 0
+    if ((p->cursor_y == ypos) && (xpos <= p->cursor_x) &&
+	(p->cursor_x < (xpos + count))) {
+	    cursor_undrawn();
+	    redraw_cursor = 1;
+    }
+#endif
+
+    while (count--) {
+	sti_putc(default_sti, scr_readw(s++), ypos, xpos++);
+    }
+
+    if (redraw_cursor)
+	    vbl_cursor_cnt = CURSOR_DRAW_DELAY;
+}
+
+static void sticon_cursor(struct vc_data *conp, int mode)
+{
+    unsigned short car1;
+
+    car1 = conp->vc_screenbuf[conp->vc_x + conp->vc_y * conp->vc_cols];
+    switch (mode) {
+    case CM_ERASE:
+	sti_putc(default_sti, car1, conp->vc_y, conp->vc_x);
+	break;
+    case CM_MOVE:
+    case CM_DRAW:
+	switch (conp->vc_cursor_type & 0x0f) {
+	case CUR_UNDERLINE:
+	case CUR_LOWER_THIRD:
+	case CUR_LOWER_HALF:
+	case CUR_TWO_THIRDS:
+	case CUR_BLOCK:
+	    sti_putc(default_sti, (car1 & 255) + (0 << 8) + (7 << 11),
+		     conp->vc_y, conp->vc_x);
+	    break;
+	}
+	break;
+    }
+}
+
+static int
+sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
+{
+    struct sti_struct *sti = default_sti;
+
+    if (vga_is_gfx)
+        return 0;
+
+    sticon_cursor(conp, CM_ERASE);
+
+    switch (dir) {
+    case SM_UP:
+	sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols);
+	sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char);
+	break;
+
+    case SM_DOWN:
+	sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols);
+	sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char);
+	break;
+    }
+
+    return 0;
+}
+
+static void
+sticon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
+	     int height, int width)
+{
+    if (!width || !height)
+	    return;
+#if 0
+    if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
+	(sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
+	((dy <= p->cursor_y) && (p->cursor_y < dy+height) &&
+	(dx <= p->cursor_x) && (p->cursor_x < dx+width)))
+		sticon_cursor(p, CM_ERASE /*|CM_SOFTBACK*/);
+#endif
+
+    sti_bmove(default_sti, sy, sx, dy, dx, height, width);
+}
+
+static void sticon_init(struct vc_data *c, int init)
+{
+    struct sti_struct *sti = default_sti;
+    int vc_cols, vc_rows;
+
+    sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0);
+    vc_cols = sti_onscreen_x(sti) / sti->font_width;
+    vc_rows = sti_onscreen_y(sti) / sti->font_height;
+    c->vc_can_do_color = 1;
+    
+    if (init) {
+	c->vc_cols = vc_cols;
+	c->vc_rows = vc_rows;
+    } else {
+	/* vc_rows = (c->vc_rows > vc_rows) ? vc_rows : c->vc_rows; */
+	/* vc_cols = (c->vc_cols > vc_cols) ? vc_cols : c->vc_cols; */
+	vc_resize_con(vc_rows, vc_cols, c->vc_num);
+    }
+}
+
+static void sticon_deinit(struct vc_data *c)
+{
+}
+
+static void sticon_clear(struct vc_data *conp, int sy, int sx, int height,
+			 int width)
+{
+    if (!height || !width)
+	return;
+
+    sti_clear(default_sti, sy, sx, height, width, conp->vc_video_erase_char);
+}
+
+static int sticon_switch(struct vc_data *conp)
+{
+    return 1;	/* needs refreshing */
+}
+
+static int sticon_set_origin(struct vc_data *conp)
+{
+    return 0;
+}
+
+static int sticon_blank(struct vc_data *c, int blank)
+{
+    switch (blank) {
+    case 0:		/* unblank */
+	vga_is_gfx = 0;
+	/* Tell console.c that it has to restore the screen itself */
+	return 1;
+    case 1:		/* normal blanking */
+    default:		/* VESA blanking */
+	if (vga_is_gfx)
+		return 0;
+	sticon_set_origin(c);
+	sti_clear(default_sti, 0,0, c->vc_rows, c->vc_cols, BLANK);
+	return 1;
+    case -1:		/* Entering graphic mode */
+	sti_clear(default_sti, 0,0, c->vc_rows, c->vc_cols, BLANK);
+	vga_is_gfx = 1;
+	return 1;
+    }
+    return 1;		/* console needs to restore screen itself */
+}
+
+static int sticon_scrolldelta(struct vc_data *conp, int lines)
+{
+    return 0;
+}
+
+static u16 *sticon_screen_pos(struct vc_data *conp, int offset)
+{
+    int line;
+    unsigned long p;
+
+    if (conp->vc_num != fg_console || !softback_lines)
+    	return (u16 *)(conp->vc_origin + offset);
+    line = offset / conp->vc_size_row;
+    if (line >= softback_lines)
+    	return (u16 *)(conp->vc_origin + offset - softback_lines * conp->vc_size_row);
+    p = softback_curr + offset;
+    if (p >= softback_end)
+    	p += softback_buf - softback_end;
+    return (u16 *)p;
+}
+
+static unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos,
+				  int *px, int *py)
+{
+    int x, y;
+    unsigned long ret;
+    if (pos >= conp->vc_origin && pos < conp->vc_scr_end) {
+    	unsigned long offset = (pos - conp->vc_origin) / 2;
+    	
+    	x = offset % conp->vc_cols;
+    	y = offset / conp->vc_cols;
+    	if (conp->vc_num == fg_console)
+    	    y += softback_lines;
+    	ret = pos + (conp->vc_cols - x) * 2;
+    } else if (conp->vc_num == fg_console && softback_lines) {
+    	unsigned long offset = pos - softback_curr;
+    	
+    	if (pos < softback_curr)
+    	    offset += softback_end - softback_buf;
+    	offset /= 2;
+    	x = offset % conp->vc_cols;
+    	y = offset / conp->vc_cols;
+	ret = pos + (conp->vc_cols - x) * 2;
+	if (ret == softback_end)
+	    ret = softback_buf;
+	if (ret == softback_in)
+	    ret = conp->vc_origin;
+    } else {
+    	/* Should not happen */
+    	x = y = 0;
+    	ret = conp->vc_origin;
+    }
+    if (px) *px = x;
+    if (py) *py = y;
+    return ret;
+}
+
+static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens,
+			    u8 blink, u8 underline, u8 reverse)
+{
+    u8 attr = ((color & 0x70) >> 1) | ((color & 7));
+
+    if (reverse) {
+	color = ((color >> 3) & 0x7) | ((color & 0x7) << 3);
+    }
+
+    return attr;
+}
+
+void sticon_invert_region(struct vc_data *conp, u16 *p, int count)
+{
+    int col = 1; /* vga_can_do_color; */
+
+    while (count--) {
+	u16 a = scr_readw(p);
+
+	if (col)
+		a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
+	else
+		a = ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
+
+	scr_writew(a, p++);
+    }
+}
+
+void sticon_save_screen(struct vc_data *conp)
+{
+}
+
+struct consw sti_con = {
+    con_startup:	sticon_startup,
+    con_init:		sticon_init,
+    con_deinit:		sticon_deinit,
+    con_clear:		sticon_clear,
+    con_putc:		sticon_putc,
+    con_putcs:		sticon_putcs,
+    con_cursor:		sticon_cursor,
+    con_scroll:		sticon_scroll,
+    con_bmove:		sticon_bmove,
+    con_switch:		sticon_switch,
+    con_blank:		sticon_blank,
+    con_font_op:	sticon_font_op,
+    con_set_palette:	sticon_set_palette,
+    con_scrolldelta:	sticon_scrolldelta,
+    con_set_origin:	sticon_set_origin,
+    con_save_screen:	sticon_save_screen, 
+    con_build_attr:	sticon_build_attr,
+    con_invert_region:	sticon_invert_region, 
+    con_screen_pos:	sticon_screen_pos,
+    con_getxy:		sticon_getxy,
+};
+
+
+
+int __init sticonsole_init(void)
+{
+    if (sti_init_roms()) {
+	if (conswitchp == &dummy_con) {
+        	printk(KERN_INFO "sticon: Initializing STI text console.\n");
+		take_over_console(&sti_con, 0, MAX_NR_CONSOLES - 1, 1);
+	}
+	return 0;
+    } else
+	return -ENODEV;
+}
+
+module_init(sticonsole_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sti/sticore.c linux-2.4.20/drivers/video/sti/sticore.c
--- linux-2.4.19/drivers/video/sti/sticore.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/video/sti/sticore.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,1051 @@
+/*
+ *  linux/drivers/video/sti/sticore.c -
+ *	core code for console driver using HP's STI firmware
+ *
+ *	Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *	Portions Copyright (C) 2001-2002 Helge Deller <deller@gmx.de>
+ *	Portions Copyright (C) 2001-2002 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+ * 
+ * TODO:
+ * - call STI in virtual mode rather than in real mode
+ * - screen blanking with state_mgmt() in text mode STI ? 
+ * - try to make it work on m68k hp workstations ;)
+ * - clean up the cache flushing functions
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <video/font.h>
+
+#include <asm/pgalloc.h>
+#include <asm/hardware.h>
+
+#include "sticore.h"
+
+#define STI_DRIVERVERSION "0.9"
+
+struct sti_struct *default_sti;
+
+static int num_sti_roms;			  /* # of STI ROMS found */
+static struct sti_struct *sti_roms[MAX_STI_ROMS]; /* ptr to each sti_struct */
+
+
+/* The colour indices used by STI are
+ *   0 - Black
+ *   1 - White
+ *   2 - Red
+ *   3 - Yellow/Brown
+ *   4 - Green
+ *   5 - Cyan
+ *   6 - Blue
+ *   7 - Magenta
+ *
+ * So we have the same colours as VGA (basically one bit each for R, G, B),
+ * but have to translate them, anyway. */
+
+static const u8 col_trans[8] = {
+        0, 6, 4, 5,
+        2, 7, 3, 1
+};
+
+#define c_fg(sti, c) col_trans[((c>> 8) & 7)]
+#define c_bg(sti, c) col_trans[((c>>11) & 7)]
+#define c_index(sti, c) ((c) & 0xff)
+
+static const struct sti_init_flags default_init_flags = {
+	wait:	STI_WAIT, 
+	reset:	1,
+	text:	1, 
+	nontext:1,
+	no_chg_bet: 1, 
+	no_chg_bei: 1, 
+	init_cmap_tx: 1,
+};
+
+int
+sti_init_graph(struct sti_struct *sti) 
+{
+	struct sti_init_inptr_ext inptr_ext = { 0, };
+	struct sti_init_inptr inptr = {
+		3,	/* # of text planes (3 is maximum for STI) */ 
+		STI_PTR(&inptr_ext)
+	};
+	struct sti_init_outptr outptr = { 0, };
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&sti->lock, flags);
+
+	ret = STI_CALL(sti->init_graph, &default_init_flags, &inptr,
+		&outptr, sti->glob_cfg);
+
+	spin_unlock_irqrestore(&sti->lock, flags);
+
+	if (ret < 0) {
+		printk(KERN_ERR "STI init_graph failed (ret %d, errno %d)\n",ret,outptr.errno);
+		return -1;
+	}
+	
+	sti->text_planes = outptr.text_planes;
+	return 0;
+}
+
+static const struct sti_conf_flags default_conf_flags = {
+		wait:	STI_WAIT,
+	};
+
+void
+sti_inq_conf(struct sti_struct *sti)
+{
+	struct sti_conf_inptr inptr = { 0 };
+	unsigned long flags;
+	s32 ret;
+
+	sti->outptr.ext_ptr = STI_PTR(&sti->outptr_ext);
+	
+	do {
+		spin_lock_irqsave(&sti->lock, flags);
+		ret = STI_CALL(sti->inq_conf, &default_conf_flags,
+			&inptr, &sti->outptr, sti->glob_cfg);
+		spin_unlock_irqrestore(&sti->lock, flags);
+	} while (ret == 1);
+}
+
+static const struct sti_font_flags default_font_flags = {
+		wait:	STI_WAIT,
+		non_text: 0,
+};
+
+void
+sti_putc(struct sti_struct *sti, int c, int y, int x)
+{
+	struct sti_font_inptr inptr = {
+		STI_PTR(sti->font->raw),
+		c_index(sti, c), c_fg(sti, c), c_bg(sti, c),
+		x * sti->font_width, y * sti->font_height, 0
+	};
+	struct sti_font_outptr outptr = { 0, };
+	s32 ret;
+	unsigned long flags;
+
+	do {
+		spin_lock_irqsave(&sti->lock, flags);
+		ret = STI_CALL(sti->font_unpmv, &default_font_flags,
+			&inptr, &outptr, sti->glob_cfg);
+		spin_unlock_irqrestore(&sti->lock, flags);
+	} while (ret == 1);
+}
+
+static const struct sti_blkmv_flags clear_blkmv_flags = {
+	wait:	STI_WAIT, 
+	color:	1, 
+	clear:	1, 
+};
+
+void
+sti_set(struct sti_struct *sti, int src_y, int src_x,
+	int height, int width, u8 color)
+{
+	struct sti_blkmv_inptr inptr = {
+		color, color,
+		src_x, src_y ,
+		src_x, src_y ,
+		width, height,
+		0
+	};
+	struct sti_blkmv_outptr outptr = { 0, };
+	s32 ret;
+	unsigned long flags;
+	
+	do {
+		spin_lock_irqsave(&sti->lock, flags);
+		ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
+			&inptr, &outptr, sti->glob_cfg);
+		spin_unlock_irqrestore(&sti->lock, flags);
+	} while (ret == 1);
+}
+
+void
+sti_clear(struct sti_struct *sti, int src_y, int src_x,
+	  int height, int width, int c)
+{
+	struct sti_blkmv_inptr inptr = {
+		c_fg(sti, c), c_bg(sti, c),
+		src_x * sti->font_width, src_y * sti->font_height,
+		src_x * sti->font_width, src_y * sti->font_height,
+		width * sti->font_width, height* sti->font_height,
+		0
+	};
+	struct sti_blkmv_outptr outptr = { 0, };
+	s32 ret;
+	unsigned long flags;
+
+	do {
+		spin_lock_irqsave(&sti->lock, flags);
+		ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
+			&inptr, &outptr, sti->glob_cfg);
+		spin_unlock_irqrestore(&sti->lock, flags);
+	} while (ret == 1);
+}
+
+static const struct sti_blkmv_flags default_blkmv_flags = {
+	wait:	STI_WAIT, 
+};
+
+void
+sti_bmove(struct sti_struct *sti, int src_y, int src_x,
+	  int dst_y, int dst_x, int height, int width)
+{
+	struct sti_blkmv_inptr inptr = {
+		0, 0,
+		src_x * sti->font_width, src_y * sti->font_height,
+		dst_x * sti->font_width, dst_y * sti->font_height,
+		width * sti->font_width, height* sti->font_height,
+		0
+	};
+	struct sti_blkmv_outptr outptr = { 0, };
+	s32 ret;
+	unsigned long flags;
+
+	do {
+		spin_lock_irqsave(&sti->lock, flags);
+		ret = STI_CALL(sti->block_move, &default_blkmv_flags,
+			&inptr, &outptr, sti->glob_cfg);
+		spin_unlock_irqrestore(&sti->lock, flags);
+	} while (ret == 1);
+}
+
+
+void __init
+sti_rom_copy(unsigned long base, unsigned long count, void *dest)
+{
+	unsigned long dest_len = count;
+	unsigned long dest_start = (unsigned long) dest;
+
+	/* this still needs to be revisited (see arch/parisc/mm/init.c:246) ! */
+	while (count >= 4) {
+		count -= 4;
+		*(u32 *)dest = __raw_readl(base);
+		base += 4;
+		dest += 4;
+	}
+	while (count) {
+		count--;
+		*(u8 *)dest = __raw_readb(base);
+		base++;
+		dest++;
+	}
+
+	sti_flush(dest_start, dest_len); /* XXX */
+}
+
+
+
+
+static char default_sti_path[21];
+
+static int __init 
+sti_setup(char *str)
+{
+	if (str)
+		strncpy (default_sti_path, str, sizeof (default_sti_path));
+	
+	return 0;
+}
+
+/*	Assuming the machine has multiple STI consoles (=graphic cards) which
+ *	all get detected by sticon, the user may define with the linux kernel
+ *	parameter sti=<x> which of them will be the initial boot-console.
+ *	<x> is a number between 0 and MAX_STI_ROMS, with 0 as the default 
+ *	STI screen.
+ */
+__setup("sti=", sti_setup);
+
+
+
+static char __initdata	*font_name[MAX_STI_ROMS] = { "VGA8x16", };
+static int __initdata	font_index[MAX_STI_ROMS], 
+			font_height[MAX_STI_ROMS],
+			font_width[MAX_STI_ROMS];
+
+static int __init sti_font_setup(char *str)
+{
+	char *x;
+	int i = 0;
+
+	/* we accept sti_font=VGA8x16, sti_font=10x20, sti_font=10*20 
+	 * or sti_font=7 style command lines. */
+
+	while (i<MAX_STI_ROMS && str && *str) {
+		if (*str>='0' && *str<='9') {
+			if ((x = strchr(str, 'x')) || (x = strchr(str, '*'))) {
+				font_height[i] = simple_strtoul(str, NULL, 0);
+				font_width[i] = simple_strtoul(x+1, NULL, 0);
+			} else {
+				font_index[i] = simple_strtoul(str, NULL, 0);
+			}
+		} else {
+			font_name[i] = str;	/* fb font name */
+		}
+
+		if ((x = strchr(str, ',')))
+			*x++ = 0;
+		str = x;
+
+		i++;
+	}
+
+	return 0;
+}
+
+/*	The optional linux kernel parameter "sti_font" defines which font
+ *	should be used by the sticon driver to draw characters to the screen.
+ *	Possible values are:
+ *	- sti_font=<fb_fontname>:
+ *		<fb_fontname> is the name of one of the linux-kernel built-in 
+ *		framebuffer font names (e.g. VGA8x16, SUN22x18). 
+ *		This is only available if the fonts have been statically compiled 
+ *		in with e.g. the CONFIG_FONT_8x16 or CONFIG_FONT_SUN12x22 options.
+ *	- sti_font=<number>
+ *		most STI ROMs have built-in HP specific fonts, which can be selected
+ *		by giving the desired number to the sticon driver. 
+ *		NOTE: This number is machine and STI ROM dependend.
+ *	- sti_font=<height>x<width>  (e.g. sti_font=16x8)
+ *		<height> and <width> gives hints to the height and width of the
+ *		font which the user wants. The sticon driver will try to use
+ *		a font with this height and width, but if no suitable font is
+ *		found, sticon will use the default 8x8 font.
+ */
+__setup("sti_font=", sti_font_setup);
+
+
+	
+void __init
+sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, unsigned int sti_mem_request)
+{
+	struct sti_glob_cfg_ext *cfg;
+	
+	DPRINTK((KERN_INFO
+		"%d text planes\n"
+		"%4d x %4d screen resolution\n"
+		"%4d x %4d offscreen\n"
+		"%4d x %4d layout\n"
+		"regions at %08x %08x %08x %08x\n"
+		"regions at %08x %08x %08x %08x\n"
+		"reent_lvl %d\n"
+		"save_addr %08x\n",
+		glob_cfg->text_planes,
+		glob_cfg->onscreen_x, glob_cfg->onscreen_y,
+		glob_cfg->offscreen_x, glob_cfg->offscreen_y,
+		glob_cfg->total_x, glob_cfg->total_y,
+		glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1],
+		glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3],
+		glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5],
+		glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7],
+		glob_cfg->reent_lvl,
+		glob_cfg->save_addr));
+
+	/* dump extended cfg */ 
+	cfg = PTR_STI(glob_cfg->ext_ptr);
+	DPRINTK(( KERN_INFO
+		"monitor %d\n"
+		"in friendly mode: %d\n"
+		"power consumption %d watts\n"
+		"freq ref %d\n"
+		"sti_mem_addr %08x (size=%d bytes)\n",
+		cfg->curr_mon,
+		cfg->friendly_boot,
+		cfg->power,
+		cfg->freq_ref,
+		cfg->sti_mem_addr, sti_mem_request));
+}
+
+void __init
+sti_dump_outptr(struct sti_struct *sti)
+{
+	DPRINTK((KERN_INFO
+		"%d bits per pixel\n"
+		"%d used bits\n"
+		"%d planes\n"
+		"attributes %08x\n",
+		 sti->outptr.bits_per_pixel,
+		 sti->outptr.bits_used,
+		 sti->outptr.planes,
+		 sti->outptr.attributes));
+}
+
+int __init
+sti_init_glob_cfg(struct sti_struct *sti,
+	    unsigned long rom_address, unsigned long hpa)
+{
+	struct sti_glob_cfg *glob_cfg;
+	struct sti_glob_cfg_ext *glob_cfg_ext;
+	void *save_addr;
+	void *sti_mem_addr;
+	const int save_addr_size = 1024;	/* XXX */
+	int i;
+
+	if (!sti->sti_mem_request)
+		sti->sti_mem_request = 256; /* STI default */
+
+	glob_cfg = kmalloc(sizeof(*sti->glob_cfg), GFP_KERNEL);
+	glob_cfg_ext = kmalloc(sizeof(*glob_cfg_ext), GFP_KERNEL);
+	save_addr = kmalloc(save_addr_size, GFP_KERNEL);
+	sti_mem_addr = kmalloc(sti->sti_mem_request, GFP_KERNEL);
+
+	if (!(glob_cfg && glob_cfg_ext && save_addr && sti_mem_addr))
+		return -ENOMEM;
+
+	memset(glob_cfg, 0, sizeof(*glob_cfg));
+	memset(glob_cfg_ext, 0, sizeof(*glob_cfg_ext));
+	memset(save_addr, 0, save_addr_size);
+	memset(sti_mem_addr, 0, sti->sti_mem_request);
+
+	glob_cfg->ext_ptr = STI_PTR(glob_cfg_ext);
+	glob_cfg->save_addr = STI_PTR(save_addr);
+	for (i=0; i<8; i++) {
+		unsigned long newhpa, len;
+	       
+		if (sti->pd) {
+			unsigned char offs = sti->rm_entry[i];
+				
+			if (offs == 0)
+				continue;
+			if (offs != PCI_ROM_ADDRESS &&
+			    (offs < PCI_BASE_ADDRESS_0 ||
+			     offs > PCI_BASE_ADDRESS_5)) {
+				printk (KERN_WARNING
+					"STI pci region maping for region %d (%02x) can't be mapped\n",
+					i,sti->rm_entry[i]);
+				continue;
+			}
+			newhpa = pci_resource_start (sti->pd, (offs - PCI_BASE_ADDRESS_0) / 4);
+		} else
+			newhpa = (i == 0) ? rom_address : hpa;
+
+		sti->regions_phys[i] =
+			REGION_OFFSET_TO_PHYS(sti->regions[i], newhpa);
+		
+		/* remap virtually */
+		/* FIXME: add BTLB support if btlb==1 */
+		len = sti->regions[i].region_desc.length * 4096;
+		
+		if (len)
+		   glob_cfg->region_ptrs[i] = (unsigned long) (
+			sti->regions[i].region_desc.cache ?
+			ioremap(sti->regions_phys[i], len) :
+			ioremap_nocache(sti->regions_phys[i], len) );
+		
+		DPRINTK(("region #%d: phys %08lx, virt %08x, len=%lukB, "
+			 "btlb=%d, sysonly=%d, cache=%d, last=%d\n",
+			i, sti->regions_phys[i], glob_cfg->region_ptrs[i],
+			len/1024,
+			sti->regions[i].region_desc.btlb,
+			sti->regions[i].region_desc.sys_only,
+			sti->regions[i].region_desc.cache, 
+			sti->regions[i].region_desc.last));
+
+		/* last entry reached ? */
+		if (sti->regions[i].region_desc.last)
+			break;
+	}
+
+	if (++i<8 && sti->regions[i].region)
+		printk(KERN_WARNING "%s: *future ptr (0x%8x) not yet supported !\n",
+				__FILE__, sti->regions[i].region);
+
+	glob_cfg_ext->sti_mem_addr = STI_PTR(sti_mem_addr);
+
+	sti->glob_cfg = glob_cfg;
+	
+	return 0;
+}
+
+struct sti_cooked_font * __init
+sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name )
+{
+	struct fbcon_font_desc *fbfont;
+	unsigned int size, bpc;
+	void *dest;
+	struct sti_rom_font *nf;
+	struct sti_cooked_font *cooked_font;
+	
+	if (!fbfont_name || !strlen(fbfont_name))
+	    return NULL;
+	fbfont = fbcon_find_font(fbfont_name);
+	if (!fbfont)
+	    fbfont = fbcon_get_default_font(1024,768);
+	if (!fbfont)
+	    return NULL;
+
+	DPRINTK((KERN_DEBUG "selected %dx%d fb-font %s\n",
+			fbfont->width, fbfont->height, fbfont->name));
+			
+	bpc = ((fbfont->width+7)/8) * fbfont->height; 
+	size = bpc * 256;
+	size += sizeof(struct sti_rom_font);
+
+	nf = kmalloc(size, GFP_KERNEL);
+	if (!nf)
+	    return NULL;
+	memset(nf, 0, size);
+
+	nf->first_char = 0;
+	nf->last_char = 255;
+	nf->width = fbfont->width;
+	nf->height = fbfont->height;
+	nf->font_type = STI_FONT_HPROMAN8;
+	nf->bytes_per_char = bpc;
+	nf->next_font = 0;
+	nf->underline_height = 1;
+	nf->underline_pos = fbfont->height - nf->underline_height;
+
+	dest = nf;
+	dest += sizeof(struct sti_rom_font);
+	memcpy(dest, fbfont->data, bpc*256);
+
+	cooked_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL);
+	if (!cooked_font) {
+	    kfree(nf);
+	    return NULL;
+	}
+	
+	cooked_font->raw = nf;
+	cooked_font->next_font = NULL;
+
+	cooked_rom->font_start = cooked_font;
+
+	return cooked_font;
+}
+
+struct sti_cooked_font * __init
+sti_select_font(struct sti_cooked_rom *rom,
+	    int (*search_font_fnc) (struct sti_cooked_rom *,int,int) )
+{
+	struct sti_cooked_font *font;
+	int i;
+	int index = num_sti_roms;
+
+	/* check for framebuffer-font first */
+	if ((font = sti_select_fbfont(rom, font_name[index])))
+		return font;
+
+	if (font_width[index] && font_height[index])
+		font_index[index] = search_font_fnc(rom, 
+				font_height[index], font_width[index]);
+
+	for (font = rom->font_start, i = font_index[index];
+	    font && (i > 0);
+	    font = font->next_font, i--);
+
+	if (font)
+		return font;
+	else
+		return rom->font_start;
+}
+
+
+static void __init 
+sti_dump_rom(struct sti_rom *rom)
+{
+        printk(KERN_INFO "STI id %04x-%04x, conforms to spec rev. %d.%02x\n",
+		rom->graphics_id[0], 
+		rom->graphics_id[1],
+		rom->revno[0] >> 4, 
+		rom->revno[0] & 0x0f);
+	DPRINTK((" supports %d monitors\n", rom->num_mons));
+	DPRINTK((" font start %08x\n", rom->font_start));
+	DPRINTK((" region list %08x\n", rom->region_list));
+	DPRINTK((" init_graph %08x\n", rom->init_graph));
+	DPRINTK((" bus support %02x\n", rom->bus_support));
+	DPRINTK((" ext bus support %02x\n", rom->ext_bus_support));
+	DPRINTK((" alternate code type %d\n", rom->alt_code_type));
+}
+
+
+static int __init 
+sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
+			struct sti_rom *raw_rom)
+{
+	struct sti_rom_font *raw_font, *font_start;
+	struct sti_cooked_font *cooked_font;
+	
+	cooked_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL);
+	if (!cooked_font)
+		return 0;
+
+	cooked_rom->font_start = cooked_font;
+
+	raw_font = ((void *)raw_rom) + (raw_rom->font_start);
+
+	font_start = raw_font;
+	cooked_font->raw = raw_font;
+
+	while (raw_font->next_font) {
+		raw_font = ((void *)font_start) + (raw_font->next_font);
+
+		cooked_font->next_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL);
+		if (!cooked_font->next_font)
+			return 1;
+
+		cooked_font = cooked_font->next_font;
+
+		cooked_font->raw = raw_font;
+	}
+
+	cooked_font->next_font = NULL;
+	return 1;
+}
+
+
+static int __init 
+sti_search_font(struct sti_cooked_rom *rom, int height, int width)
+{
+	struct sti_cooked_font *font;
+	int i = 0;
+	
+	for(font = rom->font_start; font; font = font->next_font, i++) {
+	    if((font->raw->width == width) && (font->raw->height == height))
+			return i;
+	}
+	return 0;
+}
+
+#define BMODE_RELOCATE(offset)        offset = (offset) / 4;
+#define BMODE_LAST_ADDR_OFFS          0x50
+
+static void * __init
+sti_bmode_font_raw(struct sti_cooked_font *f)
+{
+	unsigned char *n, *p, *q;
+	int size = f->raw->bytes_per_char*256+sizeof(struct sti_rom_font);
+	
+	n = kmalloc (4*size, GFP_KERNEL);
+	if (!n)
+		return NULL;
+	memset (n, 0, 4*size);
+	p = n + 3;
+	q = (unsigned char *)f->raw;
+	while (size--) {
+		*p = *q++;
+		p+=4;
+	}
+	return n + 3;
+}
+
+static void __init
+sti_bmode_rom_copy(unsigned long base, unsigned long count, void *dest)
+{
+	unsigned long dest_len = count;
+	unsigned long dest_start = (unsigned long) dest;
+
+	while (count) {
+		count--;
+		*(u8 *)dest = __raw_readl(base);
+		base += 4;
+		dest++;
+	}
+	sti_flush(dest_start, dest_len); /* XXX */
+}
+
+struct sti_rom * __init
+sti_get_bmode_rom (unsigned long address)
+{
+	struct sti_rom *raw;
+	u32 size;
+        struct sti_rom_font *raw_font, *font_start;
+    
+	sti_bmode_rom_copy(address + BMODE_LAST_ADDR_OFFS, sizeof(size), &size);
+    
+        size = (size+3) / 4;
+	raw = kmalloc(size, GFP_KERNEL);
+	if (raw) {
+	    sti_bmode_rom_copy(address, size, raw);
+	    memmove (&raw->res004, &raw->type[0], 0x3c);
+    	    raw->type[3] = raw->res004;
+
+	    BMODE_RELOCATE (raw->region_list);
+	    BMODE_RELOCATE (raw->font_start);
+
+	    BMODE_RELOCATE (raw->init_graph);
+	    BMODE_RELOCATE (raw->state_mgmt);
+	    BMODE_RELOCATE (raw->font_unpmv);
+	    BMODE_RELOCATE (raw->block_move);
+	    BMODE_RELOCATE (raw->inq_conf);
+
+	    raw_font = ((void *)raw) + raw->font_start;
+	    font_start = raw_font;
+		
+	    while (raw_font->next_font) {
+		    BMODE_RELOCATE (raw_font->next_font);
+		    raw_font = ((void *)font_start) + raw_font->next_font;
+	    }
+	}
+        return raw;
+}
+
+struct sti_rom * __init
+sti_get_wmode_rom (unsigned long address)
+{
+	struct sti_rom *raw;
+	unsigned long size;
+    
+	/* read the ROM size directly from the struct in ROM */ 
+	size = __raw_readl(address + offsetof(struct sti_rom,last_addr));
+
+	raw = kmalloc(size, GFP_KERNEL);
+	if(raw)
+	        sti_rom_copy(address, size, raw);
+
+        return raw;
+}
+
+int __init
+sti_read_rom(int wordmode, struct sti_struct *sti, unsigned long address)
+{
+	struct sti_cooked_rom *cooked;
+	struct sti_rom *raw = NULL;
+
+	cooked = kmalloc(sizeof *cooked, GFP_KERNEL);
+	if (!cooked)
+		goto out_err;
+
+        if (wordmode)
+                raw = sti_get_wmode_rom (address);
+        else
+	        raw = sti_get_bmode_rom (address);
+
+        if (!raw)
+	        goto out_err;
+    
+	if (!sti_cook_fonts(cooked, raw)) {
+		printk(KERN_ERR "No font found for STI at %08lx\n", address);
+		goto out_err;
+	}
+
+	if (raw->region_list)
+		memcpy(sti->regions, ((void *)raw)+raw->region_list, sizeof(sti->regions));
+
+	address = (unsigned long) STI_PTR(raw);
+
+	sti->font_unpmv = address + (raw->font_unpmv & 0x03ffffff);
+	sti->block_move = address + (raw->block_move & 0x03ffffff);
+	sti->init_graph = address + (raw->init_graph & 0x03ffffff);
+	sti->inq_conf   = address + (raw->inq_conf   & 0x03ffffff);
+
+	sti->rom = cooked;
+	sti->rom->raw = raw;
+	
+	sti->font = sti_select_font(sti->rom, sti_search_font);
+	sti->font_width = sti->font->raw->width;
+	sti->font_height = sti->font->raw->height;
+	if (!wordmode)
+	        sti->font->raw = sti_bmode_font_raw(sti->font);
+
+	sti->sti_mem_request = raw->sti_mem_req;
+	sti->graphics_id[0] = raw->graphics_id[0];
+	sti->graphics_id[1] = raw->graphics_id[1];
+	
+	sti_dump_rom(raw);
+	
+	return 1;
+
+out_err:
+	if(raw)
+		kfree(raw);
+	if(cooked)
+		kfree(cooked);
+
+	return 0;
+}
+
+static struct sti_struct * __init
+sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd)
+{
+	struct sti_struct *sti;
+	int ok;
+	u32 sig;
+
+	if (num_sti_roms >= MAX_STI_ROMS) {
+	    printk(KERN_WARNING "maximum number of STI ROMS reached !\n");
+	    return NULL;
+	}
+	
+	sti = kmalloc(sizeof(*sti), GFP_KERNEL);
+	if (!sti) {
+	    printk(KERN_ERR "Not enough memory !\n");
+	    return NULL;
+	}
+		    
+	memset(sti, 0, sizeof(*sti));
+	sti->lock = SPIN_LOCK_UNLOCKED;
+
+test_rom:
+	/* if we can't read the ROM, bail out early.  Not being able
+	 * to read the hpa is okay, for romless sti */
+	if (pdc_add_valid(address))
+		goto out_err;
+
+	sig = __raw_readl(address);
+
+	/* check for a PCI ROM structure */
+	if ((le32_to_cpu(sig)==0xaa55)) {
+		unsigned int i, rm_offset;
+		u32 *rm;
+		i = __raw_readl(address+0x04);
+		if (i != 1) {
+			/* The ROM could have multiple architecture 
+			 * dependent images (e.g. i386, parisc,...) */
+			printk(KERN_WARNING 
+				"PCI ROM is not a STI ROM type image (0x%8x)\n", i);
+			goto out_err;
+		}
+		
+		sti->pd = pd;
+
+		i = __raw_readl(address+0x0c);
+		DPRINTK(("PCI ROM size (from header) = %d kB\n",
+			le16_to_cpu(i>>16)*512/1024));
+		rm_offset = le16_to_cpu(i & 0xffff);
+		if (rm_offset) { 
+			/* read 16 bytes from the pci region mapper array */
+			rm = (u32*) &sti->rm_entry;
+			*rm++ = __raw_readl(address+rm_offset+0x00);
+			*rm++ = __raw_readl(address+rm_offset+0x04);
+			*rm++ = __raw_readl(address+rm_offset+0x08);
+			*rm++ = __raw_readl(address+rm_offset+0x0c);
+			DPRINTK(("PCI region Mapper offset = %08x: ",
+				rm_offset));
+			for (i=0; i<16; i++)
+				DPRINTK(("%02x ", sti->rm_entry[i]));
+			DPRINTK(("\n"));
+		}
+
+		address += le32_to_cpu(__raw_readl(address+8));
+		DPRINTK(("sig %04x, PCI STI ROM at %08lx\n", sig, address));
+		goto test_rom;
+	}
+	
+	ok = 0;
+	
+	if ((sig & 0xff) == 0x01) {
+		printk(KERN_INFO "STI byte mode ROM at %08lx, hpa at %08lx\n",
+		       address, hpa);
+		ok = sti_read_rom(0, sti, address);
+	}
+
+	if ((sig & 0xffff) == 0x0303) {
+		printk(KERN_INFO "STI word mode ROM at %08lx, hpa at %08lx\n",
+		       address, hpa);
+		ok = sti_read_rom(1, sti, address);
+	}
+
+	if (!ok)
+		goto out_err;
+
+	if (sti_init_glob_cfg(sti, address, hpa))
+		goto out_err; /* not enough memory */
+
+	/* disable STI PCI ROM. ROM and card RAM overlap and
+	 * leaving it enabled would force HPMCs
+	 */
+	if (sti->pd) {
+		unsigned long rom_base;
+		rom_base = pci_resource_start(sti->pd, PCI_ROM_RESOURCE);	
+		pci_write_config_dword(sti->pd, PCI_ROM_ADDRESS, rom_base & ~PCI_ROM_ADDRESS_ENABLE);
+		DPRINTK((KERN_DEBUG "STI PCI ROM disabled\n"));
+	}
+
+	if (sti_init_graph(sti))
+		goto out_err;
+
+	sti_inq_conf(sti);
+	sti_dump_globcfg(sti->glob_cfg, sti->sti_mem_request);
+	sti_dump_outptr(sti);
+	
+	printk(KERN_INFO "STI device: %s\n", sti->outptr.dev_name );
+
+	sti_roms[num_sti_roms] = sti;
+	num_sti_roms++;
+	
+	return sti;
+
+out_err:
+	kfree(sti);
+	return NULL;
+}
+
+static void __init sticore_check_for_default_sti (struct sti_struct *sti, char *path)
+{
+	if (strcmp (path, default_sti_path) == 0)
+		default_sti = sti;
+}
+
+/*
+ * on newer systems PDC gives the address of the ROM 
+ * in the additional address field addr[1] while on
+ * older Systems the PDC stores it in page0->proc_sti 
+ */
+static int __init sticore_pa_init(struct parisc_device *dev)
+{
+	unsigned long rom = 0;
+	char pa_path[21];
+	struct sti_struct *sti = NULL;
+	
+	if(dev->num_addrs) {
+		rom = dev->addr[0];
+	}
+	if (!rom) {
+		rom = dev->hpa;
+		DPRINTK((KERN_DEBUG "Trying STI ROM at %08lx, hpa at %08lx\n", rom, dev->hpa));
+		sti = sti_try_rom_generic(rom, dev->hpa, NULL);
+		rom = PAGE0->proc_sti;
+	}
+	if (!sti) {
+		DPRINTK((KERN_DEBUG "Trying STI ROM at %08lx, hpa at %08lx\n", rom, dev->hpa));
+		sti = sti_try_rom_generic(rom, dev->hpa, NULL);
+	}
+	if (!sti)
+		return 1;
+	
+	print_pa_hwpath(dev, pa_path);
+	sticore_check_for_default_sti (sti, pa_path);
+	return 0;
+}
+
+
+static int __devinit sticore_pci_init(struct pci_dev *pd,
+		const struct pci_device_id *ent)
+{
+#ifdef CONFIG_PCI
+	unsigned long fb_base, rom_base;
+	unsigned int fb_len, rom_len;
+	struct sti_struct *sti;
+	
+	pci_enable_device(pd);
+
+	fb_base = pci_resource_start(pd, 0);
+	fb_len = pci_resource_len(pd, 0);
+	rom_base = pci_resource_start(pd, PCI_ROM_RESOURCE);
+	rom_len = pci_resource_len(pd, PCI_ROM_RESOURCE);
+	if (rom_base) {
+		pci_write_config_dword(pd, PCI_ROM_ADDRESS, rom_base | PCI_ROM_ADDRESS_ENABLE);
+		DPRINTK((KERN_DEBUG "STI PCI ROM enabled at 0x%08lx\n", rom_base));
+	}
+
+	printk(KERN_INFO "STI PCI graphic ROM found at %08lx (%u kB), fb at %08lx (%u MB)\n",
+		rom_base, rom_len/1024, fb_base, fb_len/1024/1024);
+
+	DPRINTK((KERN_DEBUG "Trying PCI STI ROM at %08lx, PCI hpa at %08lx\n",
+		    rom_base, fb_base));
+
+	sti = sti_try_rom_generic(rom_base, fb_base, pd);
+	if (sti) {
+		char pa_path[30];
+		print_pci_hwpath(pd, pa_path);
+		sticore_check_for_default_sti(sti, pa_path);
+	}
+	
+	if (!sti) {
+		printk(KERN_WARNING "Unable to handle STI device '%s'\n",
+			pd->name);
+		return -ENODEV;
+	}
+#endif /* CONFIG_PCI */
+
+	return 0;
+}
+
+
+static void __devexit sticore_pci_remove(struct pci_dev *pd)
+{
+	BUG();
+}
+
+
+#define PCI_DEVICE_ID_VISUALIZE_EG	0x1005
+#define PCI_DEVICE_ID_VISUALIZE_FX	0x1008
+#define PCI_DEVICE_ID_VISUALIZE_FX_NEW	0x108b
+
+static struct pci_device_id sti_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_VISUALIZE_EG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_VISUALIZE_FX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_VISUALIZE_FX_NEW, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, } /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, sti_pci_tbl);
+
+static struct pci_driver pci_sti_driver = {
+	name:		"sti (pci)",
+	id_table:	sti_pci_tbl,
+	probe:		sticore_pci_init,
+	remove:		sticore_pci_remove,
+};
+
+static struct parisc_device_id sti_pa_tbl[] = {
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00077 },
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00085 },
+	{ 0, }
+};
+
+struct parisc_driver pa_sti_driver = {
+	name:		"sti (native)",
+	id_table:	sti_pa_tbl,
+	probe:		sticore_pa_init,
+};
+
+struct sti_struct * __init sti_init_roms(void)
+{
+	static int initialized;
+
+	if (initialized)
+		goto out;
+
+	printk(KERN_INFO "STI GSC/PCI graphics driver version %s\n",
+			STI_DRIVERVERSION);
+
+	/* Register drivers for native & PCI cards */
+	register_parisc_driver(&pa_sti_driver);
+	pci_module_init (&pci_sti_driver);
+
+	/* if we didn't find the given default sti, take the first one */
+	if (!default_sti)
+		default_sti = sti_roms[0];
+
+out:
+	/* return default STI if available */
+	if (num_sti_roms && default_sti && default_sti->init_graph) {
+		initialized = 1;
+		return default_sti;
+	}
+	return NULL;
+}
+
+/*
+ * index = 0 gives default sti
+ * index > 0 gives other stis in detection order
+ */
+struct sti_struct * __init sti_get_rom(int index)
+{
+	int i;
+	
+	if (index == 0)
+		return default_sti;
+
+	i = -1;
+	while (index > 0) {
+		i++;
+		if (i > num_sti_roms)
+			return NULL;
+		if (sti_roms[i] == default_sti)
+			continue;
+		index--;
+	}
+	return sti_roms[i];
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sti/sticore.h linux-2.4.20/drivers/video/sti/sticore.h
--- linux-2.4.19/drivers/video/sti/sticore.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/video/sti/sticore.h	2002-10-29 11:18:51.000000000 +0000
@@ -0,0 +1,406 @@
+#ifndef STICORE_H
+#define STICORE_H
+
+/* generic STI structures & functions */
+
+#if 0
+#define DPRINTK(x)	printk x
+#else
+#define DPRINTK(x) 
+#endif
+
+#define MAX_STI_ROMS 4		/* max no. of ROMs which this driver handles */
+
+#define STI_REGION_MAX 8	/* hardcoded STI constants */
+#define STI_DEV_NAME_LENGTH 32
+#define STI_MONITOR_MAX 256
+
+#define STI_FONT_HPROMAN8 1
+#define STI_FONT_KANA8 2
+
+/* The latency of the STI functions cannot really be reduced by setting
+ * this to 0;  STI doesn't seem to be designed to allow calling a different
+ * function (or the same function with different arguments) after a
+ * function exited with 1 as return value.
+ *
+ * As all of the functions below could be called from interrupt context,
+ * we have to spin_lock_irqsave around the do { ret = bla(); } while(ret==1)
+ * block.  Really bad latency there.
+ *
+ * Probably the best solution to all this is have the generic code manage
+ * the screen buffer and a kernel thread to call STI occasionally.
+ * 
+ * Luckily, the frame buffer guys have the same problem so we can just wait
+ * for them to fix it and steal their solution.   prumpf
+ */
+ 
+#define STI_WAIT 1
+
+#include <asm/io.h> /* for USE_HPPA_IOREMAP */
+
+#if USE_HPPA_IOREMAP
+
+#define STI_PTR(p)	(p)
+#define PTR_STI(p)	(p)
+static int inline STI_CALL( unsigned long func, 
+		void *flags, void *inptr, void *outptr, void *glob_cfg )
+{
+       int (*f)(void *,void *,void *,void *);
+       f = (void*)func;
+       return f(flags, inptr, outptr, glob_cfg);
+}
+
+#else /* !USE_HPPA_IOREMAP */
+
+#define STI_PTR(p)	( virt_to_phys(p) )
+#define PTR_STI(p)	( phys_to_virt((long)p) )
+#define STI_CALL(func, flags, inptr, outptr, glob_cfg) \
+       ({                                                      \
+               pdc_sti_call( func, (unsigned long)STI_PTR(flags), \
+                                   (unsigned long)STI_PTR(inptr), \
+                                   (unsigned long)STI_PTR(outptr), \
+                                   (unsigned long)STI_PTR(glob_cfg)); \
+       })
+
+#endif /* USE_HPPA_IOREMAP */
+
+
+#define sti_onscreen_x(sti) (sti->glob_cfg->onscreen_x)
+#define sti_onscreen_y(sti) (sti->glob_cfg->onscreen_y)
+
+/* sti_font_xy() use the native font ROM ! */
+#define sti_font_x(sti) (PTR_STI(sti->font)->width)
+#define sti_font_y(sti) (PTR_STI(sti->font)->height)
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+#endif
+
+extern struct sti_struct *sti_init_roms(void);
+
+/* XXX: this probably should not be here, but we rely on STI being
+   initialized early and independently of stifb at the moment, so
+   there's no other way for stifb to find it. */
+extern struct sti_struct *default_sti;
+
+
+int  sti_init_graph(struct sti_struct *sti);
+void sti_inq_conf(struct sti_struct *sti);
+void sti_putc(struct sti_struct *sti, int c, int y, int x);
+void sti_set(struct sti_struct *sti, int src_y, int src_x,
+	     int height, int width, u8 color);
+void sti_clear(struct sti_struct *sti, int src_y, int src_x,
+	       int height, int width, int c);
+void sti_bmove(struct sti_struct *sti, int src_y, int src_x,
+	       int dst_y, int dst_x, int height, int width);
+
+
+/* STI function configuration structs */
+
+typedef union region {
+	struct { 
+		u32 offset	: 14;	/* offset in 4kbyte page */
+		u32 sys_only	: 1;	/* don't map to user space */
+		u32 cache	: 1;	/* map to data cache */
+		u32 btlb	: 1;	/* map to block tlb */
+		u32 last	: 1;	/* last region in list */
+		u32 length	: 14;	/* length in 4kbyte page */
+	} region_desc;
+
+	u32 region;			/* complete region value */
+} region_t;
+
+#define REGION_OFFSET_TO_PHYS( rt, hpa ) \
+	(((rt).region_desc.offset << 12) + (hpa))
+
+struct sti_glob_cfg_ext {
+	 u8 curr_mon;			/* current monitor configured */
+	 u8 friendly_boot;		/* in friendly boot mode */
+	s16 power;			/* power calculation (in Watts) */
+	s32 freq_ref;			/* frequency refrence */
+	u32 sti_mem_addr;		/* pointer to global sti memory (size=sti_mem_request) */
+	u32 future_ptr; 		/* pointer to future data */
+};
+
+struct sti_glob_cfg {
+	s32 text_planes;		/* number of planes used for text */
+	s16 onscreen_x;			/* screen width in pixels */
+	s16 onscreen_y;			/* screen height in pixels */
+	s16 offscreen_x;		/* offset width in pixels */
+	s16 offscreen_y;		/* offset height in pixels */
+	s16 total_x;			/* frame buffer width in pixels */
+	s16 total_y;			/* frame buffer height in pixels */
+	u32 region_ptrs[STI_REGION_MAX]; /* region pointers */
+	s32 reent_lvl;			/* storage for reentry level value */
+	u32 save_addr;			/* where to save or restore reentrant state */
+	u32 ext_ptr;			/* pointer to extended glob_cfg data structure */
+};
+
+
+/* STI init function structs */
+
+struct sti_init_flags {
+	u32 wait : 1;		/* should routine idle wait or not */
+	u32 reset : 1;		/* hard reset the device? */
+	u32 text : 1;		/* turn on text display planes? */
+	u32 nontext : 1;	/* turn on non-text display planes? */
+	u32 clear : 1;		/* clear text display planes? */
+	u32 cmap_blk : 1;	/* non-text planes cmap black? */
+	u32 enable_be_timer : 1; /* enable bus error timer */
+	u32 enable_be_int : 1;	/* enable bus error timer interrupt */
+	u32 no_chg_tx : 1;	/* don't change text settings */
+	u32 no_chg_ntx : 1;	/* don't change non-text settings */
+	u32 no_chg_bet : 1;	/* don't change berr timer settings */
+	u32 no_chg_bei : 1;	/* don't change berr int settings */
+	u32 init_cmap_tx : 1;	/* initialize cmap for text planes */
+	u32 cmt_chg : 1;	/* change current monitor type */
+	u32 retain_ie : 1;	/* don't allow reset to clear int enables */
+	u32 caller_bootrom : 1;	/* set only by bootrom for each call */
+	u32 caller_kernel : 1;	/* set only by kernel for each call */
+	u32 caller_other : 1;	/* set only by non-[BR/K] caller */
+	u32 pad	: 14;		/* pad to word boundary */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+struct sti_init_inptr_ext {
+	u8  config_mon_type;	/* configure to monitor type */
+	u8  pad[1];		/* pad to word boundary */
+	u16 inflight_data;	/* inflight data possible on PCI */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+struct sti_init_inptr {
+	s32 text_planes;	/* number of planes to use for text */
+	u32 ext_ptr;		 /* pointer to extended init_graph inptr data structure*/
+};
+
+
+struct sti_init_outptr {
+	s32 errno;		/* error number on failure */
+	s32 text_planes;	/* number of planes used for text */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+
+
+/* STI configuration function structs */
+
+struct sti_conf_flags {
+	u32 wait : 1;		/* should routine idle wait or not */
+	u32 pad : 31;		/* pad to word boundary */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+struct sti_conf_inptr {
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+struct sti_conf_outptr_ext {
+	u32 crt_config[3];	/* hardware specific X11/OGL information */	
+	u32 crt_hdw[3];
+	u32 future_ptr;
+};
+
+struct sti_conf_outptr {
+	s32 errno;		/* error number on failure */
+	s16 onscreen_x;		/* screen width in pixels */
+	s16 onscreen_y;		/* screen height in pixels */
+	s16 offscreen_x;	/* offscreen width in pixels */
+	s16 offscreen_y;	/* offscreen height in pixels */
+	s16 total_x;		/* frame buffer width in pixels */
+	s16 total_y;		/* frame buffer height in pixels */
+	s32 bits_per_pixel;	/* bits/pixel device has configured */
+	s32 bits_used;		/* bits which can be accessed */
+	s32 planes;		/* number of fb planes in system */
+	 u8 dev_name[STI_DEV_NAME_LENGTH]; /* null terminated product name */
+	u32 attributes;		/* flags denoting attributes */
+	u32 ext_ptr;		/* pointer to future data */
+};
+
+struct sti_rom {
+	 u8 type[4];
+	 u8 res004;
+	 u8 num_mons;
+	 u8 revno[2];
+	u32 graphics_id[2];
+
+	u32 font_start;
+	u32 statesize;
+	u32 last_addr;
+	u32 region_list;
+
+	u16 reentsize;
+	u16 maxtime;
+	u32 mon_tbl_addr;
+	u32 user_data_addr;
+	u32 sti_mem_req;
+
+	u32 user_data_size;
+	u16 power;
+	 u8 bus_support;
+	 u8 ext_bus_support;
+	 u8 alt_code_type;
+	 u8 ext_dd_struct[3];
+	u32 cfb_addr;
+
+	u32 init_graph;
+	u32 state_mgmt;
+	u32 font_unpmv;
+	u32 block_move;
+	u32 self_test;
+	u32 excep_hdlr;
+	u32 inq_conf;
+	u32 set_cm_entry;
+	u32 dma_ctrl;
+	 u8 res040[7 * 4];
+	
+	u32 init_graph_addr;
+	u32 state_mgmt_addr;
+	u32 font_unp_addr;
+	u32 block_move_addr;
+	u32 self_test_addr;
+	u32 excep_hdlr_addr;
+	u32 inq_conf_addr;
+	u32 set_cm_entry_addr;
+	u32 image_unpack_addr;
+	u32 pa_risx_addrs[7];
+};
+
+struct sti_rom_font {
+	u16 first_char;
+	u16 last_char;
+	 u8 width;
+	 u8 height;
+	 u8 font_type;		/* language type */
+	 u8 bytes_per_char;
+	u32 next_font;
+	 u8 underline_height;
+	 u8 underline_pos;
+	 u8 res008[2];
+};
+
+/* sticore internal font handling */
+
+struct sti_cooked_font {
+        struct sti_rom_font *raw;
+	struct sti_cooked_font *next_font;
+};
+
+struct sti_cooked_rom {
+        struct sti_rom *raw;
+	struct sti_cooked_font *font_start;
+};
+
+/* STI font printing function structs */
+
+struct sti_font_inptr {
+	u32 font_start_addr;	/* address of font start */
+	s16 index;		/* index into font table of character */
+	u8 fg_color;		/* foreground color of character */
+	u8 bg_color;		/* background color of character */
+	s16 dest_x;		/* X location of character upper left */
+	s16 dest_y;		/* Y location of character upper left */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+struct sti_font_flags {
+	u32 wait : 1;		/* should routine idle wait or not */
+	u32 non_text : 1;	/* font unpack/move in non_text planes =1, text =0 */
+	u32 pad : 30;		/* pad to word boundary */
+	u32 future_ptr; 	/* pointer to future data */
+};
+	
+struct sti_font_outptr {
+	s32 errno;		/* error number on failure */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+/* STI blockmove structs */
+
+struct sti_blkmv_flags {
+	u32 wait : 1;		/* should routine idle wait or not */
+	u32 color : 1;		/* change color during move? */
+	u32 clear : 1;		/* clear during move? */
+	u32 non_text : 1;	/* block move in non_text planes =1, text =0 */
+	u32 pad : 28;		/* pad to word boundary */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+struct sti_blkmv_inptr {
+	u8 fg_color;		/* foreground color after move */
+	u8 bg_color;		/* background color after move */
+	s16 src_x;		/* source upper left pixel x location */
+	s16 src_y;		/* source upper left pixel y location */
+	s16 dest_x;		/* dest upper left pixel x location */
+	s16 dest_y;		/* dest upper left pixel y location */
+	s16 width;		/* block width in pixels */
+	s16 height;		/* block height in pixels */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+struct sti_blkmv_outptr {
+	s32 errno;		/* error number on failure */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+
+/* internal generic STI struct */
+
+struct sti_struct {
+	spinlock_t lock;
+		
+	/* the following fields needs to be filled in by the word/byte routines */
+	int font_width;	
+	int font_height;
+	/* char **mon_strings; */
+	int sti_mem_request;
+	u32 graphics_id[2];
+
+	struct sti_cooked_rom *rom;
+
+	unsigned long font_unpmv;
+	unsigned long block_move;
+	unsigned long init_graph;
+	unsigned long inq_conf;
+
+	/* all following fields are initialized by the generic routines */
+	int text_planes;
+	region_t regions[STI_REGION_MAX];
+	unsigned long regions_phys[STI_REGION_MAX];
+
+	struct sti_glob_cfg *glob_cfg;
+	struct sti_cooked_font *font;	/* ptr to selected font (cooked) */
+
+	struct sti_conf_outptr outptr; /* configuration */
+	struct sti_conf_outptr_ext outptr_ext;
+
+	/* PCI data structures (pg. 17ff from sti.pdf) */
+	struct pci_dev *pd;
+	u8 rm_entry[16]; /* pci region mapper array == pci config space offset */
+};
+
+
+
+/* helper functions */
+struct sti_struct *sti_init_roms(void);
+struct sti_struct *sti_get_rom(int);
+void sti_rom_copy(unsigned long base, unsigned long count, void *dest);
+struct sti_cooked_font *sti_select_font(struct sti_cooked_rom *rom,
+	    int (*search_font_fnc) (struct sti_cooked_rom *,int,int) );
+
+int sti_read_rom(int wordmode, struct sti_struct *sti,
+	    unsigned long address);
+
+
+/* FIXME: Do we have another solution for this ? */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <asm/pgalloc.h>
+static inline void sti_flush(unsigned long from, unsigned long len)
+{
+	flush_data_cache();
+	flush_kernel_dcache_range(from, len);
+	flush_icache_range(from, from+len);
+}
+
+#endif	/* STICORE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sti/stifb.c linux-2.4.20/drivers/video/sti/stifb.c
--- linux-2.4.19/drivers/video/sti/stifb.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/video/sti/stifb.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,1507 @@
+/*
+ * linux/drivers/video/sti/stifb.c - 
+ * Frame buffer driver for HP workstations with STI (standard text interface) 
+ * video firmware.
+ *
+ * Copyright (C) 2001 Helge Deller <deller@gmx.de>
+ * Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+ * 
+ * Based on:
+ * - linux/drivers/video/artistfb.c -- Artist frame buffer driver
+ *	Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *   - based on skeletonfb, which was
+ *	Created 28 Dec 1997 by Geert Uytterhoeven
+ * - HP Xhp cfb-based X11 window driver for XFree86
+ *	(c)Copyright 1992 Hewlett-Packard Co.
+ *
+ * 
+ *  The following graphics display devices (NGLE family) are supported by this driver:
+ *
+ *  HPA4070A	known as "HCRX", a 1280x1024 color device with 8 planes
+ *  HPA4071A	known as "HCRX24", a 1280x1024 color device with 24 planes,
+ *		optionally available with a hardware accelerator as HPA4071A_Z
+ *  HPA1659A	known as "CRX", a 1280x1024 color device with 8 planes
+ *  HPA1439A	known as "CRX24", a 1280x1024 color device with 24 planes,
+ *		optionally available with a hardware accelerator.
+ *  HPA1924A	known as "GRX", a 1280x1024 grayscale device with 8 planes
+ *  HPA2269A	known as "Dual CRX", a 1280x1024 color device with 8 planes,
+ *		implements support for two displays on a single graphics card.
+ *  HP710C	internal graphics support optionally available on the HP9000s710 SPU,
+ *		supports 1280x1024 color displays with 8 planes.
+ *  HP710G	same as HP710C, 1280x1024 grayscale only
+ *  HP710L	same as HP710C, 1024x768 color only
+ *  HP712	internal graphics support on HP9000s712 SPU, supports 640x480, 
+ *		1024x768 or 1280x1024 color displays on 8 planes (Artist)
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/* TODO:
+ *	- Artist gfx is the only supported chip atm,
+ *	- remove the static fb_info to support multiple cards
+ *	- remove the completely untested 1bpp mode
+ *	- add support for h/w acceleration
+ *	- add hardware cursor
+ *	-
+ */
+
+
+/* on supported graphic devices you may:
+ * #define FALLBACK_TO_1BPP to fall back to 1 bpp, or
+ * #undef  FALLBACK_TO_1BPP to reject support for unsupported cards */
+#undef FALLBACK_TO_1BPP
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb32.h>
+
+#include <asm/grfioctl.h>	/* for HP-UX compatibility */
+
+#include "sticore.h"
+
+extern struct display_switch fbcon_sti; /* fbcon-sti.c */
+
+#ifdef __LP64__
+/* return virtual address */
+#define REGION_BASE(fb_info, index) \
+	(fb_info->sti->glob_cfg->region_ptrs[index] | 0xffffffff00000000)
+#else
+/* return virtual address */
+#define REGION_BASE(fb_info, index) \
+	fb_info->sti->glob_cfg->region_ptrs[index]
+#endif
+
+#define NGLEDEVDEPROM_CRT_REGION 1
+
+typedef struct {
+	__s32	video_config_reg;
+	__s32	misc_video_start;
+	__s32	horiz_timing_fmt;
+	__s32	serr_timing_fmt;
+	__s32	vert_timing_fmt;
+	__s32	horiz_state;
+	__s32	vert_state;
+	__s32	vtg_state_elements;
+	__s32	pipeline_delay;
+	__s32	misc_video_end;
+} video_setup_t;
+
+typedef struct {                  
+	__s16	sizeof_ngle_data;
+	__s16	x_size_visible;	    /* visible screen dim in pixels  */
+	__s16	y_size_visible;
+	__s16	pad2[15];
+	__s16	cursor_pipeline_delay;
+	__s16	video_interleaves;
+	__s32	pad3[11];
+} ngle_rom_t;
+
+struct stifb_info {
+	struct fb_info info;
+        struct fb_var_screeninfo var;
+        struct fb_fix_screeninfo fix;
+	struct display disp;
+	struct sti_struct *sti;
+	unsigned int id, real_id;
+	int currcon;
+	int cmap_reload:1;   
+	int deviceSpecificConfig;
+	ngle_rom_t ngle_rom;
+	struct { u8 red, green, blue; } palette[256];
+#ifdef FBCON_HAS_CFB32	
+	union {
+		u32 cfb32[16];
+	} fbcon_cmap;
+#endif			
+};
+
+static int stifb_force_bpp[MAX_STI_ROMS] = {0, };
+
+/* ------------------- chipset specific functions -------------------------- */
+
+/* offsets to graphic-chip internal registers */
+
+#define REG_1		0x000118
+#define REG_2		0x000480
+#define REG_3		0x0004a0
+#define REG_4		0x000600
+#define REG_6		0x000800
+#define REG_8		0x000820
+#define REG_9		0x000a04
+#define REG_10		0x018000
+#define REG_11		0x018004
+#define REG_12		0x01800c
+#define REG_13		0x018018
+#define REG_14  	0x01801c
+#define REG_15		0x200000
+#define REG_15b0	0x200000
+#define REG_16b1	0x200005
+#define REG_16b3	0x200007
+#define REG_21		0x200218
+#define REG_22		0x0005a0
+#define REG_23		0x0005c0
+#define REG_26		0x200118
+#define REG_27		0x200308
+#define REG_32		0x21003c
+#define REG_33		0x210040
+#define REG_34		0x200008
+#define REG_35		0x018010
+#define REG_38		0x210020
+#define REG_39		0x210120
+#define REG_40		0x210130
+#define REG_42		0x210028
+#define REG_43		0x21002c
+#define REG_44		0x210030
+#define REG_45		0x210034
+
+#define READ_BYTE(fb,reg)		__raw_readb((fb)->fix.mmio_start + (reg))
+#define READ_WORD(fb,reg)		__raw_readl((fb)->fix.mmio_start + (reg))
+#define WRITE_BYTE(value,fb,reg)	__raw_writeb((value),(fb)->fix.mmio_start + (reg))
+#define WRITE_WORD(value,fb,reg)	__raw_writel((value),(fb)->fix.mmio_start + (reg))
+
+#define ENABLE	1	/* for enabling/disabling screen */	
+#define DISABLE 0
+
+#define NGLE_LOCK(fb_info)	do { } while (0) 
+#define NGLE_UNLOCK(fb_info)	do { } while (0)
+
+static void
+SETUP_HW(struct stifb_info *fb)
+{
+	char stat;
+
+	do {
+		stat = READ_BYTE(fb, REG_15b0);
+		if (!stat)
+	    		stat = READ_BYTE(fb, REG_15b0);
+	} while (stat);
+}
+
+
+static void
+SETUP_FB(struct stifb_info *fb)
+{	
+	unsigned int reg10_value = 0;
+	
+	SETUP_HW(fb);
+	switch (fb->id)
+	{
+		case CRT_ID_VISUALIZE_EG:
+		case S9000_ID_ARTIST:
+		case S9000_ID_A1659A:
+			reg10_value = 0x13601000;
+			break;
+		case S9000_ID_A1439A:
+			if (fb->var.bits_per_pixel == 32)						
+				reg10_value = 0xBBA0A000;
+			else 
+				reg10_value = 0x13601000;
+			break;
+		case S9000_ID_HCRX:
+			if (fb->var.bits_per_pixel == 32)
+				reg10_value = 0xBBA0A000;
+			else					
+				reg10_value = 0x13602000;
+			break;
+		case S9000_ID_TIMBER:
+		case CRX24_OVERLAY_PLANES:
+			reg10_value = 0x13602000;
+			break;
+	}
+	if (reg10_value)
+		WRITE_WORD(reg10_value, fb, REG_10);
+	WRITE_WORD(0x83000300, fb, REG_14);
+	SETUP_HW(fb);
+	WRITE_BYTE(1, fb, REG_16b1);
+}
+
+static void
+START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
+{
+	SETUP_HW(fb);
+	WRITE_WORD(0xBBE0F000, fb, REG_10);
+	WRITE_WORD(0x03000300, fb, REG_14);
+	WRITE_WORD(~0, fb, REG_13);
+}
+
+static void
+WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color) 
+{
+	SETUP_HW(fb);
+	WRITE_WORD(((0x100+index)<<2), fb, REG_3);
+	WRITE_WORD(color, fb, REG_4);
+}
+
+static void
+FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb) 
+{		
+	WRITE_WORD(0x400, fb, REG_2);
+	if (fb->var.bits_per_pixel == 32) {
+		WRITE_WORD(0x83000100, fb, REG_1);
+	} else {
+		if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
+			WRITE_WORD(0x80000100, fb, REG_26);
+		else							
+			WRITE_WORD(0x80000100, fb, REG_1);
+	}
+	SETUP_FB(fb);
+}
+
+static void
+SETUP_RAMDAC(struct stifb_info *fb) 
+{
+	SETUP_HW(fb);
+	WRITE_WORD(0x04000000, fb, 0x1020);
+	WRITE_WORD(0xff000000, fb, 0x1028);
+}
+
+static void 
+CRX24_SETUP_RAMDAC(struct stifb_info *fb) 
+{
+	SETUP_HW(fb);
+	WRITE_WORD(0x04000000, fb, 0x1000);
+	WRITE_WORD(0x02000000, fb, 0x1004);
+	WRITE_WORD(0xff000000, fb, 0x1008);
+	WRITE_WORD(0x05000000, fb, 0x1000);
+	WRITE_WORD(0x02000000, fb, 0x1004);
+	WRITE_WORD(0x03000000, fb, 0x1008);
+}
+
+#if 0
+static void 
+HCRX_SETUP_RAMDAC(struct stifb_info *fb)
+{
+	WRITE_WORD(0xffffffff, fb, REG_32);
+}
+#endif
+
+static void 
+CRX24_SET_OVLY_MASK(struct stifb_info *fb)
+{
+	SETUP_HW(fb);
+	WRITE_WORD(0x13a02000, fb, REG_11);
+	WRITE_WORD(0x03000300, fb, REG_14);
+	WRITE_WORD(0x000017f0, fb, REG_3);
+	WRITE_WORD(0xffffffff, fb, REG_13);
+	WRITE_WORD(0xffffffff, fb, REG_22);
+	WRITE_WORD(0x00000000, fb, REG_23);
+}
+
+static void
+ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
+{
+	unsigned int value = enable ? 0x43000000 : 0x03000000;
+        SETUP_HW(fb);
+        WRITE_WORD(0x06000000,	fb, 0x1030);
+        WRITE_WORD(value, 	fb, 0x1038);
+}
+
+static void 
+CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
+{
+	unsigned int value = enable ? 0x10000000 : 0x30000000;
+	SETUP_HW(fb);
+	WRITE_WORD(0x01000000,	fb, 0x1000);
+	WRITE_WORD(0x02000000,	fb, 0x1004);
+	WRITE_WORD(value,	fb, 0x1008);
+}
+
+static void
+ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) 
+{
+	u32 DregsMiscVideo = REG_21;
+	u32 DregsMiscCtl = REG_27;
+	
+	SETUP_HW(fb);
+	if (enable) {
+	  WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
+	  WRITE_WORD(READ_WORD(fb, DregsMiscCtl)   | 0x00800000, fb, DregsMiscCtl);
+	} else {
+	  WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
+	  WRITE_WORD(READ_WORD(fb, DregsMiscCtl)   & ~0x00800000, fb, DregsMiscCtl);
+	}
+}
+
+#define GET_ROMTABLE_INDEX(fb) \
+	(READ_BYTE(fb, REG_16b3) - 1)
+
+#define HYPER_CONFIG_PLANES_24 0x00000100
+	
+#define IS_24_DEVICE(fb) \
+	(fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
+
+#define IS_888_DEVICE(fb) \
+	(!(IS_24_DEVICE(fb)))
+
+#define GET_FIFO_SLOTS(fb, cnt, numslots)			\
+{	while (cnt < numslots) 					\
+		cnt = READ_WORD(fb, REG_34);	\
+	cnt -= numslots;					\
+}
+
+#define	    IndexedDcd	0	/* Pixel data is indexed (pseudo) color */
+#define	    Otc04	2	/* Pixels in each longword transfer (4) */
+#define	    Otc32	5	/* Pixels in each longword transfer (32) */
+#define	    Ots08	3	/* Each pixel is size (8)d transfer (1) */
+#define	    OtsIndirect	6	/* Each bit goes through FG/BG color(8) */
+#define	    AddrLong	5	/* FB address is Long aligned (pixel) */
+#define	    BINovly	0x2	/* 8 bit overlay */
+#define	    BINapp0I	0x0	/* Application Buffer 0, Indexed */
+#define	    BINapp1I	0x1	/* Application Buffer 1, Indexed */
+#define	    BINapp0F8	0xa	/* Application Buffer 0, Fractional 8-8-8 */
+#define	    BINattr	0xd	/* Attribute Bitmap */
+#define	    RopSrc 	0x3
+#define	    BitmapExtent08  3	/* Each write hits ( 8) bits in depth */
+#define	    BitmapExtent32  5	/* Each write hits (32) bits in depth */
+#define	    DataDynamic	    0	/* Data register reloaded by direct access */
+#define	    MaskDynamic	    1	/* Mask register reloaded by direct access */
+#define	    MaskOtc	    0	/* Mask contains Object Count valid bits */
+
+#define MaskAddrOffset(offset) (offset)
+#define StaticReg(en) (en)
+#define BGx(en) (en)
+#define FGx(en) (en)
+
+#define BAJustPoint(offset) (offset)
+#define BAIndexBase(base) (base)
+#define BA(F,C,S,A,J,B,I) \
+	(((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
+
+#define IBOvals(R,M,X,S,D,L,B,F) \
+	(((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
+
+#define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
+	WRITE_WORD(val, fb, REG_14)
+
+#define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
+	WRITE_WORD(val, fb, REG_11)
+
+#define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
+	WRITE_WORD(val, fb, REG_12)
+
+#define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
+	WRITE_WORD(plnmsk32, fb, REG_13)
+
+#define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
+	WRITE_WORD(fg32, fb, REG_35)
+
+#define NGLE_SET_TRANSFERDATA(fb, val) \
+	WRITE_WORD(val, fb, REG_8)
+
+#define NGLE_SET_DSTXY(fb, val) \
+	WRITE_WORD(val, fb, REG_6)
+
+#define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) (		\
+	(u32) (fbaddrbase) +				\
+	    (	(unsigned int)  ( (y) << 13      ) |		\
+		(unsigned int)  ( (x) << 2       )	)	\
+	)
+
+#define NGLE_BINC_SET_DSTADDR(fb, addr) \
+	WRITE_WORD(addr, fb, REG_3)
+
+#define NGLE_BINC_SET_SRCADDR(fb, addr) \
+	WRITE_WORD(addr, fb, REG_2)
+
+#define NGLE_BINC_SET_DSTMASK(fb, mask) \
+	WRITE_WORD(mask, fb, REG_22)
+
+#define NGLE_BINC_WRITE32(fb, data32) \
+	WRITE_WORD(data32, fb, REG_23)
+
+#define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
+	WRITE_WORD((cmapBltCtlData32), fb, REG_38)
+
+#define SET_LENXY_START_RECFILL(fb, lenxy) \
+	WRITE_WORD(lenxy, fb, REG_9)
+
+static void
+HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
+{
+	u32 DregsHypMiscVideo = REG_33;
+	unsigned int value;
+	SETUP_HW(fb);
+	value = READ_WORD(fb, DregsHypMiscVideo);
+	if (enable)
+		value |= 0x0A000000;
+	else
+		value &= ~0x0A000000;
+	WRITE_WORD(value, fb, DregsHypMiscVideo);
+}
+
+
+/* BufferNumbers used by SETUP_ATTR_ACCESS() */
+#define BUFF0_CMAP0	0x00001e02
+#define BUFF1_CMAP0	0x02001e02
+#define BUFF1_CMAP3	0x0c001e02
+#define ARTIST_CMAP0	0x00000102
+#define HYPER_CMAP8	0x00000100
+#define HYPER_CMAP24	0x00000800
+
+static void
+SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
+{
+	SETUP_HW(fb);
+	WRITE_WORD(0x2EA0D000, fb, REG_11);
+	WRITE_WORD(0x23000302, fb, REG_14);
+	WRITE_WORD(BufferNumber, fb, REG_12);
+	WRITE_WORD(0xffffffff, fb, REG_8);
+}
+
+static void
+SET_ATTR_SIZE(struct stifb_info *fb, int width, int height) 
+{
+	WRITE_WORD(0x00000000, fb, REG_6);
+	WRITE_WORD((width<<16) | height, fb, REG_9);
+	WRITE_WORD(0x05000000, fb, REG_6);
+	WRITE_WORD(0x00040001, fb, REG_9);
+}
+
+static void
+FINISH_ATTR_ACCESS(struct stifb_info *fb) 
+{
+	SETUP_HW(fb);
+	WRITE_WORD(0x00000000, fb, REG_12);
+}
+
+static void
+elkSetupPlanes(struct stifb_info *fb)
+{
+	SETUP_RAMDAC(fb);
+	SETUP_FB(fb);
+}
+
+static void 
+ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
+{
+	SETUP_ATTR_ACCESS(fb, BufferNumber);
+	SET_ATTR_SIZE(fb, fb->var.xres, fb->var.yres);
+	FINISH_ATTR_ACCESS(fb);
+	SETUP_FB(fb);
+}
+
+
+static void
+rattlerSetupPlanes(struct stifb_info *fb)
+{
+	CRX24_SETUP_RAMDAC(fb);
+    
+	/* replacement for: SETUP_FB(fb, CRX24_OVERLAY_PLANES); */
+	WRITE_WORD(0x83000300, fb, REG_14);
+	SETUP_HW(fb);
+	WRITE_BYTE(1, fb, REG_16b1);
+
+	/* XXX: replace by fb_setmem(), smem_start or screen_base ? */
+	memset_io(fb->fix.smem_start, 0xff,
+		fb->var.yres*fb->fix.line_length);
+    
+	CRX24_SET_OVLY_MASK(fb);
+	SETUP_FB(fb);
+}
+
+
+#define HYPER_CMAP_TYPE				0
+#define NGLE_CMAP_INDEXED0_TYPE			0
+#define NGLE_CMAP_OVERLAY_TYPE			3
+
+/* typedef of LUT (Colormap) BLT Control Register */
+typedef union	/* Note assumption that fields are packed left-to-right */
+{	u32 all;
+	struct
+	{
+		unsigned enable              :  1;
+		unsigned waitBlank           :  1;
+		unsigned reserved1           :  4;
+		unsigned lutOffset           : 10;   /* Within destination LUT */
+		unsigned lutType             :  2;   /* Cursor, image, overlay */
+		unsigned reserved2           :  4;
+		unsigned length              : 10;
+	} fields;
+} NgleLutBltCtl;
+
+
+#if 0
+static NgleLutBltCtl
+setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
+{
+	NgleLutBltCtl lutBltCtl;
+
+	/* set enable, zero reserved fields */
+	lutBltCtl.all           = 0x80000000;
+	lutBltCtl.fields.length = length;
+
+	switch (fb->id) 
+	{
+	case S9000_ID_A1439A:		/* CRX24 */
+		if (fb->var.bits_per_pixel == 8) {
+			lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;
+			lutBltCtl.fields.lutOffset = 0;
+		} else {
+			lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
+			lutBltCtl.fields.lutOffset = 0 * 256;
+		}
+		break;
+		
+	case S9000_ID_ARTIST:
+		lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
+		lutBltCtl.fields.lutOffset = 0 * 256;
+		break;
+		
+	default:
+		lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
+		lutBltCtl.fields.lutOffset = 0;
+		break;
+	}
+
+	/* Offset points to start of LUT.  Adjust for within LUT */
+	lutBltCtl.fields.lutOffset += offsetWithinLut;
+
+	return lutBltCtl;
+}
+#endif
+
+static NgleLutBltCtl
+setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length) 
+{
+	NgleLutBltCtl lutBltCtl;
+
+	/* set enable, zero reserved fields */
+	lutBltCtl.all = 0x80000000;
+
+	lutBltCtl.fields.length = length;
+	lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
+
+	/* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
+	if (fb->var.bits_per_pixel == 8)
+		lutBltCtl.fields.lutOffset = 2 * 256;
+	else
+		lutBltCtl.fields.lutOffset = 0 * 256;
+
+	/* Offset points to start of LUT.  Adjust for within LUT */
+	lutBltCtl.fields.lutOffset += offsetWithinLut;
+
+	return lutBltCtl;
+}
+
+
+static void hyperUndoITE(struct stifb_info *fb)
+{
+	int nFreeFifoSlots = 0;
+	u32 fbAddr;
+
+	NGLE_LOCK(fb);
+
+	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
+	WRITE_WORD(0xffffffff, fb, REG_32);
+
+	/* Write overlay transparency mask so only entry 255 is transparent */
+
+	/* Hardware setup for full-depth write to "magic" location */
+	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
+	NGLE_QUICK_SET_DST_BM_ACCESS(fb, 
+		BA(IndexedDcd, Otc04, Ots08, AddrLong,
+		BAJustPoint(0), BINovly, BAIndexBase(0)));
+	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
+		IBOvals(RopSrc, MaskAddrOffset(0),
+		BitmapExtent08, StaticReg(0),
+		DataDynamic, MaskOtc, BGx(0), FGx(0)));
+
+	/* Now prepare to write to the "magic" location */
+	fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
+	NGLE_BINC_SET_DSTADDR(fb, fbAddr);
+	NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
+	NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
+
+	/* Finally, write a zero to clear the mask */
+	NGLE_BINC_WRITE32(fb, 0);
+
+	NGLE_UNLOCK(fb);
+}
+
+static void 
+ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
+{
+	/* FIXME! */
+}
+
+static void 
+ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
+{
+	/* FIXME! */
+}
+
+static void
+ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
+{
+	int nFreeFifoSlots = 0;
+	u32 packed_dst;
+	u32 packed_len;
+
+	NGLE_LOCK(fb);
+
+	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
+	NGLE_QUICK_SET_DST_BM_ACCESS(fb, 
+				     BA(IndexedDcd, Otc32, OtsIndirect,
+					AddrLong, BAJustPoint(0),
+					BINattr, BAIndexBase(0)));
+	NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
+	NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
+
+	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
+				       IBOvals(RopSrc, MaskAddrOffset(0),
+					       BitmapExtent08, StaticReg(1),
+					       DataDynamic, MaskOtc,
+					       BGx(0), FGx(0)));
+	packed_dst = 0;
+	packed_len = (fb->var.xres << 16) | fb->var.yres;
+	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
+	NGLE_SET_DSTXY(fb, packed_dst);
+	SET_LENXY_START_RECFILL(fb, packed_len);
+
+	/*
+	 * In order to work around an ELK hardware problem (Buffy doesn't
+	 * always flush it's buffers when writing to the attribute
+	 * planes), at least 4 pixels must be written to the attribute
+	 * planes starting at (X == 1280) and (Y != to the last Y written
+	 * by BIF):
+	 */
+
+	if (fb->id == S9000_ID_A1659A) {   /* ELK_DEVICE_ID */
+		/* It's safe to use scanline zero: */
+		packed_dst = (1280 << 16);
+		GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
+		NGLE_SET_DSTXY(fb, packed_dst);
+		packed_len = (4 << 16) | 1;
+		SET_LENXY_START_RECFILL(fb, packed_len);
+	}   /* ELK Hardware Kludge */
+
+	/**** Finally, set the Control Plane Register back to zero: ****/
+	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
+	NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
+	
+	NGLE_UNLOCK(fb);
+}
+    
+static void
+ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
+{
+	int nFreeFifoSlots = 0;
+	u32 packed_dst;
+	u32 packed_len;
+    
+	NGLE_LOCK(fb);
+
+	/* Hardware setup */
+	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
+	NGLE_QUICK_SET_DST_BM_ACCESS(fb, 
+				     BA(IndexedDcd, Otc04, Ots08, AddrLong,
+					BAJustPoint(0), BINovly, BAIndexBase(0)));
+
+        NGLE_SET_TRANSFERDATA(fb, 0xffffffff);  /* Write foreground color */
+
+        NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
+        NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
+    
+        packed_dst = 0;
+        packed_len = (fb->var.xres << 16) | fb->var.yres;
+        NGLE_SET_DSTXY(fb, packed_dst);
+    
+        /* Write zeroes to overlay planes */		       
+	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
+				       IBOvals(RopSrc, MaskAddrOffset(0),
+					       BitmapExtent08, StaticReg(0),
+					       DataDynamic, MaskOtc, BGx(0), FGx(0)));
+		       
+        SET_LENXY_START_RECFILL(fb, packed_len);
+
+	NGLE_UNLOCK(fb);
+}
+
+static void 
+hyperResetPlanes(struct stifb_info *fb, int enable)
+{
+	unsigned int controlPlaneReg;
+
+	NGLE_LOCK(fb);
+
+	if (IS_24_DEVICE(fb))
+		if (fb->var.bits_per_pixel == 32)
+			controlPlaneReg = 0x04000F00;
+		else
+			controlPlaneReg = 0x00000F00;   /* 0x00000800 should be enought, but lets clear all 4 bits */
+	else
+		controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */
+
+	switch (enable) {
+	case 1:		/* ENABLE */
+		/* clear screen */
+		if (IS_24_DEVICE(fb))
+			ngleDepth24_ClearImagePlanes(fb);
+		else
+			ngleDepth8_ClearImagePlanes(fb);
+
+		/* Paint attribute planes for default case.
+		 * On Hyperdrive, this means all windows using overlay cmap 0. */
+		ngleResetAttrPlanes(fb, controlPlaneReg);
+
+		/* clear overlay planes */
+	        ngleClearOverlayPlanes(fb, 0xff, 255);
+
+		/**************************************************
+		 ** Also need to counteract ITE settings 
+		 **************************************************/
+		hyperUndoITE(fb);
+		break;
+
+	case 0:		/* DISABLE */
+		/* clear screen */
+		if (IS_24_DEVICE(fb))
+			ngleDepth24_ClearImagePlanes(fb);
+		else
+			ngleDepth8_ClearImagePlanes(fb);
+		ngleResetAttrPlanes(fb, controlPlaneReg);
+		ngleClearOverlayPlanes(fb, 0xff, 0);
+		break;
+
+	case -1:	/* RESET */
+		hyperUndoITE(fb);
+		ngleResetAttrPlanes(fb, controlPlaneReg);
+		break;
+    	}
+	
+	NGLE_UNLOCK(fb);
+}
+
+/* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
+
+static void 
+ngleGetDeviceRomData(struct stifb_info *fb)
+{
+#if 0
+XXX: FIXME: !!!
+	int	*pBytePerLongDevDepData;/* data byte == LSB */
+	int 	*pRomTable;
+	NgleDevRomData	*pPackedDevRomData;
+	int	sizePackedDevRomData = sizeof(*pPackedDevRomData);
+	char	*pCard8;
+	int	i;
+	char	*mapOrigin = NULL;
+    
+	int romTableIdx;
+
+	pPackedDevRomData = fb->ngle_rom;
+
+	SETUP_HW(fb);
+	if (fb->id == S9000_ID_ARTIST) {
+		pPackedDevRomData->cursor_pipeline_delay = 4;
+		pPackedDevRomData->video_interleaves     = 4;
+	} else {
+		/* Get pointer to unpacked byte/long data in ROM */
+		pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];
+
+		/* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */
+		if (fb->id == S9000_ID_TOMCAT)
+	{
+	    /*  jump to the correct ROM table  */
+	    GET_ROMTABLE_INDEX(romTableIdx);
+	    while  (romTableIdx > 0)
+	    {
+		pCard8 = (Card8 *) pPackedDevRomData;
+		pRomTable = pBytePerLongDevDepData;
+		/* Pack every fourth byte from ROM into structure */
+		for (i = 0; i < sizePackedDevRomData; i++)
+		{
+		    *pCard8++ = (Card8) (*pRomTable++);
+		}
+
+		pBytePerLongDevDepData = (Card32 *)
+			((Card8 *) pBytePerLongDevDepData +
+			       pPackedDevRomData->sizeof_ngle_data);
+
+		romTableIdx--;
+	    }
+	}
+
+	pCard8 = (Card8 *) pPackedDevRomData;
+
+	/* Pack every fourth byte from ROM into structure */
+	for (i = 0; i < sizePackedDevRomData; i++)
+	{
+	    *pCard8++ = (Card8) (*pBytePerLongDevDepData++);
+	}
+    }
+
+    SETUP_FB(fb);
+#endif
+}
+
+
+#define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES	4
+#define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE	8
+#define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE		10
+#define HYPERBOWL_MODE2_8_24					15
+
+/* HCRX specific boot-time initialization */
+static void __init
+SETUP_HCRX(struct stifb_info *fb)
+{
+	int	hyperbowl;
+        int	nFreeFifoSlots = 0;
+
+	if (fb->id != S9000_ID_HCRX)
+		return;
+
+	/* Initialize Hyperbowl registers */
+	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
+	
+	if (IS_24_DEVICE(fb)) {
+		hyperbowl = (fb->var.bits_per_pixel == 32) ?
+			HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
+			HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
+
+		/* First write to Hyperbowl must happen twice (bug) */
+		WRITE_WORD(hyperbowl, fb, REG_40);
+		WRITE_WORD(hyperbowl, fb, REG_40);
+		
+		WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);
+		
+		WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */
+		WRITE_WORD(0x404c4048, fb, REG_43);
+		WRITE_WORD(0x034c0348, fb, REG_44);
+		WRITE_WORD(0x444c4448, fb, REG_45);
+	} else {
+		hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;
+
+		/* First write to Hyperbowl must happen twice (bug) */
+		WRITE_WORD(hyperbowl, fb, REG_40);
+		WRITE_WORD(hyperbowl, fb, REG_40);
+
+		WRITE_WORD(0x00000000, fb, REG_42);
+		WRITE_WORD(0x00000000, fb, REG_43);
+		WRITE_WORD(0x00000000, fb, REG_44);
+		WRITE_WORD(0x444c4048, fb, REG_45);
+	}
+}
+
+
+/* ------------------- driver specific functions --------------------------- */
+
+static int
+stifb_getcolreg(u_int regno, u_int *red, u_int *green,
+	      u_int *blue, u_int *transp, struct fb_info *info)
+{
+	struct stifb_info *fb = (struct stifb_info *) info;
+
+	if (regno > 255)
+		return 1;
+	*red = (fb->palette[regno].red<<8) | fb->palette[regno].red;
+	*green = (fb->palette[regno].green<<8) | fb->palette[regno].green;
+	*blue = (fb->palette[regno].blue<<8) | fb->palette[regno].blue;
+	*transp = 0;
+
+	return 0;
+}
+
+static int
+stifb_setcolreg(u_int regno, u_int red, u_int green,
+	      u_int blue, u_int transp, struct fb_info *info)
+{
+	struct stifb_info *fb = (struct stifb_info *) info;
+
+	if (regno > 255)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+	
+	if ((fb->palette[regno].red != red) ||
+	    (fb->palette[regno].green != green) ||
+	    (fb->palette[regno].blue != blue))
+		fb->cmap_reload = 1;
+	    
+	fb->palette[regno].red = red;
+	fb->palette[regno].green = green;
+	fb->palette[regno].blue = blue;
+    
+#ifdef FBCON_HAS_CFB32
+	if (regno < 16 && fb->var.bits_per_pixel == 32) {
+		fb->fbcon_cmap.cfb32[regno] = ((red << 16) |
+					       (green << 8) |
+					       (blue << 0) |
+					       (transp << 24));
+	}
+#endif
+	return 0;
+}
+
+static void
+stifb_loadcmap(struct stifb_info *fb)
+{
+	u32 color;
+	int i;
+
+	if (!fb->cmap_reload)
+		return;
+
+	START_IMAGE_COLORMAP_ACCESS(fb);
+	for (i = 0; i < 256; i++) {
+		if (fb->var.bits_per_pixel > 8) {
+			color = (i << 16) | (i << 8) | i;
+		} else {
+			if (fb->var.grayscale) {
+				/* gray = 0.30*R + 0.59*G + 0.11*B */
+				color = ((fb->palette[i].red * 77) +
+					 (fb->palette[i].green * 151) +
+					 (fb->palette[i].blue * 28)) >> 8;
+			} else {
+				color = ((fb->palette[i].red << 16) |
+					 (fb->palette[i].green << 8) |
+					 (fb->palette[i].blue));
+			}
+		}
+		WRITE_IMAGE_COLOR(fb, i, color);
+	}
+	if (fb->id == S9000_ID_HCRX) {
+		NgleLutBltCtl lutBltCtl;
+
+		lutBltCtl = setHyperLutBltCtl(fb,
+				0,	/* Offset w/i LUT */
+				256);	/* Load entire LUT */
+		NGLE_BINC_SET_SRCADDR(fb,
+				NGLE_LONG_FB_ADDRESS(0, 0x100, 0)); 
+				/* 0x100 is same as used in WRITE_IMAGE_COLOR() */
+		START_COLORMAPLOAD(fb, lutBltCtl.all);
+		SETUP_FB(fb);
+	} else {
+		/* cleanup colormap hardware */
+		FINISH_IMAGE_COLORMAP_ACCESS(fb);
+	}
+	fb->cmap_reload = 0;
+}
+
+static int
+stifb_get_fix(struct fb_fix_screeninfo *fix, int con,
+	      struct fb_info *info)
+{
+	memcpy (fix, &((struct stifb_info *)info)->fix, sizeof (*fix));
+	return 0;
+}
+
+static int
+stifb_get_var(struct fb_var_screeninfo *var, int con,
+	      struct fb_info *info)
+{
+	memcpy (var, &((struct stifb_info *)info)->var, sizeof (*var));
+	return 0;
+}
+
+static int
+stifb_set_var(struct fb_var_screeninfo *var, int con,
+	      struct fb_info *info)
+{
+	struct display *disp;
+	
+	if (con >= 0)
+		disp = &fb_display[con];
+	else
+		disp = info->disp;
+
+	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+		if (disp->var.xres != var->xres ||
+		    disp->var.yres != var->yres ||
+		    disp->var.xres_virtual != var->xres_virtual ||
+		    disp->var.yres_virtual != var->yres_virtual ||
+		    disp->var.bits_per_pixel != var->bits_per_pixel ||
+		    disp->var.accel_flags != var->accel_flags)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+stifb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+	       struct fb_info *info)
+{
+	struct stifb_info *fb = (struct stifb_info *)info;
+	
+	if (con == fb->currcon) /* current console ? */
+		return fb_get_cmap(cmap, kspc, stifb_getcolreg, info);
+	else if (fb_display[con].cmap.len) /* non default colormap ? */
+		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+	else
+		fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel > 8 ? 16 : 256), cmap, kspc ? 0: 2);
+	return 0;
+}
+
+static int
+stifb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+	       struct fb_info *info)
+{
+	struct stifb_info *fb = (struct stifb_info *)info;
+	struct display *disp;
+	int err;
+	
+	if (con >= 0)
+		disp = &fb_display[con];
+	else
+		disp = info->disp;
+
+	if (!disp->cmap.len) { /* no colormap allocated ? */
+		if ((err = fb_alloc_cmap(&disp->cmap, disp->var.bits_per_pixel > 8 ? 16 : 256, 0)))
+			return err;
+	}
+	if (con == fb->currcon || con == -1) {
+		err = fb_set_cmap(cmap, kspc, stifb_setcolreg, info);
+		if (!err)
+			stifb_loadcmap ((struct stifb_info *)info);
+		return err;
+	} else
+		fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
+	return 0;
+}
+					 
+static void
+stifb_blank(int blank_mode, struct fb_info *info)
+{
+	struct stifb_info *fb = (struct stifb_info *) info;
+	int enable = (blank_mode == 0) ? ENABLE : DISABLE;
+
+	switch (fb->id) {
+	case S9000_ID_A1439A:
+		CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
+		break;
+	case CRT_ID_VISUALIZE_EG:
+	case S9000_ID_ARTIST:
+		ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
+		break;
+	case S9000_ID_HCRX:
+		HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
+		break;
+	case S9000_ID_A1659A:;	/* fall through */
+	case S9000_ID_TIMBER:;
+	case CRX24_OVERLAY_PLANES:;
+	default:
+		ENABLE_DISABLE_DISPLAY(fb, enable);
+		break;
+	}
+	
+	SETUP_FB(fb);
+}
+
+static void
+stifb_set_disp(struct stifb_info *fb)
+{
+	int id = fb->id;
+
+	SETUP_FB(fb);
+
+	/* HCRX specific initialization */
+	SETUP_HCRX(fb);
+	
+	/*
+	if (id == S9000_ID_HCRX)
+		hyperInitSprite(fb);
+	else
+		ngleInitSprite(fb);
+	*/
+	
+	/* Initialize the image planes. */ 
+        switch (id) {
+	 case S9000_ID_HCRX:
+	    hyperResetPlanes(fb, ENABLE);
+	    break;
+	 case S9000_ID_A1439A:
+	    rattlerSetupPlanes(fb);
+	    break;
+	 case S9000_ID_A1659A:
+	 case S9000_ID_ARTIST:
+	 case CRT_ID_VISUALIZE_EG:
+	    elkSetupPlanes(fb);
+	    break;
+	}
+
+	/* Clear attribute planes on non HCRX devices. */
+        switch (id) {
+	 case S9000_ID_A1659A:
+	 case S9000_ID_A1439A:
+	    if (fb->var.bits_per_pixel == 32)
+		ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
+	    else {
+		ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
+	    }
+	    if (id == S9000_ID_A1439A)
+		ngleClearOverlayPlanes(fb, 0xff, 0);
+	    break;
+	 case S9000_ID_ARTIST:
+	 case CRT_ID_VISUALIZE_EG:
+	    if (fb->var.bits_per_pixel == 32)
+		ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
+	    else {
+		ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
+	    }
+	    break;
+	}
+	stifb_blank(0, (struct fb_info *)fb);	/* 0=enable screen */
+
+	SETUP_FB(fb);
+}
+
+static int
+stifb_switch(int con, struct fb_info *info)
+{
+	struct stifb_info *fb = (struct stifb_info *)info;
+	
+	/* Do we have to save the colormap ? */
+	if (fb->currcon != -1 && fb_display[fb->currcon].cmap.len)
+		fb_get_cmap(&fb_display[fb->currcon].cmap, 1, stifb_getcolreg, info);
+
+	fb->currcon = con;
+	/* Install new colormap */
+	if (fb_display[con].cmap.len)
+		fb_set_cmap(&fb_display[con].cmap, 1, stifb_setcolreg, info);
+	else
+		fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel > 8 ? 16 : 256),
+			    1, stifb_setcolreg, info);
+	stifb_loadcmap ((struct stifb_info *)info);
+	return 0;
+}
+
+static int
+stifb_update_var(int con, struct fb_info *info)
+{
+	return 0;
+}
+
+/* ------------ Interfaces to hardware functions ------------ */
+
+static struct fb_ops stifb_ops = {
+	owner:		THIS_MODULE,
+	fb_get_fix:	stifb_get_fix,
+	fb_get_var:	stifb_get_var,
+	fb_set_var:	stifb_set_var,
+	fb_get_cmap:	stifb_get_cmap,
+	fb_set_cmap:	stifb_set_cmap,
+//	fb_pan_display:	fbgen_pan_display,
+//	fb_ioctl:       xxxfb_ioctl,   /* optional */      
+};
+
+
+    /*
+     *  Initialization
+     */
+
+int __init
+stifb_init_fb(struct sti_struct *sti, int force_bpp)
+{
+	struct fb_fix_screeninfo *fix;
+	struct fb_var_screeninfo *var;
+	struct display *disp;
+	struct stifb_info *fb;
+	unsigned long sti_rom_address;
+	char *dev_name;
+	int bpp, xres, yres;
+
+	fb = kmalloc(sizeof(struct stifb_info), GFP_ATOMIC);
+	if (!fb) {
+		printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
+		return -ENODEV;
+	}
+	
+	/* set struct to a known state */
+	memset(fb, 0, sizeof(struct stifb_info));
+	fix = &fb->fix;
+	var = &fb->var;
+	disp = &fb->disp;
+
+	fb->currcon = -1;
+	fb->cmap_reload = 1;
+	fb->sti = sti;
+	/* store upper 32bits of the graphics id */
+	fb->id = fb->sti->graphics_id[0];
+	fb->real_id = fb->id;	/* save the real id */
+
+	/* only supported cards are allowed */
+	switch (fb->id) {
+	case S9000_ID_ARTIST:
+	case S9000_ID_HCRX:
+	case S9000_ID_TIMBER:
+	case S9000_ID_A1659A:
+	case S9000_ID_A1439A:
+	case CRT_ID_VISUALIZE_EG:
+		break;
+	default:
+		printk(KERN_WARNING "stifb: Unsupported gfx card id 0x%08x\n",
+			fb->id);
+		goto out_err1;
+	}
+	
+	/* default to 8 bpp on most graphic chips */
+	bpp = 8;
+	xres = sti_onscreen_x(fb->sti);
+	yres = sti_onscreen_y(fb->sti);
+
+	ngleGetDeviceRomData(fb);
+
+	/* get (virtual) io region base addr */
+	fix->mmio_start = REGION_BASE(fb,2);
+	fix->mmio_len   = 0x400000;
+
+       	/* Reject any device not in the NGLE family */
+	switch (fb->id) {
+	case S9000_ID_A1659A:	/* CRX/A1659A */
+		break;
+	case S9000_ID_ELM:	/* GRX, grayscale but else same as A1659A */
+		var->grayscale = 1;
+		fb->id = S9000_ID_A1659A;
+		break;
+	case S9000_ID_TIMBER:	/* HP9000/710 Any (may be a grayscale device) */
+		dev_name = fb->sti->outptr.dev_name;
+		if (strstr(dev_name, "GRAYSCALE") || 
+		    strstr(dev_name, "Grayscale") ||
+		    strstr(dev_name, "grayscale"))
+			var->grayscale = 1;
+		break;
+	case S9000_ID_TOMCAT:	/* Dual CRX, behaves else like a CRX */
+		/* FIXME: TomCat supports two heads:
+		 * fb.iobase = REGION_BASE(fb_info,3);
+		 * fb.screen_base = (void*) REGION_BASE(fb_info,2);
+		 * for now we only support the left one ! */
+		xres = fb->ngle_rom.x_size_visible;
+		yres = fb->ngle_rom.y_size_visible;
+		fb->id = S9000_ID_A1659A;
+		break;
+	case S9000_ID_A1439A:	/* CRX24/A1439A */
+		bpp = 32;
+		break;
+	case S9000_ID_HCRX:	/* Hyperdrive/HCRX */
+		memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
+		if ((fb->sti->regions_phys[0] & 0xfc000000) ==
+		    (fb->sti->regions_phys[2] & 0xfc000000))
+			sti_rom_address = fb->sti->regions_phys[0];
+		else
+			sti_rom_address = fb->sti->regions_phys[1];
+#ifdef __LP64__
+	        sti_rom_address |= 0xffffffff00000000;
+#endif
+		fb->deviceSpecificConfig = __raw_readl(sti_rom_address);
+		if (IS_24_DEVICE(fb)) {
+			if (force_bpp == 8 || force_bpp == 32)
+				bpp = force_bpp;
+			else
+				bpp = 32;
+		} else
+			bpp = 8;
+		READ_WORD(fb, REG_15);
+		SETUP_HW(fb);
+		break;
+	case CRT_ID_VISUALIZE_EG:
+	case S9000_ID_ARTIST:	/* Artist */
+		break;
+	default: 
+#ifdef FALLBACK_TO_1BPP
+	       	printk(KERN_WARNING 
+			"stifb: Unsupported graphics card (id=0x%08x) "
+				"- now trying 1bpp mode instead\n",
+			fb->id);
+		bpp = 1;	/* default to 1 bpp */
+		break;
+#else
+	       	printk(KERN_WARNING 
+			"stifb: Unsupported graphics card (id=0x%08x) "
+				"- skipping.\n",
+			fb->id);
+		goto out_err1;
+#endif
+	}
+
+
+	/* get framebuffer pysical and virtual base addr & len (64bit ready) */
+	fix->smem_start = fb->sti->regions_phys[1] | 0xffffffff00000000;
+	fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
+
+	fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
+	if (!fix->line_length)
+		fix->line_length = 2048; /* default */
+	fix->accel = FB_ACCEL_NONE;
+
+	switch (bpp) {
+	    case 1:
+		fix->type = FB_TYPE_PLANES;	/* well, sort of */
+		fix->visual = FB_VISUAL_MONO10;
+		disp->dispsw = &fbcon_sti;
+		break;
+#ifdef FBCON_HAS_CFB8		
+	    case 8:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	 	disp->dispsw = &fbcon_cfb8;
+		var->red.length = var->green.length = var->blue.length = 8;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	    case 32:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->visual = FB_VISUAL_TRUECOLOR;
+		disp->dispsw = &fbcon_cfb32;
+		disp->dispsw_data = fb->fbcon_cmap.cfb32;
+		var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
+		var->blue.offset = 0;
+		var->green.offset = 8;
+		var->red.offset = 16;
+		var->transp.offset = 24;
+		break;
+#endif
+	    default:
+		disp->dispsw = &fbcon_dummy;
+		break;
+	}
+	
+	var->xres = var->xres_virtual = xres;
+	var->yres = var->yres_virtual = yres;
+	var->bits_per_pixel = bpp;
+
+	disp->var = *var;
+	disp->visual = fix->visual;
+	disp->type = fix->type;
+	disp->type_aux = fix->type_aux;
+	disp->line_length = fix->line_length;
+	disp->var.activate = FB_ACTIVATE_NOW;
+	disp->screen_base = (void*) REGION_BASE(fb,1);
+	disp->can_soft_blank = 1;
+	disp->scrollmode = SCROLL_YREDRAW;
+	
+	strcpy(fb->info.modename, "stifb");
+	fb->info.node = -1;
+	fb->info.flags = FBINFO_FLAG_DEFAULT;
+	fb->info.fbops = &stifb_ops;
+	fb->info.disp = disp;
+	fb->info.changevar = NULL;
+	fb->info.switch_con = &stifb_switch;
+	fb->info.updatevar = &stifb_update_var;
+	fb->info.blank = &stifb_blank;
+	fb->info.flags = FBINFO_FLAG_DEFAULT;
+	
+	stifb_set_var(&disp->var, 1, &fb->info);
+	
+	stifb_set_disp(fb);
+
+	if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb")) {
+		printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
+				fix->smem_start, fix->smem_start+fix->smem_len);
+		goto out_err1;
+	}
+		
+	if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
+		printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
+				fix->mmio_start, fix->mmio_start+fix->mmio_len);
+		goto out_err2;
+	}
+
+	if (register_framebuffer(&fb->info) < 0)
+		goto out_err3;
+
+	printk(KERN_INFO 
+	    "fb%d: %s %dx%d-%d frame buffer device, id: %04x, mmio: 0x%04lx\n",
+		GET_FB_IDX(fb->info.node), 
+		fb->info.modename,
+		disp->var.xres, 
+		disp->var.yres,
+		disp->var.bits_per_pixel,
+		fb->id, 
+		fix->mmio_start);
+
+	return 0;
+
+
+out_err3:
+	release_mem_region(fix->mmio_start, fix->mmio_len);
+out_err2:
+	release_mem_region(fix->smem_start, fix->smem_len);
+out_err1:
+	kfree(fb);
+	return -ENXIO;
+}
+
+int __init
+stifb_init(void)
+{
+	struct sti_struct *sti;
+	int i;
+	
+	
+	if (sti_init_roms() == NULL)
+		return -ENXIO; /* no STI cards available */
+
+	for (i = 0; i < MAX_STI_ROMS; i++) {
+		sti = sti_get_rom(i);
+		if (sti)
+			stifb_init_fb (sti, stifb_force_bpp[i]);
+		else
+			break;
+	}
+	return 0;
+}
+
+/*
+ *  Cleanup
+ */
+
+void __exit
+stifb_cleanup(struct fb_info *info)
+{
+	// unregister_framebuffer(info); 
+}
+
+int __init
+stifb_setup(char *options)
+{
+	int i;
+	
+	if (!options || !*options)
+		return 0;
+	
+	if (strncmp(options, "bpp", 3) == 0) {
+		options += 3;
+		for (i = 0; i < MAX_STI_ROMS; i++) {
+			if (*options++ == ':')
+				stifb_force_bpp[i] = simple_strtoul(options, &options, 10);
+			else
+				break;
+		}
+	}
+	return 0;
+}
+
+__setup("stifb=", stifb_setup);
+
+#ifdef MODULE
+module_init(stifb_init);
+#endif
+module_exit(stifb_cleanup);
+
+MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
+MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(bpp, "i");
+MODULE_PARM_DESC(mem, "Bits per pixel (default: 8)");
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sti-bmode.h linux-2.4.20/drivers/video/sti-bmode.h
--- linux-2.4.19/drivers/video/sti-bmode.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/drivers/video/sti-bmode.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,287 +0,0 @@
-#define STI_REGION_MAX 8
-#define STI_DEV_NAME_LENGTH 32
-
-typedef struct {
-	 u8 res[3];
-	 u8 data;
-} __attribute__((packed)) sti_u8;
-
-typedef struct {
-	sti_u8 data[2];
-} __attribute__((packed)) sti_u16;
-
-typedef struct {
-	sti_u8 data[4];
-} __attribute__((packed)) sti_u32;
-
-#define  STI_U8( u8) ((u8).data)
-#define STI_U16(u16) ((STI_U8((u16).data[0])<<8) | STI_U8((u16).data[1]))
-#define STI_U32(u32) ((STI_U8((u32).data[0])<<24) | \
-		      (STI_U8((u32).data[1])<<16) | \
-		      (STI_U8((u32).data[2])<< 8) | \
-		      (STI_U8((u32).data[3])<< 0))
-
-struct sti_rom_region {
-	sti_u32 region;
-};
-
-struct sti_rom_font {
-	sti_u16 first_char;
-	sti_u16 last_char;
-	 sti_u8 width;
-	 sti_u8 height;
-	 sti_u8 font_type;
-	 sti_u8 bytes_per_char;
-	sti_u32 next_font;
-	 sti_u8 underline_height;
-	 sti_u8 underline_pos;
-	 sti_u8 res008[2];
-};
-
-struct sti_rom {
-	 sti_u8 type;
-	 sti_u8 num_mons;
-	 sti_u8 revno[2];
-
-	 sti_u8 graphics_id[8];			/* 0x010 */
-
-	sti_u32 font_start;			/* 0x030 */
-	sti_u32 statesize;
-	sti_u32 last_addr;
-	sti_u32 region_list;
-
-	sti_u16 reentsize;			/* 0x070 */
-	sti_u16 maxtime;
-	sti_u32 mon_tbl_addr;
-	sti_u32 user_data_addr;
-	sti_u32 sti_mem_req;
-
-	sti_u32 user_data_size;			/* 0x0b0 */
-	sti_u16 power;				/* 0x0c0 */
-	 sti_u8 bus_support;
-	 sti_u8 ext_bus_support;
-	 sti_u8 alt_code_type;			/* 0x0d0 */
-	 sti_u8 ext_dd_struct[3];
-	sti_u32 cfb_addr;			/* 0x0e0 */
-	
-	 sti_u8 res0f0[4];			
-
-	sti_u32 init_graph;		/* 0x0e0 */
-	sti_u32 state_mgmt;
-	sti_u32 font_unpmv;
-	sti_u32 block_move;
-	sti_u32 self_test;
-	sti_u32 excep_hdlr;
-	sti_u32 inq_conf;
-	sti_u32 set_cm_entry;
-	sti_u32 dma_ctrl;
-	sti_u32 flow_ctrl;
-	sti_u32 user_timing;
-	sti_u32 process_mgr;
-	sti_u32 sti_util;
-	sti_u32 end_addr;
-	sti_u32 res0b8;
-	sti_u32 res0bc;
-
-	sti_u32 init_graph_m68k;		/* 0x0e0 */
-	sti_u32 state_mgmt_m68k;
-	sti_u32 font_unpmv_m68k;
-	sti_u32 block_move_m68k;
-	sti_u32 self_test_m68k;
-	sti_u32 excep_hdlr_m68k;
-	sti_u32 inq_conf_m68k;
-	sti_u32 set_cm_entry_m68k;
-	sti_u32 dma_ctrl_m68k;
-	sti_u32 flow_ctrl_m68k;
-	sti_u32 user_timing_m68k;
-	sti_u32 process_mgr_m68k;
-	sti_u32 sti_util_m68k;
-	sti_u32 end_addr_m68k;
-	sti_u32 res0b8_m68k;
-	sti_u32 res0bc_m68k;
-
-	 sti_u8 res040[7 * 4];
-};
-	
-struct sti_cooked_font {
-	struct sti_rom_font *raw;
-	struct sti_cooked_font *next_font;
-};
-
-struct sti_cooked_rom {
-	struct sti_rom *raw;
-	struct sti_cooked_font *font_start;
-	u32 *region_list;
-};
-
-struct sti_glob_cfg_ext {
-	 u8 curr_mon;
-	 u8 friendly_boot;
-	s16 power;
-	s32 freq_ref;
-	s32 *sti_mem_addr;
-	s32 *future_ptr;
-};
-
-struct sti_glob_cfg {
-	s32 text_planes;
-	s16 onscreen_x;
-	s16 onscreen_y;
-	s16 offscreen_x;
-	s16 offscreen_y;
-	s16 total_x;
-	s16 total_y;
-	u32 region_ptrs[STI_REGION_MAX];
-	s32 reent_lvl;
-	s32 *save_addr;
-	struct sti_glob_cfg_ext *ext_ptr;
-};
-
-struct sti_init_flags {
-	u32 wait : 1;
-	u32 reset : 1;
-	u32 text : 1;
-	u32 nontext : 1;
-	u32 clear : 1;
-	u32 cmap_blk : 1;
-	u32 enable_be_timer : 1;
-	u32 enable_be_int : 1;
-	u32 no_chg_tx : 1;
-	u32 no_chg_ntx : 1;
-	u32 no_chg_bet : 1;
-	u32 no_chg_bei : 1;
-	u32 init_cmap_tx : 1;
-	u32 cmt_chg : 1;
-	u32 retain_ie : 1;
-	u32 pad : 17;
-
-	s32 *future_ptr;
-};
-
-struct sti_init_inptr_ext {
-	u8  config_mon_type;
-	u8  pad[1];
-	u16 inflight_data;
-	s32 *future_ptr;
-};
-
-struct sti_init_inptr {
-	s32 text_planes;
-	struct sti_init_inptr_ext *ext_ptr;
-};
-
-struct sti_init_outptr {
-	s32 errno;
-	s32 text_planes;
-	s32 *future_ptr;
-};
-
-struct sti_conf_flags {
-	u32 wait : 1;
-	u32 pad : 31;
-	s32 *future_ptr;
-};
-
-struct sti_conf_inptr {
-	s32 *future_ptr;
-};
-
-struct sti_conf_outptr_ext {
-	u32 crt_config[3];
-	u32 crt_hdw[3];
-	s32 *future_ptr;
-};
-
-struct sti_conf_outptr {
-	s32 errno;
-	s16 onscreen_x;
-	s16 onscreen_y;
-	s16 offscreen_x;
-	s16 offscreen_y;
-	s16 total_x;
-	s16 total_y;
-	s32 bits_per_pixel;
-	s32 bits_used;
-	s32 planes;
-	 u8 dev_name[STI_DEV_NAME_LENGTH];
-	u32 attributes;
-	struct sti_conf_outptr_ext *ext_ptr;
-};
-
-
-struct sti_font_inptr {
-	u32 font_start_addr;
-	s16 index;
-	u8 fg_color;
-	u8 bg_color;
-	s16 dest_x;
-	s16 dest_y;
-	s32 *future_ptr;
-};
-
-struct sti_font_flags {
-	u32 wait : 1;
-	u32 non_text : 1;
-	u32 pad : 30;
-
-	s32 *future_ptr;
-};
-	
-struct sti_font_outptr {
-	s32 errno;
-	s32 *future_ptr;
-};
-
-struct sti_blkmv_flags {
-	u32 wait : 1;
-	u32 color : 1;
-	u32 clear : 1;
-	u32 non_text : 1;
-	u32 pad : 28;
-	s32 *future_ptr;
-};
-
-struct sti_blkmv_inptr {
-	u8 fg_color;
-	u8 bg_color;
-	s16 src_x;
-	s16 src_y;
-	s16 dest_x;
-	s16 dest_y;
-	s16 width;
-	s16 height;
-	s32 *future_ptr;
-};
-
-struct sti_blkmv_outptr {
-	s32 errno;
-	s32 *future_ptr;
-};
-
-struct sti_struct {
-	spinlock_t lock;
-
-	struct sti_cooked_rom *rom;
-
-	unsigned long font_unpmv;
-	unsigned long block_move;
-	unsigned long init_graph;
-	unsigned long inq_conf;
-
-	struct sti_glob_cfg *glob_cfg;
-	struct sti_rom_font *font;
-
-	s32 text_planes;
-
-	char **mon_strings;
-	u32 *regions;
-	 u8 *pci_regions;
-};
-
-#define STI_CALL(func, flags, inptr, outptr, glob_cfg) \
-	({	 						\
-		real32_call( func, (unsigned long)STI_PTR(flags), \
-				    STI_PTR(inptr), STI_PTR(outptr), \
-				    glob_cfg); \
-	})
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sti.h linux-2.4.20/drivers/video/sti.h
--- linux-2.4.19/drivers/video/sti.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/drivers/video/sti.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,289 +0,0 @@
-#define STI_REGION_MAX 8
-#define STI_DEV_NAME_LENGTH 32
-
-struct sti_rom_font {
-	u16 first_char;
-	u16 last_char;
-	 u8 width;
-	 u8 height;
-	 u8 font_type;
-	 u8 bytes_per_char;
-	u32 next_font;
-	 u8 underline_height;
-	 u8 underline_pos;
-	 u8 res008[2];
-};
-
-struct sti_rom {
-	 u8 type[4];
-	 u8 res004;
-	 u8 num_mons;
-	 u8 revno[2];
-	 u8 graphics_id[8];
-
-	u32 font_start;
-	u32 statesize;
-	u32 last_addr;
-	u32 region_list;
-
-	u16 reentsize;
-	u16 maxtime;
-	u32 mon_tbl_addr;
-	u32 user_data_addr;
-	u32 sti_mem_req;
-
-	u32 user_data_size;
-	u16 power;
-	 u8 bus_support;
-	 u8 ext_bus_support;
-	 u8 alt_code_type;
-	 u8 ext_dd_struct[3];
-	u32 cfb_addr;
-	
-	u32 init_graph;
-	u32 state_mgmt;
-	u32 font_unpmv;
-	u32 block_move;
-	u32 self_test;
-	u32 excep_hdlr;
-	u32 inq_conf;
-	u32 set_cm_entry;
-	u32 dma_ctrl;
-	 u8 res040[7 * 4];
-	
-	u32 init_graph_m68k;
-	u32 flow_ctrl;
-	u32 user_timing;
-	u32 process_mgr;
-	u32 sti_util;
-	u32 end_addr;
-	u32 res0b8;
-	u32 res0bc;
-};
-	
-struct sti_cooked_font {
-	struct sti_rom_font *raw;
-	struct sti_cooked_font *next_font;
-};
-
-struct sti_cooked_rom {
-	struct sti_rom *raw;
-	struct sti_cooked_font *font_start;
-	u32 *region_list;
-};
-
-struct sti_glob_cfg_ext {
-	u8  curr_mon;
-	u8  friendly_boot;
-	s16 power;
-	s32 freq_ref;
-	s32 *sti_mem_addr;
-	s32 *future_ptr;
-};
-
-struct sti_glob_cfg {
-	s32 text_planes;
-	s16 onscreen_x;
-	s16 onscreen_y;
-	s16 offscreen_x;
-	s16 offscreen_y;
-	s16 total_x;
-	s16 total_y;
-	u32 region_ptrs[STI_REGION_MAX];
-	s32 reent_lvl;
-	s32 *save_addr;
-	struct sti_glob_cfg_ext *ext_ptr;
-};
-
-struct sti_init_flags {
-	u32 wait : 1;
-	u32 reset : 1;
-	u32 text : 1;
-	u32 nontext : 1;
-	u32 clear : 1;
-	u32 cmap_blk : 1;
-	u32 enable_be_timer : 1;
-	u32 enable_be_int : 1;
-	u32 no_chg_tx : 1;
-	u32 no_chg_ntx : 1;
-	u32 no_chg_bet : 1;
-	u32 no_chg_bei : 1;
-	u32 init_cmap_tx : 1;
-	u32 cmt_chg : 1;
-	u32 retain_ie : 1;
-	u32 pad : 17;
-
-	s32 *future_ptr;
-};
-
-struct sti_init_inptr_ext {
-	u8  config_mon_type;
-	u8  pad[1];
-	u16 inflight_data;
-	s32 *future_ptr;
-};
-
-struct sti_init_inptr {
-	s32 text_planes;
-	struct sti_init_inptr_ext *ext_ptr;
-};
-
-struct sti_init_outptr {
-	s32 errno;
-	s32 text_planes;
-	s32 *future_ptr;
-};
-
-struct sti_conf_flags {
-	u32 wait : 1;
-	u32 pad : 31;
-	s32 *future_ptr;
-};
-
-struct sti_conf_inptr {
-	s32 *future_ptr;
-};
-
-struct sti_conf_outptr_ext {
-	u32 crt_config[3];
-	u32 crt_hdw[3];
-	s32 *future_ptr;
-};
-
-struct sti_conf_outptr {
-	s32 errno;
-	s16 onscreen_x;
-	s16 onscreen_y;
-	s16 offscreen_x;
-	s16 offscreen_y;
-	s16 total_x;
-	s16 total_y;
-	s32 bits_per_pixel;
-	s32 bits_used;
-	s32 planes;
-	 u8 dev_name[STI_DEV_NAME_LENGTH];
-	u32 attributes;
-	struct sti_conf_outptr_ext *ext_ptr;
-};
-
-
-struct sti_font_inptr {
-	u32 font_start_addr;
-	s16 index;
-	u8 fg_color;
-	u8 bg_color;
-	s16 dest_x;
-	s16 dest_y;
-	s32 *future_ptr;
-};
-
-struct sti_font_flags {
-	u32 wait : 1;
-	u32 non_text : 1;
-	u32 pad : 30;
-
-	s32 *future_ptr;
-};
-	
-struct sti_font_outptr {
-	s32 errno;
-	s32 *future_ptr;
-};
-
-struct sti_blkmv_flags {
-	u32 wait : 1;
-	u32 color : 1;
-	u32 clear : 1;
-	u32 non_text : 1;
-	u32 pad : 28;
-	s32 *future_ptr;
-};
-
-struct sti_blkmv_inptr {
-	u8 fg_color;
-	u8 bg_color;
-	s16 src_x;
-	s16 src_y;
-	s16 dest_x;
-	s16 dest_y;
-	s16 width;
-	s16 height;
-	s32 *future_ptr;
-};
-
-struct sti_blkmv_outptr {
-	s32 errno;
-	s32 *future_ptr;
-};
-
-struct sti_struct {
-	spinlock_t lock;
-
-	struct sti_cooked_rom *rom;
-
-	unsigned long font_unpmv;
-	unsigned long block_move;
-	unsigned long init_graph;
-	unsigned long inq_conf;
-
-	struct sti_glob_cfg *glob_cfg;
-	struct sti_rom_font *font;
-
-	s32 text_planes;
-
-	char **mon_strings;
-	u32 *regions;
-	 u8 *pci_regions;
-};
-
-#define STI_CALL(func, flags, inptr, outptr, glob_cfg) \
-	({							\
-		real32_call( func, (unsigned long)STI_PTR(flags), \
-				    STI_PTR(inptr), STI_PTR(outptr), \
-				    glob_cfg); \
-	})
-
-/* The latency of the STI functions cannot really be reduced by setting
- * this to 0;  STI doesn't seem to be designed to allow calling a different
- * function (or the same function with different arguments) after a
- * function exited with 1 as return value.
- *
- * As all of the functions below could be called from interrupt context,
- * we have to spin_lock_irqsave around the do { ret = bla(); } while(ret==1)
- * block.  Really bad latency there.
- *
- * Probably the best solution to all this is have the generic code manage
- * the screen buffer and a kernel thread to call STI occasionally.
- * 
- * Luckily, the frame buffer guys have the same problem so we can just wait
- * for them to fix it and steal their solution.   prumpf
- *
- * Actually, another long-term viable solution is to completely do STI
- * support in userspace - that way we avoid the potential license issues
- * of using proprietary fonts, too. */
- 
-#define STI_WAIT 1
-#define STI_PTR(p) ( (typeof(p)) virt_to_phys(p))
-#define PTR_STI(p) ( (typeof(p)) phys_to_virt((unsigned long)p) )
-
-#define sti_onscreen_x(sti) (PTR_STI(sti->glob_cfg)->onscreen_x)
-#define sti_onscreen_y(sti) (PTR_STI(sti->glob_cfg)->onscreen_y)
-#define sti_font_x(sti) (PTR_STI(sti->font)->width)
-#define sti_font_y(sti) (PTR_STI(sti->font)->height)
-
-extern struct sti_struct * sti_init_roms(void);
-
-void sti_init_graph(struct sti_struct *sti);
-void sti_inq_conf(struct sti_struct *sti);
-void sti_putc(struct sti_struct *sti, int c, int y, int x);
-void sti_set(struct sti_struct *sti, int src_y, int src_x,
-	     int height, int width, u8 color);
-void sti_clear(struct sti_struct *sti, int src_y, int src_x,
-	       int height, int width);
-void sti_bmove(struct sti_struct *sti, int src_y, int src_x,
-	       int dst_y, int dst_x, int height, int width);
-
-/* XXX: this probably should not be here, but we rely on STI being
-   initialized early and independently of stifb at the moment, so
-   there's no other way for stifb to find it. */
-extern struct sti_struct default_sti;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sticon-bmode.c linux-2.4.20/drivers/video/sticon-bmode.c
--- linux-2.4.19/drivers/video/sticon-bmode.c	2001-10-15 20:47:13.000000000 +0000
+++ linux-2.4.20/drivers/video/sticon-bmode.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,895 +0,0 @@
-/*
-TPG CVS users: please don't commit changes to this file directly, send
-them to prumpf@tux.org and wait for a new version instead.  Otherwise,
-your changes will get lost when prumpf releases the next version, as
-this file *will* be replaced with it.  You have been warned.
-
-2000-05-30, <deller@gmx.de>
-*/
-#if 1
-#define DPRINTK(x)	printk x
-#else
-#define DPRINTK(x)
-#endif
-
-/*
- *  linux/drivers/video/sticon.c  - console driver using HP's STI firmware
- *
- *	Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
- *
- *  Based on linux/drivers/video/vgacon.c and linux/drivers/video/fbcon.c,
- *  which were
- *
- *	Created 28 Sep 1997 by Geert Uytterhoeven
- *	Rewritten by Martin Mares <mj@ucw.cz>, July 1998
- *	Copyright (C) 1991, 1992  Linus Torvalds
- *			    1995  Jay Estabrook
- *	Copyright (C) 1995 Geert Uytterhoeven
- *	Copyright (C) 1993 Bjoern Brauel
- *			   Roman Hodek
- *	Copyright (C) 1993 Hamish Macdonald
- *			   Greg Harp
- *	Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
- *
- *	      with work by William Rucklidge (wjr@cs.cornell.edu)
- *			   Geert Uytterhoeven
- *			   Jes Sorensen (jds@kom.auc.dk)
- *			   Martin Apel
- *	      with work by Guenther Kelleter
- *			   Martin Schaller
- *			   Andreas Schwab
- *			   Emmanuel Marty (core@ggi-project.org)
- *			   Jakub Jelinek (jj@ultra.linux.cz)
- *			   Martin Mares <mj@ucw.cz>
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- */
-/*
- *  TODO:
- *   - call STI in virtual mode rather than in real mode
- *   - support for PCI-only STI ROMs (which don't have a traditional region
- *     list)
- *   - safe detection (i.e. verify there is a graphics device at a given
- *     address first, not just read a random device's io space)
- *   - support for multiple STI devices in one machine
- *   - support for byte-mode STI ROMs
- *   - support for just using STI to switch to a colour fb (stifb ?)
- *   - try to make it work on m68k hp workstations ;)
- */
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/tty.h>
-#include <linux/console.h>
-#include <linux/string.h>
-#include <linux/kd.h>
-#include <linux/slab.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-#include <asm/real.h>
-
-#include <linux/module.h>
-#include <linux/fb.h>
-#include <linux/smp.h>
-
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#include <video/fbcon.h>
-#include <video/font.h>
-
-#include "sti-bmode.h"
-
-/* The latency of the STI functions cannot really be reduced by setting
- * this to 0;  STI doesn't seem to be designed to allow calling a different
- * function (or the same function with different arguments) after a
- * function exited with 1 as return value.
- *
- * As all of the functions below could be called from interrupt context,
- * we have to spin_lock_irqsave around the do { ret = bla(); } while(ret==1)
- * block.  Really bad latency there.
- *
- * Probably the best solution to all this is have the generic code manage
- * the screen buffer and a kernel thread to call STI occasionally.
- * 
- * Luckily, the frame buffer guys have the same problem so we can just wait
- * for them to fix it and steal their solution.   prumpf
- *
- * Actually, another long-term viable solution is to completely do STI
- * support in userspace - that way we avoid the potential license issues
- * of using proprietary fonts, too. */
- 
-#define STI_WAIT 1
-#define STI_PTR(p) ( (typeof(p)) virt_to_phys(p))
-#define PTR_STI(p) ( (typeof(p)) phys_to_virt((unsigned long)p) )
-
-static struct sti_struct default_sti = {
-	SPIN_LOCK_UNLOCKED,
-};
-
-static struct sti_font_flags default_font_flags = {
-	STI_WAIT, 0, 0, NULL
-};
-
-/* The colour indices used by STI are
- *   0 - Black
- *   1 - White
- *   2 - Red
- *   3 - Yellow/Brown
- *   4 - Green
- *   5 - Cyan
- *   6 - Blue
- *   7 - Magenta
- *
- * So we have the same colours as VGA (basically one bit each for R, G, B),
- * but have to translate them, anyway. */
-
-static u8 col_trans[8] = {
-        0, 6, 4, 5,
-        2, 7, 3, 1
-};
-
-#define c_fg(sti, c) col_trans[((c>> 8) & 7)]
-#define c_bg(sti, c) col_trans[((c>>11) & 7)]
-#define c_index(sti, c) (c&0xff)
-
-#define sti_onscreen_x(sti) (PTR_STI(sti->glob_cfg)->onscreen_x)
-#define sti_onscreen_y(sti) (PTR_STI(sti->glob_cfg)->onscreen_y)
-#define sti_font_x(sti) (STI_U8(PTR_STI(sti->font)->width))
-#define sti_font_y(sti) (STI_U8(PTR_STI(sti->font)->height))
-
-static struct sti_init_flags default_init_flags = {
-	STI_WAIT, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, NULL
-};
-
-static void sti_init_graph(struct sti_struct *sti) 
-{
-	struct sti_init_inptr_ext inptr_ext = {
-		0, { 0 }, 0, NULL
-	};
-	struct sti_init_inptr inptr = {
-		3, STI_PTR(&inptr_ext)
-	};
-	struct sti_init_outptr outptr = { 0 };
-	unsigned long flags;
-	s32 ret;
-
-	spin_lock_irqsave(&sti->lock, flags);
-
-	ret = STI_CALL(sti->init_graph, &default_init_flags, &inptr,
-		&outptr, sti->glob_cfg);
-
-	spin_unlock_irqrestore(&sti->lock, flags);
-
-	sti->text_planes = outptr.text_planes;
-}
-
-#if 0
-static struct sti_conf_flags default_conf_flags = {
-	STI_WAIT, 0, NULL
-};
-
-static void sti_inq_conf(struct sti_struct *sti)
-{
-	struct sti_conf_inptr inptr = { NULL };
-	struct sti_conf_outptr_ext outptr_ext = { future_ptr: NULL };
-	struct sti_conf_outptr outptr = {
-		ext_ptr: STI_PTR(&outptr_ext)
-	};
-	unsigned long flags;
-	s32 ret;
-	
-	do {
-		spin_lock_irqsave(&sti->lock, flags);
-		ret = STI_CALL(sti->inq_conf, &default_conf_flags,
-			&inptr, &outptr, sti->glob_cfg);
-		spin_unlock_irqrestore(&sti->lock, flags);
-	} while(ret == 1);
-}
-#endif
-
-static void sti_putc(struct sti_struct *sti, int c, int y, int x)
-{
-	struct sti_font_inptr inptr = {
-		(u32) sti->font, c_index(sti, c), c_fg(sti, c), c_bg(sti, c),
-		x * sti_font_x(sti), y * sti_font_y(sti), NULL
-	};
-	struct sti_font_outptr outptr = {
-		0, NULL
-	};
-	s32 ret;
-	unsigned long flags;
-
-	do {
-		spin_lock_irqsave(&sti->lock, flags);
-		ret = STI_CALL(sti->font_unpmv, &default_font_flags,
-			&inptr, &outptr, sti->glob_cfg);
-		spin_unlock_irqrestore(&sti->lock, flags);
-	} while(ret == 1);
-}
-
-static struct sti_blkmv_flags clear_blkmv_flags = {
-	STI_WAIT, 1, 1, 0, 0, NULL
-};
-
-static void sti_set(struct sti_struct *sti, int src_y, int src_x,
-	int height, int width, u8 color)
-{
-	struct sti_blkmv_inptr inptr = {
-		color, color,
-		src_x, src_y ,
-		src_x, src_y ,
-		width, height,
-		NULL
-	};
-	struct sti_blkmv_outptr outptr = { 0, NULL };
-	s32 ret = 0;
-	unsigned long flags;
-	
-	do {
-		spin_lock_irqsave(&sti->lock, flags);
-		ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
-			&inptr, &outptr, sti->glob_cfg);
-		spin_unlock_irqrestore(&sti->lock, flags);
-	} while(ret == 1);
-}
-
-static void sti_clear(struct sti_struct *sti, int src_y, int src_x,
-	int height, int width)
-{
-	struct sti_blkmv_inptr inptr = {
-		0, 0,
-		src_x * sti_font_x(sti), src_y * sti_font_y(sti),
-		src_x * sti_font_x(sti), src_y * sti_font_y(sti),
-		width * sti_font_x(sti), height* sti_font_y(sti),
-		NULL
-	};
-	struct sti_blkmv_outptr outptr = { 0, NULL };
-	s32 ret = 0;
-	unsigned long flags;
-
-	do {
-		spin_lock_irqsave(&sti->lock, flags);
-		ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
-			&inptr, &outptr, sti->glob_cfg);
-		spin_unlock_irqrestore(&sti->lock, flags);
-	} while(ret == 1);
-}
-
-static struct sti_blkmv_flags default_blkmv_flags = {
-	STI_WAIT, 0, 0, 0, 0, NULL
-};
-
-static void sti_bmove(struct sti_struct *sti, int src_y, int src_x,
-	int dst_y, int dst_x, int height, int width)
-{
-	struct sti_blkmv_inptr inptr = {
-		0, 0,
-		src_x * sti_font_x(sti), src_y * sti_font_y(sti),
-		dst_x * sti_font_x(sti), dst_y * sti_font_y(sti),
-		width * sti_font_x(sti), height* sti_font_y(sti),
-		NULL
-	};
-	struct sti_blkmv_outptr outptr = { 0, NULL };
-	s32 ret = 0;
-	unsigned long flags;
-
-	do {
-		spin_lock_irqsave(&sti->lock, flags);
-		ret = STI_CALL(sti->block_move, &default_blkmv_flags,
-			&inptr, &outptr, sti->glob_cfg);
-		spin_unlock_irqrestore(&sti->lock, flags);
-	} while(ret == 1);
-}
-
-
-/* STICON */
-
-static const char __init *sticon_startup(void)
-{
-	return "STI console";
-}
-
-static int sticon_set_palette(struct vc_data *c, unsigned char *table)
-{
-	return -EINVAL;
-}
-static int sticon_font_op(struct vc_data *c, struct console_font_op *op)
-{
-	return -ENOSYS;
-}
-
-static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos)
-{
-	sti_putc(&default_sti, c, ypos, xpos);
-}
-
-static void sticon_putcs(struct vc_data *conp, const unsigned short *s,
-	int count, int ypos, int xpos)
-{
-	while(count--) {
-		sti_putc(&default_sti, scr_readw(s++), ypos, xpos++);
-	}
-}
-
-static void sticon_cursor(struct vc_data *conp, int mode)
-{
-}
-
-static int sticon_scroll(struct vc_data *conp, int t, int b, int dir,
-			int count)
-{
-	struct sti_struct *sti = &default_sti;
-
-	if(console_blanked)
-		return 0;
-
-	sticon_cursor(conp, CM_ERASE);
-
-	switch(dir) {
-	case SM_UP:
-		sti_bmove(sti, t+count, 0, t, 0, b-t-count, conp->vc_cols);
-		sti_clear(sti, b-count, 0, count, conp->vc_cols);
-
-		break;
-
-	case SM_DOWN:
-		sti_bmove(sti, t, 0, t+count, 0, b-t-count, conp->vc_cols);
-		sti_clear(sti, t, 0, count, conp->vc_cols);
-
-		break;
-	}
-
-	return 0;
-}
-	
-static void sticon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
-	int height, int width)
-{
-	sti_bmove(&default_sti, sy, sx, dy, dx, height, width);
-}
-
-static void sticon_init(struct vc_data *c, int init)
-{
-	struct sti_struct *sti = &default_sti;
-	int vc_cols, vc_rows;
-
-	sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0);
-	c->vc_can_do_color = 1;
-	vc_cols = PTR_STI(sti->glob_cfg)->onscreen_x / sti_font_x(sti);
-	vc_rows = PTR_STI(sti->glob_cfg)->onscreen_y / sti_font_y(sti);
-
-	vc_resize_con(vc_rows, vc_cols, c->vc_num);
-}
-
-static void sticon_deinit(struct vc_data *c)
-{
-}
-
-static void sticon_clear(struct vc_data *conp, int sy, int sx, int height,
-			int width)
-{
-	sti_clear(&default_sti, sy, sx, height, width);
-}
-
-static int sticon_switch(struct vc_data *conp)
-{
-	return 0;
-}
-
-static int sticon_blank(struct vc_data *conp, int blank)
-{
-	return 0;
-}
-
-static int sticon_scrolldelta(struct vc_data *conp, int lines)
-{
-	return 0;
-}
-
-static int sticon_set_origin(struct vc_data *conp)
-{
-	return 0;
-}
-
-static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens, u8 blink, u8 underline, u8 reverse)
-{
-	u8 attr = ((color & 0x70) >> 1) | ((color & 7));
-
-	if(reverse) {
-		color = ((color>>3)&0x7) | ((color &0x7)<<3);
-	}
-
-
-	return attr;
-}
-
-static struct consw sti_con = {
-	con_startup: 		sticon_startup, 
-	con_init: 		sticon_init,
-	con_deinit: 		sticon_deinit,
-	con_clear: 		sticon_clear,
-	con_putc: 		sticon_putc,
-	con_putcs: 		sticon_putcs,
-	con_cursor: 		sticon_cursor,
-	con_scroll: 		sticon_scroll,
-	con_bmove: 		sticon_bmove,
-	con_switch: 		sticon_switch,
-	con_blank: 		sticon_blank,
-	con_font_op:		sticon_font_op,
-	con_set_palette:	sticon_set_palette,
-	con_scrolldelta:	sticon_scrolldelta,
-	con_set_origin: 	sticon_set_origin,
-	con_build_attr:		sticon_build_attr,
-};
-
-#include <asm/pgalloc.h>	/* need cache flush routines */
-static void __init sti_rom_copy(unsigned long base, unsigned long offset,
-				unsigned long count, void *dest)
-{
-	void *savedest = dest;
-	int savecount = count;
-
-	while(count >= 4) {
-		count -= 4;
-		*(u32 *)dest = gsc_readl(base + offset);
-#if 0
-		DPRINTK(("%08x\n", *(u32 *)dest));
-		if(*(u32 *)dest == 0x64646464) {
-		  DPRINTK(("!!!!\n"));
-		  { u32 foo = 0; while(foo += 0x100); }
-		}
-#endif
-		offset += 4;
-		dest += 4;
-	}
-	while(count) {
-		count--;
-		*(u8 *)dest = gsc_readb(base + offset);
-		offset++;
-		dest++;
-	}
-
-	flush_kernel_dcache_range((unsigned long)dest, count);
-	flush_icache_range((unsigned long)dest, dest + count);
-}
-
-static void dump_sti_rom(struct sti_rom *rom)
-{
-	printk("STI byte mode ROM type %d\n", STI_U8(rom->type));
-	printk(" supports %d monitors\n", STI_U8(rom->num_mons));
-	printk(" conforms to STI ROM spec revision %d.%02x\n",
-		STI_U8(rom->revno[0]) >> 4, STI_U8(rom->revno[0]) & 0x0f);
-	printk(__FUNCTION__ ": %d\n", __LINE__);
-	printk(" graphics id %02x%02x%02x%02x%02x%02x%02x%02x\n",
-		(unsigned int) STI_U8(rom->graphics_id[0]), 
-		(unsigned int) STI_U8(rom->graphics_id[1]), 
-		(unsigned int) STI_U8(rom->graphics_id[2]), 
-		(unsigned int) STI_U8(rom->graphics_id[3]), 
-		(unsigned int) STI_U8(rom->graphics_id[4]), 
-		(unsigned int) STI_U8(rom->graphics_id[5]), 
-		(unsigned int) STI_U8(rom->graphics_id[6]), 
-		(unsigned int) STI_U8(rom->graphics_id[7]));
-	printk(__FUNCTION__ ": %d\n", __LINE__);
-	printk(" font start %08x\n",  STI_U32(rom->font_start));
-	printk(__FUNCTION__ ": %d\n", __LINE__);
-	printk(" region list %08x\n", STI_U32(rom->region_list));
-	printk(__FUNCTION__ ": %d\n", __LINE__);
-	printk(" init_graph %08x\n",  STI_U32(rom->init_graph));
-	printk(__FUNCTION__ ": %d\n", __LINE__);
-	printk(" alternate code type %d\n", STI_U8(rom->alt_code_type));
-	printk(__FUNCTION__ ": %d\n", __LINE__);
-}
-
-static void __init sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
-				  struct sti_rom *raw_rom)
-{
-	struct sti_rom_font *raw_font;
-	struct sti_cooked_font *cooked_font;
-	struct sti_rom_font *font_start;
-
-	cooked_font =
-		kmalloc(sizeof *cooked_font, GFP_KERNEL);
-	if(!cooked_font)
-		return;
-
-	cooked_rom->font_start = cooked_font;
-
-#if 0
-	DPRINTK(("%p = %p + %08x\n",
-	       ((void *)raw_rom) + (STI_U32(raw_rom->font_start)),
-	       ((void *)raw_rom), (STI_U32(raw_rom->font_start))));
-#endif
-	raw_font = ((void *)raw_rom) + STI_U32(raw_rom->font_start) - 3;
-
-	font_start = raw_font;
-	cooked_font->raw = raw_font;
-
-	DPRINTK(("next font %08x\n", STI_U32(raw_font->next_font)));
-
-	while(0 && STI_U32(raw_font->next_font)) {
-		raw_font = ((void *)font_start) + STI_U32(raw_font->next_font);
-		
-		cooked_font->next_font =
-			kmalloc(sizeof *cooked_font, GFP_KERNEL);
-		if(!cooked_font->next_font)
-			return;
-
-		cooked_font = cooked_font->next_font;
-
-//		cooked_font->raw = raw_font;
-
-		DPRINTK(("raw_font %p\n",
-		       raw_font));
-		DPRINTK(("next_font %08x %p\n",
-		       STI_U32(raw_font->next_font),
-		       ((void *)font_start) + STI_U32(raw_font->next_font)));
-	}
-
-	cooked_font->next_font = NULL;
-}
-
-static unsigned long __init sti_cook_function(void *function,
-					      u32 size)
-{
-	sti_u32 *func = (sti_u32 *)function;
-	u32 *ret;
-	int i;
-
-	ret = kmalloc(size, GFP_KERNEL);
-	if(!ret) {
-		printk(KERN_ERR __FILE__ ": could not get memory.\n");
-		return 0;
-	}
-
-	for(i=0; i<(size/4); i++)
-	    ret[i] = STI_U32(func[i]);
-
-	flush_all_caches();
-	
-	return virt_to_phys(ret);
-}
-
-static int font_index, font_height, font_width;
-
-static int __init sti_search_font(struct sti_cooked_rom *rom,
-				  int height, int width)
-{
-	struct sti_cooked_font *font;
-	int i = 0;
-	
-	for(font = rom->font_start; font; font = font->next_font, i++) {
-		if((STI_U8(font->raw->width) == width) &&
-		   (STI_U8(font->raw->height) == height))
-			return i;
-	}
-
-	return 0;
-}
-
-static struct sti_cooked_font * __init
-sti_select_font(struct sti_cooked_rom *rom)
-{
-	struct sti_cooked_font *font;
-	int i;
-
-	if(font_width && font_height)
-		font_index = sti_search_font(rom, font_height, font_width);
-
-	for(font = rom->font_start, i = font_index;
-	    font && (i > 0);
-	    font = font->next_font, i--);
-
-	if(font)
-		return font;
-	else
-		return rom->font_start;
-}
-	
-/* address is a pointer to a word mode or pci rom */
-static struct sti_struct * __init sti_read_rom(unsigned long address)
-{
-	struct sti_struct *ret = NULL;
-	struct sti_cooked_rom *cooked = NULL;
-	struct sti_rom *raw = NULL;
-	unsigned long size;
-
-	ret = &default_sti;
-
-	if(!ret)
-		goto out_err;
-
-	cooked = kmalloc(sizeof *cooked, GFP_KERNEL);
-	raw = kmalloc(sizeof *raw, GFP_KERNEL);
-	
-	if(!(raw && cooked))
-		goto out_err;
-
-	/* reallocate raw */
-	sti_rom_copy(address, 0, sizeof *raw, raw);
-
-	dump_sti_rom(raw);
-
-	size = STI_U32(raw->last_addr) + 1;
-	size = 128*1024;
-//	DPRINTK(("size %08lx\n", size));
-//	DPRINTK(("font_start %08x\n", STI_U32(raw->font_start)));
-//	kfree(raw);
-	raw = kmalloc(size, GFP_KERNEL);
-	if(!raw)
-		goto out_err;
-	sti_rom_copy(address, 0, size-1, raw);
-
-	sti_cook_fonts(cooked, raw);
-//	sti_cook_regions(cooked, raw);
-//	sti_cook_functions(cooked, raw);
-
-	if(STI_U32(raw->region_list)) {
-		struct sti_rom_region *region =
-			((void *)raw) + STI_U32(raw->region_list) - 3;
-
-//		DPRINTK(("region_list %08x\n", STI_U32(raw->region_list)));
-
-		ret->regions = kmalloc(32, GFP_KERNEL); /* FIXME!! */
-
-		ret->regions[0] = STI_U32(region[0].region);
-		ret->regions[1] = STI_U32(region[1].region);
-		ret->regions[2] = STI_U32(region[2].region);
-		ret->regions[3] = STI_U32(region[3].region);
-		ret->regions[4] = STI_U32(region[4].region);
-		ret->regions[5] = STI_U32(region[5].region);
-		ret->regions[6] = STI_U32(region[6].region);
-		ret->regions[7] = STI_U32(region[7].region);
-	}
-
-	address = virt_to_phys(raw);
-
-#if 0
-	DPRINTK(("init_graph %08x %08x\n"
-	       "state_mgmt %08x %08x\n"
-	       "font_unpmv %08x %08x\n"
-	       "block_move %08x %08x\n"
-	       "self_test  %08x %08x\n"
-	       "excep_hdlr %08x %08x\n"
-	       "irq_conf   %08x %08x\n"
-	       "set_cm_e   %08x %08x\n"
-	       "dma_ctrl   %08x %08x\n"
-	       "flow_ctrl  %08x %08x\n"
-	       "user_timin %08x %08x\n"
-	       "process_m  %08x %08x\n"
-	       "sti_util   %08x %08x\n"
-	       "end_addr   %08x %08x\n",
-	       STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
-	       STI_U32(raw->state_mgmt), STI_U32(raw->state_mgmt_m68k),
-	       STI_U32(raw->font_unpmv), STI_U32(raw->font_unpmv_m68k),
-	       STI_U32(raw->block_move), STI_U32(raw->block_move_m68k),
-	       STI_U32(raw->self_test), STI_U32(raw->self_test_m68k),
-	       STI_U32(raw->excep_hdlr), STI_U32(raw->excep_hdlr_m68k),
-	       STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
-	       STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
-	       STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
-	       STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
-	       STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
-	       STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
-	       STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
-	       STI_U32(raw->end_addr), STI_U32(raw->end_addr_m68k) ) );
-#endif
-
-	ret->init_graph = sti_cook_function(((void *)raw)+STI_U32(raw->init_graph)-3,
-					    (STI_U32(raw->state_mgmt) -
-					     STI_U32(raw->init_graph))/4);
-
-
-	ret->font_unpmv = sti_cook_function(((void *)raw)+STI_U32(raw->font_unpmv)-3,
-					    (STI_U32(raw->block_move) -
-					     STI_U32(raw->font_unpmv))/4);
-
-	ret->block_move = sti_cook_function(((void *)raw)+STI_U32(raw->block_move)-3,
-					    (STI_U32(raw->self_test) -
-					     STI_U32(raw->block_move))/4);
-
-	ret->inq_conf = sti_cook_function(((void *)raw)+STI_U32(raw->inq_conf),
-					  STI_U32(raw->set_cm_entry) -
-					  STI_U32(raw->inq_conf));
-
-	ret->rom = cooked;
-	ret->rom->raw = raw;
-
-	ret->font = (struct sti_rom_font *) virt_to_phys(sti_select_font(ret->rom)->raw);
-
-	return ret;
-
-out_err:
-	if(raw)
-		kfree(raw);
-	if(cooked)
-		kfree(cooked);
-
-	return NULL;
-}
-
-#if 0
-static void dump_globcfg_ext(struct sti_glob_cfg_ext *cfg)
-{
-	DPRINTK(("monitor %d\n"
-		"in friendly mode: %d\n"
-		"power consumption %d watts\n"
-		"freq ref %d\n"
-		"sti_mem_addr %p\n",
-		cfg->curr_mon,
-		cfg->friendly_boot,
-		cfg->power,
-		cfg->freq_ref,
-		cfg->sti_mem_addr));
-}
-
-static void dump_globcfg(struct sti_glob_cfg *glob_cfg)
-{
-	DPRINTK(("%d text planes\n"
-		"%4d x %4d screen resolution\n"
-		"%4d x %4d offscreen\n"
-		"%4d x %4d layout\n"
-		"regions at %08x %08x %08x %08x\n"
-		"regions at %08x %08x %08x %08x\n"
-		"reent_lvl %d\n"
-		"save_addr %p\n",
-		glob_cfg->text_planes,
-		glob_cfg->onscreen_x, glob_cfg->onscreen_y,
-		glob_cfg->offscreen_x, glob_cfg->offscreen_y,
-		glob_cfg->total_x, glob_cfg->total_y,
-		glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1],
-		glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3],
-		glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5],
-		glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7],
-		glob_cfg->reent_lvl,
-		glob_cfg->save_addr));
-	dump_globcfg_ext(PTR_STI(glob_cfg->ext_ptr));
-}
-#endif
-		
-static void __init sti_init_glob_cfg(struct sti_struct *sti, unsigned long hpa,
-				     unsigned long rom_address)
-{
-	struct sti_glob_cfg *glob_cfg;
-	struct sti_glob_cfg_ext *glob_cfg_ext;
-	void *save_addr;
-	void *sti_mem_addr;
-
-	glob_cfg = kmalloc(sizeof *sti->glob_cfg, GFP_KERNEL);
-	glob_cfg_ext = kmalloc(sizeof *glob_cfg_ext, GFP_KERNEL);
-	save_addr = kmalloc(1024 /*XXX*/, GFP_KERNEL);
-	sti_mem_addr = kmalloc(1024, GFP_KERNEL);
-
-	if((!glob_cfg) || (!glob_cfg_ext) || (!save_addr) || (!sti_mem_addr))
-		return;
-
-	memset(glob_cfg, 0, sizeof *glob_cfg);
-	memset(glob_cfg_ext, 0, sizeof *glob_cfg_ext);
-	memset(save_addr, 0, 1024);
-	memset(sti_mem_addr, 0, 1024);
-
-	glob_cfg->ext_ptr = STI_PTR(glob_cfg_ext);
-	glob_cfg->save_addr = STI_PTR(save_addr);
-	glob_cfg->region_ptrs[0] = ((sti->regions[0]>>18)<<12) + rom_address;
-	glob_cfg->region_ptrs[1] = ((sti->regions[1]>>18)<<12) + hpa;
-	glob_cfg->region_ptrs[2] = ((sti->regions[2]>>18)<<12) + hpa;
-	glob_cfg->region_ptrs[3] = ((sti->regions[3]>>18)<<12) + hpa;
-	glob_cfg->region_ptrs[4] = ((sti->regions[4]>>18)<<12) + hpa;
-	glob_cfg->region_ptrs[5] = ((sti->regions[5]>>18)<<12) + hpa;
-	glob_cfg->region_ptrs[6] = ((sti->regions[6]>>18)<<12) + hpa;
-	glob_cfg->region_ptrs[7] = ((sti->regions[7]>>18)<<12) + hpa;
-
-	glob_cfg_ext->sti_mem_addr = STI_PTR(sti_mem_addr);
-
-	sti->glob_cfg = STI_PTR(glob_cfg);
-}
-
-static void __init sti_try_rom(unsigned long address, unsigned long hpa)
-{
-	struct sti_struct *sti = NULL;
-	u16 sig;
-	
-	/* if we can't read the ROM, bail out early.  Not being able
-	 * to read the hpa is okay, for romless sti */
-	if(pdc_add_valid((void*)address))
-		return;
-
-	printk("found potential STI ROM at %08lx\n", address);
-
-	sig = le16_to_cpu(gsc_readw(address));
-
-	if((sig&0xff) == 0x01) {
-		sti = sti_read_rom(address);
-	}
-
-	if(sig == 0x0303) {
-		printk("STI word mode ROM at %08lx, ignored\n",
-		       address);
-
-		sti = NULL;
-	}
-
-	if(!sti)
-		return;
-
-	/* this is hacked.  We need a better way to find out the HPA for
-	 * romless STI (eg search for the graphics devices we know about
-	 * by sversion) */
-	if (!pdc_add_valid((void *)0xf5000000)) DPRINTK(("f4000000 b\n"));
-	if (!pdc_add_valid((void *)0xf7000000)) DPRINTK(("f6000000 b\n"));
-	if (!pdc_add_valid((void *)0xf9000000)) DPRINTK(("f8000000 b\n"));
-	if (!pdc_add_valid((void *)0xfb000000)) DPRINTK(("fa000000 b\n"));
-	sti_init_glob_cfg(sti, hpa, address);
-
-	sti_init_graph(sti);
-
-	//sti_inq_conf(sti);
-#if !defined(SERIAL_CONSOLE)	
-	{ 
-	    extern void pdc_console_die(void);  
-	    pdc_console_die(); 
-	}
-#endif
-		
-	take_over_console(&sti_con, 0, MAX_NR_CONSOLES-1, 1);
-
-	/* sti_inq_conf(sti); */
-}
-
-static unsigned long sti_address;
-static unsigned long sti_hpa;
-
-static void __init sti_init_roms(void)
-{
-	/* handle the command line */
-	if(sti_address && sti_hpa) {
-		sti_try_rom(sti_address, sti_hpa);
-
-		return;
-	}
-
-	/* 712, 715, some other boxes don't have a separate STI ROM,
-	 * but use part of the regular flash */
-	if(PAGE0->proc_sti) {
-		printk("STI ROM from PDC at %08x\n", PAGE0->proc_sti);
-		if(!pdc_add_valid((void *)0xf9000000))
-			sti_try_rom(PAGE0->proc_sti, 0xf8000000);
-		else if(!pdc_add_valid((void *)0xf5000000))
-			sti_try_rom(PAGE0->proc_sti, 0xf4000000);
-		else if(!pdc_add_valid((void *)0xf7000000))
-			sti_try_rom(PAGE0->proc_sti, 0xf6000000);
-		else if(!pdc_add_valid((void *)0xfb000000))
-			sti_try_rom(PAGE0->proc_sti, 0xfa000000);
-	}
-
-	/* standard locations for GSC graphic devices */
-	if(!pdc_add_valid((void *)0xf4000000))
-		sti_try_rom(0xf4000000, 0xf4000000);
-	if(!pdc_add_valid((void *)0xf6000000))
-		sti_try_rom(0xf6000000, 0xf6000000);
-	if(!pdc_add_valid((void *)0xf8000000))
-		sti_try_rom(0xf8000000, 0xf8000000);
-	if(!pdc_add_valid((void *)0xfa000000))
-		sti_try_rom(0xfa000000, 0xfa000000);
-}
-
-static int __init sti_init(void)
-{
-	printk("searching for byte mode STI ROMs\n");
-	sti_init_roms();
-	return 0;
-}
-
-module_init(sti_init)
-
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sticon.c linux-2.4.20/drivers/video/sticon.c
--- linux-2.4.19/drivers/video/sticon.c	2001-10-15 20:47:13.000000000 +0000
+++ linux-2.4.20/drivers/video/sticon.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,215 +0,0 @@
-/*
- *  linux/drivers/video/sticon.c  - console driver using HP's STI firmware
- *
- *	Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
- *
- *  Based on linux/drivers/video/vgacon.c and linux/drivers/video/fbcon.c,
- *  which were
- *
- *	Created 28 Sep 1997 by Geert Uytterhoeven
- *	Rewritten by Martin Mares <mj@ucw.cz>, July 1998
- *	Copyright (C) 1991, 1992  Linus Torvalds
- *			    1995  Jay Estabrook
- *	Copyright (C) 1995 Geert Uytterhoeven
- *	Copyright (C) 1993 Bjoern Brauel
- *			   Roman Hodek
- *	Copyright (C) 1993 Hamish Macdonald
- *			   Greg Harp
- *	Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
- *
- *	      with work by William Rucklidge (wjr@cs.cornell.edu)
- *			   Geert Uytterhoeven
- *			   Jes Sorensen (jds@kom.auc.dk)
- *			   Martin Apel
- *	      with work by Guenther Kelleter
- *			   Martin Schaller
- *			   Andreas Schwab
- *			   Emmanuel Marty (core@ggi-project.org)
- *			   Jakub Jelinek (jj@ultra.linux.cz)
- *			   Martin Mares <mj@ucw.cz>
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- */
-/*
- *  TODO:
- *   - call STI in virtual mode rather than in real mode
- *   - support for PCI-only STI ROMs (which don't have a traditional region
- *     list)
- *   - safe detection (i.e. verify there is a graphics device at a given
- *     address first, not just read a random device's io space)
- *   - support for multiple STI devices in one machine
- *   - support for byte-mode STI ROMs
- *   - support for just using STI to switch to a colour fb (stifb ?)
- *   - try to make it work on m68k hp workstations ;)
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/tty.h>
-#include <linux/console.h>
-#include <linux/console_struct.h>
-#include <linux/errno.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-
-#include <asm/io.h>
-
-#include "sti.h"
-
-/* STICON */
-
-static const char * __init
-sticon_startup(void)
-{
-	return "STI console";
-}
-
-static int
-sticon_set_palette(struct vc_data *c, unsigned char *table)
-{
-	return -EINVAL;
-}
-static int
-sticon_font_op(struct vc_data *c, struct console_font_op *op)
-{
-	return -ENOSYS;
-}
-
-static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos)
-{
-	sti_putc(&default_sti, c, ypos, xpos);
-}
-
-static void sticon_putcs(struct vc_data *conp, const unsigned short *s,
-	int count, int ypos, int xpos)
-{
-	while(count--) {
-		sti_putc(&default_sti, scr_readw(s++), ypos, xpos++);
-	}
-}
-
-static void sticon_cursor(struct vc_data *conp, int mode)
-{
-}
-
-static int sticon_scroll(struct vc_data *conp, int t, int b, int dir,
-			int count)
-{
-	struct sti_struct *sti = &default_sti;
-
-	if(console_blanked)
-		return 0;
-
-	sticon_cursor(conp, CM_ERASE);
-
-	switch(dir) {
-	case SM_UP:
-		sti_bmove(sti, t+count, 0, t, 0, b-t-count, conp->vc_cols);
-		sti_clear(sti, b-count, 0, count, conp->vc_cols);
-
-		break;
-
-	case SM_DOWN:
-		sti_bmove(sti, t, 0, t+count, 0, b-t-count, conp->vc_cols);
-		sti_clear(sti, t, 0, count, conp->vc_cols);
-
-		break;
-	}
-
-	return 0;
-}
-	
-static void sticon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
-			 int height, int width)
-{
-	sti_bmove(&default_sti, sy, sx, dy, dx, height, width);
-}
-
-static void sticon_init(struct vc_data *c, int init)
-{
-	struct sti_struct *sti = &default_sti;
-	int vc_cols, vc_rows;
-
-	sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0);
-	c->vc_can_do_color = 1;
-	vc_cols = PTR_STI(sti->glob_cfg)->onscreen_x / sti_font_x(sti);
-	vc_rows = PTR_STI(sti->glob_cfg)->onscreen_y / sti_font_y(sti);
-
-	vc_resize_con(vc_rows, vc_cols, c->vc_num);
-}
-
-static void sticon_deinit(struct vc_data *c)
-{
-}
-
-static void sticon_clear(struct vc_data *conp, int sy, int sx, int height,
-			int width)
-{
-	sti_clear(&default_sti, sy, sx, height, width);
-}
-
-static int sticon_switch(struct vc_data *conp)
-{
-	return 0;
-}
-
-static int sticon_blank(struct vc_data *conp, int blank)
-{
-	return 0;
-}
-
-static int sticon_scrolldelta(struct vc_data *conp, int lines)
-{
-	return 0;
-}
-
-static int sticon_set_origin(struct vc_data *conp)
-{
-	return 0;
-}
-
-static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens, u8 blink, u8 underline, u8 reverse)
-{
-	u8 attr = ((color & 0x70) >> 1) | ((color & 7));
-
-	if(reverse) {
-		color = ((color>>3)&0x7) | ((color &0x7)<<3);
-	}
-
-
-	return attr;
-}
-
-struct consw sti_con = {
-	con_startup: 		sticon_startup, 
-	con_init: 		sticon_init,
-	con_deinit: 		sticon_deinit,
-	con_clear: 		sticon_clear,
-	con_putc: 		sticon_putc,
-	con_putcs: 		sticon_putcs,
-	con_cursor: 		sticon_cursor,
-	con_scroll: 		sticon_scroll,
-	con_bmove: 		sticon_bmove,
-	con_switch: 		sticon_switch,
-	con_blank: 		sticon_blank,
-	con_font_op:		sticon_font_op,
-	con_set_palette:	sticon_set_palette,
-	con_scrolldelta:	sticon_scrolldelta,
-	con_set_origin: 	sticon_set_origin,
-	con_build_attr:		sticon_build_attr,
-};
-
-static int __init sti_init(void)
-{
-	printk("searching for word mode STI ROMs\n");
-	if (sti_init_roms()) {
-		pdc_console_die();
-		take_over_console(&sti_con, 0, MAX_NR_CONSOLES-1, 1);
-		return 0;
-	} else
-		return -ENODEV;
-}
-
-module_init(sti_init)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/sticore.c linux-2.4.20/drivers/video/sticore.c
--- linux-2.4.19/drivers/video/sticore.c	2001-09-13 23:04:43.000000000 +0000
+++ linux-2.4.20/drivers/video/sticore.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,601 +0,0 @@
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-#include <asm/io.h>
-
-#include "sti.h"
-
-struct sti_struct default_sti = {
-	SPIN_LOCK_UNLOCKED,
-};
-
-static struct sti_font_flags default_font_flags = {
-	STI_WAIT, 0, 0, NULL
-};
-
-/* The colour indices used by STI are
- *   0 - Black
- *   1 - White
- *   2 - Red
- *   3 - Yellow/Brown
- *   4 - Green
- *   5 - Cyan
- *   6 - Blue
- *   7 - Magenta
- *
- * So we have the same colours as VGA (basically one bit each for R, G, B),
- * but have to translate them, anyway. */
-
-static u8 col_trans[8] = {
-        0, 6, 4, 5,
-        2, 7, 3, 1
-};
-
-#define c_fg(sti, c) col_trans[((c>> 8) & 7)]
-#define c_bg(sti, c) col_trans[((c>>11) & 7)]
-#define c_index(sti, c) (c&0xff)
-
-static struct sti_init_flags default_init_flags = {
-	STI_WAIT, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, NULL
-};
-
-void
-sti_init_graph(struct sti_struct *sti) 
-{
-	struct sti_init_inptr_ext inptr_ext = {
-		0, { 0 }, 0, NULL
-	};
-	struct sti_init_inptr inptr = {
-		3, STI_PTR(&inptr_ext)
-	};
-	struct sti_init_outptr outptr = { 0 };
-	unsigned long flags;
-	s32 ret;
-
-	spin_lock_irqsave(&sti->lock, flags);
-
-	ret = STI_CALL(sti->init_graph, &default_init_flags, &inptr,
-		&outptr, sti->glob_cfg);
-
-	spin_unlock_irqrestore(&sti->lock, flags);
-
-	sti->text_planes = outptr.text_planes;
-}
-
-static struct sti_conf_flags default_conf_flags = {
-	STI_WAIT, 0, NULL
-};
-
-void
-sti_inq_conf(struct sti_struct *sti)
-{
-	struct sti_conf_inptr inptr = { NULL };
-	struct sti_conf_outptr_ext outptr_ext = { future_ptr: NULL };
-	struct sti_conf_outptr outptr = {
-		ext_ptr: STI_PTR(&outptr_ext)
-	};
-	unsigned long flags;
-	s32 ret;
-	
-	do {
-		spin_lock_irqsave(&sti->lock, flags);
-		ret = STI_CALL(sti->inq_conf, &default_conf_flags,
-			&inptr, &outptr, sti->glob_cfg);
-		spin_unlock_irqrestore(&sti->lock, flags);
-	} while(ret == 1);
-}
-
-void
-sti_putc(struct sti_struct *sti, int c, int y, int x)
-{
-	struct sti_font_inptr inptr = {
-		(u32) sti->font, c_index(sti, c), c_fg(sti, c), c_bg(sti, c),
-		x * sti_font_x(sti), y * sti_font_y(sti), NULL
-	};
-	struct sti_font_outptr outptr = {
-		0, NULL
-	};
-	s32 ret;
-	unsigned long flags;
-
-	do {
-		spin_lock_irqsave(&sti->lock, flags);
-		ret = STI_CALL(sti->font_unpmv, &default_font_flags,
-			&inptr, &outptr, sti->glob_cfg);
-		spin_unlock_irqrestore(&sti->lock, flags);
-	} while(ret == 1);
-}
-
-static struct sti_blkmv_flags clear_blkmv_flags = {
-	STI_WAIT, 1, 1, 0, 0, NULL
-};
-
-void
-sti_set(struct sti_struct *sti, int src_y, int src_x,
-	int height, int width, u8 color)
-{
-	struct sti_blkmv_inptr inptr = {
-		color, color,
-		src_x, src_y ,
-		src_x, src_y ,
-		width, height,
-		NULL
-	};
-	struct sti_blkmv_outptr outptr = { 0, NULL };
-	s32 ret = 0;
-	unsigned long flags;
-	
-	do {
-		spin_lock_irqsave(&sti->lock, flags);
-		ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
-			&inptr, &outptr, sti->glob_cfg);
-		spin_unlock_irqrestore(&sti->lock, flags);
-	} while(ret == 1);
-}
-
-void
-sti_clear(struct sti_struct *sti, int src_y, int src_x,
-	  int height, int width)
-{
-	struct sti_blkmv_inptr inptr = {
-		0, 0,
-		src_x * sti_font_x(sti), src_y * sti_font_y(sti),
-		src_x * sti_font_x(sti), src_y * sti_font_y(sti),
-		width * sti_font_x(sti), height* sti_font_y(sti),
-		NULL
-	};
-	struct sti_blkmv_outptr outptr = { 0, NULL };
-	s32 ret = 0;
-	unsigned long flags;
-
-	do {
-		spin_lock_irqsave(&sti->lock, flags);
-		ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
-			&inptr, &outptr, sti->glob_cfg);
-		spin_unlock_irqrestore(&sti->lock, flags);
-	} while(ret == 1);
-}
-
-static struct sti_blkmv_flags default_blkmv_flags = {
-	STI_WAIT, 0, 0, 0, 0, NULL
-};
-
-void
-sti_bmove(struct sti_struct *sti, int src_y, int src_x,
-	  int dst_y, int dst_x, int height, int width)
-{
-	struct sti_blkmv_inptr inptr = {
-		0, 0,
-		src_x * sti_font_x(sti), src_y * sti_font_y(sti),
-		dst_x * sti_font_x(sti), dst_y * sti_font_y(sti),
-		width * sti_font_x(sti), height* sti_font_y(sti),
-		NULL
-	};
-	struct sti_blkmv_outptr outptr = { 0, NULL };
-	s32 ret = 0;
-	unsigned long flags;
-
-	do {
-		spin_lock_irqsave(&sti->lock, flags);
-		ret = STI_CALL(sti->block_move, &default_blkmv_flags,
-			&inptr, &outptr, sti->glob_cfg);
-		spin_unlock_irqrestore(&sti->lock, flags);
-	} while(ret == 1);
-}
-
-
-static void __init
-sti_rom_copy(unsigned long base, unsigned long offset,
-	     unsigned long count, void *dest)
-{
-	void *savedest = dest;
-	int savecount = count;
-
-	while(count >= 4) {
-		count -= 4;
-		*(u32 *)dest = gsc_readl(base + offset);
-		offset += 4;
-		dest += 4;
-	}
-	while(count) {
-		count--;
-		*(u8 *)dest = gsc_readb(base + offset);
-		offset++;
-		dest++;
-	}
-
-	flush_kernel_dcache_range((unsigned long)dest, count);
-	flush_icache_range((unsigned long)dest, dest + count);
-}
-
-static void dump_sti_rom(struct sti_rom *rom)
-{
-	printk("STI word mode ROM type %d\n", rom->type[3]);
-	printk(" supports %d monitors\n", rom->num_mons);
-	printk(" conforms to STI ROM spec revision %d.%02x\n",
-		rom->revno[0] >> 4, rom->revno[0] & 0x0f);
-	printk(" graphics id %02x%02x%02x%02x%02x%02x%02x%02x\n",
-		rom->graphics_id[0], 
-		rom->graphics_id[1], 
-		rom->graphics_id[2], 
-		rom->graphics_id[3], 
-		rom->graphics_id[4], 
-		rom->graphics_id[5], 
-		rom->graphics_id[6], 
-		rom->graphics_id[7]);
-	printk(" font start %08x\n", rom->font_start);
-	printk(" region list %08x\n", rom->region_list);
-	printk(" init_graph %08x\n", rom->init_graph);
-	printk(" alternate code type %d\n", rom->alt_code_type);
-}
-
-static void __init sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
-				  struct sti_rom *raw_rom)
-{
-	struct sti_rom_font *raw_font;
-	struct sti_cooked_font *cooked_font;
-	struct sti_rom_font *font_start;
-	
-	cooked_font =
-		kmalloc(sizeof *cooked_font, GFP_KERNEL);
-	if(!cooked_font)
-		return;
-
-	cooked_rom->font_start = cooked_font;
-
-	raw_font = ((void *)raw_rom) + (raw_rom->font_start);
-
-	font_start = raw_font;
-	cooked_font->raw = raw_font;
-
-	while(raw_font->next_font) {
-		raw_font = ((void *)font_start) + (raw_font->next_font);
-		
-		cooked_font->next_font =
-			kmalloc(sizeof *cooked_font, GFP_KERNEL);
-		if(!cooked_font->next_font)
-			return;
-
-		cooked_font = cooked_font->next_font;
-
-		cooked_font->raw = raw_font;
-	}
-
-	cooked_font->next_font = NULL;
-}
-
-static int font_index, font_height, font_width;
-
-static int __init sti_font_setup(char *str)
-{
-	char *x;
-
-	/* we accept sti_font=10x20, sti_font=10*20 or sti_font=7 style
-	 * command lines. */
-
-	if((x = strchr(str, 'x')) || (x = strchr(str, '*'))) {
-		font_height = simple_strtoul(str, NULL, 0);
-		font_width = simple_strtoul(x+1, NULL, 0);
-	} else {
-		font_index = simple_strtoul(str, NULL, 0);
-	}
-
-	return 0;
-}
-
-__setup("sti_font=", sti_font_setup);
-
-static int __init sti_search_font(struct sti_cooked_rom *rom,
-				  int height, int width)
-{
-	struct sti_cooked_font *font;
-	int i = 0;
-	
-	for(font = rom->font_start; font; font = font->next_font, i++) {
-		if((font->raw->width == width) && (font->raw->height == height))
-			return i;
-	}
-
-	return 0;
-}
-
-static struct sti_cooked_font * __init
-sti_select_font(struct sti_cooked_rom *rom)
-{
-	struct sti_cooked_font *font;
-	int i;
-
-	if(font_width && font_height)
-		font_index = sti_search_font(rom, font_height, font_width);
-
-	for(font = rom->font_start, i = font_index;
-	    font && (i > 0);
-	    font = font->next_font, i--);
-
-	if(font)
-		return font;
-	else
-		return rom->font_start;
-}
-	
-static void __init
-sti_dump_globcfg_ext(struct sti_glob_cfg_ext *cfg)
-{
-	printk(	"monitor %d\n"
-		"in friendly mode: %d\n"
-		"power consumption %d watts\n"
-		"freq ref %d\n"
-		"sti_mem_addr %p\n",
-		cfg->curr_mon,
-		cfg->friendly_boot,
-		cfg->power,
-		cfg->freq_ref,
-		cfg->sti_mem_addr);
-}
-
-void __init
-sti_dump_globcfg(struct sti_glob_cfg *glob_cfg)
-{
-	printk(	"%d text planes\n"
-		"%4d x %4d screen resolution\n"
-		"%4d x %4d offscreen\n"
-		"%4d x %4d layout\n"
-		"regions at %08x %08x %08x %08x\n"
-		"regions at %08x %08x %08x %08x\n"
-		"reent_lvl %d\n"
-		"save_addr %p\n",
-		glob_cfg->text_planes,
-		glob_cfg->onscreen_x, glob_cfg->onscreen_y,
-		glob_cfg->offscreen_x, glob_cfg->offscreen_y,
-		glob_cfg->total_x, glob_cfg->total_y,
-		glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1],
-		glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3],
-		glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5],
-		glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7],
-		glob_cfg->reent_lvl,
-		glob_cfg->save_addr);
-	sti_dump_globcfg_ext(PTR_STI(glob_cfg->ext_ptr));
-}
-		
-static void __init
-sti_init_glob_cfg(struct sti_struct *sti, unsigned long hpa,
-		  unsigned long rom_address)
-{
-	struct sti_glob_cfg *glob_cfg;
-	struct sti_glob_cfg_ext *glob_cfg_ext;
-	void *save_addr;
-	void *sti_mem_addr;
-
-	glob_cfg = kmalloc(sizeof *sti->glob_cfg, GFP_KERNEL);
-	glob_cfg_ext = kmalloc(sizeof *glob_cfg_ext, GFP_KERNEL);
-	save_addr = kmalloc(1024 /*XXX*/, GFP_KERNEL);
-	sti_mem_addr = kmalloc(1024, GFP_KERNEL);
-
-	if((!glob_cfg) || (!glob_cfg_ext) || (!save_addr) || (!sti_mem_addr))
-		return;
-
-	memset(glob_cfg, 0, sizeof *glob_cfg);
-	memset(glob_cfg_ext, 0, sizeof *glob_cfg_ext);
-	memset(save_addr, 0, 1024);
-	memset(sti_mem_addr, 0, 1024);
-
-	glob_cfg->ext_ptr = STI_PTR(glob_cfg_ext);
-	glob_cfg->save_addr = STI_PTR(save_addr);
-	glob_cfg->region_ptrs[0] = ((sti->regions[0]>>18)<<12) + rom_address;
-	glob_cfg->region_ptrs[1] = ((sti->regions[1]>>18)<<12) + hpa;
-	glob_cfg->region_ptrs[2] = ((sti->regions[2]>>18)<<12) + hpa;
-	glob_cfg->region_ptrs[3] = ((sti->regions[3]>>18)<<12) + hpa;
-	glob_cfg->region_ptrs[4] = ((sti->regions[4]>>18)<<12) + hpa;
-	glob_cfg->region_ptrs[5] = ((sti->regions[5]>>18)<<12) + hpa;
-	glob_cfg->region_ptrs[6] = ((sti->regions[6]>>18)<<12) + hpa;
-	glob_cfg->region_ptrs[7] = ((sti->regions[7]>>18)<<12) + hpa;
-	
-	glob_cfg_ext->sti_mem_addr = STI_PTR(sti_mem_addr);
-
-	sti->glob_cfg = STI_PTR(glob_cfg);
-}
-
-/* address is a pointer to a word mode or pci rom */
-static struct sti_struct * __init
-sti_read_rom(unsigned long address)
-{
-	struct sti_struct *ret = NULL;
-	struct sti_cooked_rom *cooked = NULL;
-	struct sti_rom *raw = NULL;
-	unsigned long size;
-
-	ret = &default_sti;
-
-	if(!ret)
-		goto out_err;
-
-	cooked = kmalloc(sizeof *cooked, GFP_KERNEL);
-	raw = kmalloc(sizeof *raw, GFP_KERNEL);
-	
-	if(!(raw && cooked))
-		goto out_err;
-
-	/* reallocate raw */
-	sti_rom_copy(address, 0, sizeof *raw, raw);
-
-	dump_sti_rom(raw);
-
-	size = raw->last_addr;
-	/* kfree(raw); */
-	raw = kmalloc(size, GFP_KERNEL);
-	if(!raw)
-		goto out_err;
-	sti_rom_copy(address, 0, size, raw);
-
-	sti_cook_fonts(cooked, raw);
-#if 0
-	sti_cook_regions(cooked, raw);
-	sti_cook_functions(cooked, raw);
-#endif
-
-	if(raw->region_list) {
-		ret->regions = kmalloc(32, GFP_KERNEL);	/* FIXME */
-
-		memcpy(ret->regions, ((void *)raw)+raw->region_list, 32);
-	}
-
-	address = virt_to_phys(raw);
-
-	ret->font_unpmv = address+(raw->font_unpmv & 0x03ffffff);
-	ret->block_move = address+(raw->block_move & 0x03ffffff);
-	ret->init_graph = address+(raw->init_graph & 0x03ffffff);
-	ret->inq_conf = address+(raw->inq_conf     & 0x03ffffff);
-
-	ret->rom = cooked;
-	ret->rom->raw = raw;
-
-	ret->font = (struct sti_rom_font *) virt_to_phys(sti_select_font(ret->rom)->raw);
-
-	return ret;
-
-out_err:
-	if(raw)
-		kfree(raw);
-	if(cooked)
-		kfree(cooked);
-
-	return NULL;
-}
-
-static struct sti_struct * __init
-sti_try_rom(unsigned long address, unsigned long hpa)
-{
-	struct sti_struct *sti = NULL;
-	u16 sig;
-	
-test_rom:
-	/* if we can't read the ROM, bail out early.  Not being able
-	 * to read the hpa is okay, for romless sti */
-	if(pdc_add_valid((void*)address))
-		return NULL;
-
-	printk("found potential STI ROM at %08lx\n", address);
-
-	sig = le16_to_cpu(gsc_readw(address));
-
-	if((sig==0x55aa) || (sig==0xaa55)) {
-		address += le32_to_cpu(gsc_readl(address+8));
-		printk("sig %04x, PCI STI ROM at %08lx\n",
-		       sig, address);
-
-		goto test_rom;
-	}
-
-	if((sig&0xff) == 0x01) {
-		printk("STI byte mode ROM at %08lx, ignored\n",
-		       address);
-
-		sti = NULL;
-	}
-
-	if(sig == 0x0303) {
-		printk("STI word mode ROM at %08lx\n",
-		       address);
-
-		sti = sti_read_rom(address);
-	}
-
-	if (!sti)
-		return NULL;
-
-	/* this is hacked.  We need a better way to find out the HPA for
-	 * romless STI (eg search for the graphics devices we know about
-	 * by sversion) */
-	if (!pdc_add_valid((void *)0xf5000000)) printk("f4000000 g\n");
-	if (!pdc_add_valid((void *)0xf7000000)) printk("f6000000 g\n");
-	if (!pdc_add_valid((void *)0xf9000000)) printk("f8000000 g\n");
-	if (!pdc_add_valid((void *)0xfb000000)) printk("fa000000 g\n");
-	sti_init_glob_cfg(sti, hpa, address);
-
-	sti_init_graph(sti);
-
-	sti_inq_conf(sti);
-	sti_dump_globcfg(PTR_STI(sti->glob_cfg));
-
-	return sti;
-}
-
-static unsigned long sti_address;
-static unsigned long sti_hpa;
-
-/* XXX: should build a list of STI ROMs */
-struct sti_struct * __init
-sti_init_roms(void)
-{
-	struct sti_struct *tmp = NULL, *sti = NULL;
-
-	/* handle the command line */
-	if (sti_address && sti_hpa) {
-		return sti_try_rom(sti_address, sti_hpa);
-	}
-
-	/* 712, 715, some other boxes don't have a separate STI ROM,
-	 * but use part of the regular flash */
-	if (PAGE0->proc_sti) {
-		printk("STI ROM from PDC at %08x\n", PAGE0->proc_sti);
-		if (!pdc_add_valid((void *)0xf9000000))
-			sti = sti_try_rom(PAGE0->proc_sti, 0xf8000000);
-		else if (!pdc_add_valid((void *)0xf5000000))
-			sti = sti_try_rom(PAGE0->proc_sti, 0xf4000000);
-		else if (!pdc_add_valid((void *)0xf7000000))
-			sti = sti_try_rom(PAGE0->proc_sti, 0xf6000000);
-		else if (!pdc_add_valid((void *)0xfb000000))
-			sti = sti_try_rom(PAGE0->proc_sti, 0xfa000000);
-
-	}
-
-	/* standard locations for GSC graphic devices */
-	if (!pdc_add_valid((void *)0xf4000000))
-		tmp = sti_try_rom(0xf4000000, 0xf4000000);
-	sti = tmp ? tmp : sti;
-	if (!pdc_add_valid((void *)0xf6000000))
-		tmp = sti_try_rom(0xf6000000, 0xf6000000);
-	sti = tmp ? tmp : sti;
-	if (!pdc_add_valid((void *)0xf8000000))
-		tmp = sti_try_rom(0xf8000000, 0xf8000000);
-	sti = tmp ? tmp : sti;
-	if (!pdc_add_valid((void *)0xfa000000))
-		tmp = sti_try_rom(0xfa000000, 0xfa000000);
-	sti = tmp ? tmp : sti;
-
-	return sti;
-}
-
-static int __init
-sti_setup(char *str)
-{
-	char *end;
-
-	if(strcmp(str, "pdc") == 0) {
-		sti_address = PAGE0->proc_sti;
-
-		return 1;
-	} else {
-		sti_address = simple_strtoul(str, &end, 16);
-
-		if((end == str) || (sti_address < 0xf0000000)) {
-			sti_address = 0;
-			return 0;
-		}
-
-		sti_hpa = sti_address;
-
-		return 1;
-	}
-
-	return 0;
-}
-
-__setup("sti=", sti_setup);
-
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/stifb.c linux-2.4.20/drivers/video/stifb.c
--- linux-2.4.19/drivers/video/stifb.c	2001-02-09 19:30:23.000000000 +0000
+++ linux-2.4.20/drivers/video/stifb.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,230 +0,0 @@
-/*
- * linux/drivers/video/stifb.c - Generic frame buffer driver for HP
- * workstations with STI (standard text interface) video firmware.
- *
- * Based on:
- * linux/drivers/video/artistfb.c -- Artist frame buffer driver
- *
- *	Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
- *
- *  based on skeletonfb, which was
- *	Created 28 Dec 1997 by Geert Uytterhoeven
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.  */
-
-/*
- * Notes:
- *
- * This driver assumes that the video has been set up in 1bpp mode by
- * the firmware.  Since HP video tends to be planar rather than
- * packed-pixel this will probably work anyway even if it isn't.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-
-#include <video/fbcon.h>
-
-#include "sti.h"
-
-static struct fb_ops stifb_ops;
-
-struct stifb_info {
-	struct fb_info_gen gen;
-	struct sti_struct *sti;
-};
-
-struct stifb_par {
-};
-
-static struct stifb_info fb_info;
-static struct display disp;
-
-int stifb_init(void);
-int stifb_setup(char*);
-
-extern struct display_switch fbcon_sti;
-
-/* ------------------- chipset specific functions -------------------------- */
-
-static int
-sti_encode_fix(struct fb_fix_screeninfo *fix,
-	       const void *par, struct fb_info_gen *info)
-{
-	/* XXX: what about smem_len? */
-	fix->smem_start = PTR_STI(fb_info.sti->glob_cfg)->region_ptrs[1];
-	fix->type = FB_TYPE_PLANES; /* well, sort of */
-
-	return 0;
-}
-
-static int
-sti_decode_var(const struct fb_var_screeninfo *var,
-	void *par, struct fb_info_gen *info)
-{
-	return 0;
-}
-
-static int
-sti_encode_var(struct fb_var_screeninfo *var,
-	       const void *par, struct fb_info_gen *info)
-{
-	var->xres = PTR_STI(fb_info.sti->glob_cfg)->onscreen_x;
-	var->yres = PTR_STI(fb_info.sti->glob_cfg)->onscreen_y;
-	var->xres_virtual = PTR_STI(fb_info.sti->glob_cfg)->total_x;
-	var->yres_virtual = PTR_STI(fb_info.sti->glob_cfg)->total_y;
-	var->xoffset = var->yoffset = 0;
-
-	var->bits_per_pixel = 1;
-	var->grayscale = 0;
-
-	return 0;
-}
-
-static void
-sti_get_par(void *par, struct fb_info_gen *info)
-{
-}
-
-static void
-sti_set_par(const void *par, struct fb_info_gen *info)
-{
-}
-
-static int
-sti_getcolreg(unsigned regno, unsigned *red, unsigned *green,
-	      unsigned *blue, unsigned *transp, struct fb_info *info)
-{
-	return 0;
-}
-
-static int
-sti_setcolreg(unsigned regno, unsigned red, unsigned green,
-	      unsigned blue, unsigned transp, struct fb_info *info)
-{
-	return 0;
-}
-
-static void
-sti_set_disp(const void *par, struct display *disp,
-	     struct fb_info_gen *info)
-{
-	disp->screen_base =
-		(void *) PTR_STI(fb_info.sti->glob_cfg)->region_ptrs[1];
-	disp->dispsw = &fbcon_sti;
-}
-
-static void
-sti_detect(void)
-{
-}
-
-static int
-sti_blank(int blank_mode, const struct fb_info *info)
-{
-	return 0;
-}
-
-/* ------------ Interfaces to hardware functions ------------ */
-
-struct fbgen_hwswitch sti_switch = {
-	detect:		sti_detect,
-	encode_fix:	sti_encode_fix,
-	decode_var:	sti_decode_var,
-	encode_var:	sti_encode_var,
-	get_par:	sti_get_par,
-	set_par:	sti_set_par,
-	getcolreg:	sti_getcolreg,
-	setcolreg:	sti_setcolreg,
-	pan_display:	NULL,
-	blank:		sti_blank,
-	set_disp:	sti_set_disp
-};
-
-
-/* ------------ Hardware Independent Functions ------------ */
-
-    /*
-     *  Initialization
-     */
-
-int __init
-stifb_init(void)
-{
-	printk("searching for word mode STI ROMs\n");
-	/* XXX: in the future this will return a list of ROMs */
-	if ((fb_info.sti = sti_init_roms()) == NULL)
-		return -ENXIO;
-
-	fb_info.gen.info.node = -1;
-	fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
-	fb_info.gen.info.fbops = &stifb_ops;
-	fb_info.gen.info.disp = &disp;
-	fb_info.gen.info.changevar = NULL;
-	fb_info.gen.info.switch_con = &fbgen_switch;
-	fb_info.gen.info.updatevar = &fbgen_update_var;
-	fb_info.gen.info.blank = &fbgen_blank;
-	strcpy(fb_info.gen.info.modename, "STI Generic");
-	fb_info.gen.fbhw = &sti_switch;
-	fb_info.gen.fbhw->detect();
-
-	/* This should give a reasonable default video mode */
-	fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
-	fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
-	fbgen_set_disp(-1, &fb_info.gen);
-	fbgen_install_cmap(0, &fb_info.gen);
-	pdc_console_die();
-	if (register_framebuffer(&fb_info.gen.info) < 0)
-		return -EINVAL;
-
-	printk(KERN_INFO "fb%d: %s frame buffer device\n",
-		GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename);
-
-	return 0;
-}
-
-
-    /*
-     *  Cleanup
-     */
-
-void
-stifb_cleanup(struct fb_info *info)
-{
-	printk("stifb_cleanup: you're on crack\n");
-}
-
-
-int __init
-stifb_setup(char *options)
-{
-	/* XXX: we should take the resolution, bpp as command line arguments. */
-	return 0;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-
-static struct fb_ops stifb_ops = {
-	owner:		THIS_MODULE,
-	fb_open:	NULL,
-	fb_release:	NULL,
-	fb_get_fix:	fbgen_get_fix,
-	fb_get_var:	fbgen_get_var,
-	fb_set_var:	fbgen_set_var,
-	fb_get_cmap:	fbgen_get_cmap,
-	fb_set_cmap:	fbgen_set_cmap,
-	fb_pan_display:	fbgen_pan_display,
-	fb_ioctl:	NULL
-};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/tridentfb.c linux-2.4.20/drivers/video/tridentfb.c
--- linux-2.4.19/drivers/video/tridentfb.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/tridentfb.c	2002-10-29 11:18:40.000000000 +0000
@@ -56,11 +56,11 @@
 
 struct tridentfb_info {
 	struct fb_info_gen gen;
-	unsigned int fbmem_virt;	//framebuffer virtual memory address
-	unsigned int fbmem;		//framebuffer physical memory address
+	unsigned long fbmem_virt;	//framebuffer virtual memory address
+	unsigned long fbmem;		//framebuffer physical memory address
 	unsigned int memsize;		//size of fbmem
-	unsigned int io;		//io space address
-	unsigned int io_virt;		//iospace virtual memory address
+	unsigned long io;		//io space address
+	unsigned long io_virt;		//iospace virtual memory address
 	unsigned int nativex;		//flat panel xres
 	struct tridentfb_par currentmode;
 	unsigned char eng_oper;		//engine operation...
@@ -1321,7 +1321,7 @@
 		return -1;
 	}
 
-	fb_info.io_virt = (unsigned int)ioremap_nocache(fb_info.io, trident_iosize);
+	fb_info.io_virt = (unsigned long)ioremap_nocache(fb_info.io, trident_iosize);
 
 	if (!fb_info.io_virt) {
 		release_region(fb_info.io, trident_iosize);
@@ -1337,7 +1337,7 @@
 		return -1;
 	}
 
-	fb_info.fbmem_virt = (unsigned int)ioremap_nocache(fb_info.fbmem, fb_info.memsize);
+	fb_info.fbmem_virt = (unsigned long)ioremap_nocache(fb_info.fbmem, fb_info.memsize);
 
 	if (!fb_info.fbmem_virt) {
 		release_mem_region(fb_info.fbmem, fb_info.memsize);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/tx3912fb.c linux-2.4.20/drivers/video/tx3912fb.c
--- linux-2.4.19/drivers/video/tx3912fb.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/tx3912fb.c	2002-10-29 11:18:48.000000000 +0000
@@ -10,6 +10,7 @@
  *
  *  Framebuffer for LCD controller in TMPR3912/05 and PR31700 processors
  */
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/tx3912fb.h linux-2.4.20/drivers/video/tx3912fb.h
--- linux-2.4.19/drivers/video/tx3912fb.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/video/tx3912fb.h	2002-10-29 11:18:32.000000000 +0000
@@ -9,6 +9,7 @@
  *
  *  Includes for TMPR3912/05 and PR31700 LCD controller registers
  */
+#include <linux/config.h>
 
 /*
  * Begin platform specific configurations
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/vesafb.c linux-2.4.20/drivers/video/vesafb.c
--- linux-2.4.19/drivers/video/vesafb.c	2001-11-14 22:52:20.000000000 +0000
+++ linux-2.4.20/drivers/video/vesafb.c	2002-10-29 11:18:32.000000000 +0000
@@ -109,6 +109,7 @@
 static int vesafb_pan_display(struct fb_var_screeninfo *var, int con,
                               struct fb_info *info)
 {
+#ifdef __i386__
 	int offset;
 
 	if (!ypan)
@@ -130,6 +131,7 @@
                   "c" (offset),         /* ECX */
                   "d" (offset >> 16),   /* EDX */
                   "D" (&pmi_start));    /* EDI */
+#endif
 	return 0;
 }
 
@@ -302,6 +304,7 @@
 
 static void vesa_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
 {
+#ifdef i386
 	struct { u_char blue, green, red, pad; } entry;
 
 	if (pmi_setpal) {
@@ -325,6 +328,8 @@
 		outb_p(green >> 10, dac_val);
 		outb_p(blue  >> 10, dac_val);
 	}
+#endif
+
 }
 
 #endif
@@ -519,6 +524,10 @@
 	video_visual = (video_bpp == 8) ?
 		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
 
+#ifndef __i386__
+	screen_info.vesapm_seg = 0;
+#endif
+
 	if (!request_mem_region(video_base, video_size, "vesafb")) {
 		printk(KERN_WARNING
 		       "vesafb: abort, cannot reserve video memory at 0x%lx\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/video/vga.h linux-2.4.20/drivers/video/vga.h
--- linux-2.4.19/drivers/video/vga.h	2000-12-11 21:17:24.000000000 +0000
+++ linux-2.4.20/drivers/video/vga.h	2002-10-29 11:18:33.000000000 +0000
@@ -22,6 +22,19 @@
 #include <asm/io.h>
 #ifndef CONFIG_AMIGA
 #include <asm/vga.h>
+#else
+/*
+ * FIXME
+ * Ugh, we don't have PCI space, so map readb() and friends to use Zorro space
+ * for MMIO accesses. This should make clgenfb work again on Amiga
+ */
+#define inb(port)	0
+#define inw(port)	0
+#define outb(port, val)	do { } while (0)
+#define outw(port, val)	do { } while (0)
+#define readb		z_readb
+#define writeb		z_writeb
+#define writew		z_writew
 #endif
 #include <asm/byteorder.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/zorro/proc.c linux-2.4.20/drivers/zorro/proc.c
--- linux-2.4.19/drivers/zorro/proc.c	2000-03-07 18:52:41.000000000 +0000
+++ linux-2.4.20/drivers/zorro/proc.c	2002-10-29 11:18:32.000000000 +0000
@@ -48,7 +48,7 @@
 	struct proc_dir_entry *dp = ino->u.generic_ip;
 	struct zorro_dev *dev = dp->data;
 	struct ConfigDev cd;
-	int pos = *ppos;
+	loff_t pos = *ppos;
 
 	if (pos >= sizeof(struct ConfigDev))
 		return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/drivers/zorro/zorro.ids linux-2.4.20/drivers/zorro/zorro.ids
--- linux-2.4.19/drivers/zorro/zorro.ids	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/drivers/zorro/zorro.ids	2002-10-29 11:18:49.000000000 +0000
@@ -4,7 +4,7 @@
 #	Maintained by Geert Uytterhoeven <zorro@linux-m68k.org>
 #	If you have any new entries, please send them to the maintainer.
 #
-#	$Id: zorro.ids,v 1.17 2001/10/25 08:21:39 geert Exp $
+#	$Id: zorro.ids,v 1.19 2002/10/14 13:08:58 geert Exp $
 #
 
 # Manufacturers and Products. Please keep sorted.
@@ -42,7 +42,7 @@
 	5000  A2620 68020 [Accelerator and RAM Expansion]
 	5100  A2630 68030 [Accelerator and RAM Expansion]
 	5400  A4091 [SCSI Host Adapter]
-	5a00  A2065 [Ethernet Card]]
+	5a00  A2065 [Ethernet Card]
 	6000  Romulator Card
 	6100  A3000 Test Fixture [Miscellaneous Expansion Card]
 	6700  A2386-SX [ISA Bus Bridge]
@@ -56,7 +56,7 @@
 02ff  Kolff Computer Supplies
 	0000  KCS Power PC [ISA Bus Bridge]
 03ec  Cardco Ltd.
-	0400  Kronos 2000 [SCSI Host Adapter]]
+	0400  Kronos 2000 [SCSI Host Adapter]
 	0c00  A1000 [SCSI Host Adapter]
 	0e00  Escort [SCSI Host Adapter]
 	f500  A2410 HiRes [Graphics Card]
@@ -364,7 +364,13 @@
 	1300  Warp Engine 40xx [Accelerator, SCSI Host Adapter and RAM Expansion]
 089e  ElBox Computer
 	0600  1200/4 [RAM Expansion]
-	1900  PowerFlyer [IDE Interface]
+	0800  FastATA 1200 [IDE Interface]
+	1200  FastATA 1200 [IDE Interface]
+	1300  FastATA 1200 [IDE Interface]
+	1800  FastATA 1200 [IDE Interface]
+	1900  FastATA 4000 [IDE Interface]
+	1d00  FastATA 4000 [IDE Interface]
+	1e00  FastATA ZIV [IDE Interface]
 0a00  Harms Professional
 	1000  030 Plus [Accelerator]
 	d000  3500 Professional [Accelerator and RAM Expansion]
@@ -384,7 +390,7 @@
 	ff00  Pixel64 RAM [Graphics Card]
 1212  Individual Computers
 	0000  Buddha [IDE Interface]
-	1700  X-Surf [Ethernet Card]
+	1700  X-Surf [Ethernet Card and IDE Interface]
 	2a00  Catweasel [IDE Interface and Floppy Controller]
 1248  Kupke
 	0100  Golem HD 3000 [HD Controller]
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/Config.in linux-2.4.20/fs/Config.in
--- linux-2.4.19/fs/Config.in	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/Config.in	2002-10-29 11:18:33.000000000 +0000
@@ -9,16 +9,19 @@
 tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS
 
 tristate 'Reiserfs support' CONFIG_REISERFS_FS
-dep_mbool '  Have reiserfs do extra internal checking' CONFIG_REISERFS_CHECK $CONFIG_REISERFS_FS
+dep_mbool '  Enable reiserfs debug mode' CONFIG_REISERFS_CHECK $CONFIG_REISERFS_FS
 dep_mbool '  Stats in /proc/fs/reiserfs' CONFIG_REISERFS_PROC_INFO $CONFIG_REISERFS_FS
 
-dep_tristate 'ADFS file system support' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
+dep_tristate 'ADFS file system support (EXPERIMENTAL)' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
 dep_mbool '  ADFS write support (DANGEROUS)' CONFIG_ADFS_FS_RW $CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
 
 dep_tristate 'Amiga FFS file system support (EXPERIMENTAL)' CONFIG_AFFS_FS $CONFIG_EXPERIMENTAL
 
 dep_tristate 'Apple Macintosh file system support (EXPERIMENTAL)' CONFIG_HFS_FS $CONFIG_EXPERIMENTAL
 
+dep_tristate 'BeOS file systemv(BeFS) support (read only) (EXPERIMENTAL)' CONFIG_BEFS_FS $CONFIG_EXPERIMENTAL
+dep_mbool '  Debug Befs' CONFIG_BEFS_DEBUG $CONFIG_BEFS_FS
+
 dep_tristate 'BFS file system support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL
 
 tristate 'Ext3 journalling file system support' CONFIG_EXT3_FS
@@ -51,6 +54,10 @@
 dep_mbool '  Microsoft Joliet CDROM extensions' CONFIG_JOLIET $CONFIG_ISO9660_FS
 dep_mbool '  Transparent decompression extension' CONFIG_ZISOFS $CONFIG_ISO9660_FS
 
+tristate 'JFS filesystem support' CONFIG_JFS_FS
+dep_mbool '  JFS debugging' CONFIG_JFS_DEBUG $CONFIG_JFS_FS
+dep_mbool '  JFS statistics' CONFIG_JFS_STATISTICS $CONFIG_JFS_FS
+
 tristate 'Minix fs support' CONFIG_MINIX_FS
 
 tristate 'FreeVxFS file system support (VERITAS VxFS(TM) compatible)' CONFIG_VXFS_FS
@@ -92,13 +99,14 @@
    comment 'Network File Systems'
 
    dep_tristate 'Coda file system support (advanced network fs)' CONFIG_CODA_FS $CONFIG_INET
-   dep_tristate 'InterMezzo file system support (experimental, replicating fs)' CONFIG_INTERMEZZO_FS $CONFIG_INET $CONFIG_EXPERIMENTAL
+   dep_tristate 'InterMezzo file system support (replicating fs) (EXPERIMENTAL)' CONFIG_INTERMEZZO_FS $CONFIG_INET $CONFIG_EXPERIMENTAL
    dep_tristate 'NFS file system support' CONFIG_NFS_FS $CONFIG_INET
    dep_mbool '  Provide NFSv3 client support' CONFIG_NFS_V3 $CONFIG_NFS_FS
    dep_bool '  Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP
 
    dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET
    dep_mbool '  Provide NFSv3 server support' CONFIG_NFSD_V3 $CONFIG_NFSD
+   dep_mbool '  Provide NFS server over TCP support (EXPERIMENTAL)' CONFIG_NFSD_TCP $CONFIG_NFSD $CONFIG_EXPERIMENTAL
 
    if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
       define_tristate CONFIG_SUNRPC y
@@ -146,15 +154,6 @@
 else
    define_tristate CONFIG_ZISOFS_FS n
 fi
-if [ "$CONFIG_CRAMFS" = "y" -o "$CONFIG_ZISOFS_FS" = "y" ]; then
-   define_tristate CONFIG_ZLIB_FS_INFLATE y
-else
-  if [ "$CONFIG_CRAMFS" = "m" -o "$CONFIG_ZISOFS_FS" = "m" ]; then
-     define_tristate CONFIG_ZLIB_FS_INFLATE m
-  else
-     define_tristate CONFIG_ZLIB_FS_INFLATE n
-  fi
-fi
 
 mainmenu_option next_comment
 comment 'Partition Types'
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/Makefile linux-2.4.20/fs/Makefile
--- linux-2.4.19/fs/Makefile	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.20/fs/Makefile	2002-10-29 11:18:48.000000000 +0000
@@ -14,7 +14,7 @@
 		super.o block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \
 		fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
 		dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
-		filesystems.o namespace.o seq_file.o
+		filesystems.o namespace.o seq_file.o xattr.o
 
 ifeq ($(CONFIG_QUOTA),y)
 obj-y += dquot.o
@@ -29,7 +29,6 @@
 subdir-$(CONFIG_EXT3_FS)	+= ext3    # Before ext2 so root fs can be ext3
 subdir-$(CONFIG_JBD)		+= jbd
 subdir-$(CONFIG_EXT2_FS)	+= ext2
-subdir-$(CONFIG_ZLIB_FS_INFLATE) += inflate_fs
 subdir-$(CONFIG_CRAMFS)		+= cramfs
 subdir-$(CONFIG_RAMFS)		+= ramfs
 subdir-$(CONFIG_CODA_FS)	+= coda
@@ -67,6 +66,8 @@
 subdir-$(CONFIG_REISERFS_FS)	+= reiserfs
 subdir-$(CONFIG_DEVPTS_FS)	+= devpts
 subdir-$(CONFIG_SUN_OPENPROMFS)	+= openpromfs
+subdir-$(CONFIG_BEFS_FS)	+= befs
+subdir-$(CONFIG_JFS_FS)		+= jfs
 
 
 obj-$(CONFIG_BINFMT_AOUT)	+= binfmt_aout.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/befs/ChangeLog linux-2.4.20/fs/befs/ChangeLog
--- linux-2.4.19/fs/befs/ChangeLog	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/befs/ChangeLog	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,417 @@
+Version 0.92 (2002-03-29)
+==========
+* Minor cleanup. Ran Lindent on the sources.
+
+Version 0.92 (2002-03-27)
+==========
+* Fixed module makefile problem. It was not compiling all the correct 
+    source files!
+* Removed duplicated function definition
+* Fixed potential null pointer dereference when reporting an error
+
+Version 0.91 (2002-03-26)
+==========
+* Oy! Fixed stupid bug that would cause an unresolved symbol error.
+	Thanks to Laszlo Boszormenyi for pointing this out to me.
+
+Version 0.9 (2002-03-14)
+==========
+* Added Sergey S. Kostyliov's patch to eliminate memcpy() overhead
+	from b+tree operations. Changes the befs_read_datastream() interface.
+
+* Segregated the functions that interface directly with the linux  vfs 
+	interface into their own file called linuxvfs.c. [WD]
+
+Version 0.64 (2002-02-07)
+==========
+* Did the string comparision really right this time (btree.c) [WD]
+
+* Fixed up some places where I assumed that a long int could hold
+	a pointer value. (btree.c) [WD]
+
+* Andrew Farnham <andrewfarnham@uq.net.au> pointed out that the module
+	wouldn't work on older (<2.4.10) kernels due to an unresolved symbol.
+	This is bad, since 2.4.9 is still the current RedHat kernel. I added
+	a workaround for this problem (compatability.h) [WD]
+
+* Sergey S. Kostyliov made befs_find_key() use a binary search to find 
+	keys within btree nodes, rather than the linear search we were using 
+	before. (btree.c) [Sergey S. Kostyliov <rathamahata@php4.ru>]
+
+* Made a debian package of the source for use with kernel-package. [WD]
+
+
+Version 0.63 (2002-01-31)
+==========
+* Fixed bug in befs_find_brun_indirect() that would result in the wrong
+	block being read. It was introduced when adding byteswapping in 
+	0.61. (datastream.c) [WD]
+
+* Fixed a longstanding bug in befs_find_key() that would result in it 
+	finding the first key that is a substring of the string it is searching
+	for. For example, this would cause files in the same directory with 
+	names like file1 and file2 to mysteriously be duplicates of each other 
+	(because they have the same inode number). Many thanks to Pavel Roskin 
+	for reporting this serious bug!!!
+	(btree.c) [WD]
+
+* Added support for long symlinks, after Axel Dorfler explained up how 
+	they work. I had forgotten all about them. (inode.c, symlink.c) [WD]
+
+* Documentation improvements in source. [WD]
+
+* Makefile fix for independant module when CONFIG_MODVERSION is set in 
+	kernel config [Pavel Roskin <proski@gnu.org>]
+
+* Compile warning fix for namei.c. [Sergey S. Kostyliov <rathamahata@php4.ru>]
+
+
+Version 0.62
+==========
+* Fixed makefile for module install [WD]
+
+
+Version 0.61 (2002-01-20)
+==========
+* Made functions in endian.h to do the correct byteswapping, no matter
+	the arch. [WD]
+
+* Abbandoned silly checks for a NULL superblock pointer in debug.c. [WD]
+
+* Misc code cleanups. Also cleanup of this changelog file. [WD]
+
+* Added byteswapping to all metadata reads from disk.
+	Uses the functions from endian.h [WD]
+
+* Remove the typedef of struct super_block to vfs_sb, as it offended
+	certain peoples' aesthetic sense. [WD]
+
+* Ditto with the befs_read_block() interface. [WD]
+ 
+
+Version 0.6 (2001-12-15)
+==========
+* Cleanup of NLS functions (util.c) [WD]
+
+* Make directory lookup/read use the NLS if an iocharset is provided. [WD]
+
+* Fixed stupid bug where specifying the uid or gid mount options as '0' 
+	would result in the filesystem using the on-disk uid and gid. [WD]
+
+* Added mount option to control debug printing. 
+	The option is, simply enough, 'debug'. 
+	(super.c, debug.c) [WD]
+
+* Removed notion of btree handle from btree.c. It was unessisary, as the 
+	linux VFS doesn't allow us to keep any state between calls. Updated 
+	dir.c, namei.c befs_fs.h to account for it. [WD]
+
+* Improved handleing of overflow nodes when listing directories. 
+	Now works for overflow nodes hanging off of nodes other than the root 
+	node. This is the cleaner solution to Brent Miszalaski's problem. [WD]
+
+* Added new debug/warning/error print functions in debug.c. 
+	More flexible. Will soon be controllable at mount time 
+	(see TODO). [WD]
+
+* Rewrote datastream positon lookups.
+	(datastream.c) [WD]
+
+* Moved the TODO list to it's own file.
+
+
+Version 0.50 (2001-11-13)
+==========
+* Added workaround for mis-understanding of the nature of the b+trees used 
+	in directories. A cleaner solution will come after I've thought about it 
+	for a while. Thanks to Brent Miszalaski for finding and reporting this bug. 
+	(btree.c) [WD]
+
+* Minor cleanups
+
+* Added test for "impossible" condition of empty internal nodes in 
+	seekleaf() in btree.c [WD]
+
+* Implemented the abstracted read_block() in io.c [WD]
+
+* Cleaned up the inode validation in inode.c [WD]
+
+* Anton Altaparmakov figured out (by asking Linus :) ) what was causing the 
+ 	hanging disk io problem. It turns out you need to have the sync_pages 
+	callback defined in your address_space_ops, even if it just uses the 
+	default linux-supplied implementation. Fixed. Works now.
+	(file.c) [WD]
+
+* Anton Altaparmakov and Christoph Hellwig alerted me to the fact that 
+	filesystem code should be using GFP_NOFS instead of GFP_KERNEL as the 
+	priority parameter to kmalloc(). Fixed. 
+	(datastream.c, btree.c super.c inode.c) [WD]
+
+* Anton also told me that the blocksize is not allowed to be larger than 
+	the page size in linux, which is 4k i386. Oops. Added a test for 
+	(blocksize > PAGE_SIZE), and refuse to mount in that case. What this 
+	practicaly means is that 8k blocksize volumes won't work without a major
+	restructuring of the driver (or an alpha or other 64bit hardware). [WD]
+
+* Cleaned up the befs_count_blocks() function. Much smarter now. 
+	And somewhat smaller too. [WD]
+
+* Made inode allocations use a slab cache 
+	(super.c inode.c) [WD]
+
+* Moved the freeing of the private inode section from put_inode() to 
+	clear_inode(). This fixes a potential free twice type bug. Put_inode() 
+	can be called multiple times for each inode struct. [WD]
+
+* Converted all non vfs-callback functions to use befs_sb_info as the 
+	superblock type, rather than struct super_block. This is for 
+	portablity. [WD]
+
+* Fixed a couple of compile warnings due to use of malloc.h, when slab.h 
+	is the new way. (inode.c, super.c) [WD]
+
+* Fixed erronous includes of linux/befs_fs_i.h and linux/befs_fs_sb.h 
+	in inode.c [WD]
+
+Version 0.45 (2001-10-29)
+==========
+* Added functions to get the private superblock and inode structures from 
+	their enclosing public structures. Switched all references to the 
+	private portions to use them. (many files) [WD]
+
+* Made read_super and read_inode allocate the private portions of those 
+	structures into the generic pointer fields of the public structures 
+	with kmalloc(). put_super and put_inode free them. This allows us not 
+	to have to touch the definitions of the public structures in 
+	include/linux/fs.h. Also, befs_inode_info is huge (becuase of the 
+	symlink string). (super.c, inode.c, befs_fs.h) [WD]
+
+* Fixed a thinko that was corrupting file reads after the first block_run 
+	is done being read. (datastream.c) [WD]
+
+* Removed fsync() hooks, since a read-only filesystem doesn't need them. 
+	[Christoph Hellwig].
+
+* Fixed befs_readlink() (symlink.c) [Christoph Hellwig].
+
+* Removed all the Read-Write stuff. I'll redo it when it is time to add 
+	write support (various files) [WD].
+
+* Removed prototypes for functions who's definitions have been removed 
+	(befs_fs.h) [WD].
+
+
+Version 0.4 (2001-10-28)
+==========
+* Made it an option to use the old non-pagecache befs_file_read() for 
+	testing purposes. (fs/Config.in)
+
+* Fixed unused variable warnings when compiling without debugging.
+
+* Fixed a bug where the inode and super_block didn't get their blockbits 
+	fields set (inode.c and super.c). 
+
+* Release patch version 11. AKA befs-driver version 0.4.
+
+* Thats right. New versioning scheme. 
+	I've done some serious testing on it now (on my box anyhow), and it 
+	seems stable and not outragously slow. Existing features are more-or-less 
+	correct (see TODO list). But it isn't 1.0 yet. I think 0.4 gives me some 
+	headroom before the big 1.0.
+
+
+2001-10-26
+==========
+* Fixed date format in this file. Was I smoking crack?
+
+* Removed old datastream code from file.c, since it is nolonger used.
+
+* Generic_read_file() is now used to read regular file data. 
+	It doesn't chew up the buffer cache (it does page io instead), and seems 
+	to be about as fast (even though it has to look up each file block 
+	indivdualy). And it knows about doing readahead, which is a major plus. 
+	So it does i/o in much larger chunks. It is the correct linux way. It 
+	uses befs_get_block() by way of befs_readpage() to find the disk offsets 
+	of blocks, which in turn calls befs_fpos2brun() in datastream.c to do 
+	the hard work of finding the disk block number.
+
+* Changed method of checking for a dirty filesystem in befs_read_super 
+	(super.c). Now we check to see if log_start and log_end differ. If so, 
+	the journal needs to be replayed, and the filesystem cannot be mounted.
+
+* Fixed an extra instance of MOD_DEC_USE_COUNT in super.c
+
+* Fixed a problem with reading the superblock on devices with large sector 
+	sizes (such as cdroms) on linux 2.4.10 and up.
+
+2001-10-24
+==========
+* Fix nasty bug in converting block numbers to struct befs_inode_addr. 
+	Subtle, because the old version was only sometimes wrong. 
+	Probably responsible for lots of problems. (inode.c)
+
+* Fix bug with reading an empty directory. (btree.c and dir.c)
+
+* This one looks good. Release patch version 10
+
+2001-10-23
+==========
+* Added btree searching function.
+
+* Use befs_btree_find in befs_lookup (namei.c)
+
+* Additional comments in btree.c
+
+2001-10-22
+==========
+* Added B+tree reading functions (in btree.c). 
+	Made befs_readdir() use them them instead of the cruft in index.c.
+
+2001-09-11
+==========
+* Converted befs_read_file() to use the new datastream code.
+
+* Finally updated the README file.
+
+* Added many comments.
+
+* Posted version 6
+
+* Removed byte-order conversion code. 
+	I have no intention of supporting it, and it was very ugly. 
+	Flow control with #ifdef (ugh). Maybe I'll redo it once 
+	native byteorder works 100%.
+
+2001-09-10
+==========
+* Finished implementing read_datastream()
+
+* made befs_read_brun() more general
+	Supports an offset to start at and a max bytes to read
+	Added a wrapper function to give the old call
+
+2001-09-30
+==========
+* Discovered that the datastream handleing code in file.c is quite deficient 
+	in several respects. For one thing, it doesn't deal with indirect blocks
+
+* Rewrote datastream handleing.
+
+* Created io.c, for io related functions.
+	Previously, the befs_bread() funtions lived in file.c
+	Created the befs_read_brun() function.
+
+
+2001-09-07
+==========
+* Made a function to actually count the number of fs blocks used by a file.
+	And helper functions.
+	(fs/befs/inode.c)
+
+2001-09-05
+==========
+* Fixed a misunderstanding of the inode fields. 
+	This fixed the problmem with wrong file sizes from du and others.
+	The i_blocks field of the inode struct is not the nuber of blocks for the 
+	inode, it is the number of blocks for the file.	Also, i_blksize is not
+	nessisarily the size of the inode, although in  practice it works out.
+	Changed to blocksize of filesystem.
+	(fs/befs/inode.c)
+
+* Permanently removed code that had been provisionally ifdefed out of befs_fs.h
+
+* Since we don't support access time, make that field zero, instead of 
+	copying m_time.
+	(fs/befs/inode.c)
+
+* Added sanity check for inode reading
+	Make sure inode we got was the one we asked for. 
+	(fs/befs/inode.c)
+
+* Code cleanup
+	Local pointers to commonly used structures in inode.c.
+	Got rid of abominations befs_iaddr2inode() and befs_inode2ino(). 
+	Replaced with single function iaddr2blockno().
+	(fs/befs/super.c) (fs/befs/inode.c)
+
+2001-09-01
+==========
+* Fixed the problem with statfs where it would always claim the disk was 
+	half full, due to improper understanding of the statfs fields.
+	(fs/befs/super.c)
+
+* Posted verion 4 of the patch
+
+2001-09-01
+==========
+* Changed the macros in befs_fs.h to inline functions.
+	More readable. Typesafe. Better
+	(include/linux/befs_fs.h)
+
+* Moved type definitions from befs_fs.h to a new file, befs_fs_types.h 
+	Because befs_fs_i.h and befs_fs_sb.h were including befs_fs.h for the 
+	typedefs, and they are inlcuded in <linux/fs.h>, which has definitions 
+	that I want the inline functions in befs_fs.h to be able to see. Nasty
+	circularity.
+	(include/linux/befs_fs.h)
+
+2001-08-30
+==========
+* Cleaned up some wording.
+
+* Added additional consitency checks on mount
+	Check block_size agrees with block_shift
+	Check flags == BEFS_CLEAN
+	(fs/befs/super.c)
+
+* Tell the kernel to only mount befs read-only. 
+	By setting the MS_RDONLY flag in befs_read_super().
+	Not that it was possible to write before. But now the kernel won't even try.
+	(fs/befs/super.c)
+
+* Got rid of kernel warning on mount.
+	The kernel doesn't like it if you call set_blocksize() on a device when 
+	you have some of its blocks open. Moved the second set_blocksize() to the
+	very end of befs_read_super(), after we are done with the disk superblock.
+	(fs/befs/super.c)
+	
+* Fixed wrong number of args bug in befs_dump_inode
+	(fs/befs/debug.c)
+
+* Solved lots of type mismatches in kprint()s
+	(everwhere)
+
+2001-08-27
+==========
+* Cleaned up the fs/Config.in entries a bit, now slightly more descriptive.
+
+* BeFS depends on NLS, so I made activating BeFS enable the NLS questions
+	(fs/nls/Config.in)
+
+* Added Configure.help entries for CONFIG_BEFS_FS and CONFIG_DEBUG_BEFS
+	(Documentation/Configure.help)
+
+2001-08-??
+==========
+* Removed superblock locking calls in befs_read_super(). In 2.4, the VFS 
+	hands us a super_block struct that is already locked.
+
+2001-08-13
+==========
+* Will Dyson <will_dyson@pobox.com> is now attempting to maintain this module
+	Makoto Kato <m_kato@ga2.so-net.ne.jp> is original author.Daniel Berlin 
+	also did some work on it (fixing it up for the later 2.3.x kernels, IIRC).
+
+* Fixed compile errors on 2.4.1 kernel (WD)
+	Resolve rejected patches
+	Accomodate changed NLS interface (util.h)
+	Needed to include <linux/slab.h> in most files
+	Makefile changes
+	fs/Config.in changes
+
+* Tried to niceify the code using the ext2 fs as a guide
+	Declare befs_fs_type using the DECLARE_FSTYPE_DEV() macro
+
+* Made it a configure option to turn on debugging (fs/Config.in)
+
+* Compiles on 2.4.7
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/befs/Makefile linux-2.4.20/fs/befs/Makefile
--- linux-2.4.19/fs/befs/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/befs/Makefile	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,15 @@
+#
+# Makefile for the linux BeOS filesystem routines.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := befs.o
+
+obj-y    := datastream.o btree.o super.o inode.o debug.o io.o linuxvfs.o
+obj-m    := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/befs/TODO linux-2.4.20/fs/befs/TODO
--- linux-2.4.19/fs/befs/TODO	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/befs/TODO	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,16 @@
+TODO
+==========
+
+* Convert comments to the Kernel-Doc format.
+
+* Befs_fs.h has gotten big and messy. No reason not to break it up into 
+	smaller peices.
+
+* See if Alexander Viro's option parser made it into the kernel tree. 
+	Use that if we can. (include/linux/parser.h)
+
+* See if we really need separate types for on-disk and in-memory 
+	representations of the superblock and inode.
+
+* We need a wrapper around the kernel's disk cache stuff. Then it would be 
+	easy to slip in stuff like using the pagecache.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/befs/attribute.c linux-2.4.20/fs/befs/attribute.c
--- linux-2.4.19/fs/befs/attribute.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/befs/attribute.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,117 @@
+/*
+ * linux/fs/befs/attribute.c
+ *
+ * Copyright (C) 2002 Will Dyson <will_dyson@pobox.com>
+ *
+ * Many thanks to Dominic Giampaolo, author of "Practical File System
+ * Design with the Be File System", for such a helpful book.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include "befs_fs.h"
+#include "endian.h"
+
+#define SD_DATA(sd)\
+	(void*)((char*)sd + sizeof(*sd) + (sd->name_size - sizeof(sd->name)))
+
+#define SD_NEXT(sd)\
+	(befs_small_data*)((char*)sd + sizeof(*sd) + (sd->name_size - \
+	sizeof(sd->name) + sd->data_size))
+
+int
+ list_small_data(struct super_block *sb, befs_inode * inode, filldir_t filldir);
+
+befs_small_data *find_small_data(struct super_block *sb, befs_inode * inode,
+				 const char *name);
+
+int
+ read_small_data(struct super_block *sb, befs_inode * inode,
+		 befs_small_data * sdata, void *buf, size_t bufsize);
+
+/**
+ *
+ *
+ *
+ *
+ *
+ */
+befs_small_data *
+find_small_data(struct super_block *sb, befs_inode * inode, const char *name)
+{
+	befs_small_data *sdata = inode->small_data;
+
+	while (sdata->type != 0) {
+		if (strcmp(name, sdata->name) != 0) {
+			return sdata;
+		}
+		sdata = SD_NEXT(sdata);
+	}
+	return NULL;
+}
+
+/**
+ *
+ *
+ *
+ *
+ *
+ */
+int
+read_small_data(struct super_block *sb, befs_inode * inode,
+		const char *name, void *buf, size_t bufsize)
+{
+	befs_small_data *sdata;
+
+	sdata = find_small_data(sb, inode, name);
+	if (sdata == NULL)
+		return BEFS_ERR;
+	else if (sdata->data_size > bufsize)
+		return BEFS_ERR;
+
+	memcpy(buf, SD_DATA(sdata), sdata->data_size);
+
+	return BEFS_OK;
+}
+
+/**
+ *
+ *
+ *
+ *
+ *
+ */
+int
+list_small_data(struct super_block *sb, befs_inode * inode)
+{
+
+}
+
+/**
+ *
+ *
+ *
+ *
+ *
+ */
+int
+list_attr(struct super_block *sb, befs_inode * inode)
+{
+
+}
+
+/**
+ *
+ *
+ *
+ *
+ *
+ */
+int
+read_attr(struct super_block *sb, befs_inode * inode)
+{
+
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/befs/befs_fs.h linux-2.4.20/fs/befs/befs_fs.h
--- linux-2.4.19/fs/befs/befs_fs.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/befs/befs_fs.h	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,200 @@
+/*
+ * befs_fs.h
+ *
+ * Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com>
+ * Copyright (C) 1999 Makoto Kato (m_kato@ga2.so-net.ne.jp)
+ */
+
+#ifndef _LINUX_BEFS_FS
+#define _LINUX_BEFS_FS
+
+#include "befs_fs_types.h"
+#include "compatibility.h"
+
+/* used in debug.c */
+#define BEFS_VERSION "0.9.2"
+
+typedef __u64 befs_blocknr_t;
+typedef __u32 vfs_blocknr_t;
+
+/*
+ * BeFS in memory structures
+ */
+
+typedef struct befs_mount_options {
+	gid_t gid;
+	uid_t uid;
+	int use_gid;
+	int use_uid;
+	int debug;
+	char *iocharset;
+} befs_mount_options;
+
+typedef struct befs_sb_info {
+	__u32 magic1;
+	__u32 block_size;
+	__u32 block_shift;
+	__u32 byte_order;
+	befs_off_t num_blocks;
+	befs_off_t used_blocks;
+	__u32 inode_size;
+	__u32 magic2;
+
+	/* Allocation group information */
+	__u32 blocks_per_ag;
+	__u32 ag_shift;
+	__u32 num_ags;
+
+	/* jornal log entry */
+	befs_block_run log_blocks;
+	befs_off_t log_start;
+	befs_off_t log_end;
+
+	befs_inode_addr root_dir;
+	befs_inode_addr indices;
+	__u32 magic3;
+
+	befs_mount_options mount_opts;
+	struct nls_table *nls;
+
+} befs_sb_info;
+
+typedef struct befs_inode_info {
+	__u32 i_flags;
+	__u32 i_type;
+
+	befs_inode_addr i_inode_num;
+	befs_inode_addr i_parent;
+	befs_inode_addr i_attribute;
+
+	union {
+		befs_data_stream ds;
+		char symlink[BEFS_SYMLINK_LEN];
+	} i_data;
+
+} befs_inode_info;
+
+enum befs_err {
+	BEFS_OK,
+	BEFS_ERR,
+	BEFS_BAD_INODE,
+	BEFS_BT_END,
+	BEFS_BT_EMPTY,
+	BEFS_BT_MATCH,
+	BEFS_BT_PARMATCH,
+	BEFS_BT_NOT_FOUND
+};
+
+/****************************/
+/* io.c */
+struct buffer_head *befs_bread_iaddr(struct super_block *sb,
+				     befs_inode_addr iaddr);
+
+struct buffer_head *befs_bread(struct super_block *sb, befs_blocknr_t block);
+/****************************/
+
+/****************************/
+/* datastream.c */
+struct buffer_head *befs_read_datastream(struct super_block *sb,
+					 befs_data_stream * ds, befs_off_t pos,
+					 uint * off);
+
+int befs_fblock2brun(struct super_block *sb, befs_data_stream * data,
+		     befs_blocknr_t fblock, befs_block_run * run);
+
+size_t befs_read_lsymlink(struct super_block *sb, befs_data_stream * data,
+			  void *buff, befs_off_t len);
+
+befs_blocknr_t befs_count_blocks(struct super_block *sb, befs_data_stream * ds);
+
+extern const befs_inode_addr BAD_IADDR;
+/****************************/
+
+/****************************/
+/* debug.c */
+void befs_error(const struct super_block *sb, const char *fmt, ...);
+void befs_warning(const struct super_block *sb, const char *fmt, ...);
+void befs_debug(const struct super_block *sb, const char *fmt, ...);
+
+void befs_dump_super_block(const struct super_block *sb, befs_super_block *);
+void befs_dump_inode(const struct super_block *sb, befs_inode *);
+void befs_dump_index_entry(const struct super_block *sb, befs_btree_super *);
+void befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead *);
+void befs_dump_inode_addr(const struct super_block *sb, befs_inode_addr);
+/****************************/
+
+/****************************/
+/* btree.c */
+int befs_btree_find(struct super_block *sb, befs_data_stream * ds,
+		    const char *key, befs_off_t * value);
+
+int befs_btree_read(struct super_block *sb, befs_data_stream * ds,
+		    loff_t key_no, size_t bufsize, char *keybuf,
+		    size_t * keysize, befs_off_t * value);
+/****************************/
+
+/****************************/
+/* super.c */
+int befs_load_sb(struct super_block *sb, befs_super_block * disk_sb);
+int befs_check_sb(struct super_block *sb);
+/****************************/
+
+/****************************/
+/* inode.c */
+int befs_check_inode(struct super_block *sb, befs_inode * raw_inode,
+		     befs_blocknr_t inode);
+/****************************/
+
+/* Gets a pointer to the private portion of the super_block
+ * structure from the public part
+ */
+static inline befs_sb_info *
+BEFS_SB(const struct super_block *super)
+{
+	return (befs_sb_info *) super->u.generic_sbp;
+}
+
+static inline befs_inode_info *
+BEFS_I(const struct inode *inode)
+{
+	return (befs_inode_info *) inode->u.generic_ip;
+}
+
+static inline befs_blocknr_t
+iaddr2blockno(struct super_block *sb, befs_inode_addr * iaddr)
+{
+	return ((iaddr->allocation_group << BEFS_SB(sb)->ag_shift) +
+		iaddr->start);
+}
+
+static inline befs_inode_addr
+blockno2iaddr(struct super_block *sb, befs_blocknr_t blockno)
+{
+	befs_inode_addr iaddr;
+	iaddr.allocation_group = blockno >> BEFS_SB(sb)->ag_shift;
+	iaddr.start =
+	    blockno - (iaddr.allocation_group << BEFS_SB(sb)->ag_shift);
+	iaddr.len = 1;
+
+	return iaddr;
+}
+
+static inline unsigned int
+befs_iaddrs_per_block(struct super_block *sb)
+{
+	return BEFS_SB(sb)->block_size / sizeof (befs_inode_addr);
+}
+
+static inline int
+befs_iaddr_is_empty(befs_inode_addr * iaddr)
+{
+	return (!iaddr->allocation_group) && (!iaddr->start) && (!iaddr->len);
+}
+
+static inline size_t
+befs_brun_size(struct super_block *sb, befs_block_run run)
+{
+	return BEFS_SB(sb)->block_size * run.len;
+}
+
+#endif				/* _LINUX_BEFS_FS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/befs/befs_fs_types.h linux-2.4.20/fs/befs/befs_fs_types.h
--- linux-2.4.19/fs/befs/befs_fs_types.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/befs/befs_fs_types.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,211 @@
+/*
+ * include/linux/befs_fs_types.h
+ *
+ * Copyright (C) 2001 Will Dyson (will@cs.earlham.edu)
+ *
+ *
+ *
+ * from linux/include/linux/befs_fs.h
+ *
+ * Copyright (C) 1999 Makoto Kato (m_kato@ga2.so-net.ne.jp)
+ *
+ */
+
+#ifndef _LINUX_BEFS_FS_TYPES
+#define _LINUX_BEFS_FS_TYPES
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#endif /*__KERNEL__*/
+
+#define PACKED __attribute__ ((__packed__))
+
+/*
+ * Max name lengths of BFS
+ */
+
+#define BEFS_NAME_LEN 255
+
+#define BEFS_SYMLINK_LEN 144
+#define BEFS_NUM_DIRECT_BLOCKS 12
+#define B_OS_NAME_LENGTH 32
+
+/* The datastream blocks mapped by the double-indirect
+ * block are always 4 fs blocks long.
+ * This eliminates the need for linear searches among
+ * the potentially huge number of indirect blocks
+ *
+ * Err. Should that be 4 fs blocks or 4k???
+ * It matters on large blocksize volumes
+ */
+#define BEFS_DBLINDIR_BRUN_LEN 4
+
+/*
+ * Flags of superblock
+ */
+
+enum super_flags {
+	BEFS_CLEAN = 0x434c454e,
+	BEFS_DIRTY = 0x44495254,
+	BEFS_BYTESEX_BE = 0x45474942,
+	BEFS_BYTESEX_LE = 0x42494745,
+	BEFS_SUPER_MAGIC1 = 0x42465331,	/* BFS1 */
+	BEFS_SUPER_MAGIC2 = 0xdd121031,
+	BEFS_SUPER_MAGIC3 = 0x15b6830e,
+};
+
+#define BEFS_SUPER_MAGIC BEFS_SUPER_MAGIC1
+
+/*
+ * Flags of inode
+ */
+
+#define BEFS_INODE_MAGIC1 0x3bbe0ad9
+
+enum inode_flags {
+	BEFS_INODE_IN_USE = 0x00000001,
+	BEFS_ATTR_INODE = 0x00000004,
+	BEFS_INODE_LOGGED = 0x00000008,
+	BEFS_INODE_DELETED = 0x00000010,
+	BEFS_LONG_SYMLINK = 0x00000040,
+	BEFS_PERMANENT_FLAG = 0x0000ffff,
+	BEFS_INODE_NO_CREATE = 0x00010000,
+	BEFS_INODE_WAS_WRITTEN = 0x00020000,
+	BEFS_NO_TRANSACTION = 0x00040000,
+};
+/* 
+ * On-Disk datastructures of BeFS
+ */
+
+typedef __u64 befs_off_t;
+typedef __u64 befs_time_t;
+typedef void befs_binode_etc;
+
+/* Block runs */
+typedef struct {
+	__u32 allocation_group;
+	__u16 start;
+	__u16 len;
+} PACKED befs_block_run;
+
+typedef befs_block_run befs_inode_addr;
+
+/*
+ * The Superblock Structure
+ */
+typedef struct {
+	char name[B_OS_NAME_LENGTH];
+	__u32 magic1;
+	__u32 fs_byte_order;
+
+	__u32 block_size;
+	__u32 block_shift;
+
+	befs_off_t num_blocks;
+	befs_off_t used_blocks;
+
+	__u32 inode_size;
+
+	__u32 magic2;
+	__u32 blocks_per_ag;
+	__u32 ag_shift;
+	__u32 num_ags;
+
+	__u32 flags;
+
+	befs_block_run log_blocks;
+	befs_off_t log_start;
+	befs_off_t log_end;
+
+	__u32 magic3;
+	befs_inode_addr root_dir;
+	befs_inode_addr indices;
+
+} PACKED befs_super_block;
+
+/* 
+ * Note: the indirect and dbl_indir block_runs may
+ * be longer than one block!
+ */
+typedef struct {
+	befs_block_run direct[BEFS_NUM_DIRECT_BLOCKS];
+	befs_off_t max_direct_range;
+	befs_block_run indirect;
+	befs_off_t max_indirect_range;
+	befs_block_run double_indirect;
+	befs_off_t max_double_indirect_range;
+	befs_off_t size;
+} PACKED befs_data_stream;
+
+/* Attribute */
+typedef struct {
+	__u32 type;
+	__u16 name_size;
+	__u16 data_size;
+	char name[1];
+} PACKED befs_small_data;
+
+/* Inode structure */
+typedef struct {
+	__u32 magic1;
+	befs_inode_addr inode_num;
+	__u32 uid;
+	__u32 gid;
+	__u32 mode;
+	__u32 flags;
+	befs_time_t create_time;
+	befs_time_t last_modified_time;
+	befs_inode_addr parent;
+	befs_inode_addr attributes;
+	__u32 type;
+
+	__u32 inode_size;
+	__u32 etc;		/* not use */
+
+	union {
+		befs_data_stream datastream;
+		char symlink[BEFS_SYMLINK_LEN];
+	} data;
+
+	__u32 pad[4];		/* not use */
+	befs_small_data small_data[1];
+} PACKED befs_inode;
+
+/*
+ * B+tree superblock
+ */
+
+#define BEFS_BTREE_MAGIC 0x69f6c2e8
+
+enum btree_types {
+	BTREE_STRING_TYPE = 0,
+	BTREE_INT32_TYPE = 1,
+	BTREE_UINT32_TYPE = 2,
+	BTREE_INT64_TYPE = 3,
+	BTREE_UINT64_TYPE = 4,
+	BTREE_FLOAT_TYPE = 5,
+	BTREE_DOUBLE_TYPE = 6
+};
+
+typedef struct {
+	__u32 magic;
+	__u32 node_size;
+	__u32 max_depth;
+	__u32 data_type;
+	befs_off_t root_node_ptr;
+	befs_off_t free_node_ptr;
+	befs_off_t max_size;
+} PACKED befs_btree_super;
+
+/*
+ * Header stucture of each btree node
+ */
+typedef struct {
+	befs_off_t left;
+	befs_off_t right;
+	befs_off_t overflow;
+	__u16 all_key_count;
+	__u16 all_key_length;
+} PACKED befs_btree_nodehead;
+
+#endif				/* _LINUX_BEFS_FS_TYPES */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/befs/btree.c linux-2.4.20/fs/befs/btree.c
--- linux-2.4.19/fs/befs/btree.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/befs/btree.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,783 @@
+/*
+ * linux/fs/befs/btree.c
+ *
+ * Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com>
+ *
+ * Licensed under the GNU GPL. See the file COPYING for details.
+ *
+ * 2002-02-05: Sergey S. Kostyliov added binary search withing
+ * 		btree nodes.
+ *
+ * Many thanks to:
+ *
+ * Dominic Giampaolo, author of "Practical File System
+ * Design with the Be File System", for such a helpful book.
+ * 
+ * Marcus J. Ranum, author of the b+tree package in 
+ * comp.sources.misc volume 10. This code is not copied from that
+ * work, but it is partially based on it.
+ *
+ * Makoto Kato, author of the original BeFS for linux filesystem
+ * driver.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+
+#include "befs_fs.h"
+#include "endian.h"
+
+/*
+ * The btree functions in this file are built on top of the
+ * datastream.c interface, which is in turn built on top of the
+ * io.c interface.
+ */
+
+/* Befs B+tree structure:
+ * 
+ * The first thing in the tree is the tree superblock. It tells you
+ * all kinds of usefull things about the tree, like where the rootnode
+ * is located, and the size of the nodes (always 1024 with current version
+ * of BeOS).
+ *
+ * The rest of the tree consists of a series of nodes. Nodes contain a header
+ * (struct befs_btree_nodehead), the packed key data, an array of shorts 
+ * containing the ending offsets for each of the keys, and an array of
+ * befs_off_t values. In interior nodes, the keys are the ending keys for 
+ * the childnode they point to, and the values are offsets into the 
+ * datastream containing the tree. 
+ */
+
+/* Note:
+ * 
+ * The book states 2 confusing things about befs b+trees. First, 
+ * it states that the overflow feild of node headers is used by internal nodes 
+ * to point to another node that "effectivly continues this one". Here is what 
+ * I belive that means. Each key in internal nodes points to another node that
+ * contains key values less than itself. Inspection reveals that the last key 
+ * in the internal node is not the last key in the index. Keys that are 
+ * greater than the last key in the internal node go into the overflow node. 
+ * I imagine there is a performance reason for this.
+ *
+ * Second, it states that the header of a btree node is sufficient to 
+ * distinguish internal nodes from leaf nodes. Without saying exactly how. 
+ * After figuring out the first, it becomes obvious that internal nodes have
+ * overflow nodes and leafnodes do not.
+ */
+
+/* 
+ * Currently, this code is only good for directory B+trees.
+ * In order to be used for other BFS indexes, it needs to be extended to handle
+ * duplicate keys and non-string keytypes (int32, int64, float, double).
+ */
+
+/*
+ * In memory structure of each btree node
+ */
+typedef struct {
+	befs_btree_nodehead head;	/* head of node converted to cpu byteorder */
+	struct buffer_head *bh;
+	befs_btree_nodehead *od_node;	/* on disk node */
+} befs_btree_node;
+
+/* local constants */
+const static befs_off_t befs_bt_inval = 0xffffffffffffffff;
+
+/* local functions */
+static int befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,
+			       befs_btree_super * bt_super,
+			       befs_btree_node * this_node,
+			       befs_off_t * node_off);
+
+static int befs_bt_read_super(struct super_block *sb, befs_data_stream * ds,
+			      befs_btree_super * sup);
+
+static int befs_bt_read_node(struct super_block *sb, befs_data_stream * ds,
+			     befs_btree_node * node, befs_off_t node_off);
+
+static int befs_leafnode(befs_btree_node * node);
+
+static u16 *befs_bt_keylen_index(befs_btree_node * node);
+
+static befs_off_t *befs_bt_valarray(befs_btree_node * node);
+
+static char *befs_bt_keydata(befs_btree_node * node);
+
+static int befs_find_key(struct super_block *sb, befs_btree_node * node,
+			 const char *findkey, befs_off_t * value);
+
+static char *befs_bt_get_key(struct super_block *sb, befs_btree_node * node,
+			     int index, u16 * keylen);
+
+static int befs_compare_strings(const void *key1, int keylen1,
+				const void *key2, int keylen2);
+
+/**
+ * befs_bt_read_super - read in btree superblock convert to cpu byteorder
+ * @sb: Filesystem superblock
+ * @ds: Datastream to read from
+ * @sup: Buffer in which to place the btree superblock
+ *
+ * Calls befs_read_datastream to read in the btree superblock and
+ * makes sure it is in cpu byteorder, byteswapping if nessisary.
+ *
+ * On success, returns BEFS_OK and *@sup contains the btree superblock,
+ * in cpu byte order.
+ *
+ * On failure, BEFS_ERR is returned.
+ */
+static int
+befs_bt_read_super(struct super_block *sb, befs_data_stream * ds,
+		   befs_btree_super * sup)
+{
+	struct buffer_head *bh = NULL;
+	befs_btree_super *od_sup = NULL;
+
+	befs_debug(sb, "---> befs_btree_read_super()");
+
+	bh = befs_read_datastream(sb, ds, 0, NULL);
+
+	if (!bh) {
+		befs_error(sb, "Couldn't read index header.");
+		goto error;
+	}
+	od_sup = (befs_btree_super *) bh->b_data;
+	befs_dump_index_entry(sb, od_sup);
+
+	sup->magic = fs32_to_cpu(sb, od_sup->magic);
+	sup->node_size = fs32_to_cpu(sb, od_sup->node_size);
+	sup->max_depth = fs32_to_cpu(sb, od_sup->max_depth);
+	sup->data_type = fs32_to_cpu(sb, od_sup->data_type);
+	sup->root_node_ptr = fs64_to_cpu(sb, od_sup->root_node_ptr);
+	sup->free_node_ptr = fs64_to_cpu(sb, od_sup->free_node_ptr);
+	sup->max_size = fs64_to_cpu(sb, od_sup->max_size);
+
+	brelse(bh);
+	if (sup->magic != BEFS_BTREE_MAGIC) {
+		befs_error(sb, "Index header has bad magic.");
+		goto error;
+	}
+
+	befs_debug(sb, "<--- befs_btree_read_super()");
+	return BEFS_OK;
+
+      error:
+	befs_debug(sb, "<--- befs_btree_read_super() ERROR");
+	return BEFS_ERR;
+}
+
+/**
+ * befs_bt_read_node - read in btree node and convert to cpu byteorder
+ * @sb: Filesystem superblock
+ * @ds: Datastream to read from
+ * @node: Buffer in which to place the btree node
+ * @node_off: Starting offset (in bytes) of the node in @ds
+ *
+ * Calls befs_read_datastream to read in the indicated btree node and
+ * makes sure its header feilds are in cpu byteorder, byteswapping if 
+ * nessisary.
+ * Note: node->bh must be NULL when this function called first
+ * time. Don't forget brelse(node->bh) after last call.
+ *
+ * On success, returns BEFS_OK and *@node contains the btree node that
+ * starts at @node_off, with the node->head fields in cpu byte order.
+ *
+ * On failure, BEFS_ERR is returned.
+ */
+
+static int
+befs_bt_read_node(struct super_block *sb, befs_data_stream * ds,
+		  befs_btree_node * node, befs_off_t node_off)
+{
+	uint off = 0;
+
+	befs_debug(sb, "---> befs_bt_read_node()");
+
+	if (node->bh)
+		brelse(node->bh);
+
+	node->bh = befs_read_datastream(sb, ds, node_off, &off);
+	if (!node->bh) {
+		befs_error(sb, "befs_bt_read_node() failed to read "
+			   "node at %Lu", node_off);
+		befs_debug(sb, "<--- befs_bt_read_node() ERROR");
+
+		return BEFS_ERR;
+	}
+	node->od_node =
+	    (befs_btree_nodehead *) ((void *) node->bh->b_data + off);
+
+	befs_dump_index_node(sb, node->od_node);
+
+	node->head.left = fs64_to_cpu(sb, node->od_node->left);
+	node->head.right = fs64_to_cpu(sb, node->od_node->right);
+	node->head.overflow = fs64_to_cpu(sb, node->od_node->overflow);
+	node->head.all_key_count =
+	    fs16_to_cpu(sb, node->od_node->all_key_count);
+	node->head.all_key_length =
+	    fs16_to_cpu(sb, node->od_node->all_key_length);
+
+	befs_debug(sb, "<--- befs_btree_read_node()");
+	return BEFS_OK;
+}
+
+/**
+ * befs_btree_find - Find a key in a befs B+tree
+ * @sb: Filesystem superblock
+ * @ds: Datastream containing btree
+ * @key: Key string to lookup in btree
+ * @value: Value stored with @key
+ *
+ * On sucess, returns BEFS_OK and sets *@value to the value stored
+ * with @key (usually the disk block number of an inode).
+ *
+ * On failure, returns BEFS_ERR or BEFS_BT_NOT_FOUND.
+ * 
+ * Algorithm: 
+ *   Read the superblock and rootnode of the b+tree.
+ *   Drill down through the interior nodes using befs_find_key().
+ *   Once at the correct leaf node, use befs_find_key() again to get the
+ *   actuall value stored with the key.
+ */
+int
+befs_btree_find(struct super_block *sb, befs_data_stream * ds,
+		const char *key, befs_off_t * value)
+{
+	befs_btree_node *this_node = NULL;
+	befs_btree_super bt_super;
+	befs_off_t node_off;
+	int res;
+
+	befs_debug(sb, "---> befs_btree_find() Key: %s", key);
+
+	if (befs_bt_read_super(sb, ds, &bt_super) != BEFS_OK) {
+		befs_error(sb,
+			   "befs_btree_find() failed to read index superblock");
+		goto error;
+	}
+
+	this_node = (befs_btree_node *) kmalloc(sizeof (befs_btree_node),
+						GFP_NOFS);
+	if (!this_node) {
+		befs_error(sb, "befs_btree_find() failed to allocate %u "
+			   "bytes of memory", sizeof (befs_btree_node));
+		goto error;
+	}
+
+	this_node->bh = NULL;
+
+	/* read in root node */
+	node_off = bt_super.root_node_ptr;
+	if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) {
+		befs_error(sb, "befs_btree_find() failed to read "
+			   "node at %Lu", node_off);
+		goto error_alloc;
+	}
+
+	while (!befs_leafnode(this_node)) {
+		res = befs_find_key(sb, this_node, key, &node_off);
+		if (res == BEFS_BT_NOT_FOUND)
+			node_off = this_node->head.overflow;
+		/* if no match, go to overflow node */
+		if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) {
+			befs_error(sb, "befs_btree_find() failed to read "
+				   "node at %Lu", node_off);
+			goto error_alloc;
+		}
+	}
+
+	/* at the correct leaf node now */
+
+	res = befs_find_key(sb, this_node, key, value);
+
+	brelse(this_node->bh);
+	kfree(this_node);
+
+	if (res != BEFS_BT_MATCH) {
+		befs_debug(sb, "<--- befs_btree_find() Key %s not found", key);
+		*value = 0;
+		return BEFS_BT_NOT_FOUND;
+	}
+	befs_debug(sb, "<--- befs_btree_find() Found key %s, value %Lu",
+		   key, *value);
+	return BEFS_OK;
+
+      error_alloc:
+	kfree(this_node);
+      error:
+	*value = 0;
+	befs_debug(sb, "<--- befs_btree_find() ERROR");
+	return BEFS_ERR;
+}
+
+/**
+ * befs_find_key - Search for a key within a node
+ * @sb: Filesystem superblock
+ * @node: Node to find the key within
+ * @key: Keystring to search for
+ * @value: If key is found, the value stored with the key is put here
+ *
+ * finds exact match if one exists, and returns BEFS_BT_MATCH
+ * If no exact match, finds first key in node that is greater
+ * (alpabeticly) than the search key and returns BEFS_BT_PARMATCH
+ * (for partial match, I guess). Can you think of something better to
+ * call it?
+ *
+ * If no key was a match or greater than the search key, return
+ * BEFS_BT_NOT_FOUND.
+ *
+ * Use binary search instead of a linear.
+ */
+static int
+befs_find_key(struct super_block *sb, befs_btree_node * node,
+	      const char *findkey, befs_off_t * value)
+{
+	int first, last, mid;
+	int eq;
+	u16 keylen;
+	int findkey_len;
+	char *thiskey;
+	befs_off_t *valarray;
+
+	befs_debug(sb, "---> befs_find_key() %s", findkey);
+
+	*value = 0;
+
+	findkey_len = strlen(findkey);
+
+	/* if node can not contain key, just skeep this node */
+	last = node->head.all_key_count - 1;
+	thiskey = befs_bt_get_key(sb, node, last, &keylen);
+
+	eq = befs_compare_strings(thiskey, keylen, findkey, findkey_len);
+	if (eq < 0) {
+		befs_debug(sb, "<--- befs_find_key() %s not found", findkey);
+		return BEFS_BT_NOT_FOUND;
+	}
+
+	valarray = befs_bt_valarray(node);
+
+	/* simple binary search */
+	first = 0;
+	mid = 0;
+	while (last >= first) {
+		mid = (last + first) / 2;
+		befs_debug(sb, "first: %d, last: %d, mid: %d", first, last,
+			   mid);
+		thiskey = befs_bt_get_key(sb, node, mid, &keylen);
+		eq = befs_compare_strings(thiskey, keylen, findkey,
+					  findkey_len);
+		*value = fs64_to_cpu(sb, valarray[mid]);
+
+		if (eq == 0) {
+			befs_debug(sb, "<--- befs_find_key() found %s at %d",
+				   thiskey, mid);
+
+			return BEFS_BT_MATCH;
+		}
+		if (eq > 0)
+			last = mid - 1;
+		else
+			first = mid + 1;
+	}
+	if (eq < 0)
+		*value = fs64_to_cpu(sb, valarray[mid + 1]);
+	befs_debug(sb, "<--- befs_find_key() found %s at %d", thiskey, mid);
+	return BEFS_BT_PARMATCH;
+}
+
+/**
+ * befs_btree_read - Traverse leafnodes of a btree
+ * @sb: Filesystem superblock
+ * @ds: Datastream containing btree
+ * @key_no: Key number (alphabetical order) of key to read
+ * @bufsize: Size of the buffer to return key in
+ * @keybuf: Pointer to a buffer to put the key in
+ * @keysize: Length of the returned key
+ * @value: Value stored with the returned key
+ *
+ * Heres how it works: Key_no is the index of the key/value pair to 
+ * retun in keybuf/value.
+ * Bufsize is the size of keybuf (BEFS_NAME_LEN+1 is a good size). Keysize is 
+ * the number of charecters in the key (just a convience).
+ *
+ * Algorithm:
+ *   Get the first leafnode of the tree. See if the requested key is in that
+ *   node. If not, follow the node->right link to the next leafnode. Repeat 
+ *   until the (key_no)th key is found or the tree is out of keys.
+ */
+int
+befs_btree_read(struct super_block *sb, befs_data_stream * ds,
+		loff_t key_no, size_t bufsize, char *keybuf, size_t * keysize,
+		befs_off_t * value)
+{
+	befs_btree_node *this_node;
+	befs_btree_super bt_super;
+	befs_off_t node_off = 0;
+	int cur_key;
+	befs_off_t *valarray;
+	char *keystart;
+	u16 keylen;
+	int res;
+
+	uint key_sum = 0;
+
+	befs_debug(sb, "---> befs_btree_read()");
+
+	if (befs_bt_read_super(sb, ds, &bt_super) != BEFS_OK) {
+		befs_error(sb,
+			   "befs_btree_read() failed to read index superblock");
+		goto error;
+	}
+
+	if ((this_node = (befs_btree_node *)
+	     kmalloc(sizeof (befs_btree_node), GFP_NOFS)) == NULL) {
+		befs_error(sb, "befs_btree_read() failed to allocate %u "
+			   "bytes of memory", sizeof (befs_btree_node));
+		goto error;
+	}
+
+	node_off = bt_super.root_node_ptr;
+	this_node->bh = NULL;
+
+	/* seeks down to first leafnode, reads it into this_node */
+	res = befs_btree_seekleaf(sb, ds, &bt_super, this_node, &node_off);
+	if (res == BEFS_BT_EMPTY) {
+		brelse(this_node->bh);
+		kfree(this_node);
+		*value = 0;
+		*keysize = 0;
+		befs_debug(sb, "<--- befs_btree_read() Tree is EMPTY");
+		return BEFS_BT_EMPTY;
+	} else if (res == BEFS_ERR) {
+		goto error_alloc;
+	}
+
+	/* find the leaf node containing the key_no key */
+
+	while (key_sum + this_node->head.all_key_count <= key_no) {
+
+		/* no more nodes to look in: key_no is too large */
+		if (this_node->head.right == befs_bt_inval) {
+			*keysize = 0;
+			*value = 0;
+			befs_debug(sb,
+				   "<--- befs_btree_read() END of keys at %Lu",
+				   key_sum + this_node->head.all_key_count);
+			brelse(this_node->bh);
+			kfree(this_node);
+			return BEFS_BT_END;
+		}
+
+		key_sum += this_node->head.all_key_count;
+		node_off = this_node->head.right;
+
+		if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) {
+			befs_error(sb, "befs_btree_read() failed to read "
+				   "node at %Lu", node_off);
+			goto error_alloc;
+		}
+	}
+
+	/* how many keys into this_node is key_no */
+	cur_key = key_no - key_sum;
+
+	/* get pointers to datastructures within the node body */
+	valarray = befs_bt_valarray(this_node);
+
+	keystart = befs_bt_get_key(sb, this_node, cur_key, &keylen);
+
+	befs_debug(sb, "Read [%Lu,%d]: keysize %d", node_off, cur_key, keylen);
+
+	if (bufsize < keylen + 1) {
+		befs_error(sb, "befs_btree_read() keybuf too small (%u) "
+			   "for key of size %d", bufsize, keylen);
+		brelse(this_node->bh);
+		goto error_alloc;
+	};
+
+	strncpy(keybuf, keystart, keylen);
+	*value = fs64_to_cpu(sb, valarray[cur_key]);
+	*keysize = keylen;
+	keybuf[keylen] = '\0';
+
+	befs_debug(sb, "Read [%Lu,%d]: Key \"%.*s\", Value %Lu", node_off,
+		   cur_key, keylen, keybuf, *value);
+
+	brelse(this_node->bh);
+	kfree(this_node);
+
+	befs_debug(sb, "<--- befs_btree_read()");
+
+	return BEFS_OK;
+
+      error_alloc:
+	kfree(this_node);
+
+      error:
+	*keysize = 0;
+	*value = 0;
+	befs_debug(sb, "<--- befs_btree_read() ERROR");
+	return BEFS_ERR;
+}
+
+/**
+ * befs_btree_seekleaf - Find the first leafnode in the btree
+ * @sb: Filesystem superblock
+ * @ds: Datastream containing btree
+ * @bt_super: Pointer to the uperblock of the btree
+ * @this_node: Buffer to return the leafnode in
+ * @node_off: Pointer to offset of current node within datastream. Modified
+ * 		by the function.
+ *
+ *
+ * Helper function for btree traverse. Moves the current position to the 
+ * start of the first leaf node.
+ *
+ * Also checks for an empty tree. If there are no keys, returns BEFS_BT_EMPTY.
+ */
+static int
+befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,
+		    befs_btree_super * bt_super, befs_btree_node * this_node,
+		    befs_off_t * node_off)
+{
+
+	befs_debug(sb, "---> befs_btree_seekleaf()");
+
+	if (befs_bt_read_node(sb, ds, this_node, *node_off) != BEFS_OK) {
+		befs_error(sb, "befs_btree_seekleaf() failed to read "
+			   "node at %Lu", *node_off);
+		goto error;
+	}
+	befs_debug(sb, "Seekleaf to root node %Lu", *node_off);
+
+	if (this_node->head.all_key_count == 0 && befs_leafnode(this_node)) {
+		befs_debug(sb, "<--- befs_btree_seekleaf() Tree is EMPTY");
+		return BEFS_BT_EMPTY;
+	}
+
+	while (!befs_leafnode(this_node)) {
+
+		if (this_node->head.all_key_count == 0) {
+			befs_debug(sb, "befs_btree_seekleaf() encountered "
+				   "an empty interior node: %Lu. Using Overflow "
+				   "node: %Lu", *node_off,
+				   this_node->head.overflow);
+			*node_off = this_node->head.overflow;
+		} else {
+			befs_off_t *valarray = befs_bt_valarray(this_node);
+			*node_off = fs64_to_cpu(sb, valarray[0]);
+		}
+		if (befs_bt_read_node(sb, ds, this_node, *node_off) != BEFS_OK) {
+			befs_error(sb, "befs_btree_seekleaf() failed to read "
+				   "node at %Lu", *node_off);
+			goto error;
+		}
+
+		befs_debug(sb, "Seekleaf to child node %Lu", *node_off);
+	}
+	befs_debug(sb, "Node %Lu is a leaf node", *node_off);
+
+	return BEFS_OK;
+
+      error:
+	befs_debug(sb, "<--- befs_btree_seekleaf() ERROR");
+	return BEFS_ERR;
+}
+
+/**
+ * befs_leafnode - Determine if the btree node is a leaf node or an 
+ * interior node
+ * @node: Pointer to node structure to test
+ * 
+ * Return 1 if leaf, 0 if interior
+ */
+static int
+befs_leafnode(befs_btree_node * node)
+{
+	/* all interior nodes (and only interior nodes) have an overflow node */
+	if (node->head.overflow == befs_bt_inval)
+		return 1;
+	else
+		return 0;
+}
+
+/**
+ * befs_bt_keylen_index - Finds start of keylen index in a node
+ * @node: Pointer to the node structure to find the keylen index within
+ *
+ * Returns a pointer to the start of the key length index array
+ * of the B+tree node *@node
+ *
+ * "The length of all the keys in the node is added to the size of the
+ * header and then rounded up to a multiple of four to get the begining
+ * of the key length index" (p.88, practical filesystem design).
+ *
+ * Exept that rounding up to 8 works, and rounding up to 4 doesn't.
+ */
+static u16 *
+befs_bt_keylen_index(befs_btree_node * node)
+{
+	const int keylen_align = 8;
+	unsigned long int off =
+	    (sizeof (befs_btree_nodehead) + node->head.all_key_length);
+	ulong tmp = off % keylen_align;
+
+	if (tmp)
+		off += keylen_align - tmp;
+
+	return (u16 *) ((void *) node->od_node + off);
+}
+
+/**
+ * befs_bt_valarray - Finds the start of value array in a node
+ * @node: Pointer to the node structure to find the value array within
+ *
+ * Returns a pointer to the start of the value array
+ * of the node pointed to by the node header
+ */
+static befs_off_t *
+befs_bt_valarray(befs_btree_node * node)
+{
+	void *keylen_index_start = (void *) befs_bt_keylen_index(node);
+	size_t keylen_index_size = node->head.all_key_count * sizeof (u16);
+
+	return (befs_off_t *) (keylen_index_start + keylen_index_size);
+}
+
+/**
+ * befs_bt_keydata - Finds start of keydata array in a node
+ * @node: Pointer to the node structure to find the keydata array within
+ *
+ * Returns a pointer to the start of the keydata array
+ * of the node pointed to by the node header 
+ */
+static char *
+befs_bt_keydata(befs_btree_node * node)
+{
+	return (char *) ((void *) node->od_node + sizeof (befs_btree_nodehead));
+}
+
+/**
+ * befs_bt_get_key - returns a pointer to the start of a key
+ * @sb: filesystem superblock
+ * @node: node in which to look for the key
+ * @index: the index of the key to get
+ * @keylen: modified to be the length of the key at @index
+ *
+ * Returns a valid pointer into @node on success.
+ * Returns NULL on failure (bad input) and sets *@keylen = 0
+ */
+static char *
+befs_bt_get_key(struct super_block *sb, befs_btree_node * node,
+		int index, u16 * keylen)
+{
+	int prev_key_end;
+	char *keystart;
+	u16 *keylen_index;
+
+	if (index < 0 || index > node->head.all_key_count) {
+		*keylen = 0;
+		return NULL;
+	}
+
+	keystart = befs_bt_keydata(node);
+	keylen_index = befs_bt_keylen_index(node);
+
+	if (index == 0)
+		prev_key_end = 0;
+	else
+		prev_key_end = fs16_to_cpu(sb, keylen_index[index - 1]);
+
+	*keylen = fs16_to_cpu(sb, keylen_index[index]) - prev_key_end;
+
+	return keystart + prev_key_end;
+}
+
+/**
+ * befs_compare_strings - compare two strings
+ * @key1: pointer to the first key to be compared 
+ * @keylen1: length in bytes of key1
+ * @key2: pointer to the second key to be compared
+ * @kelen2: lenght in bytes of key2
+ *
+ * Returns 0 if @key1 and @key2 are equal.
+ * Returns >0 if @key1 is greater.
+ * Returns <0 if @key2 is greater..
+ */
+static int
+befs_compare_strings(const void *key1, int keylen1,
+		     const void *key2, int keylen2)
+{
+	int len = min_t(int, keylen1, keylen2);
+	int result = strncmp(key1, key2, len);
+	if (result == 0)
+		result = keylen1 - keylen2;
+	return result;
+}
+
+/* These will be used for non-string keyed btrees */
+#if 0
+static int
+btree_compare_int32(cont void *key1, int keylen1, const void *key2, int keylen2)
+{
+	return *(int32_t *) key1 - *(int32_t *) key2;
+}
+
+static int
+btree_compare_uint32(cont void *key1, int keylen1,
+		     const void *key2, int keylen2)
+{
+	if (*(u_int32_t *) key1 == *(u_int32_t *) key2)
+		return 0;
+	else if (*(u_int32_t *) key1 > *(u_int32_t *) key2)
+		return 1;
+
+	return -1;
+}
+static int
+btree_compare_int64(cont void *key1, int keylen1, const void *key2, int keylen2)
+{
+	if (*(int64_t *) key1 == *(int64_t *) key2)
+		return 0;
+	else if (*(int64_t *) key1 > *(int64_t *) key2)
+		return 1;
+
+	return -1;
+}
+
+static int
+btree_compare_uint64(cont void *key1, int keylen1,
+		     const void *key2, int keylen2)
+{
+	if (*(u_int64_t *) key1 == *(u_int64_t *) key2)
+		return 0;
+	else if (*(u_int64_t *) key1 > *(u_int64_t *) key2)
+		return 1;
+
+	return -1;
+}
+
+static int
+btree_compare_float(cont void *key1, int keylen1, const void *key2, int keylen2)
+{
+	float result = *(float *) key1 - *(float *) key2;
+	if (result == 0.0f)
+		return 0;
+
+	return (result < 0.0f) ? -1 : 1;
+}
+
+static int
+btree_compare_double(cont void *key1, int keylen1,
+		     const void *key2, int keylen2)
+{
+	double result = *(double *) key1 - *(double *) key2;
+	if (result == 0.0)
+		return 0;
+
+	return (result < 0.0) ? -1 : 1;
+}
+#endif				//0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/befs/compatibility.h linux-2.4.20/fs/befs/compatibility.h
--- linux-2.4.19/fs/befs/compatibility.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/befs/compatibility.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,26 @@
+/*
+ * linux/fs/befs/compatiblity.h
+ *
+ * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com>
+ *   AKA <will@cs.earlham.edu>
+ *
+ * This file trys to take care of differences between
+ * kernel versions
+ */
+
+#include <linux/version.h>
+
+/* New interfaces in 2.4.10 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
+
+#define min_t(type,x,y) \
+({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+
+#define max_t(type,x,y) \
+({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
+
+#define vsnprintf(buf, n, fmt, args) vsprintf(buf, fmt, args)
+
+#define MODULE_LICENSE(x)
+
+#endif				/* LINUX_VERSION_CODE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/befs/datastream.c linux-2.4.20/fs/befs/datastream.c
--- linux-2.4.19/fs/befs/datastream.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/befs/datastream.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,527 @@
+/*
+ * linux/fs/befs/datastream.c
+ *
+ * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com>
+ *
+ * Based on portions of file.c by Makoto Kato <m_kato@ga2.so-net.ne.jp>
+ *
+ * Many thanks to Dominic Giampaolo, author of "Practical File System
+ * Design with the Be File System", for such a helpful book.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "befs_fs.h"
+#include "endian.h"
+
+const befs_inode_addr BAD_IADDR = { 0, 0, 0 };
+
+static int befs_find_brun_direct(struct super_block *sb,
+				 befs_data_stream * data,
+				 befs_blocknr_t blockno, befs_block_run * run);
+
+static int befs_find_brun_indirect(struct super_block *sb,
+				   befs_data_stream * data,
+				   befs_blocknr_t blockno,
+				   befs_block_run * run);
+
+static int befs_find_brun_dblindirect(struct super_block *sb,
+				      befs_data_stream * data,
+				      befs_blocknr_t blockno,
+				      befs_block_run * run);
+
+/**
+ * befs_read_datastream - get buffer_head containing data, starting from pos.
+ * @sb: Filesystem superblock
+ * @ds: datastrem to find data with
+ * @pos: start of data
+ * @off: offset of data in buffer_head->b_data
+ *
+ * Returns pointer to buffer_head containing data starting with offset @off,
+ * if you don't need to know offset just set @off = NULL.
+ */
+struct buffer_head *
+befs_read_datastream(struct super_block *sb, befs_data_stream * ds,
+		     befs_off_t pos, uint * off)
+{
+	struct buffer_head *bh = NULL;
+	befs_block_run run;
+	befs_blocknr_t block;	/* block coresponding to pos */
+
+	befs_debug(sb, "---> befs_read_datastream() %Lu", pos);
+	block = pos >> BEFS_SB(sb)->block_shift;
+	if (off)
+		*off = pos - (block << BEFS_SB(sb)->block_shift);
+
+	if (befs_fblock2brun(sb, ds, block, &run) != BEFS_OK) {
+		befs_error(sb, "BeFS: Error finding disk addr of block %lu",
+			   block);
+		befs_debug(sb, "<--- befs_read_datastream() ERROR");
+		return NULL;
+	}
+	bh = befs_bread_iaddr(sb, run);
+	if (!bh) {
+		befs_error(sb, "BeFS: Error reading block %lu from datastream",
+			   block);
+		return NULL;
+	}
+
+	befs_debug(sb, "<--- befs_read_datastream() read data, starting at %Lu",
+		   pos);
+
+	return bh;
+}
+
+/*
+ * Takes a file position and gives back a brun who's starting block
+ * is block number fblock of the file.
+ * 
+ * Returns BEFS_OK or BEFS_ERR.
+ * 
+ * Calls specialized functions for each of the three possible
+ * datastream regions.
+ *
+ * 2001-11-15 Will Dyson
+ */
+int
+befs_fblock2brun(struct super_block *sb, befs_data_stream * data,
+		 befs_blocknr_t fblock, befs_block_run * run)
+{
+	int err;
+	befs_off_t pos = fblock << BEFS_SB(sb)->block_shift;
+
+	if (pos < data->max_direct_range) {
+		err = befs_find_brun_direct(sb, data, fblock, run);
+
+	} else if (pos < data->max_indirect_range) {
+		err = befs_find_brun_indirect(sb, data, fblock, run);
+
+	} else if (pos < data->max_double_indirect_range) {
+		err = befs_find_brun_dblindirect(sb, data, fblock, run);
+
+	} else {
+		befs_error(sb,
+			   "befs_fblock2brun() was asked to find block %lu, "
+			   "which is not mapped by the datastream\n", fblock);
+		err = BEFS_ERR;
+	}
+	return err;
+}
+
+/**
+ * befs_read_lsmylink - read long symlink from datastream.
+ * @sb: Filesystem superblock 
+ * @ds: Datastrem to read from
+ * @buf: Buffer in wich to place long symlink data
+ * @len: Length of the long symlink in bytes
+ *
+ * Returns the number of bytes read
+ */
+size_t
+befs_read_lsymlink(struct super_block * sb, befs_data_stream * ds, void *buff,
+		   befs_off_t len)
+{
+	befs_off_t bytes_read = 0;	/* bytes readed */
+	u16 plen;
+	struct buffer_head *bh = NULL;
+	befs_debug(sb, "---> befs_read_lsymlink() length: %Lu", len);
+
+	while (bytes_read < len) {
+		bh = befs_read_datastream(sb, ds, bytes_read, NULL);
+		if (!bh) {
+			befs_error(sb, "BeFS: Error reading datastream block "
+				   "starting from %Lu", bytes_read);
+			befs_debug(sb, "<--- befs_read_lsymlink() ERROR");
+			return bytes_read;
+
+		}
+		plen = ((bytes_read + BEFS_SB(sb)->block_size) < len) ?
+		    BEFS_SB(sb)->block_size : len - bytes_read;
+		memcpy(buff + bytes_read, bh->b_data, plen);
+		brelse(bh);
+		bytes_read += plen;
+	}
+
+	befs_debug(sb, "<--- befs_read_lsymlink() read %u bytes", bytes_read);
+	return bytes_read;
+}
+
+/**
+ * befs_count_blocks - blocks used by a file
+ * @sb: Filesystem superblock
+ * @ds: Datastream of the file
+ *
+ * Counts the number of fs blocks that the file represented by
+ * inode occupies on the filesystem, counting both regular file
+ * data and filesystem metadata (and eventually attribute data
+ * when we support attributes)
+*/
+
+befs_blocknr_t
+befs_count_blocks(struct super_block * sb, befs_data_stream * ds)
+{
+	befs_blocknr_t blocks;
+	befs_blocknr_t datablocks;	/* File data blocks */
+	befs_blocknr_t metablocks;	/* FS metadata blocks */
+	befs_sb_info *befs_sb = BEFS_SB(sb);
+
+	befs_debug(sb, "---> befs_count_blocks()");
+
+	datablocks = ds->size >> befs_sb->block_shift;
+	if (ds->size & (befs_sb->block_size - 1))
+		datablocks += 1;
+
+	metablocks = 1;		/* Start with 1 block for inode */
+
+	/* Size of indirect block */
+	if (ds->size > ds->max_direct_range)
+		metablocks += ds->indirect.len;
+
+	/*
+	   Double indir block, plus all the indirect blocks it mapps
+	   In the double-indirect range, all block runs of data are
+	   BEFS_DBLINDIR_BRUN_LEN blocks long. Therefore, we know 
+	   how many data block runs are in the double-indirect region,
+	   and from that we know how many indirect blocks it takes to
+	   map them. We assume that the indirect blocks are also
+	   BEFS_DBLINDIR_BRUN_LEN blocks long.
+	 */
+	if (ds->size > ds->max_indirect_range && ds->max_indirect_range != 0) {
+		uint dbl_bytes;
+		uint dbl_bruns;
+		uint indirblocks;
+
+		dbl_bytes =
+		    ds->max_double_indirect_range - ds->max_indirect_range;
+		dbl_bruns =
+		    dbl_bytes / (befs_sb->block_size * BEFS_DBLINDIR_BRUN_LEN);
+		indirblocks = dbl_bruns / befs_iaddrs_per_block(sb);
+
+		metablocks += ds->double_indirect.len;
+		metablocks += indirblocks;
+	}
+
+	blocks = datablocks + metablocks;
+	befs_debug(sb, "<--- befs_count_blocks() %u blocks", blocks);
+
+	return blocks;
+}
+
+/*
+	Finds the block run that starts at file block number blockno
+	in the file represented by the datastream data, if that 
+	blockno is in the direct region of the datastream.
+	
+	sb: the superblock
+	data: the datastream
+	blockno: the blocknumber to find
+	run: The found run is passed back through this pointer
+	
+	Return value is BEFS_OK if the blockrun is found, BEFS_ERR
+	otherwise.
+	
+	Algorithm:
+	Linear search. Checks each element of array[] to see if it
+	contains the blockno-th filesystem block. This is nessisary
+	because the block runs map variable amounts of data. Simply
+	keeps a count of the number of blocks searched so far (sum),
+	incrementing this by the length of each block run as we come
+	across it. Adds sum to *count before returning (this is so
+	you can search multiple arrays that are logicaly one array,
+	as in the indirect region code).
+	
+	When/if blockno is found, if blockno is inside of a block 
+	run as stored on disk, we offset the start and lenght members 
+	of the block run, so that blockno is the start and len is
+	still valid (the run ends in the same place).
+	
+	2001-11-15 Will Dyson
+*/
+static int
+befs_find_brun_direct(struct super_block *sb, befs_data_stream * data,
+		      befs_blocknr_t blockno, befs_block_run * run)
+{
+	int i;
+	befs_block_run *array = data->direct;
+	befs_blocknr_t sum;
+	befs_blocknr_t max_block =
+	    data->max_direct_range >> BEFS_SB(sb)->block_shift;
+
+	befs_debug(sb, "---> befs_find_brun_direct(), find %lu", blockno);
+
+	if (blockno > max_block) {
+		befs_error(sb, "befs_find_brun_direct() passed block outside of"
+			   "direct region");
+		return BEFS_ERR;
+	}
+
+	for (i = 0, sum = 0; i < BEFS_NUM_DIRECT_BLOCKS;
+	     sum += array[i].len, i++) {
+		if (blockno >= sum && blockno < sum + (array[i].len)) {
+			int offset = blockno - sum;
+			run->allocation_group = array[i].allocation_group;
+			run->start = array[i].start + offset;
+			run->len = array[i].len - offset;
+
+			befs_debug(sb, "---> befs_find_brun_direct(), "
+				   "found %lu at direct[%d]", blockno, i);
+			return BEFS_OK;
+		}
+	}
+
+	befs_debug(sb, "---> befs_find_brun_direct() ERROR");
+	return BEFS_ERR;
+}
+
+/*
+	Finds the block run that starts at file block number blockno
+	in the file represented by the datastream data, if that 
+	blockno is in the indirect region of the datastream.
+	
+	sb: the superblock
+	data: the datastream
+	blockno: the blocknumber to find
+	run: The found run is passed back through this pointer
+	
+	Return value is BEFS_OK if the blockrun is found, BEFS_ERR
+	otherwise.
+	
+	Algorithm:
+	For each block in the indirect run of the datastream, read
+	it in and search through it for	search_blk.
+	
+	XXX:
+	Really should check to make sure blockno is inside indirect
+	region.
+	
+	2001-11-15 Will Dyson
+*/
+static int
+befs_find_brun_indirect(struct super_block *sb,
+			befs_data_stream * data, befs_blocknr_t blockno,
+			befs_block_run * run)
+{
+	int i, j;
+	befs_blocknr_t sum = 0;
+	befs_blocknr_t indir_start_blk;
+	befs_blocknr_t search_blk;
+	struct buffer_head *indirblock;
+	befs_block_run *array;
+
+	befs_block_run indirect = data->indirect;
+	befs_blocknr_t indirblockno = iaddr2blockno(sb, &indirect);
+	int arraylen = befs_iaddrs_per_block(sb);
+
+	befs_debug(sb, "---> befs_find_brun_indirect(), find %lu", blockno);
+
+	indir_start_blk = data->max_direct_range >> BEFS_SB(sb)->block_shift;
+	search_blk = blockno - indir_start_blk;
+
+	/* Examine blocks of the indirect run one at a time */
+	for (i = 0; i < indirect.len; i++) {
+		indirblock = befs_bread(sb, indirblockno + i);
+		if (indirblock == NULL) {
+			befs_debug(sb,
+				   "---> befs_find_brun_indirect() failed to "
+				   "read disk block %lu from the indirect brun",
+				   indirblockno + i);
+			return BEFS_ERR;
+		}
+
+		array = (befs_block_run *) indirblock->b_data;
+
+		for (j = 0; j < arraylen; ++j) {
+			int len = fs16_to_cpu(sb, array[j].len);
+
+			if (search_blk >= sum && search_blk < sum + len) {
+				int offset = search_blk - sum;
+				run->allocation_group =
+				    fs32_to_cpu(sb, array[j].allocation_group);
+				run->start =
+				    fs16_to_cpu(sb, array[j].start) + offset;
+				run->len =
+				    fs16_to_cpu(sb, array[j].len) - offset;
+
+				brelse(indirblock);
+				befs_debug(sb,
+					   "<--- befs_find_brun_indirect() found "
+					   "file block %lu at indirect[%d]",
+					   blockno, j + (i * arraylen));
+				return BEFS_OK;
+			}
+			sum += len;
+		}
+
+		brelse(indirblock);
+	}
+
+	/* Only fallthrough is an error */
+	befs_error(sb, "BeFS: befs_find_brun_indirect() failed to find "
+		   "file block %lu", blockno);
+
+	befs_debug(sb, "<--- befs_find_brun_indirect() ERROR");
+	return BEFS_ERR;
+}
+
+/*
+	Finds the block run that starts at file block number blockno
+	in the file represented by the datastream data, if that 
+	blockno is in the double-indirect region of the datastream.
+	
+	sb: the superblock
+	data: the datastream
+	blockno: the blocknumber to find
+	run: The found run is passed back through this pointer
+	
+	Return value is BEFS_OK if the blockrun is found, BEFS_ERR
+	otherwise.
+	
+	Algorithm:
+	The block runs in the double-indirect region are different.
+	They are always allocated 4 fs blocks at a time, so each
+	block run maps a constant amount of file data. This means
+	that we can directly calculate how many block runs into the
+	double-indirect region we need to go to get to the one that
+	maps a particular filesystem block.
+	
+	We do this in two stages. First we calculate which of the
+	inode addresses in the double-indirect block will point us
+	to the indirect block that contains the mapping for the data,
+	then we calculate which of the inode addresses in that 
+	indirect block maps the data block we are after.
+	
+	Oh, and once we've done that, we actually read in the blocks 
+	that contain the inode addresses we calculated above. Even 
+	though the double-indirect run may be several blocks long, 
+	we can calculate which of those blocks will contain the index
+	we are after and only read that one. We then follow it to 
+	the indirect block and perform a  similar process to find
+	the actual block run that maps the data block we are interested
+	in.
+	
+	Then we offset the run as in befs_find_brun_array() and we are 
+	done.
+	
+	2001-11-15 Will Dyson
+*/
+static int
+befs_find_brun_dblindirect(struct super_block *sb,
+			   befs_data_stream * data, befs_blocknr_t blockno,
+			   befs_block_run * run)
+{
+	int dblindir_indx;
+	int indir_indx;
+	int offset;
+	int dbl_which_block;
+	int which_block;
+	int dbl_block_indx;
+	int block_indx;
+	off_t dblindir_leftover;
+	befs_blocknr_t blockno_at_run_start;
+	struct buffer_head *dbl_indir_block;
+	struct buffer_head *indir_block;
+	befs_block_run indir_run;
+	befs_inode_addr *iaddr_array = NULL;
+	befs_sb_info *befs_sb = BEFS_SB(sb);
+
+	befs_blocknr_t indir_start_blk =
+	    data->max_indirect_range >> befs_sb->block_shift;
+
+	off_t dbl_indir_off = blockno - indir_start_blk;
+
+	/* number of data blocks mapped by each of the iaddrs in
+	 * the indirect block pointed to by the double indirect block
+	 */
+	size_t iblklen = BEFS_DBLINDIR_BRUN_LEN;
+
+	/* number of data blocks mapped by each of the iaddrs in
+	 * the double indirect block
+	 */
+	size_t diblklen = iblklen * befs_iaddrs_per_block(sb)
+	    * BEFS_DBLINDIR_BRUN_LEN;
+
+	befs_debug(sb, "---> befs_find_brun_dblindirect() find %lu", blockno);
+
+	/* First, discover which of the double_indir->indir blocks
+	 * contains pos. Then figure out how much of pos that
+	 * accounted for. Then discover which of the iaddrs in
+	 * the indirect block contains pos.
+	 */
+
+	dblindir_indx = dbl_indir_off / diblklen;
+	dblindir_leftover = dbl_indir_off % diblklen;
+	indir_indx = dblindir_leftover / diblklen;
+
+	/* Read double indirect block */
+	dbl_which_block = dblindir_indx / befs_iaddrs_per_block(sb);
+	if (dbl_which_block > data->double_indirect.len) {
+		befs_error(sb, "The double-indirect index calculated by "
+			   "befs_read_brun_dblindirect(), %d, is outside the range "
+			   "of the double-indirect block", dblindir_indx);
+		return BEFS_ERR;
+	}
+
+	dbl_indir_block = befs_bread(sb,
+				     iaddr2blockno(sb,
+						   &data->double_indirect) +
+				     dbl_which_block);
+	if (dbl_indir_block == NULL) {
+		befs_error(sb, "befs_read_brun_dblindirect() couldn't read the "
+			   "double-indirect block at blockno %lu",
+			   iaddr2blockno(sb,
+					 &data->double_indirect) +
+			   dbl_which_block);
+		brelse(dbl_indir_block);
+		return BEFS_ERR;
+	}
+
+	dbl_block_indx =
+	    dblindir_indx - (dbl_which_block * befs_iaddrs_per_block(sb));
+	iaddr_array = (befs_inode_addr *) dbl_indir_block->b_data;
+	indir_run = fsrun_to_cpu(sb, iaddr_array[dbl_block_indx]);
+	brelse(dbl_indir_block);
+	iaddr_array = NULL;
+
+	/* Read indirect block */
+	which_block = indir_indx / befs_iaddrs_per_block(sb);
+	if (which_block > indir_run.len) {
+		befs_error(sb, "The indirect index calculated by "
+			   "befs_read_brun_dblindirect(), %d, is outside the range "
+			   "of the indirect block", indir_indx);
+		return BEFS_ERR;
+	}
+
+	indir_block =
+	    befs_bread(sb, iaddr2blockno(sb, &indir_run) + which_block);
+	if (indir_block == NULL) {
+		befs_error(sb, "befs_read_brun_dblindirect() couldn't read the "
+			   "indirect block at blockno %lu",
+			   iaddr2blockno(sb, &indir_run) + which_block);
+		brelse(indir_block);
+		return BEFS_ERR;
+	}
+
+	block_indx = indir_indx - (which_block * befs_iaddrs_per_block(sb));
+	iaddr_array = (befs_inode_addr *) indir_block->b_data;
+	*run = fsrun_to_cpu(sb, iaddr_array[block_indx]);
+	brelse(indir_block);
+	iaddr_array = NULL;
+
+	blockno_at_run_start = indir_start_blk;
+	blockno_at_run_start += diblklen * dblindir_indx;
+	blockno_at_run_start += iblklen * indir_indx;
+	offset = blockno - blockno_at_run_start;
+
+	run->start += offset;
+	run->len -= offset;
+
+	befs_debug(sb, "Found file block %lu in double_indirect[%d][%d],"
+		   " double_indirect_leftover = %lu",
+		   blockno, dblindir_indx, indir_indx, dblindir_leftover);
+
+	return BEFS_OK;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/befs/debug.c linux-2.4.20/fs/befs/debug.c
--- linux-2.4.19/fs/befs/debug.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/befs/debug.c	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,263 @@
+/*
+ *  linux/fs/befs/debug.c
+ * 
+ * Copyright (C) 2001 Will Dyson (will_dyson at pobox.com)
+ *
+ * With help from the ntfs-tng driver by Anton Altparmakov
+ *
+ * Copyright (C) 1999  Makoto Kato (m_kato@ga2.so-net.ne.jp)
+ *
+ * debug functions
+ */
+
+#ifdef __KERNEL__
+
+#include <stdarg.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+
+#endif				/* __KERNEL__ */
+
+#include "befs_fs.h"
+#include "endian.h"
+
+#define ERRBUFSIZE 1024
+
+void
+befs_error(const struct super_block *sb, const char *fmt, ...)
+{
+	va_list args;
+	char err_buf[ERRBUFSIZE];
+
+	va_start(args, fmt);
+	vsnprintf(err_buf, ERRBUFSIZE, fmt, args);
+	va_end(args);
+
+	printk(KERN_ERR "BeFS(%s): %s\n", bdevname(sb->s_dev), err_buf);
+
+	befs_debug(sb, err_buf);
+}
+
+void
+befs_warning(const struct super_block *sb, const char *fmt, ...)
+{
+	va_list args;
+	char err_buf[ERRBUFSIZE];
+
+	va_start(args, fmt);
+	vsnprintf(err_buf, ERRBUFSIZE, fmt, args);
+	va_end(args);
+
+	printk(KERN_WARNING "BeFS(%s): %s\n", bdevname(sb->s_dev), err_buf);
+
+	befs_debug(sb, err_buf);
+}
+
+void
+befs_debug(const struct super_block *sb, const char *fmt, ...)
+{
+#ifdef CONFIG_BEFS_DEBUG
+
+	va_list args;
+	char err_buf[ERRBUFSIZE];
+
+	if (BEFS_SB(sb)->mount_opts.debug) {
+		va_start(args, fmt);
+		vsnprintf(err_buf, ERRBUFSIZE, fmt, args);
+		va_end(args);
+
+		printk(KERN_DEBUG "BeFS(%s): %s\n",
+		       bdevname(sb->s_dev), err_buf);
+	}
+#endif				//CONFIG_BEFS_DEBUG
+}
+
+void
+befs_dump_inode(const struct super_block *sb, befs_inode * inode)
+{
+#ifdef CONFIG_BEFS_DEBUG
+
+	befs_block_run tmp_run;
+
+	befs_debug(sb, "befs_inode infomation");
+
+	befs_debug(sb, "  magic1 %08x", fs32_to_cpu(sb, inode->magic1));
+
+	tmp_run = fsrun_to_cpu(sb, inode->inode_num);
+	befs_debug(sb, "  inode_num %u, %hu, %hu",
+		   tmp_run.allocation_group, tmp_run.start, tmp_run.len);
+
+	befs_debug(sb, "  uid %u", fs32_to_cpu(sb, inode->uid));
+	befs_debug(sb, "  gid %u", fs32_to_cpu(sb, inode->gid));
+	befs_debug(sb, "  mode %08x", fs32_to_cpu(sb, inode->mode));
+	befs_debug(sb, "  flags %08x", fs32_to_cpu(sb, inode->flags));
+	befs_debug(sb, "  create_time %Lu",
+		   fs64_to_cpu(sb, inode->create_time));
+	befs_debug(sb, "  last_modified_time %Lu",
+		   fs64_to_cpu(sb, inode->last_modified_time));
+
+	tmp_run = fsrun_to_cpu(sb, inode->parent);
+	befs_debug(sb, "  parent [%u, %hu, %hu]",
+		   tmp_run.allocation_group, tmp_run.start, tmp_run.len);
+
+	tmp_run = fsrun_to_cpu(sb, inode->attributes);
+	befs_debug(sb, "  attributes [%u, %hu, %hu]",
+		   tmp_run.allocation_group, tmp_run.start, tmp_run.len);
+
+	befs_debug(sb, "  type %08x", fs32_to_cpu(sb, inode->type));
+	befs_debug(sb, "  inode_size %u", fs32_to_cpu(sb, inode->inode_size));
+
+	if (S_ISLNK(inode->mode)) {
+		befs_debug(sb, "  Symbolic link [%s]", inode->data.symlink);
+	} else {
+		int i;
+
+		for (i = 0; i < BEFS_NUM_DIRECT_BLOCKS; i++) {
+			tmp_run =
+			    fsrun_to_cpu(sb, inode->data.datastream.direct[i]);
+			befs_debug(sb, "  direct %d [%u, %hu, %hu]", i,
+				   tmp_run.allocation_group, tmp_run.start,
+				   tmp_run.len);
+		}
+		befs_debug(sb, "  max_direct_range %Lu",
+			   fs64_to_cpu(sb,
+				       inode->data.datastream.
+				       max_direct_range));
+
+		tmp_run = fsrun_to_cpu(sb, inode->data.datastream.indirect);
+		befs_debug(sb, "  indirect [%u, %hu, %hu]",
+			   tmp_run.allocation_group,
+			   tmp_run.start, tmp_run.len);
+
+		befs_debug(sb, "  max_indirect_range %Lu",
+			   fs64_to_cpu(sb,
+				       inode->data.datastream.
+				       max_indirect_range));
+
+		tmp_run =
+		    fsrun_to_cpu(sb, inode->data.datastream.double_indirect);
+		befs_debug(sb, "  double indirect [%u, %hu, %hu]",
+			   tmp_run.allocation_group, tmp_run.start,
+			   tmp_run.len);
+
+		befs_debug(sb, "  max_double_indirect_range %Lu",
+			   fs64_to_cpu(sb,
+				       inode->data.datastream.
+				       max_double_indirect_range));
+
+		befs_debug(sb, "  size %Lu",
+			   fs64_to_cpu(sb, inode->data.datastream.size));
+	}
+
+#endif				//CONFIG_BEFS_DEBUG
+}
+
+/*
+ * Display super block structure for debug.
+ */
+
+void
+befs_dump_super_block(const struct super_block *sb, befs_super_block * sup)
+{
+#ifdef CONFIG_BEFS_DEBUG
+
+	befs_block_run tmp_run;
+
+	befs_debug(sb, "befs_super_block information");
+
+	befs_debug(sb, "  name %s", sup->name);
+	befs_debug(sb, "  magic1 %08x", fs32_to_cpu(sb, sup->magic1));
+	befs_debug(sb, "  fs_byte_order %08x",
+		   fs32_to_cpu(sb, sup->fs_byte_order));
+
+	befs_debug(sb, "  block_size %u", fs32_to_cpu(sb, sup->block_size));
+	befs_debug(sb, "  block_shift %u", fs32_to_cpu(sb, sup->block_shift));
+
+	befs_debug(sb, "  num_blocks %Lu", fs64_to_cpu(sb, sup->num_blocks));
+	befs_debug(sb, "  used_blocks %Lu", fs64_to_cpu(sb, sup->used_blocks));
+
+	befs_debug(sb, "  magic2 %08x", fs32_to_cpu(sb, sup->magic2));
+	befs_debug(sb, "  blocks_per_ag %u",
+		   fs32_to_cpu(sb, sup->blocks_per_ag));
+	befs_debug(sb, "  ag_shift %u", fs32_to_cpu(sb, sup->ag_shift));
+	befs_debug(sb, "  num_ags %u", fs32_to_cpu(sb, sup->num_ags));
+
+	befs_debug(sb, "  flags %08x", fs32_to_cpu(sb, sup->flags));
+
+	tmp_run = fsrun_to_cpu(sb, sup->log_blocks);
+	befs_debug(sb, "  log_blocks %u, %hu, %hu",
+		   tmp_run.allocation_group, tmp_run.start, tmp_run.len);
+
+	befs_debug(sb, "  log_start %Ld", fs64_to_cpu(sb, sup->log_start));
+	befs_debug(sb, "  log_end %Ld", fs64_to_cpu(sb, sup->log_end));
+
+	befs_debug(sb, "  magic3 %08x", fs32_to_cpu(sb, sup->magic3));
+
+	tmp_run = fsrun_to_cpu(sb, sup->root_dir);
+	befs_debug(sb, "  root_dir %u, %hu, %hu",
+		   tmp_run.allocation_group, tmp_run.start, tmp_run.len);
+
+	tmp_run = fsrun_to_cpu(sb, sup->indices);
+	befs_debug(sb, "  indices %u, %hu, %hu",
+		   tmp_run.allocation_group, tmp_run.start, tmp_run.len);
+
+#endif				//CONFIG_BEFS_DEBUG
+}
+
+void
+befs_dump_small_data(const struct super_block *sb, befs_small_data * sd)
+{
+}
+
+void
+befs_dump_run(const struct super_block *sb, befs_block_run run)
+{
+#ifdef CONFIG_BEFS_DEBUG
+
+	run = fsrun_to_cpu(sb, run);
+
+	befs_debug(sb, "[%u, %hu, %hu]",
+		   run.allocation_group, run.start, run.len);
+
+#endif				//CONFIG_BEFS_DEBUG
+}
+
+void
+befs_dump_index_entry(const struct super_block *sb, befs_btree_super * super)
+{
+#ifdef CONFIG_BEFS_DEBUG
+
+	befs_debug(sb, "Btree super structure");
+	befs_debug(sb, "  magic %08x", fs32_to_cpu(sb, super->magic));
+	befs_debug(sb, "  node_size %u", fs32_to_cpu(sb, super->node_size));
+	befs_debug(sb, "  max_depth %08x", fs32_to_cpu(sb, super->max_depth));
+
+	befs_debug(sb, "  data_type %08x", fs32_to_cpu(sb, super->data_type));
+	befs_debug(sb, "  root_node_pointer %016LX",
+		   fs64_to_cpu(sb, super->root_node_ptr));
+	befs_debug(sb, "  free_node_pointer %016LX",
+		   fs64_to_cpu(sb, super->free_node_ptr));
+	befs_debug(sb, "  maximum size %016LX",
+		   fs64_to_cpu(sb, super->max_size));
+
+#endif				//CONFIG_BEFS_DEBUG
+}
+
+void
+befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead * node)
+{
+#ifdef CONFIG_BEFS_DEBUG
+
+	befs_debug(sb, "Btree node structure");
+	befs_debug(sb, "  left %016LX", fs64_to_cpu(sb, node->left));
+	befs_debug(sb, "  right %016LX", fs64_to_cpu(sb, node->right));
+	befs_debug(sb, "  overflow %016LX", fs64_to_cpu(sb, node->overflow));
+	befs_debug(sb, "  all_key_count %hu",
+		   fs16_to_cpu(sb, node->all_key_count));
+	befs_debug(sb, "  all_key_length %hu",
+		   fs16_to_cpu(sb, node->all_key_length));
+
+#endif				//CONFIG_BEFS_DEBUG
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/befs/endian.h linux-2.4.20/fs/befs/endian.h
--- linux-2.4.19/fs/befs/endian.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/befs/endian.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,126 @@
+/*
+ * linux/fs/befs/endian.h
+ *
+ * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com>
+ *
+ * Partially based on similar funtions in the sysv driver.
+ */
+
+#ifndef LINUX_BEFS_ENDIAN
+#define LINUX_BEFS_ENDIAN
+
+#include <linux/byteorder/generic.h>
+#include "befs_fs.h"
+
+static inline u64
+fs64_to_cpu(const struct super_block *sb, u64 n)
+{
+	if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
+		return le64_to_cpu(n);
+	else
+		return be64_to_cpu(n);
+}
+
+static inline u64
+cpu_to_fs64(const struct super_block *sb, u64 n)
+{
+	if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
+		return cpu_to_le64(n);
+	else
+		return cpu_to_be64(n);
+}
+
+static inline u32
+fs32_to_cpu(const struct super_block *sb, u32 n)
+{
+	if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
+		return le32_to_cpu(n);
+	else
+		return be32_to_cpu(n);
+}
+
+static inline u32
+cpu_to_fs32(const struct super_block *sb, u32 n)
+{
+	if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
+		return cpu_to_le32(n);
+	else
+		return cpu_to_be32(n);
+}
+
+static inline u16
+fs16_to_cpu(const struct super_block *sb, u16 n)
+{
+	if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
+		return le16_to_cpu(n);
+	else
+		return be16_to_cpu(n);
+}
+
+static inline u16
+cpu_to_fs16(const struct super_block *sb, u16 n)
+{
+	if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
+		return cpu_to_le16(n);
+	else
+		return cpu_to_be16(n);
+}
+
+/* Composite types below here */
+
+static inline befs_block_run
+fsrun_to_cpu(const struct super_block *sb, befs_block_run n)
+{
+	befs_block_run run;
+
+	if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) {
+		run.allocation_group = le32_to_cpu(n.allocation_group);
+		run.start = le16_to_cpu(n.start);
+		run.len = le16_to_cpu(n.len);
+	} else {
+		run.allocation_group = be32_to_cpu(n.allocation_group);
+		run.start = be16_to_cpu(n.start);
+		run.len = be16_to_cpu(n.len);
+	}
+	return run;
+}
+
+static inline befs_block_run
+cpu_to_fsrun(const struct super_block *sb, befs_block_run n)
+{
+	befs_block_run run;
+
+	if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) {
+		run.allocation_group = cpu_to_le32(n.allocation_group);
+		run.start = cpu_to_le16(n.start);
+		run.len = cpu_to_le16(n.len);
+	} else {
+		run.allocation_group = cpu_to_be32(n.allocation_group);
+		run.start = cpu_to_be16(n.start);
+		run.len = cpu_to_be16(n.len);
+	}
+	return run;
+}
+
+static inline befs_data_stream
+fsds_to_cpu(const struct super_block *sb, befs_data_stream n)
+{
+	befs_data_stream data;
+	int i;
+
+	for (i = 0; i < BEFS_NUM_DIRECT_BLOCKS; ++i)
+		data.direct[i] = fsrun_to_cpu(sb, n.direct[i]);
+
+	data.max_direct_range = fs64_to_cpu(sb, n.max_direct_range);
+	data.indirect = fsrun_to_cpu(sb, n.indirect);
+	data.max_indirect_range = fs64_to_cpu(sb, n.max_indirect_range);
+	data.double_indirect = fsrun_to_cpu(sb, n.double_indirect);
+	data.max_double_indirect_range = fs64_to_cpu(sb,
+						     n.
+						     max_double_indirect_range);
+	data.size = fs64_to_cpu(sb, n.size);
+
+	return data;
+}
+
+#endif				//LINUX_BEFS_ENDIAN
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/befs/inode.c linux-2.4.20/fs/befs/inode.c
--- linux-2.4.19/fs/befs/inode.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/befs/inode.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,52 @@
+/*
+ * inode.c
+ * 
+ * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com>
+ */
+
+#include <linux/fs.h>
+
+#include "befs_fs.h"
+#include "endian.h"
+
+/*
+	Validates the correctness of the befs inode
+	Returns BEFS_OK if the inode should be used, otherwise
+	returns BEFS_BAD_INODE
+*/
+int
+befs_check_inode(struct super_block *sb, befs_inode * raw_inode,
+		 befs_blocknr_t inode)
+{
+	__u32 magic1 = fs32_to_cpu(sb, raw_inode->magic1);
+	befs_inode_addr ino_num = fsrun_to_cpu(sb, raw_inode->inode_num);
+	__u32 flags = fs32_to_cpu(sb, raw_inode->flags);
+
+	/* check magic header. */
+	if (magic1 != BEFS_INODE_MAGIC1) {
+		befs_error(sb,
+			   "Inode has a bad magic header - inode = %lu", inode);
+		return BEFS_BAD_INODE;
+	}
+
+	/*
+	 * Sanity check2: inodes store their own block address. Check it.
+	 */
+	if (inode != iaddr2blockno(sb, &ino_num)) {
+		befs_error(sb, "inode blocknr field disagrees with vfs "
+			   "VFS: %lu, Inode %lu",
+			   inode, iaddr2blockno(sb, &ino_num));
+		return BEFS_BAD_INODE;
+	}
+
+	/*
+	 * check flag
+	 */
+
+	if (!(flags & BEFS_INODE_IN_USE)) {
+		befs_error(sb, "inode is not used - inode = %lu", inode);
+		return BEFS_BAD_INODE;
+	}
+
+	return BEFS_OK;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/befs/io.c linux-2.4.20/fs/befs/io.c
--- linux-2.4.19/fs/befs/io.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/befs/io.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,98 @@
+/*
+ * linux/fs/befs/io.c
+ *
+ * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com
+ *
+ * Based on portions of file.c and inode.c 
+ * by Makoto Kato (m_kato@ga2.so-net.ne.jp)
+ *
+ * Many thanks to Dominic Giampaolo, author of Practical File System
+ * Design with the Be File System, for such a helpful book.
+ *
+ */
+
+#include <linux/fs.h>
+
+#include "befs_fs.h"
+
+/*
+ * Converts befs notion of disk addr to a disk offset and uses
+ * linux kernel function bread() to get the buffer containing
+ * the offset. -Will Dyson
+ *
+ */
+
+struct buffer_head *
+befs_bread_iaddr(struct super_block *sb, befs_inode_addr iaddr)
+{
+	struct buffer_head *bh = NULL;
+	befs_blocknr_t block = 0;
+	vfs_blocknr_t vfs_block = 0;
+	befs_sb_info *befs_sb = BEFS_SB(sb);
+
+	befs_debug(sb, "---> Enter befs_read_iaddr() "
+		   "[%u, %hu, %hu]",
+		   iaddr.allocation_group, iaddr.start, iaddr.len);
+
+	if (iaddr.allocation_group > befs_sb->num_ags) {
+		befs_error(sb, "BEFS: Invalid allocation group %u, max is %u",
+			   iaddr.allocation_group, befs_sb->num_ags);
+		goto error;
+	}
+
+	block = iaddr2blockno(sb, &iaddr);
+	vfs_block = (vfs_blocknr_t) block;
+
+	if (vfs_block != block) {
+		befs_error(sb, "Error converting to host blocknr_t. %Lu "
+			   "is larger than the host can use", block);
+		goto error;
+	}
+
+	befs_debug(sb, "befs_read_iaddr: offset = %lu", block);
+
+	bh = bread(sb->s_dev, vfs_block, befs_sb->block_size);
+
+	if (bh == NULL) {
+		befs_error(sb, "Failed to read block %lu", block);
+		goto error;
+	}
+
+	befs_debug(sb, "<--- befs_read_iaddr()");
+	return bh;
+
+      error:
+	befs_debug(sb, "<--- befs_read_iaddr() ERROR");
+	return NULL;
+}
+
+struct buffer_head *
+befs_bread(struct super_block *sb, befs_blocknr_t block)
+{
+	struct buffer_head *bh = NULL;
+	befs_sb_info *befs_sb = BEFS_SB(sb);
+	vfs_blocknr_t vfs_block = (vfs_blocknr_t) block;
+
+	befs_debug(sb, "---> Enter befs_read() %Lu", block);
+
+	if (vfs_block != block) {
+		befs_error(sb, "Error converting to host blocknr_t. %Lu "
+			   "is larger than the host can use", block);
+		goto error;
+	}
+
+	bh = bread(sb->s_dev, vfs_block, befs_sb->block_size);
+
+	if (bh == NULL) {
+		befs_error(sb, "Failed to read block %lu", vfs_block);
+		goto error;
+	}
+
+	befs_debug(sb, "<--- befs_read()");
+
+	return bh;
+
+      error:
+	befs_debug(sb, "<--- befs_read() ERROR");
+	return NULL;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/befs/linuxvfs.c linux-2.4.20/fs/befs/linuxvfs.c
--- linux-2.4.19/fs/befs/linuxvfs.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/befs/linuxvfs.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,956 @@
+/*
+ * linux/fs/befs/linuxvfs.c
+ *
+ * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com
+ *
+ */
+
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+#include "befs_fs.h"
+#include "endian.h"
+
+EXPORT_NO_SYMBOLS;
+MODULE_DESCRIPTION("BeOS File System (BeFS) driver");
+MODULE_AUTHOR("Will Dyson");
+MODULE_LICENSE("GPL");
+
+/* The units the vfs expects inode->i_blocks to be in */
+#define VFS_BLOCK_SIZE 512
+
+static int befs_readdir(struct file *, void *, filldir_t);
+static int befs_get_block(struct inode *, long, struct buffer_head *, int);
+static int befs_readpage(struct file *file, struct page *page);
+static int befs_bmap(struct address_space *mapping, long block);
+static struct dentry *befs_lookup(struct inode *, struct dentry *);
+static void befs_read_inode(struct inode *ino);
+static void befs_clear_inode(struct inode *ino);
+static int befs_init_inodecache(void);
+static void befs_destroy_inodecache(void);
+static int befs_readlink(struct dentry *, char *, int);
+static int befs_follow_link(struct dentry *, struct nameidata *nd);
+static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,
+			char **out, int *out_len);
+static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,
+			char **out, int *out_len);
+static void befs_put_super(struct super_block *);
+static struct super_block *befs_read_super(struct super_block *, void *, int);
+static int befs_remount(struct super_block *, int *, char *);
+static int befs_statfs(struct super_block *, struct statfs *);
+static int parse_options(char *, befs_mount_options *);
+
+static const struct super_operations befs_sops = {
+	read_inode:befs_read_inode,	/* initialize & read inode */
+	clear_inode:befs_clear_inode,	/* uninit inode */
+	put_super:befs_put_super,	/* uninit super */
+	statfs:befs_statfs,	/* statfs */
+	remount_fs:befs_remount	/* remount_fs */
+};
+
+/* slab cache for befs_inode_info objects */
+static kmem_cache_t *befs_inode_cachep;
+
+struct file_operations befs_dir_operations = {
+	read:generic_read_dir,	/* read */
+	readdir:befs_readdir,	/* readdir */
+};
+
+struct inode_operations befs_dir_inode_operations = {
+	lookup:befs_lookup,	/* lookup */
+};
+
+struct file_operations befs_file_operations = {
+	llseek:default_llseek,
+	read:generic_file_read,	/* read */
+	mmap:generic_file_mmap,	/* mmap */
+};
+
+struct address_space_operations befs_aops = {
+	readpage:befs_readpage,
+	sync_page:block_sync_page,
+	bmap:befs_bmap,
+};
+
+static struct inode_operations befs_symlink_inode_operations = {
+	readlink:befs_readlink,	/* readlink */
+	follow_link:befs_follow_link	/* follow_link */
+};
+
+/* 
+ * Called by generic_file_read() to read a page of data
+ * 
+ * In turn, simply calls a generic block read function and
+ * passes it the address of befs_get_block, for mapping file
+ * positions to disk blocks.
+ */
+static int
+befs_readpage(struct file *file, struct page *page)
+{
+	return block_read_full_page(page, befs_get_block);
+}
+
+static int
+befs_bmap(struct address_space *mapping, long block)
+{
+	return generic_block_bmap(mapping, block, befs_get_block);
+}
+
+/* 
+ * Generic function to map a file position (block) to a 
+ * disk offset (passed back in bh_result).
+ *
+ * Used by many higher level functions.
+ *
+ * Calls befs_fblock2brun() in datastream.c to do the real work.
+ *
+ * -WD 10-26-01
+ */
+
+static int
+befs_get_block(struct inode *inode, long block,
+	       struct buffer_head *bh_result, int create)
+{
+	struct super_block *sb = inode->i_sb;
+	befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;
+	befs_block_run run = BAD_IADDR;
+	int res = 0;
+	ulong disk_off;
+
+	befs_debug(sb, "---> befs_get_block() for inode %lu, block %ld",
+		   inode->i_ino, block);
+
+	if (block < 0) {
+		befs_error(sb, "befs_get_block() was asked for a block "
+			   "number less than zero: block %ld in inode %lu",
+			   block, inode->i_ino);
+		return -EIO;
+	}
+
+	if (create) {
+		befs_error(sb, "befs_get_block() was asked to write to "
+			   "block %ld in inode %lu", block, inode->i_ino);
+		return -EPERM;
+	}
+
+	res = befs_fblock2brun(sb, ds, block, &run);
+	if (res != BEFS_OK) {
+		befs_error(sb,
+			   "<--- befs_get_block() for inode %lu, block "
+			   "%ld ERROR", inode->i_ino, block);
+		return -EFBIG;
+	}
+
+	disk_off = (ulong) iaddr2blockno(sb, &run);
+
+	bh_result->b_dev = inode->i_dev;
+	bh_result->b_blocknr = disk_off;
+	bh_result->b_state |= (1UL << BH_Mapped);
+
+	befs_debug(sb, "<--- befs_get_block() for inode %lu, block %ld, "
+		   "disk address %lu", inode->i_ino, block, disk_off);
+
+	return 0;
+}
+
+static struct dentry *
+befs_lookup(struct inode *dir, struct dentry *dentry)
+{
+	struct inode *inode = NULL;
+	struct super_block *sb = dir->i_sb;
+	befs_data_stream *ds = &BEFS_I(dir)->i_data.ds;
+	befs_off_t offset;
+	int ret;
+	int utfnamelen;
+	char *utfname;
+	const char *name = dentry->d_name.name;
+
+	befs_debug(sb, "---> befs_lookup() "
+		   "name %s inode %ld", dentry->d_name.name, dir->i_ino);
+
+	/* Convert to UTF-8 */
+	if (BEFS_SB(sb)->nls) {
+		ret =
+		    befs_nls2utf(sb, name, strlen(name), &utfname, &utfnamelen);
+		if (ret < 0) {
+			befs_debug(sb, "<--- befs_lookup() ERROR");
+			return ERR_PTR(ret);
+		}
+		ret = befs_btree_find(sb, ds, utfname, &offset);
+		kfree(utfname);
+
+	} else {
+		ret = befs_btree_find(sb, ds, dentry->d_name.name, &offset);
+	}
+
+	if (ret == BEFS_BT_NOT_FOUND) {
+		befs_debug(sb, "<--- befs_lookup() %s not found",
+			   dentry->d_name.name);
+		return ERR_PTR(-ENOENT);
+
+	} else if (ret != BEFS_OK || offset == 0) {
+		befs_warning(sb, "<--- befs_lookup() Error");
+		return ERR_PTR(-ENODATA);
+	}
+
+	inode = iget(dir->i_sb, (ino_t) offset);
+	if (!inode)
+		return ERR_PTR(-EACCES);
+
+	d_add(dentry, inode);
+
+	befs_debug(sb, "<--- befs_lookup()");
+
+	return NULL;
+}
+
+static int
+befs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+	struct inode *inode = filp->f_dentry->d_inode;
+	struct super_block *sb = inode->i_sb;
+	befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;
+	befs_off_t value;
+	int result;
+	size_t keysize;
+	unsigned char d_type;
+	char keybuf[BEFS_NAME_LEN + 1];
+	char *nlsname;
+	int nlsnamelen;
+	const char *dirname = filp->f_dentry->d_name.name;
+
+	befs_debug(sb, "---> befs_readdir() "
+		   "name %s, inode %ld, filp->f_pos %Ld",
+		   dirname, inode->i_ino, filp->f_pos);
+
+	result = befs_btree_read(sb, ds, filp->f_pos, BEFS_NAME_LEN + 1,
+				 keybuf, &keysize, &value);
+
+	if (result == BEFS_ERR) {
+		befs_debug(sb, "<--- befs_readdir() ERROR");
+		befs_error(sb, "IO error reading %s (inode %lu)",
+			   dirname, inode->i_ino);
+		return -EIO;
+
+	} else if (result == BEFS_BT_END) {
+		befs_debug(sb, "<--- befs_readdir() END");
+		return 0;
+
+	} else if (result == BEFS_BT_EMPTY) {
+		befs_debug(sb, "<--- befs_readdir() Empty directory");
+		return 0;
+	}
+
+	d_type = DT_UNKNOWN;
+
+	/* Convert to NLS */
+	if (BEFS_SB(sb)->nls) {
+		result =
+		    befs_utf2nls(sb, keybuf, keysize, &nlsname, &nlsnamelen);
+		if (result < 0) {
+			befs_debug(sb, "<--- befs_readdir() ERROR");
+			return result;
+		}
+		result = filldir(dirent, nlsname, nlsnamelen, filp->f_pos,
+				 (ino_t) value, d_type);
+		kfree(nlsname);
+
+	} else {
+		result = filldir(dirent, keybuf, keysize, filp->f_pos,
+				 (ino_t) value, d_type);
+	}
+
+	filp->f_pos++;
+
+	befs_debug(sb, "<--- befs_readdir() filp->f_pos %Ld", filp->f_pos);
+
+	return 0;
+}
+
+static void
+befs_clear_inode(struct inode *inode)
+{
+	befs_inode_info *b_ino = BEFS_I(inode);
+	inode->u.generic_ip = NULL;
+
+	if (b_ino) {
+		kmem_cache_free(befs_inode_cachep, b_ino);
+	}
+	return;
+}
+
+static void
+befs_read_inode(struct inode *inode)
+{
+	struct buffer_head *bh = NULL;
+	befs_inode *raw_inode = NULL;
+
+	struct super_block *sb = inode->i_sb;
+	befs_sb_info *befs_sb = BEFS_SB(sb);
+	befs_inode_info *befs_ino = NULL;
+
+	befs_debug(sb, "---> befs_read_inode() " "inode = %lu", inode->i_ino);
+
+	inode->u.generic_ip = kmem_cache_alloc(befs_inode_cachep, GFP_NOFS);
+	if (inode->u.generic_ip == NULL) {
+		befs_error(sb, "Unable to allocate memory for private "
+			   "portion of inode %lu.", inode->i_ino);
+		goto unaquire_none;
+	}
+	befs_ino = BEFS_I(inode);
+
+	/* convert from vfs's inode number to befs's inode number */
+	befs_ino->i_inode_num = blockno2iaddr(sb, inode->i_ino);
+
+	befs_debug(sb, "  real inode number [%u, %hu, %hu]",
+		   befs_ino->i_inode_num.allocation_group,
+		   befs_ino->i_inode_num.start, befs_ino->i_inode_num.len);
+
+	bh = befs_bread_iaddr(sb, befs_ino->i_inode_num);
+	if (!bh) {
+		befs_error(sb, "unable to read inode block - "
+			   "inode = %lu", inode->i_ino);
+		goto unaquire_ino_info;
+	}
+
+	raw_inode = (befs_inode *) bh->b_data;
+
+	befs_dump_inode(sb, raw_inode);
+
+	if (befs_check_inode(sb, raw_inode, inode->i_ino) != BEFS_OK) {
+		befs_error(sb, "Bad inode: %lu", inode->i_ino);
+		goto unaquire_bh;
+	}
+
+	inode->i_mode = (umode_t) fs32_to_cpu(sb, raw_inode->mode);
+
+	/*
+	 * set uid and gid.  But since current BeOS is single user OS, so
+	 * you can change by "uid" or "gid" options.
+	 */
+
+	inode->i_uid = befs_sb->mount_opts.use_uid ?
+	    befs_sb->mount_opts.uid : (uid_t) fs32_to_cpu(sb, raw_inode->uid);
+	inode->i_gid = befs_sb->mount_opts.use_gid ?
+	    befs_sb->mount_opts.gid : (gid_t) fs32_to_cpu(sb, raw_inode->gid);
+
+	inode->i_nlink = 1;
+
+	/*
+	 * BEFS's time is 64 bits, but current VFS is 32 bits...
+	 * BEFS don't have access time. Nor inode change time. VFS
+	 * doesn't have creation time.
+	 */
+
+	inode->i_mtime =
+	    (time_t) (fs64_to_cpu(sb, raw_inode->last_modified_time) >> 16);
+	inode->i_ctime = inode->i_mtime;
+	inode->i_atime = inode->i_mtime;
+
+/* Bloody hell, Linus. Why add this in a stable series? */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,9)
+	inode->i_blkbits = befs_sb->block_shift;
+#endif
+
+	inode->i_blksize = befs_sb->block_size;
+
+	befs_ino->i_inode_num = fsrun_to_cpu(sb, raw_inode->inode_num);
+	befs_ino->i_parent = fsrun_to_cpu(sb, raw_inode->parent);
+	befs_ino->i_attribute = fsrun_to_cpu(sb, raw_inode->attributes);
+	befs_ino->i_flags = fs32_to_cpu(sb, raw_inode->flags);
+
+	if (S_ISLNK(inode->i_mode) && !(inode->i_flags & BEFS_LONG_SYMLINK)) {
+		inode->i_size = 0;
+		inode->i_blocks = befs_sb->block_size / VFS_BLOCK_SIZE;
+		strncpy(befs_ino->i_data.symlink, raw_inode->data.symlink,
+			BEFS_SYMLINK_LEN);
+	} else {
+		int num_blks;
+
+		befs_ino->i_data.ds =
+		    fsds_to_cpu(sb, raw_inode->data.datastream);
+
+		num_blks = befs_count_blocks(sb, &befs_ino->i_data.ds);
+		inode->i_blocks =
+		    num_blks * (befs_sb->block_size / VFS_BLOCK_SIZE);
+		inode->i_size = befs_ino->i_data.ds.size;
+	}
+
+	inode->i_mapping->a_ops = &befs_aops;
+
+	if (S_ISREG(inode->i_mode)) {
+		inode->i_fop = &befs_file_operations;
+	} else if (S_ISDIR(inode->i_mode)) {
+		inode->i_op = &befs_dir_inode_operations;
+		inode->i_fop = &befs_dir_operations;
+	} else if (S_ISLNK(inode->i_mode)) {
+		inode->i_op = &befs_symlink_inode_operations;
+	} else {
+		befs_error(sb, "Inode %lu is not a regular file, "
+			   "directory or symlink. THAT IS WRONG! BeFS has no "
+			   "on disk special files", inode->i_ino);
+		goto unaquire_bh;
+	}
+
+	brelse(bh);
+	befs_debug(sb, "<--- befs_read_inode()");
+	return;
+
+      unaquire_bh:
+	brelse(bh);
+
+      unaquire_ino_info:
+	kmem_cache_free(befs_inode_cachep, inode->u.generic_ip);
+
+      unaquire_none:
+	make_bad_inode(inode);
+	inode->u.generic_ip = NULL;
+	befs_debug(sb, "<--- befs_read_inode() - Bad inode");
+	return;
+}
+
+/* Initialize the inode cache. Called at fs setup.
+ * 
+ * Taken from NFS implementation by Al Viro.
+ */
+static int
+befs_init_inodecache(void)
+{
+	befs_inode_cachep = kmem_cache_create("befs_inode_cache",
+					      sizeof (struct befs_inode_info),
+					      0, SLAB_HWCACHE_ALIGN,
+					      NULL, NULL);
+	if (befs_inode_cachep == NULL) {
+		printk(KERN_ERR "befs_init_inodecache: "
+		       "Couldn't initalize inode slabcache\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/* Called at fs teardown.
+ * 
+ * Taken from NFS implementation by Al Viro.
+ */
+static void
+befs_destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(befs_inode_cachep))
+		printk(KERN_ERR "befs_destroy_inodecache: "
+		       "not all structures were freed\n");
+}
+
+/*
+ * The inode of symbolic link is different to data stream.
+ * The data stream become link name. Unless the LONG_SYMLINK
+ * flag is set.
+ */
+static int
+befs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	struct super_block *sb = dentry->d_sb;
+	befs_inode_info *befs_ino = BEFS_I(dentry->d_inode);
+	char *link;
+	int res;
+
+	if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
+		befs_data_stream *data = &befs_ino->i_data.ds;
+		befs_off_t linklen = data->size;
+
+		befs_debug(sb, "Follow long symlink");
+
+		link = kmalloc(linklen, GFP_NOFS);
+		if (link == NULL)
+			return -ENOMEM;
+
+		if (befs_read_lsymlink(sb, data, link, linklen) != linklen) {
+			kfree(link);
+			befs_error(sb, "Failed to read entire long symlink");
+			return -EIO;
+		}
+
+		res = vfs_follow_link(nd, link);
+
+		kfree(link);
+	} else {
+		link = befs_ino->i_data.symlink;
+		res = vfs_follow_link(nd, link);
+	}
+
+	return res;
+}
+
+static int
+befs_readlink(struct dentry *dentry, char *buffer, int buflen)
+{
+	struct super_block *sb = dentry->d_sb;
+	befs_inode_info *befs_ino = BEFS_I(dentry->d_inode);
+	char *link;
+	int res;
+
+	if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
+		befs_data_stream *data = &befs_ino->i_data.ds;
+		befs_off_t linklen = data->size;
+
+		befs_debug(sb, "Read long symlink");
+
+		link = kmalloc(linklen, GFP_NOFS);
+		if (link == NULL)
+			return -ENOMEM;
+
+		if (befs_read_lsymlink(sb, data, link, linklen) != linklen) {
+			kfree(link);
+			befs_error(sb, "Failed to read entire long symlink");
+			return -EIO;
+		}
+
+		res = vfs_readlink(dentry, buffer, buflen, link);
+
+		kfree(link);
+	} else {
+		link = befs_ino->i_data.symlink;
+		res = vfs_readlink(dentry, buffer, buflen, link);
+	}
+
+	return res;
+}
+
+/*
+ * UTF-8 to NLS charset  convert routine
+ *
+ * Changed 8/10/01 by Will Dyson. Now use uni2char() / char2uni() rather than
+ * the nls tables directly
+ */
+
+static int
+befs_utf2nls(struct super_block *sb, const char *in,
+	     int in_len, char **out, int *out_len)
+{
+	struct nls_table *nls = BEFS_SB(sb)->nls;
+	int i, o;
+	wchar_t uni;
+	int unilen, utflen;
+	char *result;
+	int maxlen = in_len; /* The utf8->nls conversion cant make more chars */
+
+	befs_debug(sb, "---> utf2nls()");
+
+	if (!nls) {
+		befs_error(sb, "befs_utf2nls called with no NLS table loaded");
+		return -EINVAL;
+	}
+
+	*out = result = kmalloc(maxlen, GFP_NOFS);
+	if (!*out) {
+		befs_error(sb, "befs_utf2nls() cannot allocate memory");
+		*out_len = 0;
+		return -ENOMEM;
+	}
+
+	for (i = o = 0; i < in_len; i += utflen, o += unilen) {
+
+		/* convert from UTF-8 to Unicode */
+		utflen = utf8_mbtowc(&uni, &in[i], in_len - i);
+		if (utflen < 0) {
+			goto conv_err;
+		}
+
+		/* convert from Unicode to nls */
+		unilen = nls->uni2char(uni, &result[o], 1);
+		if (unilen < 0) {
+			goto conv_err;
+		}
+	}
+	result[o] = '\0';
+
+	befs_debug(sb, "<--- utf2nls()");
+
+	return o;
+	*out_len = o;
+
+      conv_err:
+	befs_error(sb, "Name using charecter set %s contains a charecter that "
+		   "cannot be converted to unicode.", nls->charset);
+	befs_debug(sb, "<--- utf2nls()");
+	kfree(result);
+	return -EILSEQ;
+}
+
+/**
+ * befs_nls2utf - Convert NLS string to utf8 encodeing
+ * @sb: Superblock
+ * @src: Input string buffer in NLS format
+ * @srclen: Length of input string in bytes
+ * @dest: The output string in UTF8 format
+ * @destlen: Length of the output buffer
+ * 
+ * Converts input string @src, which is in the format of the loaded NLS map,
+ * into a utf8 string.
+ * 
+ * The destination string @dest is allocated by this function and the caller is
+ * responsible for freeing it with kfree()
+ * 
+ * On return, *@destlen is the length of @dest in bytes.
+ *
+ * On success, the return value is the number of utf8 charecters written to
+ * the ouput buffer @dest.
+ *  
+ * On Failure, a negative number coresponding to the error code is returned.
+ */
+
+static int
+befs_nls2utf(struct super_block *sb, const char *in,
+	     int in_len, char **out, int *out_len)
+{
+	struct nls_table *nls = BEFS_SB(sb)->nls;
+	int i, o;
+	wchar_t uni;
+	int unilen, utflen;
+	char *result;
+	int maxlen = 3 * in_len;
+
+	befs_debug(sb, "---> nls2utf()\n");
+
+	if (!nls) {
+		befs_error(sb, "befs_nls2utf called with no NLS table loaded.");
+		return -EINVAL;
+	}
+
+	*out = result = kmalloc(maxlen, GFP_NOFS);
+	if (!*out) {
+		befs_error(sb, "befs_nls2utf() cannot allocate memory");
+		*out_len = 0;
+		return -ENOMEM;
+	}
+
+	for (i = o = 0; i < in_len; i += unilen, o += utflen) {
+
+		/* convert from nls to unicode */
+		unilen = nls->char2uni(&in[i], in_len - i, &uni);
+		if (unilen < 0) {
+			goto conv_err;
+		}
+
+		/* convert from unicode to UTF-8 */
+		utflen = utf8_wctomb(&result[o], uni, 3);
+		if (utflen <= 0) {
+			goto conv_err;
+		}
+	}
+
+	result[o] = '\0';
+	*out_len = o;
+
+	befs_debug(sb, "<--- nls2utf()");
+
+	return i;
+
+      conv_err:
+	befs_error(sb, "Name using charecter set %s contains a charecter that "
+		   "cannot be converted to unicode.", nls->charset);
+	befs_debug(sb, "<--- nls2utf()");
+	kfree(result);
+	return -EILSEQ;
+}
+
+static int
+parse_options(char *options, befs_mount_options * opts)
+{
+	char *this_char;
+	char *value;
+	int ret = 1;
+
+	/* Initialize options */
+	opts->uid = 0;
+	opts->gid = 0;
+	opts->use_uid = 0;
+	opts->use_gid = 0;
+	opts->iocharset = NULL;
+	opts->debug = 0;
+
+	if (!options)
+		return ret;
+
+	for (this_char = strtok(options, ","); this_char != NULL;
+	     this_char = strtok(NULL, ",")) {
+
+		if ((value = strchr(this_char, '=')) != NULL)
+			*value++ = 0;
+
+		if (!strcmp(this_char, "uid")) {
+			if (!value || !*value) {
+				ret = 0;
+			} else {
+				opts->uid = simple_strtoul(value, &value, 0);
+				opts->use_uid = 1;
+				if (*value) {
+					printk(KERN_ERR "BEFS: Invalid uid "
+					       "option: %s\n", value);
+					ret = 0;
+				}
+			}
+		} else if (!strcmp(this_char, "gid")) {
+			if (!value || !*value)
+				ret = 0;
+			else {
+				opts->gid = simple_strtoul(value, &value, 0);
+				opts->use_gid = 1;
+				if (*value) {
+					printk(KERN_ERR
+					       "BEFS: Invalid gid option: "
+					       "%s\n", value);
+					ret = 0;
+				}
+			}
+		} else if (!strcmp(this_char, "iocharset") && value) {
+			char *p = value;
+			int len;
+
+			while (*value && *value != ',')
+				value++;
+			len = value - p;
+			if (len) {
+				char *buffer = kmalloc(len + 1, GFP_NOFS);
+				if (buffer) {
+					opts->iocharset = buffer;
+					memcpy(buffer, p, len);
+					buffer[len] = 0;
+
+				} else {
+					printk(KERN_ERR "BEFS: "
+					       "cannot allocate memory\n");
+					ret = 0;
+				}
+			}
+		} else if (!strcmp(this_char, "debug")) {
+			opts->debug = 1;
+		}
+	}
+
+	return ret;
+}
+
+/* This function has the responsibiltiy of getting the
+ * filesystem ready for unmounting. 
+ * Basicly, we free everything that we allocated in
+ * befs_read_inode
+ */
+static void
+befs_put_super(struct super_block *sb)
+{
+	if (BEFS_SB(sb)->mount_opts.iocharset) {
+		kfree(BEFS_SB(sb)->mount_opts.iocharset);
+		BEFS_SB(sb)->mount_opts.iocharset = NULL;
+	}
+
+	if (BEFS_SB(sb)->nls) {
+		unload_nls(BEFS_SB(sb)->nls);
+		BEFS_SB(sb)->nls = NULL;
+	}
+
+	if (sb->u.generic_sbp) {
+		kfree(sb->u.generic_sbp);
+		sb->u.generic_sbp = NULL;
+	}
+	return;
+}
+
+/* Allocate private field of the superblock, fill it.
+ *
+ * Finish filling the public superblock fields
+ * Make the root directory
+ * Load a set of NLS translations if needed.
+ */
+static struct super_block *
+befs_read_super(struct super_block *sb, void *data, int silent)
+{
+	struct buffer_head *bh;
+	befs_sb_info *befs_sb;
+	befs_super_block *disk_sb;
+	int blocksize;
+
+	const unsigned long sb_block = 0;
+	const off_t x86_sb_off = 512;
+
+	sb->u.generic_sbp = kmalloc(sizeof (struct befs_sb_info), GFP_NOFS);
+	if (sb->u.generic_sbp == NULL) {
+		printk(KERN_ERR
+		       "BeFS(%s): Unable to allocate memory for private "
+		       "portion of superblock. Bailing.\n",
+		       kdevname(sb->s_dev));
+		goto unaquire_none;
+	}
+	befs_sb = BEFS_SB(sb);
+
+	if (!parse_options((char *) data, &befs_sb->mount_opts)) {
+		befs_error(sb, "cannot parse mount options");
+		goto unaquire_priv_sbp;
+	}
+
+	befs_debug(sb, "---> befs_read_super()");
+
+#ifndef CONFIG_BEFS_RW
+	if (!(sb->s_flags & MS_RDONLY)) {
+		befs_warning(sb,
+			     "No write support. Marking filesystem read-only");
+		sb->s_flags |= MS_RDONLY;
+	}
+#endif				/* CONFIG_BEFS_RW */
+
+	/*
+	 * Set dummy blocksize to read super block.
+	 * Will be set to real fs blocksize later.
+	 *
+	 * Linux 2.4.10 and later refuse to read blocks smaller than
+	 * the hardsect size for the device. But we also need to read at 
+	 * least 1k to get the second 512 bytes of the volume.
+	 * -WD 10-26-01
+	 */
+	blocksize = max_t(int, get_hardsect_size(sb->s_dev), 1024);
+	set_blocksize(sb->s_dev, blocksize);
+
+	if (!(bh = bread(sb->s_dev, sb_block, blocksize))) {
+		befs_error(sb, "unable to read superblock");
+		goto unaquire_priv_sbp;
+	}
+
+	/* account for offset of super block on x86 */
+	disk_sb = (befs_super_block *) bh->b_data;
+	if ((le32_to_cpu(disk_sb->magic1) == BEFS_SUPER_MAGIC1) ||
+	    (be32_to_cpu(disk_sb->magic1) == BEFS_SUPER_MAGIC1)) {
+		befs_debug(sb, "Using PPC superblock location");
+	} else {
+		befs_debug(sb, "Using x86 superblock location");
+		disk_sb =
+		    (befs_super_block *) ((void *) bh->b_data + x86_sb_off);
+	}
+
+	if (befs_load_sb(sb, disk_sb) != BEFS_OK)
+		goto unaquire_bh;
+
+	befs_dump_super_block(sb, disk_sb);
+
+	brelse(bh);
+
+	if (befs_check_sb(sb) != BEFS_OK)
+		goto unaquire_priv_sbp;
+
+	/*
+	 * set up enough so that it can read an inode
+	 * Fill in kernel superblock fields from private sb
+	 */
+	sb->s_magic = BEFS_SUPER_MAGIC;
+	sb->s_blocksize = (ulong) befs_sb->block_size;
+	sb->s_blocksize_bits = (unsigned char) befs_sb->block_shift;
+	sb->s_op = (struct super_operations *) &befs_sops;
+	sb->s_root =
+	    d_alloc_root(iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir))));
+	if (!sb->s_root) {
+		befs_error(sb, "get root inode failed");
+		goto unaquire_priv_sbp;
+	}
+
+	/* load nls library */
+	if (befs_sb->mount_opts.iocharset) {
+		befs_debug(sb, "Loading nls: %s",
+			   befs_sb->mount_opts.iocharset);
+		befs_sb->nls = load_nls(befs_sb->mount_opts.iocharset);
+		if (!befs_sb->nls) {
+			befs_warning(sb, "Cannot load nls %s"
+				     "loding default nls",
+				     befs_sb->mount_opts.iocharset);
+			befs_sb->nls = load_nls_default();
+		}
+	}
+
+	/* Set real blocksize of fs */
+	set_blocksize(sb->s_dev, (int) befs_sb->block_size);
+
+	return sb;
+/*****************/
+      unaquire_bh:
+	brelse(bh);
+
+      unaquire_priv_sbp:
+	kfree(sb->u.generic_sbp);
+
+      unaquire_none:
+	sb->s_dev = 0;
+	sb->u.generic_sbp = NULL;
+	return NULL;
+}
+
+static int
+befs_remount(struct super_block *sb, int *flags, char *data)
+{
+	if (!(*flags & MS_RDONLY))
+		return -EINVAL;
+	return 0;
+}
+
+static int
+befs_statfs(struct super_block *sb, struct statfs *buf)
+{
+
+	befs_debug(sb, "---> befs_statfs()");
+
+	buf->f_type = BEFS_SUPER_MAGIC;
+	buf->f_bsize = sb->s_blocksize;
+	buf->f_blocks = BEFS_SB(sb)->num_blocks;
+	buf->f_bfree = BEFS_SB(sb)->num_blocks - BEFS_SB(sb)->used_blocks;
+	buf->f_bavail = buf->f_bfree;
+	buf->f_files = 0;	/* UNKNOWN */
+	buf->f_ffree = 0;	/* UNKNOWN */
+	buf->f_namelen = BEFS_NAME_LEN;
+
+	befs_debug(sb, "<--- befs_statfs()");
+
+	return 0;
+}
+
+/*
+	Makes a variable of type file_system_type, 
+	named befs_fs_tipe, identified by the "befs" string,
+	and containing a reference to the befs_read_super function
+	
+	Macro declared in <linux/fs.h>
+*/
+static DECLARE_FSTYPE_DEV(befs_fs_type, "befs", befs_read_super);
+
+static int __init
+init_befs_fs(void)
+{
+	int err;
+
+	printk(KERN_INFO "BeFS version: %s\n", BEFS_VERSION);
+
+	err = befs_init_inodecache();
+	if (err)
+		return err;
+
+	return register_filesystem(&befs_fs_type);
+}
+
+static void __exit
+exit_befs_fs(void)
+{
+	befs_destroy_inodecache();
+
+	unregister_filesystem(&befs_fs_type);
+}
+
+/*
+Macros that typecheck the init and exit functions,
+ensures that they are called at init and cleanup,
+and eliminates warnings about unused functions.
+*/
+module_init(init_befs_fs)
+    module_exit(exit_befs_fs)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/befs/super.c linux-2.4.20/fs/befs/super.c
--- linux-2.4.19/fs/befs/super.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/befs/super.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,108 @@
+/*
+ * super.c
+ *
+ * Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com>
+ *
+ * Licensed under the GNU GPL. See the file COPYING for details.
+ *
+ */
+
+#include <linux/fs.h>
+
+#include "befs_fs.h"
+#include "endian.h"
+
+/**
+ * load_befs_sb -- Read from disk and properly byteswap all the fields
+ * of the befs superblock
+ *
+ *
+ *
+ *
+ */
+int
+befs_load_sb(struct super_block *sb, befs_super_block * disk_sb)
+{
+	befs_sb_info *befs_sb = BEFS_SB(sb);
+
+	/* byte_order is special, no byte-swap */
+	befs_sb->byte_order = disk_sb->fs_byte_order;
+
+	befs_sb->magic1 = fs32_to_cpu(sb, disk_sb->magic1);
+	befs_sb->magic2 = fs32_to_cpu(sb, disk_sb->magic2);
+	befs_sb->magic3 = fs32_to_cpu(sb, disk_sb->magic3);
+	befs_sb->block_size = fs32_to_cpu(sb, disk_sb->block_size);
+	befs_sb->block_shift = fs32_to_cpu(sb, disk_sb->block_shift);
+	befs_sb->num_blocks = fs64_to_cpu(sb, disk_sb->num_blocks);
+	befs_sb->used_blocks = fs64_to_cpu(sb, disk_sb->used_blocks);
+	befs_sb->inode_size = fs32_to_cpu(sb, disk_sb->inode_size);
+
+	befs_sb->blocks_per_ag = fs32_to_cpu(sb, disk_sb->blocks_per_ag);
+	befs_sb->ag_shift = fs32_to_cpu(sb, disk_sb->ag_shift);
+	befs_sb->num_ags = fs32_to_cpu(sb, disk_sb->num_ags);
+
+	befs_sb->log_blocks = fsrun_to_cpu(sb, disk_sb->log_blocks);
+	befs_sb->log_start = fs64_to_cpu(sb, disk_sb->log_start);
+	befs_sb->log_end = fs64_to_cpu(sb, disk_sb->log_end);
+
+	befs_sb->root_dir = fsrun_to_cpu(sb, disk_sb->root_dir);
+	befs_sb->indices = fsrun_to_cpu(sb, disk_sb->indices);
+	befs_sb->nls = NULL;
+
+	return BEFS_OK;
+}
+
+int
+befs_check_sb(struct super_block *sb)
+{
+	befs_sb_info *befs_sb = BEFS_SB(sb);
+
+	/* Check magic headers of super block */
+	if ((befs_sb->magic1 != BEFS_SUPER_MAGIC1)
+	    || (befs_sb->magic2 != BEFS_SUPER_MAGIC2)
+	    || (befs_sb->magic3 != BEFS_SUPER_MAGIC3)) {
+		befs_error(sb, "invalid magic header");
+		return BEFS_ERR;
+	}
+
+	/*
+	 * Check blocksize of BEFS.
+	 *
+	 * Blocksize of BEFS is 1024, 2048, 4096 or 8192.
+	 */
+
+	if ((befs_sb->block_size != 1024)
+	    && (befs_sb->block_size != 2048)
+	    && (befs_sb->block_size != 4096)
+	    && (befs_sb->block_size != 8192)) {
+		befs_error(sb, "invalid blocksize: %u", befs_sb->block_size);
+		return BEFS_ERR;
+	}
+
+	if (befs_sb->block_size > PAGE_SIZE) {
+		befs_error(sb, "blocksize(%u) cannot be larger"
+			   "than system pagesize(%lu)", befs_sb->block_size,
+			   PAGE_SIZE);
+		return BEFS_ERR;
+	}
+
+	/*
+	   * block_shift and block_size encode the same information
+	   * in different ways as a consistency check.
+	 */
+
+	if ((1 << befs_sb->block_shift) != befs_sb->block_size) {
+		befs_error(sb, "block_shift disagrees with block_size. "
+			   "Corruption likely.");
+		return BEFS_ERR;
+	}
+
+	if (befs_sb->log_start != befs_sb->log_end) {
+		befs_error(sb, "Filesystem not clean! There are blocks in the "
+			   "journal. You must boot into BeOS and mount this volume "
+			   "to make it clean.");
+		return BEFS_ERR;
+	}
+
+	return BEFS_OK;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/binfmt_som.c linux-2.4.20/fs/binfmt_som.c
--- linux-2.4.19/fs/binfmt_som.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/binfmt_som.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,329 @@
+/*
+ * linux/fs/binfmt_som.c
+ *
+ * These are the functions used to load SOM format executables as used
+ * by HP-UX.  
+ *
+ * Copyright 1999 Matthew Wilcox <willy@bofh.ai>
+ * based on binfmt_elf which is
+ * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com).
+ */
+
+#include <linux/module.h>
+
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/binfmts.h>
+#include <linux/som.h>
+#include <linux/string.h>
+#include <linux/file.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/shm.h>
+#include <linux/personality.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+#include <linux/config.h>
+
+#include <linux/elf.h>
+
+static int load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs);
+static int load_som_library(struct file *);
+
+/*
+ * If we don't support core dumping, then supply a NULL so we
+ * don't even try.
+ */
+#if 0
+static int som_core_dump(long signr, struct pt_regs * regs);
+#else
+#define som_core_dump	NULL
+#endif
+
+#define SOM_PAGESTART(_v) ((_v) & ~(unsigned long)(SOM_PAGESIZE-1))
+#define SOM_PAGEOFFSET(_v) ((_v) & (SOM_PAGESIZE-1))
+#define SOM_PAGEALIGN(_v) (((_v) + SOM_PAGESIZE - 1) & ~(SOM_PAGESIZE - 1))
+
+static struct linux_binfmt som_format = {
+	NULL, THIS_MODULE, load_som_binary, load_som_library, som_core_dump, SOM_PAGESIZE
+};
+
+/*
+ * create_som_tables() parses the env- and arg-strings in new user
+ * memory and creates the pointer tables from them, and puts their
+ * addresses on the "stack", returning the new stack pointer value.
+ */
+static void create_som_tables(struct linux_binprm *bprm)
+{
+	char **argv, **envp;
+	int argc = bprm->argc;
+	int envc = bprm->envc;
+	unsigned long p;
+	unsigned long *sp;
+
+	/* Word-align the stack pointer */
+	sp = (unsigned long *)((bprm->p + 3) & ~3);
+
+	envp = (char **) sp;
+	sp += envc + 1;
+	argv = (char **) sp;
+	sp += argc + 1;
+
+	__put_user((unsigned long) envp,++sp);
+	__put_user((unsigned long) argv,++sp);
+
+	__put_user(argc, ++sp);
+
+	bprm->p = (unsigned long) sp;
+
+	p = current->mm->arg_start;
+	while (argc-- > 0) {
+		__put_user((char *)p,argv++);
+		p += strlen_user((char *)p);
+	}
+	__put_user(NULL, argv);
+	current->mm->arg_end = current->mm->env_start = p;
+	while (envc-- > 0) {
+		__put_user((char *)p,envp++);
+		p += strlen_user((char *)p);
+	}
+	__put_user(NULL, envp);
+	current->mm->env_end = p;
+}
+
+static int check_som_header(struct som_hdr *som_ex)
+{
+	int *buf = (int *)som_ex;
+	int i, ck;
+
+	if (som_ex->system_id != SOM_SID_PARISC_1_0 &&
+	    som_ex->system_id != SOM_SID_PARISC_1_1 &&
+	    som_ex->system_id != SOM_SID_PARISC_2_0)
+		return -ENOEXEC;
+
+	if (som_ex->a_magic != SOM_EXEC_NONSHARE &&
+	    som_ex->a_magic != SOM_EXEC_SHARE &&
+	    som_ex->a_magic != SOM_EXEC_DEMAND)
+		return -ENOEXEC;
+
+	if (som_ex->version_id != SOM_ID_OLD &&
+	    som_ex->version_id != SOM_ID_NEW)
+		return -ENOEXEC;
+
+	ck = 0;
+	for (i=0; i<32; i++)
+		ck ^= buf[i];
+	if (ck != 0)
+		return -ENOEXEC;
+
+	return 0;
+}
+
+static int map_som_binary(struct file *file,
+		const struct som_exec_auxhdr *hpuxhdr)
+{
+	unsigned long code_start, code_size, data_start, data_size;
+	unsigned long bss_start, som_brk;
+	int retval;
+	int prot = PROT_READ | PROT_EXEC;
+	int flags = MAP_FIXED|MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE;
+
+	mm_segment_t old_fs = get_fs();
+	set_fs(get_ds());
+
+	code_start = SOM_PAGESTART(hpuxhdr->exec_tmem);
+	code_size = SOM_PAGEALIGN(hpuxhdr->exec_tsize);
+	current->mm->start_code = code_start;
+	current->mm->end_code = code_start + code_size;
+	down_write(&current->mm->mmap_sem);
+	retval = do_mmap(file, code_start, code_size, prot,
+			flags, SOM_PAGESTART(hpuxhdr->exec_tfile));
+	up_write(&current->mm->mmap_sem);
+	if (retval < 0 && retval > -1024)
+		goto out;
+
+	data_start = SOM_PAGESTART(hpuxhdr->exec_dmem);
+	data_size = SOM_PAGEALIGN(hpuxhdr->exec_dsize);
+	current->mm->start_data = data_start;
+	current->mm->end_data = bss_start = data_start + data_size;
+	down_write(&current->mm->mmap_sem);
+	retval = do_mmap(file, data_start, data_size,
+			prot | PROT_WRITE, flags,
+			SOM_PAGESTART(hpuxhdr->exec_dfile));
+	up_write(&current->mm->mmap_sem);
+	if (retval < 0 && retval > -1024)
+		goto out;
+
+	som_brk = bss_start + SOM_PAGEALIGN(hpuxhdr->exec_bsize);
+	current->mm->start_brk = current->mm->brk = som_brk;
+	down_write(&current->mm->mmap_sem);
+	retval = do_mmap(NULL, bss_start, som_brk - bss_start,
+			prot | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, 0);
+	up_write(&current->mm->mmap_sem);
+	if (retval > 0 || retval < -1024)
+		retval = 0;
+out:
+	set_fs(old_fs);
+	return retval;
+}
+
+
+/*
+ * These are the functions used to load SOM executables and shared
+ * libraries.  There is no binary dependent code anywhere else.
+ */
+
+static inline int
+do_load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+{
+	int som_exec_fileno;
+	int retval;
+	unsigned int size;
+	unsigned long som_entry;
+	struct som_hdr *som_ex;
+	struct som_exec_auxhdr *hpuxhdr;
+
+	/* Get the exec-header */
+	som_ex = (struct som_hdr *) bprm->buf;
+
+	retval = check_som_header(som_ex);
+	if (retval != 0)
+		goto out;
+
+	/* Now read in the auxiliary header information */
+
+	retval = -ENOMEM;
+	size = som_ex->aux_header_size;
+	if (size > SOM_PAGESIZE)
+		goto out;
+	hpuxhdr = (struct som_exec_auxhdr *) kmalloc(size, GFP_KERNEL);
+	if (!hpuxhdr)
+		goto out;
+
+	retval = kernel_read(bprm->file, som_ex->aux_header_location,
+			(char *) hpuxhdr, size);
+	if (retval < 0)
+		goto out_free;
+
+	retval = get_unused_fd();
+	if (retval < 0)
+		goto out_free;
+	get_file(bprm->file);
+	fd_install(som_exec_fileno = retval, bprm->file);
+
+	/* Flush all traces of the currently running executable */
+	retval = flush_old_exec(bprm);
+	if (retval)
+		goto out_free;
+
+	/* OK, This is the point of no return */
+	current->flags &= ~PF_FORKNOEXEC;
+	current->personality = PER_HPUX;
+
+	/* Set the task size for HP-UX processes such that
+	 * the gateway page is outside the address space.
+	 * This can be fixed later, but for now, this is much
+	 * easier.
+	 */
+
+	current->thread.task_size = 0xc0000000;
+
+	/* Set map base to allow enough room for hp-ux heap growth */
+
+	current->thread.map_base = 0x80000000;
+
+	retval = map_som_binary(bprm->file, hpuxhdr);
+	if (retval < 0)
+		goto out_free;
+
+	som_entry = hpuxhdr->exec_entry;
+	kfree(hpuxhdr);
+
+	set_binfmt(&som_format);
+	compute_creds(bprm);
+	setup_arg_pages(bprm);
+
+	create_som_tables(bprm);
+
+	current->mm->start_stack = bprm->p;
+	current->mm->rss = 0;
+
+#if 0
+	printk("(start_brk) %08lx\n" , (unsigned long) current->mm->start_brk);
+	printk("(end_code) %08lx\n" , (unsigned long) current->mm->end_code);
+	printk("(start_code) %08lx\n" , (unsigned long) current->mm->start_code);
+	printk("(end_data) %08lx\n" , (unsigned long) current->mm->end_data);
+	printk("(start_stack) %08lx\n" , (unsigned long) current->mm->start_stack);
+	printk("(brk) %08lx\n" , (unsigned long) current->mm->brk);
+#endif
+
+	map_hpux_gateway_page(current,current->mm);
+
+	start_thread_som(regs, som_entry, bprm->p);
+	if (current->ptrace & PT_PTRACED)
+		send_sig(SIGTRAP, current, 0);
+	return 0;
+
+	/* error cleanup */
+out_free:
+	kfree(hpuxhdr);
+out:
+	return retval;
+}
+
+static int
+load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+{
+	int retval;
+
+	MOD_INC_USE_COUNT;
+	retval = do_load_som_binary(bprm, regs);
+	MOD_DEC_USE_COUNT;
+	return retval;
+}
+
+static inline int
+do_load_som_library(struct file *f)
+{
+/* No lib support in SOM yet.  gizza chance.. */
+	return -ENOEXEC;
+}
+
+static int load_som_library(struct file *f)
+{
+	int retval;
+
+	MOD_INC_USE_COUNT;
+	retval = do_load_som_library(f);
+	MOD_DEC_USE_COUNT;
+	return retval;
+}
+
+	/* Install the SOM loader.
+	 * N.B. We *rely* on the table being the right size with the
+	 * right number of free slots...
+	 */
+
+static int __init init_som_binfmt(void)
+{
+	return register_binfmt(&som_format);
+}
+
+static void __exit exit_som_binfmt(void)
+{
+	/* Remove the SOM loader. */
+	unregister_binfmt(&som_format);
+}
+
+module_init(init_som_binfmt);
+module_exit(exit_som_binfmt);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/buffer.c linux-2.4.20/fs/buffer.c
--- linux-2.4.19/fs/buffer.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/buffer.c	2002-10-29 11:18:48.000000000 +0000
@@ -47,7 +47,6 @@
 #include <linux/highmem.h>
 #include <linux/module.h>
 #include <linux/completion.h>
-#include <linux/compiler.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -210,7 +209,7 @@
 		struct buffer_head * bh = next;
 		next = bh->b_next_free;
 
-		if (dev && bh->b_dev != dev)
+		if (dev != NODEV && bh->b_dev != dev)
 			continue;
 		if (test_and_set_bit(BH_Lock, &bh->b_state))
 			continue;
@@ -267,7 +266,7 @@
 				__refile_buffer(bh);
 			continue;
 		}
-		if (dev && bh->b_dev != dev)
+		if (dev != NODEV && bh->b_dev != dev)
 			continue;
 
 		get_bh(bh);
@@ -730,15 +729,11 @@
 
 static void free_more_memory(void)
 {
-	zone_t * zone = contig_page_data.node_zonelists[GFP_NOFS & GFP_ZONEMASK].zones[0];
-	
 	balance_dirty();
 	wakeup_bdflush();
-	try_to_free_pages(zone, GFP_NOFS, 0);
+	try_to_free_pages(GFP_NOIO);
 	run_task_queue(&tq_disk);
-	current->policy |= SCHED_YIELD;
-	__set_current_state(TASK_RUNNING);
-	schedule();
+	yield();
 }
 
 void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private)
@@ -958,8 +953,10 @@
 		struct buffer_head * bh;
 
 		bh = get_hash_table(dev, block, size);
-		if (bh)
+		if (bh) {
+			touch_buffer(bh);
 			return bh;
+		}
 
 		if (!grow_buffers(dev, block, size))
 			free_more_memory();
@@ -1122,7 +1119,6 @@
 	struct buffer_head * bh;
 
 	bh = getblk(dev, block, size);
-	touch_buffer(bh);
 	if (buffer_uptodate(bh))
 		return bh;
 	ll_rw_block(READ, 1, &bh);
@@ -1211,16 +1207,14 @@
 
 void set_bh_page (struct buffer_head *bh, struct page *page, unsigned long offset)
 {
-	bh->b_page = page;
 	if (offset >= PAGE_SIZE)
 		BUG();
-	if (PageHighMem(page))
-		/*
-		 * This catches illegal uses and preserves the offset:
-		 */
-		bh->b_data = (char *)(0 + offset);
-	else
-		bh->b_data = page_address(page) + offset;
+
+	/*
+	 * page_address will return NULL anyways for highmem pages
+	 */
+	bh->b_data = page_address(page) + offset;
+	bh->b_page = page;
 }
 EXPORT_SYMBOL(set_bh_page);
 
@@ -1754,9 +1748,14 @@
 	}
 
 	/* Stage 3: start the IO */
-	for (i = 0; i < nr; i++)
-		submit_bh(READ, arr[i]);
-
+	for (i = 0; i < nr; i++) {
+		struct buffer_head * bh = arr[i];
+		if (buffer_uptodate(bh))
+			end_buffer_io_async(bh, 1);
+		else
+			submit_bh(READ, bh);
+	}
+	
 	return 0;
 }
 
@@ -1991,7 +1990,12 @@
 	flush_dcache_page(page);
 	kunmap(page);
 
-	__mark_buffer_dirty(bh);
+	if (!atomic_set_buffer_dirty(bh)) {
+		__mark_dirty(bh);
+		buffer_insert_inode_data_queue(bh, inode);
+		balance_dirty();
+	}
+
 	err = 0;
 
 unlock:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/cramfs/uncompress.c linux-2.4.20/fs/cramfs/uncompress.c
--- linux-2.4.19/fs/cramfs/uncompress.c	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/cramfs/uncompress.c	2002-10-29 11:18:37.000000000 +0000
@@ -18,7 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/vmalloc.h>
-#include <linux/zlib_fs.h>
+#include <linux/zlib.h>
 
 static z_stream stream;
 static int initialized;
@@ -34,14 +34,14 @@
 	stream.next_out = dst;
 	stream.avail_out = dstlen;
 
-	err = zlib_fs_inflateReset(&stream);
+	err = zlib_inflateReset(&stream);
 	if (err != Z_OK) {
-		printk("zlib_fs_inflateReset error %d\n", err);
-		zlib_fs_inflateEnd(&stream);
-		zlib_fs_inflateInit(&stream);
+		printk("zlib_inflateReset error %d\n", err);
+		zlib_inflateEnd(&stream);
+		zlib_inflateInit(&stream);
 	}
 
-	err = zlib_fs_inflate(&stream, Z_FINISH);
+	err = zlib_inflate(&stream, Z_FINISH);
 	if (err != Z_STREAM_END)
 		goto err;
 	return stream.total_out;
@@ -55,14 +55,14 @@
 int cramfs_uncompress_init(void)
 {
 	if (!initialized++) {
-		stream.workspace = vmalloc(zlib_fs_inflate_workspacesize());
+		stream.workspace = vmalloc(zlib_inflate_workspacesize());
 		if ( !stream.workspace ) {
 			initialized = 0;
 			return -ENOMEM;
 		}
 		stream.next_in = NULL;
 		stream.avail_in = 0;
-		zlib_fs_inflateInit(&stream);
+		zlib_inflateInit(&stream);
 	}
 	return 0;
 }
@@ -70,7 +70,7 @@
 int cramfs_uncompress_exit(void)
 {
 	if (!--initialized) {
-		zlib_fs_inflateEnd(&stream);
+		zlib_inflateEnd(&stream);
 		vfree(stream.workspace);
 	}
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/dcache.c linux-2.4.20/fs/dcache.c
--- linux-2.4.19/fs/dcache.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/dcache.c	2002-10-29 11:18:33.000000000 +0000
@@ -1251,6 +1251,7 @@
 
 extern void bdev_cache_init(void);
 extern void cdev_cache_init(void);
+extern void iobuf_cache_init(void);
 
 void __init vfs_caches_init(unsigned long mempages)
 {
@@ -1282,7 +1283,9 @@
 
 	dcache_init(mempages);
 	inode_init(mempages);
+	files_init(mempages); 
 	mnt_init(mempages);
 	bdev_cache_init();
 	cdev_cache_init();
+	iobuf_cache_init();
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/devfs/base.c linux-2.4.20/fs/devfs/base.c
--- linux-2.4.19/fs/devfs/base.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/devfs/base.c	2002-10-29 11:18:34.000000000 +0000
@@ -620,6 +620,15 @@
 	       Protected <scan_dir_for_removable> and <get_removable_partition>
 	       from changing directory contents.
   v1.12a
+    20020721   Richard Gooch <rgooch@atnf.csiro.au>
+	       Switched to ISO C structure field initialisers.
+	       Switch to set_current_state() and move before add_wait_queue().
+    20020722   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed devfs entry leak in <devfs_readdir> when *readdir fails.
+  v1.12b
+    20020818   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed module unload race in <devfs_open>.
+  v1.12c
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -652,7 +661,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
-#define DEVFS_VERSION            "1.12a (20020514)"
+#define DEVFS_VERSION            "1.12c (20020818)"
 
 #define DEVFS_NAME "devfs"
 
@@ -864,7 +873,7 @@
 			  loff_t *ppos);
 static struct file_operations stat_fops =
 {
-    read:    stat_read,
+    .read    = stat_read,
 };
 #endif
 
@@ -872,9 +881,9 @@
 /*  Devfs daemon file operations  */
 static struct file_operations devfsd_fops =
 {
-    read:    devfsd_read,
-    ioctl:   devfsd_ioctl,
-    release: devfsd_close,
+    .read    = devfsd_read,
+    .ioctl   = devfsd_ioctl,
+    .release = devfsd_close,
 };
 
 
@@ -1441,12 +1450,12 @@
     if (fs_info->devfsd_task == NULL) return (TRUE);
     if (devfsd_queue_empty (fs_info) && fs_info->devfsd_sleeping) return TRUE;
     if ( is_devfsd_or_child (fs_info) ) return (FALSE);
+    set_current_state (TASK_UNINTERRUPTIBLE);
     add_wait_queue (&fs_info->revalidate_wait_queue, &wait);
-    current->state = TASK_UNINTERRUPTIBLE;
     if (!devfsd_queue_empty (fs_info) || !fs_info->devfsd_sleeping)
 	if (fs_info->devfsd_task) schedule ();
     remove_wait_queue (&fs_info->revalidate_wait_queue, &wait);
-    current->state = TASK_RUNNING;
+    __set_current_state (TASK_RUNNING);
     return (TRUE);
 }   /*  End Function wait_for_devfsd_finished  */
 
@@ -2592,9 +2601,9 @@
 
 static struct super_operations devfs_sops =
 { 
-    put_inode:     force_delete,
-    clear_inode:   devfs_clear_inode,
-    statfs:        devfs_statfs,
+    .put_inode     = force_delete,
+    .clear_inode   = devfs_clear_inode,
+    .statfs        = devfs_statfs,
 };
 
 
@@ -2740,19 +2749,20 @@
 	    {
 		err = (*filldir) (dirent, de->name, de->namelen,
 				  file->f_pos, de->inode.ino, de->mode >> 12);
-		if (err >= 0)
+		if (err < 0) devfs_put (de);
+		else
 		{
 		    file->f_pos++;
 		    ++stored;
 		}
 	    }
+	    if (err == -EINVAL) break;
+	    if (err < 0) return err;
 	    read_lock (&parent->u.dir.lock);
 	    next = devfs_get (de->next);
 	    read_unlock (&parent->u.dir.lock);
 	    devfs_put (de);
 	    de = next;
-	    if (err == -EINVAL) break;
-	    if (err < 0) return err;
 	}
 	break;
     }
@@ -2765,21 +2775,24 @@
     struct fcb_type *df;
     struct devfs_entry *de;
     struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
+    void *ops;
 
     de = get_devfs_entry_from_vfs_inode (inode);
     if (de == NULL) return -ENODEV;
     if ( S_ISDIR (de->mode) ) return 0;
     df = &de->u.fcb;
     file->private_data = de->info;
+    ops = devfs_get_ops (de);  /*  Now have module refcount  */
     if ( S_ISBLK (inode->i_mode) )
     {
 	file->f_op = &def_blk_fops;
-	if (df->ops) inode->i_bdev->bd_op = df->ops;
-	err = def_blk_fops.open (inode, file);
+	if (ops) inode->i_bdev->bd_op = ops;
+	err = def_blk_fops.open (inode, file); /* This bumps module refcount */
+	devfs_put_ops (de);                    /* So drop my refcount        */
     }
     else
     {
-	file->f_op = fops_get ( (struct file_operations *) df->ops );
+	file->f_op = ops;
 	if (file->f_op)
 	{
 	    lock_kernel ();
@@ -2787,7 +2800,7 @@
 	    unlock_kernel ();
 	}
 	else
-	{   /*  Fallback to legacy scheme  */
+	{   /*  Fallback to legacy scheme (I don't have a module refcount)  */
 	    if ( S_ISCHR (inode->i_mode) ) err = chrdev_open (inode, file);
 	    else err = -ENODEV;
 	}
@@ -2811,14 +2824,14 @@
 
 static struct file_operations devfs_fops =
 {
-    open:    devfs_open,
+    .open    = devfs_open,
 };
 
 static struct file_operations devfs_dir_fops =
 {
-    read:    generic_read_dir,
-    readdir: devfs_readdir,
-    open:    devfs_open,
+    .read    = generic_read_dir,
+    .readdir = devfs_readdir,
+    .open    = devfs_open,
 };
 
 
@@ -2860,19 +2873,19 @@
 
 static struct dentry_operations devfs_dops =
 {
-    d_delete:     devfs_d_delete,
-    d_release:    devfs_d_release,
-    d_iput:       devfs_d_iput,
+    .d_delete     = devfs_d_delete,
+    .d_release    = devfs_d_release,
+    .d_iput       = devfs_d_iput,
 };
 
 static int devfs_d_revalidate_wait (struct dentry *dentry, int flags);
 
 static struct dentry_operations devfs_wait_dops =
 {
-    d_delete:     devfs_d_delete,
-    d_release:    devfs_d_release,
-    d_iput:       devfs_d_iput,
-    d_revalidate: devfs_d_revalidate_wait,
+    .d_delete     = devfs_d_delete,
+    .d_release    = devfs_d_release,
+    .d_iput       = devfs_d_iput,
+    .d_revalidate = devfs_d_revalidate_wait,
 };
 
 /**
@@ -2959,8 +2972,8 @@
     read_lock (&parent->u.dir.lock);
     if (dentry->d_fsdata)
     {
+	set_current_state (TASK_UNINTERRUPTIBLE);
 	add_wait_queue (&lookup_info->wait_queue, &wait);
-	current->state = TASK_UNINTERRUPTIBLE;
 	read_unlock (&parent->u.dir.lock);
 	schedule ();
     }
@@ -3239,25 +3252,25 @@
 
 static struct inode_operations devfs_iops =
 {
-    setattr:        devfs_notify_change,
+    .setattr        = devfs_notify_change,
 };
 
 static struct inode_operations devfs_dir_iops =
 {
-    lookup:         devfs_lookup,
-    unlink:         devfs_unlink,
-    symlink:        devfs_symlink,
-    mkdir:          devfs_mkdir,
-    rmdir:          devfs_rmdir,
-    mknod:          devfs_mknod,
-    setattr:        devfs_notify_change,
+    .lookup         = devfs_lookup,
+    .unlink         = devfs_unlink,
+    .symlink        = devfs_symlink,
+    .mkdir          = devfs_mkdir,
+    .rmdir          = devfs_rmdir,
+    .mknod          = devfs_mknod,
+    .setattr        = devfs_notify_change,
 };
 
 static struct inode_operations devfs_symlink_iops =
 {
-    readlink:       devfs_readlink,
-    follow_link:    devfs_follow_link,
-    setattr:        devfs_notify_change,
+    .readlink       = devfs_readlink,
+    .follow_link    = devfs_follow_link,
+    .setattr        = devfs_notify_change,
 };
 
 static struct super_block *devfs_read_super (struct super_block *sb,
@@ -3313,8 +3326,8 @@
     info->major = 0;
     info->minor = 0;
     /*  Block for a new entry  */
+    set_current_state (TASK_INTERRUPTIBLE);
     add_wait_queue (&fs_info->devfsd_wait_queue, &wait);
-    current->state = TASK_INTERRUPTIBLE;
     while ( devfsd_queue_empty (fs_info) )
     {
 	fs_info->devfsd_sleeping = TRUE;
@@ -3324,13 +3337,13 @@
 	if ( signal_pending (current) )
 	{
 	    remove_wait_queue (&fs_info->devfsd_wait_queue, &wait);
-	    current->state = TASK_RUNNING;
+	    __set_current_state (TASK_RUNNING);
 	    return -EINTR;
 	}
 	set_current_state (TASK_INTERRUPTIBLE);
     }
     remove_wait_queue (&fs_info->devfsd_wait_queue, &wait);
-    current->state = TASK_RUNNING;
+    __set_current_state (TASK_RUNNING);
     /*  Now play with the data  */
     ival = atomic_read (&fs_info->devfsd_overrun_count);
     info->overrun_count = ival;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/dnotify.c linux-2.4.20/fs/dnotify.c
--- linux-2.4.19/fs/dnotify.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/dnotify.c	2002-10-29 11:18:36.000000000 +0000
@@ -135,13 +135,12 @@
 	}
 	if (changed)
 		redo_inode_mask(inode);
-out:
 	write_unlock(&dn_lock);
 }
 
 static int __init dnotify_init(void)
 {
-	dn_cache = kmem_cache_create("dnotify cache",
+	dn_cache = kmem_cache_create("dnotify_cache",
 		sizeof(struct dnotify_struct), 0, 0, NULL, NULL);
 	if (!dn_cache)
 		panic("cannot create dnotify slab cache");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/efs/super.c linux-2.4.20/fs/efs/super.c
--- linux-2.4.19/fs/efs/super.c	2002-02-25 19:38:08.000000000 +0000
+++ linux-2.4.20/fs/efs/super.c	2002-10-29 11:18:35.000000000 +0000
@@ -141,7 +141,13 @@
 	s->s_magic		= EFS_SUPER_MAGIC;
 	s->s_blocksize		= EFS_BLOCKSIZE;
 	s->s_blocksize_bits	= EFS_BLOCKSIZE_BITS;
-	set_blocksize(dev, EFS_BLOCKSIZE);
+	
+	if( set_blocksize(dev, EFS_BLOCKSIZE) < 0)
+	{
+		printk(KERN_ERR "EFS: device does not support %d byte blocks\n",
+			EFS_BLOCKSIZE);
+		goto out_no_fs_ul;
+	}
   
 	/* read the vh (volume header) block */
 	bh = sb_bread(s, 0);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/exec.c linux-2.4.20/fs/exec.c
--- linux-2.4.19/fs/exec.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/exec.c	2002-10-29 11:18:37.000000000 +0000
@@ -182,25 +182,34 @@
  */
 int copy_strings(int argc,char ** argv, struct linux_binprm *bprm) 
 {
+	struct page *kmapped_page = NULL;
+	char *kaddr = NULL;
+	int ret;
+
 	while (argc-- > 0) {
 		char *str;
 		int len;
 		unsigned long pos;
 
-		if (get_user(str, argv+argc) || !(len = strnlen_user(str, bprm->p)))
-			return -EFAULT;
-		if (bprm->p < len) 
-			return -E2BIG; 
+		if (get_user(str, argv+argc) ||
+				!(len = strnlen_user(str, bprm->p))) {
+			ret = -EFAULT;
+			goto out;
+		}
+
+		if (bprm->p < len)  {
+			ret = -E2BIG;
+			goto out;
+		}
 
 		bprm->p -= len;
 		/* XXX: add architecture specific overflow check here. */ 
-
 		pos = bprm->p;
+
 		while (len > 0) {
-			char *kaddr;
 			int i, new, err;
-			struct page *page;
 			int offset, bytes_to_copy;
+			struct page *page;
 
 			offset = pos % PAGE_SIZE;
 			i = pos/PAGE_SIZE;
@@ -209,32 +218,44 @@
 			if (!page) {
 				page = alloc_page(GFP_HIGHUSER);
 				bprm->page[i] = page;
-				if (!page)
-					return -ENOMEM;
+				if (!page) {
+					ret = -ENOMEM;
+					goto out;
+				}
 				new = 1;
 			}
-			kaddr = kmap(page);
 
+			if (page != kmapped_page) {
+				if (kmapped_page)
+					kunmap(kmapped_page);
+				kmapped_page = page;
+				kaddr = kmap(kmapped_page);
+			}
 			if (new && offset)
 				memset(kaddr, 0, offset);
 			bytes_to_copy = PAGE_SIZE - offset;
 			if (bytes_to_copy > len) {
 				bytes_to_copy = len;
 				if (new)
-					memset(kaddr+offset+len, 0, PAGE_SIZE-offset-len);
+					memset(kaddr+offset+len, 0,
+						PAGE_SIZE-offset-len);
+			}
+			err = copy_from_user(kaddr+offset, str, bytes_to_copy);
+			if (err) {
+				ret = -EFAULT;
+				goto out;
 			}
-			err = copy_from_user(kaddr + offset, str, bytes_to_copy);
-			kunmap(page);
-
-			if (err)
-				return -EFAULT; 
 
 			pos += bytes_to_copy;
 			str += bytes_to_copy;
 			len -= bytes_to_copy;
 		}
 	}
-	return 0;
+	ret = 0;
+out:
+	if (kmapped_page)
+		kunmap(kmapped_page);
+	return ret;
 }
 
 /*
@@ -343,8 +364,7 @@
 	struct file *file;
 	int err = 0;
 
-	if (path_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
-		err = path_walk(name, &nd);
+	err = path_lookup(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd);
 	file = ERR_PTR(err);
 	if (!err) {
 		inode = nd.dentry->d_inode;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/ext2/inode.c linux-2.4.20/fs/ext2/inode.c
--- linux-2.4.19/fs/ext2/inode.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/ext2/inode.c	2002-10-29 11:18:32.000000000 +0000
@@ -1094,7 +1094,7 @@
 	raw_inode->i_frag = inode->u.ext2_i.i_frag_no;
 	raw_inode->i_fsize = inode->u.ext2_i.i_frag_size;
 	raw_inode->i_file_acl = cpu_to_le32(inode->u.ext2_i.i_file_acl);
-	if (S_ISDIR(inode->i_mode))
+	if (!S_ISREG(inode->i_mode))
 		raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext2_i.i_dir_acl);
 	else {
 		raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/ext2/ioctl.c linux-2.4.20/fs/ext2/ioctl.c
--- linux-2.4.19/fs/ext2/ioctl.c	2000-09-27 20:41:33.000000000 +0000
+++ linux-2.4.20/fs/ext2/ioctl.c	2002-10-29 11:18:40.000000000 +0000
@@ -31,7 +31,7 @@
 			return -EROFS;
 
 		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
-			return -EPERM;
+			return -EACCES;
 
 		if (get_user(flags, (int *) arg))
 			return -EFAULT;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/ext2/super.c linux-2.4.20/fs/ext2/super.c
--- linux-2.4.19/fs/ext2/super.c	2002-02-25 19:38:08.000000000 +0000
+++ linux-2.4.20/fs/ext2/super.c	2002-10-29 11:18:49.000000000 +0000
@@ -486,6 +486,9 @@
 		       bdevname(dev), i);
 		goto failed_mount;
 	}
+	if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
+		ext2_warning(sb, __FUNCTION__,
+			"mounting ext3 filesystem as ext2\n");
 	sb->s_blocksize_bits =
 		le32_to_cpu(EXT2_SB(sb)->s_es->s_log_block_size) + 10;
 	sb->s_blocksize = 1 << sb->s_blocksize_bits;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/ext3/file.c linux-2.4.20/fs/ext3/file.c
--- linux-2.4.19/fs/ext3/file.c	2001-11-15 21:37:55.000000000 +0000
+++ linux-2.4.20/fs/ext3/file.c	2002-10-29 11:18:50.000000000 +0000
@@ -61,19 +61,52 @@
 static ssize_t
 ext3_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
+	int ret, err;
 	struct inode *inode = file->f_dentry->d_inode;
 
-	/*
-	 * Nasty: if the file is subject to synchronous writes then we need
-	 * to force generic_osync_inode() to call ext3_write_inode().
-	 * We do that by marking the inode dirty.  This adds much more
-	 * computational expense than we need, but we're going to sync
-	 * anyway.
-	 */
-	if (IS_SYNC(inode) || (file->f_flags & O_SYNC))
-		mark_inode_dirty(inode);
+	ret = generic_file_write(file, buf, count, ppos);
 
-	return generic_file_write(file, buf, count, ppos);
+	/* Skip file flushing code if there was an error, or if nothing
+	   was written. */
+	if (ret <= 0)
+		return ret;
+	
+	/* If the inode is IS_SYNC, or is O_SYNC and we are doing
+           data-journaling, then we need to make sure that we force the
+           transaction to disk to keep all metadata uptodate
+           synchronously. */
+
+	if (file->f_flags & O_SYNC) {
+		/* If we are non-data-journaled, then the dirty data has
+                   already been flushed to backing store by
+                   generic_osync_inode, and the inode has been flushed
+                   too if there have been any modifications other than
+                   mere timestamp updates.
+		   
+		   Open question --- do we care about flushing
+		   timestamps too if the inode is IS_SYNC? */
+		if (!ext3_should_journal_data(inode))
+			return ret;
+
+		goto force_commit;
+	}
+
+	/* So we know that there has been no forced data flush.  If the
+           inode is marked IS_SYNC, we need to force one ourselves. */
+	if (!IS_SYNC(inode))
+		return ret;
+	
+	/* Open question #2 --- should we force data to disk here too?
+           If we don't, the only impact is that data=writeback
+           filesystems won't flush data to disk automatically on
+           IS_SYNC, only metadata (but historically, that is what ext2
+           has done.) */
+	
+force_commit:
+	err = ext3_force_commit(inode->i_sb);
+	if (err) 
+		return err;
+	return ret;
 }
 
 struct file_operations ext3_file_operations = {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/ext3/fsync.c linux-2.4.20/fs/ext3/fsync.c
--- linux-2.4.19/fs/ext3/fsync.c	2001-11-21 05:34:13.000000000 +0000
+++ linux-2.4.20/fs/ext3/fsync.c	2002-10-29 11:18:50.000000000 +0000
@@ -62,7 +62,12 @@
 	 * we'll end up waiting on them in commit.
 	 */
 	ret = fsync_inode_buffers(inode);
-	ret |= fsync_inode_data_buffers(inode);
+
+	/* In writeback mode, we need to force out data buffers too.  In
+	 * the other modes, ext3_force_commit takes care of forcing out
+	 * just the right data blocks. */
+	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)
+		ret |= fsync_inode_data_buffers(inode);
 
 	ext3_force_commit(inode->i_sb);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/ext3/ialloc.c linux-2.4.20/fs/ext3/ialloc.c
--- linux-2.4.19/fs/ext3/ialloc.c	2002-02-25 19:38:08.000000000 +0000
+++ linux-2.4.20/fs/ext3/ialloc.c	2002-10-29 11:18:47.000000000 +0000
@@ -392,7 +392,7 @@
 
 	err = -ENOSPC;
 	if (!gdp)
-		goto fail;
+		goto out;
 
 	err = -EIO;
 	bitmap_nr = load_inode_bitmap (sb, i);
@@ -523,9 +523,10 @@
 	return inode;
 
 fail:
+	ext3_std_error(sb, err);
+out:
 	unlock_super(sb);
 	iput(inode);
-	ext3_std_error(sb, err);
 	return ERR_PTR(err);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/ext3/inode.c linux-2.4.20/fs/ext3/inode.c
--- linux-2.4.19/fs/ext3/inode.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/ext3/inode.c	2002-10-29 11:18:49.000000000 +0000
@@ -412,6 +412,7 @@
 	return NULL;
 
 changed:
+	brelse(bh);
 	*err = -EAGAIN;
 	goto no_block;
 failure:
@@ -948,11 +949,13 @@
 }
 
 static int walk_page_buffers(	handle_t *handle,
+				struct inode *inode,
 				struct buffer_head *head,
 				unsigned from,
 				unsigned to,
 				int *partial,
 				int (*fn)(	handle_t *handle,
+						struct inode *inode,
 						struct buffer_head *bh))
 {
 	struct buffer_head *bh;
@@ -970,7 +973,7 @@
 				*partial = 1;
 			continue;
 		}
-		err = (*fn)(handle, bh);
+		err = (*fn)(handle, inode, bh);
 		if (!ret)
 			ret = err;
 	}
@@ -1003,7 +1006,7 @@
  * write.  
  */
 
-static int do_journal_get_write_access(handle_t *handle, 
+static int do_journal_get_write_access(handle_t *handle, struct inode *inode,
 				       struct buffer_head *bh)
 {
 	return ext3_journal_get_write_access(handle, bh);
@@ -1029,7 +1032,7 @@
 		goto prepare_write_failed;
 
 	if (ext3_should_journal_data(inode)) {
-		ret = walk_page_buffers(handle, page->buffers,
+		ret = walk_page_buffers(handle, inode, page->buffers,
 				from, to, NULL, do_journal_get_write_access);
 		if (ret) {
 			/*
@@ -1050,24 +1053,30 @@
 	return ret;
 }
 
-static int journal_dirty_sync_data(handle_t *handle, struct buffer_head *bh)
+static int journal_dirty_sync_data(handle_t *handle, struct inode *inode,
+				   struct buffer_head *bh)
 {
-	return ext3_journal_dirty_data(handle, bh, 0);
+	int ret = ext3_journal_dirty_data(handle, bh, 0);
+	buffer_insert_inode_data_queue(bh, inode);
+	return ret;
 }
 
 /*
  * For ext3_writepage().  We also brelse() the buffer to account for
  * the bget() which ext3_writepage() performs.
  */
-static int journal_dirty_async_data(handle_t *handle, struct buffer_head *bh)
+static int journal_dirty_async_data(handle_t *handle, struct inode *inode, 
+				    struct buffer_head *bh)
 {
 	int ret = ext3_journal_dirty_data(handle, bh, 1);
+	buffer_insert_inode_data_queue(bh, inode);
 	__brelse(bh);
 	return ret;
 }
 
 /* For commit_write() in data=journal mode */
-static int commit_write_fn(handle_t *handle, struct buffer_head *bh)
+static int commit_write_fn(handle_t *handle, struct inode *inode, 
+			   struct buffer_head *bh)
 {
 	set_bit(BH_Uptodate, &bh->b_state);
 	return ext3_journal_dirty_metadata(handle, bh);
@@ -1102,7 +1111,7 @@
 		int partial = 0;
 		loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
 
-		ret = walk_page_buffers(handle, page->buffers,
+		ret = walk_page_buffers(handle, inode, page->buffers,
 			from, to, &partial, commit_write_fn);
 		if (!partial)
 			SetPageUptodate(page);
@@ -1112,7 +1121,7 @@
 		EXT3_I(inode)->i_state |= EXT3_STATE_JDATA;
 	} else {
 		if (ext3_should_order_data(inode)) {
-			ret = walk_page_buffers(handle, page->buffers,
+			ret = walk_page_buffers(handle, inode, page->buffers,
 				from, to, NULL, journal_dirty_sync_data);
 		}
 		/* Be careful here if generic_commit_write becomes a
@@ -1194,7 +1203,8 @@
 	return generic_block_bmap(mapping,block,ext3_get_block);
 }
 
-static int bget_one(handle_t *handle, struct buffer_head *bh)
+static int bget_one(handle_t *handle, struct inode *inode, 
+		    struct buffer_head *bh)
 {
 	atomic_inc(&bh->b_count);
 	return 0;
@@ -1293,7 +1303,7 @@
 			create_empty_buffers(page,
 				inode->i_dev, inode->i_sb->s_blocksize);
 		page_buffers = page->buffers;
-		walk_page_buffers(handle, page_buffers, 0,
+		walk_page_buffers(handle, inode, page_buffers, 0,
 				PAGE_CACHE_SIZE, NULL, bget_one);
 	}
 
@@ -1311,7 +1321,7 @@
 
 	/* And attach them to the current transaction */
 	if (order_data) {
-		err = walk_page_buffers(handle, page_buffers,
+		err = walk_page_buffers(handle, inode, page_buffers,
 			0, PAGE_CACHE_SIZE, NULL, journal_dirty_async_data);
 		if (!ret)
 			ret = err;
@@ -1579,8 +1589,10 @@
 		}
 		ext3_mark_inode_dirty(handle, inode);
 		ext3_journal_test_restart(handle, inode);
-		BUFFER_TRACE(bh, "get_write_access");
-		ext3_journal_get_write_access(handle, bh);
+		if (bh) {
+			BUFFER_TRACE(bh, "retaking write access");
+			ext3_journal_get_write_access(handle, bh);
+		}
 	}
 
 	/*
@@ -2459,7 +2471,7 @@
 		/* ext3_do_update_inode() does journal_dirty_metadata */
 		brelse(iloc->bh);
 	} else {
-		printk(KERN_EMERG __FUNCTION__ ": called with no handle!\n");
+		printk(KERN_EMERG "%s: called with no handle!\n", __FUNCTION__);
 	}
 	return err;
 }
@@ -2547,7 +2559,8 @@
 	if (current_handle &&
 		current_handle->h_transaction != handle->h_transaction) {
 		/* This task has a transaction open against a different fs */
-		printk(KERN_EMERG __FUNCTION__": transactions do not match!\n");
+		printk(KERN_EMERG "%s: transactions do not match!\n",
+			__FUNCTION__);
 	} else {
 		jbd_debug(5, "marking dirty.  outer handle=%p\n",
 				current_handle);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/ext3/ioctl.c linux-2.4.20/fs/ext3/ioctl.c
--- linux-2.4.19/fs/ext3/ioctl.c	2001-11-09 22:25:04.000000000 +0000
+++ linux-2.4.20/fs/ext3/ioctl.c	2002-10-29 11:18:38.000000000 +0000
@@ -37,7 +37,7 @@
 			return -EROFS;
 
 		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
-			return -EPERM;
+			return -EACCES;
 
 		if (get_user(flags, (int *) arg))
 			return -EFAULT;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/ext3/namei.c linux-2.4.20/fs/ext3/namei.c
--- linux-2.4.19/fs/ext3/namei.c	2001-11-09 22:25:04.000000000 +0000
+++ linux-2.4.20/fs/ext3/namei.c	2002-10-29 11:18:32.000000000 +0000
@@ -354,8 +354,8 @@
 			 */
 			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 			dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
-			ext3_mark_inode_dirty(handle, dir);
 			dir->i_version = ++event;
+			ext3_mark_inode_dirty(handle, dir);
 			BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
 			ext3_journal_dirty_metadata(handle, bh);
 			brelse(bh);
@@ -464,8 +464,8 @@
 		inode->i_op = &ext3_file_inode_operations;
 		inode->i_fop = &ext3_file_operations;
 		inode->i_mapping->a_ops = &ext3_aops;
-		ext3_mark_inode_dirty(handle, inode);
 		err = ext3_add_nondir(handle, dentry, inode);
+		ext3_mark_inode_dirty(handle, inode);
 	}
 	ext3_journal_stop(handle, dir);
 	return err;
@@ -489,8 +489,8 @@
 	err = PTR_ERR(inode);
 	if (!IS_ERR(inode)) {
 		init_special_inode(inode, mode, rdev);
-		ext3_mark_inode_dirty(handle, inode);
 		err = ext3_add_nondir(handle, dentry, inode);
+		ext3_mark_inode_dirty(handle, inode);
 	}
 	ext3_journal_stop(handle, dir);
 	return err;
@@ -829,9 +829,9 @@
 	 * recovery. */
 	inode->i_size = 0;
 	ext3_orphan_add(handle, inode);
-	ext3_mark_inode_dirty(handle, inode);
 	dir->i_nlink--;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+	ext3_mark_inode_dirty(handle, inode);
 	dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
 	ext3_mark_inode_dirty(handle, dir);
 
@@ -883,8 +883,8 @@
 	inode->i_nlink--;
 	if (!inode->i_nlink)
 		ext3_orphan_add(handle, inode);
-	ext3_mark_inode_dirty(handle, inode);
 	inode->i_ctime = dir->i_ctime;
+	ext3_mark_inode_dirty(handle, inode);
 	retval = 0;
 
 end_unlink:
@@ -933,8 +933,8 @@
 		inode->i_size = l-1;
 	}
 	inode->u.ext3_i.i_disksize = inode->i_size;
-	ext3_mark_inode_dirty(handle, inode);
 	err = ext3_add_nondir(handle, dentry, inode);
+	ext3_mark_inode_dirty(handle, inode);
 out_stop:
 	ext3_journal_stop(handle, dir);
 	return err;
@@ -970,8 +970,8 @@
 	ext3_inc_count(handle, inode);
 	atomic_inc(&inode->i_count);
 
-	ext3_mark_inode_dirty(handle, inode);
 	err = ext3_add_nondir(handle, dentry, inode);
+	ext3_mark_inode_dirty(handle, inode);
 	ext3_journal_stop(handle, dir);
 	return err;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/ext3/super.c linux-2.4.20/fs/ext3/super.c
--- linux-2.4.19/fs/ext3/super.c	2002-02-25 19:38:08.000000000 +0000
+++ linux-2.4.20/fs/ext3/super.c	2002-10-29 11:18:49.000000000 +0000
@@ -646,6 +646,11 @@
 				*mount_options &= ~EXT3_MOUNT_DATA_FLAGS;
 				*mount_options |= data_opt;
 			}
+		} else if (!strcmp (this_char, "commit")) {
+			unsigned long v;
+			if (want_numeric(value, "commit", &v))
+				return 0;
+			sbi->s_commit_interval = (HZ * v);
 		} else {
 			printk (KERN_ERR 
 				"EXT3-fs: Unrecognized mount option %s\n",
@@ -838,17 +843,16 @@
 
 		list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan);
 		if (inode->i_nlink) {
-			printk(KERN_DEBUG __FUNCTION__
-				": truncating inode %ld to %Ld bytes\n",
-				inode->i_ino, inode->i_size);
+			printk(KERN_DEBUG "%s: truncating inode %ld to %Ld "
+				"bytes\n", __FUNCTION__, inode->i_ino,
+				inode->i_size);
 			jbd_debug(2, "truncating inode %ld to %Ld bytes\n",
 				  inode->i_ino, inode->i_size);
 			ext3_truncate(inode);
 			nr_truncates++;
 		} else {
-			printk(KERN_DEBUG __FUNCTION__
-				": deleting unreferenced inode %ld\n",
-				inode->i_ino);
+			printk(KERN_DEBUG "%s: deleting unreferenced "
+				"inode %ld\n", __FUNCTION__, inode->i_ino);
 			jbd_debug(2, "deleting unreferenced inode %ld\n",
 				  inode->i_ino);
 			nr_orphans++;
@@ -1229,6 +1233,22 @@
 	return NULL;
 }
 
+/*
+ * Setup any per-fs journal parameters now.  We'll do this both on
+ * initial mount, once the journal has been initialised but before we've
+ * done any recovery; and again on any subsequent remount. 
+ */
+static void ext3_init_journal_params(struct ext3_sb_info *sbi, 
+				     journal_t *journal)
+{
+	if (sbi->s_commit_interval)
+		journal->j_commit_interval = sbi->s_commit_interval;
+	/* We could also set up an ext3-specific default for the commit
+	 * interval here, but for now we'll just fall back to the jbd
+	 * default. */
+}
+
+
 static journal_t *ext3_get_journal(struct super_block *sb, int journal_inum)
 {
 	struct inode *journal_inode;
@@ -1263,7 +1283,7 @@
 		printk(KERN_ERR "EXT3-fs: Could not load journal inode\n");
 		iput(journal_inode);
 	}
-	
+	ext3_init_journal_params(EXT3_SB(sb), journal);
 	return journal;
 }
 
@@ -1341,6 +1361,7 @@
 		goto out_journal;
 	}
 	EXT3_SB(sb)->journal_bdev = bdev;
+	ext3_init_journal_params(EXT3_SB(sb), journal);
 	return journal;
 out_journal:
 	journal_destroy(journal);
@@ -1589,8 +1610,10 @@
 		journal_t *journal = EXT3_SB(sb)->s_journal;
 
 		/* Now we set up the journal barrier. */
+		unlock_super(sb);
 		journal_lock_updates(journal);
 		journal_flush(journal);
+		lock_super(sb);
 
 		/* Journal blocked and flushed, clear needs_recovery flag. */
 		EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
@@ -1636,6 +1659,8 @@
 
 	es = sbi->s_es;
 
+	ext3_init_journal_params(sbi, sbi->s_journal);
+	
 	if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
 		if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
 			return -EROFS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/fcntl.c linux-2.4.20/fs/fcntl.c
--- linux-2.4.19/fs/fcntl.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/fcntl.c	2002-10-29 11:18:33.000000000 +0000
@@ -529,7 +529,7 @@
 
 static int __init fasync_init(void)
 {
-	fasync_cache = kmem_cache_create("fasync cache",
+	fasync_cache = kmem_cache_create("fasync_cache",
 		sizeof(struct fasync_struct), 0, 0, NULL, NULL);
 	if (!fasync_cache)
 		panic("cannot create fasync slab cache");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/file_table.c linux-2.4.20/fs/file_table.c
--- linux-2.4.19/fs/file_table.c	2001-09-17 20:16:30.000000000 +0000
+++ linux-2.4.20/fs/file_table.c	2002-10-29 11:18:32.000000000 +0000
@@ -186,3 +186,17 @@
 	file_list_unlock();
 	return 0;
 }
+
+void __init files_init(unsigned long mempages)
+{ 
+	int n; 
+	/* One file with associated inode and dcache is very roughly 1K. 
+	 * Per default don't use more than 10% of our memory for files. 
+	 */ 
+
+	n = (mempages * (PAGE_SIZE / 1024)) / 10;
+	files_stat.max_files = n; 
+	if (files_stat.max_files < NR_FILE)
+		files_stat.max_files = NR_FILE;
+} 
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/Makefile linux-2.4.20/fs/inflate_fs/Makefile
--- linux-2.4.19/fs/inflate_fs/Makefile	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/Makefile	1970-01-01 00:00:00.000000000 +0000
@@ -1,33 +0,0 @@
-#
-# This is a modified version of zlib, which does all memory
-# allocation ahead of time.
-#
-# Currently only decompression is supported.
-#
-# Decompression needs to be serialized for each memory
-# allocation.
-#
-#
-# (The upsides of the simplification is that you can't get in
-# any nasty situations wrt memory management, and that the
-# uncompression can be done without blocking on allocation).
-#
-# The modules are named *_fs.o to distinguish from other modified
-# compression libraries, like the one used by ppp.
-#
-# It is expected that when a deflate module is added it will be
-# a separate module in a deflate_fs directory, to avoid having to
-# load the deflate code for readonly filesystems.
-#
-
-O_TARGET    := inflate_fs.o
-
-export-objs := inflate_syms.o
-
-obj-y := adler32.o infblock.o infcodes.o inffast.o inflate.o \
-	 inftrees.o infutil.o inflate_syms.o
-obj-m := $(O_TARGET)
-
-EXTRA_CFLAGS += -I $(TOPDIR)/fs/inflate_fs
-
-include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/adler32.c linux-2.4.20/fs/inflate_fs/adler32.c
--- linux-2.4.19/fs/inflate_fs/adler32.c	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/adler32.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,48 +0,0 @@
-/* adler32.c -- compute the Adler-32 checksum of a data stream
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* @(#) $Id$ */
-
-#include <linux/zlib_fs.h>
-
-#define BASE 65521L /* largest prime smaller than 65536 */
-#define NMAX 5552
-/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
-
-#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
-#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
-#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
-#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
-#define DO16(buf)   DO8(buf,0); DO8(buf,8);
-
-/* ========================================================================= */
-uLong ZEXPORT zlib_fs_adler32(adler, buf, len)
-    uLong adler;
-    const Bytef *buf;
-    uInt len;
-{
-    unsigned long s1 = adler & 0xffff;
-    unsigned long s2 = (adler >> 16) & 0xffff;
-    int k;
-
-    if (buf == Z_NULL) return 1L;
-
-    while (len > 0) {
-        k = len < NMAX ? len : NMAX;
-        len -= k;
-        while (k >= 16) {
-            DO16(buf);
-	    buf += 16;
-            k -= 16;
-        }
-        if (k != 0) do {
-            s1 += *buf++;
-	    s2 += s1;
-        } while (--k);
-        s1 %= BASE;
-        s2 %= BASE;
-    }
-    return (s2 << 16) | s1;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/infblock.c linux-2.4.20/fs/inflate_fs/infblock.c
--- linux-2.4.19/fs/inflate_fs/infblock.c	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/infblock.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,355 +0,0 @@
-/* infblock.c -- interpret and process block types to last block
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-#include "zutil.h"
-#include "infblock.h"
-#include "inftrees.h"
-#include "infcodes.h"
-#include "infutil.h"
-
-struct inflate_codes_state;
-
-/* simplify the use of the inflate_huft type with some defines */
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-/* Table for deflate from PKZIP's appnote.txt. */
-local const uInt border[] = { /* Order of the bit length code lengths */
-        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-
-/*
-   Notes beyond the 1.93a appnote.txt:
-
-   1. Distance pointers never point before the beginning of the output
-      stream.
-   2. Distance pointers can point back across blocks, up to 32k away.
-   3. There is an implied maximum of 7 bits for the bit length table and
-      15 bits for the actual data.
-   4. If only one code exists, then it is encoded using one bit.  (Zero
-      would be more efficient, but perhaps a little confusing.)  If two
-      codes exist, they are coded using one bit each (0 and 1).
-   5. There is no way of sending zero distance codes--a dummy must be
-      sent if there are none.  (History: a pre 2.0 version of PKZIP would
-      store blocks with no distance codes, but this was discovered to be
-      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
-      zero distance codes, which is sent as one code of zero bits in
-      length.
-   6. There are up to 286 literal/length codes.  Code 256 represents the
-      end-of-block.  Note however that the static length tree defines
-      288 codes just to fill out the Huffman codes.  Codes 286 and 287
-      cannot be used though, since there is no length base or extra bits
-      defined for them.  Similarily, there are up to 30 distance codes.
-      However, static trees define 32 codes (all 5 bits) to fill out the
-      Huffman codes, but the last two had better not show up in the data.
-   7. Unzip can check dynamic Huffman blocks for complete code sets.
-      The exception is that a single code would not be complete (see #4).
-   8. The five bits following the block type is really the number of
-      literal codes sent minus 257.
-   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
-      (1+6+6).  Therefore, to output three times the length, you output
-      three codes (1+1+1), whereas to output four times the same length,
-      you only need two codes (1+3).  Hmm.
-  10. In the tree reconstruction algorithm, Code = Code + Increment
-      only if BitLength(i) is not zero.  (Pretty obvious.)
-  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
-  12. Note: length code 284 can represent 227-258, but length code 285
-      really is 258.  The last length deserves its own, short code
-      since it gets used a lot in very redundant files.  The length
-      258 is special since 258 - 3 (the min match length) is 255.
-  13. The literal/length and distance code bit lengths are read as a
-      single stream of lengths.  It is possible (and advantageous) for
-      a repeat code (16, 17, or 18) to go across the boundary between
-      the two sets of lengths.
- */
-
-
-void zlib_fs_inflate_blocks_reset(s, z, c)
-inflate_blocks_statef *s;
-z_streamp z;
-uLongf *c;
-{
-  if (c != Z_NULL)
-    *c = s->check;
-  if (s->mode == CODES)
-    zlib_fs_inflate_codes_free(s->sub.decode.codes, z);
-  s->mode = TYPE;
-  s->bitk = 0;
-  s->bitb = 0;
-  s->read = s->write = s->window;
-  if (s->checkfn != Z_NULL)
-    z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
-}
-
-inflate_blocks_statef *zlib_fs_inflate_blocks_new(z, c, w)
-z_streamp z;
-check_func c;
-uInt w;
-{
-  inflate_blocks_statef *s;
-
-  s = &WS(z)->working_blocks_state;
-  s->hufts = WS(z)->working_hufts;
-  s->window = WS(z)->working_window;
-  s->end = s->window + w;
-  s->checkfn = c;
-  s->mode = TYPE;
-  zlib_fs_inflate_blocks_reset(s, z, Z_NULL);
-  return s;
-}
-
-
-int zlib_fs_inflate_blocks(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt t;               /* temporary storage */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Bytef *p;             /* input data pointer */
-  uInt n;               /* bytes available there */
-  Bytef *q;             /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-
-  /* copy input/output information to locals (UPDATE macro restores) */
-  LOAD
-
-  /* process input based on current state */
-  while (1) switch (s->mode)
-  {
-    case TYPE:
-      NEEDBITS(3)
-      t = (uInt)b & 7;
-      s->last = t & 1;
-      switch (t >> 1)
-      {
-        case 0:                         /* stored */
-          DUMPBITS(3)
-          t = k & 7;                    /* go to byte boundary */
-          DUMPBITS(t)
-          s->mode = LENS;               /* get length of stored block */
-          break;
-        case 1:                         /* fixed */
-          {
-            uInt bl, bd;
-            inflate_huft *tl, *td;
-
-            zlib_fs_inflate_trees_fixed(&bl, &bd, &tl, &td, z);
-            s->sub.decode.codes = zlib_fs_inflate_codes_new(bl, bd, tl, td, z);
-            if (s->sub.decode.codes == Z_NULL)
-            {
-              r = Z_MEM_ERROR;
-              LEAVE
-            }
-          }
-          DUMPBITS(3)
-          s->mode = CODES;
-          break;
-        case 2:                         /* dynamic */
-          DUMPBITS(3)
-          s->mode = TABLE;
-          break;
-        case 3:                         /* illegal */
-          DUMPBITS(3)
-          s->mode = B_BAD;
-          z->msg = (char*)"invalid block type";
-          r = Z_DATA_ERROR;
-          LEAVE
-      }
-      break;
-    case LENS:
-      NEEDBITS(32)
-      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
-      {
-        s->mode = B_BAD;
-        z->msg = (char*)"invalid stored block lengths";
-        r = Z_DATA_ERROR;
-        LEAVE
-      }
-      s->sub.left = (uInt)b & 0xffff;
-      b = k = 0;                      /* dump bits */
-      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
-      break;
-    case STORED:
-      if (n == 0)
-        LEAVE
-      NEEDOUT
-      t = s->sub.left;
-      if (t > n) t = n;
-      if (t > m) t = m;
-      memcpy(q, p, t);
-      p += t;  n -= t;
-      q += t;  m -= t;
-      if ((s->sub.left -= t) != 0)
-        break;
-      s->mode = s->last ? DRY : TYPE;
-      break;
-    case TABLE:
-      NEEDBITS(14)
-      s->sub.trees.table = t = (uInt)b & 0x3fff;
-#ifndef PKZIP_BUG_WORKAROUND
-      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
-      {
-        s->mode = B_BAD;
-        z->msg = (char*)"too many length or distance symbols";
-        r = Z_DATA_ERROR;
-        LEAVE
-      }
-#endif
-      {
-      	s->sub.trees.blens = WS(z)->working_blens;
-      }
-      DUMPBITS(14)
-      s->sub.trees.index = 0;
-      s->mode = BTREE;
-    case BTREE:
-      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
-      {
-        NEEDBITS(3)
-        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
-        DUMPBITS(3)
-      }
-      while (s->sub.trees.index < 19)
-        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
-      s->sub.trees.bb = 7;
-      t = zlib_fs_inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
-                             &s->sub.trees.tb, s->hufts, z);
-      if (t != Z_OK)
-      {
-        r = t;
-        if (r == Z_DATA_ERROR)
-          s->mode = B_BAD;
-        LEAVE
-      }
-      s->sub.trees.index = 0;
-      s->mode = DTREE;
-    case DTREE:
-      while (t = s->sub.trees.table,
-             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
-      {
-        inflate_huft *h;
-        uInt i, j, c;
-
-        t = s->sub.trees.bb;
-        NEEDBITS(t)
-        h = s->sub.trees.tb + ((uInt)b & zlib_fs_inflate_mask[t]);
-        t = h->bits;
-        c = h->base;
-        if (c < 16)
-        {
-          DUMPBITS(t)
-          s->sub.trees.blens[s->sub.trees.index++] = c;
-        }
-        else /* c == 16..18 */
-        {
-          i = c == 18 ? 7 : c - 14;
-          j = c == 18 ? 11 : 3;
-          NEEDBITS(t + i)
-          DUMPBITS(t)
-          j += (uInt)b & zlib_fs_inflate_mask[i];
-          DUMPBITS(i)
-          i = s->sub.trees.index;
-          t = s->sub.trees.table;
-          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
-              (c == 16 && i < 1))
-          {
-            s->mode = B_BAD;
-            z->msg = (char*)"invalid bit length repeat";
-            r = Z_DATA_ERROR;
-            LEAVE
-          }
-          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
-          do {
-            s->sub.trees.blens[i++] = c;
-          } while (--j);
-          s->sub.trees.index = i;
-        }
-      }
-      s->sub.trees.tb = Z_NULL;
-      {
-        uInt bl, bd;
-        inflate_huft *tl, *td;
-        inflate_codes_statef *c;
-
-        bl = 9;         /* must be <= 9 for lookahead assumptions */
-        bd = 6;         /* must be <= 9 for lookahead assumptions */
-        t = s->sub.trees.table;
-        t = zlib_fs_inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
-                                  s->sub.trees.blens, &bl, &bd, &tl, &td,
-                                  s->hufts, z);
-        if (t != Z_OK)
-        {
-          if (t == (uInt)Z_DATA_ERROR)
-            s->mode = B_BAD;
-          r = t;
-          LEAVE
-        }
-        if ((c = zlib_fs_inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
-        {
-          r = Z_MEM_ERROR;
-          LEAVE
-        }
-        s->sub.decode.codes = c;
-      }
-      s->mode = CODES;
-    case CODES:
-      UPDATE
-      if ((r = zlib_fs_inflate_codes(s, z, r)) != Z_STREAM_END)
-        return zlib_fs_inflate_flush(s, z, r);
-      r = Z_OK;
-      zlib_fs_inflate_codes_free(s->sub.decode.codes, z);
-      LOAD
-      if (!s->last)
-      {
-        s->mode = TYPE;
-        break;
-      }
-      s->mode = DRY;
-    case DRY:
-      FLUSH
-      if (s->read != s->write)
-        LEAVE
-      s->mode = B_DONE;
-    case B_DONE:
-      r = Z_STREAM_END;
-      LEAVE
-    case B_BAD:
-      r = Z_DATA_ERROR;
-      LEAVE
-    default:
-      r = Z_STREAM_ERROR;
-      LEAVE
-  }
-}
-
-
-int zlib_fs_inflate_blocks_free(s, z)
-inflate_blocks_statef *s;
-z_streamp z;
-{
-  zlib_fs_inflate_blocks_reset(s, z, Z_NULL);
-  return Z_OK;
-}
-
-
-void zlib_fs_inflate_set_dictionary(s, d, n)
-inflate_blocks_statef *s;
-const Bytef *d;
-uInt  n;
-{
-  memcpy(s->window, d, n);
-  s->read = s->write = s->window + n;
-}
-
-
-/* Returns true if inflate is currently at the end of a block generated
- * by Z_SYNC_FLUSH or Z_FULL_FLUSH. 
- * IN assertion: s != Z_NULL
- */
-int zlib_fs_inflate_blocks_sync_point(s)
-inflate_blocks_statef *s;
-{
-  return s->mode == LENS;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/infblock.h linux-2.4.20/fs/inflate_fs/infblock.h
--- linux-2.4.19/fs/inflate_fs/infblock.h	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/infblock.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,44 +0,0 @@
-/* infblock.h -- header to use infblock.c
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-#ifndef _INFBLOCK_H
-#define _INFBLOCK_H
-
-struct inflate_blocks_state;
-typedef struct inflate_blocks_state FAR inflate_blocks_statef;
-
-extern inflate_blocks_statef * zlib_fs_inflate_blocks_new OF((
-    z_streamp z,
-    check_func c,               /* check function */
-    uInt w));                   /* window size */
-
-extern int zlib_fs_inflate_blocks OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));                      /* initial return code */
-
-extern void zlib_fs_inflate_blocks_reset OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    uLongf *));                  /* check value on output */
-
-extern int zlib_fs_inflate_blocks_free OF((
-    inflate_blocks_statef *,
-    z_streamp));
-
-extern void zlib_fs_inflate_set_dictionary OF((
-    inflate_blocks_statef *s,
-    const Bytef *d,  /* dictionary */
-    uInt  n));       /* dictionary length */
-
-extern int zlib_fs_inflate_blocks_sync_point OF((
-    inflate_blocks_statef *s));
-
-#endif /* _INFBLOCK_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/infcodes.c linux-2.4.20/fs/inflate_fs/infcodes.c
--- linux-2.4.19/fs/inflate_fs/infcodes.c	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/infcodes.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,204 +0,0 @@
-/* infcodes.c -- process literals and length/distance pairs
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-#include "zutil.h"
-#include "inftrees.h"
-#include "infblock.h"
-#include "infcodes.h"
-#include "infutil.h"
-#include "inffast.h"
-
-/* simplify the use of the inflate_huft type with some defines */
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-inflate_codes_statef *zlib_fs_inflate_codes_new(bl, bd, tl, td, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-z_streamp z;
-{
-  inflate_codes_statef *c;
-
-  c = &WS(z)->working_state;
-  {
-    c->mode = START;
-    c->lbits = (Byte)bl;
-    c->dbits = (Byte)bd;
-    c->ltree = tl;
-    c->dtree = td;
-  }
-  return c;
-}
-
-
-int zlib_fs_inflate_codes(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt j;               /* temporary storage */
-  inflate_huft *t;      /* temporary pointer */
-  uInt e;               /* extra bits or operation */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Bytef *p;             /* input data pointer */
-  uInt n;               /* bytes available there */
-  Bytef *q;             /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-  Bytef *f;             /* pointer to copy strings from */
-  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
-
-  /* copy input/output information to locals (UPDATE macro restores) */
-  LOAD
-
-  /* process input and output based on current state */
-  while (1) switch (c->mode)
-  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
-    case START:         /* x: set up for LEN */
-#ifndef SLOW
-      if (m >= 258 && n >= 10)
-      {
-        UPDATE
-        r = zlib_fs_inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
-        LOAD
-        if (r != Z_OK)
-        {
-          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
-          break;
-        }
-      }
-#endif /* !SLOW */
-      c->sub.code.need = c->lbits;
-      c->sub.code.tree = c->ltree;
-      c->mode = LEN;
-    case LEN:           /* i: get length/literal/eob next */
-      j = c->sub.code.need;
-      NEEDBITS(j)
-      t = c->sub.code.tree + ((uInt)b & zlib_fs_inflate_mask[j]);
-      DUMPBITS(t->bits)
-      e = (uInt)(t->exop);
-      if (e == 0)               /* literal */
-      {
-        c->sub.lit = t->base;
-        c->mode = LIT;
-        break;
-      }
-      if (e & 16)               /* length */
-      {
-        c->sub.copy.get = e & 15;
-        c->len = t->base;
-        c->mode = LENEXT;
-        break;
-      }
-      if ((e & 64) == 0)        /* next table */
-      {
-        c->sub.code.need = e;
-        c->sub.code.tree = t + t->base;
-        break;
-      }
-      if (e & 32)               /* end of block */
-      {
-        c->mode = WASH;
-        break;
-      }
-      c->mode = BADCODE;        /* invalid code */
-      z->msg = (char*)"invalid literal/length code";
-      r = Z_DATA_ERROR;
-      LEAVE
-    case LENEXT:        /* i: getting length extra (have base) */
-      j = c->sub.copy.get;
-      NEEDBITS(j)
-      c->len += (uInt)b & zlib_fs_inflate_mask[j];
-      DUMPBITS(j)
-      c->sub.code.need = c->dbits;
-      c->sub.code.tree = c->dtree;
-      c->mode = DIST;
-    case DIST:          /* i: get distance next */
-      j = c->sub.code.need;
-      NEEDBITS(j)
-      t = c->sub.code.tree + ((uInt)b & zlib_fs_inflate_mask[j]);
-      DUMPBITS(t->bits)
-      e = (uInt)(t->exop);
-      if (e & 16)               /* distance */
-      {
-        c->sub.copy.get = e & 15;
-        c->sub.copy.dist = t->base;
-        c->mode = DISTEXT;
-        break;
-      }
-      if ((e & 64) == 0)        /* next table */
-      {
-        c->sub.code.need = e;
-        c->sub.code.tree = t + t->base;
-        break;
-      }
-      c->mode = BADCODE;        /* invalid code */
-      z->msg = (char*)"invalid distance code";
-      r = Z_DATA_ERROR;
-      LEAVE
-    case DISTEXT:       /* i: getting distance extra */
-      j = c->sub.copy.get;
-      NEEDBITS(j)
-      c->sub.copy.dist += (uInt)b & zlib_fs_inflate_mask[j];
-      DUMPBITS(j)
-      c->mode = COPY;
-    case COPY:          /* o: copying bytes in window, waiting for space */
-#ifndef __TURBOC__ /* Turbo C bug for following expression */
-      f = (uInt)(q - s->window) < c->sub.copy.dist ?
-          s->end - (c->sub.copy.dist - (q - s->window)) :
-          q - c->sub.copy.dist;
-#else
-      f = q - c->sub.copy.dist;
-      if ((uInt)(q - s->window) < c->sub.copy.dist)
-        f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
-#endif
-      while (c->len)
-      {
-        NEEDOUT
-        OUTBYTE(*f++)
-        if (f == s->end)
-          f = s->window;
-        c->len--;
-      }
-      c->mode = START;
-      break;
-    case LIT:           /* o: got literal, waiting for output space */
-      NEEDOUT
-      OUTBYTE(c->sub.lit)
-      c->mode = START;
-      break;
-    case WASH:          /* o: got eob, possibly more output */
-      if (k > 7)        /* return unused byte, if any */
-      {
-        k -= 8;
-        n++;
-        p--;            /* can always return one */
-      }
-      FLUSH
-      if (s->read != s->write)
-        LEAVE
-      c->mode = END;
-    case END:
-      r = Z_STREAM_END;
-      LEAVE
-    case BADCODE:       /* x: got error */
-      r = Z_DATA_ERROR;
-      LEAVE
-    default:
-      r = Z_STREAM_ERROR;
-      LEAVE
-  }
-#ifdef NEED_DUMMY_RETURN
-  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
-#endif
-}
-
-
-void zlib_fs_inflate_codes_free(c, z)
-inflate_codes_statef *c;
-z_streamp z;
-{
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/infcodes.h linux-2.4.20/fs/inflate_fs/infcodes.h
--- linux-2.4.19/fs/inflate_fs/infcodes.h	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/infcodes.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,33 +0,0 @@
-/* infcodes.h -- header to use infcodes.c
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-#ifndef _INFCODES_H
-#define _INFCODES_H
-
-#include "infblock.h"
-
-struct inflate_codes_state;
-typedef struct inflate_codes_state FAR inflate_codes_statef;
-
-extern inflate_codes_statef *zlib_fs_inflate_codes_new OF((
-    uInt, uInt,
-    inflate_huft *, inflate_huft *,
-    z_streamp ));
-
-extern int zlib_fs_inflate_codes OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));
-
-extern void zlib_fs_inflate_codes_free OF((
-    inflate_codes_statef *,
-    z_streamp ));
-
-#endif /* _INFCODES_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/inffast.c linux-2.4.20/fs/inflate_fs/inffast.c
--- linux-2.4.19/fs/inflate_fs/inffast.c	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/inffast.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,161 +0,0 @@
-/* inffast.c -- process literals and length/distance pairs fast
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-#include "zutil.h"
-#include "inftrees.h"
-#include "infblock.h"
-#include "infcodes.h"
-#include "infutil.h"
-#include "inffast.h"
-
-struct inflate_codes_state;
-
-/* simplify the use of the inflate_huft type with some defines */
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-/* macros for bit input with no checking and for returning unused bytes */
-#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
-
-/* Called with number of bytes left to write in window at least 258
-   (the maximum string length) and number of input bytes available
-   at least ten.  The ten bytes are six bytes for the longest length/
-   distance pair plus four bytes for overloading the bit buffer. */
-
-int zlib_fs_inflate_fast(bl, bd, tl, td, s, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-inflate_blocks_statef *s;
-z_streamp z;
-{
-  inflate_huft *t;      /* temporary pointer */
-  uInt e;               /* extra bits or operation */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Bytef *p;             /* input data pointer */
-  uInt n;               /* bytes available there */
-  Bytef *q;             /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-  uInt ml;              /* mask for literal/length tree */
-  uInt md;              /* mask for distance tree */
-  uInt c;               /* bytes to copy */
-  uInt d;               /* distance back to copy from */
-  Bytef *r;             /* copy source pointer */
-
-  /* load input, output, bit values */
-  LOAD
-
-  /* initialize masks */
-  ml = zlib_fs_inflate_mask[bl];
-  md = zlib_fs_inflate_mask[bd];
-
-  /* do until not enough input or output space for fast loop */
-  do {                          /* assume called with m >= 258 && n >= 10 */
-    /* get literal/length code */
-    GRABBITS(20)                /* max bits for literal/length code */
-    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
-    {
-      DUMPBITS(t->bits)
-      *q++ = (Byte)t->base;
-      m--;
-      continue;
-    }
-    do {
-      DUMPBITS(t->bits)
-      if (e & 16)
-      {
-        /* get extra bits for length */
-        e &= 15;
-        c = t->base + ((uInt)b & zlib_fs_inflate_mask[e]);
-        DUMPBITS(e)
-
-        /* decode distance base of block to copy */
-        GRABBITS(15);           /* max bits for distance code */
-        e = (t = td + ((uInt)b & md))->exop;
-        do {
-          DUMPBITS(t->bits)
-          if (e & 16)
-          {
-            /* get extra bits to add to distance base */
-            e &= 15;
-            GRABBITS(e)         /* get extra bits (up to 13) */
-            d = t->base + ((uInt)b & zlib_fs_inflate_mask[e]);
-            DUMPBITS(e)
-
-            /* do the copy */
-            m -= c;
-            if ((uInt)(q - s->window) >= d)     /* offset before dest */
-            {                                   /*  just copy */
-              r = q - d;
-              *q++ = *r++;  c--;        /* minimum count is three, */
-              *q++ = *r++;  c--;        /*  so unroll loop a little */
-            }
-            else                        /* else offset after destination */
-            {
-              e = d - (uInt)(q - s->window); /* bytes from offset to end */
-              r = s->end - e;           /* pointer to offset */
-              if (c > e)                /* if source crosses, */
-              {
-                c -= e;                 /* copy to end of window */
-                do {
-                  *q++ = *r++;
-                } while (--e);
-                r = s->window;          /* copy rest from start of window */
-              }
-            }
-            do {                        /* copy all or what's left */
-              *q++ = *r++;
-            } while (--c);
-            break;
-          }
-          else if ((e & 64) == 0)
-          {
-            t += t->base;
-            e = (t += ((uInt)b & zlib_fs_inflate_mask[e]))->exop;
-          }
-          else
-          {
-            z->msg = (char*)"invalid distance code";
-            UNGRAB
-            UPDATE
-            return Z_DATA_ERROR;
-          }
-        } while (1);
-        break;
-      }
-      if ((e & 64) == 0)
-      {
-        t += t->base;
-        if ((e = (t += ((uInt)b & zlib_fs_inflate_mask[e]))->exop) == 0)
-        {
-          DUMPBITS(t->bits)
-          *q++ = (Byte)t->base;
-          m--;
-          break;
-        }
-      }
-      else if (e & 32)
-      {
-        UNGRAB
-        UPDATE
-        return Z_STREAM_END;
-      }
-      else
-      {
-        z->msg = (char*)"invalid literal/length code";
-        UNGRAB
-        UPDATE
-        return Z_DATA_ERROR;
-      }
-    } while (1);
-  } while (m >= 258 && n >= 10);
-
-  /* not enough input or output--restore pointers and return */
-  UNGRAB
-  UPDATE
-  return Z_OK;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/inffast.h linux-2.4.20/fs/inflate_fs/inffast.h
--- linux-2.4.19/fs/inflate_fs/inffast.h	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/inffast.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,17 +0,0 @@
-/* inffast.h -- header to use inffast.c
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-extern int zlib_fs_inflate_fast OF((
-    uInt,
-    uInt,
-    inflate_huft *,
-    inflate_huft *,
-    inflate_blocks_statef *,
-    z_streamp ));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/inffixed.h linux-2.4.20/fs/inflate_fs/inffixed.h
--- linux-2.4.19/fs/inflate_fs/inffixed.h	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/inffixed.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,151 +0,0 @@
-/* inffixed.h -- table for decoding fixed codes
- * Generated automatically by the maketree.c program
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-local uInt fixed_bl = 9;
-local uInt fixed_bd = 5;
-local inflate_huft fixed_tl[] = {
-    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
-    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
-    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
-    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
-    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
-    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
-    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
-    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
-    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
-    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
-    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
-    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
-    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
-    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
-    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
-    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
-    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
-    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
-    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
-    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
-    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
-    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
-    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
-    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
-    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
-    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
-    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
-    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
-    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
-    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
-    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
-    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
-    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
-    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
-    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
-    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
-    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
-    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
-    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
-    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
-    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
-    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
-    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
-    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
-    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
-    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
-    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
-    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
-    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
-    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
-    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
-    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
-    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
-    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
-    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
-    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
-    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
-    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
-    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
-    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
-    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
-    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
-    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
-    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
-    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
-    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
-    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
-    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
-    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
-    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
-    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
-    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
-    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
-    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
-    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
-    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
-    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
-    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
-    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
-    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
-    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
-    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
-    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
-    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
-    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
-    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
-    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
-    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
-    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
-    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
-    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
-    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
-    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
-    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
-    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
-    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
-    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
-    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
-    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
-    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
-    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
-    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
-    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
-    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
-    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
-    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
-    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
-    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
-    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
-    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
-    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
-    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
-    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
-    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
-    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
-    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
-    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
-    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
-    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
-    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
-    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
-    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
-    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
-    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
-    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
-    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
-    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
-    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
-  };
-local inflate_huft fixed_td[] = {
-    {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
-    {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
-    {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
-    {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
-    {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
-    {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
-    {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
-    {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
-  };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/inflate.c linux-2.4.20/fs/inflate_fs/inflate.c
--- linux-2.4.19/fs/inflate_fs/inflate.c	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/inflate.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,293 +0,0 @@
-/* inflate.c -- zlib interface to inflate modules
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-#include <linux/module.h>
-#include "zutil.h"
-#include "infblock.h"
-#include "infutil.h"
-
-int ZEXPORT zlib_fs_inflate_workspacesize(void)
-{
-  return sizeof(struct inflate_workspace);
-}
-
-
-int ZEXPORT zlib_fs_inflateReset(z)
-z_streamp z;
-{
-  if (z == Z_NULL || z->state == Z_NULL || z->workspace == Z_NULL)
-    return Z_STREAM_ERROR;
-  z->total_in = z->total_out = 0;
-  z->msg = Z_NULL;
-  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
-  zlib_fs_inflate_blocks_reset(z->state->blocks, z, Z_NULL);
-  return Z_OK;
-}
-
-
-int ZEXPORT zlib_fs_inflateEnd(z)
-z_streamp z;
-{
-  if (z == Z_NULL || z->state == Z_NULL || z->workspace == Z_NULL)
-    return Z_STREAM_ERROR;
-  if (z->state->blocks != Z_NULL)
-    zlib_fs_inflate_blocks_free(z->state->blocks, z);
-  z->state = Z_NULL;
-  return Z_OK;
-}
-
-
-int ZEXPORT zlib_fs_inflateInit2_(z, w, version, stream_size)
-z_streamp z;
-int w;
-const char *version;
-int stream_size;
-{
-  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
-      stream_size != sizeof(z_stream) || z->workspace == Z_NULL)
-      return Z_VERSION_ERROR;
-
-  /* initialize state */
-  if (z == Z_NULL)
-    return Z_STREAM_ERROR;
-  z->msg = Z_NULL;
-  z->state = &WS(z)->internal_state;
-  z->state->blocks = Z_NULL;
-
-  /* handle undocumented nowrap option (no zlib header or check) */
-  z->state->nowrap = 0;
-  if (w < 0)
-  {
-    w = - w;
-    z->state->nowrap = 1;
-  }
-
-  /* set window size */
-  if (w < 8 || w > 15)
-  {
-    zlib_fs_inflateEnd(z);
-    return Z_STREAM_ERROR;
-  }
-  z->state->wbits = (uInt)w;
-
-  /* create inflate_blocks state */
-  if ((z->state->blocks =
-      zlib_fs_inflate_blocks_new(z, z->state->nowrap ? Z_NULL : zlib_fs_adler32, (uInt)1 << w))
-      == Z_NULL)
-  {
-    zlib_fs_inflateEnd(z);
-    return Z_MEM_ERROR;
-  }
-
-  /* reset state */
-  zlib_fs_inflateReset(z);
-  return Z_OK;
-}
-
-
-int ZEXPORT zlib_fs_inflateInit_(z, version, stream_size)
-z_streamp z;
-const char *version;
-int stream_size;
-{
-  return zlib_fs_inflateInit2_(z, DEF_WBITS, version, stream_size);
-}
-
-#undef NEEDBYTE
-#undef NEXTBYTE
-#define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
-#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
-
-int ZEXPORT zlib_fs_inflate(z, f)
-z_streamp z;
-int f;
-{
-  int r;
-  uInt b;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
-    return Z_STREAM_ERROR;
-  f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
-  r = Z_BUF_ERROR;
-  while (1) switch (z->state->mode)
-  {
-    case METHOD:
-      NEEDBYTE
-      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
-      {
-        z->state->mode = I_BAD;
-        z->msg = (char*)"unknown compression method";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
-      {
-        z->state->mode = I_BAD;
-        z->msg = (char*)"invalid window size";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      z->state->mode = FLAG;
-    case FLAG:
-      NEEDBYTE
-      b = NEXTBYTE;
-      if (((z->state->sub.method << 8) + b) % 31)
-      {
-        z->state->mode = I_BAD;
-        z->msg = (char*)"incorrect header check";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      if (!(b & PRESET_DICT))
-      {
-        z->state->mode = BLOCKS;
-        break;
-      }
-      z->state->mode = DICT4;
-    case DICT4:
-      NEEDBYTE
-      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-      z->state->mode = DICT3;
-    case DICT3:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-      z->state->mode = DICT2;
-    case DICT2:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-      z->state->mode = DICT1;
-    case DICT1:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE;
-      z->adler = z->state->sub.check.need;
-      z->state->mode = DICT0;
-      return Z_NEED_DICT;
-    case DICT0:
-      z->state->mode = I_BAD;
-      z->msg = (char*)"need dictionary";
-      z->state->sub.marker = 0;       /* can try inflateSync */
-      return Z_STREAM_ERROR;
-    case BLOCKS:
-      r = zlib_fs_inflate_blocks(z->state->blocks, z, r);
-      if (r == Z_DATA_ERROR)
-      {
-        z->state->mode = I_BAD;
-        z->state->sub.marker = 0;       /* can try inflateSync */
-        break;
-      }
-      if (r == Z_OK)
-        r = f;
-      if (r != Z_STREAM_END)
-        return r;
-      r = f;
-      zlib_fs_inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
-      if (z->state->nowrap)
-      {
-        z->state->mode = I_DONE;
-        break;
-      }
-      z->state->mode = CHECK4;
-    case CHECK4:
-      NEEDBYTE
-      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-      z->state->mode = CHECK3;
-    case CHECK3:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-      z->state->mode = CHECK2;
-    case CHECK2:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-      z->state->mode = CHECK1;
-    case CHECK1:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE;
-
-      if (z->state->sub.check.was != z->state->sub.check.need)
-      {
-        z->state->mode = I_BAD;
-        z->msg = (char*)"incorrect data check";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      z->state->mode = I_DONE;
-    case I_DONE:
-      return Z_STREAM_END;
-    case I_BAD:
-      return Z_DATA_ERROR;
-    default:
-      return Z_STREAM_ERROR;
-  }
-#ifdef NEED_DUMMY_RETURN
-  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
-#endif
-}
-
-
-int ZEXPORT zlib_fs_inflateSync(z)
-z_streamp z;
-{
-  uInt n;       /* number of bytes to look at */
-  Bytef *p;     /* pointer to bytes */
-  uInt m;       /* number of marker bytes found in a row */
-  uLong r, w;   /* temporaries to save total_in and total_out */
-
-  /* set up */
-  if (z == Z_NULL || z->state == Z_NULL)
-    return Z_STREAM_ERROR;
-  if (z->state->mode != I_BAD)
-  {
-    z->state->mode = I_BAD;
-    z->state->sub.marker = 0;
-  }
-  if ((n = z->avail_in) == 0)
-    return Z_BUF_ERROR;
-  p = z->next_in;
-  m = z->state->sub.marker;
-
-  /* search */
-  while (n && m < 4)
-  {
-    static const Byte mark[4] = {0, 0, 0xff, 0xff};
-    if (*p == mark[m])
-      m++;
-    else if (*p)
-      m = 0;
-    else
-      m = 4 - m;
-    p++, n--;
-  }
-
-  /* restore */
-  z->total_in += p - z->next_in;
-  z->next_in = p;
-  z->avail_in = n;
-  z->state->sub.marker = m;
-
-  /* return no joy or set up to restart on a new block */
-  if (m != 4)
-    return Z_DATA_ERROR;
-  r = z->total_in;  w = z->total_out;
-  zlib_fs_inflateReset(z);
-  z->total_in = r;  z->total_out = w;
-  z->state->mode = BLOCKS;
-  return Z_OK;
-}
-
-
-/* Returns true if inflate is currently at the end of a block generated
- * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
- * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
- * but removes the length bytes of the resulting empty stored block. When
- * decompressing, PPP checks that at the end of input packet, inflate is
- * waiting for these length bytes.
- */
-int ZEXPORT zlib_fs_inflateSyncPoint(z)
-z_streamp z;
-{
-  if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
-    return Z_STREAM_ERROR;
-  return zlib_fs_inflate_blocks_sync_point(z->state->blocks);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/inflate_syms.c linux-2.4.20/fs/inflate_fs/inflate_syms.c
--- linux-2.4.19/fs/inflate_fs/inflate_syms.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/inflate_syms.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,22 +0,0 @@
-/*
- * linux/fs/zlib/inflate_syms.c
- *
- * Exported symbols for the inflate functionality.
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/zlib_fs.h>
-
-EXPORT_SYMBOL(zlib_fs_inflate_workspacesize);
-EXPORT_SYMBOL(zlib_fs_inflate);
-EXPORT_SYMBOL(zlib_fs_inflateInit_);
-EXPORT_SYMBOL(zlib_fs_inflateInit2_);
-EXPORT_SYMBOL(zlib_fs_inflateEnd);
-EXPORT_SYMBOL(zlib_fs_inflateSync);
-EXPORT_SYMBOL(zlib_fs_inflateReset);
-EXPORT_SYMBOL(zlib_fs_adler32);
-EXPORT_SYMBOL(zlib_fs_inflateSyncPoint);
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/inftrees.c linux-2.4.20/fs/inflate_fs/inftrees.c
--- linux-2.4.19/fs/inflate_fs/inftrees.c	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/inftrees.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,391 +0,0 @@
-/* inftrees.c -- generate Huffman trees for efficient decoding
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-#include "zutil.h"
-#include "inftrees.h"
-#include "infutil.h"
-
-static const char inflate_copyright[] =
-   " inflate 1.1.3 Copyright 1995-1998 Mark Adler ";
-/*
-  If you use the zlib library in a product, an acknowledgment is welcome
-  in the documentation of your product. If for some reason you cannot
-  include such an acknowledgment, I would appreciate that you keep this
-  copyright string in the executable of your product.
- */
-struct internal_state;
-
-/* simplify the use of the inflate_huft type with some defines */
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-
-local int huft_build OF((
-    uIntf *,            /* code lengths in bits */
-    uInt,               /* number of codes */
-    uInt,               /* number of "simple" codes */
-    const uIntf *,      /* list of base values for non-simple codes */
-    const uIntf *,      /* list of extra bits for non-simple codes */
-    inflate_huft * FAR*,/* result: starting table */
-    uIntf *,            /* maximum lookup bits (returns actual) */
-    inflate_huft *,     /* space for trees */
-    uInt *,             /* hufts used in space */
-    uIntf * ));         /* space for values */
-
-/* Tables for deflate from PKZIP's appnote.txt. */
-local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
-        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
-        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
-        /* see note #13 above about 258 */
-local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
-        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
-        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
-local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
-        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
-        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
-        8193, 12289, 16385, 24577};
-local const uInt cpdext[30] = { /* Extra bits for distance codes */
-        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
-        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
-        12, 12, 13, 13};
-
-/*
-   Huffman code decoding is performed using a multi-level table lookup.
-   The fastest way to decode is to simply build a lookup table whose
-   size is determined by the longest code.  However, the time it takes
-   to build this table can also be a factor if the data being decoded
-   is not very long.  The most common codes are necessarily the
-   shortest codes, so those codes dominate the decoding time, and hence
-   the speed.  The idea is you can have a shorter table that decodes the
-   shorter, more probable codes, and then point to subsidiary tables for
-   the longer codes.  The time it costs to decode the longer codes is
-   then traded against the time it takes to make longer tables.
-
-   This results of this trade are in the variables lbits and dbits
-   below.  lbits is the number of bits the first level table for literal/
-   length codes can decode in one step, and dbits is the same thing for
-   the distance codes.  Subsequent tables are also less than or equal to
-   those sizes.  These values may be adjusted either when all of the
-   codes are shorter than that, in which case the longest code length in
-   bits is used, or when the shortest code is *longer* than the requested
-   table size, in which case the length of the shortest code in bits is
-   used.
-
-   There are two different values for the two tables, since they code a
-   different number of possibilities each.  The literal/length table
-   codes 286 possible values, or in a flat code, a little over eight
-   bits.  The distance table codes 30 possible values, or a little less
-   than five bits, flat.  The optimum values for speed end up being
-   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
-   The optimum values may differ though from machine to machine, and
-   possibly even between compilers.  Your mileage may vary.
- */
-
-
-/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
-#define BMAX 15         /* maximum bit length of any code */
-
-local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
-uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
-uInt n;                 /* number of codes (assumed <= 288) */
-uInt s;                 /* number of simple-valued codes (0..s-1) */
-const uIntf *d;         /* list of base values for non-simple codes */
-const uIntf *e;         /* list of extra bits for non-simple codes */
-inflate_huft * FAR *t;  /* result: starting table */
-uIntf *m;               /* maximum lookup bits, returns actual */
-inflate_huft *hp;       /* space for trees */
-uInt *hn;               /* hufts used in space */
-uIntf *v;               /* working area: values in order of bit length */
-/* Given a list of code lengths and a maximum table size, make a set of
-   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
-   if the given code set is incomplete (the tables are still built in this
-   case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
-   lengths), or Z_MEM_ERROR if not enough memory. */
-{
-
-  uInt a;                       /* counter for codes of length k */
-  uInt c[BMAX+1];               /* bit length count table */
-  uInt f;                       /* i repeats in table every f entries */
-  int g;                        /* maximum code length */
-  int h;                        /* table level */
-  register uInt i;              /* counter, current code */
-  register uInt j;              /* counter */
-  register int k;               /* number of bits in current code */
-  int l;                        /* bits per table (returned in m) */
-  uInt mask;                    /* (1 << w) - 1, to avoid cc -O bug on HP */
-  register uIntf *p;            /* pointer into c[], b[], or v[] */
-  inflate_huft *q;              /* points to current table */
-  struct inflate_huft_s r;      /* table entry for structure assignment */
-  inflate_huft *u[BMAX];        /* table stack */
-  register int w;               /* bits before this table == (l * h) */
-  uInt x[BMAX+1];               /* bit offsets, then code stack */
-  uIntf *xp;                    /* pointer into x */
-  int y;                        /* number of dummy codes added */
-  uInt z;                       /* number of entries in current table */
-
-
-  /* Generate counts for each bit length */
-  p = c;
-#define C0 *p++ = 0;
-#define C2 C0 C0 C0 C0
-#define C4 C2 C2 C2 C2
-  C4                            /* clear c[]--assume BMAX+1 is 16 */
-  p = b;  i = n;
-  do {
-    c[*p++]++;                  /* assume all entries <= BMAX */
-  } while (--i);
-  if (c[0] == n)                /* null input--all zero length codes */
-  {
-    *t = (inflate_huft *)Z_NULL;
-    *m = 0;
-    return Z_OK;
-  }
-
-
-  /* Find minimum and maximum length, bound *m by those */
-  l = *m;
-  for (j = 1; j <= BMAX; j++)
-    if (c[j])
-      break;
-  k = j;                        /* minimum code length */
-  if ((uInt)l < j)
-    l = j;
-  for (i = BMAX; i; i--)
-    if (c[i])
-      break;
-  g = i;                        /* maximum code length */
-  if ((uInt)l > i)
-    l = i;
-  *m = l;
-
-
-  /* Adjust last length count to fill out codes, if needed */
-  for (y = 1 << j; j < i; j++, y <<= 1)
-    if ((y -= c[j]) < 0)
-      return Z_DATA_ERROR;
-  if ((y -= c[i]) < 0)
-    return Z_DATA_ERROR;
-  c[i] += y;
-
-
-  /* Generate starting offsets into the value table for each length */
-  x[1] = j = 0;
-  p = c + 1;  xp = x + 2;
-  while (--i) {                 /* note that i == g from above */
-    *xp++ = (j += *p++);
-  }
-
-
-  /* Make a table of values in order of bit lengths */
-  p = b;  i = 0;
-  do {
-    if ((j = *p++) != 0)
-      v[x[j]++] = i;
-  } while (++i < n);
-  n = x[g];                     /* set n to length of v */
-
-
-  /* Generate the Huffman codes and for each, make the table entries */
-  x[0] = i = 0;                 /* first Huffman code is zero */
-  p = v;                        /* grab values in bit order */
-  h = -1;                       /* no tables yet--level -1 */
-  w = -l;                       /* bits decoded == (l * h) */
-  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
-  q = (inflate_huft *)Z_NULL;   /* ditto */
-  z = 0;                        /* ditto */
-
-  /* go through the bit lengths (k already is bits in shortest code) */
-  for (; k <= g; k++)
-  {
-    a = c[k];
-    while (a--)
-    {
-      /* here i is the Huffman code of length k bits for value *p */
-      /* make tables up to required level */
-      while (k > w + l)
-      {
-        h++;
-        w += l;                 /* previous table always l bits */
-
-        /* compute minimum size table less than or equal to l bits */
-        z = g - w;
-        z = z > (uInt)l ? l : z;        /* table size upper limit */
-        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
-        {                       /* too few codes for k-w bit table */
-          f -= a + 1;           /* deduct codes from patterns left */
-          xp = c + k;
-          if (j < z)
-            while (++j < z)     /* try smaller tables up to z bits */
-            {
-              if ((f <<= 1) <= *++xp)
-                break;          /* enough codes to use up j bits */
-              f -= *xp;         /* else deduct codes from patterns */
-            }
-        }
-        z = 1 << j;             /* table entries for j-bit table */
-
-        /* allocate new table */
-        if (*hn + z > MANY)     /* (note: doesn't matter for fixed) */
-          return Z_MEM_ERROR;   /* not enough memory */
-        u[h] = q = hp + *hn;
-        *hn += z;
-
-        /* connect to last table, if there is one */
-        if (h)
-        {
-          x[h] = i;             /* save pattern for backing up */
-          r.bits = (Byte)l;     /* bits to dump before this table */
-          r.exop = (Byte)j;     /* bits in this table */
-          j = i >> (w - l);
-          r.base = (uInt)(q - u[h-1] - j);   /* offset to this table */
-          u[h-1][j] = r;        /* connect to last table */
-        }
-        else
-          *t = q;               /* first table is returned result */
-      }
-
-      /* set up table entry in r */
-      r.bits = (Byte)(k - w);
-      if (p >= v + n)
-        r.exop = 128 + 64;      /* out of values--invalid code */
-      else if (*p < s)
-      {
-        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
-        r.base = *p++;          /* simple code is just the value */
-      }
-      else
-      {
-        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
-        r.base = d[*p++ - s];
-      }
-
-      /* fill code-like entries with r */
-      f = 1 << (k - w);
-      for (j = i >> w; j < z; j += f)
-        q[j] = r;
-
-      /* backwards increment the k-bit code i */
-      for (j = 1 << (k - 1); i & j; j >>= 1)
-        i ^= j;
-      i ^= j;
-
-      /* backup over finished tables */
-      mask = (1 << w) - 1;      /* needed on HP, cc -O bug */
-      while ((i & mask) != x[h])
-      {
-        h--;                    /* don't need to update q */
-        w -= l;
-        mask = (1 << w) - 1;
-      }
-    }
-  }
-
-
-  /* Return Z_BUF_ERROR if we were given an incomplete table */
-  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
-}
-
-
-int zlib_fs_inflate_trees_bits(c, bb, tb, hp, z)
-uIntf *c;               /* 19 code lengths */
-uIntf *bb;              /* bits tree desired/actual depth */
-inflate_huft * FAR *tb; /* bits tree result */
-inflate_huft *hp;       /* space for trees */
-z_streamp z;            /* for messages */
-{
-  int r;
-  uInt hn = 0;          /* hufts used in space */
-  uIntf *v;             /* work area for huft_build */
-  
-  v = WS(z)->tree_work_area_1;
-  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
-                 tb, bb, hp, &hn, v);
-  if (r == Z_DATA_ERROR)
-    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
-  else if (r == Z_BUF_ERROR || *bb == 0)
-  {
-    z->msg = (char*)"incomplete dynamic bit lengths tree";
-    r = Z_DATA_ERROR;
-  }
-  return r;
-}
-
-int zlib_fs_inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
-uInt nl;                /* number of literal/length codes */
-uInt nd;                /* number of distance codes */
-uIntf *c;               /* that many (total) code lengths */
-uIntf *bl;              /* literal desired/actual bit depth */
-uIntf *bd;              /* distance desired/actual bit depth */
-inflate_huft * FAR *tl; /* literal/length tree result */
-inflate_huft * FAR *td; /* distance tree result */
-inflate_huft *hp;       /* space for trees */
-z_streamp z;            /* for messages */
-{
-  int r;
-  uInt hn = 0;          /* hufts used in space */
-  uIntf *v;             /* work area for huft_build */
-
-  /* allocate work area */
-  v = WS(z)->tree_work_area_2;
-
-  /* build literal/length tree */
-  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
-  if (r != Z_OK || *bl == 0)
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed literal/length tree";
-    else if (r != Z_MEM_ERROR)
-    {
-      z->msg = (char*)"incomplete literal/length tree";
-      r = Z_DATA_ERROR;
-    }
-    return r;
-  }
-
-  /* build distance tree */
-  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
-  if (r != Z_OK || (*bd == 0 && nl > 257))
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed distance tree";
-    else if (r == Z_BUF_ERROR) {
-#ifdef PKZIP_BUG_WORKAROUND
-      r = Z_OK;
-    }
-#else
-      z->msg = (char*)"incomplete distance tree";
-      r = Z_DATA_ERROR;
-    }
-    else if (r != Z_MEM_ERROR)
-    {
-      z->msg = (char*)"empty distance tree with lengths";
-      r = Z_DATA_ERROR;
-    }
-    return r;
-#endif
-  }
-
-  /* done */
-  return Z_OK;
-}
-
-
-/* build fixed tables only once--keep them here */
-#include "inffixed.h"
-
-
-int zlib_fs_inflate_trees_fixed(bl, bd, tl, td, z)
-uIntf *bl;               /* literal desired/actual bit depth */
-uIntf *bd;               /* distance desired/actual bit depth */
-inflate_huft * FAR *tl;  /* literal/length tree result */
-inflate_huft * FAR *td;  /* distance tree result */
-z_streamp z;             /* for memory allocation */
-{
-  *bl = fixed_bl;
-  *bd = fixed_bd;
-  *tl = fixed_tl;
-  *td = fixed_td;
-  return Z_OK;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/inftrees.h linux-2.4.20/fs/inflate_fs/inftrees.h
--- linux-2.4.19/fs/inflate_fs/inftrees.h	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/inftrees.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,63 +0,0 @@
-/* inftrees.h -- header to use inftrees.c
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-/* Huffman code lookup table entry--this entry is four bytes for machines
-   that have 16-bit pointers (e.g. PC's in the small or medium model). */
-
-#ifndef _INFTREES_H
-#define _INFTREES_H
-
-typedef struct inflate_huft_s FAR inflate_huft;
-
-struct inflate_huft_s {
-  union {
-    struct {
-      Byte Exop;        /* number of extra bits or operation */
-      Byte Bits;        /* number of bits in this code or subcode */
-    } what;
-    uInt pad;           /* pad structure to a power of 2 (4 bytes for */
-  } word;               /*  16-bit, 8 bytes for 32-bit int's) */
-  uInt base;            /* literal, length base, distance base,
-                           or table offset */
-};
-
-/* Maximum size of dynamic tree.  The maximum found in a long but non-
-   exhaustive search was 1004 huft structures (850 for length/literals
-   and 154 for distances, the latter actually the result of an
-   exhaustive search).  The actual maximum is not known, but the
-   value below is more than safe. */
-#define MANY 1440
-
-extern int zlib_fs_inflate_trees_bits OF((
-    uIntf *,                    /* 19 code lengths */
-    uIntf *,                    /* bits tree desired/actual depth */
-    inflate_huft * FAR *,       /* bits tree result */
-    inflate_huft *,             /* space for trees */
-    z_streamp));                /* for messages */
-
-extern int zlib_fs_inflate_trees_dynamic OF((
-    uInt,                       /* number of literal/length codes */
-    uInt,                       /* number of distance codes */
-    uIntf *,                    /* that many (total) code lengths */
-    uIntf *,                    /* literal desired/actual bit depth */
-    uIntf *,                    /* distance desired/actual bit depth */
-    inflate_huft * FAR *,       /* literal/length tree result */
-    inflate_huft * FAR *,       /* distance tree result */
-    inflate_huft *,             /* space for trees */
-    z_streamp));                /* for messages */
-
-extern int zlib_fs_inflate_trees_fixed OF((
-    uIntf *,                    /* literal desired/actual bit depth */
-    uIntf *,                    /* distance desired/actual bit depth */
-    inflate_huft * FAR *,       /* literal/length tree result */
-    inflate_huft * FAR *,       /* distance tree result */
-    z_streamp));                /* for memory allocation */
-
-#endif /* _INFTREES_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/infutil.c linux-2.4.20/fs/inflate_fs/infutil.c
--- linux-2.4.19/fs/inflate_fs/infutil.c	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/infutil.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,87 +0,0 @@
-/* inflate_util.c -- data and routines common to blocks and codes
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-#include "zutil.h"
-#include "infblock.h"
-#include "inftrees.h"
-#include "infcodes.h"
-#include "infutil.h"
-
-struct inflate_codes_state;
-
-/* And'ing with mask[n] masks the lower n bits */
-uInt zlib_fs_inflate_mask[17] = {
-    0x0000,
-    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
-    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-};
-
-
-/* copy as much as possible from the sliding window to the output area */
-int zlib_fs_inflate_flush(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt n;
-  Bytef *p;
-  Bytef *q;
-
-  /* local copies of source and destination pointers */
-  p = z->next_out;
-  q = s->read;
-
-  /* compute number of bytes to copy as far as end of window */
-  n = (uInt)((q <= s->write ? s->write : s->end) - q);
-  if (n > z->avail_out) n = z->avail_out;
-  if (n && r == Z_BUF_ERROR) r = Z_OK;
-
-  /* update counters */
-  z->avail_out -= n;
-  z->total_out += n;
-
-  /* update check information */
-  if (s->checkfn != Z_NULL)
-    z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-  /* copy as far as end of window */
-  memcpy(p, q, n);
-  p += n;
-  q += n;
-
-  /* see if more to copy at beginning of window */
-  if (q == s->end)
-  {
-    /* wrap pointers */
-    q = s->window;
-    if (s->write == s->end)
-      s->write = s->window;
-
-    /* compute bytes to copy */
-    n = (uInt)(s->write - q);
-    if (n > z->avail_out) n = z->avail_out;
-    if (n && r == Z_BUF_ERROR) r = Z_OK;
-
-    /* update counters */
-    z->avail_out -= n;
-    z->total_out += n;
-
-    /* update check information */
-    if (s->checkfn != Z_NULL)
-      z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-    /* copy */
-    memcpy(p, q, n);
-    p += n;
-    q += n;
-  }
-
-  /* update pointers */
-  z->next_out = p;
-  s->read = q;
-
-  /* done */
-  return r;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/infutil.h linux-2.4.20/fs/inflate_fs/infutil.h
--- linux-2.4.19/fs/inflate_fs/infutil.h	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/infutil.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,197 +0,0 @@
-/* infutil.h -- types and macros common to blocks and codes
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-#ifndef _INFUTIL_H
-#define _INFUTIL_H
-
-#include "zconf.h"
-#include "inftrees.h"
-#include "infcodes.h"
-
-typedef enum {
-      TYPE,     /* get type bits (3, including end bit) */
-      LENS,     /* get lengths for stored */
-      STORED,   /* processing stored block */
-      TABLE,    /* get table lengths */
-      BTREE,    /* get bit lengths tree for a dynamic block */
-      DTREE,    /* get length, distance trees for a dynamic block */
-      CODES,    /* processing fixed or dynamic block */
-      DRY,      /* output remaining window bytes */
-      B_DONE,   /* finished last block, done */
-      B_BAD}    /* got a data error--stuck here */
-inflate_block_mode;
-
-/* inflate blocks semi-private state */
-struct inflate_blocks_state {
-
-  /* mode */
-  inflate_block_mode  mode;     /* current inflate_block mode */
-
-  /* mode dependent information */
-  union {
-    uInt left;          /* if STORED, bytes left to copy */
-    struct {
-      uInt table;               /* table lengths (14 bits) */
-      uInt index;               /* index into blens (or border) */
-      uIntf *blens;             /* bit lengths of codes */
-      uInt bb;                  /* bit length tree depth */
-      inflate_huft *tb;         /* bit length decoding tree */
-    } trees;            /* if DTREE, decoding info for trees */
-    struct {
-      inflate_codes_statef 
-         *codes;
-    } decode;           /* if CODES, current state */
-  } sub;                /* submode */
-  uInt last;            /* true if this block is the last block */
-
-  /* mode independent information */
-  uInt bitk;            /* bits in bit buffer */
-  uLong bitb;           /* bit buffer */
-  inflate_huft *hufts;  /* single malloc for tree space */
-  Bytef *window;        /* sliding window */
-  Bytef *end;           /* one byte after sliding window */
-  Bytef *read;          /* window read pointer */
-  Bytef *write;         /* window write pointer */
-  check_func checkfn;   /* check function */
-  uLong check;          /* check on output */
-
-};
-
-
-/* defines for inflate input/output */
-/*   update pointers and return */
-#define UPDBITS {s->bitb=b;s->bitk=k;}
-#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
-#define UPDOUT {s->write=q;}
-#define UPDATE {UPDBITS UPDIN UPDOUT}
-#define LEAVE {UPDATE return zlib_fs_inflate_flush(s,z,r);}
-/*   get bytes and bits */
-#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
-#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
-#define NEXTBYTE (n--,*p++)
-#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-#define DUMPBITS(j) {b>>=(j);k-=(j);}
-/*   output bytes */
-#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
-#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
-#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
-#define FLUSH {UPDOUT r=zlib_fs_inflate_flush(s,z,r); LOADOUT}
-#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
-#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
-/*   load local pointers */
-#define LOAD {LOADIN LOADOUT}
-
-/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
-extern uInt zlib_fs_inflate_mask[17];
-
-/* copy as much as possible from the sliding window to the output area */
-extern int zlib_fs_inflate_flush OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));
-
-/* inflate private state */
-typedef enum {
-      METHOD,   /* waiting for method byte */
-      FLAG,     /* waiting for flag byte */
-      DICT4,    /* four dictionary check bytes to go */
-      DICT3,    /* three dictionary check bytes to go */
-      DICT2,    /* two dictionary check bytes to go */
-      DICT1,    /* one dictionary check byte to go */
-      DICT0,    /* waiting for inflateSetDictionary */
-      BLOCKS,   /* decompressing blocks */
-      CHECK4,   /* four check bytes to go */
-      CHECK3,   /* three check bytes to go */
-      CHECK2,   /* two check bytes to go */
-      CHECK1,   /* one check byte to go */
-      I_DONE,   /* finished check, done */
-      I_BAD}    /* got an error--stay here */
-inflate_mode;
-
-struct internal_state {
-
-  /* mode */
-  inflate_mode  mode;   /* current inflate mode */
-
-  /* mode dependent information */
-  union {
-    uInt method;        /* if FLAGS, method byte */
-    struct {
-      uLong was;                /* computed check value */
-      uLong need;               /* stream check value */
-    } check;            /* if CHECK, check values to compare */
-    uInt marker;        /* if BAD, inflateSync's marker bytes count */
-  } sub;        /* submode */
-
-  /* mode independent information */
-  int  nowrap;          /* flag for no wrapper */
-  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
-  inflate_blocks_statef 
-    *blocks;            /* current inflate_blocks state */
-
-};
-
-/* inflate codes private state */
-typedef enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
-      START,    /* x: set up for LEN */
-      LEN,      /* i: get length/literal/eob next */
-      LENEXT,   /* i: getting length extra (have base) */
-      DIST,     /* i: get distance next */
-      DISTEXT,  /* i: getting distance extra */
-      COPY,     /* o: copying bytes in window, waiting for space */
-      LIT,      /* o: got literal, waiting for output space */
-      WASH,     /* o: got eob, possibly still output waiting */
-      END,      /* x: got eob and all data flushed */
-      BADCODE}  /* x: got error */
-inflate_codes_mode;
-
-struct inflate_codes_state {
-
-  /* mode */
-  inflate_codes_mode mode;      /* current inflate_codes mode */
-
-  /* mode dependent information */
-  uInt len;
-  union {
-    struct {
-      inflate_huft *tree;       /* pointer into tree */
-      uInt need;                /* bits needed */
-    } code;             /* if LEN or DIST, where in tree */
-    uInt lit;           /* if LIT, literal */
-    struct {
-      uInt get;                 /* bits to get for extra */
-      uInt dist;                /* distance back to copy from */
-    } copy;             /* if EXT or COPY, where and how much */
-  } sub;                /* submode */
-
-  /* mode independent information */
-  Byte lbits;           /* ltree bits decoded per branch */
-  Byte dbits;           /* dtree bits decoder per branch */
-  inflate_huft *ltree;          /* literal/length/eob tree */
-  inflate_huft *dtree;          /* distance tree */
-
-};
-
-/* memory allocation for inflation */
-
-struct inflate_workspace {
-	inflate_codes_statef working_state;
-	struct inflate_blocks_state working_blocks_state;
-	struct internal_state internal_state;
-	unsigned int tree_work_area_1[19];
-	unsigned int tree_work_area_2[288];
-	unsigned working_blens[258 + 0x1f + 0x1f];
-	inflate_huft working_hufts[MANY];
-	unsigned char working_window[1 << MAX_WBITS];
-};
-
-#define WS(z) ((struct inflate_workspace *)(z->workspace))
-
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/zconf.h linux-2.4.20/fs/inflate_fs/zconf.h
--- linux-2.4.19/fs/inflate_fs/zconf.h	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/zconf.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,90 +0,0 @@
-/* zconf.h -- configuration of the zlib compression library
- * Copyright (C) 1995-1998 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* @(#) $Id$ */
-
-#ifndef _ZCONF_H
-#define _ZCONF_H
-
-#if defined(__GNUC__) || defined(__386__) || defined(i386)
-#  ifndef __32BIT__
-#    define __32BIT__
-#  endif
-#endif
-
-#if defined(__STDC__) || defined(__cplusplus)
-#  ifndef STDC
-#    define STDC
-#  endif
-#endif
-
-/* The memory requirements for deflate are (in bytes):
-            (1 << (windowBits+2)) +  (1 << (memLevel+9))
- that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
- plus a few kilobytes for small objects. For example, if you want to reduce
- the default memory requirements from 256K to 128K, compile with
-     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
- Of course this will generally degrade compression (there's no free lunch).
-
-   The memory requirements for inflate are (in bytes) 1 << windowBits
- that is, 32K for windowBits=15 (default value) plus a few kilobytes
- for small objects.
-*/
-
-/* Maximum value for memLevel in deflateInit2 */
-#ifndef MAX_MEM_LEVEL
-#  define MAX_MEM_LEVEL 9
-#endif
-
-/* Maximum value for windowBits in deflateInit2 and inflateInit2.
- * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
- * created by gzip. (Files created by minigzip can still be extracted by
- * gzip.)
- */
-#ifndef MAX_WBITS
-#  define MAX_WBITS   15 /* 32K LZ77 window */
-#endif
-
-                        /* Type declarations */
-
-#ifndef OF /* function prototypes */
-#  ifdef STDC
-#    define OF(args)  args
-#  else
-#    define OF(args)  ()
-#  endif
-#endif
-
-#ifndef ZEXPORT
-#  define ZEXPORT
-#endif
-#ifndef ZEXPORTVA
-#  define ZEXPORTVA
-#endif
-#ifndef ZEXTERN
-#  define ZEXTERN extern
-#endif
-#ifndef FAR
-#   define FAR
-#endif
-
-typedef unsigned char  Byte;  /* 8 bits */
-typedef unsigned int   uInt;  /* 16 bits or more */
-typedef unsigned long  uLong; /* 32 bits or more */
-
-typedef Byte  FAR Bytef;
-typedef char  FAR charf;
-typedef int   FAR intf;
-typedef uInt  FAR uIntf;
-typedef uLong FAR uLongf;
-
-typedef void FAR *voidpf;
-typedef void     *voidp;
-
-#include <linux/types.h> /* for off_t */
-#include <linux/unistd.h>    /* for SEEK_* and off_t */
-#define z_off_t  off_t
-
-#endif /* _ZCONF_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/inflate_fs/zutil.h linux-2.4.20/fs/inflate_fs/zutil.h
--- linux-2.4.19/fs/inflate_fs/zutil.h	2001-10-25 20:53:53.000000000 +0000
+++ linux-2.4.20/fs/inflate_fs/zutil.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,70 +0,0 @@
-/* zutil.h -- internal interface and configuration of the compression library
- * Copyright (C) 1995-1998 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-/* @(#) $Id: zutil.h,v 1.1 2000/01/01 03:32:23 davem Exp $ */
-
-#ifndef _Z_UTIL_H
-#define _Z_UTIL_H
-
-#include <linux/zlib_fs.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-
-#ifndef local
-#  define local static
-#endif
-/* compile with -Dlocal if your debugger can't find static symbols */
-
-typedef unsigned char  uch;
-typedef uch FAR uchf;
-typedef unsigned short ush;
-typedef ush FAR ushf;
-typedef unsigned long  ulg;
-
-        /* common constants */
-
-#ifndef DEF_WBITS
-#  define DEF_WBITS MAX_WBITS
-#endif
-/* default windowBits for decompression. MAX_WBITS is for compression only */
-
-#if MAX_MEM_LEVEL >= 8
-#  define DEF_MEM_LEVEL 8
-#else
-#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
-#endif
-/* default memLevel */
-
-#define STORED_BLOCK 0
-#define STATIC_TREES 1
-#define DYN_TREES    2
-/* The three kinds of block type */
-
-#define MIN_MATCH  3
-#define MAX_MATCH  258
-/* The minimum and maximum match lengths */
-
-#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
-
-        /* target dependencies */
-
-        /* Common defaults */
-
-#ifndef OS_CODE
-#  define OS_CODE  0x03  /* assume Unix */
-#endif
-
-         /* functions */
-
-typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
-				       uInt len));
-
-#endif /* _Z_UTIL_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/Makefile linux-2.4.20/fs/intermezzo/Makefile
--- linux-2.4.19/fs/intermezzo/Makefile	2001-11-11 18:20:21.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/Makefile	2002-10-29 11:18:34.000000000 +0000
@@ -4,8 +4,11 @@
 
 O_TARGET := intermezzo.o
 
-obj-y :=  journal_reiserfs.o cache.o  journal.o presto.o vfs.o psdev.o upcall.o methods.o sysctl.o dcache.o  dir.o  super.o journal_ext2.o journal_ext3.o journal_xfs.o  inode.o  file.o journal_obdfs.o
-
+obj-y :=  cache.o dcache.o dir.o ext_attr.o file.o fileset.o inode.o \
+	  journal.o journal_ext2.o journal_ext3.o journal_obdfs.o \
+          journal_reiserfs.o journal_tmpfs.o journal_xfs.o kml_reint.o \
+          kml_unpack.o methods.o presto.o psdev.o replicator.o super.o \
+          sysctl.o upcall.o vfs.o
 
 obj-m := $(O_TARGET)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/cache.c linux-2.4.20/fs/intermezzo/cache.c
--- linux-2.4.19/fs/intermezzo/cache.c	2001-11-11 18:20:21.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/cache.c	2002-10-29 11:18:39.000000000 +0000
@@ -1,10 +1,23 @@
-/*
- *
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
  *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #define __NO_VERSION__
@@ -27,7 +40,6 @@
 #include <linux/init.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 
 /*
@@ -38,6 +50,8 @@
    The methods for the cache are set up in methods.
 */
 
+extern kmem_cache_t * presto_dentry_slab;
+
 /* the intent of this hash is to have collision chains of length 1 */
 #define CACHES_BITS 8
 #define CACHES_SIZE (1 << CACHES_BITS)
@@ -56,7 +70,7 @@
         cache->cache_dev = dev;
 }
 
-inline void presto_init_cache_hash(void)
+inline void presto_cache_init_hash(void)
 {
         int i;
         for ( i = 0; i < CACHES_SIZE; i++ ) {
@@ -65,7 +79,7 @@
 }
 
 /* map a device to a cache */
-struct presto_cache *presto_find_cache(kdev_t dev)
+struct presto_cache *presto_cache_find(kdev_t dev)
 {
         struct presto_cache *cache;
         struct list_head *lh, *tmp;
@@ -85,85 +99,19 @@
 struct presto_cache *presto_get_cache(struct inode *inode)
 {
         struct presto_cache *cache;
-
+        ENTRY;
         /* find the correct presto_cache here, based on the device */
-        cache = presto_find_cache(inode->i_dev);
+        cache = presto_cache_find(inode->i_dev);
         if ( !cache ) {
-                printk("WARNING: no presto cache for dev %x, ino %ld\n",
+                CERROR("WARNING: no presto cache for dev %x, ino %ld\n",
                        inode->i_dev, inode->i_ino);
                 EXIT;
                 return NULL;
         }
+        EXIT;
         return cache;
 }
 
-
-/* list cache mount points for ioctl's or /proc/fs/intermezzo/mounts */
-int presto_sprint_mounts(char *buf, int buflen, int minor)
-{
-        int len = 0;
-        int i;
-        struct list_head *head, *tmp;
-        struct presto_cache *cache;
-
-        buf[0] = '\0';
-        for (i=0 ; i<CACHES_SIZE ; i++) {
-                head = tmp = &presto_caches[i];
-                while ( (tmp = tmp->next) != head ) {
-                        cache = list_entry(tmp, struct presto_cache,
-                                            cache_chain);
-                        if ( !cache->cache_root_fileset || !cache->cache_mtpt)
-                                continue;
-                        if ((minor != -1) &&
-                            (cache->cache_psdev->uc_minor != minor))
-                                continue;
-                        if ( strlen(cache->cache_root_fileset) +
-                             strlen(cache->cache_mtpt) + 
-                             strlen(cache->cache_psdev->uc_devname) +
-                             4 > buflen - len)
-                                break;
-                        len += sprintf(buf + len, "%s %s %s\n",
-                                       cache->cache_root_fileset,
-                                       cache->cache_mtpt,
-                                       cache->cache_psdev->uc_devname);
-                }
-        }
-
-        buf[buflen-1] = '\0';
-        CDEBUG(D_SUPER, "%s\n", buf);
-        return len;
-}
-
-#ifdef CONFIG_KREINT
-/* get mount point by volname
-       Arthur Ma, 2000.12.25
- */
-int presto_get_mount (char *buf, int buflen, char *volname)
-{
-        int i;
-        struct list_head *head, *tmp;
-        struct presto_cache *cache = NULL;
-        char *path = "";
-
-        buf[0] = '\0';
-        for (i=0 ; i<CACHES_SIZE ; i++) {
-                head = tmp = &presto_caches[i];
-                while ( (tmp = tmp->next) != head ) {
-                        cache = list_entry(tmp, struct presto_cache,
-                                            cache_chain);
-                        if ( !cache->cache_root_fileset || !cache->cache_mtpt)
-                                continue;
-                        if ( strcmp(cache->cache_root_fileset, volname) == 0)
-                                break;
-                }
-        }
-        if (cache != NULL)
-                path = cache->cache_mtpt;
-        strncpy (buf, path, buflen);
-        return strlen (buf);
-}
-#endif
-
 /* another debugging routine: check fs is InterMezzo fs */
 int presto_ispresto(struct inode *inode)
 {
@@ -178,23 +126,21 @@
 }
 
 /* setup a cache structure when we need one */
-struct presto_cache *presto_init_cache(void)
+struct presto_cache *presto_cache_init(void)
 {
         struct presto_cache *cache;
 
-        /* make a presto_cache structure for the hash */
-        PRESTO_ALLOC(cache, struct presto_cache *, sizeof(struct presto_cache));
+        PRESTO_ALLOC(cache, sizeof(struct presto_cache));
         if ( cache ) {
                 memset(cache, 0, sizeof(struct presto_cache));
                 INIT_LIST_HEAD(&cache->cache_chain);
                 INIT_LIST_HEAD(&cache->cache_fset_list);
+                cache->cache_lock = SPIN_LOCK_UNLOCKED;
+                cache->cache_reserved = 0; 
         }
-	cache->cache_lock = SPIN_LOCK_UNLOCKED;
-	cache->cache_reserved = 0; 
         return cache;
 }
 
-
 /* free a cache structure and all of the memory it is pointing to */
 inline void presto_free_cache(struct presto_cache *cache)
 {
@@ -202,12 +148,12 @@
                 return;
 
         list_del(&cache->cache_chain);
-        if (cache->cache_mtpt)
-                PRESTO_FREE(cache->cache_mtpt, strlen(cache->cache_mtpt) + 1);
-        if (cache->cache_type)
-                PRESTO_FREE(cache->cache_type, strlen(cache->cache_type) + 1);
-        if (cache->cache_root_fileset)
-                PRESTO_FREE(cache->cache_root_fileset, strlen(cache->cache_root_fileset) + 1);
+        if (cache->cache_sb && cache->cache_sb->s_root &&
+                        presto_d2d(cache->cache_sb->s_root)) {
+                kmem_cache_free(presto_dentry_slab, 
+                                presto_d2d(cache->cache_sb->s_root));
+                cache->cache_sb->s_root->d_fsdata = NULL;
+        }
 
         PRESTO_FREE(cache, sizeof(struct presto_cache));
 }
@@ -216,41 +162,43 @@
 {
         struct filter_fs *filter; 
         loff_t avail; 
-	struct super_block *sb = cache->cache_sb;
+        struct super_block *sb = cache->cache_sb;
         filter = cache->cache_filter;
-	if (!filter ) {
-		EXIT;
-		return 0; 
-	}
-	if (!filter->o_trops ) {
-		EXIT;
-		return 0; 
-	}
-	if (!filter->o_trops->tr_avail ) {
-		EXIT;
-		return 0; 
-	}
+        if (!filter ) {
+                EXIT;
+                return 0; 
+        }
+        if (!filter->o_trops ) {
+                EXIT;
+                return 0; 
+        }
+        if (!filter->o_trops->tr_avail ) {
+                EXIT;
+                return 0; 
+        }
+
+        spin_lock(&cache->cache_lock);
         avail = filter->o_trops->tr_avail(cache, sb); 
         CDEBUG(D_SUPER, "ESC::%ld +++> %ld \n", (long) cache->cache_reserved,
-	         (long) (cache->cache_reserved + req)); 
+                 (long) (cache->cache_reserved + req)); 
         CDEBUG(D_SUPER, "ESC::Avail::%ld \n", (long) avail);
-	spin_lock(&cache->cache_lock);
         if (req + cache->cache_reserved > avail) {
-		spin_unlock(&cache->cache_lock);
+                spin_unlock(&cache->cache_lock);
                 EXIT;
                 return -ENOSPC;
         }
-	cache->cache_reserved += req; 
-	spin_unlock(&cache->cache_lock);
+        cache->cache_reserved += req; 
+        spin_unlock(&cache->cache_lock);
 
+        EXIT;
         return 0;
 }
 
 void presto_release_space(struct presto_cache *cache, loff_t req)
 {
         CDEBUG(D_SUPER, "ESC::%ld ---> %ld \n", (long) cache->cache_reserved,
-	         (long) (cache->cache_reserved - req)); 
-	spin_lock(&cache->cache_lock);
-	cache->cache_reserved -= req; 
-	spin_unlock(&cache->cache_lock);
+                 (long) (cache->cache_reserved - req)); 
+        spin_lock(&cache->cache_lock);
+        cache->cache_reserved -= req; 
+        spin_unlock(&cache->cache_lock);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/dcache.c linux-2.4.20/fs/intermezzo/dcache.c
--- linux-2.4.19/fs/intermezzo/dcache.c	2002-02-25 19:38:08.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/dcache.c	2002-10-29 11:18:36.000000000 +0000
@@ -1,10 +1,34 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Original version: Copyright (C) 1996 P. Braam and M. Callahan
+ *  Rewritten for Linux 2.1. Copyright (C) 1997 Carnegie Mellon University
+ *  d_fsdata and NFS compatiblity fixes Copyright (C) 2001 Tacit Networks, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
  * Directory operations for InterMezzo filesystem
- * Original version: (C) 1996 P. Braam and M. Callahan
- * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
+ */
+
+/* inode dentry alias list walking code adapted from linux/fs/dcache.c
  *
- * Stelias encourages users to contribute improvements to
- * the InterMezzo project. Contact Peter Braam (coda@stelias.com).
+ * fs/dcache.c
+ *
+ * (C) 1997 Thomas Schoebel-Theuer,
+ * with heavy changes by Linus Torvalds
  */
 
 #define __NO_VERSION__
@@ -15,48 +39,307 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/locks.h>
+#include <linux/slab.h>
 #include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
 
 #include <linux/intermezzo_fs.h>
 
-static int presto_dentry_revalidate(struct dentry *de, int );
-
+static kmem_cache_t * presto_dentry_slab;
 
 /* called when a cache lookup succeeds */
-static int presto_dentry_revalidate(struct dentry *de, int flag)
+static int presto_d_revalidate(struct dentry *de, int flag)
 {
-	struct inode *inode = de->d_inode;
-	ENTRY;
-	if (!inode) {
-		EXIT;
-		return 1;
-	}
-	if (is_bad_inode(inode)) {
-		EXIT;
-		return 0;
-	}
-
-	if ( S_ISDIR(inode->i_mode) ) {
-		EXIT;
-		return (presto_chk(de, PRESTO_DATA) &&
-			(presto_chk(de, PRESTO_ATTR)));
-	} else {
-		EXIT;
-		return presto_chk(de, PRESTO_ATTR);
-	}
+        struct inode *inode = de->d_inode;
+        struct presto_file_set * root_fset;
+
+        ENTRY;
+        if (!inode) {
+                EXIT;
+                return 0;
+        }
+
+        if (is_bad_inode(inode)) {
+                EXIT;
+                return 0;
+        }
+
+        if (!presto_d2d(de)) {
+                presto_set_dd(de);
+        }
+
+        if (!presto_d2d(de)) {
+                EXIT;
+                return 0;
+        }
+
+        root_fset = presto_d2d(de->d_inode->i_sb->s_root)->dd_fset;
+        if (root_fset->fset_flags & FSET_FLAT_BRANCH && 
+            (presto_d2d(de)->dd_fset != root_fset )) {
+                presto_d2d(de)->dd_fset = root_fset;
+        }
+
+        EXIT;
+        return 1;
+
+#if 0
+        /* The following is needed for metadata on demand. */
+        if ( S_ISDIR(inode->i_mode) ) {
+                EXIT;
+                return (presto_chk(de, PRESTO_DATA) &&
+                        (presto_chk(de, PRESTO_ATTR)));
+        } else {
+                EXIT;
+                return presto_chk(de, PRESTO_ATTR);
+        }
+#endif
 }
 
-static void presto_dentry_iput(struct dentry *dentry, struct inode *inode)
+static void presto_d_release(struct dentry *dentry)
 {
-	dentry->d_time = 0;
-	iput(inode);
+        if (!presto_d2d(dentry)) {
+                /* This can happen for dentries from NFSd */
+                return;
+        }
+        presto_d2d(dentry)->dd_count--;
+
+        if (!presto_d2d(dentry)->dd_count) {
+                kmem_cache_free(presto_dentry_slab, presto_d2d(dentry));
+                dentry->d_fsdata = NULL;
+        }
 }
 
 struct dentry_operations presto_dentry_ops = 
 {
-	d_revalidate: presto_dentry_revalidate,
-        d_iput: presto_dentry_iput
+        .d_revalidate =  presto_d_revalidate,
+        .d_release = presto_d_release
 };
 
+static inline int presto_is_dentry_ROOT (struct dentry *dentry)
+{
+        return(dentry_name_cmp(dentry,"ROOT") &&
+               !dentry_name_cmp(dentry->d_parent,".intermezzo"));
+}
+
+static struct presto_file_set* presto_try_find_fset(struct dentry* dentry,
+                int *is_under_d_intermezzo)
+{
+        struct dentry* temp_dentry;
+        struct presto_dentry_data *d_data;
+        int found_root=0;
+
+        ENTRY;
+        CDEBUG(D_FSDATA, "finding fileset for %p:%s\n", dentry, 
+                        dentry->d_name.name);
+
+        *is_under_d_intermezzo = 0;
+
+        /* walk up through the branch to get the fileset */
+        /* The dentry we are passed presumably does not have the correct
+         * fset information. However, we still want to start walking up
+         * the branch from this dentry to get our found_root and 
+         * is_under_d_intermezzo decisions correct
+         */
+        for (temp_dentry = dentry ; ; temp_dentry = temp_dentry->d_parent) {
+                CDEBUG(D_FSDATA, "--->dentry %p:%*s\n", temp_dentry, 
+                        temp_dentry->d_name.len,temp_dentry->d_name.name);
+                if (presto_is_dentry_ROOT(temp_dentry))
+                        found_root = 1;
+                if (!found_root &&
+                    dentry_name_cmp(temp_dentry, ".intermezzo")) {
+                        *is_under_d_intermezzo = 1;
+                }
+                d_data = presto_d2d(temp_dentry);
+                if (d_data) {
+                        /* If we found a "ROOT" dentry while walking up the
+                         * branch, we will journal regardless of whether
+                         * we are under .intermezzo or not.
+                         * If we are already under d_intermezzo don't reverse
+                         * the decision here...even if we found a "ROOT"
+                         * dentry above .intermezzo (if we were ever to
+                         * modify the directory structure).
+                         */
+                        if (!*is_under_d_intermezzo)  
+                                *is_under_d_intermezzo = !found_root &&
+                                  (d_data->dd_flags & PRESTO_DONT_JOURNAL);
+                        EXIT;
+                        return d_data->dd_fset;
+                }
+                if (temp_dentry->d_parent == temp_dentry) {
+                        break;
+                }
+        }
+        EXIT;
+        return NULL;
+}
+
+/* Only call this function on positive dentries */
+static struct presto_dentry_data* presto_try_find_alias_with_dd (
+                  struct dentry* dentry)
+{
+        struct inode *inode=dentry->d_inode;
+        struct list_head *head, *next, *tmp;
+        struct dentry *tmp_dentry;
+
+        /* Search through the alias list for dentries with d_fsdata */
+        spin_lock(&dcache_lock);
+        head = &inode->i_dentry;
+        next = inode->i_dentry.next;
+        while (next != head) {
+                tmp = next;
+                next = tmp->next;
+                tmp_dentry = list_entry(tmp, struct dentry, d_alias);
+                if (!presto_d2d(tmp_dentry)) {
+                        spin_unlock(&dcache_lock);
+                        return presto_d2d(tmp_dentry);
+                }
+        }
+        spin_unlock(&dcache_lock);
+        return NULL;
+}
+
+/* Only call this function on positive dentries */
+static void presto_set_alias_dd (struct dentry *dentry, 
+                struct presto_dentry_data* dd)
+{
+        struct inode *inode=dentry->d_inode;
+        struct list_head *head, *next, *tmp;
+        struct dentry *tmp_dentry;
+
+        /* Set d_fsdata for this dentry */
+        dd->dd_count++;
+        dentry->d_fsdata = dd;
+
+        /* Now set d_fsdata for all dentries in the alias list. */
+        spin_lock(&dcache_lock);
+        head = &inode->i_dentry;
+        next = inode->i_dentry.next;
+        while (next != head) {
+                tmp = next;
+                next = tmp->next;
+                tmp_dentry = list_entry(tmp, struct dentry, d_alias);
+                if (!presto_d2d(tmp_dentry)) {
+                        dd->dd_count++;
+                        tmp_dentry->d_fsdata = dd;
+                }
+        }
+        spin_unlock(&dcache_lock);
+        return;
+}
+
+inline struct presto_dentry_data *izo_alloc_ddata(void)
+{
+        struct presto_dentry_data *dd;
+
+        dd = kmem_cache_alloc(presto_dentry_slab, SLAB_KERNEL);
+        if (dd == NULL) {
+                CERROR("IZO: out of memory trying to allocate presto_dentry_data\n");
+                return NULL;
+        }
+        memset(dd, 0, sizeof(*dd));
+        dd->dd_count = 1;
+
+        return dd;
+}
+
+/* This uses the BKL! */
+int presto_set_dd(struct dentry * dentry)
+{
+        struct presto_file_set *fset;
+        struct presto_dentry_data *dd;
+        int is_under_d_izo;
+        int error=0;
+
+        ENTRY;
+
+        if (!dentry)
+                BUG();
+
+        lock_kernel();
+
+        /* Did we lose a race? */
+        if (dentry->d_fsdata) {
+                CERROR("dentry %p already has d_fsdata set\n", dentry);
+                if (dentry->d_inode)
+                        CERROR("    inode: %ld\n", dentry->d_inode->i_ino);
+                EXIT;
+                goto out_unlock;
+        }
+
+        if (dentry->d_inode != NULL) {
+                /* NFSd runs find_fh_dentry which instantiates disconnected
+                 * dentries which are then connected without a lookup(). 
+                 * So it is possible to have connected dentries that do not 
+                 * have d_fsdata set. So we walk the list trying to find 
+                 * an alias which has its d_fsdata set and then use that 
+                 * for all the other dentries  as well. 
+                 * - SHP,Vinny. 
+                 */
+
+                /* If there is an alias with d_fsdata use it. */
+                if ((dd = presto_try_find_alias_with_dd (dentry))) {
+                        presto_set_alias_dd (dentry, dd);
+                        EXIT;
+                        goto out_unlock;
+                }
+        } else {
+                /* Negative dentry */
+                CDEBUG(D_FSDATA,"negative dentry %p: %*s\n", dentry, 
+                                dentry->d_name.len, dentry->d_name.name);
+        }
+
+        /* No pre-existing d_fsdata, we need to construct one.
+         * First, we must walk up the tree to find the fileset 
+         * If a fileset can't be found, we leave a null fsdata
+         * and return EROFS to indicate that we can't journal
+         * updates. 
+         */
+        fset = presto_try_find_fset (dentry, &is_under_d_izo);
+        if (!fset) { 
+#ifdef PRESTO_NO_NFS
+                CERROR("No fileset for dentry %p: %*s\n", dentry,
+                                dentry->d_name.len, dentry->d_name.name);
+#endif
+                error = -EROFS;
+                EXIT;
+                goto out_unlock;
+        }
+
+        dentry->d_fsdata = izo_alloc_ddata();
+        if (!presto_d2d(dentry)) {
+                CERROR ("InterMezzo: out of memory allocating d_fsdata\n");
+                error = -ENOMEM;
+                goto out_unlock;
+        }
+        presto_d2d(dentry)->dd_fset = fset;
+        if (is_under_d_izo)
+                presto_d2d(dentry)->dd_flags |= PRESTO_DONT_JOURNAL;
+        EXIT;
+
+out_unlock:    
+        CDEBUG(D_FSDATA,"presto_set_dd dentry %p: %*s, d_fsdata %p\n", 
+                        dentry, dentry->d_name.len, dentry->d_name.name, 
+                        dentry->d_fsdata);
+        unlock_kernel();
+        return error; 
+}
+
+int presto_init_ddata_cache(void)
+{
+        ENTRY;
+        presto_dentry_slab =
+                kmem_cache_create("presto_cache",
+                                  sizeof(struct presto_dentry_data), 0,
+                                  SLAB_HWCACHE_ALIGN, NULL,
+                                  NULL);
+        EXIT;
+        return (presto_dentry_slab != NULL);
+}
+
+void presto_cleanup_ddata_cache(void)
+{
+        kmem_cache_destroy(presto_dentry_slab);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/dir.c linux-2.4.20/fs/intermezzo/dir.c
--- linux-2.4.19/fs/intermezzo/dir.c	2002-02-25 19:38:08.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/dir.c	2002-10-29 11:18:35.000000000 +0000
@@ -1,14 +1,27 @@
-/*
- *
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
  *  Copyright (C) 2000 Tacitus Systems
  *  Copyright (C) 2000 Peter J. Braam
  *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-
 #include <stdarg.h>
 
 #include <asm/bitops.h>
@@ -31,39 +44,38 @@
 #include <linux/module.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 
 static inline void presto_relock_sem(struct inode *dir) 
 {
-	/* the lock from sys_mkdir / lookup_create */
-	down(&dir->i_sem);
-	/* the rest is done by the do_{create,mkdir, ...} */
+        /* the lock from sys_mkdir / lookup_create */
+        down(&dir->i_sem);
+        /* the rest is done by the do_{create,mkdir, ...} */
 }
 
 static inline void presto_relock_other(struct inode *dir) 
 {
-	/* vfs_mkdir locks */
+        /* vfs_mkdir locks */
         down(&dir->i_zombie);
-	lock_kernel(); 
+        lock_kernel(); 
 }
 
 static inline void presto_fulllock(struct inode *dir) 
 {
-	/* the lock from sys_mkdir / lookup_create */
-	down(&dir->i_sem);
-	/* vfs_mkdir locks */
+        /* the lock from sys_mkdir / lookup_create */
+        down(&dir->i_sem);
+        /* vfs_mkdir locks */
         down(&dir->i_zombie);
-	lock_kernel(); 
+        lock_kernel(); 
 }
 
 static inline void presto_unlock(struct inode *dir) 
 {
-	/* vfs_mkdir locks */
-	unlock_kernel(); 
+        /* vfs_mkdir locks */
+        unlock_kernel(); 
         up(&dir->i_zombie);
-	/* the lock from sys_mkdir / lookup_create */
-	up(&dir->i_sem);
+        /* the lock from sys_mkdir / lookup_create */
+        up(&dir->i_sem);
 }
 
 
@@ -71,116 +83,83 @@
  * these are initialized in super.c
  */
 extern int presto_permission(struct inode *inode, int mask);
-int presto_ilookup_uid = 0;
-
-extern int presto_prep(struct dentry *, struct presto_cache **,
-                       struct presto_file_set **);
+static int izo_authorized_uid = 0;
 
-static int dentry2id(struct dentry *dentry, ino_t *id, unsigned int *generation)
+int izo_dentry_is_ilookup(struct dentry *dentry, ino_t *id,
+                          unsigned int *generation)
 {
-        char *tmpname;
+        char tmpname[64];
         char *next;
-        int error = 0;
 
         ENTRY;
-        if (dentry->d_name.len > EXT2_NAME_LEN) {
-                EXIT;
-                return -ENAMETOOLONG;
-        }
-
         /* prefix is 7 characters: '...ino:' */
-        if ( dentry->d_name.len < 7 ||
+        if ( dentry->d_name.len < 7 || dentry->d_name.len > 64 ||
              memcmp(dentry->d_name.name, PRESTO_ILOOKUP_MAGIC, 7) != 0 ) {
                 EXIT;
-                return 1;
-        }
-
-        PRESTO_ALLOC(tmpname, char *, dentry->d_name.len - 7 + 1);
-        if ( !tmpname ) {
-                EXIT;
-                return -ENOMEM;
+                return 0;
         }
 
         memcpy(tmpname, dentry->d_name.name + 7, dentry->d_name.len - 7);
-        *(tmpname + dentry->d_name.len) = '\0';
+        *(tmpname + dentry->d_name.len - 7) = '\0';
 
-        /* name is of the form <inode number>:<generation> */
-        *id = simple_strtoul(tmpname, &next, 0);
+        /* name is of the form ...ino:<inode number>:<generation> */
+        *id = simple_strtoul(tmpname, &next, 16);
         if ( *next == PRESTO_ILOOKUP_SEP ) {
-                *generation = simple_strtoul(next + 1, 0, 0);
-                CDEBUG(D_INODE, "INO to find = %s\n", tmpname);
-                CDEBUG(D_INODE, "Id = %lx (%lu), generation %x (%d)\n",
-                       *id, *id, *generation, *generation);
-        } else
-                error = 1;
-
-        PRESTO_FREE(tmpname, dentry->d_name.len - 7 + 1);
-        EXIT;
-        return error;
+                *generation = simple_strtoul(next + 1, 0, 16);
+                CDEBUG(D_INODE, "ino string: %s, Id = %lx (%lu), "
+                       "generation %x (%d)\n",
+                       tmpname, *id, *id, *generation, *generation);
+                EXIT;
+                return 1;
+        } else {
+                EXIT;
+                return 0;
+        }
 }
 
-static int presto_opendir_upcall(int minor, struct dentry *de, 
-                          struct dentry *root, int async)
+struct dentry *presto_tmpfs_ilookup(struct inode *dir, 
+                                    struct dentry *dentry,
+                                    ino_t ino, 
+                                    unsigned int generation)
 {
-        int rc;
-        char *path, *buffer;
-        int pathlen;
-
-        PRESTO_ALLOC(buffer, char *, PAGE_SIZE);
-        if ( !buffer ) {
-                printk("PRESTO: out of memory!\n");
-                return ENOMEM;
-        }
-        path = presto_path(de, root, buffer, PAGE_SIZE);
-        pathlen = MYPATHLEN(buffer, path);
-        CDEBUG(D_INODE, "path: %*s, len %d\n", pathlen, path, pathlen);
-        rc = lento_opendir(minor, pathlen, path, async);
-        PRESTO_FREE(buffer, PAGE_SIZE);
-        return rc;
+        return dentry; 
 }
 
+
 inline int presto_can_ilookup(void)
 {
-        return (current->euid == presto_ilookup_uid ||
+        return (current->euid == izo_authorized_uid ||
                 capable(CAP_DAC_READ_SEARCH));
 }
 
-struct dentry *presto_ilookup(struct inode *dir, struct dentry *dentry,
-                            ino_t ino, unsigned int generation)
+struct dentry *presto_iget_ilookup(struct inode *dir, 
+                                          struct dentry *dentry,
+                                          ino_t ino, 
+                                          unsigned int generation)
 {
         struct inode *inode;
         int error;
 
         ENTRY;
 
-        /* if we can't ilookup, forbid anything with this name to
-         * avoid any security issues/name clashes.
-         */
         if ( !presto_can_ilookup() ) {
-                CDEBUG(D_CACHE, "ilookup denied: euid %u, ilookup_uid %u\n",
-                       current->euid, presto_ilookup_uid);
-                EXIT;
+                CERROR("ilookup denied: euid %u, authorized_uid %u\n",
+                       current->euid, izo_authorized_uid);
                 return ERR_PTR(-EPERM);
         }
+        error = -ENOENT;
         inode = iget(dir->i_sb, ino);
-        if (!inode || !inode->i_nlink || is_bad_inode(inode)) {
-                CDEBUG(D_PIOCTL, "fatal: invalid inode %ld (%s).\n",
-                       ino, inode ? inode->i_nlink ? "bad inode" :
-                       "no links" : "NULL");
-                error = -ENOENT;
-                EXIT;
+        if (!inode) { 
+                CERROR("fatal: NULL inode ino %lu\n", ino); 
+                goto cleanup_iput;
+        }
+        if (is_bad_inode(inode) || inode->i_nlink == 0) {
+                CERROR("fatal: bad inode ino %lu, links %d\n", ino, inode->i_nlink); 
                 goto cleanup_iput;
         }
-
-        /* We need to make sure we have the right inode (by checking the
-         * generation) so we don't write into the wrong file (old inode was
-         * deleted and then a new one was created with the same number).
-         */
         if (inode->i_generation != generation) {
-                CDEBUG(D_PIOCTL, "fatal: bad generation %u (want %u)\n",
+                CERROR("fatal: bad generation %u (want %u)\n",
                        inode->i_generation, generation);
-                error = -ENOENT;
-                EXIT;
                 goto cleanup_iput;
         }
 
@@ -196,73 +175,164 @@
         return ERR_PTR(error);
 }
 
+struct dentry *presto_add_ilookup_dentry(struct dentry *parent,
+                                         struct dentry *real)
+{
+        struct inode *inode = real->d_inode;
+        struct dentry *de;
+        char buf[32];
+        char *ptr = buf;
+        struct dentry *inodir;
+        struct presto_dentry_data *dd;
+
+        inodir = lookup_one_len("..iopen..", parent,  strlen("..iopen..")); 
+        if (!inodir || IS_ERR(inodir) || !inodir->d_inode ) { 
+                CERROR("%s: bad ..iopen.. lookup\n", __FUNCTION__); 
+                return NULL; 
+        }
+        inodir->d_inode->i_op = &presto_dir_iops;
+
+        snprintf(ptr, 32, "...ino:%lx:%x", inode->i_ino, inode->i_generation);
+
+        de = lookup_one_len(ptr, inodir,  strlen(ptr)); 
+        if (!de || IS_ERR(de)) {
+                CERROR("%s: bad ...ino lookup %ld\n", 
+                       __FUNCTION__, PTR_ERR(de)); 
+                dput(inodir);
+                return NULL; 
+        }
+
+        dd = presto_d2d(real);
+        if (!dd) 
+                BUG();
+
+        /* already exists */
+        if (de->d_inode)
+                BUG();
+#if 0 
+                if (de->d_inode != inode ) { 
+                        CERROR("XX de->d_inode %ld, inode %ld\n", 
+                               de->d_inode->i_ino, inode->i_ino); 
+                        BUG();
+                }
+                if (dd->dd_inodentry) { 
+                        CERROR("inodentry exists %ld \n", inode->i_ino);
+                        BUG();
+                }
+                dput(inodir);
+                return de;
+        }
+#endif 
+
+        if (presto_d2d(de)) 
+                BUG();
+
+        atomic_inc(&inode->i_count);
+        de->d_op = &presto_dentry_ops;
+        d_add(de, inode);
+        if (!de->d_op)
+                CERROR("DD: no ops dentry %p, dd %p\n", de, dd);
+        dd->dd_inodentry = de;
+        dd->dd_count++;
+        de->d_fsdata = dd;
+
+        dput(inodir);
+        return de;
+}
 
 struct dentry *presto_lookup(struct inode * dir, struct dentry *dentry)
 {
         int rc = 0;
         struct dentry *de;
         struct presto_cache *cache;
-        struct presto_file_set *fset;
-        int error; 
         int minor;
         ino_t ino;
         unsigned int generation;
+        struct inode_operations *iops;
+        int is_ilookup = 0;
 
         ENTRY;
-        error = presto_prep(dentry->d_parent, &cache, &fset);
-        if ( error  ) {
+        cache = presto_get_cache(dir);
+        if (cache == NULL) {
+                CERROR("InterMezzo BUG: no cache in presto_lookup "
+                       "(dir ino: %ld)!\n", dir->i_ino);
                 EXIT;
-                return ERR_PTR(error);
+                return NULL;
         }
         minor = presto_c2m(cache);
 
-        CDEBUG(D_CACHE, "dir ino: %ld, name: %*s\n",
-               dir->i_ino, dentry->d_name.len, dentry->d_name.name);
-        if ( ISLENTO(minor) )
-                CDEBUG(D_CACHE, "We are lento\n");
-
-        rc = dentry2id(dentry, &ino, &generation);
-        CDEBUG(D_CACHE, "dentry2id returned %d\n", rc);
-        if ( rc < 0 ) {
-                EXIT;
-                goto exit;
+        iops = filter_c2cdiops(cache->cache_filter);
+        if (!iops || !iops->lookup) {
+                CERROR("InterMezzo BUG: filesystem has no lookup\n");
+                EXIT;
+                return NULL;
         }
 
-        if ( rc == 0 ) {
-                de = presto_ilookup(dir, dentry, ino, generation);
-        } else {
-                struct inode_operations *iops = filter_c2cdiops(cache->cache_filter);
-                rc = 0;
-                /* recursively do a cache lookup in dir */
-                if (iops && iops->lookup) 
+
+        CDEBUG(D_CACHE, "dentry %p, dir ino: %ld, name: %*s, islento: %d\n",
+               dentry, dir->i_ino, dentry->d_name.len, dentry->d_name.name,
+               ISLENTO(minor));
+
+        if (dentry->d_fsdata)
+                CERROR("DD -- BAD dentry %p has data\n", dentry);
+                       
+        dentry->d_fsdata = NULL;
+#if 0
+        if (ext2_check_for_iopen(dir, dentry))
+                de = NULL;
+        else {
+#endif
+                if ( izo_dentry_is_ilookup(dentry, &ino, &generation) ) { 
+                        de = cache->cache_filter->o_trops->tr_ilookup
+                                (dir, dentry, ino, generation);
+                        is_ilookup = 1;
+                } else
                         de = iops->lookup(dir, dentry);
-                else {
-                        printk("filesystem has no lookup\n");
-                        EXIT;
-                        goto exit;
-                }
+#if 0
         }
-        /* XXX this needs some work to handle returning de if we get it */
-        filter_setup_dentry_ops(cache->cache_filter, 
+#endif
+
+        if ( IS_ERR(de) ) {
+                CERROR("dentry lookup error %ld\n", PTR_ERR(de));
+                return de;
+        }
+
+        /* some file systems have no read_inode: set methods here */
+        if (dentry->d_inode)
+                presto_set_ops(dentry->d_inode, cache->cache_filter);
+
+        filter_setup_dentry_ops(cache->cache_filter,
                                 dentry->d_op, &presto_dentry_ops);
         dentry->d_op = filter_c2udops(cache->cache_filter);
-        if ( IS_ERR(de) ) {
-                rc = PTR_ERR(de);
-                CDEBUG(D_CACHE, "dentry lookup error %d\n", rc);
-                EXIT;
-                goto exit;
+
+        /* In lookup we will tolerate EROFS return codes from presto_set_dd
+         * to placate NFS. EROFS indicates that a fileset was not found but
+         * we should still be able to continue through a lookup.
+         * Anything else is a hard error and must be returned to VFS. */
+        if (!is_ilookup)
+                rc = presto_set_dd(dentry);
+        if (rc && rc != -EROFS) {
+                CERROR("presto_set_dd failed (dir %ld, name %*s): %d\n",
+                       dir->i_ino, dentry->d_name.len, dentry->d_name.name, rc);
+                return ERR_PTR(rc);
         }
 
-        /* some file systems set the methods in lookup, not in
-           read_inode, as a result we should set the methods here 
-           as well as in read_inode 
-        */
-	if (dentry->d_inode) {
-		presto_set_ops(dentry->d_inode, cache->cache_filter); 
-	}
         EXIT;
-exit:
-        return ERR_PTR(rc);
+        return NULL;
+}
+
+static inline int presto_check_set_fsdata (struct dentry *de)
+{
+        if (presto_d2d(de) == NULL) {
+#ifdef PRESTO_NO_NFS
+                CERROR("dentry without fsdata: %p: %*s\n", de, 
+                                de->d_name.len, de->d_name.name);
+                BUG();
+#endif
+                return presto_set_dd (de);
+        }
+
+        return 0;
 }
 
 int presto_setattr(struct dentry *de, struct iattr *iattr)
@@ -273,6 +343,7 @@
         struct lento_vfs_context info = { 0, 0, 0 };
 
         ENTRY;
+
         error = presto_prep(de, &cache, &fset);
         if ( error ) {
                 EXIT;
@@ -295,7 +366,7 @@
 
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_setattr(fset, de, iattr, &info);
         presto_put_permit(de->d_inode);
         return error;
@@ -310,23 +381,32 @@
 
 int presto_prep(struct dentry *dentry, struct presto_cache **cache,
                 struct presto_file_set **fset)
-{
+{       
+        int rc;
+
+        /* NFS might pass us dentries which have not gone through lookup.
+         * Test and set d_fsdata for such dentries
+         */
+        rc = presto_check_set_fsdata (dentry);
+        if (rc) return rc;
+
         *fset = presto_fset(dentry);
-        if ( !*fset ) {
-                CDEBUG(D_INODE, "No file set for dentry at %p\n", dentry);
+        if ( *fset == NULL ) {
+                CERROR("No file set for dentry at %p: %*s\n", dentry,
+                                dentry->d_name.len, dentry->d_name.name);
                 return -EROFS;
         }
 
         *cache = (*fset)->fset_cache;
-        if ( !*cache ) {
-                printk("PRESTO: BAD, BAD: cannot find cache\n");
+        if ( *cache == NULL ) {
+                CERROR("PRESTO: BAD, BAD: cannot find cache\n");
                 return -EBADF;
         }
 
         CDEBUG(D_PIOCTL, "---> cache flags %x, fset flags %x\n",
               (*cache)->cache_flags, (*fset)->fset_flags);
         if( presto_is_read_only(*fset) ) {
-                printk("PRESTO: cannot modify read-only fileset, minor %d.\n",
+                CERROR("PRESTO: cannot modify read-only fileset, minor %d.\n",
                        presto_c2m(*cache));
                 return -EROFS;
         }
@@ -342,12 +422,18 @@
         struct presto_file_set *fset;
 
         ENTRY;
+        error = presto_check_set_fsdata(dentry);
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error ) {
                 EXIT;
                 return error;
         }
-	presto_unlock(dir);
+        presto_unlock(dir);
 
         /* Does blocking and non-blocking behavious need to be 
            checked for.  Without blocking (return 1), the permit
@@ -360,12 +446,13 @@
         }
 
         presto_relock_sem(dir);
-	parent = dentry->d_parent; 
+        parent = dentry->d_parent; 
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_create(fset, parent, dentry, mode, &info);
+
         presto_relock_other(dir);
         presto_put_permit(dir);
         EXIT;
@@ -388,6 +475,12 @@
                 return error;
         }
 
+        error = presto_check_set_fsdata(new_dentry);
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(new_dentry->d_parent, &new_cache, &new_fset);
         if ( error ) {
                 EXIT;
@@ -412,15 +505,25 @@
                 return -EROFS;
         }
 
-	presto_relock_sem(dir);
+        presto_relock_sem(dir);
         parent = new_dentry->d_parent;
 
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_link(fset, old_dentry, parent,
                                new_dentry, &info);
+
+#if 0
+        /* XXX for links this is not right */
+        if (cache->cache_filter->o_trops->tr_add_ilookup ) { 
+                struct dentry *d;
+                d = cache->cache_filter->o_trops->tr_add_ilookup
+                        (dir->i_sb->s_root, new_dentry, 1); 
+        }
+#endif 
+
         presto_relock_other(dir);
         presto_put_permit(dir);
         presto_put_permit(old_dentry->d_inode);
@@ -437,13 +540,19 @@
 
         ENTRY;
 
+        error = presto_check_set_fsdata(dentry);
+        if ( error  ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error  ) {
                 EXIT;
                 return error;
         }
 
-	presto_unlock(dir); 
+        presto_unlock(dir); 
 
         if ( presto_get_permit(dir) < 0 ) {
                 EXIT;
@@ -454,17 +563,18 @@
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
 
-	presto_relock_sem(dir); 
-	parent = dentry->d_parent;
+        presto_relock_sem(dir); 
+        parent = dentry->d_parent;
         error = presto_do_mkdir(fset, parent, dentry, mode, &info);
-	presto_relock_other(dir); 
+        presto_relock_other(dir); 
         presto_put_permit(dir);
         return error;
 }
 
 
+
 static int presto_symlink(struct inode *dir, struct dentry *dentry,
                    const char *name)
 {
@@ -475,6 +585,12 @@
         struct lento_vfs_context info;
 
         ENTRY;
+        error = presto_check_set_fsdata(dentry);
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error ) {
                 EXIT;
@@ -484,16 +600,16 @@
         presto_unlock(dir);
         if ( presto_get_permit(dir) < 0 ) {
                 EXIT;
-		presto_fulllock(dir);
+                presto_fulllock(dir);
                 return -EROFS;
         }
 
-	presto_relock_sem(dir);
+        presto_relock_sem(dir);
         parent = dentry->d_parent;
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_symlink(fset, parent, dentry, name, &info);
         presto_relock_other(dir);
         presto_put_permit(dir);
@@ -509,6 +625,12 @@
         struct lento_vfs_context info;
 
         ENTRY;
+        error = presto_check_set_fsdata(dentry);
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error  ) {
                 EXIT;
@@ -518,17 +640,19 @@
         presto_unlock(dir);
         if ( presto_get_permit(dir) < 0 ) {
                 EXIT;
-		presto_fulllock(dir);
+                presto_fulllock(dir);
                 return -EROFS;
         }
 
-	presto_relock_sem(dir);
+        presto_relock_sem(dir);
         parent = dentry->d_parent;
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
+
         error = presto_do_unlink(fset, parent, dentry, &info);
+
         presto_relock_other(dir);
         presto_put_permit(dir);
         return error;
@@ -544,6 +668,13 @@
 
         ENTRY;
         CDEBUG(D_FILE, "prepping presto\n");
+        error = presto_check_set_fsdata(dentry);
+
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error ) {
                 EXIT;
@@ -554,32 +685,32 @@
         /* We need to dget() before the dput in double_unlock, to ensure we
          * still have dentry references.  double_lock doesn't do dget for us.
          */
-	unlock_kernel();
-	if (d_unhashed(dentry))
-		d_rehash(dentry);
+        unlock_kernel();
+        if (d_unhashed(dentry))
+                d_rehash(dentry);
         double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);
         double_up(&dir->i_sem, &dentry->d_inode->i_sem);
 
         CDEBUG(D_FILE, "getting permit\n");
         if ( presto_get_permit(parent->d_inode) < 0 ) {
                 EXIT;
-		double_down(&dir->i_sem, &dentry->d_inode->i_sem);
-		double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
-		
-		lock_kernel();
+                double_down(&dir->i_sem, &dentry->d_inode->i_sem);
+                double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
+                
+                lock_kernel();
                 return -EROFS;
         }
         CDEBUG(D_FILE, "locking\n");
 
-	double_down(&dir->i_sem, &dentry->d_inode->i_sem);
-	parent = dentry->d_parent;
+        double_down(&dir->i_sem, &dentry->d_inode->i_sem);
+        parent = dentry->d_parent;
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_rmdir(fset, parent, dentry, &info);
         presto_put_permit(parent->d_inode);
-	lock_kernel();
+        lock_kernel();
         EXIT;
         return error;
 }
@@ -593,6 +724,12 @@
         struct lento_vfs_context info;
 
         ENTRY;
+        error = presto_check_set_fsdata(dentry);
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error  ) {
                 EXIT;
@@ -605,13 +742,13 @@
                 presto_fulllock(dir);
                 return -EROFS;
         }
-	
-	presto_relock_sem(dir);
+        
+        presto_relock_sem(dir);
         parent = dentry->d_parent;
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_mknod(fset, parent, dentry, mode, rdev, &info);
         presto_relock_other(dir);
         presto_put_permit(dir);
@@ -620,80 +757,81 @@
 }
 
 inline void presto_triple_unlock(struct inode *old_dir, struct inode *new_dir, 
-				 struct dentry *old_dentry, 
-				 struct dentry *new_dentry, int triple)
+                                 struct dentry *old_dentry, 
+                                 struct dentry *new_dentry, int triple)
 {
-	/* rename_dir case */ 
-	if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
-		if (triple) {			
-			triple_up(&old_dir->i_zombie,
-				  &new_dir->i_zombie,
-				  &new_dentry->d_inode->i_zombie);
-		} else { 
-			double_up(&old_dir->i_zombie,
-				  &new_dir->i_zombie);
-		}
-		up(&old_dir->i_sb->s_vfs_rename_sem);
-	} else /* this case is rename_other */
-		double_up(&old_dir->i_zombie, &new_dir->i_zombie);
-	/* done by do_rename */
-	unlock_kernel();
-	double_up(&old_dir->i_sem, &new_dir->i_sem);
+        /* rename_dir case */ 
+        if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
+                if (triple) {                   
+                        triple_up(&old_dir->i_zombie,
+                                  &new_dir->i_zombie,
+                                  &new_dentry->d_inode->i_zombie);
+                } else { 
+                        double_up(&old_dir->i_zombie,
+                                  &new_dir->i_zombie);
+                }
+                up(&old_dir->i_sb->s_vfs_rename_sem);
+        } else /* this case is rename_other */
+                double_up(&old_dir->i_zombie, &new_dir->i_zombie);
+        /* done by do_rename */
+        unlock_kernel();
+        double_up(&old_dir->i_sem, &new_dir->i_sem);
 }
 
 inline void presto_triple_fulllock(struct inode *old_dir, 
-				   struct inode *new_dir, 
-				   struct dentry *old_dentry, 
-				   struct dentry *new_dentry, int triple)
-{
-	/* done by do_rename */
-	double_down(&old_dir->i_sem, &new_dir->i_sem);
-	lock_kernel();
-	/* rename_dir case */ 
-	if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
-		down(&old_dir->i_sb->s_vfs_rename_sem);
-		if (triple) {			
-			triple_down(&old_dir->i_zombie,
-				  &new_dir->i_zombie,
-				  &new_dentry->d_inode->i_zombie);
-		} else { 
-			double_down(&old_dir->i_zombie,
-				  &new_dir->i_zombie);
-		}
-	} else /* this case is rename_other */
-		double_down(&old_dir->i_zombie, &new_dir->i_zombie);
+                                   struct inode *new_dir, 
+                                   struct dentry *old_dentry, 
+                                   struct dentry *new_dentry, int triple)
+{
+        /* done by do_rename */
+        double_down(&old_dir->i_sem, &new_dir->i_sem);
+        lock_kernel();
+        /* rename_dir case */ 
+        if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
+                down(&old_dir->i_sb->s_vfs_rename_sem);
+                if (triple) {                   
+                        triple_down(&old_dir->i_zombie,
+                                  &new_dir->i_zombie,
+                                  &new_dentry->d_inode->i_zombie);
+                } else { 
+                        double_down(&old_dir->i_zombie,
+                                  &new_dir->i_zombie);
+                }
+        } else /* this case is rename_other */
+                double_down(&old_dir->i_zombie, &new_dir->i_zombie);
 }
 
 inline void presto_triple_relock_sem(struct inode *old_dir, 
-				   struct inode *new_dir, 
-				   struct dentry *old_dentry, 
-				   struct dentry *new_dentry, int triple)
-{
-	/* done by do_rename */
-	double_down(&old_dir->i_sem, &new_dir->i_sem);
-	lock_kernel();
+                                   struct inode *new_dir, 
+                                   struct dentry *old_dentry, 
+                                   struct dentry *new_dentry, int triple)
+{
+        /* done by do_rename */
+        double_down(&old_dir->i_sem, &new_dir->i_sem);
+        lock_kernel();
 }
 
 inline void presto_triple_relock_other(struct inode *old_dir, 
-				   struct inode *new_dir, 
-				   struct dentry *old_dentry, 
-				   struct dentry *new_dentry, int triple)
-{
-	/* rename_dir case */ 
-	if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
-		down(&old_dir->i_sb->s_vfs_rename_sem);
-		if (triple) {			
-			triple_down(&old_dir->i_zombie,
-				  &new_dir->i_zombie,
-				  &new_dentry->d_inode->i_zombie);
-		} else { 
-			double_down(&old_dir->i_zombie,
-				  &new_dir->i_zombie);
-		}
-	} else /* this case is rename_other */
-		double_down(&old_dir->i_zombie, &new_dir->i_zombie);
+                                   struct inode *new_dir, 
+                                   struct dentry *old_dentry, 
+                                   struct dentry *new_dentry, int triple)
+{
+        /* rename_dir case */ 
+        if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
+                down(&old_dir->i_sb->s_vfs_rename_sem);
+                if (triple) {                   
+                        triple_down(&old_dir->i_zombie,
+                                  &new_dir->i_zombie,
+                                  &new_dentry->d_inode->i_zombie);
+                } else { 
+                        double_down(&old_dir->i_zombie,
+                                  &new_dir->i_zombie);
+                }
+        } else /* this case is rename_other */
+                double_down(&old_dir->i_zombie, &new_dir->i_zombie);
 }
 
+
 // XXX this can be optimized: renamtes across filesets only require 
 //     multiple KML records, but can locally be executed normally. 
 int presto_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -713,7 +851,6 @@
                 EXIT;
                 return error;
         }
-
         error = presto_prep(new_parent, &new_cache, &new_fset);
         if ( error ) {
                 EXIT;
@@ -732,27 +869,27 @@
         triple = (S_ISDIR(old_dentry->d_inode->i_mode) && new_dentry->d_inode)?
                 1:0;
 
-	presto_triple_unlock(old_dir, new_dir, old_dentry, new_dentry, triple); 
+        presto_triple_unlock(old_dir, new_dir, old_dentry, new_dentry, triple); 
 
         if ( presto_get_permit(old_dir) < 0 ) {
                 EXIT;
-		presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple); 
+                presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple); 
                 return -EROFS;
         }
         if ( presto_get_permit(new_dir) < 0 ) {
                 EXIT;
-		presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple); 
+                presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple); 
                 return -EROFS;
         }
 
-	presto_triple_relock_sem(old_dir, new_dir, old_dentry, new_dentry, triple); 
+        presto_triple_relock_sem(old_dir, new_dir, old_dentry, new_dentry, triple); 
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
-        error = presto_do_rename(fset, old_parent, old_dentry, new_parent,
-                                 new_dentry, &info);
-	presto_triple_relock_other(old_dir, new_dir, old_dentry, new_dentry, triple); 
+        info.flags |= LENTO_FL_IGNORE_TIME;
+        error = do_rename(fset, old_parent, old_dentry, new_parent,
+                          new_dentry, &info);
+        presto_triple_relock_other(old_dir, new_dir, old_dentry, new_dentry, triple); 
 
         presto_put_permit(new_dir);
         presto_put_permit(old_dir);
@@ -812,72 +949,467 @@
 }
 
 
-static int presto_dir_open(struct inode *inode, struct file *file)
+int presto_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
 {
-        int rc = 0;
-        struct dentry *de = file->f_dentry;
-        struct file_operations *fops;
-        struct presto_cache *cache;
-        struct presto_file_set *fset;
-        int minor;
-        int error; 
+        char buf[1024];
+        struct izo_ioctl_data *data = NULL;
+        struct presto_dentry_data *dd;
+        int rc;
 
         ENTRY;
 
-        error = presto_prep(file->f_dentry, &cache, &fset);
-        if ( error  ) {
+        /* Try the filesystem's ioctl first, and return if it succeeded. */
+        dd = presto_d2d(file->f_dentry); 
+        if (dd && dd->dd_fset) { 
+                int (*cache_ioctl)(struct inode *, struct file *, unsigned int, unsigned long ) = filter_c2cdfops(dd->dd_fset->fset_cache->cache_filter)->ioctl;
+                rc = -ENOTTY;
+                if (cache_ioctl)
+                        rc = cache_ioctl(inode, file, cmd, arg);
+                if (rc != -ENOTTY) {
+                        EXIT;
+                        return rc;
+                }
+        }
+
+        if (current->euid != 0 && current->euid != izo_authorized_uid) {
                 EXIT;
-                make_bad_inode(inode);
-                return error;
+                return -EPERM;
         }
-        minor = presto_c2m(cache);
 
-        CDEBUG(D_CACHE, "minor %d, DATA_OK: %d, ino: %ld\n",
-               minor, presto_chk(de, PRESTO_DATA), inode->i_ino);
+        memset(buf, 0, sizeof(buf));
+        
+        if (izo_ioctl_getdata(buf, buf + 1024, (void *)arg)) { 
+                CERROR("intermezzo ioctl: data error\n");
+                return -EINVAL;
+        }
+        data = (struct izo_ioctl_data *)buf;
+        
+        switch(cmd) {
+        case IZO_IOC_REINTKML: { 
+                int rc;
+                int cperr;
+                rc = kml_reint_rec(file, data);
+
+                EXIT;
+                cperr = copy_to_user((char *)arg, data, sizeof(*data));
+                if (cperr) { 
+                        CERROR("WARNING: cperr %d\n", cperr); 
+                        rc = -EFAULT;
+                }
+                return rc;
+        }
+
+        case IZO_IOC_GET_RCVD: {
+                struct izo_rcvd_rec rec;
+                struct presto_file_set *fset;
+                int rc;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                rc = izo_rcvd_get(&rec, fset, data->ioc_uuid);
+                if (rc < 0) {
+                        EXIT;
+                        return rc;
+                }
+
+                EXIT;
+                return copy_to_user((char *)arg, &rec, sizeof(rec))? -EFAULT : 0;
+        }
+
+        case IZO_IOC_REPSTATUS: {
+                __u64 client_kmlsize;
+                struct izo_rcvd_rec *lr_client;
+                struct izo_rcvd_rec rec;
+                struct presto_file_set *fset;
+                int minor;
+                int rc;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                client_kmlsize = data->ioc_kmlsize;
+                lr_client =  (struct izo_rcvd_rec *) data->ioc_pbuf1;
+
+                rc = izo_repstatus(fset, client_kmlsize, 
+                                       lr_client, &rec);
+                if (rc < 0) {
+                        EXIT;
+                        return rc;
+                }
+
+                EXIT;
+                return copy_to_user((char *)arg, &rec, sizeof(rec))? -EFAULT : 0;
+        }
+
+        case IZO_IOC_GET_CHANNEL: {
+                struct presto_file_set *fset;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                
+                data->ioc_dev = fset->fset_cache->cache_psdev->uc_minor;
+                CDEBUG(D_PSDEV, "CHANNEL %d\n", data->ioc_dev); 
+                EXIT;
+                return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
+        }
+
+        case IZO_IOC_SET_IOCTL_UID:
+                izo_authorized_uid = data->ioc_uid;
+                EXIT;
+                return 0;
+
+        case IZO_IOC_SET_PID:
+                rc = izo_psdev_setpid(data->ioc_dev);
+                EXIT;
+                return rc;
+
+        case IZO_IOC_SET_CHANNEL:
+                rc = izo_psdev_setchannel(file, data->ioc_dev);
+                EXIT;
+                return rc;
+
+        case IZO_IOC_GET_KML_SIZE: {
+                struct presto_file_set *fset;
+                __u64 kmlsize;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+
+                kmlsize = presto_kml_offset(fset) + fset->fset_kml_logical_off;
+
+                EXIT;
+                return copy_to_user((char *)arg, &kmlsize, sizeof(kmlsize))?-EFAULT : 0;
+        }
+
+        case IZO_IOC_PURGE_FILE_DATA: {
+                struct presto_file_set *fset;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+
+                rc = izo_purge_file(fset, data->ioc_inlbuf1);
+                EXIT;
+                return rc;
+        }
+
+        case IZO_IOC_GET_FILEID: {
+                rc = izo_get_fileid(file, data);
+                EXIT;
+                if (rc)
+                        return rc;
+                return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
+        }
+
+        case IZO_IOC_SET_FILEID: {
+                rc = izo_set_fileid(file, data);
+                EXIT;
+                if (rc)
+                        return rc;
+                return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT  : 0;
+        }
+
+        case IZO_IOC_ADJUST_LML: { 
+                struct lento_vfs_context *info; 
+                info = (struct lento_vfs_context *)data->ioc_inlbuf1;
+                rc = presto_adjust_lml(file, info); 
+                EXIT;
+                return rc;
+        }
+
+        case IZO_IOC_CONNECT: {
+                struct presto_file_set *fset;
+                int minor;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                rc = izo_upc_connect(minor, data->ioc_ino,
+                                     data->ioc_generation, data->ioc_uuid,
+                                     data->ioc_flags);
+                EXIT;
+                return rc;
+        }
+
+        case IZO_IOC_GO_FETCH_KML: {
+                struct presto_file_set *fset;
+                int minor;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                rc = izo_upc_go_fetch_kml(minor, fset->fset_name,
+                                          data->ioc_uuid, data->ioc_kmlsize);
+                EXIT;
+                return rc;
+        }
+
+        case IZO_IOC_REVOKE_PERMIT:
+                if (data->ioc_flags)
+                        rc = izo_revoke_permit(file->f_dentry, data->ioc_uuid);
+                else
+                        rc = izo_revoke_permit(file->f_dentry, NULL);
+                EXIT;
+                return rc;
+
+        case IZO_IOC_CLEAR_FSET:
+                rc = izo_clear_fsetroot(file->f_dentry);
+                EXIT;
+                return rc;
+
+        case IZO_IOC_CLEAR_ALL_FSETS: { 
+                struct presto_file_set *fset;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+
+                rc = izo_clear_all_fsetroots(fset->fset_cache);
+                EXIT;
+                return rc;
+        }
+
+        case IZO_IOC_SET_FSET:
+                /*
+                 * Mark this dentry as being a fileset root.
+                 */
+                rc = presto_set_fsetroot_from_ioc(file->f_dentry, 
+                                                  data->ioc_inlbuf1,
+                                                  data->ioc_flags);
+                EXIT;
+                return rc;
+
+
+        case IZO_IOC_MARK: {
+                int res = 0;  /* resulting flags - returned to user */
+                int error;
+
+                CDEBUG(D_DOWNCALL, "mark inode: %ld, and: %x, or: %x, what %d\n",
+                       file->f_dentry->d_inode->i_ino, data->ioc_and_flag,
+                       data->ioc_or_flag, data->ioc_mark_what);
+
+                switch (data->ioc_mark_what) {
+                case MARK_DENTRY:               
+                        error = izo_mark_dentry(file->f_dentry,
+                                                   data->ioc_and_flag,
+                                                   data->ioc_or_flag, &res);
+                        break;
+                case MARK_FSET:
+                        error = izo_mark_fset(file->f_dentry,
+                                                 data->ioc_and_flag,
+                                                 data->ioc_or_flag, &res);
+                        break;
+                case MARK_CACHE:
+                        error = izo_mark_cache(file->f_dentry,
+                                                  data->ioc_and_flag,
+                                                  data->ioc_or_flag, &res);
+                        break;
+                case MARK_GETFL: {
+                        int fflags, cflags;
+                        data->ioc_and_flag = 0xffffffff;
+                        data->ioc_or_flag = 0; 
+                        error = izo_mark_dentry(file->f_dentry,
+                                                   data->ioc_and_flag,
+                                                   data->ioc_or_flag, &res);
+                        if (error) 
+                                break;
+                        error = izo_mark_fset(file->f_dentry,
+                                                 data->ioc_and_flag,
+                                                 data->ioc_or_flag, &fflags);
+                        if (error) 
+                                break;
+                        error = izo_mark_cache(file->f_dentry,
+                                                  data->ioc_and_flag,
+                                                  data->ioc_or_flag,
+                                                  &cflags);
+
+                        if (error) 
+                                break;
+                        data->ioc_and_flag = fflags;
+                        data->ioc_or_flag = cflags;
+                        break;
+                }
+                default:
+                        error = -EINVAL;
+                }
+
+                if (error) { 
+                        EXIT;
+                        return error;
+                }
+                data->ioc_mark_what = res;
+                CDEBUG(D_DOWNCALL, "mark inode: %ld, and: %x, or: %x, what %x\n",
+                       file->f_dentry->d_inode->i_ino, data->ioc_and_flag,
+                       data->ioc_or_flag, data->ioc_mark_what);
+
+                EXIT;
+                return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
+        }
+#if 0
+        case IZO_IOC_CLIENT_MAKE_BRANCH: {
+                struct presto_file_set *fset;
+                int minor;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                rc = izo_upc_client_make_branch(minor, fset->fset_name,
+                                                data->ioc_inlbuf1,
+                                                data->ioc_inlbuf2);
+                EXIT;
+                return rc;
+        }
+#endif
+        case IZO_IOC_SERVER_MAKE_BRANCH: {
+                struct presto_file_set *fset;
+                int minor;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                izo_upc_server_make_branch(minor, data->ioc_inlbuf1);
+                EXIT;
+                return 0;
+        }
+        case IZO_IOC_SET_KMLSIZE: {
+                struct presto_file_set *fset;
+                int minor;
+                struct izo_rcvd_rec rec;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                rc = izo_upc_set_kmlsize(minor, fset->fset_name, data->ioc_uuid,
+                                         data->ioc_kmlsize);
+
+                if (rc != 0) {
+                        EXIT;
+                        return rc;
+                }
+
+                rc = izo_rcvd_get(&rec, fset, data->ioc_uuid);
+                if (rc == -EINVAL) {
+                        /* We don't know anything about this uuid yet; no
+                         * worries. */
+                        memset(&rec, 0, sizeof(rec));
+                } else if (rc <= 0) {
+                        CERROR("InterMezzo: error reading last_rcvd: %d\n", rc);
+                        EXIT;
+                        return rc;
+                }
+                rec.lr_remote_offset = data->ioc_kmlsize;
+                rc = izo_rcvd_write(fset, &rec);
+                if (rc <= 0) {
+                        CERROR("InterMezzo: error writing last_rcvd: %d\n", rc);
+                        EXIT;
+                        return rc;
+                }
+                EXIT;
+                return rc;
+        }
+        case IZO_IOC_BRANCH_UNDO: {
+                struct presto_file_set *fset;
+                int minor;
 
-        if ( ISLENTO(minor) )
-                goto cache;
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
 
-        if ( !presto_chk(de, PRESTO_DATA) ) {
-                CDEBUG(D_CACHE, "doing lento_opendir\n");
-                rc = presto_opendir_upcall(minor, file->f_dentry, fset->fset_mtpt, SYNCHRONOUS);
+                rc = izo_upc_branch_undo(minor, fset->fset_name,
+                                         data->ioc_inlbuf1);
+                EXIT;
+                return rc;
         }
+        case IZO_IOC_BRANCH_REDO: {
+                struct presto_file_set *fset;
+                int minor;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
 
-        if ( rc ) {
-                printk("presto_dir_open: DATA_OK: %d, ino: %ld, error %d\n",
-                       presto_chk(de, PRESTO_DATA), inode->i_ino, rc);
-                return rc ;
+                rc = izo_upc_branch_redo(minor, fset->fset_name,
+                                         data->ioc_inlbuf1);
+                EXIT;
+                return rc;
         }
 
- cache:
-        fops = filter_c2cdfops(cache->cache_filter);
-        if ( fops->open ) {
-                rc = fops->open(inode, file);
+        case TCGETS:
+                EXIT;
+                return -EINVAL;
+
+        default:
+                EXIT;
+                return -EINVAL;
+                
         }
-        presto_set(de, PRESTO_DATA | PRESTO_ATTR);
-        CDEBUG(D_CACHE, "returns %d, data %d, attr %d\n", rc,
-               presto_chk(de, PRESTO_DATA), presto_chk(de, PRESTO_ATTR));
+        EXIT;
         return 0;
 }
 
 struct file_operations presto_dir_fops = {
-        open: presto_dir_open
+        .ioctl =  presto_ioctl
 };
 
 struct inode_operations presto_dir_iops = {
-        create: presto_create,
-        lookup: presto_lookup,
-        link:   presto_link,
-        unlink: presto_unlink,
-        symlink:        presto_symlink,
-        mkdir:  presto_mkdir,
-        rmdir:  presto_rmdir,
-        mknod:  presto_mknod,
-        rename: presto_rename,
-        permission:     presto_permission,
-        setattr:        presto_setattr,
+        .create       = presto_create,
+        .lookup       = presto_lookup,
+        .link         = presto_link,
+        .unlink       = presto_unlink,
+        .symlink      = presto_symlink,
+        .mkdir        = presto_mkdir,
+        .rmdir        = presto_rmdir,
+        .mknod        = presto_mknod,
+        .rename       = presto_rename,
+        .permission   = presto_permission,
+        .setattr      = presto_setattr,
 #ifdef CONFIG_FS_EXT_ATTR
-	set_ext_attr:	presto_set_ext_attr,
+        .set_ext_attr = presto_set_ext_attr,
 #endif
-
 };
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/ext_attr.c linux-2.4.20/fs/intermezzo/ext_attr.c
--- linux-2.4.19/fs/intermezzo/ext_attr.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/ext_attr.c	2002-10-29 11:18:32.000000000 +0000
@@ -1,10 +1,25 @@
-/* 
- * Extended attribute handling for presto.
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ * 
+ *  Copyright (C) 2001 Tacit Networks, Inc.
+ *    Author: Shirish H. Phatak <shirish@tacitnetworks.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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.
  *
- * Copyright (C) 2001. All rights reserved.
- * Shirish H. Phatak
- * Tacit Networks, Inc.
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ * Extended attribute handling for presto.
  */
 
 #define __NO_VERSION__
@@ -32,10 +47,7 @@
 #include <linux/smp_lock.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
-
 
 #ifdef CONFIG_FS_EXT_ATTR
 #include <linux/ext_attr.h>
@@ -43,9 +55,6 @@
 extern inline void presto_debug_fail_blkdev(struct presto_file_set *fset,
                                             unsigned long value);
 
-extern int presto_prep(struct dentry *, struct presto_cache **,
-                       struct presto_file_set **);
-
 
 /* VFS interface */
 /* XXX! Fixme test for user defined attributes */
@@ -77,7 +86,7 @@
          * we do a reverse mapping from inode to the first dentry 
          */
         if (list_empty(&inode->i_dentry)) {
-                printk("No alias for inode %d\n", (int) inode->i_ino);
+                CERROR("No alias for inode %d\n", (int) inode->i_ino);
                 EXIT;
                 return -EINVAL;
         }
@@ -101,12 +110,13 @@
             * (works for ext3)
             */
             if (flags & EXT_ATTR_FLAG_USER) {
-                PRESTO_ALLOC(buf, char *, buffer_len);
+                PRESTO_ALLOC(buf, buffer_len);
                 if (!buf) {
-                        printk("InterMezzo: out of memory!!!\n");
+                        CERROR("InterMezzo: out of memory!!!\n");
                         return -ENOMEM;
                 }
-                if (copy_from_user(buf, buffer, buffer_len))
+                error = copy_from_user(buf, buffer, buffer_len);
+                if (error) 
                         return -EFAULT;
             } else 
                 buf = buffer;
@@ -174,7 +184,7 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto exit_dentry;
         }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/file.c linux-2.4.20/fs/intermezzo/file.c
--- linux-2.4.19/fs/intermezzo/file.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/file.c	2002-10-29 11:18:32.000000000 +0000
@@ -1,22 +1,34 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
  *  Copyright (C) 2000 TurboLinux, Inc.
  *  Copyright (C) 2000 Los Alamos National Laboratory.
- *  Copyright (C) 2000 Tacitus Systems
+ *  Copyright (C) 2000, 2001 Tacit Networks, Inc.
  *  Copyright (C) 2000 Peter J. Braam
  *  Copyright (C) 2001 Mountain View Data, Inc. 
  *  Copyright (C) 2001 Cluster File Systems, 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 file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ *  This file manages file I/O
+ * 
  */
 
-
 #include <stdarg.h>
 
 #include <asm/bitops.h>
@@ -39,71 +51,126 @@
 #include <linux/module.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_kml.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 #include <linux/fsfilter.h>
 /*
  * these are initialized in super.c
  */
 extern int presto_permission(struct inode *inode, int mask);
-extern int presto_opendir_upcall(int minor, struct dentry *de, int async);
-
-extern int presto_prep(struct dentry *, struct presto_cache **,
-                       struct presto_file_set **);
 
 
-#if 0
 static int presto_open_upcall(int minor, struct dentry *de)
 {
         int rc;
         char *path, *buffer;
+        struct presto_file_set *fset;
         int pathlen;
+        struct lento_vfs_context info;
+        struct presto_dentry_data *dd = presto_d2d(de);
 
-        PRESTO_ALLOC(buffer, char *, PAGE_SIZE);
+        PRESTO_ALLOC(buffer, PAGE_SIZE);
         if ( !buffer ) {
-                printk("PRESTO: out of memory!\n");
-                return ENOMEM;
+                CERROR("PRESTO: out of memory!\n");
+                return -ENOMEM;
         }
-        path = presto_path(de, buffer, PAGE_SIZE);
+        fset = presto_fset(de);
+        path = presto_path(de, fset->fset_dentry, buffer, PAGE_SIZE);
         pathlen = MYPATHLEN(buffer, path);
-        rc = lento_open(minor, pathlen, path);
+        
+        CDEBUG(D_FILE, "de %p, dd %p\n", de, dd);
+        if (dd->remote_ino == 0) {
+                rc = presto_get_fileid(minor, fset, de);
+        }
+        memset (&info, 0, sizeof(info));
+        if (dd->remote_ino > 0) {
+                info.remote_ino = dd->remote_ino;
+                info.remote_generation = dd->remote_generation;
+        } else
+                CERROR("get_fileid failed %d, ino: %Lx, fetching by name\n", rc,
+                       dd->remote_ino);
+
+        rc = izo_upc_open(minor, pathlen, path, fset->fset_name, &info);
         PRESTO_FREE(buffer, PAGE_SIZE);
         return rc;
 }
-#endif
 
+static inline int open_check_dod(struct file *file,
+                                 struct presto_file_set *fset)
+{
+        int gen, is_iopen = 0, minor;
+        struct presto_cache *cache = fset->fset_cache;
+        ino_t inum;
+
+        minor = presto_c2m(cache);
+
+        if ( ISLENTO(minor) ) {
+                CDEBUG(D_CACHE, "is lento, not doing DOD.\n");
+                return 0;
+        }
+
+        /* Files are only ever opened by inode during backfetches, when by
+         * definition we have the authoritative copy of the data.  No DOD. */
+        is_iopen = izo_dentry_is_ilookup(file->f_dentry, &inum, &gen);
+
+        if (is_iopen) {
+                CDEBUG(D_CACHE, "doing iopen, not doing DOD.\n");
+                return 0;
+        }
+
+        if (!(fset->fset_flags & FSET_DATA_ON_DEMAND)) {
+                CDEBUG(D_CACHE, "fileset not on demand.\n");
+                return 0;
+        }
+                
+        if (file->f_flags & O_TRUNC) {
+                CDEBUG(D_CACHE, "fileset dod: O_TRUNC.\n");
+                return 0;
+        }
+                
+        if (presto_chk(file->f_dentry, PRESTO_DONT_JOURNAL)) {
+                CDEBUG(D_CACHE, "file under .intermezzo, not doing DOD\n");
+                return 0;
+        }
+
+        if (presto_chk(file->f_dentry, PRESTO_DATA)) {
+                CDEBUG(D_CACHE, "PRESTO_DATA is set, not doing DOD.\n");
+                return 0;
+        }
+
+        if (cache->cache_filter->o_trops->tr_all_data(file->f_dentry->d_inode)) {
+                CDEBUG(D_CACHE, "file not sparse, not doing DOD.\n");
+                return 0;
+        }
+
+        return 1;
+}
 
 static int presto_file_open(struct inode *inode, struct file *file)
 {
         int rc = 0;
         struct file_operations *fops;
         struct presto_cache *cache;
+        struct presto_file_set *fset;
         struct presto_file_data *fdata;
         int writable = (file->f_flags & (O_RDWR | O_WRONLY));
-        int minor;
-        int i;
+        int minor, i;
 
         ENTRY;
 
-        cache = presto_get_cache(inode);
-        if ( !cache ) {
-                printk("PRESTO: BAD, BAD: cannot find cache\n");
+        if (presto_prep(file->f_dentry, &cache, &fset) < 0) {
                 EXIT;
                 return -EBADF;
         }
 
         minor = presto_c2m(cache);
 
-        CDEBUG(D_CACHE, "presto_file_open: DATA_OK: %d, ino: %ld\n",
-               presto_chk(file->f_dentry, PRESTO_DATA), inode->i_ino);
-
-        if ( ISLENTO(minor) )
-                goto cache;
-
-        if ( file->f_flags & O_RDWR || file->f_flags & O_WRONLY) {
-                CDEBUG(D_CACHE, "presto_file_open: calling presto_get_permit\n");
-                /* lock needed to protect permit_count manipulations -SHP */
+        CDEBUG(D_CACHE, "DATA_OK: %d, ino: %ld, islento: %d\n",
+               presto_chk(file->f_dentry, PRESTO_DATA), inode->i_ino,
+               ISLENTO(minor));
+
+        if ( !ISLENTO(minor) && (file->f_flags & O_RDWR ||
+                                 file->f_flags & O_WRONLY)) {
+                CDEBUG(D_CACHE, "calling presto_get_permit\n");
                 if ( presto_get_permit(inode) < 0 ) {
                         EXIT;
                         return -EROFS;
@@ -111,71 +178,97 @@
                 presto_put_permit(inode);
         }
 
-        /* XXX name space synchronization here for data/streaming on demand?*/
-        /* XXX Lento can make us wait here for backfetches to complete */
-#if 0
-        if ( !presto_chk(file->f_dentry, PRESTO_DATA) ||
-             !presto_has_all_data(file->f_dentry->d_inode) ) {
-                CDEBUG(D_CACHE, "presto_file_open: presto_open_upcall\n");
+        if (open_check_dod(file, fset)) {
+                CDEBUG(D_CACHE, "presto_open_upcall\n");
+                CDEBUG(D_CACHE, "dentry: %p setting DATA, ATTR\n", file->f_dentry);
+                presto_set(file->f_dentry, PRESTO_ATTR | PRESTO_DATA);
                 rc = presto_open_upcall(minor, file->f_dentry);
+                if (rc) {
+                        EXIT;
+                        CERROR("%s: returning error %d\n", __FUNCTION__, rc);
+                        return rc;
+                }
+
+        }
+
+        /* file was truncated upon open: do not refetch */
+        if (file->f_flags & O_TRUNC) { 
+                CDEBUG(D_CACHE, "setting DATA, ATTR\n");
+                presto_set(file->f_dentry, PRESTO_ATTR | PRESTO_DATA);
         }
 
-#endif
-        rc = 0;
- cache:
         fops = filter_c2cffops(cache->cache_filter);
         if ( fops->open ) {
-                CDEBUG(D_CACHE, "presto_file_open: calling fs open\n");
+                CDEBUG(D_CACHE, "calling fs open\n");
                 rc = fops->open(inode, file);
-        }
-        if (rc) {
-            EXIT;
-            return rc;
-        }
 
-        CDEBUG(D_CACHE, "presto_file_open: setting DATA, ATTR\n");
-        if( ISLENTO(minor) )
-            presto_set(file->f_dentry, PRESTO_ATTR );
-        else
-                presto_set(file->f_dentry, PRESTO_ATTR | PRESTO_DATA);
+                if (rc) {
+                        EXIT;
+                        return rc;
+                }
+        }
 
-        if (writable) { 
-                PRESTO_ALLOC(fdata, struct presto_file_data *, sizeof(*fdata));
+        if (writable) {
+                PRESTO_ALLOC(fdata, sizeof(*fdata));
                 if (!fdata) {
                         EXIT;
                         return -ENOMEM;
                 }
-                /* we believe that on open the kernel lock
-                   assures that only one process will do this allocation */ 
+                /* LOCK: XXX check that the kernel lock protects this alloc */
                 fdata->fd_do_lml = 0;
+                fdata->fd_bytes_written = 0;
                 fdata->fd_fsuid = current->fsuid;
                 fdata->fd_fsgid = current->fsgid;
                 fdata->fd_mode = file->f_dentry->d_inode->i_mode;
+                fdata->fd_uid = file->f_dentry->d_inode->i_uid;
+                fdata->fd_gid = file->f_dentry->d_inode->i_gid;
                 fdata->fd_ngroups = current->ngroups;
-                for (i=0 ; i<current->ngroups ; i++)
-                        fdata->fd_groups[i] = current->groups[i]; 
-                fdata->fd_bytes_written = 0; /*when open,written data is zero*/ 
-                file->private_data = fdata; 
+                for (i=0 ; i < current->ngroups ; i++)
+                        fdata->fd_groups[i] = current->groups[i];
+                if (!ISLENTO(minor)) 
+                        fdata->fd_info.flags = LENTO_FL_KML; 
+                else { 
+                        /* this is for the case of DOD, 
+                           reint_close will adjust flags if needed */
+                        fdata->fd_info.flags = 0;
+                }
+
+                presto_getversion(&fdata->fd_version, inode);
+                file->private_data = fdata;
         } else {
                 file->private_data = NULL;
         }
 
+        EXIT;
         return 0;
 }
 
+int presto_adjust_lml(struct file *file, struct lento_vfs_context *info)
+{
+        struct presto_file_data *fdata = 
+                (struct presto_file_data *) file->private_data;
+
+        if (!fdata) { 
+                EXIT;
+                return -EINVAL;
+        }
+                
+        memcpy(&fdata->fd_info, info, sizeof(*info));
+        EXIT;
+        return 0; 
+}
+
+
 static int presto_file_release(struct inode *inode, struct file *file)
 {
-        struct rec_info rec;
         int rc;
-        int writable = (file->f_flags & (O_RDWR | O_WRONLY));
         struct file_operations *fops;
         struct presto_cache *cache;
         struct presto_file_set *fset;
-        void *handle; 
         struct presto_file_data *fdata = 
                 (struct presto_file_data *)file->private_data;
-
         ENTRY;
+
         rc = presto_prep(file->f_dentry, &cache, &fset);
         if ( rc ) {
                 EXIT;
@@ -183,96 +276,40 @@
         }
 
         fops = filter_c2cffops(cache->cache_filter);
-        rc = fops->release(inode, file);
+        if (fops && fops->release)
+                rc = fops->release(inode, file);
 
-        CDEBUG(D_CACHE, "islento = %d (minor %d), writable = %d, rc %d, data %p\n",
+        CDEBUG(D_CACHE, "islento = %d (minor %d), rc %d, data %p\n",
                ISLENTO(cache->cache_psdev->uc_minor), 
-               cache->cache_psdev->uc_minor, 
-               writable, rc, fdata);
-
-        if (fdata && fdata->fd_do_lml) { 
-                CDEBUG(D_CACHE, "LML at %lld\n", fdata->fd_lml_offset); 
-        }
-
-        /* don't journal close if file couldn't have been written to */
-        /*    if (!ISLENTO(cache->cache_prestominor) && !rc && writable) {*/
-        if (fdata && fdata->fd_do_lml && 
-            !rc && writable && (! ISLENTO(cache->cache_psdev->uc_minor))) {
-                struct presto_version new_ver;
-
-                presto_getversion(&new_ver, inode);
+               cache->cache_psdev->uc_minor, rc, fdata);
 
+        /* this file was modified: ignore close errors, write KML */
+        if (fdata && fdata->fd_do_lml) {
                 /* XXX: remove when lento gets file granularity cd */
-                /* Lock needed to protect permit_count manipulations -SHP */
                 if ( presto_get_permit(inode) < 0 ) {
                         EXIT;
                         return -EROFS;
                 }
-                CDEBUG(D_CACHE, "presto_file_release: writing journal\n");
         
-                rc = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
-                if (rc) { 
-                        presto_put_permit(inode); 
-                        EXIT; 
-                        return rc;
-                }
-                handle = presto_trans_start(fset, file->f_dentry->d_inode, 
-                                            PRESTO_OP_RELEASE);
-                if ( IS_ERR(handle) ) {
-                        printk("presto_release: no space for transaction\n");
-                        presto_put_permit(inode);
-                        return -ENOSPC;
-                }
-                rc = presto_journal_close(&rec, fset, file, file->f_dentry, 
-                                          &new_ver);
-                if (rc) { 
-                        printk("presto_close: cannot journal close\n");
-                        /* XXX oops here to get this bug */ 
-                        *(int *)0 = 1;
-                        presto_put_permit(inode);
-                        return -ENOSPC;
-                }
-                presto_trans_commit(fset, handle); 
-
-                /* cancel the LML record */ 
-                handle = presto_trans_start
-                        (fset, inode, PRESTO_OP_WRITE);
-                if ( IS_ERR(handle) ) {
-                        printk("presto_release: no space for clear\n");
-                        presto_put_permit(inode);
-                        return -ENOSPC;
-                }
-                rc = presto_clear_lml_close(fset,
-                                            fdata->fd_lml_offset); 
-                if (rc < 0 ) { 
-                        /* XXX oops here to get this bug */ 
-                        *(int *)0 = 1;
-                        presto_put_permit(inode);
-                        printk("presto_close: cannot journal close\n");
-                        return -ENOSPC;
-                }
-                presto_trans_commit(fset, handle); 
-                presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-
-                presto_truncate_lml(fset);
-
+                fdata->fd_info.updated_time = file->f_dentry->d_inode->i_mtime;
+                rc = presto_do_close(fset, file); 
                 presto_put_permit(inode);
         }
 
         if (!rc && fdata) {
                 PRESTO_FREE(fdata, sizeof(*fdata));
+                file->private_data = NULL; 
         }
-        file->private_data = NULL; 
         
         EXIT;
         return rc;
 }
 
-
-
-static void presto_apply_write_policy(struct file *file, struct presto_file_set *fset, loff_t res)
+static void presto_apply_write_policy(struct file *file,
+                                      struct presto_file_set *fset, loff_t res)
 {
-        struct presto_file_data *fdata = (struct presto_file_data *)file->private_data;
+        struct presto_file_data *fdata =
+                (struct presto_file_data *)file->private_data;
         struct presto_cache *cache = fset->fset_cache;
         struct presto_version new_file_ver;
         int error;
@@ -285,40 +322,44 @@
          journaling in a thread, add more options etc.)
         */ 
  
-         if (  (fset->fset_flags & FSET_JCLOSE_ON_WRITE)
-                 && (!ISLENTO(cache->cache_psdev->uc_minor)))  {
-                 fdata->fd_bytes_written += res;
+        if ((fset->fset_flags & FSET_JCLOSE_ON_WRITE) &&
+            (!ISLENTO(cache->cache_psdev->uc_minor))) {
+                fdata->fd_bytes_written += res;
  
-                 if (fdata->fd_bytes_written >= fset->fset_file_maxio) {
-                         presto_getversion(&new_file_ver, file->f_dentry->d_inode);
+                if (fdata->fd_bytes_written >= fset->fset_file_maxio) {
+                        presto_getversion(&new_file_ver,
+                                          file->f_dentry->d_inode);
                         /* This is really heavy weight and should be fixed
                            ASAP. At most we should be recording the number
                            of bytes written and not locking the kernel, 
                            wait for permits, etc, on the write path. SHP
                         */
                         lock_kernel();
-                         if ( presto_get_permit(file->f_dentry->d_inode) < 0 ) {
-                                 EXIT;
-                                 /* we must be disconnected, not to worry */
+                        if ( presto_get_permit(file->f_dentry->d_inode) < 0 ) {
+                                EXIT;
+                                /* we must be disconnected, not to worry */
+                                unlock_kernel();
                                 return; 
-                         }
-                         error = presto_journal_close
-                                (&rec, fset, file, file->f_dentry, &new_file_ver);
-                         presto_put_permit(file->f_dentry->d_inode);
+                        }
+                        error = presto_journal_close(&rec, fset, file,
+                                                     file->f_dentry,
+                                                     &fdata->fd_version,
+                                                     &new_file_ver);
+                        presto_put_permit(file->f_dentry->d_inode);
                         unlock_kernel();
-                         if ( error ) {
-                                 printk("presto_close: cannot journal close\n");
-                                 /* XXX these errors are really bad */
+                        if ( error ) {
+                                CERROR("presto_close: cannot journal close\n");
+                                /* XXX these errors are really bad */
                                 /* panic(); */
-                                 return;
-                         }
-                             fdata->fd_bytes_written = 0;
-                     } 
+                                return;
+                        }
+                        fdata->fd_bytes_written = 0;
+                }
         }
 }
 
-static ssize_t presto_file_write(struct file *file, const char *buf, size_t size, 
-                          loff_t *off)
+static ssize_t presto_file_write(struct file *file, const char *buf,
+                                 size_t size, loff_t *off)
 {
         struct rec_info rec;
         int error;
@@ -344,83 +385,155 @@
                 << file->f_dentry->d_inode->i_sb->s_blocksize_bits);
 
         error = presto_reserve_space(fset->fset_cache, res_size); 
-        CDEBUG(D_INODE, "Reserved %Ld for %Zd\n", res_size, size); 
+        CDEBUG(D_INODE, "Reserved %Ld for %d\n", res_size, size); 
         if ( error ) { 
                 EXIT;
                 return -ENOSPC;
         }
 
-        /* XXX lock something here */
-        CDEBUG(D_INODE, "islento %d, minor: %d\n", ISLENTO(cache->cache_psdev->uc_minor),
+        CDEBUG(D_INODE, "islento %d, minor: %d\n", 
+               ISLENTO(cache->cache_psdev->uc_minor),
                cache->cache_psdev->uc_minor); 
+
+        /* 
+         *  XXX this lock should become a per inode lock when 
+         *  Vinny's changes are in; we could just use i_sem.
+         */
         read_lock(&fset->fset_lml.fd_lock); 
         fdata = (struct presto_file_data *)file->private_data;
-        do_lml_here = (!ISLENTO(cache->cache_psdev->uc_minor)) &&
-                size && (fdata->fd_do_lml == 0);
+        do_lml_here = size && (fdata->fd_do_lml == 0) &&
+                !presto_chk(file->f_dentry, PRESTO_DONT_JOURNAL);
 
         if (do_lml_here)
                 fdata->fd_do_lml = 1;
         read_unlock(&fset->fset_lml.fd_lock); 
 
-        /* XXX we have two choices:
-           - we do the transaction for the LML record BEFORE any write
-           transaction starts - that has the benefit that no other
-           short write can complete without the record being there. 
-           The disadvantage is that even if no write happens we get 
-           the LML record. 
-           - we bundle the transaction with this write.  In that case
-           we may not have an LML record is a short write goes through
-           before this one (can that actually happen?).
+        /* XXX 
+           There might be a bug here.  We need to make 
+           absolutely sure that the ext3_file_write commits 
+           after our transaction that writes the LML record.
+           Nesting the file write helps if new blocks are allocated. 
         */
         res = 0;
         if (do_lml_here) {
+                struct presto_version file_version;
                 /* handle different space reqs from file system below! */
                 handle = presto_trans_start(fset, file->f_dentry->d_inode, 
-                                            PRESTO_OP_WRITE);
+                                            KML_OPCODE_WRITE);
                 if ( IS_ERR(handle) ) {
                         presto_release_space(fset->fset_cache, res_size); 
-                        printk("presto_write: no space for transaction\n");
+                        CERROR("presto_write: no space for transaction\n");
                         return -ENOSPC;
                 }
-                res = presto_journal_write(&rec, fset, file);
+
+                presto_getversion(&file_version, file->f_dentry->d_inode); 
+                res = presto_write_lml_close(&rec, fset, file, 
+                                             fdata->fd_info.remote_ino, 
+                                             fdata->fd_info.remote_generation, 
+                                             &fdata->fd_info.remote_version, 
+                                             &file_version);
                 fdata->fd_lml_offset = rec.offset;
                 if ( res ) {
-                        /* XXX oops here to get this bug */ 
-                        /* *(int *)0 = 1; */
+                        CERROR("intermezzo: PANIC failed to write LML\n");
+                        *(int *)0 = 1;
                         EXIT;
                         goto exit_write;
                 }
-                
                 presto_trans_commit(fset, handle);
         }
 
         fops = filter_c2cffops(cache->cache_filter);
         res = fops->write(file, buf, size, off);
         if ( res != size ) {
-                CDEBUG(D_FILE, "file write returns short write: size %Zd, res %Zd\n", size, res); 
+                CDEBUG(D_FILE, "file write returns short write: size %d, res %d\n", size, res); 
         }
 
         if ( (res > 0) && fdata ) 
                  presto_apply_write_policy(file, fset, res);
-  
+
  exit_write:
         presto_release_space(fset->fset_cache, res_size); 
         return res;
 }
 
 struct file_operations presto_file_fops = {
-        write:   presto_file_write,
-        open:    presto_file_open,
-        release: presto_file_release
+        .write   = presto_file_write,
+        .open    = presto_file_open,
+        .release = presto_file_release,
+        .ioctl   = presto_ioctl
 };
 
 struct inode_operations presto_file_iops = {
-        permission: presto_permission,
-	setattr: presto_setattr,
+        .permission   = presto_permission,
+        .setattr      = presto_setattr,
 #ifdef CONFIG_FS_EXT_ATTR
-	set_ext_attr: presto_set_ext_attr,
+        .set_ext_attr = presto_set_ext_attr,
 #endif
 };
 
+/* FIXME: I bet we want to add a lock here and in presto_file_open. */
+int izo_purge_file(struct presto_file_set *fset, char *file)
+{
+#if 0
+        void *handle = NULL;
+        char *path = NULL;
+        struct nameidata nd;
+        struct dentry *dentry;
+        int rc = 0, len;
+        loff_t oldsize;
+
+        /* FIXME: not mtpt it's gone */
+        len = strlen(fset->fset_cache->cache_mtpt) + strlen(file) + 1;
+        PRESTO_ALLOC(path, len + 1);
+        if (path == NULL)
+                return -1;
+
+        sprintf(path, "%s/%s", fset->fset_cache->cache_mtpt, file);
+        rc = izo_lookup_file(fset, path, &nd);
+        if (rc)
+                goto error;
+        dentry = nd.dentry;
+
+        /* FIXME: take a lock here */
+
+        if (dentry->d_inode->i_atime > CURRENT_TIME - 5) {
+                /* We lost the race; this file was accessed while we were doing
+                 * ioctls and lookups and whatnot. */
+                rc = -EBUSY;
+                goto error_unlock;
+        }
+
+        /* FIXME: Check if this file is open. */
+
+        handle = presto_trans_start(fset, dentry->d_inode, KML_OPCODE_TRUNC);
+        if (IS_ERR(handle)) {
+                rc = -ENOMEM;
+                goto error_unlock;
+        }
+
+        /* FIXME: Write LML record */
+
+        oldsize = dentry->d_inode->i_size;
+        rc = izo_do_truncate(fset, dentry, 0, oldsize);
+        if (rc != 0)
+                goto error_clear;
+        rc = izo_do_truncate(fset, dentry, oldsize, 0);
+        if (rc != 0)
+                goto error_clear;
 
+ error_clear:
+        /* FIXME: clear LML record */
 
+ error_unlock:
+        /* FIXME: release the lock here */
+
+ error:
+        if (handle != NULL && !IS_ERR(handle))
+                presto_trans_commit(fset, handle);
+        if (path != NULL)
+                PRESTO_FREE(path, len + 1);
+        return rc;
+#else
+        return 0;
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/fileset.c linux-2.4.20/fs/intermezzo/fileset.c
--- linux-2.4.19/fs/intermezzo/fileset.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/fileset.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,675 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Managing filesets
+ *
+ */
+
+#define __NO_VERSION__
+#include <stdarg.h>
+
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <linux/intermezzo_fs.h>
+#include <linux/intermezzo_psdev.h>
+
+static inline struct presto_file_set *presto_dentry2fset(struct dentry *dentry)
+{
+        if (presto_d2d(dentry) == NULL) {
+                EXIT;
+                return NULL;
+        }
+        return presto_d2d(dentry)->dd_fset;
+}
+
+/* find the fileset dentry for this dentry */
+struct presto_file_set *presto_fset(struct dentry *de)
+{
+        struct dentry *fsde;
+        ENTRY;
+        if ( !de->d_inode ) {
+                /* FIXME: is this ok to be NULL? */
+                CDEBUG(D_INODE,"presto_fset: warning %*s has NULL inode.\n",
+                de->d_name.len, de->d_name.name);
+        }
+        for (fsde = de;; fsde = fsde->d_parent) {
+                if ( presto_dentry2fset(fsde) ) {
+                        EXIT;
+                        return presto_dentry2fset(fsde);
+                }
+                if (fsde->d_parent == fsde)
+                        break;
+        }
+        EXIT;
+        return NULL;
+}
+
+int presto_get_lastrecno(char *path, off_t *recno)
+{
+        struct nameidata nd; 
+        struct presto_file_set *fset;
+        struct dentry *dentry;
+        int error;
+        ENTRY;
+
+        error = presto_walk(path, &nd);
+        if (error) {
+                EXIT;
+                return error;
+        }
+
+        dentry = nd.dentry;
+
+        error = -ENXIO;
+        if ( !presto_ispresto(dentry->d_inode) ) {
+                EXIT;
+                goto kml_out;
+        }
+
+        error = -EINVAL;
+        if ( ! presto_dentry2fset(dentry)) {
+                EXIT;
+                goto kml_out;
+        }
+
+        fset = presto_dentry2fset(dentry);
+        if (!fset) {
+                EXIT;
+                goto kml_out;
+        }
+        error = 0;
+        *recno = fset->fset_kml.fd_recno;
+
+ kml_out:
+        path_release(&nd);
+        return error;
+}
+
+static char * _izo_make_path(char *fsetname, char *name)
+{
+        char *path = NULL;
+        int len;
+
+        len = strlen("/.intermezzo/") + strlen(fsetname) 
+                + 1 + strlen(name) + 1;
+
+        PRESTO_ALLOC(path, len);
+        if (path == NULL)
+                return NULL;
+
+        sprintf(path, "/.intermezzo/%s/%s", fsetname, name);
+
+        return path;
+}
+
+char * izo_make_path(struct presto_file_set *fset, char *name)
+{
+        return _izo_make_path(fset->fset_name, name);
+}
+
+static struct file *_izo_fset_open(char *fsetname, char *name, int flags, int mode) 
+{
+        char *path;
+        struct file *f;
+        int error;
+        ENTRY;
+
+        path = _izo_make_path(fsetname, name);
+        if (path == NULL) {
+                EXIT;
+                return ERR_PTR(-ENOMEM);
+        }
+
+        CDEBUG(D_INODE, "opening file %s\n", path);
+        f = filp_open(path, flags, mode);
+        error = PTR_ERR(f);
+        if (IS_ERR(f)) {
+                CDEBUG(D_INODE, "Error %d\n", error);
+        }
+
+        PRESTO_FREE(path, strlen(path));
+
+        EXIT;
+        return f;
+
+}
+
+struct file *izo_fset_open(struct presto_file_set *fset, char *name, int flags, int mode) 
+{
+        return _izo_fset_open(fset->fset_name, name, flags, mode);
+}
+
+
+
+/*
+ *  note: this routine "pins" a dentry for a fileset root
+ */
+int presto_set_fsetroot(struct dentry *ioctl_dentry, char *fsetname,
+                        unsigned int flags)
+{
+        struct presto_file_set *fset = NULL;
+        struct presto_cache *cache;
+        int error;
+        struct file  *fset_root;
+        struct dentry *dentry;
+
+        ENTRY;
+
+        fset_root = _izo_fset_open(fsetname, "ROOT",  O_RDONLY, 000);
+        if (IS_ERR(fset_root)) {
+                CERROR("Can't open %s/ROOT\n", fsetname);
+                EXIT;
+                error = PTR_ERR(fset_root);
+                goto out;
+        }
+        dentry = dget(fset_root->f_dentry);
+        filp_close(fset_root, NULL);
+
+        dentry->d_inode->i_op = ioctl_dentry->d_inode->i_op;
+        dentry->d_inode->i_fop = ioctl_dentry->d_inode->i_fop;
+        dentry->d_op = ioctl_dentry->d_op;
+        fset = presto_dentry2fset(dentry);
+        if (fset && (fset->fset_dentry == dentry) ) { 
+                CERROR("Fsetroot already set (inode %ld)\n",
+                       dentry->d_inode->i_ino);
+                /* XXX: ignore because clear_fsetroot is broken  */
+#if 0
+                dput(dentry);
+                EXIT;
+                error = -EEXIST;
+                goto out;
+#endif
+        }
+
+        cache = presto_get_cache(dentry->d_inode);
+        if (!cache) { 
+                CERROR("No cache found for inode %ld\n",
+                       dentry->d_inode->i_ino);
+                EXIT;
+                error = -ENODEV;
+                goto out_free;
+        }
+
+        PRESTO_ALLOC(fset, sizeof(*fset));
+        if ( !fset ) {
+                CERROR("No memory allocating fset for %s\n", fsetname);
+                EXIT;
+                error = -ENOMEM;
+                goto out_free;
+        }
+        CDEBUG(D_INODE, "fset at %p\n", fset);
+
+        CDEBUG(D_INODE, "InterMezzo: fsetroot: inode %ld, fileset name %s\n",
+               dentry->d_inode->i_ino, fsetname);
+
+        fset->fset_mnt = mntget(current->fs->pwdmnt); 
+        fset->fset_cache = cache;
+        fset->fset_dentry = dentry; 
+        fset->fset_name = strdup(fsetname);
+        fset->fset_chunkbits = CHUNK_BITS;
+        fset->fset_flags = flags;
+        fset->fset_file_maxio = FSET_DEFAULT_MAX_FILEIO; 
+        fset->fset_permit_lock = SPIN_LOCK_UNLOCKED;
+        PRESTO_ALLOC(fset->fset_reint_buf, 64 * 1024);
+        if (fset->fset_reint_buf == NULL) {
+                EXIT;
+                error = -ENOMEM;
+                goto out_free;
+        }
+        init_waitqueue_head(&fset->fset_permit_queue);
+
+        if (presto_d2d(dentry) == NULL) { 
+                dentry->d_fsdata = izo_alloc_ddata();
+        }
+        if (presto_d2d(dentry) == NULL) {
+                CERROR("InterMezzo: %s: no memory\n", __FUNCTION__);
+                EXIT;
+                error = -ENOMEM;
+                goto out_free;
+        }
+        presto_d2d(dentry)->dd_fset = fset;
+        list_add(&fset->fset_list, &cache->cache_fset_list);
+
+        error = izo_init_kml_file(fset, &fset->fset_kml);
+        if ( error ) {
+                EXIT;
+                CDEBUG(D_JOURNAL, "Error init_kml %d\n", error);
+                goto out_list_del;
+        }
+
+        error = izo_init_lml_file(fset, &fset->fset_lml);
+        if ( error ) {
+                int rc;
+                EXIT;
+                rc = izo_log_close(&fset->fset_kml);
+                CDEBUG(D_JOURNAL, "Error init_lml %d, cleanup %d\n", error, rc);
+                goto out_list_del;
+        }
+
+        /* init_last_rcvd_file could trigger a presto_file_write(), which
+         * requires that the lml structure be initialized. -phil */
+        error = izo_init_last_rcvd_file(fset, &fset->fset_rcvd);
+        if ( error ) {
+                int rc;
+                EXIT;
+                rc = izo_log_close(&fset->fset_kml);
+                rc = izo_log_close(&fset->fset_lml);
+                CDEBUG(D_JOURNAL, "Error init_lastrcvd %d, cleanup %d\n", error, rc);
+                goto out_list_del;
+        }
+
+        CDEBUG(D_PIOCTL, "-------> fset at %p, dentry at %p, mtpt %p,"
+               "fset %s, cache %p, presto_d2d(dentry)->dd_fset %p\n",
+               fset, dentry, fset->fset_dentry, fset->fset_name, cache,
+               presto_d2d(dentry)->dd_fset);
+
+        EXIT;
+        return 0;
+
+ out_list_del:
+        list_del(&fset->fset_list);
+        presto_d2d(dentry)->dd_fset = NULL;
+ out_free:
+        if (fset) {
+                mntput(fset->fset_mnt); 
+                if (fset->fset_reint_buf != NULL)
+                        PRESTO_FREE(fset->fset_reint_buf, 64 * 1024);
+                PRESTO_FREE(fset, sizeof(*fset));
+        }
+        dput(dentry); 
+ out:
+        return error;
+}
+
+static int izo_cleanup_fset(struct presto_file_set *fset)
+{
+        int error;
+        struct presto_cache *cache;
+
+        ENTRY;
+
+        CERROR("Cleaning up fset %s\n", fset->fset_name);
+
+        error = izo_log_close(&fset->fset_kml);
+        if (error)
+                CERROR("InterMezzo: Closing kml for fset %s: %d\n",
+                       fset->fset_name, error);
+        error = izo_log_close(&fset->fset_lml);
+        if (error)
+                CERROR("InterMezzo: Closing lml for fset %s: %d\n",
+                       fset->fset_name, error);
+        error = izo_log_close(&fset->fset_rcvd);
+        if (error)
+                CERROR("InterMezzo: Closing last_rcvd for fset %s: %d\n",
+                       fset->fset_name, error);
+
+        cache = fset->fset_cache;
+
+        list_del(&fset->fset_list);
+
+        presto_d2d(fset->fset_dentry)->dd_fset = NULL;
+        dput(fset->fset_dentry);
+        mntput(fset->fset_mnt);
+
+        PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) + 1);
+        PRESTO_FREE(fset->fset_reint_buf, 64 * 1024);
+        PRESTO_FREE(fset, sizeof(*fset));
+        EXIT;
+        return error;
+}
+
+int izo_clear_fsetroot(struct dentry *dentry)
+{
+        struct presto_file_set *fset;
+
+        ENTRY;
+
+        fset = presto_dentry2fset(dentry);
+        if (!fset) {
+                EXIT;
+                return -EINVAL;
+        }
+
+        izo_cleanup_fset(fset);
+        EXIT;
+        return 0;
+}
+
+int izo_clear_all_fsetroots(struct presto_cache *cache)
+{
+        struct presto_file_set *fset;
+        struct list_head *tmp,*tmpnext;
+        int error;
+ 
+        error = 0;
+        tmp = &cache->cache_fset_list;
+        tmpnext = tmp->next;
+        while ( tmpnext != &cache->cache_fset_list) {
+                tmp = tmpnext;
+                tmpnext = tmp->next;
+                fset = list_entry(tmp, struct presto_file_set, fset_list);
+
+                error = izo_cleanup_fset(fset);
+                if (error)
+                        break;
+        }
+        return error;
+}
+
+static struct vfsmount *izo_alloc_vfsmnt(void)
+{
+        struct vfsmount *mnt;
+        PRESTO_ALLOC(mnt, sizeof(*mnt));
+        if (mnt) {
+                memset(mnt, 0, sizeof(struct vfsmount));
+                atomic_set(&mnt->mnt_count,1);
+                INIT_LIST_HEAD(&mnt->mnt_hash);
+                INIT_LIST_HEAD(&mnt->mnt_child);
+                INIT_LIST_HEAD(&mnt->mnt_mounts);
+                INIT_LIST_HEAD(&mnt->mnt_list);
+        }
+        return mnt;
+}
+
+
+static void izo_setup_ctxt(struct dentry *root, struct vfsmount *mnt,
+                           struct run_ctxt *save) 
+{
+        struct run_ctxt new;
+
+        mnt->mnt_root = root;
+        mnt->mnt_sb = root->d_inode->i_sb;
+        unlock_super(mnt->mnt_sb);
+
+        new.rootmnt = mnt;
+        new.root = root;
+        new.pwdmnt = mnt;
+        new.pwd = root;
+        new.fsuid = 0;
+        new.fsgid = 0;
+        new.fs = get_fs(); 
+        /* XXX where can we get the groups from? */
+        new.ngroups = 0;
+
+        push_ctxt(save, &new); 
+}
+
+static void izo_cleanup_ctxt(struct vfsmount *mnt, struct run_ctxt *save) 
+{
+        lock_super(mnt->mnt_sb);
+        pop_ctxt(save); 
+}
+
+static int izo_simple_mkdir(struct dentry *dir, char *name, int mode)
+{
+        struct dentry *dchild; 
+        int err;
+        ENTRY;
+        
+        dchild = lookup_one_len(name, dir, strlen(name));
+        if (IS_ERR(dchild)) { 
+                EXIT;
+                return PTR_ERR(dchild); 
+        }
+
+        if (dchild->d_inode) { 
+                dput(dchild);
+                EXIT;
+                return -EEXIST;
+        }
+
+        err = vfs_mkdir(dir->d_inode, dchild, mode);
+        dput(dchild);
+        
+        EXIT;
+        return err;
+}
+
+static int izo_simple_symlink(struct dentry *dir, char *name, char *tgt)
+{
+        struct dentry *dchild; 
+        int err;
+        ENTRY;
+        
+        dchild = lookup_one_len(name, dir, strlen(name));
+        if (IS_ERR(dchild)) { 
+                EXIT;
+                return PTR_ERR(dchild); 
+        }
+
+        if (dchild->d_inode) { 
+                dput(dchild);
+                EXIT;
+                return -EEXIST;
+        }
+
+        err = vfs_symlink(dir->d_inode, dchild, tgt);
+        dput(dchild);
+        
+        EXIT;
+        return err;
+}
+
+/*
+ * run set_fsetroot in chroot environment
+ */
+int presto_set_fsetroot_from_ioc(struct dentry *root, char *fsetname,
+                                 unsigned int flags)
+{
+        int rc;
+        struct presto_cache *cache;
+        struct vfsmount *mnt;
+        struct run_ctxt save;
+
+        if (root != root->d_inode->i_sb->s_root) {
+                CERROR ("IOC_SET_FSET must be called on mount point\n");
+                return -ENODEV;
+        }
+
+        cache = presto_get_cache(root->d_inode);
+        mnt = cache->cache_vfsmount;
+        if (!mnt) { 
+                EXIT;
+                return -ENOMEM;
+        }
+        
+        izo_setup_ctxt(root, mnt, &save); 
+        rc = presto_set_fsetroot(root, fsetname, flags);
+        izo_cleanup_ctxt(mnt, &save);
+        return rc;
+}
+
+/* XXX: this function should detect if fsetname is already in use for
+   the cache under root
+*/ 
+int izo_prepare_fileset(struct dentry *root, char *fsetname) 
+{
+        int err;
+        struct dentry *dotizo = NULL, *fsetdir = NULL, *dotiopen = NULL; 
+        struct presto_cache *cache;
+        struct vfsmount *mnt;
+        struct run_ctxt save;
+
+        cache = presto_get_cache(root->d_inode);
+        mnt = cache->cache_vfsmount = izo_alloc_vfsmnt();
+        if (!mnt) { 
+                EXIT;
+                return -ENOMEM;
+        }
+        
+        if (!fsetname) 
+                fsetname = "rootfset"; 
+
+        izo_setup_ctxt(root, mnt, &save); 
+
+        err = izo_simple_mkdir(root, ".intermezzo", 0755);
+        CDEBUG(D_CACHE, "mkdir on .intermezzo err %d\n", err); 
+
+        err = izo_simple_mkdir(root, "..iopen..", 0755);
+        CDEBUG(D_CACHE, "mkdir on ..iopen.. err %d\n", err); 
+
+        dotiopen = lookup_one_len("..iopen..", root, strlen("..iopen.."));
+        if (IS_ERR(dotiopen)) { 
+                EXIT;
+                goto out;
+        }
+        dotiopen->d_inode->i_op = &presto_dir_iops;
+        dput(dotiopen);
+
+
+        dotizo = lookup_one_len(".intermezzo", root, strlen(".intermezzo"));
+        if (IS_ERR(dotizo)) { 
+                EXIT;
+                goto out;
+        }
+
+
+        err = izo_simple_mkdir(dotizo, fsetname, 0755);
+        CDEBUG(D_CACHE, "mkdir err %d\n", err); 
+
+        /* XXX find the dentry of the root of the fileset (root for now) */ 
+        fsetdir = lookup_one_len(fsetname, dotizo, strlen(fsetname));
+        if (IS_ERR(fsetdir)) { 
+                EXIT;
+                goto out;
+        }
+
+        err = izo_simple_symlink(fsetdir, "ROOT", "../.."); 
+
+        /* XXX read flags from flags file */ 
+        err =  presto_set_fsetroot(root, fsetname, 0); 
+        CDEBUG(D_CACHE, "set_fsetroot err %d\n", err); 
+
+ out:
+        if (dotizo && !IS_ERR(dotizo)) 
+                dput(dotizo); 
+        if (fsetdir && !IS_ERR(fsetdir)) 
+                dput(fsetdir); 
+        izo_cleanup_ctxt(mnt, &save);
+        return err; 
+}
+
+int izo_set_fileid(struct file *dir, struct izo_ioctl_data *data)
+{
+        int rc = 0;
+        struct presto_cache *cache;
+        struct vfsmount *mnt;
+        struct run_ctxt save;
+        struct nameidata nd;
+        struct dentry *dentry;
+        struct presto_dentry_data *dd;
+        struct dentry *root;
+        char *buf = NULL; 
+
+        ENTRY;
+
+
+        root = dir->f_dentry;
+
+        /* actually, needs to be called on ROOT of fset, not mount point  
+        if (root != root->d_inode->i_sb->s_root) {
+                CERROR ("IOC_SET_FSET must be called on mount point\n");
+                return -ENODEV;
+        }
+        */
+
+        cache = presto_get_cache(root->d_inode);
+        mnt = cache->cache_vfsmount;
+        if (!mnt) { 
+                EXIT;
+                return -ENOMEM;
+        }
+        
+        izo_setup_ctxt(root, mnt, &save); 
+        
+        PRESTO_ALLOC(buf, data->ioc_plen1);
+        if (!buf) { 
+                rc = -ENOMEM;
+                EXIT;
+                goto out;
+        }
+        if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) { 
+                rc =  -EFAULT;
+                EXIT;
+                goto out;
+        }
+
+        rc = presto_walk(buf, &nd);
+        if (rc) {
+                CERROR("Unable to open: %s\n", buf);
+                EXIT;
+                goto out;
+        }
+        dentry = nd.dentry;
+        if (!dentry) {
+                CERROR("no dentry!\n");
+                rc =  -EINVAL;
+                EXIT;
+                goto out_close;
+        }
+        dd = presto_d2d(dentry);
+        if (!dd) {
+                CERROR("no dentry_data!\n");
+                rc = -EINVAL;
+                EXIT;
+                goto out_close;
+        }
+
+        CDEBUG(D_FILE,"de:%p dd:%p\n", dentry, dd);
+
+        if (dd->remote_ino != 0) {
+                CERROR("remote_ino already set? %Lx:%Lx\n", dd->remote_ino,
+                       dd->remote_generation);
+                rc = 0;
+                EXIT;
+                goto out_close;
+        }
+
+
+        CDEBUG(D_FILE,"setting %p %p, %s to %Lx:%Lx\n", dentry, dd, 
+               buf, data->ioc_ino,
+               data->ioc_generation);
+        dd->remote_ino = data->ioc_ino;
+        dd->remote_generation = data->ioc_generation;
+
+        EXIT;
+ out_close:
+        path_release(&nd);
+ out:
+        if (buf)
+                PRESTO_FREE(buf, data->ioc_plen1);
+        izo_cleanup_ctxt(mnt, &save);
+        return rc;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/inode.c linux-2.4.20/fs/intermezzo/inode.c
--- linux-2.4.19/fs/intermezzo/inode.c	2002-02-25 19:38:08.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/inode.c	2002-10-29 11:18:31.000000000 +0000
@@ -1,11 +1,27 @@
-/*
- * Super block/filesystem wide operations
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and
+ *    Michael Callahan <callahan@maths.ox.ac.uk>
+ *  Copyright (C) 1999 Carnegie Mellon University
+ *    Rewritten for Linux 2.1.  Peter Braam <braam@cs.cmu.edu>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
  *
- * Copryright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and
- * Michael Callahan <callahan@maths.ox.ac.uk>
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
  *
- * Rewritten for Linux 2.1.  Peter Braam <braam@cs.cmu.edu>
- * Copyright (C) Carnegie Mellon University
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Super block/filesystem wide operations
  */
 
 #define __NO_VERSION__
@@ -32,57 +48,45 @@
 #include <asm/segment.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 
-extern int presto_remount(struct super_block *, int *, char *);
-
-int presto_excluded_gid = PRESTO_EXCL_GID;
-
-extern int presto_prep(struct dentry *, struct presto_cache **,
-                              struct presto_file_set **);
 extern void presto_free_cache(struct presto_cache *);
 
-
 void presto_set_ops(struct inode *inode, struct  filter_fs *filter)
 {
-	ENTRY; 
+        ENTRY; 
+
         if (!inode || is_bad_inode(inode))
                 return;
-	if (inode->i_gid == presto_excluded_gid ) { 
-		EXIT;
-                CDEBUG(D_INODE, "excluded methods for %ld at %p, %p\n",
-                       inode->i_ino, inode->i_op, inode->i_fop);
-		return; 
-	}
+
         if (S_ISREG(inode->i_mode)) {
                 if ( !filter_c2cfiops(filter) ) {
                        filter_setup_file_ops(filter, 
-					     inode, &presto_file_iops,
-					     &presto_file_fops);
+                                             inode, &presto_file_iops,
+                                             &presto_file_fops);
                 }
-		inode->i_op = filter_c2ufiops(filter);
-		inode->i_fop = filter_c2uffops(filter);
+                inode->i_op = filter_c2ufiops(filter);
+                inode->i_fop = filter_c2uffops(filter);
                 CDEBUG(D_INODE, "set file methods for %ld to %p\n",
                        inode->i_ino, inode->i_op);
         } else if (S_ISDIR(inode->i_mode)) {
-		inode->i_op = filter_c2udiops(filter);
-		inode->i_fop = filter_c2udfops(filter);
-                CDEBUG(D_INODE, "set dir methods for %ld to %p lookup %p\n",
-                       inode->i_ino, inode->i_op, inode->i_op->lookup);
+                inode->i_op = filter_c2udiops(filter);
+                inode->i_fop = filter_c2udfops(filter);
+                CDEBUG(D_INODE, "set dir methods for %ld to %p ioctl %p\n",
+                       inode->i_ino, inode->i_op, inode->i_fop->ioctl);
         } else if (S_ISLNK(inode->i_mode)) {
                 if ( !filter_c2csiops(filter)) {
                         filter_setup_symlink_ops(filter, 
                                                  inode,
                                                  &presto_sym_iops, 
-						 &presto_sym_fops);
+                                                 &presto_sym_fops);
                 }
-		inode->i_op = filter_c2usiops(filter);
-		inode->i_fop = filter_c2usfops(filter);
+                inode->i_op = filter_c2usiops(filter);
+                inode->i_fop = filter_c2usfops(filter);
                 CDEBUG(D_INODE, "set link methods for %ld to %p\n",
                        inode->i_ino, inode->i_op);
         }
-	EXIT;
+        EXIT;
 }
 
 void presto_read_inode(struct inode *inode)
@@ -91,7 +95,7 @@
 
         cache = presto_get_cache(inode);
         if ( !cache ) {
-                printk("PRESTO: BAD, BAD: cannot find cache\n");
+                CERROR("PRESTO: BAD, BAD: cannot find cache\n");
                 make_bad_inode(inode);
                 return ;
         }
@@ -99,37 +103,52 @@
         filter_c2csops(cache->cache_filter)->read_inode(inode);
 
         CDEBUG(D_INODE, "presto_read_inode: ino %ld, gid %d\n", 
-	       inode->i_ino, inode->i_gid);
-
-	//        if (inode->i_gid == presto_excluded_gid)
-        //       return;
+               inode->i_ino, inode->i_gid);
 
-	presto_set_ops(inode, cache->cache_filter); 
+        presto_set_ops(inode, cache->cache_filter); 
         /* XXX handle special inodes here or not - probably not? */
 }
 
-void presto_put_super(struct super_block *sb)
+static void presto_put_super(struct super_block *sb)
 {
         struct presto_cache *cache;
-        struct upc_comm *psdev;
+        struct upc_channel *channel;
         struct super_operations *sops;
         struct list_head *lh;
+        int err;
 
-	ENTRY;
-        cache = presto_find_cache(sb->s_dev);
+        ENTRY;
+        cache = presto_cache_find(sb->s_dev);
         if (!cache) {
-		EXIT;
+                EXIT;
                 goto exit;
-	}
-        psdev = &upc_comms[presto_c2m(cache)];
-
+        }
+        channel = &izo_channels[presto_c2m(cache)];
         sops = filter_c2csops(cache->cache_filter);
+        err = izo_clear_all_fsetroots(cache); 
+        if (err) { 
+                CERROR("%s: err %d\n", __FUNCTION__, err);
+        }
+        PRESTO_FREE(cache->cache_vfsmount, sizeof(struct vfsmount));
+
+        /* look at kill_super - fsync_super is not exported GRRR but 
+           probably not needed */ 
+        unlock_super(sb);
+        shrink_dcache_parent(cache->cache_root); 
+        dput(cache->cache_root); 
+        //fsync_super(sb); 
+        lock_super(sb);
+
+        if (sops->write_super)
+                sops->write_super(sb); 
+
         if (sops->put_super)
                 sops->put_super(sb);
 
         /* free any remaining async upcalls when the filesystem is unmounted */
-        lh = psdev->uc_pending.next;
-        while ( lh != &psdev->uc_pending) {
+        spin_lock(&channel->uc_lock);
+        lh = channel->uc_pending.next;
+        while ( lh != &channel->uc_pending) {
                 struct upc_req *req;
                 req = list_entry(lh, struct upc_req, rq_chain);
 
@@ -141,6 +160,8 @@
                 PRESTO_FREE(req->rq_data, req->rq_bufsize);
                 PRESTO_FREE(req, sizeof(struct upc_req));
         }
+        list_del(&cache->cache_channel_list); 
+        spin_unlock(&channel->uc_lock);
 
         presto_free_cache(cache);
 
@@ -151,18 +172,16 @@
         return ;
 }
 
+struct super_operations presto_super_ops = {
+        .read_inode    = presto_read_inode,
+        .put_super     = presto_put_super,
+};
+
 
 /* symlinks can be chowned */
 struct inode_operations presto_sym_iops = {
-	setattr:	presto_setattr
+        .setattr       = presto_setattr
 };
 
 /* NULL for now */
 struct file_operations presto_sym_fops; 
-
-struct super_operations presto_super_ops = {
-        read_inode:     presto_read_inode,
-        put_super:      presto_put_super,
-        remount_fs:     presto_remount
-};
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/journal.c linux-2.4.20/fs/intermezzo/journal.c
--- linux-2.4.19/fs/intermezzo/journal.c	2002-02-25 19:38:08.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/journal.c	2002-10-29 11:18:31.000000000 +0000
@@ -1,13 +1,32 @@
-/*
- * Intermezzo. (C) 1998 Peter J. Braam
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam
+ *  Copyright (C) 2001 Cluster File Systems, Inc. 
+ *  Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
+ *
+ *  Support for journalling extended attributes
+ *  Copyright (C) 2001 Shirish H. Phatak, Tacit Networks, Inc.
+ * 
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
  *
- * Support for journalling extended attributes
- * (C) 2001 Shirish H. Phatak, Tacit Networks, Inc.
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
@@ -19,15 +38,25 @@
 #include <linux/string.h>
 #include <linux/smp_lock.h>
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
-static int presto_log(struct presto_file_set *fset, struct rec_info *rec,
-                      const char *buf, size_t size,
-                      const char *string1, int len1, 
-                      const char *string2, int len2,
-                      const char *string3, int len3);
+struct presto_reservation_data {
+        unsigned int ri_recno;
+        loff_t ri_offset;
+        loff_t ri_size;
+        struct list_head ri_list;
+};
+
+/* 
+ *  Locking Semantics
+ * 
+ * write lock in struct presto_log_fd: 
+ *  - name: fd_lock
+ *  - required for: accessing any field in a presto_log_fd 
+ *  - may not be held across I/O
+ *  - 
+ *  
+ */
 
 /*
  *  reserve record space and/or atomically request state of the log
@@ -57,22 +86,25 @@
 
         fd->fd_recno++;
         
-        /* this move the fd_offset back after truncation */ 
+        /* this moves the fd_offset back after truncation */ 
         if ( list_empty(&fd->fd_reservations) && 
              !chunked_record) { 
                 fd->fd_offset = fd->fd_file->f_dentry->d_inode->i_size;
         }
 
         rec->offset = fd->fd_offset;
-        rec->recno = fd->fd_recno;
+        if (rec->is_kml)
+                rec->offset += fset->fset_kml_logical_off;
 
-        fd->fd_offset += rec->size;
+        rec->recno = fd->fd_recno;
 
         /* add the reservation data to the end of the list */
-        list_add(&rd->ri_list, fd->fd_reservations.prev);
-        rd->ri_offset = rec->offset;
+        rd->ri_offset = fd->fd_offset;
         rd->ri_size = rec->size;
         rd->ri_recno = rec->recno; 
+        list_add(&rd->ri_list, fd->fd_reservations.prev);
+
+        fd->fd_offset += rec->size;
 
         write_unlock(&fd->fd_lock); 
 
@@ -87,61 +119,92 @@
         write_unlock(&fd->fd_lock);
 }
 
-static int presto_do_truncate(struct presto_file_set *fset, 
-                              struct dentry *dentry, loff_t length, 
-                              loff_t size_check)
+/* XXX should we ask for do_truncate to be exported? */
+int izo_do_truncate(struct presto_file_set *fset, struct dentry *dentry,
+                    loff_t length,  loff_t size_check)
 {
         struct inode *inode = dentry->d_inode;
-        struct inode_operations *op; 
         int error;
         struct iattr newattrs;
 
         ENTRY;
 
-        /* Not pretty: "inode->i_size" shouldn't really be "loff_t". */
-        if ((off_t) length < 0)
+        if (length < 0) {
+                EXIT;
                 return -EINVAL;
+        }
 
-        fs_down(&inode->i_sem);
+        down(&inode->i_sem);
         lock_kernel();
         
         if (size_check != inode->i_size) { 
                 unlock_kernel();
-                fs_up(&inode->i_sem);
+                up(&inode->i_sem);
                 EXIT;
                 return -EALREADY; 
         }
 
         newattrs.ia_size = length;
         newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
-        op = filter_c2cfiops(fset->fset_cache->cache_filter);
 
-        if (op != NULL && op->setattr != NULL)
-                error = op->setattr(dentry, &newattrs);
+        if (inode->i_op && inode->i_op->setattr)
+                error = inode->i_op->setattr(dentry, &newattrs);
         else {
                 inode_setattr(dentry->d_inode, &newattrs);
-                /* Some filesystems, e.g. ext2 and older versions of ext3
-                   legitimately do not have a <fs>_setattr method. -SHP
-                */
-                /*
-                printk ("Warning:: int presto_do_truncate(xxx), op->setattr == NULL");
-		error = -EOPNOTSUPP; 
-		*/
-		error = 0;
+                error = 0;
         }
+
         unlock_kernel();
-        fs_up(&inode->i_sem);
+        up(&inode->i_sem);
         EXIT;
         return error;
 }
 
+static void presto_kml_truncate(struct presto_file_set *fset)
+{
+        int rc;
+        ENTRY;
+
+        write_lock(&fset->fset_kml.fd_lock);
+        if (fset->fset_kml.fd_truncating == 1 ) {
+                write_unlock(&fset->fset_kml.fd_lock);
+                EXIT;
+                return;
+        }
+
+        fset->fset_kml.fd_truncating = 1;
+        write_unlock(&fset->fset_kml.fd_lock);
+
+        CERROR("islento: %d, count: %d\n",
+               ISLENTO(presto_i2m(fset->fset_dentry->d_inode)),
+               fset->fset_permit_count);
+
+        rc = izo_upc_kml_truncate(fset->fset_cache->cache_psdev->uc_minor,
+                                fset->fset_lento_off, fset->fset_lento_recno,
+                                fset->fset_name);
+
+        /* Userspace is the only permitholder now, and will retain an exclusive
+         * hold on the permit until KML truncation completes. */
+        /* FIXME: double check this code path now that the precise semantics of
+         * fset->fset_permit_count have changed. */
+
+        if (rc != 0) {
+                write_lock(&fset->fset_kml.fd_lock);
+                fset->fset_kml.fd_truncating = 0;
+                write_unlock(&fset->fset_kml.fd_lock);
+        }
+
+        EXIT;
+}
 
 void *presto_trans_start(struct presto_file_set *fset, struct inode *inode,
                          int op)
 {
         ENTRY;
-        if ( !fset->fset_cache->cache_filter->o_trops )
+        if ( !fset->fset_cache->cache_filter->o_trops ) {
+                EXIT;
                 return NULL;
+        }
         EXIT;
         return fset->fset_cache->cache_filter->o_trops->tr_start
                 (fset, inode, op);
@@ -150,28 +213,39 @@
 void presto_trans_commit(struct presto_file_set *fset, void *handle)
 {
         ENTRY;
-        if (!fset->fset_cache->cache_filter->o_trops )
+        if (!fset->fset_cache->cache_filter->o_trops ) {
+                EXIT;
                 return;
-        EXIT;
-        return fset->fset_cache->cache_filter->o_trops->tr_commit(fset, handle);
+        }
+
+        fset->fset_cache->cache_filter->o_trops->tr_commit(fset, handle);
 
+        /* Check to see if the KML needs truncated. */
+        if (fset->kml_truncate_size > 0 &&
+            !fset->fset_kml.fd_truncating &&
+            fset->fset_kml.fd_offset > fset->kml_truncate_size) {
+                CDEBUG(D_JOURNAL, "kml size: %lu; truncating\n",
+                       (unsigned long)fset->fset_kml.fd_offset);
+                presto_kml_truncate(fset);
+        }
+        EXIT;
 }
 
 inline int presto_no_journal(struct presto_file_set *fset)
 {
         int minor = fset->fset_cache->cache_psdev->uc_minor;
-        return upc_comms[minor].uc_no_journal;
+        return izo_channels[minor].uc_no_journal;
 }
 
 #define size_round(x)  (((x)+3) & ~0x3)
 
 #define BUFF_FREE(buf) PRESTO_FREE(buf, PAGE_SIZE)
-#define BUFF_ALLOC(newbuf, oldbuf)                      \
-        PRESTO_ALLOC(newbuf, char *, PAGE_SIZE);        \
-        if ( !newbuf ) {                                \
-                if (oldbuf)                             \
-                        BUFF_FREE(oldbuf);              \
-                return -ENOMEM;                         \
+#define BUFF_ALLOC(newbuf, oldbuf)              \
+        PRESTO_ALLOC(newbuf, PAGE_SIZE);        \
+        if ( !newbuf ) {                        \
+                if (oldbuf)                     \
+                        BUFF_FREE(oldbuf);      \
+                return -ENOMEM;                 \
         }
 
 /*
@@ -234,38 +308,40 @@
                                        __u32 ngroups, gid_t *groups,
                                        __u32 fsuid, __u32 fsgid)
 {
-        struct big_journal_prefix p;
+        struct kml_prefix_hdr p;
+        u32 loggroups[NGROUPS_MAX];
+
         int i; 
 
         p.len = cpu_to_le32(rec->size);
-        p.version = PRESTO_KML_MAJOR_VERSION | PRESTO_KML_MINOR_VERSION;
+        p.version = KML_MAJOR_VERSION | KML_MINOR_VERSION;
         p.pid = cpu_to_le32(current->pid);
-        p.uid = cpu_to_le32(current->uid);
+        p.auid = cpu_to_le32(current->uid);
         p.fsuid = cpu_to_le32(fsuid);
         p.fsgid = cpu_to_le32(fsgid);
         p.ngroups = cpu_to_le32(ngroups);
         p.opcode = cpu_to_le32(opcode);
         for (i=0 ; i < ngroups ; i++)
-                p.groups[i] = cpu_to_le32((__u32) groups[i]);
+                loggroups[i] = cpu_to_le32((__u32) groups[i]);
 
-        buf = logit(buf, &p, sizeof(struct journal_prefix) + 
-                    sizeof(__u32) * ngroups);
+        buf = logit(buf, &p, sizeof(struct kml_prefix_hdr));
+        buf = logit(buf, &loggroups, sizeof(__u32) * ngroups);
         return buf;
 }
 
 static inline char *
 journal_log_prefix(char *buf, int opcode, struct rec_info *rec)
 {
-	__u32 groups[NGROUPS_MAX]; 
-	int i; 
+        __u32 groups[NGROUPS_MAX]; 
+        int i; 
 
-	/* convert 16 bit gid's to 32 bit gid's */
-	for (i=0; i<current->ngroups; i++) 
-		groups[i] = (__u32) current->groups[i];
-	
+        /* convert 16 bit gid's to 32 bit gid's */
+        for (i=0; i<current->ngroups; i++) 
+                groups[i] = (__u32) current->groups[i];
+        
         return journal_log_prefix_with_groups_and_ids(buf, opcode, rec,
                                                       (__u32)current->ngroups,
-						      groups,
+                                                      groups,
                                                       (__u32)current->fsuid,
                                                       (__u32)current->fsgid);
 }
@@ -280,83 +356,86 @@
                                                       (__u32)current->fsgid);
 }
 
-static inline char *log_version(char *buf, struct dentry *dentry)
+static inline char *log_dentry_version(char *buf, struct dentry *dentry)
 {
         struct presto_version version;
 
         presto_getversion(&version, dentry->d_inode);
+        
+        version.pv_mtime = HTON__u64(version.pv_mtime);
+        version.pv_ctime = HTON__u64(version.pv_ctime);
+        version.pv_size = HTON__u64(version.pv_size);
 
         return logit(buf, &version, sizeof(version));
 }
 
+static inline char *log_version(char *buf, struct presto_version *pv)
+{
+        struct presto_version version;
+
+        memcpy(&version, pv, sizeof(version));
+        
+        version.pv_mtime = HTON__u64(version.pv_mtime);
+        version.pv_ctime = HTON__u64(version.pv_ctime);
+        version.pv_size = HTON__u64(version.pv_size);
+
+        return logit(buf, &version, sizeof(version));
+}
+
+static inline char *log_rollback(char *buf, struct izo_rollback_data *rb)
+{
+        struct izo_rollback_data rollback;
+
+        memcpy(&rollback, rb, sizeof(rollback));
+        
+        rollback.rb_mode = HTON__u32(rollback.rb_mode);
+        rollback.rb_rdev = HTON__u32(rollback.rb_rdev);
+        rollback.rb_uid = HTON__u64(rollback.rb_uid);
+        rollback.rb_gid = HTON__u64(rollback.rb_gid);
+
+        return logit(buf, &rollback, sizeof(rollback));
+}
+
 static inline char *journal_log_suffix(char *buf, char *log,
                                        struct presto_file_set *fset,
                                        struct dentry *dentry,
                                        struct rec_info *rec)
 {
-        struct journal_suffix s;
-        struct journal_prefix *p = (struct journal_prefix *)log;
+        struct kml_suffix s;
+        struct kml_prefix_hdr *p = (struct kml_prefix_hdr *)log;
 
 #if 0
-	/* XXX needs to be done after reservation, 
-	   disable ths until version 1.2 */
+        /* XXX needs to be done after reservation, 
+           disable ths until version 1.2 */
         if ( dentry ) { 
-                s.prevrec = cpu_to_le32(rec->offset - dentry->d_time);
-                dentry->d_time = (unsigned long) rec->offset;
+                s.prevrec = cpu_to_le32(rec->offset - 
+                                        presto_d2d(dentry)->dd_kml_offset);
+                presto_d2d(dentry)->dd_kml_offset = rec->offset;
         } else { 
                 s.prevrec = -1;
         }
 #endif
-	s.prevrec = 0; 
+        s.prevrec = 0; 
 
         /* record number needs to be filled in after reservation 
            s.recno = cpu_to_le32(rec->recno); */ 
         s.time = cpu_to_le32(CURRENT_TIME);
-        s.len = cpu_to_le32(p->len);
+        s.len = p->len;
         return logit(buf, &s, sizeof(s));
 }
 
-int presto_close_journal_file(struct presto_file_set *fset)
+int izo_log_close(struct presto_log_fd *logfd)
 {
         int rc = 0;
-        int rc2 = 0;
-        int rc3 = 0;
 
-        ENTRY;
-        if ( fset->fset_kml.fd_file) {
-                rc =filp_close(fset->fset_kml.fd_file, 0);
-                fset->fset_kml.fd_file = NULL;
-        } else {
-                printk("hehehehe no filp\n");
-        }
-        if ( rc ) {
-                printk("presto: close files: kml filp won't close %d\n", rc);
-        }
-
-        if ( fset->fset_last_rcvd) {
-                rc2 = filp_close(fset->fset_last_rcvd, 0);
-                fset->fset_last_rcvd = NULL;
-        } else {
-                printk("hehehehe no filp\n");
-        }
-
-        if ( rc2 ) {
-                if ( !rc )
-                        rc = rc2;
-                printk("presto: close files: last_rcvd filp won't close %d\n", rc2);
-        }
+        if (logfd->fd_file) {
+                rc = filp_close(logfd->fd_file, 0);
+                logfd->fd_file = NULL;
+        } else
+                CERROR("InterMezzo: %s: no filp\n", __FUNCTION__);
+        if (rc != 0)
+                CERROR("InterMezzo: close files: filp won't close: %d\n", rc);
 
-        if ( fset->fset_lml.fd_file) {
-                rc3 = filp_close(fset->fset_lml.fd_file, 0);
-                fset->fset_lml.fd_file = NULL;
-        } else {
-                printk("hehehehe no filp\n");
-        }
-        if ( rc3 ) {
-                if ( (!rc) && (!rc2) )
-                        rc = rc3;
-                printk("presto: close files: lml filp won't close %d\n", rc3);
-        }
         return rc;
 }
 
@@ -391,7 +470,7 @@
         set_fs(get_ds());
         rc = file->f_op->write(file, str, len, off);
         if (rc != len) {
-                printk("presto_fwrite: wrote %d bytes instead of "
+                CERROR("presto_fwrite: wrote %d bytes instead of "
                        "%d at %ld\n", rc, len, (long)*off);
                 rc = -EIO; 
         }
@@ -406,10 +485,9 @@
         mm_segment_t old_fs;
         ENTRY;
 
-        if ( len > 512 ) {
-                printk("presto_fread: read at %Ld for %d bytes, ino %ld\n",
+        if (len > 512)
+                CERROR("presto_fread: read at %Ld for %d bytes, ino %ld\n",
                        *off, len, file->f_dentry->d_inode->i_ino); 
-        }
 
         rc = -EINVAL;
         if ( !off ) {
@@ -436,21 +514,47 @@
         set_fs(get_ds());
         rc = file->f_op->read(file, str, len, off);
         if (rc != len) {
-                printk("presto_fread: read %d bytes instead of "
-                       "%d at %ld\n", rc, len, (long)*off);
+                CDEBUG(D_FILE, "presto_fread: read %d bytes instead of "
+                       "%d at %Ld\n", rc, len, *off);
                 rc = -EIO; 
         }
         set_fs(old_fs);
+        EXIT;
         return rc;
 }
 
+loff_t presto_kml_offset(struct presto_file_set *fset)
+{
+        unsigned int kml_recno;
+        struct presto_log_fd *fd = &fset->fset_kml;
+        loff_t  offset;
+        ENTRY;
+
+        write_lock(&fd->fd_lock); 
+
+        /* Determine the largest valid offset, i.e. up until the first
+         * reservation held on the file. */
+        if ( !list_empty(&fd->fd_reservations) ) {
+                struct presto_reservation_data *rd;
+                rd = list_entry(fd->fd_reservations.next, 
+                                struct presto_reservation_data, 
+                                ri_list);
+                offset = rd->ri_offset;
+                kml_recno = rd->ri_recno;
+        } else {
+                offset = fd->fd_file->f_dentry->d_inode->i_size;
+                kml_recno = fset->fset_kml.fd_recno; 
+        }
+        write_unlock(&fd->fd_lock); 
+        return offset; 
+}
 
 static int presto_kml_dispatch(struct presto_file_set *fset)
 {
         int rc = 0;
         unsigned int kml_recno;
         struct presto_log_fd *fd = &fset->fset_kml;
-        loff_t  offset;
+        loff_t offset;
         ENTRY;
 
         write_lock(&fd->fd_lock); 
@@ -470,18 +574,27 @@
         }
 
         if ( kml_recno < fset->fset_lento_recno ) {
-                printk("presto_kml_dispatch: smoke is coming\n"); 
+                CERROR("presto_kml_dispatch: smoke is coming\n"); 
                 write_unlock(&fd->fd_lock);
+                EXIT;
                 return 0; 
         } else if ( kml_recno == fset->fset_lento_recno ) {
                 write_unlock(&fd->fd_lock);
                 EXIT;
                 return 0; 
+                /* XXX add a further "if" here to delay the KML upcall */ 
+#if 0
+        } else if ( kml_recno < fset->fset_lento_recno + 100) {
+                write_unlock(&fd->fd_lock);
+                EXIT;
+                return 0;
+#endif
         }
         CDEBUG(D_PIOCTL, "fset: %s\n", fset->fset_name);
-        rc = lento_kml(fset->fset_cache->cache_psdev->uc_minor,
+
+        rc = izo_upc_kml(fset->fset_cache->cache_psdev->uc_minor,
                        fset->fset_lento_off, fset->fset_lento_recno,
-                       offset, kml_recno, strlen(fset->fset_name),
+                       offset + fset->fset_kml_logical_off, kml_recno,
                        fset->fset_name);
 
         if ( rc ) {
@@ -497,6 +610,256 @@
         return 0;
 }
 
+int izo_lookup_file(struct presto_file_set *fset, char *path,
+                    struct nameidata *nd)
+{
+        int error = 0;
+
+        CDEBUG(D_CACHE, "looking up: %s\n", path);
+
+        if (path_init(path, LOOKUP_PARENT, nd))
+                error = path_walk(path, nd);
+        if (error) {
+                EXIT;
+                return error;
+        }
+
+        return 0;
+}
+
+/* FIXME: this function is a mess of locking and error handling.  There's got to
+ * be a better way. */
+static int do_truncate_rename(struct presto_file_set *fset, char *oldname,
+                              char *newname)
+{
+        struct dentry *old_dentry, *new_dentry;
+        struct nameidata oldnd, newnd;
+        char *oldpath, *newpath;
+        int error;
+
+        ENTRY;
+
+        oldpath = izo_make_path(fset, oldname);
+        if (oldpath == NULL) {
+                EXIT;
+                return -ENOENT;
+        }
+
+        newpath = izo_make_path(fset, newname);
+        if (newpath == NULL) {
+                error = -ENOENT;
+                EXIT;
+                goto exit;
+        }
+
+        if ((error = izo_lookup_file(fset, oldpath, &oldnd)) != 0) {
+                EXIT;
+                goto exit1;
+        }
+
+        if ((error = izo_lookup_file(fset, newpath, &newnd)) != 0) {
+                EXIT;
+                goto exit2;
+        }
+
+        double_lock(newnd.dentry, oldnd.dentry);
+        old_dentry = lookup_hash(&oldnd.last, oldnd.dentry);
+        error = PTR_ERR(old_dentry);
+        if (IS_ERR(old_dentry)) {
+                EXIT;
+                goto exit3;
+        }
+        error = -ENOENT;
+        if (!old_dentry->d_inode) {
+                EXIT;
+                goto exit4;
+        }
+        new_dentry = lookup_hash(&newnd.last, newnd.dentry);
+        error = PTR_ERR(new_dentry);
+        if (IS_ERR(new_dentry)) {
+                EXIT;
+                goto exit4;
+        }
+
+        {
+        extern int presto_rename(struct inode *old_dir,struct dentry *old_dentry,
+                                struct inode *new_dir,struct dentry *new_dentry);
+        error = presto_rename(old_dentry->d_parent->d_inode, old_dentry,
+                              new_dentry->d_parent->d_inode, new_dentry);
+        }
+
+        dput(new_dentry);
+        EXIT;
+ exit4:
+        dput(old_dentry);
+ exit3:
+        double_up(&newnd.dentry->d_inode->i_sem, &oldnd.dentry->d_inode->i_sem);
+        path_release(&newnd);
+ exit2:
+        path_release(&oldnd);
+ exit1:
+        PRESTO_FREE(newpath, strlen(newpath) + 1);
+ exit:
+        PRESTO_FREE(oldpath, strlen(oldpath) + 1);
+        return error;
+}
+
+/* This function is called with the fset->fset_kml.fd_lock held */
+int presto_finish_kml_truncate(struct presto_file_set *fset,
+                               unsigned long int offset)
+{
+        struct lento_vfs_context info;
+        void *handle;
+        struct file *f;
+        struct dentry *dentry;
+        int error = 0, len;
+        struct nameidata nd;
+        char *kmlpath = NULL, *smlpath = NULL;
+        ENTRY;
+
+        if (offset == 0) {
+                /* Lento couldn't do what it needed to; abort the truncation. */
+                fset->fset_kml.fd_truncating = 0;
+                EXIT;
+                return 0;
+        }
+
+        /* someone is about to write to the end of the KML; try again later. */
+        if ( !list_empty(&fset->fset_kml.fd_reservations) ) {
+                EXIT;
+                return -EAGAIN;
+        }
+
+        f = presto_copy_kml_tail(fset, offset);
+        if (IS_ERR(f)) {
+                EXIT;
+                return PTR_ERR(f);
+        }                        
+
+        /* In a single transaction:
+         *
+         *   - unlink 'kml'
+         *   - rename 'kml_tmp' to 'kml'
+         *   - unlink 'sml'
+         *   - rename 'sml_tmp' to 'sml'
+         *   - rewrite the first record of last_rcvd with the new kml
+         *     offset.
+         */
+        handle = presto_trans_start(fset, fset->fset_dentry->d_inode,
+                                    KML_OPCODE_KML_TRUNC);
+        if (IS_ERR(handle)) {
+                presto_release_space(fset->fset_cache, PRESTO_REQLOW);
+                CERROR("ERROR: presto_finish_kml_truncate: no space for transaction\n");
+                EXIT;
+                return -ENOMEM;
+        }
+
+        memset(&info, 0, sizeof(info));
+        info.flags = LENTO_FL_IGNORE_TIME;
+
+        kmlpath = izo_make_path(fset, "kml");
+        if (kmlpath == NULL) {
+                error = -ENOMEM;
+                CERROR("make_path failed: ENOMEM\n");
+                EXIT;
+                goto exit_commit;
+        }
+
+        if ((error = izo_lookup_file(fset, kmlpath, &nd)) != 0) {
+                CERROR("izo_lookup_file(kml) failed: %d.\n", error);
+                EXIT;
+                goto exit_commit;
+        }
+        down(&nd.dentry->d_inode->i_sem);
+        dentry = lookup_hash(&nd.last, nd.dentry);
+        error = PTR_ERR(dentry);
+        if (IS_ERR(dentry)) {
+                up(&nd.dentry->d_inode->i_sem);
+                path_release(&nd);
+                CERROR("lookup_hash failed\n");
+                EXIT;
+                goto exit_commit;
+        }
+        error = presto_do_unlink(fset, dentry->d_parent, dentry, &info);
+        dput(dentry);
+        up(&nd.dentry->d_inode->i_sem);
+        path_release(&nd);
+
+        if (error != 0) {
+                CERROR("presto_do_unlink(kml) failed: %d.\n", error);
+                EXIT;
+                goto exit_commit;
+        }
+
+        smlpath = izo_make_path(fset, "sml");
+        if (smlpath == NULL) {
+                error = -ENOMEM;
+                CERROR("make_path() failed: ENOMEM\n");
+                EXIT;
+                goto exit_commit;
+        }
+
+        if ((error = izo_lookup_file(fset, smlpath, &nd)) != 0) {
+                CERROR("izo_lookup_file(sml) failed: %d.\n", error);
+                EXIT;
+                goto exit_commit;
+        }
+        down(&nd.dentry->d_inode->i_sem);
+        dentry = lookup_hash(&nd.last, nd.dentry);
+        error = PTR_ERR(dentry);
+        if (IS_ERR(dentry)) {
+                up(&nd.dentry->d_inode->i_sem);
+                path_release(&nd);
+                CERROR("lookup_hash failed\n");
+                EXIT;
+                goto exit_commit;
+        }
+        error = presto_do_unlink(fset, dentry->d_parent, dentry, &info);
+        dput(dentry);
+        up(&nd.dentry->d_inode->i_sem);
+        path_release(&nd);
+
+        if (error != 0) {
+                CERROR("presto_do_unlink(sml) failed: %d.\n", error);
+                EXIT;
+                goto exit_commit;
+        }
+
+        error = do_truncate_rename(fset, "kml_tmp", "kml");
+        if (error != 0)
+                CERROR("do_truncate_rename(kml_tmp, kml) failed: %d\n", error);
+        error = do_truncate_rename(fset, "sml_tmp", "sml");
+        if (error != 0)
+                CERROR("do_truncate_rename(sml_tmp, sml) failed: %d\n", error);
+
+        /* Write a new 'last_rcvd' record with the new KML offset */
+        fset->fset_kml_logical_off += offset;
+        CDEBUG(D_CACHE, "new kml_logical_offset: %Lu\n",
+               fset->fset_kml_logical_off);
+        if (presto_write_kml_logical_offset(fset) != 0) {
+                CERROR("presto_write_kml_logical_offset failed\n");
+        }
+
+        presto_trans_commit(fset, handle);
+
+        /* Everything was successful, so swap the KML file descriptors */
+        filp_close(fset->fset_kml.fd_file, NULL);
+        fset->fset_kml.fd_file = f;
+        fset->fset_kml.fd_offset -= offset;
+        fset->fset_kml.fd_truncating = 0;
+
+        EXIT;
+        return 0;
+
+ exit_commit:
+        presto_trans_commit(fset, handle);
+        len = strlen("/.intermezzo/") + strlen(fset->fset_name) +strlen("sml");
+        if (kmlpath != NULL)
+                PRESTO_FREE(kmlpath, len);
+        if (smlpath != NULL)
+                PRESTO_FREE(smlpath, len);
+        return error;
+}
 
 /* structure of an extended log record:
 
@@ -513,10 +876,10 @@
         size_t prefix_size; 
         int rc;
 
-        prefix_size = size - sizeof(struct journal_suffix);
+        prefix_size = size - sizeof(struct kml_suffix);
         rc = presto_fwrite(f, buf, prefix_size, off);
         if ( rc != prefix_size ) {
-                printk("Write error!\n");
+                CERROR("Write error!\n");
                 EXIT;
                 return -EIO;
         }
@@ -524,7 +887,7 @@
         if  ( string1  && len1 ) {
                 rc = presto_fwrite(f, string1, len1, off);
                 if ( rc != len1 ) {
-                        printk("Write error!\n");
+                        CERROR("Write error!\n");
                         EXIT;
                         return -EIO;
                 }
@@ -533,7 +896,7 @@
         if  ( string2 && len2 ) {
                 rc = presto_fwrite(f, string2, len2, off);
                 if ( rc != len2 ) {
-                        printk("Write error!\n");
+                        CERROR("Write error!\n");
                         EXIT;
                         return -EIO;
                 }
@@ -542,16 +905,16 @@
         if  ( string3 && len3 ) {
                 rc = presto_fwrite(f, string3, len3, off);
                 if ( rc != len3 ) {
-                        printk("Write error!\n");
+                        CERROR("Write error!\n");
                         EXIT;
                         return -EIO;
                 }
         }
 
         rc = presto_fwrite(f, buf + prefix_size,
-                           sizeof(struct journal_suffix), off);
-        if ( rc != sizeof(struct journal_suffix) ) {
-                printk("Write error!\n");
+                           sizeof(struct kml_suffix), off);
+        if ( rc != sizeof(struct kml_suffix) ) {
+                CERROR("Write error!\n");
                 EXIT;
                 return -EIO;
         }
@@ -561,18 +924,20 @@
 
 /*
  * rec->size must be valid prior to calling this function.
+ *
+ * had to export this for branch_reinter in kml_reint.c 
  */
-static int presto_log(struct presto_file_set *fset, struct rec_info *rec,
-                      const char *buf, size_t size,
-                      const char *string1, int len1, 
-                      const char *string2, int len2,
-                      const char *string3, int len3)
+int presto_log(struct presto_file_set *fset, struct rec_info *rec,
+               const char *buf, size_t size,
+               const char *string1, int len1, 
+               const char *string2, int len2,
+               const char *string3, int len3)
 {
         int rc;
         struct presto_reservation_data rd;
         loff_t offset;
         struct presto_log_fd *fd;
-        struct journal_suffix *s;
+        struct kml_suffix *s;
         int prefix_size; 
 
         ENTRY;
@@ -590,17 +955,26 @@
         }
 
         presto_reserve_record(fset, fd, rec, &rd);
-        offset = rec->offset;
+
+        if (rec->is_kml) {
+                if (rec->offset < fset->fset_kml_logical_off) {
+                        CERROR("record with pre-trunc offset.  tell phil.\n");
+                        BUG();
+                }
+                offset = rec->offset - fset->fset_kml_logical_off;
+        } else {
+                offset = rec->offset;
+        }
 
         /* now we know the record number */ 
-        prefix_size = size - sizeof(struct journal_suffix);
-        s = (struct journal_suffix *) (buf + prefix_size); 
-        s->recno =  cpu_to_le32(rec->recno); 
+        prefix_size = size - sizeof(struct kml_suffix);
+        s = (struct kml_suffix *) (buf + prefix_size); 
+        s->recno = cpu_to_le32(rec->recno); 
 
         rc = presto_write_record(fd->fd_file, &offset, buf, size, 
                                  string1, len1, string2, len2, string3, len3); 
         if (rc) {
-                printk("presto: error writing record to %s\n",
+                CERROR("presto: error writing record to %s\n",
                         rec->is_kml ? "KML" : "LML"); 
                 return rc;
         }
@@ -616,7 +990,7 @@
 static int presto_last_record(struct presto_log_fd *fd, loff_t *size, 
                              loff_t *tail_offset, __u32 *recno, loff_t tail)
 {
-        struct journal_suffix suffix;
+        struct kml_suffix suffix;
         int rc;
         loff_t zeroes;
 
@@ -624,7 +998,7 @@
         *tail_offset = 0;
         *size = 0;
         
-        if (tail < sizeof(struct journal_prefix) + sizeof(suffix)) {
+        if (tail < sizeof(struct kml_prefix_hdr) + sizeof(suffix)) {
                 EXIT;
                 return 0;
         }
@@ -644,18 +1018,18 @@
         }
 
         /* zeroes at the begining of file. this is needed to prevent
-	   presto_fread errors  -SHP
-	*/
+           presto_fread errors  -SHP
+        */
         if (zeroes <= 0) return 0;
                        
-        zeroes -= sizeof(suffix);
+        zeroes -= sizeof(suffix) + sizeof(int);
         rc = presto_fread(fd->fd_file, (char *)&suffix, sizeof(suffix), &zeroes);
         if ( rc != sizeof(suffix) ) {
                 EXIT;
                 return rc;
         }
         if ( suffix.len > 500 ) {
-                printk("PRESTO: Warning long record tail at %ld, rec tail_offset at %ld (size %d)\n", 
+                CERROR("InterMezzo: Warning long record tail at %ld, rec tail_offset at %ld (size %d)\n", 
                         (long) zeroes, (long)*tail_offset, suffix.len); 
         }
 
@@ -665,213 +1039,259 @@
         return 0;
 }
 
-static int presto_kml_last_recno(struct presto_file_set *fset)
+static int izo_kml_last_recno(struct presto_log_fd *logfd)
 {
         int rc; 
         loff_t size;
         loff_t tail_offset;
         int recno;
-        loff_t tail = fset->fset_kml.fd_file->f_dentry->d_inode->i_size;
+        loff_t tail = logfd->fd_file->f_dentry->d_inode->i_size;
 
-        if ((rc = presto_last_record(&fset->fset_kml, &size, 
-                                        &tail_offset, &recno, tail)) ) {
+        rc = presto_last_record(logfd, &size, &tail_offset, &recno, tail);
+        if (rc != 0) {
                 EXIT;
                 return rc;
         }
 
-        fset->fset_kml.fd_offset = tail_offset;
-        fset->fset_kml.fd_recno = recno;
+        logfd->fd_offset = tail_offset;
+        logfd->fd_recno = recno;
         CDEBUG(D_JOURNAL, "setting fset_kml->fd_recno to %d, offset  %Ld\n",
                recno, tail_offset); 
         EXIT;
         return 0;
 }
 
-static struct file *presto_log_open(struct presto_file_set *fset, char *name, int flags)
+struct file *izo_log_open(struct presto_file_set *fset, char *name, int flags)
 {
         struct presto_cache *cache = fset->fset_cache;
         struct file *f;
         int error;
-        int mtpt_len, path_len;
-        char *path;
         ENTRY;
 
-        mtpt_len = strlen(cache->cache_mtpt);
-        path_len = mtpt_len + strlen("/.intermezzo/") +
-                strlen(fset->fset_name) + strlen(name);
-
-        error = -ENOMEM;
-        PRESTO_ALLOC(path, char *, path_len + 1);
-        if ( !path ) {
-                EXIT;
-                return ERR_PTR(-ENOMEM);
-        }
-
-        sprintf(path, "%s/.intermezzo/%s/%s", cache->cache_mtpt,
-                fset->fset_name, name);
-        CDEBUG(D_INODE, "opening file %s\n", path);
-
-        f = filp_open(path, flags, 0);
+        f = izo_fset_open(fset, name, flags, 0644);
         error = PTR_ERR(f);
         if (IS_ERR(f)) {
-                CDEBUG(D_INODE, "Error %d\n", error);
                 EXIT;
-                goto out_free;
+                return f;
         }
 
         error = -EINVAL;
         if ( cache != presto_get_cache(f->f_dentry->d_inode) ) {
-                printk("PRESTO: %s cache does not match fset cache!\n", name);
+                CERROR("InterMezzo: %s cache does not match fset cache!\n",name);
                 fset->fset_kml.fd_file = NULL;
                 filp_close(f, NULL);
-                goto out_free;
+                f = NULL;
+                EXIT;
+                return f;
         }
 
         if (cache->cache_filter &&  cache->cache_filter->o_trops &&
-	    cache->cache_filter->o_trops->tr_journal_data) {
-		CDEBUG(D_INODE, "\n");
+            cache->cache_filter->o_trops->tr_journal_data) {
                 cache->cache_filter->o_trops->tr_journal_data
                         (f->f_dentry->d_inode);
         } else {
-                printk("WARNING: InterMezzo no file data logging!\n"); 
+                CERROR("InterMezzo WARNING: no file data logging!\n"); 
         }
 
- out_free:
-        PRESTO_FREE(path, path_len + 1);
-
         EXIT;
+
         return f;
 }
 
-int presto_init_kml_file(struct presto_file_set *fset)
+int izo_init_kml_file(struct presto_file_set *fset, struct presto_log_fd *logfd)
 {
         int error = 0;
         struct file *f;
 
         ENTRY;
-        if (fset->fset_kml.fd_file) {
+        if (logfd->fd_file) {
                 CDEBUG(D_INODE, "fset already has KML open\n");
                 EXIT;
                 return 0;
         }
 
-        fset->fset_kml.fd_lock = RW_LOCK_UNLOCKED;
-        INIT_LIST_HEAD(&fset->fset_kml.fd_reservations); 
-        f = presto_log_open(fset, "kml",  O_RDWR | O_CREAT);
-        if ( IS_ERR(f) ) {
+        logfd->fd_lock = RW_LOCK_UNLOCKED;
+        INIT_LIST_HEAD(&logfd->fd_reservations); 
+        f = izo_log_open(fset, "kml",  O_RDWR | O_CREAT);
+        if (IS_ERR(f)) {
                 error = PTR_ERR(f);
                 return error;
         }
 
-        fset->fset_kml.fd_file = f;
-        error = presto_kml_last_recno(fset);
+        logfd->fd_file = f;
+        error = izo_kml_last_recno(logfd);
 
-        if ( error ) {
-                EXIT;
-                fset->fset_kml.fd_file = NULL;
+        if (error) {
+                logfd->fd_file = NULL;
                 filp_close(f, NULL);
-                printk("presto: IO error in KML of fset %s\n", 
+                CERROR("InterMezzo: IO error in KML of fset %s\n",
                        fset->fset_name);
+                EXIT;
+                return error;
         }
-        fset->fset_lento_off = fset->fset_kml.fd_offset;
-        fset->fset_lento_recno = fset->fset_kml.fd_recno;
+        fset->fset_lento_off = logfd->fd_offset;
+        fset->fset_lento_recno = logfd->fd_recno;
 
         EXIT;
         return error;
 }
 
-
-int presto_init_last_rcvd_file(struct presto_file_set *fset)
+int izo_init_last_rcvd_file(struct presto_file_set *fset, struct presto_log_fd *logfd)
 {
         int error = 0;
         struct file *f;
+        struct rec_info recinfo;
 
         ENTRY;
-        if (fset->fset_last_rcvd) {
+        if (logfd->fd_file != NULL) {
                 CDEBUG(D_INODE, "fset already has last_rcvd open\n");
                 EXIT;
                 return 0;
         }
 
-        f = presto_log_open(fset, "last_rcvd", O_RDWR | O_CREAT);
-        if ( IS_ERR(f) ) {
+        logfd->fd_lock = RW_LOCK_UNLOCKED;
+        INIT_LIST_HEAD(&logfd->fd_reservations); 
+        f = izo_log_open(fset, "last_rcvd", O_RDWR | O_CREAT);
+        if (IS_ERR(f)) {
                 error = PTR_ERR(f);
                 return error;
         }
 
-        fset->fset_last_rcvd = f;
+        logfd->fd_file = f;
+        logfd->fd_offset = f->f_dentry->d_inode->i_size;
+
+        error = izo_rep_cache_init(fset);
+
+        if (presto_read_kml_logical_offset(&recinfo, fset) == 0) {
+                fset->fset_kml_logical_off = recinfo.offset;
+        } else {
+                /* The 'last_rcvd' file doesn't contain a kml offset record,
+                 * probably because we just created 'last_rcvd'.  Write one. */
+                fset->fset_kml_logical_off = 0;
+                presto_write_kml_logical_offset(fset);
+        }
 
         EXIT;
         return error;
 }
 
-int presto_init_lml_file(struct presto_file_set *fset)
+int izo_init_lml_file(struct presto_file_set *fset, struct presto_log_fd *logfd)
 {
         int error = 0;
         struct file *f;
 
         ENTRY;
-        if (fset->fset_lml.fd_file) {
+        if (logfd->fd_file) {
                 CDEBUG(D_INODE, "fset already has lml open\n");
                 EXIT;
                 return 0;
         }
 
-        fset->fset_lml.fd_lock = RW_LOCK_UNLOCKED;
-        INIT_LIST_HEAD(&fset->fset_lml.fd_reservations); 
-        f = presto_log_open(fset, "lml", O_RDWR | O_CREAT);
-        if ( IS_ERR(f) ) {
+        logfd->fd_lock = RW_LOCK_UNLOCKED;
+        INIT_LIST_HEAD(&logfd->fd_reservations); 
+        f = izo_log_open(fset, "lml", O_RDWR | O_CREAT);
+        if (IS_ERR(f)) {
                 error = PTR_ERR(f);
                 return error;
         }
 
-        fset->fset_lml.fd_file = f;
-        fset->fset_lml.fd_offset = 
-                fset->fset_lml.fd_file->f_dentry->d_inode->i_size;
+        logfd->fd_file = f;
+        logfd->fd_offset = f->f_dentry->d_inode->i_size;
 
         EXIT;
         return error;
 }
 
-/* Write the last_rcvd values to the last)_rcvd file */
-int presto_write_last_rcvd(struct rec_info *recinfo,
-                           struct presto_file_set *fset,
-                           struct lento_vfs_context *info)
-{
-        int ret;
-        loff_t off = info->slot_offset;
-        struct {
-                __u32 remote_recno;
-                __u64 remote_offset;
-                __u32 local_recno;
-                __u64 local_offset;
-        } rcvd_rec;
-
-        rcvd_rec.remote_recno = cpu_to_le32(info->recno);
-        rcvd_rec.remote_offset = cpu_to_le64(info->kml_offset);
-        rcvd_rec.local_recno = cpu_to_le32(recinfo->recno);
-        rcvd_rec.local_offset = cpu_to_le64(recinfo->offset + recinfo->size);
+/* Get the KML-offset record from the last_rcvd file */
+int presto_read_kml_logical_offset(struct rec_info *recinfo,
+                                   struct presto_file_set *fset)
+{
+        loff_t off;
+        struct izo_rcvd_rec rec;
+        char uuid[16] = {0};
+
+        off = izo_rcvd_get(&rec, fset, uuid);
+        if (off < 0)
+                return -1;
 
-        ret = presto_fwrite(fset->fset_last_rcvd, (char *)(&rcvd_rec),
-                            sizeof(rcvd_rec), &off);
+        recinfo->offset = rec.lr_local_offset;
+        return 0;
+}
 
-        if (ret == sizeof(rcvd_rec))
-                ret = 0;
+int presto_write_kml_logical_offset(struct presto_file_set *fset)
+{
+        loff_t rc;
+        struct izo_rcvd_rec rec;
+        char uuid[16] = {0};
+
+        rc = izo_rcvd_get(&rec, fset, uuid);
+        if (rc < 0)
+                memset(&rec, 0, sizeof(rec));
+
+        rec.lr_local_offset =
+                cpu_to_le64(fset->fset_kml_logical_off);
 
-        return ret;
+        return izo_rcvd_write(fset, &rec);
 }
 
+struct file * presto_copy_kml_tail(struct presto_file_set *fset,
+                                   unsigned long int start)
+{
+        struct file *f;
+        int len;
+        loff_t read_off, write_off, bytes;
+
+        ENTRY;
+
+        /* Copy the tail of 'kml' to 'kml_tmp' */
+        f = izo_log_open(fset, "kml_tmp", O_RDWR);
+        if (IS_ERR(f)) {
+                EXIT;
+                return f;
+        }
+
+        write_off = 0;
+        read_off = start;
+        bytes = fset->fset_kml.fd_offset - start;
+        while (bytes > 0) {
+                char buf[4096];
+                int toread;
+
+                if (bytes > sizeof(buf))
+                        toread = sizeof(buf);
+                else
+                        toread = bytes;
+
+                len = presto_fread(fset->fset_kml.fd_file, buf, toread,
+                                   &read_off);
+                if (len <= 0)
+                        break;
+
+                if (presto_fwrite(f, buf, len, &write_off) != len) {
+                        filp_close(f, NULL);
+                        EXIT;
+                        return ERR_PTR(-EIO);
+                }
+
+                bytes -= len;
+        }
+
+        EXIT;
+        return f;
+}
+
+
 /* LML records here */
-/* this writes the LML records for close, in conjunction with the KML  */
+/* this writes an LML record to the LML file (rec->is_kml =0)  */
 int presto_write_lml_close(struct rec_info *rec,
                            struct presto_file_set *fset, 
                            struct file *file,
                            __u64 remote_ino,
-                           __u32 remote_generation,
-                           __u32 remote_version,
+                           __u64 remote_generation,
+                           struct presto_version *remote_version,
                            struct presto_version *new_file_ver)
 {
-        int opcode = PRESTO_OP_CLOSE;
+        int opcode = KML_OPCODE_CLOSE;
         char *buffer;
         struct dentry *dentry = file->f_dentry; 
         __u64 ino;
@@ -890,7 +1310,7 @@
           EXIT;
           return 0;
         }
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
@@ -899,28 +1319,27 @@
         ino = cpu_to_le64(dentry->d_inode->i_ino);
         generation = cpu_to_le32(dentry->d_inode->i_generation);
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + sizeof(*new_file_ver) +
+                sizeof(struct kml_prefix_hdr) + sizeof(*new_file_ver) +
                 sizeof(ino) + sizeof(generation) + sizeof(pathlen) +
                 sizeof(remote_ino) + sizeof(remote_generation) + 
                 sizeof(remote_version) + sizeof(rec->offset) +
-                sizeof(struct journal_suffix);
-
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+                sizeof(struct kml_suffix);
 
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
+        
         rec->is_kml = 0;
         rec->size = size + size_round(le32_to_cpu(pathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, new_file_ver, sizeof(*new_file_ver));
+        logrecord = log_version(logrecord, new_file_ver);
         logrecord = logit(logrecord, &ino, sizeof(ino));
         logrecord = logit(logrecord, &generation, sizeof(generation));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = logit(logrecord, &remote_ino, sizeof(remote_ino));
         logrecord = logit(logrecord, &remote_generation,
                           sizeof(remote_generation));
-        logrecord = logit(logrecord, &remote_version, sizeof(remote_version));
+        logrecord = log_version(logrecord, remote_version);
         logrecord = logit(logrecord, &rec->offset, sizeof(rec->offset));
         logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec);
 
@@ -934,28 +1353,6 @@
         return error;
 }
 
-int presto_journal_write(struct rec_info *rec,
-                         struct presto_file_set *fset, 
-                         struct file *file)
-{
-        struct presto_version file_version;
-        int rc;
-        ENTRY;
-
-        presto_getversion(&file_version, file->f_dentry->d_inode); 
-        /* append this record */
-        rc = presto_write_lml_close
-                (rec, 
-                 fset, 
-                 file,
-                 0, /* remote_ino */
-                 0, /* remote_generation */
-                 0, /* remote_version */
-                 &file_version);
-        EXIT;
-        return rc;
-}
-
 /* 
  * Check if the given record is at the end of the file. If it is, truncate
  * the lml to the record's offset, removing it. Repeat on prior record,
@@ -969,7 +1366,7 @@
         loff_t lml_last_recsize;
         loff_t local_offset;
         int recno;
-        struct journal_prefix prefix;
+        struct kml_prefix_hdr prefix;
         struct inode *inode = fset->fset_lml.fd_file->f_dentry->d_inode;
         void *handle;
         int rc;
@@ -1004,33 +1401,33 @@
           beginning of the file. -SHP
        */
        if (lml_last_recsize != 0) {
-       		local_offset = lml_last_rec - lml_last_recsize;
-       		rc = presto_fread(fset->fset_lml.fd_file, (char *)&prefix,  
-                          		sizeof(prefix), &local_offset); 
-        	if (rc != sizeof(prefix)) {
-                	EXIT;
-                	goto tr_out;
-        	}
+                local_offset = lml_last_rec - lml_last_recsize;
+                rc = presto_fread(fset->fset_lml.fd_file, (char *)&prefix,  
+                                        sizeof(prefix), &local_offset); 
+                if (rc != sizeof(prefix)) {
+                        EXIT;
+                        goto tr_out;
+                }
        
-        	if ( prefix.opcode != PRESTO_OP_NOOP ) {
-                	EXIT;
-                	rc = 0;
+                if ( prefix.opcode != KML_OPCODE_NOOP ) {
+                        EXIT;
+                        rc = 0;
                         /* We may have zeroes at the end of the file, should
-			   we clear them out? -SHP
+                           we clear them out? -SHP
                         */
-                	goto tr_out;
-        	}
-	} else 
-	 	lml_last_rec=0;
+                        goto tr_out;
+                }
+        } else 
+                lml_last_rec=0;
 
-        handle = presto_trans_start(fset, inode, PRESTO_OP_TRUNC);
-        if ( !handle ) {
+        handle = presto_trans_start(fset, inode, KML_OPCODE_TRUNC);
+        if ( IS_ERR(handle) ) {
                 EXIT;
                 rc = -ENOMEM;
                 goto tr_out;
         }
 
-        rc = presto_do_truncate(fset, fset->fset_lml.fd_file->f_dentry, 
+        rc = izo_do_truncate(fset, fset->fset_lml.fd_file->f_dentry, 
                                 lml_last_rec - lml_last_recsize, lml_tail);
         presto_trans_commit(fset, handle); 
         if ( rc == 0 ) {
@@ -1048,25 +1445,21 @@
 
 int presto_truncate_lml(struct presto_file_set *fset)
 {
-
         int rc; 
         ENTRY;
         
         while ( (rc = presto_truncate_lml_tail(fset)) > 0);
         if ( rc < 0 && rc != -EALREADY) {
-                printk("truncate_lml error %d\n", rc); 
+                CERROR("truncate_lml error %d\n", rc); 
         }
         EXIT;
         return rc;
 }
 
-
-
-int presto_clear_lml_close(struct presto_file_set *fset, 
-                           loff_t  lml_offset)
+int presto_clear_lml_close(struct presto_file_set *fset, loff_t lml_offset)
 {
         int rc;
-        struct journal_prefix record;
+        struct kml_prefix_hdr record;
         loff_t offset = lml_offset;
 
         ENTRY;
@@ -1076,20 +1469,20 @@
                 return 0;
         }
 
-        CDEBUG(D_JOURNAL, "reading prefix: off %ld, size %Zd\n", 
+        CDEBUG(D_JOURNAL, "reading prefix: off %ld, size %d\n", 
                (long)lml_offset, sizeof(record));
         rc = presto_fread(fset->fset_lml.fd_file, (char *)&record,
                           sizeof(record), &offset);
 
         if ( rc != sizeof(record) ) {
-                printk("presto: clear_lml io error %d\n", rc); 
+                CERROR("presto: clear_lml io error %d\n", rc); 
                 EXIT;
                 return -EIO;
         }
 
         /* overwrite the prefix */ 
         CDEBUG(D_JOURNAL, "overwriting prefix: off %ld\n", (long)lml_offset);
-        record.opcode = PRESTO_OP_NOOP;
+        record.opcode = KML_OPCODE_NOOP;
         offset = lml_offset;
         /* note: this does just a single transaction in the cache */
         rc = presto_fwrite(fset->fset_lml.fd_file, (char *)(&record), 
@@ -1107,22 +1500,16 @@
 
 /* now a journal function for every operation */
 
-int presto_journal_setattr(struct rec_info *rec, 
-                           struct presto_file_set *fset, 
-                           struct dentry *dentry,
-                           struct presto_version *old_ver, struct iattr *iattr)
+int presto_journal_setattr(struct rec_info *rec, struct presto_file_set *fset,
+                           struct dentry *dentry, struct presto_version *old_ver,
+                           struct izo_rollback_data *rb, struct iattr *iattr)
 {
-        int opcode = PRESTO_OP_SETATTR;
-        char *buffer;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
+        int opcode = KML_OPCODE_SETATTR;
+        char *buffer, *path, *logrecord, record[316];
         struct dentry *root;
-        __u32 uid, gid, mode, valid, flags;
+        __u32 uid, gid, mode, valid, flags, pathlen;
         __u64 fsize, mtime, ctime;
-        int error;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1130,25 +1517,26 @@
                 return 0;
         }
 
-        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) ) {
+        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) 
+            || ((dentry->d_parent != dentry) && list_empty(&dentry->d_hash))) {
                 EXIT;
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + sizeof(*old_ver) +
+                sizeof(struct kml_prefix_hdr) + sizeof(*old_ver) +
                 sizeof(valid) + sizeof(mode) + sizeof(uid) + sizeof(gid) +
                 sizeof(fsize) + sizeof(mtime) + sizeof(ctime) + sizeof(flags) +
-                sizeof(pathlen) + sizeof(struct journal_suffix);
+                sizeof(pathlen) + sizeof(*rb) + sizeof(struct kml_suffix);
+
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
         /* Only journal one kind of mtime, and not atime at all.  Also don't
          * journal bogus data in iattr, to make the journal more compressible.
          */
@@ -1169,7 +1557,7 @@
         rec->size = size + size_round(le32_to_cpu(pathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, old_ver, sizeof(*old_ver));
+        logrecord = log_version(logrecord, old_ver);
         logrecord = logit(logrecord, &valid, sizeof(valid));
         logrecord = logit(logrecord, &mode, sizeof(mode));
         logrecord = logit(logrecord, &uid, sizeof(uid));
@@ -1178,6 +1566,7 @@
         logrecord = logit(logrecord, &mtime, sizeof(mtime));
         logrecord = logit(logrecord, &ctime, sizeof(ctime));
         logrecord = logit(logrecord, &flags, sizeof(flags));
+        logrecord = log_rollback(logrecord, rb);
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec);
 
@@ -1190,21 +1579,69 @@
         return error;
 }
 
+int presto_get_fileid(int minor, struct presto_file_set *fset,
+                      struct dentry *dentry)
+{
+        int opcode = KML_OPCODE_GET_FILEID;
+        struct rec_info rec;
+        char *buffer, *path, *logrecord, record[4096]; /*include path*/
+        struct dentry *root;
+        __u32 uid, gid, pathlen;
+        int error, size;
+        struct kml_suffix *suffix;
+
+        ENTRY;
+
+        root = fset->fset_dentry;
+
+        uid = cpu_to_le32(dentry->d_inode->i_uid);
+        gid = cpu_to_le32(dentry->d_inode->i_gid);
+        BUFF_ALLOC(buffer, NULL);
+        path = presto_path(dentry, root, buffer, PAGE_SIZE);
+        pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
+        size =  sizeof(__u32) * current->ngroups + 
+                sizeof(struct kml_prefix_hdr) + sizeof(pathlen) +
+                size_round(le32_to_cpu(pathlen)) +
+                sizeof(struct kml_suffix);
+
+        CDEBUG(D_FILE, "kml size: %d\n", size);
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
+
+        memset(&rec, 0, sizeof(rec));
+        rec.is_kml = 1;
+        rec.size = size;
+
+        logrecord = journal_log_prefix(record, opcode, &rec);
+        logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
+        logrecord = logit(logrecord, path, size_round(le32_to_cpu(pathlen)));
+        suffix = (struct kml_suffix *)logrecord;
+        logrecord = journal_log_suffix(logrecord, record, fset, dentry, &rec);
+        /* journal_log_suffix expects journal_log to set this */
+        suffix->recno = 0;
+
+        CDEBUG(D_FILE, "actual kml size: %d\n", logrecord - record);
+        CDEBUG(D_FILE, "get fileid: uid %d, gid %d, path: %s\n", uid, gid,path);
+
+        error = izo_upc_get_fileid(minor, size, record, 
+                                   size_round(le32_to_cpu(pathlen)), path,
+                                   fset->fset_name);
+
+        BUFF_FREE(buffer);
+        EXIT;
+        return error;
+}
+
 int presto_journal_create(struct rec_info *rec, struct presto_file_set *fset,
                           struct dentry *dentry,
                           struct presto_version *tgt_dir_ver,
                           struct presto_version *new_file_ver, int mode)
 {
-        int opcode = PRESTO_OP_CREATE;
-        char *buffer;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
+        int opcode = KML_OPCODE_CREATE;
+        char *buffer, *path, *logrecord, record[292];
         struct dentry *root;
-        __u32 uid, gid, lmode;
-        int error;
+        __u32 uid, gid, lmode, pathlen;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1212,7 +1649,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         uid = cpu_to_le32(dentry->d_inode->i_uid);
         gid = cpu_to_le32(dentry->d_inode->i_gid);
@@ -1222,21 +1659,20 @@
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dentry->d_parent);
-        logrecord = logit(logrecord, new_file_ver, sizeof(*new_file_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dentry->d_parent);
+        logrecord = log_version(logrecord, new_file_ver);
         logrecord = logit(logrecord, &lmode, sizeof(lmode));
         logrecord = logit(logrecord, &uid, sizeof(uid));
         logrecord = logit(logrecord, &gid, sizeof(gid));
@@ -1252,22 +1688,17 @@
         return error;
 }
 
-int presto_journal_symlink(struct rec_info *rec, struct presto_file_set *fset, struct dentry *dentry,
-                           const char *target,
+int presto_journal_symlink(struct rec_info *rec, struct presto_file_set *fset,
+                           struct dentry *dentry, const char *target,
                            struct presto_version *tgt_dir_ver,
                            struct presto_version *new_link_ver)
 {
-        int opcode = PRESTO_OP_SYMLINK;
-        char *buffer;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
-        __u32 targetlen = cpu_to_le32(strlen(target));
+        int opcode = KML_OPCODE_SYMLINK;
+        char *buffer, *path, *logrecord, record[292];
         struct dentry *root;
-        __u32 uid, gid;
-        int error;
+        __u32 uid, gid, pathlen;
+        __u32 targetlen = cpu_to_le32(strlen(target));
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1275,7 +1706,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         uid = cpu_to_le32(dentry->d_inode->i_uid);
         gid = cpu_to_le32(dentry->d_inode->i_gid);
@@ -1284,22 +1715,21 @@
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(uid) + sizeof(gid) + sizeof(pathlen) +
-                sizeof(targetlen) + sizeof(struct journal_suffix);
+                sizeof(targetlen) + sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen)) +
                 size_round(le32_to_cpu(targetlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dentry->d_parent);
-        logrecord = logit(logrecord, new_link_ver, sizeof(*new_link_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dentry->d_parent);
+        logrecord = log_version(logrecord, new_link_ver);
         logrecord = logit(logrecord, &uid, sizeof(uid));
         logrecord = logit(logrecord, &gid, sizeof(gid));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
@@ -1316,20 +1746,16 @@
         return error;
 }
 
-int presto_journal_mkdir(struct rec_info *rec, struct presto_file_set *fset, struct dentry *dentry,
+int presto_journal_mkdir(struct rec_info *rec, struct presto_file_set *fset,
+                         struct dentry *dentry,
                          struct presto_version *tgt_dir_ver,
                          struct presto_version *new_dir_ver, int mode)
 {
-        int opcode = PRESTO_OP_MKDIR;
-        char *buffer;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
+        int opcode = KML_OPCODE_MKDIR;
+        char *buffer, *path, *logrecord, record[292];
         struct dentry *root;
-        __u32 uid, gid, lmode;
-        int error;
+        __u32 uid, gid, lmode, pathlen;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1337,7 +1763,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         uid = cpu_to_le32(dentry->d_inode->i_uid);
         gid = cpu_to_le32(dentry->d_inode->i_gid);
@@ -1347,21 +1773,20 @@
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size = sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen));
         logrecord = journal_log_prefix(record, opcode, rec);
 
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dentry->d_parent);
-        logrecord = logit(logrecord, new_dir_ver, sizeof(*new_dir_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dentry->d_parent);
+        logrecord = log_version(logrecord, new_dir_ver);
         logrecord = logit(logrecord, &lmode, sizeof(lmode));
         logrecord = logit(logrecord, &uid, sizeof(uid));
         logrecord = logit(logrecord, &gid, sizeof(gid));
@@ -1381,18 +1806,14 @@
 int
 presto_journal_rmdir(struct rec_info *rec, struct presto_file_set *fset,
                      struct dentry *dir, struct presto_version *tgt_dir_ver,
-                     struct presto_version *old_dir_ver, int len,
-                     const char *name)
+                     struct presto_version *old_dir_ver,
+                     struct izo_rollback_data *rb, int len, const char *name)
 {
-        int opcode = PRESTO_OP_RMDIR;
-        char *buffer;
-        char *path;
+        int opcode = KML_OPCODE_RMDIR;
+        char *buffer, *path, *logrecord, record[316];
         __u32 pathlen, llen;
-        int size;
-        char *logrecord;
-        char record[292];
         struct dentry *root;
-        int error;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1400,19 +1821,19 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         llen = cpu_to_le32(len);
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dir, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
-                sizeof(pathlen) + sizeof(llen) + sizeof(struct journal_suffix);
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(pathlen) + sizeof(llen) + sizeof(*rb) +
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         CDEBUG(D_JOURNAL, "path: %s (%d), name: %s (%d), size %d\n",
                path, pathlen, name, len, size);
@@ -1422,9 +1843,10 @@
                 size_round(len);
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dir);
-        logrecord = logit(logrecord, old_dir_ver, sizeof(*old_dir_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dir);
+        logrecord = log_version(logrecord, old_dir_ver);
+        logrecord = logit(logrecord, rb, sizeof(*rb));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = logit(logrecord, &llen, sizeof(llen));
         logrecord = journal_log_suffix(logrecord, record, fset, dir, rec);
@@ -1445,16 +1867,11 @@
                      struct presto_version *new_node_ver, int mode,
                      int dmajor, int dminor )
 {
-        int opcode = PRESTO_OP_MKNOD;
-        char *buffer;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
+        int opcode = KML_OPCODE_MKNOD;
+        char *buffer, *path, *logrecord, record[292];
         struct dentry *root;
-        __u32 uid, gid, lmode, lmajor, lminor;
-        int error;
+        __u32 uid, gid, lmode, lmajor, lminor, pathlen;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1462,7 +1879,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         uid = cpu_to_le32(dentry->d_inode->i_uid);
         gid = cpu_to_le32(dentry->d_inode->i_gid);
@@ -1474,22 +1891,21 @@
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size = sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(lmajor) +
                 sizeof(lminor) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dentry->d_parent);
-        logrecord = logit(logrecord, new_node_ver, sizeof(*new_node_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dentry->d_parent);
+        logrecord = log_version(logrecord, new_node_ver);
         logrecord = logit(logrecord, &lmode, sizeof(lmode));
         logrecord = logit(logrecord, &uid, sizeof(uid));
         logrecord = logit(logrecord, &gid, sizeof(gid));
@@ -1513,15 +1929,11 @@
                     struct presto_version *tgt_dir_ver,
                     struct presto_version *new_link_ver)
 {
-        int opcode = PRESTO_OP_LINK;
-        char *buffer, *srcbuffer;
-        char *path, *srcpath;
+        int opcode = KML_OPCODE_LINK;
+        char *buffer, *srcbuffer, *path, *srcpath, *logrecord, record[292];
         __u32 pathlen, srcpathlen;
-        int size;
-        char *logrecord;
-        char record[292];
         struct dentry *root;
-        int error;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1529,7 +1941,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         BUFF_ALLOC(srcbuffer, NULL);
         srcpath = presto_path(src, root, srcbuffer, PAGE_SIZE);
@@ -1539,22 +1951,21 @@
         path = presto_path(tgt, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(srcpathlen) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen)) + 
                 size_round(le32_to_cpu(srcpathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, tgt->d_parent);
-        logrecord = logit(logrecord, new_link_ver, sizeof(*new_link_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, tgt->d_parent);
+        logrecord = log_version(logrecord, new_link_ver);
         logrecord = logit(logrecord, &srcpathlen, sizeof(srcpathlen));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = journal_log_suffix(logrecord, record, fset, tgt, rec);
@@ -1571,20 +1982,16 @@
 }
 
 
-int presto_journal_rename(struct rec_info *rec, struct presto_file_set *fset, struct dentry *src,
-                          struct dentry *tgt,
+int presto_journal_rename(struct rec_info *rec, struct presto_file_set *fset,
+                          struct dentry *src, struct dentry *tgt,
                           struct presto_version *src_dir_ver,
                           struct presto_version *tgt_dir_ver)
 {
-        int opcode = PRESTO_OP_RENAME;
-        char *buffer, *srcbuffer;
-        char *path, *srcpath;
+        int opcode = KML_OPCODE_RENAME;
+        char *buffer, *srcbuffer, *path, *srcpath, *logrecord, record[292];
         __u32 pathlen, srcpathlen;
-        int size;
-        char *logrecord;
-        char record[292];
         struct dentry *root;
-        int error;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1592,7 +1999,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         BUFF_ALLOC(srcbuffer, NULL);
         srcpath = presto_path(src, root, srcbuffer, PAGE_SIZE);
@@ -1602,23 +2009,22 @@
         path = presto_path(tgt, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 4 * sizeof(*src_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 4 * sizeof(*src_dir_ver) +
                 sizeof(srcpathlen) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen)) + 
                 size_round(le32_to_cpu(srcpathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, src_dir_ver, sizeof(*src_dir_ver));
-        logrecord = log_version(logrecord, src->d_parent);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, tgt->d_parent);
+        logrecord = log_version(logrecord, src_dir_ver);
+        logrecord = log_dentry_version(logrecord, src->d_parent);
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, tgt->d_parent);
         logrecord = logit(logrecord, &srcpathlen, sizeof(srcpathlen));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = journal_log_suffix(logrecord, record, fset, tgt, rec);
@@ -1634,21 +2040,18 @@
         return error;
 }
 
-
-int presto_journal_unlink(struct rec_info *rec, struct presto_file_set *fset, struct dentry *dir,
-                          struct presto_version *tgt_dir_ver,
-                          struct presto_version *old_file_ver, int len,
-                          const char *name)
-{
-        int opcode = PRESTO_OP_UNLINK;
-        char *buffer;
-        char *path;
+int presto_journal_unlink(struct rec_info *rec, struct presto_file_set *fset,
+                          struct dentry *dir, struct presto_version *tgt_dir_ver,
+                          struct presto_version *old_file_ver,
+                          struct izo_rollback_data *rb, struct dentry *dentry,
+                          char *old_target, int old_targetlen)
+{
+        int opcode = KML_OPCODE_UNLINK;
+        char *buffer, *path, *logrecord, record[316];
+        const char *name;
         __u32 pathlen, llen;
-        int size;
-        char *logrecord;
-        char record[292];
         struct dentry *root;
-        int error;
+        int error, size, len;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1656,35 +2059,41 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
+
+        name = dentry->d_name.name;
+        len = dentry->d_name.len;
 
         llen = cpu_to_le32(len);
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dir, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
-        size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
-                sizeof(pathlen) + sizeof(llen) + sizeof(struct journal_suffix);
+        size = sizeof(__u32) * current->ngroups + 
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(pathlen) + sizeof(llen) + sizeof(*rb) +
+                sizeof(old_targetlen) + sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
-        rec->size = size + size_round(le32_to_cpu(pathlen)) + size_round(len);
+        rec->size = size + size_round(le32_to_cpu(pathlen)) + size_round(len) +
+                size_round(old_targetlen);
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dir);
-        logrecord = logit(logrecord, old_file_ver, sizeof(*old_file_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dir);
+        logrecord = log_version(logrecord, old_file_ver);
+        logrecord = log_rollback(logrecord, rb);
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = logit(logrecord, &llen, sizeof(llen));
+        logrecord = logit(logrecord, &old_targetlen, sizeof(old_targetlen));
         logrecord = journal_log_suffix(logrecord, record, fset, dir, rec);
 
         error = presto_log(fset, rec, record, size,
                            path, size_round(le32_to_cpu(pathlen)),
-                           name, size_round(len), 
-                           NULL, 0);
+                           name, size_round(len),
+                           old_target, size_round(old_targetlen));
 
         BUFF_FREE(buffer);
         EXIT;
@@ -1694,20 +2103,16 @@
 int
 presto_journal_close(struct rec_info *rec, struct presto_file_set *fset,
                      struct file *file, struct dentry *dentry,
-		     struct presto_version *new_file_ver)
+                     struct presto_version *old_file_ver,
+                     struct presto_version *new_file_ver)
 {
-        int opcode = PRESTO_OP_CLOSE;
+        int opcode = KML_OPCODE_CLOSE;
         struct presto_file_data *fd;
-        char *buffer;
-        char *path;
-        __u64 ino;
-        __u32 pathlen;
-        __u32 generation;
-        int size;
-        char *logrecord;
-        char record[292];
+        char *buffer, *path, *logrecord, record[316];
         struct dentry *root;
-        int error;
+        int error, size, i;
+        __u32 pathlen, generation;
+        __u64 ino;
         __u32 open_fsuid;
         __u32 open_fsgid;
         __u32 open_ngroups;
@@ -1715,7 +2120,6 @@
         __u32 open_mode;
         __u32 open_uid;
         __u32 open_gid;
-        int i;
 
         ENTRY;
 
@@ -1724,18 +2128,19 @@
                 return 0;
         }
 
-        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) ) {
+        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) 
+            || ((dentry->d_parent != dentry) && list_empty(&dentry->d_hash))) {
                 EXIT;
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         fd = (struct presto_file_data *)file->private_data;
         if (fd) {
                 open_ngroups = fd->fd_ngroups;
                 for (i = 0; i < fd->fd_ngroups; i++)
-			open_groups[i] = (__u32) fd->fd_groups[i];
+                        open_groups[i] = (__u32) fd->fd_groups[i];
                 open_mode = fd->fd_mode;
                 open_uid = fd->fd_uid;
                 open_gid = fd->fd_gid;
@@ -1744,7 +2149,7 @@
         } else {
                 open_ngroups = current->ngroups;
                 for (i=0; i<current->ngroups; i++)
-			open_groups[i] =  (__u32) current->groups[i]; 
+                        open_groups[i] =  (__u32) current->groups[i]; 
                 open_mode = dentry->d_inode->i_mode;
                 open_uid = dentry->d_inode->i_uid;
                 open_gid = dentry->d_inode->i_gid;
@@ -1758,13 +2163,12 @@
         generation = cpu_to_le32(dentry->d_inode->i_generation);
         size =  sizeof(__u32) * open_ngroups +
                 sizeof(open_mode) + sizeof(open_uid) + sizeof(open_gid) +
-                sizeof(struct journal_prefix) + sizeof(*new_file_ver) +
-                sizeof(ino) + sizeof(generation) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_prefix_hdr) + sizeof(*old_file_ver) +
+                sizeof(*new_file_ver) + sizeof(ino) + sizeof(generation) +
+                sizeof(pathlen) + sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen));
@@ -1775,7 +2179,8 @@
         logrecord = logit(logrecord, &open_mode, sizeof(open_mode));
         logrecord = logit(logrecord, &open_uid, sizeof(open_uid));
         logrecord = logit(logrecord, &open_gid, sizeof(open_gid));
-        logrecord = logit(logrecord, new_file_ver, sizeof(*new_file_ver));
+        logrecord = log_version(logrecord, old_file_ver);
+        logrecord = log_version(logrecord, new_file_ver);
         logrecord = logit(logrecord, &ino, sizeof(ino));
         logrecord = logit(logrecord, &generation, sizeof(generation));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
@@ -1796,12 +2201,10 @@
                          __u64 ino,     __u32 generation, 
                          struct presto_version *new_file_ver)
 {
-        int opcode = PRESTO_OP_CLOSE;
-        int size;
-        char *logrecord;
-        char record[292];
+        int opcode = KML_OPCODE_CLOSE;
+        char *logrecord, record[292];
         struct dentry *root;
-        int error;
+        int error, size;
 
         ENTRY;
 
@@ -1810,24 +2213,23 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         size =  sizeof(__u32) * ngroups + 
-                sizeof(struct journal_prefix) + sizeof(*new_file_ver) +
+                sizeof(struct kml_prefix_hdr) + sizeof(*new_file_ver) +
                 sizeof(ino) + sizeof(generation) + 
                 sizeof(le32_to_cpu(pathlen)) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen));
 
         logrecord = journal_log_prefix_with_groups(record, opcode, rec,
                                                    ngroups, groups);
-        logrecord = logit(logrecord, new_file_ver, sizeof(*new_file_ver));
+        logrecord = log_version(logrecord, new_file_ver);
         logrecord = logit(logrecord, &ino, sizeof(ino));
         logrecord = logit(logrecord, &generation, sizeof(generation));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
@@ -1862,7 +2264,7 @@
                 __u64 lml_offset;
         } close_rec; 
         struct file *file = fset->fset_lml.fd_file;
-        struct journal_prefix prefix;
+        struct kml_prefix_hdr prefix;
         int rc = 0;
         ENTRY;
 
@@ -1878,11 +2280,11 @@
                           sizeof(prefix), &read_offset);
         if ( rc != sizeof(prefix) ) {
                 EXIT;
-                printk("presto_complete_lml: ioerror - 1, tell Peter\n");
+                CERROR("presto_complete_lml: ioerror - 1, tell Peter\n");
                 return -EIO;
         }
 
-        if ( prefix.opcode == PRESTO_OP_NOOP ) {
+        if ( prefix.opcode == KML_OPCODE_NOOP ) {
                 lml_offset += prefix.len; 
                 goto again; 
         }
@@ -1891,7 +2293,7 @@
                           prefix.ngroups * sizeof(__u32), &read_offset); 
         if ( rc != prefix.ngroups * sizeof(__u32) ) {
                 EXIT;
-                printk("presto_complete_lml: ioerror - 2, tell Peter\n");
+                CERROR("presto_complete_lml: ioerror - 2, tell Peter\n");
                 return -EIO;
         }
 
@@ -1899,7 +2301,7 @@
                           sizeof(close_rec), &read_offset); 
         if ( rc != sizeof(close_rec) ) {
                 EXIT;
-                printk("presto_complete_lml: ioerror - 3, tell Peter\n");
+                CERROR("presto_complete_lml: ioerror - 3, tell Peter\n");
                 return -EIO;
         }
 
@@ -1914,20 +2316,20 @@
                           le32_to_cpu(close_rec.pathlen), &read_offset); 
         if ( rc != le32_to_cpu(close_rec.pathlen) ) {
                 EXIT;
-                printk("presto_complete_lml: ioerror - 4, tell Peter\n");
+                CERROR("presto_complete_lml: ioerror - 4, tell Peter\n");
                 return -EIO;
         }
         
         handle = presto_trans_start(fset, file->f_dentry->d_inode, 
-                                    PRESTO_OP_RELEASE);
-        if ( !handle ) {
+                                    KML_OPCODE_RELEASE);
+        if ( IS_ERR(handle) ) {
                 EXIT;
                 return -ENOMEM; 
         }
 
         rc = presto_clear_lml_close(fset, lml_offset); 
         if ( rc ) {
-                printk("error during clearing: %d\n", rc);
+                CERROR("error during clearing: %d\n", rc);
                 presto_trans_commit(fset, handle);
                 EXIT; 
                 return rc; 
@@ -1938,7 +2340,7 @@
                                   close_rec.ino, close_rec.generation,
                                   &close_rec.new_file_ver); 
         if ( rc ) {
-                printk("error during rewrite close: %d\n", rc);
+                CERROR("error during rewrite close: %d\n", rc);
                 presto_trans_commit(fset, handle);
                 EXIT; 
                 return rc; 
@@ -1946,7 +2348,7 @@
 
         presto_trans_commit(fset, handle); 
         if ( rc ) { 
-                printk("error during truncation: %d\n", rc);
+                CERROR("error during truncation: %d\n", rc);
                 EXIT; 
                 return rc;
         }
@@ -1973,20 +2375,14 @@
                                  int flags) 
 { 
         int opcode = (buffer == NULL) ? 
-                     PRESTO_OP_DELEXTATTR : 
-                     PRESTO_OP_SETEXTATTR ;
-        char *temp;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
+                     KML_OPCODE_DELEXTATTR : 
+                     KML_OPCODE_SETEXTATTR ;
+        char *temp, *path, *logrecord, record[292];
         struct dentry *root;
-        int error;
+        int error, size;
         __u32 namelen=cpu_to_le32(strnlen(name,PRESTO_EXT_ATTR_NAME_MAX));
         __u32 buflen=(buffer != NULL)? cpu_to_le32(buffer_len): cpu_to_le32(0);
-        __u32 mode;
-
+        __u32 mode, pathlen;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1994,12 +2390,13 @@
                 return 0;
         }
 
-        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) ) {
+        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) 
+            || ((dentry->d_parent != dentry) && list_empty(&dentry->d_hash))) {
                 EXIT;
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         BUFF_ALLOC(temp, NULL);
         path = presto_path(dentry, root, temp, PAGE_SIZE);
@@ -2013,15 +2410,14 @@
         mode=cpu_to_le32(dentry->d_inode->i_mode);
 
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 
+                sizeof(struct kml_prefix_hdr) + 
                 2 * sizeof(struct presto_version) +
                 sizeof(flags) + sizeof(mode) + sizeof(namelen) + 
                 sizeof(buflen) + sizeof(pathlen) + 
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         /* Make space for a path, a attr name and value*/
@@ -2036,8 +2432,8 @@
                     size_round(le32_to_cpu(buflen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, ver, sizeof(*ver));
-        logrecord = log_version(logrecord, dentry);
+        logrecord = log_version(logrecord, ver);
+        logrecord = log_dentry_version(logrecord, dentry);
         logrecord = logit(logrecord, &flags, sizeof(flags));
         logrecord = logit(logrecord, &mode, sizeof(flags));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
@@ -2055,4 +2451,3 @@
         return error;
 }
 #endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/journal_ext2.c linux-2.4.20/fs/intermezzo/journal_ext2.c
--- linux-2.4.19/fs/intermezzo/journal_ext2.c	2001-11-11 18:20:21.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/journal_ext2.c	2002-10-29 11:18:35.000000000 +0000
@@ -1,6 +1,22 @@
-
-/*
- * Intermezzo. (C) 1998 Peter J. Braam
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/types.h>
@@ -18,9 +34,7 @@
 #include <linux/ext2_fs.h> 
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
 #if defined(CONFIG_EXT2_FS)
 
@@ -48,7 +62,7 @@
                 return ERR_PTR(-ENOSPC);
         }
         
-        if (  (op != PRESTO_OP_UNLINK && op != PRESTO_OP_RMDIR)
+        if (  (op != KML_OPCODE_UNLINK && op != KML_OPCODE_RMDIR)
               && avail_kmlblocks < 6 ) {
                 return ERR_PTR(-ENOSPC);
         }            
@@ -57,10 +71,17 @@
 
 static void presto_e2_trans_commit(struct presto_file_set *fset, void *handle)
 {
-  do {} while (0);
+        do {} while (0);
+}
+
+static int presto_e2_has_all_data(struct inode *inode)
+{
+        BUG();
+        return 0;
 }
 
 struct journal_ops presto_ext2_journal_ops = {
+        tr_all_data: presto_e2_has_all_data,
         tr_avail: presto_e2_freespace,
         tr_start: presto_e2_trans_start,
         tr_commit: presto_e2_trans_commit,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/journal_ext3.c linux-2.4.20/fs/intermezzo/journal_ext3.c
--- linux-2.4.19/fs/intermezzo/journal_ext3.c	2001-11-11 18:20:21.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/journal_ext3.c	2002-10-29 11:18:40.000000000 +0000
@@ -1,10 +1,27 @@
-
-/*
- * Intermezzo. (C) 1998 Peter J. Braam
- * Intermezzo. (C) 2000 Red Hat, Inc.
- * Intermezzo. (C) 2000 Los Alamos National Laboratory
- * Intermezzo. (C) 2000 TurboLinux, Inc.
- * Intermezzo. (C) 2001 Mountain View Data, Inc.
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *  Copyright (C) 2000 Red Hat, Inc.
+ *  Copyright (C) 2000 Los Alamos National Laboratory
+ *  Copyright (C) 2000 TurboLinux, Inc.
+ *  Copyright (C) 2001 Mountain View Data, Inc.
+ *  Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/types.h>
@@ -28,9 +45,7 @@
 #endif
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
 #if defined(CONFIG_EXT3_FS) || defined (CONFIG_EXT3_FS_MODULE)
 
@@ -85,7 +100,7 @@
                 return ERR_PTR(-ENOSPC);
         }
         
-        if (  (op != PRESTO_OP_UNLINK && op != PRESTO_OP_RMDIR)
+        if (  (op != KML_OPCODE_UNLINK && op != KML_OPCODE_RMDIR)
               && avail_kmlblocks < 6 ) {
                 return ERR_PTR(-ENOSPC);
         }            
@@ -107,52 +122,71 @@
            and operations involving the LML records 
         */
         switch (op) {
-        case PRESTO_OP_TRUNC:
+        case KML_OPCODE_TRUNC:
                 jblocks = one_path_blks + extra_name_blks + trunc_blks
                         + EXT3_DELETE_TRANS_BLOCKS; 
                 break;
-        case PRESTO_OP_RELEASE:
+        case KML_OPCODE_KML_TRUNC:
+                /* Hopefully this is a little better, but I'm still mostly
+                 * guessing here. */
+                /* unlink 1 */
+                jblocks = extra_name_blks + trunc_blks +
+                        EXT3_DELETE_TRANS_BLOCKS + 2; 
+
+                /* unlink 2 */
+                jblocks += extra_name_blks + trunc_blks +
+                        EXT3_DELETE_TRANS_BLOCKS + 2; 
+
+                /* rename 1 */
+                jblocks += 2 * extra_path_blks + trunc_blks + 
+                        2 * EXT3_DATA_TRANS_BLOCKS + 2 + 3;
+
+                /* rename 2 */
+                jblocks += 2 * extra_path_blks + trunc_blks + 
+                        2 * EXT3_DATA_TRANS_BLOCKS + 2 + 3;
+                break;
+        case KML_OPCODE_RELEASE:
                 /* 
                 jblocks = one_path_blks + lml_blks + 2*trunc_blks; 
                 */
                 jblocks = one_path_blks; 
                 break;
-        case PRESTO_OP_SETATTR:
+        case KML_OPCODE_SETATTR:
                 jblocks = one_path_blks + trunc_blks + 1 ; 
                 break;
-        case PRESTO_OP_CREATE:
+        case KML_OPCODE_CREATE:
                 jblocks = one_path_blks + trunc_blks 
                         + EXT3_DATA_TRANS_BLOCKS + 3 + 2; 
                 break;
-        case PRESTO_OP_LINK:
+        case KML_OPCODE_LINK:
                 jblocks = one_path_blks + trunc_blks 
                         + EXT3_DATA_TRANS_BLOCKS + 2; 
                 break;
-        case PRESTO_OP_UNLINK:
+        case KML_OPCODE_UNLINK:
                 jblocks = one_path_blks + extra_name_blks + trunc_blks
                         + EXT3_DELETE_TRANS_BLOCKS + 2; 
                 break;
-        case PRESTO_OP_SYMLINK:
+        case KML_OPCODE_SYMLINK:
                 jblocks = one_path_blks + extra_path_blks + trunc_blks
                         + EXT3_DATA_TRANS_BLOCKS + 5; 
                 break;
-        case PRESTO_OP_MKDIR:
+        case KML_OPCODE_MKDIR:
                 jblocks = one_path_blks + trunc_blks
                         + EXT3_DATA_TRANS_BLOCKS + 4 + 2;
                 break;
-        case PRESTO_OP_RMDIR:
+        case KML_OPCODE_RMDIR:
                 jblocks = one_path_blks + extra_name_blks + trunc_blks
                         + EXT3_DELETE_TRANS_BLOCKS + 1; 
                 break;
-        case PRESTO_OP_MKNOD:
+        case KML_OPCODE_MKNOD:
                 jblocks = one_path_blks + trunc_blks + 
                         EXT3_DATA_TRANS_BLOCKS + 3 + 2;
                 break;
-        case PRESTO_OP_RENAME:
+        case KML_OPCODE_RENAME:
                 jblocks = one_path_blks + extra_path_blks + trunc_blks + 
                         2 * EXT3_DATA_TRANS_BLOCKS + 2 + 3;
                 break;
-        case PRESTO_OP_WRITE:
+        case KML_OPCODE_WRITE:
                 jblocks = one_path_blks; 
                 /*  add this when we can wrap our transaction with 
                     that of ext3_file_write (ordered writes)
@@ -164,7 +198,8 @@
                 return NULL;
         }
 
-        CDEBUG(D_JOURNAL, "creating journal handle (%d blocks)\n", jblocks);
+        CDEBUG(D_JOURNAL, "creating journal handle (%d blocks) for op %d\n",
+               jblocks, op);
         /* journal_start/stop does not do its own locking while updating
          * the handle/transaction information. Hence we create our own
          * critical section to protect these calls. -SHP
@@ -175,7 +210,7 @@
         return handle;
 }
 
-void presto_e3_trans_commit(struct presto_file_set *fset, void *handle)
+static void presto_e3_trans_commit(struct presto_file_set *fset, void *handle)
 {
         if ( presto_no_journal(fset) || !handle)
                 return;
@@ -186,7 +221,7 @@
         unlock_kernel();
 }
 
-void presto_e3_journal_file_data(struct inode *inode)
+static void presto_e3_journal_file_data(struct inode *inode)
 {
 #ifdef EXT3_JOURNAL_DATA_FL
         inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
@@ -195,11 +230,56 @@
 #endif
 }
 
+/* The logic here is a slightly modified version of ext3/inode.c:block_to_path
+ */
+static int presto_e3_has_all_data(struct inode *inode)
+{
+        int ptrs = EXT3_ADDR_PER_BLOCK(inode->i_sb);
+        int ptrs_bits = EXT3_ADDR_PER_BLOCK_BITS(inode->i_sb);
+        const long direct_blocks = EXT3_NDIR_BLOCKS,
+                indirect_blocks = ptrs,
+                double_blocks = (1 << (ptrs_bits * 2));
+        long block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
+                inode->i_sb->s_blocksize_bits;
+
+        ENTRY;
+
+        if (inode->i_size == 0) {
+                EXIT;
+                return 1;
+        }
+
+        if (block < direct_blocks) {
+                /* No indirect blocks, no problem. */
+        } else if (block < indirect_blocks + direct_blocks) {
+                block++;
+        } else if (block < double_blocks + indirect_blocks + direct_blocks) {
+                block += 2;
+        } else if (((block - double_blocks - indirect_blocks - direct_blocks)
+                    >> (ptrs_bits * 2)) < ptrs) {
+                block += 3;
+        }
+
+        block *= (inode->i_sb->s_blocksize / 512);
+
+        CDEBUG(D_CACHE, "Need %ld blocks, have %ld.\n", block, inode->i_blocks);
+
+        if (block > inode->i_blocks) {
+                EXIT;
+                return 0;
+        }
+
+        EXIT;
+        return 1;
+}
+
 struct journal_ops presto_ext3_journal_ops = {
-        tr_avail: presto_e3_freespace,
-        tr_start:  presto_e3_trans_start,
-        tr_commit: presto_e3_trans_commit,
-        tr_journal_data: presto_e3_journal_file_data
+        .tr_all_data     = presto_e3_has_all_data,
+        .tr_avail        = presto_e3_freespace,
+        .tr_start        =  presto_e3_trans_start,
+        .tr_commit       = presto_e3_trans_commit,
+        .tr_journal_data = presto_e3_journal_file_data,
+        .tr_ilookup      = presto_iget_ilookup
 };
 
 #endif /* CONFIG_EXT3_FS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/journal_obdfs.c linux-2.4.20/fs/intermezzo/journal_obdfs.c
--- linux-2.4.19/fs/intermezzo/journal_obdfs.c	2001-11-11 18:20:21.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/journal_obdfs.c	2002-10-29 11:18:31.000000000 +0000
@@ -1,10 +1,26 @@
-
-/*
- * Intermezzo. (C) 1998 Peter J. Braam
- * Intermezzo. (C) 2000 Red Hat, Inc.
- * Intermezzo. (C) 2000 Los Alamos National Laboratory
- * Intermezzo. (C) 2000 TurboLinux, Inc.
- * Intermezzo. (C) 2001 Mountain View Data, Inc.
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *  Copyright (C) 2000 Red Hat, Inc.
+ *  Copyright (C) 2000 Los Alamos National Laboratory
+ *  Copyright (C) 2000 TurboLinux, Inc.
+ *  Copyright (C) 2001 Mountain View Data, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/types.h>
@@ -25,9 +41,7 @@
 #endif
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
 #ifdef CONFIG_OBDFS_FS
 
@@ -171,10 +185,10 @@
 }
 
 struct journal_ops presto_obdfs_journal_ops = {
-        tr_avail: presto_obdfs_freespace,
-        tr_start:  presto_obdfs_trans_start,
-        tr_commit: presto_obdfs_trans_commit,
-        tr_journal_data: presto_obdfs_journal_file_data
+        .tr_avail        = presto_obdfs_freespace,
+        .tr_start        =  presto_obdfs_trans_start,
+        .tr_commit       = presto_obdfs_trans_commit,
+        .tr_journal_data = presto_obdfs_journal_file_data
 };
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/journal_reiserfs.c linux-2.4.20/fs/intermezzo/journal_reiserfs.c
--- linux-2.4.19/fs/intermezzo/journal_reiserfs.c	2001-11-11 18:20:21.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/journal_reiserfs.c	2002-10-29 11:18:35.000000000 +0000
@@ -1,10 +1,26 @@
-
-/*
- * Intermezzo. (C) 1998 Peter J. Braam
- * Intermezzo. (C) 2000 Red Hat, Inc.
- * Intermezzo. (C) 2000 Los Alamos National Laboratory
- * Intermezzo. (C) 2000 TurboLinux, Inc.
- * Intermezzo. (C) 2001 Mountain View Data, Inc.
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *  Copyright (C) 2000 Red Hat, Inc.
+ *  Copyright (C) 2000 Los Alamos National Laboratory
+ *  Copyright (C) 2000 TurboLinux, Inc.
+ *  Copyright (C) 2001 Mountain View Data, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/types.h>
@@ -28,9 +44,8 @@
 #endif
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
+
 #if defined(CONFIG_REISERFS_FS) || defined(CONFIG_REISERFS_FS_MODULE)
 
 
@@ -54,9 +69,9 @@
         __u32 avail_kmlblocks;
 	struct reiserfs_transaction_handle *th ;
 
-	PRESTO_ALLOC(th, struct reiserfs_transaction_handle *, sizeof(*th));
+	PRESTO_ALLOC(th, sizeof(*th));
 	if (!th) { 
-		printk("presto: No memory for trans handle\n");
+		CERROR("presto: No memory for trans handle\n");
 		return NULL;
 	}
 
@@ -83,23 +98,24 @@
         CDEBUG(D_JOURNAL, "creating journal handle (%d blocks)\n", jblocks);
 
 	lock_kernel();
-	//journal_begin(th, inode->i_sb, jblocks);
+	journal_begin(th, inode->i_sb, jblocks);
 	unlock_kernel();
 	return th; 
 }
 
-void presto_reiserfs_trans_commit(struct presto_file_set *fset, void *handle)
+static void presto_reiserfs_trans_commit(struct presto_file_set *fset,
+                                         void *handle)
 {
 	int jblocks;
 	jblocks = 3 + JOURNAL_PER_BALANCE_CNT * 4;
 	
 	lock_kernel();
-	//journal_end(handle, fset->fset_cache->cache_sb, jblocks);
+	journal_end(handle, fset->fset_cache->cache_sb, jblocks);
 	unlock_kernel();
 	PRESTO_FREE(handle, sizeof(struct reiserfs_transaction_handle));
 }
 
-void presto_reiserfs_journal_file_data(struct inode *inode)
+static void presto_reiserfs_journal_file_data(struct inode *inode)
 {
 #ifdef EXT3_JOURNAL_DATA_FL
         inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
@@ -108,11 +124,18 @@
 #endif
 }
 
+static int presto_reiserfs_has_all_data(struct inode *inode)
+{
+        BUG();
+        return 0;
+}
+
 struct journal_ops presto_reiserfs_journal_ops = {
-        tr_avail: presto_reiserfs_freespace,
-        tr_start:  presto_reiserfs_trans_start,
-        tr_commit: presto_reiserfs_trans_commit,
-        tr_journal_data: presto_reiserfs_journal_file_data
+        .tr_all_data     = presto_reiserfs_has_all_data,
+        .tr_avail        = presto_reiserfs_freespace,
+        .tr_start        = presto_reiserfs_trans_start,
+        .tr_commit       = presto_reiserfs_trans_commit,
+        .tr_journal_data = presto_reiserfs_journal_file_data
 };
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/journal_tmpfs.c linux-2.4.20/fs/intermezzo/journal_tmpfs.c
--- linux-2.4.19/fs/intermezzo/journal_tmpfs.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/journal_tmpfs.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,109 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *  Copyright (C) 2000 Red Hat, Inc.
+ *  Copyright (C) 2000 Los Alamos National Laboratory
+ *  Copyright (C) 2000 TurboLinux, Inc.
+ *  Copyright (C) 2001 Mountain View Data, Inc.
+ *  Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/param.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/locks.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+#include <linux/string.h>
+#include <linux/smp_lock.h>
+#if defined(CONFIG_TMPFS)
+#include <linux/jbd.h>
+#if defined(CONFIG_EXT3)
+#include <linux/ext3_fs.h>
+#include <linux/ext3_jbd.h>
+#endif
+#endif
+
+#include <linux/intermezzo_fs.h>
+#include <linux/intermezzo_psdev.h>
+
+#if defined(CONFIG_TMPFS)
+
+/* space requirements: 
+   presto_do_truncate: 
+        used to truncate the KML forward to next fset->chunksize boundary
+          - zero partial block
+          - update inode
+   presto_write_record: 
+        write header (< one block) 
+        write one path (< MAX_PATHLEN) 
+        possibly write another path (< MAX_PATHLEN)
+        write suffix (< one block) 
+   presto_update_last_rcvd
+        write one block
+*/
+
+static loff_t presto_tmpfs_freespace(struct presto_cache *cache,
+                                         struct super_block *sb)
+{
+        return (1<<30);
+}
+
+/* start the filesystem journal operations */
+static void *presto_tmpfs_trans_start(struct presto_file_set *fset, 
+                                   struct inode *inode, 
+                                   int op)
+{
+        return (void *)1; 
+}
+
+static void presto_tmpfs_trans_commit(struct presto_file_set *fset, void *handle)
+{
+        return;
+}
+
+static void presto_tmpfs_journal_file_data(struct inode *inode)
+{
+        return; 
+}
+
+/* The logic here is a slightly modified version of ext3/inode.c:block_to_path
+ */
+static int presto_tmpfs_has_all_data(struct inode *inode)
+{
+        return 0;
+}
+
+struct journal_ops presto_tmpfs_journal_ops = {
+        tr_all_data: presto_tmpfs_has_all_data,
+        tr_avail: presto_tmpfs_freespace,
+        tr_start:  presto_tmpfs_trans_start,
+        tr_commit: presto_tmpfs_trans_commit,
+        tr_journal_data: presto_tmpfs_journal_file_data,
+        tr_ilookup: presto_tmpfs_ilookup,
+        tr_add_ilookup: presto_add_ilookup_dentry
+};
+
+#endif /* CONFIG_EXT3_FS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/journal_xfs.c linux-2.4.20/fs/intermezzo/journal_xfs.c
--- linux-2.4.19/fs/intermezzo/journal_xfs.c	2001-11-13 17:20:56.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/journal_xfs.c	2002-10-29 11:18:49.000000000 +0000
@@ -1,7 +1,23 @@
-
-/*
- *  * Intermezzo. (C) 1998 Peter J. Braam
- *   */
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
 
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -15,13 +31,13 @@
 #include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
+#if 0
+/* XFS Support not there yet */
 #ifdef CONFIG_FS_XFS
 #include <linux/xfs_fs.h>
 #endif
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 #include <linux/intermezzo_journal.h>
 
 #if 0
@@ -120,18 +136,27 @@
 	xfs_trans_stop(handle);
 }
 
-void presto_xfs_journal_file_data(struct inode *inode)
+static void presto_xfs_journal_file_data(struct inode *inode)
 {
         return; 
 }
 
+static int presto_xfs_has_all_data(struct inode *inode)
+{
+        BUG();
+        return 0;
+}
+
 struct journal_ops presto_xfs_journal_ops = {
-        tr_avail: presto_xfs_freespace,
-        tr_start:  presto_xfs_trans_start,
-        tr_commit: presto_xfs_trans_commit,
-        tr_journal_data: presto_xfs_journal_file_data
+        .tr_all_data     = presto_xfs_has_all_data,
+        .tr_avail        = presto_xfs_freespace,
+        .tr_start        = presto_xfs_trans_start,
+        .tr_commit       = presto_xfs_trans_commit,
+        .tr_journal_data = presto_xfs_journal_file_data
 };
 
-#endif /* CONFIG_XFS_FS */
+#endif
 
 
+#endif /* CONFIG_XFS_FS */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/kml.c linux-2.4.20/fs/intermezzo/kml.c
--- linux-2.4.19/fs/intermezzo/kml.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/kml.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,214 +0,0 @@
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <asm/uaccess.h>
-
-#include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
-#include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
-
-static struct presto_file_set * kml_getfset (char *path)
-{
-        return presto_path2fileset(path);
-}
-
-/* Send the KML buffer and related volume info into kernel */
-int begin_kml_reint (struct file *file, unsigned long arg)
-{
-        struct {
-                char *volname;
-                unsigned int namelen;  
-                char *recbuf;
-                unsigned int reclen;     /* int   newpos; */
-        } input;
-        struct kml_fsdata *kml_fsdata = NULL;
-        struct presto_file_set *fset = NULL;
-        char   *path;
-        int    error;
-
-        ENTRY;
-        /* allocate buffer & copy it to kernel space */
-        if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                EXIT;
-                return -EFAULT;
-        }
-
-	if (input.namelen > PATH_MAX)
-	{
-		EXIT;
-		return -EINVAL;
-	}
-		
-        if (input.reclen > kml_fsdata->kml_maxsize)
-                return -ENOMEM; /* we'll find solution to this in the future */
-
-        PRESTO_ALLOC(path, char *, input.namelen + 1);
-        if ( !path ) {
-                EXIT;
-                return -ENOMEM;
-        }
-        if (copy_from_user(path, input.volname, input.namelen)) {
-                PRESTO_FREE(path, input.namelen + 1);
-                EXIT;
-                return -EFAULT;
-        }
-        path[input.namelen] = '\0';
-        fset = kml_getfset (path);
-        PRESTO_FREE(path, input.namelen + 1);
-
-        kml_fsdata = FSET_GET_KMLDATA(fset);
-        /* read the buf from user memory here */
-        if (copy_from_user(kml_fsdata->kml_buf, input.recbuf, input.reclen)) {
-                EXIT;
-                return -EFAULT;
-        }
-        kml_fsdata->kml_len = input.reclen;
-
-        decode_kmlrec (&kml_fsdata->kml_reint_cache,
-                        kml_fsdata->kml_buf, kml_fsdata->kml_len);
-
-        kml_fsdata->kml_reint_current = kml_fsdata->kml_reint_cache.next;
-        kml_fsdata->kml_reintpos = 0;
-        kml_fsdata->kml_count = 0;
-        return 0;
-}
-
-/* DO_KML_REINT  */
-int do_kml_reint (struct file *file, unsigned long arg)
-{
-        struct {
-                char *volname;
-                unsigned int namelen;  
-                char *path;
-                unsigned int pathlen;
-                int recno;
-                int offset;
-                int len;
-                int generation;
-                __u64 ino;
-        } input;
-        int error;
-        char   *path;
-        struct kml_rec *close_rec;
-        struct kml_fsdata *kml_fsdata;
-        struct presto_file_set *fset;
-
-        ENTRY;
-        if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                EXIT;
-                return -EFAULT;
-        }
-        
-        if(input.namelen > PATH_MAX || input.pathlen > PATH_MAX)
-        {
-        	EXIT;
-        	return -EFAULT;
-        }
-        
-        PRESTO_ALLOC(path, char *, input.namelen + 1);
-        if ( !path ) {
-                EXIT;
-                return -ENOMEM;
-        }
-        if (copy_from_user(path, input.volname, input.namelen)) {
-                PRESTO_FREE(path, input.namelen + 1);
-                EXIT;
-                return -EFAULT;
-        }
-        path[input.namelen] = '\0';
-        fset = kml_getfset (path);
-        PRESTO_FREE(path, input.namelen + 1);
-
-        kml_fsdata = FSET_GET_KMLDATA(fset);
-
-        error = kml_reintbuf(kml_fsdata, 
-                fset->fset_mtpt->d_name.name, 
-                &close_rec);
-
-        if (error == KML_CLOSE_BACKFETCH && close_rec != NULL) {
-                struct kml_close *close = &close_rec->rec_kml.close;
-                input.ino = close->ino;
-                input.generation = close->generation;
-                if (strlen (close->path) + 1 < input.pathlen) {
-                        strcpy (input.path, close->path);
-                        input.pathlen = strlen (close->path) + 1;
-                        input.recno = close_rec->rec_tail.recno;
-                        input.offset = close_rec->rec_kml_offset;
-                        input.len = close_rec->rec_size;
-                        input.generation = close->generation;
-                        input.ino = close->ino;
-                }
-                else {
-                        CDEBUG(D_KML, "KML_DO_REINT::no space to save:%d < %d",
-                                strlen (close->path) + 1, input.pathlen);
-                        error = -ENOMEM;
-                }
-                if (copy_to_user((char *)arg, &input, sizeof (input)))
-			return -EFAULT;
-        }
-        return error;
-}
-
-/* END_KML_REINT */
-int end_kml_reint (struct file *file, unsigned long arg)
-{
-        /* Free KML buffer and related volume info */
-        struct {
-                char *volname;
-                unsigned int namelen;  
-#if 0
-                int   count; 
-                int   newpos; 
-#endif
-        } input;
-        struct presto_file_set *fset = NULL;
-        struct kml_fsdata *kml_fsdata = NULL;
-        int error;
-        char *path;
-
-        ENTRY;
-        if (copy_from_user(&input, (char *)arg, sizeof(input))) { 
-               EXIT;
-               return -EFAULT;
-        }
-
-	if (input.namelen > PATH_MAX)
-	{
-		EXIT;
-		return -EFAULT;
-	}
-	
-        PRESTO_ALLOC(path, char *, input.namelen + 1);
-        if ( !path ) {
-                EXIT;
-                return -ENOMEM;
-        }
-        if (copy_from_user(path, input.volname, input.namelen)) {
-        if ( error ) {
-                PRESTO_FREE(path, input.namelen + 1);
-                EXIT;
-                return -EFAULT;
-        }
-        path[input.namelen] = '\0';
-        fset = kml_getfset (path);
-        PRESTO_FREE(path, input.namelen + 1);
-
-        kml_fsdata = FSET_GET_KMLDATA(fset);
-        delete_kmlrec (&kml_fsdata->kml_reint_cache);
-
-        /* kml reint support */
-        kml_fsdata->kml_reint_current = NULL;
-        kml_fsdata->kml_len = 0;
-        kml_fsdata->kml_reintpos = 0;
-        kml_fsdata->kml_count = 0;
-#if 0
-        input.newpos = kml_upc->newpos;
-        input.count = kml_upc->count;
-        if (copy_to_user((char *)arg, &input, sizeof (input)))
-		return -EFAULT;
-#endif
-        return error;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/kml_decode.c linux-2.4.20/fs/intermezzo/kml_decode.c
--- linux-2.4.19/fs/intermezzo/kml_decode.c	2001-11-11 18:20:21.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/kml_decode.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1017 +0,0 @@
-/*
- * KML Decoding
- *
- * Copryright (C) 1996 Arthur Ma <arthur.ma@mountainviewdata.com> 
- *
- * Copyright (C) 2001 Mountainview Data, Inc.
- */
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/mm.h>
-#include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_kml.h>
-
-static int size_round (int val);
-static int unpack_create (struct kml_create *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_open (struct kml_open *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_symlink (struct kml_symlink *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_mknod (struct kml_mknod *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_link (struct kml_link *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_rename (struct kml_rename *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_unlink (struct kml_unlink *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_rmdir (struct kml_rmdir *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_setattr (struct kml_setattr *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_close (struct kml_close *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_mkdir (struct kml_mkdir *rec, char *buf,
-                                int pos, int *rec_offs);
-
-#if 0
-static int unpack_endmark (struct kml_endmark *rec, char *buf,
-                                int pos, int *rec_offs);
-static void print_kml_endmark (struct kml_endmark *rec);
-#endif
-
-static int kml_unpack (char *kml_buf, int rec_size, int kml_offset,
-                        struct kml_rec **newrec);
-static char *kml_version (struct presto_version *ver);
-static void print_kml_prefix (struct big_journal_prefix *head);
-static void print_kml_create (struct kml_create *rec);
-static void print_kml_mkdir (struct kml_mkdir *rec);
-static void print_kml_unlink (struct kml_unlink *rec);
-static void print_kml_rmdir (struct kml_rmdir *rec);
-static void print_kml_close (struct kml_close *rec);
-static void print_kml_symlink (struct kml_symlink *rec);
-static void print_kml_rename (struct kml_rename *rec);
-static void print_kml_setattr (struct kml_setattr *rec);
-static void print_kml_link (struct kml_link *rec);
-static void print_kml_mknod (struct kml_mknod *rec);
-static void print_kml_open (struct kml_open *rec);
-static void print_kml_suffix (struct journal_suffix *tail);
-static char *readrec (char *recbuf, int reclen, int pos, int *size);
-
-#define  KML_PREFIX_WORDS           8
-static int kml_unpack (char *kml_buf, int rec_size, int kml_offset, 
-                        struct kml_rec **newrec)
-{
-        struct kml_rec  *rec;
-        char            *p;
-        int             pos, rec_offs;
-        int             error;
-
-        ENTRY;
-        if (rec_size < sizeof (struct journal_prefix) +
-                       sizeof (struct journal_suffix))
-                return -EBADF;
-
-        PRESTO_ALLOC(rec, struct kml_rec *, sizeof (struct kml_rec));
-        if (rec == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-        rec->rec_kml_offset = kml_offset;
-        rec->rec_size = rec_size;
-        p = kml_buf;
-        p = dlogit (&rec->rec_head, p, KML_PREFIX_WORDS * sizeof (int));
-        p = dlogit (&rec->rec_head.groups, p, 
-                        sizeof (int) * rec->rec_head.ngroups);
-
-        pos = sizeof (struct journal_prefix) + 
-                        sizeof (int) * rec->rec_head.ngroups;
-        switch (rec->rec_head.opcode)
-        {
-                case KML_CREATE:
-                        error = unpack_create (&rec->rec_kml.create, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_MKDIR:
-                        error = unpack_mkdir (&rec->rec_kml.mkdir, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_UNLINK:
-                        error = unpack_unlink (&rec->rec_kml.unlink, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_RMDIR:
-                        error = unpack_rmdir (&rec->rec_kml.rmdir, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_CLOSE:
-                        error = unpack_close (&rec->rec_kml.close, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_SYMLINK:
-                        error = unpack_symlink (&rec->rec_kml.symlink, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_RENAME:
-                        error = unpack_rename (&rec->rec_kml.rename, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_SETATTR:
-                        error = unpack_setattr (&rec->rec_kml.setattr, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_LINK:
-                        error = unpack_link (&rec->rec_kml.link, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_OPEN:
-                        error = unpack_open (&rec->rec_kml.open, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_MKNOD:
-                        error = unpack_mknod (&rec->rec_kml.mknod, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-#if 0
-                case KML_ENDMARK:
-                        error = unpack_endmark (&rec->rec_kml.endmark, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-#endif
-                default:
-                        CDEBUG (D_KML, "wrong opcode::%u\n", 
-                                        rec->rec_head.opcode);
-                        EXIT;
-                        return -EINVAL;
-        } 
-        if (error) {
-                PRESTO_FREE (rec, sizeof (struct kml_rec));
-                return -EINVAL;
-        }
-        p = kml_buf + rec_offs;
-        p = dlogit (&rec->rec_tail, p, sizeof (struct journal_suffix));
-        memset (&rec->kml_optimize, 0, sizeof (struct kml_optimize));
-        *newrec = rec;
-        EXIT;
-        return 0;
-}
-
-static int size_round (int val)
-{
-        return (val + 3) & (~0x3);
-}
-
-static int unpack_create (struct kml_create *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 88;
-        int pathlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->mode, p, sizeof (int));
-        p = dlogit (&rec->uid, p, sizeof (int));
-        p = dlogit (&rec->gid, p, sizeof (int));
-        p = dlogit (&pathlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->path = q;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_open (struct kml_open *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        *rec_offs = pos;
-        return 0;
-}
-
-static int unpack_symlink (struct kml_symlink *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 88;
-        int pathlen, targetlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->uid, p, sizeof (int));
-        p = dlogit (&rec->gid, p, sizeof (int));
-        p = dlogit (&pathlen, p, sizeof (int));
-        p = dlogit (&targetlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->sourcepath = q;
-
-        PRESTO_ALLOC(q, char *, targetlen + 1);
-        if (q == NULL) {
-                PRESTO_FREE (rec->sourcepath, pathlen + 1);
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, targetlen);
-        q[targetlen] = '\0';
-        rec->targetpath = q;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen) +
-                        size_round(targetlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_mknod (struct kml_mknod *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 96;
-        int pathlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->mode, p, sizeof (int));
-        p = dlogit (&rec->uid, p, sizeof (int));
-        p = dlogit (&rec->gid, p, sizeof (int));
-        p = dlogit (&rec->major, p, sizeof (int));
-        p = dlogit (&rec->minor, p, sizeof (int));
-        p = dlogit (&pathlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->path = q;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_link (struct kml_link *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 80;
-        int pathlen, targetlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&pathlen, p, sizeof (int));
-        p = dlogit (&targetlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->sourcepath = q;
-        p += size_round (pathlen);
-
-        PRESTO_ALLOC(q, char *, targetlen + 1);
-        if (q == NULL) {
-                PRESTO_FREE (rec->sourcepath, pathlen + 1);
-                EXIT;
-                return -ENOMEM;
-        }
-        memcpy (q, p, targetlen);
-        q[targetlen] = '\0';
-        rec->targetpath = q;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen) +
-                        size_round(targetlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_rename (struct kml_rename *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 104;
-        int pathlen, targetlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_tgtv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->old_tgtv, p, sizeof (struct presto_version));
-        p = dlogit (&pathlen, p, sizeof (int));
-        p = dlogit (&targetlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->sourcepath = q;
-        p += size_round (pathlen);
-
-        PRESTO_ALLOC(q, char *, targetlen + 1);
-        if (q == NULL) {
-                PRESTO_FREE (rec->sourcepath, pathlen + 1);
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, targetlen);
-        q[targetlen] = '\0';
-        rec->targetpath = q;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen) +
-                        size_round(targetlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_unlink (struct kml_unlink *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 80;
-        int pathlen, targetlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->old_tgtv, p, sizeof (struct presto_version));
-        p = dlogit (&pathlen, p, sizeof (int));
-        p = dlogit (&targetlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->path = q;
-        p += size_round (pathlen);
-
-        PRESTO_ALLOC(q, char *, targetlen + 1);
-        if (q == NULL) {
-                PRESTO_FREE (rec->path, pathlen + 1);
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, targetlen);
-        q[targetlen] = '\0';
-        rec->name = q;
-
-        /* fix the presto_journal_unlink problem */
-        *rec_offs = pos + unpack_size + size_round(pathlen) +
-                        size_round(targetlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_rmdir (struct kml_rmdir *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 80;
-        int pathlen, targetlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->old_tgtv, p, sizeof (struct presto_version));
-        p = dlogit (&pathlen, p, sizeof (int));
-        p = dlogit (&targetlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->path = q;
-        p += size_round (pathlen);
-
-        PRESTO_ALLOC(q, char *, targetlen + 1);
-        if (q == NULL) {
-                PRESTO_FREE (rec->path, pathlen + 1);
-                EXIT;
-                return -ENOMEM;
-        }
-        memcpy (q, p, targetlen);
-        q[targetlen] = '\0';
-        rec->name = q;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen) +
-                        size_round(targetlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_setattr (struct kml_setattr *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 72;
-        struct kml_attr {
-                __u64   size, mtime, ctime;
-        } objattr;
-        int     valid, mode, uid, gid, flags;
-        int pathlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&valid, p, sizeof (int));
-        p = dlogit (&mode, p, sizeof (int));
-        p = dlogit (&uid, p, sizeof (int));
-        p = dlogit (&gid, p, sizeof (int));
-        p = dlogit (&objattr, p, sizeof (struct kml_attr));
-        p = dlogit (&flags, p, sizeof (int));
-        p = dlogit (&pathlen, p, sizeof (int));
-
-        rec->iattr.ia_valid = valid;
-        rec->iattr.ia_mode = mode;
-        rec->iattr.ia_uid = uid;
-        rec->iattr.ia_gid = gid;
-        rec->iattr.ia_size = objattr.size;
-        rec->iattr.ia_mtime = objattr.mtime;
-        rec->iattr.ia_ctime = objattr.ctime;
-        rec->iattr.ia_atime = 0;
-        rec->iattr.ia_attr_flags = flags;
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->path = q;
-        p += pathlen;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_close (struct kml_close *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 52;
-        int pathlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->open_mode, p, sizeof (int));
-        p = dlogit (&rec->open_uid, p, sizeof (int));
-        p = dlogit (&rec->open_gid, p, sizeof (int));
-        p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->ino, p, sizeof (__u64));
-        p = dlogit (&rec->generation, p, sizeof (int));
-        p = dlogit (&pathlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->path = q;
-        p += pathlen;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_mkdir (struct kml_mkdir *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 88;
-        int pathlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->mode, p, sizeof (int));
-        p = dlogit (&rec->uid, p, sizeof (int));
-        p = dlogit (&rec->gid, p, sizeof (int));
-        p = dlogit (&pathlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->path = q;
-        p += pathlen;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen);
-        EXIT;
-        return 0;
-}
-
-#if 0
-static int unpack_endmark (struct kml_endmark *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p;
-        p = buf + pos;
-        p = dlogit (&rec->total, p, sizeof (int));
-
-        PRESTO_ALLOC (rec->kop, struct kml_kop_node *, 
-                        sizeof (struct kml_kop_node) * rec->total);
-        if (rec->kop == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        p = dlogit (rec->kop, p, sizeof (struct kml_kop_node) * rec->total);
-
-        *rec_offs = pos + sizeof (int) + sizeof (struct kml_kop_node) * rec->total;
-        return 0;
-}
-#endif
-
-static char *kml_version (struct presto_version *ver)
-{
-        static char buf[256];
-        sprintf (buf, "mt::%lld, ct::%lld, size::%lld",
-                ver->pv_mtime, ver->pv_ctime, ver->pv_size); 
-        return buf;
-}
-
-static void print_kml_prefix (struct big_journal_prefix *head)
-{
-        int i;
-
-        CDEBUG (D_KML, " === KML PREFIX\n");
-        CDEBUG (D_KML, "     len        = %u\n", head->len);
-        CDEBUG (D_KML, "     version    = %u\n", head->version);
-        CDEBUG (D_KML, "     pid        = %u\n", head->pid);
-        CDEBUG (D_KML, "     uid        = %u\n", head->uid);
-        CDEBUG (D_KML, "     fsuid      = %u\n", head->fsuid);
-        CDEBUG (D_KML, "     fsgid      = %u\n", head->fsgid);
-        CDEBUG (D_KML, "     opcode     = %u\n", head->opcode);
-        CDEBUG (D_KML, "     ngroup     = %u",  head->ngroups);
-        for (i = 0; i < head->ngroups; i++)
-                CDEBUG (D_KML, "%u  ",  head->groups[i]);
-        CDEBUG (D_KML, "\n");
-}
-
-static void print_kml_create (struct kml_create *rec)
-{
-        CDEBUG (D_KML, " === CREATE\n");
-        CDEBUG (D_KML, "     path::%s\n", rec->path);
-        CDEBUG (D_KML, "     new_objv::%s\n", kml_version (&rec->new_objectv));
-        CDEBUG (D_KML, "     old_parv::%s\n", kml_version (&rec->old_parentv));
-        CDEBUG (D_KML, "     new_parv::%s\n", kml_version (&rec->new_parentv));
-        CDEBUG (D_KML, "     mode::%o\n", rec->mode);
-        CDEBUG (D_KML, "     uid::%d\n", rec->uid);
-        CDEBUG (D_KML, "     gid::%d\n", rec->gid);
-}
-
-static void print_kml_mkdir (struct kml_mkdir *rec)
-{
-        CDEBUG (D_KML, " === MKDIR\n");
-        CDEBUG (D_KML, "     path::%s\n", rec->path);
-        CDEBUG (D_KML, "     new_objv::%s\n", kml_version (&rec->new_objectv));
-        CDEBUG (D_KML, "     old_parv::%s\n", kml_version (&rec->old_parentv));
-        CDEBUG (D_KML, "     new_parv::%s\n", kml_version (&rec->new_parentv));
-        CDEBUG (D_KML, "     mode::%o\n", rec->mode);
-        CDEBUG (D_KML, "     uid::%d\n", rec->uid);
-        CDEBUG (D_KML, "     gid::%d\n", rec->gid);
-}
-
-static void print_kml_unlink (struct kml_unlink *rec)
-{
-        CDEBUG (D_KML, " === UNLINK\n");
-        CDEBUG (D_KML, "     path::%s/%s\n", rec->path, rec->name);
-        CDEBUG (D_KML, "     old_tgtv::%s\n", kml_version (&rec->old_tgtv));
-        CDEBUG (D_KML, "     old_parv::%s\n", kml_version (&rec->old_parentv));
-        CDEBUG (D_KML, "     new_parv::%s\n", kml_version (&rec->new_parentv));
-}
-
-static void print_kml_rmdir (struct kml_rmdir *rec)
-{
-        CDEBUG (D_KML, " === RMDIR\n");
-        CDEBUG (D_KML, "     path::%s/%s\n", rec->path, rec->name);
-        CDEBUG (D_KML, "     old_tgtv::%s\n", kml_version (&rec->old_tgtv));
-        CDEBUG (D_KML, "     old_parv::%s\n", kml_version (&rec->old_parentv));
-        CDEBUG (D_KML, "     new_parv::%s\n", kml_version (&rec->new_parentv));
-}
-
-static void print_kml_close (struct kml_close *rec)
-{
-        CDEBUG (D_KML, " === CLOSE\n");
-        CDEBUG (D_KML, "     mode::%o\n", rec->open_mode);
-        CDEBUG (D_KML, "     uid::%d\n", rec->open_uid);
-        CDEBUG (D_KML, "     gid::%d\n", rec->open_gid);
-        CDEBUG (D_KML, "     path::%s\n", rec->path);
-        CDEBUG (D_KML, "     new_objv::%s\n", kml_version (&rec->new_objectv));
-        CDEBUG (D_KML, "     ino::%lld\n", rec->ino);
-        CDEBUG (D_KML, "     gen::%u\n", rec->generation);
-}
-
-static void print_kml_symlink (struct kml_symlink *rec)
-{
-        CDEBUG (D_KML, " === SYMLINK\n");
-        CDEBUG (D_KML, "     s-path::%s\n", rec->sourcepath);
-        CDEBUG (D_KML, "     t-path::%s\n", rec->targetpath);
-        CDEBUG (D_KML, "     old_parv::%s\n", kml_version (&rec->old_parentv));
-        CDEBUG (D_KML, "     new_parv::%s\n", kml_version (&rec->new_parentv));
-        CDEBUG (D_KML, "     new_objv::%s\n", kml_version (&rec->new_objectv));
-        CDEBUG (D_KML, "     uid::%d\n", rec->uid);
-        CDEBUG (D_KML, "     gid::%d\n", rec->gid);
-}
-
-static void print_kml_rename (struct kml_rename *rec)
-{
-        CDEBUG (D_KML, " === RENAME\n");
-        CDEBUG (D_KML, "     s-path::%s\n", rec->sourcepath);
-        CDEBUG (D_KML, "     t-path::%s\n", rec->targetpath);
-        CDEBUG (D_KML, "     old_tgtv::%s\n", kml_version (&rec->old_tgtv));
-        CDEBUG (D_KML, "     new_tgtv::%s\n", kml_version (&rec->new_tgtv));
-        CDEBUG (D_KML, "     new_objv::%s\n", kml_version (&rec->new_objectv));
-        CDEBUG (D_KML, "     old_objv::%s\n", kml_version (&rec->old_objectv));
-}
-
-static void print_kml_setattr (struct kml_setattr *rec)
-{
-        CDEBUG (D_KML, " === SETATTR\n");
-        CDEBUG (D_KML, "     path::%s\n", rec->path);
-        CDEBUG (D_KML, "     old_objv::%s\n", kml_version (&rec->old_objectv));
-        CDEBUG (D_KML, "     valid::0x%x\n", rec->iattr.ia_valid);
-        CDEBUG (D_KML, "     mode::%o\n", rec->iattr.ia_mode);
-        CDEBUG (D_KML, "     uid::%d\n", rec->iattr.ia_uid);
-        CDEBUG (D_KML, "     gid::%d\n", rec->iattr.ia_gid);
-        CDEBUG (D_KML, "     size::%u\n", (u32) rec->iattr.ia_size);
-        CDEBUG (D_KML, "     mtime::%u\n", (u32) rec->iattr.ia_mtime);
-        CDEBUG (D_KML, "     ctime::%u\n", (u32) rec->iattr.ia_ctime);
-        CDEBUG (D_KML, "     flags::%u\n", (u32) rec->iattr.ia_attr_flags);
-}
-
-static void print_kml_link (struct kml_link *rec)
-{
-        CDEBUG (D_KML, " === LINK\n");
-        CDEBUG (D_KML, "     path::%s ==> %s\n", rec->sourcepath, rec->targetpath);
-        CDEBUG (D_KML, "     old_parv::%s\n", kml_version (&rec->old_parentv));
-        CDEBUG (D_KML, "     new_obj::%s\n", kml_version (&rec->new_objectv));
-        CDEBUG (D_KML, "     new_parv::%s\n", kml_version (&rec->new_parentv));
-}
-
-static void print_kml_mknod (struct kml_mknod *rec)
-{
-        CDEBUG (D_KML, " === MKNOD\n");
-        CDEBUG (D_KML, "     path::%s\n", rec->path);
-        CDEBUG (D_KML, "     new_obj::%s\n", kml_version (&rec->new_objectv));
-        CDEBUG (D_KML, "     old_parv::%s\n", kml_version (&rec->old_parentv));
-        CDEBUG (D_KML, "     new_parv::%s\n", kml_version (&rec->new_parentv));
-        CDEBUG (D_KML, "     mode::%o\n", rec->mode);
-        CDEBUG (D_KML, "     uid::%d\n", rec->uid);
-        CDEBUG (D_KML, "     gid::%d\n", rec->gid);
-        CDEBUG (D_KML, "     major::%d\n", rec->major);
-        CDEBUG (D_KML, "     minor::%d\n", rec->minor);
-}
-
-static void print_kml_open (struct kml_open *rec)
-{
-        CDEBUG (D_KML, " === OPEN\n");
-}
-
-#if 0
-static void print_kml_endmark (struct kml_endmark *rec)
-{
-        int i;
-        CDEBUG (D_KML, " === ENDMARK\n");
-        CDEBUG (D_KML, "     total::%u\n", rec->total);
-        for (i = 0; i < rec->total; i++)
-        {       
-                CDEBUG (D_KML, "         recno=%ld::flag=%ld,op=%ld, i_ino=%ld, \
-                        i_nlink=%ld\n", (long) rec->kop[i].kml_recno, 
-                        (long) rec->kop[i].kml_flag, (long) rec->kop[i].kml_op, 
-                        (long) rec->kop[i].i_ino, (long) rec->kop[i].i_nlink);
-        }
-}
-#endif
-
-static void print_kml_optimize (struct kml_optimize  *rec)
-{
-        CDEBUG (D_KML, " === OPTIMIZE\n");
-        if (rec->kml_flag == KML_REC_DELETE)
-                CDEBUG (D_KML, "     kml_flag::deleted\n");
-        else
-                CDEBUG (D_KML, "     kml_flag::exist\n");
-        CDEBUG (D_KML, "     kml_op::%u\n", rec->kml_op);
-        CDEBUG (D_KML, "     i_nlink::%d\n", rec->i_nlink);
-        CDEBUG (D_KML, "     i_ino::%u\n", rec->i_ino);
-}
-
-static void print_kml_suffix (struct journal_suffix *tail)
-{
-        CDEBUG (D_KML, " === KML SUFFIX\n");
-        CDEBUG (D_KML, "     prevrec::%ld\n", tail->prevrec);
-        CDEBUG (D_KML, "     recno::%ld\n", (long) tail->recno);
-        CDEBUG (D_KML, "     time::%d\n", tail->time);
-        CDEBUG (D_KML, "     len::%d\n", tail->len);
-}
-
-void kml_printrec (struct kml_rec *rec, int kml_printop)
-{
-        if (kml_printop & PRINT_KML_PREFIX)
-                print_kml_prefix (&rec->rec_head);
-        if (kml_printop & PRINT_KML_REC) 
-        { 
-                switch (rec->rec_head.opcode)
-                {
-                        case KML_CREATE:
-                                print_kml_create (&rec->rec_kml.create);
-                                break;
-                        case KML_MKDIR:
-                                print_kml_mkdir (&rec->rec_kml.mkdir);
-                                break;
-                        case KML_UNLINK:
-                                print_kml_unlink (&rec->rec_kml.unlink);
-                                break;
-                        case KML_RMDIR:
-                                print_kml_rmdir (&rec->rec_kml.rmdir);
-                                break;
-                        case KML_CLOSE:
-                                print_kml_close (&rec->rec_kml.close);
-                                break;
-                        case KML_SYMLINK:
-                                print_kml_symlink (&rec->rec_kml.symlink);
-                                break;
-                        case KML_RENAME:
-                                print_kml_rename (&rec->rec_kml.rename);
-                                break;
-                        case KML_SETATTR:
-                                print_kml_setattr (&rec->rec_kml.setattr);
-                                break;
-                        case KML_LINK:
-                                print_kml_link (&rec->rec_kml.link);
-                                break;
-                        case KML_OPEN:
-                                print_kml_open (&rec->rec_kml.open);
-                                break;
-                        case KML_MKNOD:
-                                print_kml_mknod (&rec->rec_kml.mknod);
-                                break;
-#if 0
-                        case KML_ENDMARK:
-                                print_kml_endmark (&rec->rec_kml.endmark);
-#endif
-                                break;
-                        default:
-                                CDEBUG (D_KML, " === BAD RECORD, opcode=%u\n",
-                                        rec->rec_head.opcode);
-                                break;
-                }
-        }
-        if (kml_printop & PRINT_KML_SUFFIX)
-                print_kml_suffix (&rec->rec_tail);
-        if (kml_printop & PRINT_KML_OPTIMIZE)
-                print_kml_optimize (&rec->kml_optimize);
-}
-
-void kml_freerec (struct kml_rec *rec)
-{
-        char *sourcepath = NULL,
-             *targetpath = NULL;
-        switch (rec->rec_head.opcode)
-        {
-                case KML_CREATE:
-                        sourcepath = rec->rec_kml.create.path;
-                        break;
-                case KML_MKDIR:
-                        sourcepath = rec->rec_kml.create.path;
-                        break;
-                case KML_UNLINK:
-                        sourcepath = rec->rec_kml.unlink.path;
-                        targetpath = rec->rec_kml.unlink.name;
-                        break;
-                case KML_RMDIR:
-                        sourcepath = rec->rec_kml.rmdir.path;
-                        targetpath = rec->rec_kml.rmdir.name;
-                        break;
-                case KML_CLOSE:
-                        sourcepath = rec->rec_kml.close.path;
-                        break;
-                case KML_SYMLINK:
-                        sourcepath = rec->rec_kml.symlink.sourcepath;
-                        targetpath = rec->rec_kml.symlink.targetpath;
-                        break;
-                case KML_RENAME:
-                        sourcepath = rec->rec_kml.rename.sourcepath;
-                        targetpath = rec->rec_kml.rename.targetpath;
-                        break;
-                case KML_SETATTR:
-                        sourcepath = rec->rec_kml.setattr.path;
-                        break;
-                case KML_LINK:
-                        sourcepath = rec->rec_kml.link.sourcepath;
-                        targetpath = rec->rec_kml.link.targetpath;
-                        break;
-                case KML_OPEN:
-                        break;
-                case KML_MKNOD:
-                        sourcepath = rec->rec_kml.mknod.path;
-                        break;
-#if 0
-                case KML_ENDMARK:
-                        PRESTO_FREE (rec->rec_kml.endmark.kop, sizeof (int) + 
-                                sizeof (struct kml_kop_node) * 
-                                rec->rec_kml.endmark.total);
-#endif
-                        break;
-                default:
-                        break;
-        }
-        if (sourcepath != NULL)
-                PRESTO_FREE (sourcepath, strlen (sourcepath) + 1);
-        if (targetpath != NULL)
-                PRESTO_FREE (targetpath, strlen (targetpath) + 1);
-}
-
-char *readrec (char *recbuf, int reclen, int pos, int *size)
-{
-        char *p = recbuf + pos;
-        *size = *((int *) p);
-        if (*size > (reclen - pos))
-            return NULL;
-        return p; 
-}
-
-int kml_decoderec (char *buf, int pos, int buflen, int *size, 
-                        struct kml_rec **newrec)
-{
-        char *tmp;
-        int  error;
-        tmp = readrec (buf, buflen, pos, size);
-        if (tmp == NULL)
-                return -EBADF;
-        error = kml_unpack (tmp, *size, pos, newrec); 
-        return error;
-}
-
-#if 0
-static void fill_kmlrec_optimize (struct list_head *head, 
-                struct kml_rec *optrec)
-{
-        struct kml_rec *kmlrec;
-        struct list_head *tmp;
-        struct kml_endmark *km;
-        struct kml_optimize *ko;
-        int    n;
-
-        if (optrec->rec_kml.endmark.total == 0)
-                return;
-        n = optrec->rec_kml.endmark.total - 1;
-        tmp = head->prev;
-        km = &optrec->rec_kml.endmark;
-        while ( n >= 0 && tmp != head ) 
-        {
-                kmlrec = list_entry(tmp, struct kml_rec,
-                        kml_optimize.kml_chains);
-                tmp = tmp->prev;
-                if (kmlrec->rec_tail.recno == km->kop[n].kml_recno) 
-                {
-                        ko = &kmlrec->kml_optimize;
-                        ko->kml_flag = km->kop[n].kml_flag;
-                        ko->kml_op   = km->kop[n].kml_op;
-                        ko->i_nlink  = km->kop[n].i_nlink;
-                        ko->i_ino    = km->kop[n].i_ino;
-                        n --;
-                }
-        }
-        if (n != -1)
-                CDEBUG (D_KML, "Yeah!!!, KML optimize error, recno=%d, n=%d\n",
-                        optrec->rec_tail.recno, n);     
-}
-#endif
-
-int decode_kmlrec (struct list_head *head, char *kml_buf, int buflen)
-{
-        struct kml_rec *rec;
-        int    pos = 0, size;
-        int    err;
-        while (pos < buflen) {
-                err = kml_decoderec (kml_buf, pos, buflen, &size, &rec);
-                if (err != 0)
-                        break;
-#if 0
-                if (rec->rec_head.opcode == KML_ENDMARK) {
-                        fill_kmlrec_optimize (head, rec);
-                        mark_rec_deleted (rec);
-                }
-#endif
-                list_add_tail (&rec->kml_optimize.kml_chains, head);
-                pos += size;
-        }
-        return err;
-}
-
-int delete_kmlrec (struct list_head *head)
-{
-        struct kml_rec *rec;
-        struct list_head *tmp;
-
-        if (list_empty(head))
-                return 0;
-        tmp = head->next;
-        while ( tmp != head ) {
-                rec = list_entry(tmp, struct kml_rec, 
-                        kml_optimize.kml_chains);
-                tmp = tmp->next;
-                kml_freerec (rec);
-        }
-        INIT_LIST_HEAD(head);
-        return 0;
-}
-
-int print_allkmlrec (struct list_head *head, int printop)
-{
-        struct kml_rec *rec;
-        struct list_head *tmp;
-
-        if (list_empty(head))
-                return 0;
-        tmp = head->next;
-        while ( tmp != head ) {
-                rec = list_entry(tmp, struct kml_rec,
-                        kml_optimize.kml_chains);
-                tmp = tmp->next;
-#if 0
-                if (printop & PRINT_KML_EXIST) {
-                        if (is_deleted_node (rec))
-                                continue;
-                }
-                else if (printop & PRINT_KML_DELETE) {
-                        if (! is_deleted_node (rec))
-                                continue;
-                }
-#endif
-                kml_printrec (rec, printop);
-        }
-        INIT_LIST_HEAD(head);
-        return 0;
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/kml_reint.c linux-2.4.20/fs/intermezzo/kml_reint.c
--- linux-2.4.19/fs/intermezzo/kml_reint.c	2001-11-11 18:20:21.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/kml_reint.c	2002-10-29 11:18:49.000000000 +0000
@@ -1,9 +1,25 @@
-/*
- * KML REINT
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
- * Copryright (C) 1996 Arthur Ma <arthur.ma@mountainviewdata.com>
+ *  Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Reintegration of KML records
  *
- * Copyright (C) 2000 Mountainview Data, Inc.
  */
 
 #define __NO_VERSION__
@@ -19,393 +35,596 @@
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_kml.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_upcall.h>
-
-static void kmlreint_pre_secure (struct kml_rec *rec);
-static void kmlreint_post_secure (struct kml_rec *rec);
 
-static void kmlreint_pre_secure (struct kml_rec *rec)
+static void kmlreint_pre_secure(struct kml_rec *rec, struct file *dir,
+                                struct run_ctxt *saved)
 {
-        if (current->fsuid != current->uid)
-                CDEBUG (D_KML, "reint_kmlreint_pre_secure: cannot setfsuid\n");
-        if (current->fsgid != current->gid)
-                CDEBUG (D_KML, "reint_kmlreint_pre_secure: cannot setfsgid\n");
-        current->fsuid = rec->rec_head.uid;
-        current->fsgid = rec->rec_head.fsgid;
+        struct run_ctxt ctxt; 
+        struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
+        int i;
+
+        ctxt.fsuid = rec->prefix.hdr->fsuid;
+        ctxt.fsgid = rec->prefix.hdr->fsgid;
+        ctxt.fs = KERNEL_DS; 
+        ctxt.pwd = dd->dd_fset->fset_dentry;
+        ctxt.pwdmnt = dd->dd_fset->fset_mnt;
+
+        ctxt.root = ctxt.pwd;
+        ctxt.rootmnt = ctxt.pwdmnt;
+        if (rec->prefix.hdr->ngroups > 0) {
+                ctxt.ngroups = rec->prefix.hdr->ngroups;
+                for (i = 0; i< ctxt.ngroups; i++) 
+                        ctxt.groups[i] = rec->prefix.groups[i];
+        } else
+                ctxt.ngroups = 0;
+
+        push_ctxt(saved, &ctxt);
+}
+
+
+/* Append two strings in a less-retarded fashion. */
+static char * path_join(char *p1, int p1len, char *p2, int p2len)
+{
+        int size = p1len + p2len + 2; /* possibly one extra /, one NULL */
+        char *path;
+
+        path = kmalloc(size, GFP_KERNEL);
+        if (path == NULL)
+                return NULL;
+
+        memcpy(path, p1, p1len);
+        if (path[p1len - 1] != '/') {
+                path[p1len] = '/';
+                p1len++;
+        }
+        memcpy(path + p1len, p2, p2len);
+        path[p1len + p2len] = '\0';
+
+        return path;
 }
 
-static void kmlreint_post_secure (struct kml_rec *rec)
+static inline int kml_recno_equal(struct kml_rec *rec,
+                                  struct presto_file_set *fset)
 {
-        current->fsuid = current->uid; 
-        current->fsgid = current->gid;
-        /* current->egid = current->gid; */ 
-        /* ????????????? */
+        return (rec->suffix->recno == fset->fset_lento_recno + 1);
 }
 
-static int reint_create (int slot_offset, struct kml_rec *rec)
+static inline int version_equal(struct presto_version *a, struct inode *inode)
 {
-        struct  lento_vfs_context info;
-        struct  kml_create *create = &rec->rec_kml.create;
-        mm_segment_t old_fs;
-        int     error;
+        if (a == NULL)
+                return 1;
+
+        if (inode == NULL) {
+                CERROR("InterMezzo: NULL inode in version_equal()\n");
+                return 0;
+        }
+
+        if (inode->i_mtime == a->pv_mtime &&
+            (S_ISDIR(inode->i_mode) || inode->i_size == a->pv_size))
+                return 1;
 
+        return 0;
+}
+
+static int reint_close(struct kml_rec *rec, struct file *file,
+                       struct lento_vfs_context *given_info)
+{
+        struct run_ctxt saved_ctxt;
+        int error;
+        struct presto_file_set *fset;
+        struct lento_vfs_context info; 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0; 
+        memcpy(&info, given_info, sizeof(*given_info));
 
-        CDEBUG (D_KML, "=====REINT_CREATE::%s\n", create->path);
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_create(create->path, create->mode, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
+
+        CDEBUG (D_KML, "=====REINT_CLOSE::%s\n", rec->path);
+
+        fset = presto_fset(file->f_dentry);
+        if (fset->fset_flags & FSET_DATA_ON_DEMAND) {
+                struct iattr iattr;
+
+                iattr.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_SIZE;
+                iattr.ia_mtime = (time_t)rec->new_objectv->pv_mtime;
+                iattr.ia_ctime = (time_t)rec->new_objectv->pv_ctime;
+                iattr.ia_size = (time_t)rec->new_objectv->pv_size;
+
+                /* no kml record, but update last rcvd */
+                /* save fileid in dentry for later backfetch */
+                info.flags |= LENTO_FL_EXPECT | LENTO_FL_SET_DDFILEID;
+                info.remote_ino = rec->ino;
+                info.remote_generation = rec->generation;
+                info.flags &= ~LENTO_FL_KML;
+                kmlreint_pre_secure(rec, file, &saved_ctxt);
+                error = lento_setattr(rec->path, &iattr, &info);
+                pop_ctxt(&saved_ctxt);
+
+                presto_d2d(file->f_dentry)->dd_flags &= ~PRESTO_DATA;
+        } else {
+                int minor = presto_f2m(fset);
+
+                info.updated_time = rec->new_objectv->pv_mtime;
+                memcpy(&info.remote_version, rec->old_objectv, 
+                       sizeof(*rec->old_objectv));
+                info.remote_ino = rec->ino;
+                info.remote_generation = rec->generation;
+                error = izo_upc_backfetch(minor, rec->path, fset->fset_name,
+                                          &info);
+                if (error) {
+                        CERROR("backfetch error %d\n", error);
+                        /* if file doesn't exist anymore,  then ignore the CLOSE
+                         * and just update the last_rcvd.
+                         */
+                        if (error == ENOENT) {
+                                CDEBUG(D_KML, "manually updating remote offset uuid %s"
+                                       "recno %d offset %Lu\n", info.uuid, info.recno, info.kml_offset);
+                                error = izo_rcvd_upd_remote(fset, info.uuid, info.recno, info.kml_offset);
+                                if(error)
+                                        CERROR("izo_rcvd_upd_remote error %d\n", error);
+
+                        } 
+                }
+                        
+                /* propagate error to avoid further reint */
+        }
 
         EXIT;
         return error;
 }
 
-static int reint_open (int slot_offset, struct kml_rec *rec)
+static int reint_create(struct kml_rec *rec, struct file *dir,
+                        struct lento_vfs_context *info)
 {
-        return 0;
+        struct run_ctxt saved_ctxt;
+        int     error;        ENTRY;
+
+        CDEBUG (D_KML, "=====REINT_CREATE::%s\n", rec->path);
+        info->updated_time = rec->new_objectv->pv_ctime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_create(rec->path, rec->mode, info);
+        pop_ctxt(&saved_ctxt); 
+
+        EXIT;
+        return error;
 }
 
-static int reint_mkdir (int slot_offset, struct kml_rec *rec)
+static int reint_link(struct kml_rec *rec, struct file *dir,
+                      struct lento_vfs_context *info)
 {
-        struct  lento_vfs_context info;
-        struct  kml_mkdir *mkdir = &rec->rec_kml.mkdir;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
         int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0; 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_mkdir (mkdir->path, mkdir->mode, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
+        CDEBUG (D_KML, "=====REINT_LINK::%s -> %s\n", rec->path, rec->target);
+        info->updated_time = rec->new_objectv->pv_mtime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_link(rec->path, rec->target, info);
+        pop_ctxt(&saved_ctxt); 
 
         EXIT;
         return error;
 }
 
-static int reint_rmdir (int slot_offset, struct kml_rec *rec)
+static int reint_mkdir(struct kml_rec *rec, struct file *dir,
+                       struct lento_vfs_context *info)
 {
-        struct  kml_rmdir  *rmdir = &rec->rec_kml.rmdir;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
-        char *name;
-        int error;
+        struct run_ctxt saved_ctxt;
+        int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
-        name = bdup_printf ("%s/%s", rmdir->path, rmdir->name);
-        if (name == NULL)
-        {
-                kmlreint_post_secure (rec);
-                EXIT;
-                return -ENOMEM;
-        }
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0;
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_rmdir (name, &info);
-        set_fs (old_fs);
+        CDEBUG (D_KML, "=====REINT_MKDIR::%s\n", rec->path);
+        info->updated_time = rec->new_objectv->pv_ctime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_mkdir(rec->path, rec->mode, info);
+        pop_ctxt(&saved_ctxt); 
+
+        EXIT;
+        return error;
+}
+
+static int reint_mknod(struct kml_rec *rec, struct file *dir,
+                       struct lento_vfs_context *info)
+{
+        struct run_ctxt saved_ctxt;
+        int     error, dev;
+
+        ENTRY;
+
+        CDEBUG (D_KML, "=====REINT_MKNOD::%s\n", rec->path);
+        info->updated_time = rec->new_objectv->pv_ctime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+
+        dev = rec->rdev ?: MKDEV(rec->major, rec->minor);
+
+        error = lento_mknod(rec->path, rec->mode, dev, info);
+        pop_ctxt(&saved_ctxt); 
 
-        PRESTO_FREE (name, strlen (name) + 1);
-        kmlreint_post_secure (rec);
         EXIT;
         return error;
 }
 
-static int reint_link (int slot_offset, struct kml_rec *rec)
+
+static int reint_noop(struct kml_rec *rec, struct file *dir,
+                      struct lento_vfs_context *info)
+{
+        return 0;
+}
+
+static int reint_rename(struct kml_rec *rec, struct file *dir,
+                        struct lento_vfs_context *info)
 {
-        struct  kml_link *link = &rec->rec_kml.link;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
         int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0; 
+        CDEBUG (D_KML, "=====REINT_RENAME::%s -> %s\n", rec->path, rec->target);
+        info->updated_time = rec->new_objectv->pv_mtime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_rename(rec->path, rec->target, info);
+        pop_ctxt(&saved_ctxt); 
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_link (link->sourcepath, link->targetpath, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
         EXIT;
         return error;
 }
 
-static int reint_unlink (int slot_offset, struct kml_rec *rec)
+static int reint_rmdir(struct kml_rec *rec, struct file *dir,
+                       struct lento_vfs_context *info)
 {
-        struct  kml_unlink *unlink = &rec->rec_kml.unlink;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
         int     error;
-        char   *name;
+        char *path;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
-        name = bdup_printf ("%s/%s", unlink->path, unlink->name);
-        if (name == NULL)
-        {
-                kmlreint_post_secure (rec);
+
+        path = path_join(rec->path, rec->pathlen - 1, rec->target, rec->targetlen);
+        if (path == NULL) {
                 EXIT;
                 return -ENOMEM;
         }
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0;
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_unlink (name, &info);
-        set_fs (old_fs);
-        PRESTO_FREE (name, strlen (name));
-        kmlreint_post_secure (rec);
+        CDEBUG (D_KML, "=====REINT_RMDIR::%s\n", path);
+        info->updated_time = rec->new_parentv->pv_mtime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_rmdir(path, info);
+        pop_ctxt(&saved_ctxt); 
 
+        kfree(path);
         EXIT;
         return error;
 }
 
-static int reint_symlink (int slot_offset, struct kml_rec *rec)
+static int reint_setattr(struct kml_rec *rec, struct file *dir,
+                         struct lento_vfs_context *info)
 {
-        struct  kml_symlink *symlink = &rec->rec_kml.symlink;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
+        struct iattr iattr;
         int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0; 
+        iattr.ia_valid = rec->valid;
+        iattr.ia_mode  = (umode_t)rec->mode;
+        iattr.ia_uid   = (uid_t)rec->uid;
+        iattr.ia_gid   = (gid_t)rec->gid;
+        iattr.ia_size  = (off_t)rec->size;
+        iattr.ia_ctime = (time_t)rec->ctime;
+        iattr.ia_mtime = (time_t)rec->mtime;
+        iattr.ia_atime = iattr.ia_mtime; /* We don't track atimes. */
+        iattr.ia_attr_flags = rec->flags;
+
+        CDEBUG (D_KML, "=====REINT_SETATTR::%s (%d)\n", rec->path, rec->valid);
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_setattr(rec->path, &iattr, info);
+        pop_ctxt(&saved_ctxt); 
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_symlink (symlink->targetpath, 
-                        symlink->sourcepath, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
         EXIT;
         return error;
 }
 
-static int reint_rename (int slot_offset, struct kml_rec *rec)
+static int reint_symlink(struct kml_rec *rec, struct file *dir,
+                         struct lento_vfs_context *info)
 {
-        struct  kml_rename *rename = &rec->rec_kml.rename;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
         int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0;
-
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_rename (rename->sourcepath, rename->targetpath, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
+        CDEBUG (D_KML, "=====REINT_SYMLINK::%s -> %s\n", rec->path, rec->target);
+        info->updated_time = rec->new_objectv->pv_ctime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_symlink(rec->target, rec->path, info);
+        pop_ctxt(&saved_ctxt); 
 
         EXIT;
         return error;
 }
 
-static int reint_setattr (int slot_offset, struct kml_rec *rec)
+static int reint_unlink(struct kml_rec *rec, struct file *dir,
+                        struct lento_vfs_context *info)
 {
-        struct  kml_setattr *setattr = &rec->rec_kml.setattr;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
         int     error;
+        char *path;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = setattr->iattr.ia_attr_flags;
+        path = path_join(rec->path, rec->pathlen - 1, rec->target, rec->targetlen);
+        if (path == NULL) {
+                EXIT;
+                return -ENOMEM;
+        }
+
+        CDEBUG (D_KML, "=====REINT_UNLINK::%s\n", path);
+        info->updated_time = rec->new_parentv->pv_mtime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_unlink(path, info);
+        pop_ctxt(&saved_ctxt); 
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_setattr (setattr->path, &setattr->iattr, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
+        kfree(path);
         EXIT;
         return error;
 }
 
-static int reint_mknod (int slot_offset, struct kml_rec *rec)
+static int branch_reint_rename(struct presto_file_set *fset, struct kml_rec *rec, 
+                   struct file *dir, struct lento_vfs_context *info,
+                   char * kml_data, __u64 kml_size)
 {
-        struct  kml_mknod *mknod = &rec->rec_kml.mknod;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
         int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0;
+        error = reint_rename(rec, dir, info);
+        if (error == -ENOENT) {
+                /* normal reint failed because path was not found */
+                struct rec_info rec;
+                
+                CDEBUG(D_KML, "saving branch rename kml\n");
+                rec.is_kml = 1;
+                rec.size = kml_size;
+                error = presto_log(fset, &rec, kml_data, kml_size,
+                           NULL, 0, NULL, 0,  NULL, 0);
+                if (error == 0)
+                        error = presto_write_last_rcvd(&rec, fset, info);
+        }
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_mknod (mknod->path, mknod->mode, 
-                MKDEV(mknod->major, mknod->minor), &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
         EXIT;
         return error;
 }
 
-int kml_reint (char *mtpt, int slot_offset, struct kml_rec *rec)
+int branch_reinter(struct presto_file_set *fset, struct kml_rec *rec, 
+                   struct file *dir, struct lento_vfs_context *info,
+                   char * kml_data, __u64 kml_size)
 {
         int error = 0;
-        switch (rec->rec_head.opcode)
-        {
-                case KML_CREATE:
-                        error = reint_create (slot_offset, rec);
-                        break;
-                case KML_OPEN:
-                        error = reint_open (slot_offset, rec);
-                        break;
-                case KML_CLOSE:
-                        /* error = reint_close (slot_offset, rec);
-                           force the system to return to lento */
-                        error = KML_CLOSE_BACKFETCH;
-                        break;
-                case KML_MKDIR:
-                        error = reint_mkdir (slot_offset, rec);
-                        break;
-                case KML_RMDIR:
-                        error = reint_rmdir (slot_offset, rec);
-                        break;
-                case KML_UNLINK:
-                        error = reint_unlink (slot_offset, rec);
-                        break;
-                case KML_LINK:
-                        error =  reint_link (slot_offset, rec);
-                        break;
-                case KML_SYMLINK:
-                        error = reint_symlink (slot_offset, rec);
-                        break;
-                case KML_RENAME:
-                        error = reint_rename (slot_offset, rec);
-                        break;
-                case KML_SETATTR:
-                        error =  reint_setattr (slot_offset, rec);
-                        break;
-                case KML_MKNOD:
-                        error = reint_mknod (slot_offset, rec);
-                        break;
-                default:
-                        CDEBUG (D_KML, "wrong opcode::%d\n", rec->rec_head.opcode);
-                        return -EBADF;
-        }
-        if (error != 0 && error != KML_CLOSE_BACKFETCH)
-                CDEBUG (D_KML, "KML_ERROR::error = %d\n", error);
+        int op = rec->prefix.hdr->opcode;
+
+        if (op == KML_OPCODE_CLOSE) {
+                /* regular close and backfetch */
+                error = reint_close(rec, dir, info);
+        } else if  (op == KML_OPCODE_RENAME) {
+                /* rename only if name already exists  */
+                error = branch_reint_rename(fset, rec, dir, info,
+                                            kml_data, kml_size);
+        } else {
+                /* just rewrite kml into branch/kml and update last_rcvd */
+                struct rec_info rec;
+                
+                CDEBUG(D_KML, "Saving branch kml\n");
+                rec.is_kml = 1;
+                rec.size = kml_size;
+                error = presto_log(fset, &rec, kml_data, kml_size,
+                           NULL, 0, NULL, 0,  NULL, 0);
+                if (error == 0)
+                        error = presto_write_last_rcvd(&rec, fset, info);
+        }
+                
         return error;
 }
 
-/* return the old mtpt */
-/*
-struct fs_struct {
-        atomic_t count;
-        int umask;
-        struct dentry * root, * pwd;
+typedef int (*reinter_t)(struct kml_rec *rec, struct file *basedir,
+                         struct lento_vfs_context *info);
+
+static reinter_t presto_reinters[KML_OPCODE_NUM] =
+{
+        [KML_OPCODE_CLOSE] = reint_close,
+        [KML_OPCODE_CREATE] = reint_create,
+        [KML_OPCODE_LINK] = reint_link,
+        [KML_OPCODE_MKDIR] = reint_mkdir,
+        [KML_OPCODE_MKNOD] = reint_mknod,
+        [KML_OPCODE_NOOP] = reint_noop,
+        [KML_OPCODE_RENAME] = reint_rename,
+        [KML_OPCODE_RMDIR] = reint_rmdir,
+        [KML_OPCODE_SETATTR] = reint_setattr,
+        [KML_OPCODE_SYMLINK] = reint_symlink,
+        [KML_OPCODE_UNLINK] = reint_unlink,
 };
-*/
-static int do_set_fs_root (struct dentry *newroot, 
-                                        struct dentry **old_root)
-{
-        struct dentry *de = current->fs->root;
-        current->fs->root = newroot;
-	if (old_root != (struct dentry **) NULL)
-        	*old_root = de;
-        return 0;
+
+static inline reinter_t get_reinter(int op)
+{
+        if (op < 0 || op >= sizeof(presto_reinters) / sizeof(reinter_t)) 
+                return NULL; 
+        else 
+                return  presto_reinters[op];
 }
 
-static int set_system_mtpt (char *mtpt, struct dentry **old_root)
+int kml_reint_rec(struct file *dir, struct izo_ioctl_data *data)
 {
-	struct nameidata nd;
-        struct dentry *dentry;
-	int error;
-
-	if (path_init(pathname, LOOKUP_PARENT, &nd))
-		error = path_walk(mtpt, &nd);
-        if (error) {
-                CDEBUG (D_KML, "Yean!!!!::Can't find mtpt::%s\n", mtpt);
+        char *ptr;
+        char *end;
+        struct kml_rec rec;
+        int error = 0;
+        struct lento_vfs_context info;
+        struct presto_cache *cache;
+        struct presto_file_set *fset;
+        struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
+        int op;
+        reinter_t reinter;
+
+        struct izo_rcvd_rec lr_rec;
+        int off;
+
+        ENTRY;
+
+        error = presto_prep(dir->f_dentry, &cache, &fset);
+        if ( error  ) {
+                CERROR("intermezzo: Reintegration on invalid file\n");
                 return error;
-	}
+        }
+
+        if (!dd || !dd->dd_fset || dd->dd_fset->fset_dentry != dir->f_dentry) { 
+                CERROR("intermezzo: reintegration on non-fset root (ino %ld)\n",
+                       dir->f_dentry->d_inode->i_ino);
+                    
+                return -EINVAL;
+        }
+
+        if (data->ioc_plen1 > 64 * 1024) {
+                EXIT;
+                return -ENOSPC;
+        }
+
+        ptr = fset->fset_reint_buf;
+        end = ptr + data->ioc_plen1;
+
+        if (copy_from_user(ptr, data->ioc_pbuf1, data->ioc_plen1)) { 
+                EXIT;
+                error = -EFAULT;
+                goto out;
+        }
+
+        error = kml_unpack(&rec, &ptr, end);
+        if (error) { 
+                EXIT;
+                error = -EFAULT;
+                goto out;
+        }
+
+        off = izo_rcvd_get(&lr_rec, fset, data->ioc_uuid);
+        if (off < 0) {
+                CERROR("No last_rcvd record, setting to 0\n");
+                memset(&lr_rec, 0, sizeof(lr_rec));
+        }
+ 
+        data->ioc_kmlsize = ptr - fset->fset_reint_buf;
 
-        dentry = nd.dentry;
-        error = do_set_fs_root (dentry, old_root);
-        path_release (&nd);
+        if (rec.suffix->recno != lr_rec.lr_remote_recno + 1) {
+                CERROR("KML record number %Lu expected, not %d\n",
+                       lr_rec.lr_remote_recno + 1,
+                       rec.suffix->recno);
+
+#if 0
+                if (!version_check(&rec, dd->dd_fset, &info)) {
+                        /* FIXME: do an upcall to resolve conflicts */
+                        CERROR("intermezzo: would be a conflict!\n");
+                        error = -EINVAL;
+                        EXIT;
+                        goto out;
+                }
+#endif
+        }
+
+        op = rec.prefix.hdr->opcode;
+
+        reinter = get_reinter(op);
+        if (!reinter) { 
+                CERROR("%s: Unrecognized KML opcode %d\n", __FUNCTION__, op);
+                error = -EINVAL;
+                EXIT;
+                goto out;
+        }
+
+        info.kml_offset = data->ioc_offset + data->ioc_kmlsize;
+        info.recno = rec.suffix->recno;
+        info.flags = LENTO_FL_EXPECT;
+        if (data->ioc_flags)
+                info.flags |= LENTO_FL_KML;
+
+        memcpy(info.uuid, data->ioc_uuid, sizeof(info.uuid));
+
+        if (fset->fset_flags & FSET_IS_BRANCH && data->ioc_flags)
+                error = branch_reinter(fset, &rec, dir, &info, fset->fset_reint_buf,
+                                       data->ioc_kmlsize);
+        else 
+                error = reinter(&rec, dir, &info);
+ out: 
+        EXIT;
         return error;
 }
 
-int kml_reintbuf (struct  kml_fsdata *kml_fsdata,
-                  char *mtpt, struct kml_rec **close_rec)
+int izo_get_fileid(struct file *dir, struct izo_ioctl_data *data)
 {
-        struct kml_rec *rec = NULL;
-        struct list_head *head, *tmp;
-        struct dentry *old_root;
-        int    error = 0;
-
-        head = &kml_fsdata->kml_reint_cache;
-        if (list_empty(head))
-                return 0;
+        char *buf = NULL; 
+        char *ptr;
+        char *end;
+        struct kml_rec rec;
+        struct file *file;
+        struct presto_cache *cache;
+        struct presto_file_set *fset;
+        struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
+        struct run_ctxt saved_ctxt;
+        int     error;
 
-        if (kml_fsdata->kml_reint_current == NULL ||
-            kml_fsdata->kml_reint_current == head->next)
-                return 0;
+        ENTRY;
 
-        error = set_system_mtpt (mtpt, &old_root);
-        if (error)
+        error = presto_prep(dir->f_dentry, &cache, &fset);
+        if ( error  ) {
+                CERROR("intermezzo: Reintegration on invalid file\n");
                 return error;
+        }
+
+        if (!dd || !dd->dd_fset || dd->dd_fset->fset_dentry != dir->f_dentry) { 
+                CERROR("intermezzo: reintegration on non-fset root (ino %ld)\n",
+                       dir->f_dentry->d_inode->i_ino);
+                    
+                return -EINVAL;
+        }
+
+
+        PRESTO_ALLOC(buf, data->ioc_plen1);
+        if (!buf) { 
+                EXIT;
+                return -ENOMEM;
+        }
+        ptr = buf;
+        end = buf + data->ioc_plen1;
+
+        if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) { 
+                EXIT;
+                PRESTO_FREE(buf, data->ioc_plen1);
+                return -EFAULT;
+        }
 
-        tmp = head->next;
-        while (error == 0 &&  tmp != head ) {
-                rec = list_entry(tmp, struct kml_rec, kml_optimize.kml_chains);
-                error = kml_reint (mtpt, rec->rec_kml_offset, rec);
-                tmp = tmp->next;
+        error = kml_unpack(&rec, &ptr, end);
+        if (error) { 
+                EXIT;
+                PRESTO_FREE(buf, data->ioc_plen1);
+                return -EFAULT;
         }
 
-        do_set_fs_root (old_root, NULL);
-
-        if (error == KML_CLOSE_BACKFETCH)
-                *close_rec = rec;
-        kml_fsdata->kml_reint_current = tmp;
+        kmlreint_pre_secure(&rec, dir, &saved_ctxt);
+
+        file = filp_open(rec.path, O_RDONLY, 0);
+        if (!file || IS_ERR(file)) { 
+                error = PTR_ERR(file);
+                goto out;
+        }
+        data->ioc_ino = file->f_dentry->d_inode->i_ino;
+        data->ioc_generation = file->f_dentry->d_inode->i_generation; 
+        filp_close(file, 0); 
+
+        CDEBUG(D_FILE, "%s ino %Lx, gen %Lx\n", rec.path, 
+               data->ioc_ino, data->ioc_generation);
+
+ out:
+        if (buf) 
+                PRESTO_FREE(buf, data->ioc_plen1);
+        pop_ctxt(&saved_ctxt); 
+        EXIT;
         return error;
 }
 
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/kml_setup.c linux-2.4.20/fs/intermezzo/kml_setup.c
--- linux-2.4.19/fs/intermezzo/kml_setup.c	2001-11-11 18:20:21.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/kml_setup.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,59 +0,0 @@
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <asm/uaccess.h>
-
-#include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
-#include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
-
-int kml_init (struct presto_file_set *fset)
-{
-        struct kml_fsdata *data;
-
-        ENTRY;
-        PRESTO_ALLOC (data, struct kml_fsdata *, sizeof (struct kml_fsdata));
-        if (data == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-        INIT_LIST_HEAD (&data->kml_reint_cache);
-        INIT_LIST_HEAD (&data->kml_kop_cache);
-
-        PRESTO_ALLOC (data->kml_buf, char *, KML_REINT_MAXBUF);
-        if (data->kml_buf == NULL) {
-                PRESTO_FREE (data, sizeof (struct kml_fsdata));
-                EXIT;
-                return -ENOMEM;
-        }
-
-        data->kml_maxsize = KML_REINT_MAXBUF;
-        data->kml_len = 0;
-        data->kml_reintpos = 0;
-        data->kml_count = 0;
-        fset->fset_kmldata = data;
-        EXIT;
-        return 0;
-}
-
-int kml_cleanup (struct presto_file_set *fset)
-{
-        struct kml_fsdata *data = fset->fset_kmldata;
-
-        if (data == NULL)
-                return 0;
-
-        fset->fset_kmldata = NULL;
-#if 0
-        kml_sop_cleanup (&data->kml_reint_cache);
-        kml_kop_cleanup (&data->kml_kop_cache);
-#endif
-        PRESTO_FREE (data->kml_buf, KML_REINT_MAXBUF);
-        PRESTO_FREE (data, sizeof (struct kml_fsdata));
-        return 0;
-}
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/kml_unpack.c linux-2.4.20/fs/intermezzo/kml_unpack.c
--- linux-2.4.19/fs/intermezzo/kml_unpack.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/kml_unpack.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,708 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Unpacking of KML records
+ *
+ */
+
+#ifdef __KERNEL__
+#  include <linux/module.h>
+#  include <linux/errno.h>
+#  include <linux/kernel.h>
+#  include <linux/major.h>
+#  include <linux/sched.h>
+#  include <linux/lp.h>
+#  include <linux/slab.h>
+#  include <linux/ioport.h>
+#  include <linux/fcntl.h>
+#  include <linux/delay.h>
+#  include <linux/skbuff.h>
+#  include <linux/proc_fs.h>
+#  include <linux/vmalloc.h>
+#  include <linux/fs.h>
+#  include <linux/poll.h>
+#  include <linux/init.h>
+#  include <linux/list.h>
+#  include <linux/stat.h>
+#  include <asm/io.h>
+#  include <asm/segment.h>
+#  include <asm/system.h>
+#  include <asm/poll.h>
+#  include <asm/uaccess.h>
+#else
+#  include <time.h>
+#  include <stdio.h>
+#  include <string.h>
+#  include <stdlib.h>
+#  include <errno.h>
+#  include <sys/stat.h>
+#  include <glib.h>
+#endif
+
+#include <linux/intermezzo_lib.h>
+#include <linux/intermezzo_idl.h>
+#include <linux/intermezzo_fs.h>
+
+int kml_unpack_version(struct presto_version **ver, char **buf, char *end) 
+{
+	char *ptr = *buf;
+        struct presto_version *pv;
+
+	UNLOGP(*ver, struct presto_version, ptr, end);
+        pv = *ver;
+        pv->pv_mtime   = NTOH__u64(pv->pv_mtime);
+        pv->pv_ctime   = NTOH__u64(pv->pv_ctime);
+        pv->pv_size    = NTOH__u64(pv->pv_size);
+
+	*buf = ptr;
+
+        return 0;
+}
+
+
+static int kml_unpack_noop(struct kml_rec *rec, char **buf, char *end)
+{
+	return 0;
+}
+
+ 
+static int kml_unpack_get_fileid(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+
+	*buf = ptr;
+	return 0;
+}
+
+static int kml_unpack_create(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->uid, __u32, ptr, end);
+	LUNLOGV(rec->gid, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+ 
+static int kml_unpack_mkdir(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->uid, __u32, ptr, end);
+	LUNLOGV(rec->gid, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_unlink(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+        LUNLOGV(rec->old_mode, __u32, ptr, end);
+        LUNLOGV(rec->old_rdev, __u32, ptr, end);
+        LUNLOGV(rec->old_uid, __u64, ptr, end);
+        LUNLOGV(rec->old_gid, __u64, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+        LUNLOGV(rec->old_targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+        UNLOGL(rec->old_target, char, rec->old_targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_rmdir(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+        LUNLOGV(rec->old_mode, __u32, ptr, end);
+        LUNLOGV(rec->old_rdev, __u32, ptr, end);
+        LUNLOGV(rec->old_uid, __u64, ptr, end);
+        LUNLOGV(rec->old_gid, __u64, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_close(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	LUNLOGV(rec->mode, __u32, ptr, end);  // used for open_mode
+	LUNLOGV(rec->uid, __u32, ptr, end);   // used for open_uid
+	LUNLOGV(rec->gid, __u32, ptr, end);   // used for open_gid
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->ino, __u64, ptr, end);
+	LUNLOGV(rec->generation, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_symlink(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->uid, __u32, ptr, end);
+	LUNLOGV(rec->gid, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_rename(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_setattr(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+	LUNLOGV(rec->valid, __u32, ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->uid, __u32, ptr, end);
+	LUNLOGV(rec->gid, __u32, ptr, end);
+	LUNLOGV(rec->size, __u64, ptr, end);
+	LUNLOGV(rec->mtime, __u64, ptr, end);
+	LUNLOGV(rec->ctime, __u64, ptr, end);
+	LUNLOGV(rec->flags, __u32, ptr, end);
+        LUNLOGV(rec->old_mode, __u32, ptr, end);
+        LUNLOGV(rec->old_rdev, __u32, ptr, end);
+        LUNLOGV(rec->old_uid, __u64, ptr, end);
+        LUNLOGV(rec->old_gid, __u64, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_link(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+static int kml_unpack_mknod(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->uid, __u32, ptr, end);
+	LUNLOGV(rec->gid, __u32, ptr, end);
+	LUNLOGV(rec->major, __u32, ptr, end);
+	LUNLOGV(rec->minor, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_write(struct kml_rec *rec, char **buf, char *end)
+{
+	printf("NOT IMPLEMENTED");
+	return 0;
+}
+
+
+static int kml_unpack_release(struct kml_rec *rec, char **buf, char *end)
+{
+	printf("NOT IMPLEMENTED");
+	return 0;
+}
+
+
+static int kml_unpack_trunc(struct kml_rec *rec, char **buf, char *end)
+{
+	printf("NOT IMPLEMENTED");
+	return 0;
+}
+
+
+static int kml_unpack_setextattr(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->flags, __u32, ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->namelen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+        UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->name, char, rec->namelen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_delextattr(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->flags, __u32, ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->namelen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->name, char, rec->namelen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+static int kml_unpack_open(struct kml_rec *rec, char **buf, char *end)
+{
+	printf("NOT IMPLEMENTED");
+	return 0;
+}
+
+static int kml_unpack_kml_trunc(struct kml_rec *rec, char **buf, char *end)
+{
+
+	printf("NOT IMPLEMENTED");
+	return 0;
+}
+
+
+typedef int (*unpacker)(struct kml_rec *rec, char **buf, char *end);
+
+static unpacker unpackers[KML_OPCODE_NUM] = 
+{
+	[KML_OPCODE_NOOP] = kml_unpack_noop,
+	[KML_OPCODE_CREATE] = kml_unpack_create, 
+	[KML_OPCODE_MKDIR] = kml_unpack_mkdir,
+	[KML_OPCODE_UNLINK] = kml_unpack_unlink,
+	[KML_OPCODE_RMDIR] = kml_unpack_rmdir,
+	[KML_OPCODE_CLOSE] = kml_unpack_close,
+	[KML_OPCODE_SYMLINK] = kml_unpack_symlink,
+	[KML_OPCODE_RENAME] = kml_unpack_rename,
+	[KML_OPCODE_SETATTR] = kml_unpack_setattr,
+	[KML_OPCODE_LINK] = kml_unpack_link,
+	[KML_OPCODE_OPEN] = kml_unpack_open,
+	[KML_OPCODE_MKNOD] = kml_unpack_mknod,
+	[KML_OPCODE_WRITE] = kml_unpack_write,
+	[KML_OPCODE_RELEASE] = kml_unpack_release,
+	[KML_OPCODE_TRUNC] = kml_unpack_trunc,
+	[KML_OPCODE_SETEXTATTR] = kml_unpack_setextattr,
+	[KML_OPCODE_DELEXTATTR] = kml_unpack_delextattr,
+	[KML_OPCODE_KML_TRUNC] = kml_unpack_kml_trunc,
+	[KML_OPCODE_GET_FILEID] = kml_unpack_get_fileid
+};
+
+int kml_unpack_prefix(struct kml_rec *rec, char **buf, char *end) 
+{
+	char *ptr = *buf;
+        int n;
+
+        UNLOGP(rec->prefix.hdr, struct kml_prefix_hdr, ptr, end);
+        rec->prefix.hdr->len     = NTOH__u32(rec->prefix.hdr->len);
+        rec->prefix.hdr->version = NTOH__u32(rec->prefix.hdr->version);
+        rec->prefix.hdr->pid     = NTOH__u32(rec->prefix.hdr->pid);
+        rec->prefix.hdr->auid    = NTOH__u32(rec->prefix.hdr->auid);
+        rec->prefix.hdr->fsuid   = NTOH__u32(rec->prefix.hdr->fsuid);
+        rec->prefix.hdr->fsgid   = NTOH__u32(rec->prefix.hdr->fsgid);
+        rec->prefix.hdr->opcode  = NTOH__u32(rec->prefix.hdr->opcode);
+        rec->prefix.hdr->ngroups = NTOH__u32(rec->prefix.hdr->ngroups);
+
+	UNLOGL(rec->prefix.groups, __u32, rec->prefix.hdr->ngroups, ptr, end);
+        for (n = 0; n < rec->prefix.hdr->ngroups; n++) {
+                rec->prefix.groups[n] = NTOH__u32(rec->prefix.groups[n]);
+        }
+
+	*buf = ptr;
+
+        return 0;
+}
+
+int kml_unpack_suffix(struct kml_rec *rec, char **buf, char *end) 
+{
+	char *ptr = *buf;
+
+	UNLOGP(rec->suffix, struct kml_suffix, ptr, end);
+        rec->suffix->prevrec   = NTOH__u32(rec->suffix->prevrec);
+        rec->suffix->recno    = NTOH__u32(rec->suffix->recno);
+        rec->suffix->time     = NTOH__u32(rec->suffix->time);
+        rec->suffix->len      = NTOH__u32(rec->suffix->len);
+
+	*buf = ptr;
+
+        return 0;
+}
+
+int kml_unpack(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+	int err; 
+
+        if (((unsigned long)ptr % 4) != 0) {
+                printf("InterMezzo: %s: record misaligned.\n", __FUNCTION__);
+                return -EINVAL;
+        }
+
+        while (ptr < end) { 
+                __u32 *i = (__u32 *)ptr;
+                if (*i)
+                        break;
+                ptr += sizeof(*i);
+        }
+	*buf = ptr;
+
+	memset(rec, 0, sizeof(*rec));
+
+        err = kml_unpack_prefix(rec, &ptr, end);
+	if (err) {
+                printf("InterMezzo: %s: unpack_prefix failed: %d\n",
+                       __FUNCTION__, err);
+		return err;
+        }
+
+        if (rec->prefix.hdr->opcode < 0  ||
+            rec->prefix.hdr->opcode >= KML_OPCODE_NUM) {
+                printf("InterMezzo: %s: invalid opcode (%d)\n",
+                       __FUNCTION__, rec->prefix.hdr->opcode);
+		return -EINVAL;
+        }
+	err = unpackers[rec->prefix.hdr->opcode](rec, &ptr, end);
+	if (err) {
+                printf("InterMezzo: %s: unpacker failed: %d\n",
+                       __FUNCTION__, err);
+		return err;
+        }
+
+        err = kml_unpack_suffix(rec, &ptr, end);
+	if (err) {
+                printf("InterMezzo: %s: unpack_suffix failed: %d\n",
+                       __FUNCTION__, err);
+		return err;
+        }
+
+
+	if (rec->prefix.hdr->len != rec->suffix->len) {
+                printf("InterMezzo: %s: lengths don't match\n",
+                       __FUNCTION__);
+		return -EINVAL;
+        }
+        if ((rec->prefix.hdr->len % 4) != 0) {
+                printf("InterMezzo: %s: record length not a "
+                       "multiple of 4.\n", __FUNCTION__);
+                return -EINVAL;
+        }
+        if (ptr - *buf != rec->prefix.hdr->len) {
+                printf("InterMezzo: %s: unpacking error\n",
+                       __FUNCTION__);
+                return -EINVAL;
+        }
+        while (ptr < end) { 
+                __u32 *i = (__u32 *)ptr;
+                if (*i)
+                        break;
+                ptr += sizeof(*i);
+        }
+	*buf = ptr;
+	return 0;
+}
+
+
+#ifndef __KERNEL__
+#define STR(ptr) ((ptr))? (ptr) : ""
+
+#define OPNAME(n) [KML_OPCODE_##n] = #n
+static char *opnames[KML_OPCODE_NUM] = {
+	OPNAME(NOOP),
+	OPNAME(CREATE),
+	OPNAME(MKDIR), 
+	OPNAME(UNLINK),
+	OPNAME(RMDIR),
+	OPNAME(CLOSE),
+	OPNAME(SYMLINK),
+	OPNAME(RENAME),
+	OPNAME(SETATTR),
+	OPNAME(LINK),
+	OPNAME(OPEN),
+	OPNAME(MKNOD),
+	OPNAME(WRITE),
+	OPNAME(RELEASE),
+	OPNAME(TRUNC),
+	OPNAME(SETEXTATTR),
+	OPNAME(DELEXTATTR),
+	OPNAME(KML_TRUNC),
+	OPNAME(GET_FILEID)
+};
+#undef OPNAME
+
+static char *print_opname(int op)
+{
+	if (op < 0 || op >= sizeof (opnames) / sizeof (*opnames))
+		return NULL;
+	return opnames[op];
+}
+
+
+static char *print_time(__u64 i)
+{
+	char buf[128];
+	
+	memset(buf, 0, 128);
+
+#ifndef __KERNEL__
+	strftime(buf, 128, "%Y/%m/%d %H:%M:%S", gmtime((time_t *)&i));
+#else
+	sprintf(buf, "%Ld\n", i);
+#endif
+
+	return strdup(buf);
+}
+
+static char *print_version(struct presto_version *ver)
+{
+	char ver_buf[128];
+	char *mtime;
+	char *ctime;
+
+	if (!ver || ver->pv_ctime == 0) {
+		return strdup("");
+	} 
+	mtime = print_time(ver->pv_mtime);
+	ctime = print_time(ver->pv_ctime);
+	sprintf(ver_buf, "mtime %s, ctime %s, len %lld", 
+		mtime, ctime, ver->pv_size);
+	free(mtime);
+	free(ctime);
+	return strdup(ver_buf);
+}
+
+
+char *kml_print_rec(struct kml_rec *rec, int brief)
+{
+	char *str;
+	char *nov, *oov, *ntv, *otv, *npv, *opv;
+	char *rectime, *mtime, *ctime;
+
+        if (brief) {
+		str = g_strdup_printf(" %08d %7s %*s %*s", 
+                                      rec->suffix->recno,
+                                      print_opname (rec->prefix.hdr->opcode),
+                                      rec->pathlen, STR(rec->path),
+                                      rec->targetlen, STR(rec->target));
+                
+		return str;
+	}
+
+	rectime = print_time(rec->suffix->time);
+	mtime = print_time(rec->mtime);
+	ctime = print_time(rec->ctime);
+
+	nov = print_version(rec->new_objectv);
+	oov = print_version(rec->old_objectv);
+	ntv = print_version(rec->new_targetv);
+	otv = print_version(rec->old_targetv);
+	npv = print_version(rec->new_parentv);
+	opv = print_version(rec->old_parentv);
+
+	str = g_strdup_printf("\n -- Record:\n"
+		"    Recno     %d\n"
+		"    KML off   %lld\n" 
+		"    Version   %d\n" 
+		"    Len       %d\n"
+		"    Suf len   %d\n"
+		"    Time      %s\n"
+		"    Opcode    %d\n"
+		"    Op        %s\n"
+		"    Pid       %d\n"
+		"    AUid      %d\n"
+		"    Fsuid     %d\n" 
+		"    Fsgid     %d\n"
+		"    Prevrec   %d\n" 
+		"    Ngroups   %d\n"
+		//"    Groups    @{$self->{groups}}\n" 
+		" -- Path:\n"
+		"    Inode     %d\n"
+		"    Gen num   %u\n"
+                "    Old mode  %o\n"
+                "    Old rdev  %x\n"
+                "    Old uid   %llu\n"
+                "    Old gid   %llu\n"
+		"    Path      %*s\n"
+		//"    Open_mode %o\n",
+		"    Pathlen   %d\n"
+		"    Tgt       %*s\n"
+		"    Tgtlen    %d\n" 
+		"    Old Tgt   %*s\n"
+		"    Old Tgtln %d\n" 
+		" -- Attr:\n"
+		"    Valid     %x\n"
+		"    mode %o, uid %d, gid %d, size %lld, mtime %s, ctime %s rdev %x (%d:%d)\n"
+		" -- Versions:\n"
+		"    New object %s\n"
+		"    Old object %s\n"
+		"    New target %s\n"
+		"    Old target %s\n"
+		"    New parent %s\n"
+		"    Old parent %s\n", 
+		
+		rec->suffix->recno, 
+		rec->offset, 
+		rec->prefix.hdr->version, 
+		rec->prefix.hdr->len, 
+		rec->suffix->len, 
+		rectime,
+		rec->prefix.hdr->opcode, 
+		print_opname (rec->prefix.hdr->opcode),
+		rec->prefix.hdr->pid,
+		rec->prefix.hdr->auid,
+		rec->prefix.hdr->fsuid,
+		rec->prefix.hdr->fsgid,
+		rec->suffix->prevrec,
+		rec->prefix.hdr->ngroups,
+		rec->ino,
+		rec->generation,
+                rec->old_mode,
+                rec->old_rdev,
+                rec->old_uid,
+                rec->old_gid,
+		rec->pathlen,
+		STR(rec->path),
+		rec->pathlen,
+		rec->targetlen,
+		STR(rec->target),
+		rec->targetlen,
+		rec->old_targetlen,
+		STR(rec->old_target),
+		rec->old_targetlen,
+		
+		rec->valid, 
+		rec->mode,
+		rec->uid,
+		rec->gid,
+		rec->size,
+		mtime,
+		ctime,
+		rec->rdev, rec->major, rec->minor,
+		nov, oov, ntv, otv, npv, opv);
+		
+	free(nov);
+	free(oov);
+	free(ntv);
+	free(otv);
+	free(npv);
+	free(opv);
+
+	free(rectime); 
+	free(ctime);
+	free(mtime);
+
+	return str;
+}
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/kml_utils.c linux-2.4.20/fs/intermezzo/kml_utils.c
--- linux-2.4.19/fs/intermezzo/kml_utils.c	2001-11-11 18:20:21.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/kml_utils.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,44 +0,0 @@
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_kml.h>
-
-
-// dlogit -- oppsite to logit ()
-//         return the sbuf + size;
-char *dlogit (void *tbuf, const void *sbuf, int size)
-{
-        char *ptr = (char *)sbuf;
-        memcpy(tbuf, ptr, size);
-        ptr += size;
-        return ptr;
-}
-
-static spinlock_t kml_lock = SPIN_LOCK_UNLOCKED;
-static char  buf[1024];
-char * bdup_printf (char *format, ...)
-{
-        va_list args;
-        int  i;
-        char *path;
-        long flags;
-
-        spin_lock_irqsave(&kml_lock, flags);
-        va_start(args, format);
-        i = vsprintf(buf, format, args); /* hopefully i < sizeof(buf) */
-        va_end(args);
-
-        PRESTO_ALLOC (path, char *, i + 1);
-        if (path == NULL)
-                return NULL;
-        strcpy (path, buf);
-
-        spin_unlock_irqrestore(&kml_lock, flags);
-        return path;
-}
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/methods.c linux-2.4.20/fs/intermezzo/methods.c
--- linux-2.4.19/fs/intermezzo/methods.c	2001-11-13 17:20:56.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/methods.c	2002-10-29 11:18:38.000000000 +0000
@@ -1,5 +1,5 @@
-/*
- *
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
@@ -7,6 +7,22 @@
  *
  *  Extended Attribute Support
  *  Copyright (C) 2001 Shirish H. Phatak, Tacit Networks, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
  */
 
 #include <stdarg.h>
@@ -150,6 +166,16 @@
                 FDEBUG(D_SUPER, "ops at %p\n", ops);
         }
 
+        if ( strlen(cache_type) == strlen("tmpfs") &&
+             memcmp(cache_type, "tmpfs", strlen("tmpfs")) == 0 ) {
+#if defined(CONFIG_TMPFS)
+                ops->o_trops = &presto_tmpfs_journal_ops;
+#else
+                ops->o_trops = NULL;
+#endif
+                FDEBUG(D_SUPER, "ops at %p\n", ops);
+        }
+
         if ( strlen(cache_type) == strlen("reiserfs") &&
              memcmp(cache_type, "reiserfs", strlen("reiserfs")) == 0 ) {
 #if 0
@@ -164,7 +190,7 @@
         if ( strlen(cache_type) == strlen("xfs") &&
              memcmp(cache_type, "xfs", strlen("xfs")) == 0 ) {
 #if 0
-                //#if defined(CONFIG_XFS_FS) || defined (CONFIG_XFS_FS_MODULE)
+/*#if defined(CONFIG_XFS_FS) || defined (CONFIG_XFS_FS_MODULE) */
                 ops->o_trops = &presto_xfs_journal_ops;
 #else
                 ops->o_trops = NULL;
@@ -207,6 +233,13 @@
                 ops = &filter_oppar[FILTER_FS_EXT3];
                 FDEBUG(D_SUPER, "ops at %p\n", ops);
         }
+
+        if ( strlen(cache_type) == strlen("tmpfs") &&
+             memcmp(cache_type, "tmpfs", strlen("tmpfs")) == 0 ) {
+                ops = &filter_oppar[FILTER_FS_TMPFS];
+                FDEBUG(D_SUPER, "ops at %p\n", ops);
+        }
+
         if ( strlen(cache_type) == strlen("reiserfs") &&
              memcmp(cache_type, "reiserfs", strlen("reiserfs")) == 0 ) {
                 ops = &filter_oppar[FILTER_FS_REISERFS];
@@ -219,7 +252,7 @@
         }
 
         if (ops == NULL) {
-                printk("prepare to die: unrecognized cache type for Filter\n");
+                CERROR("prepare to die: unrecognized cache type for Filter\n");
         }
         return ops;
         FEXIT;
@@ -343,7 +376,7 @@
         memcpy(filter_c2udfops(cache), cache_fops, sizeof(*cache_fops));
 
         /* unconditional filtering operations */
-        filter_c2udfops(cache)->open = filter_fops->open;
+        filter_c2udfops(cache)->ioctl = filter_fops->ioctl;
 
         FEXIT;
 }
@@ -374,7 +407,7 @@
         memcpy(pr_iops, cache_iops, sizeof(*cache_iops));
 
         /* copy dir fops */
-        printk("*** cache file ops at %p\n", cache_fops);
+        CERROR("*** cache file ops at %p\n", cache_fops);
         memcpy(filter_c2uffops(cache), cache_fops, sizeof(*cache_fops));
 
         /* assign */
@@ -383,6 +416,8 @@
                 pr_iops->setattr = filter_iops->setattr;
         if (cache_iops->getattr)
                 pr_iops->getattr = filter_iops->getattr;
+        /* XXX Should this be conditional rmr ? */
+        pr_iops->permission = filter_iops->permission;
 #ifdef CONFIG_FS_EXT_ATTR
     	/* For now we assume that posix acls are handled through extended
 	* attributes. If this is not the case, we must explicitly trap and 
@@ -397,6 +432,7 @@
         filter_c2uffops(cache)->open = filter_fops->open;
         filter_c2uffops(cache)->release = filter_fops->release;
         filter_c2uffops(cache)->write = filter_fops->write;
+        filter_c2uffops(cache)->ioctl = filter_fops->ioctl;
 
         FEXIT;
 }
@@ -455,7 +491,7 @@
                filter_dop, sizeof(*filter_dop));
         
         if (cache_dop &&  cache_dop != filter_dop && cache_dop->d_revalidate){
-                printk("WARNING: filter overriding revalidation!\n");
+                CERROR("WARNING: filter overriding revalidation!\n");
         }
         return;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/presto.c linux-2.4.20/fs/intermezzo/presto.c
--- linux-2.4.19/fs/intermezzo/presto.c	2002-02-25 19:38:08.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/presto.c	2002-10-29 11:18:32.000000000 +0000
@@ -1,12 +1,26 @@
-/*
- * intermezzo.c
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
- * This file implements basic routines supporting the semantics
+ *  Author: Peter J. Braam <braam@clusterfs.com>
+ *  Copyright (C) 1998 Stelias Computing Inc
+ *  Copyright (C) 1999 Red Hat Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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.
  *
- * Author: Peter J. Braam  <braam@cs.cmu.edu>
- * Copyright (C) 1998 Stelias Computing Inc
- * Copyright (C) 1999 Red Hat Inc.
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ * This file implements basic routines supporting the semantics
  */
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -23,13 +37,7 @@
 #include <linux/smp_lock.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
-
-extern int presto_init_last_rcvd_file(struct presto_file_set *);
-extern int presto_init_lml_file(struct presto_file_set *);
-extern int presto_init_kml_file(struct presto_file_set *);
 
 int presto_walk(const char *name, struct nameidata *nd)
 {
@@ -37,7 +45,7 @@
         /* we do not follow symlinks to support symlink operations 
            correctly. The vfs should always hand us resolved dentries
            so we should not be required to use LOOKUP_FOLLOW. At the
-	   reintegrating end, lento again should be working with the 
+           reintegrating end, lento again should be working with the 
            resolved pathname and not the symlink. SHP
            XXX: This code implies that direct symlinks do not work. SHP
         */
@@ -51,17 +59,6 @@
 }
 
 
-static inline int presto_dentry_is_fsetroot(struct dentry *dentry)
-{
-        return ((long) dentry->d_fsdata) & PRESTO_FSETROOT;
-}
-
-static inline struct presto_file_set *presto_dentry2fset(struct dentry *dentry)
-{
-        return (struct presto_file_set *)
-                (((long) dentry->d_fsdata) - PRESTO_FSETROOT);
-}
-
 /* find the presto minor device for this inode */
 int presto_i2m(struct inode *inode)
 {
@@ -70,7 +67,7 @@
         cache = presto_get_cache(inode);
         CDEBUG(D_PSDEV, "\n");
         if ( !cache ) {
-                printk("PRESTO: BAD: cannot find cache for dev %d, ino %ld\n",
+                CERROR("PRESTO: BAD: cannot find cache for dev %d, ino %ld\n",
                        inode->i_dev, inode->i_ino);
                 EXIT;
                 return -1;
@@ -91,48 +88,6 @@
 
 }
 
-int presto_has_all_data(struct inode *inode)
-{
-        ENTRY;
-
-        if ( (inode->i_size >> inode->i_sb->s_blocksize_bits) >
-             inode->i_blocks) {
-                EXIT;
-                return 0;
-        }
-        EXIT;
-        return 1;
-
-}
-
-/* find the fileset dentry for this dentry */
-struct presto_file_set *presto_fset(struct dentry *de)
-{
-        struct dentry *fsde;
-        ENTRY;
-        fsde = de;
-        for ( ; ; ) {
-                if ( presto_dentry_is_fsetroot(fsde) ) {
-                        EXIT;
-                        return presto_dentry2fset(fsde);
-                }
-                /* are we at the cache "/" ?? */
-                if ( fsde->d_parent == fsde ) {
-                        if ( !de->d_inode ) {
-                                printk("Warning %*s has no fileset inode.\n",
-                                       de->d_name.len, de->d_name.name);
-                        }
-                        /* better to return a BAD thing */
-                        EXIT;
-                        return NULL;
-                }
-                fsde = fsde->d_parent;
-        }
-        /* not reached */
-        EXIT;
-        return NULL;
-}
-
 /* XXX check this out */
 struct presto_file_set *presto_path2fileset(const char *name)
 {
@@ -168,7 +123,7 @@
 
         ENTRY;
         minor = presto_i2m(dentry->d_inode);
-        if ( upc_comms[minor].uc_no_filter ) {
+        if ( izo_channels[minor].uc_no_filter ) {
                 EXIT;
                 return ~0;
         }
@@ -178,41 +133,30 @@
              (flag == PRESTO_ATTR || flag == PRESTO_DATA) &&
              (fset->fset_flags & FSET_INSYNC) ) {
                 CDEBUG(D_INODE, "fset in sync (ino %ld)!\n",
-                       fset->fset_mtpt->d_inode->i_ino);
+                       fset->fset_dentry->d_inode->i_ino);
                 EXIT;
                 return 1;
         }
 
-        /* if it is a fsetroot, it's stored in the fset_flags */
-        if ( fset && presto_dentry_is_fsetroot(dentry) ) {
-                EXIT;
-                return fset->fset_data & flag;
-        }
-
         EXIT;
-        return ((int)(long)dentry->d_fsdata & flag);
+        return (presto_d2d(dentry)->dd_flags & flag);
 }
 
 /* set a bit in the dentry flags */
 void presto_set(struct dentry *dentry, int flag)
 {
-
+        ENTRY;
         if ( dentry->d_inode ) {
                 CDEBUG(D_INODE, "SET ino %ld, flag %x\n",
                        dentry->d_inode->i_ino, flag);
         }
-
-        if ( presto_dentry_is_fsetroot(dentry)) {
-                struct presto_file_set *fset = presto_dentry2fset(dentry);
-                if (fset) {
-                        fset->fset_data |= flag;
-                        CDEBUG(D_INODE, "Setting fset->fset_data: now %x\n",
-                               fset->fset_data);
-                }
-        } else {
-                CDEBUG(D_INODE, "Setting dentry->d_fsdata\n");
-                ((int)(long)dentry->d_fsdata) |= flag;
+        if ( presto_d2d(dentry) == NULL) {
+                CERROR("dentry without d_fsdata in presto_set: %p: %*s", dentry,
+                                dentry->d_name.len, dentry->d_name.name);
+                BUG();
         }
+        presto_d2d(dentry)->dd_flags |= flag;
+        EXIT;
 }
 
 /* given a path: complete the closes on the fset */
@@ -224,7 +168,6 @@
         struct presto_file_set *fset;
         ENTRY;
 
-
         error = presto_walk(path, &nd);
         if (error) {
                 EXIT;
@@ -242,7 +185,7 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto out_complete;
         }
@@ -256,108 +199,7 @@
         return error;
 }       
 
-/* set the fset recno and offset to a given value */ 
-int lento_reset_fset(char *path, __u64 offset, __u32 recno)
-{
-        struct nameidata nd;
-        struct dentry *dentry;
-        int error;
-        struct presto_file_set *fset;
-        ENTRY;
-
-
-        error = presto_walk(path, &nd);
-        if (error)
-                return error;
-
-        dentry = nd.dentry;
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto out_complete;
-        }
-        
-        fset = presto_fset(dentry);
-        error = -EINVAL;
-        if ( !fset ) {
-                printk("No fileset!\n");
-                EXIT;
-                goto out_complete;
-        }
-
-        write_lock(&fset->fset_kml.fd_lock);
-        fset->fset_kml.fd_recno = recno;
-        fset->fset_kml.fd_offset = offset;
-        read_lock(&fset->fset_kml.fd_lock);
-        
-        EXIT;
- out_complete:
-        path_release(&nd);
-        return error;
-}       
-
-
-
-/* given a path, write an LML record for it - thus must have root's 
-   group array settings, since lento is doing this 
-*/ 
-int lento_write_lml(char *path,
-                     __u64 remote_ino, 
-                     __u32 remote_generation,
-                     __u32 remote_version,
-                     struct presto_version *remote_file_version)
-{
-        struct nameidata nd; 
-        struct rec_info rec;
-        struct dentry *dentry;
-        struct file file;
-        int error;
-        struct presto_file_set *fset;
-        ENTRY;
-
-        error = presto_walk(path, &nd);
-        if (error) {
-                EXIT;
-                return error;
-        }
-        dentry = nd.dentry;
-
-        file.f_dentry = dentry;
-        file.private_data = NULL;
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto out_lml;
-        }
-        
-        fset = presto_fset(dentry);
-        error = -EINVAL;
-        if ( !fset ) {
-                printk("No fileset!\n");
-                EXIT;
-                goto out_lml;
-        }
-
-        
-        /* setting offset to -1 appends */
-        rec.offset = -1;
-        /* this only requires a transaction below which is automatic */
-        error = presto_write_lml_close(&rec, 
-                                       fset,
-                                       &file, 
-                                       remote_ino,
-                                       remote_generation,
-                                       remote_version,
-                                       remote_file_version);
-        
-        EXIT;
- out_lml:
-        path_release(&nd);
-        return error;
-}       
-
+#if 0
 /* given a path: write a close record and cancel an LML record, finally
    call truncate LML.  Lento is doing this so it goes in with uid/gid's 
    root. 
@@ -396,14 +238,14 @@
 
         error=-EINVAL;
         if (fset==NULL) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto out_cancel_lml;
         }
         
         /* this only requires a transaction below which is automatic */
         handle = presto_trans_start(fset, dentry->d_inode, PRESTO_OP_RELEASE); 
-        if ( !handle ) {
+        if ( IS_ERR(handle) ) {
                 error = -ENOMEM; 
                 EXIT; 
                 goto out_cancel_lml; 
@@ -435,7 +277,7 @@
 
         if (info->flags & LENTO_FL_WRITE_EXPECT) {
                 error = presto_write_last_rcvd(&rec, fset, info); 
-                if ( error ) {
+                if ( error < 0 ) {
                         EXIT; 
                         presto_trans_commit(fset, handle);
                         goto out_cancel_lml;
@@ -454,148 +296,101 @@
         path_release(&nd); 
         return error;
 }       
+#endif 
 
-
-/* given a path, operate on the flags in its dentry.  Used by downcalls */
-int presto_mark_dentry(const char *name, int and_flag, int or_flag, 
+/* given a dentry, operate on the flags in its dentry.  Used by downcalls */
+int izo_mark_dentry(struct dentry *dentry, int and_flag, int or_flag, 
                        int *res)
 {
-        struct nameidata nd;
-        struct dentry *dentry;
-        int error;
-
-        CDEBUG(D_INODE, "name: %s, and flag %x, or flag %x\n",
-               name, and_flag, or_flag);
-
-        error = presto_walk(name, &nd);
-        if (error)
-                return error;
-        dentry = nd.dentry;
-        CDEBUG(D_INODE, "dentry at %p, d_fsdata %p\n", dentry, dentry->d_fsdata);
+        int error = 0;
 
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) )
-                goto out;
-
-        error = 0;
-        if ( presto_dentry_is_fsetroot(dentry) ) {
-                struct presto_file_set *fset = presto_dentry2fset(dentry);
-                CDEBUG(D_INODE, "Setting fset fset_data: fset %p\n", fset);
-                if ( fset ) {
-                        fset->fset_data &= and_flag;
-                        fset->fset_data |= or_flag;
-                        if (res) {
-                                *res = fset->fset_data;
-                        }
-                }
-                CDEBUG(D_INODE, "fset %p, flags %x data %x\n", 
-                       fset, fset->fset_flags, fset->fset_data);
-        } else {
-                ((int)(long)dentry->d_fsdata) &= and_flag;
-                ((int)(long)dentry->d_fsdata) |= or_flag;
-                if (res) 
-                        *res = (int)(long)dentry->d_fsdata;
+        if (presto_d2d(dentry) == NULL) {
+                CERROR("InterMezzo: no ddata for inode %ld in %s\n",
+                       dentry->d_inode->i_ino, __FUNCTION__);
+                return -EINVAL;
         }
 
-        /* indicate if we were the only users while changing the flag */
-        if ( atomic_read(&dentry->d_count) > 1 )
-                error = -EBUSY;
+        CDEBUG(D_INODE, "inode: %ld, and flag %x, or flag %x, dd_flags %x\n",
+               dentry->d_inode->i_ino, and_flag, or_flag,
+               presto_d2d(dentry)->dd_flags);
+
+        presto_d2d(dentry)->dd_flags &= and_flag;
+        presto_d2d(dentry)->dd_flags |= or_flag;
+        if (res) 
+                *res = presto_d2d(dentry)->dd_flags;
 
-out:
-        path_release(&nd);
         return error;
 }
 
 /* given a path, operate on the flags in its cache.  Used by mark_ioctl */
-int presto_mark_cache(const char *name, int and_flag, int or_flag, 
-                      int *res)
+int izo_mark_cache(struct dentry *dentry, int and_flag, int or_flag, 
+                   int *res)
 {
-        struct nameidata nd;
-        struct dentry *dentry;
         struct presto_cache *cache;
-        int error;
-
-        CDEBUG(D_INODE,
-               "presto_mark_cache :: name: %s, and flag %x, or flag %x\n",
-               name, and_flag, or_flag);
 
-        error = presto_walk(name, &nd);
-        if (error)
-                return error;
+        if (presto_d2d(dentry) == NULL) {
+                CERROR("InterMezzo: no ddata for inode %ld in %s\n",
+                       dentry->d_inode->i_ino, __FUNCTION__);
+                return -EINVAL;
+        }
 
-        dentry = nd.dentry;
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) )
-                goto out;
+        CDEBUG(D_INODE, "inode: %ld, and flag %x, or flag %x, dd_flags %x\n",
+               dentry->d_inode->i_ino, and_flag, or_flag,
+               presto_d2d(dentry)->dd_flags);
 
-        error = -EBADF;
         cache = presto_get_cache(dentry->d_inode);
         if ( !cache ) {
-                printk("PRESTO: BAD: cannot find cache in presto_mark_cache\n");
-                make_bad_inode(dentry->d_inode);
-                goto out;
+                CERROR("PRESTO: BAD: cannot find cache in izo_mark_cache\n");
+                return -EBADF;
         }
-        error = 0;
+
         ((int)cache->cache_flags) &= and_flag;
         ((int)cache->cache_flags) |= or_flag;
-        if (res) {
+        if (res)
                 *res = (int)cache->cache_flags;
-        }
 
-out:
-        path_release(&nd);
-        return error;
+        return 0;
 }
 
-int presto_mark_fset_dentry(struct dentry *dentry, int and_flag, int or_flag, 
-                     int * res)
+int presto_set_max_kml_size(const char *path, unsigned long max_size)
 {
-        int error;
         struct presto_file_set *fset;
 
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) )
-                return error;
+        ENTRY;
+
+        fset = presto_path2fileset(path);
+        if (IS_ERR(fset)) {
+                EXIT;
+                return PTR_ERR(fset);
+        }
+
+        fset->kml_truncate_size = max_size;
+        CDEBUG(D_CACHE, "KML truncate size set to %lu bytes for fset %s.\n",
+               max_size, path);
+
+        EXIT;
+        return 0;
+}
 
-        error = -EBADF;
+int izo_mark_fset(struct dentry *dentry, int and_flag, int or_flag, 
+                  int * res)
+{
+        struct presto_file_set *fset;
+        
         fset = presto_fset(dentry);
         if ( !fset ) {
-                printk("PRESTO: BAD: cannot find cache in presto_mark_cache\n");
+                CERROR("PRESTO: BAD: cannot find cache in izo_mark_cache\n");
                 make_bad_inode(dentry->d_inode);
-                return error;
+                return -EBADF;
         }
-        error = 0;
         ((int)fset->fset_flags) &= and_flag;
         ((int)fset->fset_flags) |= or_flag;
-        if (res) { 
+        if (res)
                 *res = (int)fset->fset_flags;
-        }
-
-        return error;
-}
-
-/* given a path, operate on the flags in its cache.  Used by mark_ioctl */
-inline int presto_mark_fset(const char *name, int and_flag, int or_flag, 
-                     int * res)
-{
-        struct nameidata nd;
-        struct dentry *dentry;
-        int error;
-        ENTRY;
 
-        error = presto_walk(name, &nd);
-        if (error)
-                return error;
-
-
-        dentry = nd.dentry;
-        error = presto_mark_fset_dentry(dentry, and_flag, or_flag, res);
-
-        path_release(&nd);
-        return error;
+        return 0;
 }
 
-
 /* talk to Lento about the permit */
 static int presto_permit_upcall(struct dentry *dentry)
 {
@@ -606,8 +401,12 @@
         int fsetnamelen;
         struct presto_file_set *fset = NULL;
 
-        if ( (minor = presto_i2m(dentry->d_inode)) < 0)
+        ENTRY;
+
+        if ( (minor = presto_i2m(dentry->d_inode)) < 0) {
+                EXIT;
                 return -EINVAL;
+        }
 
         fset = presto_fset(dentry);
         if (!fset) {
@@ -617,22 +416,26 @@
         
         if ( !presto_lento_up(minor) ) {
                 if ( fset->fset_flags & FSET_STEAL_PERMIT ) {
+                        EXIT;
                         return 0;
                 } else {
+                        EXIT;
                         return -ENOTCONN;
                 }
         }
 
-        PRESTO_ALLOC(buffer, char *, PAGE_SIZE);
+        PRESTO_ALLOC(buffer, PAGE_SIZE);
         if ( !buffer ) {
-                printk("PRESTO: out of memory!\n");
+                CERROR("PRESTO: out of memory!\n");
+                EXIT;
                 return -ENOMEM;
         }
-        path = presto_path(dentry, fset->fset_mtpt, buffer, PAGE_SIZE);
+        path = presto_path(dentry, fset->fset_dentry, buffer, PAGE_SIZE);
         pathlen = MYPATHLEN(buffer, path);
         fsetnamelen = strlen(fset->fset_name); 
-        rc = lento_permit(minor, pathlen, fsetnamelen, path, fset->fset_name);
+        rc = izo_upc_permit(minor, dentry, pathlen, path, fset->fset_name);
         PRESTO_FREE(buffer, PAGE_SIZE);
+        EXIT;
         return rc;
 }
 
@@ -641,13 +444,16 @@
  *  - if 0 is returned the permit was already in the kernel -- or --
  *    Lento gave us the permit without reintegration
  *  - lento returns the number of records it reintegrated 
+ *
+ * Note that if this fileset has branches, a permit will -never- to a normal
+ * process for writing in the data area (ie, outside of .intermezzo)
  */
 int presto_get_permit(struct inode * inode)
 {
         struct dentry *de;
         struct presto_file_set *fset;
         int minor = presto_i2m(inode);
-        int rc;
+        int rc = 0;
 
         ENTRY;
         if (minor < 0) {
@@ -657,47 +463,101 @@
 
         if ( ISLENTO(minor) ) {
                 EXIT;
-                return -EINVAL;
+                return 0;
         }
 
         if (list_empty(&inode->i_dentry)) {
-                printk("No alias for inode %d\n", (int) inode->i_ino);
+                CERROR("No alias for inode %d\n", (int) inode->i_ino);
                 EXIT;
                 return -EINVAL;
         }
 
         de = list_entry(inode->i_dentry.next, struct dentry, d_alias);
 
+        if (presto_chk(de, PRESTO_DONT_JOURNAL)) {
+                EXIT;
+                return 0;
+        }
+
         fset = presto_fset(de);
         if ( !fset ) {
-                printk("Presto: no fileset in presto_get_permit!\n");
+                CERROR("Presto: no fileset in presto_get_permit!\n");
                 EXIT;
                 return -EINVAL;
         }
 
+        if (fset->fset_flags & FSET_HAS_BRANCHES) {
+                EXIT;
+                return -EROFS;
+        }
+
+        spin_lock(&fset->fset_permit_lock);
         if (fset->fset_flags & FSET_HASPERMIT) {
-                lock_kernel();
                 fset->fset_permit_count++;
                 CDEBUG(D_INODE, "permit count now %d, inode %lx\n", 
                        fset->fset_permit_count, inode->i_ino);
-                unlock_kernel();
+                spin_unlock(&fset->fset_permit_lock);
                 EXIT;
                 return 0;
+        }
+
+        /* Allow reintegration to proceed without locks -SHP */
+        fset->fset_permit_upcall_count++;
+        if (fset->fset_permit_upcall_count == 1) {
+                spin_unlock(&fset->fset_permit_lock);
+                rc = presto_permit_upcall(fset->fset_dentry);
+                spin_lock(&fset->fset_permit_lock);
+                fset->fset_permit_upcall_count--;
+                if (rc == 0) {
+                        izo_mark_fset(fset->fset_dentry, ~0, FSET_HASPERMIT,
+                                      NULL);
+                        fset->fset_permit_count++;
+                } else if (rc == ENOTCONN) {
+                        CERROR("InterMezzo: disconnected operation. stealing permit.\n");
+                        izo_mark_fset(fset->fset_dentry, ~0, FSET_HASPERMIT,
+                                      NULL);
+                        fset->fset_permit_count++;
+                        /* set a disconnected flag here to stop upcalls */
+                        rc = 0;
+                } else {
+                        CERROR("InterMezzo: presto_permit_upcall failed: %d\n", rc);
+                        rc = -EROFS;
+                        /* go to sleep here and try again? */
+                }
+                wake_up_interruptible(&fset->fset_permit_queue);
         } else {
-		/* Allow reintegration to proceed without locks -SHP */
-                rc = presto_permit_upcall(fset->fset_mtpt);
-                lock_kernel();
-                if ( !rc ) { 
-                	presto_mark_fset_dentry
-				(fset->fset_mtpt, ~0, FSET_HASPERMIT, NULL);
-                	fset->fset_permit_count++;
+                /* Someone is already doing an upcall; go to sleep. */
+                DECLARE_WAITQUEUE(wait, current);
+
+                spin_unlock(&fset->fset_permit_lock);
+                add_wait_queue(&fset->fset_permit_queue, &wait);
+                while (1) {
+                        set_current_state(TASK_INTERRUPTIBLE);
+
+                        spin_lock(&fset->fset_permit_lock);
+                        if (fset->fset_permit_upcall_count == 0)
+                                break;
+                        spin_unlock(&fset->fset_permit_lock);
+
+                        if (signal_pending(current)) {
+                                remove_wait_queue(&fset->fset_permit_queue,
+                                                  &wait);
+                                return -ERESTARTSYS;
+                        }
+                        schedule();
                 }
-                CDEBUG(D_INODE, "permit count now %d, ino %lx (likely 1), rc %d\n", 
-        		fset->fset_permit_count, inode->i_ino, rc);
-                unlock_kernel();
-                EXIT;
-                return rc;
+                remove_wait_queue(&fset->fset_permit_queue, &wait);
+                /* We've been woken up: do we have the permit? */
+                if (fset->fset_flags & FSET_HASPERMIT)
+                        /* FIXME: Is this the right thing? */
+                        rc = -EAGAIN;
         }
+
+        CDEBUG(D_INODE, "permit count now %d, ino %ld (likely 1), "
+               "rc %d\n", fset->fset_permit_count, inode->i_ino, rc);
+        spin_unlock(&fset->fset_permit_lock);
+        EXIT;
+        return rc;
 }
 
 int presto_put_permit(struct inode * inode)
@@ -714,11 +574,11 @@
 
         if ( ISLENTO(minor) ) {
                 EXIT;
-                return -1;
+                return 0;
         }
 
         if (list_empty(&inode->i_dentry)) {
-                printk("No alias for inode %d\n", (int) inode->i_ino);
+                CERROR("No alias for inode %d\n", (int) inode->i_ino);
                 EXIT;
                 return -1;
         }
@@ -727,436 +587,143 @@
 
         fset = presto_fset(de);
         if ( !fset ) {
-                printk("Presto: no fileset in presto_get_permit!\n");
+                CERROR("InterMezzo: no fileset in %s!\n", __FUNCTION__);
                 EXIT;
                 return -1;
         }
 
-        lock_kernel();
+        if (presto_chk(de, PRESTO_DONT_JOURNAL)) {
+                EXIT;
+                return 0;
+        }
+
+        spin_lock(&fset->fset_permit_lock);
         if (fset->fset_flags & FSET_HASPERMIT) {
-                if (fset->fset_permit_count > 0) fset->fset_permit_count--;
-                else printk("Put permit while permit count is 0, inode %lx!\n",
-                                inode->i_ino); 
+                if (fset->fset_permit_count > 0)
+                        fset->fset_permit_count--;
+                else
+                        CERROR("Put permit while permit count is 0, "
+                               "inode %ld!\n", inode->i_ino); 
         } else {
-        	fset->fset_permit_count=0;
-        	printk("Put permit while no permit, inode %lx, flags %x!\n", 
-               		inode->i_ino, fset->fset_flags);
+                fset->fset_permit_count = 0;
+                CERROR("InterMezzo: put permit while no permit, inode %ld, "
+                       "flags %x!\n", inode->i_ino, fset->fset_flags);
         }
 
-        CDEBUG(D_INODE, "permit count now %d, inode %lx\n", 
-        		fset->fset_permit_count, inode->i_ino);
+        CDEBUG(D_INODE, "permit count now %d, inode %ld\n",
+               fset->fset_permit_count, inode->i_ino);
 
         if (fset->fset_flags & FSET_PERMIT_WAITING &&
-                    fset->fset_permit_count == 0) {
-                CDEBUG(D_INODE, "permit count now 0, ino %lx, notify Lento\n", 
+            fset->fset_permit_count == 0) {
+                CDEBUG(D_INODE, "permit count now 0, ino %ld, wake sleepers\n",
                        inode->i_ino);
-                presto_mark_fset_dentry(fset->fset_mtpt, ~FSET_PERMIT_WAITING, 0, NULL);
-                presto_mark_fset_dentry(fset->fset_mtpt, ~FSET_HASPERMIT, 0, NULL);
-                lento_release_permit(fset->fset_cache->cache_psdev->uc_minor,
-                                     fset->fset_permit_cookie);
-                fset->fset_permit_cookie = 0; 
+                wake_up_interruptible(&fset->fset_permit_queue);
         }
-        unlock_kernel();
+        spin_unlock(&fset->fset_permit_lock);
 
         EXIT;
         return 0;
 }
 
-
 void presto_getversion(struct presto_version * presto_version,
                        struct inode * inode)
 {
-        presto_version->pv_mtime = cpu_to_le64((__u64)inode->i_mtime);
-        presto_version->pv_ctime = cpu_to_le64((__u64)inode->i_ctime);
-        presto_version->pv_size = cpu_to_le64((__u64)inode->i_size);
-}
-
-/*
- *  note: this routine "pins" a dentry for a fileset root
- */
-int presto_set_fsetroot(char *path, char *fsetname, unsigned int fsetid,
-                        unsigned int flags)
-{
-        struct presto_file_set *fset;
-        struct presto_file_set *fset2;
-        struct dentry *dentry;
-        struct presto_cache *cache;
-        int error;
-
-        ENTRY;
-
-        PRESTO_ALLOC(fset, struct presto_file_set *, sizeof(*fset));
-        error = -ENOMEM;
-        if ( !fset ) {
-                printk(KERN_ERR "No memory allocating fset for %s\n", fsetname);
-                EXIT;
-                return -ENOMEM;
-        }
-        CDEBUG(D_INODE, "fset at %p\n", fset);
-
-        printk("presto: fsetroot: path %s, fileset name %s\n", path, fsetname);
-        error = presto_walk(path, &fset->fset_nd);
-        CDEBUG(D_INODE, "\n");
-        if (error) {
-                EXIT;
-                goto out_free;
-        }
-        dentry = fset->fset_nd.dentry;
-        CDEBUG(D_INODE, "\n");
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto out_dput;
-        }
-
-        CDEBUG(D_INODE, "\n");
-        cache = presto_get_cache(dentry->d_inode);
-        if (!cache) {
-                printk(KERN_ERR "No cache found for %s\n", path);
-                EXIT;
-                goto out_dput;
-        }
-
-        CDEBUG(D_INODE, "\n");
-        error = -EINVAL;
-        if ( !cache->cache_mtpt) {
-                printk(KERN_ERR "Presto - no mountpoint: fsetroot fails!\n");
-                EXIT;
-                goto out_dput;
-        }
-        CDEBUG(D_INODE, "\n");
-
-        if (!cache->cache_root_fileset)  {
-                printk(KERN_ERR "Presto - no file set: fsetroot fails!\n");
-                EXIT;
-                goto out_dput;
-        }
-
-        error = -EEXIST;
-        CDEBUG(D_INODE, "\n");
-        fset2 = presto_fset(dentry);
-        if (fset2 && (fset2->fset_mtpt == dentry) ) { 
-                printk(KERN_ERR "Fsetroot already set (path %s)\n", path);
-                EXIT;
-                goto out_dput;
-        }
-
-        fset->fset_cache = cache;
-        fset->fset_mtpt = dentry;
-        fset->fset_name = fsetname;
-        fset->fset_chunkbits = CHUNK_BITS;
-        fset->fset_flags = flags;
-	fset->fset_file_maxio = FSET_DEFAULT_MAX_FILEIO; 
-
-        dentry->d_fsdata = (void *) ( ((long)fset) + PRESTO_FSETROOT );
-        list_add(&fset->fset_list, &cache->cache_fset_list);
-
-        error = presto_init_kml_file(fset);
-        if ( error ) {
-                EXIT;
-                CDEBUG(D_JOURNAL, "Error init_kml %d\n", error);
-                goto out_list_del;
-        }
-
-        error = presto_init_last_rcvd_file(fset);
-        if ( error ) {
-                int rc;
-                EXIT;
-                rc = presto_close_journal_file(fset);
-                CDEBUG(D_JOURNAL, "Error init_lastrcvd %d, cleanup %d\n", error, rc);
-                goto out_list_del;
-        }
-
-        error = presto_init_lml_file(fset);
-        if ( error ) {
-                int rc;
-                EXIT;
-                rc = presto_close_journal_file(fset);
-                CDEBUG(D_JOURNAL, "Error init_lml %d, cleanup %d\n", error, rc);
-                goto out_list_del;
-        }
-
-#ifdef  CONFIG_KREINT
-        /* initialize kml reint buffer */
-        error = kml_init (fset); 
-        if ( error ) {
-                int rc;
-                EXIT;
-                rc = presto_close_journal_file(fset);
-                CDEBUG(D_JOURNAL, "Error init kml reint %d, cleanup %d\n", 
-                                error, rc);
-                goto out_list_del;
-        }
-#endif
-        if ( dentry->d_inode == dentry->d_inode->i_sb->s_root->d_inode) {
-                cache->cache_flags |= CACHE_FSETROOT_SET;
-        }
-
-        CDEBUG(D_PIOCTL, "-------> fset at %p, dentry at %p, mtpt %p, fset %s, cache %p, d_fsdata %p\n",
-               fset, dentry, fset->fset_mtpt, fset->fset_name, cache, dentry->d_fsdata);
-
-        EXIT;
-        return 0;
-
- out_list_del:
-        list_del(&fset->fset_list);
-        dentry->d_fsdata = 0;
- out_dput:
-        path_release(&fset->fset_nd); 
- out_free:
-        PRESTO_FREE(fset, sizeof(*fset));
-        return error;
+        presto_version->pv_mtime = (__u64)inode->i_mtime;
+        presto_version->pv_ctime = (__u64)inode->i_ctime;
+        presto_version->pv_size  = (__u64)inode->i_size;
 }
 
-int presto_get_kmlsize(char *path, size_t *size)
-{
-        struct nameidata nd;
-        struct presto_file_set *fset;
-        struct dentry *dentry;
-        int error;
-
-        ENTRY;
-        error = presto_walk(path, &nd);
-        if (error) {
-                EXIT;
-                return error;
-        }
-        dentry = nd.dentry;
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto kml_out;
-        }
-
-        error = -EINVAL;
-        if ( ! presto_dentry_is_fsetroot(dentry)) {
-                EXIT;
-                goto kml_out;
-        }
-
-        fset = presto_dentry2fset(dentry);
-        if (!fset) {
-                EXIT;
-                goto kml_out;
-        }
-        error = 0;
-        *size = fset->fset_kml.fd_offset;
 
- kml_out:
-        path_release(&nd);
-        return error;
-}
-
-int presto_clear_fsetroot(char *path)
+/* If uuid is non-null, it is the uuid of the peer that's making the revocation
+ * request.  If it is null, this request was made locally, without external
+ * pressure to give up the permit.  This most often occurs when a client
+ * starts up.
+ *
+ * FIXME: this function needs to be refactored slightly once we start handling
+ * multiple clients.
+ */
+int izo_revoke_permit(struct dentry *dentry, __u8 uuid[16])
 {
-        struct nameidata nd;
-        struct presto_file_set *fset;
-        struct dentry *dentry;
-        struct presto_cache *cache;
-        int error;
+        struct presto_file_set *fset; 
+        DECLARE_WAITQUEUE(wait, current);
+        int minor, rc;
 
         ENTRY;
-        error = presto_walk(path, &nd);
-        if (error) {
-                EXIT;
-                return error;
-        }
-        dentry = nd.dentry;
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto put_out;
-        }
-
-        error = -EINVAL;
-        if ( ! presto_dentry_is_fsetroot(dentry)) {
-                EXIT;
-                goto put_out;
-        }
 
-        fset = presto_dentry2fset(dentry);
-        if (!fset) {
+        minor = presto_i2m(dentry->d_inode);
+        if (minor < 0) {
                 EXIT;
-                goto put_out;
+                return -ENODEV;
         }
 
-#ifdef  CONFIG_KREINT
-        error = kml_cleanup (fset);
-        if ( error ) {
-                printk("InterMezzo: Closing kml for fset %s: %d\n",
-                       fset->fset_name, error);
-        }
-#endif
-
-        error = presto_close_journal_file(fset);
-        if ( error ) {
-                printk("InterMezzo: Closing journal for fset %s: %d\n",
-                       fset->fset_name, error);
-        }
-        cache = fset->fset_cache;
-        cache->cache_flags &= ~CACHE_FSETROOT_SET;
-
-        list_del(&fset->fset_list);
-        dentry->d_fsdata = 0;
-        path_release(&fset->fset_nd);
-        fset->fset_mtpt = NULL;
-        PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) + 1);
-        PRESTO_FREE(fset, sizeof(*fset));
-        EXIT;
-
-put_out:
-        path_release(&nd); /* for our lookup */
-        return error;
-}
-
-int presto_clear_all_fsetroots(char *path)
-{
-        struct nameidata nd;
-        struct presto_file_set *fset;
-        struct dentry *dentry;
-        struct presto_cache *cache;
-        int error;
-        struct list_head *tmp,*tmpnext;
-
-
-        ENTRY;
-        error = presto_walk(path, &nd);
-        if (error) {
+        fset = presto_fset(dentry);
+        if (fset == NULL) {
                 EXIT;
-                return error;
+                return -ENODEV;
         }
-        dentry = nd.dentry;
 
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
+        spin_lock(&fset->fset_permit_lock);
+        if (fset->fset_flags & FSET_PERMIT_WAITING) {
+                CERROR("InterMezzo: Two processes are waiting on the same permit--this not yet supported!  Aborting this particular permit request...\n");
                 EXIT;
-                goto put_out;
+                spin_unlock(&fset->fset_permit_lock);
+                return -EINVAL;
         }
 
-        error = -EINVAL;
-        if ( ! presto_dentry_is_fsetroot(dentry)) {
-                EXIT;
-                goto put_out;
-        }
+        if (fset->fset_permit_count == 0)
+                goto got_permit;
 
-        fset = presto_dentry2fset(dentry);
-        if (!fset) {
+        /* Something is still using this permit.  Mark that we're waiting for it
+         * and go to sleep. */
+        rc = izo_mark_fset(dentry, ~0, FSET_PERMIT_WAITING, NULL);
+        spin_unlock(&fset->fset_permit_lock);
+        if (rc < 0) {
                 EXIT;
-                goto put_out;
+                return rc;
         }
 
-        cache = fset->fset_cache;
-        cache = fset->fset_cache;
-        cache->cache_flags &= ~CACHE_FSETROOT_SET;
-
-        tmp = &cache->cache_fset_list;
-        tmpnext = tmp->next;
-        while ( tmpnext != &cache->cache_fset_list) {
-		tmp=tmpnext;
-                tmpnext=tmp->next;
-                fset = list_entry(tmp, struct presto_file_set, fset_list);
-
-                
-                error = presto_close_journal_file(fset);
-                if ( error ) {
-                        printk("InterMezzo: Closing journal for fset %s: %d\n",
-                               fset->fset_name, error);
+        add_wait_queue(&fset->fset_permit_queue, &wait);
+        while (1) {
+                set_current_state(TASK_INTERRUPTIBLE);
+
+                spin_lock(&fset->fset_permit_lock);
+                if (fset->fset_permit_count == 0)
+                        break;
+                spin_unlock(&fset->fset_permit_lock);
+
+                if (signal_pending(current)) {
+                        /* FIXME: there must be a better thing to return... */
+                        remove_wait_queue(&fset->fset_permit_queue, &wait);
+                        EXIT;
+                        return -ERESTARTSYS;
                 }
-                list_del(&fset->fset_list);
-                fset->fset_mtpt->d_fsdata = 0;
-                path_release(&fset->fset_nd);
-                fset->fset_mtpt = NULL;
-                PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) +1);
-                PRESTO_FREE(fset, sizeof(*fset));
-        }
-
-        EXIT;
- put_out:
-        path_release(&nd); /* for our lookup */
-        return error;
-}
-
-
-int presto_get_lastrecno(char *path, off_t *recno)
-{
-        struct nameidata nd; 
-        struct presto_file_set *fset;
-        struct dentry *dentry;
-        int error;
-        ENTRY;
-
-        error = presto_walk(path, &nd);
-        if (error) {
-                EXIT;
-                return error;
-        }
-
-        dentry = nd.dentry;
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto kml_out;
-        }
 
-        error = -EINVAL;
-        if ( ! presto_dentry_is_fsetroot(dentry)) {
-                EXIT;
-                goto kml_out;
-        }
+                /* FIXME: maybe there should be a timeout here. */
 
-        fset = presto_dentry2fset(dentry);
-        if (!fset) {
-                EXIT;
-                goto kml_out;
+                schedule();
         }
-        error = 0;
-        *recno = fset->fset_kml.fd_recno;
-
- kml_out:
-        path_release(&nd);
-        return error;
-}
-
-/* 
-   if *cookie != 0, lento must wait for this cookie
-   before releasing the permit, operations are in progress. 
-*/ 
-int presto_permit_downcall( const char * path, int *cookie )
-{
-        int result;
-        struct presto_file_set *fset; 
 
-        fset = presto_path2fileset(path);
-        if (IS_ERR(fset)) { 
-                EXIT;
-                return PTR_ERR(fset);
-        }
+        remove_wait_queue(&fset->fset_permit_queue, &wait);
+ got_permit:
+        /* By this point fset->fset_permit_count is zero and we're holding the
+         * lock. */
+        CDEBUG(D_CACHE, "InterMezzo: releasing permit inode %ld\n",
+               dentry->d_inode->i_ino);
 
-	lock_kernel();
-        if (fset->fset_permit_count != 0) {
-                /* is there are previous cookie? */
-                if (fset->fset_permit_cookie == 0) {
-                        CDEBUG(D_CACHE, "presto installing cookie 0x%x, %s\n",
-                               *cookie, path);
-                        fset->fset_permit_cookie = *cookie;
-                } else {
-                        *cookie = fset->fset_permit_cookie;
-                        CDEBUG(D_CACHE, "presto has cookie 0x%x, %s\n",
-                               *cookie, path);
+        if (uuid != NULL) {
+                rc = izo_upc_revoke_permit(minor, fset->fset_name, uuid);
+                if (rc < 0) {
+                        spin_unlock(&fset->fset_permit_lock);
+                        EXIT;
+                        return rc;
                 }
-                result = presto_mark_fset(path, 0, FSET_PERMIT_WAITING, NULL);
-        } else {
-                *cookie = 0;
-                CDEBUG(D_CACHE, "presto releasing permit %s\n", path);
-                result = presto_mark_fset(path, ~FSET_HASPERMIT, 0, NULL);
         }
-	unlock_kernel();
 
-        return result;
+        izo_mark_fset(fset->fset_dentry, ~FSET_PERMIT_WAITING, 0, NULL);
+        izo_mark_fset(fset->fset_dentry, ~FSET_HASPERMIT, 0, NULL);
+        spin_unlock(&fset->fset_permit_lock);
+        EXIT;
+        return 0;
 }
 
 inline int presto_is_read_only(struct presto_file_set * fset)
@@ -1171,4 +738,3 @@
         mask= (ISLENTO(minor)? CACHE_LENTO_RO : CACHE_CLIENT_RO);
         return  ((cache->cache_flags & mask)? 1 : 0);
 }
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/psdev.c linux-2.4.20/fs/intermezzo/psdev.c
--- linux-2.4.19/fs/intermezzo/psdev.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/psdev.c	2002-10-29 11:18:36.000000000 +0000
@@ -1,4 +1,6 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
  *              An implementation of a loadable kernel mode driver providing
  *              multiple kernel/user space bidirectional communications links.
  *
@@ -6,8 +8,7 @@
  *
  *              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.
+ *              version 2 as published by the Free Software Foundation.
  *
  *              Adapted to become the Linux 2.0 Coda pseudo device
  *              Peter  Braam  <braam@maths.ox.ac.uk>
@@ -22,12 +23,8 @@
  *              Copyright (c) 2000 Tacitus Systems, Inc.
  *              Copyright (c) 2001 Cluster File Systems, Inc.
  *
- *		Extended attribute support
- *		Copyright (c) 2001 Shirish. H. Phatak
- *		Copyright (c) 2001 Tacit Networks, Inc.
  */
 
-
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -42,20 +39,20 @@
 #include <linux/proc_fs.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/list.h>
+#include <linux/devfs_fs_kernel.h>
 #include <asm/io.h>
-#include <asm/ioctls.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/poll.h>
 #include <asm/uaccess.h>
+#include <linux/miscdevice.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
 
 #ifdef PRESTO_DEVEL
@@ -67,120 +64,178 @@
 #endif
 
 /* Like inode.c (presto_sym_iops), the initializer is just to prevent
-   upc_comms from appearing as a COMMON symbol (and therefore
-   interfering with other modules that use the same variable name. */
-struct upc_comm upc_comms[MAX_PRESTODEV] = {{0}};
+   izo_channels from appearing as a COMMON symbol (and therefore
+   interfering with other modules that use the same variable name). */
+struct upc_channel izo_channels[MAX_CHANNEL] = {{0}};
 
-/*
- * Device operations: map file to upcall structure
- */
-static inline struct upc_comm *presto_psdev_f2u(struct file *file)
+int izo_psdev_get_free_channel(void)
 {
-        int minor;
+        int i, result = -1;
+        
+        for (i = 0 ; i < MAX_CHANNEL ; i++ ) {
+                if (list_empty(&(izo_channels[i].uc_cache_list))) { 
+                    result = i;
+                    break;
+                }
+        }
+        return result;
+}
 
-        if ( MAJOR(file->f_dentry->d_inode->i_rdev) != PRESTO_PSDEV_MAJOR ) {
-                EXIT;
-                return NULL;
+
+int izo_psdev_setpid(int minor)
+{
+        struct upc_channel *channel; 
+        if (minor < 0 || minor >= MAX_CHANNEL) { 
+                return -EINVAL;
         }
 
-        minor = MINOR(file->f_dentry->d_inode->i_rdev);
-        if ( minor < 0 || minor >= MAX_PRESTODEV ) {
-                EXIT;
-                return NULL;
+        channel = &(izo_channels[minor]); 
+        /*
+         * This ioctl is performed by each Lento that starts up
+         * and wants to do further communication with presto.
+         */
+        CDEBUG(D_PSDEV, "Setting current pid to %d channel %d\n", 
+               current->pid, minor);
+        channel->uc_pid = current->pid;
+        spin_lock(&channel->uc_lock); 
+        if ( !list_empty(&channel->uc_processing) ) {
+                struct list_head *lh;
+                struct upc_req *req;
+                CERROR("WARNING: setpid & processing not empty!\n");
+                lh = &channel->uc_processing;
+                while ( (lh = lh->next) != &channel->uc_processing) {
+                        req = list_entry(lh, struct upc_req, rq_chain);
+                        /* freeing of req and data is done by the sleeper */
+                        wake_up(&req->rq_sleep);
+                }
+        }
+        if ( !list_empty(&channel->uc_processing) ) {
+                CERROR("BAD: FAILDED TO CLEAN PROCESSING LIST!\n");
+        }
+        spin_unlock(&channel->uc_lock); 
+        EXIT;
+        return 0;
+}
+
+int izo_psdev_setchannel(struct file *file, int fd)
+{
+
+        struct file *psdev_file = fget(fd); 
+        struct presto_cache *cache = presto_get_cache(file->f_dentry->d_inode);
+
+        if (!psdev_file) { 
+                CERROR("%s: no psdev_file!\n", __FUNCTION__);
+                return -EINVAL;
         }
 
-        return &(upc_comms[minor]);
+        if (!cache) { 
+                CERROR("%s: no cache!\n", __FUNCTION__);
+                fput(psdev_file); 
+                return -EINVAL;
+        } 
+
+        if (psdev_file->private_data) { 
+                CERROR("%s: channel already set!\n", __FUNCTION__);
+                fput(psdev_file); 
+                return -EINVAL;
+        }
+
+        psdev_file->private_data = cache->cache_psdev;
+        fput(psdev_file); 
+        EXIT; 
+        return 0; 
 }
 
 inline int presto_lento_up(int minor) 
 {
-        return upc_comms[minor].uc_pid;
+        return izo_channels[minor].uc_pid;
 }
 
-
 static unsigned int presto_psdev_poll(struct file *file, poll_table * wait)
-{
-        struct upc_comm *upccom;
+ {
+        struct upc_channel *channel = (struct upc_channel *)file->private_data;
         unsigned int mask = POLLOUT | POLLWRNORM;
-        /* ENTRY; this will flood you */
 
-        if ( ! (upccom = presto_psdev_f2u(file)) ) {
-                kdev_t dev = file->f_dentry->d_inode->i_rdev;
-                printk("InterMezzo: %s, bad device %s\n",
-                       __FUNCTION__, kdevname(dev));
+        /* ENTRY; this will flood you */
+        if ( ! channel ) { 
+                CERROR("%s: bad psdev file\n", __FUNCTION__);
+                return -EBADF;
         }
 
-        poll_wait(file, &(upccom->uc_waitq), wait);
+        poll_wait(file, &(channel->uc_waitq), wait);
 
-        if (!list_empty(&upccom->uc_pending)) {
+        spin_lock(&channel->uc_lock);
+        if (!list_empty(&channel->uc_pending)) {
                 CDEBUG(D_PSDEV, "Non-empty pending list.\n");
                 mask |= POLLIN | POLLRDNORM;
         }
+        spin_unlock(&channel->uc_lock);
 
         /* EXIT; will flood you */
         return mask;
 }
 
-
-
 /*
  *      Receive a message written by Lento to the psdev
  */
 static ssize_t presto_psdev_write(struct file *file, const char *buf,
                                   size_t count, loff_t *off)
 {
-        struct upc_comm *upccom;
+        struct upc_channel *channel = (struct upc_channel *)file->private_data;
         struct upc_req *req = NULL;
         struct upc_req *tmp;
         struct list_head *lh;
-        struct lento_down_hdr hdr;
+        struct izo_upcall_resp hdr;
+        int error;
 
-        if ( ! (upccom = presto_psdev_f2u(file)) ) {
-                kdev_t dev = file->f_dentry->d_inode->i_rdev;
-                printk("InterMezzo: %s, bad device %s\n",
-                       __FUNCTION__, kdevname(dev));
+        if ( ! channel ) { 
+                CERROR("%s: bad psdev file\n", __FUNCTION__);
+                return -EBADF;
         }
 
         /* Peek at the opcode, uniquefier */
         if ( count < sizeof(hdr) ) {
-              printk("presto_psdev_write: Lento didn't write full hdr.\n");
+              CERROR("presto_psdev_write: Lento didn't write full hdr.\n");
                 return -EINVAL;
         }
 
-        if (copy_from_user(&hdr, buf, sizeof(hdr)))
+        error = copy_from_user(&hdr, buf, sizeof(hdr));
+        if ( error )
                 return -EFAULT;
 
         CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%d,%d)\n",
                current->pid, hdr.opcode, hdr.unique);
 
+        spin_lock(&channel->uc_lock); 
         /* Look for the message on the processing queue. */
-        lh  = &upccom->uc_processing;
-        while ( (lh = lh->next) != &upccom->uc_processing ) {
+        lh  = &channel->uc_processing;
+        while ( (lh = lh->next) != &channel->uc_processing ) {
                 tmp = list_entry(lh, struct upc_req , rq_chain);
                 if (tmp->rq_unique == hdr.unique) {
                         req = tmp;
-                      /* unlink here: keeps search length minimal */
-                        list_del(&req->rq_chain);
-                      INIT_LIST_HEAD(&req->rq_chain);
+                        /* unlink here: keeps search length minimal */
+                        list_del_init(&req->rq_chain);
                         CDEBUG(D_PSDEV,"Eureka opc %d uniq %d!\n",
                                hdr.opcode, hdr.unique);
                         break;
                 }
         }
+        spin_unlock(&channel->uc_lock); 
         if (!req) {
-                printk("psdev_write: msg (%d, %d) not found\n",
+                CERROR("psdev_write: msg (%d, %d) not found\n",
                        hdr.opcode, hdr.unique);
                 return(-ESRCH);
         }
 
         /* move data into response buffer. */
         if (req->rq_bufsize < count) {
-                printk("psdev_write: too much cnt: %d, cnt: %Zd, "
+                CERROR("psdev_write: too much cnt: %d, cnt: %d, "
                        "opc: %d, uniq: %d.\n",
                        req->rq_bufsize, count, hdr.opcode, hdr.unique);
                 count = req->rq_bufsize; /* don't have more space! */
         }
-        if (copy_from_user(req->rq_data, buf, count))
+        error = copy_from_user(req->rq_data, buf, count);
+        if ( error )
                 return -EFAULT;
 
         /* adjust outsize: good upcalls can be aware of this */
@@ -197,40 +252,43 @@
 static ssize_t presto_psdev_read(struct file * file, char * buf,
                                  size_t count, loff_t *off)
 {
-        struct upc_comm *upccom;
+        struct upc_channel *channel = (struct upc_channel *)file->private_data;
         struct upc_req *req;
         int result = count;
 
-        if ( ! (upccom = presto_psdev_f2u(file)) ) {
-                kdev_t dev = file->f_dentry->d_inode->i_rdev;
-                printk("InterMezzo: %s, bad device %s\n",
-                       __FUNCTION__, kdevname(dev));
+        if ( ! channel ) { 
+                CERROR("%s: bad psdev file\n", __FUNCTION__);
+                return -EBADF;
         }
 
-        CDEBUG(D_PSDEV, "count %Zd\n", count);
-        if (list_empty(&(upccom->uc_pending))) {
+        spin_lock(&channel->uc_lock); 
+        if (list_empty(&(channel->uc_pending))) {
                 CDEBUG(D_UPCALL, "Empty pending list in read, not good\n");
+                spin_unlock(&channel->uc_lock); 
                 return -EINVAL;
         }
-
-        req = list_entry((upccom->uc_pending.next), struct upc_req, rq_chain);
+        req = list_entry((channel->uc_pending.next), struct upc_req, rq_chain);
         list_del(&(req->rq_chain));
-      if (! (req->rq_flags & REQ_ASYNC) ) {
-              list_add(&(req->rq_chain), upccom->uc_processing.prev);
-      }
-      req->rq_flags |= REQ_READ;
+        if (! (req->rq_flags & REQ_ASYNC) ) {
+                list_add(&(req->rq_chain), channel->uc_processing.prev);
+        }
+        spin_unlock(&channel->uc_lock); 
+
+        req->rq_flags |= REQ_READ;
 
         /* Move the input args into userspace */
+        CDEBUG(D_PSDEV, "\n");
         if (req->rq_bufsize <= count) {
                 result = req->rq_bufsize;
         }
 
         if (count < req->rq_bufsize) {
-                printk ("psdev_read: buffer too small, read %Zd of %d bytes\n",
+                CERROR ("psdev_read: buffer too small, read %d of %d bytes\n",
                         count, req->rq_bufsize);
         }
 
         if ( copy_to_user(buf, req->rq_data, result) ) {
+                BUG();
                 return -EFAULT;
         }
 
@@ -246,1059 +304,16 @@
         return result;
 }
 
-static int presto_psdev_ioctl(struct inode *inode, struct file *file,
-                              unsigned int cmd, unsigned long arg)
-{
-        struct upc_comm *upccom;
-        /* XXX is this rdev or dev? */
-        kdev_t dev = inode->i_rdev;
-
-        ENTRY;
-        upccom = presto_psdev_f2u(file);
-        if ( !upccom) {
-                printk("InterMezzo: %s, bad device %s\n",
-                       __FUNCTION__, kdevname(dev));
-                EXIT;
-                return -ENODEV;
-        }
-
-        switch(cmd) {
-
-        case TCGETS:
-                return -EINVAL;
-
-        case PRESTO_GETMOUNT: {
-                /* return all the mounts for this device.  */
-                int minor = 0;
-                int len, outlen;
-                struct readmount readmount;
-                struct readmount *user_readmount = (struct readmount *) arg;
-                char * tmp;
-                int error = 0;
-
-                if (copy_from_user(&readmount, (void *)arg, sizeof(readmount)))
-                {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                len = readmount.io_len;
-                minor = MINOR(dev);
-                PRESTO_ALLOC(tmp, char *, len);
-                if (!tmp) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-
-                outlen = presto_sprint_mounts(tmp, len, minor);
-                CDEBUG(D_PSDEV, "presto_sprint_mounts returns %d bytes\n",
-                                outlen);
-
-                /* as this came out on 1/3/2000, it could NEVER work.
-                 * So fix it ... RGM
-                 * I mean, let's let the compiler do a little work ...
-                 * gcc suggested the extra ()
-                 */
-                if (copy_to_user(readmount.io_string, tmp, outlen)) {
-                        CDEBUG(D_PSDEV, "Copy_to_user string 0x%p failed\n",
-                               readmount.io_string);
-			error = -EFAULT;
-                }
-                if (!error && copy_to_user(&(user_readmount->io_len),
-                                           &outlen, sizeof(int))) {
-                        CDEBUG(D_PSDEV, "Copy_to_user len @0x%p failed\n",
-                               &(user_readmount->io_len));
-			error = -EFAULT;
-                }
-
-                PRESTO_FREE(tmp, len);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_SETPID: {
-                /*
-                 * This ioctl is performed by each Lento that starts up
-                 * and wants to do further communication with presto.
-                 */
-                CDEBUG(D_PSDEV, "Setting current pid to %d\n", current->pid);
-                upccom->uc_pid = current->pid;
-                if ( !list_empty(&upccom->uc_processing) ) {
-                        struct list_head *lh;
-                        struct upc_req *req;
-                        printk("WARNING: setpid & processing not empty!\n");
-                        lh = &upccom->uc_processing;
-                        while ( (lh = lh->next) != &upccom->uc_processing) {
-                                req = list_entry(lh, struct upc_req, rq_chain);
-                                /* freeing of req and data is done by the sleeper */
-                                wake_up(&req->rq_sleep);
-                        }
-                }
-                if ( !list_empty(&upccom->uc_processing) ) {
-                        printk("BAD: FAILDED TO CLEAN PROCESSING LIST!\n");
-                }
-                EXIT;
-                return 0;
-        }
-
-        case PRESTO_CLEAR_FSETROOT: {
-                /*
-                 * Close KML files.
-                 */
-                int error;
-                int saved_pid = upccom->uc_pid;
-                char *path;
-                struct {
-                        char *path;
-                        unsigned int path_len;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-                
-                if(input.path_len > PATH_MAX)
-                {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                PRESTO_ALLOC(path, char *, input.path_len + 1);
-                if ( !path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(path, input.path, input.path_len)) {
-                        PRESTO_FREE(path, input.path_len + 1);
-                        EXIT;
-                        return -EFAULT;
-                }
-                path[input.path_len] = '\0';
-                CDEBUG(D_PSDEV, "clear_fsetroot: path %s\n", path);
-
-                upccom->uc_pid = current->pid;
-                error = presto_clear_fsetroot(path);
-                upccom->uc_pid = saved_pid;
-                PRESTO_FREE(path, input.path_len + 1);
-                EXIT;
-                return error;
-        }
-
-
-        case PRESTO_CLEAR_ALL_FSETROOTS: {
-                /*
-                 * Close KML files.
-                 */
-                int error;
-                int saved_pid = upccom->uc_pid;
-                char *path;
-                struct {
-                        char *path;
-                        unsigned int path_len;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-                
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                PRESTO_ALLOC(path, char *, input.path_len + 1);
-                if ( !path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(path, input.path, input.path_len)) {
-                        PRESTO_FREE(path, input.path_len + 1);
-                        EXIT;
-                        return -EFAULT;
-                }
-                path[input.path_len] = '\0';
-                CDEBUG(D_PSDEV, "clear_all_fsetroot: path %s\n", path);
-
-                upccom->uc_pid = current->pid;
-                error = presto_clear_all_fsetroots(path);
-                upccom->uc_pid = saved_pid;
-                PRESTO_FREE(path, input.path_len + 1);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_GET_KMLSIZE: {
-                int error;
-                int saved_pid = upccom->uc_pid;
-                char *path;
-                size_t size = 0;
-                struct {
-                        __u64 size;
-                        char *path;
-                        unsigned int path_len;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                PRESTO_ALLOC(path, char *, input.path_len + 1);
-                if ( !path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(path, input.path, input.path_len)) {
-                        PRESTO_FREE(path, input.path_len + 1);
-                        EXIT;
-                        return -EFAULT;
-                }
-                path[input.path_len] = '\0';
-                CDEBUG(D_PSDEV, "get_kmlsize: len %d path %s\n", 
-                       input.path_len, path);
-
-                upccom->uc_pid = current->pid;
-                error = presto_get_kmlsize(path, &size);
-                PRESTO_FREE(path, input.path_len + 1);
-                if (error) {
-                        EXIT;
-                        return error;
-                }
-                input.size = size;
-                upccom->uc_pid = saved_pid;
-
-                CDEBUG(D_PSDEV, "get_kmlsize: size = %Zd\n", size);
-
-                EXIT;
-                if (copy_to_user((char *)arg, &input, sizeof(input)))
-			return -EFAULT;
-		return 0;
-        }
-
-        case PRESTO_GET_RECNO: {
-                int error;
-                int saved_pid = upccom->uc_pid;
-                char *path;
-                off_t recno = 0;
-                struct {
-                        __u64 recno;
-                        char *path;
-                        unsigned int path_len;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                PRESTO_ALLOC(path, char *, input.path_len + 1);
-                if ( !path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(path, input.path, input.path_len)) {
-                        PRESTO_FREE(path, input.path_len + 1);
-                        EXIT;
-                        return -EFAULT;
-                }
-                path[input.path_len] = '\0';
-                CDEBUG(D_PSDEV, "get_recno: len %d path %s\n", 
-                       input.path_len, path);
-
-                upccom->uc_pid = current->pid;
-                error = presto_get_lastrecno(path, &recno);
-                PRESTO_FREE(path, input.path_len + 1);
-                if (error) {
-                        EXIT;
-                        return error;
-                }
-                input.recno = recno;
-                upccom->uc_pid = saved_pid;
-
-                CDEBUG(D_PSDEV, "get_recno: recno = %d\n", (int) recno);
-
-                EXIT;
-                if (copy_to_user((char *)arg, &input, sizeof(input)))
-			return -EFAULT;
-		return 0;
-        }
-
-        case PRESTO_SET_FSETROOT: {
-                /*
-                 * Save information about the cache, and initialize "special"
-                 * cache files (KML, etc).
-                 */
-                int error;
-                int saved_pid = upccom->uc_pid;
-                char *fsetname;
-                char *path;
-                struct {
-                        char *path;
-                        unsigned int path_len;
-                        char *name;
-                        unsigned int name_len;
-                        int   id;
-                        int   flags;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                if(input.name_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-                
-                PRESTO_ALLOC(path, char *, input.path_len + 1);
-                if ( !path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(path, input.path, input.path_len)) {
-                        EXIT;
-			error = -EFAULT;
-                        goto exit_free_path;
-                }
-                path[input.path_len] = '\0';
-
-                PRESTO_ALLOC(fsetname, char *, input.name_len + 1);
-                if ( !fsetname ) {
-                        error = -ENOMEM;
-                        EXIT;
-                        goto exit_free_path;
-                }
-                if (copy_from_user(fsetname, input.name, input.name_len)) {
-                        EXIT;
-			error = -EFAULT;
-                        goto exit_free_fsetname;
-                }
-                fsetname[input.name_len] = '\0';
-
-                CDEBUG(D_PSDEV,
-                       "set_fsetroot: path %s name %s, id %d, flags %x\n",
-                       path, fsetname, input.id, input.flags);
-                upccom->uc_pid = current->pid;
-                error = presto_set_fsetroot(path, fsetname, input.id,input.flags);
-                upccom->uc_pid = saved_pid;
-                if ( error ) {
-                        EXIT;
-                        goto exit_free_fsetname;
-                }
-                /* fsetname is kept in the fset, so don't free it now */
-                PRESTO_FREE(path, input.path_len + 1);
-                EXIT;
-                return 0;
-
-        exit_free_fsetname:
-                PRESTO_FREE(fsetname, input.name_len + 1);
-        exit_free_path:
-                PRESTO_FREE(path, input.path_len + 1);
-                return error;
-        }
-
-        case PRESTO_CLOSE_JOURNALF: {
-                int saved_pid = upccom->uc_pid;
-                int error;
-
-                CDEBUG(D_SUPER, "HELLO\n");
-
-                /* pretend we are lento: we should lock something */
-                upccom->uc_pid = current->pid;
-                error = presto_close_journal_file(NULL);
-                CDEBUG(D_PSDEV, "error is %d\n", error);
-                upccom->uc_pid = saved_pid;
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_GETOPT:
-        case PRESTO_SETOPT: {
-                /* return all the mounts for this device.  */
-                int dosetopt(int, struct psdev_opt *);
-                int dogetopt(int, struct psdev_opt *);
-                int minor = 0;
-                struct psdev_opt kopt;
-                int error = 0;
-                struct psdev_opt *user_opt = (struct psdev_opt *) arg;
-
-                if (copy_from_user(&kopt, (void *)arg, sizeof(kopt))) {
-                        printk("psdev: can't copyin %Zd bytes from %p to %p\n",
-                               sizeof(kopt), (struct kopt *) arg, &kopt);
-                        EXIT;
-                        return -EFAULT;
-                }
-                minor = MINOR(dev);
-                if (cmd == PRESTO_SETOPT)
-                        error = dosetopt(minor, &kopt);
-
-                if ( error ) {
-                        CDEBUG(D_PSDEV,
-                               "dosetopt failed minor %d, opt %d, val %d\n",
-                               minor, kopt.optname, kopt.optval);
-                        EXIT;
-                        return error;
-                }
-
-                error = dogetopt(minor, &kopt);
-
-                if ( error ) {
-                        CDEBUG(D_PSDEV,
-                               "dogetopt failed minor %d, opt %d, val %d\n",
-                               minor, kopt.optname, kopt.optval);
-                        EXIT;
-                        return error;
-                }
-
-                if (copy_to_user(user_opt, &kopt, sizeof(kopt))) {
-                        CDEBUG(D_PSDEV, "Copy_to_user opt 0x%p failed\n",
-                               user_opt);
-                        EXIT;
-                        return -EFAULT;
-                }
-                CDEBUG(D_PSDEV, "dosetopt minor %d, opt %d, val %d return %d\n",
-                         minor, kopt.optname, kopt.optval, error);
-                EXIT;
-                return 0;
-        }
-
-        case PRESTO_VFS_SETATTR: {
-                int error;
-                struct lento_input_attr input;
-                struct iattr iattr;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-                iattr.ia_valid = input.valid;
-                iattr.ia_mode  = (umode_t)input.mode;
-                iattr.ia_uid   = (uid_t)input.uid;
-                iattr.ia_gid   = (gid_t)input.gid;
-                iattr.ia_size  = (off_t)input.size;
-                iattr.ia_atime = (time_t)input.atime;
-                iattr.ia_mtime = (time_t)input.mtime;
-                iattr.ia_ctime = (time_t)input.ctime;
-                iattr.ia_attr_flags = input.attr_flags;
-
-                error = lento_setattr(input.name, &iattr, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_CREATE: {
-                int error;
-                struct lento_input_mode input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_create(input.name, input.mode, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_LINK: {
-                int error;
-                struct lento_input_old_new input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_link(input.oldname, input.newname, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_UNLINK: {
-                int error;
-                struct lento_input input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_unlink(input.name, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_SYMLINK: {
-                int error;
-                struct lento_input_old_new input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_symlink(input.oldname, input.newname,&input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_MKDIR: {
-                int error;
-                struct lento_input_mode input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_mkdir(input.name, input.mode, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_RMDIR: {
-                int error;
-                struct lento_input input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_rmdir(input.name, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_MKNOD: {
-                int error;
-                struct lento_input_dev input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_mknod(input.name, input.mode,
-                                    MKDEV(input.major,input.minor),&input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_RENAME: {
-                int error;
-                struct lento_input_old_new input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_rename(input.oldname, input.newname, &input.info);
-                EXIT;
-                return error;
-        }
-
-#ifdef CONFIG_FS_EXT_ATTR
-        /* IOCTL to create/modify an extended attribute */
-        case PRESTO_VFS_SETEXTATTR: {
-                int error;
-                struct lento_input_ext_attr input;
-                char *name;
-                char *buffer;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                    EXIT;
-                    return -EFAULT;
-                }
-
-                /* Now setup the input parameters */
-                PRESTO_ALLOC(name, char *, input.name_len+1);
-                /* We need null terminated strings for attr names */
-                name[input.name_len] = '\0';
-                if (copy_from_user(name, input.name, input.name_len)) {
-                    EXIT;
-                    PRESTO_FREE(name,input.name_len+1);
-                    return -EFAULT;
-                }
-
-                PRESTO_ALLOC(buffer, char *, input.buffer_len+1);
-                if (copy_from_user(buffer, input.buffer, input.buffer_len)) {
-                    EXIT;
-                    PRESTO_FREE(name,input.name_len+1);
-                    PRESTO_FREE(buffer,input.buffer_len+1);
-                    return -EFAULT;
-                }
-                /* Make null terminated for easy printing */
-                buffer[input.buffer_len]='\0';
- 
-                CDEBUG(D_PSDEV," setextattr params: name %s, valuelen %d,"
-                       " value %s, attr flags %x, mode %o, slot offset %d,"
-                       " recno %d, kml offset %lu, flags %x, time %d\n", 
-                       name, input.buffer_len, buffer, input.flags, input.mode,
-                       input.info.slot_offset, input.info.recno,
-                       (unsigned long) input.info.kml_offset, input.info.flags,
-                       input.info.updated_time);
-
-                error=lento_set_ext_attr
-                      (input.path,name,buffer,input.buffer_len,
-                       input.flags, input.mode, &input.info);
-
-                PRESTO_FREE(name,input.name_len+1);
-                PRESTO_FREE(buffer,input.buffer_len+1);
-                EXIT;
-                return error;
-        }
-
-        /* IOCTL to delete an extended attribute */
-        case PRESTO_VFS_DELEXTATTR: {
-                int error;
-                struct lento_input_ext_attr input;
-                char *name;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                    EXIT;
-                    return -EFAULT;
-                }
-
-                /* Now setup the input parameters */
-                PRESTO_ALLOC(name, char *, input.name_len+1);
-                /* We need null terminated strings for attr names */
-                name[input.name_len] = '\0';
-                if (copy_from_user(name, input.name, input.name_len)) {
-                    EXIT;
-                    PRESTO_FREE(name,input.name_len+1);
-                    return -EFAULT;
-                }
-
-                CDEBUG(D_PSDEV," delextattr params: name %s,"
-                       " attr flags %x, mode %o, slot offset %d, recno %d,"
-                       " kml offset %lu, flags %x, time %d\n", 
-                       name, input.flags, input.mode,
-                       input.info.slot_offset, input.info.recno,
-                       (unsigned long) input.info.kml_offset, input.info.flags,
-                       input.info.updated_time);
-
-                error=lento_set_ext_attr
-                      (input.path,name,NULL,0,input.flags,
-                       input.mode,&input.info);
-                PRESTO_FREE(name,input.name_len+1);
-                EXIT;
-                return error;
-        }
-#endif
-
-        case PRESTO_VFS_IOPEN: {
-                struct lento_input_iopen input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                input.fd = lento_iopen(input.name, (ino_t)input.ino,
-                                       input.generation, input.flags);
-                CDEBUG(D_PIOCTL, "lento_iopen file descriptor: %d\n", input.fd);
-                if (input.fd < 0) {
-                        EXIT;
-                        return input.fd;
-                }
-                EXIT;
-                if (copy_to_user((char *)arg, &input, sizeof(input)))
-			return -EFAULT;
-		return 0;
-        }
-
-        case PRESTO_VFS_CLOSE: {
-                int error;
-                struct lento_input_close input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                CDEBUG(D_PIOCTL, "lento_close file descriptor: %d\n", input.fd);
-                error = lento_close(input.fd, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_BACKFETCH_LML: {
-                char *user_path;
-                struct lml_arg {
-                        char *path;
-                        __u32 path_len;
-                        __u64 remote_ino;
-                        __u32 remote_generation;
-                        __u32 remote_version;
-                        struct presto_version remote_file_version;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                user_path = input.path;
-
-                PRESTO_ALLOC(input.path, char *, input.path_len + 1);
-                if ( !input.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(input.path, user_path, input.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(input.path, input.path_len + 1);
-                        return -EFAULT;
-                }
-                input.path[input.path_len] = '\0';
-
-                CDEBUG(D_DOWNCALL, "lml name: %s\n", input.path);
-                
-                return lento_write_lml(input.path, 
-                                       input.remote_ino, 
-                                       input.remote_generation,
-                                       input.remote_version,
-                                       &input.remote_file_version); 
-
-        }
-                
-
-        case PRESTO_CANCEL_LML: {
-                char *user_path;
-                struct lml_arg {
-                        char *path;
-                        __u64 lml_offset; 
-                        __u32 path_len;
-                        __u64 remote_ino;
-                        __u32 remote_generation;
-                        __u32 remote_version;
-                        struct lento_vfs_context info;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                user_path = input.path;
-
-                PRESTO_ALLOC(input.path, char *, input.path_len + 1);
-                if ( !input.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(input.path, user_path, input.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(input.path, input.path_len + 1);
-                        return -EFAULT;
-                }
-                input.path[input.path_len] = '\0';
-
-                CDEBUG(D_DOWNCALL, "lml name: %s\n", input.path);
-                
-                return lento_cancel_lml(input.path, 
-                                        input.lml_offset, 
-                                        input.remote_ino, 
-                                        input.remote_generation,
-                                        input.remote_version,
-                                        &input.info); 
-
-        }
-
-        case PRESTO_COMPLETE_CLOSES: {
-                char *user_path;
-                int error;
-                struct lml_arg {
-                        char *path;
-                        __u32 path_len;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                user_path = input.path;
-
-                PRESTO_ALLOC(input.path, char *, input.path_len + 1);
-                if ( !input.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(input.path, user_path, input.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(input.path, input.path_len + 1);
-                        return -EFAULT;
-                }
-                input.path[input.path_len] = '\0';
-
-                CDEBUG(D_DOWNCALL, "lml name: %s\n", input.path);
-                
-                error = lento_complete_closes(input.path);
-                PRESTO_FREE(input.path, input.path_len + 1);
-                return error;
-        }
-
-        case PRESTO_RESET_FSET: {
-                char *user_path;
-                struct lml_arg {
-                        char *path;
-                        __u32 path_len;
-                        __u64 offset;
-                        __u32 recno;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                user_path = input.path;
-
-                PRESTO_ALLOC(input.path, char *, input.path_len + 1);
-                if ( !input.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(input.path, user_path, input.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(input.path, input.path_len + 1);
-                        return -EFAULT;
-                }
-                input.path[input.path_len] = '\0';
-
-                CDEBUG(D_DOWNCALL, "lml name: %s\n", input.path);
-                
-                return lento_reset_fset(input.path, input.offset, input.recno); 
-
-        }
-                
-
-        case PRESTO_MARK: {
-                char *user_path;
-                int res = 0;  /* resulting flags - returned to user */
-                int error;
-                struct {
-                        int  mark_what;
-                        int  and_flag;
-                        int  or_flag;
-                        unsigned int path_len;
-                        char *path;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                user_path = input.path;
-
-                PRESTO_ALLOC(input.path, char *, input.path_len + 1);
-                if ( !input.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(input.path, user_path, input.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(input.path, input.path_len + 1);
-                        return -EFAULT;
-                }
-                input.path[input.path_len] = '\0';
-
-                CDEBUG(D_DOWNCALL, "mark name: %s, and: %x, or: %x, what %d\n",
-                       input.path, input.and_flag, input.or_flag, 
-                       input.mark_what);
-
-                switch (input.mark_what) {
-                case MARK_DENTRY:               
-                        error = presto_mark_dentry(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &res);
-                        break;
-                case MARK_FSET:
-                        error = presto_mark_fset(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &res);
-                        break;
-                case MARK_CACHE:
-                        error = presto_mark_cache(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &res);
-                        break;
-                case MARK_GETFL: {
-                        int fflags, cflags;
-                        input.and_flag = 0xffffffff;
-                        input.or_flag = 0; 
-                        error = presto_mark_dentry(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &res);
-                        if (error) 
-                                break;
-                        error = presto_mark_fset(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &fflags);
-                        if (error) 
-                                break;
-                        error = presto_mark_cache(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &cflags);
-
-                        if (error) 
-                                break;
-                        input.and_flag = fflags;
-                        input.or_flag = cflags;
-                	break;
-                }
-                default:
-                        error = -EINVAL;
-                }
-
-                PRESTO_FREE(input.path, input.path_len + 1);
-                if (error == -EBUSY) {
-                        input.and_flag = error;
-                        error = 0;
-                }
-                if (error) { 
-                        EXIT;
-                        return error;
-                }
-                /* return the correct cookie to wait for */
-                input.mark_what = res;
-                if (copy_to_user((char *)arg, &input, sizeof(input)))
-			return -EFAULT;
-		return 0;
-        }
-
-#ifdef  CONFIG_KREINT
-        case PRESTO_REINT_BEGIN:
-                return begin_kml_reint (file, arg);
-        case PRESTO_DO_REINT:
-                return do_kml_reint (file, arg);
-        case PRESTO_REINT_END:
-                return end_kml_reint (file, arg);
-#endif
-
-        case PRESTO_RELEASE_PERMIT: {
-                int error;
-                char *user_path;
-                struct {
-                        int  cookie;
-                        unsigned int path_len;
-                        char *path;
-                } permit;
-                
-                if (copy_from_user(&permit, (char *)arg, sizeof(permit))) {
-                        EXIT;
-                        return -EFAULT;
-		}
-
-                if(permit.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-                user_path = permit.path;
-                
-                PRESTO_ALLOC(permit.path, char *, permit.path_len + 1);
-                if ( !permit.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(permit.path, user_path, permit.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(permit.path, permit.path_len + 1);
-                        return -EFAULT;
-                }
-                permit.path[permit.path_len] = '\0';
-                
-                CDEBUG(D_DOWNCALL, "release permit: %s, in cookie=%d\n",
-                       permit.path, permit.cookie);
-                error = presto_permit_downcall(permit.path, &permit.cookie);
-                
-                PRESTO_FREE(permit.path, permit.path_len + 1);
-                if (error) {
-                        EXIT;
-                        return error;
-                }
-                /* return the correct cookie to wait for */
-                if (copy_to_user((char *)arg, &permit, sizeof(permit)))
-			return -EFAULT;
-		return 0;
-        }
-        
-        default:
-                CDEBUG(D_PSDEV, "bad ioctl 0x%x, \n", cmd);
-                CDEBUG(D_PSDEV, "valid are 0x%Zx - 0x%Zx, 0x%Zx - 0x%Zx \n",
-                        PRESTO_GETMOUNT, PRESTO_GET_KMLSIZE,
-                        PRESTO_VFS_SETATTR, PRESTO_VFS_IOPEN);
-                EXIT;
-        }
-
-        return -EINVAL;
-}
-
 
 static int presto_psdev_open(struct inode * inode, struct file * file)
 {
-         struct upc_comm *upccom;
-         ENTRY;
+        ENTRY;
 
-         if ( ! (upccom = presto_psdev_f2u(file)) ) {
-                 kdev_t dev = file->f_dentry->d_inode->i_rdev;
-                 printk("InterMezzo: %s, bad device %s\n",
-                        __FUNCTION__, kdevname(dev));
-                 EXIT;
-                 return -EINVAL;
-         }
+        file->private_data = NULL;  
 
         MOD_INC_USE_COUNT;
 
-        CDEBUG(D_PSDEV, "Psdev_open: uc_pid: %d, caller: %d, flags: %d\n",
-               upccom->uc_pid, current->pid, file->f_flags);
+        CDEBUG(D_PSDEV, "Psdev_open: caller: %d, flags: %d\n", current->pid, file->f_flags);
 
         EXIT;
         return 0;
@@ -1308,32 +323,25 @@
 
 static int presto_psdev_release(struct inode * inode, struct file * file)
 {
-        struct upc_comm *upccom;
+        struct upc_channel *channel = (struct upc_channel *)file->private_data;
         struct upc_req *req;
         struct list_head *lh;
         ENTRY;
 
-
-        if ( ! (upccom = presto_psdev_f2u(file)) ) {
-                kdev_t dev = file->f_dentry->d_inode->i_rdev;
-                printk("InterMezzo: %s, bad device %s\n",
-                       __FUNCTION__, kdevname(dev));
-        }
-
-        if ( upccom->uc_pid != current->pid ) {
-                printk("psdev_release: Not lento.\n");
-                MOD_DEC_USE_COUNT;
-                return 0;
+        if ( ! channel ) { 
+                CERROR("%s: bad psdev file\n", __FUNCTION__);
+                return -EBADF;
         }
 
         MOD_DEC_USE_COUNT;
         CDEBUG(D_PSDEV, "Lento: pid %d\n", current->pid);
-        upccom->uc_pid = 0;
+        channel->uc_pid = 0;
 
         /* Wake up clients so they can return. */
         CDEBUG(D_PSDEV, "Wake up clients sleeping for pending.\n");
-        lh = &upccom->uc_pending;
-        while ( (lh = lh->next) != &upccom->uc_pending) {
+        spin_lock(&channel->uc_lock); 
+        lh = &channel->uc_pending;
+        while ( (lh = lh->next) != &channel->uc_pending) {
                 req = list_entry(lh, struct upc_req, rq_chain);
 
                 /* Async requests stay around for a new lento */
@@ -1346,13 +354,14 @@
         }
 
         CDEBUG(D_PSDEV, "Wake up clients sleeping for processing\n");
-        lh = &upccom->uc_processing;
-        while ( (lh = lh->next) != &upccom->uc_processing) {
+        lh = &channel->uc_processing;
+        while ( (lh = lh->next) != &channel->uc_processing) {
                 req = list_entry(lh, struct upc_req, rq_chain);
                 /* freeing of req and data is done by the sleeper */
                 req->rq_flags |= REQ_DEAD; 
                 wake_up(&req->rq_sleep);
         }
+        spin_unlock(&channel->uc_lock); 
         CDEBUG(D_PSDEV, "Done.\n");
 
         EXIT;
@@ -1360,57 +369,46 @@
 }
 
 static struct file_operations presto_psdev_fops = {
-        read:    presto_psdev_read,
-        write:   presto_psdev_write,
-        poll:    presto_psdev_poll,
-        ioctl:   presto_psdev_ioctl,
-        open:    presto_psdev_open,
-        release: presto_psdev_release
+        .read    = presto_psdev_read,
+        .write   = presto_psdev_write,
+        .poll    = presto_psdev_poll,
+        .open    = presto_psdev_open,
+        .release = presto_psdev_release
 };
 
+/* modules setup */
+static struct miscdevice intermezzo_psdev = {
+        INTERMEZZO_MINOR,
+        "intermezzo",
+        &presto_psdev_fops
+};
 
 int  presto_psdev_init(void)
 {
         int i;
+        int err; 
 
-#ifdef PRESTO_DEVEL
-        if (register_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev_devel",
-                           &presto_psdev_fops)) {
-                printk(KERN_ERR "presto_psdev: unable to get major %d\n",
-                       PRESTO_PSDEV_MAJOR);
+        if ( (err = misc_register(&intermezzo_psdev)) ) { 
+                CERROR("%s: cannot register %d err %d\n", 
+                       __FUNCTION__, INTERMEZZO_MINOR, err);
                 return -EIO;
         }
-#else
-        if (register_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev",
-                           &presto_psdev_fops)) {
-                printk("presto_psdev: unable to get major %d\n",
-                       PRESTO_PSDEV_MAJOR);
-                return -EIO;
-        }
-#endif
 
-        memset(&upc_comms, 0, sizeof(upc_comms));
-        for ( i = 0 ; i < MAX_PRESTODEV ; i++ ) {
-                char *name;
-                struct upc_comm *psdev = &upc_comms[i];
-                INIT_LIST_HEAD(&psdev->uc_pending);
-                INIT_LIST_HEAD(&psdev->uc_processing);
-                INIT_LIST_HEAD(&psdev->uc_cache_list);
-                init_waitqueue_head(&psdev->uc_waitq);
-                psdev->uc_hard = 0;
-                psdev->uc_no_filter = 0;
-                psdev->uc_no_journal = 0;
-                psdev->uc_no_upcall = 0;
-                psdev->uc_timeout = 30;
-                psdev->uc_errorval = 0;
-                psdev->uc_minor = i;
-                PRESTO_ALLOC(name, char *, strlen(PRESTO_PSDEV_NAME "256")+1);
-                if (!name) { 
-                        printk("Unable to allocate memory for device name\n");
-                        continue;
-                }
-                sprintf(name, PRESTO_PSDEV_NAME "%d", i); 
-                psdev->uc_devname = name;
+        memset(&izo_channels, 0, sizeof(izo_channels));
+        for ( i = 0 ; i < MAX_CHANNEL ; i++ ) {
+                struct upc_channel *channel = &(izo_channels[i]);
+                INIT_LIST_HEAD(&channel->uc_pending);
+                INIT_LIST_HEAD(&channel->uc_processing);
+                INIT_LIST_HEAD(&channel->uc_cache_list);
+                init_waitqueue_head(&channel->uc_waitq);
+                channel->uc_lock = SPIN_LOCK_UNLOCKED;
+                channel->uc_hard = 0;
+                channel->uc_no_filter = 0;
+                channel->uc_no_journal = 0;
+                channel->uc_no_upcall = 0;
+                channel->uc_timeout = 30;
+                channel->uc_errorval = 0;
+                channel->uc_minor = i;
         }
         return 0;
 }
@@ -1419,25 +417,24 @@
 {
         int i;
 
-        for ( i = 0 ; i < MAX_PRESTODEV ; i++ ) {
-                struct upc_comm *psdev = &upc_comms[i];
+        misc_deregister(&intermezzo_psdev);
+
+        for ( i = 0 ; i < MAX_CHANNEL ; i++ ) {
+                struct upc_channel *channel = &(izo_channels[i]);
                 struct list_head *lh;
 
-                if ( ! list_empty(&psdev->uc_pending)) { 
-                        printk("Weird, tell Peter: module cleanup and pending list not empty dev %d\n", i);
-                }
-                if ( ! list_empty(&psdev->uc_processing)) { 
-                        printk("Weird, tell Peter: module cleanup and processing list not empty dev %d\n", i);
+                spin_lock(&channel->uc_lock); 
+                if ( ! list_empty(&channel->uc_pending)) { 
+                        CERROR("Weird, tell Peter: module cleanup and pending list not empty dev %d\n", i);
                 }
-                if ( ! list_empty(&psdev->uc_cache_list)) { 
-                        printk("Weird, tell Peter: module cleanup and cache listnot empty dev %d\n", i);
+                if ( ! list_empty(&channel->uc_processing)) { 
+                        CERROR("Weird, tell Peter: module cleanup and processing list not empty dev %d\n", i);
                 }
-                if (psdev->uc_devname) {
-                        PRESTO_FREE(psdev->uc_devname,
-                                    strlen(PRESTO_PSDEV_NAME "256")+1);
+                if ( ! list_empty(&channel->uc_cache_list)) { 
+                        CERROR("Weird, tell Peter: module cleanup and cache listnot empty dev %d\n", i);
                 }
-                lh = psdev->uc_pending.next;
-                while ( lh != &psdev->uc_pending) {
+                lh = channel->uc_pending.next;
+                while ( lh != &channel->uc_pending) {
                         struct upc_req *req;
 
                         req = list_entry(lh, struct upc_req, rq_chain);
@@ -1453,22 +450,23 @@
                                 wake_up(&req->rq_sleep);
                         }
                 }
-                lh = &psdev->uc_processing;
-                while ( (lh = lh->next) != &psdev->uc_processing ) {
+                lh = &channel->uc_processing;
+                while ( (lh = lh->next) != &channel->uc_processing ) {
                         struct upc_req *req;
                         req = list_entry(lh, struct upc_req, rq_chain);
                         list_del(&(req->rq_chain));
                         req->rq_flags |= REQ_DEAD; 
                         wake_up(&req->rq_sleep);
                 }
+                spin_unlock(&channel->uc_lock); 
         }
 }
 
 /*
  * lento_upcall and lento_downcall routines
  */
-static inline unsigned long lento_waitfor_upcall(struct upc_req *req,
-                                                 int minor)
+static inline unsigned long lento_waitfor_upcall
+            (struct upc_channel *channel, struct upc_req *req, int minor)
 {
         DECLARE_WAITQUEUE(wait, current);
         unsigned long posttime;
@@ -1477,16 +475,17 @@
 
         add_wait_queue(&req->rq_sleep, &wait);
         for (;;) {
-                if ( upc_comms[minor].uc_hard == 0 )
-                        current->state = TASK_INTERRUPTIBLE;
+                if ( izo_channels[minor].uc_hard == 0 )
+                        set_current_state(TASK_INTERRUPTIBLE);
                 else
-                        current->state = TASK_UNINTERRUPTIBLE;
+                        set_current_state(TASK_UNINTERRUPTIBLE);
 
                 /* got a reply */
                 if ( req->rq_flags & (REQ_WRITE | REQ_DEAD) )
                         break;
 
-                if ( !upc_comms[minor].uc_hard && signal_pending(current) ) {
+                /* these cases only apply when TASK_INTERRUPTIBLE */ 
+                if ( !izo_channels[minor].uc_hard && signal_pending(current) ) {
                         /* if this process really wants to die, let it go */
                         if (sigismember(&(current->pending.signal), SIGKILL)||
                             sigismember(&(current->pending.signal), SIGINT) )
@@ -1494,21 +493,21 @@
                         /* signal is present: after timeout always return
                            really smart idea, probably useless ... */
                         if ( time_after(jiffies, req->rq_posttime +
-                             upc_comms[minor].uc_timeout * HZ) )
+                             izo_channels[minor].uc_timeout * HZ) )
                                 break;
                 }
                 schedule();
-
         }
-      list_del(&req->rq_chain); 
-      INIT_LIST_HEAD(&req->rq_chain); 
+
+        spin_lock(&channel->uc_lock);
+        list_del_init(&req->rq_chain); 
+        spin_unlock(&channel->uc_lock);
         remove_wait_queue(&req->rq_sleep, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
 
         CDEBUG(D_SPECIAL, "posttime: %ld, returned: %ld\n",
                posttime, jiffies-posttime);
         return  (jiffies - posttime);
-
 }
 
 /*
@@ -1524,31 +523,30 @@
  * is read (in presto_psdev_read), when the filesystem is unmounted, or
  * when the module is unloaded.
  */
-int lento_upcall(int minor, int bufsize, int *rep_size, union up_args *buffer,
-                 int async, struct upc_req *rq)
+int izo_upc_upcall(int minor, int *size, struct izo_upcall_hdr *buffer, 
+                   int async)
 {
         unsigned long runtime;
-        struct upc_comm *upc_commp;
-        union down_args *out;
+        struct upc_channel *channel;
+        struct izo_upcall_resp *out;
         struct upc_req *req;
         int error = 0;
 
         ENTRY;
-        upc_commp = &(upc_comms[minor]);
+        channel = &(izo_channels[minor]);
 
-        if (upc_commp->uc_no_upcall) {
+        if (channel->uc_no_upcall) {
                 EXIT;
                 goto exit_buf;
         }
-        if (!upc_commp->uc_pid && !async) {
+        if (!channel->uc_pid && !async) {
                 EXIT;
                 error = -ENXIO;
                 goto exit_buf;
         }
 
         /* Format the request message. */
-        CDEBUG(D_UPCALL, "buffer at %p, size %d\n", buffer, bufsize);
-        PRESTO_ALLOC(req, struct upc_req *, sizeof(struct upc_req));
+        PRESTO_ALLOC(req, sizeof(struct upc_req));
         if ( !req ) {
                 EXIT;
                 error = -ENOMEM;
@@ -1556,29 +554,29 @@
         }
         req->rq_data = (void *)buffer;
         req->rq_flags = 0;
-        req->rq_bufsize = bufsize;
+        req->rq_bufsize = *size;
         req->rq_rep_size = 0;
-        req->rq_opcode = ((union up_args *)buffer)->uh.opcode;
-        req->rq_unique = ++upc_commp->uc_seq;
+        req->rq_opcode = buffer->u_opc;
+        req->rq_unique = ++channel->uc_seq;
         init_waitqueue_head(&req->rq_sleep);
 
         /* Fill in the common input args. */
-        ((union up_args *)buffer)->uh.unique = req->rq_unique;
+        buffer->u_uniq = req->rq_unique;
+        buffer->u_async = async;
+
+        spin_lock(&channel->uc_lock); 
         /* Append msg to pending queue and poke Lento. */
-        list_add(&req->rq_chain, upc_commp->uc_pending.prev);
+        list_add(&req->rq_chain, channel->uc_pending.prev);
+        spin_unlock(&channel->uc_lock); 
         CDEBUG(D_UPCALL,
                "Proc %d waking Lento %d for(opc,uniq) =(%d,%d) msg at %p.\n",
-               current->pid, upc_commp->uc_pid, req->rq_opcode,
+               current->pid, channel->uc_pid, req->rq_opcode,
                req->rq_unique, req);
-
-        wake_up_interruptible(&upc_commp->uc_waitq);
+        wake_up_interruptible(&channel->uc_waitq);
 
         if ( async ) {
-                req->rq_flags = REQ_ASYNC;
-                if( rq != NULL ) {
-                        *rq = *req; /* struct copying */
-                }
                 /* req, rq_data are freed in presto_psdev_read for async */
+                req->rq_flags = REQ_ASYNC;
                 EXIT;
                 return 0;
         }
@@ -1593,29 +591,29 @@
          * ENODEV.  */
 
         /* Go to sleep.  Wake up on signals only after the timeout. */
-        runtime = lento_waitfor_upcall(req, minor);
+        runtime = lento_waitfor_upcall(channel, req, minor);
 
         CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
                req->rq_opcode, jiffies - req->rq_posttime,
                req->rq_unique, req->rq_rep_size);
         CDEBUG(D_UPCALL,
-               "..process %d woken up by Lento for req at 0x%p, data at %p\n",
-               current->pid, req, req->rq_data);
+               "..process %d woken up by Lento for req at 0x%x, data at %x\n",
+               current->pid, (int)req, (int)req->rq_data);
 
-        if (upc_commp->uc_pid) {      /* i.e. Lento is still alive */
+        if (channel->uc_pid) {      /* i.e. Lento is still alive */
           /* Op went through, interrupt or not we go on */
             if (req->rq_flags & REQ_WRITE) {
-                    out = (union down_args *)req->rq_data;
+                    out = (struct izo_upcall_resp *)req->rq_data;
                     /* here we map positive Lento errors to kernel errors */
-                    if ( out->dh.result < 0 ) {
-                            printk("Tell Peter: Lento returns negative error %d, for oc %d!\n",
-                                   out->dh.result, out->dh.opcode);
-                          out->dh.result = EINVAL;
+                    if ( out->result < 0 ) {
+                            CERROR("Tell Peter: Lento returns negative error %d, for oc %d!\n",
+                                   out->result, out->opcode);
+                          out->result = EINVAL;
                     }
-                    error = -out->dh.result;
+                    error = -out->result;
                     CDEBUG(D_UPCALL, "upcall: (u,o,r) (%d, %d, %d) out at %p\n",
-                           out->dh.unique, out->dh.opcode, out->dh.result, out);
-                    *rep_size = req->rq_rep_size;
+                           out->unique, out->opcode, out->result, out);
+                    *size = req->rq_rep_size;
                     EXIT;
                     goto exit_req;
             }
@@ -1632,53 +630,16 @@
 
             /* interrupted after Lento did its read, send signal */
             if ( (req->rq_flags & REQ_READ) && signal_pending(current) ) {
-                    union up_args *sigargs;
-                    struct upc_req *sigreq;
-
-                    CDEBUG(D_UPCALL,"Sending for: op = %d.%d, flags = %x\n",
+                    CDEBUG(D_UPCALL,"Interrupt after read: op = %d.%d, flags = %x\n",
                            req->rq_opcode, req->rq_unique, req->rq_flags);
 
                     error = -EINTR;
-
-                    /* req, rq_data are freed in presto_psdev_read for async */
-                    PRESTO_ALLOC(sigreq, struct upc_req *,
-                                 sizeof (struct upc_req));
-                    if (!sigreq) {
-                            error = -ENOMEM;
-                            EXIT;
-                            goto exit_req;
-                    }
-                    PRESTO_ALLOC((sigreq->rq_data), char *,
-                                 sizeof(struct lento_up_hdr));
-                    if (!(sigreq->rq_data)) {
-                            PRESTO_FREE(sigreq, sizeof (struct upc_req));
-                            error = -ENOMEM;
-                            EXIT;
-                            goto exit_req;
-                    }
-
-                    sigargs = (union up_args *)sigreq->rq_data;
-                    sigargs->uh.opcode = LENTO_SIGNAL;
-                    sigargs->uh.unique = req->rq_unique;
-
-                    sigreq->rq_flags = REQ_ASYNC;
-                    sigreq->rq_opcode = sigargs->uh.opcode;
-                    sigreq->rq_unique = sigargs->uh.unique;
-                    sigreq->rq_bufsize = sizeof(struct lento_up_hdr);
-                    sigreq->rq_rep_size = 0;
-                    CDEBUG(D_UPCALL,
-                           "presto_upcall: enqueing signal msg (%d, %d)\n",
-                           sigreq->rq_opcode, sigreq->rq_unique);
-
-                    /* insert at head of queue! */
-                    list_add(&sigreq->rq_chain, &upc_commp->uc_pending);
-                    wake_up_interruptible(&upc_commp->uc_waitq);
             } else {
-                  printk("Lento: Strange interruption - tell Peter.\n");
+                  CERROR("Lento: Strange interruption - tell Peter.\n");
                     error = -EINTR;
             }
-        } else {        /* If lento died i.e. !UC_OPEN(upc_commp) */
-                printk("presto_upcall: Lento dead on (op,un) (%d.%d) flags %d\n",
+        } else {        /* If lento died i.e. !UC_OPEN(channel) */
+                CERROR("lento_upcall: Lento dead on (op,un) (%d.%d) flags %d\n",
                        req->rq_opcode, req->rq_unique, req->rq_flags);
                 error = -ENODEV;
         }
@@ -1686,8 +647,5 @@
 exit_req:
         PRESTO_FREE(req, sizeof(struct upc_req));
 exit_buf:
-        PRESTO_FREE(buffer, bufsize);
         return error;
 }
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/replicator.c linux-2.4.20/fs/intermezzo/replicator.c
--- linux-2.4.19/fs/intermezzo/replicator.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/replicator.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,291 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
+ * Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Manage RCVD records for clients in the kernel
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <stdarg.h>
+#include <asm/uaccess.h>
+
+#include <linux/errno.h>
+
+#include <linux/intermezzo_fs.h>
+
+/*
+ * this file contains a hash table of replicators/clients for a
+ * fileset. It allows fast lookup and update of reintegration status
+ */
+
+struct izo_offset_rec {
+	struct list_head or_list;
+	char             or_uuid[16];
+	loff_t           or_offset;
+};
+
+#define RCACHE_BITS 8
+#define RCACHE_SIZE (1 << RCACHE_BITS)
+#define RCACHE_MASK (RCACHE_SIZE - 1)
+
+static struct list_head *
+izo_rep_cache(void)
+{
+	int i;
+	struct list_head *cache;
+	PRESTO_ALLOC(cache, sizeof(struct list_head) * RCACHE_SIZE);
+	if (cache == NULL) {
+		CERROR("intermezzo-fatal: no memory for replicator cache\n");
+                return NULL;
+	}
+	memset(cache, 0, sizeof(struct list_head) * RCACHE_SIZE);
+	for (i = 0; i < RCACHE_SIZE; i++)
+		INIT_LIST_HEAD(&cache[i]);
+
+	return cache;
+}
+
+static struct list_head *
+izo_rep_hash(struct list_head *cache, char *uuid)
+{
+        return &cache[(RCACHE_MASK & uuid[1])];
+}
+
+static void
+izo_rep_cache_clean(struct presto_file_set *fset)
+{
+	int i;
+	struct list_head *bucket;
+	struct list_head *tmp;
+
+        if (fset->fset_clients == NULL)
+		return;
+        for (i = 0; i < RCACHE_SIZE; i++) {
+		tmp = bucket = &fset->fset_clients[i];
+
+		tmp = tmp->next;
+                while (tmp != bucket) {
+			struct izo_offset_rec *offrec;
+			tmp = tmp->next;
+			list_del(tmp);
+			offrec = list_entry(tmp, struct izo_offset_rec,
+					    or_list);
+			PRESTO_FREE(offrec, sizeof(struct izo_offset_rec));
+		}
+	}
+}
+
+struct izo_offset_rec *
+izo_rep_cache_find(struct presto_file_set *fset, char *uuid)
+{
+	struct list_head *buck = izo_rep_hash(fset->fset_clients, uuid);
+	struct list_head *tmp = buck;
+        struct izo_offset_rec *rec = NULL;
+
+        while ( (tmp = tmp->next) != buck ) {
+		rec = list_entry(tmp, struct izo_offset_rec, or_list);
+                if ( memcmp(rec->or_uuid, uuid, sizeof(rec->or_uuid)) == 0 )
+			return rec;
+	}
+
+	return NULL;
+}
+
+static int
+izo_rep_cache_add(struct presto_file_set *fset, struct izo_rcvd_rec *rec,
+                  loff_t offset)
+{
+        struct izo_offset_rec *offrec;
+
+        if (izo_rep_cache_find(fset, rec->lr_uuid)) {
+                CERROR("izo: duplicate client entry %s off %Ld\n",
+                       fset->fset_name, offset);
+                return -EINVAL;
+        }
+
+        PRESTO_ALLOC(offrec, sizeof(*offrec));
+        if (offrec == NULL) {
+                CERROR("izo: cannot allocate offrec\n");
+                return -ENOMEM;
+        }
+
+        memcpy(offrec->or_uuid, rec->lr_uuid, sizeof(rec->lr_uuid));
+        offrec->or_offset = offset;
+
+        list_add(&offrec->or_list,
+                 izo_rep_hash(fset->fset_clients, rec->lr_uuid));
+        return 0;
+}
+
+int
+izo_rep_cache_init(struct presto_file_set *fset)
+{
+	struct izo_rcvd_rec rec;
+        loff_t offset = 0, last_offset = 0;
+
+	fset->fset_clients = izo_rep_cache();
+        if (fset->fset_clients == NULL) {
+		CERROR("Error initializing client cache\n");
+		return -ENOMEM;
+	}
+
+        while ( presto_fread(fset->fset_rcvd.fd_file, (char *)&rec,
+                             sizeof(rec), &offset) == sizeof(rec) ) {
+                int rc;
+
+                if ((rc = izo_rep_cache_add(fset, &rec, last_offset)) < 0) {
+			izo_rep_cache_clean(fset);
+			return rc;
+		}
+
+                last_offset = offset;
+	}
+
+	return 0;
+}
+
+/*
+ * Return local last_rcvd record for the client. Update or create 
+ * if necessary.
+ *
+ * XXX: After this call, any -EINVAL from izo_rcvd_get is a real error.
+ */
+int
+izo_repstatus(struct presto_file_set *fset,  __u64 client_kmlsize, 
+              struct izo_rcvd_rec *lr_client, struct izo_rcvd_rec *lr_server)
+{
+        int rc;
+        rc = izo_rcvd_get(lr_server, fset, lr_client->lr_uuid);
+        if (rc < 0 && rc != -EINVAL) {
+                return rc;
+        }
+
+        /* client is new or has been reset. */
+        if (rc < 0 || (client_kmlsize == 0 && lr_client->lr_remote_offset == 0)) {
+                memset(lr_server, 0, sizeof(*lr_server));
+                memcpy(lr_server->lr_uuid, lr_client->lr_uuid, sizeof(lr_server->lr_uuid));
+                rc = izo_rcvd_write(fset, lr_server);
+                if (rc < 0)
+                        return rc;
+        }
+
+        /* update intersync */
+        rc = izo_upc_repstatus(presto_f2m(fset), fset->fset_name, lr_server);
+        return rc;
+}
+
+loff_t
+izo_rcvd_get(struct izo_rcvd_rec *rec, struct presto_file_set *fset, char *uuid)
+{
+        struct izo_offset_rec *offrec;
+        struct izo_rcvd_rec tmprec;
+        loff_t offset;
+
+        offrec = izo_rep_cache_find(fset, uuid);
+        if (offrec == NULL) {
+                CDEBUG(D_SPECIAL, "izo_get_rcvd: uuid not in hash.\n");
+                return -EINVAL;
+        }
+        offset = offrec->or_offset;
+
+        if (rec == NULL)
+                return offset;
+
+        if (presto_fread(fset->fset_rcvd.fd_file, (char *)&tmprec,
+                         sizeof(tmprec), &offset) != sizeof(tmprec)) {
+                CERROR("izo_get_rcvd: Unable to read from last_rcvd file offset "
+                       "%Lu\n", offset);
+                return -EIO;
+        }
+
+        memcpy(rec->lr_uuid, tmprec.lr_uuid, sizeof(tmprec.lr_uuid));
+        rec->lr_remote_recno = le64_to_cpu(tmprec.lr_remote_recno);
+        rec->lr_remote_offset = le64_to_cpu(tmprec.lr_remote_offset);
+        rec->lr_local_recno = le64_to_cpu(tmprec.lr_local_recno);
+        rec->lr_local_offset = le64_to_cpu(tmprec.lr_local_offset);
+        rec->lr_last_ctime = le64_to_cpu(tmprec.lr_last_ctime);
+
+        return offrec->or_offset;
+}
+
+/* Try to lookup the UUID in the hash.  Insert it if it isn't found.  Write the
+ * data to the file.
+ *
+ * Returns the offset of the beginning of the record in the last_rcvd file. */
+loff_t
+izo_rcvd_write(struct presto_file_set *fset, struct izo_rcvd_rec *rec)
+{
+        struct izo_offset_rec *offrec;
+        loff_t offset, rc;
+
+        ENTRY;
+
+        offrec = izo_rep_cache_find(fset, rec->lr_uuid);
+        if (offrec == NULL) {
+                /* I don't think it should be possible for an entry to be not in
+                 * the hash table without also having an invalid offset, but we
+                 * handle it gracefully regardless. */
+                write_lock(&fset->fset_rcvd.fd_lock);
+                offset = fset->fset_rcvd.fd_offset;
+                fset->fset_rcvd.fd_offset += sizeof(*rec);
+                write_unlock(&fset->fset_rcvd.fd_lock);
+
+                rc = izo_rep_cache_add(fset, rec, offset);
+                if (rc < 0) {
+                        EXIT;
+                        return rc;
+                }
+        } else
+                offset = offrec->or_offset;
+        
+
+        rc = presto_fwrite(fset->fset_rcvd.fd_file, (char *)rec, sizeof(*rec),
+                           &offset);
+        if (rc == sizeof(*rec))
+                /* presto_fwrite() advances 'offset' */
+                rc = offset - sizeof(*rec);
+
+        EXIT;
+        return rc;
+}
+
+loff_t
+izo_rcvd_upd_remote(struct presto_file_set *fset, char * uuid,  __u64 remote_recno, 
+                    __u64 remote_offset)
+{
+        struct izo_rcvd_rec rec;
+        
+        loff_t rc;
+
+        ENTRY;
+        rc = izo_rcvd_get(&rec, fset, uuid);
+        if (rc < 0)
+                return rc;
+        rec.lr_remote_recno = remote_recno;
+        rec.lr_remote_offset = remote_offset;
+
+        rc = izo_rcvd_write(fset, &rec);
+        EXIT;
+        if (rc < 0)
+                return rc;
+        return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/super.c linux-2.4.20/fs/intermezzo/super.c
--- linux-2.4.19/fs/intermezzo/super.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/super.c	2002-10-29 11:18:51.000000000 +0000
@@ -1,13 +1,30 @@
-/*
- *  presto's super.c
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
- *  Copyright (C) 1998 Peter J. Braam
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
  *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ *  presto's super.c
  */
 
+static char rcsid[] __attribute ((unused)) = "$Id: super.c,v 1.41 2002/10/03 03:50:49 rread Exp $";
+#define INTERMEZZO_VERSION "$Revision: 1.41 $"
 
 #include <stdarg.h>
 
@@ -26,11 +43,11 @@
 #include <linux/locks.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 
 #ifdef PRESTO_DEBUG
@@ -38,23 +55,8 @@
 long presto_kmemory = 0;
 #endif
 
-extern struct presto_cache *presto_init_cache(void);
-extern inline void presto_cache_add(struct presto_cache *cache, kdev_t dev);
-extern inline void presto_init_cache_hash(void);
-
-int presto_remount(struct super_block *, int *, char *);
-extern ssize_t presto_file_write(struct file *file, const char *buf, 
-                                 size_t size, loff_t *off);
-
-/*
- *  Reading the super block.
- *
- *
- *
- */
-
 /* returns an allocated string, copied out from data if opt is found */
-static char *read_opt(const char *opt, char *data)
+static char *opt_read(const char *opt, char *data)
 {
         char *value;
         char *retval;
@@ -67,9 +69,9 @@
                 return NULL;
 
         value++;
-        PRESTO_ALLOC(retval, char *, strlen(value) + 1);
+        PRESTO_ALLOC(retval, strlen(value) + 1);
         if ( !retval ) {
-                printk("InterMezzo: Out of memory!\n");
+                CERROR("InterMezzo: Out of memory!\n");
                 return NULL;
         }
 
@@ -78,21 +80,30 @@
         return retval;
 }
 
-static void store_opt(char **dst, char *opt, char *defval)
+static void opt_store(char **dst, char *opt)
 {
-        if (dst) {
-                if (*dst) { 
-                        PRESTO_FREE(*dst, strlen(*dst) + 1);
-                }
-                *dst = opt;
-        } else {
-                printk("presto: store_opt, error dst == NULL\n"); 
-        }
+        if (!dst) 
+                CERROR("intermezzo: store_opt, error dst == NULL\n"); 
+
+        if (*dst)
+                PRESTO_FREE(*dst, strlen(*dst) + 1);
+        *dst = opt;
+}
 
+static void opt_set_default(char **dst, char *defval)
+{
+        if (!dst) 
+                CERROR("intermezzo: store_opt, error dst == NULL\n"); 
 
-        if (!opt && defval) {
+        if (*dst)
+                PRESTO_FREE(*dst, strlen(*dst) + 1);
+        if (defval) {
                 char *def_alloced; 
-                PRESTO_ALLOC(def_alloced, char *, strlen(defval)+1);
+                PRESTO_ALLOC(def_alloced, strlen(defval)+1);
+                if (!def_alloced) {
+                        CERROR("InterMezzo: Out of memory!\n");
+                        return ;
+                }
                 strcpy(def_alloced, defval);
                 *dst = def_alloced; 
         }
@@ -105,19 +116,23 @@
  * to the read_super operation of the cache).  The return value will
  * be a pointer to the end of the cache_data.
  */
-static char *presto_options(char *options, char *cache_data,
+static char *presto_options(struct super_block *sb, 
+                            char *options, char *cache_data,
                             char **cache_type, char **fileset,
-                            char **prestodev,  char **mtpt)
+                            char **channel)
 {
         char *this_char;
         char *cache_data_end = cache_data;
 
+        /* set the defaults */ 
+        if (strcmp(sb->s_type->name, "intermezzo") == 0)
+            opt_set_default(cache_type, "ext3"); 
+        else 
+            opt_set_default(cache_type, "tmpfs"); 
+            
         if (!options || !cache_data)
                 return cache_data_end;
 
-        /* set the defaults */ 
-        store_opt(cache_type, NULL, "ext3"); 
-        store_opt(prestodev, NULL, PRESTO_PSDEV_NAME "0"); 
 
         CDEBUG(D_SUPER, "parsing options\n");
         for (this_char = strtok (options, ",");
@@ -126,119 +141,80 @@
                 char *opt;
                 CDEBUG(D_SUPER, "this_char %s\n", this_char);
 
-                if ( (opt = read_opt("fileset", this_char)) ) {
-                        store_opt(fileset, opt, NULL);
+                if ( (opt = opt_read("fileset", this_char)) ) {
+                        opt_store(fileset, opt);
                         continue;
                 }
-                if ( (opt = read_opt("cache_type", this_char)) ) {
-                        store_opt(cache_type, opt, "ext3");
+                if ( (opt = opt_read("cache_type", this_char)) ) {
+                        opt_store(cache_type, opt);
                         continue;
                 }
-                if ( (opt = read_opt("mtpt", this_char)) ) {
-                        store_opt(mtpt, opt, NULL);
-                        continue;
-                }
-                if ( (opt = read_opt("prestodev", this_char)) ) {
-                        store_opt(prestodev, opt, PRESTO_PSDEV_NAME);
+                if ( (opt = opt_read("channel", this_char)) ) {
+                        opt_store(channel, opt);
                         continue;
                 }
 
-                cache_data_end += sprintf(cache_data_end, "%s%s",
-                                          cache_data_end != cache_data ? ",":"",
-                                          this_char);
+                cache_data_end += 
+                        sprintf(cache_data_end, "%s%s",
+                                cache_data_end != cache_data ? ",":"", 
+                                this_char);
         }
 
         return cache_data_end;
 }
 
-/*
-    map a /dev/intermezzoX path to a minor:
-    used to validate mount options passed to InterMezzo
- */
-static int presto_get_minor(char *dev_path, int *minor)
+static int presto_set_channel(struct presto_cache *cache, char *channel)
 {
-        struct nameidata nd;
-        struct dentry *dentry;
-        kdev_t devno = 0;
-        int error; 
+        int minor; 
+
         ENTRY;
+        if (!channel) {
+                minor = izo_psdev_get_free_channel();
+        } else {
+                minor = simple_strtoul(channel, NULL, 0); 
+        }
+        if (minor < 0 || minor >= MAX_CHANNEL) { 
+                CERROR("all channels in use or channel too large %d\n", 
+                       minor);
+                return -EINVAL;
+        }
+        
+        cache->cache_psdev = &(izo_channels[minor]);
+        list_add(&cache->cache_channel_list, 
+                 &cache->cache_psdev->uc_cache_list); 
 
-        /* Special case for root filesystem - use minor 0 always. */
-        if ( current->pid == 1 ) {
-                *minor = 0;
-                return 0;
-        }
-
-        error = presto_walk(dev_path, &nd);
-        if (error) {
-		EXIT;
-                return error;
-	}
-        dentry = nd.dentry;
-
-	error = -ENODEV;
-        if (!dentry->d_inode) { 
-		EXIT;
-		goto out;
-	}
-
-        if (!S_ISCHR(dentry->d_inode->i_mode)) {
-		EXIT;
-		goto out;
-	}
-
-        devno = dentry->d_inode->i_rdev;
-        if ( MAJOR(devno) != PRESTO_PSDEV_MAJOR ) { 
-		EXIT;
-		goto out;
-	}
-
-        if ( MINOR(devno) >= MAX_PRESTODEV ) {
-		EXIT;
-		goto out;
-	}
-
-	EXIT;
- out:
-        *minor = MINOR(devno);
-        path_release(&nd);
-        return 0;
+        EXIT;
+        return minor;
 }
 
-/* We always need to remove the presto options before passing to bottom FS */
-struct super_block * presto_read_super(struct super_block * presto_sb,
+/* We always need to remove the presto options before passing 
+   mount options to cache FS */
+struct super_block * presto_read_super(struct super_block * sb,
                                        void * data, int silent)
 {
-        struct super_block *mysb = NULL;
         struct file_system_type *fstype;
         struct presto_cache *cache = NULL;
         char *cache_data = NULL;
         char *cache_data_end;
         char *cache_type = NULL;
         char *fileset = NULL;
-        char *presto_mtpt = NULL;
-        char *prestodev = NULL;
-        struct filter_fs *ops;
-        int minor;
-        struct upc_comm *psdev;
+        char *channel = NULL;
+        int err; 
+        unsigned int minor;
 
         ENTRY;
-        CDEBUG(D_MALLOC, "before parsing: kmem %ld, vmem %ld\n",
-               presto_kmemory, presto_vmemory);
 
         /* reserve space for the cache's data */
-        PRESTO_ALLOC(cache_data, void *, PAGE_SIZE);
+        PRESTO_ALLOC(cache_data, PAGE_SIZE);
         if ( !cache_data ) {
-                printk("presto_read_super: Cannot allocate data page.\n");
+                CERROR("presto_read_super: Cannot allocate data page.\n");
                 EXIT;
                 goto out_err;
         }
 
-        CDEBUG(D_SUPER, "mount opts: %s\n", data ? (char *)data : "(none)");
-
         /* read and validate options */
-        cache_data_end = presto_options(data, cache_data, &cache_type, &fileset,
-                                        &prestodev, &presto_mtpt);
+        cache_data_end = presto_options(sb, data, cache_data, &cache_type, 
+                                        &fileset, &channel);
 
         /* was there anything for the cache filesystem in the data? */
         if (cache_data_end == cache_data) {
@@ -249,112 +225,87 @@
                        cache_data);
         }
 
-        /* prepare the communication channel */
-        if ( presto_get_minor(prestodev, &minor) ) {
-                /* if (!silent) */
-                printk("InterMezzo: %s not a valid presto dev\n", prestodev);
-                EXIT;
-                goto out_err;
-        }
-        psdev = &upc_comms[minor];
-        CDEBUG(D_SUPER, "\n");
-        psdev->uc_no_filter = 1;
-
-        CDEBUG(D_SUPER, "presto minor is %d\n", minor);
-
         /* set up the cache */
-        cache = presto_init_cache();
+        cache = presto_cache_init();
         if ( !cache ) {
-                printk("presto_read_super: failure allocating cache.\n");
+                CERROR("presto_read_super: failure allocating cache.\n");
                 EXIT;
                 goto out_err;
         }
-
-        /* no options were passed: likely we are "/" readonly */
-        if ( !presto_mtpt || !fileset ) {
-                cache->cache_flags |= CACHE_LENTO_RO | CACHE_CLIENT_RO;
-        }
-        cache->cache_psdev = psdev;
-        /* no options were passed: likely we are "/" readonly */
-        /* before the journaling infrastructure can work, these
-           need to be set; that happens in presto_remount */
-        if ( !presto_mtpt || !fileset ) {
-                if (!presto_mtpt) 
-                        printk("No mountpoint marking cache RO\n");
-                if (!fileset) 
-                        printk("No fileset marking cache RO\n");
-                cache->cache_flags |= CACHE_LENTO_RO | CACHE_CLIENT_RO;
-        }
-
-        cache->cache_mtpt = presto_mtpt;
-        cache->cache_root_fileset = fileset;
         cache->cache_type = cache_type;
 
-        printk("Presto: type=%s, vol=%s, dev=%s (minor %d), mtpt %s, flags %x\n",
-               cache_type, fileset ? fileset : "NULL", prestodev, minor,
-               presto_mtpt ? presto_mtpt : "NULL", cache->cache_flags);
+        /* link cache to channel */ 
+        minor = presto_set_channel(cache, channel);
+        if (minor < 0) { 
+                EXIT;
+                goto out_err;
+        }
 
+        CDEBUG(D_SUPER, "Presto: type=%s, fset=%s, dev= %d, flags %x\n",
+               cache_type, fileset?fileset:"NULL", minor, cache->cache_flags);
 
         MOD_INC_USE_COUNT;
-        fstype = get_fs_type(cache_type);
 
+        /* get the filter for the cache */
+        fstype = get_fs_type(cache_type);
         cache->cache_filter = filter_get_filter_fs((const char *)cache_type); 
         if ( !fstype || !cache->cache_filter) {
-                printk("Presto: unrecognized fs type or cache type\n");
+                CERROR("Presto: unrecognized fs type or cache type\n");
                 MOD_DEC_USE_COUNT;
                 EXIT;
                 goto out_err;
         }
-        mysb = fstype->read_super(presto_sb, cache_data, silent);
+
+        /* can we in fact mount the cache */ 
+        if ((fstype->fs_flags & FS_REQUIRES_DEV) && !sb->s_bdev) {
+                CERROR("filesystem \"%s\" requires a valid block device\n",
+                                cache_type);
+                MOD_DEC_USE_COUNT;
+                EXIT;
+                goto out_err;
+        }
+
+        sb = fstype->read_super(sb, cache_data, silent);
+
         /* this might have been freed above */
         if (cache_data) {
                 PRESTO_FREE(cache_data, PAGE_SIZE);
                 cache_data = NULL;
         }
-        if ( !mysb ) {
-                /* if (!silent) */
-                printk("InterMezzo: cache mount failure.\n");
+
+        if ( !sb ) {
+                CERROR("InterMezzo: cache mount failure.\n");
                 MOD_DEC_USE_COUNT;
                 EXIT;
                 goto out_err;
         }
 
-	
-	cache->cache_sb = mysb;
-        ops = filter_get_filter_fs(cache_type);
-
-        filter_setup_journal_ops(cache->cache_filter, cache->cache_type); 
+        cache->cache_sb = sb;
+        cache->cache_root = dget(sb->s_root);
 
         /* we now know the dev of the cache: hash the cache */
-        presto_cache_add(cache, mysb->s_dev);
+        presto_cache_add(cache, sb->s_dev);
+        err = izo_prepare_fileset(sb->s_root, fileset); 
 
-        /* make sure we have our own super operations: mysb
+        filter_setup_journal_ops(cache->cache_filter, cache->cache_type); 
+
+        /* make sure we have our own super operations: sb
            still contains the cache operations */
-        filter_setup_super_ops(cache->cache_filter, mysb->s_op, 
+        filter_setup_super_ops(cache->cache_filter, sb->s_op, 
                                &presto_super_ops);
-        mysb->s_op = filter_c2usops(cache->cache_filter);
+        sb->s_op = filter_c2usops(cache->cache_filter);
 
-        /* now get our own directory operations */
-        if ( mysb->s_root && mysb->s_root->d_inode ) {
-                CDEBUG(D_SUPER, "\n");
-                filter_setup_dir_ops(cache->cache_filter, 
-                                     mysb->s_root->d_inode,
-                                     &presto_dir_iops, &presto_dir_fops);
-                mysb->s_root->d_inode->i_op = filter_c2udiops(cache->cache_filter);
-                CDEBUG(D_SUPER, "lookup at %p\n", 
-                       mysb->s_root->d_inode->i_op->lookup);
-                filter_setup_dentry_ops(cache->cache_filter, 
-                                        mysb->s_root->d_op, 
-                                        &presto_dentry_ops);
-                presto_sb->s_root->d_op = filter_c2udops(cache->cache_filter);
-                cache->cache_mtde = mysb->s_root;
-        }
-
-        CDEBUG(D_MALLOC, "after mounting: kmem %ld, vmem %ld\n",
-               presto_kmemory, presto_vmemory);
+        /* get izo directory operations: sb->s_root->d_inode exists now */
+        filter_setup_dir_ops(cache->cache_filter, sb->s_root->d_inode,
+                             &presto_dir_iops, &presto_dir_fops);
+        filter_setup_dentry_ops(cache->cache_filter, sb->s_root->d_op, 
+                                &presto_dentry_ops);
+        sb->s_root->d_inode->i_op = filter_c2udiops(cache->cache_filter);
+        sb->s_root->d_inode->i_fop = filter_c2udfops(cache->cache_filter);
+        sb->s_root->d_op = filter_c2udops(cache->cache_filter);
 
         EXIT;
-        return mysb;
+        return sb;
 
  out_err:
         CDEBUG(D_SUPER, "out_err called\n");
@@ -364,10 +315,8 @@
                 PRESTO_FREE(cache_data, PAGE_SIZE);
         if (fileset)
                 PRESTO_FREE(fileset, strlen(fileset) + 1);
-        if (presto_mtpt)
-                PRESTO_FREE(presto_mtpt, strlen(presto_mtpt) + 1);
-        if (prestodev)
-                PRESTO_FREE(prestodev, strlen(prestodev) + 1);
+        if (channel)
+                PRESTO_FREE(channel, strlen(channel) + 1);
         if (cache_type)
                 PRESTO_FREE(cache_type, strlen(cache_type) + 1);
 
@@ -376,152 +325,78 @@
         return NULL;
 }
 
-int presto_remount(struct super_block * sb, int *flags, char *data)
-{
-        char *cache_data = NULL;
-        char *cache_data_end;
-        char **type;
-        char **fileset;
-        char **mtpt;
-        char **prestodev;
-        struct super_operations *sops;
-        struct presto_cache *cache = NULL;
-        int err = 0;
-
-        ENTRY;
-        CDEBUG(D_MALLOC, "before remount: kmem %ld, vmem %ld\n",
-               presto_kmemory, presto_vmemory);
-        CDEBUG(D_SUPER, "remount opts: %s\n", data ? (char *)data : "(none)");
-        if (data) {
-                /* reserve space for the cache's data */
-                PRESTO_ALLOC(cache_data, void *, PAGE_SIZE);
-                if ( !cache_data ) {
-                        err = -ENOMEM;
-                        EXIT;
-                        goto out_err;
-                }
-        }
-
-        cache = presto_find_cache(sb->s_dev);
-        if (!cache) {
-                printk( "%s: cannot find cache on remount\n", __FUNCTION__);
-                err = -ENODEV;
-                EXIT;
-                goto out_err;
-        }
-
-        /* If an option has not yet been set, we allow it to be set on
-         * remount.  If an option already has a value, we pass NULL for
-         * the option pointer, which means that the InterMezzo option
-         * will be parsed but discarded.
-         */
-        type = cache->cache_type ? NULL : &cache->cache_type;
-        fileset = cache->cache_root_fileset ? NULL : &cache->cache_root_fileset;
-        prestodev = cache->cache_psdev ? NULL : &cache->cache_psdev->uc_devname;
-        mtpt = cache->cache_mtpt ? NULL : &cache->cache_mtpt;
-        cache_data_end = presto_options(data, cache_data, type, fileset,
-                                        prestodev, mtpt);
 
-        if (cache_data) {
-                if (cache_data_end == cache_data) {
-                        PRESTO_FREE(cache_data, PAGE_SIZE);
-                        cache_data = NULL;
-                } else {
-                        CDEBUG(D_SUPER, "cache_data at %p is: %s\n", cache_data,
-                               cache_data);
-                }
-        }
-
-        if (cache->cache_root_fileset && cache->cache_mtpt) {
-                cache->cache_flags &= ~(CACHE_LENTO_RO|CACHE_CLIENT_RO);
-        }
-
-        sops = filter_c2csops(cache->cache_filter);
-        if (sops->remount_fs) {
-                err = sops->remount_fs(sb, flags, cache_data);
-        }
 
-        CDEBUG(D_MALLOC, "after remount: kmem %ld, vmem %ld\n",
-               presto_kmemory, presto_vmemory);
-        EXIT;
-out_err:
-        if (cache_data)
-                PRESTO_FREE(cache_data, PAGE_SIZE);
-        return err;
-}
-
-struct file_system_type presto_fs_type = {
 #ifdef PRESTO_DEVEL
-        "izofs",
+static DECLARE_FSTYPE(presto_fs_type, "izo", presto_read_super, FS_REQUIRES_DEV);
+static DECLARE_FSTYPE(vpresto_fs_type, "vintermezzo", presto_read_super, FS_LITTER);
 #else 
-        "intermezzo",
+static DECLARE_FSTYPE(vpresto_fs_type, "vintermezzo", presto_read_super, FS_LITTER);
+static DECLARE_FSTYPE(presto_fs_type, "intermezzo", presto_read_super, FS_REQUIRES_DEV);
 #endif
-        FS_REQUIRES_DEV, /* can use Ibaskets when ext2 does */
-        presto_read_super,
-        NULL
-};
 
 
-int /* __init */ init_intermezzo_fs(void)
+
+int __init init_intermezzo_fs(void)
 {
         int status;
 
-        printk(KERN_INFO "InterMezzo Kernel/Lento communications, "
-               "v1.04, braam@inter-mezzo.org\n");
+        printk(KERN_INFO "InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION
+               " info@clusterfs.com\n");
 
         status = presto_psdev_init();
         if ( status ) {
-                printk("Problem (%d) in init_intermezzo_psdev\n", status);
+                CERROR("Problem (%d) in init_intermezzo_psdev\n", status);
                 return status;
         }
 
         status = init_intermezzo_sysctl();
         if (status) {
-                printk("presto: failed in init_intermezzo_sysctl!\n");
+                CERROR("presto: failed in init_intermezzo_sysctl!\n");
         }
 
-        presto_init_cache_hash();
+        presto_cache_init_hash();
+
+        if (!presto_init_ddata_cache()) {
+                CERROR("presto out of memory!\n");
+                return -ENOMEM;
+        }
 
         status = register_filesystem(&presto_fs_type);
         if (status) {
-                printk("presto: failed in register_filesystem!\n");
+                CERROR("presto: failed in register_filesystem!\n");
+        }
+        status = register_filesystem(&vpresto_fs_type);
+        if (status) {
+                CERROR("vpresto: failed in register_filesystem!\n");
         }
         return status;
 }
 
-
-#ifdef MODULE
-MODULE_AUTHOR("Peter J. Braam <braam@inter-mezzo.org>");
-MODULE_DESCRIPTION("InterMezzo Kernel/Lento communications, v1.0.5.1");
-
-int init_module(void)
-{
-        return init_intermezzo_fs();
-}
-
-
-void cleanup_module(void)
+void __exit exit_intermezzo_fs(void)
 {
         int err;
 
         ENTRY;
 
         if ( (err = unregister_filesystem(&presto_fs_type)) != 0 ) {
-                printk("presto: failed to unregister filesystem\n");
+                CERROR("presto: failed to unregister filesystem\n");
+        }
+        if ( (err = unregister_filesystem(&vpresto_fs_type)) != 0 ) {
+                CERROR("vpresto: failed to unregister filesystem\n");
         }
 
         presto_psdev_cleanup();
         cleanup_intermezzo_sysctl();
-
-
-#ifdef PRESTO_DEVEL
-        unregister_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev_devel");
-#else 
-        unregister_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev");
-#endif
-        CDEBUG(D_MALLOC, "after cleanup: kmem %ld, vmem %ld\n",
+        presto_cleanup_ddata_cache();
+        CERROR("after cleanup: kmem %ld, vmem %ld\n",
                presto_kmemory, presto_vmemory);
 }
 
-#endif
 
+MODULE_AUTHOR("Cluster Filesystems Inc. <info@clusterfs.com>");
+MODULE_DESCRIPTION("InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION);
+MODULE_LICENSE("GPL");
+
+module_init(init_intermezzo_fs)
+module_exit(exit_intermezzo_fs)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/sysctl.c linux-2.4.20/fs/intermezzo/sysctl.c
--- linux-2.4.19/fs/intermezzo/sysctl.c	2001-11-11 18:20:21.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/sysctl.c	2002-10-29 11:18:34.000000000 +0000
@@ -1,4 +1,23 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1999 Peter J. Braam <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
  *  Sysctrl entries for Intermezzo!
  */
 
@@ -24,7 +43,6 @@
 
 #include <linux/intermezzo_fs.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_upcall.h>
 
 /* /proc entries */
 
@@ -36,8 +54,6 @@
 	int len=0;
 
 	/* this works as long as we are below 1024 characters! */
-	len += presto_sprint_mounts(buffer, length, -1);
-
 	*start = buffer + offset;
 	len -= offset;
 
@@ -67,30 +83,27 @@
 #define PSDEV_NO_UPCALL    7      /* controls lento_upcall */
 #define PSDEV_ERRORVAL     8      /* controls presto_debug_fail_blkdev */
 #define PSDEV_EXCL_GID     9      /* which GID is ignored by presto */
-#define PSDEV_ILOOKUP_UID 10      /* which UID bypasses file access perms */
 #define PSDEV_BYTES_TO_CLOSE 11   /* bytes to write before close */
 
 /* These are global presto control options */
-#define PRESTO_PRIMARY_CTLCNT 4
-static struct ctl_table presto_table[ PRESTO_PRIMARY_CTLCNT + MAX_PRESTODEV + 1] =
+#define PRESTO_PRIMARY_CTLCNT 2
+static struct ctl_table presto_table[ PRESTO_PRIMARY_CTLCNT + MAX_CHANNEL + 1] =
 {
 	{PSDEV_DEBUG, "debug", &presto_debug, sizeof(int), 0644, NULL, &proc_dointvec},
 	{PSDEV_TRACE, "trace", &presto_print_entry, sizeof(int), 0644, NULL, &proc_dointvec},
-	{PSDEV_EXCL_GID, "presto_excluded_gid", &presto_excluded_gid, sizeof(int), 0644, NULL, &proc_dointvec},
-	{PSDEV_ILOOKUP_UID, "presto_ilookup_uid", &presto_ilookup_uid, sizeof(int), 0644, NULL, &proc_dointvec},
 };
 
 /*
  * Intalling the sysctl entries: strategy
  * - have templates for each /proc/sys/intermezzo/ entry
  *   such an entry exists for each /dev/presto
- *    (proto_prestodev_entry)
+ *    (proto_channel_entry)
  * - have a template for the contents of such directories
  *    (proto_psdev_table)
  * - have the master table (presto_table)
  *
  * When installing, malloc, memcpy and fix up the pointers to point to
- * the appropriate constants in upc_comms[your_minor]
+ * the appropriate constants in izo_channels[your_minor]
  */
 
 static ctl_table proto_psdev_table[] = {
@@ -99,15 +112,13 @@
 	{PSDEV_NO_JOURNAL, "no_journal", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
 	{PSDEV_NO_UPCALL, "no_upcall", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
 	{PSDEV_TIMEOUT, "timeout", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
-	{PSDEV_TRACE, "trace", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
-	{PSDEV_DEBUG, "debug", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
 #ifdef PRESTO_DEBUG
 	{PSDEV_ERRORVAL, "errorval", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
 #endif
 	{ 0 }
 };
 
-static ctl_table proto_prestodev_entry = {
+static ctl_table proto_channel_entry = {
 	PSDEV_INTERMEZZO, 0,  NULL, 0, 0555, 0,
 };
 
@@ -124,6 +135,7 @@
 /* we made these separate as setting may in future be more restricted
  * than getting
  */
+#ifdef RON_MINNICH
 int dosetopt(int minor, struct psdev_opt *opt)
 {
 	int retval = 0;
@@ -134,23 +146,23 @@
 	switch(opt->optname) {
 
 	case PSDEV_TIMEOUT:
-		upc_comms[minor].uc_timeout = newval;
+		izo_channels[minor].uc_timeout = newval;
 		break;
 
 	case PSDEV_HARD:
-		upc_comms[minor].uc_hard = newval;
+		izo_channels[minor].uc_hard = newval;
 		break;
 
 	case PSDEV_NO_FILTER:
-		upc_comms[minor].uc_no_filter = newval;
+		izo_channels[minor].uc_no_filter = newval;
 		break;
 
 	case PSDEV_NO_JOURNAL:
-		upc_comms[minor].uc_no_journal = newval;
+		izo_channels[minor].uc_no_journal = newval;
 		break;
 
 	case PSDEV_NO_UPCALL:
-		upc_comms[minor].uc_no_upcall = newval;
+		izo_channels[minor].uc_no_upcall = newval;
 		break;
 
 #ifdef PRESTO_DEBUG
@@ -161,17 +173,17 @@
 		 * allow setting the underlying device read-only for the
 		 * current presto cache.
 		 */
-		int errorval = upc_comms[minor].uc_errorval;
+		int errorval = izo_channels[minor].uc_errorval;
 		if (errorval < 0) {
 			if (newval == 0)
 				set_device_ro(-errorval, 0);
 			else
-				printk("device %s already read only\n",
+				CERROR("device %s already read only\n",
 				       kdevname(-errorval));
 		} else {
 			if (newval < 0)
 				set_device_ro(-newval, 1);
-			upc_comms[minor].uc_errorval = newval;
+			izo_channels[minor].uc_errorval = newval;
 			CDEBUG(D_PSDEV, "setting errorval to %d\n", newval);
 		}
 
@@ -203,32 +215,32 @@
 	switch(opt->optname) {
 
 	case PSDEV_TIMEOUT:
-		opt->optval = upc_comms[minor].uc_timeout;
+		opt->optval = izo_channels[minor].uc_timeout;
 		break;
 
 	case PSDEV_HARD:
-		opt->optval = upc_comms[minor].uc_hard;
+		opt->optval = izo_channels[minor].uc_hard;
 		break;
 
 	case PSDEV_NO_FILTER:
-		opt->optval = upc_comms[minor].uc_no_filter;
+		opt->optval = izo_channels[minor].uc_no_filter;
 		break;
 
 	case PSDEV_NO_JOURNAL:
-		opt->optval = upc_comms[minor].uc_no_journal;
+		opt->optval = izo_channels[minor].uc_no_journal;
 		break;
 
 	case PSDEV_NO_UPCALL:
-		opt->optval = upc_comms[minor].uc_no_upcall;
+		opt->optval = izo_channels[minor].uc_no_upcall;
 		break;
 
 #ifdef PSDEV_DEBUG
 	case PSDEV_ERRORVAL: {
-		int errorval = upc_comms[minor].uc_errorval;
+		int errorval = izo_channels[minor].uc_errorval;
 		if (errorval < 0 && is_read_only(-errorval))
-			printk(KERN_INFO "device %s has been set read-only\n",
+			CERROR("device %s has been set read-only\n",
 			       kdevname(-errorval));
-		opt->optval = upc_comms[minor].uc_errorval;
+		opt->optval = izo_channels[minor].uc_errorval;
 		break;
 	}
 #endif
@@ -247,29 +259,26 @@
 	EXIT;
 	return retval;
 }
+#endif
 
 
-
+/* allocate the tables for the presto devices. We need
+ * sizeof(proto_channel_table)/sizeof(proto_channel_table[0])
+ * entries for each dev
+ */
 int /* __init */ init_intermezzo_sysctl(void)
 {
 	int i;
-	extern struct upc_comm upc_comms[MAX_PRESTODEV];
-
-	/* allocate the tables for the presto devices. We need
-	 * sizeof(proto_prestodev_table)/sizeof(proto_prestodev_table[0])
-	 * entries for each dev
-	 */
-	int total_dev = MAX_PRESTODEV;
+	int total_dev = MAX_CHANNEL;
 	int entries_per_dev = sizeof(proto_psdev_table) /
 		sizeof(proto_psdev_table[0]);
 	int total_entries = entries_per_dev * total_dev;
 	ctl_table *dev_ctl_table;
 
-	PRESTO_ALLOC(dev_ctl_table, ctl_table *,
-		     sizeof(ctl_table) * total_entries);
+	PRESTO_ALLOC(dev_ctl_table, sizeof(ctl_table) * total_entries);
 
 	if (! dev_ctl_table) {
-		printk("WARNING: presto couldn't allocate dev_ctl_table\n");
+		CERROR("WARNING: presto couldn't allocate dev_ctl_table\n");
 		EXIT;
 		return -ENOMEM;
 	}
@@ -286,14 +295,14 @@
 		/* entries for the individual "files" in this "directory" */
 		ctl_table *psdev_entries = &dev_ctl_table[i * entries_per_dev];
 		/* init the psdev and psdev_entries with the prototypes */
-		*psdev = proto_prestodev_entry;
+		*psdev = proto_channel_entry;
 		memcpy(psdev_entries, proto_psdev_table,
 		       sizeof(proto_psdev_table));
 		/* now specialize them ... */
 		/* the psdev has to point to psdev_entries, and fix the number */
 		psdev->ctl_name = psdev->ctl_name + i + 1; /* sorry */
 
-		psdev->procname = kmalloc(32, GFP_KERNEL);
+		PRESTO_ALLOC((void*)psdev->procname, PROCNAME_SIZE);
 		if (!psdev->procname) {
 			PRESTO_FREE(dev_ctl_table,
 				    sizeof(ctl_table) * total_entries);
@@ -304,15 +313,13 @@
 		psdev->child = psdev_entries;
 
 		/* now for each psdev entry ... */
-		psdev_entries[0].data = &(upc_comms[i].uc_hard);
-		psdev_entries[1].data = &(upc_comms[i].uc_no_filter);
-		psdev_entries[2].data = &(upc_comms[i].uc_no_journal);
-		psdev_entries[3].data = &(upc_comms[i].uc_no_upcall);
-		psdev_entries[4].data = &(upc_comms[i].uc_timeout);
-		psdev_entries[5].data = &presto_print_entry;
-		psdev_entries[6].data = &presto_debug;
+		psdev_entries[0].data = &(izo_channels[i].uc_hard);
+		psdev_entries[1].data = &(izo_channels[i].uc_no_filter);
+		psdev_entries[2].data = &(izo_channels[i].uc_no_journal);
+		psdev_entries[3].data = &(izo_channels[i].uc_no_upcall);
+		psdev_entries[4].data = &(izo_channels[i].uc_timeout);
 #ifdef PRESTO_DEBUG
-		psdev_entries[7].data = &(upc_comms[i].uc_errorval);
+		psdev_entries[5].data = &(izo_channels[i].uc_errorval);
 #endif
 	}
 
@@ -331,8 +338,9 @@
 	return 0;
 }
 
-void cleanup_intermezzo_sysctl() {
-	int total_dev = MAX_PRESTODEV;
+void cleanup_intermezzo_sysctl(void)
+{
+	int total_dev = MAX_CHANNEL;
 	int entries_per_dev = sizeof(proto_psdev_table) /
 		sizeof(proto_psdev_table[0]);
 	int total_entries = entries_per_dev * total_dev;
@@ -346,7 +354,7 @@
 	for(i = 0; i < total_dev; i++) {
 		/* entry for this /proc/sys/intermezzo/intermezzo"i" */
 		ctl_table *psdev = &presto_table[i + PRESTO_PRIMARY_CTLCNT];
-		kfree(psdev->procname);
+		PRESTO_FREE(psdev->procname, PROCNAME_SIZE);
 	}
 	/* presto_table[PRESTO_PRIMARY_CTLCNT].child points to the
 	 * dev_ctl_table previously allocated in init_intermezzo_psdev()
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/upcall.c linux-2.4.20/fs/intermezzo/upcall.c
--- linux-2.4.19/fs/intermezzo/upcall.c	2001-11-11 18:20:21.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/upcall.c	2002-10-29 11:18:51.000000000 +0000
@@ -1,22 +1,28 @@
-/*
- * Mostly platform independent upcall operations to Venus:
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * Copyright (C) 2001, 2002 Cluster File Systems, Inc. <braam@clusterfs.com>
+ * Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Mostly platform independent upcall operations to a cache manager:
  *  -- upcalls
  *  -- upcall routines
  *
- * Linux 2.0 version
- * Copyright (C) 1996 Peter J. Braam <braam@cs.cmu.edu>,
- * Michael Callahan <callahan@maths.ox.ac.uk>
- *
- * Redone for Linux 2.1
- * Copyright (C) 1997 Carnegie Mellon University
- *
- * Carnegie Mellon University encourages users of this code to contribute
- * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
- *
- * Much cleaned up for InterMezzo
- * Copyright (C) 1998 Peter J. Braam <braam@cs.cmu.edu>,
- * Copyright (C) 1999 Carnegie Mellon University
- *
  */
 
 #include <asm/system.h>
@@ -39,210 +45,513 @@
 #include <linux/vmalloc.h>
 #include <asm/segment.h>
 
+#include <linux/intermezzo_lib.h>
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 
+#include <linux/intermezzo_idl.h>
+
 /*
-  At present: four upcalls
-  - opendir: fetch a directory (synchronous & asynchronous)
-  - open: fetch file (synchronous)
-  - journal: send a journal page (asynchronous)
-  - permit: get a permit (synchronous)
+  At present:
+  -- Asynchronous calls:
+   - kml:            give a "more" kml indication to userland
+   - kml_truncate:   initiate KML truncation
+   - release_permit: kernel is done with permit
+  -- Synchronous
+   - open:           fetch file
+   - permit:         get a permit
 
-  Errors returned here are positive.
+  Errors returned by user level code are positive
 
  */
 
+static struct izo_upcall_hdr *upc_pack(__u32 opcode, int pathlen, char *path,
+                                       char *fsetname, int reclen, char *rec,
+                                       int *size)
+{
+        struct izo_upcall_hdr *hdr;
+        char *ptr;
+        ENTRY;
 
-#define INSIZE(tag) sizeof(struct lento_ ## tag ## _in)
-#define OUTSIZE(tag) sizeof(struct lento_ ## tag ## _out)
-#define SIZE(tag)  ( (INSIZE(tag)>OUTSIZE(tag)) ? INSIZE(tag) : OUTSIZE(tag) )
-
-#define UPARG(op)\
-do {\
-        PRESTO_ALLOC(inp, union up_args *, insize);\
-        if ( !inp ) { return -ENOMEM; }\
-        outp = (union down_args *) (inp);\
-        inp->uh.opcode = (op);\
-        inp->uh.pid = current->pid;\
-        inp->uh.uid = current->fsuid;\
-        outsize = insize;\
-} while (0)
-
-#define BUFF_ALLOC(buffer)                              \
-        PRESTO_ALLOC(buffer, char *, PAGE_SIZE);        \
-        if ( !buffer ) {                                \
-                printk("PRESTO: out of memory!\n");     \
-                return -ENOMEM;                         \
+        *size = sizeof(struct izo_upcall_hdr);
+        if ( fsetname ) {
+                *size += round_strlen(fsetname);
+        }
+        if ( path ) { 
+                *size += round_strlen(path);
         }
+        if ( rec ) { 
+                *size += size_round(reclen);
+        }
+        PRESTO_ALLOC(hdr, *size);
+        if (!hdr) { 
+                CERROR("intermezzo upcall: out of memory (opc %d)\n", opcode);
+                EXIT;
+                return NULL;
+        }
+        memset(hdr, 0, *size);
+
+        ptr = (char *)hdr + sizeof(*hdr);
+
+        /* XXX do we need fsuid ? */
+        hdr->u_len = *size;
+        hdr->u_version = IZO_UPC_VERSION;
+        hdr->u_opc = opcode;
+        hdr->u_pid = current->pid;
+        hdr->u_uid = current->fsuid;
+
+        if (path) { 
+                /*XXX Robert: please review what len to pass in for 
+                  NUL terminated strings */
+                hdr->u_pathlen = strlen(path);
+                LOGL0(path, hdr->u_pathlen, ptr);
+        }
+        if (fsetname) { 
+                hdr->u_fsetlen = strlen(fsetname);
+                LOGL0(fsetname, strlen(fsetname), ptr);
+        }
+        if (rec) { 
+                hdr->u_reclen = reclen;
+                LOGL(rec, reclen, ptr);
+        }
+        
+        EXIT;
+        return hdr;
+}
 
 /* the upcalls */
-int lento_kml(int minor, unsigned int offset, unsigned int first_recno,
-              unsigned int length, unsigned int last_recno, int namelen,
-              char *fsetname)
-{
-        union up_args *inp;
-        union down_args *outp;
-        int insize, outsize, error;
+int izo_upc_kml(int minor, __u64 offset, __u32 first_recno, __u64 length, __u32 last_recno, char *fsetname)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+
         ENTRY;
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return 0;
+        }
+
+        hdr = upc_pack(IZO_UPC_KML, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        hdr->u_offset = offset;
+        hdr->u_first_recno = first_recno;
+        hdr->u_length = length;
+        hdr->u_last_recno = last_recno;
+
+        CDEBUG(D_UPCALL, "KML: fileset %s, offset %Lu, length %Lu, "
+               "first %u, last %d; minor %d\n",
+               fsetname, hdr->u_offset, hdr->u_length, hdr->u_first_recno,
+               hdr->u_last_recno, minor);
+
+        error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
+
+        EXIT;
+        return -error;
+}
+
+int izo_upc_kml_truncate(int minor, __u64 length, __u32 last_recno, char *fsetname)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
 
+        ENTRY;
         if (!presto_lento_up(minor)) {
                 EXIT;
                 return 0;
         }
 
-        insize = SIZE(kml) + namelen + 1;
-        UPARG(LENTO_KML);
-        inp->lento_kml.namelen = namelen;
-        memcpy(inp->lento_kml.fsetname, fsetname, namelen);
-        inp->lento_kml.fsetname[namelen] = '\0';
-        inp->lento_kml.offset = offset;
-        inp->lento_kml.first_recno = first_recno;
-        inp->lento_kml.length = length;
-        inp->lento_kml.last_recno = last_recno;
-
-        CDEBUG(D_UPCALL, "KML: fileset %s, offset %d, length %d, "
-               "first %d, last %d; minor %d\n",
-               inp->lento_kml.fsetname,
-               inp->lento_kml.offset,
-               inp->lento_kml.length,
-               inp->lento_kml.first_recno,
-               inp->lento_kml.last_recno, minor);
+        hdr = upc_pack(IZO_UPC_KML_TRUNC, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        hdr->u_length = length;
+        hdr->u_last_recno = last_recno;
+
+        CDEBUG(D_UPCALL, "KML TRUNCATE: fileset %s, length %Lu, "
+               "last recno %d, minor %d\n",
+               fsetname, hdr->u_length, hdr->u_last_recno, minor);
 
-        error = lento_upcall(minor, insize, &outsize, inp,
-                             ASYNCHRONOUS, NULL);
+        error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
 
         EXIT;
         return error;
 }
 
-int lento_release_permit( int minor, int mycookie )
+int izo_upc_open(int minor, __u32 pathlen, char *path, char *fsetname, struct lento_vfs_context *info)
 {
-        union up_args *inp;
-        union down_args *outp;
-        int insize, outsize, error;
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
         ENTRY;
 
         if (!presto_lento_up(minor)) {
                 EXIT;
-                return 0;
+                return -EIO;
         }
 
-        insize= SIZE(response_cookie);
-        UPARG(LENTO_COOKIE);
-        inp->lento_response_cookie.cookie= mycookie;
+        hdr = upc_pack(IZO_UPC_OPEN, pathlen, path, fsetname, 
+                       sizeof(*info), (char*)info, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
 
-        CDEBUG(D_UPCALL, "cookie %d\n", mycookie);
+        CDEBUG(D_UPCALL, "path %s\n", path);
 
-        error = lento_upcall(minor, insize, &outsize, inp,
-                             ASYNCHRONOUS, NULL);
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
 
         EXIT;
-        return error;
+        return -error;
 }
 
-int lento_opendir(int minor, int pathlen, char *path, int async)
+int izo_upc_get_fileid(int minor, __u32 reclen, char *rec, 
+                       __u32 pathlen, char *path, char *fsetname)
 {
-        union up_args *inp;
-        union down_args *outp;
-        int insize, outsize, error;
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
         ENTRY;
 
-        insize = SIZE(opendir) + pathlen + 1;
-        UPARG(LENTO_OPENDIR);
-        inp->lento_opendir.async = async;
-        inp->lento_opendir.pathlen = pathlen;
-        memcpy(inp->lento_opendir.path, path, pathlen);
-        inp->lento_opendir.path[pathlen] = '\0';
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_GET_FILEID, pathlen, path, fsetname, reclen, rec, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
 
-        CDEBUG(D_UPCALL, "path %s\n", inp->lento_opendir.path);
+        CDEBUG(D_UPCALL, "path %s\n", path);
 
-        if (async) {
-                error = lento_upcall(minor, insize, &outsize, inp,
-                                     ASYNCHRONOUS, NULL);
-                return 0;
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
+
+int izo_upc_backfetch(int minor, char *path, char *fsetname, struct lento_vfs_context *info)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
+
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
         }
 
-        error = lento_upcall(minor, insize, &outsize, inp,
-                             SYNCHRONOUS, NULL);
-        if (error && error != EISFSETROOT) {
-                printk("lento_opendir: error %d\n", error);
+        hdr = upc_pack(IZO_UPC_BACKFETCH, strlen(path), path, fsetname, 
+                       sizeof(*info), (char *)info, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
         }
 
+        /* This is currently synchronous, kml_reint_record blocks */
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+
         EXIT;
-        return error;
+        return -error;
 }
 
-int lento_open(int minor, int pathlen, char *path)
+int izo_upc_permit(int minor, struct dentry *dentry, __u32 pathlen, char *path,
+                   char *fsetname)
 {
-        union up_args *inp;
-        union down_args *outp;
-        int insize, outsize, error;
-
-	ENTRY;
-	insize = SIZE(open) + pathlen + 1;
-	UPARG(LENTO_OPEN);
-	inp->lento_open.pathlen = pathlen;
-	memcpy(inp->lento_open.path, path, pathlen);
-	inp->lento_open.path[pathlen] = '\0';
-
-	CDEBUG(D_UPCALL, "path %s\n", inp->lento_open.path);
-
-	error = lento_upcall(minor, insize, &outsize, inp,
-			     SYNCHRONOUS, NULL);
-	if (error) {
-	        printk("lento_open: error %d\n", error);
-	}
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+
+        ENTRY;
+
+        hdr = upc_pack(IZO_UPC_PERMIT, pathlen, path, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        CDEBUG(D_UPCALL, "Permit minor %d path %s\n", minor, path);
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+
+        if (error == -EROFS) {
+                int err;
+                CERROR("InterMezzo: ERROR - requested permit for read-only "
+                       "fileset.\n   Setting \"%s\" read-only!\n", path);
+                err = izo_mark_cache(dentry, 0xFFFFFFFF, CACHE_CLIENT_RO, NULL);
+                if (err)
+                        CERROR("InterMezzo ERROR: mark_cache %d\n", err);
+        } else if (error) {
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+        }
 
         EXIT;
         return error;
 }
 
+/* This is a ping-pong upcall handled on the server when a client (uuid)
+ * requests the permit for itself. */
+int izo_upc_revoke_permit(int minor, char *fsetname, __u8 uuid[16])
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+
+        ENTRY;
+
+        hdr = upc_pack(IZO_UPC_REVOKE_PERMIT, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
 
-int lento_permit(int minor, int pathlen, int fsetnamelen, char *path, char *fsetname)
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
+
+int izo_upc_go_fetch_kml(int minor, char *fsetname, __u8 uuid[16],
+                         __u64 kmlsize)
 {
-        union up_args *inp;
-        union down_args *outp;
-        int insize, outsize, error;
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
         ENTRY;
 
-        insize = SIZE(permit) + pathlen + 1 + fsetnamelen + 1;
-        UPARG(LENTO_PERMIT);
-        inp->lento_permit.pathlen = pathlen;
-        inp->lento_permit.fsetnamelen = fsetnamelen;
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_GO_FETCH_KML, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        hdr->u_offset = kmlsize;
+        memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
+
+        error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
+        if (error)
+                CERROR("%s: error %d\n", __FUNCTION__, error);
 
-        memcpy(inp->lento_permit.path, path, pathlen);
-        inp->lento_permit.path[pathlen] = '\0';
+        EXIT;
+        return -error;
+}
 
-	memcpy(&(inp->lento_permit.path[pathlen+1]), fsetname, fsetnamelen); 
-        inp->lento_permit.path[fsetnamelen + 1 + pathlen] = '\0';
+int izo_upc_connect(int minor, __u64 ip_address, __u64 port, __u8 uuid[16],
+                    int client_flag)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
 
-        CDEBUG(D_UPCALL, "Permit minor %d path %s\n", minor,
-               inp->lento_permit.path);
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
 
-        error = lento_upcall(minor, insize, &outsize, inp,
-                             SYNCHRONOUS, NULL);
+        hdr = upc_pack(IZO_UPC_CONNECT, 0, NULL, NULL, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        hdr->u_offset = ip_address;
+        hdr->u_length = port;
+        memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
+        hdr->u_first_recno = client_flag;
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
         if (error) {
-                if( error == -EROFS ) {
-                        int err;
-                        printk("lento_permit: ERROR - requested permit for "
-                               "read-only fileset.\n"
-                               "   Setting \"%s\" read-only!\n",
-                               path);
-                        err= presto_mark_cache(path, 0xFFFFFFFF, 
-                                               CACHE_CLIENT_RO, NULL);
-                        if( err ) {
-                                printk("ERROR : mark_cache %d\n", err);
-                        }
-                }
-                else {
-                        printk("lento_permit: error %d\n", error);
-                }
+                CERROR("%s: error %d\n", __FUNCTION__, error);
         }
 
         EXIT;
+        return -error;
+}
+
+int izo_upc_set_kmlsize(int minor, char *fsetname, __u8 uuid[16], __u64 kmlsize)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
+
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_SET_KMLSIZE, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
+        hdr->u_length = kmlsize;
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("%s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
+
+int izo_upc_repstatus(int minor,  char * fsetname, struct izo_rcvd_rec *lr_server)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
+
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_REPSTATUS, 0, NULL, fsetname, 
+                       sizeof(*lr_server), (char*)lr_server, 
+                       &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("%s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
+
+
+#if 0
+int izo_upc_client_make_branch(int minor, char *fsetname, char *tagname,
+                               char *branchname)
+{
+        int size, error;
+        struct izo_upcall_hdr *hdr;
+        int pathlen;
+        char *path;
+        ENTRY;
+
+        hdr = upc_pack(IZO_UPC_CLIENT_MAKE_BRANCH, strlen(tagname), tagname,
+                       fsetname, strlen(branchname) + 1, branchname, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                error = -PTR_ERR(hdr);
+                goto error;
+        }
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: error %d\n", error);
 
+ error:
+        PRESTO_FREE(path, pathlen);
+        EXIT;
         return error;
 }
+#endif
+
+int izo_upc_server_make_branch(int minor, char *fsetname)
+{
+        int size, error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
 
+        hdr = upc_pack(IZO_UPC_SERVER_MAKE_BRANCH, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                error = -PTR_ERR(hdr);
+                goto error;
+        }
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: error %d\n", error);
+
+ error:
+        EXIT;
+        return -error;
+}
+
+int izo_upc_branch_undo(int minor, char *fsetname, char *branchname)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
+
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_BRANCH_UNDO, strlen(branchname), branchname,
+                       fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
+
+int izo_upc_branch_redo(int minor, char *fsetname, char *branchname)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
+
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_BRANCH_REDO, strlen(branchname) + 1, branchname,
+                       fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/intermezzo/vfs.c linux-2.4.20/fs/intermezzo/vfs.c
--- linux-2.4.19/fs/intermezzo/vfs.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/intermezzo/vfs.c	2002-10-29 11:18:36.000000000 +0000
@@ -1,4 +1,25 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2001, 2002 Cluster File Systems, Inc.
+ *  Copyright (C) 2000 Stelias Computing, Inc.
+ *  Copyright (C) 2000 Red Hat, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
  * vfs.c
  *
  * This file implements kernel downcalls from lento.
@@ -48,20 +69,50 @@
 #include <linux/blk.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
 #ifdef CONFIG_FS_EXT_ATTR
-#include <linux/ext_attr.h>
+# include <linux/ext_attr.h>
 
-#ifdef CONFIG_FS_POSIX_ACL
-#include <linux/posix_acl.h>
-#endif
+# ifdef CONFIG_FS_POSIX_ACL
+#  include <linux/posix_acl.h>
+# endif
 #endif
 
 extern struct inode_operations presto_sym_iops;
 
+/* Write the last_rcvd values to the last_rcvd file.  We don't know what the
+ * UUID or last_ctime values are, so we have to read from the file first
+ * (sigh). 
+ * exported for branch_reinter in kml_reint.c*/
+int presto_write_last_rcvd(struct rec_info *recinfo,
+                           struct presto_file_set *fset,
+                           struct lento_vfs_context *info)
+{
+        int rc;
+        struct izo_rcvd_rec rcvd_rec;
+
+        ENTRY;
+
+        memset(&rcvd_rec, 0, sizeof(rcvd_rec));
+        memcpy(rcvd_rec.lr_uuid, info->uuid, sizeof(rcvd_rec.lr_uuid));
+        rcvd_rec.lr_remote_recno = HTON__u64(info->recno);
+        rcvd_rec.lr_remote_offset = HTON__u64(info->kml_offset);
+        rcvd_rec.lr_local_recno = HTON__u64(recinfo->recno);
+        rcvd_rec.lr_local_offset = HTON__u64(recinfo->offset + recinfo->size);
+
+        rc = izo_rcvd_write(fset, &rcvd_rec);
+        if (rc < 0) {
+                /* izo_rcvd_write returns negative errors and non-negative
+                 * offsets */
+                CERROR("InterMezzo: izo_rcvd_write failed: %d\n", rc);
+                EXIT;
+                return rc;
+        }
+        EXIT;
+        return 0;
+}
+
 /*
  * It's inline, so penalty for filesystems that don't use sticky bit is
  * minimal.
@@ -130,13 +181,13 @@
                                      unsigned long value)
 {
         int minor = presto_f2m(fset);
-        int errorval = upc_comms[minor].uc_errorval;
-        kdev_t dev = fset->fset_mtpt->d_inode->i_dev;
+        int errorval = izo_channels[minor].uc_errorval;
+        kdev_t dev = fset->fset_dentry->d_inode->i_dev;
 
         if (errorval && errorval == (long)value && !is_read_only(dev)) {
                 CDEBUG(D_SUPER, "setting device %s read only\n", kdevname(dev));
                 BLKDEV_FAIL(dev, 1);
-                upc_comms[minor].uc_errorval = -dev;
+                izo_channels[minor].uc_errorval = -dev;
         }
 }
 #else
@@ -144,20 +195,22 @@
 #endif
 
 
-static inline int presto_do_kml(struct lento_vfs_context *info, struct inode* inode)
+static inline int presto_do_kml(struct lento_vfs_context *info,
+                                struct dentry *dentry)
 {
-        if ( ! (info->flags & LENTO_FL_KML) ) 
+        if ( ! (info->flags & LENTO_FL_KML) )
                 return 0;
-        if ( inode->i_gid == presto_excluded_gid ) 
+        if ( presto_chk(dentry, PRESTO_DONT_JOURNAL) )
                 return 0;
         return 1;
 }
 
-static inline int presto_do_expect(struct lento_vfs_context *info, struct inode *inode)
+static inline int presto_do_rcvd(struct lento_vfs_context *info,
+                                 struct dentry *dentry)
 {
         if ( ! (info->flags & LENTO_FL_EXPECT) ) 
                 return 0;
-        if ( inode->i_gid == presto_excluded_gid ) 
+        if ( presto_chk(dentry, PRESTO_DONT_JOURNAL) )
                 return 0;
         return 1;
 }
@@ -166,12 +219,15 @@
 /* XXX fixme: this should not fail, all these dentries are in memory
    when _we_ call this */
 int presto_settime(struct presto_file_set *fset, 
-                   struct dentry *dentry, 
+                   struct dentry *newobj,
+                   struct dentry *parent,
+                   struct dentry *target,
                    struct lento_vfs_context *ctx, 
                    int valid)
 {
-        int error; 
-        struct inode *inode = dentry->d_inode;
+        int error = 0;
+        struct dentry *dentry;
+        struct inode *inode;
         struct inode_operations *iops;
         struct iattr iattr;
 
@@ -180,39 +236,128 @@
                 EXIT;
                 return 0;
         }
+
         iattr.ia_ctime = ctx->updated_time;
         iattr.ia_mtime = ctx->updated_time;
         iattr.ia_valid = valid;
 
-        error = -EROFS;
-        if (IS_RDONLY(inode)) {
-                EXIT;
-                return -EROFS;
+        while (1) {
+                if (parent && ctx->flags & LENTO_FL_TOUCH_PARENT) {
+                        dentry = parent;
+                        parent = NULL;
+                } else if (newobj && ctx->flags & LENTO_FL_TOUCH_NEWOBJ) {
+                        dentry = newobj;
+                        newobj = NULL;
+                } else if (target) {
+                        dentry = target;
+                        target = NULL;
+                } else
+                        break;
+
+                inode = dentry->d_inode;
+
+                error = -EROFS;
+                if (IS_RDONLY(inode)) {
+                        EXIT;
+                        return -EROFS;
+                }
+
+                if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+                        EXIT;
+                        return -EPERM;
+                }
+
+                error = -EPERM;
+                iops = filter_c2cdiops(fset->fset_cache->cache_filter); 
+                if (!iops) { 
+                        EXIT;
+                        return error;
+                }
+
+                if (iops->setattr != NULL)
+                        error = iops->setattr(dentry, &iattr);
+                else {
+                        error = 0;
+                        inode_setattr(dentry->d_inode, &iattr);
+                }
         }
+        EXIT;
+        return error;
+}
 
-        if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+void izo_get_rollback_data(struct inode *inode, struct izo_rollback_data *rb)
+{
+        rb->rb_mode = (__u32)inode->i_mode;
+        rb->rb_rdev = (__u32)inode->i_rdev;
+        rb->rb_uid  = (__u64)inode->i_uid;
+        rb->rb_gid  = (__u64)inode->i_gid;
+}
+
+
+int presto_do_close(struct presto_file_set *fset, struct file *file)
+{
+        struct rec_info rec;
+        int rc = -ENOSPC; 
+        void *handle;
+        struct inode *inode = file->f_dentry->d_inode;
+        struct presto_file_data *fdata = 
+                (struct presto_file_data *)file->private_data;
+
+        ENTRY;
+        presto_getversion(&fdata->fd_info.remote_version, inode);
+
+        rc = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
+        if (rc) { 
                 EXIT;
-                return -EPERM;
+                return rc;
         }
 
-        error = -EPERM;
-        iops = filter_c2cdiops(fset->fset_cache->cache_filter); 
-        if (!iops) {
-                EXIT;
-                return error;
+        handle = presto_trans_start(fset, file->f_dentry->d_inode, 
+                                            KML_OPCODE_RELEASE);
+        if ( IS_ERR(handle) ) {
+                CERROR("presto_release: no space for transaction\n");
+                return rc;
         }
 
-        if (iops->setattr != NULL)
-                error = iops->setattr(dentry, &iattr);
-        else {
-		error = 0;
-                inode_setattr(dentry->d_inode, &iattr);
-	}
+        if (fdata->fd_info.flags & LENTO_FL_KML) 
+                rc = presto_journal_close(&rec, fset, file, file->f_dentry,
+                                          &fdata->fd_version, 
+                                          &fdata->fd_info.remote_version);
+        if (rc) { 
+                CERROR("presto_close: cannot journal close\n");
+                goto out;
+        }
+
+        if (fdata->fd_info.flags & LENTO_FL_EXPECT) 
+                rc = presto_write_last_rcvd(&rec, fset, &fdata->fd_info);
+
+        if (rc) { 
+                CERROR("presto_close: cannot journal last_rcvd\n");
+                goto out;
+        }
+        presto_trans_commit(fset, handle); 
+        
+        /* cancel the LML record */ 
+        handle = presto_trans_start(fset, inode, KML_OPCODE_WRITE);
+        if ( IS_ERR(handle) ) {
+                CERROR("presto_release: no space for clear\n");
+                return -ENOSPC;
+        }
+
+        rc = presto_clear_lml_close(fset, fdata->fd_lml_offset); 
+        if (rc < 0 ) { 
+                CERROR("presto_close: cannot journal close\n");
+                goto out;
+        }
+        presto_truncate_lml(fset);
+
+ out:
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+        presto_trans_commit(fset, handle); 
         EXIT;
-        return error;
+        return rc;
 }
 
-
 int presto_do_setattr(struct presto_file_set *fset, struct dentry *dentry,
                       struct iattr *iattr, struct lento_vfs_context *info)
 {
@@ -221,8 +366,9 @@
         struct inode_operations *iops;
         int error;
         struct presto_version old_ver, new_ver;
+        struct izo_rollback_data rb;
         void *handle;
-	off_t old_size=inode->i_size;
+        loff_t old_size=inode->i_size;
 
         ENTRY;
         error = -EROFS;
@@ -237,33 +383,34 @@
         }
 
         presto_getversion(&old_ver, dentry->d_inode);
+        izo_get_rollback_data(dentry->d_inode, &rb);
         error = -EPERM;
         iops = filter_c2cdiops(fset->fset_cache->cache_filter); 
-        if (!iops &&
-            !iops->setattr) {
+
+        error = presto_reserve_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
+        if (error) {
                 EXIT;
                 return error;
         }
 
-	error = presto_reserve_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
-	if (error) {
-		EXIT;
-		return error;
-	}
-
-	if  (iattr->ia_valid & ATTR_SIZE) { 
-		handle = presto_trans_start(fset, dentry->d_inode, PRESTO_OP_TRUNC);
-	} else {
-		handle = presto_trans_start(fset, dentry->d_inode, PRESTO_OP_SETATTR);
-	}
+        if  (iattr->ia_valid & ATTR_SIZE) {
+                if (izo_mark_dentry(dentry, ~PRESTO_DATA, 0, NULL) != 0)
+                        CERROR("izo_mark_dentry(inode %ld, ~PRESTO_DATA) "
+                               "failed\n", dentry->d_inode->i_ino);
+                handle = presto_trans_start(fset, dentry->d_inode,
+                                            KML_OPCODE_TRUNC);
+        } else {
+                handle = presto_trans_start(fset, dentry->d_inode,
+                                            KML_OPCODE_SETATTR);
+        }
 
         if ( IS_ERR(handle) ) {
-                printk("presto_do_setattr: no space for transaction\n");
-		presto_release_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
+                CERROR("presto_do_setattr: no space for transaction\n");
+                presto_release_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
                 return -ENOSPC;
         }
 
-        if (dentry->d_inode && iops->setattr) {
+        if (dentry->d_inode && iops && iops->setattr) {
                 error = iops->setattr(dentry, iattr);
         } else {
                 error = inode_change_ok(dentry->d_inode, iattr);
@@ -271,41 +418,43 @@
                         inode_setattr(inode, iattr);
         }
 
-	if (!error && (iattr->ia_valid & ATTR_SIZE))
-		vmtruncate(inode, iattr->ia_size);
+        if (!error && (iattr->ia_valid & ATTR_SIZE))
+                vmtruncate(inode, iattr->ia_size);
 
         if (error) {
                 EXIT;
                 goto exit;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETATTR | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETATTR | 0x10);
 
-        if ( presto_do_kml(info, dentry->d_inode) ) {
+        if ( presto_do_kml(info, dentry) ) {
                 if ((iattr->ia_valid & ATTR_SIZE) && (old_size != inode->i_size)) {
-                	struct file file;
-                	/* Journal a close whenever we see a potential truncate
-                 	* At the receiving end, lento should explicitly remove
-                 	* ATTR_SIZE from the list of valid attributes */
-                	presto_getversion(&new_ver, inode);
-                	file.private_data = NULL;
-                	file.f_dentry = dentry;
-                	error=presto_journal_close(&rec, fset, &file, dentry, &new_ver);
-            	}
+                        struct file file;
+                        /* Journal a close whenever we see a potential truncate
+                        * At the receiving end, lento should explicitly remove
+                        * ATTR_SIZE from the list of valid attributes */
+                        presto_getversion(&new_ver, inode);
+                        file.private_data = NULL;
+                        file.f_dentry = dentry;
+                        error = presto_journal_close(&rec, fset, &file, dentry,
+                                                     &old_ver, &new_ver);
+                }
 
-		if (!error)
-                	error = presto_journal_setattr(&rec, fset, dentry, &old_ver, iattr);
+                if (!error)
+                        error = presto_journal_setattr(&rec, fset, dentry,
+                                                       &old_ver, &rb, iattr);
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETATTR | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETATTR | 0x20);
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETATTR | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETATTR | 0x30);
 
         EXIT;
 exit:
-	presto_release_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
+        presto_release_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
         presto_trans_commit(fset, handle);
         return error;
 }
@@ -342,7 +491,7 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto exit_lock;
         }
@@ -378,6 +527,14 @@
 
         error = presto_do_setattr(fset, dentry, iattr, info);
 
+        if (info->flags & LENTO_FL_SET_DDFILEID) {
+                struct presto_dentry_data *dd = presto_d2d(dentry);
+                if (dd) {
+                        dd->remote_ino = info->remote_ino;
+                        dd->remote_generation = info->remote_generation;
+                }
+        }
+
 #ifdef CONFIG_FS_POSIX_ACL
         /* restore the inode_operations if we changed them*/
         if (iattr->ia_valid & ATTR_MODE) 
@@ -408,12 +565,12 @@
         mode |= S_IFREG;
 
         down(&dir->d_inode->i_zombie);
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
-	if (error) {
-		EXIT;
-        	up(&dir->d_inode->i_zombie);
-		return error;
-	}
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
+        if (error) {
+                EXIT;
+                up(&dir->d_inode->i_zombie);
+                return error;
+        }
 
         error = may_create(dir->d_inode, dentry);
         if (error) {
@@ -429,13 +586,13 @@
         }
 
         presto_getversion(&tgt_dir_ver, dir->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_CREATE);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_CREATE);
         if ( IS_ERR(handle) ) {
                 EXIT;
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-                printk("presto_do_create: no space for transaction\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+                CERROR("presto_do_create: no space for transaction\n");
                 error=-ENOSPC;
-		goto exit_pre_lock;
+                goto exit_pre_lock;
         }
         DQUOT_INIT(dir->d_inode);
         lock_kernel();
@@ -445,21 +602,11 @@
                 goto exit_lock;
         }
 
-        if (dentry->d_inode && 
-            dentry->d_inode->i_gid != presto_excluded_gid) {
+        if (dentry->d_inode) {
                 struct presto_cache *cache = fset->fset_cache;
                 /* was this already done? */
-                if ( !filter_c2cfiops(cache->cache_filter) )
-                        filter_setup_file_ops(cache->cache_filter, 
-                                              dentry->d_inode,
-                                              &presto_file_iops,
-                                              &presto_file_fops);
-
-                /* make the new inode ours */
-                dentry->d_inode->i_op = 
-                        filter_c2ufiops(cache->cache_filter);
-                dentry->d_inode->i_fop = 
-                        filter_c2uffops(cache->cache_filter);
+                presto_set_ops(dentry->d_inode, cache->cache_filter);
+
                 filter_setup_dentry_ops(cache->cache_filter, 
                                         dentry->d_op, 
                                         &presto_dentry_ops);
@@ -473,37 +620,44 @@
                 }
         }
 
-        error = presto_settime(fset, dir, info, ATTR_CTIME | ATTR_MTIME);
-        if (error) { 
-                EXIT;
-                goto exit_lock;
-        }
-        error = presto_settime(fset, dentry, info, ATTR_CTIME | ATTR_MTIME);
+        info->flags |= LENTO_FL_TOUCH_PARENT;
+        error = presto_settime(fset, NULL, dir, dentry,
+                               info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
                 goto exit_lock;
         }
 
+        presto_debug_fail_blkdev(fset, KML_OPCODE_CREATE | 0x10);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_CREATE | 0x10);
-        presto_getversion(&new_file_ver, dentry->d_inode);
-        if ( presto_do_kml(info, dentry->d_inode) )
+        if ( presto_do_kml(info, dentry) ) { 
+                presto_getversion(&new_file_ver, dentry->d_inode);
                 error = presto_journal_create(&rec, fset, dentry, &tgt_dir_ver,
-                                              &new_file_ver,
+                                              &new_file_ver, 
                                               dentry->d_inode->i_mode);
+        }
+
+        presto_debug_fail_blkdev(fset, KML_OPCODE_CREATE | 0x20);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_CREATE | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) )
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_CREATE | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_CREATE | 0x30);
+
+        /* add inode dentry */
+        if (fset->fset_cache->cache_filter->o_trops->tr_add_ilookup ) { 
+                struct dentry *d;
+                d = fset->fset_cache->cache_filter->o_trops->tr_add_ilookup
+                        (dir->d_inode->i_sb->s_root, dentry);
+        }
+
         EXIT;
 
  exit_lock:
         unlock_kernel();
         presto_trans_commit(fset, handle);
  exit_pre_lock:
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
         up(&dir->d_inode->i_zombie);
         return error;
 }
@@ -551,9 +705,9 @@
         if (path_init(pathname,  LOOKUP_PARENT, &nd))
                 error = path_walk(pathname, &nd);
         if (error) {
-		EXIT;
+                EXIT;
                 goto exit;
-	}
+        }
         dentry = lookup_create(&nd, 0);
         error = PTR_ERR(dentry);
         if (IS_ERR(dentry)) {
@@ -564,7 +718,7 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto exit_lock;
         }
@@ -575,7 +729,7 @@
 
  exit_lock:
         path_release (&nd);
-	dput(dentry); 
+        dput(dentry); 
         up(&dentry->d_parent->d_inode->i_sem);
         putname(pathname);
 exit:
@@ -595,12 +749,12 @@
         void *handle;
 
         down(&dir->d_inode->i_zombie);
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
-	if (error) {
-		EXIT;
-        	up(&dir->d_inode->i_zombie);
-		return error;
-	}
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
+        if (error) {
+                EXIT;
+                up(&dir->d_inode->i_zombie);
+                return error;
+        }
         error = -ENOENT;
         inode = old_dentry->d_inode;
         if (!inode)
@@ -631,10 +785,10 @@
 
 
         presto_getversion(&tgt_dir_ver, dir->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_LINK);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_LINK);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-                printk("presto_do_link: no space for transaction\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+                CERROR("presto_do_link: no space for transaction\n");
                 return -ENOSPC;
         }
 
@@ -647,32 +801,37 @@
                 goto exit_lock;
         }
 
-        error = presto_settime(fset, dir, info, ATTR_CTIME | ATTR_MTIME);
-        if (error) { 
-                EXIT;
-                goto exit_lock;
-        }
-        error = presto_settime(fset, new_dentry, info, ATTR_CTIME);
+        /* link dd data to that of existing dentry */
+        old_dentry->d_op->d_release(new_dentry); 
+        if (!presto_d2d(old_dentry)) 
+                BUG();
+        presto_d2d(old_dentry)->dd_count++;
+
+        new_dentry->d_fsdata = presto_d2d(old_dentry);
+
+        info->flags |= LENTO_FL_TOUCH_PARENT;
+        error = presto_settime(fset, NULL, dir, new_dentry,
+                               info, ATTR_CTIME);
         if (error) { 
                 EXIT;
                 goto exit_lock;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_LINK | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_LINK | 0x10);
         presto_getversion(&new_link_ver, new_dentry->d_inode);
-        if ( presto_do_kml(info, old_dentry->d_inode) )
+        if ( presto_do_kml(info, old_dentry) )
                 error = presto_journal_link(&rec, fset, old_dentry, new_dentry,
                                             &tgt_dir_ver, &new_link_ver);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_LINK | 0x20);
-        if ( presto_do_expect(info, old_dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_LINK | 0x20);
+        if ( presto_do_rcvd(info, old_dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_LINK | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_LINK | 0x30);
         EXIT;
         presto_trans_commit(fset, handle);
 exit_lock:
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
         up(&dir->d_inode->i_zombie);
         return error;
 }
@@ -714,7 +873,7 @@
                         fset = presto_fset(new_dentry);
                         error = -EINVAL;
                         if ( !fset ) {
-                                printk("No fileset!\n");
+                                CERROR("No fileset!\n");
                                 EXIT;
                                 goto out2;
                         }
@@ -736,17 +895,17 @@
         return error;
 }
 
-
 int presto_do_unlink(struct presto_file_set *fset, struct dentry *dir,
                      struct dentry *dentry, struct lento_vfs_context *info)
 {
         struct rec_info rec;
-        int error;
         struct inode_operations *iops;
         struct presto_version tgt_dir_ver, old_file_ver;
+        struct izo_rollback_data rb;
         void *handle;
-        int do_kml = 0, do_expect =0;
-	int linkno = 0;
+        int do_kml = 0, do_rcvd = 0, linkno = 0, error, old_targetlen = 0;
+        char *old_target = NULL;
+
         ENTRY;
         down(&dir->d_inode->i_zombie);
         error = may_delete(dir->d_inode, dentry, 0);
@@ -764,19 +923,34 @@
                 return error;
         }
 
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQLOW); 
-	if (error) {
-		EXIT;
-        	up(&dir->d_inode->i_zombie);
-		return error;
-	}
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQLOW); 
+        if (error) {
+                EXIT;
+                up(&dir->d_inode->i_zombie);
+                return error;
+        }
+
+
+        if (presto_d2d(dentry)) { 
+                struct presto_dentry_data *dd = presto_d2d(dentry); 
+                struct dentry *de = dd->dd_inodentry;
+                if (de && dentry->d_inode->i_nlink == 1) { 
+                        dd->dd_count--;
+                        dd->dd_inodentry = NULL; 
+                        de->d_fsdata = NULL; 
+                        atomic_dec(&de->d_inode->i_count); 
+                        de->d_inode = NULL;
+                        dput(de); 
+                }
+        }
 
         presto_getversion(&tgt_dir_ver, dir->d_inode);
         presto_getversion(&old_file_ver, dentry->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_UNLINK);
+        izo_get_rollback_data(dentry->d_inode, &rb);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_UNLINK);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQLOW); 
-                printk("ERROR: presto_do_unlink: no space for transaction. Tell Peter.\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQLOW); 
+                CERROR("ERROR: presto_do_unlink: no space for transaction. Tell Peter.\n");
                 up(&dir->d_inode->i_zombie);
                 return -ENOSPC;
         }
@@ -785,12 +959,45 @@
                 error = -EBUSY;
         else {
                 lock_kernel();
-		linkno = dentry->d_inode->i_nlink;
-		if (linkno > 1) {
-			dget(dentry);
-		}
-                do_kml = presto_do_kml(info, dir->d_inode);
-                do_expect = presto_do_expect(info, dir->d_inode);
+                linkno = dentry->d_inode->i_nlink;
+                if (linkno > 1) {
+                        dget(dentry);
+                }
+
+                if (S_ISLNK(dentry->d_inode->i_mode)) {
+                        mm_segment_t old_fs;
+                        struct inode_operations *riops;
+                        riops = filter_c2csiops(fset->fset_cache->cache_filter);
+
+                        PRESTO_ALLOC(old_target, PATH_MAX);
+                        if (old_target == NULL) {
+                                error = -ENOMEM;
+                                EXIT;
+                                goto exit;
+                        }
+
+                        old_fs = get_fs();
+                        set_fs(get_ds());
+
+                        if (riops->readlink == NULL)
+                                CERROR("InterMezzo %s: no readlink iops.\n",
+                                       __FUNCTION__);
+                        else
+                                old_targetlen =
+                                        riops->readlink(dentry, old_target,
+                                                        PATH_MAX);
+                        if (old_targetlen < 0) {
+                                CERROR("InterMezzo: readlink failed: %ld\n",
+                                       PTR_ERR(old_target));
+                                PRESTO_FREE(old_target, PATH_MAX);
+                                old_target = NULL;
+                                old_targetlen = 0;
+                        }
+                        set_fs(old_fs);
+                }
+
+                do_kml = presto_do_kml(info, dir);
+                do_rcvd = presto_do_rcvd(info, dir);
                 error = iops->unlink(dir->d_inode, dentry);
                 unlock_kernel();
                 if (!error)
@@ -798,7 +1005,9 @@
         }
 
         if (linkno > 1) { 
-                error = presto_settime(fset, dentry, info, ATTR_CTIME);
+                /* FIXME: Combine this with the next call? */
+                error = presto_settime(fset, NULL, NULL, dentry,
+                                       info, ATTR_CTIME);
                 dput(dentry); 
                 if (error) { 
                         EXIT;
@@ -806,7 +1015,8 @@
                 }
         }
 
-        error = presto_settime(fset, dir, info, ATTR_CTIME | ATTR_MTIME);
+        error = presto_settime(fset, NULL, NULL, dir,
+                               info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
                 goto exit;
@@ -818,22 +1028,22 @@
                 goto exit;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_UNLINK | 0x10);
-        if ( do_kml ) { 
+        presto_debug_fail_blkdev(fset, KML_OPCODE_UNLINK | 0x10);
+        if ( do_kml )
                 error = presto_journal_unlink(&rec, fset, dir, &tgt_dir_ver,
-                                              &old_file_ver,
-                                              dentry->d_name.len,
-                                              dentry->d_name.name);
-	}
-        presto_debug_fail_blkdev(fset, PRESTO_OP_UNLINK | 0x20);
-        if ( do_expect ) { 
+                                              &old_file_ver, &rb, dentry,
+                                              old_target, old_targetlen);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_UNLINK | 0x20);
+        if ( do_rcvd ) { 
                 error = presto_write_last_rcvd(&rec, fset, info);
-	}
-        presto_debug_fail_blkdev(fset, PRESTO_OP_UNLINK | 0x30);
+        }
+        presto_debug_fail_blkdev(fset, KML_OPCODE_UNLINK | 0x30);
         EXIT;
 exit:
-	presto_release_space(fset->fset_cache, PRESTO_REQLOW); 
+        presto_release_space(fset->fset_cache, PRESTO_REQLOW); 
         presto_trans_commit(fset, handle);
+        if (old_target != NULL)
+                PRESTO_FREE(old_target, PATH_MAX);
         return error;
 }
 
@@ -866,7 +1076,7 @@
                 fset = presto_fset(dentry);
                 error = -EINVAL;
                 if ( !fset ) {
-                        printk("No fileset!\n");
+                        CERROR("No fileset!\n");
                         EXIT;
                         goto exit2;
                 }
@@ -904,13 +1114,13 @@
 
         ENTRY;
         down(&dir->d_inode->i_zombie);
-	/* record + max path len + space to free */ 
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
-	if (error) {
-		EXIT;
-        	up(&dir->d_inode->i_zombie);
-		return error;
-	}
+        /* record + max path len + space to free */ 
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+        if (error) {
+                EXIT;
+                up(&dir->d_inode->i_zombie);
+                return error;
+        }
 
         error = may_create(dir->d_inode, dentry);
         if (error) {
@@ -926,11 +1136,12 @@
         }
 
         presto_getversion(&tgt_dir_ver, dir->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_SYMLINK);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_SYMLINK);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
-                printk("ERROR: presto_do_symlink: no space for transaction. Tell Peter.\n"); 
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+                CERROR("ERROR: presto_do_symlink: no space for transaction. Tell Peter.\n"); 
                 EXIT;
+                up(&dir->d_inode->i_zombie);
                 return -ENOSPC;
         }
         DQUOT_INIT(dir->d_inode);
@@ -941,19 +1152,11 @@
                 goto exit;
         }
 
-        if (dentry->d_inode &&
-            dentry->d_inode->i_gid != presto_excluded_gid) {
+        if (dentry->d_inode) {
                 struct presto_cache *cache = fset->fset_cache;
                 
-                /* was this already done? */
-                if ( !filter_c2csiops(cache->cache_filter) )
-                        filter_setup_symlink_ops(cache->cache_filter, 
-                                                 dentry->d_inode,
-                                                 &presto_sym_iops,
-                                                 NULL);
+                presto_set_ops(dentry->d_inode, cache->cache_filter);
 
-                /* make the new inode ours */
-                dentry->d_inode->i_op = filter_c2usiops(cache->cache_filter);
                 filter_setup_dentry_ops(cache->cache_filter, dentry->d_op, 
                                         &presto_dentry_ops);
                 dentry->d_op = filter_c2udops(cache->cache_filter);
@@ -965,34 +1168,31 @@
                 }
         }
 
-        error = presto_settime(fset, dir, info, ATTR_CTIME | ATTR_MTIME);
-        if (error) { 
-                EXIT;
-                goto exit;
-        }
-        error = presto_settime(fset, dentry, info, ATTR_CTIME | ATTR_MTIME);
+        info->flags |= LENTO_FL_TOUCH_PARENT;
+        error = presto_settime(fset, NULL, dir, dentry,
+                               info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
                 goto exit;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SYMLINK | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SYMLINK | 0x10);
         presto_getversion(&new_link_ver, dentry->d_inode);
-        if ( presto_do_kml(info, dentry->d_inode) )
+        if ( presto_do_kml(info, dentry) )
                 error = presto_journal_symlink(&rec, fset, dentry, oldname,
                                                &tgt_dir_ver, &new_link_ver);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SYMLINK | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SYMLINK | 0x20);
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SYMLINK | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SYMLINK | 0x30);
         EXIT;
 exit:
         unlock_kernel();
         presto_trans_commit(fset, handle);
  exit_lock:
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
         up(&dir->d_inode->i_zombie);
         return error;
 }
@@ -1033,7 +1233,7 @@
         dentry = lookup_create(&nd, 0);
         error = PTR_ERR(dentry);
         if (IS_ERR(dentry)) {
-        	path_release(&nd);
+                path_release(&nd);
                 EXIT;
                 goto exit_to;
         }
@@ -1041,8 +1241,8 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
-        	path_release(&nd);
+                CERROR("No fileset!\n");
+                path_release(&nd);
                 EXIT;
                 goto exit_lock;
         }
@@ -1073,11 +1273,12 @@
 
         ENTRY;
         down(&dir->d_inode->i_zombie);
-	/* one journal record + directory block + room for removals*/ 
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
-	if (error) { 
+
+        /* one journal record + directory block + room for removals*/ 
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+        if (error) { 
                 EXIT;
-        	up(&dir->d_inode->i_zombie);
+                up(&dir->d_inode->i_zombie);
                 return error;
         }
 
@@ -1095,10 +1296,10 @@
 
         error = -ENOSPC;
         presto_getversion(&tgt_dir_ver, dir->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_MKDIR);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_MKDIR);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
-                printk("presto_do_mkdir: no space for transaction\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+                CERROR("presto_do_mkdir: no space for transaction\n");
                 goto exit_lock;
         }
 
@@ -1111,11 +1312,11 @@
                 goto exit;
         }
 
-        if ( dentry->d_inode && !error && 
-             dentry->d_inode->i_gid != presto_excluded_gid) {
+        if ( dentry->d_inode && !error) {
                 struct presto_cache *cache = fset->fset_cache;
-                /* make it ours */
-                dentry->d_inode->i_op = filter_c2udiops(cache->cache_filter);
+
+                presto_set_ops(dentry->d_inode, cache->cache_filter);
+
                 filter_setup_dentry_ops(cache->cache_filter, 
                                         dentry->d_op, 
                                         &presto_dentry_ops);
@@ -1128,35 +1329,32 @@
                 }
         }
 
-        error = presto_settime(fset, dir, info, ATTR_CTIME | ATTR_MTIME);
-        if (error) { 
-                EXIT;
-                goto exit;
-        }
-        error = presto_settime(fset, dentry, info, ATTR_CTIME | ATTR_MTIME);
+        info->flags |= LENTO_FL_TOUCH_PARENT;
+        error = presto_settime(fset, NULL, dir, dentry,
+                             info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
                 goto exit;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKDIR | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKDIR | 0x10);
         presto_getversion(&new_dir_ver, dentry->d_inode);
-        if ( presto_do_kml(info, dentry->d_inode) )
+        if ( presto_do_kml(info, dir) )
                 error = presto_journal_mkdir(&rec, fset, dentry, &tgt_dir_ver,
-                                             &new_dir_ver,
+                                             &new_dir_ver, 
                                              dentry->d_inode->i_mode);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKDIR | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKDIR | 0x20);
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKDIR | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKDIR | 0x30);
         EXIT;
 exit:
         unlock_kernel();
         presto_trans_commit(fset, handle);
  exit_lock:
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
         up(&dir->d_inode->i_zombie);
         return error;
 }
@@ -1193,8 +1391,8 @@
         if (!IS_ERR(dentry)) {
                 fset = presto_fset(dentry);
                 error = -EINVAL;
-                if ( !fset ) {
-                        printk("No fileset!\n");
+                if (!fset) {
+                        CERROR("No fileset!\n");
                         EXIT;
                         goto out_dput;
                 }
@@ -1202,14 +1400,14 @@
                 error = presto_do_mkdir(fset, nd.dentry, dentry, 
                                         mode & S_IALLUGO, info);
 out_dput:
-		dput(dentry);
+                dput(dentry);
         }
-	up(&nd.dentry->d_inode->i_sem);
-	path_release(&nd);
+        up(&nd.dentry->d_inode->i_sem);
+        path_release(&nd);
 out_name:
         EXIT;
         putname(pathname);
-	CDEBUG(D_PIOCTL, "error: %d\n", error);
+        CDEBUG(D_PIOCTL, "error: %d\n", error);
         return error;
 }
 
@@ -1232,10 +1430,11 @@
         struct rec_info rec;
         int error;
         struct presto_version tgt_dir_ver, old_dir_ver;
+        struct izo_rollback_data rb;
         struct inode_operations *iops;
         void *handle;
-        int do_kml, do_expect;
-	int size;
+        int do_kml, do_rcvd;
+        int size;
 
         ENTRY;
         error = may_delete(dir->d_inode, dentry, 1);
@@ -1249,64 +1448,67 @@
                 return error;
         }
 
-	size = PRESTO_REQHIGH - dentry->d_inode->i_size; 
-	error = presto_reserve_space(fset->fset_cache, size); 
-	if (error) { 
-		EXIT;
-		return error;
-	}
+        size = PRESTO_REQHIGH - dentry->d_inode->i_size; 
+        error = presto_reserve_space(fset->fset_cache, size); 
+        if (error) { 
+                EXIT;
+                return error;
+        }
 
         presto_getversion(&tgt_dir_ver, dir->d_inode);
         presto_getversion(&old_dir_ver, dentry->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_RMDIR);
+        izo_get_rollback_data(dentry->d_inode, &rb);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_RMDIR);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, size); 
-                printk("ERROR: presto_do_rmdir: no space for transaction. Tell Peter.\n");
+                presto_release_space(fset->fset_cache, size); 
+                CERROR("ERROR: presto_do_rmdir: no space for transaction. Tell Peter.\n");
                 return -ENOSPC;
         }
 
         DQUOT_INIT(dir->d_inode);
 
-        do_kml = presto_do_kml(info, dir->d_inode);
-        do_expect = presto_do_expect(info, dir->d_inode);
+        do_kml = presto_do_kml(info, dir);
+        do_rcvd = presto_do_rcvd(info, dir);
 
         double_down(&dir->d_inode->i_zombie, &dentry->d_inode->i_zombie);
         d_unhash(dentry);
         if (IS_DEADDIR(dir->d_inode))
                 error = -ENOENT;
-        else if (d_mountpoint(dentry))
+        else if (d_mountpoint(dentry)) {
+                CERROR("foo: d_mountpoint(dentry): ino %ld\n",
+                       dentry->d_inode->i_ino);
                 error = -EBUSY;
-        else {
+        } else {
                 lock_kernel();
                 error = iops->rmdir(dir->d_inode, dentry);
                 unlock_kernel();
                 if (!error) {
                         dentry->d_inode->i_flags |= S_DEAD;
-			error = presto_settime(fset, dir, info, 
-					       ATTR_CTIME | ATTR_MTIME);
-		}
+                        error = presto_settime(fset, NULL, NULL, dir, info,
+                                               ATTR_CTIME | ATTR_MTIME);
+                }
         }
         double_up(&dir->d_inode->i_zombie, &dentry->d_inode->i_zombie);
         if (!error)
                 d_delete(dentry);
         dput(dentry);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RMDIR | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RMDIR | 0x10);
         if ( !error && do_kml )
                 error = presto_journal_rmdir(&rec, fset, dir, &tgt_dir_ver,
-                                             &old_dir_ver,
+                                             &old_dir_ver, &rb,
                                              dentry->d_name.len,
                                              dentry->d_name.name);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RMDIR | 0x20);
-        if ( !error && do_expect ) 
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RMDIR | 0x20);
+        if ( !error && do_rcvd ) 
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RMDIR | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RMDIR | 0x30);
         EXIT;
 
         presto_trans_commit(fset, handle);
-	presto_release_space(fset->fset_cache, size); 
+        presto_release_space(fset->fset_cache, size); 
         return error;
 }
 
@@ -1320,21 +1522,27 @@
 
         ENTRY;
         name = getname(pathname);
-        if(IS_ERR(name))
+        if(IS_ERR(name)) {
+                EXIT;
                 return PTR_ERR(name);
+        }
 
         if (path_init(name, LOOKUP_PARENT, &nd))
                 error = path_walk(name, &nd);
-        if (error)
+        if (error) {
+                EXIT;
                 goto exit;
-
+        }
         switch(nd.last_type) {
-                case LAST_DOTDOT:
-                        error = -ENOTEMPTY;
-                        goto exit1;
-                case LAST_ROOT: case LAST_DOT:
-                        error = -EBUSY;
-                        goto exit1;
+        case LAST_DOTDOT:
+                error = -ENOTEMPTY;
+                EXIT;
+                goto exit1;
+        case LAST_ROOT:
+        case LAST_DOT:
+                error = -EBUSY;
+                EXIT;
+                goto exit1;
         }
         down(&nd.dentry->d_inode->i_sem);
         dentry = lookup_hash(&nd.last, nd.dentry);
@@ -1343,7 +1551,7 @@
                 fset = presto_fset(dentry);
                 error = -EINVAL;
                 if ( !fset ) {
-                        printk("No fileset!\n");
+                        CERROR("No fileset!\n");
                         EXIT;
                         goto exit_put;
                 }
@@ -1353,11 +1561,10 @@
         }
         up(&nd.dentry->d_inode->i_sem);
 exit1:
-        EXIT;
         path_release(&nd);
 exit:
-        EXIT;
         putname(name);
+        EXIT;
         return error;
 }
 
@@ -1374,13 +1581,13 @@
         ENTRY;
 
         down(&dir->d_inode->i_zombie);
-	/* one KML entry */ 
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
-	if (error) {
-		EXIT;
-        	up(&dir->d_inode->i_zombie);
-		return error;
-	}
+        /* one KML entry */ 
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
+        if (error) {
+                EXIT;
+                up(&dir->d_inode->i_zombie);
+                return error;
+        }
 
         if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD)) {
                 EXIT;
@@ -1405,10 +1612,10 @@
         
         error = -ENOSPC;
         presto_getversion(&tgt_dir_ver, dir->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_MKNOD);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_MKNOD);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-                printk("presto_do_mknod: no space for transaction\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+                CERROR("presto_do_mknod: no space for transaction\n");
                 goto exit_lock2;
         }
 
@@ -1417,11 +1624,11 @@
                 EXIT;
                 goto exit_commit;
         }
-        if ( dentry->d_inode &&
-             dentry->d_inode->i_gid != presto_excluded_gid) {
+        if ( dentry->d_inode) {
                 struct presto_cache *cache = fset->fset_cache;
-                /* make it ours */
-                dentry->d_inode->i_op = filter_c2udiops(cache->cache_filter);
+
+                presto_set_ops(dentry->d_inode, cache->cache_filter);
+
                 filter_setup_dentry_ops(cache->cache_filter, dentry->d_op, 
                                         &presto_dentry_ops);
                 dentry->d_op = filter_c2udops(cache->cache_filter);
@@ -1434,35 +1641,37 @@
                 }
         }
 
-        error = presto_settime(fset, dir, info, ATTR_MTIME);
+        error = presto_settime(fset, NULL, NULL, dir,
+                               info, ATTR_MTIME);
         if (error) { 
                 EXIT;
         }
-        error = presto_settime(fset, dentry, info, ATTR_CTIME | ATTR_MTIME);
+        error = presto_settime(fset, NULL, NULL, dentry,
+                               info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKNOD | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKNOD | 0x10);
         presto_getversion(&new_node_ver, dentry->d_inode);
-        if ( presto_do_kml(info, dentry->d_inode) )
+        if ( presto_do_kml(info, dentry) )
                 error = presto_journal_mknod(&rec, fset, dentry, &tgt_dir_ver,
-                                             &new_node_ver,
+                                             &new_node_ver, 
                                              dentry->d_inode->i_mode,
                                              MAJOR(dev), MINOR(dev) );
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKNOD | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) ) 
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKNOD | 0x20);
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKNOD | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKNOD | 0x30);
         EXIT;
  exit_commit:
         presto_trans_commit(fset, handle);
  exit_lock2:
         unlock_kernel();
  exit_lock:
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
         up(&dir->d_inode->i_zombie);
         return error;
 }
@@ -1494,7 +1703,7 @@
                 fset = presto_fset(dentry);
                 error = -EINVAL;
                 if ( !fset ) {
-                        printk("No fileset!\n");
+                        CERROR("No fileset!\n");
                         EXIT;
                         goto exit_put;
                 }
@@ -1523,7 +1732,7 @@
         return error;
 }
 
-static int do_rename(struct presto_file_set *fset,
+int do_rename(struct presto_file_set *fset,
                      struct dentry *old_parent, struct dentry *old_dentry,
                      struct dentry *new_parent, struct dentry *new_dentry,
                      struct lento_vfs_context *info)
@@ -1533,7 +1742,7 @@
         struct inode_operations *iops;
         struct presto_version src_dir_ver, tgt_dir_ver;
         void *handle;
-	int new_inode_unlink = 0;
+        int new_inode_unlink = 0;
         struct inode *old_dir = old_parent->d_inode;
         struct inode *new_dir = new_parent->d_inode;
 
@@ -1548,15 +1757,15 @@
                 return error;
         }
 
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
-	if (error) {
-		EXIT;
-		return error;
-	}
-        handle = presto_trans_start(fset, old_dir, PRESTO_OP_RENAME);
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
+        if (error) {
+                EXIT;
+                return error;
+        }
+        handle = presto_trans_start(fset, old_dir, KML_OPCODE_RENAME);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-                printk("presto_do_rename: no space for transaction\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+                CERROR("presto_do_rename: no space for transaction\n");
                 return -ENOSPC;
         }
         if (new_dentry->d_inode && new_dentry->d_inode->i_nlink > 1) { 
@@ -1572,19 +1781,17 @@
         }
 
         if (new_inode_unlink) { 
-                error = presto_settime(fset, old_dentry, info, ATTR_CTIME);
+                error = presto_settime(fset, NULL, NULL, old_dentry,
+                                       info, ATTR_CTIME);
                 dput(old_dentry); 
                 if (error) { 
                         EXIT;
                         goto exit;
                 }
         }
-        error = presto_settime(fset, old_parent, info, ATTR_CTIME | ATTR_MTIME);
-        if (error) { 
-                EXIT;
-                goto exit;
-        }
-        error = presto_settime(fset, new_parent, info, ATTR_CTIME | ATTR_MTIME);
+        info->flags |= LENTO_FL_TOUCH_PARENT;
+        error = presto_settime(fset, NULL, new_parent, old_parent,
+                               info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
                 goto exit;
@@ -1593,21 +1800,22 @@
         /* XXX make a distinction between cross file set
          * and intra file set renames here
          */
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RENAME | 0x10);
-        if ( presto_do_kml(info, old_dir) )
-                error = presto_journal_rename(&rec, fset, old_dentry, new_dentry,
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RENAME | 0x10);
+        if ( presto_do_kml(info, old_dentry) )
+                error = presto_journal_rename(&rec, fset, old_dentry,
+                                              new_dentry,
                                               &src_dir_ver, &tgt_dir_ver);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RENAME | 0x20);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RENAME | 0x20);
 
-        if ( presto_do_expect(info, new_dir) ) 
+        if ( presto_do_rcvd(info, old_dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RENAME | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RENAME | 0x30);
         EXIT;
 exit:
         presto_trans_commit(fset, handle);
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
         return error;
 }
 
@@ -1729,7 +1937,7 @@
                 error = -EBUSY;
         else
                 error = do_rename(fset, old_parent, old_dentry,
-                                         new_parent, new_dentry, info);
+                                  new_parent, new_dentry, info);
         double_up(&old_dir->i_zombie, &new_dir->i_zombie);
         if (error)
                 return error;
@@ -1802,7 +2010,7 @@
         fset = presto_fset(old_dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto exit4;
         }
@@ -1852,7 +2060,7 @@
         if (!IS_ERR(to)) {
                 error = lento_do_rename(from,to, info);
                 putname(to);
-        }
+        } 
         putname(from);
         return error;
 }
@@ -1879,7 +2087,7 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if (!fset) {
-                printk("No fileset for %*s!\n",
+                CERROR("No fileset for %*s!\n",
                        dentry->d_name.len, dentry->d_name.name);
                 EXIT;
                 dput(dentry);
@@ -1890,7 +2098,7 @@
         sprintf(name, "%s%#lx%c%#x",
                 PRESTO_ILOOKUP_MAGIC, ino, PRESTO_ILOOKUP_SEP, generation);
         CDEBUG(D_PIOCTL, "opening %ld by number (as %s)\n", ino, name);
-        return lookup_one_len(name, fset->fset_mtpt, strlen(name));
+        return lookup_one_len(name, fset->fset_dentry, strlen(name));
 }
 
 static struct file *presto_filp_dopen(struct dentry *dentry, int flags)
@@ -1914,8 +2122,7 @@
                 error = get_write_access(inode);
                 if (error) {
                         CDEBUG(D_PIOCTL, "error getting write access\n");
-                        EXIT;
-                        goto cleanup_file;
+                        EXIT;                        goto cleanup_file;
                 }
         }
 
@@ -1969,8 +2176,8 @@
          * just turn off the flag and ignore it.
          */
         if (flags & O_CREAT) {
-                printk(KERN_WARNING "%s: create file by inode number (%ld) not allowed\n",
-                	__FUNCTION__, ino);
+                CERROR("%s: create file by inode number (%ld) not allowed\n",
+                       __FUNCTION__, ino);
                 EXIT;
                 return -EACCES;
         }
@@ -1986,6 +2193,7 @@
         error = presto_walk(tmp, &nd);
         if ( error && error != -ENOENT ) {
                 EXIT;
+                unlock_kernel();
                 return error;
         } 
         if (error == -ENOENT)
@@ -2000,7 +2208,7 @@
                 slash = strrchr(tmp, '/');
                 if (slash && slash != tmp) {
                         *slash = '\0';
-			path_release(&nd);
+                        path_release(&nd);
                         goto again;
                 }
                 /* we should never get here... */
@@ -2052,7 +2260,7 @@
         EXIT;
 exit:
         unlock_kernel();
-	path_release(&nd);
+        path_release(&nd);
         putname(tmp);
         return fd;
 
@@ -2061,72 +2269,6 @@
         goto exit;
 }
 
-int lento_close(unsigned int fd, struct lento_vfs_context *info)
-{
-        struct rec_info rec;
-        int error;
-        struct file * filp;
-        struct dentry *dentry;
-        int do_kml, do_expect;
-
-        ENTRY;
-        lock_kernel();
-
-        error = -EBADF;
-        filp = fcheck(fd);
-        if (filp) {
-
-                struct files_struct * files = current->files;
-                dentry = filp->f_dentry;
-                dget(dentry);
-                do_kml = presto_do_kml(info, dentry->d_inode);
-                do_expect = presto_do_expect(info, dentry->d_inode);
-                files->fd[fd] = NULL;
-                put_unused_fd(fd);
-                FD_CLR(fd, files->close_on_exec);
-                error = filp_close(filp, files);
-        } else {
-                EXIT;
-                return error;
-        }
-
-        if (error) {
-                EXIT;
-                goto exit;
-        }
-
-        if ( do_kml ) { 
-                struct presto_file_set *fset;
-                struct presto_version new_file_ver;
-
-                fset = presto_fset(dentry);
-                error = -EINVAL;
-                if (!fset) {
-                        printk("No fileset for %*s!\n",
-                               dentry->d_name.len, dentry->d_name.name);
-                        EXIT;
-                        goto exit;
-                }
-                presto_getversion(&new_file_ver, dentry->d_inode);
-                error = presto_journal_close(&rec, fset, filp, dentry, 
-					     &new_file_ver);
-                if ( error ) {
-                        printk("presto: close error %d!\n", error);
-                        EXIT;
-                        goto exit;
-                }
-                if ( do_expect ) 
-
-                        error = presto_write_last_rcvd(&rec, fset, info);
-        }
-
-        EXIT;
-exit:
-        dput(dentry);
-        unlock_kernel();
-        return error;
-}
-
 #ifdef CONFIG_FS_EXT_ATTR
 
 #ifdef CONFIG_FS_POSIX_ACL
@@ -2254,9 +2396,9 @@
         }
 
         
-        handle = presto_trans_start(fset,dentry->d_inode,PRESTO_OP_SETEXTATTR);
+        handle = presto_trans_start(fset,dentry->d_inode,KML_OPCODE_SETEXTATTR);
         if ( IS_ERR(handle) ) {
-                printk("presto_do_set_ext_attr: no space for transaction\n");
+                CERROR("presto_do_set_ext_attr: no space for transaction\n");
                 presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
                 return -ENOSPC;
         }
@@ -2285,15 +2427,15 @@
 #endif
 
         /* Reset ctime. Only inode change time (ctime) is affected */
-        error = presto_settime(fset, dentry, info, ATTR_CTIME);
+        error = presto_settime(fset, NULL, NULL, dentry, info, ATTR_CTIME);
         if (error) { 
                 EXIT;
                 goto exit;
         }
 
         if (flags & EXT_ATTR_FLAG_USER) {
-                printk(" USER flag passed to presto_do_set_ext_attr!\n");
-                *(int *)0 = 1;
+                CERROR(" USER flag passed to presto_do_set_ext_attr!\n");
+                BUG();
         }
 
         /* We are here, so set_ext_attr succeeded. We no longer need to keep
@@ -2302,17 +2444,17 @@
          */
         flags &= ~(EXT_ATTR_FLAG_EXISTS | EXT_ATTR_FLAG_CREATE);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETEXTATTR | 0x10);
-        if ( presto_do_kml(info, dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETEXTATTR | 0x10);
+        if ( presto_do_kml(info, dentry) )
                 error = presto_journal_set_ext_attr
                         (&rec, fset, dentry, &ver, name, buffer, 
                          buffer_len, flags);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETEXTATTR | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETEXTATTR | 0x20);
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETEXTATTR | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETEXTATTR | 0x30);
         EXIT;
 exit:
         presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/iobuf.c linux-2.4.20/fs/iobuf.c
--- linux-2.4.19/fs/iobuf.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/iobuf.c	2002-10-29 11:18:49.000000000 +0000
@@ -10,6 +10,9 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 
+
+static kmem_cache_t *kiobuf_cachep;
+
 void end_kio_request(struct kiobuf *kiobuf, int uptodate)
 {
 	if ((!uptodate) && !kiobuf->errno)
@@ -22,39 +25,67 @@
 	}
 }
 
-static void kiobuf_init(struct kiobuf *iobuf)
+static int kiobuf_init(struct kiobuf *iobuf)
 {
 	init_waitqueue_head(&iobuf->wait_queue);
-	iobuf->array_len = KIO_STATIC_PAGES;
-	iobuf->maplist = iobuf->map_array;
+	iobuf->array_len = 0;
 	iobuf->nr_pages = 0;
 	iobuf->locked = 0;
+	iobuf->bh = NULL;
+	iobuf->blocks = NULL;
 	atomic_set(&iobuf->io_count, 0);
 	iobuf->end_io = NULL;
+	return expand_kiobuf(iobuf, KIO_STATIC_PAGES);
 }
 
 int alloc_kiobuf_bhs(struct kiobuf * kiobuf)
 {
 	int i;
 
-	for (i = 0; i < KIO_MAX_SECTORS; i++)
-		if (!(kiobuf->bh[i] = kmem_cache_alloc(bh_cachep, SLAB_KERNEL))) {
-			while (i--) {
-				kmem_cache_free(bh_cachep, kiobuf->bh[i]);
-				kiobuf->bh[i] = NULL;
-			}
-			return -ENOMEM;
-		}
+	kiobuf->blocks =
+		kmalloc(sizeof(*kiobuf->blocks) * KIO_MAX_SECTORS, GFP_KERNEL);
+	if (unlikely(!kiobuf->blocks))
+		goto nomem;
+	kiobuf->bh =
+		kmalloc(sizeof(*kiobuf->bh) * KIO_MAX_SECTORS, GFP_KERNEL);
+	if (unlikely(!kiobuf->bh))
+		goto nomem;
+
+	for (i = 0; i < KIO_MAX_SECTORS; i++) {
+		kiobuf->bh[i] = kmem_cache_alloc(bh_cachep, GFP_KERNEL);
+		if (unlikely(!kiobuf->bh[i]))
+			goto nomem2;
+	}
+
 	return 0;
+
+nomem2:
+	while (i--) {
+		kmem_cache_free(bh_cachep, kiobuf->bh[i]);
+		kiobuf->bh[i] = NULL;
+	}
+	memset(kiobuf->bh, 0, sizeof(*kiobuf->bh) * KIO_MAX_SECTORS);
+
+nomem:
+	free_kiobuf_bhs(kiobuf);
+	return -ENOMEM;
 }
 
 void free_kiobuf_bhs(struct kiobuf * kiobuf)
 {
 	int i;
 
-	for (i = 0; i < KIO_MAX_SECTORS; i++) {
-		kmem_cache_free(bh_cachep, kiobuf->bh[i]);
-		kiobuf->bh[i] = NULL;
+	if (kiobuf->bh) {
+		for (i = 0; i < KIO_MAX_SECTORS; i++)
+			if (kiobuf->bh[i])
+				kmem_cache_free(bh_cachep, kiobuf->bh[i]);
+		kfree(kiobuf->bh);
+		kiobuf->bh = NULL;
+	}
+
+	if (kiobuf->blocks) {
+		kfree(kiobuf->blocks);
+		kiobuf->blocks = NULL;
 	}
 }
 
@@ -64,21 +95,23 @@
 	struct kiobuf *iobuf;
 	
 	for (i = 0; i < nr; i++) {
-		iobuf = vmalloc(sizeof(struct kiobuf));
-		if (!iobuf) {
-			free_kiovec(i, bufp);
-			return -ENOMEM;
-		}
-		kiobuf_init(iobuf);
- 		if (alloc_kiobuf_bhs(iobuf)) {
-			vfree(iobuf);
- 			free_kiovec(i, bufp);
- 			return -ENOMEM;
- 		}
+		iobuf = kmem_cache_alloc(kiobuf_cachep, GFP_KERNEL);
+		if (unlikely(!iobuf))
+			goto nomem;
+		if (unlikely(kiobuf_init(iobuf)))
+			goto nomem2;
+ 		if (unlikely(alloc_kiobuf_bhs(iobuf)))
+			goto nomem2;
 		bufp[i] = iobuf;
 	}
 	
 	return 0;
+
+nomem2:
+	kmem_cache_free(kiobuf_cachep, iobuf);
+nomem:
+	free_kiovec(i, bufp);
+	return -ENOMEM;
 }
 
 void free_kiovec(int nr, struct kiobuf **bufp) 
@@ -90,10 +123,9 @@
 		iobuf = bufp[i];
 		if (iobuf->locked)
 			unlock_kiovec(1, &iobuf);
-		if (iobuf->array_len > KIO_STATIC_PAGES)
-			kfree (iobuf->maplist);
+		kfree(iobuf->maplist);
 		free_kiobuf_bhs(iobuf);
-		vfree(bufp[i]);
+		kmem_cache_free(kiobuf_cachep, bufp[i]);
 	}
 }
 
@@ -104,28 +136,26 @@
 	if (iobuf->array_len >= wanted)
 		return 0;
 	
-	maplist = (struct page **) 
-		kmalloc(wanted * sizeof(struct page **), GFP_KERNEL);
-	if (!maplist)
+	maplist = kmalloc(wanted * sizeof(struct page **), GFP_KERNEL);
+	if (unlikely(!maplist))
 		return -ENOMEM;
 
 	/* Did it grow while we waited? */
-	if (iobuf->array_len >= wanted) {
+	if (unlikely(iobuf->array_len >= wanted)) {
 		kfree(maplist);
 		return 0;
 	}
-	
-	memcpy (maplist, iobuf->maplist, iobuf->array_len * sizeof(struct page **));
 
-	if (iobuf->array_len > KIO_STATIC_PAGES)
-		kfree (iobuf->maplist);
+	if (iobuf->array_len) {
+		memcpy(maplist, iobuf->maplist, iobuf->array_len * sizeof(*maplist));
+		kfree(iobuf->maplist);
+	}
 	
 	iobuf->maplist   = maplist;
 	iobuf->array_len = wanted;
 	return 0;
 }
 
-
 void kiobuf_wait_for_io(struct kiobuf *kiobuf)
 {
 	struct task_struct *tsk = current;
@@ -147,5 +177,10 @@
 	remove_wait_queue(&kiobuf->wait_queue, &wait);
 }
 
-
-
+void __init iobuf_cache_init(void)
+{
+	kiobuf_cachep = kmem_cache_create("kiobuf", sizeof(struct kiobuf),
+					  0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!kiobuf_cachep)
+		panic("Cannot create kiobuf SLAB cache");
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/isofs/compress.c linux-2.4.20/fs/isofs/compress.c
--- linux-2.4.19/fs/isofs/compress.c	2001-11-06 16:34:40.000000000 +0000
+++ linux-2.4.20/fs/isofs/compress.c	2002-10-29 11:18:33.000000000 +0000
@@ -36,7 +36,7 @@
 #include <linux/smp_lock.h>
 #include <linux/blkdev.h>
 #include <linux/vmalloc.h>
-#include <linux/zlib_fs.h>
+#include <linux/zlib.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -209,7 +209,7 @@
 		stream.workspace = zisofs_zlib_workspace;
 		down(&zisofs_zlib_semaphore);
 		
-		zerr = zlib_fs_inflateInit(&stream);
+		zerr = zlib_inflateInit(&stream);
 		if ( zerr != Z_OK ) {
 			if ( err && zerr == Z_MEM_ERROR )
 				err = -ENOMEM;
@@ -250,7 +250,7 @@
 					}
 				}
 				ao = stream.avail_out;  ai = stream.avail_in;
-				zerr = zlib_fs_inflate(&stream, Z_SYNC_FLUSH);
+				zerr = zlib_inflate(&stream, Z_SYNC_FLUSH);
 				left_out = stream.avail_out;
 				if ( zerr == Z_BUF_ERROR && stream.avail_in == 0 )
 					continue;
@@ -291,7 +291,7 @@
 				fpage++;
 			}
 		}
-		zlib_fs_inflateEnd(&stream);
+		zlib_inflateEnd(&stream);
 
 	z_eio:
 		up(&zisofs_zlib_semaphore);
@@ -339,7 +339,7 @@
 		return 0;
 	}
 
-	zisofs_zlib_workspace = vmalloc(zlib_fs_inflate_workspacesize());
+	zisofs_zlib_workspace = vmalloc(zlib_inflate_workspacesize());
 	if ( !zisofs_zlib_workspace )
 		return -ENOMEM;
 	init_MUTEX(&zisofs_zlib_semaphore);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/isofs/inode.c linux-2.4.20/fs/isofs/inode.c
--- linux-2.4.19/fs/isofs/inode.c	2002-02-25 19:38:08.000000000 +0000
+++ linux-2.4.20/fs/isofs/inode.c	2002-10-29 11:18:50.000000000 +0000
@@ -1283,6 +1283,15 @@
 	/* get the volume sequence number */
 	volume_seq_no = isonum_723 (de->volume_sequence_number) ;
 
+    /*
+     * Multi volume means tagging a group of CDs with info in their headers.
+     * All CDs of a group must share the same vol set name and vol set size
+     * and have different vol set seq num. Deciding that data is wrong based
+     * in that three fields is wrong. The fields are informative, for
+     * cataloging purposes in a big jukebox, ie. Read sections 4.17, 4.18, 6.6
+     * of ftp://ftp.ecma.ch/ecma-st/Ecma-119.pdf (ECMA 119 2nd Ed = ISO 9660)
+     */
+#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
 	/*
 	 * Disable checking if we see any volume number other than 0 or 1.
 	 * We could use the cruft option, but that has multiple purposes, one
@@ -1296,6 +1305,7 @@
 		       "Enabling \"cruft\" mount option.\n", volume_seq_no);
 		inode->i_sb->u.isofs_sb.s_cruft = 'y';
 	}
+#endif /*IGNORE_WRONG_MULTI_VOLUME_SPECS */
 
 	/* Install the inode operations vector */
 #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jbd/checkpoint.c linux-2.4.20/fs/jbd/checkpoint.c
--- linux-2.4.19/fs/jbd/checkpoint.c	2002-02-25 19:38:08.000000000 +0000
+++ linux-2.4.20/fs/jbd/checkpoint.c	2002-10-29 11:18:34.000000000 +0000
@@ -594,7 +594,8 @@
 	J_ASSERT (transaction->t_log_list == NULL);
 	J_ASSERT (transaction->t_checkpoint_list == NULL);
 	J_ASSERT (transaction->t_updates == 0);
-	
+	J_ASSERT (list_empty(&transaction->t_jcb));
+
 	J_ASSERT (transaction->t_journal->j_committing_transaction !=
 					transaction);
 	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jbd/commit.c linux-2.4.20/fs/jbd/commit.c
--- linux-2.4.19/fs/jbd/commit.c	2002-02-25 19:38:08.000000000 +0000
+++ linux-2.4.20/fs/jbd/commit.c	2002-10-29 11:18:36.000000000 +0000
@@ -475,7 +475,7 @@
            transaction's t_log_list queue, and metadata buffers are on
            the t_iobuf_list queue.
 
-	   Wait for the transactions in reverse order.  That way we are
+	   Wait for the buffers in reverse order.  That way we are
 	   less likely to be woken up until all IOs have completed, and
 	   so we incur less scheduling load.
 	*/
@@ -566,8 +566,10 @@
 
 	jbd_debug(3, "JBD: commit phase 6\n");
 
-	if (is_journal_aborted(journal))
+	if (is_journal_aborted(journal)) {
+		unlock_journal(journal);
 		goto skip_commit;
+	}
 
 	/* Done it all: now write the commit record.  We should have
 	 * cleaned up our previous buffers by now, so if we are in abort
@@ -577,9 +579,10 @@
 	descriptor = journal_get_descriptor_buffer(journal);
 	if (!descriptor) {
 		__journal_abort_hard(journal);
+		unlock_journal(journal);
 		goto skip_commit;
 	}
-	
+
 	/* AKPM: buglet - add `i' to tmp! */
 	for (i = 0; i < jh2bh(descriptor)->b_size; i += 512) {
 		journal_header_t *tmp =
@@ -600,14 +603,32 @@
 		put_bh(bh);		/* One for getblk() */
 		journal_unlock_journal_head(descriptor);
 	}
-	lock_journal(journal);
 
 	/* End of a transaction!  Finally, we can do checkpoint
            processing: any buffers committed as a result of this
            transaction can be removed from any checkpoint list it was on
            before. */
 
-skip_commit:
+skip_commit: /* The journal should be unlocked by now. */
+
+	/* Call any callbacks that had been registered for handles in this
+	 * transaction.  It is up to the callback to free any allocated
+	 * memory.
+	 */
+	if (!list_empty(&commit_transaction->t_jcb)) {
+		struct list_head *p, *n;
+		int error = is_journal_aborted(journal);
+
+		list_for_each_safe(p, n, &commit_transaction->t_jcb) {
+			struct journal_callback *jcb;
+
+			jcb = list_entry(p, struct journal_callback, jcb_list);
+			list_del(p);
+			jcb->jcb_func(jcb, error);
+		}
+	}
+
+	lock_journal(journal);
 
 	jbd_debug(3, "JBD: commit phase 7\n");
 
@@ -663,6 +684,20 @@
 		 * there's no point in keeping a checkpoint record for
 		 * it. */
 		bh = jh2bh(jh);
+
+		/* A buffer which has been freed while still being
+		 * journaled by a previous transaction may end up still
+		 * being dirty here, but we want to avoid writing back
+		 * that buffer in the future now that the last use has
+		 * been committed.  That's not only a performance gain,
+		 * it also stops aliasing problems if the buffer is left
+		 * behind for writeback and gets reallocated for another
+		 * use in a different page. */
+		if (__buffer_state(bh, Freed)) {
+			clear_bit(BH_Freed, &bh->b_state);
+			clear_bit(BH_JBDDirty, &bh->b_state);
+		}
+			
 		if (buffer_jdirty(bh)) {
 			JBUFFER_TRACE(jh, "add to new checkpointing trans");
 			__journal_insert_checkpoint(jh, commit_transaction);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jbd/journal.c linux-2.4.20/fs/jbd/journal.c
--- linux-2.4.19/fs/jbd/journal.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/jbd/journal.c	2002-10-29 11:18:34.000000000 +0000
@@ -58,6 +58,7 @@
 #endif
 EXPORT_SYMBOL(journal_flush);
 EXPORT_SYMBOL(journal_revoke);
+EXPORT_SYMBOL(journal_callback_set);
 
 EXPORT_SYMBOL(journal_init_dev);
 EXPORT_SYMBOL(journal_init_inode);
@@ -459,11 +460,10 @@
 	do {
 		new_bh = get_unused_buffer_head(0);
 		if (!new_bh) {
-			printk (KERN_NOTICE __FUNCTION__
-				": ENOMEM at get_unused_buffer_head, "
-				"trying again.\n");
-			current->policy |= SCHED_YIELD;
-			schedule();
+			printk (KERN_NOTICE "%s: ENOMEM at "
+				"get_unused_buffer_head, trying again.\n",
+				__FUNCTION__);
+			yield();
 		}
 	} while (!new_bh);
 	/* keep subsequent assertions sane */
@@ -588,9 +588,8 @@
 #ifdef CONFIG_JBD_DEBUG
 	lock_journal(journal);
 	if (!tid_geq(journal->j_commit_request, tid)) {
-		printk(KERN_EMERG __FUNCTION__
-			": error: j_commit_request=%d, tid=%d\n",
-			journal->j_commit_request, tid);
+		printk(KERN_EMERG "%s: error: j_commit_request=%d, tid=%d\n",
+			__FUNCTION__, journal->j_commit_request, tid);
 	}
 	unlock_journal(journal);
 #endif
@@ -639,9 +638,8 @@
 		if (ret)
 			*retp = ret;
 		else {
-			printk (KERN_ALERT __FUNCTION__ 
-				": journal block not found "
-				"at offset %lu on %s\n",
+			printk (KERN_ALERT "%s: journal block not found "
+				"at offset %lu on %s\n", __FUNCTION__,
 				blocknr, bdevname(journal->j_dev));
 			err = -EIO;
 			__journal_abort_soft(journal, err);
@@ -788,8 +786,8 @@
 	err = journal_bmap(journal, 0, &blocknr);
 	/* If that failed, give up */
 	if (err) {
-		printk(KERN_ERR __FUNCTION__ ": Cannnot locate journal "
-		       "superblock\n");
+		printk(KERN_ERR "%s: Cannnot locate journal superblock\n",
+			__FUNCTION__);
 		kfree(journal);
 		return NULL;
 	}
@@ -875,8 +873,8 @@
 		/*
 		 * We don't know what block to start at!
 		 */
-		printk(KERN_EMERG __FUNCTION__
-			": creation of journal on external device!\n");
+		printk(KERN_EMERG "%s: creation of journal on external "
+			"device!\n", __FUNCTION__);
 		BUG();
 	}
 
@@ -1488,6 +1486,49 @@
 	unlock_journal(journal);
 }
 
+
+/*
+ * Report any unexpected dirty buffers which turn up.  Normally those
+ * indicate an error, but they can occur if the user is running (say)
+ * tune2fs to modify the live filesystem, so we need the option of
+ * continuing as gracefully as possible.  #
+ *
+ * The caller should already hold the journal lock and
+ * journal_datalist_lock spinlock: most callers will need those anyway
+ * in order to probe the buffer's journaling state safely.
+ */
+void __jbd_unexpected_dirty_buffer(char *function, int line, 
+				 struct journal_head *jh)
+{
+	struct buffer_head *bh = jh2bh(jh);
+	int jlist;
+	
+	if (buffer_dirty(bh)) {
+		printk ("%sUnexpected dirty buffer encountered at "
+			"%s:%d (%s blocknr %lu)\n",
+			KERN_WARNING, function, line,
+			kdevname(bh->b_dev), bh->b_blocknr);
+#ifdef JBD_PARANOID_WRITES
+		J_ASSERT_BH (bh, !buffer_dirty(bh));
+#endif	
+		
+		/* If this buffer is one which might reasonably be dirty
+		 * --- ie. data, or not part of this journal --- then
+		 * we're OK to leave it alone, but otherwise we need to
+		 * move the dirty bit to the journal's own internal
+		 * JBDDirty bit. */
+		jlist = jh->b_jlist;
+		
+		if (jlist == BJ_Metadata || jlist == BJ_Reserved || 
+		    jlist == BJ_Shadow || jlist == BJ_Forget) {
+			if (atomic_set_buffer_clean(jh2bh(jh))) {
+				set_bit(BH_JBDDirty, &jh2bh(jh)->b_state);
+			}
+		}
+	}
+}
+
+
 int journal_blocks_per_page(struct inode *inode)
 {
 	return 1 << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
@@ -1543,8 +1584,7 @@
 			last_warning = jiffies;
 		}
 		
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 	}
 }
 
@@ -1597,13 +1637,12 @@
 	if (ret == 0) {
 		jbd_debug(1, "out of memory for journal_head\n");
 		if (time_after(jiffies, last_warning + 5*HZ)) {
-			printk(KERN_NOTICE "ENOMEM in " __FUNCTION__
-			       ", retrying.\n");
+			printk(KERN_NOTICE "ENOMEM in %s, retrying.\n",
+				__FUNCTION__);
 			last_warning = jiffies;
 		}
 		while (ret == 0) {
-			current->policy |= SCHED_YIELD;
-			schedule();
+			yield();
 			ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS);
 		}
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jbd/revoke.c linux-2.4.20/fs/jbd/revoke.c
--- linux-2.4.19/fs/jbd/revoke.c	2002-02-25 19:38:08.000000000 +0000
+++ linux-2.4.20/fs/jbd/revoke.c	2002-10-29 11:18:33.000000000 +0000
@@ -137,8 +137,7 @@
 	if (!journal_oom_retry)
 		return -ENOMEM;
 	jbd_debug(1, "ENOMEM in " __FUNCTION__ ", retrying.\n");
-	current->policy |= SCHED_YIELD;
-	schedule();
+	yield();
 	goto repeat;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jbd/transaction.c linux-2.4.20/fs/jbd/transaction.c
--- linux-2.4.19/fs/jbd/transaction.c	2002-02-25 19:38:08.000000000 +0000
+++ linux-2.4.20/fs/jbd/transaction.c	2002-10-29 11:18:36.000000000 +0000
@@ -57,6 +57,7 @@
 	transaction->t_state = T_RUNNING;
 	transaction->t_tid = journal->j_transaction_sequence++;
 	transaction->t_expires = jiffies + journal->j_commit_interval;
+	INIT_LIST_HEAD(&transaction->t_jcb);
 
 	/* Set up the commit timer for the new transaction. */
 	J_ASSERT (!journal->j_commit_timer_active);
@@ -90,7 +91,14 @@
 	transaction_t *transaction;
 	int needed;
 	int nblocks = handle->h_buffer_credits;
-	
+
+	if (nblocks > journal->j_max_transaction_buffers) {
+		jbd_debug(1, "JBD: %s wants too many credits (%d > %d)\n",
+		       current->comm, nblocks,
+		       journal->j_max_transaction_buffers);
+		return -ENOSPC;
+	}
+
 	jbd_debug(3, "New handle %p going live.\n", handle);
 
 repeat:
@@ -201,6 +209,20 @@
 	return 0;
 }
 
+/* Allocate a new handle.  This should probably be in a slab... */
+static handle_t *new_handle(int nblocks)
+{
+	handle_t *handle = jbd_kmalloc(sizeof (handle_t), GFP_NOFS);
+	if (!handle)
+		return NULL;
+	memset(handle, 0, sizeof (handle_t));
+	handle->h_buffer_credits = nblocks;
+	handle->h_ref = 1;
+	INIT_LIST_HEAD(&handle->h_jcb);
+
+	return handle;
+}
+
 /*
  * Obtain a new handle.  
  *
@@ -227,14 +249,11 @@
 		handle->h_ref++;
 		return handle;
 	}
-	
-	handle = jbd_kmalloc(sizeof (handle_t), GFP_NOFS);
+
+	handle = new_handle(nblocks);
 	if (!handle)
 		return ERR_PTR(-ENOMEM);
-	memset (handle, 0, sizeof (handle_t));
 
-	handle->h_buffer_credits = nblocks;
-	handle->h_ref = 1;
 	current->journal_info = handle;
 
 	err = start_this_handle(journal, handle);
@@ -333,14 +352,11 @@
 	
 	if (is_journal_aborted(journal))
 		return ERR_PTR(-EIO);
-	
-	handle = jbd_kmalloc(sizeof (handle_t), GFP_NOFS);
+
+	handle = new_handle(nblocks);
 	if (!handle)
 		return ERR_PTR(-ENOMEM);
-	memset (handle, 0, sizeof (handle_t));
 
-	handle->h_buffer_credits = nblocks;
-	handle->h_ref = 1;
 	current->journal_info = handle;
 
 	err = try_start_this_handle(journal, handle);
@@ -539,76 +555,67 @@
 static int
 do_get_write_access(handle_t *handle, struct journal_head *jh, int force_copy) 
 {
+	struct buffer_head *bh;
 	transaction_t *transaction = handle->h_transaction;
 	journal_t *journal = transaction->t_journal;
 	int error;
 	char *frozen_buffer = NULL;
 	int need_copy = 0;
-
+	int locked;
+	
 	jbd_debug(5, "buffer_head %p, force_copy %d\n", jh, force_copy);
 
 	JBUFFER_TRACE(jh, "entry");
 repeat:
+	bh = jh2bh(jh);
+
 	/* @@@ Need to check for errors here at some point. */
 
 	/*
-	 * AKPM: neither bdflush nor kupdate run with the BKL.   There's
-	 * nothing we can do to prevent them from starting writeout of a
-	 * BUF_DIRTY buffer at any time.  And checkpointing buffers are on
-	 * BUF_DIRTY.  So.  We no longer assert that the buffer is unlocked.
-	 *
-	 * However.  It is very wrong for us to allow ext3 to start directly
-	 * altering the ->b_data of buffers which may at that very time be
-	 * undergoing writeout to the client filesystem.  This can leave
-	 * the filesystem in an inconsistent, transient state if we crash.
-	 * So what we do is to steal the buffer if it is in checkpoint
-	 * mode and dirty.  The journal lock will keep out checkpoint-mode
-	 * state transitions within journal_remove_checkpoint() and the buffer
-	 * is locked to keep bdflush/kupdate/whoever away from it as well.
-	 *
 	 * AKPM: we have replaced all the lock_journal_bh_wait() stuff with a
 	 * simple lock_journal().  This code here will care for locked buffers.
 	 */
-	/*
-	 * The buffer_locked() || buffer_dirty() tests here are simply an
-	 * optimisation tweak.  If anyone else in the system decides to
-	 * lock this buffer later on, we'll blow up.  There doesn't seem
-	 * to be a good reason why they should do this.
-	 */
-	if (jh->b_cp_transaction &&
-	    (buffer_locked(jh2bh(jh)) || buffer_dirty(jh2bh(jh)))) {
+	locked = test_and_set_bit(BH_Lock, &bh->b_state);
+	if (locked) {
+		/* We can't reliably test the buffer state if we found
+		 * it already locked, so just wait for the lock and
+		 * retry. */
 		unlock_journal(journal);
-		lock_buffer(jh2bh(jh));
-		spin_lock(&journal_datalist_lock);
-		if (jh->b_cp_transaction && buffer_dirty(jh2bh(jh))) {
-			/* OK, we need to steal it */
-			JBUFFER_TRACE(jh, "stealing from checkpoint mode");
-			J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
-			J_ASSERT_JH(jh, jh->b_frozen_data == NULL);
-
-			J_ASSERT(handle->h_buffer_credits > 0);
-			handle->h_buffer_credits--;
-
-			/* This will clear BH_Dirty and set BH_JBDDirty. */
-			JBUFFER_TRACE(jh, "file as BJ_Reserved");
-			__journal_file_buffer(jh, transaction, BJ_Reserved);
-
-			/* And pull it off BUF_DIRTY, onto BUF_CLEAN */
-			refile_buffer(jh2bh(jh));
+		__wait_on_buffer(bh);
+		lock_journal(journal);
+		goto repeat;
+	}
+	
+	/* We now hold the buffer lock so it is safe to query the buffer
+	 * state.  Is the buffer dirty? 
+	 * 
+	 * If so, there are two possibilities.  The buffer may be
+	 * non-journaled, and undergoing a quite legitimate writeback.
+	 * Otherwise, it is journaled, and we don't expect dirty buffers
+	 * in that state (the buffers should be marked JBD_Dirty
+	 * instead.)  So either the IO is being done under our own
+	 * control and this is a bug, or it's a third party IO such as
+	 * dump(8) (which may leave the buffer scheduled for read ---
+	 * ie. locked but not dirty) or tune2fs (which may actually have
+	 * the buffer dirtied, ugh.)  */
 
-			/*
-			 * The buffer is now hidden from bdflush.   It is
-			 * metadata against the current transaction.
-			 */
-			JBUFFER_TRACE(jh, "steal from cp mode is complete");
+	if (buffer_dirty(bh)) {
+		spin_lock(&journal_datalist_lock);
+		/* First question: is this buffer already part of the
+		 * current transaction or the existing committing
+		 * transaction? */
+		if (jh->b_transaction) {
+			J_ASSERT_JH(jh, jh->b_transaction == transaction || 
+				    jh->b_transaction == journal->j_committing_transaction);
+			if (jh->b_next_transaction)
+				J_ASSERT_JH(jh, jh->b_next_transaction == transaction);
+			JBUFFER_TRACE(jh, "Unexpected dirty buffer");
+			jbd_unexpected_dirty_buffer(jh);
 		}
 		spin_unlock(&journal_datalist_lock);
-		unlock_buffer(jh2bh(jh));
-		lock_journal(journal);
-		goto repeat;
 	}
 
-	J_ASSERT_JH(jh, !buffer_locked(jh2bh(jh)));
+	unlock_buffer(bh);
 
 	error = -EROFS;
 	if (is_handle_aborted(handle)) 
@@ -688,8 +695,9 @@
 							    GFP_NOFS);
 				lock_journal(journal);
 				if (!frozen_buffer) {
-					printk(KERN_EMERG __FUNCTION__
-						"OOM for frozen_buffer\n");
+					printk(KERN_EMERG
+						"%s: OOM for frozen_buffer\n",
+						__FUNCTION__);
 					JBUFFER_TRACE(jh, "oom!");
 					error = -ENOMEM;
 					spin_lock(&journal_datalist_lock);
@@ -887,8 +895,8 @@
 		jh->b_committed_data = jbd_kmalloc(jh2bh(jh)->b_size, 
 						   GFP_NOFS);
 		if (!jh->b_committed_data) {
-			printk(KERN_EMERG __FUNCTION__
-				": No memory for committed data!\n");
+			printk(KERN_EMERG "%s: No memory for committed data!\n",
+				__FUNCTION__);
 			err = -ENOMEM;
 			goto out;
 		}
@@ -1328,6 +1336,28 @@
 #endif
 
 /*
+ * Register a callback function for this handle.  The function will be
+ * called when the transaction that this handle is part of has been
+ * committed to disk with the original callback data struct and the
+ * error status of the journal as parameters.  There is no guarantee of
+ * ordering between handles within a single transaction, nor between
+ * callbacks registered on the same handle.
+ *
+ * The caller is responsible for allocating the journal_callback struct.
+ * This is to allow the caller to add as much extra data to the callback
+ * as needed, but reduce the overhead of multiple allocations.  The caller
+ * allocated struct must start with a struct journal_callback at offset 0,
+ * and has the caller-specific data afterwards.
+ */
+void journal_callback_set(handle_t *handle,
+			  void (*func)(struct journal_callback *jcb, int error),
+			  struct journal_callback *jcb)
+{
+	list_add_tail(&jcb->jcb_list, &handle->h_jcb);
+	jcb->jcb_func = func;
+}
+
+/*
  * All done for a particular handle.
  *
  * There is not much action needed here.  We just return any remaining
@@ -1378,9 +1408,7 @@
 	if (handle->h_sync) {
 		do {
 			old_handle_count = transaction->t_handle_count;
-			set_current_state(TASK_RUNNING);
-			current->policy |= SCHED_YIELD;
-			schedule();
+			yield();
 		} while (old_handle_count != transaction->t_handle_count);
 	}
 
@@ -1393,7 +1421,10 @@
 			wake_up(&journal->j_wait_transaction_locked);
 	}
 
-	/* 
+	/* Move callbacks from the handle to the transaction. */
+	list_splice(&handle->h_jcb, &transaction->t_jcb);
+
+	/*
 	 * If the handle is marked SYNC, we need to set another commit
 	 * going!  We also want to force a commit if the current
 	 * transaction is occupying too much of the log, or if the
@@ -1843,6 +1874,7 @@
 		 * running transaction if that is set, but nothing
 		 * else. */
 		JBUFFER_TRACE(jh, "on committing transaction");
+		set_bit(BH_Freed, &bh->b_state);
 		if (jh->b_next_transaction) {
 			J_ASSERT(jh->b_next_transaction ==
 					journal->j_running_transaction);
@@ -1926,6 +1958,7 @@
 			transaction_t *transaction, int jlist)
 {
 	struct journal_head **list = 0;
+	int was_dirty = 0;
 
 	assert_spin_locked(&journal_datalist_lock);
 	
@@ -1936,13 +1969,24 @@
 	J_ASSERT_JH(jh, jh->b_transaction == transaction ||
 				jh->b_transaction == 0);
 
-	if (jh->b_transaction) {
-		if (jh->b_jlist == jlist)
-			return;
+	if (jh->b_transaction && jh->b_jlist == jlist)
+		return;
+	
+	/* The following list of buffer states needs to be consistent
+	 * with __jbd_unexpected_dirty_buffer()'s handling of dirty
+	 * state. */
+
+	if (jlist == BJ_Metadata || jlist == BJ_Reserved || 
+	    jlist == BJ_Shadow || jlist == BJ_Forget) {
+		if (atomic_set_buffer_clean(jh2bh(jh)) ||
+		    test_and_clear_bit(BH_JBDDirty, &jh2bh(jh)->b_state))
+			was_dirty = 1;
+	}
+
+	if (jh->b_transaction)
 		__journal_unfile_buffer(jh);
-	} else {
+	else
 		jh->b_transaction = transaction;
-	}
 
 	switch (jlist) {
 	case BJ_None:
@@ -1979,12 +2023,8 @@
 	__blist_add_buffer(list, jh);
 	jh->b_jlist = jlist;
 
-	if (jlist == BJ_Metadata || jlist == BJ_Reserved || 
-	    jlist == BJ_Shadow || jlist == BJ_Forget) {
-		if (atomic_set_buffer_clean(jh2bh(jh))) {
-			set_bit(BH_JBDDirty, &jh2bh(jh)->b_state);
-		}
-	}
+	if (was_dirty)
+		set_bit(BH_JBDDirty, &jh2bh(jh)->b_state);
 }
 
 void journal_file_buffer(struct journal_head *jh,
@@ -2004,26 +2044,36 @@
 
 void __journal_refile_buffer(struct journal_head *jh)
 {
+	int was_dirty = 0;
+
 	assert_spin_locked(&journal_datalist_lock);
 #ifdef __SMP__
 	J_ASSERT_JH(jh, current->lock_depth >= 0);
 #endif
-	__journal_unfile_buffer(jh);
+	/* If the buffer is now unused, just drop it. */
+	if (jh->b_next_transaction == NULL) {
+		__journal_unfile_buffer(jh);
+		jh->b_transaction = NULL;
+		/* Onto BUF_DIRTY for writeback */
+		refile_buffer(jh2bh(jh));
+		return;
+	}
+	
+	/* It has been modified by a later transaction: add it to the
+	 * new transaction's metadata list. */
 
-	/* If the buffer is now unused, just drop it.  If it has been
-	   modified by a later transaction, add it to the new
-	   transaction's metadata list. */
+	if (test_and_clear_bit(BH_JBDDirty, &jh2bh(jh)->b_state))
+			was_dirty = 1;
 
+	__journal_unfile_buffer(jh);
 	jh->b_transaction = jh->b_next_transaction;
 	jh->b_next_transaction = NULL;
+	__journal_file_buffer(jh, jh->b_transaction, BJ_Metadata);
+	J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING);
+
+	if (was_dirty)
+		set_bit(BH_JBDDirty, &jh2bh(jh)->b_state);
 
-	if (jh->b_transaction != NULL) {
-		__journal_file_buffer(jh, jh->b_transaction, BJ_Metadata);
-		J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING);
-	} else {
-		/* Onto BUF_DIRTY for writeback */
-		refile_buffer(jh2bh(jh));
-	}
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jffs2/Makefile linux-2.4.20/fs/jffs2/Makefile
--- linux-2.4.19/fs/jffs2/Makefile	2001-10-04 22:13:18.000000000 +0000
+++ linux-2.4.20/fs/jffs2/Makefile	2002-10-29 11:18:34.000000000 +0000
@@ -1,7 +1,7 @@
 #
 # Makefile for the linux Journalling Flash FileSystem (JFFS) routines.
 #
-# $Id: Makefile,v 1.25 2001/09/25 20:59:41 dwmw2 Exp $
+# $Id: Makefile,v 1.25.2.1 2002/10/11 09:04:44 dwmw2 Exp $
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 # removes any old dependencies. DON'T put your own dependencies here
@@ -11,7 +11,7 @@
 
 
 COMPR_OBJS	:= compr.o compr_rubin.o compr_rtime.o pushpull.o \
-			compr_zlib.o zlib.o
+			compr_zlib.o
 JFFS2_OBJS	:= crc32.o dir.o file.o ioctl.o nodelist.o malloc.o \
 	read.o nodemgmt.o readinode.o super.o write.o scan.o gc.o \
 	symlink.o build.o erase.o background.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jffs2/compr_zlib.c linux-2.4.20/fs/jffs2/compr_zlib.c
--- linux-2.4.19/fs/jffs2/compr_zlib.c	2001-10-04 22:13:18.000000000 +0000
+++ linux-2.4.20/fs/jffs2/compr_zlib.c	2002-10-29 11:18:30.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001 Red Hat, Inc.
+ * Copyright (C) 2001, 2002 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
  *
@@ -31,42 +31,22 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: compr_zlib.c,v 1.8 2001/09/20 15:28:31 dwmw2 Exp $
+ * $Id: compr_zlib.c,v 1.8.2.1 2002/10/11 09:04:44 dwmw2 Exp $
  *
  */
 
-#include "zlib.h"
+#ifndef __KERNEL__
+#error "The userspace support got too messy and was removed. Update your mkfs.jffs2"
+#endif
 
-#ifdef __KERNEL__
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/mtd/compatmac.h> /* for min() */
 #include <linux/slab.h>
 #include <linux/jffs2.h>
+#include <linux/zlib.h>
 #include "nodelist.h"
 
-static void *zalloc(void *opaque, unsigned nr, unsigned size)
-{
-	/* How much does it request? Should we use vmalloc? Or be dynamic? */
-	return kmalloc(nr * size, GFP_KERNEL);
-}
-
-static void zfree(void *opaque, void *addr)
-{
-	kfree(addr);
-}
-#else
-#define min(x,y) ((x)<(y)?(x):(y))
-#ifndef D1
-#define D1(x)
-#endif
-#define KERN_DEBUG
-#define KERN_NOTICE
-#define KERN_WARNING
-#define printk printf
-#include <stdio.h>
-#include <asm/types.h>
-#endif
-
 	/* Plan: call deflate() with avail_in == *sourcelen, 
 		avail_out = *dstlen - 12 and flush == Z_FINISH. 
 		If it doesn't manage to finish,	call it again with
@@ -76,6 +56,35 @@
 	*/
 #define STREAM_END_SPACE 12
 
+static DECLARE_MUTEX(deflate_sem);
+static DECLARE_MUTEX(inflate_sem);
+static void *deflate_workspace;
+static void *inflate_workspace;
+
+int __init jffs2_zlib_init(void)
+{
+	deflate_workspace = vmalloc(zlib_deflate_workspacesize());
+	if (!deflate_workspace) {
+		printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize());
+		return -ENOMEM;
+	}
+	D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize()));
+	inflate_workspace = vmalloc(zlib_inflate_workspacesize());
+	if (!inflate_workspace) {
+		printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize());
+		vfree(deflate_workspace);
+		return -ENOMEM;
+	}
+	D1(printk(KERN_DEBUG "Allocated %d bytes for inflate workspace\n", zlib_inflate_workspacesize()));
+	return 0;
+}
+
+void jffs2_zlib_exit(void)
+{
+	vfree(deflate_workspace);
+	vfree(inflate_workspace);
+}
+
 int zlib_compress(unsigned char *data_in, unsigned char *cpage_out, 
 		   __u32 *sourcelen, __u32 *dstlen)
 {
@@ -85,18 +94,15 @@
 	if (*dstlen <= STREAM_END_SPACE)
 		return -1;
 
-#ifdef __KERNEL__
-	strm.zalloc = zalloc;
-	strm.zfree = zfree;
-#else
-	strm.zalloc = (void *)0;
-	strm.zfree = (void *)0;
-#endif
+	down(&deflate_sem);
+	strm.workspace = deflate_workspace;
 
-	if (Z_OK != deflateInit(&strm, 3)) {
+	if (Z_OK != zlib_deflateInit(&strm, 3)) {
 		printk(KERN_WARNING "deflateInit failed\n");
+		up(&deflate_sem);
 		return -1;
 	}
+
 	strm.next_in = data_in;
 	strm.total_in = 0;
 	
@@ -108,31 +114,32 @@
 		strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out);
 		D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n",
 			  strm.avail_in, strm.avail_out));
-		ret = deflate(&strm, Z_PARTIAL_FLUSH);
+		ret = zlib_deflate(&strm, Z_PARTIAL_FLUSH);
 		D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n", 
 			  strm.avail_in, strm.avail_out, strm.total_in, strm.total_out));
 		if (ret != Z_OK) {
 			D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret));
-			deflateEnd(&strm);
+			zlib_deflateEnd(&strm);
+			up(&deflate_sem);
 			return -1;
 		}
 	}
 	strm.avail_out += STREAM_END_SPACE;
 	strm.avail_in = 0;
-	ret = deflate(&strm, Z_FINISH);
+	ret = zlib_deflate(&strm, Z_FINISH);
+	zlib_deflateEnd(&strm);
+	up(&deflate_sem);
 	if (ret != Z_STREAM_END) {
 		D1(printk(KERN_DEBUG "final deflate returned %d\n", ret));
-		deflateEnd(&strm);
 		return -1;
 	}
-	deflateEnd(&strm);
 
-	D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n", strm.total_in, strm.total_out));
+	D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n",
+		  strm.total_in, strm.total_out));
 
 	if (strm.total_out >= strm.total_in)
 		return -1;
 
-
 	*dstlen = strm.total_out;
 	*sourcelen = strm.total_in;
 	return 0;
@@ -144,16 +151,12 @@
 	z_stream strm;
 	int ret;
 
-#ifdef __KERNEL__
-	strm.zalloc = zalloc;
-	strm.zfree = zfree;
-#else
-	strm.zalloc = (void *)0;
-	strm.zfree = (void *)0;
-#endif
+	down(&inflate_sem);
+	strm.workspace = inflate_workspace;
 
-	if (Z_OK != inflateInit(&strm)) {
+	if (Z_OK != zlib_inflateInit(&strm)) {
 		printk(KERN_WARNING "inflateInit failed\n");
+		up(&inflate_sem);
 		return;
 	}
 	strm.next_in = data_in;
@@ -164,10 +167,11 @@
 	strm.avail_out = destlen;
 	strm.total_out = 0;
 
-	while((ret = inflate(&strm, Z_FINISH)) == Z_OK)
+	while((ret = zlib_inflate(&strm, Z_FINISH)) == Z_OK)
 		;
 	if (ret != Z_STREAM_END) {
 		printk(KERN_NOTICE "inflate returned %d\n", ret);
 	}
-	inflateEnd(&strm);
+	zlib_inflateEnd(&strm);
+	up(&inflate_sem);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jffs2/dir.c linux-2.4.20/fs/jffs2/dir.c
--- linux-2.4.19/fs/jffs2/dir.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/jffs2/dir.c	2002-10-29 11:18:35.000000000 +0000
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: dir.c,v 1.45.2.6 2002/06/20 23:54:48 dwmw2 Exp $
+ * $Id: dir.c,v 1.45.2.7 2002/08/26 15:30:18 dwmw2 Exp $
  *
  */
 
@@ -404,8 +404,9 @@
 			jffs2_mark_node_obsolete(c, fd->raw);
 			jffs2_free_full_dirent(fd);
 		}
-
-		f->inocache->nlink--;
+		/* Don't oops on unlinking a bad inode */
+		if (f->inocache)
+			f->inocache->nlink--;
 		dentry->d_inode->i_nlink--;
 		up(&f->sem);
 	}
@@ -489,6 +490,10 @@
 {
 	int ret;
 
+	/* Can't link a bad inode. */
+	if (!JFFS2_INODE_INFO(old_dentry->d_inode)->inocache)
+		return -EIO;
+
 	if (S_ISDIR(old_dentry->d_inode->i_mode))
 		return -EPERM;
 
@@ -991,7 +996,8 @@
 		/* Oh shit. We really ought to make a single node which can do both atomically */
 		struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
 		down(&f->sem);
-		old_dentry->d_inode->i_nlink = f->inocache->nlink++;
+		if (f->inocache)
+			old_dentry->d_inode->i_nlink = f->inocache->nlink++;
 		up(&f->sem);
 		       
 		printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jffs2/file.c linux-2.4.20/fs/jffs2/file.c
--- linux-2.4.19/fs/jffs2/file.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/jffs2/file.c	2002-10-29 11:18:40.000000000 +0000
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: file.c,v 1.58.2.1 2002/02/23 14:25:36 dwmw2 Exp $
+ * $Id: file.c,v 1.58.2.3 2002/10/07 12:25:55 dwmw2 Exp $
  *
  */
 
@@ -315,18 +315,18 @@
 
 int jffs2_readpage (struct file *filp, struct page *pg)
 {
-	struct jffs2_inode_info *f = JFFS2_INODE_INFO(filp->f_dentry->d_inode);
+	struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host);
 	int ret;
 	
 	down(&f->sem);
-	ret = jffs2_do_readpage_unlock(filp->f_dentry->d_inode, pg);
+	ret = jffs2_do_readpage_unlock(pg->mapping->host, pg);
 	up(&f->sem);
 	return ret;
 }
 
 int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, unsigned end)
 {
-	struct inode *inode = filp->f_dentry->d_inode;
+	struct inode *inode = pg->mapping->host;
 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
 	__u32 pageofs = pg->index << PAGE_CACHE_SHIFT;
 	int ret = 0;
@@ -394,10 +394,10 @@
 	}
 	
 
-	/* Read in the page if it wasn't already present */
-	if (!Page_Uptodate(pg) && (start || end < PAGE_SIZE))
+	/* Read in the page if it wasn't already present, unless it's a whole page */
+	if (!Page_Uptodate(pg) && (start || end < PAGE_CACHE_SIZE))
 		ret = jffs2_do_readpage_nolock(inode, pg);
-	D1(printk(KERN_DEBUG "end prepare_write(). nrpages %ld\n", inode->i_mapping->nrpages));
+	D1(printk(KERN_DEBUG "end prepare_write(). pg->flags %lx\n", pg->flags));
 	up(&f->sem);
 	return ret;
 }
@@ -407,7 +407,7 @@
 	/* Actually commit the write from the page cache page we're looking at.
 	 * For now, we write the full page out each time. It sucks, but it's simple
 	 */
-	struct inode *inode = filp->f_dentry->d_inode;
+	struct inode *inode = pg->mapping->host;
 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
 	__u32 newsize = max_t(__u32, filp->f_dentry->d_inode->i_size, (pg->index << PAGE_CACHE_SHIFT) + end);
@@ -417,7 +417,15 @@
 	int ret = 0;
 	ssize_t writtenlen = 0;
 
-	D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, nrpages %ld\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, filp->f_dentry->d_inode->i_mapping->nrpages));
+	D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags));
+
+	if (!start && end == PAGE_CACHE_SIZE) {
+		/* We need to avoid deadlock with page_cache_read() in
+		   jffs2_garbage_collect_pass(). So we have to mark the
+		   page up to date, to prevent page_cache_read() from 
+		   trying to re-lock it. */
+		SetPageUptodate(pg);
+	}
 
 	ri = jffs2_alloc_raw_inode();
 	if (!ri)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jffs2/gc.c linux-2.4.20/fs/jffs2/gc.c
--- linux-2.4.19/fs/jffs2/gc.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/jffs2/gc.c	2002-10-29 11:18:35.000000000 +0000
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: gc.c,v 1.52.2.3 2002/05/12 17:27:08 dwmw2 Exp $
+ * $Id: gc.c,v 1.52.2.5 2002/10/10 13:18:38 dwmw2 Exp $
  *
  */
 
@@ -134,8 +134,10 @@
 
 	D1(printk(KERN_DEBUG "garbage collect from block at phys 0x%08x\n", jeb->offset));
 
-	if (!jeb->used_size)
+	if (!jeb->used_size) {
+		up(&c->alloc_sem);
 		goto eraseit;
+	}
 
 	raw = jeb->gc_node;
 			
@@ -156,6 +158,7 @@
 		/* Inode-less node. Clean marker, snapshot or something like that */
 		spin_unlock_bh(&c->erase_completion_lock);
 		jffs2_mark_node_obsolete(c, raw);
+		up(&c->alloc_sem);
 		goto eraseit_lock;
 	}
 						     
@@ -170,8 +173,8 @@
 	if (is_bad_inode(inode)) {
 		printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", inum);
 		/* NB. This will happen again. We need to do something appropriate here. */
-		iput(inode);
 		up(&c->alloc_sem);
+		iput(inode);
 		return -EIO;
 	}
 
@@ -234,6 +237,7 @@
 	}
  upnout:
 	up(&f->sem);
+	up(&c->alloc_sem);
 	iput(inode);
 
  eraseit_lock:
@@ -250,7 +254,6 @@
 		jffs2_erase_pending_trigger(c);
 	}
 	spin_unlock_bh(&c->erase_completion_lock);
-	up(&c->alloc_sem);
 
 	return ret;
 }
@@ -507,7 +510,7 @@
 	 * number as before. (Except in case of error -- see 'goto fill;' 
 	 * above.)
 	 */
-	D1(if(unlikely(fn->frags <= 1)) {
+	D1(if(fn->frags <= 1) {
 		printk(KERN_WARNING "jffs2_garbage_collect_hole: Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d\n",
 		       fn->frags, ri.version, f->highest_version, ri.ino);
 	});
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jffs2/nodelist.c linux-2.4.20/fs/jffs2/nodelist.c
--- linux-2.4.19/fs/jffs2/nodelist.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/jffs2/nodelist.c	2002-10-29 11:18:48.000000000 +0000
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: nodelist.c,v 1.30.2.4 2002/05/10 18:30:33 dwmw2 Exp $
+ * $Id: nodelist.c,v 1.30.2.5 2002/08/20 21:02:00 dwmw2 Exp $
  *
  */
 
@@ -202,9 +202,9 @@
 				err = -EIO;
 				goto free_out;
 			}
-			if (node.d.version > *highest_version)
+			if (node.i.version > *highest_version)
 				*highest_version = node.i.version;
-			D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", node.d.version, *highest_version));
+			D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", node.i.version, *highest_version));
 
 			if (ref->flash_offset & 1) {
 				D1(printk(KERN_DEBUG "obsoleted\n"));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jffs2/nodelist.h linux-2.4.20/fs/jffs2/nodelist.h
--- linux-2.4.19/fs/jffs2/nodelist.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/jffs2/nodelist.h	2002-10-29 11:18:48.000000000 +0000
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: nodelist.h,v 1.46.2.1 2002/02/23 14:04:44 dwmw2 Exp $
+ * $Id: nodelist.h,v 1.46.2.3 2002/10/11 09:04:44 dwmw2 Exp $
  *
  */
 
@@ -163,7 +163,6 @@
 	struct jffs2_full_dnode *node; /* NULL for holes */
 	__u32 size;
 	__u32 ofs; /* Don't really need this, but optimisation */
-	__u32 node_ofs; /* offset within the physical node */
 };
 
 struct jffs2_eraseblock
@@ -349,3 +348,7 @@
 void jffs2_erase_pending_blocks(struct jffs2_sb_info *c);
 void jffs2_mark_erased_blocks(struct jffs2_sb_info *c);
 void jffs2_erase_pending_trigger(struct jffs2_sb_info *c);
+
+/* compr_zlib.c */
+int jffs2_zlib_init(void);
+void jffs2_zlib_exit(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jffs2/readinode.c linux-2.4.20/fs/jffs2/readinode.c
--- linux-2.4.19/fs/jffs2/readinode.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/jffs2/readinode.c	2002-10-29 11:18:32.000000000 +0000
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: readinode.c,v 1.58.2.5 2002/03/05 22:40:03 dwmw2 Exp $
+ * $Id: readinode.c,v 1.58.2.6 2002/10/10 13:18:38 dwmw2 Exp $
  *
  */
 
@@ -468,15 +468,28 @@
 	struct jffs2_node_frag *frag, *frags;
 	struct jffs2_full_dirent *fd, *fds;
 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+        /* I don't think we care about the potential race due to reading this
+           without f->sem. It can never get undeleted. */
+        int deleted = f->inocache && !f->inocache->nlink;
 
 	D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
 
+	/* If it's a deleted inode, grab the alloc_sem. This prevents
+	   jffs2_garbage_collect_pass() from deciding that it wants to
+	   garbage collect one of the nodes we're just about to mark 
+	   obsolete -- by the time we drop alloc_sem and return, all
+	   the nodes are marked obsolete, and jffs2_g_c_pass() won't
+	   call iget() for the inode in question.
+	*/
+	if (deleted)
+		down(&c->alloc_sem);
+
 	down(&f->sem);
 
 	frags = f->fraglist;
 	fds = f->dents;
 	if (f->metadata) {
-		if (!f->inocache->nlink)
+		if (deleted)
 			jffs2_mark_node_obsolete(c, f->metadata->raw);
 		jffs2_free_full_dnode(f->metadata);
 	}
@@ -488,7 +501,7 @@
 
 		if (frag->node && !(--frag->node->frags)) {
 			/* Not a hole, and it's the final remaining frag of this node. Free the node */
-			if (!f->inocache->nlink)
+			if (deleted)
 				jffs2_mark_node_obsolete(c, frag->node->raw);
 
 			jffs2_free_full_dnode(frag->node);
@@ -502,5 +515,8 @@
 	}
 
 	up(&f->sem);
+
+	if(deleted)
+		up(&c->alloc_sem);
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jffs2/scan.c linux-2.4.20/fs/jffs2/scan.c
--- linux-2.4.19/fs/jffs2/scan.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/jffs2/scan.c	2002-10-29 11:18:38.000000000 +0000
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: scan.c,v 1.51.2.2 2002/02/23 13:34:31 dwmw2 Exp $
+ * $Id: scan.c,v 1.51.2.3 2002/07/25 20:49:06 dwmw2 Exp $
  *
  */
 #include <linux/kernel.h>
@@ -261,6 +261,16 @@
 			continue;
 		}
 
+		if (ofs + node.totlen > jeb->offset + c->sector_size) {
+			/* Eep. Node goes over the end of the erase block. */
+			printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
+			       ofs, node.totlen);
+			printk(KERN_WARNING "Perhaps the file system was created with the wrong erase size?\n");
+			DIRTY_SPACE(4);
+			ofs += 4;
+			continue;
+		}
+
 		switch(node.nodetype | JFFS2_NODE_ACCURATE) {
 		case JFFS2_NODETYPE_INODE:
 			err = jffs2_scan_inode_node(c, jeb, &ofs);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jffs2/super.c linux-2.4.20/fs/jffs2/super.c
--- linux-2.4.19/fs/jffs2/super.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/jffs2/super.c	2002-10-29 11:18:36.000000000 +0000
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: super.c,v 1.48.2.2 2002/03/12 15:36:43 dwmw2 Exp $
+ * $Id: super.c,v 1.48.2.3 2002/10/11 09:04:44 dwmw2 Exp $
  *
  */
 
@@ -361,22 +361,35 @@
 	}
 #endif
 
+	ret = jffs2_zlib_init();
+	if (ret) {
+		printk(KERN_ERR "JFFS2 error: Failed to initialise zlib workspaces\n");
+		goto out;
+	}
 	ret = jffs2_create_slab_caches();
 	if (ret) {
 		printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
-		return ret;
+		goto out_zlib;
 	}
 	ret = register_filesystem(&jffs2_fs_type);
 	if (ret) {
 		printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n");
-		jffs2_destroy_slab_caches();
+		goto out_slab;
 	}
+	return 0;
+
+ out_slab:
+	jffs2_destroy_slab_caches();
+ out_zlib:
+	jffs2_zlib_exit();
+ out:
 	return ret;
 }
 
 static void __exit exit_jffs2_fs(void)
 {
 	jffs2_destroy_slab_caches();
+	jffs2_zlib_exit();
 	unregister_filesystem(&jffs2_fs_type);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jffs2/write.c linux-2.4.20/fs/jffs2/write.c
--- linux-2.4.19/fs/jffs2/write.c	2002-02-25 19:38:09.000000000 +0000
+++ linux-2.4.20/fs/jffs2/write.c	2002-10-29 11:18:40.000000000 +0000
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: write.c,v 1.30 2001/12/30 16:01:11 dwmw2 Exp $
+ * $Id: write.c,v 1.30.2.1 2002/08/08 08:36:31 dwmw2 Exp $
  *
  */
 
@@ -110,8 +110,9 @@
 	return inode;
 }
 
-/* This ought to be in core MTD code. All registered MTD devices without writev should have
-   this put in place. Bug the MTD maintainer */
+/* This ought to be in core MTD code. All registered MTD devices
+   without writev should have this put in place. Bug the MTD
+   maintainer */
 static int mtd_fake_writev(struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen)
 {
 	unsigned long i;
@@ -119,7 +120,7 @@
 	int ret = 0;
 
 	for (i=0; i<count; i++) {
-		mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base);
+		ret = mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base);
 		totlen += thislen;
 		if (ret || thislen != vecs[i].iov_len)
 			break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jffs2/zlib.c linux-2.4.20/fs/jffs2/zlib.c
--- linux-2.4.19/fs/jffs2/zlib.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/jffs2/zlib.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,5376 +0,0 @@
-/*
- * This file is derived from various .h and .c files from the zlib-1.0.4
- * distribution by Jean-loup Gailly and Mark Adler, with some additions
- * by Paul Mackerras to aid in implementing Deflate compression and
- * decompression for PPP packets.  See zlib.h for conditions of
- * distribution and use.
- *
- * Changes that have been made include:
- * - added Z_PACKET_FLUSH (see zlib.h for details)
- * - added inflateIncomp and deflateOutputPending
- * - allow strm->next_out to be NULL, meaning discard the output
- *
- * $Id: zlib.c,v 1.3 1997/12/23 10:47:42 paulus Exp $
- */
-
-/* 
- *  ==FILEVERSION 20020318==
- *
- * This marker is used by the Linux installation script to determine
- * whether an up-to-date version of this file is already installed.
- */
-
-#define NO_DUMMY_DECL
-#define NO_ZCFUNCS
-#define MY_ZCALLOC
-
-#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL))
-#define inflate	inflate_ppp	/* FreeBSD already has an inflate :-( */
-#endif
-
-
-/* +++ zutil.h */
-/* zutil.h -- internal interface and configuration of the compression library
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-/* From: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp $ */
-
-#ifndef _Z_UTIL_H
-#define _Z_UTIL_H
-
-#include "zlib.h"
-
-#if defined(KERNEL) || defined(_KERNEL)
-/* Assume this is a *BSD or SVR4 kernel */
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/systm.h>
-#  define HAVE_MEMCPY
-#  define memcpy(d, s, n)	bcopy((s), (d), (n))
-#  define memset(d, v, n)	bzero((d), (n))
-#  define memcmp		bcmp
-
-#else
-#if defined(__KERNEL__)
-/* Assume this is a Linux kernel */
-#include <linux/string.h>
-#define HAVE_MEMCPY
-
-#else /* not kernel */
-
-#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS)
-#   include <stddef.h>
-#   include <errno.h>
-#else
-    extern int errno;
-#endif
-#ifdef STDC
-#  include <string.h>
-#  include <stdlib.h>
-#endif
-#endif /* __KERNEL__ */
-#endif /* _KERNEL || KERNEL */
-
-#ifndef local
-#  define local static
-#endif
-/* compile with -Dlocal if your debugger can't find static symbols */
-
-typedef unsigned char  uch;
-typedef uch FAR uchf;
-typedef unsigned short ush;
-typedef ush FAR ushf;
-typedef unsigned long  ulg;
-
-extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
-/* (size given to avoid silly warnings with Visual C++) */
-
-#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
-
-#define ERR_RETURN(strm,err) \
-  return (strm->msg = (char*)ERR_MSG(err), (err))
-/* To be used only when the state is known to be valid */
-
-        /* common constants */
-
-#ifndef DEF_WBITS
-#  define DEF_WBITS MAX_WBITS
-#endif
-/* default windowBits for decompression. MAX_WBITS is for compression only */
-
-#if MAX_MEM_LEVEL >= 8
-#  define DEF_MEM_LEVEL 8
-#else
-#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
-#endif
-/* default memLevel */
-
-#define STORED_BLOCK 0
-#define STATIC_TREES 1
-#define DYN_TREES    2
-/* The three kinds of block type */
-
-#define MIN_MATCH  3
-#define MAX_MATCH  258
-/* The minimum and maximum match lengths */
-
-#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
-
-        /* target dependencies */
-
-#ifdef MSDOS
-#  define OS_CODE  0x00
-#  ifdef __TURBOC__
-#    include <alloc.h>
-#  else /* MSC or DJGPP */
-#    include <malloc.h>
-#  endif
-#endif
-
-#ifdef OS2
-#  define OS_CODE  0x06
-#endif
-
-#ifdef WIN32 /* Window 95 & Windows NT */
-#  define OS_CODE  0x0b
-#endif
-
-#if defined(VAXC) || defined(VMS)
-#  define OS_CODE  0x02
-#  define FOPEN(name, mode) \
-     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
-#endif
-
-#ifdef AMIGA
-#  define OS_CODE  0x01
-#endif
-
-#if defined(ATARI) || defined(atarist)
-#  define OS_CODE  0x05
-#endif
-
-#ifdef MACOS
-#  define OS_CODE  0x07
-#endif
-
-#ifdef __50SERIES /* Prime/PRIMOS */
-#  define OS_CODE  0x0F
-#endif
-
-#ifdef TOPS20
-#  define OS_CODE  0x0a
-#endif
-
-#if defined(_BEOS_) || defined(RISCOS)
-#  define fdopen(fd,mode) NULL /* No fdopen() */
-#endif
-
-        /* Common defaults */
-
-#ifndef OS_CODE
-#  define OS_CODE  0x03  /* assume Unix */
-#endif
-
-#ifndef FOPEN
-#  define FOPEN(name, mode) fopen((name), (mode))
-#endif
-
-         /* functions */
-
-#ifdef HAVE_STRERROR
-   extern char *strerror OF((int));
-#  define zstrerror(errnum) strerror(errnum)
-#else
-#  define zstrerror(errnum) ""
-#endif
-
-#if defined(pyr)
-#  define NO_MEMCPY
-#endif
-#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER)
- /* Use our own functions for small and medium model with MSC <= 5.0.
-  * You may have to use the same strategy for Borland C (untested).
-  */
-#  define NO_MEMCPY
-#endif
-#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
-#  define HAVE_MEMCPY
-#endif
-#ifdef HAVE_MEMCPY
-#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
-#    define zmemcpy _fmemcpy
-#    define zmemcmp _fmemcmp
-#    define zmemzero(dest, len) _fmemset(dest, 0, len)
-#  else
-#    define zmemcpy memcpy
-#    define zmemcmp memcmp
-#    define zmemzero(dest, len) memset(dest, 0, len)
-#  endif
-#else
-   extern void zmemcpy  OF((Bytef* dest, Bytef* source, uInt len));
-   extern int  zmemcmp  OF((Bytef* s1,   Bytef* s2, uInt len));
-   extern void zmemzero OF((Bytef* dest, uInt len));
-#endif
-
-/* Diagnostic functions */
-#ifdef DEBUG_ZLIB
-#  include <stdio.h>
-#  ifndef verbose
-#    define verbose 0
-#  endif
-   extern void z_error    OF((char *m));
-#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
-#  define Trace(x) fprintf x
-#  define Tracev(x) {if (verbose) fprintf x ;}
-#  define Tracevv(x) {if (verbose>1) fprintf x ;}
-#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
-#else
-#  define Assert(cond,msg)
-#  define Trace(x)
-#  define Tracev(x)
-#  define Tracevv(x)
-#  define Tracec(c,x)
-#  define Tracecv(c,x)
-#endif
-
-
-typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len));
-
-voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
-void   zcfree  OF((voidpf opaque, voidpf ptr));
-
-#define ZALLOC(strm, items, size) \
-           (*((strm)->zalloc))((strm)->opaque, (items), (size))
-#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
-#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
-
-#endif /* _Z_UTIL_H */
-/* --- zutil.h */
-
-/* +++ deflate.h */
-/* deflate.h -- internal compression state
- * Copyright (C) 1995-1996 Jean-loup Gailly
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-/* From: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */
-
-#ifndef _DEFLATE_H
-#define _DEFLATE_H
-
-/* #include "zutil.h" */
-
-/* ===========================================================================
- * Internal compression state.
- */
-
-#define LENGTH_CODES 29
-/* number of length codes, not counting the special END_BLOCK code */
-
-#define LITERALS  256
-/* number of literal bytes 0..255 */
-
-#define L_CODES (LITERALS+1+LENGTH_CODES)
-/* number of Literal or Length codes, including the END_BLOCK code */
-
-#define D_CODES   30
-/* number of distance codes */
-
-#define BL_CODES  19
-/* number of codes used to transfer the bit lengths */
-
-#define HEAP_SIZE (2*L_CODES+1)
-/* maximum heap size */
-
-#define MAX_BITS 15
-/* All codes must not exceed MAX_BITS bits */
-
-#define INIT_STATE    42
-#define BUSY_STATE   113
-#define FINISH_STATE 666
-/* Stream status */
-
-
-/* Data structure describing a single value and its code string. */
-typedef struct ct_data_s {
-    union {
-        ush  freq;       /* frequency count */
-        ush  code;       /* bit string */
-    } fc;
-    union {
-        ush  dad;        /* father node in Huffman tree */
-        ush  len;        /* length of bit string */
-    } dl;
-} FAR ct_data;
-
-#define Freq fc.freq
-#define Code fc.code
-#define Dad  dl.dad
-#define Len  dl.len
-
-typedef struct static_tree_desc_s  static_tree_desc;
-
-typedef struct tree_desc_s {
-    ct_data *dyn_tree;           /* the dynamic tree */
-    int     max_code;            /* largest code with non zero frequency */
-    static_tree_desc *stat_desc; /* the corresponding static tree */
-} FAR tree_desc;
-
-typedef ush Pos;
-typedef Pos FAR Posf;
-typedef unsigned IPos;
-
-/* A Pos is an index in the character window. We use short instead of int to
- * save space in the various tables. IPos is used only for parameter passing.
- */
-
-typedef struct deflate_state {
-    z_streamp strm;      /* pointer back to this zlib stream */
-    int   status;        /* as the name implies */
-    Bytef *pending_buf;  /* output still pending */
-    ulg   pending_buf_size; /* size of pending_buf */
-    Bytef *pending_out;  /* next pending byte to output to the stream */
-    int   pending;       /* nb of bytes in the pending buffer */
-    int   noheader;      /* suppress zlib header and adler32 */
-    Byte  data_type;     /* UNKNOWN, BINARY or ASCII */
-    Byte  method;        /* STORED (for zip only) or DEFLATED */
-    int   last_flush;    /* value of flush param for previous deflate call */
-
-                /* used by deflate.c: */
-
-    uInt  w_size;        /* LZ77 window size (32K by default) */
-    uInt  w_bits;        /* log2(w_size)  (8..16) */
-    uInt  w_mask;        /* w_size - 1 */
-
-    Bytef *window;
-    /* Sliding window. Input bytes are read into the second half of the window,
-     * and move to the first half later to keep a dictionary of at least wSize
-     * bytes. With this organization, matches are limited to a distance of
-     * wSize-MAX_MATCH bytes, but this ensures that IO is always
-     * performed with a length multiple of the block size. Also, it limits
-     * the window size to 64K, which is quite useful on MSDOS.
-     * To do: use the user input buffer as sliding window.
-     */
-
-    ulg window_size;
-    /* Actual size of window: 2*wSize, except when the user input buffer
-     * is directly used as sliding window.
-     */
-
-    Posf *prev;
-    /* Link to older string with same hash index. To limit the size of this
-     * array to 64K, this link is maintained only for the last 32K strings.
-     * An index in this array is thus a window index modulo 32K.
-     */
-
-    Posf *head; /* Heads of the hash chains or NIL. */
-
-    uInt  ins_h;          /* hash index of string to be inserted */
-    uInt  hash_size;      /* number of elements in hash table */
-    uInt  hash_bits;      /* log2(hash_size) */
-    uInt  hash_mask;      /* hash_size-1 */
-
-    uInt  hash_shift;
-    /* Number of bits by which ins_h must be shifted at each input
-     * step. It must be such that after MIN_MATCH steps, the oldest
-     * byte no longer takes part in the hash key, that is:
-     *   hash_shift * MIN_MATCH >= hash_bits
-     */
-
-    long block_start;
-    /* Window position at the beginning of the current output block. Gets
-     * negative when the window is moved backwards.
-     */
-
-    uInt match_length;           /* length of best match */
-    IPos prev_match;             /* previous match */
-    int match_available;         /* set if previous match exists */
-    uInt strstart;               /* start of string to insert */
-    uInt match_start;            /* start of matching string */
-    uInt lookahead;              /* number of valid bytes ahead in window */
-
-    uInt prev_length;
-    /* Length of the best match at previous step. Matches not greater than this
-     * are discarded. This is used in the lazy match evaluation.
-     */
-
-    uInt max_chain_length;
-    /* To speed up deflation, hash chains are never searched beyond this
-     * length.  A higher limit improves compression ratio but degrades the
-     * speed.
-     */
-
-    uInt max_lazy_match;
-    /* Attempt to find a better match only when the current match is strictly
-     * smaller than this value. This mechanism is used only for compression
-     * levels >= 4.
-     */
-#   define max_insert_length  max_lazy_match
-    /* Insert new strings in the hash table only if the match length is not
-     * greater than this length. This saves time but degrades compression.
-     * max_insert_length is used only for compression levels <= 3.
-     */
-
-    int level;    /* compression level (1..9) */
-    int strategy; /* favor or force Huffman coding*/
-
-    uInt good_match;
-    /* Use a faster search when the previous match is longer than this */
-
-    int nice_match; /* Stop searching when current match exceeds this */
-
-                /* used by trees.c: */
-    /* Didn't use ct_data typedef below to supress compiler warning */
-    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
-    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
-    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
-
-    struct tree_desc_s l_desc;               /* desc. for literal tree */
-    struct tree_desc_s d_desc;               /* desc. for distance tree */
-    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
-
-    ush bl_count[MAX_BITS+1];
-    /* number of codes at each bit length for an optimal tree */
-
-    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
-    int heap_len;               /* number of elements in the heap */
-    int heap_max;               /* element of largest frequency */
-    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
-     * The same heap array is used to build all trees.
-     */
-
-    uch depth[2*L_CODES+1];
-    /* Depth of each subtree used as tie breaker for trees of equal frequency
-     */
-
-    uchf *l_buf;          /* buffer for literals or lengths */
-
-    uInt  lit_bufsize;
-    /* Size of match buffer for literals/lengths.  There are 4 reasons for
-     * limiting lit_bufsize to 64K:
-     *   - frequencies can be kept in 16 bit counters
-     *   - if compression is not successful for the first block, all input
-     *     data is still in the window so we can still emit a stored block even
-     *     when input comes from standard input.  (This can also be done for
-     *     all blocks if lit_bufsize is not greater than 32K.)
-     *   - if compression is not successful for a file smaller than 64K, we can
-     *     even emit a stored file instead of a stored block (saving 5 bytes).
-     *     This is applicable only for zip (not gzip or zlib).
-     *   - creating new Huffman trees less frequently may not provide fast
-     *     adaptation to changes in the input data statistics. (Take for
-     *     example a binary file with poorly compressible code followed by
-     *     a highly compressible string table.) Smaller buffer sizes give
-     *     fast adaptation but have of course the overhead of transmitting
-     *     trees more frequently.
-     *   - I can't count above 4
-     */
-
-    uInt last_lit;      /* running index in l_buf */
-
-    ushf *d_buf;
-    /* Buffer for distances. To simplify the code, d_buf and l_buf have
-     * the same number of elements. To use different lengths, an extra flag
-     * array would be necessary.
-     */
-
-    ulg opt_len;        /* bit length of current block with optimal trees */
-    ulg static_len;     /* bit length of current block with static trees */
-    ulg compressed_len; /* total bit length of compressed file */
-    uInt matches;       /* number of string matches in current block */
-    int last_eob_len;   /* bit length of EOB code for last block */
-
-#ifdef DEBUG_ZLIB
-    ulg bits_sent;      /* bit length of the compressed data */
-#endif
-
-    ush bi_buf;
-    /* Output buffer. bits are inserted starting at the bottom (least
-     * significant bits).
-     */
-    int bi_valid;
-    /* Number of valid bits in bi_buf.  All bits above the last valid bit
-     * are always zero.
-     */
-
-} FAR deflate_state;
-
-/* Output a byte on the stream.
- * IN assertion: there is enough room in pending_buf.
- */
-#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
-
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
-/* In order to simplify the code, particularly on 16 bit machines, match
- * distances are limited to MAX_DIST instead of WSIZE.
- */
-
-        /* in trees.c */
-void _tr_init         OF((deflate_state *s));
-int  _tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
-ulg  _tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
-			  int eof));
-void _tr_align        OF((deflate_state *s));
-void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
-                          int eof));
-void _tr_stored_type_only OF((deflate_state *));
-
-#endif
-/* --- deflate.h */
-
-/* +++ deflate.c */
-/* deflate.c -- compress data using the deflation algorithm
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/*
- *  ALGORITHM
- *
- *      The "deflation" process depends on being able to identify portions
- *      of the input text which are identical to earlier input (within a
- *      sliding window trailing behind the input currently being processed).
- *
- *      The most straightforward technique turns out to be the fastest for
- *      most input files: try all possible matches and select the longest.
- *      The key feature of this algorithm is that insertions into the string
- *      dictionary are very simple and thus fast, and deletions are avoided
- *      completely. Insertions are performed at each input character, whereas
- *      string matches are performed only when the previous match ends. So it
- *      is preferable to spend more time in matches to allow very fast string
- *      insertions and avoid deletions. The matching algorithm for small
- *      strings is inspired from that of Rabin & Karp. A brute force approach
- *      is used to find longer strings when a small match has been found.
- *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
- *      (by Leonid Broukhis).
- *         A previous version of this file used a more sophisticated algorithm
- *      (by Fiala and Greene) which is guaranteed to run in linear amortized
- *      time, but has a larger average cost, uses more memory and is patented.
- *      However the F&G algorithm may be faster for some highly redundant
- *      files if the parameter max_chain_length (described below) is too large.
- *
- *  ACKNOWLEDGEMENTS
- *
- *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
- *      I found it in 'freeze' written by Leonid Broukhis.
- *      Thanks to many people for bug reports and testing.
- *
- *  REFERENCES
- *
- *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
- *      Available in ftp://ds.internic.net/rfc/rfc1951.txt
- *
- *      A description of the Rabin and Karp algorithm is given in the book
- *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
- *
- *      Fiala,E.R., and Greene,D.H.
- *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
- *
- */
-
-/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */
-
-/* #include "deflate.h" */
-
-char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly ";
-/*
-  If you use the zlib library in a product, an acknowledgment is welcome
-  in the documentation of your product. If for some reason you cannot
-  include such an acknowledgment, I would appreciate that you keep this
-  copyright string in the executable of your product.
- */
-
-/* ===========================================================================
- *  Function prototypes.
- */
-typedef enum {
-    need_more,      /* block not completed, need more input or more output */
-    block_done,     /* block flush performed */
-    finish_started, /* finish started, need only more output at next deflate */
-    finish_done     /* finish done, accept no more input or output */
-} block_state;
-
-typedef block_state (*compress_func) OF((deflate_state *s, int flush));
-/* Compression function. Returns the block state after the call. */
-
-local void fill_window    OF((deflate_state *s));
-local block_state deflate_stored OF((deflate_state *s, int flush));
-local block_state deflate_fast   OF((deflate_state *s, int flush));
-local block_state deflate_slow   OF((deflate_state *s, int flush));
-local void lm_init        OF((deflate_state *s));
-local void putShortMSB    OF((deflate_state *s, uInt b));
-local void flush_pending  OF((z_streamp strm));
-local int read_buf        OF((z_streamp strm, charf *buf, unsigned size));
-#ifdef ASMV
-      void match_init OF((void)); /* asm code initialization */
-      uInt longest_match  OF((deflate_state *s, IPos cur_match));
-#else
-local uInt longest_match  OF((deflate_state *s, IPos cur_match));
-#endif
-
-#ifdef DEBUG_ZLIB
-local  void check_match OF((deflate_state *s, IPos start, IPos match,
-                            int length));
-#endif
-
-/* ===========================================================================
- * Local data
- */
-
-#define NIL 0
-/* Tail of hash chains */
-
-#ifndef TOO_FAR
-#  define TOO_FAR 4096
-#endif
-/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-/* Values for max_lazy_match, good_match and max_chain_length, depending on
- * the desired pack level (0..9). The values given below have been tuned to
- * exclude worst case performance for pathological files. Better values may be
- * found for specific files.
- */
-typedef struct config_s {
-   ush good_length; /* reduce lazy search above this match length */
-   ush max_lazy;    /* do not perform lazy search above this match length */
-   ush nice_length; /* quit search above this match length */
-   ush max_chain;
-   compress_func func;
-} config;
-
-local config configuration_table[10] = {
-/*      good lazy nice chain */
-/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
-/* 1 */ {4,    4,  8,    4, deflate_fast}, /* maximum speed, no lazy matches */
-/* 2 */ {4,    5, 16,    8, deflate_fast},
-/* 3 */ {4,    6, 32,   32, deflate_fast},
-
-/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
-/* 5 */ {8,   16, 32,   32, deflate_slow},
-/* 6 */ {8,   16, 128, 128, deflate_slow},
-/* 7 */ {8,   32, 128, 256, deflate_slow},
-/* 8 */ {32, 128, 258, 1024, deflate_slow},
-/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
-
-/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
- * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
- * meaning.
- */
-
-#define EQUAL 0
-/* result of memcmp for equal strings */
-
-#ifndef NO_DUMMY_DECL
-struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
-#endif
-
-/* ===========================================================================
- * Update a hash value with the given input byte
- * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
- *    input characters, so that a running hash key can be computed from the
- *    previous key instead of complete recalculation each time.
- */
-#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
-
-
-/* ===========================================================================
- * Insert string str in the dictionary and set match_head to the previous head
- * of the hash chain (the most recent string with same hash key). Return
- * the previous length of the hash chain.
- * IN  assertion: all calls to to INSERT_STRING are made with consecutive
- *    input characters and the first MIN_MATCH bytes of str are valid
- *    (except for the last MIN_MATCH-1 bytes of the input file).
- */
-#define INSERT_STRING(s, str, match_head) \
-   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
-    s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
-    s->head[s->ins_h] = (Pos)(str))
-
-/* ===========================================================================
- * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
- * prev[] will be initialized on the fly.
- */
-#define CLEAR_HASH(s) \
-    s->head[s->hash_size-1] = NIL; \
-    zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
-
-/* ========================================================================= */
-int deflateInit_(strm, level, version, stream_size)
-    z_streamp strm;
-    int level;
-    const char *version;
-    int stream_size;
-{
-    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
-			 Z_DEFAULT_STRATEGY, version, stream_size);
-    /* To do: ignore strm->next_in if we use it as window */
-}
-
-/* ========================================================================= */
-int deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
-		  version, stream_size)
-    z_streamp strm;
-    int  level;
-    int  method;
-    int  windowBits;
-    int  memLevel;
-    int  strategy;
-    const char *version;
-    int stream_size;
-{
-    deflate_state *s;
-    int noheader = 0;
-    static char* my_version = ZLIB_VERSION;
-
-    ushf *overlay;
-    /* We overlay pending_buf and d_buf+l_buf. This works since the average
-     * output size for (length,distance) codes is <= 24 bits.
-     */
-
-    if (version == Z_NULL || version[0] != my_version[0] ||
-        stream_size != sizeof(z_stream)) {
-	return Z_VERSION_ERROR;
-    }
-    if (strm == Z_NULL) return Z_STREAM_ERROR;
-
-    strm->msg = Z_NULL;
-#ifndef NO_ZCFUNCS
-    if (strm->zalloc == Z_NULL) {
-	strm->zalloc = zcalloc;
-	strm->opaque = (voidpf)0;
-    }
-    if (strm->zfree == Z_NULL) strm->zfree = zcfree;
-#endif
-
-    if (level == Z_DEFAULT_COMPRESSION) level = 6;
-
-    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
-        noheader = 1;
-        windowBits = -windowBits;
-    }
-    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
-        windowBits < 9 || windowBits > 15 || level < 0 || level > 9 ||
-	strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
-        return Z_STREAM_ERROR;
-    }
-    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
-    if (s == Z_NULL) return Z_MEM_ERROR;
-    strm->state = (struct internal_state FAR *)s;
-    s->strm = strm;
-
-    s->noheader = noheader;
-    s->w_bits = windowBits;
-    s->w_size = 1 << s->w_bits;
-    s->w_mask = s->w_size - 1;
-
-    s->hash_bits = memLevel + 7;
-    s->hash_size = 1 << s->hash_bits;
-    s->hash_mask = s->hash_size - 1;
-    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
-
-    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
-    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
-    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
-
-    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
-
-    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
-    s->pending_buf = (uchf *) overlay;
-    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
-
-    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
-        s->pending_buf == Z_NULL) {
-        strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
-        deflateEnd (strm);
-        return Z_MEM_ERROR;
-    }
-    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
-    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
-
-    s->level = level;
-    s->strategy = strategy;
-    s->method = (Byte)method;
-
-    return deflateReset(strm);
-}
-
-/* ========================================================================= */
-int deflateSetDictionary (strm, dictionary, dictLength)
-    z_streamp strm;
-    const Bytef *dictionary;
-    uInt  dictLength;
-{
-    deflate_state *s;
-    uInt length = dictLength;
-    uInt n;
-    IPos hash_head = 0;
-
-    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
-	return Z_STREAM_ERROR;
-
-    s = (deflate_state *) strm->state;
-    if (s->status != INIT_STATE) return Z_STREAM_ERROR;
-
-    strm->adler = adler32(strm->adler, dictionary, dictLength);
-
-    if (length < MIN_MATCH) return Z_OK;
-    if (length > MAX_DIST(s)) {
-	length = MAX_DIST(s);
-#ifndef USE_DICT_HEAD
-	dictionary += dictLength - length; /* use the tail of the dictionary */
-#endif
-    }
-    zmemcpy((charf *)s->window, dictionary, length);
-    s->strstart = length;
-    s->block_start = (long)length;
-
-    /* Insert all strings in the hash table (except for the last two bytes).
-     * s->lookahead stays null, so s->ins_h will be recomputed at the next
-     * call of fill_window.
-     */
-    s->ins_h = s->window[0];
-    UPDATE_HASH(s, s->ins_h, s->window[1]);
-    for (n = 0; n <= length - MIN_MATCH; n++) {
-	INSERT_STRING(s, n, hash_head);
-    }
-    if (hash_head) hash_head = 0;  /* to make compiler happy */
-    return Z_OK;
-}
-
-/* ========================================================================= */
-int deflateReset (strm)
-    z_streamp strm;
-{
-    deflate_state *s;
-    
-    if (strm == Z_NULL || strm->state == Z_NULL ||
-        strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
-
-    strm->total_in = strm->total_out = 0;
-    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
-    strm->data_type = Z_UNKNOWN;
-
-    s = (deflate_state *)strm->state;
-    s->pending = 0;
-    s->pending_out = s->pending_buf;
-
-    if (s->noheader < 0) {
-        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
-    }
-    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
-    strm->adler = 1;
-    s->last_flush = Z_NO_FLUSH;
-
-    _tr_init(s);
-    lm_init(s);
-
-    return Z_OK;
-}
-
-/* ========================================================================= */
-int deflateParams(strm, level, strategy)
-    z_streamp strm;
-    int level;
-    int strategy;
-{
-    deflate_state *s;
-    compress_func func;
-    int err = Z_OK;
-
-    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
-    s = (deflate_state *) strm->state;
-
-    if (level == Z_DEFAULT_COMPRESSION) {
-	level = 6;
-    }
-    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
-	return Z_STREAM_ERROR;
-    }
-    func = configuration_table[s->level].func;
-
-    if (func != configuration_table[level].func && strm->total_in != 0) {
-	/* Flush the last buffer: */
-	err = deflate(strm, Z_PARTIAL_FLUSH);
-    }
-    if (s->level != level) {
-	s->level = level;
-	s->max_lazy_match   = configuration_table[level].max_lazy;
-	s->good_match       = configuration_table[level].good_length;
-	s->nice_match       = configuration_table[level].nice_length;
-	s->max_chain_length = configuration_table[level].max_chain;
-    }
-    s->strategy = strategy;
-    return err;
-}
-
-/* =========================================================================
- * Put a short in the pending buffer. The 16-bit value is put in MSB order.
- * IN assertion: the stream state is correct and there is enough room in
- * pending_buf.
- */
-local void putShortMSB (s, b)
-    deflate_state *s;
-    uInt b;
-{
-    put_byte(s, (Byte)(b >> 8));
-    put_byte(s, (Byte)(b & 0xff));
-}   
-
-/* =========================================================================
- * Flush as much pending output as possible. All deflate() output goes
- * through this function so some applications may wish to modify it
- * to avoid allocating a large strm->next_out buffer and copying into it.
- * (See also read_buf()).
- */
-local void flush_pending(strm)
-    z_streamp strm;
-{
-    deflate_state *s = (deflate_state *) strm->state;
-    unsigned len = s->pending;
-
-    if (len > strm->avail_out) len = strm->avail_out;
-    if (len == 0) return;
-
-    if (strm->next_out != Z_NULL) {
-	zmemcpy(strm->next_out, s->pending_out, len);
-	strm->next_out += len;
-    }
-    s->pending_out += len;
-    strm->total_out += len;
-    strm->avail_out  -= len;
-    s->pending -= len;
-    if (s->pending == 0) {
-        s->pending_out = s->pending_buf;
-    }
-}
-
-/* ========================================================================= */
-int deflate (strm, flush)
-    z_streamp strm;
-    int flush;
-{
-    int old_flush; /* value of flush param for previous deflate call */
-    deflate_state *s;
-
-    if (strm == Z_NULL || strm->state == Z_NULL ||
-	flush > Z_FINISH || flush < 0) {
-        return Z_STREAM_ERROR;
-    }
-    s = (deflate_state *) strm->state;
-
-    if ((strm->next_in == Z_NULL && strm->avail_in != 0) ||
-	(s->status == FINISH_STATE && flush != Z_FINISH)) {
-        ERR_RETURN(strm, Z_STREAM_ERROR);
-    }
-    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
-
-    s->strm = strm; /* just in case */
-    old_flush = s->last_flush;
-    s->last_flush = flush;
-
-    /* Write the zlib header */
-    if (s->status == INIT_STATE) {
-
-        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
-        uInt level_flags = (s->level-1) >> 1;
-
-        if (level_flags > 3) level_flags = 3;
-        header |= (level_flags << 6);
-	if (s->strstart != 0) header |= PRESET_DICT;
-        header += 31 - (header % 31);
-
-        s->status = BUSY_STATE;
-        putShortMSB(s, header);
-
-	/* Save the adler32 of the preset dictionary: */
-	if (s->strstart != 0) {
-	    putShortMSB(s, (uInt)(strm->adler >> 16));
-	    putShortMSB(s, (uInt)(strm->adler & 0xffff));
-	}
-	strm->adler = 1L;
-    }
-
-    /* Flush as much pending output as possible */
-    if (s->pending != 0) {
-        flush_pending(strm);
-        if (strm->avail_out == 0) {
-	    /* Since avail_out is 0, deflate will be called again with
-	     * more output space, but possibly with both pending and
-	     * avail_in equal to zero. There won't be anything to do,
-	     * but this is not an error situation so make sure we
-	     * return OK instead of BUF_ERROR at next call of deflate:
-             */
-	    s->last_flush = -1;
-	    return Z_OK;
-	}
-
-    /* Make sure there is something to do and avoid duplicate consecutive
-     * flushes. For repeated and useless calls with Z_FINISH, we keep
-     * returning Z_STREAM_END instead of Z_BUFF_ERROR.
-     */
-    } else if (strm->avail_in == 0 && flush <= old_flush &&
-	       flush != Z_FINISH) {
-        ERR_RETURN(strm, Z_BUF_ERROR);
-    }
-
-    /* User must not provide more input after the first FINISH: */
-    if (s->status == FINISH_STATE && strm->avail_in != 0) {
-        ERR_RETURN(strm, Z_BUF_ERROR);
-    }
-
-    /* Start a new block or continue the current one.
-     */
-    if (strm->avail_in != 0 || s->lookahead != 0 ||
-        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
-        block_state bstate;
-
-	bstate = (*(configuration_table[s->level].func))(s, flush);
-
-        if (bstate == finish_started || bstate == finish_done) {
-            s->status = FINISH_STATE;
-        }
-        if (bstate == need_more || bstate == finish_started) {
-	    if (strm->avail_out == 0) {
-	        s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
-	    }
-	    return Z_OK;
-	    /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
-	     * of deflate should use the same flush parameter to make sure
-	     * that the flush is complete. So we don't have to output an
-	     * empty block here, this will be done at next call. This also
-	     * ensures that for a very small output buffer, we emit at most
-	     * one empty block.
-	     */
-	}
-        if (bstate == block_done) {
-            if (flush == Z_PARTIAL_FLUSH) {
-                _tr_align(s);
-	    } else if (flush == Z_PACKET_FLUSH) {
-		/* Output just the 3-bit `stored' block type value,
-		   but not a zero length. */
-		_tr_stored_type_only(s);
-            } else { /* FULL_FLUSH or SYNC_FLUSH */
-                _tr_stored_block(s, (char*)0, 0L, 0);
-                /* For a full flush, this empty block will be recognized
-                 * as a special marker by inflate_sync().
-                 */
-                if (flush == Z_FULL_FLUSH) {
-                    CLEAR_HASH(s);             /* forget history */
-                }
-            }
-            flush_pending(strm);
-	    if (strm->avail_out == 0) {
-	      s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
-	      return Z_OK;
-	    }
-        }
-    }
-    Assert(strm->avail_out > 0, "bug2");
-
-    if (flush != Z_FINISH) return Z_OK;
-    if (s->noheader) return Z_STREAM_END;
-
-    /* Write the zlib trailer (adler32) */
-    putShortMSB(s, (uInt)(strm->adler >> 16));
-    putShortMSB(s, (uInt)(strm->adler & 0xffff));
-    flush_pending(strm);
-    /* If avail_out is zero, the application will call deflate again
-     * to flush the rest.
-     */
-    s->noheader = -1; /* write the trailer only once! */
-    return s->pending != 0 ? Z_OK : Z_STREAM_END;
-}
-
-/* ========================================================================= */
-int deflateEnd (strm)
-    z_streamp strm;
-{
-    int status;
-    deflate_state *s;
-
-    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
-    s = (deflate_state *) strm->state;
-
-    status = s->status;
-    if (status != INIT_STATE && status != BUSY_STATE &&
-	status != FINISH_STATE) {
-      return Z_STREAM_ERROR;
-    }
-
-    /* Deallocate in reverse order of allocations: */
-    TRY_FREE(strm, s->pending_buf);
-    TRY_FREE(strm, s->head);
-    TRY_FREE(strm, s->prev);
-    TRY_FREE(strm, s->window);
-
-    ZFREE(strm, s);
-    strm->state = Z_NULL;
-
-    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
-}
-
-/* =========================================================================
- * Copy the source state to the destination state.
- */
-int deflateCopy (dest, source)
-    z_streamp dest;
-    z_streamp source;
-{
-    deflate_state *ds;
-    deflate_state *ss;
-    ushf *overlay;
-
-    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL)
-        return Z_STREAM_ERROR;
-    ss = (deflate_state *) source->state;
-
-    *dest = *source;
-
-    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
-    if (ds == Z_NULL) return Z_MEM_ERROR;
-    dest->state = (struct internal_state FAR *) ds;
-    *ds = *ss;
-    ds->strm = dest;
-
-    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
-    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
-    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
-    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
-    ds->pending_buf = (uchf *) overlay;
-
-    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
-        ds->pending_buf == Z_NULL) {
-        deflateEnd (dest);
-        return Z_MEM_ERROR;
-    }
-    /* ??? following zmemcpy doesn't work for 16-bit MSDOS */
-    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
-    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
-    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
-    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
-
-    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
-    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
-    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
-
-    ds->l_desc.dyn_tree = ds->dyn_ltree;
-    ds->d_desc.dyn_tree = ds->dyn_dtree;
-    ds->bl_desc.dyn_tree = ds->bl_tree;
-
-    return Z_OK;
-}
-
-/* ===========================================================================
- * Return the number of bytes of output which are immediately available
- * for output from the decompressor.
- */
-int deflateOutputPending (strm)
-    z_streamp strm;
-{
-    if (strm == Z_NULL || strm->state == Z_NULL) return 0;
-    
-    return ((deflate_state *)(strm->state))->pending;
-}
-
-/* ===========================================================================
- * Read a new buffer from the current input stream, update the adler32
- * and total number of bytes read.  All deflate() input goes through
- * this function so some applications may wish to modify it to avoid
- * allocating a large strm->next_in buffer and copying from it.
- * (See also flush_pending()).
- */
-local int read_buf(strm, buf, size)
-    z_streamp strm;
-    charf *buf;
-    unsigned size;
-{
-    unsigned len = strm->avail_in;
-
-    if (len > size) len = size;
-    if (len == 0) return 0;
-
-    strm->avail_in  -= len;
-
-    if (!((deflate_state *)(strm->state))->noheader) {
-        strm->adler = adler32(strm->adler, strm->next_in, len);
-    }
-    zmemcpy(buf, strm->next_in, len);
-    strm->next_in  += len;
-    strm->total_in += len;
-
-    return (int)len;
-}
-
-/* ===========================================================================
- * Initialize the "longest match" routines for a new zlib stream
- */
-local void lm_init (s)
-    deflate_state *s;
-{
-    s->window_size = (ulg)2L*s->w_size;
-
-    CLEAR_HASH(s);
-
-    /* Set the default configuration parameters:
-     */
-    s->max_lazy_match   = configuration_table[s->level].max_lazy;
-    s->good_match       = configuration_table[s->level].good_length;
-    s->nice_match       = configuration_table[s->level].nice_length;
-    s->max_chain_length = configuration_table[s->level].max_chain;
-
-    s->strstart = 0;
-    s->block_start = 0L;
-    s->lookahead = 0;
-    s->match_length = s->prev_length = MIN_MATCH-1;
-    s->match_available = 0;
-    s->ins_h = 0;
-#ifdef ASMV
-    match_init(); /* initialize the asm code */
-#endif
-}
-
-/* ===========================================================================
- * Set match_start to the longest match starting at the given string and
- * return its length. Matches shorter or equal to prev_length are discarded,
- * in which case the result is equal to prev_length and match_start is
- * garbage.
- * IN assertions: cur_match is the head of the hash chain for the current
- *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
- * OUT assertion: the match length is not greater than s->lookahead.
- */
-#ifndef ASMV
-/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
- * match.S. The code will be functionally equivalent.
- */
-local uInt longest_match(s, cur_match)
-    deflate_state *s;
-    IPos cur_match;                             /* current match */
-{
-    unsigned chain_length = s->max_chain_length;/* max hash chain length */
-    register Bytef *scan = s->window + s->strstart; /* current string */
-    register Bytef *match;                       /* matched string */
-    register int len;                           /* length of current match */
-    int best_len = s->prev_length;              /* best match length so far */
-    int nice_match = s->nice_match;             /* stop if match long enough */
-    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
-        s->strstart - (IPos)MAX_DIST(s) : NIL;
-    /* Stop when cur_match becomes <= limit. To simplify the code,
-     * we prevent matches with the string of window index 0.
-     */
-    Posf *prev = s->prev;
-    uInt wmask = s->w_mask;
-
-#ifdef UNALIGNED_OK
-    /* Compare two bytes at a time. Note: this is not always beneficial.
-     * Try with and without -DUNALIGNED_OK to check.
-     */
-    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
-    register ush scan_start = *(ushf*)scan;
-    register ush scan_end   = *(ushf*)(scan+best_len-1);
-#else
-    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
-    register Byte scan_end1  = scan[best_len-1];
-    register Byte scan_end   = scan[best_len];
-#endif
-
-    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
-     * It is easy to get rid of this optimization if necessary.
-     */
-    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
-
-    /* Do not waste too much time if we already have a good match: */
-    if (s->prev_length >= s->good_match) {
-        chain_length >>= 2;
-    }
-    /* Do not look for matches beyond the end of the input. This is necessary
-     * to make deflate deterministic.
-     */
-    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
-
-    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
-
-    do {
-        Assert(cur_match < s->strstart, "no future");
-        match = s->window + cur_match;
-
-        /* Skip to next match if the match length cannot increase
-         * or if the match length is less than 2:
-         */
-#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
-        /* This code assumes sizeof(unsigned short) == 2. Do not use
-         * UNALIGNED_OK if your compiler uses a different size.
-         */
-        if (*(ushf*)(match+best_len-1) != scan_end ||
-            *(ushf*)match != scan_start) continue;
-
-        /* It is not necessary to compare scan[2] and match[2] since they are
-         * always equal when the other bytes match, given that the hash keys
-         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
-         * strstart+3, +5, ... up to strstart+257. We check for insufficient
-         * lookahead only every 4th comparison; the 128th check will be made
-         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
-         * necessary to put more guard bytes at the end of the window, or
-         * to check more often for insufficient lookahead.
-         */
-        Assert(scan[2] == match[2], "scan[2]?");
-        scan++, match++;
-        do {
-        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 scan < strend);
-        /* The funny "do {}" generates better code on most compilers */
-
-        /* Here, scan <= window+strstart+257 */
-        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-        if (*scan == *match) scan++;
-
-        len = (MAX_MATCH - 1) - (int)(strend-scan);
-        scan = strend - (MAX_MATCH-1);
-
-#else /* UNALIGNED_OK */
-
-        if (match[best_len]   != scan_end  ||
-            match[best_len-1] != scan_end1 ||
-            *match            != *scan     ||
-            *++match          != scan[1])      continue;
-
-        /* The check at best_len-1 can be removed because it will be made
-         * again later. (This heuristic is not always a win.)
-         * It is not necessary to compare scan[2] and match[2] since they
-         * are always equal when the other bytes match, given that
-         * the hash keys are equal and that HASH_BITS >= 8.
-         */
-        scan += 2, match++;
-        Assert(*scan == *match, "match[2]?");
-
-        /* We check for insufficient lookahead only every 8th comparison;
-         * the 256th check will be made at strstart+258.
-         */
-        do {
-        } while (*++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 scan < strend);
-
-        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-
-        len = MAX_MATCH - (int)(strend - scan);
-        scan = strend - MAX_MATCH;
-
-#endif /* UNALIGNED_OK */
-
-        if (len > best_len) {
-            s->match_start = cur_match;
-            best_len = len;
-            if (len >= nice_match) break;
-#ifdef UNALIGNED_OK
-            scan_end = *(ushf*)(scan+best_len-1);
-#else
-            scan_end1  = scan[best_len-1];
-            scan_end   = scan[best_len];
-#endif
-        }
-    } while ((cur_match = prev[cur_match & wmask]) > limit
-             && --chain_length != 0);
-
-    if ((uInt)best_len <= s->lookahead) return best_len;
-    return s->lookahead;
-}
-#endif /* ASMV */
-
-#ifdef DEBUG_ZLIB
-/* ===========================================================================
- * Check that the match at match_start is indeed a match.
- */
-local void check_match(s, start, match, length)
-    deflate_state *s;
-    IPos start, match;
-    int length;
-{
-    /* check that the match is indeed a match */
-    if (zmemcmp((charf *)s->window + match,
-                (charf *)s->window + start, length) != EQUAL) {
-        fprintf(stderr, " start %u, match %u, length %d\n",
-		start, match, length);
-        do {
-	    fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
-	} while (--length != 0);
-        z_error("invalid match");
-    }
-    if (z_verbose > 1) {
-        fprintf(stderr,"\\[%d,%d]", start-match, length);
-        do { putc(s->window[start++], stderr); } while (--length != 0);
-    }
-}
-#else
-#  define check_match(s, start, match, length)
-#endif
-
-/* ===========================================================================
- * Fill the window when the lookahead becomes insufficient.
- * Updates strstart and lookahead.
- *
- * IN assertion: lookahead < MIN_LOOKAHEAD
- * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
- *    At least one byte has been read, or avail_in == 0; reads are
- *    performed for at least two bytes (required for the zip translate_eol
- *    option -- not supported here).
- */
-local void fill_window(s)
-    deflate_state *s;
-{
-    register unsigned n, m;
-    register Posf *p;
-    unsigned more;    /* Amount of free space at the end of the window. */
-    uInt wsize = s->w_size;
-
-    do {
-        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
-
-        /* Deal with !@#$% 64K limit: */
-        if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
-            more = wsize;
-
-        } else if (more == (unsigned)(-1)) {
-            /* Very unlikely, but possible on 16 bit machine if strstart == 0
-             * and lookahead == 1 (input done one byte at time)
-             */
-            more--;
-
-        /* If the window is almost full and there is insufficient lookahead,
-         * move the upper half to the lower one to make room in the upper half.
-         */
-        } else if (s->strstart >= wsize+MAX_DIST(s)) {
-
-            zmemcpy((charf *)s->window, (charf *)s->window+wsize,
-                   (unsigned)wsize);
-            s->match_start -= wsize;
-            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
-            s->block_start -= (long) wsize;
-
-            /* Slide the hash table (could be avoided with 32 bit values
-               at the expense of memory usage). We slide even when level == 0
-               to keep the hash table consistent if we switch back to level > 0
-               later. (Using level 0 permanently is not an optimal usage of
-               zlib, so we don't care about this pathological case.)
-             */
-            n = s->hash_size;
-            p = &s->head[n];
-            do {
-                m = *--p;
-                *p = (Pos)(m >= wsize ? m-wsize : NIL);
-            } while (--n);
-
-            n = wsize;
-            p = &s->prev[n];
-            do {
-                m = *--p;
-                *p = (Pos)(m >= wsize ? m-wsize : NIL);
-                /* If n is not on any hash chain, prev[n] is garbage but
-                 * its value will never be used.
-                 */
-            } while (--n);
-            more += wsize;
-        }
-        if (s->strm->avail_in == 0) return;
-
-        /* If there was no sliding:
-         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
-         *    more == window_size - lookahead - strstart
-         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
-         * => more >= window_size - 2*WSIZE + 2
-         * In the BIG_MEM or MMAP case (not yet supported),
-         *   window_size == input_size + MIN_LOOKAHEAD  &&
-         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
-         * Otherwise, window_size == 2*WSIZE so more >= 2.
-         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
-         */
-        Assert(more >= 2, "more < 2");
-
-        n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead,
-                     more);
-        s->lookahead += n;
-
-        /* Initialize the hash value now that we have some input: */
-        if (s->lookahead >= MIN_MATCH) {
-            s->ins_h = s->window[s->strstart];
-            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
-#if MIN_MATCH != 3
-            Call UPDATE_HASH() MIN_MATCH-3 more times
-#endif
-        }
-        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
-         * but this is not important since only literal bytes will be emitted.
-         */
-
-    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
-}
-
-/* ===========================================================================
- * Flush the current block, with given end-of-file flag.
- * IN assertion: strstart is set to the end of the current match.
- */
-#define FLUSH_BLOCK_ONLY(s, eof) { \
-   _tr_flush_block(s, (s->block_start >= 0L ? \
-                   (charf *)&s->window[(unsigned)s->block_start] : \
-                   (charf *)Z_NULL), \
-		(ulg)((long)s->strstart - s->block_start), \
-		(eof)); \
-   s->block_start = s->strstart; \
-   flush_pending(s->strm); \
-   Tracev((stderr,"[FLUSH]")); \
-}
-
-/* Same but force premature exit if necessary. */
-#define FLUSH_BLOCK(s, eof) { \
-   FLUSH_BLOCK_ONLY(s, eof); \
-   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
-}
-
-/* ===========================================================================
- * Copy without compression as much as possible from the input stream, return
- * the current block state.
- * This function does not insert new strings in the dictionary since
- * uncompressible data is probably not useful. This function is used
- * only for the level=0 compression option.
- * NOTE: this function should be optimized to avoid extra copying from
- * window to pending_buf.
- */
-local block_state deflate_stored(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
-     * to pending_buf_size, and each stored block has a 5 byte header:
-     */
-    ulg max_block_size = 0xffff;
-    ulg max_start;
-
-    if (max_block_size > s->pending_buf_size - 5) {
-        max_block_size = s->pending_buf_size - 5;
-    }
-
-    /* Copy as much as possible from input to output: */
-    for (;;) {
-        /* Fill the window as much as possible: */
-        if (s->lookahead <= 1) {
-
-            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
-		   s->block_start >= (long)s->w_size, "slide too late");
-
-            fill_window(s);
-            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
-
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-	Assert(s->block_start >= 0L, "block gone");
-
-	s->strstart += s->lookahead;
-	s->lookahead = 0;
-
-	/* Emit a stored block if pending_buf will be full: */
- 	max_start = s->block_start + max_block_size;
-        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
-	    /* strstart == 0 is possible when wraparound on 16-bit machine */
-	    s->lookahead = (uInt)(s->strstart - max_start);
-	    s->strstart = (uInt)max_start;
-            FLUSH_BLOCK(s, 0);
-	}
-	/* Flush if we may have to slide, otherwise block_start may become
-         * negative and the data will be gone:
-         */
-        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
-            FLUSH_BLOCK(s, 0);
-	}
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-
-/* ===========================================================================
- * Compress as much as possible from the input stream, return the current
- * block state.
- * This function does not perform lazy evaluation of matches and inserts
- * new strings in the dictionary only for unmatched strings or for short
- * matches. It is used only for the fast compression options.
- */
-local block_state deflate_fast(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    IPos hash_head = NIL; /* head of the hash chain */
-    int bflush;           /* set if current block must be flushed */
-
-    for (;;) {
-        /* Make sure that we always have enough lookahead, except
-         * at the end of the input file. We need MAX_MATCH bytes
-         * for the next match, plus MIN_MATCH bytes to insert the
-         * string following the next match.
-         */
-        if (s->lookahead < MIN_LOOKAHEAD) {
-            fill_window(s);
-            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
-	        return need_more;
-	    }
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-
-        /* Insert the string window[strstart .. strstart+2] in the
-         * dictionary, and set hash_head to the head of the hash chain:
-         */
-        if (s->lookahead >= MIN_MATCH) {
-            INSERT_STRING(s, s->strstart, hash_head);
-        }
-
-        /* Find the longest match, discarding those <= prev_length.
-         * At this point we have always match_length < MIN_MATCH
-         */
-        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
-            /* To simplify the code, we prevent matches with the string
-             * of window index 0 (in particular we have to avoid a match
-             * of the string with itself at the start of the input file).
-             */
-            if (s->strategy != Z_HUFFMAN_ONLY) {
-                s->match_length = longest_match (s, hash_head);
-            }
-            /* longest_match() sets match_start */
-        }
-        if (s->match_length >= MIN_MATCH) {
-            check_match(s, s->strstart, s->match_start, s->match_length);
-
-            bflush = _tr_tally(s, s->strstart - s->match_start,
-                               s->match_length - MIN_MATCH);
-
-            s->lookahead -= s->match_length;
-
-            /* Insert new strings in the hash table only if the match length
-             * is not too large. This saves time but degrades compression.
-             */
-            if (s->match_length <= s->max_insert_length &&
-                s->lookahead >= MIN_MATCH) {
-                s->match_length--; /* string at strstart already in hash table */
-                do {
-                    s->strstart++;
-                    INSERT_STRING(s, s->strstart, hash_head);
-                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
-                     * always MIN_MATCH bytes ahead.
-                     */
-                } while (--s->match_length != 0);
-                s->strstart++; 
-            } else {
-                s->strstart += s->match_length;
-                s->match_length = 0;
-                s->ins_h = s->window[s->strstart];
-                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
-#if MIN_MATCH != 3
-                Call UPDATE_HASH() MIN_MATCH-3 more times
-#endif
-                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
-                 * matter since it will be recomputed at next deflate call.
-                 */
-            }
-        } else {
-            /* No match, output a literal byte */
-            Tracevv((stderr,"%c", s->window[s->strstart]));
-            bflush = _tr_tally (s, 0, s->window[s->strstart]);
-            s->lookahead--;
-            s->strstart++; 
-        }
-        if (bflush) FLUSH_BLOCK(s, 0);
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-
-/* ===========================================================================
- * Same as above, but achieves better compression. We use a lazy
- * evaluation for matches: a match is finally adopted only if there is
- * no better match at the next window position.
- */
-local block_state deflate_slow(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    IPos hash_head = NIL;    /* head of hash chain */
-    int bflush;              /* set if current block must be flushed */
-
-    /* Process the input block. */
-    for (;;) {
-        /* Make sure that we always have enough lookahead, except
-         * at the end of the input file. We need MAX_MATCH bytes
-         * for the next match, plus MIN_MATCH bytes to insert the
-         * string following the next match.
-         */
-        if (s->lookahead < MIN_LOOKAHEAD) {
-            fill_window(s);
-            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
-	        return need_more;
-	    }
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-
-        /* Insert the string window[strstart .. strstart+2] in the
-         * dictionary, and set hash_head to the head of the hash chain:
-         */
-        if (s->lookahead >= MIN_MATCH) {
-            INSERT_STRING(s, s->strstart, hash_head);
-        }
-
-        /* Find the longest match, discarding those <= prev_length.
-         */
-        s->prev_length = s->match_length, s->prev_match = s->match_start;
-        s->match_length = MIN_MATCH-1;
-
-        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
-            s->strstart - hash_head <= MAX_DIST(s)) {
-            /* To simplify the code, we prevent matches with the string
-             * of window index 0 (in particular we have to avoid a match
-             * of the string with itself at the start of the input file).
-             */
-            if (s->strategy != Z_HUFFMAN_ONLY) {
-                s->match_length = longest_match (s, hash_head);
-            }
-            /* longest_match() sets match_start */
-
-            if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
-                 (s->match_length == MIN_MATCH &&
-                  s->strstart - s->match_start > TOO_FAR))) {
-
-                /* If prev_match is also MIN_MATCH, match_start is garbage
-                 * but we will ignore the current match anyway.
-                 */
-                s->match_length = MIN_MATCH-1;
-            }
-        }
-        /* If there was a match at the previous step and the current
-         * match is not better, output the previous match:
-         */
-        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
-            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
-            /* Do not insert strings in hash table beyond this. */
-
-            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
-
-            bflush = _tr_tally(s, s->strstart -1 - s->prev_match,
-                               s->prev_length - MIN_MATCH);
-
-            /* Insert in hash table all strings up to the end of the match.
-             * strstart-1 and strstart are already inserted. If there is not
-             * enough lookahead, the last two strings are not inserted in
-             * the hash table.
-             */
-            s->lookahead -= s->prev_length-1;
-            s->prev_length -= 2;
-            do {
-                if (++s->strstart <= max_insert) {
-                    INSERT_STRING(s, s->strstart, hash_head);
-                }
-            } while (--s->prev_length != 0);
-            s->match_available = 0;
-            s->match_length = MIN_MATCH-1;
-            s->strstart++;
-
-            if (bflush) FLUSH_BLOCK(s, 0);
-
-        } else if (s->match_available) {
-            /* If there was no match at the previous position, output a
-             * single literal. If there was a match but the current match
-             * is longer, truncate the previous match to a single literal.
-             */
-            Tracevv((stderr,"%c", s->window[s->strstart-1]));
-            if (_tr_tally (s, 0, s->window[s->strstart-1])) {
-                FLUSH_BLOCK_ONLY(s, 0);
-            }
-            s->strstart++;
-            s->lookahead--;
-            if (s->strm->avail_out == 0) return need_more;
-        } else {
-            /* There is no previous match to compare with, wait for
-             * the next step to decide.
-             */
-            s->match_available = 1;
-            s->strstart++;
-            s->lookahead--;
-        }
-    }
-    Assert (flush != Z_NO_FLUSH, "no flush?");
-    if (s->match_available) {
-        Tracevv((stderr,"%c", s->window[s->strstart-1]));
-        _tr_tally (s, 0, s->window[s->strstart-1]);
-        s->match_available = 0;
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-/* --- deflate.c */
-
-/* +++ trees.c */
-/* trees.c -- output deflated data using Huffman coding
- * Copyright (C) 1995-1996 Jean-loup Gailly
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/*
- *  ALGORITHM
- *
- *      The "deflation" process uses several Huffman trees. The more
- *      common source values are represented by shorter bit sequences.
- *
- *      Each code tree is stored in a compressed form which is itself
- * a Huffman encoding of the lengths of all the code strings (in
- * ascending order by source values).  The actual code strings are
- * reconstructed from the lengths in the inflate process, as described
- * in the deflate specification.
- *
- *  REFERENCES
- *
- *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
- *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
- *
- *      Storer, James A.
- *          Data Compression:  Methods and Theory, pp. 49-50.
- *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
- *
- *      Sedgewick, R.
- *          Algorithms, p290.
- *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
- */
-
-/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */
-
-/* #include "deflate.h" */
-
-#ifdef DEBUG_ZLIB
-#  include <ctype.h>
-#endif
-
-/* ===========================================================================
- * Constants
- */
-
-#define MAX_BL_BITS 7
-/* Bit length codes must not exceed MAX_BL_BITS bits */
-
-#define END_BLOCK 256
-/* end of block literal code */
-
-#define REP_3_6      16
-/* repeat previous bit length 3-6 times (2 bits of repeat count) */
-
-#define REPZ_3_10    17
-/* repeat a zero length 3-10 times  (3 bits of repeat count) */
-
-#define REPZ_11_138  18
-/* repeat a zero length 11-138 times  (7 bits of repeat count) */
-
-local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
-   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
-
-local int extra_dbits[D_CODES] /* extra bits for each distance code */
-   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
-
-local int extra_blbits[BL_CODES]/* extra bits for each bit length code */
-   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
-
-local uch bl_order[BL_CODES]
-   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
-/* The lengths of the bit length codes are sent in order of decreasing
- * probability, to avoid transmitting the lengths for unused bit length codes.
- */
-
-#define Buf_size (8 * 2*sizeof(char))
-/* Number of bits used within bi_buf. (bi_buf might be implemented on
- * more than 16 bits on some systems.)
- */
-
-/* ===========================================================================
- * Local data. These are initialized only once.
- */
-
-local ct_data static_ltree[L_CODES+2];
-/* The static literal tree. Since the bit lengths are imposed, there is no
- * need for the L_CODES extra codes used during heap construction. However
- * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
- * below).
- */
-
-local ct_data static_dtree[D_CODES];
-/* The static distance tree. (Actually a trivial tree since all codes use
- * 5 bits.)
- */
-
-local uch dist_code[512];
-/* distance codes. The first 256 values correspond to the distances
- * 3 .. 258, the last 256 values correspond to the top 8 bits of
- * the 15 bit distances.
- */
-
-local uch length_code[MAX_MATCH-MIN_MATCH+1];
-/* length code for each normalized match length (0 == MIN_MATCH) */
-
-local int base_length[LENGTH_CODES];
-/* First normalized length for each code (0 = MIN_MATCH) */
-
-local int base_dist[D_CODES];
-/* First normalized distance for each code (0 = distance of 1) */
-
-struct static_tree_desc_s {
-    ct_data *static_tree;        /* static tree or NULL */
-    intf    *extra_bits;         /* extra bits for each code or NULL */
-    int     extra_base;          /* base index for extra_bits */
-    int     elems;               /* max number of elements in the tree */
-    int     max_length;          /* max bit length for the codes */
-};
-
-local static_tree_desc  static_l_desc =
-{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
-
-local static_tree_desc  static_d_desc =
-{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
-
-local static_tree_desc  static_bl_desc =
-{(ct_data *)0, extra_blbits, 0,      BL_CODES, MAX_BL_BITS};
-
-/* ===========================================================================
- * Local (static) routines in this file.
- */
-
-local void tr_static_init OF((void));
-local void init_block     OF((deflate_state *s));
-local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
-local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
-local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
-local void build_tree     OF((deflate_state *s, tree_desc *desc));
-local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
-local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
-local int  build_bl_tree  OF((deflate_state *s));
-local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
-                              int blcodes));
-local void compress_block OF((deflate_state *s, ct_data *ltree,
-                              ct_data *dtree));
-local void set_data_type  OF((deflate_state *s));
-local unsigned bi_reverse OF((unsigned value, int length));
-local void bi_windup      OF((deflate_state *s));
-local void bi_flush       OF((deflate_state *s));
-local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
-                              int header));
-
-#ifndef DEBUG_ZLIB
-#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
-   /* Send a code of the given tree. c and tree must not have side effects */
-
-#else /* DEBUG_ZLIB */
-#  define send_code(s, c, tree) \
-     { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
-       send_bits(s, tree[c].Code, tree[c].Len); }
-#endif
-
-#define d_code(dist) \
-   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
-/* Mapping from a distance to a distance code. dist is the distance - 1 and
- * must not have side effects. dist_code[256] and dist_code[257] are never
- * used.
- */
-
-/* ===========================================================================
- * Output a short LSB first on the stream.
- * IN assertion: there is enough room in pendingBuf.
- */
-#define put_short(s, w) { \
-    put_byte(s, (uch)((w) & 0xff)); \
-    put_byte(s, (uch)((ush)(w) >> 8)); \
-}
-
-/* ===========================================================================
- * Send a value on a given number of bits.
- * IN assertion: length <= 16 and value fits in length bits.
- */
-#ifdef DEBUG_ZLIB
-local void send_bits      OF((deflate_state *s, int value, int length));
-
-local void send_bits(s, value, length)
-    deflate_state *s;
-    int value;  /* value to send */
-    int length; /* number of bits */
-{
-    Tracevv((stderr," l %2d v %4x ", length, value));
-    Assert(length > 0 && length <= 15, "invalid length");
-    s->bits_sent += (ulg)length;
-
-    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
-     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
-     * unused bits in value.
-     */
-    if (s->bi_valid > (int)Buf_size - length) {
-        s->bi_buf |= (value << s->bi_valid);
-        put_short(s, s->bi_buf);
-        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
-        s->bi_valid += length - Buf_size;
-    } else {
-        s->bi_buf |= value << s->bi_valid;
-        s->bi_valid += length;
-    }
-}
-#else /* !DEBUG_ZLIB */
-
-#define send_bits(s, value, length) \
-{ int len = length;\
-  if (s->bi_valid > (int)Buf_size - len) {\
-    int val = value;\
-    s->bi_buf |= (val << s->bi_valid);\
-    put_short(s, s->bi_buf);\
-    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
-    s->bi_valid += len - Buf_size;\
-  } else {\
-    s->bi_buf |= (value) << s->bi_valid;\
-    s->bi_valid += len;\
-  }\
-}
-#endif /* DEBUG_ZLIB */
-
-
-#define MAX(a,b) (a >= b ? a : b)
-/* the arguments must not have side effects */
-
-/* ===========================================================================
- * Initialize the various 'constant' tables. In a multi-threaded environment,
- * this function may be called by two threads concurrently, but this is
- * harmless since both invocations do exactly the same thing.
- */
-local void tr_static_init()
-{
-    static int static_init_done = 0;
-    int n;        /* iterates over tree elements */
-    int bits;     /* bit counter */
-    int length;   /* length value */
-    int code;     /* code value */
-    int dist;     /* distance index */
-    ush bl_count[MAX_BITS+1];
-    /* number of codes at each bit length for an optimal tree */
-
-    if (static_init_done) return;
-
-    /* Initialize the mapping length (0..255) -> length code (0..28) */
-    length = 0;
-    for (code = 0; code < LENGTH_CODES-1; code++) {
-        base_length[code] = length;
-        for (n = 0; n < (1<<extra_lbits[code]); n++) {
-            length_code[length++] = (uch)code;
-        }
-    }
-    Assert (length == 256, "tr_static_init: length != 256");
-    /* Note that the length 255 (match length 258) can be represented
-     * in two different ways: code 284 + 5 bits or code 285, so we
-     * overwrite length_code[255] to use the best encoding:
-     */
-    length_code[length-1] = (uch)code;
-
-    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
-    dist = 0;
-    for (code = 0 ; code < 16; code++) {
-        base_dist[code] = dist;
-        for (n = 0; n < (1<<extra_dbits[code]); n++) {
-            dist_code[dist++] = (uch)code;
-        }
-    }
-    Assert (dist == 256, "tr_static_init: dist != 256");
-    dist >>= 7; /* from now on, all distances are divided by 128 */
-    for ( ; code < D_CODES; code++) {
-        base_dist[code] = dist << 7;
-        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
-            dist_code[256 + dist++] = (uch)code;
-        }
-    }
-    Assert (dist == 256, "tr_static_init: 256+dist != 512");
-
-    /* Construct the codes of the static literal tree */
-    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
-    n = 0;
-    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
-    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
-    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
-    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
-    /* Codes 286 and 287 do not exist, but we must include them in the
-     * tree construction to get a canonical Huffman tree (longest code
-     * all ones)
-     */
-    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
-
-    /* The static distance tree is trivial: */
-    for (n = 0; n < D_CODES; n++) {
-        static_dtree[n].Len = 5;
-        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
-    }
-    static_init_done = 1;
-}
-
-/* ===========================================================================
- * Initialize the tree data structures for a new zlib stream.
- */
-void _tr_init(s)
-    deflate_state *s;
-{
-    tr_static_init();
-
-    s->compressed_len = 0L;
-
-    s->l_desc.dyn_tree = s->dyn_ltree;
-    s->l_desc.stat_desc = &static_l_desc;
-
-    s->d_desc.dyn_tree = s->dyn_dtree;
-    s->d_desc.stat_desc = &static_d_desc;
-
-    s->bl_desc.dyn_tree = s->bl_tree;
-    s->bl_desc.stat_desc = &static_bl_desc;
-
-    s->bi_buf = 0;
-    s->bi_valid = 0;
-    s->last_eob_len = 8; /* enough lookahead for inflate */
-#ifdef DEBUG_ZLIB
-    s->bits_sent = 0L;
-#endif
-
-    /* Initialize the first block of the first file: */
-    init_block(s);
-}
-
-/* ===========================================================================
- * Initialize a new block.
- */
-local void init_block(s)
-    deflate_state *s;
-{
-    int n; /* iterates over tree elements */
-
-    /* Initialize the trees. */
-    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
-    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
-    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
-
-    s->dyn_ltree[END_BLOCK].Freq = 1;
-    s->opt_len = s->static_len = 0L;
-    s->last_lit = s->matches = 0;
-}
-
-#define SMALLEST 1
-/* Index within the heap array of least frequent node in the Huffman tree */
-
-
-/* ===========================================================================
- * Remove the smallest element from the heap and recreate the heap with
- * one less element. Updates heap and heap_len.
- */
-#define pqremove(s, tree, top) \
-{\
-    top = s->heap[SMALLEST]; \
-    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
-    pqdownheap(s, tree, SMALLEST); \
-}
-
-/* ===========================================================================
- * Compares to subtrees, using the tree depth as tie breaker when
- * the subtrees have equal frequency. This minimizes the worst case length.
- */
-#define smaller(tree, n, m, depth) \
-   (tree[n].Freq < tree[m].Freq || \
-   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
-
-/* ===========================================================================
- * Restore the heap property by moving down the tree starting at node k,
- * exchanging a node with the smallest of its two sons if necessary, stopping
- * when the heap property is re-established (each father smaller than its
- * two sons).
- */
-local void pqdownheap(s, tree, k)
-    deflate_state *s;
-    ct_data *tree;  /* the tree to restore */
-    int k;               /* node to move down */
-{
-    int v = s->heap[k];
-    int j = k << 1;  /* left son of k */
-    while (j <= s->heap_len) {
-        /* Set j to the smallest of the two sons: */
-        if (j < s->heap_len &&
-            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
-            j++;
-        }
-        /* Exit if v is smaller than both sons */
-        if (smaller(tree, v, s->heap[j], s->depth)) break;
-
-        /* Exchange v with the smallest son */
-        s->heap[k] = s->heap[j];  k = j;
-
-        /* And continue down the tree, setting j to the left son of k */
-        j <<= 1;
-    }
-    s->heap[k] = v;
-}
-
-/* ===========================================================================
- * Compute the optimal bit lengths for a tree and update the total bit length
- * for the current block.
- * IN assertion: the fields freq and dad are set, heap[heap_max] and
- *    above are the tree nodes sorted by increasing frequency.
- * OUT assertions: the field len is set to the optimal bit length, the
- *     array bl_count contains the frequencies for each bit length.
- *     The length opt_len is updated; static_len is also updated if stree is
- *     not null.
- */
-local void gen_bitlen(s, desc)
-    deflate_state *s;
-    tree_desc *desc;    /* the tree descriptor */
-{
-    ct_data *tree  = desc->dyn_tree;
-    int max_code   = desc->max_code;
-    ct_data *stree = desc->stat_desc->static_tree;
-    intf *extra    = desc->stat_desc->extra_bits;
-    int base       = desc->stat_desc->extra_base;
-    int max_length = desc->stat_desc->max_length;
-    int h;              /* heap index */
-    int n, m;           /* iterate over the tree elements */
-    int bits;           /* bit length */
-    int xbits;          /* extra bits */
-    ush f;              /* frequency */
-    int overflow = 0;   /* number of elements with bit length too large */
-
-    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
-
-    /* In a first pass, compute the optimal bit lengths (which may
-     * overflow in the case of the bit length tree).
-     */
-    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
-
-    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
-        n = s->heap[h];
-        bits = tree[tree[n].Dad].Len + 1;
-        if (bits > max_length) bits = max_length, overflow++;
-        tree[n].Len = (ush)bits;
-        /* We overwrite tree[n].Dad which is no longer needed */
-
-        if (n > max_code) continue; /* not a leaf node */
-
-        s->bl_count[bits]++;
-        xbits = 0;
-        if (n >= base) xbits = extra[n-base];
-        f = tree[n].Freq;
-        s->opt_len += (ulg)f * (bits + xbits);
-        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
-    }
-    if (overflow == 0) return;
-
-    Trace((stderr,"\nbit length overflow\n"));
-    /* This happens for example on obj2 and pic of the Calgary corpus */
-
-    /* Find the first bit length which could increase: */
-    do {
-        bits = max_length-1;
-        while (s->bl_count[bits] == 0) bits--;
-        s->bl_count[bits]--;      /* move one leaf down the tree */
-        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
-        s->bl_count[max_length]--;
-        /* The brother of the overflow item also moves one step up,
-         * but this does not affect bl_count[max_length]
-         */
-        overflow -= 2;
-    } while (overflow > 0);
-
-    /* Now recompute all bit lengths, scanning in increasing frequency.
-     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
-     * lengths instead of fixing only the wrong ones. This idea is taken
-     * from 'ar' written by Haruhiko Okumura.)
-     */
-    for (bits = max_length; bits != 0; bits--) {
-        n = s->bl_count[bits];
-        while (n != 0) {
-            m = s->heap[--h];
-            if (m > max_code) continue;
-            if (tree[m].Len != (unsigned) bits) {
-                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
-                s->opt_len += ((long)bits - (long)tree[m].Len)
-                              *(long)tree[m].Freq;
-                tree[m].Len = (ush)bits;
-            }
-            n--;
-        }
-    }
-}
-
-/* ===========================================================================
- * Generate the codes for a given tree and bit counts (which need not be
- * optimal).
- * IN assertion: the array bl_count contains the bit length statistics for
- * the given tree and the field len is set for all tree elements.
- * OUT assertion: the field code is set for all tree elements of non
- *     zero code length.
- */
-local void gen_codes (tree, max_code, bl_count)
-    ct_data *tree;             /* the tree to decorate */
-    int max_code;              /* largest code with non zero frequency */
-    ushf *bl_count;            /* number of codes at each bit length */
-{
-    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
-    ush code = 0;              /* running code value */
-    int bits;                  /* bit index */
-    int n;                     /* code index */
-
-    /* The distribution counts are first used to generate the code values
-     * without bit reversal.
-     */
-    for (bits = 1; bits <= MAX_BITS; bits++) {
-        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
-    }
-    /* Check that the bit counts in bl_count are consistent. The last code
-     * must be all ones.
-     */
-    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
-            "inconsistent bit counts");
-    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
-
-    for (n = 0;  n <= max_code; n++) {
-        int len = tree[n].Len;
-        if (len == 0) continue;
-        /* Now reverse the bits */
-        tree[n].Code = bi_reverse(next_code[len]++, len);
-
-        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
-             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
-    }
-}
-
-/* ===========================================================================
- * Construct one Huffman tree and assigns the code bit strings and lengths.
- * Update the total bit length for the current block.
- * IN assertion: the field freq is set for all tree elements.
- * OUT assertions: the fields len and code are set to the optimal bit length
- *     and corresponding code. The length opt_len is updated; static_len is
- *     also updated if stree is not null. The field max_code is set.
- */
-local void build_tree(s, desc)
-    deflate_state *s;
-    tree_desc *desc; /* the tree descriptor */
-{
-    ct_data *tree   = desc->dyn_tree;
-    ct_data *stree  = desc->stat_desc->static_tree;
-    int elems       = desc->stat_desc->elems;
-    int n, m;          /* iterate over heap elements */
-    int max_code = -1; /* largest code with non zero frequency */
-    int node;          /* new node being created */
-
-    /* Construct the initial heap, with least frequent element in
-     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
-     * heap[0] is not used.
-     */
-    s->heap_len = 0, s->heap_max = HEAP_SIZE;
-
-    for (n = 0; n < elems; n++) {
-        if (tree[n].Freq != 0) {
-            s->heap[++(s->heap_len)] = max_code = n;
-            s->depth[n] = 0;
-        } else {
-            tree[n].Len = 0;
-        }
-    }
-
-    /* The pkzip format requires that at least one distance code exists,
-     * and that at least one bit should be sent even if there is only one
-     * possible code. So to avoid special checks later on we force at least
-     * two codes of non zero frequency.
-     */
-    while (s->heap_len < 2) {
-        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
-        tree[node].Freq = 1;
-        s->depth[node] = 0;
-        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
-        /* node is 0 or 1 so it does not have extra bits */
-    }
-    desc->max_code = max_code;
-
-    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
-     * establish sub-heaps of increasing lengths:
-     */
-    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
-
-    /* Construct the Huffman tree by repeatedly combining the least two
-     * frequent nodes.
-     */
-    node = elems;              /* next internal node of the tree */
-    do {
-        pqremove(s, tree, n);  /* n = node of least frequency */
-        m = s->heap[SMALLEST]; /* m = node of next least frequency */
-
-        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
-        s->heap[--(s->heap_max)] = m;
-
-        /* Create a new node father of n and m */
-        tree[node].Freq = tree[n].Freq + tree[m].Freq;
-        s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
-        tree[n].Dad = tree[m].Dad = (ush)node;
-#ifdef DUMP_BL_TREE
-        if (tree == s->bl_tree) {
-            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
-                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
-        }
-#endif
-        /* and insert the new node in the heap */
-        s->heap[SMALLEST] = node++;
-        pqdownheap(s, tree, SMALLEST);
-
-    } while (s->heap_len >= 2);
-
-    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
-
-    /* At this point, the fields freq and dad are set. We can now
-     * generate the bit lengths.
-     */
-    gen_bitlen(s, (tree_desc *)desc);
-
-    /* The field len is now set, we can generate the bit codes */
-    gen_codes ((ct_data *)tree, max_code, s->bl_count);
-}
-
-/* ===========================================================================
- * Scan a literal or distance tree to determine the frequencies of the codes
- * in the bit length tree.
- */
-local void scan_tree (s, tree, max_code)
-    deflate_state *s;
-    ct_data *tree;   /* the tree to be scanned */
-    int max_code;    /* and its largest code of non zero frequency */
-{
-    int n;                     /* iterates over all tree elements */
-    int prevlen = -1;          /* last emitted length */
-    int curlen;                /* length of current code */
-    int nextlen = tree[0].Len; /* length of next code */
-    int count = 0;             /* repeat count of the current code */
-    int max_count = 7;         /* max repeat count */
-    int min_count = 4;         /* min repeat count */
-
-    if (nextlen == 0) max_count = 138, min_count = 3;
-    tree[max_code+1].Len = (ush)0xffff; /* guard */
-
-    for (n = 0; n <= max_code; n++) {
-        curlen = nextlen; nextlen = tree[n+1].Len;
-        if (++count < max_count && curlen == nextlen) {
-            continue;
-        } else if (count < min_count) {
-            s->bl_tree[curlen].Freq += count;
-        } else if (curlen != 0) {
-            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
-            s->bl_tree[REP_3_6].Freq++;
-        } else if (count <= 10) {
-            s->bl_tree[REPZ_3_10].Freq++;
-        } else {
-            s->bl_tree[REPZ_11_138].Freq++;
-        }
-        count = 0; prevlen = curlen;
-        if (nextlen == 0) {
-            max_count = 138, min_count = 3;
-        } else if (curlen == nextlen) {
-            max_count = 6, min_count = 3;
-        } else {
-            max_count = 7, min_count = 4;
-        }
-    }
-}
-
-/* ===========================================================================
- * Send a literal or distance tree in compressed form, using the codes in
- * bl_tree.
- */
-local void send_tree (s, tree, max_code)
-    deflate_state *s;
-    ct_data *tree; /* the tree to be scanned */
-    int max_code;       /* and its largest code of non zero frequency */
-{
-    int n;                     /* iterates over all tree elements */
-    int prevlen = -1;          /* last emitted length */
-    int curlen;                /* length of current code */
-    int nextlen = tree[0].Len; /* length of next code */
-    int count = 0;             /* repeat count of the current code */
-    int max_count = 7;         /* max repeat count */
-    int min_count = 4;         /* min repeat count */
-
-    /* tree[max_code+1].Len = -1; */  /* guard already set */
-    if (nextlen == 0) max_count = 138, min_count = 3;
-
-    for (n = 0; n <= max_code; n++) {
-        curlen = nextlen; nextlen = tree[n+1].Len;
-        if (++count < max_count && curlen == nextlen) {
-            continue;
-        } else if (count < min_count) {
-            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
-
-        } else if (curlen != 0) {
-            if (curlen != prevlen) {
-                send_code(s, curlen, s->bl_tree); count--;
-            }
-            Assert(count >= 3 && count <= 6, " 3_6?");
-            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
-
-        } else if (count <= 10) {
-            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
-
-        } else {
-            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
-        }
-        count = 0; prevlen = curlen;
-        if (nextlen == 0) {
-            max_count = 138, min_count = 3;
-        } else if (curlen == nextlen) {
-            max_count = 6, min_count = 3;
-        } else {
-            max_count = 7, min_count = 4;
-        }
-    }
-}
-
-/* ===========================================================================
- * Construct the Huffman tree for the bit lengths and return the index in
- * bl_order of the last bit length code to send.
- */
-local int build_bl_tree(s)
-    deflate_state *s;
-{
-    int max_blindex;  /* index of last bit length code of non zero freq */
-
-    /* Determine the bit length frequencies for literal and distance trees */
-    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
-    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
-
-    /* Build the bit length tree: */
-    build_tree(s, (tree_desc *)(&(s->bl_desc)));
-    /* opt_len now includes the length of the tree representations, except
-     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
-     */
-
-    /* Determine the number of bit length codes to send. The pkzip format
-     * requires that at least 4 bit length codes be sent. (appnote.txt says
-     * 3 but the actual value used is 4.)
-     */
-    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
-        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
-    }
-    /* Update opt_len to include the bit length tree and counts */
-    s->opt_len += 3*(max_blindex+1) + 5+5+4;
-    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
-            s->opt_len, s->static_len));
-
-    return max_blindex;
-}
-
-/* ===========================================================================
- * Send the header for a block using dynamic Huffman trees: the counts, the
- * lengths of the bit length codes, the literal tree and the distance tree.
- * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
- */
-local void send_all_trees(s, lcodes, dcodes, blcodes)
-    deflate_state *s;
-    int lcodes, dcodes, blcodes; /* number of codes for each tree */
-{
-    int rank;                    /* index in bl_order */
-
-    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
-    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
-            "too many codes");
-    Tracev((stderr, "\nbl counts: "));
-    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
-    send_bits(s, dcodes-1,   5);
-    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
-    for (rank = 0; rank < blcodes; rank++) {
-        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
-        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
-    }
-    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
-
-    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
-    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
-
-    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
-    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
-}
-
-/* ===========================================================================
- * Send a stored block
- */
-void _tr_stored_block(s, buf, stored_len, eof)
-    deflate_state *s;
-    charf *buf;       /* input block */
-    ulg stored_len;   /* length of input block */
-    int eof;          /* true if this is the last block for a file */
-{
-    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
-    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
-    s->compressed_len += (stored_len + 4) << 3;
-
-    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
-}
-
-/* Send just the `stored block' type code without any length bytes or data.
- */
-void _tr_stored_type_only(s)
-    deflate_state *s;
-{
-    send_bits(s, (STORED_BLOCK << 1), 3);
-    bi_windup(s);
-    s->compressed_len = (s->compressed_len + 3) & ~7L;
-}
-
-
-/* ===========================================================================
- * Send one empty static block to give enough lookahead for inflate.
- * This takes 10 bits, of which 7 may remain in the bit buffer.
- * The current inflate code requires 9 bits of lookahead. If the
- * last two codes for the previous block (real code plus EOB) were coded
- * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
- * the last real code. In this case we send two empty static blocks instead
- * of one. (There are no problems if the previous block is stored or fixed.)
- * To simplify the code, we assume the worst case of last real code encoded
- * on one bit only.
- */
-void _tr_align(s)
-    deflate_state *s;
-{
-    send_bits(s, STATIC_TREES<<1, 3);
-    send_code(s, END_BLOCK, static_ltree);
-    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
-    bi_flush(s);
-    /* Of the 10 bits for the empty block, we have already sent
-     * (10 - bi_valid) bits. The lookahead for the last real code (before
-     * the EOB of the previous block) was thus at least one plus the length
-     * of the EOB plus what we have just sent of the empty static block.
-     */
-    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
-        send_bits(s, STATIC_TREES<<1, 3);
-        send_code(s, END_BLOCK, static_ltree);
-        s->compressed_len += 10L;
-        bi_flush(s);
-    }
-    s->last_eob_len = 7;
-}
-
-/* ===========================================================================
- * Determine the best encoding for the current block: dynamic trees, static
- * trees or store, and output the encoded block to the zip file. This function
- * returns the total compressed length for the file so far.
- */
-ulg _tr_flush_block(s, buf, stored_len, eof)
-    deflate_state *s;
-    charf *buf;       /* input block, or NULL if too old */
-    ulg stored_len;   /* length of input block */
-    int eof;          /* true if this is the last block for a file */
-{
-    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
-    int max_blindex = 0;  /* index of last bit length code of non zero freq */
-
-    /* Build the Huffman trees unless a stored block is forced */
-    if (s->level > 0) {
-
-	 /* Check if the file is ascii or binary */
-	if (s->data_type == Z_UNKNOWN) set_data_type(s);
-
-	/* Construct the literal and distance trees */
-	build_tree(s, (tree_desc *)(&(s->l_desc)));
-	Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
-		s->static_len));
-
-	build_tree(s, (tree_desc *)(&(s->d_desc)));
-	Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
-		s->static_len));
-	/* At this point, opt_len and static_len are the total bit lengths of
-	 * the compressed block data, excluding the tree representations.
-	 */
-
-	/* Build the bit length tree for the above two trees, and get the index
-	 * in bl_order of the last bit length code to send.
-	 */
-	max_blindex = build_bl_tree(s);
-
-	/* Determine the best encoding. Compute first the block length in bytes*/
-	opt_lenb = (s->opt_len+3+7)>>3;
-	static_lenb = (s->static_len+3+7)>>3;
-
-	Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
-		opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
-		s->last_lit));
-
-	if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
-
-    } else {
-        Assert(buf != (char*)0, "lost buf");
-	opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
-    }
-
-    /* If compression failed and this is the first and last block,
-     * and if the .zip file can be seeked (to rewrite the local header),
-     * the whole file is transformed into a stored file:
-     */
-#ifdef STORED_FILE_OK
-#  ifdef FORCE_STORED_FILE
-    if (eof && s->compressed_len == 0L) { /* force stored file */
-#  else
-    if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) {
-#  endif
-        /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
-        if (buf == (charf*)0) error ("block vanished");
-
-        copy_block(s, buf, (unsigned)stored_len, 0); /* without header */
-        s->compressed_len = stored_len << 3;
-        s->method = STORED;
-    } else
-#endif /* STORED_FILE_OK */
-
-#ifdef FORCE_STORED
-    if (buf != (char*)0) { /* force stored block */
-#else
-    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
-                       /* 4: two words for the lengths */
-#endif
-        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
-         * Otherwise we can't have processed more than WSIZE input bytes since
-         * the last block flush, because compression would have been
-         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
-         * transform a block into a stored block.
-         */
-        _tr_stored_block(s, buf, stored_len, eof);
-
-#ifdef FORCE_STATIC
-    } else if (static_lenb >= 0) { /* force static trees */
-#else
-    } else if (static_lenb == opt_lenb) {
-#endif
-        send_bits(s, (STATIC_TREES<<1)+eof, 3);
-        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
-        s->compressed_len += 3 + s->static_len;
-    } else {
-        send_bits(s, (DYN_TREES<<1)+eof, 3);
-        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
-                       max_blindex+1);
-        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
-        s->compressed_len += 3 + s->opt_len;
-    }
-    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
-    init_block(s);
-
-    if (eof) {
-        bi_windup(s);
-        s->compressed_len += 7;  /* align on byte boundary */
-    }
-    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
-           s->compressed_len-7*eof));
-
-    return s->compressed_len >> 3;
-}
-
-/* ===========================================================================
- * Save the match info and tally the frequency counts. Return true if
- * the current block must be flushed.
- */
-int _tr_tally (s, dist, lc)
-    deflate_state *s;
-    unsigned dist;  /* distance of matched string */
-    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
-{
-    s->d_buf[s->last_lit] = (ush)dist;
-    s->l_buf[s->last_lit++] = (uch)lc;
-    if (dist == 0) {
-        /* lc is the unmatched char */
-        s->dyn_ltree[lc].Freq++;
-    } else {
-        s->matches++;
-        /* Here, lc is the match length - MIN_MATCH */
-        dist--;             /* dist = match distance - 1 */
-        Assert((ush)dist < (ush)MAX_DIST(s) &&
-               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
-               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
-
-        s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
-        s->dyn_dtree[d_code(dist)].Freq++;
-    }
-
-    /* Try to guess if it is profitable to stop the current block here */
-    if (s->level > 2 && (s->last_lit & 0xfff) == 0) {
-        /* Compute an upper bound for the compressed length */
-        ulg out_length = (ulg)s->last_lit*8L;
-        ulg in_length = (ulg)((long)s->strstart - s->block_start);
-        int dcode;
-        for (dcode = 0; dcode < D_CODES; dcode++) {
-            out_length += (ulg)s->dyn_dtree[dcode].Freq *
-                (5L+extra_dbits[dcode]);
-        }
-        out_length >>= 3;
-        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
-               s->last_lit, in_length, out_length,
-               100L - out_length*100L/in_length));
-        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
-    }
-    return (s->last_lit == s->lit_bufsize-1);
-    /* We avoid equality with lit_bufsize because of wraparound at 64K
-     * on 16 bit machines and because stored blocks are restricted to
-     * 64K-1 bytes.
-     */
-}
-
-/* ===========================================================================
- * Send the block data compressed using the given Huffman trees
- */
-local void compress_block(s, ltree, dtree)
-    deflate_state *s;
-    ct_data *ltree; /* literal tree */
-    ct_data *dtree; /* distance tree */
-{
-    unsigned dist;      /* distance of matched string */
-    int lc;             /* match length or unmatched char (if dist == 0) */
-    unsigned lx = 0;    /* running index in l_buf */
-    unsigned code;      /* the code to send */
-    int extra;          /* number of extra bits to send */
-
-    if (s->last_lit != 0) do {
-        dist = s->d_buf[lx];
-        lc = s->l_buf[lx++];
-        if (dist == 0) {
-            send_code(s, lc, ltree); /* send a literal byte */
-            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
-        } else {
-            /* Here, lc is the match length - MIN_MATCH */
-            code = length_code[lc];
-            send_code(s, code+LITERALS+1, ltree); /* send the length code */
-            extra = extra_lbits[code];
-            if (extra != 0) {
-                lc -= base_length[code];
-                send_bits(s, lc, extra);       /* send the extra length bits */
-            }
-            dist--; /* dist is now the match distance - 1 */
-            code = d_code(dist);
-            Assert (code < D_CODES, "bad d_code");
-
-            send_code(s, code, dtree);       /* send the distance code */
-            extra = extra_dbits[code];
-            if (extra != 0) {
-                dist -= base_dist[code];
-                send_bits(s, dist, extra);   /* send the extra distance bits */
-            }
-        } /* literal or match pair ? */
-
-        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
-        Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
-
-    } while (lx < s->last_lit);
-
-    send_code(s, END_BLOCK, ltree);
-    s->last_eob_len = ltree[END_BLOCK].Len;
-}
-
-/* ===========================================================================
- * Set the data type to ASCII or BINARY, using a crude approximation:
- * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
- * IN assertion: the fields freq of dyn_ltree are set and the total of all
- * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
- */
-local void set_data_type(s)
-    deflate_state *s;
-{
-    int n = 0;
-    unsigned ascii_freq = 0;
-    unsigned bin_freq = 0;
-    while (n < 7)        bin_freq += s->dyn_ltree[n++].Freq;
-    while (n < 128)    ascii_freq += s->dyn_ltree[n++].Freq;
-    while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
-    s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
-}
-
-/* ===========================================================================
- * Reverse the first len bits of a code, using straightforward code (a faster
- * method would use a table)
- * IN assertion: 1 <= len <= 15
- */
-local unsigned bi_reverse(code, len)
-    unsigned code; /* the value to invert */
-    int len;       /* its bit length */
-{
-    register unsigned res = 0;
-    do {
-        res |= code & 1;
-        code >>= 1, res <<= 1;
-    } while (--len > 0);
-    return res >> 1;
-}
-
-/* ===========================================================================
- * Flush the bit buffer, keeping at most 7 bits in it.
- */
-local void bi_flush(s)
-    deflate_state *s;
-{
-    if (s->bi_valid == 16) {
-        put_short(s, s->bi_buf);
-        s->bi_buf = 0;
-        s->bi_valid = 0;
-    } else if (s->bi_valid >= 8) {
-        put_byte(s, (Byte)s->bi_buf);
-        s->bi_buf >>= 8;
-        s->bi_valid -= 8;
-    }
-}
-
-/* ===========================================================================
- * Flush the bit buffer and align the output on a byte boundary
- */
-local void bi_windup(s)
-    deflate_state *s;
-{
-    if (s->bi_valid > 8) {
-        put_short(s, s->bi_buf);
-    } else if (s->bi_valid > 0) {
-        put_byte(s, (Byte)s->bi_buf);
-    }
-    s->bi_buf = 0;
-    s->bi_valid = 0;
-#ifdef DEBUG_ZLIB
-    s->bits_sent = (s->bits_sent+7) & ~7;
-#endif
-}
-
-/* ===========================================================================
- * Copy a stored block, storing first the length and its
- * one's complement if requested.
- */
-local void copy_block(s, buf, len, header)
-    deflate_state *s;
-    charf    *buf;    /* the input data */
-    unsigned len;     /* its length */
-    int      header;  /* true if block header must be written */
-{
-    bi_windup(s);        /* align on byte boundary */
-    s->last_eob_len = 8; /* enough lookahead for inflate */
-
-    if (header) {
-        put_short(s, (ush)len);   
-        put_short(s, (ush)~len);
-#ifdef DEBUG_ZLIB
-        s->bits_sent += 2*16;
-#endif
-    }
-#ifdef DEBUG_ZLIB
-    s->bits_sent += (ulg)len<<3;
-#endif
-    /* bundle up the put_byte(s, *buf++) calls */
-    zmemcpy(&s->pending_buf[s->pending], buf, len);
-    s->pending += len;
-}
-/* --- trees.c */
-
-/* +++ inflate.c */
-/* inflate.c -- zlib interface to inflate modules
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-
-/* +++ infblock.h */
-/* infblock.h -- header to use infblock.c
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-struct inflate_blocks_state;
-typedef struct inflate_blocks_state FAR inflate_blocks_statef;
-
-extern inflate_blocks_statef * inflate_blocks_new OF((
-    z_streamp z,
-    check_func c,               /* check function */
-    uInt w));                   /* window size */
-
-extern int inflate_blocks OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));                      /* initial return code */
-
-extern void inflate_blocks_reset OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    uLongf *));                  /* check value on output */
-
-extern int inflate_blocks_free OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    uLongf *));                  /* check value on output */
-
-extern void inflate_set_dictionary OF((
-    inflate_blocks_statef *s,
-    const Bytef *d,  /* dictionary */
-    uInt  n));       /* dictionary length */
-
-extern int inflate_addhistory OF((
-    inflate_blocks_statef *,
-    z_streamp));
-
-extern int inflate_packet_flush OF((
-    inflate_blocks_statef *));
-/* --- infblock.h */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* inflate private state */
-struct internal_state {
-
-  /* mode */
-  enum {
-      METHOD,   /* waiting for method byte */
-      FLAG,     /* waiting for flag byte */
-      DICT4,    /* four dictionary check bytes to go */
-      DICT3,    /* three dictionary check bytes to go */
-      DICT2,    /* two dictionary check bytes to go */
-      DICT1,    /* one dictionary check byte to go */
-      DICT0,    /* waiting for inflateSetDictionary */
-      BLOCKS,   /* decompressing blocks */
-      CHECK4,   /* four check bytes to go */
-      CHECK3,   /* three check bytes to go */
-      CHECK2,   /* two check bytes to go */
-      CHECK1,   /* one check byte to go */
-      DONE,     /* finished check, done */
-      BAD}      /* got an error--stay here */
-    mode;               /* current inflate mode */
-
-  /* mode dependent information */
-  union {
-    uInt method;        /* if FLAGS, method byte */
-    struct {
-      uLong was;                /* computed check value */
-      uLong need;               /* stream check value */
-    } check;            /* if CHECK, check values to compare */
-    uInt marker;        /* if BAD, inflateSync's marker bytes count */
-  } sub;        /* submode */
-
-  /* mode independent information */
-  int  nowrap;          /* flag for no wrapper */
-  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
-  inflate_blocks_statef 
-    *blocks;            /* current inflate_blocks state */
-
-};
-
-
-int inflateReset(z)
-z_streamp z;
-{
-  uLong c;
-
-  if (z == Z_NULL || z->state == Z_NULL)
-    return Z_STREAM_ERROR;
-  z->total_in = z->total_out = 0;
-  z->msg = Z_NULL;
-  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
-  inflate_blocks_reset(z->state->blocks, z, &c);
-  Trace((stderr, "inflate: reset\n"));
-  return Z_OK;
-}
-
-
-int inflateEnd(z)
-z_streamp z;
-{
-  uLong c;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
-    return Z_STREAM_ERROR;
-  if (z->state->blocks != Z_NULL)
-    inflate_blocks_free(z->state->blocks, z, &c);
-  ZFREE(z, z->state);
-  z->state = Z_NULL;
-  Trace((stderr, "inflate: end\n"));
-  return Z_OK;
-}
-
-
-int inflateInit2_(z, w, version, stream_size)
-z_streamp z;
-int w;
-const char *version;
-int stream_size;
-{
-  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
-      stream_size != sizeof(z_stream))
-      return Z_VERSION_ERROR;
-
-  /* initialize state */
-  if (z == Z_NULL)
-    return Z_STREAM_ERROR;
-  z->msg = Z_NULL;
-#ifndef NO_ZCFUNCS
-  if (z->zalloc == Z_NULL)
-  {
-    z->zalloc = zcalloc;
-    z->opaque = (voidpf)0;
-  }
-  if (z->zfree == Z_NULL) z->zfree = zcfree;
-#endif
-  if ((z->state = (struct internal_state FAR *)
-       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
-    return Z_MEM_ERROR;
-  z->state->blocks = Z_NULL;
-
-  /* handle undocumented nowrap option (no zlib header or check) */
-  z->state->nowrap = 0;
-  if (w < 0)
-  {
-    w = - w;
-    z->state->nowrap = 1;
-  }
-
-  /* set window size */
-  if (w < 8 || w > 15)
-  {
-    inflateEnd(z);
-    return Z_STREAM_ERROR;
-  }
-  z->state->wbits = (uInt)w;
-
-  /* create inflate_blocks state */
-  if ((z->state->blocks =
-      inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
-      == Z_NULL)
-  {
-    inflateEnd(z);
-    return Z_MEM_ERROR;
-  }
-  Trace((stderr, "inflate: allocated\n"));
-
-  /* reset state */
-  inflateReset(z);
-  return Z_OK;
-}
-
-
-int inflateInit_(z, version, stream_size)
-z_streamp z;
-const char *version;
-int stream_size;
-{
-  return inflateInit2_(z, DEF_WBITS, version, stream_size);
-}
-
-
-#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
-#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
-
-int inflate(z, f)
-z_streamp z;
-int f;
-{
-  int r;
-  uInt b;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0)
-    return Z_STREAM_ERROR;
-  r = Z_BUF_ERROR;
-  while (1) switch (z->state->mode)
-  {
-    case METHOD:
-      NEEDBYTE
-      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"unknown compression method";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"invalid window size";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      z->state->mode = FLAG;
-    case FLAG:
-      NEEDBYTE
-      b = NEXTBYTE;
-      if (((z->state->sub.method << 8) + b) % 31)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"incorrect header check";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      Trace((stderr, "inflate: zlib header ok\n"));
-      if (!(b & PRESET_DICT))
-      {
-        z->state->mode = BLOCKS;
-	break;
-      }
-      z->state->mode = DICT4;
-    case DICT4:
-      NEEDBYTE
-      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-      z->state->mode = DICT3;
-    case DICT3:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-      z->state->mode = DICT2;
-    case DICT2:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-      z->state->mode = DICT1;
-    case DICT1:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE;
-      z->adler = z->state->sub.check.need;
-      z->state->mode = DICT0;
-      return Z_NEED_DICT;
-    case DICT0:
-      z->state->mode = BAD;
-      z->msg = (char*)"need dictionary";
-      z->state->sub.marker = 0;       /* can try inflateSync */
-      return Z_STREAM_ERROR;
-    case BLOCKS:
-      r = inflate_blocks(z->state->blocks, z, r);
-      if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
-	  r = inflate_packet_flush(z->state->blocks);
-      if (r == Z_DATA_ERROR)
-      {
-        z->state->mode = BAD;
-        z->state->sub.marker = 0;       /* can try inflateSync */
-        break;
-      }
-      if (r != Z_STREAM_END)
-        return r;
-      r = Z_OK;
-      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
-      if (z->state->nowrap)
-      {
-        z->state->mode = DONE;
-        break;
-      }
-      z->state->mode = CHECK4;
-    case CHECK4:
-      NEEDBYTE
-      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-      z->state->mode = CHECK3;
-    case CHECK3:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-      z->state->mode = CHECK2;
-    case CHECK2:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-      z->state->mode = CHECK1;
-    case CHECK1:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE;
-
-      if (z->state->sub.check.was != z->state->sub.check.need)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"incorrect data check";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      Trace((stderr, "inflate: zlib check ok\n"));
-      z->state->mode = DONE;
-    case DONE:
-      return Z_STREAM_END;
-    case BAD:
-      return Z_DATA_ERROR;
-    default:
-      return Z_STREAM_ERROR;
-  }
-
- empty:
-  if (f != Z_PACKET_FLUSH)
-    return r;
-  z->state->mode = BAD;
-  z->msg = (char *)"need more for packet flush";
-  z->state->sub.marker = 0;       /* can try inflateSync */
-  return Z_DATA_ERROR;
-}
-
-
-int inflateSetDictionary(z, dictionary, dictLength)
-z_streamp z;
-const Bytef *dictionary;
-uInt  dictLength;
-{
-  uInt length = dictLength;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
-    return Z_STREAM_ERROR;
-
-  if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
-  z->adler = 1L;
-
-  if (length >= ((uInt)1<<z->state->wbits))
-  {
-    length = (1<<z->state->wbits)-1;
-    dictionary += dictLength - length;
-  }
-  inflate_set_dictionary(z->state->blocks, dictionary, length);
-  z->state->mode = BLOCKS;
-  return Z_OK;
-}
-
-/*
- * This subroutine adds the data at next_in/avail_in to the output history
- * without performing any output.  The output buffer must be "caught up";
- * i.e. no pending output (hence s->read equals s->write), and the state must
- * be BLOCKS (i.e. we should be willing to see the start of a series of
- * BLOCKS).  On exit, the output will also be caught up, and the checksum
- * will have been updated if need be.
- */
-
-int inflateIncomp(z)
-z_stream *z;
-{
-    if (z->state->mode != BLOCKS)
-	return Z_DATA_ERROR;
-    return inflate_addhistory(z->state->blocks, z);
-}
-
-
-int inflateSync(z)
-z_streamp z;
-{
-  uInt n;       /* number of bytes to look at */
-  Bytef *p;     /* pointer to bytes */
-  uInt m;       /* number of marker bytes found in a row */
-  uLong r, w;   /* temporaries to save total_in and total_out */
-
-  /* set up */
-  if (z == Z_NULL || z->state == Z_NULL)
-    return Z_STREAM_ERROR;
-  if (z->state->mode != BAD)
-  {
-    z->state->mode = BAD;
-    z->state->sub.marker = 0;
-  }
-  if ((n = z->avail_in) == 0)
-    return Z_BUF_ERROR;
-  p = z->next_in;
-  m = z->state->sub.marker;
-
-  /* search */
-  while (n && m < 4)
-  {
-    if (*p == (Byte)(m < 2 ? 0 : 0xff))
-      m++;
-    else if (*p)
-      m = 0;
-    else
-      m = 4 - m;
-    p++, n--;
-  }
-
-  /* restore */
-  z->total_in += p - z->next_in;
-  z->next_in = p;
-  z->avail_in = n;
-  z->state->sub.marker = m;
-
-  /* return no joy or set up to restart on a new block */
-  if (m != 4)
-    return Z_DATA_ERROR;
-  r = z->total_in;  w = z->total_out;
-  inflateReset(z);
-  z->total_in = r;  z->total_out = w;
-  z->state->mode = BLOCKS;
-  return Z_OK;
-}
-
-#undef NEEDBYTE
-#undef NEXTBYTE
-/* --- inflate.c */
-
-/* +++ infblock.c */
-/* infblock.c -- interpret and process block types to last block
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "infblock.h" */
-
-/* +++ inftrees.h */
-/* inftrees.h -- header to use inftrees.c
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-/* Huffman code lookup table entry--this entry is four bytes for machines
-   that have 16-bit pointers (e.g. PC's in the small or medium model). */
-
-typedef struct inflate_huft_s FAR inflate_huft;
-
-struct inflate_huft_s {
-  union {
-    struct {
-      Byte Exop;        /* number of extra bits or operation */
-      Byte Bits;        /* number of bits in this code or subcode */
-    } what;
-    Bytef *pad;         /* pad structure to a power of 2 (4 bytes for */
-  } word;               /*  16-bit, 8 bytes for 32-bit machines) */
-  union {
-    uInt Base;          /* literal, length base, or distance base */
-    inflate_huft *Next; /* pointer to next level of table */
-  } more;
-};
-
-#ifdef DEBUG_ZLIB
-  extern uInt inflate_hufts;
-#endif
-
-extern int inflate_trees_bits OF((
-    uIntf *,                    /* 19 code lengths */
-    uIntf *,                    /* bits tree desired/actual depth */
-    inflate_huft * FAR *,       /* bits tree result */
-    z_streamp ));               /* for zalloc, zfree functions */
-
-extern int inflate_trees_dynamic OF((
-    uInt,                       /* number of literal/length codes */
-    uInt,                       /* number of distance codes */
-    uIntf *,                    /* that many (total) code lengths */
-    uIntf *,                    /* literal desired/actual bit depth */
-    uIntf *,                    /* distance desired/actual bit depth */
-    inflate_huft * FAR *,       /* literal/length tree result */
-    inflate_huft * FAR *,       /* distance tree result */
-    z_streamp ));               /* for zalloc, zfree functions */
-
-extern int inflate_trees_fixed OF((
-    uIntf *,                    /* literal desired/actual bit depth */
-    uIntf *,                    /* distance desired/actual bit depth */
-    inflate_huft * FAR *,       /* literal/length tree result */
-    inflate_huft * FAR *));     /* distance tree result */
-
-extern int inflate_trees_free OF((
-    inflate_huft *,             /* tables to free */
-    z_streamp ));               /* for zfree function */
-
-/* --- inftrees.h */
-
-/* +++ infcodes.h */
-/* infcodes.h -- header to use infcodes.c
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-struct inflate_codes_state;
-typedef struct inflate_codes_state FAR inflate_codes_statef;
-
-extern inflate_codes_statef *inflate_codes_new OF((
-    uInt, uInt,
-    inflate_huft *, inflate_huft *,
-    z_streamp ));
-
-extern int inflate_codes OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));
-
-extern void inflate_codes_free OF((
-    inflate_codes_statef *,
-    z_streamp ));
-
-/* --- infcodes.h */
-
-/* +++ infutil.h */
-/* infutil.h -- types and macros common to blocks and codes
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-#ifndef _INFUTIL_H
-#define _INFUTIL_H
-
-typedef enum {
-      TYPE,     /* get type bits (3, including end bit) */
-      LENS,     /* get lengths for stored */
-      STORED,   /* processing stored block */
-      TABLE,    /* get table lengths */
-      BTREE,    /* get bit lengths tree for a dynamic block */
-      DTREE,    /* get length, distance trees for a dynamic block */
-      CODES,    /* processing fixed or dynamic block */
-      DRY,      /* output remaining window bytes */
-      DONEB,    /* finished last block, done */
-      BADB}     /* got a data error--stuck here */
-inflate_block_mode;
-
-/* inflate blocks semi-private state */
-struct inflate_blocks_state {
-
-  /* mode */
-  inflate_block_mode  mode;     /* current inflate_block mode */
-
-  /* mode dependent information */
-  union {
-    uInt left;          /* if STORED, bytes left to copy */
-    struct {
-      uInt table;               /* table lengths (14 bits) */
-      uInt index;               /* index into blens (or border) */
-      uIntf *blens;             /* bit lengths of codes */
-      uInt bb;                  /* bit length tree depth */
-      inflate_huft *tb;         /* bit length decoding tree */
-    } trees;            /* if DTREE, decoding info for trees */
-    struct {
-      inflate_huft *tl;
-      inflate_huft *td;         /* trees to free */
-      inflate_codes_statef 
-         *codes;
-    } decode;           /* if CODES, current state */
-  } sub;                /* submode */
-  uInt last;            /* true if this block is the last block */
-
-  /* mode independent information */
-  uInt bitk;            /* bits in bit buffer */
-  uLong bitb;           /* bit buffer */
-  Bytef *window;        /* sliding window */
-  Bytef *end;           /* one byte after sliding window */
-  Bytef *read;          /* window read pointer */
-  Bytef *write;         /* window write pointer */
-  check_func checkfn;   /* check function */
-  uLong check;          /* check on output */
-
-};
-
-
-/* defines for inflate input/output */
-/*   update pointers and return */
-#define UPDBITS {s->bitb=b;s->bitk=k;}
-#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
-#define UPDOUT {s->write=q;}
-#define UPDATE {UPDBITS UPDIN UPDOUT}
-#define LEAVE {UPDATE return inflate_flush(s,z,r);}
-/*   get bytes and bits */
-#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
-#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
-#define NEXTBYTE (n--,*p++)
-#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-#define DUMPBITS(j) {b>>=(j);k-=(j);}
-/*   output bytes */
-#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
-#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
-#define WWRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
-#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
-#define NEEDOUT {if(m==0){WWRAP if(m==0){FLUSH WWRAP if(m==0) LEAVE}}r=Z_OK;}
-#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
-/*   load local pointers */
-#define LOAD {LOADIN LOADOUT}
-
-/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
-extern uInt inflate_mask[17];
-
-/* copy as much as possible from the sliding window to the output area */
-extern int inflate_flush OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));
-
-#ifndef NO_DUMMY_DECL
-struct internal_state      {int dummy;}; /* for buggy compilers */
-#endif
-
-#endif
-/* --- infutil.h */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* Table for deflate from PKZIP's appnote.txt. */
-local const uInt border[] = { /* Order of the bit length code lengths */
-        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-
-/*
-   Notes beyond the 1.93a appnote.txt:
-
-   1. Distance pointers never point before the beginning of the output
-      stream.
-   2. Distance pointers can point back across blocks, up to 32k away.
-   3. There is an implied maximum of 7 bits for the bit length table and
-      15 bits for the actual data.
-   4. If only one code exists, then it is encoded using one bit.  (Zero
-      would be more efficient, but perhaps a little confusing.)  If two
-      codes exist, they are coded using one bit each (0 and 1).
-   5. There is no way of sending zero distance codes--a dummy must be
-      sent if there are none.  (History: a pre 2.0 version of PKZIP would
-      store blocks with no distance codes, but this was discovered to be
-      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
-      zero distance codes, which is sent as one code of zero bits in
-      length.
-   6. There are up to 286 literal/length codes.  Code 256 represents the
-      end-of-block.  Note however that the static length tree defines
-      288 codes just to fill out the Huffman codes.  Codes 286 and 287
-      cannot be used though, since there is no length base or extra bits
-      defined for them.  Similarily, there are up to 30 distance codes.
-      However, static trees define 32 codes (all 5 bits) to fill out the
-      Huffman codes, but the last two had better not show up in the data.
-   7. Unzip can check dynamic Huffman blocks for complete code sets.
-      The exception is that a single code would not be complete (see #4).
-   8. The five bits following the block type is really the number of
-      literal codes sent minus 257.
-   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
-      (1+6+6).  Therefore, to output three times the length, you output
-      three codes (1+1+1), whereas to output four times the same length,
-      you only need two codes (1+3).  Hmm.
-  10. In the tree reconstruction algorithm, Code = Code + Increment
-      only if BitLength(i) is not zero.  (Pretty obvious.)
-  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
-  12. Note: length code 284 can represent 227-258, but length code 285
-      really is 258.  The last length deserves its own, short code
-      since it gets used a lot in very redundant files.  The length
-      258 is special since 258 - 3 (the min match length) is 255.
-  13. The literal/length and distance code bit lengths are read as a
-      single stream of lengths.  It is possible (and advantageous) for
-      a repeat code (16, 17, or 18) to go across the boundary between
-      the two sets of lengths.
- */
-
-
-void inflate_blocks_reset(s, z, c)
-inflate_blocks_statef *s;
-z_streamp z;
-uLongf *c;
-{
-  if (s->checkfn != Z_NULL)
-    *c = s->check;
-  if (s->mode == BTREE || s->mode == DTREE)
-    ZFREE(z, s->sub.trees.blens);
-  if (s->mode == CODES)
-  {
-    inflate_codes_free(s->sub.decode.codes, z);
-    inflate_trees_free(s->sub.decode.td, z);
-    inflate_trees_free(s->sub.decode.tl, z);
-  }
-  s->mode = TYPE;
-  s->bitk = 0;
-  s->bitb = 0;
-  s->read = s->write = s->window;
-  if (s->checkfn != Z_NULL)
-    z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0);
-  Trace((stderr, "inflate:   blocks reset\n"));
-}
-
-
-inflate_blocks_statef *inflate_blocks_new(z, c, w)
-z_streamp z;
-check_func c;
-uInt w;
-{
-  inflate_blocks_statef *s;
-
-  if ((s = (inflate_blocks_statef *)ZALLOC
-       (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
-    return s;
-  if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
-  {
-    ZFREE(z, s);
-    return Z_NULL;
-  }
-  s->end = s->window + w;
-  s->checkfn = c;
-  s->mode = TYPE;
-  Trace((stderr, "inflate:   blocks allocated\n"));
-  inflate_blocks_reset(s, z, &s->check);
-  return s;
-}
-
-
-#ifdef DEBUG_ZLIB
-  extern uInt inflate_hufts;
-#endif
-int inflate_blocks(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt t;               /* temporary storage */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Bytef *p;             /* input data pointer */
-  uInt n;               /* bytes available there */
-  Bytef *q;             /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-
-  /* copy input/output information to locals (UPDATE macro restores) */
-  LOAD
-
-  /* process input based on current state */
-  while (1) switch (s->mode)
-  {
-    case TYPE:
-      NEEDBITS(3)
-      t = (uInt)b & 7;
-      s->last = t & 1;
-      switch (t >> 1)
-      {
-        case 0:                         /* stored */
-          Trace((stderr, "inflate:     stored block%s\n",
-                 s->last ? " (last)" : ""));
-          DUMPBITS(3)
-          t = k & 7;                    /* go to byte boundary */
-          DUMPBITS(t)
-          s->mode = LENS;               /* get length of stored block */
-          break;
-        case 1:                         /* fixed */
-          Trace((stderr, "inflate:     fixed codes block%s\n",
-                 s->last ? " (last)" : ""));
-          {
-            uInt bl, bd;
-            inflate_huft *tl, *td;
-
-            inflate_trees_fixed(&bl, &bd, &tl, &td);
-            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
-            if (s->sub.decode.codes == Z_NULL)
-            {
-              r = Z_MEM_ERROR;
-              LEAVE
-            }
-            s->sub.decode.tl = Z_NULL;  /* don't try to free these */
-            s->sub.decode.td = Z_NULL;
-          }
-          DUMPBITS(3)
-          s->mode = CODES;
-          break;
-        case 2:                         /* dynamic */
-          Trace((stderr, "inflate:     dynamic codes block%s\n",
-                 s->last ? " (last)" : ""));
-          DUMPBITS(3)
-          s->mode = TABLE;
-          break;
-        case 3:                         /* illegal */
-          DUMPBITS(3)
-          s->mode = BADB;
-          z->msg = (char*)"invalid block type";
-          r = Z_DATA_ERROR;
-          LEAVE
-      }
-      break;
-    case LENS:
-      NEEDBITS(32)
-      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
-      {
-        s->mode = BADB;
-        z->msg = (char*)"invalid stored block lengths";
-        r = Z_DATA_ERROR;
-        LEAVE
-      }
-      s->sub.left = (uInt)b & 0xffff;
-      b = k = 0;                      /* dump bits */
-      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
-      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
-      break;
-    case STORED:
-      if (n == 0)
-        LEAVE
-      NEEDOUT
-      t = s->sub.left;
-      if (t > n) t = n;
-      if (t > m) t = m;
-      zmemcpy(q, p, t);
-      p += t;  n -= t;
-      q += t;  m -= t;
-      if ((s->sub.left -= t) != 0)
-        break;
-      Tracev((stderr, "inflate:       stored end, %lu total out\n",
-              z->total_out + (q >= s->read ? q - s->read :
-              (s->end - s->read) + (q - s->window))));
-      s->mode = s->last ? DRY : TYPE;
-      break;
-    case TABLE:
-      NEEDBITS(14)
-      s->sub.trees.table = t = (uInt)b & 0x3fff;
-#ifndef PKZIP_BUG_WORKAROUND
-      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
-      {
-        s->mode = BADB;
-        z->msg = (char*)"too many length or distance symbols";
-        r = Z_DATA_ERROR;
-        LEAVE
-      }
-#endif
-      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
-      if (t < 19)
-        t = 19;
-      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
-      {
-        r = Z_MEM_ERROR;
-        LEAVE
-      }
-      DUMPBITS(14)
-      s->sub.trees.index = 0;
-      Tracev((stderr, "inflate:       table sizes ok\n"));
-      s->mode = BTREE;
-    case BTREE:
-      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
-      {
-        NEEDBITS(3)
-        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
-        DUMPBITS(3)
-      }
-      while (s->sub.trees.index < 19)
-        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
-      s->sub.trees.bb = 7;
-      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
-                             &s->sub.trees.tb, z);
-      if (t != Z_OK)
-      {
-        r = t;
-        if (r == Z_DATA_ERROR)
-	{
-	  ZFREE(z, s->sub.trees.blens);
-          s->mode = BADB;
-	}
-        LEAVE
-      }
-      s->sub.trees.index = 0;
-      Tracev((stderr, "inflate:       bits tree ok\n"));
-      s->mode = DTREE;
-    case DTREE:
-      while (t = s->sub.trees.table,
-             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
-      {
-        inflate_huft *h;
-        uInt i, j, c;
-
-        t = s->sub.trees.bb;
-        NEEDBITS(t)
-        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
-        t = h->word.what.Bits;
-        c = h->more.Base;
-        if (c < 16)
-        {
-          DUMPBITS(t)
-          s->sub.trees.blens[s->sub.trees.index++] = c;
-        }
-        else /* c == 16..18 */
-        {
-          i = c == 18 ? 7 : c - 14;
-          j = c == 18 ? 11 : 3;
-          NEEDBITS(t + i)
-          DUMPBITS(t)
-          j += (uInt)b & inflate_mask[i];
-          DUMPBITS(i)
-          i = s->sub.trees.index;
-          t = s->sub.trees.table;
-          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
-              (c == 16 && i < 1))
-          {
-            inflate_trees_free(s->sub.trees.tb, z);
-            ZFREE(z, s->sub.trees.blens);
-            s->mode = BADB;
-            z->msg = (char*)"invalid bit length repeat";
-            r = Z_DATA_ERROR;
-            LEAVE
-          }
-          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
-          do {
-            s->sub.trees.blens[i++] = c;
-          } while (--j);
-          s->sub.trees.index = i;
-        }
-      }
-      inflate_trees_free(s->sub.trees.tb, z);
-      s->sub.trees.tb = Z_NULL;
-      {
-        uInt bl, bd;
-        inflate_huft *tl, *td;
-        inflate_codes_statef *c;
-
-        bl = 9;         /* must be <= 9 for lookahead assumptions */
-        bd = 6;         /* must be <= 9 for lookahead assumptions */
-        t = s->sub.trees.table;
-#ifdef DEBUG_ZLIB
-      inflate_hufts = 0;
-#endif
-        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
-                                  s->sub.trees.blens, &bl, &bd, &tl, &td, z);
-        if (t != Z_OK)
-        {
-          if (t == (uInt)Z_DATA_ERROR)
-	  {
-	    ZFREE(z, s->sub.trees.blens);
-            s->mode = BADB;
-	  }
-          r = t;
-          LEAVE
-        }
-        Tracev((stderr, "inflate:       trees ok, %d * %d bytes used\n",
-              inflate_hufts, sizeof(inflate_huft)));
-        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
-        {
-          inflate_trees_free(td, z);
-          inflate_trees_free(tl, z);
-          r = Z_MEM_ERROR;
-          LEAVE
-        }
-        ZFREE(z, s->sub.trees.blens);
-        s->sub.decode.codes = c;
-        s->sub.decode.tl = tl;
-        s->sub.decode.td = td;
-      }
-      s->mode = CODES;
-    case CODES:
-      UPDATE
-      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
-        return inflate_flush(s, z, r);
-      r = Z_OK;
-      inflate_codes_free(s->sub.decode.codes, z);
-      inflate_trees_free(s->sub.decode.td, z);
-      inflate_trees_free(s->sub.decode.tl, z);
-      LOAD
-      Tracev((stderr, "inflate:       codes end, %lu total out\n",
-              z->total_out + (q >= s->read ? q - s->read :
-              (s->end - s->read) + (q - s->window))));
-      if (!s->last)
-      {
-        s->mode = TYPE;
-        break;
-      }
-      if (k > 7)              /* return unused byte, if any */
-      {
-        Assert(k < 16, "inflate_codes grabbed too many bytes")
-        k -= 8;
-        n++;
-        p--;                    /* can always return one */
-      }
-      s->mode = DRY;
-    case DRY:
-      FLUSH
-      if (s->read != s->write)
-        LEAVE
-      s->mode = DONEB;
-    case DONEB:
-      r = Z_STREAM_END;
-      LEAVE
-    case BADB:
-      r = Z_DATA_ERROR;
-      LEAVE
-    default:
-      r = Z_STREAM_ERROR;
-      LEAVE
-  }
-}
-
-
-int inflate_blocks_free(s, z, c)
-inflate_blocks_statef *s;
-z_streamp z;
-uLongf *c;
-{
-  inflate_blocks_reset(s, z, c);
-  ZFREE(z, s->window);
-  ZFREE(z, s);
-  Trace((stderr, "inflate:   blocks freed\n"));
-  return Z_OK;
-}
-
-
-void inflate_set_dictionary(s, d, n)
-inflate_blocks_statef *s;
-const Bytef *d;
-uInt  n;
-{
-  zmemcpy((charf *)s->window, d, n);
-  s->read = s->write = s->window + n;
-}
-
-/*
- * This subroutine adds the data at next_in/avail_in to the output history
- * without performing any output.  The output buffer must be "caught up";
- * i.e. no pending output (hence s->read equals s->write), and the state must
- * be BLOCKS (i.e. we should be willing to see the start of a series of
- * BLOCKS).  On exit, the output will also be caught up, and the checksum
- * will have been updated if need be.
- */
-int inflate_addhistory(s, z)
-inflate_blocks_statef *s;
-z_stream *z;
-{
-    uLong b;              /* bit buffer */  /* NOT USED HERE */
-    uInt k;               /* bits in bit buffer */ /* NOT USED HERE */
-    uInt t;               /* temporary storage */
-    Bytef *p;             /* input data pointer */
-    uInt n;               /* bytes available there */
-    Bytef *q;             /* output window write pointer */
-    uInt m;               /* bytes to end of window or read pointer */
-
-    if (s->read != s->write)
-	return Z_STREAM_ERROR;
-    if (s->mode != TYPE)
-	return Z_DATA_ERROR;
-
-    /* we're ready to rock */
-    LOAD
-    /* while there is input ready, copy to output buffer, moving
-     * pointers as needed.
-     */
-    while (n) {
-	t = n;  /* how many to do */
-	/* is there room until end of buffer? */
-	if (t > m) t = m;
-	/* update check information */
-	if (s->checkfn != Z_NULL)
-	    s->check = (*s->checkfn)(s->check, q, t);
-	zmemcpy(q, p, t);
-	q += t;
-	p += t;
-	n -= t;
-	z->total_out += t;
-	s->read = q;    /* drag read pointer forward */
-/*      WWRAP  */ 	/* expand WWRAP macro by hand to handle s->read */
-	if (q == s->end) {
-	    s->read = q = s->window;
-	    m = WAVAIL;
-	}
-    }
-    UPDATE
-    return Z_OK;
-}
-
-
-/*
- * At the end of a Deflate-compressed PPP packet, we expect to have seen
- * a `stored' block type value but not the (zero) length bytes.
- */
-int inflate_packet_flush(s)
-    inflate_blocks_statef *s;
-{
-    if (s->mode != LENS)
-	return Z_DATA_ERROR;
-    s->mode = TYPE;
-    return Z_OK;
-}
-/* --- infblock.c */
-
-/* +++ inftrees.c */
-/* inftrees.c -- generate Huffman trees for efficient decoding
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-
-char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler ";
-/*
-  If you use the zlib library in a product, an acknowledgment is welcome
-  in the documentation of your product. If for some reason you cannot
-  include such an acknowledgment, I would appreciate that you keep this
-  copyright string in the executable of your product.
- */
-
-#ifndef NO_DUMMY_DECL
-struct internal_state  {int dummy;}; /* for buggy compilers */
-#endif
-
-/* simplify the use of the inflate_huft type with some defines */
-#define base more.Base
-#define next more.Next
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-
-local int huft_build OF((
-    uIntf *,            /* code lengths in bits */
-    uInt,               /* number of codes */
-    uInt,               /* number of "simple" codes */
-    const uIntf *,      /* list of base values for non-simple codes */
-    const uIntf *,      /* list of extra bits for non-simple codes */
-    inflate_huft * FAR*,/* result: starting table */
-    uIntf *,            /* maximum lookup bits (returns actual) */
-    z_streamp ));       /* for zalloc function */
-
-local voidpf falloc OF((
-    voidpf,             /* opaque pointer (not used) */
-    uInt,               /* number of items */
-    uInt));             /* size of item */
-
-/* Tables for deflate from PKZIP's appnote.txt. */
-local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
-        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
-        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
-        /* see note #13 above about 258 */
-local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
-        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
-        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
-local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
-        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
-        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
-        8193, 12289, 16385, 24577};
-local const uInt cpdext[30] = { /* Extra bits for distance codes */
-        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
-        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
-        12, 12, 13, 13};
-
-/*
-   Huffman code decoding is performed using a multi-level table lookup.
-   The fastest way to decode is to simply build a lookup table whose
-   size is determined by the longest code.  However, the time it takes
-   to build this table can also be a factor if the data being decoded
-   is not very long.  The most common codes are necessarily the
-   shortest codes, so those codes dominate the decoding time, and hence
-   the speed.  The idea is you can have a shorter table that decodes the
-   shorter, more probable codes, and then point to subsidiary tables for
-   the longer codes.  The time it costs to decode the longer codes is
-   then traded against the time it takes to make longer tables.
-
-   This results of this trade are in the variables lbits and dbits
-   below.  lbits is the number of bits the first level table for literal/
-   length codes can decode in one step, and dbits is the same thing for
-   the distance codes.  Subsequent tables are also less than or equal to
-   those sizes.  These values may be adjusted either when all of the
-   codes are shorter than that, in which case the longest code length in
-   bits is used, or when the shortest code is *longer* than the requested
-   table size, in which case the length of the shortest code in bits is
-   used.
-
-   There are two different values for the two tables, since they code a
-   different number of possibilities each.  The literal/length table
-   codes 286 possible values, or in a flat code, a little over eight
-   bits.  The distance table codes 30 possible values, or a little less
-   than five bits, flat.  The optimum values for speed end up being
-   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
-   The optimum values may differ though from machine to machine, and
-   possibly even between compilers.  Your mileage may vary.
- */
-
-
-/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
-#define BMAX 15         /* maximum bit length of any code */
-#define N_MAX 288       /* maximum number of codes in any set */
-
-#ifdef DEBUG_ZLIB
-  uInt inflate_hufts;
-#endif
-
-local int huft_build(b, n, s, d, e, t, m, zs)
-uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
-uInt n;                 /* number of codes (assumed <= N_MAX) */
-uInt s;                 /* number of simple-valued codes (0..s-1) */
-const uIntf *d;         /* list of base values for non-simple codes */
-const uIntf *e;         /* list of extra bits for non-simple codes */
-inflate_huft * FAR *t;  /* result: starting table */
-uIntf *m;               /* maximum lookup bits, returns actual */
-z_streamp zs;           /* for zalloc function */
-/* Given a list of code lengths and a maximum table size, make a set of
-   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
-   if the given code set is incomplete (the tables are still built in this
-   case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
-   lengths), or Z_MEM_ERROR if not enough memory. */
-{
-
-  uInt a;                       /* counter for codes of length k */
-  uInt c[BMAX+1];               /* bit length count table */
-  uInt f;                       /* i repeats in table every f entries */
-  int g;                        /* maximum code length */
-  int h;                        /* table level */
-  register uInt i;              /* counter, current code */
-  register uInt j;              /* counter */
-  register int k;               /* number of bits in current code */
-  int l;                        /* bits per table (returned in m) */
-  register uIntf *p;            /* pointer into c[], b[], or v[] */
-  inflate_huft *q;              /* points to current table */
-  struct inflate_huft_s r;      /* table entry for structure assignment */
-  inflate_huft *u[BMAX];        /* table stack */
-  uInt v[N_MAX];                /* values in order of bit length */
-  register int w;               /* bits before this table == (l * h) */
-  uInt x[BMAX+1];               /* bit offsets, then code stack */
-  uIntf *xp;                    /* pointer into x */
-  int y;                        /* number of dummy codes added */
-  uInt z;                       /* number of entries in current table */
-
-
-  /* Generate counts for each bit length */
-  p = c;
-#define C0 *p++ = 0;
-#define C2 C0 C0 C0 C0
-#define C4 C2 C2 C2 C2
-  C4                            /* clear c[]--assume BMAX+1 is 16 */
-  p = b;  i = n;
-  do {
-    c[*p++]++;                  /* assume all entries <= BMAX */
-  } while (--i);
-  if (c[0] == n)                /* null input--all zero length codes */
-  {
-    *t = (inflate_huft *)Z_NULL;
-    *m = 0;
-    return Z_OK;
-  }
-
-
-  /* Find minimum and maximum length, bound *m by those */
-  l = *m;
-  for (j = 1; j <= BMAX; j++)
-    if (c[j])
-      break;
-  k = j;                        /* minimum code length */
-  if ((uInt)l < j)
-    l = j;
-  for (i = BMAX; i; i--)
-    if (c[i])
-      break;
-  g = i;                        /* maximum code length */
-  if ((uInt)l > i)
-    l = i;
-  *m = l;
-
-
-  /* Adjust last length count to fill out codes, if needed */
-  for (y = 1 << j; j < i; j++, y <<= 1)
-    if ((y -= c[j]) < 0)
-      return Z_DATA_ERROR;
-  if ((y -= c[i]) < 0)
-    return Z_DATA_ERROR;
-  c[i] += y;
-
-
-  /* Generate starting offsets into the value table for each length */
-  x[1] = j = 0;
-  p = c + 1;  xp = x + 2;
-  while (--i) {                 /* note that i == g from above */
-    *xp++ = (j += *p++);
-  }
-
-
-  /* Make a table of values in order of bit lengths */
-  p = b;  i = 0;
-  do {
-    if ((j = *p++) != 0)
-      v[x[j]++] = i;
-  } while (++i < n);
-  n = x[g];                   /* set n to length of v */
-
-
-  /* Generate the Huffman codes and for each, make the table entries */
-  x[0] = i = 0;                 /* first Huffman code is zero */
-  p = v;                        /* grab values in bit order */
-  h = -1;                       /* no tables yet--level -1 */
-  w = -l;                       /* bits decoded == (l * h) */
-  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
-  q = (inflate_huft *)Z_NULL;   /* ditto */
-  z = 0;                        /* ditto */
-
-  /* go through the bit lengths (k already is bits in shortest code) */
-  for (; k <= g; k++)
-  {
-    a = c[k];
-    while (a--)
-    {
-      /* here i is the Huffman code of length k bits for value *p */
-      /* make tables up to required level */
-      while (k > w + l)
-      {
-        h++;
-        w += l;                 /* previous table always l bits */
-
-        /* compute minimum size table less than or equal to l bits */
-        z = g - w;
-        z = z > (uInt)l ? l : z;        /* table size upper limit */
-        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
-        {                       /* too few codes for k-w bit table */
-          f -= a + 1;           /* deduct codes from patterns left */
-          xp = c + k;
-          if (j < z)
-            while (++j < z)     /* try smaller tables up to z bits */
-            {
-              if ((f <<= 1) <= *++xp)
-                break;          /* enough codes to use up j bits */
-              f -= *xp;         /* else deduct codes from patterns */
-            }
-        }
-        z = 1 << j;             /* table entries for j-bit table */
-
-        /* allocate and link in new table */
-        if ((q = (inflate_huft *)ZALLOC
-             (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
-        {
-          if (h)
-            inflate_trees_free(u[0], zs);
-          return Z_MEM_ERROR;   /* not enough memory */
-        }
-#ifdef DEBUG_ZLIB
-        inflate_hufts += z + 1;
-#endif
-        *t = q + 1;             /* link to list for huft_free() */
-        *(t = &(q->next)) = Z_NULL;
-        u[h] = ++q;             /* table starts after link */
-
-        /* connect to last table, if there is one */
-        if (h)
-        {
-          x[h] = i;             /* save pattern for backing up */
-          r.bits = (Byte)l;     /* bits to dump before this table */
-          r.exop = (Byte)j;     /* bits in this table */
-          r.next = q;           /* pointer to this table */
-          j = i >> (w - l);     /* (get around Turbo C bug) */
-          u[h-1][j] = r;        /* connect to last table */
-        }
-      }
-
-      /* set up table entry in r */
-      r.bits = (Byte)(k - w);
-      if (p >= v + n)
-        r.exop = 128 + 64;      /* out of values--invalid code */
-      else if (*p < s)
-      {
-        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
-        r.base = *p++;          /* simple code is just the value */
-      }
-      else
-      {
-        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
-        r.base = d[*p++ - s];
-      }
-
-      /* fill code-like entries with r */
-      f = 1 << (k - w);
-      for (j = i >> w; j < z; j += f)
-        q[j] = r;
-
-      /* backwards increment the k-bit code i */
-      for (j = 1 << (k - 1); i & j; j >>= 1)
-        i ^= j;
-      i ^= j;
-
-      /* backup over finished tables */
-      while ((i & ((1 << w) - 1)) != x[h])
-      {
-        h--;                    /* don't need to update q */
-        w -= l;
-      }
-    }
-  }
-
-
-  /* Return Z_BUF_ERROR if we were given an incomplete table */
-  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
-}
-
-
-int inflate_trees_bits(c, bb, tb, z)
-uIntf *c;               /* 19 code lengths */
-uIntf *bb;              /* bits tree desired/actual depth */
-inflate_huft * FAR *tb; /* bits tree result */
-z_streamp z;            /* for zfree function */
-{
-  int r;
-
-  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
-  if (r == Z_DATA_ERROR)
-    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
-  else if (r == Z_BUF_ERROR || *bb == 0)
-  {
-    inflate_trees_free(*tb, z);
-    z->msg = (char*)"incomplete dynamic bit lengths tree";
-    r = Z_DATA_ERROR;
-  }
-  return r;
-}
-
-
-int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
-uInt nl;                /* number of literal/length codes */
-uInt nd;                /* number of distance codes */
-uIntf *c;               /* that many (total) code lengths */
-uIntf *bl;              /* literal desired/actual bit depth */
-uIntf *bd;              /* distance desired/actual bit depth */
-inflate_huft * FAR *tl; /* literal/length tree result */
-inflate_huft * FAR *td; /* distance tree result */
-z_streamp z;            /* for zfree function */
-{
-  int r;
-
-  /* build literal/length tree */
-  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z);
-  if (r != Z_OK || *bl == 0)
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed literal/length tree";
-    else if (r != Z_MEM_ERROR)
-    {
-      inflate_trees_free(*tl, z);
-      z->msg = (char*)"incomplete literal/length tree";
-      r = Z_DATA_ERROR;
-    }
-    return r;
-  }
-
-  /* build distance tree */
-  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z);
-  if (r != Z_OK || (*bd == 0 && nl > 257))
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed distance tree";
-    else if (r == Z_BUF_ERROR) {
-#ifdef PKZIP_BUG_WORKAROUND
-      r = Z_OK;
-    }
-#else
-      inflate_trees_free(*td, z);
-      z->msg = (char*)"incomplete distance tree";
-      r = Z_DATA_ERROR;
-    }
-    else if (r != Z_MEM_ERROR)
-    {
-      z->msg = (char*)"empty distance tree with lengths";
-      r = Z_DATA_ERROR;
-    }
-    inflate_trees_free(*tl, z);
-    return r;
-#endif
-  }
-
-  /* done */
-  return Z_OK;
-}
-
-
-/* build fixed tables only once--keep them here */
-local int fixed_built = 0;
-#define FIXEDH 530      /* number of hufts used by fixed tables */
-local inflate_huft fixed_mem[FIXEDH];
-local uInt fixed_bl;
-local uInt fixed_bd;
-local inflate_huft *fixed_tl;
-local inflate_huft *fixed_td;
-
-
-local voidpf falloc(q, n, s)
-voidpf q;       /* opaque pointer */
-uInt n;         /* number of items */
-uInt s;         /* size of item */
-{
-  Assert(s == sizeof(inflate_huft) && n <= *(intf *)q,
-         "inflate_trees falloc overflow");
-  *(intf *)q -= n+s-s; /* s-s to avoid warning */
-  return (voidpf)(fixed_mem + *(intf *)q);
-}
-
-
-int inflate_trees_fixed(bl, bd, tl, td)
-uIntf *bl;               /* literal desired/actual bit depth */
-uIntf *bd;               /* distance desired/actual bit depth */
-inflate_huft * FAR *tl;  /* literal/length tree result */
-inflate_huft * FAR *td;  /* distance tree result */
-{
-  /* build fixed tables if not already (multiple overlapped executions ok) */
-  if (!fixed_built)
-  {
-    int k;              /* temporary variable */
-    unsigned c[288];    /* length list for huft_build */
-    z_stream z;         /* for falloc function */
-    int f = FIXEDH;     /* number of hufts left in fixed_mem */
-
-    /* set up fake z_stream for memory routines */
-    z.zalloc = falloc;
-    z.zfree = Z_NULL;
-    z.opaque = (voidpf)&f;
-
-    /* literal table */
-    for (k = 0; k < 144; k++)
-      c[k] = 8;
-    for (; k < 256; k++)
-      c[k] = 9;
-    for (; k < 280; k++)
-      c[k] = 7;
-    for (; k < 288; k++)
-      c[k] = 8;
-    fixed_bl = 7;
-    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
-
-    /* distance table */
-    for (k = 0; k < 30; k++)
-      c[k] = 5;
-    fixed_bd = 5;
-    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
-
-    /* done */
-    Assert(f == 0, "invalid build of fixed tables");
-    fixed_built = 1;
-  }
-  *bl = fixed_bl;
-  *bd = fixed_bd;
-  *tl = fixed_tl;
-  *td = fixed_td;
-  return Z_OK;
-}
-
-
-int inflate_trees_free(t, z)
-inflate_huft *t;        /* table to free */
-z_streamp z;            /* for zfree function */
-/* Free the malloc'ed tables built by huft_build(), which makes a linked
-   list of the tables it made, with the links in a dummy first entry of
-   each table. */
-{
-  register inflate_huft *p, *q, *r;
-
-  /* Reverse linked list */
-  p = Z_NULL;
-  q = t;
-  while (q != Z_NULL)
-  {
-    r = (q - 1)->next;
-    (q - 1)->next = p;
-    p = q;
-    q = r;
-  }
-  /* Go through linked list, freeing from the malloced (t[-1]) address. */
-  while (p != Z_NULL)
-  {
-    q = (--p)->next;
-    ZFREE(z,p);
-    p = q;
-  } 
-  return Z_OK;
-}
-/* --- inftrees.c */
-
-/* +++ infcodes.c */
-/* infcodes.c -- process literals and length/distance pairs
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-/* #include "infblock.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-
-/* +++ inffast.h */
-/* inffast.h -- header to use inffast.c
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-extern int inflate_fast OF((
-    uInt,
-    uInt,
-    inflate_huft *,
-    inflate_huft *,
-    inflate_blocks_statef *,
-    z_streamp ));
-/* --- inffast.h */
-
-/* simplify the use of the inflate_huft type with some defines */
-#define base more.Base
-#define next more.Next
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-/* inflate codes private state */
-struct inflate_codes_state {
-
-  /* mode */
-  enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
-      START,    /* x: set up for LEN */
-      LEN,      /* i: get length/literal/eob next */
-      LENEXT,   /* i: getting length extra (have base) */
-      DIST,     /* i: get distance next */
-      DISTEXT,  /* i: getting distance extra */
-      COPY,     /* o: copying bytes in window, waiting for space */
-      LIT,      /* o: got literal, waiting for output space */
-      WASH,     /* o: got eob, possibly still output waiting */
-      END,      /* x: got eob and all data flushed */
-      BADCODE}  /* x: got error */
-    mode;               /* current inflate_codes mode */
-
-  /* mode dependent information */
-  uInt len;
-  union {
-    struct {
-      inflate_huft *tree;       /* pointer into tree */
-      uInt need;                /* bits needed */
-    } code;             /* if LEN or DIST, where in tree */
-    uInt lit;           /* if LIT, literal */
-    struct {
-      uInt get;                 /* bits to get for extra */
-      uInt dist;                /* distance back to copy from */
-    } copy;             /* if EXT or COPY, where and how much */
-  } sub;                /* submode */
-
-  /* mode independent information */
-  Byte lbits;           /* ltree bits decoded per branch */
-  Byte dbits;           /* dtree bits decoder per branch */
-  inflate_huft *ltree;          /* literal/length/eob tree */
-  inflate_huft *dtree;          /* distance tree */
-
-};
-
-
-inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-z_streamp z;
-{
-  inflate_codes_statef *c;
-
-  if ((c = (inflate_codes_statef *)
-       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
-  {
-    c->mode = START;
-    c->lbits = (Byte)bl;
-    c->dbits = (Byte)bd;
-    c->ltree = tl;
-    c->dtree = td;
-    Tracev((stderr, "inflate:       codes new\n"));
-  }
-  return c;
-}
-
-
-int inflate_codes(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt j;               /* temporary storage */
-  inflate_huft *t;      /* temporary pointer */
-  uInt e;               /* extra bits or operation */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Bytef *p;             /* input data pointer */
-  uInt n;               /* bytes available there */
-  Bytef *q;             /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-  Bytef *f;             /* pointer to copy strings from */
-  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
-
-  /* copy input/output information to locals (UPDATE macro restores) */
-  LOAD
-
-  /* process input and output based on current state */
-  while (1) switch (c->mode)
-  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
-    case START:         /* x: set up for LEN */
-#ifndef SLOW
-      if (m >= 258 && n >= 10)
-      {
-        UPDATE
-        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
-        LOAD
-        if (r != Z_OK)
-        {
-          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
-          break;
-        }
-      }
-#endif /* !SLOW */
-      c->sub.code.need = c->lbits;
-      c->sub.code.tree = c->ltree;
-      c->mode = LEN;
-    case LEN:           /* i: get length/literal/eob next */
-      j = c->sub.code.need;
-      NEEDBITS(j)
-      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
-      DUMPBITS(t->bits)
-      e = (uInt)(t->exop);
-      if (e == 0)               /* literal */
-      {
-        c->sub.lit = t->base;
-        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-                 "inflate:         literal '%c'\n" :
-                 "inflate:         literal 0x%02x\n", t->base));
-        c->mode = LIT;
-        break;
-      }
-      if (e & 16)               /* length */
-      {
-        c->sub.copy.get = e & 15;
-        c->len = t->base;
-        c->mode = LENEXT;
-        break;
-      }
-      if ((e & 64) == 0)        /* next table */
-      {
-        c->sub.code.need = e;
-        c->sub.code.tree = t->next;
-        break;
-      }
-      if (e & 32)               /* end of block */
-      {
-        Tracevv((stderr, "inflate:         end of block\n"));
-        c->mode = WASH;
-        break;
-      }
-      c->mode = BADCODE;        /* invalid code */
-      z->msg = (char*)"invalid literal/length code";
-      r = Z_DATA_ERROR;
-      LEAVE
-    case LENEXT:        /* i: getting length extra (have base) */
-      j = c->sub.copy.get;
-      NEEDBITS(j)
-      c->len += (uInt)b & inflate_mask[j];
-      DUMPBITS(j)
-      c->sub.code.need = c->dbits;
-      c->sub.code.tree = c->dtree;
-      Tracevv((stderr, "inflate:         length %u\n", c->len));
-      c->mode = DIST;
-    case DIST:          /* i: get distance next */
-      j = c->sub.code.need;
-      NEEDBITS(j)
-      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
-      DUMPBITS(t->bits)
-      e = (uInt)(t->exop);
-      if (e & 16)               /* distance */
-      {
-        c->sub.copy.get = e & 15;
-        c->sub.copy.dist = t->base;
-        c->mode = DISTEXT;
-        break;
-      }
-      if ((e & 64) == 0)        /* next table */
-      {
-        c->sub.code.need = e;
-        c->sub.code.tree = t->next;
-        break;
-      }
-      c->mode = BADCODE;        /* invalid code */
-      z->msg = (char*)"invalid distance code";
-      r = Z_DATA_ERROR;
-      LEAVE
-    case DISTEXT:       /* i: getting distance extra */
-      j = c->sub.copy.get;
-      NEEDBITS(j)
-      c->sub.copy.dist += (uInt)b & inflate_mask[j];
-      DUMPBITS(j)
-      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
-      c->mode = COPY;
-    case COPY:          /* o: copying bytes in window, waiting for space */
-#ifndef __TURBOC__ /* Turbo C bug for following expression */
-      f = (uInt)(q - s->window) < c->sub.copy.dist ?
-          s->end - (c->sub.copy.dist - (q - s->window)) :
-          q - c->sub.copy.dist;
-#else
-      f = q - c->sub.copy.dist;
-      if ((uInt)(q - s->window) < c->sub.copy.dist)
-        f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
-#endif
-      while (c->len)
-      {
-        NEEDOUT
-        OUTBYTE(*f++)
-        if (f == s->end)
-          f = s->window;
-        c->len--;
-      }
-      c->mode = START;
-      break;
-    case LIT:           /* o: got literal, waiting for output space */
-      NEEDOUT
-      OUTBYTE(c->sub.lit)
-      c->mode = START;
-      break;
-    case WASH:          /* o: got eob, possibly more output */
-      FLUSH
-      if (s->read != s->write)
-        LEAVE
-      c->mode = END;
-    case END:
-      r = Z_STREAM_END;
-      LEAVE
-    case BADCODE:       /* x: got error */
-      r = Z_DATA_ERROR;
-      LEAVE
-    default:
-      r = Z_STREAM_ERROR;
-      LEAVE
-  }
-}
-
-
-void inflate_codes_free(c, z)
-inflate_codes_statef *c;
-z_streamp z;
-{
-  ZFREE(z, c);
-  Tracev((stderr, "inflate:       codes free\n"));
-}
-/* --- infcodes.c */
-
-/* +++ infutil.c */
-/* inflate_util.c -- data and routines common to blocks and codes
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "infblock.h" */
-/* #include "inftrees.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* And'ing with mask[n] masks the lower n bits */
-uInt inflate_mask[17] = {
-    0x0000,
-    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
-    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-};
-
-
-/* copy as much as possible from the sliding window to the output area */
-int inflate_flush(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt n;
-  Bytef *p;
-  Bytef *q;
-
-  /* local copies of source and destination pointers */
-  p = z->next_out;
-  q = s->read;
-
-  /* compute number of bytes to copy as far as end of window */
-  n = (uInt)((q <= s->write ? s->write : s->end) - q);
-  if (n > z->avail_out) n = z->avail_out;
-  if (n && r == Z_BUF_ERROR) r = Z_OK;
-
-  /* update counters */
-  z->avail_out -= n;
-  z->total_out += n;
-
-  /* update check information */
-  if (s->checkfn != Z_NULL)
-    z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-  /* copy as far as end of window */
-  if (p != Z_NULL) {
-    zmemcpy(p, q, n);
-    p += n;
-  }
-  q += n;
-
-  /* see if more to copy at beginning of window */
-  if (q == s->end)
-  {
-    /* wrap pointers */
-    q = s->window;
-    if (s->write == s->end)
-      s->write = s->window;
-
-    /* compute bytes to copy */
-    n = (uInt)(s->write - q);
-    if (n > z->avail_out) n = z->avail_out;
-    if (n && r == Z_BUF_ERROR) r = Z_OK;
-
-    /* update counters */
-    z->avail_out -= n;
-    z->total_out += n;
-
-    /* update check information */
-    if (s->checkfn != Z_NULL)
-      z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-    /* copy */
-    if (p != Z_NULL) {
-      zmemcpy(p, q, n);
-      p += n;
-    }
-    q += n;
-  }
-
-  /* update pointers */
-  z->next_out = p;
-  s->read = q;
-
-  /* done */
-  return r;
-}
-/* --- infutil.c */
-
-/* +++ inffast.c */
-/* inffast.c -- process literals and length/distance pairs fast
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-/* #include "infblock.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-/* #include "inffast.h" */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* simplify the use of the inflate_huft type with some defines */
-#define base more.Base
-#define next more.Next
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-/* macros for bit input with no checking and for returning unused bytes */
-#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;}
-
-/* Called with number of bytes left to write in window at least 258
-   (the maximum string length) and number of input bytes available
-   at least ten.  The ten bytes are six bytes for the longest length/
-   distance pair plus four bytes for overloading the bit buffer. */
-
-int inflate_fast(bl, bd, tl, td, s, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-inflate_blocks_statef *s;
-z_streamp z;
-{
-  inflate_huft *t;      /* temporary pointer */
-  uInt e;               /* extra bits or operation */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Bytef *p;             /* input data pointer */
-  uInt n;               /* bytes available there */
-  Bytef *q;             /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-  uInt ml;              /* mask for literal/length tree */
-  uInt md;              /* mask for distance tree */
-  uInt c;               /* bytes to copy */
-  uInt d;               /* distance back to copy from */
-  Bytef *r;             /* copy source pointer */
-
-  /* load input, output, bit values */
-  LOAD
-
-  /* initialize masks */
-  ml = inflate_mask[bl];
-  md = inflate_mask[bd];
-
-  /* do until not enough input or output space for fast loop */
-  do {                          /* assume called with m >= 258 && n >= 10 */
-    /* get literal/length code */
-    GRABBITS(20)                /* max bits for literal/length code */
-    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
-    {
-      DUMPBITS(t->bits)
-      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-                "inflate:         * literal '%c'\n" :
-                "inflate:         * literal 0x%02x\n", t->base));
-      *q++ = (Byte)t->base;
-      m--;
-      continue;
-    }
-    do {
-      DUMPBITS(t->bits)
-      if (e & 16)
-      {
-        /* get extra bits for length */
-        e &= 15;
-        c = t->base + ((uInt)b & inflate_mask[e]);
-        DUMPBITS(e)
-        Tracevv((stderr, "inflate:         * length %u\n", c));
-
-        /* decode distance base of block to copy */
-        GRABBITS(15);           /* max bits for distance code */
-        e = (t = td + ((uInt)b & md))->exop;
-        do {
-          DUMPBITS(t->bits)
-          if (e & 16)
-          {
-            /* get extra bits to add to distance base */
-            e &= 15;
-            GRABBITS(e)         /* get extra bits (up to 13) */
-            d = t->base + ((uInt)b & inflate_mask[e]);
-            DUMPBITS(e)
-            Tracevv((stderr, "inflate:         * distance %u\n", d));
-
-            /* do the copy */
-            m -= c;
-            if ((uInt)(q - s->window) >= d)     /* offset before dest */
-            {                                   /*  just copy */
-              r = q - d;
-              *q++ = *r++;  c--;        /* minimum count is three, */
-              *q++ = *r++;  c--;        /*  so unroll loop a little */
-            }
-            else                        /* else offset after destination */
-            {
-              e = d - (uInt)(q - s->window); /* bytes from offset to end */
-              r = s->end - e;           /* pointer to offset */
-              if (c > e)                /* if source crosses, */
-              {
-                c -= e;                 /* copy to end of window */
-                do {
-                  *q++ = *r++;
-                } while (--e);
-                r = s->window;          /* copy rest from start of window */
-              }
-            }
-            do {                        /* copy all or what's left */
-              *q++ = *r++;
-            } while (--c);
-            break;
-          }
-          else if ((e & 64) == 0)
-            e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
-          else
-          {
-            z->msg = (char*)"invalid distance code";
-            UNGRAB
-            UPDATE
-            return Z_DATA_ERROR;
-          }
-        } while (1);
-        break;
-      }
-      if ((e & 64) == 0)
-      {
-        if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
-        {
-          DUMPBITS(t->bits)
-          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-                    "inflate:         * literal '%c'\n" :
-                    "inflate:         * literal 0x%02x\n", t->base));
-          *q++ = (Byte)t->base;
-          m--;
-          break;
-        }
-      }
-      else if (e & 32)
-      {
-        Tracevv((stderr, "inflate:         * end of block\n"));
-        UNGRAB
-        UPDATE
-        return Z_STREAM_END;
-      }
-      else
-      {
-        z->msg = (char*)"invalid literal/length code";
-        UNGRAB
-        UPDATE
-        return Z_DATA_ERROR;
-      }
-    } while (1);
-  } while (m >= 258 && n >= 10);
-
-  /* not enough input or output--restore pointers and return */
-  UNGRAB
-  UPDATE
-  return Z_OK;
-}
-/* --- inffast.c */
-
-/* +++ zutil.c */
-/* zutil.c -- target dependent utility functions for the compression library
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */
-
-/* #include "zutil.h" */
-
-#ifndef NO_DUMMY_DECL
-struct internal_state      {int dummy;}; /* for buggy compilers */
-#endif
-
-#ifndef STDC
-extern void exit OF((int));
-#endif
-
-const char *z_errmsg[10] = {
-"need dictionary",     /* Z_NEED_DICT       2  */
-"stream end",          /* Z_STREAM_END      1  */
-"",                    /* Z_OK              0  */
-"file error",          /* Z_ERRNO         (-1) */
-"stream error",        /* Z_STREAM_ERROR  (-2) */
-"data error",          /* Z_DATA_ERROR    (-3) */
-"insufficient memory", /* Z_MEM_ERROR     (-4) */
-"buffer error",        /* Z_BUF_ERROR     (-5) */
-"incompatible version",/* Z_VERSION_ERROR (-6) */
-""};
-
-
-const char *zlibVersion()
-{
-    return ZLIB_VERSION;
-}
-
-#ifdef DEBUG_ZLIB
-void z_error (m)
-    char *m;
-{
-    fprintf(stderr, "%s\n", m);
-    exit(1);
-}
-#endif
-
-#ifndef HAVE_MEMCPY
-
-void zmemcpy(dest, source, len)
-    Bytef* dest;
-    Bytef* source;
-    uInt  len;
-{
-    if (len == 0) return;
-    do {
-        *dest++ = *source++; /* ??? to be unrolled */
-    } while (--len != 0);
-}
-
-int zmemcmp(s1, s2, len)
-    Bytef* s1;
-    Bytef* s2;
-    uInt  len;
-{
-    uInt j;
-
-    for (j = 0; j < len; j++) {
-        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
-    }
-    return 0;
-}
-
-void zmemzero(dest, len)
-    Bytef* dest;
-    uInt  len;
-{
-    if (len == 0) return;
-    do {
-        *dest++ = 0;  /* ??? to be unrolled */
-    } while (--len != 0);
-}
-#endif
-
-#ifdef __TURBOC__
-#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
-/* Small and medium model in Turbo C are for now limited to near allocation
- * with reduced MAX_WBITS and MAX_MEM_LEVEL
- */
-#  define MY_ZCALLOC
-
-/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
- * and farmalloc(64K) returns a pointer with an offset of 8, so we
- * must fix the pointer. Warning: the pointer must be put back to its
- * original form in order to free it, use zcfree().
- */
-
-#define MAX_PTR 10
-/* 10*64K = 640K */
-
-local int next_ptr = 0;
-
-typedef struct ptr_table_s {
-    voidpf org_ptr;
-    voidpf new_ptr;
-} ptr_table;
-
-local ptr_table table[MAX_PTR];
-/* This table is used to remember the original form of pointers
- * to large buffers (64K). Such pointers are normalized with a zero offset.
- * Since MSDOS is not a preemptive multitasking OS, this table is not
- * protected from concurrent access. This hack doesn't work anyway on
- * a protected system like OS/2. Use Microsoft C instead.
- */
-
-voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
-{
-    voidpf buf = opaque; /* just to make some compilers happy */
-    ulg bsize = (ulg)items*size;
-
-    /* If we allocate less than 65520 bytes, we assume that farmalloc
-     * will return a usable pointer which doesn't have to be normalized.
-     */
-    if (bsize < 65520L) {
-        buf = farmalloc(bsize);
-        if (*(ush*)&buf != 0) return buf;
-    } else {
-        buf = farmalloc(bsize + 16L);
-    }
-    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
-    table[next_ptr].org_ptr = buf;
-
-    /* Normalize the pointer to seg:0 */
-    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
-    *(ush*)&buf = 0;
-    table[next_ptr++].new_ptr = buf;
-    return buf;
-}
-
-void  zcfree (voidpf opaque, voidpf ptr)
-{
-    int n;
-    if (*(ush*)&ptr != 0) { /* object < 64K */
-        farfree(ptr);
-        return;
-    }
-    /* Find the original pointer */
-    for (n = 0; n < next_ptr; n++) {
-        if (ptr != table[n].new_ptr) continue;
-
-        farfree(table[n].org_ptr);
-        while (++n < next_ptr) {
-            table[n-1] = table[n];
-        }
-        next_ptr--;
-        return;
-    }
-    ptr = opaque; /* just to make some compilers happy */
-    Assert(0, "zcfree: ptr not found");
-}
-#endif
-#endif /* __TURBOC__ */
-
-
-#if defined(M_I86) && !defined(__32BIT__)
-/* Microsoft C in 16-bit mode */
-
-#  define MY_ZCALLOC
-
-#if (!defined(_MSC_VER) || (_MSC_VER < 600))
-#  define _halloc  halloc
-#  define _hfree   hfree
-#endif
-
-voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
-{
-    if (opaque) opaque = 0; /* to make compiler happy */
-    return _halloc((long)items, size);
-}
-
-void  zcfree (voidpf opaque, voidpf ptr)
-{
-    if (opaque) opaque = 0; /* to make compiler happy */
-    _hfree(ptr);
-}
-
-#endif /* MSC */
-
-
-#ifndef MY_ZCALLOC /* Any system without a special alloc function */
-
-#ifndef STDC
-extern voidp  calloc OF((uInt items, uInt size));
-extern void   free   OF((voidpf ptr));
-#endif
-
-voidpf zcalloc (opaque, items, size)
-    voidpf opaque;
-    unsigned items;
-    unsigned size;
-{
-    if (opaque) items += size - size; /* make compiler happy */
-    return (voidpf)calloc(items, size);
-}
-
-void  zcfree (opaque, ptr)
-    voidpf opaque;
-    voidpf ptr;
-{
-    free(ptr);
-    if (opaque) return; /* make compiler happy */
-}
-
-#endif /* MY_ZCALLOC */
-/* --- zutil.c */
-
-/* +++ adler32.c */
-/* adler32.c -- compute the Adler-32 checksum of a data stream
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */
-
-/* #include "zlib.h" */
-
-#define BASE 65521L /* largest prime smaller than 65536 */
-#define NMAX 5552
-/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
-
-#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
-#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
-#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
-#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
-#define DO16(buf)   DO8(buf,0); DO8(buf,8);
-
-/* ========================================================================= */
-uLong adler32(adler, buf, len)
-    uLong adler;
-    const Bytef *buf;
-    uInt len;
-{
-    unsigned long s1 = adler & 0xffff;
-    unsigned long s2 = (adler >> 16) & 0xffff;
-    int k;
-
-    if (buf == Z_NULL) return 1L;
-
-    while (len > 0) {
-        k = len < NMAX ? len : NMAX;
-        len -= k;
-        while (k >= 16) {
-            DO16(buf);
-	    buf += 16;
-            k -= 16;
-        }
-        if (k != 0) do {
-            s1 += *buf++;
-	    s2 += s1;
-        } while (--k);
-        s1 %= BASE;
-        s2 %= BASE;
-    }
-    return (s2 << 16) | s1;
-}
-/* --- adler32.c */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jffs2/zlib.h linux-2.4.20/fs/jffs2/zlib.h
--- linux-2.4.19/fs/jffs2/zlib.h	2001-09-14 21:04:07.000000000 +0000
+++ linux-2.4.20/fs/jffs2/zlib.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,1010 +0,0 @@
-/*	$Id: zlib.h,v 1.2 1997/12/23 10:47:44 paulus Exp $	*/
-
-/*
- * This file is derived from zlib.h and zconf.h from the zlib-1.0.4
- * distribution by Jean-loup Gailly and Mark Adler, with some additions
- * by Paul Mackerras to aid in implementing Deflate compression and
- * decompression for PPP packets.
- */
-
-/*
- *  ==FILEVERSION 971127==
- *
- * This marker is used by the Linux installation script to determine
- * whether an up-to-date version of this file is already installed.
- */
-
-
-/* +++ zlib.h */
-/* zlib.h -- interface of the 'zlib' general purpose compression library
-  version 1.0.4, Jul 24th, 1996.
-
-  Copyright (C) 1995-1996 Jean-loup Gailly and Mark Adler
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  Jean-loup Gailly        Mark Adler
-  gzip@prep.ai.mit.edu    madler@alumni.caltech.edu
-
-
-  The data format used by the zlib library is described by RFCs (Request for
-  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
-  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
-*/
-
-#ifndef _ZLIB_H
-#define _ZLIB_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* +++ zconf.h */
-/* zconf.h -- configuration of the zlib compression library
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: zconf.h,v 1.20 1996/07/02 15:09:28 me Exp $ */
-
-#ifndef _ZCONF_H
-#define _ZCONF_H
-
-/*
- * If you *really* need a unique prefix for all types and library functions,
- * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
- */
-#ifdef Z_PREFIX
-#  define deflateInit_	z_deflateInit_
-#  define deflate	z_deflate
-#  define deflateEnd	z_deflateEnd
-#  define inflateInit_ 	z_inflateInit_
-#  define inflate	z_inflate
-#  define inflateEnd	z_inflateEnd
-#  define deflateInit2_	z_deflateInit2_
-#  define deflateSetDictionary z_deflateSetDictionary
-#  define deflateCopy	z_deflateCopy
-#  define deflateReset	z_deflateReset
-#  define deflateParams	z_deflateParams
-#  define inflateInit2_	z_inflateInit2_
-#  define inflateSetDictionary z_inflateSetDictionary
-#  define inflateSync	z_inflateSync
-#  define inflateReset	z_inflateReset
-#  define compress	z_compress
-#  define uncompress	z_uncompress
-#  define adler32	z_adler32
-#  define crc32		z_crc32
-#  define get_crc_table z_get_crc_table
-
-#  define Byte		z_Byte
-#  define uInt		z_uInt
-#  define uLong		z_uLong
-#  define Bytef	        z_Bytef
-#  define charf		z_charf
-#  define intf		z_intf
-#  define uIntf		z_uIntf
-#  define uLongf	z_uLongf
-#  define voidpf	z_voidpf
-#  define voidp		z_voidp
-#endif
-
-#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
-#  define WIN32
-#endif
-#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
-#  ifndef __32BIT__
-#    define __32BIT__
-#  endif
-#endif
-#if defined(__MSDOS__) && !defined(MSDOS)
-#  define MSDOS
-#endif
-
-/*
- * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
- * than 64k bytes at a time (needed on systems with 16-bit int).
- */
-#if defined(MSDOS) && !defined(__32BIT__)
-#  define MAXSEG_64K
-#endif
-#ifdef MSDOS
-#  define UNALIGNED_OK
-#endif
-
-#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
-#  define STDC
-#endif
-#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC)
-#  define STDC
-#endif
-
-#ifndef STDC
-#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
-#    define const
-#  endif
-#endif
-
-/* Some Mac compilers merge all .h files incorrectly: */
-#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
-#  define NO_DUMMY_DECL
-#endif
-
-/* Maximum value for memLevel in deflateInit2 */
-#ifndef MAX_MEM_LEVEL
-#  ifdef MAXSEG_64K
-#    define MAX_MEM_LEVEL 8
-#  else
-#    define MAX_MEM_LEVEL 9
-#  endif
-#endif
-
-/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
-#ifndef MAX_WBITS
-#  define MAX_WBITS   15 /* 32K LZ77 window */
-#endif
-
-/* The memory requirements for deflate are (in bytes):
-            1 << (windowBits+2)   +  1 << (memLevel+9)
- that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
- plus a few kilobytes for small objects. For example, if you want to reduce
- the default memory requirements from 256K to 128K, compile with
-     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
- Of course this will generally degrade compression (there's no free lunch).
-
-   The memory requirements for inflate are (in bytes) 1 << windowBits
- that is, 32K for windowBits=15 (default value) plus a few kilobytes
- for small objects.
-*/
-
-                        /* Type declarations */
-
-#ifndef OF /* function prototypes */
-#  ifdef STDC
-#    define OF(args)  args
-#  else
-#    define OF(args)  ()
-#  endif
-#endif
-
-/* The following definitions for FAR are needed only for MSDOS mixed
- * model programming (small or medium model with some far allocations).
- * This was tested only with MSC; for other MSDOS compilers you may have
- * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
- * just define FAR to be empty.
- */
-#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
-   /* MSC small or medium model */
-#  define SMALL_MEDIUM
-#  ifdef _MSC_VER
-#    define FAR __far
-#  else
-#    define FAR far
-#  endif
-#endif
-#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
-#  ifndef __32BIT__
-#    define SMALL_MEDIUM
-#    define FAR __far
-#  endif
-#endif
-#ifndef FAR
-#   define FAR
-#endif
-
-typedef unsigned char  Byte;  /* 8 bits */
-typedef unsigned int   uInt;  /* 16 bits or more */
-typedef unsigned long  uLong; /* 32 bits or more */
-
-#if defined(__BORLANDC__) && defined(SMALL_MEDIUM)
-   /* Borland C/C++ ignores FAR inside typedef */
-#  define Bytef Byte FAR
-#else
-   typedef Byte  FAR Bytef;
-#endif
-typedef char  FAR charf;
-typedef int   FAR intf;
-typedef uInt  FAR uIntf;
-typedef uLong FAR uLongf;
-
-#ifdef STDC
-   typedef void FAR *voidpf;
-   typedef void     *voidp;
-#else
-   typedef Byte FAR *voidpf;
-   typedef Byte     *voidp;
-#endif
-
-
-/* Compile with -DZLIB_DLL for Windows DLL support */
-#if (defined(_WINDOWS) || defined(WINDOWS)) && defined(ZLIB_DLL)
-#  include <windows.h>
-#  define EXPORT  WINAPI
-#else
-#  define EXPORT
-#endif
-
-#endif /* _ZCONF_H */
-/* --- zconf.h */
-
-#define ZLIB_VERSION "1.0.4P"
-
-/* 
-     The 'zlib' compression library provides in-memory compression and
-  decompression functions, including integrity checks of the uncompressed
-  data.  This version of the library supports only one compression method
-  (deflation) but other algorithms may be added later and will have the same
-  stream interface.
-
-     For compression the application must provide the output buffer and
-  may optionally provide the input buffer for optimization. For decompression,
-  the application must provide the input buffer and may optionally provide
-  the output buffer for optimization.
-
-     Compression can be done in a single step if the buffers are large
-  enough (for example if an input file is mmap'ed), or can be done by
-  repeated calls of the compression function.  In the latter case, the
-  application must provide more input and/or consume the output
-  (providing more output space) before each call.
-
-     The library does not install any signal handler. It is recommended to
-  add at least a handler for SIGSEGV when decompressing; the library checks
-  the consistency of the input data whenever possible but may go nuts
-  for some forms of corrupted input.
-*/
-
-typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
-typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
-
-struct internal_state;
-
-typedef struct z_stream_s {
-    Bytef    *next_in;  /* next input byte */
-    uInt     avail_in;  /* number of bytes available at next_in */
-    uLong    total_in;  /* total nb of input bytes read so far */
-
-    Bytef    *next_out; /* next output byte should be put there */
-    uInt     avail_out; /* remaining free space at next_out */
-    uLong    total_out; /* total nb of bytes output so far */
-
-    char     *msg;      /* last error message, NULL if no error */
-    struct internal_state FAR *state; /* not visible by applications */
-
-    alloc_func zalloc;  /* used to allocate the internal state */
-    free_func  zfree;   /* used to free the internal state */
-    voidpf     opaque;  /* private data object passed to zalloc and zfree */
-
-    int     data_type;  /* best guess about the data type: ascii or binary */
-    uLong   adler;      /* adler32 value of the uncompressed data */
-    uLong   reserved;   /* reserved for future use */
-} z_stream;
-
-typedef z_stream FAR *z_streamp;
-
-/*
-   The application must update next_in and avail_in when avail_in has
-   dropped to zero. It must update next_out and avail_out when avail_out
-   has dropped to zero. The application must initialize zalloc, zfree and
-   opaque before calling the init function. All other fields are set by the
-   compression library and must not be updated by the application.
-
-   The opaque value provided by the application will be passed as the first
-   parameter for calls of zalloc and zfree. This can be useful for custom
-   memory management. The compression library attaches no meaning to the
-   opaque value.
-
-   zalloc must return Z_NULL if there is not enough memory for the object.
-   On 16-bit systems, the functions zalloc and zfree must be able to allocate
-   exactly 65536 bytes, but will not be required to allocate more than this
-   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
-   pointers returned by zalloc for objects of exactly 65536 bytes *must*
-   have their offset normalized to zero. The default allocation function
-   provided by this library ensures this (see zutil.c). To reduce memory
-   requirements and avoid any allocation of 64K objects, at the expense of
-   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
-
-   The fields total_in and total_out can be used for statistics or
-   progress reports. After compression, total_in holds the total size of
-   the uncompressed data and may be saved for use in the decompressor
-   (particularly if the decompressor wants to decompress everything in
-   a single step).
-*/
-
-                        /* constants */
-
-#define Z_NO_FLUSH      0
-#define Z_PARTIAL_FLUSH 1
-#define Z_PACKET_FLUSH	2
-#define Z_SYNC_FLUSH    3
-#define Z_FULL_FLUSH    4
-#define Z_FINISH        5
-/* Allowed flush values; see deflate() below for details */
-
-#define Z_OK            0
-#define Z_STREAM_END    1
-#define Z_NEED_DICT     2
-#define Z_ERRNO        (-1)
-#define Z_STREAM_ERROR (-2)
-#define Z_DATA_ERROR   (-3)
-#define Z_MEM_ERROR    (-4)
-#define Z_BUF_ERROR    (-5)
-#define Z_VERSION_ERROR (-6)
-/* Return codes for the compression/decompression functions. Negative
- * values are errors, positive values are used for special but normal events.
- */
-
-#define Z_NO_COMPRESSION         0
-#define Z_BEST_SPEED             1
-#define Z_BEST_COMPRESSION       9
-#define Z_DEFAULT_COMPRESSION  (-1)
-/* compression levels */
-
-#define Z_FILTERED            1
-#define Z_HUFFMAN_ONLY        2
-#define Z_DEFAULT_STRATEGY    0
-/* compression strategy; see deflateInit2() below for details */
-
-#define Z_BINARY   0
-#define Z_ASCII    1
-#define Z_UNKNOWN  2
-/* Possible values of the data_type field */
-
-#define Z_DEFLATED   8
-/* The deflate compression method (the only one supported in this version) */
-
-#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
-
-#define zlib_version zlibVersion()
-/* for compatibility with versions < 1.0.2 */
-
-                        /* basic functions */
-
-extern const char * EXPORT zlibVersion OF((void));
-/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
-   If the first character differs, the library code actually used is
-   not compatible with the zlib.h header file used by the application.
-   This check is automatically made by deflateInit and inflateInit.
- */
-
-/* 
-extern int EXPORT deflateInit OF((z_streamp strm, int level));
-
-     Initializes the internal stream state for compression. The fields
-   zalloc, zfree and opaque must be initialized before by the caller.
-   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
-   use default allocation functions.
-
-     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
-   1 gives best speed, 9 gives best compression, 0 gives no compression at
-   all (the input data is simply copied a block at a time).
-   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
-   compression (currently equivalent to level 6).
-
-     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
-   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
-   with the version assumed by the caller (ZLIB_VERSION).
-   msg is set to null if there is no error message.  deflateInit does not
-   perform any compression: this will be done by deflate().
-*/
-
-
-extern int EXPORT deflate OF((z_streamp strm, int flush));
-/*
-  Performs one or both of the following actions:
-
-  - Compress more input starting at next_in and update next_in and avail_in
-    accordingly. If not all input can be processed (because there is not
-    enough room in the output buffer), next_in and avail_in are updated and
-    processing will resume at this point for the next call of deflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly. This action is forced if the parameter flush is non zero.
-    Forcing flush frequently degrades the compression ratio, so this parameter
-    should be set only when necessary (in interactive applications).
-    Some output may be provided even if flush is not set.
-
-  Before the call of deflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating avail_in or avail_out accordingly; avail_out
-  should never be zero before the call. The application can consume the
-  compressed output when it wants, for example when the output buffer is full
-  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
-  and with zero avail_out, it must be called again after making room in the
-  output buffer because there might be more output pending.
-
-    If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
-  block is terminated and flushed to the output buffer so that the
-  decompressor can get all input data available so far. For method 9, a future
-  variant on method 8, the current block will be flushed but not terminated.
-  Z_SYNC_FLUSH has the same effect as partial flush except that the compressed
-  output is byte aligned (the compressor can clear its internal bit buffer)
-  and the current block is always terminated; this can be useful if the
-  compressor has to be restarted from scratch after an interruption (in which
-  case the internal state of the compressor may be lost).
-    If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
-  special marker is output and the compression dictionary is discarded; this
-  is useful to allow the decompressor to synchronize if one compressed block
-  has been damaged (see inflateSync below).  Flushing degrades compression and
-  so should be used only when necessary.  Using Z_FULL_FLUSH too often can
-  seriously degrade the compression. If deflate returns with avail_out == 0,
-  this function must be called again with the same value of the flush
-  parameter and more output space (updated avail_out), until the flush is
-  complete (deflate returns with non-zero avail_out).
-
-    If the parameter flush is set to Z_PACKET_FLUSH, the compression
-  block is terminated, and a zero-length stored block is output,
-  omitting the length bytes (the effect of this is that the 3-bit type
-  code 000 for a stored block is output, and the output is then
-  byte-aligned).  This is designed for use at the end of a PPP packet.
-
-    If the parameter flush is set to Z_FINISH, pending input is processed,
-  pending output is flushed and deflate returns with Z_STREAM_END if there
-  was enough output space; if deflate returns with Z_OK, this function must be
-  called again with Z_FINISH and more output space (updated avail_out) but no
-  more input data, until it returns with Z_STREAM_END or an error. After
-  deflate has returned Z_STREAM_END, the only possible operations on the
-  stream are deflateReset or deflateEnd.
-  
-    Z_FINISH can be used immediately after deflateInit if all the compression
-  is to be done in a single step. In this case, avail_out must be at least
-  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
-  Z_STREAM_END, then it must be called again as described above.
-
-    deflate() may update data_type if it can make a good guess about
-  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
-  binary. This field is only for information purposes and does not affect
-  the compression algorithm in any manner.
-
-    deflate() returns Z_OK if some progress has been made (more input
-  processed or more output produced), Z_STREAM_END if all input has been
-  consumed and all output has been produced (only when flush is set to
-  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
-  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible.
-*/
-
-
-extern int EXPORT deflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
-   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
-   prematurely (some input or output was discarded). In the error case,
-   msg may be set but then points to a static string (which must not be
-   deallocated).
-*/
-
-
-/* 
-extern int EXPORT inflateInit OF((z_streamp strm));
-
-     Initializes the internal stream state for decompression. The fields
-   zalloc, zfree and opaque must be initialized before by the caller.  If
-   zalloc and zfree are set to Z_NULL, inflateInit updates them to use default
-   allocation functions.
-
-     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_VERSION_ERROR if the zlib library version is incompatible
-   with the version assumed by the caller.  msg is set to null if there is no
-   error message. inflateInit does not perform any decompression: this will be
-   done by inflate().
-*/
-
-
-extern int EXPORT inflate OF((z_streamp strm, int flush));
-/*
-  Performs one or both of the following actions:
-
-  - Decompress more input starting at next_in and update next_in and avail_in
-    accordingly. If not all input can be processed (because there is not
-    enough room in the output buffer), next_in is updated and processing
-    will resume at this point for the next call of inflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly.  inflate() provides as much output as possible, until there
-    is no more input data or no more space in the output buffer (see below
-    about the flush parameter).
-
-  Before the call of inflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating the next_* and avail_* values accordingly.
-  The application can consume the uncompressed output when it wants, for
-  example when the output buffer is full (avail_out == 0), or after each
-  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
-  must be called again after making room in the output buffer because there
-  might be more output pending.
-
-    If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
-  inflate flushes as much output as possible to the output buffer. The
-  flushing behavior of inflate is not specified for values of the flush
-  parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
-  current implementation actually flushes as much output as possible
-  anyway.  For Z_PACKET_FLUSH, inflate checks that once all the input data
-  has been consumed, it is expecting to see the length field of a stored
-  block; if not, it returns Z_DATA_ERROR.
-
-    inflate() should normally be called until it returns Z_STREAM_END or an
-  error. However if all decompression is to be performed in a single step
-  (a single call of inflate), the parameter flush should be set to
-  Z_FINISH. In this case all pending input is processed and all pending
-  output is flushed; avail_out must be large enough to hold all the
-  uncompressed data. (The size of the uncompressed data may have been saved
-  by the compressor for this purpose.) The next operation on this stream must
-  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
-  is never required, but can be used to inform inflate that a faster routine
-  may be used for the single inflate() call.
-
-    inflate() returns Z_OK if some progress has been made (more input
-  processed or more output produced), Z_STREAM_END if the end of the
-  compressed data has been reached and all uncompressed output has been
-  produced, Z_NEED_DICT if a preset dictionary is needed at this point (see
-  inflateSetDictionary below), Z_DATA_ERROR if the input data was corrupted,
-  Z_STREAM_ERROR if the stream structure was inconsistent (for example if
-  next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
-  Z_BUF_ERROR if no progress is possible or if there was not enough room in
-  the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the
-  application may then call inflateSync to look for a good compression block.
-  In the Z_NEED_DICT case, strm->adler is set to the Adler32 value of the
-  dictionary chosen by the compressor.
-*/
-
-
-extern int EXPORT inflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
-   was inconsistent. In the error case, msg may be set but then points to a
-   static string (which must not be deallocated).
-*/
-
-                        /* Advanced functions */
-
-/*
-    The following functions are needed only in some special applications.
-*/
-
-/*   
-extern int EXPORT deflateInit2 OF((z_streamp strm,
-                                   int  level,
-                                   int  method,
-                                   int  windowBits,
-                                   int  memLevel,
-                                   int  strategy));
-
-     This is another version of deflateInit with more compression options. The
-   fields next_in, zalloc, zfree and opaque must be initialized before by
-   the caller.
-
-     The method parameter is the compression method. It must be Z_DEFLATED in
-   this version of the library. (Method 9 will allow a 64K history buffer and
-   partial block flushes.)
-
-     The windowBits parameter is the base two logarithm of the window size
-   (the size of the history buffer).  It should be in the range 8..15 for this
-   version of the library (the value 16 will be allowed for method 9). Larger
-   values of this parameter result in better compression at the expense of
-   memory usage. The default value is 15 if deflateInit is used instead.
-
-     The memLevel parameter specifies how much memory should be allocated
-   for the internal compression state. memLevel=1 uses minimum memory but
-   is slow and reduces compression ratio; memLevel=9 uses maximum memory
-   for optimal speed. The default value is 8. See zconf.h for total memory
-   usage as a function of windowBits and memLevel.
-
-     The strategy parameter is used to tune the compression algorithm. Use the
-   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
-   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
-   string match).  Filtered data consists mostly of small values with a
-   somewhat random distribution. In this case, the compression algorithm is
-   tuned to compress them better. The effect of Z_FILTERED is to force more
-   Huffman coding and less string matching; it is somewhat intermediate
-   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
-   the compression ratio but not the correctness of the compressed output even
-   if it is not set appropriately.
-
-     If next_in is not null, the library will use this buffer to hold also
-   some history information; the buffer must either hold the entire input
-   data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in
-   is null, the library will allocate its own history buffer (and leave next_in
-   null). next_out need not be provided here but must be provided by the
-   application for the next call of deflate().
-
-     If the history buffer is provided by the application, next_in must
-   must never be changed by the application since the compressor maintains
-   information inside this buffer from call to call; the application
-   must provide more input only by increasing avail_in. next_in is always
-   reset by the library in this case.
-
-      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
-   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
-   an invalid method). msg is set to null if there is no error message.
-   deflateInit2 does not perform any compression: this will be done by
-   deflate(). 
-*/
-                            
-extern int EXPORT deflateSetDictionary OF((z_streamp strm,
-                                           const Bytef *dictionary,
-				           uInt  dictLength));
-/*
-     Initializes the compression dictionary (history buffer) from the given
-   byte sequence without producing any compressed output. This function must
-   be called immediately after deflateInit or deflateInit2, before any call
-   of deflate. The compressor and decompressor must use exactly the same
-   dictionary (see inflateSetDictionary).
-     The dictionary should consist of strings (byte sequences) that are likely
-   to be encountered later in the data to be compressed, with the most commonly
-   used strings preferably put towards the end of the dictionary. Using a
-   dictionary is most useful when the data to be compressed is short and
-   can be predicted with good accuracy; the data can then be compressed better
-   than with the default empty dictionary. In this version of the library,
-   only the last 32K bytes of the dictionary are used.
-     Upon return of this function, strm->adler is set to the Adler32 value
-   of the dictionary; the decompressor may later use this value to determine
-   which dictionary has been used by the compressor. (The Adler32 value
-   applies to the whole dictionary even if only a subset of the dictionary is
-   actually used by the compressor.)
-
-     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state
-   is inconsistent (for example if deflate has already been called for this
-   stream). deflateSetDictionary does not perform any compression: this will
-   be done by deflate(). 
-*/
-
-extern int EXPORT deflateCopy OF((z_streamp dest,
-                                  z_streamp source));
-/*
-     Sets the destination stream as a complete copy of the source stream.  If
-   the source stream is using an application-supplied history buffer, a new
-   buffer is allocated for the destination stream.  The compressed output
-   buffer is always application-supplied. It's the responsibility of the
-   application to provide the correct values of next_out and avail_out for the
-   next call of deflate.
-
-     This function can be useful when several compression strategies will be
-   tried, for example when there are several ways of pre-processing the input
-   data with a filter. The streams that will be discarded should then be freed
-   by calling deflateEnd.  Note that deflateCopy duplicates the internal
-   compression state which can be quite large, so this strategy is slow and
-   can consume lots of memory.
-
-     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
-   (such as zalloc being NULL). msg is left unchanged in both source and
-   destination.
-*/
-
-extern int EXPORT deflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to deflateEnd followed by deflateInit,
-   but does not free and reallocate all the internal compression state.
-   The stream will keep the same compression level and any other attributes
-   that may have been set by deflateInit2.
-
-      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent (such as zalloc or state being NULL).
-*/
-
-extern int EXPORT deflateParams OF((z_streamp strm, int level, int strategy));
-/*
-     Dynamically update the compression level and compression strategy.
-   This can be used to switch between compression and straight copy of
-   the input data, or to switch to a different kind of input data requiring
-   a different strategy. If the compression level is changed, the input
-   available so far is compressed with the old level (and may be flushed);
-   the new level will take effect only at the next call of deflate().
-
-     Before the call of deflateParams, the stream state must be set as for
-   a call of deflate(), since the currently available input may have to
-   be compressed and flushed. In particular, strm->avail_out must be non-zero.
-
-     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
-   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
-   if strm->avail_out was zero.
-*/
-
-extern int EXPORT deflateOutputPending OF((z_streamp strm));
-/*
-     Returns the number of bytes of output which are immediately
-   available from the compressor (i.e. without any further input
-   or flush).
-*/
-
-/*   
-extern int EXPORT inflateInit2 OF((z_streamp strm,
-                                   int  windowBits));
-
-     This is another version of inflateInit with more compression options. The
-   fields next_out, zalloc, zfree and opaque must be initialized before by
-   the caller.
-
-     The windowBits parameter is the base two logarithm of the maximum window
-   size (the size of the history buffer).  It should be in the range 8..15 for
-   this version of the library (the value 16 will be allowed soon). The
-   default value is 15 if inflateInit is used instead. If a compressed stream
-   with a larger window size is given as input, inflate() will return with
-   the error code Z_DATA_ERROR instead of trying to allocate a larger window.
-
-     If next_out is not null, the library will use this buffer for the history
-   buffer; the buffer must either be large enough to hold the entire output
-   data, or have at least 1<<windowBits bytes.  If next_out is null, the
-   library will allocate its own buffer (and leave next_out null). next_in
-   need not be provided here but must be provided by the application for the
-   next call of inflate().
-
-     If the history buffer is provided by the application, next_out must
-   never be changed by the application since the decompressor maintains
-   history information inside this buffer from call to call; the application
-   can only reset next_out to the beginning of the history buffer when
-   avail_out is zero and all output has been consumed.
-
-      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
-   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
-   windowBits < 8). msg is set to null if there is no error message.
-   inflateInit2 does not perform any decompression: this will be done by
-   inflate().
-*/
-
-extern int EXPORT inflateSetDictionary OF((z_streamp strm,
-				           const Bytef *dictionary,
-					   uInt  dictLength));
-/*
-     Initializes the decompression dictionary (history buffer) from the given
-   uncompressed byte sequence. This function must be called immediately after
-   a call of inflate if this call returned Z_NEED_DICT. The dictionary chosen
-   by the compressor can be determined from the Adler32 value returned by this
-   call of inflate. The compressor and decompressor must use exactly the same
-   dictionary (see deflateSetDictionary).
-
-     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state is
-   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
-   expected one (incorrect Adler32 value). inflateSetDictionary does not
-   perform any decompression: this will be done by subsequent calls of
-   inflate().
-*/
-
-extern int EXPORT inflateSync OF((z_streamp strm));
-/* 
-    Skips invalid compressed data until the special marker (see deflate()
-  above) can be found, or until all available input is skipped. No output
-  is provided.
-
-    inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
-  if no more input was provided, Z_DATA_ERROR if no marker has been found,
-  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
-  case, the application may save the current current value of total_in which
-  indicates where valid compressed data was found. In the error case, the
-  application may repeatedly call inflateSync, providing more input each time,
-  until success or end of the input data.
-*/
-
-extern int EXPORT inflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to inflateEnd followed by inflateInit,
-   but does not free and reallocate all the internal decompression state.
-   The stream will keep attributes that may have been set by inflateInit2.
-
-      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent (such as zalloc or state being NULL).
-*/
-
-extern int inflateIncomp OF((z_stream *strm));
-/*
-     This function adds the data at next_in (avail_in bytes) to the output
-   history without performing any output.  There must be no pending output,
-   and the decompressor must be expecting to see the start of a block.
-   Calling this function is equivalent to decompressing a stored block
-   containing the data at next_in (except that the data is not output).
-*/
-
-                        /* utility functions */
-
-/*
-     The following utility functions are implemented on top of the
-   basic stream-oriented functions. To simplify the interface, some
-   default options are assumed (compression level, window size,
-   standard memory allocation functions). The source code of these
-   utility functions can easily be modified if you need special options.
-*/
-
-extern int EXPORT compress OF((Bytef *dest,   uLongf *destLen,
-			       const Bytef *source, uLong sourceLen));
-/*
-     Compresses the source buffer into the destination buffer.  sourceLen is
-   the byte length of the source buffer. Upon entry, destLen is the total
-   size of the destination buffer, which must be at least 0.1% larger than
-   sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
-   compressed buffer.
-     This function can be used to compress a whole file at once if the
-   input file is mmap'ed.
-     compress returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_BUF_ERROR if there was not enough room in the output
-   buffer.
-*/
-
-extern int EXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
-				 const Bytef *source, uLong sourceLen));
-/*
-     Decompresses the source buffer into the destination buffer.  sourceLen is
-   the byte length of the source buffer. Upon entry, destLen is the total
-   size of the destination buffer, which must be large enough to hold the
-   entire uncompressed data. (The size of the uncompressed data must have
-   been saved previously by the compressor and transmitted to the decompressor
-   by some mechanism outside the scope of this compression library.)
-   Upon exit, destLen is the actual size of the compressed buffer.
-     This function can be used to decompress a whole file at once if the
-   input file is mmap'ed.
-
-     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_BUF_ERROR if there was not enough room in the output
-   buffer, or Z_DATA_ERROR if the input data was corrupted.
-*/
-
-
-typedef voidp gzFile;
-
-extern gzFile EXPORT gzopen  OF((const char *path, const char *mode));
-/*
-     Opens a gzip (.gz) file for reading or writing. The mode parameter
-   is as in fopen ("rb" or "wb") but can also include a compression level
-   ("wb9").  gzopen can be used to read a file which is not in gzip format;
-   in this case gzread will directly read from the file without decompression.
-     gzopen returns NULL if the file could not be opened or if there was
-   insufficient memory to allocate the (de)compression state; errno
-   can be checked to distinguish the two cases (if errno is zero, the
-   zlib error is Z_MEM_ERROR).
-*/
-
-extern gzFile EXPORT gzdopen  OF((int fd, const char *mode));
-/*
-     gzdopen() associates a gzFile with the file descriptor fd.  File
-   descriptors are obtained from calls like open, dup, creat, pipe or
-   fileno (in the file has been previously opened with fopen).
-   The mode parameter is as in gzopen.
-     The next call of gzclose on the returned gzFile will also close the
-   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
-   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
-     gzdopen returns NULL if there was insufficient memory to allocate
-   the (de)compression state.
-*/
-
-extern int EXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
-/*
-     Reads the given number of uncompressed bytes from the compressed file.
-   If the input file was not in gzip format, gzread copies the given number
-   of bytes into the buffer.
-     gzread returns the number of uncompressed bytes actually read (0 for
-   end of file, -1 for error). */
-
-extern int EXPORT    gzwrite OF((gzFile file, const voidp buf, unsigned len));
-/*
-     Writes the given number of uncompressed bytes into the compressed file.
-   gzwrite returns the number of uncompressed bytes actually written
-   (0 in case of error).
-*/
-
-extern int EXPORT    gzflush OF((gzFile file, int flush));
-/*
-     Flushes all pending output into the compressed file. The parameter
-   flush is as in the deflate() function. The return value is the zlib
-   error number (see function gzerror below). gzflush returns Z_OK if
-   the flush parameter is Z_FINISH and all output could be flushed.
-     gzflush should be called only when strictly necessary because it can
-   degrade compression.
-*/
-
-extern int EXPORT    gzclose OF((gzFile file));
-/*
-     Flushes all pending output if necessary, closes the compressed file
-   and deallocates all the (de)compression state. The return value is the zlib
-   error number (see function gzerror below).
-*/
-
-extern const char * EXPORT gzerror OF((gzFile file, int *errnum));
-/*
-     Returns the error message for the last error which occurred on the
-   given compressed file. errnum is set to zlib error number. If an
-   error occurred in the file system and not in the compression library,
-   errnum is set to Z_ERRNO and the application may consult errno
-   to get the exact error code.
-*/
-
-                        /* checksum functions */
-
-/*
-     These functions are not related to compression but are exported
-   anyway because they might be useful in applications using the
-   compression library.
-*/
-
-extern uLong EXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
-
-/*
-     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
-   return the updated checksum. If buf is NULL, this function returns
-   the required initial value for the checksum.
-   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
-   much faster. Usage example:
-
-     uLong adler = adler32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       adler = adler32(adler, buffer, length);
-     }
-     if (adler != original_adler) error();
-*/
-
-extern uLong EXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
-/*
-     Update a running crc with the bytes buf[0..len-1] and return the updated
-   crc. If buf is NULL, this function returns the required initial value
-   for the crc. Pre- and post-conditioning (one's complement) is performed
-   within this function so it shouldn't be done by the application.
-   Usage example:
-
-     uLong crc = crc32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       crc = crc32(crc, buffer, length);
-     }
-     if (crc != original_crc) error();
-*/
-
-
-                        /* various hacks, don't look :) */
-
-/* deflateInit and inflateInit are macros to allow checking the zlib version
- * and the compiler's view of z_stream:
- */
-extern int EXPORT deflateInit_ OF((z_streamp strm, int level,
-			           const char *version, int stream_size));
-extern int EXPORT inflateInit_ OF((z_streamp strm,
-				   const char *version, int stream_size));
-extern int EXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
-				    int windowBits, int memLevel, int strategy,
-				    const char *version, int stream_size));
-extern int EXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
-				    const char *version, int stream_size));
-#define deflateInit(strm, level) \
-        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
-#define inflateInit(strm) \
-        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
-#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
-        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
-		      (strategy),           ZLIB_VERSION, sizeof(z_stream))
-#define inflateInit2(strm, windowBits) \
-        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
-
-#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
-    struct internal_state {int dummy;}; /* hack for buggy compilers */
-#endif
-
-uLongf *get_crc_table OF((void)); /* can be used by asm versions of crc32() */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ZLIB_H */
-/* --- zlib.h */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/Makefile linux-2.4.20/fs/jfs/Makefile
--- linux-2.4.19/fs/jfs/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/Makefile	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,15 @@
+#
+# Makefile for the Linux JFS filesystem routines.
+#
+
+O_TARGET := jfs.o
+obj-y   := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \
+	    jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \
+	    jfs_unicode.o jfs_dtree.o jfs_inode.o \
+	    jfs_extent.o symlink.o jfs_metapage.o \
+	    jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o resize.o xattr.o
+obj-m   := $(O_TARGET)
+
+EXTRA_CFLAGS += -D_JFS_4K
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/file.c linux-2.4.20/fs/jfs/file.c
--- linux-2.4.19/fs/jfs/file.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/file.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,157 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *
+ *   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
+ */
+
+#include <linux/fs.h>
+#include "jfs_incore.h"
+#include "jfs_dmap.h"
+#include "jfs_txnmgr.h"
+#include "jfs_xattr.h"
+#include "jfs_debug.h"
+
+
+extern int jfs_commit_inode(struct inode *, int);
+
+int jfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+	struct inode *inode = dentry->d_inode;
+	int rc = 0;
+
+	rc = fsync_inode_data_buffers(inode);
+
+	if (!(inode->i_state & I_DIRTY))
+		return rc;
+	if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+		return rc;
+
+	rc |= jfs_commit_inode(inode, 1);
+
+	return rc ? -EIO : 0;
+}
+
+/*
+ * Guts of jfs_truncate.  Called with locks already held.  Can be called
+ * with directory for truncating directory index table.
+ */
+void jfs_truncate_nolock(struct inode *ip, loff_t length)
+{
+	loff_t newsize;
+	tid_t tid;
+
+	ASSERT(length >= 0);
+
+	if (test_cflag(COMMIT_Nolink, ip)) {
+		xtTruncate(0, ip, length, COMMIT_WMAP);
+		return;
+	}
+
+	do {
+		tid = txBegin(ip->i_sb, 0);
+
+		/*
+		 * The commit_sem cannot be taken before txBegin.
+		 * txBegin may block and there is a chance the inode
+		 * could be marked dirty and need to be committed
+		 * before txBegin unblocks
+		 */
+		down(&JFS_IP(ip)->commit_sem);
+
+		newsize = xtTruncate(tid, ip, length,
+				     COMMIT_TRUNCATE | COMMIT_PWMAP);
+		if (newsize < 0) {
+			txEnd(tid);
+			up(&JFS_IP(ip)->commit_sem);
+			break;
+		}
+
+		ip->i_mtime = ip->i_ctime = CURRENT_TIME;
+		mark_inode_dirty(ip);
+
+		txCommit(tid, 1, &ip, 0);
+		txEnd(tid);
+		up(&JFS_IP(ip)->commit_sem);
+	} while (newsize > length);	/* Truncate isn't always atomic */
+}
+
+static void jfs_truncate(struct inode *ip)
+{
+	jFYI(1, ("jfs_truncate: size = 0x%lx\n", (ulong) ip->i_size));
+
+	IWRITE_LOCK(ip);
+	jfs_truncate_nolock(ip, ip->i_size);
+	IWRITE_UNLOCK(ip);
+}
+
+static int jfs_open(struct inode *inode, struct file *file)
+{
+	int rc;
+
+	if ((rc = generic_file_open(inode, file)))
+		return rc;
+
+	/*
+	 * We attempt to allow only one "active" file open per aggregate
+	 * group.  Otherwise, appending to files in parallel can cause
+	 * fragmentation within the files.
+	 *
+	 * If the file is empty, it was probably just created and going
+	 * to be written to.  If it has a size, we'll hold off until the
+	 * file is actually grown.
+	 */
+	if (S_ISREG(inode->i_mode) && file->f_mode & FMODE_WRITE &&
+	    (inode->i_size == 0)) {
+		struct jfs_inode_info *ji = JFS_IP(inode);
+		if (ji->active_ag == -1) {
+			ji->active_ag = ji->agno;
+			atomic_inc(
+			    &JFS_SBI(inode->i_sb)->bmap->db_active[ji->agno]);
+		}
+	}
+
+	return 0;
+}
+static int jfs_release(struct inode *inode, struct file *file)
+{
+	struct jfs_inode_info *ji = JFS_IP(inode);
+
+	if (ji->active_ag != -1) {
+		struct bmap *bmap = JFS_SBI(inode->i_sb)->bmap;
+		atomic_dec(&bmap->db_active[ji->active_ag]);
+		ji->active_ag = -1;
+	}
+
+	return 0;
+}
+
+struct inode_operations jfs_file_inode_operations = {
+	.truncate	= jfs_truncate,
+	.setxattr	= jfs_setxattr,
+	.getxattr	= jfs_getxattr,
+	.listxattr	= jfs_listxattr,
+	.removexattr	= jfs_removexattr,
+};
+
+struct file_operations jfs_file_operations = {
+	.open		= jfs_open,
+	.llseek		= generic_file_llseek,
+	.write		= generic_file_write,
+	.read		= generic_file_read,
+	.mmap		= generic_file_mmap,
+	.fsync		= jfs_fsync,
+	.release	= jfs_release,
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/inode.c linux-2.4.20/fs/jfs/inode.c
--- linux-2.4.19/fs/jfs/inode.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/inode.c	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,341 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *
+ *   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
+ */
+
+#include <linux/fs.h>
+//#include <linux/locks.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_imap.h"
+#include "jfs_extent.h"
+#include "jfs_unicode.h"
+#include "jfs_debug.h"
+
+
+extern struct inode_operations jfs_dir_inode_operations;
+extern struct inode_operations jfs_file_inode_operations;
+extern struct inode_operations jfs_symlink_inode_operations;
+extern struct file_operations jfs_dir_operations;
+extern struct file_operations jfs_file_operations;
+struct address_space_operations jfs_aops;
+extern int freeZeroLink(struct inode *);
+
+void jfs_clear_inode(struct inode *inode)
+{
+	struct jfs_inode_info *ji = JFS_IP(inode);
+
+	jFYI(1, ("jfs_clear_inode called ip = 0x%p\n", inode));
+
+	if (ji->active_ag != -1) {
+		printk(KERN_ERR "jfs_clear_inode, active_ag = %d\n",
+		       ji->active_ag);
+		printk(KERN_ERR "i_ino = %ld, i_mode = %o\n",
+		       inode->i_ino, inode->i_mode);
+	}
+
+	ASSERT(list_empty(&ji->mp_list));
+	ASSERT(list_empty(&ji->anon_inode_list));
+
+	if (ji->atlhead) {
+		jERROR(1, ("jfs_clear_inode: inode %p has anonymous tlocks\n",
+					inode));
+		jERROR(1, ("i_state = 0x%lx, cflag = 0x%lx\n",
+					inode->i_state, ji->cflag));
+	}
+
+	free_jfs_inode(inode);
+}
+
+void jfs_read_inode(struct inode *inode)
+{
+	int rc;
+
+	rc = alloc_jfs_inode(inode);
+	if (rc) {
+		jFYI(1, ("In jfs_read_inode, alloc_jfs_inode failed"));
+		goto bad_inode;
+	}
+	jFYI(1, ("In jfs_read_inode, inode = 0x%p\n", inode));
+
+	if (diRead(inode))
+		goto bad_inode_free;
+
+	if (S_ISREG(inode->i_mode)) {
+		inode->i_op = &jfs_file_inode_operations;
+		inode->i_fop = &jfs_file_operations;
+		inode->i_mapping->a_ops = &jfs_aops;
+	} else if (S_ISDIR(inode->i_mode)) {
+		inode->i_op = &jfs_dir_inode_operations;
+		inode->i_fop = &jfs_dir_operations;
+		inode->i_mapping->a_ops = &jfs_aops;
+		inode->i_mapping->gfp_mask = GFP_NOFS;
+	} else if (S_ISLNK(inode->i_mode)) {
+		if (inode->i_size > IDATASIZE) {
+			inode->i_op = &page_symlink_inode_operations;
+			inode->i_mapping->a_ops = &jfs_aops;
+		} else
+			inode->i_op = &jfs_symlink_inode_operations;
+	} else {
+		inode->i_op = &jfs_file_inode_operations;
+		init_special_inode(inode, inode->i_mode,
+				   kdev_t_to_nr(inode->i_rdev));
+	}
+
+	return;
+
+      bad_inode_free:
+	free_jfs_inode(inode);
+      bad_inode:
+	make_bad_inode(inode);
+}
+
+/* This define is from fs/open.c */
+#define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
+
+/*
+ * Workhorse of both fsync & write_inode
+ */
+int jfs_commit_inode(struct inode *inode, int wait)
+{
+	int rc = 0;
+	tid_t tid;
+	static int noisy = 5;
+
+	jFYI(1, ("In jfs_commit_inode, inode = 0x%p\n", inode));
+
+	/*
+	 * Don't commit if inode has been committed since last being
+	 * marked dirty, or if it has been deleted.
+	 */
+	if (test_cflag(COMMIT_Nolink, inode) ||
+	    !test_cflag(COMMIT_Dirty, inode))
+		return 0;
+
+	if (isReadOnly(inode)) {
+		/* kernel allows writes to devices on read-only
+		 * partitions and may think inode is dirty
+		 */
+		if (!special_file(inode->i_mode) && noisy) {
+			jERROR(1, ("jfs_commit_inode(0x%p) called on "
+				   "read-only volume\n", inode));
+			jERROR(1, ("Is remount racy?\n"));
+			noisy--;
+		}
+		return 0;
+	}
+
+	tid = txBegin(inode->i_sb, COMMIT_INODE);
+	down(&JFS_IP(inode)->commit_sem);
+	rc = txCommit(tid, 1, &inode, wait ? COMMIT_SYNC : 0);
+	txEnd(tid);
+	up(&JFS_IP(inode)->commit_sem);
+	return -rc;
+}
+
+void jfs_write_inode(struct inode *inode, int wait)
+{
+	/*
+	 * If COMMIT_DIRTY is not set, the inode isn't really dirty.
+	 * It has been committed since the last change, but was still
+	 * on the dirty inode list
+	 */
+	if (test_cflag(COMMIT_Nolink, inode) ||
+	    !test_cflag(COMMIT_Dirty, inode))
+		return;
+
+	if (jfs_commit_inode(inode, wait)) {
+		jERROR(1, ("jfs_write_inode: jfs_commit_inode failed!\n"));
+	}
+}
+
+void jfs_delete_inode(struct inode *inode)
+{
+	jFYI(1, ("In jfs_delete_inode, inode = 0x%p\n", inode));
+
+	if (test_cflag(COMMIT_Freewmap, inode))
+		freeZeroLink(inode);
+
+	diFree(inode);
+
+	clear_inode(inode);
+}
+
+void jfs_dirty_inode(struct inode *inode)
+{
+	static int noisy = 5;
+
+	if (isReadOnly(inode)) {
+		if (!special_file(inode->i_mode) && noisy) {
+			/* kernel allows writes to devices on read-only
+			 * partitions and may try to mark inode dirty
+			 */
+			jERROR(1, ("jfs_dirty_inode called on "
+				   "read-only volume\n"));
+			jERROR(1, ("Is remount racy?\n"));
+			noisy--;
+		}
+		return;
+	}
+
+	set_cflag(COMMIT_Dirty, inode);
+}
+
+static int jfs_get_block(struct inode *ip, long lblock,
+			 struct buffer_head *bh_result, int create)
+{
+	s64 lblock64 = lblock;
+	int no_size_check = 0;
+	int rc = 0;
+	int take_locks;
+	xad_t xad;
+	s64 xaddr;
+	int xflag;
+	s32 xlen;
+
+	/*
+	 * If this is a special inode (imap, dmap) or directory,
+	 * the lock should already be taken
+	 */
+	take_locks = ((JFS_IP(ip)->fileset != AGGREGATE_I) &&
+		      !S_ISDIR(ip->i_mode));
+	/*
+	 * Take appropriate lock on inode
+	 */
+	if (take_locks) {
+		if (create)
+			IWRITE_LOCK(ip);
+		else
+			IREAD_LOCK(ip);
+	}
+
+	/*
+	 * A directory's "data" is the inode index table, but i_size is the
+	 * size of the d-tree, so don't check the offset against i_size
+	 */
+	if (S_ISDIR(ip->i_mode))
+		no_size_check = 1;
+
+	if ((no_size_check ||
+	     ((lblock64 << ip->i_sb->s_blocksize_bits) < ip->i_size)) &&
+	    (xtLookup(ip, lblock64, 1, &xflag, &xaddr, &xlen, no_size_check)
+	     == 0) && xlen) {
+		if (xflag & XAD_NOTRECORDED) {
+			if (!create)
+				/*
+				 * Allocated but not recorded, read treats
+				 * this as a hole
+				 */
+				goto unlock;
+#ifdef _JFS_4K
+			XADoffset(&xad, lblock64);
+			XADlength(&xad, xlen);
+			XADaddress(&xad, xaddr);
+#else				/* _JFS_4K */
+			/*
+			 * As long as block size = 4K, this isn't a problem.
+			 * We should mark the whole page not ABNR, but how
+			 * will we know to mark the other blocks BH_New?
+			 */
+			BUG();
+#endif				/* _JFS_4K */
+			rc = extRecord(ip, &xad);
+			if (rc)
+				goto unlock;
+			bh_result->b_state |= (1UL << BH_New);
+		}
+
+		bh_result->b_dev = ip->i_dev;
+		bh_result->b_blocknr = xaddr;
+		bh_result->b_state |= (1UL << BH_Mapped);
+		goto unlock;
+	}
+	if (!create)
+		goto unlock;
+
+	/*
+	 * Allocate a new block
+	 */
+#ifdef _JFS_4K
+	if ((rc = extHint(ip, lblock64 << ip->i_sb->s_blocksize_bits, &xad)))
+		goto unlock;
+	rc = extAlloc(ip, 1, lblock64, &xad, FALSE);
+	if (rc)
+		goto unlock;
+
+	bh_result->b_dev = ip->i_dev;
+	bh_result->b_blocknr = addressXAD(&xad);
+	bh_result->b_state |= ((1UL << BH_Mapped) | (1UL << BH_New));
+
+#else				/* _JFS_4K */
+	/*
+	 * We need to do whatever it takes to keep all but the last buffers
+	 * in 4K pages - see jfs_write.c
+	 */
+	BUG();
+#endif				/* _JFS_4K */
+
+      unlock:
+	/*
+	 * Release lock on inode
+	 */
+	if (take_locks) {
+		if (create)
+			IWRITE_UNLOCK(ip);
+		else
+			IREAD_UNLOCK(ip);
+	}
+	return -rc;
+}
+
+static int jfs_writepage(struct page *page)
+{
+	return block_write_full_page(page, jfs_get_block);
+}
+
+static int jfs_readpage(struct file *file, struct page *page)
+{
+	return block_read_full_page(page, jfs_get_block);
+}
+
+static int jfs_prepare_write(struct file *file,
+			     struct page *page, unsigned from, unsigned to)
+{
+	return block_prepare_write(page, from, to, jfs_get_block);
+}
+
+static int jfs_bmap(struct address_space *mapping, long block)
+{
+	return generic_block_bmap(mapping, block, jfs_get_block);
+}
+
+static int jfs_direct_IO(int rw, struct inode *inode, struct kiobuf *iobuf,
+			 unsigned long blocknr, int blocksize)
+{
+	return generic_direct_IO(rw, inode, iobuf, blocknr,
+				 blocksize, jfs_get_block);
+}
+
+struct address_space_operations jfs_aops = {
+	.readpage	= jfs_readpage,
+	.writepage	= jfs_writepage,
+	.sync_page	= block_sync_page,
+	.prepare_write	= jfs_prepare_write,
+	.commit_write	= generic_commit_write,
+	.bmap		= jfs_bmap,
+	.direct_IO	= jfs_direct_IO,
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_btree.h linux-2.4.20/fs/jfs/jfs_btree.h
--- linux-2.4.19/fs/jfs/jfs_btree.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_btree.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,163 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2001
+ *
+ *   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
+ */
+#ifndef	_H_JFS_BTREE
+#define _H_JFS_BTREE
+
+/*
+ *	jfs_btree.h: B+-tree
+ *
+ * JFS B+-tree (dtree and xtree) common definitions
+ */
+
+/*
+ *	basic btree page - btpage
+ *
+struct btpage {
+	s64 next;		right sibling bn
+	s64 prev;		left sibling bn
+
+	u8 flag;
+	u8 rsrvd[7];		type specific
+	s64 self;		self address
+
+	u8 entry[4064];
+};						*/
+
+/* btpaget_t flag */
+#define BT_TYPE		0x07	/* B+-tree index */
+#define	BT_ROOT		0x01	/* root page */
+#define	BT_LEAF		0x02	/* leaf page */
+#define	BT_INTERNAL	0x04	/* internal page */
+#define	BT_RIGHTMOST	0x10	/* rightmost page */
+#define	BT_LEFTMOST	0x20	/* leftmost page */
+#define	BT_SWAPPED	0x80	/* used by fsck for endian swapping */
+
+/* btorder (in inode) */
+#define	BT_RANDOM		0x0000
+#define	BT_SEQUENTIAL		0x0001
+#define	BT_LOOKUP		0x0010
+#define	BT_INSERT		0x0020
+#define	BT_DELETE		0x0040
+
+/*
+ *	btree page buffer cache access
+ */
+#define BT_IS_ROOT(MP) (((MP)->xflag & COMMIT_PAGE) == 0)
+
+/* get page from buffer page */
+#define BT_PAGE(IP, MP, TYPE, ROOT)\
+	(BT_IS_ROOT(MP) ? (TYPE *)&JFS_IP(IP)->ROOT : (TYPE *)(MP)->data)
+
+/* get the page buffer and the page for specified block address */
+#define BT_GETPAGE(IP, BN, MP, TYPE, SIZE, P, RC, ROOT)\
+{\
+	if ((BN) == 0)\
+	{\
+		MP = (struct metapage *)&JFS_IP(IP)->bxflag;\
+		P = (TYPE *)&JFS_IP(IP)->ROOT;\
+		RC = 0;\
+		jEVENT(0,("%d BT_GETPAGE returning root\n", __LINE__));\
+	}\
+	else\
+	{\
+		jEVENT(0,("%d BT_GETPAGE reading block %d\n", __LINE__,\
+			 (int)BN));\
+		MP = read_metapage((IP), BN, SIZE, 1);\
+		if (MP) {\
+			RC = 0;\
+			P = (MP)->data;\
+		} else {\
+			P = NULL;\
+			jERROR(1,("bread failed!\n"));\
+			RC = EIO;\
+		}\
+	}\
+}
+
+#define BT_MARK_DIRTY(MP, IP)\
+{\
+	if (BT_IS_ROOT(MP))\
+		mark_inode_dirty(IP);\
+	else\
+		mark_metapage_dirty(MP);\
+}
+
+/* put the page buffer */
+#define BT_PUTPAGE(MP)\
+{\
+	if (! BT_IS_ROOT(MP)) \
+		release_metapage(MP); \
+}
+
+
+/*
+ *	btree traversal stack
+ *
+ * record the path traversed during the search;
+ * top frame record the leaf page/entry selected.
+ */
+#define	MAXTREEHEIGHT		8
+struct btframe {	/* stack frame */
+	s64 bn;			/* 8: */
+	s16 index;		/* 2: */
+	s16 lastindex;		/* 2: */
+	struct metapage *mp;	/* 4: */
+};				/* (16) */
+
+struct btstack {
+	struct btframe *top;
+	int nsplit;
+	struct btframe stack[MAXTREEHEIGHT];
+};
+
+#define BT_CLR(btstack)\
+	(btstack)->top = (btstack)->stack
+
+#define BT_PUSH(BTSTACK, BN, INDEX)\
+{\
+	(BTSTACK)->top->bn = BN;\
+	(BTSTACK)->top->index = INDEX;\
+	++(BTSTACK)->top;\
+	assert((BTSTACK)->top != &((BTSTACK)->stack[MAXTREEHEIGHT]));\
+}
+
+#define BT_POP(btstack)\
+	( (btstack)->top == (btstack)->stack ? NULL : --(btstack)->top )
+
+#define BT_STACK(btstack)\
+	( (btstack)->top == (btstack)->stack ? NULL : (btstack)->top )
+
+/* retrieve search results */
+#define BT_GETSEARCH(IP, LEAF, BN, MP, TYPE, P, INDEX, ROOT)\
+{\
+	BN = (LEAF)->bn;\
+	MP = (LEAF)->mp;\
+	if (BN)\
+		P = (TYPE *)MP->data;\
+	else\
+		P = (TYPE *)&JFS_IP(IP)->ROOT;\
+	INDEX = (LEAF)->index;\
+}
+
+/* put the page buffer of search */
+#define BT_PUTSEARCH(BTSTACK)\
+{\
+	if (! BT_IS_ROOT((BTSTACK)->top->mp))\
+		release_metapage((BTSTACK)->top->mp);\
+}
+#endif				/* _H_JFS_BTREE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_debug.c linux-2.4.20/fs/jfs/jfs_debug.c
--- linux-2.4.19/fs/jfs/jfs_debug.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_debug.c	2002-10-29 11:18:38.000000000 +0000
@@ -0,0 +1,152 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *
+ *   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
+ */
+
+#include <linux/fs.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_debug.h"
+
+#ifdef CONFIG_JFS_DEBUG
+void dump_mem(char *label, void *data, int length)
+{
+	int i, j;
+	int *intptr = data;
+	char *charptr = data;
+	char buf[10], line[80];
+
+	printk("%s: dump of %d bytes of data at 0x%p\n\n", label, length,
+	       data);
+	for (i = 0; i < length; i += 16) {
+		line[0] = 0;
+		for (j = 0; (j < 4) && (i + j * 4 < length); j++) {
+			sprintf(buf, " %08x", intptr[i / 4 + j]);
+			strcat(line, buf);
+		}
+		buf[0] = ' ';
+		buf[2] = 0;
+		for (j = 0; (j < 16) && (i + j < length); j++) {
+			buf[1] =
+			    isprint(charptr[i + j]) ? charptr[i + j] : '.';
+			strcat(line, buf);
+		}
+		printk("%s\n", line);
+	}
+}
+#endif
+
+#ifdef PROC_FS_JFS /* see jfs_debug.h */
+
+static struct proc_dir_entry *base;
+#ifdef CONFIG_JFS_DEBUG
+extern read_proc_t jfs_txanchor_read;
+
+static int loglevel_read(char *page, char **start, off_t off,
+			 int count, int *eof, void *data)
+{
+	int len;
+
+	len = sprintf(page, "%d\n", jfsloglevel);
+
+	len -= off;
+	*start = page + off;
+
+	if (len > count)
+		len = count;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+
+static int loglevel_write(struct file *file, const char *buffer,
+			unsigned long count, void *data)
+{
+	char c;
+
+	if (get_user(c, buffer))
+		return -EFAULT;
+
+	/* yes, I know this is an ASCIIism.  --hch */
+	if (c < '0' || c > '9')
+		return -EINVAL;
+	jfsloglevel = c - '0';
+	return count;
+}
+#endif
+
+
+#ifdef CONFIG_JFS_STATISTICS
+extern read_proc_t jfs_lmstats_read;
+extern read_proc_t jfs_xtstat_read;
+extern read_proc_t jfs_mpstat_read;
+#endif
+
+static struct {
+	const char	*name;
+	read_proc_t	*read_fn;
+	write_proc_t	*write_fn;
+} Entries[] = {
+#ifdef CONFIG_JFS_STATISTICS
+	{ "lmstats",	jfs_lmstats_read, },
+	{ "xtstat",	jfs_xtstat_read, },
+	{ "mpstat",	jfs_mpstat_read, },
+#endif
+#ifdef CONFIG_JFS_DEBUG
+	{ "TxAnchor",	jfs_txanchor_read, },
+	{ "loglevel",	loglevel_read, loglevel_write }
+#endif
+};
+#define NPROCENT	(sizeof(Entries)/sizeof(Entries[0]))
+
+void jfs_proc_init(void)
+{
+	int i;
+
+	if (!(base = proc_mkdir("jfs", proc_root_fs)))
+		return;
+	base->owner = THIS_MODULE;
+
+	for (i = 0; i < NPROCENT; i++) {
+		struct proc_dir_entry *p;
+		if ((p = create_proc_entry(Entries[i].name, 0, base))) {
+			p->read_proc = Entries[i].read_fn;
+			p->write_proc = Entries[i].write_fn;
+		}
+	}
+}
+
+void jfs_proc_clean(void)
+{
+	int i;
+
+	if (base) {
+		for (i = 0; i < NPROCENT; i++)
+			remove_proc_entry(Entries[i].name, base);
+		remove_proc_entry("jfs", base);
+	}
+}
+
+#endif /* PROC_FS_JFS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_debug.h linux-2.4.20/fs/jfs/jfs_debug.h
--- linux-2.4.19/fs/jfs/jfs_debug.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_debug.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,103 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *
+ *   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
+ */
+#ifndef _H_JFS_DEBUG
+#define _H_JFS_DEBUG
+
+/*
+ *	jfs_debug.h
+ *
+ * global debug message, data structure/macro definitions
+ * under control of CONFIG_JFS_DEBUG, CONFIG_JFS_STATISTICS;
+ */
+
+/*
+ * Create /proc/fs/jfs if procfs is enabled andeither
+ * CONFIG_JFS_DEBUG or CONFIG_JFS_STATISTICS is defined
+ */
+#if defined(CONFIG_PROC_FS) && (defined(CONFIG_JFS_DEBUG) || defined(CONFIG_JFS_STATISTICS))
+	#define PROC_FS_JFS
+#endif
+
+/*
+ *	assert with traditional printf/panic
+ */
+#ifdef CONFIG_KERNEL_ASSERTS
+/* kgdb stuff */
+#define assert(p) KERNEL_ASSERT(#p, p)
+#else
+#define assert(p) {\
+if (!(p))\
+	{\
+		printk("assert(%s)\n",#p);\
+		BUG();\
+	}\
+}
+#endif
+
+/*
+ *	debug ON
+ *	--------
+ */
+#ifdef CONFIG_JFS_DEBUG
+#define ASSERT(p) assert(p)
+
+/* dump memory contents */
+extern void dump_mem(char *label, void *data, int length);
+extern int jfsloglevel;
+
+/* information message: e.g., configuration, major event */
+#define jFYI(button, prspec) \
+	do { if (button && jfsloglevel > 1) printk prspec; } while (0)
+
+/* error event message: e.g., i/o error */
+extern int jfsERROR;
+#define jERROR(button, prspec) \
+	do { if (button && jfsloglevel > 0) { printk prspec; } } while (0)
+
+/* debug event message: */
+#define jEVENT(button,prspec) \
+	do { if (button) printk prspec; } while (0)
+
+/*
+ *	debug OFF
+ *	---------
+ */
+#else				/* CONFIG_JFS_DEBUG */
+#define dump_mem(label,data,length)
+#define ASSERT(p)
+#define jEVENT(button,prspec)
+#define jERROR(button,prspec)
+#define jFYI(button,prspec)
+#endif				/* CONFIG_JFS_DEBUG */
+
+/*
+ *	statistics
+ *	----------
+ */
+#ifdef	CONFIG_JFS_STATISTICS
+#define	INCREMENT(x)		((x)++)
+#define	DECREMENT(x)		((x)--)
+#define	HIGHWATERMARK(x,y)	((x) = max((x), (y)))
+#else
+#define	INCREMENT(x)
+#define	DECREMENT(x)
+#define	HIGHWATERMARK(x,y)
+#endif				/* CONFIG_JFS_STATISTICS */
+
+#endif				/* _H_JFS_DEBUG */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_defragfs.h linux-2.4.20/fs/jfs/jfs_defragfs.h
--- linux-2.4.19/fs/jfs/jfs_defragfs.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_defragfs.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,51 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2001
+ *
+ *   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
+ */
+#ifndef	_H_JFS_DEFRAGFS
+#define _H_JFS_DEFRAGFS
+
+/*
+ *	defragfs parameter list
+ */
+struct defragfs {
+	uint flag;		/* 4: */
+	u8 dev;			/* 1: */
+	u8 pad[3];		/* 3: */
+	s32 fileset;		/* 4: */
+	u32 inostamp;		/* 4: */
+	u32 ino;		/* 4: */
+	u32 gen;		/* 4: */
+	s64 xoff;		/* 8: */
+	s64 old_xaddr;		/* 8: */
+	s64 new_xaddr;		/* 8: */
+	s32 xlen;		/* 4: */
+};
+
+/* plist flag */
+#define DEFRAGFS_SYNC		0x80000000
+#define DEFRAGFS_COMMIT		0x40000000
+#define DEFRAGFS_RELOCATE	0x10000000
+
+#define	INODE_TYPE		0x0000F000	/* IFREG or IFDIR */
+
+#define EXTENT_TYPE		0x000000ff
+#define DTPAGE			0x00000001
+#define XTPAGE			0x00000002
+#define DATAEXT			0x00000004
+#define EAEXT			0x00000008
+
+#endif				/* _H_JFS_DEFRAGFS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_dinode.h linux-2.4.20/fs/jfs/jfs_dinode.h
--- linux-2.4.19/fs/jfs/jfs_dinode.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_dinode.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,151 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2001
+ *
+ *   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
+ */
+#ifndef _H_JFS_DINODE
+#define _H_JFS_DINODE
+
+/*
+ *      jfs_dinode.h: on-disk inode manager
+ */
+
+#define INODESLOTSIZE           128
+#define L2INODESLOTSIZE         7
+#define log2INODESIZE           9	/* log2(bytes per dinode) */
+
+
+/*
+ *      on-disk inode : 512 bytes
+ *
+ * note: align 64-bit fields on 8-byte boundary.
+ */
+struct dinode {
+	/*
+	 *      I. base area (128 bytes)
+	 *      ------------------------
+	 *
+	 * define generic/POSIX attributes
+	 */
+	u32 di_inostamp;	/* 4: stamp to show inode belongs to fileset */
+	s32 di_fileset;		/* 4: fileset number */
+	u32 di_number;		/* 4: inode number, aka file serial number */
+	u32 di_gen;		/* 4: inode generation number */
+
+	pxd_t di_ixpxd;		/* 8: inode extent descriptor */
+
+	s64 di_size;		/* 8: size */
+	s64 di_nblocks;		/* 8: number of blocks allocated */
+
+	u32 di_nlink;		/* 4: number of links to the object */
+
+	u32 di_uid;		/* 4: user id of owner */
+	u32 di_gid;		/* 4: group id of owner */
+
+	u32 di_mode;		/* 4: attribute, format and permission */
+
+	struct timestruc_t di_atime;	/* 8: time last data accessed */
+	struct timestruc_t di_ctime;	/* 8: time last status changed */
+	struct timestruc_t di_mtime;	/* 8: time last data modified */
+	struct timestruc_t di_otime;	/* 8: time created */
+
+	dxd_t di_acl;		/* 16: acl descriptor */
+
+	dxd_t di_ea;		/* 16: ea descriptor */
+
+	u32 di_next_index;	/* 4: Next available dir_table index */
+
+	s32 di_acltype;		/* 4: Type of ACL */
+
+	/*
+	 *      Extension Areas.
+	 *
+	 *      Historically, the inode was partitioned into 4 128-byte areas,
+	 *      the last 3 being defined as unions which could have multiple
+	 *      uses.  The first 96 bytes had been completely unused until
+	 *      an index table was added to the directory.  It is now more
+	 *      useful to describe the last 3/4 of the inode as a single
+	 *      union.  We would probably be better off redesigning the
+	 *      entire structure from scratch, but we don't want to break
+	 *      commonality with OS/2's JFS at this time.
+	 */
+	union {
+		struct {
+			/*
+			 * This table contains the information needed to
+			 * find a directory entry from a 32-bit index.
+			 * If the index is small enough, the table is inline,
+			 * otherwise, an x-tree root overlays this table
+			 */
+			struct dir_table_slot _table[12]; /* 96: inline */
+
+			dtroot_t _dtroot;		/* 288: dtree root */
+		} _dir;					/* (384) */
+#define di_dirtable	u._dir._table
+#define di_dtroot	u._dir._dtroot
+#define di_parent       di_dtroot.header.idotdot
+#define di_DASD		di_dtroot.header.DASD
+
+		struct {
+			union {
+				u8 _data[96];		/* 96: unused */
+				struct {
+					void *_imap;	/* 4: unused */
+					u32 _gengen;	/* 4: generator */
+				} _imap;
+			} _u1;				/* 96: */
+#define di_gengen	u._file._u1._imap._gengen
+
+			union {
+				xtpage_t _xtroot;
+				struct {
+					u8 unused[16];	/* 16: */
+					dxd_t _dxd;	/* 16: */
+					union {
+						u32 _rdev;	/* 4: */
+						u8 _fastsymlink[128];
+					} _u;
+					u8 _inlineea[128];
+				} _special;
+			} _u2;
+		} _file;
+#define di_xtroot	u._file._u2._xtroot
+#define di_dxd		u._file._u2._special._dxd
+#define di_btroot	di_xtroot
+#define di_inlinedata	u._file._u2._special._u
+#define di_rdev		u._file._u2._special._u._rdev
+#define di_fastsymlink	u._file._u2._special._u._fastsymlink
+#define di_inlineea     u._file._u2._special._inlineea
+	} u;
+};
+
+/* extended mode bits (on-disk inode di_mode) */
+#define IFJOURNAL       0x00010000	/* journalled file */
+#define ISPARSE         0x00020000	/* sparse file enabled */
+#define INLINEEA        0x00040000	/* inline EA area free */
+#define ISWAPFILE	0x00800000	/* file open for pager swap space */
+
+/* more extended mode bits: attributes for OS/2 */
+#define IREADONLY	0x02000000	/* no write access to file */
+#define IARCHIVE	0x40000000	/* file archive bit */
+#define ISYSTEM		0x08000000	/* system file */
+#define IHIDDEN		0x04000000	/* hidden file */
+#define IRASH		0x4E000000	/* mask for changeable attributes */
+#define INEWNAME	0x80000000	/* non-8.3 filename format */
+#define IDIRECTORY	0x20000000	/* directory (shadow of real bit) */
+#define ATTRSHIFT	25	/* bits to shift to move attribute
+				   specification to mode position */
+
+#endif /*_H_JFS_DINODE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_dmap.c linux-2.4.20/fs/jfs/jfs_dmap.c
--- linux-2.4.19/fs/jfs/jfs_dmap.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_dmap.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,4192 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+
+#include <linux/fs.h>
+#include "jfs_incore.h"
+#include "jfs_dmap.h"
+#include "jfs_imap.h"
+#include "jfs_lock.h"
+#include "jfs_metapage.h"
+#include "jfs_debug.h"
+
+/*
+ *	Debug code for double-checking block map
+ */
+/* #define	_JFS_DEBUG_DMAP	1 */
+
+#ifdef	_JFS_DEBUG_DMAP
+#define DBINITMAP(size,ipbmap,results) \
+	DBinitmap(size,ipbmap,results)
+#define DBALLOC(dbmap,mapsize,blkno,nblocks) \
+	DBAlloc(dbmap,mapsize,blkno,nblocks)
+#define DBFREE(dbmap,mapsize,blkno,nblocks) \
+	DBFree(dbmap,mapsize,blkno,nblocks)
+#define DBALLOCCK(dbmap,mapsize,blkno,nblocks) \
+	DBAllocCK(dbmap,mapsize,blkno,nblocks)
+#define DBFREECK(dbmap,mapsize,blkno,nblocks) \
+	DBFreeCK(dbmap,mapsize,blkno,nblocks)
+
+static void DBinitmap(s64, struct inode *, u32 **);
+static void DBAlloc(uint *, s64, s64, s64);
+static void DBFree(uint *, s64, s64, s64);
+static void DBAllocCK(uint *, s64, s64, s64);
+static void DBFreeCK(uint *, s64, s64, s64);
+#else
+#define DBINITMAP(size,ipbmap,results)
+#define DBALLOC(dbmap, mapsize, blkno, nblocks)
+#define DBFREE(dbmap, mapsize, blkno, nblocks)
+#define DBALLOCCK(dbmap, mapsize, blkno, nblocks)
+#define DBFREECK(dbmap, mapsize, blkno, nblocks)
+#endif				/* _JFS_DEBUG_DMAP */
+
+/*
+ *	SERIALIZATION of the Block Allocation Map.
+ *
+ *	the working state of the block allocation map is accessed in
+ *	two directions:
+ *	
+ *	1) allocation and free requests that start at the dmap
+ *	   level and move up through the dmap control pages (i.e.
+ *	   the vast majority of requests).
+ * 
+ * 	2) allocation requests that start at dmap control page
+ *	   level and work down towards the dmaps.
+ *	
+ *	the serialization scheme used here is as follows. 
+ *
+ *	requests which start at the bottom are serialized against each 
+ *	other through buffers and each requests holds onto its buffers 
+ *	as it works it way up from a single dmap to the required level 
+ *	of dmap control page.
+ *	requests that start at the top are serialized against each other
+ *	and request that start from the bottom by the multiple read/single
+ *	write inode lock of the bmap inode. requests starting at the top
+ *	take this lock in write mode while request starting at the bottom
+ *	take the lock in read mode.  a single top-down request may proceed
+ *	exclusively while multiple bottoms-up requests may proceed 
+ * 	simultaneously (under the protection of busy buffers).
+ *	
+ *	in addition to information found in dmaps and dmap control pages,
+ *	the working state of the block allocation map also includes read/
+ *	write information maintained in the bmap descriptor (i.e. total
+ *	free block count, allocation group level free block counts).
+ *	a single exclusive lock (BMAP_LOCK) is used to guard this information
+ *	in the face of multiple-bottoms up requests.
+ *	(lock ordering: IREAD_LOCK, BMAP_LOCK);
+ *	
+ *	accesses to the persistent state of the block allocation map (limited
+ *	to the persistent bitmaps in dmaps) is guarded by (busy) buffers.
+ */
+
+#define BMAP_LOCK_INIT(bmp)	init_MUTEX(&bmp->db_bmaplock)
+#define BMAP_LOCK(bmp)		down(&bmp->db_bmaplock)
+#define BMAP_UNLOCK(bmp)	up(&bmp->db_bmaplock)
+
+/*
+ * forward references
+ */
+static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
+			int nblocks);
+static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval);
+static void dbBackSplit(dmtree_t * tp, int leafno);
+static void dbJoin(dmtree_t * tp, int leafno, int newval);
+static void dbAdjTree(dmtree_t * tp, int leafno, int newval);
+static int dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc,
+		    int level);
+static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results);
+static int dbAllocNext(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		       int nblocks);
+static int dbAllocNear(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		       int nblocks,
+		       int l2nb, s64 * results);
+static int dbAllocDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		       int nblocks);
+static int dbAllocDmapLev(struct bmap * bmp, struct dmap * dp, int nblocks,
+			  int l2nb,
+			  s64 * results);
+static int dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb,
+		     s64 * results);
+static int dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno,
+		      s64 * results);
+int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks);
+static int dbFindBits(u32 word, int l2nb);
+static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno);
+static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx);
+static void dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		       int nblocks);
+static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		      int nblocks);
+static int dbMaxBud(u8 * cp);
+s64 dbMapFileSizeToMapSize(struct inode *ipbmap);
+int blkstol2(s64 nb);
+void fsDirty(void);
+
+int cntlz(u32 value);
+int cnttz(u32 word);
+
+static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno,
+			 int nblocks);
+static int dbInitDmap(struct dmap * dp, s64 blkno, int nblocks);
+static int dbInitDmapTree(struct dmap * dp);
+static int dbInitTree(struct dmaptree * dtp);
+static int dbInitDmapCtl(struct dmapctl * dcp, int level, int i);
+static int dbGetL2AGSize(s64 nblocks);
+
+/*
+ *	buddy table
+ *
+ * table used for determining buddy sizes within characters of 
+ * dmap bitmap words.  the characters themselves serve as indexes
+ * into the table, with the table elements yielding the maximum
+ * binary buddy of free bits within the character.
+ */
+signed char budtab[256] = {
+	3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1
+};
+
+
+/*
+ * NAME:    	dbMount()
+ *
+ * FUNCTION:	initializate the block allocation map.
+ *
+ *		memory is allocated for the in-core bmap descriptor and
+ *		the in-core descriptor is initialized from disk.
+ *
+ * PARAMETERS:
+ *      ipbmap	-  pointer to in-core inode for the block map.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOMEM	- insufficient memory
+ *      EIO	- i/o error
+ */
+int dbMount(struct inode *ipbmap)
+{
+	struct bmap *bmp;
+	struct dbmap *dbmp_le;
+	struct metapage *mp;
+	int i;
+
+	/*
+	 * allocate/initialize the in-memory bmap descriptor
+	 */
+	/* allocate memory for the in-memory bmap descriptor */
+	bmp = kmalloc(sizeof(struct bmap), GFP_KERNEL);
+	if (bmp == NULL)
+		return (ENOMEM);
+
+	/* read the on-disk bmap descriptor. */
+	mp = read_metapage(ipbmap,
+			   BMAPBLKNO << JFS_SBI(ipbmap->i_sb)->l2nbperpage,
+			   PSIZE, 0);
+	if (mp == NULL) {
+		kfree(bmp);
+		return (EIO);
+	}
+
+	/* copy the on-disk bmap descriptor to its in-memory version. */
+	dbmp_le = (struct dbmap *) mp->data;
+	bmp->db_mapsize = le64_to_cpu(dbmp_le->dn_mapsize);
+	bmp->db_nfree = le64_to_cpu(dbmp_le->dn_nfree);
+	bmp->db_l2nbperpage = le32_to_cpu(dbmp_le->dn_l2nbperpage);
+	bmp->db_numag = le32_to_cpu(dbmp_le->dn_numag);
+	bmp->db_maxlevel = le32_to_cpu(dbmp_le->dn_maxlevel);
+	bmp->db_maxag = le32_to_cpu(dbmp_le->dn_maxag);
+	bmp->db_agpref = le32_to_cpu(dbmp_le->dn_agpref);
+	bmp->db_aglevel = le32_to_cpu(dbmp_le->dn_aglevel);
+	bmp->db_agheigth = le32_to_cpu(dbmp_le->dn_agheigth);
+	bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth);
+	bmp->db_agstart = le32_to_cpu(dbmp_le->dn_agstart);
+	bmp->db_agl2size = le32_to_cpu(dbmp_le->dn_agl2size);
+	for (i = 0; i < MAXAG; i++)
+		bmp->db_agfree[i] = le64_to_cpu(dbmp_le->dn_agfree[i]);
+	bmp->db_agsize = le64_to_cpu(dbmp_le->dn_agsize);
+	bmp->db_maxfreebud = dbmp_le->dn_maxfreebud;
+
+	/* release the buffer. */
+	release_metapage(mp);
+
+	/* bind the bmap inode and the bmap descriptor to each other. */
+	bmp->db_ipbmap = ipbmap;
+	JFS_SBI(ipbmap->i_sb)->bmap = bmp;
+
+	memset(bmp->db_active, 0, sizeof(bmp->db_active));
+	DBINITMAP(bmp->db_mapsize, ipbmap, &bmp->db_DBmap);
+
+	/*
+	 * allocate/initialize the bmap lock
+	 */
+	BMAP_LOCK_INIT(bmp);
+
+	return (0);
+}
+
+
+/*
+ * NAME:    	dbUnmount()
+ *
+ * FUNCTION:	terminate the block allocation map in preparation for
+ *		file system unmount.
+ *
+ * 		the in-core bmap descriptor is written to disk and
+ *		the memory for this descriptor is freed.
+ *
+ * PARAMETERS:
+ *      ipbmap	-  pointer to in-core inode for the block map.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      EIO	- i/o error
+ */
+int dbUnmount(struct inode *ipbmap, int mounterror)
+{
+	struct bmap *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
+	int i;
+
+	if (!(mounterror || isReadOnly(ipbmap)))
+		dbSync(ipbmap);
+
+	/*
+	 * Invalidate the page cache buffers
+	 */
+	truncate_inode_pages(ipbmap->i_mapping, 0);
+
+	/*
+	 * Sanity Check
+	 */
+	for (i = 0; i < bmp->db_numag; i++)
+		if (atomic_read(&bmp->db_active[i]))
+			printk(KERN_ERR "dbUnmount: db_active[%d] = %d\n",
+			       i, atomic_read(&bmp->db_active[i]));
+
+	/* free the memory for the in-memory bmap. */
+	kfree(bmp);
+
+	return (0);
+}
+
+/*
+ *	dbSync()
+ */
+int dbSync(struct inode *ipbmap)
+{
+	struct dbmap *dbmp_le;
+	struct bmap *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
+	struct metapage *mp;
+	int i;
+
+	/*
+	 * write bmap global control page
+	 */
+	/* get the buffer for the on-disk bmap descriptor. */
+	mp = read_metapage(ipbmap,
+			   BMAPBLKNO << JFS_SBI(ipbmap->i_sb)->l2nbperpage,
+			   PSIZE, 0);
+	if (mp == NULL) {
+		jERROR(1,("dbSync: read_metapage failed!\n"));
+		return (EIO);
+	}
+	/* copy the in-memory version of the bmap to the on-disk version */
+	dbmp_le = (struct dbmap *) mp->data;
+	dbmp_le->dn_mapsize = cpu_to_le64(bmp->db_mapsize);
+	dbmp_le->dn_nfree = cpu_to_le64(bmp->db_nfree);
+	dbmp_le->dn_l2nbperpage = cpu_to_le32(bmp->db_l2nbperpage);
+	dbmp_le->dn_numag = cpu_to_le32(bmp->db_numag);
+	dbmp_le->dn_maxlevel = cpu_to_le32(bmp->db_maxlevel);
+	dbmp_le->dn_maxag = cpu_to_le32(bmp->db_maxag);
+	dbmp_le->dn_agpref = cpu_to_le32(bmp->db_agpref);
+	dbmp_le->dn_aglevel = cpu_to_le32(bmp->db_aglevel);
+	dbmp_le->dn_agheigth = cpu_to_le32(bmp->db_agheigth);
+	dbmp_le->dn_agwidth = cpu_to_le32(bmp->db_agwidth);
+	dbmp_le->dn_agstart = cpu_to_le32(bmp->db_agstart);
+	dbmp_le->dn_agl2size = cpu_to_le32(bmp->db_agl2size);
+	for (i = 0; i < MAXAG; i++)
+		dbmp_le->dn_agfree[i] = cpu_to_le64(bmp->db_agfree[i]);
+	dbmp_le->dn_agsize = cpu_to_le64(bmp->db_agsize);
+	dbmp_le->dn_maxfreebud = bmp->db_maxfreebud;
+
+	/* write the buffer */
+	write_metapage(mp);
+
+	/*
+	 * write out dirty pages of bmap
+	 */
+	fsync_inode_data_buffers(ipbmap);
+
+	ipbmap->i_state |= I_DIRTY;
+	diWriteSpecial(ipbmap, 0);
+
+	return (0);
+}
+
+
+/*
+ * NAME:    	dbFree()
+ *
+ * FUNCTION:	free the specified block range from the working block
+ *		allocation map.
+ *
+ *		the blocks will be free from the working map one dmap
+ *		at a time.
+ *
+ * PARAMETERS:
+ *      ip	-  pointer to in-core inode;
+ *      blkno	-  starting block number to be freed.
+ *      nblocks	-  number of blocks to be freed.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      EIO	- i/o error
+ */
+int dbFree(struct inode *ip, s64 blkno, s64 nblocks)
+{
+	struct metapage *mp;
+	struct dmap *dp;
+	int nb, rc;
+	s64 lblkno, rem;
+	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
+	struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
+
+	IREAD_LOCK(ipbmap);
+
+	/* block to be freed better be within the mapsize. */
+	assert(blkno + nblocks <= bmp->db_mapsize);
+
+	/*
+	 * free the blocks a dmap at a time.
+	 */
+	mp = NULL;
+	for (rem = nblocks; rem > 0; rem -= nb, blkno += nb) {
+		/* release previous dmap if any */
+		if (mp) {
+			write_metapage(mp);
+		}
+
+		/* get the buffer for the current dmap. */
+		lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage);
+		mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
+		if (mp == NULL) {
+			IREAD_UNLOCK(ipbmap);
+			return (EIO);
+		}
+		dp = (struct dmap *) mp->data;
+
+		/* determine the number of blocks to be freed from
+		 * this dmap.
+		 */
+		nb = min(rem, BPERDMAP - (blkno & (BPERDMAP - 1)));
+
+		DBALLOCCK(bmp->db_DBmap, bmp->db_mapsize, blkno, nb);
+
+		/* free the blocks. */
+		if ((rc = dbFreeDmap(bmp, dp, blkno, nb))) {
+			release_metapage(mp);
+			IREAD_UNLOCK(ipbmap);
+			return (rc);
+		}
+
+		DBFREE(bmp->db_DBmap, bmp->db_mapsize, blkno, nb);
+	}
+
+	/* write the last buffer. */
+	write_metapage(mp);
+
+	IREAD_UNLOCK(ipbmap);
+
+	return (0);
+}
+
+
+/*
+ * NAME:	dbUpdatePMap()
+ *
+ * FUNCTION:    update the allocation state (free or allocate) of the
+ *		specified block range in the persistent block allocation map.
+ *		
+ *		the blocks will be updated in the persistent map one
+ *		dmap at a time.
+ *
+ * PARAMETERS:
+ *      ipbmap	-  pointer to in-core inode for the block map.
+ *      free	- TRUE if block range is to be freed from the persistent
+ *		  map; FALSE if it is to   be allocated.
+ *      blkno	-  starting block number of the range.
+ *      nblocks	-  number of contiguous blocks in the range.
+ *      tblk	-  transaction block;
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      EIO	- i/o error
+ */
+int
+dbUpdatePMap(struct inode *ipbmap,
+	     int free, s64 blkno, s64 nblocks, struct tblock * tblk)
+{
+	int nblks, dbitno, wbitno, rbits;
+	int word, nbits, nwords;
+	struct bmap *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
+	s64 lblkno, rem, lastlblkno;
+	u32 mask;
+	struct dmap *dp;
+	struct metapage *mp;
+	struct jfs_log *log;
+	int lsn, difft, diffp;
+
+	/* the blocks better be within the mapsize. */
+	assert(blkno + nblocks <= bmp->db_mapsize);
+
+	/* compute delta of transaction lsn from log syncpt */
+	lsn = tblk->lsn;
+	log = (struct jfs_log *) JFS_SBI(tblk->sb)->log;
+	logdiff(difft, lsn, log);
+
+	/*
+	 * update the block state a dmap at a time.
+	 */
+	mp = NULL;
+	lastlblkno = 0;
+	for (rem = nblocks; rem > 0; rem -= nblks, blkno += nblks) {
+		/* get the buffer for the current dmap. */
+		lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage);
+		if (lblkno != lastlblkno) {
+			if (mp) {
+				write_metapage(mp);
+			}
+
+			mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE,
+					   0);
+			if (mp == NULL)
+				return (EIO);
+		}
+		dp = (struct dmap *) mp->data;
+
+		/* determine the bit number and word within the dmap of
+		 * the starting block.  also determine how many blocks
+		 * are to be updated within this dmap.
+		 */
+		dbitno = blkno & (BPERDMAP - 1);
+		word = dbitno >> L2DBWORD;
+		nblks = min(rem, (s64)BPERDMAP - dbitno);
+
+		/* update the bits of the dmap words. the first and last
+		 * words may only have a subset of their bits updated. if
+		 * this is the case, we'll work against that word (i.e.
+		 * partial first and/or last) only in a single pass.  a 
+		 * single pass will also be used to update all words that
+		 * are to have all their bits updated.
+		 */
+		for (rbits = nblks; rbits > 0;
+		     rbits -= nbits, dbitno += nbits) {
+			/* determine the bit number within the word and
+			 * the number of bits within the word.
+			 */
+			wbitno = dbitno & (DBWORD - 1);
+			nbits = min(rbits, DBWORD - wbitno);
+
+			/* check if only part of the word is to be updated. */
+			if (nbits < DBWORD) {
+				/* update (free or allocate) the bits
+				 * in this word.
+				 */
+				mask =
+				    (ONES << (DBWORD - nbits) >> wbitno);
+				if (free)
+					dp->pmap[word] &=
+					    cpu_to_le32(~mask);
+				else
+					dp->pmap[word] |=
+					    cpu_to_le32(mask);
+
+				word += 1;
+			} else {
+				/* one or more words are to have all
+				 * their bits updated.  determine how
+				 * many words and how many bits.
+				 */
+				nwords = rbits >> L2DBWORD;
+				nbits = nwords << L2DBWORD;
+
+				/* update (free or allocate) the bits
+				 * in these words.
+				 */
+				if (free)
+					memset(&dp->pmap[word], 0,
+					       nwords * 4);
+				else
+					memset(&dp->pmap[word], (int) ONES,
+					       nwords * 4);
+
+				word += nwords;
+			}
+		}
+
+		/*
+		 * update dmap lsn
+		 */
+		if (lblkno == lastlblkno)
+			continue;
+
+		lastlblkno = lblkno;
+
+		if (mp->lsn != 0) {
+			/* inherit older/smaller lsn */
+			logdiff(diffp, mp->lsn, log);
+			if (difft < diffp) {
+				mp->lsn = lsn;
+
+				/* move bp after tblock in logsync list */
+				LOGSYNC_LOCK(log);
+				list_del(&mp->synclist);
+				list_add(&mp->synclist, &tblk->synclist);
+				LOGSYNC_UNLOCK(log);
+			}
+
+			/* inherit younger/larger clsn */
+			LOGSYNC_LOCK(log);
+			logdiff(difft, tblk->clsn, log);
+			logdiff(diffp, mp->clsn, log);
+			if (difft > diffp)
+				mp->clsn = tblk->clsn;
+			LOGSYNC_UNLOCK(log);
+		} else {
+			mp->log = log;
+			mp->lsn = lsn;
+
+			/* insert bp after tblock in logsync list */
+			LOGSYNC_LOCK(log);
+
+			log->count++;
+			list_add(&mp->synclist, &tblk->synclist);
+
+			mp->clsn = tblk->clsn;
+			LOGSYNC_UNLOCK(log);
+		}
+	}
+
+	/* write the last buffer. */
+	if (mp) {
+		write_metapage(mp);
+	}
+
+	return (0);
+}
+
+
+/*
+ * NAME:	dbNextAG()
+ *
+ * FUNCTION:    find the preferred allocation group for new allocations.
+ *
+ *		Within the allocation groups, we maintain a preferred
+ *		allocation group which consists of a group with at least
+ *		average free space.  It is the preferred group that we target
+ *		new inode allocation towards.  The tie-in between inode
+ *		allocation and block allocation occurs as we allocate the
+ *		first (data) block of an inode and specify the inode (block)
+ *		as the allocation hint for this block.
+ *
+ *		We try to avoid having more than one open file growing in
+ *		an allocation group, as this will lead to fragmentation.
+ *		This differs from the old OS/2 method of trying to keep
+ *		empty ags around for large allocations.
+ *
+ * PARAMETERS:
+ *      ipbmap	-  pointer to in-core inode for the block map.
+ *
+ * RETURN VALUES:
+ *      the preferred allocation group number.
+ */
+int dbNextAG(struct inode *ipbmap)
+{
+	s64 avgfree;
+	int agpref;
+	s64 hwm = 0;
+	int i;
+	int next_best = -1;
+	struct bmap *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
+
+	BMAP_LOCK(bmp);
+
+	/* determine the average number of free blocks within the ags. */
+	avgfree = (u32)bmp->db_nfree / bmp->db_numag;
+
+	/*
+	 * if the current preferred ag does not have an active allocator
+	 * and has at least average freespace, return it
+	 */
+	agpref = bmp->db_agpref;
+	if ((atomic_read(&bmp->db_active[agpref]) == 0) &&
+	    (bmp->db_agfree[agpref] >= avgfree))
+		goto unlock;
+
+	/* From the last preferred ag, find the next one with at least
+	 * average free space.
+	 */
+	for (i = 0 ; i < bmp->db_numag; i++, agpref++) {
+		if (agpref == bmp->db_numag)
+			agpref = 0;
+
+		if (atomic_read(&bmp->db_active[agpref]))
+			/* open file is currently growing in this ag */
+			continue;
+		if (bmp->db_agfree[agpref] >= avgfree) {
+			/* Return this one */
+			bmp->db_agpref = agpref;
+			goto unlock;
+		} else if (bmp->db_agfree[agpref] > hwm) {
+			/* Less than avg. freespace, but best so far */
+			hwm = bmp->db_agfree[agpref];
+			next_best = agpref;
+		}
+	}
+
+	/*
+	 * If no inactive ag was found with average freespace, use the
+	 * next best
+	 */
+	if (next_best != -1)
+		bmp->db_agpref = next_best;
+	/* else leave db_agpref unchanged */
+unlock:
+	BMAP_UNLOCK(bmp);
+
+	/* return the preferred group.
+	 */
+	return (bmp->db_agpref);
+}
+
+/*
+ * NAME:	dbAlloc()
+ *
+ * FUNCTION:    attempt to allocate a specified number of contiguous free
+ *		blocks from the working allocation block map.
+ *
+ *		the block allocation policy uses hints and a multi-step
+ *		approach.
+ *
+ *	  	for allocation requests smaller than the number of blocks
+ *		per dmap, we first try to allocate the new blocks
+ *		immediately following the hint.  if these blocks are not
+ *		available, we try to allocate blocks near the hint.  if
+ *		no blocks near the hint are available, we next try to 
+ *		allocate within the same dmap as contains the hint.
+ *
+ *		if no blocks are available in the dmap or the allocation
+ *		request is larger than the dmap size, we try to allocate
+ *		within the same allocation group as contains the hint. if
+ *		this does not succeed, we finally try to allocate anywhere
+ *		within the aggregate.
+ *
+ *		we also try to allocate anywhere within the aggregate for
+ *		for allocation requests larger than the allocation group
+ *		size or requests that specify no hint value.
+ *
+ * PARAMETERS:
+ *      ip	-  pointer to in-core inode;
+ *      hint	- allocation hint.
+ *      nblocks	- number of contiguous blocks in the range.
+ *      results	- on successful return, set to the starting block number
+ *		  of the newly allocated contiguous range.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ */
+int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
+{
+	int rc, agno;
+	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
+	struct bmap *bmp;
+	struct metapage *mp;
+	s64 lblkno, blkno;
+	struct dmap *dp;
+	int l2nb;
+	s64 mapSize;
+	int writers;
+
+	/* assert that nblocks is valid */
+	assert(nblocks > 0);
+
+#ifdef _STILL_TO_PORT
+	/* DASD limit check                                     F226941 */
+	if (OVER_LIMIT(ip, nblocks))
+		return ENOSPC;
+#endif				/* _STILL_TO_PORT */
+
+	/* get the log2 number of blocks to be allocated.
+	 * if the number of blocks is not a log2 multiple, 
+	 * it will be rounded up to the next log2 multiple.
+	 */
+	l2nb = BLKSTOL2(nblocks);
+
+	bmp = JFS_SBI(ip->i_sb)->bmap;
+
+//retry:        /* serialize w.r.t.extendfs() */
+	mapSize = bmp->db_mapsize;
+
+	/* the hint should be within the map */
+	assert(hint < mapSize);
+
+	/* if the number of blocks to be allocated is greater than the
+	 * allocation group size, try to allocate anywhere.
+	 */
+	if (l2nb > bmp->db_agl2size) {
+		IWRITE_LOCK(ipbmap);
+
+		rc = dbAllocAny(bmp, nblocks, l2nb, results);
+		if (rc == 0) {
+			DBALLOC(bmp->db_DBmap, bmp->db_mapsize, *results,
+				nblocks);
+		}
+
+		goto write_unlock;
+	}
+
+	/*
+	 * If no hint, let dbNextAG recommend an allocation group
+	 */
+	if (hint == 0)
+		goto pref_ag;
+
+	/* we would like to allocate close to the hint.  adjust the
+	 * hint to the block following the hint since the allocators
+	 * will start looking for free space starting at this point.
+	 */
+	blkno = hint + 1;
+
+	if (blkno >= bmp->db_mapsize)
+		goto pref_ag;
+
+	agno = blkno >> bmp->db_agl2size;
+
+	/* check if blkno crosses over into a new allocation group.
+	 * if so, check if we should allow allocations within this
+	 * allocation group.
+	 */
+	if ((blkno & (bmp->db_agsize - 1)) == 0)
+		/* check if the AG is currenly being written to.
+		 * if so, call dbNextAG() to find a non-busy
+		 * AG with sufficient free space.
+		 */
+		if (atomic_read(&bmp->db_active[agno]))
+			goto pref_ag;
+
+	/* check if the allocation request size can be satisfied from a
+	 * single dmap.  if so, try to allocate from the dmap containing
+	 * the hint using a tiered strategy.
+	 */
+	if (nblocks <= BPERDMAP) {
+		IREAD_LOCK(ipbmap);
+
+		/* get the buffer for the dmap containing the hint.
+		 */
+		rc = EIO;
+		lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage);
+		mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
+		if (mp == NULL)
+			goto read_unlock;
+
+		dp = (struct dmap *) mp->data;
+
+		/* first, try to satisfy the allocation request with the
+		 * blocks beginning at the hint.
+		 */
+		if ((rc = dbAllocNext(bmp, dp, blkno, (int) nblocks))
+		    != ENOSPC) {
+			if (rc == 0) {
+				*results = blkno;
+				DBALLOC(bmp->db_DBmap, bmp->db_mapsize,
+					*results, nblocks);
+				mark_metapage_dirty(mp);
+			}
+
+			release_metapage(mp);
+			goto read_unlock;
+		}
+
+		writers = atomic_read(&bmp->db_active[agno]);
+		if ((writers > 1) ||
+		    ((writers == 1) && (JFS_IP(ip)->active_ag != agno))) {
+			/*
+			 * Someone else is writing in this allocation
+			 * group.  To avoid fragmenting, try another ag
+			 */
+			release_metapage(mp);
+			IREAD_UNLOCK(ipbmap);
+			goto pref_ag;
+		}
+
+		/* next, try to satisfy the allocation request with blocks
+		 * near the hint.
+		 */
+		if ((rc =
+		     dbAllocNear(bmp, dp, blkno, (int) nblocks, l2nb, results))
+		    != ENOSPC) {
+			if (rc == 0) {
+				DBALLOC(bmp->db_DBmap, bmp->db_mapsize,
+					*results, nblocks);
+				mark_metapage_dirty(mp);
+			}
+
+			release_metapage(mp);
+			goto read_unlock;
+		}
+
+		/* try to satisfy the allocation request with blocks within
+		 * the same dmap as the hint.
+		 */
+		if ((rc = dbAllocDmapLev(bmp, dp, (int) nblocks, l2nb, results))
+		    != ENOSPC) {
+			if (rc == 0) {
+				DBALLOC(bmp->db_DBmap, bmp->db_mapsize,
+					*results, nblocks);
+				mark_metapage_dirty(mp);
+			}
+
+			release_metapage(mp);
+			goto read_unlock;
+		}
+
+		release_metapage(mp);
+		IREAD_UNLOCK(ipbmap);
+	}
+
+	/* try to satisfy the allocation request with blocks within
+	 * the same allocation group as the hint.
+	 */
+	IWRITE_LOCK(ipbmap);
+	if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results))
+	    != ENOSPC) {
+		if (rc == 0)
+			DBALLOC(bmp->db_DBmap, bmp->db_mapsize,
+				*results, nblocks);
+		goto write_unlock;
+	}
+	IWRITE_UNLOCK(ipbmap);
+
+
+      pref_ag:
+	/*
+	 * Let dbNextAG recommend a preferred allocation group
+	 */
+	agno = dbNextAG(ipbmap);
+	IWRITE_LOCK(ipbmap);
+
+	/* Try to allocate within this allocation group.  if that fails, try to
+	 * allocate anywhere in the map.
+	 */
+	if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results)) == ENOSPC)
+		rc = dbAllocAny(bmp, nblocks, l2nb, results);
+	if (rc == 0) {
+		DBALLOC(bmp->db_DBmap, bmp->db_mapsize, *results, nblocks);
+	}
+
+      write_unlock:
+	IWRITE_UNLOCK(ipbmap);
+
+	return (rc);
+
+      read_unlock:
+	IREAD_UNLOCK(ipbmap);
+
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbAllocExact()
+ *
+ * FUNCTION:    try to allocate the requested extent;
+ *
+ * PARAMETERS:
+ *      ip	- pointer to in-core inode;
+ *      blkno	- extent address;
+ *      nblocks	- extent length;
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ */
+int dbAllocExact(struct inode *ip, s64 blkno, int nblocks)
+{
+	int rc;
+	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
+	struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
+	struct dmap *dp;
+	s64 lblkno;
+	struct metapage *mp;
+
+	IREAD_LOCK(ipbmap);
+
+	/*
+	 * validate extent request:
+	 *
+	 * note: defragfs policy:
+	 *  max 64 blocks will be moved.  
+	 *  allocation request size must be satisfied from a single dmap.
+	 */
+	if (nblocks <= 0 || nblocks > BPERDMAP || blkno >= bmp->db_mapsize) {
+		IREAD_UNLOCK(ipbmap);
+		return EINVAL;
+	}
+
+	if (nblocks > ((s64) 1 << bmp->db_maxfreebud)) {
+		/* the free space is no longer available */
+		IREAD_UNLOCK(ipbmap);
+		return ENOSPC;
+	}
+
+	/* read in the dmap covering the extent */
+	lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage);
+	mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
+	if (mp == NULL) {
+		IREAD_UNLOCK(ipbmap);
+		return (EIO);
+	}
+	dp = (struct dmap *) mp->data;
+
+	/* try to allocate the requested extent */
+	rc = dbAllocNext(bmp, dp, blkno, nblocks);
+
+	IREAD_UNLOCK(ipbmap);
+
+	if (rc == 0) {
+		DBALLOC(bmp->db_DBmap, bmp->db_mapsize, blkno, nblocks);
+		mark_metapage_dirty(mp);
+	}
+	release_metapage(mp);
+
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbReAlloc()
+ *
+ * FUNCTION:    attempt to extend a current allocation by a specified
+ *		number of blocks.
+ *
+ *		this routine attempts to satisfy the allocation request
+ *		by first trying to extend the existing allocation in
+ *		place by allocating the additional blocks as the blocks
+ *		immediately following the current allocation.  if these
+ *		blocks are not available, this routine will attempt to
+ *		allocate a new set of contiguous blocks large enough
+ *		to cover the existing allocation plus the additional
+ *		number of blocks required.
+ *
+ * PARAMETERS:
+ *      ip	    -  pointer to in-core inode requiring allocation.
+ *      blkno	    -  starting block of the current allocation.
+ *      nblocks	    -  number of contiguous blocks within the current
+ *		       allocation.
+ *      addnblocks  -  number of blocks to add to the allocation.
+ *      results	-      on successful return, set to the starting block number
+ *		       of the existing allocation if the existing allocation
+ *		       was extended in place or to a newly allocated contiguous
+ *		       range if the existing allocation could not be extended
+ *		       in place.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ */
+int
+dbReAlloc(struct inode *ip,
+	  s64 blkno, s64 nblocks, s64 addnblocks, s64 * results)
+{
+	int rc;
+
+	/* try to extend the allocation in place.
+	 */
+	if ((rc = dbExtend(ip, blkno, nblocks, addnblocks)) == 0) {
+		*results = blkno;
+		return (0);
+	} else {
+		if (rc != ENOSPC)
+			return (rc);
+	}
+
+	/* could not extend the allocation in place, so allocate a
+	 * new set of blocks for the entire request (i.e. try to get
+	 * a range of contiguous blocks large enough to cover the
+	 * existing allocation plus the additional blocks.)
+	 */
+	return (dbAlloc
+		(ip, blkno + nblocks - 1, addnblocks + nblocks, results));
+}
+
+
+/*
+ * NAME:	dbExtend()
+ *
+ * FUNCTION:    attempt to extend a current allocation by a specified
+ *		number of blocks.
+ *
+ *		this routine attempts to satisfy the allocation request
+ *		by first trying to extend the existing allocation in
+ *		place by allocating the additional blocks as the blocks
+ *		immediately following the current allocation.
+ *
+ * PARAMETERS:
+ *      ip	    -  pointer to in-core inode requiring allocation.
+ *      blkno	    -  starting block of the current allocation.
+ *      nblocks	    -  number of contiguous blocks within the current
+ *		       allocation.
+ *      addnblocks  -  number of blocks to add to the allocation.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ */
+int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
+	s64 lblkno, lastblkno, extblkno;
+	uint rel_block;
+	struct metapage *mp;
+	struct dmap *dp;
+	int rc;
+	struct inode *ipbmap = sbi->ipbmap;
+	struct bmap *bmp;
+
+	/*
+	 * We don't want a non-aligned extent to cross a page boundary
+	 */
+	if (((rel_block = blkno & (sbi->nbperpage - 1))) &&
+	    (rel_block + nblocks + addnblocks > sbi->nbperpage))
+		return (ENOSPC);
+
+	/* get the last block of the current allocation */
+	lastblkno = blkno + nblocks - 1;
+
+	/* determine the block number of the block following
+	 * the existing allocation.
+	 */
+	extblkno = lastblkno + 1;
+
+	IREAD_LOCK(ipbmap);
+
+	/* better be within the file system */
+	bmp = sbi->bmap;
+	assert(lastblkno >= 0 && lastblkno < bmp->db_mapsize);
+
+	/* we'll attempt to extend the current allocation in place by
+	 * allocating the additional blocks as the blocks immediately
+	 * following the current allocation.  we only try to extend the
+	 * current allocation in place if the number of additional blocks
+	 * can fit into a dmap, the last block of the current allocation
+	 * is not the last block of the file system, and the start of the
+	 * inplace extension is not on an allocation group boundry.
+	 */
+	if (addnblocks > BPERDMAP || extblkno >= bmp->db_mapsize ||
+	    (extblkno & (bmp->db_agsize - 1)) == 0) {
+		IREAD_UNLOCK(ipbmap);
+		return (ENOSPC);
+	}
+
+	/* get the buffer for the dmap containing the first block
+	 * of the extension.
+	 */
+	lblkno = BLKTODMAP(extblkno, bmp->db_l2nbperpage);
+	mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
+	if (mp == NULL) {
+		IREAD_UNLOCK(ipbmap);
+		return (EIO);
+	}
+
+	DBALLOCCK(bmp->db_DBmap, bmp->db_mapsize, blkno, nblocks);
+	dp = (struct dmap *) mp->data;
+
+	/* try to allocate the blocks immediately following the
+	 * current allocation.
+	 */
+	rc = dbAllocNext(bmp, dp, extblkno, (int) addnblocks);
+
+	IREAD_UNLOCK(ipbmap);
+
+	/* were we successful ? */
+	if (rc == 0) {
+		DBALLOC(bmp->db_DBmap, bmp->db_mapsize, extblkno,
+			addnblocks);
+		write_metapage(mp);
+	} else {
+		/* we were not successful */
+		release_metapage(mp);
+		assert(rc == ENOSPC || rc == EIO);
+	}
+
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbAllocNext()
+ *
+ * FUNCTION:    attempt to allocate the blocks of the specified block
+ *		range within a dmap.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      dp	-  pointer to dmap.
+ *      blkno	-  starting block number of the range.
+ *      nblocks	-  number of contiguous free blocks of the range.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ *
+ * serialization: IREAD_LOCK(ipbmap) held on entry/exit;
+ */
+static int dbAllocNext(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		       int nblocks)
+{
+	int dbitno, word, rembits, nb, nwords, wbitno, nw;
+	int l2size;
+	s8 *leaf;
+	u32 mask;
+
+	/* pick up a pointer to the leaves of the dmap tree.
+	 */
+	leaf = dp->tree.stree + le32_to_cpu(dp->tree.leafidx);
+
+	/* determine the bit number and word within the dmap of the
+	 * starting block.
+	 */
+	dbitno = blkno & (BPERDMAP - 1);
+	word = dbitno >> L2DBWORD;
+
+	/* check if the specified block range is contained within
+	 * this dmap.
+	 */
+	if (dbitno + nblocks > BPERDMAP)
+		return (ENOSPC);
+
+	/* check if the starting leaf indicates that anything
+	 * is free.
+	 */
+	if (leaf[word] == NOFREE)
+		return (ENOSPC);
+
+	/* check the dmaps words corresponding to block range to see
+	 * if the block range is free.  not all bits of the first and
+	 * last words may be contained within the block range.  if this
+	 * is the case, we'll work against those words (i.e. partial first
+	 * and/or last) on an individual basis (a single pass) and examine
+	 * the actual bits to determine if they are free.  a single pass
+	 * will be used for all dmap words fully contained within the
+	 * specified range.  within this pass, the leaves of the dmap
+	 * tree will be examined to determine if the blocks are free. a
+	 * single leaf may describe the free space of multiple dmap
+	 * words, so we may visit only a subset of the actual leaves
+	 * corresponding to the dmap words of the block range.
+	 */
+	for (rembits = nblocks; rembits > 0; rembits -= nb, dbitno += nb) {
+		/* determine the bit number within the word and
+		 * the number of bits within the word.
+		 */
+		wbitno = dbitno & (DBWORD - 1);
+		nb = min(rembits, DBWORD - wbitno);
+
+		/* check if only part of the word is to be examined.
+		 */
+		if (nb < DBWORD) {
+			/* check if the bits are free.
+			 */
+			mask = (ONES << (DBWORD - nb) >> wbitno);
+			if ((mask & ~le32_to_cpu(dp->wmap[word])) != mask)
+				return (ENOSPC);
+
+			word += 1;
+		} else {
+			/* one or more dmap words are fully contained
+			 * within the block range.  determine how many
+			 * words and how many bits.
+			 */
+			nwords = rembits >> L2DBWORD;
+			nb = nwords << L2DBWORD;
+
+			/* now examine the appropriate leaves to determine
+			 * if the blocks are free.
+			 */
+			while (nwords > 0) {
+				/* does the leaf describe any free space ?
+				 */
+				if (leaf[word] < BUDMIN)
+					return (ENOSPC);
+
+				/* determine the l2 number of bits provided
+				 * by this leaf.
+				 */
+				l2size =
+				    min((int)leaf[word], NLSTOL2BSZ(nwords));
+
+				/* determine how many words were handled.
+				 */
+				nw = BUDSIZE(l2size, BUDMIN);
+
+				nwords -= nw;
+				word += nw;
+			}
+		}
+	}
+
+	/* allocate the blocks.
+	 */
+	return (dbAllocDmap(bmp, dp, blkno, nblocks));
+}
+
+
+/*
+ * NAME:	dbAllocNear()
+ *
+ * FUNCTION:    attempt to allocate a number of contiguous free blocks near
+ *		a specified block (hint) within a dmap.
+ *
+ *		starting with the dmap leaf that covers the hint, we'll
+ *		check the next four contiguous leaves for sufficient free
+ *		space.  if sufficient free space is found, we'll allocate
+ *		the desired free space.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      dp	-  pointer to dmap.
+ *      blkno	-  block number to allocate near.
+ *      nblocks	-  actual number of contiguous free blocks desired.
+ *      l2nb	-  log2 number of contiguous free blocks desired.
+ *      results	-  on successful return, set to the starting block number
+ *		   of the newly allocated range.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ *
+ * serialization: IREAD_LOCK(ipbmap) held on entry/exit;
+ */
+static int
+dbAllocNear(struct bmap * bmp,
+	    struct dmap * dp, s64 blkno, int nblocks, int l2nb, s64 * results)
+{
+	int word, lword, rc;
+	s8 *leaf = dp->tree.stree + le32_to_cpu(dp->tree.leafidx);
+
+	/* determine the word within the dmap that holds the hint
+	 * (i.e. blkno).  also, determine the last word in the dmap
+	 * that we'll include in our examination.
+	 */
+	word = (blkno & (BPERDMAP - 1)) >> L2DBWORD;
+	lword = min(word + 4, LPERDMAP);
+
+	/* examine the leaves for sufficient free space.
+	 */
+	for (; word < lword; word++) {
+		/* does the leaf describe sufficient free space ?
+		 */
+		if (leaf[word] < l2nb)
+			continue;
+
+		/* determine the block number within the file system
+		 * of the first block described by this dmap word.
+		 */
+		blkno = le64_to_cpu(dp->start) + (word << L2DBWORD);
+
+		/* if not all bits of the dmap word are free, get the
+		 * starting bit number within the dmap word of the required
+		 * string of free bits and adjust the block number with the
+		 * value.
+		 */
+		if (leaf[word] < BUDMIN)
+			blkno +=
+			    dbFindBits(le32_to_cpu(dp->wmap[word]), l2nb);
+
+		/* allocate the blocks.
+		 */
+		if ((rc = dbAllocDmap(bmp, dp, blkno, nblocks)) == 0)
+			*results = blkno;
+
+		return (rc);
+	}
+
+	return (ENOSPC);
+}
+
+
+/*
+ * NAME:	dbAllocAG()
+ *
+ * FUNCTION:    attempt to allocate the specified number of contiguous
+ *		free blocks within the specified allocation group.
+ *
+ *		unless the allocation group size is equal to the number
+ *		of blocks per dmap, the dmap control pages will be used to
+ *		find the required free space, if available.  we start the
+ *		search at the highest dmap control page level which
+ *		distinctly describes the allocation group's free space
+ *		(i.e. the highest level at which the allocation group's
+ *		free space is not mixed in with that of any other group).
+ *		in addition, we start the search within this level at a
+ *		height of the dmapctl dmtree at which the nodes distinctly
+ *		describe the allocation group's free space.  at this height,
+ *		the allocation group's free space may be represented by 1
+ *		or two sub-trees, depending on the allocation group size.
+ *		we search the top nodes of these subtrees left to right for
+ *		sufficient free space.  if sufficient free space is found,
+ *		the subtree is searched to find the leftmost leaf that 
+ *		has free space.  once we have made it to the leaf, we
+ *		move the search to the next lower level dmap control page
+ *		corresponding to this leaf.  we continue down the dmap control
+ *		pages until we find the dmap that contains or starts the
+ *		sufficient free space and we allocate at this dmap.
+ *
+ *		if the allocation group size is equal to the dmap size,
+ *		we'll start at the dmap corresponding to the allocation
+ *		group and attempt the allocation at this level.
+ *
+ *		the dmap control page search is also not performed if the
+ *		allocation group is completely free and we go to the first
+ *		dmap of the allocation group to do the allocation.  this is
+ *		done because the allocation group may be part (not the first
+ *		part) of a larger binary buddy system, causing the dmap
+ *		control pages to indicate no free space (NOFREE) within
+ *		the allocation group.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *	agno	- allocation group number.
+ *      nblocks	-  actual number of contiguous free blocks desired.
+ *      l2nb	-  log2 number of contiguous free blocks desired.
+ *      results	-  on successful return, set to the starting block number
+ *		   of the newly allocated range.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ *
+ * note: IWRITE_LOCK(ipmap) held on entry/exit;
+ */
+static int
+dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
+{
+	struct metapage *mp;
+	struct dmapctl *dcp;
+	int rc, ti, i, k, m, n, agperlev;
+	s64 blkno, lblkno;
+	int budmin;
+
+	/* allocation request should not be for more than the
+	 * allocation group size.
+	 */
+	assert(l2nb <= bmp->db_agl2size);
+
+	/* determine the starting block number of the allocation
+	 * group.
+	 */
+	blkno = (s64) agno << bmp->db_agl2size;
+
+	/* check if the allocation group size is the minimum allocation
+	 * group size or if the allocation group is completely free. if
+	 * the allocation group size is the minimum size of BPERDMAP (i.e.
+	 * 1 dmap), there is no need to search the dmap control page (below)
+	 * that fully describes the allocation group since the allocation
+	 * group is already fully described by a dmap.  in this case, we
+	 * just call dbAllocCtl() to search the dmap tree and allocate the
+	 * required space if available.  
+	 *
+	 * if the allocation group is completely free, dbAllocCtl() is
+	 * also called to allocate the required space.  this is done for
+	 * two reasons.  first, it makes no sense searching the dmap control
+	 * pages for free space when we know that free space exists.  second,
+	 * the dmap control pages may indicate that the allocation group
+	 * has no free space if the allocation group is part (not the first
+	 * part) of a larger binary buddy system.
+	 */
+	if (bmp->db_agsize == BPERDMAP
+	    || bmp->db_agfree[agno] == bmp->db_agsize) {
+		rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results);
+		/* assert(!(rc == ENOSPC && bmp->db_agfree[agno] == bmp->db_agsize)); */
+		if ((rc == ENOSPC) &&
+		    (bmp->db_agfree[agno] == bmp->db_agsize)) {
+			jERROR(1,
+			       ("dbAllocAG: removed assert, but still need to debug here\nblkno = 0x%Lx, nblocks = 0x%Lx\n",
+				(unsigned long long) blkno,
+				(unsigned long long) nblocks));
+		}
+		return (rc);
+	}
+
+	/* the buffer for the dmap control page that fully describes the
+	 * allocation group.
+	 */
+	lblkno = BLKTOCTL(blkno, bmp->db_l2nbperpage, bmp->db_aglevel);
+	mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
+	if (mp == NULL)
+		return (EIO);
+	dcp = (struct dmapctl *) mp->data;
+	budmin = dcp->budmin;
+
+	/* search the subtree(s) of the dmap control page that describes
+	 * the allocation group, looking for sufficient free space.  to begin,
+	 * determine how many allocation groups are represented in a dmap
+	 * control page at the control page level (i.e. L0, L1, L2) that
+	 * fully describes an allocation group. next, determine the starting
+	 * tree index of this allocation group within the control page.
+	 */
+	agperlev =
+	    (1 << (L2LPERCTL - (bmp->db_agheigth << 1))) / bmp->db_agwidth;
+	ti = bmp->db_agstart + bmp->db_agwidth * (agno & (agperlev - 1));
+
+	/* dmap control page trees fan-out by 4 and a single allocation 
+	 * group may be described by 1 or 2 subtrees within the ag level
+	 * dmap control page, depending upon the ag size. examine the ag's
+	 * subtrees for sufficient free space, starting with the leftmost
+	 * subtree.
+	 */
+	for (i = 0; i < bmp->db_agwidth; i++, ti++) {
+		/* is there sufficient free space ?
+		 */
+		if (l2nb > dcp->stree[ti])
+			continue;
+
+		/* sufficient free space found in a subtree. now search down
+		 * the subtree to find the leftmost leaf that describes this
+		 * free space.
+		 */
+		for (k = bmp->db_agheigth; k > 0; k--) {
+			for (n = 0, m = (ti << 2) + 1; n < 4; n++) {
+				if (l2nb <= dcp->stree[m + n]) {
+					ti = m + n;
+					break;
+				}
+			}
+			assert(n < 4);
+		}
+
+		/* determine the block number within the file system
+		 * that corresponds to this leaf.
+		 */
+		if (bmp->db_aglevel == 2)
+			blkno = 0;
+		else if (bmp->db_aglevel == 1)
+			blkno &= ~(MAXL1SIZE - 1);
+		else		/* bmp->db_aglevel == 0 */
+			blkno &= ~(MAXL0SIZE - 1);
+
+		blkno +=
+		    ((s64) (ti - le32_to_cpu(dcp->leafidx))) << budmin;
+
+		/* release the buffer in preparation for going down
+		 * the next level of dmap control pages.
+		 */
+		release_metapage(mp);
+
+		/* check if we need to continue to search down the lower
+		 * level dmap control pages.  we need to if the number of
+		 * blocks required is less than maximum number of blocks
+		 * described at the next lower level.
+		 */
+		if (l2nb < budmin) {
+
+			/* search the lower level dmap control pages to get
+			 * the starting block number of the the dmap that
+			 * contains or starts off the free space.
+			 */
+			if ((rc =
+			     dbFindCtl(bmp, l2nb, bmp->db_aglevel - 1,
+				       &blkno))) {
+				assert(rc != ENOSPC);
+				return (rc);
+			}
+		}
+
+		/* allocate the blocks.
+		 */
+		rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results);
+		assert(rc != ENOSPC);
+		return (rc);
+	}
+
+	/* no space in the allocation group.  release the buffer and
+	 * return ENOSPC.
+	 */
+	release_metapage(mp);
+
+	return (ENOSPC);
+}
+
+
+/*
+ * NAME:	dbAllocAny()
+ *
+ * FUNCTION:    attempt to allocate the specified number of contiguous
+ *		free blocks anywhere in the file system.
+ *
+ *		dbAllocAny() attempts to find the sufficient free space by
+ *		searching down the dmap control pages, starting with the
+ *		highest level (i.e. L0, L1, L2) control page.  if free space
+ *		large enough to satisfy the desired free space is found, the
+ *		desired free space is allocated.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      nblocks	 -  actual number of contiguous free blocks desired.
+ *      l2nb	 -  log2 number of contiguous free blocks desired.
+ *      results	-  on successful return, set to the starting block number
+ *		   of the newly allocated range.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ *
+ * serialization: IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results)
+{
+	int rc;
+	s64 blkno = 0;
+
+	/* starting with the top level dmap control page, search
+	 * down the dmap control levels for sufficient free space.
+	 * if free space is found, dbFindCtl() returns the starting
+	 * block number of the dmap that contains or starts off the
+	 * range of free space.
+	 */
+	if ((rc = dbFindCtl(bmp, l2nb, bmp->db_maxlevel, &blkno)))
+		return (rc);
+
+	/* allocate the blocks.
+	 */
+	rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results);
+	assert(rc != ENOSPC);
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbFindCtl()
+ *
+ * FUNCTION:    starting at a specified dmap control page level and block
+ *		number, search down the dmap control levels for a range of
+ *	        contiguous free blocks large enough to satisfy an allocation
+ *		request for the specified number of free blocks.
+ *
+ *		if sufficient contiguous free blocks are found, this routine
+ *		returns the starting block number within a dmap page that
+ *		contains or starts a range of contiqious free blocks that
+ *		is sufficient in size.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      level	-  starting dmap control page level.
+ *      l2nb	-  log2 number of contiguous free blocks desired.
+ *      *blkno	-  on entry, starting block number for conducting the search.
+ *		   on successful return, the first block within a dmap page
+ *		   that contains or starts a range of contiguous free blocks.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ *
+ * serialization: IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno)
+{
+	int rc, leafidx, lev;
+	s64 b, lblkno;
+	struct dmapctl *dcp;
+	int budmin;
+	struct metapage *mp;
+
+	/* starting at the specified dmap control page level and block
+	 * number, search down the dmap control levels for the starting
+	 * block number of a dmap page that contains or starts off 
+	 * sufficient free blocks.
+	 */
+	for (lev = level, b = *blkno; lev >= 0; lev--) {
+		/* get the buffer of the dmap control page for the block
+		 * number and level (i.e. L0, L1, L2).
+		 */
+		lblkno = BLKTOCTL(b, bmp->db_l2nbperpage, lev);
+		mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
+		if (mp == NULL)
+			return (EIO);
+		dcp = (struct dmapctl *) mp->data;
+		budmin = dcp->budmin;
+
+		/* search the tree within the dmap control page for
+		 * sufficent free space.  if sufficient free space is found,
+		 * dbFindLeaf() returns the index of the leaf at which
+		 * free space was found.
+		 */
+		rc = dbFindLeaf((dmtree_t *) dcp, l2nb, &leafidx);
+
+		/* release the buffer.
+		 */
+		release_metapage(mp);
+
+		/* space found ?
+		 */
+		if (rc) {
+			assert(lev == level);
+			return (ENOSPC);
+		}
+
+		/* adjust the block number to reflect the location within
+		 * the dmap control page (i.e. the leaf) at which free 
+		 * space was found.
+		 */
+		b += (((s64) leafidx) << budmin);
+
+		/* we stop the search at this dmap control page level if
+		 * the number of blocks required is greater than or equal
+		 * to the maximum number of blocks described at the next
+		 * (lower) level.
+		 */
+		if (l2nb >= budmin)
+			break;
+	}
+
+	*blkno = b;
+	return (0);
+}
+
+
+/*
+ * NAME:	dbAllocCtl()
+ *
+ * FUNCTION:    attempt to allocate a specified number of contiguous
+ *		blocks starting within a specific dmap.  
+ *		
+ *		this routine is called by higher level routines that search
+ *		the dmap control pages above the actual dmaps for contiguous
+ *		free space.  the result of successful searches by these
+ * 		routines are the starting block numbers within dmaps, with
+ *		the dmaps themselves containing the desired contiguous free
+ *		space or starting a contiguous free space of desired size
+ *		that is made up of the blocks of one or more dmaps. these
+ *		calls should not fail due to insufficent resources.
+ *
+ *		this routine is called in some cases where it is not known
+ *		whether it will fail due to insufficient resources.  more
+ *		specifically, this occurs when allocating from an allocation
+ *		group whose size is equal to the number of blocks per dmap.
+ *		in this case, the dmap control pages are not examined prior
+ *		to calling this routine (to save pathlength) and the call
+ *		might fail.
+ *
+ *		for a request size that fits within a dmap, this routine relies
+ *		upon the dmap's dmtree to find the requested contiguous free
+ *		space.  for request sizes that are larger than a dmap, the
+ *		requested free space will start at the first block of the
+ *		first dmap (i.e. blkno).
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      nblocks	 -  actual number of contiguous free blocks to allocate.
+ *      l2nb	 -  log2 number of contiguous free blocks to allocate.
+ *      blkno	 -  starting block number of the dmap to start the allocation
+ *		    from.
+ *      results	-  on successful return, set to the starting block number
+ *		   of the newly allocated range.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ *
+ * serialization: IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static int
+dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results)
+{
+	int rc, nb;
+	s64 b, lblkno, n;
+	struct metapage *mp;
+	struct dmap *dp;
+
+	/* check if the allocation request is confined to a single dmap.
+	 */
+	if (l2nb <= L2BPERDMAP) {
+		/* get the buffer for the dmap.
+		 */
+		lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage);
+		mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
+		if (mp == NULL)
+			return (EIO);
+		dp = (struct dmap *) mp->data;
+
+		/* try to allocate the blocks.
+		 */
+		rc = dbAllocDmapLev(bmp, dp, (int) nblocks, l2nb, results);
+		if (rc == 0)
+			mark_metapage_dirty(mp);
+
+		release_metapage(mp);
+
+		return (rc);
+	}
+
+	/* allocation request involving multiple dmaps. it must start on
+	 * a dmap boundary.
+	 */
+	assert((blkno & (BPERDMAP - 1)) == 0);
+
+	/* allocate the blocks dmap by dmap.
+	 */
+	for (n = nblocks, b = blkno; n > 0; n -= nb, b += nb) {
+		/* get the buffer for the dmap.
+		 */
+		lblkno = BLKTODMAP(b, bmp->db_l2nbperpage);
+		mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
+		if (mp == NULL) {
+			rc = EIO;
+			goto backout;
+		}
+		dp = (struct dmap *) mp->data;
+
+		/* the dmap better be all free.
+		 */
+		assert(dp->tree.stree[ROOT] == L2BPERDMAP);
+
+		/* determine how many blocks to allocate from this dmap.
+		 */
+		nb = min(n, (s64)BPERDMAP);
+
+		/* allocate the blocks from the dmap.
+		 */
+		if ((rc = dbAllocDmap(bmp, dp, b, nb))) {
+			release_metapage(mp);
+			goto backout;
+		}
+
+		/* write the buffer.
+		 */
+		write_metapage(mp);
+	}
+
+	/* set the results (starting block number) and return.
+	 */
+	*results = blkno;
+	return (0);
+
+	/* something failed in handling an allocation request involving
+	 * multiple dmaps.  we'll try to clean up by backing out any
+	 * allocation that has already happened for this request.  if
+	 * we fail in backing out the allocation, we'll mark the file
+	 * system to indicate that blocks have been leaked.
+	 */
+      backout:
+
+	/* try to backout the allocations dmap by dmap.
+	 */
+	for (n = nblocks - n, b = blkno; n > 0;
+	     n -= BPERDMAP, b += BPERDMAP) {
+		/* get the buffer for this dmap.
+		 */
+		lblkno = BLKTODMAP(b, bmp->db_l2nbperpage);
+		mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
+		if (mp == NULL) {
+			/* could not back out.  mark the file system
+			 * to indicate that we have leaked blocks.
+			 */
+			fsDirty();	/* !!! */
+			jERROR(1,
+			       ("dbAllocCtl: I/O Error: Block Leakage.\n"));
+			continue;
+		}
+		dp = (struct dmap *) mp->data;
+
+		/* free the blocks is this dmap.
+		 */
+		if (dbFreeDmap(bmp, dp, b, BPERDMAP)) {
+			/* could not back out.  mark the file system
+			 * to indicate that we have leaked blocks.
+			 */
+			release_metapage(mp);
+			fsDirty();	/* !!! */
+			jERROR(1, ("dbAllocCtl: Block Leakage.\n"));
+			continue;
+		}
+
+		/* write the buffer.
+		 */
+		write_metapage(mp);
+	}
+
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbAllocDmapLev()
+ *
+ * FUNCTION:    attempt to allocate a specified number of contiguous blocks
+ *		from a specified dmap.
+ *		
+ *		this routine checks if the contiguous blocks are available.
+ *		if so, nblocks of blocks are allocated; otherwise, ENOSPC is
+ *		returned.
+ *
+ * PARAMETERS:
+ *      mp	-  pointer to bmap descriptor
+ *      dp	-  pointer to dmap to attempt to allocate blocks from. 
+ *      l2nb	-  log2 number of contiguous block desired.
+ *      nblocks	-  actual number of contiguous block desired.
+ *      results	-  on successful return, set to the starting block number
+ *		   of the newly allocated range.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ *
+ * serialization: IREAD_LOCK(ipbmap), e.g., from dbAlloc(), or 
+ *	IWRITE_LOCK(ipbmap), e.g., dbAllocCtl(), held on entry/exit;
+ */
+static int
+dbAllocDmapLev(struct bmap * bmp,
+	       struct dmap * dp, int nblocks, int l2nb, s64 * results)
+{
+	s64 blkno;
+	int leafidx, rc;
+
+	/* can't be more than a dmaps worth of blocks */
+	assert(l2nb <= L2BPERDMAP);
+
+	/* search the tree within the dmap page for sufficient
+	 * free space.  if sufficient free space is found, dbFindLeaf()
+	 * returns the index of the leaf at which free space was found.
+	 */
+	if (dbFindLeaf((dmtree_t *) & dp->tree, l2nb, &leafidx))
+		return (ENOSPC);
+
+	/* determine the block number within the file system corresponding
+	 * to the leaf at which free space was found.
+	 */
+	blkno = le64_to_cpu(dp->start) + (leafidx << L2DBWORD);
+
+	/* if not all bits of the dmap word are free, get the starting
+	 * bit number within the dmap word of the required string of free
+	 * bits and adjust the block number with this value.
+	 */
+	if (dp->tree.stree[leafidx + LEAFIND] < BUDMIN)
+		blkno += dbFindBits(le32_to_cpu(dp->wmap[leafidx]), l2nb);
+
+	/* allocate the blocks */
+	if ((rc = dbAllocDmap(bmp, dp, blkno, nblocks)) == 0)
+		*results = blkno;
+
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbAllocDmap()
+ *
+ * FUNCTION:    adjust the disk allocation map to reflect the allocation
+ *		of a specified block range within a dmap.
+ *
+ *		this routine allocates the specified blocks from the dmap
+ *		through a call to dbAllocBits(). if the allocation of the
+ *		block range causes the maximum string of free blocks within
+ *		the dmap to change (i.e. the value of the root of the dmap's
+ *		dmtree), this routine will cause this change to be reflected
+ *		up through the appropriate levels of the dmap control pages
+ *		by a call to dbAdjCtl() for the L0 dmap control page that
+ *		covers this dmap.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      dp	-  pointer to dmap to allocate the block range from.
+ *      blkno	-  starting block number of the block to be allocated.
+ *      nblocks	-  number of blocks to be allocated.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      EIO	- i/o error
+ *
+ * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static int dbAllocDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		       int nblocks)
+{
+	s8 oldroot;
+	int rc;
+
+	/* save the current value of the root (i.e. maximum free string)
+	 * of the dmap tree.
+	 */
+	oldroot = dp->tree.stree[ROOT];
+
+	/* allocate the specified (blocks) bits */
+	dbAllocBits(bmp, dp, blkno, nblocks);
+
+	/* if the root has not changed, done. */
+	if (dp->tree.stree[ROOT] == oldroot)
+		return (0);
+
+	/* root changed. bubble the change up to the dmap control pages.
+	 * if the adjustment of the upper level control pages fails,
+	 * backout the bit allocation (thus making everything consistent).
+	 */
+	if ((rc = dbAdjCtl(bmp, blkno, dp->tree.stree[ROOT], 1, 0)))
+		dbFreeBits(bmp, dp, blkno, nblocks);
+
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbFreeDmap()
+ *
+ * FUNCTION:    adjust the disk allocation map to reflect the allocation
+ *		of a specified block range within a dmap.
+ *
+ *		this routine frees the specified blocks from the dmap through
+ *		a call to dbFreeBits(). if the deallocation of the block range
+ *		causes the maximum string of free blocks within the dmap to
+ *		change (i.e. the value of the root of the dmap's dmtree), this
+ *		routine will cause this change to be reflected up through the
+ *	        appropriate levels of the dmap control pages by a call to
+ *		dbAdjCtl() for the L0 dmap control page that covers this dmap.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      dp	-  pointer to dmap to free the block range from.
+ *      blkno	-  starting block number of the block to be freed.
+ *      nblocks	-  number of blocks to be freed.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      EIO	- i/o error
+ *
+ * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		      int nblocks)
+{
+	s8 oldroot;
+	int rc, word;
+
+	/* save the current value of the root (i.e. maximum free string)
+	 * of the dmap tree.
+	 */
+	oldroot = dp->tree.stree[ROOT];
+
+	/* free the specified (blocks) bits */
+	dbFreeBits(bmp, dp, blkno, nblocks);
+
+	/* if the root has not changed, done. */
+	if (dp->tree.stree[ROOT] == oldroot)
+		return (0);
+
+	/* root changed. bubble the change up to the dmap control pages.
+	 * if the adjustment of the upper level control pages fails,
+	 * backout the deallocation. 
+	 */
+	if ((rc = dbAdjCtl(bmp, blkno, dp->tree.stree[ROOT], 0, 0))) {
+		word = (blkno & (BPERDMAP - 1)) >> L2DBWORD;
+
+		/* as part of backing out the deallocation, we will have
+		 * to back split the dmap tree if the deallocation caused
+		 * the freed blocks to become part of a larger binary buddy
+		 * system.
+		 */
+		if (dp->tree.stree[word] == NOFREE)
+			dbBackSplit((dmtree_t *) & dp->tree, word);
+
+		dbAllocBits(bmp, dp, blkno, nblocks);
+	}
+
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbAllocBits()
+ *
+ * FUNCTION:    allocate a specified block range from a dmap.
+ *
+ *		this routine updates the dmap to reflect the working
+ *		state allocation of the specified block range. it directly
+ *		updates the bits of the working map and causes the adjustment
+ *		of the binary buddy system described by the dmap's dmtree
+ *		leaves to reflect the bits allocated.  it also causes the
+ *		dmap's dmtree, as a whole, to reflect the allocated range.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      dp	-  pointer to dmap to allocate bits from.
+ *      blkno	-  starting block number of the bits to be allocated.
+ *      nblocks	-  number of bits to be allocated.
+ *
+ * RETURN VALUES: none
+ *
+ * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
+			int nblocks)
+{
+	int dbitno, word, rembits, nb, nwords, wbitno, nw, agno;
+	dmtree_t *tp = (dmtree_t *) & dp->tree;
+	int size;
+	s8 *leaf;
+
+	/* pick up a pointer to the leaves of the dmap tree */
+	leaf = dp->tree.stree + LEAFIND;
+
+	/* determine the bit number and word within the dmap of the
+	 * starting block.
+	 */
+	dbitno = blkno & (BPERDMAP - 1);
+	word = dbitno >> L2DBWORD;
+
+	/* block range better be within the dmap */
+	assert(dbitno + nblocks <= BPERDMAP);
+
+	/* allocate the bits of the dmap's words corresponding to the block
+	 * range. not all bits of the first and last words may be contained
+	 * within the block range.  if this is the case, we'll work against
+	 * those words (i.e. partial first and/or last) on an individual basis
+	 * (a single pass), allocating the bits of interest by hand and
+	 * updating the leaf corresponding to the dmap word. a single pass
+	 * will be used for all dmap words fully contained within the
+	 * specified range.  within this pass, the bits of all fully contained
+	 * dmap words will be marked as free in a single shot and the leaves
+	 * will be updated. a single leaf may describe the free space of
+	 * multiple dmap words, so we may update only a subset of the actual
+	 * leaves corresponding to the dmap words of the block range.
+	 */
+	for (rembits = nblocks; rembits > 0; rembits -= nb, dbitno += nb) {
+		/* determine the bit number within the word and
+		 * the number of bits within the word.
+		 */
+		wbitno = dbitno & (DBWORD - 1);
+		nb = min(rembits, DBWORD - wbitno);
+
+		/* check if only part of a word is to be allocated.
+		 */
+		if (nb < DBWORD) {
+			/* allocate (set to 1) the appropriate bits within
+			 * this dmap word.
+			 */
+			dp->wmap[word] |= cpu_to_le32(ONES << (DBWORD - nb)
+						      >> wbitno);
+
+			/* update the leaf for this dmap word. in addition
+			 * to setting the leaf value to the binary buddy max
+			 * of the updated dmap word, dbSplit() will split
+			 * the binary system of the leaves if need be.
+			 */
+			dbSplit(tp, word, BUDMIN,
+				dbMaxBud((u8 *) & dp->wmap[word]));
+
+			word += 1;
+		} else {
+			/* one or more dmap words are fully contained
+			 * within the block range.  determine how many
+			 * words and allocate (set to 1) the bits of these
+			 * words.
+			 */
+			nwords = rembits >> L2DBWORD;
+			memset(&dp->wmap[word], (int) ONES, nwords * 4);
+
+			/* determine how many bits.
+			 */
+			nb = nwords << L2DBWORD;
+
+			/* now update the appropriate leaves to reflect
+			 * the allocated words.
+			 */
+			for (; nwords > 0; nwords -= nw) {
+				assert(leaf[word] >= BUDMIN);
+
+				/* determine what the leaf value should be
+				 * updated to as the minimum of the l2 number
+				 * of bits being allocated and the l2 number
+				 * of bits currently described by this leaf.
+				 */
+				size = min((int)leaf[word], NLSTOL2BSZ(nwords));
+
+				/* update the leaf to reflect the allocation.
+				 * in addition to setting the leaf value to
+				 * NOFREE, dbSplit() will split the binary
+				 * system of the leaves to reflect the current
+				 * allocation (size).
+				 */
+				dbSplit(tp, word, size, NOFREE);
+
+				/* get the number of dmap words handled */
+				nw = BUDSIZE(size, BUDMIN);
+				word += nw;
+			}
+		}
+	}
+
+	/* update the free count for this dmap */
+	dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) - nblocks);
+
+	BMAP_LOCK(bmp);
+
+	/* if this allocation group is completely free,
+	 * update the maximum allocation group number if this allocation
+	 * group is the new max.
+	 */
+	agno = blkno >> bmp->db_agl2size;
+	if (agno > bmp->db_maxag)
+		bmp->db_maxag = agno;
+
+	/* update the free count for the allocation group and map */
+	bmp->db_agfree[agno] -= nblocks;
+	bmp->db_nfree -= nblocks;
+
+	BMAP_UNLOCK(bmp);
+}
+
+
+/*
+ * NAME:	dbFreeBits()
+ *
+ * FUNCTION:    free a specified block range from a dmap.
+ *
+ *		this routine updates the dmap to reflect the working
+ *		state allocation of the specified block range. it directly
+ *		updates the bits of the working map and causes the adjustment
+ *		of the binary buddy system described by the dmap's dmtree
+ *		leaves to reflect the bits freed.  it also causes the dmap's
+ *		dmtree, as a whole, to reflect the deallocated range.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      dp	-  pointer to dmap to free bits from.
+ *      blkno	-  starting block number of the bits to be freed.
+ *      nblocks	-  number of bits to be freed.
+ *
+ * RETURN VALUES: none
+ *
+ * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static void dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		       int nblocks)
+{
+	int dbitno, word, rembits, nb, nwords, wbitno, nw, agno;
+	dmtree_t *tp = (dmtree_t *) & dp->tree;
+	int size;
+
+	/* determine the bit number and word within the dmap of the
+	 * starting block.
+	 */
+	dbitno = blkno & (BPERDMAP - 1);
+	word = dbitno >> L2DBWORD;
+
+	/* block range better be within the dmap.
+	 */
+	assert(dbitno + nblocks <= BPERDMAP);
+
+	/* free the bits of the dmaps words corresponding to the block range.
+	 * not all bits of the first and last words may be contained within
+	 * the block range.  if this is the case, we'll work against those
+	 * words (i.e. partial first and/or last) on an individual basis
+	 * (a single pass), freeing the bits of interest by hand and updating
+	 * the leaf corresponding to the dmap word. a single pass will be used
+	 * for all dmap words fully contained within the specified range.  
+	 * within this pass, the bits of all fully contained dmap words will
+	 * be marked as free in a single shot and the leaves will be updated. a
+	 * single leaf may describe the free space of multiple dmap words,
+	 * so we may update only a subset of the actual leaves corresponding
+	 * to the dmap words of the block range.
+	 *
+	 * dbJoin() is used to update leaf values and will join the binary
+	 * buddy system of the leaves if the new leaf values indicate this
+	 * should be done.
+	 */
+	for (rembits = nblocks; rembits > 0; rembits -= nb, dbitno += nb) {
+		/* determine the bit number within the word and
+		 * the number of bits within the word.
+		 */
+		wbitno = dbitno & (DBWORD - 1);
+		nb = min(rembits, DBWORD - wbitno);
+
+		/* check if only part of a word is to be freed.
+		 */
+		if (nb < DBWORD) {
+			/* free (zero) the appropriate bits within this
+			 * dmap word. 
+			 */
+			dp->wmap[word] &=
+			    cpu_to_le32(~(ONES << (DBWORD - nb)
+					  >> wbitno));
+
+			/* update the leaf for this dmap word.
+			 */
+			dbJoin(tp, word,
+			       dbMaxBud((u8 *) & dp->wmap[word]));
+
+			word += 1;
+		} else {
+			/* one or more dmap words are fully contained
+			 * within the block range.  determine how many
+			 * words and free (zero) the bits of these words.
+			 */
+			nwords = rembits >> L2DBWORD;
+			memset(&dp->wmap[word], 0, nwords * 4);
+
+			/* determine how many bits.
+			 */
+			nb = nwords << L2DBWORD;
+
+			/* now update the appropriate leaves to reflect
+			 * the freed words.
+			 */
+			for (; nwords > 0; nwords -= nw) {
+				/* determine what the leaf value should be
+				 * updated to as the minimum of the l2 number
+				 * of bits being freed and the l2 (max) number
+				 * of bits that can be described by this leaf.
+				 */
+				size =
+				    min(LITOL2BSZ
+					(word, L2LPERDMAP, BUDMIN),
+					NLSTOL2BSZ(nwords));
+
+				/* update the leaf.
+				 */
+				dbJoin(tp, word, size);
+
+				/* get the number of dmap words handled.
+				 */
+				nw = BUDSIZE(size, BUDMIN);
+				word += nw;
+			}
+		}
+	}
+
+	/* update the free count for this dmap.
+	 */
+	dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) + nblocks);
+
+	BMAP_LOCK(bmp);
+
+	/* update the free count for the allocation group and 
+	 * map.
+	 */
+	agno = blkno >> bmp->db_agl2size;
+	bmp->db_nfree += nblocks;
+	bmp->db_agfree[agno] += nblocks;
+
+	/* check if this allocation group is not completely free and
+	 * if it is currently the maximum (rightmost) allocation group.
+	 * if so, establish the new maximum allocation group number by
+	 * searching left for the first allocation group with allocation.
+	 */
+	if ((bmp->db_agfree[agno] == bmp->db_agsize && agno == bmp->db_maxag) ||
+	    (agno == bmp->db_numag - 1 &&
+	     bmp->db_agfree[agno] == (bmp-> db_mapsize & (BPERDMAP - 1)))) {
+		while (bmp->db_maxag > 0) {
+			bmp->db_maxag -= 1;
+			if (bmp->db_agfree[bmp->db_maxag] !=
+			    bmp->db_agsize)
+				break;
+		}
+
+		/* re-establish the allocation group preference if the
+		 * current preference is right of the maximum allocation
+		 * group.
+		 */
+		if (bmp->db_agpref > bmp->db_maxag)
+			bmp->db_agpref = bmp->db_maxag;
+	}
+
+	BMAP_UNLOCK(bmp);
+}
+
+
+/*
+ * NAME:	dbAdjCtl()
+ *
+ * FUNCTION:	adjust a dmap control page at a specified level to reflect
+ *		the change in a lower level dmap or dmap control page's
+ *		maximum string of free blocks (i.e. a change in the root
+ *		of the lower level object's dmtree) due to the allocation
+ *		or deallocation of a range of blocks with a single dmap.
+ *
+ *		on entry, this routine is provided with the new value of
+ *		the lower level dmap or dmap control page root and the
+ *		starting block number of the block range whose allocation
+ *		or deallocation resulted in the root change.  this range
+ *		is respresented by a single leaf of the current dmapctl
+ *		and the leaf will be updated with this value, possibly
+ *		causing a binary buddy system within the leaves to be 
+ *		split or joined.  the update may also cause the dmapctl's
+ *		dmtree to be updated.
+ *
+ *		if the adjustment of the dmap control page, itself, causes its
+ *		root to change, this change will be bubbled up to the next dmap
+ *		control level by a recursive call to this routine, specifying
+ *		the new root value and the next dmap control page level to
+ *		be adjusted.
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      blkno	-  the first block of a block range within a dmap.  it is
+ *		   the allocation or deallocation of this block range that
+ *		   requires the dmap control page to be adjusted.
+ *      newval	-  the new value of the lower level dmap or dmap control
+ *		   page root.
+ *      alloc	-  TRUE if adjustment is due to an allocation.
+ *      level	-  current level of dmap control page (i.e. L0, L1, L2) to
+ *		   be adjusted.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      EIO	- i/o error
+ *
+ * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static int
+dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level)
+{
+	struct metapage *mp;
+	s8 oldroot;
+	int oldval;
+	s64 lblkno;
+	struct dmapctl *dcp;
+	int rc, leafno, ti;
+
+	/* get the buffer for the dmap control page for the specified
+	 * block number and control page level.
+	 */
+	lblkno = BLKTOCTL(blkno, bmp->db_l2nbperpage, level);
+	mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
+	if (mp == NULL)
+		return (EIO);
+	dcp = (struct dmapctl *) mp->data;
+
+	/* determine the leaf number corresponding to the block and
+	 * the index within the dmap control tree.
+	 */
+	leafno = BLKTOCTLLEAF(blkno, dcp->budmin);
+	ti = leafno + le32_to_cpu(dcp->leafidx);
+
+	/* save the current leaf value and the current root level (i.e.
+	 * maximum l2 free string described by this dmapctl).
+	 */
+	oldval = dcp->stree[ti];
+	oldroot = dcp->stree[ROOT];
+
+	/* check if this is a control page update for an allocation.
+	 * if so, update the leaf to reflect the new leaf value using
+	 * dbSplit(); otherwise (deallocation), use dbJoin() to udpate
+	 * the leaf with the new value.  in addition to updating the
+	 * leaf, dbSplit() will also split the binary buddy system of
+	 * the leaves, if required, and bubble new values within the
+	 * dmapctl tree, if required.  similarly, dbJoin() will join
+	 * the binary buddy system of leaves and bubble new values up
+	 * the dmapctl tree as required by the new leaf value.
+	 */
+	if (alloc) {
+		/* check if we are in the middle of a binary buddy
+		 * system.  this happens when we are performing the
+		 * first allocation out of an allocation group that
+		 * is part (not the first part) of a larger binary
+		 * buddy system.  if we are in the middle, back split
+		 * the system prior to calling dbSplit() which assumes
+		 * that it is at the front of a binary buddy system.
+		 */
+		if (oldval == NOFREE) {
+			dbBackSplit((dmtree_t *) dcp, leafno);
+			oldval = dcp->stree[ti];
+		}
+		dbSplit((dmtree_t *) dcp, leafno, dcp->budmin, newval);
+	} else {
+		dbJoin((dmtree_t *) dcp, leafno, newval);
+	}
+
+	/* check if the root of the current dmap control page changed due
+	 * to the update and if the current dmap control page is not at
+	 * the current top level (i.e. L0, L1, L2) of the map.  if so (i.e.
+	 * root changed and this is not the top level), call this routine
+	 * again (recursion) for the next higher level of the mapping to
+	 * reflect the change in root for the current dmap control page.
+	 */
+	if (dcp->stree[ROOT] != oldroot) {
+		/* are we below the top level of the map.  if so,
+		 * bubble the root up to the next higher level.
+		 */
+		if (level < bmp->db_maxlevel) {
+			/* bubble up the new root of this dmap control page to
+			 * the next level.
+			 */
+			if ((rc =
+			     dbAdjCtl(bmp, blkno, dcp->stree[ROOT], alloc,
+				      level + 1))) {
+				/* something went wrong in bubbling up the new
+				 * root value, so backout the changes to the
+				 * current dmap control page.
+				 */
+				if (alloc) {
+					dbJoin((dmtree_t *) dcp, leafno,
+					       oldval);
+				} else {
+					/* the dbJoin() above might have
+					 * caused a larger binary buddy system
+					 * to form and we may now be in the
+					 * middle of it.  if this is the case,
+					 * back split the buddies.
+					 */
+					if (dcp->stree[ti] == NOFREE)
+						dbBackSplit((dmtree_t *)
+							    dcp, leafno);
+					dbSplit((dmtree_t *) dcp, leafno,
+						dcp->budmin, oldval);
+				}
+
+				/* release the buffer and return the error.
+				 */
+				release_metapage(mp);
+				return (rc);
+			}
+		} else {
+			/* we're at the top level of the map. update
+			 * the bmap control page to reflect the size
+			 * of the maximum free buddy system.
+			 */
+			assert(level == bmp->db_maxlevel);
+			assert(bmp->db_maxfreebud == oldroot);
+			bmp->db_maxfreebud = dcp->stree[ROOT];
+		}
+	}
+
+	/* write the buffer.
+	 */
+	write_metapage(mp);
+
+	return (0);
+}
+
+
+/*
+ * NAME:	dbSplit()
+ *
+ * FUNCTION:    update the leaf of a dmtree with a new value, splitting
+ *		the leaf from the binary buddy system of the dmtree's
+ *		leaves, as required.
+ *
+ * PARAMETERS:
+ *      tp	- pointer to the tree containing the leaf.
+ *      leafno	- the number of the leaf to be updated.
+ *      splitsz	- the size the binary buddy system starting at the leaf
+ *		  must be split to, specified as the log2 number of blocks.
+ *      newval	- the new value for the leaf.
+ *
+ * RETURN VALUES: none
+ *
+ * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval)
+{
+	int budsz;
+	int cursz;
+	s8 *leaf = tp->dmt_stree + le32_to_cpu(tp->dmt_leafidx);
+
+	/* check if the leaf needs to be split.
+	 */
+	if (leaf[leafno] > tp->dmt_budmin) {
+		/* the split occurs by cutting the buddy system in half
+		 * at the specified leaf until we reach the specified
+		 * size.  pick up the starting split size (current size
+		 * - 1 in l2) and the corresponding buddy size.
+		 */
+		cursz = leaf[leafno] - 1;
+		budsz = BUDSIZE(cursz, tp->dmt_budmin);
+
+		/* split until we reach the specified size.
+		 */
+		while (cursz >= splitsz) {
+			/* update the buddy's leaf with its new value.
+			 */
+			dbAdjTree(tp, leafno ^ budsz, cursz);
+
+			/* on to the next size and buddy.
+			 */
+			cursz -= 1;
+			budsz >>= 1;
+		}
+	}
+
+	/* adjust the dmap tree to reflect the specified leaf's new 
+	 * value.
+	 */
+	dbAdjTree(tp, leafno, newval);
+}
+
+
+/*
+ * NAME:	dbBackSplit()
+ *
+ * FUNCTION:    back split the binary buddy system of dmtree leaves
+ *		that hold a specified leaf until the specified leaf
+ *		starts its own binary buddy system.
+ *
+ *		the allocators typically perform allocations at the start
+ *		of binary buddy systems and dbSplit() is used to accomplish
+ *		any required splits.  in some cases, however, allocation
+ *		may occur in the middle of a binary system and requires a
+ *		back split, with the split proceeding out from the middle of
+ *		the system (less efficient) rather than the start of the
+ *		system (more efficient).  the cases in which a back split
+ *		is required are rare and are limited to the first allocation
+ *		within an allocation group which is a part (not first part)
+ *		of a larger binary buddy system and a few exception cases
+ *		in which a previous join operation must be backed out.
+ *
+ * PARAMETERS:
+ *      tp	- pointer to the tree containing the leaf.
+ *      leafno	- the number of the leaf to be updated.
+ *
+ * RETURN VALUES: none
+ *
+ * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static void dbBackSplit(dmtree_t * tp, int leafno)
+{
+	int budsz, bud, w, bsz, size;
+	int cursz;
+	s8 *leaf = tp->dmt_stree + le32_to_cpu(tp->dmt_leafidx);
+
+	/* leaf should be part (not first part) of a binary
+	 * buddy system.
+	 */
+	assert(leaf[leafno] == NOFREE);
+
+	/* the back split is accomplished by iteratively finding the leaf
+	 * that starts the buddy system that contains the specified leaf and
+	 * splitting that system in two.  this iteration continues until
+	 * the specified leaf becomes the start of a buddy system. 
+	 *
+	 * determine maximum possible l2 size for the specified leaf.
+	 */
+	size =
+	    LITOL2BSZ(leafno, le32_to_cpu(tp->dmt_l2nleafs),
+		      tp->dmt_budmin);
+
+	/* determine the number of leaves covered by this size.  this
+	 * is the buddy size that we will start with as we search for
+	 * the buddy system that contains the specified leaf.
+	 */
+	budsz = BUDSIZE(size, tp->dmt_budmin);
+
+	/* back split.
+	 */
+	while (leaf[leafno] == NOFREE) {
+		/* find the leftmost buddy leaf.
+		 */
+		for (w = leafno, bsz = budsz;; bsz <<= 1,
+		     w = (w < bud) ? w : bud) {
+			assert(bsz < le32_to_cpu(tp->dmt_nleafs));
+
+			/* determine the buddy.
+			 */
+			bud = w ^ bsz;
+
+			/* check if this buddy is the start of the system.
+			 */
+			if (leaf[bud] != NOFREE) {
+				/* split the leaf at the start of the
+				 * system in two.
+				 */
+				cursz = leaf[bud] - 1;
+				dbSplit(tp, bud, cursz, cursz);
+				break;
+			}
+		}
+	}
+
+	assert(leaf[leafno] == size);
+}
+
+
+/*
+ * NAME:	dbJoin()
+ *
+ * FUNCTION:    update the leaf of a dmtree with a new value, joining
+ *		the leaf with other leaves of the dmtree into a multi-leaf
+ *		binary buddy system, as required.
+ *
+ * PARAMETERS:
+ *      tp	- pointer to the tree containing the leaf.
+ *      leafno	- the number of the leaf to be updated.
+ *      newval	- the new value for the leaf.
+ *
+ * RETURN VALUES: none
+ */
+static void dbJoin(dmtree_t * tp, int leafno, int newval)
+{
+	int budsz, buddy;
+	s8 *leaf;
+
+	/* can the new leaf value require a join with other leaves ?
+	 */
+	if (newval >= tp->dmt_budmin) {
+		/* pickup a pointer to the leaves of the tree.
+		 */
+		leaf = tp->dmt_stree + le32_to_cpu(tp->dmt_leafidx);
+
+		/* try to join the specified leaf into a large binary
+		 * buddy system.  the join proceeds by attempting to join
+		 * the specified leafno with its buddy (leaf) at new value.
+		 * if the join occurs, we attempt to join the left leaf
+		 * of the joined buddies with its buddy at new value + 1.
+		 * we continue to join until we find a buddy that cannot be
+		 * joined (does not have a value equal to the size of the
+		 * last join) or until all leaves have been joined into a
+		 * single system.
+		 *
+		 * get the buddy size (number of words covered) of
+		 * the new value.
+		 */
+		budsz = BUDSIZE(newval, tp->dmt_budmin);
+
+		/* try to join.
+		 */
+		while (budsz < le32_to_cpu(tp->dmt_nleafs)) {
+			/* get the buddy leaf.
+			 */
+			buddy = leafno ^ budsz;
+
+			/* if the leaf's new value is greater than its
+			 * buddy's value, we join no more.
+			 */
+			if (newval > leaf[buddy])
+				break;
+
+			assert(newval == leaf[buddy]);
+
+			/* check which (leafno or buddy) is the left buddy.
+			 * the left buddy gets to claim the blocks resulting
+			 * from the join while the right gets to claim none.
+			 * the left buddy is also eligable to participate in
+			 * a join at the next higher level while the right
+			 * is not.
+			 *
+			 */
+			if (leafno < buddy) {
+				/* leafno is the left buddy.
+				 */
+				dbAdjTree(tp, buddy, NOFREE);
+			} else {
+				/* buddy is the left buddy and becomes
+				 * leafno.
+				 */
+				dbAdjTree(tp, leafno, NOFREE);
+				leafno = buddy;
+			}
+
+			/* on to try the next join.
+			 */
+			newval += 1;
+			budsz <<= 1;
+		}
+	}
+
+	/* update the leaf value.
+	 */
+	dbAdjTree(tp, leafno, newval);
+}
+
+
+/*
+ * NAME:	dbAdjTree()
+ *
+ * FUNCTION:    update a leaf of a dmtree with a new value, adjusting
+ *		the dmtree, as required, to reflect the new leaf value.
+ *		the combination of any buddies must already be done before
+ *		this is called.
+ *
+ * PARAMETERS:
+ *      tp	- pointer to the tree to be adjusted.
+ *      leafno	- the number of the leaf to be updated.
+ *      newval	- the new value for the leaf.
+ *
+ * RETURN VALUES: none
+ */
+static void dbAdjTree(dmtree_t * tp, int leafno, int newval)
+{
+	int lp, pp, k;
+	int max;
+
+	/* pick up the index of the leaf for this leafno.
+	 */
+	lp = leafno + le32_to_cpu(tp->dmt_leafidx);
+
+	/* is the current value the same as the old value ?  if so,
+	 * there is nothing to do.
+	 */
+	if (tp->dmt_stree[lp] == newval)
+		return;
+
+	/* set the new value.
+	 */
+	tp->dmt_stree[lp] = newval;
+
+	/* bubble the new value up the tree as required.
+	 */
+	for (k = 0; k < le32_to_cpu(tp->dmt_height); k++) {
+		/* get the index of the first leaf of the 4 leaf
+		 * group containing the specified leaf (leafno).
+		 */
+		lp = ((lp - 1) & ~0x03) + 1;
+
+		/* get the index of the parent of this 4 leaf group.
+		 */
+		pp = (lp - 1) >> 2;
+
+		/* determine the maximum of the 4 leaves.
+		 */
+		max = TREEMAX(&tp->dmt_stree[lp]);
+
+		/* if the maximum of the 4 is the same as the
+		 * parent's value, we're done.
+		 */
+		if (tp->dmt_stree[pp] == max)
+			break;
+
+		/* parent gets new value.
+		 */
+		tp->dmt_stree[pp] = max;
+
+		/* parent becomes leaf for next go-round.
+		 */
+		lp = pp;
+	}
+}
+
+
+/*
+ * NAME:	dbFindLeaf()
+ *
+ * FUNCTION:    search a dmtree_t for sufficient free blocks, returning
+ *		the index of a leaf describing the free blocks if 
+ *		sufficient free blocks are found.
+ *
+ *		the search starts at the top of the dmtree_t tree and
+ *		proceeds down the tree to the leftmost leaf with sufficient
+ *		free space.
+ *
+ * PARAMETERS:
+ *      tp	- pointer to the tree to be searched.
+ *      l2nb	- log2 number of free blocks to search for.
+ *	leafidx	- return pointer to be set to the index of the leaf
+ *		  describing at least l2nb free blocks if sufficient
+ *		  free blocks are found.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient free blocks. 
+ */
+static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx)
+{
+	int ti, n = 0, k, x = 0;
+
+	/* first check the root of the tree to see if there is
+	 * sufficient free space.
+	 */
+	if (l2nb > tp->dmt_stree[ROOT])
+		return (ENOSPC);
+
+	/* sufficient free space available. now search down the tree
+	 * starting at the next level for the leftmost leaf that
+	 * describes sufficient free space.
+	 */
+	for (k = le32_to_cpu(tp->dmt_height), ti = 1;
+	     k > 0; k--, ti = ((ti + n) << 2) + 1) {
+		/* search the four nodes at this level, starting from
+		 * the left.
+		 */
+		for (x = ti, n = 0; n < 4; n++) {
+			/* sufficient free space found.  move to the next
+			 * level (or quit if this is the last level).
+			 */
+			if (l2nb <= tp->dmt_stree[x + n])
+				break;
+		}
+
+		/* better have found something since the higher
+		 * levels of the tree said it was here.
+		 */
+		assert(n < 4);
+	}
+
+	/* set the return to the leftmost leaf describing sufficient
+	 * free space.
+	 */
+	*leafidx = x + n - le32_to_cpu(tp->dmt_leafidx);
+
+	return (0);
+}
+
+
+/*
+ * NAME:	dbFindBits()
+ *
+ * FUNCTION:    find a specified number of binary buddy free bits within a
+ *		dmap bitmap word value.
+ *
+ *		this routine searches the bitmap value for (1 << l2nb) free
+ *		bits at (1 << l2nb) alignments within the value.
+ *
+ * PARAMETERS:
+ *      word	-  dmap bitmap word value.
+ *      l2nb	-  number of free bits specified as a log2 number.
+ *
+ * RETURN VALUES:
+ *      starting bit number of free bits.
+ */
+static int dbFindBits(u32 word, int l2nb)
+{
+	int bitno, nb;
+	u32 mask;
+
+	/* get the number of bits.
+	 */
+	nb = 1 << l2nb;
+	assert(nb <= DBWORD);
+
+	/* complement the word so we can use a mask (i.e. 0s represent
+	 * free bits) and compute the mask.
+	 */
+	word = ~word;
+	mask = ONES << (DBWORD - nb);
+
+	/* scan the word for nb free bits at nb alignments.
+	 */
+	for (bitno = 0; mask != 0; bitno += nb, mask >>= nb) {
+		if ((mask & word) == mask)
+			break;
+	}
+
+	ASSERT(bitno < 32);
+
+	/* return the bit number.
+	 */
+	return (bitno);
+}
+
+
+/*
+ * NAME:	dbMaxBud(u8 *cp)
+ *
+ * FUNCTION:    determine the largest binary buddy string of free
+ *		bits within 32-bits of the map.
+ *
+ * PARAMETERS:
+ *      cp	-  pointer to the 32-bit value.
+ *
+ * RETURN VALUES:
+ *      largest binary buddy of free bits within a dmap word.
+ */
+static int dbMaxBud(u8 * cp)
+{
+	signed char tmp1, tmp2;
+
+	/* check if the wmap word is all free. if so, the
+	 * free buddy size is BUDMIN.
+	 */
+	if (*((uint *) cp) == 0)
+		return (BUDMIN);
+
+	/* check if the wmap word is half free. if so, the
+	 * free buddy size is BUDMIN-1.
+	 */
+	if (*((u16 *) cp) == 0 || *((u16 *) cp + 1) == 0)
+		return (BUDMIN - 1);
+
+	/* not all free or half free. determine the free buddy
+	 * size thru table lookup using quarters of the wmap word.
+	 */
+	tmp1 = max(budtab[cp[2]], budtab[cp[3]]);
+	tmp2 = max(budtab[cp[0]], budtab[cp[1]]);
+	return (max(tmp1, tmp2));
+}
+
+
+/*
+ * NAME:	cnttz(uint word)
+ *
+ * FUNCTION:    determine the number of trailing zeros within a 32-bit
+ *		value.
+ *
+ * PARAMETERS:
+ *      value	-  32-bit value to be examined.
+ *
+ * RETURN VALUES:
+ *      count of trailing zeros
+ */
+int cnttz(u32 word)
+{
+	int n;
+
+	for (n = 0; n < 32; n++, word >>= 1) {
+		if (word & 0x01)
+			break;
+	}
+
+	return (n);
+}
+
+
+/*
+ * NAME:	cntlz(u32 value)
+ *
+ * FUNCTION:    determine the number of leading zeros within a 32-bit
+ *		value.
+ *
+ * PARAMETERS:
+ *      value	-  32-bit value to be examined.
+ *
+ * RETURN VALUES:
+ *      count of leading zeros
+ */
+int cntlz(u32 value)
+{
+	int n;
+
+	for (n = 0; n < 32; n++, value <<= 1) {
+		if (value & HIGHORDER)
+			break;
+	}
+	return (n);
+}
+
+
+/*
+ * NAME:	blkstol2(s64 nb)
+ *
+ * FUNCTION:	convert a block count to its log2 value. if the block
+ *	        count is not a l2 multiple, it is rounded up to the next
+ *		larger l2 multiple.
+ *
+ * PARAMETERS:
+ *      nb	-  number of blocks
+ *
+ * RETURN VALUES:
+ *      log2 number of blocks
+ */
+int blkstol2(s64 nb)
+{
+	int l2nb;
+	s64 mask;		/* meant to be signed */
+
+	mask = (s64) 1 << (64 - 1);
+
+	/* count the leading bits.
+	 */
+	for (l2nb = 0; l2nb < 64; l2nb++, mask >>= 1) {
+		/* leading bit found.
+		 */
+		if (nb & mask) {
+			/* determine the l2 value.
+			 */
+			l2nb = (64 - 1) - l2nb;
+
+			/* check if we need to round up.
+			 */
+			if (~mask & nb)
+				l2nb++;
+
+			return (l2nb);
+		}
+	}
+	assert(0);
+	return 0;		/* fix compiler warning */
+}
+
+
+/*
+ * NAME:	fsDirty()
+ *
+ * FUNCTION:    xxx
+ *
+ * PARAMETERS:
+ *      ipmnt	- mount inode
+ *
+ * RETURN VALUES:
+ *      none
+ */
+void fsDirty()
+{
+	printk("fsDirty(): bye-bye\n");
+	assert(0);
+}
+
+
+/*
+ * NAME:    	dbAllocBottomUp()
+ *
+ * FUNCTION:	alloc the specified block range from the working block
+ *		allocation map.
+ *
+ *		the blocks will be alloc from the working map one dmap
+ *		at a time.
+ *
+ * PARAMETERS:
+ *      ip	-  pointer to in-core inode;
+ *      blkno	-  starting block number to be freed.
+ *      nblocks	-  number of blocks to be freed.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      EIO	- i/o error
+ */
+int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks)
+{
+	struct metapage *mp;
+	struct dmap *dp;
+	int nb, rc;
+	s64 lblkno, rem;
+	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
+	struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
+
+	IREAD_LOCK(ipbmap);
+
+	/* block to be allocated better be within the mapsize. */
+	ASSERT(nblocks <= bmp->db_mapsize - blkno);
+
+	/*
+	 * allocate the blocks a dmap at a time.
+	 */
+	mp = NULL;
+	for (rem = nblocks; rem > 0; rem -= nb, blkno += nb) {
+		/* release previous dmap if any */
+		if (mp) {
+			write_metapage(mp);
+		}
+
+		/* get the buffer for the current dmap. */
+		lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage);
+		mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
+		if (mp == NULL) {
+			IREAD_UNLOCK(ipbmap);
+			return (EIO);
+		}
+		dp = (struct dmap *) mp->data;
+
+		/* determine the number of blocks to be allocated from
+		 * this dmap.
+		 */
+		nb = min(rem, BPERDMAP - (blkno & (BPERDMAP - 1)));
+
+		DBFREECK(bmp->db_DBmap, bmp->db_mapsize, blkno, nb);
+
+		/* allocate the blocks. */
+		if ((rc = dbAllocDmapBU(bmp, dp, blkno, nb))) {
+			release_metapage(mp);
+			IREAD_UNLOCK(ipbmap);
+			return (rc);
+		}
+
+		DBALLOC(bmp->db_DBmap, bmp->db_mapsize, blkno, nb);
+	}
+
+	/* write the last buffer. */
+	write_metapage(mp);
+
+	IREAD_UNLOCK(ipbmap);
+
+	return (0);
+}
+
+
+static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno,
+			 int nblocks)
+{
+	int rc;
+	int dbitno, word, rembits, nb, nwords, wbitno, agno;
+	s8 oldroot, *leaf;
+	struct dmaptree *tp = (struct dmaptree *) & dp->tree;
+
+	/* save the current value of the root (i.e. maximum free string)
+	 * of the dmap tree.
+	 */
+	oldroot = tp->stree[ROOT];
+
+	/* pick up a pointer to the leaves of the dmap tree */
+	leaf = tp->stree + LEAFIND;
+
+	/* determine the bit number and word within the dmap of the
+	 * starting block.
+	 */
+	dbitno = blkno & (BPERDMAP - 1);
+	word = dbitno >> L2DBWORD;
+
+	/* block range better be within the dmap */
+	assert(dbitno + nblocks <= BPERDMAP);
+
+	/* allocate the bits of the dmap's words corresponding to the block
+	 * range. not all bits of the first and last words may be contained
+	 * within the block range.  if this is the case, we'll work against
+	 * those words (i.e. partial first and/or last) on an individual basis
+	 * (a single pass), allocating the bits of interest by hand and
+	 * updating the leaf corresponding to the dmap word. a single pass
+	 * will be used for all dmap words fully contained within the
+	 * specified range.  within this pass, the bits of all fully contained
+	 * dmap words will be marked as free in a single shot and the leaves
+	 * will be updated. a single leaf may describe the free space of
+	 * multiple dmap words, so we may update only a subset of the actual
+	 * leaves corresponding to the dmap words of the block range.
+	 */
+	for (rembits = nblocks; rembits > 0; rembits -= nb, dbitno += nb) {
+		/* determine the bit number within the word and
+		 * the number of bits within the word.
+		 */
+		wbitno = dbitno & (DBWORD - 1);
+		nb = min(rembits, DBWORD - wbitno);
+
+		/* check if only part of a word is to be allocated.
+		 */
+		if (nb < DBWORD) {
+			/* allocate (set to 1) the appropriate bits within
+			 * this dmap word.
+			 */
+			dp->wmap[word] |= cpu_to_le32(ONES << (DBWORD - nb)
+						      >> wbitno);
+
+			word++;
+		} else {
+			/* one or more dmap words are fully contained
+			 * within the block range.  determine how many
+			 * words and allocate (set to 1) the bits of these
+			 * words.
+			 */
+			nwords = rembits >> L2DBWORD;
+			memset(&dp->wmap[word], (int) ONES, nwords * 4);
+
+			/* determine how many bits */
+			nb = nwords << L2DBWORD;
+			word += nwords;
+		}
+	}
+
+	/* update the free count for this dmap */
+	dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) - nblocks);
+
+	/* reconstruct summary tree */
+	dbInitDmapTree(dp);
+
+	BMAP_LOCK(bmp);
+
+	/* if this allocation group is completely free,
+	 * update the highest active allocation group number 
+	 * if this allocation group is the new max.
+	 */
+	agno = blkno >> bmp->db_agl2size;
+	if (agno > bmp->db_maxag)
+		bmp->db_maxag = agno;
+
+	/* update the free count for the allocation group and map */
+	bmp->db_agfree[agno] -= nblocks;
+	bmp->db_nfree -= nblocks;
+
+	BMAP_UNLOCK(bmp);
+
+	/* if the root has not changed, done. */
+	if (tp->stree[ROOT] == oldroot)
+		return (0);
+
+	/* root changed. bubble the change up to the dmap control pages.
+	 * if the adjustment of the upper level control pages fails,
+	 * backout the bit allocation (thus making everything consistent).
+	 */
+	if ((rc = dbAdjCtl(bmp, blkno, tp->stree[ROOT], 1, 0)))
+		dbFreeBits(bmp, dp, blkno, nblocks);
+
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbExtendFS()
+ *
+ * FUNCTION:	extend bmap from blkno for nblocks;
+ * 		dbExtendFS() updates bmap ready for dbAllocBottomUp();
+ *
+ * L2
+ *  |
+ *   L1---------------------------------L1
+ *    |                                  |
+ *     L0---------L0---------L0           L0---------L0---------L0
+ *      |          |          |            |          |          |
+ *       d0,...,dn  d0,...,dn  d0,...,dn    d0,...,dn  d0,...,dn  d0,.,dm;
+ * L2L1L0d0,...,dnL0d0,...,dnL0d0,...,dnL1L0d0,...,dnL0d0,...,dnL0d0,..dm
+ *
+ * <---old---><----------------------------extend----------------------->   
+ */
+int dbExtendFS(struct inode *ipbmap, s64 blkno,	s64 nblocks)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(ipbmap->i_sb);
+	int nbperpage = sbi->nbperpage;
+	int i, i0 = TRUE, j, j0 = TRUE, k, n;
+	s64 newsize;
+	s64 p;
+	struct metapage *mp, *l2mp, *l1mp, *l0mp;
+	struct dmapctl *l2dcp, *l1dcp, *l0dcp;
+	struct dmap *dp;
+	s8 *l0leaf, *l1leaf, *l2leaf;
+	struct bmap *bmp = sbi->bmap;
+	int agno, l2agsize, oldl2agsize;
+	s64 ag_rem;
+
+	newsize = blkno + nblocks;
+
+	jEVENT(0, ("dbExtendFS: blkno:%Ld nblocks:%Ld newsize:%Ld\n",
+		   (long long) blkno, (long long) nblocks,
+		   (long long) newsize));
+
+	/*
+	 *      initialize bmap control page.
+	 *
+	 * all the data in bmap control page should exclude
+	 * the mkfs hidden dmap page.
+	 */
+
+	/* update mapsize */
+	bmp->db_mapsize = newsize;
+	bmp->db_maxlevel = BMAPSZTOLEV(bmp->db_mapsize);
+
+	/* compute new AG size */
+	l2agsize = dbGetL2AGSize(newsize);
+	oldl2agsize = bmp->db_agl2size;
+
+	bmp->db_agl2size = l2agsize;
+	bmp->db_agsize = 1 << l2agsize;
+
+	/* compute new number of AG */
+	agno = bmp->db_numag;
+	bmp->db_numag = newsize >> l2agsize;
+	bmp->db_numag += ((u32) newsize % (u32) bmp->db_agsize) ? 1 : 0;
+
+	/*
+	 *      reconfigure db_agfree[] 
+	 * from old AG configuration to new AG configuration;
+	 *
+	 * coalesce contiguous k (newAGSize/oldAGSize) AGs;
+	 * i.e., (AGi, ..., AGj) where i = k*n and j = k*(n+1) - 1 to AGn;
+	 * note: new AG size = old AG size * (2**x).
+	 */
+	if (l2agsize == oldl2agsize)
+		goto extend;
+	k = 1 << (l2agsize - oldl2agsize);
+	ag_rem = bmp->db_agfree[0];	/* save agfree[0] */
+	for (i = 0, n = 0; i < agno; n++) {
+		bmp->db_agfree[n] = 0;	/* init collection point */
+
+		/* coalesce cotiguous k AGs; */
+		for (j = 0; j < k && i < agno; j++, i++) {
+			/* merge AGi to AGn */
+			bmp->db_agfree[n] += bmp->db_agfree[i];
+		}
+	}
+	bmp->db_agfree[0] += ag_rem;	/* restore agfree[0] */
+
+	for (; n < MAXAG; n++)
+		bmp->db_agfree[n] = 0;
+
+	/*
+	 * update highest active ag number
+	 */
+
+	bmp->db_maxag = bmp->db_maxag / k;
+
+	/*
+	 *      extend bmap
+	 *
+	 * update bit maps and corresponding level control pages;
+	 * global control page db_nfree, db_agfree[agno], db_maxfreebud;
+	 */
+      extend:
+	/* get L2 page */
+	p = BMAPBLKNO + nbperpage;	/* L2 page */
+	l2mp = read_metapage(ipbmap, p, PSIZE, 0);
+	assert(l2mp);
+	l2dcp = (struct dmapctl *) l2mp->data;
+
+	/* compute start L1 */
+	k = blkno >> L2MAXL1SIZE;
+	l2leaf = l2dcp->stree + CTLLEAFIND + k;
+	p = BLKTOL1(blkno, sbi->l2nbperpage);	/* L1 page */
+
+	/*
+	 * extend each L1 in L2
+	 */
+	for (; k < LPERCTL; k++, p += nbperpage) {
+		/* get L1 page */
+		if (j0) {
+			/* read in L1 page: (blkno & (MAXL1SIZE - 1)) */
+			l1mp = read_metapage(ipbmap, p, PSIZE, 0);
+			if (l1mp == NULL)
+				goto errout;
+			l1dcp = (struct dmapctl *) l1mp->data;
+
+			/* compute start L0 */
+			j = (blkno & (MAXL1SIZE - 1)) >> L2MAXL0SIZE;
+			l1leaf = l1dcp->stree + CTLLEAFIND + j;
+			p = BLKTOL0(blkno, sbi->l2nbperpage);
+			j0 = FALSE;
+		} else {
+			/* assign/init L1 page */
+			l1mp = get_metapage(ipbmap, p, PSIZE, 0);
+			if (l1mp == NULL)
+				goto errout;
+
+			l1dcp = (struct dmapctl *) l1mp->data;
+
+			/* compute start L0 */
+			j = 0;
+			l1leaf = l1dcp->stree + CTLLEAFIND;
+			p += nbperpage;	/* 1st L0 of L1.k  */
+		}
+
+		/*
+		 * extend each L0 in L1
+		 */
+		for (; j < LPERCTL; j++) {
+			/* get L0 page */
+			if (i0) {
+				/* read in L0 page: (blkno & (MAXL0SIZE - 1)) */
+
+				l0mp = read_metapage(ipbmap, p, PSIZE, 0);
+				if (l0mp == NULL)
+					goto errout;
+				l0dcp = (struct dmapctl *) l0mp->data;
+
+				/* compute start dmap */
+				i = (blkno & (MAXL0SIZE - 1)) >>
+				    L2BPERDMAP;
+				l0leaf = l0dcp->stree + CTLLEAFIND + i;
+				p = BLKTODMAP(blkno,
+					      sbi->l2nbperpage);
+				i0 = FALSE;
+			} else {
+				/* assign/init L0 page */
+				l0mp = get_metapage(ipbmap, p, PSIZE, 0);
+				if (l0mp == NULL)
+					goto errout;
+
+				l0dcp = (struct dmapctl *) l0mp->data;
+
+				/* compute start dmap */
+				i = 0;
+				l0leaf = l0dcp->stree + CTLLEAFIND;
+				p += nbperpage;	/* 1st dmap of L0.j */
+			}
+
+			/*
+			 * extend each dmap in L0
+			 */
+			for (; i < LPERCTL; i++) {
+				/*
+				 * reconstruct the dmap page, and
+				 * initialize corresponding parent L0 leaf
+				 */
+				if ((n = blkno & (BPERDMAP - 1))) {
+					/* read in dmap page: */
+					mp = read_metapage(ipbmap, p,
+							   PSIZE, 0);
+					if (mp == NULL)
+						goto errout;
+					n = min(nblocks, (s64)BPERDMAP - n);
+				} else {
+					/* assign/init dmap page */
+					mp = read_metapage(ipbmap, p,
+							   PSIZE, 0);
+					if (mp == NULL)
+						goto errout;
+
+					n = min(nblocks, (s64)BPERDMAP);
+				}
+
+				dp = (struct dmap *) mp->data;
+				*l0leaf = dbInitDmap(dp, blkno, n);
+
+				bmp->db_nfree += n;
+				agno = le64_to_cpu(dp->start) >> l2agsize;
+				bmp->db_agfree[agno] += n;
+
+				write_metapage(mp);
+
+				l0leaf++;
+				p += nbperpage;
+
+				blkno += n;
+				nblocks -= n;
+				if (nblocks == 0)
+					break;
+			}	/* for each dmap in a L0 */
+
+			/*
+			 * build current L0 page from its leaves, and 
+			 * initialize corresponding parent L1 leaf
+			 */
+			*l1leaf = dbInitDmapCtl(l0dcp, 0, ++i);
+			write_metapage(l0mp);
+
+			if (nblocks)
+				l1leaf++;	/* continue for next L0 */
+			else {
+				/* more than 1 L0 ? */
+				if (j > 0)
+					break;	/* build L1 page */
+				else {
+					/* summarize in global bmap page */
+					bmp->db_maxfreebud = *l1leaf;
+					release_metapage(l1mp);
+					release_metapage(l2mp);
+					goto finalize;
+				}
+			}
+		}		/* for each L0 in a L1 */
+
+		/*
+		 * build current L1 page from its leaves, and 
+		 * initialize corresponding parent L2 leaf
+		 */
+		*l2leaf = dbInitDmapCtl(l1dcp, 1, ++j);
+		write_metapage(l1mp);
+
+		if (nblocks)
+			l2leaf++;	/* continue for next L1 */
+		else {
+			/* more than 1 L1 ? */
+			if (k > 0)
+				break;	/* build L2 page */
+			else {
+				/* summarize in global bmap page */
+				bmp->db_maxfreebud = *l2leaf;
+				release_metapage(l2mp);
+				goto finalize;
+			}
+		}
+	}			/* for each L1 in a L2 */
+
+	assert(0);
+
+	/*
+	 *      finalize bmap control page
+	 */
+      finalize:
+
+	return 0;
+
+      errout:
+	return EIO;
+}
+
+
+/*
+ *	dbFinalizeBmap()
+ */
+void dbFinalizeBmap(struct inode *ipbmap)
+{
+	struct bmap *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
+	int actags, inactags, l2nl;
+	s64 ag_rem, actfree, inactfree, avgfree;
+	int i, n;
+
+	/*
+	 *      finalize bmap control page
+	 */
+//finalize:
+	/* 
+	 * compute db_agpref: preferred ag to allocate from
+	 * (the leftmost ag with average free space in it);
+	 */
+//agpref:
+	/* get the number of active ags and inacitve ags */
+	actags = bmp->db_maxag + 1;
+	inactags = bmp->db_numag - actags;
+	ag_rem = bmp->db_mapsize & (bmp->db_agsize - 1);	/* ??? */
+
+	/* determine how many blocks are in the inactive allocation
+	 * groups. in doing this, we must account for the fact that
+	 * the rightmost group might be a partial group (i.e. file
+	 * system size is not a multiple of the group size).
+	 */
+	inactfree = (inactags && ag_rem) ?
+	    ((inactags - 1) << bmp->db_agl2size) + ag_rem
+	    : inactags << bmp->db_agl2size;
+
+	/* determine how many free blocks are in the active
+	 * allocation groups plus the average number of free blocks
+	 * within the active ags.
+	 */
+	actfree = bmp->db_nfree - inactfree;
+	avgfree = (u32) actfree / (u32) actags;
+
+	/* if the preferred allocation group has not average free space.
+	 * re-establish the preferred group as the leftmost
+	 * group with average free space.
+	 */
+	if (bmp->db_agfree[bmp->db_agpref] < avgfree) {
+		for (bmp->db_agpref = 0; bmp->db_agpref < actags;
+		     bmp->db_agpref++) {
+			if (bmp->db_agfree[bmp->db_agpref] >= avgfree)
+				break;
+		}
+		assert(bmp->db_agpref < bmp->db_numag);
+	}
+
+	/*
+	 * compute db_aglevel, db_agheigth, db_width, db_agstart:
+	 * an ag is covered in aglevel dmapctl summary tree, 
+	 * at agheight level height (from leaf) with agwidth number of nodes 
+	 * each, which starts at agstart index node of the smmary tree node 
+	 * array;
+	 */
+	bmp->db_aglevel = BMAPSZTOLEV(bmp->db_agsize);
+	l2nl =
+	    bmp->db_agl2size - (L2BPERDMAP + bmp->db_aglevel * L2LPERCTL);
+	bmp->db_agheigth = l2nl >> 1;
+	bmp->db_agwidth = 1 << (l2nl - (bmp->db_agheigth << 1));
+	for (i = 5 - bmp->db_agheigth, bmp->db_agstart = 0, n = 1; i > 0;
+	     i--) {
+		bmp->db_agstart += n;
+		n <<= 2;
+	}
+
+/*
+printk("bmap: agpref:%d aglevel:%d agheigth:%d agwidth:%d\n",
+	bmp->db_agpref, bmp->db_aglevel, bmp->db_agheigth, bmp->db_agwidth);
+*/
+}
+
+
+/*
+ * NAME:	dbInitDmap()/ujfs_idmap_page()
+ *                                                                    
+ * FUNCTION:	initialize working/persistent bitmap of the dmap page
+ *		for the specified number of blocks:
+ *                                                                    
+ *		at entry, the bitmaps had been initialized as free (ZEROS);
+ *		The number of blocks will only account for the actually 
+ *		existing blocks. Blocks which don't actually exist in 
+ *		the aggregate will be marked as allocated (ONES);
+ *
+ * PARAMETERS:
+ *	dp	- pointer to page of map
+ *	nblocks	- number of blocks this page
+ *
+ * RETURNS: NONE
+ */
+static int dbInitDmap(struct dmap * dp, s64 Blkno, int nblocks)
+{
+	int blkno, w, b, r, nw, nb, i;
+/*
+printk("sbh_dmap:  in dbInitDmap blkno:%Ld nblocks:%ld\n", Blkno, nblocks); 
+*/
+
+	/* starting block number within the dmap */
+	blkno = Blkno & (BPERDMAP - 1);
+
+	if (blkno == 0) {
+		dp->nblocks = dp->nfree = cpu_to_le32(nblocks);
+		dp->start = cpu_to_le64(Blkno);
+
+		if (nblocks == BPERDMAP) {
+			memset(&dp->wmap[0], 0, LPERDMAP * 4);
+			memset(&dp->pmap[0], 0, LPERDMAP * 4);
+			goto initTree;
+		}
+	} else {
+		dp->nblocks =
+		    cpu_to_le32(le32_to_cpu(dp->nblocks) + nblocks);
+		dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) + nblocks);
+	}
+
+	/* word number containing start block number */
+	w = blkno >> L2DBWORD;
+
+	/*
+	 * free the bits corresponding to the block range (ZEROS):
+	 * note: not all bits of the first and last words may be contained 
+	 * within the block range.
+	 */
+	for (r = nblocks; r > 0; r -= nb, blkno += nb) {
+		/* number of bits preceding range to be freed in the word */
+		b = blkno & (DBWORD - 1);
+		/* number of bits to free in the word */
+		nb = min(r, DBWORD - b);
+
+		/* is partial word to be freed ? */
+		if (nb < DBWORD) {
+			/* free (set to 0) from the bitmap word */
+			dp->wmap[w] &= cpu_to_le32(~(ONES << (DBWORD - nb)
+						     >> b));
+			dp->pmap[w] &= cpu_to_le32(~(ONES << (DBWORD - nb)
+						     >> b));
+
+			/* skip the word freed */
+			w++;
+		} else {
+			/* free (set to 0) contiguous bitmap words */
+			nw = r >> L2DBWORD;
+			memset(&dp->wmap[w], 0, nw * 4);
+			memset(&dp->pmap[w], 0, nw * 4);
+
+			/* skip the words freed */
+			nb = nw << L2DBWORD;
+			w += nw;
+		}
+	}
+
+	/*
+	 * mark bits following the range to be freed (non-existing 
+	 * blocks) as allocated (ONES)
+	 */
+/*
+printk("sbh_dmap:  in dbInitDmap, preparing to mark unbacked, blkno:%ld nblocks:%ld\n",
+		blkno, nblocks); 
+*/
+
+	if (blkno == BPERDMAP)
+		goto initTree;
+
+	/* the first word beyond the end of existing blocks */
+	w = blkno >> L2DBWORD;
+
+	/* does nblocks fall on a 32-bit boundary ? */
+	b = blkno & (DBWORD - 1);
+/*
+printk("sbh_dmap:  in dbInitDmap, b:%ld w:%ld mask: %lx\n", b, w, (ONES>>b)); 
+*/
+	if (b) {
+		/* mark a partial word allocated */
+		dp->wmap[w] = dp->pmap[w] = cpu_to_le32(ONES >> b);
+		w++;
+	}
+
+	/* set the rest of the words in the page to allocated (ONES) */
+	for (i = w; i < LPERDMAP; i++)
+		dp->pmap[i] = dp->wmap[i] = ONES;
+
+	/*
+	 * init tree
+	 */
+      initTree:
+	return (dbInitDmapTree(dp));
+}
+
+
+/*
+ * NAME:	dbInitDmapTree()/ujfs_complete_dmap()
+ *                                                                    
+ * FUNCTION:	initialize summary tree of the specified dmap:
+ *
+ *		at entry, bitmap of the dmap has been initialized;
+ *                                                                    
+ * PARAMETERS:
+ *	dp	- dmap to complete
+ *	blkno	- starting block number for this dmap
+ *	treemax	- will be filled in with max free for this dmap
+ *
+ * RETURNS:	max free string at the root of the tree
+ */
+static int dbInitDmapTree(struct dmap * dp)
+{
+	struct dmaptree *tp;
+	s8 *cp;
+	int i;
+
+	/* init fixed info of tree */
+	tp = &dp->tree;
+	tp->nleafs = cpu_to_le32(LPERDMAP);
+	tp->l2nleafs = cpu_to_le32(L2LPERDMAP);
+	tp->leafidx = cpu_to_le32(LEAFIND);
+	tp->height = cpu_to_le32(4);
+	tp->budmin = BUDMIN;
+
+	/* init each leaf from corresponding wmap word:
+	 * note: leaf is set to NOFREE(-1) if all blocks of corresponding
+	 * bitmap word are allocated. 
+	 */
+	cp = tp->stree + le32_to_cpu(tp->leafidx);
+	for (i = 0; i < LPERDMAP; i++)
+		*cp++ = dbMaxBud((u8 *) & dp->wmap[i]);
+
+	/* build the dmap's binary buddy summary tree */
+	return (dbInitTree(tp));
+}
+
+
+/*
+ * NAME:	dbInitTree()/ujfs_adjtree()
+ *                                                                    
+ * FUNCTION:	initialize binary buddy summary tree of a dmap or dmapctl.
+ *
+ *		at entry, the leaves of the tree has been initialized 
+ *		from corresponding bitmap word or root of summary tree
+ *		of the child control page;
+ *		configure binary buddy system at the leaf level, then
+ *		bubble up the values of the leaf nodes up the tree.
+ *
+ * PARAMETERS:
+ *	cp	- Pointer to the root of the tree
+ *	l2leaves- Number of leaf nodes as a power of 2
+ *	l2min	- Number of blocks that can be covered by a leaf
+ *		  as a power of 2
+ *
+ * RETURNS: max free string at the root of the tree
+ */
+static int dbInitTree(struct dmaptree * dtp)
+{
+	int l2max, l2free, bsize, nextb, i;
+	int child, parent, nparent;
+	s8 *tp, *cp, *cp1;
+
+	tp = dtp->stree;
+
+	/* Determine the maximum free string possible for the leaves */
+	l2max = le32_to_cpu(dtp->l2nleafs) + dtp->budmin;
+
+	/*
+	 * configure the leaf levevl into binary buddy system
+	 *
+	 * Try to combine buddies starting with a buddy size of 1 
+	 * (i.e. two leaves). At a buddy size of 1 two buddy leaves 
+	 * can be combined if both buddies have a maximum free of l2min; 
+	 * the combination will result in the left-most buddy leaf having 
+	 * a maximum free of l2min+1.  
+	 * After processing all buddies for a given size, process buddies 
+	 * at the next higher buddy size (i.e. current size * 2) and 
+	 * the next maximum free (current free + 1).  
+	 * This continues until the maximum possible buddy combination 
+	 * yields maximum free.
+	 */
+	for (l2free = dtp->budmin, bsize = 1; l2free < l2max;
+	     l2free++, bsize = nextb) {
+		/* get next buddy size == current buddy pair size */
+		nextb = bsize << 1;
+
+		/* scan each adjacent buddy pair at current buddy size */
+		for (i = 0, cp = tp + le32_to_cpu(dtp->leafidx);
+		     i < le32_to_cpu(dtp->nleafs);
+		     i += nextb, cp += nextb) {
+			/* coalesce if both adjacent buddies are max free */
+			if (*cp == l2free && *(cp + bsize) == l2free) {
+				*cp = l2free + 1;	/* left take right */
+				*(cp + bsize) = -1;	/* right give left */
+			}
+		}
+	}
+
+	/*
+	 * bubble summary information of leaves up the tree.
+	 *
+	 * Starting at the leaf node level, the four nodes described by
+	 * the higher level parent node are compared for a maximum free and 
+	 * this maximum becomes the value of the parent node.  
+	 * when all lower level nodes are processed in this fashion then 
+	 * move up to the next level (parent becomes a lower level node) and 
+	 * continue the process for that level.
+	 */
+	for (child = le32_to_cpu(dtp->leafidx),
+	     nparent = le32_to_cpu(dtp->nleafs) >> 2;
+	     nparent > 0; nparent >>= 2, child = parent) {
+		/* get index of 1st node of parent level */
+		parent = (child - 1) >> 2;
+
+		/* set the value of the parent node as the maximum 
+		 * of the four nodes of the current level.
+		 */
+		for (i = 0, cp = tp + child, cp1 = tp + parent;
+		     i < nparent; i++, cp += 4, cp1++)
+			*cp1 = TREEMAX(cp);
+	}
+
+	return (*tp);
+}
+
+
+/*
+ *	dbInitDmapCtl()
+ *
+ * function: initialize dmapctl page
+ */
+static int dbInitDmapCtl(struct dmapctl * dcp, int level, int i)
+{				/* start leaf index not covered by range */
+	s8 *cp;
+
+	dcp->nleafs = cpu_to_le32(LPERCTL);
+	dcp->l2nleafs = cpu_to_le32(L2LPERCTL);
+	dcp->leafidx = cpu_to_le32(CTLLEAFIND);
+	dcp->height = cpu_to_le32(5);
+	dcp->budmin = L2BPERDMAP + L2LPERCTL * level;
+
+	/*
+	 * initialize the leaves of current level that were not covered 
+	 * by the specified input block range (i.e. the leaves have no 
+	 * low level dmapctl or dmap).
+	 */
+	cp = &dcp->stree[CTLLEAFIND + i];
+	for (; i < LPERCTL; i++)
+		*cp++ = NOFREE;
+
+	/* build the dmap's binary buddy summary tree */
+	return (dbInitTree((struct dmaptree *) dcp));
+}
+
+
+/*
+ * NAME:	dbGetL2AGSize()/ujfs_getagl2size()
+ *                                                                    
+ * FUNCTION:	Determine log2(allocation group size) from aggregate size
+ *                                                                    
+ * PARAMETERS:
+ *	nblocks	- Number of blocks in aggregate
+ *
+ * RETURNS: log2(allocation group size) in aggregate blocks
+ */
+static int dbGetL2AGSize(s64 nblocks)
+{
+	s64 sz;
+	s64 m;
+	int l2sz;
+
+	if (nblocks < BPERDMAP * MAXAG)
+		return (L2BPERDMAP);
+
+	/* round up aggregate size to power of 2 */
+	m = ((u64) 1 << (64 - 1));
+	for (l2sz = 64; l2sz >= 0; l2sz--, m >>= 1) {
+		if (m & nblocks)
+			break;
+	}
+
+	sz = (s64) 1 << l2sz;
+	if (sz < nblocks)
+		l2sz += 1;
+
+	/* agsize = roundupSize/max_number_of_ag */
+	return (l2sz - L2MAXAG);
+}
+
+
+/*
+ * NAME:	dbMapFileSizeToMapSize()
+ *                                                                    
+ * FUNCTION:	compute number of blocks the block allocation map file 
+ *		can cover from the map file size;
+ *
+ * RETURNS:	Number of blocks which can be covered by this block map file;
+ */
+
+/*
+ * maximum number of map pages at each level including control pages
+ */
+#define MAXL0PAGES	(1 + LPERCTL)
+#define MAXL1PAGES	(1 + LPERCTL * MAXL0PAGES)
+#define MAXL2PAGES	(1 + LPERCTL * MAXL1PAGES)
+
+/*
+ * convert number of map pages to the zero origin top dmapctl level
+ */
+#define BMAPPGTOLEV(npages)	\
+	(((npages) <= 3 + MAXL0PAGES) ? 0 \
+       : ((npages) <= 2 + MAXL1PAGES) ? 1 : 2)
+
+s64 dbMapFileSizeToMapSize(struct inode * ipbmap)
+{
+	struct super_block *sb = ipbmap->i_sb;
+	s64 nblocks;
+	s64 npages, ndmaps;
+	int level, i;
+	int complete, factor;
+
+	nblocks = ipbmap->i_size >> JFS_SBI(sb)->l2bsize;
+	npages = nblocks >> JFS_SBI(sb)->l2nbperpage;
+	level = BMAPPGTOLEV(npages);
+
+	/* At each level, accumulate the number of dmap pages covered by 
+	 * the number of full child levels below it;
+	 * repeat for the last incomplete child level.
+	 */
+	ndmaps = 0;
+	npages--;		/* skip the first global control page */
+	/* skip higher level control pages above top level covered by map */
+	npages -= (2 - level);
+	npages--;		/* skip top level's control page */
+	for (i = level; i >= 0; i--) {
+		factor =
+		    (i == 2) ? MAXL1PAGES : ((i == 1) ? MAXL0PAGES : 1);
+		complete = (u32) npages / factor;
+		ndmaps += complete * ((i == 2) ? LPERCTL * LPERCTL
+				      : ((i == 1) ? LPERCTL : 1));
+
+		/* pages in last/incomplete child */
+		npages = (u32) npages % factor;
+		/* skip incomplete child's level control page */
+		npages--;
+	}
+
+	/* convert the number of dmaps into the number of blocks 
+	 * which can be covered by the dmaps;
+	 */
+	nblocks = ndmaps << L2BPERDMAP;
+
+	return (nblocks);
+}
+
+
+#ifdef	_JFS_DEBUG_DMAP
+/*
+ *	DBinitmap()
+ */
+static void DBinitmap(s64 size, struct inode *ipbmap, u32 ** results)
+{
+	int npages;
+	u32 *dbmap, *d;
+	int n;
+	s64 lblkno, cur_block;
+	struct dmap *dp;
+	struct metapage *mp;
+
+	npages = size / 32768;
+	npages += (size % 32768) ? 1 : 0;
+
+	dbmap = (u32 *) xmalloc(npages * 4096, L2PSIZE, kernel_heap);
+	if (dbmap == NULL)
+		assert(0);
+
+	for (n = 0, d = dbmap; n < npages; n++, d += 1024)
+		bzero(d, 4096);
+
+	/* Need to initialize from disk map pages
+	 */
+	for (d = dbmap, cur_block = 0; cur_block < size;
+	     cur_block += BPERDMAP, d += LPERDMAP) {
+		lblkno = BLKTODMAP(cur_block,
+				   JFS_SBI(ipbmap->i_sb)->bmap->
+				   db_l2nbperpage);
+		mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
+		if (mp == NULL) {
+			assert(0);
+		}
+		dp = (struct dmap *) mp->data;
+
+		for (n = 0; n < LPERDMAP; n++)
+			d[n] = le32_to_cpu(dp->wmap[n]);
+
+		release_metapage(mp);
+	}
+
+	*results = dbmap;
+}
+
+
+/*
+ *	DBAlloc()
+ */
+void DBAlloc(uint * dbmap, s64 mapsize, s64 blkno, s64 nblocks)
+{
+	int word, nb, bitno;
+	u32 mask;
+
+	assert(blkno > 0 && blkno < mapsize);
+	assert(nblocks > 0 && nblocks <= mapsize);
+
+	assert(blkno + nblocks <= mapsize);
+
+	dbmap += (blkno / 32);
+	while (nblocks > 0) {
+		bitno = blkno & (32 - 1);
+		nb = min(nblocks, 32 - bitno);
+
+		mask = (0xffffffff << (32 - nb) >> bitno);
+		assert((mask & *dbmap) == 0);
+		*dbmap |= mask;
+
+		dbmap++;
+		blkno += nb;
+		nblocks -= nb;
+	}
+}
+
+
+/*
+ *	DBFree()
+ */
+static void DBFree(uint * dbmap, s64 mapsize, s64 blkno, s64 nblocks)
+{
+	int word, nb, bitno;
+	u32 mask;
+
+	assert(blkno > 0 && blkno < mapsize);
+	assert(nblocks > 0 && nblocks <= mapsize);
+
+	assert(blkno + nblocks <= mapsize);
+
+	dbmap += (blkno / 32);
+	while (nblocks > 0) {
+		bitno = blkno & (32 - 1);
+		nb = min(nblocks, 32 - bitno);
+
+		mask = (0xffffffff << (32 - nb) >> bitno);
+		assert((mask & *dbmap) == mask);
+		*dbmap &= ~mask;
+
+		dbmap++;
+		blkno += nb;
+		nblocks -= nb;
+	}
+}
+
+
+/*
+ *	DBAllocCK()
+ */
+static void DBAllocCK(uint * dbmap, s64 mapsize, s64 blkno, s64 nblocks)
+{
+	int word, nb, bitno;
+	u32 mask;
+
+	assert(blkno > 0 && blkno < mapsize);
+	assert(nblocks > 0 && nblocks <= mapsize);
+
+	assert(blkno + nblocks <= mapsize);
+
+	dbmap += (blkno / 32);
+	while (nblocks > 0) {
+		bitno = blkno & (32 - 1);
+		nb = min(nblocks, 32 - bitno);
+
+		mask = (0xffffffff << (32 - nb) >> bitno);
+		assert((mask & *dbmap) == mask);
+
+		dbmap++;
+		blkno += nb;
+		nblocks -= nb;
+	}
+}
+
+
+/*
+ *	DBFreeCK()
+ */
+static void DBFreeCK(uint * dbmap, s64 mapsize, s64 blkno, s64 nblocks)
+{
+	int word, nb, bitno;
+	u32 mask;
+
+	assert(blkno > 0 && blkno < mapsize);
+	assert(nblocks > 0 && nblocks <= mapsize);
+
+	assert(blkno + nblocks <= mapsize);
+
+	dbmap += (blkno / 32);
+	while (nblocks > 0) {
+		bitno = blkno & (32 - 1);
+		nb = min(nblocks, 32 - bitno);
+
+		mask = (0xffffffff << (32 - nb) >> bitno);
+		assert((mask & *dbmap) == 0);
+
+		dbmap++;
+		blkno += nb;
+		nblocks -= nb;
+	}
+}
+
+
+/*
+ *	dbPrtMap()
+ */
+static void dbPrtMap(struct bmap * bmp)
+{
+	printk("   mapsize:   %d%d\n", bmp->db_mapsize);
+	printk("   nfree:     %d%d\n", bmp->db_nfree);
+	printk("   numag:     %d\n", bmp->db_numag);
+	printk("   agsize:    %d%d\n", bmp->db_agsize);
+	printk("   agl2size:  %d\n", bmp->db_agl2size);
+	printk("   agwidth:   %d\n", bmp->db_agwidth);
+	printk("   agstart:   %d\n", bmp->db_agstart);
+	printk("   agheigth:  %d\n", bmp->db_agheigth);
+	printk("   aglevel:   %d\n", bmp->db_aglevel);
+	printk("   maxlevel:  %d\n", bmp->db_maxlevel);
+	printk("   maxag:     %d\n", bmp->db_maxag);
+	printk("   agpref:    %d\n", bmp->db_agpref);
+	printk("   l2nbppg:   %d\n", bmp->db_l2nbperpage);
+}
+
+
+/*
+ *	dbPrtCtl()
+ */
+static void dbPrtCtl(struct dmapctl * dcp)
+{
+	int i, j, n;
+
+	printk("   height:    %08x\n", le32_to_cpu(dcp->height));
+	printk("   leafidx:   %08x\n", le32_to_cpu(dcp->leafidx));
+	printk("   budmin:    %08x\n", dcp->budmin);
+	printk("   nleafs:    %08x\n", le32_to_cpu(dcp->nleafs));
+	printk("   l2nleafs:  %08x\n", le32_to_cpu(dcp->l2nleafs));
+
+	printk("\n Tree:\n");
+	for (i = 0; i < CTLLEAFIND; i += 8) {
+		n = min(8, CTLLEAFIND - i);
+
+		for (j = 0; j < n; j++)
+			printf("  [%03x]: %02x", i + j,
+			       (char) dcp->stree[i + j]);
+		printf("\n");
+	}
+
+	printk("\n Tree Leaves:\n");
+	for (i = 0; i < LPERCTL; i += 8) {
+		n = min(8, LPERCTL - i);
+
+		for (j = 0; j < n; j++)
+			printf("  [%03x]: %02x",
+			       i + j,
+			       (char) dcp->stree[i + j + CTLLEAFIND]);
+		printf("\n");
+	}
+}
+#endif				/* _JFS_DEBUG_DMAP */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_dmap.h linux-2.4.20/fs/jfs/jfs_dmap.h
--- linux-2.4.19/fs/jfs/jfs_dmap.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_dmap.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,299 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+#ifndef	_H_JFS_DMAP
+#define _H_JFS_DMAP
+
+#include "jfs_txnmgr.h"
+
+#define BMAPVERSION	1	/* version number */
+#define	TREESIZE	(256+64+16+4+1)	/* size of a dmap tree */
+#define	LEAFIND		(64+16+4+1)	/* index of 1st leaf of a dmap tree */
+#define LPERDMAP	256	/* num leaves per dmap tree */
+#define L2LPERDMAP	8	/* l2 number of leaves per dmap tree */
+#define	DBWORD		32	/* # of blks covered by a map word */
+#define	L2DBWORD	5	/* l2 # of blks covered by a mword */
+#define BUDMIN  	L2DBWORD	/* max free string in a map word */
+#define BPERDMAP	(LPERDMAP * DBWORD)	/* num of blks per dmap */
+#define L2BPERDMAP	13	/* l2 num of blks per dmap */
+#define CTLTREESIZE	(1024+256+64+16+4+1)	/* size of a dmapctl tree */
+#define CTLLEAFIND	(256+64+16+4+1)	/* idx of 1st leaf of a dmapctl tree */
+#define LPERCTL		1024	/* num of leaves per dmapctl tree */
+#define L2LPERCTL	10	/* l2 num of leaves per dmapctl tree */
+#define	ROOT		0	/* index of the root of a tree */
+#define	NOFREE		((s8) -1)	/* no blocks free */
+#define	MAXAG		128	/* max number of allocation groups */
+#define L2MAXAG		7	/* l2 max num of AG */
+#define L2MINAGSZ	25	/* l2 of minimum AG size in bytes */
+#define	BMAPBLKNO	0	/* lblkno of bmap within the map */
+
+/*
+ * maximum l2 number of disk blocks at the various dmapctl levels.
+ */
+#define	L2MAXL0SIZE	(L2BPERDMAP + 1 * L2LPERCTL)
+#define	L2MAXL1SIZE	(L2BPERDMAP + 2 * L2LPERCTL)
+#define	L2MAXL2SIZE	(L2BPERDMAP + 3 * L2LPERCTL)
+
+/*
+ * maximum number of disk blocks at the various dmapctl levels.
+ */
+#define	MAXL0SIZE	((s64)1 << L2MAXL0SIZE)
+#define	MAXL1SIZE	((s64)1 << L2MAXL1SIZE)
+#define	MAXL2SIZE	((s64)1 << L2MAXL2SIZE)
+
+#define	MAXMAPSIZE	MAXL2SIZE	/* maximum aggregate map size */
+
+/* 
+ * determine the maximum free string for four (lower level) nodes
+ * of the tree.
+ */
+static __inline signed char TREEMAX(signed char *cp)
+{
+	signed char tmp1, tmp2;
+
+	tmp1 = max(*(cp+2), *(cp+3));
+	tmp2 = max(*(cp), *(cp+1));
+
+	return max(tmp1, tmp2);
+}
+
+/*
+ * convert disk block number to the logical block number of the dmap
+ * describing the disk block.  s is the log2(number of logical blocks per page)
+ *
+ * The calculation figures out how many logical pages are in front of the dmap.
+ *	- the number of dmaps preceding it
+ *	- the number of L0 pages preceding its L0 page
+ *	- the number of L1 pages preceding its L1 page
+ *	- 3 is added to account for the L2, L1, and L0 page for this dmap
+ *	- 1 is added to account for the control page of the map.
+ */
+#define BLKTODMAP(b,s)    \
+        ((((b) >> 13) + ((b) >> 23) + ((b) >> 33) + 3 + 1) << (s))
+
+/*
+ * convert disk block number to the logical block number of the LEVEL 0
+ * dmapctl describing the disk block.  s is the log2(number of logical blocks
+ * per page)
+ *
+ * The calculation figures out how many logical pages are in front of the L0.
+ *	- the number of dmap pages preceding it
+ *	- the number of L0 pages preceding it
+ *	- the number of L1 pages preceding its L1 page
+ *	- 2 is added to account for the L2, and L1 page for this L0
+ *	- 1 is added to account for the control page of the map.
+ */
+#define BLKTOL0(b,s)      \
+        (((((b) >> 23) << 10) + ((b) >> 23) + ((b) >> 33) + 2 + 1) << (s))
+
+/*
+ * convert disk block number to the logical block number of the LEVEL 1
+ * dmapctl describing the disk block.  s is the log2(number of logical blocks
+ * per page)
+ *
+ * The calculation figures out how many logical pages are in front of the L1.
+ *	- the number of dmap pages preceding it
+ *	- the number of L0 pages preceding it
+ *	- the number of L1 pages preceding it
+ *	- 1 is added to account for the L2 page
+ *	- 1 is added to account for the control page of the map.
+ */
+#define BLKTOL1(b,s)      \
+     (((((b) >> 33) << 20) + (((b) >> 33) << 10) + ((b) >> 33) + 1 + 1) << (s))
+
+/*
+ * convert disk block number to the logical block number of the dmapctl
+ * at the specified level which describes the disk block.
+ */
+#define BLKTOCTL(b,s,l)   \
+        (((l) == 2) ? 1 : ((l) == 1) ? BLKTOL1((b),(s)) : BLKTOL0((b),(s)))
+
+/* 
+ * convert aggregate map size to the zero origin dmapctl level of the
+ * top dmapctl.
+ */
+#define	BMAPSZTOLEV(size)	\
+	(((size) <= MAXL0SIZE) ? 0 : ((size) <= MAXL1SIZE) ? 1 : 2)
+
+/* convert disk block number to allocation group number.
+ */
+#define BLKTOAG(b,sbi)	((b) >> ((sbi)->bmap->db_agl2size))
+
+/* convert allocation group number to starting disk block
+ * number.
+ */
+#define AGTOBLK(a,ip)	\
+	((s64)(a) << (JFS_SBI((ip)->i_sb)->bmap->db_agl2size))
+
+/*
+ *	dmap summary tree
+ *
+ * dmaptree must be consistent with dmapctl.
+ */
+struct dmaptree {
+	s32 nleafs;		/* 4: number of tree leafs      */
+	s32 l2nleafs;		/* 4: l2 number of tree leafs   */
+	s32 leafidx;		/* 4: index of first tree leaf  */
+	s32 height;		/* 4: height of the tree        */
+	s8 budmin;		/* 1: min l2 tree leaf value to combine */
+	s8 stree[TREESIZE];	/* TREESIZE: tree               */
+	u8 pad[2];		/* 2: pad to word boundary      */
+};				/* - 360 -                      */
+
+/*
+ *	dmap page per 8K blocks bitmap
+ */
+struct dmap {
+	s32 nblocks;		/* 4: num blks covered by this dmap     */
+	s32 nfree;		/* 4: num of free blks in this dmap     */
+	s64 start;		/* 8: starting blkno for this dmap      */
+	struct dmaptree tree;	/* 360: dmap tree                       */
+	u8 pad[1672];		/* 1672: pad to 2048 bytes              */
+	u32 wmap[LPERDMAP];	/* 1024: bits of the working map        */
+	u32 pmap[LPERDMAP];	/* 1024: bits of the persistent map     */
+};				/* - 4096 -                             */
+
+/*
+ *	disk map control page per level.
+ *
+ * dmapctl must be consistent with dmaptree.
+ */
+struct dmapctl {
+	s32 nleafs;		/* 4: number of tree leafs      */
+	s32 l2nleafs;		/* 4: l2 number of tree leafs   */
+	s32 leafidx;		/* 4: index of the first tree leaf      */
+	s32 height;		/* 4: height of tree            */
+	s8 budmin;		/* 1: minimum l2 tree leaf value        */
+	s8 stree[CTLTREESIZE];	/* CTLTREESIZE: dmapctl tree    */
+	u8 pad[2714];		/* 2714: pad to 4096            */
+};				/* - 4096 -                     */
+
+/*
+ *	common definition for dmaptree within dmap and dmapctl
+ */
+typedef union dmtree {
+	struct dmaptree t1;
+	struct dmapctl t2;
+} dmtree_t;
+
+/* macros for accessing fields within dmtree */
+#define	dmt_nleafs	t1.nleafs
+#define	dmt_l2nleafs 	t1.l2nleafs
+#define	dmt_leafidx 	t1.leafidx
+#define	dmt_height 	t1.height
+#define	dmt_budmin 	t1.budmin
+#define	dmt_stree 	t1.stree
+
+/* 
+ *	on-disk aggregate disk allocation map descriptor.
+ */
+struct dbmap {
+	s64 dn_mapsize;		/* 8: number of blocks in aggregate     */
+	s64 dn_nfree;		/* 8: num free blks in aggregate map    */
+	s32 dn_l2nbperpage;	/* 4: number of blks per page           */
+	s32 dn_numag;		/* 4: total number of ags               */
+	s32 dn_maxlevel;	/* 4: number of active ags              */
+	s32 dn_maxag;		/* 4: max active alloc group number     */
+	s32 dn_agpref;		/* 4: preferred alloc group (hint)      */
+	s32 dn_aglevel;		/* 4: dmapctl level holding the AG      */
+	s32 dn_agheigth;	/* 4: height in dmapctl of the AG       */
+	s32 dn_agwidth;		/* 4: width in dmapctl of the AG        */
+	s32 dn_agstart;		/* 4: start tree index at AG height     */
+	s32 dn_agl2size;	/* 4: l2 num of blks per alloc group    */
+	s64 dn_agfree[MAXAG];	/* 8*MAXAG: per AG free count           */
+	s64 dn_agsize;		/* 8: num of blks per alloc group       */
+	s8 dn_maxfreebud;	/* 1: max free buddy system             */
+	u8 pad[3007];		/* 3007: pad to 4096                    */
+};				/* - 4096 -                             */
+
+/* 
+ *	in-memory aggregate disk allocation map descriptor.
+ */
+struct bmap {
+	struct dbmap db_bmap;	/* on-disk aggregate map descriptor */
+	struct inode *db_ipbmap;	/* ptr to aggregate map incore inode */
+	struct semaphore db_bmaplock;	/* aggregate map lock */
+	atomic_t db_active[MAXAG];	/* count of active, open files in AG */
+	u32 *db_DBmap;
+};
+
+/* macros for accessing fields within in-memory aggregate map descriptor */
+#define	db_mapsize	db_bmap.dn_mapsize
+#define	db_nfree	db_bmap.dn_nfree
+#define	db_agfree	db_bmap.dn_agfree
+#define	db_agsize	db_bmap.dn_agsize
+#define	db_agl2size	db_bmap.dn_agl2size
+#define	db_agwidth	db_bmap.dn_agwidth
+#define	db_agheigth	db_bmap.dn_agheigth
+#define	db_agstart	db_bmap.dn_agstart
+#define	db_numag	db_bmap.dn_numag
+#define	db_maxlevel	db_bmap.dn_maxlevel
+#define	db_aglevel	db_bmap.dn_aglevel
+#define	db_agpref	db_bmap.dn_agpref
+#define	db_maxag	db_bmap.dn_maxag
+#define	db_maxfreebud	db_bmap.dn_maxfreebud
+#define	db_l2nbperpage	db_bmap.dn_l2nbperpage
+
+/*
+ * macros for various conversions needed by the allocators.
+ * blkstol2(), cntlz(), and cnttz() are operating system dependent functions.
+ */
+/* convert number of blocks to log2 number of blocks, rounding up to
+ * the next log2 value if blocks is not a l2 multiple.
+ */
+#define	BLKSTOL2(d)		(blkstol2(d))
+
+/* convert number of leafs to log2 leaf value */
+#define	NLSTOL2BSZ(n)		(31 - cntlz((n)) + BUDMIN)
+
+/* convert leaf index to log2 leaf value */
+#define	LITOL2BSZ(n,m,b)	((((n) == 0) ? (m) : cnttz((n))) + (b))
+
+/* convert a block number to a dmap control leaf index */
+#define BLKTOCTLLEAF(b,m)	\
+	(((b) & (((s64)1 << ((m) + L2LPERCTL)) - 1)) >> (m))
+
+/* convert log2 leaf value to buddy size */
+#define	BUDSIZE(s,m)		(1 << ((s) - (m)))
+
+/*
+ *	external references.
+ */
+extern int dbMount(struct inode *ipbmap);
+
+extern int dbUnmount(struct inode *ipbmap, int mounterror);
+
+extern int dbFree(struct inode *ipbmap, s64 blkno, s64 nblocks);
+
+extern int dbUpdatePMap(struct inode *ipbmap,
+			int free, s64 blkno, s64 nblocks, struct tblock * tblk);
+
+extern int dbNextAG(struct inode *ipbmap);
+
+extern int dbAlloc(struct inode *ipbmap, s64 hint, s64 nblocks, s64 * results);
+
+extern int dbAllocExact(struct inode *ip, s64 blkno, int nblocks);
+
+extern int dbReAlloc(struct inode *ipbmap,
+		     s64 blkno, s64 nblocks, s64 addnblocks, s64 * results);
+
+extern int dbSync(struct inode *ipbmap);
+extern int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks);
+extern int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks);
+extern void dbFinalizeBmap(struct inode *ipbmap);
+extern s64 dbMapFileSizeToMapSize(struct inode *ipbmap);
+#endif				/* _H_JFS_DMAP */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_dtree.c linux-2.4.20/fs/jfs/jfs_dtree.c
--- linux-2.4.19/fs/jfs/jfs_dtree.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_dtree.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,4663 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+
+/*
+ *	jfs_dtree.c: directory B+-tree manager
+ *
+ * B+-tree with variable length key directory:
+ *
+ * each directory page is structured as an array of 32-byte
+ * directory entry slots initialized as a freelist
+ * to avoid search/compaction of free space at insertion.
+ * when an entry is inserted, a number of slots are allocated
+ * from the freelist as required to store variable length data
+ * of the entry; when the entry is deleted, slots of the entry
+ * are returned to freelist.
+ *
+ * leaf entry stores full name as key and file serial number
+ * (aka inode number) as data.
+ * internal/router entry stores sufffix compressed name
+ * as key and simple extent descriptor as data.
+ *
+ * each directory page maintains a sorted entry index table
+ * which stores the start slot index of sorted entries
+ * to allow binary search on the table.
+ *
+ * directory starts as a root/leaf page in on-disk inode
+ * inline data area.
+ * when it becomes full, it starts a leaf of a external extent
+ * of length of 1 block. each time the first leaf becomes full,
+ * it is extended rather than split (its size is doubled),
+ * until its length becoms 4 KBytes, from then the extent is split
+ * with new 4 Kbyte extent when it becomes full
+ * to reduce external fragmentation of small directories.
+ *
+ * blah, blah, blah, for linear scan of directory in pieces by
+ * readdir().
+ *
+ *
+ *	case-insensitive directory file system
+ *
+ * names are stored in case-sensitive way in leaf entry.
+ * but stored, searched and compared in case-insensitive (uppercase) order
+ * (i.e., both search key and entry key are folded for search/compare):
+ * (note that case-sensitive order is BROKEN in storage, e.g.,
+ *  sensitive: Ad, aB, aC, aD -> insensitive: aB, aC, aD, Ad
+ *
+ *  entries which folds to the same key makes up a equivalent class
+ *  whose members are stored as contiguous cluster (may cross page boundary)
+ *  but whose order is arbitrary and acts as duplicate, e.g.,
+ *  abc, Abc, aBc, abC)
+ *
+ * once match is found at leaf, requires scan forward/backward
+ * either for, in case-insensitive search, duplicate
+ * or for, in case-sensitive search, for exact match
+ *
+ * router entry must be created/stored in case-insensitive way
+ * in internal entry:
+ * (right most key of left page and left most key of right page
+ * are folded, and its suffix compression is propagated as router
+ * key in parent)
+ * (e.g., if split occurs <abc> and <aBd>, <ABD> trather than <aB>
+ * should be made the router key for the split)
+ *
+ * case-insensitive search:
+ *
+ * 	fold search key;
+ *
+ *	case-insensitive search of B-tree:
+ *	for internal entry, router key is already folded;
+ *	for leaf entry, fold the entry key before comparison.
+ *
+ *	if (leaf entry case-insensitive match found)
+ *		if (next entry satisfies case-insensitive match)
+ *			return EDUPLICATE;
+ *		if (prev entry satisfies case-insensitive match)
+ *			return EDUPLICATE;
+ *		return match;
+ *	else
+ *		return no match;
+ *
+ * 	serialization:
+ * target directory inode lock is being held on entry/exit
+ * of all main directory service routines.
+ *
+ *	log based recovery:
+ */
+
+#include <linux/fs.h>
+#include "jfs_incore.h"
+#include "jfs_superblock.h"
+#include "jfs_filsys.h"
+#include "jfs_metapage.h"
+#include "jfs_dmap.h"
+#include "jfs_unicode.h"
+#include "jfs_debug.h"
+
+/* dtree split parameter */
+struct dtsplit {
+	struct metapage *mp;
+	s16 index;
+	s16 nslot;
+	struct component_name *key;
+	ddata_t *data;
+	struct pxdlist *pxdlist;
+};
+
+#define DT_PAGE(IP, MP) BT_PAGE(IP, MP, dtpage_t, i_dtroot)
+
+/* get page buffer for specified block address */
+#define DT_GETPAGE(IP, BN, MP, SIZE, P, RC)\
+{\
+	BT_GETPAGE(IP, BN, MP, dtpage_t, SIZE, P, RC, i_dtroot)\
+	if (!(RC))\
+	{\
+		if (((P)->header.nextindex > (((BN)==0)?DTROOTMAXSLOT:(P)->header.maxslot)) ||\
+		    ((BN) && ((P)->header.maxslot > DTPAGEMAXSLOT)))\
+		{\
+			jERROR(1,("DT_GETPAGE: dtree page corrupt\n"));\
+			BT_PUTPAGE(MP);\
+			updateSuper((IP)->i_sb, FM_DIRTY);\
+			MP = NULL;\
+			RC = EIO;\
+		}\
+	}\
+}
+
+/* for consistency */
+#define DT_PUTPAGE(MP) BT_PUTPAGE(MP)
+
+#define DT_GETSEARCH(IP, LEAF, BN, MP, P, INDEX) \
+	BT_GETSEARCH(IP, LEAF, BN, MP, dtpage_t, P, INDEX, i_dtroot)
+
+/*
+ * forward references
+ */
+static int dtSplitUp(tid_t tid, struct inode *ip,
+		     struct dtsplit * split, struct btstack * btstack);
+
+static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
+		       struct metapage ** rmpp, dtpage_t ** rpp, pxd_t * rxdp);
+
+static int dtExtendPage(tid_t tid, struct inode *ip,
+			struct dtsplit * split, struct btstack * btstack);
+
+static int dtSplitRoot(tid_t tid, struct inode *ip,
+		       struct dtsplit * split, struct metapage ** rmpp);
+
+static int dtDeleteUp(tid_t tid, struct inode *ip, struct metapage * fmp,
+		      dtpage_t * fp, struct btstack * btstack);
+
+static int dtSearchNode(struct inode *ip,
+			s64 lmxaddr, pxd_t * kpxd, struct btstack * btstack);
+
+static int dtRelink(tid_t tid, struct inode *ip, dtpage_t * p);
+
+static int dtReadFirst(struct inode *ip, struct btstack * btstack);
+
+static int dtReadNext(struct inode *ip,
+		      loff_t * offset, struct btstack * btstack);
+
+static int dtCompare(struct component_name * key, dtpage_t * p, int si);
+
+static int ciCompare(struct component_name * key, dtpage_t * p, int si,
+		     int flag);
+
+static void dtGetKey(dtpage_t * p, int i, struct component_name * key,
+		     int flag);
+
+static void ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
+			       int ri, struct component_name * key, int flag);
+
+static void dtInsertEntry(dtpage_t * p, int index, struct component_name * key,
+			  ddata_t * data, struct dt_lock **);
+
+static void dtMoveEntry(dtpage_t * sp, int si, dtpage_t * dp,
+			struct dt_lock ** sdtlock, struct dt_lock ** ddtlock,
+			int do_index);
+
+static void dtDeleteEntry(dtpage_t * p, int fi, struct dt_lock ** dtlock);
+
+static void dtTruncateEntry(dtpage_t * p, int ti, struct dt_lock ** dtlock);
+
+static void dtLinelockFreelist(dtpage_t * p, int m, struct dt_lock ** dtlock);
+
+#define ciToUpper(c)	UniStrupr((c)->name)
+
+/*
+ *	find_index()
+ *
+ *	Returns dtree page containing directory table entry for specified
+ *	index and pointer to its entry.
+ *
+ *	mp must be released by caller.
+ */
+static struct dir_table_slot *find_index(struct inode *ip, u32 index,
+					 struct metapage ** mp)
+{
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	s64 blkno;
+	s64 offset;
+	int page_offset;
+	struct dir_table_slot *slot;
+	static int maxWarnings = 10;
+
+	if (index < 2) {
+		if (maxWarnings) {
+			jERROR(1, ("find_entry called with index = %d\n",
+				   index));
+			maxWarnings--;
+		}
+		return 0;
+	}
+
+	if (index >= jfs_ip->next_index) {
+		jFYI(1, ("find_entry called with index >= next_index\n"));
+		return 0;
+	}
+
+	if (jfs_ip->next_index <= (MAX_INLINE_DIRTABLE_ENTRY + 1)) {
+		/*
+		 * Inline directory table
+		 */
+		*mp = 0;
+		slot = &jfs_ip->i_dirtable[index - 2];
+	} else {
+		offset = (index - 2) * sizeof(struct dir_table_slot);
+		page_offset = offset & (PSIZE - 1);
+		blkno = ((offset + 1) >> L2PSIZE) <<
+		    JFS_SBI(ip->i_sb)->l2nbperpage;
+
+		if (*mp && ((*mp)->index != blkno)) {
+			release_metapage(*mp);
+			*mp = 0;
+		}
+		if (*mp == 0)
+			*mp = read_metapage(ip, blkno, PSIZE, 0);
+		if (*mp == 0) {
+			jERROR(1,
+			       ("free_index: error reading directory table\n"));
+			return 0;
+		}
+
+		slot =
+		    (struct dir_table_slot *) ((char *) (*mp)->data +
+					       page_offset);
+	}
+	return slot;
+}
+
+static inline void lock_index(tid_t tid, struct inode *ip, struct metapage * mp,
+			      u32 index)
+{
+	struct tlock *tlck;
+	struct linelock *llck;
+	struct lv *lv;
+
+	tlck = txLock(tid, ip, mp, tlckDATA);
+	llck = (struct linelock *) tlck->lock;
+
+	if (llck->index >= llck->maxcnt)
+		llck = txLinelock(llck);
+	lv = &llck->lv[llck->index];
+
+	/*
+	 *      Linelock slot size is twice the size of directory table
+	 *      slot size.  512 entries per page.
+	 */
+	lv->offset = ((index - 2) & 511) >> 1;
+	lv->length = 1;
+	llck->index++;
+}
+
+/*
+ *	add_index()
+ *
+ *	Adds an entry to the directory index table.  This is used to provide
+ *	each directory entry with a persistent index in which to resume
+ *	directory traversals
+ */
+static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
+{
+	struct super_block *sb = ip->i_sb;
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	u64 blkno;
+	struct dir_table_slot *dirtab_slot;
+	u32 index;
+	struct linelock *llck;
+	struct lv *lv;
+	struct metapage *mp;
+	s64 offset;
+	uint page_offset;
+	int rc;
+	struct tlock *tlck;
+	s64 xaddr;
+
+	ASSERT(DO_INDEX(ip));
+
+	if (jfs_ip->next_index < 2) {
+		jERROR(1, ("next_index = %d.  Please fix this!\n",
+			   jfs_ip->next_index));
+		jfs_ip->next_index = 2;
+	}
+
+	index = jfs_ip->next_index++;
+
+	if (index <= MAX_INLINE_DIRTABLE_ENTRY) {
+		/*
+		 * i_size reflects size of index table, or 8 bytes per entry.
+		 */
+		ip->i_size = (loff_t) (index - 1) << 3;
+
+		/*
+		 * dir table fits inline within inode
+		 */
+		dirtab_slot = &jfs_ip->i_dirtable[index-2];
+		dirtab_slot->flag = DIR_INDEX_VALID;
+		dirtab_slot->slot = slot;
+		DTSaddress(dirtab_slot, bn);
+
+		set_cflag(COMMIT_Dirtable, ip);
+
+		return index;
+	}
+	if (index == (MAX_INLINE_DIRTABLE_ENTRY + 1)) {
+		/*
+		 * It's time to move the inline table to an external
+		 * page and begin to build the xtree
+		 */
+
+		/*
+		 * Save the table, we're going to overwrite it with the
+		 * xtree root
+		 */
+		struct dir_table_slot temp_table[12];
+		memcpy(temp_table, &jfs_ip->i_dirtable, sizeof(temp_table));
+
+		/*
+		 * Initialize empty x-tree
+		 */
+		xtInitRoot(tid, ip);
+
+		/*
+		 * Allocate the first block & add it to the xtree
+		 */
+		xaddr = 0;
+		if ((rc =
+		     xtInsert(tid, ip, 0, 0, sbi->nbperpage,
+			      &xaddr, 0))) {
+			jFYI(1, ("add_index: xtInsert failed!\n"));
+			return -1;
+		}
+		ip->i_size = PSIZE;
+		ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage);
+
+		if ((mp = get_metapage(ip, 0, ip->i_blksize, 0)) == 0) {
+			jERROR(1, ("add_index: get_metapage failed!\n"));
+			xtTruncate(tid, ip, 0, COMMIT_PWMAP);
+			return -1;
+		}
+		tlck = txLock(tid, ip, mp, tlckDATA);
+		llck = (struct linelock *) & tlck->lock;
+		ASSERT(llck->index == 0);
+		lv = &llck->lv[0];
+
+		lv->offset = 0;
+		lv->length = 6;	/* tlckDATA slot size is 16 bytes */
+		llck->index++;
+
+		memcpy(mp->data, temp_table, sizeof(temp_table));
+
+		mark_metapage_dirty(mp);
+		release_metapage(mp);
+
+		/*
+		 * Logging is now directed by xtree tlocks
+		 */
+		clear_cflag(COMMIT_Dirtable, ip);
+	}
+
+	offset = (index - 2) * sizeof(struct dir_table_slot);
+	page_offset = offset & (PSIZE - 1);
+	blkno = ((offset + 1) >> L2PSIZE) << sbi->l2nbperpage;
+	if (page_offset == 0) {
+		/*
+		 * This will be the beginning of a new page
+		 */
+		xaddr = 0;
+		if ((rc =
+		     xtInsert(tid, ip, 0, blkno, sbi->nbperpage,
+			      &xaddr, 0))) {
+			jFYI(1, ("add_index: xtInsert failed!\n"));
+			jfs_ip->next_index--;
+			return -1;
+		}
+		ip->i_size += PSIZE;
+		ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage);
+
+		if ((mp = get_metapage(ip, blkno, PSIZE, 0)))
+			memset(mp->data, 0, PSIZE);	/* Just looks better */
+		else
+			xtTruncate(tid, ip, offset, COMMIT_PWMAP);
+	} else
+		mp = read_metapage(ip, blkno, PSIZE, 0);
+
+	if (mp == 0) {
+		jERROR(1, ("add_index: get/read_metapage failed!\n"));
+		return -1;
+	}
+
+	lock_index(tid, ip, mp, index);
+
+	dirtab_slot =
+	    (struct dir_table_slot *) ((char *) mp->data + page_offset);
+	dirtab_slot->flag = DIR_INDEX_VALID;
+	dirtab_slot->slot = slot;
+	DTSaddress(dirtab_slot, bn);
+
+	mark_metapage_dirty(mp);
+	release_metapage(mp);
+
+	return index;
+}
+
+/*
+ *	free_index()
+ *
+ *	Marks an entry to the directory index table as free.
+ */
+static void free_index(tid_t tid, struct inode *ip, u32 index, u32 next)
+{
+	struct dir_table_slot *dirtab_slot;
+	struct metapage *mp = 0;
+
+	dirtab_slot = find_index(ip, index, &mp);
+
+	if (dirtab_slot == 0)
+		return;
+
+	dirtab_slot->flag = DIR_INDEX_FREE;
+	dirtab_slot->slot = dirtab_slot->addr1 = 0;
+	dirtab_slot->addr2 = cpu_to_le32(next);
+
+	if (mp) {
+		lock_index(tid, ip, mp, index);
+		mark_metapage_dirty(mp);
+		release_metapage(mp);
+	} else
+		set_cflag(COMMIT_Dirtable, ip);
+}
+
+/*
+ *	modify_index()
+ *
+ *	Changes an entry in the directory index table
+ */
+static void modify_index(tid_t tid, struct inode *ip, u32 index, s64 bn,
+			 int slot, struct metapage ** mp)
+{
+	struct dir_table_slot *dirtab_slot;
+
+	dirtab_slot = find_index(ip, index, mp);
+
+	if (dirtab_slot == 0)
+		return;
+
+	DTSaddress(dirtab_slot, bn);
+	dirtab_slot->slot = slot;
+
+	if (*mp) {
+		lock_index(tid, ip, *mp, index);
+		mark_metapage_dirty(*mp);
+	} else
+		set_cflag(COMMIT_Dirtable, ip);
+}
+
+/*
+ *	read_index()
+ *
+ *	reads a directory table slot
+ */
+static int read_index(struct inode *ip, u32 index,
+		     struct dir_table_slot * dirtab_slot)
+{
+	struct metapage *mp = 0;
+	struct dir_table_slot *slot;
+
+	slot = find_index(ip, index, &mp);
+	if (slot == 0) {
+		return -EIO;
+	}
+
+	memcpy(dirtab_slot, slot, sizeof(struct dir_table_slot));
+
+	if (mp)
+		release_metapage(mp);
+
+	return 0;
+}
+
+/*
+ *	dtSearch()
+ *
+ * function:
+ *	Search for the entry with specified key
+ *
+ * parameter:
+ *
+ * return: 0 - search result on stack, leaf page pinned;
+ *	   errno - I/O error
+ */
+int dtSearch(struct inode *ip, struct component_name * key, ino_t * data,
+	     struct btstack * btstack, int flag)
+{
+	int rc = 0;
+	int cmp = 1;		/* init for empty page */
+	s64 bn;
+	struct metapage *mp;
+	dtpage_t *p;
+	s8 *stbl;
+	int base, index, lim;
+	struct btframe *btsp;
+	pxd_t *pxd;
+	int psize = 288;	/* initial in-line directory */
+	ino_t inumber;
+	struct component_name ciKey;
+	struct super_block *sb = ip->i_sb;
+
+	ciKey.name =
+	    (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t),
+				GFP_NOFS);
+	if (ciKey.name == 0) {
+		rc = ENOMEM;
+		goto dtSearch_Exit2;
+	}
+
+
+	/* uppercase search key for c-i directory */
+	UniStrcpy(ciKey.name, key->name);
+	ciKey.namlen = key->namlen;
+
+	/* only uppercase if case-insensitive support is on */
+	if ((JFS_SBI(sb)->mntflag & JFS_OS2) == JFS_OS2) {
+		ciToUpper(&ciKey);
+	}
+	BT_CLR(btstack);	/* reset stack */
+
+	/* init level count for max pages to split */
+	btstack->nsplit = 1;
+
+	/*
+	 *      search down tree from root:
+	 *
+	 * between two consecutive entries of <Ki, Pi> and <Kj, Pj> of
+	 * internal page, child page Pi contains entry with k, Ki <= K < Kj.
+	 *
+	 * if entry with search key K is not found
+	 * internal page search find the entry with largest key Ki
+	 * less than K which point to the child page to search;
+	 * leaf page search find the entry with smallest key Kj
+	 * greater than K so that the returned index is the position of
+	 * the entry to be shifted right for insertion of new entry.
+	 * for empty tree, search key is greater than any key of the tree.
+	 *
+	 * by convention, root bn = 0.
+	 */
+	for (bn = 0;;) {
+		/* get/pin the page to search */
+		DT_GETPAGE(ip, bn, mp, psize, p, rc);
+		if (rc)
+			goto dtSearch_Exit1;
+
+		/* get sorted entry table of the page */
+		stbl = DT_GETSTBL(p);
+
+		/*
+		 * binary search with search key K on the current page.
+		 */
+		for (base = 0, lim = p->header.nextindex; lim; lim >>= 1) {
+			index = base + (lim >> 1);
+
+			if (p->header.flag & BT_LEAF) {
+				/* uppercase leaf name to compare */
+				cmp =
+				    ciCompare(&ciKey, p, stbl[index],
+					      JFS_SBI(sb)->mntflag);
+			} else {
+				/* router key is in uppercase */
+
+				cmp = dtCompare(&ciKey, p, stbl[index]);
+
+
+			}
+			if (cmp == 0) {
+				/*
+				 *      search hit
+				 */
+				/* search hit - leaf page:
+				 * return the entry found
+				 */
+				if (p->header.flag & BT_LEAF) {
+					inumber = le32_to_cpu(
+			((struct ldtentry *) & p->slot[stbl[index]])->inumber);
+
+					/*
+					 * search for JFS_LOOKUP
+					 */
+					if (flag == JFS_LOOKUP) {
+						*data = inumber;
+						rc = 0;
+						goto out;
+					}
+
+					/*
+					 * search for JFS_CREATE
+					 */
+					if (flag == JFS_CREATE) {
+						*data = inumber;
+						rc = EEXIST;
+						goto out;
+					}
+
+					/*
+					 * search for JFS_REMOVE or JFS_RENAME
+					 */
+					if ((flag == JFS_REMOVE ||
+					     flag == JFS_RENAME) &&
+					    *data != inumber) {
+						rc = ESTALE;
+						goto out;
+					}
+
+					/*
+					 * JFS_REMOVE|JFS_FINDDIR|JFS_RENAME
+					 */
+					/* save search result */
+					*data = inumber;
+					btsp = btstack->top;
+					btsp->bn = bn;
+					btsp->index = index;
+					btsp->mp = mp;
+
+					rc = 0;
+					goto dtSearch_Exit1;
+				}
+
+				/* search hit - internal page:
+				 * descend/search its child page
+				 */
+				goto getChild;
+			}
+
+			if (cmp > 0) {
+				base = index + 1;
+				--lim;
+			}
+		}
+
+		/*
+		 *      search miss
+		 *
+		 * base is the smallest index with key (Kj) greater than
+		 * search key (K) and may be zero or (maxindex + 1) index.
+		 */
+		/*
+		 * search miss - leaf page
+		 *
+		 * return location of entry (base) where new entry with
+		 * search key K is to be inserted.
+		 */
+		if (p->header.flag & BT_LEAF) {
+			/*
+			 * search for JFS_LOOKUP, JFS_REMOVE, or JFS_RENAME
+			 */
+			if (flag == JFS_LOOKUP || flag == JFS_REMOVE ||
+			    flag == JFS_RENAME) {
+				rc = ENOENT;
+				goto out;
+			}
+
+			/*
+			 * search for JFS_CREATE|JFS_FINDDIR:
+			 *
+			 * save search result
+			 */
+			*data = 0;
+			btsp = btstack->top;
+			btsp->bn = bn;
+			btsp->index = base;
+			btsp->mp = mp;
+
+			rc = 0;
+			goto dtSearch_Exit1;
+		}
+
+		/*
+		 * search miss - internal page
+		 *
+		 * if base is non-zero, decrement base by one to get the parent
+		 * entry of the child page to search.
+		 */
+		index = base ? base - 1 : base;
+
+		/*
+		 * go down to child page
+		 */
+	      getChild:
+		/* update max. number of pages to split */
+		if (btstack->nsplit >= 8) {
+			/* Something's corrupted, mark filesytem dirty so
+			 * chkdsk will fix it.
+			 */
+			jERROR(1, ("stack overrun in dtSearch!\n"));
+			updateSuper(sb, FM_DIRTY);
+			rc = EIO;
+			goto out;
+		}
+		btstack->nsplit++;
+
+		/* push (bn, index) of the parent page/entry */
+		BT_PUSH(btstack, bn, index);
+
+		/* get the child page block number */
+		pxd = (pxd_t *) & p->slot[stbl[index]];
+		bn = addressPXD(pxd);
+		psize = lengthPXD(pxd) << JFS_SBI(ip->i_sb)->l2bsize;
+
+		/* unpin the parent page */
+		DT_PUTPAGE(mp);
+	}
+
+      out:
+	DT_PUTPAGE(mp);
+
+      dtSearch_Exit1:
+
+	kfree(ciKey.name);
+
+      dtSearch_Exit2:
+
+	return rc;
+}
+
+
+/*
+ *	dtInsert()
+ *
+ * function: insert an entry to directory tree
+ *
+ * parameter:
+ *
+ * return: 0 - success;
+ *	   errno - failure;
+ */
+int dtInsert(tid_t tid, struct inode *ip,
+	 struct component_name * name, ino_t * fsn, struct btstack * btstack)
+{
+	int rc = 0;
+	struct metapage *mp;	/* meta-page buffer */
+	dtpage_t *p;		/* base B+-tree index page */
+	s64 bn;
+	int index;
+	struct dtsplit split;	/* split information */
+	ddata_t data;
+	struct dt_lock *dtlck;
+	int n;
+	struct tlock *tlck;
+	struct lv *lv;
+
+	/*
+	 *      retrieve search result
+	 *
+	 * dtSearch() returns (leaf page pinned, index at which to insert).
+	 * n.b. dtSearch() may return index of (maxindex + 1) of
+	 * the full page.
+	 */
+	DT_GETSEARCH(ip, btstack->top, bn, mp, p, index);
+
+	/*
+	 *      insert entry for new key
+	 */
+	if (DO_INDEX(ip)) {
+		if (JFS_IP(ip)->next_index == DIREND) {
+			DT_PUTPAGE(mp);
+			return EMLINK;
+		}
+		n = NDTLEAF(name->namlen);
+		data.leaf.tid = tid;
+		data.leaf.ip = ip;
+	} else {
+		n = NDTLEAF_LEGACY(name->namlen);
+		data.leaf.ip = 0;	/* signifies legacy directory format */
+	}
+	data.leaf.ino = cpu_to_le32(*fsn);
+
+	/*
+	 *      leaf page does not have enough room for new entry:
+	 *
+	 *      extend/split the leaf page;
+	 *
+	 * dtSplitUp() will insert the entry and unpin the leaf page.
+	 */
+	if (n > p->header.freecnt) {
+		split.mp = mp;
+		split.index = index;
+		split.nslot = n;
+		split.key = name;
+		split.data = &data;
+		rc = dtSplitUp(tid, ip, &split, btstack);
+		return rc;
+	}
+
+	/*
+	 *      leaf page does have enough room for new entry:
+	 *
+	 *      insert the new data entry into the leaf page;
+	 */
+	BT_MARK_DIRTY(mp, ip);
+	/*
+	 * acquire a transaction lock on the leaf page
+	 */
+	tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+	dtlck = (struct dt_lock *) & tlck->lock;
+	ASSERT(dtlck->index == 0);
+	lv = & dtlck->lv[0];
+
+	/* linelock header */
+	lv->offset = 0;
+	lv->length = 1;
+	dtlck->index++;
+
+	dtInsertEntry(p, index, name, &data, &dtlck);
+
+	/* linelock stbl of non-root leaf page */
+	if (!(p->header.flag & BT_ROOT)) {
+		if (dtlck->index >= dtlck->maxcnt)
+			dtlck = (struct dt_lock *) txLinelock(dtlck);
+		lv = & dtlck->lv[dtlck->index];
+		n = index >> L2DTSLOTSIZE;
+		lv->offset = p->header.stblindex + n;
+		lv->length =
+		    ((p->header.nextindex - 1) >> L2DTSLOTSIZE) - n + 1;
+		dtlck->index++;
+	}
+
+	/* unpin the leaf page */
+	DT_PUTPAGE(mp);
+
+	return 0;
+}
+
+
+/*
+ *	dtSplitUp()
+ *
+ * function: propagate insertion bottom up;
+ *
+ * parameter:
+ *
+ * return: 0 - success;
+ *	   errno - failure;
+ * 	leaf page unpinned;
+ */
+static int dtSplitUp(tid_t tid,
+	  struct inode *ip, struct dtsplit * split, struct btstack * btstack)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
+	int rc = 0;
+	struct metapage *smp;
+	dtpage_t *sp;		/* split page */
+	struct metapage *rmp;
+	dtpage_t *rp;		/* new right page split from sp */
+	pxd_t rpxd;		/* new right page extent descriptor */
+	struct metapage *lmp;
+	dtpage_t *lp;		/* left child page */
+	int skip;		/* index of entry of insertion */
+	struct btframe *parent;	/* parent page entry on traverse stack */
+	s64 xaddr, nxaddr;
+	int xlen, xsize;
+	struct pxdlist pxdlist;
+	pxd_t *pxd;
+	struct component_name key = { 0, 0 };
+	ddata_t *data = split->data;
+	int n;
+	struct dt_lock *dtlck;
+	struct tlock *tlck;
+	struct lv *lv;
+
+	/* get split page */
+	smp = split->mp;
+	sp = DT_PAGE(ip, smp);
+
+	key.name =
+	    (wchar_t *) kmalloc((JFS_NAME_MAX + 2) * sizeof(wchar_t),
+				GFP_NOFS);
+	if (key.name == 0) {
+		DT_PUTPAGE(smp);
+		rc = ENOMEM;
+		goto dtSplitUp_Exit;
+	}
+
+	/*
+	 *      split leaf page
+	 *
+	 * The split routines insert the new entry, and
+	 * acquire txLock as appropriate.
+	 */
+	/*
+	 *      split root leaf page:
+	 */
+	if (sp->header.flag & BT_ROOT) {
+		/*
+		 * allocate a single extent child page
+		 */
+		xlen = 1;
+		n = sbi->bsize >> L2DTSLOTSIZE;
+		n -= (n + 31) >> L2DTSLOTSIZE;	/* stbl size */
+		n -= DTROOTMAXSLOT - sp->header.freecnt; /* header + entries */
+		if (n <= split->nslot)
+			xlen++;
+		if ((rc = dbAlloc(ip, 0, (s64) xlen, &xaddr)))
+			goto freeKeyName;
+
+		pxdlist.maxnpxd = 1;
+		pxdlist.npxd = 0;
+		pxd = &pxdlist.pxd[0];
+		PXDaddress(pxd, xaddr);
+		PXDlength(pxd, xlen);
+		split->pxdlist = &pxdlist;
+		rc = dtSplitRoot(tid, ip, split, &rmp);
+
+		DT_PUTPAGE(rmp);
+		DT_PUTPAGE(smp);
+
+		goto freeKeyName;
+	}
+
+	/*
+	 *      extend first leaf page
+	 *
+	 * extend the 1st extent if less than buffer page size
+	 * (dtExtendPage() reurns leaf page unpinned)
+	 */
+	pxd = &sp->header.self;
+	xlen = lengthPXD(pxd);
+	xsize = xlen << sbi->l2bsize;
+	if (xsize < PSIZE) {
+		xaddr = addressPXD(pxd);
+		n = xsize >> L2DTSLOTSIZE;
+		n -= (n + 31) >> L2DTSLOTSIZE;	/* stbl size */
+		if ((n + sp->header.freecnt) <= split->nslot)
+			n = xlen + (xlen << 1);
+		else
+			n = xlen;
+		if ((rc = dbReAlloc(sbi->ipbmap, xaddr, (s64) xlen,
+				    (s64) n, &nxaddr)))
+			goto extendOut;
+
+		pxdlist.maxnpxd = 1;
+		pxdlist.npxd = 0;
+		pxd = &pxdlist.pxd[0];
+		PXDaddress(pxd, nxaddr)
+		    PXDlength(pxd, xlen + n);
+		split->pxdlist = &pxdlist;
+		if ((rc = dtExtendPage(tid, ip, split, btstack))) {
+			nxaddr = addressPXD(pxd);
+			if (xaddr != nxaddr) {
+				/* free relocated extent */
+				xlen = lengthPXD(pxd);
+				dbFree(ip, nxaddr, (s64) xlen);
+			} else {
+				/* free extended delta */
+				xlen = lengthPXD(pxd) - n;
+				xaddr = addressPXD(pxd) + xlen;
+				dbFree(ip, xaddr, (s64) n);
+			}
+		}
+
+	      extendOut:
+		DT_PUTPAGE(smp);
+		goto freeKeyName;
+	}
+
+	/*
+	 *      split leaf page <sp> into <sp> and a new right page <rp>.
+	 *
+	 * return <rp> pinned and its extent descriptor <rpxd>
+	 */
+	/*
+	 * allocate new directory page extent and
+	 * new index page(s) to cover page split(s)
+	 *
+	 * allocation hint: ?
+	 */
+	n = btstack->nsplit;
+	pxdlist.maxnpxd = pxdlist.npxd = 0;
+	xlen = sbi->nbperpage;
+	for (pxd = pxdlist.pxd; n > 0; n--, pxd++) {
+		if ((rc = dbAlloc(ip, 0, (s64) xlen, &xaddr)) == 0) {
+			PXDaddress(pxd, xaddr);
+			PXDlength(pxd, xlen);
+			pxdlist.maxnpxd++;
+			continue;
+		}
+
+		DT_PUTPAGE(smp);
+
+		/* undo allocation */
+		goto splitOut;
+	}
+
+	split->pxdlist = &pxdlist;
+	if ((rc = dtSplitPage(tid, ip, split, &rmp, &rp, &rpxd))) {
+		DT_PUTPAGE(smp);
+
+		/* undo allocation */
+		goto splitOut;
+	}
+
+	/*
+	 * propagate up the router entry for the leaf page just split
+	 *
+	 * insert a router entry for the new page into the parent page,
+	 * propagate the insert/split up the tree by walking back the stack
+	 * of (bn of parent page, index of child page entry in parent page)
+	 * that were traversed during the search for the page that split.
+	 *
+	 * the propagation of insert/split up the tree stops if the root
+	 * splits or the page inserted into doesn't have to split to hold
+	 * the new entry.
+	 *
+	 * the parent entry for the split page remains the same, and
+	 * a new entry is inserted at its right with the first key and
+	 * block number of the new right page.
+	 *
+	 * There are a maximum of 4 pages pinned at any time:
+	 * two children, left parent and right parent (when the parent splits).
+	 * keep the child pages pinned while working on the parent.
+	 * make sure that all pins are released at exit.
+	 */
+	while ((parent = BT_POP(btstack)) != NULL) {
+		/* parent page specified by stack frame <parent> */
+
+		/* keep current child pages (<lp>, <rp>) pinned */
+		lmp = smp;
+		lp = sp;
+
+		/*
+		 * insert router entry in parent for new right child page <rp>
+		 */
+		/* get the parent page <sp> */
+		DT_GETPAGE(ip, parent->bn, smp, PSIZE, sp, rc);
+		if (rc) {
+			DT_PUTPAGE(lmp);
+			DT_PUTPAGE(rmp);
+			goto splitOut;
+		}
+
+		/*
+		 * The new key entry goes ONE AFTER the index of parent entry,
+		 * because the split was to the right.
+		 */
+		skip = parent->index + 1;
+
+		/*
+		 * compute the key for the router entry
+		 *
+		 * key suffix compression:
+		 * for internal pages that have leaf pages as children,
+		 * retain only what's needed to distinguish between
+		 * the new entry and the entry on the page to its left.
+		 * If the keys compare equal, retain the entire key.
+		 *
+		 * note that compression is performed only at computing
+		 * router key at the lowest internal level.
+		 * further compression of the key between pairs of higher
+		 * level internal pages loses too much information and
+		 * the search may fail.
+		 * (e.g., two adjacent leaf pages of {a, ..., x} {xx, ...,}
+		 * results in two adjacent parent entries (a)(xx).
+		 * if split occurs between these two entries, and
+		 * if compression is applied, the router key of parent entry
+		 * of right page (x) will divert search for x into right
+		 * subtree and miss x in the left subtree.)
+		 *
+		 * the entire key must be retained for the next-to-leftmost
+		 * internal key at any level of the tree, or search may fail
+		 * (e.g., ?)
+		 */
+		switch (rp->header.flag & BT_TYPE) {
+		case BT_LEAF:
+			/*
+			 * compute the length of prefix for suffix compression
+			 * between last entry of left page and first entry
+			 * of right page
+			 */
+			if ((sp->header.flag & BT_ROOT && skip > 1) ||
+			    sp->header.prev != 0 || skip > 1) {
+				/* compute uppercase router prefix key */
+				ciGetLeafPrefixKey(lp,
+						   lp->header.nextindex - 1,
+						   rp, 0, &key, sbi->mntflag);
+			} else {
+				/* next to leftmost entry of
+				   lowest internal level */
+
+				/* compute uppercase router key */
+				dtGetKey(rp, 0, &key, sbi->mntflag);
+				key.name[key.namlen] = 0;
+
+				if ((sbi->mntflag & JFS_OS2) == JFS_OS2)
+					ciToUpper(&key);
+			}
+
+			n = NDTINTERNAL(key.namlen);
+			break;
+
+		case BT_INTERNAL:
+			dtGetKey(rp, 0, &key, sbi->mntflag);
+			n = NDTINTERNAL(key.namlen);
+			break;
+
+		default:
+			jERROR(2, ("dtSplitUp(): UFO!\n"));
+			break;
+		}
+
+		/* unpin left child page */
+		DT_PUTPAGE(lmp);
+
+		/*
+		 * compute the data for the router entry
+		 */
+		data->xd = rpxd;	/* child page xd */
+
+		/*
+		 * parent page is full - split the parent page
+		 */
+		if (n > sp->header.freecnt) {
+			/* init for parent page split */
+			split->mp = smp;
+			split->index = skip;	/* index at insert */
+			split->nslot = n;
+			split->key = &key;
+			/* split->data = data; */
+
+			/* unpin right child page */
+			DT_PUTPAGE(rmp);
+
+			/* The split routines insert the new entry,
+			 * acquire txLock as appropriate.
+			 * return <rp> pinned and its block number <rbn>.
+			 */
+			rc = (sp->header.flag & BT_ROOT) ?
+			    dtSplitRoot(tid, ip, split, &rmp) :
+			    dtSplitPage(tid, ip, split, &rmp, &rp, &rpxd);
+			if (rc) {
+				DT_PUTPAGE(smp);
+				goto splitOut;
+			}
+
+			/* smp and rmp are pinned */
+		}
+		/*
+		 * parent page is not full - insert router entry in parent page
+		 */
+		else {
+			BT_MARK_DIRTY(smp, ip);
+			/*
+			 * acquire a transaction lock on the parent page
+			 */
+			tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY);
+			dtlck = (struct dt_lock *) & tlck->lock;
+			ASSERT(dtlck->index == 0);
+			lv = & dtlck->lv[0];
+
+			/* linelock header */
+			lv->offset = 0;
+			lv->length = 1;
+			dtlck->index++;
+
+			/* linelock stbl of non-root parent page */
+			if (!(sp->header.flag & BT_ROOT)) {
+				lv++;
+				n = skip >> L2DTSLOTSIZE;
+				lv->offset = sp->header.stblindex + n;
+				lv->length =
+				    ((sp->header.nextindex -
+				      1) >> L2DTSLOTSIZE) - n + 1;
+				dtlck->index++;
+			}
+
+			dtInsertEntry(sp, skip, &key, data, &dtlck);
+
+			/* exit propagate up */
+			break;
+		}
+	}
+
+	/* unpin current split and its right page */
+	DT_PUTPAGE(smp);
+	DT_PUTPAGE(rmp);
+
+	/*
+	 * free remaining extents allocated for split
+	 */
+      splitOut:
+	n = pxdlist.npxd;
+	pxd = &pxdlist.pxd[n];
+	for (; n < pxdlist.maxnpxd; n++, pxd++)
+		dbFree(ip, addressPXD(pxd), (s64) lengthPXD(pxd));
+
+      freeKeyName:
+	kfree(key.name);
+
+      dtSplitUp_Exit:
+
+	return rc;
+}
+
+
+/*
+ *	dtSplitPage()
+ *
+ * function: Split a non-root page of a btree.
+ *
+ * parameter:
+ *
+ * return: 0 - success;
+ *	   errno - failure;
+ *	return split and new page pinned;
+ */
+static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
+	    struct metapage ** rmpp, dtpage_t ** rpp, pxd_t * rpxdp)
+{
+	struct super_block *sb = ip->i_sb;
+	int rc = 0;
+	struct metapage *smp;
+	dtpage_t *sp;
+	struct metapage *rmp;
+	dtpage_t *rp;		/* new right page allocated */
+	s64 rbn;		/* new right page block number */
+	struct metapage *mp;
+	dtpage_t *p;
+	s64 nextbn;
+	struct pxdlist *pxdlist;
+	pxd_t *pxd;
+	int skip, nextindex, half, left, nxt, off, si;
+	struct ldtentry *ldtentry;
+	struct idtentry *idtentry;
+	u8 *stbl;
+	struct dtslot *f;
+	int fsi, stblsize;
+	int n;
+	struct dt_lock *sdtlck, *rdtlck;
+	struct tlock *tlck;
+	struct dt_lock *dtlck;
+	struct lv *slv, *rlv, *lv;
+
+	/* get split page */
+	smp = split->mp;
+	sp = DT_PAGE(ip, smp);
+
+	/*
+	 * allocate the new right page for the split
+	 */
+	pxdlist = split->pxdlist;
+	pxd = &pxdlist->pxd[pxdlist->npxd];
+	pxdlist->npxd++;
+	rbn = addressPXD(pxd);
+	rmp = get_metapage(ip, rbn, PSIZE, 1);
+	if (rmp == NULL)
+		return EIO;
+
+	jEVENT(0,
+	       ("dtSplitPage: ip:0x%p smp:0x%p rmp:0x%p\n", ip, smp, rmp));
+
+	BT_MARK_DIRTY(rmp, ip);
+	/*
+	 * acquire a transaction lock on the new right page
+	 */
+	tlck = txLock(tid, ip, rmp, tlckDTREE | tlckNEW);
+	rdtlck = (struct dt_lock *) & tlck->lock;
+
+	rp = (dtpage_t *) rmp->data;
+	*rpp = rp;
+	rp->header.self = *pxd;
+
+	BT_MARK_DIRTY(smp, ip);
+	/*
+	 * acquire a transaction lock on the split page
+	 *
+	 * action:
+	 */
+	tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY);
+	sdtlck = (struct dt_lock *) & tlck->lock;
+
+	/* linelock header of split page */
+	ASSERT(sdtlck->index == 0);
+	slv = & sdtlck->lv[0];
+	slv->offset = 0;
+	slv->length = 1;
+	sdtlck->index++;
+
+	/*
+	 * initialize/update sibling pointers between sp and rp
+	 */
+	nextbn = le64_to_cpu(sp->header.next);
+	rp->header.next = cpu_to_le64(nextbn);
+	rp->header.prev = cpu_to_le64(addressPXD(&sp->header.self));
+	sp->header.next = cpu_to_le64(rbn);
+
+	/*
+	 * initialize new right page
+	 */
+	rp->header.flag = sp->header.flag;
+
+	/* compute sorted entry table at start of extent data area */
+	rp->header.nextindex = 0;
+	rp->header.stblindex = 1;
+
+	n = PSIZE >> L2DTSLOTSIZE;
+	rp->header.maxslot = n;
+	stblsize = (n + 31) >> L2DTSLOTSIZE;	/* in unit of slot */
+
+	/* init freelist */
+	fsi = rp->header.stblindex + stblsize;
+	rp->header.freelist = fsi;
+	rp->header.freecnt = rp->header.maxslot - fsi;
+
+	/*
+	 *      sequential append at tail: append without split
+	 *
+	 * If splitting the last page on a level because of appending
+	 * a entry to it (skip is maxentry), it's likely that the access is
+	 * sequential. Adding an empty page on the side of the level is less
+	 * work and can push the fill factor much higher than normal.
+	 * If we're wrong it's no big deal, we'll just do the split the right
+	 * way next time.
+	 * (It may look like it's equally easy to do a similar hack for
+	 * reverse sorted data, that is, split the tree left,
+	 * but it's not. Be my guest.)
+	 */
+	if (nextbn == 0 && split->index == sp->header.nextindex) {
+		/* linelock header + stbl (first slot) of new page */
+		rlv = & rdtlck->lv[rdtlck->index];
+		rlv->offset = 0;
+		rlv->length = 2;
+		rdtlck->index++;
+
+		/*
+		 * initialize freelist of new right page
+		 */
+		f = &rp->slot[fsi];
+		for (fsi++; fsi < rp->header.maxslot; f++, fsi++)
+			f->next = fsi;
+		f->next = -1;
+
+		/* insert entry at the first entry of the new right page */
+		dtInsertEntry(rp, 0, split->key, split->data, &rdtlck);
+
+		goto out;
+	}
+
+	/*
+	 *      non-sequential insert (at possibly middle page)
+	 */
+
+	/*
+	 * update prev pointer of previous right sibling page;
+	 */
+	if (nextbn != 0) {
+		DT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		BT_MARK_DIRTY(mp, ip);
+		/*
+		 * acquire a transaction lock on the next page
+		 */
+		tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK);
+		jEVENT(0,
+		       ("dtSplitPage: tlck = 0x%p, ip = 0x%p, mp=0x%p\n",
+			tlck, ip, mp));
+		dtlck = (struct dt_lock *) & tlck->lock;
+
+		/* linelock header of previous right sibling page */
+		lv = & dtlck->lv[dtlck->index];
+		lv->offset = 0;
+		lv->length = 1;
+		dtlck->index++;
+
+		p->header.prev = cpu_to_le64(rbn);
+
+		DT_PUTPAGE(mp);
+	}
+
+	/*
+	 * split the data between the split and right pages.
+	 */
+	skip = split->index;
+	half = (PSIZE >> L2DTSLOTSIZE) >> 1;	/* swag */
+	left = 0;
+
+	/*
+	 *      compute fill factor for split pages
+	 *
+	 * <nxt> traces the next entry to move to rp
+	 * <off> traces the next entry to stay in sp
+	 */
+	stbl = (u8 *) & sp->slot[sp->header.stblindex];
+	nextindex = sp->header.nextindex;
+	for (nxt = off = 0; nxt < nextindex; ++off) {
+		if (off == skip)
+			/* check for fill factor with new entry size */
+			n = split->nslot;
+		else {
+			si = stbl[nxt];
+			switch (sp->header.flag & BT_TYPE) {
+			case BT_LEAF:
+				ldtentry = (struct ldtentry *) & sp->slot[si];
+				if (DO_INDEX(ip))
+					n = NDTLEAF(ldtentry->namlen);
+				else
+					n = NDTLEAF_LEGACY(ldtentry->
+							   namlen);
+				break;
+
+			case BT_INTERNAL:
+				idtentry = (struct idtentry *) & sp->slot[si];
+				n = NDTINTERNAL(idtentry->namlen);
+				break;
+
+			default:
+				break;
+			}
+
+			++nxt;	/* advance to next entry to move in sp */
+		}
+
+		left += n;
+		if (left >= half)
+			break;
+	}
+
+	/* <nxt> poins to the 1st entry to move */
+
+	/*
+	 *      move entries to right page
+	 *
+	 * dtMoveEntry() initializes rp and reserves entry for insertion
+	 *
+	 * split page moved out entries are linelocked;
+	 * new/right page moved in entries are linelocked;
+	 */
+	/* linelock header + stbl of new right page */
+	rlv = & rdtlck->lv[rdtlck->index];
+	rlv->offset = 0;
+	rlv->length = 5;
+	rdtlck->index++;
+
+	dtMoveEntry(sp, nxt, rp, &sdtlck, &rdtlck, DO_INDEX(ip));
+
+	sp->header.nextindex = nxt;
+
+	/*
+	 * finalize freelist of new right page
+	 */
+	fsi = rp->header.freelist;
+	f = &rp->slot[fsi];
+	for (fsi++; fsi < rp->header.maxslot; f++, fsi++)
+		f->next = fsi;
+	f->next = -1;
+
+	/*
+	 * Update directory index table for entries now in right page
+	 */
+	if ((rp->header.flag & BT_LEAF) && DO_INDEX(ip)) {
+		mp = 0;
+		stbl = DT_GETSTBL(rp);
+		for (n = 0; n < rp->header.nextindex; n++) {
+			ldtentry = (struct ldtentry *) & rp->slot[stbl[n]];
+			modify_index(tid, ip, le32_to_cpu(ldtentry->index),
+				     rbn, n, &mp);
+		}
+		if (mp)
+			release_metapage(mp);
+	}
+
+	/*
+	 * the skipped index was on the left page,
+	 */
+	if (skip <= off) {
+		/* insert the new entry in the split page */
+		dtInsertEntry(sp, skip, split->key, split->data, &sdtlck);
+
+		/* linelock stbl of split page */
+		if (sdtlck->index >= sdtlck->maxcnt)
+			sdtlck = (struct dt_lock *) txLinelock(sdtlck);
+		slv = & sdtlck->lv[sdtlck->index];
+		n = skip >> L2DTSLOTSIZE;
+		slv->offset = sp->header.stblindex + n;
+		slv->length =
+		    ((sp->header.nextindex - 1) >> L2DTSLOTSIZE) - n + 1;
+		sdtlck->index++;
+	}
+	/*
+	 * the skipped index was on the right page,
+	 */
+	else {
+		/* adjust the skip index to reflect the new position */
+		skip -= nxt;
+
+		/* insert the new entry in the right page */
+		dtInsertEntry(rp, skip, split->key, split->data, &rdtlck);
+	}
+
+      out:
+	*rmpp = rmp;
+	*rpxdp = *pxd;
+
+	ip->i_blocks += LBLK2PBLK(sb, lengthPXD(pxd));
+
+	jEVENT(0, ("dtSplitPage: ip:0x%p sp:0x%p rp:0x%p\n", ip, sp, rp));
+	return 0;
+}
+
+
+/*
+ *	dtExtendPage()
+ *
+ * function: extend 1st/only directory leaf page
+ *
+ * parameter:
+ *
+ * return: 0 - success;
+ *	   errno - failure;
+ *	return extended page pinned;
+ */
+static int dtExtendPage(tid_t tid,
+	     struct inode *ip, struct dtsplit * split, struct btstack * btstack)
+{
+	struct super_block *sb = ip->i_sb;
+	int rc;
+	struct metapage *smp, *pmp, *mp;
+	dtpage_t *sp, *pp;
+	struct pxdlist *pxdlist;
+	pxd_t *pxd, *tpxd;
+	int xlen, xsize;
+	int newstblindex, newstblsize;
+	int oldstblindex, oldstblsize;
+	int fsi, last;
+	struct dtslot *f;
+	struct btframe *parent;
+	int n;
+	struct dt_lock *dtlck;
+	s64 xaddr, txaddr;
+	struct tlock *tlck;
+	struct pxd_lock *pxdlock;
+	struct lv *lv;
+	uint type;
+	struct ldtentry *ldtentry;
+	u8 *stbl;
+
+	/* get page to extend */
+	smp = split->mp;
+	sp = DT_PAGE(ip, smp);
+
+	/* get parent/root page */
+	parent = BT_POP(btstack);
+	DT_GETPAGE(ip, parent->bn, pmp, PSIZE, pp, rc);
+	if (rc)
+		return (rc);
+
+	/*
+	 *      extend the extent
+	 */
+	pxdlist = split->pxdlist;
+	pxd = &pxdlist->pxd[pxdlist->npxd];
+	pxdlist->npxd++;
+
+	xaddr = addressPXD(pxd);
+	tpxd = &sp->header.self;
+	txaddr = addressPXD(tpxd);
+	/* in-place extension */
+	if (xaddr == txaddr) {
+		type = tlckEXTEND;
+	}
+	/* relocation */
+	else {
+		type = tlckNEW;
+
+		/* save moved extent descriptor for later free */
+		tlck = txMaplock(tid, ip, tlckDTREE | tlckRELOCATE);
+		pxdlock = (struct pxd_lock *) & tlck->lock;
+		pxdlock->flag = mlckFREEPXD;
+		pxdlock->pxd = sp->header.self;
+		pxdlock->index = 1;
+
+		/*
+		 * Update directory index table to reflect new page address
+		 */
+		if (DO_INDEX(ip)) {
+			mp = 0;
+			stbl = DT_GETSTBL(sp);
+			for (n = 0; n < sp->header.nextindex; n++) {
+				ldtentry =
+				    (struct ldtentry *) & sp->slot[stbl[n]];
+				modify_index(tid, ip,
+					     le32_to_cpu(ldtentry->index),
+					     xaddr, n, &mp);
+			}
+			if (mp)
+				release_metapage(mp);
+		}
+	}
+
+	/*
+	 *      extend the page
+	 */
+	sp->header.self = *pxd;
+
+	jEVENT(0,
+	       ("dtExtendPage: ip:0x%p smp:0x%p sp:0x%p\n", ip, smp, sp));
+
+	BT_MARK_DIRTY(smp, ip);
+	/*
+	 * acquire a transaction lock on the extended/leaf page
+	 */
+	tlck = txLock(tid, ip, smp, tlckDTREE | type);
+	dtlck = (struct dt_lock *) & tlck->lock;
+	lv = & dtlck->lv[0];
+
+	/* update buffer extent descriptor of extended page */
+	xlen = lengthPXD(pxd);
+	xsize = xlen << JFS_SBI(sb)->l2bsize;
+#ifdef _STILL_TO_PORT
+	bmSetXD(smp, xaddr, xsize);
+#endif				/*  _STILL_TO_PORT */
+
+	/*
+	 * copy old stbl to new stbl at start of extended area
+	 */
+	oldstblindex = sp->header.stblindex;
+	oldstblsize = (sp->header.maxslot + 31) >> L2DTSLOTSIZE;
+	newstblindex = sp->header.maxslot;
+	n = xsize >> L2DTSLOTSIZE;
+	newstblsize = (n + 31) >> L2DTSLOTSIZE;
+	memcpy(&sp->slot[newstblindex], &sp->slot[oldstblindex],
+	       sp->header.nextindex);
+
+	/*
+	 * in-line extension: linelock old area of extended page
+	 */
+	if (type == tlckEXTEND) {
+		/* linelock header */
+		lv->offset = 0;
+		lv->length = 1;
+		dtlck->index++;
+		lv++;
+
+		/* linelock new stbl of extended page */
+		lv->offset = newstblindex;
+		lv->length = newstblsize;
+	}
+	/*
+	 * relocation: linelock whole relocated area
+	 */
+	else {
+		lv->offset = 0;
+		lv->length = sp->header.maxslot + newstblsize;
+	}
+
+	dtlck->index++;
+
+	sp->header.maxslot = n;
+	sp->header.stblindex = newstblindex;
+	/* sp->header.nextindex remains the same */
+
+	/*
+	 * add old stbl region at head of freelist
+	 */
+	fsi = oldstblindex;
+	f = &sp->slot[fsi];
+	last = sp->header.freelist;
+	for (n = 0; n < oldstblsize; n++, fsi++, f++) {
+		f->next = last;
+		last = fsi;
+	}
+	sp->header.freelist = last;
+	sp->header.freecnt += oldstblsize;
+
+	/*
+	 * append free region of newly extended area at tail of freelist
+	 */
+	/* init free region of newly extended area */
+	fsi = n = newstblindex + newstblsize;
+	f = &sp->slot[fsi];
+	for (fsi++; fsi < sp->header.maxslot; f++, fsi++)
+		f->next = fsi;
+	f->next = -1;
+
+	/* append new free region at tail of old freelist */
+	fsi = sp->header.freelist;
+	if (fsi == -1)
+		sp->header.freelist = n;
+	else {
+		do {
+			f = &sp->slot[fsi];
+			fsi = f->next;
+		} while (fsi != -1);
+
+		f->next = n;
+	}
+
+	sp->header.freecnt += sp->header.maxslot - n;
+
+	/*
+	 * insert the new entry
+	 */
+	dtInsertEntry(sp, split->index, split->key, split->data, &dtlck);
+
+	BT_MARK_DIRTY(pmp, ip);
+	/*
+	 * linelock any freeslots residing in old extent
+	 */
+	if (type == tlckEXTEND) {
+		n = sp->header.maxslot >> 2;
+		if (sp->header.freelist < n)
+			dtLinelockFreelist(sp, n, &dtlck);
+	}
+
+	/*
+	 *      update parent entry on the parent/root page
+	 */
+	/*
+	 * acquire a transaction lock on the parent/root page
+	 */
+	tlck = txLock(tid, ip, pmp, tlckDTREE | tlckENTRY);
+	dtlck = (struct dt_lock *) & tlck->lock;
+	lv = & dtlck->lv[dtlck->index];
+
+	/* linelock parent entry - 1st slot */
+	lv->offset = 1;
+	lv->length = 1;
+	dtlck->index++;
+
+	/* update the parent pxd for page extension */
+	tpxd = (pxd_t *) & pp->slot[1];
+	*tpxd = *pxd;
+
+	/* Since the directory might have an EA and/or ACL associated with it
+	 * we need to make sure we take that into account when setting the
+	 * i_nblocks
+	 */
+	ip->i_blocks = LBLK2PBLK(ip->i_sb, xlen +
+				 ((JFS_IP(ip)->ea.flag & DXD_EXTENT) ?
+				  lengthDXD(&JFS_IP(ip)->ea) : 0) +
+				 ((JFS_IP(ip)->acl.flag & DXD_EXTENT) ?
+				  lengthDXD(&JFS_IP(ip)->acl) : 0));
+
+	jEVENT(0,
+	       ("dtExtendPage: ip:0x%p smp:0x%p sp:0x%p\n", ip, smp, sp));
+
+
+	DT_PUTPAGE(pmp);
+	return 0;
+}
+
+
+/*
+ *	dtSplitRoot()
+ *
+ * function:
+ *	split the full root page into
+ *	original/root/split page and new right page
+ *	i.e., root remains fixed in tree anchor (inode) and
+ *	the root is copied to a single new right child page
+ *	since root page << non-root page, and
+ *	the split root page contains a single entry for the
+ *	new right child page.
+ *
+ * parameter:
+ *
+ * return: 0 - success;
+ *	   errno - failure;
+ *	return new page pinned;
+ */
+static int dtSplitRoot(tid_t tid,
+	    struct inode *ip, struct dtsplit * split, struct metapage ** rmpp)
+{
+	struct super_block *sb = ip->i_sb;
+	struct metapage *smp;
+	dtroot_t *sp;
+	struct metapage *rmp;
+	dtpage_t *rp;
+	s64 rbn;
+	int xlen;
+	int xsize;
+	struct dtslot *f;
+	s8 *stbl;
+	int fsi, stblsize, n;
+	struct idtentry *s;
+	pxd_t *ppxd;
+	struct pxdlist *pxdlist;
+	pxd_t *pxd;
+	struct dt_lock *dtlck;
+	struct tlock *tlck;
+	struct lv *lv;
+
+	/* get split root page */
+	smp = split->mp;
+	sp = &JFS_IP(ip)->i_dtroot;
+
+	/*
+	 *      allocate/initialize a single (right) child page
+	 *
+	 * N.B. at first split, a one (or two) block to fit new entry
+	 * is allocated; at subsequent split, a full page is allocated;
+	 */
+	pxdlist = split->pxdlist;
+	pxd = &pxdlist->pxd[pxdlist->npxd];
+	pxdlist->npxd++;
+	rbn = addressPXD(pxd);
+	xlen = lengthPXD(pxd);
+	xsize = xlen << JFS_SBI(sb)->l2bsize;
+	rmp = get_metapage(ip, rbn, xsize, 1);
+	rp = rmp->data;
+
+	BT_MARK_DIRTY(rmp, ip);
+	/*
+	 * acquire a transaction lock on the new right page
+	 */
+	tlck = txLock(tid, ip, rmp, tlckDTREE | tlckNEW);
+	dtlck = (struct dt_lock *) & tlck->lock;
+
+	rp->header.flag =
+	    (sp->header.flag & BT_LEAF) ? BT_LEAF : BT_INTERNAL;
+	rp->header.self = *pxd;
+
+	/* initialize sibling pointers */
+	rp->header.next = 0;
+	rp->header.prev = 0;
+
+	/*
+	 *      move in-line root page into new right page extent
+	 */
+	/* linelock header + copied entries + new stbl (1st slot) in new page */
+	ASSERT(dtlck->index == 0);
+	lv = & dtlck->lv[0];
+	lv->offset = 0;
+	lv->length = 10;	/* 1 + 8 + 1 */
+	dtlck->index++;
+
+	n = xsize >> L2DTSLOTSIZE;
+	rp->header.maxslot = n;
+	stblsize = (n + 31) >> L2DTSLOTSIZE;
+
+	/* copy old stbl to new stbl at start of extended area */
+	rp->header.stblindex = DTROOTMAXSLOT;
+	stbl = (s8 *) & rp->slot[DTROOTMAXSLOT];
+	memcpy(stbl, sp->header.stbl, sp->header.nextindex);
+	rp->header.nextindex = sp->header.nextindex;
+
+	/* copy old data area to start of new data area */
+	memcpy(&rp->slot[1], &sp->slot[1], IDATASIZE);
+
+	/*
+	 * append free region of newly extended area at tail of freelist
+	 */
+	/* init free region of newly extended area */
+	fsi = n = DTROOTMAXSLOT + stblsize;
+	f = &rp->slot[fsi];
+	for (fsi++; fsi < rp->header.maxslot; f++, fsi++)
+		f->next = fsi;
+	f->next = -1;
+
+	/* append new free region at tail of old freelist */
+	fsi = sp->header.freelist;
+	if (fsi == -1)
+		rp->header.freelist = n;
+	else {
+		rp->header.freelist = fsi;
+
+		do {
+			f = &rp->slot[fsi];
+			fsi = f->next;
+		} while (fsi != -1);
+
+		f->next = n;
+	}
+
+	rp->header.freecnt = sp->header.freecnt + rp->header.maxslot - n;
+
+	/*
+	 * Update directory index table for entries now in right page
+	 */
+	if ((rp->header.flag & BT_LEAF) && DO_INDEX(ip)) {
+		struct metapage *mp = 0;
+		struct ldtentry *ldtentry;
+
+		stbl = DT_GETSTBL(rp);
+		for (n = 0; n < rp->header.nextindex; n++) {
+			ldtentry = (struct ldtentry *) & rp->slot[stbl[n]];
+			modify_index(tid, ip, le32_to_cpu(ldtentry->index),
+				     rbn, n, &mp);
+		}
+		if (mp)
+			release_metapage(mp);
+	}
+	/*
+	 * insert the new entry into the new right/child page
+	 * (skip index in the new right page will not change)
+	 */
+	dtInsertEntry(rp, split->index, split->key, split->data, &dtlck);
+
+	/*
+	 *      reset parent/root page
+	 *
+	 * set the 1st entry offset to 0, which force the left-most key
+	 * at any level of the tree to be less than any search key.
+	 *
+	 * The btree comparison code guarantees that the left-most key on any
+	 * level of the tree is never used, so it doesn't need to be filled in.
+	 */
+	BT_MARK_DIRTY(smp, ip);
+	/*
+	 * acquire a transaction lock on the root page (in-memory inode)
+	 */
+	tlck = txLock(tid, ip, smp, tlckDTREE | tlckNEW | tlckBTROOT);
+	dtlck = (struct dt_lock *) & tlck->lock;
+
+	/* linelock root */
+	ASSERT(dtlck->index == 0);
+	lv = & dtlck->lv[0];
+	lv->offset = 0;
+	lv->length = DTROOTMAXSLOT;
+	dtlck->index++;
+
+	/* update page header of root */
+	if (sp->header.flag & BT_LEAF) {
+		sp->header.flag &= ~BT_LEAF;
+		sp->header.flag |= BT_INTERNAL;
+	}
+
+	/* init the first entry */
+	s = (struct idtentry *) & sp->slot[DTENTRYSTART];
+	ppxd = (pxd_t *) s;
+	*ppxd = *pxd;
+	s->next = -1;
+	s->namlen = 0;
+
+	stbl = sp->header.stbl;
+	stbl[0] = DTENTRYSTART;
+	sp->header.nextindex = 1;
+
+	/* init freelist */
+	fsi = DTENTRYSTART + 1;
+	f = &sp->slot[fsi];
+
+	/* init free region of remaining area */
+	for (fsi++; fsi < DTROOTMAXSLOT; f++, fsi++)
+		f->next = fsi;
+	f->next = -1;
+
+	sp->header.freelist = DTENTRYSTART + 1;
+	sp->header.freecnt = DTROOTMAXSLOT - (DTENTRYSTART + 1);
+
+	*rmpp = rmp;
+
+	ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd));
+	return 0;
+}
+
+
+/*
+ *	dtDelete()
+ *
+ * function: delete the entry(s) referenced by a key.
+ *
+ * parameter:
+ *
+ * return:
+ */
+int dtDelete(tid_t tid,
+	 struct inode *ip, struct component_name * key, ino_t * ino, int flag)
+{
+	int rc = 0;
+	s64 bn;
+	struct metapage *mp, *imp;
+	dtpage_t *p;
+	int index;
+	struct btstack btstack;
+	struct dt_lock *dtlck;
+	struct tlock *tlck;
+	struct lv *lv;
+	int i;
+	struct ldtentry *ldtentry;
+	u8 *stbl;
+	u32 table_index, next_index;
+	struct metapage *nmp;
+	dtpage_t *np;
+
+	/*
+	 *      search for the entry to delete:
+	 *
+	 * dtSearch() returns (leaf page pinned, index at which to delete).
+	 */
+	if ((rc = dtSearch(ip, key, ino, &btstack, flag)))
+		return rc;
+
+	/* retrieve search result */
+	DT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+	/*
+	 * We need to find put the index of the next entry into the
+	 * directory index table in order to resume a readdir from this
+	 * entry.
+	 */
+	if (DO_INDEX(ip)) {
+		stbl = DT_GETSTBL(p);
+		ldtentry = (struct ldtentry *) & p->slot[stbl[index]];
+		table_index = le32_to_cpu(ldtentry->index);
+		if (index == (p->header.nextindex - 1)) {
+			/*
+			 * Last entry in this leaf page
+			 */
+			if ((p->header.flag & BT_ROOT)
+			    || (p->header.next == 0))
+				next_index = -1;
+			else {
+				/* Read next leaf page */
+				DT_GETPAGE(ip, le64_to_cpu(p->header.next),
+					   nmp, PSIZE, np, rc);
+				if (rc)
+					next_index = -1;
+				else {
+					stbl = DT_GETSTBL(np);
+					ldtentry =
+					    (struct ldtentry *) & np->
+					    slot[stbl[0]];
+					next_index =
+					    le32_to_cpu(ldtentry->index);
+					DT_PUTPAGE(nmp);
+				}
+			}
+		} else {
+			ldtentry =
+			    (struct ldtentry *) & p->slot[stbl[index + 1]];
+			next_index = le32_to_cpu(ldtentry->index);
+		}
+		free_index(tid, ip, table_index, next_index);
+	}
+	/*
+	 * the leaf page becomes empty, delete the page
+	 */
+	if (p->header.nextindex == 1) {
+		/* delete empty page */
+		rc = dtDeleteUp(tid, ip, mp, p, &btstack);
+	}
+	/*
+	 * the leaf page has other entries remaining:
+	 *
+	 * delete the entry from the leaf page.
+	 */
+	else {
+		BT_MARK_DIRTY(mp, ip);
+		/*
+		 * acquire a transaction lock on the leaf page
+		 */
+		tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+		dtlck = (struct dt_lock *) & tlck->lock;
+
+		/*
+		 * Do not assume that dtlck->index will be zero.  During a
+		 * rename within a directory, this transaction may have
+		 * modified this page already when adding the new entry.
+		 */
+
+		/* linelock header */
+		if (dtlck->index >= dtlck->maxcnt)
+			dtlck = (struct dt_lock *) txLinelock(dtlck);
+		lv = & dtlck->lv[dtlck->index];
+		lv->offset = 0;
+		lv->length = 1;
+		dtlck->index++;
+
+		/* linelock stbl of non-root leaf page */
+		if (!(p->header.flag & BT_ROOT)) {
+			if (dtlck->index >= dtlck->maxcnt)
+				dtlck = (struct dt_lock *) txLinelock(dtlck);
+			lv = & dtlck->lv[dtlck->index];
+			i = index >> L2DTSLOTSIZE;
+			lv->offset = p->header.stblindex + i;
+			lv->length =
+			    ((p->header.nextindex - 1) >> L2DTSLOTSIZE) -
+			    i + 1;
+			dtlck->index++;
+		}
+
+		/* free the leaf entry */
+		dtDeleteEntry(p, index, &dtlck);
+
+		/*
+		 * Update directory index table for entries moved in stbl
+		 */
+		if (DO_INDEX(ip) && index < p->header.nextindex) {
+			imp = 0;
+			stbl = DT_GETSTBL(p);
+			for (i = index; i < p->header.nextindex; i++) {
+				ldtentry =
+				    (struct ldtentry *) & p->slot[stbl[i]];
+				modify_index(tid, ip,
+					     le32_to_cpu(ldtentry->index),
+					     bn, i, &imp);
+			}
+			if (imp)
+				release_metapage(imp);
+		}
+
+		DT_PUTPAGE(mp);
+	}
+
+	return rc;
+}
+
+
+/*
+ *	dtDeleteUp()
+ *
+ * function:
+ *	free empty pages as propagating deletion up the tree
+ *
+ * parameter:
+ *
+ * return:
+ */
+static int dtDeleteUp(tid_t tid, struct inode *ip,
+	   struct metapage * fmp, dtpage_t * fp, struct btstack * btstack)
+{
+	int rc = 0;
+	struct metapage *mp;
+	dtpage_t *p;
+	int index, nextindex;
+	int xlen;
+	struct btframe *parent;
+	struct dt_lock *dtlck;
+	struct tlock *tlck;
+	struct lv *lv;
+	struct pxd_lock *pxdlock;
+	int i;
+
+	/*
+	 *      keep the root leaf page which has become empty
+	 */
+	if (BT_IS_ROOT(fmp)) {
+		/*
+		 * reset the root
+		 *
+		 * dtInitRoot() acquires txlock on the root
+		 */
+		dtInitRoot(tid, ip, PARENT(ip));
+
+		DT_PUTPAGE(fmp);
+
+		return 0;
+	}
+
+	/*
+	 *      free the non-root leaf page
+	 */
+	/*
+	 * acquire a transaction lock on the page
+	 *
+	 * write FREEXTENT|NOREDOPAGE log record
+	 * N.B. linelock is overlaid as freed extent descriptor, and
+	 * the buffer page is freed;
+	 */
+	tlck = txMaplock(tid, ip, tlckDTREE | tlckFREE);
+	pxdlock = (struct pxd_lock *) & tlck->lock;
+	pxdlock->flag = mlckFREEPXD;
+	pxdlock->pxd = fp->header.self;
+	pxdlock->index = 1;
+
+	/* update sibling pointers */
+	if ((rc = dtRelink(tid, ip, fp)))
+		return rc;
+
+	xlen = lengthPXD(&fp->header.self);
+	ip->i_blocks -= LBLK2PBLK(ip->i_sb, xlen);
+
+	/* free/invalidate its buffer page */
+	discard_metapage(fmp);
+
+	/*
+	 *      propagate page deletion up the directory tree
+	 *
+	 * If the delete from the parent page makes it empty,
+	 * continue all the way up the tree.
+	 * stop if the root page is reached (which is never deleted) or
+	 * if the entry deletion does not empty the page.
+	 */
+	while ((parent = BT_POP(btstack)) != NULL) {
+		/* pin the parent page <sp> */
+		DT_GETPAGE(ip, parent->bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		/*
+		 * free the extent of the child page deleted
+		 */
+		index = parent->index;
+
+		/*
+		 * delete the entry for the child page from parent
+		 */
+		nextindex = p->header.nextindex;
+
+		/*
+		 * the parent has the single entry being deleted:
+		 *
+		 * free the parent page which has become empty.
+		 */
+		if (nextindex == 1) {
+			/*
+			 * keep the root internal page which has become empty
+			 */
+			if (p->header.flag & BT_ROOT) {
+				/*
+				 * reset the root
+				 *
+				 * dtInitRoot() acquires txlock on the root
+				 */
+				dtInitRoot(tid, ip, PARENT(ip));
+
+				DT_PUTPAGE(mp);
+
+				return 0;
+			}
+			/*
+			 * free the parent page
+			 */
+			else {
+				/*
+				 * acquire a transaction lock on the page
+				 *
+				 * write FREEXTENT|NOREDOPAGE log record
+				 */
+				tlck =
+				    txMaplock(tid, ip,
+					      tlckDTREE | tlckFREE);
+				pxdlock = (struct pxd_lock *) & tlck->lock;
+				pxdlock->flag = mlckFREEPXD;
+				pxdlock->pxd = p->header.self;
+				pxdlock->index = 1;
+
+				/* update sibling pointers */
+				if ((rc = dtRelink(tid, ip, p)))
+					return rc;
+
+				xlen = lengthPXD(&p->header.self);
+				ip->i_blocks -= LBLK2PBLK(ip->i_sb, xlen);
+
+				/* free/invalidate its buffer page */
+				discard_metapage(mp);
+
+				/* propagate up */
+				continue;
+			}
+		}
+
+		/*
+		 * the parent has other entries remaining:
+		 *
+		 * delete the router entry from the parent page.
+		 */
+		BT_MARK_DIRTY(mp, ip);
+		/*
+		 * acquire a transaction lock on the page
+		 *
+		 * action: router entry deletion
+		 */
+		tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+		dtlck = (struct dt_lock *) & tlck->lock;
+
+		/* linelock header */
+		if (dtlck->index >= dtlck->maxcnt)
+			dtlck = (struct dt_lock *) txLinelock(dtlck);
+		lv = & dtlck->lv[dtlck->index];
+		lv->offset = 0;
+		lv->length = 1;
+		dtlck->index++;
+
+		/* linelock stbl of non-root leaf page */
+		if (!(p->header.flag & BT_ROOT)) {
+			if (dtlck->index < dtlck->maxcnt)
+				lv++;
+			else {
+				dtlck = (struct dt_lock *) txLinelock(dtlck);
+				lv = & dtlck->lv[0];
+			}
+			i = index >> L2DTSLOTSIZE;
+			lv->offset = p->header.stblindex + i;
+			lv->length =
+			    ((p->header.nextindex - 1) >> L2DTSLOTSIZE) -
+			    i + 1;
+			dtlck->index++;
+		}
+
+		/* free the router entry */
+		dtDeleteEntry(p, index, &dtlck);
+
+		/* reset key of new leftmost entry of level (for consistency) */
+		if (index == 0 &&
+		    ((p->header.flag & BT_ROOT) || p->header.prev == 0))
+			dtTruncateEntry(p, 0, &dtlck);
+
+		/* unpin the parent page */
+		DT_PUTPAGE(mp);
+
+		/* exit propagation up */
+		break;
+	}
+
+	return 0;
+}
+
+
+/*
+ * NAME:        dtRelocate()
+ *
+ * FUNCTION:    relocate dtpage (internal or leaf) of directory;
+ *              This function is mainly used by defragfs utility.
+ */
+int dtRelocate(tid_t tid, struct inode *ip, s64 lmxaddr, pxd_t * opxd,
+	       s64 nxaddr)
+{
+	int rc = 0;
+	struct metapage *mp, *pmp, *lmp, *rmp;
+	dtpage_t *p, *pp, *rp = 0, *lp= 0;
+	s64 bn;
+	int index;
+	struct btstack btstack;
+	pxd_t *pxd;
+	s64 oxaddr, nextbn, prevbn;
+	int xlen, xsize;
+	struct tlock *tlck;
+	struct dt_lock *dtlck;
+	struct pxd_lock *pxdlock;
+	s8 *stbl;
+	struct lv *lv;
+
+	oxaddr = addressPXD(opxd);
+	xlen = lengthPXD(opxd);
+
+	jEVENT(0, ("dtRelocate: lmxaddr:%Ld xaddr:%Ld:%Ld xlen:%d\n",
+		   (long long)lmxaddr, (long long)oxaddr, (long long)nxaddr,
+		   xlen));
+
+	/*
+	 *      1. get the internal parent dtpage covering
+	 *      router entry for the tartget page to be relocated;
+	 */
+	rc = dtSearchNode(ip, lmxaddr, opxd, &btstack);
+	if (rc)
+		return rc;
+
+	/* retrieve search result */
+	DT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
+	jEVENT(0, ("dtRelocate: parent router entry validated.\n"));
+
+	/*
+	 *      2. relocate the target dtpage
+	 */
+	/* read in the target page from src extent */
+	DT_GETPAGE(ip, oxaddr, mp, PSIZE, p, rc);
+	if (rc) {
+		/* release the pinned parent page */
+		DT_PUTPAGE(pmp);
+		return rc;
+	}
+
+	/*
+	 * read in sibling pages if any to update sibling pointers;
+	 */
+	rmp = NULL;
+	if (p->header.next) {
+		nextbn = le64_to_cpu(p->header.next);
+		DT_GETPAGE(ip, nextbn, rmp, PSIZE, rp, rc);
+		if (rc) {
+			DT_PUTPAGE(mp);
+			DT_PUTPAGE(pmp);
+			return (rc);
+		}
+	}
+
+	lmp = NULL;
+	if (p->header.prev) {
+		prevbn = le64_to_cpu(p->header.prev);
+		DT_GETPAGE(ip, prevbn, lmp, PSIZE, lp, rc);
+		if (rc) {
+			DT_PUTPAGE(mp);
+			DT_PUTPAGE(pmp);
+			if (rmp)
+				DT_PUTPAGE(rmp);
+			return (rc);
+		}
+	}
+
+	/* at this point, all xtpages to be updated are in memory */
+
+	/*
+	 * update sibling pointers of sibling dtpages if any;
+	 */
+	if (lmp) {
+		tlck = txLock(tid, ip, lmp, tlckDTREE | tlckRELINK);
+		dtlck = (struct dt_lock *) & tlck->lock;
+		/* linelock header */
+		ASSERT(dtlck->index == 0);
+		lv = & dtlck->lv[0];
+		lv->offset = 0;
+		lv->length = 1;
+		dtlck->index++;
+
+		lp->header.next = cpu_to_le64(nxaddr);
+		DT_PUTPAGE(lmp);
+	}
+
+	if (rmp) {
+		tlck = txLock(tid, ip, rmp, tlckDTREE | tlckRELINK);
+		dtlck = (struct dt_lock *) & tlck->lock;
+		/* linelock header */
+		ASSERT(dtlck->index == 0);
+		lv = & dtlck->lv[0];
+		lv->offset = 0;
+		lv->length = 1;
+		dtlck->index++;
+
+		rp->header.prev = cpu_to_le64(nxaddr);
+		DT_PUTPAGE(rmp);
+	}
+
+	/*
+	 * update the target dtpage to be relocated
+	 *
+	 * write LOG_REDOPAGE of LOG_NEW type for dst page
+	 * for the whole target page (logredo() will apply
+	 * after image and update bmap for allocation of the
+	 * dst extent), and update bmap for allocation of
+	 * the dst extent;
+	 */
+	tlck = txLock(tid, ip, mp, tlckDTREE | tlckNEW);
+	dtlck = (struct dt_lock *) & tlck->lock;
+	/* linelock header */
+	ASSERT(dtlck->index == 0);
+	lv = & dtlck->lv[0];
+
+	/* update the self address in the dtpage header */
+	pxd = &p->header.self;
+	PXDaddress(pxd, nxaddr);
+
+	/* the dst page is the same as the src page, i.e.,
+	 * linelock for afterimage of the whole page;
+	 */
+	lv->offset = 0;
+	lv->length = p->header.maxslot;
+	dtlck->index++;
+
+	/* update the buffer extent descriptor of the dtpage */
+	xsize = xlen << JFS_SBI(ip->i_sb)->l2bsize;
+#ifdef _STILL_TO_PORT
+	bmSetXD(mp, nxaddr, xsize);
+#endif /* _STILL_TO_PORT */
+	/* unpin the relocated page */
+	DT_PUTPAGE(mp);
+	jEVENT(0, ("dtRelocate: target dtpage relocated.\n"));
+
+	/* the moved extent is dtpage, then a LOG_NOREDOPAGE log rec
+	 * needs to be written (in logredo(), the LOG_NOREDOPAGE log rec
+	 * will also force a bmap update ).
+	 */
+
+	/*
+	 *      3. acquire maplock for the source extent to be freed;
+	 */
+	/* for dtpage relocation, write a LOG_NOREDOPAGE record
+	 * for the source dtpage (logredo() will init NoRedoPage
+	 * filter and will also update bmap for free of the source
+	 * dtpage), and upadte bmap for free of the source dtpage;
+	 */
+	tlck = txMaplock(tid, ip, tlckDTREE | tlckFREE);
+	pxdlock = (struct pxd_lock *) & tlck->lock;
+	pxdlock->flag = mlckFREEPXD;
+	PXDaddress(&pxdlock->pxd, oxaddr);
+	PXDlength(&pxdlock->pxd, xlen);
+	pxdlock->index = 1;
+
+	/*
+	 *      4. update the parent router entry for relocation;
+	 *
+	 * acquire tlck for the parent entry covering the target dtpage;
+	 * write LOG_REDOPAGE to apply after image only;
+	 */
+	jEVENT(0, ("dtRelocate: update parent router entry.\n"));
+	tlck = txLock(tid, ip, pmp, tlckDTREE | tlckENTRY);
+	dtlck = (struct dt_lock *) & tlck->lock;
+	lv = & dtlck->lv[dtlck->index];
+
+	/* update the PXD with the new address */
+	stbl = DT_GETSTBL(pp);
+	pxd = (pxd_t *) & pp->slot[stbl[index]];
+	PXDaddress(pxd, nxaddr);
+	lv->offset = stbl[index];
+	lv->length = 1;
+	dtlck->index++;
+
+	/* unpin the parent dtpage */
+	DT_PUTPAGE(pmp);
+
+	return rc;
+}
+
+
+/*
+ * NAME:	dtSearchNode()
+ *
+ * FUNCTION:	Search for an dtpage containing a specified address
+ *              This function is mainly used by defragfs utility.
+ *
+ * NOTE:	Search result on stack, the found page is pinned at exit.
+ *		The result page must be an internal dtpage.
+ *		lmxaddr give the address of the left most page of the
+ *		dtree level, in which the required dtpage resides.
+ */
+static int dtSearchNode(struct inode *ip, s64 lmxaddr, pxd_t * kpxd,
+			struct btstack * btstack)
+{
+	int rc = 0;
+	s64 bn;
+	struct metapage *mp;
+	dtpage_t *p;
+	int psize = 288;	/* initial in-line directory */
+	s8 *stbl;
+	int i;
+	pxd_t *pxd;
+	struct btframe *btsp;
+
+	BT_CLR(btstack);	/* reset stack */
+
+	/*
+	 *      descend tree to the level with specified leftmost page
+	 *
+	 *  by convention, root bn = 0.
+	 */
+	for (bn = 0;;) {
+		/* get/pin the page to search */
+		DT_GETPAGE(ip, bn, mp, psize, p, rc);
+		if (rc)
+			return rc;
+
+		/* does the xaddr of leftmost page of the levevl
+		 * matches levevl search key ?
+		 */
+		if (p->header.flag & BT_ROOT) {
+			if (lmxaddr == 0)
+				break;
+		} else if (addressPXD(&p->header.self) == lmxaddr)
+			break;
+
+		/*
+		 * descend down to leftmost child page
+		 */
+		if (p->header.flag & BT_LEAF)
+			return ESTALE;
+
+		/* get the leftmost entry */
+		stbl = DT_GETSTBL(p);
+		pxd = (pxd_t *) & p->slot[stbl[0]];
+
+		/* get the child page block address */
+		bn = addressPXD(pxd);
+		psize = lengthPXD(pxd) << JFS_SBI(ip->i_sb)->l2bsize;
+		/* unpin the parent page */
+		DT_PUTPAGE(mp);
+	}
+
+	/*
+	 *      search each page at the current levevl
+	 */
+      loop:
+	stbl = DT_GETSTBL(p);
+	for (i = 0; i < p->header.nextindex; i++) {
+		pxd = (pxd_t *) & p->slot[stbl[i]];
+
+		/* found the specified router entry */
+		if (addressPXD(pxd) == addressPXD(kpxd) &&
+		    lengthPXD(pxd) == lengthPXD(kpxd)) {
+			btsp = btstack->top;
+			btsp->bn = bn;
+			btsp->index = i;
+			btsp->mp = mp;
+
+			return 0;
+		}
+	}
+
+	/* get the right sibling page if any */
+	if (p->header.next)
+		bn = le64_to_cpu(p->header.next);
+	else {
+		DT_PUTPAGE(mp);
+		return ESTALE;
+	}
+
+	/* unpin current page */
+	DT_PUTPAGE(mp);
+
+	/* get the right sibling page */
+	DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return rc;
+
+	goto loop;
+}
+
+
+/*
+ *	dtRelink()
+ *
+ * function:
+ *	link around a freed page.
+ *
+ * parameter:
+ *	fp:	page to be freed
+ *
+ * return:
+ */
+static int dtRelink(tid_t tid, struct inode *ip, dtpage_t * p)
+{
+	int rc;
+	struct metapage *mp;
+	s64 nextbn, prevbn;
+	struct tlock *tlck;
+	struct dt_lock *dtlck;
+	struct lv *lv;
+
+	nextbn = le64_to_cpu(p->header.next);
+	prevbn = le64_to_cpu(p->header.prev);
+
+	/* update prev pointer of the next page */
+	if (nextbn != 0) {
+		DT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		BT_MARK_DIRTY(mp, ip);
+		/*
+		 * acquire a transaction lock on the next page
+		 *
+		 * action: update prev pointer;
+		 */
+		tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK);
+		jEVENT(0,
+		       ("dtRelink nextbn: tlck = 0x%p, ip = 0x%p, mp=0x%p\n",
+			tlck, ip, mp));
+		dtlck = (struct dt_lock *) & tlck->lock;
+
+		/* linelock header */
+		if (dtlck->index >= dtlck->maxcnt)
+			dtlck = (struct dt_lock *) txLinelock(dtlck);
+		lv = & dtlck->lv[dtlck->index];
+		lv->offset = 0;
+		lv->length = 1;
+		dtlck->index++;
+
+		p->header.prev = cpu_to_le64(prevbn);
+		DT_PUTPAGE(mp);
+	}
+
+	/* update next pointer of the previous page */
+	if (prevbn != 0) {
+		DT_GETPAGE(ip, prevbn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		BT_MARK_DIRTY(mp, ip);
+		/*
+		 * acquire a transaction lock on the prev page
+		 *
+		 * action: update next pointer;
+		 */
+		tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK);
+		jEVENT(0,
+		       ("dtRelink prevbn: tlck = 0x%p, ip = 0x%p, mp=0x%p\n",
+			tlck, ip, mp));
+		dtlck = (struct dt_lock *) & tlck->lock;
+
+		/* linelock header */
+		if (dtlck->index >= dtlck->maxcnt)
+			dtlck = (struct dt_lock *) txLinelock(dtlck);
+		lv = & dtlck->lv[dtlck->index];
+		lv->offset = 0;
+		lv->length = 1;
+		dtlck->index++;
+
+		p->header.next = cpu_to_le64(nextbn);
+		DT_PUTPAGE(mp);
+	}
+
+	return 0;
+}
+
+
+/*
+ *	dtInitRoot()
+ *
+ * initialize directory root (inline in inode)
+ */
+void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot)
+{
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	dtroot_t *p;
+	int fsi;
+	struct dtslot *f;
+	struct tlock *tlck;
+	struct dt_lock *dtlck;
+	struct lv *lv;
+	u16 xflag_save;
+
+	/*
+	 * If this was previously an non-empty directory, we need to remove
+	 * the old directory table.
+	 */
+	if (DO_INDEX(ip)) {
+		if (jfs_ip->next_index > (MAX_INLINE_DIRTABLE_ENTRY + 1)) {
+			struct tblock *tblk = tid_to_tblock(tid);
+			/*
+			 * We're playing games with the tid's xflag.  If
+			 * we're removing a regular file, the file's xtree
+			 * is committed with COMMIT_PMAP, but we always
+			 * commit the directories xtree with COMMIT_PWMAP.
+			 */
+			xflag_save = tblk->xflag;
+			tblk->xflag = 0;
+			/*
+			 * xtTruncate isn't guaranteed to fully truncate
+			 * the xtree.  The caller needs to check i_size
+			 * after committing the transaction to see if
+			 * additional truncation is needed.  The
+			 * COMMIT_Stale flag tells caller that we
+			 * initiated the truncation.
+			 */
+			xtTruncate(tid, ip, 0, COMMIT_PWMAP);
+			set_cflag(COMMIT_Stale, ip);
+
+			tblk->xflag = xflag_save;
+			/*
+			 * Tells jfs_metapage code that the metadata pages
+			 * for the index table are no longer useful, and
+			 * remove them from page cache.
+			 */
+			invalidate_inode_metapages(ip);
+		} else
+			ip->i_size = 1;
+
+		jfs_ip->next_index = 2;
+	} else
+		ip->i_size = IDATASIZE;
+
+	/*
+	 * acquire a transaction lock on the root
+	 *
+	 * action: directory initialization;
+	 */
+	tlck = txLock(tid, ip, (struct metapage *) & jfs_ip->bxflag,
+		      tlckDTREE | tlckENTRY | tlckBTROOT);
+	dtlck = (struct dt_lock *) & tlck->lock;
+
+	/* linelock root */
+	ASSERT(dtlck->index == 0);
+	lv = & dtlck->lv[0];
+	lv->offset = 0;
+	lv->length = DTROOTMAXSLOT;
+	dtlck->index++;
+
+	p = &jfs_ip->i_dtroot;
+
+	p->header.flag = DXD_INDEX | BT_ROOT | BT_LEAF;
+
+	p->header.nextindex = 0;
+
+	/* init freelist */
+	fsi = 1;
+	f = &p->slot[fsi];
+
+	/* init data area of root */
+	for (fsi++; fsi < DTROOTMAXSLOT; f++, fsi++)
+		f->next = fsi;
+	f->next = -1;
+
+	p->header.freelist = 1;
+	p->header.freecnt = 8;
+
+	/* init '..' entry */
+	p->header.idotdot = cpu_to_le32(idotdot);
+
+#if 0
+	ip->i_blocks = LBLK2PBLK(ip->i_sb,
+				 ((jfs_ip->ea.flag & DXD_EXTENT) ?
+				  lengthDXD(&jfs_ip->ea) : 0) +
+				 ((jfs_ip->acl.flag & DXD_EXTENT) ?
+				  lengthDXD(&jfs_ip->acl) : 0));
+#endif
+
+	return;
+}
+
+/*
+ *	add_missing_indices()
+ *
+ * function: Fix dtree page in which one or more entries has an invalid index.
+ *	     fsck.jfs should really fix this, but it currently does not.
+ *	     Called from jfs_readdir when bad index is detected.
+ */
+static void add_missing_indices(struct inode *inode, s64 bn)
+{
+	struct ldtentry *d;
+	struct dt_lock *dtlck;
+	int i;
+	uint index;
+	struct lv *lv;
+	struct metapage *mp;
+	dtpage_t *p;
+	int rc;
+	s8 *stbl;
+	tid_t tid;
+	struct tlock *tlck;
+
+	tid = txBegin(inode->i_sb, 0);
+
+	DT_GETPAGE(inode, bn, mp, PSIZE, p, rc);
+
+	if (rc) {
+		printk(KERN_ERR "DT_GETPAGE failed!\n");
+		goto end;
+	}
+	BT_MARK_DIRTY(mp, inode);
+
+	ASSERT(p->header.flag & BT_LEAF);
+
+	tlck = txLock(tid, inode, mp, tlckDTREE | tlckENTRY);
+	dtlck = (struct dt_lock *) &tlck->lock;
+
+	stbl = DT_GETSTBL(p);
+	for (i = 0; i < p->header.nextindex; i++) {
+		d = (struct ldtentry *) &p->slot[stbl[i]];
+		index = le32_to_cpu(d->index);
+		if ((index < 2) || (index >= JFS_IP(inode)->next_index)) {
+			d->index = cpu_to_le32(add_index(tid, inode, bn, i));
+			if (dtlck->index >= dtlck->maxcnt)
+				dtlck = (struct dt_lock *) txLinelock(dtlck);
+			lv = dtlck->lv;
+			lv->offset = stbl[i];
+			lv->length = 1;
+			dtlck->index++;
+		}
+	}
+
+	DT_PUTPAGE(mp);
+	(void) txCommit(tid, 1, &inode, 0);
+end:
+	txEnd(tid);
+}
+
+/*
+ * Buffer to hold directory entry info while traversing a dtree page
+ * before being fed to the filldir function
+ */
+struct jfs_dirent {
+	loff_t position;
+	int ino;
+	u16 name_len;
+	char name[0];
+};
+
+/*
+ * function to determine next variable-sized jfs_dirent in buffer
+ */
+inline struct jfs_dirent *next_jfs_dirent(struct jfs_dirent *dirent)
+{
+	return (struct jfs_dirent *)
+		((char *)dirent +
+		 ((sizeof (struct jfs_dirent) + dirent->name_len + 1 +
+		   sizeof (loff_t) - 1) &
+		  ~(sizeof (loff_t) - 1)));
+}
+
+/*
+ *	jfs_readdir()
+ *
+ * function: read directory entries sequentially
+ *	from the specified entry offset
+ *
+ * parameter:
+ *
+ * return: offset = (pn, index) of start entry
+ *	of next jfs_readdir()/dtRead()
+ */
+int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+	struct inode *ip = filp->f_dentry->d_inode;
+	struct nls_table *codepage = JFS_SBI(ip->i_sb)->nls_tab;
+	int rc = 0;
+	loff_t dtpos;	/* legacy OS/2 style position */
+	struct dtoffset {
+		s16 pn;
+		s16 index;
+		s32 unused;
+	} *dtoffset = (struct dtoffset *) &dtpos;
+	s64 bn;
+	struct metapage *mp;
+	dtpage_t *p;
+	int index;
+	s8 *stbl;
+	struct btstack btstack;
+	int i, next;
+	struct ldtentry *d;
+	struct dtslot *t;
+	int d_namleft, len, outlen;
+	unsigned long dirent_buf;
+	char *name_ptr;
+	int dtlhdrdatalen;
+	u32 dir_index;
+	int do_index = 0;
+	uint loop_count = 0;
+	struct jfs_dirent *jfs_dirent;
+	int jfs_dirents;
+	int overflow, fix_page, page_fixed = 0;
+	static int unique_pos = 2;	/* If we can't fix broken index */
+
+	if (filp->f_pos == DIREND)
+		return 0;
+
+	if (DO_INDEX(ip)) {
+		/*
+		 * persistent index is stored in directory entries.
+		 * Special cases:        0 = .
+		 *                       1 = ..
+		 *                      -1 = End of directory
+		 */
+		do_index = 1;
+		dtlhdrdatalen = DTLHDRDATALEN;
+
+		dir_index = (u32) filp->f_pos;
+
+		if (dir_index > 1) {
+			struct dir_table_slot dirtab_slot;
+
+			if (dtEmpty(ip) ||
+			    (dir_index >= JFS_IP(ip)->next_index)) {
+				/* Stale position.  Directory has shrunk */
+				filp->f_pos = DIREND;
+				return 0;
+			}
+		      repeat:
+			rc = read_index(ip, dir_index, &dirtab_slot);
+			if (rc) {
+				filp->f_pos = DIREND;
+				return rc;
+			}
+			if (dirtab_slot.flag == DIR_INDEX_FREE) {
+				if (loop_count++ > JFS_IP(ip)->next_index) {
+					jERROR(1, ("jfs_readdir detected "
+						   "infinite loop!\n"));
+					filp->f_pos = DIREND;
+					return 0;
+				}
+				dir_index = le32_to_cpu(dirtab_slot.addr2);
+				if (dir_index == -1) {
+					filp->f_pos = DIREND;
+					return 0;
+				}
+				goto repeat;
+			}
+			bn = addressDTS(&dirtab_slot);
+			index = dirtab_slot.slot;
+			DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+			if (rc) {
+				filp->f_pos = DIREND;
+				return 0;
+			}
+			if (p->header.flag & BT_INTERNAL) {
+				jERROR(1,("jfs_readdir: bad index table\n"));
+				DT_PUTPAGE(mp);
+				filp->f_pos = -1;
+				return 0;
+			}
+		} else {
+			if (dir_index == 0) {
+				/*
+				 * self "."
+				 */
+				filp->f_pos = 0;
+				if (filldir(dirent, ".", 1, 0, ip->i_ino,
+					    DT_DIR))
+					return 0;
+			}
+			/*
+			 * parent ".."
+			 */
+			filp->f_pos = 1;
+			if (filldir(dirent, "..", 2, 1, PARENT(ip), DT_DIR))
+				return 0;
+
+			/*
+			 * Find first entry of left-most leaf
+			 */
+			if (dtEmpty(ip)) {
+				filp->f_pos = DIREND;
+				return 0;
+			}
+
+			if ((rc = dtReadFirst(ip, &btstack)))
+				return -rc;
+
+			DT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+		}
+	} else {
+		/*
+		 * Legacy filesystem - OS/2 & Linux JFS < 0.3.6
+		 *
+		 * pn = index = 0:      First entry "."
+		 * pn = 0; index = 1:   Second entry ".."
+		 * pn > 0:              Real entries, pn=1 -> leftmost page
+		 * pn = index = -1:     No more entries
+		 */
+		dtlhdrdatalen = DTLHDRDATALEN_LEGACY;
+
+		dtpos = filp->f_pos;
+		if (dtpos == 0) {
+			/* build "." entry */
+
+			if (filldir(dirent, ".", 1, filp->f_pos, ip->i_ino,
+				    DT_DIR))
+				return 0;
+			dtoffset->index = 1;
+			filp->f_pos = dtpos;
+		}
+
+		if (dtoffset->pn == 0) {
+			if (dtoffset->index == 1) {
+				/* build ".." entry */
+
+				if (filldir(dirent, "..", 2, filp->f_pos,
+					    PARENT(ip), DT_DIR))
+					return 0;
+			} else {
+				jERROR(1,
+				       ("jfs_readdir called with invalid offset!\n"));
+			}
+			dtoffset->pn = 1;
+			dtoffset->index = 0;
+			filp->f_pos = dtpos;
+		}
+
+		if (dtEmpty(ip)) {
+			filp->f_pos = DIREND;
+			return 0;
+		}
+
+		if ((rc = dtReadNext(ip, &filp->f_pos, &btstack))) {
+			jERROR(1,
+			       ("jfs_readdir: unexpected rc = %d from dtReadNext\n",
+				rc));
+			filp->f_pos = DIREND;
+			return 0;
+		}
+		/* get start leaf page and index */
+		DT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+		/* offset beyond directory eof ? */
+		if (bn < 0) {
+			filp->f_pos = DIREND;
+			return 0;
+		}
+	}
+
+	dirent_buf = __get_free_page(GFP_KERNEL);
+	if (dirent_buf == 0) {
+		DT_PUTPAGE(mp);
+		jERROR(1, ("jfs_readdir: __get_free_page failed!\n"));
+		filp->f_pos = DIREND;
+		return -ENOMEM;
+	}
+
+	while (1) {
+		jfs_dirent = (struct jfs_dirent *) dirent_buf;
+		jfs_dirents = 0;
+		overflow = fix_page = 0;
+
+		stbl = DT_GETSTBL(p);
+
+		for (i = index; i < p->header.nextindex; i++) {
+			d = (struct ldtentry *) & p->slot[stbl[i]];
+
+			if (((long) jfs_dirent + d->namlen + 1) >
+			    (dirent_buf + PSIZE)) {
+				/* DBCS codepages could overrun dirent_buf */
+				index = i;
+				overflow = 1;
+				break;
+			}
+
+			d_namleft = d->namlen;
+			name_ptr = jfs_dirent->name;
+			jfs_dirent->ino = le32_to_cpu(d->inumber);
+
+			if (do_index) {
+				len = min(d_namleft, DTLHDRDATALEN);
+				jfs_dirent->position = le32_to_cpu(d->index);
+				/*
+				 * d->index should always be valid, but it
+				 * isn't.  fsck.jfs doesn't create the
+				 * directory index for the lost+found
+				 * directory.  Rather than let it go,
+				 * we can try to fix it.
+				 */
+				if ((jfs_dirent->position < 2) ||
+				    (jfs_dirent->position >=
+				     JFS_IP(ip)->next_index)) {
+					if (!page_fixed && !isReadOnly(ip)) {
+						fix_page = 1;
+						/*
+						 * setting overflow and setting
+						 * index to i will cause the
+						 * same page to be processed
+						 * again starting here
+						 */
+						overflow = 1;
+						index = i;
+						break;
+					}
+					jfs_dirent->position = unique_pos++;
+				}
+			} else {
+				jfs_dirent->position = dtpos;
+				len = min(d_namleft, DTLHDRDATALEN_LEGACY);
+			}
+
+			/* copy the name of head/only segment */
+			outlen = jfs_strfromUCS_le(name_ptr, d->name, len,
+						   codepage);
+			jfs_dirent->name_len = outlen;
+
+			/* copy name in the additional segment(s) */
+			next = d->next;
+			while (next >= 0) {
+				t = (struct dtslot *) & p->slot[next];
+				name_ptr += outlen;
+				d_namleft -= len;
+				/* Sanity Check */
+				if (d_namleft == 0) {
+					jERROR(1,("JFS:Dtree error: "
+					  "ino = %ld, bn=%Ld, index = %d\n",
+						  (long)ip->i_ino, (long long)bn, i));
+					updateSuper(ip->i_sb, FM_DIRTY);
+					goto skip_one;
+				}
+				len = min(d_namleft, DTSLOTDATALEN);
+				outlen = jfs_strfromUCS_le(name_ptr, t->name,
+							   len, codepage);
+				jfs_dirent->name_len += outlen;
+
+				next = t->next;
+			}
+
+			jfs_dirents++;
+			jfs_dirent = next_jfs_dirent(jfs_dirent);
+skip_one:
+			if (!do_index)
+				dtoffset->index++;
+		}
+
+		if (!overflow) {
+			/* Point to next leaf page */
+			if (p->header.flag & BT_ROOT)
+				bn = 0;
+			else {
+				bn = le64_to_cpu(p->header.next);
+				index = 0;
+				/* update offset (pn:index) for new page */
+				if (!do_index) {
+					dtoffset->pn++;
+					dtoffset->index = 0;
+				}
+			}
+			page_fixed = 0;
+		}
+
+		/* unpin previous leaf page */
+		DT_PUTPAGE(mp);
+
+		jfs_dirent = (struct jfs_dirent *) dirent_buf;
+		while (jfs_dirents--) {
+			filp->f_pos = jfs_dirent->position;
+			if (filldir(dirent, jfs_dirent->name,
+				    jfs_dirent->name_len, filp->f_pos,
+				    jfs_dirent->ino, DT_UNKNOWN))
+				goto out;
+			jfs_dirent = next_jfs_dirent(jfs_dirent);
+		}
+
+		if (fix_page) {
+			add_missing_indices(ip, bn);
+			page_fixed = 1;
+		}
+
+		if (!overflow && (bn == 0)) {
+			filp->f_pos = DIREND;
+			break;
+		}
+
+		DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc) {
+			free_page(dirent_buf);
+			return -rc;
+		}
+	}
+
+      out:
+	free_page(dirent_buf);
+
+	return rc;
+}
+
+
+/*
+ *	dtReadFirst()
+ *
+ * function: get the leftmost page of the directory
+ */
+static int dtReadFirst(struct inode *ip, struct btstack * btstack)
+{
+	int rc = 0;
+	s64 bn;
+	int psize = 288;	/* initial in-line directory */
+	struct metapage *mp;
+	dtpage_t *p;
+	s8 *stbl;
+	struct btframe *btsp;
+	pxd_t *xd;
+
+	BT_CLR(btstack);	/* reset stack */
+
+	/*
+	 *      descend leftmost path of the tree
+	 *
+	 * by convention, root bn = 0.
+	 */
+	for (bn = 0;;) {
+		DT_GETPAGE(ip, bn, mp, psize, p, rc);
+		if (rc)
+			return rc;
+
+		/*
+		 * leftmost leaf page
+		 */
+		if (p->header.flag & BT_LEAF) {
+			/* return leftmost entry */
+			btsp = btstack->top;
+			btsp->bn = bn;
+			btsp->index = 0;
+			btsp->mp = mp;
+
+			return 0;
+		}
+
+		/*
+		 * descend down to leftmost child page
+		 */
+		/* push (bn, index) of the parent page/entry */
+		BT_PUSH(btstack, bn, 0);
+
+		/* get the leftmost entry */
+		stbl = DT_GETSTBL(p);
+		xd = (pxd_t *) & p->slot[stbl[0]];
+
+		/* get the child page block address */
+		bn = addressPXD(xd);
+		psize = lengthPXD(xd) << JFS_SBI(ip->i_sb)->l2bsize;
+
+		/* unpin the parent page */
+		DT_PUTPAGE(mp);
+	}
+}
+
+
+/*
+ *	dtReadNext()
+ *
+ * function: get the page of the specified offset (pn:index)
+ *
+ * return: if (offset > eof), bn = -1;
+ *
+ * note: if index > nextindex of the target leaf page,
+ * start with 1st entry of next leaf page;
+ */
+static int dtReadNext(struct inode *ip, loff_t * offset,
+		      struct btstack * btstack)
+{
+	int rc = 0;
+	struct dtoffset {
+		s16 pn;
+		s16 index;
+		s32 unused;
+	} *dtoffset = (struct dtoffset *) offset;
+	s64 bn;
+	struct metapage *mp;
+	dtpage_t *p;
+	int index;
+	int pn;
+	s8 *stbl;
+	struct btframe *btsp, *parent;
+	pxd_t *xd;
+
+	/*
+	 * get leftmost leaf page pinned
+	 */
+	if ((rc = dtReadFirst(ip, btstack)))
+		return rc;
+
+	/* get leaf page */
+	DT_GETSEARCH(ip, btstack->top, bn, mp, p, index);
+
+	/* get the start offset (pn:index) */
+	pn = dtoffset->pn - 1;	/* Now pn = 0 represents leftmost leaf */
+	index = dtoffset->index;
+
+	/* start at leftmost page ? */
+	if (pn == 0) {
+		/* offset beyond eof ? */
+		if (index < p->header.nextindex)
+			goto out;
+
+		if (p->header.flag & BT_ROOT) {
+			bn = -1;
+			goto out;
+		}
+
+		/* start with 1st entry of next leaf page */
+		dtoffset->pn++;
+		dtoffset->index = index = 0;
+		goto a;
+	}
+
+	/* start at non-leftmost page: scan parent pages for large pn */
+	if (p->header.flag & BT_ROOT) {
+		bn = -1;
+		goto out;
+	}
+
+	/* start after next leaf page ? */
+	if (pn > 1)
+		goto b;
+
+	/* get leaf page pn = 1 */
+      a:
+	bn = le64_to_cpu(p->header.next);
+
+	/* unpin leaf page */
+	DT_PUTPAGE(mp);
+
+	/* offset beyond eof ? */
+	if (bn == 0) {
+		bn = -1;
+		goto out;
+	}
+
+	goto c;
+
+	/*
+	 * scan last internal page level to get target leaf page
+	 */
+      b:
+	/* unpin leftmost leaf page */
+	DT_PUTPAGE(mp);
+
+	/* get left most parent page */
+	btsp = btstack->top;
+	parent = btsp - 1;
+	bn = parent->bn;
+	DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return rc;
+
+	/* scan parent pages at last internal page level */
+	while (pn >= p->header.nextindex) {
+		pn -= p->header.nextindex;
+
+		/* get next parent page address */
+		bn = le64_to_cpu(p->header.next);
+
+		/* unpin current parent page */
+		DT_PUTPAGE(mp);
+
+		/* offset beyond eof ? */
+		if (bn == 0) {
+			bn = -1;
+			goto out;
+		}
+
+		/* get next parent page */
+		DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		/* update parent page stack frame */
+		parent->bn = bn;
+	}
+
+	/* get leaf page address */
+	stbl = DT_GETSTBL(p);
+	xd = (pxd_t *) & p->slot[stbl[pn]];
+	bn = addressPXD(xd);
+
+	/* unpin parent page */
+	DT_PUTPAGE(mp);
+
+	/*
+	 * get target leaf page
+	 */
+      c:
+	DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return rc;
+
+	/*
+	 * leaf page has been completed:
+	 * start with 1st entry of next leaf page
+	 */
+	if (index >= p->header.nextindex) {
+		bn = le64_to_cpu(p->header.next);
+
+		/* unpin leaf page */
+		DT_PUTPAGE(mp);
+
+		/* offset beyond eof ? */
+		if (bn == 0) {
+			bn = -1;
+			goto out;
+		}
+
+		/* get next leaf page */
+		DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		/* start with 1st entry of next leaf page */
+		dtoffset->pn++;
+		dtoffset->index = 0;
+	}
+
+      out:
+	/* return target leaf page pinned */
+	btsp = btstack->top;
+	btsp->bn = bn;
+	btsp->index = dtoffset->index;
+	btsp->mp = mp;
+
+	return 0;
+}
+
+
+/*
+ *	dtCompare()
+ *
+ * function: compare search key with an internal entry
+ *
+ * return:
+ *	< 0 if k is < record
+ *	= 0 if k is = record
+ *	> 0 if k is > record
+ */
+static int dtCompare(struct component_name * key,	/* search key */
+		     dtpage_t * p,	/* directory page */
+		     int si)
+{				/* entry slot index */
+	wchar_t *kname, *name;
+	int klen, namlen, len, rc;
+	struct idtentry *ih;
+	struct dtslot *t;
+
+	/*
+	 * force the left-most key on internal pages, at any level of
+	 * the tree, to be less than any search key.
+	 * this obviates having to update the leftmost key on an internal
+	 * page when the user inserts a new key in the tree smaller than
+	 * anything that has been stored.
+	 *
+	 * (? if/when dtSearch() narrows down to 1st entry (index = 0),
+	 * at any internal page at any level of the tree,
+	 * it descends to child of the entry anyway -
+	 * ? make the entry as min size dummy entry)
+	 *
+	 * if (e->index == 0 && h->prevpg == P_INVALID && !(h->flags & BT_LEAF))
+	 * return (1);
+	 */
+
+	kname = key->name;
+	klen = key->namlen;
+
+	ih = (struct idtentry *) & p->slot[si];
+	si = ih->next;
+	name = ih->name;
+	namlen = ih->namlen;
+	len = min(namlen, DTIHDRDATALEN);
+
+	/* compare with head/only segment */
+	len = min(klen, len);
+	if ((rc = UniStrncmp_le(kname, name, len)))
+		return rc;
+
+	klen -= len;
+	namlen -= len;
+
+	/* compare with additional segment(s) */
+	kname += len;
+	while (klen > 0 && namlen > 0) {
+		/* compare with next name segment */
+		t = (struct dtslot *) & p->slot[si];
+		len = min(namlen, DTSLOTDATALEN);
+		len = min(klen, len);
+		name = t->name;
+		if ((rc = UniStrncmp_le(kname, name, len)))
+			return rc;
+
+		klen -= len;
+		namlen -= len;
+		kname += len;
+		si = t->next;
+	}
+
+	return (klen - namlen);
+}
+
+
+
+
+/*
+ *	ciCompare()
+ *
+ * function: compare search key with an (leaf/internal) entry
+ *
+ * return:
+ *	< 0 if k is < record
+ *	= 0 if k is = record
+ *	> 0 if k is > record
+ */
+static int ciCompare(struct component_name * key,	/* search key */
+		     dtpage_t * p,	/* directory page */
+		     int si,	/* entry slot index */
+		     int flag)
+{
+	wchar_t *kname, *name, x;
+	int klen, namlen, len, rc;
+	struct ldtentry *lh;
+	struct idtentry *ih;
+	struct dtslot *t;
+	int i;
+
+	/*
+	 * force the left-most key on internal pages, at any level of
+	 * the tree, to be less than any search key.
+	 * this obviates having to update the leftmost key on an internal
+	 * page when the user inserts a new key in the tree smaller than
+	 * anything that has been stored.
+	 *
+	 * (? if/when dtSearch() narrows down to 1st entry (index = 0),
+	 * at any internal page at any level of the tree,
+	 * it descends to child of the entry anyway -
+	 * ? make the entry as min size dummy entry)
+	 *
+	 * if (e->index == 0 && h->prevpg == P_INVALID && !(h->flags & BT_LEAF))
+	 * return (1);
+	 */
+
+	kname = key->name;
+	klen = key->namlen;
+
+	/*
+	 * leaf page entry
+	 */
+	if (p->header.flag & BT_LEAF) {
+		lh = (struct ldtentry *) & p->slot[si];
+		si = lh->next;
+		name = lh->name;
+		namlen = lh->namlen;
+		if (flag & JFS_DIR_INDEX)
+			len = min(namlen, DTLHDRDATALEN);
+		else
+			len = min(namlen, DTLHDRDATALEN_LEGACY);
+	}
+	/*
+	 * internal page entry
+	 */
+	else {
+		ih = (struct idtentry *) & p->slot[si];
+		si = ih->next;
+		name = ih->name;
+		namlen = ih->namlen;
+		len = min(namlen, DTIHDRDATALEN);
+	}
+
+	/* compare with head/only segment */
+	len = min(klen, len);
+	for (i = 0; i < len; i++, kname++, name++) {
+		/* only uppercase if case-insensitive support is on */
+		if ((flag & JFS_OS2) == JFS_OS2)
+			x = UniToupper(le16_to_cpu(*name));
+		else
+			x = le16_to_cpu(*name);
+		if ((rc = *kname - x))
+			return rc;
+	}
+
+	klen -= len;
+	namlen -= len;
+
+	/* compare with additional segment(s) */
+	while (klen > 0 && namlen > 0) {
+		/* compare with next name segment */
+		t = (struct dtslot *) & p->slot[si];
+		len = min(namlen, DTSLOTDATALEN);
+		len = min(klen, len);
+		name = t->name;
+		for (i = 0; i < len; i++, kname++, name++) {
+			/* only uppercase if case-insensitive support is on */
+			if ((flag & JFS_OS2) == JFS_OS2)
+				x = UniToupper(le16_to_cpu(*name));
+			else
+				x = le16_to_cpu(*name);
+
+			if ((rc = *kname - x))
+				return rc;
+		}
+
+		klen -= len;
+		namlen -= len;
+		si = t->next;
+	}
+
+	return (klen - namlen);
+}
+
+
+/*
+ *	ciGetLeafPrefixKey()
+ *
+ * function: compute prefix of suffix compression
+ *	     from two adjacent leaf entries
+ *	     across page boundary
+ *
+ * return:
+ *	Number of prefix bytes needed to distinguish b from a.
+ */
+static void ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
+			       int ri, struct component_name * key, int flag)
+{
+	int klen, namlen;
+	wchar_t *pl, *pr, *kname;
+	wchar_t lname[JFS_NAME_MAX + 1];
+	struct component_name lkey = { 0, lname };
+	wchar_t rname[JFS_NAME_MAX + 1];
+	struct component_name rkey = { 0, rname };
+
+	/* get left and right key */
+	dtGetKey(lp, li, &lkey, flag);
+	lkey.name[lkey.namlen] = 0;
+
+	if ((flag & JFS_OS2) == JFS_OS2)
+		ciToUpper(&lkey);
+
+	dtGetKey(rp, ri, &rkey, flag);
+	rkey.name[rkey.namlen] = 0;
+
+
+	if ((flag & JFS_OS2) == JFS_OS2)
+		ciToUpper(&rkey);
+
+	/* compute prefix */
+	klen = 0;
+	kname = key->name;
+	namlen = min(lkey.namlen, rkey.namlen);
+	for (pl = lkey.name, pr = rkey.name;
+	     namlen; pl++, pr++, namlen--, klen++, kname++) {
+		*kname = *pr;
+		if (*pl != *pr) {
+			key->namlen = klen + 1;
+			return;
+		}
+	}
+
+	/* l->namlen <= r->namlen since l <= r */
+	if (lkey.namlen < rkey.namlen) {
+		*kname = *pr;
+		key->namlen = klen + 1;
+	} else			/* l->namelen == r->namelen */
+		key->namlen = klen;
+
+	return;
+}
+
+
+
+/*
+ *	dtGetKey()
+ *
+ * function: get key of the entry
+ */
+static void dtGetKey(dtpage_t * p, int i,	/* entry index */
+		     struct component_name * key, int flag)
+{
+	int si;
+	s8 *stbl;
+	struct ldtentry *lh;
+	struct idtentry *ih;
+	struct dtslot *t;
+	int namlen, len;
+	wchar_t *name, *kname;
+
+	/* get entry */
+	stbl = DT_GETSTBL(p);
+	si = stbl[i];
+	if (p->header.flag & BT_LEAF) {
+		lh = (struct ldtentry *) & p->slot[si];
+		si = lh->next;
+		namlen = lh->namlen;
+		name = lh->name;
+		if (flag & JFS_DIR_INDEX)
+			len = min(namlen, DTLHDRDATALEN);
+		else
+			len = min(namlen, DTLHDRDATALEN_LEGACY);
+	} else {
+		ih = (struct idtentry *) & p->slot[si];
+		si = ih->next;
+		namlen = ih->namlen;
+		name = ih->name;
+		len = min(namlen, DTIHDRDATALEN);
+	}
+
+	key->namlen = namlen;
+	kname = key->name;
+
+	/*
+	 * move head/only segment
+	 */
+	UniStrncpy_le(kname, name, len);
+
+	/*
+	 * move additional segment(s)
+	 */
+	while (si >= 0) {
+		/* get next segment */
+		t = &p->slot[si];
+		kname += len;
+		namlen -= len;
+		len = min(namlen, DTSLOTDATALEN);
+		UniStrncpy_le(kname, t->name, len);
+
+		si = t->next;
+	}
+}
+
+
+/*
+ *	dtInsertEntry()
+ *
+ * function: allocate free slot(s) and
+ *	     write a leaf/internal entry
+ *
+ * return: entry slot index
+ */
+static void dtInsertEntry(dtpage_t * p, int index, struct component_name * key,
+			  ddata_t * data, struct dt_lock ** dtlock)
+{
+	struct dtslot *h, *t;
+	struct ldtentry *lh = 0;
+	struct idtentry *ih = 0;
+	int hsi, fsi, klen, len, nextindex;
+	wchar_t *kname, *name;
+	s8 *stbl;
+	pxd_t *xd;
+	struct dt_lock *dtlck = *dtlock;
+	struct lv *lv;
+	int xsi, n;
+	s64 bn = 0;
+	struct metapage *mp = 0;
+
+	klen = key->namlen;
+	kname = key->name;
+
+	/* allocate a free slot */
+	hsi = fsi = p->header.freelist;
+	h = &p->slot[fsi];
+	p->header.freelist = h->next;
+	--p->header.freecnt;
+
+	/* open new linelock */
+	if (dtlck->index >= dtlck->maxcnt)
+		dtlck = (struct dt_lock *) txLinelock(dtlck);
+
+	lv = & dtlck->lv[dtlck->index];
+	lv->offset = hsi;
+
+	/* write head/only segment */
+	if (p->header.flag & BT_LEAF) {
+		lh = (struct ldtentry *) h;
+		lh->next = h->next;
+		lh->inumber = data->leaf.ino;	/* little-endian */
+		lh->namlen = klen;
+		name = lh->name;
+		if (data->leaf.ip) {
+			len = min(klen, DTLHDRDATALEN);
+			if (!(p->header.flag & BT_ROOT))
+				bn = addressPXD(&p->header.self);
+			lh->index = cpu_to_le32(add_index(data->leaf.tid,
+							  data->leaf.ip,
+							  bn, index));
+		} else
+			len = min(klen, DTLHDRDATALEN_LEGACY);
+	} else {
+		ih = (struct idtentry *) h;
+		ih->next = h->next;
+		xd = (pxd_t *) ih;
+		*xd = data->xd;
+		ih->namlen = klen;
+		name = ih->name;
+		len = min(klen, DTIHDRDATALEN);
+	}
+
+	UniStrncpy_le(name, kname, len);
+
+	n = 1;
+	xsi = hsi;
+
+	/* write additional segment(s) */
+	t = h;
+	klen -= len;
+	while (klen) {
+		/* get free slot */
+		fsi = p->header.freelist;
+		t = &p->slot[fsi];
+		p->header.freelist = t->next;
+		--p->header.freecnt;
+
+		/* is next slot contiguous ? */
+		if (fsi != xsi + 1) {
+			/* close current linelock */
+			lv->length = n;
+			dtlck->index++;
+
+			/* open new linelock */
+			if (dtlck->index < dtlck->maxcnt)
+				lv++;
+			else {
+				dtlck = (struct dt_lock *) txLinelock(dtlck);
+				lv = & dtlck->lv[0];
+			}
+
+			lv->offset = fsi;
+			n = 0;
+		}
+
+		kname += len;
+		len = min(klen, DTSLOTDATALEN);
+		UniStrncpy_le(t->name, kname, len);
+
+		n++;
+		xsi = fsi;
+		klen -= len;
+	}
+
+	/* close current linelock */
+	lv->length = n;
+	dtlck->index++;
+
+	*dtlock = dtlck;
+
+	/* terminate last/only segment */
+	if (h == t) {
+		/* single segment entry */
+		if (p->header.flag & BT_LEAF)
+			lh->next = -1;
+		else
+			ih->next = -1;
+	} else
+		/* multi-segment entry */
+		t->next = -1;
+
+	/* if insert into middle, shift right succeeding entries in stbl */
+	stbl = DT_GETSTBL(p);
+	nextindex = p->header.nextindex;
+	if (index < nextindex) {
+		memmove(stbl + index + 1, stbl + index, nextindex - index);
+
+		if ((p->header.flag & BT_LEAF) && data->leaf.ip) {
+			/*
+			 * Need to update slot number for entries that moved
+			 * in the stbl
+			 */
+			mp = 0;
+			for (n = index + 1; n <= nextindex; n++) {
+				lh = (struct ldtentry *) & (p->slot[stbl[n]]);
+				modify_index(data->leaf.tid, data->leaf.ip,
+					     le32_to_cpu(lh->index), bn, n,
+					     &mp);
+			}
+			if (mp)
+				release_metapage(mp);
+		}
+	}
+
+	stbl[index] = hsi;
+
+	/* advance next available entry index of stbl */
+	++p->header.nextindex;
+}
+
+
+/*
+ *	dtMoveEntry()
+ *
+ * function: move entries from split/left page to new/right page
+ *
+ *	nextindex of dst page and freelist/freecnt of both pages
+ *	are updated.
+ */
+static void dtMoveEntry(dtpage_t * sp, int si, dtpage_t * dp,
+			struct dt_lock ** sdtlock, struct dt_lock ** ddtlock,
+			int do_index)
+{
+	int ssi, next;		/* src slot index */
+	int di;			/* dst entry index */
+	int dsi;		/* dst slot index */
+	s8 *sstbl, *dstbl;	/* sorted entry table */
+	int snamlen, len;
+	struct ldtentry *slh, *dlh = 0;
+	struct idtentry *sih, *dih = 0;
+	struct dtslot *h, *s, *d;
+	struct dt_lock *sdtlck = *sdtlock, *ddtlck = *ddtlock;
+	struct lv *slv, *dlv;
+	int xssi, ns, nd;
+	int sfsi;
+
+	sstbl = (s8 *) & sp->slot[sp->header.stblindex];
+	dstbl = (s8 *) & dp->slot[dp->header.stblindex];
+
+	dsi = dp->header.freelist;	/* first (whole page) free slot */
+	sfsi = sp->header.freelist;
+
+	/* linelock destination entry slot */
+	dlv = & ddtlck->lv[ddtlck->index];
+	dlv->offset = dsi;
+
+	/* linelock source entry slot */
+	slv = & sdtlck->lv[sdtlck->index];
+	slv->offset = sstbl[si];
+	xssi = slv->offset - 1;
+
+	/*
+	 * move entries
+	 */
+	ns = nd = 0;
+	for (di = 0; si < sp->header.nextindex; si++, di++) {
+		ssi = sstbl[si];
+		dstbl[di] = dsi;
+
+		/* is next slot contiguous ? */
+		if (ssi != xssi + 1) {
+			/* close current linelock */
+			slv->length = ns;
+			sdtlck->index++;
+
+			/* open new linelock */
+			if (sdtlck->index < sdtlck->maxcnt)
+				slv++;
+			else {
+				sdtlck = (struct dt_lock *) txLinelock(sdtlck);
+				slv = & sdtlck->lv[0];
+			}
+
+			slv->offset = ssi;
+			ns = 0;
+		}
+
+		/*
+		 * move head/only segment of an entry
+		 */
+		/* get dst slot */
+		h = d = &dp->slot[dsi];
+
+		/* get src slot and move */
+		s = &sp->slot[ssi];
+		if (sp->header.flag & BT_LEAF) {
+			/* get source entry */
+			slh = (struct ldtentry *) s;
+			dlh = (struct ldtentry *) h;
+			snamlen = slh->namlen;
+
+			if (do_index) {
+				len = min(snamlen, DTLHDRDATALEN);
+				dlh->index = slh->index; /* little-endian */
+			} else
+				len = min(snamlen, DTLHDRDATALEN_LEGACY);
+
+			memcpy(dlh, slh, 6 + len * 2);
+
+			next = slh->next;
+
+			/* update dst head/only segment next field */
+			dsi++;
+			dlh->next = dsi;
+		} else {
+			sih = (struct idtentry *) s;
+			snamlen = sih->namlen;
+
+			len = min(snamlen, DTIHDRDATALEN);
+			dih = (struct idtentry *) h;
+			memcpy(dih, sih, 10 + len * 2);
+			next = sih->next;
+
+			dsi++;
+			dih->next = dsi;
+		}
+
+		/* free src head/only segment */
+		s->next = sfsi;
+		s->cnt = 1;
+		sfsi = ssi;
+
+		ns++;
+		nd++;
+		xssi = ssi;
+
+		/*
+		 * move additional segment(s) of the entry
+		 */
+		snamlen -= len;
+		while ((ssi = next) >= 0) {
+			/* is next slot contiguous ? */
+			if (ssi != xssi + 1) {
+				/* close current linelock */
+				slv->length = ns;
+				sdtlck->index++;
+
+				/* open new linelock */
+				if (sdtlck->index < sdtlck->maxcnt)
+					slv++;
+				else {
+					sdtlck =
+					    (struct dt_lock *)
+					    txLinelock(sdtlck);
+					slv = & sdtlck->lv[0];
+				}
+
+				slv->offset = ssi;
+				ns = 0;
+			}
+
+			/* get next source segment */
+			s = &sp->slot[ssi];
+
+			/* get next destination free slot */
+			d++;
+
+			len = min(snamlen, DTSLOTDATALEN);
+			UniStrncpy(d->name, s->name, len);
+
+			ns++;
+			nd++;
+			xssi = ssi;
+
+			dsi++;
+			d->next = dsi;
+
+			/* free source segment */
+			next = s->next;
+			s->next = sfsi;
+			s->cnt = 1;
+			sfsi = ssi;
+
+			snamlen -= len;
+		}		/* end while */
+
+		/* terminate dst last/only segment */
+		if (h == d) {
+			/* single segment entry */
+			if (dp->header.flag & BT_LEAF)
+				dlh->next = -1;
+			else
+				dih->next = -1;
+		} else
+			/* multi-segment entry */
+			d->next = -1;
+	}			/* end for */
+
+	/* close current linelock */
+	slv->length = ns;
+	sdtlck->index++;
+	*sdtlock = sdtlck;
+
+	dlv->length = nd;
+	ddtlck->index++;
+	*ddtlock = ddtlck;
+
+	/* update source header */
+	sp->header.freelist = sfsi;
+	sp->header.freecnt += nd;
+
+	/* update destination header */
+	dp->header.nextindex = di;
+
+	dp->header.freelist = dsi;
+	dp->header.freecnt -= nd;
+}
+
+
+/*
+ *	dtDeleteEntry()
+ *
+ * function: free a (leaf/internal) entry
+ *
+ * log freelist header, stbl, and each segment slot of entry
+ * (even though last/only segment next field is modified,
+ * physical image logging requires all segment slots of
+ * the entry logged to avoid applying previous updates
+ * to the same slots)
+ */
+static void dtDeleteEntry(dtpage_t * p, int fi, struct dt_lock ** dtlock)
+{
+	int fsi;		/* free entry slot index */
+	s8 *stbl;
+	struct dtslot *t;
+	int si, freecnt;
+	struct dt_lock *dtlck = *dtlock;
+	struct lv *lv;
+	int xsi, n;
+
+	/* get free entry slot index */
+	stbl = DT_GETSTBL(p);
+	fsi = stbl[fi];
+
+	/* open new linelock */
+	if (dtlck->index >= dtlck->maxcnt)
+		dtlck = (struct dt_lock *) txLinelock(dtlck);
+	lv = & dtlck->lv[dtlck->index];
+
+	lv->offset = fsi;
+
+	/* get the head/only segment */
+	t = &p->slot[fsi];
+	if (p->header.flag & BT_LEAF)
+		si = ((struct ldtentry *) t)->next;
+	else
+		si = ((struct idtentry *) t)->next;
+	t->next = si;
+	t->cnt = 1;
+
+	n = freecnt = 1;
+	xsi = fsi;
+
+	/* find the last/only segment */
+	while (si >= 0) {
+		/* is next slot contiguous ? */
+		if (si != xsi + 1) {
+			/* close current linelock */
+			lv->length = n;
+			dtlck->index++;
+
+			/* open new linelock */
+			if (dtlck->index < dtlck->maxcnt)
+				lv++;
+			else {
+				dtlck = (struct dt_lock *) txLinelock(dtlck);
+				lv = & dtlck->lv[0];
+			}
+
+			lv->offset = si;
+			n = 0;
+		}
+
+		n++;
+		xsi = si;
+		freecnt++;
+
+		t = &p->slot[si];
+		t->cnt = 1;
+		si = t->next;
+	}
+
+	/* close current linelock */
+	lv->length = n;
+	dtlck->index++;
+
+	*dtlock = dtlck;
+
+	/* update freelist */
+	t->next = p->header.freelist;
+	p->header.freelist = fsi;
+	p->header.freecnt += freecnt;
+
+	/* if delete from middle,
+	 * shift left the succedding entries in the stbl
+	 */
+	si = p->header.nextindex;
+	if (fi < si - 1)
+		memmove(&stbl[fi], &stbl[fi + 1], si - fi - 1);
+
+	p->header.nextindex--;
+}
+
+
+/*
+ *	dtTruncateEntry()
+ *
+ * function: truncate a (leaf/internal) entry
+ *
+ * log freelist header, stbl, and each segment slot of entry
+ * (even though last/only segment next field is modified,
+ * physical image logging requires all segment slots of
+ * the entry logged to avoid applying previous updates
+ * to the same slots)
+ */
+static void dtTruncateEntry(dtpage_t * p, int ti, struct dt_lock ** dtlock)
+{
+	int tsi;		/* truncate entry slot index */
+	s8 *stbl;
+	struct dtslot *t;
+	int si, freecnt;
+	struct dt_lock *dtlck = *dtlock;
+	struct lv *lv;
+	int fsi, xsi, n;
+
+	/* get free entry slot index */
+	stbl = DT_GETSTBL(p);
+	tsi = stbl[ti];
+
+	/* open new linelock */
+	if (dtlck->index >= dtlck->maxcnt)
+		dtlck = (struct dt_lock *) txLinelock(dtlck);
+	lv = & dtlck->lv[dtlck->index];
+
+	lv->offset = tsi;
+
+	/* get the head/only segment */
+	t = &p->slot[tsi];
+	ASSERT(p->header.flag & BT_INTERNAL);
+	((struct idtentry *) t)->namlen = 0;
+	si = ((struct idtentry *) t)->next;
+	((struct idtentry *) t)->next = -1;
+
+	n = 1;
+	freecnt = 0;
+	fsi = si;
+	xsi = tsi;
+
+	/* find the last/only segment */
+	while (si >= 0) {
+		/* is next slot contiguous ? */
+		if (si != xsi + 1) {
+			/* close current linelock */
+			lv->length = n;
+			dtlck->index++;
+
+			/* open new linelock */
+			if (dtlck->index < dtlck->maxcnt)
+				lv++;
+			else {
+				dtlck = (struct dt_lock *) txLinelock(dtlck);
+				lv = & dtlck->lv[0];
+			}
+
+			lv->offset = si;
+			n = 0;
+		}
+
+		n++;
+		xsi = si;
+		freecnt++;
+
+		t = &p->slot[si];
+		t->cnt = 1;
+		si = t->next;
+	}
+
+	/* close current linelock */
+	lv->length = n;
+	dtlck->index++;
+
+	*dtlock = dtlck;
+
+	/* update freelist */
+	if (freecnt == 0)
+		return;
+	t->next = p->header.freelist;
+	p->header.freelist = fsi;
+	p->header.freecnt += freecnt;
+}
+
+
+/*
+ *	dtLinelockFreelist()
+ */
+static void dtLinelockFreelist(dtpage_t * p,	/* directory page */
+			       int m,	/* max slot index */
+			       struct dt_lock ** dtlock)
+{
+	int fsi;		/* free entry slot index */
+	struct dtslot *t;
+	int si;
+	struct dt_lock *dtlck = *dtlock;
+	struct lv *lv;
+	int xsi, n;
+
+	/* get free entry slot index */
+	fsi = p->header.freelist;
+
+	/* open new linelock */
+	if (dtlck->index >= dtlck->maxcnt)
+		dtlck = (struct dt_lock *) txLinelock(dtlck);
+	lv = & dtlck->lv[dtlck->index];
+
+	lv->offset = fsi;
+
+	n = 1;
+	xsi = fsi;
+
+	t = &p->slot[fsi];
+	si = t->next;
+
+	/* find the last/only segment */
+	while (si < m && si >= 0) {
+		/* is next slot contiguous ? */
+		if (si != xsi + 1) {
+			/* close current linelock */
+			lv->length = n;
+			dtlck->index++;
+
+			/* open new linelock */
+			if (dtlck->index < dtlck->maxcnt)
+				lv++;
+			else {
+				dtlck = (struct dt_lock *) txLinelock(dtlck);
+				lv = & dtlck->lv[0];
+			}
+
+			lv->offset = si;
+			n = 0;
+		}
+
+		n++;
+		xsi = si;
+
+		t = &p->slot[si];
+		si = t->next;
+	}
+
+	/* close current linelock */
+	lv->length = n;
+	dtlck->index++;
+
+	*dtlock = dtlck;
+}
+
+
+/*
+ * NAME: dtModify
+ *
+ * FUNCTION: Modify the inode number part of a directory entry
+ *
+ * PARAMETERS:
+ *	tid	- Transaction id
+ *	ip	- Inode of parent directory
+ *	key	- Name of entry to be modified
+ *	orig_ino	- Original inode number expected in entry
+ *	new_ino	- New inode number to put into entry
+ *	flag	- JFS_RENAME
+ *
+ * RETURNS:
+ *	ESTALE	- If entry found does not match orig_ino passed in
+ *	ENOENT	- If no entry can be found to match key
+ *	0	- If successfully modified entry
+ */
+int dtModify(tid_t tid, struct inode *ip,
+	 struct component_name * key, ino_t * orig_ino, ino_t new_ino, int flag)
+{
+	int rc;
+	s64 bn;
+	struct metapage *mp;
+	dtpage_t *p;
+	int index;
+	struct btstack btstack;
+	struct tlock *tlck;
+	struct dt_lock *dtlck;
+	struct lv *lv;
+	s8 *stbl;
+	int entry_si;		/* entry slot index */
+	struct ldtentry *entry;
+
+	/*
+	 *      search for the entry to modify:
+	 *
+	 * dtSearch() returns (leaf page pinned, index at which to modify).
+	 */
+	if ((rc = dtSearch(ip, key, orig_ino, &btstack, flag)))
+		return rc;
+
+	/* retrieve search result */
+	DT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+	BT_MARK_DIRTY(mp, ip);
+	/*
+	 * acquire a transaction lock on the leaf page of named entry
+	 */
+	tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+	dtlck = (struct dt_lock *) & tlck->lock;
+
+	/* get slot index of the entry */
+	stbl = DT_GETSTBL(p);
+	entry_si = stbl[index];
+
+	/* linelock entry */
+	ASSERT(dtlck->index == 0);
+	lv = & dtlck->lv[0];
+	lv->offset = entry_si;
+	lv->length = 1;
+	dtlck->index++;
+
+	/* get the head/only segment */
+	entry = (struct ldtentry *) & p->slot[entry_si];
+
+	/* substitute the inode number of the entry */
+	entry->inumber = cpu_to_le32(new_ino);
+
+	/* unpin the leaf page */
+	DT_PUTPAGE(mp);
+
+	return 0;
+}
+
+#ifdef _JFS_DEBUG_DTREE
+/*
+ *	dtDisplayTree()
+ *
+ * function: traverse forward
+ */
+int dtDisplayTree(struct inode *ip)
+{
+	int rc;
+	struct metapage *mp;
+	dtpage_t *p;
+	s64 bn, pbn;
+	int index, lastindex, v, h;
+	pxd_t *xd;
+	struct btstack btstack;
+	struct btframe *btsp;
+	struct btframe *parent;
+	u8 *stbl;
+	int psize = 256;
+
+	printk("display B+-tree.\n");
+
+	/* clear stack */
+	btsp = btstack.stack;
+
+	/*
+	 * start with root
+	 *
+	 * root resides in the inode
+	 */
+	bn = 0;
+	v = h = 0;
+
+	/*
+	 * first access of each page:
+	 */
+      newPage:
+	DT_GETPAGE(ip, bn, mp, psize, p, rc);
+	if (rc)
+		return rc;
+
+	/* process entries forward from first index */
+	index = 0;
+	lastindex = p->header.nextindex - 1;
+
+	if (p->header.flag & BT_INTERNAL) {
+		/*
+		 * first access of each internal page
+		 */
+		printf("internal page ");
+		dtDisplayPage(ip, bn, p);
+
+		goto getChild;
+	} else {		/* (p->header.flag & BT_LEAF) */
+
+		/*
+		 * first access of each leaf page
+		 */
+		printf("leaf page ");
+		dtDisplayPage(ip, bn, p);
+
+		/*
+		 * process leaf page entries
+		 *
+		 for ( ; index <= lastindex; index++)
+		 {
+		 }
+		 */
+
+		/* unpin the leaf page */
+		DT_PUTPAGE(mp);
+	}
+
+	/*
+	 * go back up to the parent page
+	 */
+      getParent:
+	/* pop/restore parent entry for the current child page */
+	if ((parent = (btsp == btstack.stack ? NULL : --btsp)) == NULL)
+		/* current page must have been root */
+		return;
+
+	/*
+	 * parent page scan completed
+	 */
+	if ((index = parent->index) == (lastindex = parent->lastindex)) {
+		/* go back up to the parent page */
+		goto getParent;
+	}
+
+	/*
+	 * parent page has entries remaining
+	 */
+	/* get back the parent page */
+	bn = parent->bn;
+	/* v = parent->level; */
+	DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return rc;
+
+	/* get next parent entry */
+	index++;
+
+	/*
+	 * internal page: go down to child page of current entry
+	 */
+      getChild:
+	/* push/save current parent entry for the child page */
+	btsp->bn = pbn = bn;
+	btsp->index = index;
+	btsp->lastindex = lastindex;
+	/* btsp->level = v; */
+	/* btsp->node = h; */
+	++btsp;
+
+	/* get current entry for the child page */
+	stbl = DT_GETSTBL(p);
+	xd = (pxd_t *) & p->slot[stbl[index]];
+
+	/*
+	 * first access of each internal entry:
+	 */
+
+	/* get child page */
+	bn = addressPXD(xd);
+	psize = lengthPXD(xd) << ip->i_ipmnt->i_l2bsize;
+
+	printk("traverse down 0x%Lx[%d]->0x%Lx\n", pbn, index, bn);
+	v++;
+	h = index;
+
+	/* release parent page */
+	DT_PUTPAGE(mp);
+
+	/* process the child page */
+	goto newPage;
+}
+
+
+/*
+ *	dtDisplayPage()
+ *
+ * function: display page
+ */
+int dtDisplayPage(struct inode *ip, s64 bn, dtpage_t * p)
+{
+	int rc;
+	struct metapage *mp;
+	struct ldtentry *lh;
+	struct idtentry *ih;
+	pxd_t *xd;
+	int i, j;
+	u8 *stbl;
+	wchar_t name[JFS_NAME_MAX + 1];
+	struct component_name key = { 0, name };
+	int freepage = 0;
+
+	if (p == NULL) {
+		freepage = 1;
+		DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+	}
+
+	/* display page control */
+	printk("bn:0x%Lx flag:0x%08x nextindex:%d\n",
+	       bn, p->header.flag, p->header.nextindex);
+
+	/* display entries */
+	stbl = DT_GETSTBL(p);
+	for (i = 0, j = 1; i < p->header.nextindex; i++, j++) {
+		dtGetKey(p, i, &key, JFS_SBI(ip->i_sb)->mntflag);
+		key.name[key.namlen] = '\0';
+		if (p->header.flag & BT_LEAF) {
+			lh = (struct ldtentry *) & p->slot[stbl[i]];
+			printf("\t[%d] %s:%d", i, key.name,
+			       le32_to_cpu(lh->inumber));
+		} else {
+			ih = (struct idtentry *) & p->slot[stbl[i]];
+			xd = (pxd_t *) ih;
+			bn = addressPXD(xd);
+			printf("\t[%d] %s:0x%Lx", i, key.name, bn);
+		}
+
+		if (j == 4) {
+			printf("\n");
+			j = 0;
+		}
+	}
+
+	printf("\n");
+
+	if (freepage)
+		DT_PUTPAGE(mp);
+
+	return 0;
+}
+#endif				/* _JFS_DEBUG_DTREE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_dtree.h linux-2.4.20/fs/jfs/jfs_dtree.h
--- linux-2.4.19/fs/jfs/jfs_dtree.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_dtree.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,282 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+#ifndef _H_JFS_DTREE
+#define	_H_JFS_DTREE
+
+/*
+ *	jfs_dtree.h: directory B+-tree manager
+ */
+
+#include "jfs_btree.h"
+
+typedef union {
+	struct {
+		tid_t tid;
+		struct inode *ip;
+		u32 ino;
+	} leaf;
+	pxd_t xd;
+} ddata_t;
+
+
+/*
+ *      entry segment/slot
+ *
+ * an entry consists of type dependent head/only segment/slot and
+ * additional segments/slots linked vi next field;
+ * N.B. last/only segment of entry is terminated by next = -1;
+ */
+/*
+ *	directory page slot
+ */
+struct dtslot {
+	s8 next;		/* 1: */
+	s8 cnt;			/* 1: */
+	wchar_t name[15];	/* 30: */
+};				/* (32) */
+
+
+#define DATASLOTSIZE	16
+#define L2DATASLOTSIZE	4
+#define	DTSLOTSIZE	32
+#define	L2DTSLOTSIZE	5
+#define DTSLOTHDRSIZE	2
+#define DTSLOTDATASIZE	30
+#define DTSLOTDATALEN	15
+
+/*
+ *	 internal node entry head/only segment
+ */
+struct idtentry {
+	pxd_t xd;		/* 8: child extent descriptor */
+
+	s8 next;		/* 1: */
+	u8 namlen;		/* 1: */
+	wchar_t name[11];	/* 22: 2-byte aligned */
+};				/* (32) */
+
+#define DTIHDRSIZE	10
+#define DTIHDRDATALEN	11
+
+/* compute number of slots for entry */
+#define	NDTINTERNAL(klen) ( ((4 + (klen)) + (15 - 1)) / 15 )
+
+
+/*
+ *	leaf node entry head/only segment
+ *
+ * 	For legacy filesystems, name contains 13 wchars -- no index field
+ */
+struct ldtentry {
+	u32 inumber;		/* 4: 4-byte aligned */
+	s8 next;		/* 1: */
+	u8 namlen;		/* 1: */
+	wchar_t name[11];	/* 22: 2-byte aligned */
+	u32 index;		/* 4: index into dir_table */
+};				/* (32) */
+
+#define DTLHDRSIZE	6
+#define DTLHDRDATALEN_LEGACY	13	/* Old (OS/2) format */
+#define DTLHDRDATALEN	11
+
+/*
+ * dir_table used for directory traversal during readdir
+ */
+
+/*
+ * Keep persistent index for directory entries
+ */
+#define DO_INDEX(INODE) (JFS_SBI((INODE)->i_sb)->mntflag & JFS_DIR_INDEX)
+
+/*
+ * Maximum entry in inline directory table
+ */
+#define MAX_INLINE_DIRTABLE_ENTRY 13
+
+struct dir_table_slot {
+	u8 rsrvd;		/* 1: */
+	u8 flag;		/* 1: 0 if free */
+	u8 slot;		/* 1: slot within leaf page of entry */
+	u8 addr1;		/* 1: upper 8 bits of leaf page address */
+	u32 addr2;		/* 4: lower 32 bits of leaf page address -OR-
+				   index of next entry when this entry was deleted */
+};				/* (8) */
+
+/*
+ * flag values
+ */
+#define DIR_INDEX_VALID 1
+#define DIR_INDEX_FREE 0
+
+#define DTSaddress(dir_table_slot, address64)\
+{\
+	(dir_table_slot)->addr1 = ((u64)address64) >> 32;\
+	(dir_table_slot)->addr2 = __cpu_to_le32((address64) & 0xffffffff);\
+}
+
+#define addressDTS(dts)\
+	( ((s64)((dts)->addr1)) << 32 | __le32_to_cpu((dts)->addr2) )
+
+/* compute number of slots for entry */
+#define	NDTLEAF_LEGACY(klen)	( ((2 + (klen)) + (15 - 1)) / 15 )
+#define	NDTLEAF	NDTINTERNAL
+
+
+/*
+ *	directory root page (in-line in on-disk inode):
+ *
+ * cf. dtpage_t below.
+ */
+typedef union {
+	struct {
+		struct dasd DASD; /* 16: DASD limit/usage info */
+
+		u8 flag;	/* 1: */
+		u8 nextindex;	/* 1: next free entry in stbl */
+		s8 freecnt;	/* 1: free count */
+		s8 freelist;	/* 1: freelist header */
+
+		u32 idotdot;	/* 4: parent inode number */
+
+		s8 stbl[8];	/* 8: sorted entry index table */
+	} header;		/* (32) */
+
+	struct dtslot slot[9];
+} dtroot_t;
+
+#define PARENT(IP) \
+	(le32_to_cpu(JFS_IP(IP)->i_dtroot.header.idotdot))
+
+#define DTROOTMAXSLOT	9
+
+#define	dtEmpty(IP) (JFS_IP(IP)->i_dtroot.header.nextindex == 0)
+
+
+/*
+ *	directory regular page:
+ *
+ *	entry slot array of 32 byte slot
+ *
+ * sorted entry slot index table (stbl):
+ * contiguous slots at slot specified by stblindex,
+ * 1-byte per entry
+ *   512 byte block:  16 entry tbl (1 slot)
+ *  1024 byte block:  32 entry tbl (1 slot)
+ *  2048 byte block:  64 entry tbl (2 slot)
+ *  4096 byte block: 128 entry tbl (4 slot)
+ *
+ * data area:
+ *   512 byte block:  16 - 2 =  14 slot
+ *  1024 byte block:  32 - 2 =  30 slot
+ *  2048 byte block:  64 - 3 =  61 slot
+ *  4096 byte block: 128 - 5 = 123 slot
+ *
+ * N.B. index is 0-based; index fields refer to slot index
+ * except nextindex which refers to entry index in stbl;
+ * end of entry stot list or freelist is marked with -1.
+ */
+typedef union {
+	struct {
+		s64 next;	/* 8: next sibling */
+		s64 prev;	/* 8: previous sibling */
+
+		u8 flag;	/* 1: */
+		u8 nextindex;	/* 1: next entry index in stbl */
+		s8 freecnt;	/* 1: */
+		s8 freelist;	/* 1: slot index of head of freelist */
+
+		u8 maxslot;	/* 1: number of slots in page slot[] */
+		u8 stblindex;	/* 1: slot index of start of stbl */
+		u8 rsrvd[2];	/* 2: */
+
+		pxd_t self;	/* 8: self pxd */
+	} header;		/* (32) */
+
+	struct dtslot slot[128];
+} dtpage_t;
+
+#define DTPAGEMAXSLOT        128
+
+#define DT8THPGNODEBYTES     512
+#define DT8THPGNODETSLOTS      1
+#define DT8THPGNODESLOTS      16
+
+#define DTQTRPGNODEBYTES    1024
+#define DTQTRPGNODETSLOTS      1
+#define DTQTRPGNODESLOTS      32
+
+#define DTHALFPGNODEBYTES   2048
+#define DTHALFPGNODETSLOTS     2
+#define DTHALFPGNODESLOTS     64
+
+#define DTFULLPGNODEBYTES   4096
+#define DTFULLPGNODETSLOTS     4
+#define DTFULLPGNODESLOTS    128
+
+#define DTENTRYSTART	1
+
+/* get sorted entry table of the page */
+#define DT_GETSTBL(p) ( ((p)->header.flag & BT_ROOT) ?\
+	((dtroot_t *)(p))->header.stbl : \
+	(s8 *)&(p)->slot[(p)->header.stblindex] )
+
+/*
+ * Flags for dtSearch
+ */
+#define JFS_CREATE 1
+#define JFS_LOOKUP 2
+#define JFS_REMOVE 3
+#define JFS_RENAME 4
+
+#define DIRENTSIZ(namlen) \
+    ( (sizeof(struct dirent) - 2*(JFS_NAME_MAX+1) + 2*((namlen)+1) + 3) &~ 3 )
+
+/*
+ * Maximum file offset for directories.
+ */
+#define DIREND	INT_MAX
+
+/*
+ *	external declarations
+ */
+extern void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot);
+
+extern int dtSearch(struct inode *ip, struct component_name * key,
+		    ino_t * data, struct btstack * btstack, int flag);
+
+extern int dtInsert(tid_t tid, struct inode *ip, struct component_name * key,
+		    ino_t * ino, struct btstack * btstack);
+
+extern int dtDelete(tid_t tid, struct inode *ip, struct component_name * key,
+		    ino_t * data, int flag);
+
+extern int dtRelocate(tid_t tid,
+		      struct inode *ip, s64 lmxaddr, pxd_t * opxd, s64 nxaddr);
+
+extern int dtModify(tid_t tid, struct inode *ip, struct component_name * key,
+		    ino_t * orig_ino, ino_t new_ino, int flag);
+
+extern int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir);
+
+#ifdef  _JFS_DEBUG_DTREE
+extern int dtDisplayTree(struct inode *ip);
+
+extern int dtDisplayPage(struct inode *ip, s64 bn, dtpage_t * p);
+#endif				/* _JFS_DEBUG_DTREE */
+
+#endif				/* !_H_JFS_DTREE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_extent.c linux-2.4.20/fs/jfs/jfs_extent.c
--- linux-2.4.19/fs/jfs/jfs_extent.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_extent.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,655 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+
+#include <linux/fs.h>
+#include "jfs_incore.h"
+#include "jfs_dmap.h"
+#include "jfs_extent.h"
+#include "jfs_debug.h"
+
+/*
+ * forward references
+ */
+static int extBalloc(struct inode *, s64, s64 *, s64 *);
+#ifdef _NOTYET
+static int extBrealloc(struct inode *, s64, s64, s64 *, s64 *);
+#endif
+static s64 extRoundDown(s64 nb);
+
+/*
+ * external references
+ */
+extern int dbExtend(struct inode *, s64, s64, s64);
+extern int jfs_commit_inode(struct inode *, int);
+
+
+#define DPD(a)          (printk("(a): %d\n",(a)))
+#define DPC(a)          (printk("(a): %c\n",(a)))
+#define DPL1(a)					\
+{						\
+	if ((a) >> 32)				\
+		printk("(a): %x%08x  ",(a));	\
+	else					\
+		printk("(a): %x  ",(a) << 32);	\
+}
+#define DPL(a)					\
+{						\
+	if ((a) >> 32)				\
+		printk("(a): %x%08x\n",(a));	\
+	else					\
+		printk("(a): %x\n",(a) << 32);	\
+}
+
+#define DPD1(a)         (printk("(a): %d  ",(a)))
+#define DPX(a)          (printk("(a): %08x\n",(a)))
+#define DPX1(a)         (printk("(a): %08x  ",(a)))
+#define DPS(a)          (printk("%s\n",(a)))
+#define DPE(a)          (printk("\nENTERING: %s\n",(a)))
+#define DPE1(a)          (printk("\nENTERING: %s",(a)))
+#define DPS1(a)         (printk("  %s  ",(a)))
+
+
+/*
+ * NAME:	extAlloc()
+ *
+ * FUNCTION:    allocate an extent for a specified page range within a
+ *		file.
+ *
+ * PARAMETERS:
+ *	ip	- the inode of the file.
+ *	xlen	- requested extent length.
+ *	pno	- the starting page number with the file.
+ *	xp	- pointer to an xad.  on entry, xad describes an
+ *		  extent that is used as an allocation hint if the
+ *		  xaddr of the xad is non-zero.  on successful exit,
+ *		  the xad describes the newly allocated extent.
+ *	abnr	- boolean_t indicating whether the newly allocated extent
+ *		  should be marked as allocated but not recorded.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO	- i/o error.
+ *      ENOSPC	- insufficient disk resources.
+ */
+int
+extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
+	s64 nxlen, nxaddr, xoff, hint, xaddr = 0;
+	int rc, nbperpage;
+	int xflag;
+
+	/* This blocks if we are low on resources */
+	txBeginAnon(ip->i_sb);
+
+	/* Avoid race with jfs_commit_inode() */
+	down(&JFS_IP(ip)->commit_sem);
+
+	/* validate extent length */
+	if (xlen > MAXXLEN)
+		xlen = MAXXLEN;
+
+	/* get the number of blocks per page */
+	nbperpage = sbi->nbperpage;
+
+	/* get the page's starting extent offset */
+	xoff = pno << sbi->l2nbperpage;
+
+	/* check if an allocation hint was provided */
+	if ((hint = addressXAD(xp))) {
+		/* get the size of the extent described by the hint */
+		nxlen = lengthXAD(xp);
+
+		/* check if the hint is for the portion of the file
+		 * immediately previous to the current allocation
+		 * request and if hint extent has the same abnr
+		 * value as the current request.  if so, we can
+		 * extend the hint extent to include the current
+		 * extent if we can allocate the blocks immediately
+		 * following the hint extent.
+		 */
+		if (offsetXAD(xp) + nxlen == xoff &&
+		    abnr == ((xp->flag & XAD_NOTRECORDED) ? TRUE : FALSE))
+			xaddr = hint + nxlen;
+
+		/* adjust the hint to the last block of the extent */
+		hint += (nxlen - 1);
+	}
+
+	/* allocate the disk blocks for the extent.  initially, extBalloc()
+	 * will try to allocate disk blocks for the requested size (xlen). 
+	 * if this fails (xlen contigious free blocks not avaliable), it'll
+	 * try to allocate a smaller number of blocks (producing a smaller
+	 * extent), with this smaller number of blocks consisting of the
+	 * requested number of blocks rounded down to the next smaller
+	 * power of 2 number (i.e. 16 -> 8).  it'll continue to round down
+	 * and retry the allocation until the number of blocks to allocate
+	 * is smaller than the number of blocks per page.
+	 */
+	nxlen = xlen;
+	if ((rc = extBalloc(ip, hint ? hint : INOHINT(ip), &nxlen, &nxaddr))) {
+		up(&JFS_IP(ip)->commit_sem);
+		return (rc);
+	}
+
+	/* determine the value of the extent flag */
+	xflag = (abnr == TRUE) ? XAD_NOTRECORDED : 0;
+
+	/* if we can extend the hint extent to cover the current request, 
+	 * extend it.  otherwise, insert a new extent to
+	 * cover the current request.
+	 */
+	if (xaddr && xaddr == nxaddr)
+		rc = xtExtend(0, ip, xoff, (int) nxlen, 0);
+	else
+		rc = xtInsert(0, ip, xflag, xoff, (int) nxlen, &nxaddr, 0);
+
+	/* if the extend or insert failed, 
+	 * free the newly allocated blocks and return the error.
+	 */
+	if (rc) {
+		dbFree(ip, nxaddr, nxlen);
+		up(&JFS_IP(ip)->commit_sem);
+		return (rc);
+	}
+
+	/* update the number of blocks allocated to the file */
+	ip->i_blocks += LBLK2PBLK(ip->i_sb, nxlen);
+
+	/* set the results of the extent allocation */
+	XADaddress(xp, nxaddr);
+	XADlength(xp, nxlen);
+	XADoffset(xp, xoff);
+	xp->flag = xflag;
+
+	mark_inode_dirty(ip);
+
+	up(&JFS_IP(ip)->commit_sem);
+	/*
+	 * COMMIT_SyncList flags an anonymous tlock on page that is on
+	 * sync list.
+	 * We need to commit the inode to get the page written disk.
+	 */
+	if (test_and_clear_cflag(COMMIT_Synclist,ip))
+		jfs_commit_inode(ip, 0);
+
+	return (0);
+}
+
+
+#ifdef _NOTYET
+/*
+ * NAME:        extRealloc()
+ *
+ * FUNCTION:    extend the allocation of a file extent containing a
+ *		partial back last page.
+ *
+ * PARAMETERS:
+ *	ip	- the inode of the file.
+ *	cp	- cbuf for the partial backed last page.
+ *	xlen	- request size of the resulting extent.
+ *	xp	- pointer to an xad. on successful exit, the xad
+ *		  describes the newly allocated extent.
+ *	abnr	- boolean_t indicating whether the newly allocated extent
+ *		  should be marked as allocated but not recorded.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO	- i/o error.
+ *      ENOSPC	- insufficient disk resources.
+ */
+int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr)
+{
+	struct super_block *sb = ip->i_sb;
+	s64 xaddr, xlen, nxaddr, delta, xoff;
+	s64 ntail, nextend, ninsert;
+	int rc, nbperpage = JFS_SBI(sb)->nbperpage;
+	int xflag;
+
+	/* This blocks if we are low on resources */
+	txBeginAnon(ip->i_sb);
+
+	down(&JFS_IP(ip)->commit_sem);
+	/* validate extent length */
+	if (nxlen > MAXXLEN)
+		nxlen = MAXXLEN;
+
+	/* get the extend (partial) page's disk block address and
+	 * number of blocks.
+	 */
+	xaddr = addressXAD(xp);
+	xlen = lengthXAD(xp);
+	xoff = offsetXAD(xp);
+
+	/* if the extend page is abnr and if the request is for
+	 * the extent to be allocated and recorded, 
+	 * make the page allocated and recorded.
+	 */
+	if ((xp->flag & XAD_NOTRECORDED) && !abnr) {
+		xp->flag = 0;
+		if ((rc = xtUpdate(0, ip, xp)))
+			goto exit;
+	}
+
+	/* try to allocated the request number of blocks for the
+	 * extent.  dbRealloc() first tries to satisfy the request
+	 * by extending the allocation in place. otherwise, it will
+	 * try to allocate a new set of blocks large enough for the
+	 * request.  in satisfying a request, dbReAlloc() may allocate
+	 * less than what was request but will always allocate enough
+	 * space as to satisfy the extend page.
+	 */
+	if ((rc = extBrealloc(ip, xaddr, xlen, &nxlen, &nxaddr)))
+		goto exit;
+
+	delta = nxlen - xlen;
+
+	/* check if the extend page is not abnr but the request is abnr
+	 * and the allocated disk space is for more than one page.  if this
+	 * is the case, there is a miss match of abnr between the extend page
+	 * and the one or more pages following the extend page.  as a result,
+	 * two extents will have to be manipulated. the first will be that
+	 * of the extent of the extend page and will be manipulated thru
+	 * an xtExtend() or an xtTailgate(), depending upon whether the
+	 * disk allocation occurred as an inplace extension.  the second
+	 * extent will be manipulated (created) through an xtInsert() and
+	 * will be for the pages following the extend page.
+	 */
+	if (abnr && (!(xp->flag & XAD_NOTRECORDED)) && (nxlen > nbperpage)) {
+		ntail = nbperpage;
+		nextend = ntail - xlen;
+		ninsert = nxlen - nbperpage;
+
+		xflag = XAD_NOTRECORDED;
+	} else {
+		ntail = nxlen;
+		nextend = delta;
+		ninsert = 0;
+
+		xflag = xp->flag;
+	}
+
+	/* if we were able to extend the disk allocation in place,
+	 * extend the extent.  otherwise, move the extent to a
+	 * new disk location.
+	 */
+	if (xaddr == nxaddr) {
+		/* extend the extent */
+		if ((rc = xtExtend(0, ip, xoff + xlen, (int) nextend, 0))) {
+			dbFree(ip, xaddr + xlen, delta);
+			goto exit;
+		}
+	} else {
+		/*
+		 * move the extent to a new location:
+		 *
+		 * xtTailgate() accounts for relocated tail extent;
+		 */
+		if ((rc = xtTailgate(0, ip, xoff, (int) ntail, nxaddr, 0))) {
+			dbFree(ip, nxaddr, nxlen);
+			goto exit;
+		}
+	}
+
+
+	/* check if we need to also insert a new extent */
+	if (ninsert) {
+		/* perform the insert.  if it fails, free the blocks
+		 * to be inserted and make it appear that we only did
+		 * the xtExtend() or xtTailgate() above.
+		 */
+		xaddr = nxaddr + ntail;
+		if (xtInsert (0, ip, xflag, xoff + ntail, (int) ninsert,
+			      &xaddr, 0)) {
+			dbFree(ip, xaddr, (s64) ninsert);
+			delta = nextend;
+			nxlen = ntail;
+			xflag = 0;
+		}
+	}
+
+	/* update the inode with the number of blocks allocated */
+	ip->i_blocks += LBLK2PBLK(sb, delta);
+
+	/* set the return results */
+	XADaddress(xp, nxaddr);
+	XADlength(xp, nxlen);
+	XADoffset(xp, xoff);
+	xp->flag = xflag;
+
+	mark_inode_dirty(ip);
+exit:
+	up(&JFS_IP(ip)->commit_sem);
+	return (rc);
+}
+#endif			/* _NOTYET */
+
+
+/*
+ * NAME:        extHint()
+ *
+ * FUNCTION:    produce an extent allocation hint for a file offset.
+ *
+ * PARAMETERS:
+ *	ip	- the inode of the file.
+ *	offset  - file offset for which the hint is needed.
+ *	xp	- pointer to the xad that is to be filled in with
+ *		  the hint.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO	- i/o error.
+ */
+int extHint(struct inode *ip, s64 offset, xad_t * xp)
+{
+	struct super_block *sb = ip->i_sb;
+	struct xadlist xadl;
+	struct lxdlist lxdl;
+	lxd_t lxd;
+	s64 prev;
+	int rc, nbperpage = JFS_SBI(sb)->nbperpage;
+
+	/* init the hint as "no hint provided" */
+	XADaddress(xp, 0);
+
+	/* determine the starting extent offset of the page previous
+	 * to the page containing the offset.
+	 */
+	prev = ((offset & ~POFFSET) >> JFS_SBI(sb)->l2bsize) - nbperpage;
+
+	/* if the offsets in the first page of the file,
+	 * no hint provided.
+	 */
+	if (prev < 0)
+		return (0);
+
+	/* prepare to lookup the previous page's extent info */
+	lxdl.maxnlxd = 1;
+	lxdl.nlxd = 1;
+	lxdl.lxd = &lxd;
+	LXDoffset(&lxd, prev)
+	    LXDlength(&lxd, nbperpage);
+
+	xadl.maxnxad = 1;
+	xadl.nxad = 0;
+	xadl.xad = xp;
+
+	/* perform the lookup */
+	if ((rc = xtLookupList(ip, &lxdl, &xadl, 0)))
+		return (rc);
+
+	/* check if not extent exists for the previous page.  
+	 * this is possible for sparse files.
+	 */
+	if (xadl.nxad == 0) {
+//              assert(ISSPARSE(ip));
+		return (0);
+	}
+
+	/* only preserve the abnr flag within the xad flags
+	 * of the returned hint.
+	 */
+	xp->flag &= XAD_NOTRECORDED;
+
+	assert(xadl.nxad == 1);
+	assert(lengthXAD(xp) == nbperpage);
+
+	return (0);
+}
+
+
+/*
+ * NAME:        extRecord()
+ *
+ * FUNCTION:    change a page with a file from not recorded to recorded.
+ *
+ * PARAMETERS:
+ *	ip	- inode of the file.
+ *	cp	- cbuf of the file page.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO	- i/o error.
+ *      ENOSPC	- insufficient disk resources.
+ */
+int extRecord(struct inode *ip, xad_t * xp)
+{
+	int rc;
+
+	txBeginAnon(ip->i_sb);
+
+	down(&JFS_IP(ip)->commit_sem);
+
+	/* update the extent */
+	rc = xtUpdate(0, ip, xp);
+
+	up(&JFS_IP(ip)->commit_sem);
+	return (rc);
+}
+
+
+#ifdef _NOTYET
+/*
+ * NAME:        extFill()
+ *
+ * FUNCTION:    allocate disk space for a file page that represents
+ *		a file hole.
+ *
+ * PARAMETERS:
+ *	ip	- the inode of the file.
+ *	cp	- cbuf of the file page represent the hole.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO	- i/o error.
+ *      ENOSPC	- insufficient disk resources.
+ */
+int extFill(struct inode *ip, xad_t * xp)
+{
+	int rc, nbperpage = JFS_SBI(ip->i_sb)->nbperpage;
+	s64 blkno = offsetXAD(xp) >> ip->i_blksize;
+
+//      assert(ISSPARSE(ip));
+
+	/* initialize the extent allocation hint */
+	XADaddress(xp, 0);
+
+	/* allocate an extent to fill the hole */
+	if ((rc = extAlloc(ip, nbperpage, blkno, xp, FALSE)))
+		return (rc);
+
+	assert(lengthPXD(xp) == nbperpage);
+
+	return (0);
+}
+#endif			/* _NOTYET */
+
+
+/*
+ * NAME:	extBalloc()
+ *
+ * FUNCTION:    allocate disk blocks to form an extent.
+ *
+ *		initially, we will try to allocate disk blocks for the
+ *		requested size (nblocks).  if this fails (nblocks 
+ *		contigious free blocks not avaliable), we'll try to allocate
+ *		a smaller number of blocks (producing a smaller extent), with
+ *		this smaller number of blocks consisting of the requested
+ *		number of blocks rounded down to the next smaller power of 2
+ *		number (i.e. 16 -> 8).  we'll continue to round down and
+ *		retry the allocation until the number of blocks to allocate
+ *		is smaller than the number of blocks per page.
+ *		
+ * PARAMETERS:
+ *	ip	 - the inode of the file.
+ *	hint	 - disk block number to be used as an allocation hint.
+ *	*nblocks - pointer to an s64 value.  on entry, this value specifies
+ *		   the desired number of block to be allocated. on successful
+ *		   exit, this value is set to the number of blocks actually
+ *		   allocated.
+ *	blkno	 - pointer to a block address that is filled in on successful
+ *		   return with the starting block number of the newly 
+ *		   allocated block range.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO	- i/o error.
+ *      ENOSPC	- insufficient disk resources.
+ */
+static int
+extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno)
+{
+	struct jfs_inode_info *ji = JFS_IP(ip);
+	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
+	s64 nb, nblks, daddr, max;
+	int rc, nbperpage = sbi->nbperpage;
+	struct bmap *bmp = sbi->bmap;
+	int ag;
+
+	/* get the number of blocks to initially attempt to allocate.
+	 * we'll first try the number of blocks requested unless this
+	 * number is greater than the maximum number of contigious free
+	 * blocks in the map. in that case, we'll start off with the 
+	 * maximum free.
+	 */
+	max = (s64) 1 << bmp->db_maxfreebud;
+	if (*nblocks >= max && *nblocks > nbperpage)
+		nb = nblks = (max > nbperpage) ? max : nbperpage;
+	else
+		nb = nblks = *nblocks;
+
+	/* try to allocate blocks */
+	while ((rc = dbAlloc(ip, hint, nb, &daddr))) {
+		/* if something other than an out of space error,
+		 * stop and return this error.
+		 */
+		if (rc != ENOSPC)
+			return (rc);
+
+		/* decrease the allocation request size */
+		nb = min(nblks, extRoundDown(nb));
+
+		/* give up if we cannot cover a page */
+		if (nb < nbperpage)
+			return (rc);
+	}
+
+	*nblocks = nb;
+	*blkno = daddr;
+
+	if (S_ISREG(ip->i_mode) && (ji->fileset == FILESYSTEM_I)) {
+		ag = BLKTOAG(daddr, sbi);
+		if (ji->active_ag == -1) {
+			atomic_inc(&bmp->db_active[ag]);
+			ji->active_ag = ag;
+		} else if (ji->active_ag != ag) {
+			atomic_dec(&bmp->db_active[ji->active_ag]);
+			atomic_inc(&bmp->db_active[ag]);
+			ji->active_ag = ag;
+		}
+	}
+
+	return (0);
+}
+
+
+#ifdef _NOTYET
+/*
+ * NAME:	extBrealloc()
+ *
+ * FUNCTION:    attempt to extend an extent's allocation.
+ *
+ *		initially, we will try to extend the extent's allocation
+ *		in place.  if this fails, we'll try to move the extent
+ *		to a new set of blocks. if moving the extent, we initially
+ *		will try to allocate disk blocks for the requested size
+ *		(nnew).  if this fails 	(nnew contigious free blocks not
+ *		avaliable), we'll try  to allocate a smaller number of
+ *		blocks (producing a smaller extent), with this smaller
+ *		number of blocks consisting of the requested number of
+ *		blocks rounded down to the next smaller power of 2
+ *		number (i.e. 16 -> 8).  we'll continue to round down and
+ *		retry the allocation until the number of blocks to allocate
+ *		is smaller than the number of blocks per page.
+ *		
+ * PARAMETERS:
+ *	ip	 - the inode of the file.
+ *	blkno    - starting block number of the extents current allocation.
+ *	nblks    - number of blocks within the extents current allocation.
+ *	newnblks - pointer to a s64 value.  on entry, this value is the
+ *		   the new desired extent size (number of blocks).  on
+ *		   successful exit, this value is set to the extent's actual
+ *		   new size (new number of blocks).
+ *	newblkno - the starting block number of the extents new allocation.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO	- i/o error.
+ *      ENOSPC	- insufficient disk resources.
+ */
+static int
+extBrealloc(struct inode *ip,
+	    s64 blkno, s64 nblks, s64 * newnblks, s64 * newblkno)
+{
+	int rc;
+
+	/* try to extend in place */
+	if ((rc = dbExtend(ip, blkno, nblks, *newnblks - nblks)) == 0) {
+		*newblkno = blkno;
+		return (0);
+	} else {
+		if (rc != ENOSPC)
+			return (rc);
+	}
+
+	/* in place extension not possible.  
+	 * try to move the extent to a new set of blocks.
+	 */
+	return (extBalloc(ip, blkno, newnblks, newblkno));
+}
+#endif			/* _NOTYET */
+
+
+/*
+ * NAME:        extRoundDown()
+ *
+ * FUNCTION:    round down a specified number of blocks to the next
+ *		smallest power of 2 number.
+ *
+ * PARAMETERS:
+ *	nb	- the inode of the file.
+ *
+ * RETURN VALUES:
+ *      next smallest power of 2 number.
+ */
+static s64 extRoundDown(s64 nb)
+{
+	int i;
+	u64 m, k;
+
+	for (i = 0, m = (u64) 1 << 63; i < 64; i++, m >>= 1) {
+		if (m & nb)
+			break;
+	}
+
+	i = 63 - i;
+	k = (u64) 1 << i;
+	k = ((k - 1) & nb) ? k : k >> 1;
+
+	return (k);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_extent.h linux-2.4.20/fs/jfs/jfs_extent.h
--- linux-2.4.19/fs/jfs/jfs_extent.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_extent.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,31 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2001
+ *
+ *   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
+ */
+#ifndef	_H_JFS_EXTENT
+#define _H_JFS_EXTENT
+
+/*  get block allocation allocation hint as location of disk inode */
+#define	INOHINT(ip)	\
+	(addressPXD(&(JFS_IP(ip)->ixpxd)) + lengthPXD(&(JFS_IP(ip)->ixpxd)) - 1)
+
+extern int	extAlloc(struct inode *, s64, s64, xad_t *, boolean_t);
+extern int	extFill(struct inode *, xad_t *);
+extern int	extHint(struct inode *, s64, xad_t *);
+extern int	extRealloc(struct inode *, s64, xad_t *, boolean_t);
+extern int	extRecord(struct inode *, xad_t *);
+
+#endif	/* _H_JFS_EXTENT */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_filsys.h linux-2.4.20/fs/jfs/jfs_filsys.h
--- linux-2.4.19/fs/jfs/jfs_filsys.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_filsys.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,272 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2001
+ *
+ *   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
+ */
+#ifndef _H_JFS_FILSYS
+#define _H_JFS_FILSYS
+
+/*
+ *	jfs_filsys.h
+ *
+ * file system (implementation-dependent) constants 
+ *
+ * refer to <limits.h> for system wide implementation-dependent constants 
+ */
+
+/*
+ *	 file system option (superblock flag)
+ */
+/* platform option (conditional compilation) */
+#define JFS_AIX		0x80000000	/* AIX support */
+/*	POSIX name/directory  support */
+
+#define JFS_OS2		0x40000000	/* OS/2 support */
+/*	case-insensitive name/directory support */
+
+#define JFS_DFS		0x20000000	/* DCE DFS LFS support */
+
+#define JFS_LINUX      	0x10000000	/* Linux support */
+/*	case-sensitive name/directory support */
+
+/* directory option */
+#define JFS_UNICODE	0x00000001	/* unicode name */
+
+/* commit option */
+#define	JFS_COMMIT	0x00000f00	/* commit option mask */
+#define	JFS_GROUPCOMMIT	0x00000100	/* group (of 1) commit */
+#define	JFS_LAZYCOMMIT	0x00000200	/* lazy commit */
+#define	JFS_TMPFS	0x00000400	/* temporary file system - 
+					 * do not log/commit:
+					 */
+
+/* log logical volume option */
+#define	JFS_INLINELOG	0x00000800	/* inline log within file system */
+#define JFS_INLINEMOVE	0x00001000	/* inline log being moved */
+
+/* Secondary aggregate inode table */
+#define JFS_BAD_SAIT	0x00010000	/* current secondary ait is bad */
+
+/* sparse regular file support */
+#define JFS_SPARSE	0x00020000	/* sparse regular file */
+
+/* DASD Limits		F226941 */
+#define JFS_DASD_ENABLED	0x00040000	/* DASD limits enabled */
+#define	JFS_DASD_PRIME		0x00080000	/* Prime DASD usage on boot */
+
+/* big endian flag */
+#define	JFS_SWAP_BYTES		0x00100000	/* running on big endian computer */
+
+/* Directory index */
+#define JFS_DIR_INDEX		0x00200000	/* Persistant index for */
+						/* directory entries    */
+
+
+/*
+ *	buffer cache configuration
+ */
+/* page size */
+#ifdef PSIZE
+#undef PSIZE
+#endif
+#define	PSIZE		4096	/* page size (in byte) */
+#define	L2PSIZE		12	/* log2(PSIZE) */
+#define	POFFSET		4095	/* offset within page */
+
+/* buffer page size */
+#define BPSIZE	PSIZE
+
+/*
+ *	fs fundamental size
+ *
+ * PSIZE >= file system block size >= PBSIZE >= DISIZE
+ */
+#define	PBSIZE		512	/* physical block size (in byte) */
+#define	L2PBSIZE	9	/* log2(PBSIZE) */
+
+#define DISIZE		512	/* on-disk inode size (in byte) */
+#define L2DISIZE	9	/* log2(DISIZE) */
+
+#define IDATASIZE	256	/* inode inline data size */
+#define	IXATTRSIZE	128	/* inode inline extended attribute size */
+
+#define XTPAGE_SIZE     4096
+#define log2_PAGESIZE     12
+
+#define IAG_SIZE        4096
+#define IAG_EXTENT_SIZE 4096
+#define	INOSPERIAG	4096	/* number of disk inodes per iag */
+#define	L2INOSPERIAG	12	/* l2 number of disk inodes per iag */
+#define INOSPEREXT	32	/* number of disk inode per extent */
+#define L2INOSPEREXT	5	/* l2 number of disk inode per extent */
+#define	IXSIZE		(DISIZE * INOSPEREXT)	/* inode extent size */
+#define	INOSPERPAGE	8	/* number of disk inodes per 4K page */
+#define	L2INOSPERPAGE	3	/* log2(INOSPERPAGE) */
+
+#define	IAGFREELIST_LWM	64
+
+#define INODE_EXTENT_SIZE	IXSIZE	/* inode extent size */
+#define NUM_INODE_PER_EXTENT	INOSPEREXT
+#define NUM_INODE_PER_IAG	INOSPERIAG
+
+#define MINBLOCKSIZE		512
+#define MAXBLOCKSIZE		4096
+#define	MAXFILESIZE		((s64)1 << 52)
+
+#define JFS_LINK_MAX		65535	/* nlink_t is unsigned short */
+
+/* Minimum number of bytes supported for a JFS partition */
+#define MINJFS			(0x1000000)
+#define MINJFSTEXT		"16"
+
+/*
+ * file system block size -> physical block size
+ */
+#define LBOFFSET(x)	((x) & (PBSIZE - 1))
+#define LBNUMBER(x)	((x) >> L2PBSIZE)
+#define	LBLK2PBLK(sb,b)	((b) << (sb->s_blocksize_bits - L2PBSIZE))
+#define	PBLK2LBLK(sb,b)	((b) >> (sb->s_blocksize_bits - L2PBSIZE))
+/* size in byte -> last page number */
+#define	SIZE2PN(size)	( ((s64)((size) - 1)) >> (L2PSIZE) )
+/* size in byte -> last file system block number */
+#define	SIZE2BN(size, l2bsize) ( ((s64)((size) - 1)) >> (l2bsize) )
+
+/*
+ * fixed physical block address (physical block size = 512 byte)
+ *
+ * NOTE: since we can't guarantee a physical block size of 512 bytes the use of
+ *	 these macros should be removed and the byte offset macros used instead.
+ */
+#define SUPER1_B	64	/* primary superblock */
+#define	AIMAP_B		(SUPER1_B + 8)	/* 1st extent of aggregate inode map */
+#define	AITBL_B		(AIMAP_B + 16)	/*
+					 * 1st extent of aggregate inode table
+					 */
+#define	SUPER2_B	(AITBL_B + 32)	/* 2ndary superblock pbn */
+#define	BMAP_B		(SUPER2_B + 8)	/* block allocation map */
+
+/*
+ * SIZE_OF_SUPER defines the total amount of space reserved on disk for the
+ * superblock.  This is not the same as the superblock structure, since all of
+ * this space is not currently being used.
+ */
+#define SIZE_OF_SUPER	PSIZE
+
+/*
+ * SIZE_OF_AG_TABLE defines the amount of space reserved to hold the AG table
+ */
+#define SIZE_OF_AG_TABLE	PSIZE
+
+/*
+ * SIZE_OF_MAP_PAGE defines the amount of disk space reserved for each page of
+ * the inode allocation map (to hold iag)
+ */
+#define SIZE_OF_MAP_PAGE	PSIZE
+
+/*
+ * fixed byte offset address
+ */
+#define SUPER1_OFF	0x8000	/* primary superblock */
+#define AIMAP_OFF	(SUPER1_OFF + SIZE_OF_SUPER)
+					/*
+					 * Control page of aggregate inode map
+					 * followed by 1st extent of map
+					 */
+#define AITBL_OFF	(AIMAP_OFF + (SIZE_OF_MAP_PAGE << 1))
+					/* 
+					 * 1st extent of aggregate inode table
+					 */
+#define SUPER2_OFF	(AITBL_OFF + INODE_EXTENT_SIZE)
+					/*
+					 * secondary superblock
+					 */
+#define BMAP_OFF	(SUPER2_OFF + SIZE_OF_SUPER)
+					/*
+					 * block allocation map
+					 */
+
+/*
+ * The following macro is used to indicate the number of reserved disk blocks at
+ * the front of an aggregate, in terms of physical blocks.  This value is
+ * currently defined to be 32K.  This turns out to be the same as the primary
+ * superblock's address, since it directly follows the reserved blocks.
+ */
+#define AGGR_RSVD_BLOCKS	SUPER1_B
+
+/*
+ * The following macro is used to indicate the number of reserved bytes at the
+ * front of an aggregate.  This value is currently defined to be 32K.  This
+ * turns out to be the same as the primary superblock's byte offset, since it
+ * directly follows the reserved blocks.
+ */
+#define AGGR_RSVD_BYTES	SUPER1_OFF
+
+/*
+ * The following macro defines the byte offset for the first inode extent in
+ * the aggregate inode table.  This allows us to find the self inode to find the
+ * rest of the table.  Currently this value is 44K.
+ */
+#define AGGR_INODE_TABLE_START	AITBL_OFF
+
+/*
+ *	fixed reserved inode number
+ */
+/* aggregate inode */
+#define AGGR_RESERVED_I	0	/* aggregate inode (reserved) */
+#define	AGGREGATE_I	1	/* aggregate inode map inode */
+#define	BMAP_I		2	/* aggregate block allocation map inode */
+#define	LOG_I		3	/* aggregate inline log inode */
+#define BADBLOCK_I	4	/* aggregate bad block inode */
+#define	FILESYSTEM_I	16	/* 1st/only fileset inode in ait:
+				 * fileset inode map inode
+				 */
+
+/* per fileset inode */
+#define FILESET_RSVD_I	0	/* fileset inode (reserved) */
+#define FILESET_EXT_I	1	/* fileset inode extension */
+#define	ROOT_I		2	/* fileset root inode */
+#define ACL_I		3	/* fileset ACL inode */
+
+#define FILESET_OBJECT_I 4	/* the first fileset inode available for a file
+				 * or directory or link...
+				 */
+#define FIRST_FILESET_INO 16	/* the first aggregate inode which describes
+				 * an inode.  (To fsck this is also the first
+				 * inode in part 2 of the agg inode table.)
+				 */
+
+/*
+ *	directory configuration
+ */
+#define JFS_NAME_MAX	255
+#define JFS_PATH_MAX	BPSIZE
+
+
+/*
+ *	file system state (superblock state)
+ */
+#define FM_CLEAN 0x00000000	/* file system is unmounted and clean */
+#define FM_MOUNT 0x00000001	/* file system is mounted cleanly */
+#define FM_DIRTY 0x00000002	/* file system was not unmounted and clean 
+				 * when mounted or 
+				 * commit failure occurred while being mounted:
+				 * fsck() must be run to repair 
+				 */
+#define	FM_LOGREDO 0x00000004	/* log based recovery (logredo()) failed:
+				 * fsck() must be run to repair 
+				 */
+#define	FM_EXTENDFS 0x00000008	/* file system extendfs() in progress */
+
+#endif				/* _H_JFS_FILSYS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_imap.c linux-2.4.20/fs/jfs/jfs_imap.c
--- linux-2.4.19/fs/jfs/jfs_imap.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_imap.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,3202 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+
+/*
+ *	jfs_imap.c: inode allocation map manager
+ *
+ * Serialization:
+ *   Each AG has a simple lock which is used to control the serialization of
+ *	the AG level lists.  This lock should be taken first whenever an AG
+ *	level list will be modified or accessed.
+ *
+ *   Each IAG is locked by obtaining the buffer for the IAG page.
+ *
+ *   There is also a inode lock for the inode map inode.  A read lock needs to
+ *	be taken whenever an IAG is read from the map or the global level
+ *	information is read.  A write lock needs to be taken whenever the global
+ *	level information is modified or an atomic operation needs to be used.
+ *
+ *	If more than one IAG is read at one time, the read lock may not
+ *	be given up until all of the IAG's are read.  Otherwise, a deadlock
+ *	may occur when trying to obtain the read lock while another thread
+ *	holding the read lock is waiting on the IAG already being held.
+ *
+ *   The control page of the inode map is read into memory by diMount().
+ *	Thereafter it should only be modified in memory and then it will be
+ *	written out when the filesystem is unmounted by diUnmount().
+ */
+
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_dinode.h"
+#include "jfs_dmap.h"
+#include "jfs_imap.h"
+#include "jfs_metapage.h"
+#include "jfs_superblock.h"
+#include "jfs_debug.h"
+
+/*
+ * imap locks
+ */
+/* iag free list lock */
+#define IAGFREE_LOCK_INIT(imap)		init_MUTEX(&imap->im_freelock)
+#define IAGFREE_LOCK(imap)		down(&imap->im_freelock)
+#define IAGFREE_UNLOCK(imap)		up(&imap->im_freelock)
+
+/* per ag iag list locks */
+#define AG_LOCK_INIT(imap,index)	init_MUTEX(&(imap->im_aglock[index]))
+#define AG_LOCK(imap,agno)		down(&imap->im_aglock[agno])
+#define AG_UNLOCK(imap,agno)		up(&imap->im_aglock[agno])
+
+/*
+ * external references
+ */
+extern struct address_space_operations jfs_aops;
+
+/*
+ * forward references
+ */
+static int diAllocAG(struct inomap *, int, boolean_t, struct inode *);
+static int diAllocAny(struct inomap *, int, boolean_t, struct inode *);
+static int diAllocBit(struct inomap *, struct iag *, int);
+static int diAllocExt(struct inomap *, int, struct inode *);
+static int diAllocIno(struct inomap *, int, struct inode *);
+static int diFindFree(u32, int);
+static int diNewExt(struct inomap *, struct iag *, int);
+static int diNewIAG(struct inomap *, int *, int, struct metapage **);
+static void duplicateIXtree(struct super_block *, s64, int, s64 *);
+
+static int diIAGRead(struct inomap * imap, int, struct metapage **);
+static int copy_from_dinode(struct dinode *, struct inode *);
+static void copy_to_dinode(struct dinode *, struct inode *);
+
+/*
+ *	debug code for double-checking inode map
+ */
+/* #define	_JFS_DEBUG_IMAP	1 */
+
+#ifdef	_JFS_DEBUG_IMAP
+#define DBG_DIINIT(imap)	DBGdiInit(imap)
+#define DBG_DIALLOC(imap, ino)	DBGdiAlloc(imap, ino)
+#define DBG_DIFREE(imap, ino)	DBGdiFree(imap, ino)
+
+static void *DBGdiInit(struct inomap * imap);
+static void DBGdiAlloc(struct inomap * imap, ino_t ino);
+static void DBGdiFree(struct inomap * imap, ino_t ino);
+#else
+#define DBG_DIINIT(imap)
+#define DBG_DIALLOC(imap, ino)
+#define DBG_DIFREE(imap, ino)
+#endif				/* _JFS_DEBUG_IMAP */
+
+/*
+ * NAME:        diMount()
+ *
+ * FUNCTION:    initialize the incore inode map control structures for
+ *		a fileset or aggregate init time.
+ *
+ *              the inode map's control structure (dinomap) is 
+ *              brought in from disk and placed in virtual memory.
+ *
+ * PARAMETERS:
+ *      ipimap  - pointer to inode map inode for the aggregate or fileset.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      ENOMEM  - insufficient free virtual memory.
+ *      EIO  	- i/o error.
+ */
+int diMount(struct inode *ipimap)
+{
+	struct inomap *imap;
+	struct metapage *mp;
+	int index;
+	struct dinomap *dinom_le;
+
+	/*
+	 * allocate/initialize the in-memory inode map control structure
+	 */
+	/* allocate the in-memory inode map control structure. */
+	imap = (struct inomap *) kmalloc(sizeof(struct inomap), GFP_KERNEL);
+	if (imap == NULL) {
+		jERROR(1, ("diMount: kmalloc returned NULL!\n"));
+		return (ENOMEM);
+	}
+
+	/* read the on-disk inode map control structure. */
+
+	mp = read_metapage(ipimap,
+			   IMAPBLKNO << JFS_SBI(ipimap->i_sb)->l2nbperpage,
+			   PSIZE, 0);
+	if (mp == NULL) {
+		kfree(imap);
+		return (EIO);
+	}
+
+	/* copy the on-disk version to the in-memory version. */
+	dinom_le = (struct dinomap *) mp->data;
+	imap->im_freeiag = le32_to_cpu(dinom_le->in_freeiag);
+	imap->im_nextiag = le32_to_cpu(dinom_le->in_nextiag);
+	atomic_set(&imap->im_numinos, le32_to_cpu(dinom_le->in_numinos));
+	atomic_set(&imap->im_numfree, le32_to_cpu(dinom_le->in_numfree));
+	imap->im_nbperiext = le32_to_cpu(dinom_le->in_nbperiext);
+	imap->im_l2nbperiext = le32_to_cpu(dinom_le->in_l2nbperiext);
+	for (index = 0; index < MAXAG; index++) {
+		imap->im_agctl[index].inofree =
+		    le32_to_cpu(dinom_le->in_agctl[index].inofree);
+		imap->im_agctl[index].extfree =
+		    le32_to_cpu(dinom_le->in_agctl[index].extfree);
+		imap->im_agctl[index].numinos =
+		    le32_to_cpu(dinom_le->in_agctl[index].numinos);
+		imap->im_agctl[index].numfree =
+		    le32_to_cpu(dinom_le->in_agctl[index].numfree);
+	}
+
+	/* release the buffer. */
+	release_metapage(mp);
+
+	/*
+	 * allocate/initialize inode allocation map locks
+	 */
+	/* allocate and init iag free list lock */
+	IAGFREE_LOCK_INIT(imap);
+
+	/* allocate and init ag list locks */
+	for (index = 0; index < MAXAG; index++) {
+		AG_LOCK_INIT(imap, index);
+	}
+
+	/* bind the inode map inode and inode map control structure
+	 * to each other.
+	 */
+	imap->im_ipimap = ipimap;
+	JFS_IP(ipimap)->i_imap = imap;
+
+//      DBG_DIINIT(imap);
+
+	return (0);
+}
+
+
+/*
+ * NAME:        diUnmount()
+ *
+ * FUNCTION:    write to disk the incore inode map control structures for
+ *		a fileset or aggregate at unmount time.
+ *
+ * PARAMETERS:
+ *      ipimap  - pointer to inode map inode for the aggregate or fileset.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      ENOMEM  - insufficient free virtual memory.
+ *      EIO  	- i/o error.
+ */
+int diUnmount(struct inode *ipimap, int mounterror)
+{
+	struct inomap *imap = JFS_IP(ipimap)->i_imap;
+
+	/*
+	 * update the on-disk inode map control structure
+	 */
+
+	if (!(mounterror || isReadOnly(ipimap)))
+		diSync(ipimap);
+
+	/*
+	 * Invalidate the page cache buffers
+	 */
+	truncate_inode_pages(ipimap->i_mapping, 0);
+
+	/*
+	 * free in-memory control structure
+	 */
+	kfree(imap);
+
+	return (0);
+}
+
+
+/*
+ *	diSync()
+ */
+int diSync(struct inode *ipimap)
+{
+	struct dinomap *dinom_le;
+	struct inomap *imp = JFS_IP(ipimap)->i_imap;
+	struct metapage *mp;
+	int index;
+
+	/*
+	 * write imap global conrol page
+	 */
+	/* read the on-disk inode map control structure */
+	mp = get_metapage(ipimap,
+			  IMAPBLKNO << JFS_SBI(ipimap->i_sb)->l2nbperpage,
+			  PSIZE, 0);
+	if (mp == NULL) {
+		jERROR(1,("diSync: get_metapage failed!\n"));
+		return EIO;
+	}
+
+	/* copy the in-memory version to the on-disk version */
+	dinom_le = (struct dinomap *) mp->data;
+	dinom_le->in_freeiag = cpu_to_le32(imp->im_freeiag);
+	dinom_le->in_nextiag = cpu_to_le32(imp->im_nextiag);
+	dinom_le->in_numinos = cpu_to_le32(atomic_read(&imp->im_numinos));
+	dinom_le->in_numfree = cpu_to_le32(atomic_read(&imp->im_numfree));
+	dinom_le->in_nbperiext = cpu_to_le32(imp->im_nbperiext);
+	dinom_le->in_l2nbperiext = cpu_to_le32(imp->im_l2nbperiext);
+	for (index = 0; index < MAXAG; index++) {
+		dinom_le->in_agctl[index].inofree =
+		    cpu_to_le32(imp->im_agctl[index].inofree);
+		dinom_le->in_agctl[index].extfree =
+		    cpu_to_le32(imp->im_agctl[index].extfree);
+		dinom_le->in_agctl[index].numinos =
+		    cpu_to_le32(imp->im_agctl[index].numinos);
+		dinom_le->in_agctl[index].numfree =
+		    cpu_to_le32(imp->im_agctl[index].numfree);
+	}
+
+	/* write out the control structure */
+	write_metapage(mp);
+
+	/*
+	 * write out dirty pages of imap
+	 */
+	fsync_inode_data_buffers(ipimap);
+
+	diWriteSpecial(ipimap, 0);
+
+	return (0);
+}
+
+
+/*
+ * NAME:        diRead()
+ *
+ * FUNCTION:    initialize an incore inode from disk.
+ *
+ *		on entry, the specifed incore inode should itself
+ *		specify the disk inode number corresponding to the
+ *		incore inode (i.e. i_number should be initialized).
+ *		
+ *		this routine handles incore inode initialization for
+ *		both "special" and "regular" inodes.  special inodes
+ *		are those required early in the mount process and
+ *	        require special handling since much of the file system
+ *		is not yet initialized.  these "special" inodes are
+ *		identified by a NULL inode map inode pointer and are
+ *		actually initialized by a call to diReadSpecial().
+ *		
+ *		for regular inodes, the iag describing the disk inode
+ *		is read from disk to determine the inode extent address
+ *		for the disk inode.  with the inode extent address in
+ *		hand, the page of the extent that contains the disk
+ *		inode is read and the disk inode is copied to the
+ *		incore inode.
+ *
+ * PARAMETERS:
+ *      ip  -  pointer to incore inode to be initialized from disk.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO  	- i/o error.
+ *      ENOMEM	- insufficient memory
+ *      
+ */
+int diRead(struct inode *ip)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
+	int iagno, ino, extno, rc;
+	struct inode *ipimap;
+	struct dinode *dp;
+	struct iag *iagp;
+	struct metapage *mp;
+	s64 blkno, agstart;
+	struct inomap *imap;
+	int block_offset;
+	int inodes_left;
+	uint pageno;
+	int rel_inode;
+
+	jFYI(1, ("diRead: ino = %ld\n", ip->i_ino));
+
+	ipimap = sbi->ipimap;
+	JFS_IP(ip)->ipimap = ipimap;
+
+	/* determine the iag number for this inode (number) */
+	iagno = INOTOIAG(ip->i_ino);
+
+	/* read the iag */
+	imap = JFS_IP(ipimap)->i_imap;
+	IREAD_LOCK(ipimap);
+	rc = diIAGRead(imap, iagno, &mp);
+	IREAD_UNLOCK(ipimap);
+	if (rc) {
+		jERROR(1, ("diRead: diIAGRead returned %d\n", rc));
+		return (rc);
+	}
+
+	iagp = (struct iag *) mp->data;
+
+	/* determine inode extent that holds the disk inode */
+	ino = ip->i_ino & (INOSPERIAG - 1);
+	extno = ino >> L2INOSPEREXT;
+
+	if ((lengthPXD(&iagp->inoext[extno]) != imap->im_nbperiext) ||
+	    (addressPXD(&iagp->inoext[extno]) == 0)) {
+		release_metapage(mp);
+		return ESTALE;
+	}
+
+	/* get disk block number of the page within the inode extent
+	 * that holds the disk inode.
+	 */
+	blkno = INOPBLK(&iagp->inoext[extno], ino, sbi->l2nbperpage);
+
+	/* get the ag for the iag */
+	agstart = le64_to_cpu(iagp->agstart);
+
+	release_metapage(mp);
+
+	rel_inode = (ino & (INOSPERPAGE - 1));
+	pageno = blkno >> sbi->l2nbperpage;
+
+	if ((block_offset = ((u32) blkno & (sbi->nbperpage - 1)))) {
+		/*
+		 * OS/2 didn't always align inode extents on page boundaries
+		 */
+		inodes_left =
+		     (sbi->nbperpage - block_offset) << sbi->l2niperblk;
+
+		if (rel_inode < inodes_left)
+			rel_inode += block_offset << sbi->l2niperblk;
+		else {
+			pageno += 1;
+			rel_inode -= inodes_left;
+		}
+	}
+
+	/* read the page of disk inode */
+	mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1);
+	if (mp == 0) {
+		jERROR(1, ("diRead: read_metapage failed\n"));
+		return EIO;
+	}
+
+	/* locate the the disk inode requested */
+	dp = (struct dinode *) mp->data;
+	dp += rel_inode;
+
+	if (ip->i_ino != le32_to_cpu(dp->di_number)) {
+		jERROR(1, ("diRead: i_ino != di_number\n"));
+		updateSuper(ip->i_sb, FM_DIRTY);
+		rc = EIO;
+	} else if (le32_to_cpu(dp->di_nlink) == 0)
+		rc = ESTALE;
+	else
+		/* copy the disk inode to the in-memory inode */
+		rc = copy_from_dinode(dp, ip);
+
+	release_metapage(mp);
+
+	/* set the ag for the inode */
+	JFS_IP(ip)->agno = BLKTOAG(agstart, sbi);
+	JFS_IP(ip)->active_ag = -1;
+
+	return (rc);
+}
+
+
+/*
+ * NAME:        diReadSpecial()
+ *
+ * FUNCTION:    initialize a 'special' inode from disk.
+ *
+ *		this routines handles aggregate level inodes.  The
+ *		inode cache cannot differentiate between the
+ *		aggregate inodes and the filesystem inodes, so we
+ *		handle these here.  We don't actually use the aggregate
+ *	        inode map, since these inodes are at a fixed location
+ *		and in some cases the aggregate inode map isn't initialized
+ *		yet.
+ *
+ * PARAMETERS:
+ *      sb - filesystem superblock
+ *	inum - aggregate inode number
+ *	secondary - 1 if secondary aggregate inode table
+ *
+ * RETURN VALUES:
+ *      new inode	- success
+ *      NULL		- i/o error.
+ */
+struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	uint address;
+	struct dinode *dp;
+	struct inode *ip;
+	struct metapage *mp;
+	int rc;
+
+	ip = new_inode(sb);
+	if (ip == NULL) {
+		jERROR(1,
+		       ("diReadSpecial: new_inode returned NULL!\n"));
+		return ip;
+	}
+
+	rc = alloc_jfs_inode(ip);
+	if (rc) {
+		make_bad_inode(ip);
+		iput(ip);
+		return NULL;
+	}
+
+	if (secondary) {
+		address = addressPXD(&sbi->ait2) >> sbi->l2nbperpage;
+		JFS_IP(ip)->ipimap = sbi->ipaimap2;
+	} else {
+		address = AITBL_OFF >> L2PSIZE;
+		JFS_IP(ip)->ipimap = sbi->ipaimap;
+	}
+
+	ASSERT(inum < INOSPEREXT);
+
+	ip->i_ino = inum;
+
+	address += inum >> 3;	/* 8 inodes per 4K page */
+
+	/* read the page of fixed disk inode (AIT) in raw mode */
+	jEVENT(0,
+	       ("Reading aggregate inode %d from block %d\n", (uint) inum,
+		address));
+	mp = read_metapage(ip, address << sbi->l2nbperpage, PSIZE, 1);
+	if (mp == NULL) {
+		ip->i_sb = NULL;
+		ip->i_nlink = 1;	/* Don't want iput() deleting it */
+		iput(ip);
+		return (NULL);
+	}
+
+	/* get the pointer to the disk inode of interest */
+	dp = (struct dinode *) (mp->data);
+	dp += inum % 8;		/* 8 inodes per 4K page */
+
+	/* copy on-disk inode to in-memory inode */
+	if ((copy_from_dinode(dp, ip)) != 0) {
+		/* handle bad return by returning NULL for ip */
+		ip->i_sb = NULL;
+		ip->i_nlink = 1;	/* Don't want iput() deleting it */
+		iput(ip);
+		/* release the page */
+		release_metapage(mp);
+		return (NULL);
+
+	}
+
+	ip->i_mapping->a_ops = &jfs_aops;
+	ip->i_mapping->gfp_mask = GFP_NOFS;
+
+	if ((inum == FILESYSTEM_I) && (JFS_IP(ip)->ipimap == sbi->ipaimap)) {
+		sbi->gengen = le32_to_cpu(dp->di_gengen);
+		sbi->inostamp = le32_to_cpu(dp->di_inostamp);
+	}
+
+	/* release the page */
+	release_metapage(mp);
+
+	return (ip);
+}
+
+/*
+ * NAME:        diWriteSpecial()
+ *
+ * FUNCTION:    Write the special inode to disk
+ *
+ * PARAMETERS:
+ *      ip - special inode
+ *	secondary - 1 if secondary aggregate inode table
+ *
+ * RETURN VALUES: none
+ */
+
+void diWriteSpecial(struct inode *ip, int secondary)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
+	uint address;
+	struct dinode *dp;
+	ino_t inum = ip->i_ino;
+	struct metapage *mp;
+
+	ip->i_state &= ~I_DIRTY;
+
+	if (secondary)
+		address = addressPXD(&sbi->ait2) >> sbi->l2nbperpage;
+	else
+		address = AITBL_OFF >> L2PSIZE;
+
+	ASSERT(inum < INOSPEREXT);
+
+	address += inum >> 3;	/* 8 inodes per 4K page */
+
+	/* read the page of fixed disk inode (AIT) in raw mode */
+	jEVENT(0,
+	       ("Reading aggregate inode %d from block %d\n", (uint) inum,
+		address));
+	mp = read_metapage(ip, address << sbi->l2nbperpage, PSIZE, 1);
+	if (mp == NULL) {
+		jERROR(1,
+		       ("diWriteSpecial: failed to read aggregate inode extent!\n"));
+		return;
+	}
+
+	/* get the pointer to the disk inode of interest */
+	dp = (struct dinode *) (mp->data);
+	dp += inum % 8;		/* 8 inodes per 4K page */
+
+	/* copy on-disk inode to in-memory inode */
+	copy_to_dinode(dp, ip);
+	memcpy(&dp->di_xtroot, &JFS_IP(ip)->i_xtroot, 288);
+
+	if (inum == FILESYSTEM_I)
+		dp->di_gengen = cpu_to_le32(sbi->gengen);
+
+	/* write the page */
+	write_metapage(mp);
+}
+
+/*
+ * NAME:        diFreeSpecial()
+ *
+ * FUNCTION:    Free allocated space for special inode
+ */
+void diFreeSpecial(struct inode *ip)
+{
+	if (ip == NULL) {
+		jERROR(1, ("diFreeSpecial called with NULL ip!\n"));
+		return;
+	}
+	fsync_inode_data_buffers(ip);
+	truncate_inode_pages(ip->i_mapping, 0);
+	iput(ip);
+}
+
+
+
+/*
+ * NAME:        diWrite()
+ *
+ * FUNCTION:    write the on-disk inode portion of the in-memory inode
+ *		to its corresponding on-disk inode.
+ *
+ *		on entry, the specifed incore inode should itself
+ *		specify the disk inode number corresponding to the
+ *		incore inode (i.e. i_number should be initialized).
+ *
+ *		the inode contains the inode extent address for the disk
+ *		inode.  with the inode extent address in hand, the
+ *		page of the extent that contains the disk inode is
+ *		read and the disk inode portion of the incore inode
+ *		is copied to the disk inode.
+ *		
+ * PARAMETERS:
+ *	tid -  transacation id
+ *      ip  -  pointer to incore inode to be written to the inode extent.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO  	- i/o error.
+ */
+int diWrite(tid_t tid, struct inode *ip)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	int rc = 0;
+	s32 ino;
+	struct dinode *dp;
+	s64 blkno;
+	int block_offset;
+	int inodes_left;
+	struct metapage *mp;
+	uint pageno;
+	int rel_inode;
+	int dioffset;
+	struct inode *ipimap;
+	uint type;
+	lid_t lid;
+	struct tlock *ditlck, *tlck;
+	struct linelock *dilinelock, *ilinelock;
+	struct lv *lv;
+	int n;
+
+	ipimap = jfs_ip->ipimap;
+
+	ino = ip->i_ino & (INOSPERIAG - 1);
+
+	assert(lengthPXD(&(jfs_ip->ixpxd)) ==
+	       JFS_IP(ipimap)->i_imap->im_nbperiext);
+	assert(addressPXD(&(jfs_ip->ixpxd)));
+
+	/*
+	 * read the page of disk inode containing the specified inode:
+	 */
+	/* compute the block address of the page */
+	blkno = INOPBLK(&(jfs_ip->ixpxd), ino, sbi->l2nbperpage);
+
+	rel_inode = (ino & (INOSPERPAGE - 1));
+	pageno = blkno >> sbi->l2nbperpage;
+
+	if ((block_offset = ((u32) blkno & (sbi->nbperpage - 1)))) {
+		/*
+		 * OS/2 didn't always align inode extents on page boundaries
+		 */
+		inodes_left =
+		    (sbi->nbperpage - block_offset) << sbi->l2niperblk;
+
+		if (rel_inode < inodes_left)
+			rel_inode += block_offset << sbi->l2niperblk;
+		else {
+			pageno += 1;
+			rel_inode -= inodes_left;
+		}
+	}
+	/* read the page of disk inode */
+      retry:
+	mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1);
+	if (mp == 0)
+		return (EIO);
+
+	/* get the pointer to the disk inode */
+	dp = (struct dinode *) mp->data;
+	dp += rel_inode;
+
+	dioffset = (ino & (INOSPERPAGE - 1)) << L2DISIZE;
+
+	/*
+	 * acquire transaction lock on the on-disk inode;
+	 * N.B. tlock is acquired on ipimap not ip;
+	 */
+	if ((ditlck =
+	     txLock(tid, ipimap, mp, tlckINODE | tlckENTRY)) == NULL)
+		goto retry;
+	dilinelock = (struct linelock *) & ditlck->lock;
+
+	/*
+	 * copy btree root from in-memory inode to on-disk inode
+	 *
+	 * (tlock is taken from inline B+-tree root in in-memory
+	 * inode when the B+-tree root is updated, which is pointed 
+	 * by jfs_ip->blid as well as being on tx tlock list)
+	 *
+	 * further processing of btree root is based on the copy 
+	 * in in-memory inode, where txLog() will log from, and, 
+	 * for xtree root, txUpdateMap() will update map and reset
+	 * XAD_NEW bit;
+	 */
+
+	if (S_ISDIR(ip->i_mode) && (lid = jfs_ip->xtlid)) {
+		/*
+		 * This is the special xtree inside the directory for storing
+		 * the directory table
+		 */
+		xtpage_t *p, *xp;
+		xad_t *xad;
+
+		jfs_ip->xtlid = 0;
+		tlck = lid_to_tlock(lid);
+		assert(tlck->type & tlckXTREE);
+		tlck->type |= tlckBTROOT;
+		tlck->mp = mp;
+		ilinelock = (struct linelock *) & tlck->lock;
+
+		/*
+		 * copy xtree root from inode to dinode:
+		 */
+		p = &jfs_ip->i_xtroot;
+		xp = (xtpage_t *) &dp->di_dirtable;
+		lv = ilinelock->lv;
+		for (n = 0; n < ilinelock->index; n++, lv++) {
+			memcpy(&xp->xad[lv->offset], &p->xad[lv->offset],
+			       lv->length << L2XTSLOTSIZE);
+		}
+
+		/* reset on-disk (metadata page) xtree XAD_NEW bit */
+		xad = &xp->xad[XTENTRYSTART];
+		for (n = XTENTRYSTART;
+		     n < le16_to_cpu(xp->header.nextindex); n++, xad++)
+			if (xad->flag & (XAD_NEW | XAD_EXTENDED))
+				xad->flag &= ~(XAD_NEW | XAD_EXTENDED);
+	}
+
+	if ((lid = jfs_ip->blid) == 0)
+		goto inlineData;
+	jfs_ip->blid = 0;
+
+	tlck = lid_to_tlock(lid);
+	type = tlck->type;
+	tlck->type |= tlckBTROOT;
+	tlck->mp = mp;
+	ilinelock = (struct linelock *) & tlck->lock;
+
+	/*
+	 *      regular file: 16 byte (XAD slot) granularity
+	 */
+	if (type & tlckXTREE) {
+		xtpage_t *p, *xp;
+		xad_t *xad;
+
+		/*
+		 * copy xtree root from inode to dinode:
+		 */
+		p = &jfs_ip->i_xtroot;
+		xp = &dp->di_xtroot;
+		lv = ilinelock->lv;
+		for (n = 0; n < ilinelock->index; n++, lv++) {
+			memcpy(&xp->xad[lv->offset], &p->xad[lv->offset],
+			       lv->length << L2XTSLOTSIZE);
+		}
+
+		/* reset on-disk (metadata page) xtree XAD_NEW bit */
+		xad = &xp->xad[XTENTRYSTART];
+		for (n = XTENTRYSTART;
+		     n < le16_to_cpu(xp->header.nextindex); n++, xad++)
+			if (xad->flag & (XAD_NEW | XAD_EXTENDED))
+				xad->flag &= ~(XAD_NEW | XAD_EXTENDED);
+	}
+	/*
+	 *      directory: 32 byte (directory entry slot) granularity
+	 */
+	else if (type & tlckDTREE) {
+		dtpage_t *p, *xp;
+
+		/*
+		 * copy dtree root from inode to dinode:
+		 */
+		p = (dtpage_t *) &jfs_ip->i_dtroot;
+		xp = (dtpage_t *) & dp->di_dtroot;
+		lv = ilinelock->lv;
+		for (n = 0; n < ilinelock->index; n++, lv++) {
+			memcpy(&xp->slot[lv->offset], &p->slot[lv->offset],
+			       lv->length << L2DTSLOTSIZE);
+		}
+	} else {
+		jERROR(1, ("diWrite: UFO tlock\n"));
+	}
+
+      inlineData:
+	/*
+	 * copy inline symlink from in-memory inode to on-disk inode
+	 */
+	if (S_ISLNK(ip->i_mode) && ip->i_size < IDATASIZE) {
+		lv = & dilinelock->lv[dilinelock->index];
+		lv->offset = (dioffset + 2 * 128) >> L2INODESLOTSIZE;
+		lv->length = 2;
+		memcpy(&dp->di_fastsymlink, jfs_ip->i_inline, IDATASIZE);
+		dilinelock->index++;
+	}
+	/*
+	 * copy inline data from in-memory inode to on-disk inode:
+	 * 128 byte slot granularity
+	 */
+	if (test_cflag(COMMIT_Inlineea, ip)) {
+		lv = & dilinelock->lv[dilinelock->index];
+		lv->offset = (dioffset + 3 * 128) >> L2INODESLOTSIZE;
+		lv->length = 1;
+		memcpy(&dp->di_inlineea, jfs_ip->i_inline_ea, INODESLOTSIZE);
+		dilinelock->index++;
+
+		clear_cflag(COMMIT_Inlineea, ip);
+	}
+
+	/*
+	 *      lock/copy inode base: 128 byte slot granularity
+	 */
+// baseDinode:
+	lv = & dilinelock->lv[dilinelock->index];
+	lv->offset = dioffset >> L2INODESLOTSIZE;
+	copy_to_dinode(dp, ip);
+	if (test_and_clear_cflag(COMMIT_Dirtable, ip)) {
+		lv->length = 2;
+		memcpy(&dp->di_dirtable, &jfs_ip->i_dirtable, 96);
+	} else
+		lv->length = 1;
+	dilinelock->index++;
+
+#ifdef _JFS_FASTDASD
+	/*
+	 * We aren't logging changes to the DASD used in directory inodes,
+	 * but we need to write them to disk.  If we don't unmount cleanly,
+	 * mount will recalculate the DASD used.
+	 */
+	if (S_ISDIR(ip->i_mode)
+	    && (ip->i_ipmnt->i_mntflag & JFS_DASD_ENABLED))
+		bcopy(&ip->i_DASD, &dp->di_DASD, sizeof(struct dasd));
+#endif				/*  _JFS_FASTDASD */
+
+	/* release the buffer holding the updated on-disk inode. 
+	 * the buffer will be later written by commit processing.
+	 */
+	write_metapage(mp);
+
+	return (rc);
+}
+
+
+/*
+ * NAME:        diFree(ip)
+ *
+ * FUNCTION:    free a specified inode from the inode working map
+ *		for a fileset or aggregate.
+ *
+ *		if the inode to be freed represents the first (only)
+ *		free inode within the iag, the iag will be placed on
+ *		the ag free inode list.
+ *	
+ *		freeing the inode will cause the inode extent to be
+ *		freed if the inode is the only allocated inode within
+ *		the extent.  in this case all the disk resource backing
+ *		up the inode extent will be freed. in addition, the iag
+ *		will be placed on the ag extent free list if the extent
+ *		is the first free extent in the iag.  if freeing the
+ *		extent also means that no free inodes will exist for
+ *		the iag, the iag will also be removed from the ag free
+ *		inode list.
+ *
+ *		the iag describing the inode will be freed if the extent
+ *		is to be freed and it is the only backed extent within
+ *		the iag.  in this case, the iag will be removed from the
+ *		ag free extent list and ag free inode list and placed on
+ *		the inode map's free iag list.
+ *
+ *		a careful update approach is used to provide consistency
+ *		in the face of updates to multiple buffers.  under this
+ *		approach, all required buffers are obtained before making
+ *		any updates and are held until all updates are complete.
+ *
+ * PARAMETERS:
+ *      ip  	- inode to be freed.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO  	- i/o error.
+ */
+int diFree(struct inode *ip)
+{
+	int rc;
+	ino_t inum = ip->i_ino;
+	struct iag *iagp, *aiagp, *biagp, *ciagp, *diagp;
+	struct metapage *mp, *amp, *bmp, *cmp, *dmp;
+	int iagno, ino, extno, bitno, sword, agno;
+	int back, fwd;
+	u32 bitmap, mask;
+	struct inode *ipimap = JFS_SBI(ip->i_sb)->ipimap;
+	struct inomap *imap = JFS_IP(ipimap)->i_imap;
+	pxd_t freepxd;
+	tid_t tid;
+	struct inode *iplist[3];
+	struct tlock *tlck;
+	struct pxd_lock *pxdlock;
+
+	/*
+	 * This is just to suppress compiler warnings.  The same logic that
+	 * references these variables is used to initialize them.
+	 */
+	aiagp = biagp = ciagp = diagp = NULL;
+
+	/* get the iag number containing the inode.
+	 */
+	iagno = INOTOIAG(inum);
+
+	/* make sure that the iag is contained within 
+	 * the map.
+	 */
+	//assert(iagno < imap->im_nextiag);
+	if (iagno >= imap->im_nextiag) {
+		jERROR(1, ("diFree: inum = %d, iagno = %d, nextiag = %d\n",
+			   (uint) inum, iagno, imap->im_nextiag));
+		dump_mem("imap", imap, 32);
+		updateSuper(ip->i_sb, FM_DIRTY);
+		return EIO;
+	}
+
+	/* get the allocation group for this ino.
+	 */
+	agno = JFS_IP(ip)->agno;
+
+	/* Lock the AG specific inode map information
+	 */
+	AG_LOCK(imap, agno);
+
+	/* Obtain read lock in imap inode.  Don't release it until we have
+	 * read all of the IAG's that we are going to.
+	 */
+	IREAD_LOCK(ipimap);
+
+	/* read the iag.
+	 */
+	if ((rc = diIAGRead(imap, iagno, &mp))) {
+		IREAD_UNLOCK(ipimap);
+		AG_UNLOCK(imap, agno);
+		return (rc);
+	}
+	iagp = (struct iag *) mp->data;
+
+	/* get the inode number and extent number of the inode within
+	 * the iag and the inode number within the extent.
+	 */
+	ino = inum & (INOSPERIAG - 1);
+	extno = ino >> L2INOSPEREXT;
+	bitno = ino & (INOSPEREXT - 1);
+	mask = HIGHORDER >> bitno;
+
+	assert(le32_to_cpu(iagp->wmap[extno]) & mask);
+#ifdef _STILL_TO_PORT
+	assert((le32_to_cpu(iagp->pmap[extno]) & mask) == 0);
+#endif				/*  _STILL_TO_PORT */
+	assert(addressPXD(&iagp->inoext[extno]));
+
+	/* compute the bitmap for the extent reflecting the freed inode.
+	 */
+	bitmap = le32_to_cpu(iagp->wmap[extno]) & ~mask;
+
+	if (imap->im_agctl[agno].numfree > imap->im_agctl[agno].numinos) {
+		jERROR(1,("diFree: numfree > numinos\n"));
+		release_metapage(mp);
+		IREAD_UNLOCK(ipimap);
+		AG_UNLOCK(imap, agno);
+		updateSuper(ip->i_sb, FM_DIRTY);
+		return EIO;
+	}
+	/*
+	 *      inode extent still has some inodes or below low water mark:
+	 *      keep the inode extent;
+	 */
+	if (bitmap ||
+	    imap->im_agctl[agno].numfree < 96 ||
+	    (imap->im_agctl[agno].numfree < 288 &&
+	     (((imap->im_agctl[agno].numfree * 100) /
+	       imap->im_agctl[agno].numinos) <= 25))) {
+		/* if the iag currently has no free inodes (i.e.,
+		 * the inode being freed is the first free inode of iag),
+		 * insert the iag at head of the inode free list for the ag.
+		 */
+		if (iagp->nfreeinos == 0) {
+			/* check if there are any iags on the ag inode
+			 * free list.  if so, read the first one so that
+			 * we can link the current iag onto the list at
+			 * the head.
+			 */
+			if ((fwd = imap->im_agctl[agno].inofree) >= 0) {
+				/* read the iag that currently is the head
+				 * of the list.
+				 */
+				if ((rc = diIAGRead(imap, fwd, &amp))) {
+					IREAD_UNLOCK(ipimap);
+					AG_UNLOCK(imap, agno);
+					release_metapage(mp);
+					return (rc);
+				}
+				aiagp = (struct iag *) amp->data;
+
+				/* make current head point back to the iag.
+				 */
+				aiagp->inofreeback = cpu_to_le32(iagno);
+
+				write_metapage(amp);
+			}
+
+			/* iag points forward to current head and iag
+			 * becomes the new head of the list.
+			 */
+			iagp->inofreefwd =
+			    cpu_to_le32(imap->im_agctl[agno].inofree);
+			iagp->inofreeback = -1;
+			imap->im_agctl[agno].inofree = iagno;
+		}
+		IREAD_UNLOCK(ipimap);
+
+		/* update the free inode summary map for the extent if
+		 * freeing the inode means the extent will now have free
+		 * inodes (i.e., the inode being freed is the first free 
+		 * inode of extent),
+		 */
+		if (iagp->wmap[extno] == ONES) {
+			sword = extno >> L2EXTSPERSUM;
+			bitno = extno & (EXTSPERSUM - 1);
+			iagp->inosmap[sword] &=
+			    cpu_to_le32(~(HIGHORDER >> bitno));
+		}
+
+		/* update the bitmap.
+		 */
+		iagp->wmap[extno] = cpu_to_le32(bitmap);
+		DBG_DIFREE(imap, inum);
+
+		/* update the free inode counts at the iag, ag and
+		 * map level.
+		 */
+		iagp->nfreeinos =
+		    cpu_to_le32(le32_to_cpu(iagp->nfreeinos) + 1);
+		imap->im_agctl[agno].numfree += 1;
+		atomic_inc(&imap->im_numfree);
+
+		/* release the AG inode map lock
+		 */
+		AG_UNLOCK(imap, agno);
+
+		/* write the iag */
+		write_metapage(mp);
+
+		return (0);
+	}
+
+
+	/*
+	 *      inode extent has become free and above low water mark:
+	 *      free the inode extent;
+	 */
+
+	/*
+	 *      prepare to update iag list(s) (careful update step 1)
+	 */
+	amp = bmp = cmp = dmp = NULL;
+	fwd = back = -1;
+
+	/* check if the iag currently has no free extents.  if so,
+	 * it will be placed on the head of the ag extent free list.
+	 */
+	if (iagp->nfreeexts == 0) {
+		/* check if the ag extent free list has any iags.
+		 * if so, read the iag at the head of the list now.
+		 * this (head) iag will be updated later to reflect
+		 * the addition of the current iag at the head of
+		 * the list.
+		 */
+		if ((fwd = imap->im_agctl[agno].extfree) >= 0) {
+			if ((rc = diIAGRead(imap, fwd, &amp)))
+				goto error_out;
+			aiagp = (struct iag *) amp->data;
+		}
+	} else {
+		/* iag has free extents. check if the addition of a free
+		 * extent will cause all extents to be free within this
+		 * iag.  if so, the iag will be removed from the ag extent
+		 * free list and placed on the inode map's free iag list.
+		 */
+		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG - 1)) {
+			/* in preparation for removing the iag from the
+			 * ag extent free list, read the iags preceeding
+			 * and following the iag on the ag extent free
+			 * list.
+			 */
+			if ((fwd = le32_to_cpu(iagp->extfreefwd)) >= 0) {
+				if ((rc = diIAGRead(imap, fwd, &amp)))
+					goto error_out;
+				aiagp = (struct iag *) amp->data;
+			}
+
+			if ((back = le32_to_cpu(iagp->extfreeback)) >= 0) {
+				if ((rc = diIAGRead(imap, back, &bmp)))
+					goto error_out;
+				biagp = (struct iag *) bmp->data;
+			}
+		}
+	}
+
+	/* remove the iag from the ag inode free list if freeing
+	 * this extent cause the iag to have no free inodes.
+	 */
+	if (iagp->nfreeinos == cpu_to_le32(INOSPEREXT - 1)) {
+		int inofreeback = le32_to_cpu(iagp->inofreeback);
+		int inofreefwd = le32_to_cpu(iagp->inofreefwd);
+
+		/* in preparation for removing the iag from the
+		 * ag inode free list, read the iags preceeding
+		 * and following the iag on the ag inode free
+		 * list.  before reading these iags, we must make
+		 * sure that we already don't have them in hand
+		 * from up above, since re-reading an iag (buffer)
+		 * we are currently holding would cause a deadlock.
+		 */
+		if (inofreefwd >= 0) {
+
+			if (inofreefwd == fwd)
+				ciagp = (struct iag *) amp->data;
+			else if (inofreefwd == back)
+				ciagp = (struct iag *) bmp->data;
+			else {
+				if ((rc =
+				     diIAGRead(imap, inofreefwd, &cmp)))
+					goto error_out;
+				assert(cmp != NULL);
+				ciagp = (struct iag *) cmp->data;
+			}
+			assert(ciagp != NULL);
+		}
+
+		if (inofreeback >= 0) {
+			if (inofreeback == fwd)
+				diagp = (struct iag *) amp->data;
+			else if (inofreeback == back)
+				diagp = (struct iag *) bmp->data;
+			else {
+				if ((rc =
+				     diIAGRead(imap, inofreeback, &dmp)))
+					goto error_out;
+				assert(dmp != NULL);
+				diagp = (struct iag *) dmp->data;
+			}
+			assert(diagp != NULL);
+		}
+	}
+
+	IREAD_UNLOCK(ipimap);
+
+	/*
+	 * invalidate any page of the inode extent freed from buffer cache;
+	 */
+	freepxd = iagp->inoext[extno];
+	invalidate_pxd_metapages(ip->i_sb->s_bdev->bd_inode, freepxd);
+
+	/*
+	 *      update iag list(s) (careful update step 2)
+	 */
+	/* add the iag to the ag extent free list if this is the
+	 * first free extent for the iag.
+	 */
+	if (iagp->nfreeexts == 0) {
+		if (fwd >= 0)
+			aiagp->extfreeback = cpu_to_le32(iagno);
+
+		iagp->extfreefwd =
+		    cpu_to_le32(imap->im_agctl[agno].extfree);
+		iagp->extfreeback = -1;
+		imap->im_agctl[agno].extfree = iagno;
+	} else {
+		/* remove the iag from the ag extent list if all extents
+		 * are now free and place it on the inode map iag free list.
+		 */
+		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG - 1)) {
+			if (fwd >= 0)
+				aiagp->extfreeback = iagp->extfreeback;
+
+			if (back >= 0)
+				biagp->extfreefwd = iagp->extfreefwd;
+			else
+				imap->im_agctl[agno].extfree =
+				    le32_to_cpu(iagp->extfreefwd);
+
+			iagp->extfreefwd = iagp->extfreeback = -1;
+
+			IAGFREE_LOCK(imap);
+			iagp->iagfree = cpu_to_le32(imap->im_freeiag);
+			imap->im_freeiag = iagno;
+			IAGFREE_UNLOCK(imap);
+		}
+	}
+
+	/* remove the iag from the ag inode free list if freeing
+	 * this extent causes the iag to have no free inodes.
+	 */
+	if (iagp->nfreeinos == cpu_to_le32(INOSPEREXT - 1)) {
+		if ((int) le32_to_cpu(iagp->inofreefwd) >= 0)
+			ciagp->inofreeback = iagp->inofreeback;
+
+		if ((int) le32_to_cpu(iagp->inofreeback) >= 0)
+			diagp->inofreefwd = iagp->inofreefwd;
+		else
+			imap->im_agctl[agno].inofree =
+			    le32_to_cpu(iagp->inofreefwd);
+
+		iagp->inofreefwd = iagp->inofreeback = -1;
+	}
+
+	/* update the inode extent address and working map 
+	 * to reflect the free extent.
+	 * the permanent map should have been updated already 
+	 * for the inode being freed.
+	 */
+	assert(iagp->pmap[extno] == 0);
+	iagp->wmap[extno] = 0;
+	DBG_DIFREE(imap, inum);
+	PXDlength(&iagp->inoext[extno], 0);
+	PXDaddress(&iagp->inoext[extno], 0);
+
+	/* update the free extent and free inode summary maps
+	 * to reflect the freed extent.
+	 * the inode summary map is marked to indicate no inodes 
+	 * available for the freed extent.
+	 */
+	sword = extno >> L2EXTSPERSUM;
+	bitno = extno & (EXTSPERSUM - 1);
+	mask = HIGHORDER >> bitno;
+	iagp->inosmap[sword] |= cpu_to_le32(mask);
+	iagp->extsmap[sword] &= cpu_to_le32(~mask);
+
+	/* update the number of free inodes and number of free extents
+	 * for the iag.
+	 */
+	iagp->nfreeinos = cpu_to_le32(le32_to_cpu(iagp->nfreeinos) -
+				      (INOSPEREXT - 1));
+	iagp->nfreeexts = cpu_to_le32(le32_to_cpu(iagp->nfreeexts) + 1);
+
+	/* update the number of free inodes and backed inodes
+	 * at the ag and inode map level.
+	 */
+	imap->im_agctl[agno].numfree -= (INOSPEREXT - 1);
+	imap->im_agctl[agno].numinos -= INOSPEREXT;
+	atomic_sub(INOSPEREXT - 1, &imap->im_numfree);
+	atomic_sub(INOSPEREXT, &imap->im_numinos);
+
+	if (amp)
+		write_metapage(amp);
+	if (bmp)
+		write_metapage(bmp);
+	if (cmp)
+		write_metapage(cmp);
+	if (dmp)
+		write_metapage(dmp);
+
+	/*
+	 * start transaction to update block allocation map
+	 * for the inode extent freed;
+	 *
+	 * N.B. AG_LOCK is released and iag will be released below, and 
+	 * other thread may allocate inode from/reusing the ixad freed
+	 * BUT with new/different backing inode extent from the extent 
+	 * to be freed by the transaction;  
+	 */
+	tid = txBegin(ipimap->i_sb, COMMIT_FORCE);
+
+	/* acquire tlock of the iag page of the freed ixad 
+	 * to force the page NOHOMEOK (even though no data is
+	 * logged from the iag page) until NOREDOPAGE|FREEXTENT log 
+	 * for the free of the extent is committed;
+	 * write FREEXTENT|NOREDOPAGE log record
+	 * N.B. linelock is overlaid as freed extent descriptor;
+	 */
+	tlck = txLock(tid, ipimap, mp, tlckINODE | tlckFREE);
+	pxdlock = (struct pxd_lock *) & tlck->lock;
+	pxdlock->flag = mlckFREEPXD;
+	pxdlock->pxd = freepxd;
+	pxdlock->index = 1;
+
+	write_metapage(mp);
+
+	iplist[0] = ipimap;
+
+	/*
+	 * logredo needs the IAG number and IAG extent index in order
+	 * to ensure that the IMap is consistent.  The least disruptive
+	 * way to pass these values through  to the transaction manager
+	 * is in the iplist array.  
+	 * 
+	 * It's not pretty, but it works.
+	 */
+	iplist[1] = (struct inode *) (size_t)iagno;
+	iplist[2] = (struct inode *) (size_t)extno;
+
+	rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);	// D233382
+
+	txEnd(tid);
+
+	/* unlock the AG inode map information */
+	AG_UNLOCK(imap, agno);
+
+	return (0);
+
+      error_out:
+	IREAD_UNLOCK(ipimap);
+
+	if (amp)
+		release_metapage(amp);
+	if (bmp)
+		release_metapage(bmp);
+	if (cmp)
+		release_metapage(cmp);
+	if (dmp)
+		release_metapage(dmp);
+
+	AG_UNLOCK(imap, agno);
+
+	release_metapage(mp);
+
+	return (rc);
+}
+
+/*
+ * There are several places in the diAlloc* routines where we initialize
+ * the inode.
+ */
+static inline void
+diInitInode(struct inode *ip, int iagno, int ino, int extno, struct iag * iagp)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+
+	ip->i_ino = (iagno << L2INOSPERIAG) + ino;
+	DBG_DIALLOC(JFS_IP(ipimap)->i_imap, ip->i_ino);
+	jfs_ip->ixpxd = iagp->inoext[extno];
+	jfs_ip->agno = BLKTOAG(le64_to_cpu(iagp->agstart), sbi);
+	jfs_ip->active_ag = -1;
+}
+
+
+/*
+ * NAME:        diAlloc(pip,dir,ip)
+ *
+ * FUNCTION:    allocate a disk inode from the inode working map 
+ *		for a fileset or aggregate.
+ *
+ * PARAMETERS:
+ *      pip  	- pointer to incore inode for the parent inode.
+ *      dir  	- TRUE if the new disk inode is for a directory.
+ *      ip  	- pointer to a new inode
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      ENOSPC 	- insufficient disk resources.
+ *      EIO  	- i/o error.
+ */
+int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip)
+{
+	int rc, ino, iagno, addext, extno, bitno, sword;
+	int nwords, rem, i, agno;
+	u32 mask, inosmap, extsmap;
+	struct inode *ipimap;
+	struct metapage *mp;
+	ino_t inum;
+	struct iag *iagp;
+	struct inomap *imap;
+
+	/* get the pointers to the inode map inode and the
+	 * corresponding imap control structure.
+	 */
+	ipimap = JFS_SBI(pip->i_sb)->ipimap;
+	imap = JFS_IP(ipimap)->i_imap;
+	JFS_IP(ip)->ipimap = ipimap;
+	JFS_IP(ip)->fileset = FILESYSTEM_I;
+
+	/* for a directory, the allocation policy is to start 
+	 * at the ag level using the preferred ag.
+	 */
+	if (dir == TRUE) {
+		agno = dbNextAG(JFS_SBI(pip->i_sb)->ipbmap);
+		AG_LOCK(imap, agno);
+		goto tryag;
+	}
+
+	/* for files, the policy starts off by trying to allocate from
+	 * the same iag containing the parent disk inode:
+	 * try to allocate the new disk inode close to the parent disk
+	 * inode, using parent disk inode number + 1 as the allocation
+	 * hint.  (we use a left-to-right policy to attempt to avoid
+	 * moving backward on the disk.)  compute the hint within the
+	 * file system and the iag.
+	 */
+
+	/* get the ag number of this iag */
+	agno = JFS_IP(pip)->agno;
+
+	if (atomic_read(&JFS_SBI(pip->i_sb)->bmap->db_active[agno])) {
+		/*
+		 * There is an open file actively growing.  We want to
+		 * allocate new inodes from a different ag to avoid
+		 * fragmentation problems.
+		 */
+		agno = dbNextAG(JFS_SBI(pip->i_sb)->ipbmap);
+		AG_LOCK(imap, agno);
+		goto tryag;
+	}
+
+	inum = pip->i_ino + 1;
+	ino = inum & (INOSPERIAG - 1);
+
+	/* back off the the hint if it is outside of the iag */
+	if (ino == 0)
+		inum = pip->i_ino;
+
+	/* lock the AG inode map information */
+	AG_LOCK(imap, agno);
+
+	/* Get read lock on imap inode */
+	IREAD_LOCK(ipimap);
+
+	/* get the iag number and read the iag */
+	iagno = INOTOIAG(inum);
+	if ((rc = diIAGRead(imap, iagno, &mp))) {
+		IREAD_UNLOCK(ipimap);
+		return (rc);
+	}
+	iagp = (struct iag *) mp->data;
+
+	/* determine if new inode extent is allowed to be added to the iag.
+	 * new inode extent can be added to the iag if the ag
+	 * has less than 32 free disk inodes and the iag has free extents.
+	 */
+	addext = (imap->im_agctl[agno].numfree < 32 && iagp->nfreeexts);
+
+	/*
+	 *      try to allocate from the IAG
+	 */
+	/* check if the inode may be allocated from the iag 
+	 * (i.e. the inode has free inodes or new extent can be added).
+	 */
+	if (iagp->nfreeinos || addext) {
+		/* determine the extent number of the hint.
+		 */
+		extno = ino >> L2INOSPEREXT;
+
+		/* check if the extent containing the hint has backed
+		 * inodes.  if so, try to allocate within this extent.
+		 */
+		if (addressPXD(&iagp->inoext[extno])) {
+			bitno = ino & (INOSPEREXT - 1);
+			if ((bitno =
+			     diFindFree(le32_to_cpu(iagp->wmap[extno]),
+					bitno))
+			    < INOSPEREXT) {
+				ino = (extno << L2INOSPEREXT) + bitno;
+
+				/* a free inode (bit) was found within this
+				 * extent, so allocate it.
+				 */
+				rc = diAllocBit(imap, iagp, ino);
+				IREAD_UNLOCK(ipimap);
+				if (rc) {
+					assert(rc == EIO);
+				} else {
+					/* set the results of the allocation
+					 * and write the iag.
+					 */
+					diInitInode(ip, iagno, ino, extno,
+						    iagp);
+					mark_metapage_dirty(mp);
+				}
+				release_metapage(mp);
+
+				/* free the AG lock and return.
+				 */
+				AG_UNLOCK(imap, agno);
+				return (rc);
+			}
+
+			if (!addext)
+				extno =
+				    (extno ==
+				     EXTSPERIAG - 1) ? 0 : extno + 1;
+		}
+
+		/*
+		 * no free inodes within the extent containing the hint.
+		 *
+		 * try to allocate from the backed extents following
+		 * hint or, if appropriate (i.e. addext is true), allocate
+		 * an extent of free inodes at or following the extent
+		 * containing the hint.
+		 * 
+		 * the free inode and free extent summary maps are used
+		 * here, so determine the starting summary map position
+		 * and the number of words we'll have to examine.  again,
+		 * the approach is to allocate following the hint, so we
+		 * might have to initially ignore prior bits of the summary
+		 * map that represent extents prior to the extent containing
+		 * the hint and later revisit these bits.
+		 */
+		bitno = extno & (EXTSPERSUM - 1);
+		nwords = (bitno == 0) ? SMAPSZ : SMAPSZ + 1;
+		sword = extno >> L2EXTSPERSUM;
+
+		/* mask any prior bits for the starting words of the
+		 * summary map.
+		 */
+		mask = ONES << (EXTSPERSUM - bitno);
+		inosmap = le32_to_cpu(iagp->inosmap[sword]) | mask;
+		extsmap = le32_to_cpu(iagp->extsmap[sword]) | mask;
+
+		/* scan the free inode and free extent summary maps for
+		 * free resources.
+		 */
+		for (i = 0; i < nwords; i++) {
+			/* check if this word of the free inode summary
+			 * map describes an extent with free inodes.
+			 */
+			if (~inosmap) {
+				/* an extent with free inodes has been
+				 * found. determine the extent number
+				 * and the inode number within the extent.
+				 */
+				rem = diFindFree(inosmap, 0);
+				extno = (sword << L2EXTSPERSUM) + rem;
+				rem =
+				    diFindFree(le32_to_cpu
+					       (iagp->wmap[extno]), 0);
+				assert(rem < INOSPEREXT);
+
+				/* determine the inode number within the
+				 * iag and allocate the inode from the
+				 * map.
+				 */
+				ino = (extno << L2INOSPEREXT) + rem;
+				rc = diAllocBit(imap, iagp, ino);
+				IREAD_UNLOCK(ipimap);
+				if (rc) {
+					assert(rc == EIO);
+				} else {
+					/* set the results of the allocation
+					 * and write the iag.
+					 */
+					diInitInode(ip, iagno, ino, extno,
+						    iagp);
+					mark_metapage_dirty(mp);
+				}
+				release_metapage(mp);
+
+				/* free the AG lock and return.
+				 */
+				AG_UNLOCK(imap, agno);
+				return (rc);
+
+			}
+
+			/* check if we may allocate an extent of free
+			 * inodes and whether this word of the free
+			 * extents summary map describes a free extent.
+			 */
+			if (addext && ~extsmap) {
+				/* a free extent has been found.  determine
+				 * the extent number.
+				 */
+				rem = diFindFree(extsmap, 0);
+				extno = (sword << L2EXTSPERSUM) + rem;
+
+				/* allocate an extent of free inodes.
+				 */
+				if ((rc = diNewExt(imap, iagp, extno))) {
+					/* if there is no disk space for a
+					 * new extent, try to allocate the
+					 * disk inode from somewhere else.
+					 */
+					if (rc == ENOSPC)
+						break;
+
+					assert(rc == EIO);
+				} else {
+					/* set the results of the allocation
+					 * and write the iag.
+					 */
+					diInitInode(ip, iagno,
+						    extno << L2INOSPEREXT,
+						    extno, iagp);
+					mark_metapage_dirty(mp);
+				}
+				release_metapage(mp);
+				/* free the imap inode & the AG lock & return.
+				 */
+				IREAD_UNLOCK(ipimap);
+				AG_UNLOCK(imap, agno);
+				return (rc);
+			}
+
+			/* move on to the next set of summary map words.
+			 */
+			sword = (sword == SMAPSZ - 1) ? 0 : sword + 1;
+			inosmap = le32_to_cpu(iagp->inosmap[sword]);
+			extsmap = le32_to_cpu(iagp->extsmap[sword]);
+		}
+	}
+	/* unlock imap inode */
+	IREAD_UNLOCK(ipimap);
+
+	/* nothing doing in this iag, so release it. */
+	release_metapage(mp);
+
+      tryag:
+	/*
+	 * try to allocate anywhere within the same AG as the parent inode.
+	 */
+	rc = diAllocAG(imap, agno, dir, ip);
+
+	AG_UNLOCK(imap, agno);
+
+	if (rc != ENOSPC)
+		return (rc);
+
+	/*
+	 * try to allocate in any AG.
+	 */
+	return (diAllocAny(imap, agno, dir, ip));
+}
+
+
+/*
+ * NAME:        diAllocAG(imap,agno,dir,ip)
+ *
+ * FUNCTION:    allocate a disk inode from the allocation group.
+ *
+ *		this routine first determines if a new extent of free
+ *		inodes should be added for the allocation group, with
+ *		the current request satisfied from this extent. if this
+ *		is the case, an attempt will be made to do just that.  if
+ *		this attempt fails or it has been determined that a new 
+ *		extent should not be added, an attempt is made to satisfy
+ *		the request by allocating an existing (backed) free inode
+ *		from the allocation group.
+ *
+ * PRE CONDITION: Already have the AG lock for this AG.
+ *
+ * PARAMETERS:
+ *      imap  	- pointer to inode map control structure.
+ *      agno  	- allocation group to allocate from.
+ *      dir  	- TRUE if the new disk inode is for a directory.
+ *      ip  	- pointer to the new inode to be filled in on successful return
+ *		  with the disk inode number allocated, its extent address
+ *		  and the start of the ag.
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      ENOSPC 	- insufficient disk resources.
+ *      EIO  	- i/o error.
+ */
+static int
+diAllocAG(struct inomap * imap, int agno, boolean_t dir, struct inode *ip)
+{
+	int rc, addext, numfree, numinos;
+
+	/* get the number of free and the number of backed disk 
+	 * inodes currently within the ag.
+	 */
+	numfree = imap->im_agctl[agno].numfree;
+	numinos = imap->im_agctl[agno].numinos;
+
+	if (numfree > numinos) {
+		jERROR(1,("diAllocAG: numfree > numinos\n"));
+		updateSuper(ip->i_sb, FM_DIRTY);
+		return EIO;
+	}
+
+	/* determine if we should allocate a new extent of free inodes
+	 * within the ag: for directory inodes, add a new extent
+	 * if there are a small number of free inodes or number of free
+	 * inodes is a small percentage of the number of backed inodes.
+	 */
+	if (dir == TRUE)
+		addext = (numfree < 64 ||
+			  (numfree < 256
+			   && ((numfree * 100) / numinos) <= 20));
+	else
+		addext = (numfree == 0);
+
+	/*
+	 * try to allocate a new extent of free inodes.
+	 */
+	if (addext) {
+		/* if free space is not avaliable for this new extent, try
+		 * below to allocate a free and existing (already backed)
+		 * inode from the ag.
+		 */
+		if ((rc = diAllocExt(imap, agno, ip)) != ENOSPC)
+			return (rc);
+	}
+
+	/*
+	 * try to allocate an existing free inode from the ag.
+	 */
+	return (diAllocIno(imap, agno, ip));
+}
+
+
+/*
+ * NAME:        diAllocAny(imap,agno,dir,iap)
+ *
+ * FUNCTION:    allocate a disk inode from any other allocation group.
+ *
+ *		this routine is called when an allocation attempt within
+ *		the primary allocation group has failed. if attempts to
+ *		allocate an inode from any allocation group other than the
+ *		specified primary group.
+ *
+ * PARAMETERS:
+ *      imap  	- pointer to inode map control structure.
+ *      agno  	- primary allocation group (to avoid).
+ *      dir  	- TRUE if the new disk inode is for a directory.
+ *      ip  	- pointer to a new inode to be filled in on successful return
+ *		  with the disk inode number allocated, its extent address
+ *		  and the start of the ag.
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      ENOSPC 	- insufficient disk resources.
+ *      EIO  	- i/o error.
+ */
+static int
+diAllocAny(struct inomap * imap, int agno, boolean_t dir, struct inode *ip)
+{
+	int ag, rc;
+	int maxag = JFS_SBI(imap->im_ipimap->i_sb)->bmap->db_maxag;
+
+
+	/* try to allocate from the ags following agno up to 
+	 * the maximum ag number.
+	 */
+	for (ag = agno + 1; ag <= maxag; ag++) {
+		AG_LOCK(imap, ag);
+
+		rc = diAllocAG(imap, ag, dir, ip);
+
+		AG_UNLOCK(imap, ag);
+
+		if (rc != ENOSPC)
+			return (rc);
+	}
+
+	/* try to allocate from the ags in front of agno.
+	 */
+	for (ag = 0; ag < agno; ag++) {
+		AG_LOCK(imap, ag);
+
+		rc = diAllocAG(imap, ag, dir, ip);
+
+		AG_UNLOCK(imap, ag);
+
+		if (rc != ENOSPC)
+			return (rc);
+	}
+
+	/* no free disk inodes.
+	 */
+	return (ENOSPC);
+}
+
+
+/*
+ * NAME:        diAllocIno(imap,agno,ip)
+ *
+ * FUNCTION:    allocate a disk inode from the allocation group's free
+ *		inode list, returning an error if this free list is
+ *		empty (i.e. no iags on the list).
+ *
+ *		allocation occurs from the first iag on the list using
+ *		the iag's free inode summary map to find the leftmost
+ *		free inode in the iag. 
+ *		
+ * PRE CONDITION: Already have AG lock for this AG.
+ *		
+ * PARAMETERS:
+ *      imap  	- pointer to inode map control structure.
+ *      agno  	- allocation group.
+ *      ip  	- pointer to new inode to be filled in on successful return
+ *		  with the disk inode number allocated, its extent address
+ *		  and the start of the ag.
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      ENOSPC 	- insufficient disk resources.
+ *      EIO  	- i/o error.
+ */
+static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
+{
+	int iagno, ino, rc, rem, extno, sword;
+	struct metapage *mp;
+	struct iag *iagp;
+
+	/* check if there are iags on the ag's free inode list.
+	 */
+	if ((iagno = imap->im_agctl[agno].inofree) < 0)
+		return (ENOSPC);
+
+	/* obtain read lock on imap inode */
+	IREAD_LOCK(imap->im_ipimap);
+
+	/* read the iag at the head of the list.
+	 */
+	if ((rc = diIAGRead(imap, iagno, &mp))) {
+		IREAD_UNLOCK(imap->im_ipimap);
+		return (rc);
+	}
+	iagp = (struct iag *) mp->data;
+
+	/* better be free inodes in this iag if it is on the
+	 * list.
+	 */
+	//assert(iagp->nfreeinos);
+	if (!iagp->nfreeinos) {
+		jERROR(1,
+		       ("diAllocIno: nfreeinos = 0, but iag on freelist\n"));
+		jERROR(1, ("  agno = %d, iagno = %d\n", agno, iagno));
+		dump_mem("iag", iagp, 64);
+		updateSuper(ip->i_sb, FM_DIRTY);
+		return EIO;
+	}
+
+	/* scan the free inode summary map to find an extent
+	 * with free inodes.
+	 */
+	for (sword = 0;; sword++) {
+		assert(sword < SMAPSZ);
+
+		if (~iagp->inosmap[sword])
+			break;
+	}
+
+	/* found a extent with free inodes. determine
+	 * the extent number.
+	 */
+	rem = diFindFree(le32_to_cpu(iagp->inosmap[sword]), 0);
+	assert(rem < EXTSPERSUM);
+	extno = (sword << L2EXTSPERSUM) + rem;
+
+	/* find the first free inode in the extent.
+	 */
+	rem = diFindFree(le32_to_cpu(iagp->wmap[extno]), 0);
+	assert(rem < INOSPEREXT);
+
+	/* compute the inode number within the iag. 
+	 */
+	ino = (extno << L2INOSPEREXT) + rem;
+
+	/* allocate the inode.
+	 */
+	rc = diAllocBit(imap, iagp, ino);
+	IREAD_UNLOCK(imap->im_ipimap);
+	if (rc) {
+		release_metapage(mp);
+		return (rc);
+	}
+
+	/* set the results of the allocation and write the iag.
+	 */
+	diInitInode(ip, iagno, ino, extno, iagp);
+	write_metapage(mp);
+
+	return (0);
+}
+
+
+/*
+ * NAME:        diAllocExt(imap,agno,ip)
+ *
+ * FUNCTION:   	add a new extent of free inodes to an iag, allocating
+ *	       	an inode from this extent to satisfy the current allocation
+ *	       	request.
+ *		
+ *		this routine first tries to find an existing iag with free
+ *		extents through the ag free extent list.  if list is not
+ *		empty, the head of the list will be selected as the home
+ *		of the new extent of free inodes.  otherwise (the list is
+ *		empty), a new iag will be allocated for the ag to contain
+ *		the extent.
+ *		
+ *		once an iag has been selected, the free extent summary map
+ *		is used to locate a free extent within the iag and diNewExt()
+ *		is called to initialize the extent, with initialization
+ *		including the allocation of the first inode of the extent
+ *		for the purpose of satisfying this request.
+ *
+ * PARAMETERS:
+ *      imap  	- pointer to inode map control structure.
+ *      agno  	- allocation group number.
+ *      ip  	- pointer to new inode to be filled in on successful return
+ *		  with the disk inode number allocated, its extent address
+ *		  and the start of the ag.
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      ENOSPC 	- insufficient disk resources.
+ *      EIO  	- i/o error.
+ */
+static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
+{
+	int rem, iagno, sword, extno, rc;
+	struct metapage *mp;
+	struct iag *iagp;
+
+	/* check if the ag has any iags with free extents.  if not,
+	 * allocate a new iag for the ag.
+	 */
+	if ((iagno = imap->im_agctl[agno].extfree) < 0) {
+		/* If successful, diNewIAG will obtain the read lock on the
+		 * imap inode.
+		 */
+		if ((rc = diNewIAG(imap, &iagno, agno, &mp))) {
+			return (rc);
+		}
+		iagp = (struct iag *) mp->data;
+
+		/* set the ag number if this a brand new iag
+		 */
+		iagp->agstart =
+		    cpu_to_le64(AGTOBLK(agno, imap->im_ipimap));
+	} else {
+		/* read the iag.
+		 */
+		IREAD_LOCK(imap->im_ipimap);
+		if ((rc = diIAGRead(imap, iagno, &mp))) {
+			assert(0);
+		}
+		iagp = (struct iag *) mp->data;
+	}
+
+	/* using the free extent summary map, find a free extent.
+	 */
+	for (sword = 0;; sword++) {
+		assert(sword < SMAPSZ);
+		if (~iagp->extsmap[sword])
+			break;
+	}
+
+	/* determine the extent number of the free extent.
+	 */
+	rem = diFindFree(le32_to_cpu(iagp->extsmap[sword]), 0);
+	assert(rem < EXTSPERSUM);
+	extno = (sword << L2EXTSPERSUM) + rem;
+
+	/* initialize the new extent.
+	 */
+	rc = diNewExt(imap, iagp, extno);
+	IREAD_UNLOCK(imap->im_ipimap);
+	if (rc) {
+		/* something bad happened.  if a new iag was allocated,
+		 * place it back on the inode map's iag free list, and
+		 * clear the ag number information.
+		 */
+		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
+			IAGFREE_LOCK(imap);
+			iagp->iagfree = cpu_to_le32(imap->im_freeiag);
+			imap->im_freeiag = iagno;
+			IAGFREE_UNLOCK(imap);
+		}
+		write_metapage(mp);
+		return (rc);
+	}
+
+	/* set the results of the allocation and write the iag.
+	 */
+	diInitInode(ip, iagno, extno << L2INOSPEREXT, extno, iagp);
+
+	write_metapage(mp);
+
+	return (0);
+}
+
+
+/*
+ * NAME:        diAllocBit(imap,iagp,ino)
+ *
+ * FUNCTION:   	allocate a backed inode from an iag.
+ *
+ *		this routine performs the mechanics of allocating a
+ *		specified inode from a backed extent.
+ *
+ *		if the inode to be allocated represents the last free
+ *		inode within the iag, the iag will be removed from the
+ *		ag free inode list.
+ *
+ *		a careful update approach is used to provide consistency
+ *		in the face of updates to multiple buffers.  under this
+ *		approach, all required buffers are obtained before making
+ *		any updates and are held all are updates are complete.
+ *		
+ * PRE CONDITION: Already have buffer lock on iagp.  Already have AG lock on
+ *	this AG.  Must have read lock on imap inode.
+ *
+ * PARAMETERS:
+ *      imap  	- pointer to inode map control structure.
+ *      iagp  	- pointer to iag. 
+ *      ino   	- inode number to be allocated within the iag.
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      ENOSPC 	- insufficient disk resources.
+ *      EIO  	- i/o error.
+ */
+static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino)
+{
+	int extno, bitno, agno, sword, rc;
+	struct metapage *amp, *bmp;
+	struct iag *aiagp = 0, *biagp = 0;
+	u32 mask;
+
+	/* check if this is the last free inode within the iag.
+	 * if so, it will have to be removed from the ag free
+	 * inode list, so get the iags preceeding and following
+	 * it on the list.
+	 */
+	if (iagp->nfreeinos == cpu_to_le32(1)) {
+		amp = bmp = NULL;
+
+		if ((int) le32_to_cpu(iagp->inofreefwd) >= 0) {
+			if ((rc =
+			     diIAGRead(imap, le32_to_cpu(iagp->inofreefwd),
+				       &amp)))
+				return (rc);
+			aiagp = (struct iag *) amp->data;
+		}
+
+		if ((int) le32_to_cpu(iagp->inofreeback) >= 0) {
+			if ((rc =
+			     diIAGRead(imap,
+				       le32_to_cpu(iagp->inofreeback),
+				       &bmp))) {
+				if (amp)
+					release_metapage(amp);
+				return (rc);
+			}
+			biagp = (struct iag *) bmp->data;
+		}
+	}
+
+	/* get the ag number, extent number, inode number within
+	 * the extent.
+	 */
+	agno = BLKTOAG(le64_to_cpu(iagp->agstart), JFS_SBI(imap->im_ipimap->i_sb));
+	extno = ino >> L2INOSPEREXT;
+	bitno = ino & (INOSPEREXT - 1);
+
+	/* compute the mask for setting the map.
+	 */
+	mask = HIGHORDER >> bitno;
+
+	/* the inode should be free and backed.
+	 */
+	assert((le32_to_cpu(iagp->pmap[extno]) & mask) == 0);
+	assert((le32_to_cpu(iagp->wmap[extno]) & mask) == 0);
+	assert(addressPXD(&iagp->inoext[extno]) != 0);
+
+	/* mark the inode as allocated in the working map.
+	 */
+	iagp->wmap[extno] |= cpu_to_le32(mask);
+
+	/* check if all inodes within the extent are now
+	 * allocated.  if so, update the free inode summary
+	 * map to reflect this.
+	 */
+	if (iagp->wmap[extno] == ONES) {
+		sword = extno >> L2EXTSPERSUM;
+		bitno = extno & (EXTSPERSUM - 1);
+		iagp->inosmap[sword] |= cpu_to_le32(HIGHORDER >> bitno);
+	}
+
+	/* if this was the last free inode in the iag, remove the
+	 * iag from the ag free inode list.
+	 */
+	if (iagp->nfreeinos == cpu_to_le32(1)) {
+		if (amp) {
+			aiagp->inofreeback = iagp->inofreeback;
+			write_metapage(amp);
+		}
+
+		if (bmp) {
+			biagp->inofreefwd = iagp->inofreefwd;
+			write_metapage(bmp);
+		} else {
+			imap->im_agctl[agno].inofree =
+			    le32_to_cpu(iagp->inofreefwd);
+		}
+		iagp->inofreefwd = iagp->inofreeback = -1;
+	}
+
+	/* update the free inode count at the iag, ag, inode
+	 * map levels.
+	 */
+	iagp->nfreeinos = cpu_to_le32(le32_to_cpu(iagp->nfreeinos) - 1);
+	imap->im_agctl[agno].numfree -= 1;
+	atomic_dec(&imap->im_numfree);
+
+	return (0);
+}
+
+
+/*
+ * NAME:        diNewExt(imap,iagp,extno)
+ *
+ * FUNCTION:    initialize a new extent of inodes for an iag, allocating
+ *	        the first inode of the extent for use for the current
+ *	        allocation request.
+ *
+ *		disk resources are allocated for the new extent of inodes
+ *		and the inodes themselves are initialized to reflect their
+ *		existence within the extent (i.e. their inode numbers and
+ *		inode extent addresses are set) and their initial state
+ *		(mode and link count are set to zero).
+ *
+ *		if the iag is new, it is not yet on an ag extent free list
+ *		but will now be placed on this list.
+ *
+ *		if the allocation of the new extent causes the iag to
+ *		have no free extent, the iag will be removed from the
+ *		ag extent free list.
+ *
+ *		if the iag has no free backed inodes, it will be placed
+ *		on the ag free inode list, since the addition of the new
+ *		extent will now cause it to have free inodes.
+ *
+ *		a careful update approach is used to provide consistency
+ *		(i.e. list consistency) in the face of updates to multiple
+ *		buffers.  under this approach, all required buffers are
+ *		obtained before making any updates and are held until all
+ *		updates are complete.
+ *		
+ * PRE CONDITION: Already have buffer lock on iagp.  Already have AG lock on
+ *	this AG.  Must have read lock on imap inode.
+ *
+ * PARAMETERS:
+ *      imap  	- pointer to inode map control structure.
+ *      iagp  	- pointer to iag. 
+ *      extno  	- extent number.
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      ENOSPC 	- insufficient disk resources.
+ *      EIO  	- i/o error.
+ */
+static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
+{
+	int agno, iagno, fwd, back, freei = 0, sword, rc;
+	struct iag *aiagp = 0, *biagp = 0, *ciagp = 0;
+	struct metapage *amp, *bmp, *cmp, *dmp;
+	struct inode *ipimap;
+	s64 blkno, hint;
+	int i, j;
+	u32 mask;
+	ino_t ino;
+	struct dinode *dp;
+	struct jfs_sb_info *sbi;
+
+	/* better have free extents.
+	 */
+	assert(iagp->nfreeexts);
+
+	/* get the inode map inode.
+	 */
+	ipimap = imap->im_ipimap;
+	sbi = JFS_SBI(ipimap->i_sb);
+
+	amp = bmp = cmp = NULL;
+
+	/* get the ag and iag numbers for this iag.
+	 */
+	agno = BLKTOAG(le64_to_cpu(iagp->agstart), sbi);
+	iagno = le32_to_cpu(iagp->iagnum);
+
+	/* check if this is the last free extent within the
+	 * iag.  if so, the iag must be removed from the ag
+	 * free extent list, so get the iags preceeding and
+	 * following the iag on this list.
+	 */
+	if (iagp->nfreeexts == cpu_to_le32(1)) {
+		if ((fwd = le32_to_cpu(iagp->extfreefwd)) >= 0) {
+			if ((rc = diIAGRead(imap, fwd, &amp)))
+				return (rc);
+			aiagp = (struct iag *) amp->data;
+		}
+
+		if ((back = le32_to_cpu(iagp->extfreeback)) >= 0) {
+			if ((rc = diIAGRead(imap, back, &bmp)))
+				goto error_out;
+			biagp = (struct iag *) bmp->data;
+		}
+	} else {
+		/* the iag has free extents.  if all extents are free
+		 * (as is the case for a newly allocated iag), the iag
+		 * must be added to the ag free extent list, so get
+		 * the iag at the head of the list in preparation for
+		 * adding this iag to this list.
+		 */
+		fwd = back = -1;
+		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
+			if ((fwd = imap->im_agctl[agno].extfree) >= 0) {
+				if ((rc = diIAGRead(imap, fwd, &amp)))
+					goto error_out;
+				aiagp = (struct iag *) amp->data;
+			}
+		}
+	}
+
+	/* check if the iag has no free inodes.  if so, the iag
+	 * will have to be added to the ag free inode list, so get
+	 * the iag at the head of the list in preparation for
+	 * adding this iag to this list.  in doing this, we must
+	 * check if we already have the iag at the head of
+	 * the list in hand.
+	 */
+	if (iagp->nfreeinos == 0) {
+		freei = imap->im_agctl[agno].inofree;
+
+		if (freei >= 0) {
+			if (freei == fwd) {
+				ciagp = aiagp;
+			} else if (freei == back) {
+				ciagp = biagp;
+			} else {
+				if ((rc = diIAGRead(imap, freei, &cmp)))
+					goto error_out;
+				ciagp = (struct iag *) cmp->data;
+			}
+			assert(ciagp != NULL);
+		}
+	}
+
+	/* allocate disk space for the inode extent.
+	 */
+	if ((extno == 0) || (addressPXD(&iagp->inoext[extno - 1]) == 0))
+		hint = ((s64) agno << sbi->bmap->db_agl2size) - 1;
+	else
+		hint = addressPXD(&iagp->inoext[extno - 1]) +
+		    lengthPXD(&iagp->inoext[extno - 1]) - 1;
+
+	if ((rc = dbAlloc(ipimap, hint, (s64) imap->im_nbperiext, &blkno)))
+		goto error_out;
+
+	/* compute the inode number of the first inode within the
+	 * extent.
+	 */
+	ino = (iagno << L2INOSPERIAG) + (extno << L2INOSPEREXT);
+
+	/* initialize the inodes within the newly allocated extent a
+	 * page at a time.
+	 */
+	for (i = 0; i < imap->im_nbperiext; i += sbi->nbperpage) {
+		/* get a buffer for this page of disk inodes.
+		 */
+		dmp = get_metapage(ipimap, blkno + i, PSIZE, 1);
+		if (dmp == NULL) {
+			rc = EIO;
+			goto error_out;
+		}
+		dp = (struct dinode *) dmp->data;
+
+		/* initialize the inode number, mode, link count and
+		 * inode extent address.
+		 */
+		for (j = 0; j < INOSPERPAGE; j++, dp++, ino++) {
+			dp->di_inostamp = cpu_to_le32(sbi->inostamp);
+			dp->di_number = cpu_to_le32(ino);
+			dp->di_fileset = cpu_to_le32(FILESYSTEM_I);
+			dp->di_mode = 0;
+			dp->di_nlink = 0;
+			PXDaddress(&(dp->di_ixpxd), blkno);
+			PXDlength(&(dp->di_ixpxd), imap->im_nbperiext);
+		}
+		write_metapage(dmp);
+	}
+
+	/* if this is the last free extent within the iag, remove the
+	 * iag from the ag free extent list.
+	 */
+	if (iagp->nfreeexts == cpu_to_le32(1)) {
+		if (fwd >= 0)
+			aiagp->extfreeback = iagp->extfreeback;
+
+		if (back >= 0)
+			biagp->extfreefwd = iagp->extfreefwd;
+		else
+			imap->im_agctl[agno].extfree =
+			    le32_to_cpu(iagp->extfreefwd);
+
+		iagp->extfreefwd = iagp->extfreeback = -1;
+	} else {
+		/* if the iag has all free extents (newly allocated iag),
+		 * add the iag to the ag free extent list.
+		 */
+		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
+			if (fwd >= 0)
+				aiagp->extfreeback = cpu_to_le32(iagno);
+
+			iagp->extfreefwd = cpu_to_le32(fwd);
+			iagp->extfreeback = -1;
+			imap->im_agctl[agno].extfree = iagno;
+		}
+	}
+
+	/* if the iag has no free inodes, add the iag to the
+	 * ag free inode list.
+	 */
+	if (iagp->nfreeinos == 0) {
+		if (freei >= 0)
+			ciagp->inofreeback = cpu_to_le32(iagno);
+
+		iagp->inofreefwd =
+		    cpu_to_le32(imap->im_agctl[agno].inofree);
+		iagp->inofreeback = -1;
+		imap->im_agctl[agno].inofree = iagno;
+	}
+
+	/* initialize the extent descriptor of the extent. */
+	PXDlength(&iagp->inoext[extno], imap->im_nbperiext);
+	PXDaddress(&iagp->inoext[extno], blkno);
+
+	/* initialize the working and persistent map of the extent.
+	 * the working map will be initialized such that
+	 * it indicates the first inode of the extent is allocated.
+	 */
+	iagp->wmap[extno] = cpu_to_le32(HIGHORDER);
+	iagp->pmap[extno] = 0;
+
+	/* update the free inode and free extent summary maps
+	 * for the extent to indicate the extent has free inodes
+	 * and no longer represents a free extent.
+	 */
+	sword = extno >> L2EXTSPERSUM;
+	mask = HIGHORDER >> (extno & (EXTSPERSUM - 1));
+	iagp->extsmap[sword] |= cpu_to_le32(mask);
+	iagp->inosmap[sword] &= cpu_to_le32(~mask);
+
+	/* update the free inode and free extent counts for the
+	 * iag.
+	 */
+	iagp->nfreeinos = cpu_to_le32(le32_to_cpu(iagp->nfreeinos) +
+				      (INOSPEREXT - 1));
+	iagp->nfreeexts = cpu_to_le32(le32_to_cpu(iagp->nfreeexts) - 1);
+
+	/* update the free and backed inode counts for the ag.
+	 */
+	imap->im_agctl[agno].numfree += (INOSPEREXT - 1);
+	imap->im_agctl[agno].numinos += INOSPEREXT;
+
+	/* update the free and backed inode counts for the inode map.
+	 */
+	atomic_add(INOSPEREXT - 1, &imap->im_numfree);
+	atomic_add(INOSPEREXT, &imap->im_numinos);
+
+	/* write the iags.
+	 */
+	if (amp)
+		write_metapage(amp);
+	if (bmp)
+		write_metapage(bmp);
+	if (cmp)
+		write_metapage(cmp);
+
+	return (0);
+
+      error_out:
+
+	/* release the iags.
+	 */
+	if (amp)
+		release_metapage(amp);
+	if (bmp)
+		release_metapage(bmp);
+	if (cmp)
+		release_metapage(cmp);
+
+	return (rc);
+}
+
+
+/*
+ * NAME:        diNewIAG(imap,iagnop,agno)
+ *
+ * FUNCTION:   	allocate a new iag for an allocation group.
+ *		
+ *		first tries to allocate the iag from the inode map 
+ *		iagfree list:  
+ *		if the list has free iags, the head of the list is removed 
+ *		and returned to satisfy the request.
+ *		if the inode map's iag free list is empty, the inode map
+ *		is extended to hold a new iag. this new iag is initialized
+ *		and returned to satisfy the request.
+ *
+ * PARAMETERS:
+ *      imap  	- pointer to inode map control structure.
+ *      iagnop 	- pointer to an iag number set with the number of the
+ *		  newly allocated iag upon successful return.
+ *      agno  	- allocation group number.
+ *	bpp	- Buffer pointer to be filled in with new IAG's buffer
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      ENOSPC 	- insufficient disk resources.
+ *      EIO  	- i/o error.
+ *
+ * serialization: 
+ *	AG lock held on entry/exit;
+ *	write lock on the map is held inside;
+ *	read lock on the map is held on successful completion;
+ *
+ * note: new iag transaction: 
+ * . synchronously write iag;
+ * . write log of xtree and inode  of imap;
+ * . commit;
+ * . synchronous write of xtree (right to left, bottom to top);
+ * . at start of logredo(): init in-memory imap with one additional iag page;
+ * . at end of logredo(): re-read imap inode to determine
+ *   new imap size;
+ */
+static int
+diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
+{
+	int rc;
+	int iagno, i, xlen;
+	struct inode *ipimap;
+	struct super_block *sb;
+	struct jfs_sb_info *sbi;
+	struct metapage *mp;
+	struct iag *iagp;
+	s64 xaddr = 0;
+	s64 blkno;
+	tid_t tid;
+#ifdef _STILL_TO_PORT
+	xad_t xad;
+#endif				/*  _STILL_TO_PORT */
+	struct inode *iplist[1];
+
+	/* pick up pointers to the inode map and mount inodes */
+	ipimap = imap->im_ipimap;
+	sb = ipimap->i_sb;
+	sbi = JFS_SBI(sb);
+
+	/* acquire the free iag lock */
+	IAGFREE_LOCK(imap);
+
+	/* if there are any iags on the inode map free iag list, 
+	 * allocate the iag from the head of the list.
+	 */
+	if (imap->im_freeiag >= 0) {
+		/* pick up the iag number at the head of the list */
+		iagno = imap->im_freeiag;
+
+		/* determine the logical block number of the iag */
+		blkno = IAGTOLBLK(iagno, sbi->l2nbperpage);
+	} else {
+		/* no free iags. the inode map will have to be extented
+		 * to include a new iag.
+		 */
+
+		/* acquire inode map lock */
+		IWRITE_LOCK(ipimap);
+
+		assert(ipimap->i_size >> L2PSIZE == imap->im_nextiag + 1);
+
+		/* get the next avaliable iag number */
+		iagno = imap->im_nextiag;
+
+		/* make sure that we have not exceeded the maximum inode
+		 * number limit.
+		 */
+		if (iagno > (MAXIAGS - 1)) {
+			/* release the inode map lock */
+			IWRITE_UNLOCK(ipimap);
+
+			rc = ENOSPC;
+			goto out;
+		}
+
+		/*
+		 * synchronously append new iag page.
+		 */
+		/* determine the logical address of iag page to append */
+		blkno = IAGTOLBLK(iagno, sbi->l2nbperpage);
+
+		/* Allocate extent for new iag page */
+		xlen = sbi->nbperpage;
+		if ((rc = dbAlloc(ipimap, 0, (s64) xlen, &xaddr))) {
+			/* release the inode map lock */
+			IWRITE_UNLOCK(ipimap);
+
+			goto out;
+		}
+
+		/* assign a buffer for the page */
+		mp = get_metapage(ipimap, xaddr, PSIZE, 1);
+		//bp = bmAssign(ipimap, blkno, xaddr, PSIZE, bmREAD_PAGE);
+		if (!mp) {
+			/* Free the blocks allocated for the iag since it was
+			 * not successfully added to the inode map
+			 */
+			dbFree(ipimap, xaddr, (s64) xlen);
+
+			/* release the inode map lock */
+			IWRITE_UNLOCK(ipimap);
+
+			rc = EIO;
+			goto out;
+		}
+		iagp = (struct iag *) mp->data;
+
+		/* init the iag */
+		memset(iagp, 0, sizeof(struct iag));
+		iagp->iagnum = cpu_to_le32(iagno);
+		iagp->inofreefwd = iagp->inofreeback = -1;
+		iagp->extfreefwd = iagp->extfreeback = -1;
+		iagp->iagfree = -1;
+		iagp->nfreeinos = 0;
+		iagp->nfreeexts = cpu_to_le32(EXTSPERIAG);
+
+		/* initialize the free inode summary map (free extent
+		 * summary map initialization handled by bzero).
+		 */
+		for (i = 0; i < SMAPSZ; i++)
+			iagp->inosmap[i] = ONES;
+
+		flush_metapage(mp);
+#ifdef _STILL_TO_PORT
+		/* synchronously write the iag page */
+		if (bmWrite(bp)) {
+			/* Free the blocks allocated for the iag since it was
+			 * not successfully added to the inode map
+			 */
+			dbFree(ipimap, xaddr, (s64) xlen);
+
+			/* release the inode map lock */
+			IWRITE_UNLOCK(ipimap);
+
+			rc = EIO;
+			goto out;
+		}
+
+		/* Now the iag is on disk */
+
+		/*
+		 * start tyransaction of update of the inode map
+		 * addressing structure pointing to the new iag page;
+		 */
+#endif				/*  _STILL_TO_PORT */
+		tid = txBegin(sb, COMMIT_FORCE);
+
+		/* update the inode map addressing structure to point to it */
+		if ((rc =
+		     xtInsert(tid, ipimap, 0, blkno, xlen, &xaddr, 0))) {
+			/* Free the blocks allocated for the iag since it was
+			 * not successfully added to the inode map
+			 */
+			dbFree(ipimap, xaddr, (s64) xlen);
+
+			/* release the inode map lock */
+			IWRITE_UNLOCK(ipimap);
+
+			goto out;
+		}
+
+		/* update the inode map's inode to reflect the extension */
+		ipimap->i_size += PSIZE;
+		ipimap->i_blocks += LBLK2PBLK(sb, xlen);
+
+		/*
+		 * txCommit(COMMIT_FORCE) will synchronously write address 
+		 * index pages and inode after commit in careful update order 
+		 * of address index pages (right to left, bottom up);
+		 */
+		iplist[0] = ipimap;
+		rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);
+
+		txEnd(tid);
+
+		duplicateIXtree(sb, blkno, xlen, &xaddr);
+
+		/* update the next avaliable iag number */
+		imap->im_nextiag += 1;
+
+		/* Add the iag to the iag free list so we don't lose the iag
+		 * if a failure happens now.
+		 */
+		imap->im_freeiag = iagno;
+
+		/* Until we have logredo working, we want the imap inode &
+		 * control page to be up to date.
+		 */
+		diSync(ipimap);
+
+		/* release the inode map lock */
+		IWRITE_UNLOCK(ipimap);
+	}
+
+	/* obtain read lock on map */
+	IREAD_LOCK(ipimap);
+
+	/* read the iag */
+	if ((rc = diIAGRead(imap, iagno, &mp))) {
+		IREAD_UNLOCK(ipimap);
+		rc = EIO;
+		goto out;
+	}
+	iagp = (struct iag *) mp->data;
+
+	/* remove the iag from the iag free list */
+	imap->im_freeiag = le32_to_cpu(iagp->iagfree);
+	iagp->iagfree = -1;
+
+	/* set the return iag number and buffer pointer */
+	*iagnop = iagno;
+	*mpp = mp;
+
+      out:
+	/* release the iag free lock */
+	IAGFREE_UNLOCK(imap);
+
+	return (rc);
+}
+
+/*
+ * NAME:        diIAGRead()
+ *
+ * FUNCTION:    get the buffer for the specified iag within a fileset
+ *		or aggregate inode map.
+ *		
+ * PARAMETERS:
+ *      imap  	- pointer to inode map control structure.
+ *      iagno  	- iag number.
+ *      bpp  	- point to buffer pointer to be filled in on successful
+ *		  exit.
+ *
+ * SERIALIZATION:
+ *	must have read lock on imap inode
+ *	(When called by diExtendFS, the filesystem is quiesced, therefore
+ *	 the read lock is unnecessary.)
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      EIO  	- i/o error.
+ */
+static int diIAGRead(struct inomap * imap, int iagno, struct metapage ** mpp)
+{
+	struct inode *ipimap = imap->im_ipimap;
+	s64 blkno;
+
+	/* compute the logical block number of the iag. */
+	blkno = IAGTOLBLK(iagno, JFS_SBI(ipimap->i_sb)->l2nbperpage);
+
+	/* read the iag. */
+	*mpp = read_metapage(ipimap, blkno, PSIZE, 0);
+	if (*mpp == NULL) {
+		return (EIO);
+	}
+
+	return (0);
+}
+
+/*
+ * NAME:        diFindFree()
+ *
+ * FUNCTION:    find the first free bit in a word starting at
+ *		the specified bit position.
+ *
+ * PARAMETERS:
+ *      word  	- word to be examined.
+ *      start  	- starting bit position.
+ *
+ * RETURN VALUES:
+ *      bit position of first free bit in the word or 32 if
+ *	no free bits were found.
+ */
+static int diFindFree(u32 word, int start)
+{
+	int bitno;
+	assert(start < 32);
+	/* scan the word for the first free bit. */
+	for (word <<= start, bitno = start; bitno < 32;
+	     bitno++, word <<= 1) {
+		if ((word & HIGHORDER) == 0)
+			break;
+	}
+	return (bitno);
+}
+
+/*
+ * NAME:	diUpdatePMap()
+ *                                                                    
+ * FUNCTION: Update the persistent map in an IAG for the allocation or 
+ *	freeing of the specified inode.
+ *                                                                    
+ * PRE CONDITIONS: Working map has already been updated for allocate.
+ *
+ * PARAMETERS:
+ *	ipimap	- Incore inode map inode
+ *	inum	- Number of inode to mark in permanent map
+ *	is_free	- If TRUE indicates inode should be marked freed, otherwise
+ *		  indicates inode should be marked allocated.
+ *
+ * RETURNS: 0 for success
+ */
+int
+diUpdatePMap(struct inode *ipimap,
+	     unsigned long inum, boolean_t is_free, struct tblock * tblk)
+{
+	int rc;
+	struct iag *iagp;
+	struct metapage *mp;
+	int iagno, ino, extno, bitno;
+	struct inomap *imap;
+	u32 mask;
+	struct jfs_log *log;
+	int lsn, difft, diffp;
+
+	imap = JFS_IP(ipimap)->i_imap;
+	/* get the iag number containing the inode */
+	iagno = INOTOIAG(inum);
+	/* make sure that the iag is contained within the map */
+	assert(iagno < imap->im_nextiag);
+	/* read the iag */
+	IREAD_LOCK(ipimap);
+	rc = diIAGRead(imap, iagno, &mp);
+	IREAD_UNLOCK(ipimap);
+	if (rc)
+		return (rc);
+	iagp = (struct iag *) mp->data;
+	/* get the inode number and extent number of the inode within
+	 * the iag and the inode number within the extent.
+	 */
+	ino = inum & (INOSPERIAG - 1);
+	extno = ino >> L2INOSPEREXT;
+	bitno = ino & (INOSPEREXT - 1);
+	mask = HIGHORDER >> bitno;
+	/* 
+	 * mark the inode free in persistent map:
+	 */
+	if (is_free == TRUE) {
+		/* The inode should have been allocated both in working
+		 * map and in persistent map;
+		 * the inode will be freed from working map at the release
+		 * of last reference release;
+		 */
+//              assert(le32_to_cpu(iagp->wmap[extno]) & mask);
+		if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
+			jERROR(1,
+			       ("diUpdatePMap: inode %ld not marked as allocated in wmap!\n",
+				inum));
+			updateSuper(ipimap->i_sb, FM_DIRTY);
+		}
+//              assert(le32_to_cpu(iagp->pmap[extno]) & mask);
+		if (!(le32_to_cpu(iagp->pmap[extno]) & mask)) {
+			jERROR(1,
+			       ("diUpdatePMap: inode %ld not marked as allocated in pmap!\n",
+				inum));
+			updateSuper(ipimap->i_sb, FM_DIRTY);
+		}
+		/* update the bitmap for the extent of the freed inode */
+		iagp->pmap[extno] &= cpu_to_le32(~mask);
+	}
+	/*
+	 * mark the inode allocated in persistent map:
+	 */
+	else {
+		/* The inode should be already allocated in the working map
+		 * and should be free in persistent map;
+		 */
+		assert(le32_to_cpu(iagp->wmap[extno]) & mask);
+		assert((le32_to_cpu(iagp->pmap[extno]) & mask) == 0);
+		/* update the bitmap for the extent of the allocated inode */
+		iagp->pmap[extno] |= cpu_to_le32(mask);
+	}
+	/*
+	 * update iag lsn
+	 */
+	lsn = tblk->lsn;
+	log = JFS_SBI(tblk->sb)->log;
+	if (mp->lsn != 0) {
+		/* inherit older/smaller lsn */
+		logdiff(difft, lsn, log);
+		logdiff(diffp, mp->lsn, log);
+		if (difft < diffp) {
+			mp->lsn = lsn;
+			/* move mp after tblock in logsync list */
+			LOGSYNC_LOCK(log);
+			list_del(&mp->synclist);
+			list_add(&mp->synclist, &tblk->synclist);
+			LOGSYNC_UNLOCK(log);
+		}
+		/* inherit younger/larger clsn */
+		LOGSYNC_LOCK(log);
+		assert(mp->clsn);
+		logdiff(difft, tblk->clsn, log);
+		logdiff(diffp, mp->clsn, log);
+		if (difft > diffp)
+			mp->clsn = tblk->clsn;
+		LOGSYNC_UNLOCK(log);
+	} else {
+		mp->log = log;
+		mp->lsn = lsn;
+		/* insert mp after tblock in logsync list */
+		LOGSYNC_LOCK(log);
+		log->count++;
+		list_add(&mp->synclist, &tblk->synclist);
+		mp->clsn = tblk->clsn;
+		LOGSYNC_UNLOCK(log);
+	}
+//      bmLazyWrite(mp, log->flag & JFS_COMMIT);
+	write_metapage(mp);
+	return (0);
+}
+
+/*
+ *	diExtendFS()
+ *
+ * function: update imap for extendfs();
+ * 
+ * note: AG size has been increased s.t. each k old contiguous AGs are 
+ * coalesced into a new AG;
+ */
+int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
+{
+	int rc, rcx = 0;
+	struct inomap *imap = JFS_IP(ipimap)->i_imap;
+	struct iag *iagp = 0, *hiagp = 0;
+	struct bmap *mp = JFS_SBI(ipbmap->i_sb)->bmap;
+	struct metapage *bp, *hbp;
+	int i, n, head;
+	int numinos, xnuminos = 0, xnumfree = 0;
+	s64 agstart;
+
+	jEVENT(0, ("diExtendFS: nextiag:%d numinos:%d numfree:%d\n",
+		   imap->im_nextiag, atomic_read(&imap->im_numinos),
+		   atomic_read(&imap->im_numfree)));
+
+	/*
+	 *      reconstruct imap 
+	 *
+	 * coalesce contiguous k (newAGSize/oldAGSize) AGs;
+	 * i.e., (AGi, ..., AGj) where i = k*n and j = k*(n+1) - 1 to AGn;
+	 * note: new AG size = old AG size * (2**x).
+	 */
+
+	/* init per AG control information im_agctl[] */
+	for (i = 0; i < MAXAG; i++) {
+		imap->im_agctl[i].inofree = -1;	/* free inode list */
+		imap->im_agctl[i].extfree = -1;	/* free extent list */
+		imap->im_agctl[i].numinos = 0;	/* number of backed inodes */
+		imap->im_agctl[i].numfree = 0;	/* number of free backed inodes */
+	}
+
+	/*
+	 *      process each iag page of the map.
+	 *
+	 * rebuild AG Free Inode List, AG Free Inode Extent List;
+	 */
+	for (i = 0; i < imap->im_nextiag; i++) {
+		if ((rc = diIAGRead(imap, i, &bp))) {
+			rcx = rc;
+			continue;
+		}
+		iagp = (struct iag *) bp->data;
+		assert(le32_to_cpu(iagp->iagnum) == i);
+
+		/* leave free iag in the free iag list */
+		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {  
+		        release_metapage(bp);
+			continue;
+		}
+
+		/* agstart that computes to the same ag is treated as same; */
+		agstart = le64_to_cpu(iagp->agstart);
+		/* iagp->agstart = agstart & ~(mp->db_agsize - 1); */
+		n = agstart >> mp->db_agl2size;
+/*
+printf("diExtendFS: iag:%d agstart:%Ld agno:%d\n", i, agstart, n);
+*/
+
+		/* compute backed inodes */
+		numinos = (EXTSPERIAG - le32_to_cpu(iagp->nfreeexts))
+		    << L2INOSPEREXT;
+		if (numinos > 0) {
+			/* merge AG backed inodes */
+			imap->im_agctl[n].numinos += numinos;
+			xnuminos += numinos;
+		}
+
+		/* if any backed free inodes, insert at AG free inode list */
+		if ((int) le32_to_cpu(iagp->nfreeinos) > 0) {
+			if ((head = imap->im_agctl[n].inofree) == -1)
+				iagp->inofreefwd = iagp->inofreeback = -1;
+			else {
+				if ((rc = diIAGRead(imap, head, &hbp))) {
+					rcx = rc;
+					goto nextiag;
+				}
+				hiagp = (struct iag *) hbp->data;
+				hiagp->inofreeback =
+				    le32_to_cpu(iagp->iagnum);
+				iagp->inofreefwd = cpu_to_le32(head);
+				iagp->inofreeback = -1;
+				write_metapage(hbp);
+			}
+
+			imap->im_agctl[n].inofree =
+			    le32_to_cpu(iagp->iagnum);
+
+			/* merge AG backed free inodes */
+			imap->im_agctl[n].numfree +=
+			    le32_to_cpu(iagp->nfreeinos);
+			xnumfree += le32_to_cpu(iagp->nfreeinos);
+		}
+
+		/* if any free extents, insert at AG free extent list */
+		if (le32_to_cpu(iagp->nfreeexts) > 0) {
+			if ((head = imap->im_agctl[n].extfree) == -1)
+				iagp->extfreefwd = iagp->extfreeback = -1;
+			else {
+				if ((rc = diIAGRead(imap, head, &hbp))) {
+					rcx = rc;
+					goto nextiag;
+				}
+				hiagp = (struct iag *) hbp->data;
+				hiagp->extfreeback = iagp->iagnum;
+				iagp->extfreefwd = cpu_to_le32(head);
+				iagp->extfreeback = -1;
+				write_metapage(hbp);
+			}
+
+			imap->im_agctl[n].extfree =
+			    le32_to_cpu(iagp->iagnum);
+		}
+
+	      nextiag:
+		write_metapage(bp);
+	}
+
+	ASSERT(xnuminos == atomic_read(&imap->im_numinos) &&
+	       xnumfree == atomic_read(&imap->im_numfree));
+
+	return rcx;
+}
+
+
+/*
+ *	duplicateIXtree()
+ *
+ * serialization: IWRITE_LOCK held on entry/exit
+ *
+ * note: shadow page with regular inode (rel.2);
+ */
+static void duplicateIXtree(struct super_block *sb, s64 blkno,
+			    int xlen, s64 *xaddr)
+{
+	struct jfs_superblock *j_sb;
+	struct buffer_head *bh;
+	struct inode *ip;
+	tid_t tid;
+	int rc;
+
+	/* if AIT2 ipmap2 is bad, do not try to update it */
+	if (JFS_SBI(sb)->mntflag & JFS_BAD_SAIT)	/* s_flag */
+		return;
+	ip = diReadSpecial(sb, FILESYSTEM_I, 1);
+	if (ip == NULL) {
+		JFS_SBI(sb)->mntflag |= JFS_BAD_SAIT;
+		if ((rc = readSuper(sb, &bh)))
+			return;
+		j_sb = (struct jfs_superblock *)bh->b_data;
+		j_sb->s_flag |= JFS_BAD_SAIT;
+
+		mark_buffer_dirty(bh);
+		ll_rw_block(WRITE, 1, &bh);
+		wait_on_buffer(bh);
+		brelse(bh);
+		return;
+	}
+
+	/* start transaction */
+	tid = txBegin(sb, COMMIT_FORCE);
+	/* update the inode map addressing structure to point to it */
+	if ((rc = xtInsert(tid, ip, 0, blkno, xlen, xaddr, 0))) {
+		JFS_SBI(sb)->mntflag |= JFS_BAD_SAIT;
+		txAbort(tid, 1);
+		goto cleanup;
+
+	}
+	/* update the inode map's inode to reflect the extension */
+	ip->i_size += PSIZE;
+	ip->i_blocks += LBLK2PBLK(sb, xlen);
+	rc = txCommit(tid, 1, &ip, COMMIT_FORCE);
+      cleanup:
+	txEnd(tid);
+	diFreeSpecial(ip);
+}
+
+/*
+ * NAME:        copy_from_dinode()
+ *
+ * FUNCTION:    Copies inode info from disk inode to in-memory inode
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      ENOMEM	- insufficient memory
+ */
+static int copy_from_dinode(struct dinode * dip, struct inode *ip)
+{
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+
+	jfs_ip->fileset = le32_to_cpu(dip->di_fileset);
+	jfs_ip->mode2 = le32_to_cpu(dip->di_mode);
+
+	ip->i_mode = le32_to_cpu(dip->di_mode) & 0xffff;
+	ip->i_nlink = le32_to_cpu(dip->di_nlink);
+	ip->i_uid = le32_to_cpu(dip->di_uid);
+	ip->i_gid = le32_to_cpu(dip->di_gid);
+	ip->i_size = le64_to_cpu(dip->di_size);
+	ip->i_atime = le32_to_cpu(dip->di_atime.tv_sec);
+	ip->i_mtime = le32_to_cpu(dip->di_mtime.tv_sec);
+	ip->i_ctime = le32_to_cpu(dip->di_ctime.tv_sec);
+	ip->i_blksize = ip->i_sb->s_blocksize;
+	ip->i_blocks = LBLK2PBLK(ip->i_sb, le64_to_cpu(dip->di_nblocks));
+	ip->i_generation = le32_to_cpu(dip->di_gen);
+
+	jfs_ip->ixpxd = dip->di_ixpxd;	/* in-memory pxd's are little-endian */
+	jfs_ip->acl = dip->di_acl;	/* as are dxd's */
+	jfs_ip->ea = dip->di_ea;
+	jfs_ip->next_index = le32_to_cpu(dip->di_next_index);
+	jfs_ip->otime = le32_to_cpu(dip->di_otime.tv_sec);
+	jfs_ip->acltype = le32_to_cpu(dip->di_acltype);
+
+	if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode))
+		ip->i_rdev = to_kdev_t(le32_to_cpu(dip->di_rdev));
+
+	if (S_ISDIR(ip->i_mode)) {
+		memcpy(&jfs_ip->i_dirtable, &dip->di_dirtable, 384);
+	} else if (S_ISREG(ip->i_mode) || S_ISLNK(ip->i_mode)) {
+		memcpy(&jfs_ip->i_xtroot, &dip->di_xtroot, 288);
+	} else
+		memcpy(&jfs_ip->i_inline_ea, &dip->di_inlineea, 128);
+
+	/* Zero the in-memory-only stuff */
+	jfs_ip->cflag = 0;
+	jfs_ip->btindex = 0;
+	jfs_ip->btorder = 0;
+	jfs_ip->bxflag = 0;
+	jfs_ip->blid = 0;
+	jfs_ip->atlhead = 0;
+	jfs_ip->atltail = 0;
+	jfs_ip->xtlid = 0;
+	return (0);
+}
+
+/*
+ * NAME:        copy_to_dinode()
+ *
+ * FUNCTION:    Copies inode info from in-memory inode to disk inode
+ */
+static void copy_to_dinode(struct dinode * dip, struct inode *ip)
+{
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+
+	dip->di_fileset = cpu_to_le32(jfs_ip->fileset);
+	dip->di_inostamp = cpu_to_le32(JFS_SBI(ip->i_sb)->inostamp);
+	dip->di_number = cpu_to_le32(ip->i_ino);
+	dip->di_gen = cpu_to_le32(ip->i_generation);
+	dip->di_size = cpu_to_le64(ip->i_size);
+	dip->di_nblocks = cpu_to_le64(PBLK2LBLK(ip->i_sb, ip->i_blocks));
+	dip->di_nlink = cpu_to_le32(ip->i_nlink);
+	dip->di_uid = cpu_to_le32(ip->i_uid);
+	dip->di_gid = cpu_to_le32(ip->i_gid);
+	/*
+	 * mode2 is only needed for storing the higher order bits.
+	 * Trust i_mode for the lower order ones
+	 */
+	dip->di_mode = cpu_to_le32((jfs_ip->mode2 & 0xffff0000) | ip->i_mode);
+	dip->di_atime.tv_sec = cpu_to_le32(ip->i_atime);
+	dip->di_atime.tv_nsec = 0;
+	dip->di_ctime.tv_sec = cpu_to_le32(ip->i_ctime);
+	dip->di_ctime.tv_nsec = 0;
+	dip->di_mtime.tv_sec = cpu_to_le32(ip->i_mtime);
+	dip->di_mtime.tv_nsec = 0;
+	dip->di_ixpxd = jfs_ip->ixpxd;	/* in-memory pxd's are little-endian */
+	dip->di_acl = jfs_ip->acl;	/* as are dxd's */
+	dip->di_ea = jfs_ip->ea;
+	dip->di_next_index = cpu_to_le32(jfs_ip->next_index);
+	dip->di_otime.tv_sec = cpu_to_le32(jfs_ip->otime);
+	dip->di_otime.tv_nsec = 0;
+	dip->di_acltype = cpu_to_le32(jfs_ip->acltype);
+
+	if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode))
+		dip->di_rdev = cpu_to_le32(kdev_t_to_nr(ip->i_rdev));
+}
+
+#ifdef	_JFS_DEBUG_IMAP
+/*
+ *	DBGdiInit()
+ */
+static void *DBGdiInit(struct inomap * imap)
+{
+	u32 *dimap;
+	int size;
+	size = 64 * 1024;
+	if ((dimap = (u32 *) xmalloc(size, L2PSIZE, kernel_heap)) == NULL)
+		assert(0);
+	bzero((void *) dimap, size);
+	imap->im_DBGdimap = dimap;
+}
+
+/*
+ *	DBGdiAlloc()
+ */
+static void DBGdiAlloc(struct inomap * imap, ino_t ino)
+{
+	u32 *dimap = imap->im_DBGdimap;
+	int w, b;
+	u32 m;
+	w = ino >> 5;
+	b = ino & 31;
+	m = 0x80000000 >> b;
+	assert(w < 64 * 256);
+	if (dimap[w] & m) {
+		printk("DEBUG diAlloc: duplicate alloc ino:0x%x\n", ino);
+	}
+	dimap[w] |= m;
+}
+
+/*
+ *	DBGdiFree()
+ */
+static void DBGdiFree(struct inomap * imap, ino_t ino)
+{
+	u32 *dimap = imap->im_DBGdimap;
+	int w, b;
+	u32 m;
+	w = ino >> 5;
+	b = ino & 31;
+	m = 0x80000000 >> b;
+	assert(w < 64 * 256);
+	if ((dimap[w] & m) == 0) {
+		printk("DEBUG diFree: duplicate free ino:0x%x\n", ino);
+	}
+	dimap[w] &= ~m;
+}
+
+static void dump_cp(struct inomap * ipimap, char *function, int line)
+{
+	printk("\n* ********* *\nControl Page %s %d\n", function, line);
+	printk("FreeIAG %d\tNextIAG %d\n", ipimap->im_freeiag,
+	       ipimap->im_nextiag);
+	printk("NumInos %d\tNumFree %d\n",
+	       atomic_read(&ipimap->im_numinos),
+	       atomic_read(&ipimap->im_numfree));
+	printk("AG InoFree %d\tAG ExtFree %d\n",
+	       ipimap->im_agctl[0].inofree, ipimap->im_agctl[0].extfree);
+	printk("AG NumInos %d\tAG NumFree %d\n",
+	       ipimap->im_agctl[0].numinos, ipimap->im_agctl[0].numfree);
+}
+
+static void dump_iag(struct iag * iag, char *function, int line)
+{
+	printk("\n* ********* *\nIAG %s %d\n", function, line);
+	printk("IagNum %d\tIAG Free %d\n", le32_to_cpu(iag->iagnum),
+	       le32_to_cpu(iag->iagfree));
+	printk("InoFreeFwd %d\tInoFreeBack %d\n",
+	       le32_to_cpu(iag->inofreefwd),
+	       le32_to_cpu(iag->inofreeback));
+	printk("ExtFreeFwd %d\tExtFreeBack %d\n",
+	       le32_to_cpu(iag->extfreefwd),
+	       le32_to_cpu(iag->extfreeback));
+	printk("NFreeInos %d\tNFreeExts %d\n", le32_to_cpu(iag->nfreeinos),
+	       le32_to_cpu(iag->nfreeexts));
+}
+#endif				/* _JFS_DEBUG_IMAP */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_imap.h linux-2.4.20/fs/jfs/jfs_imap.h
--- linux-2.4.19/fs/jfs/jfs_imap.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_imap.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,157 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+#ifndef	_H_JFS_IMAP
+#define _H_JFS_IMAP
+
+#include "jfs_txnmgr.h"
+
+/*
+ *	jfs_imap.h: disk inode manager
+ */
+
+#define	EXTSPERIAG	128	/* number of disk inode extent per iag  */
+#define IMAPBLKNO	0	/* lblkno of dinomap within inode map   */
+#define SMAPSZ		4	/* number of words per summary map      */
+#define	EXTSPERSUM	32	/* number of extents per summary map entry */
+#define	L2EXTSPERSUM	5	/* l2 number of extents per summary map */
+#define	PGSPERIEXT	4	/* number of 4K pages per dinode extent */
+#define	MAXIAGS		((1<<20)-1)	/* maximum number of iags       */
+#define	MAXAG		128	/* maximum number of allocation groups  */
+
+#define AMAPSIZE      512	/* bytes in the IAG allocation maps */
+#define SMAPSIZE      16	/* bytes in the IAG summary maps */
+
+/* convert inode number to iag number */
+#define	INOTOIAG(ino)	((ino) >> L2INOSPERIAG)
+
+/* convert iag number to logical block number of the iag page */
+#define IAGTOLBLK(iagno,l2nbperpg)	(((iagno) + 1) << (l2nbperpg))
+
+/* get the starting block number of the 4K page of an inode extent
+ * that contains ino.
+ */
+#define INOPBLK(pxd,ino,l2nbperpg)    	(addressPXD((pxd)) +		\
+	((((ino) & (INOSPEREXT-1)) >> L2INOSPERPAGE) << (l2nbperpg)))
+
+/*
+ *	inode allocation map:
+ * 
+ * inode allocation map consists of 
+ * . the inode map control page and
+ * . inode allocation group pages (per 4096 inodes)
+ * which are addressed by standard JFS xtree.
+ */
+/*
+ *	inode allocation group page (per 4096 inodes of an AG)
+ */
+struct iag {
+	s64 agstart;		/* 8: starting block of ag              */
+	s32 iagnum;		/* 4: inode allocation group number     */
+	s32 inofreefwd;		/* 4: ag inode free list forward        */
+	s32 inofreeback;	/* 4: ag inode free list back           */
+	s32 extfreefwd;		/* 4: ag inode extent free list forward */
+	s32 extfreeback;	/* 4: ag inode extent free list back    */
+	s32 iagfree;		/* 4: iag free list                     */
+
+	/* summary map: 1 bit per inode extent */
+	s32 inosmap[SMAPSZ];	/* 16: sum map of mapwords w/ free inodes;
+				 *      note: this indicates free and backed
+				 *      inodes, if the extent is not backed the
+				 *      value will be 1.  if the extent is
+				 *      backed but all inodes are being used the
+				 *      value will be 1.  if the extent is
+				 *      backed but at least one of the inodes is
+				 *      free the value will be 0.
+				 */
+	s32 extsmap[SMAPSZ];	/* 16: sum map of mapwords w/ free extents */
+	s32 nfreeinos;		/* 4: number of free inodes             */
+	s32 nfreeexts;		/* 4: number of free extents            */
+	/* (72) */
+	u8 pad[1976];		/* 1976: pad to 2048 bytes */
+	/* allocation bit map: 1 bit per inode (0 - free, 1 - allocated) */
+	u32 wmap[EXTSPERIAG];	/* 512: working allocation map  */
+	u32 pmap[EXTSPERIAG];	/* 512: persistent allocation map */
+	pxd_t inoext[EXTSPERIAG];	/* 1024: inode extent addresses */
+};				/* (4096) */
+
+/*
+ *	per AG control information (in inode map control page)
+ */
+struct iagctl {
+	s32 inofree;		/* 4: free inode list anchor            */
+	s32 extfree;		/* 4: free extent list anchor           */
+	s32 numinos;		/* 4: number of backed inodes           */
+	s32 numfree;		/* 4: number of free inodes             */
+};				/* (16) */
+
+/*
+ *	per fileset/aggregate inode map control page
+ */
+struct dinomap {
+	s32 in_freeiag;		/* 4: free iag list anchor     */
+	s32 in_nextiag;		/* 4: next free iag number     */
+	s32 in_numinos;		/* 4: num of backed inodes */
+	s32 in_numfree;		/* 4: num of free backed inodes */
+	s32 in_nbperiext;	/* 4: num of blocks per inode extent */
+	s32 in_l2nbperiext;	/* 4: l2 of in_nbperiext */
+	s32 in_diskblock;	/* 4: for standalone test driver  */
+	s32 in_maxag;		/* 4: for standalone test driver  */
+	u8 pad[2016];		/* 2016: pad to 2048 */
+	struct iagctl in_agctl[MAXAG];	/* 2048: AG control information */
+};				/* (4096) */
+
+
+/*
+ *	In-core inode map control page
+ */
+struct inomap {
+	struct dinomap im_imap;		/* 4096: inode allocation control */
+	struct inode *im_ipimap;	/* 4: ptr to inode for imap   */
+	struct semaphore im_freelock;	/* 4: iag free list lock      */
+	struct semaphore im_aglock[MAXAG];	/* 512: per AG locks          */
+	u32 *im_DBGdimap;
+	atomic_t im_numinos;	/* num of backed inodes */
+	atomic_t im_numfree;	/* num of free backed inodes */
+};
+
+#define	im_freeiag	im_imap.in_freeiag
+#define	im_nextiag	im_imap.in_nextiag
+#define	im_agctl	im_imap.in_agctl
+#define	im_nbperiext	im_imap.in_nbperiext
+#define	im_l2nbperiext	im_imap.in_l2nbperiext
+
+/* for standalone testdriver
+ */
+#define	im_diskblock	im_imap.in_diskblock
+#define	im_maxag	im_imap.in_maxag
+
+extern int diFree(struct inode *);
+extern int diAlloc(struct inode *, boolean_t, struct inode *);
+extern int diSync(struct inode *);
+/* external references */
+extern int diUpdatePMap(struct inode *ipimap, unsigned long inum,
+			boolean_t is_free, struct tblock * tblk);
+extern int diExtendFS(struct inode *ipimap, struct inode *ipbmap);
+extern int diMount(struct inode *);
+extern int diUnmount(struct inode *, int);
+extern int diRead(struct inode *);
+extern struct inode *diReadSpecial(struct super_block *, ino_t, int);
+extern void diWriteSpecial(struct inode *, int);
+extern void diFreeSpecial(struct inode *);
+extern int diWrite(tid_t tid, struct inode *);
+#endif				/* _H_JFS_IMAP */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_incore.h linux-2.4.20/fs/jfs/jfs_incore.h
--- linux-2.4.19/fs/jfs/jfs_incore.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_incore.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,184 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *
+ *   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
+ */ 
+#ifndef _H_JFS_INCORE
+#define _H_JFS_INCORE
+
+#include <linux/rwsem.h>
+#include <linux/slab.h>
+#include <asm/bitops.h>
+#include "jfs_types.h"
+#include "jfs_xtree.h"
+#include "jfs_dtree.h"
+
+/*
+ * JFS magic number
+ */
+#define JFS_SUPER_MAGIC 0x3153464a /* "JFS1" */
+
+/*
+ * JFS-private inode information
+ */
+struct jfs_inode_info {
+	struct inode *inode;	/* pointer back to fs-independent inode */
+	int	fileset;	/* fileset number (always 16)*/
+	uint	mode2;		/* jfs-specific mode		*/
+	pxd_t   ixpxd;		/* inode extent descriptor	*/
+	dxd_t	acl;		/* dxd describing acl	*/
+	dxd_t	ea;		/* dxd describing ea	*/
+	time_t	otime;		/* time created	*/
+	uint	next_index;	/* next available directory entry index */
+	int	acltype;	/* Type of ACL	*/
+	short	btorder;	/* access order	*/
+	short	btindex;	/* btpage entry index*/
+	struct inode *ipimap;	/* inode map			*/
+	long	cflag;		/* commit flags		*/
+	u16	bxflag;		/* xflag of pseudo buffer?	*/
+	unchar	agno;		/* ag number			*/
+	signed char active_ag;	/* ag currently allocating from	*/
+	lid_t	blid;		/* lid of pseudo buffer?	*/
+	lid_t	atlhead;	/* anonymous tlock list head	*/
+	lid_t	atltail;	/* anonymous tlock list tail	*/
+	struct list_head anon_inode_list; /* inodes having anonymous txns */
+	struct list_head mp_list; /* metapages in inode's address space */
+	/*
+	 * rdwrlock serializes xtree between reads & writes and synchronizes
+	 * changes to special inodes.  It's use would be redundant on
+	 * directories since the i_sem taken in the VFS is sufficient.
+	 */
+	struct rw_semaphore rdwrlock;
+	/*
+	 * commit_sem serializes transaction processing on an inode.
+	 * It must be taken after beginning a transaction (txBegin), since
+	 * dirty inodes may be committed while a new transaction on the
+	 * inode is blocked in txBegin or TxBeginAnon
+	 */
+	struct semaphore commit_sem;
+	lid_t	xtlid;		/* lid of xtree lock on directory */
+	union {
+		struct {
+			xtpage_t _xtroot;	/* 288: xtree root */
+			struct inomap *_imap;	/* 4: inode map header	*/
+		} file;
+		struct {
+			struct dir_table_slot _table[12]; /* 96: dir index */
+			dtroot_t _dtroot;	/* 288: dtree root */
+		} dir;
+		struct {
+			unchar _unused[16];	/* 16: */
+			dxd_t _dxd;		/* 16: */
+			unchar _inline[128];	/* 128: inline symlink */
+			/* _inline_ea may overlay the last part of
+			 * file._xtroot if maxentry = XTROOTINITSLOT
+			 */
+			unchar _inline_ea[128];	/* 128: inline extended attr */
+		} link;
+	} u;
+};
+#define i_xtroot u.file._xtroot
+#define i_imap u.file._imap
+#define i_dirtable u.dir._table
+#define i_dtroot u.dir._dtroot
+#define i_inline u.link._inline
+#define i_inline_ea u.link._inline_ea
+
+
+#define IREAD_LOCK(ip)		down_read(&JFS_IP(ip)->rdwrlock)
+#define IREAD_UNLOCK(ip)	up_read(&JFS_IP(ip)->rdwrlock)
+#define IWRITE_LOCK(ip)		down_write(&JFS_IP(ip)->rdwrlock)
+#define IWRITE_UNLOCK(ip)	up_write(&JFS_IP(ip)->rdwrlock)
+
+/*
+ * cflag
+ */
+enum cflags {
+	COMMIT_New,		/* never committed inode   */
+	COMMIT_Nolink,		/* inode committed with zero link count */
+	COMMIT_Inlineea,	/* commit inode inline EA */
+	COMMIT_Freewmap,	/* free WMAP at iClose() */
+	COMMIT_Dirty,		/* Inode is really dirty */
+	COMMIT_Holdlock,	/* Hold the IWRITE_LOCK until commit is done */
+	COMMIT_Dirtable,	/* commit changes to di_dirtable */
+	COMMIT_Stale,		/* data extent is no longer valid */
+	COMMIT_Synclist,	/* metadata pages on group commit synclist */
+};
+
+#define set_cflag(flag, ip)	set_bit(flag, &(JFS_IP(ip)->cflag))
+#define clear_cflag(flag, ip)	clear_bit(flag, &(JFS_IP(ip)->cflag))
+#define test_cflag(flag, ip)	test_bit(flag, &(JFS_IP(ip)->cflag))
+#define test_and_clear_cflag(flag, ip) \
+	test_and_clear_bit(flag, &(JFS_IP(ip)->cflag))
+/*
+ * JFS-private superblock information.
+ */
+struct jfs_sb_info {
+	unsigned long	mntflag;	/* 4: aggregate attributes	*/
+	struct inode	*ipbmap;	/* 4: block map inode		*/
+	struct inode	*ipaimap;	/* 4: aggregate inode map inode	*/
+	struct inode	*ipaimap2;	/* 4: secondary aimap inode	*/
+	struct inode	*ipimap;	/* 4: aggregate inode map inode	*/
+	struct jfs_log	*log;		/* 4: log			*/
+	short		bsize;		/* 2: logical block size	*/
+	short		l2bsize;	/* 2: log2 logical block size	*/
+	short		nbperpage;	/* 2: blocks per page		*/
+	short		l2nbperpage;	/* 2: log2 blocks per page	*/
+	short		l2niperblk;	/* 2: log2 inodes per page	*/
+	kdev_t		logdev;		/* 2: external log device	*/
+	uint		aggregate;	/* volume identifier in log record */
+	pxd_t		logpxd;		/* 8: pxd describing log	*/
+	pxd_t		fsckpxd;	/* 8: pxd describing fsck wkspc */
+	pxd_t		ait2;		/* 8: pxd describing AIT copy	*/
+	char		uuid[16];	/* 16: 128-bit uuid for volume	*/
+	char		loguuid[16];	/* 16: 128-bit uuid for log	*/
+	/* Formerly in ipimap */
+	uint		gengen;		/* 4: inode generation generator*/
+	uint		inostamp;	/* 4: shows inode belongs to fileset*/
+
+        /* Formerly in ipbmap */
+	struct bmap	*bmap;		/* 4: incore bmap descriptor	*/
+	struct nls_table *nls_tab;	/* 4: current codepage		*/
+	uint		state;		/* 4: mount/recovery state	*/
+};
+
+static inline struct jfs_inode_info *JFS_IP(struct inode *inode)
+{
+	return inode->u.generic_ip;
+}
+
+static inline struct jfs_sb_info *JFS_SBI(struct super_block *sb)
+{
+	return sb->u.generic_sbp;
+}
+
+static inline int isReadOnly(struct inode *inode)
+{
+	if (JFS_SBI(inode->i_sb)->log)
+		return 0;
+	return 1;
+}
+
+/*
+ * Allocating and freeing the structure
+ */
+extern kmem_cache_t *jfs_inode_cachep;
+extern int alloc_jfs_inode(struct inode *);
+
+#define free_jfs_inode(inode) \
+	kmem_cache_free(jfs_inode_cachep, (inode)->u.generic_ip)
+
+#endif /* _H_JFS_INCORE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_inode.c linux-2.4.20/fs/jfs/jfs_inode.c
--- linux-2.4.19/fs/jfs/jfs_inode.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_inode.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,121 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+
+#include <linux/fs.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_imap.h"
+#include "jfs_dinode.h"
+#include "jfs_debug.h"
+
+kmem_cache_t *jfs_inode_cachep;
+
+/*
+ * NAME:	ialloc()
+ *
+ * FUNCTION:	Allocate a new inode
+ *
+ */
+struct inode *ialloc(struct inode *parent, umode_t mode)
+{
+	struct super_block *sb = parent->i_sb;
+	struct inode *inode;
+	struct jfs_inode_info *jfs_inode;
+	int rc;
+
+	inode = new_inode(sb);
+	if (!inode) {
+		jERROR(1, ("ialloc: new_inode returned NULL!\n"));
+		return inode;
+	}
+
+	rc = alloc_jfs_inode(inode);
+	if (rc) {
+		make_bad_inode(inode);
+		iput(inode);
+		return NULL;
+	}
+	jfs_inode = JFS_IP(inode);
+
+	rc = diAlloc(parent, S_ISDIR(mode), inode);
+	if (rc) {
+		jERROR(1, ("ialloc: diAlloc returned %d!\n", rc));
+		free_jfs_inode(inode);
+		make_bad_inode(inode);
+		iput(inode);
+		return NULL;
+	}
+
+	inode->i_uid = current->fsuid;
+	if (parent->i_mode & S_ISGID) {
+		inode->i_gid = parent->i_gid;
+		if (S_ISDIR(mode))
+			mode |= S_ISGID;
+	} else
+		inode->i_gid = current->fsgid;
+
+	inode->i_mode = mode;
+	if (S_ISDIR(mode))
+		jfs_inode->mode2 = IDIRECTORY | mode;
+	else
+		jfs_inode->mode2 = INLINEEA | ISPARSE | mode;
+	inode->i_blksize = sb->s_blocksize;
+	inode->i_blocks = 0;
+	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+	jfs_inode->otime = inode->i_ctime;
+	inode->i_generation = JFS_SBI(sb)->gengen++;
+
+	jfs_inode->cflag = 0;
+	set_cflag(COMMIT_New, inode);
+
+	/* Zero remaining fields */
+	memset(&jfs_inode->acl, 0, sizeof(dxd_t));
+	memset(&jfs_inode->ea, 0, sizeof(dxd_t));
+	jfs_inode->next_index = 0;
+	jfs_inode->acltype = 0;
+	jfs_inode->btorder = 0;
+	jfs_inode->btindex = 0;
+	jfs_inode->bxflag = 0;
+	jfs_inode->blid = 0;
+	jfs_inode->atlhead = 0;
+	jfs_inode->atltail = 0;
+	jfs_inode->xtlid = 0;
+
+	jFYI(1, ("ialloc returns inode = 0x%p\n", inode));
+
+	return inode;
+}
+
+/*
+ * NAME:	alloc_jfs_inode()
+ *
+ * FUNCTION:	Allocate jfs portion of in-memory inode
+ *
+ */
+int alloc_jfs_inode(struct inode *inode)
+{
+	struct jfs_inode_info *jfs_inode;
+
+	jfs_inode = kmem_cache_alloc(jfs_inode_cachep, GFP_NOFS);
+	inode->u.generic_ip = jfs_inode;
+	if (!jfs_inode)
+		return -ENOSPC;
+	jfs_inode->inode = inode;
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_inode.h linux-2.4.20/fs/jfs/jfs_inode.h
--- linux-2.4.19/fs/jfs/jfs_inode.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_inode.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,23 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2001
+ *
+ *   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
+ */
+#ifndef	_H_JFS_INODE
+#define _H_JFS_INODE
+
+extern struct inode *ialloc(struct inode *, umode_t);
+
+#endif				/* _H_JFS_INODE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_lock.h linux-2.4.20/fs/jfs/jfs_lock.h
--- linux-2.4.19/fs/jfs/jfs_lock.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_lock.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,51 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2001
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *
+ *   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
+ */
+#ifndef _H_JFS_LOCK
+#define _H_JFS_LOCK
+
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+
+/*
+ *	jfs_lock.h
+ */
+
+/*
+ * Conditional sleep where condition is protected by spinlock
+ *
+ * lock_cmd and unlock_cmd take and release the spinlock
+ */
+#define __SLEEP_COND(wq, cond, lock_cmd, unlock_cmd)	\
+do {							\
+	DECLARE_WAITQUEUE(__wait, current);		\
+							\
+	add_wait_queue(&wq, &__wait);			\
+	for (;;) {					\
+		set_current_state(TASK_UNINTERRUPTIBLE);\
+		if (cond)				\
+			break;				\
+		unlock_cmd;				\
+		schedule();				\
+		lock_cmd;				\
+	}						\
+	current->state = TASK_RUNNING;			\
+	remove_wait_queue(&wq, &__wait);		\
+} while (0)
+
+#endif				/* _H_JFS_LOCK */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_logmgr.c linux-2.4.20/fs/jfs/jfs_logmgr.c
--- linux-2.4.19/fs/jfs/jfs_logmgr.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_logmgr.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,2310 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *
+ *   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
+ */
+
+/*
+ *	jfs_logmgr.c: log manager
+ *
+ * for related information, see transaction manager (jfs_txnmgr.c), and
+ * recovery manager (jfs_logredo.c).
+ *
+ * note: for detail, RTFS.
+ *
+ *	log buffer manager:
+ * special purpose buffer manager supporting log i/o requirements.
+ * per log serial pageout of logpage
+ * queuing i/o requests and redrive i/o at iodone
+ * maintain current logpage buffer
+ * no caching since append only
+ * appropriate jfs buffer cache buffers as needed
+ *
+ *	group commit:
+ * transactions which wrote COMMIT records in the same in-memory
+ * log page during the pageout of previous/current log page(s) are
+ * committed together by the pageout of the page.
+ *
+ *	TBD lazy commit:
+ * transactions are committed asynchronously when the log page
+ * containing it COMMIT is paged out when it becomes full;
+ *
+ *	serialization:
+ * . a per log lock serialize log write.
+ * . a per log lock serialize group commit.
+ * . a per log lock serialize log open/close;
+ *
+ *	TBD log integrity:
+ * careful-write (ping-pong) of last logpage to recover from crash
+ * in overwrite.
+ * detection of split (out-of-order) write of physical sectors
+ * of last logpage via timestamp at end of each sector
+ * with its mirror data array at trailer).
+ *
+ *	alternatives:
+ * lsn - 64-bit monotonically increasing integer vs
+ * 32-bit lspn and page eor.
+ */
+
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
+#include <linux/completion.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_metapage.h"
+#include "jfs_txnmgr.h"
+#include "jfs_debug.h"
+
+
+/*
+ * lbuf's ready to be redriven.  Protected by log_redrive_lock (jfsIO thread)
+ */
+static struct lbuf *log_redrive_list;
+static spinlock_t log_redrive_lock = SPIN_LOCK_UNLOCKED;
+DECLARE_WAIT_QUEUE_HEAD(jfs_IO_thread_wait);
+
+
+/*
+ *	log read/write serialization (per log)
+ */
+#define LOG_LOCK_INIT(log)	init_MUTEX(&(log)->loglock)
+#define LOG_LOCK(log)		down(&((log)->loglock))
+#define LOG_UNLOCK(log)		up(&((log)->loglock))
+
+
+/*
+ *	log group commit serialization (per log)
+ */
+
+#define LOGGC_LOCK_INIT(log)	spin_lock_init(&(log)->gclock)
+#define LOGGC_LOCK(log)		spin_lock_irq(&(log)->gclock)
+#define LOGGC_UNLOCK(log)	spin_unlock_irq(&(log)->gclock)
+#define LOGGC_WAKEUP(tblk)	wake_up(&(tblk)->gcwait)
+
+/*
+ *	log sync serialization (per log)
+ */
+#define	LOGSYNC_DELTA(logsize)		min((logsize)/8, 128*LOGPSIZE)
+#define	LOGSYNC_BARRIER(logsize)	((logsize)/4)
+/*
+#define	LOGSYNC_DELTA(logsize)		min((logsize)/4, 256*LOGPSIZE)
+#define	LOGSYNC_BARRIER(logsize)	((logsize)/2)
+*/
+
+
+/*
+ *	log buffer cache synchronization
+ */
+static spinlock_t jfsLCacheLock = SPIN_LOCK_UNLOCKED;
+
+#define	LCACHE_LOCK(flags)	spin_lock_irqsave(&jfsLCacheLock, flags)
+#define	LCACHE_UNLOCK(flags)	spin_unlock_irqrestore(&jfsLCacheLock, flags)
+
+/*
+ * See __SLEEP_COND in jfs_locks.h
+ */
+#define LCACHE_SLEEP_COND(wq, cond, flags)	\
+do {						\
+	if (cond)				\
+		break;				\
+	__SLEEP_COND(wq, cond, LCACHE_LOCK(flags), LCACHE_UNLOCK(flags)); \
+} while (0)
+
+#define	LCACHE_WAKEUP(event)	wake_up(event)
+
+
+/*
+ *	lbuf buffer cache (lCache) control
+ */
+/* log buffer manager pageout control (cumulative, inclusive) */
+#define	lbmREAD		0x0001
+#define	lbmWRITE	0x0002	/* enqueue at tail of write queue;
+				 * init pageout if at head of queue;
+				 */
+#define	lbmRELEASE	0x0004	/* remove from write queue
+				 * at completion of pageout;
+				 * do not free/recycle it yet:
+				 * caller will free it;
+				 */
+#define	lbmSYNC		0x0008	/* do not return to freelist
+				 * when removed from write queue;
+				 */
+#define lbmFREE		0x0010	/* return to freelist
+				 * at completion of pageout;
+				 * the buffer may be recycled;
+				 */
+#define	lbmDONE		0x0020
+#define	lbmERROR	0x0040
+#define lbmGC		0x0080	/* lbmIODone to perform post-GC processing
+				 * of log page
+				 */
+#define lbmDIRECT	0x0100
+
+/*
+ * external references
+ */
+extern void txLazyUnlock(struct tblock * tblk);
+extern int jfs_stop_threads;
+extern struct completion jfsIOwait;
+
+/*
+ * forward references
+ */
+static int lmWriteRecord(struct jfs_log * log, struct tblock * tblk,
+			 struct lrd * lrd, struct tlock * tlck);
+
+static int lmNextPage(struct jfs_log * log);
+static int lmLogFileSystem(struct jfs_log * log, char *uuid, int activate);
+
+static int lbmLogInit(struct jfs_log * log);
+static void lbmLogShutdown(struct jfs_log * log);
+static struct lbuf *lbmAllocate(struct jfs_log * log, int);
+static void lbmFree(struct lbuf * bp);
+static void lbmfree(struct lbuf * bp);
+static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp);
+static void lbmWrite(struct jfs_log * log, struct lbuf * bp, int flag,
+		     int cant_block);
+static void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag);
+static int lbmIOWait(struct lbuf * bp, int flag);
+static void lbmIODone(struct buffer_head *bh, int);
+
+void lbmStartIO(struct lbuf * bp);
+void lmGCwrite(struct jfs_log * log, int cant_block);
+
+
+/*
+ *	statistics
+ */
+#ifdef CONFIG_JFS_STATISTICS
+struct lmStat {
+	uint commit;		/* # of commit */
+	uint pagedone;		/* # of page written */
+	uint submitted;		/* # of pages submitted */
+} lmStat;
+#endif
+
+
+/*
+ * NAME:	lmLog()
+ *
+ * FUNCTION:	write a log record;
+ *
+ * PARAMETER:
+ *
+ * RETURN:	lsn - offset to the next log record to write (end-of-log);
+ *		-1  - error;
+ *
+ * note: todo: log error handler
+ */
+int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	  struct tlock * tlck)
+{
+	int lsn;
+	int diffp, difft;
+	struct metapage *mp = NULL;
+
+	jFYI(1, ("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p\n",
+		 log, tblk, lrd, tlck));
+
+	LOG_LOCK(log);
+
+	/* log by (out-of-transaction) JFS ? */
+	if (tblk == NULL)
+		goto writeRecord;
+
+	/* log from page ? */
+	if (tlck == NULL ||
+	    tlck->type & tlckBTROOT || (mp = tlck->mp) == NULL)
+		goto writeRecord;
+
+	/*
+	 *      initialize/update page/transaction recovery lsn
+	 */
+	lsn = log->lsn;
+
+	LOGSYNC_LOCK(log);
+
+	/*
+	 * initialize page lsn if first log write of the page
+	 */
+	if (mp->lsn == 0) {
+		mp->log = log;
+		mp->lsn = lsn;
+		log->count++;
+
+		/* insert page at tail of logsynclist */
+		list_add_tail(&mp->synclist, &log->synclist);
+	}
+
+	/*
+	 *      initialize/update lsn of tblock of the page
+	 *
+	 * transaction inherits oldest lsn of pages associated
+	 * with allocation/deallocation of resources (their
+	 * log records are used to reconstruct allocation map
+	 * at recovery time: inode for inode allocation map,
+	 * B+-tree index of extent descriptors for block
+	 * allocation map);
+	 * allocation map pages inherit transaction lsn at
+	 * commit time to allow forwarding log syncpt past log
+	 * records associated with allocation/deallocation of
+	 * resources only after persistent map of these map pages
+	 * have been updated and propagated to home.
+	 */
+	/*
+	 * initialize transaction lsn:
+	 */
+	if (tblk->lsn == 0) {
+		/* inherit lsn of its first page logged */
+		tblk->lsn = mp->lsn;
+		log->count++;
+
+		/* insert tblock after the page on logsynclist */
+		list_add(&tblk->synclist, &mp->synclist);
+	}
+	/*
+	 * update transaction lsn:
+	 */
+	else {
+		/* inherit oldest/smallest lsn of page */
+		logdiff(diffp, mp->lsn, log);
+		logdiff(difft, tblk->lsn, log);
+		if (diffp < difft) {
+			/* update tblock lsn with page lsn */
+			tblk->lsn = mp->lsn;
+
+			/* move tblock after page on logsynclist */
+			list_del(&tblk->synclist);
+			list_add(&tblk->synclist, &mp->synclist);
+		}
+	}
+
+	LOGSYNC_UNLOCK(log);
+
+	/*
+	 *      write the log record
+	 */
+      writeRecord:
+	lsn = lmWriteRecord(log, tblk, lrd, tlck);
+
+	/*
+	 * forward log syncpt if log reached next syncpt trigger
+	 */
+	logdiff(diffp, lsn, log);
+	if (diffp >= log->nextsync)
+		lsn = lmLogSync(log, 0);
+
+	/* update end-of-log lsn */
+	log->lsn = lsn;
+
+	LOG_UNLOCK(log);
+
+	/* return end-of-log address */
+	return lsn;
+}
+
+
+/*
+ * NAME:	lmWriteRecord()
+ *
+ * FUNCTION:	move the log record to current log page
+ *
+ * PARAMETER:	cd	- commit descriptor
+ *
+ * RETURN:	end-of-log address
+ *			
+ * serialization: LOG_LOCK() held on entry/exit
+ */
+static int
+lmWriteRecord(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	      struct tlock * tlck)
+{
+	int lsn = 0;		/* end-of-log address */
+	struct lbuf *bp;	/* dst log page buffer */
+	struct logpage *lp;	/* dst log page */
+	caddr_t dst;		/* destination address in log page */
+	int dstoffset;		/* end-of-log offset in log page */
+	int freespace;		/* free space in log page */
+	caddr_t p;		/* src meta-data page */
+	caddr_t src;
+	int srclen;
+	int nbytes;		/* number of bytes to move */
+	int i;
+	int len;
+	struct linelock *linelock;
+	struct lv *lv;
+	struct lvd *lvd;
+	int l2linesize;
+
+	len = 0;
+
+	/* retrieve destination log page to write */
+	bp = (struct lbuf *) log->bp;
+	lp = (struct logpage *) bp->l_ldata;
+	dstoffset = log->eor;
+
+	/* any log data to write ? */
+	if (tlck == NULL)
+		goto moveLrd;
+
+	/*
+	 *      move log record data
+	 */
+	/* retrieve source meta-data page to log */
+	if (tlck->flag & tlckPAGELOCK) {
+		p = (caddr_t) (tlck->mp->data);
+		linelock = (struct linelock *) & tlck->lock;
+	}
+	/* retrieve source in-memory inode to log */
+	else if (tlck->flag & tlckINODELOCK) {
+		if (tlck->type & tlckDTREE)
+			p = (caddr_t) &JFS_IP(tlck->ip)->i_dtroot;
+		else
+			p = (caddr_t) &JFS_IP(tlck->ip)->i_xtroot;
+		linelock = (struct linelock *) & tlck->lock;
+	}
+#ifdef	_JFS_WIP
+	else if (tlck->flag & tlckINLINELOCK) {
+
+		inlinelock = (struct inlinelock *) & tlck;
+		p = (caddr_t) & inlinelock->pxd;
+		linelock = (struct linelock *) & tlck;
+	}
+#endif				/* _JFS_WIP */
+	else {
+		jERROR(2, ("lmWriteRecord: UFO tlck:0x%p\n", tlck));
+		return 0;	/* Probably should trap */
+	}
+	l2linesize = linelock->l2linesize;
+
+      moveData:
+	ASSERT(linelock->index <= linelock->maxcnt);
+
+	lv = linelock->lv;
+	for (i = 0; i < linelock->index; i++, lv++) {
+		if (lv->length == 0)
+			continue;
+
+		/* is page full ? */
+		if (dstoffset >= LOGPSIZE - LOGPTLRSIZE) {
+			/* page become full: move on to next page */
+			lmNextPage(log);
+
+			bp = log->bp;
+			lp = (struct logpage *) bp->l_ldata;
+			dstoffset = LOGPHDRSIZE;
+		}
+
+		/*
+		 * move log vector data
+		 */
+		src = (u8 *) p + (lv->offset << l2linesize);
+		srclen = lv->length << l2linesize;
+		len += srclen;
+		while (srclen > 0) {
+			freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset;
+			nbytes = min(freespace, srclen);
+			dst = (caddr_t) lp + dstoffset;
+			memcpy(dst, src, nbytes);
+			dstoffset += nbytes;
+
+			/* is page not full ? */
+			if (dstoffset < LOGPSIZE - LOGPTLRSIZE)
+				break;
+
+			/* page become full: move on to next page */
+			lmNextPage(log);
+
+			bp = (struct lbuf *) log->bp;
+			lp = (struct logpage *) bp->l_ldata;
+			dstoffset = LOGPHDRSIZE;
+
+			srclen -= nbytes;
+			src += nbytes;
+		}
+
+		/*
+		 * move log vector descriptor
+		 */
+		len += 4;
+		lvd = (struct lvd *) ((caddr_t) lp + dstoffset);
+		lvd->offset = cpu_to_le16(lv->offset);
+		lvd->length = cpu_to_le16(lv->length);
+		dstoffset += 4;
+		jFYI(1,
+		     ("lmWriteRecord: lv offset:%d length:%d\n",
+		      lv->offset, lv->length));
+	}
+
+	if ((i = linelock->next)) {
+		linelock = (struct linelock *) lid_to_tlock(i);
+		goto moveData;
+	}
+
+	/*
+	 *      move log record descriptor
+	 */
+      moveLrd:
+	lrd->length = cpu_to_le16(len);
+
+	src = (caddr_t) lrd;
+	srclen = LOGRDSIZE;
+
+	while (srclen > 0) {
+		freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset;
+		nbytes = min(freespace, srclen);
+		dst = (caddr_t) lp + dstoffset;
+		memcpy(dst, src, nbytes);
+
+		dstoffset += nbytes;
+		srclen -= nbytes;
+
+		/* are there more to move than freespace of page ? */
+		if (srclen)
+			goto pageFull;
+
+		/*
+		 * end of log record descriptor
+		 */
+
+		/* update last log record eor */
+		log->eor = dstoffset;
+		bp->l_eor = dstoffset;
+		lsn = (log->page << L2LOGPSIZE) + dstoffset;
+
+		if (lrd->type & cpu_to_le16(LOG_COMMIT)) {
+			tblk->clsn = lsn;
+			jFYI(1,
+			     ("wr: tclsn:0x%x, beor:0x%x\n", tblk->clsn,
+			      bp->l_eor));
+
+			INCREMENT(lmStat.commit);	/* # of commit */
+
+			/*
+			 * enqueue tblock for group commit:
+			 *
+			 * enqueue tblock of non-trivial/synchronous COMMIT
+			 * at tail of group commit queue
+			 * (trivial/asynchronous COMMITs are ignored by
+			 * group commit.)
+			 */
+			LOGGC_LOCK(log);
+
+			/* init tblock gc state */
+			tblk->flag = tblkGC_QUEUE;
+			tblk->bp = log->bp;
+			tblk->pn = log->page;
+			tblk->eor = log->eor;
+			init_waitqueue_head(&tblk->gcwait);
+
+			/* enqueue transaction to commit queue */
+			tblk->cqnext = NULL;
+			if (log->cqueue.head) {
+				log->cqueue.tail->cqnext = tblk;
+				log->cqueue.tail = tblk;
+			} else
+				log->cqueue.head = log->cqueue.tail = tblk;
+
+			LOGGC_UNLOCK(log);
+		}
+
+		jFYI(1,
+		     ("lmWriteRecord: lrd:0x%04x bp:0x%p pn:%d eor:0x%x\n",
+		      le16_to_cpu(lrd->type), log->bp, log->page,
+		      dstoffset));
+
+		/* page not full ? */
+		if (dstoffset < LOGPSIZE - LOGPTLRSIZE)
+			return lsn;
+
+	      pageFull:
+		/* page become full: move on to next page */
+		lmNextPage(log);
+
+		bp = (struct lbuf *) log->bp;
+		lp = (struct logpage *) bp->l_ldata;
+		dstoffset = LOGPHDRSIZE;
+		src += nbytes;
+	}
+
+	return lsn;
+}
+
+
+/*
+ * NAME:	lmNextPage()
+ *
+ * FUNCTION:	write current page and allocate next page.
+ *
+ * PARAMETER:	log
+ *
+ * RETURN:	0
+ *			
+ * serialization: LOG_LOCK() held on entry/exit
+ */
+static int lmNextPage(struct jfs_log * log)
+{
+	struct logpage *lp;
+	int lspn;		/* log sequence page number */
+	int pn;			/* current page number */
+	struct lbuf *bp;
+	struct lbuf *nextbp;
+	struct tblock *tblk;
+
+	jFYI(1, ("lmNextPage\n"));
+
+	/* get current log page number and log sequence page number */
+	pn = log->page;
+	bp = log->bp;
+	lp = (struct logpage *) bp->l_ldata;
+	lspn = le32_to_cpu(lp->h.page);
+
+	LOGGC_LOCK(log);
+
+	/*
+	 *      write or queue the full page at the tail of write queue
+	 */
+	/* get the tail tblk on commit queue */
+	tblk = log->cqueue.tail;
+
+	/* every tblk who has COMMIT record on the current page,
+	 * and has not been committed, must be on commit queue
+	 * since tblk is queued at commit queueu at the time
+	 * of writing its COMMIT record on the page before
+	 * page becomes full (even though the tblk thread
+	 * who wrote COMMIT record may have been suspended
+	 * currently);
+	 */
+
+	/* is page bound with outstanding tail tblk ? */
+	if (tblk && tblk->pn == pn) {
+		/* mark tblk for end-of-page */
+		tblk->flag |= tblkGC_EOP;
+
+		/* if page is not already on write queue,
+		 * just enqueue (no lbmWRITE to prevent redrive)
+		 * buffer to wqueue to ensure correct serial order
+		 * of the pages since log pages will be added
+		 * continuously (tblk bound with the page hasn't
+		 * got around to init write of the page, either
+		 * preempted or the page got filled by its COMMIT
+		 * record);
+		 * pages with COMMIT are paged out explicitly by
+		 * tblk in lmGroupCommit();
+		 */
+		if (bp->l_wqnext == NULL) {
+			/* bp->l_ceor = bp->l_eor; */
+			/* lp->h.eor = lp->t.eor = bp->l_ceor; */
+			lbmWrite(log, bp, 0, 0);
+		}
+	}
+	/* page is not bound with outstanding tblk:
+	 * init write or mark it to be redriven (lbmWRITE)
+	 */
+	else {
+		/* finalize the page */
+		bp->l_ceor = bp->l_eor;
+		lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
+		lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE, 0);
+	}
+	LOGGC_UNLOCK(log);
+
+	/*
+	 *      allocate/initialize next page
+	 */
+	/* if log wraps, the first data page of log is 2
+	 * (0 never used, 1 is superblock).
+	 */
+	log->page = (pn == log->size - 1) ? 2 : pn + 1;
+	log->eor = LOGPHDRSIZE;	/* ? valid page empty/full at logRedo() */
+
+	/* allocate/initialize next log page buffer */
+	nextbp = lbmAllocate(log, log->page);
+	nextbp->l_eor = log->eor;
+	log->bp = nextbp;
+
+	/* initialize next log page */
+	lp = (struct logpage *) nextbp->l_ldata;
+	lp->h.page = lp->t.page = cpu_to_le32(lspn + 1);
+	lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE);
+
+	jFYI(1, ("lmNextPage done\n"));
+	return 0;
+}
+
+
+/*
+ * NAME:	lmGroupCommit()
+ *
+ * FUNCTION:	group commit
+ *	initiate pageout of the pages with COMMIT in the order of
+ *	page number - redrive pageout of the page at the head of
+ *	pageout queue until full page has been written.
+ *
+ * RETURN:	
+ *
+ * NOTE:
+ *	LOGGC_LOCK serializes log group commit queue, and
+ *	transaction blocks on the commit queue.
+ *	N.B. LOG_LOCK is NOT held during lmGroupCommit().
+ */
+int lmGroupCommit(struct jfs_log * log, struct tblock * tblk)
+{
+	int rc = 0;
+
+	LOGGC_LOCK(log);
+
+	/* group committed already ? */
+	if (tblk->flag & tblkGC_COMMITTED) {
+		if (tblk->flag & tblkGC_ERROR)
+			rc = EIO;
+
+		LOGGC_UNLOCK(log);
+		return rc;
+	}
+	jFYI(1,
+	     ("lmGroup Commit: tblk = 0x%p, gcrtc = %d\n", tblk,
+	      log->gcrtc));
+
+	/*
+	 * group commit pageout in progress
+	 */
+	if ((!(log->cflag & logGC_PAGEOUT)) && log->cqueue.head) {
+		/*
+		 * only transaction in the commit queue:
+		 *
+		 * start one-transaction group commit as
+		 * its group leader.
+		 */
+		log->cflag |= logGC_PAGEOUT;
+
+		lmGCwrite(log, 0);
+	}
+	/* lmGCwrite gives up LOGGC_LOCK, check again */
+
+	if (tblk->flag & tblkGC_COMMITTED) {
+		if (tblk->flag & tblkGC_ERROR)
+			rc = EIO;
+
+		LOGGC_UNLOCK(log);
+		return rc;
+	}
+
+	/* upcount transaction waiting for completion
+	 */
+	log->gcrtc++;
+
+	if (tblk->xflag & COMMIT_LAZY) {
+		tblk->flag |= tblkGC_LAZY;
+		LOGGC_UNLOCK(log);
+		return 0;
+	}
+	tblk->flag |= tblkGC_READY;
+
+	__SLEEP_COND(tblk->gcwait, (tblk->flag & tblkGC_COMMITTED),
+		     LOGGC_LOCK(log), LOGGC_UNLOCK(log));
+
+	/* removed from commit queue */
+	if (tblk->flag & tblkGC_ERROR)
+		rc = EIO;
+
+	LOGGC_UNLOCK(log);
+	return rc;
+}
+
+/*
+ * NAME:	lmGCwrite()
+ *
+ * FUNCTION:	group commit write
+ *	initiate write of log page, building a group of all transactions
+ *	with commit records on that page.
+ *
+ * RETURN:	None
+ *
+ * NOTE:
+ *	LOGGC_LOCK must be held by caller.
+ *	N.B. LOG_LOCK is NOT held during lmGroupCommit().
+ */
+void lmGCwrite(struct jfs_log * log, int cant_write)
+{
+	struct lbuf *bp;
+	struct logpage *lp;
+	int gcpn;		/* group commit page number */
+	struct tblock *tblk;
+	struct tblock *xtblk;
+
+	/*
+	 * build the commit group of a log page
+	 *
+	 * scan commit queue and make a commit group of all
+	 * transactions with COMMIT records on the same log page.
+	 */
+	/* get the head tblk on the commit queue */
+	tblk = xtblk = log->cqueue.head;
+	gcpn = tblk->pn;
+
+	while (tblk && tblk->pn == gcpn) {
+		xtblk = tblk;
+
+		/* state transition: (QUEUE, READY) -> COMMIT */
+		tblk->flag |= tblkGC_COMMIT;
+		tblk = tblk->cqnext;
+	}
+	tblk = xtblk;		/* last tblk of the page */
+
+	/*
+	 * pageout to commit transactions on the log page.
+	 */
+	bp = (struct lbuf *) tblk->bp;
+	lp = (struct logpage *) bp->l_ldata;
+	/* is page already full ? */
+	if (tblk->flag & tblkGC_EOP) {
+		/* mark page to free at end of group commit of the page */
+		tblk->flag &= ~tblkGC_EOP;
+		tblk->flag |= tblkGC_FREE;
+		bp->l_ceor = bp->l_eor;
+		lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
+		jEVENT(0,
+		       ("gc: tclsn:0x%x, bceor:0x%x\n", tblk->clsn,
+			bp->l_ceor));
+		lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmGC,
+			 cant_write);
+	}
+	/* page is not yet full */
+	else {
+		bp->l_ceor = tblk->eor;	/* ? bp->l_ceor = bp->l_eor; */
+		lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
+		jEVENT(0,
+		       ("gc: tclsn:0x%x, bceor:0x%x\n", tblk->clsn,
+			bp->l_ceor));
+		lbmWrite(log, bp, lbmWRITE | lbmGC, cant_write);
+	}
+}
+
+/*
+ * NAME:	lmPostGC()
+ *
+ * FUNCTION:	group commit post-processing
+ *	Processes transactions after their commit records have been written
+ *	to disk, redriving log I/O if necessary.
+ *
+ * RETURN:	None
+ *
+ * NOTE:
+ *	This routine is called a interrupt time by lbmIODone
+ */
+void lmPostGC(struct lbuf * bp)
+{
+	unsigned long flags;
+	struct jfs_log *log = bp->l_log;
+	struct logpage *lp;
+	struct tblock *tblk;
+
+	//LOGGC_LOCK(log);
+	spin_lock_irqsave(&log->gclock, flags);
+	/*
+	 * current pageout of group commit completed.
+	 *
+	 * remove/wakeup transactions from commit queue who were
+	 * group committed with the current log page
+	 */
+	while ((tblk = log->cqueue.head) && (tblk->flag & tblkGC_COMMIT)) {
+		/* if transaction was marked GC_COMMIT then
+		 * it has been shipped in the current pageout
+		 * and made it to disk - it is committed.
+		 */
+
+		if (bp->l_flag & lbmERROR)
+			tblk->flag |= tblkGC_ERROR;
+
+		/* remove it from the commit queue */
+		log->cqueue.head = tblk->cqnext;
+		if (log->cqueue.head == NULL)
+			log->cqueue.tail = NULL;
+		tblk->flag &= ~tblkGC_QUEUE;
+		tblk->cqnext = 0;
+
+		jEVENT(0,
+		       ("lmPostGC: tblk = 0x%p, flag = 0x%x\n", tblk,
+			tblk->flag));
+
+		if (!(tblk->xflag & COMMIT_FORCE))
+			/*
+			 * Hand tblk over to lazy commit thread
+			 */
+			txLazyUnlock(tblk);
+		else {
+			/* state transition: COMMIT -> COMMITTED */
+			tblk->flag |= tblkGC_COMMITTED;
+
+			if (tblk->flag & tblkGC_READY) {
+				log->gcrtc--;
+				LOGGC_WAKEUP(tblk);
+			}
+		}
+
+		/* was page full before pageout ?
+		 * (and this is the last tblk bound with the page)
+		 */
+		if (tblk->flag & tblkGC_FREE)
+			lbmFree(bp);
+		/* did page become full after pageout ?
+		 * (and this is the last tblk bound with the page)
+		 */
+		else if (tblk->flag & tblkGC_EOP) {
+			/* finalize the page */
+			lp = (struct logpage *) bp->l_ldata;
+			bp->l_ceor = bp->l_eor;
+			lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
+			jEVENT(0, ("lmPostGC: calling lbmWrite\n"));
+			lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE,
+				 1);
+		}
+
+	}
+
+	/* are there any transactions who have entered lnGroupCommit()
+	 * (whose COMMITs are after that of the last log page written.
+	 * They are waiting for new group commit (above at (SLEEP 1)):
+	 * select the latest ready transaction as new group leader and
+	 * wake her up to lead her group.
+	 */
+	if ((log->gcrtc > 0) && log->cqueue.head)
+		/*
+		 * Call lmGCwrite with new group leader
+		 */
+		lmGCwrite(log, 1);
+
+	/* no transaction are ready yet (transactions are only just
+	 * queued (GC_QUEUE) and not entered for group commit yet).
+	 * let the first transaction entering group commit
+	 * will elect hetself as new group leader.
+	 */
+	else
+		log->cflag &= ~logGC_PAGEOUT;
+
+	//LOGGC_UNLOCK(log);
+	spin_unlock_irqrestore(&log->gclock, flags);
+	return;
+}
+
+/*
+ * NAME:	lmLogSync()
+ *
+ * FUNCTION:	write log SYNCPT record for specified log
+ *	if new sync address is available
+ *	(normally the case if sync() is executed by back-ground
+ *	process).
+ *	if not, explicitly run jfs_blogsync() to initiate
+ *	getting of new sync address.
+ *	calculate new value of i_nextsync which determines when
+ *	this code is called again.
+ *
+ *	this is called only from lmLog().
+ *
+ * PARAMETER:	ip	- pointer to logs inode.
+ *
+ * RETURN:	0
+ *			
+ * serialization: LOG_LOCK() held on entry/exit
+ */
+int lmLogSync(struct jfs_log * log, int nosyncwait)
+{
+	int logsize;
+	int written;		/* written since last syncpt */
+	int free;		/* free space left available */
+	int delta;		/* additional delta to write normally */
+	int more;		/* additional write granted */
+	struct lrd lrd;
+	int lsn;
+	struct logsyncblk *lp;
+
+	/*
+	 *      forward syncpt
+	 */
+	/* if last sync is same as last syncpt,
+	 * invoke sync point forward processing to update sync.
+	 */
+
+	if (log->sync == log->syncpt) {
+		LOGSYNC_LOCK(log);
+		/* ToDo: push dirty metapages out to disk */
+//              bmLogSync(log);
+
+		if (list_empty(&log->synclist))
+			log->sync = log->lsn;
+		else {
+			lp = list_entry(log->synclist.next,
+					struct logsyncblk, synclist);
+			log->sync = lp->lsn;
+		}
+		LOGSYNC_UNLOCK(log);
+
+	}
+
+	/* if sync is different from last syncpt,
+	 * write a SYNCPT record with syncpt = sync.
+	 * reset syncpt = sync
+	 */
+	if (log->sync != log->syncpt) {
+		struct super_block *sb = log->sb;
+		struct jfs_sb_info *sbi = JFS_SBI(sb);
+
+		/*
+		 * We need to make sure all of the "written" metapages
+		 * actually make it to disk
+		 */
+		fsync_inode_data_buffers(sbi->ipbmap);
+		fsync_inode_data_buffers(sbi->ipimap);
+		fsync_inode_data_buffers(sb->s_bdev->bd_inode);
+
+		lrd.logtid = 0;
+		lrd.backchain = 0;
+		lrd.type = cpu_to_le16(LOG_SYNCPT);
+		lrd.length = 0;
+		lrd.log.syncpt.sync = cpu_to_le32(log->sync);
+		lsn = lmWriteRecord(log, NULL, &lrd, NULL);
+
+		log->syncpt = log->sync;
+	} else
+		lsn = log->lsn;
+
+	/*
+	 *      setup next syncpt trigger (SWAG)
+	 */
+	logsize = log->logsize;
+
+	logdiff(written, lsn, log);
+	free = logsize - written;
+	delta = LOGSYNC_DELTA(logsize);
+	more = min(free / 2, delta);
+	if (more < 2 * LOGPSIZE) {
+		jEVENT(1,
+		       ("\n ... Log Wrap ... Log Wrap ... Log Wrap ...\n\n"));
+		/*
+		 *      log wrapping
+		 *
+		 * option 1 - panic ? No.!
+		 * option 2 - shutdown file systems
+		 *            associated with log ?
+		 * option 3 - extend log ?
+		 */
+		/*
+		 * option 4 - second chance
+		 *
+		 * mark log wrapped, and continue.
+		 * when all active transactions are completed,
+		 * mark log vaild for recovery.
+		 * if crashed during invalid state, log state
+		 * implies invald log, forcing fsck().
+		 */
+		/* mark log state log wrap in log superblock */
+		/* log->state = LOGWRAP; */
+
+		/* reset sync point computation */
+		log->syncpt = log->sync = lsn;
+		log->nextsync = delta;
+	} else
+		/* next syncpt trigger = written + more */
+		log->nextsync = written + more;
+
+	/* return if lmLogSync() from outside of transaction, e.g., sync() */
+	if (nosyncwait)
+		return lsn;
+
+	/* if number of bytes written from last sync point is more
+	 * than 1/4 of the log size, stop new transactions from
+	 * starting until all current transactions are completed
+	 * by setting syncbarrier flag.
+	 */
+	if (written > LOGSYNC_BARRIER(logsize) && logsize > 32 * LOGPSIZE) {
+		set_bit(log_SYNCBARRIER, &log->flag);
+		jFYI(1, ("log barrier on: lsn=0x%x syncpt=0x%x\n", lsn,
+			 log->syncpt));
+	}
+
+	return lsn;
+}
+
+
+/*
+ * NAME:	lmLogOpen()
+ *
+ * FUNCTION:    open the log on first open;
+ *	insert filesystem in the active list of the log.
+ *
+ * PARAMETER:	ipmnt	- file system mount inode
+ *		iplog 	- log inode (out)
+ *
+ * RETURN:
+ *
+ * serialization:
+ */
+int lmLogOpen(struct super_block *sb, struct jfs_log ** logptr)
+{
+	int rc;
+	struct block_device *bdev;
+	struct jfs_log *log;
+
+	if (!(log = kmalloc(sizeof(struct jfs_log), GFP_KERNEL)))
+		return ENOMEM;
+	memset(log, 0, sizeof(struct jfs_log));
+	init_waitqueue_head(&log->syncwait);
+
+	log->sb = sb;		/* This should be a list */
+
+	if (!(JFS_SBI(sb)->mntflag & JFS_INLINELOG))
+		goto externalLog;
+
+	/*
+	 *      in-line log in host file system
+	 *
+	 * file system to log have 1-to-1 relationship;
+	 */
+
+	set_bit(log_INLINELOG, &log->flag);
+	log->bdev = sb->s_bdev;
+	log->base = addressPXD(&JFS_SBI(sb)->logpxd);
+	log->size = lengthPXD(&JFS_SBI(sb)->logpxd) >>
+	    (L2LOGPSIZE - sb->s_blocksize_bits);
+	log->l2bsize = sb->s_blocksize_bits;
+	ASSERT(L2LOGPSIZE >= sb->s_blocksize_bits);
+
+	/*
+	 * initialize log.
+	 */
+	if ((rc = lmLogInit(log)))
+		goto free;
+	goto out;
+
+	/*
+	 *      external log as separate logical volume
+	 *
+	 * file systems to log may have n-to-1 relationship;
+	 */
+      externalLog:
+
+	/*
+	 * TODO: Check for already opened log devices
+	 */
+
+	if (!(bdev = bdget(kdev_t_to_nr(JFS_SBI(sb)->logdev)))) {
+		rc = ENODEV;
+		goto free;
+	}
+
+	if ((rc = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_FS))) {
+		rc = -rc;
+		goto free;
+	}
+
+	log->bdev = bdev;
+	memcpy(log->uuid, JFS_SBI(sb)->loguuid, sizeof(log->uuid));
+	
+	/*
+	 * initialize log:
+	 */
+	if ((rc = lmLogInit(log)))
+		goto close;
+
+	/*
+	 * add file system to log active file system list
+	 */
+	if ((rc = lmLogFileSystem(log, JFS_SBI(sb)->uuid, 1)))
+		goto shutdown;
+
+      out:
+	jFYI(1, ("lmLogOpen: exit(0)\n"));
+	*logptr = log;
+	return 0;
+
+	/*
+	 *      unwind on error
+	 */
+      shutdown:		/* unwind lbmLogInit() */
+	lbmLogShutdown(log);
+
+      close:		/* close external log device */
+	blkdev_put(bdev, BDEV_FS);
+
+      free:		/* free log descriptor */
+	kfree(log);
+
+	jFYI(1, ("lmLogOpen: exit(%d)\n", rc));
+	return rc;
+}
+
+
+/*
+ * NAME:	lmLogInit()
+ *
+ * FUNCTION:	log initialization at first log open.
+ *
+ *	logredo() (or logformat()) should have been run previously.
+ *	initialize the log inode from log superblock.
+ *	set the log state in the superblock to LOGMOUNT and
+ *	write SYNCPT log record.
+ *		
+ * PARAMETER:	log	- log structure
+ *
+ * RETURN:	0	- if ok
+ *		EINVAL	- bad log magic number or superblock dirty
+ *		error returned from logwait()
+ *			
+ * serialization: single first open thread
+ */
+int lmLogInit(struct jfs_log * log)
+{
+	int rc = 0;
+	struct lrd lrd;
+	struct logsuper *logsuper;
+	struct lbuf *bpsuper;
+	struct lbuf *bp;
+	struct logpage *lp;
+	int lsn;
+
+	jFYI(1, ("lmLogInit: log:0x%p\n", log));
+
+	/*
+	 * log inode is overlaid on generic inode where
+	 * dinode have been zeroed out by iRead();
+	 */
+
+	/*
+	 * initialize log i/o
+	 */
+	if ((rc = lbmLogInit(log)))
+		return rc;
+
+	/*
+	 * validate log superblock
+	 */
+
+
+	if (!test_bit(log_INLINELOG, &log->flag))
+		log->l2bsize = 12;	/* XXX kludge alert XXX */
+	if ((rc = lbmRead(log, 1, &bpsuper)))
+		goto errout10;
+
+	logsuper = (struct logsuper *) bpsuper->l_ldata;
+
+	if (logsuper->magic != cpu_to_le32(LOGMAGIC)) {
+		jERROR(1, ("*** Log Format Error ! ***\n"));
+		rc = EINVAL;
+		goto errout20;
+	}
+
+	/* logredo() should have been run successfully. */
+	if (logsuper->state != cpu_to_le32(LOGREDONE)) {
+		jERROR(1, ("*** Log Is Dirty ! ***\n"));
+		rc = EINVAL;
+		goto errout20;
+	}
+
+	/* initialize log inode from log superblock */
+	if (test_bit(log_INLINELOG,&log->flag)) {
+		if (log->size != le32_to_cpu(logsuper->size)) {
+			rc = EINVAL;
+			goto errout20;
+		}
+		jFYI(0,
+		     ("lmLogInit: inline log:0x%p base:0x%Lx size:0x%x\n",
+		      log, (unsigned long long) log->base, log->size));
+	} else {
+		if (memcmp(logsuper->uuid, log->uuid, 16)) {
+			jERROR(1,("wrong uuid on JFS log device\n"));
+			goto errout20;
+		}
+		log->size = le32_to_cpu(logsuper->size);
+		log->l2bsize = le32_to_cpu(logsuper->l2bsize);
+		jFYI(0,
+		     ("lmLogInit: external log:0x%p base:0x%Lx size:0x%x\n",
+		      log, (unsigned long long) log->base, log->size));
+	}
+
+	log->page = le32_to_cpu(logsuper->end) / LOGPSIZE;
+	log->eor = le32_to_cpu(logsuper->end) - (LOGPSIZE * log->page);
+
+	/*
+	 * initialize for log append write mode
+	 */
+	/* establish current/end-of-log page/buffer */
+	if ((rc = lbmRead(log, log->page, &bp)))
+		goto errout20;
+
+	lp = (struct logpage *) bp->l_ldata;
+
+	jFYI(1, ("lmLogInit: lsn:0x%x page:%d eor:%d:%d\n",
+		 le32_to_cpu(logsuper->end), log->page, log->eor,
+		 le16_to_cpu(lp->h.eor)));
+
+//      ASSERT(log->eor == lp->h.eor);
+
+	log->bp = bp;
+	bp->l_pn = log->page;
+	bp->l_eor = log->eor;
+
+	/* initialize the group commit serialization lock */
+	LOGGC_LOCK_INIT(log);
+
+	/* if current page is full, move on to next page */
+	if (log->eor >= LOGPSIZE - LOGPTLRSIZE)
+		lmNextPage(log);
+
+	/* allocate/initialize the log write serialization lock */
+	LOG_LOCK_INIT(log);
+
+	/*
+	 * initialize log syncpoint
+	 */
+	/*
+	 * write the first SYNCPT record with syncpoint = 0
+	 * (i.e., log redo up to HERE !);
+	 * remove current page from lbm write queue at end of pageout
+	 * (to write log superblock update), but do not release to freelist;
+	 */
+	lrd.logtid = 0;
+	lrd.backchain = 0;
+	lrd.type = cpu_to_le16(LOG_SYNCPT);
+	lrd.length = 0;
+	lrd.log.syncpt.sync = 0;
+	lsn = lmWriteRecord(log, NULL, &lrd, NULL);
+	bp = log->bp;
+	bp->l_ceor = bp->l_eor;
+	lp = (struct logpage *) bp->l_ldata;
+	lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
+	lbmWrite(log, bp, lbmWRITE | lbmSYNC, 0);
+	if ((rc = lbmIOWait(bp, 0)))
+		goto errout30;
+
+	/* initialize logsync parameters */
+	log->logsize = (log->size - 2) << L2LOGPSIZE;
+	log->lsn = lsn;
+	log->syncpt = lsn;
+	log->sync = log->syncpt;
+	log->nextsync = LOGSYNC_DELTA(log->logsize);
+
+	jFYI(1, ("lmLogInit: lsn:0x%x syncpt:0x%x sync:0x%x\n",
+		 log->lsn, log->syncpt, log->sync));
+
+	LOGSYNC_LOCK_INIT(log);
+
+	INIT_LIST_HEAD(&log->synclist);
+
+	log->cqueue.head = log->cqueue.tail = 0;
+
+	log->count = 0;
+
+	/*
+	 * initialize for lazy/group commit
+	 */
+	log->clsn = lsn;
+
+	/*
+	 * update/write superblock
+	 */
+	logsuper->state = cpu_to_le32(LOGMOUNT);
+	log->serial = le32_to_cpu(logsuper->serial) + 1;
+	logsuper->serial = cpu_to_le32(log->serial);
+	lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
+	if ((rc = lbmIOWait(bpsuper, lbmFREE)))
+		goto errout30;
+
+	jFYI(1, ("lmLogInit: exit(%d)\n", rc));
+	return 0;
+
+	/*
+	 *      unwind on error
+	 */
+      errout30:		/* release log page */
+	lbmFree(bp);
+
+      errout20:		/* release log superblock */
+	lbmFree(bpsuper);
+
+      errout10:		/* unwind lbmLogInit() */
+	lbmLogShutdown(log);
+
+	jFYI(1, ("lmLogInit: exit(%d)\n", rc));
+	return rc;
+}
+
+
+/*
+ * NAME:	lmLogClose()
+ *
+ * FUNCTION:	remove file system <ipmnt> from active list of log <iplog>
+ *		and close it on last close.
+ *
+ * PARAMETER:	sb	- superblock
+ *		log	- log inode
+ *
+ * RETURN:	errors from subroutines
+ *
+ * serialization:
+ */
+int lmLogClose(struct super_block *sb, struct jfs_log * log)
+{
+	int rc;
+
+	jFYI(1, ("lmLogClose: log:0x%p\n", log));
+
+	if (!test_bit(log_INLINELOG, &log->flag))
+		goto externalLog;
+	
+	/*
+	 *      in-line log in host file system
+	 */
+	rc = lmLogShutdown(log);
+	goto out;
+
+	/*
+	 *      external log as separate logical volume
+	 */
+      externalLog:
+	lmLogFileSystem(log, JFS_SBI(sb)->uuid, 0);
+	rc = lmLogShutdown(log);
+	blkdev_put(log->bdev, BDEV_FS);
+
+      out:
+	jFYI(0, ("lmLogClose: exit(%d)\n", rc));
+	return rc;
+}
+
+
+/*
+ * NAME:	lmLogWait()
+ *
+ * FUNCTION:	wait for all outstanding log records to be written to disk
+ */
+void lmLogWait(struct jfs_log *log)
+{
+	int i;
+
+	jFYI(1, ("lmLogWait: log:0x%p\n", log));
+
+	if (log->cqueue.head || !list_empty(&log->synclist)) {
+		/*
+		 * If there was very recent activity, we may need to wait
+		 * for the lazycommit thread to catch up
+		 */
+
+		for (i = 0; i < 800; i++) {	/* Too much? */
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(HZ / 4);
+			if ((log->cqueue.head == NULL) &&
+			    list_empty(&log->synclist))
+				break;
+		}
+	}
+	assert(log->cqueue.head == NULL);
+	assert(list_empty(&log->synclist));
+}
+
+/*
+ * NAME:	lmLogShutdown()
+ *
+ * FUNCTION:	log shutdown at last LogClose().
+ *
+ *		write log syncpt record.
+ *		update super block to set redone flag to 0.
+ *
+ * PARAMETER:	log	- log inode
+ *
+ * RETURN:	0	- success
+ *			
+ * serialization: single last close thread
+ */
+int lmLogShutdown(struct jfs_log * log)
+{
+	int rc;
+	struct lrd lrd;
+	int lsn;
+	struct logsuper *logsuper;
+	struct lbuf *bpsuper;
+	struct lbuf *bp;
+	struct logpage *lp;
+
+	jFYI(1, ("lmLogShutdown: log:0x%p\n", log));
+
+	lmLogWait(log);
+
+	/*
+	 * We need to make sure all of the "written" metapages
+	 * actually make it to disk
+	 */
+	fsync_no_super(log->sb->s_dev);
+
+	/*
+	 * write the last SYNCPT record with syncpoint = 0
+	 * (i.e., log redo up to HERE !)
+	 */
+	lrd.logtid = 0;
+	lrd.backchain = 0;
+	lrd.type = cpu_to_le16(LOG_SYNCPT);
+	lrd.length = 0;
+	lrd.log.syncpt.sync = 0;
+	lsn = lmWriteRecord(log, NULL, &lrd, NULL);
+	bp = log->bp;
+	lp = (struct logpage *) bp->l_ldata;
+	lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
+	lbmWrite(log, log->bp, lbmWRITE | lbmRELEASE | lbmSYNC, 0);
+	lbmIOWait(log->bp, lbmFREE);
+
+	/*
+	 * synchronous update log superblock
+	 * mark log state as shutdown cleanly
+	 * (i.e., Log does not need to be replayed).
+	 */
+	if ((rc = lbmRead(log, 1, &bpsuper)))
+		goto out;
+
+	logsuper = (struct logsuper *) bpsuper->l_ldata;
+	logsuper->state = cpu_to_le32(LOGREDONE);
+	logsuper->end = cpu_to_le32(lsn);
+	lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
+	rc = lbmIOWait(bpsuper, lbmFREE);
+
+	jFYI(1, ("lmLogShutdown: lsn:0x%x page:%d eor:%d\n",
+		 lsn, log->page, log->eor));
+
+      out:    
+	/*
+	 * shutdown per log i/o
+	 */
+	lbmLogShutdown(log);
+
+	if (rc) {
+		jFYI(1, ("lmLogShutdown: exit(%d)\n", rc));
+	}
+	return rc;
+}
+
+
+/*
+ * NAME:	lmLogFileSystem()
+ *
+ * FUNCTION:	insert (<activate> = true)/remove (<activate> = false)
+ *	file system into/from log active file system list.
+ *
+ * PARAMETE:	log	- pointer to logs inode.
+ *		fsdev	- kdev_t of filesystem.
+ *		serial  - pointer to returned log serial number
+ *		activate - insert/remove device from active list.
+ *
+ * RETURN:	0	- success
+ *		errors returned by vms_iowait().
+ */
+static int lmLogFileSystem(struct jfs_log * log, char *uuid, int activate)
+{
+	int rc = 0;
+	int i;
+	struct logsuper *logsuper;
+	struct lbuf *bpsuper;
+
+	/*
+	 * insert/remove file system device to log active file system list.
+	 */
+	if ((rc = lbmRead(log, 1, &bpsuper)))
+		return rc;
+
+	logsuper = (struct logsuper *) bpsuper->l_ldata;
+	if (activate) {
+		for (i = 0; i < MAX_ACTIVE; i++)
+			if (!memcmp(logsuper->active[i].uuid, NULL_UUID, 16)) {
+				memcpy(logsuper->active[i].uuid, uuid, 16);
+				break;
+			}
+		if (i == MAX_ACTIVE) {
+			jERROR(1,("Too many file systems sharing journal!\n"));
+			lbmFree(bpsuper);
+			return EMFILE;	/* Is there a better rc? */
+		}
+	} else {
+		for (i = 0; i < MAX_ACTIVE; i++)
+			if (!memcmp(logsuper->active[i].uuid, uuid, 16)) {
+				memcpy(logsuper->active[i].uuid, NULL_UUID, 16);
+				break;
+			}
+		if (i == MAX_ACTIVE) {
+			jERROR(1,("Somebody stomped on the journal!\n"));
+			lbmFree(bpsuper);
+			return EIO;
+		}
+		
+	}
+
+	/*
+	 * synchronous write log superblock:
+	 *
+	 * write sidestream bypassing write queue:
+	 * at file system mount, log super block is updated for
+	 * activation of the file system before any log record
+	 * (MOUNT record) of the file system, and at file system
+	 * unmount, all meta data for the file system has been
+	 * flushed before log super block is updated for deactivation
+	 * of the file system.
+	 */
+	lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
+	rc = lbmIOWait(bpsuper, lbmFREE);
+
+	return rc;
+}
+
+/*
+ *		log buffer manager (lbm)
+ *		------------------------
+ *
+ * special purpose buffer manager supporting log i/o requirements.
+ *
+ * per log write queue:
+ * log pageout occurs in serial order by fifo write queue and
+ * restricting to a single i/o in pregress at any one time.
+ * a circular singly-linked list
+ * (log->wrqueue points to the tail, and buffers are linked via
+ * bp->wrqueue field), and
+ * maintains log page in pageout ot waiting for pageout in serial pageout.
+ */
+
+/*
+ *	lbmLogInit()
+ *
+ * initialize per log I/O setup at lmLogInit()
+ */
+static int lbmLogInit(struct jfs_log * log)
+{				/* log inode */
+	int i;
+	struct lbuf *lbuf;
+
+	jFYI(1, ("lbmLogInit: log:0x%p\n", log));
+
+	/* initialize current buffer cursor */
+	log->bp = NULL;
+
+	/* initialize log device write queue */
+	log->wqueue = NULL;
+
+	/*
+	 * Each log has its own buffer pages allocated to it.  These are
+	 * not managed by the page cache.  This ensures that a transaction
+	 * writing to the log does not block trying to allocate a page from
+	 * the page cache (for the log).  This would be bad, since page
+	 * allocation waits on the kswapd thread that may be committing inodes
+	 * which would cause log activity.  Was that clear?  I'm trying to
+	 * avoid deadlock here.
+	 */
+	init_waitqueue_head(&log->free_wait);
+
+	log->lbuf_free = NULL;
+
+	for (i = 0; i < LOGPAGES; i++) {
+		lbuf = kmalloc(sizeof(struct lbuf), GFP_KERNEL);
+		if (lbuf == 0)
+			goto error;
+		lbuf->l_bh.b_data = lbuf->l_ldata =
+		    (char *) __get_free_page(GFP_KERNEL);
+		if (lbuf->l_ldata == 0) {
+			kfree(lbuf);
+			goto error;
+		}
+		lbuf->l_log = log;
+		init_waitqueue_head(&lbuf->l_ioevent);
+
+		lbuf->l_bh.b_size = LOGPSIZE;
+		lbuf->l_bh.b_dev = to_kdev_t(log->bdev->bd_dev);
+		lbuf->l_bh.b_end_io = lbmIODone;
+		lbuf->l_bh.b_private = lbuf;
+		lbuf->l_bh.b_page = virt_to_page(lbuf->l_ldata);
+		lbuf->l_bh.b_state = 0;
+		init_waitqueue_head(&lbuf->l_bh.b_wait);
+
+		lbuf->l_freelist = log->lbuf_free;
+		log->lbuf_free = lbuf;
+	}
+
+	return (0);
+
+      error:
+	lbmLogShutdown(log);
+	return (ENOMEM);
+}
+
+
+/*
+ *	lbmLogShutdown()
+ *
+ * finalize per log I/O setup at lmLogShutdown()
+ */
+static void lbmLogShutdown(struct jfs_log * log)
+{
+	struct lbuf *lbuf;
+
+	jFYI(1, ("lbmLogShutdown: log:0x%p\n", log));
+
+	lbuf = log->lbuf_free;
+	while (lbuf) {
+		struct lbuf *next = lbuf->l_freelist;
+		free_page((unsigned long) lbuf->l_ldata);
+		kfree(lbuf);
+		lbuf = next;
+	}
+
+	log->bp = NULL;
+}
+
+
+/*
+ *	lbmAllocate()
+ *
+ * allocate an empty log buffer
+ */
+static struct lbuf *lbmAllocate(struct jfs_log * log, int pn)
+{
+	struct lbuf *bp;
+	unsigned long flags;
+
+	/*
+	 * recycle from log buffer freelist if any
+	 */
+	LCACHE_LOCK(flags);
+	LCACHE_SLEEP_COND(log->free_wait, (bp = log->lbuf_free), flags);
+	log->lbuf_free = bp->l_freelist;
+	LCACHE_UNLOCK(flags);
+
+	bp->l_flag = 0;
+
+	bp->l_wqnext = NULL;
+	bp->l_freelist = NULL;
+
+	bp->l_pn = pn;
+	bp->l_blkno = log->base + (pn << (L2LOGPSIZE - log->l2bsize));
+	bp->l_bh.b_blocknr = bp->l_blkno;
+	bp->l_ceor = 0;
+
+	return bp;
+}
+
+
+/*
+ *	lbmFree()
+ *
+ * release a log buffer to freelist
+ */
+static void lbmFree(struct lbuf * bp)
+{
+	unsigned long flags;
+
+	LCACHE_LOCK(flags);
+
+	lbmfree(bp);
+
+	LCACHE_UNLOCK(flags);
+}
+
+static void lbmfree(struct lbuf * bp)
+{
+	struct jfs_log *log = bp->l_log;
+
+	assert(bp->l_wqnext == NULL);
+
+	/*
+	 * return the buffer to head of freelist
+	 */
+	bp->l_freelist = log->lbuf_free;
+	log->lbuf_free = bp;
+
+	wake_up(&log->free_wait);
+	return;
+}
+
+
+/*
+ * NAME:	lbmRedrive
+ *
+ * FUNCTION:	add a log buffer to the the log redrive list
+ *
+ * PARAMETER:
+ *     bp	- log buffer
+ *
+ * NOTES:
+ *	Takes log_redrive_lock.
+ */
+static inline void lbmRedrive(struct lbuf *bp)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&log_redrive_lock, flags);
+	bp->l_redrive_next = log_redrive_list;
+	log_redrive_list = bp;
+	spin_unlock_irqrestore(&log_redrive_lock, flags);
+
+	wake_up(&jfs_IO_thread_wait);
+}
+
+
+/*
+ *	lbmRead()
+ */
+static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp)
+{
+	struct lbuf *bp;
+
+	/*
+	 * allocate a log buffer
+	 */
+	*bpp = bp = lbmAllocate(log, pn);
+	jFYI(1, ("lbmRead: bp:0x%p pn:0x%x\n", bp, pn));
+
+	bp->l_flag |= lbmREAD;
+	bp->l_bh.b_reqnext = NULL;
+	clear_bit(BH_Uptodate, &bp->l_bh.b_state);
+	lock_buffer(&bp->l_bh);
+	set_bit(BH_Mapped, &bp->l_bh.b_state);
+	set_bit(BH_Req, &bp->l_bh.b_state);
+	bp->l_bh.b_rdev = bp->l_bh.b_dev;
+	bp->l_bh.b_rsector = bp->l_blkno << (log->l2bsize - 9);
+	generic_make_request(READ, &bp->l_bh);
+	run_task_queue(&tq_disk);
+
+	wait_event(bp->l_ioevent, (bp->l_flag != lbmREAD));
+
+	return 0;
+}
+
+
+/*
+ *	lbmWrite()
+ *
+ * buffer at head of pageout queue stays after completion of
+ * partial-page pageout and redriven by explicit initiation of
+ * pageout by caller until full-page pageout is completed and
+ * released.
+ *
+ * device driver i/o done redrives pageout of new buffer at
+ * head of pageout queue when current buffer at head of pageout
+ * queue is released at the completion of its full-page pageout.
+ *
+ * LOGGC_LOCK() serializes lbmWrite() by lmNextPage() and lmGroupCommit().
+ * LCACHE_LOCK() serializes xflag between lbmWrite() and lbmIODone()
+ */
+static void lbmWrite(struct jfs_log * log, struct lbuf * bp, int flag,
+		     int cant_block)
+{
+	struct lbuf *tail;
+	unsigned long flags;
+
+	jFYI(1, ("lbmWrite: bp:0x%p flag:0x%x pn:0x%x\n",
+		 bp, flag, bp->l_pn));
+
+	/* map the logical block address to physical block address */
+	bp->l_blkno =
+	    log->base + (bp->l_pn << (L2LOGPSIZE - log->l2bsize));
+
+	LCACHE_LOCK(flags);		/* disable+lock */
+
+	/*
+	 * initialize buffer for device driver
+	 */
+	bp->l_flag = flag;
+
+	/*
+	 *      insert bp at tail of write queue associated with log
+	 *
+	 * (request is either for bp already/currently at head of queue
+	 * or new bp to be inserted at tail)
+	 */
+	tail = log->wqueue;
+
+	/* is buffer not already on write queue ? */
+	if (bp->l_wqnext == NULL) {
+		/* insert at tail of wqueue */
+		if (tail == NULL) {
+			log->wqueue = bp;
+			bp->l_wqnext = bp;
+		} else {
+			log->wqueue = bp;
+			bp->l_wqnext = tail->l_wqnext;
+			tail->l_wqnext = bp;
+		}
+
+		tail = bp;
+	}
+
+	/* is buffer at head of wqueue and for write ? */
+	if ((bp != tail->l_wqnext) || !(flag & lbmWRITE)) {
+		LCACHE_UNLOCK(flags);	/* unlock+enable */
+		return;
+	}
+
+	LCACHE_UNLOCK(flags);	/* unlock+enable */
+
+	if (cant_block)
+		lbmRedrive(bp);
+	else if (flag & lbmSYNC)
+		lbmStartIO(bp);
+	else {
+		LOGGC_UNLOCK(log);
+		lbmStartIO(bp);
+		LOGGC_LOCK(log);
+	}
+}
+
+
+/*
+ *	lbmDirectWrite()
+ *
+ * initiate pageout bypassing write queue for sidestream
+ * (e.g., log superblock) write;
+ */
+static void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag)
+{
+	jEVENT(0, ("lbmDirectWrite: bp:0x%p flag:0x%x pn:0x%x\n",
+		   bp, flag, bp->l_pn));
+
+	/*
+	 * initialize buffer for device driver
+	 */
+	bp->l_flag = flag | lbmDIRECT;
+
+	/* map the logical block address to physical block address */
+	bp->l_blkno =
+	    log->base + (bp->l_pn << (L2LOGPSIZE - log->l2bsize));
+
+	/*
+	 *      initiate pageout of the page
+	 */
+	lbmStartIO(bp);
+}
+
+
+/*
+ * NAME:	lbmStartIO()
+ *
+ * FUNCTION:	Interface to DD strategy routine
+ *
+ * RETURN:      none
+ *
+ * serialization: LCACHE_LOCK() is NOT held during log i/o;
+ */
+void lbmStartIO(struct lbuf * bp)
+{
+	jFYI(1, ("lbmStartIO\n"));
+
+	bp->l_bh.b_reqnext = NULL;
+	set_bit(BH_Dirty, &bp->l_bh.b_state);
+//      lock_buffer(&bp->l_bh);
+	assert(!test_bit(BH_Lock, &bp->l_bh.b_state));
+	set_bit(BH_Lock, &bp->l_bh.b_state);
+
+	set_bit(BH_Mapped, &bp->l_bh.b_state);
+	set_bit(BH_Req, &bp->l_bh.b_state);
+	bp->l_bh.b_rdev = bp->l_bh.b_dev;
+	bp->l_bh.b_rsector = bp->l_blkno << (bp->l_log->l2bsize - 9);
+	generic_make_request(WRITE, &bp->l_bh);
+
+	INCREMENT(lmStat.submitted);
+	run_task_queue(&tq_disk);
+
+	jFYI(1, ("lbmStartIO done\n"));
+}
+
+
+/*
+ *	lbmIOWait()
+ */
+static int lbmIOWait(struct lbuf * bp, int flag)
+{
+	unsigned long flags;
+	int rc = 0;
+
+	jFYI(1,
+	     ("lbmIOWait1: bp:0x%p flag:0x%x:0x%x\n", bp, bp->l_flag,
+	      flag));
+
+	LCACHE_LOCK(flags);		/* disable+lock */
+
+	LCACHE_SLEEP_COND(bp->l_ioevent, (bp->l_flag & lbmDONE), flags);
+
+	rc = (bp->l_flag & lbmERROR) ? EIO : 0;
+
+	if (flag & lbmFREE)
+		lbmfree(bp);
+
+	LCACHE_UNLOCK(flags);	/* unlock+enable */
+
+	jFYI(1,
+	     ("lbmIOWait2: bp:0x%p flag:0x%x:0x%x\n", bp, bp->l_flag,
+	      flag));
+	return rc;
+}
+
+/*
+ *	lbmIODone()
+ *
+ * executed at INTIODONE level
+ */
+static void lbmIODone(struct buffer_head *bh, int uptodate)
+{
+	struct lbuf *bp = bh->b_private;
+	struct lbuf *nextbp, *tail;
+	struct jfs_log *log;
+	unsigned long flags;
+
+	/*
+	 * get back jfs buffer bound to the i/o buffer
+	 */
+	jEVENT(0, ("lbmIODone: bp:0x%p flag:0x%x\n", bp, bp->l_flag));
+
+	LCACHE_LOCK(flags);		/* disable+lock */
+
+	unlock_buffer(&bp->l_bh);
+	bp->l_flag |= lbmDONE;
+
+	if (!uptodate) {
+		bp->l_flag |= lbmERROR;
+
+		jERROR(1, ("lbmIODone: I/O error in JFS log\n"));
+	}
+
+	/*
+	 *      pagein completion
+	 */
+	if (bp->l_flag & lbmREAD) {
+		bp->l_flag &= ~lbmREAD;
+
+		LCACHE_UNLOCK(flags);	/* unlock+enable */
+
+		/* wakeup I/O initiator */
+		LCACHE_WAKEUP(&bp->l_ioevent);
+
+		return;
+	}
+
+	/*
+	 *      pageout completion
+	 *
+	 * the bp at the head of write queue has completed pageout.
+	 *
+	 * if single-commit/full-page pageout, remove the current buffer
+	 * from head of pageout queue, and redrive pageout with
+	 * the new buffer at head of pageout queue;
+	 * otherwise, the partial-page pageout buffer stays at
+	 * the head of pageout queue to be redriven for pageout
+	 * by lmGroupCommit() until full-page pageout is completed.
+	 */
+	bp->l_flag &= ~lbmWRITE;
+	INCREMENT(lmStat.pagedone);
+
+	/* update committed lsn */
+	log = bp->l_log;
+	log->clsn = (bp->l_pn << L2LOGPSIZE) + bp->l_ceor;
+
+	if (bp->l_flag & lbmDIRECT) {
+		LCACHE_WAKEUP(&bp->l_ioevent);
+		LCACHE_UNLOCK(flags);
+		return;
+	}
+
+	tail = log->wqueue;
+
+	/* single element queue */
+	if (bp == tail) {
+		/* remove head buffer of full-page pageout
+		 * from log device write queue
+		 */
+		if (bp->l_flag & lbmRELEASE) {
+			log->wqueue = NULL;
+			bp->l_wqnext = NULL;
+		}
+	}
+	/* multi element queue */
+	else {
+		/* remove head buffer of full-page pageout
+		 * from log device write queue
+		 */
+		if (bp->l_flag & lbmRELEASE) {
+			nextbp = tail->l_wqnext = bp->l_wqnext;
+			bp->l_wqnext = NULL;
+
+			/*
+			 * redrive pageout of next page at head of write queue:
+			 * redrive next page without any bound tblk
+			 * (i.e., page w/o any COMMIT records), or
+			 * first page of new group commit which has been
+			 * queued after current page (subsequent pageout
+			 * is performed synchronously, except page without
+			 * any COMMITs) by lmGroupCommit() as indicated
+			 * by lbmWRITE flag;
+			 */
+			if (nextbp->l_flag & lbmWRITE) {
+				/*
+				 * We can't do the I/O at interrupt time.
+				 * The jfsIO thread can do it
+				 */
+				lbmRedrive(nextbp);
+			}
+		}
+	}
+
+	/*
+	 *      synchronous pageout:
+	 *
+	 * buffer has not necessarily been removed from write queue
+	 * (e.g., synchronous write of partial-page with COMMIT):
+	 * leave buffer for i/o initiator to dispose
+	 */
+	if (bp->l_flag & lbmSYNC) {
+		LCACHE_UNLOCK(flags);	/* unlock+enable */
+
+		/* wakeup I/O initiator */
+		LCACHE_WAKEUP(&bp->l_ioevent);
+	}
+
+	/*
+	 *      Group Commit pageout:
+	 */
+	else if (bp->l_flag & lbmGC) {
+		LCACHE_UNLOCK(flags);
+		lmPostGC(bp);
+	}
+
+	/*
+	 *      asynchronous pageout:
+	 *
+	 * buffer must have been removed from write queue:
+	 * insert buffer at head of freelist where it can be recycled
+	 */
+	else {
+		assert(bp->l_flag & lbmRELEASE);
+		assert(bp->l_flag & lbmFREE);
+		lbmfree(bp);
+
+		LCACHE_UNLOCK(flags);	/* unlock+enable */
+	}
+}
+
+int jfsIOWait(void *arg)
+{
+	struct lbuf *bp;
+
+	jFYI(1, ("jfsIOWait is here!\n"));
+
+	lock_kernel();
+
+	daemonize();
+	current->tty = NULL;
+	strcpy(current->comm, "jfsIO");
+
+	unlock_kernel();
+
+	spin_lock_irq(&current->sigmask_lock);
+	sigfillset(&current->blocked);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	complete(&jfsIOwait);
+
+	do {
+		DECLARE_WAITQUEUE(wq, current);
+
+		spin_lock_irq(&log_redrive_lock);
+		while ((bp = log_redrive_list)) {
+			log_redrive_list = bp->l_redrive_next;
+			bp->l_redrive_next = NULL;
+			spin_unlock_irq(&log_redrive_lock);
+			lbmStartIO(bp);
+			spin_lock_irq(&log_redrive_lock);
+		}
+		add_wait_queue(&jfs_IO_thread_wait, &wq);
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_unlock_irq(&log_redrive_lock);
+		schedule();
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&jfs_IO_thread_wait, &wq);
+	} while (!jfs_stop_threads);
+
+	jFYI(1,("jfsIOWait being killed!\n"));
+	complete(&jfsIOwait);
+	return 0;
+}
+
+/*
+ * NAME:	lmLogFormat()/jfs_logform()
+ *
+ * FUNCTION:	format file system log
+ *
+ * PARAMETERS:
+ *      log	- volume log
+ *	logAddress - start address of log space in FS block
+ *	logSize	- length of log space in FS block;
+ *
+ * RETURN:	0	- success
+ *		-EIO	- i/o error
+ *
+ * XXX: We're synchronously writing one page at a time.  This needs to
+ *	be improved by writing multiple pages at once.
+ */
+int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize)
+{
+	int rc = -EIO;
+	struct jfs_sb_info *sbi = JFS_SBI(log->sb);
+	struct logsuper *logsuper;
+	struct logpage *lp;
+	int lspn;		/* log sequence page number */
+	struct lrd *lrd_ptr;
+	int npages = 0;
+	struct lbuf *bp;
+
+	jFYI(0, ("lmLogFormat: logAddress:%Ld logSize:%d\n",
+		 (long long)logAddress, logSize));
+
+	/* allocate a log buffer */
+	bp = lbmAllocate(log, 1);
+
+	npages = logSize >> sbi->l2nbperpage;
+
+	/*
+	 *      log space:
+	 *
+	 * page 0 - reserved;
+	 * page 1 - log superblock;
+	 * page 2 - log data page: A SYNC log record is written
+	 *          into this page at logform time;
+	 * pages 3-N - log data page: set to empty log data pages;
+	 */
+	/*
+	 *      init log superblock: log page 1
+	 */
+	logsuper = (struct logsuper *) bp->l_ldata;
+
+	logsuper->magic = cpu_to_le32(LOGMAGIC);
+	logsuper->version = cpu_to_le32(LOGVERSION);
+	logsuper->state = cpu_to_le32(LOGREDONE);
+	logsuper->flag = cpu_to_le32(sbi->mntflag);	/* ? */
+	logsuper->size = cpu_to_le32(npages);
+	logsuper->bsize = cpu_to_le32(sbi->bsize);
+	logsuper->l2bsize = cpu_to_le32(sbi->l2bsize);
+	logsuper->end = cpu_to_le32(2 * LOGPSIZE + LOGPHDRSIZE + LOGRDSIZE);
+
+	bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT;
+	bp->l_blkno = logAddress + sbi->nbperpage;
+	lbmStartIO(bp);
+	if ((rc = lbmIOWait(bp, 0)))
+		goto exit;
+
+	/*
+	 *      init pages 2 to npages-1 as log data pages:
+	 *
+	 * log page sequence number (lpsn) initialization:
+	 *
+	 * pn:   0     1     2     3                 n-1
+	 *       +-----+-----+=====+=====+===.....===+=====+
+	 * lspn:             N-1   0     1           N-2
+	 *                   <--- N page circular file ---->
+	 *
+	 * the N (= npages-2) data pages of the log is maintained as
+	 * a circular file for the log records;
+	 * lpsn grows by 1 monotonically as each log page is written
+	 * to the circular file of the log;
+	 * and setLogpage() will not reset the page number even if
+	 * the eor is equal to LOGPHDRSIZE. In order for binary search
+	 * still work in find log end process, we have to simulate the
+	 * log wrap situation at the log format time.
+	 * The 1st log page written will have the highest lpsn. Then
+	 * the succeeding log pages will have ascending order of
+	 * the lspn starting from 0, ... (N-2)
+	 */
+	lp = (struct logpage *) bp->l_ldata;
+	/*
+	 * initialize 1st log page to be written: lpsn = N - 1,
+	 * write a SYNCPT log record is written to this page
+	 */
+	lp->h.page = lp->t.page = cpu_to_le32(npages - 3);
+	lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE + LOGRDSIZE);
+
+	lrd_ptr = (struct lrd *) &lp->data;
+	lrd_ptr->logtid = 0;
+	lrd_ptr->backchain = 0;
+	lrd_ptr->type = cpu_to_le16(LOG_SYNCPT);
+	lrd_ptr->length = 0;
+	lrd_ptr->log.syncpt.sync = 0;
+
+	bp->l_blkno += sbi->nbperpage;
+	bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT;
+	lbmStartIO(bp);
+	if ((rc = lbmIOWait(bp, 0)))
+		goto exit;
+
+	/*
+	 *      initialize succeeding log pages: lpsn = 0, 1, ..., (N-2)
+	 */
+	for (lspn = 0; lspn < npages - 3; lspn++) {
+		lp->h.page = lp->t.page = cpu_to_le32(lspn);
+		lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE);
+
+		bp->l_blkno += sbi->nbperpage;
+		bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT;
+		lbmStartIO(bp);
+		if ((rc = lbmIOWait(bp, 0)))
+			goto exit;
+	}
+
+	rc = 0;
+exit:
+	/*
+	 *      finalize log
+	 */
+	/* release the buffer */
+	lbmFree(bp);
+
+	return rc;
+}
+
+#ifdef CONFIG_JFS_STATISTICS
+int jfs_lmstats_read(char *buffer, char **start, off_t offset, int length,
+		      int *eof, void *data)
+{
+	int len = 0;
+	off_t begin;
+
+	len += sprintf(buffer,
+		       "JFS Logmgr stats\n"
+		       "================\n"
+		       "commits = %d\n"
+		       "writes submitted = %d\n"
+		       "writes completed = %d\n",
+		       lmStat.commit,
+		       lmStat.submitted,
+		       lmStat.pagedone);
+
+	begin = offset;
+	*start = buffer + begin;
+	len -= begin;
+
+	if (len > length)
+		len = length;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+#endif /* CONFIG_JFS_STATISTICS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_logmgr.h linux-2.4.20/fs/jfs/jfs_logmgr.h
--- linux-2.4.19/fs/jfs/jfs_logmgr.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_logmgr.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,512 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *
+ *   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
+ */
+#ifndef	_H_JFS_LOGMGR
+#define _H_JFS_LOGMGR
+
+#include "jfs_filsys.h"
+#include "jfs_lock.h"
+
+/*
+ *	log manager configuration parameters
+ */
+
+/* log page size */
+#define	LOGPSIZE	4096
+#define	L2LOGPSIZE	12
+
+#define LOGPAGES	16	/* Log pages per mounted file system */
+
+/*
+ *	log logical volume
+ *
+ * a log is used to make the commit operation on journalled 
+ * files within the same logical volume group atomic.
+ * a log is implemented with a logical volume.
+ * there is one log per logical volume group. 
+ *
+ * block 0 of the log logical volume is not used (ipl etc).
+ * block 1 contains a log "superblock" and is used by logFormat(),
+ * lmLogInit(), lmLogShutdown(), and logRedo() to record status 
+ * of the log but is not otherwise used during normal processing. 
+ * blocks 2 - (N-1) are used to contain log records.
+ *
+ * when a volume group is varied-on-line, logRedo() must have 
+ * been executed before the file systems (logical volumes) in 
+ * the volume group can be mounted.
+ */
+/*
+ *	log superblock (block 1 of logical volume)
+ */
+#define	LOGSUPER_B	1
+#define	LOGSTART_B	2
+
+#define	LOGMAGIC	0x87654321
+#define	LOGVERSION	1
+
+#define MAX_ACTIVE	128	/* Max active file systems sharing log */
+
+struct logsuper {
+	u32 magic;		/* 4: log lv identifier */
+	s32 version;		/* 4: version number */
+	s32 serial;		/* 4: log open/mount counter */
+	s32 size;		/* 4: size in number of LOGPSIZE blocks */
+	s32 bsize;		/* 4: logical block size in byte */
+	s32 l2bsize;		/* 4: log2 of bsize */
+
+	u32 flag;		/* 4: option */
+	u32 state;		/* 4: state - see below */
+
+	s32 end;		/* 4: addr of last log record set by logredo */
+	char uuid[16];		/* 16: 128-bit journal uuid */
+	char label[16];		/* 16: journal label */
+	struct {
+		char uuid[16];
+	} active[MAX_ACTIVE];	/* 2048: active file systems list */
+};
+
+#define NULL_UUID "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+
+/* log flag: commit option (see jfs_filsys.h) */
+
+/* log state */
+#define	LOGMOUNT	0	/* log mounted by lmLogInit() */
+#define LOGREDONE	1	/* log shutdown by lmLogShutdown().
+				 * log redo completed by logredo().
+				 */
+#define LOGWRAP		2	/* log wrapped */
+#define LOGREADERR	3	/* log read error detected in logredo() */
+
+
+/*
+ *	log logical page
+ *
+ * (this comment should be rewritten !)
+ * the header and trailer structures (h,t) will normally have 
+ * the same page and eor value.
+ * An exception to this occurs when a complete page write is not 
+ * accomplished on a power failure. Since the hardware may "split write"
+ * sectors in the page, any out of order sequence may occur during powerfail 
+ * and needs to be recognized during log replay.  The xor value is
+ * an "exclusive or" of all log words in the page up to eor.  This
+ * 32 bit eor is stored with the top 16 bits in the header and the
+ * bottom 16 bits in the trailer.  logredo can easily recognize pages
+ * that were not completed by reconstructing this eor and checking 
+ * the log page.
+ *
+ * Previous versions of the operating system did not allow split 
+ * writes and detected partially written records in logredo by 
+ * ordering the updates to the header, trailer, and the move of data 
+ * into the logdata area.  The order: (1) data is moved (2) header 
+ * is updated (3) trailer is updated.  In logredo, when the header 
+ * differed from the trailer, the header and trailer were reconciled 
+ * as follows: if h.page != t.page they were set to the smaller of 
+ * the two and h.eor and t.eor set to 8 (i.e. empty page). if (only) 
+ * h.eor != t.eor they were set to the smaller of their two values.
+ */
+struct logpage {
+	struct {		/* header */
+		s32 page;	/* 4: log sequence page number */
+		s16 rsrvd;	/* 2: */
+		s16 eor;	/* 2: end-of-log offset of lasrt record write */
+	} h;
+
+	s32 data[LOGPSIZE / 4 - 4];	/* log record area */
+
+	struct {		/* trailer */
+		s32 page;	/* 4: normally the same as h.page */
+		s16 rsrvd;	/* 2: */
+		s16 eor;	/* 2: normally the same as h.eor */
+	} t;
+};
+
+#define LOGPHDRSIZE	8	/* log page header size */
+#define LOGPTLRSIZE	8	/* log page trailer size */
+
+
+/*
+ *	log record
+ *
+ * (this comment should be rewritten !)
+ * jfs uses only "after" log records (only a single writer is allowed
+ * in a  page, pages are written to temporary paging space if
+ * if they must be written to disk before commit, and i/o is
+ * scheduled for modified pages to their home location after
+ * the log records containing the after values and the commit 
+ * record is written to the log on disk, undo discards the copy
+ * in main-memory.)
+ *
+ * a log record consists of a data area of variable length followed by 
+ * a descriptor of fixed size LOGRDSIZE bytes.
+ * the  data area is rounded up to an integral number of 4-bytes and 
+ * must be no longer than LOGPSIZE.
+ * the descriptor is of size of multiple of 4-bytes and aligned on a 
+ * 4-byte boundary. 
+ * records are packed one after the other in the data area of log pages.
+ * (sometimes a DUMMY record is inserted so that at least one record ends 
+ * on every page or the longest record is placed on at most two pages).
+ * the field eor in page header/trailer points to the byte following 
+ * the last record on a page.
+ */
+
+/* log record types */
+#define LOG_COMMIT		0x8000
+#define LOG_SYNCPT		0x4000
+#define LOG_MOUNT		0x2000
+#define LOG_REDOPAGE		0x0800
+#define LOG_NOREDOPAGE		0x0080
+#define LOG_NOREDOINOEXT	0x0040
+#define LOG_UPDATEMAP		0x0008
+#define LOG_NOREDOFILE		0x0001
+
+/* REDOPAGE/NOREDOPAGE log record data type */
+#define	LOG_INODE		0x0001
+#define	LOG_XTREE		0x0002
+#define	LOG_DTREE		0x0004
+#define	LOG_BTROOT		0x0010
+#define	LOG_EA			0x0020
+#define	LOG_ACL			0x0040
+#define	LOG_DATA		0x0080
+#define	LOG_NEW			0x0100
+#define	LOG_EXTEND		0x0200
+#define LOG_RELOCATE		0x0400
+#define LOG_DIR_XTREE		0x0800	/* Xtree is in directory inode */
+
+/* UPDATEMAP log record descriptor type */
+#define	LOG_ALLOCXADLIST	0x0080
+#define	LOG_ALLOCPXDLIST	0x0040
+#define	LOG_ALLOCXAD		0x0020
+#define	LOG_ALLOCPXD		0x0010
+#define	LOG_FREEXADLIST		0x0008
+#define	LOG_FREEPXDLIST		0x0004
+#define	LOG_FREEXAD		0x0002
+#define	LOG_FREEPXD		0x0001
+
+
+struct lrd {
+	/*
+	 * type independent area
+	 */
+	s32 logtid;		/* 4: log transaction identifier */
+	s32 backchain;		/* 4: ptr to prev record of same transaction */
+	u16 type;		/* 2: record type */
+	s16 length;		/* 2: length of data in record (in byte) */
+	u32 aggregate;		/* 4: file system lv/aggregate */
+	/* (16) */
+
+	/*
+	 * type dependent area (20)
+	 */
+	union {
+
+		/*
+		 *      COMMIT: commit
+		 *
+		 * transaction commit: no type-dependent information;
+		 */
+
+		/*
+		 *      REDOPAGE: after-image
+		 *
+		 * apply after-image;
+		 *
+		 * N.B. REDOPAGE, NOREDOPAGE, and UPDATEMAP must be same format;
+		 */
+		struct {
+			u32 fileset;	/* 4: fileset number */
+			u32 inode;	/* 4: inode number */
+			u16 type;	/* 2: REDOPAGE record type */
+			s16 l2linesize;	/* 2: log2 of line size */
+			pxd_t pxd;	/* 8: on-disk page pxd */
+		} redopage;	/* (20) */
+
+		/*
+		 *      NOREDOPAGE: the page is freed
+		 *
+		 * do not apply after-image records which precede this record
+		 * in the log with the same page block number to this page.
+		 *
+		 * N.B. REDOPAGE, NOREDOPAGE, and UPDATEMAP must be same format;
+		 */
+		struct {
+			s32 fileset;	/* 4: fileset number */
+			u32 inode;	/* 4: inode number */
+			u16 type;	/* 2: NOREDOPAGE record type */
+			s16 rsrvd;	/* 2: reserved */
+			pxd_t pxd;	/* 8: on-disk page pxd */
+		} noredopage;	/* (20) */
+
+		/*
+		 *      UPDATEMAP: update block allocation map
+		 *
+		 * either in-line PXD,
+		 * or     out-of-line  XADLIST;
+		 *
+		 * N.B. REDOPAGE, NOREDOPAGE, and UPDATEMAP must be same format;
+		 */
+		struct {
+			u32 fileset;	/* 4: fileset number */
+			u32 inode;	/* 4: inode number */
+			u16 type;	/* 2: UPDATEMAP record type */
+			s16 nxd;	/* 2: number of extents */
+			pxd_t pxd;	/* 8: pxd */
+		} updatemap;	/* (20) */
+
+		/*
+		 *      NOREDOINOEXT: the inode extent is freed
+		 *
+		 * do not apply after-image records which precede this 
+		 * record in the log with the any of the 4 page block 
+		 * numbers in this inode extent. 
+		 * 
+		 * NOTE: The fileset and pxd fields MUST remain in 
+		 *       the same fields in the REDOPAGE record format.
+		 *
+		 */
+		struct {
+			s32 fileset;	/* 4: fileset number */
+			s32 iagnum;	/* 4: IAG number     */
+			s32 inoext_idx;	/* 4: inode extent index */
+			pxd_t pxd;	/* 8: on-disk page pxd */
+		} noredoinoext;	/* (20) */
+
+		/*
+		 *      SYNCPT: log sync point
+		 *
+		 * replay log upto syncpt address specified;
+		 */
+		struct {
+			s32 sync;	/* 4: syncpt address (0 = here) */
+		} syncpt;
+
+		/*
+		 *      MOUNT: file system mount
+		 *
+		 * file system mount: no type-dependent information;
+		 */
+
+		/*
+		 *      ? FREEXTENT: free specified extent(s)
+		 *
+		 * free specified extent(s) from block allocation map
+		 * N.B.: nextents should be length of data/sizeof(xad_t)
+		 */
+		struct {
+			s32 type;	/* 4: FREEXTENT record type */
+			s32 nextent;	/* 4: number of extents */
+
+			/* data: PXD or XAD list */
+		} freextent;
+
+		/*
+		 *      ? NOREDOFILE: this file is freed
+		 *
+		 * do not apply records which precede this record in the log
+		 * with the same inode number.
+		 *
+		 * NOREDILE must be the first to be written at commit
+		 * (last to be read in logredo()) - it prevents
+		 * replay of preceding updates of all preceding generations
+		 * of the inumber esp. the on-disk inode itself, 
+		 * but does NOT prevent
+		 * replay of the 
+		 */
+		struct {
+			s32 fileset;	/* 4: fileset number */
+			u32 inode;	/* 4: inode number */
+		} noredofile;
+
+		/*
+		 *      ? NEWPAGE: 
+		 *
+		 * metadata type dependent
+		 */
+		struct {
+			s32 fileset;	/* 4: fileset number */
+			u32 inode;	/* 4: inode number */
+			s32 type;	/* 4: NEWPAGE record type */
+			pxd_t pxd;	/* 8: on-disk page pxd */
+		} newpage;
+
+		/*
+		 *      ? DUMMY: filler
+		 *
+		 * no type-dependent information
+		 */
+	} log;
+};					/* (36) */
+
+#define	LOGRDSIZE	(sizeof(struct lrd))
+
+/*
+ *	line vector descriptor
+ */
+struct lvd {
+	s16 offset;
+	s16 length;
+};
+
+
+/*
+ *	log logical volume
+ */
+struct jfs_log {
+
+	struct super_block *sb;	/* 4: This is used to sync metadata
+				 *    before writing syncpt.  Will
+				 *    need to be a list if we share
+				 *    the log between fs's
+				 */
+	struct block_device *bdev; /* 4: log lv pointer */
+	s32 serial;		/* 4: log mount serial number */
+
+	s64 base;		/* @8: log extent address (inline log ) */
+	int size;		/* 4: log size in log page (in page) */
+	int l2bsize;		/* 4: log2 of bsize */
+
+	long flag;		/* 4: flag */
+
+	struct lbuf *lbuf_free;	/* 4: free lbufs */
+	wait_queue_head_t free_wait;	/* 4: */
+
+	/* log write */
+	int logtid;		/* 4: log tid */
+	int page;		/* 4: page number of eol page */
+	int eor;		/* 4: eor of last record in eol page */
+	struct lbuf *bp;	/* 4: current log page buffer */
+
+	struct semaphore loglock;	/* 4: log write serialization lock */
+
+	/* syncpt */
+	int nextsync;		/* 4: bytes to write before next syncpt */
+	int active;		/* 4: */
+	wait_queue_head_t syncwait;	/* 4: */
+
+	/* commit */
+	uint cflag;		/* 4: */
+	struct {		/* 8: FIFO commit queue header */
+		struct tblock *head;
+		struct tblock *tail;
+	} cqueue;
+	int gcrtc;		/* 4: GC_READY transaction count */
+	struct tblock *gclrt;	/* 4: latest GC_READY transaction */
+	spinlock_t gclock;	/* 4: group commit lock */
+	int logsize;		/* 4: log data area size in byte */
+	int lsn;		/* 4: end-of-log */
+	int clsn;		/* 4: clsn */
+	int syncpt;		/* 4: addr of last syncpt record */
+	int sync;		/* 4: addr from last logsync() */
+	struct list_head synclist;	/* 8: logsynclist anchor */
+	spinlock_t synclock;	/* 4: synclist lock */
+	struct lbuf *wqueue;	/* 4: log pageout queue */
+	int count;		/* 4: count */
+	char uuid[16];		/* 16: 128-bit uuid of log device */
+};
+
+/*
+ * Log flag
+ */
+#define log_INLINELOG	1
+#define log_SYNCBARRIER	2
+#define log_QUIESCE	3
+
+/*
+ * group commit flag
+ */
+/* jfs_log */
+#define logGC_PAGEOUT	0x00000001
+
+/* tblock/lbuf */
+#define tblkGC_QUEUE		0x0001
+#define tblkGC_READY		0x0002
+#define tblkGC_COMMIT		0x0004
+#define tblkGC_COMMITTED	0x0008
+#define tblkGC_EOP		0x0010
+#define tblkGC_FREE		0x0020
+#define tblkGC_LEADER		0x0040
+#define tblkGC_ERROR		0x0080
+#define tblkGC_LAZY		0x0100	// D230860
+#define tblkGC_UNLOCKED		0x0200	// D230860
+
+/*
+ *		log cache buffer header
+ */
+struct lbuf {
+	struct buffer_head l_bh;	/* for doing I/O */
+	struct jfs_log *l_log;		/* 4: log associated with buffer */
+
+	/*
+	 * data buffer base area
+	 */
+	uint l_flag;		/* 4: pageout control flags */
+
+	struct lbuf *l_wqnext;	/* 4: write queue link */
+	struct lbuf *l_freelist;	/* 4: freelistlink */
+
+	int l_pn;		/* 4: log page number */
+	int l_eor;		/* 4: log record eor */
+	int l_ceor;		/* 4: committed log record eor */
+
+	s64 l_blkno;		/* 8: log page block number */
+	caddr_t l_ldata;	/* 4: data page */
+
+	wait_queue_head_t l_ioevent;	/* 4: i/o done event */
+	struct page *l_page;	/* The page itself */
+};
+
+/* Reuse l_freelist for redrive list */
+#define l_redrive_next l_freelist
+
+/*
+ *	logsynclist block
+ *
+ * common logsyncblk prefix for jbuf_t and tblock
+ */
+struct logsyncblk {
+	u16 xflag;		/* flags */
+	u16 flag;		/* only meaninful in tblock */
+	lid_t lid;		/* lock id */
+	s32 lsn;		/* log sequence number */
+	struct list_head synclist;	/* log sync list link */
+};
+
+/*
+ *	logsynclist serialization (per log)
+ */
+
+#define LOGSYNC_LOCK_INIT(log) spin_lock_init(&(log)->synclock)
+#define LOGSYNC_LOCK(log) spin_lock(&(log)->synclock)
+#define LOGSYNC_UNLOCK(log) spin_unlock(&(log)->synclock)
+
+/* compute the difference in bytes of lsn from sync point */
+#define logdiff(diff, lsn, log)\
+{\
+	diff = (lsn) - (log)->syncpt;\
+	if (diff < 0)\
+		diff += (log)->logsize;\
+}
+
+extern int lmLogOpen(struct super_block *sb, struct jfs_log ** log);
+extern void lmLogWait(struct jfs_log * log);
+extern int lmLogClose(struct super_block *sb, struct jfs_log * log);
+extern int lmLogSync(struct jfs_log * log, int nosyncwait);
+extern int lmLogShutdown(struct jfs_log * log);
+extern int lmLogInit(struct jfs_log * log);
+extern int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize);
+
+#endif				/* _H_JFS_LOGMGR */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_metapage.c linux-2.4.20/fs/jfs/jfs_metapage.c
--- linux-2.4.19/fs/jfs/jfs_metapage.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_metapage.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,628 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *
+ *   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
+ */
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_metapage.h"
+#include "jfs_txnmgr.h"
+#include "jfs_debug.h"
+
+extern struct task_struct *jfsCommitTask;
+static spinlock_t meta_lock = SPIN_LOCK_UNLOCKED;
+static wait_queue_head_t meta_wait;
+
+#ifdef CONFIG_JFS_STATISTICS
+struct {
+	uint	pagealloc;	/* # of page allocations */
+	uint	pagefree;	/* # of page frees */
+	uint	lockwait;	/* # of sleeping lock_metapage() calls */
+	uint	allocwait;	/* # of sleeping alloc_metapage() calls */
+} mpStat;
+#endif
+
+
+#define HASH_BITS 10		/* This makes hash_table 1 4K page */
+#define HASH_SIZE (1 << HASH_BITS)
+static struct metapage **hash_table = NULL;
+static unsigned long hash_order;
+
+
+static inline int metapage_locked(struct metapage *mp)
+{
+	return test_bit(META_locked, &mp->flag);
+}
+
+static inline int trylock_metapage(struct metapage *mp)
+{
+	return test_and_set_bit(META_locked, &mp->flag);
+}
+
+static inline void unlock_metapage(struct metapage *mp)
+{
+	clear_bit(META_locked, &mp->flag);
+	wake_up(&mp->wait);
+}
+
+static void __lock_metapage(struct metapage *mp)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	INCREMENT(mpStat.lockwait);
+
+	add_wait_queue_exclusive(&mp->wait, &wait);
+	do {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		if (metapage_locked(mp)) {
+			spin_unlock(&meta_lock);
+			schedule();
+			spin_lock(&meta_lock);
+		}
+	} while (trylock_metapage(mp));
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&mp->wait, &wait);
+}
+
+/* needs meta_lock */
+static inline void lock_metapage(struct metapage *mp)
+{
+	if (trylock_metapage(mp))
+		__lock_metapage(mp);
+}
+
+/*
+ * metapage pool is based on Linux 2.5's mempool
+ *
+ * Tap into reserved structures in critical paths where waiting on a
+ * memory allocation could cause deadlock
+ */
+#define METAPOOL_MIN_PAGES 32
+static struct metapage *reserved_metapages[METAPOOL_MIN_PAGES];
+static int num_reserved = 0;
+kmem_cache_t *metapage_cache;
+
+static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags)
+{
+	struct metapage *mp = (struct metapage *)foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		mp->lid = 0;
+		mp->lsn = 0;
+		mp->flag = 0;
+		mp->data = NULL;
+		mp->clsn = 0;
+		mp->log = NULL;
+		set_bit(META_free, &mp->flag);
+		init_waitqueue_head(&mp->wait);
+	}
+}
+
+static void empty_reserved(void)
+{
+	while (num_reserved--)
+		kmem_cache_free(metapage_cache,
+				reserved_metapages[num_reserved]);
+}
+
+static struct metapage *alloc_metapage(int *dropped_lock, int no_wait)
+{
+	struct metapage *new;
+
+	*dropped_lock = 0;
+
+	/*
+	 * Always try an atomic alloc first, to avoid dropping the
+	 * spinlock
+	 */
+	new = kmem_cache_alloc(metapage_cache, GFP_ATOMIC);
+	if (new)
+		return new;
+
+	if (no_wait && num_reserved)
+		return reserved_metapages[--num_reserved];
+
+	*dropped_lock = 1;
+	spin_unlock(&meta_lock);
+	new = kmem_cache_alloc(metapage_cache, GFP_NOFS);
+	spin_lock(&meta_lock);
+	return new;
+}
+
+static void __free_metapage(struct metapage *mp)
+{
+	mp->flag = 0;
+	set_bit(META_free, &mp->flag);
+
+	if (num_reserved < METAPOOL_MIN_PAGES)
+		reserved_metapages[num_reserved++] = mp;
+	else
+		kmem_cache_free(metapage_cache, mp);
+}
+
+static inline void free_metapage(struct metapage * mp)
+{
+	spin_lock(&meta_lock);
+	__free_metapage(mp);
+	spin_unlock(&meta_lock);
+}
+
+int __init metapage_init(void)
+{
+	struct metapage *mp;
+
+	/*
+	 * Initialize wait queue
+	 */
+	init_waitqueue_head(&meta_wait);
+
+	/*
+	 * Allocate the metapage structures
+	 */
+	metapage_cache = kmem_cache_create("jfs_mp", sizeof(struct metapage),
+					   0, 0, init_once, NULL);
+	if (metapage_cache == NULL)
+		return -ENOMEM;
+
+	while (num_reserved < METAPOOL_MIN_PAGES) {
+		mp = kmem_cache_alloc(metapage_cache, GFP_NOFS);
+		if (mp)
+			reserved_metapages[num_reserved++] = mp;
+		else {
+			empty_reserved();
+			kmem_cache_destroy(metapage_cache);
+			return -ENOMEM;
+		}
+	}
+	/*
+	 * Now the hash list
+	 */
+	for (hash_order = 0;
+	     ((PAGE_SIZE << hash_order) / sizeof(void *)) < HASH_SIZE;
+	     hash_order++);
+	hash_table =
+	    (struct metapage **) __get_free_pages(GFP_KERNEL, hash_order);
+	assert(hash_table);
+	memset(hash_table, 0, PAGE_SIZE << hash_order);
+
+	return 0;
+}
+
+void metapage_exit(void)
+{
+	empty_reserved();
+	kmem_cache_destroy(metapage_cache);
+}
+
+/*
+ * Basically same hash as in pagemap.h, but using our hash table
+ */
+static struct metapage **meta_hash(struct address_space *mapping,
+				   unsigned long index)
+{
+#define i (((unsigned long)mapping)/ \
+	   (sizeof(struct inode) & ~(sizeof(struct inode) -1 )))
+#define s(x) ((x) + ((x) >> HASH_BITS))
+	return hash_table + (s(i + index) & (HASH_SIZE - 1));
+#undef i
+#undef s
+}
+
+static struct metapage *search_hash(struct metapage ** hash_ptr,
+				    struct address_space *mapping,
+			       unsigned long index)
+{
+	struct metapage *ptr;
+
+	for (ptr = *hash_ptr; ptr; ptr = ptr->hash_next) {
+		if ((ptr->mapping == mapping) && (ptr->index == index))
+			return ptr;
+	}
+
+	return NULL;
+}
+
+static void add_to_hash(struct metapage * mp, struct metapage ** hash_ptr)
+{
+	if (*hash_ptr)
+		(*hash_ptr)->hash_prev = mp;
+
+	mp->hash_prev = NULL;
+	mp->hash_next = *hash_ptr;
+	*hash_ptr = mp;
+}
+
+static void remove_from_hash(struct metapage * mp, struct metapage ** hash_ptr)
+{
+	if (mp->hash_prev)
+		mp->hash_prev->hash_next = mp->hash_next;
+	else {
+		assert(*hash_ptr == mp);
+		*hash_ptr = mp->hash_next;
+	}
+
+	if (mp->hash_next)
+		mp->hash_next->hash_prev = mp->hash_prev;
+}
+
+struct metapage *__get_metapage(struct inode *inode, unsigned long lblock,
+				unsigned int size, int absolute,
+				unsigned long new)
+{
+	int dropped_lock;
+	struct metapage **hash_ptr;
+	int l2BlocksPerPage;
+	int l2bsize;
+	int no_wait;
+	struct address_space *mapping;
+	struct metapage *mp;
+	unsigned long page_index;
+	unsigned long page_offset;
+
+	jFYI(1, ("__get_metapage: inode = 0x%p, lblock = 0x%lx\n",
+		 inode, lblock));
+
+	if (absolute)
+		mapping = inode->i_sb->s_bdev->bd_inode->i_mapping;
+	else
+		mapping = inode->i_mapping;
+
+	spin_lock(&meta_lock);
+
+	hash_ptr = meta_hash(mapping, lblock);
+
+	mp = search_hash(hash_ptr, mapping, lblock);
+	if (mp) {
+	      page_found:
+		if (test_bit(META_discard, &mp->flag)) {
+			assert(new);	/* It's okay to reuse a discarded
+					 * if we expect it to be empty
+					 */
+			clear_bit(META_discard, &mp->flag);
+		}
+		mp->count++;
+		jFYI(1, ("__get_metapage: found 0x%p, in hash\n", mp));
+		assert(mp->logical_size == size);
+		lock_metapage(mp);
+		spin_unlock(&meta_lock);
+	} else {
+		l2bsize = inode->i_blkbits;
+		l2BlocksPerPage = PAGE_CACHE_SHIFT - l2bsize;
+		page_index = lblock >> l2BlocksPerPage;
+		page_offset = (lblock - (page_index << l2BlocksPerPage)) <<
+		    l2bsize;
+		if ((page_offset + size) > PAGE_CACHE_SIZE) {
+			spin_unlock(&meta_lock);
+			jERROR(1, ("MetaData crosses page boundary!!\n"));
+			return NULL;
+		}
+		
+		/*
+		 * Locks held on aggregate inode pages are usually
+		 * not held long, and they are taken in critical code
+		 * paths (committing dirty inodes, txCommit thread) 
+		 * 
+		 * Attempt to get metapage without blocking, tapping into
+		 * reserves if necessary.
+		 */
+		if (JFS_IP(inode)->fileset == AGGREGATE_I)
+			no_wait = 1;
+		else
+			no_wait = 0;
+
+		mp = alloc_metapage(&dropped_lock, no_wait);
+		if (dropped_lock) {
+			/* alloc_metapage blocked, we need to search the hash
+			 * again.
+			 */
+			struct metapage *mp2;
+			mp2 = search_hash(hash_ptr, mapping, lblock);
+			if (mp2) {
+				__free_metapage(mp);
+				mp = mp2;
+				goto page_found;
+			}
+		}
+		mp->flag = 0;
+		lock_metapage(mp);
+		if (absolute)
+			set_bit(META_absolute, &mp->flag);
+		mp->xflag = COMMIT_PAGE;
+		mp->count = 1;
+		atomic_set(&mp->nohomeok,0);
+		mp->mapping = mapping;
+		mp->index = lblock;
+		mp->page = 0;
+		mp->logical_size = size;
+		add_to_hash(mp, hash_ptr);
+		if (!absolute)
+			list_add(&mp->inode_list, &JFS_IP(inode)->mp_list);
+		spin_unlock(&meta_lock);
+
+		if (new) {
+			jFYI(1,
+			     ("__get_metapage: Calling grab_cache_page\n"));
+			mp->page = grab_cache_page(mapping, page_index);
+			if (!mp->page) {
+				jERROR(1, ("grab_cache_page failed!\n"));
+				goto freeit;
+			} else
+				INCREMENT(mpStat.pagealloc);
+		} else {
+			jFYI(1,
+			     ("__get_metapage: Calling read_cache_page\n"));
+			mp->page = read_cache_page(mapping, lblock,
+				    (filler_t *)mapping->a_ops->readpage, NULL);
+			if (IS_ERR(mp->page)) {
+				jERROR(1, ("read_cache_page failed!\n"));
+				goto freeit;
+			} else
+				INCREMENT(mpStat.pagealloc);
+			lock_page(mp->page);
+		}
+		mp->data = kmap(mp->page) + page_offset;
+	}
+	jFYI(1, ("__get_metapage: returning = 0x%p\n", mp));
+	return mp;
+
+freeit:
+	spin_lock(&meta_lock);
+	remove_from_hash(mp, hash_ptr);
+	if (!absolute)
+		list_del(&mp->inode_list);
+	__free_metapage(mp);
+	spin_unlock(&meta_lock);
+	return NULL;
+}
+
+void hold_metapage(struct metapage * mp, int force)
+{
+	spin_lock(&meta_lock);
+
+	mp->count++;
+
+	if (force) {
+		ASSERT (!(test_bit(META_forced, &mp->flag)));
+		if (trylock_metapage(mp))
+			set_bit(META_forced, &mp->flag);
+	} else
+		lock_metapage(mp);
+
+	spin_unlock(&meta_lock);
+}
+
+static void __write_metapage(struct metapage * mp)
+{
+	int l2bsize = mp->mapping->host->i_blkbits;
+	int l2BlocksPerPage = PAGE_CACHE_SHIFT - l2bsize;
+	unsigned long page_index;
+	unsigned long page_offset;
+	int rc;
+
+	jFYI(1, ("__write_metapage: mp = 0x%p\n", mp));
+
+	if (test_bit(META_discard, &mp->flag)) {
+		/*
+		 * This metadata is no longer valid
+		 */
+		clear_bit(META_dirty, &mp->flag);
+		return;
+	}
+
+	page_index = mp->page->index;
+	page_offset =
+	    (mp->index - (page_index << l2BlocksPerPage)) << l2bsize;
+
+	rc = mp->mapping->a_ops->prepare_write(NULL, mp->page, page_offset,
+					       page_offset +
+					       mp->logical_size);
+	if (rc) {
+		jERROR(1, ("prepare_write return %d!\n", rc));
+		ClearPageUptodate(mp->page);
+		kunmap(mp->page);
+		clear_bit(META_dirty, &mp->flag);
+		return;
+	}
+	rc = mp->mapping->a_ops->commit_write(NULL, mp->page, page_offset,
+					      page_offset +
+					      mp->logical_size);
+	if (rc) {
+		jERROR(1, ("commit_write returned %d\n", rc));
+	}
+
+	clear_bit(META_dirty, &mp->flag);
+
+	jFYI(1, ("__write_metapage done\n"));
+}
+
+static inline void sync_metapage(struct metapage *mp)
+{
+	struct page *page = mp->page;
+
+	page_cache_get(page);
+	lock_page(page);
+
+	/* we're done with this page - no need to check for errors */
+	if (page->buffers) {
+		writeout_one_page(page);
+		waitfor_one_page(page);
+	}
+
+	UnlockPage(page);
+	page_cache_release(page);
+}
+
+void release_metapage(struct metapage * mp)
+{
+	struct jfs_log *log;
+
+	jFYI(1,
+	     ("release_metapage: mp = 0x%p, flag = 0x%lx\n", mp,
+	      mp->flag));
+
+	spin_lock(&meta_lock);
+	if (test_bit(META_forced, &mp->flag)) {
+		clear_bit(META_forced, &mp->flag);
+		mp->count--;
+		spin_unlock(&meta_lock);
+		return;
+	}
+
+	assert(mp->count);
+	if (--mp->count || atomic_read(&mp->nohomeok)) {
+		unlock_metapage(mp);
+		spin_unlock(&meta_lock);
+	} else {
+		remove_from_hash(mp, meta_hash(mp->mapping, mp->index));
+		if (!test_bit(META_absolute, &mp->flag))
+			list_del(&mp->inode_list);
+		spin_unlock(&meta_lock);
+
+		if (mp->page) {
+			kunmap(mp->page);
+			mp->data = 0;
+			if (test_bit(META_dirty, &mp->flag))
+				__write_metapage(mp);
+			UnlockPage(mp->page);
+			if (test_bit(META_sync, &mp->flag)) {
+				sync_metapage(mp);
+				clear_bit(META_sync, &mp->flag);
+			}
+
+			if (test_bit(META_discard, &mp->flag)) {
+				lock_page(mp->page);
+				block_flushpage(mp->page, 0);
+				unlock_page(mp->page);
+			}
+
+			page_cache_release(mp->page);
+			INCREMENT(mpStat.pagefree);
+		}
+
+		if (mp->lsn) {
+			/*
+			 * Remove metapage from logsynclist.
+			 */
+			log = mp->log;
+			LOGSYNC_LOCK(log);
+			mp->log = 0;
+			mp->lsn = 0;
+			mp->clsn = 0;
+			log->count--;
+			list_del(&mp->synclist);
+			LOGSYNC_UNLOCK(log);
+		}
+
+		free_metapage(mp);
+	}
+	jFYI(1, ("release_metapage: done\n"));
+}
+
+void __invalidate_metapages(struct inode *ip, s64 addr, int len)
+{
+	struct metapage **hash_ptr;
+	unsigned long lblock;
+	int l2BlocksPerPage = PAGE_CACHE_SHIFT - ip->i_blkbits;
+	struct address_space *mapping = ip->i_mapping;
+	struct metapage *mp;
+	struct page *page;
+
+	/*
+	 * First, mark metapages to discard.  They will eventually be
+	 * released, but should not be written.
+	 */
+	for (lblock = addr; lblock < addr + len;
+	     lblock += 1 << l2BlocksPerPage) {
+		hash_ptr = meta_hash(mapping, lblock);
+		spin_lock(&meta_lock);
+		mp = search_hash(hash_ptr, mapping, lblock);
+		if (mp) {
+			set_bit(META_discard, &mp->flag);
+			spin_unlock(&meta_lock);
+			/*
+			 * If in the metapage cache, we've got the page locked
+			 */
+			block_flushpage(mp->page, 0);
+		} else {
+			spin_unlock(&meta_lock);
+			page = find_lock_page(mapping, lblock>>l2BlocksPerPage);
+			if (page) {
+				block_flushpage(page, 0);
+				UnlockPage(page);
+			}
+		}
+	}
+}
+
+void invalidate_inode_metapages(struct inode *inode)
+{
+	struct list_head *ptr;
+	struct metapage *mp;
+
+	spin_lock(&meta_lock);
+	list_for_each(ptr, &JFS_IP(inode)->mp_list) {
+		mp = list_entry(ptr, struct metapage, inode_list);
+		clear_bit(META_dirty, &mp->flag);
+		set_bit(META_discard, &mp->flag);
+		kunmap(mp->page);
+		UnlockPage(mp->page);
+		page_cache_release(mp->page);
+		INCREMENT(mpStat.pagefree);
+		mp->data = 0;
+		mp->page = 0;
+	}
+	spin_unlock(&meta_lock);
+	truncate_inode_pages(inode->i_mapping, 0);
+}
+
+#ifdef CONFIG_JFS_STATISTICS
+int jfs_mpstat_read(char *buffer, char **start, off_t offset, int length,
+		    int *eof, void *data)
+{
+	int len = 0;
+	off_t begin;
+
+	len += sprintf(buffer,
+		       "JFS Metapage statistics\n"
+		       "=======================\n"
+		       "page allocations = %d\n"
+		       "page frees = %d\n"
+		       "lock waits = %d\n"
+		       "allocation waits = %d\n",
+		       mpStat.pagealloc,
+		       mpStat.pagefree,
+		       mpStat.lockwait,
+		       mpStat.allocwait);
+
+	begin = offset;
+	*start = buffer + begin;
+	len -= begin;
+
+	if (len > length)
+		len = length;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_metapage.h linux-2.4.20/fs/jfs/jfs_metapage.h
--- linux-2.4.19/fs/jfs/jfs_metapage.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_metapage.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,117 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *
+ *   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
+ */
+#ifndef	_H_JFS_METAPAGE
+#define _H_JFS_METAPAGE
+
+#include <linux/pagemap.h>
+
+struct metapage {
+	/* Common logsyncblk prefix (see jfs_logmgr.h) */
+	u16 xflag;
+	u16 unused;
+	lid_t lid;
+	int lsn;
+	struct list_head synclist;
+	/* End of logsyncblk prefix */
+
+	unsigned long flag;	/* See Below */
+	unsigned long count;	/* Reference count */
+	void *data;		/* Data pointer */
+
+	/* list management stuff */
+	struct metapage *hash_prev;
+	struct metapage *hash_next;	/* Also used for free list */
+
+	struct list_head inode_list;	/* per-inode metapage list */
+	/*
+	 * mapping & index become redundant, but we need these here to
+	 * add the metapage to the hash before we have the real page
+	 */
+	struct address_space *mapping;
+	unsigned long index;
+	wait_queue_head_t wait;
+
+	/* implementation */
+	struct page *page;
+	unsigned long logical_size;
+
+	/* Journal management */
+	int clsn;
+	atomic_t nohomeok;
+	struct jfs_log *log;
+};
+
+/* metapage flag */
+#define META_locked	0
+#define META_absolute	1
+#define META_free	2
+#define META_dirty	3
+#define META_sync	4
+#define META_discard	5
+#define META_forced	6
+
+#define mark_metapage_dirty(mp) set_bit(META_dirty, &(mp)->flag)
+
+/* function prototypes */
+extern struct metapage *__get_metapage(struct inode *inode,
+				  unsigned long lblock, unsigned int size,
+				  int absolute, unsigned long new);
+
+#define read_metapage(inode, lblock, size, absolute)\
+	 __get_metapage(inode, lblock, size, absolute, FALSE)
+
+#define get_metapage(inode, lblock, size, absolute)\
+	 __get_metapage(inode, lblock, size, absolute, TRUE)
+
+extern void release_metapage(struct metapage *);
+extern void hold_metapage(struct metapage *, int);
+
+static inline void write_metapage(struct metapage *mp)
+{
+	set_bit(META_dirty, &mp->flag);
+	release_metapage(mp);
+}
+
+static inline void flush_metapage(struct metapage *mp)
+{
+	set_bit(META_sync, &mp->flag);
+	write_metapage(mp);
+}
+
+static inline void discard_metapage(struct metapage *mp)
+{
+	clear_bit(META_dirty, &mp->flag);
+	set_bit(META_discard, &mp->flag);
+	release_metapage(mp);
+}
+
+/*
+ * This routines invalidate all pages for an extent.
+ */
+extern void __invalidate_metapages(struct inode *, s64, int);
+#define invalidate_pxd_metapages(ip, pxd) \
+	__invalidate_metapages((ip), addressPXD(&(pxd)), lengthPXD(&(pxd)))
+#define invalidate_dxd_metapages(ip, dxd) \
+	__invalidate_metapages((ip), addressDXD(&(dxd)), lengthDXD(&(dxd)))
+
+/*
+ * This one uses mp_list to invalidate all pages for an inode
+ */
+extern void invalidate_inode_metapages(struct inode *inode);
+#endif				/* _H_JFS_METAPAGE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_mount.c linux-2.4.20/fs/jfs/jfs_mount.c
--- linux-2.4.19/fs/jfs/jfs_mount.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_mount.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,520 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+
+/*
+ * Module: jfs_mount.c
+ *
+ * note: file system in transition to aggregate/fileset:
+ *
+ * file system mount is interpreted as the mount of aggregate, 
+ * if not already mounted, and mount of the single/only fileset in 
+ * the aggregate;
+ *
+ * a file system/aggregate is represented by an internal inode
+ * (aka mount inode) initialized with aggregate superblock;
+ * each vfs represents a fileset, and points to its "fileset inode 
+ * allocation map inode" (aka fileset inode):
+ * (an aggregate itself is structured recursively as a filset: 
+ * an internal vfs is constructed and points to its "fileset inode 
+ * allocation map inode" (aka aggregate inode) where each inode 
+ * represents a fileset inode) so that inode number is mapped to 
+ * on-disk inode in uniform way at both aggregate and fileset level;
+ *
+ * each vnode/inode of a fileset is linked to its vfs (to facilitate
+ * per fileset inode operations, e.g., unmount of a fileset, etc.);
+ * each inode points to the mount inode (to facilitate access to
+ * per aggregate information, e.g., block size, etc.) as well as
+ * its file set inode.
+ *
+ *   aggregate 
+ *   ipmnt
+ *   mntvfs -> fileset ipimap+ -> aggregate ipbmap -> aggregate ipaimap;
+ *             fileset vfs     -> vp(1) <-> ... <-> vp(n) <->vproot;
+ */
+
+#include <linux/fs.h>
+#include <linux/locks.h>
+
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_superblock.h"
+#include "jfs_dmap.h"
+#include "jfs_imap.h"
+#include "jfs_metapage.h"
+#include "jfs_debug.h"
+
+
+/*
+ * forward references
+ */
+static int chkSuper(struct super_block *);
+static int logMOUNT(struct super_block *sb);
+
+/*
+ * NAME:	jfs_mount(sb)
+ *
+ * FUNCTION:	vfs_mount()
+ *
+ * PARAMETER:	sb	- super block
+ *
+ * RETURN:	EBUSY	- device already mounted or open for write
+ *		EBUSY	- cvrdvp already mounted;
+ *		EBUSY	- mount table full
+ *		ENOTDIR	- cvrdvp not directory on a device mount
+ *		ENXIO	- device open failure
+ */
+int jfs_mount(struct super_block *sb)
+{
+	int rc = 0;		/* Return code          */
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	struct inode *ipaimap = NULL;
+	struct inode *ipaimap2 = NULL;
+	struct inode *ipimap = NULL;
+	struct inode *ipbmap = NULL;
+
+	jFYI(1, ("\nMount JFS\n"));
+
+	/*
+	 * read/validate superblock 
+	 * (initialize mount inode from the superblock)
+	 */
+	if ((rc = chkSuper(sb))) {
+		goto errout20;
+	}
+
+	ipaimap = diReadSpecial(sb, AGGREGATE_I, 0);
+	if (ipaimap == NULL) {
+		jERROR(1, ("jfs_mount: Faild to read AGGREGATE_I\n"));
+		rc = EIO;
+		goto errout20;
+	}
+	sbi->ipaimap = ipaimap;
+
+	jFYI(1, ("jfs_mount: ipaimap:0x%p\n", ipaimap));
+
+	/*
+	 * initialize aggregate inode allocation map
+	 */
+	if ((rc = diMount(ipaimap))) {
+		jERROR(1,
+		       ("jfs_mount: diMount(ipaimap) failed w/rc = %d\n",
+			rc));
+		goto errout21;
+	}
+
+	/*
+	 * open aggregate block allocation map
+	 */
+	ipbmap = diReadSpecial(sb, BMAP_I, 0);
+	if (ipbmap == NULL) {
+		rc = EIO;
+		goto errout22;
+	}
+
+	jFYI(1, ("jfs_mount: ipbmap:0x%p\n", ipbmap));
+
+	sbi->ipbmap = ipbmap;
+
+	/*
+	 * initialize aggregate block allocation map
+	 */
+	if ((rc = dbMount(ipbmap))) {
+		jERROR(1, ("jfs_mount: dbMount failed w/rc = %d\n", rc));
+		goto errout22;
+	}
+
+	/*
+	 * open the secondary aggregate inode allocation map
+	 *
+	 * This is a duplicate of the aggregate inode allocation map.
+	 *
+	 * hand craft a vfs in the same fashion as we did to read ipaimap.
+	 * By adding INOSPEREXT (32) to the inode number, we are telling
+	 * diReadSpecial that we are reading from the secondary aggregate
+	 * inode table.  This also creates a unique entry in the inode hash
+	 * table.
+	 */
+	if ((sbi->mntflag & JFS_BAD_SAIT) == 0) {
+		ipaimap2 = diReadSpecial(sb, AGGREGATE_I, 1);
+		if (ipaimap2 == 0) {
+			jERROR(1,
+			       ("jfs_mount: Faild to read AGGREGATE_I\n"));
+			rc = EIO;
+			goto errout35;
+		}
+		sbi->ipaimap2 = ipaimap2;
+
+		jFYI(1, ("jfs_mount: ipaimap2:0x%p\n", ipaimap2));
+
+		/*
+		 * initialize secondary aggregate inode allocation map
+		 */
+		if ((rc = diMount(ipaimap2))) {
+			jERROR(1,
+			       ("jfs_mount: diMount(ipaimap2) failed, rc = %d\n",
+				rc));
+			goto errout35;
+		}
+	} else
+		/* Secondary aggregate inode table is not valid */
+		sbi->ipaimap2 = 0;
+
+	/*
+	 *      mount (the only/single) fileset
+	 */
+	/*
+	 * open fileset inode allocation map (aka fileset inode)
+	 */
+	ipimap = diReadSpecial(sb, FILESYSTEM_I, 0);
+	if (ipimap == NULL) {
+		jERROR(1, ("jfs_mount: Failed to read FILESYSTEM_I\n"));
+		/* open fileset secondary inode allocation map */
+		rc = EIO;
+		goto errout40;
+	}
+	jFYI(1, ("jfs_mount: ipimap:0x%p\n", ipimap));
+
+	/* map further access of per fileset inodes by the fileset inode */
+	sbi->ipimap = ipimap;
+
+	/* initialize fileset inode allocation map */
+	if ((rc = diMount(ipimap))) {
+		jERROR(1, ("jfs_mount: diMount failed w/rc = %d\n", rc));
+		goto errout41;
+	}
+
+	jFYI(1, ("Mount JFS Complete.\n"));
+	goto out;
+
+	/*
+	 *      unwind on error
+	 */
+//errout42: /* close fileset inode allocation map */
+	diUnmount(ipimap, 1);
+
+      errout41:		/* close fileset inode allocation map inode */
+	diFreeSpecial(ipimap);
+
+      errout40:		/* fileset closed */
+
+	/* close secondary aggregate inode allocation map */
+	if (ipaimap2) {
+		diUnmount(ipaimap2, 1);
+		diFreeSpecial(ipaimap2);
+	}
+
+      errout35:
+
+	/* close aggregate block allocation map */
+	dbUnmount(ipbmap, 1);
+	diFreeSpecial(ipbmap);
+
+      errout22:		/* close aggregate inode allocation map */
+
+	diUnmount(ipaimap, 1);
+
+      errout21:		/* close aggregate inodes */
+	diFreeSpecial(ipaimap);
+      errout20:		/* aggregate closed */
+
+      out:
+
+	if (rc) {
+		jERROR(1, ("Mount JFS Failure: %d\n", rc));
+	}
+	return rc;
+}
+
+/*
+ * NAME:	jfs_mount_rw(sb, remount)
+ *
+ * FUNCTION:	Completes read-write mount, or remounts read-only volume
+ *		as read-write
+ */
+int jfs_mount_rw(struct super_block *sb, int remount)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(sb);  
+	struct jfs_log *log;
+	int rc;
+
+	/*
+	 * If we are re-mounting a previously read-only volume, we want to
+	 * re-read the inode and block maps, since fsck.jfs may have updated
+	 * them.
+	 */
+	if (remount) {
+		if (chkSuper(sb) || (sbi->state != FM_CLEAN))
+			return -EINVAL;
+
+		truncate_inode_pages(sbi->ipimap->i_mapping, 0);
+		truncate_inode_pages(sbi->ipbmap->i_mapping, 0);
+		diUnmount(sbi->ipimap, 1);
+		if ((rc = diMount(sbi->ipimap))) {
+			jERROR(1,("jfs_mount_rw: diMount failed!\n"));
+			return rc;
+		}
+
+		dbUnmount(sbi->ipbmap, 1);
+		if ((rc = dbMount(sbi->ipbmap))) {
+			jERROR(1,("jfs_mount_rw: dbMount failed!\n"));
+			return rc;
+		}
+	}
+
+	/*
+	 * open/initialize log
+	 */
+	if ((rc = lmLogOpen(sb, &log)))
+		return rc;
+
+	JFS_SBI(sb)->log = log;
+
+	/*
+	 * update file system superblock;
+	 */
+	if ((rc = updateSuper(sb, FM_MOUNT))) {
+		jERROR(1,
+		       ("jfs_mount: updateSuper failed w/rc = %d\n", rc));
+		lmLogClose(sb, log);
+		JFS_SBI(sb)->log = 0;
+		return rc;
+	}
+
+	/*
+	 * write MOUNT log record of the file system
+	 */
+	logMOUNT(sb);
+
+	return rc;
+}
+
+/*
+ *	chkSuper()
+ *
+ * validate the superblock of the file system to be mounted and 
+ * get the file system parameters.
+ *
+ * returns
+ *	0 with fragsize set if check successful
+ *	error code if not successful
+ */
+static int chkSuper(struct super_block *sb)
+{
+	int rc = 0;
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	struct jfs_superblock *j_sb;
+	struct buffer_head *bh;
+	int AIM_bytesize, AIT_bytesize;
+	int expected_AIM_bytesize, expected_AIT_bytesize;
+	s64 AIM_byte_addr, AIT_byte_addr, fsckwsp_addr;
+	s64 byte_addr_diff0, byte_addr_diff1;
+	s32 bsize;
+
+	if ((rc = readSuper(sb, &bh)))
+		return rc;
+	j_sb = (struct jfs_superblock *)bh->b_data;
+
+	/*
+	 * validate superblock
+	 */
+	/* validate fs signature */
+	if (strncmp(j_sb->s_magic, JFS_MAGIC, 4) ||
+	    j_sb->s_version > cpu_to_le32(JFS_VERSION)) {
+		//rc = EFORMAT;
+		rc = EINVAL;
+		goto out;
+	}
+
+	bsize = le32_to_cpu(j_sb->s_bsize);
+#ifdef _JFS_4K
+	if (bsize != PSIZE) {
+		jERROR(1, ("Currently only 4K block size supported!\n"));
+		rc = EINVAL;
+		goto out;
+	}
+#endif				/* _JFS_4K */
+
+	jFYI(1, ("superblock: flag:0x%08x state:0x%08x size:0x%Lx\n",
+		 le32_to_cpu(j_sb->s_flag), le32_to_cpu(j_sb->s_state),
+		 (unsigned long long) le64_to_cpu(j_sb->s_size)));
+
+	/* validate the descriptors for Secondary AIM and AIT */
+	if ((j_sb->s_flag & cpu_to_le32(JFS_BAD_SAIT)) !=
+	    cpu_to_le32(JFS_BAD_SAIT)) {
+		expected_AIM_bytesize = 2 * PSIZE;
+		AIM_bytesize = lengthPXD(&(j_sb->s_aim2)) * bsize;
+		expected_AIT_bytesize = 4 * PSIZE;
+		AIT_bytesize = lengthPXD(&(j_sb->s_ait2)) * bsize;
+		AIM_byte_addr = addressPXD(&(j_sb->s_aim2)) * bsize;
+		AIT_byte_addr = addressPXD(&(j_sb->s_ait2)) * bsize;
+		byte_addr_diff0 = AIT_byte_addr - AIM_byte_addr;
+		fsckwsp_addr = addressPXD(&(j_sb->s_fsckpxd)) * bsize;
+		byte_addr_diff1 = fsckwsp_addr - AIT_byte_addr;
+		if ((AIM_bytesize != expected_AIM_bytesize) ||
+		    (AIT_bytesize != expected_AIT_bytesize) ||
+		    (byte_addr_diff0 != AIM_bytesize) ||
+		    (byte_addr_diff1 <= AIT_bytesize))
+			j_sb->s_flag |= cpu_to_le32(JFS_BAD_SAIT);
+	}
+
+	if ((j_sb->s_flag & cpu_to_le32(JFS_GROUPCOMMIT)) !=
+	    cpu_to_le32(JFS_GROUPCOMMIT))
+		j_sb->s_flag |= cpu_to_le32(JFS_GROUPCOMMIT);
+	jFYI(0, ("superblock: flag:0x%08x state:0x%08x size:0x%Lx\n",
+		 le32_to_cpu(j_sb->s_flag), le32_to_cpu(j_sb->s_state),
+		 (unsigned long long) le64_to_cpu(j_sb->s_size)));
+
+	/* validate fs state */
+	if (j_sb->s_state != cpu_to_le32(FM_CLEAN) &&
+	    !(sb->s_flags & MS_RDONLY)) {
+		jERROR(1,
+		       ("jfs_mount: Mount Failure: File System Dirty.\n"));
+		rc = EINVAL;
+		goto out;
+	}
+
+	sbi->state = le32_to_cpu(j_sb->s_state);
+	sbi->mntflag = le32_to_cpu(j_sb->s_flag);
+
+	/*
+	 * JFS always does I/O by 4K pages.  Don't tell the buffer cache
+	 * that we use anything else (leave s_blocksize alone).
+	 */
+	sbi->bsize = bsize;
+	sbi->l2bsize = le16_to_cpu(j_sb->s_l2bsize);
+
+	/*
+	 * For now, ignore s_pbsize, l2bfactor.  All I/O going through buffer
+	 * cache.
+	 */
+	sbi->nbperpage = PSIZE >> sbi->l2bsize;
+	sbi->l2nbperpage = L2PSIZE - sbi->l2bsize;
+	sbi->l2niperblk = sbi->l2bsize - L2DISIZE;
+	if (sbi->mntflag & JFS_INLINELOG)
+		sbi->logpxd = j_sb->s_logpxd;
+	else {
+		sbi->logdev = to_kdev_t(le32_to_cpu(j_sb->s_logdev));
+		memcpy(sbi->uuid, j_sb->s_uuid, sizeof(sbi->uuid));
+		memcpy(sbi->loguuid, j_sb->s_loguuid, sizeof(sbi->uuid));
+	}
+	sbi->fsckpxd = j_sb->s_fsckpxd;
+	sbi->ait2 = j_sb->s_ait2;
+
+      out:
+	brelse(bh);
+	return rc;
+}
+
+
+/*
+ *	updateSuper()
+ *
+ * update synchronously superblock if it is mounted read-write.
+ */
+int updateSuper(struct super_block *sb, uint state)
+{
+	struct jfs_superblock *j_sb;
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	struct buffer_head *bh;
+	int rc;
+
+	/*
+	 * Only fsck can fix dirty state
+	 */
+	if (sbi->state == FM_DIRTY)
+		return 0;
+
+	if ((rc = readSuper(sb, &bh)))
+		return rc;
+
+	j_sb = (struct jfs_superblock *)bh->b_data;
+
+	j_sb->s_state = cpu_to_le32(state);
+	sbi->state = state;
+
+	if (state == FM_MOUNT) {
+		/* record log's dev_t and mount serial number */
+		j_sb->s_logdev = cpu_to_le32(sbi->log->bdev->bd_dev);
+		j_sb->s_logserial = cpu_to_le32(sbi->log->serial);
+	} else if (state == FM_CLEAN) {
+		/*
+		 * If this volume is shared with OS/2, OS/2 will need to
+		 * recalculate DASD usage, since we don't deal with it.
+		 */
+		if (j_sb->s_flag & cpu_to_le32(JFS_DASD_ENABLED))
+			j_sb->s_flag |= cpu_to_le32(JFS_DASD_PRIME);
+	}
+
+	mark_buffer_dirty(bh);
+	ll_rw_block(WRITE, 1, &bh);
+	wait_on_buffer(bh);
+	brelse(bh);
+
+	return 0;
+}
+
+
+/*
+ *	readSuper()
+ *
+ * read superblock by raw sector address
+ */
+int readSuper(struct super_block *sb, struct buffer_head **bpp)
+{
+	/* read in primary superblock */
+	*bpp = sb_bread(sb, SUPER1_OFF >> sb->s_blocksize_bits);
+	if (*bpp)
+		return 0;
+
+	/* read in secondary/replicated superblock */
+	*bpp = sb_bread(sb, SUPER2_OFF >> sb->s_blocksize_bits);
+	if (*bpp)
+		return 0;
+
+	return -EIO;
+}
+
+
+/*
+ *	logMOUNT()
+ *
+ * function: write a MOUNT log record for file system.
+ *
+ * MOUNT record keeps logredo() from processing log records
+ * for this file system past this point in log.
+ * it is harmless if mount fails.
+ *
+ * note: MOUNT record is at aggregate level, not at fileset level, 
+ * since log records of previous mounts of a fileset
+ * (e.g., AFTER record of extent allocation) have to be processed 
+ * to update block allocation map at aggregate level.
+ */
+static int logMOUNT(struct super_block *sb)
+{
+	struct jfs_log *log = JFS_SBI(sb)->log;
+	struct lrd lrd;
+
+	lrd.logtid = 0;
+	lrd.backchain = 0;
+	lrd.type = cpu_to_le16(LOG_MOUNT);
+	lrd.length = 0;
+	lrd.aggregate = cpu_to_le32(kdev_t_to_nr(sb->s_dev));
+	lmLog(log, NULL, &lrd, NULL);
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_superblock.h linux-2.4.20/fs/jfs/jfs_superblock.h
--- linux-2.4.19/fs/jfs/jfs_superblock.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_superblock.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,112 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+#ifndef	_H_JFS_SUPERBLOCK
+#define _H_JFS_SUPERBLOCK
+
+/*
+ * make the magic number something a human could read
+ */
+#define JFS_MAGIC 	"JFS1"	/* Magic word */
+
+#define JFS_VERSION	2	/* Version number: Version 2 */
+
+#define LV_NAME_SIZE	11	/* MUST BE 11 for OS/2 boot sector */
+
+/* 
+ *	aggregate superblock 
+ *
+ * The name superblock is too close to super_block, so the name has been
+ * changed to jfs_superblock.  The utilities are still using the old name.
+ */
+struct jfs_superblock {
+	char s_magic[4];	/* 4: magic number */
+	u32 s_version;		/* 4: version number */
+
+	s64 s_size;		/* 8: aggregate size in hardware/LVM blocks;
+				 * VFS: number of blocks
+				 */
+	s32 s_bsize;		/* 4: aggregate block size in bytes; 
+				 * VFS: fragment size
+				 */
+	s16 s_l2bsize;		/* 2: log2 of s_bsize */
+	s16 s_l2bfactor;	/* 2: log2(s_bsize/hardware block size) */
+	s32 s_pbsize;		/* 4: hardware/LVM block size in bytes */
+	s16 s_l2pbsize;		/* 2: log2 of s_pbsize */
+	s16 pad;		/* 2: padding necessary for alignment */
+
+	u32 s_agsize;		/* 4: allocation group size in aggr. blocks */
+
+	u32 s_flag;		/* 4: aggregate attributes:
+				 *    see jfs_filsys.h
+				 */
+	u32 s_state;		/* 4: mount/unmount/recovery state: 
+				 *    see jfs_filsys.h
+				 */
+	s32 s_compress;		/* 4: > 0 if data compression */
+
+	pxd_t s_ait2;		/* 8: first extent of secondary
+				 *    aggregate inode table
+				 */
+
+	pxd_t s_aim2;		/* 8: first extent of secondary
+				 *    aggregate inode map
+				 */
+	u32 s_logdev;		/* 4: device address of log */
+	s32 s_logserial;	/* 4: log serial number at aggregate mount */
+	pxd_t s_logpxd;		/* 8: inline log extent */
+
+	pxd_t s_fsckpxd;	/* 8: inline fsck work space extent */
+
+	struct timestruc_t s_time;	/* 8: time last updated */
+
+	s32 s_fsckloglen;	/* 4: Number of filesystem blocks reserved for
+				 *    the fsck service log.  
+				 *    N.B. These blocks are divided among the
+				 *         versions kept.  This is not a per
+				 *         version size.
+				 *    N.B. These blocks are included in the 
+				 *         length field of s_fsckpxd.
+				 */
+	s8 s_fscklog;		/* 1: which fsck service log is most recent
+				 *    0 => no service log data yet
+				 *    1 => the first one
+				 *    2 => the 2nd one
+				 */
+	char s_fpack[11];	/* 11: file system volume name 
+				 *     N.B. This must be 11 bytes to
+				 *          conform with the OS/2 BootSector
+				 *          requirements
+				 *          Only used when s_version is 1
+				 */
+
+	/* extendfs() parameter under s_state & FM_EXTENDFS */
+	s64 s_xsize;		/* 8: extendfs s_size */
+	pxd_t s_xfsckpxd;	/* 8: extendfs fsckpxd */
+	pxd_t s_xlogpxd;	/* 8: extendfs logpxd */
+	/* - 128 byte boundary - */
+
+	char s_uuid[16];	/* 16: 128-bit uuid for volume */
+	char s_label[16];	/* 16: volume label */
+	char s_loguuid[16];	/* 16: 128-bit uuid for log device */
+
+};
+
+extern int readSuper(struct super_block *, struct buffer_head **);
+extern int updateSuper(struct super_block *, uint);
+
+#endif /*_H_JFS_SUPERBLOCK */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_txnmgr.c linux-2.4.20/fs/jfs/jfs_txnmgr.c
--- linux-2.4.19/fs/jfs/jfs_txnmgr.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_txnmgr.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,3093 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *
+ *   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
+ */
+
+/*
+ *      jfs_txnmgr.c: transaction manager
+ *
+ * notes:
+ * transaction starts with txBegin() and ends with txCommit()
+ * or txAbort().
+ *
+ * tlock is acquired at the time of update;
+ * (obviate scan at commit time for xtree and dtree)
+ * tlock and mp points to each other;
+ * (no hashlist for mp -> tlock).
+ *
+ * special cases:
+ * tlock on in-memory inode:
+ * in-place tlock in the in-memory inode itself;
+ * converted to page lock by iWrite() at commit time.
+ *
+ * tlock during write()/mmap() under anonymous transaction (tid = 0):
+ * transferred (?) to transaction at commit time.
+ *
+ * use the page itself to update allocation maps
+ * (obviate intermediate replication of allocation/deallocation data)
+ * hold on to mp+lock thru update of maps
+ */
+
+
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/smp_lock.h>
+#include <linux/completion.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_metapage.h"
+#include "jfs_dinode.h"
+#include "jfs_imap.h"
+#include "jfs_dmap.h"
+#include "jfs_superblock.h"
+#include "jfs_debug.h"
+
+/*
+ *      transaction management structures
+ */
+static struct {
+	/* tblock */
+	int freetid;		/* index of a free tid structure */
+	wait_queue_head_t freewait;	/* eventlist of free tblock */
+
+	/* tlock */
+	int freelock;		/* index first free lock word */
+	wait_queue_head_t freelockwait;	/* eventlist of free tlock */
+	wait_queue_head_t lowlockwait;	/* eventlist of ample tlocks */
+	int tlocksInUse;	/* Number of tlocks in use */
+	spinlock_t LazyLock;	/* synchronize sync_queue & unlock_queue */
+/*	struct tblock *sync_queue; * Transactions waiting for data sync */
+	struct tblock *unlock_queue;	/* Txns waiting to be released */
+	struct tblock *unlock_tail;	/* Tail of unlock_queue */
+	struct list_head anon_list;	/* inodes having anonymous txns */
+	struct list_head anon_list2;	/* inodes having anonymous txns
+					   that couldn't be sync'ed */
+} TxAnchor;
+
+static int nTxBlock = 512;	/* number of transaction blocks */
+struct tblock *TxBlock;	        /* transaction block table */
+
+static int nTxLock = 4096;	/* number of transaction locks */
+static int TxLockLWM = 4096*.4;	/* Low water mark for number of txLocks used */
+static int TxLockHWM = 4096*.8;	/* High water mark for number of txLocks used */
+struct tlock *TxLock;           /* transaction lock table */
+static int TlocksLow = 0;	/* Indicates low number of available tlocks */
+
+
+/*
+ *      transaction management lock
+ */
+static spinlock_t jfsTxnLock = SPIN_LOCK_UNLOCKED;
+
+#define TXN_LOCK()              spin_lock(&jfsTxnLock)
+#define TXN_UNLOCK()            spin_unlock(&jfsTxnLock)
+
+#define LAZY_LOCK_INIT()	spin_lock_init(&TxAnchor.LazyLock);
+#define LAZY_LOCK(flags)	spin_lock_irqsave(&TxAnchor.LazyLock, flags)
+#define LAZY_UNLOCK(flags) spin_unlock_irqrestore(&TxAnchor.LazyLock, flags)
+
+DECLARE_WAIT_QUEUE_HEAD(jfs_sync_thread_wait);
+DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait);
+
+/*
+ * Retry logic exist outside these macros to protect from spurrious wakeups.
+ */
+static inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	add_wait_queue(event, &wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	TXN_UNLOCK();
+	schedule();
+	current->state = TASK_RUNNING;
+	remove_wait_queue(event, &wait);
+}
+
+#define TXN_SLEEP(event)\
+{\
+	TXN_SLEEP_DROP_LOCK(event);\
+	TXN_LOCK();\
+}
+
+#define TXN_WAKEUP(event) wake_up_all(event)
+
+
+/*
+ *      statistics
+ */
+struct {
+	tid_t maxtid;		/* 4: biggest tid ever used */
+	lid_t maxlid;		/* 4: biggest lid ever used */
+	int ntid;		/* 4: # of transactions performed */
+	int nlid;		/* 4: # of tlocks acquired */
+	int waitlock;		/* 4: # of tlock wait */
+} stattx;
+
+
+/*
+ * external references
+ */
+extern int lmGroupCommit(struct jfs_log * log, struct tblock * tblk);
+extern void lmSync(struct jfs_log *);
+extern int jfs_commit_inode(struct inode *, int);
+extern int jfs_stop_threads;
+
+struct task_struct *jfsCommitTask;
+extern struct completion jfsIOwait;
+
+/*
+ * forward references
+ */
+int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	  struct tlock * tlck, struct commit * cd);
+int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	    struct tlock * tlck);
+void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	   struct tlock * tlck);
+void inlineLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	       struct tlock * tlck);
+void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	    struct tlock * tlck);
+void txAbortCommit(struct commit * cd, int exval);
+static void txAllocPMap(struct inode *ip, struct maplock * maplock,
+			struct tblock * tblk);
+void txForce(struct tblock * tblk);
+static int txLog(struct jfs_log * log, struct tblock * tblk, struct commit * cd);
+int txMoreLock(void);
+static void txUpdateMap(struct tblock * tblk);
+static void txRelease(struct tblock * tblk);
+void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	   struct tlock * tlck);
+static void LogSyncRelease(struct metapage * mp);
+
+/*
+ *              transaction block/lock management
+ *              ---------------------------------
+ */
+
+/*
+ * Get a transaction lock from the free list.  If the number in use is
+ * greater than the high water mark, wake up the sync daemon.  This should
+ * free some anonymous transaction locks.  (TXN_LOCK must be held.)
+ */
+static lid_t txLockAlloc(void)
+{
+	lid_t lid;
+
+	while (!(lid = TxAnchor.freelock))
+		TXN_SLEEP(&TxAnchor.freelockwait);
+	TxAnchor.freelock = TxLock[lid].next;
+	HIGHWATERMARK(stattx.maxlid, lid);
+	if ((++TxAnchor.tlocksInUse > TxLockHWM) && (TlocksLow == 0)) {
+		jEVENT(0,("txLockAlloc TlocksLow\n"));
+		TlocksLow = 1;
+		wake_up(&jfs_sync_thread_wait);
+	}
+
+	return lid;
+}
+
+static void txLockFree(lid_t lid)
+{
+	TxLock[lid].next = TxAnchor.freelock;
+	TxAnchor.freelock = lid;
+	TxAnchor.tlocksInUse--;
+	if (TlocksLow && (TxAnchor.tlocksInUse < TxLockLWM)) {
+		jEVENT(0,("txLockFree TlocksLow no more\n"));
+		TlocksLow = 0;
+		TXN_WAKEUP(&TxAnchor.lowlockwait);
+	}
+	TXN_WAKEUP(&TxAnchor.freelockwait);
+}
+
+/*
+ * NAME:        txInit()
+ *
+ * FUNCTION:    initialize transaction management structures
+ *
+ * RETURN:
+ *
+ * serialization: single thread at jfs_init()
+ */
+int txInit(void)
+{
+	int k, size;
+
+	/*
+	 * initialize transaction block (tblock) table
+	 *
+	 * transaction id (tid) = tblock index
+	 * tid = 0 is reserved.
+	 */
+	size = sizeof(struct tblock) * nTxBlock;
+	TxBlock = (struct tblock *) vmalloc(size);
+	if (TxBlock == NULL)
+		return ENOMEM;
+
+	for (k = 1; k < nTxBlock - 1; k++) {
+		TxBlock[k].next = k + 1;
+		init_waitqueue_head(&TxBlock[k].gcwait);
+		init_waitqueue_head(&TxBlock[k].waitor);
+	}
+	TxBlock[k].next = 0;
+	init_waitqueue_head(&TxBlock[k].gcwait);
+	init_waitqueue_head(&TxBlock[k].waitor);
+
+	TxAnchor.freetid = 1;
+	init_waitqueue_head(&TxAnchor.freewait);
+
+	stattx.maxtid = 1;	/* statistics */
+
+	/*
+	 * initialize transaction lock (tlock) table
+	 *
+	 * transaction lock id = tlock index
+	 * tlock id = 0 is reserved.
+	 */
+	size = sizeof(struct tlock) * nTxLock;
+	TxLock = (struct tlock *) vmalloc(size);
+	if (TxLock == NULL) {
+		vfree(TxBlock);
+		return ENOMEM;
+	}
+
+	/* initialize tlock table */
+	for (k = 1; k < nTxLock - 1; k++)
+		TxLock[k].next = k + 1;
+	TxLock[k].next = 0;
+	init_waitqueue_head(&TxAnchor.freelockwait);
+	init_waitqueue_head(&TxAnchor.lowlockwait);
+
+	TxAnchor.freelock = 1;
+	TxAnchor.tlocksInUse = 0;
+	INIT_LIST_HEAD(&TxAnchor.anon_list);
+	INIT_LIST_HEAD(&TxAnchor.anon_list2);
+
+	stattx.maxlid = 1;	/* statistics */
+
+	return 0;
+}
+
+/*
+ * NAME:        txExit()
+ *
+ * FUNCTION:    clean up when module is unloaded
+ */
+void txExit(void)
+{
+	vfree(TxLock);
+	TxLock = 0;
+	vfree(TxBlock);
+	TxBlock = 0;
+}
+
+
+/*
+ * NAME:        txBegin()
+ *
+ * FUNCTION:    start a transaction.
+ *
+ * PARAMETER:   sb	- superblock
+ *              flag	- force for nested tx;
+ *
+ * RETURN:	tid	- transaction id
+ *
+ * note: flag force allows to start tx for nested tx
+ * to prevent deadlock on logsync barrier;
+ */
+tid_t txBegin(struct super_block *sb, int flag)
+{
+	tid_t t;
+	struct tblock *tblk;
+	struct jfs_log *log;
+
+	jFYI(1, ("txBegin: flag = 0x%x\n", flag));
+	log = JFS_SBI(sb)->log;
+
+	TXN_LOCK();
+
+      retry:
+	if (!(flag & COMMIT_FORCE)) {
+		/*
+		 * synchronize with logsync barrier
+		 */
+		if (test_bit(log_SYNCBARRIER, &log->flag) ||
+		    test_bit(log_QUIESCE, &log->flag)) {
+			TXN_SLEEP(&log->syncwait);
+			goto retry;
+		}
+	}
+	if (flag == 0) {
+		/*
+		 * Don't begin transaction if we're getting starved for tlocks
+		 * unless COMMIT_FORCE or COMMIT_INODE (which may ultimately
+		 * free tlocks)
+		 */
+		if (TlocksLow) {
+			TXN_SLEEP(&TxAnchor.lowlockwait);
+			goto retry;
+		}
+	}
+
+	/*
+	 * allocate transaction id/block
+	 */
+	if ((t = TxAnchor.freetid) == 0) {
+		jFYI(1, ("txBegin: waiting for free tid\n"));
+		TXN_SLEEP(&TxAnchor.freewait);
+		goto retry;
+	}
+
+	tblk = tid_to_tblock(t);
+
+	if ((tblk->next == 0) && (current != jfsCommitTask)) {
+		/* Save one tblk for jfsCommit thread */
+		jFYI(1, ("txBegin: waiting for free tid\n"));
+		TXN_SLEEP(&TxAnchor.freewait);
+		goto retry;
+	}
+
+	TxAnchor.freetid = tblk->next;
+
+	/*
+	 * initialize transaction
+	 */
+
+	/*
+	 * We can't zero the whole thing or we screw up another thread being
+	 * awakened after sleeping on tblk->waitor
+	 *
+	 * memset(tblk, 0, sizeof(struct tblock));
+	 */
+	tblk->next = tblk->last = tblk->xflag = tblk->flag = tblk->lsn = 0;
+
+	tblk->sb = sb;
+	++log->logtid;
+	tblk->logtid = log->logtid;
+
+	++log->active;
+
+	HIGHWATERMARK(stattx.maxtid, t);	/* statistics */
+	INCREMENT(stattx.ntid);	/* statistics */
+
+	TXN_UNLOCK();
+
+	jFYI(1, ("txBegin: returning tid = %d\n", t));
+
+	return t;
+}
+
+
+/*
+ * NAME:        txBeginAnon()
+ *
+ * FUNCTION:    start an anonymous transaction.
+ *		Blocks if logsync or available tlocks are low to prevent
+ *		anonymous tlocks from depleting supply.
+ *
+ * PARAMETER:   sb	- superblock
+ *
+ * RETURN:	none
+ */
+void txBeginAnon(struct super_block *sb)
+{
+	struct jfs_log *log;
+
+	log = JFS_SBI(sb)->log;
+
+	TXN_LOCK();
+
+      retry:
+	/*
+	 * synchronize with logsync barrier
+	 */
+	if (test_bit(log_SYNCBARRIER, &log->flag) ||
+	    test_bit(log_QUIESCE, &log->flag)) {
+		TXN_SLEEP(&log->syncwait);
+		goto retry;
+	}
+
+	/*
+	 * Don't begin transaction if we're getting starved for tlocks
+	 */
+	if (TlocksLow) {
+		TXN_SLEEP(&TxAnchor.lowlockwait);
+		goto retry;
+	}
+	TXN_UNLOCK();
+}
+
+
+/*
+ *      txEnd()
+ *
+ * function: free specified transaction block.
+ *
+ *      logsync barrier processing:
+ *
+ * serialization:
+ */
+void txEnd(tid_t tid)
+{
+	struct tblock *tblk = tid_to_tblock(tid);
+	struct jfs_log *log;
+
+	jFYI(1, ("txEnd: tid = %d\n", tid));
+	TXN_LOCK();
+
+	/*
+	 * wakeup transactions waiting on the page locked
+	 * by the current transaction
+	 */
+	TXN_WAKEUP(&tblk->waitor);
+
+	log = JFS_SBI(tblk->sb)->log;
+
+	/*
+	 * Lazy commit thread can't free this guy until we mark it UNLOCKED,
+	 * otherwise, we would be left with a transaction that may have been
+	 * reused.
+	 *
+	 * Lazy commit thread will turn off tblkGC_LAZY before calling this
+	 * routine.
+	 */
+	if (tblk->flag & tblkGC_LAZY) {
+		jFYI(1,
+		     ("txEnd called w/lazy tid: %d, tblk = 0x%p\n",
+		      tid, tblk));
+		TXN_UNLOCK();
+
+		spin_lock_irq(&log->gclock);	// LOGGC_LOCK
+		tblk->flag |= tblkGC_UNLOCKED;
+		spin_unlock_irq(&log->gclock);	// LOGGC_UNLOCK
+		return;
+	}
+
+	jFYI(1, ("txEnd: tid: %d, tblk = 0x%p\n", tid, tblk));
+
+	assert(tblk->next == 0);
+
+	/*
+	 * insert tblock back on freelist
+	 */
+	tblk->next = TxAnchor.freetid;
+	TxAnchor.freetid = tid;
+
+	/*
+	 * mark the tblock not active
+	 */
+	--log->active;
+
+	/*
+	 * synchronize with logsync barrier
+	 */
+	if (test_bit(log_SYNCBARRIER, &log->flag) && log->active == 0) {
+		/* forward log syncpt */
+		/* lmSync(log); */
+
+		jFYI(1, ("     log barrier off: 0x%x\n", log->lsn));
+
+		/* enable new transactions start */
+		clear_bit(log_SYNCBARRIER, &log->flag);
+
+		/* wakeup all waitors for logsync barrier */
+		TXN_WAKEUP(&log->syncwait);
+	}
+
+	/*
+	 * wakeup all waitors for a free tblock
+	 */
+	TXN_WAKEUP(&TxAnchor.freewait);
+
+	TXN_UNLOCK();
+	jFYI(1, ("txEnd: exitting\n"));
+}
+
+
+/*
+ *      txLock()
+ *
+ * function: acquire a transaction lock on the specified <mp>
+ *
+ * parameter:
+ *
+ * return:      transaction lock id
+ *
+ * serialization:
+ */
+struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
+		     int type)
+{
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	int dir_xtree = 0;
+	lid_t lid;
+	tid_t xtid;
+	struct tlock *tlck;
+	struct xtlock *xtlck;
+	struct linelock *linelock;
+	xtpage_t *p;
+	struct tblock *tblk;
+
+	assert(!test_cflag(COMMIT_Nolink, ip));
+
+	TXN_LOCK();
+
+	if (S_ISDIR(ip->i_mode) && (type & tlckXTREE) &&
+	    !(mp->xflag & COMMIT_PAGE)) {
+		/*
+		 * Directory inode is special.  It can have both an xtree tlock
+		 * and a dtree tlock associated with it.
+		 */
+		dir_xtree = 1;
+		lid = jfs_ip->xtlid;
+	} else
+		lid = mp->lid;
+
+	/* is page not locked by a transaction ? */
+	if (lid == 0)
+		goto allocateLock;
+
+	jFYI(1, ("txLock: tid:%d ip:0x%p mp:0x%p lid:%d\n",
+		 tid, ip, mp, lid));
+
+	/* is page locked by the requester transaction ? */
+	tlck = lid_to_tlock(lid);
+	if ((xtid = tlck->tid) == tid)
+		goto grantLock;
+
+	/*
+	 * is page locked by anonymous transaction/lock ?
+	 *
+	 * (page update without transaction (i.e., file write) is
+	 * locked under anonymous transaction tid = 0:
+	 * anonymous tlocks maintained on anonymous tlock list of
+	 * the inode of the page and available to all anonymous
+	 * transactions until txCommit() time at which point
+	 * they are transferred to the transaction tlock list of
+	 * the commiting transaction of the inode)
+	 */
+	if (xtid == 0) {
+		tlck->tid = tid;
+		tblk = tid_to_tblock(tid);
+		/*
+		 * The order of the tlocks in the transaction is important
+		 * (during truncate, child xtree pages must be freed before
+		 * parent's tlocks change the working map).
+		 * Take tlock off anonymous list and add to tail of
+		 * transaction list
+		 *
+		 * Note:  We really need to get rid of the tid & lid and
+		 * use list_head's.  This code is getting UGLY!
+		 */
+		if (jfs_ip->atlhead == lid) {
+			if (jfs_ip->atltail == lid) {
+				/* only anonymous txn.
+				 * Remove from anon_list
+				 */
+				list_del_init(&jfs_ip->anon_inode_list);
+			}
+			jfs_ip->atlhead = tlck->next;
+		} else {
+			lid_t last;
+			for (last = jfs_ip->atlhead;
+			     lid_to_tlock(last)->next != lid;
+			     last = lid_to_tlock(last)->next) {
+				assert(last);
+			}
+			lid_to_tlock(last)->next = tlck->next;
+			if (jfs_ip->atltail == lid)
+				jfs_ip->atltail = last;
+		}
+
+		/* insert the tlock at tail of transaction tlock list */
+
+		if (tblk->next)
+			lid_to_tlock(tblk->last)->next = lid;
+		else
+			tblk->next = lid;
+		tlck->next = 0;
+		tblk->last = lid;
+
+		goto grantLock;
+	}
+
+	goto waitLock;
+
+	/*
+	 * allocate a tlock
+	 */
+      allocateLock:
+	lid = txLockAlloc();
+	tlck = lid_to_tlock(lid);
+
+	/*
+	 * initialize tlock
+	 */
+	tlck->tid = tid;
+
+	/* mark tlock for meta-data page */
+	if (mp->xflag & COMMIT_PAGE) {
+
+		tlck->flag = tlckPAGELOCK;
+
+		/* mark the page dirty and nohomeok */
+		mark_metapage_dirty(mp);
+		atomic_inc(&mp->nohomeok);
+
+		jFYI(1,
+		     ("locking mp = 0x%p, nohomeok = %d tid = %d tlck = 0x%p\n",
+		      mp, atomic_read(&mp->nohomeok), tid, tlck));
+
+		/* if anonymous transaction, and buffer is on the group
+		 * commit synclist, mark inode to show this.  This will
+		 * prevent the buffer from being marked nohomeok for too
+		 * long a time.
+		 */
+		if ((tid == 0) && mp->lsn)
+			set_cflag(COMMIT_Synclist, ip);
+	}
+	/* mark tlock for in-memory inode */
+	else
+		tlck->flag = tlckINODELOCK;
+
+	tlck->type = 0;
+
+	/* bind the tlock and the page */
+	tlck->ip = ip;
+	tlck->mp = mp;
+	if (dir_xtree)
+		jfs_ip->xtlid = lid;
+	else
+		mp->lid = lid;
+
+	/*
+	 * enqueue transaction lock to transaction/inode
+	 */
+	/* insert the tlock at tail of transaction tlock list */
+	if (tid) {
+		tblk = tid_to_tblock(tid);
+		if (tblk->next)
+			lid_to_tlock(tblk->last)->next = lid;
+		else
+			tblk->next = lid;
+		tlck->next = 0;
+		tblk->last = lid;
+	}
+	/* anonymous transaction:
+	 * insert the tlock at head of inode anonymous tlock list
+	 */
+	else {
+		tlck->next = jfs_ip->atlhead;
+		jfs_ip->atlhead = lid;
+		if (tlck->next == 0) {
+			/* This inode's first anonymous transaction */
+			jfs_ip->atltail = lid;
+			list_add_tail(&jfs_ip->anon_inode_list,
+				      &TxAnchor.anon_list);
+		}
+	}
+
+	/* initialize type dependent area for linelock */
+	linelock = (struct linelock *) & tlck->lock;
+	linelock->next = 0;
+	linelock->flag = tlckLINELOCK;
+	linelock->maxcnt = TLOCKSHORT;
+	linelock->index = 0;
+
+	switch (type & tlckTYPE) {
+	case tlckDTREE:
+		linelock->l2linesize = L2DTSLOTSIZE;
+		break;
+
+	case tlckXTREE:
+		linelock->l2linesize = L2XTSLOTSIZE;
+
+		xtlck = (struct xtlock *) linelock;
+		xtlck->header.offset = 0;
+		xtlck->header.length = 2;
+
+		if (type & tlckNEW) {
+			xtlck->lwm.offset = XTENTRYSTART;
+		} else {
+			if (mp->xflag & COMMIT_PAGE)
+				p = (xtpage_t *) mp->data;
+			else
+				p = &jfs_ip->i_xtroot;
+			xtlck->lwm.offset =
+			    le16_to_cpu(p->header.nextindex);
+		}
+		xtlck->lwm.length = 0;	/* ! */
+		xtlck->twm.offset = 0;
+		xtlck->hwm.offset = 0;
+
+		xtlck->index = 2;
+		break;
+
+	case tlckINODE:
+		linelock->l2linesize = L2INODESLOTSIZE;
+		break;
+
+	case tlckDATA:
+		linelock->l2linesize = L2DATASLOTSIZE;
+		break;
+
+	default:
+		jERROR(1, ("UFO tlock:0x%p\n", tlck));
+	}
+
+	/*
+	 * update tlock vector
+	 */
+      grantLock:
+	tlck->type |= type;
+
+	TXN_UNLOCK();
+
+	return tlck;
+
+	/*
+	 * page is being locked by another transaction:
+	 */
+      waitLock:
+	/* Only locks on ipimap or ipaimap should reach here */
+	/* assert(jfs_ip->fileset == AGGREGATE_I); */
+	if (jfs_ip->fileset != AGGREGATE_I) {
+		jERROR(1, ("txLock: trying to lock locked page!\n"));
+		dump_mem("ip", ip, sizeof(struct inode));
+		dump_mem("mp", mp, sizeof(struct metapage));
+		dump_mem("Locker's tblk", tid_to_tblock(tid),
+			 sizeof(struct tblock));
+		dump_mem("Tlock", tlck, sizeof(struct tlock));
+		BUG();
+	}
+	INCREMENT(stattx.waitlock);	/* statistics */
+	release_metapage(mp);
+
+	jEVENT(0, ("txLock: in waitLock, tid = %d, xtid = %d, lid = %d\n",
+		   tid, xtid, lid));
+	TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor);
+	jEVENT(0, ("txLock: awakened     tid = %d, lid = %d\n", tid, lid));
+
+	return NULL;
+}
+
+
+/*
+ * NAME:        txRelease()
+ *
+ * FUNCTION:    Release buffers associated with transaction locks, but don't
+ *		mark homeok yet.  The allows other transactions to modify
+ *		buffers, but won't let them go to disk until commit record
+ *		actually gets written.
+ *
+ * PARAMETER:
+ *              tblk    -
+ *
+ * RETURN:      Errors from subroutines.
+ */
+static void txRelease(struct tblock * tblk)
+{
+	struct metapage *mp;
+	lid_t lid;
+	struct tlock *tlck;
+
+	TXN_LOCK();
+
+	for (lid = tblk->next; lid; lid = tlck->next) {
+		tlck = lid_to_tlock(lid);
+		if ((mp = tlck->mp) != NULL &&
+		    (tlck->type & tlckBTROOT) == 0) {
+			assert(mp->xflag & COMMIT_PAGE);
+			mp->lid = 0;
+		}
+	}
+
+	/*
+	 * wakeup transactions waiting on a page locked
+	 * by the current transaction
+	 */
+	TXN_WAKEUP(&tblk->waitor);
+
+	TXN_UNLOCK();
+}
+
+
+/*
+ * NAME:        txUnlock()
+ *
+ * FUNCTION:    Initiates pageout of pages modified by tid in journalled
+ *              objects and frees their lockwords.
+ */
+static void txUnlock(struct tblock * tblk)
+{
+	struct tlock *tlck;
+	struct linelock *linelock;
+	lid_t lid, next, llid, k;
+	struct metapage *mp;
+	struct jfs_log *log;
+	int difft, diffp;
+
+	jFYI(1, ("txUnlock: tblk = 0x%p\n", tblk));
+	log = JFS_SBI(tblk->sb)->log;
+
+	/*
+	 * mark page under tlock homeok (its log has been written):
+	 */
+	for (lid = tblk->next; lid; lid = next) {
+		tlck = lid_to_tlock(lid);
+		next = tlck->next;
+
+		jFYI(1, ("unlocking lid = %d, tlck = 0x%p\n", lid, tlck));
+
+		/* unbind page from tlock */
+		if ((mp = tlck->mp) != NULL &&
+		    (tlck->type & tlckBTROOT) == 0) {
+			assert(mp->xflag & COMMIT_PAGE);
+
+			/* hold buffer
+			 *
+			 * It's possible that someone else has the metapage.
+			 * The only things were changing are nohomeok, which
+			 * is handled atomically, and clsn which is protected
+			 * by the LOGSYNC_LOCK.
+			 */
+			hold_metapage(mp, 1);
+
+			assert(atomic_read(&mp->nohomeok) > 0);
+			atomic_dec(&mp->nohomeok);
+
+			/* inherit younger/larger clsn */
+			LOGSYNC_LOCK(log);
+			if (mp->clsn) {
+				logdiff(difft, tblk->clsn, log);
+				logdiff(diffp, mp->clsn, log);
+				if (difft > diffp)
+					mp->clsn = tblk->clsn;
+			} else
+				mp->clsn = tblk->clsn;
+			LOGSYNC_UNLOCK(log);
+
+			assert(!(tlck->flag & tlckFREEPAGE));
+
+			if (tlck->flag & tlckWRITEPAGE) {
+				write_metapage(mp);
+			} else {
+				/* release page which has been forced */
+				release_metapage(mp);
+			}
+		}
+
+		/* insert tlock, and linelock(s) of the tlock if any,
+		 * at head of freelist
+		 */
+		TXN_LOCK();
+
+		llid = ((struct linelock *) & tlck->lock)->next;
+		while (llid) {
+			linelock = (struct linelock *) lid_to_tlock(llid);
+			k = linelock->next;
+			txLockFree(llid);
+			llid = k;
+		}
+		txLockFree(lid);
+
+		TXN_UNLOCK();
+	}
+	tblk->next = tblk->last = 0;
+
+	/*
+	 * remove tblock from logsynclist
+	 * (allocation map pages inherited lsn of tblk and
+	 * has been inserted in logsync list at txUpdateMap())
+	 */
+	if (tblk->lsn) {
+		LOGSYNC_LOCK(log);
+		log->count--;
+		list_del(&tblk->synclist);
+		LOGSYNC_UNLOCK(log);
+	}
+}
+
+
+/*
+ *      txMaplock()
+ *
+ * function: allocate a transaction lock for freed page/entry;
+ *      for freed page, maplock is used as xtlock/dtlock type;
+ */
+struct tlock *txMaplock(tid_t tid, struct inode *ip, int type)
+{
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	lid_t lid;
+	struct tblock *tblk;
+	struct tlock *tlck;
+	struct maplock *maplock;
+
+	TXN_LOCK();
+
+	/*
+	 * allocate a tlock
+	 */
+	lid = txLockAlloc();
+	tlck = lid_to_tlock(lid);
+
+	/*
+	 * initialize tlock
+	 */
+	tlck->tid = tid;
+
+	/* bind the tlock and the object */
+	tlck->flag = tlckINODELOCK;
+	tlck->ip = ip;
+	tlck->mp = NULL;
+
+	tlck->type = type;
+
+	/*
+	 * enqueue transaction lock to transaction/inode
+	 */
+	/* insert the tlock at tail of transaction tlock list */
+	if (tid) {
+		tblk = tid_to_tblock(tid);
+		if (tblk->next)
+			lid_to_tlock(tblk->last)->next = lid;
+		else
+			tblk->next = lid;
+		tlck->next = 0;
+		tblk->last = lid;
+	}
+	/* anonymous transaction:
+	 * insert the tlock at head of inode anonymous tlock list
+	 */
+	else {
+		tlck->next = jfs_ip->atlhead;
+		jfs_ip->atlhead = lid;
+		if (tlck->next == 0) {
+			/* This inode's first anonymous transaction */
+			jfs_ip->atltail = lid;
+			list_add_tail(&jfs_ip->anon_inode_list,
+				      &TxAnchor.anon_list);
+		}
+	}
+
+	TXN_UNLOCK();
+
+	/* initialize type dependent area for maplock */
+	maplock = (struct maplock *) & tlck->lock;
+	maplock->next = 0;
+	maplock->maxcnt = 0;
+	maplock->index = 0;
+
+	return tlck;
+}
+
+
+/*
+ *      txLinelock()
+ *
+ * function: allocate a transaction lock for log vector list
+ */
+struct linelock *txLinelock(struct linelock * tlock)
+{
+	lid_t lid;
+	struct tlock *tlck;
+	struct linelock *linelock;
+
+	TXN_LOCK();
+
+	/* allocate a TxLock structure */
+	lid = txLockAlloc();
+	tlck = lid_to_tlock(lid);
+
+	TXN_UNLOCK();
+
+	/* initialize linelock */
+	linelock = (struct linelock *) tlck;
+	linelock->next = 0;
+	linelock->flag = tlckLINELOCK;
+	linelock->maxcnt = TLOCKLONG;
+	linelock->index = 0;
+
+	/* append linelock after tlock */
+	linelock->next = tlock->next;
+	tlock->next = lid;
+
+	return linelock;
+}
+
+
+
+/*
+ *              transaction commit management
+ *              -----------------------------
+ */
+
+/*
+ * NAME:        txCommit()
+ *
+ * FUNCTION:    commit the changes to the objects specified in
+ *              clist.  For journalled segments only the
+ *              changes of the caller are committed, ie by tid.
+ *              for non-journalled segments the data are flushed to
+ *              disk and then the change to the disk inode and indirect
+ *              blocks committed (so blocks newly allocated to the
+ *              segment will be made a part of the segment atomically).
+ *
+ *              all of the segments specified in clist must be in
+ *              one file system. no more than 6 segments are needed
+ *              to handle all unix svcs.
+ *
+ *              if the i_nlink field (i.e. disk inode link count)
+ *              is zero, and the type of inode is a regular file or
+ *              directory, or symbolic link , the inode is truncated
+ *              to zero length. the truncation is committed but the
+ *              VM resources are unaffected until it is closed (see
+ *              iput and iclose).
+ *
+ * PARAMETER:
+ *
+ * RETURN:
+ *
+ * serialization:
+ *              on entry the inode lock on each segment is assumed
+ *              to be held.
+ *
+ * i/o error:
+ */
+int txCommit(tid_t tid,		/* transaction identifier */
+	     int nip,		/* number of inodes to commit */
+	     struct inode **iplist,	/* list of inode to commit */
+	     int flag)
+{
+	int rc = 0, rc1 = 0;
+	struct commit cd;
+	struct jfs_log *log;
+	struct tblock *tblk;
+	struct lrd *lrd;
+	int lsn;
+	struct inode *ip;
+	struct jfs_inode_info *jfs_ip;
+	int k, n;
+	ino_t top;
+	struct super_block *sb;
+
+	jFYI(1, ("txCommit, tid = %d, flag = %d\n", tid, flag));
+	/* is read-only file system ? */
+	if (isReadOnly(iplist[0])) {
+		rc = EROFS;
+		goto TheEnd;
+	}
+
+	sb = cd.sb = iplist[0]->i_sb;
+	cd.tid = tid;
+
+	if (tid == 0)
+		tid = txBegin(sb, 0);
+	tblk = tid_to_tblock(tid);
+
+	/*
+	 * initialize commit structure
+	 */
+	log = JFS_SBI(sb)->log;
+	cd.log = log;
+
+	/* initialize log record descriptor in commit */
+	lrd = &cd.lrd;
+	lrd->logtid = cpu_to_le32(tblk->logtid);
+	lrd->backchain = 0;
+
+	tblk->xflag |= flag;
+
+	if ((flag & (COMMIT_FORCE | COMMIT_SYNC)) == 0)
+		tblk->xflag |= COMMIT_LAZY;
+	/*
+	 *      prepare non-journaled objects for commit
+	 *
+	 * flush data pages of non-journaled file
+	 * to prevent the file getting non-initialized disk blocks
+	 * in case of crash.
+	 * (new blocks - )
+	 */
+	cd.iplist = iplist;
+	cd.nip = nip;
+
+	/*
+	 *      acquire transaction lock on (on-disk) inodes
+	 *
+	 * update on-disk inode from in-memory inode
+	 * acquiring transaction locks for AFTER records
+	 * on the on-disk inode of file object
+	 *
+	 * sort the inodes array by inode number in descending order
+	 * to prevent deadlock when acquiring transaction lock
+	 * of on-disk inodes on multiple on-disk inode pages by
+	 * multiple concurrent transactions
+	 */
+	for (k = 0; k < cd.nip; k++) {
+		top = (cd.iplist[k])->i_ino;
+		for (n = k + 1; n < cd.nip; n++) {
+			ip = cd.iplist[n];
+			if (ip->i_ino > top) {
+				top = ip->i_ino;
+				cd.iplist[n] = cd.iplist[k];
+				cd.iplist[k] = ip;
+			}
+		}
+
+		ip = cd.iplist[k];
+		jfs_ip = JFS_IP(ip);
+
+		/*
+		 * BUGBUG - Should we call filemap_fdatasync here instead
+		 * of fsync_inode_data?
+		 * If we do, we have a deadlock condition since we may end
+		 * up recursively calling jfs_get_block with the IWRITELOCK
+		 * held.  We may be able to do away with IWRITELOCK while
+		 * committing transactions and use i_sem instead.
+		 */
+		if ((!S_ISDIR(ip->i_mode))
+		    && (tblk->flag & COMMIT_DELETE) == 0)
+			fsync_inode_data_buffers(ip);
+
+		/*
+		 * Mark inode as not dirty.  It will still be on the dirty
+		 * inode list, but we'll know not to commit it again unless
+		 * it gets marked dirty again
+		 */
+		clear_cflag(COMMIT_Dirty, ip);
+
+		/* inherit anonymous tlock(s) of inode */
+		if (jfs_ip->atlhead) {
+			lid_to_tlock(jfs_ip->atltail)->next = tblk->next;
+			tblk->next = jfs_ip->atlhead;
+			if (!tblk->last)
+				tblk->last = jfs_ip->atltail;
+			jfs_ip->atlhead = jfs_ip->atltail = 0;
+			TXN_LOCK();
+			list_del_init(&jfs_ip->anon_inode_list);
+			TXN_UNLOCK();
+		}
+
+		/*
+		 * acquire transaction lock on on-disk inode page
+		 * (become first tlock of the tblk's tlock list)
+		 */
+		if (((rc = diWrite(tid, ip))))
+			goto out;
+	}
+
+	/*
+	 *      write log records from transaction locks
+	 *
+	 * txUpdateMap() resets XAD_NEW in XAD.
+	 */
+	if ((rc = txLog(log, tblk, &cd)))
+		goto TheEnd;
+
+	/*
+	 * Ensure that inode isn't reused before
+	 * lazy commit thread finishes processing
+	 */
+	if (tblk->xflag & (COMMIT_CREATE | COMMIT_DELETE))
+		atomic_inc(&tblk->ip->i_count);
+
+	ASSERT((!(tblk->xflag & COMMIT_DELETE)) ||
+	       ((tblk->ip->i_nlink == 0) &&
+		!test_cflag(COMMIT_Nolink, tblk->ip)));
+
+	/*
+	 *      write COMMIT log record
+	 */
+	lrd->type = cpu_to_le16(LOG_COMMIT);
+	lrd->length = 0;
+	lsn = lmLog(log, tblk, lrd, NULL);
+
+	lmGroupCommit(log, tblk);
+
+	/*
+	 *      - transaction is now committed -
+	 */
+
+	/*
+	 * force pages in careful update
+	 * (imap addressing structure update)
+	 */
+	if (flag & COMMIT_FORCE)
+		txForce(tblk);
+
+	/*
+	 *      update allocation map.
+	 *
+	 * update inode allocation map and inode:
+	 * free pager lock on memory object of inode if any.
+	 * update  block allocation map.
+	 *
+	 * txUpdateMap() resets XAD_NEW in XAD.
+	 */
+	if (tblk->xflag & COMMIT_FORCE)
+		txUpdateMap(tblk);
+
+	/*
+	 *      free transaction locks and pageout/free pages
+	 */
+	txRelease(tblk);
+
+	if ((tblk->flag & tblkGC_LAZY) == 0)
+		txUnlock(tblk);
+
+
+	/*
+	 *      reset in-memory object state
+	 */
+	for (k = 0; k < cd.nip; k++) {
+		ip = cd.iplist[k];
+		jfs_ip = JFS_IP(ip);
+
+		/*
+		 * reset in-memory inode state
+		 */
+		jfs_ip->bxflag = 0;
+		jfs_ip->blid = 0;
+	}
+
+      out:
+	if (rc != 0)
+		txAbortCommit(&cd, rc);
+	else
+		rc = rc1;
+
+      TheEnd:
+	jFYI(1, ("txCommit: tid = %d, returning %d\n", tid, rc));
+	return rc;
+}
+
+
+/*
+ * NAME:        txLog()
+ *
+ * FUNCTION:    Writes AFTER log records for all lines modified
+ *              by tid for segments specified by inodes in comdata.
+ *              Code assumes only WRITELOCKS are recorded in lockwords.
+ *
+ * PARAMETERS:
+ *
+ * RETURN :
+ */
+static int txLog(struct jfs_log * log, struct tblock * tblk, struct commit * cd)
+{
+	int rc = 0;
+	struct inode *ip;
+	lid_t lid;
+	struct tlock *tlck;
+	struct lrd *lrd = &cd->lrd;
+
+	/*
+	 * write log record(s) for each tlock of transaction,
+	 */
+	for (lid = tblk->next; lid; lid = tlck->next) {
+		tlck = lid_to_tlock(lid);
+
+		tlck->flag |= tlckLOG;
+
+		/* initialize lrd common */
+		ip = tlck->ip;
+		lrd->aggregate = cpu_to_le32(kdev_t_to_nr(ip->i_dev));
+		lrd->log.redopage.fileset = cpu_to_le32(JFS_IP(ip)->fileset);
+		lrd->log.redopage.inode = cpu_to_le32(ip->i_ino);
+
+		if (tlck->mp)
+			hold_metapage(tlck->mp, 0);
+
+		/* write log record of page from the tlock */
+		switch (tlck->type & tlckTYPE) {
+		case tlckXTREE:
+			xtLog(log, tblk, lrd, tlck);
+			break;
+
+		case tlckDTREE:
+			dtLog(log, tblk, lrd, tlck);
+			break;
+
+		case tlckINODE:
+			diLog(log, tblk, lrd, tlck, cd);
+			break;
+
+		case tlckMAP:
+			mapLog(log, tblk, lrd, tlck);
+			break;
+
+		case tlckDATA:
+			dataLog(log, tblk, lrd, tlck);
+			break;
+
+		default:
+			jERROR(1, ("UFO tlock:0x%p\n", tlck));
+		}
+		if (tlck->mp)
+			release_metapage(tlck->mp);
+	}
+
+	return rc;
+}
+
+
+/*
+ *      diLog()
+ *
+ * function:    log inode tlock and format maplock to update bmap;
+ */
+int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	  struct tlock * tlck, struct commit * cd)
+{
+	int rc = 0;
+	struct metapage *mp;
+	pxd_t *pxd;
+	struct pxd_lock *pxdlock;
+
+	mp = tlck->mp;
+
+	/* initialize as REDOPAGE record format */
+	lrd->log.redopage.type = cpu_to_le16(LOG_INODE);
+	lrd->log.redopage.l2linesize = cpu_to_le16(L2INODESLOTSIZE);
+
+	pxd = &lrd->log.redopage.pxd;
+
+	/*
+	 *      inode after image
+	 */
+	if (tlck->type & tlckENTRY) {
+		/* log after-image for logredo(): */
+		lrd->type = cpu_to_le16(LOG_REDOPAGE);
+//              *pxd = mp->cm_pxd;
+		PXDaddress(pxd, mp->index);
+		PXDlength(pxd,
+			  mp->logical_size >> tblk->sb->s_blocksize_bits);
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+
+		/* mark page as homeward bound */
+		tlck->flag |= tlckWRITEPAGE;
+	} else if (tlck->type & tlckFREE) {
+		/*
+		 *      free inode extent
+		 *
+		 * (pages of the freed inode extent have been invalidated and
+		 * a maplock for free of the extent has been formatted at
+		 * txLock() time);
+		 *
+		 * the tlock had been acquired on the inode allocation map page
+		 * (iag) that specifies the freed extent, even though the map
+		 * page is not itself logged, to prevent pageout of the map
+		 * page before the log;
+		 */
+		assert(tlck->type & tlckFREE);
+
+		/* log LOG_NOREDOINOEXT of the freed inode extent for
+		 * logredo() to start NoRedoPage filters, and to update
+		 * imap and bmap for free of the extent;
+		 */
+		lrd->type = cpu_to_le16(LOG_NOREDOINOEXT);
+		/*
+		 * For the LOG_NOREDOINOEXT record, we need
+		 * to pass the IAG number and inode extent
+		 * index (within that IAG) from which the
+		 * the extent being released.  These have been
+		 * passed to us in the iplist[1] and iplist[2].
+		 */
+		lrd->log.noredoinoext.iagnum =
+		    cpu_to_le32((u32) (size_t) cd->iplist[1]);
+		lrd->log.noredoinoext.inoext_idx =
+		    cpu_to_le32((u32) (size_t) cd->iplist[2]);
+
+		pxdlock = (struct pxd_lock *) & tlck->lock;
+		*pxd = pxdlock->pxd;
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
+
+		/* update bmap */
+		tlck->flag |= tlckUPDATEMAP;
+
+		/* mark page as homeward bound */
+		tlck->flag |= tlckWRITEPAGE;
+	} else {
+		jERROR(2, ("diLog: UFO type tlck:0x%p\n", tlck));
+	}
+#ifdef  _JFS_WIP
+	/*
+	 *      alloc/free external EA extent
+	 *
+	 * a maplock for txUpdateMap() to update bPWMAP for alloc/free
+	 * of the extent has been formatted at txLock() time;
+	 */
+	else {
+		assert(tlck->type & tlckEA);
+
+		/* log LOG_UPDATEMAP for logredo() to update bmap for
+		 * alloc of new (and free of old) external EA extent;
+		 */
+		lrd->type = cpu_to_le16(LOG_UPDATEMAP);
+		pxdlock = (struct pxd_lock *) & tlck->lock;
+		nlock = pxdlock->index;
+		for (i = 0; i < nlock; i++, pxdlock++) {
+			if (pxdlock->flag & mlckALLOCPXD)
+				lrd->log.updatemap.type =
+				    cpu_to_le16(LOG_ALLOCPXD);
+			else
+				lrd->log.updatemap.type =
+				    cpu_to_le16(LOG_FREEPXD);
+			lrd->log.updatemap.nxd = cpu_to_le16(1);
+			lrd->log.updatemap.pxd = pxdlock->pxd;
+			lrd->backchain =
+			    cpu_to_le32(lmLog(log, tblk, lrd, NULL));
+		}
+
+		/* update bmap */
+		tlck->flag |= tlckUPDATEMAP;
+	}
+#endif				/* _JFS_WIP */
+
+	return rc;
+}
+
+
+/*
+ *      dataLog()
+ *
+ * function:    log data tlock
+ */
+int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	    struct tlock * tlck)
+{
+	struct metapage *mp;
+	pxd_t *pxd;
+	int rc;
+	s64 xaddr;
+	int xflag;
+	s32 xlen;
+
+	mp = tlck->mp;
+
+	/* initialize as REDOPAGE record format */
+	lrd->log.redopage.type = cpu_to_le16(LOG_DATA);
+	lrd->log.redopage.l2linesize = cpu_to_le16(L2DATASLOTSIZE);
+
+	pxd = &lrd->log.redopage.pxd;
+
+	/* log after-image for logredo(): */
+	lrd->type = cpu_to_le16(LOG_REDOPAGE);
+
+	if (JFS_IP(tlck->ip)->next_index < MAX_INLINE_DIRTABLE_ENTRY) {
+		/*
+		 * The table has been truncated, we've must have deleted
+		 * the last entry, so don't bother logging this
+		 */
+		mp->lid = 0;
+		atomic_dec(&mp->nohomeok);
+		discard_metapage(mp);
+		tlck->mp = 0;
+		return 0;
+	}
+
+	rc = xtLookup(tlck->ip, mp->index, 1, &xflag, &xaddr, &xlen, 1);
+	if (rc || (xlen == 0)) {
+		jERROR(1, ("dataLog: can't find physical address\n"));
+		return 0;
+	}
+
+	PXDaddress(pxd, xaddr);
+	PXDlength(pxd, mp->logical_size >> tblk->sb->s_blocksize_bits);
+
+	lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+
+	/* mark page as homeward bound */
+	tlck->flag |= tlckWRITEPAGE;
+
+	return 0;
+}
+
+
+/*
+ *      dtLog()
+ *
+ * function:    log dtree tlock and format maplock to update bmap;
+ */
+void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	   struct tlock * tlck)
+{
+	struct inode *ip;
+	struct metapage *mp;
+	struct pxd_lock *pxdlock;
+	pxd_t *pxd;
+
+	ip = tlck->ip;
+	mp = tlck->mp;
+
+	/* initialize as REDOPAGE/NOREDOPAGE record format */
+	lrd->log.redopage.type = cpu_to_le16(LOG_DTREE);
+	lrd->log.redopage.l2linesize = cpu_to_le16(L2DTSLOTSIZE);
+
+	pxd = &lrd->log.redopage.pxd;
+
+	if (tlck->type & tlckBTROOT)
+		lrd->log.redopage.type |= cpu_to_le16(LOG_BTROOT);
+
+	/*
+	 *      page extension via relocation: entry insertion;
+	 *      page extension in-place: entry insertion;
+	 *      new right page from page split, reinitialized in-line
+	 *      root from root page split: entry insertion;
+	 */
+	if (tlck->type & (tlckNEW | tlckEXTEND)) {
+		/* log after-image of the new page for logredo():
+		 * mark log (LOG_NEW) for logredo() to initialize
+		 * freelist and update bmap for alloc of the new page;
+		 */
+		lrd->type = cpu_to_le16(LOG_REDOPAGE);
+		if (tlck->type & tlckEXTEND)
+			lrd->log.redopage.type |= cpu_to_le16(LOG_EXTEND);
+		else
+			lrd->log.redopage.type |= cpu_to_le16(LOG_NEW);
+//              *pxd = mp->cm_pxd;
+		PXDaddress(pxd, mp->index);
+		PXDlength(pxd,
+			  mp->logical_size >> tblk->sb->s_blocksize_bits);
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+
+		/* format a maplock for txUpdateMap() to update bPMAP for
+		 * alloc of the new page;
+		 */
+		if (tlck->type & tlckBTROOT)
+			return;
+		tlck->flag |= tlckUPDATEMAP;
+		pxdlock = (struct pxd_lock *) & tlck->lock;
+		pxdlock->flag = mlckALLOCPXD;
+		pxdlock->pxd = *pxd;
+
+		pxdlock->index = 1;
+
+		/* mark page as homeward bound */
+		tlck->flag |= tlckWRITEPAGE;
+		return;
+	}
+
+	/*
+	 *      entry insertion/deletion,
+	 *      sibling page link update (old right page before split);
+	 */
+	if (tlck->type & (tlckENTRY | tlckRELINK)) {
+		/* log after-image for logredo(): */
+		lrd->type = cpu_to_le16(LOG_REDOPAGE);
+		PXDaddress(pxd, mp->index);
+		PXDlength(pxd,
+			  mp->logical_size >> tblk->sb->s_blocksize_bits);
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+
+		/* mark page as homeward bound */
+		tlck->flag |= tlckWRITEPAGE;
+		return;
+	}
+
+	/*
+	 *      page deletion: page has been invalidated
+	 *      page relocation: source extent
+	 *
+	 *      a maplock for free of the page has been formatted
+	 *      at txLock() time);
+	 */
+	if (tlck->type & (tlckFREE | tlckRELOCATE)) {
+		/* log LOG_NOREDOPAGE of the deleted page for logredo()
+		 * to start NoRedoPage filter and to update bmap for free
+		 * of the deletd page
+		 */
+		lrd->type = cpu_to_le16(LOG_NOREDOPAGE);
+		pxdlock = (struct pxd_lock *) & tlck->lock;
+		*pxd = pxdlock->pxd;
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
+
+		/* a maplock for txUpdateMap() for free of the page
+		 * has been formatted at txLock() time;
+		 */
+		tlck->flag |= tlckUPDATEMAP;
+	}
+	return;
+}
+
+
+/*
+ *      xtLog()
+ *
+ * function:    log xtree tlock and format maplock to update bmap;
+ */
+void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	   struct tlock * tlck)
+{
+	struct inode *ip;
+	struct metapage *mp;
+	xtpage_t *p;
+	struct xtlock *xtlck;
+	struct maplock *maplock;
+	struct xdlistlock *xadlock;
+	struct pxd_lock *pxdlock;
+	pxd_t *pxd;
+	int next, lwm, hwm;
+
+	ip = tlck->ip;
+	mp = tlck->mp;
+
+	/* initialize as REDOPAGE/NOREDOPAGE record format */
+	lrd->log.redopage.type = cpu_to_le16(LOG_XTREE);
+	lrd->log.redopage.l2linesize = cpu_to_le16(L2XTSLOTSIZE);
+
+	pxd = &lrd->log.redopage.pxd;
+
+	if (tlck->type & tlckBTROOT) {
+		lrd->log.redopage.type |= cpu_to_le16(LOG_BTROOT);
+		p = &JFS_IP(ip)->i_xtroot;
+		if (S_ISDIR(ip->i_mode))
+			lrd->log.redopage.type |=
+			    cpu_to_le16(LOG_DIR_XTREE);
+	} else
+		p = (xtpage_t *) mp->data;
+	next = le16_to_cpu(p->header.nextindex);
+
+	xtlck = (struct xtlock *) & tlck->lock;
+
+	maplock = (struct maplock *) & tlck->lock;
+	xadlock = (struct xdlistlock *) maplock;
+
+	/*
+	 *      entry insertion/extension;
+	 *      sibling page link update (old right page before split);
+	 */
+	if (tlck->type & (tlckNEW | tlckGROW | tlckRELINK)) {
+		/* log after-image for logredo():
+		 * logredo() will update bmap for alloc of new/extended
+		 * extents (XAD_NEW|XAD_EXTEND) of XAD[lwm:next) from
+		 * after-image of XADlist;
+		 * logredo() resets (XAD_NEW|XAD_EXTEND) flag when
+		 * applying the after-image to the meta-data page.
+		 */
+		lrd->type = cpu_to_le16(LOG_REDOPAGE);
+//              *pxd = mp->cm_pxd;
+		PXDaddress(pxd, mp->index);
+		PXDlength(pxd,
+			  mp->logical_size >> tblk->sb->s_blocksize_bits);
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+
+		/* format a maplock for txUpdateMap() to update bPMAP
+		 * for alloc of new/extended extents of XAD[lwm:next)
+		 * from the page itself;
+		 * txUpdateMap() resets (XAD_NEW|XAD_EXTEND) flag.
+		 */
+		lwm = xtlck->lwm.offset;
+		if (lwm == 0)
+			lwm = XTPAGEMAXSLOT;
+
+		if (lwm == next)
+			goto out;
+		assert(lwm < next);
+		tlck->flag |= tlckUPDATEMAP;
+		xadlock->flag = mlckALLOCXADLIST;
+		xadlock->count = next - lwm;
+		if ((xadlock->count <= 2) && (tblk->xflag & COMMIT_LAZY)) {
+			int i;
+			/*
+			 * Lazy commit may allow xtree to be modified before
+			 * txUpdateMap runs.  Copy xad into linelock to
+			 * preserve correct data.
+			 */
+			xadlock->xdlist = &xtlck->pxdlock;
+			memcpy(xadlock->xdlist, &p->xad[lwm],
+			       sizeof(xad_t) * xadlock->count);
+
+			for (i = 0; i < xadlock->count; i++)
+				p->xad[lwm + i].flag &=
+				    ~(XAD_NEW | XAD_EXTENDED);
+		} else {
+			/*
+			 * xdlist will point to into inode's xtree, ensure
+			 * that transaction is not committed lazily.
+			 */
+			xadlock->xdlist = &p->xad[lwm];
+			tblk->xflag &= ~COMMIT_LAZY;
+		}
+		jFYI(1,
+		     ("xtLog: alloc ip:0x%p mp:0x%p tlck:0x%p lwm:%d count:%d\n",
+		      tlck->ip, mp, tlck, lwm, xadlock->count));
+
+		maplock->index = 1;
+
+	      out:
+		/* mark page as homeward bound */
+		tlck->flag |= tlckWRITEPAGE;
+
+		return;
+	}
+
+	/*
+	 *      page deletion: file deletion/truncation (ref. xtTruncate())
+	 *
+	 * (page will be invalidated after log is written and bmap
+	 * is updated from the page);
+	 */
+	if (tlck->type & tlckFREE) {
+		/* LOG_NOREDOPAGE log for NoRedoPage filter:
+		 * if page free from file delete, NoRedoFile filter from
+		 * inode image of zero link count will subsume NoRedoPage
+		 * filters for each page;
+		 * if page free from file truncattion, write NoRedoPage
+		 * filter;
+		 *
+		 * upadte of block allocation map for the page itself:
+		 * if page free from deletion and truncation, LOG_UPDATEMAP
+		 * log for the page itself is generated from processing
+		 * its parent page xad entries;
+		 */
+		/* if page free from file truncation, log LOG_NOREDOPAGE
+		 * of the deleted page for logredo() to start NoRedoPage
+		 * filter for the page;
+		 */
+		if (tblk->xflag & COMMIT_TRUNCATE) {
+			/* write NOREDOPAGE for the page */
+			lrd->type = cpu_to_le16(LOG_NOREDOPAGE);
+			PXDaddress(pxd, mp->index);
+			PXDlength(pxd,
+				  mp->logical_size >> tblk->sb->
+				  s_blocksize_bits);
+			lrd->backchain =
+			    cpu_to_le32(lmLog(log, tblk, lrd, NULL));
+
+			if (tlck->type & tlckBTROOT) {
+				/* Empty xtree must be logged */
+				lrd->type = cpu_to_le16(LOG_REDOPAGE);
+				lrd->backchain =
+				    cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+			}
+		}
+
+		/* init LOG_UPDATEMAP of the freed extents
+		 * XAD[XTENTRYSTART:hwm) from the deleted page itself
+		 * for logredo() to update bmap;
+		 */
+		lrd->type = cpu_to_le16(LOG_UPDATEMAP);
+		lrd->log.updatemap.type = cpu_to_le16(LOG_FREEXADLIST);
+		xtlck = (struct xtlock *) & tlck->lock;
+		hwm = xtlck->hwm.offset;
+		lrd->log.updatemap.nxd =
+		    cpu_to_le16(hwm - XTENTRYSTART + 1);
+		/* reformat linelock for lmLog() */
+		xtlck->header.offset = XTENTRYSTART;
+		xtlck->header.length = hwm - XTENTRYSTART + 1;
+		xtlck->index = 1;
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+
+		/* format a maplock for txUpdateMap() to update bmap
+		 * to free extents of XAD[XTENTRYSTART:hwm) from the
+		 * deleted page itself;
+		 */
+		tlck->flag |= tlckUPDATEMAP;
+		xadlock->flag = mlckFREEXADLIST;
+		xadlock->count = hwm - XTENTRYSTART + 1;
+		if ((xadlock->count <= 2) && (tblk->xflag & COMMIT_LAZY)) {
+			/*
+			 * Lazy commit may allow xtree to be modified before
+			 * txUpdateMap runs.  Copy xad into linelock to
+			 * preserve correct data.
+			 */
+			xadlock->xdlist = &xtlck->pxdlock;
+			memcpy(xadlock->xdlist, &p->xad[XTENTRYSTART],
+			       sizeof(xad_t) * xadlock->count);
+		} else {
+			/*
+			 * xdlist will point to into inode's xtree, ensure
+			 * that transaction is not committed lazily unless
+			 * we're deleting the inode (unlink).  In that case
+			 * we have special logic for the inode to be
+			 * unlocked by the lazy commit thread.
+			 */
+			xadlock->xdlist = &p->xad[XTENTRYSTART];
+			if ((tblk->xflag & COMMIT_LAZY) &&
+			    (tblk->xflag & COMMIT_DELETE) &&
+			    (tblk->ip == ip))
+				set_cflag(COMMIT_Holdlock, ip);
+			else
+				tblk->xflag &= ~COMMIT_LAZY;
+		}
+		jFYI(1,
+		     ("xtLog: free ip:0x%p mp:0x%p count:%d lwm:2\n",
+		      tlck->ip, mp, xadlock->count));
+
+		maplock->index = 1;
+
+		/* mark page as invalid */
+		if (((tblk->xflag & COMMIT_PWMAP) || S_ISDIR(ip->i_mode))
+		    && !(tlck->type & tlckBTROOT))
+			tlck->flag |= tlckFREEPAGE;
+		/*
+		   else (tblk->xflag & COMMIT_PMAP)
+		   ? release the page;
+		 */
+		return;
+	}
+
+	/*
+	 *      page/entry truncation: file truncation (ref. xtTruncate())
+	 *
+	 *     |----------+------+------+---------------|
+	 *                |      |      |
+	 *                |      |     hwm - hwm before truncation
+	 *                |     next - truncation point
+	 *               lwm - lwm before truncation
+	 * header ?
+	 */
+	if (tlck->type & tlckTRUNCATE) {
+		pxd_t tpxd;	/* truncated extent of xad */
+		int twm;
+
+		/*
+		 * For truncation the entire linelock may be used, so it would
+		 * be difficult to store xad list in linelock itself.
+		 * Therefore, we'll just force transaction to be committed
+		 * synchronously, so that xtree pages won't be changed before
+		 * txUpdateMap runs.
+		 */
+		tblk->xflag &= ~COMMIT_LAZY;
+		lwm = xtlck->lwm.offset;
+		if (lwm == 0)
+			lwm = XTPAGEMAXSLOT;
+		hwm = xtlck->hwm.offset;
+		twm = xtlck->twm.offset;
+
+		/*
+		 *      write log records
+		 */
+		/*
+		 * allocate entries XAD[lwm:next]:
+		 */
+		if (lwm < next) {
+			/* log after-image for logredo():
+			 * logredo() will update bmap for alloc of new/extended
+			 * extents (XAD_NEW|XAD_EXTEND) of XAD[lwm:next) from
+			 * after-image of XADlist;
+			 * logredo() resets (XAD_NEW|XAD_EXTEND) flag when
+			 * applying the after-image to the meta-data page.
+			 */
+			lrd->type = cpu_to_le16(LOG_REDOPAGE);
+			PXDaddress(pxd, mp->index);
+			PXDlength(pxd,
+				  mp->logical_size >> tblk->sb->
+				  s_blocksize_bits);
+			lrd->backchain =
+			    cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+		}
+
+		/*
+		 * truncate entry XAD[twm == next - 1]:
+		 */
+		if (twm == next - 1) {
+			/* init LOG_UPDATEMAP for logredo() to update bmap for
+			 * free of truncated delta extent of the truncated
+			 * entry XAD[next - 1]:
+			 * (xtlck->pxdlock = truncated delta extent);
+			 */
+			pxdlock = (struct pxd_lock *) & xtlck->pxdlock;
+			/* assert(pxdlock->type & tlckTRUNCATE); */
+			lrd->type = cpu_to_le16(LOG_UPDATEMAP);
+			lrd->log.updatemap.type = cpu_to_le16(LOG_FREEPXD);
+			lrd->log.updatemap.nxd = cpu_to_le16(1);
+			lrd->log.updatemap.pxd = pxdlock->pxd;
+			tpxd = pxdlock->pxd;	/* save to format maplock */
+			lrd->backchain =
+			    cpu_to_le32(lmLog(log, tblk, lrd, NULL));
+		}
+
+		/*
+		 * free entries XAD[next:hwm]:
+		 */
+		if (hwm >= next) {
+			/* init LOG_UPDATEMAP of the freed extents
+			 * XAD[next:hwm] from the deleted page itself
+			 * for logredo() to update bmap;
+			 */
+			lrd->type = cpu_to_le16(LOG_UPDATEMAP);
+			lrd->log.updatemap.type =
+			    cpu_to_le16(LOG_FREEXADLIST);
+			xtlck = (struct xtlock *) & tlck->lock;
+			hwm = xtlck->hwm.offset;
+			lrd->log.updatemap.nxd =
+			    cpu_to_le16(hwm - next + 1);
+			/* reformat linelock for lmLog() */
+			xtlck->header.offset = next;
+			xtlck->header.length = hwm - next + 1;
+			xtlck->index = 1;
+			lrd->backchain =
+			    cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+		}
+
+		/*
+		 *      format maplock(s) for txUpdateMap() to update bmap
+		 */
+		maplock->index = 0;
+
+		/*
+		 * allocate entries XAD[lwm:next):
+		 */
+		if (lwm < next) {
+			/* format a maplock for txUpdateMap() to update bPMAP
+			 * for alloc of new/extended extents of XAD[lwm:next)
+			 * from the page itself;
+			 * txUpdateMap() resets (XAD_NEW|XAD_EXTEND) flag.
+			 */
+			tlck->flag |= tlckUPDATEMAP;
+			xadlock->flag = mlckALLOCXADLIST;
+			xadlock->count = next - lwm;
+			xadlock->xdlist = &p->xad[lwm];
+
+			jFYI(1,
+			     ("xtLog: alloc ip:0x%p mp:0x%p count:%d lwm:%d next:%d\n",
+			      tlck->ip, mp, xadlock->count, lwm, next));
+			maplock->index++;
+			xadlock++;
+		}
+
+		/*
+		 * truncate entry XAD[twm == next - 1]:
+		 */
+		if (twm == next - 1) {
+			struct pxd_lock *pxdlock;
+
+			/* format a maplock for txUpdateMap() to update bmap
+			 * to free truncated delta extent of the truncated
+			 * entry XAD[next - 1];
+			 * (xtlck->pxdlock = truncated delta extent);
+			 */
+			tlck->flag |= tlckUPDATEMAP;
+			pxdlock = (struct pxd_lock *) xadlock;
+			pxdlock->flag = mlckFREEPXD;
+			pxdlock->count = 1;
+			pxdlock->pxd = tpxd;
+
+			jFYI(1,
+			     ("xtLog: truncate ip:0x%p mp:0x%p count:%d hwm:%d\n",
+			      ip, mp, pxdlock->count, hwm));
+			maplock->index++;
+			xadlock++;
+		}
+
+		/*
+		 * free entries XAD[next:hwm]:
+		 */
+		if (hwm >= next) {
+			/* format a maplock for txUpdateMap() to update bmap
+			 * to free extents of XAD[next:hwm] from thedeleted
+			 * page itself;
+			 */
+			tlck->flag |= tlckUPDATEMAP;
+			xadlock->flag = mlckFREEXADLIST;
+			xadlock->count = hwm - next + 1;
+			xadlock->xdlist = &p->xad[next];
+
+			jFYI(1,
+			     ("xtLog: free ip:0x%p mp:0x%p count:%d next:%d hwm:%d\n",
+			      tlck->ip, mp, xadlock->count, next, hwm));
+			maplock->index++;
+		}
+
+		/* mark page as homeward bound */
+		tlck->flag |= tlckWRITEPAGE;
+	}
+	return;
+}
+
+
+/*
+ *      mapLog()
+ *
+ * function:    log from maplock of freed data extents;
+ */
+void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	    struct tlock * tlck)
+{
+	struct pxd_lock *pxdlock;
+	int i, nlock;
+	pxd_t *pxd;
+
+	/*
+	 *      page relocation: free the source page extent
+	 *
+	 * a maplock for txUpdateMap() for free of the page
+	 * has been formatted at txLock() time saving the src
+	 * relocated page address;
+	 */
+	if (tlck->type & tlckRELOCATE) {
+		/* log LOG_NOREDOPAGE of the old relocated page
+		 * for logredo() to start NoRedoPage filter;
+		 */
+		lrd->type = cpu_to_le16(LOG_NOREDOPAGE);
+		pxdlock = (struct pxd_lock *) & tlck->lock;
+		pxd = &lrd->log.redopage.pxd;
+		*pxd = pxdlock->pxd;
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
+
+		/* (N.B. currently, logredo() does NOT update bmap
+		 * for free of the page itself for (LOG_XTREE|LOG_NOREDOPAGE);
+		 * if page free from relocation, LOG_UPDATEMAP log is
+		 * specifically generated now for logredo()
+		 * to update bmap for free of src relocated page;
+		 * (new flag LOG_RELOCATE may be introduced which will
+		 * inform logredo() to start NORedoPage filter and also
+		 * update block allocation map at the same time, thus
+		 * avoiding an extra log write);
+		 */
+		lrd->type = cpu_to_le16(LOG_UPDATEMAP);
+		lrd->log.updatemap.type = cpu_to_le16(LOG_FREEPXD);
+		lrd->log.updatemap.nxd = cpu_to_le16(1);
+		lrd->log.updatemap.pxd = pxdlock->pxd;
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
+
+		/* a maplock for txUpdateMap() for free of the page
+		 * has been formatted at txLock() time;
+		 */
+		tlck->flag |= tlckUPDATEMAP;
+		return;
+	}
+	/*
+
+	 * Otherwise it's not a relocate request
+	 *
+	 */
+	else {
+		/* log LOG_UPDATEMAP for logredo() to update bmap for
+		 * free of truncated/relocated delta extent of the data;
+		 * e.g.: external EA extent, relocated/truncated extent
+		 * from xtTailgate();
+		 */
+		lrd->type = cpu_to_le16(LOG_UPDATEMAP);
+		pxdlock = (struct pxd_lock *) & tlck->lock;
+		nlock = pxdlock->index;
+		for (i = 0; i < nlock; i++, pxdlock++) {
+			if (pxdlock->flag & mlckALLOCPXD)
+				lrd->log.updatemap.type =
+				    cpu_to_le16(LOG_ALLOCPXD);
+			else
+				lrd->log.updatemap.type =
+				    cpu_to_le16(LOG_FREEPXD);
+			lrd->log.updatemap.nxd = cpu_to_le16(1);
+			lrd->log.updatemap.pxd = pxdlock->pxd;
+			lrd->backchain =
+			    cpu_to_le32(lmLog(log, tblk, lrd, NULL));
+			jFYI(1, ("mapLog: xaddr:0x%lx xlen:0x%x\n",
+				 (ulong) addressPXD(&pxdlock->pxd),
+				 lengthPXD(&pxdlock->pxd)));
+		}
+
+		/* update bmap */
+		tlck->flag |= tlckUPDATEMAP;
+	}
+}
+
+
+/*
+ *      txEA()
+ *
+ * function:    acquire maplock for EA/ACL extents or
+ *              set COMMIT_INLINE flag;
+ */
+void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea)
+{
+	struct tlock *tlck = NULL;
+	struct pxd_lock *maplock = NULL, *pxdlock = NULL;
+
+	/*
+	 * format maplock for alloc of new EA extent
+	 */
+	if (newea) {
+		/* Since the newea could be a completely zeroed entry we need to
+		 * check for the two flags which indicate we should actually
+		 * commit new EA data
+		 */
+		if (newea->flag & DXD_EXTENT) {
+			tlck = txMaplock(tid, ip, tlckMAP);
+			maplock = (struct pxd_lock *) & tlck->lock;
+			pxdlock = (struct pxd_lock *) maplock;
+			pxdlock->flag = mlckALLOCPXD;
+			PXDaddress(&pxdlock->pxd, addressDXD(newea));
+			PXDlength(&pxdlock->pxd, lengthDXD(newea));
+			pxdlock++;
+			maplock->index = 1;
+		} else if (newea->flag & DXD_INLINE) {
+			tlck = NULL;
+
+			set_cflag(COMMIT_Inlineea, ip);
+		}
+	}
+
+	/*
+	 * format maplock for free of old EA extent
+	 */
+	if (!test_cflag(COMMIT_Nolink, ip) && oldea->flag & DXD_EXTENT) {
+		if (tlck == NULL) {
+			tlck = txMaplock(tid, ip, tlckMAP);
+			maplock = (struct pxd_lock *) & tlck->lock;
+			pxdlock = (struct pxd_lock *) maplock;
+			maplock->index = 0;
+		}
+		pxdlock->flag = mlckFREEPXD;
+		PXDaddress(&pxdlock->pxd, addressDXD(oldea));
+		PXDlength(&pxdlock->pxd, lengthDXD(oldea));
+		maplock->index++;
+	}
+}
+
+
+/*
+ *      txForce()
+ *
+ * function: synchronously write pages locked by transaction
+ *              after txLog() but before txUpdateMap();
+ */
+void txForce(struct tblock * tblk)
+{
+	struct tlock *tlck;
+	lid_t lid, next;
+	struct metapage *mp;
+
+	/*
+	 * reverse the order of transaction tlocks in
+	 * careful update order of address index pages
+	 * (right to left, bottom up)
+	 */
+	tlck = lid_to_tlock(tblk->next);
+	lid = tlck->next;
+	tlck->next = 0;
+	while (lid) {
+		tlck = lid_to_tlock(lid);
+		next = tlck->next;
+		tlck->next = tblk->next;
+		tblk->next = lid;
+		lid = next;
+	}
+
+	/*
+	 * synchronously write the page, and
+	 * hold the page for txUpdateMap();
+	 */
+	for (lid = tblk->next; lid; lid = next) {
+		tlck = lid_to_tlock(lid);
+		next = tlck->next;
+
+		if ((mp = tlck->mp) != NULL &&
+		    (tlck->type & tlckBTROOT) == 0) {
+			assert(mp->xflag & COMMIT_PAGE);
+
+			if (tlck->flag & tlckWRITEPAGE) {
+				tlck->flag &= ~tlckWRITEPAGE;
+
+				/* do not release page to freelist */
+				assert(atomic_read(&mp->nohomeok));
+				hold_metapage(mp, 0);
+				write_metapage(mp);
+			}
+		}
+	}
+}
+
+
+/*
+ *      txUpdateMap()
+ *
+ * function:    update persistent allocation map (and working map
+ *              if appropriate);
+ *
+ * parameter:
+ */
+static void txUpdateMap(struct tblock * tblk)
+{
+	struct inode *ip;
+	struct inode *ipimap;
+	lid_t lid;
+	struct tlock *tlck;
+	struct maplock *maplock;
+	struct pxd_lock pxdlock;
+	int maptype;
+	int k, nlock;
+	struct metapage *mp = 0;
+
+	ipimap = JFS_SBI(tblk->sb)->ipimap;
+
+	maptype = (tblk->xflag & COMMIT_PMAP) ? COMMIT_PMAP : COMMIT_PWMAP;
+
+
+	/*
+	 *      update block allocation map
+	 *
+	 * update allocation state in pmap (and wmap) and
+	 * update lsn of the pmap page;
+	 */
+	/*
+	 * scan each tlock/page of transaction for block allocation/free:
+	 *
+	 * for each tlock/page of transaction, update map.
+	 *  ? are there tlock for pmap and pwmap at the same time ?
+	 */
+	for (lid = tblk->next; lid; lid = tlck->next) {
+		tlck = lid_to_tlock(lid);
+
+		if ((tlck->flag & tlckUPDATEMAP) == 0)
+			continue;
+
+		if (tlck->flag & tlckFREEPAGE) {
+			/*
+			 * Another thread may attempt to reuse freed space
+			 * immediately, so we want to get rid of the metapage
+			 * before anyone else has a chance to get it.
+			 * Lock metapage, update maps, then invalidate
+			 * the metapage.
+			 */
+			mp = tlck->mp;
+			ASSERT(mp->xflag & COMMIT_PAGE);
+			hold_metapage(mp, 0);
+		}
+
+		/*
+		 * extent list:
+		 * . in-line PXD list:
+		 * . out-of-line XAD list:
+		 */
+		maplock = (struct maplock *) & tlck->lock;
+		nlock = maplock->index;
+
+		for (k = 0; k < nlock; k++, maplock++) {
+			/*
+			 * allocate blocks in persistent map:
+			 *
+			 * blocks have been allocated from wmap at alloc time;
+			 */
+			if (maplock->flag & mlckALLOC) {
+				txAllocPMap(ipimap, maplock, tblk);
+			}
+			/*
+			 * free blocks in persistent and working map:
+			 * blocks will be freed in pmap and then in wmap;
+			 *
+			 * ? tblock specifies the PMAP/PWMAP based upon
+			 * transaction
+			 *
+			 * free blocks in persistent map:
+			 * blocks will be freed from wmap at last reference
+			 * release of the object for regular files;
+			 *
+			 * Alway free blocks from both persistent & working
+			 * maps for directories
+			 */
+			else {	/* (maplock->flag & mlckFREE) */
+
+				if (S_ISDIR(tlck->ip->i_mode))
+					txFreeMap(ipimap, maplock,
+						  tblk, COMMIT_PWMAP);
+				else
+					txFreeMap(ipimap, maplock,
+						  tblk, maptype);
+			}
+		}
+		if (tlck->flag & tlckFREEPAGE) {
+			if (!(tblk->flag & tblkGC_LAZY)) {
+				/* This is equivalent to txRelease */
+				ASSERT(mp->lid == lid);
+				tlck->mp->lid = 0;
+			}
+			assert(atomic_read(&mp->nohomeok) == 1);
+			atomic_dec(&mp->nohomeok);
+			discard_metapage(mp);
+			tlck->mp = 0;
+		}
+	}
+	/*
+	 *      update inode allocation map
+	 *
+	 * update allocation state in pmap and
+	 * update lsn of the pmap page;
+	 * update in-memory inode flag/state
+	 *
+	 * unlock mapper/write lock
+	 */
+	if (tblk->xflag & COMMIT_CREATE) {
+		ip = tblk->ip;
+
+		ASSERT(test_cflag(COMMIT_New, ip));
+		clear_cflag(COMMIT_New, ip);
+
+		diUpdatePMap(ipimap, ip->i_ino, FALSE, tblk);
+		ipimap->i_state |= I_DIRTY;
+		/* update persistent block allocation map
+		 * for the allocation of inode extent;
+		 */
+		pxdlock.flag = mlckALLOCPXD;
+		pxdlock.pxd = JFS_IP(ip)->ixpxd;
+		pxdlock.index = 1;
+		txAllocPMap(ip, (struct maplock *) & pxdlock, tblk);
+		iput(ip);
+	} else if (tblk->xflag & COMMIT_DELETE) {
+		ip = tblk->ip;
+		diUpdatePMap(ipimap, ip->i_ino, TRUE, tblk);
+		ipimap->i_state |= I_DIRTY;
+		if (test_and_clear_cflag(COMMIT_Holdlock, ip)) {
+			if (tblk->flag & tblkGC_LAZY)
+				IWRITE_UNLOCK(ip);
+		}
+		iput(ip);
+	}
+}
+
+
+/*
+ *      txAllocPMap()
+ *
+ * function: allocate from persistent map;
+ *
+ * parameter:
+ *      ipbmap  -
+ *      malock -
+ *              xad list:
+ *              pxd:
+ *
+ *      maptype -
+ *              allocate from persistent map;
+ *              free from persistent map;
+ *              (e.g., tmp file - free from working map at releae
+ *               of last reference);
+ *              free from persistent and working map;
+ *
+ *      lsn     - log sequence number;
+ */
+static void txAllocPMap(struct inode *ip, struct maplock * maplock,
+			struct tblock * tblk)
+{
+	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
+	struct xdlistlock *xadlistlock;
+	xad_t *xad;
+	s64 xaddr;
+	int xlen;
+	struct pxd_lock *pxdlock;
+	struct xdlistlock *pxdlistlock;
+	pxd_t *pxd;
+	int n;
+
+	/*
+	 * allocate from persistent map;
+	 */
+	if (maplock->flag & mlckALLOCXADLIST) {
+		xadlistlock = (struct xdlistlock *) maplock;
+		xad = xadlistlock->xdlist;
+		for (n = 0; n < xadlistlock->count; n++, xad++) {
+			if (xad->flag & (XAD_NEW | XAD_EXTENDED)) {
+				xaddr = addressXAD(xad);
+				xlen = lengthXAD(xad);
+				dbUpdatePMap(ipbmap, FALSE, xaddr,
+					     (s64) xlen, tblk);
+				xad->flag &= ~(XAD_NEW | XAD_EXTENDED);
+				jFYI(1,
+				     ("allocPMap: xaddr:0x%lx xlen:%d\n",
+				      (ulong) xaddr, xlen));
+			}
+		}
+	} else if (maplock->flag & mlckALLOCPXD) {
+		pxdlock = (struct pxd_lock *) maplock;
+		xaddr = addressPXD(&pxdlock->pxd);
+		xlen = lengthPXD(&pxdlock->pxd);
+		dbUpdatePMap(ipbmap, FALSE, xaddr, (s64) xlen, tblk);
+		jFYI(1,
+		     ("allocPMap: xaddr:0x%lx xlen:%d\n", (ulong) xaddr,
+		      xlen));
+	} else {		/* (maplock->flag & mlckALLOCPXDLIST) */
+
+		pxdlistlock = (struct xdlistlock *) maplock;
+		pxd = pxdlistlock->xdlist;
+		for (n = 0; n < pxdlistlock->count; n++, pxd++) {
+			xaddr = addressPXD(pxd);
+			xlen = lengthPXD(pxd);
+			dbUpdatePMap(ipbmap, FALSE, xaddr, (s64) xlen,
+				     tblk);
+			jFYI(1,
+			     ("allocPMap: xaddr:0x%lx xlen:%d\n",
+			      (ulong) xaddr, xlen));
+		}
+	}
+}
+
+
+/*
+ *      txFreeMap()
+ *
+ * function:    free from persistent and/or working map;
+ *
+ * todo: optimization
+ */
+void txFreeMap(struct inode *ip,
+	       struct maplock * maplock, struct tblock * tblk, int maptype)
+{
+	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
+	struct xdlistlock *xadlistlock;
+	xad_t *xad;
+	s64 xaddr;
+	int xlen;
+	struct pxd_lock *pxdlock;
+	struct xdlistlock *pxdlistlock;
+	pxd_t *pxd;
+	int n;
+
+	jFYI(1,
+	     ("txFreeMap: tblk:0x%p maplock:0x%p maptype:0x%x\n",
+	      tblk, maplock, maptype));
+
+	/*
+	 * free from persistent map;
+	 */
+	if (maptype == COMMIT_PMAP || maptype == COMMIT_PWMAP) {
+		if (maplock->flag & mlckFREEXADLIST) {
+			xadlistlock = (struct xdlistlock *) maplock;
+			xad = xadlistlock->xdlist;
+			for (n = 0; n < xadlistlock->count; n++, xad++) {
+				if (!(xad->flag & XAD_NEW)) {
+					xaddr = addressXAD(xad);
+					xlen = lengthXAD(xad);
+					dbUpdatePMap(ipbmap, TRUE, xaddr,
+						     (s64) xlen, tblk);
+					jFYI(1,
+					     ("freePMap: xaddr:0x%lx xlen:%d\n",
+					      (ulong) xaddr, xlen));
+				}
+			}
+		} else if (maplock->flag & mlckFREEPXD) {
+			pxdlock = (struct pxd_lock *) maplock;
+			xaddr = addressPXD(&pxdlock->pxd);
+			xlen = lengthPXD(&pxdlock->pxd);
+			dbUpdatePMap(ipbmap, TRUE, xaddr, (s64) xlen,
+				     tblk);
+			jFYI(1,
+			     ("freePMap: xaddr:0x%lx xlen:%d\n",
+			      (ulong) xaddr, xlen));
+		} else {	/* (maplock->flag & mlckALLOCPXDLIST) */
+
+			pxdlistlock = (struct xdlistlock *) maplock;
+			pxd = pxdlistlock->xdlist;
+			for (n = 0; n < pxdlistlock->count; n++, pxd++) {
+				xaddr = addressPXD(pxd);
+				xlen = lengthPXD(pxd);
+				dbUpdatePMap(ipbmap, TRUE, xaddr,
+					     (s64) xlen, tblk);
+				jFYI(1,
+				     ("freePMap: xaddr:0x%lx xlen:%d\n",
+				      (ulong) xaddr, xlen));
+			}
+		}
+	}
+
+	/*
+	 * free from working map;
+	 */
+	if (maptype == COMMIT_PWMAP || maptype == COMMIT_WMAP) {
+		if (maplock->flag & mlckFREEXADLIST) {
+			xadlistlock = (struct xdlistlock *) maplock;
+			xad = xadlistlock->xdlist;
+			for (n = 0; n < xadlistlock->count; n++, xad++) {
+				xaddr = addressXAD(xad);
+				xlen = lengthXAD(xad);
+				dbFree(ip, xaddr, (s64) xlen);
+				xad->flag = 0;
+				jFYI(1,
+				     ("freeWMap: xaddr:0x%lx xlen:%d\n",
+				      (ulong) xaddr, xlen));
+			}
+		} else if (maplock->flag & mlckFREEPXD) {
+			pxdlock = (struct pxd_lock *) maplock;
+			xaddr = addressPXD(&pxdlock->pxd);
+			xlen = lengthPXD(&pxdlock->pxd);
+			dbFree(ip, xaddr, (s64) xlen);
+			jFYI(1,
+			     ("freeWMap: xaddr:0x%lx xlen:%d\n",
+			      (ulong) xaddr, xlen));
+		} else {	/* (maplock->flag & mlckFREEPXDLIST) */
+
+			pxdlistlock = (struct xdlistlock *) maplock;
+			pxd = pxdlistlock->xdlist;
+			for (n = 0; n < pxdlistlock->count; n++, pxd++) {
+				xaddr = addressPXD(pxd);
+				xlen = lengthPXD(pxd);
+				dbFree(ip, xaddr, (s64) xlen);
+				jFYI(1,
+				     ("freeWMap: xaddr:0x%lx xlen:%d\n",
+				      (ulong) xaddr, xlen));
+			}
+		}
+	}
+}
+
+
+/*
+ *      txFreelock()
+ *
+ * function:    remove tlock from inode anonymous locklist
+ */
+void txFreelock(struct inode *ip)
+{
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	struct tlock *xtlck, *tlck;
+	lid_t xlid = 0, lid;
+
+	if (!jfs_ip->atlhead)
+		return;
+
+	xtlck = (struct tlock *) &jfs_ip->atlhead;
+
+	while ((lid = xtlck->next)) {
+		tlck = lid_to_tlock(lid);
+		if (tlck->flag & tlckFREELOCK) {
+			xtlck->next = tlck->next;
+			txLockFree(lid);
+		} else {
+			xtlck = tlck;
+			xlid = lid;
+		}
+	}
+
+	if (jfs_ip->atlhead)
+		jfs_ip->atltail = xlid;
+	else {
+		jfs_ip->atltail = 0;
+		/*
+		 * If inode was on anon_list, remove it
+		 */
+		TXN_LOCK();
+		list_del_init(&jfs_ip->anon_inode_list);
+		TXN_UNLOCK();
+	}
+}
+
+
+/*
+ *      txAbort()
+ *
+ * function: abort tx before commit;
+ *
+ * frees line-locks and segment locks for all
+ * segments in comdata structure.
+ * Optionally sets state of file-system to FM_DIRTY in super-block.
+ * log age of page-frames in memory for which caller has
+ * are reset to 0 (to avoid logwarap).
+ */
+void txAbort(tid_t tid, int dirty)
+{
+	lid_t lid, next;
+	struct metapage *mp;
+	struct tblock *tblk = tid_to_tblock(tid);
+
+	jEVENT(1, ("txAbort: tid:%d dirty:0x%x\n", tid, dirty));
+
+	/*
+	 * free tlocks of the transaction
+	 */
+	for (lid = tblk->next; lid; lid = next) {
+		next = lid_to_tlock(lid)->next;
+
+		mp = lid_to_tlock(lid)->mp;
+
+		if (mp) {
+			mp->lid = 0;
+
+			/*
+			 * reset lsn of page to avoid logwarap:
+			 *
+			 * (page may have been previously committed by another
+			 * transaction(s) but has not been paged, i.e.,
+			 * it may be on logsync list even though it has not
+			 * been logged for the current tx.)
+			 */
+			if (mp->xflag & COMMIT_PAGE && mp->lsn)
+				LogSyncRelease(mp);
+		}
+		/* insert tlock at head of freelist */
+		TXN_LOCK();
+		txLockFree(lid);
+		TXN_UNLOCK();
+	}
+
+	/* caller will free the transaction block */
+
+	tblk->next = tblk->last = 0;
+
+	/*
+	 * mark filesystem dirty
+	 */
+	if (dirty)
+		updateSuper(tblk->sb, FM_DIRTY);
+
+	return;
+}
+
+
+/*
+ *      txAbortCommit()
+ *
+ * function: abort commit.
+ *
+ * frees tlocks of transaction; line-locks and segment locks for all
+ * segments in comdata structure. frees malloc storage
+ * sets state of file-system to FM_MDIRTY in super-block.
+ * log age of page-frames in memory for which caller has
+ * are reset to 0 (to avoid logwarap).
+ */
+void txAbortCommit(struct commit * cd, int exval)
+{
+	struct tblock *tblk;
+	tid_t tid;
+	lid_t lid, next;
+	struct metapage *mp;
+
+	assert(exval == EIO || exval == ENOMEM);
+	jEVENT(1, ("txAbortCommit: cd:0x%p\n", cd));
+
+	/*
+	 * free tlocks of the transaction
+	 */
+	tid = cd->tid;
+	tblk = tid_to_tblock(tid);
+	for (lid = tblk->next; lid; lid = next) {
+		next = lid_to_tlock(lid)->next;
+
+		mp = lid_to_tlock(lid)->mp;
+		if (mp) {
+			mp->lid = 0;
+
+			/*
+			 * reset lsn of page to avoid logwarap;
+			 */
+			if (mp->xflag & COMMIT_PAGE)
+				LogSyncRelease(mp);
+		}
+
+		/* insert tlock at head of freelist */
+		TXN_LOCK();
+		txLockFree(lid);
+		TXN_UNLOCK();
+	}
+
+	tblk->next = tblk->last = 0;
+
+	/* free the transaction block */
+	txEnd(tid);
+
+	/*
+	 * mark filesystem dirty
+	 */
+	updateSuper(cd->sb, FM_DIRTY);
+}
+
+
+/*
+ *      txLazyCommit(void)
+ *
+ *	All transactions except those changing ipimap (COMMIT_FORCE) are
+ *	processed by this routine.  This insures that the inode and block
+ *	allocation maps are updated in order.  For synchronous transactions,
+ *	let the user thread finish processing after txUpdateMap() is called.
+ */
+void txLazyCommit(struct tblock * tblk)
+{
+	struct jfs_log *log;
+
+	while (((tblk->flag & tblkGC_READY) == 0) &&
+	       ((tblk->flag & tblkGC_UNLOCKED) == 0)) {
+		/* We must have gotten ahead of the user thread
+		 */
+		jFYI(1, ("txLazyCommit: tblk 0x%p not unlocked\n", tblk));
+		schedule();
+	}
+
+	jFYI(1, ("txLazyCommit: processing tblk 0x%p\n", tblk));
+
+	txUpdateMap(tblk);
+
+	log = (struct jfs_log *) JFS_SBI(tblk->sb)->log;
+
+	spin_lock_irq(&log->gclock);	// LOGGC_LOCK
+
+	tblk->flag |= tblkGC_COMMITTED;
+
+	if ((tblk->flag & tblkGC_READY) || (tblk->flag & tblkGC_LAZY))
+		log->gcrtc--;
+
+	if (tblk->flag & tblkGC_READY)
+		wake_up(&tblk->gcwait);	// LOGGC_WAKEUP
+
+	/*
+	 * Can't release log->gclock until we've tested tblk->flag
+	 */
+	if (tblk->flag & tblkGC_LAZY) {
+		spin_unlock_irq(&log->gclock);	// LOGGC_UNLOCK
+		txUnlock(tblk);
+		tblk->flag &= ~tblkGC_LAZY;
+		txEnd(tblk - TxBlock);	/* Convert back to tid */
+	} else
+		spin_unlock_irq(&log->gclock);	// LOGGC_UNLOCK
+
+	jFYI(1, ("txLazyCommit: done: tblk = 0x%p\n", tblk));
+}
+
+/*
+ *      jfs_lazycommit(void)
+ *
+ *	To be run as a kernel daemon.  If lbmIODone is called in an interrupt
+ *	context, or where blocking is not wanted, this routine will process
+ *	committed transactions from the unlock queue.
+ */
+int jfs_lazycommit(void *arg)
+{
+	int WorkDone;
+	struct tblock *tblk;
+	unsigned long flags;
+
+	lock_kernel();
+
+	daemonize();
+	current->tty = NULL;
+	strcpy(current->comm, "jfsCommit");
+
+	unlock_kernel();
+
+	jfsCommitTask = current;
+
+	spin_lock_irq(&current->sigmask_lock);
+	sigfillset(&current->blocked);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	LAZY_LOCK_INIT();
+	TxAnchor.unlock_queue = TxAnchor.unlock_tail = 0;
+
+	complete(&jfsIOwait);
+
+	do {
+		DECLARE_WAITQUEUE(wq, current);
+
+		LAZY_LOCK(flags);
+restart:
+		WorkDone = 0;
+		while ((tblk = TxAnchor.unlock_queue)) {
+			/*
+			 * We can't get ahead of user thread.  Spinning is
+			 * simpler than blocking/waking.  We shouldn't spin
+			 * very long, since user thread shouldn't be blocking
+			 * between lmGroupCommit & txEnd.
+			 */
+			WorkDone = 1;
+
+			/*
+			 * Remove first transaction from queue
+			 */
+			TxAnchor.unlock_queue = tblk->cqnext;
+			tblk->cqnext = 0;
+			if (TxAnchor.unlock_tail == tblk)
+				TxAnchor.unlock_tail = 0;
+
+			LAZY_UNLOCK(flags);
+			txLazyCommit(tblk);
+
+			/*
+			 * We can be running indefinately if other processors
+			 * are adding transactions to this list
+			 */
+			cond_resched();
+			LAZY_LOCK(flags);
+		}
+
+		if (WorkDone)
+			goto restart;
+
+		add_wait_queue(&jfs_commit_thread_wait, &wq);
+		set_current_state(TASK_INTERRUPTIBLE);
+		LAZY_UNLOCK(flags);
+		schedule();
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&jfs_commit_thread_wait, &wq);
+	} while (!jfs_stop_threads);
+
+	if (TxAnchor.unlock_queue)
+		jERROR(1, ("jfs_lazycommit being killed with pending transactions!\n"));
+	else
+		jFYI(1, ("jfs_lazycommit being killed\n"));
+	complete(&jfsIOwait);
+	return 0;
+}
+
+void txLazyUnlock(struct tblock * tblk)
+{
+	unsigned long flags;
+
+	LAZY_LOCK(flags);
+
+	if (TxAnchor.unlock_tail)
+		TxAnchor.unlock_tail->cqnext = tblk;
+	else
+		TxAnchor.unlock_queue = tblk;
+	TxAnchor.unlock_tail = tblk;
+	tblk->cqnext = 0;
+	LAZY_UNLOCK(flags);
+	wake_up(&jfs_commit_thread_wait);
+}
+
+static void LogSyncRelease(struct metapage * mp)
+{
+	struct jfs_log *log = mp->log;
+
+	assert(atomic_read(&mp->nohomeok));
+	assert(log);
+	atomic_dec(&mp->nohomeok);
+
+	if (atomic_read(&mp->nohomeok))
+		return;
+
+	hold_metapage(mp, 0);
+
+	LOGSYNC_LOCK(log);
+	mp->log = NULL;
+	mp->lsn = 0;
+	mp->clsn = 0;
+	log->count--;
+	list_del_init(&mp->synclist);
+	LOGSYNC_UNLOCK(log);
+
+	release_metapage(mp);
+}
+
+/*
+ *	txQuiesce
+ *
+ *	Block all new transactions and push anonymous transactions to
+ *	completion
+ *
+ *	This does almost the same thing as jfs_sync below.  We don't
+ *	worry about deadlocking when TlocksLow is set, since we would
+ *	expect jfs_sync to get us out of that jam.
+ */
+void txQuiesce(struct super_block *sb)
+{
+	struct inode *ip;
+	struct jfs_inode_info *jfs_ip;
+	struct jfs_log *log = JFS_SBI(sb)->log;
+	int rc;
+	tid_t tid;
+
+	set_bit(log_QUIESCE, &log->flag);
+
+	TXN_LOCK();
+restart:
+	while (!list_empty(&TxAnchor.anon_list)) {
+		jfs_ip = list_entry(TxAnchor.anon_list.next,
+				    struct jfs_inode_info,
+				    anon_inode_list);
+		ip = jfs_ip->inode;
+
+		/*
+		 * inode will be removed from anonymous list
+		 * when it is committed
+		 */
+		TXN_UNLOCK();
+		tid = txBegin(ip->i_sb, COMMIT_INODE | COMMIT_FORCE);
+		down(&jfs_ip->commit_sem);
+		rc = txCommit(tid, 1, &ip, 0);
+		txEnd(tid);
+		up(&jfs_ip->commit_sem);
+		/*
+		 * Just to be safe.  I don't know how
+		 * long we can run without blocking
+		 */
+		cond_resched();
+		TXN_LOCK();
+	}
+
+	/*
+	 * If jfs_sync is running in parallel, there could be some inodes
+	 * on anon_list2.  Let's check.
+	 */
+	if (!list_empty(&TxAnchor.anon_list2)) {
+		list_splice(&TxAnchor.anon_list2, &TxAnchor.anon_list);
+		INIT_LIST_HEAD(&TxAnchor.anon_list2);
+		goto restart;
+	}
+	TXN_UNLOCK();
+}
+
+/*
+ * txResume()
+ *
+ * Allows transactions to start again following txQuiesce
+ */
+void txResume(struct super_block *sb)
+{
+	struct jfs_log *log = JFS_SBI(sb)->log;
+
+	clear_bit(log_QUIESCE, &log->flag);
+	TXN_WAKEUP(&log->syncwait);
+}
+
+/*
+ *      jfs_sync(void)
+ *
+ *	To be run as a kernel daemon.  This is awakened when tlocks run low.
+ *	We write any inodes that have anonymous tlocks so they will become
+ *	available.
+ */
+int jfs_sync(void *arg)
+{
+	struct inode *ip;
+	struct jfs_inode_info *jfs_ip;
+	int rc;
+	tid_t tid;
+
+	lock_kernel();
+
+	daemonize();
+	current->tty = NULL;
+	strcpy(current->comm, "jfsSync");
+
+	unlock_kernel();
+
+	spin_lock_irq(&current->sigmask_lock);
+	sigfillset(&current->blocked);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	complete(&jfsIOwait);
+
+	do {
+		DECLARE_WAITQUEUE(wq, current);
+		/*
+		 * write each inode on the anonymous inode list
+		 */
+		TXN_LOCK();
+		while (TlocksLow && !list_empty(&TxAnchor.anon_list)) {
+			jfs_ip = list_entry(TxAnchor.anon_list.next,
+					    struct jfs_inode_info,
+					    anon_inode_list);
+			ip = jfs_ip->inode;
+
+			/*
+			 * down_trylock returns 0 on success.  This is
+			 * inconsistent with spin_trylock.
+			 */
+			if (! down_trylock(&jfs_ip->commit_sem)) {
+				/*
+				 * inode will be removed from anonymous list
+				 * when it is committed
+				 */
+				TXN_UNLOCK();
+				tid = txBegin(ip->i_sb,
+					      COMMIT_INODE | COMMIT_FORCE);
+				rc = txCommit(tid, 1, &ip, 0);
+				txEnd(tid);
+				up(&jfs_ip->commit_sem);
+				/*
+				 * Just to be safe.  I don't know how
+				 * long we can run without blocking
+				 */
+				cond_resched();
+				TXN_LOCK();
+			} else {
+				/* We can't get the commit semaphore.  It may
+				 * be held by a thread waiting for tlock's
+				 * so let's not block here.  Save it to
+				 * put back on the anon_list.
+				 */
+
+				/* Take off anon_list */
+				list_del(&jfs_ip->anon_inode_list);
+
+				/* Put on anon_list2 */
+				list_add(&jfs_ip->anon_inode_list,
+					 &TxAnchor.anon_list2);
+			}
+		}
+		/* Add anon_list2 back to anon_list */
+		if (!list_empty(&TxAnchor.anon_list2)) {
+			list_splice(&TxAnchor.anon_list2, &TxAnchor.anon_list);
+			INIT_LIST_HEAD(&TxAnchor.anon_list2);
+		}
+		add_wait_queue(&jfs_sync_thread_wait, &wq);
+		set_current_state(TASK_INTERRUPTIBLE);
+		TXN_UNLOCK();
+		schedule();
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&jfs_sync_thread_wait, &wq);
+	} while (!jfs_stop_threads);
+
+	jFYI(1, ("jfs_sync being killed\n"));
+	complete(&jfsIOwait);
+	return 0;
+}
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_JFS_DEBUG)
+int jfs_txanchor_read(char *buffer, char **start, off_t offset, int length,
+		      int *eof, void *data)
+{
+	int len = 0;
+	off_t begin;
+	char *freewait;
+	char *freelockwait;
+	char *lowlockwait;
+
+	freewait =
+	    waitqueue_active(&TxAnchor.freewait) ? "active" : "empty";
+	freelockwait =
+	    waitqueue_active(&TxAnchor.freelockwait) ? "active" : "empty";
+	lowlockwait =
+	    waitqueue_active(&TxAnchor.lowlockwait) ? "active" : "empty";
+
+	len += sprintf(buffer,
+		       "JFS TxAnchor\n"
+		       "============\n"
+		       "freetid = %d\n"
+		       "freewait = %s\n"
+		       "freelock = %d\n"
+		       "freelockwait = %s\n"
+		       "lowlockwait = %s\n"
+		       "tlocksInUse = %d\n"
+		       "unlock_queue = 0x%p\n"
+		       "unlock_tail = 0x%p\n",
+		       TxAnchor.freetid,
+		       freewait,
+		       TxAnchor.freelock,
+		       freelockwait,
+		       lowlockwait,
+		       TxAnchor.tlocksInUse,
+		       TxAnchor.unlock_queue,
+		       TxAnchor.unlock_tail);
+
+	begin = offset;
+	*start = buffer + begin;
+	len -= begin;
+
+	if (len > length)
+		len = length;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_txnmgr.h linux-2.4.20/fs/jfs/jfs_txnmgr.h
--- linux-2.4.19/fs/jfs/jfs_txnmgr.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_txnmgr.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,314 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+#ifndef _H_JFS_TXNMGR
+#define _H_JFS_TXNMGR
+
+#include "jfs_logmgr.h"
+
+/*
+ * Hide implementation of TxBlock and TxLock
+ */
+#define tid_to_tblock(tid) (&TxBlock[tid])
+
+#define lid_to_tlock(lid) (&TxLock[lid])
+
+/*
+ *	transaction block
+ */
+struct tblock {
+	/*
+	 * tblock and jbuf_t common area: struct logsyncblk
+	 *
+	 * the following 5 fields are the same as struct logsyncblk
+	 * which is common to tblock and jbuf to form logsynclist
+	 */
+	u16 xflag;		/* tx commit type */
+	u16 flag;		/* tx commit state */
+	lid_t dummy;		/* Must keep structures common */
+	s32 lsn;		/* recovery lsn */
+	struct list_head synclist;	/* logsynclist link */
+
+	/* lock management */
+	struct super_block *sb;	/* super block */
+	lid_t next;		/* index of first tlock of tid */
+	lid_t last;		/* index of last tlock of tid */
+	wait_queue_head_t waitor;	/* tids waiting on this tid */
+
+	/* log management */
+	u32 logtid;		/* log transaction id */
+
+	/* commit management */
+	struct tblock *cqnext;	/* commit queue link */
+	s32 clsn;		/* commit lsn */
+	struct lbuf *bp;
+	s32 pn;			/* commit record log page number */
+	s32 eor;		/* commit record eor */
+	wait_queue_head_t gcwait;	/* group commit event list:
+					 * ready transactions wait on this
+					 * event for group commit completion.
+					 */
+	struct inode *ip;	/* inode being created or deleted */
+};
+
+extern struct tblock *TxBlock;	/* transaction block table */
+
+/* commit flags: tblk->xflag */
+#define	COMMIT_SYNC	0x0001	/* synchronous commit */
+#define	COMMIT_FORCE	0x0002	/* force pageout at end of commit */
+#define	COMMIT_FLUSH	0x0004	/* init flush at end of commit */
+#define COMMIT_MAP	0x00f0
+#define	COMMIT_PMAP	0x0010	/* update pmap */
+#define	COMMIT_WMAP	0x0020	/* update wmap */
+#define	COMMIT_PWMAP	0x0040	/* update pwmap */
+#define	COMMIT_FREE	0x0f00
+#define	COMMIT_DELETE	0x0100	/* inode delete */
+#define	COMMIT_TRUNCATE	0x0200	/* file truncation */
+#define	COMMIT_CREATE	0x0400	/* inode create */
+#define	COMMIT_LAZY	0x0800	/* lazy commit */
+#define COMMIT_PAGE	0x1000	/* Identifies element as metapage */
+#define COMMIT_INODE	0x2000	/* Identifies element as inode */
+
+/* group commit flags tblk->flag: see jfs_logmgr.h */
+
+/*
+ *	transaction lock
+ */
+struct tlock {
+	lid_t next;		/* index next lockword on tid locklist
+				 *          next lockword on freelist
+				 */
+	tid_t tid;		/* transaction id holding lock */
+
+	u16 flag;		/* 2: lock control */
+	u16 type;		/* 2: log type */
+
+	struct metapage *mp;	/* 4: object page buffer locked */
+	struct inode *ip;	/* 4: object */
+	/* (16) */
+
+	s16 lock[24];		/* 48: overlay area */
+};				/* (64) */
+
+extern struct tlock *TxLock;	/* transaction lock table */
+
+/*
+ * tlock flag
+ */
+/* txLock state */
+#define tlckPAGELOCK		0x8000
+#define tlckINODELOCK		0x4000
+#define tlckLINELOCK		0x2000
+#define tlckINLINELOCK		0x1000
+/* lmLog state */
+#define tlckLOG			0x0800
+/* updateMap state */
+#define	tlckUPDATEMAP		0x0080
+/* freeLock state */
+#define tlckFREELOCK		0x0008
+#define tlckWRITEPAGE		0x0004
+#define tlckFREEPAGE		0x0002
+
+/*
+ * tlock type
+ */
+#define	tlckTYPE		0xfe00
+#define	tlckINODE		0x8000
+#define	tlckXTREE		0x4000
+#define	tlckDTREE		0x2000
+#define	tlckMAP			0x1000
+#define	tlckEA			0x0800
+#define	tlckACL			0x0400
+#define	tlckDATA		0x0200
+#define	tlckBTROOT		0x0100
+
+#define	tlckOPERATION		0x00ff
+#define tlckGROW		0x0001	/* file grow */
+#define tlckREMOVE		0x0002	/* file delete */
+#define tlckTRUNCATE		0x0004	/* file truncate */
+#define tlckRELOCATE		0x0008	/* file/directory relocate */
+#define tlckENTRY		0x0001	/* directory insert/delete */
+#define tlckEXTEND		0x0002	/* directory extend in-line */
+#define tlckSPLIT		0x0010	/* splited page */
+#define tlckNEW			0x0020	/* new page from split */
+#define tlckFREE		0x0040	/* free page */
+#define tlckRELINK		0x0080	/* update sibling pointer */
+
+/*
+ *	linelock for lmLog()
+ *
+ * note: linelock and its variations are overlaid
+ * at tlock.lock: watch for alignment;
+ */
+struct lv {
+	u8 offset;		/* 1: */
+	u8 length;		/* 1: */
+};				/* (2) */
+
+#define	TLOCKSHORT	20
+#define	TLOCKLONG	28
+
+struct linelock {
+	u16 next;		/* 2: next linelock */
+
+	s8 maxcnt;		/* 1: */
+	s8 index;		/* 1: */
+
+	u16 flag;		/* 2: */
+	u8 type;		/* 1: */
+	u8 l2linesize;		/* 1: log2 of linesize */
+	/* (8) */
+
+	struct lv lv[20];	/* 40: */
+}; 				/* (48) */
+
+#define dt_lock	linelock
+
+struct xtlock {
+	u16 next;		/* 2: */
+
+	s8 maxcnt;		/* 1: */
+	s8 index;		/* 1: */
+
+	u16 flag;		/* 2: */
+	u8 type;		/* 1: */
+	u8 l2linesize;		/* 1: log2 of linesize */
+				/* (8) */
+
+	struct lv header;	/* 2: */
+	struct lv lwm;		/* 2: low water mark */
+	struct lv hwm;		/* 2: high water mark */
+	struct lv twm;		/* 2: */
+				/* (16) */
+
+	s32 pxdlock[8];		/* 32: */
+};				/* (48) */
+
+
+/*
+ *	maplock for txUpdateMap()
+ *
+ * note: maplock and its variations are overlaid
+ * at tlock.lock/linelock: watch for alignment;
+ * N.B. next field may be set by linelock, and should not
+ * be modified by maplock;
+ * N.B. index of the first pxdlock specifies index of next 
+ * free maplock (i.e., number of maplock) in the tlock; 
+ */
+struct maplock {
+	u16 next;		/* 2: */
+
+	u8 maxcnt;		/* 2: */
+	u8 index;		/* 2: next free maplock index */
+
+	u16 flag;		/* 2: */
+	u8 type;		/* 1: */
+	u8 count;		/* 1: number of pxd/xad */
+				/* (8) */
+
+	pxd_t pxd;		/* 8: */
+};				/* (16): */
+
+/* maplock flag */
+#define	mlckALLOC		0x00f0
+#define	mlckALLOCXADLIST	0x0080
+#define	mlckALLOCPXDLIST	0x0040
+#define	mlckALLOCXAD		0x0020
+#define	mlckALLOCPXD		0x0010
+#define	mlckFREE		0x000f
+#define	mlckFREEXADLIST		0x0008
+#define	mlckFREEPXDLIST		0x0004
+#define	mlckFREEXAD		0x0002
+#define	mlckFREEPXD		0x0001
+
+#define	pxd_lock	maplock
+
+struct xdlistlock {
+	u16 next;		/* 2: */
+
+	u8 maxcnt;		/* 2: */
+	u8 index;		/* 2: */
+
+	u16 flag;		/* 2: */
+	u8 type;		/* 1: */
+	u8 count;		/* 1: number of pxd/xad */
+				/* (8) */
+
+	/*
+	 * We need xdlist to be 64 bits (8 bytes), regardless of
+	 * whether void * is 32 or 64 bits
+	 */
+	union {
+		void *_xdlist;	/* pxd/xad list */
+		s64 pad;	/* 8: Force 64-bit xdlist size */
+	} union64;
+};				/* (16): */
+
+#define xdlist union64._xdlist
+
+/*
+ *	commit
+ *
+ * parameter to the commit manager routines
+ */
+struct commit {
+	tid_t tid;		/* tid = index of tblock */
+	int flag;		/* flags */
+	struct jfs_log *log;	/* log */
+	struct super_block *sb;	/* superblock */
+
+	int nip;		/* number of entries in iplist */
+	struct inode **iplist;	/* list of pointers to inodes */
+
+	/* log record descriptor on 64-bit boundary */
+	struct lrd lrd;		/* : log record descriptor */
+};
+
+/*
+ * external declarations
+ */
+extern struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage *mp,
+			    int flag);
+
+extern struct tlock *txMaplock(tid_t tid, struct inode *ip, int flag);
+
+extern int txCommit(tid_t tid, int nip, struct inode **iplist, int flag);
+
+extern tid_t txBegin(struct super_block *sb, int flag);
+
+extern void txBeginAnon(struct super_block *sb);
+
+extern void txEnd(tid_t tid);
+
+extern void txAbort(tid_t tid, int dirty);
+
+extern struct linelock *txLinelock(struct linelock * tlock);
+
+extern void txFreeMap(struct inode *ip, struct maplock * maplock,
+		      struct tblock * tblk, int maptype);
+
+extern void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea);
+
+extern void txFreelock(struct inode *ip);
+
+extern int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+		 struct tlock * tlck);
+
+extern void txQuiesce(struct super_block *sb);
+
+extern void txResume(struct super_block *sb);
+#endif				/* _H_JFS_TXNMGR */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_types.h linux-2.4.20/fs/jfs/jfs_types.h
--- linux-2.4.19/fs/jfs/jfs_types.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_types.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,186 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+#ifndef _H_JFS_TYPES
+#define	_H_JFS_TYPES
+
+/*
+ *	jfs_types.h:
+ *
+ * basic type/utility  definitions
+ *
+ * note: this header file must be the 1st include file
+ * of JFS include list in all JFS .c file.
+ */
+
+#include <linux/types.h>
+#include <linux/nls.h>
+
+/*
+ * transaction and lock id's
+ */
+typedef uint tid_t;
+typedef uint lid_t;
+
+/*
+ * Almost identical to Linux's timespec, but not quite
+ */
+struct timestruc_t {
+	u32 tv_sec;
+	u32 tv_nsec;
+};
+
+/*
+ *	handy
+ */
+
+#define LEFTMOSTONE	0x80000000
+#define	HIGHORDER	0x80000000u	/* high order bit on            */
+#define	ONES		0xffffffffu	/* all bit on                   */
+
+typedef int boolean_t;
+#define TRUE 1
+#define FALSE 0
+
+/*
+ *	logical xd (lxd)
+ */
+typedef struct {
+	unsigned len:24;
+	unsigned off1:8;
+	u32 off2;
+} lxd_t;
+
+/* lxd_t field construction */
+#define	LXDlength(lxd, length32)	( (lxd)->len = length32 )
+#define	LXDoffset(lxd, offset64)\
+{\
+	(lxd)->off1 = ((s64)offset64) >> 32;\
+	(lxd)->off2 = (offset64) & 0xffffffff;\
+}
+
+/* lxd_t field extraction */
+#define	lengthLXD(lxd)	( (lxd)->len )
+#define	offsetLXD(lxd)\
+	( ((s64)((lxd)->off1)) << 32 | (lxd)->off2 )
+
+/* lxd list */
+struct lxdlist {
+	s16 maxnlxd;
+	s16 nlxd;
+	lxd_t *lxd;
+};
+
+/*
+ *	physical xd (pxd)
+ */
+typedef struct {
+	unsigned len:24;
+	unsigned addr1:8;
+	u32 addr2;
+} pxd_t;
+
+/* xd_t field construction */
+
+#define	PXDlength(pxd, length32)	((pxd)->len = __cpu_to_le24(length32))
+#define	PXDaddress(pxd, address64)\
+{\
+	(pxd)->addr1 = ((s64)address64) >> 32;\
+	(pxd)->addr2 = __cpu_to_le32((address64) & 0xffffffff);\
+}
+
+/* xd_t field extraction */
+#define	lengthPXD(pxd)	__le24_to_cpu((pxd)->len)
+#define	addressPXD(pxd)\
+	( ((s64)((pxd)->addr1)) << 32 | __le32_to_cpu((pxd)->addr2))
+
+/* pxd list */
+struct pxdlist {
+	s16 maxnpxd;
+	s16 npxd;
+	pxd_t pxd[8];
+};
+
+
+/*
+ *	data extent descriptor (dxd)
+ */
+typedef struct {
+	unsigned flag:8;	/* 1: flags */
+	unsigned rsrvd:24;	/* 3: */
+	u32 size;		/* 4: size in byte */
+	unsigned len:24;	/* 3: length in unit of fsblksize */
+	unsigned addr1:8;	/* 1: address in unit of fsblksize */
+	u32 addr2;		/* 4: address in unit of fsblksize */
+} dxd_t;			/* - 16 - */
+
+/* dxd_t flags */
+#define	DXD_INDEX	0x80	/* B+-tree index */
+#define	DXD_INLINE	0x40	/* in-line data extent */
+#define	DXD_EXTENT	0x20	/* out-of-line single extent */
+#define	DXD_FILE	0x10	/* out-of-line file (inode) */
+#define DXD_CORRUPT	0x08	/* Inconsistency detected */
+
+/* dxd_t field construction
+ *	Conveniently, the PXD macros work for DXD
+ */
+#define	DXDlength	PXDlength
+#define	DXDaddress	PXDaddress
+#define	lengthDXD	lengthPXD
+#define	addressDXD	addressPXD
+#define	DXDsize(dxd, size32) ((dxd)->size = cpu_to_le32(size32))
+#define	sizeDXD(dxd)	le32_to_cpu((dxd)->size)
+
+/*
+ *      directory entry argument
+ */
+struct component_name {
+	int namlen;
+	wchar_t *name;
+};
+
+
+/*
+ *	DASD limit information - stored in directory inode
+ */
+struct dasd {
+	u8 thresh;		/* Alert Threshold (in percent) */
+	u8 delta;		/* Alert Threshold delta (in percent)   */
+	u8 rsrvd1;
+	u8 limit_hi;		/* DASD limit (in logical blocks)       */
+	u32 limit_lo;		/* DASD limit (in logical blocks)       */
+	u8 rsrvd2[3];
+	u8 used_hi;		/* DASD usage (in logical blocks)       */
+	u32 used_lo;		/* DASD usage (in logical blocks)       */
+};
+
+#define DASDLIMIT(dasdp) \
+	(((u64)((dasdp)->limit_hi) << 32) + __le32_to_cpu((dasdp)->limit_lo))
+#define setDASDLIMIT(dasdp, limit)\
+{\
+	(dasdp)->limit_hi = ((u64)limit) >> 32;\
+	(dasdp)->limit_lo = __cpu_to_le32(limit);\
+}
+#define DASDUSED(dasdp) \
+	(((u64)((dasdp)->used_hi) << 32) + __le32_to_cpu((dasdp)->used_lo))
+#define setDASDUSED(dasdp, used)\
+{\
+	(dasdp)->used_hi = ((u64)used) >> 32;\
+	(dasdp)->used_lo = __cpu_to_le32(used);\
+}
+
+#endif				/* !_H_JFS_TYPES */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_umount.c linux-2.4.20/fs/jfs/jfs_umount.c
--- linux-2.4.19/fs/jfs/jfs_umount.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_umount.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,166 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+
+/*
+ *	jfs_umount.c
+ *
+ * note: file system in transition to aggregate/fileset:
+ * (ref. jfs_mount.c)
+ *
+ * file system unmount is interpreted as mount of the single/only 
+ * fileset in the aggregate and, if unmount of the last fileset, 
+ * as unmount of the aggerate;
+ */
+
+#include <linux/fs.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_superblock.h"
+#include "jfs_dmap.h"
+#include "jfs_imap.h"
+#include "jfs_metapage.h"
+#include "jfs_debug.h"
+
+/*
+ * NAME:	jfs_umount(vfsp, flags, crp)
+ *
+ * FUNCTION:	vfs_umount()
+ *
+ * PARAMETERS:	vfsp	- virtual file system pointer
+ *		flags	- unmount for shutdown
+ *		crp	- credential
+ *
+ * RETURN :	EBUSY	- device has open files
+ */
+int jfs_umount(struct super_block *sb)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	struct inode *ipbmap = sbi->ipbmap;
+	struct inode *ipimap = sbi->ipimap;
+	struct inode *ipaimap = sbi->ipaimap;
+	struct inode *ipaimap2 = sbi->ipaimap2;
+	struct jfs_log *log;
+	int rc = 0;
+
+	jFYI(1, ("\n	UnMount JFS: sb:0x%p\n", sb));
+
+	/*
+	 *      update superblock and close log 
+	 *
+	 * if mounted read-write and log based recovery was enabled
+	 */
+	if ((log = sbi->log))
+		/*
+		 * Wait for outstanding transactions to be written to log: 
+		 */
+		lmLogWait(log);
+
+	/*
+	 * close fileset inode allocation map (aka fileset inode)
+	 */
+	jEVENT(0, ("jfs_umount: close ipimap:0x%p\n", ipimap));
+	diUnmount(ipimap, 0);
+
+	diFreeSpecial(ipimap);
+	sbi->ipimap = NULL;
+
+	/*
+	 * close secondary aggregate inode allocation map
+	 */
+	ipaimap2 = sbi->ipaimap2;
+	if (ipaimap2) {
+		jEVENT(0, ("jfs_umount: close ipaimap2:0x%p\n", ipaimap2));
+		diUnmount(ipaimap2, 0);
+		diFreeSpecial(ipaimap2);
+		sbi->ipaimap2 = NULL;
+	}
+
+	/*
+	 * close aggregate inode allocation map
+	 */
+	ipaimap = sbi->ipaimap;
+	jEVENT(0, ("jfs_umount: close ipaimap:0x%p\n", ipaimap));
+	diUnmount(ipaimap, 0);
+	diFreeSpecial(ipaimap);
+	sbi->ipaimap = NULL;
+
+	/*
+	 * close aggregate block allocation map
+	 */
+	jEVENT(0, ("jfs_umount: close ipbmap:%p\n", ipbmap));
+	dbUnmount(ipbmap, 0);
+
+	diFreeSpecial(ipbmap);
+	sbi->ipimap = NULL;
+
+	/*
+	 * Make sure all metadata makes it to disk before we mark
+	 * the superblock as clean
+	 */
+	fsync_inode_data_buffers(sb->s_bdev->bd_inode);
+
+	/*
+	 * ensure all file system file pages are propagated to their
+	 * home blocks on disk (and their in-memory buffer pages are 
+	 * invalidated) BEFORE updating file system superblock state
+	 * (to signify file system is unmounted cleanly, and thus in 
+	 * consistent state) and log superblock active file system 
+	 * list (to signify skip logredo()).
+	 */
+	if (log) {		/* log = NULL if read-only mount */
+		rc = updateSuper(sb, FM_CLEAN);
+
+		/*
+		 * close log: 
+		 *
+		 * remove file system from log active file system list.
+		 */
+		rc = lmLogClose(sb, log);
+	}
+	jFYI(0, ("	UnMount JFS Complete: %d\n", rc));
+	return rc;
+}
+
+
+int jfs_umount_rw(struct super_block *sb)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	struct jfs_log *log = sbi->log;
+
+	if (!log)
+		return 0;
+
+	/*
+	 * close log: 
+	 *
+	 * remove file system from log active file system list.
+	 */
+	lmLogWait(log);
+
+	/*
+	 * Make sure all metadata makes it to disk
+	 */
+	dbSync(sbi->ipbmap);
+	diSync(sbi->ipimap);
+	fsync_inode_data_buffers(sb->s_bdev->bd_inode);
+
+	updateSuper(sb, FM_CLEAN);
+	sbi->log = NULL;
+
+	return lmLogClose(sb, log);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_unicode.c linux-2.4.20/fs/jfs/jfs_unicode.c
--- linux-2.4.19/fs/jfs/jfs_unicode.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_unicode.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,110 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include "jfs_types.h"
+#include "jfs_filsys.h"
+#include "jfs_unicode.h"
+#include "jfs_debug.h"
+
+/*
+ * NAME:	jfs_strfromUCS()
+ *
+ * FUNCTION:	Convert little-endian unicode string to character string
+ *
+ */
+int jfs_strfromUCS_le(char *to, const wchar_t * from,	/* LITTLE ENDIAN */
+		      int len, struct nls_table *codepage)
+{
+	int i;
+	int outlen = 0;
+
+	for (i = 0; (i < len) && from[i]; i++) {
+		int charlen;
+		charlen =
+		    codepage->uni2char(le16_to_cpu(from[i]), &to[outlen],
+				       NLS_MAX_CHARSET_SIZE);
+		if (charlen > 0) {
+			outlen += charlen;
+		} else {
+			to[outlen++] = '?';
+		}
+	}
+	to[outlen] = 0;
+	jEVENT(0, ("jfs_strfromUCS returning %d - '%s'\n", outlen, to));
+	return outlen;
+}
+
+/*
+ * NAME:	jfs_strtoUCS()
+ *
+ * FUNCTION:	Convert character string to unicode string
+ *
+ */
+int jfs_strtoUCS(wchar_t * to,
+		 const char *from, int len, struct nls_table *codepage)
+{
+	int charlen;
+	int i;
+
+	jEVENT(0, ("jfs_strtoUCS - '%s'\n", from));
+
+	for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
+		charlen = codepage->char2uni(from, len, &to[i]);
+		if (charlen < 1) {
+			jERROR(1, ("jfs_strtoUCS: char2uni returned %d.\n",
+				   charlen));
+			jERROR(1, ("charset = %s, char = 0x%x\n",
+				   codepage->charset, (unsigned char) *from));
+			to[i] = 0x003f;	/* a question mark */
+			charlen = 1;
+		}
+	}
+
+	jEVENT(0, (" returning %d\n", i));
+
+	to[i] = 0;
+	return i;
+}
+
+/*
+ * NAME:	get_UCSname()
+ *
+ * FUNCTION:	Allocate and translate to unicode string
+ *
+ */
+int get_UCSname(struct component_name * uniName, struct dentry *dentry,
+		struct nls_table *nls_tab)
+{
+	int length = dentry->d_name.len;
+
+	if (length > JFS_NAME_MAX)
+		return ENAMETOOLONG;
+
+	uniName->name =
+	    kmalloc((length + 1) * sizeof(wchar_t), GFP_NOFS);
+
+	if (uniName->name == NULL)
+		return ENOSPC;
+
+	uniName->namlen = jfs_strtoUCS(uniName->name, dentry->d_name.name,
+				       length, nls_tab);
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_unicode.h linux-2.4.20/fs/jfs/jfs_unicode.h
--- linux-2.4.19/fs/jfs/jfs_unicode.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_unicode.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,140 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *
+ *   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
+ */
+#ifndef _H_JFS_UNICODE
+#define _H_JFS_UNICODE
+
+#include <asm/byteorder.h>
+#include "jfs_types.h"
+
+typedef struct {
+	wchar_t start;
+	wchar_t end;
+	signed char *table;
+} UNICASERANGE;
+
+extern signed char UniUpperTable[512];
+extern UNICASERANGE UniUpperRange[];
+extern int get_UCSname(struct component_name *, struct dentry *,
+		       struct nls_table *);
+extern int jfs_strfromUCS_le(char *, const wchar_t *, int, struct nls_table *);
+
+#define free_UCSname(COMP) kfree((COMP)->name)
+
+/*
+ * UniStrcpy:  Copy a string
+ */
+static inline wchar_t *UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2)
+{
+	wchar_t *anchor = ucs1;	/* save the start of result string */
+
+	while ((*ucs1++ = *ucs2++));
+	return anchor;
+}
+
+
+
+/*
+ * UniStrncpy:  Copy length limited string with pad
+ */
+static inline wchar_t *UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2,
+				  size_t n)
+{
+	wchar_t *anchor = ucs1;
+
+	while (n-- && *ucs2)	/* Copy the strings */
+		*ucs1++ = *ucs2++;
+
+	n++;
+	while (n--)		/* Pad with nulls */
+		*ucs1++ = 0;
+	return anchor;
+}
+
+/*
+ * UniStrncmp_le:  Compare length limited string - native to little-endian
+ */
+static inline int UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2,
+				size_t n)
+{
+	if (!n)
+		return 0;	/* Null strings are equal */
+	while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
+		ucs1++;
+		ucs2++;
+	}
+	return (int) *ucs1 - (int) __le16_to_cpu(*ucs2);
+}
+
+/*
+ * UniStrncpy_le:  Copy length limited string with pad to little-endian
+ */
+static inline wchar_t *UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2,
+				     size_t n)
+{
+	wchar_t *anchor = ucs1;
+
+	while (n-- && *ucs2)	/* Copy the strings */
+		*ucs1++ = __le16_to_cpu(*ucs2++);
+
+	n++;
+	while (n--)		/* Pad with nulls */
+		*ucs1++ = 0;
+	return anchor;
+}
+
+
+/*
+ * UniToupper:  Convert a unicode character to upper case
+ */
+static inline wchar_t UniToupper(wchar_t uc)
+{
+	UNICASERANGE *rp;
+
+	if (uc < sizeof(UniUpperTable)) {	/* Latin characters */
+		return uc + UniUpperTable[uc];	/* Use base tables */
+	} else {
+		rp = UniUpperRange;	/* Use range tables */
+		while (rp->start) {
+			if (uc < rp->start)	/* Before start of range */
+				return uc;	/* Uppercase = input */
+			if (uc <= rp->end)	/* In range */
+				return uc + rp->table[uc - rp->start];
+			rp++;	/* Try next range */
+		}
+	}
+	return uc;		/* Past last range */
+}
+
+
+/*
+ * UniStrupr:  Upper case a unicode string
+ */
+static inline wchar_t *UniStrupr(wchar_t * upin)
+{
+	wchar_t *up;
+
+	up = upin;
+	while (*up) {		/* For all characters */
+		*up = UniToupper(*up);
+		up++;
+	}
+	return upin;		/* Return input pointer */
+}
+
+#endif				/* !_H_JFS_UNICODE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_uniupr.c linux-2.4.20/fs/jfs/jfs_uniupr.c
--- linux-2.4.19/fs/jfs/jfs_uniupr.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_uniupr.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,134 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+
+#include <linux/fs.h>
+#include "jfs_unicode.h"
+
+/*
+ * Latin upper case
+ */
+signed char UniUpperTable[512] = {
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 000-00f */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 010-01f */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 020-02f */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 030-03f */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 040-04f */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 050-05f */
+   0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 060-06f */
+ -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,  0,  0,  0,  0,  0, /* 070-07f */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 080-08f */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 090-09f */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 0a0-0af */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 0b0-0bf */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 0c0-0cf */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 0d0-0df */
+ -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 0e0-0ef */
+ -32,-32,-32,-32,-32,-32,-32,  0,-32,-32,-32,-32,-32,-32,-32,121, /* 0f0-0ff */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 100-10f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 110-11f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 120-12f */
+   0,  0,  0, -1,  0, -1,  0, -1,  0,  0, -1,  0, -1,  0, -1,  0, /* 130-13f */
+  -1,  0, -1,  0, -1,  0, -1,  0, -1,  0,  0, -1,  0, -1,  0, -1, /* 140-14f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 150-15f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 160-16f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0,  0, -1,  0, -1,  0, -1,  0, /* 170-17f */
+   0,  0,  0, -1,  0, -1,  0,  0, -1,  0,  0,  0, -1,  0,  0,  0, /* 180-18f */
+   0,  0, -1,  0,  0,  0,  0,  0,  0, -1,  0,  0,  0,  0,  0,  0, /* 190-19f */
+   0, -1,  0, -1,  0, -1,  0,  0, -1,  0,  0,  0,  0, -1,  0,  0, /* 1a0-1af */
+  -1,  0,  0,  0, -1,  0, -1,  0,  0, -1,  0,  0,  0, -1,  0,  0, /* 1b0-1bf */
+   0,  0,  0,  0,  0, -1, -2,  0, -1, -2,  0, -1, -2,  0, -1,  0, /* 1c0-1cf */
+  -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,-79,  0, -1, /* 1d0-1df */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e0-1ef */
+   0,  0, -1, -2,  0, -1,  0,  0,  0, -1,  0, -1,  0, -1,  0, -1, /* 1f0-1ff */
+};
+
+/* Upper case range - Greek */
+static signed char UniCaseRangeU03a0[47] = {
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,-38,-37,-37,-37, /* 3a0-3af */
+   0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 3b0-3bf */
+ -32,-32,-31,-32,-32,-32,-32,-32,-32,-32,-32,-32,-64,-63,-63,
+};
+
+/* Upper case range - Cyrillic */
+static signed char UniCaseRangeU0430[48] = {
+ -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 430-43f */
+ -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 440-44f */
+   0,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80,  0,-80,-80, /* 450-45f */
+};
+
+/* Upper case range - Extended cyrillic */
+static signed char UniCaseRangeU0490[61] = {
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 490-49f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 4a0-4af */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 4b0-4bf */
+   0,  0, -1,  0, -1,  0,  0,  0, -1,  0,  0,  0, -1,
+};
+
+/* Upper case range - Extended latin and greek */
+static signed char UniCaseRangeU1e00[509] = {
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e00-1e0f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e10-1e1f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e20-1e2f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e30-1e3f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e40-1e4f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e50-1e5f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e60-1e6f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e70-1e7f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e80-1e8f */
+   0, -1,  0, -1,  0, -1,  0,  0,  0,  0,  0,-59,  0, -1,  0, -1, /* 1e90-1e9f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1ea0-1eaf */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1eb0-1ebf */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1ec0-1ecf */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1ed0-1edf */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1ee0-1eef */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0,  0,  0,  0,  0,  0, /* 1ef0-1eff */
+   8,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f00-1f0f */
+   8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f10-1f1f */
+   8,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f20-1f2f */
+   8,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f30-1f3f */
+   8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f40-1f4f */
+   0,  8,  0,  8,  0,  8,  0,  8,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f50-1f5f */
+   8,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f60-1f6f */
+  74, 74, 86, 86, 86, 86,100,100,  0,  0,112,112,126,126,  0,  0, /* 1f70-1f7f */
+   8,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f80-1f8f */
+   8,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f90-1f9f */
+   8,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0, /* 1fa0-1faf */
+   8,  8,  0,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 1fb0-1fbf */
+   0,  0,  0,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 1fc0-1fcf */
+   8,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 1fd0-1fdf */
+   8,  8,  0,  0,  0,  7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 1fe0-1fef */
+   0,  0,  0,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+};
+
+/* Upper case range - Wide latin */
+static signed char UniCaseRangeUff40[27] = {
+   0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* ff40-ff4f */
+ -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,
+};
+
+/*
+ * Upper Case Range
+ */
+UNICASERANGE UniUpperRange[] = {
+    { 0x03a0,  0x03ce,  UniCaseRangeU03a0 },
+    { 0x0430,  0x045f,  UniCaseRangeU0430 },
+    { 0x0490,  0x04cc,  UniCaseRangeU0490 },
+    { 0x1e00,  0x1ffc,  UniCaseRangeU1e00 },
+    { 0xff40,  0xff5a,  UniCaseRangeUff40 },
+    { 0, 0, 0 }
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_xattr.h linux-2.4.20/fs/jfs/jfs_xattr.h
--- linux-2.4.19/fs/jfs/jfs_xattr.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_xattr.h	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,62 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+
+#ifndef H_JFS_XATTR
+#define H_JFS_XATTR
+
+/*
+ * jfs_ea_list describe the on-disk format of the extended attributes.
+ * I know the null-terminator is redundant since namelen is stored, but
+ * I am maintaining compatibility with OS/2 where possible.
+ */
+struct jfs_ea {
+	u8 flag;	/* Unused? */
+	u8 namelen;	/* Length of name */
+	u16 valuelen;	/* Length of value */
+	char name[0];	/* Attribute name (includes null-terminator) */
+};			/* Value immediately follows name */
+
+struct jfs_ea_list {
+	u32 size;		/* overall size */
+	struct jfs_ea ea[0];	/* Variable length list */
+};
+
+/* Macros for defining maxiumum number of bytes supported for EAs */
+#define MAXEASIZE	65535
+#define MAXEALISTSIZE	MAXEASIZE
+
+/*
+ * some macros for dealing with variable length EA lists.
+ */
+#define EA_SIZE(ea) \
+	(sizeof (struct jfs_ea) + (ea)->namelen + 1 + \
+	 le16_to_cpu((ea)->valuelen))
+#define	NEXT_EA(ea) ((struct jfs_ea *) (((char *) (ea)) + (EA_SIZE (ea))))
+#define	FIRST_EA(ealist) ((ealist)->ea)
+#define	EALIST_SIZE(ealist) le32_to_cpu((ealist)->size)
+#define	END_EALIST(ealist) \
+	((struct jfs_ea *) (((char *) (ealist)) + EALIST_SIZE(ealist)))
+
+extern int __jfs_setxattr(struct inode *, const char *, void *, size_t, int);
+extern int jfs_setxattr(struct dentry *, const char *, void *, size_t, int);
+extern ssize_t __jfs_getxattr(struct inode *, const char *, void *, size_t);
+extern ssize_t jfs_getxattr(struct dentry *, const char *, void *, size_t);
+extern ssize_t jfs_listxattr(struct dentry *, char *, size_t);
+extern int jfs_removexattr(struct dentry *, const char *);
+
+#endif	/* H_JFS_XATTR */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_xtree.c linux-2.4.20/fs/jfs/jfs_xtree.c
--- linux-2.4.19/fs/jfs/jfs_xtree.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_xtree.c	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,4432 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+/*
+ *      jfs_xtree.c: extent allocation descriptor B+-tree manager
+ */
+
+#include <linux/fs.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_metapage.h"
+#include "jfs_dmap.h"
+#include "jfs_dinode.h"
+#include "jfs_superblock.h"
+#include "jfs_debug.h"
+
+/*
+ * xtree local flag
+ */
+#define XT_INSERT       0x00000001
+
+/*
+ *       xtree key/entry comparison: extent offset
+ *
+ * return:
+ *      -1: k < start of extent
+ *       0: start_of_extent <= k <= end_of_extent
+ *       1: k > end_of_extent
+ */
+#define XT_CMP(CMP, K, X, OFFSET64)\
+{\
+        OFFSET64 = offsetXAD(X);\
+        (CMP) = ((K) >= OFFSET64 + lengthXAD(X)) ? 1 :\
+              ((K) < OFFSET64) ? -1 : 0;\
+}
+
+/* write a xad entry */
+#define XT_PUTENTRY(XAD, FLAG, OFF, LEN, ADDR)\
+{\
+        (XAD)->flag = (FLAG);\
+        XADoffset((XAD), (OFF));\
+        XADlength((XAD), (LEN));\
+        XADaddress((XAD), (ADDR));\
+}
+
+#define XT_PAGE(IP, MP) BT_PAGE(IP, MP, xtpage_t, i_xtroot)
+
+/* get page buffer for specified block address */
+#define XT_GETPAGE(IP, BN, MP, SIZE, P, RC)\
+{\
+        BT_GETPAGE(IP, BN, MP, xtpage_t, SIZE, P, RC, i_xtroot)\
+        if (!(RC))\
+        {\
+                if ((le16_to_cpu((P)->header.nextindex) < XTENTRYSTART) ||\
+                    (le16_to_cpu((P)->header.nextindex) > le16_to_cpu((P)->header.maxentry)) ||\
+                    (le16_to_cpu((P)->header.maxentry) > (((BN)==0)?XTROOTMAXSLOT:PSIZE>>L2XTSLOTSIZE)))\
+                {\
+                        jERROR(1,("XT_GETPAGE: xtree page corrupt\n"));\
+			BT_PUTPAGE(MP);\
+			updateSuper((IP)->i_sb, FM_DIRTY);\
+			MP = NULL;\
+                        RC = EIO;\
+                }\
+        }\
+}
+
+/* for consistency */
+#define XT_PUTPAGE(MP) BT_PUTPAGE(MP)
+
+#define XT_GETSEARCH(IP, LEAF, BN, MP,  P, INDEX) \
+	BT_GETSEARCH(IP, LEAF, BN, MP, xtpage_t, P, INDEX, i_xtroot)
+/* xtree entry parameter descriptor */
+struct xtsplit {
+	struct metapage *mp;
+	s16 index;
+	u8 flag;
+	s64 off;
+	s64 addr;
+	int len;
+	struct pxdlist *pxdlist;
+};
+
+
+/*
+ *      statistics
+ */
+#ifdef CONFIG_JFS_STATISTICS
+static struct {
+	uint search;
+	uint fastSearch;
+	uint split;
+} xtStat;
+#endif
+
+
+/*
+ * forward references
+ */
+static int xtSearch(struct inode *ip,
+		    s64 xoff, int *cmpp, struct btstack * btstack, int flag);
+
+static int xtSplitUp(tid_t tid,
+		     struct inode *ip,
+		     struct xtsplit * split, struct btstack * btstack);
+
+static int xtSplitPage(tid_t tid, struct inode *ip, struct xtsplit * split,
+		       struct metapage ** rmpp, s64 * rbnp);
+
+static int xtSplitRoot(tid_t tid, struct inode *ip,
+		       struct xtsplit * split, struct metapage ** rmpp);
+
+#ifdef _STILL_TO_PORT
+static int xtDeleteUp(tid_t tid, struct inode *ip, struct metapage * fmp,
+		      xtpage_t * fp, struct btstack * btstack);
+
+static int xtSearchNode(struct inode *ip,
+			xad_t * xad,
+			int *cmpp, struct btstack * btstack, int flag);
+
+static int xtRelink(tid_t tid, struct inode *ip, xtpage_t * fp);
+#endif				/*  _STILL_TO_PORT */
+
+/* External references */
+
+/*
+ *      debug control
+ */
+/*      #define _JFS_DEBUG_XTREE        1 */
+
+
+/*
+ *      xtLookup()
+ *
+ * function: map a single page into a physical extent;
+ */
+int xtLookup(struct inode *ip, s64 lstart,
+	     s64 llen, int *pflag, s64 * paddr, s32 * plen, int no_check)
+{
+	int rc = 0;
+	struct btstack btstack;
+	int cmp;
+	s64 bn;
+	struct metapage *mp;
+	xtpage_t *p;
+	int index;
+	xad_t *xad;
+	s64 size, xoff, xend;
+	int xlen;
+	s64 xaddr;
+
+	*plen = 0;
+
+	if (!no_check) {
+		/* is lookup offset beyond eof ? */
+		size = ((u64) ip->i_size + (JFS_SBI(ip->i_sb)->bsize - 1)) >>
+		    JFS_SBI(ip->i_sb)->l2bsize;
+		if (lstart >= size) {
+			jERROR(1,
+			       ("xtLookup: lstart (0x%lx) >= size (0x%lx)\n",
+				(ulong) lstart, (ulong) size));
+			return 0;
+		}
+	}
+
+	/*
+	 * search for the xad entry covering the logical extent
+	 */
+//search:
+	if ((rc = xtSearch(ip, lstart, &cmp, &btstack, 0))) {
+		jERROR(1, ("xtLookup: xtSearch returned %d\n", rc));
+		return rc;
+	}
+
+	/*
+	 *      compute the physical extent covering logical extent
+	 *
+	 * N.B. search may have failed (e.g., hole in sparse file),
+	 * and returned the index of the next entry.
+	 */
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+	/* is xad found covering start of logical extent ?
+	 * lstart is a page start address,
+	 * i.e., lstart cannot start in a hole;
+	 */
+	if (cmp) {
+		jFYI(1, ("xtLookup: cmp = %d\n", cmp));
+		goto out;
+	}
+
+	/*
+	 * lxd covered by xad
+	 */
+	xad = &p->xad[index];
+	xoff = offsetXAD(xad);
+	xlen = lengthXAD(xad);
+	xend = xoff + xlen;
+	xaddr = addressXAD(xad);
+
+	jEVENT(0,
+	       ("index = %d, xoff = 0x%lx, xlen = 0x%x, xaddr = 0x%lx\n",
+		index, (ulong) xoff, xlen, (ulong) xaddr));
+
+	/* initialize new pxd */
+	*pflag = xad->flag;
+	*paddr = xaddr + (lstart - xoff);
+	/* a page must be fully covered by an xad */
+	*plen = min(xend - lstart, llen);
+
+      out:
+	XT_PUTPAGE(mp);
+
+	return rc;
+}
+
+
+/*
+ *      xtLookupList()
+ *
+ * function: map a single logical extent into a list of physical extent;
+ *
+ * parameter:
+ *      struct inode    *ip,
+ *      struct lxdlist  *lxdlist,       lxd list (in)
+ *      struct xadlist  *xadlist,       xad list (in/out)
+ *      int		flag)
+ *
+ * coverage of lxd by xad under assumption of
+ * . lxd's are ordered and disjoint.
+ * . xad's are ordered and disjoint.
+ *
+ * return:
+ *      0:      success
+ *
+ * note: a page being written (even a single byte) is backed fully,
+ *      except the last page which is only backed with blocks
+ *      required to cover the last byte;
+ *      the extent backing a page is fully contained within an xad;
+ */
+int xtLookupList(struct inode *ip, struct lxdlist * lxdlist,
+		 struct xadlist * xadlist, int flag)
+{
+	int rc = 0;
+	struct btstack btstack;
+	int cmp;
+	s64 bn;
+	struct metapage *mp;
+	xtpage_t *p;
+	int index;
+	lxd_t *lxd;
+	xad_t *xad, *pxd;
+	s64 size, lstart, lend, xstart, xend, pstart;
+	s64 llen, xlen, plen;
+	s64 xaddr, paddr;
+	int nlxd, npxd, maxnpxd;
+
+	npxd = xadlist->nxad = 0;
+	maxnpxd = xadlist->maxnxad;
+	pxd = xadlist->xad;
+
+	nlxd = lxdlist->nlxd;
+	lxd = lxdlist->lxd;
+
+	lstart = offsetLXD(lxd);
+	llen = lengthLXD(lxd);
+	lend = lstart + llen;
+
+	size = (ip->i_size + (JFS_SBI(ip->i_sb)->bsize - 1)) >>
+	    JFS_SBI(ip->i_sb)->l2bsize;
+
+	/*
+	 * search for the xad entry covering the logical extent
+	 */
+      search:
+	if (lstart >= size)
+		return 0;
+
+	if ((rc = xtSearch(ip, lstart, &cmp, &btstack, 0)))
+		return rc;
+
+	/*
+	 *      compute the physical extent covering logical extent
+	 *
+	 * N.B. search may have failed (e.g., hole in sparse file),
+	 * and returned the index of the next entry.
+	 */
+//map:
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+	/* is xad on the next sibling page ? */
+	if (index == le16_to_cpu(p->header.nextindex)) {
+		if (p->header.flag & BT_ROOT)
+			goto mapend;
+
+		if ((bn = le64_to_cpu(p->header.next)) == 0)
+			goto mapend;
+
+		XT_PUTPAGE(mp);
+
+		/* get next sibling page */
+		XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		index = XTENTRYSTART;
+	}
+
+	xad = &p->xad[index];
+
+	/*
+	 * is lxd covered by xad ?
+	 */
+      compare:
+	xstart = offsetXAD(xad);
+	xlen = lengthXAD(xad);
+	xend = xstart + xlen;
+	xaddr = addressXAD(xad);
+
+      compare1:
+	if (xstart < lstart)
+		goto compare2;
+
+	/* (lstart <= xstart) */
+
+	/* lxd is NOT covered by xad */
+	if (lend <= xstart) {
+		/*
+		 * get next lxd
+		 */
+		if (--nlxd == 0)
+			goto mapend;
+		lxd++;
+
+		lstart = offsetLXD(lxd);
+		llen = lengthLXD(lxd);
+		lend = lstart + llen;
+		if (lstart >= size)
+			goto mapend;
+
+		/* compare with the current xad  */
+		goto compare1;
+	}
+	/* lxd is covered by xad */
+	else {			/* (xstart < lend) */
+
+		/* initialize new pxd */
+		pstart = xstart;
+		plen = min(lend - xstart, xlen);
+		paddr = xaddr;
+
+		goto cover;
+	}
+
+	/* (xstart < lstart) */
+      compare2:
+	/* lxd is covered by xad */
+	if (lstart < xend) {
+		/* initialize new pxd */
+		pstart = lstart;
+		plen = min(xend - lstart, llen);
+		paddr = xaddr + (lstart - xstart);
+
+		goto cover;
+	}
+	/* lxd is NOT covered by xad */
+	else {			/* (xend <= lstart) */
+
+		/*
+		 * get next xad
+		 *
+		 * linear search next xad covering lxd on
+		 * the current xad page, and then tree search
+		 */
+		if (index == le16_to_cpu(p->header.nextindex) - 1) {
+			if (p->header.flag & BT_ROOT)
+				goto mapend;
+
+			XT_PUTPAGE(mp);
+			goto search;
+		} else {
+			index++;
+			xad++;
+
+			/* compare with new xad */
+			goto compare;
+		}
+	}
+
+	/*
+	 * lxd is covered by xad and a new pxd has been initialized
+	 * (lstart <= xstart < lend) or (xstart < lstart < xend)
+	 */
+      cover:
+	/* finalize pxd corresponding to current xad */
+	XT_PUTENTRY(pxd, xad->flag, pstart, plen, paddr);
+
+	if (++npxd >= maxnpxd)
+		goto mapend;
+	pxd++;
+
+	/*
+	 * lxd is fully covered by xad
+	 */
+	if (lend <= xend) {
+		/*
+		 * get next lxd
+		 */
+		if (--nlxd == 0)
+			goto mapend;
+		lxd++;
+
+		lstart = offsetLXD(lxd);
+		llen = lengthLXD(lxd);
+		lend = lstart + llen;
+		if (lstart >= size)
+			goto mapend;
+
+		/*
+		 * test for old xad covering new lxd
+		 * (old xstart < new lstart)
+		 */
+		goto compare2;
+	}
+	/*
+	 * lxd is partially covered by xad
+	 */
+	else {			/* (xend < lend)  */
+
+		/*
+		 * get next xad
+		 *
+		 * linear search next xad covering lxd on
+		 * the current xad page, and then next xad page search
+		 */
+		if (index == le16_to_cpu(p->header.nextindex) - 1) {
+			if (p->header.flag & BT_ROOT)
+				goto mapend;
+
+			if ((bn = le64_to_cpu(p->header.next)) == 0)
+				goto mapend;
+
+			XT_PUTPAGE(mp);
+
+			/* get next sibling page */
+			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+			if (rc)
+				return rc;
+
+			index = XTENTRYSTART;
+			xad = &p->xad[index];
+		} else {
+			index++;
+			xad++;
+		}
+
+		/*
+		 * test for new xad covering old lxd
+		 * (old lstart < new xstart)
+		 */
+		goto compare;
+	}
+
+      mapend:
+	xadlist->nxad = npxd;
+
+//out:
+	XT_PUTPAGE(mp);
+
+	return rc;
+}
+
+
+/*
+ *      xtSearch()
+ *
+ * function:    search for the xad entry covering specified offset.
+ *
+ * parameters:
+ *      ip      - file object;
+ *      xoff    - extent offset;
+ *      cmpp    - comparison result:
+ *      btstack - traverse stack;
+ *      flag    - search process flag (XT_INSERT);
+ *
+ * returns:
+ *      btstack contains (bn, index) of search path traversed to the entry.
+ *      *cmpp is set to result of comparison with the entry returned.
+ *      the page containing the entry is pinned at exit.
+ */
+static int xtSearch(struct inode *ip, s64 xoff,	/* offset of extent */
+		    int *cmpp, struct btstack * btstack, int flag)
+{
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	int rc = 0;
+	int cmp = 1;		/* init for empty page */
+	s64 bn;			/* block number */
+	struct metapage *mp;	/* page buffer */
+	xtpage_t *p;		/* page */
+	xad_t *xad;
+	int base, index, lim, btindex;
+	struct btframe *btsp;
+	int nsplit = 0;		/* number of pages to split */
+	s64 t64;
+
+	INCREMENT(xtStat.search);
+
+	BT_CLR(btstack);
+
+	btstack->nsplit = 0;
+
+	/*
+	 *      search down tree from root:
+	 *
+	 * between two consecutive entries of <Ki, Pi> and <Kj, Pj> of
+	 * internal page, child page Pi contains entry with k, Ki <= K < Kj.
+	 *
+	 * if entry with search key K is not found
+	 * internal page search find the entry with largest key Ki
+	 * less than K which point to the child page to search;
+	 * leaf page search find the entry with smallest key Kj
+	 * greater than K so that the returned index is the position of
+	 * the entry to be shifted right for insertion of new entry.
+	 * for empty tree, search key is greater than any key of the tree.
+	 *
+	 * by convention, root bn = 0.
+	 */
+	for (bn = 0;;) {
+		/* get/pin the page to search */
+		XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		/* try sequential access heuristics with the previous
+		 * access entry in target leaf page:
+		 * once search narrowed down into the target leaf,
+		 * key must either match an entry in the leaf or
+		 * key entry does not exist in the tree;
+		 */
+//fastSearch:
+		if ((jfs_ip->btorder & BT_SEQUENTIAL) &&
+		    (p->header.flag & BT_LEAF) &&
+		    (index = jfs_ip->btindex) <
+		    le16_to_cpu(p->header.nextindex)) {
+			xad = &p->xad[index];
+			t64 = offsetXAD(xad);
+			if (xoff < t64 + lengthXAD(xad)) {
+				if (xoff >= t64) {
+					*cmpp = 0;
+					goto out;
+				}
+
+				/* stop sequential access heuristics */
+				goto binarySearch;
+			} else {	/* (t64 + lengthXAD(xad)) <= xoff */
+
+				/* try next sequential entry */
+				index++;
+				if (index <
+				    le16_to_cpu(p->header.nextindex)) {
+					xad++;
+					t64 = offsetXAD(xad);
+					if (xoff < t64 + lengthXAD(xad)) {
+						if (xoff >= t64) {
+							*cmpp = 0;
+							goto out;
+						}
+
+						/* miss: key falls between
+						 * previous and this entry
+						 */
+						*cmpp = 1;
+						goto out;
+					}
+
+					/* (xoff >= t64 + lengthXAD(xad));
+					 * matching entry may be further out:
+					 * stop heuristic search
+					 */
+					/* stop sequential access heuristics */
+					goto binarySearch;
+				}
+
+				/* (index == p->header.nextindex);
+				 * miss: key entry does not exist in
+				 * the target leaf/tree
+				 */
+				*cmpp = 1;
+				goto out;
+			}
+
+			/*
+			 * if hit, return index of the entry found, and
+			 * if miss, where new entry with search key is
+			 * to be inserted;
+			 */
+		      out:
+			/* compute number of pages to split */
+			if (flag & XT_INSERT) {
+				if (p->header.nextindex ==	/* little-endian */
+				    p->header.maxentry)
+					nsplit++;
+				else
+					nsplit = 0;
+				btstack->nsplit = nsplit;
+			}
+
+			/* save search result */
+			btsp = btstack->top;
+			btsp->bn = bn;
+			btsp->index = index;
+			btsp->mp = mp;
+
+			/* update sequential access heuristics */
+			jfs_ip->btindex = index;
+
+			INCREMENT(xtStat.fastSearch);
+			return 0;
+		}
+
+		/* well, ... full search now */
+	      binarySearch:
+		lim = le16_to_cpu(p->header.nextindex) - XTENTRYSTART;
+
+		/*
+		 * binary search with search key K on the current page
+		 */
+		for (base = XTENTRYSTART; lim; lim >>= 1) {
+			index = base + (lim >> 1);
+
+			XT_CMP(cmp, xoff, &p->xad[index], t64);
+			if (cmp == 0) {
+				/*
+				 *      search hit
+				 */
+				/* search hit - leaf page:
+				 * return the entry found
+				 */
+				if (p->header.flag & BT_LEAF) {
+					*cmpp = cmp;
+
+					/* compute number of pages to split */
+					if (flag & XT_INSERT) {
+						if (p->header.nextindex ==
+						    p->header.maxentry)
+							nsplit++;
+						else
+							nsplit = 0;
+						btstack->nsplit = nsplit;
+					}
+
+					/* save search result */
+					btsp = btstack->top;
+					btsp->bn = bn;
+					btsp->index = index;
+					btsp->mp = mp;
+
+					/* init sequential access heuristics */
+					btindex = jfs_ip->btindex;
+					if (index == btindex ||
+					    index == btindex + 1)
+						jfs_ip->btorder = BT_SEQUENTIAL;
+					else
+						jfs_ip->btorder = BT_RANDOM;
+					jfs_ip->btindex = index;
+
+					return 0;
+				}
+
+				/* search hit - internal page:
+				 * descend/search its child page
+				 */
+				goto next;
+			}
+
+			if (cmp > 0) {
+				base = index + 1;
+				--lim;
+			}
+		}
+
+		/*
+		 *      search miss
+		 *
+		 * base is the smallest index with key (Kj) greater than
+		 * search key (K) and may be zero or maxentry index.
+		 */
+		/*
+		 * search miss - leaf page:
+		 *
+		 * return location of entry (base) where new entry with
+		 * search key K is to be inserted.
+		 */
+		if (p->header.flag & BT_LEAF) {
+			*cmpp = cmp;
+
+			/* compute number of pages to split */
+			if (flag & XT_INSERT) {
+				if (p->header.nextindex ==
+				    p->header.maxentry)
+					nsplit++;
+				else
+					nsplit = 0;
+				btstack->nsplit = nsplit;
+			}
+
+			/* save search result */
+			btsp = btstack->top;
+			btsp->bn = bn;
+			btsp->index = base;
+			btsp->mp = mp;
+
+			/* init sequential access heuristics */
+			btindex = jfs_ip->btindex;
+			if (base == btindex || base == btindex + 1)
+				jfs_ip->btorder = BT_SEQUENTIAL;
+			else
+				jfs_ip->btorder = BT_RANDOM;
+			jfs_ip->btindex = base;
+
+			return 0;
+		}
+
+		/*
+		 * search miss - non-leaf page:
+		 *
+		 * if base is non-zero, decrement base by one to get the parent
+		 * entry of the child page to search.
+		 */
+		index = base ? base - 1 : base;
+
+		/*
+		 * go down to child page
+		 */
+	      next:
+		/* update number of pages to split */
+		if (p->header.nextindex == p->header.maxentry)
+			nsplit++;
+		else
+			nsplit = 0;
+
+		/* push (bn, index) of the parent page/entry */
+		BT_PUSH(btstack, bn, index);
+
+		/* get the child page block number */
+		bn = addressXAD(&p->xad[index]);
+
+		/* unpin the parent page */
+		XT_PUTPAGE(mp);
+	}
+}
+
+/*
+ *      xtInsert()
+ *
+ * function:
+ *
+ * parameter:
+ *      tid     - transaction id;
+ *      ip      - file object;
+ *      xflag   - extent flag (XAD_NOTRECORDED):
+ *      xoff    - extent offset;
+ *      xlen    - extent length;
+ *      xaddrp  - extent address pointer (in/out):
+ *              if (*xaddrp)
+ *                      caller allocated data extent at *xaddrp;
+ *              else
+ *                      allocate data extent and return its xaddr;
+ *      flag    -
+ *
+ * return:
+ */
+int xtInsert(tid_t tid,		/* transaction id */
+	     struct inode *ip, int xflag, s64 xoff, s32 xlen, s64 * xaddrp,
+	     int flag)
+{
+	int rc = 0;
+	s64 xaddr, hint;
+	struct metapage *mp;	/* meta-page buffer */
+	xtpage_t *p;		/* base B+-tree index page */
+	s64 bn;
+	int index, nextindex;
+	struct btstack btstack;	/* traverse stack */
+	struct xtsplit split;	/* split information */
+	xad_t *xad;
+	int cmp;
+	struct tlock *tlck;
+	struct xtlock *xtlck;
+
+	jFYI(1,
+	     ("xtInsert: nxoff:0x%lx nxlen:0x%x\n", (ulong) xoff, xlen));
+
+	/*
+	 *      search for the entry location at which to insert:
+	 *
+	 * xtFastSearch() and xtSearch() both returns (leaf page
+	 * pinned, index at which to insert).
+	 * n.b. xtSearch() may return index of maxentry of
+	 * the full page.
+	 */
+	if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT)))
+		return rc;
+
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+	/* This test must follow XT_GETSEARCH since mp must be valid if
+	 * we branch to out: */
+	if (cmp == 0) {
+		rc = EEXIST;
+		goto out;
+	}
+
+	/*
+	 * allocate data extent requested
+	 *
+	 * allocation hint: last xad
+	 */
+	if ((xaddr = *xaddrp) == 0) {
+		if (index > XTENTRYSTART) {
+			xad = &p->xad[index - 1];
+			hint = addressXAD(xad) + lengthXAD(xad) - 1;
+		} else
+			hint = 0;
+		if ((rc = dbAlloc(ip, hint, (s64) xlen, &xaddr)))
+			goto out;
+	}
+
+	/*
+	 *      insert entry for new extent
+	 */
+	xflag |= XAD_NEW;
+
+	/*
+	 *      if the leaf page is full, split the page and
+	 *      propagate up the router entry for the new page from split
+	 *
+	 * The xtSplitUp() will insert the entry and unpin the leaf page.
+	 */
+	nextindex = le16_to_cpu(p->header.nextindex);
+	if (nextindex == le16_to_cpu(p->header.maxentry)) {
+		split.mp = mp;
+		split.index = index;
+		split.flag = xflag;
+		split.off = xoff;
+		split.len = xlen;
+		split.addr = xaddr;
+		split.pxdlist = NULL;
+		if ((rc = xtSplitUp(tid, ip, &split, &btstack))) {
+			/* undo data extent allocation */
+			if (*xaddrp == 0)
+				dbFree(ip, xaddr, (s64) xlen);
+			return rc;
+		}
+
+		*xaddrp = xaddr;
+		return 0;
+	}
+
+	/*
+	 *      insert the new entry into the leaf page
+	 */
+	/*
+	 * acquire a transaction lock on the leaf page;
+	 *
+	 * action: xad insertion/extension;
+	 */
+	BT_MARK_DIRTY(mp, ip);
+
+	/* if insert into middle, shift right remaining entries. */
+	if (index < nextindex)
+		memmove(&p->xad[index + 1], &p->xad[index],
+			(nextindex - index) * sizeof(xad_t));
+
+	/* insert the new entry: mark the entry NEW */
+	xad = &p->xad[index];
+	XT_PUTENTRY(xad, xflag, xoff, xlen, xaddr);
+
+	/* advance next available entry index */
+	p->header.nextindex =
+	    cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
+
+	/* Don't log it if there are no links to the file */
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+		xtlck = (struct xtlock *) & tlck->lock;
+		xtlck->lwm.offset =
+		    (xtlck->lwm.offset) ? min(index,
+					      (int)xtlck->lwm.offset) : index;
+		xtlck->lwm.length =
+		    le16_to_cpu(p->header.nextindex) - xtlck->lwm.offset;
+	}
+
+	*xaddrp = xaddr;
+
+      out:
+	/* unpin the leaf page */
+	XT_PUTPAGE(mp);
+
+	return rc;
+}
+
+
+/*
+ *      xtSplitUp()
+ *
+ * function:
+ *      split full pages as propagating insertion up the tree
+ *
+ * parameter:
+ *      tid     - transaction id;
+ *      ip      - file object;
+ *      split   - entry parameter descriptor;
+ *      btstack - traverse stack from xtSearch()
+ *
+ * return:
+ */
+static int
+xtSplitUp(tid_t tid,
+	  struct inode *ip, struct xtsplit * split, struct btstack * btstack)
+{
+	int rc = 0;
+	struct metapage *smp;
+	xtpage_t *sp;		/* split page */
+	struct metapage *rmp;
+	s64 rbn;		/* new right page block number */
+	struct metapage *rcmp;
+	xtpage_t *rcp;		/* right child page */
+	s64 rcbn;		/* right child page block number */
+	int skip;		/* index of entry of insertion */
+	int nextindex;		/* next available entry index of p */
+	struct btframe *parent;	/* parent page entry on traverse stack */
+	xad_t *xad;
+	s64 xaddr;
+	int xlen;
+	int nsplit;		/* number of pages split */
+	struct pxdlist pxdlist;
+	pxd_t *pxd;
+	struct tlock *tlck;
+	struct xtlock *xtlck;
+
+	smp = split->mp;
+	sp = XT_PAGE(ip, smp);
+
+	/* is inode xtree root extension/inline EA area free ? */
+	if ((sp->header.flag & BT_ROOT) && (!S_ISDIR(ip->i_mode)) &&
+	    (sp->header.maxentry < cpu_to_le16(XTROOTMAXSLOT)) &&
+	    (JFS_IP(ip)->mode2 & INLINEEA)) {
+		sp->header.maxentry = cpu_to_le16(XTROOTMAXSLOT);
+		JFS_IP(ip)->mode2 &= ~INLINEEA;
+
+		BT_MARK_DIRTY(smp, ip);
+		/*
+		 * acquire a transaction lock on the leaf page;
+		 *
+		 * action: xad insertion/extension;
+		 */
+
+		/* if insert into middle, shift right remaining entries. */
+		skip = split->index;
+		nextindex = le16_to_cpu(sp->header.nextindex);
+		if (skip < nextindex)
+			memmove(&sp->xad[skip + 1], &sp->xad[skip],
+				(nextindex - skip) * sizeof(xad_t));
+
+		/* insert the new entry: mark the entry NEW */
+		xad = &sp->xad[skip];
+		XT_PUTENTRY(xad, split->flag, split->off, split->len,
+			    split->addr);
+
+		/* advance next available entry index */
+		sp->header.nextindex =
+		    cpu_to_le16(le16_to_cpu(sp->header.nextindex) + 1);
+
+		/* Don't log it if there are no links to the file */
+		if (!test_cflag(COMMIT_Nolink, ip)) {
+			tlck = txLock(tid, ip, smp, tlckXTREE | tlckGROW);
+			xtlck = (struct xtlock *) & tlck->lock;
+			xtlck->lwm.offset = (xtlck->lwm.offset) ?
+			    min(skip, (int)xtlck->lwm.offset) : skip;
+			xtlck->lwm.length =
+			    le16_to_cpu(sp->header.nextindex) -
+			    xtlck->lwm.offset;
+		}
+
+		return 0;
+	}
+
+	/*
+	 * allocate new index blocks to cover index page split(s)
+	 *
+	 * allocation hint: ?
+	 */
+	if (split->pxdlist == NULL) {
+		nsplit = btstack->nsplit;
+		split->pxdlist = &pxdlist;
+		pxdlist.maxnpxd = pxdlist.npxd = 0;
+		pxd = &pxdlist.pxd[0];
+		xlen = JFS_SBI(ip->i_sb)->nbperpage;
+		for (; nsplit > 0; nsplit--, pxd++) {
+			if ((rc = dbAlloc(ip, (s64) 0, (s64) xlen, &xaddr))
+			    == 0) {
+				PXDaddress(pxd, xaddr);
+				PXDlength(pxd, xlen);
+
+				pxdlist.maxnpxd++;
+
+				continue;
+			}
+
+			/* undo allocation */
+
+			XT_PUTPAGE(smp);
+			return rc;
+		}
+	}
+
+	/*
+	 * Split leaf page <sp> into <sp> and a new right page <rp>.
+	 *
+	 * The split routines insert the new entry into the leaf page,
+	 * and acquire txLock as appropriate.
+	 * return <rp> pinned and its block number <rpbn>.
+	 */
+	rc = (sp->header.flag & BT_ROOT) ?
+	    xtSplitRoot(tid, ip, split, &rmp) :
+	    xtSplitPage(tid, ip, split, &rmp, &rbn);
+	if (rc)
+		return EIO;
+
+	XT_PUTPAGE(smp);
+
+	/*
+	 * propagate up the router entry for the leaf page just split
+	 *
+	 * insert a router entry for the new page into the parent page,
+	 * propagate the insert/split up the tree by walking back the stack
+	 * of (bn of parent page, index of child page entry in parent page)
+	 * that were traversed during the search for the page that split.
+	 *
+	 * the propagation of insert/split up the tree stops if the root
+	 * splits or the page inserted into doesn't have to split to hold
+	 * the new entry.
+	 *
+	 * the parent entry for the split page remains the same, and
+	 * a new entry is inserted at its right with the first key and
+	 * block number of the new right page.
+	 *
+	 * There are a maximum of 3 pages pinned at any time:
+	 * right child, left parent and right parent (when the parent splits)
+	 * to keep the child page pinned while working on the parent.
+	 * make sure that all pins are released at exit.
+	 */
+	while ((parent = BT_POP(btstack)) != NULL) {
+		/* parent page specified by stack frame <parent> */
+
+		/* keep current child pages <rcp> pinned */
+		rcmp = rmp;
+		rcbn = rbn;
+		rcp = XT_PAGE(ip, rcmp);
+
+		/*
+		 * insert router entry in parent for new right child page <rp>
+		 */
+		/* get/pin the parent page <sp> */
+		XT_GETPAGE(ip, parent->bn, smp, PSIZE, sp, rc);
+		if (rc)
+			goto errout2;
+
+		/*
+		 * The new key entry goes ONE AFTER the index of parent entry,
+		 * because the split was to the right.
+		 */
+		skip = parent->index + 1;
+
+		/*
+		 * split or shift right remaining entries of the parent page
+		 */
+		nextindex = le16_to_cpu(sp->header.nextindex);
+		/*
+		 * parent page is full - split the parent page
+		 */
+		if (nextindex == le16_to_cpu(sp->header.maxentry)) {
+			/* init for parent page split */
+			split->mp = smp;
+			split->index = skip;	/* index at insert */
+			split->flag = XAD_NEW;
+			split->off = offsetXAD(&rcp->xad[XTENTRYSTART]);
+			split->len = JFS_SBI(ip->i_sb)->nbperpage;
+			split->addr = rcbn;
+
+			/* unpin previous right child page */
+			XT_PUTPAGE(rcmp);
+
+			/* The split routines insert the new entry,
+			 * and acquire txLock as appropriate.
+			 * return <rp> pinned and its block number <rpbn>.
+			 */
+			rc = (sp->header.flag & BT_ROOT) ?
+			    xtSplitRoot(tid, ip, split, &rmp) :
+			    xtSplitPage(tid, ip, split, &rmp, &rbn);
+			if (rc)
+				goto errout1;
+
+			XT_PUTPAGE(smp);
+			/* keep new child page <rp> pinned */
+		}
+		/*
+		 * parent page is not full - insert in parent page
+		 */
+		else {
+			/*
+			 * insert router entry in parent for the right child
+			 * page from the first entry of the right child page:
+			 */
+			/*
+			 * acquire a transaction lock on the parent page;
+			 *
+			 * action: router xad insertion;
+			 */
+			BT_MARK_DIRTY(smp, ip);
+
+			/*
+			 * if insert into middle, shift right remaining entries
+			 */
+			if (skip < nextindex)
+				memmove(&sp->xad[skip + 1], &sp->xad[skip],
+					(nextindex -
+					 skip) << L2XTSLOTSIZE);
+
+			/* insert the router entry */
+			xad = &sp->xad[skip];
+			XT_PUTENTRY(xad, XAD_NEW,
+				    offsetXAD(&rcp->xad[XTENTRYSTART]),
+				    JFS_SBI(ip->i_sb)->nbperpage, rcbn);
+
+			/* advance next available entry index. */
+			sp->header.nextindex =
+			    cpu_to_le16(le16_to_cpu(sp->header.nextindex) +
+					1);
+
+			/* Don't log it if there are no links to the file */
+			if (!test_cflag(COMMIT_Nolink, ip)) {
+				tlck = txLock(tid, ip, smp,
+					      tlckXTREE | tlckGROW);
+				xtlck = (struct xtlock *) & tlck->lock;
+				xtlck->lwm.offset = (xtlck->lwm.offset) ?
+				    min(skip, (int)xtlck->lwm.offset) : skip;
+				xtlck->lwm.length =
+				    le16_to_cpu(sp->header.nextindex) -
+				    xtlck->lwm.offset;
+			}
+
+			/* unpin parent page */
+			XT_PUTPAGE(smp);
+
+			/* exit propagate up */
+			break;
+		}
+	}
+
+	/* unpin current right page */
+	XT_PUTPAGE(rmp);
+
+	return 0;
+
+	/*
+	 * If something fails in the above loop we were already walking back
+	 * up the tree and the tree is now inconsistent.
+	 * release all pages we're holding.
+	 */
+      errout1:
+	XT_PUTPAGE(smp);
+
+      errout2:
+	XT_PUTPAGE(rcmp);
+
+	return rc;
+}
+
+
+/*
+ *      xtSplitPage()
+ *
+ * function:
+ *      split a full non-root page into
+ *      original/split/left page and new right page
+ *      i.e., the original/split page remains as left page.
+ *
+ * parameter:
+ *      int		tid,
+ *      struct inode    *ip,
+ *      struct xtsplit  *split,
+ *      struct metapage	**rmpp,
+ *      u64		*rbnp,
+ *
+ * return:
+ *      Pointer to page in which to insert or NULL on error.
+ */
+static int
+xtSplitPage(tid_t tid, struct inode *ip,
+	    struct xtsplit * split, struct metapage ** rmpp, s64 * rbnp)
+{
+	int rc = 0;
+	struct metapage *smp;
+	xtpage_t *sp;
+	struct metapage *rmp;
+	xtpage_t *rp;		/* new right page allocated */
+	s64 rbn;		/* new right page block number */
+	struct metapage *mp;
+	xtpage_t *p;
+	s64 nextbn;
+	int skip, maxentry, middle, righthalf, n;
+	xad_t *xad;
+	struct pxdlist *pxdlist;
+	pxd_t *pxd;
+	struct tlock *tlck;
+	struct xtlock *sxtlck = 0, *rxtlck = 0;
+
+	smp = split->mp;
+	sp = XT_PAGE(ip, smp);
+
+	INCREMENT(xtStat.split);
+
+	/*
+	 * allocate the new right page for the split
+	 */
+	pxdlist = split->pxdlist;
+	pxd = &pxdlist->pxd[pxdlist->npxd];
+	pxdlist->npxd++;
+	rbn = addressPXD(pxd);
+	rmp = get_metapage(ip, rbn, PSIZE, 1);
+	if (rmp == NULL)
+		return EIO;
+
+	jEVENT(0,
+	       ("xtSplitPage: ip:0x%p smp:0x%p rmp:0x%p\n", ip, smp, rmp));
+
+	BT_MARK_DIRTY(rmp, ip);
+	/*
+	 * action: new page;
+	 */
+
+	rp = (xtpage_t *) rmp->data;
+	rp->header.self = *pxd;
+	rp->header.flag = sp->header.flag & BT_TYPE;
+	rp->header.maxentry = sp->header.maxentry;	/* little-endian */
+	rp->header.nextindex = cpu_to_le16(XTENTRYSTART);
+
+	BT_MARK_DIRTY(smp, ip);
+	/* Don't log it if there are no links to the file */
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		/*
+		 * acquire a transaction lock on the new right page;
+		 */
+		tlck = txLock(tid, ip, rmp, tlckXTREE | tlckNEW);
+		rxtlck = (struct xtlock *) & tlck->lock;
+		rxtlck->lwm.offset = XTENTRYSTART;
+		/*
+		 * acquire a transaction lock on the split page
+		 */
+		tlck = txLock(tid, ip, smp, tlckXTREE | tlckGROW);
+		sxtlck = (struct xtlock *) & tlck->lock;
+	}
+
+	/*
+	 * initialize/update sibling pointers of <sp> and <rp>
+	 */
+	nextbn = le64_to_cpu(sp->header.next);
+	rp->header.next = cpu_to_le64(nextbn);
+	rp->header.prev = cpu_to_le64(addressPXD(&sp->header.self));
+	sp->header.next = cpu_to_le64(rbn);
+
+	skip = split->index;
+
+	/*
+	 *      sequential append at tail (after last entry of last page)
+	 *
+	 * if splitting the last page on a level because of appending
+	 * a entry to it (skip is maxentry), it's likely that the access is
+	 * sequential. adding an empty page on the side of the level is less
+	 * work and can push the fill factor much higher than normal.
+	 * if we're wrong it's no big deal -  we will do the split the right
+	 * way next time.
+	 * (it may look like it's equally easy to do a similar hack for
+	 * reverse sorted data, that is, split the tree left, but it's not.
+	 * Be my guest.)
+	 */
+	if (nextbn == 0 && skip == le16_to_cpu(sp->header.maxentry)) {
+		/*
+		 * acquire a transaction lock on the new/right page;
+		 *
+		 * action: xad insertion;
+		 */
+		/* insert entry at the first entry of the new right page */
+		xad = &rp->xad[XTENTRYSTART];
+		XT_PUTENTRY(xad, split->flag, split->off, split->len,
+			    split->addr);
+
+		rp->header.nextindex = cpu_to_le16(XTENTRYSTART + 1);
+
+		if (!test_cflag(COMMIT_Nolink, ip)) {
+			/* rxtlck->lwm.offset = XTENTRYSTART; */
+			rxtlck->lwm.length = 1;
+		}
+
+		*rmpp = rmp;
+		*rbnp = rbn;
+
+		ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd));
+
+		jEVENT(0, ("xtSplitPage: sp:0x%p rp:0x%p\n", sp, rp));
+		return 0;
+	}
+
+	/*
+	 *      non-sequential insert (at possibly middle page)
+	 */
+
+	/*
+	 * update previous pointer of old next/right page of <sp>
+	 */
+	if (nextbn != 0) {
+		XT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc);
+		if (rc) {
+			XT_PUTPAGE(rmp);
+			return rc;
+		}
+
+		BT_MARK_DIRTY(mp, ip);
+		/*
+		 * acquire a transaction lock on the next page;
+		 *
+		 * action:sibling pointer update;
+		 */
+		if (!test_cflag(COMMIT_Nolink, ip))
+			tlck = txLock(tid, ip, mp, tlckXTREE | tlckRELINK);
+
+		p->header.prev = cpu_to_le64(rbn);
+
+		/* sibling page may have been updated previously, or
+		 * it may be updated later;
+		 */
+
+		XT_PUTPAGE(mp);
+	}
+
+	/*
+	 * split the data between the split and new/right pages
+	 */
+	maxentry = le16_to_cpu(sp->header.maxentry);
+	middle = maxentry >> 1;
+	righthalf = maxentry - middle;
+
+	/*
+	 * skip index in old split/left page - insert into left page:
+	 */
+	if (skip <= middle) {
+		/* move right half of split page to the new right page */
+		memmove(&rp->xad[XTENTRYSTART], &sp->xad[middle],
+			righthalf << L2XTSLOTSIZE);
+
+		/* shift right tail of left half to make room for new entry */
+		if (skip < middle)
+			memmove(&sp->xad[skip + 1], &sp->xad[skip],
+				(middle - skip) << L2XTSLOTSIZE);
+
+		/* insert new entry */
+		xad = &sp->xad[skip];
+		XT_PUTENTRY(xad, split->flag, split->off, split->len,
+			    split->addr);
+
+		/* update page header */
+		sp->header.nextindex = cpu_to_le16(middle + 1);
+		if (!test_cflag(COMMIT_Nolink, ip)) {
+			sxtlck->lwm.offset = (sxtlck->lwm.offset) ?
+			    min(skip, (int)sxtlck->lwm.offset) : skip;
+		}
+
+		rp->header.nextindex =
+		    cpu_to_le16(XTENTRYSTART + righthalf);
+	}
+	/*
+	 * skip index in new right page - insert into right page:
+	 */
+	else {
+		/* move left head of right half to right page */
+		n = skip - middle;
+		memmove(&rp->xad[XTENTRYSTART], &sp->xad[middle],
+			n << L2XTSLOTSIZE);
+
+		/* insert new entry */
+		n += XTENTRYSTART;
+		xad = &rp->xad[n];
+		XT_PUTENTRY(xad, split->flag, split->off, split->len,
+			    split->addr);
+
+		/* move right tail of right half to right page */
+		if (skip < maxentry)
+			memmove(&rp->xad[n + 1], &sp->xad[skip],
+				(maxentry - skip) << L2XTSLOTSIZE);
+
+		/* update page header */
+		sp->header.nextindex = cpu_to_le16(middle);
+		if (!test_cflag(COMMIT_Nolink, ip)) {
+			sxtlck->lwm.offset = (sxtlck->lwm.offset) ?
+			    min(middle, (int)sxtlck->lwm.offset) : middle;
+		}
+
+		rp->header.nextindex = cpu_to_le16(XTENTRYSTART +
+						   righthalf + 1);
+	}
+
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		sxtlck->lwm.length = le16_to_cpu(sp->header.nextindex) -
+		    sxtlck->lwm.offset;
+
+		/* rxtlck->lwm.offset = XTENTRYSTART; */
+		rxtlck->lwm.length = le16_to_cpu(rp->header.nextindex) -
+		    XTENTRYSTART;
+	}
+
+	*rmpp = rmp;
+	*rbnp = rbn;
+
+	ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd));
+
+	jEVENT(0, ("xtSplitPage: sp:0x%p rp:0x%p\n", sp, rp));
+	return rc;
+}
+
+
+/*
+ *      xtSplitRoot()
+ *
+ * function:
+ *      split the full root page into
+ *      original/root/split page and new right page
+ *      i.e., root remains fixed in tree anchor (inode) and
+ *      the root is copied to a single new right child page
+ *      since root page << non-root page, and
+ *      the split root page contains a single entry for the
+ *      new right child page.
+ *
+ * parameter:
+ *      int		tid,
+ *      struct inode    *ip,
+ *      struct xtsplit  *split,
+ *      struct metapage	**rmpp)
+ *
+ * return:
+ *      Pointer to page in which to insert or NULL on error.
+ */
+static int
+xtSplitRoot(tid_t tid,
+	    struct inode *ip, struct xtsplit * split, struct metapage ** rmpp)
+{
+	xtpage_t *sp;
+	struct metapage *rmp;
+	xtpage_t *rp;
+	s64 rbn;
+	int skip, nextindex;
+	xad_t *xad;
+	pxd_t *pxd;
+	struct pxdlist *pxdlist;
+	struct tlock *tlck;
+	struct xtlock *xtlck;
+
+	sp = &JFS_IP(ip)->i_xtroot;
+
+	INCREMENT(xtStat.split);
+
+	/*
+	 *      allocate a single (right) child page
+	 */
+	pxdlist = split->pxdlist;
+	pxd = &pxdlist->pxd[pxdlist->npxd];
+	pxdlist->npxd++;
+	rbn = addressPXD(pxd);
+	rmp = get_metapage(ip, rbn, PSIZE, 1);
+	if (rmp == NULL)
+		return EIO;
+
+	jEVENT(0, ("xtSplitRoot: ip:0x%p rmp:0x%p\n", ip, rmp));
+
+	/*
+	 * acquire a transaction lock on the new right page;
+	 *
+	 * action: new page;
+	 */
+	BT_MARK_DIRTY(rmp, ip);
+
+	rp = (xtpage_t *) rmp->data;
+	rp->header.flag =
+	    (sp->header.flag & BT_LEAF) ? BT_LEAF : BT_INTERNAL;
+	rp->header.self = *pxd;
+	rp->header.nextindex = cpu_to_le16(XTENTRYSTART);
+	rp->header.maxentry = cpu_to_le16(PSIZE >> L2XTSLOTSIZE);
+
+	/* initialize sibling pointers */
+	rp->header.next = 0;
+	rp->header.prev = 0;
+
+	/*
+	 * copy the in-line root page into new right page extent
+	 */
+	nextindex = le16_to_cpu(sp->header.maxentry);
+	memmove(&rp->xad[XTENTRYSTART], &sp->xad[XTENTRYSTART],
+		(nextindex - XTENTRYSTART) << L2XTSLOTSIZE);
+
+	/*
+	 * insert the new entry into the new right/child page
+	 * (skip index in the new right page will not change)
+	 */
+	skip = split->index;
+	/* if insert into middle, shift right remaining entries */
+	if (skip != nextindex)
+		memmove(&rp->xad[skip + 1], &rp->xad[skip],
+			(nextindex - skip) * sizeof(xad_t));
+
+	xad = &rp->xad[skip];
+	XT_PUTENTRY(xad, split->flag, split->off, split->len, split->addr);
+
+	/* update page header */
+	rp->header.nextindex = cpu_to_le16(nextindex + 1);
+
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		tlck = txLock(tid, ip, rmp, tlckXTREE | tlckNEW);
+		xtlck = (struct xtlock *) & tlck->lock;
+		xtlck->lwm.offset = XTENTRYSTART;
+		xtlck->lwm.length = le16_to_cpu(rp->header.nextindex) -
+		    XTENTRYSTART;
+	}
+
+	/*
+	 *      reset the root
+	 *
+	 * init root with the single entry for the new right page
+	 * set the 1st entry offset to 0, which force the left-most key
+	 * at any level of the tree to be less than any search key.
+	 */
+	/*
+	 * acquire a transaction lock on the root page (in-memory inode);
+	 *
+	 * action: root split;
+	 */
+	BT_MARK_DIRTY(split->mp, ip);
+
+	xad = &sp->xad[XTENTRYSTART];
+	XT_PUTENTRY(xad, XAD_NEW, 0, JFS_SBI(ip->i_sb)->nbperpage, rbn);
+
+	/* update page header of root */
+	sp->header.flag &= ~BT_LEAF;
+	sp->header.flag |= BT_INTERNAL;
+
+	sp->header.nextindex = cpu_to_le16(XTENTRYSTART + 1);
+
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		tlck = txLock(tid, ip, split->mp, tlckXTREE | tlckGROW);
+		xtlck = (struct xtlock *) & tlck->lock;
+		xtlck->lwm.offset = XTENTRYSTART;
+		xtlck->lwm.length = 1;
+	}
+
+	*rmpp = rmp;
+
+	ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd));
+
+	jEVENT(0, ("xtSplitRoot: sp:0x%p rp:0x%p\n", sp, rp));
+	return 0;
+}
+
+
+/*
+ *      xtExtend()
+ *
+ * function: extend in-place;
+ *
+ * note: existing extent may or may not have been committed.
+ * caller is responsible for pager buffer cache update, and
+ * working block allocation map update;
+ * update pmap: alloc whole extended extent;
+ */
+int xtExtend(tid_t tid,		/* transaction id */
+	     struct inode *ip, s64 xoff,	/* delta extent offset */
+	     s32 xlen,		/* delta extent length */
+	     int flag)
+{
+	int rc = 0;
+	int cmp;
+	struct metapage *mp;	/* meta-page buffer */
+	xtpage_t *p;		/* base B+-tree index page */
+	s64 bn;
+	int index, nextindex, len;
+	struct btstack btstack;	/* traverse stack */
+	struct xtsplit split;	/* split information */
+	xad_t *xad;
+	s64 xaddr;
+	struct tlock *tlck;
+	struct xtlock *xtlck = 0;
+	int rootsplit = 0;
+
+	jFYI(1,
+	     ("xtExtend: nxoff:0x%lx nxlen:0x%x\n", (ulong) xoff, xlen));
+
+	/* there must exist extent to be extended */
+	if ((rc = xtSearch(ip, xoff - 1, &cmp, &btstack, XT_INSERT)))
+		return rc;
+	assert(cmp == 0);
+
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+	/* extension must be contiguous */
+	xad = &p->xad[index];
+	jFYI(0, ("xtExtend: xoff:0x%lx xlen:0x%x xaddr:0x%lx\n",
+		 (ulong) offsetXAD(xad), lengthXAD(xad),
+		 (ulong) addressXAD(xad)));
+	assert((offsetXAD(xad) + lengthXAD(xad)) == xoff);
+
+	/*
+	 * acquire a transaction lock on the leaf page;
+	 *
+	 * action: xad insertion/extension;
+	 */
+	BT_MARK_DIRTY(mp, ip);
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+		xtlck = (struct xtlock *) & tlck->lock;
+	}
+
+	/* extend will overflow extent ? */
+	xlen = lengthXAD(xad) + xlen;
+	if ((len = xlen - MAXXLEN) <= 0)
+		goto extendOld;
+
+	/*
+	 *      extent overflow: insert entry for new extent
+	 */
+//insertNew:
+	xoff = offsetXAD(xad) + MAXXLEN;
+	xaddr = addressXAD(xad) + MAXXLEN;
+	nextindex = le16_to_cpu(p->header.nextindex);
+
+	/*
+	 *      if the leaf page is full, insert the new entry and
+	 *      propagate up the router entry for the new page from split
+	 *
+	 * The xtSplitUp() will insert the entry and unpin the leaf page.
+	 */
+	if (nextindex == le16_to_cpu(p->header.maxentry)) {
+		rootsplit = p->header.flag & BT_ROOT;
+
+		/* xtSpliUp() unpins leaf pages */
+		split.mp = mp;
+		split.index = index + 1;
+		split.flag = XAD_NEW;
+		split.off = xoff;	/* split offset */
+		split.len = len;
+		split.addr = xaddr;
+		split.pxdlist = NULL;
+		if ((rc = xtSplitUp(tid, ip, &split, &btstack)))
+			return rc;
+
+		/*
+		 * if leaf root has been split, original root has been
+		 * copied to new child page, i.e., original entry now
+		 * resides on the new child page;
+		 */
+		if (rootsplit) {
+			if (p->header.nextindex ==
+			    cpu_to_le16(XTENTRYSTART + 1)) {
+				xad = &p->xad[XTENTRYSTART];
+				bn = addressXAD(xad);
+
+				/* get new child page */
+				XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+
+				BT_MARK_DIRTY(mp, ip);
+				if (!test_cflag(COMMIT_Nolink, ip)) {
+					tlck = txLock(tid, ip, mp,
+						      tlckXTREE |
+						      tlckGROW);
+					xtlck = (struct xtlock *) & tlck->lock;
+				}
+			}
+		} else
+			/* get back old page */
+			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	}
+	/*
+	 *      insert the new entry into the leaf page
+	 */
+	else {
+		/* insert the new entry: mark the entry NEW */
+		xad = &p->xad[index + 1];
+		XT_PUTENTRY(xad, XAD_NEW, xoff, len, xaddr);
+
+		/* advance next available entry index */
+		p->header.nextindex =
+		    cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
+	}
+
+	/* get back old entry */
+	xad = &p->xad[index];
+	xlen = MAXXLEN;
+
+	/*
+	 * extend old extent
+	 */
+      extendOld:
+	XADlength(xad, xlen);
+	if (!(xad->flag & XAD_NEW))
+		xad->flag |= XAD_EXTENDED;
+
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		xtlck->lwm.offset =
+		    (xtlck->lwm.offset) ? min(index,
+					      (int)xtlck->lwm.offset) : index;
+		xtlck->lwm.length =
+		    le16_to_cpu(p->header.nextindex) - xtlck->lwm.offset;
+	}
+
+	/* unpin the leaf page */
+	XT_PUTPAGE(mp);
+
+	return rc;
+}
+
+
+/*
+ *      xtTailgate()
+ *
+ * function: split existing 'tail' extent
+ *      (split offset >= start offset of tail extent), and
+ *      relocate and extend the split tail half;
+ *
+ * note: existing extent may or may not have been committed.
+ * caller is responsible for pager buffer cache update, and
+ * working block allocation map update;
+ * update pmap: free old split tail extent, alloc new extent;
+ */
+int xtTailgate(tid_t tid,		/* transaction id */
+	       struct inode *ip, s64 xoff,	/* split/new extent offset */
+	       s32 xlen,	/* new extent length */
+	       s64 xaddr,	/* new extent address */
+	       int flag)
+{
+	int rc = 0;
+	int cmp;
+	struct metapage *mp;	/* meta-page buffer */
+	xtpage_t *p;		/* base B+-tree index page */
+	s64 bn;
+	int index, nextindex, llen, rlen;
+	struct btstack btstack;	/* traverse stack */
+	struct xtsplit split;	/* split information */
+	xad_t *xad;
+	struct tlock *tlck;
+	struct xtlock *xtlck = 0;
+	struct tlock *mtlck;
+	struct maplock *pxdlock;
+	int rootsplit = 0;
+
+/*
+printf("xtTailgate: nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n",
+        (ulong)xoff, xlen, (ulong)xaddr);
+*/
+
+	/* there must exist extent to be tailgated */
+	if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT)))
+		return rc;
+	assert(cmp == 0);
+
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+	/* entry found must be last entry */
+	nextindex = le16_to_cpu(p->header.nextindex);
+	assert(index == nextindex - 1);
+
+	BT_MARK_DIRTY(mp, ip);
+	/*
+	 * acquire tlock of the leaf page containing original entry
+	 */
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+		xtlck = (struct xtlock *) & tlck->lock;
+	}
+
+	/* completely replace extent ? */
+	xad = &p->xad[index];
+/*
+printf("xtTailgate: xoff:0x%lx xlen:0x%x xaddr:0x%lx\n",
+        (ulong)offsetXAD(xad), lengthXAD(xad), (ulong)addressXAD(xad));
+*/
+	if ((llen = xoff - offsetXAD(xad)) == 0)
+		goto updateOld;
+
+	/*
+	 *      partially replace extent: insert entry for new extent
+	 */
+//insertNew:
+	/*
+	 *      if the leaf page is full, insert the new entry and
+	 *      propagate up the router entry for the new page from split
+	 *
+	 * The xtSplitUp() will insert the entry and unpin the leaf page.
+	 */
+	if (nextindex == le16_to_cpu(p->header.maxentry)) {
+		rootsplit = p->header.flag & BT_ROOT;
+
+		/* xtSpliUp() unpins leaf pages */
+		split.mp = mp;
+		split.index = index + 1;
+		split.flag = XAD_NEW;
+		split.off = xoff;	/* split offset */
+		split.len = xlen;
+		split.addr = xaddr;
+		split.pxdlist = NULL;
+		if ((rc = xtSplitUp(tid, ip, &split, &btstack)))
+			return rc;
+
+		/*
+		 * if leaf root has been split, original root has been
+		 * copied to new child page, i.e., original entry now
+		 * resides on the new child page;
+		 */
+		if (rootsplit) {
+			if (p->header.nextindex ==
+			    cpu_to_le16(XTENTRYSTART + 1)) {
+				xad = &p->xad[XTENTRYSTART];
+				bn = addressXAD(xad);
+
+				/* get new child page */
+				XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+
+				BT_MARK_DIRTY(mp, ip);
+				if (!test_cflag(COMMIT_Nolink, ip)) {
+					tlck = txLock(tid, ip, mp,
+						      tlckXTREE |
+						      tlckGROW);
+					xtlck = (struct xtlock *) & tlck->lock;
+				}
+			}
+		} else
+			/* get back old page */
+			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	}
+	/*
+	 *      insert the new entry into the leaf page
+	 */
+	else {
+		/* insert the new entry: mark the entry NEW */
+		xad = &p->xad[index + 1];
+		XT_PUTENTRY(xad, XAD_NEW, xoff, xlen, xaddr);
+
+		/* advance next available entry index */
+		p->header.nextindex =
+		    cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
+	}
+
+	/* get back old XAD */
+	xad = &p->xad[index];
+
+	/*
+	 * truncate/relocate old extent at split offset
+	 */
+      updateOld:
+	/* update dmap for old/committed/truncated extent */
+	rlen = lengthXAD(xad) - llen;
+	if (!(xad->flag & XAD_NEW)) {
+		/* free from PWMAP at commit */
+		if (!test_cflag(COMMIT_Nolink, ip)) {
+			mtlck = txMaplock(tid, ip, tlckMAP);
+			pxdlock = (struct maplock *) & mtlck->lock;
+			pxdlock->flag = mlckFREEPXD;
+			PXDaddress(&pxdlock->pxd, addressXAD(xad) + llen);
+			PXDlength(&pxdlock->pxd, rlen);
+			pxdlock->index = 1;
+		}
+		jEVENT(0,
+		       ("xtTailgate: free extent xaddr:0x%lx xlen:0x%x\n",
+			(ulong) addressPXD(&pxdlock->pxd),
+			lengthPXD(&pxdlock->pxd)));
+	} else
+		/* free from WMAP */
+		dbFree(ip, addressXAD(xad) + llen, (s64) rlen);
+
+	if (llen)
+		/* truncate */
+		XADlength(xad, llen);
+	else
+		/* replace */
+		XT_PUTENTRY(xad, XAD_NEW, xoff, xlen, xaddr);
+
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		xtlck->lwm.offset = (xtlck->lwm.offset) ?
+		    min(index, (int)xtlck->lwm.offset) : index;
+		xtlck->lwm.length = le16_to_cpu(p->header.nextindex) -
+		    xtlck->lwm.offset;
+	}
+
+	/* unpin the leaf page */
+	XT_PUTPAGE(mp);
+
+	return rc;
+}
+
+
+/*
+ *      xtUpdate()
+ *
+ * function: update XAD;
+ *
+ *      update extent for allocated_but_not_recorded or
+ *      compressed extent;
+ *
+ * parameter:
+ *      nxad    - new XAD;
+ *                logical extent of the specified XAD must be completely
+ *                contained by an existing XAD;
+ */
+int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
+{				/* new XAD */
+	int rc = 0;
+	int cmp;
+	struct metapage *mp;	/* meta-page buffer */
+	xtpage_t *p;		/* base B+-tree index page */
+	s64 bn;
+	int index0, index, newindex, nextindex;
+	struct btstack btstack;	/* traverse stack */
+	struct xtsplit split;	/* split information */
+	xad_t *xad, *lxad, *rxad;
+	int xflag;
+	s64 nxoff, xoff;
+	int nxlen, xlen, lxlen, rxlen;
+	s64 nxaddr, xaddr;
+	struct tlock *tlck;
+	struct xtlock *xtlck = 0;
+	int rootsplit = 0, newpage = 0;
+
+	/* there must exist extent to be tailgated */
+	nxoff = offsetXAD(nxad);
+	nxlen = lengthXAD(nxad);
+	nxaddr = addressXAD(nxad);
+/*
+printf("xtUpdate: nxflag:0x%x nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n",
+        nxad->flag, (ulong)nxoff, nxlen, (ulong)nxaddr);
+*/
+	if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT)))
+		return rc;
+	assert(cmp == 0);
+
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0);
+
+	BT_MARK_DIRTY(mp, ip);
+	/*
+	 * acquire tlock of the leaf page containing original entry
+	 */
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+		xtlck = (struct xtlock *) & tlck->lock;
+	}
+
+	xad = &p->xad[index0];
+	xflag = xad->flag;
+	xoff = offsetXAD(xad);
+	xlen = lengthXAD(xad);
+	xaddr = addressXAD(xad);
+/*
+printf("xtUpdate: xflag:0x%x xoff:0x%lx xlen:0x%x xaddr:0x%lx\n",
+        xflag, (ulong)xoff, xlen, (ulong)xaddr);
+*/
+
+	/* nXAD must be completely contained within XAD */
+	assert(xoff <= nxoff);
+	assert(nxoff + nxlen <= xoff + xlen);
+
+	index = index0;
+	newindex = index + 1;
+	nextindex = le16_to_cpu(p->header.nextindex);
+
+#ifdef  _JFS_WIP_NOCOALESCE
+	if (xoff < nxoff)
+		goto updateRight;
+
+	/*
+	 * replace XAD with nXAD
+	 */
+      replace:			/* (nxoff == xoff) */
+	if (nxlen == xlen) {
+		/* replace XAD with nXAD:recorded */
+		*xad = *nxad;
+		xad->flag = xflag & ~XAD_NOTRECORDED;
+
+		goto out;
+	} else			/* (nxlen < xlen) */
+		goto updateLeft;
+#endif				/* _JFS_WIP_NOCOALESCE */
+
+/* #ifdef _JFS_WIP_COALESCE */
+	if (xoff < nxoff)
+		goto coalesceRight;
+
+	/*
+	 * coalesce with left XAD
+	 */
+//coalesceLeft: /* (xoff == nxoff) */
+	/* is XAD first entry of page ? */
+	if (index == XTENTRYSTART)
+		goto replace;
+
+	/* is nXAD logically and physically contiguous with lXAD ? */
+	lxad = &p->xad[index - 1];
+	lxlen = lengthXAD(lxad);
+	if (!(lxad->flag & XAD_NOTRECORDED) &&
+	    (nxoff == offsetXAD(lxad) + lxlen) &&
+	    (nxaddr == addressXAD(lxad) + lxlen) &&
+	    (lxlen + nxlen < MAXXLEN)) {
+		/* extend right lXAD */
+		index0 = index - 1;
+		XADlength(lxad, lxlen + nxlen);
+
+		/* If we just merged two extents together, need to make sure the
+		 * right extent gets logged.  If the left one is marked XAD_NEW,
+		 * then we know it will be logged.  Otherwise, mark as
+		 * XAD_EXTENDED
+		 */
+		if (!(lxad->flag & XAD_NEW))
+			lxad->flag |= XAD_EXTENDED;
+
+		if (xlen > nxlen) {
+			/* truncate XAD */
+			XADoffset(xad, xoff + nxlen);
+			XADlength(xad, xlen - nxlen);
+			XADaddress(xad, xaddr + nxlen);
+			goto out;
+		} else {	/* (xlen == nxlen) */
+
+			/* remove XAD */
+			if (index < nextindex - 1)
+				memmove(&p->xad[index], &p->xad[index + 1],
+					(nextindex - index -
+					 1) << L2XTSLOTSIZE);
+
+			p->header.nextindex =
+			    cpu_to_le16(le16_to_cpu(p->header.nextindex) -
+					1);
+
+			index = index0;
+			newindex = index + 1;
+			nextindex = le16_to_cpu(p->header.nextindex);
+			xoff = nxoff = offsetXAD(lxad);
+			xlen = nxlen = lxlen + nxlen;
+			xaddr = nxaddr = addressXAD(lxad);
+			goto coalesceRight;
+		}
+	}
+
+	/*
+	 * replace XAD with nXAD
+	 */
+      replace:			/* (nxoff == xoff) */
+	if (nxlen == xlen) {
+		/* replace XAD with nXAD:recorded */
+		*xad = *nxad;
+		xad->flag = xflag & ~XAD_NOTRECORDED;
+
+		goto coalesceRight;
+	} else			/* (nxlen < xlen) */
+		goto updateLeft;
+
+	/*
+	 * coalesce with right XAD
+	 */
+      coalesceRight:		/* (xoff <= nxoff) */
+	/* is XAD last entry of page ? */
+	if (newindex == nextindex) {
+		if (xoff == nxoff)
+			goto out;
+		goto updateRight;
+	}
+
+	/* is nXAD logically and physically contiguous with rXAD ? */
+	rxad = &p->xad[index + 1];
+	rxlen = lengthXAD(rxad);
+	if (!(rxad->flag & XAD_NOTRECORDED) &&
+	    (nxoff + nxlen == offsetXAD(rxad)) &&
+	    (nxaddr + nxlen == addressXAD(rxad)) &&
+	    (rxlen + nxlen < MAXXLEN)) {
+		/* extend left rXAD */
+		XADoffset(rxad, nxoff);
+		XADlength(rxad, rxlen + nxlen);
+		XADaddress(rxad, nxaddr);
+
+		/* If we just merged two extents together, need to make sure
+		 * the left extent gets logged.  If the right one is marked
+		 * XAD_NEW, then we know it will be logged.  Otherwise, mark as
+		 * XAD_EXTENDED
+		 */
+		if (!(rxad->flag & XAD_NEW))
+			rxad->flag |= XAD_EXTENDED;
+
+		if (xlen > nxlen)
+			/* truncate XAD */
+			XADlength(xad, xlen - nxlen);
+		else {		/* (xlen == nxlen) */
+
+			/* remove XAD */
+			memmove(&p->xad[index], &p->xad[index + 1],
+				(nextindex - index - 1) << L2XTSLOTSIZE);
+
+			p->header.nextindex =
+			    cpu_to_le16(le16_to_cpu(p->header.nextindex) -
+					1);
+		}
+
+		goto out;
+	} else if (xoff == nxoff)
+		goto out;
+
+	assert(xoff < nxoff);
+/* #endif _JFS_WIP_COALESCE */
+
+	/*
+	 * split XAD into (lXAD, nXAD):
+	 *
+	 *          |---nXAD--->
+	 * --|----------XAD----------|--
+	 *   |-lXAD-|
+	 */
+      updateRight:		/* (xoff < nxoff) */
+	/* truncate old XAD as lXAD:not_recorded */
+	xad = &p->xad[index];
+	XADlength(xad, nxoff - xoff);
+
+	/* insert nXAD:recorded */
+	if (nextindex == le16_to_cpu(p->header.maxentry)) {
+/*
+printf("xtUpdate.updateRight.split p:0x%p\n", p);
+*/
+		rootsplit = p->header.flag & BT_ROOT;
+
+		/* xtSpliUp() unpins leaf pages */
+		split.mp = mp;
+		split.index = newindex;
+		split.flag = xflag & ~XAD_NOTRECORDED;
+		split.off = nxoff;
+		split.len = nxlen;
+		split.addr = nxaddr;
+		split.pxdlist = NULL;
+		if ((rc = xtSplitUp(tid, ip, &split, &btstack)))
+			return rc;
+
+		/*
+		 * if leaf root has been split, original root has been
+		 * copied to new child page, i.e., original entry now
+		 * resides on the new child page;
+		 */
+		if (rootsplit) {
+			if (p->header.nextindex ==
+			    cpu_to_le16(XTENTRYSTART + 1)) {
+				xad = &p->xad[XTENTRYSTART];
+				bn = addressXAD(xad);
+
+				/* get new child page */
+				XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+
+				BT_MARK_DIRTY(mp, ip);
+				if (!test_cflag(COMMIT_Nolink, ip)) {
+					tlck = txLock(tid, ip, mp,
+						      tlckXTREE |
+						      tlckGROW);
+					xtlck = (struct xtlock *) & tlck->lock;
+				}
+			}
+		} else {
+			/* get back old page */
+			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+
+			/* is nXAD on new page ? */
+			if (newindex >
+			    (le16_to_cpu(p->header.maxentry) >> 1)) {
+				newindex =
+				    newindex -
+				    le16_to_cpu(p->header.nextindex) +
+				    XTENTRYSTART;
+				newpage = 1;
+			}
+		}
+	} else {
+		/* if insert into middle, shift right remaining entries */
+		if (newindex < nextindex)
+			memmove(&p->xad[newindex + 1], &p->xad[newindex],
+				(nextindex - newindex) << L2XTSLOTSIZE);
+
+		/* insert the entry */
+		xad = &p->xad[newindex];
+		*xad = *nxad;
+		xad->flag = xflag & ~XAD_NOTRECORDED;
+
+		/* advance next available entry index. */
+		p->header.nextindex =
+		    cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
+	}
+
+	/*
+	 * does nXAD force 3-way split ?
+	 *
+	 *          |---nXAD--->|
+	 * --|----------XAD-------------|--
+	 *   |-lXAD-|           |-rXAD -|
+	 */
+	if (nxoff + nxlen == xoff + xlen)
+		goto out;
+
+	/* reorient nXAD as XAD for further split XAD into (nXAD, rXAD) */
+	if (newpage) {
+		/* close out old page */
+		if (!test_cflag(COMMIT_Nolink, ip)) {
+			xtlck->lwm.offset = (xtlck->lwm.offset) ?
+			    min(index0, (int)xtlck->lwm.offset) : index0;
+			xtlck->lwm.length =
+			    le16_to_cpu(p->header.nextindex) -
+			    xtlck->lwm.offset;
+		}
+
+		bn = le64_to_cpu(p->header.next);
+		XT_PUTPAGE(mp);
+
+		/* get new right page */
+		XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+
+		BT_MARK_DIRTY(mp, ip);
+		if (!test_cflag(COMMIT_Nolink, ip)) {
+			tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+			xtlck = (struct xtlock *) & tlck->lock;
+		}
+
+		index0 = index = newindex;
+	} else
+		index++;
+
+	newindex = index + 1;
+	nextindex = le16_to_cpu(p->header.nextindex);
+	xlen = xlen - (nxoff - xoff);
+	xoff = nxoff;
+	xaddr = nxaddr;
+
+	/* recompute split pages */
+	if (nextindex == le16_to_cpu(p->header.maxentry)) {
+/*
+printf("xtUpdate: updateRight+Left recompute split pages: p:0x%p\n", p);
+*/
+		XT_PUTPAGE(mp);
+
+		if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT)))
+			return rc;
+		assert(cmp == 0);
+
+		/* retrieve search result */
+		XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0);
+		assert(index0 == index);
+	}
+
+	/*
+	 * split XAD into (nXAD, rXAD)
+	 *
+	 *          ---nXAD---|
+	 * --|----------XAD----------|--
+	 *                    |-rXAD-|
+	 */
+      updateLeft:		/* (nxoff == xoff) && (nxlen < xlen) */
+	/* update old XAD with nXAD:recorded */
+	xad = &p->xad[index];
+	*xad = *nxad;
+	xad->flag = xflag & ~XAD_NOTRECORDED;
+
+	/* insert rXAD:not_recorded */
+	xoff = xoff + nxlen;
+	xlen = xlen - nxlen;
+	xaddr = xaddr + nxlen;
+	if (nextindex == le16_to_cpu(p->header.maxentry)) {
+		rootsplit = p->header.flag & BT_ROOT;
+
+/*
+printf("xtUpdate.updateLeft.split p:0x%p\n", p);
+*/
+		/* xtSpliUp() unpins leaf pages */
+		split.mp = mp;
+		split.index = newindex;
+		split.flag = xflag;
+		split.off = xoff;
+		split.len = xlen;
+		split.addr = xaddr;
+		split.pxdlist = NULL;
+		if ((rc = xtSplitUp(tid, ip, &split, &btstack)))
+			return rc;
+
+		/*
+		 * if leaf root has been split, original root has been
+		 * copied to new child page, i.e., original entry now
+		 * resides on the new child page;
+		 */
+		if (rootsplit) {
+			if (p->header.nextindex ==
+			    cpu_to_le16(XTENTRYSTART + 1)) {
+				xad = &p->xad[XTENTRYSTART];
+				bn = addressXAD(xad);
+
+				/* get new child page */
+				XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+
+				BT_MARK_DIRTY(mp, ip);
+				if (!test_cflag(COMMIT_Nolink, ip)) {
+					tlck = txLock(tid, ip, mp,
+						      tlckXTREE |
+						      tlckGROW);
+					xtlck = (struct xtlock *) & tlck->lock;
+				}
+			}
+		} else
+			/* get back old page */
+			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	} else {
+		/* if insert into middle, shift right remaining entries */
+		if (newindex < nextindex)
+			memmove(&p->xad[newindex + 1], &p->xad[newindex],
+				(nextindex - newindex) << L2XTSLOTSIZE);
+
+		/* insert the entry */
+		xad = &p->xad[newindex];
+		XT_PUTENTRY(xad, xflag, xoff, xlen, xaddr);
+
+		/* advance next available entry index. */
+		p->header.nextindex =
+		    cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
+	}
+
+      out:
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		xtlck->lwm.offset = (xtlck->lwm.offset) ?
+		    min(index0, (int)xtlck->lwm.offset) : index0;
+		xtlck->lwm.length = le16_to_cpu(p->header.nextindex) -
+		    xtlck->lwm.offset;
+	}
+
+	/* unpin the leaf page */
+	XT_PUTPAGE(mp);
+
+	return rc;
+}
+
+
+/*
+ *      xtAppend()
+ *
+ * function: grow in append mode from contiguous region specified ;
+ *
+ * parameter:
+ *      tid             - transaction id;
+ *      ip              - file object;
+ *      xflag           - extent flag:
+ *      xoff            - extent offset;
+ *      maxblocks       - max extent length;
+ *      xlen            - extent length (in/out);
+ *      xaddrp          - extent address pointer (in/out):
+ *      flag            -
+ *
+ * return:
+ */
+int xtAppend(tid_t tid,		/* transaction id */
+	     struct inode *ip, int xflag, s64 xoff, s32 maxblocks,	
+	     s32 * xlenp,	/* (in/out) */
+	     s64 * xaddrp,	/* (in/out) */
+	     int flag)
+{
+	int rc = 0;
+	struct metapage *mp;	/* meta-page buffer */
+	xtpage_t *p;		/* base B+-tree index page */
+	s64 bn, xaddr;
+	int index, nextindex;
+	struct btstack btstack;	/* traverse stack */
+	struct xtsplit split;	/* split information */
+	xad_t *xad;
+	int cmp;
+	struct tlock *tlck;
+	struct xtlock *xtlck;
+	int nsplit, nblocks, xlen;
+	struct pxdlist pxdlist;
+	pxd_t *pxd;
+
+	xaddr = *xaddrp;
+	xlen = *xlenp;
+	jEVENT(0,
+	       ("xtAppend: xoff:0x%lx maxblocks:%d xlen:%d xaddr:0x%lx\n",
+		(ulong) xoff, maxblocks, xlen, (ulong) xaddr));
+
+	/*
+	 *      search for the entry location at which to insert:
+	 *
+	 * xtFastSearch() and xtSearch() both returns (leaf page
+	 * pinned, index at which to insert).
+	 * n.b. xtSearch() may return index of maxentry of
+	 * the full page.
+	 */
+	if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT)))
+		return rc;
+
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+	if (cmp == 0) {
+		rc = EEXIST;
+		goto out;
+	}
+//insert:
+	/*
+	 *      insert entry for new extent
+	 */
+	xflag |= XAD_NEW;
+
+	/*
+	 *      if the leaf page is full, split the page and
+	 *      propagate up the router entry for the new page from split
+	 *
+	 * The xtSplitUp() will insert the entry and unpin the leaf page.
+	 */
+	nextindex = le16_to_cpu(p->header.nextindex);
+	if (nextindex < le16_to_cpu(p->header.maxentry))
+		goto insertLeaf;
+
+	/*
+	 * allocate new index blocks to cover index page split(s)
+	 */
+	nsplit = btstack.nsplit;
+	split.pxdlist = &pxdlist;
+	pxdlist.maxnpxd = pxdlist.npxd = 0;
+	pxd = &pxdlist.pxd[0];
+	nblocks = JFS_SBI(ip->i_sb)->nbperpage;
+	for (; nsplit > 0; nsplit--, pxd++, xaddr += nblocks, maxblocks -= nblocks) {	
+		if ((rc = dbAllocBottomUp(ip, xaddr, (s64) nblocks)) == 0) {
+			PXDaddress(pxd, xaddr);
+			PXDlength(pxd, nblocks);
+
+			pxdlist.maxnpxd++;
+
+			continue;
+		}
+
+		/* undo allocation */
+
+		goto out;
+	}
+
+	xlen = min(xlen, maxblocks);	
+
+	/*
+	 * allocate data extent requested
+	 */
+	if ((rc = dbAllocBottomUp(ip, xaddr, (s64) xlen)))
+		goto out;
+
+	split.mp = mp;
+	split.index = index;
+	split.flag = xflag;
+	split.off = xoff;
+	split.len = xlen;
+	split.addr = xaddr;
+	if ((rc = xtSplitUp(tid, ip, &split, &btstack))) {
+		/* undo data extent allocation */
+		dbFree(ip, *xaddrp, (s64) * xlenp);
+
+		return rc;
+	}
+
+	*xaddrp = xaddr;
+	*xlenp = xlen;
+	return 0;
+
+	/*
+	 *      insert the new entry into the leaf page
+	 */
+      insertLeaf:
+	/*
+	 * allocate data extent requested
+	 */
+	if ((rc = dbAllocBottomUp(ip, xaddr, (s64) xlen)))
+		goto out;
+
+	BT_MARK_DIRTY(mp, ip);
+	/*
+	 * acquire a transaction lock on the leaf page;
+	 *
+	 * action: xad insertion/extension;
+	 */
+	tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+	xtlck = (struct xtlock *) & tlck->lock;
+
+	/* insert the new entry: mark the entry NEW */
+	xad = &p->xad[index];
+	XT_PUTENTRY(xad, xflag, xoff, xlen, xaddr);
+
+	/* advance next available entry index */
+	p->header.nextindex =
+	    cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
+
+	xtlck->lwm.offset =
+	    (xtlck->lwm.offset) ? min(index,(int) xtlck->lwm.offset) : index;
+	xtlck->lwm.length = le16_to_cpu(p->header.nextindex) -
+	    xtlck->lwm.offset;
+
+	*xaddrp = xaddr;
+	*xlenp = xlen;
+
+      out:
+	/* unpin the leaf page */
+	XT_PUTPAGE(mp);
+
+	return rc;
+}
+#ifdef _STILL_TO_PORT
+
+/* - TBD for defragmentaion/reorganization -
+ *
+ *      xtDelete()
+ *
+ * function:
+ *      delete the entry with the specified key.
+ *
+ *      N.B.: whole extent of the entry is assumed to be deleted.
+ *
+ * parameter:
+ *
+ * return:
+ *       ENOENT: if the entry is not found.
+ *
+ * exception:
+ */
+int xtDelete(tid_t tid, struct inode *ip, s64 xoff, s32 xlen, int flag)
+{
+	int rc = 0;
+	struct btstack btstack;
+	int cmp;
+	s64 bn;
+	struct metapage *mp;
+	xtpage_t *p;
+	int index, nextindex;
+	struct tlock *tlck;
+	struct xtlock *xtlck;
+
+	/*
+	 * find the matching entry; xtSearch() pins the page
+	 */
+	if ((rc = xtSearch(ip, xoff, &cmp, &btstack, 0)))
+		return rc;
+
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+	if (cmp) {
+		/* unpin the leaf page */
+		XT_PUTPAGE(mp);
+		return ENOENT;
+	}
+
+	/*
+	 * delete the entry from the leaf page
+	 */
+	nextindex = le16_to_cpu(p->header.nextindex);
+	p->header.nextindex =
+	    cpu_to_le16(le16_to_cpu(p->header.nextindex) - 1);
+
+	/*
+	 * if the leaf page bocome empty, free the page
+	 */
+	if (p->header.nextindex == cpu_to_le16(XTENTRYSTART))
+		return (xtDeleteUp(tid, ip, mp, p, &btstack));
+
+	BT_MARK_DIRTY(mp, ip);
+	/*
+	 * acquire a transaction lock on the leaf page;
+	 *
+	 * action:xad deletion;
+	 */
+	tlck = txLock(tid, ip, mp, tlckXTREE);
+	xtlck = (struct xtlock *) & tlck->lock;
+	xtlck->lwm.offset =
+	    (xtlck->lwm.offset) ? min(index, xtlck->lwm.offset) : index;
+
+	/* if delete from middle, shift left/compact the remaining entries */
+	if (index < nextindex - 1)
+		memmove(&p->xad[index], &p->xad[index + 1],
+			(nextindex - index - 1) * sizeof(xad_t));
+
+	XT_PUTPAGE(mp);
+
+	return 0;
+}
+
+
+/* - TBD for defragmentaion/reorganization -
+ *
+ *      xtDeleteUp()
+ *
+ * function:
+ *      free empty pages as propagating deletion up the tree
+ *
+ * parameter:
+ *
+ * return:
+ */
+static int
+xtDeleteUp(tid_t tid, struct inode *ip,
+	   struct metapage * fmp, xtpage_t * fp, struct btstack * btstack)
+{
+	int rc = 0;
+	struct metapage *mp;
+	xtpage_t *p;
+	int index, nextindex;
+	s64 xaddr;
+	int xlen;
+	struct btframe *parent;
+	struct tlock *tlck;
+	struct xtlock *xtlck;
+
+	/*
+	 * keep root leaf page which has become empty
+	 */
+	if (fp->header.flag & BT_ROOT) {
+		/* keep the root page */
+		fp->header.flag &= ~BT_INTERNAL;
+		fp->header.flag |= BT_LEAF;
+		fp->header.nextindex = cpu_to_le16(XTENTRYSTART);
+
+		/* XT_PUTPAGE(fmp); */
+
+		return 0;
+	}
+
+	/*
+	 * free non-root leaf page
+	 */
+	if ((rc = xtRelink(tid, ip, fp)))
+		return rc;
+
+	xaddr = addressPXD(&fp->header.self);
+	xlen = lengthPXD(&fp->header.self);
+	/* free the page extent */
+	dbFree(ip, xaddr, (s64) xlen);
+
+	/* free the buffer page */
+	discard_metapage(fmp);
+
+	/*
+	 * propagate page deletion up the index tree
+	 *
+	 * If the delete from the parent page makes it empty,
+	 * continue all the way up the tree.
+	 * stop if the root page is reached (which is never deleted) or
+	 * if the entry deletion does not empty the page.
+	 */
+	while ((parent = BT_POP(btstack)) != NULL) {
+		/* get/pin the parent page <sp> */
+		XT_GETPAGE(ip, parent->bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		index = parent->index;
+
+		/* delete the entry for the freed child page from parent.
+		 */
+		nextindex = le16_to_cpu(p->header.nextindex);
+
+		/*
+		 * the parent has the single entry being deleted:
+		 * free the parent page which has become empty.
+		 */
+		if (nextindex == 1) {
+			if (p->header.flag & BT_ROOT) {
+				/* keep the root page */
+				p->header.flag &= ~BT_INTERNAL;
+				p->header.flag |= BT_LEAF;
+				p->header.nextindex =
+				    cpu_to_le16(XTENTRYSTART);
+
+				/* XT_PUTPAGE(fmp); */
+
+				break;
+			} else {
+				/* free the parent page */
+				if ((rc = xtRelink(tid, ip, p)))
+					return rc;
+
+				xaddr = addressPXD(&p->header.self);
+				/* free the page extent */
+				dbFree(ip, xaddr,
+				       (s64) JFS_SBI(ip->i_sb)->nbperpage);
+
+				/* unpin/free the buffer page */
+				discard_metapage(fmp);
+
+				/* propagate up */
+				continue;
+			}
+		}
+		/*
+		 * the parent has other entries remaining:
+		 * delete the router entry from the parent page.
+		 */
+		else {
+			BT_MARK_DIRTY(mp, ip);
+			/*
+			 * acquire a transaction lock on the leaf page;
+			 *
+			 * action:xad deletion;
+			 */
+			tlck = txLock(tid, ip, mp, tlckXTREE);
+			xtlck = (struct xtlock *) & tlck->lock;
+			xtlck->lwm.offset =
+			    (xtlck->lwm.offset) ? min(index,
+						      xtlck->lwm.
+						      offset) : index;
+
+			/* if delete from middle,
+			 * shift left/compact the remaining entries in the page
+			 */
+			if (index < nextindex - 1)
+				memmove(&p->xad[index], &p->xad[index + 1],
+					(nextindex - index -
+					 1) << L2XTSLOTSIZE);
+
+			p->header.nextindex =
+			    cpu_to_le16(le16_to_cpu(p->header.nextindex) -
+					1);
+			jEVENT(0,
+			       ("xtDeleteUp(entry): 0x%lx[%d]\n",
+				(ulong) parent->bn, index));
+		}
+
+		/* unpin the parent page */
+		XT_PUTPAGE(mp);
+
+		/* exit propagation up */
+		break;
+	}
+
+	return 0;
+}
+
+
+/*
+ * NAME:        xtRelocate()
+ *
+ * FUNCTION:    relocate xtpage or data extent of regular file;
+ *              This function is mainly used by defragfs utility.
+ *
+ * NOTE:        This routine does not have the logic to handle
+ *              uncommitted allocated extent. The caller should call
+ *              txCommit() to commit all the allocation before call
+ *              this routine.
+ */
+xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad,	/* old XAD */
+	   s64 nxaddr,		/* new xaddr */
+	   int xtype)
+{				/* extent type: XTPAGE or DATAEXT */
+	int rc = 0;
+	struct tblock *tblk;
+	struct tlock *tlck;
+	struct xtlock *xtlck;
+	struct metapage *mp, *pmp, *lmp, *rmp;	/* meta-page buffer */
+	xtpage_t *p, *pp, *rp, *lp;	/* base B+-tree index page */
+	xad_t *xad;
+	pxd_t *pxd;
+	s64 xoff, xsize;
+	int xlen;
+	s64 oxaddr, sxaddr, dxaddr, nextbn, prevbn;
+	cbuf_t *cp;
+	s64 offset, nbytes, nbrd, pno;
+	int nb, npages, nblks;
+	s64 bn;
+	int cmp;
+	int index;
+	struct pxd_lock *pxdlock;
+	struct btstack btstack;	/* traverse stack */
+
+	xtype = xtype & EXTENT_TYPE;
+
+	xoff = offsetXAD(oxad);
+	oxaddr = addressXAD(oxad);
+	xlen = lengthXAD(oxad);
+
+	/* validate extent offset */
+	offset = xoff << JFS_SBI(ip->i_sb)->l2bsize;
+	if (offset >= ip->i_size)
+		return ESTALE;	/* stale extent */
+
+	jEVENT(0,
+	       ("xtRelocate: xtype:%d xoff:0x%lx xlen:0x%x xaddr:0x%lx:0x%lx\n",
+		xtype, (ulong) xoff, xlen, (ulong) oxaddr,
+		(ulong) nxaddr));
+
+	/*
+	 *      1. get and validate the parent xtpage/xad entry
+	 *      covering the source extent to be relocated;
+	 */
+	if (xtype == DATAEXT) {
+		/* search in leaf entry */
+		rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
+		if (rc)
+			return rc;
+		if (cmp) {
+			XT_PUTPAGE(pmp);
+			return ESTALE;
+		}
+
+		/* retrieve search result */
+		XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
+
+		/* validate for exact match with a single entry */
+		xad = &pp->xad[index];
+		if (addressXAD(xad) != oxaddr || lengthXAD(xad) != xlen) {
+			XT_PUTPAGE(pmp);
+			return ESTALE;
+		}
+	} else {		/* (xtype == XTPAGE) */
+
+		/* search in internal entry */
+		rc = xtSearchNode(ip, oxad, &cmp, &btstack, 0);
+		if (rc)
+			return rc;
+		if (cmp) {
+			XT_PUTPAGE(pmp);
+			return ESTALE;
+		}
+
+		/* retrieve search result */
+		XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
+
+		/* xtSearchNode() validated for exact match with a single entry
+		 */
+		xad = &pp->xad[index];
+	}
+	jEVENT(0, ("xtRelocate: parent xad entry validated.\n"));
+
+	/*
+	 *      2. relocate the extent
+	 */
+	if (xtype == DATAEXT) {
+		/* if the extent is allocated-but-not-recorded
+		 * there is no real data to be moved in this extent,
+		 */
+		if (xad->flag & XAD_NOTRECORDED)
+			goto out;
+		else
+			/* release xtpage for cmRead()/xtLookup() */
+			XT_PUTPAGE(pmp);
+
+		/*
+		 *      cmRelocate()
+		 *
+		 * copy target data pages to be relocated;
+		 *
+		 * data extent must start at page boundary and
+		 * multiple of page size (except the last data extent);
+		 * read in each page of the source data extent into cbuf,
+		 * update the cbuf extent descriptor of the page to be
+		 * homeward bound to new dst data extent
+		 * copy the data from the old extent to new extent.
+		 * copy is essential for compressed files to avoid problems
+		 * that can arise if there was a change in compression
+		 * algorithms.
+		 * it is a good strategy because it may disrupt cache
+		 * policy to keep the pages in memory afterwards.
+		 */
+		offset = xoff << JFS_SBI(ip->i_sb)->l2bsize;
+		assert((offset & CM_OFFSET) == 0);
+		nbytes = xlen << JFS_SBI(ip->i_sb)->l2bsize;
+		pno = offset >> CM_L2BSIZE;
+		npages = (nbytes + (CM_BSIZE - 1)) >> CM_L2BSIZE;
+/*
+                npages = ((offset + nbytes - 1) >> CM_L2BSIZE) -
+                         (offset >> CM_L2BSIZE) + 1;
+*/
+		sxaddr = oxaddr;
+		dxaddr = nxaddr;
+
+		/* process the request one cache buffer at a time */
+		for (nbrd = 0; nbrd < nbytes; nbrd += nb,
+		     offset += nb, pno++, npages--) {
+			/* compute page size */
+			nb = min(nbytes - nbrd, CM_BSIZE);
+
+			/* get the cache buffer of the page */
+			if (rc = cmRead(ip, offset, npages, &cp))
+				break;
+
+			assert(addressPXD(&cp->cm_pxd) == sxaddr);
+			assert(!cp->cm_modified);
+
+			/* bind buffer with the new extent address */
+			nblks = nb >> JFS_IP(ip->i_sb)->l2bsize;
+			cmSetXD(ip, cp, pno, dxaddr, nblks);
+
+			/* release the cbuf, mark it as modified */
+			cmPut(cp, TRUE);
+
+			dxaddr += nblks;
+			sxaddr += nblks;
+		}
+
+		/* get back parent page */
+		rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
+		XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
+		jEVENT(0, ("xtRelocate: target data extent relocated.\n"));
+	} else {		/* (xtype  == XTPAGE) */
+
+		/*
+		 * read in the target xtpage from the source extent;
+		 */
+		XT_GETPAGE(ip, oxaddr, mp, PSIZE, p, rc);
+		if (rc) {
+			XT_PUTPAGE(pmp);
+			return rc;
+		}
+
+		/*
+		 * read in sibling pages if any to update sibling pointers;
+		 */
+		rmp = NULL;
+		if (p->header.next) {
+			nextbn = le64_to_cpu(p->header.next);
+			XT_GETPAGE(ip, nextbn, rmp, PSIZE, rp, rc);
+			if (rc) {
+				XT_PUTPAGE(pmp);
+				XT_PUTPAGE(mp);
+				return (rc);
+			}
+		}
+
+		lmp = NULL;
+		if (p->header.prev) {
+			prevbn = le64_to_cpu(p->header.prev);
+			XT_GETPAGE(ip, prevbn, lmp, PSIZE, lp, rc);
+			if (rc) {
+				XT_PUTPAGE(pmp);
+				XT_PUTPAGE(mp);
+				if (rmp)
+					XT_PUTPAGE(rmp);
+				return (rc);
+			}
+		}
+
+		/* at this point, all xtpages to be updated are in memory */
+
+		/*
+		 * update sibling pointers of sibling xtpages if any;
+		 */
+		if (lmp) {
+			BT_MARK_DIRTY(lmp, ip);
+			tlck =
+			    txLock(tid, ip, lmp, tlckXTREE | tlckRELINK);
+			lp->header.next = cpu_to_le64(nxaddr);
+			XT_PUTPAGE(lmp);
+		}
+
+		if (rmp) {
+			BT_MARK_DIRTY(rmp, ip);
+			tlck =
+			    txLock(tid, ip, rmp, tlckXTREE | tlckRELINK);
+			rp->header.prev = cpu_to_le64(nxaddr);
+			XT_PUTPAGE(rmp);
+		}
+
+		/*
+		 * update the target xtpage to be relocated
+		 *
+		 * update the self address of the target page
+		 * and write to destination extent;
+		 * redo image covers the whole xtpage since it is new page
+		 * to the destination extent;
+		 * update of bmap for the free of source extent
+		 * of the target xtpage itself:
+		 * update of bmap for the allocation of destination extent
+		 * of the target xtpage itself:
+		 * update of bmap for the extents covered by xad entries in
+		 * the target xtpage is not necessary since they are not
+		 * updated;
+		 * if not committed before this relocation,
+		 * target page may contain XAD_NEW entries which must
+		 * be scanned for bmap update (logredo() always
+		 * scan xtpage REDOPAGE image for bmap update);
+		 * if committed before this relocation (tlckRELOCATE),
+		 * scan may be skipped by commit() and logredo();
+		 */
+		BT_MARK_DIRTY(mp, ip);
+		/* tlckNEW init  xtlck->lwm.offset = XTENTRYSTART; */
+		tlck = txLock(tid, ip, mp, tlckXTREE | tlckNEW);
+		xtlck = (struct xtlock *) & tlck->lock;
+
+		/* update the self address in the xtpage header */
+		pxd = &p->header.self;
+		PXDaddress(pxd, nxaddr);
+
+		/* linelock for the after image of the whole page */
+		xtlck->lwm.length =
+		    le16_to_cpu(p->header.nextindex) - xtlck->lwm.offset;
+
+		/* update the buffer extent descriptor of target xtpage */
+		xsize = xlen << JFS_SBI(ip->i_sb)->l2bsize;
+		bmSetXD(mp, nxaddr, xsize);
+
+		/* unpin the target page to new homeward bound */
+		XT_PUTPAGE(mp);
+		jEVENT(0, ("xtRelocate: target xtpage relocated.\n"));
+	}
+
+	/*
+	 *      3. acquire maplock for the source extent to be freed;
+	 *
+	 * acquire a maplock saving the src relocated extent address;
+	 * to free of the extent at commit time;
+	 */
+      out:
+	/* if DATAEXT relocation, write a LOG_UPDATEMAP record for
+	 * free PXD of the source data extent (logredo() will update
+	 * bmap for free of source data extent), and update bmap for
+	 * free of the source data extent;
+	 */
+	if (xtype == DATAEXT)
+		tlck = txMaplock(tid, ip, tlckMAP);
+	/* if XTPAGE relocation, write a LOG_NOREDOPAGE record
+	 * for the source xtpage (logredo() will init NoRedoPage
+	 * filter and will also update bmap for free of the source
+	 * xtpage), and update bmap for free of the source xtpage;
+	 * N.B. We use tlckMAP instead of tlkcXTREE because there
+	 *      is no buffer associated with this lock since the buffer
+	 *      has been redirected to the target location.
+	 */
+	else			/* (xtype  == XTPAGE) */
+		tlck = txMaplock(tid, ip, tlckMAP | tlckRELOCATE);
+
+	pxdlock = (struct pxd_lock *) & tlck->lock;
+	pxdlock->flag = mlckFREEPXD;
+	PXDaddress(&pxdlock->pxd, oxaddr);
+	PXDlength(&pxdlock->pxd, xlen);
+	pxdlock->index = 1;
+
+	/*
+	 *      4. update the parent xad entry for relocation;
+	 *
+	 * acquire tlck for the parent entry with XAD_NEW as entry
+	 * update which will write LOG_REDOPAGE and update bmap for
+	 * allocation of XAD_NEW destination extent;
+	 */
+	jEVENT(0, ("xtRelocate: update parent xad entry.\n"));
+	BT_MARK_DIRTY(pmp, ip);
+	tlck = txLock(tid, ip, pmp, tlckXTREE | tlckGROW);
+	xtlck = (struct xtlock *) & tlck->lock;
+
+	/* update the XAD with the new destination extent; */
+	xad = &pp->xad[index];
+	xad->flag |= XAD_NEW;
+	XADaddress(xad, nxaddr);
+
+	xtlck->lwm.offset = min(index, xtlck->lwm.offset);
+	xtlck->lwm.length = le16_to_cpu(pp->header.nextindex) -
+	    xtlck->lwm.offset;
+
+	/* unpin the parent xtpage */
+	XT_PUTPAGE(pmp);
+
+	return rc;
+}
+
+
+/*
+ *      xtSearchNode()
+ *
+ * function:    search for the internal xad entry covering specified extent.
+ *              This function is mainly used by defragfs utility.
+ *
+ * parameters:
+ *      ip      - file object;
+ *      xad     - extent to find;
+ *      cmpp    - comparison result:
+ *      btstack - traverse stack;
+ *      flag    - search process flag;
+ *
+ * returns:
+ *      btstack contains (bn, index) of search path traversed to the entry.
+ *      *cmpp is set to result of comparison with the entry returned.
+ *      the page containing the entry is pinned at exit.
+ */
+static int xtSearchNode(struct inode *ip, xad_t * xad,	/* required XAD entry */
+			int *cmpp, struct btstack * btstack, int flag)
+{
+	int rc = 0;
+	s64 xoff, xaddr;
+	int xlen;
+	int cmp = 1;		/* init for empty page */
+	s64 bn;			/* block number */
+	struct metapage *mp;	/* meta-page buffer */
+	xtpage_t *p;		/* page */
+	int base, index, lim;
+	struct btframe *btsp;
+	s64 t64;
+
+	BT_CLR(btstack);
+
+	xoff = offsetXAD(xad);
+	xlen = lengthXAD(xad);
+	xaddr = addressXAD(xad);
+
+	/*
+	 *      search down tree from root:
+	 *
+	 * between two consecutive entries of <Ki, Pi> and <Kj, Pj> of
+	 * internal page, child page Pi contains entry with k, Ki <= K < Kj.
+	 *
+	 * if entry with search key K is not found
+	 * internal page search find the entry with largest key Ki
+	 * less than K which point to the child page to search;
+	 * leaf page search find the entry with smallest key Kj
+	 * greater than K so that the returned index is the position of
+	 * the entry to be shifted right for insertion of new entry.
+	 * for empty tree, search key is greater than any key of the tree.
+	 *
+	 * by convention, root bn = 0.
+	 */
+	for (bn = 0;;) {
+		/* get/pin the page to search */
+		XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+		if (p->header.flag & BT_LEAF)
+			return ESTALE;
+
+		lim = le16_to_cpu(p->header.nextindex) - XTENTRYSTART;
+
+		/*
+		 * binary search with search key K on the current page
+		 */
+		for (base = XTENTRYSTART; lim; lim >>= 1) {
+			index = base + (lim >> 1);
+
+			XT_CMP(cmp, xoff, &p->xad[index], t64);
+			if (cmp == 0) {
+				/*
+				 *      search hit
+				 *
+				 * verify for exact match;
+				 */
+				if (xaddr == addressXAD(&p->xad[index]) &&
+				    xoff == offsetXAD(&p->xad[index])) {
+					*cmpp = cmp;
+
+					/* save search result */
+					btsp = btstack->top;
+					btsp->bn = bn;
+					btsp->index = index;
+					btsp->mp = mp;
+
+					return 0;
+				}
+
+				/* descend/search its child page */
+				goto next;
+			}
+
+			if (cmp > 0) {
+				base = index + 1;
+				--lim;
+			}
+		}
+
+		/*
+		 *      search miss - non-leaf page:
+		 *
+		 * base is the smallest index with key (Kj) greater than
+		 * search key (K) and may be zero or maxentry index.
+		 * if base is non-zero, decrement base by one to get the parent
+		 * entry of the child page to search.
+		 */
+		index = base ? base - 1 : base;
+
+		/*
+		 * go down to child page
+		 */
+	      next:
+		/* get the child page block number */
+		bn = addressXAD(&p->xad[index]);
+
+		/* unpin the parent page */
+		XT_PUTPAGE(mp);
+	}
+}
+
+
+/*
+ *      xtRelink()
+ *
+ * function:
+ *      link around a freed page.
+ *
+ * Parameter:
+ *      int           tid,
+ *      struct inode    *ip,
+ *      xtpage_t        *p)
+ *
+ * returns:
+ */
+static int xtRelink(tid_t tid, struct inode *ip, xtpage_t * p)
+{
+	int rc = 0;
+	struct metapage *mp;
+	s64 nextbn, prevbn;
+	struct tlock *tlck;
+
+	nextbn = le64_to_cpu(p->header.next);
+	prevbn = le64_to_cpu(p->header.prev);
+
+	/* update prev pointer of the next page */
+	if (nextbn != 0) {
+		XT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		/*
+		 * acquire a transaction lock on the page;
+		 *
+		 * action: update prev pointer;
+		 */
+		BT_MARK_DIRTY(mp, ip);
+		tlck = txLock(tid, ip, mp, tlckXTREE | tlckRELINK);
+
+		/* the page may already have been tlock'd */
+
+		p->header.prev = cpu_to_le64(prevbn);
+
+		XT_PUTPAGE(mp);
+	}
+
+	/* update next pointer of the previous page */
+	if (prevbn != 0) {
+		XT_GETPAGE(ip, prevbn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		/*
+		 * acquire a transaction lock on the page;
+		 *
+		 * action: update next pointer;
+		 */
+		BT_MARK_DIRTY(mp, ip);
+		tlck = txLock(tid, ip, mp, tlckXTREE | tlckRELINK);
+
+		/* the page may already have been tlock'd */
+
+		p->header.next = le64_to_cpu(nextbn);
+
+		XT_PUTPAGE(mp);
+	}
+
+	return 0;
+}
+#endif				/*  _STILL_TO_PORT */
+
+
+/*
+ *      xtInitRoot()
+ *
+ * initialize file root (inline in inode)
+ */
+void xtInitRoot(tid_t tid, struct inode *ip)
+{
+	xtpage_t *p;
+	struct tlock *tlck;
+
+	/*
+	 * acquire a transaction lock on the root
+	 *
+	 * action:
+	 */
+	tlck = txLock(tid, ip, (struct metapage *) &JFS_IP(ip)->bxflag,
+		      tlckXTREE | tlckNEW);
+	p = &JFS_IP(ip)->i_xtroot;
+
+	p->header.flag = DXD_INDEX | BT_ROOT | BT_LEAF;
+	p->header.nextindex = cpu_to_le16(XTENTRYSTART);
+
+	if (S_ISDIR(ip->i_mode))
+		p->header.maxentry = cpu_to_le16(XTROOTINITSLOT_DIR);
+	else {
+		p->header.maxentry = cpu_to_le16(XTROOTINITSLOT);
+		ip->i_size = 0;
+	}
+
+
+	return;
+}
+
+
+/*
+ * We can run into a deadlock truncating a file with a large number of
+ * xtree pages (large fragmented file).  A robust fix would entail a
+ * reservation system where we would reserve a number of metadata pages
+ * and tlocks which we would be guaranteed without a deadlock.  Without
+ * this, a partial fix is to limit number of metadata pages we will lock
+ * in a single transaction.  Currently we will truncate the file so that
+ * no more than 50 leaf pages will be locked.  The caller of xtTruncate
+ * will be responsible for ensuring that the current transaction gets
+ * committed, and that subsequent transactions are created to truncate
+ * the file further if needed.
+ */
+#define MAX_TRUNCATE_LEAVES 50
+
+/*
+ *      xtTruncate()
+ *
+ * function:
+ *      traverse for truncation logging backward bottom up;
+ *      terminate at the last extent entry at the current subtree
+ *      root page covering new down size.
+ *      truncation may occur within the last extent entry.
+ *
+ * parameter:
+ *      int           tid,
+ *      struct inode    *ip,
+ *      s64           newsize,
+ *      int           type)   {PWMAP, PMAP, WMAP; DELETE, TRUNCATE}
+ *
+ * return:
+ *
+ * note:
+ *      PWMAP:
+ *       1. truncate (non-COMMIT_NOLINK file)
+ *          by jfs_truncate() or jfs_open(O_TRUNC):
+ *          xtree is updated;
+ *	 2. truncate index table of directory when last entry removed
+ *       map update via tlock at commit time;
+ *      PMAP:
+ *	 Call xtTruncate_pmap instead
+ *      WMAP:
+ *       1. remove (free zero link count) on last reference release
+ *          (pmap has been freed at commit zero link count);
+ *       2. truncate (COMMIT_NOLINK file, i.e., tmp file):
+ *          xtree is updated;
+ *       map update directly at truncation time;
+ *
+ *      if (DELETE)
+ *              no LOG_NOREDOPAGE is required (NOREDOFILE is sufficient);
+ *      else if (TRUNCATE)
+ *              must write LOG_NOREDOPAGE for deleted index page;
+ *
+ * pages may already have been tlocked by anonymous transactions
+ * during file growth (i.e., write) before truncation;
+ *
+ * except last truncated entry, deleted entries remains as is
+ * in the page (nextindex is updated) for other use
+ * (e.g., log/update allocation map): this avoid copying the page
+ * info but delay free of pages;
+ *
+ */
+s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
+{
+	int rc = 0;
+	s64 teof;
+	struct metapage *mp;
+	xtpage_t *p;
+	s64 bn;
+	int index, nextindex;
+	xad_t *xad;
+	s64 xoff, xaddr;
+	int xlen, len, freexlen;
+	struct btstack btstack;
+	struct btframe *parent;
+	struct tblock *tblk = 0;
+	struct tlock *tlck = 0;
+	struct xtlock *xtlck = 0;
+	struct xdlistlock xadlock;	/* maplock for COMMIT_WMAP */
+	struct pxd_lock *pxdlock;		/* maplock for COMMIT_WMAP */
+	s64 nfreed;
+	int freed, log;
+	int locked_leaves = 0;
+
+	/* save object truncation type */
+	if (tid) {
+		tblk = tid_to_tblock(tid);
+		tblk->xflag |= flag;
+	}
+
+	nfreed = 0;
+
+	flag &= COMMIT_MAP;
+	assert(flag != COMMIT_PMAP);
+
+	if (flag == COMMIT_PWMAP)
+		log = 1;
+	else {
+		log = 0;
+		xadlock.flag = mlckFREEXADLIST;
+		xadlock.index = 1;
+	}
+
+	/*
+	 * if the newsize is not an integral number of pages,
+	 * the file between newsize and next page boundary will
+	 * be cleared.
+	 * if truncating into a file hole, it will cause
+	 * a full block to be allocated for the logical block.
+	 */
+
+	/*
+	 * release page blocks of truncated region <teof, eof>
+	 *
+	 * free the data blocks from the leaf index blocks.
+	 * delete the parent index entries corresponding to
+	 * the freed child data/index blocks.
+	 * free the index blocks themselves which aren't needed
+	 * in new sized file.
+	 *
+	 * index blocks are updated only if the blocks are to be
+	 * retained in the new sized file.
+	 * if type is PMAP, the data and index pages are NOT
+	 * freed, and the data and index blocks are NOT freed
+	 * from  working map.
+	 * (this will allow continued access of data/index of
+	 * temporary file (zerolink count file truncated to zero-length)).
+	 */
+	teof = (newsize + (JFS_SBI(ip->i_sb)->bsize - 1)) >>
+	    JFS_SBI(ip->i_sb)->l2bsize;
+
+	/* clear stack */
+	BT_CLR(&btstack);
+
+	/*
+	 * start with root
+	 *
+	 * root resides in the inode
+	 */
+	bn = 0;
+
+	/*
+	 * first access of each page:
+	 */
+      getPage:
+	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return -rc;
+
+	/* process entries backward from last index */
+	index = le16_to_cpu(p->header.nextindex) - 1;
+
+	if (p->header.flag & BT_INTERNAL)
+		goto getChild;
+
+	/*
+	 *      leaf page
+	 */
+
+	/* Since this is the rightmost leaf, and we may have already freed
+	 * a page that was formerly to the right, let's make sure that the
+	 * next pointer is zero.
+	 */
+	p->header.next = 0;
+
+	freed = 0;
+
+	/* does region covered by leaf page precede Teof ? */
+	xad = &p->xad[index];
+	xoff = offsetXAD(xad);
+	xlen = lengthXAD(xad);
+	if (teof >= xoff + xlen) {
+		XT_PUTPAGE(mp);
+		goto getParent;
+	}
+
+	/* (re)acquire tlock of the leaf page */
+	if (log) {
+		if (++locked_leaves > MAX_TRUNCATE_LEAVES) {
+			/*
+			 * We need to limit the size of the transaction
+			 * to avoid exhausting pagecache & tlocks
+			 */
+			XT_PUTPAGE(mp);
+			newsize = (xoff + xlen) << JFS_SBI(ip->i_sb)->l2bsize;
+			goto getParent;
+		}
+		tlck = txLock(tid, ip, mp, tlckXTREE);
+		tlck->type = tlckXTREE | tlckTRUNCATE;
+		xtlck = (struct xtlock *) & tlck->lock;
+		xtlck->hwm.offset = le16_to_cpu(p->header.nextindex) - 1;
+	}
+	BT_MARK_DIRTY(mp, ip);
+
+	/*
+	 * scan backward leaf page entries
+	 */
+	for (; index >= XTENTRYSTART; index--) {
+		xad = &p->xad[index];
+		xoff = offsetXAD(xad);
+		xlen = lengthXAD(xad);
+		xaddr = addressXAD(xad);
+
+		/*
+		 * entry beyond eof: continue scan of current page
+		 *          xad
+		 * ---|---=======------->
+		 *   eof
+		 */
+		if (teof < xoff) {
+			nfreed += xlen;
+			continue;
+		}
+
+		/*
+		 * (xoff <= teof): last entry to be deleted from page;
+		 * If other entries remain in page: keep and update the page.
+		 */
+
+		/*
+		 * eof == entry_start: delete the entry
+		 *           xad
+		 * -------|=======------->
+		 *       eof
+		 *
+		 */
+		if (teof == xoff) {
+			nfreed += xlen;
+
+			if (index == XTENTRYSTART)
+				break;
+
+			nextindex = index;
+		}
+		/*
+		 * eof within the entry: truncate the entry.
+		 *          xad
+		 * -------===|===------->
+		 *          eof
+		 */
+		else if (teof < xoff + xlen) {
+			/* update truncated entry */
+			len = teof - xoff;
+			freexlen = xlen - len;
+			XADlength(xad, len);
+
+			/* save pxd of truncated extent in tlck */
+			xaddr += len;
+			if (log) {	/* COMMIT_PWMAP */
+				xtlck->lwm.offset = (xtlck->lwm.offset) ?
+				    min(index, (int)xtlck->lwm.offset) : index;
+				xtlck->lwm.length = index + 1 -
+				    xtlck->lwm.offset;
+				xtlck->twm.offset = index;
+				pxdlock = (struct pxd_lock *) & xtlck->pxdlock;
+				pxdlock->flag = mlckFREEPXD;
+				PXDaddress(&pxdlock->pxd, xaddr);
+				PXDlength(&pxdlock->pxd, freexlen);
+			}
+			/* free truncated extent */
+			else {	/* COMMIT_WMAP */
+
+				pxdlock = (struct pxd_lock *) & xadlock;
+				pxdlock->flag = mlckFREEPXD;
+				PXDaddress(&pxdlock->pxd, xaddr);
+				PXDlength(&pxdlock->pxd, freexlen);
+				txFreeMap(ip, pxdlock, 0, COMMIT_WMAP);
+
+				/* reset map lock */
+				xadlock.flag = mlckFREEXADLIST;
+			}
+
+			/* current entry is new last entry; */
+			nextindex = index + 1;
+
+			nfreed += freexlen;
+		}
+		/*
+		 * eof beyond the entry:
+		 *          xad
+		 * -------=======---|--->
+		 *                 eof
+		 */
+		else {		/* (xoff + xlen < teof) */
+
+			nextindex = index + 1;
+		}
+
+		if (nextindex < le16_to_cpu(p->header.nextindex)) {
+			if (!log) {	/* COMMIT_WAMP */
+				xadlock.xdlist = &p->xad[nextindex];
+				xadlock.count =
+				    le16_to_cpu(p->header.nextindex) -
+				    nextindex;
+				txFreeMap(ip, (struct maplock *) & xadlock, 0,
+					  COMMIT_WMAP);
+			}
+			p->header.nextindex = cpu_to_le16(nextindex);
+		}
+
+		XT_PUTPAGE(mp);
+
+		/* assert(freed == 0); */
+		goto getParent;
+	}			/* end scan of leaf page entries */
+
+	freed = 1;
+
+	/*
+	 * leaf page become empty: free the page if type != PMAP
+	 */
+	if (log) {		/* COMMIT_PWMAP */
+		/* txCommit() with tlckFREE:
+		 * free data extents covered by leaf [XTENTRYSTART:hwm);
+		 * invalidate leaf if COMMIT_PWMAP;
+		 * if (TRUNCATE), will write LOG_NOREDOPAGE;
+		 */
+		tlck->type = tlckXTREE | tlckFREE;
+	} else {		/* COMMIT_WAMP */
+
+		/* free data extents covered by leaf */
+		xadlock.xdlist = &p->xad[XTENTRYSTART];
+		xadlock.count =
+		    le16_to_cpu(p->header.nextindex) - XTENTRYSTART;
+		txFreeMap(ip, (struct maplock *) & xadlock, 0, COMMIT_WMAP);
+	}
+
+	if (p->header.flag & BT_ROOT) {
+		p->header.flag &= ~BT_INTERNAL;
+		p->header.flag |= BT_LEAF;
+		p->header.nextindex = cpu_to_le16(XTENTRYSTART);
+
+		XT_PUTPAGE(mp);	/* debug */
+		goto out;
+	} else {
+		if (log) {	/* COMMIT_PWMAP */
+			/* page will be invalidated at tx completion
+			 */
+			XT_PUTPAGE(mp);
+		} else {	/* COMMIT_WMAP */
+
+			if (mp->lid)
+				lid_to_tlock(mp->lid)->flag |= tlckFREELOCK;
+
+			/* invalidate empty leaf page */
+			discard_metapage(mp);
+		}
+	}
+
+	/*
+	 * the leaf page become empty: delete the parent entry
+	 * for the leaf page if the parent page is to be kept
+	 * in the new sized file.
+	 */
+
+	/*
+	 * go back up to the parent page
+	 */
+      getParent:
+	/* pop/restore parent entry for the current child page */
+	if ((parent = BT_POP(&btstack)) == NULL)
+		/* current page must have been root */
+		goto out;
+
+	/* get back the parent page */
+	bn = parent->bn;
+	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return -rc;
+
+	index = parent->index;
+
+	/*
+	 * child page was not empty:
+	 */
+	if (freed == 0) {
+		/* has any entry deleted from parent ? */
+		if (index < le16_to_cpu(p->header.nextindex) - 1) {
+			/* (re)acquire tlock on the parent page */
+			if (log) {	/* COMMIT_PWMAP */
+				/* txCommit() with tlckTRUNCATE:
+				 * free child extents covered by parent [);
+				 */
+				tlck = txLock(tid, ip, mp, tlckXTREE);
+				xtlck = (struct xtlock *) & tlck->lock;
+				if (!(tlck->type & tlckTRUNCATE)) {
+					xtlck->hwm.offset =
+					    le16_to_cpu(p->header.
+							nextindex) - 1;
+					tlck->type =
+					    tlckXTREE | tlckTRUNCATE;
+				}
+			} else {	/* COMMIT_WMAP */
+
+				/* free child extents covered by parent */
+				xadlock.xdlist = &p->xad[index + 1];
+				xadlock.count =
+				    le16_to_cpu(p->header.nextindex) -
+				    index - 1;
+				txFreeMap(ip, (struct maplock *) & xadlock, 0,
+					  COMMIT_WMAP);
+			}
+			BT_MARK_DIRTY(mp, ip);
+
+			p->header.nextindex = cpu_to_le16(index + 1);
+		}
+		XT_PUTPAGE(mp);
+		goto getParent;
+	}
+
+	/*
+	 * child page was empty:
+	 */
+	nfreed += lengthXAD(&p->xad[index]);
+
+	/*
+	 * During working map update, child page's tlock must be handled
+	 * before parent's.  This is because the parent's tlock will cause
+	 * the child's disk space to be marked available in the wmap, so
+	 * it's important that the child page be released by that time.
+	 *
+	 * ToDo:  tlocks should be on doubly-linked list, so we can
+	 * quickly remove it and add it to the end.
+	 */
+
+	/*
+	 * Move parent page's tlock to the end of the tid's tlock list
+	 */
+	if (log && mp->lid && (tblk->last != mp->lid) &&
+	    lid_to_tlock(mp->lid)->tid) {
+		lid_t lid = mp->lid;
+		struct tlock *prev;
+
+		tlck = lid_to_tlock(lid);
+
+		if (tblk->next == lid)
+			tblk->next = tlck->next;
+		else {
+			for (prev = lid_to_tlock(tblk->next);
+			     prev->next != lid;
+			     prev = lid_to_tlock(prev->next)) {
+				assert(prev->next);
+			}
+			prev->next = tlck->next;
+		}
+		lid_to_tlock(tblk->last)->next = lid;
+		tlck->next = 0;
+		tblk->last = lid;
+	}
+
+	/*
+	 * parent page become empty: free the page
+	 */
+	if (index == XTENTRYSTART) {
+		if (log) {	/* COMMIT_PWMAP */
+			/* txCommit() with tlckFREE:
+			 * free child extents covered by parent;
+			 * invalidate parent if COMMIT_PWMAP;
+			 */
+			tlck = txLock(tid, ip, mp, tlckXTREE);
+			xtlck = (struct xtlock *) & tlck->lock;
+			xtlck->hwm.offset =
+			    le16_to_cpu(p->header.nextindex) - 1;
+			tlck->type = tlckXTREE | tlckFREE;
+		} else {	/* COMMIT_WMAP */
+
+			/* free child extents covered by parent */
+			xadlock.xdlist = &p->xad[XTENTRYSTART];
+			xadlock.count =
+			    le16_to_cpu(p->header.nextindex) -
+			    XTENTRYSTART;
+			txFreeMap(ip, (struct maplock *) & xadlock, 0,
+				  COMMIT_WMAP);
+		}
+		BT_MARK_DIRTY(mp, ip);
+
+		if (p->header.flag & BT_ROOT) {
+			p->header.flag &= ~BT_INTERNAL;
+			p->header.flag |= BT_LEAF;
+			p->header.nextindex = cpu_to_le16(XTENTRYSTART);
+			if (le16_to_cpu(p->header.maxentry) == XTROOTMAXSLOT) {
+				/*
+				 * Shrink root down to allow inline
+				 * EA (otherwise fsck complains)
+				 */
+				p->header.maxentry =
+				    cpu_to_le16(XTROOTINITSLOT);
+				JFS_IP(ip)->mode2 |= INLINEEA;
+			}
+
+			XT_PUTPAGE(mp);	/* debug */
+			goto out;
+		} else {
+			if (log) {	/* COMMIT_PWMAP */
+				/* page will be invalidated at tx completion
+				 */
+				XT_PUTPAGE(mp);
+			} else {	/* COMMIT_WMAP */
+
+				if (mp->lid)
+					lid_to_tlock(mp->lid)->flag |=
+						tlckFREELOCK;
+
+				/* invalidate parent page */
+				discard_metapage(mp);
+			}
+
+			/* parent has become empty and freed:
+			 * go back up to its parent page
+			 */
+			/* freed = 1; */
+			goto getParent;
+		}
+	}
+	/*
+	 * parent page still has entries for front region;
+	 */
+	else {
+		/* try truncate region covered by preceding entry
+		 * (process backward)
+		 */
+		index--;
+
+		/* go back down to the child page corresponding
+		 * to the entry
+		 */
+		goto getChild;
+	}
+
+	/*
+	 *      internal page: go down to child page of current entry
+	 */
+      getChild:
+	/* save current parent entry for the child page */
+	BT_PUSH(&btstack, bn, index);
+
+	/* get child page */
+	xad = &p->xad[index];
+	bn = addressXAD(xad);
+
+	/*
+	 * first access of each internal entry:
+	 */
+	/* release parent page */
+	XT_PUTPAGE(mp);
+
+	/* process the child page */
+	goto getPage;
+
+      out:
+	/*
+	 * update file resource stat
+	 */
+	/* set size
+	 */
+	if (S_ISDIR(ip->i_mode) && !newsize)
+		ip->i_size = 1;	/* fsck hates zero-length directories */
+	else
+		ip->i_size = newsize;
+
+	/* update nblocks to reflect freed blocks */
+	ip->i_blocks -= LBLK2PBLK(ip->i_sb, nfreed);
+
+	/*
+	 * free tlock of invalidated pages
+	 */
+	if (flag == COMMIT_WMAP)
+		txFreelock(ip);
+
+	return newsize;
+}
+
+
+/*
+ *      xtTruncate_pmap()
+ *
+ * function:
+ *	Perform truncate to zero lenghth for deleted file, leaving the
+ *	the xtree and working map untouched.  This allows the file to
+ *	be accessed via open file handles, while the delete of the file
+ *	is committed to disk.
+ *
+ * parameter:
+ *      tid_t		tid,
+ *      struct inode	*ip,
+ *      s64		committed_size)
+ *
+ * return: new committed size
+ *
+ * note:
+ *
+ *	To avoid deadlock by holding too many transaction locks, the
+ *	truncation may be broken up into multiple transactions.
+ *	The committed_size keeps track of part of the file has been
+ *	freed from the pmaps.
+ */
+s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
+{
+	s64 bn;
+	struct btstack btstack;
+	int cmp;
+	int index;
+	int locked_leaves = 0;
+	struct metapage *mp;
+	xtpage_t *p;
+	struct btframe *parent;
+	int rc;
+	struct tblock *tblk;
+	struct tlock *tlck = 0;
+	xad_t *xad;
+	int xlen;
+	s64 xoff;
+	struct xtlock *xtlck = 0;
+
+	/* save object truncation type */
+	tblk = tid_to_tblock(tid);
+	tblk->xflag |= COMMIT_PMAP;
+
+	/* clear stack */
+	BT_CLR(&btstack);
+
+	if (committed_size) {
+		xoff = (committed_size >> JFS_SBI(ip->i_sb)->l2bsize) - 1;
+		rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
+		if (rc)
+			return -rc;
+		assert(cmp == 0);
+		XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+	} else {
+		/*
+		 * start with root
+		 *
+		 * root resides in the inode
+		 */
+		bn = 0;
+
+		/*
+		 * first access of each page:
+		 */
+      getPage:
+		XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return -rc;
+
+		/* process entries backward from last index */
+		index = le16_to_cpu(p->header.nextindex) - 1;
+
+		if (p->header.flag & BT_INTERNAL)
+			goto getChild;
+	}
+
+	/*
+	 *      leaf page
+	 */
+
+	if (++locked_leaves > MAX_TRUNCATE_LEAVES) {
+		/*
+		 * We need to limit the size of the transaction
+		 * to avoid exhausting pagecache & tlocks
+		 */
+		xad = &p->xad[index];
+		xoff = offsetXAD(xad);
+		xlen = lengthXAD(xad);
+		XT_PUTPAGE(mp);
+		return  (xoff + xlen) << JFS_SBI(ip->i_sb)->l2bsize;
+	}
+	tlck = txLock(tid, ip, mp, tlckXTREE);
+	tlck->type = tlckXTREE | tlckFREE;
+	xtlck = (struct xtlock *) & tlck->lock;
+	xtlck->hwm.offset = index;
+
+
+	XT_PUTPAGE(mp);
+
+	/*
+	 * go back up to the parent page
+	 */
+      getParent:
+	/* pop/restore parent entry for the current child page */
+	if ((parent = BT_POP(&btstack)) == NULL)
+		/* current page must have been root */
+		goto out;
+
+	/* get back the parent page */
+	bn = parent->bn;
+	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return -rc;
+
+	index = parent->index;
+
+	/*
+	 * parent page become empty: free the page
+	 */
+	if (index == XTENTRYSTART) {
+		/* txCommit() with tlckFREE:
+		 * free child extents covered by parent;
+		 * invalidate parent if COMMIT_PWMAP;
+		 */
+		tlck = txLock(tid, ip, mp, tlckXTREE);
+		xtlck = (struct xtlock *) & tlck->lock;
+		xtlck->hwm.offset =
+		    le16_to_cpu(p->header.nextindex) - 1;
+		tlck->type = tlckXTREE | tlckFREE;
+
+		XT_PUTPAGE(mp);
+
+		if (p->header.flag & BT_ROOT) {
+
+			goto out;
+		} else {
+			goto getParent;
+		}
+	}
+	/*
+	 * parent page still has entries for front region;
+	 */
+	else
+		index--;
+	/*
+	 *      internal page: go down to child page of current entry
+	 */
+      getChild:
+	/* save current parent entry for the child page */
+	BT_PUSH(&btstack, bn, index);
+
+	/* get child page */
+	xad = &p->xad[index];
+	bn = addressXAD(xad);
+
+	/*
+	 * first access of each internal entry:
+	 */
+	/* release parent page */
+	XT_PUTPAGE(mp);
+
+	/* process the child page */
+	goto getPage;
+
+      out:
+
+	return 0;
+}
+
+
+#ifdef _JFS_DEBUG_XTREE
+/*
+ *      xtDisplayTree()
+ *
+ * function: traverse forward
+ */
+int xtDisplayTree(struct inode *ip)
+{
+	int rc = 0;
+	struct metapage *mp;
+	xtpage_t *p;
+	s64 bn, pbn;
+	int index, lastindex, v, h;
+	xad_t *xad;
+	struct btstack btstack;
+	struct btframe *btsp;
+	struct btframe *parent;
+
+	printk("display B+-tree.\n");
+
+	/* clear stack */
+	btsp = btstack.stack;
+
+	/*
+	 * start with root
+	 *
+	 * root resides in the inode
+	 */
+	bn = 0;
+	v = h = 0;
+
+	/*
+	 * first access of each page:
+	 */
+      getPage:
+	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return rc;
+
+	/* process entries forward from first index */
+	index = XTENTRYSTART;
+	lastindex = le16_to_cpu(p->header.nextindex) - 1;
+
+	if (p->header.flag & BT_INTERNAL) {
+		/*
+		 * first access of each internal page
+		 */
+		goto getChild;
+	} else {		/* (p->header.flag & BT_LEAF) */
+
+		/*
+		 * first access of each leaf page
+		 */
+		printf("leaf page ");
+		xtDisplayPage(ip, bn, p);
+
+		/* unpin the leaf page */
+		XT_PUTPAGE(mp);
+	}
+
+	/*
+	 * go back up to the parent page
+	 */
+      getParent:
+	/* pop/restore parent entry for the current child page */
+	if ((parent = (btsp == btstack.stack ? NULL : --btsp)) == NULL)
+		/* current page must have been root */
+		return;
+
+	/*
+	 * parent page scan completed
+	 */
+	if ((index = parent->index) == (lastindex = parent->lastindex)) {
+		/* go back up to the parent page */
+		goto getParent;
+	}
+
+	/*
+	 * parent page has entries remaining
+	 */
+	/* get back the parent page */
+	bn = parent->bn;
+	/* v = parent->level; */
+	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return rc;
+
+	/* get next parent entry */
+	index++;
+
+	/*
+	 * internal page: go down to child page of current entry
+	 */
+      getChild:
+	/* push/save current parent entry for the child page */
+	btsp->bn = pbn = bn;
+	btsp->index = index;
+	btsp->lastindex = lastindex;
+	/* btsp->level = v; */
+	/* btsp->node = h; */
+	++btsp;
+
+	/* get child page */
+	xad = &p->xad[index];
+	bn = addressXAD(xad);
+
+	/*
+	 * first access of each internal entry:
+	 */
+	/* release parent page */
+	XT_PUTPAGE(mp);
+
+	printk("traverse down 0x%lx[%d]->0x%lx\n", (ulong) pbn, index,
+	       (ulong) bn);
+	v++;
+	h = index;
+
+	/* process the child page */
+	goto getPage;
+}
+
+
+/*
+ *      xtDisplayPage()
+ *
+ * function: display page
+ */
+int xtDisplayPage(struct inode *ip, s64 bn, xtpage_t * p)
+{
+	int rc = 0;
+	struct metapage *mp;
+	xad_t *xad;
+	s64 xaddr, xoff;
+	int xlen, i, j;
+
+	if (p == NULL) {
+		XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+	}
+
+	/* display page control */
+	printf("bn:0x%lx flag:0x%x nextindex:%d\n",
+	       (ulong) bn, p->header.flag,
+	       le16_to_cpu(p->header.nextindex));
+
+	/* display entries */
+	xad = &p->xad[XTENTRYSTART];
+		for (i = XTENTRYSTART, j = 1; i < le16_to_cpu(p->header.nextindex);
+		     i++, xad++, j++) {
+			xoff = offsetXAD(xad);
+			xaddr = addressXAD(xad);
+			xlen = lengthXAD(xad);
+			printf("\t[%d] 0x%lx:0x%lx(0x%x)", i, (ulong) xoff,
+			       (ulong) xaddr, xlen);
+
+			if (j == 4) {
+				printf("\n");
+				j = 0;
+		}
+	}
+
+	printf("\n");
+}
+#endif				/* _JFS_DEBUG_XTREE */
+
+
+#ifdef _JFS_WIP
+/*
+ *      xtGather()
+ *
+ * function:
+ *      traverse for allocation acquiring tlock at commit time
+ *      (vs at the time of update) logging backward top down
+ *
+ * note:
+ *      problem - establishing that all new allocation have been
+ *      processed both for append and random write in sparse file
+ *      at the current entry at the current subtree root page
+ *
+ */
+int xtGather(t)
+btree_t *t;
+{
+	int rc = 0;
+	xtpage_t *p;
+	u64 bn;
+	int index;
+	btentry_t *e;
+	struct btstack btstack;
+	struct btsf *parent;
+
+	/* clear stack */
+	BT_CLR(&btstack);
+
+	/*
+	 * start with root
+	 *
+	 * root resides in the inode
+	 */
+	bn = 0;
+	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return rc;
+
+	/* new root is NOT pointed by a new entry
+	   if (p->header.flag & NEW)
+	   allocate new page lock;
+	   write a NEWPAGE log;
+	 */
+
+      dopage:
+	/*
+	 * first access of each page:
+	 */
+	/* process entries backward from last index */
+	index = le16_to_cpu(p->header.nextindex) - 1;
+
+	if (p->header.flag & BT_LEAF) {
+		/*
+		 * first access of each leaf page
+		 */
+		/* process leaf page entries backward */
+		for (; index >= XTENTRYSTART; index--) {
+			e = &p->xad[index];
+			/*
+			 * if newpage, log NEWPAGE.
+			 *
+			 if (e->flag & XAD_NEW) {
+			 nfound =+ entry->length;
+			 update current page lock for the entry;
+			 newpage(entry);
+			 *
+			 * if moved, log move.
+			 *
+			 } else if (e->flag & XAD_MOVED) {
+			 reset flag;
+			 update current page lock for the entry;
+			 }
+			 */
+		}
+
+		/* unpin the leaf page */
+		XT_PUTPAGE(mp);
+
+		/*
+		 * go back up to the parent page
+		 */
+	      getParent:
+		/* restore parent entry for the current child page */
+		if ((parent = BT_POP(&btstack)) == NULL)
+			/* current page must have been root */
+			return 0;
+
+		if ((index = parent->index) == XTENTRYSTART) {
+			/*
+			 * parent page scan completed
+			 */
+			/* go back up to the parent page */
+			goto getParent;
+		} else {
+			/*
+			 * parent page has entries remaining
+			 */
+			/* get back the parent page */
+			bn = parent->bn;
+			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+			if (rc)
+				return EIO;
+
+			/* first subroot page which
+			 * covers all new allocated blocks
+			 * itself not new/modified.
+			 * (if modified from split of descendent,
+			 * go down path of split page)
+
+			 if (nfound == nnew &&
+			 !(p->header.flag & (NEW | MOD)))
+			 exit scan;
+			 */
+
+			/* process parent page entries backward */
+			index--;
+		}
+	} else {
+		/*
+		 * first access of each internal page
+		 */
+	}
+
+	/*
+	 * internal page: go down to child page of current entry
+	 */
+
+	/* save current parent entry for the child page */
+	BT_PUSH(&btstack, bn, index);
+
+	/* get current entry for the child page */
+	e = &p->xad[index];
+
+	/*
+	 * first access of each internal entry:
+	 */
+	/*
+	 * if new entry, log btree_tnewentry.
+	 *
+	 if (e->flag & XAD_NEW)
+	 update parent page lock for the entry;
+	 */
+
+	/* release parent page */
+	XT_PUTPAGE(mp);
+
+	/* get child page */
+	bn = e->bn;
+	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return rc;
+
+	/*
+	 * first access of each non-root page:
+	 */
+	/*
+	 * if new, log btree_newpage.
+	 *
+	 if (p->header.flag & NEW)
+	 allocate new page lock;
+	 write a NEWPAGE log (next, prev);
+	 */
+
+	/* process the child page */
+	goto dopage;
+
+      out:
+	return 0;
+}
+#endif				/* _JFS_WIP */
+
+
+#ifdef CONFIG_JFS_STATISTICS
+int jfs_xtstat_read(char *buffer, char **start, off_t offset, int length,
+		    int *eof, void *data)
+{
+	int len = 0;
+	off_t begin;
+
+	len += sprintf(buffer,
+		       "JFS Xtree statistics\n"
+		       "====================\n"
+		       "searches = %d\n"
+		       "fast searches = %d\n"
+		       "splits = %d\n",
+		       xtStat.search,
+		       xtStat.fastSearch,
+		       xtStat.split);
+
+	begin = offset;
+	*start = buffer + begin;
+	len -= begin;
+
+	if (len > length)
+		len = length;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/jfs_xtree.h linux-2.4.20/fs/jfs/jfs_xtree.h
--- linux-2.4.19/fs/jfs/jfs_xtree.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/jfs_xtree.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,138 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ *   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
+ */
+#ifndef _H_JFS_XTREE
+#define _H_JFS_XTREE
+
+/*
+ *      jfs_xtree.h: extent allocation descriptor B+-tree manager
+ */
+
+#include "jfs_btree.h"
+
+
+/*
+ *      extent allocation descriptor (xad)
+ */
+typedef struct xad {
+	unsigned flag:8;	/* 1: flag */
+	unsigned rsvrd:16;	/* 2: reserved */
+	unsigned off1:8;	/* 1: offset in unit of fsblksize */
+	u32 off2;		/* 4: offset in unit of fsblksize */
+	unsigned len:24;	/* 3: length in unit of fsblksize */
+	unsigned addr1:8;	/* 1: address in unit of fsblksize */
+	u32 addr2;		/* 4: address in unit of fsblksize */
+} xad_t;			/* (16) */
+
+#define MAXXLEN         ((1 << 24) - 1)
+
+#define XTSLOTSIZE      16
+#define L2XTSLOTSIZE    4
+
+/* xad_t field construction */
+#define XADoffset(xad, offset64)\
+{\
+        (xad)->off1 = ((u64)offset64) >> 32;\
+        (xad)->off2 = __cpu_to_le32((offset64) & 0xffffffff);\
+}
+#define XADaddress(xad, address64)\
+{\
+        (xad)->addr1 = ((u64)address64) >> 32;\
+        (xad)->addr2 = __cpu_to_le32((address64) & 0xffffffff);\
+}
+#define XADlength(xad, length32)        (xad)->len = __cpu_to_le24(length32)
+
+/* xad_t field extraction */
+#define offsetXAD(xad)\
+        ( ((s64)((xad)->off1)) << 32 | __le32_to_cpu((xad)->off2))
+#define addressXAD(xad)\
+        ( ((s64)((xad)->addr1)) << 32 | __le32_to_cpu((xad)->addr2))
+#define lengthXAD(xad)  __le24_to_cpu((xad)->len)
+
+/* xad list */
+struct xadlist {
+	s16 maxnxad;
+	s16 nxad;
+	xad_t *xad;
+};
+
+/* xad_t flags */
+#define XAD_NEW         0x01	/* new */
+#define XAD_EXTENDED    0x02	/* extended */
+#define XAD_COMPRESSED  0x04	/* compressed with recorded length */
+#define XAD_NOTRECORDED 0x08	/* allocated but not recorded */
+#define XAD_COW         0x10	/* copy-on-write */
+
+
+/* possible values for maxentry */
+#define XTROOTINITSLOT_DIR  6
+#define XTROOTINITSLOT  10
+#define XTROOTMAXSLOT   18
+#define XTPAGEMAXSLOT   256
+#define XTENTRYSTART    2
+
+/*
+ *      xtree page:
+ */
+typedef union {
+	struct xtheader {
+		s64 next;	/* 8: */
+		s64 prev;	/* 8: */
+
+		u8 flag;	/* 1: */
+		u8 rsrvd1;	/* 1: */
+		s16 nextindex;	/* 2: next index = number of entries */
+		s16 maxentry;	/* 2: max number of entries */
+		s16 rsrvd2;	/* 2: */
+
+		pxd_t self;	/* 8: self */
+	} header;		/* (32) */
+
+	xad_t xad[XTROOTMAXSLOT];	/* 16 * maxentry: xad array */
+} xtpage_t;
+
+/*
+ *      external declaration
+ */
+extern int xtLookup(struct inode *ip, s64 lstart, s64 llen,
+		    int *pflag, s64 * paddr, int *plen, int flag);
+extern int xtLookupList(struct inode *ip, struct lxdlist * lxdlist,
+			struct xadlist * xadlist, int flag);
+extern void xtInitRoot(tid_t tid, struct inode *ip);
+extern int xtInsert(tid_t tid, struct inode *ip,
+		    int xflag, s64 xoff, int xlen, s64 * xaddrp, int flag);
+extern int xtExtend(tid_t tid, struct inode *ip, s64 xoff, int xlen,
+		    int flag);
+extern int xtTailgate(tid_t tid, struct inode *ip,
+		      s64 xoff, int xlen, s64 xaddr, int flag);
+extern int xtUpdate(tid_t tid, struct inode *ip, struct xad *nxad);
+extern int xtDelete(tid_t tid, struct inode *ip, s64 xoff, int xlen,
+		    int flag);
+extern s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int type);
+extern s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size);
+extern int xtRelocate(tid_t tid, struct inode *ip,
+		      xad_t * oxad, s64 nxaddr, int xtype);
+extern int xtAppend(tid_t tid,
+		    struct inode *ip, int xflag, s64 xoff, int maxblocks,
+		    int *xlenp, s64 * xaddrp, int flag);
+
+#ifdef  _JFS_DEBUG_XTREE
+extern int xtDisplayTree(struct inode *ip);
+extern int xtDisplayPage(struct inode *ip, s64 bn, xtpage_t * p);
+#endif				/* _JFS_DEBUG_XTREE */
+
+#endif				/* !_H_JFS_XTREE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/namei.c linux-2.4.20/fs/jfs/namei.c
--- linux-2.4.19/fs/jfs/namei.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/namei.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,1441 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *
+ *   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
+ */
+
+#include <linux/fs.h>
+#include "jfs_incore.h"
+#include "jfs_inode.h"
+#include "jfs_dinode.h"
+#include "jfs_dmap.h"
+#include "jfs_unicode.h"
+#include "jfs_metapage.h"
+#include "jfs_xattr.h"
+#include "jfs_debug.h"
+
+extern struct inode_operations jfs_file_inode_operations;
+extern struct inode_operations jfs_symlink_inode_operations;
+extern struct file_operations jfs_file_operations;
+extern struct address_space_operations jfs_aops;
+
+extern int jfs_fsync(struct file *, struct dentry *, int);
+extern void jfs_truncate_nolock(struct inode *, loff_t);
+
+/*
+ * forward references
+ */
+struct inode_operations jfs_dir_inode_operations;
+struct file_operations jfs_dir_operations;
+
+s64 commitZeroLink(tid_t, struct inode *);
+
+/*
+ * NAME:	jfs_create(dip, dentry, mode)
+ *
+ * FUNCTION:	create a regular file in the parent directory <dip>
+ *		with name = <from dentry> and mode = <mode>
+ *
+ * PARAMETER:	dip 	- parent directory vnode
+ *		dentry	- dentry of new file
+ *		mode	- create mode (rwxrwxrwx).
+ *
+ * RETURN:	Errors from subroutines
+ *
+ */
+int jfs_create(struct inode *dip, struct dentry *dentry, int mode)
+{
+	int rc = 0;
+	tid_t tid;		/* transaction id */
+	struct inode *ip = NULL;	/* child directory inode */
+	ino_t ino;
+	struct component_name dname;	/* child directory name */
+	struct btstack btstack;
+	struct inode *iplist[2];
+	struct tblock *tblk;
+
+	jFYI(1, ("jfs_create: dip:0x%p name:%s\n", dip, dentry->d_name.name));
+
+	/*
+	 * search parent directory for entry/freespace
+	 * (dtSearch() returns parent directory page pinned)
+	 */
+	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
+		goto out1;
+
+	/*
+	 * Either iAlloc() or txBegin() may block.  Deadlock can occur if we
+	 * block there while holding dtree page, so we allocate the inode &
+	 * begin the transaction before we search the directory.
+	 */
+	ip = ialloc(dip, mode);
+	if (ip == NULL) {
+		rc = ENOSPC;
+		goto out2;
+	}
+
+	tid = txBegin(dip->i_sb, 0);
+
+	down(&JFS_IP(dip)->commit_sem);
+	down(&JFS_IP(ip)->commit_sem);
+
+	if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
+		jERROR(1, ("jfs_create: dtSearch returned %d\n", rc));
+		goto out3;
+	}
+
+	tblk = tid_to_tblock(tid);
+	tblk->xflag |= COMMIT_CREATE;
+	tblk->ip = ip;
+
+	iplist[0] = dip;
+	iplist[1] = ip;
+
+	/*
+	 * initialize the child XAD tree root in-line in inode
+	 */
+	xtInitRoot(tid, ip);
+
+	/*
+	 * create entry in parent directory for child directory
+	 * (dtInsert() releases parent directory page)
+	 */
+	ino = ip->i_ino;
+	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
+		jERROR(1, ("jfs_create: dtInsert returned %d\n", rc));
+		if (rc == EIO)
+			txAbort(tid, 1);	/* Marks Filesystem dirty */
+		else
+			txAbort(tid, 0);	/* Filesystem full */
+		goto out3;
+	}
+
+	ip->i_op = &jfs_file_inode_operations;
+	ip->i_fop = &jfs_file_operations;
+	ip->i_mapping->a_ops = &jfs_aops;
+
+	insert_inode_hash(ip);
+	mark_inode_dirty(ip);
+	d_instantiate(dentry, ip);
+
+	dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+
+	mark_inode_dirty(dip);
+
+	rc = txCommit(tid, 2, &iplist[0], 0);
+
+      out3:
+	txEnd(tid);
+	up(&JFS_IP(dip)->commit_sem);
+	up(&JFS_IP(ip)->commit_sem);
+	if (rc) {
+		ip->i_nlink = 0;
+		iput(ip);
+	}
+
+      out2:
+	free_UCSname(&dname);
+
+      out1:
+
+	jFYI(1, ("jfs_create: rc:%d\n", -rc));
+	return -rc;
+}
+
+
+/*
+ * NAME:	jfs_mkdir(dip, dentry, mode)
+ *
+ * FUNCTION:	create a child directory in the parent directory <dip>
+ *		with name = <from dentry> and mode = <mode>
+ *
+ * PARAMETER:	dip 	- parent directory vnode
+ *		dentry	- dentry of child directory
+ *		mode	- create mode (rwxrwxrwx).
+ *
+ * RETURN:	Errors from subroutines
+ *
+ * note:
+ * EACCESS: user needs search+write permission on the parent directory
+ */
+int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
+{
+	int rc = 0;
+	tid_t tid;		/* transaction id */
+	struct inode *ip = NULL;	/* child directory inode */
+	ino_t ino;
+	struct component_name dname;	/* child directory name */
+	struct btstack btstack;
+	struct inode *iplist[2];
+	struct tblock *tblk;
+
+	jFYI(1, ("jfs_mkdir: dip:0x%p name:%s\n", dip, dentry->d_name.name));
+
+	/* link count overflow on parent directory ? */
+	if (dip->i_nlink == JFS_LINK_MAX) {
+		rc = EMLINK;
+		goto out1;
+	}
+
+	/*
+	 * search parent directory for entry/freespace
+	 * (dtSearch() returns parent directory page pinned)
+	 */
+	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
+		goto out1;
+
+	/*
+	 * Either iAlloc() or txBegin() may block.  Deadlock can occur if we
+	 * block there while holding dtree page, so we allocate the inode &
+	 * begin the transaction before we search the directory.
+	 */
+	ip = ialloc(dip, S_IFDIR | mode);
+	if (ip == NULL) {
+		rc = ENOSPC;
+		goto out2;
+	}
+
+	tid = txBegin(dip->i_sb, 0);
+
+	down(&JFS_IP(dip)->commit_sem);
+	down(&JFS_IP(ip)->commit_sem);
+
+	if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
+		jERROR(1, ("jfs_mkdir: dtSearch returned %d\n", rc));
+		goto out3;
+	}
+
+	tblk = tid_to_tblock(tid);
+	tblk->xflag |= COMMIT_CREATE;
+	tblk->ip = ip;
+
+	iplist[0] = dip;
+	iplist[1] = ip;
+
+	/*
+	 * initialize the child directory in-line in inode
+	 */
+	dtInitRoot(tid, ip, dip->i_ino);
+
+	/*
+	 * create entry in parent directory for child directory
+	 * (dtInsert() releases parent directory page)
+	 */
+	ino = ip->i_ino;
+	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
+		jERROR(1, ("jfs_mkdir: dtInsert returned %d\n", rc));
+
+		if (rc == EIO)
+			txAbort(tid, 1);	/* Marks Filesystem dirty */
+		else
+			txAbort(tid, 0);	/* Filesystem full */
+		goto out3;
+	}
+
+	ip->i_nlink = 2;	/* for '.' */
+	ip->i_op = &jfs_dir_inode_operations;
+	ip->i_fop = &jfs_dir_operations;
+	ip->i_mapping->a_ops = &jfs_aops;
+	ip->i_mapping->gfp_mask = GFP_NOFS;
+
+	insert_inode_hash(ip);
+	mark_inode_dirty(ip);
+	d_instantiate(dentry, ip);
+
+	/* update parent directory inode */
+	dip->i_nlink++;		/* for '..' from child directory */
+	dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+	mark_inode_dirty(dip);
+
+	rc = txCommit(tid, 2, &iplist[0], 0);
+
+      out3:
+	txEnd(tid);
+	up(&JFS_IP(dip)->commit_sem);
+	up(&JFS_IP(ip)->commit_sem);
+	if (rc) {
+		ip->i_nlink = 0;
+		iput(ip);
+	}
+
+      out2:
+	free_UCSname(&dname);
+
+      out1:
+
+	jFYI(1, ("jfs_mkdir: rc:%d\n", -rc));
+	return -rc;
+}
+
+/*
+ * NAME:	jfs_rmdir(dip, dentry)
+ *
+ * FUNCTION:	remove a link to child directory
+ *
+ * PARAMETER:	dip 	- parent inode
+ *		dentry	- child directory dentry
+ *
+ * RETURN:	EINVAL	- if name is . or ..
+ *		EINVAL  - if . or .. exist but are invalid.
+ *		errors from subroutines
+ *
+ * note:
+ * if other threads have the directory open when the last link 
+ * is removed, the "." and ".." entries, if present, are removed before 
+ * rmdir() returns and no new entries may be created in the directory, 
+ * but the directory is not removed until the last reference to 
+ * the directory is released (cf.unlink() of regular file).
+ */
+int jfs_rmdir(struct inode *dip, struct dentry *dentry)
+{
+	int rc;
+	tid_t tid;		/* transaction id */
+	struct inode *ip = dentry->d_inode;
+	ino_t ino;
+	struct component_name dname;
+	struct inode *iplist[2];
+	struct tblock *tblk;
+
+	jFYI(1, ("jfs_rmdir: dip:0x%p name:%s\n", dip, dentry->d_name.name));
+
+	/* directory must be empty to be removed */
+	if (!dtEmpty(ip)) {
+		rc = ENOTEMPTY;
+		goto out;
+	}
+
+	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab))) {
+		goto out;
+	}
+
+	tid = txBegin(dip->i_sb, 0);
+
+	down(&JFS_IP(dip)->commit_sem);
+	down(&JFS_IP(ip)->commit_sem);
+
+	iplist[0] = dip;
+	iplist[1] = ip;
+
+	tblk = tid_to_tblock(tid);
+	tblk->xflag |= COMMIT_DELETE;
+	tblk->ip = ip;
+
+	/*
+	 * delete the entry of target directory from parent directory
+	 */
+	ino = ip->i_ino;
+	if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
+		jERROR(1, ("jfs_rmdir: dtDelete returned %d\n", rc));
+		if (rc == EIO)
+			txAbort(tid, 1);
+		txEnd(tid);
+		up(&JFS_IP(dip)->commit_sem);
+		up(&JFS_IP(ip)->commit_sem);
+
+		goto out2;
+	}
+
+	/* update parent directory's link count corresponding
+	 * to ".." entry of the target directory deleted
+	 */
+	dip->i_nlink--;
+	dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+	mark_inode_dirty(dip);
+
+	/*
+	 * OS/2 could have created EA and/or ACL
+	 */
+	/* free EA from both persistent and working map */
+	if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
+		/* free EA pages */
+		txEA(tid, ip, &JFS_IP(ip)->ea, NULL);
+	}
+	JFS_IP(ip)->ea.flag = 0;
+
+	/* free ACL from both persistent and working map */
+	if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
+		/* free ACL pages */
+		txEA(tid, ip, &JFS_IP(ip)->acl, NULL);
+	}
+	JFS_IP(ip)->acl.flag = 0;
+
+	/* mark the target directory as deleted */
+	ip->i_nlink = 0;
+	mark_inode_dirty(ip);
+
+	rc = txCommit(tid, 2, &iplist[0], 0);
+
+	txEnd(tid);
+
+	up(&JFS_IP(dip)->commit_sem);
+	up(&JFS_IP(ip)->commit_sem);
+
+	/*
+	 * Truncating the directory index table is not guaranteed.  It
+	 * may need to be done iteratively
+	 */
+	if (test_cflag(COMMIT_Stale, dip)) {
+		if (dip->i_size > 1)
+			jfs_truncate_nolock(dip, 0);
+
+		clear_cflag(COMMIT_Stale, dip);
+	}
+
+      out2:
+	free_UCSname(&dname);
+
+      out:
+	jFYI(1, ("jfs_rmdir: rc:%d\n", rc));
+	return -rc;
+}
+
+/*
+ * NAME:	jfs_unlink(dip, dentry)
+ *
+ * FUNCTION:	remove a link to object <vp> named by <name> 
+ *		from parent directory <dvp>
+ *
+ * PARAMETER:	dip 	- inode of parent directory
+ *		dentry 	- dentry of object to be removed
+ *
+ * RETURN:	errors from subroutines
+ *
+ * note:
+ * temporary file: if one or more processes have the file open
+ * when the last link is removed, the link will be removed before
+ * unlink() returns, but the removal of the file contents will be
+ * postponed until all references to the files are closed.
+ *
+ * JFS does NOT support unlink() on directories.
+ *
+ */
+int jfs_unlink(struct inode *dip, struct dentry *dentry)
+{
+	int rc;
+	tid_t tid;		/* transaction id */
+	struct inode *ip = dentry->d_inode;
+	ino_t ino;
+	struct component_name dname;	/* object name */
+	struct inode *iplist[2];
+	struct tblock *tblk;
+	s64 new_size = 0;
+	int commit_flag;
+
+	jFYI(1, ("jfs_unlink: dip:0x%p name:%s\n", dip, dentry->d_name.name));
+
+	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
+		goto out;
+
+	IWRITE_LOCK(ip);
+
+	tid = txBegin(dip->i_sb, 0);
+
+	down(&JFS_IP(dip)->commit_sem);
+	down(&JFS_IP(ip)->commit_sem);
+
+	iplist[0] = dip;
+	iplist[1] = ip;
+
+	/*
+	 * delete the entry of target file from parent directory
+	 */
+	ino = ip->i_ino;
+	if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
+		jERROR(1, ("jfs_unlink: dtDelete returned %d\n", rc));
+		if (rc == EIO)
+			txAbort(tid, 1);	/* Marks FS Dirty */
+		txEnd(tid);
+		up(&JFS_IP(dip)->commit_sem);
+		up(&JFS_IP(ip)->commit_sem);
+		IWRITE_UNLOCK(ip);
+		goto out1;
+	}
+
+	ASSERT(ip->i_nlink);
+
+	ip->i_ctime = dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+	mark_inode_dirty(dip);
+
+	/* update target's inode */
+	ip->i_nlink--;
+	mark_inode_dirty(ip);
+
+	/*
+	 *      commit zero link count object
+	 */
+	if (ip->i_nlink == 0) {
+		assert(!test_cflag(COMMIT_Nolink, ip));
+		/* free block resources */
+		if ((new_size = commitZeroLink(tid, ip)) < 0) {
+			txAbort(tid, 1);	/* Marks FS Dirty */
+			txEnd(tid);
+			up(&JFS_IP(dip)->commit_sem);
+			up(&JFS_IP(ip)->commit_sem);
+			IWRITE_UNLOCK(ip);
+			rc = -new_size;		/* We return -rc */
+			goto out1;
+		}
+		tblk = tid_to_tblock(tid);
+		tblk->xflag |= COMMIT_DELETE;
+		tblk->ip = ip;
+	}
+
+	/*
+	 * Incomplete truncate of file data can
+	 * result in timing problems unless we synchronously commit the
+	 * transaction.
+	 */
+	if (new_size)
+		commit_flag = COMMIT_SYNC;
+	else
+		commit_flag = 0;
+
+	/*
+	 * If xtTruncate was incomplete, commit synchronously to avoid
+	 * timing complications
+	 */
+	rc = txCommit(tid, 2, &iplist[0], commit_flag);
+
+	txEnd(tid);
+
+	up(&JFS_IP(dip)->commit_sem);
+	up(&JFS_IP(ip)->commit_sem);
+
+
+	while (new_size && (rc == 0)) {
+		tid = txBegin(dip->i_sb, 0);
+		down(&JFS_IP(ip)->commit_sem);
+		new_size = xtTruncate_pmap(tid, ip, new_size);
+		if (new_size < 0) {
+			txAbort(tid, 1);	/* Marks FS Dirty */
+			rc = -new_size;		/* We return -rc */
+		} else
+			rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC);
+		txEnd(tid);
+		up(&JFS_IP(ip)->commit_sem);
+	}
+
+	if (ip->i_nlink == 0)
+		set_cflag(COMMIT_Nolink, ip);
+
+	if (!test_cflag(COMMIT_Holdlock, ip))
+		IWRITE_UNLOCK(ip);
+
+	/*
+	 * Truncating the directory index table is not guaranteed.  It
+	 * may need to be done iteratively
+	 */
+	if (test_cflag(COMMIT_Stale, dip)) {
+		if (dip->i_size > 1)
+			jfs_truncate_nolock(dip, 0);
+
+		clear_cflag(COMMIT_Stale, dip);
+	}
+
+      out1:
+	free_UCSname(&dname);
+      out:
+	jFYI(1, ("jfs_unlink: rc:%d\n", -rc));
+	return -rc;
+}
+
+/*
+ * NAME:	commitZeroLink()
+ *
+ * FUNCTION:    for non-directory, called by jfs_remove(),
+ *		truncate a regular file, directory or symbolic
+ *		link to zero length. return 0 if type is not 
+ *		one of these.
+ *
+ *		if the file is currently associated with a VM segment
+ *		only permanent disk and inode map resources are freed,
+ *		and neither the inode nor indirect blocks are modified
+ *		so that the resources can be later freed in the work
+ *		map by ctrunc1.
+ *		if there is no VM segment on entry, the resources are
+ *		freed in both work and permanent map.
+ *		(? for temporary file - memory object is cached even 
+ *		after no reference:
+ *		reference count > 0 -   )
+ *
+ * PARAMETERS:	cd	- pointer to commit data structure.
+ *			  current inode is the one to truncate.
+ *
+ * RETURN :	Errors from subroutines
+ */
+s64 commitZeroLink(tid_t tid, struct inode *ip)
+{
+	int filetype;
+	struct tblock *tblk;
+
+	jFYI(1, ("commitZeroLink: tid = %d, ip = 0x%p\n", tid, ip));
+
+	filetype = ip->i_mode & S_IFMT;
+	switch (filetype) {
+	case S_IFREG:
+		break;
+	case S_IFLNK:
+		/* fast symbolic link */
+		if (ip->i_size <= 256) {
+			ip->i_size = 0;
+			return 0;
+		}
+		break;
+	default:
+		assert(filetype != S_IFDIR);
+		return 0;
+	}
+
+	set_cflag(COMMIT_Freewmap, ip);
+
+	/* mark transaction of block map update type */
+	tblk = tid_to_tblock(tid);
+	tblk->xflag |= COMMIT_PMAP;
+
+	/*
+	 * free EA
+	 */
+	if (JFS_IP(ip)->ea.flag & DXD_EXTENT)
+		/* acquire maplock on EA to be freed from block map */
+		txEA(tid, ip, &JFS_IP(ip)->ea, NULL);
+
+	/*
+	 * free ACL
+	 */
+	if (JFS_IP(ip)->acl.flag & DXD_EXTENT)
+		/* acquire maplock on EA to be freed from block map */
+		txEA(tid, ip, &JFS_IP(ip)->acl, NULL);
+
+	/*
+	 * free xtree/data (truncate to zero length):
+	 * free xtree/data pages from cache if COMMIT_PWMAP, 
+	 * free xtree/data blocks from persistent block map, and
+	 * free xtree/data blocks from working block map if COMMIT_PWMAP;
+	 */
+	if (ip->i_size)
+		return xtTruncate_pmap(tid, ip, 0);
+
+	return 0;
+}
+
+
+/*
+ * NAME:	freeZeroLink()
+ *
+ * FUNCTION:    for non-directory, called by iClose(),
+ *		free resources of a file from cache and WORKING map 
+ *		for a file previously committed with zero link count
+ *		while associated with a pager object,
+ *
+ * PARAMETER:	ip	- pointer to inode of file.
+ *
+ * RETURN:	0 -ok
+ */
+int freeZeroLink(struct inode *ip)
+{
+	int rc = 0;
+	int type;
+
+	jFYI(1, ("freeZeroLink: ip = 0x%p\n", ip));
+
+	/* return if not reg or symbolic link or if size is
+	 * already ok.
+	 */
+	type = ip->i_mode & S_IFMT;
+
+	switch (type) {
+	case S_IFREG:
+		break;
+	case S_IFLNK:
+		/* if its contained in inode nothing to do */
+		if (ip->i_size <= 256)
+			return 0;
+		break;
+	default:
+		return 0;
+	}
+
+	/*
+	 * free EA
+	 */
+	if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
+		s64 xaddr = addressDXD(&JFS_IP(ip)->ea);
+		int xlen = lengthDXD(&JFS_IP(ip)->ea);
+		struct maplock maplock;	/* maplock for COMMIT_WMAP */
+		struct pxd_lock *pxdlock;	/* maplock for COMMIT_WMAP */
+
+		/* free EA pages from cache */
+		invalidate_dxd_metapages(ip, JFS_IP(ip)->ea);
+
+		/* free EA extent from working block map */
+		maplock.index = 1;
+		pxdlock = (struct pxd_lock *) & maplock;
+		pxdlock->flag = mlckFREEPXD;
+		PXDaddress(&pxdlock->pxd, xaddr);
+		PXDlength(&pxdlock->pxd, xlen);
+		txFreeMap(ip, pxdlock, 0, COMMIT_WMAP);
+	}
+
+	/*
+	 * free ACL
+	 */
+	if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
+		s64 xaddr = addressDXD(&JFS_IP(ip)->acl);
+		int xlen = lengthDXD(&JFS_IP(ip)->acl);
+		struct maplock maplock;	/* maplock for COMMIT_WMAP */
+		struct pxd_lock *pxdlock;	/* maplock for COMMIT_WMAP */
+
+		invalidate_dxd_metapages(ip, JFS_IP(ip)->acl);
+
+		/* free ACL extent from working block map */
+		maplock.index = 1;
+		pxdlock = (struct pxd_lock *) & maplock;
+		pxdlock->flag = mlckFREEPXD;
+		PXDaddress(&pxdlock->pxd, xaddr);
+		PXDlength(&pxdlock->pxd, xlen);
+		txFreeMap(ip, pxdlock, 0, COMMIT_WMAP);
+	}
+
+	/*
+	 * free xtree/data (truncate to zero length):
+	 * free xtree/data pages from cache, and
+	 * free xtree/data blocks from working block map;
+	 */
+	if (ip->i_size)
+		rc = xtTruncate(0, ip, 0, COMMIT_WMAP);
+
+	return rc;
+}
+
+/*
+ * NAME:	jfs_link(vp, dvp, name, crp)
+ *
+ * FUNCTION:	create a link to <vp> by the name = <name>
+ *		in the parent directory <dvp>
+ *
+ * PARAMETER:	vp 	- target object
+ *		dvp	- parent directory of new link
+ *		name	- name of new link to target object
+ *		crp	- credential
+ *
+ * RETURN:	Errors from subroutines
+ *
+ * note:
+ * JFS does NOT support link() on directories (to prevent circular
+ * path in the directory hierarchy);
+ * EPERM: the target object is a directory, and either the caller
+ * does not have appropriate privileges or the implementation prohibits
+ * using link() on directories [XPG4.2].
+ *
+ * JFS does NOT support links between file systems:
+ * EXDEV: target object and new link are on different file systems and
+ * implementation does not support links between file systems [XPG4.2].
+ */
+int jfs_link(struct dentry *old_dentry,
+	     struct inode *dir, struct dentry *dentry)
+{
+	int rc;
+	tid_t tid;
+	struct inode *ip = old_dentry->d_inode;
+	ino_t ino;
+	struct component_name dname;
+	struct btstack btstack;
+	struct inode *iplist[2];
+
+	jFYI(1,
+	     ("jfs_link: %s %s\n", old_dentry->d_name.name,
+	      dentry->d_name.name));
+
+	/* JFS does NOT support link() on directories */
+	if (S_ISDIR(ip->i_mode))
+		return -EPERM;
+
+	tid = txBegin(ip->i_sb, 0);
+
+	down(&JFS_IP(dir)->commit_sem);
+	down(&JFS_IP(ip)->commit_sem);
+
+	if (ip->i_nlink == JFS_LINK_MAX) {
+		rc = EMLINK;
+		goto out;
+	}
+
+	/*
+	 * scan parent directory for entry/freespace
+	 */
+	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(ip->i_sb)->nls_tab)))
+		goto out;
+
+	if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
+		goto out;
+
+	/*
+	 * create entry for new link in parent directory
+	 */
+	ino = ip->i_ino;
+	if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack)))
+		goto out;
+
+	/* update object inode */
+	ip->i_nlink++;		/* for new link */
+	ip->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(dir);
+	atomic_inc(&ip->i_count);
+	d_instantiate(dentry, ip);
+
+	iplist[0] = ip;
+	iplist[1] = dir;
+	rc = txCommit(tid, 2, &iplist[0], 0);
+
+      out:
+	txEnd(tid);
+
+	up(&JFS_IP(dir)->commit_sem);
+	up(&JFS_IP(ip)->commit_sem);
+
+	jFYI(1, ("jfs_link: rc:%d\n", rc));
+	return -rc;
+}
+
+/*
+ * NAME:	jfs_symlink(dip, dentry, name)
+ *
+ * FUNCTION:	creates a symbolic link to <symlink> by name <name>
+ *		        in directory <dip>
+ *
+ * PARAMETER:	dip	    - parent directory vnode
+ *		        dentry 	- dentry of symbolic link
+ *		        name    - the path name of the existing object 
+ *			              that will be the source of the link
+ *
+ * RETURN:	errors from subroutines
+ *
+ * note:
+ * ENAMETOOLONG: pathname resolution of a symbolic link produced
+ * an intermediate result whose length exceeds PATH_MAX [XPG4.2]
+*/
+
+int jfs_symlink(struct inode *dip, struct dentry *dentry, const char *name)
+{
+	int rc;
+	tid_t tid;
+	ino_t ino = 0;
+	struct component_name dname;
+	int ssize;		/* source pathname size */
+	struct btstack btstack;
+	struct inode *ip = dentry->d_inode;
+	unchar *i_fastsymlink;
+	s64 xlen = 0;
+	int bmask = 0, xsize;
+	s64 xaddr;
+	struct metapage *mp;
+	struct super_block *sb;
+	struct tblock *tblk;
+
+	struct inode *iplist[2];
+
+	jFYI(1, ("jfs_symlink: dip:0x%p name:%s\n", dip, name));
+
+	ssize = strlen(name) + 1;
+
+	/*
+	 * search parent directory for entry/freespace
+	 * (dtSearch() returns parent directory page pinned)
+	 */
+
+	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
+		goto out1;
+
+	/*
+	 * allocate on-disk/in-memory inode for symbolic link:
+	 * (iAlloc() returns new, locked inode)
+	 */
+	ip = ialloc(dip, S_IFLNK | 0777);
+	if (ip == NULL) {
+		rc = ENOSPC;
+		goto out2;
+	}
+
+	tid = txBegin(dip->i_sb, 0);
+
+	down(&JFS_IP(dip)->commit_sem);
+	down(&JFS_IP(ip)->commit_sem);
+
+	if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE)))
+		goto out3;
+
+	tblk = tid_to_tblock(tid);
+	tblk->xflag |= COMMIT_CREATE;
+	tblk->ip = ip;
+
+	/*
+	 * create entry for symbolic link in parent directory
+	 */
+
+	ino = ip->i_ino;
+
+
+
+	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
+		jERROR(1, ("jfs_symlink: dtInsert returned %d\n", rc));
+		/* discard ne inode */
+		goto out3;
+
+	}
+
+	/* fix symlink access permission
+	 * (dir_create() ANDs in the u.u_cmask, 
+	 * but symlinks really need to be 777 access)
+	 */
+	ip->i_mode |= 0777;
+
+	/*
+	   *       write symbolic link target path name
+	 */
+	xtInitRoot(tid, ip);
+
+	/*
+	 * write source path name inline in on-disk inode (fast symbolic link)
+	 */
+
+	if (ssize <= IDATASIZE) {
+		ip->i_op = &jfs_symlink_inode_operations;
+
+		i_fastsymlink = JFS_IP(ip)->i_inline;
+		memcpy(i_fastsymlink, name, ssize);
+		ip->i_size = ssize - 1;
+
+		/*
+		 * if symlink is > 128 bytes, we don't have the space to
+		 * store inline extended attributes
+		 */
+		if (ssize > sizeof (JFS_IP(ip)->i_inline))
+			JFS_IP(ip)->mode2 &= ~INLINEEA;
+
+		jFYI(1,
+		     ("jfs_symlink: fast symlink added  ssize:%d name:%s \n",
+		      ssize, name));
+	}
+	/*
+	 * write source path name in a single extent
+	 */
+	else {
+		jFYI(1, ("jfs_symlink: allocate extent ip:0x%p\n", ip));
+
+		ip->i_op = &page_symlink_inode_operations;
+		ip->i_mapping->a_ops = &jfs_aops;
+
+		/*
+		 * even though the data of symlink object (source 
+		 * path name) is treated as non-journaled user data,
+		 * it is read/written thru buffer cache for performance.
+		 */
+		sb = ip->i_sb;
+		bmask = JFS_SBI(sb)->bsize - 1;
+		xsize = (ssize + bmask) & ~bmask;
+		xaddr = 0;
+		xlen = xsize >> JFS_SBI(sb)->l2bsize;
+		if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0)) == 0) {
+			ip->i_size = ssize - 1;
+			while (ssize) {
+				int copy_size = min(ssize, PSIZE);
+
+				mp = get_metapage(ip, xaddr, PSIZE, 1);
+
+				if (mp == NULL) {
+					dtDelete(tid, dip, &dname, &ino,
+						 JFS_REMOVE);
+					rc = EIO;
+					goto out3;
+				}
+				memcpy(mp->data, name, copy_size);
+				flush_metapage(mp);
+#if 0
+				mark_buffer_uptodate(bp, 1);
+				mark_buffer_dirty(bp, 1);
+				if (IS_SYNC(dip)) {
+					ll_rw_block(WRITE, 1, &bp);
+					wait_on_buffer(bp);
+				}
+				brelse(bp);
+#endif				/* 0 */
+				ssize -= copy_size;
+				xaddr += JFS_SBI(sb)->nbperpage;
+			}
+			ip->i_blocks = LBLK2PBLK(sb, xlen);
+		} else {
+			dtDelete(tid, dip, &dname, &ino, JFS_REMOVE);
+			rc = ENOSPC;
+			goto out3;
+		}
+	}
+
+	insert_inode_hash(ip);
+	mark_inode_dirty(ip);
+	d_instantiate(dentry, ip);
+
+	/*
+	 * commit update of parent directory and link object
+	 *
+	 * if extent allocation failed (ENOSPC),
+	 * the parent inode is committed regardless to avoid
+	 * backing out parent directory update (by dtInsert())
+	 * and subsequent dtDelete() which is harmless wrt 
+	 * integrity concern.  
+	 * the symlink inode will be freed by iput() at exit
+	 * as it has a zero link count (by dtDelete()) and 
+	 * no permanant resources. 
+	 */
+
+	iplist[0] = dip;
+	if (rc == 0) {
+		iplist[1] = ip;
+		rc = txCommit(tid, 2, &iplist[0], 0);
+	} else
+		rc = txCommit(tid, 1, &iplist[0], 0);
+
+      out3:
+	txEnd(tid);
+	up(&JFS_IP(dip)->commit_sem);
+	up(&JFS_IP(ip)->commit_sem);
+	if (rc) {
+		ip->i_nlink = 0;
+		iput(ip);
+	}
+
+      out2:
+	free_UCSname(&dname);
+
+      out1:
+	jFYI(1, ("jfs_symlink: rc:%d\n", -rc));
+	return -rc;
+}
+
+
+/*
+ * NAME:        jfs_rename
+ *
+ * FUNCTION:    rename a file or directory
+ */
+int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+	       struct inode *new_dir, struct dentry *new_dentry)
+{
+	struct btstack btstack;
+	ino_t ino;
+	struct component_name new_dname;
+	struct inode *new_ip;
+	struct component_name old_dname;
+	struct inode *old_ip;
+	int rc;
+	tid_t tid;
+	struct tlock *tlck;
+	struct dt_lock *dtlck;
+	struct lv *lv;
+	int ipcount;
+	struct inode *iplist[4];
+	struct tblock *tblk;
+	s64 new_size = 0;
+	int commit_flag;
+
+
+	jFYI(1,
+	     ("jfs_rename: %s %s\n", old_dentry->d_name.name,
+	      new_dentry->d_name.name));
+
+	old_ip = old_dentry->d_inode;
+	new_ip = new_dentry->d_inode;
+
+	if ((rc = get_UCSname(&old_dname, old_dentry,
+			      JFS_SBI(old_dir->i_sb)->nls_tab)))
+		goto out1;
+
+	if ((rc = get_UCSname(&new_dname, new_dentry,
+			      JFS_SBI(old_dir->i_sb)->nls_tab)))
+		goto out2;
+
+	/*
+	 * Make sure source inode number is what we think it is
+	 */
+	rc = dtSearch(old_dir, &old_dname, &ino, &btstack, JFS_LOOKUP);
+	if (rc || (ino != old_ip->i_ino)) {
+		rc = ENOENT;
+		goto out3;
+	}
+
+	/*
+	 * Make sure dest inode number (if any) is what we think it is
+	 */
+	rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP);
+	if (rc == 0) {
+		if ((new_ip == 0) || (ino != new_ip->i_ino)) {
+			rc = ESTALE;
+			goto out3;
+		}
+	} else if (rc != ENOENT)
+		goto out3;
+	else if (new_ip) {
+		/* no entry exists, but one was expected */
+		rc = ESTALE;
+		goto out3;
+	}
+
+	if (S_ISDIR(old_ip->i_mode)) {
+		if (new_ip) {
+			if (!dtEmpty(new_ip)) {
+				rc = ENOTEMPTY;
+				goto out3;
+			}
+		} else if ((new_dir != old_dir) &&
+			   (new_dir->i_nlink == JFS_LINK_MAX)) {
+			rc = EMLINK;
+			goto out3;
+		}
+	} else if (new_ip)
+		IWRITE_LOCK(new_ip);
+
+	/*
+	 * The real work starts here
+	 */
+	tid = txBegin(new_dir->i_sb, 0);
+
+	down(&JFS_IP(new_dir)->commit_sem);
+	down(&JFS_IP(old_ip)->commit_sem);
+	if (old_dir != new_dir)
+		down(&JFS_IP(old_dir)->commit_sem);
+
+	if (new_ip) {
+		down(&JFS_IP(new_ip)->commit_sem);
+		/*
+		 * Change existing directory entry to new inode number
+		 */
+		ino = new_ip->i_ino;
+		rc = dtModify(tid, new_dir, &new_dname, &ino,
+			      old_ip->i_ino, JFS_RENAME);
+		if (rc)
+			goto out4;
+		new_ip->i_nlink--;
+		if (S_ISDIR(new_ip->i_mode)) {
+			new_ip->i_nlink--;
+			assert(new_ip->i_nlink == 0);
+			tblk = tid_to_tblock(tid);
+			tblk->xflag |= COMMIT_DELETE;
+			tblk->ip = new_ip;
+		} else if (new_ip->i_nlink == 0) {
+			assert(!test_cflag(COMMIT_Nolink, new_ip));
+			/* free block resources */
+			if ((new_size = commitZeroLink(tid, new_ip)) < 0) {
+				txAbort(tid, 1);	/* Marks FS Dirty */
+				rc = -new_size;		/* We return -rc */
+				goto out4;
+			}
+			tblk = tid_to_tblock(tid);
+			tblk->xflag |= COMMIT_DELETE;
+			tblk->ip = new_ip;
+		} else {
+			new_ip->i_ctime = CURRENT_TIME;
+			mark_inode_dirty(new_ip);
+		}
+	} else {
+		/*
+		 * Add new directory entry
+		 */
+		rc = dtSearch(new_dir, &new_dname, &ino, &btstack,
+			      JFS_CREATE);
+		if (rc) {
+			jERROR(1,
+			       ("jfs_rename didn't expect dtSearch to fail w/rc = %d\n",
+				rc));
+			goto out4;
+		}
+
+		ino = old_ip->i_ino;
+		rc = dtInsert(tid, new_dir, &new_dname, &ino, &btstack);
+		if (rc) {
+			jERROR(1,
+			       ("jfs_rename: dtInsert failed w/rc = %d\n",
+				rc));
+			goto out4;
+		}
+		if (S_ISDIR(old_ip->i_mode))
+			new_dir->i_nlink++;
+	}
+	/*
+	 * Remove old directory entry
+	 */
+
+	ino = old_ip->i_ino;
+	rc = dtDelete(tid, old_dir, &old_dname, &ino, JFS_REMOVE);
+	if (rc) {
+		jERROR(1,
+		       ("jfs_rename did not expect dtDelete to return rc = %d\n",
+			rc));
+		txAbort(tid, 1);	/* Marks Filesystem dirty */
+		goto out4;
+	}
+	if (S_ISDIR(old_ip->i_mode)) {
+		old_dir->i_nlink--;
+		if (old_dir != new_dir) {
+			/*
+			 * Change inode number of parent for moved directory
+			 */
+
+			JFS_IP(old_ip)->i_dtroot.header.idotdot =
+				cpu_to_le32(new_dir->i_ino);
+
+			/* Linelock header of dtree */
+			tlck = txLock(tid, old_ip,
+				    (struct metapage *) &JFS_IP(old_ip)->bxflag,
+				      tlckDTREE | tlckBTROOT);
+			dtlck = (struct dt_lock *) & tlck->lock;
+			ASSERT(dtlck->index == 0);
+			lv = & dtlck->lv[0];
+			lv->offset = 0;
+			lv->length = 1;
+			dtlck->index++;
+		}
+	}
+
+	/*
+	 * Update ctime on changed/moved inodes & mark dirty
+	 */
+	old_ip->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(old_ip);
+
+	new_dir->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(new_dir);
+
+	/* Build list of inodes modified by this transaction */
+	ipcount = 0;
+	iplist[ipcount++] = old_ip;
+	if (new_ip)
+		iplist[ipcount++] = new_ip;
+	iplist[ipcount++] = old_dir;
+
+	if (old_dir != new_dir) {
+		iplist[ipcount++] = new_dir;
+		old_dir->i_ctime = CURRENT_TIME;
+		mark_inode_dirty(old_dir);
+	}
+
+	/*
+	 * Incomplete truncate of file data can
+	 * result in timing problems unless we synchronously commit the
+	 * transaction.
+	 */
+	if (new_size)
+		commit_flag = COMMIT_SYNC;
+	else
+		commit_flag = 0;
+
+	rc = txCommit(tid, ipcount, iplist, commit_flag);
+
+	/*
+	 * Don't unlock new_ip if COMMIT_HOLDLOCK is set
+	 */
+	if (new_ip && test_cflag(COMMIT_Holdlock, new_ip)) {
+		up(&JFS_IP(new_ip)->commit_sem);
+		new_ip = 0;
+	}
+
+      out4:
+	txEnd(tid);
+
+	up(&JFS_IP(new_dir)->commit_sem);
+	up(&JFS_IP(old_ip)->commit_sem);
+	if (old_dir != new_dir)
+		up(&JFS_IP(old_dir)->commit_sem);
+	if (new_ip)
+		up(&JFS_IP(new_ip)->commit_sem);
+
+	while (new_size && (rc == 0)) {
+		tid = txBegin(new_ip->i_sb, 0);
+		down(&JFS_IP(new_ip)->commit_sem);
+		new_size = xtTruncate_pmap(tid, new_ip, new_size);
+		if (new_size < 0) {
+			txAbort(tid, 1);
+			rc = -new_size;		/* We return -rc */
+		} else
+			rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC);
+		txEnd(tid);
+		up(&JFS_IP(new_ip)->commit_sem);
+	}
+	if (new_ip && (new_ip->i_nlink == 0))
+		set_cflag(COMMIT_Nolink, new_ip);
+      out3:
+	free_UCSname(&new_dname);
+      out2:
+	free_UCSname(&old_dname);
+      out1:
+	if (new_ip && !S_ISDIR(new_ip->i_mode))
+		IWRITE_UNLOCK(new_ip);
+	/*
+	 * Truncating the directory index table is not guaranteed.  It
+	 * may need to be done iteratively
+	 */
+	if (test_cflag(COMMIT_Stale, old_dir)) {
+		if (old_dir->i_size > 1)
+			jfs_truncate_nolock(old_dir, 0);
+
+		clear_cflag(COMMIT_Stale, old_dir);
+	}
+
+	jFYI(1, ("jfs_rename: returning %d\n", rc));
+	return -rc;
+}
+
+
+/*
+ * NAME:        jfs_mknod
+ *
+ * FUNCTION:    Create a special file (device)
+ */
+int jfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
+{
+	struct btstack btstack;
+	struct component_name dname;
+	ino_t ino;
+	struct inode *ip;
+	struct inode *iplist[2];
+	int rc;
+	tid_t tid;
+	struct tblock *tblk;
+
+	jFYI(1, ("jfs_mknod: %s\n", dentry->d_name.name));
+
+	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dir->i_sb)->nls_tab)))
+		goto out;
+
+	ip = ialloc(dir, mode);
+	if (ip == NULL) {
+		rc = ENOSPC;
+		goto out1;
+	}
+
+	tid = txBegin(dir->i_sb, 0);
+
+	down(&JFS_IP(dir)->commit_sem);
+	down(&JFS_IP(ip)->commit_sem);
+
+	if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
+		goto out3;
+
+	tblk = tid_to_tblock(tid);
+	tblk->xflag |= COMMIT_CREATE;
+	tblk->ip = ip;
+
+	ino = ip->i_ino;
+	if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack)))
+		goto out3;
+
+	ip->i_op = &jfs_file_inode_operations;
+	init_special_inode(ip, ip->i_mode, rdev);
+
+	insert_inode_hash(ip);
+	mark_inode_dirty(ip);
+	d_instantiate(dentry, ip);
+
+	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+
+	mark_inode_dirty(dir);
+
+	iplist[0] = dir;
+	iplist[1] = ip;
+	rc = txCommit(tid, 2, iplist, 0);
+
+      out3:
+	txEnd(tid);
+	up(&JFS_IP(ip)->commit_sem);
+	up(&JFS_IP(dir)->commit_sem);
+	if (rc) {
+		ip->i_nlink = 0;
+		iput(ip);
+	}
+
+      out1:
+	free_UCSname(&dname);
+
+      out:
+	jFYI(1, ("jfs_mknod: returning %d\n", rc));
+	return -rc;
+}
+
+static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry)
+{
+	struct btstack btstack;
+	ino_t inum;
+	struct inode *ip;
+	struct component_name key;
+	const char *name = dentry->d_name.name;
+	int len = dentry->d_name.len;
+	int rc;
+
+	jFYI(1, ("jfs_lookup: name = %s\n", name));
+
+
+	if ((name[0] == '.') && (len == 1))
+		inum = dip->i_ino;
+	else if (strcmp(name, "..") == 0)
+		inum = PARENT(dip);
+	else {
+		if ((rc =
+		     get_UCSname(&key, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
+			return ERR_PTR(-rc);
+		rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP);
+		free_UCSname(&key);
+		if (rc == ENOENT) {
+			d_add(dentry, NULL);
+			return ERR_PTR(0);
+		} else if (rc) {
+			jERROR(1,
+			       ("jfs_lookup: dtSearch returned %d\n", rc));
+			return ERR_PTR(-rc);
+		}
+	}
+
+	ip = iget(dip->i_sb, inum);
+	if (ip == NULL) {
+		jERROR(1,
+		       ("jfs_lookup: iget failed on inum %d\n",
+			(uint) inum));
+		return ERR_PTR(-EACCES);
+	}
+
+	d_add(dentry, ip);
+
+	return ERR_PTR(0);
+}
+
+struct inode_operations jfs_dir_inode_operations = {
+	.create		= jfs_create,
+	.lookup		= jfs_lookup,
+	.link		= jfs_link,
+	.unlink		= jfs_unlink,
+	.symlink	= jfs_symlink,
+	.mkdir		= jfs_mkdir,
+	.rmdir		= jfs_rmdir,
+	.mknod		= jfs_mknod,
+	.rename		= jfs_rename,
+	.setxattr	= jfs_setxattr,
+	.getxattr	= jfs_getxattr,
+	.listxattr	= jfs_listxattr,
+	.removexattr	= jfs_removexattr,
+};
+
+struct file_operations jfs_dir_operations = {
+	.read		= generic_read_dir,
+	.readdir	= jfs_readdir,
+	.fsync		= jfs_fsync,
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/resize.c linux-2.4.20/fs/jfs/resize.c
--- linux-2.4.19/fs/jfs/resize.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/resize.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,537 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000-2002
+ *
+ *   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
+*/
+
+#include <linux/fs.h>
+#include <linux/locks.h>
+
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_metapage.h"
+#include "jfs_dinode.h"
+#include "jfs_imap.h"
+#include "jfs_dmap.h"
+#include "jfs_superblock.h"
+#include "jfs_txnmgr.h"
+#include "jfs_debug.h"
+
+#define BITSPERPAGE     (PSIZE << 3)
+#define L2MEGABYTE      20
+#define MEGABYTE        (1 << L2MEGABYTE)
+#define MEGABYTE32     (MEGABYTE << 5)
+
+/* convert block number to bmap file page number */
+#define BLKTODMAPN(b)\
+        (((b) >> 13) + ((b) >> 23) + ((b) >> 33) + 3 + 1)
+
+/*
+ *      jfs_extendfs()
+ *
+ * function: extend file system;
+ *
+ *   |-------------------------------|----------|----------|
+ *   file system space               fsck       inline log
+ *                                   workspace  space
+ *
+ * input:
+ *      new LVSize: in LV blocks (required)
+ *      new LogSize: in LV blocks (optional)
+ *      new FSSize: in LV blocks (optional)
+ *
+ * new configuration:
+ * 1. set new LogSize as specified or default from new LVSize;
+ * 2. compute new FSCKSize from new LVSize;
+ * 3. set new FSSize as MIN(FSSize, LVSize-(LogSize+FSCKSize)) where
+ *    assert(new FSSize >= old FSSize),
+ *    i.e., file system must not be shrinked;
+ */
+int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
+{
+	int rc = 0;
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	struct inode *ipbmap = sbi->ipbmap;
+	struct inode *ipbmap2;
+	struct inode *ipimap = sbi->ipimap;
+	struct jfs_log *log = sbi->log;
+	struct bmap *bmp = sbi->bmap;
+	s64 newLogAddress, newFSCKAddress;
+	int newFSCKSize;
+	s64 newMapSize = 0, mapSize;
+	s64 XAddress, XSize, nblocks, xoff, xaddr, t64;
+	s64 oldLVSize;
+	s64 newFSSize;
+	s64 VolumeSize;
+	int newNpages = 0, nPages, newPage, xlen, t32;
+	int tid;
+	int log_formatted = 0;
+	struct inode *iplist[1];
+	struct jfs_superblock *j_sb, *j_sb2;
+	uint old_agsize;
+	struct buffer_head *bh, *bh2;
+
+	/* If the volume hasn't grown, get out now */
+
+	if (sbi->mntflag & JFS_INLINELOG)
+		oldLVSize = addressPXD(&sbi->logpxd) + lengthPXD(&sbi->logpxd);
+	else
+		oldLVSize = addressPXD(&sbi->fsckpxd) +
+		    lengthPXD(&sbi->fsckpxd);
+
+	if (oldLVSize >= newLVSize) {
+		printk(KERN_WARNING
+		       "jfs_extendfs: volume hasn't grown, returning\n");
+		goto out;
+	}
+
+	VolumeSize = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits;
+	if (VolumeSize) {
+		if (newLVSize > VolumeSize) {
+			printk(KERN_WARNING "jfs_extendfs: invalid size\n");
+			rc = -EINVAL;
+			goto out;
+		}
+	} else {
+		/* check the device */
+		bh = sb_bread(sb, newLVSize - 1);
+		if (!bh) {
+			printk(KERN_WARNING "jfs_extendfs: invalid size\n");
+			rc = -EINVAL;
+			goto out;
+		}
+		bforget(bh);
+	}
+
+	/* Can't extend write-protected drive */
+
+	if (isReadOnly(ipbmap)) {
+		printk(KERN_WARNING "jfs_extendfs: read-only file system\n");
+		rc = -EROFS;
+		goto out;
+	}
+
+	/*
+	 *      reconfigure LV spaces
+	 *      ---------------------
+	 *
+	 * validate new size, or, if not specified, determine new size
+	 */
+
+	/*
+	 * reconfigure inline log space:
+	 */
+	if ((sbi->mntflag & JFS_INLINELOG)) {
+		if (newLogSize == 0) {
+			/*
+			 * no size specified: default to 1/256 of aggregate
+			 * size; rounded up to a megabyte boundary;
+			 */
+			newLogSize = newLVSize >> 8;
+			t32 = (1 << (20 - sbi->l2bsize)) - 1;
+			newLogSize = (newLogSize + t32) & ~t32;
+			newLogSize =
+			    min(newLogSize, MEGABYTE32 >> sbi->l2bsize);
+		} else {
+			/*
+			 * convert the newLogSize to fs blocks.
+			 *
+			 * Since this is given in megabytes, it will always be
+			 * an even number of pages.
+			 */
+			newLogSize = (newLogSize * MEGABYTE) >> sbi->l2bsize;
+		}
+
+	} else
+		newLogSize = 0;
+
+	newLogAddress = newLVSize - newLogSize;
+
+	/*
+	 * reconfigure fsck work space:
+	 *
+	 * configure it to the end of the logical volume regardless of
+	 * whether file system extends to the end of the aggregate;
+	 * Need enough 4k pages to cover:
+	 *  - 1 bit per block in aggregate rounded up to BPERDMAP boundary
+	 *  - 1 extra page to handle control page and intermediate level pages
+	 *  - 50 extra pages for the chkdsk service log
+	 */
+	t64 = ((newLVSize - newLogSize + BPERDMAP - 1) >> L2BPERDMAP)
+	    << L2BPERDMAP;
+	t32 = ((t64 + (BITSPERPAGE - 1)) / BITSPERPAGE) + 1 + 50;
+	newFSCKSize = t32 << sbi->l2nbperpage;
+	newFSCKAddress = newLogAddress - newFSCKSize;
+
+	/*
+	 * compute new file system space;
+	 */
+	newFSSize = newLVSize - newLogSize - newFSCKSize;
+
+	/* file system cannot be shrinked */
+	if (newFSSize < bmp->db_mapsize) {
+		rc = EINVAL;
+		goto out;
+	}
+
+	/*
+	 * If we're expanding enough that the inline log does not overlap
+	 * the old one, we can format the new log before we quiesce the
+	 * filesystem.
+	 */
+	if ((sbi->mntflag & JFS_INLINELOG) && (newLogAddress > oldLVSize)) {
+		if ((rc = lmLogFormat(log, newLogAddress, newLogSize)))
+			goto out;
+		log_formatted = 1;
+	}
+	/*
+	 *      quiesce file system
+	 *
+	 * (prepare to move the inline log and to prevent map update)
+	 *
+	 * block any new transactions and wait for completion of
+	 * all wip transactions and flush modified pages s.t.
+	 * on-disk file system is in consistent state and
+	 * log is not required for recovery.
+	 */
+	txQuiesce(sb);
+
+	if (sbi->mntflag & JFS_INLINELOG) {
+		/*
+		 * deactivate old inline log
+		 */
+		lmLogShutdown(log);
+
+		/*
+		 * mark on-disk super block for fs in transition;
+		 *
+		 * update on-disk superblock for the new space configuration
+		 * of inline log space and fsck work space descriptors:
+		 * N.B. FS descriptor is NOT updated;
+		 *
+		 * crash recovery:
+		 * logredo(): if FM_EXTENDFS, return to fsck() for cleanup;
+		 * fsck(): if FM_EXTENDFS, reformat inline log and fsck
+		 * workspace from superblock inline log descriptor and fsck
+		 * workspace descriptor;
+		 */
+
+		/* read in superblock */
+		if ((rc = readSuper(sb, &bh)))
+			goto error_out;
+		j_sb = (struct jfs_superblock *)bh->b_data;
+
+		/* mark extendfs() in progress */
+		j_sb->s_state |= cpu_to_le32(FM_EXTENDFS);
+		j_sb->s_xsize = cpu_to_le64(newFSSize);
+		PXDaddress(&j_sb->s_xfsckpxd, newFSCKAddress);
+		PXDlength(&j_sb->s_xfsckpxd, newFSCKSize);
+		PXDaddress(&j_sb->s_xlogpxd, newLogAddress);
+		PXDlength(&j_sb->s_xlogpxd, newLogSize);
+
+		/* synchronously update superblock */
+		mark_buffer_dirty(bh);
+		ll_rw_block(WRITE, 1, &bh);
+		wait_on_buffer(bh);
+		brelse(bh);
+
+		/*
+		 * format new inline log synchronously;
+		 *
+		 * crash recovery: if log move in progress,
+		 * reformat log and exit success;
+		 */
+		if (!log_formatted)
+			if ((rc = lmLogFormat(log, newLogAddress, newLogSize)))
+				goto error_out;
+
+		/*
+		 * activate new log
+		 */
+		log->base = newLogAddress;
+		log->size = newLogSize >> (L2LOGPSIZE - sb->s_blocksize_bits);
+		if ((rc = lmLogInit(log)))
+			goto error_out;
+	}
+
+	/*
+	 *      extend block allocation map
+	 *      ---------------------------
+	 *
+	 * extendfs() for new extension, retry after crash recovery;
+	 *
+	 * note: both logredo() and fsck() rebuild map from
+	 * the bitmap and configuration parameter from superblock
+	 * (disregarding all other control information in the map);
+	 *
+	 * superblock:
+	 *  s_size: aggregate size in physical blocks;
+	 */
+	/*
+	 *      compute the new block allocation map configuration
+	 *
+	 * map dinode:
+	 *  di_size: map file size in byte;
+	 *  di_nblocks: number of blocks allocated for map file;
+	 *  di_mapsize: number of blocks in aggregate (covered by map);
+	 * map control page:
+	 *  db_mapsize: number of blocks in aggregate (covered by map);
+	 */
+	newMapSize = newFSSize;
+	/* number of data pages of new bmap file:
+	 * roundup new size to full dmap page boundary and
+	 * add 1 extra dmap page for next extendfs()
+	 */
+	t64 = (newMapSize - 1) + BPERDMAP;
+	newNpages = BLKTODMAPN(t64) + 1;
+
+	/*
+	 *      extend map from current map (WITHOUT growing mapfile)
+	 *
+	 * map new extension with unmapped part of the last partial
+	 * dmap page, if applicable, and extra page(s) allocated
+	 * at end of bmap by mkfs() or previous extendfs();
+	 */
+      extendBmap:
+	/* compute number of blocks requested to extend */
+	mapSize = bmp->db_mapsize;
+	XAddress = mapSize;	/* eXtension Address */
+	XSize = newMapSize - mapSize;	/* eXtension Size */
+	old_agsize = bmp->db_agsize;	/* We need to know if this changes */
+
+	/* compute number of blocks that can be extended by current mapfile */
+	t64 = dbMapFileSizeToMapSize(ipbmap);
+	if (mapSize > t64) {
+		printk(KERN_ERR "jfs_extendfs: mapSize (0x%Lx) > t64 (0x%Lx)\n",
+		       (long long)mapSize, (long long)t64);
+		rc = EIO;
+		goto error_out;
+	}
+	nblocks = min(t64 - mapSize, XSize);
+
+	/*
+	 * update map pages for new extension:
+	 *
+	 * update/init dmap and bubble up the control hierarchy
+	 * incrementally fold up dmaps into upper levels;
+	 * update bmap control page;
+	 */
+	if ((rc = dbExtendFS(ipbmap, XAddress, nblocks)))
+		goto error_out;
+	/*
+	 * the map now has extended to cover additional nblocks:
+	 * dn_mapsize = oldMapsize + nblocks;
+	 */
+	/* ipbmap->i_mapsize += nblocks; */
+	XSize -= nblocks;
+
+	/*
+	 *      grow map file to cover remaining extension
+	 *      and/or one extra dmap page for next extendfs();
+	 *
+	 * allocate new map pages and its backing blocks, and
+	 * update map file xtree
+	 */
+	/* compute number of data pages of current bmap file */
+	nPages = ipbmap->i_size >> L2PSIZE;
+
+	/* need to grow map file ? */
+	if (nPages == newNpages)
+		goto updateImap;
+
+	/*
+	 * grow bmap file for the new map pages required:
+	 *
+	 * allocate growth at the start of newly extended region;
+	 * bmap file only grows sequentially, i.e., both data pages
+	 * and possibly xtree index pages may grow in append mode,
+	 * s.t. logredo() can reconstruct pre-extension state
+	 * by washing away bmap file of pages outside s_size boundary;
+	 */
+	/*
+	 * journal map file growth as if a regular file growth:
+	 * (note: bmap is created with di_mode = IFJOURNAL|IFREG);
+	 *
+	 * journaling of bmap file growth is not required since
+	 * logredo() do/can not use log records of bmap file growth
+	 * but it provides careful write semantics, pmap update, etc.;
+	 */
+	/* synchronous write of data pages: bmap data pages are
+	 * cached in meta-data cache, and not written out
+	 * by txCommit();
+	 */
+	fsync_inode_data_buffers(ipbmap);
+	diWriteSpecial(ipbmap, 0);
+
+	newPage = nPages;	/* first new page number */
+	xoff = newPage << sbi->l2nbperpage;
+	xlen = (newNpages - nPages) << sbi->l2nbperpage;
+	xlen = min(xlen, (int) nblocks) & ~(sbi->nbperpage - 1);
+	xaddr = XAddress;
+
+	tid = txBegin(sb, COMMIT_FORCE);
+
+	if ((rc = xtAppend(tid, ipbmap, 0, xoff, nblocks, &xlen, &xaddr, 0))) {
+		txEnd(tid);
+		goto error_out;
+	}
+	/* update bmap file size */
+	ipbmap->i_size += xlen << sbi->l2bsize;
+	ipbmap->i_blocks += LBLK2PBLK(sb, xlen);
+
+	iplist[0] = ipbmap;
+	rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);
+
+	txEnd(tid);
+
+	if (rc)
+		goto error_out;
+
+	/*
+	 * map file has been grown now to cover extension to further out;
+	 * di_size = new map file size;
+	 *
+	 * if huge extension, the previous extension based on previous
+	 * map file size may not have been sufficient to cover whole extension
+	 * (it could have been used up for new map pages),
+	 * but the newly grown map file now covers lot bigger new free space
+	 * available for further extension of map;
+	 */
+	/* any more blocks to extend ? */
+	if (XSize)
+		goto extendBmap;
+
+	/* finalize bmap */
+	dbFinalizeBmap(ipbmap);
+
+	/*
+	 *      update inode allocation map
+	 *      ---------------------------
+	 *
+	 * move iag lists from old to new iag;
+	 * agstart field is not updated for logredo() to reconstruct
+	 * iag lists if system crash occurs.
+	 * (computation of ag number from agstart based on agsize
+	 * will correctly identify the new ag);
+	 */
+      updateImap:
+	/* if new AG size the same as old AG size, done! */
+	if (bmp->db_agsize != old_agsize) {
+		if ((rc = diExtendFS(ipimap, ipbmap)))
+			goto error_out;
+
+		/* finalize imap */
+		if ((rc = diSync(ipimap)))
+			goto error_out;
+	}
+
+	/*
+	 *      finalize
+	 *      --------
+	 *
+	 * extension is committed when on-disk super block is
+	 * updated with new descriptors: logredo will recover
+	 * crash before it to pre-extension state;
+	 */
+
+	/* sync log to skip log replay of bmap file growth transaction; */
+	/* lmLogSync(log, 1); */
+
+	/*
+	 * synchronous write bmap global control page;
+	 * for crash before completion of write
+	 * logredo() will recover to pre-extendfs state;
+	 * for crash after completion of write,
+	 * logredo() will recover post-extendfs state;
+	 */
+	if ((rc = dbSync(ipbmap)))
+		goto error_out;
+
+	/*
+	 * copy primary bmap inode to secondary bmap inode
+	 */
+
+	ipbmap2 = diReadSpecial(sb, BMAP_I, 1);
+	if (ipbmap2 == NULL) {
+		printk(KERN_ERR "jfs_extendfs: diReadSpecial(bmap) failed\n");
+		goto error_out;
+	}
+	memcpy(&JFS_IP(ipbmap2)->i_xtroot, &JFS_IP(ipbmap)->i_xtroot, 288);
+	ipbmap2->i_size = ipbmap->i_size;
+	ipbmap2->i_blocks = ipbmap->i_blocks;
+
+	diWriteSpecial(ipbmap2, 1);
+	diFreeSpecial(ipbmap2);
+
+	/*
+	 *      update superblock
+	 */
+	if ((rc = readSuper(sb, &bh)))
+		goto error_out;
+	j_sb = (struct jfs_superblock *)bh->b_data;
+
+	/* mark extendfs() completion */
+	j_sb->s_state &= cpu_to_le32(~FM_EXTENDFS);
+	j_sb->s_size = cpu_to_le64(bmp->db_mapsize) <<
+		       le16_to_cpu(j_sb->s_l2bfactor);
+	j_sb->s_agsize = cpu_to_le32(bmp->db_agsize);
+
+	/* update inline log space descriptor */
+	if (sbi->mntflag & JFS_INLINELOG) {
+		PXDaddress(&(j_sb->s_logpxd), newLogAddress);
+		PXDlength(&(j_sb->s_logpxd), newLogSize);
+	}
+
+	/* record log's mount serial number */
+	j_sb->s_logserial = cpu_to_le32(log->serial);
+
+	/* update fsck work space descriptor */
+	PXDaddress(&(j_sb->s_fsckpxd), newFSCKAddress);
+	PXDlength(&(j_sb->s_fsckpxd), newFSCKSize);
+	j_sb->s_fscklog = 1;
+	/* sb->s_fsckloglen remains the same */
+
+	/* Update secondary superblock */
+	bh2 = sb_bread(sb, SUPER2_OFF >> sb->s_blocksize_bits);
+	if (bh2) {
+		j_sb2 = (struct jfs_superblock *)bh2->b_data;
+		memcpy(j_sb2, j_sb, sizeof (struct jfs_superblock));
+
+		mark_buffer_dirty(bh);
+		ll_rw_block(WRITE, 1, &bh2);
+		wait_on_buffer(bh2);
+		brelse(bh);
+	}
+
+	/* write primary superblock */
+	mark_buffer_dirty(bh);
+	ll_rw_block(WRITE, 1, &bh);
+	wait_on_buffer(bh);
+	brelse(bh);
+
+	goto resume;
+
+      error_out:
+	updateSuper(sb, FM_DIRTY);
+
+      resume:
+	/*
+	 *      resume file system transactions
+	 */
+	txResume(sb);
+
+      out:
+	return rc;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/super.c linux-2.4.20/fs/jfs/super.c
--- linux-2.4.19/fs/jfs/super.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/super.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,490 @@
+/*
+ *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *
+ *   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
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include <asm/uaccess.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_metapage.h"
+#include "jfs_superblock.h"
+#include "jfs_dmap.h"
+#include "jfs_imap.h"
+#include "jfs_debug.h"
+
+MODULE_DESCRIPTION("The Journaled Filesystem (JFS)");
+MODULE_AUTHOR("Steve Best/Dave Kleikamp/Barry Arndt, IBM");
+MODULE_LICENSE("GPL");
+
+static struct super_operations jfs_super_operations;
+static struct file_system_type jfs_fs_type;
+
+int jfs_stop_threads;
+static pid_t jfsIOthread;
+static pid_t jfsCommitThread;
+static pid_t jfsSyncThread;
+DECLARE_COMPLETION(jfsIOwait);
+
+#ifdef CONFIG_JFS_DEBUG
+int jfsloglevel = 1;
+MODULE_PARM(jfsloglevel, "i");
+MODULE_PARM_DESC(jfsloglevel, "Specify JFS loglevel (0, 1 or 2)");
+#endif
+
+/*
+ * External declarations
+ */
+extern int jfs_mount(struct super_block *);
+extern int jfs_mount_rw(struct super_block *, int);
+extern int jfs_umount(struct super_block *);
+extern int jfs_umount_rw(struct super_block *);
+
+extern int jfsIOWait(void *);
+extern int jfs_lazycommit(void *);
+extern int jfs_sync(void *);
+extern void jfs_clear_inode(struct inode *inode);
+extern void jfs_read_inode(struct inode *inode);
+extern void jfs_dirty_inode(struct inode *inode);
+extern void jfs_delete_inode(struct inode *inode);
+extern void jfs_write_inode(struct inode *inode, int wait);
+extern int jfs_extendfs(struct super_block *, s64, int);
+
+#ifdef PROC_FS_JFS		/* see jfs_debug.h */
+extern void jfs_proc_init(void);
+extern void jfs_proc_clean(void);
+#endif
+
+extern wait_queue_head_t jfs_IO_thread_wait;
+extern wait_queue_head_t jfs_commit_thread_wait;
+extern wait_queue_head_t jfs_sync_thread_wait;
+
+static int jfs_statfs(struct super_block *sb, struct statfs *buf)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	s64 maxinodes;
+	struct inomap *imap = JFS_IP(sbi->ipimap)->i_imap;
+
+	jFYI(1, ("In jfs_statfs\n"));
+	buf->f_type = JFS_SUPER_MAGIC;
+	buf->f_bsize = sbi->bsize;
+	buf->f_blocks = sbi->bmap->db_mapsize;
+	buf->f_bfree = sbi->bmap->db_nfree;
+	buf->f_bavail = sbi->bmap->db_nfree;
+	/*
+	 * If we really return the number of allocated & free inodes, some
+	 * applications will fail because they won't see enough free inodes.
+	 * We'll try to calculate some guess as to how may inodes we can
+	 * really allocate
+	 *
+	 * buf->f_files = atomic_read(&imap->im_numinos);
+	 * buf->f_ffree = atomic_read(&imap->im_numfree);
+	 */
+	maxinodes = min((s64) atomic_read(&imap->im_numinos) +
+			((sbi->bmap->db_nfree >> imap->im_l2nbperiext)
+			 << L2INOSPEREXT), (s64) 0xffffffffLL);
+	buf->f_files = maxinodes;
+	buf->f_ffree = maxinodes - (atomic_read(&imap->im_numinos) -
+				    atomic_read(&imap->im_numfree));
+
+	buf->f_namelen = JFS_NAME_MAX;
+	return 0;
+}
+
+static void jfs_put_super(struct super_block *sb)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	int rc;
+
+	jFYI(1, ("In jfs_put_super\n"));
+	rc = jfs_umount(sb);
+	if (rc) {
+		jERROR(1, ("jfs_umount failed with return code %d\n", rc));
+	}
+	unload_nls(sbi->nls_tab);
+	sbi->nls_tab = NULL;
+
+	kfree(sbi);
+}
+
+static int parse_options(char *options, struct super_block *sb, s64 *newLVSize)
+{
+	void *nls_map = NULL;
+	char *this_char;
+	char *value;
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+
+	*newLVSize = 0;
+
+	if (!options)
+		return 1;
+	while ((this_char = strsep(&options, ",")) != NULL) {
+		if (!*this_char)
+			continue;
+		if ((value = strchr(this_char, '=')) != NULL)
+			*value++ = 0;
+		if (!strcmp(this_char, "iocharset")) {
+			if (!value || !*value)
+				goto needs_arg;
+			if (nls_map)	/* specified iocharset twice! */
+				unload_nls(nls_map);
+			nls_map = load_nls(value);
+			if (!nls_map) {
+				printk(KERN_ERR "JFS: charset not found\n");
+				goto cleanup;
+			}
+		} else if (!strcmp(this_char, "resize")) {
+			if (!value || !*value) {
+				*newLVSize = sb->s_bdev->bd_inode->i_size >>
+					sb->s_blocksize_bits;
+				if (*newLVSize == 0)
+					printk(KERN_ERR
+					 "JFS: Cannot determine volume size\n");
+			} else
+				*newLVSize = simple_strtoull(value, &value, 0);
+
+			/* Silently ignore the quota options */
+		} else if (!strcmp(this_char, "grpquota")
+			   || !strcmp(this_char, "noquota")
+			   || !strcmp(this_char, "quota")
+			   || !strcmp(this_char, "usrquota"))
+			/* Don't do anything ;-) */ ;
+		else {
+			printk("jfs: Unrecognized mount option %s\n",
+			       this_char);
+			goto cleanup;
+		}
+	}
+	if (nls_map) {
+		/* Discard old (if remount) */
+		if (sbi->nls_tab)
+			unload_nls(sbi->nls_tab);
+		sbi->nls_tab = nls_map;
+	}
+	return 1;
+needs_arg:
+	printk(KERN_ERR "JFS: %s needs an argument\n", this_char);
+cleanup:
+	if (nls_map)
+		unload_nls(nls_map);
+	return 0;
+}
+
+int jfs_remount(struct super_block *sb, int *flags, char *data)
+{
+	s64 newLVSize = 0;
+	int rc = 0;
+
+	if (!parse_options(data, sb, &newLVSize)) {
+		return -EINVAL;
+	}
+	if (newLVSize) {
+		if (sb->s_flags & MS_RDONLY) {
+			printk(KERN_ERR
+		  "JFS: resize requires volume to be mounted read-write\n");
+			return -EROFS;
+		}
+		rc = jfs_extendfs(sb, newLVSize, 0);
+		if (rc)
+			return rc;
+	}
+
+	if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY))
+		return jfs_mount_rw(sb, 1);
+	else if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY))
+		return jfs_umount_rw(sb);
+
+	return 0;
+}
+
+static struct super_block *jfs_read_super(struct super_block *sb,
+					  void *data, int silent)
+{
+	struct jfs_sb_info *sbi;
+	struct inode *inode;
+	int rc;
+	s64 newLVSize = 0;
+
+	jFYI(1,
+	     ("In jfs_read_super s_dev=0x%x s_flags=0x%lx\n", sb->s_dev,
+	      sb->s_flags));
+
+	sbi = kmalloc(sizeof (struct jfs_sb_info), GFP_KERNEL);
+	if (!sbi)
+		return NULL;
+	memset(sbi, 0, sizeof (struct jfs_sb_info));
+	sb->u.generic_sbp = sbi;
+
+	if (!parse_options((char *) data, sb, &newLVSize)) {
+		kfree(sbi);
+		return NULL;
+	}
+
+	if (newLVSize) {
+		printk(KERN_ERR "resize option for remount only\n");
+		return NULL;
+	}
+
+	/*
+	 * Initialize blocksize to 4K.
+	 */
+	sb_set_blocksize(sb, PSIZE);
+
+	/*
+	 * Set method vectors.
+	 */
+	sb->s_op = &jfs_super_operations;
+
+	rc = jfs_mount(sb);
+	if (rc) {
+		if (!silent) {
+			jERROR(1,
+			       ("jfs_mount failed w/return code = %d\n", rc));
+		}
+		goto out_kfree;
+	}
+	if (sb->s_flags & MS_RDONLY)
+		sbi->log = 0;
+	else {
+		rc = jfs_mount_rw(sb, 0);
+		if (rc) {
+			if (!silent) {
+				jERROR(1,
+				       ("jfs_mount_rw failed w/return code = %d\n",
+					rc));
+			}
+			goto out_no_rw;
+		}
+	}
+
+	sb->s_magic = JFS_SUPER_MAGIC;
+
+	inode = iget(sb, ROOT_I);
+	if (!inode || is_bad_inode(inode))
+		goto out_no_root;
+	sb->s_root = d_alloc_root(inode);
+	if (!sb->s_root)
+		goto out_no_root;
+
+	if (!sbi->nls_tab)
+		sbi->nls_tab = load_nls_default();
+
+	/* logical blocks are represented by 40 bits in pxd_t, etc. */
+	sb->s_maxbytes = ((u64) sb->s_blocksize) << 40;
+#if BITS_PER_LONG == 32
+	/*
+	 * Page cache is indexed by long.
+	 * I would use MAX_LFS_FILESIZE, but it's only half as big
+	 */
+	sb->s_maxbytes = min(((u64) PAGE_CACHE_SIZE << 32) - 1, sb->s_maxbytes);
+#endif
+
+	return sb;
+
+out_no_root:
+	jEVENT(1, ("jfs_read_super: get root inode failed\n"));
+	if (inode)
+		iput(inode);
+
+out_no_rw:
+	rc = jfs_umount(sb);
+	if (rc) {
+		jERROR(1, ("jfs_umount failed with return code %d\n", rc));
+	}
+out_kfree:
+	if (sbi->nls_tab)
+		unload_nls(sbi->nls_tab);
+	kfree(sbi);
+	return NULL;
+}
+
+static void jfs_write_super_lockfs(struct super_block *sb)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	struct jfs_log *log = sbi->log;
+
+	if (!(sb->s_flags & MS_RDONLY)) {
+		txQuiesce(sb);
+		lmLogShutdown(log);
+	}
+}
+
+static void jfs_unlockfs(struct super_block *sb)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	struct jfs_log *log = sbi->log;
+	int rc = 0;
+
+	if (!(sb->s_flags & MS_RDONLY)) {
+		if ((rc = lmLogInit(log)))
+			jERROR(1,
+			       ("jfs_unlock failed with return code %d\n", rc));
+		else
+			txResume(sb);
+	}
+}
+
+
+static struct super_operations jfs_super_operations = {
+	.read_inode	= jfs_read_inode,
+	.dirty_inode	= jfs_dirty_inode,
+	.write_inode	= jfs_write_inode,
+	.clear_inode	= jfs_clear_inode,
+	.delete_inode	= jfs_delete_inode,
+	.put_super	= jfs_put_super,
+	.write_super_lockfs = jfs_write_super_lockfs,
+	.unlockfs       = jfs_unlockfs,
+	.statfs		= jfs_statfs,
+	.remount_fs	= jfs_remount,
+};
+
+static struct file_system_type jfs_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "jfs",
+	.read_super	= jfs_read_super,
+	.fs_flags	= FS_REQUIRES_DEV,
+};
+
+extern int metapage_init(void);
+extern int txInit(void);
+extern void txExit(void);
+extern void metapage_exit(void);
+
+static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		INIT_LIST_HEAD(&jfs_ip->anon_inode_list);
+		INIT_LIST_HEAD(&jfs_ip->mp_list);
+		init_rwsem(&jfs_ip->rdwrlock);
+		init_MUTEX(&jfs_ip->commit_sem);
+		jfs_ip->atlhead = 0;
+		jfs_ip->active_ag = -1;
+	}
+}
+
+static int __init init_jfs_fs(void)
+{
+	int rc;
+
+	jfs_inode_cachep =
+	    kmem_cache_create("jfs_ip", sizeof (struct jfs_inode_info), 0, 0,
+			      init_once, NULL);
+	if (jfs_inode_cachep == NULL)
+		return -ENOMEM;
+
+	/*
+	 * Metapage initialization
+	 */
+	rc = metapage_init();
+	if (rc) {
+		jERROR(1, ("metapage_init failed w/rc = %d\n", rc));
+		goto free_slab;
+	}
+
+	/*
+	 * Transaction Manager initialization
+	 */
+	rc = txInit();
+	if (rc) {
+		jERROR(1, ("txInit failed w/rc = %d\n", rc));
+		goto free_metapage;
+	}
+
+	/*
+	 * I/O completion thread (endio)
+	 */
+	jfsIOthread = kernel_thread(jfsIOWait, 0,
+				    CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	if (jfsIOthread < 0) {
+		jERROR(1,
+		       ("init_jfs_fs: fork failed w/rc = %d\n", jfsIOthread));
+		goto end_txmngr;
+	}
+	wait_for_completion(&jfsIOwait);	/* Wait until thread starts */
+
+	jfsCommitThread = kernel_thread(jfs_lazycommit, 0,
+					CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	if (jfsCommitThread < 0) {
+		jERROR(1,
+		       ("init_jfs_fs: fork failed w/rc = %d\n",
+			jfsCommitThread));
+		goto kill_iotask;
+	}
+	wait_for_completion(&jfsIOwait);	/* Wait until thread starts */
+
+	jfsSyncThread = kernel_thread(jfs_sync, 0,
+				      CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	if (jfsSyncThread < 0) {
+		jERROR(1,
+		       ("init_jfs_fs: fork failed w/rc = %d\n", jfsSyncThread));
+		goto kill_committask;
+	}
+	wait_for_completion(&jfsIOwait);	/* Wait until thread starts */
+
+#ifdef PROC_FS_JFS
+	jfs_proc_init();
+#endif
+
+	return register_filesystem(&jfs_fs_type);
+
+kill_committask:
+	jfs_stop_threads = 1;
+	wake_up(&jfs_commit_thread_wait);
+	wait_for_completion(&jfsIOwait);	/* Wait for thread exit */
+kill_iotask:
+	jfs_stop_threads = 1;
+	wake_up(&jfs_IO_thread_wait);
+	wait_for_completion(&jfsIOwait);	/* Wait for thread exit */
+end_txmngr:
+	txExit();
+free_metapage:
+	metapage_exit();
+free_slab:
+	kmem_cache_destroy(jfs_inode_cachep);
+	return -rc;
+}
+
+static void __exit exit_jfs_fs(void)
+{
+	jFYI(1, ("exit_jfs_fs called\n"));
+
+	jfs_stop_threads = 1;
+	txExit();
+	metapage_exit();
+	wake_up(&jfs_IO_thread_wait);
+	wait_for_completion(&jfsIOwait);	/* Wait for IO thread exit */
+	wake_up(&jfs_commit_thread_wait);
+	wait_for_completion(&jfsIOwait);	/* Wait for Commit thread exit */
+	wake_up(&jfs_sync_thread_wait);
+	wait_for_completion(&jfsIOwait);	/* Wait for Sync thread exit */
+#ifdef PROC_FS_JFS
+	jfs_proc_clean();
+#endif
+	unregister_filesystem(&jfs_fs_type);
+	kmem_cache_destroy(jfs_inode_cachep);
+}
+
+EXPORT_NO_SYMBOLS;
+
+module_init(init_jfs_fs)
+module_exit(exit_jfs_fs)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/symlink.c linux-2.4.20/fs/jfs/symlink.c
--- linux-2.4.19/fs/jfs/symlink.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/symlink.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,43 @@
+/*
+ *   Copyright (c) Christoph Hellwig, 2001-2002
+ *
+ *   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
+ */
+
+#include <linux/fs.h>
+#include "jfs_incore.h"
+#include "jfs_xattr.h"
+
+static int jfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	char *s = JFS_IP(dentry->d_inode)->i_inline;
+	return vfs_follow_link(nd, s);
+}
+
+static int jfs_readlink(struct dentry *dentry, char *buffer, int buflen)
+{
+	char *s = JFS_IP(dentry->d_inode)->i_inline;
+	return vfs_readlink(dentry, buffer, buflen, s);
+}
+
+struct inode_operations jfs_symlink_inode_operations = {
+	.readlink	= jfs_readlink,
+	.follow_link	= jfs_follow_link,
+	.setxattr	= jfs_setxattr,
+	.getxattr	= jfs_getxattr,
+	.listxattr	= jfs_listxattr,
+	.removexattr	= jfs_removexattr,
+};
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/jfs/xattr.c linux-2.4.20/fs/jfs/xattr.c
--- linux-2.4.19/fs/jfs/xattr.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/jfs/xattr.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,937 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000-2002
+ *   Copyright (c) Christoph Hellwig, 2002
+ *
+ *   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
+ */
+
+#include <linux/fs.h>
+#include <linux/xattr.h>
+#include "jfs_incore.h"
+#include "jfs_dmap.h"
+#include "jfs_debug.h"
+#include "jfs_dinode.h"
+#include "jfs_extent.h"
+#include "jfs_metapage.h"
+#include "jfs_xattr.h"
+
+/*
+ *	jfs_xattr.c: extended attribute service
+ *
+ * Overall design --
+ *
+ * Format:
+ *
+ *   Extended attribute lists (jfs_ea_list) consist of an overall size (32 bit
+ *   value) and a variable (0 or more) number of extended attribute
+ *   entries.  Each extended attribute entry (jfs_ea) is a <name,value> double
+ *   where <name> is constructed from a null-terminated ascii string
+ *   (1 ... 255 bytes in the name) and <value> is arbitrary 8 bit data
+ *   (1 ... 65535 bytes).  The in-memory format is
+ *
+ *   0       1        2        4                4 + namelen + 1
+ *   +-------+--------+--------+----------------+-------------------+
+ *   | Flags | Name   | Value  | Name String \0 | Data . . . .      |
+ *   |       | Length | Length |                |                   |
+ *   +-------+--------+--------+----------------+-------------------+
+ *
+ *   A jfs_ea_list then is structured as
+ *
+ *   0            4                   4 + EA_SIZE(ea1)
+ *   +------------+-------------------+--------------------+-----
+ *   | Overall EA | First FEA Element | Second FEA Element | ..... 
+ *   | List Size  |                   |                    |
+ *   +------------+-------------------+--------------------+-----
+ *
+ *   On-disk:
+ *
+ *     FEALISTs are stored on disk using blocks allocated by dbAlloc() and
+ *     written directly. An EA list may be in-lined in the inode if there is
+ *     sufficient room available.
+ */
+
+struct ea_buffer {
+	int flag;		/* Indicates what storage xattr points to */
+	int max_size;		/* largest xattr that fits in current buffer */
+	dxd_t new_ea;		/* dxd to replace ea when modifying xattr */
+	struct metapage *mp;	/* metapage containing ea list */
+	struct jfs_ea_list *xattr;	/* buffer containing ea list */
+};
+
+/*
+ * ea_buffer.flag values
+ */
+#define EA_INLINE	0x0001
+#define EA_EXTENT	0x0002
+#define EA_NEW		0x0004
+#define EA_MALLOC	0x0008
+
+/* Namespaces */
+#define XATTR_SYSTEM_PREFIX "system."
+#define XATTR_SYSTEM_PREFIX_LEN (sizeof (XATTR_SYSTEM_PREFIX) - 1)
+
+#define XATTR_USER_PREFIX "user."
+#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
+
+#define XATTR_OS2_PREFIX "os2."
+#define XATTR_OS2_PREFIX_LEN (sizeof (XATTR_OS2_PREFIX) - 1)
+
+/*
+ * These three routines are used to recognize on-disk extended attributes
+ * that are in a recognized namespace.  If the attribute is not recognized,
+ * "os2." is prepended to the name
+ */
+static inline int is_os2_xattr(struct jfs_ea *ea)
+{
+	/*
+	 * Check for "system."
+	 */
+	if ((ea->namelen >= XATTR_SYSTEM_PREFIX_LEN) &&
+	    !strncmp(ea->name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+		return FALSE;
+	/*
+	 * Check for "user."
+	 */
+	if ((ea->namelen >= XATTR_USER_PREFIX_LEN) &&
+	    !strncmp(ea->name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
+		return FALSE;
+	/*
+	 * Add any other valid namespace prefixes here
+	 */
+
+	/*
+	 * We assume it's OS/2's flat namespace
+	 */
+	return TRUE;
+}
+
+static inline int name_size(struct jfs_ea *ea)
+{
+	if (is_os2_xattr(ea))
+		return ea->namelen + XATTR_OS2_PREFIX_LEN;
+	else
+		return ea->namelen;
+}
+
+static inline int copy_name(char *buffer, struct jfs_ea *ea)
+{
+	int len = ea->namelen;
+
+	if (is_os2_xattr(ea)) {
+		memcpy(buffer, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN);
+		buffer += XATTR_OS2_PREFIX_LEN;
+		len += XATTR_OS2_PREFIX_LEN;
+	}
+	memcpy(buffer, ea->name, ea->namelen);
+	buffer[ea->namelen] = 0;
+
+	return len;
+}
+
+/* Forward references */
+static void ea_release(struct inode *inode, struct ea_buffer *ea_buf);
+
+/*
+ * NAME: ea_write_inline
+ *                                                                    
+ * FUNCTION: Attempt to write an EA inline if area is available
+ *                                                                    
+ * PRE CONDITIONS:
+ *	Already verified that the specified EA is small enough to fit inline
+ *
+ * PARAMETERS:
+ *	ip	- Inode pointer
+ *	ealist	- EA list pointer
+ *	size	- size of ealist in bytes
+ *	ea	- dxd_t structure to be filled in with necessary EA information
+ *		  if we successfully copy the EA inline
+ *
+ * NOTES:
+ *	Checks if the inode's inline area is available.  If so, copies EA inline
+ *	and sets <ea> fields appropriately.  Otherwise, returns failure, EA will
+ *	have to be put into an extent.
+ *
+ * RETURNS: 0 for successful copy to inline area; -1 if area not available
+ */
+static int ea_write_inline(struct inode *ip, struct jfs_ea_list *ealist,
+			   int size, dxd_t * ea)
+{
+	struct jfs_inode_info *ji = JFS_IP(ip);
+
+	/*
+	 * Make sure we have an EA -- the NULL EA list is valid, but you
+	 * can't copy it!
+	 */
+	if (ealist && size > sizeof (struct jfs_ea_list)) {
+		assert(size <= sizeof (ji->i_inline_ea));
+
+		/*
+		 * See if the space is available or if it is already being
+		 * used for an inline EA.
+		 */
+		if (!(ji->mode2 & INLINEEA) && !(ji->ea.flag & DXD_INLINE))
+			return -1;
+
+		DXDsize(ea, size);
+		DXDlength(ea, 0);
+		DXDaddress(ea, 0);
+		memcpy(ji->i_inline_ea, ealist, size);
+		ea->flag = DXD_INLINE;
+		ji->mode2 &= ~INLINEEA;
+	} else {
+		ea->flag = 0;
+		DXDsize(ea, 0);
+		DXDlength(ea, 0);
+		DXDaddress(ea, 0);
+
+		/* Free up INLINE area */
+		if (ji->ea.flag & DXD_INLINE)
+			ji->mode2 |= INLINEEA;
+	}
+
+	mark_inode_dirty(ip);
+	return 0;
+}
+
+/*
+ * NAME: ea_write
+ *                                                                    
+ * FUNCTION: Write an EA for an inode
+ *                                                                    
+ * PRE CONDITIONS: EA has been verified 
+ *
+ * PARAMETERS:
+ *	ip	- Inode pointer
+ *	ealist	- EA list pointer
+ *	size	- size of ealist in bytes
+ *	ea	- dxd_t structure to be filled in appropriately with where the
+ *		  EA was copied
+ *
+ * NOTES: Will write EA inline if able to, otherwise allocates blocks for an
+ *	extent and synchronously writes it to those blocks.
+ *
+ * RETURNS: 0 for success; Anything else indicates failure
+ */
+static int ea_write(struct inode *ip, struct jfs_ea_list *ealist, int size,
+		       dxd_t * ea)
+{
+	struct super_block *sb = ip->i_sb;
+	struct jfs_inode_info *ji = JFS_IP(ip);
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	int nblocks;
+	s64 blkno;
+	int rc = 0, i;
+	char *cp;
+	s32 nbytes, nb;
+	s32 bytes_to_write;
+	struct metapage *mp;
+
+	/*
+	 * Quick check to see if this is an in-linable EA.  Short EAs
+	 * and empty EAs are all in-linable, provided the space exists.
+	 */
+	if (!ealist || size <= sizeof (ji->i_inline_ea)) {
+		if (!ea_write_inline(ip, ealist, size, ea))
+			return 0;
+	}
+
+	/* figure out how many blocks we need */
+	nblocks = (size + (sb->s_blocksize - 1)) >> sb->s_blocksize_bits;
+
+	rc = dbAlloc(ip, INOHINT(ip), nblocks, &blkno);
+	if (rc)
+		return -rc;
+
+	/*
+	 * Now have nblocks worth of storage to stuff into the FEALIST.
+	 * loop over the FEALIST copying data into the buffer one page at
+	 * a time.
+	 */
+	cp = (char *) ealist;
+	nbytes = size;
+	for (i = 0; i < nblocks; i += sbi->nbperpage) {
+		/*
+		 * Determine how many bytes for this request, and round up to
+		 * the nearest aggregate block size
+		 */
+		nb = min(PSIZE, nbytes);
+		bytes_to_write =
+		    ((((nb + sb->s_blocksize - 1)) >> sb->s_blocksize_bits))
+		    << sb->s_blocksize_bits;
+
+		if (!(mp = get_metapage(ip, blkno + i, bytes_to_write, 1))) {
+			rc = -EIO;
+			goto failed;
+		}
+
+		memcpy(mp->data, cp, nb);
+
+		/*
+		 * We really need a way to propagate errors for
+		 * forced writes like this one.  --hch
+		 *
+		 * (__write_metapage => release_metapage => flush_metapage)
+		 */
+#ifdef _JFS_FIXME
+		if ((rc = flush_metapage(mp))) {
+			/*
+			 * the write failed -- this means that the buffer
+			 * is still assigned and the blocks are not being
+			 * used.  this seems like the best error recovery
+			 * we can get ...
+			 */
+			goto failed;
+		}
+#else
+		flush_metapage(mp);
+#endif
+
+		cp += PSIZE;
+		nbytes -= nb;
+	}
+
+	ea->flag = DXD_EXTENT;
+	DXDsize(ea, le32_to_cpu(ealist->size));
+	DXDlength(ea, nblocks);
+	DXDaddress(ea, blkno);
+
+	/* Free up INLINE area */
+	if (ji->ea.flag & DXD_INLINE)
+		ji->mode2 |= INLINEEA;
+
+	return 0;
+
+      failed:
+	dbFree(ip, blkno, nblocks);
+	return rc;
+}
+
+/*
+ * NAME: ea_read_inline
+ *                                                                    
+ * FUNCTION: Read an inlined EA into user's buffer
+ *                                                                    
+ * PARAMETERS:
+ *	ip	- Inode pointer
+ *	ealist	- Pointer to buffer to fill in with EA
+ *
+ * RETURNS: 0
+ */
+static int ea_read_inline(struct inode *ip, struct jfs_ea_list *ealist)
+{
+	struct jfs_inode_info *ji = JFS_IP(ip);
+	int ea_size = sizeDXD(&ji->ea);
+
+	if (ea_size == 0) {
+		ealist->size = 0;
+		return 0;
+	}
+
+	/* Sanity Check */
+	if ((sizeDXD(&ji->ea) > sizeof (ji->i_inline_ea)))
+		return -EIO;
+	if (le32_to_cpu(((struct jfs_ea_list *) &ji->i_inline_ea)->size)
+	    != ea_size)
+		return -EIO;
+
+	memcpy(ealist, ji->i_inline_ea, ea_size);
+	return 0;
+}
+
+/*
+ * NAME: ea_read
+ *                                                                    
+ * FUNCTION: copy EA data into user's buffer
+ *                                                                    
+ * PARAMETERS:
+ *	ip	- Inode pointer
+ *	ealist	- Pointer to buffer to fill in with EA
+ *
+ * NOTES:  If EA is inline calls ea_read_inline() to copy EA.
+ *
+ * RETURNS: 0 for success; other indicates failure
+ */
+static int ea_read(struct inode *ip, struct jfs_ea_list *ealist)
+{
+	struct super_block *sb = ip->i_sb;
+	struct jfs_inode_info *ji = JFS_IP(ip);
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	int nblocks;
+	s64 blkno;
+	char *cp = (char *) ealist;
+	int i;
+	int nbytes, nb;
+	s32 bytes_to_read;
+	struct metapage *mp;
+
+	/* quick check for in-line EA */
+	if (ji->ea.flag & DXD_INLINE)
+		return ea_read_inline(ip, ealist);
+
+	nbytes = sizeDXD(&ji->ea);
+	assert(nbytes);
+
+	/* 
+	 * Figure out how many blocks were allocated when this EA list was
+	 * originally written to disk.
+	 */
+	nblocks = lengthDXD(&ji->ea) << sbi->l2nbperpage;
+	blkno = addressDXD(&ji->ea) << sbi->l2nbperpage;
+
+	/*
+	 * I have found the disk blocks which were originally used to store
+	 * the FEALIST.  now i loop over each contiguous block copying the
+	 * data into the buffer.
+	 */
+	for (i = 0; i < nblocks; i += sbi->nbperpage) {
+		/*
+		 * Determine how many bytes for this request, and round up to
+		 * the nearest aggregate block size
+		 */
+		nb = min(PSIZE, nbytes);
+		bytes_to_read =
+		    ((((nb + sb->s_blocksize - 1)) >> sb->s_blocksize_bits))
+		    << sb->s_blocksize_bits;
+
+		if (!(mp = read_metapage(ip, blkno + i, bytes_to_read, 1)))
+			return -EIO;
+
+		memcpy(cp, mp->data, nb);
+		release_metapage(mp);
+
+		cp += PSIZE;
+		nbytes -= nb;
+	}
+
+	return 0;
+}
+
+/*
+ * NAME: ea_get
+ *                                                                    
+ * FUNCTION: Returns buffer containing existing extended attributes.
+ *	     The size of the buffer will be the larger of the existing
+ *	     attributes size, or min_size.
+ *
+ *	     The buffer, which may be inlined in the inode or in the
+ * 	     page cache must be release by calling ea_release or ea_put
+ *                                                                    
+ * PARAMETERS:
+ *	inode	- Inode pointer
+ *	ea_buf	- Structure to be populated with ealist and its metadata
+ *	min_size- minimum size of buffer to be returned
+ *
+ * RETURNS: 0 for success; Other indicates failure
+ */
+static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
+{
+	struct jfs_inode_info *ji = JFS_IP(inode);
+	struct super_block *sb = inode->i_sb;
+	int size;
+	int ea_size = sizeDXD(&ji->ea);
+	int blocks_needed, current_blocks;
+	s64 blkno;
+	int rc;
+
+	/* When fsck.jfs clears a bad ea, it doesn't clear the size */
+	if (ji->ea.flag == 0)
+		ea_size = 0;
+
+	if (ea_size == 0) {
+		if (min_size == 0) {
+			ea_buf->flag = 0;
+			ea_buf->max_size = 0;
+			ea_buf->xattr = NULL;
+			return 0;
+		}
+		if ((min_size <= sizeof (ji->i_inline_ea)) &&
+		    (ji->mode2 & INLINEEA)) {
+			ea_buf->flag = EA_INLINE | EA_NEW;
+			ea_buf->max_size = sizeof (ji->i_inline_ea);
+			ea_buf->xattr = (struct jfs_ea_list *) ji->i_inline_ea;
+			DXDlength(&ea_buf->new_ea, 0);
+			DXDaddress(&ea_buf->new_ea, 0);
+			ea_buf->new_ea.flag = DXD_INLINE;
+			DXDsize(&ea_buf->new_ea, min_size);
+			return 0;
+		}
+		current_blocks = 0;
+	} else if (ji->ea.flag & DXD_INLINE) {
+		if (min_size <= sizeof (ji->i_inline_ea)) {
+			ea_buf->flag = EA_INLINE;
+			ea_buf->max_size = sizeof (ji->i_inline_ea);
+			ea_buf->xattr = (struct jfs_ea_list *) ji->i_inline_ea;
+			goto size_check;
+		}
+		current_blocks = 0;
+	} else {
+		assert(ji->ea.flag & DXD_EXTENT);
+		current_blocks = (ea_size + sb->s_blocksize - 1) >>
+		    sb->s_blocksize_bits;
+	}
+	size = max(min_size, ea_size);
+
+	if (size > PSIZE) {
+		/*
+		 * To keep the rest of the code simple.  Allocate a
+		 * contiguous buffer to work with
+		 */
+		ea_buf->xattr = kmalloc(size, GFP_KERNEL);
+		if (ea_buf->xattr == NULL)
+			return -ENOMEM;
+
+		ea_buf->flag |= EA_MALLOC;
+		ea_buf->max_size = (size + sb->s_blocksize - 1) &
+		    ~(sb->s_blocksize - 1);
+
+		if (ea_size == 0)
+			return 0;
+
+		if ((rc = ea_read(inode, ea_buf->xattr))) {
+			kfree(ea_buf->xattr);
+			ea_buf->xattr = NULL;
+			return rc;
+		}
+		goto size_check;
+	}
+	blocks_needed = (min_size + sb->s_blocksize - 1) >>
+	    sb->s_blocksize_bits;
+
+	if (blocks_needed > current_blocks) {
+		rc = dbAlloc(inode, INOHINT(inode), (s64) blocks_needed,
+			     &blkno);
+		if (rc)
+			return -rc;
+
+		DXDlength(&ea_buf->new_ea, blocks_needed);
+		DXDaddress(&ea_buf->new_ea, blkno);
+		ea_buf->new_ea.flag = DXD_EXTENT;
+		DXDsize(&ea_buf->new_ea, min_size);
+
+		ea_buf->flag = EA_EXTENT | EA_NEW;
+
+		ea_buf->mp = get_metapage(inode, blkno,
+					  blocks_needed << sb->s_blocksize_bits,
+					  1);
+		if (ea_buf->mp == NULL) {
+			dbFree(inode, blkno, (s64) blocks_needed);
+			return -EIO;
+		}
+		ea_buf->xattr = ea_buf->mp->data;
+		ea_buf->max_size = (min_size + sb->s_blocksize - 1) &
+		    ~(sb->s_blocksize - 1);
+		if (ea_size == 0)
+			return 0;
+		if ((rc = ea_read(inode, ea_buf->xattr))) {
+			discard_metapage(ea_buf->mp);
+			dbFree(inode, blkno, (s64) blocks_needed);
+			return rc;
+		}
+		goto size_check;
+	}
+	ea_buf->flag = EA_EXTENT;
+	ea_buf->mp = read_metapage(inode, addressDXD(&ji->ea),
+				   lengthDXD(&ji->ea), 1);
+	if (ea_buf->mp == NULL)
+		return -EIO;
+	ea_buf->xattr = ea_buf->mp->data;
+	ea_buf->max_size = (ea_size + sb->s_blocksize - 1) &
+	    ~(sb->s_blocksize - 1);
+
+      size_check:
+	if (EALIST_SIZE(ea_buf->xattr) != ea_size) {
+		printk(KERN_ERR "ea_get: invalid extended attribute\n");
+		dump_mem("xattr", ea_buf->xattr, ea_size);
+		ea_release(inode, ea_buf);
+		return -EIO;
+	}
+
+	return ea_size;
+}
+
+static void ea_release(struct inode *inode, struct ea_buffer *ea_buf)
+{
+	if (ea_buf->flag & EA_MALLOC)
+		kfree(ea_buf->xattr);
+	else if (ea_buf->flag & EA_EXTENT) {
+		assert(ea_buf->mp);
+		release_metapage(ea_buf->mp);
+
+		if (ea_buf->flag & EA_NEW)
+			dbFree(inode, addressDXD(&ea_buf->new_ea),
+			       lengthDXD(&ea_buf->new_ea));
+	}
+}
+
+static int ea_put(struct inode *inode, struct ea_buffer *ea_buf, int new_size)
+{
+	struct jfs_inode_info *ji = JFS_IP(inode);
+	unsigned long old_blocks, new_blocks;
+	int rc = 0;
+	tid_t tid;
+
+	if (new_size == 0) {
+		ea_release(inode, ea_buf);
+		ea_buf = 0;
+	} else if (ea_buf->flag & EA_INLINE) {
+		assert(new_size <= sizeof (ji->i_inline_ea));
+		ji->mode2 &= ~INLINEEA;
+		ea_buf->new_ea.flag = DXD_INLINE;
+		DXDsize(&ea_buf->new_ea, new_size);
+		DXDaddress(&ea_buf->new_ea, 0);
+		DXDlength(&ea_buf->new_ea, 0);
+	} else if (ea_buf->flag & EA_MALLOC) {
+		rc = ea_write(inode, ea_buf->xattr, new_size, &ea_buf->new_ea);
+		kfree(ea_buf->xattr);
+	} else if (ea_buf->flag & EA_NEW) {
+		/* We have already allocated a new dxd */
+		flush_metapage(ea_buf->mp);
+	} else {
+		/* ->xattr must point to original ea's metapage */
+		rc = ea_write(inode, ea_buf->xattr, new_size, &ea_buf->new_ea);
+		discard_metapage(ea_buf->mp);
+	}
+	if (rc)
+		return rc;
+
+	tid = txBegin(inode->i_sb, 0);
+	down(&ji->commit_sem);
+
+	old_blocks = new_blocks = 0;
+
+	if (ji->ea.flag & DXD_EXTENT) {
+		invalidate_dxd_metapages(inode, ji->ea);
+		old_blocks = lengthDXD(&ji->ea);
+	}
+
+	if (ea_buf) {
+		txEA(tid, inode, &ji->ea, &ea_buf->new_ea);
+		if (ea_buf->new_ea.flag & DXD_EXTENT) {
+			new_blocks = lengthDXD(&ea_buf->new_ea);
+			if (ji->ea.flag & DXD_INLINE)
+				ji->mode2 |= INLINEEA;
+		}
+		ji->ea = ea_buf->new_ea;
+	} else {
+		txEA(tid, inode, &ji->ea, 0);
+		if (ji->ea.flag & DXD_INLINE)
+			ji->mode2 |= INLINEEA;
+		ji->ea.flag = 0;
+		ji->ea.size = 0;
+	}
+
+	inode->i_blocks += LBLK2PBLK(inode->i_sb, new_blocks - old_blocks);
+	rc = txCommit(tid, 1, &inode, 0);
+	txEnd(tid);
+	up(&ji->commit_sem);
+
+	return rc;
+}
+
+static int can_set_xattr(struct inode *inode, const char *name,
+			 void *value, size_t value_len)
+{
+	if (IS_RDONLY(inode))
+		return -EROFS;
+
+	if (IS_IMMUTABLE(inode) || IS_APPEND(inode) || S_ISLNK(inode->i_mode))
+		return -EPERM;
+
+	if((strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) != 0) &&
+	   (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) != 0))
+		return -EOPNOTSUPP;
+
+	if (!S_ISREG(inode->i_mode) &&
+	    (!S_ISDIR(inode->i_mode) || inode->i_mode &S_ISVTX))
+		return -EPERM;
+
+	return permission(inode, MAY_WRITE);
+}
+
+int __jfs_setxattr(struct inode *inode, const char *name, void *value,
+		   size_t value_len, int flags)
+{
+	struct jfs_ea_list *ealist;
+	struct jfs_ea *ea, *old_ea = NULL, *next_ea = NULL;
+	struct ea_buffer ea_buf;
+	int old_ea_size = 0;
+	int xattr_size;
+	int new_size;
+	int namelen = strlen(name);
+	char *os2name = NULL;
+	int found = 0;
+	int rc;
+	int length;
+
+	if ((rc = can_set_xattr(inode, name, value, value_len)))
+		return rc;
+
+	if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
+		os2name = kmalloc(namelen - XATTR_OS2_PREFIX_LEN + 1,
+				  GFP_KERNEL);
+		if (!os2name)
+			return -ENOMEM;
+		strcpy(os2name, name + XATTR_OS2_PREFIX_LEN);
+		name = os2name;
+		namelen -= XATTR_OS2_PREFIX_LEN;
+	}
+
+	xattr_size = ea_get(inode, &ea_buf, 0);
+	if (xattr_size < 0) {
+		rc = xattr_size;
+		goto out;
+	}
+
+      again:
+	ealist = (struct jfs_ea_list *) ea_buf.xattr;
+	new_size = sizeof (struct jfs_ea_list);
+
+	if (xattr_size) {
+		for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist);
+		     ea = NEXT_EA(ea)) {
+			if ((namelen == ea->namelen) &&
+			    (memcmp(name, ea->name, namelen) == 0)) {
+				found = 1;
+				if (flags & XATTR_CREATE) {
+					rc = -EEXIST;
+					goto release;
+				}
+				old_ea = ea;
+				old_ea_size = EA_SIZE(ea);
+				next_ea = NEXT_EA(ea);
+			} else
+				new_size += EA_SIZE(ea);
+		}
+	}
+
+	if (!found) {
+		if (flags & XATTR_REPLACE) {
+			rc = -ENODATA;
+			goto release;
+		}
+		if (value == NULL) {
+			rc = 0;
+			goto release;
+		}
+	}
+	if (value)
+		new_size += sizeof (struct jfs_ea) + namelen + 1 + value_len;
+
+	if (new_size > ea_buf.max_size) {
+		/*
+		 * We need to allocate more space for merged ea list.
+		 * We should only have loop to again: once.
+		 */
+		ea_release(inode, &ea_buf);
+		xattr_size = ea_get(inode, &ea_buf, new_size);
+		if (xattr_size < 0) {
+			rc = xattr_size;
+			goto out;
+		}
+		goto again;
+	}
+
+	/* Remove old ea of the same name */
+	if (found) {
+		/* number of bytes following target EA */
+		length = (char *) END_EALIST(ealist) - (char *) next_ea;
+		if (length > 0)
+			memmove(old_ea, next_ea, length);
+		xattr_size -= old_ea_size;
+	}
+
+	/* Add new entry to the end */
+	if (value) {
+		if (xattr_size == 0)
+			/* Completely new ea list */
+			xattr_size = sizeof (struct jfs_ea_list);
+
+		ea = (struct jfs_ea *) ((char *) ealist + xattr_size);
+		ea->flag = 0;
+		ea->namelen = namelen;
+		ea->valuelen = (cpu_to_le16(value_len));
+		memcpy(ea->name, name, namelen);
+		ea->name[namelen] = 0;
+		if (value_len)
+			memcpy(&ea->name[namelen + 1], value, value_len);
+		xattr_size += EA_SIZE(ea);
+	}
+
+	/* DEBUG - If we did this right, these number match */
+	if (xattr_size != new_size) {
+		printk(KERN_ERR
+		       "jfs_xsetattr: xattr_size = %d, new_size = %d\n",
+		       xattr_size, new_size);
+
+		rc = -EINVAL;
+		goto release;
+	}
+
+	/*
+	 * If we're left with an empty list, there's no ea
+	 */
+	if (new_size == sizeof (struct jfs_ea_list))
+		new_size = 0;
+
+	ealist->size = cpu_to_le32(new_size);
+
+	rc = ea_put(inode, &ea_buf, new_size);
+
+	goto out;
+      release:
+	ea_release(inode, &ea_buf);
+      out:
+	if (os2name)
+		kfree(os2name);
+
+	return rc;
+}
+
+int jfs_setxattr(struct dentry *dentry, const char *name, void *value,
+		 size_t value_len, int flags)
+{
+	if (value == NULL) {	/* empty EA, do not remove */
+		value = "";
+		value_len = 0;
+	}
+
+	return __jfs_setxattr(dentry->d_inode, name, value, value_len, flags);
+}
+
+static inline int can_get_xattr(struct inode *inode, const char *name)
+{
+	return permission(inode, MAY_READ);
+}
+
+ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data,
+		       size_t buf_size)
+{
+	struct jfs_ea_list *ealist;
+	struct jfs_ea *ea;
+	struct ea_buffer ea_buf;
+	int xattr_size;
+	ssize_t size;
+	int namelen = strlen(name);
+	char *os2name = NULL;
+	int rc;
+	char *value;
+
+	if ((rc = can_get_xattr(inode, name)))
+		return rc;
+
+	if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
+		os2name = kmalloc(namelen - XATTR_OS2_PREFIX_LEN + 1,
+				  GFP_KERNEL);
+		if (!os2name)
+			return -ENOMEM;
+		strcpy(os2name, name + XATTR_OS2_PREFIX_LEN);
+		name = os2name;
+		namelen -= XATTR_OS2_PREFIX_LEN;
+	}
+
+	xattr_size = ea_get(inode, &ea_buf, 0);
+	if (xattr_size < 0) {
+		size = xattr_size;
+		goto out;
+	}
+
+	if (xattr_size == 0)
+		goto not_found;
+
+	ealist = (struct jfs_ea_list *) ea_buf.xattr;
+
+	/* Find the named attribute */
+	for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea))
+		if ((namelen == ea->namelen) &&
+		    memcmp(name, ea->name, namelen) == 0) {
+			/* Found it */
+			size = le16_to_cpu(ea->valuelen);
+			if (!data)
+				goto release;
+			else if (size > buf_size) {
+				size = -ERANGE;
+				goto release;
+			}
+			value = ((char *) &ea->name) + ea->namelen + 1;
+			memcpy(data, value, size);
+			goto release;
+		}
+      not_found:
+	size = -ENODATA;
+      release:
+	ea_release(inode, &ea_buf);
+      out:
+	if (os2name)
+		kfree(os2name);
+
+	return size;
+}
+
+ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data,
+		     size_t buf_size)
+{
+	return __jfs_getxattr(dentry->d_inode, name, data, buf_size);
+}
+
+ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size)
+{
+	struct inode *inode = dentry->d_inode;
+	char *buffer;
+	ssize_t size = 0;
+	int xattr_size;
+	struct jfs_ea_list *ealist;
+	struct jfs_ea *ea;
+	struct ea_buffer ea_buf;
+
+	xattr_size = ea_get(inode, &ea_buf, 0);
+	if (xattr_size < 0) {
+		size = xattr_size;
+		goto out;
+	}
+
+	if (xattr_size == 0)
+		goto release;
+
+	ealist = (struct jfs_ea_list *) ea_buf.xattr;
+
+	/* compute required size of list */
+	for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea))
+		size += name_size(ea) + 1;
+
+	if (!data)
+		goto release;
+
+	if (size > buf_size) {
+		size = -ERANGE;
+		goto release;
+	}
+
+	/* Copy attribute names to buffer */
+	buffer = data;
+	for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) {
+		int namelen = copy_name(buffer, ea);
+		buffer += namelen + 1;
+	}
+
+      release:
+	ea_release(inode, &ea_buf);
+      out:
+	return size;
+}
+
+int jfs_removexattr(struct dentry *dentry, const char *name)
+{
+	return __jfs_setxattr(dentry->d_inode, name, 0, 0, XATTR_REPLACE);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/lockd/svc4proc.c linux-2.4.20/fs/lockd/svc4proc.c
--- linux-2.4.19/fs/lockd/svc4proc.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/lockd/svc4proc.c	2002-10-29 11:18:37.000000000 +0000
@@ -528,7 +528,7 @@
 
 struct nlm_void			{ int dummy; };
 
-#define PROC(name, xargt, xrest, argt, rest)	\
+#define PROC(name, xargt, xrest, argt, rest, respsize)	\
  { (svc_procfunc) nlm4svc_proc_##name,	\
    (kxdrproc_t) nlm4svc_decode_##xargt,	\
    (kxdrproc_t) nlm4svc_encode_##xrest,	\
@@ -536,33 +536,38 @@
    sizeof(struct nlm_##argt),		\
    sizeof(struct nlm_##rest),		\
    0,					\
-   0					\
+   0,					\
+   respsize,				\
  }
+#define	Ck	(1+8)	/* cookie */
+#define	No	(1+1024/4)	/* netobj */
+#define	St	1	/* status */
+#define	Rg	4	/* range (offset + length) */
 struct svc_procedure		nlmsvc_procedures4[] = {
-  PROC(null,		void,		void,		void,	void),
-  PROC(test,		testargs,	testres,	args,	res),
-  PROC(lock,		lockargs,	res,		args,	res),
-  PROC(cancel,		cancargs,	res,		args,	res),
-  PROC(unlock,		unlockargs,	res,		args,	res),
-  PROC(granted,		testargs,	res,		args,	res),
-  PROC(test_msg,	testargs,	norep,		args,	void),
-  PROC(lock_msg,	lockargs,	norep,		args,	void),
-  PROC(cancel_msg,	cancargs,	norep,		args,	void),
-  PROC(unlock_msg,	unlockargs,	norep,		args,	void),
-  PROC(granted_msg,	testargs,	norep,		args,	void),
-  PROC(test_res,	testres,	norep,		res,	void),
-  PROC(lock_res,	lockres,	norep,		res,	void),
-  PROC(cancel_res,	cancelres,	norep,		res,	void),
-  PROC(unlock_res,	unlockres,	norep,		res,	void),
-  PROC(granted_res,	grantedres,	norep,		res,	void),
+  PROC(null,		void,		void,		void,	void, 1),
+  PROC(test,		testargs,	testres,	args,	res, Ck+St+2+No+Rg),
+  PROC(lock,		lockargs,	res,		args,	res, Ck+St),
+  PROC(cancel,		cancargs,	res,		args,	res, Ck+St),
+  PROC(unlock,		unlockargs,	res,		args,	res, Ck+St),
+  PROC(granted,		testargs,	res,		args,	res, Ck+St),
+  PROC(test_msg,	testargs,	norep,		args,	void, 1),
+  PROC(lock_msg,	lockargs,	norep,		args,	void, 1),
+  PROC(cancel_msg,	cancargs,	norep,		args,	void, 1),
+  PROC(unlock_msg,	unlockargs,	norep,		args,	void, 1),
+  PROC(granted_msg,	testargs,	norep,		args,	void, 1),
+  PROC(test_res,	testres,	norep,		res,	void, 1),
+  PROC(lock_res,	lockres,	norep,		res,	void, 1),
+  PROC(cancel_res,	cancelres,	norep,		res,	void, 1),
+  PROC(unlock_res,	unlockres,	norep,		res,	void, 1),
+  PROC(granted_res,	grantedres,	norep,		res,	void, 1),
   /* statd callback */
-  PROC(sm_notify,	reboot,		void,		reboot,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(share,		shareargs,	shareres,	args,	res),
-  PROC(unshare,		shareargs,	shareres,	args,	res),
-  PROC(nm_lock,		lockargs,	res,		args,	res),
-  PROC(free_all,	notify,		void,		args,	void),
+  PROC(sm_notify,	reboot,		void,		reboot,	void, 1),
+  PROC(none,		void,		void,		void,	void, 0),
+  PROC(none,		void,		void,		void,	void, 0),
+  PROC(none,		void,		void,		void,	void, 0),
+  PROC(share,		shareargs,	shareres,	args,	res, Ck+St+1),
+  PROC(unshare,		shareargs,	shareres,	args,	res, Ck+St+1),
+  PROC(nm_lock,		lockargs,	res,		args,	res, Ck+St),
+  PROC(free_all,	notify,		void,		args,	void, 1),
 
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/lockd/svcproc.c linux-2.4.20/fs/lockd/svcproc.c
--- linux-2.4.19/fs/lockd/svcproc.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/lockd/svcproc.c	2002-10-29 11:18:49.000000000 +0000
@@ -556,7 +556,7 @@
 
 struct nlm_void			{ int dummy; };
 
-#define PROC(name, xargt, xrest, argt, rest)	\
+#define PROC(name, xargt, xrest, argt, rest, respsize)	\
  { (svc_procfunc) nlmsvc_proc_##name,	\
    (kxdrproc_t) nlmsvc_decode_##xargt,	\
    (kxdrproc_t) nlmsvc_encode_##xrest,	\
@@ -564,33 +564,40 @@
    sizeof(struct nlm_##argt),		\
    sizeof(struct nlm_##rest),		\
    0,					\
-   0					\
+   0,					\
+   respsize,				\
  }
+
+#define	Ck	(1+8)	/* cookie */
+#define	St	1	/* status */
+#define	No	(1+1024/4) /* Net Obj */
+#define	Rg	2	/* range - offset + size */
+
 struct svc_procedure		nlmsvc_procedures[] = {
-  PROC(null,		void,		void,		void,	void),
-  PROC(test,		testargs,	testres,	args,	res),
-  PROC(lock,		lockargs,	res,		args,	res),
-  PROC(cancel,		cancargs,	res,		args,	res),
-  PROC(unlock,		unlockargs,	res,		args,	res),
-  PROC(granted,		testargs,	res,		args,	res),
-  PROC(test_msg,	testargs,	norep,		args,	void),
-  PROC(lock_msg,	lockargs,	norep,		args,	void),
-  PROC(cancel_msg,	cancargs,	norep,		args,	void),
-  PROC(unlock_msg,	unlockargs,	norep,		args,	void),
-  PROC(granted_msg,	testargs,	norep,		args,	void),
-  PROC(test_res,	testres,	norep,		res,	void),
-  PROC(lock_res,	lockres,	norep,		res,	void),
-  PROC(cancel_res,	cancelres,	norep,		res,	void),
-  PROC(unlock_res,	unlockres,	norep,		res,	void),
-  PROC(granted_res,	grantedres,	norep,		res,	void),
+  PROC(null,		void,		void,		void,	void, 1),
+  PROC(test,		testargs,	testres,	args,	res, Ck+St+2+No+Rg),
+  PROC(lock,		lockargs,	res,		args,	res, Ck+St),
+  PROC(cancel,		cancargs,	res,		args,	res, Ck+St),
+  PROC(unlock,		unlockargs,	res,		args,	res, Ck+St),
+  PROC(granted,		testargs,	res,		args,	res, Ck+St),
+  PROC(test_msg,	testargs,	norep,		args,	void, 1),
+  PROC(lock_msg,	lockargs,	norep,		args,	void, 1),
+  PROC(cancel_msg,	cancargs,	norep,		args,	void, 1),
+  PROC(unlock_msg,	unlockargs,	norep,		args,	void, 1),
+  PROC(granted_msg,	testargs,	norep,		args,	void, 1),
+  PROC(test_res,	testres,	norep,		res,	void, 1),
+  PROC(lock_res,	lockres,	norep,		res,	void, 1),
+  PROC(cancel_res,	cancelres,	norep,		res,	void, 1),
+  PROC(unlock_res,	unlockres,	norep,		res,	void, 1),
+  PROC(granted_res,	grantedres,	norep,		res,	void, 1),
   /* statd callback */
-  PROC(sm_notify,	reboot,		void,		reboot,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(share,		shareargs,	shareres,	args,	res),
-  PROC(unshare,		shareargs,	shareres,	args,	res),
-  PROC(nm_lock,		lockargs,	res,		args,	res),
-  PROC(free_all,	notify,		void,		args,	void),
+  PROC(sm_notify,	reboot,		void,		reboot,	void, 1),
+  PROC(none,		void,		void,		void,	void, 1),
+  PROC(none,		void,		void,		void,	void, 1),
+  PROC(none,		void,		void,		void,	void, 1),
+  PROC(share,		shareargs,	shareres,	args,	res, Ck+St+1),
+  PROC(unshare,		shareargs,	shareres,	args,	res, Ck+St+1),
+  PROC(nm_lock,		lockargs,	res,		args,	res, Ck+St),
+  PROC(free_all,	notify,		void,		args,	void, 0),
 
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/lockd/xdr.c linux-2.4.20/fs/lockd/xdr.c
--- linux-2.4.19/fs/lockd/xdr.c	2001-10-01 20:45:47.000000000 +0000
+++ linux-2.4.20/fs/lockd/xdr.c	2002-10-29 11:18:32.000000000 +0000
@@ -561,11 +561,10 @@
 #define nlmclt_decode_norep	NULL
 
 #define PROC(proc, argtype, restype)	\
-    { "nlm_" #proc,						\
-      (kxdrproc_t) nlmclt_encode_##argtype,			\
-      (kxdrproc_t) nlmclt_decode_##restype,			\
-      MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2,		\
-      0								\
+    { .p_procname  = "nlm_" #proc,					\
+      .p_encode    = (kxdrproc_t) nlmclt_encode_##argtype,		\
+      .p_decode    = (kxdrproc_t) nlmclt_decode_##restype,		\
+      .p_bufsiz    = MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2	\
     }
 
 static struct rpc_procinfo	nlm_procedures[] = {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/lockd/xdr4.c linux-2.4.20/fs/lockd/xdr4.c
--- linux-2.4.19/fs/lockd/xdr4.c	2001-10-01 20:45:47.000000000 +0000
+++ linux-2.4.20/fs/lockd/xdr4.c	2002-10-29 11:18:31.000000000 +0000
@@ -566,12 +566,11 @@
  */
 #define nlm4clt_decode_norep	NULL
 
-#define PROC(proc, argtype, restype)				\
-    { "nlm4_" #proc,						\
-      (kxdrproc_t) nlm4clt_encode_##argtype,			\
-      (kxdrproc_t) nlm4clt_decode_##restype,			\
-      MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2,	\
-      0								\
+#define PROC(proc, argtype, restype)					\
+    { .p_procname  = "nlm4_" #proc,					\
+      .p_encode    = (kxdrproc_t) nlm4clt_encode_##argtype,		\
+      .p_decode    = (kxdrproc_t) nlm4clt_decode_##restype,		\
+      .p_bufsiz    = MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2	\
     }
 
 static struct rpc_procinfo	nlm4_procedures[] = {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/locks.c linux-2.4.20/fs/locks.c
--- linux-2.4.19/fs/locks.c	2001-10-11 14:52:18.000000000 +0000
+++ linux-2.4.20/fs/locks.c	2002-10-29 11:18:38.000000000 +0000
@@ -121,6 +121,7 @@
 #include <linux/init.h>
 #include <linux/capability.h>
 #include <linux/sched.h>
+#include <linux/timer.h>
 
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
@@ -445,8 +446,7 @@
 			/* Let the blocked process remove waiter from the
 			 * block list when it gets scheduled.
 			 */
-			current->policy |= SCHED_YIELD;
-			schedule();
+			yield();
 		} else {
 			/* Remove waiter from the block list, because by the
 			 * time it wakes up blocker won't exist any more.
@@ -1051,6 +1051,47 @@
 	return -EINVAL;
 }
 
+/* We already had a lease on this file; just change its type */
+static int lease_modify(struct file_lock **before, int arg)
+{
+	struct file_lock *fl = *before;
+	int error = assign_type(fl, arg);
+
+	if (error)
+		return error;
+	locks_wake_up_blocks(fl, 0);
+	if (arg == F_UNLCK) {
+		struct file *filp = fl->fl_file;
+
+		filp->f_owner.pid = 0;
+		filp->f_owner.uid = 0;
+		filp->f_owner.euid = 0;
+		filp->f_owner.signum = 0;
+		locks_delete_lock(before, 0);
+	}
+	return 0;
+}
+
+static void time_out_leases(struct inode *inode)
+{
+	struct file_lock **before;
+	struct file_lock *fl;
+
+	before = &inode->i_flock;
+	while ((fl = *before) && (fl->fl_flags & FL_LEASE)
+			&& (fl->fl_type & F_INPROGRESS)) {
+		if ((fl->fl_break_time == 0)
+				|| time_before(jiffies, fl->fl_break_time)) {
+			before = &fl->fl_next;
+			continue;
+		}
+		printk(KERN_INFO "lease broken - owner pid = %d\n", fl->fl_pid);
+		lease_modify(before, fl->fl_type & ~F_INPROGRESS);
+		if (fl == *before)	/* lease_modify may have freed fl */
+			before = &fl->fl_next;
+	}
+}
+
 /**
  *	__get_lease	-	revoke all outstanding leases on file
  *	@inode: the inode of the file to return
@@ -1067,34 +1108,30 @@
 	struct file_lock *new_fl, *flock;
 	struct file_lock *fl;
 	int alloc_err;
+	unsigned long break_time;
+	int i_have_this_lease = 0;
 
-	alloc_err = lease_alloc(NULL, 0, &new_fl);
+	alloc_err = lease_alloc(NULL, mode & FMODE_WRITE ? F_WRLCK : F_RDLCK,
+			&new_fl);
 
 	lock_kernel();
+
+	time_out_leases(inode);
+
 	flock = inode->i_flock;
-	if (flock->fl_type & F_INPROGRESS) {
-		if ((mode & O_NONBLOCK)
-		    || (flock->fl_owner == current->files)) {
-			error = -EWOULDBLOCK;
-			goto out;
-		}
-		if (alloc_err != 0) {
-			error = alloc_err;
-			goto out;
-		}
-		do {
-			error = locks_block_on(flock, new_fl);
-			if (error != 0)
-				goto out;
-			flock = inode->i_flock;
-			if (!(flock && (flock->fl_flags & FL_LEASE)))
-				goto out;
-		} while (flock->fl_type & F_INPROGRESS);
-	}
+	if ((flock == NULL) || (flock->fl_flags & FL_LEASE) == 0)
+		goto out;
+
+	for (fl = flock; fl && (fl->fl_flags & FL_LEASE); fl = fl->fl_next)
+		if (fl->fl_owner == current->files)
+			i_have_this_lease = 1;
 
 	if (mode & FMODE_WRITE) {
 		/* If we want write access, we have to revoke any lease. */
 		future = F_UNLCK | F_INPROGRESS;
+	} else if (flock->fl_type & F_INPROGRESS) {
+		/* If the lease is already being broken, we just leave it */
+		future = flock->fl_type;
 	} else if (flock->fl_type & F_WRLCK) {
 		/* Downgrade the exclusive lease to a read-only lease. */
 		future = F_RDLCK | F_INPROGRESS;
@@ -1103,38 +1140,49 @@
 		goto out;
 	}
 
-	if (alloc_err && (flock->fl_owner != current->files)) {
+	if (alloc_err && !i_have_this_lease && ((mode & O_NONBLOCK) == 0)) {
 		error = alloc_err;
 		goto out;
 	}
 
-	fl = flock;
-	do {
-		fl->fl_type = future;
-		fl = fl->fl_next;
-	} while (fl != NULL && (fl->fl_flags & FL_LEASE));
+	break_time = 0;
+	if (lease_break_time > 0) {
+		break_time = jiffies + lease_break_time * HZ;
+		if (break_time == 0)
+			break_time++;	/* so that 0 means no break time */
+	}
 
-	kill_fasync(&flock->fl_fasync, SIGIO, POLL_MSG);
+	for (fl = flock; fl && (fl->fl_flags & FL_LEASE); fl = fl->fl_next) {
+		if (fl->fl_type != future) {
+			fl->fl_type = future;
+			fl->fl_break_time = break_time;
+			kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG);
+		}
+	}
 
-	if ((mode & O_NONBLOCK) || (flock->fl_owner == current->files)) {
+	if (i_have_this_lease || (mode & O_NONBLOCK)) {
 		error = -EWOULDBLOCK;
 		goto out;
 	}
 
-	if (lease_break_time > 0)
-		error = lease_break_time * HZ;
-	else
-		error = 0;
 restart:
-	error = locks_block_on_timeout(flock, new_fl, error);
-	if (error == 0) {
-		/* We timed out.  Unilaterally break the lease. */
-		locks_delete_lock(&inode->i_flock, 0);
-		printk(KERN_WARNING "lease timed out\n");
-	} else if (error > 0) {
-		flock = inode->i_flock;
-		if (flock && (flock->fl_flags & FL_LEASE))
-			goto restart;
+	break_time = flock->fl_break_time;
+	if (break_time != 0) {
+		break_time -= jiffies;
+		if (break_time == 0)
+			break_time++;
+	}
+	error = locks_block_on_timeout(flock, new_fl, break_time);
+	if (error >= 0) {
+		if (error == 0)
+			time_out_leases(inode);
+		/* Wait for the next lease that has not been broken yet */
+		for (flock = inode->i_flock;
+				flock && (flock->fl_flags & FL_LEASE);
+				flock = flock->fl_next) {
+			if (flock->fl_type & F_INPROGRESS)
+				goto restart;
+		}
 		error = 0;
 	}
 
@@ -1166,45 +1214,41 @@
  *	@filp: the file
  *
  *	The value returned by this function will be one of
+ *	(if no lease break is pending):
  *
- *	%F_RDLCK to indicate a read-only (type II) lease is held.
+ *	%F_RDLCK to indicate a shared lease is held.
  *
  *	%F_WRLCK to indicate an exclusive lease is held.
  *
- *	XXX: sfr & i disagree over whether F_INPROGRESS
+ *	%F_UNLCK to indicate no lease is held.
+ *
+ *	(if a lease break is pending):
+ *
+ *	%F_RDLCK to indicate an exclusive lease needs to be
+ *		changed to a shared lease (or removed).
+ *
+ *	%F_UNLCK to indicate the lease needs to be removed.
+ *
+ *	XXX: sfr & willy disagree over whether F_INPROGRESS
  *	should be returned to userspace.
  */
 int fcntl_getlease(struct file *filp)
 {
 	struct file_lock *fl;
-	
-	fl = filp->f_dentry->d_inode->i_flock;
-	if ((fl == NULL) || ((fl->fl_flags & FL_LEASE) == 0))
-		return F_UNLCK;
-	return fl->fl_type & ~F_INPROGRESS;
-}
+	int type = F_UNLCK;
 
-/* We already had a lease on this file; just change its type */
-static int lease_modify(struct file_lock **before, int arg, int fd, struct file *filp)
-{
-	struct file_lock *fl = *before;
-	int error = assign_type(fl, arg);
-	if (error < 0)
-		goto out;
-
-	locks_wake_up_blocks(fl, 0);
-
-	if (arg == F_UNLCK) {
-		filp->f_owner.pid = 0;
-		filp->f_owner.uid = 0;
-		filp->f_owner.euid = 0;
-		filp->f_owner.signum = 0;
-		locks_delete_lock(before, 0);
-		fasync_helper(fd, filp, 0, &fl->fl_fasync);
+	lock_kernel();
+	time_out_leases(filp->f_dentry->d_inode);
+	for (fl = filp->f_dentry->d_inode->i_flock;
+			fl && (fl->fl_flags & FL_LEASE);
+			fl = fl->fl_next) {
+		if (fl->fl_file == filp) {
+			type = fl->fl_type & ~F_INPROGRESS;
+			break;
+		}
 	}
-
-out:
-	return error;
+	unlock_kernel();
+	return type;
 }
 
 /**
@@ -1232,50 +1276,59 @@
 	if (!S_ISREG(inode->i_mode))
 		return -EINVAL;
 
+	lock_kernel();
+
+	time_out_leases(inode);
+
 	/*
 	 * FIXME: What about F_RDLCK and files open for writing?
 	 */
+	error = -EAGAIN;
 	if ((arg == F_WRLCK)
 	    && ((atomic_read(&dentry->d_count) > 1)
 		|| (atomic_read(&inode->i_count) > 1)))
-		return -EAGAIN;
-
-	before = &inode->i_flock;
-
-	lock_kernel();
+		goto out_unlock;
 
-	while ((fl = *before) != NULL) {
-		if (fl->fl_flags != FL_LEASE)
-			break;
+	/*
+	 * At this point, we know that if there is an exclusive
+	 * lease on this file, then we hold it on this filp
+	 * (otherwise our open of this file would have blocked).
+	 * And if we are trying to acquire an exclusive lease,
+	 * then the file is not open by anyone (including us)
+	 * except for this filp.
+	 */
+	for (before = &inode->i_flock;
+			((fl = *before) != NULL) && (fl->fl_flags & FL_LEASE);
+			before = &fl->fl_next) {
 		if (fl->fl_file == filp)
 			my_before = before;
-		else if (fl->fl_type & F_WRLCK)
+		else if (fl->fl_type == (F_INPROGRESS | F_UNLCK))
+			/*
+			 * Someone is in the process of opening this
+			 * file for writing so we may not take an
+			 * exclusive lease on it.
+			 */
 			wrlease_count++;
 		else
 			rdlease_count++;
-		before = &fl->fl_next;
 	}
 
 	if ((arg == F_RDLCK && (wrlease_count > 0)) ||
-	    (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0))) {
-		error = -EAGAIN;
+	    (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0)))
 		goto out_unlock;
-	}
 
 	if (my_before != NULL) {
-		error = lease_modify(my_before, arg, fd, filp);
+		error = lease_modify(my_before, arg);
 		goto out_unlock;
 	}
 
-	if (arg == F_UNLCK) {
-		error = 0;
+	error = 0;
+	if (arg == F_UNLCK)
 		goto out_unlock;
-	}
 
-	if (!leases_enable) {
-		error = -EINVAL;
+	error = -EINVAL;
+	if (!leases_enable)
 		goto out_unlock;
-	}
 
 	error = lease_alloc(filp, arg, &fl);
 	if (error)
@@ -1710,10 +1763,15 @@
 	before = &inode->i_flock;
 
 	while ((fl = *before) != NULL) {
-		if ((fl->fl_flags & (FL_FLOCK|FL_LEASE))
-		    && (fl->fl_file == filp)) {
-			locks_delete_lock(before, 0);
-			continue;
+		if (fl->fl_file == filp) {
+			if (fl->fl_flags & FL_FLOCK) {
+				locks_delete_lock(before, 0);
+				continue;
+			}
+			if (fl->fl_flags & FL_LEASE) {
+				lease_modify(before, F_UNLCK);
+				continue;
+			}
  		}
 		before = &fl->fl_next;
 	}
@@ -1769,7 +1827,13 @@
 #endif
 			out += sprintf(out, "FLOCK  ADVISORY  ");
 	} else if (fl->fl_flags & FL_LEASE) {
-		out += sprintf(out, "LEASE  MANDATORY ");
+		out += sprintf(out, "LEASE  ");
+		if (fl->fl_type & F_INPROGRESS)
+			out += sprintf(out, "BREAKING  ");
+		else if (fl->fl_file)
+			out += sprintf(out, "ACTIVE    ");
+		else
+			out += sprintf(out, "BREAKER   ");
 	} else {
 		out += sprintf(out, "UNKNOWN UNKNOWN  ");
 	}
@@ -1782,7 +1846,9 @@
 	} else
 #endif
 		out += sprintf(out, "%s ",
-			       (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
+			       (fl->fl_type & F_INPROGRESS)
+			       ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ "
+			       : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
 	out += sprintf(out, "%d %s:%ld ",
 		     fl->fl_pid,
 		     inode ? kdevname(inode->i_dev) : "<none>",
@@ -1940,7 +2006,7 @@
 
 static int __init filelock_init(void)
 {
-	filelock_cache = kmem_cache_create("file lock cache",
+	filelock_cache = kmem_cache_create("file_lock_cache",
 			sizeof(struct file_lock), 0, 0, init_once, NULL);
 	if (!filelock_cache)
 		panic("cannot create file lock slab cache");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/namei.c linux-2.4.20/fs/namei.c
--- linux-2.4.19/fs/namei.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/namei.c	2002-10-29 11:18:36.000000000 +0000
@@ -739,6 +739,16 @@
 }
 
 /* SMP-safe */
+int path_lookup(const char *path, unsigned flags, struct nameidata *nd)
+{
+	int error = 0;
+	if (path_init(path, flags, nd))
+		error = path_walk(path, nd);
+	return error;
+}
+
+
+/* SMP-safe */
 int path_init(const char *name, unsigned int flags, struct nameidata *nd)
 {
 	nd->last_type = LAST_ROOT; /* if there are only slashes... */
@@ -844,8 +854,7 @@
 	err = PTR_ERR(tmp);
 	if (!IS_ERR(tmp)) {
 		err = 0;
-		if (path_init(tmp, flags, nd))
-			err = path_walk(tmp, nd);
+		err = path_lookup(tmp, flags, nd);
 		putname(tmp);
 	}
 	return err;
@@ -1001,8 +1010,7 @@
 	 * The simplest case - just a plain lookup.
 	 */
 	if (!(flag & O_CREAT)) {
-		if (path_init(pathname, lookup_flags(flag), nd))
-			error = path_walk(pathname, nd);
+		error = path_lookup(pathname, lookup_flags(flag), nd);
 		if (error)
 			return error;
 		dentry = nd->dentry;
@@ -1012,8 +1020,7 @@
 	/*
 	 * Create - we need to know the parent.
 	 */
-	if (path_init(pathname, LOOKUP_PARENT, nd))
-		error = path_walk(pathname, nd);
+	error = path_lookup(pathname, LOOKUP_PARENT, nd);
 	if (error)
 		return error;
 
@@ -1265,8 +1272,7 @@
 	if (IS_ERR(tmp))
 		return PTR_ERR(tmp);
 
-	if (path_init(tmp, LOOKUP_PARENT, &nd))
-		error = path_walk(tmp, &nd);
+	error = path_lookup(tmp, LOOKUP_PARENT, &nd);
 	if (error)
 		goto out;
 	dentry = lookup_create(&nd, 0);
@@ -1334,8 +1340,7 @@
 		struct dentry *dentry;
 		struct nameidata nd;
 
-		if (path_init(tmp, LOOKUP_PARENT, &nd))
-			error = path_walk(tmp, &nd);
+		error = path_lookup(tmp, LOOKUP_PARENT, &nd);
 		if (error)
 			goto out;
 		dentry = lookup_create(&nd, 1);
@@ -1431,8 +1436,7 @@
 	if(IS_ERR(name))
 		return PTR_ERR(name);
 
-	if (path_init(name, LOOKUP_PARENT, &nd))
-		error = path_walk(name, &nd);
+	error = path_lookup(name, LOOKUP_PARENT, &nd);
 	if (error)
 		goto exit;
 
@@ -1500,8 +1504,7 @@
 	if(IS_ERR(name))
 		return PTR_ERR(name);
 
-	if (path_init(name, LOOKUP_PARENT, &nd))
-		error = path_walk(name, &nd);
+	error = path_lookup(name, LOOKUP_PARENT, &nd);
 	if (error)
 		goto exit;
 	error = -EISDIR;
@@ -1572,8 +1575,7 @@
 		struct dentry *dentry;
 		struct nameidata nd;
 
-		if (path_init(to, LOOKUP_PARENT, &nd))
-			error = path_walk(to, &nd);
+		error = path_lookup(to, LOOKUP_PARENT, &nd);
 		if (error)
 			goto out;
 		dentry = lookup_create(&nd, 0);
@@ -1643,25 +1645,18 @@
 asmlinkage long sys_link(const char * oldname, const char * newname)
 {
 	int error;
-	char * from;
 	char * to;
 
-	from = getname(oldname);
-	if(IS_ERR(from))
-		return PTR_ERR(from);
 	to = getname(newname);
 	error = PTR_ERR(to);
 	if (!IS_ERR(to)) {
 		struct dentry *new_dentry;
 		struct nameidata nd, old_nd;
 
-		error = 0;
-		if (path_init(from, LOOKUP_POSITIVE, &old_nd))
-			error = path_walk(from, &old_nd);
+		error = __user_walk(oldname, LOOKUP_POSITIVE, &old_nd);
 		if (error)
 			goto exit;
-		if (path_init(to, LOOKUP_PARENT, &nd))
-			error = path_walk(to, &nd);
+		error = path_lookup(to, LOOKUP_PARENT, &nd);
 		if (error)
 			goto out;
 		error = -EXDEV;
@@ -1681,8 +1676,6 @@
 exit:
 		putname(to);
 	}
-	putname(from);
-
 	return error;
 }
 
@@ -1859,14 +1852,11 @@
 	struct dentry * old_dentry, *new_dentry;
 	struct nameidata oldnd, newnd;
 
-	if (path_init(oldname, LOOKUP_PARENT, &oldnd))
-		error = path_walk(oldname, &oldnd);
-
+	error = path_lookup(oldname, LOOKUP_PARENT, &oldnd);
 	if (error)
 		goto exit;
 
-	if (path_init(newname, LOOKUP_PARENT, &newnd))
-		error = path_walk(newname, &newnd);
+	error = path_lookup(newname, LOOKUP_PARENT, &newnd);
 	if (error)
 		goto exit1;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/namespace.c linux-2.4.20/fs/namespace.c
--- linux-2.4.19/fs/namespace.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/namespace.c	2002-10-29 11:18:49.000000000 +0000
@@ -29,6 +29,8 @@
 static int hash_mask, hash_bits;
 static kmem_cache_t *mnt_cache; 
 
+extern void init_rootfs(void);
+
 static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
 {
 	unsigned long tmp = ((unsigned long) mnt / L1_CACHE_BYTES);
@@ -359,17 +361,9 @@
 asmlinkage long sys_umount(char * name, int flags)
 {
 	struct nameidata nd;
-	char *kname;
 	int retval;
 
-	kname = getname(name);
-	retval = PTR_ERR(kname);
-	if (IS_ERR(kname))
-		goto out;
-	retval = 0;
-	if (path_init(kname, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd))
-		retval = path_walk(kname, &nd);
-	putname(kname);
+	retval = __user_walk(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd);
 	if (retval)
 		goto out;
 	retval = -EINVAL;
@@ -496,8 +490,7 @@
 		return err;
 	if (!old_name || !*old_name)
 		return -EINVAL;
-	if (path_init(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd))
-		err = path_walk(old_name, &old_nd);
+	err = path_lookup(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd);
 	if (err)
 		return err;
 
@@ -563,8 +556,7 @@
 		return -EPERM;
 	if (!old_name || !*old_name)
 		return -EINVAL;
-	if (path_init(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd))
-		err = path_walk(old_name, &old_nd);
+	err = path_lookup(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd);
 	if (err)
 		return err;
 
@@ -730,8 +722,7 @@
 	flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV);
 
 	/* ... and get the mountpoint */
-	if (path_init(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
-		retval = path_walk(dir_name, &nd);
+	retval = path_lookup(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd);
 	if (retval)
 		return retval;
 
@@ -910,7 +901,6 @@
 {
 	struct vfsmount *tmp;
 	struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd;
-	char *name;
 	int error;
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -918,28 +908,14 @@
 
 	lock_kernel();
 
-	name = getname(new_root);
-	error = PTR_ERR(name);
-	if (IS_ERR(name))
-		goto out0;
-	error = 0;
-	if (path_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd))
-		error = path_walk(name, &new_nd);
-	putname(name);
+	error = __user_walk(new_root, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd);
 	if (error)
 		goto out0;
 	error = -EINVAL;
 	if (!check_mnt(new_nd.mnt))
 		goto out1;
 
-	name = getname(put_old);
-	error = PTR_ERR(name);
-	if (IS_ERR(name))
-		goto out1;
-	error = 0;
-	if (path_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd))
-		error = path_walk(name, &old_nd);
-	putname(name);
+	error = __user_walk(put_old, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd);
 	if (error)
 		goto out1;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/ncpfs/dir.c linux-2.4.20/fs/ncpfs/dir.c
--- linux-2.4.19/fs/ncpfs/dir.c	2001-03-08 00:53:48.000000000 +0000
+++ linux-2.4.20/fs/ncpfs/dir.c	2002-10-29 11:18:31.000000000 +0000
@@ -74,7 +74,7 @@
 static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
 static int ncp_delete_dentry(struct dentry *);
 
-struct dentry_operations ncp_dentry_operations =
+static struct dentry_operations ncp_dentry_operations =
 {
 	d_revalidate:	ncp_lookup_validate,
 	d_hash:		ncp_hash_dentry,
@@ -82,6 +82,13 @@
 	d_delete:	ncp_delete_dentry,
 };
 
+struct dentry_operations ncp_root_dentry_operations =
+{
+	d_hash:		ncp_hash_dentry,
+	d_compare:	ncp_compare_dentry,
+	d_delete:	ncp_delete_dentry,
+};
+
 
 /*
  * Note: leave the hash unchanged if the directory
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/ncpfs/inode.c linux-2.4.20/fs/ncpfs/inode.c
--- linux-2.4.19/fs/ncpfs/inode.c	2001-09-30 19:26:08.000000000 +0000
+++ linux-2.4.20/fs/ncpfs/inode.c	2002-10-29 11:18:48.000000000 +0000
@@ -44,7 +44,7 @@
 	statfs:		ncp_statfs,
 };
 
-extern struct dentry_operations ncp_dentry_operations;
+extern struct dentry_operations ncp_root_dentry_operations;
 #ifdef CONFIG_NCPFS_EXTRAS
 extern struct address_space_operations ncp_symlink_aops;
 extern int ncp_symlink(struct inode*, struct dentry*, const char*);
@@ -443,7 +443,7 @@
 	sb->s_root = d_alloc_root(root_inode);
         if (!sb->s_root)
 		goto out_no_root;
-	sb->s_root->d_op = &ncp_dentry_operations;
+	sb->s_root->d_op = &ncp_root_dentry_operations;
 	return sb;
 
 out_no_root:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/ncpfs/ioctl.c linux-2.4.20/fs/ncpfs/ioctl.c
--- linux-2.4.19/fs/ncpfs/ioctl.c	2001-09-10 14:31:30.000000000 +0000
+++ linux-2.4.20/fs/ncpfs/ioctl.c	2002-10-29 11:18:31.000000000 +0000
@@ -418,7 +418,7 @@
 			if (user.object_name_len) {
 				newname = ncp_kmalloc(user.object_name_len, GFP_USER);
 				if (!newname) return -ENOMEM;
-				if (copy_from_user(newname, user.object_name, sizeof(user))) {
+				if (copy_from_user(newname, user.object_name, user.object_name_len)) {
 					ncp_kfree_s(newname, user.object_name_len);
 					return -EFAULT;
 				}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/ncpfs/ncplib_kernel.c linux-2.4.20/fs/ncpfs/ncplib_kernel.c
--- linux-2.4.19/fs/ncpfs/ncplib_kernel.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/fs/ncpfs/ncplib_kernel.c	2002-10-29 11:18:40.000000000 +0000
@@ -258,6 +258,7 @@
 	target->nameLen = *name_len;
 	memcpy(target->entryName, name_len + 1, *name_len);
 	target->entryName[*name_len] = '\0';
+	target->volNumber = le32_to_cpu(target->volNumber);
 	return;
 }
 
@@ -338,7 +339,7 @@
 	}
 
 	result = NW_NS_DOS;
-	no_namespaces = ncp_reply_word(server, 0);
+	no_namespaces = le16_to_cpu(ncp_reply_word(server, 0));
 	namespace = ncp_reply_data(server, 2);
 
 	while (no_namespaces > 0) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfs/dir.c linux-2.4.20/fs/nfs/dir.c
--- linux-2.4.19/fs/nfs/dir.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/nfs/dir.c	2002-10-29 11:18:40.000000000 +0000
@@ -45,12 +45,14 @@
 static int nfs_mknod(struct inode *, struct dentry *, int, int);
 static int nfs_rename(struct inode *, struct dentry *,
 		      struct inode *, struct dentry *);
+static int nfs_fsync_dir(struct file *, struct dentry *, int);
 
 struct file_operations nfs_dir_operations = {
 	read:		generic_read_dir,
 	readdir:	nfs_readdir,
 	open:		nfs_open,
 	release:	nfs_release,
+	fsync:		nfs_fsync_dir
 };
 
 struct inode_operations nfs_dir_inode_operations = {
@@ -99,13 +101,12 @@
 	struct file	*file = desc->file;
 	struct inode	*inode = file->f_dentry->d_inode;
 	struct rpc_cred	*cred = nfs_file_cred(file);
-	void		*buffer = kmap(page);
 	int		error;
 
 	dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index);
 
  again:
-	error = NFS_PROTO(inode)->readdir(inode, cred, desc->entry->cookie, buffer,
+	error = NFS_PROTO(inode)->readdir(inode, cred, desc->entry->cookie, page,
 					  NFS_SERVER(inode)->dtsize, desc->plus);
 	/* We requested READDIRPLUS, but the server doesn't grok it */
 	if (desc->plus && error == -ENOTSUPP) {
@@ -116,7 +117,6 @@
 	if (error < 0)
 		goto error;
 	SetPageUptodate(page);
-	kunmap(page);
 	/* Ensure consistent page alignment of the data.
 	 * Note: assumes we have exclusive access to this mapping either
 	 *	 throught inode->i_sem or some other mechanism.
@@ -127,7 +127,6 @@
 	return 0;
  error:
 	SetPageError(page);
-	kunmap(page);
 	UnlockPage(page);
 	invalidate_inode_pages(inode);
 	desc->error = error;
@@ -315,12 +314,12 @@
 		status = -ENOMEM;
 		goto out;
 	}
-	desc->page = page;
-	desc->ptr = kmap(page);
 	desc->error = NFS_PROTO(inode)->readdir(inode, cred, desc->target,
-						desc->ptr,
+						page,
 						NFS_SERVER(inode)->dtsize,
 						desc->plus);
+	desc->page = page;
+	desc->ptr = kmap(page);
 	if (desc->error >= 0) {
 		if ((status = dir_decode(desc)) == 0)
 			desc->entry->prev_cookie = desc->target;
@@ -402,6 +401,15 @@
 }
 
 /*
+ * All directory operations under NFS are synchronous, so fsync()
+ * is a dummy operation.
+ */
+int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync)
+{
+	return 0;
+}
+
+/*
  * A check for whether or not the parent directory has changed.
  * In the case it has, we assume that the dentries are untrustworthy
  * and may need to be looked up again.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfs/flushd.c linux-2.4.20/fs/nfs/flushd.c
--- linux-2.4.19/fs/nfs/flushd.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/nfs/flushd.c	2002-10-29 11:18:49.000000000 +0000
@@ -50,7 +50,7 @@
 /*
  * This is the wait queue all cluster daemons sleep on
  */
-static struct rpc_wait_queue    flushd_queue = RPC_INIT_WAITQ("nfs_flushd");
+static RPC_WAITQ(flushd_queue, "nfs_flushd");
 
 /*
  * Local function declarations.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfs/inode.c linux-2.4.20/fs/nfs/inode.c
--- linux-2.4.19/fs/nfs/inode.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/nfs/inode.c	2002-10-29 11:18:34.000000000 +0000
@@ -472,7 +472,8 @@
 		goto failure_kill_reqlist;
 	}
 
-	/* We're airborne */
+	/* We're airborne Set socket buffersize */
+	rpc_setbufsize(clnt, server->wsize + 100, server->rsize + 100);
 
 	/* Check whether to start the lockd process */
 	if (!(server->flags & NFS_MOUNT_NONLM))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfs/mount_clnt.c linux-2.4.20/fs/nfs/mount_clnt.c
--- linux-2.4.19/fs/nfs/mount_clnt.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/nfs/mount_clnt.c	2002-10-29 11:18:32.000000000 +0000
@@ -29,10 +29,9 @@
 #define MOUNT_UMNT		3
  */
 
-static int			nfs_gen_mount(struct sockaddr_in *,
-					      char *, struct nfs_fh *, int);
-static struct rpc_clnt *	mnt_create(char *, struct sockaddr_in *, int);
-extern struct rpc_program	mnt_program;
+static struct rpc_clnt *	mnt_create(char *, struct sockaddr_in *,
+								int, int);
+struct rpc_program      mnt_program;
 
 struct mnt_fhstatus {
 	unsigned int		status;
@@ -43,19 +42,8 @@
  * Obtain an NFS file handle for the given host and path
  */
 int
-nfs_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
-{
-	return nfs_gen_mount(addr, path, fh, NFS_MNT_VERSION);
-}
-
-int
-nfs3_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
-{
-	return nfs_gen_mount(addr, path, fh, NFS_MNT3_VERSION);
-}
-
-static int
-nfs_gen_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, int version)
+nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh,
+		int version, int protocol)
 {
 	struct rpc_clnt		*mnt_clnt;
 	struct mnt_fhstatus	result = { 0, fh };
@@ -67,21 +55,22 @@
 			(unsigned)ntohl(addr->sin_addr.s_addr), path);
 
 	sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr->sin_addr.s_addr));
-	if (!(mnt_clnt = mnt_create(hostname, addr, version)))
+	if (!(mnt_clnt = mnt_create(hostname, addr, version, protocol)))
 		return -EACCES;
 
-	call = (version == 3) ? MOUNTPROC3_MNT : MNTPROC_MNT;
+	call = (version == NFS_MNT3_VERSION)?  MOUNTPROC3_MNT : MNTPROC_MNT;
 	status = rpc_call(mnt_clnt, call, path, &result, 0);
 	return status < 0? status : (result.status? -EACCES : 0);
 }
 
 static struct rpc_clnt *
-mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version)
+mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version,
+		int protocol)
 {
 	struct rpc_xprt	*xprt;
 	struct rpc_clnt	*clnt;
 
-	if (!(xprt = xprt_create_proto(IPPROTO_UDP, srvaddr, NULL)))
+	if (!(xprt = xprt_create_proto(protocol, srvaddr, NULL)))
 		return NULL;
 
 	clnt = rpc_create_client(xprt, hostname,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfs/nfs2xdr.c linux-2.4.20/fs/nfs/nfs2xdr.c
--- linux-2.4.19/fs/nfs/nfs2xdr.c	2002-02-25 19:38:09.000000000 +0000
+++ linux-2.4.20/fs/nfs/nfs2xdr.c	2002-10-29 11:18:37.000000000 +0000
@@ -24,9 +24,6 @@
 #include <linux/nfs2.h>
 #include <linux/nfs_fs.h>
 
-/* Uncomment this to support servers requiring longword lengths */
-#define NFS_PAD_WRITES 1
-
 #define NFSDBG_FACILITY		NFSDBG_XDR
 /* #define NFS_PARANOIA 1 */
 
@@ -90,17 +87,6 @@
 	return p + XDR_QUADLEN(NFS2_FHSIZE);
 }
 
-static inline u32 *
-xdr_decode_string2(u32 *p, char **string, unsigned int *len,
-			unsigned int maxlen)
-{
-	*len = ntohl(*p++);
-	if (*len > maxlen)
-		return NULL;
-	*string = (char *) p;
-	return p + XDR_QUADLEN(*len);
-}
-
 static inline u32*
 xdr_decode_time(u32 *p, u64 *timep)
 {
@@ -109,7 +95,7 @@
 	return p;
 }
 
-static inline u32 *
+static u32 *
 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
 {
 	fattr->type = (enum nfs_ftype) ntohl(*p++);
@@ -223,35 +209,20 @@
 nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
-	int		buflen, replen;
-	unsigned int	nr;
+	unsigned int replen;
+	u32 offset = (u32)args->offset;
+	u32 count = args->count;
 
 	p = xdr_encode_fhandle(p, args->fh);
-	*p++ = htonl(args->offset);
-	*p++ = htonl(args->count);
-	*p++ = htonl(args->count);
+	*p++ = htonl(offset);
+	*p++ = htonl(count);
+	*p++ = htonl(count);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-	/* Get the number of buffers in the receive iovec */
-        nr = args->nriov;
-
-        if (nr+2 > MAX_IOVEC) {
-                printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargs\n");
-                return -EINVAL;
-        }
-
-	/* set up reply iovec */
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-        /* Copy the iovec */
-        memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
-
-	req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[nr+1].iov_len  = buflen - replen;
-	req->rq_rlen = args->count + buflen;
-	req->rq_rnr += nr+1;
-
+	xdr_inline_pages(&req->rq_rcv_buf, replen,
+			 args->pages, args->pgbase, count);
 	return 0;
 }
 
@@ -272,7 +243,7 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READ header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
 	}
 
 	recvd = req->rq_rlen - hdrlen;
@@ -284,7 +255,6 @@
 
 	dprintk("RPC:      readres OK count %d\n", count);
 	if (count < res->count) {
-		xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
 		res->count = count;
 		res->eof = 1;  /* Silly NFSv3ism which can't be helped */
 	} else
@@ -300,46 +270,19 @@
 static int
 nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
 {
-	unsigned int nr;
+	struct xdr_buf *sndbuf = &req->rq_snd_buf;
+	u32 offset = (u32)args->offset;
 	u32 count = args->count;
 
 	p = xdr_encode_fhandle(p, args->fh);
-	*p++ = htonl(args->offset);
-	*p++ = htonl(args->offset);
+	*p++ = htonl(offset);
+	*p++ = htonl(offset);
 	*p++ = htonl(count);
 	*p++ = htonl(count);
-	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
-
-	/* Get the number of buffers in the send iovec */
-	nr = args->nriov;
-
-	if (nr+2 > MAX_IOVEC) {
-                printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs "
-                        "(nr %d max %d)\n", nr, MAX_IOVEC);
-                return -EINVAL;
-        }
-
-	/* Copy the iovec */
-        memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
-
-#ifdef NFS_PAD_WRITES
-	/*
-	 * Some old servers require that the message length
-	 * be a multiple of 4, so we pad it here if needed.
-	 */
-	if (count & 3) {
-		struct iovec	*iov = req->rq_svec + nr + 1;
-		int		pad = 4 - (count & 3);
-
-		iov->iov_base = (void *) "\0\0\0";
-		iov->iov_len  = pad;
-		count += pad;
-		nr++;
-	}
-#endif
-	req->rq_slen += count;
-	req->rq_snr += nr;
+	sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
 
+	/* Copy the page array */
+	xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
 	return 0;
 }
 
@@ -406,32 +349,24 @@
 {
 	struct rpc_task	*task = req->rq_task;
 	struct rpc_auth	*auth = task->tk_auth;
-	u32		bufsiz = args->bufsiz;
-	int		buflen, replen;
+	unsigned int replen;
+	u32 count = args->count;
 
 	/*
 	 * Some servers (e.g. HP OS 9.5) seem to expect the buffer size
 	 * to be in longwords ... check whether to convert the size.
 	 */
 	if (task->tk_client->cl_flags & NFS_CLNTF_BUFSIZE)
-		bufsiz = bufsiz >> 2;
+		count = count >> 2;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	*p++ = htonl(args->cookie);
-	*p++ = htonl(bufsiz); /* see above */
+	*p++ = htonl(count); /* see above */
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-	/* set up reply iovec */
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = args->bufsiz;
-	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[2].iov_len  = buflen - replen;
-	req->rq_rlen = buflen + args->bufsiz;
-	req->rq_rnr += 2;
-
+	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
 	return 0;
 }
 
@@ -443,12 +378,15 @@
  * from nfs_readdir for each entry.
  */
 static int
-nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
+nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
 {
-	struct iovec		*iov = req->rq_rvec;
-	int			 hdrlen;
-	int			 status, nr;
-	u32			*end, *entry, len;
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+	struct iovec *iov = rcvbuf->head;
+	struct page **page;
+	int hdrlen;
+	int status, nr;
+	unsigned int len, pglen;
+	u32 *end, *entry;
 
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
@@ -456,13 +394,13 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 	}
 
-
-	/* Get start and end address of XDR data */
-	p   = (u32 *) iov[1].iov_base;
-	end = (u32 *) ((u8 *) p + iov[1].iov_len);
+	pglen = rcvbuf->page_len;
+	page = rcvbuf->pages;
+	p = kmap(*page);
+	end = (u32 *)((char *)p + pglen);
 	for (nr = 0; *p++; nr++) {
 		entry = p - 1;
 		if (p + 2 > end)
@@ -473,16 +411,21 @@
 		if (len > NFS2_MAXNAMLEN) {
 			printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
 						len);
-			return -errno_NFSERR_IO;
+			goto err_unmap;
 		}
 		if (p + 2 > end)
 			goto short_pkt;
 	}
+	kunmap(*page);
 	return nr;
  short_pkt:
 	printk(KERN_NOTICE "NFS: short packet in readdir reply!\n");
 	entry[0] = entry[1] = 0;
+	kunmap(*page);
 	return nr;
+err_unmap:
+	kunmap(*page);
+	return -errno_NFSERR_IO;
 }
 
 u32 *
@@ -568,21 +511,16 @@
 static int
 nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
 {
-	struct rpc_task *task = req->rq_task;
-	struct rpc_auth *auth = task->tk_auth;
-	int		buflen, replen;
+	struct rpc_auth *auth = req->rq_task->tk_auth;
+	unsigned int replen;
+	u32 count = args->count - 4;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = args->bufsiz;
-	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[2].iov_len  = buflen - replen;
-	req->rq_rlen = buflen + args->bufsiz;
-	req->rq_rnr += 2;
+	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
 	return 0;
 }
 
@@ -590,32 +528,33 @@
  * Decode READLINK reply
  */
 static int
-nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_readlinkres *res)
+nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
 {
-	struct iovec *iov = req->rq_rvec;
-	u32	*strlen;
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+	struct iovec *iov = rcvbuf->head;
+	unsigned int hdrlen;
+	u32	*strlen, len;
 	char	*string;
-	int	hdrlen;
 	int	status;
-	unsigned int len;
 
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 	}
 
-	strlen = (u32*)res->buffer;
+	strlen = (u32*)kmap(rcvbuf->pages[0]);
 	/* Convert length of symlink */
 	len = ntohl(*strlen);
-	if (len > res->bufsiz - 5)
-		len = res->bufsiz - 5;
+	if (len > rcvbuf->page_len)
+		len = rcvbuf->page_len;
 	*strlen = len;
 	/* NULL terminate the string we got */
 	string = (char *)(strlen + 1);
 	string[len] = 0;
+	kunmap(rcvbuf->pages[0]);
 	return 0;
 }
 
@@ -732,33 +671,32 @@
 # define MAX(a, b)	(((a) > (b))? (a) : (b))
 #endif
 
-#define PROC(proc, argtype, restype)	\
-    { "nfs_" #proc,					\
-      (kxdrproc_t) nfs_xdr_##argtype,			\
-      (kxdrproc_t) nfs_xdr_##restype,			\
-      MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2,	\
-      0							\
+#define PROC(proc, argtype, restype, timer)				\
+    { .p_procname =  "nfs_" #proc,					\
+      .p_encode   =  (kxdrproc_t) nfs_xdr_##argtype,			\
+      .p_decode   =  (kxdrproc_t) nfs_xdr_##restype,			\
+      .p_bufsiz   =  MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2,	\
+      .p_timer    =  timer						\
     }
-
 static struct rpc_procinfo	nfs_procedures[18] = {
-    PROC(null,		enc_void,	dec_void),
-    PROC(getattr,	fhandle,	attrstat),
-    PROC(setattr,	sattrargs,	attrstat),
-    PROC(root,		enc_void,	dec_void),
-    PROC(lookup,	diropargs,	diropres),
-    PROC(readlink,	readlinkargs,	readlinkres),
-    PROC(read,		readargs,	readres),
-    PROC(writecache,	enc_void,	dec_void),
-    PROC(write,		writeargs,	writeres),
-    PROC(create,	createargs,	diropres),
-    PROC(remove,	diropargs,	stat),
-    PROC(rename,	renameargs,	stat),
-    PROC(link,		linkargs,	stat),
-    PROC(symlink,	symlinkargs,	stat),
-    PROC(mkdir,		createargs,	diropres),
-    PROC(rmdir,		diropargs,	stat),
-    PROC(readdir,	readdirargs,	readdirres),
-    PROC(statfs,	fhandle,	statfsres),
+    PROC(null,		enc_void,	dec_void, 0),
+    PROC(getattr,	fhandle,	attrstat, 1),
+    PROC(setattr,	sattrargs,	attrstat, 0),
+    PROC(root,		enc_void,	dec_void, 0),
+    PROC(lookup,	diropargs,	diropres, 2),
+    PROC(readlink,	readlinkargs,	readlinkres, 3),
+    PROC(read,		readargs,	readres, 3),
+    PROC(writecache,	enc_void,	dec_void, 0),
+    PROC(write,		writeargs,	writeres, 4),
+    PROC(create,	createargs,	diropres, 0),
+    PROC(remove,	diropargs,	stat, 0),
+    PROC(rename,	renameargs,	stat, 0),
+    PROC(link,		linkargs,	stat, 0),
+    PROC(symlink,	symlinkargs,	stat, 0),
+    PROC(mkdir,		createargs,	diropres, 0),
+    PROC(rmdir,		diropargs,	stat, 0),
+    PROC(readdir,	readdirargs,	readdirres, 3),
+    PROC(statfs,	fhandle,	statfsres, 0),
 };
 
 struct rpc_version		nfs_version2 = {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfs/nfs3proc.c linux-2.4.20/fs/nfs/nfs3proc.c
--- linux-2.4.19/fs/nfs/nfs3proc.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/nfs/nfs3proc.c	2002-10-29 11:18:40.000000000 +0000
@@ -151,17 +151,16 @@
 }
 
 static int
-nfs3_proc_readlink(struct inode *inode, void *buffer, unsigned int buflen)
+nfs3_proc_readlink(struct inode *inode, struct page *page)
 {
 	struct nfs_fattr	fattr;
-	struct nfs3_readlinkargs args = { NFS_FH(inode), buffer, buflen };
-	struct nfs3_readlinkres	res = { &fattr, buffer, buflen };
+	struct nfs3_readlinkargs args = { NFS_FH(inode), PAGE_CACHE_SIZE, &page };
 	int			status;
 
 	dprintk("NFS call  readlink\n");
 	fattr.valid = 0;
 	status = rpc_call(NFS_CLIENT(inode), NFS3PROC_READLINK,
-			  &args, &res, 0);
+			&args, &fattr, 0);
 	nfs_refresh_inode(inode, &fattr);
 	dprintk("NFS reply readlink: %d\n", status);
 	return status;
@@ -170,11 +169,12 @@
 static int
 nfs3_proc_read(struct inode *inode, struct rpc_cred *cred,
 	       struct nfs_fattr *fattr, int flags,
-	       loff_t offset, unsigned int count, void *buffer, int *eofp)
+	       unsigned int base, unsigned int count, struct page *page,
+	       int *eofp)
 {
-	struct nfs_readargs	arg = { NFS_FH(inode), offset, count, 1,
-					{{buffer, count}, {0,0}, {0,0}, {0,0},
-					 {0,0}, {0,0}, {0,0}, {0,0}} };
+	u64			offset = page_offset(page) + base;
+	struct nfs_readargs	arg = { NFS_FH(inode), offset, count,
+					base, &page };
 	struct nfs_readres	res = { fattr, count, 0 };
 	struct rpc_message	msg = { NFS3PROC_READ, &arg, &res, cred };
 	int			status;
@@ -190,13 +190,12 @@
 static int
 nfs3_proc_write(struct inode *inode, struct rpc_cred *cred,
 		struct nfs_fattr *fattr, int flags,
-		loff_t offset, unsigned int count,
-		void *buffer, struct nfs_writeverf *verf)
+		unsigned int base, unsigned int count,
+		struct page *page, struct nfs_writeverf *verf)
 {
+	u64			offset = page_offset(page) + base;
 	struct nfs_writeargs	arg = { NFS_FH(inode), offset, count,
-					NFS_FILE_SYNC, 1,
-					{{buffer, count}, {0,0}, {0,0}, {0,0},
-					 {0,0}, {0,0}, {0,0}, {0,0}} };
+					NFS_FILE_SYNC, base, &page };
 	struct nfs_writeres	res = { fattr, verf, 0 };
 	struct rpc_message	msg = { NFS3PROC_WRITE, &arg, &res, cred };
 	int			status, rpcflags = 0;
@@ -434,26 +433,16 @@
  */
 static int
 nfs3_proc_readdir(struct inode *dir, struct rpc_cred *cred,
-		  u64 cookie, void *entry,
-		  unsigned int size, int plus)
+		  u64 cookie, struct page *page, unsigned int count, int plus)
 {
 	struct nfs_fattr	dir_attr;
-	struct nfs3_readdirargs	arg = { NFS_FH(dir), cookie, {0, 0}, 0, 0, 0 };
-	struct nfs3_readdirres	res = { &dir_attr, 0, 0, 0, 0 };
-	struct rpc_message	msg = { NFS3PROC_READDIR, &arg, &res, cred };
 	u32			*verf = NFS_COOKIEVERF(dir);
+	struct nfs3_readdirargs	arg = { NFS_FH(dir), cookie, {verf[0], verf[1]},
+	       				plus, count, &page };
+	struct nfs3_readdirres	res = { &dir_attr, verf, plus };
+	struct rpc_message	msg = { NFS3PROC_READDIR, &arg, &res, cred };
 	int			status;
 
-	arg.buffer  = entry;
-	arg.bufsiz  = size;
-	arg.verf[0] = verf[0];
-	arg.verf[1] = verf[1];
-	arg.plus    = plus;
-	res.buffer  = entry;
-	res.bufsiz  = size;
-	res.verf    = verf;
-	res.plus    = plus;
-
 	if (plus)
 		msg.rpc_proc = NFS3PROC_READDIRPLUS;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfs/nfs3xdr.c linux-2.4.20/fs/nfs/nfs3xdr.c
--- linux-2.4.19/fs/nfs/nfs3xdr.c	2001-11-03 01:40:09.000000000 +0000
+++ linux-2.4.20/fs/nfs/nfs3xdr.c	2002-10-29 11:18:51.000000000 +0000
@@ -22,9 +22,6 @@
 #include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
 
-/* Uncomment this to support servers requiring longword lengths */
-#define NFS_PAD_WRITES		1
-
 #define NFSDBG_FACILITY		NFSDBG_XDR
 
 /* Mapping from NFS error code to "errno" error code. */
@@ -156,18 +153,7 @@
 	return p;
 }
 
-static inline u32 *
-xdr_decode_string2(u32 *p, char **string, unsigned int *len,
-			unsigned int maxlen)
-{
-	*len = ntohl(*p++);
-	if (*len > maxlen)
-		return NULL;
-	*string = (char *) p;
-	return p + XDR_QUADLEN(*len);
-}
-
-static inline u32 *
+static u32 *
 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
 {
 	unsigned int	type;
@@ -350,35 +336,18 @@
 nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
-	int		buflen, replen;
-	unsigned int	nr;
+	unsigned int replen;
+	u32 count = args->count;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_hyper(p, args->offset);
-	*p++ = htonl(args->count);
+	*p++ = htonl(count);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-	/* Get the number of buffers in the receive iovec */
-	nr = args->nriov;
-
-	if (nr+2 > MAX_IOVEC) {
-		printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargs\n");
-		return -EINVAL;
-	}
-
-	/* set up reply iovec */
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-
-	/* Copy the iovec */
-	memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
-
-	req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[nr+1].iov_len  = buflen - replen;
-	req->rq_rlen = args->count + buflen;
-	req->rq_rnr += nr+1;
-
+	xdr_inline_pages(&req->rq_rcv_buf, replen,
+			 args->pages, args->pgbase, count);
 	return 0;
 }
 
@@ -388,7 +357,7 @@
 static int
 nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
 {
-	unsigned int	nr;
+	struct xdr_buf *sndbuf = &req->rq_snd_buf;
 	u32 count = args->count;
 
 	p = xdr_encode_fhandle(p, args->fh);
@@ -396,37 +365,10 @@
 	*p++ = htonl(count);
 	*p++ = htonl(args->stable);
 	*p++ = htonl(count);
-	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
-
-	/* Get the number of buffers in the send iovec */
-	nr = args->nriov;
-
-	if (nr+2 > MAX_IOVEC) {
-		printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs\n");
-		return -EINVAL;
-	}
-
-	/* Copy the iovec */
-	memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
-
-#ifdef NFS_PAD_WRITES
-	/*
-	 * Some old servers require that the message length
-	 * be a multiple of 4, so we pad it here if needed.
-	 */
-	if (count & 3) {
-		struct iovec	*iov = req->rq_svec + nr + 1;
-		int		pad = 4 - (count & 3);
-
-		iov->iov_base = (void *) "\0\0\0";
-		iov->iov_len  = pad;
-		count += pad;
-		nr++;
-	}
-#endif
-	req->rq_slen += count;
-	req->rq_snr  += nr;
+	sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
 
+	/* Copy the page array */
+	xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
 	return 0;
 }
 
@@ -530,7 +472,8 @@
 nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
-	int		buflen, replen;
+	unsigned int replen;
+	u32 count = args->count;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_hyper(p, args->cookie);
@@ -539,22 +482,14 @@
 	if (args->plus) {
 		/* readdirplus: need dircount + buffer size.
 		 * We just make sure we make dircount big enough */
-		*p++ = htonl(args->bufsiz >> 3);
+		*p++ = htonl(count >> 3);
 	}
-	*p++ = htonl(args->bufsiz);
+	*p++ = htonl(count);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-	/* set up reply iovec */
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = args->bufsiz;
-	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[2].iov_len  = buflen - replen;
-	req->rq_rlen = buflen + args->bufsiz;
-	req->rq_rnr += 2;
-
+	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
 	return 0;
 }
 
@@ -565,11 +500,13 @@
 static int
 nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
 {
-	struct iovec	*iov = req->rq_rvec;
-	int		hdrlen;
-	int		status, nr;
-	unsigned int	len;
-	u32		*entry, *end;
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+	struct iovec *iov = rcvbuf->head;
+	struct page **page;
+	int hdrlen;
+	int status, nr;
+	unsigned int len, pglen;
+	u32 *entry, *end;
 
 	status = ntohl(*p++);
 	/* Decode post_op_attrs */
@@ -587,11 +524,13 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 	}
 
-	p   = (u32 *) iov[1].iov_base;
-	end = (u32 *) ((u8 *) p + iov[1].iov_len);
+	pglen = rcvbuf->page_len;
+	page = rcvbuf->pages;
+	p = kmap(*page);
+	end = (u32 *)((char *)p + pglen);
 	for (nr = 0; *p++; nr++) {
 		entry = p - 1;
 		if (p + 3 > end)
@@ -602,7 +541,7 @@
 		if (len > NFS3_MAXNAMLEN) {
 			printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
 						len);
-			return -errno_NFSERR_IO;
+			goto err_unmap;
 		}
 
 		if (res->plus) {
@@ -622,7 +561,7 @@
 				if (len > NFS3_FHSIZE) {
 					printk(KERN_WARNING "NFS: giant filehandle in "
 						"readdir (len %x)!\n", len);
-					return -errno_NFSERR_IO;
+					goto err_unmap;
 				}
 				p += XDR_QUADLEN(len);
 			}
@@ -631,13 +570,17 @@
 		if (p + 2 > end)
 			goto short_pkt;
 	}
-
+	kunmap(*page);
 	return nr;
  short_pkt:
 	printk(KERN_NOTICE "NFS: short packet in readdir reply!\n");
 	/* truncate listing */
 	entry[0] = entry[1] = 0;
+	kunmap(*page);
 	return nr;
+err_unmap:
+	kunmap(*page);
+	return -errno_NFSERR_IO;
 }
 
 u32 *
@@ -772,21 +715,16 @@
 static int
 nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
 {
-	struct rpc_task *task = req->rq_task;
-	struct rpc_auth *auth = task->tk_auth;
-	int		buflen, replen;
+	struct rpc_auth *auth = req->rq_task->tk_auth;
+	unsigned int replen;
+	u32 count = args->count - 4;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = args->bufsiz;
-	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[2].iov_len  = buflen - replen;
-	req->rq_rlen = buflen + args->bufsiz;
-	req->rq_rnr += 2;
+	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
 	return 0;
 }
 
@@ -794,17 +732,17 @@
  * Decode READLINK reply
  */
 static int
-nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkres *res)
+nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
 {
-	struct iovec	*iov = req->rq_rvec;
-	int		hdrlen;
-	u32	*strlen;
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+	struct iovec *iov = rcvbuf->head;
+	unsigned int hdrlen;
+	u32	*strlen, len;
 	char	*string;
 	int	status;
-	unsigned int len;
 
 	status = ntohl(*p++);
-	p = xdr_decode_post_op_attr(p, res->fattr);
+	p = xdr_decode_post_op_attr(p, fattr);
 
 	if (status != 0)
 		return -nfs_stat_to_errno(status);
@@ -812,18 +750,19 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 	}
 
-	strlen = (u32*)res->buffer;
+	strlen = (u32*)kmap(rcvbuf->pages[0]);
 	/* Convert length of symlink */
 	len = ntohl(*strlen);
-	if (len > res->bufsiz - 5)
-		len = res->bufsiz - 5;
+	if (len > rcvbuf->page_len)
+		len = rcvbuf->page_len;
 	*strlen = len;
 	/* NULL terminate the string we got */
 	string = (char *)(strlen + 1);
 	string[len] = 0;
+	kunmap(rcvbuf->pages[0]);
 	return 0;
 }
 
@@ -857,7 +796,7 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READ header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
 	}
 
 	recvd = req->rq_rlen - hdrlen;
@@ -867,10 +806,8 @@
 		count = recvd;
 	}
 
-	if (count < res->count) {
-		xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
+	if (count < res->count)
 		res->count = count;
-	}
 
 	return count;
 }
@@ -1051,37 +988,37 @@
 # define MAX(a, b)	(((a) > (b))? (a) : (b))
 #endif
 
-#define PROC(proc, argtype, restype)				\
-    { "nfs3_" #proc,						\
-      (kxdrproc_t) nfs3_xdr_##argtype,				\
-      (kxdrproc_t) nfs3_xdr_##restype,				\
-      MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2,	\
-      0							\
+#define PROC(proc, argtype, restype, timer)				\
+    { .p_procname  = "nfs3_" #proc,					\
+      .p_encode    = (kxdrproc_t) nfs3_xdr_##argtype,			\
+      .p_decode    = (kxdrproc_t) nfs3_xdr_##restype,			\
+      .p_bufsiz    = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2,	\
+      .p_timer     = timer						\
     }
 
 static struct rpc_procinfo	nfs3_procedures[22] = {
-  PROC(null,		enc_void,	dec_void),
-  PROC(getattr,		fhandle,	attrstat),
-  PROC(setattr, 	sattrargs,	wccstat),
-  PROC(lookup,		diropargs,	lookupres),
-  PROC(access,		accessargs,	accessres),
-  PROC(readlink,	readlinkargs,	readlinkres),
-  PROC(read,		readargs,	readres),
-  PROC(write,		writeargs,	writeres),
-  PROC(create,		createargs,	createres),
-  PROC(mkdir,		mkdirargs,	createres),
-  PROC(symlink,		symlinkargs,	createres),
-  PROC(mknod,		mknodargs,	createres),
-  PROC(remove,		diropargs,	wccstat),
-  PROC(rmdir,		diropargs,	wccstat),
-  PROC(rename,		renameargs,	renameres),
-  PROC(link,		linkargs,	linkres),
-  PROC(readdir,		readdirargs,	readdirres),
-  PROC(readdirplus,	readdirargs,	readdirres),
-  PROC(fsstat,		fhandle,	fsstatres),
-  PROC(fsinfo,  	fhandle,	fsinfores),
-  PROC(pathconf,	fhandle,	pathconfres),
-  PROC(commit,		commitargs,	commitres),
+  PROC(null,		enc_void,	dec_void, 0),
+  PROC(getattr,		fhandle,	attrstat, 1),
+  PROC(setattr, 	sattrargs,	wccstat, 0),
+  PROC(lookup,		diropargs,	lookupres, 2),
+  PROC(access,		accessargs,	accessres, 1),
+  PROC(readlink,	readlinkargs,	readlinkres, 3),
+  PROC(read,		readargs,	readres, 3),
+  PROC(write,		writeargs,	writeres, 4),
+  PROC(create,		createargs,	createres, 0),
+  PROC(mkdir,		mkdirargs,	createres, 0),
+  PROC(symlink,		symlinkargs,	createres, 0),
+  PROC(mknod,		mknodargs,	createres, 0),
+  PROC(remove,		diropargs,	wccstat, 0),
+  PROC(rmdir,		diropargs,	wccstat, 0),
+  PROC(rename,		renameargs,	renameres, 0),
+  PROC(link,		linkargs,	linkres, 0),
+  PROC(readdir,		readdirargs,	readdirres, 3),
+  PROC(readdirplus,	readdirargs,	readdirres, 3),
+  PROC(fsstat,		fhandle,	fsstatres, 0),
+  PROC(fsinfo,  	fhandle,	fsinfores, 0),
+  PROC(pathconf,	fhandle,	pathconfres, 0),
+  PROC(commit,		commitargs,	commitres, 5),
 };
 
 struct rpc_version		nfs_version3 = {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfs/nfsroot.c linux-2.4.20/fs/nfs/nfsroot.c
--- linux-2.4.19/fs/nfs/nfsroot.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/nfs/nfsroot.c	2002-10-29 11:18:49.000000000 +0000
@@ -64,6 +64,8 @@
  *	Trond Myklebust :	Add in preliminary support for NFSv3 and TCP.
  *				Fix bug in root_nfs_addr(). nfs_data.namlen
  *				is NOT for the length of the hostname.
+ *	Hua Qin		:	Finish support for mounting root file system
+ *				via NFS over TCP.
  */
 
 #include <linux/config.h>
@@ -407,12 +409,14 @@
 {
 	struct sockaddr_in sin;
 	int status;
+	int protocol = (nfs_data.flags & NFS_MOUNT_TCP) ?
+					IPPROTO_TCP : IPPROTO_UDP;
+	int version = (nfs_data.flags & NFS_MOUNT_VER3) ?
+					NFS_MNT3_VERSION : NFS_MNT_VERSION;
 
 	set_sockaddr(&sin, servaddr, mount_port);
-	if (nfs_data.flags & NFS_MOUNT_VER3)
-		status = nfs3_mount(&sin, nfs_path, &nfs_data.root);
-	else
-		status = nfs_mount(&sin, nfs_path, &nfs_data.root);
+	status = nfsroot_mount(&sin, nfs_path, &nfs_data.root,
+							version, protocol);
 	if (status < 0)
 		printk(KERN_ERR "Root-NFS: Server returned error %d "
 				"while mounting %s\n", status, nfs_path);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfs/pagelist.c linux-2.4.20/fs/nfs/pagelist.c
--- linux-2.4.19/fs/nfs/pagelist.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/nfs/pagelist.c	2002-10-29 11:18:37.000000000 +0000
@@ -96,8 +96,7 @@
 			continue;
 		if (signalled() && (server->flags & NFS_MOUNT_INTR))
 			return ERR_PTR(-ERESTARTSYS);
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 	}
 
 	/* Initialize the request struct. Initially, we assume a
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfs/proc.c linux-2.4.20/fs/nfs/proc.c
--- linux-2.4.19/fs/nfs/proc.c	2001-02-09 19:29:44.000000000 +0000
+++ linux-2.4.20/fs/nfs/proc.c	2002-10-29 11:18:38.000000000 +0000
@@ -106,15 +106,13 @@
 }
 
 static int
-nfs_proc_readlink(struct inode *inode, void *buffer, unsigned int bufsiz)
+nfs_proc_readlink(struct inode *inode, struct page *page)
 {
-	struct nfs_readlinkargs	args = { NFS_FH(inode), buffer, bufsiz };
-	struct nfs_readlinkres	res = { buffer, bufsiz };
+	struct nfs_readlinkargs	args = { NFS_FH(inode), PAGE_CACHE_SIZE, &page };
 	int			status;
 
 	dprintk("NFS call  readlink\n");
-	status = rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK,
-					&args, &res, 0);
+	status = rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK, &args, NULL, 0);
 	dprintk("NFS reply readlink: %d\n", status);
 	return status;
 }
@@ -122,11 +120,12 @@
 static int
 nfs_proc_read(struct inode *inode, struct rpc_cred *cred,
 	      struct nfs_fattr *fattr, int flags,
-	      loff_t offset, unsigned int count, void *buffer, int *eofp)
+	      unsigned int base, unsigned int count,
+	      struct page *page, int *eofp)
 {
-	struct nfs_readargs	arg = { NFS_FH(inode), offset, count, 1,
-				       {{ buffer, count }, {0,0}, {0,0}, {0,0},
-					{0,0}, {0,0}, {0,0}, {0,0}} };
+	u64			offset = page_offset(page) + base;
+	struct nfs_readargs	arg = { NFS_FH(inode), offset, count,
+					base, &page };
 	struct nfs_readres	res = { fattr, count, 0};
 	struct rpc_message	msg = { NFSPROC_READ, &arg, &res, cred };
 	int			status;
@@ -143,13 +142,12 @@
 static int
 nfs_proc_write(struct inode *inode, struct rpc_cred *cred,
 	       struct nfs_fattr *fattr, int how,
-	       loff_t offset, unsigned int count,
-	       void *buffer, struct nfs_writeverf *verf)
+	       unsigned int base, unsigned int count,
+	       struct page *page, struct nfs_writeverf *verf)
 {
-	struct nfs_writeargs	arg = {NFS_FH(inode), offset, count,
-					NFS_FILE_SYNC, 1,
-					{{buffer, count}, {0,0}, {0,0}, {0,0},
-					 {0,0}, {0,0}, {0,0}, {0,0}}};
+	u64			offset = page_offset(page) + base;
+	struct nfs_writeargs	arg = { NFS_FH(inode), offset, count,
+					NFS_FILE_SYNC, base, &page };
 	struct nfs_writeres     res = {fattr, verf, count};
 	struct rpc_message	msg = { NFSPROC_WRITE, &arg, &res, cred };
 	int			status, flags = 0;
@@ -337,21 +335,13 @@
  */
 static int
 nfs_proc_readdir(struct inode *dir, struct rpc_cred *cred,
-		 __u64 cookie, void *entry, 
-		 unsigned int size, int plus)
+		 __u64 cookie, struct page *page, 
+		 unsigned int count, int plus)
 {
-	struct nfs_readdirargs	arg;
-	struct nfs_readdirres	res;
-	struct rpc_message	msg = { NFSPROC_READDIR, &arg, &res, cred };
+	struct nfs_readdirargs	arg = { NFS_FH(dir), cookie, count, &page };
+	struct rpc_message	msg = { NFSPROC_READDIR, &arg, NULL, cred };
 	int			status;
 
-	arg.fh = NFS_FH(dir);
-	arg.cookie = cookie;
-	arg.buffer = entry;
-	arg.bufsiz = size;
-	res.buffer = entry;
-	res.bufsiz = size;
-
 	dprintk("NFS call  readdir %d\n", (unsigned int)cookie);
 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfs/read.c linux-2.4.20/fs/nfs/read.c
--- linux-2.4.19/fs/nfs/read.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/nfs/read.c	2002-10-29 11:18:30.000000000 +0000
@@ -42,6 +42,7 @@
 	struct nfs_readres	res;	/* ... and result struct */
 	struct nfs_fattr	fattr;	/* fattr storage */
 	struct list_head	pages;	/* Coalesced read requests */
+	struct page		*pagevec[NFS_READ_MAXIOV];
 };
 
 /*
@@ -63,6 +64,7 @@
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
+		p->args.pages = p->pagevec;
 	}
 	return p;
 }
@@ -86,8 +88,7 @@
 {
 	struct rpc_cred	*cred = NULL;
 	struct nfs_fattr fattr;
-	loff_t		offset = page_offset(page);
-	char		*buffer;
+	unsigned int	offset = 0;
 	int		rsize = NFS_SERVER(inode)->rsize;
 	int		result;
 	int		count = PAGE_CACHE_SIZE;
@@ -103,19 +104,18 @@
 	 * This works now because the socket layer never tries to DMA
 	 * into this buffer directly.
 	 */
-	buffer = kmap(page);
 	do {
 		if (count < rsize)
 			rsize = count;
 
-		dprintk("NFS: nfs_proc_read(%s, (%x/%Ld), %Ld, %d, %p)\n",
+		dprintk("NFS: nfs_proc_read(%s, (%x/%Ld), %u, %u, %p)\n",
 			NFS_SERVER(inode)->hostname,
 			inode->i_dev, (long long)NFS_FILEID(inode),
-			(long long)offset, rsize, buffer);
+			offset, rsize, page);
 
 		lock_kernel();
 		result = NFS_PROTO(inode)->read(inode, cred, &fattr, flags,
-						offset, rsize, buffer, &eof);
+						offset, rsize, page, &eof);
 		nfs_refresh_inode(inode, &fattr);
 		unlock_kernel();
 
@@ -130,12 +130,15 @@
 		}
 		count  -= result;
 		offset += result;
-		buffer += result;
 		if (result < rsize)	/* NFSv2ism */
 			break;
 	} while (count);
 
-	memset(buffer, 0, count);
+	if (count) {
+		char *kaddr = kmap(page);
+		memset(kaddr + offset, 0, count);
+		kunmap(page);
+	}
 	flush_dcache_page(page);
 	SetPageUptodate(page);
 	if (PageError(page))
@@ -143,7 +146,6 @@
 	result = 0;
 
 io_error:
-	kunmap(page);
 	UnlockPage(page);
 	return result;
 }
@@ -186,26 +188,24 @@
 nfs_read_rpcsetup(struct list_head *head, struct nfs_read_data *data)
 {
 	struct nfs_page		*req;
-	struct iovec		*iov;
+	struct page		**pages;
 	unsigned int		count;
 
-	iov = data->args.iov;
+	pages = data->args.pages;
 	count = 0;
 	while (!list_empty(head)) {
 		struct nfs_page *req = nfs_list_entry(head->next);
 		nfs_list_remove_request(req);
 		nfs_list_add_request(req, &data->pages);
-		iov->iov_base = kmap(req->wb_page) + req->wb_offset;
-		iov->iov_len = req->wb_bytes;
+		*pages++ = req->wb_page;
 		count += req->wb_bytes;
-		iov++;
-		data->args.nriov++;
 	}
 	req = nfs_list_entry(data->pages.next);
 	data->inode	  = req->wb_inode;
 	data->cred	  = req->wb_cred;
 	data->args.fh     = NFS_FH(req->wb_inode);
 	data->args.offset = page_offset(req->wb_page) + req->wb_offset;
+	data->args.pgbase = req->wb_offset;
 	data->args.count  = count;
 	data->res.fattr   = &data->fattr;
 	data->res.count   = count;
@@ -266,10 +266,10 @@
 	msg.rpc_cred = data->cred;
 
 	/* Start the async call */
-	dprintk("NFS: %4d initiated read call (req %x/%Ld count %d nriov %d.\n",
+	dprintk("NFS: %4d initiated read call (req %x/%Ld count %u.\n",
 		task->tk_pid,
 		inode->i_dev, (long long)NFS_FILEID(inode),
-		data->args.count, data->args.nriov);
+		data->args.count);
 
 	rpc_clnt_sigmask(clnt, &oldset);
 	rpc_call_setup(task, &msg, 0);
@@ -424,7 +424,6 @@
 		} else
 			SetPageError(page);
 		flush_dcache_page(page);
-		kunmap(page);
 		UnlockPage(page);
 
 		dprintk("NFS: read (%x/%Ld %d@%Ld)\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfs/symlink.c linux-2.4.20/fs/nfs/symlink.c
--- linux-2.4.19/fs/nfs/symlink.c	2001-02-09 19:29:44.000000000 +0000
+++ linux-2.4.20/fs/nfs/symlink.c	2002-10-29 11:18:30.000000000 +0000
@@ -29,7 +29,6 @@
  */
 static int nfs_symlink_filler(struct inode *inode, struct page *page)
 {
-	void *buffer = kmap(page);
 	int error;
 
 	/* We place the length at the beginning of the page,
@@ -37,13 +36,11 @@
 	 * XDR response verification will NULL terminate it.
 	 */
 	lock_kernel();
-	error = NFS_PROTO(inode)->readlink(inode, buffer,
-					   PAGE_CACHE_SIZE - sizeof(u32)-4);
+	error = NFS_PROTO(inode)->readlink(inode, page);
 	unlock_kernel();
 	if (error < 0)
 		goto error;
 	SetPageUptodate(page);
-	kunmap(page);
 	UnlockPage(page);
 	return 0;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfs/unlink.c linux-2.4.20/fs/nfs/unlink.c
--- linux-2.4.19/fs/nfs/unlink.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.20/fs/nfs/unlink.c	2002-10-29 11:18:39.000000000 +0000
@@ -24,7 +24,7 @@
 };
 
 static struct nfs_unlinkdata	*nfs_deletes;
-static struct rpc_wait_queue	nfs_delete_queue = RPC_INIT_WAITQ("nfs_delete_queue");
+static RPC_WAITQ(nfs_delete_queue, "nfs_delete_queue");
 
 /**
  * nfs_detach_unlinkdata - Remove asynchronous unlink from global list
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfs/write.c linux-2.4.20/fs/nfs/write.c
--- linux-2.4.19/fs/nfs/write.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/nfs/write.c	2002-10-29 11:18:34.000000000 +0000
@@ -77,6 +77,7 @@
 	struct nfs_fattr	fattr;
 	struct nfs_writeverf	verf;
 	struct list_head	pages;		/* Coalesced requests we wish to flush */
+	struct page		*pagevec[NFS_WRITE_MAXIOV];
 };
 
 /*
@@ -105,6 +106,7 @@
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
+		p->args.pages = p->pagevec;
 	}
 	return p;
 }
@@ -163,7 +165,6 @@
 		inode->i_dev, (long long)NFS_FILEID(inode),
 		count, (long long)(page_offset(page) + offset));
 
-	buffer = kmap(page) + offset;
 	base = page_offset(page) + offset;
 
 	flags = ((IS_SWAPFILE(inode)) ? NFS_RW_SWAP : 0) | NFS_RW_SYNC;
@@ -173,7 +174,7 @@
 			wsize = count;
 
 		result = NFS_PROTO(inode)->write(inode, cred, &fattr, flags,
-						 base, wsize, buffer, &verf);
+						 offset, wsize, page, &verf);
 		nfs_write_attributes(inode, &fattr);
 
 		if (result < 0) {
@@ -186,7 +187,8 @@
 			wsize, result);
 		refresh = 1;
 		buffer  += wsize;
-	        base    += wsize;
+		base    += wsize;
+	        offset  += wsize;
 		written += wsize;
 		count   -= wsize;
 		/*
@@ -201,7 +203,6 @@
 		ClearPageError(page);
 
 io_error:
-	kunmap(page);
 	if (cred)
 		put_rpccred(cred);
 
@@ -861,29 +862,27 @@
 nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data)
 {
 	struct nfs_page		*req;
-	struct iovec		*iov;
+	struct page		**pages;
 	unsigned int		count;
 
 	/* Set up the RPC argument and reply structs
 	 * NB: take care not to mess about with data->commit et al. */
 
-	iov = data->args.iov;
+	pages = data->args.pages;
 	count = 0;
 	while (!list_empty(head)) {
 		struct nfs_page *req = nfs_list_entry(head->next);
 		nfs_list_remove_request(req);
 		nfs_list_add_request(req, &data->pages);
-		iov->iov_base = kmap(req->wb_page) + req->wb_offset;
-		iov->iov_len = req->wb_bytes;
+		*pages++ = req->wb_page;
 		count += req->wb_bytes;
-		iov++;
-		data->args.nriov++;
 	}
 	req = nfs_list_entry(data->pages.next);
 	data->inode = req->wb_inode;
 	data->cred = req->wb_cred;
 	data->args.fh     = NFS_FH(req->wb_inode);
 	data->args.offset = page_offset(req->wb_page) + req->wb_offset;
+	data->args.pgbase = req->wb_offset;
 	data->args.count  = count;
 	data->res.fattr   = &data->fattr;
 	data->res.count   = count;
@@ -948,11 +947,11 @@
 	msg.rpc_resp = &data->res;
 	msg.rpc_cred = data->cred;
 
-	dprintk("NFS: %4d initiated write call (req %x/%Ld count %d nriov %d)\n",
+	dprintk("NFS: %4d initiated write call (req %x/%Ld count %u)\n",
 		task->tk_pid, 
 		inode->i_dev,
 		(long long)NFS_FILEID(inode),
-		data->args.count, data->args.nriov);
+		data->args.count);
 
 	rpc_clnt_sigmask(clnt, &oldset);
 	rpc_call_setup(task, &msg, 0);
@@ -1064,8 +1063,6 @@
 		nfs_list_remove_request(req);
 		page = req->wb_page;
 
-		kunmap(page);
-
 		dprintk("NFS: write (%x/%Ld %d@%Ld)",
 			req->wb_inode->i_dev,
 			(long long)NFS_FILEID(req->wb_inode),
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfsd/export.c linux-2.4.20/fs/nfsd/export.c
--- linux-2.4.19/fs/nfsd/export.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/nfsd/export.c	2002-10-29 11:18:48.000000000 +0000
@@ -50,6 +50,7 @@
 		((((a)>>24) ^ ((a)>>16) ^ ((a)>>8) ^(a)) & CLIENT_HASHMASK)
 /* XXX: is this adequate for 32bit kdev_t ? */
 #define EXPORT_HASH(dev)	((dev) & (NFSCLNT_EXPMAX - 1))
+#define EXPORT_FSID_HASH(fsid)	((fsid) & (NFSCLNT_EXPMAX - 1))
 
 struct svc_clnthash {
 	struct svc_clnthash *	h_next;
@@ -58,7 +59,6 @@
 };
 static struct svc_clnthash *	clnt_hash[CLIENT_HASHMAX];
 static svc_client *		clients;
-static int			initialized;
 
 static int			hash_lock;
 static int			want_lock;
@@ -87,6 +87,26 @@
 }
 
 /*
+ * Find the client's export entry matching fsid
+ */
+svc_export *
+exp_get_fsid(svc_client *clp, int fsid)
+{
+	struct list_head *head, *p;
+
+	if (!clp)
+		return NULL;
+
+	head = &clp->cl_expfsid[EXPORT_FSID_HASH(fsid)];
+	list_for_each(p, head) {
+		svc_export *exp = list_entry(p, svc_export, ex_fsid_hash);
+		if (exp->ex_fsid == fsid)
+			return exp;
+	}
+	return NULL;
+}
+
+/*
  * Find the export entry for a given dentry.  <gam3@acm.org>
  */
 static svc_export *
@@ -138,6 +158,25 @@
 	}
 }
 
+static void exp_fsid_unhash(struct svc_export *exp)
+{
+
+	if ((exp->ex_flags & NFSEXP_FSID) == 0)
+		return;
+
+	list_del_init(&exp->ex_fsid_hash);
+}
+
+static void exp_fsid_hash(struct svc_client *clp, struct svc_export *exp)
+{
+	struct list_head *head;
+
+	if ((exp->ex_flags & NFSEXP_FSID) == 0)
+		return;
+	head = clp->cl_expfsid + EXPORT_FSID_HASH(exp->ex_fsid);
+	list_add(&exp->ex_fsid_hash, head);
+}
+
 /*
  * Export a file system.
  */
@@ -145,7 +184,8 @@
 exp_export(struct nfsctl_export *nxp)
 {
 	svc_client	*clp;
-	svc_export	*exp, *parent;
+	svc_export	*exp = NULL, *parent;
+	svc_export	*fsid_exp;
 	struct nameidata nd;
 	struct inode	*inode = NULL;
 	int		err;
@@ -161,8 +201,6 @@
 	dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
 			nxp->ex_client, nxp->ex_path,
 			nxp->ex_dev, (long) nxp->ex_ino, nxp->ex_flags);
-	dev = to_kdev_t(nxp->ex_dev);
-	ino = nxp->ex_ino;
 
 	/* Try to lock the export table for update */
 	if ((err = exp_writelock()) < 0)
@@ -173,17 +211,6 @@
 	if (!(clp = exp_getclientbyname(nxp->ex_client)))
 		goto out_unlock;
 
-	/*
-	 * If there's already an export for this file, assume this
-	 * is just a flag update.
-	 */
-	if ((exp = exp_get(clp, dev, ino)) != NULL) {
-		exp->ex_flags    = nxp->ex_flags;
-		exp->ex_anon_uid = nxp->ex_anon_uid;
-		exp->ex_anon_gid = nxp->ex_anon_gid;
-		err = 0;
-		goto out_unlock;
-	}
 
 	/* Look up the dentry */
 	err = 0;
@@ -193,11 +220,28 @@
 		goto out_unlock;
 
 	inode = nd.dentry->d_inode;
+	dev = inode->i_dev;
+	ino = inode->i_ino;
 	err = -EINVAL;
-	if (inode->i_dev != dev || inode->i_ino != nxp->ex_ino) {
-		printk(KERN_DEBUG "exp_export: i_dev = %x, dev = %x\n",
-			inode->i_dev, dev); 
-		/* I'm just being paranoid... */
+
+	exp = exp_get(clp, dev, ino);
+
+	/* must make sure there wont be an ex_fsid clash */
+	if ((nxp->ex_flags & NFSEXP_FSID) &&
+	    (fsid_exp = exp_get_fsid(clp, nxp->ex_dev)) &&
+	    fsid_exp != exp)
+		goto finish;
+
+	if (exp != NULL) {
+		/* just a flags/id/fsid update */
+
+		exp_fsid_unhash(exp);
+		exp->ex_flags    = nxp->ex_flags;
+		exp->ex_anon_uid = nxp->ex_anon_uid;
+		exp->ex_anon_gid = nxp->ex_anon_gid;
+		exp->ex_fsid     = nxp->ex_dev;
+		exp_fsid_hash(clp, exp);
+		err = 0;
 		goto finish;
 	}
 
@@ -209,7 +253,17 @@
 		goto finish;
 
 	err = -EINVAL;
-	if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) ||
+	/* There are two requirements on a filesystem to be exportable.
+	 * 1:  We must be able to identify the filesystem from a number.
+	 *       either a device number (so FS_REQUIRES_DEV needed)
+	 *       or an FSID number (so NFSEXP_FSID needed).
+	 * 2:  We must be able to find an inode from a filehandle.
+	 *       either using fh_to_dentry (prefered)
+	 *       or using read_inode (the hack).
+	 */
+	if (!((inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV)
+	      || (nxp->ex_flags & NFSEXP_FSID))
+	    ||
 	    (inode->i_sb->s_op->read_inode == NULL
 	     && inode->i_sb->s_op->fh_to_dentry == NULL)) {
 		dprintk("exp_export: export of invalid fs type.\n");
@@ -241,6 +295,8 @@
 	exp->ex_ino = ino;
 	exp->ex_anon_uid = nxp->ex_anon_uid;
 	exp->ex_anon_gid = nxp->ex_anon_gid;
+	exp->ex_fsid = nxp->ex_dev;
+
 
 	/* Update parent pointers of all exports */
 	if (parent)
@@ -249,6 +305,8 @@
 	list_add(&exp->ex_hash, clp->cl_export + EXPORT_HASH(dev));
 	list_add_tail(&exp->ex_list, &clp->cl_list);
 
+	exp_fsid_hash(clp, exp);
+
 	err = 0;
 
 finish:
@@ -272,6 +330,7 @@
 
 	list_del(&unexp->ex_hash);
 	list_del(&unexp->ex_list);
+	exp_fsid_unhash(unexp);
 
 	exp_change_parents(unexp->ex_client, unexp, unexp->ex_parent);
 
@@ -470,9 +529,6 @@
 	struct svc_clnthash	**hp, **head, *tmp;
 	unsigned long		addr = sin->sin_addr.s_addr;
 
-	if (!initialized)
-		return NULL;
-
 	head = &clnt_hash[CLIENT_HASH(addr)];
 
 	for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
@@ -590,7 +646,7 @@
 	{ 0, {"", ""}}
 };
 
-static void exp_flags(struct seq_file *m, int flag)
+static void exp_flags(struct seq_file *m, int flag, int fsid)
 {
 	int first = 0;
 	struct flags *flg;
@@ -600,6 +656,8 @@
 		if (*flg->name[state])
 			seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
 	}
+	if (flag & NFSEXP_FSID)
+		seq_printf(m, "%sfsid=%d", first++?",":"", fsid);
 }
 
 static inline void mangle(struct seq_file *m, const char *s)
@@ -625,7 +683,7 @@
 	seq_putc(m, '\t');
 	mangle(m, clp->cl_ident);
 	seq_putc(m, '(');
-	exp_flags(m, exp->ex_flags);
+	exp_flags(m, exp->ex_flags, exp->ex_fsid);
 	seq_puts(m, ") # ");
 	for (j = 0; j < clp->cl_naddr; j++) {
 		struct svc_clnthash **hp, **head, *tmp;
@@ -696,8 +754,10 @@
 		if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL)))
 			goto out_unlock;
 		memset(clp, 0, sizeof(*clp));
-		for (i = 0; i < NFSCLNT_EXPMAX; i++)
+		for (i = 0; i < NFSCLNT_EXPMAX; i++) {
 			INIT_LIST_HEAD(&clp->cl_export[i]);
+			INIT_LIST_HEAD(&clp->cl_expfsid[i]);
+		}
 		INIT_LIST_HEAD(&clp->cl_list);
 
 		dprintk("created client %s (%p)\n", ncp->cl_ident, clp);
@@ -869,13 +929,11 @@
 	int		i;
 
 	dprintk("nfsd: initializing export module.\n");
-	if (initialized)
-		return;
+
 	for (i = 0; i < CLIENT_HASHMAX; i++)
 		clnt_hash[i] = NULL;
 	clients = NULL;
 
-	initialized = 1;
 }
 
 /*
@@ -887,8 +945,7 @@
 	int	i;
 
 	dprintk("nfsd: shutting down export module.\n");
-	if (!initialized)
-		return;
+
 	if (exp_writelock() < 0) {
 		printk(KERN_WARNING "Weird: hashtable locked in exp_shutdown");
 		return;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfsd/nfs3proc.c linux-2.4.20/fs/nfsd/nfs3proc.c
--- linux-2.4.19/fs/nfsd/nfs3proc.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/nfsd/nfs3proc.c	2002-10-29 11:18:37.000000000 +0000
@@ -188,6 +188,8 @@
 	if ((avail << 2) < resp->count)
 		resp->count = avail << 2;
 
+	svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + argp->count +4);
+
 	fh_copy(&resp->fh, &argp->fh);
 	nfserr = nfsd_read(rqstp, &resp->fh,
 				  argp->offset,
@@ -646,7 +648,7 @@
 #define nfsd3_voidres			nfsd3_voidargs
 struct nfsd3_voidargs { int dummy; };
 
-#define PROC(name, argt, rest, relt, cache)	\
+#define PROC(name, argt, rest, relt, cache, respsize)	\
  { (svc_procfunc) nfsd3_proc_##name,		\
    (kxdrproc_t) nfs3svc_decode_##argt##args,	\
    (kxdrproc_t) nfs3svc_encode_##rest##res,	\
@@ -654,29 +656,37 @@
    sizeof(struct nfsd3_##argt##args),		\
    sizeof(struct nfsd3_##rest##res),		\
    0,						\
-   cache					\
+   cache,					\
+   respsize,					\
  }
+
+#define ST 1		/* status*/
+#define FH 17		/* filehandle with length */
+#define AT 21		/* attributes */
+#define pAT (1+AT)	/* post attributes - conditional */
+#define WC (7+pAT)	/* WCC attributes */
+
 struct svc_procedure		nfsd_procedures3[22] = {
-  PROC(null,	 void,		void,		void,	 RC_NOCACHE),
-  PROC(getattr,	 fhandle,	attrstat,	fhandle, RC_NOCACHE),
-  PROC(setattr,  sattr,		wccstat,	fhandle,  RC_REPLBUFF),
-  PROC(lookup,	 dirop,		dirop,		fhandle2, RC_NOCACHE),
-  PROC(access,	 access,	access,		fhandle,  RC_NOCACHE),
-  PROC(readlink, fhandle,	readlink,	fhandle,  RC_NOCACHE),
-  PROC(read,	 read,		read,		fhandle, RC_NOCACHE),
-  PROC(write,	 write,		write,		fhandle,  RC_REPLBUFF),
-  PROC(create,	 create,	create,		fhandle2, RC_REPLBUFF),
-  PROC(mkdir,	 mkdir,		create,		fhandle2, RC_REPLBUFF),
-  PROC(symlink,	 symlink,	create,		fhandle2, RC_REPLBUFF),
-  PROC(mknod,	 mknod,		create,		fhandle2, RC_REPLBUFF),
-  PROC(remove,	 dirop,		wccstat,	fhandle,  RC_REPLBUFF),
-  PROC(rmdir,	 dirop,		wccstat,	fhandle,  RC_REPLBUFF),
-  PROC(rename,	 rename,	rename,		fhandle2, RC_REPLBUFF),
-  PROC(link,	 link,		link,		fhandle2, RC_REPLBUFF),
-  PROC(readdir,	 readdir,	readdir,	fhandle,  RC_NOCACHE),
-  PROC(readdirplus,readdirplus,	readdir,	fhandle,  RC_NOCACHE),
-  PROC(fsstat,	 fhandle,	fsstat,		void,     RC_NOCACHE),
-  PROC(fsinfo,   fhandle,	fsinfo,		void,     RC_NOCACHE),
-  PROC(pathconf, fhandle,	pathconf,	void,     RC_NOCACHE),
-  PROC(commit,	 commit,	commit,		fhandle,  RC_NOCACHE)
+  PROC(null,	 void,		void,		void,	 RC_NOCACHE, ST),
+  PROC(getattr,	 fhandle,	attrstat,	fhandle, RC_NOCACHE, ST+AT),
+  PROC(setattr,  sattr,		wccstat,	fhandle,  RC_REPLBUFF, ST+WC),
+  PROC(lookup,	 dirop,		dirop,		fhandle2, RC_NOCACHE, ST+FH+pAT+pAT),
+  PROC(access,	 access,	access,		fhandle,  RC_NOCACHE, ST+pAT+1),
+  PROC(readlink, fhandle,	readlink,	fhandle,  RC_NOCACHE, ST+pAT+1+256),
+  PROC(read,	 read,		read,		fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE),
+  PROC(write,	 write,		write,		fhandle,  RC_REPLBUFF, ST+WC+4),
+  PROC(create,	 create,	create,		fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC),
+  PROC(mkdir,	 mkdir,		create,		fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC),
+  PROC(symlink,	 symlink,	create,		fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC),
+  PROC(mknod,	 mknod,		create,		fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC),
+  PROC(remove,	 dirop,		wccstat,	fhandle,  RC_REPLBUFF, ST+WC),
+  PROC(rmdir,	 dirop,		wccstat,	fhandle,  RC_REPLBUFF, ST+WC),
+  PROC(rename,	 rename,	rename,		fhandle2, RC_REPLBUFF, ST+WC+WC),
+  PROC(link,	 link,		link,		fhandle2, RC_REPLBUFF, ST+pAT+WC),
+  PROC(readdir,	 readdir,	readdir,	fhandle,  RC_NOCACHE, 0),
+  PROC(readdirplus,readdirplus,	readdir,	fhandle,  RC_NOCACHE, 0),
+  PROC(fsstat,	 fhandle,	fsstat,		void,     RC_NOCACHE, ST+pAT+2*6+1),
+  PROC(fsinfo,   fhandle,	fsinfo,		void,     RC_NOCACHE, ST+pAT+12),
+  PROC(pathconf, fhandle,	pathconf,	void,     RC_NOCACHE, ST+pAT+6),
+  PROC(commit,	 commit,	commit,		fhandle,  RC_NOCACHE, ST+WC+2),
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfsd/nfs3xdr.c linux-2.4.20/fs/nfsd/nfs3xdr.c
--- linux-2.4.19/fs/nfsd/nfs3xdr.c	2001-10-04 05:27:48.000000000 +0000
+++ linux-2.4.20/fs/nfsd/nfs3xdr.c	2002-10-29 11:18:30.000000000 +0000
@@ -154,9 +154,9 @@
 }
 
 static inline u32 *
-encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
+encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
 {
-	struct inode	*inode = dentry->d_inode;
+	struct inode	*inode = fhp->fh_dentry->d_inode;
 
 	*p++ = htonl(nfs3_ftypes[(inode->i_mode & S_IFMT) >> 12]);
 	*p++ = htonl((u32) inode->i_mode);
@@ -175,7 +175,12 @@
 		p = xdr_encode_hyper(p, ((u64)inode->i_blocks) << 9);
 	*p++ = htonl((u32) MAJOR(inode->i_rdev));
 	*p++ = htonl((u32) MINOR(inode->i_rdev));
-	p = xdr_encode_hyper(p, (u64) inode->i_dev);
+	if (rqstp->rq_reffh->fh_version == 1
+	    && rqstp->rq_reffh->fh_fsid_type == 1
+	    && (fhp->fh_export->ex_flags & NFSEXP_FSID))
+		p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
+	else
+		p = xdr_encode_hyper(p, (u64) inode->i_dev);
 	p = xdr_encode_hyper(p, (u64) inode->i_ino);
 	p = encode_time3(p, inode->i_atime);
 	p = encode_time3(p, lease_get_mtime(inode));
@@ -205,7 +210,12 @@
 	p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
 	*p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
 	*p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
-	p = xdr_encode_hyper(p, (u64) inode->i_dev);
+	if (rqstp->rq_reffh->fh_version == 1
+	    && rqstp->rq_reffh->fh_fsid_type == 1
+	    && (fhp->fh_export->ex_flags & NFSEXP_FSID))
+		p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
+	else
+		p = xdr_encode_hyper(p, (u64) inode->i_dev);
 	p = xdr_encode_hyper(p, (u64) inode->i_ino);
 	p = encode_time3(p, fhp->fh_post_atime);
 	p = encode_time3(p, fhp->fh_post_mtime);
@@ -220,11 +230,12 @@
  * handle. In this case, no attributes are returned.
  */
 static u32 *
-encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
+encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
 {
+	struct dentry *dentry = fhp->fh_dentry;
 	if (dentry && dentry->d_inode != NULL) {
 		*p++ = xdr_one;		/* attributes follow */
-		return encode_fattr3(rqstp, p, dentry);
+		return encode_fattr3(rqstp, p, fhp);
 	}
 	*p++ = xdr_zero;
 	return p;
@@ -251,7 +262,7 @@
 	}
 	/* no pre- or post-attrs */
 	*p++ = xdr_zero;
-	return encode_post_op_attr(rqstp, p, dentry);
+	return encode_post_op_attr(rqstp, p, fhp);
 }
 
 /*
@@ -509,7 +520,7 @@
 					struct nfsd3_attrstat *resp)
 {
 	if (resp->status == 0)
-		p = encode_fattr3(rqstp, p, resp->fh.fh_dentry);
+		p = encode_fattr3(rqstp, p, &resp->fh);
 	return xdr_ressize_check(rqstp, p);
 }
 
@@ -529,9 +540,9 @@
 {
 	if (resp->status == 0) {
 		p = encode_fh(p, &resp->fh);
-		p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
+		p = encode_post_op_attr(rqstp, p, &resp->fh);
 	}
-	p = encode_post_op_attr(rqstp, p, resp->dirfh.fh_dentry);
+	p = encode_post_op_attr(rqstp, p, &resp->dirfh);
 	return xdr_ressize_check(rqstp, p);
 }
 
@@ -540,7 +551,7 @@
 nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_accessres *resp)
 {
-	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
+	p = encode_post_op_attr(rqstp, p, &resp->fh);
 	if (resp->status == 0)
 		*p++ = htonl(resp->access);
 	return xdr_ressize_check(rqstp, p);
@@ -551,7 +562,7 @@
 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_readlinkres *resp)
 {
-	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
+	p = encode_post_op_attr(rqstp, p, &resp->fh);
 	if (resp->status == 0) {
 		*p++ = htonl(resp->len);
 		p += XDR_QUADLEN(resp->len);
@@ -564,7 +575,7 @@
 nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_readres *resp)
 {
-	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
+	p = encode_post_op_attr(rqstp, p, &resp->fh);
 	if (resp->status == 0) {
 		*p++ = htonl(resp->count);
 		*p++ = htonl(resp->eof);
@@ -597,7 +608,7 @@
 	if (resp->status == 0) {
 		*p++ = xdr_one;
 		p = encode_fh(p, &resp->fh);
-		p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
+		p = encode_post_op_attr(rqstp, p, &resp->fh);
 	}
 	p = encode_wcc_data(rqstp, p, &resp->dirfh);
 	return xdr_ressize_check(rqstp, p);
@@ -618,7 +629,7 @@
 nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_linkres *resp)
 {
-	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
+	p = encode_post_op_attr(rqstp, p, &resp->fh);
 	p = encode_wcc_data(rqstp, p, &resp->tfh);
 	return xdr_ressize_check(rqstp, p);
 }
@@ -628,7 +639,7 @@
 nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_readdirres *resp)
 {
-	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
+	p = encode_post_op_attr(rqstp, p, &resp->fh);
 	if (resp->status == 0) {
 		/* stupid readdir cookie */
 		memcpy(p, resp->verf, 8); p += 2;
@@ -709,7 +720,7 @@
 			goto noexec;
 		if (fh_compose(&fh, exp, dchild, cd->dirfh) != 0 || !dchild->d_inode)
 			goto noexec;
-		p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry);
+		p = encode_post_op_attr(cd->rqstp, p, &fh);
 		*p++ = xdr_one; /* yes, a file handle follows */
 		p = encode_fh(p, &fh);
 		fh_put(&fh);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfsd/nfscache.c linux-2.4.20/fs/nfsd/nfscache.c
--- linux-2.4.19/fs/nfsd/nfscache.c	2001-02-15 18:56:29.000000000 +0000
+++ linux-2.4.20/fs/nfsd/nfscache.c	2002-10-29 11:18:40.000000000 +0000
@@ -38,7 +38,6 @@
 static struct svc_cacherep *	lru_head;
 static struct svc_cacherep *	lru_tail;
 static struct svc_cacherep *	nfscache;
-static int			cache_initialized;
 static int			cache_disabled = 1;
 
 static int	nfsd_cache_append(struct svc_rqst *rqstp, struct svc_buf *data);
@@ -51,8 +50,6 @@
 	size_t			i;
 	unsigned long		order;
 
-	if (cache_initialized)
-		return;
 
 	i = CACHESIZE * sizeof (struct svc_cacherep);
 	for (order = 0; (PAGE_SIZE << order) < i; order++)
@@ -90,7 +87,6 @@
 	lru_head->c_lru_prev = NULL;
 	lru_tail->c_lru_next = NULL;
 
-	cache_initialized = 1;
 	cache_disabled = 0;
 }
 
@@ -101,15 +97,11 @@
 	size_t			i;
 	unsigned long		order;
 
-	if (!cache_initialized)
-		return;
-
 	for (rp = lru_head; rp; rp = rp->c_lru_next) {
 		if (rp->c_state == RC_DONE && rp->c_type == RC_REPLBUFF)
 			kfree(rp->c_replbuf.buf);
 	}
 
-	cache_initialized = 0;
 	cache_disabled = 1;
 
 	i = CACHESIZE * sizeof (struct svc_cacherep);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfsd/nfsfh.c linux-2.4.20/fs/nfsd/nfsfh.c
--- linux-2.4.19/fs/nfsd/nfsfh.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/nfsd/nfsfh.c	2002-10-29 11:18:37.000000000 +0000
@@ -273,7 +273,9 @@
 	/* I'm going to assume that if the returned dentry is different, then
 	 * it is well connected.  But nobody returns different dentrys do they?
 	 */
+	down(&child->d_inode->i_sem);
 	pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry);
+	up(&child->d_inode->i_sem);
 	d_drop(tdentry); /* we never want ".." hashed */
 	if (!pdentry && tdentry->d_inode == NULL) {
 		/* File system cannot find ".." ... sad but possible */
@@ -534,12 +536,17 @@
 
 	dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
 
+	/* keep this filehandle for possible reference  when encoding attributes */
+	rqstp->rq_reffh = fh;
+
 	if (!fhp->fh_dentry) {
-		kdev_t xdev;
-		ino_t xino;
+		kdev_t xdev = NODEV;
+		ino_t xino = 0;
 		__u32 *datap=NULL;
 		int data_left = fh->fh_size/4;
 		int nfsdev;
+		int fsid = 0;
+
 		error = nfserr_stale;
 		if (rqstp->rq_vers == 3)
 			error = nfserr_badhandle;
@@ -559,6 +566,10 @@
 				xdev = MKDEV(nfsdev>>16, nfsdev&0xFFFF);
 				xino = *datap++;
 				break;
+			case 1:
+				if ((data_left-=1)<0) goto out;
+				fsid = *datap++;
+				break;
 			default:
 				goto out;
 			}
@@ -574,7 +585,10 @@
 		 * Look up the export entry.
 		 */
 		error = nfserr_stale; 
-		exp = exp_get(rqstp->rq_client, xdev, xino);
+		if (fh->fh_version == 1 && fh->fh_fsid_type == 1)
+			exp = exp_get_fsid(rqstp->rq_client, fsid);
+		else
+			exp = exp_get(rqstp->rq_client, xdev, xino);
 
 		if (!exp)
 			/* export entry revoked */
@@ -818,12 +832,20 @@
 	} else {
 		fhp->fh_handle.fh_version = 1;
 		fhp->fh_handle.fh_auth_type = 0;
-		fhp->fh_handle.fh_fsid_type = 0;
 		datap = fhp->fh_handle.fh_auth+0;
-		/* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */
-		*datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
-		*datap++ = ino_t_to_u32(exp->ex_ino);
-		fhp->fh_handle.fh_size = 3*4;
+		if ((exp->ex_flags & NFSEXP_FSID) &&
+		    (!ref_fh || ref_fh->fh_handle.fh_fsid_type == 1)) {
+			fhp->fh_handle.fh_fsid_type = 1;
+			/* fsid_type 1 == 4 bytes filesystem id */
+			*datap++ = exp->ex_fsid;
+			fhp->fh_handle.fh_size = 2*4;
+		} else {
+			fhp->fh_handle.fh_fsid_type = 0;
+			/* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */
+			*datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
+			*datap++ = ino_t_to_u32(exp->ex_ino);
+			fhp->fh_handle.fh_size = 3*4;
+		}
 		if (inode) {
 			int size = fhp->fh_maxsize/4 - 3;
 			fhp->fh_handle.fh_fileid_type =
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfsd/nfsproc.c linux-2.4.20/fs/nfsd/nfsproc.c
--- linux-2.4.19/fs/nfsd/nfsproc.c	2001-10-21 17:40:36.000000000 +0000
+++ linux-2.4.20/fs/nfsd/nfsproc.c	2002-10-29 11:18:36.000000000 +0000
@@ -148,6 +148,7 @@
 				argp->count);
 		argp->count = avail << 2;
 	}
+	svc_reserve(rqstp, (19<<2) + argp->count + 4);
 
 	resp->count = argp->count;
 	nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
@@ -263,11 +264,11 @@
 					/* this is probably a permission check..
 					 * at least IRIX implements perm checking on
 					 *   echo thing > device-special-file-or-pipe
-					 * by does a CREATE with type==0
+					 * by doing a CREATE with type==0
 					 */
 					nfserr = nfsd_permission(newfhp->fh_export,
 								 newfhp->fh_dentry,
-								 MAY_WRITE);
+								 MAY_WRITE|_NFSD_IRIX_BOGOSITY);
 					if (nfserr && nfserr != nfserr_rofs)
 						goto out_unlock;
 				}
@@ -522,7 +523,7 @@
 #define nfssvc_release_none	NULL
 struct nfsd_void { int dummy; };
 
-#define PROC(name, argt, rest, relt, cache)	\
+#define PROC(name, argt, rest, relt, cache, respsize)	\
  { (svc_procfunc) nfsd_proc_##name,		\
    (kxdrproc_t) nfssvc_decode_##argt,		\
    (kxdrproc_t) nfssvc_encode_##rest,		\
@@ -530,27 +531,33 @@
    sizeof(struct nfsd_##argt),			\
    sizeof(struct nfsd_##rest),			\
    0,						\
-   cache					\
+   cache,					\
+   respsize,				       	\
  }
+
+#define ST 1		/* status */
+#define FH 8		/* filehandle */
+#define	AT 18		/* attributes */
+
 struct svc_procedure		nfsd_procedures2[18] = {
-  PROC(null,	 void,		void,		none,		RC_NOCACHE),
-  PROC(getattr,	 fhandle,	attrstat,	fhandle,	RC_NOCACHE),
-  PROC(setattr,  sattrargs,	attrstat,	fhandle,	RC_REPLBUFF),
-  PROC(none,	 void,		void,		none,		RC_NOCACHE),
-  PROC(lookup,	 diropargs,	diropres,	fhandle,	RC_NOCACHE),
-  PROC(readlink, fhandle,	readlinkres,	none,		RC_NOCACHE),
-  PROC(read,	 readargs,	readres,	fhandle,	RC_NOCACHE),
-  PROC(none,	 void,		void,		none,		RC_NOCACHE),
-  PROC(write,	 writeargs,	attrstat,	fhandle,	RC_REPLBUFF),
-  PROC(create,	 createargs,	diropres,	fhandle,	RC_REPLBUFF),
-  PROC(remove,	 diropargs,	void,		none,		RC_REPLSTAT),
-  PROC(rename,	 renameargs,	void,		none,		RC_REPLSTAT),
-  PROC(link,	 linkargs,	void,		none,		RC_REPLSTAT),
-  PROC(symlink,	 symlinkargs,	void,		none,		RC_REPLSTAT),
-  PROC(mkdir,	 createargs,	diropres,	fhandle,	RC_REPLBUFF),
-  PROC(rmdir,	 diropargs,	void,		none,		RC_REPLSTAT),
-  PROC(readdir,	 readdirargs,	readdirres,	none,		RC_REPLBUFF),
-  PROC(statfs,	 fhandle,	statfsres,	none,		RC_NOCACHE),
+  PROC(null,	 void,		void,		none,		RC_NOCACHE, ST),
+  PROC(getattr,	 fhandle,	attrstat,	fhandle,	RC_NOCACHE, ST+AT),
+  PROC(setattr,  sattrargs,	attrstat,	fhandle,	RC_REPLBUFF, ST+AT),
+  PROC(none,	 void,		void,		none,		RC_NOCACHE, ST),
+  PROC(lookup,	 diropargs,	diropres,	fhandle,	RC_NOCACHE, ST+FH+AT),
+  PROC(readlink, fhandle,	readlinkres,	none,		RC_NOCACHE, ST+1+256),
+  PROC(read,	 readargs,	readres,	fhandle,	RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE),
+  PROC(none,	 void,		void,		none,		RC_NOCACHE, ST),
+  PROC(write,	 writeargs,	attrstat,	fhandle,	RC_REPLBUFF, ST+AT),
+  PROC(create,	 createargs,	diropres,	fhandle,	RC_REPLBUFF, ST+FH+AT),
+  PROC(remove,	 diropargs,	void,		none,		RC_REPLSTAT, ST),
+  PROC(rename,	 renameargs,	void,		none,		RC_REPLSTAT, ST),
+  PROC(link,	 linkargs,	void,		none,		RC_REPLSTAT, ST),
+  PROC(symlink,	 symlinkargs,	void,		none,		RC_REPLSTAT, ST),
+  PROC(mkdir,	 createargs,	diropres,	fhandle,	RC_REPLBUFF, ST+FH+AT),
+  PROC(rmdir,	 diropargs,	void,		none,		RC_REPLSTAT, ST),
+  PROC(readdir,	 readdirargs,	readdirres,	none,		RC_REPLBUFF, 0),
+  PROC(statfs,	 fhandle,	statfsres,	none,		RC_NOCACHE, ST+5),
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfsd/nfssvc.c linux-2.4.20/fs/nfsd/nfssvc.c
--- linux-2.4.19/fs/nfsd/nfssvc.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/nfsd/nfssvc.c	2002-10-29 11:18:31.000000000 +0000
@@ -95,7 +95,7 @@
 		if (error < 0)
 			goto failure;
 
-#if 0	/* Don't even pretend that TCP works. It doesn't. */
+#if CONFIG_NFSD_TCP
 		error = svc_makesock(nfsd_serv, IPPROTO_TCP, port);
 		if (error < 0)
 			goto failure;
@@ -189,7 +189,7 @@
 		 * recvfrom routine.
 		 */
 		while ((err = svc_recv(serv, rqstp,
-				       MAX_SCHEDULE_TIMEOUT)) == -EAGAIN)
+				       5*60*HZ)) == -EAGAIN)
 		    ;
 		if (err < 0)
 			break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfsd/nfsxdr.c linux-2.4.20/fs/nfsd/nfsxdr.c
--- linux-2.4.19/fs/nfsd/nfsxdr.c	2001-10-17 21:16:34.000000000 +0000
+++ linux-2.4.20/fs/nfsd/nfsxdr.c	2002-10-29 11:18:31.000000000 +0000
@@ -132,8 +132,9 @@
 }
 
 static inline u32 *
-encode_fattr(struct svc_rqst *rqstp, u32 *p, struct inode *inode)
+encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
 {
+	struct inode *inode = fhp->fh_dentry->d_inode;
 	int type = (inode->i_mode & S_IFMT);
 
 	*p++ = htonl(nfs_ftypes[type >> 12]);
@@ -153,7 +154,12 @@
 	else
 		*p++ = htonl(0xffffffff);
 	*p++ = htonl((u32) inode->i_blocks);
-	*p++ = htonl((u32) inode->i_dev);
+	if (rqstp->rq_reffh->fh_version == 1 
+	    && rqstp->rq_reffh->fh_fsid_type == 1
+	    && (fhp->fh_export->ex_flags & NFSEXP_FSID))
+		*p++ = htonl((u32) fhp->fh_export->ex_fsid);
+	else
+		*p++ = htonl((u32) inode->i_dev);
 	*p++ = htonl((u32) inode->i_ino);
 	*p++ = htonl((u32) inode->i_atime);
 	*p++ = 0;
@@ -332,7 +338,7 @@
 nfssvc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd_attrstat *resp)
 {
-	p = encode_fattr(rqstp, p, resp->fh.fh_dentry->d_inode);
+	p = encode_fattr(rqstp, p, &resp->fh);
 	return xdr_ressize_check(rqstp, p);
 }
 
@@ -341,7 +347,7 @@
 					struct nfsd_diropres *resp)
 {
 	p = encode_fh(p, &resp->fh);
-	p = encode_fattr(rqstp, p, resp->fh.fh_dentry->d_inode);
+	p = encode_fattr(rqstp, p, &resp->fh);
 	return xdr_ressize_check(rqstp, p);
 }
 
@@ -358,7 +364,7 @@
 nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd_readres *resp)
 {
-	p = encode_fattr(rqstp, p, resp->fh.fh_dentry->d_inode);
+	p = encode_fattr(rqstp, p, &resp->fh);
 	*p++ = htonl(resp->count);
 	p += XDR_QUADLEN(resp->count);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nfsd/vfs.c linux-2.4.20/fs/nfsd/vfs.c
--- linux-2.4.19/fs/nfsd/vfs.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/nfsd/vfs.c	2002-10-29 11:18:38.000000000 +0000
@@ -114,35 +114,31 @@
 	if (isdotent(name, len)) {
 		if (len==1)
 			dentry = dget(dparent);
-		else  { /* must be ".." */
+		else if (dparent != exp->ex_dentry)
+			dentry = dget(dparent->d_parent);
+		else if (!EX_CROSSMNT(exp))
+			dentry = dget(dparent); /* .. == . just like at / */
+		else {
 			/* checking mountpoint crossing is very different when stepping up */
-			if (dparent == exp->ex_dentry) {
-				if (!EX_CROSSMNT(exp))
-					dentry = dget(dparent); /* .. == . just like at / */
-				else
-				{
-					struct svc_export *exp2 = NULL;
-					struct dentry *dp;
-					struct vfsmount *mnt = mntget(exp->ex_mnt);
-					dentry = dget(dparent);
-					while(follow_up(&mnt, &dentry))
-						;
-					dp = dget(dentry->d_parent);
-					dput(dentry);
-					dentry = dp;
-					for ( ; exp2 == NULL && dp->d_parent != dp;
-					      dp=dp->d_parent)
-						exp2 = exp_get(exp->ex_client, dp->d_inode->i_dev, dp->d_inode->i_ino);
-					if (exp2==NULL) {
-						dput(dentry);
-						dentry = dget(dparent);
-					} else {
-						exp = exp2;
-					}
-					mntput(mnt);
-				}
-			} else
-				dentry = dget(dparent->d_parent);
+			struct svc_export *exp2 = NULL;
+			struct dentry *dp;
+			struct vfsmount *mnt = mntget(exp->ex_mnt);
+			dentry = dget(dparent);
+			while(follow_up(&mnt, &dentry))
+				;
+			dp = dget(dentry->d_parent);
+			dput(dentry);
+			dentry = dp;
+			for ( ; exp2 == NULL && dp->d_parent != dp;
+			      dp=dp->d_parent)
+				exp2 = exp_get(exp->ex_client, dp->d_inode->i_dev, dp->d_inode->i_ino);
+			if (exp2==NULL) {
+				dput(dentry);
+				dentry = dget(dparent);
+			} else {
+				exp = exp2;
+			}
+			mntput(mnt);
 		}
 	} else {
 		fh_lock(fhp);
@@ -1497,17 +1493,21 @@
 		inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
 #endif
 
-	/* only care about readonly exports for files and
-	 * directories. links don't have meaningful write access,
-	 * and all else is local to the client
-	 */
-	if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)) 
-		if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) {
-			if (EX_RDONLY(exp) || IS_RDONLY(inode))
-				return nfserr_rofs;
-			if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))
-				return nfserr_perm;
-		}
+	/* The following code is here to make IRIX happy, which
+	 * does a permission check every time a user does
+	 *	echo yaddayadda > special-file
+	 * by sending a CREATE request.
+	 * The original code would check read-only export status
+	 * only for regular files and directories, allowing
+	 * clients to chown/chmod device files and fifos even
+	 * on volumes exported read-only. */
+	if (!(acc & _NFSD_IRIX_BOGOSITY)
+	 && (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC))) {
+		if (EX_RDONLY(exp) || IS_RDONLY(inode))
+			return nfserr_rofs;
+		if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))
+			return nfserr_perm;
+	}
 	if ((acc & MAY_TRUNC) && IS_APPEND(inode))
 		return nfserr_perm;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nls/Config.in linux-2.4.20/fs/nls/Config.in
--- linux-2.4.19/fs/nls/Config.in	2002-02-25 19:38:09.000000000 +0000
+++ linux-2.4.20/fs/nls/Config.in	2002-10-29 11:18:37.000000000 +0000
@@ -12,7 +12,8 @@
 # msdos and Joliet want NLS
 if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \
 	-o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" \
-	-o "$CONFIG_SMB_NLS" = "y" ]; then
+	-o "$CONFIG_SMB_NLS" = "y" -o "$CONFIG_JFS_FS" != "n" \
+	-o "$CONFIG_BEFS_FS" != "n" ]; then
   define_bool CONFIG_NLS y
 else
   define_bool CONFIG_NLS n
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nls/Makefile linux-2.4.20/fs/nls/Makefile
--- linux-2.4.19/fs/nls/Makefile	2001-05-20 00:47:55.000000000 +0000
+++ linux-2.4.20/fs/nls/Makefile	2002-10-29 11:18:34.000000000 +0000
@@ -29,12 +29,6 @@
 obj-$(CONFIG_NLS_CODEPAGE_950)	+= nls_cp950.o nls_big5.o
 obj-$(CONFIG_NLS_CODEPAGE_1250)	+= nls_cp1250.o
 obj-$(CONFIG_NLS_CODEPAGE_1251)	+= nls_cp1251.o
-obj-$(CONFIG_NLS_CODEPAGE_1252)	+= nls_cp1252.o
-obj-$(CONFIG_NLS_CODEPAGE_1253)	+= nls_cp1253.o
-obj-$(CONFIG_NLS_CODEPAGE_1254)	+= nls_cp1254.o
-obj-$(CONFIG_NLS_CODEPAGE_1256)	+= nls_cp1256.o
-obj-$(CONFIG_NLS_CODEPAGE_1257)	+= nls_cp1257.o
-obj-$(CONFIG_NLS_CODEPAGE_1258)	+= nls_cp1258.o
 obj-$(CONFIG_NLS_ISO8859_1)	+= nls_iso8859-1.o
 obj-$(CONFIG_NLS_ISO8859_2)	+= nls_iso8859-2.o
 obj-$(CONFIG_NLS_ISO8859_3)	+= nls_iso8859-3.o
@@ -44,13 +38,11 @@
 obj-$(CONFIG_NLS_ISO8859_7)	+= nls_iso8859-7.o
 obj-$(CONFIG_NLS_ISO8859_8)	+= nls_cp1255.o nls_iso8859-8.o
 obj-$(CONFIG_NLS_ISO8859_9)	+= nls_iso8859-9.o
-obj-$(CONFIG_NLS_ISO8859_10)	+= nls_iso8859-10.o
 obj-$(CONFIG_NLS_ISO8859_13)	+= nls_iso8859-13.o
 obj-$(CONFIG_NLS_ISO8859_14)	+= nls_iso8859-14.o
 obj-$(CONFIG_NLS_ISO8859_15)	+= nls_iso8859-15.o
 obj-$(CONFIG_NLS_KOI8_R)	+= nls_koi8-r.o
 obj-$(CONFIG_NLS_KOI8_U)	+= nls_koi8-u.o nls_koi8-ru.o
-obj-$(CONFIG_NLS_ABC)		+= nls_abc.o
 obj-$(CONFIG_NLS_UTF8)		+= nls_utf8.o
 
 export-objs = $(obj-y)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/nls/nls_cp1250.c linux-2.4.20/fs/nls/nls_cp1250.c
--- linux-2.4.19/fs/nls/nls_cp1250.c	2002-02-25 19:38:09.000000000 +0000
+++ linux-2.4.20/fs/nls/nls_cp1250.c	2002-10-29 11:18:47.000000000 +0000
@@ -344,7 +344,7 @@
 module_init(init_nls_cp1250)
 module_exit(exit_nls_cp1250)
 
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/open.c linux-2.4.20/fs/open.c
--- linux-2.4.19/fs/open.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/open.c	2002-10-29 11:18:32.000000000 +0000
@@ -385,17 +385,8 @@
 {
 	int error;
 	struct nameidata nd;
-	char *name;
 
-	name = getname(filename);
-	error = PTR_ERR(name);
-	if (IS_ERR(name))
-		goto out;
-
-	error = 0;
-	if (path_init(name,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd))
-		error = path_walk(name, &nd);
-	putname(name);
+	error = __user_walk(filename,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd);
 	if (error)
 		goto out;
 
@@ -445,17 +436,9 @@
 {
 	int error;
 	struct nameidata nd;
-	char *name;
-
-	name = getname(filename);
-	error = PTR_ERR(name);
-	if (IS_ERR(name))
-		goto out;
 
-	path_init(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW |
+	error = __user_walk(filename, LOOKUP_POSITIVE | LOOKUP_FOLLOW |
 		      LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
-	error = path_walk(name, &nd);	
-	putname(name);
 	if (error)
 		goto out;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/partitions/Config.in linux-2.4.20/fs/partitions/Config.in
--- linux-2.4.19/fs/partitions/Config.in	2001-08-12 18:13:59.000000000 +0000
+++ linux-2.4.20/fs/partitions/Config.in	2002-10-29 11:18:35.000000000 +0000
@@ -25,15 +25,16 @@
       bool '    Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION
       bool '    Unixware slices support' CONFIG_UNIXWARE_DISKLABEL
    fi
-   dep_bool '  Windows Logical Disk Manager (Dynamic Disk) support' CONFIG_LDM_PARTITION $CONFIG_EXPERIMENTAL
+   dep_bool '  Windows Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL)' CONFIG_LDM_PARTITION $CONFIG_EXPERIMENTAL
    if [ "$CONFIG_LDM_PARTITION" = "y" ]; then
       bool '    Windows LDM extra logging' CONFIG_LDM_DEBUG
    fi
    bool '  SGI partition support' CONFIG_SGI_PARTITION
    bool '  Ultrix partition table support' CONFIG_ULTRIX_PARTITION
    bool '  Sun partition tables support' CONFIG_SUN_PARTITION
+   bool '  EFI GUID Partition support' CONFIG_EFI_PARTITION
 else
-   if [ "$ARCH" = "alpha" ]; then
+   if [ "$CONFIG_ALPHA" = "y" ]; then
       define_bool CONFIG_OSF_PARTITION y
    fi
    if [ "$CONFIG_AMIGA" != "y" -a "$CONFIG_ATARI" != "y" -a \
@@ -64,7 +65,7 @@
    if [ "$CONFIG_DECSTATION" = "y" ]; then
       define_bool CONFIG_ULTRIX_PARTITION y
    fi
-   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
       define_bool CONFIG_SUN_PARTITION y
    fi
 fi
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/partitions/Makefile linux-2.4.20/fs/partitions/Makefile
--- linux-2.4.19/fs/partitions/Makefile	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/partitions/Makefile	2002-10-29 11:18:39.000000000 +0000
@@ -24,6 +24,6 @@
 obj-$(CONFIG_SUN_PARTITION) += sun.o
 obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o
 obj-$(CONFIG_IBM_PARTITION) += ibm.o
+obj-$(CONFIG_EFI_PARTITION) += efi.o
 
 include $(TOPDIR)/Rules.make
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/partitions/check.c linux-2.4.20/fs/partitions/check.c
--- linux-2.4.19/fs/partitions/check.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/partitions/check.c	2002-10-29 11:18:37.000000000 +0000
@@ -33,6 +33,7 @@
 #include "sun.h"
 #include "ibm.h"
 #include "ultrix.h"
+#include "efi.h"
 
 extern int *blk_size[];
 
@@ -42,6 +43,9 @@
 #ifdef CONFIG_ACORN_PARTITION
 	acorn_partition,
 #endif
+#ifdef CONFIG_EFI_PARTITION
+	efi_partition,		/* this must come before msdos */
+#endif
 #ifdef CONFIG_LDM_PARTITION
 	ldm_partition,		/* this must come before msdos */
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/partitions/efi.c linux-2.4.20/fs/partitions/efi.c
--- linux-2.4.19/fs/partitions/efi.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/partitions/efi.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,804 @@
+/************************************************************
+ * EFI GUID Partition Table handling
+ * Per Intel EFI Specification v1.02
+ * http://developer.intel.com/technology/efi/efi.htm
+ * efi.[ch] by Matt Domsch <Matt_Domsch@dell.com>
+ *   Copyright 2000,2001,2002 Dell Computer Corporation
+ *
+ *  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
+ *
+ *
+ * TODO:
+ *
+ * Changelog:
+ * Wed  Mar 27 2002 Matt Domsch <Matt_Domsch@dell.com>
+ * - Ported to 2.5.7-pre1 and 2.4.18
+ * - Applied patch to avoid fault in alternate header handling
+ * - cleaned up find_valid_gpt
+ * - On-disk structure and copy in memory is *always* LE now - 
+ *   swab fields as needed
+ * - remove print_gpt_header()
+ * - only use first max_p partition entries, to keep the kernel minor number
+ *   and partition numbers tied.
+ * - 2.4.18 patch needs own crc32() function - there's no official
+ *   lib/crc32.c in 2.4.x.
+ *
+ * Mon  Feb 04 2002 Matt Domsch <Matt_Domsch@dell.com>
+ * - Removed __PRIPTR_PREFIX - not being used
+ *
+ * Mon  Jan 14 2002 Matt Domsch <Matt_Domsch@dell.com>
+ * - Ported to 2.5.2-pre11 + library crc32 patch Linus applied
+ *
+ * Thu Dec 6 2001 Matt Domsch <Matt_Domsch@dell.com>
+ * - Added compare_gpts().
+ * - moved le_efi_guid_to_cpus() back into this file.  GPT is the only
+ *   thing that keeps EFI GUIDs on disk.
+ * - Changed gpt structure names and members to be simpler and more Linux-like.
+ * 
+ * Wed Oct 17 2001 Matt Domsch <Matt_Domsch@dell.com>
+ * - Removed CONFIG_DEVFS_VOLUMES_UUID code entirely per Martin Wilck
+ *
+ * Wed Oct 10 2001 Matt Domsch <Matt_Domsch@dell.com>
+ * - Changed function comments to DocBook style per Andreas Dilger suggestion.
+ *
+ * Mon Oct 08 2001 Matt Domsch <Matt_Domsch@dell.com>
+ * - Change read_lba() to use the page cache per Al Viro's work.
+ * - print u64s properly on all architectures
+ * - fixed debug_printk(), now Dprintk()
+ *
+ * Mon Oct 01 2001 Matt Domsch <Matt_Domsch@dell.com>
+ * - Style cleanups
+ * - made most functions static
+ * - Endianness addition
+ * - remove test for second alternate header, as it's not per spec,
+ *   and is unnecessary.  There's now a method to read/write the last
+ *   sector of an odd-sized disk from user space.  No tools have ever
+ *   been released which used this code, so it's effectively dead.
+ * - Per Asit Mallick of Intel, added a test for a valid PMBR.
+ * - Added kernel command line option 'gpt' to override valid PMBR test.
+ *
+ * Wed Jun  6 2001 Martin Wilck <Martin.Wilck@Fujitsu-Siemens.com>
+ * - added devfs volume UUID support (/dev/volumes/uuids) for
+ *   mounting file systems by the partition GUID. 
+ *
+ * Tue Dec  5 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Moved crc32() to linux/lib, added efi_crc32().
+ *
+ * Thu Nov 30 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Replaced Intel's CRC32 function with an equivalent
+ *   non-license-restricted version.
+ *
+ * Wed Oct 25 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Fixed the last_lba() call to return the proper last block
+ *
+ * Thu Oct 12 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Thanks to Andries Brouwer for his debugging assistance.
+ * - Code works, detects all the partitions.
+ *
+ ************************************************************/
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+#include "check.h"
+#include "efi.h"
+
+#if CONFIG_BLK_DEV_MD
+extern void md_autodetect_dev(kdev_t dev);
+#endif
+
+/* Handle printing of 64-bit values */
+/* Borrowed from /usr/include/inttypes.h */
+# if BITS_PER_LONG == 64 
+#  define __PRI64_PREFIX	"l"
+# else
+#  define __PRI64_PREFIX	"ll"
+# endif
+# define PRIx64		__PRI64_PREFIX "x"
+
+
+#undef EFI_DEBUG
+#ifdef EFI_DEBUG
+#define Dprintk(x...) printk(KERN_DEBUG x)
+#else
+#define Dprintk(x...)
+#endif
+
+/* This allows a kernel command line option 'gpt' to override
+ * the test for invalid PMBR.  Not __initdata because reloading
+ * the partition tables happens after init too.
+ */
+static int force_gpt;
+static int __init
+force_gpt_fn(char *str)
+{
+	force_gpt = 1;
+	return 1;
+}
+__setup("gpt", force_gpt_fn);
+
+
+/*
+ * There are multiple 16-bit CRC polynomials in common use, but this is
+ * *the* standard CRC-32 polynomial, first popularized by Ethernet.
+ * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
+ */
+#define CRCPOLY_LE 0xedb88320
+/* How many bits at a time to use.  Requires a table of 4<<CRC_xx_BITS bytes. */
+/* For less performance-sensitive, use 4 */
+#define CRC_LE_BITS 8
+static u32 *crc32table_le;
+
+/**
+ * crc32init_le() - allocate and initialize LE table data
+ *
+ * crc is the crc of the byte i; other entries are filled in based on the
+ * fact that crctable[i^j] = crctable[i] ^ crctable[j].
+ *
+ */
+static int __init crc32init_le(void)
+{
+	unsigned i, j;
+	u32 crc = 1;
+
+	crc32table_le =
+	    kmalloc((1 << CRC_LE_BITS) * sizeof(u32), GFP_KERNEL);
+	if (!crc32table_le)
+		return 1;
+	crc32table_le[0] = 0;
+
+	for (i = 1 << (CRC_LE_BITS - 1); i; i >>= 1) {
+		crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+		for (j = 0; j < 1 << CRC_LE_BITS; j += 2 * i)
+			crc32table_le[i + j] = crc ^ crc32table_le[j];
+	}
+	return 0;
+}
+
+/**
+ * crc32cleanup_le(): free LE table data
+ */
+static void __exit crc32cleanup_le(void)
+{
+	if (crc32table_le) kfree(crc32table_le);
+	crc32table_le = NULL;
+}
+
+__initcall(crc32init_le);
+__exitcall(crc32cleanup_le);
+
+/**
+ * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
+ * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
+ *        other uses, or the previous crc32 value if computing incrementally.
+ * @p   - pointer to buffer over which CRC is run
+ * @len - length of buffer @p
+ * 
+ */
+static u32 crc32_le(u32 crc, unsigned char const *p, size_t len)
+{
+	while (len--) {
+		crc = (crc >> 8) ^ crc32table_le[(crc ^ *p++) & 255];
+	}
+	return crc;
+}
+
+
+/**
+ * efi_crc32() - EFI version of crc32 function
+ * @buf: buffer to calculate crc32 of
+ * @len - length of buf
+ *
+ * Description: Returns EFI-style CRC32 value for @buf
+ * 
+ * This function uses the little endian Ethernet polynomial
+ * but seeds the function with ~0, and xor's with ~0 at the end.
+ * Note, the EFI Specification, v1.02, has a reference to
+ * Dr. Dobbs Journal, May 1994 (actually it's in May 1992).
+ */
+static inline u32
+efi_crc32(const void *buf, unsigned long len)
+{
+	return (crc32_le(~0L, buf, len) ^ ~0L);
+}
+
+/**
+ * is_pmbr_valid(): test Protective MBR for validity
+ * @mbr: pointer to a legacy mbr structure
+ *
+ * Description: Returns 1 if PMBR is valid, 0 otherwise.
+ * Validity depends on two things:
+ *  1) MSDOS signature is in the last two bytes of the MBR
+ *  2) One partition of type 0xEE is found
+ */
+static int
+is_pmbr_valid(legacy_mbr *mbr)
+{
+	int i, found = 0, signature = 0;
+	if (!mbr)
+		return 0;
+	signature = (le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE);
+	for (i = 0; signature && i < 4; i++) {
+		if (mbr->partition_record[i].sys_ind ==
+                    EFI_PMBR_OSTYPE_EFI_GPT) {
+			found = 1;
+			break;
+		}
+	}
+	return (signature && found);
+}
+
+/**
+ * last_lba(): return number of last logical block of device
+ * @hd: gendisk with partition list
+ * @bdev: block device
+ * 
+ * Description: Returns last LBA value on success, 0 on error.
+ * This is stored (by sd and ide-geometry) in
+ *  the part[0] entry for this disk, and is the number of
+ *  physical sectors available on the disk.
+ */
+static u64
+last_lba(struct gendisk *hd, struct block_device *bdev)
+{
+	if (!hd || !hd->part || !bdev)
+		return 0;
+	return hd->part[MINOR(to_kdev_t(bdev->bd_dev))].nr_sects - 1;
+}
+
+/**
+ * read_lba(): Read bytes from disk, starting at given LBA
+ * @hd
+ * @bdev
+ * @lba
+ * @buffer
+ * @size_t
+ *
+ * Description:  Reads @count bytes from @bdev into @buffer.
+ * Returns number of bytes read on success, 0 on error.
+ */
+static size_t
+read_lba(struct gendisk *hd, struct block_device *bdev, u64 lba,
+	 u8 * buffer, size_t count)
+{
+
+	size_t totalreadcount = 0, bytesread = 0;
+	unsigned long blocksize;
+	int i;
+	Sector sect;
+	unsigned char *data = NULL;
+
+	if (!hd || !bdev || !buffer || !count)
+		return 0;
+
+	blocksize = get_hardsect_size(to_kdev_t(bdev->bd_dev));
+	if (!blocksize)
+		blocksize = 512;
+
+	for (i = 0; count > 0; i++) {
+		data = read_dev_sector(bdev, lba, &sect);
+		if (!data)
+			return totalreadcount;
+
+		bytesread =
+		    PAGE_CACHE_SIZE - (data -
+				       (unsigned char *) page_address(sect.v));
+		bytesread = min(bytesread, count);
+		memcpy(buffer, data, bytesread);
+		put_dev_sector(sect);
+
+		buffer += bytesread;
+		totalreadcount += bytesread;
+		count -= bytesread;
+		lba += (bytesread / blocksize);
+	}
+	return totalreadcount;
+}
+
+
+/**
+ * alloc_read_gpt_entries(): reads partition entries from disk
+ * @hd
+ * @bdev
+ * @gpt - GPT header
+ * 
+ * Description: Returns ptes on success,  NULL on error.
+ * Allocates space for PTEs based on information found in @gpt.
+ * Notes: remember to free pte when you're done!
+ */
+static gpt_entry *
+alloc_read_gpt_entries(struct gendisk *hd,
+		       struct block_device *bdev, gpt_header *gpt)
+{
+	size_t count;
+	gpt_entry *pte;
+	if (!hd || !bdev || !gpt)
+		return NULL;
+
+	count = le32_to_cpu(gpt->num_partition_entries) *
+                le32_to_cpu(gpt->sizeof_partition_entry);
+	if (!count)
+		return NULL;
+	pte = kmalloc(count, GFP_KERNEL);
+	if (!pte)
+		return NULL;
+	memset(pte, 0, count);
+
+	if (read_lba(hd, bdev, le64_to_cpu(gpt->partition_entry_lba),
+                     (u8 *) pte,
+		     count) < count) {
+		kfree(pte);
+                pte=NULL;
+		return NULL;
+	}
+	return pte;
+}
+
+/**
+ * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk
+ * @hd
+ * @bdev
+ * @lba is the Logical Block Address of the partition table
+ * 
+ * Description: returns GPT header on success, NULL on error.   Allocates
+ * and fills a GPT header starting at @ from @bdev.
+ * Note: remember to free gpt when finished with it.
+ */
+static gpt_header *
+alloc_read_gpt_header(struct gendisk *hd, struct block_device *bdev, u64 lba)
+{
+	gpt_header *gpt;
+	if (!hd || !bdev)
+		return NULL;
+
+	gpt = kmalloc(sizeof (gpt_header), GFP_KERNEL);
+	if (!gpt)
+		return NULL;
+	memset(gpt, 0, sizeof (gpt_header));
+
+	if (read_lba(hd, bdev, lba, (u8 *) gpt,
+		     sizeof (gpt_header)) < sizeof (gpt_header)) {
+		kfree(gpt);
+                gpt=NULL;
+		return NULL;
+	}
+
+	return gpt;
+}
+
+/**
+ * is_gpt_valid() - tests one GPT header and PTEs for validity
+ * @hd
+ * @bdev
+ * @lba is the logical block address of the GPT header to test
+ * @gpt is a GPT header ptr, filled on return.
+ * @ptes is a PTEs ptr, filled on return.
+ *
+ * Description: returns 1 if valid,  0 on error.
+ * If valid, returns pointers to newly allocated GPT header and PTEs.
+ */
+static int
+is_gpt_valid(struct gendisk *hd, struct block_device *bdev, u64 lba,
+	     gpt_header **gpt, gpt_entry **ptes)
+{
+	u32 crc, origcrc;
+
+	if (!hd || !bdev || !gpt || !ptes)
+		return 0;
+	if (!(*gpt = alloc_read_gpt_header(hd, bdev, lba)))
+		return 0;
+
+	/* Check the GUID Partition Table signature */
+	if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
+		Dprintk("GUID Partition Table Header signature is wrong: %"
+			PRIx64 " != %" PRIx64 "\n", le64_to_cpu((*gpt)->signature),
+			GPT_HEADER_SIGNATURE);
+		kfree(*gpt);
+		*gpt = NULL;
+		return 0;
+	}
+
+	/* Check the GUID Partition Table CRC */
+	origcrc = le32_to_cpu((*gpt)->header_crc32);
+	(*gpt)->header_crc32 = 0;
+	crc = efi_crc32((const unsigned char *) (*gpt), le32_to_cpu((*gpt)->header_size));
+
+	if (crc != origcrc) {
+		Dprintk
+		    ("GUID Partition Table Header CRC is wrong: %x != %x\n",
+		     crc, origcrc);
+		kfree(*gpt);
+		*gpt = NULL;
+		return 0;
+	}
+	(*gpt)->header_crc32 = cpu_to_le32(origcrc);
+
+	/* Check that the my_lba entry points to the LBA that contains
+	 * the GUID Partition Table */
+	if (le64_to_cpu((*gpt)->my_lba) != lba) {
+		Dprintk("GPT my_lba incorrect: %" PRIx64 " != %" PRIx64 "\n",
+			le64_to_cpu((*gpt)->my_lba), lba);
+		kfree(*gpt);
+		*gpt = NULL;
+		return 0;
+	}
+
+	if (!(*ptes = alloc_read_gpt_entries(hd, bdev, *gpt))) {
+		kfree(*gpt);
+		*gpt = NULL;
+		return 0;
+	}
+
+	/* Check the GUID Partition Entry Array CRC */
+	crc = efi_crc32((const unsigned char *) (*ptes),
+			le32_to_cpu((*gpt)->num_partition_entries) *
+			le32_to_cpu((*gpt)->sizeof_partition_entry));
+
+	if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
+		Dprintk("GUID Partitition Entry Array CRC check failed.\n");
+		kfree(*gpt);
+		*gpt = NULL;
+		kfree(*ptes);
+		*ptes = NULL;
+		return 0;
+	}
+
+	/* We're done, all's well */
+	return 1;
+}
+
+/**
+ * compare_gpts() - Search disk for valid GPT headers and PTEs
+ * @pgpt is the primary GPT header
+ * @agpt is the alternate GPT header
+ * @lastlba is the last LBA number
+ * Description: Returns nothing.  Sanity checks pgpt and agpt fields
+ * and prints warnings on discrepancies.
+ * 
+ */
+static void
+compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba)
+{
+	int error_found = 0;
+	if (!pgpt || !agpt)
+		return;
+	if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) {
+		printk(KERN_WARNING
+		       "GPT:Primary header LBA != Alt. header alternate_lba\n");
+		printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+		       le64_to_cpu(pgpt->my_lba),
+                       le64_to_cpu(agpt->alternate_lba));
+		error_found++;
+	}
+	if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) {
+		printk(KERN_WARNING
+		       "GPT:Primary header alternate_lba != Alt. header my_lba\n");
+		printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+		       le64_to_cpu(pgpt->alternate_lba),
+                       le64_to_cpu(agpt->my_lba));
+		error_found++;
+	}
+	if (le64_to_cpu(pgpt->first_usable_lba) !=
+            le64_to_cpu(agpt->first_usable_lba)) {
+		printk(KERN_WARNING "GPT:first_usable_lbas don't match.\n");
+		printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+		       le64_to_cpu(pgpt->first_usable_lba),
+                       le64_to_cpu(agpt->first_usable_lba));
+		error_found++;
+	}
+	if (le64_to_cpu(pgpt->last_usable_lba) !=
+            le64_to_cpu(agpt->last_usable_lba)) {
+		printk(KERN_WARNING "GPT:last_usable_lbas don't match.\n");
+		printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+		       le64_to_cpu(pgpt->last_usable_lba),
+                       le64_to_cpu(agpt->last_usable_lba));
+		error_found++;
+	}
+	if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
+		printk(KERN_WARNING "GPT:disk_guids don't match.\n");
+		error_found++;
+	}
+	if (le32_to_cpu(pgpt->num_partition_entries) !=
+            le32_to_cpu(agpt->num_partition_entries)) {
+		printk(KERN_WARNING "GPT:num_partition_entries don't match: "
+		       "0x%x != 0x%x\n",
+		       le32_to_cpu(pgpt->num_partition_entries),
+		       le32_to_cpu(agpt->num_partition_entries));
+		error_found++;
+	}
+	if (le32_to_cpu(pgpt->sizeof_partition_entry) !=
+            le32_to_cpu(agpt->sizeof_partition_entry)) {
+		printk(KERN_WARNING
+		       "GPT:sizeof_partition_entry values don't match: "
+		       "0x%x != 0x%x\n",
+                       le32_to_cpu(pgpt->sizeof_partition_entry),
+		       le32_to_cpu(agpt->sizeof_partition_entry));
+		error_found++;
+	}
+	if (le32_to_cpu(pgpt->partition_entry_array_crc32) !=
+            le32_to_cpu(agpt->partition_entry_array_crc32)) {
+		printk(KERN_WARNING
+		       "GPT:partition_entry_array_crc32 values don't match: "
+		       "0x%x != 0x%x\n",
+                       le32_to_cpu(pgpt->partition_entry_array_crc32),
+		       le32_to_cpu(agpt->partition_entry_array_crc32));
+		error_found++;
+	}
+	if (le64_to_cpu(pgpt->alternate_lba) != lastlba) {
+		printk(KERN_WARNING
+		       "GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
+		printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+		       le64_to_cpu(pgpt->alternate_lba), lastlba);
+		error_found++;
+	}
+
+	if (le64_to_cpu(agpt->my_lba) != lastlba) {
+		printk(KERN_WARNING
+		       "GPT:Alternate GPT header not at the end of the disk.\n");
+		printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+		       le64_to_cpu(agpt->my_lba), lastlba);
+		error_found++;
+	}
+
+	if (error_found)
+		printk(KERN_WARNING
+		       "GPT: Use GNU Parted to correct GPT errors.\n");
+	return;
+}
+
+/**
+ * find_valid_gpt() - Search disk for valid GPT headers and PTEs
+ * @hd
+ * @bdev
+ * @gpt is a GPT header ptr, filled on return.
+ * @ptes is a PTEs ptr, filled on return.
+ * Description: Returns 1 if valid, 0 on error.
+ * If valid, returns pointers to newly allocated GPT header and PTEs.
+ * Validity depends on finding either the Primary GPT header and PTEs valid,
+ * or the Alternate GPT header and PTEs valid, and the PMBR valid.
+ */
+static int
+find_valid_gpt(struct gendisk *hd, struct block_device *bdev,
+	       gpt_header **gpt, gpt_entry **ptes)
+{
+	int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
+	gpt_header *pgpt = NULL, *agpt = NULL;
+	gpt_entry *pptes = NULL, *aptes = NULL;
+	legacy_mbr *legacymbr = NULL;
+	u64 lastlba;
+	if (!hd || !bdev || !gpt || !ptes)
+		return 0;
+
+	lastlba = last_lba(hd, bdev);
+	good_pgpt = is_gpt_valid(hd, bdev, GPT_PRIMARY_PARTITION_TABLE_LBA,
+				 &pgpt, &pptes);
+        if (good_pgpt) {
+		good_agpt = is_gpt_valid(hd, bdev,
+                                         le64_to_cpu(pgpt->alternate_lba),
+					 &agpt, &aptes);
+                if (!good_agpt) {
+                        good_agpt = is_gpt_valid(hd, bdev, lastlba,
+                                                 &agpt, &aptes);
+                }
+        }
+        else {
+                good_agpt = is_gpt_valid(hd, bdev, lastlba,
+                                         &agpt, &aptes);
+        }
+
+        /* The obviously unsuccessful case */
+        if (!good_pgpt && !good_agpt) {
+                goto fail;
+        }
+
+	/* This will be added to the EFI Spec. per Intel after v1.02. */
+        legacymbr = kmalloc(sizeof (*legacymbr), GFP_KERNEL);
+        if (legacymbr) {
+                memset(legacymbr, 0, sizeof (*legacymbr));
+                read_lba(hd, bdev, 0, (u8 *) legacymbr,
+                         sizeof (*legacymbr));
+                good_pmbr = is_pmbr_valid(legacymbr);
+                kfree(legacymbr);
+                legacymbr=NULL;
+        }
+
+        /* Failure due to bad PMBR */
+        if ((good_pgpt || good_agpt) && !good_pmbr && !force_gpt) {
+                printk(KERN_WARNING 
+                       "  Warning: Disk has a valid GPT signature "
+                       "but invalid PMBR.\n");
+                printk(KERN_WARNING
+                       "  Assuming this disk is *not* a GPT disk anymore.\n");
+                printk(KERN_WARNING
+                       "  Use gpt kernel option to override.  "
+                       "Use GNU Parted to correct disk.\n");
+                goto fail;
+        }
+
+        /* Would fail due to bad PMBR, but force GPT anyhow */
+        if ((good_pgpt || good_agpt) && !good_pmbr && force_gpt) {
+                printk(KERN_WARNING
+                       "  Warning: Disk has a valid GPT signature but "
+                       "invalid PMBR.\n");
+                printk(KERN_WARNING
+                       "  Use GNU Parted to correct disk.\n");
+                printk(KERN_WARNING
+                       "  gpt option taken, disk treated as GPT.\n");
+        }
+
+        compare_gpts(pgpt, agpt, lastlba);
+
+        /* The good cases */
+        if (good_pgpt && (good_pmbr || force_gpt)) {
+                *gpt  = pgpt;
+                *ptes = pptes;
+                if (agpt)  { kfree(agpt);   agpt = NULL; }
+                if (aptes) { kfree(aptes); aptes = NULL; }
+                if (!good_agpt) {
+                        printk(KERN_WARNING 
+			       "Alternate GPT is invalid, "
+                               "using primary GPT.\n");
+                }
+                return 1;
+        }
+        else if (good_agpt && (good_pmbr || force_gpt)) {
+                *gpt  = agpt;
+                *ptes = aptes;
+                if (pgpt)  { kfree(pgpt);   pgpt = NULL; }
+                if (pptes) { kfree(pptes); pptes = NULL; }
+                printk(KERN_WARNING 
+                       "Primary GPT is invalid, using alternate GPT.\n");
+                return 1;
+        }
+
+ fail:
+        if (pgpt)  { kfree(pgpt);   pgpt=NULL; }
+        if (agpt)  { kfree(agpt);   agpt=NULL; }
+        if (pptes) { kfree(pptes); pptes=NULL; }
+        if (aptes) { kfree(aptes); aptes=NULL; }
+        *gpt = NULL;
+        *ptes = NULL;
+        return 0;
+}
+
+/**
+ * add_gpt_partitions(struct gendisk *hd, struct block_device *bdev,
+ * @hd
+ * @bdev
+ *
+ * Description: Create devices for each entry in the GUID Partition Table
+ * Entries.
+ *
+ * We do not create a Linux partition for GPT, but
+ * only for the actual data partitions.
+ * Returns:
+ * -1 if unable to read the partition table
+ *  0 if this isn't our partition table
+ *  1 if successful
+ *
+ */
+static int
+add_gpt_partitions(struct gendisk *hd, struct block_device *bdev, int nextminor)
+{
+	gpt_header *gpt = NULL;
+	gpt_entry *ptes = NULL;
+	u32 i;
+	int max_p; 
+
+	if (!hd || !bdev)
+		return -1;
+
+	if (!find_valid_gpt(hd, bdev, &gpt, &ptes) || !gpt || !ptes) {
+		if (gpt) {
+			kfree(gpt);
+                        gpt = NULL;
+                }
+		if (ptes) {
+			kfree(ptes);
+                        ptes = NULL;
+                }
+		return 0;
+	}
+
+	Dprintk("GUID Partition Table is valid!  Yea!\n");
+
+	max_p = (1 << hd->minor_shift) - 1;
+	for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < max_p; i++) {
+		if (!efi_guidcmp(ptes[i].partition_type_guid, NULL_GUID))
+			continue;
+
+		add_gd_partition(hd, nextminor+i,
+                                 le64_to_cpu(ptes[i].starting_lba),
+				 (le64_to_cpu(ptes[i].ending_lba) -
+                                  le64_to_cpu(ptes[i].starting_lba) +
+				  1));
+
+		/* If there's this is a RAID volume, tell md */
+#if CONFIG_BLK_DEV_MD
+		if (!efi_guidcmp(ptes[i].partition_type_guid,
+                                 PARTITION_LINUX_RAID_GUID)) {
+                        md_autodetect_dev(MKDEV
+                                          (MAJOR(to_kdev_t(bdev->bd_dev)),
+                                           nextminor+i));
+		}
+#endif
+	}
+	kfree(ptes);
+        ptes=NULL;
+	kfree(gpt);
+        gpt=NULL;
+	printk("\n");
+	return 1;
+}
+
+/**
+ * efi_partition(): EFI GPT partition handling entry function
+ * @hd
+ * @bdev
+ * @first_sector: unused
+ * @first_part_minor: minor number assigned to first GPT partition found
+ *
+ * Description: called from check.c, if the disk contains GPT
+ * partitions, sets up partition entries in the kernel.
+ *
+ * If the first block on the disk is a legacy MBR,
+ * it will get handled by msdos_partition().
+ * If it's a Protective MBR, we'll handle it here.
+ *
+ * set_blocksize() calls are necessary to be able to read
+ * a disk with an odd number of 512-byte sectors, as the
+ * default BLOCK_SIZE of 1024 bytes won't let that last
+ * sector be read otherwise.
+ *
+ * Returns:
+ * -1 if unable to read the partition table
+ *  0 if this isn't our partitoin table
+ *  1 if successful
+ */
+int
+efi_partition(struct gendisk *hd, struct block_device *bdev,
+	      unsigned long first_sector, int first_part_minor)
+{
+
+	kdev_t dev = to_kdev_t(bdev->bd_dev);
+	int hardblocksize = get_hardsect_size(dev);
+	int orig_blksize_size = BLOCK_SIZE;
+	int rc = 0;
+
+	/* Need to change the block size that the block layer uses */
+	if (blksize_size[MAJOR(dev)]) {
+                orig_blksize_size = blksize_size[MAJOR(dev)][MINOR(dev)];
+	}
+
+	if (orig_blksize_size != hardblocksize)
+		set_blocksize(dev, hardblocksize);
+
+	rc = add_gpt_partitions(hd, bdev, first_part_minor);
+
+	/* change back */
+	if (orig_blksize_size != hardblocksize)
+		set_blocksize(dev, orig_blksize_size);
+
+	return rc;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/partitions/efi.h linux-2.4.20/fs/partitions/efi.h
--- linux-2.4.19/fs/partitions/efi.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/partitions/efi.h	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,115 @@
+/************************************************************
+ * EFI GUID Partition Table
+ * Per Intel EFI Specification v1.02
+ * http://developer.intel.com/technology/efi/efi.htm
+ *
+ * By Matt Domsch <Matt_Domsch@dell.com>  Fri Sep 22 22:15:56 CDT 2000  
+ *   Copyright 2000,2001 Dell Computer Corporation
+ *
+ *  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
+ * 
+ ************************************************************/
+
+#ifndef FS_PART_EFI_H_INCLUDED
+#define FS_PART_EFI_H_INCLUDED
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/efi.h>
+
+#define MSDOS_MBR_SIGNATURE 0xaa55
+#define EFI_PMBR_OSTYPE_EFI 0xEF
+#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
+
+#define GPT_BLOCK_SIZE 512
+#define GPT_HEADER_SIGNATURE 0x5452415020494645L
+#define GPT_HEADER_REVISION_V1 0x00010000
+#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
+
+#define PARTITION_SYSTEM_GUID \
+    EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \
+              0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B) 
+#define LEGACY_MBR_PARTITION_GUID \
+    EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \
+              0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F)
+#define PARTITION_MSFT_RESERVED_GUID \
+    EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \
+              0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE)
+#define PARTITION_BASIC_DATA_GUID \
+    EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \
+              0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7)
+#define PARTITION_LINUX_RAID_GUID \
+    EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \
+              0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e)
+#define PARTITION_LINUX_SWAP_GUID \
+    EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \
+              0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f)
+#define PARTITION_LINUX_LVM_GUID \
+    EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \
+              0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
+
+typedef struct _gpt_header {
+	u64 signature;
+	u32 revision;
+	u32 header_size;
+	u32 header_crc32;
+	u32 reserved1;
+	u64 my_lba;
+	u64 alternate_lba;
+	u64 first_usable_lba;
+	u64 last_usable_lba;
+	efi_guid_t disk_guid;
+	u64 partition_entry_lba;
+	u32 num_partition_entries;
+	u32 sizeof_partition_entry;
+	u32 partition_entry_array_crc32;
+	u8 reserved2[GPT_BLOCK_SIZE - 92];
+} __attribute__ ((packed)) gpt_header;
+
+typedef struct _gpt_entry_attributes {
+	u64 required_to_function:1;
+	u64 reserved:47;
+        u64 type_guid_specific:16;
+} __attribute__ ((packed)) gpt_entry_attributes;
+
+typedef struct _gpt_entry {
+	efi_guid_t partition_type_guid;
+	efi_guid_t unique_partition_guid;
+	u64 starting_lba;
+	u64 ending_lba;
+	gpt_entry_attributes attributes;
+	efi_char16_t partition_name[72 / sizeof (efi_char16_t)];
+} __attribute__ ((packed)) gpt_entry;
+
+typedef struct _legacy_mbr {
+	u8 boot_code[440];
+	u32 unique_mbr_signature;
+	u16 unknown;
+	struct partition partition_record[4];
+	u16 signature;
+} __attribute__ ((packed)) legacy_mbr;
+
+/* Functions */
+extern int
+ efi_partition(struct gendisk *hd, struct block_device *bdev,
+	      unsigned long first_sector, int first_part_minor);
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/partitions/ldm.c linux-2.4.20/fs/partitions/ldm.c
--- linux-2.4.19/fs/partitions/ldm.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/partitions/ldm.c	2002-10-29 11:18:37.000000000 +0000
@@ -1,1074 +1,1543 @@
-/*
- * ldm - Part of the Linux-NTFS project.
+/**
+ * ldm - Support for Windows Logical Disk Manager (Dynamic Disks)
  *
- * Copyright (C) 2001 Richard Russon <ldm@flatcap.org>
- * Copyright (C) 2001 Anton Altaparmakov <antona@users.sf.net> (AIA)
+ * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
+ * Copyright (C) 2001      Anton Altaparmakov <aia21@cantab.net>
+ * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
  *
  * Documentation is available at http://linux-ntfs.sf.net/ldm
  *
- * 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 (in the main directory of the Linux-NTFS source
- * in the file COPYING); if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * 28/10/2001 - Added sorting of ldm partitions. (AIA)
- */
-#include <linux/types.h>
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-#include <linux/genhd.h>
-#include <linux/blkdev.h>
+ * 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 (in the main directory of the source in the file COPYING); if
+ * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA  02111-1307  USA
+ */
+
 #include <linux/slab.h>
+#include <linux/stringify.h>
 #include <linux/pagemap.h>
-#include "check.h"
 #include "ldm.h"
+#include "check.h"
 #include "msdos.h"
 
-#if 0 /* Fool kernel-doc since it doesn't do macros yet. */
+typedef enum {
+	FALSE = 0,
+	TRUE  = 1
+} BOOL;
+
 /**
- * ldm_debug - output an error message if debugging was enabled at compile time
- * @f:		a printf format string containing the message
- * @...:	the variables to substitute into @f
+ * ldm_debug/info/error/crit - Output an error message
+ * @f:    A printf format string containing the message
+ * @...:  Variables to substitute into @f
  *
  * ldm_debug() writes a DEBUG level message to the syslog but only if the
  * driver was compiled with debug enabled. Otherwise, the call turns into a NOP.
  */
-static void ldm_debug(const char *f, ...);
+#ifndef CONFIG_LDM_DEBUG
+#define ldm_debug(...)	do {} while (0)
+#else
+#define ldm_debug(f, a...) _ldm_printk (KERN_DEBUG, __FUNCTION__, f, ##a)
 #endif
-#ifdef CONFIG_LDM_DEBUG
-#define ldm_debug(f, a...)						\
-	{								\
-		printk(LDM_DEBUG " DEBUG (%s, %d): %s: ",		\
-				__FILE__, __LINE__, __FUNCTION__);	\
-		printk(f, ##a);						\
-	}
-#else	/* !CONFIG_LDM_DEBUG */
-#define ldm_debug(f, a...)	do {} while (0)
-#endif	/* !CONFIG_LDM_DEBUG */
 
-/* Necessary forward declarations. */
-static int create_partition(struct gendisk *, int, int, int);
-static int parse_privhead(const u8 *, struct privhead *);
-static u64 get_vnum(const u8 *, int *);
-static int get_vstr(const u8 *, u8 *, const int);
+#define ldm_crit(f, a...)  _ldm_printk (KERN_CRIT,  __FUNCTION__, f, ##a)
+#define ldm_error(f, a...) _ldm_printk (KERN_ERR,   __FUNCTION__, f, ##a)
+#define ldm_info(f, a...)  _ldm_printk (KERN_INFO,  __FUNCTION__, f, ##a)
+
+__attribute__ ((format (printf, 3, 4)))
+static void _ldm_printk (const char *level, const char *function,
+			 const char *fmt, ...)
+{
+	static char buf[128];
+	va_list args;
+
+	va_start (args, fmt);
+	vsnprintf (buf, sizeof (buf), fmt, args);
+	va_end (args);
+
+	printk ("%s%s(): %s\n", level, function, buf);
+}
+
 
 /**
- * parse_vblk_part - parse a LDM database vblk partition record
- * @buffer:	vblk partition record loaded from the LDM database
- * @buf_size:	size of @buffer in bytes
- * @vb:		in memory vblk structure to return parsed information in
+ * ldm_parse_hexbyte - Convert a ASCII hex number to a byte
+ * @src:  Pointer to at least 2 characters to convert.
  *
- * This parses the LDM database vblk record of type VBLK_PART, i.e. a partition
- * record, supplied in @buffer and sets up the in memory vblk structure @vb
- * with the obtained information.
+ * Convert a two character ASCII hex string to a number.
  *
- * Return 1 on success and -1 on error, in which case @vb is undefined.
+ * Return:  0-255  Success, the byte was parsed correctly
+ *          -1     Error, an invalid character was supplied
  */
-static int parse_vblk_part(const u8 *buffer, const int buf_size,
-		struct vblk *vb)
+static int ldm_parse_hexbyte (const u8 *src)
 {
-	int err, rel_objid, rel_name, rel_size, rel_parent;
+	unsigned int x;		/* For correct wrapping */
+	int h;
 
-	if (0x34 >= buf_size)
-		return -1;
-	/* Calculate relative offsets. */
-	rel_objid  = 1 + buffer[0x18];
-	if (0x18 + rel_objid >= buf_size)
-		return -1;
-	rel_name   = 1 + buffer[0x18 + rel_objid] + rel_objid;
-	if (0x34 + rel_name >= buf_size)
-		return -1;
-	rel_size   = 1 + buffer[0x34 + rel_name] + rel_name;
-	if (0x34 + rel_size >= buf_size)
-		return -1;
-	rel_parent = 1 + buffer[0x34 + rel_size] + rel_size;
-	if (0x34 + rel_parent >= buf_size)
-		return -1;
-	/* Setup @vb. */
-	vb->vblk_type    = VBLK_PART;
-	vb->obj_id       = get_vnum(buffer + 0x18, &err);
-	if (err || 0x34 + rel_parent + buffer[0x34 + rel_parent] >= buf_size)
-		return -1;
-	vb->disk_id      = get_vnum(buffer + 0x34 + rel_parent, &err);
-	if (err || 0x24 + rel_name + 8 > buf_size)
-		return -1;
-	vb->start_sector = BE64(buffer + 0x24 + rel_name);
-	if (0x34 + rel_name + buffer[0x34 + rel_name] >= buf_size)
-		return -1;
-	vb->num_sectors  = get_vnum(buffer + 0x34 + rel_name, &err);
-	if (err || 0x18 + rel_objid + buffer[0x18 + rel_objid] >= buf_size)
-		return -1;
-	err = get_vstr(buffer + 0x18 + rel_objid, vb->name, sizeof(vb->name));
-	if (err == -1)
-		return err;
-	ldm_debug("Parsed Partition VBLK successfully.\n");
-	return 1;
+	/* high part */
+	if      ((x = src[0] - '0') <= '9'-'0') h = x;
+	else if ((x = src[0] - 'a') <= 'f'-'a') h = x+10;
+	else if ((x = src[0] - 'A') <= 'F'-'A') h = x+10;
+	else return -1;
+	h <<= 4;
+
+	/* low part */
+	if ((x = src[1] - '0') <= '9'-'0') return h | x;
+	if ((x = src[1] - 'a') <= 'f'-'a') return h | (x+10);
+	if ((x = src[1] - 'A') <= 'F'-'A') return h | (x+10);
+	return -1;
 }
 
 /**
- * parse_vblk - parse a LDM database vblk record
- * @buffer:	vblk record loaded from the LDM database
- * @buf_size:	size of @buffer in bytes
- * @vb:		in memory vblk structure to return parsed information in
+ * ldm_parse_guid - Convert GUID from ASCII to binary
+ * @src:   36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
+ * @dest:  Memory block to hold binary GUID (16 bytes)
+ *
+ * N.B. The GUID need not be NULL terminated.
  *
- * This parses the LDM database vblk record supplied in @buffer and sets up
- * the in memory vblk structure @vb with the obtained information.
+ * Return:  TRUE   @dest contains binary GUID
+ *          FALSE  @dest contents are undefined
+ */
+static BOOL ldm_parse_guid (const u8 *src, u8 *dest)
+{
+	static const int size[] = { 4, 2, 2, 2, 6 };
+	int i, j, v;
+
+	if (src[8]  != '-' || src[13] != '-' ||
+	    src[18] != '-' || src[23] != '-')
+		return FALSE;
+
+	for (j = 0; j < 5; j++, src++)
+		for (i = 0; i < size[j]; i++, src+=2, *dest++ = v)
+			if ((v = ldm_parse_hexbyte (src)) < 0)
+				return FALSE;
+
+	return TRUE;
+}
+
+
+/**
+ * ldm_parse_privhead - Read the LDM Database PRIVHEAD structure
+ * @data:  Raw database PRIVHEAD structure loaded from the device
+ * @ph:    In-memory privhead structure in which to return parsed information
  *
- * Return 1 on success, 0 if successful but record not in use, and -1 on error.
- * If the return value is 0 or -1, @vb is undefined.
+ * This parses the LDM database PRIVHEAD structure supplied in @data and
+ * sets up the in-memory privhead structure @ph with the obtained information.
  *
- * NOTE: Currently the only record type we handle is VBLK_PART, i.e. records
- * describing a partition. For all others, we just set @vb->vblk_type to 0 and
- * return success. This of course means that if @vb->vblk_type is zero, all
- * other fields in @vb are undefined.
+ * Return:  TRUE   @ph contains the PRIVHEAD data
+ *          FALSE  @ph contents are undefined
  */
-static int parse_vblk(const u8 *buffer, const int buf_size, struct vblk *vb)
+static BOOL ldm_parse_privhead (const u8 *data, struct privhead *ph)
 {
-	int err = 1;
+	BUG_ON (!data);
+	BUG_ON (!ph);
 
-	if (buf_size < 0x14)
-		return -1;
-	if (MAGIC_VBLK != BE32(buffer)) {
-		printk(LDM_CRIT "Cannot find VBLK, database may be corrupt.\n");
-		return -1;
+	if (MAGIC_PRIVHEAD != BE64 (data)) {
+		ldm_error ("Cannot find PRIVHEAD structure. LDM database is"
+			" corrupt. Aborting.");
+		return FALSE;
 	}
-	if ((BE16(buffer + 0x0E) == 0) ||       /* Record is not in use. */
-	    (BE16(buffer + 0x0C) != 0))         /* Part 2 of an ext. record */
-		return 0;
-	/* FIXME: What about extended VBLKs? */
-	switch (buffer[0x13]) {
-	case VBLK_PART:
-		err = parse_vblk_part(buffer, buf_size, vb);
-		break;
-	default:
-		vb->vblk_type = 0;
+
+	ph->ver_major          = BE16 (data + 0x000C);
+	ph->ver_minor          = BE16 (data + 0x000E);
+	ph->logical_disk_start = BE64 (data + 0x011B);
+	ph->logical_disk_size  = BE64 (data + 0x0123);
+	ph->config_start       = BE64 (data + 0x012B);
+	ph->config_size        = BE64 (data + 0x0133);
+
+	if ((ph->ver_major != 2) || (ph->ver_minor != 11)) {
+		ldm_error ("Expected PRIVHEAD version %d.%d, got %d.%d."
+			" Aborting.", 2, 11, ph->ver_major, ph->ver_minor);
+		return FALSE;
+	}
+	if (ph->config_size != LDM_DB_SIZE) {	/* 1 MiB in sectors. */
+		/* Warn the user and continue, carefully */
+		ldm_info ("Database is normally %u bytes, it claims to "
+			"be %llu bytes.", LDM_DB_SIZE,
+			(unsigned long long)ph->config_size );
+	}
+	if ((ph->logical_disk_size == 0) ||
+	    (ph->logical_disk_start + ph->logical_disk_size > ph->config_start)) {
+		ldm_error ("PRIVHEAD disk size doesn't match real disk size");
+		return FALSE;
+	}
+
+	if (!ldm_parse_guid (data + 0x0030, ph->disk_id)) {
+		ldm_error ("PRIVHEAD contains an invalid GUID.");
+		return FALSE;
 	}
-	if (err != -1)
-		ldm_debug("Parsed VBLK successfully.\n");
-	return err;
+
+	ldm_debug ("Parsed PRIVHEAD successfully.");
+	return TRUE;
 }
 
 /**
- * add_partition_to_list - insert partition into a partition list
- * @pl:		sorted list of partitions
- * @hd:		gendisk structure to which the data partition belongs
- * @disk_minor:	minor number of the disk device
- * @start:	first sector within the disk device
- * @size:	number of sectors on the partition device
+ * ldm_parse_tocblock - Read the LDM Database TOCBLOCK structure
+ * @data:  Raw database TOCBLOCK structure loaded from the device
+ * @toc:   In-memory toc structure in which to return parsed information
  *
- * This sanity checks the partition specified by @start and @size against the
- * device specified by @hd and inserts the partition into the sorted partition
- * list @pl if the checks pass.
+ * This parses the LDM Database TOCBLOCK (table of contents) structure supplied
+ * in @data and sets up the in-memory tocblock structure @toc with the obtained
+ * information.
  *
- * On success return 1, otherwise return -1.
+ * N.B.  The *_start and *_size values returned in @toc are not range-checked.
  *
- * TODO: Add sanity check for overlapping partitions. (AIA)
- */ 
-static int add_partition_to_list(struct list_head *pl, const struct gendisk *hd,
-		const int disk_minor, const unsigned long start,
-		const unsigned long size)
+ * Return:  TRUE   @toc contains the TOCBLOCK data
+ *          FALSE  @toc contents are undefined
+ */
+static BOOL ldm_parse_tocblock (const u8 *data, struct tocblock *toc)
 {
-	struct ldm_part *lp, *lptmp;
-	struct list_head *tmp;
+	BUG_ON (!data);
+	BUG_ON (!toc);
 
-	if (!hd->part)
-		return -1;
-	if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) {
-		printk(LDM_CRIT "LDM partition exceeds physical disk. "
-				"Skipping.\n");
-		return -1;
+	if (MAGIC_TOCBLOCK != BE64 (data)) {
+		ldm_crit ("Cannot find TOCBLOCK, database may be corrupt.");
+		return FALSE;
+	}
+	strncpy (toc->bitmap1_name, data + 0x24, sizeof (toc->bitmap1_name));
+	toc->bitmap1_name[sizeof (toc->bitmap1_name) - 1] = 0;
+	toc->bitmap1_start = BE64 (data + 0x2E);
+	toc->bitmap1_size  = BE64 (data + 0x36);
+
+	if (strncmp (toc->bitmap1_name, TOC_BITMAP1,
+			sizeof (toc->bitmap1_name)) != 0) {
+		ldm_crit ("TOCBLOCK's first bitmap is '%s', should be '%s'.",
+				TOC_BITMAP1, toc->bitmap1_name);
+		return FALSE;
+	}
+	strncpy (toc->bitmap2_name, data + 0x46, sizeof (toc->bitmap2_name));
+	toc->bitmap2_name[sizeof (toc->bitmap2_name) - 1] = 0;
+	toc->bitmap2_start = BE64 (data + 0x50);
+	toc->bitmap2_size  = BE64 (data + 0x58);
+	if (strncmp (toc->bitmap2_name, TOC_BITMAP2,
+			sizeof (toc->bitmap2_name)) != 0) {
+		ldm_crit ("TOCBLOCK's second bitmap is '%s', should be '%s'.",
+				TOC_BITMAP2, toc->bitmap2_name);
+		return FALSE;
 	}
-	lp = (struct ldm_part*)kmalloc(sizeof(struct ldm_part), GFP_KERNEL);
-	if (!lp) {
-		printk(LDM_CRIT "Not enough memory! Aborting LDM partition "
-				"parsing.\n");
-		return -2;
-	}
-	INIT_LIST_HEAD(&lp->part_list);
-	lp->start = start;
-	lp->size = size;
-	list_for_each(tmp, pl) {
-		lptmp = list_entry(tmp, struct ldm_part, part_list);
-		if (start > lptmp->start)
-			continue;
-		if (start < lptmp->start)
-			break;
-		printk(LDM_CRIT "Duplicate LDM partition entry! Skipping.\n");
-		kfree(lp);
-		return -1;
-	}
-	list_add_tail(&lp->part_list, tmp);
-	ldm_debug("Added LDM partition successfully.\n");
-	return 1;
+	ldm_debug ("Parsed TOCBLOCK successfully.");
+	return TRUE;
 }
 
 /**
- * create_data_partitions - create the data partition devices
- * @hd:			gendisk structure in which to create the data partitions
- * @first_sector:	first sector within the disk device
- * @first_part_minor:	first minor number of data partition devices
- * @dev:		partition device holding the LDM database
- * @vm:			in memory vmdb structure of @dev
- * @ph:			in memory privhead structure of the disk device
- * @dk:			in memory ldmdisk structure of the disk device
+ * ldm_parse_vmdb - Read the LDM Database VMDB structure
+ * @data:  Raw database VMDB structure loaded from the device
+ * @vm:    In-memory vmdb structure in which to return parsed information
  *
- * The database contains ALL the partitions for ALL the disks, so we need to
- * filter out this specific disk. Using the disk's object id, we can find all
- * the partitions in the database that belong to this disk.
+ * This parses the LDM Database VMDB structure supplied in @data and sets up
+ * the in-memory vmdb structure @vm with the obtained information.
+ *
+ * N.B.  The *_start, *_size and *_seq values will be range-checked later.
  *
- * For each found partition, we create a corresponding partition device starting
- * with minor number @first_part_minor. But we do this in such a way that we
- * actually sort the partitions in order of on-disk position. Any invalid
- * partitions are completely ignored/skipped (an error is output but that's
- * all).
- *
- * Return 1 on success and -1 on error.
- */
-static int create_data_partitions(struct gendisk *hd,
-		const unsigned long first_sector, int first_part_minor,
-		struct block_device *bdev, const struct vmdb *vm,
-		const struct privhead *ph, const struct ldmdisk *dk,
-		unsigned long base)
+ * Return:  TRUE   @vm contains VMDB info
+ *          FALSE  @vm contents are undefined
+ */
+static BOOL ldm_parse_vmdb (const u8 *data, struct vmdb *vm)
 {
-	Sector sect;
-	unsigned char *data;
-	struct vblk *vb;
-	LIST_HEAD(pl);		/* Sorted list of partitions. */
-	struct ldm_part *lp;
-	struct list_head *tmp;
-	int vblk;
-	int vsize;		/* VBLK size. */
-	int perbuf;		/* VBLKs per buffer. */
-	int buffer, lastbuf, lastofs, err, disk_minor;
-
-	vb = (struct vblk*)kmalloc(sizeof(struct vblk), GFP_KERNEL);
-	if (!vb)
-		goto no_mem;
-	vsize   = vm->vblk_size;
-	if (vsize < 1 || vsize > 512)
-		goto err_out;
-	perbuf  = 512 / vsize;
-	if (perbuf < 1 || 512 % vsize)
-		goto err_out;
-					/* 512 == VMDB size */
-	lastbuf = vm->last_vblk_seq / perbuf - 1;
-	lastofs = vm->last_vblk_seq % perbuf;
-	if (lastofs)
-		lastbuf++;
-	if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize >
-			ph->config_size * 512)
-		goto err_out;
-	/*
-	 * Get the minor number of the parent device so we can check we don't
-	 * go beyond the end of the device.
-	 */
-	disk_minor = (first_part_minor >> hd->minor_shift) << hd->minor_shift;
-	for (buffer = 0; buffer < lastbuf; buffer++) {
-		data = read_dev_sector(bdev, base + 2*OFF_VBLK + buffer, &sect);
-		if (!data)
-			goto read_err;
-		for (vblk = 0; vblk < perbuf; vblk++) {
-			u8 *block;
-			
-			if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs)
-				break;
-			block = data + vsize * vblk;
-			if (block + vsize > data + 512)
-				goto brelse_out;
-			if (parse_vblk(block, vsize, vb) != 1)
-				continue;
-			if (vb->vblk_type != VBLK_PART)
-				continue;
-			if (dk->obj_id != vb->disk_id)
-				continue;
-			/* Ignore invalid partition errors. */
-			if (add_partition_to_list(&pl, hd, disk_minor,
-					first_sector + vb->start_sector +
-					ph->logical_disk_start,
-					vb->num_sectors) < -1)
-				goto brelse_out;
-		}
-		put_dev_sector(sect);
+	BUG_ON (!data);
+	BUG_ON (!vm);
+
+	if (MAGIC_VMDB != BE32 (data)) {
+		ldm_crit ("Cannot find the VMDB, database may be corrupt.");
+		return FALSE;
 	}
-	err = 1;
-out:
-	/* Finally create the nicely sorted data partitions. */
-	printk(" <");
-	list_for_each(tmp, &pl) {
-		lp = list_entry(tmp, struct ldm_part, part_list);
-		add_gd_partition(hd, first_part_minor++, lp->start, lp->size);
-	}
-	printk(" >\n");
-	if (!list_empty(&pl)) {
-		struct list_head *tmp2;
-
-		/* Cleanup the partition list which is now superfluous. */
-		list_for_each_safe(tmp, tmp2, &pl) {
-			lp = list_entry(tmp, struct ldm_part, part_list);
-			list_del(tmp);
-			kfree(lp);
-		}
+
+	vm->ver_major = BE16 (data + 0x12);
+	vm->ver_minor = BE16 (data + 0x14);
+	if ((vm->ver_major != 4) || (vm->ver_minor != 10)) {
+		ldm_error ("Expected VMDB version %d.%d, got %d.%d. "
+			"Aborting.", 4, 10, vm->ver_major, vm->ver_minor);
+		return FALSE;
 	}
-	kfree(vb);
-	return err;
-brelse_out:
-	put_dev_sector(sect);
-	goto err_out;
-no_mem:
-	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
-	goto err_out;
-read_err:
-	printk(LDM_CRIT "Disk read failed in create_partitions.\n");
-err_out:
-	err = -1;
-	goto out;
+
+	vm->vblk_size     = BE32 (data + 0x08);
+	vm->vblk_offset   = BE32 (data + 0x0C);
+	vm->last_vblk_seq = BE32 (data + 0x04);
+
+	ldm_debug ("Parsed VMDB successfully.");
+	return TRUE;
 }
 
 /**
- * get_vnum - convert a variable-width, big endian number, to cpu u64 one
- * @block:	pointer to the variable-width number to convert
- * @err:	address of an integer into which to return the error code.
- *
- * This converts a variable-width, big endian number into a 64-bit, CPU format
- * number and returns the result with err set to 0. If an error occurs return 0
- * with err set to -1.
+ * ldm_compare_privheads - Compare two privhead objects
+ * @ph1:  First privhead
+ * @ph2:  Second privhead
  *
- * The first byte of a variable-width number is the size of the number in bytes.
+ * This compares the two privhead structures @ph1 and @ph2.
+ *
+ * Return:  TRUE   Identical
+ *          FALSE  Different
  */
-static u64 get_vnum(const u8 *block, int *err)
+static BOOL ldm_compare_privheads (const struct privhead *ph1,
+				   const struct privhead *ph2)
 {
-	u64 tmp = 0ULL;
-	u8 length = *block++;
+	BUG_ON (!ph1);
+	BUG_ON (!ph2);
 
-	if (length && length <= 8) {
-		while (length--)
-			tmp = (tmp << 8) | *block++;
-		*err = 0;
-	} else {
-		printk(LDM_ERR "Illegal length in get_vnum(): %d.\n", length);
-		*err = 1;
-	}
-	return tmp;
+	return ((ph1->ver_major          == ph2->ver_major)		&&
+		(ph1->ver_minor          == ph2->ver_minor)		&&
+		(ph1->logical_disk_start == ph2->logical_disk_start)	&&
+		(ph1->logical_disk_size  == ph2->logical_disk_size)	&&
+		(ph1->config_start       == ph2->config_start)		&&
+		(ph1->config_size        == ph2->config_size)		&&
+		!memcmp (ph1->disk_id, ph2->disk_id, GUID_SIZE));
 }
 
 /**
- * get_vstr - convert a counted, non-null-terminated ASCII string to C-style one
- * @block:	string to convert
- * @buffer:	output buffer
- * @buflen:	size of output buffer
+ * ldm_compare_tocblocks - Compare two tocblock objects
+ * @toc1:  First toc
+ * @toc2:  Second toc
  *
- * This converts @block, a counted, non-null-terminated ASCII string, into a
- * C-style, null-terminated, ASCII string and returns this in @buffer. The
- * maximum number of characters converted is given by @buflen.
+ * This compares the two tocblock structures @toc1 and @toc2.
  *
- * The first bytes of a counted string stores the length of the string in bytes.
+ * Return:  TRUE   Identical
+ *          FALSE  Different
+ */
+static BOOL ldm_compare_tocblocks (const struct tocblock *toc1,
+				   const struct tocblock *toc2)
+{
+	BUG_ON (!toc1);
+	BUG_ON (!toc2);
+
+	return ((toc1->bitmap1_start == toc2->bitmap1_start)	&&
+		(toc1->bitmap1_size  == toc2->bitmap1_size)	&&
+		(toc1->bitmap2_start == toc2->bitmap2_start)	&&
+		(toc1->bitmap2_size  == toc2->bitmap2_size)	&&
+		!strncmp (toc1->bitmap1_name, toc2->bitmap1_name,
+			sizeof (toc1->bitmap1_name))		&&
+		!strncmp (toc1->bitmap2_name, toc2->bitmap2_name,
+			sizeof (toc1->bitmap2_name)));
+}
+
+/**
+ * ldm_validate_privheads - Compare the primary privhead with its backups
+ * @bdev:  Device holding the LDM Database
+ * @ph1:   Memory struct to fill with ph contents
+ *
+ * Read and compare all three privheads from disk.
  *
- * Return the number of characters written to @buffer, not including the
- * terminating null character, on success, and -1 on error, in which case
- * @buffer is not defined.
+ * The privheads on disk show the size and location of the main disk area and
+ * the configuration area (the database).
+ *
+ * Return:  TRUE   Success
+ *          FALSE  Error
  */
-static int get_vstr(const u8 *block, u8 *buffer, const int buflen)
+static BOOL ldm_validate_privheads (struct block_device *bdev,
+	unsigned long first_sector, struct privhead *ph1, struct gendisk *hd,
+	unsigned long first_minor)
 {
-	int length = block[0];
+	static const int off[3] = { OFF_PRIV1, OFF_PRIV2, OFF_PRIV3 };
+	struct privhead *ph[3] = { ph1 };
+	Sector sect;
+	u8 *data;
+	BOOL result = FALSE;
+	long num_sects;
+	int i;
+
+	BUG_ON (!bdev);
+	BUG_ON (!ph1);
+
+	ph[1] = kmalloc (sizeof (*ph[1]), GFP_KERNEL);
+	ph[2] = kmalloc (sizeof (*ph[2]), GFP_KERNEL);
+	if (!ph[1] || !ph[2]) {
+		ldm_crit ("Out of memory.");
+		goto out;
+	}
 
-	if (length < 1)
-		return -1;
-	if (length >= buflen) {
-		printk(LDM_ERR "String too long for buffer in get_vstr(): "
-				"(%d/%d). Truncating.\n", length, buflen);
-		length = buflen - 1;
+	/* off[1 & 2] are relative to ph[0]->config_start */
+	ph[0]->config_start = 0;
+
+	/* Read and parse privheads */
+	for (i = 0; i < 3; i++) {
+		data = read_dev_sector (bdev,
+			first_sector + ph[0]->config_start + off[i], &sect);
+		if (!data) {
+			ldm_crit ("Disk read failed.");
+			goto out;
+		}
+		result = ldm_parse_privhead (data, ph[i]);
+		put_dev_sector (sect);
+		if (!result) {
+			ldm_error ("Cannot find PRIVHEAD %d.", i+1); /* Log again */
+			if (i < 2)
+				goto out;	/* Already logged */
+			else
+				break;	/* FIXME ignore for now, 3rd PH can fail on odd-sized disks */
+		}
 	}
-	memcpy(buffer, block + 1, length);
-	buffer[length] = (u8)'\0';
-	return length;
+
+	num_sects = hd->part[(first_minor >> hd->minor_shift)
+				<< hd->minor_shift].nr_sects;
+
+	if ((ph[0]->config_start > num_sects) ||
+	   ((ph[0]->config_start + ph[0]->config_size) > num_sects)) {
+		ldm_crit ("Database extends beyond the end of the disk.");
+		goto out;
+	}
+
+	if ((ph[0]->logical_disk_start > ph[0]->config_start) ||
+	   ((ph[0]->logical_disk_start + ph[0]->logical_disk_size)
+		    > ph[0]->config_start)) {
+		ldm_crit ("Disk and database overlap.");
+		goto out;
+	}
+
+	if (!ldm_compare_privheads (ph[0], ph[1])) {
+		ldm_crit ("Primary and backup PRIVHEADs don't match.");
+		goto out;
+	}
+	/* FIXME ignore this for now
+	if (!ldm_compare_privheads (ph[0], ph[2])) {
+		ldm_crit ("Primary and backup PRIVHEADs don't match.");
+		goto out;
+	}*/
+	ldm_debug ("Validated PRIVHEADs successfully.");
+	result = TRUE;
+out:
+	kfree (ph[1]);
+	kfree (ph[2]);
+	return result;
 }
 
 /**
- * get_disk_objid - obtain the object id for the device we are working on
- * @dev:	partition device holding the LDM database
- * @vm:		in memory vmdb structure of the LDM database
- * @ph:		in memory privhead structure of the device we are working on
- * @dk:		in memory ldmdisk structure to return information into
- *
- * This obtains the object id for the device we are working on as defined by
- * the private header @ph. The obtained object id, together with the disk's
- * GUID from @ph are returned in the ldmdisk structure pointed to by @dk.
- *
- * A Disk has two Ids. The main one is a GUID in string format. The second,
- * used internally for cross-referencing, is a small, sequentially allocated,
- * number. The PRIVHEAD, just after the partition table, tells us the disk's
- * GUID. To find the disk's object id, we have to look through the database.
- *
- * Return 1 on success and -1 on error, in which case @dk is undefined.
- */
-static int get_disk_objid(struct block_device *bdev, const struct vmdb *vm,
-		const struct privhead *ph, struct ldmdisk *dk,
-		unsigned long base)
+ * ldm_validate_tocblocks - Validate the table of contents and its backups
+ * @bdev:  Device holding the LDM Database
+ * @base:  Offset, into @bdev, of the database
+ * @ldb:   Cache of the database structures
+ *
+ * Find and compare the four tables of contents of the LDM Database stored on
+ * @bdev and return the parsed information into @toc1.
+ *
+ * The offsets and sizes of the configs are range-checked against a privhead.
+ *
+ * Return:  TRUE   @toc1 contains validated TOCBLOCK info
+ *          FALSE  @toc1 contents are undefined
+ */
+static BOOL ldm_validate_tocblocks (struct block_device *bdev,
+	unsigned long base, struct ldmdb *ldb)
 {
+	static const int off[4] = { OFF_TOCB1, OFF_TOCB2, OFF_TOCB3, OFF_TOCB4};
+	struct tocblock *tb[4];
+	struct privhead *ph;
 	Sector sect;
-	unsigned char *data;
-	u8 *disk_id;
-	int vblk;
-	int vsize;		/* VBLK size. */
-	int perbuf;		/* VBLKs per buffer. */
-	int buffer, lastbuf, lastofs, err;
-
-	disk_id = (u8*)kmalloc(DISK_ID_SIZE, GFP_KERNEL);
-	if (!disk_id)
-		goto no_mem;
-	vsize   = vm->vblk_size;
-	if (vsize < 1 || vsize > 512)
-		goto err_out;
-	perbuf  = 512 / vsize;
-	if (perbuf < 1 || 512 % vsize)
-		goto err_out;
-					/* 512 == VMDB size */
-	lastbuf = vm->last_vblk_seq / perbuf - 1;
-	lastofs = vm->last_vblk_seq % perbuf;
-	if (lastofs)
-		lastbuf++;
-	if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize >
-			ph->config_size * 512)
-		goto err_out;
-	for (buffer = 0; buffer < lastbuf; buffer++) {
-		data = read_dev_sector(bdev, base + 2*OFF_VBLK + buffer, &sect);
-		if (!data)
-			goto read_err;
-		for (vblk = 0; vblk < perbuf; vblk++) {
-			int rel_objid, rel_name, delta;
-			u8 *block;
-
-			if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs)
-				break;
-			block = data + vblk * vsize;
-			delta = vblk * vsize + 0x18;
-			if (delta >= 512)
-				goto brelse_out;
-			if (block[0x0D] != 0)	/* Extended VBLK, ignore */
-				continue;
-			if ((block[0x13] != VBLK_DSK1) &&
-			    (block[0x13] != VBLK_DSK2))
-				continue;
-			/* Calculate relative offsets. */
-			rel_objid = 1 + block[0x18];
-			if (delta + rel_objid >= 512)
-				goto brelse_out;
-			rel_name  = 1 + block[0x18 + rel_objid] + rel_objid;
-			if (delta + rel_name >= 512 ||
-			    delta + rel_name + block[0x18 + rel_name] >= 512)
-				goto brelse_out;
-			err = get_vstr(block + 0x18 + rel_name, disk_id,
-					DISK_ID_SIZE);
-			if (err == -1)
-				goto brelse_out;
-			if (!strncmp(disk_id, ph->disk_id, DISK_ID_SIZE)) {
-				dk->obj_id = get_vnum(block + 0x18, &err);
-				put_dev_sector(sect);
-				if (err)
-					goto out;
-				strncpy(dk->disk_id, ph->disk_id,
-						sizeof(dk->disk_id));
-				dk->disk_id[sizeof(dk->disk_id) - 1] = (u8)'\0';
-				err = 1;
-				goto out;
-			}
+	u8 *data;
+	BOOL result = FALSE;
+	int i;
+
+	BUG_ON (!bdev);
+	BUG_ON (!ldb);
+
+	ph    = &ldb->ph;
+	tb[0] = &ldb->toc;
+	tb[1] = kmalloc (sizeof (*tb[1]), GFP_KERNEL);
+	tb[2] = kmalloc (sizeof (*tb[2]), GFP_KERNEL);
+	tb[3] = kmalloc (sizeof (*tb[3]), GFP_KERNEL);
+	if (!tb[1] || !tb[2] || !tb[3]) {
+		ldm_crit ("Out of memory.");
+		goto out;
+	}
+
+	for (i = 0; i < 4; i++)		/* Read and parse all four toc's. */
+	{
+		data = read_dev_sector (bdev, base + off[i], &sect);
+		if (!data) {
+			ldm_crit ("Disk read failed.");
+			goto out;
 		}
-		put_dev_sector(sect);
+		result = ldm_parse_tocblock (data, tb[i]);
+		put_dev_sector (sect);
+		if (!result)
+			goto out;	/* Already logged */
+	}
+
+	/* Range check the toc against a privhead. */
+	if (((tb[0]->bitmap1_start + tb[0]->bitmap1_size) > ph->config_size) ||
+	    ((tb[0]->bitmap2_start + tb[0]->bitmap2_size) > ph->config_size)) {
+		ldm_crit ("The bitmaps are out of range.  Giving up.");
+		goto out;
+	}
+
+	if (!ldm_compare_tocblocks (tb[0], tb[1]) ||	/* Compare all tocs. */
+	    !ldm_compare_tocblocks (tb[0], tb[2]) ||
+	    !ldm_compare_tocblocks (tb[0], tb[3])) {
+		ldm_crit ("The TOCBLOCKs don't match.");
+		goto out;
 	}
-	err = -1;
+
+	ldm_debug ("Validated TOCBLOCKs successfully.");
+	result = TRUE;
 out:
-	kfree(disk_id);
-	return err;
-brelse_out:
-	put_dev_sector(sect);
-	goto err_out;
-no_mem:
-	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
-	goto err_out;
-read_err:
-	printk(LDM_CRIT "Disk read failed in get_disk_objid.\n");
-err_out:
-	err = -1;
-	goto out;
+	kfree (tb[1]);
+	kfree (tb[2]);
+	kfree (tb[3]);
+	return result;
 }
 
 /**
- * parse_vmdb - parse the LDM database vmdb structure
- * @buffer:	LDM database vmdb structure loaded from the device
- * @vm:		in memory vmdb structure to return parsed information in
- *
- * This parses the LDM database vmdb structure supplied in @buffer and sets up
- * the in memory vmdb structure @vm with the obtained information.
- *
- * Return 1 on success and -1 on error, in which case @vm is undefined.
+ * ldm_validate_vmdb - Read the VMDB and validate it
+ * @bdev:  Device holding the LDM Database
+ * @base:  Offset, into @bdev, of the database
+ * @ldb:   Cache of the database structures
+ *
+ * Find the vmdb of the LDM Database stored on @bdev and return the parsed
+ * information in @ldb.
  *
- * NOTE: The *_start, *_size and *_seq values returned in @vm have not been
- * checked for validity, so make sure to check them when using them.
+ * Return:  TRUE   @ldb contains validated VBDB info
+ *          FALSE  @ldb contents are undefined
  */
-static int parse_vmdb(const u8 *buffer, struct vmdb *vm)
+static BOOL ldm_validate_vmdb (struct block_device *bdev, unsigned long base,
+			       struct ldmdb *ldb)
 {
-	if (MAGIC_VMDB != BE32(buffer)) {
-		printk(LDM_CRIT "Cannot find VMDB, database may be corrupt.\n");
-		return -1;
+	Sector sect;
+	u8 *data;
+	BOOL result = FALSE;
+	struct vmdb *vm;
+	struct tocblock *toc;
+
+	BUG_ON (!bdev);
+	BUG_ON (!ldb);
+
+	vm  = &ldb->vm;
+	toc = &ldb->toc;
+
+	data = read_dev_sector (bdev, base + OFF_VMDB, &sect);
+	if (!data) {
+		ldm_crit ("Disk read failed.");
+		return FALSE;
 	}
-	vm->ver_major = BE16(buffer + 0x12);
-	vm->ver_minor = BE16(buffer + 0x14);
-	if ((vm->ver_major != 4) || (vm->ver_minor != 10)) {
-		printk(LDM_ERR "Expected VMDB version %d.%d, got %d.%d. "
-				"Aborting.\n", 4, 10, vm->ver_major,
-				vm->ver_minor);
-		return -1;
+
+	if (!ldm_parse_vmdb (data, vm))
+		goto out;				/* Already logged */
+
+	/* Are there uncommitted transactions? */
+	if (BE16(data + 0x10) != 0x01) {
+		ldm_crit ("Database is not in a consistant state.  Aborting.");
+		goto out;
 	}
-	vm->vblk_size	  = BE32(buffer + 0x08);
-	vm->vblk_offset   = BE32(buffer + 0x0C);
-	vm->last_vblk_seq = BE32(buffer + 0x04);
 
-	ldm_debug("Parsed VMDB successfully.\n");
-	return 1;
+	if (vm->vblk_offset != 512)
+		ldm_info ("VBLKs start at offset 0x%04x.", vm->vblk_offset);
+
+	/* FIXME: How should we handle this situation? */
+	if ((vm->vblk_size * vm->last_vblk_seq) != (toc->bitmap1_size << 9))
+		ldm_info ("VMDB and TOCBLOCK don't agree on the database size.");
+
+	result = TRUE;
+out:
+	put_dev_sector (sect);
+	return result;
 }
 
+
 /**
- * validate_vmdb - validate the vmdb
- * @dev:	partition device holding the LDM database
- * @vm:		in memory vmdb in which to return information
+ * ldm_validate_partition_table - Determine whether bdev might be a dynamic disk
+ * @bdev:  Device holding the LDM Database
  *
- * Find the vmdb of the LDM database stored on @dev and return the parsed
- * information into @vm.
+ * This function provides a weak test to decide whether the device is a dynamic
+ * disk or not.  It looks for an MS-DOS-style partition table containing at
+ * least one partition of type 0x42 (formerly SFS, now used by Windows for
+ * dynamic disks).
+ *
+ * N.B.  The only possible error can come from the read_dev_sector and that is
+ *       only likely to happen if the underlying device is strange.  If that IS
+ *       the case we should return zero to let someone else try.
  *
- * Return 1 on success and -1 on error, in which case @vm is undefined.
+ * Return:  TRUE   @bdev is a dynamic disk
+ *          FALSE  @bdev is not a dynamic disk, or an error occurred
  */
-static int validate_vmdb(struct block_device *bdev, struct vmdb *vm, unsigned long base)
+static BOOL ldm_validate_partition_table (struct block_device *bdev)
 {
 	Sector sect;
-	unsigned char *data;
-	int ret;
+	u8 *data;
+	struct partition *p;
+	int i;
+	BOOL result = FALSE;
 
-	data = read_dev_sector(bdev, base + OFF_VMDB * 2 + 1, &sect);
+	BUG_ON (!bdev);
+
+	data = read_dev_sector (bdev, 0, &sect);
 	if (!data) {
-		printk(LDM_CRIT "Disk read failed in validate_vmdb.\n");
-		return -1;
+		ldm_crit ("Disk read failed.");
+		return FALSE;
+	}
+
+	if (*(u16*) (data + 0x01FE) != cpu_to_le16 (MSDOS_LABEL_MAGIC)) {
+		ldm_debug ("No MS-DOS partition table found.");
+		goto out;
 	}
-	ret = parse_vmdb(data, vm);
-	put_dev_sector(sect);
-	return ret;
+
+	p = (struct partition*)(data + 0x01BE);
+	for (i = 0; i < 4; i++, p++)
+		if (SYS_IND (p) == WIN2K_DYNAMIC_PARTITION) {
+			result = TRUE;
+			break;
+		}
+
+	if (result)
+		ldm_debug ("Parsed partition table successfully.");
+	else
+		ldm_debug ("Found an MS-DOS partition table, not a dynamic disk.");
+out:
+	put_dev_sector (sect);
+	return result;
 }
 
 /**
- * compare_tocblocks - compare two tables of contents
- * @toc1:	first toc
- * @toc2:	second toc
+ * ldm_get_disk_objid - Search a linked list of vblk's for a given Disk Id
+ * @ldb:  Cache of the database structures
  *
- * This compares the two tables of contents @toc1 and @toc2.
+ * The LDM Database contains a list of all partitions on all dynamic disks.  The
+ * primary PRIVHEAD, at the beginning of the physical disk, tells us the GUID of
+ * this disk.  This function searches for the GUID in a linked list of vblk's.
  *
- * Return 1 if @toc1 and @toc2 are equal and -1 otherwise.
+ * Return:  Pointer, A matching vblk was found
+ *          NULL,    No match, or an error
  */
-static int compare_tocblocks(const struct tocblock *toc1,
-		const struct tocblock *toc2)
+static struct vblk * ldm_get_disk_objid (const struct ldmdb *ldb)
 {
-	if ((toc1->bitmap1_start == toc2->bitmap1_start)	&&
-	    (toc1->bitmap1_size  == toc2->bitmap1_size)		&&
-	    (toc1->bitmap2_start == toc2->bitmap2_start)	&&
-	    (toc1->bitmap2_size  == toc2->bitmap2_size)		&&
-	    !strncmp(toc1->bitmap1_name, toc2->bitmap1_name,
-			sizeof(toc1->bitmap1_name))		&&
-	    !strncmp(toc1->bitmap2_name, toc2->bitmap2_name,
-			sizeof(toc1->bitmap2_name)))
-		return 1;
-	return -1;
+	struct list_head *item;
+
+	BUG_ON (!ldb);
+
+	list_for_each (item, &ldb->v_disk) {
+		struct vblk *v = list_entry (item, struct vblk, list);
+		if (!memcmp (v->vblk.disk.disk_id, ldb->ph.disk_id, GUID_SIZE))
+			return v;
+	}
+
+	return NULL;
 }
 
 /**
- * parse_tocblock - parse the LDM database table of contents structure
- * @buffer:	LDM database toc structure loaded from the device
- * @toc:	in memory toc structure to return parsed information in
+ * ldm_create_partition - Create a kernel partition device
+ * @hd:     gendisk structure in which to create partition
+ * @minor:  Create a this minor number on the device
+ * @start:  Offset (in sectors) into the device of the partition
+ * @size:   Size (in sectors) of the partition
  *
- * This parses the LDM database table of contents structure supplied in @buffer
- * and sets up the in memory table of contents structure @toc with the obtained
- * information.
+ * This validates the range, then puts an entry into the kernel's partition
+ * table.
+ *
+ * Return:  TRUE   Created the partition
+ *          FALSE  Error
+ */
+static BOOL ldm_create_partition (struct gendisk *hd, int minor, int start,
+				  int size)
+{
+	int disk_minor;
+
+	BUG_ON (!hd);;
+	BUG_ON (!hd->part);
+
+	/* Get the minor number of the parent device
+	 * so we can check we don't go beyond the end of the device.  */
+	disk_minor = (minor >> hd->minor_shift) << hd->minor_shift;
+	if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) {
+		ldm_crit ("Partition exceeds physical disk. Aborting.");
+		return FALSE;
+	}
+	add_gd_partition (hd, minor, start, size);
+	ldm_debug ("Created partition successfully.");
+	return TRUE;
+}
+
+/**
+ * ldm_create_data_partitions - Create data partitions for this device
+ * @pp:   List of the partitions parsed so far
+ * @ldb:  Cache of the database structures
  *
- * Return 1 on success and -1 on error, in which case @toc is undefined.
+ * The database contains ALL the partitions for ALL disk groups, so we need to
+ * filter out this specific disk. Using the disk's object id, we can find all
+ * the partitions in the database that belong to this disk.
+ *
+ * Add each partition in our database, to the parsed_partitions structure.
+ *
+ * N.B.  This function creates the partitions in the order it finds partition
+ *       objects in the linked list.
  *
- * FIXME: The *_start and *_size values returned in @toc are not been checked
- * for validity but as we don't use the actual values for anything other than
- * comparing between the toc and its backups, the values are not important.
+ * Return:  TRUE   Partition created
+ *          FALSE  Error, probably a range checking problem
  */
-static int parse_tocblock(const u8 *buffer, struct tocblock *toc)
+static BOOL ldm_create_data_partitions (struct gendisk *hd,
+	unsigned long first_sector, int first_minor, const struct ldmdb *ldb)
 {
-	if (MAGIC_TOCBLOCK != BE64(buffer)) {
-		printk(LDM_CRIT "Cannot find TOCBLOCK, database may be "
-				"corrupt.\n");
-		return -1;
+	struct list_head *item;
+	struct vblk_part *part;
+	struct vblk *disk;
+	int disk_minor;
+	int minor;
+
+	BUG_ON (!hd);
+	BUG_ON (!ldb);
+
+	disk = ldm_get_disk_objid (ldb);
+	if (!disk) {
+		ldm_crit ("Can't find the ID of this disk in the database.");
+		return FALSE;
 	}
-	strncpy(toc->bitmap1_name, buffer + 0x24, sizeof(toc->bitmap1_name));
-	toc->bitmap1_name[sizeof(toc->bitmap1_name) - 1] = (u8)'\0';
-	toc->bitmap1_start = BE64(buffer + 0x2E);
-	toc->bitmap1_size  = BE64(buffer + 0x36);
-	/*toc->bitmap1_flags = BE64(buffer + 0x3E);*/
-	if (strncmp(toc->bitmap1_name, TOC_BITMAP1,
-			sizeof(toc->bitmap1_name)) != 0) {
-		printk(LDM_CRIT "TOCBLOCK's first bitmap should be %s, but is "
-				"%s.\n", TOC_BITMAP1, toc->bitmap1_name);
-		return -1;
+
+	/* We use the range-check the partitions against the parent device. */
+	disk_minor = (first_minor >> hd->minor_shift) << hd->minor_shift;
+	minor = first_minor;
+
+	printk (" [LDM]");
+
+	/* Create the data partitions */
+	list_for_each (item, &ldb->v_part) {
+		struct vblk *vb;
+		vb = list_entry (item, struct vblk, list);
+		part = &vb->vblk.part;
+
+		if (part->disk_id != disk->obj_id)
+			continue;
+
+		if (!ldm_create_partition (hd, minor,
+		    part->start + ldb->ph.logical_disk_start, part->size))
+			continue;			/* Already logged */
+		minor++;
 	}
-	strncpy(toc->bitmap2_name, buffer + 0x46, sizeof(toc->bitmap2_name));
-	toc->bitmap2_name[sizeof(toc->bitmap2_name) - 1] = (u8)'\0';
-	toc->bitmap2_start = BE64(buffer + 0x50);
-	toc->bitmap2_size  = BE64(buffer + 0x58);
-	/*toc->bitmap2_flags = BE64(buffer + 0x60);*/
-	if (strncmp(toc->bitmap2_name, TOC_BITMAP2,
-			sizeof(toc->bitmap2_name)) != 0) {
-		printk(LDM_CRIT "TOCBLOCK's second bitmap should be %s, but is "
-				"%s.\n", TOC_BITMAP2, toc->bitmap2_name);
+
+	printk ("\n");
+	return TRUE;
+}
+
+
+/**
+ * ldm_relative - Calculate the next relative offset
+ * @buffer:  Block of data being worked on
+ * @buflen:  Size of the block of data
+ * @base:    Size of the previous fixed width fields
+ * @offset:  Cumulative size of the previous variable-width fields
+ *
+ * Because many of the VBLK fields are variable-width, it's necessary
+ * to calculate each offset based on the previous one and the length
+ * of the field it pointed to.
+ *
+ * Return:  -1 Error, the calculated offset exceeded the size of the buffer
+ *           n OK, a range-checked offset into buffer
+ */
+static int ldm_relative (const u8 *buffer, int buflen, int base, int offset)
+{
+
+	base += offset;
+	if ((!buffer) || (offset < 0) || (base > buflen))
 		return -1;
-	}
-	ldm_debug("Parsed TOCBLOCK successfully.\n");
-	return 1;
+	if ((base + buffer[base]) >= buflen)
+		return -1;
+
+	return buffer[base] + offset + 1;
 }
 
 /**
- * validate_tocblocks - validate the table of contents and its backups
- * @dev:	partition device holding the LDM database
- * @toc1:	in memory table of contents in which to return information
+ * ldm_get_vnum - Convert a variable-width, big endian number, into cpu order
+ * @block:  Pointer to the variable-width number to convert
+ *
+ * Large numbers in the LDM Database are often stored in a packed format.  Each
+ * number is prefixed by a one byte width marker.  All numbers in the database
+ * are stored in big-endian byte order.  This function reads one of these
+ * numbers and returns the result
  *
- * Find and compare the four tables of contents of the LDM database stored on
- * @dev and return the parsed information into @toc1.
+ * N.B.  This function DOES NOT perform any range checking, though the most
+ *       it will read is eight bytes.
  *
- * Return 1 on success and -1 on error, in which case @toc1 is undefined.
+ * Return:  n A number
+ *          0 Zero, or an error occurred
  */
-static int validate_tocblocks(struct block_device *bdev,
-			struct tocblock *toc1,
-			unsigned long base)
+static u64 ldm_get_vnum (const u8 *block)
 {
-	Sector sect;
-	unsigned char *data;
-	struct tocblock *toc2 = NULL, *toc3 = NULL, *toc4 = NULL;
-	int err;
-
-	toc2 = (struct tocblock*)kmalloc(sizeof(*toc2), GFP_KERNEL);
-	if (!toc2)
-		goto no_mem;
-	toc3 = (struct tocblock*)kmalloc(sizeof(*toc3), GFP_KERNEL);
-	if (!toc3)
-		goto no_mem;
-	toc4 = (struct tocblock*)kmalloc(sizeof(*toc4), GFP_KERNEL);
-	if (!toc4)
-		goto no_mem;
-	/* Read and parse first toc. */
-	data = read_dev_sector(bdev, base + OFF_TOCBLOCK1 * 2 + 1, &sect);
-	if (!data) {
-		printk(LDM_CRIT "Disk read 1 failed in validate_tocblocks.\n");
-		goto err_out;
-	}
-	err = parse_tocblock(data, toc1);
-	put_dev_sector(sect);
-	if (err != 1)
-		goto out;
-	/* Read and parse second toc. */
-	data = read_dev_sector(bdev, base + OFF_TOCBLOCK2 * 2, &sect);
-	if (!data) {
-		printk(LDM_CRIT "Disk read 2 failed in validate_tocblocks.\n");
-		goto err_out;
-	}
-	err = parse_tocblock(data, toc2);
-	put_dev_sector(sect);
-	if (err != 1)
-		goto out;
-	/* Read and parse third toc. */
-	data = read_dev_sector(bdev, base + OFF_TOCBLOCK3 * 2 + 1, &sect);
-	if (!data) {
-		printk(LDM_CRIT "Disk read 3 failed in validate_tocblocks.\n");
-		goto err_out;
-	}
-	err = parse_tocblock(data, toc3);
-	put_dev_sector(sect);
-	if (err != 1)
-		goto out;
-	/* Read and parse fourth toc. */
-	data = read_dev_sector(bdev, base + OFF_TOCBLOCK4 * 2, &sect);
-	if (!data) {
-		printk(LDM_CRIT "Disk read 4 failed in validate_tocblocks.\n");
-		goto err_out;
-	}
-	err = parse_tocblock(data, toc4);
-	put_dev_sector(sect);
-	if (err != 1)
-		goto out;
-	/* Compare all tocs. */
-	err = compare_tocblocks(toc1, toc2);
-	if (err != 1) {
-		printk(LDM_CRIT "First and second TOCBLOCKs don't match.\n");
-		goto out;
-	}
-	err = compare_tocblocks(toc3, toc4);
-	if (err != 1) {
-		printk(LDM_CRIT "Third and fourth TOCBLOCKs don't match.\n");
-		goto out;
-	}
-	err = compare_tocblocks(toc1, toc3);
-	if (err != 1)
-		printk(LDM_CRIT "First and third TOCBLOCKs don't match.\n");
+	u64 tmp = 0;
+	u8 length;
+
+	BUG_ON (!block);
+
+	length = *block++;
+
+	if (length && length <= 8)
+		while (length--)
+			tmp = (tmp << 8) | *block++;
 	else
-		ldm_debug("Validated TOCBLOCKs successfully.\n");
-out:
-	kfree(toc2);
-	kfree(toc3);
-	kfree(toc4);
-	return err;
-no_mem:
-	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
-err_out:
-	err = -1;
-	goto out;
+		ldm_error ("Illegal length %d.", length);
+
+	return tmp;
 }
 
 /**
- * compare_privheads - compare two privheads
- * @ph1:	first privhead
- * @ph2:	second privhead
- *
- * This compares the two privheads @ph1 and @ph2.
- *
- * Return 1 if @ph1 and @ph2 are equal and -1 otherwise.
- */
-static int compare_privheads(const struct privhead *ph1,
-		const struct privhead *ph2)
-{
-	if ((ph1->ver_major == ph2->ver_major)			 &&
-	    (ph1->ver_minor == ph2->ver_minor)			 &&
-	    (ph1->logical_disk_start == ph2->logical_disk_start) &&
-	    (ph1->logical_disk_size  == ph2->logical_disk_size)	 &&
-	    (ph1->config_start == ph2->config_start)		 &&
-	    (ph1->config_size  == ph2->config_size)		 &&
-	    !strncmp(ph1->disk_id, ph2->disk_id, sizeof(ph1->disk_id)))
-		return 1;
-	return -1;
+ * ldm_get_vstr - Read a length-prefixed string into a buffer
+ * @block:   Pointer to the length marker
+ * @buffer:  Location to copy string to
+ * @buflen:  Size of the output buffer
+ *
+ * Many of the strings in the LDM Database are not NULL terminated.  Instead
+ * they are prefixed by a one byte length marker.  This function copies one of
+ * these strings into a buffer.
+ *
+ * N.B.  This function DOES NOT perform any range checking on the input.
+ *       If the buffer is too small, the output will be truncated.
+ *
+ * Return:  0, Error and @buffer contents are undefined
+ *          n, String length in characters (excluding NULL)
+ *          buflen-1, String was truncated.
+ */
+static int ldm_get_vstr (const u8 *block, u8 *buffer, int buflen)
+{
+	int length;
+
+	BUG_ON (!block);
+	BUG_ON (!buffer);
+
+	length = block[0];
+	if (length >= buflen) {
+		ldm_error ("Truncating string %d -> %d.", length, buflen);
+		length = buflen - 1;
+	}
+	memcpy (buffer, block + 1, length);
+	buffer[length] = 0;
+	return length;
+}
+
+
+/**
+ * ldm_parse_cmp3 - Read a raw VBLK Component object into a vblk structure
+ * @buffer:  Block of data being worked on
+ * @buflen:  Size of the block of data
+ * @vb:      In-memory vblk in which to return information
+ *
+ * Read a raw VBLK Component object (version 3) into a vblk structure.
+ *
+ * Return:  TRUE   @vb contains a Component VBLK
+ *          FALSE  @vb contents are not defined
+ */
+static BOOL ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb)
+{
+	int r_objid, r_name, r_vstate, r_child, r_parent, r_stripe, r_cols, len;
+	struct vblk_comp *comp;
+
+	BUG_ON (!buffer);
+	BUG_ON (!vb);
+
+	r_objid  = ldm_relative (buffer, buflen, 0x18, 0);
+	r_name   = ldm_relative (buffer, buflen, 0x18, r_objid);
+	r_vstate = ldm_relative (buffer, buflen, 0x18, r_name);
+	r_child  = ldm_relative (buffer, buflen, 0x1D, r_vstate);
+	r_parent = ldm_relative (buffer, buflen, 0x2D, r_child);
+
+	if (buffer[0x12] & VBLK_FLAG_COMP_STRIPE) {
+		r_stripe = ldm_relative (buffer, buflen, 0x2E, r_parent);
+		r_cols   = ldm_relative (buffer, buflen, 0x2E, r_stripe);
+		len = r_cols;
+	} else {
+		r_stripe = 0;
+		r_cols   = 0;
+		len = r_parent;
+	}
+	if (len < 0)
+		return FALSE;
+
+	len += VBLK_SIZE_CMP3;
+	if (len != BE32 (buffer + 0x14))
+		return FALSE;
+
+	comp = &vb->vblk.comp;
+	ldm_get_vstr (buffer + 0x18 + r_name, comp->state,
+		sizeof (comp->state));
+	comp->type      = buffer[0x18 + r_vstate];
+	comp->children  = ldm_get_vnum (buffer + 0x1D + r_vstate);
+	comp->parent_id = ldm_get_vnum (buffer + 0x2D + r_child);
+	comp->chunksize = r_stripe ? ldm_get_vnum (buffer+r_parent+0x2E) : 0;
+
+	return TRUE;
+}
+
+/**
+ * ldm_parse_dgr3 - Read a raw VBLK Disk Group object into a vblk structure
+ * @buffer:  Block of data being worked on
+ * @buflen:  Size of the block of data
+ * @vb:      In-memory vblk in which to return information
+ *
+ * Read a raw VBLK Disk Group object (version 3) into a vblk structure.
+ *
+ * Return:  TRUE   @vb contains a Disk Group VBLK
+ *          FALSE  @vb contents are not defined
+ */
+static int ldm_parse_dgr3 (const u8 *buffer, int buflen, struct vblk *vb)
+{
+	int r_objid, r_name, r_diskid, r_id1, r_id2, len;
+	struct vblk_dgrp *dgrp;
+
+	BUG_ON (!buffer);
+	BUG_ON (!vb);
+
+	r_objid  = ldm_relative (buffer, buflen, 0x18, 0);
+	r_name   = ldm_relative (buffer, buflen, 0x18, r_objid);
+	r_diskid = ldm_relative (buffer, buflen, 0x18, r_name);
+
+	if (buffer[0x12] & VBLK_FLAG_DGR3_IDS) {
+		r_id1 = ldm_relative (buffer, buflen, 0x24, r_diskid);
+		r_id2 = ldm_relative (buffer, buflen, 0x24, r_id1);
+		len = r_id2;
+	} else {
+		r_id1 = 0;
+		r_id2 = 0;
+		len = r_diskid;
+	}
+	if (len < 0)
+		return FALSE;
+
+	len += VBLK_SIZE_DGR3;
+	if (len != BE32 (buffer + 0x14))
+		return FALSE;
+
+	dgrp = &vb->vblk.dgrp;
+	ldm_get_vstr (buffer + 0x18 + r_name, dgrp->disk_id,
+		sizeof (dgrp->disk_id));
+	return TRUE;
 }
 
 /**
- * validate_privheads - compare the privhead backups to the first one
- * @dev:	partition device holding the LDM database
- * @ph1:	first privhead which we have already validated before
- *
- * We already have one privhead from the beginning of the disk.
- * Now we compare the two other copies for safety.
- *
- * Return 1 on succes and -1 on error.
- */
-static int validate_privheads(struct block_device *bdev,
-			      const struct privhead *ph1,
-			      unsigned long base)
+ * ldm_parse_dgr4 - Read a raw VBLK Disk Group object into a vblk structure
+ * @buffer:  Block of data being worked on
+ * @buflen:  Size of the block of data
+ * @vb:      In-memory vblk in which to return information
+ *
+ * Read a raw VBLK Disk Group object (version 4) into a vblk structure.
+ *
+ * Return:  TRUE   @vb contains a Disk Group VBLK
+ *          FALSE  @vb contents are not defined
+ */
+static BOOL ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb)
 {
-	Sector sect;
-	unsigned char *data;
-	struct privhead *ph2 = NULL, *ph3 = NULL;
-	int err;
-
-	ph2 = (struct privhead*)kmalloc(sizeof(*ph2), GFP_KERNEL);
-	if (!ph2)
-		goto no_mem;
-	ph3 = (struct privhead*)kmalloc(sizeof(*ph3), GFP_KERNEL);
-	if (!ph3)
-		goto no_mem;
-	data = read_dev_sector(bdev, base + OFF_PRIVHEAD2 * 2, &sect);
-	if (!data) {
-		printk(LDM_CRIT "Disk read 1 failed in validate_privheads.\n");
-		goto err_out;
+	char buf[64];
+	int r_objid, r_name, r_id1, r_id2, len;
+	struct vblk_dgrp *dgrp;
+
+	BUG_ON (!buffer);
+	BUG_ON (!vb);
+
+	r_objid  = ldm_relative (buffer, buflen, 0x18, 0);
+	r_name   = ldm_relative (buffer, buflen, 0x18, r_objid);
+
+	if (buffer[0x12] & VBLK_FLAG_DGR4_IDS) {
+		r_id1 = ldm_relative (buffer, buflen, 0x44, r_name);
+		r_id2 = ldm_relative (buffer, buflen, 0x44, r_id1);
+		len = r_id2;
+	} else {
+		r_id1 = 0;
+		r_id2 = 0;
+		len = r_name;
 	}
-	err = parse_privhead(data, ph2);
-	put_dev_sector(sect);
-	if (err != 1)
-		goto out;
-	data = read_dev_sector(bdev, base + OFF_PRIVHEAD3 * 2 + 1, &sect);
-	if (!data) {
-		printk(LDM_CRIT "Disk read 2 failed in validate_privheads.\n");
-		goto err_out;
+	if (len < 0)
+		return FALSE;
+
+	len += VBLK_SIZE_DGR4;
+	if (len != BE32 (buffer + 0x14))
+		return FALSE;
+
+	dgrp = &vb->vblk.dgrp;
+
+	ldm_get_vstr (buffer + 0x18 + r_objid, buf, sizeof (buf));
+	return TRUE;
+}
+
+/**
+ * ldm_parse_dsk3 - Read a raw VBLK Disk object into a vblk structure
+ * @buffer:  Block of data being worked on
+ * @buflen:  Size of the block of data
+ * @vb:      In-memory vblk in which to return information
+ *
+ * Read a raw VBLK Disk object (version 3) into a vblk structure.
+ *
+ * Return:  TRUE   @vb contains a Disk VBLK
+ *          FALSE  @vb contents are not defined
+ */
+static BOOL ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb)
+{
+	int r_objid, r_name, r_diskid, r_altname, len;
+	struct vblk_disk *disk;
+
+	BUG_ON (!buffer);
+	BUG_ON (!vb);
+
+	r_objid   = ldm_relative (buffer, buflen, 0x18, 0);
+	r_name    = ldm_relative (buffer, buflen, 0x18, r_objid);
+	r_diskid  = ldm_relative (buffer, buflen, 0x18, r_name);
+	r_altname = ldm_relative (buffer, buflen, 0x18, r_diskid);
+	len = r_altname;
+	if (len < 0)
+		return FALSE;
+
+	len += VBLK_SIZE_DSK3;
+	if (len != BE32 (buffer + 0x14))
+		return FALSE;
+
+	disk = &vb->vblk.disk;
+	ldm_get_vstr (buffer + 0x18 + r_diskid, disk->alt_name,
+		sizeof (disk->alt_name));
+	if (!ldm_parse_guid (buffer + 0x19 + r_name, disk->disk_id))
+		return FALSE;
+
+	return TRUE;
+}
+
+/**
+ * ldm_parse_dsk4 - Read a raw VBLK Disk object into a vblk structure
+ * @buffer:  Block of data being worked on
+ * @buflen:  Size of the block of data
+ * @vb:      In-memory vblk in which to return information
+ *
+ * Read a raw VBLK Disk object (version 4) into a vblk structure.
+ *
+ * Return:  TRUE   @vb contains a Disk VBLK
+ *          FALSE  @vb contents are not defined
+ */
+static BOOL ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb)
+{
+	int r_objid, r_name, len;
+	struct vblk_disk *disk;
+
+	BUG_ON (!buffer);
+	BUG_ON (!vb);
+
+	r_objid = ldm_relative (buffer, buflen, 0x18, 0);
+	r_name  = ldm_relative (buffer, buflen, 0x18, r_objid);
+	len     = r_name;
+	if (len < 0)
+		return FALSE;
+
+	len += VBLK_SIZE_DSK4;
+	if (len != BE32 (buffer + 0x14))
+		return FALSE;
+
+	disk = &vb->vblk.disk;
+	memcpy (disk->disk_id, buffer + 0x18 + r_name, GUID_SIZE);
+	return TRUE;
+}
+
+/**
+ * ldm_parse_prt3 - Read a raw VBLK Partition object into a vblk structure
+ * @buffer:  Block of data being worked on
+ * @buflen:  Size of the block of data
+ * @vb:      In-memory vblk in which to return information
+ *
+ * Read a raw VBLK Partition object (version 3) into a vblk structure.
+ *
+ * Return:  TRUE   @vb contains a Partition VBLK
+ *          FALSE  @vb contents are not defined
+ */
+static BOOL ldm_parse_prt3 (const u8 *buffer, int buflen, struct vblk *vb)
+{
+	int r_objid, r_name, r_size, r_parent, r_diskid, r_index, len;
+	struct vblk_part *part;
+
+	BUG_ON (!buffer);
+	BUG_ON (!vb);
+
+	r_objid  = ldm_relative (buffer, buflen, 0x18, 0);
+	r_name   = ldm_relative (buffer, buflen, 0x18, r_objid);
+	r_size   = ldm_relative (buffer, buflen, 0x34, r_name);
+	r_parent = ldm_relative (buffer, buflen, 0x34, r_size);
+	r_diskid = ldm_relative (buffer, buflen, 0x34, r_parent);
+
+	if (buffer[0x12] & VBLK_FLAG_PART_INDEX) {
+		r_index = ldm_relative (buffer, buflen, 0x34, r_diskid);
+		len = r_index;
+	} else {
+		r_index = 0;
+		len = r_diskid;
 	}
-	err = parse_privhead(data, ph3);
-	put_dev_sector(sect);
-	if (err != 1)
-		goto out;
-	err = compare_privheads(ph1, ph2);
-	if (err != 1) {
-		printk(LDM_CRIT "First and second PRIVHEADs don't match.\n");
-		goto out;
+	if (len < 0)
+		return FALSE;
+
+	len += VBLK_SIZE_PRT3;
+	if (len != BE32 (buffer + 0x14))
+		return FALSE;
+
+	part = &vb->vblk.part;
+	part->start         = BE64         (buffer + 0x24 + r_name);
+	part->volume_offset = BE64         (buffer + 0x2C + r_name);
+	part->size          = ldm_get_vnum (buffer + 0x34 + r_name);
+	part->parent_id     = ldm_get_vnum (buffer + 0x34 + r_size);
+	part->disk_id       = ldm_get_vnum (buffer + 0x34 + r_parent);
+	if (vb->flags & VBLK_FLAG_PART_INDEX)
+		part->partnum = buffer[0x35 + r_diskid];
+	else
+		part->partnum = 0;
+
+	return TRUE;
+}
+
+/**
+ * ldm_parse_vol5 - Read a raw VBLK Volume object into a vblk structure
+ * @buffer:  Block of data being worked on
+ * @buflen:  Size of the block of data
+ * @vb:      In-memory vblk in which to return information
+ *
+ * Read a raw VBLK Volume object (version 5) into a vblk structure.
+ *
+ * Return:  TRUE   @vb contains a Volume VBLK
+ *          FALSE  @vb contents are not defined
+ */
+static BOOL ldm_parse_vol5 (const u8 *buffer, int buflen, struct vblk *vb)
+{
+	int r_objid, r_name, r_vtype, r_child, r_size, r_id1, r_id2, r_size2;
+	int r_drive, len;
+	struct vblk_volu *volu;
+
+	BUG_ON (!buffer);
+	BUG_ON (!vb);
+
+	r_objid  = ldm_relative (buffer, buflen, 0x18, 0);
+	r_name   = ldm_relative (buffer, buflen, 0x18, r_objid);
+	r_vtype  = ldm_relative (buffer, buflen, 0x18, r_name);
+	r_child  = ldm_relative (buffer, buflen, 0x2E, r_vtype);
+	r_size   = ldm_relative (buffer, buflen, 0x3E, r_child);
+
+	if (buffer[0x12] & VBLK_FLAG_VOLU_ID1)
+		r_id1 = ldm_relative (buffer, buflen, 0x53, r_size);
+	else
+		r_id1 = r_size;
+
+	if (buffer[0x12] & VBLK_FLAG_VOLU_ID2)
+		r_id2 = ldm_relative (buffer, buflen, 0x53, r_id1);
+	else
+		r_id2 = r_id1;
+
+	if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE)
+		r_size2 = ldm_relative (buffer, buflen, 0x53, r_id2);
+	else
+		r_size2 = r_id2;
+
+	if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE)
+		r_drive = ldm_relative (buffer, buflen, 0x53, r_size2);
+	else
+		r_drive = r_size2;
+
+	len = r_drive;
+	if (len < 0)
+		return FALSE;
+
+	len += VBLK_SIZE_VOL5;
+	if (len != BE32 (buffer + 0x14))
+		return FALSE;
+
+	volu = &vb->vblk.volu;
+
+	ldm_get_vstr (buffer + 0x18 + r_name,  volu->volume_type,
+		sizeof (volu->volume_type));
+	memcpy (volu->volume_state, buffer + 0x19 + r_vtype,
+			sizeof (volu->volume_state));
+	volu->size = ldm_get_vnum (buffer + 0x3E + r_child);
+	volu->partition_type = buffer[0x42 + r_size];
+	memcpy (volu->guid, buffer + 0x43 + r_size,  sizeof (volu->guid));
+	if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {
+		ldm_get_vstr (buffer + 0x53 + r_size,  volu->drive_hint,
+			sizeof (volu->drive_hint));
 	}
-	err = compare_privheads(ph1, ph3);
-	if (err != 1)
-		printk(LDM_CRIT "First and third PRIVHEADs don't match.\n");
+	return TRUE;
+}
+
+/**
+ * ldm_parse_vblk - Read a raw VBLK object into a vblk structure
+ * @buf:  Block of data being worked on
+ * @len:  Size of the block of data
+ * @vb:   In-memory vblk in which to return information
+ *
+ * Read a raw VBLK object into a vblk structure.  This function just reads the
+ * information common to all VBLK types, then delegates the rest of the work to
+ * helper functions: ldm_parse_*.
+ *
+ * Return:  TRUE   @vb contains a VBLK
+ *          FALSE  @vb contents are not defined
+ */
+static BOOL ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb)
+{
+	BOOL result = FALSE;
+	int r_objid;
+
+	BUG_ON (!buf);
+	BUG_ON (!vb);
+
+	r_objid = ldm_relative (buf, len, 0x18, 0);
+	if (r_objid < 0) {
+		ldm_error ("VBLK header is corrupt.");
+		return FALSE;
+	}
+
+	vb->flags  = buf[0x12];
+	vb->type   = buf[0x13];
+	vb->obj_id = ldm_get_vnum (buf + 0x18);
+	ldm_get_vstr (buf+0x18+r_objid, vb->name, sizeof (vb->name));
+
+	switch (vb->type) {
+		case VBLK_CMP3:  result = ldm_parse_cmp3 (buf, len, vb); break;
+		case VBLK_DSK3:  result = ldm_parse_dsk3 (buf, len, vb); break;
+		case VBLK_DSK4:  result = ldm_parse_dsk4 (buf, len, vb); break;
+		case VBLK_DGR3:  result = ldm_parse_dgr3 (buf, len, vb); break;
+		case VBLK_DGR4:  result = ldm_parse_dgr4 (buf, len, vb); break;
+		case VBLK_PRT3:  result = ldm_parse_prt3 (buf, len, vb); break;
+		case VBLK_VOL5:  result = ldm_parse_vol5 (buf, len, vb); break;
+	}
+
+	if (result)
+		ldm_debug ("Parsed VBLK 0x%llx (type: 0x%02x) ok.",
+			 (unsigned long long) vb->obj_id, vb->type);
 	else
-		/* We _could_ have checked more. */
-		ldm_debug("Validated PRIVHEADs successfully.\n");
-out:
-	kfree(ph2);
-	kfree(ph3);
-	return err;
-no_mem:
-	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
-err_out:
-	err = -1;
-	goto out;
+		ldm_error ("Failed to parse VBLK 0x%llx (type: 0x%02x).",
+			(unsigned long long) vb->obj_id, vb->type);
+
+	return result;
 }
 
+
 /**
- * create_partition - validate input and create a kernel partition device
- * @hd:		gendisk structure in which to create partition
- * @minor:	minor number for device to create
- * @start:	starting offset of the partition into the parent device
- * @size:	size of the partition
+ * ldm_ldmdb_add - Adds a raw VBLK entry to the ldmdb database
+ * @data:  Raw VBLK to add to the database
+ * @len:   Size of the raw VBLK
+ * @ldb:   Cache of the database structures
  *
- * This validates the range, then puts an entry into the kernel's partition
- * table.
+ * The VBLKs are sorted into categories.  Partitions are also sorted by offset.
  *
- * @start and @size are numbers of sectors.
+ * N.B.  This function does not check the validity of the VBLKs.
  *
- * Return 1 on succes and -1 on error.
+ * Return:  TRUE   The VBLK was added
+ *          FALSE  An error occurred
  */
-static int create_partition(struct gendisk *hd, const int minor,
-		const int start, const int size)
+static BOOL ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb)
 {
-	int disk_minor;
+	struct vblk *vb;
+	struct list_head *item;
 
-	if (!hd->part)
-		return -1;
-	/*
-	 * Get the minor number of the parent device so we can check we don't
-	 * go beyond the end of the device.
-	 */
-	disk_minor = (minor >> hd->minor_shift) << hd->minor_shift;
-	if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) {
-		printk(LDM_CRIT "LDM Partition exceeds physical disk. "
-				"Aborting.\n");
-		return -1;
+	BUG_ON (!data);
+	BUG_ON (!ldb);
+
+	vb = kmalloc (sizeof (*vb), GFP_KERNEL);
+	if (!vb) {
+		ldm_crit ("Out of memory.");
+		return FALSE;
+	}
+
+	if (!ldm_parse_vblk (data, len, vb))
+		return FALSE;			/* Already logged */
+
+	/* Put vblk into the correct list. */
+	switch (vb->type) {
+	case VBLK_DGR3:
+	case VBLK_DGR4:
+		list_add (&vb->list, &ldb->v_dgrp);
+		break;
+	case VBLK_DSK3:
+	case VBLK_DSK4:
+		list_add (&vb->list, &ldb->v_disk);
+		break;
+	case VBLK_VOL5:
+		list_add (&vb->list, &ldb->v_volu);
+		break;
+	case VBLK_CMP3:
+		list_add (&vb->list, &ldb->v_comp);
+		break;
+	case VBLK_PRT3:
+		/* Sort by the partition's start sector. */
+		list_for_each (item, &ldb->v_part) {
+			struct vblk *v = list_entry (item, struct vblk, list);
+			if ((v->vblk.part.disk_id == vb->vblk.part.disk_id) &&
+			    (v->vblk.part.start > vb->vblk.part.start)) {
+				list_add_tail (&vb->list, &v->list);
+				return TRUE;
+			}
+		}
+		list_add_tail (&vb->list, &ldb->v_part);
+		break;
 	}
-	add_gd_partition(hd, minor, start, size);
-	ldm_debug("Created partition successfully.\n");
-	return 1;
+	return TRUE;
 }
 
 /**
- * parse_privhead - parse the LDM database PRIVHEAD structure
- * @buffer:	LDM database privhead structure loaded from the device
- * @ph:		in memory privhead structure to return parsed information in
+ * ldm_frag_add - Add a VBLK fragment to a list
+ * @data:   Raw fragment to be added to the list
+ * @size:   Size of the raw fragment
+ * @frags:  Linked list of VBLK fragments
  *
- * This parses the LDM database PRIVHEAD structure supplied in @buffer and
- * sets up the in memory privhead structure @ph with the obtained information.
+ * Fragmented VBLKs may not be consecutive in the database, so they are placed
+ * in a list so they can be pieced together later.
  *
- * Return 1 on succes and -1 on error, in which case @ph is undefined.
+ * Return:  TRUE   Success, the VBLK was added to the list
+ *          FALSE  Error, a problem occurred
  */
-static int parse_privhead(const u8 *buffer, struct privhead *ph)
+static BOOL ldm_frag_add (const u8 *data, int size, struct list_head *frags)
 {
-	if (MAGIC_PRIVHEAD != BE64(buffer)) {
-		printk(LDM_ERR "Cannot find PRIVHEAD structure. LDM database "
-				"is corrupt. Aborting.\n");
-		return -1;
+	struct frag *f;
+	struct list_head *item;
+	int rec, num, group;
+
+	BUG_ON (!data);
+	BUG_ON (!frags);
+
+	group = BE32 (data + 0x08);
+	rec   = BE16 (data + 0x0C);
+	num   = BE16 (data + 0x0E);
+	if ((num < 1) || (num > 4)) {
+		ldm_error ("A VBLK claims to have %d parts.", num);
+		return FALSE;
 	}
-	ph->ver_major = BE16(buffer + 0x000C);
-	ph->ver_minor = BE16(buffer + 0x000E);
-	if ((ph->ver_major != 2) || (ph->ver_minor != 11)) {
-		printk(LDM_ERR "Expected PRIVHEAD version %d.%d, got %d.%d. "
-				"Aborting.\n", 2, 11, ph->ver_major,
-				ph->ver_minor);
-		return -1;
+
+	list_for_each (item, frags) {
+		f = list_entry (item, struct frag, list);
+		if (f->group == group)
+			goto found;
 	}
-	ph->config_start = BE64(buffer + 0x012B);
-	ph->config_size  = BE64(buffer + 0x0133);
-	if (ph->config_size != LDM_DB_SIZE) {	/* 1 MiB in sectors. */
-		printk(LDM_ERR "Database should be %u bytes, claims to be %Lu "
-				"bytes. Aborting.\n", LDM_DB_SIZE,
-				ph->config_size);
-		return -1;
+
+	f = kmalloc (sizeof (*f) + size*num, GFP_KERNEL);
+	if (!f) {
+		ldm_crit ("Out of memory.");
+		return FALSE;
 	}
-	ph->logical_disk_start = BE64(buffer + 0x011B);
-	ph->logical_disk_size  = BE64(buffer + 0x0123);
-	if (!ph->logical_disk_size ||
-	    ph->logical_disk_start + ph->logical_disk_size > ph->config_start)
-		return -1;
 
-	memcpy(ph->disk_id, buffer + 0x0030, sizeof(ph->disk_id));
+	f->group = group;
+	f->num   = num;
+	f->rec   = rec;
+	f->map   = 0xFF << num;
+
+	list_add_tail (&f->list, frags);
+found:
+	if (f->map & (1 << rec)) {
+		ldm_error ("Duplicate VBLK, part %d.", rec);
+		f->map &= 0x7F;			/* Mark the group as broken */
+		return FALSE;
+	}
 
-	ldm_debug("Parsed PRIVHEAD successfully.\n");
-	return 1;
+	f->map |= (1 << rec);
+
+	if (num > 0) {
+		data += VBLK_SIZE_HEAD;
+		size -= VBLK_SIZE_HEAD;
+	}
+	memcpy (f->data+rec*(size-VBLK_SIZE_HEAD)+VBLK_SIZE_HEAD, data, size);
+
+	return TRUE;
 }
 
 /**
- * create_db_partition - create a dedicated partition for our database
- * @hd:		gendisk structure in which to create partition
- * @dev:	device of which to create partition
- * @ph:		@dev's LDM database private header
+ * ldm_frag_free - Free a linked list of VBLK fragments
+ * @list:  Linked list of fragments
  *
- * Find the primary private header, locate the LDM database, then create a
- * partition to wrap it.
+ * Free a linked list of VBLK fragments
  *
- * Return 1 on succes, 0 if device is not a dynamic disk and -1 on error.
+ * Return:  none
  */
-static int create_db_partition(struct gendisk *hd, struct block_device *bdev,
-		const unsigned long first_sector, const int first_part_minor,
-		struct privhead *ph)
+static void ldm_frag_free (struct list_head *list)
 {
-	Sector sect;
-	unsigned char *data;
-	int err;
+	struct list_head *item, *tmp;
 
-	data = read_dev_sector(bdev, OFF_PRIVHEAD1*2, &sect);
-	if (!data) {
-		printk(LDM_CRIT __FUNCTION__ "(): Device read failed.\n");
-		return -1;
-	}
-	if (BE64(data) != MAGIC_PRIVHEAD) {
-		ldm_debug("Cannot find PRIVHEAD structure. Not a dynamic disk "
-				"or corrupt LDM database.\n");
-		return 0;
+	BUG_ON (!list);
+
+	list_for_each_safe (item, tmp, list)
+		kfree (list_entry (item, struct frag, list));
+}
+
+/**
+ * ldm_frag_commit - Validate fragmented VBLKs and add them to the database
+ * @frags:  Linked list of VBLK fragments
+ * @ldb:    Cache of the database structures
+ *
+ * Now that all the fragmented VBLKs have been collected, they must be added to
+ * the database for later use.
+ *
+ * Return:  TRUE   All the fragments we added successfully
+ *          FALSE  One or more of the fragments we invalid
+ */
+static BOOL ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb)
+{
+	struct frag *f;
+	struct list_head *item;
+
+	BUG_ON (!frags);
+	BUG_ON (!ldb);
+
+	list_for_each (item, frags) {
+		f = list_entry (item, struct frag, list);
+
+		if (f->map != 0xFF) {
+			ldm_error ("VBLK group %d is incomplete (0x%02x).",
+				f->group, f->map);
+			return FALSE;
+		}
+
+		if (!ldm_ldmdb_add (f->data, f->num*ldb->vm.vblk_size, ldb))
+			return FALSE;		/* Already logged */
 	}
-	err = parse_privhead(data, ph);
-	if (err == 1)
-		err = create_partition(hd, first_part_minor, first_sector +
-				ph->config_start, ph->config_size);
-	put_dev_sector(sect);
-	return err;
+	return TRUE;
 }
 
 /**
- * validate_patition_table - check whether @dev is a dynamic disk
- * @dev:	device to test
+ * ldm_get_vblks - Read the on-disk database of VBLKs into memory
+ * @bdev:  Device holding the LDM Database
+ * @base:  Offset, into @bdev, of the database
+ * @ldb:   Cache of the database structures
  *
- * Check whether @dev is a dynamic disk by looking for an MS-DOS-style partition
- * table with one or more entries of type 0x42 (the former Secure File System
- * (Landis) partition type, now recycled by Microsoft for dynamic disks) in it.
- * If this succeeds we assume we have a dynamic disk, and not otherwise.
+ * To use the information from the VBLKs, they need to be read from the disk,
+ * unpacked and validated.  We cache them in @ldb according to their type.
  *
- * Return 1 if @dev is a dynamic disk, 0 if not and -1 on error.
+ * Return:  TRUE   All the VBLKs were read successfully
+ *          FALSE  An error occurred
  */
-static int validate_partition_table(struct block_device *bdev)
+static BOOL ldm_get_vblks (struct block_device *bdev, unsigned long base,
+			   struct ldmdb *ldb)
 {
+	int size, perbuf, skip, finish, s, v, recs;
+	u8 *data = NULL;
 	Sector sect;
-	unsigned char *data;
-	struct partition *p;
-	int i, nr_sfs;
+	BOOL result = FALSE;
+	LIST_HEAD (frags);
 
-	data = read_dev_sector(bdev, 0, &sect);
-	if (!data)
-		return -1;
+	BUG_ON (!bdev);
+	BUG_ON (!ldb);
 
-	if (*(u16*)(data + 0x01FE) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
-		ldm_debug("No MS-DOS partition found.\n");
-		goto no_msdos_partition;
-	}
-	nr_sfs = 0;
-	p = (struct partition*)(data + 0x01BE);
-	for (i = 0; i < 4; i++) {
-		if (!SYS_IND(p+i) || SYS_IND(p+i) == WIN2K_EXTENDED_PARTITION)
-			continue;
-		if (SYS_IND(p+i) == WIN2K_DYNAMIC_PARTITION) {
-			nr_sfs++;
-			continue;
+	size   = ldb->vm.vblk_size;
+	perbuf = 512 / size;
+	skip   = ldb->vm.vblk_offset >> 9;		/* Bytes to sectors */
+	finish = (size * ldb->vm.last_vblk_seq) >> 9;
+
+	for (s = skip; s < finish; s++) {		/* For each sector */
+		data = read_dev_sector (bdev, base + OFF_VMDB + s, &sect);
+		if (!data) {
+			ldm_crit ("Disk read failed.");
+			goto out;
 		}
-		goto not_dynamic_disk;
+
+		for (v = 0; v < perbuf; v++, data+=size) {  /* For each vblk */
+			if (MAGIC_VBLK != BE32 (data)) {
+				ldm_error ("Expected to find a VBLK.");
+				goto out;
+			}
+
+			recs = BE16 (data + 0x0E);	/* Number of records */
+			if (recs == 1) {
+				if (!ldm_ldmdb_add (data, size, ldb))
+					goto out;	/* Already logged */
+			} else if (recs > 1) {
+				if (!ldm_frag_add (data, size, &frags))
+					goto out;	/* Already logged */
+			}
+			/* else Record is not in use, ignore it. */
+		}
+		put_dev_sector (sect);
+		data = NULL;
 	}
-	if (!nr_sfs)
-		goto not_dynamic_disk;
-	ldm_debug("Parsed partition table successfully.\n");
-	put_dev_sector(sect);
-	return 1;
-not_dynamic_disk:
-//	ldm_debug("Found basic MS-DOS partition, not a dynamic disk.\n");
-no_msdos_partition:
-	put_dev_sector(sect);
-	return 0;
+
+	result = ldm_frag_commit (&frags, ldb);	/* Failures, already logged */
+out:
+	if (data)
+		put_dev_sector (sect);
+	ldm_frag_free (&frags);
+
+	return result;
 }
 
 /**
- * ldm_partition - find out whether a device is a dynamic disk and handle it
- * @hd:			gendisk structure in which to return the handled disk
- * @dev:		device we need to look at
- * @first_sector:	first sector within the device
- * @first_part_minor:	first minor number of partitions for the device
+ * ldm_free_vblks - Free a linked list of vblk's
+ * @lh:  Head of a linked list of struct vblk
  *
- * Description:
+ * Free a list of vblk's and free the memory used to maintain the list.
+ *
+ * Return:  none
+ */
+static void ldm_free_vblks (struct list_head *lh)
+{
+	struct list_head *item, *tmp;
+
+	BUG_ON (!lh);
+
+	list_for_each_safe (item, tmp, lh)
+		kfree (list_entry (item, struct vblk, list));
+}
+
+
+/**
+ * ldm_partition - Find out whether a device is a dynamic disk and handle it
+ * @hd:            gendisk structure in which to return the handled disk
+ * @bdev:          Device we need to look at
+ * @first_sector:  First sector within the device
+ * @first_minor:   First minor number of partitions for the device
  *
- * This determines whether the device @dev is a dynamic disk and if so creates
+ * This determines whether the device @bdev is a dynamic disk and if so creates
  * the partitions necessary in the gendisk structure pointed to by @hd.
  *
- * We create a dummy device 1, which contains the LDM database, we skip
- * devices 2-4 and then create each partition described by the LDM database
- * in sequence as devices 5 and following. For example, if the device is hda,
- * we would have: hda1: LDM database, hda2-4: nothing, hda5-following: the
- * actual data containing partitions.
- *
- * Return values:
- *
- *	 1 if @dev is a dynamic disk and we handled it,
- *	 0 if @dev is not a dynamic disk,
- *	-1 if an error occured.
- */
-int ldm_partition(struct gendisk *hd, struct block_device *bdev,
-		unsigned long first_sector, int first_part_minor)
-{
-	struct privhead *ph  = NULL;
-	struct tocblock *toc = NULL;
-	struct vmdb     *vm  = NULL;
-	struct ldmdisk  *dk  = NULL;
-	unsigned long db_first;
-	int err;
+ * We create a dummy device 1, which contains the LDM database, and then create
+ * each partition described by the LDM database in sequence as devices 2+. For
+ * example, if the device is hda, we would have: hda1: LDM database, hda2, hda3,
+ * and so on: the actual data containing partitions.
+ *
+ * Return:  1 Success, @bdev is a dynamic disk and we handled it
+ *          0 Success, @bdev is not a dynamic disk
+ *         -1 An error occurred before enough information had been read
+ *            Or @bdev is a dynamic disk, but it may be corrupted
+ */
+int ldm_partition (struct gendisk *hd, struct block_device *bdev,
+	unsigned long first_sector, int first_minor)
+{
+	struct ldmdb  *ldb;
+	unsigned long base;
+	int result = -1;
+
+	BUG_ON (!hd);
+	BUG_ON (!bdev);
 
-	if (!hd)
+	/* Look for signs of a Dynamic Disk */
+	if (!ldm_validate_partition_table (bdev))
 		return 0;
-	/* Check the partition table. */
-	err = validate_partition_table(bdev);
-	if (err != 1)
-		return err;
-	if (!(ph = (struct privhead*)kmalloc(sizeof(*ph), GFP_KERNEL)))
-		goto no_mem;
-	/* Create the LDM database device. */
-	err = create_db_partition(hd, bdev, first_sector, first_part_minor, ph);
-	if (err != 1)
-		goto out;
-	db_first = hd->part[first_part_minor].start_sect;
-	/* Check the backup privheads. */
-	err = validate_privheads(bdev, ph, db_first);
-	if (err != 1)
-		goto out;
-	/* Check the table of contents and its backups. */
-	if (!(toc = (struct tocblock*)kmalloc(sizeof(*toc), GFP_KERNEL)))
-		goto no_mem;
-	err = validate_tocblocks(bdev, toc, db_first);
-	if (err != 1)
-		goto out;
-	/* Check the vmdb. */
-	if (!(vm = (struct vmdb*)kmalloc(sizeof(*vm), GFP_KERNEL)))
-		goto no_mem;
-	err = validate_vmdb(bdev, vm, db_first);
-	if (err != 1)
-		goto out;
-	/* Find the object id for @dev in the LDM database. */
-	if (!(dk = (struct ldmdisk*)kmalloc(sizeof(*dk), GFP_KERNEL)))
-		goto no_mem;
-	err = get_disk_objid(bdev, vm, ph, dk, db_first);
-	if (err != 1)
+
+	ldb = kmalloc (sizeof (*ldb), GFP_KERNEL);
+	if (!ldb) {
+		ldm_crit ("Out of memory.");
 		goto out;
+	}
+
+	/* Parse and check privheads. */
+	if (!ldm_validate_privheads (bdev, first_sector, &ldb->ph, hd, first_minor))
+		goto out;		/* Already logged */
+
+	/* All further references are relative to base (database start). */
+	base = first_sector + ldb->ph.config_start;
+
+	/* Parse and check tocs and vmdb. */
+	if (!ldm_validate_tocblocks (bdev, base, ldb) ||
+	    !ldm_validate_vmdb      (bdev, base, ldb))
+	    	goto out;		/* Already logged */
+
+	/* Initialize vblk lists in ldmdb struct */
+	INIT_LIST_HEAD (&ldb->v_dgrp);
+	INIT_LIST_HEAD (&ldb->v_disk);
+	INIT_LIST_HEAD (&ldb->v_volu);
+	INIT_LIST_HEAD (&ldb->v_comp);
+	INIT_LIST_HEAD (&ldb->v_part);
+
+	if (!ldm_get_vblks (bdev, base, ldb)) {
+		ldm_crit ("Failed to read the VBLKs from the database.");
+		goto cleanup;
+	}
+
 	/* Finally, create the data partition devices. */
-	err = create_data_partitions(hd, first_sector, first_part_minor +
-			LDM_FIRST_PART_OFFSET, bdev, vm, ph, dk, db_first);
-	if (err == 1)
-		ldm_debug("Parsed LDM database successfully.\n");
+	if (ldm_create_data_partitions (hd, first_sector, first_minor, ldb)) {
+		ldm_debug ("Parsed LDM database successfully.");
+		result = 1;
+	}
+	/* else Already logged */
+
+cleanup:
+	ldm_free_vblks (&ldb->v_dgrp);
+	ldm_free_vblks (&ldb->v_disk);
+	ldm_free_vblks (&ldb->v_volu);
+	ldm_free_vblks (&ldb->v_comp);
+	ldm_free_vblks (&ldb->v_part);
 out:
-	kfree(ph);
-	kfree(toc);
-	kfree(vm);
-	kfree(dk);
-	return err;
-no_mem:
-	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
-	err = -1;
-	goto out;
+	kfree (ldb);
+	return result;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/partitions/ldm.h linux-2.4.20/fs/partitions/ldm.h
--- linux-2.4.19/fs/partitions/ldm.h	2001-11-22 19:48:07.000000000 +0000
+++ linux-2.4.20/fs/partitions/ldm.h	2002-10-29 11:18:36.000000000 +0000
@@ -1,10 +1,9 @@
-#ifndef _FS_PT_LDM_H_
-#define _FS_PT_LDM_H_
-/*
+/**
  * ldm - Part of the Linux-NTFS project.
  *
- * Copyright (C) 2001 Richard Russon <ldm@flatcap.org>
- * Copyright (C) 2001 Anton Altaparmakov <antona@users.sf.net>
+ * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
+ * Copyright (C) 2001      Anton Altaparmakov <aia21@cantab.net>
+ * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
  *
  * Documentation is available at http://linux-ntfs.sf.net/ldm
  *
@@ -23,16 +22,18 @@
  * in the file COPYING); if not, write to the Free Software Foundation,
  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+
+#ifndef _FS_PT_LDM_H_
+#define _FS_PT_LDM_H_
+
 #include <linux/types.h>
+#include <linux/list.h>
+#include <linux/genhd.h>
+#include <linux/fs.h>
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
-#include <linux/genhd.h>
 
-/* Borrowed from kernel.h. */
-#define LDM_PREFIX	"LDM: "	   /* Prefix our error messages with this. */
-#define LDM_CRIT	KERN_CRIT	LDM_PREFIX /* critical conditions */
-#define LDM_ERR		KERN_ERR	LDM_PREFIX /* error conditions */
-#define LDM_DEBUG	KERN_DEBUG	LDM_PREFIX /* debug-level messages */
+struct parsed_partitions;
 
 /* Magic numbers in CPU format. */
 #define MAGIC_VMDB	0x564D4442		/* VMDB */
@@ -41,41 +42,58 @@
 #define MAGIC_TOCBLOCK	0x544F43424C4F434B	/* TOCBLOCK */
 
 /* The defined vblk types. */
-#define VBLK_COMP		0x32		/* Component */
-#define VBLK_PART		0x33		/* Partition */
-#define VBLK_DSK1		0x34		/* Disk */
-#define VBLK_DSK2		0x44		/* Disk */
-#define VBLK_DGR1		0x35		/* Disk Group */
-#define VBLK_DGR2		0x45		/* Disk Group */
-#define VBLK_VOLU		0x51		/* Volume */
+#define VBLK_VOL5		0x51		/* Volume,     version 5 */
+#define VBLK_CMP3		0x32		/* Component,  version 3 */
+#define VBLK_PRT3		0x33		/* Partition,  version 3 */
+#define VBLK_DSK3		0x34		/* Disk,       version 3 */
+#define VBLK_DSK4		0x44		/* Disk,       version 4 */
+#define VBLK_DGR3		0x35		/* Disk Group, version 3 */
+#define VBLK_DGR4		0x45		/* Disk Group, version 4 */
+
+/* vblk flags indicating extra information will be present */
+#define	VBLK_FLAG_COMP_STRIPE	0x10
+#define	VBLK_FLAG_PART_INDEX	0x08
+#define	VBLK_FLAG_DGR3_IDS	0x08
+#define	VBLK_FLAG_DGR4_IDS	0x08
+#define	VBLK_FLAG_VOLU_ID1	0x08
+#define	VBLK_FLAG_VOLU_ID2	0x20
+#define	VBLK_FLAG_VOLU_SIZE	0x80
+#define	VBLK_FLAG_VOLU_DRIVE	0x02
+
+/* size of a vblk's static parts */
+#define VBLK_SIZE_HEAD		16
+#define VBLK_SIZE_CMP3		22		/* Name and version */
+#define VBLK_SIZE_DGR3		12
+#define VBLK_SIZE_DGR4		44
+#define VBLK_SIZE_DSK3		12
+#define VBLK_SIZE_DSK4		45
+#define VBLK_SIZE_PRT3		28
+#define VBLK_SIZE_VOL5		59
+
+/* component types */
+#define COMP_STRIPE		0x01		/* Stripe-set */
+#define COMP_BASIC		0x02		/* Basic disk */
+#define COMP_RAID		0x03		/* Raid-set */
 
 /* Other constants. */
-#define LDM_BLOCKSIZE		1024		/* Size of block in bytes. */
 #define LDM_DB_SIZE		2048		/* Size in sectors (= 1MiB). */
-#define LDM_FIRST_PART_OFFSET	4		/* Add this to first_part_minor
-						   to get to the first data
-						   partition device minor. */
 
-#define OFF_PRIVHEAD1		3		/* Offset of the first privhead
+#define OFF_PRIV1		6		/* Offset of the first privhead
 						   relative to the start of the
-						   device in units of
-						   LDM_BLOCKSIZE. */
+						   device in sectors */
 
-/* Offsets to structures within the LDM Database in units of LDM_BLOCKSIZE. */
-#define OFF_PRIVHEAD2		928		/* Backup private headers. */
-#define OFF_PRIVHEAD3		1023
-
-#define OFF_TOCBLOCK1		0		/* Tables of contents. */
-#define OFF_TOCBLOCK2		1
-#define OFF_TOCBLOCK3		1022
-#define OFF_TOCBLOCK4		1023
-
-#define OFF_VMDB		8		/* List of partitions. */
-#define OFF_VBLK		9
-
-#define WIN2K_DYNAMIC_PARTITION		0x42	/* Formerly SFS (Landis). */
-#define WIN2K_EXTENDED_PARTITION	0x05	/* A standard extended
-						   partition. */
+/* Offsets to structures within the LDM Database in sectors. */
+#define OFF_PRIV2		1856		/* Backup private headers. */
+#define OFF_PRIV3		2047
+
+#define OFF_TOCB1		1		/* Tables of contents. */
+#define OFF_TOCB2		2
+#define OFF_TOCB3		2045
+#define OFF_TOCB4		2046
+
+#define OFF_VMDB		17		/* List of partitions. */
+
+#define WIN2K_DYNAMIC_PARTITION	0x42		/* Formerly SFS (Landis). */
 
 #define TOC_BITMAP1		"config"	/* Names of the two defined */
 #define TOC_BITMAP2		"log"		/* bitmaps in the TOCBLOCK. */
@@ -85,49 +103,42 @@
 #define BE32(x)			((u32)be32_to_cpu(get_unaligned((u32*)(x))))
 #define BE64(x)			((u64)be64_to_cpu(get_unaligned((u64*)(x))))
 
-/* Borrowed from msdos.c. */
+/* Borrowed from msdos.c */
 #define SYS_IND(p)		(get_unaligned(&(p)->sys_ind))
-#define NR_SECTS(p)		({ __typeof__((p)->nr_sects) __a =	\
-					get_unaligned(&(p)->nr_sects);	\
-					le32_to_cpu(__a);		\
-				})
-
-#define START_SECT(p)		({ __typeof__((p)->start_sect) __a =	\
-					get_unaligned(&(p)->start_sect);\
-					le32_to_cpu(__a);		\
-				})
 
-/* In memory LDM database structures. */
+struct frag {				/* VBLK Fragment handling */
+	struct list_head list;
+	u32		group;
+	u8		num;		/* Total number of records */
+	u8		rec;		/* This is record number n */
+	u8		map;		/* Which portions are in use */
+	u8		data[0];
+};
 
-#define DISK_ID_SIZE		64	/* Size in bytes. */
+/* In memory LDM database structures. */
 
-struct ldmdisk {
-	u64	obj_id;
-	u8	disk_id[DISK_ID_SIZE];
-};
+#define GUID_SIZE		16
 
-struct privhead	{			/* Offsets and sizes are in sectors. */
+struct privhead {			/* Offsets and sizes are in sectors. */
 	u16	ver_major;
 	u16	ver_minor;
 	u64	logical_disk_start;
 	u64	logical_disk_size;
 	u64	config_start;
 	u64	config_size;
-	u8	disk_id[DISK_ID_SIZE];
+	u8	disk_id[GUID_SIZE];
 };
 
 struct tocblock {			/* We have exactly two bitmaps. */
 	u8	bitmap1_name[16];
 	u64	bitmap1_start;
 	u64	bitmap1_size;
-	/*u64	bitmap1_flags;*/
 	u8	bitmap2_name[16];
 	u64	bitmap2_start;
 	u64	bitmap2_size;
-	/*u64	bitmap2_flags;*/
 };
 
-struct vmdb {
+struct vmdb {				/* VMDB: The database header */
 	u16	ver_major;
 	u16	ver_minor;
 	u32	vblk_size;
@@ -135,23 +146,76 @@
 	u32	last_vblk_seq;
 };
 
-struct vblk {
-	u8	name[64];
-	u8	vblk_type;
-	u64	obj_id;
+struct vblk_comp {			/* VBLK Component */
+	u8	state[16];
+	u64	parent_id;
+	u8	type;
+	u8	children;
+	u16	chunksize;
+};
+
+struct vblk_dgrp {			/* VBLK Disk Group */
+	u8	disk_id[64];
+};
+
+struct vblk_disk {			/* VBLK Disk */
+	u8	disk_id[GUID_SIZE];
+	u8	alt_name[128];
+};
+
+struct vblk_part {			/* VBLK Partition */
+	u64	start;
+	u64	size;			/* start, size and vol_off in sectors */
+	u64	volume_offset;
+	u64	parent_id;
 	u64	disk_id;
-	u64	start_sector;
-	u64	num_sectors;
+	u8	partnum;
+};
+
+struct vblk_volu {			/* VBLK Volume */
+	u8	volume_type[16];
+	u8	volume_state[16];
+	u8	guid[16];
+	u8	drive_hint[4];
+	u64	size;
+	u8	partition_type;
 };
 
-struct ldm_part {
-	struct list_head part_list;
-	unsigned long start;
-	unsigned long size;
+struct vblk_head {			/* VBLK standard header */
+	u32 group;
+	u16 rec;
+	u16 nrec;
+};
+
+struct vblk {				/* Generalised VBLK */
+	u8	name[64];
+	u64	obj_id;
+	u32	sequence;
+	u8	flags;
+	u8	type;
+	union {
+		struct vblk_comp comp;
+		struct vblk_dgrp dgrp;
+		struct vblk_disk disk;
+		struct vblk_part part;
+		struct vblk_volu volu;
+	} vblk;
+	struct list_head list;
+};
+
+struct ldmdb {				/* Cache of the database */
+	struct privhead ph;
+	struct tocblock toc;
+	struct vmdb     vm;
+	struct list_head v_dgrp;
+	struct list_head v_disk;
+	struct list_head v_volu;
+	struct list_head v_comp;
+	struct list_head v_part;
 };
 
-int ldm_partition(struct gendisk *hd, struct block_device *bdev,
-		unsigned long first_sector, int first_part_minor);
+int ldm_partition (struct gendisk *hd, struct block_device *bdev,
+	unsigned long first_sector, int first_minor);
 
 #endif /* _FS_PT_LDM_H_ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/partitions/msdos.c linux-2.4.20/fs/partitions/msdos.c
--- linux-2.4.19/fs/partitions/msdos.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/partitions/msdos.c	2002-10-29 11:18:32.000000000 +0000
@@ -488,8 +488,8 @@
 	/*
 	 * The i386 partition handling programs very often
 	 * make partitions end on cylinder boundaries.
-	 * There is no need to do so, and Linux fdisk doesnt always
-	 * do this, and Windows NT on Alpha doesnt do this either,
+	 * There is no need to do so, and Linux fdisk doesn't always
+	 * do this, and Windows NT on Alpha doesn't do this either,
 	 * but still, this helps to guess #heads.
 	 */
 	data = read_dev_sector(bdev, 0, &sect);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/partitions/sun.c linux-2.4.20/fs/partitions/sun.c
--- linux-2.4.19/fs/partitions/sun.c	2001-10-02 03:03:26.000000000 +0000
+++ linux-2.4.20/fs/partitions/sun.c	2002-10-29 11:18:37.000000000 +0000
@@ -7,6 +7,7 @@
  *  Re-organised Feb 1998 Russell King
  */
 
+#include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/genhd.h>
 #include <linux/kernel.h>
@@ -19,6 +20,10 @@
 #include "check.h"
 #include "sun.h"
 
+#ifdef CONFIG_BLK_DEV_MD
+extern void md_autodetect_dev(kdev_t dev);
+#endif
+
 int sun_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int first_part_minor)
 {
 	int i, csum;
@@ -27,7 +32,14 @@
 	kdev_t dev = to_kdev_t(bdev->bd_dev);
 	struct sun_disklabel {
 		unsigned char info[128];   /* Informative text string */
-		unsigned char spare[292];  /* Boot information etc. */
+		unsigned char spare0[14];
+		struct sun_info {
+			unsigned char spare1;
+			unsigned char id;
+			unsigned char spare2;
+			unsigned char flags;
+		} infos[8];
+		unsigned char spare[246];  /* Boot information etc. */
 		unsigned short rspeed;     /* Disk rotational speed */
 		unsigned short pcylcount;  /* Physical cylinder count */
 		unsigned short sparecyl;   /* extra sects per cylinder */
@@ -63,22 +75,30 @@
 	ush = ((unsigned short *) (label+1)) - 1;
 	for (csum = 0; ush >= ((unsigned short *) label);)
 		csum ^= *ush--;
-	if(csum) {
+	if (csum) {
 		printk("Dev %s Sun disklabel: Csum bad, label corrupted\n",
 		       bdevname(dev));
 		put_dev_sector(sect);
 		return 0;
 	}
+
 	/* All Sun disks have 8 partition entries */
 	spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect);
-	for(i=0; i < 8; i++, p++) {
+	for (i = 0; i < 8; i++, p++) {
 		unsigned long st_sector;
 		int num_sectors;
 
 		st_sector = first_sector + be32_to_cpu(p->start_cylinder) * spc;
 		num_sectors = be32_to_cpu(p->num_sectors);
-		if (num_sectors)
-			add_gd_partition(hd, first_part_minor, st_sector, num_sectors);
+		if (num_sectors) {
+			add_gd_partition(hd, first_part_minor,
+					 st_sector, num_sectors);
+#ifdef CONFIG_BLK_DEV_MD
+			if (label->infos[i].id == LINUX_RAID_PARTITION)
+				md_autodetect_dev(MKDEV(hd->major,
+							first_part_minor));
+#endif
+		}
 		first_part_minor++;
 	}
 	printk("\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/pipe.c linux-2.4.20/fs/pipe.c
--- linux-2.4.19/fs/pipe.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/pipe.c	2002-10-29 11:18:31.000000000 +0000
@@ -212,7 +212,7 @@
 		do {
 			/*
 			 * Synchronous wake-up: it knows that this process
-			 * is going to give up this CPU, so it doesnt have
+			 * is going to give up this CPU, so it doesn't have
 			 * to do idle reschedules.
 			 */
 			wake_up_interruptible_sync(PIPE_WAIT(*inode));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/proc/proc_misc.c linux-2.4.20/fs/proc/proc_misc.c
--- linux-2.4.19/fs/proc/proc_misc.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/proc/proc_misc.c	2002-10-29 11:18:33.000000000 +0000
@@ -55,7 +55,6 @@
 extern int get_module_list(char *);
 #endif
 extern int get_device_list(char *);
-extern int get_partition_list(char *, char **, off_t, int);
 extern int get_filesystem_list(char *);
 extern int get_exec_domain_list(char *);
 extern int get_irq_list(char *);
@@ -254,6 +253,18 @@
 }
 #endif
 
+extern struct seq_operations partitions_op;
+static int partitions_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &partitions_op);
+}
+static struct file_operations proc_partitions_operations = {
+	open:		partitions_open,
+	read:		seq_read,
+	llseek:		seq_lseek,
+	release:	seq_release,
+};
+
 #ifdef CONFIG_MODULES
 static int modules_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
@@ -377,14 +388,6 @@
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
-static int partitions_read_proc(char *page, char **start, off_t off,
-				 int count, int *eof, void *data)
-{
-	int len = get_partition_list(page, start, off, count);
-	if (len < count) *eof = 1;
-	return len;
-}
-
 #if !defined(CONFIG_ARCH_S390)
 static int interrupts_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
@@ -561,7 +564,6 @@
 #endif
 		{"stat",	kstat_read_proc},
 		{"devices",	devices_read_proc},
-		{"partitions",	partitions_read_proc},
 #if !defined(CONFIG_ARCH_S390)
 		{"interrupts",	interrupts_read_proc},
 #endif
@@ -588,6 +590,7 @@
 	if (entry)
 		entry->proc_fops = &proc_kmsg_operations;
 	create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
+	create_seq_entry("partitions", 0, &proc_partitions_operations);
 	create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
 #ifdef CONFIG_MODULES
 	create_seq_entry("ksyms", 0, &proc_ksyms_operations);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/bitmap.c linux-2.4.20/fs/reiserfs/bitmap.c
--- linux-2.4.19/fs/reiserfs/bitmap.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/bitmap.c	2002-10-29 11:18:49.000000000 +0000
@@ -1,26 +1,70 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
+   
+/* Reiserfs block (de)allocator, bitmap-based. */
 
 #include <linux/config.h>
 #include <linux/sched.h>
-#include <linux/reiserfs_fs.h>
+#include <linux/vmalloc.h>
+#include <linux/errno.h>
 #include <linux/locks.h>
-#include <asm/bitops.h>
-#include <linux/list.h>
+#include <linux/kernel.h>
 
-#ifdef CONFIG_REISERFS_CHECK
+#include <linux/reiserfs_fs.h>
+#include <linux/reiserfs_fs_sb.h>
+#include <linux/reiserfs_fs_i.h>
+
+#define PREALLOCATION_SIZE 9
+
+#define INODE_INFO(inode) (&(inode)->u.reiserfs_i)
+
+/* different reiserfs block allocator options */
+
+#define SB_ALLOC_OPTS(s) ((s)->u.reiserfs_sb.s_alloc_options.bits)
+
+#define  _ALLOC_concentrating_formatted_nodes 0
+#define  _ALLOC_displacing_large_files 1
+#define  _ALLOC_displacing_new_packing_localities 2
+#define  _ALLOC_old_hashed_relocation 3
+#define  _ALLOC_new_hashed_relocation 4
+#define  _ALLOC_skip_busy 5
+#define  _ALLOC_displace_based_on_dirid 6
+#define  _ALLOC_hashed_formatted_nodes 7
+#define  _ALLOC_old_way 8
+#define  _ALLOC_hundredth_slices 9
+
+#define  concentrating_formatted_nodes(s)     test_bit(_ALLOC_concentrating_formatted_nodes, &SB_ALLOC_OPTS(s))
+#define  displacing_large_files(s)            test_bit(_ALLOC_displacing_large_files, &SB_ALLOC_OPTS(s))
+#define  displacing_new_packing_localities(s) test_bit(_ALLOC_displacing_new_packing_localities, &SB_ALLOC_OPTS(s))
+
+#define SET_OPTION(optname) \
+   do { \
+        reiserfs_warning("reiserfs: option \"%s\" is set\n", #optname); \
+        set_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s)); \
+    } while(0)
+#define TEST_OPTION(optname, s) \
+    test_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s))
+
+
+/* #define LIMIT(a,b) do { if ((a) > (b)) (a) = (b); } while(0) */
+
+static inline void get_bit_address (struct super_block * s,
+				    unsigned long block, int * bmap_nr, int * offset)
+{
+    /* It is in the bitmap block number equal to the block
+     * number divided by the number of bits in a block. */
+    *bmap_nr = block / (s->s_blocksize << 3);
+    /* Within that bitmap block it is located at bit offset *offset. */
+    *offset = block & ((s->s_blocksize << 3) - 1 );
+    return;
+}
 
-/* this is a safety check to make sure
-** blocks are reused properly.  used for debugging only.
-**
-** this checks, that block can be reused, and it has correct state
-**   (free or busy) 
-*/
+#ifdef CONFIG_REISERFS_CHECK
 int is_reusable (struct super_block * s, unsigned long block, int bit_value)
 {
     int i, j;
-  
+
     if (block == 0 || block >= SB_BLOCK_COUNT (s)) {
 	reiserfs_warning ("vs-4010: is_reusable: block number is out of range %lu (%u)\n",
 			  block, SB_BLOCK_COUNT (s));
@@ -29,104 +73,266 @@
 
     /* it can't be one of the bitmap blocks */
     for (i = 0; i < SB_BMAP_NR (s); i ++)
-	if (block == SB_AP_BITMAP (s)[i]->b_blocknr) {
+	if (block == SB_AP_BITMAP (s)[i].bh->b_blocknr) {
 	    reiserfs_warning ("vs: 4020: is_reusable: "
 			      "bitmap block %lu(%u) can't be freed or reused\n",
 			      block, SB_BMAP_NR (s));
 	    return 0;
 	}
   
-    i = block / (s->s_blocksize << 3);
+    get_bit_address (s, block, &i, &j);
+
     if (i >= SB_BMAP_NR (s)) {
 	reiserfs_warning ("vs-4030: is_reusable: there is no so many bitmap blocks: "
 			  "block=%lu, bitmap_nr=%d\n", block, i);
 	return 0;
     }
 
-    j = block % (s->s_blocksize << 3);
     if ((bit_value == 0 && 
-         reiserfs_test_le_bit(j, SB_AP_BITMAP(s)[i]->b_data)) ||
+         reiserfs_test_le_bit(j, SB_AP_BITMAP(s)[i].bh->b_data)) ||
 	(bit_value == 1 && 
-	 reiserfs_test_le_bit(j, SB_AP_BITMAP (s)[i]->b_data) == 0)) {
+	 reiserfs_test_le_bit(j, SB_AP_BITMAP (s)[i].bh->b_data) == 0)) {
 	reiserfs_warning ("vs-4040: is_reusable: corresponding bit of block %lu does not "
 			  "match required value (i==%d, j==%d) test_bit==%d\n",
-		block, i, j, reiserfs_test_le_bit (j, SB_AP_BITMAP (s)[i]->b_data));
+		block, i, j, reiserfs_test_le_bit (j, SB_AP_BITMAP (s)[i].bh->b_data));
+		
 	return 0;
     }
 
     if (bit_value == 0 && block == SB_ROOT_BLOCK (s)) {
 	reiserfs_warning ("vs-4050: is_reusable: this is root block (%u), "
-			  "it must be busy", SB_ROOT_BLOCK (s));
+			  "it must be busy\n", SB_ROOT_BLOCK (s));
 	return 0;
     }
 
     return 1;
 }
+#endif /* CONFIG_REISERFS_CHECK */
 
+/* searches in journal structures for a given block number (bmap, off). If block
+   is found in reiserfs journal it suggests next free block candidate to test. */
+static inline  int is_block_in_journal (struct super_block * s, int bmap, int off, int *next)
+{
+    unsigned int tmp;
 
+    if (reiserfs_in_journal (s, s->s_dev, bmap, off, s->s_blocksize, 1, &tmp)) {
+	if (tmp) {		/* hint supplied */
+	    *next = tmp;
+	    PROC_INFO_INC( s, scan_bitmap.in_journal_hint );
+	} else {
+	    (*next) = off + 1;		/* inc offset to avoid looping. */
+	    PROC_INFO_INC( s, scan_bitmap.in_journal_nohint );
+	}
+	PROC_INFO_INC( s, scan_bitmap.retry );
+	return 1;
+    }
+    return 0;
+}
 
+/* it searches for a window of zero bits with given minimum and maximum lengths in one bitmap
+ * block; */
+static int scan_bitmap_block (struct reiserfs_transaction_handle *th,
+			      int bmap_n, int *beg, int boundary, int min, int max, int unfm)
+{
+    struct super_block *s = th->t_super;
+    struct reiserfs_bitmap_info *bi=&SB_AP_BITMAP(s)[bmap_n];
+    int end, next;
+    int org = *beg;
+
+    RFALSE(bmap_n >= SB_BMAP_NR (s), "Bitmap %d is out of range (0..%d)\n",bmap_n, SB_BMAP_NR (s) - 1);
+    PROC_INFO_INC( s, scan_bitmap.bmap );
+/* this is unclear and lacks comments, explain how journal bitmaps
+   work here for the reader.  Convey a sense of the design here. What
+   is a window? */
+/* - I mean `a window of zero bits' as in description of this function - Zam. */
 
-#endif /* CONFIG_REISERFS_CHECK */
+    if ( !bi ) {
+	printk("Hey, bitmap info pointer is zero for bitmap %d!\n",bmap_n);
+	return 0;
+    }
+    if (buffer_locked (bi->bh)) {
+       PROC_INFO_INC( s, scan_bitmap.wait );
+       __wait_on_buffer (bi->bh);
+    }
+
+    /* If we know that first zero bit is only one or first zero bit is
+       closer to the end of bitmap than our start pointer */
+    if (bi->first_zero_hint > *beg || bi->free_count == 1)
+	*beg = bi->first_zero_hint;
+
+    while (1) {
+	cont:
+	if (bi->free_count < min)
+		return 0; // No free blocks in this bitmap
+
+	/* search for a first zero bit -- beggining of a window */
+	*beg = reiserfs_find_next_zero_le_bit
+	        ((unsigned long*)(bi->bh->b_data), boundary, *beg);
 
-/* get address of corresponding bit (bitmap block number and offset in it) */
-static inline void get_bit_address (struct super_block * s, unsigned long block, int * bmap_nr, int * offset)
-{
-                                /* It is in the bitmap block number equal to the block number divided by the number of
-                                   bits in a block. */
-    *bmap_nr = block / (s->s_blocksize << 3);
-                                /* Within that bitmap block it is located at bit offset *offset. */
-    *offset = block % (s->s_blocksize << 3);
-    return;
+	if (*beg + min > boundary) { /* search for a zero bit fails or the rest of bitmap block
+				      * cannot contain a zero window of minimum size */
+	    return 0;
+	}
+
+	if (unfm && is_block_in_journal(s,bmap_n, *beg, beg))
+	    continue;
+	/* first zero bit found; we check next bits */
+	for (end = *beg + 1;; end ++) {
+	    if (end >= *beg + max || end >= boundary || reiserfs_test_le_bit (end, bi->bh->b_data)) {
+		next = end;
+		break;
+	    }
+	    /* finding the other end of zero bit window requires looking into journal structures (in
+	     * case of searching for free blocks for unformatted nodes) */
+	    if (unfm && is_block_in_journal(s, bmap_n, end, &next))
+		break;
+	}
+
+	/* now (*beg) points to beginning of zero bits window,
+	 * (end) points to one bit after the window end */
+	if (end - *beg >= min) { /* it seems we have found window of proper size */
+	    int i;
+	    reiserfs_prepare_for_journal (s, bi->bh, 1);
+	    /* try to set all blocks used checking are they still free */
+	    for (i = *beg; i < end; i++) {
+		/* It seems that we should not check in journal again. */
+		if (reiserfs_test_and_set_le_bit (i, bi->bh->b_data)) {
+		    /* bit was set by another process
+		     * while we slept in prepare_for_journal() */
+		    PROC_INFO_INC( s, scan_bitmap.stolen );
+		    if (i >= *beg + min)	{ /* we can continue with smaller set of allocated blocks,
+					   * if length of this set is more or equal to `min' */
+			end = i;
+			break;
+		    }
+		    /* otherwise we clear all bit were set ... */
+		    while (--i >= *beg)
+			reiserfs_test_and_clear_le_bit (i, bi->bh->b_data);
+		    reiserfs_restore_prepared_buffer (s, bi->bh);
+		    *beg = max(org, (int)bi->first_zero_hint);
+		    /* ... and search again in current block from beginning */
+		    goto cont;	
+		}
+	    }
+	    bi->free_count -= (end - *beg);
+
+	    /* if search started from zero_hint bit, and zero hint have not
+                changed since, then we need to update first_zero_hint */
+	    if ( bi->first_zero_hint >= *beg)
+		/* no point in looking for free bit if there is not any */
+		bi->first_zero_hint = (bi->free_count > 0 ) ?
+			reiserfs_find_next_zero_le_bit
+			((unsigned long*)(bi->bh->b_data), s->s_blocksize << 3, end) : (s->s_blocksize << 3);
+
+	    journal_mark_dirty (th, s, bi->bh);
+
+	    /* free block count calculation */
+	    reiserfs_prepare_for_journal (s, SB_BUFFER_WITH_SB(s), 1);
+	    PUT_SB_FREE_BLOCKS(s, SB_FREE_BLOCKS(s) - (end - *beg));
+	    journal_mark_dirty (th, s, SB_BUFFER_WITH_SB(s));
+
+	    return end - (*beg);
+	} else {
+	    *beg = next;
+	}
+    }
 }
 
+/* Tries to find contiguous zero bit window (given size) in given region of
+ * bitmap and place new blocks there. Returns number of allocated blocks. */
+static int scan_bitmap (struct reiserfs_transaction_handle *th,
+			unsigned long *start, unsigned long finish,
+			int min, int max, int unfm, unsigned long file_block)
+{
+    int nr_allocated=0;
+    struct super_block * s = th->t_super;
+    /* find every bm and bmap and bmap_nr in this file, and change them all to bitmap_blocknr
+     * - Hans, it is not a block number - Zam. */
+
+    int bm, off;
+    int end_bm, end_off;
+    int off_max = s->s_blocksize << 3;
+
+    PROC_INFO_INC( s, scan_bitmap.call ); 
+    if ( SB_FREE_BLOCKS(s) <= 0)
+	return 0; // No point in looking for more free blocks
+
+    get_bit_address (s, *start, &bm, &off);
+    get_bit_address (s, finish, &end_bm, &end_off);
+
+    // With this option set first we try to find a bitmap that is at least 10%
+    // free, and if that fails, then we fall back to old whole bitmap scanning
+    if ( TEST_OPTION(skip_busy, s) && SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s)/20 ) {
+	for (;bm < end_bm; bm++, off = 0) {
+	    if ( ( off && (!unfm || (file_block != 0))) || SB_AP_BITMAP(s)[bm].free_count > (s->s_blocksize << 3) / 10 )
+		nr_allocated = scan_bitmap_block(th, bm, &off, off_max, min, max, unfm);
+	    if (nr_allocated)
+		goto ret;
+        }
+	get_bit_address (s, *start, &bm, &off);
+    }
+
+    for (;bm < end_bm; bm++, off = 0) {
+	nr_allocated = scan_bitmap_block(th, bm, &off, off_max, min, max, unfm);
+	if (nr_allocated)
+	    goto ret;
+    }
+
+    nr_allocated = scan_bitmap_block(th, bm, &off, end_off + 1, min, max, unfm);
 
-/* There would be a modest performance benefit if we write a version
-   to free a list of blocks at once. -Hans */
-				/* I wonder if it would be less modest
-                                   now that we use journaling. -Hans */
-static void _reiserfs_free_block (struct reiserfs_transaction_handle *th, unsigned long block)
+ ret:
+    *start = bm * off_max + off;
+    return nr_allocated;
+
+}
+
+static void _reiserfs_free_block (struct reiserfs_transaction_handle *th,
+			  b_blocknr_t block)
 {
     struct super_block * s = th->t_super;
     struct reiserfs_super_block * rs;
     struct buffer_head * sbh;
-    struct buffer_head ** apbh;
+    struct reiserfs_bitmap_info *apbi;
     int nr, offset;
 
-  PROC_INFO_INC( s, free_block );
-
-  rs = SB_DISK_SUPER_BLOCK (s);
-  sbh = SB_BUFFER_WITH_SB (s);
-  apbh = SB_AP_BITMAP (s);
-
-  get_bit_address (s, block, &nr, &offset);
-
-  if (nr >= sb_bmap_nr (rs)) {
-	  reiserfs_warning ("vs-4075: reiserfs_free_block: "
-			    "block %lu is out of range on %s\n", 
-			    block, bdevname(s->s_dev));
-	  return;
-  }
-
-  reiserfs_prepare_for_journal(s, apbh[nr], 1 ) ;
-
-  /* clear bit for the given block in bit map */
-  if (!reiserfs_test_and_clear_le_bit (offset, apbh[nr]->b_data)) {
-      reiserfs_warning ("vs-4080: reiserfs_free_block: "
-			"free_block (%04x:%lu)[dev:blocknr]: bit already cleared\n", 
-	    s->s_dev, block);
-  }
-  journal_mark_dirty (th, s, apbh[nr]);
+    PROC_INFO_INC( s, free_block );
 
-  reiserfs_prepare_for_journal(s, sbh, 1) ;
-  /* update super block */
-  set_sb_free_blocks( rs, sb_free_blocks(rs) + 1 );
+    rs = SB_DISK_SUPER_BLOCK (s);
+    sbh = SB_BUFFER_WITH_SB (s);
+    apbi = SB_AP_BITMAP(s);
+  
+    get_bit_address (s, block, &nr, &offset);
+  
+    if (nr >= sb_bmap_nr (rs)) {
+	reiserfs_warning ("vs-4075: reiserfs_free_block: "
+			  "block %lu is out of range on %s\n",
+			  block, bdevname(s->s_dev));
+	return;
+    }
 
-  journal_mark_dirty (th, s, sbh);
-  s->s_dirt = 1;
+    reiserfs_prepare_for_journal(s, apbi[nr].bh, 1 ) ;
+  
+    /* clear bit for the given block in bit map */
+    if (!reiserfs_test_and_clear_le_bit (offset, apbi[nr].bh->b_data)) {
+	reiserfs_warning ("vs-4080: reiserfs_free_block: "
+			  "free_block (%04x:%lu)[dev:blocknr]: bit already cleared\n", 
+			  s->s_dev, block);
+    }
+    if (offset < apbi[nr].first_zero_hint) {
+	apbi[nr].first_zero_hint = offset;
+    }
+    apbi[nr].free_count ++;
+    journal_mark_dirty (th, s, apbi[nr].bh);
+  
+    reiserfs_prepare_for_journal(s, sbh, 1) ;
+    /* update super block */
+    set_sb_free_blocks( rs, sb_free_blocks(rs) + 1 );
+  
+    journal_mark_dirty (th, s, sbh);
 }
 
-void reiserfs_free_block (struct reiserfs_transaction_handle *th, 
-                          unsigned long block) {
+void reiserfs_free_block (struct reiserfs_transaction_handle *th,
+			  unsigned long block) {
     struct super_block * s = th->t_super;
 
     RFALSE(!s, "vs-4061: trying to free block on nonexistent device");
@@ -144,568 +350,557 @@
     _reiserfs_free_block(th, block) ;
 }
 
-/* beginning from offset-th bit in bmap_nr-th bitmap block,
-   find_forward finds the closest zero bit. It returns 1 and zero
-   bit address (bitmap, offset) if zero bit found or 0 if there is no
-   zero bit in the forward direction */
-/* The function is NOT SCHEDULE-SAFE! */
-static int find_forward (struct super_block * s, int * bmap_nr, int * offset, int for_unformatted)
-{
-  int i, j;
-  struct buffer_head * bh;
-  unsigned long block_to_try = 0;
-  unsigned long next_block_to_try = 0 ;
-
-  PROC_INFO_INC( s, find_forward.call );
-
-  for (i = *bmap_nr; i < SB_BMAP_NR (s); i ++, *offset = 0, 
-	       PROC_INFO_INC( s, find_forward.bmap )) {
-    /* get corresponding bitmap block */
-    bh = SB_AP_BITMAP (s)[i];
-    if (buffer_locked (bh)) {
-	PROC_INFO_INC( s, find_forward.wait );
-        __wait_on_buffer (bh);
-    }
-retry:
-    j = reiserfs_find_next_zero_le_bit ((unsigned long *)bh->b_data, 
-                                         s->s_blocksize << 3, *offset);
-
-    /* wow, this really needs to be redone.  We can't allocate a block if
-    ** it is in the journal somehow.  reiserfs_in_journal makes a suggestion
-    ** for a good block if the one you ask for is in the journal.  Note,
-    ** reiserfs_in_journal might reject the block it suggests.  The big
-    ** gain from the suggestion is when a big file has been deleted, and
-    ** many blocks show free in the real bitmap, but are all not free
-    ** in the journal list bitmaps.
-    **
-    ** this whole system sucks.  The bitmaps should reflect exactly what
-    ** can and can't be allocated, and the journal should update them as
-    ** it goes.  TODO.
-    */
-    if (j < (s->s_blocksize << 3)) {
-      block_to_try = (i * (s->s_blocksize << 3)) + j; 
-
-      /* the block is not in the journal, we can proceed */
-      if (!(reiserfs_in_journal(s, s->s_dev, block_to_try, s->s_blocksize, for_unformatted, &next_block_to_try))) {
-	*bmap_nr = i;
-	*offset = j;
-	return 1;
-      } 
-      /* the block is in the journal */
-      else if ((j+1) < (s->s_blocksize << 3)) { /* try again */
-	/* reiserfs_in_journal suggested a new block to try */
-	if (next_block_to_try > 0) {
-	  int new_i ;
-	  get_bit_address (s, next_block_to_try, &new_i, offset);
-
-	  PROC_INFO_INC( s, find_forward.in_journal_hint );
-
-	  /* block is not in this bitmap. reset i and continue
-	  ** we only reset i if new_i is in a later bitmap.
-	  */
-	  if (new_i > i) {
-	    i = (new_i - 1 ); /* i gets incremented by the for loop */
-	    PROC_INFO_INC( s, find_forward.in_journal_out );
-	    continue ;
-	  }
-	} else {
-	  /* no suggestion was made, just try the next block */
-	  *offset = j+1 ;
-	}
-	PROC_INFO_INC( s, find_forward.retry );
-	goto retry ;
-      }
+static void __discard_prealloc (struct reiserfs_transaction_handle * th,
+				struct inode * inode)
+{
+    unsigned long save = inode->u.reiserfs_i.i_prealloc_block ;
+#ifdef CONFIG_REISERFS_CHECK
+    if (inode->u.reiserfs_i.i_prealloc_count < 0)
+	reiserfs_warning("zam-4001:%s: inode has negative prealloc blocks count.\n", __FUNCTION__ );
+#endif  
+    while (inode->u.reiserfs_i.i_prealloc_count > 0) {
+	reiserfs_free_prealloc_block(th,inode->u.reiserfs_i.i_prealloc_block);
+	inode->u.reiserfs_i.i_prealloc_block++;
+	inode->u.reiserfs_i.i_prealloc_count --;
+    }
+    inode->u.reiserfs_i.i_prealloc_block = save ;
+    list_del (&(inode->u.reiserfs_i.i_prealloc_list));
+}
+
+/* FIXME: It should be inline function */
+void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th,
+				struct inode * inode)
+{
+    if (inode->u.reiserfs_i.i_prealloc_count) {
+	__discard_prealloc(th, inode);
+    }
+}
+
+void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th)
+{
+  struct list_head * plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
+  struct inode * inode;
+  
+  while (!list_empty(plist)) {
+    inode = list_entry(plist->next, struct inode, u.reiserfs_i.i_prealloc_list);
+#ifdef CONFIG_REISERFS_CHECK
+    if (!inode->u.reiserfs_i.i_prealloc_count) {
+      reiserfs_warning("zam-4001:%s: inode is in prealloc list but has no preallocated blocks.\n", __FUNCTION__ );
     }
+#endif
+    __discard_prealloc(th, inode);
   }
-    /* zero bit not found */
-    return 0;
 }
 
-/* return 0 if no free blocks, else return 1 */
-/* The function is NOT SCHEDULE-SAFE!  
-** because the bitmap block we want to change could be locked, and on its
-** way to the disk when we want to read it, and because of the 
-** flush_async_commits.  Per bitmap block locks won't help much, and 
-** really aren't needed, as we retry later on if we try to set the bit
-** and it is already set.
-*/
-static int find_zero_bit_in_bitmap (struct super_block * s, 
-                                    unsigned long search_start, 
-				    int * bmap_nr, int * offset, 
-				    int for_unformatted)
-{
-  int retry_count = 0 ;
-  /* get bit location (bitmap number and bit offset) of search_start block */
-  get_bit_address (s, search_start, bmap_nr, offset);
-
-    /* note that we search forward in the bitmap, benchmarks have shown that it is better to allocate in increasing
-       sequence, which is probably due to the disk spinning in the forward direction.. */
-    if (find_forward (s, bmap_nr, offset, for_unformatted) == 0) {
-      /* there wasn't a free block with number greater than our
-         starting point, so we are going to go to the beginning of the disk */
-
-retry:
-      search_start = 0; /* caller will reset search_start for itself also. */
-      get_bit_address (s, search_start, bmap_nr, offset);
-      if (find_forward (s, bmap_nr,offset,for_unformatted) == 0) {
-	if (for_unformatted) {	/* why only unformatted nodes? -Hans */
-	  if (retry_count == 0) {
-	    /* we've got a chance that flushing async commits will free up
-	    ** some space.  Sync then retry
-	    */
-	    flush_async_commits(s) ;
-	    retry_count++ ;
-	    goto retry ;
-	  } else if (retry_count > 0) {
-	    /* nothing more we can do.  Make the others wait, flush
-	    ** all log blocks to disk, and flush to their home locations.
-	    ** this will free up any blocks held by the journal
-	    */
-	    SB_JOURNAL(s)->j_must_wait = 1 ;
-	  }
+/* block allocator related options are parsed here */
+int reiserfs_parse_alloc_options(struct super_block * s, char * options)
+{
+    char * this_char, * value;
+
+    s->u.reiserfs_sb.s_alloc_options.bits = 0; /* clear default settings */
+
+    for (this_char = strtok (options, ":"); this_char != NULL; this_char = strtok (NULL, ":")) {
+	if ((value = strchr (this_char, '=')) != NULL)
+	    *value++ = 0;
+
+	if (!strcmp(this_char, "concentrating_formatted_nodes")) {
+	    int temp;
+	    SET_OPTION(concentrating_formatted_nodes);
+	    temp = (value && *value) ? simple_strtoul (value, &value, 0) : 10;
+	    if (temp <= 0 || temp > 100) {
+		s->u.reiserfs_sb.s_alloc_options.border = 10;
+	    } else {
+		s->u.reiserfs_sb.s_alloc_options.border = 100 / temp;
+	   }
+	    continue;
+	}
+	if (!strcmp(this_char, "displacing_large_files")) {
+	    SET_OPTION(displacing_large_files);
+	    s->u.reiserfs_sb.s_alloc_options.large_file_size =
+		(value && *value) ? simple_strtoul (value, &value, 0) : 16;
+	    continue;
+	}
+	if (!strcmp(this_char, "displacing_new_packing_localities")) {
+	    SET_OPTION(displacing_new_packing_localities);
+	    continue;
+	};
+
+	if (!strcmp(this_char, "old_hashed_relocation")) {
+	    SET_OPTION(old_hashed_relocation);
+	    continue;
+	}
+
+	if (!strcmp(this_char, "new_hashed_relocation")) {
+	    SET_OPTION(new_hashed_relocation);
+	    continue;
+	}
+
+	if (!strcmp(this_char, "hashed_formatted_nodes")) {
+	    SET_OPTION(hashed_formatted_nodes);
+	    continue;
+	}
+
+	if (!strcmp(this_char, "skip_busy")) {
+	    SET_OPTION(skip_busy);
+	    continue;
 	}
-        return 0;
-      }
+
+	if (!strcmp(this_char, "hundredth_slices")) {
+	    SET_OPTION(hundredth_slices);
+	    continue;
+	}
+
+	if (!strcmp(this_char, "old_way")) {
+	    SET_OPTION(old_way);
+	    continue;
+	}
+
+	if (!strcmp(this_char, "displace_based_on_dirid")) {
+	    SET_OPTION(displace_based_on_dirid);
+	    continue;
+	}
+
+	if (!strcmp(this_char, "preallocmin")) {
+	    s->u.reiserfs_sb.s_alloc_options.preallocmin =
+		(value && *value) ? simple_strtoul (value, &value, 0) : 4;
+	    continue;
+	}
+
+	if (!strcmp(this_char, "preallocsize")) {
+	    s->u.reiserfs_sb.s_alloc_options.preallocsize =
+		(value && *value) ? simple_strtoul (value, &value, 0) : PREALLOCATION_SIZE;
+	    continue;
+	}
+
+	reiserfs_warning("zam-4001: %s : unknown option - %s\n", __FUNCTION__ , this_char);
+	return 1;
     }
-  return 1;
+
+    return 0;
 }
 
-/* get amount_needed free block numbers from scanning the bitmap of
-   free/used blocks.
-   
-   Optimize layout by trying to find them starting from search_start
-   and moving in increasing blocknr direction.  (This was found to be
-   faster than using a bi-directional elevator_direction, in part
-   because of disk spin direction, in part because by the time one
-   reaches the end of the disk the beginning of the disk is the least
-   congested).
-
-   search_start is the block number of the left
-   semantic neighbor of the node we create.
-
-   return CARRY_ON if everything is ok
-   return NO_DISK_SPACE if out of disk space
-   return NO_MORE_UNUSED_CONTIGUOUS_BLOCKS if the block we found is not contiguous to the last one
-   
-   return block numbers found, in the array free_blocknrs.  assumes
-   that any non-zero entries already present in the array are valid.
-   This feature is perhaps convenient coding when one might not have
-   used all blocknrs from the last time one called this function, or
-   perhaps it is an archaism from the days of schedule tracking, one
-   of us ought to reread the code that calls this, and analyze whether
-   it is still the right way to code it.
-
-   spare space is used only when priority is set to 1. reiserfsck has
-   its own reiserfs_new_blocknrs, which can use reserved space
-
-   exactly what reserved space?  the SPARE_SPACE?  if so, please comment reiserfs.h.
-
-   Give example of who uses spare space, and say that it is a deadlock
-   avoidance mechanism.  -Hans */
-
-/* This function is NOT SCHEDULE-SAFE! */
-
-static int do_reiserfs_new_blocknrs (struct reiserfs_transaction_handle *th,
-                                     unsigned long * free_blocknrs, 
-				     unsigned long search_start, 
-				     int amount_needed, int priority, 
-				     int for_unformatted,
-				     int for_prealloc)
-{
-  struct super_block * s = th->t_super;
-  int i, j;
-  unsigned long * block_list_start = free_blocknrs;
-  int init_amount_needed = amount_needed;
-  unsigned long new_block = 0 ; 
-
-    if (SB_FREE_BLOCKS (s) < SPARE_SPACE && !priority)
-	/* we can answer NO_DISK_SPACE being asked for new block with
-	   priority 0 */
-	return NO_DISK_SPACE;
-
-  RFALSE( !s, "vs-4090: trying to get new block from nonexistent device");
-  RFALSE( search_start == MAX_B_NUM,
-	  "vs-4100: we are optimizing location based on "
-	  "the bogus location of a temp buffer (%lu).", search_start);
-  RFALSE( amount_needed < 1 || amount_needed > 2,
-	  "vs-4110: amount_needed parameter incorrect (%d)", amount_needed);
-
-  /* We continue the while loop if another process snatches our found
-   * free block from us after we find it but before we successfully
-   * mark it as in use */
-
-  while (amount_needed--) {
-    /* skip over any blocknrs already gotten last time. */
-    if (*(free_blocknrs) != 0) {
-      RFALSE( is_reusable (s, *free_blocknrs, 1) == 0, 
-	      "vs-4120: bad blocknr on free_blocknrs list");
-      free_blocknrs++;
-      continue;
-    }
-    /* look for zero bits in bitmap */
-    if (find_zero_bit_in_bitmap(s,search_start, &i, &j,for_unformatted) == 0) {
-      if (find_zero_bit_in_bitmap(s,search_start,&i,&j, for_unformatted) == 0) {
-				/* recode without the goto and without
-				   the if.  It will require a
-				   duplicate for.  This is worth the
-				   code clarity.  Your way was
-				   admirable, and just a bit too
-				   clever in saving instructions.:-)
-				   I'd say create a new function, but
-				   that would slow things also, yes?
-				   -Hans */
-free_and_return:
-	for ( ; block_list_start != free_blocknrs; block_list_start++) {
-	  reiserfs_free_block (th, *block_list_start);
-	  *block_list_start = 0;
-	}
-	if (for_prealloc) 
-	    return NO_MORE_UNUSED_CONTIGUOUS_BLOCKS;
-	else
-	    return NO_DISK_SPACE;
-      }
+static void inline new_hashed_relocation (reiserfs_blocknr_hint_t * hint)
+{
+    char * hash_in;
+    if (hint->formatted_node) {
+	    hash_in = (char*)&hint->key.k_dir_id;
+    } else {
+	if (!hint->inode) {
+	    //hint->search_start = hint->beg;
+	    hash_in = (char*)&hint->key.k_dir_id;
+	} else 
+	    if ( TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
+		hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id);
+	    else
+		hash_in = (char *)(&INODE_PKEY(hint->inode)->k_objectid);
     }
-    
-    /* i and j now contain the results of the search. i = bitmap block
-       number containing free block, j = offset in this block.  we
-       compute the blocknr which is our result, store it in
-       free_blocknrs, and increment the pointer so that on the next
-       loop we will insert into the next location in the array.  Also
-       in preparation for the next loop, search_start is changed so
-       that the next search will not rescan the same range but will
-       start where this search finished.  Note that while it is
-       possible that schedule has occurred and blocks have been freed
-       in that range, it is perhaps more important that the blocks
-       returned be near each other than that they be near their other
-       neighbors, and it also simplifies and speeds the code this way.  */
-
-    /* journal: we need to make sure the block we are giving out is not
-    ** a log block, horrible things would happen there.
-    */
-    new_block = (i * (s->s_blocksize << 3)) + j; 
-    if (for_prealloc && (new_block - 1) != search_start) {
-      /* preallocated blocks must be contiguous, bail if we didnt find one.
-      ** this is not a bug.  We want to do the check here, before the
-      ** bitmap block is prepared, and before we set the bit and log the
-      ** bitmap. 
-      **
-      ** If we do the check after this function returns, we have to 
-      ** call reiserfs_free_block for new_block, which would be pure
-      ** overhead.
-      **
-      ** for_prealloc should only be set if the caller can deal with the
-      ** NO_MORE_UNUSED_CONTIGUOUS_BLOCKS return value.  This can be
-      ** returned before the disk is actually full
-      */
-      goto free_and_return ;
-    }
-    search_start = new_block ;
-    if (search_start >= reiserfs_get_journal_block(s) &&
-        search_start < (reiserfs_get_journal_block(s) + JOURNAL_BLOCK_COUNT)) {
-	reiserfs_warning("vs-4130: reiserfs_new_blocknrs: trying to allocate log block %lu\n",
-			 search_start) ;
-	search_start++ ;
-	amount_needed++ ;
-	continue ;
-    }
-       
-
-    reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[i], 1) ;
-
-    RFALSE( buffer_locked (SB_AP_BITMAP (s)[i]) || 
-	    is_reusable (s, search_start, 0) == 0,
-	    "vs-4140: bitmap block is locked or bad block number found");
-
-    /* if this bit was already set, we've scheduled, and someone else
-    ** has allocated it.  loop around and try again
-    */
-    if (reiserfs_test_and_set_le_bit (j, SB_AP_BITMAP (s)[i]->b_data)) {
-	reiserfs_restore_prepared_buffer(s, SB_AP_BITMAP(s)[i]) ;
-	amount_needed++ ;
-	continue ;
-    }    
-    journal_mark_dirty (th, s, SB_AP_BITMAP (s)[i]); 
-    *free_blocknrs = search_start ;
-    free_blocknrs ++;
-  }
 
-  reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
-  /* update free block count in super block */
-  PUT_SB_FREE_BLOCKS( s, SB_FREE_BLOCKS(s) - init_amount_needed );
-  journal_mark_dirty (th, s, SB_BUFFER_WITH_SB (s));
-  s->s_dirt = 1;
-
-  return CARRY_ON;
-}
-
-// this is called only by get_empty_nodes
-int reiserfs_new_blocknrs (struct reiserfs_transaction_handle *th, unsigned long * free_blocknrs,
-			    unsigned long search_start, int amount_needed) {
-  return do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, amount_needed, 0/*priority*/, 0/*for_formatted*/, 0/*for_prealloc */) ;
-}
-
-
-// called by get_new_buffer and by reiserfs_get_block with amount_needed == 1
-int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle *th, unsigned long * free_blocknrs,
-			      unsigned long search_start) {
-  return do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, 
-                                  1/*amount_needed*/,
-				  0/*priority*/, 
-				  1/*for formatted*/,
-				  0/*for prealloc */) ;
-}
-
-#ifdef REISERFS_PREALLOCATE
-
-/* 
-** We pre-allocate 8 blocks.  Pre-allocation is used for files > 16 KB only.
-** This lowers fragmentation on large files by grabbing a contiguous set of
-** blocks at once.  It also limits the number of times the bitmap block is
-** logged by making X number of allocation changes in a single transaction.
-**
-** We are using a border to divide the disk into two parts.  The first part
-** is used for tree blocks, which have a very high turnover rate (they
-** are constantly allocated then freed)
-**
-** The second part of the disk is for the unformatted nodes of larger files.
-** Putting them away from the tree blocks lowers fragmentation, and makes
-** it easier to group files together.  There are a number of different
-** allocation schemes being tried right now, each is documented below.
-**
-** A great deal of the allocator's speed comes because reiserfs_get_block
-** sends us the block number of the last unformatted node in the file.  Once
-** a given block is allocated past the border, we don't collide with the
-** blocks near the search_start again.
-** 
-*/
-int reiserfs_new_unf_blocknrs2 (struct reiserfs_transaction_handle *th, 
-				struct inode       * p_s_inode,
-				unsigned long      * free_blocknrs,
-				unsigned long        search_start)
-{
-  int ret=0, blks_gotten=0;
-  unsigned long border = 0;
-  unsigned long bstart = 0;
-  unsigned long hash_in, hash_out;
-  unsigned long saved_search_start=search_start;
-  int allocated[PREALLOCATION_SIZE];
-  int blks;
-
-  if (!reiserfs_no_border(th->t_super)) {
-    /* we default to having the border at the 10% mark of the disk.  This
-    ** is an arbitrary decision and it needs tuning.  It also needs a limit
-    ** to prevent it from taking too much space on huge drives.
-    */
-    bstart = (SB_BLOCK_COUNT(th->t_super) / 10); 
-  }
-  if (!reiserfs_no_unhashed_relocation(th->t_super)) {
-    /* this is a very simple first attempt at preventing too much grouping
-    ** around the border value.  Since k_dir_id is never larger than the
-    ** highest allocated oid, it is far from perfect, and files will tend
-    ** to be grouped towards the start of the border
-    */
-    border = le32_to_cpu(INODE_PKEY(p_s_inode)->k_dir_id) % (SB_BLOCK_COUNT(th->t_super) - bstart - 1) ;
-  } else if (!reiserfs_hashed_relocation(th->t_super)) {
-      hash_in = le32_to_cpu((INODE_PKEY(p_s_inode))->k_dir_id);
-				/* I wonder if the CPU cost of the
-                                   hash will obscure the layout
-                                   effect? Of course, whether that
-                                   effect is good or bad we don't
-                                   know.... :-) */
-      
-      hash_out = keyed_hash(((char *) (&hash_in)), 4);
-      border = hash_out % (SB_BLOCK_COUNT(th->t_super) - bstart - 1) ;
-  }
-  border += bstart ;
-  allocated[0] = 0 ; /* important.  Allows a check later on to see if at
-                      * least one block was allocated.  This prevents false
-		      * no disk space returns
-		      */
-
-  if ( (p_s_inode->i_size < 4 * 4096) || 
-       !(S_ISREG(p_s_inode->i_mode)) )
-    {
-      if ( search_start < border 
-	   || (
-				/* allow us to test whether it is a
-                                   good idea to prevent files from
-                                   getting too far away from their
-                                   packing locality by some unexpected
-                                   means.  This might be poor code for
-                                   directories whose files total
-                                   larger than 1/10th of the disk, and
-                                   it might be good code for
-                                   suffering from old insertions when the disk
-                                   was almost full. */
-               /* changed from !reiserfs_test3(th->t_super), which doesn't
-               ** seem like a good idea.  Think about adding blocks to
-               ** a large file.  If you've allocated 10% of the disk
-               ** in contiguous blocks, you start over at the border value
-               ** for every new allocation.  This throws away all the
-               ** information sent in about the last block that was allocated
-               ** in the file.  Not a good general case at all.
-               ** -chris
-               */
-	       reiserfs_test4(th->t_super) && 
-	       (search_start > border + (SB_BLOCK_COUNT(th->t_super) / 10))
-	       )
-	   )
-	search_start=border;
-  
-      ret = do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, 
-				     1/*amount_needed*/, 
-				     0/*use reserved blocks for root */,
-				     1/*for_formatted*/,
-				     0/*for prealloc */) ;  
-      return ret;
-    }
-
-  /* take a block off the prealloc list and return it -Hans */
-  if (p_s_inode->u.reiserfs_i.i_prealloc_count > 0) {
-    p_s_inode->u.reiserfs_i.i_prealloc_count--;
-    *free_blocknrs = p_s_inode->u.reiserfs_i.i_prealloc_block++;
-
-    /* if no more preallocated blocks, remove inode from list */
-    if (! p_s_inode->u.reiserfs_i.i_prealloc_count) {
-      list_del(&p_s_inode->u.reiserfs_i.i_prealloc_list);
+    hint->search_start = hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
+}
+
+static void inline get_left_neighbor(reiserfs_blocknr_hint_t *hint)
+{
+    struct path * path;
+    struct buffer_head * bh;
+    struct item_head * ih;
+    int pos_in_item;
+    __u32 * item;
+
+    if (!hint->path)		/* reiserfs code can call this function w/o pointer to path
+				 * structure supplied; then we rely on supplied search_start */
+	return;
+
+    path = hint->path;
+    bh = get_last_bh(path);
+    RFALSE( !bh, "green-4002: Illegal path specified to get_left_neighbor\n");
+    ih = get_ih(path);
+    pos_in_item = path->pos_in_item;
+    item = get_item (path);
+
+    hint->search_start = bh->b_blocknr;
+
+    if (!hint->formatted_node && is_indirect_le_ih (ih)) {
+	/* for indirect item: go to left and look for the first non-hole entry
+	   in the indirect item */
+	if (pos_in_item == I_UNFM_NUM (ih))
+	    pos_in_item--;
+//	    pos_in_item = I_UNFM_NUM (ih) - 1;
+	while (pos_in_item >= 0) {
+	    int t=get_block_num(item,pos_in_item);
+	    if (t) {
+		hint->search_start = t;
+		break;
+	    }
+	    pos_in_item --;
+	}
+    } else {
     }
+
+    /* does result value fit into specified region? */
+    return;
+}
+
+/* should be, if formatted node, then try to put on first part of the device
+   specified as number of percent with mount option device, else try to put
+   on last of device.  This is not to say it is good code to do so,
+   but the effect should be measured.  */
+static void inline set_border_in_hint(struct super_block *s, reiserfs_blocknr_hint_t *hint)
+{
+    b_blocknr_t border = SB_BLOCK_COUNT(hint->th->t_super) / s->u.reiserfs_sb.s_alloc_options.border;
+
+    if (hint->formatted_node)
+	hint->end = border - 1;
+    else
+	hint->beg = border;
+}
+
+static void inline displace_large_file(reiserfs_blocknr_hint_t *hint)
+{
+    if ( TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
+	hint->search_start = hint->beg + keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_dir_id), 4) % (hint->end - hint->beg);
+    else
+	hint->search_start = hint->beg + keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_objectid), 4) % (hint->end - hint->beg);
+}
+
+static void inline hash_formatted_node(reiserfs_blocknr_hint_t *hint)
+{
+   char * hash_in;
+
+   if (!hint->inode)
+	hash_in = (char*)&hint->key.k_dir_id;
+    else if ( TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
+	hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id);
+    else
+	hash_in = (char *)(&INODE_PKEY(hint->inode)->k_objectid);
+
+	hint->search_start = hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
+}
+
+static int inline this_blocknr_allocation_would_make_it_a_large_file(reiserfs_blocknr_hint_t *hint)
+{
+    return hint->block == hint->th->t_super->u.reiserfs_sb.s_alloc_options.large_file_size;
+}
+
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+static void inline displace_new_packing_locality (reiserfs_blocknr_hint_t *hint)
+{
+    struct key * key = &hint->key;
+
+    hint->th->displace_new_blocks = 0;
+    hint->search_start = hint->beg + keyed_hash((char*)(&key->k_objectid),4) % (hint->end - hint->beg);
+}
+#endif
+
+static int inline old_hashed_relocation (reiserfs_blocknr_hint_t * hint)
+{
+    unsigned long border;
+    unsigned long hash_in;
     
-    return ret;
-  }
+    if (hint->formatted_node || hint->inode == NULL) {
+	return 0;
+    }
 
-				/* else get a new preallocation for the file */
-  reiserfs_discard_prealloc (th, p_s_inode);
-  /* this uses the last preallocated block as the search_start.  discard
-  ** prealloc does not zero out this number.
-  */
-  if (search_start <= p_s_inode->u.reiserfs_i.i_prealloc_block) {
-    search_start = p_s_inode->u.reiserfs_i.i_prealloc_block;
-  }
-  
-  /* doing the compare again forces search_start to be >= the border,
-  ** even if the file already had prealloction done.  This seems extra,
-  ** and should probably be removed
-  */
-  if ( search_start < border ) search_start=border; 
-
-  /* If the disk free space is already below 10% we should 
-  ** start looking for the free blocks from the beginning 
-  ** of the partition, before the border line.
-  */
-  if ( SB_FREE_BLOCKS(th->t_super) <= (SB_BLOCK_COUNT(th->t_super) / 10) ) {
-    search_start=saved_search_start;
-  }
+    hash_in = le32_to_cpu((INODE_PKEY(hint->inode))->k_dir_id);
+    border = hint->beg + (unsigned long) keyed_hash(((char *) (&hash_in)), 4) % (hint->end - hint->beg - 1);
+    if (border > hint->search_start)
+	hint->search_start = border;
 
-  *free_blocknrs = 0;
-  blks = PREALLOCATION_SIZE-1;
-  for (blks_gotten=0; blks_gotten<PREALLOCATION_SIZE; blks_gotten++) {
-    ret = do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, 
-				   1/*amount_needed*/, 
-				   0/*for root reserved*/,
-				   1/*for_formatted*/,
-				   (blks_gotten > 0)/*must_be_contiguous*/) ;
-    /* if we didn't find a block this time, adjust blks to reflect
-    ** the actual number of blocks allocated
-    */ 
-    if (ret != CARRY_ON) {
-      blks = blks_gotten > 0 ? (blks_gotten - 1) : 0 ;
-      break ;
+    return 1;
+}
+
+static int inline old_way (reiserfs_blocknr_hint_t * hint)
+{
+    unsigned long border;
+    
+    if (hint->formatted_node || hint->inode == NULL) {
+	return 0;
     }
-    allocated[blks_gotten]= *free_blocknrs;
-#ifdef CONFIG_REISERFS_CHECK
-    if ( (blks_gotten>0) && (allocated[blks_gotten] - allocated[blks_gotten-1]) != 1 ) {
-      /* this should be caught by new_blocknrs now, checking code */
-      reiserfs_warning("yura-1, reiserfs_new_unf_blocknrs2: pre-allocated not contiguous set of blocks!\n") ;
-      reiserfs_free_block(th, allocated[blks_gotten]);
-      blks = blks_gotten-1; 
-      break;
+
+      border = hint->beg + le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id) % (hint->end  - hint->beg);
+    if (border > hint->search_start)
+	hint->search_start = border;
+
+    return 1;
+}
+
+static void inline hundredth_slices (reiserfs_blocknr_hint_t * hint)
+{
+    struct key * key = &hint->key;
+    unsigned long slice_start;
+
+    slice_start = (keyed_hash((char*)(&key->k_dir_id),4) % 100) * (hint->end / 100);
+    if ( slice_start > hint->search_start || slice_start + (hint->end / 100) <= hint->search_start) {
+	hint->search_start = slice_start;
     }
+}
+
+static void inline determine_search_start(reiserfs_blocknr_hint_t *hint,
+					  int amount_needed)
+{
+    struct super_block *s = hint->th->t_super;
+    hint->beg = 0;
+    hint->end = SB_BLOCK_COUNT(s) - 1;
+
+    /* This is former border algorithm. Now with tunable border offset */
+    if (concentrating_formatted_nodes(s))
+	set_border_in_hint(s, hint);
+
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+    /* whenever we create a new directory, we displace it.  At first we will
+       hash for location, later we might look for a moderately empty place for
+       it */
+    if (displacing_new_packing_localities(s)
+	&& hint->th->displace_new_blocks) {
+	displace_new_packing_locality(hint);
+
+	/* we do not continue determine_search_start,
+	 * if new packing locality is being displaced */
+	return;
+    }				      
 #endif
-    if (blks_gotten==0) {
-      p_s_inode->u.reiserfs_i.i_prealloc_block = *free_blocknrs;
+
+    /* all persons should feel encouraged to add more special cases here and
+     * test them */
+
+    if (displacing_large_files(s) && !hint->formatted_node
+	&& this_blocknr_allocation_would_make_it_a_large_file(hint)) {
+	displace_large_file(hint);
+	return;
+    }
+
+    /* attempt to copy a feature from old block allocator code */
+    if (TEST_OPTION(old_hashed_relocation, s) && !hint->formatted_node) {
+	old_hashed_relocation(hint);
+    }
+
+    /* if none of our special cases is relevant, use the left neighbor in the
+       tree order of the new node we are allocating for */
+    if (hint->formatted_node && TEST_OPTION(hashed_formatted_nodes,s)) {
+	hash_formatted_node(hint);
+	return;
+    } 
+
+    get_left_neighbor(hint);
+
+    /* Mimic old block allocator behaviour, that is if VFS allowed for preallocation,
+       new blocks are displaced based on directory ID. Also, if suggested search_start
+       is less than last preallocated block, we start searching from it, assuming that
+       HDD dataflow is faster in forward direction */
+    if ( TEST_OPTION(old_way, s)) {
+	if (!hint->formatted_node) {
+	    if ( !reiserfs_hashed_relocation(s))
+		old_way(hint);
+	    else if (!reiserfs_no_unhashed_relocation(s))
+		old_hashed_relocation(hint);
+
+	    if ( hint->inode && hint->search_start < hint->inode->u.reiserfs_i.i_prealloc_block)
+		hint->search_start = hint->inode->u.reiserfs_i.i_prealloc_block;
+	}
+	return;
     }
-    search_start = *free_blocknrs; 
-    *free_blocknrs = 0;
-  }
-  p_s_inode->u.reiserfs_i.i_prealloc_count = blks;
-  *free_blocknrs = p_s_inode->u.reiserfs_i.i_prealloc_block;
-  p_s_inode->u.reiserfs_i.i_prealloc_block++;
-
-  /* if inode has preallocated blocks, link him to list */
-  if (p_s_inode->u.reiserfs_i.i_prealloc_count) {
-    list_add(&p_s_inode->u.reiserfs_i.i_prealloc_list,
-	     &SB_JOURNAL(th->t_super)->j_prealloc_list);
-  } 
-  /* we did actually manage to get 1 block */
-  if (ret != CARRY_ON && allocated[0] > 0) {
-    return CARRY_ON ;
-  }
-  /* NO_MORE_UNUSED_CONTIGUOUS_BLOCKS should only mean something to
-  ** the preallocation code.  The rest of the filesystem asks for a block
-  ** and should either get it, or know the disk is full.  The code
-  ** above should never allow ret == NO_MORE_UNUSED_CONTIGUOUS_BLOCK,
-  ** as it doesn't send for_prealloc = 1 to do_reiserfs_new_blocknrs
-  ** unless it has already successfully allocated at least one block.
-  ** Just in case, we translate into a return value the rest of the
-  ** filesystem can understand.
-  **
-  ** It is an error to change this without making the
-  ** rest of the filesystem understand NO_MORE_UNUSED_CONTIGUOUS_BLOCKS
-  ** If you consider it a bug to return NO_DISK_SPACE here, fix the rest
-  ** of the fs first.
-  */
-  if (ret == NO_MORE_UNUSED_CONTIGUOUS_BLOCKS) {
-#ifdef CONFIG_REISERFS_CHECK
-    reiserfs_warning("reiser-2015: this shouldn't happen, may cause false out of disk space error");
-#endif
-     return NO_DISK_SPACE; 
-  }
-  return ret;
+
+    /* This is an approach proposed by Hans */
+    if ( TEST_OPTION(hundredth_slices, s) && ! (displacing_large_files(s) && !hint->formatted_node)) {
+	hundredth_slices(hint);
+	return;
+    }
+
+    if (TEST_OPTION(old_hashed_relocation, s))
+	old_hashed_relocation(hint);
+    if (TEST_OPTION(new_hashed_relocation, s))
+	new_hashed_relocation(hint);
+    return;
 }
 
-//
-// a portion of this function, was derived from minix or ext2's
-// analog. You should be able to tell which portion by looking at the
-// ext2 code and comparing. 
-static void __discard_prealloc (struct reiserfs_transaction_handle * th,
-				struct inode * inode)
+static int determine_prealloc_size(reiserfs_blocknr_hint_t * hint)
 {
-  unsigned long save = inode->u.reiserfs_i.i_prealloc_block ;
-  while (inode->u.reiserfs_i.i_prealloc_count > 0) {
-    reiserfs_free_prealloc_block(th,inode->u.reiserfs_i.i_prealloc_block);
-    inode->u.reiserfs_i.i_prealloc_block++;
-    inode->u.reiserfs_i.i_prealloc_count --;
-  }
-  inode->u.reiserfs_i.i_prealloc_block = save ; 
-  list_del (&(inode->u.reiserfs_i.i_prealloc_list));
-}
+    /* make minimum size a mount option and benchmark both ways */
+    /* we preallocate blocks only for regular files, specific size */
+    /* benchmark preallocating always and see what happens */
+
+    hint->prealloc_size = 0;
+
+    if (!hint->formatted_node && hint->preallocate) {
+	if (S_ISREG(hint->inode->i_mode)
+	    && hint->inode->i_size >= hint->th->t_super->u.reiserfs_sb.s_alloc_options.preallocmin * hint->inode->i_sb->s_blocksize)
+	    hint->prealloc_size = hint->th->t_super->u.reiserfs_sb.s_alloc_options.preallocsize - 1;
+    }
+    return CARRY_ON;
+}
+
+/* XXX I know it could be merged with upper-level function;
+   but may be result function would be too complex. */
+static inline int allocate_without_wrapping_disk (reiserfs_blocknr_hint_t * hint,
+					 b_blocknr_t * new_blocknrs,
+					 b_blocknr_t start, b_blocknr_t finish,
+					 int amount_needed, int prealloc_size)
+{
+    int rest = amount_needed;
+    int nr_allocated;
+
+    while (rest > 0) {
+	nr_allocated = scan_bitmap (hint->th, &start, finish, 1,
+				    rest + prealloc_size, !hint->formatted_node,
+				    hint->block);
+
+	if (nr_allocated == 0)	/* no new blocks allocated, return */
+	    break;
+	
+	/* fill free_blocknrs array first */
+	while (rest > 0 && nr_allocated > 0) {
+	    * new_blocknrs ++ = start ++;
+	    rest --; nr_allocated --;
+	}
 
+	/* do we have something to fill prealloc. array also ? */
+	if (nr_allocated > 0) {
+	    /* it means prealloc_size was greater that 0 and we do preallocation */
+	    list_add(&INODE_INFO(hint->inode)->i_prealloc_list,
+		     &SB_JOURNAL(hint->th->t_super)->j_prealloc_list);
+	    INODE_INFO(hint->inode)->i_prealloc_block = start;
+	    INODE_INFO(hint->inode)->i_prealloc_count = nr_allocated;
+	    break;
+	}
+    }
 
-void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th, 
-				struct inode * inode)
+    return (amount_needed - rest);
+}
+
+static inline int blocknrs_and_prealloc_arrays_from_search_start
+    (reiserfs_blocknr_hint_t *hint, b_blocknr_t *new_blocknrs, int amount_needed)
 {
-#ifdef CONFIG_REISERFS_CHECK
-  if (inode->u.reiserfs_i.i_prealloc_count < 0)
-     reiserfs_warning("zam-4001:" __FUNCTION__ ": inode has negative prealloc blocks count.\n");
-#endif  
-    if (inode->u.reiserfs_i.i_prealloc_count > 0) {
-    __discard_prealloc(th, inode);
-  }
-      }
+    struct super_block *s = hint->th->t_super;
+    b_blocknr_t start = hint->search_start;
+    b_blocknr_t finish = SB_BLOCK_COUNT(s) - 1;
+    int second_pass = 0;
+    int nr_allocated = 0;
+
+    determine_prealloc_size(hint);
+    while((nr_allocated
+	  += allocate_without_wrapping_disk(hint, new_blocknrs + nr_allocated, start, finish,
+					  amount_needed - nr_allocated, hint->prealloc_size))
+	  < amount_needed) {
+
+	/* not all blocks were successfully allocated yet*/
+	if (second_pass) {	/* it was a second pass; we must free all blocks */
+	    while (nr_allocated --)
+		reiserfs_free_block(hint->th, new_blocknrs[nr_allocated]);
 
-void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th)
+	    return NO_DISK_SPACE;
+	} else {		/* refine search parameters for next pass */
+	    second_pass = 1;
+	    finish = start;
+	    start = 0;
+	    continue;
+	}
+    }
+    return CARRY_ON;
+}
+
+/* grab new blocknrs from preallocated list */
+/* return amount still needed after using them */
+static int use_preallocated_list_if_available (reiserfs_blocknr_hint_t *hint,
+					       b_blocknr_t *new_blocknrs, int amount_needed)
 {
-  struct list_head * plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
-  struct inode * inode;
-  
-  while (!list_empty(plist)) {
-    inode = list_entry(plist->next, struct inode, u.reiserfs_i.i_prealloc_list);
-#ifdef CONFIG_REISERFS_CHECK
-    if (!inode->u.reiserfs_i.i_prealloc_count) {
-      reiserfs_warning("zam-4001:" __FUNCTION__ ": inode is in prealloc list but has no preallocated blocks.\n");
+    struct inode * inode = hint->inode;
+
+    if (INODE_INFO(inode)->i_prealloc_count > 0) {
+	while (amount_needed) {
+
+	    *new_blocknrs ++ = INODE_INFO(inode)->i_prealloc_block ++;
+	    INODE_INFO(inode)->i_prealloc_count --;
+
+	    amount_needed --;
+
+	    if (INODE_INFO(inode)->i_prealloc_count <= 0) {
+		list_del(&inode->u.reiserfs_i.i_prealloc_list);  
+		break;
+	    }
+	}
     }
-#endif    
-    __discard_prealloc(th, inode);
+    /* return amount still needed after using preallocated blocks */
+    return amount_needed;
+}
+
+int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *hint,
+			       b_blocknr_t * new_blocknrs, int amount_needed,
+			       int reserved_by_us /* Amount of blocks we have
+						      already reserved */)
+{
+    int initial_amount_needed = amount_needed;
+    int ret;
+
+    /* Check if there is enough space, taking into account reserved space */
+    if ( SB_FREE_BLOCKS(hint->th->t_super) - hint->th->t_super->u.reiserfs_sb.reserved_blocks <
+	 amount_needed - reserved_by_us)
+        return NO_DISK_SPACE;
+    /* should this be if !hint->inode &&  hint->preallocate? */
+    /* do you mean hint->formatted_node can be removed ? - Zam */
+    /* hint->formatted_node cannot be removed because we try to access
+       inode information here, and there is often no inode assotiated with
+       metadata allocations - green */
+
+    if (!hint->formatted_node && hint->preallocate) {
+	amount_needed = use_preallocated_list_if_available
+	    (hint, new_blocknrs, amount_needed);
+	if (amount_needed == 0)	/* all blocknrs we need we got from
+                                   prealloc. list */
+	    return CARRY_ON;
+	new_blocknrs += (initial_amount_needed - amount_needed);
+    }
+
+    /* find search start and save it in hint structure */
+    determine_search_start(hint, amount_needed);
+
+    /* allocation itself; fill new_blocknrs and preallocation arrays */
+    ret = blocknrs_and_prealloc_arrays_from_search_start
+	(hint, new_blocknrs, amount_needed);
+
+    /* we used prealloc. list to fill (partially) new_blocknrs array. If final allocation fails we
+     * need to return blocks back to prealloc. list or just free them. -- Zam (I chose second
+     * variant) */
+
+    if (ret != CARRY_ON) {
+	while (amount_needed ++ < initial_amount_needed) {
+	    reiserfs_free_block(hint->th, *(--new_blocknrs));
+	}
     }
+    return ret;
+}
+
+/* These 2 functions are here to provide blocks reservation to the rest of kernel */
+/* Reserve @blocks amount of blocks in fs pointed by @sb. Caller must make sure
+   there are actually this much blocks on the FS available */
+void reiserfs_claim_blocks_to_be_allocated( 
+				      struct super_block *sb, /* super block of
+							        filesystem where
+								blocks should be
+								reserved */
+				      int blocks /* How much to reserve */
+					  )
+{
+
+    /* Fast case, if reservation is zero - exit immediately. */
+    if ( !blocks )
+	return;
+
+    sb->u.reiserfs_sb.reserved_blocks += blocks;
+}
+
+/* Unreserve @blocks amount of blocks in fs pointed by @sb */
+void reiserfs_release_claimed_blocks( 
+				struct super_block *sb, /* super block of
+							  filesystem where
+							  blocks should be
+							  reserved */
+				int blocks /* How much to unreserve */
+					  )
+{
+
+    /* Fast case, if unreservation is zero - exit immediately. */
+    if ( !blocks )
+	return;
+
+    sb->u.reiserfs_sb.reserved_blocks -= blocks;
+    RFALSE( sb->u.reiserfs_sb.reserved_blocks < 0, "amount of blocks reserved became zero?");
 }
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/buffer2.c linux-2.4.20/fs/reiserfs/buffer2.c
--- linux-2.4.19/fs/reiserfs/buffer2.c	2001-12-21 17:42:03.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/buffer2.c	2002-10-29 11:18:39.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README  
+ *  Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README  
  */
 
 #include <linux/config.h>
@@ -33,8 +33,7 @@
 			buffer_journal_dirty(bh) ? ' ' : '!');
     }
     run_task_queue(&tq_disk);
-    current->policy |= SCHED_YIELD;
-    schedule();
+    yield();
   }
   if (repeat_counter > 30000000) {
     reiserfs_warning("vs-3051: done waiting, ignore vs-3050 messages for (%b)\n", bh) ;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/dir.c linux-2.4.20/fs/reiserfs/dir.c
--- linux-2.4.19/fs/reiserfs/dir.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/dir.c	2002-10-29 11:18:31.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/config.h>
@@ -106,7 +106,7 @@
 		if (!d_name[d_reclen - 1])
 		    d_reclen = strlen (d_name);
 	
-		if (d_reclen > REISERFS_MAX_NAME_LEN(inode->i_sb->s_blocksize)){
+		if (d_reclen > REISERFS_MAX_NAME(inode->i_sb->s_blocksize)){
 		    /* too big to send back to VFS */
 		    continue ;
 		}
@@ -177,7 +177,7 @@
 
 
  end:
-    // FIXME: ext2_readdir does not reset f_pos
+
     filp->f_pos = next_pos;
     pathrelse (&path_to_entry);
     reiserfs_check_path(&path_to_entry) ;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/do_balan.c linux-2.4.20/fs/reiserfs/do_balan.c
--- linux-2.4.19/fs/reiserfs/do_balan.c	2001-12-21 17:42:03.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/do_balan.c	2002-10-29 11:18:33.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 /* Now we have all buffers that must be used in balancing of the tree 	*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/file.c linux-2.4.20/fs/reiserfs/file.c
--- linux-2.4.19/fs/reiserfs/file.c	2002-02-25 19:38:09.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/file.c	2002-10-29 11:18:31.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/fix_node.c linux-2.4.20/fs/reiserfs/fix_node.c
--- linux-2.4.19/fs/reiserfs/fix_node.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/fix_node.c	2002-10-29 11:18:35.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 /**
@@ -795,8 +795,8 @@
   else /* If we have enough already then there is nothing to do. */
     return CARRY_ON;
 
-  if ( reiserfs_new_blocknrs (p_s_tb->transaction_handle, a_n_blocknrs,
-			      PATH_PLAST_BUFFER(p_s_tb->tb_path)->b_blocknr, n_amount_needed) == NO_DISK_SPACE )
+  if ( reiserfs_new_form_blocknrs (p_s_tb, a_n_blocknrs,
+                                   n_amount_needed) == NO_DISK_SPACE )
     return NO_DISK_SPACE;
 
   /* for each blocknumber we just got, get a buffer and stick it on FEB */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/hashes.c linux-2.4.20/fs/reiserfs/hashes.c
--- linux-2.4.19/fs/reiserfs/hashes.c	2001-10-12 21:19:28.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/hashes.c	2002-10-29 11:18:34.000000000 +0000
@@ -18,7 +18,9 @@
 // r5_hash
 //
 
+#include <linux/kernel.h>	/* for printk() as called by BUG() */
 #include <asm/types.h>
+#include <asm/page.h>
 
 
 
@@ -57,7 +59,6 @@
 	u32 pad;
 	int i;
  
-
 	//	assert(len >= 0 && len < 256);
 
 	pad = (u32)len | ((u32)len << 8);
@@ -92,7 +93,7 @@
 	{
 	    	//assert(len < 16);
 		if (len >= 16)
-		    *(int *)0 = 0;
+		    BUG();
 
 		a = (u32)msg[ 0]      |
 		    (u32)msg[ 1] << 8 |
@@ -118,7 +119,7 @@
 	{
 	    	//assert(len < 12);
 		if (len >= 12)
-		    *(int *)0 = 0;
+		    BUG();
 		a = (u32)msg[ 0]      |
 		    (u32)msg[ 1] << 8 |
 		    (u32)msg[ 2] << 16|
@@ -139,7 +140,7 @@
 	{
 	    	//assert(len < 8);
 		if (len >= 8)
-		    *(int *)0 = 0;
+		    BUG();
 		a = (u32)msg[ 0]      |
 		    (u32)msg[ 1] << 8 |
 		    (u32)msg[ 2] << 16|
@@ -156,7 +157,7 @@
 	{
 	    	//assert(len < 4);
 		if (len >= 4)
-		    *(int *)0 = 0;
+		    BUG();
 		a = b = c = d = pad;
 		for(i = 0; i < len; i++)
 		{
@@ -171,7 +172,7 @@
 	return h0^h1;
 }
 
-/* What follows in this file is copyright 2000 by Hans Reiser, and the
+/* What follows in this file is copyright 2000-2002 by Hans Reiser, and the
  * licensing of what follows is governed by reiserfs/README */
 
 u32 yura_hash (const signed char *msg, int len)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/ibalance.c linux-2.4.20/fs/reiserfs/ibalance.c
--- linux-2.4.19/fs/reiserfs/ibalance.c	2001-11-09 22:18:25.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/ibalance.c	2002-10-29 11:18:48.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/config.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/inode.c linux-2.4.20/fs/reiserfs/inode.c
--- linux-2.4.19/fs/reiserfs/inode.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/inode.c	2002-10-29 11:18:36.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/config.h>
@@ -19,10 +19,7 @@
 
 static int reiserfs_get_block (struct inode * inode, long block,
 			       struct buffer_head * bh_result, int create);
-//
-// initially this function was derived from minix or ext2's analog and
-// evolved as the prototype did
-//
+
 void reiserfs_delete_inode (struct inode * inode)
 {
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2; 
@@ -111,8 +108,7 @@
 }
 
 //
-// FIXME: we might cache recently accessed indirect item (or at least
-// first 15 pointers just like ext2 does
+// FIXME: we might cache recently accessed indirect item
 
 // Ugh.  Not too eager for that....
 //  I cut the code until such time as I see a convincing argument (benchmark).
@@ -159,33 +155,6 @@
     }
 }
 
-
-
-
-/* we need to allocate a block for new unformatted node.  Try to figure out
-   what point in bitmap reiserfs_new_blocknrs should start from. */
-static b_blocknr_t find_tag (struct buffer_head * bh, struct item_head * ih,
-			     __u32 * item, int pos_in_item)
-{
-  __u32 block ;
-  if (!is_indirect_le_ih (ih))
-	 /* something more complicated could be here */
-	 return bh->b_blocknr;
-
-  /* for indirect item: go to left and look for the first non-hole entry in
-	  the indirect item */
-  if (pos_in_item == I_UNFM_NUM (ih))
-	 pos_in_item --;
-  while (pos_in_item >= 0) {
-	 block = get_block_num(item, pos_in_item) ;
-	 if (block)
-		return block ;
-	 pos_in_item --;
-  }
-  return bh->b_blocknr;
-}
-
-
 /* reiserfs_get_block does not need to allocate a block only if it has been
    done already or non-hole position has been found in the indirect item */
 static inline int allocation_needed (int retval, b_blocknr_t allocated, 
@@ -348,10 +317,10 @@
     ** kmap schedules
     */
     if (!p) {
-    p = (char *)kmap(bh_result->b_page) ;
-    if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) {
-        goto research;
-    }
+	p = (char *)kmap(bh_result->b_page) ;
+	if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) {
+	    goto research;
+	}
     }
     p += offset ;
     memset (p, 0, inode->i_sb->s_blocksize);
@@ -531,29 +500,24 @@
 }
 
 static inline int _allocate_block(struct reiserfs_transaction_handle *th,
+			   long block,
                            struct inode *inode, 
 			   b_blocknr_t *allocated_block_nr, 
-			   unsigned long tag,
+			   struct path * path,
 			   int flags) {
   
 #ifdef REISERFS_PREALLOCATE
     if (!(flags & GET_BLOCK_NO_ISEM)) {
-        return reiserfs_new_unf_blocknrs2(th, inode, allocated_block_nr, tag);
+        return reiserfs_new_unf_blocknrs2(th, inode, allocated_block_nr, path, block);
     }
 #endif
-    return reiserfs_new_unf_blocknrs (th, allocated_block_nr, tag);
+    return reiserfs_new_unf_blocknrs (th, inode, allocated_block_nr, path, block);
 }
-//
-// initially this function was derived from ext2's analog and evolved
-// as the prototype did.  You'll need to look at the ext2 version to
-// determine which parts are derivative, if any, understanding that
-// there are only so many ways to code to a given interface.
-//
+
 static int reiserfs_get_block (struct inode * inode, long block,
 			       struct buffer_head * bh_result, int create)
 {
     int repeat, retval;
-    unsigned long tag;
     b_blocknr_t allocated_block_nr = 0;// b_blocknr_t is unsigned long
     INITIALIZE_PATH(path);
     int pos_in_item;
@@ -632,7 +596,6 @@
 
     if (allocation_needed (retval, allocated_block_nr, ih, item, pos_in_item)) {
 	/* we have to allocate block for the unformatted node */
-	tag = find_tag (bh, ih, item, pos_in_item);
 	if (!transaction_started) {
 	    pathrelse(&path) ;
 	    journal_begin(&th, inode->i_sb, jbegin_count) ;
@@ -641,7 +604,7 @@
 	    goto research ;
 	}
 
-	repeat = _allocate_block(&th, inode, &allocated_block_nr, tag, create);
+	repeat = _allocate_block(&th, block, inode, &allocated_block_nr, &path, create);
 
 	if (repeat == NO_DISK_SPACE) {
 	    /* restart the transaction to give the journal a chance to free
@@ -649,7 +612,7 @@
 	    ** research if we succeed on the second try
 	    */
 	    restart_transaction(&th, inode, &path) ; 
-	    repeat = _allocate_block(&th, inode,&allocated_block_nr,tag,create);
+	    repeat = _allocate_block(&th, block, inode, &allocated_block_nr, NULL, create);
 
 	    if (repeat != NO_DISK_SPACE) {
 		goto research ;
@@ -800,10 +763,10 @@
 	    add_to_flushlist(inode, unbh) ;
 
 	    /* mark it dirty now to prevent commit_write from adding
-	    ** this buffer to the inode's dirty buffer list
-	    */
+	     ** this buffer to the inode's dirty buffer list
+	     */
 	    __mark_buffer_dirty(unbh) ;
-		  
+
 	    //inode->i_blocks += inode->i_sb->s_blocksize / 512;
 	    //mark_tail_converted (inode);
 	} else {
@@ -1137,15 +1100,17 @@
     return;
 }
 
-void reiserfs_read_inode(struct inode *inode) {
-    make_bad_inode(inode) ;
+/* We need to clear inode key in private part of inode to avoid races between
+   blocking iput, knfsd and file deletion with creating of safelinks.*/
+static void reiserfs_make_bad_inode(struct inode *inode) {
+    memset(INODE_PKEY(inode), 0, KEY_SIZE);
+    make_bad_inode(inode);
 }
 
+void reiserfs_read_inode(struct inode *inode) {
+    reiserfs_make_bad_inode(inode) ;
+}
 
-//
-// initially this function was derived from minix or ext2's analog and
-// evolved as the prototype did
-//
 
 /* looks for stat data in the tree, and fills up the fields of in-core
    inode stat data fields */
@@ -1158,7 +1123,7 @@
     int retval;
 
     if (!p) {
-	make_bad_inode(inode) ;
+	reiserfs_make_bad_inode(inode) ;
 	return;
     }
 
@@ -1178,13 +1143,13 @@
 	reiserfs_warning ("vs-13070: reiserfs_read_inode2: "
                     "i/o failure occurred trying to find stat data of %K\n",
                     &key);
-	make_bad_inode(inode) ;
+	reiserfs_make_bad_inode(inode) ;
 	return;
     }
     if (retval != ITEM_FOUND) {
 	/* a stale NFS handle can trigger this without it being an error */
 	pathrelse (&path_to_sd);
-	make_bad_inode(inode) ;
+	reiserfs_make_bad_inode(inode) ;
 	inode->i_nlink = 0;
 	return;
     }
@@ -1211,7 +1176,7 @@
 			      "dead inode read from disk %K. "
 			      "This is likely to be race with knfsd. Ignore\n", 
 			      &key );
-	    make_bad_inode( inode );
+	    reiserfs_make_bad_inode( inode );
     }
 
     reiserfs_check_path(&path_to_sd) ; /* init inode should be relsing */
@@ -1368,10 +1333,6 @@
 }
 
 
-//
-// initially this function was derived from minix or ext2's analog and
-// evolved as the prototype did
-//
 /* looks for stat data, then copies fields to it, marks the buffer
    containing stat data as dirty */
 /* reiserfs inodes are never really dirty, since the dirty inode call
@@ -1504,7 +1465,7 @@
    directory) or reiserfs_new_symlink (to insert symlink body if new
    object is symlink) or nothing (if new object is regular file) */
 struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th,
-				   const struct inode * dir, int mode, 
+				   struct inode * dir, int mode, 
 				   const char * symname, 
 				   int i_size, /* 0 for regular, EMTRY_DIR_SIZE for dirs,
 						  strlen (symname) for symlinks)*/
@@ -1628,6 +1589,10 @@
 	set_inode_sd_version (inode, STAT_DATA_V2);
     
     /* insert the stat data into the tree */
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+    if (dir->u.reiserfs_i.new_packing_locality)
+	th->displace_new_blocks = 1;
+#endif
     retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, (char *)(&sd));
     if (retval) {
 	iput (inode);
@@ -1636,6 +1601,10 @@
 	return NULL;
     }
 
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+    if (!th->displace_new_blocks)
+	dir->u.reiserfs_i.new_packing_locality = 0;
+#endif
     if (S_ISDIR(mode)) {
 	/* insert item with "." and ".." */
 	retval = reiserfs_new_directory (th, &ih, &path_to_key, dir);
@@ -1793,16 +1762,16 @@
     reiserfs_update_inode_transaction(p_s_inode) ;
     windex = push_journal_writer("reiserfs_vfs_truncate_file") ;
     if (update_timestamps)
-           /* we are doing real truncate: if the system crashes before the last
-              transaction of truncating gets committed - on reboot the file
-              either appears truncated properly or not truncated at all */
-           add_save_link (&th, p_s_inode, 1);
+	    /* we are doing real truncate: if the system crashes before the last
+	       transaction of truncating gets committed - on reboot the file
+	       either appears truncated properly or not truncated at all */
+	add_save_link (&th, p_s_inode, 1);
     reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ;
     pop_journal_writer(windex) ;
     journal_end(&th, p_s_inode->i_sb,  JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ;
 
     if (update_timestamps)
-       remove_save_link (p_s_inode, 1/* truncate */);
+	remove_save_link (p_s_inode, 1/* truncate */);
 
     if (page) {
         length = offset & (blocksize - 1) ;
@@ -2042,18 +2011,13 @@
     return error ;
 }
 
-//
-// this is exactly what 2.3.99-pre9's ext2_readpage is
-//
+
 static int reiserfs_readpage (struct file *f, struct page * page)
 {
     return block_read_full_page (page, reiserfs_get_block);
 }
 
 
-//
-// modified from ext2_writepage is
-//
 static int reiserfs_writepage (struct page * page)
 {
     struct inode *inode = page->mapping->host ;
@@ -2062,9 +2026,6 @@
 }
 
 
-//
-// from ext2_prepare_write, but modified
-//
 int reiserfs_prepare_write(struct file *f, struct page *page, 
 			   unsigned from, unsigned to) {
     struct inode *inode = page->mapping->host ;
@@ -2074,9 +2035,6 @@
 }
 
 
-//
-// this is exactly what 2.3.99-pre9's ext2_bmap is
-//
 static int reiserfs_aop_bmap(struct address_space *as, long block) {
   return generic_block_bmap(as, block, reiserfs_bmap) ;
 }
@@ -2095,13 +2053,13 @@
     */
     if (pos > inode->i_size) {
 	struct reiserfs_transaction_handle th ;
-	lock_kernel() ;
+	lock_kernel();
 	journal_begin(&th, inode->i_sb, 1) ;
 	reiserfs_update_inode_transaction(inode) ;
 	inode->i_size = pos ;
 	reiserfs_update_sd(&th, inode) ;
 	journal_end(&th, inode->i_sb, 1) ;
-	unlock_kernel() ;
+	unlock_kernel();
     }
  
     ret = generic_commit_write(f, page, from, to) ;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/ioctl.c linux-2.4.20/fs/reiserfs/ioctl.c
--- linux-2.4.19/fs/reiserfs/ioctl.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/ioctl.c	2002-10-29 11:18:39.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/fs.h>
@@ -31,8 +31,12 @@
 				return 0;
 		} else
 			return -ENOTTY;
-	/* following two cases are taken from fs/ext2/ioctl.c by Remy
-	   Card (card@masi.ibp.fr) */
+	/*
+	 * Following {G,S}ETFLAGS, and {G,S}ETVERSION are providing ext2
+	 * binary compatible interface (used by lsattr(1), and chattr(1)) and
+	 * are * thus conceptually similar to appropriate pieces of
+	 * fs/ext2/ioctl.c
+	 */
 	case REISERFS_IOC_GETFLAGS:
 		flags = inode -> u.reiserfs_i.i_attrs;
 		i_attrs_to_sd_attrs( inode, ( __u16 * ) &flags );
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/item_ops.c linux-2.4.20/fs/reiserfs/item_ops.c
--- linux-2.4.19/fs/reiserfs/item_ops.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/item_ops.c	2002-10-29 11:18:33.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/sched.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/journal.c linux-2.4.20/fs/reiserfs/journal.c
--- linux-2.4.19/fs/reiserfs/journal.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/journal.c	2002-10-29 11:18:32.000000000 +0000
@@ -151,8 +151,7 @@
   }
   bn = allocate_bitmap_node(p_s_sb) ;
   if (!bn) {
-    current->policy |= SCHED_YIELD ;
-    schedule() ;
+    yield();
     goto repeat ;
   }
   return bn ;
@@ -191,7 +190,7 @@
   if (!jb->bitmaps[bmap_nr]) {
     jb->bitmaps[bmap_nr] = get_bitmap_node(p_s_sb) ;
   }
-  set_bit(bit_nr, jb->bitmaps[bmap_nr]->data) ;
+  set_bit(bit_nr, (unsigned long *)jb->bitmaps[bmap_nr]->data) ;
   return 0 ;
 }
 
@@ -375,7 +374,7 @@
 /* buffer is in current transaction */
 inline int buffer_journaled(const struct buffer_head *bh) {
   if (bh)
-    return test_bit(BH_JDirty, ( struct buffer_head * ) &bh->b_state) ;
+    return test_bit(BH_JDirty, &((struct buffer_head *)bh)->b_state) ;
   else
     return 0 ;
 }
@@ -385,7 +384,7 @@
 */ 
 inline int buffer_journal_new(const struct buffer_head *bh) {
   if (bh) 
-    return test_bit(BH_JNew, ( struct buffer_head * )&bh->b_state) ;
+    return test_bit(BH_JNew, &((struct buffer_head *)bh)->b_state) ;
   else
     return 0 ;
 }
@@ -508,14 +507,12 @@
 **
 */
 int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev, 
-                        unsigned long bl, int size, int search_all, 
-			unsigned long *next_zero_bit) {
+                        int bmap_nr, int bit_nr, int size, int search_all, 
+			unsigned int *next_zero_bit) {
   struct reiserfs_journal_cnode *cn ;
   struct reiserfs_list_bitmap *jb ;
   int i ;
-  int bmap_nr = bl / (p_s_sb->s_blocksize << 3) ;
-  int bit_nr = bl % (p_s_sb->s_blocksize << 3) ;
-  int tmp_bit ;
+  unsigned long bl;
 
   *next_zero_bit = 0 ; /* always start this at zero. */
 
@@ -534,16 +531,16 @@
       PROC_INFO_INC( p_s_sb, journal.in_journal_bitmap );
       jb = SB_JOURNAL(p_s_sb)->j_list_bitmap + i ;
       if (jb->journal_list && jb->bitmaps[bmap_nr] &&
-          test_bit(bit_nr, jb->bitmaps[bmap_nr]->data)) {
-	tmp_bit = find_next_zero_bit((unsigned long *)
+          test_bit(bit_nr, (unsigned long *)jb->bitmaps[bmap_nr]->data)) {
+	*next_zero_bit = find_next_zero_bit((unsigned long *)
 	                             (jb->bitmaps[bmap_nr]->data),
 	                             p_s_sb->s_blocksize << 3, bit_nr+1) ; 
-	*next_zero_bit = bmap_nr * (p_s_sb->s_blocksize << 3) + tmp_bit ;
 	return 1 ;
       }
     }
   }
 
+  bl = bmap_nr * (p_s_sb->s_blocksize << 3) + bit_nr;
   /* is it in any old transactions? */
   if (search_all && (cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_list_hash_table, dev,bl,size))) {
     return 1; 
@@ -1811,7 +1808,8 @@
   jl = SB_JOURNAL_LIST(ct->p_s_sb) + ct->jindex ;
 
   flush_commit_list(ct->p_s_sb, SB_JOURNAL_LIST(ct->p_s_sb) + ct->jindex, 1) ; 
-  if (jl->j_len > 0 && atomic_read(&(jl->j_nonzerolen)) > 0 && 
+
+  if (jl->j_len > 0 && atomic_read(&(jl->j_nonzerolen)) > 0 &&
       atomic_read(&(jl->j_commit_left)) == 0) {
     kupdate_one_transaction(ct->p_s_sb, jl) ;
   }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/lbalance.c linux-2.4.20/fs/reiserfs/lbalance.c
--- linux-2.4.19/fs/reiserfs/lbalance.c	2001-12-21 17:42:03.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/lbalance.c	2002-10-29 11:18:51.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/config.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/namei.c linux-2.4.20/fs/reiserfs/namei.c
--- linux-2.4.19/fs/reiserfs/namei.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/namei.c	2002-10-29 11:18:48.000000000 +0000
@@ -1,14 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
- *
- * Trivial changes by Alan Cox to remove EHASHCOLLISION for compatibility
- *
- * Trivial Changes:
- * Rights granted to Hans Reiser to redistribute under other terms providing
- * he accepts all liability including but not limited to patent, fitness
- * for purpose, and direct or indirect claims arising from failure to perform.
- *
- * NO WARRANTY
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/config.h>
@@ -195,13 +186,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static int reiserfs_match (struct reiserfs_dir_entry * de, 
 			   const char * name, int namelen)
 {
@@ -248,7 +232,7 @@
    
 	/* mark, that this generation number is used */
 	if (de->de_gen_number_bit_string)
-	    set_bit (GET_GENERATION_NUMBER (deh_offset (deh)), de->de_gen_number_bit_string);
+	    set_bit (GET_GENERATION_NUMBER (deh_offset (deh)), (unsigned long *)de->de_gen_number_bit_string);
 
 	// calculate pointer to name and namelen
 	de->de_entry_num = i;
@@ -284,13 +268,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 // may return NAME_FOUND, NAME_FOUND_INVISIBLE, NAME_NOT_FOUND
 // FIXME: should add something like IOERROR
 static int reiserfs_find_entry (struct inode * dir, const char * name, int namelen, 
@@ -300,7 +277,7 @@
     int retval;
 
 
-    if (namelen > REISERFS_MAX_NAME_LEN (dir->i_sb->s_blocksize))
+    if (namelen > REISERFS_MAX_NAME (dir->i_sb->s_blocksize))
 	return NAME_NOT_FOUND;
 
     /* we will search for this key in the tree */
@@ -310,7 +287,7 @@
     while (1) {
 	retval = search_by_entry_key (dir->i_sb, &key_to_search, path_to_entry, de);
 	if (retval == IO_ERROR) {
-	    reiserfs_warning ("zam-7001: io error in " __FUNCTION__ "\n");
+	    reiserfs_warning ("zam-7001: io error in %s\n", __FUNCTION__);
 	    return IO_ERROR;
 	}
 
@@ -330,13 +307,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static struct dentry * reiserfs_lookup (struct inode * dir, struct dentry * dentry)
 {
     int retval;
@@ -346,7 +316,7 @@
 
     reiserfs_check_lock_depth("lookup") ;
 
-    if (dentry->d_name.len > REISERFS_MAX_NAME_LEN (dir->i_sb->s_blocksize))
+    if (REISERFS_MAX_NAME (dir->i_sb->s_blocksize) < dentry->d_name.len)
 	return ERR_PTR(-ENAMETOOLONG);
 
     de.de_gen_number_bit_string = 0;
@@ -366,14 +336,6 @@
     return NULL;
 }
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
-
 /* add entry to the directory (entry can be hidden). 
 
 insert definition of when hidden directories are used here -Hans
@@ -401,7 +363,7 @@
     if (!namelen)
 	return -EINVAL;
 
-    if (namelen > REISERFS_MAX_NAME_LEN (dir->i_sb->s_blocksize))
+    if (namelen > REISERFS_MAX_NAME (dir->i_sb->s_blocksize))
 	return -ENAMETOOLONG;
 
     /* each entry has unique key. compose it */
@@ -417,7 +379,7 @@
     } else
 	buffer = small_buf;
 
-    paste_size = (old_format_only (dir->i_sb)) ? (DEH_SIZE + namelen) : buflen;
+    paste_size = (get_inode_sd_version (dir) == STAT_DATA_V1) ? (DEH_SIZE + namelen) : buflen;
 
     /* fill buffer : directory entry head, name[, dir objectid | , stat data | ,stat data, dir objectid ] */
     deh = (struct reiserfs_de_head *)buffer;
@@ -451,21 +413,36 @@
 	}
 
         if (retval != NAME_FOUND) {
-	    reiserfs_warning ("zam-7002:" __FUNCTION__ ": \"reiserfs_find_entry\" has returned"
-                              " unexpected value (%d)\n", retval);
+	    reiserfs_warning ("zam-7002:%s: \"reiserfs_find_entry\" has returned"
+                              " unexpected value (%d)\n", __FUNCTION__, retval);
        }
 
 	return -EEXIST;
     }
 
-    gen_number = find_first_zero_bit (bit_string, MAX_GENERATION_NUMBER + 1);
+    gen_number = find_first_zero_bit ((unsigned long *)bit_string, MAX_GENERATION_NUMBER + 1);
     if (gen_number > MAX_GENERATION_NUMBER) {
       /* there is no free generation number */
       reiserfs_warning ("reiserfs_add_entry: Congratulations! we have got hash function screwed up\n");
       if (buffer != small_buf)
           reiserfs_kfree (buffer, buflen, dir->i_sb);
       pathrelse (&path);
+/*
+ * Trivial changes by Alan Cox to remove EHASHCOLLISION for compatibility
+ *
+ * Trivial Changes:
+ * Rights granted to Hans Reiser to redistribute under other terms providing
+ * he accepts all liability including but not limited to patent, fitness
+ * for purpose, and direct or indirect claims arising from failure to perform.
+ *
+ * NO WARRANTY
+ * This is one of two lines that this fix consist of.
+ */
       return -EBUSY;
+      /* I think it was better to have an error code with a name that says
+	 what it means, but I choose not to fight over it.  Persons porting to
+	 other operating systems should consider keeping it as it was
+	 (return -EHASHCOLLISION;). -Hans */
     }
     /* adjust offset of directory enrty */
     put_deh_offset(deh, SET_GENERATION_NUMBER(deh_offset(deh), gen_number));
@@ -482,7 +459,12 @@
 	    if (buffer != small_buf)
 		reiserfs_kfree (buffer, buflen, dir->i_sb);
 	    pathrelse (&path);
+	    /* Following line is 2nd line touched by Alan Cox' trivial fix */
 	    return -EBUSY;
+      /* I think it was better to have an error code with a name that says
+	 what it means, but I choose not to fight over it.  Persons porting to
+	 other operating systems should consider keeping it as it was
+	 (return -EHASHCOLLISION;). -Hans */
 	}
     }
   
@@ -507,13 +489,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode)
 {
     int retval;
@@ -523,8 +498,7 @@
     struct reiserfs_transaction_handle th ;
 
 
-    inode = new_inode(dir->i_sb) ;
-    if (!inode) {
+    if (!(inode = new_inode(dir->i_sb))) {
 	return -ENOMEM ;
     }
     journal_begin(&th, dir->i_sb, jbegin_count) ;
@@ -563,13 +537,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static int reiserfs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
 {
     int retval;
@@ -578,8 +545,7 @@
     struct reiserfs_transaction_handle th ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
 
-    inode = new_inode(dir->i_sb) ;
-    if (!inode) {
+    if (!(inode = new_inode(dir->i_sb))) {
 	return -ENOMEM ;
     }
     journal_begin(&th, dir->i_sb, jbegin_count) ;
@@ -618,13 +584,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode)
 {
     int retval;
@@ -633,8 +592,7 @@
     struct reiserfs_transaction_handle th ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
 
-    inode = new_inode(dir->i_sb) ;
-    if (!inode) {
+    if (!(inode = new_inode(dir->i_sb))) {
 	return -ENOMEM ;
     }
     journal_begin(&th, dir->i_sb, jbegin_count) ;
@@ -645,6 +603,10 @@
     */
     INC_DIR_INODE_NLINK(dir)
 
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+    /* set flag that new packing locality created and new blocks for the content     * of that directory are not displaced yet */
+    dir->u.reiserfs_i.new_packing_locality = 1;
+#endif
     mode = S_IFDIR | mode;
     inode = reiserfs_new_inode (&th, dir, mode, 0/*symlink*/,
 				old_format_only (dir->i_sb) ? EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
@@ -697,13 +659,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static int reiserfs_rmdir (struct inode * dir, struct dentry *dentry)
 {
     int retval;
@@ -784,13 +739,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static int reiserfs_unlink (struct inode * dir, struct dentry *dentry)
 {
     int retval;
@@ -866,14 +814,7 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
-static int reiserfs_symlink (struct inode * dir, struct dentry * dentry, const char * symname)
+static int reiserfs_symlink (struct inode * parent_dir, struct dentry * dentry, const char * symname)
 {
     int retval;
     struct inode * inode;
@@ -884,18 +825,17 @@
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
 
 
-    inode = new_inode(dir->i_sb) ;
-    if (!inode) {
-	return -ENOMEM ;
+    if (!(inode = new_inode(parent_dir->i_sb))) {
+  	return -ENOMEM ;
     }
 
     item_len = ROUND_UP (strlen (symname));
-    if (item_len > MAX_DIRECT_ITEM_LEN (dir->i_sb->s_blocksize)) {
+    if (item_len > MAX_DIRECT_ITEM_LEN (parent_dir->i_sb->s_blocksize)) {
 	iput(inode) ;
 	return -ENAMETOOLONG;
     }
   
-    name = reiserfs_kmalloc (item_len, GFP_NOFS, dir->i_sb);
+    name = reiserfs_kmalloc (item_len, GFP_NOFS, parent_dir->i_sb);
     if (!name) {
 	iput(inode) ;
 	return -ENOMEM;
@@ -903,20 +843,20 @@
     memcpy (name, symname, strlen (symname));
     padd_item (name, item_len, strlen (symname));
 
-    journal_begin(&th, dir->i_sb, jbegin_count) ;
+    journal_begin(&th, parent_dir->i_sb, jbegin_count) ;
     windex = push_journal_writer("reiserfs_symlink") ;
 
-    inode = reiserfs_new_inode (&th, dir, S_IFLNK | S_IRWXUGO, name, strlen (symname), dentry,
+    inode = reiserfs_new_inode (&th, parent_dir, S_IFLNK | S_IRWXUGO, name, strlen (symname), dentry,
 				inode, &retval);
-    reiserfs_kfree (name, item_len, dir->i_sb);
+    reiserfs_kfree (name, item_len, parent_dir->i_sb);
     if (inode == 0) { /* reiserfs_new_inode iputs for us */
 	pop_journal_writer(windex) ;
-	journal_end(&th, dir->i_sb, jbegin_count) ;
+	journal_end(&th, parent_dir->i_sb, jbegin_count) ;
 	return retval;
     }
 
     reiserfs_update_inode_transaction(inode) ;
-    reiserfs_update_inode_transaction(dir) ;
+    reiserfs_update_inode_transaction(parent_dir) ;
 
     inode->i_op = &page_symlink_inode_operations;
     inode->i_mapping->a_ops = &reiserfs_address_space_operations;
@@ -925,31 +865,24 @@
     //
     //reiserfs_update_sd (&th, inode, READ_BLOCKS);
 
-    retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, 
+    retval = reiserfs_add_entry (&th, parent_dir, dentry->d_name.name, dentry->d_name.len, 
 				 inode, 1/*visible*/);
     if (retval) {
 	inode->i_nlink--;
 	reiserfs_update_sd (&th, inode);
 	pop_journal_writer(windex) ;
-	journal_end(&th, dir->i_sb, jbegin_count) ;
+	journal_end(&th, parent_dir->i_sb, jbegin_count) ;
 	iput (inode);
 	return retval;
     }
 
     d_instantiate(dentry, inode);
     pop_journal_writer(windex) ;
-    journal_end(&th, dir->i_sb, jbegin_count) ;
+    journal_end(&th, parent_dir->i_sb, jbegin_count) ;
     return 0;
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static int reiserfs_link (struct dentry * old_dentry, struct inode * dir, struct dentry * dentry)
 {
     int retval;
@@ -957,6 +890,7 @@
     int windex ;
     struct reiserfs_transaction_handle th ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
+    time_t ctime;
 
 
     if (S_ISDIR(inode->i_mode))
@@ -984,7 +918,8 @@
     }
 
     inode->i_nlink++;
-    inode->i_ctime = CURRENT_TIME;
+    ctime = CURRENT_TIME;
+    inode->i_ctime = ctime;
     reiserfs_update_sd (&th, inode);
 
     atomic_inc(&inode->i_count) ;
@@ -1037,14 +972,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
-
 /* 
  * process, that is going to call fix_nodes/do_balance must hold only
  * one path. If it holds 2 or more, it can get into endless waiting in
@@ -1059,10 +986,12 @@
     INITIALIZE_PATH (dot_dot_entry_path);
     struct item_head new_entry_ih, old_entry_ih, dot_dot_ih ;
     struct reiserfs_dir_entry old_de, new_de, dot_dot_de;
-    struct inode * old_inode, * new_inode;
+    struct inode * old_inode, * new_dentry_inode;
     int windex ;
     struct reiserfs_transaction_handle th ;
     int jbegin_count ; 
+    umode_t old_inode_mode;
+    time_t ctime;
 
 
     /* two balancings: old name removal, new name insertion or "save" link,
@@ -1071,7 +1000,7 @@
     jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 3;
 
     old_inode = old_dentry->d_inode;
-    new_inode = new_dentry->d_inode;
+    new_dentry_inode = new_dentry->d_inode;
 
     // make sure, that oldname still exists and points to an object we
     // are going to rename
@@ -1086,13 +1015,14 @@
 	return -ENOENT;
     }
 
-    if (S_ISDIR(old_inode->i_mode)) {
+    old_inode_mode = old_inode->i_mode;
+    if (S_ISDIR(old_inode_mode)) {
 	// make sure, that directory being renamed has correct ".." 
 	// and that its new parent directory has not too many links
 	// already
 
-	if (new_inode) {
-	    if (!reiserfs_empty_dir(new_inode)) {
+	if (new_dentry_inode) {
+	    if (!reiserfs_empty_dir(new_dentry_inode)) {
 		return -ENOTEMPTY;
 	    }
 	}
@@ -1118,9 +1048,7 @@
     retval = reiserfs_add_entry (&th, new_dir, new_dentry->d_name.name, new_dentry->d_name.len, 
 				 old_inode, 0);
     if (retval == -EEXIST) {
-	// FIXME: is it possible, that new_inode == 0 here? If yes, it
-	// is not clear how does ext2 handle that
-	if (!new_inode) {
+	if (!new_dentry_inode) {
 	    reiserfs_panic (old_dir->i_sb,
 			    "vs-7050: new entry is found, new inode == 0\n");
 	}
@@ -1138,8 +1066,8 @@
     */
     reiserfs_update_inode_transaction(old_inode) ;
 
-    if (new_inode) 
-	reiserfs_update_inode_transaction(new_inode) ;
+    if (new_dentry_inode) 
+	reiserfs_update_inode_transaction(new_dentry_inode) ;
 
     while (1) {
 	// look for old name using corresponding entry key (found by reiserfs_find_entry)
@@ -1186,18 +1114,18 @@
 	if (item_moved(&new_entry_ih, &new_entry_path) ||
 	    !entry_points_to_object(new_dentry->d_name.name, 
 	                            new_dentry->d_name.len,
-				    &new_de, new_inode) ||
+				    &new_de, new_dentry_inode) ||
 	    item_moved(&old_entry_ih, &old_entry_path) || 
 	    !entry_points_to_object (old_dentry->d_name.name, 
 	                             old_dentry->d_name.len,
 				     &old_de, old_inode)) {
 	    reiserfs_restore_prepared_buffer (old_inode->i_sb, new_de.de_bh);
 	    reiserfs_restore_prepared_buffer (old_inode->i_sb, old_de.de_bh);
-	    if (S_ISDIR(old_inode->i_mode))
+	    if (S_ISDIR(old_inode_mode))
 		reiserfs_restore_prepared_buffer (old_inode->i_sb, dot_dot_de.de_bh);
 	    continue;
 	}
-	if (S_ISDIR(old_inode->i_mode)) {
+	if (S_ISDIR(old_inode_mode)) {
 	    if ( item_moved(&dot_dot_ih, &dot_dot_entry_path) ||
 		 !entry_points_to_object ( "..", 2, &dot_dot_de, old_dir) ) {
 		reiserfs_restore_prepared_buffer (old_inode->i_sb, old_de.de_bh);
@@ -1208,7 +1136,7 @@
 	}
 
 
-	RFALSE( S_ISDIR(old_inode->i_mode) && 
+	RFALSE( S_ISDIR(old_inode_mode) && 
 		!reiserfs_buffer_prepared(dot_dot_de.de_bh), "" );
 
 	break;
@@ -1226,22 +1154,23 @@
     old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
     new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
 
-    if (new_inode) {
+    if (new_dentry_inode) {
 	// adjust link number of the victim
-	if (S_ISDIR(new_inode->i_mode)) {
-	    new_inode->i_nlink  = 0;
+	if (S_ISDIR(new_dentry_inode->i_mode)) {
+	    new_dentry_inode->i_nlink  = 0;
 	} else {
-	    new_inode->i_nlink--;
+	    new_dentry_inode->i_nlink--;
 	}
-	new_inode->i_ctime = CURRENT_TIME;
+	ctime = CURRENT_TIME;
+	new_dentry_inode->i_ctime = ctime;
     }
 
-    if (S_ISDIR(old_inode->i_mode)) {
+    if (S_ISDIR(old_inode_mode)) {
 	// adjust ".." of renamed directory 
 	set_ino_in_dir_entry (&dot_dot_de, INODE_PKEY (new_dir));
 	journal_mark_dirty (&th, new_dir->i_sb, dot_dot_de.de_bh);
 	
-        if (!new_inode)
+        if (!new_dentry_inode)
 	    /* there (in new_dir) was no directory, so it got new link
 	       (".."  of renamed directory) */
 	    INC_DIR_INODE_NLINK(new_dir);
@@ -1266,10 +1195,10 @@
     reiserfs_update_sd (&th, old_dir);
     reiserfs_update_sd (&th, new_dir);
 
-    if (new_inode) {
-	if (new_inode->i_nlink == 0)
-	    add_save_link (&th, new_inode, 0/* not truncate */);
-	reiserfs_update_sd (&th, new_inode);
+    if (new_dentry_inode) {
+	if (new_dentry_inode->i_nlink == 0)
+	    add_save_link (&th, new_dentry_inode, 0/* not truncate */);
+	reiserfs_update_sd (&th, new_dentry_inode);
     }
 
     pop_journal_writer(windex) ;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/objectid.c linux-2.4.20/fs/reiserfs/objectid.c
--- linux-2.4.19/fs/reiserfs/objectid.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/objectid.c	2002-10-29 11:18:39.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/config.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/prints.c linux-2.4.20/fs/reiserfs/prints.c
--- linux-2.4.19/fs/reiserfs/prints.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/prints.c	2002-10-29 11:18:48.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/config.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/procfs.c linux-2.4.20/fs/reiserfs/procfs.c
--- linux-2.4.19/fs/reiserfs/procfs.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/procfs.c	2002-10-29 11:18:35.000000000 +0000
@@ -1,9 +1,7 @@
 /* -*- linux-c -*- */
-
 /* fs/reiserfs/procfs.c */
-
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 /* proc info support a la one created by Sizif@Botik.RU for PGC */
@@ -120,7 +118,7 @@
 #define SF( x ) ( r -> x )
 #define SFP( x ) SF( s_proc_info_data.x )
 #define SFPL( x ) SFP( x[ level ] )
-#define SFPF( x ) SFP( find_forward.x )
+#define SFPF( x ) SFP( scan_bitmap.x )
 #define SFPJ( x ) SFP( journal.x )
 
 #define D2C( x ) le16_to_cpu( x )
@@ -191,7 +189,7 @@
 			reiserfs_no_unhashed_relocation( sb ) ? "NO_UNHASHED_RELOCATION " : "",
 			reiserfs_hashed_relocation( sb ) ? "UNHASHED_RELOCATION " : "",
 			reiserfs_test4( sb ) ? "TEST4 " : "",
-			dont_have_tails( sb ) ? "NO_TAILS " : "TAILS ",
+			have_large_tails( sb ) ? "TAILS " : have_small_tails(sb)?"SMALL_TAILS ":"NO_TAILS ",
 			replay_only( sb ) ? "REPLAY_ONLY " : "",
 			reiserfs_dont_log( sb ) ? "DONT_LOG " : "LOG ",
 			convert_reiserfs( sb ) ? "CONV " : "",
@@ -321,27 +319,30 @@
 	r = &sb->u.reiserfs_sb;
 
 	len += sprintf( &buffer[ len ], "free_block: %lu\n"
-			"find_forward:"
-			"         wait"
-			"         bmap"
-			"        retry"
-			" journal_hint"
-			"  journal_out"
+			"  scan_bitmap:"
+			"          wait"
+			"          bmap"
+			"         retry"
+			"        stolen"
+			"  journal_hint"
+			"journal_nohint"
 			"\n"
-			" %12lu"
-			" %12lu"
-			" %12lu"
-			" %12lu"
-			" %12lu"
-			" %12lu"
+			" %14lu"
+			" %14lu"
+			" %14lu"
+			" %14lu"
+			" %14lu"
+			" %14lu"
+			" %14lu"
 			"\n",
 			SFP( free_block ),
 			SFPF( call ), 
 			SFPF( wait ), 
 			SFPF( bmap ),
 			SFPF( retry ),
+			SFPF( stolen ),
 			SFPF( in_journal_hint ),
-			SFPF( in_journal_out ) );
+			SFPF( in_journal_nohint ) );
 
 	procinfo_epilogue( sb );
 	return reiserfs_proc_tail( len, buffer, start, offset, count, eof );
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/resize.c linux-2.4.20/fs/reiserfs/resize.c
--- linux-2.4.19/fs/reiserfs/resize.c	2002-02-25 19:38:09.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/resize.c	2002-10-29 11:18:36.000000000 +0000
@@ -1,5 +1,5 @@
 /* 
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
  
 /* 
@@ -19,7 +19,8 @@
 int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
 {
 	struct reiserfs_super_block * sb;
-	struct buffer_head ** bitmap, * bh;
+        struct reiserfs_bitmap_info *bitmap;
+	struct buffer_head * bh;
 	struct reiserfs_transaction_handle th;
 	unsigned int bmap_nr_new, bmap_nr;
 	unsigned int block_r_new, block_r;
@@ -103,7 +104,7 @@
 	
 	    /* allocate additional bitmap blocks, reallocate array of bitmap
 	     * block pointers */
-	    bitmap = reiserfs_kmalloc(sizeof(struct buffer_head *) * bmap_nr_new, GFP_KERNEL, s);
+	    bitmap = vmalloc(sizeof(struct reiserfs_bitmap_info) * bmap_nr_new);
 	    if (!bitmap) {
 		printk("reiserfs_resize: unable to allocate memory.\n");
 		return -ENOMEM;
@@ -111,18 +112,20 @@
 	    for (i = 0; i < bmap_nr; i++)
 		bitmap[i] = SB_AP_BITMAP(s)[i];
 	    for (i = bmap_nr; i < bmap_nr_new; i++) {
-		bitmap[i] = getblk(s->s_dev, i * s->s_blocksize * 8, s->s_blocksize);
-		memset(bitmap[i]->b_data, 0, sb->s_blocksize);
-		reiserfs_test_and_set_le_bit(0, bitmap[i]->b_data);
-
-		mark_buffer_dirty(bitmap[i]) ;
-		mark_buffer_uptodate(bitmap[i], 1);
-		ll_rw_block(WRITE, 1, bitmap + i);
-		wait_on_buffer(bitmap[i]);
+		bitmap[i].bh = sb_getblk(s, i * s->s_blocksize * 8);
+		memset(bitmap[i].bh->b_data, 0, sb->s_blocksize);
+		reiserfs_test_and_set_le_bit(0, bitmap[i].bh->b_data);
+
+		mark_buffer_dirty(bitmap[i].bh) ;
+		mark_buffer_uptodate(bitmap[i].bh, 1);
+		ll_rw_block(WRITE, 1, &bitmap[i].bh);
+		wait_on_buffer(bitmap[i].bh);
+		bitmap[i].first_zero_hint=1;
+		bitmap[i].free_count = s->s_blocksize * 8 - 1;
 	    }	
 	    /* free old bitmap blocks array */
-	    reiserfs_kfree(SB_AP_BITMAP(s), 
-			   sizeof(struct buffer_head *) * bmap_nr, s);
+	    vfree(SB_AP_BITMAP(s)); 
+			   
 	    SB_AP_BITMAP(s) = bitmap;
 	}
 	
@@ -130,18 +133,25 @@
 	journal_begin(&th, s, 10);
 
 	/* correct last bitmap blocks in old and new disk layout */
-	reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr - 1], 1);
+	reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr - 1].bh, 1);
 	for (i = block_r; i < s->s_blocksize * 8; i++)
 	    reiserfs_test_and_clear_le_bit(i, 
-					   SB_AP_BITMAP(s)[bmap_nr - 1]->b_data);
-	journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr - 1]);
+					   SB_AP_BITMAP(s)[bmap_nr - 1].bh->b_data);
+	SB_AP_BITMAP(s)[bmap_nr - 1].free_count += s->s_blocksize * 8 - block_r;
+	if ( !SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint)
+	    SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint = block_r;
+	journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr - 1].bh);
 
-	reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr_new - 1], 1);
+	reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh, 1);
 	for (i = block_r_new; i < s->s_blocksize * 8; i++)
 	    reiserfs_test_and_set_le_bit(i,
-					 SB_AP_BITMAP(s)[bmap_nr_new - 1]->b_data);
-	journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr_new - 1]);
- 
+					 SB_AP_BITMAP(s)[bmap_nr_new - 1].bh->b_data);
+	journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh);
+
+	SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count -= s->s_blocksize * 8 - block_r_new;
+	/* Extreme case where last bitmap is the only valid block in itself. */
+	if ( !SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count )
+	    SB_AP_BITMAP(s)[bmap_nr_new - 1].first_zero_hint = 0;
  	/* update super */
 	reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
 	free_blocks = SB_FREE_BLOCKS(s);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/stree.c linux-2.4.20/fs/reiserfs/stree.c
--- linux-2.4.19/fs/reiserfs/stree.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/stree.c	2002-10-29 11:18:49.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ *  Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 /*
@@ -1621,9 +1621,9 @@
     
     do_balance(&s_cut_balance, NULL, NULL, c_mode);
     if ( n_is_inode_locked ) {
-	/* we've done an indirect->direct conversion.  when the data block 
-	** was freed, it was removed from the list of blocks that must 
-	** be flushed before the transaction commits, so we don't need to 
+	/* we've done an indirect->direct conversion.  when the data block
+	** was freed, it was removed from the list of blocks that must
+	** be flushed before the transaction commits, so we don't need to
 	** deal with it here.
 	*/
 	p_s_inode->u.reiserfs_i.i_flags &= ~i_pack_on_close_mask;
@@ -1814,6 +1814,9 @@
     int                 retval;
 
     init_tb_struct(th, &s_paste_balance, th->t_super, p_s_search_path, n_pasted_size);
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+    s_paste_balance.key = p_s_key->on_disk_key;
+#endif
     
     while ( (retval = fix_nodes(M_PASTE, &s_paste_balance, NULL, p_c_body)) == REPEAT_SEARCH ) {
 	/* file system changed while we were in the fix_nodes */
@@ -1824,7 +1827,7 @@
 	    goto error_out ;
 	}
 	if (retval == POSITION_FOUND) {
-	    reiserfs_warning ("PAP-5710: reiserfs_paste_into_item: entry or pasted byte (%K) exists", p_s_key);
+	    reiserfs_warning ("PAP-5710: reiserfs_paste_into_item: entry or pasted byte (%K) exists\n", p_s_key);
 	    retval = -EEXIST ;
 	    goto error_out ;
 	}
@@ -1859,6 +1862,9 @@
     int                 retval;
 
     init_tb_struct(th, &s_ins_balance, th->t_super, p_s_path, IH_SIZE + ih_item_len(p_s_ih));
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+    s_ins_balance.key = key->on_disk_key;
+#endif
 
     /*
     if (p_c_body == 0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/super.c linux-2.4.20/fs/reiserfs/super.c
--- linux-2.4.19/fs/reiserfs/super.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/super.c	2002-10-29 11:18:40.000000000 +0000
@@ -1,19 +1,11 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
- *
- * Trivial changes by Alan Cox to add the LFS fixes
- *
- * Trivial Changes:
- * Rights granted to Hans Reiser to redistribute under other terms providing
- * he accepts all liability including but not limited to patent, fitness
- * for purpose, and direct or indirect claims arising from failure to perform.
- *
- * NO WARRANTY
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/vmalloc.h>
 #include <asm/uaccess.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/smp_lock.h>
@@ -29,13 +21,6 @@
 static int reiserfs_remount (struct super_block * s, int * flags, char * data);
 static int reiserfs_statfs (struct super_block * s, struct statfs * buf);
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static void reiserfs_write_super (struct super_block * s)
 {
 
@@ -48,13 +33,6 @@
   unlock_kernel() ;
 }
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static void reiserfs_write_super_lockfs (struct super_block * s)
 {
 
@@ -333,13 +311,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static void reiserfs_put_super (struct super_block * s)
 {
   int i;
@@ -359,9 +330,9 @@
   journal_release(&th, s) ;
 
   for (i = 0; i < SB_BMAP_NR (s); i ++)
-    brelse (SB_AP_BITMAP (s)[i]);
+    brelse (SB_AP_BITMAP (s)[i].bh);
 
-  reiserfs_kfree (SB_AP_BITMAP (s), sizeof (struct buffer_head *) * SB_BMAP_NR (s), s);
+  vfree (SB_AP_BITMAP (s));
 
   brelse (SB_BUFFER_WITH_SB (s));
 
@@ -372,6 +343,11 @@
 		      s->u.reiserfs_sb.s_kmallocs);
   }
 
+  if (s->u.reiserfs_sb.reserved_blocks != 0) {
+    reiserfs_warning ("green-2005: reiserfs_put_super: reserved blocks left %d\n",
+		      s->u.reiserfs_sb.reserved_blocks);
+  }
+
   reiserfs_proc_unregister( s, "journal" );
   reiserfs_proc_unregister( s, "oidmap" );
   reiserfs_proc_unregister( s, "on-disk-super" );
@@ -422,81 +398,210 @@
 
 };
 
-/* this was (ext2)parse_options */
-static int parse_options (char * options, unsigned long * mount_options, unsigned long * blocks)
-{
-    char * this_char;
+/* this struct is used in reiserfs_getopt () for containing the value for those
+   mount options that have values rather than being toggles. */
+typedef struct {
     char * value;
-  
+    int bitmask; /* bit which is to be set in mount_options bitmask when this
+                    value is found, 0 is no bits are to be set */
+} arg_desc_t;
+
+
+/* this struct is used in reiserfs_getopt() for describing the set of reiserfs
+   mount options */
+typedef struct {
+    char * option_name;
+    int arg_required; /* 0 is argument is not required, not 0 otherwise */
+    const arg_desc_t * values; /* list of values accepted by an option */
+    int bitmask;  /* bit which is to be set in mount_options bitmask when this
+		     option is selected, 0 is not bits are to be set */
+} opt_desc_t;
+
+
+/* possible values for "-o hash=" and bits which are to be set in s_mount_opt
+   of reiserfs specific part of in-core super block */
+const arg_desc_t hash[] = {
+    {"rupasov", FORCE_RUPASOV_HASH},
+    {"tea", FORCE_TEA_HASH},
+    {"r5", FORCE_R5_HASH},
+    {"detect", FORCE_HASH_DETECT},
+    {NULL, 0}
+};
+
+
+/* possible values for "-o block-allocator=" and bits which are to be set in
+   s_mount_opt of reiserfs specific part of in-core super block */
+const arg_desc_t balloc[] = {
+    {"noborder", REISERFS_NO_BORDER},
+    {"no_unhashed_relocation", REISERFS_NO_UNHASHED_RELOCATION},
+    {"hashed_relocation", REISERFS_HASHED_RELOCATION},
+    {"test4", REISERFS_TEST4},
+    {NULL, 0}
+};
+
+const arg_desc_t tails[] = {
+    {"on", REISERFS_LARGETAIL},
+    {"off", -1},
+    {"small", REISERFS_SMALLTAIL},
+    {NULL, 0}
+};
+
+
+/* proceed only one option from a list *cur - string containing of mount options
+   opts - array of options which are accepted
+   opt_arg - if option is found and requires an argument and if it is specifed
+   in the input - pointer to the argument is stored here
+   bit_flags - if option requires to set a certain bit - it is set here
+   return -1 if unknown option is found, opt->arg_required otherwise */
+static int reiserfs_getopt ( struct super_block * s, char ** cur, opt_desc_t * opts, char ** opt_arg,
+			    unsigned long * bit_flags)
+{
+    char * p;
+    /* foo=bar, 
+       ^   ^  ^
+       |   |  +-- option_end
+       |   +-- arg_start
+       +-- option_start
+    */
+    const opt_desc_t * opt;
+    const arg_desc_t * arg;
+    
+    
+    p = *cur;
+    
+    /* assume argument cannot contain commas */
+    *cur = strchr (p, ',');
+    if (*cur) {
+	*(*cur) = '\0';
+	(*cur) ++;
+    }
+
+    if ( !strncmp (p, "alloc=", 6) ) {
+	/* Ugly special case, probably we should redo options parser so that
+	   it can understand several arguments for some options, also so that
+	   it can fill several bitfields with option values. */
+	reiserfs_parse_alloc_options( s, p + 6);
+	return 0;
+    }
+	
+    /* for every option in the list */
+    for (opt = opts; opt->option_name; opt ++) {
+	if (!strncmp (p, opt->option_name, strlen (opt->option_name))) {
+	    if (bit_flags && opt->bitmask != -1 )
+		set_bit (opt->bitmask, bit_flags);
+	    break;
+	}
+    }
+    if (!opt->option_name) {
+	printk ("reiserfs_getopt: unknown option \"%s\"\n", p);
+	return -1;
+    }
+    
+    p += strlen (opt->option_name);
+    switch (*p) {
+    case '=':
+	if (!opt->arg_required) {
+	    printk ("reiserfs_getopt: the option \"%s\" does not require an argument\n",
+		    opt->option_name);
+	    return -1;
+	}
+	break;
+	
+    case 0:
+	if (opt->arg_required) {
+	    printk ("reiserfs_getopt: the option \"%s\" requires an argument\n", opt->option_name);
+	    return -1;
+	}
+	break;
+    default:
+	printk ("reiserfs_getopt: head of option \"%s\" is only correct\n", opt->option_name);
+	return -1;
+    }
+	
+    /* move to the argument, or to next option if argument is not required */
+    p ++;
+    
+    if ( opt->arg_required && !strlen (p) ) {
+	/* this catches "option=," */
+	printk ("reiserfs_getopt: empty argument for \"%s\"\n", opt->option_name);
+	return -1;
+    }
+    
+    if (!opt->values) {
+	/* *opt_arg contains pointer to argument */
+	*opt_arg = p;
+	return opt->arg_required;
+    }
+    
+    /* values possible for this option are listed in opt->values */
+    for (arg = opt->values; arg->value; arg ++) {
+	if (!strcmp (p, arg->value)) {
+	    if (bit_flags && arg->bitmask != -1 )
+		set_bit (arg->bitmask, bit_flags);
+	    return opt->arg_required;
+	}
+    }
+    
+    printk ("reiserfs_getopt: bad value \"%s\" for option \"%s\"\n", p, opt->option_name);
+    return -1;
+}
+
+
+/* returns 0 if something is wrong in option string, 1 - otherwise */
+static int reiserfs_parse_options (struct super_block * s, char * options, /* string given via mount's -o */
+				   unsigned long * mount_options,
+				   /* after the parsing phase, contains the
+				      collection of bitflags defining what
+				      mount options were selected. */
+				   unsigned long * blocks) /* strtol-ed from NNN of resize=NNN */
+{
+    int c;
+    char * arg = NULL;
+    char * pos;
+    opt_desc_t opts[] = {
+		{"tails", 't', tails, -1},
+		{"notail", 0, 0, -1}, /* Compatibility stuff, so that -o notail for old setups still work */
+		{"conv", 0, 0, REISERFS_CONVERT}, 
+		{"nolog", 0, 0, -1},
+		{"replayonly", 0, 0, REPLAYONLY},
+		
+		{"block-allocator", 'a', balloc, -1}, 
+		{"hash", 'h', hash, FORCE_HASH_DETECT},
+		
+		{"resize", 'r', 0, -1},
+		{"attrs", 0, 0, REISERFS_ATTRS},
+		{NULL, 0, 0, 0}
+    };
+	
     *blocks = 0;
-    if (!options)
+    if (!options || !*options)
 	/* use default configuration: create tails, journaling on, no
-           conversion to newest format */
+	   conversion to newest format */
 	return 1;
-    for (this_char = strtok (options, ","); this_char != NULL; this_char = strtok (NULL, ",")) {
-	if ((value = strchr (this_char, '=')) != NULL)
-	    *value++ = 0;
-	if (!strcmp (this_char, "notail")) {
-	    set_bit (NOTAIL, mount_options);
-	} else if (!strcmp (this_char, "conv")) {
-	    // if this is set, we update super block such that
-	    // the partition will not be mounable by 3.5.x anymore
-	    set_bit (REISERFS_CONVERT, mount_options);
-	} else if (!strcmp (this_char, "noborder")) {
-				/* this is used for benchmarking
-                                   experimental variations, it is not
-                                   intended for users to use, only for
-                                   developers who want to casually
-                                   hack in something to test */
-	    set_bit (REISERFS_NO_BORDER, mount_options);
-	} else if (!strcmp (this_char, "no_unhashed_relocation")) {
-	    set_bit (REISERFS_NO_UNHASHED_RELOCATION, mount_options);
-	} else if (!strcmp (this_char, "hashed_relocation")) {
-	    set_bit (REISERFS_HASHED_RELOCATION, mount_options);
-	} else if (!strcmp (this_char, "test4")) {
-	    set_bit (REISERFS_TEST4, mount_options);
-	} else if (!strcmp (this_char, "nolog")) {
-	    reiserfs_warning("reiserfs: nolog mount option not supported yet\n");
-	} else if (!strcmp (this_char, "replayonly")) {
-	    set_bit (REPLAYONLY, mount_options);
-	} else if (!strcmp (this_char, "resize")) {
-	    if (value && *value){
-		*blocks = simple_strtoul (value, &value, 0);
-	    } else {
-	  	printk("reiserfs: resize option requires a value\n");
+    else
+	/* Drop defaults to zeroes */
+	*mount_options = 0;
+    
+    for (pos = options; pos; ) {
+	c = reiserfs_getopt (s, &pos, opts, &arg, mount_options);
+	if (c == -1)
+	    /* wrong option is given */
+	    return 0;
+	
+	if (c == 'r') {
+	    char * p;
+	    
+	    p = 0;
+	    /* "resize=NNN" */
+	    *blocks = simple_strtoul (arg, &p, 0);
+	    if (*p != '\0') {
+		/* NNN does not look like a number */
+		printk ("reiserfs_parse_options: bad value %s\n", arg);
 		return 0;
 	    }
-	} else if (!strcmp (this_char, "hash")) {
-	    if (value && *value) {
-		/* if they specify any hash option, we force detection
-		** to make sure they aren't using the wrong hash
-		*/
-	        if (!strcmp(value, "rupasov")) {
-		    set_bit (FORCE_RUPASOV_HASH, mount_options);
-		    set_bit (FORCE_HASH_DETECT, mount_options);
-		} else if (!strcmp(value, "tea")) {
-		    set_bit (FORCE_TEA_HASH, mount_options);
-		    set_bit (FORCE_HASH_DETECT, mount_options);
-		} else if (!strcmp(value, "r5")) {
-		    set_bit (FORCE_R5_HASH, mount_options);
-		    set_bit (FORCE_HASH_DETECT, mount_options);
-		} else if (!strcmp(value, "detect")) {
-		    set_bit (FORCE_HASH_DETECT, mount_options);
-		} else {
-		    printk("reiserfs: invalid hash function specified\n") ;
-		    return 0 ;
-		}
-	    } else {
-	  	printk("reiserfs: hash option requires a value\n");
-		return 0 ;
-	    }
-	} else if (!strcmp (this_char, "attrs")) {
-	    set_bit (REISERFS_ATTRS, mount_options);
-	} else {
-	    printk ("reiserfs: Unrecognized mount option %s\n", this_char);
-	    return 0;
 	}
     }
+    
     return 1;
 }
 
@@ -524,14 +629,7 @@
 	}
 }
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
-static int reiserfs_remount (struct super_block * s, int * flags, char * data)
+static int reiserfs_remount (struct super_block * s, int * mount_flags, char * data)
 {
   struct reiserfs_super_block * rs;
   struct reiserfs_transaction_handle th ;
@@ -540,7 +638,7 @@
 
   rs = SB_DISK_SUPER_BLOCK (s);
 
-  if (!parse_options(data, &mount_options, &blocks))
+  if (!reiserfs_parse_options(s, data, &mount_options, &blocks))
   	return 0;
 
 #define SET_OPT( opt, bits, super )					\
@@ -548,7 +646,8 @@
 	    ( super ) -> u.reiserfs_sb.s_mount_opt |= ( 1 << ( opt ) )
 
   /* set options in the super-block bitmask */
-  SET_OPT( NOTAIL, mount_options, s );
+  SET_OPT( REISERFS_SMALLTAIL, mount_options, s );
+  SET_OPT( REISERFS_LARGETAIL, mount_options, s );
   SET_OPT( REISERFS_NO_BORDER, mount_options, s );
   SET_OPT( REISERFS_NO_UNHASHED_RELOCATION, mount_options, s );
   SET_OPT( REISERFS_HASHED_RELOCATION, mount_options, s );
@@ -564,12 +663,11 @@
 	  return rc;
   }
 
-  if ((unsigned long)(*flags & MS_RDONLY) == (s->s_flags & MS_RDONLY)) {
-    /* there is nothing to do to remount read-only fs as read-only fs */
-    return 0;
-  }
-  
-  if (*flags & MS_RDONLY) {
+  if (*mount_flags & MS_RDONLY) {
+    /* remount read-only */
+    if (s->s_flags & MS_RDONLY)
+      /* it is read-only already */
+      return 0;
     /* try to remount file system with read-only permissions */
     if (sb_state(rs) == REISERFS_VALID_FS || s->u.reiserfs_sb.s_mount_state != REISERFS_VALID_FS) {
       return 0;
@@ -582,10 +680,14 @@
     journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
     s->s_dirt = 0;
   } else {
+    /* remount read-write */
+    if (!(s->s_flags & MS_RDONLY))
+	return 0; /* We are read-write already */
+
     s->u.reiserfs_sb.s_mount_state = sb_state(rs) ;
     s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */
     journal_begin(&th, s, 10) ;
-
+    
     /* Mount a partition which is read-only, read-write */
     reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
     s->u.reiserfs_sb.s_mount_state = sb_state(rs);
@@ -600,38 +702,90 @@
   SB_JOURNAL(s)->j_must_wait = 1 ;
   journal_end(&th, s, 10) ;
 
-  if (!( *flags & MS_RDONLY ) )
+  if (!( *mount_flags & MS_RDONLY ) )
     finish_unfinished( s );
 
   return 0;
 }
 
+/* load_bitmap_info_data - Sets up the reiserfs_bitmap_info structure from disk.
+ * @sb - superblock for this filesystem
+ * @bi - the bitmap info to be loaded. Requires that bi->bh is valid.
+ *
+ * This routine counts how many free bits there are, finding the first zero
+ * as a side effect. Could also be implemented as a loop of test_bit() calls, or
+ * a loop of find_first_zero_bit() calls. This implementation is similar to
+ * find_first_zero_bit(), but doesn't return after it finds the first bit.
+ * Should only be called on fs mount, but should be fairly efficient anyways.
+ *
+ * bi->first_zero_hint is considered unset if it == 0, since the bitmap itself
+ * will * invariably occupt block 0 represented in the bitmap. The only
+ * exception to this is when free_count also == 0, since there will be no
+ * free blocks at all.
+ */
+static void load_bitmap_info_data (struct super_block *sb,
+                                   struct reiserfs_bitmap_info *bi)
+{
+    unsigned long *cur = (unsigned long *)bi->bh->b_data;
+
+    while ((char *)cur < (bi->bh->b_data + sb->s_blocksize)) {
+
+	/* No need to scan if all 0's or all 1's.
+	 * Since we're only counting 0's, we can simply ignore all 1's */
+	if (*cur == 0) {
+	    if (bi->first_zero_hint == 0) {
+		bi->first_zero_hint = ((char *)cur - bi->bh->b_data) << 3;
+	    }
+	    bi->free_count += sizeof ( unsigned long ) * 8;
+	} else if (*cur != ~0L) {
+	    int b;
+	    for (b = 0; b < sizeof ( unsigned long ) * 8; b++) {
+		if (!reiserfs_test_le_bit (b, cur)) {
+		    bi->free_count ++;
+		    if (bi->first_zero_hint == 0)
+			bi->first_zero_hint =
+					(((char *)cur - bi->bh->b_data) << 3) + b;
+		    }
+		}
+	    }
+	cur ++;
+    }
+
+#ifdef CONFIG_REISERFS_CHECK
+// This outputs a lot of unneded info on big FSes
+//    reiserfs_warning ("bitmap loaded from block %d: %d free blocks\n",
+//		      bi->bh->b_blocknr, bi->free_count);
+#endif
+}
 
 static int read_bitmaps (struct super_block * s)
 {
     int i, bmp;
 
-    SB_AP_BITMAP (s) = reiserfs_kmalloc (sizeof (struct buffer_head *) * SB_BMAP_NR(s), GFP_NOFS, s);
+    SB_AP_BITMAP (s) = vmalloc (sizeof (struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
     if (SB_AP_BITMAP (s) == 0)
       return 1;
+    memset (SB_AP_BITMAP (s), 0, sizeof (struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
+
     for (i = 0, bmp = REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize + 1;
  	 i < SB_BMAP_NR(s); i++, bmp = s->s_blocksize * 8 * i) {
-      SB_AP_BITMAP (s)[i] = getblk (s->s_dev, bmp, s->s_blocksize);
-      if (!buffer_uptodate(SB_AP_BITMAP(s)[i]))
-	ll_rw_block(READ, 1, SB_AP_BITMAP(s) + i); 
+      SB_AP_BITMAP (s)[i].bh = sb_getblk (s, bmp);
+      if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh))
+	ll_rw_block(READ, 1, &SB_AP_BITMAP(s)[i].bh); 
     }
     for (i = 0; i < SB_BMAP_NR(s); i++) {
-      wait_on_buffer(SB_AP_BITMAP (s)[i]);
-      if (!buffer_uptodate(SB_AP_BITMAP(s)[i])) {
+      wait_on_buffer(SB_AP_BITMAP (s)[i].bh);
+      if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) {
 	reiserfs_warning("sh-2029: reiserfs read_bitmaps: "
 			 "bitmap block (#%lu) reading failed\n",
-			 SB_AP_BITMAP(s)[i]->b_blocknr);
+			 SB_AP_BITMAP(s)[i].bh->b_blocknr);
 	for (i = 0; i < SB_BMAP_NR(s); i++)
-	  brelse(SB_AP_BITMAP(s)[i]);
-	reiserfs_kfree(SB_AP_BITMAP(s), sizeof(struct buffer_head *) * SB_BMAP_NR(s), s);
+	  brelse(SB_AP_BITMAP(s)[i].bh);
+	vfree(SB_AP_BITMAP(s));
 	SB_AP_BITMAP(s) = NULL;
 	return 1;
       }
+      load_bitmap_info_data (s, SB_AP_BITMAP (s) + i);
     }   
     return 0;
 }
@@ -643,16 +797,17 @@
   int bmp1 = (REISERFS_OLD_DISK_OFFSET_IN_BYTES / s->s_blocksize) + 1;  /* first of bitmap blocks */
 
   /* read true bitmap */
-  SB_AP_BITMAP (s) = reiserfs_kmalloc (sizeof (struct buffer_head *) * sb_bmap_nr(rs), GFP_NOFS, s);
+  SB_AP_BITMAP (s) = vmalloc (sizeof (struct reiserfs_buffer_info *) * sb_bmap_nr(rs));
   if (SB_AP_BITMAP (s) == 0)
     return 1;
 
-  memset (SB_AP_BITMAP (s), 0, sizeof (struct buffer_head *) * sb_bmap_nr(rs));
+  memset (SB_AP_BITMAP (s), 0, sizeof (struct reiserfs_buffer_info *) * sb_bmap_nr(rs));
 
   for (i = 0; i < sb_bmap_nr(rs); i ++) {
-    SB_AP_BITMAP (s)[i] = reiserfs_bread (s, bmp1 + i, s->s_blocksize);
-    if (!SB_AP_BITMAP (s)[i])
+    SB_AP_BITMAP (s)[i].bh = reiserfs_bread (s, bmp1 + i, s->s_blocksize);
+    if (!SB_AP_BITMAP (s)[i].bh)
       return 1;
+    load_bitmap_info_data (s, SB_AP_BITMAP (s) + i);
   }
 
   return 0;
@@ -665,7 +820,7 @@
   char * buf;
 
   while (i < SB_BLOCK_COUNT (s)) {
-    buf = SB_AP_BITMAP (s)[i / (s->s_blocksize * 8)]->b_data;
+    buf = SB_AP_BITMAP (s)[i / (s->s_blocksize * 8)].bh->b_data;
     if (!reiserfs_test_le_bit (i % (s->s_blocksize * 8), buf))
       free ++;
     i ++;
@@ -777,10 +932,11 @@
   }
 
   for (i = 0; i < SB_BMAP_NR(s) ; i++) {
-    ll_rw_block(READ, 1, &(SB_AP_BITMAP(s)[i])) ;
-    wait_on_buffer(SB_AP_BITMAP(s)[i]) ;
-    if (!buffer_uptodate(SB_AP_BITMAP(s)[i])) {
-      printk("reread_meta_blocks, error reading bitmap block number %d at %ld\n", i, SB_AP_BITMAP(s)[i]->b_blocknr) ;
+    ll_rw_block(READ, 1, &(SB_AP_BITMAP(s)[i].bh)) ;
+    wait_on_buffer(SB_AP_BITMAP(s)[i].bh) ;
+    if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) {
+      printk("reread_meta_blocks, error reading bitmap block number %d at
+      %ld\n", i, SB_AP_BITMAP(s)[i].bh->b_blocknr) ;
       return 1 ;
     }
   }
@@ -944,13 +1100,6 @@
     return 0;
 }
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static struct super_block * reiserfs_read_super (struct super_block * s, void * data, int silent)
 {
     int size;
@@ -969,7 +1118,16 @@
 
     memset (&s->u.reiserfs_sb, 0, sizeof (struct reiserfs_sb_info));
 
-    if (parse_options ((char *) data, &(s->u.reiserfs_sb.s_mount_opt), &blocks) == 0) {
+    /* Set default values for options: non-aggressive tails */
+    s->u.reiserfs_sb.s_mount_opt = ( 1 << REISERFS_SMALLTAIL );
+    /* default block allocator option: skip_busy */
+    s->u.reiserfs_sb.s_alloc_options.bits = ( 1 << 5);
+    /* If file grew past 4 blocks, start preallocation blocks for it. */
+    s->u.reiserfs_sb.s_alloc_options.preallocmin = 4;
+    /* Preallocate by 8 blocks (9-1) at once */
+    s->u.reiserfs_sb.s_alloc_options.preallocsize = 9;
+
+    if (reiserfs_parse_options (s, (char *) data, &(s->u.reiserfs_sb.s_mount_opt), &blocks) == 0) {
 	return NULL;
     }
 
@@ -1119,10 +1277,10 @@
     if (SB_DISK_SUPER_BLOCK (s)) {
 	for (j = 0; j < SB_BMAP_NR (s); j ++) {
 	    if (SB_AP_BITMAP (s))
-		brelse (SB_AP_BITMAP (s)[j]);
+		brelse (SB_AP_BITMAP (s)[j].bh);
 	}
 	if (SB_AP_BITMAP (s))
-	    reiserfs_kfree (SB_AP_BITMAP (s), sizeof (struct buffer_head *) * SB_BMAP_NR (s), s);
+	    vfree (SB_AP_BITMAP (s));
     }
     if (SB_BUFFER_WITH_SB (s))
 	brelse(SB_BUFFER_WITH_SB (s));
@@ -1131,34 +1289,24 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static int reiserfs_statfs (struct super_block * s, struct statfs * buf)
 {
   struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
   
-				/* changed to accomodate gcc folks.*/
-  buf->f_type    =  REISERFS_SUPER_MAGIC;
-  buf->f_bsize   = s->s_blocksize;
-  buf->f_blocks  = sb_block_count(rs) - sb_bmap_nr(rs) - 1;
+  buf->f_namelen = (REISERFS_MAX_NAME (s->s_blocksize));
+  buf->f_ffree   = -1;
+  buf->f_files   = -1;
   buf->f_bfree   = sb_free_blocks(rs);
   buf->f_bavail  = buf->f_bfree;
-  buf->f_files   = -1;
-  buf->f_ffree   = -1;
-  buf->f_namelen = (REISERFS_MAX_NAME_LEN (s->s_blocksize));
+  buf->f_blocks  = sb_block_count(rs) - sb_bmap_nr(rs) - 1;
+  buf->f_bsize   = s->s_blocksize;
+  /* changed to accomodate gcc folks.*/
+  buf->f_type    =  REISERFS_SUPER_MAGIC;
   return 0;
 }
 
 static DECLARE_FSTYPE_DEV(reiserfs_fs_type,"reiserfs",reiserfs_read_super);
 
-//
-// this is exactly what 2.3.99-pre9's init_ext2_fs is
-//
 static int __init init_reiserfs_fs (void)
 {
 	reiserfs_proc_info_global_init();
@@ -1172,9 +1320,6 @@
 MODULE_LICENSE("GPL");
 EXPORT_NO_SYMBOLS;
 
-//
-// this is exactly what 2.3.99-pre9's init_ext2_fs is
-//
 static void __exit exit_reiserfs_fs(void)
 {
 	reiserfs_proc_unregister_global( "version" );
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/tail_conversion.c linux-2.4.20/fs/reiserfs/tail_conversion.c
--- linux-2.4.19/fs/reiserfs/tail_conversion.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/tail_conversion.c	2002-10-29 11:18:48.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999 Hans Reiser, see reiserfs/README for licensing and copyright details
+ * Copyright 1999-2002 Hans Reiser, see reiserfs/README for licensing and copyright details
  */
 
 #include <linux/config.h>
@@ -213,7 +213,7 @@
     copy_item_head (&s_ih, PATH_PITEM_HEAD(p_s_path));
 
     tail_len = (n_new_file_size & (n_block_size - 1));
-    if (!old_format_only (p_s_sb))
+    if (get_inode_sd_version (p_s_inode) == STAT_DATA_V2)
 	round_tail_len = ROUND_UP (tail_len);
     else
 	round_tail_len = tail_len;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/reiserfs/version.c linux-2.4.20/fs/reiserfs/version.c
--- linux-2.4.19/fs/reiserfs/version.c	2001-01-15 20:42:32.000000000 +0000
+++ linux-2.4.20/fs/reiserfs/version.c	2002-10-29 11:18:39.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 char *reiserfs_get_version_string(void) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/smbfs/inode.c linux-2.4.20/fs/smbfs/inode.c
--- linux-2.4.19/fs/smbfs/inode.c	2002-02-25 19:38:09.000000000 +0000
+++ linux-2.4.20/fs/smbfs/inode.c	2002-10-29 11:18:33.000000000 +0000
@@ -43,6 +43,7 @@
 #endif
 
 #define SMB_TTL_DEFAULT 1000
+#define SMB_TIMEO_DEFAULT 30
 
 static void smb_delete_inode(struct inode *);
 static void smb_put_super(struct super_block *);
@@ -277,6 +278,7 @@
 	{ "iocharset",	0, 'i' },
 	{ "codepage",	0, 'c' },
 	{ "ttl",	0, 't' },
+	{ "timeo",	0, 'o' },
 	{ NULL,		0, 0}
 };
 
@@ -330,6 +332,9 @@
 		case 't':
 			mnt->ttl = value;
 			break;
+		case 'o':
+			mnt->timeo = value;
+			break;
 		default:
 			printk ("smbfs: Unrecognized mount option %s\n",
 				optopt);
@@ -376,6 +381,8 @@
 
 	if (mnt->ttl != SMB_TTL_DEFAULT)
 		seq_printf(s, ",ttl=%d", mnt->ttl);
+	if (mnt->timeo != SMB_TIMEO_DEFAULT)
+		seq_printf(s, ",timeo=%d", mnt->timeo);
 
 	return 0;
 }
@@ -467,6 +474,7 @@
 		SMB_NLS_MAXNAMELEN);
 
 	mnt->ttl = SMB_TTL_DEFAULT;
+	mnt->timeo = SMB_TIMEO_DEFAULT;
 	if (ver == SMB_MOUNT_OLDVERSION) {
 		mnt->version = oldmnt->version;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/smbfs/proc.c linux-2.4.20/fs/smbfs/proc.c
--- linux-2.4.19/fs/smbfs/proc.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/smbfs/proc.c	2002-10-29 11:18:33.000000000 +0000
@@ -33,9 +33,6 @@
    config option. */
 #define SMBFS_POSIX_UNLINK 1
 
-/* Allow smb_retry to be interrupted. */
-#define SMB_RETRY_INTR
-
 #define SMB_VWV(packet)  ((packet) + SMB_HEADER_LEN)
 #define SMB_CMD(packet)  (*(packet+8))
 #define SMB_WCT(packet)  (*(packet+SMB_HEADER_LEN - 1))
@@ -715,28 +712,11 @@
 	/*
 	 * Wait for the new connection.
 	 */
-#ifdef SMB_RETRY_INTR
 	smb_unlock_server(server);
-	interruptible_sleep_on_timeout(&server->wait,  30*HZ);
+	interruptible_sleep_on_timeout(&server->wait, server->mnt->timeo*HZ);
 	smb_lock_server(server);
 	if (signal_pending(current))
 		printk(KERN_INFO "smb_retry: caught signal\n");
-#else
-	/*
-	 * We don't want to be interrupted. For example, what if 'current'
-	 * already has received a signal? sleep_on would terminate immediately
-	 * and smbmount would not be able to re-establish connection.
-	 *
-	 * smbmount should be able to reconnect later, but it can't because
-	 * it will get an -EIO on attempts to open the mountpoint!
-	 *
-	 * FIXME: go back to the interruptable version now that smbmount
-	 * can avoid -EIO on the mountpoint when reconnecting?
-	 */
-	smb_unlock_server(server);
-	sleep_on_timeout(&server->wait, 30*HZ);
-	smb_lock_server(server);
-#endif
 
 	/*
 	 * Check for a valid connection.
@@ -895,11 +875,7 @@
 int
 smb_wakeup(struct smb_sb_info *server)
 {
-#ifdef SMB_RETRY_INTR
 	wake_up_interruptible(&server->wait);
-#else
-	wake_up(&server->wait);
-#endif
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/smbfs/smb_debug.h linux-2.4.20/fs/smbfs/smb_debug.h
--- linux-2.4.19/fs/smbfs/smb_debug.h	2001-01-01 17:57:08.000000000 +0000
+++ linux-2.4.20/fs/smbfs/smb_debug.h	2002-10-29 11:18:33.000000000 +0000
@@ -7,20 +7,20 @@
 	(dentry)->d_parent->d_name.name,(dentry)->d_name.name
 
 /*
- * safety checks that should never happen ??? 
+ * safety checks that should never happen ???
  * these are normally enabled.
  */
 #ifdef SMBFS_PARANOIA
-#define PARANOIA(x...) printk(KERN_NOTICE __FUNCTION__ ": " x)
+# define PARANOIA(f, a...) printk(KERN_NOTICE "%s: " f, __FUNCTION__ , ## a)
 #else
-#define PARANOIA(x...) do { ; } while(0)
+# define PARANOIA(f, a...) do { ; } while(0)
 #endif
 
 /* lots of debug messages */
 #ifdef SMBFS_DEBUG_VERBOSE
-#define VERBOSE(x...) printk(KERN_DEBUG __FUNCTION__ ": " x)
+# define VERBOSE(f, a...) printk(KERN_DEBUG "%s: " f, __FUNCTION__ , ## a)
 #else
-#define VERBOSE(x...) do { ; } while(0)
+# define VERBOSE(f, a...) do { ; } while(0)
 #endif
 
 /*
@@ -28,7 +28,7 @@
  * too common name.
  */
 #ifdef SMBFS_DEBUG
-#define DEBUG1(x...) printk(KERN_DEBUG __FUNCTION__ ": " x)
+# define DEBUG1(f, a...) printk(KERN_DEBUG "%s: " f, __FUNCTION__ , ## a)
 #else
-#define DEBUG1(x...) do { ; } while(0)
+# define DEBUG1(f, a...) do { ; } while(0)
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/smbfs/sock.c linux-2.4.20/fs/smbfs/sock.c
--- linux-2.4.19/fs/smbfs/sock.c	2001-10-03 00:03:34.000000000 +0000
+++ linux-2.4.20/fs/smbfs/sock.c	2002-10-29 11:18:37.000000000 +0000
@@ -12,6 +12,7 @@
 #include <linux/socket.h>
 #include <linux/fcntl.h>
 #include <linux/file.h>
+#include <linux/poll.h>
 #include <linux/in.h>
 #include <linux/net.h>
 #include <linux/mm.h>
@@ -305,6 +306,55 @@
 	}
 }
 
+/*
+ * Poll the server->socket to allow receives to time out.
+ * returns 0 when ok to continue, <0 on errors.
+ */
+static int
+smb_receive_poll(struct smb_sb_info *server)
+{
+	struct file *file = server->sock_file;
+	poll_table wait_table;
+	int result = 0;
+	int timeout = server->mnt->timeo * HZ;
+	int mask;
+
+	for (;;) {
+		poll_initwait(&wait_table);
+                set_current_state(TASK_INTERRUPTIBLE);
+
+		mask = file->f_op->poll(file, &wait_table);
+		if (mask & POLLIN) {
+			poll_freewait(&wait_table);
+			current->state = TASK_RUNNING;
+			break;
+		}
+
+		timeout = schedule_timeout(timeout);
+		poll_freewait(&wait_table);
+                set_current_state(TASK_RUNNING);
+
+		if (wait_table.error) {
+			result = wait_table.error;
+			break;
+		}
+
+		if (signal_pending(current)) {
+			/* we got a signal (which?) tell the caller to
+			   try again (on all signals?). */
+			DEBUG1("got signal_pending()\n");
+			result = -ERESTARTSYS;
+			break;
+		}
+		if (!timeout) {
+			printk(KERN_WARNING "SMB server not responding\n");
+			result = -EIO;
+			break;
+		}
+	}
+	return result;
+}
+
 static int
 smb_send_raw(struct socket *socket, unsigned char *source, int length)
 {
@@ -332,13 +382,19 @@
 }
 
 static int
-smb_receive_raw(struct socket *socket, unsigned char *target, int length)
+smb_receive_raw(struct smb_sb_info *server, unsigned char *target, int length)
 {
 	int result;
 	int already_read = 0;
+	struct socket *socket = server_sock(server);
 
 	while (already_read < length)
 	{
+		result = smb_receive_poll(server);
+		if (result < 0) {
+			DEBUG1("poll error = %d\n", -result);
+			return result;
+		}
 		result = _recvfrom(socket,
 				   (void *) (target + already_read),
 				   length - already_read, 0);
@@ -358,7 +414,7 @@
 }
 
 static int
-smb_get_length(struct socket *socket, unsigned char *header)
+smb_get_length(struct smb_sb_info *server, unsigned char *header)
 {
 	int result;
 	unsigned char peek_buf[4];
@@ -367,7 +423,7 @@
       re_recv:
 	fs = get_fs();
 	set_fs(get_ds());
-	result = smb_receive_raw(socket, peek_buf, 4);
+	result = smb_receive_raw(server, peek_buf, 4);
 	set_fs(fs);
 
 	if (result < 0)
@@ -415,12 +471,11 @@
 static int
 smb_receive(struct smb_sb_info *server)
 {
-	struct socket *socket = server_sock(server);
 	unsigned char * packet = server->packet;
 	int len, result;
 	unsigned char peek_buf[4];
 
-	result = smb_get_length(socket, peek_buf);
+	result = smb_get_length(server, peek_buf);
 	if (result < 0)
 		goto out;
 	len = result;
@@ -442,7 +497,7 @@
 		server->packet_size = new_len;
 	}
 	memcpy(packet, peek_buf, 4);
-	result = smb_receive_raw(socket, packet + 4, len);
+	result = smb_receive_raw(server, packet + 4, len);
 	if (result < 0)
 	{
 		VERBOSE("receive error: %d\n", result);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/super.c linux-2.4.20/fs/super.c
--- linux-2.4.19/fs/super.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/fs/super.c	2002-10-29 11:18:40.000000000 +0000
@@ -659,8 +659,7 @@
 	/* What device it is? */
 	if (!dev_name || !*dev_name)
 		return ERR_PTR(-EINVAL);
-	if (path_init(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
-		error = path_walk(dev_name, &nd);
+	error = path_lookup(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd);
 	if (error)
 		return ERR_PTR(error);
 	inode = nd.dentry->d_inode;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/ufs/truncate.c linux-2.4.20/fs/ufs/truncate.c
--- linux-2.4.19/fs/ufs/truncate.c	2002-02-25 19:38:09.000000000 +0000
+++ linux-2.4.20/fs/ufs/truncate.c	2002-10-29 11:18:40.000000000 +0000
@@ -448,10 +448,7 @@
 		if (IS_SYNC(inode) && (inode->i_state & I_DIRTY))
 			ufs_sync_inode (inode);
 		run_task_queue(&tq_disk);
-		current->policy |= SCHED_YIELD;
-		schedule ();
-
-
+		yield();
 	}
 	offset = inode->i_size & uspi->s_fshift;
 	if (offset) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/fs/xattr.c linux-2.4.20/fs/xattr.c
--- linux-2.4.19/fs/xattr.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/fs/xattr.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,355 @@
+/*
+  File: fs/xattr.c
+
+  Extended attribute handling.
+
+  Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
+  Copyright (C) 2001 SGI - Silicon Graphics, Inc <linux-xfs@oss.sgi.com>
+ */
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/smp_lock.h>
+#include <linux/file.h>
+#include <linux/xattr.h>
+#include <asm/uaccess.h>
+
+/*
+ * Extended attribute memory allocation wrappers, originally
+ * based on the Intermezzo PRESTO_ALLOC/PRESTO_FREE macros.
+ * The vmalloc use here is very uncommon - extended attributes
+ * are supposed to be small chunks of metadata, and it is quite
+ * unusual to have very many extended attributes, so lists tend
+ * to be quite short as well.  The 64K upper limit is derived
+ * from the extended attribute size limit used by XFS.
+ * Intentionally allow zero @size for value/list size requests.
+ */
+static void *
+xattr_alloc(size_t size, size_t limit)
+{
+	void *ptr;
+
+	if (size > limit)
+		return ERR_PTR(-E2BIG);
+
+	if (!size)	/* size request, no buffer is needed */
+		return NULL;
+	else if (size <= PAGE_SIZE)
+		ptr = kmalloc((unsigned long) size, GFP_KERNEL);
+	else
+		ptr = vmalloc((unsigned long) size);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+	return ptr;
+}
+
+static void
+xattr_free(void *ptr, size_t size)
+{
+	if (!size)	/* size request, no buffer was needed */
+		return;
+	else if (size <= PAGE_SIZE)
+		kfree(ptr);
+	else
+		vfree(ptr);
+}
+
+/*
+ * Extended attribute SET operations
+ */
+static long
+setxattr(struct dentry *d, char *name, void *value, size_t size, int flags)
+{
+	int error;
+	void *kvalue;
+	char kname[XATTR_NAME_MAX + 1];
+
+	if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
+		return -EINVAL;
+
+	error = strncpy_from_user(kname, name, sizeof(kname));
+	if (error == 0 || error == sizeof(kname))
+		error = -ERANGE;
+	if (error < 0)
+		return error;
+
+	kvalue = xattr_alloc(size, XATTR_SIZE_MAX);
+	if (IS_ERR(kvalue))
+		return PTR_ERR(kvalue);
+
+	if (size > 0 && copy_from_user(kvalue, value, size)) {
+		xattr_free(kvalue, size);
+		return -EFAULT;
+	}
+
+	error = -EOPNOTSUPP;
+	if (d->d_inode->i_op && d->d_inode->i_op->setxattr) {
+		down(&d->d_inode->i_sem);
+		lock_kernel();
+		error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags);
+		unlock_kernel();
+		up(&d->d_inode->i_sem);
+	}
+
+	xattr_free(kvalue, size);
+	return error;
+}
+
+asmlinkage long
+sys_setxattr(char *path, char *name, void *value, size_t size, int flags)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk(path, &nd);
+	if (error)
+		return error;
+	error = setxattr(nd.dentry, name, value, size, flags);
+	path_release(&nd);
+	return error;
+}
+
+asmlinkage long
+sys_lsetxattr(char *path, char *name, void *value, size_t size, int flags)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk_link(path, &nd);
+	if (error)
+		return error;
+	error = setxattr(nd.dentry, name, value, size, flags);
+	path_release(&nd);
+	return error;
+}
+
+asmlinkage long
+sys_fsetxattr(int fd, char *name, void *value, size_t size, int flags)
+{
+	struct file *f;
+	int error = -EBADF;
+
+	f = fget(fd);
+	if (!f)
+		return error;
+	error = setxattr(f->f_dentry, name, value, size, flags);
+	fput(f);
+	return error;
+}
+
+/*
+ * Extended attribute GET operations
+ */
+static ssize_t
+getxattr(struct dentry *d, char *name, void *value, size_t size)
+{
+	ssize_t error;
+	void *kvalue;
+	char kname[XATTR_NAME_MAX + 1];
+
+	error = strncpy_from_user(kname, name, sizeof(kname));
+	if (error == 0 || error == sizeof(kname))
+		error = -ERANGE;
+	if (error < 0)
+		return error;
+
+	kvalue = xattr_alloc(size, XATTR_SIZE_MAX);
+	if (IS_ERR(kvalue))
+		return PTR_ERR(kvalue);
+
+	error = -EOPNOTSUPP;
+	if (d->d_inode->i_op && d->d_inode->i_op->getxattr) {
+		down(&d->d_inode->i_sem);
+		lock_kernel();
+		error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
+		unlock_kernel();
+		up(&d->d_inode->i_sem);
+	}
+
+	if (kvalue && error > 0)
+		if (copy_to_user(value, kvalue, error))
+			error = -EFAULT;
+	xattr_free(kvalue, size);
+	return error;
+}
+
+asmlinkage ssize_t
+sys_getxattr(char *path, char *name, void *value, size_t size)
+{
+	struct nameidata nd;
+	ssize_t error;
+
+	error = user_path_walk(path, &nd);
+	if (error)
+		return error;
+	error = getxattr(nd.dentry, name, value, size);
+	path_release(&nd);
+	return error;
+}
+
+asmlinkage ssize_t
+sys_lgetxattr(char *path, char *name, void *value, size_t size)
+{
+	struct nameidata nd;
+	ssize_t error;
+
+	error = user_path_walk_link(path, &nd);
+	if (error)
+		return error;
+	error = getxattr(nd.dentry, name, value, size);
+	path_release(&nd);
+	return error;
+}
+
+asmlinkage ssize_t
+sys_fgetxattr(int fd, char *name, void *value, size_t size)
+{
+	struct file *f;
+	ssize_t error = -EBADF;
+
+	f = fget(fd);
+	if (!f)
+		return error;
+	error = getxattr(f->f_dentry, name, value, size);
+	fput(f);
+	return error;
+}
+
+/*
+ * Extended attribute LIST operations
+ */
+static ssize_t
+listxattr(struct dentry *d, char *list, size_t size)
+{
+	ssize_t error;
+	char *klist;
+
+	klist = (char *)xattr_alloc(size, XATTR_LIST_MAX);
+	if (IS_ERR(klist))
+		return PTR_ERR(klist);
+
+	error = -EOPNOTSUPP;
+	if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
+		down(&d->d_inode->i_sem);
+		lock_kernel();
+		error = d->d_inode->i_op->listxattr(d, klist, size);
+		unlock_kernel();
+		up(&d->d_inode->i_sem);
+	}
+
+	if (klist && error > 0)
+		if (copy_to_user(list, klist, error))
+			error = -EFAULT;
+	xattr_free(klist, size);
+	return error;
+}
+
+asmlinkage ssize_t
+sys_listxattr(char *path, char *list, size_t size)
+{
+	struct nameidata nd;
+	ssize_t error;
+
+	error = user_path_walk(path, &nd);
+	if (error)
+		return error;
+	error = listxattr(nd.dentry, list, size);
+	path_release(&nd);
+	return error;
+}
+
+asmlinkage ssize_t
+sys_llistxattr(char *path, char *list, size_t size)
+{
+	struct nameidata nd;
+	ssize_t error;
+
+	error = user_path_walk_link(path, &nd);
+	if (error)
+		return error;
+	error = listxattr(nd.dentry, list, size);
+	path_release(&nd);
+	return error;
+}
+
+asmlinkage ssize_t
+sys_flistxattr(int fd, char *list, size_t size)
+{
+	struct file *f;
+	ssize_t error = -EBADF;
+
+	f = fget(fd);
+	if (!f)
+		return error;
+	error = listxattr(f->f_dentry, list, size);
+	fput(f);
+	return error;
+}
+
+/*
+ * Extended attribute REMOVE operations
+ */
+static long
+removexattr(struct dentry *d, char *name)
+{
+	int error;
+	char kname[XATTR_NAME_MAX + 1];
+
+	error = strncpy_from_user(kname, name, sizeof(kname));
+	if (error == 0 || error == sizeof(kname))
+		error = -ERANGE;
+	if (error < 0)
+		return error;
+
+	error = -EOPNOTSUPP;
+	if (d->d_inode->i_op && d->d_inode->i_op->removexattr) {
+		down(&d->d_inode->i_sem);
+		lock_kernel();
+		error = d->d_inode->i_op->removexattr(d, kname);
+		unlock_kernel();
+		up(&d->d_inode->i_sem);
+	}
+	return error;
+}
+
+asmlinkage long
+sys_removexattr(char *path, char *name)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk(path, &nd);
+	if (error)
+		return error;
+	error = removexattr(nd.dentry, name);
+	path_release(&nd);
+	return error;
+}
+
+asmlinkage long
+sys_lremovexattr(char *path, char *name)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk_link(path, &nd);
+	if (error)
+		return error;
+	error = removexattr(nd.dentry, name);
+	path_release(&nd);
+	return error;
+}
+
+asmlinkage long
+sys_fremovexattr(int fd, char *name)
+{
+	struct file *f;
+	int error = -EBADF;
+
+	f = fget(fd);
+	if (!f)
+		return error;
+	error = removexattr(f->f_dentry, name);
+	fput(f);
+	return error;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-alpha/floppy.h linux-2.4.20/include/asm-alpha/floppy.h
--- linux-2.4.19/include/asm-alpha/floppy.h	2001-10-25 20:53:55.000000000 +0000
+++ linux-2.4.20/include/asm-alpha/floppy.h	2002-10-29 11:18:50.000000000 +0000
@@ -76,11 +76,6 @@
 
 #endif /* CONFIG_PCI */
 
-__inline__ void virtual_dma_init(void)
-{
-	/* Nothing to do on an Alpha */
-}
-
 static int FDC1 = 0x3f0;
 static int FDC2 = -1;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-alpha/io.h linux-2.4.20/include/asm-alpha/io.h
--- linux-2.4.19/include/asm-alpha/io.h	2001-11-09 21:45:35.000000000 +0000
+++ linux-2.4.20/include/asm-alpha/io.h	2002-10-29 11:18:37.000000000 +0000
@@ -60,6 +60,8 @@
 	return (void *) (address + IDENT_ADDR);
 }
 
+#define page_to_phys(page)	PAGE_TO_PA(page)
+
 /*
  * Change addresses as seen by the kernel (virtual) to addresses as
  * seen by a device (bus), and vice versa.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-alpha/ioctls.h linux-2.4.20/include/asm-alpha/ioctls.h
--- linux-2.4.19/include/asm-alpha/ioctls.h	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/include/asm-alpha/ioctls.h	2002-10-29 11:18:34.000000000 +0000
@@ -65,6 +65,8 @@
 # define TIOCM_OUT2	0x4000
 # define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 #define TIOCGSOFTCAR	0x5419
 #define TIOCSSOFTCAR	0x541A
 #define TIOCLINUX	0x541C
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-alpha/rwsem.h linux-2.4.20/include/asm-alpha/rwsem.h
--- linux-2.4.19/include/asm-alpha/rwsem.h	2001-10-05 19:10:00.000000000 +0000
+++ linux-2.4.20/include/asm-alpha/rwsem.h	2002-10-29 11:18:49.000000000 +0000
@@ -87,6 +87,24 @@
 		rwsem_down_read_failed(sem);
 }
 
+/*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	long old, new, res;
+
+	res = sem->count;
+	do {
+		new = res + RWSEM_ACTIVE_READ_BIAS;
+		if (new <= 0)
+			break;
+		old = res;
+		res = cmpxchg(&sem->count, old, new);
+	} while (res != old);
+	return res >= 0 ? 1 : 0;
+}
+
 static inline void __down_write(struct rw_semaphore *sem)
 {
 	long oldcount;
@@ -111,6 +129,18 @@
 		rwsem_down_write_failed(sem);
 }
 
+/*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	long ret = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
+			   RWSEM_ACTIVE_WRITE_BIAS);
+	if (ret == RWSEM_UNLOCKED_VALUE)
+		return 1;
+	return 0;
+}
+
 static inline void __up_read(struct rw_semaphore *sem)
 {
 	long oldcount;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-alpha/semaphore.h linux-2.4.20/include/asm-alpha/semaphore.h
--- linux-2.4.19/include/asm-alpha/semaphore.h	2001-11-20 23:49:31.000000000 +0000
+++ linux-2.4.20/include/asm-alpha/semaphore.h	2002-10-29 11:18:49.000000000 +0000
@@ -80,6 +80,11 @@
 extern void up(struct semaphore *);
 extern void __up_wakeup(struct semaphore *);
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 /*
  * Hidden out of line code is fun, but extremely messy.  Rely on newer
  * compilers to do a respectable job with this.  The contention cases
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-alpha/socket.h linux-2.4.20/include/asm-alpha/socket.h
--- linux-2.4.19/include/asm-alpha/socket.h	2001-06-21 04:00:55.000000000 +0000
+++ linux-2.4.20/include/asm-alpha/socket.h	2002-10-29 11:18:50.000000000 +0000
@@ -3,7 +3,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 /*
  * Note: we only bother about making the SOL_SOCKET options
  * same as OSF/1, as that's all that "normal" programs are
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-alpha/timex.h linux-2.4.20/include/asm-alpha/timex.h
--- linux-2.4.19/include/asm-alpha/timex.h	1998-12-29 21:56:15.000000000 +0000
+++ linux-2.4.20/include/asm-alpha/timex.h	2002-10-29 11:18:48.000000000 +0000
@@ -27,4 +27,7 @@
 	return ret;
 }
 
+#define vxtime_lock()		do {} while (0)
+#define vxtime_unlock()		do {} while (0)
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-arm/semaphore.h linux-2.4.20/include/asm-arm/semaphore.h
--- linux-2.4.19/include/asm-arm/semaphore.h	2001-08-12 18:14:00.000000000 +0000
+++ linux-2.4.20/include/asm-arm/semaphore.h	2002-10-29 11:18:47.000000000 +0000
@@ -125,4 +125,9 @@
 	__up_op(sem, __up_wakeup);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-arm/socket.h linux-2.4.20/include/asm-arm/socket.h
--- linux-2.4.19/include/asm-arm/socket.h	2001-06-21 04:00:55.000000000 +0000
+++ linux-2.4.20/include/asm-arm/socket.h	2002-10-29 11:18:35.000000000 +0000
@@ -3,7 +3,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	1
 
 #define SO_DEBUG	1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-arm/timex.h linux-2.4.20/include/asm-arm/timex.h
--- linux-2.4.19/include/asm-arm/timex.h	2000-09-18 22:15:24.000000000 +0000
+++ linux-2.4.20/include/asm-arm/timex.h	2002-10-29 11:18:34.000000000 +0000
@@ -23,4 +23,7 @@
 	return 0;
 }
 
+#define vxtime_lock()		do {} while (0)
+#define vxtime_unlock()		do {} while (0)
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-cris/etraxgpio.h linux-2.4.20/include/asm-cris/etraxgpio.h
--- linux-2.4.19/include/asm-cris/etraxgpio.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-cris/etraxgpio.h	2002-10-29 11:18:39.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: etraxgpio.h,v 1.7 2002/04/10 11:55:50 johana Exp $ */
+/* $Id: etraxgpio.h,v 1.8 2002/06/17 15:53:07 johana Exp $ */
 /*
  * The following devices are accessable using this driver using
  * GPIO_MAJOR (120) and a couple of minor numbers:
@@ -25,7 +25,7 @@
 
 /* supported ioctl _IOC_NR's */
 
-#define IO_READBITS  0x1  /* read and return current port bits */
+#define IO_READBITS  0x1  /* read and return current port bits (obsolete) */
 #define IO_SETBITS   0x2  /* set the bits marked by 1 in the argument */
 #define IO_CLRBITS   0x3  /* clear the bits marked by 1 in the argument */
 
@@ -40,11 +40,11 @@
                               * 0=off, 1=green, 2=red, 3=yellow */
 
 /* GPIO direction ioctl's */
-#define IO_READDIR    0x8  /* Read direction 0=input 1=output */
+#define IO_READDIR    0x8  /* Read direction 0=input 1=output  (obsolete) */
 #define IO_SETINPUT   0x9  /* Set direction for bits set, 0=unchanged 1=input, 
-                              returns mask with current inputs */
+                              returns mask with current inputs (obsolete) */
 #define IO_SETOUTPUT  0xA  /* Set direction for bits set, 0=unchanged 1=output,
-                              returns mask with current outputs */
+                              returns mask with current outputs (obsolete)*/
 
 /* LED ioctl extended */
 #define IO_LED_SETBIT 0xB
@@ -63,5 +63,19 @@
 #define IO_CFG_WRITE_MODE_VALUE(msb, data_mask, clk_mask) \
   ( (((msb)&1) << 16) | (((data_mask) &0xFF) << 8) | ((clk_mask) & 0xFF) )
 
+/* The following 4 ioctl's take a pointer as argument and handles
+ * 32 bit ports (port G) properly.
+ * These replaces IO_READBITS,IO_SETINPUT AND IO_SETOUTPUT
+ */
+#define IO_READ_INBITS   0x10 /* *arg is result of reading the input pins */
+#define IO_READ_OUTBITS  0x11 /* *arg is result of reading the output shadow */
+#define IO_SETGET_INPUT  0x12 /* bits set in *arg is set to input,
+                               * *arg updated with current input pins.
+                               */
+#define IO_SETGET_OUTPUT 0x13 /* bits set in *arg is set to output,
+                               * *arg updated with current output pins.
+                               */
+
+
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-cris/etraxvirtex.h linux-2.4.20/include/asm-cris/etraxvirtex.h
--- linux-2.4.19/include/asm-cris/etraxvirtex.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-cris/etraxvirtex.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,35 @@
+/* $Id: etraxvirtex.h,v 1.1 2002/06/25 10:01:05 stefanl Exp $ */
+
+#ifndef _LINUX_ETRAXVIRTEX_FPGA_H
+#define _LINUX_ETRAXVIRTEX_FPGA_H
+
+/* etraxvirtex_fpga _IOC_TYPE, bits 8 to 15 in ioctl cmd */
+
+#define ETRAXVIRTEX_FPGA_IOCTYPE 45
+
+/* supported ioctl _IOC_NR's */
+
+/* in write operations, the argument contains both virtex
+ * register and value.
+ */
+
+#define VIRTEX_FPGA_WRITEARG(reg, value) (((reg) << 16) | (value))
+#define VIRTEX_FPGA_READARG(reg) ((reg) << 16)
+
+#define VIRTEX_FPGA_ARGREG(arg) (((arg) >> 16) & 0x0fff)
+#define VIRTEX_FPGA_ARGVALUE(arg) ((arg) & 0xffff)
+
+#define VIRTEX_FPGA_WRITEREG 0x1   /* write to an (FPGA implemented) register */
+#define VIRTEX_FPGA_READREG  0x2   /* read from an (FPGA implemented register */
+
+/*
+EXAMPLE usage:
+
+    virtex_arg = VIRTEX_FPGA_WRITEARG( reg, val);
+    ioctl(fd, _IO(ETRAXVIRTEX_FPGA_IOCTYPE, VIRTEX_FPGA_WRITEREG), virtex_arg);
+
+    virtex_arg = VIRTEX_FPGA_READARG( reg);
+    val = ioctl(fd, _IO(ETRAXVIRTEX_FPGA_IOCTYPE, VIRTEX_FPGA_READREG), virtex_arg);
+
+*/
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-cris/fasttimer.h linux-2.4.20/include/asm-cris/fasttimer.h
--- linux-2.4.19/include/asm-cris/fasttimer.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-cris/fasttimer.h	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,47 @@
+/* $Id: fasttimer.h,v 1.2 2002/05/28 17:45:34 johana Exp $
+ * linux/include/asm-cris/fasttimer.h
+ *
+ * Fast timers for ETRAX100LX
+ * This may be useful in other OS than Linux so use 2 space indentation...
+ * Copyright (C) 2000, 2002 Axis Communications AB
+ */
+#include <linux/config.h>
+#include <linux/time.h> /* struct timeval */
+#include <linux/timex.h>
+
+/* The timer0 values gives 52us resolution (1/19200) or higher 
+ * but interrupts at HZ 
+ */
+/* We use timer1 to generate interrupts at desired times. */
+
+#ifdef CONFIG_ETRAX_FAST_TIMER
+
+typedef void fast_timer_function_type(unsigned long);
+
+struct fast_timer{ /* Close to timer_list */
+  struct fast_timer *next;
+  struct fast_timer *prev;
+  struct timeval tv_set;
+  struct timeval tv_expires;
+  unsigned long delay_us;
+  fast_timer_function_type *function;
+  unsigned long data;
+  const char *name;
+};
+
+void start_one_shot_timer(struct fast_timer *t,
+                          fast_timer_function_type *function,
+                          unsigned long data,
+                          unsigned long delay_us,
+                          const char *name);
+
+int del_fast_timer(struct fast_timer * t);
+/* return 1 if deleted */
+
+
+void schedule_usleep(unsigned long us);
+
+
+void fast_timer_init(void);
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-cris/pgtable.h linux-2.4.20/include/asm-cris/pgtable.h
--- linux-2.4.19/include/asm-cris/pgtable.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-cris/pgtable.h	2002-10-29 11:18:31.000000000 +0000
@@ -167,7 +167,7 @@
  */
 #define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
 /*
- * (pmds are folded into pgds so this doesnt get actually called,
+ * (pmds are folded into pgds so this doesn't get actually called,
  * but the define is needed for a generic inline function.)
  */
 #define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-cris/rtc.h linux-2.4.20/include/asm-cris/rtc.h
--- linux-2.4.19/include/asm-cris/rtc.h	2001-05-01 23:05:00.000000000 +0000
+++ linux-2.4.20/include/asm-cris/rtc.h	2002-10-29 11:18:32.000000000 +0000
@@ -1,55 +1,86 @@
-/* $Id: rtc.h,v 1.3 2001/03/21 09:56:31 magnusmn Exp $ */
+/* $Id: rtc.h,v 1.5 2002/08/14 11:04:10 sebsjo Exp $ */
+
+#ifndef __RTC_H__
+#define __RTC_H__
 
-#ifndef RTC_H
-#define RTC_H
 
 #include <linux/config.h>
 
-/* Dallas DS1302 clock/calendar register numbers */
+#ifdef CONFIG_ETRAX_DS1302
+   /* Dallas DS1302 clock/calendar register numbers. */
+#  define RTC_SECONDS      0
+#  define RTC_MINUTES      1
+#  define RTC_HOURS        2
+#  define RTC_DAY_OF_MONTH 3
+#  define RTC_MONTH        4
+#  define RTC_WEEKDAY      5
+#  define RTC_YEAR         6
+#  define RTC_CONTROL      7
+
+   /* Bits in CONTROL register. */
+#  define RTC_CONTROL_WRITEPROTECT 	0x80
+#  define RTC_TRICKLECHARGER 		8
+  
+  /* Bits in TRICKLECHARGER register TCS TCS TCS TCS DS DS RS RS. */
+#  define RTC_TCR_PATTERN 	0xA0	/* 1010xxxx */
+#  define RTC_TCR_1DIOD 	0x04	/* xxxx01xx */
+#  define RTC_TCR_2DIOD 	0x08	/* xxxx10xx */
+#  define RTC_TCR_DISABLED 	0x00	/* xxxxxx00 Disabled */
+#  define RTC_TCR_2KOHM 	0x01	/* xxxxxx01 2KOhm */
+#  define RTC_TCR_4KOHM 	0x02	/* xxxxxx10 4kOhm */
+#  define RTC_TCR_8KOHM 	0x03	/* xxxxxx11 8kOhm */
+
+#elif defined(CONFIG_ETRAX_PCF8563)
+   /* I2C bus slave registers. */
+#  define RTC_I2C_READ		0xa3
+#  define RTC_I2C_WRITE		0xa2
+
+   /* Phillips PCF8563 registers. */
+#  define RTC_CONTROL1		0x00		/* Control/Status register 1. */
+#  define RTC_CONTROL2		0x01		/* Control/Status register 2. */
+#  define RTC_CLOCKOUT_FREQ	0x0d		/* CLKOUT frequency. */
+#  define RTC_TIMER_CONTROL	0x0e		/* Timer control. */
+#  define RTC_TIMER_CNTDOWN	0x0f		/* Timer countdown. */
+
+   /* BCD encoded clock registers. */
+#  define RTC_SECONDS		0x02
+#  define RTC_MINUTES		0x03
+#  define RTC_HOURS		0x04
+#  define RTC_DAY_OF_MONTH	0x05
+#  define RTC_WEEKDAY		0x06	/* Not coded in BCD! */
+#  define RTC_MONTH		0x07
+#  define RTC_YEAR		0x08
+#  define RTC_MINUTE_ALARM	0x09
+#  define RTC_HOUR_ALARM	0x0a
+#  define RTC_DAY_ALARM		0x0b
+#  define RTC_WEEKDAY_ALARM 0x0c
 
-#define RTC_SECONDS 0
-#define RTC_MINUTES 1
-#define RTC_HOURS 2
-#define RTC_DAY_OF_MONTH 3
-#define RTC_MONTH 4
-#define RTC_WEEKDAY 5
-#define RTC_YEAR 6
-#define RTC_CONTROL 7
-
-/* Bits in CONTROL register */
-#define RTC_CONTROL_WRITEPROTECT 0x80
-#define RTC_TRICKLECHARGER 8
-/* Bits in TRICKLECHARGER register TCS TCS TCS TCS DS DS RS RS */
-#define   RTC_TCR_PATTERN 0xA0 /* 1010xxxx */
-#define   RTC_TCR_1DIOD 0x04 /* xxxx01xx */
-#define   RTC_TCR_2DIOD 0x08 /* xxxx10xx */
-#define   RTC_TCR_DISABLED 0x00 /* xxxxxx00 Disabled */
-#define   RTC_TCR_2KOHM 0x01      /* xxxxxx01 2KOhm */
-#define   RTC_TCR_4KOHM 0x02      /* xxxxxx10 4kOhm */
-#define   RTC_TCR_8KOHM 0x03      /* xxxxxx11 8kOhm */
+#endif
 
 #ifdef CONFIG_ETRAX_DS1302
-#define CMOS_READ(x) ds1302_readreg(x)
-#define CMOS_WRITE(val,reg) ds1302_writereg(reg,val)
-#define RTC_INIT() ds1302_init()
+#  define CMOS_READ(x) ds1302_readreg(x)
+#  define CMOS_WRITE(val,reg) ds1302_writereg(reg,val)
+#  define RTC_INIT() ds1302_init()
+#elif defined(CONFIG_ETRAX_PCF8563)
+#  define CMOS_READ(x) i2c_readreg(RTC_I2C_READ, x)
+#  define CMOS_WRITE(val,reg) i2c_writereg(RTC_I2C_WRITE,reg,val)
+#  define RTC_INIT() pcf8563_init()
 #else
-/* no RTC configured so we shouldn't try to access any */
-#define CMOS_READ(x) 42
-#define CMOS_WRITE(x,y)
-#define RTC_INIT() (-1)
+  /* No RTC configured so we shouldn't try to access any. */
+#  define CMOS_READ(x) 42
+#  define CMOS_WRITE(x,y)
+#  define RTC_INIT() (-1)
 #endif
 
-/* conversions to and from the stupid RTC internal format */
-
-#define BCD_TO_BIN(x) x = (((x & 0xf0) >> 3) * 5 + (x & 0xf))
-#define BIN_TO_BCD(x) x = (x % 10) | ((x / 10) << 4) 
+/* Conversions to and from the RTC BCD encoded format. */
+#define BCD_TO_BIN(x) ((x)=((x)&15) + ((x)>>4)*10)
+#define BIN_TO_BCD(x) ((x)=(((x)/10)<<4) + (x)%10)
 
 /*
  * The struct used to pass data via the following ioctl. Similar to the
  * struct tm in <time.h>, but it needs to be here so that the kernel 
  * source is self contained, allowing cross-compiles, etc. etc.
  */
-
 struct rtc_time {
 	int tm_sec;
 	int tm_min;
@@ -62,14 +93,18 @@
 	int tm_isdst;
 };
 
-/*
- * ioctl calls that are permitted to the /dev/rtc interface
- */
-
-#define RTC_RD_TIME	_IOR('p', 0x09, struct rtc_time) /* Read RTC time   */
-#define RTC_SET_TIME	_IOW('p', 0x0a, struct rtc_time) /* Set RTC time    */
-#define RTC_SET_CHARGE  _IOW('p', 0x0b, int) /* Set CHARGE mode    */
-
+/* ioctl() calls that are permitted to the /dev/rtc interface. */
+#ifdef CONFIG_ETRAX_DS1302
+#  define DS1302_MAGIC 'p'
+#  define RTC_RD_TIME		_IOR(DS1302_MAGIC, 0x09, struct rtc_time) 	/* Read RTC time. */
+#  define RTC_SET_TIME		_IOW(DS1302_MAGIC, 0x0a, struct rtc_time) 	/* Set RTC time. */
+#  define RTC_SET_CHARGE  	_IOW(DS1302_MAGIC, 0x0b, int) 				/* Set CHARGE mode. */
+#elif defined(CONFIG_ETRAX_PCF8563)
+#  define PCF8563_MAGIC 'T'
+#  define RTC_RD_TIME		_IOR(PCF8563_MAGIC, 0x01, struct rtc_time)	/* Read RTC time. */
+#  define RTC_SET_TIME		_IOW(PCF8563_MAGIC, 0x02, struct rtc_time)	/* Set RTC time. */
+#  define RTC_SET_CHARGE  	_IOW(PCF8563_MAGIC, 0x03, int) 		
+#  define RTC_MAX_IOCTL 3
 #endif
 
-
+#endif /* __RTC_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-cris/semaphore.h linux-2.4.20/include/asm-cris/semaphore.h
--- linux-2.4.19/include/asm-cris/semaphore.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.20/include/asm-cris/semaphore.h	2002-10-29 11:18:37.000000000 +0000
@@ -158,4 +158,9 @@
 	}
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return sem->count;
+}
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-cris/termios.h linux-2.4.20/include/asm-cris/termios.h
--- linux-2.4.19/include/asm-cris/termios.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-cris/termios.h	2002-10-29 11:18:33.000000000 +0000
@@ -38,6 +38,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
 /* line disciplines */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-cris/timex.h linux-2.4.20/include/asm-cris/timex.h
--- linux-2.4.19/include/asm-cris/timex.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-cris/timex.h	2002-10-29 11:18:36.000000000 +0000
@@ -42,4 +42,7 @@
         return 0;
 }
 
+#define vxtime_lock()		do {} while (0)
+#define vxtime_unlock()		do {} while (0)
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/apicdef.h linux-2.4.20/include/asm-i386/apicdef.h
--- linux-2.4.19/include/asm-i386/apicdef.h	2001-08-12 18:13:59.000000000 +0000
+++ linux-2.4.20/include/asm-i386/apicdef.h	2002-10-29 11:18:48.000000000 +0000
@@ -32,6 +32,7 @@
 #define			SET_APIC_LOGICAL_ID(x)	(((x)<<24))
 #define			APIC_ALL_CPUS		0xFF
 #define		APIC_DFR	0xE0
+#define			APIC_DFR_FLAT		0xFFFFFFFFul	/* Flat mode */
 #define		APIC_SPIV	0xF0
 #define			APIC_SPIV_FOCUS_DISABLED	(1<<9)
 #define			APIC_SPIV_APIC_ENABLED		(1<<8)
@@ -110,6 +111,11 @@
 #define MAX_IO_APICS 8
 
 /*
+ * The broadcast ID is 0xF for old APICs.
+ */
+#define APIC_BROADCAST_ID_APIC  (0x0F)
+
+/*
  * the local APIC register structure, memory mapped. Not terribly well
  * tested, but we might eventually use this one in the future - the
  * problem why we cannot use it right now is the P5 APIC, it has an
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/bitops.h linux-2.4.20/include/asm-i386/bitops.h
--- linux-2.4.19/include/asm-i386/bitops.h	2001-11-22 19:46:18.000000000 +0000
+++ linux-2.4.20/include/asm-i386/bitops.h	2002-10-29 11:18:49.000000000 +0000
@@ -347,7 +347,7 @@
 	__asm__("bsfl %1,%0\n\t"
 		"jnz 1f\n\t"
 		"movl $-1,%0\n"
-		"1:" : "=r" (r) : "g" (x));
+		"1:" : "=r" (r) : "rm" (x));
 	return r+1;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/fixmap.h linux-2.4.20/include/asm-i386/fixmap.h
--- linux-2.4.19/include/asm-i386/fixmap.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-i386/fixmap.h	2002-10-29 11:18:32.000000000 +0000
@@ -61,6 +61,9 @@
 	FIX_LI_PCIA,	/* Lithium PCI Bridge A */
 	FIX_LI_PCIB,	/* Lithium PCI Bridge B */
 #endif
+#ifndef CONFIG_X86_F00F_WORKS_OK
+	FIX_F00F,
+#endif
 #ifdef CONFIG_HIGHMEM
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings */
 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/io.h linux-2.4.20/include/asm-i386/io.h
--- linux-2.4.19/include/asm-i386/io.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-i386/io.h	2002-10-29 11:18:40.000000000 +0000
@@ -333,7 +333,7 @@
 #define __OUT2(s,s1,s2) \
 __asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
 
-#ifdef CONFIG_MULTIQUAD
+#if defined (CONFIG_MULTIQUAD) && !defined(STANDALONE)
 #define __OUTQ(s,ss,x)    /* Do the equivalent of the portio op on quads */ \
 static inline void out##ss(unsigned x value, unsigned short port) { \
 	if (xquad_portio) \
@@ -361,9 +361,9 @@
 	else\
 		return 0;\
 }
-#endif /* CONFIG_MULTIQUAD */
+#endif /* CONFIG_MULTIQUAD && !STANDALONE */
 
-#ifndef CONFIG_MULTIQUAD
+#if !defined(CONFIG_MULTIQUAD) || defined(STANDALONE)
 #define __OUT(s,s1,x) \
 __OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
 __OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} 
@@ -374,7 +374,7 @@
 __OUT1(s##_p_local,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
 __OUTQ(s,s,x) \
 __OUTQ(s,s##_p,x) 
-#endif /* CONFIG_MULTIQUAD */
+#endif /* !CONFIG_MULTIQUAD || STANDALONE */
 
 #define __IN1(s) \
 static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
@@ -382,7 +382,7 @@
 #define __IN2(s,s1,s2) \
 __asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
 
-#ifndef CONFIG_MULTIQUAD
+#if !defined(CONFIG_MULTIQUAD) || defined(STANDALONE)
 #define __IN(s,s1,i...) \
 __IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
 __IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } 
@@ -393,7 +393,7 @@
 __IN1(s##_p_local) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
 __INQ(s,s) \
 __INQ(s,s##_p) 
-#endif /* CONFIG_MULTIQUAD */
+#endif /* !CONFIG_MULTIQUAD || STANDALONE */
 
 #define __INS(s) \
 static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/kmap_types.h linux-2.4.20/include/asm-i386/kmap_types.h
--- linux-2.4.19/include/asm-i386/kmap_types.h	2001-09-17 20:16:30.000000000 +0000
+++ linux-2.4.20/include/asm-i386/kmap_types.h	2002-10-29 11:18:49.000000000 +0000
@@ -3,10 +3,11 @@
 
 enum km_type {
 	KM_BOUNCE_READ,
-	KM_SKB_DATA,
+	KM_SKB_SUNRPC_DATA,
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
+	KM_BH_IRQ,
 	KM_TYPE_NR
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/msr.h linux-2.4.20/include/asm-i386/msr.h
--- linux-2.4.19/include/asm-i386/msr.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-i386/msr.h	2002-10-29 11:18:31.000000000 +0000
@@ -54,6 +54,11 @@
 #define MSR_IA32_MCG_STATUS		0x17a
 #define MSR_IA32_MCG_CTL		0x17b
 
+#define MSR_IA32_THERM_CONTROL		0x19a
+#define MSR_IA32_THERM_INTERRUPT	0x19b
+#define MSR_IA32_THERM_STATUS		0x19c
+#define MSR_IA32_MISC_ENABLE		0x1a0
+
 #define MSR_IA32_DEBUGCTLMSR		0x1d9
 #define MSR_IA32_LASTBRANCHFROMIP	0x1db
 #define MSR_IA32_LASTBRANCHTOIP		0x1dc
@@ -75,12 +80,15 @@
 #define MSR_K6_STAR			0xC0000081
 #define MSR_K6_WHCR			0xC0000082
 #define MSR_K6_UWCCR			0xC0000085
+#define MSR_K6_EPMR			0xC0000086
 #define MSR_K6_PSOR			0xC0000087
 #define MSR_K6_PFIR			0xC0000088
 
 #define MSR_K7_EVNTSEL0			0xC0010000
 #define MSR_K7_PERFCTR0			0xC0010004
 #define MSR_K7_HWCR			0xC0010015
+#define MSR_K7_FID_VID_CTL		0xC0010041
+#define MSR_K7_VID_STATUS		0xC0010042
 
 /* Centaur-Hauls/IDT defined MSRs. */
 #define MSR_IDT_FCR1			0x107
@@ -100,5 +108,11 @@
 
 /* VIA Cyrix defined MSRs*/
 #define MSR_VIA_FCR			0x1107
+#define MSR_VIA_LONGHAUL		0x110a
+#define MSR_VIA_BCR2			0x1147
+
+/* Transmeta defined MSRs */
+#define MSR_TMTA_LONGRUN_CTRL		0x80868010
+#define MSR_TMTA_LONGRUN_FLAGS		0x80868011
 
 #endif /* __ASM_MSR_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/pgtable-2level.h linux-2.4.20/include/asm-i386/pgtable-2level.h
--- linux-2.4.19/include/asm-i386/pgtable-2level.h	2001-07-26 20:40:32.000000000 +0000
+++ linux-2.4.20/include/asm-i386/pgtable-2level.h	2002-10-29 11:18:31.000000000 +0000
@@ -40,6 +40,8 @@
  * hook is made available.
  */
 #define set_pte(pteptr, pteval) (*(pteptr) = pteval)
+#define set_pte_atomic(pteptr, pteval) (*(pteptr) = pteval)
+
 /*
  * (pmds are folded into pgds so this doesnt get actually called,
  * but the define is needed for a generic inline function.)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/pgtable-3level.h linux-2.4.20/include/asm-i386/pgtable-3level.h
--- linux-2.4.19/include/asm-i386/pgtable-3level.h	2001-07-26 20:40:32.000000000 +0000
+++ linux-2.4.20/include/asm-i386/pgtable-3level.h	2002-10-29 11:18:49.000000000 +0000
@@ -53,6 +53,9 @@
 		set_64bit((unsigned long long *)(pmdptr),pmd_val(pmdval))
 #define set_pgd(pgdptr,pgdval) \
 		set_64bit((unsigned long long *)(pgdptr),pgd_val(pgdval))
+#define set_pte_atomic(pteptr,pteval) \
+		set_64bit((unsigned long long *)(pteptr),pte_val(pteval))
+
 
 /*
  * Pentium-II erratum A13: in PAE mode we explicitly have to flush
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/pgtable.h linux-2.4.20/include/asm-i386/pgtable.h
--- linux-2.4.19/include/asm-i386/pgtable.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-i386/pgtable.h	2002-10-29 11:18:49.000000000 +0000
@@ -82,11 +82,19 @@
 	} while (0)
 #endif
 
-#ifndef CONFIG_X86_INVLPG
-#define __flush_tlb_one(addr) __flush_tlb()
+#define __flush_tlb_single(addr) \
+	__asm__ __volatile__("invlpg %0": :"m" (*(char *) addr))
+
+#ifdef CONFIG_X86_INVLPG
+# define __flush_tlb_one(addr) __flush_tlb_single(addr)
 #else
-#define __flush_tlb_one(addr) \
-__asm__ __volatile__("invlpg %0": :"m" (*(char *) addr))
+# define __flush_tlb_one(addr)						\
+	do {								\
+		if (cpu_has_pge)					\
+			__flush_tlb_single(addr);			\
+		else							\
+			__flush_tlb();					\
+	} while (0)
 #endif
 
 /*
@@ -347,6 +355,9 @@
 #define pte_to_swp_entry(pte)		((swp_entry_t) { (pte).pte_low })
 #define swp_entry_to_pte(x)		((pte_t) { (x).val })
 
+struct page;
+int change_page_attr(struct page *, int, pgprot_t prot);
+
 #endif /* !__ASSEMBLY__ */
 
 /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/rwsem.h linux-2.4.20/include/asm-i386/rwsem.h
--- linux-2.4.19/include/asm-i386/rwsem.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-i386/rwsem.h	2002-10-29 11:18:39.000000000 +0000
@@ -4,6 +4,8 @@
  *
  * Derived from asm-i386/semaphore.h
  *
+ * Trylock by Brian Watson (Brian.J.Watson@compaq.com).
+ *
  *
  * The MSW of the count is the negated number of active writers and waiting
  * lockers, and the LSW is the total number of active locks
@@ -117,6 +119,29 @@
 }
 
 /*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	__s32 result, tmp;
+	__asm__ __volatile__(
+		"# beginning __down_read_trylock\n\t"
+		"  movl      %0,%1\n\t"
+		"1:\n\t"
+		"  movl	     %1,%2\n\t"
+		"  addl      %3,%2\n\t"
+		"  jle	     2f\n\t"
+LOCK_PREFIX	"  cmpxchgl  %2,%0\n\t"
+		"  jnz	     1b\n\t"
+		"2:\n\t"
+		"# ending __down_read_trylock\n\t"
+		: "+m"(sem->count), "=&a"(result), "=&r"(tmp)
+		: "i"(RWSEM_ACTIVE_READ_BIAS)
+		: "memory", "cc");
+	return result>=0 ? 1 : 0;
+}
+
+/*
  * lock for writing
  */
 static inline void __down_write(struct rw_semaphore *sem)
@@ -144,6 +169,19 @@
 }
 
 /*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	signed long ret = cmpxchg(&sem->count,
+				  RWSEM_UNLOCKED_VALUE, 
+				  RWSEM_ACTIVE_WRITE_BIAS);
+	if (ret == RWSEM_UNLOCKED_VALUE)
+		return 1;
+	return 0;
+}
+
+/*
  * unlock after reading
  */
 static inline void __up_read(struct rw_semaphore *sem)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/scatterlist.h linux-2.4.20/include/asm-i386/scatterlist.h
--- linux-2.4.19/include/asm-i386/scatterlist.h	2001-10-12 22:35:54.000000000 +0000
+++ linux-2.4.20/include/asm-i386/scatterlist.h	2002-10-29 11:18:40.000000000 +0000
@@ -1,6 +1,24 @@
 #ifndef _I386_SCATTERLIST_H
 #define _I386_SCATTERLIST_H
 
+/*
+ * Drivers must set either ->address or (preferred) ->page and ->offset
+ * to indicate where data must be transferred to/from.
+ *
+ * Using ->page is recommended since it handles highmem data as well as
+ * low mem. ->address is restricted to data which has a virtual mapping, and
+ * it will go away in the future. Updating to ->page can be automated very
+ * easily -- something like
+ *
+ * sg->address = some_ptr;
+ *
+ * can be rewritten as
+ *
+ * sg->page = virt_to_page(some_ptr);
+ * sg->offset = (unsigned long) some_ptr & ~PAGE_MASK;
+ *
+ * and that's it. There's no excuse for not highmem enabling YOUR driver. /jens
+ */
 struct scatterlist {
     char *  address;    /* Location data is to be transferred to, NULL for
 			 * highmem page */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/semaphore.h linux-2.4.20/include/asm-i386/semaphore.h
--- linux-2.4.19/include/asm-i386/semaphore.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-i386/semaphore.h	2002-10-29 11:18:35.000000000 +0000
@@ -213,5 +213,10 @@
 		:"memory");
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/smp.h linux-2.4.20/include/asm-i386/smp.h
--- linux-2.4.19/include/asm-i386/smp.h	2001-12-21 17:42:03.000000000 +0000
+++ linux-2.4.20/include/asm-i386/smp.h	2002-10-29 11:18:32.000000000 +0000
@@ -23,29 +23,6 @@
 #endif
 
 #ifdef CONFIG_SMP
-# ifdef CONFIG_MULTIQUAD
-#  define TARGET_CPUS 0xf     /* all CPUs in *THIS* quad */
-#  define INT_DELIVERY_MODE 0     /* physical delivery on LOCAL quad */
-# else
-#  define TARGET_CPUS cpu_online_map
-#  define INT_DELIVERY_MODE 1     /* logical delivery broadcast to all procs */
-# endif
-#else
-# define INT_DELIVERY_MODE 1     /* logical delivery */
-# define TARGET_CPUS 0x01
-#endif
-
-#ifndef clustered_apic_mode
- #ifdef CONFIG_MULTIQUAD
-  #define clustered_apic_mode (1)
-  #define esr_disable (1)
- #else /* !CONFIG_MULTIQUAD */
-  #define clustered_apic_mode (0)
-  #define esr_disable (0)
- #endif /* CONFIG_MULTIQUAD */
-#endif 
-
-#ifdef CONFIG_SMP
 #ifndef __ASSEMBLY__
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/smpboot.h linux-2.4.20/include/asm-i386/smpboot.h
--- linux-2.4.19/include/asm-i386/smpboot.h	2001-11-22 19:48:46.000000000 +0000
+++ linux-2.4.20/include/asm-i386/smpboot.h	2002-10-29 11:18:38.000000000 +0000
@@ -1,36 +1,62 @@
 #ifndef __ASM_SMPBOOT_H
 #define __ASM_SMPBOOT_H
 
-#ifndef clustered_apic_mode
- #ifdef CONFIG_MULTIQUAD
-  #define clustered_apic_mode (1)
- #else /* !CONFIG_MULTIQUAD */
-  #define clustered_apic_mode (0)
- #endif /* CONFIG_MULTIQUAD */
-#endif 
- 
-#ifdef CONFIG_MULTIQUAD
- #define TRAMPOLINE_LOW phys_to_virt(0x8)
- #define TRAMPOLINE_HIGH phys_to_virt(0xa)
-#else /* !CONFIG_MULTIQUAD */
- #define TRAMPOLINE_LOW phys_to_virt(0x467)
- #define TRAMPOLINE_HIGH phys_to_virt(0x469)
-#endif /* CONFIG_MULTIQUAD */
+/*emum for clustered_apic_mode values*/
+enum{
+	CLUSTERED_APIC_NONE = 0,
+	CLUSTERED_APIC_XAPIC,
+	CLUSTERED_APIC_NUMAQ
+};
 
 #ifdef CONFIG_MULTIQUAD
- #define boot_cpu_apicid boot_cpu_logical_apicid
+ #define clustered_apic_mode (CLUSTERED_APIC_NUMAQ)
 #else /* !CONFIG_MULTIQUAD */
- #define boot_cpu_apicid boot_cpu_physical_apicid
+ #define clustered_apic_mode (CLUSTERED_APIC_NONE)
 #endif /* CONFIG_MULTIQUAD */
 
+#ifdef CONFIG_X86_LOCAL_APIC
+extern unsigned char esr_disable;
+static inline int target_cpus(void)
+{
+	switch(clustered_apic_mode){
+		case CLUSTERED_APIC_NUMAQ:
+			/* Broadcast intrs to local quad only. */
+			return APIC_BROADCAST_ID_APIC;
+		default:
+	}
+	return cpu_online_map;
+}
+#ifdef CONFIG_X86_IO_APIC
+extern unsigned char int_delivery_mode;
+extern unsigned int int_dest_addr_mode;
+#define	INT_DEST_ADDR_MODE (int_dest_addr_mode)
+#define	INT_DELIVERY_MODE (int_delivery_mode)
+#endif /* CONFIG_X86_IO_APIC */
+#else /* CONFIG_X86_LOCAL_APIC */
+#define esr_disable (0)
+#define target_cpus() (0x01)
+#ifdef CONFIG_X86_IO_APIC
+#define INT_DEST_ADDR_MODE (APIC_DEST_LOGICAL)	/* logical delivery */
+#define INT_DELIVERY_MODE (dest_LowestPrio)
+#endif /* CONFIG_X86_IO_APIC */
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+#define TRAMPOLINE_LOW phys_to_virt((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?0x8:0x467)
+#define TRAMPOLINE_HIGH phys_to_virt((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?0xa:0x469)
+
+#define boot_cpu_apicid ((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?boot_cpu_logical_apicid:boot_cpu_physical_apicid)
+
 /*
  * How to map from the cpu_present_map
  */
-#ifdef CONFIG_MULTIQUAD
- #define cpu_present_to_apicid(mps_cpu) ( ((mps_cpu/4)*16) + (1<<(mps_cpu%4)) )
-#else /* !CONFIG_MULTIQUAD */
- #define cpu_present_to_apicid(apicid) (apicid)
-#endif /* CONFIG_MULTIQUAD */
+static inline int cpu_present_to_apicid(int mps_cpu)
+{
+	if(clustered_apic_mode == CLUSTERED_APIC_NUMAQ)
+		return (mps_cpu/4)*16 + (1<<(mps_cpu%4));
+	return mps_cpu;
+}
+
+#define physical_to_logical_apicid(phys_apic) ( (1ul << (phys_apic & 0x3)) | (phys_apic & 0xF0u) )
 
 /*
  * Mappings between logical cpu number and logical / physical apicid
@@ -53,10 +79,4 @@
 #define cpu_to_boot_apicid(cpu) cpu_2_physical_apicid[cpu]
 #endif /* CONFIG_MULTIQUAD */
 
-
-#ifdef CONFIG_MULTIQUAD
-#else /* !CONFIG_MULTIQUAD */
-#endif /* CONFIG_MULTIQUAD */
-
-
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/socket.h linux-2.4.20/include/asm-i386/socket.h
--- linux-2.4.19/include/asm-i386/socket.h	2001-06-21 04:00:55.000000000 +0000
+++ linux-2.4.20/include/asm-i386/socket.h	2002-10-29 11:18:33.000000000 +0000
@@ -3,7 +3,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	1
 
 #define SO_DEBUG	1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/spinlock.h linux-2.4.20/include/asm-i386/spinlock.h
--- linux-2.4.19/include/asm-i386/spinlock.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-i386/spinlock.h	2002-10-29 11:18:34.000000000 +0000
@@ -49,7 +49,7 @@
  * We make no fairness assumptions. They have a cost.
  */
 
-#define spin_is_locked(x)	(*(volatile char *)(&(x)->lock) <= 0)
+#define spin_is_locked(x)	(*(volatile signed char *)(&(x)->lock) <= 0)
 #define spin_unlock_wait(x)	do { barrier(); } while(spin_is_locked(x))
 
 #define spin_lock_string \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/system.h linux-2.4.20/include/asm-i386/system.h
--- linux-2.4.19/include/asm-i386/system.h	2001-11-22 19:46:18.000000000 +0000
+++ linux-2.4.20/include/asm-i386/system.h	2002-10-29 11:18:31.000000000 +0000
@@ -154,6 +154,11 @@
  * to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that
  * might have an implicit FPU-save as a cost, so it's not
  * clear which path to go.)
+ *
+ * chmxchg8b must be used with the lock prefix here to allow
+ * the instruction to be executed atomically, see page 3-102
+ * of the instruction set reference 24319102.pdf. We need
+ * the reader side to see the coherent 64bit value.
  */
 static inline void __set_64bit (unsigned long long * ptr,
 		unsigned int low, unsigned int high)
@@ -162,7 +167,7 @@
 		"\n1:\t"
 		"movl (%0), %%eax\n\t"
 		"movl 4(%0), %%edx\n\t"
-		"cmpxchg8b (%0)\n\t"
+		"lock cmpxchg8b (%0)\n\t"
 		"jnz 1b"
 		: /* no outputs */
 		:	"D"(ptr),
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/termios.h linux-2.4.20/include/asm-i386/termios.h
--- linux-2.4.19/include/asm-i386/termios.h	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.20/include/asm-i386/termios.h	2002-10-29 11:18:30.000000000 +0000
@@ -37,6 +37,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
 /* line disciplines */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/timex.h linux-2.4.20/include/asm-i386/timex.h
--- linux-2.4.19/include/asm-i386/timex.h	2002-02-25 19:38:12.000000000 +0000
+++ linux-2.4.20/include/asm-i386/timex.h	2002-10-29 11:18:36.000000000 +0000
@@ -52,4 +52,7 @@
 
 extern unsigned long cpu_khz;
 
+#define vxtime_lock()		do {} while (0)
+#define vxtime_unlock()		do {} while (0)
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-i386/unistd.h linux-2.4.20/include/asm-i386/unistd.h
--- linux-2.4.19/include/asm-i386/unistd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-i386/unistd.h	2002-10-29 11:18:49.000000000 +0000
@@ -247,6 +247,16 @@
 #define __NR_futex		240
 #define __NR_sched_setaffinity	241
 #define __NR_sched_getaffinity	242
+#define __NR_set_thread_area	243
+#define __NR_get_thread_area	244
+#define __NR_io_setup		245
+#define __NR_io_destroy		246
+#define __NR_io_getevents	247
+#define __NR_io_submit		248
+#define __NR_io_cancel		249
+#define __NR_alloc_hugepages	250
+#define __NR_free_hugepages	251
+#define __NR_exit_group		252
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/acpi-ext.h linux-2.4.20/include/asm-ia64/acpi-ext.h
--- linux-2.4.19/include/asm-ia64/acpi-ext.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/acpi-ext.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,323 +0,0 @@
-#ifndef _ASM_IA64_ACPI_EXT_H
-#define _ASM_IA64_ACPI_EXT_H
-
-/*
- * Advanced Configuration and Power Infterface
- * Based on 'ACPI Specification 1.0b' Febryary 2, 1999
- * and 'IA-64 Extensions to the ACPI Specification' Rev 0.6
- *
- * Copyright (C) 1999 VA Linux Systems
- * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 2000 Intel Corp.
- * Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@intel.com>
- *	ACPI 2.0 specification
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-
-#pragma	pack(1)
-#define ACPI_RSDP_SIG "RSD PTR " /* Trailing space required */
-#define ACPI_RSDP_SIG_LEN 8
-typedef struct {
-	char signature[8];
-	u8 checksum;
-	char oem_id[6];
-	u8 revision;
-	u32 rsdt;
-	u32 length;
-	struct acpi_xsdt *xsdt;
-	u8 ext_checksum;
-	u8 reserved[3];
-} acpi20_rsdp_t;
-
-typedef struct {
-	char signature[4];
-	u32 length;
-	u8 revision;
-	u8 checksum;
-	char oem_id[6];
-	char oem_table_id[8];
-	u32 oem_revision;
-	u32 creator_id;
-	u32 creator_revision;
-} acpi_desc_table_hdr_t;
-
-#define ACPI_RSDT_SIG "RSDT"
-#define ACPI_RSDT_SIG_LEN 4
-typedef struct {
-	acpi_desc_table_hdr_t header;
-	u8 reserved[4];
-	u32 entry_ptrs[1];	/* Not really . . . */
-} acpi20_rsdt_t;
-
-#define ACPI_XSDT_SIG "XSDT"
-#define ACPI_XSDT_SIG_LEN 4
-typedef struct acpi_xsdt {
-	acpi_desc_table_hdr_t header;
-	unsigned long entry_ptrs[1];	/* Not really . . . */
-} acpi_xsdt_t;
-
-/* Common structures for ACPI 2.0 and 0.71 */
-
-typedef struct acpi_entry_iosapic {
-	u8 type;
-	u8 length;
-	u8 id;
-	u8 reserved;
-	u32 irq_base;	/* start of IRQ's this IOSAPIC is responsible for. */
-	unsigned long address;	/* Address of this IOSAPIC */
-} acpi_entry_iosapic_t;
-
-/* Local SAPIC flags */
-#define LSAPIC_ENABLED                (1<<0)
-#define LSAPIC_PERFORMANCE_RESTRICTED (1<<1)
-#define LSAPIC_PRESENT                (1<<2)
-
-/* Defines legacy IRQ->pin mapping */
-typedef struct {
-	u8 type;
-	u8 length;
-	u8 bus;		/* Constant 0 == ISA */
-	u8 isa_irq;	/* ISA IRQ # */
-	u32 pin;		/* called vector in spec; really IOSAPIC pin number */
-	u16 flags;	/* Edge/Level trigger & High/Low active */
-} acpi_entry_int_override_t;
-
-#define INT_OVERRIDE_ACTIVE_LOW    0x03
-#define INT_OVERRIDE_LEVEL_TRIGGER 0x0d
-
-/* IA64 ext 0.71 */
-
-typedef struct {
-	char signature[8];
-	u8 checksum;
-	char oem_id[6];
-	char reserved;		/* Must be 0 */
-	struct acpi_rsdt *rsdt;
-} acpi_rsdp_t;
-
-typedef struct acpi_rsdt {
-	acpi_desc_table_hdr_t header;
-	u8 reserved[4];
-	unsigned long entry_ptrs[1];	/* Not really . . . */
-} acpi_rsdt_t;
-
-#define ACPI_SAPIC_SIG "SPIC"
-#define ACPI_SAPIC_SIG_LEN 4
-typedef struct {
-	acpi_desc_table_hdr_t header;
-	u8 reserved[4];
-	unsigned long interrupt_block;
-} acpi_sapic_t;
-
-/* SAPIC structure types */
-#define ACPI_ENTRY_LOCAL_SAPIC         0
-#define ACPI_ENTRY_IO_SAPIC            1
-#define ACPI_ENTRY_INT_SRC_OVERRIDE    2
-#define ACPI_ENTRY_PLATFORM_INT_SOURCE 3	/* Unimplemented */
-
-typedef struct acpi_entry_lsapic {
-	u8 type;
-	u8 length;
-	u16 acpi_processor_id;
-	u16 flags;
-	u8 id;
-	u8 eid;
-} acpi_entry_lsapic_t;
-
-typedef struct {
-	u8 type;
-	u8 length;
-	u16 flags;
-	u8 int_type;
-	u8 id;
-	u8 eid;
-	u8 iosapic_vector;
-	u8 reserved[4];
-	u32 global_vector;
-} acpi_entry_platform_src_t;
-
-/* ACPI 2.0 with 1.3 errata specific structures */
-
-#define ACPI_MADT_SIG "APIC"
-#define ACPI_MADT_SIG_LEN 4
-typedef struct {
-	acpi_desc_table_hdr_t header;
-	u32 lapic_address;
-	u32 flags;
-} acpi_madt_t;
-
-/* acpi 2.0 MADT flags */
-#define MADT_PCAT_COMPAT	(1<<0)
-
-/* acpi 2.0 MADT structure types */
-#define ACPI20_ENTRY_LOCAL_APIC			0
-#define ACPI20_ENTRY_IO_APIC			1
-#define ACPI20_ENTRY_INT_SRC_OVERRIDE		2
-#define ACPI20_ENTRY_NMI_SOURCE			3
-#define ACPI20_ENTRY_LOCAL_APIC_NMI		4
-#define ACPI20_ENTRY_LOCAL_APIC_ADDR_OVERRIDE	5
-#define ACPI20_ENTRY_IO_SAPIC			6
-#define ACPI20_ENTRY_LOCAL_SAPIC		7
-#define ACPI20_ENTRY_PLATFORM_INT_SOURCE	8
-
-typedef struct acpi20_entry_lsapic {
-	u8 type;
-	u8 length;
-	u8 acpi_processor_id;
-	u8 id;
-	u8 eid;
-	u8 reserved[3];
-	u32 flags;
-} acpi20_entry_lsapic_t;
-
-typedef struct acpi20_entry_lapic_addr_override {
-	u8 type;
-	u8 length;
-	u8 reserved[2];
-	unsigned long lapic_address;
-} acpi20_entry_lapic_addr_override_t;
-
-typedef struct {
-	u8 type;
-	u8 length;
-	u16 flags;
-	u8 int_type;
-	u8 id;
-	u8 eid;
-	u8 iosapic_vector;
-	u32 global_vector;
-} acpi20_entry_platform_src_t;
-
-/* constants for interrupt routing API for device drivers */
-#define ACPI20_ENTRY_PIS_PMI	1
-#define ACPI20_ENTRY_PIS_INIT	2
-#define ACPI20_ENTRY_PIS_CPEI	3
-#define ACPI_MAX_PLATFORM_IRQS	4
-
-#define ACPI_SPCRT_SIG	"SPCR"
-#define ACPI_SPCRT_SIG_LEN 4
-
-#define ACPI_DBGPT_SIG	"DBGP"
-#define ACPI_DBGPT_SIG_LEN 4
-
-extern int acpi20_parse(acpi20_rsdp_t *);
-extern int acpi20_early_parse(acpi20_rsdp_t *);
-extern int acpi_parse(acpi_rsdp_t *);
-extern const char *acpi_get_sysname (void);
-extern int acpi_request_vector(u32 int_type);
-extern void (*acpi_idle) (void);	/* power-management idle function, if any */
-#ifdef CONFIG_NUMA
-extern cnodeid_t paddr_to_nid(unsigned long paddr);
-#endif
-
-/*
- * ACPI 2.0 SRAT Table
- * http://www.microsoft.com/HWDEV/design/SRAT.htm
- */
-
-typedef struct acpi_srat {
-	acpi_desc_table_hdr_t header;
-	u32 table_revision;
-	u64 reserved;
-} acpi_srat_t;
-
-typedef struct srat_cpu_affinity {
-	u8 type;
-	u8 length;
-	u8 proximity_domain;
-	u8 apic_id;
-	u32 flags;
-	u8 local_sapic_eid;
-	u8 reserved[7];
-} srat_cpu_affinity_t;
-
-typedef struct srat_memory_affinity {
-	u8 type;
-	u8 length;
-	u8 proximity_domain;
-	u8 reserved[5];
-	u32 base_addr_lo;
-	u32 base_addr_hi;
-	u32 length_lo;
-	u32 length_hi;
-	u32 memory_type;
-	u32 flags;
-	u64 reserved2;
-} srat_memory_affinity_t;
-
-/* ACPI 2.0 SRAT structure */
-#define ACPI_SRAT_SIG "SRAT"
-#define ACPI_SRAT_SIG_LEN 4
-#define ACPI_SRAT_REVISION 1
-
-#define SRAT_CPU_STRUCTURE		0
-#define SRAT_MEMORY_STRUCTURE		1
-
-/* Only 1 flag for cpu affinity structure! */
-#define SRAT_CPU_FLAGS_ENABLED			0x00000001
-
-#define SRAT_MEMORY_FLAGS_ENABLED		0x00000001
-#define SRAT_MEMORY_FLAGS_HOTREMOVABLE		0x00000002
-
-/* ACPI 2.0 address range types */
-#define ACPI_ADDRESS_RANGE_MEMORY	1
-#define ACPI_ADDRESS_RANGE_RESERVED	2
-#define ACPI_ADDRESS_RANGE_ACPI		3
-#define ACPI_ADDRESS_RANGE_NVS		4
-
-#define NODE_ARRAY_INDEX(x)	((x) / 8)	/* 8 bits/char */
-#define NODE_ARRAY_OFFSET(x)	((x) % 8)	/* 8 bits/char */
-#define MAX_PXM_DOMAINS		(256)
-
-#ifdef CONFIG_DISCONTIGMEM
-/*
- * List of node memory chunks. Filled when parsing SRAT table to
- * obtain information about memory nodes.
-*/
-
-struct node_memory_chunk_s {
-	unsigned long start_paddr;
-	unsigned long size;
-	int pxm;			// proximity domain of node
-	int nid;			// which cnode contains this chunk?
-	int bank;			// which mem bank on this node
-};
-
-extern struct node_memory_chunk_s node_memory_chunk[PLAT_MAXCLUMPS];	// temporary?
-
-struct node_cpuid_s {
-	u16	phys_id;		/* id << 8 | eid */
-	int	pxm;			// proximity domain of cpu
-	int	nid;
-};
-extern struct node_cpuid_s node_cpuid[NR_CPUS];
-
-extern int pxm_to_nid_map[MAX_PXM_DOMAINS]; /* _PXM to logical node ID map */
-extern int nid_to_pxm_map[PLAT_MAX_COMPACT_NODES]; /* logical node ID to _PXM map */
-extern int numnodes;			/* total number of nodes in system */
-extern int num_memory_chunks;		/* total number of memory chunks */
-
-/*
- * ACPI 2.0 SLIT Table
- * http://devresource.hp.com/devresource/Docs/TechPapers/IA64/slit.pdf
- */
-
-typedef struct acpi_slit {
-	acpi_desc_table_hdr_t header;
-	u64 localities;
-	u8 entries[1];			/* dummy, real size = locality^2 */
-} acpi_slit_t;
-
-extern u8 acpi20_slit[PLAT_MAX_COMPACT_NODES * PLAT_MAX_COMPACT_NODES];
-
-#define ACPI_SLIT_SIG "SLIT"
-#define ACPI_SLIT_SIG_LEN 4
-#define ACPI_SLIT_REVISION 1
-#define ACPI_SLIT_LOCAL 10
-#endif /* CONFIG_DISCONTIGMEM */
-
-#pragma	pack()
-#endif /* _ASM_IA64_ACPI_EXT_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/acpi.h linux-2.4.20/include/asm-ia64/acpi.h
--- linux-2.4.19/include/asm-ia64/acpi.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/acpi.h	2002-10-29 11:18:38.000000000 +0000
@@ -0,0 +1,114 @@
+/*
+ *  asm-ia64/acpi.h
+ *
+ *  Copyright (C) 1999 VA Linux Systems
+ *  Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+ *  Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@intel.com>
+ *  Copyright (C) 2001,2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#ifndef _ASM_ACPI_H
+#define _ASM_ACPI_H
+
+#ifdef __KERNEL__
+
+#define COMPILER_DEPENDENT_INT64	long
+#define COMPILER_DEPENDENT_UINT64	unsigned long
+
+/*
+ * Calling conventions:
+ *
+ * ACPI_SYSTEM_XFACE        - Interfaces to host OS (handlers, threads)
+ * ACPI_EXTERNAL_XFACE      - External ACPI interfaces
+ * ACPI_INTERNAL_XFACE      - Internal ACPI interfaces
+ * ACPI_INTERNAL_VAR_XFACE  - Internal variable-parameter list interfaces
+ */
+#define ACPI_SYSTEM_XFACE
+#define ACPI_EXTERNAL_XFACE
+#define ACPI_INTERNAL_XFACE
+#define ACPI_INTERNAL_VAR_XFACE
+
+/* Asm macros */
+
+#define ACPI_ASM_MACROS
+#define BREAKPOINT3
+#define ACPI_DISABLE_IRQS() __cli()
+#define ACPI_ENABLE_IRQS()  __sti()
+#define ACPI_FLUSH_CPU_CACHE()
+
+#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
+	do { \
+	__asm__ volatile ("1:  ld4      r29=%1\n"  \
+		";;\n"                  \
+		"mov    ar.ccv=r29\n"   \
+		"mov    r2=r29\n"       \
+		"shr.u  r30=r29,1\n"    \
+		"and    r29=-4,r29\n"   \
+		";;\n"                  \
+		"add    r29=2,r29\n"    \
+		"and    r30=1,r30\n"    \
+		";;\n"                  \
+		"add    r29=r29,r30\n"  \
+		";;\n"                  \
+		"cmpxchg4.acq   r30=%1,r29,ar.ccv\n" \
+		";;\n"                  \
+		"cmp.eq p6,p7=r2,r30\n" \
+		"(p7) br.dpnt.few 1b\n" \
+		"cmp.gt p8,p9=3,r29\n"  \
+		";;\n"                  \
+		"(p8) mov %0=-1\n"      \
+		"(p9) mov %0=r0\n"      \
+		:"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \
+	} while (0)
+
+#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
+	do { \
+	__asm__ volatile ("1:  ld4      r29=%1\n" \
+		";;\n"                  \
+		"mov    ar.ccv=r29\n"   \
+		"mov    r2=r29\n"       \
+		"and    r29=-4,r29\n"   \
+		";;\n"                  \
+		"cmpxchg4.acq   r30=%1,r29,ar.ccv\n" \
+		";;\n"                  \
+		"cmp.eq p6,p7=r2,r30\n" \
+		"(p7) br.dpnt.few 1b\n" \
+		"and    %0=1,r2\n"      \
+		";;\n"                  \
+		:"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \
+	} while (0)
+
+const char *acpi_get_sysname (void);
+int acpi_boot_init (char *cdline);
+int acpi_request_vector (u32 int_type);
+int acpi_get_prt (struct pci_vector_struct **vectors, int *count);
+int acpi_get_interrupt_model (int *type);
+int acpi_irq_to_vector (u32 irq);
+
+#ifdef CONFIG_DISCONTIGMEM
+#define NODE_ARRAY_INDEX(x)	((x) / 8)	/* 8 bits/char */
+#define NODE_ARRAY_OFFSET(x)	((x) % 8)	/* 8 bits/char */
+#define MAX_PXM_DOMAINS		(256)
+#endif /* CONFIG_DISCONTIGMEM */
+
+#endif /*__KERNEL__*/
+
+#endif /*_ASM_ACPI_H*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/acpikcfg.h linux-2.4.20/include/asm-ia64/acpikcfg.h
--- linux-2.4.19/include/asm-ia64/acpikcfg.h	2001-07-31 17:30:09.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/acpikcfg.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,30 +0,0 @@
-#ifndef _ASM_IA64_ACPIKCFG_H
-#define _ASM_IA64_ACPIKCFG_H
-
-/*
- *  acpikcfg.h - ACPI based Kernel Configuration Manager External Interfaces
- *
- *  Copyright (C) 2000 Intel Corp.
- *  Copyright (C) 2000 J.I. Lee  <jung-ik.lee@intel.com>
- */
-
-
-u32	__init acpi_cf_init (void * rsdp);
-u32	__init acpi_cf_terminate (void );
-
-u32	__init
-acpi_cf_get_pci_vectors (
-	struct pci_vector_struct	**vectors,
-	int				*num_pci_vectors
-	);
-
-
-#ifdef	CONFIG_ACPI_KERNEL_CONFIG_DEBUG
-void	__init
-acpi_cf_print_pci_vectors (
-	struct pci_vector_struct	*vectors,
-	int				num_pci_vectors
-	);
-#endif
-
-#endif /* _ASM_IA64_ACPIKCFG_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/atomic.h linux-2.4.20/include/asm-ia64/atomic.h
--- linux-2.4.19/include/asm-ia64/atomic.h	2001-07-10 04:30:19.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/atomic.h	2002-10-29 11:18:34.000000000 +0000
@@ -9,8 +9,8 @@
  * "int" types were carefully placed so as to ensure proper operation
  * of the macros.
  *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998, 1999, 2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #include <linux/types.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/bitops.h linux-2.4.20/include/asm-ia64/bitops.h
--- linux-2.4.19/include/asm-ia64/bitops.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/bitops.h	2002-10-29 11:18:49.000000000 +0000
@@ -325,7 +325,7 @@
 /*
  * Find next zero bit in a bitmap reasonably efficiently..
  */
-static inline int
+static inline unsigned long
 find_next_zero_bit (void *addr, unsigned long size, unsigned long offset)
 {
 	unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/cache.h linux-2.4.20/include/asm-ia64/cache.h
--- linux-2.4.19/include/asm-ia64/cache.h	2001-04-05 19:51:47.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/cache.h	2002-10-29 11:18:40.000000000 +0000
@@ -5,7 +5,7 @@
 
 /*
  * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 /* Bytes per L1 (data) cache line.  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/current.h linux-2.4.20/include/asm-ia64/current.h
--- linux-2.4.19/include/asm-ia64/current.h	2000-04-21 22:21:24.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/current.h	2002-10-29 11:18:35.000000000 +0000
@@ -3,7 +3,7 @@
 
 /*
  * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 /* In kernel mode, thread pointer (r13) is used to point to the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/efi.h linux-2.4.20/include/asm-ia64/efi.h
--- linux-2.4.19/include/asm-ia64/efi.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/efi.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,262 +0,0 @@
-#ifndef _ASM_IA64_EFI_H
-#define _ASM_IA64_EFI_H
-
-/*
- * Extensible Firmware Interface
- * Based on 'Extensible Firmware Interface Specification' version 0.9, April 30, 1999
- *
- * Copyright (C) 1999 VA Linux Systems
- * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 1999 Hewlett-Packard Co.
- * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
- */
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/time.h>
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-
-#include <asm/page.h>
-#include <asm/system.h>
-
-#define EFI_SUCCESS		0
-#define EFI_LOAD_ERROR          (1L | (1L << 63))
-#define EFI_INVALID_PARAMETER	(2L | (1L << 63))
-#define EFI_UNSUPPORTED		(3L | (1L << 63))
-#define EFI_BAD_BUFFER_SIZE     (4L | (1L << 63))
-#define EFI_BUFFER_TOO_SMALL	(5L | (1L << 63))
-#define EFI_NOT_FOUND          (14L | (1L << 63))
-
-typedef unsigned long efi_status_t;
-typedef u8 efi_bool_t;
-typedef u16 efi_char16_t;		/* UNICODE character */
-
-typedef struct {
-	u32 data1;
-	u16 data2;
-	u16 data3;
-	u8 data4[8];
-} efi_guid_t;
-
-/*
- * Generic EFI table header
- */
-typedef	struct {
-	u64 signature;
-	u32 revision;
-	u32 headersize;
-	u32 crc32;
-	u32 reserved;
-} efi_table_hdr_t;
-
-/*
- * Memory map descriptor:
- */
-
-/* Memory types: */
-#define EFI_RESERVED_TYPE		 0
-#define EFI_LOADER_CODE			 1
-#define EFI_LOADER_DATA			 2
-#define EFI_BOOT_SERVICES_CODE		 3
-#define EFI_BOOT_SERVICES_DATA		 4
-#define EFI_RUNTIME_SERVICES_CODE	 5
-#define EFI_RUNTIME_SERVICES_DATA	 6
-#define EFI_CONVENTIONAL_MEMORY		 7
-#define EFI_UNUSABLE_MEMORY		 8
-#define EFI_ACPI_RECLAIM_MEMORY		 9
-#define EFI_ACPI_MEMORY_NVS		10
-#define EFI_MEMORY_MAPPED_IO		11
-#define EFI_MEMORY_MAPPED_IO_PORT_SPACE	12
-#define EFI_PAL_CODE			13
-#define EFI_MAX_MEMORY_TYPE		14
-
-/* Attribute values: */
-#define EFI_MEMORY_UC		0x0000000000000001	/* uncached */
-#define EFI_MEMORY_WC		0x0000000000000002	/* write-coalescing */
-#define EFI_MEMORY_WT		0x0000000000000004	/* write-through */
-#define EFI_MEMORY_WB		0x0000000000000008	/* write-back */
-#define EFI_MEMORY_WP		0x0000000000001000	/* write-protect */
-#define EFI_MEMORY_RP		0x0000000000002000	/* read-protect */
-#define EFI_MEMORY_XP		0x0000000000004000	/* execute-protect */
-#define EFI_MEMORY_RUNTIME	0x8000000000000000	/* range requires runtime mapping */
-#define EFI_MEMORY_DESCRIPTOR_VERSION	1
-
-typedef struct {
-	u32 type;
-	u32 pad;
-	u64 phys_addr;
-	u64 virt_addr;
-	u64 num_pages;
-	u64 attribute;
-} efi_memory_desc_t;
-
-typedef int efi_freemem_callback_t (u64 start, u64 end, void *arg);
-
-/*
- * Types and defines for Time Services
- */
-#define EFI_TIME_ADJUST_DAYLIGHT 0x1
-#define EFI_TIME_IN_DAYLIGHT     0x2
-#define EFI_UNSPECIFIED_TIMEZONE 0x07ff
-
-typedef struct {
-	u16 year;
-	u8 month;
-	u8 day;
-	u8 hour;
-	u8 minute;
-	u8 second;
-	u8 pad1;
-	u32 nanosecond;
-	s16 timezone;
-	u8 daylight;
-	u8 pad2;
-} efi_time_t;
-
-typedef struct {
-	u32 resolution;
-	u32 accuracy;
-	u8 sets_to_zero;
-} efi_time_cap_t;
-
-/*
- * Types and defines for EFI ResetSystem
- */
-#define EFI_RESET_COLD 0
-#define EFI_RESET_WARM 1
-
-/*
- * EFI Runtime Services table
- */
-#define EFI_RUNTIME_SERVICES_SIGNATURE 0x5652453544e5552
-#define EFI_RUNTIME_SERVICES_REVISION  0x00010000
-
-typedef struct {
-	efi_table_hdr_t hdr;
-	u64 get_time;
-	u64 set_time;
-	u64 get_wakeup_time;
-	u64 set_wakeup_time;
-	u64 set_virtual_address_map;
-	u64 convert_pointer;
-	u64 get_variable;
-	u64 get_next_variable;
-	u64 set_variable;
-	u64 get_next_high_mono_count;
-	u64 reset_system;
-} efi_runtime_services_t;
-
-typedef efi_status_t efi_get_time_t (efi_time_t *tm, efi_time_cap_t *tc);
-typedef efi_status_t efi_set_time_t (efi_time_t *tm);
-typedef efi_status_t efi_get_wakeup_time_t (efi_bool_t *enabled, efi_bool_t *pending,
-					    efi_time_t *tm);
-typedef efi_status_t efi_set_wakeup_time_t (efi_bool_t enabled, efi_time_t *tm);
-typedef efi_status_t efi_get_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
-					 unsigned long *data_size, void *data);
-typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char16_t *name,
-					      efi_guid_t *vendor);
-typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 attr,
-					 unsigned long data_size, void *data);
-typedef efi_status_t efi_get_next_high_mono_count_t (u64 *count);
-typedef void efi_reset_system_t (int reset_type, efi_status_t status,
-				 unsigned long data_size, efi_char16_t *data);
-
-/*
- *  EFI Configuration Table and GUID definitions
- */
-
-#define MPS_TABLE_GUID    \
-    ((efi_guid_t) { 0xeb9d2d2f, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }})
-
-#define ACPI_TABLE_GUID    \
-    ((efi_guid_t) { 0xeb9d2d30, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }})
-
-#define ACPI_20_TABLE_GUID    \
-    ((efi_guid_t) { 0x8868e871, 0xe4f1, 0x11d3, { 0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 }})
-
-#define SMBIOS_TABLE_GUID    \
-    ((efi_guid_t) { 0xeb9d2d31, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }})
-
-#define SAL_SYSTEM_TABLE_GUID    \
-    ((efi_guid_t) { 0xeb9d2d32, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }})
-
-#define HCDP_TABLE_GUID	\
-    ((efi_guid_t) { 0xf951938d, 0x620b, 0x42ef, {0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98}})
-
-typedef struct {
-	efi_guid_t guid;
-	u64 table;
-} efi_config_table_t;
-
-#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249
-#define EFI_SYSTEM_TABLE_REVISION  ((1 << 16) | 00)
-
-typedef struct {
-	efi_table_hdr_t hdr;
-	u64 fw_vendor;		/* physical addr of CHAR16 vendor string */
-	u32 fw_revision;
-	u64 con_in_handle;
-	u64 con_in;
-	u64 con_out_handle;
-	u64 con_out;
-	u64 stderr_handle;
-	u64 stderr;
-	u64 runtime;
-	u64 boottime;
-	u64 nr_tables;
-	u64 tables;
-} efi_system_table_t;
-
-/*
- * All runtime access to EFI goes through this structure:
- */
-extern struct efi {
-	efi_system_table_t *systab;	/* EFI system table */
-	void *mps;			/* MPS table */
-	void *acpi;			/* ACPI table  (IA64 ext 0.71) */
-	void *acpi20;			/* ACPI table  (ACPI 2.0) */
-	void *smbios;			/* SM BIOS table */
-	void *sal_systab;		/* SAL system table */
-	void *hcdp;			/* HCDP table */
-	void *boot_info;		/* boot info table */
-	efi_get_time_t *get_time;
-	efi_set_time_t *set_time;
-	efi_get_wakeup_time_t *get_wakeup_time;
-	efi_set_wakeup_time_t *set_wakeup_time;
-	efi_get_variable_t *get_variable;
-	efi_get_next_variable_t *get_next_variable;
-	efi_set_variable_t *set_variable;
-	efi_get_next_high_mono_count_t *get_next_high_mono_count;
-	efi_reset_system_t *reset_system;
-} efi;
-
-static inline int
-efi_guidcmp (efi_guid_t left, efi_guid_t right)
-{
-	return memcmp(&left, &right, sizeof (efi_guid_t));
-}
-
-extern void efi_init (void);
-extern void efi_map_pal_code (void);
-extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
-extern void efi_gettimeofday (struct timeval *tv);
-extern void efi_enter_virtual_mode (void);	/* switch EFI to virtual mode, if possible */
-extern u64  efi_get_iobase (void);
-
-/*
- * Variable Attributes
- */
-#define EFI_VARIABLE_NON_VOLATILE       0x0000000000000001
-#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
-#define EFI_VARIABLE_RUNTIME_ACCESS     0x0000000000000004
-
-
-/*
- * efi_dir is allocated in arch/ia64/kernel/efi.c.
- */
-#ifdef CONFIG_PROC_FS
-extern struct proc_dir_entry *efi_dir;
-#endif
-
-#endif /* _ASM_IA64_EFI_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/elf.h linux-2.4.20/include/asm-ia64/elf.h
--- linux-2.4.19/include/asm-ia64/elf.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/elf.h	2002-10-29 11:18:49.000000000 +0000
@@ -39,7 +39,7 @@
  * the way of the program that it will "exec", and that there is
  * sufficient room for the brk.
  */
-#define ELF_ET_DYN_BASE		(TASK_UNMAPPED_BASE + 0x1000000)
+#define ELF_ET_DYN_BASE		(TASK_UNMAPPED_BASE + 0x800000000)
 
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/errno.h linux-2.4.20/include/asm-ia64/errno.h
--- linux-2.4.19/include/asm-ia64/errno.h	2001-04-10 19:23:06.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/errno.h	2002-10-29 11:18:37.000000000 +0000
@@ -14,7 +14,7 @@
 #define	EINTR		 4	/* Interrupted system call */
 #define	EIO		 5	/* I/O error */
 #define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Arg list too long */
+#define	E2BIG		 7	/* Argument list too long */
 #define	ENOEXEC		 8	/* Exec format error */
 #define	EBADF		 9	/* Bad file number */
 #define	ECHILD		10	/* No child processes */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/hw_irq.h linux-2.4.20/include/asm-ia64/hw_irq.h
--- linux-2.4.19/include/asm-ia64/hw_irq.h	2001-07-31 17:30:09.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/hw_irq.h	2002-10-29 11:18:40.000000000 +0000
@@ -2,8 +2,8 @@
 #define _ASM_IA64_HW_IRQ_H
 
 /*
- * Copyright (C) 2001 Hewlett-Packard Co
- * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2001, 2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <linux/sched.h>
@@ -52,6 +52,10 @@
 #define IA64_IPI_RESCHEDULE		0xfd	/* SMP reschedule */
 #define IA64_IPI_VECTOR			0xfe	/* inter-processor interrupt vector */
 
+/* Used for encoding redirected irqs */
+
+#define IA64_IRQ_REDIRECTED		(1 << 31)
+
 /* IA64 inter-cpu interrupt related definitions */
 
 #define IA64_IPI_DEFAULT_BASE_ADDR	0xfee00000
@@ -72,7 +76,7 @@
 
 extern struct hw_interrupt_type irq_type_ia64_lsapic;	/* CPU-internal interrupt controller */
 
-extern int ia64_alloc_irq (void);	/* allocate a free irq */
+extern int ia64_alloc_vector (void);	/* allocate a free vector */
 extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
 extern void register_percpu_irq (ia64_vector vec, struct irqaction *action);
 
@@ -88,6 +92,7 @@
 
 extern struct irq_desc _irq_desc[NR_IRQS];
 
+#ifndef CONFIG_IA64_GENERIC
 static inline struct irq_desc *
 __ia64_irq_desc (unsigned int irq)
 {
@@ -105,6 +110,7 @@
 {
 	return (unsigned int) vec;
 }
+#endif
 
 /*
  * Next follows the irq descriptor interface.  On IA-64, each CPU supports 256 interrupt
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/ide.h linux-2.4.20/include/asm-ia64/ide.h
--- linux-2.4.19/include/asm-ia64/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/ide.h	2002-10-29 11:18:31.000000000 +0000
@@ -27,8 +27,7 @@
 
 #define ide__sti()	__sti()
 
-static __inline__ int
-ide_default_irq (ide_ioreg_t base)
+static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
 		case 0x1f0: return isa_irq_to_vector(14);
@@ -42,8 +41,7 @@
 	}
 }
 
-static __inline__ ide_ioreg_t
-ide_default_io_base (int index)
+static __inline__ ide_ioreg_t ide_default_io_base(int index)
 {
 	switch (index) {
 		case 0:	return 0x1f0;
@@ -57,8 +55,7 @@
 	}
 }
 
-static __inline__ void
-ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
 	ide_ioreg_t reg = data_port;
 	int i;
@@ -77,8 +74,7 @@
 	hw->io_ports[IDE_IRQ_OFFSET] = 0;
 }
 
-static __inline__ void
-ide_init_default_hwifs (void)
+static __inline__ void ide_init_default_hwifs(void)
 {
 #ifndef CONFIG_BLK_DEV_IDEPCI
 	hw_regs_t hw;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/ioctls.h linux-2.4.20/include/asm-ia64/ioctls.h
--- linux-2.4.19/include/asm-ia64/ioctls.h	2000-02-07 02:42:40.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/ioctls.h	2002-10-29 11:18:33.000000000 +0000
@@ -11,7 +11,7 @@
 /* 0x54 is just a magic number to make these relatively unique ('T') */
 
 #define TCGETS		0x5401
-#define TCSETS		0x5402
+#define TCSETS		0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */
 #define TCSETSW		0x5403
 #define TCSETSF		0x5404
 #define TCGETA		0x5405
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/iosapic.h linux-2.4.20/include/asm-ia64/iosapic.h
--- linux-2.4.19/include/asm-ia64/iosapic.h	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/iosapic.h	2002-10-29 11:18:31.000000000 +0000
@@ -51,17 +51,24 @@
 
 #ifndef __ASSEMBLY__
 
-extern void __init iosapic_init (unsigned long address, unsigned int base_irq,
-                                 int pcat_compat);
-extern int iosapic_register_irq (u32 global_vector, unsigned long polarity,
-                                 unsigned long edge_triggered, u32 base_irq,
-                                 char *iosapic_address);
-extern void iosapic_register_legacy_irq (unsigned long irq, unsigned long pin,
-					 unsigned long polarity, unsigned long trigger);
-extern int iosapic_register_platform_irq (u32 int_type, u32 global_vector, u32 iosapic_vector,
-					  u16 eid, u16 id, unsigned long polarity,
-					  unsigned long edge_triggered, u32 base_irq,
-					  char *iosapic_address);
+extern void __devinit iosapic_init (unsigned long address,
+				    unsigned int gsi_base,
+				    int pcat_compat);
+extern int gsi_to_vector (unsigned int gsi);
+extern int iosapic_register_intr (unsigned int gsi, unsigned long polarity,
+				  unsigned long edge_triggered,
+				  u32 gsi_base, char *iosapic_address);
+extern void iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
+				      unsigned long polarity,
+				      unsigned long edge_triggered);
+extern int iosapic_register_platform_intr (u32 int_type,
+					   unsigned int gsi,
+					   int pmi_vector,
+					   u16 eid, u16 id,
+					   unsigned long polarity,
+					   unsigned long edge_triggered,
+					   unsigned int gsi_base,
+					   char *iosapic_address);
 extern unsigned int iosapic_version (char *addr);
 
 extern void iosapic_pci_fixup (int);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/keyboard.h linux-2.4.20/include/asm-ia64/keyboard.h
--- linux-2.4.19/include/asm-ia64/keyboard.h	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/keyboard.h	2002-10-29 11:18:33.000000000 +0000
@@ -16,6 +16,7 @@
 #define KEYBOARD_IRQ			isa_irq_to_vector(1)
 #define DISABLE_KBD_DURING_INTERRUPTS	0
 
+extern unsigned char acpi_kbd_controller_present;
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
 extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
@@ -26,6 +27,7 @@
 extern void pckbd_init_hw(void);
 extern unsigned char pckbd_sysrq_xlate[128];
 
+#define kbd_controller_present() acpi_kbd_controller_present
 #define kbd_setkeycode		pckbd_setkeycode
 #define kbd_getkeycode		pckbd_getkeycode
 #define kbd_pretranslate	pckbd_pretranslate
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/kregs.h linux-2.4.20/include/asm-ia64/kregs.h
--- linux-2.4.19/include/asm-ia64/kregs.h	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/kregs.h	2002-10-29 11:18:34.000000000 +0000
@@ -2,8 +2,8 @@
 #define _ASM_IA64_KREGS_H
 
 /*
- * Copyright (C) 2001 Hewlett-Packard Co
- * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2001-2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 /*
  * This file defines the kernel register usage convention used by Linux/ia64.
@@ -31,4 +31,132 @@
 #define IA64_TR_PERCPU_DATA	1	/* dtr1: percpu data */
 #define IA64_TR_CURRENT_STACK	2	/* dtr2: maps kernel's memory- & register-stacks */
 
-#endif /* _ASM_IA64_kREGS_H */
+/* Processor status register bits: */
+#define IA64_PSR_BE_BIT		1
+#define IA64_PSR_UP_BIT		2
+#define IA64_PSR_AC_BIT		3
+#define IA64_PSR_MFL_BIT	4
+#define IA64_PSR_MFH_BIT	5
+#define IA64_PSR_IC_BIT		13
+#define IA64_PSR_I_BIT		14
+#define IA64_PSR_PK_BIT		15
+#define IA64_PSR_DT_BIT		17
+#define IA64_PSR_DFL_BIT	18
+#define IA64_PSR_DFH_BIT	19
+#define IA64_PSR_SP_BIT		20
+#define IA64_PSR_PP_BIT		21
+#define IA64_PSR_DI_BIT		22
+#define IA64_PSR_SI_BIT		23
+#define IA64_PSR_DB_BIT		24
+#define IA64_PSR_LP_BIT		25
+#define IA64_PSR_TB_BIT		26
+#define IA64_PSR_RT_BIT		27
+/* The following are not affected by save_flags()/restore_flags(): */
+#define IA64_PSR_CPL0_BIT	32
+#define IA64_PSR_CPL1_BIT	33
+#define IA64_PSR_IS_BIT		34
+#define IA64_PSR_MC_BIT		35
+#define IA64_PSR_IT_BIT		36
+#define IA64_PSR_ID_BIT		37
+#define IA64_PSR_DA_BIT		38
+#define IA64_PSR_DD_BIT		39
+#define IA64_PSR_SS_BIT		40
+#define IA64_PSR_RI_BIT		41
+#define IA64_PSR_ED_BIT		43
+#define IA64_PSR_BN_BIT		44
+#define IA64_PSR_IA_BIT		45
+
+#define IA64_PSR_BE	(__IA64_UL(1) << IA64_PSR_BE_BIT)
+#define IA64_PSR_UP	(__IA64_UL(1) << IA64_PSR_UP_BIT)
+#define IA64_PSR_AC	(__IA64_UL(1) << IA64_PSR_AC_BIT)
+#define IA64_PSR_MFL	(__IA64_UL(1) << IA64_PSR_MFL_BIT)
+#define IA64_PSR_MFH	(__IA64_UL(1) << IA64_PSR_MFH_BIT)
+#define IA64_PSR_IC	(__IA64_UL(1) << IA64_PSR_IC_BIT)
+#define IA64_PSR_I	(__IA64_UL(1) << IA64_PSR_I_BIT)
+#define IA64_PSR_PK	(__IA64_UL(1) << IA64_PSR_PK_BIT)
+#define IA64_PSR_DT	(__IA64_UL(1) << IA64_PSR_DT_BIT)
+#define IA64_PSR_DFL	(__IA64_UL(1) << IA64_PSR_DFL_BIT)
+#define IA64_PSR_DFH	(__IA64_UL(1) << IA64_PSR_DFH_BIT)
+#define IA64_PSR_SP	(__IA64_UL(1) << IA64_PSR_SP_BIT)
+#define IA64_PSR_PP	(__IA64_UL(1) << IA64_PSR_PP_BIT)
+#define IA64_PSR_DI	(__IA64_UL(1) << IA64_PSR_DI_BIT)
+#define IA64_PSR_SI	(__IA64_UL(1) << IA64_PSR_SI_BIT)
+#define IA64_PSR_DB	(__IA64_UL(1) << IA64_PSR_DB_BIT)
+#define IA64_PSR_LP	(__IA64_UL(1) << IA64_PSR_LP_BIT)
+#define IA64_PSR_TB	(__IA64_UL(1) << IA64_PSR_TB_BIT)
+#define IA64_PSR_RT	(__IA64_UL(1) << IA64_PSR_RT_BIT)
+/* The following are not affected by save_flags()/restore_flags(): */
+#define IA64_PSR_CPL	(__IA64_UL(3) << IA64_PSR_CPL0_BIT)
+#define IA64_PSR_IS	(__IA64_UL(1) << IA64_PSR_IS_BIT)
+#define IA64_PSR_MC	(__IA64_UL(1) << IA64_PSR_MC_BIT)
+#define IA64_PSR_IT	(__IA64_UL(1) << IA64_PSR_IT_BIT)
+#define IA64_PSR_ID	(__IA64_UL(1) << IA64_PSR_ID_BIT)
+#define IA64_PSR_DA	(__IA64_UL(1) << IA64_PSR_DA_BIT)
+#define IA64_PSR_DD	(__IA64_UL(1) << IA64_PSR_DD_BIT)
+#define IA64_PSR_SS	(__IA64_UL(1) << IA64_PSR_SS_BIT)
+#define IA64_PSR_RI	(__IA64_UL(3) << IA64_PSR_RI_BIT)
+#define IA64_PSR_ED	(__IA64_UL(1) << IA64_PSR_ED_BIT)
+#define IA64_PSR_BN	(__IA64_UL(1) << IA64_PSR_BN_BIT)
+#define IA64_PSR_IA	(__IA64_UL(1) << IA64_PSR_IA_BIT)
+
+/* A mask of PSR bits that we generally don't want to inherit across a clone2() or an
+   execve().  Only list flags here that need to be cleared/set for BOTH clone2() and
+   execve().  */
+#define IA64_PSR_BITS_TO_CLEAR	(IA64_PSR_MFL | IA64_PSR_MFH | IA64_PSR_DB | IA64_PSR_LP | \
+				 IA64_PSR_TB  | IA64_PSR_ID  | IA64_PSR_DA | IA64_PSR_DD | \
+				 IA64_PSR_SS  | IA64_PSR_ED  | IA64_PSR_IA)
+#define IA64_PSR_BITS_TO_SET	(IA64_PSR_DFH)
+
+/* User mask bits: */
+#define IA64_PSR_UM	(IA64_PSR_BE | IA64_PSR_UP | IA64_PSR_AC | IA64_PSR_MFL | IA64_PSR_MFH)
+
+/* Default Control Register */
+#define IA64_DCR_PP_BIT		 0	/* privileged performance monitor default */
+#define IA64_DCR_BE_BIT		 1	/* big-endian default */
+#define IA64_DCR_LC_BIT		 2	/* ia32 lock-check enable */
+#define IA64_DCR_DM_BIT		 8	/* defer TLB miss faults */
+#define IA64_DCR_DP_BIT		 9	/* defer page-not-present faults */
+#define IA64_DCR_DK_BIT		10	/* defer key miss faults */
+#define IA64_DCR_DX_BIT		11	/* defer key permission faults */
+#define IA64_DCR_DR_BIT		12	/* defer access right faults */
+#define IA64_DCR_DA_BIT		13	/* defer access bit faults */
+#define IA64_DCR_DD_BIT		14	/* defer debug faults */
+
+#define IA64_DCR_PP	(__IA64_UL(1) << IA64_DCR_PP_BIT)
+#define IA64_DCR_BE	(__IA64_UL(1) << IA64_DCR_BE_BIT)
+#define IA64_DCR_LC	(__IA64_UL(1) << IA64_DCR_LC_BIT)
+#define IA64_DCR_DM	(__IA64_UL(1) << IA64_DCR_DM_BIT)
+#define IA64_DCR_DP	(__IA64_UL(1) << IA64_DCR_DP_BIT)
+#define IA64_DCR_DK	(__IA64_UL(1) << IA64_DCR_DK_BIT)
+#define IA64_DCR_DX	(__IA64_UL(1) << IA64_DCR_DX_BIT)
+#define IA64_DCR_DR	(__IA64_UL(1) << IA64_DCR_DR_BIT)
+#define IA64_DCR_DA	(__IA64_UL(1) << IA64_DCR_DA_BIT)
+#define IA64_DCR_DD	(__IA64_UL(1) << IA64_DCR_DD_BIT)
+
+/* Interrupt Status Register */
+#define IA64_ISR_X_BIT		32	/* execute access */
+#define IA64_ISR_W_BIT		33	/* write access */
+#define IA64_ISR_R_BIT		34	/* read access */
+#define IA64_ISR_NA_BIT		35	/* non-access */
+#define IA64_ISR_SP_BIT		36	/* speculative load exception */
+#define IA64_ISR_RS_BIT		37	/* mandatory register-stack exception */
+#define IA64_ISR_IR_BIT		38	/* invalid register frame exception */
+#define IA64_ISR_CODE_MASK	0xf
+
+#define IA64_ISR_X	(__IA64_UL(1) << IA64_ISR_X_BIT)
+#define IA64_ISR_W	(__IA64_UL(1) << IA64_ISR_W_BIT)
+#define IA64_ISR_R	(__IA64_UL(1) << IA64_ISR_R_BIT)
+#define IA64_ISR_NA	(__IA64_UL(1) << IA64_ISR_NA_BIT)
+#define IA64_ISR_SP	(__IA64_UL(1) << IA64_ISR_SP_BIT)
+#define IA64_ISR_RS	(__IA64_UL(1) << IA64_ISR_RS_BIT)
+#define IA64_ISR_IR	(__IA64_UL(1) << IA64_ISR_IR_BIT)
+
+/* ISR code field for non-access instructions */
+#define IA64_ISR_CODE_TPA	0
+#define IA64_ISR_CODE_FC	1
+#define IA64_ISR_CODE_PROBE	2
+#define IA64_ISR_CODE_TAK	3
+#define IA64_ISR_CODE_LFETCH	4
+#define IA64_ISR_CODE_PROBEF	5
+
+#endif /* _ASM_IA64_KREGS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/machvec.h linux-2.4.20/include/asm-ia64/machvec.h
--- linux-2.4.19/include/asm-ia64/machvec.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/machvec.h	2002-10-29 11:18:31.000000000 +0000
@@ -18,11 +18,13 @@
 struct pt_regs;
 struct scatterlist;
 struct irq_desc;
+struct page;
 
 typedef void ia64_mv_setup_t (char **);
 typedef void ia64_mv_cpu_init_t(void);
 typedef void ia64_mv_irq_init_t (void);
 typedef void ia64_mv_pci_fixup_t (int);
+typedef void ia64_mv_pci_enable_device_t (struct pci_dev *);
 typedef unsigned long ia64_mv_map_nr_t (unsigned long);
 typedef void ia64_mv_mca_init_t (void);
 typedef void ia64_mv_mca_handler_t (void);
@@ -45,6 +47,8 @@
 typedef void ia64_mv_pci_dma_sync_single (struct pci_dev *, dma_addr_t, size_t, int);
 typedef void ia64_mv_pci_dma_sync_sg (struct pci_dev *, struct scatterlist *, int, int);
 typedef unsigned long ia64_mv_pci_dma_address (struct scatterlist *);
+typedef int ia64_mv_pci_dma_supported (struct pci_dev *, u64);
+
 /*
  * WARNING: The legacy I/O space is _architected_.  Platforms are
  * expected to follow this architected model (see Section 10.7 in the
@@ -67,6 +71,8 @@
 #  include <asm/machvec_hpsim.h>
 # elif defined (CONFIG_IA64_DIG)
 #  include <asm/machvec_dig.h>
+# elif defined (CONFIG_IA64_HP_ZX1)
+#  include <asm/machvec_hpzx1.h>
 # elif defined (CONFIG_IA64_SGI_SN1)
 #  include <asm/machvec_sn1.h>
 # elif defined (CONFIG_IA64_SGI_SN2)
@@ -86,7 +92,8 @@
 #  define platform_cmci_handler	ia64_mv.cmci_handler
 #  define platform_log_print	ia64_mv.log_print
 #  define platform_pci_fixup	ia64_mv.pci_fixup
-#  define platform_send_ipi	ia64_mv.send_ipi
+#  define platform_pci_enable_device	ia64_mv.pci_enable_device
+#  define platform_send_ipi		ia64_mv.send_ipi
 #  define platform_global_tlb_purge	ia64_mv.global_tlb_purge
 #  define platform_pci_dma_init		ia64_mv.dma_init
 #  define platform_pci_alloc_consistent	ia64_mv.alloc_consistent
@@ -98,6 +105,7 @@
 #  define platform_pci_dma_sync_single	ia64_mv.sync_single
 #  define platform_pci_dma_sync_sg	ia64_mv.sync_sg
 #  define platform_pci_dma_address	ia64_mv.dma_address
+#  define platform_pci_dma_supported	ia64_mv.dma_supported
 #  define platform_irq_desc		ia64_mv.irq_desc
 #  define platform_irq_to_vector	ia64_mv.irq_to_vector
 #  define platform_local_vector_to_irq	ia64_mv.local_vector_to_irq
@@ -115,12 +123,14 @@
 	ia64_mv_cpu_init_t *cpu_init;
 	ia64_mv_irq_init_t *irq_init;
 	ia64_mv_pci_fixup_t *pci_fixup;
+	ia64_mv_pci_enable_device_t *pci_enable_device;
 	ia64_mv_map_nr_t *map_nr;
 	ia64_mv_mca_init_t *mca_init;
 	ia64_mv_mca_handler_t *mca_handler;
 	ia64_mv_cmci_handler_t *cmci_handler;
 	ia64_mv_log_print_t *log_print;
 	ia64_mv_send_ipi_t *send_ipi;
+	ia64_mv_global_tlb_purge_t *global_tlb_purge;
 	ia64_mv_pci_dma_init *dma_init;
 	ia64_mv_pci_alloc_consistent *alloc_consistent;
 	ia64_mv_pci_free_consistent *free_consistent;
@@ -131,6 +141,7 @@
 	ia64_mv_pci_dma_sync_single *sync_single;
 	ia64_mv_pci_dma_sync_sg *sync_sg;
 	ia64_mv_pci_dma_address *dma_address;
+	ia64_mv_pci_dma_supported *dma_supported;
 	ia64_mv_irq_desc *irq_desc;
 	ia64_mv_irq_to_vector *irq_to_vector;
 	ia64_mv_local_vector_to_irq *local_vector_to_irq;
@@ -146,8 +157,10 @@
 {						\
 	#name,					\
 	platform_setup,				\
+	platform_cpu_init,			\
 	platform_irq_init,			\
 	platform_pci_fixup,			\
+	platform_pci_enable_device,		\
 	platform_map_nr,			\
 	platform_mca_init,			\
 	platform_mca_handler,			\
@@ -165,6 +178,7 @@
 	platform_pci_dma_sync_single,		\
 	platform_pci_dma_sync_sg,		\
 	platform_pci_dma_address,		\
+	platform_pci_dma_supported,		\
 	platform_irq_desc,			\
 	platform_irq_to_vector,			\
 	platform_local_vector_to_irq,		\
@@ -196,6 +210,7 @@
 extern ia64_mv_pci_dma_sync_single swiotlb_sync_single;
 extern ia64_mv_pci_dma_sync_sg swiotlb_sync_sg;
 extern ia64_mv_pci_dma_address swiotlb_dma_address;
+extern ia64_mv_pci_dma_supported swiotlb_pci_dma_supported;
 
 /*
  * Define default versions so we can extend machvec for new platforms without having
@@ -225,6 +240,9 @@
 #ifndef platform_pci_fixup
 # define platform_pci_fixup	((ia64_mv_pci_fixup_t *) machvec_noop)
 #endif
+#ifndef platform_pci_enable_device
+# define platform_pci_enable_device	((ia64_mv_pci_enable_device_t *) machvec_noop)
+#endif
 #ifndef platform_send_ipi
 # define platform_send_ipi	ia64_send_ipi	/* default to architected version */
 #endif
@@ -261,6 +279,9 @@
 #ifndef platform_pci_dma_address
 # define  platform_pci_dma_address	swiotlb_dma_address
 #endif
+#ifndef platform_pci_dma_supported
+# define  platform_pci_dma_supported	swiotlb_pci_dma_supported
+#endif
 #ifndef platform_irq_desc
 # define platform_irq_desc		__ia64_irq_desc
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/machvec_hpzx1.h linux-2.4.20/include/asm-ia64/machvec_hpzx1.h
--- linux-2.4.19/include/asm-ia64/machvec_hpzx1.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/machvec_hpzx1.h	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,41 @@
+#ifndef _ASM_IA64_MACHVEC_HPZX1_h
+#define _ASM_IA64_MACHVEC_HPZX1_h
+
+extern ia64_mv_setup_t dig_setup;
+extern ia64_mv_pci_fixup_t hpzx1_pci_fixup;
+extern ia64_mv_pci_enable_device_t sba_enable_device;
+extern ia64_mv_map_nr_t map_nr_dense;
+extern ia64_mv_pci_alloc_consistent sba_alloc_consistent;
+extern ia64_mv_pci_free_consistent sba_free_consistent;
+extern ia64_mv_pci_map_single sba_map_single;
+extern ia64_mv_pci_unmap_single sba_unmap_single;
+extern ia64_mv_pci_map_sg sba_map_sg;
+extern ia64_mv_pci_unmap_sg sba_unmap_sg;
+extern ia64_mv_pci_dma_address sba_dma_address;
+extern ia64_mv_pci_dma_supported sba_dma_supported;
+
+/*
+ * This stuff has dual use!
+ *
+ * For a generic kernel, the macros are used to initialize the
+ * platform's machvec structure.  When compiling a non-generic kernel,
+ * the macros are used directly.
+ */
+#define platform_name			"hpzx1"
+#define platform_setup			dig_setup
+#define platform_pci_fixup		hpzx1_pci_fixup
+#define platform_pci_enable_device	sba_enable_device
+#define platform_map_nr			map_nr_dense
+#define platform_pci_dma_init		((ia64_mv_pci_dma_init *) machvec_noop)
+#define platform_pci_alloc_consistent	sba_alloc_consistent
+#define platform_pci_free_consistent	sba_free_consistent
+#define platform_pci_map_single		sba_map_single
+#define platform_pci_unmap_single	sba_unmap_single
+#define platform_pci_map_sg		sba_map_sg
+#define platform_pci_unmap_sg		sba_unmap_sg
+#define platform_pci_dma_sync_single	((ia64_mv_pci_dma_sync_single *) machvec_noop)
+#define platform_pci_dma_sync_sg	((ia64_mv_pci_dma_sync_sg *) machvec_noop)
+#define platform_pci_dma_address	sba_dma_address
+#define platform_pci_dma_supported	sba_dma_supported
+
+#endif /* _ASM_IA64_MACHVEC_HPZX1_h */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/machvec_init.h linux-2.4.20/include/asm-ia64/machvec_init.h
--- linux-2.4.19/include/asm-ia64/machvec_init.h	2001-01-04 20:50:17.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/machvec_init.h	2002-10-29 11:18:32.000000000 +0000
@@ -5,6 +5,11 @@
 #include <asm/machvec.h>
 
 extern ia64_mv_send_ipi_t ia64_send_ipi;
+extern ia64_mv_global_tlb_purge_t ia64_global_tlb_purge;
+extern ia64_mv_irq_desc __ia64_irq_desc;
+extern ia64_mv_irq_to_vector __ia64_irq_to_vector;
+extern ia64_mv_local_vector_to_irq __ia64_local_vector_to_irq;
+
 extern ia64_mv_inb_t __ia64_inb;
 extern ia64_mv_inw_t __ia64_inw;
 extern ia64_mv_inl_t __ia64_inl;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/machvec_sn1.h linux-2.4.20/include/asm-ia64/machvec_sn1.h
--- linux-2.4.19/include/asm-ia64/machvec_sn1.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/machvec_sn1.h	2002-10-29 11:18:49.000000000 +0000
@@ -59,6 +59,7 @@
 extern ia64_mv_pci_dma_sync_single	sn_pci_dma_sync_single;
 extern ia64_mv_pci_dma_sync_sg		sn_pci_dma_sync_sg;
 extern ia64_mv_pci_dma_address		sn_dma_address;
+extern ia64_mv_pci_dma_supported	sn_pci_dma_supported;
 
 /*
  * This stuff has dual use!
@@ -95,5 +96,6 @@
 #define platform_pci_dma_sync_single	sn_pci_dma_sync_single
 #define platform_pci_dma_sync_sg	sn_pci_dma_sync_sg
 #define platform_pci_dma_address	sn_dma_address
+#define platform_pci_dma_supported	sn_pci_dma_supported
 
 #endif /* _ASM_IA64_MACHVEC_SN1_h */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/machvec_sn2.h linux-2.4.20/include/asm-ia64/machvec_sn2.h
--- linux-2.4.19/include/asm-ia64/machvec_sn2.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/machvec_sn2.h	2002-10-29 11:18:31.000000000 +0000
@@ -59,6 +59,7 @@
 extern ia64_mv_pci_dma_sync_single	sn_pci_dma_sync_single;
 extern ia64_mv_pci_dma_sync_sg		sn_pci_dma_sync_sg;
 extern ia64_mv_pci_dma_address		sn_dma_address;
+extern ia64_mv_pci_dma_supported	sn_pci_dma_supported;
 
 /*
  * This stuff has dual use!
@@ -95,5 +96,6 @@
 #define platform_pci_dma_sync_single	sn_pci_dma_sync_single
 #define platform_pci_dma_sync_sg	sn_pci_dma_sync_sg
 #define platform_pci_dma_address	sn_dma_address
+#define platform_pci_dma_supported	sn_pci_dma_supported
 
 #endif /* _ASM_IA64_MACHVEC_SN2_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/module.h linux-2.4.20/include/asm-ia64/module.h
--- linux-2.4.19/include/asm-ia64/module.h	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/module.h	2002-10-29 11:18:36.000000000 +0000
@@ -51,6 +51,9 @@
 		return 0;
 	archdata = (struct archdata *)(mod->archdata_start);
 
+	if (archdata->unw_start == 0)
+		return 0;
+
 	/*
 	 * Make sure the unwind pointers are sane.
 	 */
@@ -72,7 +75,7 @@
 		return 1;
 	}
 	if (!mod_bound(archdata->segment_base, 0, mod)) {
-		printk(KERN_ERR "module_arch_init: archdata->unw_table out of bounds.\n");
+		printk(KERN_ERR "module_arch_init: archdata->segment_base out of bounds.\n");
 		return 1;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/offsets.h linux-2.4.20/include/asm-ia64/offsets.h
--- linux-2.4.19/include/asm-ia64/offsets.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/offsets.h	2002-10-29 11:18:47.000000000 +0000
@@ -8,7 +8,7 @@
  */
 #define PT_PTRACED_BIT		0
 #define PT_TRACESYS_BIT		1
-#define IA64_TASK_SIZE			3936	/* 0xf60 */
+#define IA64_TASK_SIZE			3424	/* 0xd60 */
 #define IA64_PT_REGS_SIZE		400	/* 0x190 */
 #define IA64_SWITCH_STACK_SIZE		560	/* 0x230 */
 #define IA64_SIGINFO_SIZE		128	/* 0x80 */
@@ -20,9 +20,9 @@
 #define IA64_TASK_SIGPENDING_OFFSET	16	/* 0x10 */
 #define IA64_TASK_NEED_RESCHED_OFFSET	40	/* 0x28 */
 #define IA64_TASK_PROCESSOR_OFFSET	96	/* 0x60 */
-#define IA64_TASK_THREAD_OFFSET		1488	/* 0x5d0 */
-#define IA64_TASK_THREAD_KSP_OFFSET	1488	/* 0x5d0 */
-#define IA64_TASK_PFM_OVFL_BLOCK_RESET_OFFSET 2112	/* 0x840 */
+#define IA64_TASK_THREAD_OFFSET		992	/* 0x3e0 */
+#define IA64_TASK_THREAD_KSP_OFFSET	992	/* 0x3e0 */
+#define IA64_TASK_PFM_OVFL_BLOCK_RESET_OFFSET 1616	/* 0x650 */
 #define IA64_TASK_PID_OFFSET		228	/* 0xe4 */
 #define IA64_TASK_MM_OFFSET		88	/* 0x58 */
 #define IA64_PT_REGS_CR_IPSR_OFFSET	0	/* 0x0 */
@@ -115,6 +115,7 @@
 #define IA64_SWITCH_STACK_AR_RNAT_OFFSET 536	/* 0x218 */
 #define IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET 544	/* 0x220 */
 #define IA64_SWITCH_STACK_PR_OFFSET	552	/* 0x228 */
+#define IA64_SIGCONTEXT_IP_OFFSET	40	/* 0x28 */
 #define IA64_SIGCONTEXT_AR_BSP_OFFSET	72	/* 0x48 */
 #define IA64_SIGCONTEXT_AR_FPSR_OFFSET	104	/* 0x68 */
 #define IA64_SIGCONTEXT_AR_RNAT_OFFSET	80	/* 0x50 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/page.h linux-2.4.20/include/asm-ia64/page.h
--- linux-2.4.19/include/asm-ia64/page.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/page.h	2002-10-29 11:18:33.000000000 +0000
@@ -55,7 +55,7 @@
 #ifdef CONFIG_IA64_GENERIC
 # include <asm/machvec.h>
 # define virt_to_page(kaddr)	(mem_map + platform_map_nr(kaddr))
-# define page_to_phys(page)	XXX fix me
+# define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
 #elif defined (CONFIG_IA64_SGI_SN1)
 # ifndef CONFIG_DISCONTIGMEM
 #  define virt_to_page(kaddr)	(mem_map + MAP_NR_DENSE(kaddr))
@@ -65,7 +65,13 @@
 # define virt_to_page(kaddr)	(mem_map + MAP_NR_DENSE(kaddr))
 # define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
 #endif
-#define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+  struct page;
+  extern int ia64_page_valid (struct page *);
+# define VALID_PAGE(page)	(((page - mem_map) < max_mapnr) && ia64_page_valid(page))
+#else
+# define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
+#endif
 
 typedef union ia64_va {
 	struct {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/pci.h linux-2.4.20/include/asm-ia64/pci.h
--- linux-2.4.19/include/asm-ia64/pci.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/pci.h	2002-10-29 11:18:50.000000000 +0000
@@ -19,6 +19,11 @@
 #define PCIBIOS_MIN_IO		0x1000
 #define PCIBIOS_MIN_MEM		0x10000000
 
+void pcibios_config_init(void);
+struct pci_bus *pcibios_scan_root(void *acpi_handle, int segment, int bus);
+extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value);
+extern int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value);
+
 struct pci_dev;
 
 static inline void
@@ -45,6 +50,7 @@
 #define pci_dma_sync_single		platform_pci_dma_sync_single
 #define pci_dma_sync_sg			platform_pci_dma_sync_sg
 #define sg_dma_address			platform_pci_dma_address
+#define pci_dma_supported		platform_pci_dma_supported
 
 /* pci_unmap_{single,page} is not a nop, thus... */
 #define DECLARE_PCI_UNMAP_ADDR(addr_name)	dma_addr_t addr_name;
@@ -54,17 +60,6 @@
 #define pci_unmap_len(ptr, len_name)		((ptr)->len_name)
 #define pci_unmap_len_set(ptr, len_name, val)	(((ptr)->len_name) = (val))
 
-/*
- * Return whether the given PCI device DMA address mask can be supported properly.  For
- * example, if your device can only drive the low 24-bits during PCI bus mastering, then
- * you would pass 0x00ffffff as the mask to this function.
- */
-static inline int
-pci_dma_supported (struct pci_dev *hwdev, u64 mask)
-{
-	return 1;
-}
-
 #define pci_map_page(dev,pg,off,size,dir)				\
 	pci_map_single((dev), page_address(pg) + (off), (size), (dir))
 #define pci_unmap_page(dev,dma_addr,size,dir)				\
@@ -73,7 +68,7 @@
 /* The ia64 platform always supports 64-bit addressing. */
 #define pci_dac_dma_supported(pci_dev, mask)	(1)
 
-#define pci_dac_page_to_dma(dev,pg,off,dir)	((dma64_addr_t) page_to_bus(pg) + (off))
+#define pci_dac_page_to_dma(dev,pg,off,dir)	((dma_addr_t) page_to_bus(pg) + (off))
 #define pci_dac_dma_to_page(dev,dma_addr)	(virt_to_page(bus_to_virt(dma_addr)))
 #define pci_dac_dma_to_offset(dev,dma_addr)	((dma_addr) & ~PAGE_MASK)
 #define pci_dac_dma_sync_single(dev,dma_addr,len,dir)	do { /* nothing */ } while (0)
@@ -87,4 +82,17 @@
 extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
 				enum pci_mmap_state mmap_state, int write_combine);
 
+struct pci_controller {
+	void *acpi_handle;
+	void *iommu;
+	int segment;
+
+	u64 mem_offset;
+
+	void *platform_data;
+};
+
+#define PCI_CONTROLLER(dev) ((struct pci_controller *) dev->sysdata)
+#define PCI_SEGMENT(dev)    (PCI_CONTROLLER(dev)->segment)
+
 #endif /* _ASM_IA64_PCI_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/perfmon.h linux-2.4.20/include/asm-ia64/perfmon.h
--- linux-2.4.19/include/asm-ia64/perfmon.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/perfmon.h	2002-10-29 11:18:48.000000000 +0000
@@ -23,6 +23,7 @@
 #define PFM_GET_FEATURES	0x0c
 #define PFM_DEBUG		0x0d
 #define PFM_UNPROTECT_CONTEXT	0x0e
+#define PFM_GET_PMC_RESET_VAL	0x0f
 
 
 /*
@@ -171,6 +172,7 @@
 extern int  pfm_release_debug_registers(struct task_struct *);
 extern int  pfm_cleanup_smpl_buf(struct task_struct *);
 extern void pfm_syst_wide_update_task(struct task_struct *, int);
+extern void perfmon_init_percpu(void);
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/pgalloc.h linux-2.4.20/include/asm-ia64/pgalloc.h
--- linux-2.4.19/include/asm-ia64/pgalloc.h	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/pgalloc.h	2002-10-29 11:18:31.000000000 +0000
@@ -8,13 +8,14 @@
  * This hopefully works with any (fixed) ia-64 page-size, as defined
  * in <asm/page.h> (currently 8192).
  *
- * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2002 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 2000, Goutham Rao <goutham.rao@intel.com>
  */
 
 #include <linux/config.h>
 
+#include <linux/compiler.h>
 #include <linux/mm.h>
 #include <linux/threads.h>
 
@@ -194,6 +195,8 @@
 #else
 	if (vma->vm_mm == current->active_mm)
 		asm volatile ("ptc.l %0,%1" :: "r"(addr), "r"(PAGE_SHIFT << 2) : "memory");
+	else
+		vma->vm_mm->context = 0;
 #endif
 }
 
@@ -204,30 +207,41 @@
 static inline void
 flush_tlb_pgtables (struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-	if (rgn_index(start) != rgn_index(end))
-		printk("flush_tlb_pgtables: can't flush across regions!!\n");
-	flush_tlb_range(mm, ia64_thash(start), ia64_thash(end));
+	if (unlikely(end - start >= 1024*1024*1024*1024UL
+		     || rgn_index(start) != rgn_index(end - 1)))
+		/*
+		 * This condition is very rare and normal applications shouldn't get
+		 * here. No attempt has been made to optimize for this case.
+		 */
+		flush_tlb_all();
+	else
+		flush_tlb_range(mm, ia64_thash(start), ia64_thash(end));
 }
 
 /*
- * Now for some cache flushing routines.  This is the kind of stuff
- * that can be very expensive, so try to avoid them whenever possible.
+ * Cache flushing routines.  This is the kind of stuff that can be very expensive, so try
+ * to avoid them whenever possible.
  */
 
-/* Caches aren't brain-dead on the IA-64. */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
 #define flush_cache_range(mm, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
+#define flush_icache_page(vma,page)		do { } while (0)
+
+#define flush_dcache_page(page)			\
+do {						\
+	clear_bit(PG_arch_1, &(page)->flags);	\
+} while (0)
 
 extern void flush_icache_range (unsigned long start, unsigned long end);
 
-static inline void
-flush_dcache_page (struct page *page)
-{
-	clear_bit(PG_arch_1, &page->flags);
-}
+#define flush_icache_user_range(vma, page, user_addr, len)					\
+do {												\
+	unsigned long _addr = (unsigned long) page_address(page) + ((user_addr) & ~PAGE_MASK);	\
+	flush_icache_range(_addr, _addr + (len));						\
+} while (0)
 
 static inline void
 clear_user_page (void *addr, unsigned long vaddr, struct page *page)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/pgtable.h linux-2.4.20/include/asm-ia64/pgtable.h
--- linux-2.4.19/include/asm-ia64/pgtable.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/pgtable.h	2002-10-29 11:18:36.000000000 +0000
@@ -156,12 +156,6 @@
 #define pte_ERROR(e)	printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
 
 
-/*
- * Some definitions to translate between mem_map, PTEs, and page
- * addresses:
- */
-
-
 /* Quick test to see if ADDR is a (potentially) valid physical address. */
 static inline long
 ia64_phys_addr_valid (unsigned long addr)
@@ -204,7 +198,13 @@
 
 #define VMALLOC_START		(0xa000000000000000 + 3*PAGE_SIZE)
 #define VMALLOC_VMADDR(x)	((unsigned long)(x))
-#define VMALLOC_END		(0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9)))
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+# define VMALLOC_END_INIT        (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) 
+# define VMALLOC_END             vmalloc_end
+  extern unsigned long vmalloc_end;
+#else
+# define VMALLOC_END		(0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9)))
+#endif
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
@@ -448,6 +448,20 @@
  */
 #define pgtable_cache_init()	do { } while (0)
 
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+
+/* arch mem_map init routines are needed due to holes in a virtual mem_map */
+#define HAVE_ARCH_MEMMAP_INIT
+
+typedef unsigned long memmap_init_callback_t(struct page *start,
+	struct page *end, int zone, unsigned long start_paddr, int highmem);
+
+extern unsigned long arch_memmap_init (memmap_init_callback_t *callback,
+	struct page *start, struct page *end, int zone,
+	unsigned long start_paddr, int highmem);
+
+#endif /* CONFIG_VIRTUAL_MEM_MAP */
+
 # endif /* !__ASSEMBLY__ */
 
 /*
@@ -468,9 +482,4 @@
 #define KERNEL_TR_PAGE_SIZE	(1 << KERNEL_TR_PAGE_SHIFT)
 #define KERNEL_TR_PAGE_NUM	((KERNEL_START - PAGE_OFFSET) / KERNEL_TR_PAGE_SIZE)
 
-/*
- * No page table caches to initialise
- */
-#define pgtable_cache_init()	do { } while (0)
-
 #endif /* _ASM_IA64_PGTABLE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/processor.h linux-2.4.20/include/asm-ia64/processor.h
--- linux-2.4.19/include/asm-ia64/processor.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/processor.h	2002-10-29 11:18:37.000000000 +0000
@@ -18,7 +18,6 @@
 
 #include <asm/ptrace.h>
 #include <asm/kregs.h>
-#include <asm/system.h>
 #include <asm/types.h>
 
 #define IA64_NUM_DBG_REGS	8
@@ -54,114 +53,6 @@
 #define MCA_bus 0
 #define MCA_bus__is_a_macro /* for versions in ksyms.c */
 
-/* Processor status register bits: */
-#define IA64_PSR_BE_BIT		1
-#define IA64_PSR_UP_BIT		2
-#define IA64_PSR_AC_BIT		3
-#define IA64_PSR_MFL_BIT	4
-#define IA64_PSR_MFH_BIT	5
-#define IA64_PSR_IC_BIT		13
-#define IA64_PSR_I_BIT		14
-#define IA64_PSR_PK_BIT		15
-#define IA64_PSR_DT_BIT		17
-#define IA64_PSR_DFL_BIT	18
-#define IA64_PSR_DFH_BIT	19
-#define IA64_PSR_SP_BIT		20
-#define IA64_PSR_PP_BIT		21
-#define IA64_PSR_DI_BIT		22
-#define IA64_PSR_SI_BIT		23
-#define IA64_PSR_DB_BIT		24
-#define IA64_PSR_LP_BIT		25
-#define IA64_PSR_TB_BIT		26
-#define IA64_PSR_RT_BIT		27
-/* The following are not affected by save_flags()/restore_flags(): */
-#define IA64_PSR_CPL0_BIT	32
-#define IA64_PSR_CPL1_BIT	33
-#define IA64_PSR_IS_BIT		34
-#define IA64_PSR_MC_BIT		35
-#define IA64_PSR_IT_BIT		36
-#define IA64_PSR_ID_BIT		37
-#define IA64_PSR_DA_BIT		38
-#define IA64_PSR_DD_BIT		39
-#define IA64_PSR_SS_BIT		40
-#define IA64_PSR_RI_BIT		41
-#define IA64_PSR_ED_BIT		43
-#define IA64_PSR_BN_BIT		44
-
-#define IA64_PSR_BE	(__IA64_UL(1) << IA64_PSR_BE_BIT)
-#define IA64_PSR_UP	(__IA64_UL(1) << IA64_PSR_UP_BIT)
-#define IA64_PSR_AC	(__IA64_UL(1) << IA64_PSR_AC_BIT)
-#define IA64_PSR_MFL	(__IA64_UL(1) << IA64_PSR_MFL_BIT)
-#define IA64_PSR_MFH	(__IA64_UL(1) << IA64_PSR_MFH_BIT)
-#define IA64_PSR_IC	(__IA64_UL(1) << IA64_PSR_IC_BIT)
-#define IA64_PSR_I	(__IA64_UL(1) << IA64_PSR_I_BIT)
-#define IA64_PSR_PK	(__IA64_UL(1) << IA64_PSR_PK_BIT)
-#define IA64_PSR_DT	(__IA64_UL(1) << IA64_PSR_DT_BIT)
-#define IA64_PSR_DFL	(__IA64_UL(1) << IA64_PSR_DFL_BIT)
-#define IA64_PSR_DFH	(__IA64_UL(1) << IA64_PSR_DFH_BIT)
-#define IA64_PSR_SP	(__IA64_UL(1) << IA64_PSR_SP_BIT)
-#define IA64_PSR_PP	(__IA64_UL(1) << IA64_PSR_PP_BIT)
-#define IA64_PSR_DI	(__IA64_UL(1) << IA64_PSR_DI_BIT)
-#define IA64_PSR_SI	(__IA64_UL(1) << IA64_PSR_SI_BIT)
-#define IA64_PSR_DB	(__IA64_UL(1) << IA64_PSR_DB_BIT)
-#define IA64_PSR_LP	(__IA64_UL(1) << IA64_PSR_LP_BIT)
-#define IA64_PSR_TB	(__IA64_UL(1) << IA64_PSR_TB_BIT)
-#define IA64_PSR_RT	(__IA64_UL(1) << IA64_PSR_RT_BIT)
-/* The following are not affected by save_flags()/restore_flags(): */
-#define IA64_PSR_IS	(__IA64_UL(1) << IA64_PSR_IS_BIT)
-#define IA64_PSR_MC	(__IA64_UL(1) << IA64_PSR_MC_BIT)
-#define IA64_PSR_IT	(__IA64_UL(1) << IA64_PSR_IT_BIT)
-#define IA64_PSR_ID	(__IA64_UL(1) << IA64_PSR_ID_BIT)
-#define IA64_PSR_DA	(__IA64_UL(1) << IA64_PSR_DA_BIT)
-#define IA64_PSR_DD	(__IA64_UL(1) << IA64_PSR_DD_BIT)
-#define IA64_PSR_SS	(__IA64_UL(1) << IA64_PSR_SS_BIT)
-#define IA64_PSR_RI	(__IA64_UL(3) << IA64_PSR_RI_BIT)
-#define IA64_PSR_ED	(__IA64_UL(1) << IA64_PSR_ED_BIT)
-#define IA64_PSR_BN	(__IA64_UL(1) << IA64_PSR_BN_BIT)
-
-/* User mask bits: */
-#define IA64_PSR_UM	(IA64_PSR_BE | IA64_PSR_UP | IA64_PSR_AC | IA64_PSR_MFL | IA64_PSR_MFH)
-
-/* Default Control Register */
-#define IA64_DCR_PP_BIT		 0	/* privileged performance monitor default */
-#define IA64_DCR_BE_BIT		 1	/* big-endian default */
-#define IA64_DCR_LC_BIT		 2	/* ia32 lock-check enable */
-#define IA64_DCR_DM_BIT		 8	/* defer TLB miss faults */
-#define IA64_DCR_DP_BIT		 9	/* defer page-not-present faults */
-#define IA64_DCR_DK_BIT		10	/* defer key miss faults */
-#define IA64_DCR_DX_BIT		11	/* defer key permission faults */
-#define IA64_DCR_DR_BIT		12	/* defer access right faults */
-#define IA64_DCR_DA_BIT		13	/* defer access bit faults */
-#define IA64_DCR_DD_BIT		14	/* defer debug faults */
-
-#define IA64_DCR_PP	(__IA64_UL(1) << IA64_DCR_PP_BIT)
-#define IA64_DCR_BE	(__IA64_UL(1) << IA64_DCR_BE_BIT)
-#define IA64_DCR_LC	(__IA64_UL(1) << IA64_DCR_LC_BIT)
-#define IA64_DCR_DM	(__IA64_UL(1) << IA64_DCR_DM_BIT)
-#define IA64_DCR_DP	(__IA64_UL(1) << IA64_DCR_DP_BIT)
-#define IA64_DCR_DK	(__IA64_UL(1) << IA64_DCR_DK_BIT)
-#define IA64_DCR_DX	(__IA64_UL(1) << IA64_DCR_DX_BIT)
-#define IA64_DCR_DR	(__IA64_UL(1) << IA64_DCR_DR_BIT)
-#define IA64_DCR_DA	(__IA64_UL(1) << IA64_DCR_DA_BIT)
-#define IA64_DCR_DD	(__IA64_UL(1) << IA64_DCR_DD_BIT)
-
-/* Interrupt Status Register */
-#define IA64_ISR_X_BIT		32	/* execute access */
-#define IA64_ISR_W_BIT		33	/* write access */
-#define IA64_ISR_R_BIT		34	/* read access */
-#define IA64_ISR_NA_BIT		35	/* non-access */
-#define IA64_ISR_SP_BIT		36	/* speculative load exception */
-#define IA64_ISR_RS_BIT		37	/* mandatory register-stack exception */
-#define IA64_ISR_IR_BIT		38	/* invalid register frame exception */
-
-#define IA64_ISR_X	(__IA64_UL(1) << IA64_ISR_X_BIT)
-#define IA64_ISR_W	(__IA64_UL(1) << IA64_ISR_W_BIT)
-#define IA64_ISR_R	(__IA64_UL(1) << IA64_ISR_R_BIT)
-#define IA64_ISR_NA	(__IA64_UL(1) << IA64_ISR_NA_BIT)
-#define IA64_ISR_SP	(__IA64_UL(1) << IA64_ISR_SP_BIT)
-#define IA64_ISR_RS	(__IA64_UL(1) << IA64_ISR_RS_BIT)
-#define IA64_ISR_IR	(__IA64_UL(1) << IA64_ISR_IR_BIT)
-
 #define IA64_THREAD_FPH_VALID	(__IA64_UL(1) << 0)	/* floating-point high state valid? */
 #define IA64_THREAD_DBG_VALID	(__IA64_UL(1) << 1)	/* debug registers valid? */
 #define IA64_THREAD_PM_VALID	(__IA64_UL(1) << 2)	/* performance registers valid? */
@@ -188,6 +79,7 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/threads.h>
+#include <linux/cache.h>
 
 #include <asm/fpu.h>
 #include <asm/offsets.h>
@@ -281,10 +173,18 @@
 	__u64 ipi_count;
 	__u64 prof_counter;
 	__u64 prof_multiplier;
+# ifdef CONFIG_PERFMON
 	__u32 pfm_syst_wide;
 	__u32 pfm_dcr_pp;
-	/* this is written to by *other* CPUs: */
-	__u64 ipi_operation ____cacheline_aligned;
+# endif
+	union {
+		/*
+		 *  This is written to by *other* CPUs,
+		 *  so isolate it in its own cacheline.
+		 */
+		__u64 operation;
+		char pad[SMP_CACHE_BYTES] ____cacheline_aligned;
+	} ipi;
 #endif
 #ifdef CONFIG_NUMA
 	void *node_directory;
@@ -293,7 +193,7 @@
 #endif
 	/* Platform specific word.  MUST BE LAST IN STRUCT */
 	__u64 platform_specific;
-} __attribute__ ((aligned (PAGE_SIZE))) ;
+} __attribute__ ((aligned (PAGE_SIZE)));
 
 /*
  * The "local" data pointer.  It points to the per-CPU data of the currently executing
@@ -388,6 +288,7 @@
 	__u64 dbr[IA64_NUM_DBG_REGS];
 	__u64 ibr[IA64_NUM_DBG_REGS];
 	struct ia64_fpreg fph[96];	/* saved/loaded on demand */
+	int last_fph_cpu;
 };
 
 #define INIT_THREAD {					\
@@ -405,12 +306,8 @@
 
 #define start_thread(regs,new_ip,new_sp) do {							\
 	set_fs(USER_DS);									\
-	ia64_psr(regs)->dfh = 1;	/* disable fph */					\
-	ia64_psr(regs)->mfh = 0;	/* clear mfh */						\
-	ia64_psr(regs)->cpl = 3;	/* set user mode */					\
-	ia64_psr(regs)->ri = 0;		/* clear return slot number */				\
-	ia64_psr(regs)->is = 0;		/* IA-64 instruction set */				\
-	ia64_psr(regs)->sp = 1;		/* enforce secure perfmon */				\
+	regs->cr_ipsr = ((regs->cr_ipsr | (IA64_PSR_BITS_TO_SET | IA64_PSR_CPL | IA64_PSR_SP))	\
+			 & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_RI | IA64_PSR_IS));		\
 	regs->cr_iip = new_ip;									\
 	regs->ar_rsc = 0xf;		/* eager mode, privilege level 3 */			\
 	regs->ar_rnat = 0;									\
@@ -528,8 +425,6 @@
 	}
 }
 
-#ifndef CONFIG_SMP
-
 static inline struct task_struct *
 ia64_get_fpu_owner (void)
 {
@@ -542,8 +437,6 @@
 	ia64_set_kr(IA64_KR_FPU_OWNER, (unsigned long) t);
 }
 
-#endif /* !CONFIG_SMP */
-
 extern void __ia64_init_fpu (void);
 extern void __ia64_save_fpu (struct ia64_fpreg *fph);
 extern void __ia64_load_fpu (struct ia64_fpreg *fph);
@@ -654,9 +547,22 @@
  * interrupt enable bits.  Don't trigger any mandatory RSE references while this bit is
  * off!
  */
-#define ia64_clear_ic(flags)						\
-	asm volatile ("mov %0=psr;; rsm psr.i | psr.ic;; srlz.i;;"	\
-			      : "=r"(flags) :: "memory");
+static inline __u64
+ia64_clear_ic (void)
+{
+	__u64 psr;
+	asm volatile ("mov %0=psr;; rsm psr.i | psr.ic;; srlz.i;;" : "=r"(psr) :: "memory");
+	return psr;
+}
+
+/*
+ * Restore the psr.
+ */
+static inline void
+ia64_set_psr (__u64 psr)
+{
+	asm volatile (";; mov psr.l=%0;; srlz.d" :: "r" (psr) : "memory");
+}
 
 /*
  * Insert a translation into an instruction and/or data translation
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/sal.h linux-2.4.20/include/asm-ia64/sal.h
--- linux-2.4.19/include/asm-ia64/sal.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/sal.h	2002-10-29 11:18:39.000000000 +0000
@@ -24,9 +24,9 @@
  */
 
 #include <linux/spinlock.h>
+#include <linux/efi.h>
 
 #include <asm/pal.h>
-#include <asm/efi.h>
 #include <asm/system.h>
 #include <asm/fpu.h>
 
@@ -241,32 +241,32 @@
 
 /* SAL Error Record Section GUID Definitions */
 #define SAL_PROC_DEV_ERR_SECT_GUID  \
-    ((efi_guid_t) { 0xe429faf1, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \
-                    0xc7, 0x3c, 0x88, 0x81 }} )
+    EFI_GUID ( 0xe429faf1, 0x3cb7, 0x11d4,  0xbc, 0xa7, 0x0, 0x80, \
+                    0xc7, 0x3c, 0x88, 0x81 )
 #define SAL_PLAT_MEM_DEV_ERR_SECT_GUID  \
-    ((efi_guid_t) { 0xe429faf2, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \
-                    0xc7, 0x3c, 0x88, 0x81 }} )
+    EFI_GUID(  0xe429faf2, 0x3cb7, 0x11d4,  0xbc, 0xa7, 0x0, 0x80, \
+                    0xc7, 0x3c, 0x88, 0x81 )
 #define SAL_PLAT_SEL_DEV_ERR_SECT_GUID  \
-    ((efi_guid_t) { 0xe429faf3, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \
-                    0xc7, 0x3c, 0x88, 0x81 }} )
+    EFI_GUID(  0xe429faf3, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \
+                    0xc7, 0x3c, 0x88, 0x81 )
 #define SAL_PLAT_PCI_BUS_ERR_SECT_GUID  \
-    ((efi_guid_t) { 0xe429faf4, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \
-                    0xc7, 0x3c, 0x88, 0x81 }} )
+    EFI_GUID(  0xe429faf4, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \
+                    0xc7, 0x3c, 0x88, 0x81 )
 #define SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID  \
-    ((efi_guid_t) { 0xe429faf5, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \
-                    0xc7, 0x3c, 0x88, 0x81 }} )
+    EFI_GUID(  0xe429faf5, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \
+                    0xc7, 0x3c, 0x88, 0x81 )
 #define SAL_PLAT_PCI_COMP_ERR_SECT_GUID  \
-    ((efi_guid_t) { 0xe429faf6, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \
-                    0xc7, 0x3c, 0x88, 0x81 }} )
+    EFI_GUID(  0xe429faf6, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \
+                    0xc7, 0x3c, 0x88, 0x81 )
 #define SAL_PLAT_SPECIFIC_ERR_SECT_GUID  \
-    ((efi_guid_t) { 0xe429faf7, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \
-                    0xc7, 0x3c, 0x88, 0x81 }} )
+    EFI_GUID(  0xe429faf7, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \
+                    0xc7, 0x3c, 0x88, 0x81 )
 #define SAL_PLAT_HOST_CTLR_ERR_SECT_GUID  \
-    ((efi_guid_t) { 0xe429faf8, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \
-                    0xc7, 0x3c, 0x88, 0x81 }} )
+    EFI_GUID(  0xe429faf8, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \
+                    0xc7, 0x3c, 0x88, 0x81 )
 #define SAL_PLAT_BUS_ERR_SECT_GUID  \
-    ((efi_guid_t) { 0xe429faf9, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \
-                    0xc7, 0x3c, 0x88, 0x81 }} )
+    EFI_GUID(  0xe429faf9, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \
+                    0xc7, 0x3c, 0x88, 0x81 )
 
 #define MAX_CACHE_ERRORS			6
 #define MAX_TLB_ERRORS				6
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/semaphore.h linux-2.4.20/include/asm-ia64/semaphore.h
--- linux-2.4.19/include/asm-ia64/semaphore.h	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/semaphore.h	2002-10-29 11:18:40.000000000 +0000
@@ -117,4 +117,9 @@
 		__up(sem);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif /* _ASM_IA64_SEMAPHORE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/serial.h linux-2.4.20/include/asm-ia64/serial.h
--- linux-2.4.19/include/asm-ia64/serial.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/serial.h	2002-10-29 11:18:40.000000000 +0000
@@ -35,7 +35,9 @@
 #else
 #define RS_TABLE_SIZE
 #endif
-	
+
+#define MCA_COM_FLAGS  STD_COM_FLAGS
+
 /*
  * The following define the access methods for the HUB6 card. All
  * access is through two ports for all 24 possible chips. The card is
@@ -60,16 +62,16 @@
 	{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },	/* ttyS3 */
 
 /*
- * HCDP_SERIAL_PORT_DEFNS should be placed in exactly the same slot
- * in rs_table as defined by HCDP_SERIAL_CONSOLE_PORT in
+ * HCDP_SERIAL_PORT_DEFNS should be placed in exactly the same slot 
+ * in rs_table as defined by HCDP_SERIAL_CONSOLE_PORT in 
  * include/linux/serial.h
  */
-#define HCDP_SERIAL_PORT_DEFNS			\
+#define HCDP_SERIAL_PORT_DEFNS	\
 	{ 0, BASE_BAUD, -1, 0, STD_COM_FLAGS},		/* ttySx device
 							   in comments sucks.
 							   You add an entry
-							   and you get to edit
-							   boatloads of these
+							   and you get to edit 
+							   boatloads of these 
 							   comments. Not worth
 							   it */
 
@@ -131,12 +133,12 @@
 
 #ifdef CONFIG_MCA
 #define MCA_SERIAL_PORT_DFNS			\
-	{ 0, BASE_BAUD, 0x3220, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x3228, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x4220, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x4228, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x5220, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x5228, 3, STD_COM_FLAGS },
+	{ 0, BASE_BAUD, 0x3220, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x3228, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x4220, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x4228, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x5220, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x5228, 3, MCA_COM_FLAGS },
 #else
 #define MCA_SERIAL_PORT_DFNS
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/siginfo.h linux-2.4.20/include/asm-ia64/siginfo.h
--- linux-2.4.19/include/asm-ia64/siginfo.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/siginfo.h	2002-10-29 11:18:37.000000000 +0000
@@ -153,7 +153,8 @@
 #define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
 #define ILL_BADIADDR	(__SI_FAULT|9)	/* unimplemented instruction address */
 #define __ILL_BREAK	(__SI_FAULT|10)	/* illegal break */
-#define NSIGILL		10
+#define __ILL_BNDMOD	(__SI_FAULT|11)	/* bundle-update (modification) in progress */
+#define NSIGILL		11
 
 /*
  * SIGFPE si_codes
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/sn/sn2/shub_md.h linux-2.4.20/include/asm-ia64/sn/sn2/shub_md.h
--- linux-2.4.19/include/asm-ia64/sn/sn2/shub_md.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/sn/sn2/shub_md.h	2002-10-29 11:18:39.000000000 +0000
@@ -1,14 +1,12 @@
-/**************************************************************************
- *                                                                        *
- *  Copyright (C) 2001 Silicon Graphics, Inc. All rights reserved.        *
- *                                                                        *
- *  These coded instructions, statements, and computer programs  contain  *
- *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
- *  are protected by Federal copyright law.  They  may  not be disclosed  *
- *  to  third  parties  or copied or duplicated in any form, in whole or  *
- *  in part, without the prior written consent of Silicon Graphics, Inc.  *
- *                                                                        *
- **************************************************************************/
+/*
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2001, 2002 Silicon Graphics, Inc.  All rights reserved.
+ */
+
 
 #ifndef _SHUB_MD_H
 #define _SHUB_MD_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/socket.h linux-2.4.20/include/asm-ia64/socket.h
--- linux-2.4.19/include/asm-ia64/socket.h	2001-06-21 04:00:55.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/socket.h	2002-10-29 11:18:31.000000000 +0000
@@ -10,7 +10,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	1
 
 #define SO_DEBUG	1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/string.h linux-2.4.20/include/asm-ia64/string.h
--- linux-2.4.19/include/asm-ia64/string.h	2001-07-31 17:30:09.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/string.h	2002-10-29 11:18:36.000000000 +0000
@@ -5,8 +5,8 @@
  * Here is where we want to put optimized versions of the string
  * routines.
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000, 2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <linux/config.h>	/* remove this once we remove the A-step workaround... */
@@ -17,7 +17,7 @@
 #define __HAVE_ARCH_BCOPY	1 /* see arch/ia64/lib/memcpy.S */
 
 extern __kernel_size_t strlen (const char *);
-extern void *memset (void *, int, __kernel_size_t);
 extern void *memcpy (void *, const void *, __kernel_size_t);
+extern void *memset (void *, int, __kernel_size_t);
 
 #endif /* _ASM_IA64_STRING_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/system.h linux-2.4.20/include/asm-ia64/system.h
--- linux-2.4.19/include/asm-ia64/system.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/system.h	2002-10-29 11:18:39.000000000 +0000
@@ -14,18 +14,12 @@
  */
 #include <linux/config.h>
 
+#include <asm/kregs.h>
 #include <asm/page.h>
+#include <asm/pal.h>
 
 #define KERNEL_START		(PAGE_OFFSET + 68*1024*1024)
 
-/*
- * The following #defines must match with vmlinux.lds.S:
- */
-#define IVT_ADDR		(KERNEL_START)
-#define IVT_END_ADDR		(KERNEL_START + 0x8000)
-#define ZERO_PAGE_ADDR		PAGE_ALIGN(IVT_END_ADDR)
-#define SWAPPER_PGD_ADDR	(ZERO_PAGE_ADDR + 1*PAGE_SIZE)
-
 #define GATE_ADDR		(0xa000000000000000 + PAGE_SIZE)
 #define PERCPU_ADDR		(0xa000000000000000 + 2*PAGE_SIZE)
 
@@ -35,10 +29,11 @@
 #include <linux/types.h>
 
 struct pci_vector_struct {
+	__u16 segment;	/* PCI Segment number */
 	__u16 bus;	/* PCI Bus number */
 	__u32 pci_id;	/* ACPI split 16 bits device, 16 bits function (see section 6.1.1) */
 	__u8 pin;	/* PCI PIN (0 = A, 1 = B, 2 = C, 3 = D) */
-	__u8 irq;	/* IRQ assigned */
+	__u32 irq;	/* IRQ assigned */
 };
 
 extern struct ia64_boot_param {
@@ -109,6 +104,8 @@
 #define set_mb(var, value)	do { (var) = (value); mb(); } while (0)
 #define set_wmb(var, value)	do { (var) = (value); mb(); } while (0)
 
+#define safe_halt()         ia64_pal_halt(1)                /* PAL_HALT */
+
 /*
  * The group barrier in front of the rsm & ssm are necessary to ensure
  * that none of the previous instructions in the same group are
@@ -143,16 +140,21 @@
 	}										\
 } while (0)
 
-# define local_irq_restore(x)						 \
-do {									 \
-	unsigned long ip, old_psr, psr = (x);				 \
-									 \
-	__asm__ __volatile__ (";;mov %0=psr; mov psr.l=%1;; srlz.d"	 \
-			      : "=&r" (old_psr) : "r" (psr) : "memory"); \
-	if ((old_psr & (1UL << 14)) && !(psr & (1UL << 14))) {		 \
-		__asm__ ("mov %0=ip" : "=r"(ip));			 \
-		last_cli_ip = ip;					 \
-	}								 \
+# define local_irq_restore(x)							\
+do {										\
+	unsigned long ip, old_psr, psr = (x);					\
+										\
+	__asm__ __volatile__ ("mov %0=psr;"					\
+			      "cmp.ne p6,p7=%1,r0;;"				\
+			      "(p6) ssm psr.i;"					\
+			      "(p7) rsm psr.i;;"				\
+			      "srlz.d"						\
+			      : "=&r" (old_psr) : "r"((psr) & IA64_PSR_I)	\
+			      : "p6", "p7", "memory");				\
+	if ((old_psr & IA64_PSR_I) && !(psr & IA64_PSR_I)) {			\
+		__asm__ ("mov %0=ip" : "=r"(ip));				\
+		last_cli_ip = ip;						\
+	}									\
 } while (0)
 
 #else /* !CONFIG_IA64_DEBUG_IRQ */
@@ -161,8 +163,12 @@
 						      : "=r" (x) :: "memory")
 # define local_irq_disable()	__asm__ __volatile__ (";; rsm psr.i;;" ::: "memory")
 /* (potentially) setting psr.i requires data serialization: */
-# define local_irq_restore(x)	__asm__ __volatile__ (";; mov psr.l=%0;; srlz.d"	\
-						      :: "r" (x) : "memory")
+# define local_irq_restore(x)	__asm__ __volatile__ ("cmp.ne p6,p7=%0,r0;;"		\
+						      "(p6) ssm psr.i;"			\
+						      "(p7) rsm psr.i;;"		\
+						      "srlz.d"				\
+						      :: "r"((x) & IA64_PSR_I)		\
+						      : "p6", "p7", "memory")
 #endif /* !CONFIG_IA64_DEBUG_IRQ */
 
 #define local_irq_enable()	__asm__ __volatile__ (";; ssm psr.i;; srlz.d" ::: "memory")
@@ -395,26 +401,39 @@
 } while (0)
 
 #ifdef CONFIG_SMP
-  /*
-   * In the SMP case, we save the fph state when context-switching
-   * away from a thread that modified fph.  This way, when the thread
-   * gets scheduled on another CPU, the CPU can pick up the state from
-   * task->thread.fph, avoiding the complication of having to fetch
-   * the latest fph state from another CPU.
-   */
-# define switch_to(prev,next,last) do {						\
-	if (ia64_psr(ia64_task_regs(prev))->mfh) {				\
-		ia64_psr(ia64_task_regs(prev))->mfh = 0;			\
-		(prev)->thread.flags |= IA64_THREAD_FPH_VALID;			\
-		__ia64_save_fpu((prev)->thread.fph);				\
-	}									\
-	ia64_psr(ia64_task_regs(prev))->dfh = 1;				\
-	__switch_to(prev,next,last);						\
+
+/* Return true if this CPU can call the console drivers in printk() */
+#define arch_consoles_callable() (cpu_online_map & (1UL << smp_processor_id()))
+
+/*
+ * In the SMP case, we save the fph state when context-switching
+ * away from a thread that modified fph.  This way, when the thread
+ * gets scheduled on another CPU, the CPU can pick up the state from
+ * task->thread.fph, avoiding the complication of having to fetch
+ * the latest fph state from another CPU.
+ */
+# define switch_to(prev,next,last) do {					\
+	if (ia64_psr(ia64_task_regs(prev))->mfh) {			\
+		ia64_psr(ia64_task_regs(prev))->mfh = 0;		\
+		(prev)->thread.flags |= IA64_THREAD_FPH_VALID;		\
+		__ia64_save_fpu((prev)->thread.fph);			\
+		(prev)->thread.last_fph_cpu = smp_processor_id();	\
+	}								\
+	if ((next)->thread.flags & IA64_THREAD_FPH_VALID) {		\
+		if (((next)->thread.last_fph_cpu == smp_processor_id()) \
+		    && (ia64_get_fpu_owner() == next)) {		\
+			ia64_psr(ia64_task_regs(next))->dfh = 0;	\
+			ia64_psr(ia64_task_regs(next))->mfh = 0;	\
+		} else {						\
+			ia64_psr(ia64_task_regs(next))->dfh = 1;	\
+		}							\
+	}								\
+	__switch_to(prev,next,last);					\
   } while (0)
 #else
-# define switch_to(prev,next,last) do {						\
+# define switch_to(prev,next,last) do {					\
 	ia64_psr(ia64_task_regs(next))->dfh = (ia64_get_fpu_owner() != (next));	\
-	__switch_to(prev,next,last);						\
+	__switch_to(prev,next,last);					\
 } while (0)
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/termios.h linux-2.4.20/include/asm-ia64/termios.h
--- linux-2.4.19/include/asm-ia64/termios.h	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/termios.h	2002-10-29 11:18:48.000000000 +0000
@@ -44,6 +44,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
 /* line disciplines */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/timex.h linux-2.4.20/include/asm-ia64/timex.h
--- linux-2.4.19/include/asm-ia64/timex.h	2001-04-05 19:51:47.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/timex.h	2002-10-29 11:18:35.000000000 +0000
@@ -21,4 +21,7 @@
 	return ret;
 }
 
+#define vxtime_lock()		do {} while (0)
+#define vxtime_unlock()		do {} while (0)
+
 #endif /* _ASM_IA64_TIMEX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/uaccess.h linux-2.4.20/include/asm-ia64/uaccess.h
--- linux-2.4.19/include/asm-ia64/uaccess.h	2001-04-05 19:51:47.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/uaccess.h	2002-10-29 11:18:36.000000000 +0000
@@ -320,4 +320,22 @@
 extern struct exception_fixup search_exception_table (unsigned long addr);
 extern void handle_exception (struct pt_regs *regs, struct exception_fixup fixup);
 
+#ifdef GAS_HAS_LOCAL_TAGS
+#define SEARCH_EXCEPTION_TABLE(regs) search_exception_table(regs->cr_iip + ia64_psr(regs)->ri);
+#else
+#define SEARCH_EXCEPTION_TABLE(regs) search_exception_table(regs->cr_iip);
+#endif
+
+static inline int
+done_with_exception (struct pt_regs *regs)
+{
+	struct exception_fixup fix;
+	fix = SEARCH_EXCEPTION_TABLE(regs);
+	if (fix.cont) {
+		handle_exception(regs, fix);
+		return 1;
+	}
+	return 0;
+}
+
 #endif /* _ASM_IA64_UACCESS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/unistd.h linux-2.4.20/include/asm-ia64/unistd.h
--- linux-2.4.19/include/asm-ia64/unistd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/unistd.h	2002-10-29 11:18:33.000000000 +0000
@@ -206,7 +206,12 @@
 #define __NR_getdents64			1214
 #define __NR_getunwind			1215
 #define __NR_readahead			1216
+/*
+ * 1217-1228: reserved for xattr
+ * 1230-1232: reserved for futex and sched_[sg]etaffinity.
+ */
 #define __NR_tkill			1229
+#define __NR_security			1233 /* syscall for security modules */
 
 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ia64/vga.h linux-2.4.20/include/asm-ia64/vga.h
--- linux-2.4.19/include/asm-ia64/vga.h	2000-02-07 02:42:40.000000000 +0000
+++ linux-2.4.20/include/asm-ia64/vga.h	2002-10-29 11:18:40.000000000 +0000
@@ -1,22 +1,39 @@
+#ifndef _ASM_IA64_VGA_H
+#define _ASM_IA64_VGA_H
+
 /*
  *	Access to VGA videoram
  *
  *	(c) 1998 Martin Mares <mj@ucw.cz>
  *	(c) 1999 Asit Mallick <asit.k.mallick@intel.com>
  *	(c) 1999 Don Dugger <don.dugger@intel.com>
+ *	Copyright (C) 2002 Hewlett-Packard Co
  */
-
-#ifndef __ASM_IA64_VGA_H_
-#define __ASM_IA64_VGA_H_
-
 /*
- * On the PC, we can just recalculate addresses and then access the
- * videoram directly without any black magic.
+ * 2002/07/19	davidm@hpl.hp.com	Access frame-buffer memory via readX/writeX.
  */
 
+#include <asm/io.h>
+
+#define VT_BUF_HAVE_RW
+
 #define VGA_MAP_MEM(x)	((unsigned long) ioremap((x), 0))
 
-#define vga_readb(x)	(*(x))
-#define vga_writeb(x,y)	(*(y) = (x))
+#define vga_readb	__raw_readb
+#define vga_writeb	__raw_writeb
+
+extern inline void
+scr_writew (u16 val, volatile u16 *addr)
+{
+	/* Note: ADDR may point to normal memory.  That's OK on ia64.  */
+	__raw_writew(val, (unsigned long) addr);
+}
+
+extern inline u16
+scr_readw (volatile const u16 *addr)
+{
+	/* Note: ADDR may point to normal memory.  That's OK on ia64.  */
+	return __raw_readw((unsigned long) addr);
+}
 
-#endif /* __ASM_IA64_VGA_H_ */
+#endif /* _ASM_IA64_VGA_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-m68k/apollodma.h linux-2.4.20/include/asm-m68k/apollodma.h
--- linux-2.4.19/include/asm-m68k/apollodma.h	2000-01-28 16:04:58.000000000 +0000
+++ linux-2.4.20/include/asm-m68k/apollodma.h	2002-10-29 11:18:40.000000000 +0000
@@ -9,7 +9,7 @@
 #define _ASM_APOLLO_DMA_H
 
 #include <asm/apollohw.h>		/* need byte IO */
-#include <asm/spinlock.h>	/* And spinlocks */
+#include <linux/spinlock.h>		/* And spinlocks */
 #include <linux/delay.h>
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-m68k/io.h linux-2.4.20/include/asm-m68k/io.h
--- linux-2.4.19/include/asm-m68k/io.h	2001-10-25 20:53:55.000000000 +0000
+++ linux-2.4.20/include/asm-m68k/io.h	2002-10-29 11:18:48.000000000 +0000
@@ -240,7 +240,7 @@
 #define readb   isa_readb
 #define readw   isa_readw
 #define writeb  isa_writeb
-#define writew  isa_writeb
+#define writew  isa_writew
 #endif /* CONFIG_ISA */
 
 #if defined(CONFIG_PCI)
@@ -286,6 +286,11 @@
 #define IOMAP_NOCACHE_NONSER		2
 #define IOMAP_WRITETHROUGH		3
 
+/*
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
+
 extern void iounmap(void *addr);
 
 extern void *__ioremap(unsigned long physaddr, unsigned long size,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-m68k/irq.h linux-2.4.20/include/asm-m68k/irq.h
--- linux-2.4.19/include/asm-m68k/irq.h	2000-02-13 19:21:42.000000000 +0000
+++ linux-2.4.20/include/asm-m68k/irq.h	2002-10-29 11:18:49.000000000 +0000
@@ -83,7 +83,7 @@
  * mechanism like all other architectures - SA_INTERRUPT and SA_SHIRQ
  * are your friends.
  */
-#ifndef CONFIG_AMIGA
+#ifndef MACH_AMIGA_ONLY
 #define IRQ_FLG_LOCK	(0x0001)	/* handler is not replaceable	*/
 #define IRQ_FLG_REPLACE	(0x0002)	/* replace existing handler	*/
 #define IRQ_FLG_FAST	(0x0004)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-m68k/mac_via.h linux-2.4.20/include/asm-m68k/mac_via.h
--- linux-2.4.19/include/asm-m68k/mac_via.h	1999-09-04 20:06:41.000000000 +0000
+++ linux-2.4.20/include/asm-m68k/mac_via.h	2002-10-29 11:18:31.000000000 +0000
@@ -3,7 +3,7 @@
  *
  *	There are two of these on the Mac II. Some IRQ's are vectored
  *	via them as are assorted bits and bobs - eg rtc, adb. The picture
- *	is a bit incomplete as the Mac documentation doesnt cover this well
+ *	is a bit incomplete as the Mac documentation doesn't cover this well
  */
  
 #ifndef _ASM_MAC_VIA_H_
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-m68k/machw.h linux-2.4.20/include/asm-m68k/machw.h
--- linux-2.4.19/include/asm-m68k/machw.h	1999-09-04 20:06:41.000000000 +0000
+++ linux-2.4.20/include/asm-m68k/machw.h	2002-10-29 11:18:35.000000000 +0000
@@ -68,11 +68,11 @@
 
 /* hardware stuff */
 
-#define MACHW_DECLARE(name)    unsigned name : 1
-#define MACHW_SET(name)                (mac_hw_present.name = 1)
-#define MACHW_PRESENT(name)    (mac_hw_present.name)
+#define MACHW_DECLARE(name)	unsigned name : 1
+#define MACHW_SET(name)		(mac_hw_present.name = 1)
+#define MACHW_PRESENT(name)	(mac_hw_present.name)
 
-struct {
+struct mac_hw_present {
   /* video hardware */
   /* sound hardware */
   /* disk storage interfaces */
@@ -92,9 +92,9 @@
   MACHW_DECLARE(RBV);             /* Versatile Interface Ad. 2+ */
   /* NUBUS */
   MACHW_DECLARE(NUBUS);           /* NUBUS */
-} mac_hw_present;
+};
 
-/* extern struct mac_hw_present mac_hw_present; */
+extern struct mac_hw_present mac_hw_present;
 
 #endif /* __ASSEMBLY__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-m68k/macintosh.h linux-2.4.20/include/asm-m68k/macintosh.h
--- linux-2.4.19/include/asm-m68k/macintosh.h	2000-02-13 19:21:42.000000000 +0000
+++ linux-2.4.20/include/asm-m68k/macintosh.h	2002-10-29 11:18:31.000000000 +0000
@@ -37,9 +37,6 @@
  *	Macintosh Table
  */
  
-struct mac_model *macintosh_config;
-
-
 struct mac_model
 {
 	short ident;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-m68k/nubus.h linux-2.4.20/include/asm-m68k/nubus.h
--- linux-2.4.19/include/asm-m68k/nubus.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-m68k/nubus.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,46 @@
+#ifndef _ASM_M68K_NUBUS_H
+#define _ASM_M68K_NUBUS_H
+
+#include <asm/io.h>
+
+#define nubus_readb raw_inb
+#define nubus_readw raw_inw
+#define nubus_readl raw_inl
+
+#define nubus_writeb raw_outb
+#define nubus_writew raw_outw
+#define nubus_writel raw_outl
+
+#define nubus_memset_io(a,b,c)		memset((void *)(a),(b),(c))
+#define nubus_memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
+#define nubus_memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
+
+extern inline void *nubus_remap_nocache_ser(unsigned long physaddr,
+					    unsigned long size)
+{
+	return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
+}
+
+extern inline void *nubus_remap_nocache_nonser(unsigned long physaddr,
+					       unsigned long size)
+{
+	return __ioremap(physaddr, size, IOMAP_NOCACHE_NONSER);
+}
+
+extern inline void *nbus_remap_writethrough(unsigned long physaddr,
+					    unsigned long size)
+{
+	return __ioremap(physaddr, size, IOMAP_WRITETHROUGH);
+}
+
+extern inline void *nubus_remap_fullcache(unsigned long physaddr,
+					  unsigned long size)
+{
+	return __ioremap(physaddr, size, IOMAP_FULL_CACHING);
+}
+
+#define nubus_unmap iounmap
+#define nubus_iounmap iounmap
+#define nubus_ioremap nubus_remap_nocache_ser
+
+#endif /* _ASM_NUBUS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-m68k/pci.h linux-2.4.20/include/asm-m68k/pci.h
--- linux-2.4.19/include/asm-m68k/pci.h	2001-05-16 17:31:27.000000000 +0000
+++ linux-2.4.20/include/asm-m68k/pci.h	2002-10-29 11:18:40.000000000 +0000
@@ -48,4 +48,10 @@
 /* Return the index of the PCI controller for device PDEV. */
 #define pci_controller_num(PDEV)	(0)
 
+/* The PCI address space does equal the physical memory
+ * address space.  The networking and block device layers use
+ * this boolean for bounce buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS	(1)
+
 #endif /* _ASM_M68K_PCI_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-m68k/q40_keyboard.h linux-2.4.20/include/asm-m68k/q40_keyboard.h
--- linux-2.4.19/include/asm-m68k/q40_keyboard.h	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.20/include/asm-m68k/q40_keyboard.h	2002-10-29 11:18:50.000000000 +0000
@@ -20,7 +20,7 @@
 extern char q40kbd_unexpected_up(unsigned char keycode);
 extern void q40kbd_leds(unsigned char leds);
 extern int q40kbd_is_sysrq(unsigned char keycode);
-extern void q40kbd_init_hw(void);
+extern int q40kbd_init_hw(void);
 extern unsigned char q40kbd_sysrq_xlate[128];
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-m68k/raw_io.h linux-2.4.20/include/asm-m68k/raw_io.h
--- linux-2.4.19/include/asm-m68k/raw_io.h	2001-10-25 20:53:55.000000000 +0000
+++ linux-2.4.20/include/asm-m68k/raw_io.h	2002-10-29 11:18:48.000000000 +0000
@@ -20,10 +20,16 @@
     ({ unsigned short __v = (*(volatile unsigned short *) (addr)); __v; })
 #define in_be32(addr) \
     ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; })
+#define in_le16(addr) \
+    ({ unsigned short __v = le16_to_cpu(*(volatile unsigned short *) (addr)); __v; })
+#define in_le32(addr) \
+    ({ unsigned int __v = le32_to_cpu(*(volatile unsigned int *) (addr)); __v; })
 
 #define out_8(addr,b) (void)((*(volatile unsigned char *) (addr)) = (b))
-#define out_be16(addr,b) (void)((*(volatile unsigned short *) (addr)) = (b))
-#define out_be32(addr,b) (void)((*(volatile unsigned int *) (addr)) = (b))
+#define out_be16(addr,w) (void)((*(volatile unsigned short *) (addr)) = (w))
+#define out_be32(addr,l) (void)((*(volatile unsigned int *) (addr)) = (l))
+#define out_le16(addr,w) (void)((*(volatile unsigned short *) (addr)) = cpu_to_le16(w))
+#define out_le32(addr,l) (void)((*(volatile unsigned int *) (addr)) = cpu_to_le32(l))
 
 #define raw_inb in_8
 #define raw_inw in_be16
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-m68k/semaphore.h linux-2.4.20/include/asm-m68k/semaphore.h
--- linux-2.4.19/include/asm-m68k/semaphore.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-m68k/semaphore.h	2002-10-29 11:18:40.000000000 +0000
@@ -182,6 +182,12 @@
 		: "memory");
 }
 
+
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif /* __ASSEMBLY__ */
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-m68k/socket.h linux-2.4.20/include/asm-m68k/socket.h
--- linux-2.4.19/include/asm-m68k/socket.h	2001-06-21 04:00:55.000000000 +0000
+++ linux-2.4.20/include/asm-m68k/socket.h	2002-10-29 11:18:34.000000000 +0000
@@ -3,7 +3,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	1
 
 #define SO_DEBUG	1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-m68k/termios.h linux-2.4.20/include/asm-m68k/termios.h
--- linux-2.4.19/include/asm-m68k/termios.h	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.20/include/asm-m68k/termios.h	2002-10-29 11:18:32.000000000 +0000
@@ -47,6 +47,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
 /* line disciplines */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-m68k/timex.h linux-2.4.20/include/asm-m68k/timex.h
--- linux-2.4.19/include/asm-m68k/timex.h	1999-01-05 19:20:43.000000000 +0000
+++ linux-2.4.20/include/asm-m68k/timex.h	2002-10-29 11:18:32.000000000 +0000
@@ -19,4 +19,7 @@
 	return 0;
 }
 
+#define vxtime_lock()		do {} while (0)
+#define vxtime_unlock()		do {} while (0)
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-m68k/types.h linux-2.4.20/include/asm-m68k/types.h
--- linux-2.4.19/include/asm-m68k/types.h	2000-11-28 02:00:49.000000000 +0000
+++ linux-2.4.20/include/asm-m68k/types.h	2002-10-29 11:18:30.000000000 +0000
@@ -49,9 +49,10 @@
 
 #define BITS_PER_LONG 32
 
-/* DMA addresses are 32-bits wide */
+/* DMA addresses are always 32-bits wide */
 
 typedef u32 dma_addr_t;
+typedef u32 dma64_addr_t;
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-m68k/unistd.h linux-2.4.20/include/asm-m68k/unistd.h
--- linux-2.4.19/include/asm-m68k/unistd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-m68k/unistd.h	2002-10-29 11:18:40.000000000 +0000
@@ -225,6 +225,18 @@
 #define __NR_getdents64		220
 #define __NR_gettid		221
 #define __NR_tkill		222
+#define __NR_setxattr		223
+#define __NR_lsetxattr		224
+#define __NR_fsetxattr		225
+#define __NR_getxattr		226
+#define __NR_lgetxattr		227
+#define __NR_fgetxattr		228
+#define __NR_listxattr		229
+#define __NR_llistxattr		230
+#define __NR_flistxattr		231
+#define __NR_removexattr	232
+#define __NR_lremovexattr	233
+#define __NR_fremovexattr	234
 
 /* user-visible error numbers are in the range -1 - -122: see
    <asm-m68k/errno.h> */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/addrspace.h linux-2.4.20/include/asm-mips/addrspace.h
--- linux-2.4.19/include/asm-mips/addrspace.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/addrspace.h	2002-10-29 11:18:31.000000000 +0000
@@ -92,7 +92,7 @@
 #define K_CALG_NOTUSED		6
 #define K_CALG_UNCACHED_ACCEL	7
 
-#define TO_PHYS_MASK		0xfffffffff			/* 36 bit */
+#define TO_PHYS_MASK			0xfffffffffULL		/* 36 bit */
 
 /*
  * 64-bit address conversions
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/asm.h linux-2.4.20/include/asm-mips/asm.h
--- linux-2.4.19/include/asm-mips/asm.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/asm.h	2002-10-29 11:18:30.000000000 +0000
@@ -96,7 +96,7 @@
 #define	PANIC(msg)                                      \
 		.set	push;				\
 		.set	reorder;                        \
-		la	a0,8f;                          \
+		PTR_LA	a0,8f;                          \
 		jal	panic;                          \
 9:		b	9b;                             \
 		.set	pop;				\
@@ -108,7 +108,7 @@
 #define PRINT(string)                                   \
 		.set	push;				\
 		.set	reorder;                        \
-		la	a0,8f;                          \
+		PTR_LA	a0,8f;                          \
 		jal	printk;                         \
 		.set	pop;				\
 		TEXT(string)
@@ -172,7 +172,7 @@
 		.set	push;				\
 		.set	reorder;			\
 		bnez	rt,9f;                          \
-		move	rd,rt;                          \
+		move	rd,rs;                          \
 		.set	pop;				\
 9:
 #endif /* _MIPS_ISA == _MIPS_ISA_MIPS1 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/asmmacro.h linux-2.4.20/include/asm-mips/asmmacro.h
--- linux-2.4.19/include/asm-mips/asmmacro.h	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/include/asm-mips/asmmacro.h	2002-10-29 11:18:49.000000000 +0000
@@ -7,8 +7,22 @@
 #ifndef _ASM_ASMMACRO_H
 #define _ASM_ASMMACRO_H
 
+#include <linux/config.h>
 #include <asm/offset.h>
 
+#ifdef CONFIG_CPU_SB1
+#define FPU_ENABLE_HAZARD		\
+	.set	push;			\
+	.set	noreorder;		\
+	.set	mips2;			\
+	SSNOP;				\
+	bnezl	$0, .+4;		\
+	 SSNOP;				\
+	.set	pop
+#else
+#define FPU_ENABLE_HAZARD
+#endif
+
 #define FPU_SAVE_DOUBLE(thread, tmp) \
 	cfc1	tmp,  fcr31;                    \
 	sdc1	$f0,  (THREAD_FPU + 0x000)(thread); \
@@ -29,41 +43,79 @@
 	sdc1	$f30, (THREAD_FPU + 0x0f0)(thread); \
 	sw	tmp,  (THREAD_FPU + 0x100)(thread)
 
+#ifdef __LITTLE_ENDIAN
 #define FPU_SAVE_SINGLE(thread,tmp)                 \
 	cfc1	tmp,  fcr31;                        \
 	swc1	$f0,  (THREAD_FPU + 0x000)(thread); \
-	swc1	$f1,  (THREAD_FPU + 0x008)(thread); \
+	swc1	$f1,  (THREAD_FPU + 0x004)(thread); \
 	swc1	$f2,  (THREAD_FPU + 0x010)(thread); \
-	swc1	$f3,  (THREAD_FPU + 0x018)(thread); \
+	swc1	$f3,  (THREAD_FPU + 0x014)(thread); \
 	swc1	$f4,  (THREAD_FPU + 0x020)(thread); \
-	swc1	$f5,  (THREAD_FPU + 0x028)(thread); \
+	swc1	$f5,  (THREAD_FPU + 0x024)(thread); \
 	swc1	$f6,  (THREAD_FPU + 0x030)(thread); \
-	swc1	$f7,  (THREAD_FPU + 0x038)(thread); \
+	swc1	$f7,  (THREAD_FPU + 0x034)(thread); \
 	swc1	$f8,  (THREAD_FPU + 0x040)(thread); \
-	swc1	$f9,  (THREAD_FPU + 0x048)(thread); \
+	swc1	$f9,  (THREAD_FPU + 0x044)(thread); \
 	swc1	$f10, (THREAD_FPU + 0x050)(thread); \
-	swc1	$f11, (THREAD_FPU + 0x058)(thread); \
+	swc1	$f11, (THREAD_FPU + 0x054)(thread); \
 	swc1	$f12, (THREAD_FPU + 0x060)(thread); \
-	swc1	$f13, (THREAD_FPU + 0x068)(thread); \
+	swc1	$f13, (THREAD_FPU + 0x064)(thread); \
 	swc1	$f14, (THREAD_FPU + 0x070)(thread); \
-	swc1	$f15, (THREAD_FPU + 0x078)(thread); \
+	swc1	$f15, (THREAD_FPU + 0x074)(thread); \
 	swc1	$f16, (THREAD_FPU + 0x080)(thread); \
-	swc1	$f17, (THREAD_FPU + 0x088)(thread); \
+	swc1	$f17, (THREAD_FPU + 0x084)(thread); \
 	swc1	$f18, (THREAD_FPU + 0x090)(thread); \
-	swc1	$f19, (THREAD_FPU + 0x098)(thread); \
+	swc1	$f19, (THREAD_FPU + 0x094)(thread); \
 	swc1	$f20, (THREAD_FPU + 0x0a0)(thread); \
-	swc1	$f21, (THREAD_FPU + 0x0a8)(thread); \
+	swc1	$f21, (THREAD_FPU + 0x0a4)(thread); \
 	swc1	$f22, (THREAD_FPU + 0x0b0)(thread); \
-	swc1	$f23, (THREAD_FPU + 0x0b8)(thread); \
+	swc1	$f23, (THREAD_FPU + 0x0b4)(thread); \
 	swc1	$f24, (THREAD_FPU + 0x0c0)(thread); \
-	swc1	$f25, (THREAD_FPU + 0x0c8)(thread); \
+	swc1	$f25, (THREAD_FPU + 0x0c4)(thread); \
 	swc1	$f26, (THREAD_FPU + 0x0d0)(thread); \
-	swc1	$f27, (THREAD_FPU + 0x0d8)(thread); \
+	swc1	$f27, (THREAD_FPU + 0x0d4)(thread); \
 	swc1	$f28, (THREAD_FPU + 0x0e0)(thread); \
-	swc1	$f29, (THREAD_FPU + 0x0e8)(thread); \
+	swc1	$f29, (THREAD_FPU + 0x0e4)(thread); \
 	swc1	$f30, (THREAD_FPU + 0x0f0)(thread); \
-	swc1	$f31, (THREAD_FPU + 0x0f8)(thread); \
+	swc1	$f31, (THREAD_FPU + 0x0f4)(thread); \
+	sw	tmp,  (THREAD_FPU + 0x100)(thread)
+#else
+#define FPU_SAVE_SINGLE(thread,tmp)                 \
+	cfc1	tmp,  fcr31;                        \
+	swc1	$f0,  (THREAD_FPU + 0x004)(thread); \
+	swc1	$f1,  (THREAD_FPU + 0x000)(thread); \
+	swc1	$f2,  (THREAD_FPU + 0x014)(thread); \
+	swc1	$f3,  (THREAD_FPU + 0x010)(thread); \
+	swc1	$f4,  (THREAD_FPU + 0x024)(thread); \
+	swc1	$f5,  (THREAD_FPU + 0x020)(thread); \
+	swc1	$f6,  (THREAD_FPU + 0x034)(thread); \
+	swc1	$f7,  (THREAD_FPU + 0x030)(thread); \
+	swc1	$f8,  (THREAD_FPU + 0x044)(thread); \
+	swc1	$f9,  (THREAD_FPU + 0x040)(thread); \
+	swc1	$f10, (THREAD_FPU + 0x054)(thread); \
+	swc1	$f11, (THREAD_FPU + 0x050)(thread); \
+	swc1	$f12, (THREAD_FPU + 0x064)(thread); \
+	swc1	$f13, (THREAD_FPU + 0x060)(thread); \
+	swc1	$f14, (THREAD_FPU + 0x074)(thread); \
+	swc1	$f15, (THREAD_FPU + 0x070)(thread); \
+	swc1	$f16, (THREAD_FPU + 0x084)(thread); \
+	swc1	$f17, (THREAD_FPU + 0x080)(thread); \
+	swc1	$f18, (THREAD_FPU + 0x094)(thread); \
+	swc1	$f19, (THREAD_FPU + 0x090)(thread); \
+	swc1	$f20, (THREAD_FPU + 0x0a4)(thread); \
+	swc1	$f21, (THREAD_FPU + 0x0a0)(thread); \
+	swc1	$f22, (THREAD_FPU + 0x0b4)(thread); \
+	swc1	$f23, (THREAD_FPU + 0x0b0)(thread); \
+	swc1	$f24, (THREAD_FPU + 0x0c4)(thread); \
+	swc1	$f25, (THREAD_FPU + 0x0c0)(thread); \
+	swc1	$f26, (THREAD_FPU + 0x0d4)(thread); \
+	swc1	$f27, (THREAD_FPU + 0x0d0)(thread); \
+	swc1	$f28, (THREAD_FPU + 0x0e4)(thread); \
+	swc1	$f29, (THREAD_FPU + 0x0e0)(thread); \
+	swc1	$f30, (THREAD_FPU + 0x0f4)(thread); \
+	swc1	$f31, (THREAD_FPU + 0x0f0)(thread); \
 	sw	tmp,  (THREAD_FPU + 0x100)(thread)
+#endif
 
 #define FPU_RESTORE_DOUBLE(thread, tmp) \
 	lw	tmp,  (THREAD_FPU + 0x100)(thread); \
@@ -85,41 +137,79 @@
 	ldc1	$f30, (THREAD_FPU + 0x0f0)(thread); \
 	ctc1	tmp,  fcr31
 
+#ifdef __LITTLE_ENDIAN
 #define FPU_RESTORE_SINGLE(thread,tmp)              \
 	lw	tmp,  (THREAD_FPU + 0x100)(thread); \
 	lwc1	$f0,  (THREAD_FPU + 0x000)(thread); \
-	lwc1	$f1,  (THREAD_FPU + 0x008)(thread); \
+	lwc1	$f1,  (THREAD_FPU + 0x004)(thread); \
 	lwc1	$f2,  (THREAD_FPU + 0x010)(thread); \
-	lwc1	$f3,  (THREAD_FPU + 0x018)(thread); \
+	lwc1	$f3,  (THREAD_FPU + 0x014)(thread); \
 	lwc1	$f4,  (THREAD_FPU + 0x020)(thread); \
-	lwc1	$f5,  (THREAD_FPU + 0x028)(thread); \
+	lwc1	$f5,  (THREAD_FPU + 0x024)(thread); \
 	lwc1	$f6,  (THREAD_FPU + 0x030)(thread); \
-	lwc1	$f7,  (THREAD_FPU + 0x038)(thread); \
+	lwc1	$f7,  (THREAD_FPU + 0x034)(thread); \
 	lwc1	$f8,  (THREAD_FPU + 0x040)(thread); \
-	lwc1	$f9,  (THREAD_FPU + 0x048)(thread); \
+	lwc1	$f9,  (THREAD_FPU + 0x044)(thread); \
 	lwc1	$f10, (THREAD_FPU + 0x050)(thread); \
-	lwc1	$f11, (THREAD_FPU + 0x058)(thread); \
+	lwc1	$f11, (THREAD_FPU + 0x054)(thread); \
 	lwc1	$f12, (THREAD_FPU + 0x060)(thread); \
-	lwc1	$f13, (THREAD_FPU + 0x068)(thread); \
+	lwc1	$f13, (THREAD_FPU + 0x064)(thread); \
 	lwc1	$f14, (THREAD_FPU + 0x070)(thread); \
-	lwc1	$f15, (THREAD_FPU + 0x078)(thread); \
+	lwc1	$f15, (THREAD_FPU + 0x074)(thread); \
 	lwc1	$f16, (THREAD_FPU + 0x080)(thread); \
-	lwc1	$f17, (THREAD_FPU + 0x088)(thread); \
+	lwc1	$f17, (THREAD_FPU + 0x084)(thread); \
 	lwc1	$f18, (THREAD_FPU + 0x090)(thread); \
-	lwc1	$f19, (THREAD_FPU + 0x098)(thread); \
+	lwc1	$f19, (THREAD_FPU + 0x094)(thread); \
 	lwc1	$f20, (THREAD_FPU + 0x0a0)(thread); \
-	lwc1	$f21, (THREAD_FPU + 0x0a8)(thread); \
+	lwc1	$f21, (THREAD_FPU + 0x0a4)(thread); \
 	lwc1	$f22, (THREAD_FPU + 0x0b0)(thread); \
-	lwc1	$f23, (THREAD_FPU + 0x0b8)(thread); \
+	lwc1	$f23, (THREAD_FPU + 0x0b4)(thread); \
 	lwc1	$f24, (THREAD_FPU + 0x0c0)(thread); \
-	lwc1	$f25, (THREAD_FPU + 0x0c8)(thread); \
+	lwc1	$f25, (THREAD_FPU + 0x0c4)(thread); \
 	lwc1	$f26, (THREAD_FPU + 0x0d0)(thread); \
-	lwc1	$f27, (THREAD_FPU + 0x0d8)(thread); \
+	lwc1	$f27, (THREAD_FPU + 0x0d4)(thread); \
 	lwc1	$f28, (THREAD_FPU + 0x0e0)(thread); \
-	lwc1	$f29, (THREAD_FPU + 0x0e8)(thread); \
+	lwc1	$f29, (THREAD_FPU + 0x0e4)(thread); \
 	lwc1	$f30, (THREAD_FPU + 0x0f0)(thread); \
-	lwc1	$f31, (THREAD_FPU + 0x0f8)(thread); \
+	lwc1	$f31, (THREAD_FPU + 0x0f4)(thread); \
+	ctc1	tmp,  fcr31
+#else
+#define FPU_RESTORE_SINGLE(thread,tmp)              \
+	lw	tmp,  (THREAD_FPU + 0x100)(thread); \
+	lwc1	$f0,  (THREAD_FPU + 0x004)(thread); \
+	lwc1	$f1,  (THREAD_FPU + 0x000)(thread); \
+	lwc1	$f2,  (THREAD_FPU + 0x014)(thread); \
+	lwc1	$f3,  (THREAD_FPU + 0x010)(thread); \
+	lwc1	$f4,  (THREAD_FPU + 0x024)(thread); \
+	lwc1	$f5,  (THREAD_FPU + 0x020)(thread); \
+	lwc1	$f6,  (THREAD_FPU + 0x034)(thread); \
+	lwc1	$f7,  (THREAD_FPU + 0x030)(thread); \
+	lwc1	$f8,  (THREAD_FPU + 0x044)(thread); \
+	lwc1	$f9,  (THREAD_FPU + 0x040)(thread); \
+	lwc1	$f10, (THREAD_FPU + 0x054)(thread); \
+	lwc1	$f11, (THREAD_FPU + 0x050)(thread); \
+	lwc1	$f12, (THREAD_FPU + 0x064)(thread); \
+	lwc1	$f13, (THREAD_FPU + 0x060)(thread); \
+	lwc1	$f14, (THREAD_FPU + 0x074)(thread); \
+	lwc1	$f15, (THREAD_FPU + 0x070)(thread); \
+	lwc1	$f16, (THREAD_FPU + 0x084)(thread); \
+	lwc1	$f17, (THREAD_FPU + 0x080)(thread); \
+	lwc1	$f18, (THREAD_FPU + 0x094)(thread); \
+	lwc1	$f19, (THREAD_FPU + 0x090)(thread); \
+	lwc1	$f20, (THREAD_FPU + 0x0a4)(thread); \
+	lwc1	$f21, (THREAD_FPU + 0x0a0)(thread); \
+	lwc1	$f22, (THREAD_FPU + 0x0b4)(thread); \
+	lwc1	$f23, (THREAD_FPU + 0x0b0)(thread); \
+	lwc1	$f24, (THREAD_FPU + 0x0c4)(thread); \
+	lwc1	$f25, (THREAD_FPU + 0x0c0)(thread); \
+	lwc1	$f26, (THREAD_FPU + 0x0d4)(thread); \
+	lwc1	$f27, (THREAD_FPU + 0x0d0)(thread); \
+	lwc1	$f28, (THREAD_FPU + 0x0e4)(thread); \
+	lwc1	$f29, (THREAD_FPU + 0x0e0)(thread); \
+	lwc1	$f30, (THREAD_FPU + 0x0f4)(thread); \
+	lwc1	$f31, (THREAD_FPU + 0x0f0)(thread); \
 	ctc1	tmp,  fcr31
+#endif
 
 #define CPU_SAVE_NONSCRATCH(thread) \
 	sw	s0, THREAD_REG16(thread); \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/atomic.h linux-2.4.20/include/asm-mips/atomic.h
--- linux-2.4.19/include/asm-mips/atomic.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/atomic.h	2002-10-29 11:18:31.000000000 +0000
@@ -57,10 +57,9 @@
  */
 extern __inline__ void atomic_add(int i, atomic_t * v)
 {
-	int	flags;
+	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	save_and_cli(flags);
 	v->counter += i;
 	restore_flags(flags);
 }
@@ -75,20 +74,19 @@
  */
 extern __inline__ void atomic_sub(int i, atomic_t * v)
 {
-	int	flags;
+	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	save_and_cli(flags);
 	v->counter -= i;
 	restore_flags(flags);
 }
 
 extern __inline__ int atomic_add_return(int i, atomic_t * v)
 {
-	int	temp, flags;
+	unsigned long flags;
+	int temp;
 
-	save_flags(flags);
-	cli();
+	save_and_cli(flags);
 	temp = v->counter;
 	temp += i;
 	v->counter = temp;
@@ -99,10 +97,10 @@
 
 extern __inline__ int atomic_sub_return(int i, atomic_t * v)
 {
-	int	temp, flags;
+	unsigned long flags;
+	int temp;
 
-	save_flags(flags);
-	cli();
+	save_and_cli(flags);
 	temp = v->counter;
 	temp -= i;
 	v->counter = temp;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/au1000.h linux-2.4.20/include/asm-mips/au1000.h
--- linux-2.4.19/include/asm-mips/au1000.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/au1000.h	2002-10-29 11:18:31.000000000 +0000
@@ -31,6 +31,7 @@
 #ifndef _AU1000_H_
 #define _AU1000_H_
 
+#include <linux/config.h>
 #include <linux/delay.h>
 #include <asm/io.h>
 
@@ -52,22 +53,34 @@
 	mdelay(ms);
 }
 
-void static inline outb_sync(u8 val, int reg)
+void static inline au_writeb(u8 val, int reg)
 {
-	outb(val, reg);
-	au_sync();
+	*(volatile u8 *)(reg) = val;
 }
 
-void static inline outw_sync(u16 val, int reg)
+void static inline au_writew(u16 val, int reg)
 {
-	outw(val, reg);
-	au_sync();
+	*(volatile u16 *)(reg) = val;
 }
 
-void static inline outl_sync(u32 val, int reg)
+void static inline au_writel(u32 val, int reg)
 {
-	outl(val, reg);
-	au_sync();
+	*(volatile u32 *)(reg) = val;
+}
+
+static inline u8 au_readb(unsigned long port)
+{
+	return (*(volatile u8 *)port);
+}
+
+static inline u16 au_readw(unsigned long port)
+{
+	return (*(volatile u16 *)port);
+}
+
+static inline u32 au_readl(unsigned long port)
+{
+	return (*(volatile u32 *)port);
 }
 
 /* arch/mips/au1000/common/clocks.c */
@@ -300,6 +313,12 @@
 
 #define AU1000_MAX_INTR           63
 
+#define AU1100_SD		2
+#define	AU1100_GPIO_208_215	29
+// REDEFINE SECONDARY GPIO BLOCK INTO IC1 CONTROLLER HERE
+
+
+
 /* Programmable Counters 0 and 1 */
 #define SYS_BASE                   0xB1900000
 #define SYS_COUNTER_CNTRL          (SYS_BASE + 0x14)
@@ -339,11 +358,36 @@
 #define SYS_RTCMATCH2               (SYS_BASE + 0x54)
 #define SYS_RTCREAD                 (SYS_BASE + 0x58)
 
-
 /* I2S Controller */
 #define I2S_DATA                    0xB1000000
-#define I2S_CONFIG                  0xB1000001
-#define I2S_ENABLE                  0xB1000002
+  #define I2S_DATA_MASK        (0xffffff)
+#define I2S_CONFIG                0xB1000004
+  #define I2S_CONFIG_XU        (1<<25)
+  #define I2S_CONFIG_XO        (1<<24)
+  #define I2S_CONFIG_RU        (1<<23)
+  #define I2S_CONFIG_RO        (1<<22)
+  #define I2S_CONFIG_TR        (1<<21)
+  #define I2S_CONFIG_TE        (1<<20)
+  #define I2S_CONFIG_TF        (1<<19)
+  #define I2S_CONFIG_RR        (1<<18)
+  #define I2S_CONFIG_RE        (1<<17)
+  #define I2S_CONFIG_RF        (1<<16)
+  #define I2S_CONFIG_PD        (1<<11)
+  #define I2S_CONFIG_LB        (1<<10)
+  #define I2S_CONFIG_IC        (1<<9)
+  #define I2S_CONFIG_FM_BIT    7
+  #define I2S_CONFIG_FM_MASK     (0x3 << I2S_CONFIG_FM_BIT)
+    #define I2S_CONFIG_FM_I2S    (0x0 << I2S_CONFIG_FM_BIT)
+    #define I2S_CONFIG_FM_LJ     (0x1 << I2S_CONFIG_FM_BIT)
+    #define I2S_CONFIG_FM_RJ     (0x2 << I2S_CONFIG_FM_BIT)
+  #define I2S_CONFIG_TN        (1<<6)
+  #define I2S_CONFIG_RN        (1<<5)
+  #define I2S_CONFIG_SZ_BIT    0
+  #define I2S_CONFIG_SZ_MASK     (0x1F << I2S_CONFIG_SZ_BIT)
+
+#define I2S_CONTROL                0xB1000008
+  #define I2S_CONTROL_D         (1<<1)
+  #define I2S_CONTROL_CE        (1<<0)
 
 /* USB Host Controller */
 // We pass USB_OHCI_BASE to ioremap, so it needs to be a physical address
@@ -398,12 +442,13 @@
 #define AU1000_ETH1_BASE          0xB0510000
 #define AU1500_ETH0_BASE	  0xB1500000
 #define AU1500_ETH1_BASE	  0xB1510000
+#define AU1100_ETH0_BASE	  0xB0500000
 
 /* 4 byte offsets from AU1000_ETH_BASE */
 #define MAC_CONTROL                     0x0
-  #define MAC_RX_ENABLE               (1<<2) 
+  #define MAC_RX_ENABLE               (1<<2)
   #define MAC_TX_ENABLE               (1<<3)
-  #define MAC_DEF_CHECK               (1<<5) 
+  #define MAC_DEF_CHECK               (1<<5)
   #define MAC_SET_BL(X)       (((X)&0x3)<<6)
   #define MAC_AUTO_PAD                (1<<8)
   #define MAC_DISABLE_RETRY          (1<<10)
@@ -428,7 +473,7 @@
 #define MAC_MCAST_LOW                  0x10
 #define MAC_MII_CNTRL                  0x14
   #define MAC_MII_BUSY                (1<<0)
-  #define MAC_MII_READ                     0 
+  #define MAC_MII_READ                     0
   #define MAC_MII_WRITE               (1<<1)
   #define MAC_SET_MII_SELECT_REG(X)   (((X)&0x1f)<<6)
   #define MAC_SET_MII_SELECT_PHY(X)   (((X)&0x1f)<<11)
@@ -446,6 +491,8 @@
 #define AU1000_MAC1_ENABLE       0xB0520004
 #define AU1500_MAC0_ENABLE       0xB1520000
 #define AU1500_MAC1_ENABLE       0xB1520004
+#define AU1100_MAC0_ENABLE       0xB0520000
+
   #define MAC_EN_CLOCK_ENABLE         (1<<0)
   #define MAC_EN_RESET0               (1<<1)
   #define MAC_EN_TOSS                 (0<<2)
@@ -510,7 +557,7 @@
   #define RX_FILTER_FAIL             (1<<29)
   #define RX_PACKET_FILTER           (1<<30)
   #define RX_MISSED_FRAME            (1<<31)
-  
+
   #define RX_ERROR (RX_WDOG_TIMER | RX_RUNT | RX_OVERLEN |  \
                     RX_COLL | RX_MII_ERROR | RX_CRC_ERROR | \
                     RX_LEN_ERROR | RX_U_CNTRL_FRAME | RX_MISSED_FRAME)
@@ -628,12 +675,44 @@
 
 /* SSIO */
 #define SSI0_STATUS                0xB1600000
+  #define SSI_STATUS_BF              (1<<4)
+  #define SSI_STATUS_OF              (1<<3)
+  #define SSI_STATUS_UF              (1<<2)
+  #define SSI_STATUS_D               (1<<1)
+  #define SSI_STATUS_B               (1<<0)
 #define SSI0_INT                   0xB1600004
+  #define SSI_INT_OI                 (1<<3)
+  #define SSI_INT_UI                 (1<<2)
+  #define SSI_INT_DI                 (1<<1)
 #define SSI0_INT_ENABLE            0xB1600008
+  #define SSI_INTE_OIE               (1<<3)
+  #define SSI_INTE_UIE               (1<<2)
+  #define SSI_INTE_DIE               (1<<1)
 #define SSI0_CONFIG                0xB1600020
+  #define SSI_CONFIG_AO              (1<<24)
+  #define SSI_CONFIG_DO              (1<<23)
+  #define SSI_CONFIG_ALEN_BIT        20
+    #define SSI_CONFIG_ALEN_MASK       (0x7<<20)
+  #define SSI_CONFIG_DLEN_BIT        16
+    #define SSI_CONFIG_DLEN_MASK       (0x7<<16)
+  #define SSI_CONFIG_DD              (1<<11)
+  #define SSI_CONFIG_AD              (1<<10)
+  #define SSI_CONFIG_BM_BIT          8
+    #define SSI_CONFIG_BM_MASK         (0x3<<8)
+  #define SSI_CONFIG_CE              (1<<7)
+  #define SSI_CONFIG_DP              (1<<6)
+  #define SSI_CONFIG_DL              (1<<5)
+  #define SSI_CONFIG_EP              (1<<4)
 #define SSI0_ADATA                 0xB1600024
+  #define SSI_AD_D                   (1<<24)
+  #define SSI_AD_ADDR_BIT            16
+    #define SSI_AD_ADDR_MASK           (0xff<<16)
+  #define SSI_AD_DATA_BIT            0
+    #define SSI_AD_DATA_MASK           (0xfff<<0)
 #define SSI0_CLKDIV                0xB1600028
 #define SSI0_CONTROL               0xB1600100
+  #define SSI_CONTROL_CD             (1<<1)
+  #define SSI_CONTROL_E              (1<<0)
 
 /* SSI1 */
 #define SSI1_STATUS                0xB1680000
@@ -685,12 +764,29 @@
 
 /* GPIO */
 #define SYS_PINFUNC               0xB190002C
+  #define SYS_PF_USB			(1<<15)	/* 2nd USB device/host */
+  #define SYS_PF_U3			(1<<14)	/* GPIO23/U3TXD */
+  #define SYS_PF_U2			(1<<13) /* GPIO22/U2TXD */
+  #define SYS_PF_U1			(1<<12) /* GPIO21/U1TXD */
+  #define SYS_PF_SRC			(1<<11)	/* GPIO6/SROMCKE */
+  #define SYS_PF_CK5			(1<<10)	/* GPIO3/CLK5 */
+  #define SYS_PF_CK4			(1<<9)	/* GPIO2/CLK4 */
+  #define SYS_PF_IRF			(1<<8)	/* GPIO15/IRFIRSEL */
+  #define SYS_PF_UR3			(1<<7)	/* GPIO[14:9]/UART3 */
+  #define SYS_PF_I2D			(1<<6)	/* GPIO8/I2SDI */
+  #define SYS_PF_I2S			(1<<5)	/* I2S/GPIO[29:31] */
+  #define SYS_PF_NI2			(1<<4)	/* NI2/GPIO[24:28] */
+  #define SYS_PF_U0			(1<<3)	/* U0TXD/GPIO20 */
+  #define SYS_PF_RD			(1<<2)	/* IRTXD/GPIO19 */
+  #define SYS_PF_A97			(1<<1)	/* AC97/SSL1 */
+  #define SYS_PF_S0			(1<<0)	/* SSI_0/GPIO[16:18] */
 #define SYS_TRIOUTRD              0xB1900100
 #define SYS_TRIOUTCLR             0xB1900100
 #define SYS_OUTPUTRD              0xB1900108
 #define SYS_OUTPUTSET             0xB1900108
 #define SYS_OUTPUTCLR             0xB190010C
 #define SYS_PINSTATERD            0xB1900110
+#define SYS_PININPUTEN            0xB1900110
 
 /* GPIO2, Au1500 only */
 #define GPIO2_BASE                0xB1700000
@@ -712,8 +808,64 @@
 
 /* Clock Controller */
 #define SYS_FREQCTRL0             0xB1900020
+  #define SYS_FC_FRDIV2_BIT         22
+  #define SYS_FC_FRDIV2_MASK        (0xff << FQC2_FRDIV2_BIT)
+  #define SYS_FC_FE2                (1<<21)
+  #define SYS_FC_FS2                (1<<20)
+  #define SYS_FC_FRDIV1_BIT         12
+  #define SYS_FC_FRDIV1_MASK        (0xff << FQC2_FRDIV1_BIT)
+  #define SYS_FC_FE1                (1<<11)
+  #define SYS_FC_FS1                (1<<10)
+  #define SYS_FC_FRDIV0_BIT         2
+  #define SYS_FC_FRDIV0_MASK        (0xff << FQC2_FRDIV0_BIT)
+  #define SYS_FC_FE0                (1<<1)
+  #define SYS_FC_FS0                (1<<0)
 #define SYS_FREQCTRL1             0xB1900024
+  #define SYS_FC_FRDIV5_BIT         22
+  #define SYS_FC_FRDIV5_MASK        (0xff << FQC2_FRDIV5_BIT)
+  #define SYS_FC_FE5                (1<<21)
+  #define SYS_FC_FS5                (1<<20)
+  #define SYS_FC_FRDIV4_BIT         12
+  #define SYS_FC_FRDIV4_MASK        (0xff << FQC2_FRDIV4_BIT)
+  #define SYS_FC_FE4                (1<<11)
+  #define SYS_FC_FS4                (1<<10)
+  #define SYS_FC_FRDIV3_BIT         2
+  #define SYS_FC_FRDIV3_MASK        (0xff << FQC2_FRDIV3_BIT)
+  #define SYS_FC_FE3                (1<<1)
+  #define SYS_FC_FS3                (1<<0)
 #define SYS_CLKSRC                0xB1900028
+  #define SYS_CS_ME1_BIT            27
+  #define SYS_CS_ME1_MASK           (0x7<<CSC_ME1_BIT)
+  #define SYS_CS_DE1                (1<<26)
+  #define SYS_CS_CE1                (1<<25)
+  #define SYS_CS_ME0_BIT            22
+  #define SYS_CS_ME0_MASK           (0x7<<CSC_ME0_BIT)
+  #define SYS_CS_DE0                (1<<21)
+  #define SYS_CS_CE0                (1<<20)
+  #define SYS_CS_MI2_BIT            17
+  #define SYS_CS_MI2_MASK           (0x7<<CSC_MI2_BIT)
+  #define SYS_CS_DI2                (1<<16)
+  #define SYS_CS_CI2                (1<<15)
+  #define SYS_CS_MUH_BIT            12
+  #define SYS_CS_MUH_MASK           (0x7<<CSC_MUH_BIT)
+  #define SYS_CS_DUH                (1<<11)
+  #define SYS_CS_CUH                (1<<10)
+  #define SYS_CS_MUD_BIT            7
+  #define SYS_CS_MUD_MASK           (0x7<<CSC_MUD_BIT)
+  #define SYS_CS_DUD                (1<<6)
+  #define SYS_CS_CUD                (1<<5)
+  #define SYS_CS_MIR_BIT            2
+  #define SYS_CS_MIR_MASK           (0x7<<CSC_MIR_BIT)
+  #define SYS_CS_DIR                (1<<1)
+  #define SYS_CS_CIR                (1<<0)
+
+  #define SYS_CS_MUX_AUX            0x1
+  #define SYS_CS_MUX_FQ0            0x2
+  #define SYS_CS_MUX_FQ1            0x3
+  #define SYS_CS_MUX_FQ2            0x4
+  #define SYS_CS_MUX_FQ3            0x5
+  #define SYS_CS_MUX_FQ4            0x6
+  #define SYS_CS_MUX_FQ5            0x7
 #define SYS_CPUPLL                0xB1900060
 #define SYS_AUXPLL                0xB1900064
 
@@ -768,11 +920,19 @@
 
 #define Au1500_PCI_HDR            0xB4005100 // virtual, kseg0 addr
 
-  /* these are all pseudo physical addresses */
-#define Au1500_EXT_CFG            0x20000000
-#define Au1500_PCI_IO_START       0x70000000
-#define Au1500_PCI_IO_END         0x700FFFFF
-#define Au1500_PCI_MEM_START      0x80000000
-#define Au1500_PCI_MEM_END        0x83FFFFFF
+/* All of our structures, like pci resource, have 32 bit members.
+ * Drivers are expected to do an ioremap on the PCI MEM resource, but it's
+ * hard to store 0x4 0000 0000 in a 32 bit type.  We require a small patch
+ * to __ioremap to check for addresses between (u32)Au1500_PCI_MEM_START and
+ * (u32)Au1500_PCI_MEM_END and change those to the full 36 bit PCI MEM
+ * addresses.  For PCI IO, it's simpler because we get to do the ioremap
+ * ourselves and then adjust the device's resources.
+ */
+#define Au1500_EXT_CFG            0x600000000
+#define Au1500_EXT_CFG_TYPE1      0x680000000
+#define Au1500_PCI_IO_START       0x500000000
+#define Au1500_PCI_IO_END         0x5000FFFFF
+#define Au1500_PCI_MEM_START      0x440000000
+#define Au1500_PCI_MEM_END        0x443FFFFFF
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/au1000_dma.h linux-2.4.20/include/asm-mips/au1000_dma.h
--- linux-2.4.19/include/asm-mips/au1000_dma.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/au1000_dma.h	2002-10-29 11:18:36.000000000 +0000
@@ -44,6 +44,7 @@
 
 /* DMA Channel Register Offsets */
 #define DMA_MODE_SET		0x00000000
+#define DMA_MODE_READ		DMA_MODE_SET
 #define DMA_MODE_CLEAR		0x00000004
 /* DMA Mode register bits follow */
 #define DMA_DAH_MASK		(0x0f << 20)
@@ -101,15 +102,21 @@
 struct dma_chan {
 	int dev_id;		// this channel is allocated if >=0, free otherwise
 	unsigned int io;
-	int irq;
 	const char *dev_str;
+	int irq;
+	void *irq_dev;
 	unsigned int fifo_addr;
 	unsigned int mode;
 };
 
 /* These are in arch/mips/au1000/common/dma.c */
 extern struct dma_chan au1000_dma_table[];
-extern int request_au1000_dma(int dev_id, const char *dev_str);
+extern int request_au1000_dma(int dev_id,
+			      const char *dev_str,
+			      void (*irqhandler)(int, void *,
+						 struct pt_regs *),
+			      unsigned long irqflags,
+			      void *irq_dev_id);
 extern void free_au1000_dma(unsigned int dmanr);
 extern int au1000_dma_read_proc(char *buf, char **start, off_t fpos,
 				int length, int *eof, void *data);
@@ -162,45 +169,75 @@
 	au_writel(DMA_BE0 | DMA_BE1, chan->io + DMA_MODE_SET);
 }
 
-/* enable/disable a specific DMA channel */
-static __inline__ void enable_dma(unsigned int dmanr)
+static __inline__ void start_dma(unsigned int dmanr)
 {
 	struct dma_chan *chan = get_dma_chan(dmanr);
 	if (!chan)
 		return;
 
-	// set device FIFO address
-	au_writel(virt_to_phys((void *) chan->fifo_addr),
-		  chan->io + DMA_PERIPHERAL_ADDR);
-
-	au_writel(chan->
-		  mode | (chan->dev_id << DMA_DID_BIT) | DMA_IE | DMA_GO,
-		  chan->io + DMA_MODE_SET);
+	au_writel(DMA_GO, chan->io + DMA_MODE_SET);
 }
 
 #define DMA_HALT_POLL 0x5000
 
-static __inline__ void disable_dma(unsigned int dmanr)
+static __inline__ void halt_dma(unsigned int dmanr)
 {
-	int i;
 	struct dma_chan *chan = get_dma_chan(dmanr);
+	int i;
 	if (!chan)
 		return;
 
-	au_writel(DMA_D1 | DMA_D0 | DMA_GO, chan->io + DMA_MODE_CLEAR);
-
+	au_writel(DMA_GO, chan->io + DMA_MODE_CLEAR);
 	// poll the halt bit
 	for (i = 0; i < DMA_HALT_POLL; i++)
-		if (au_readl(chan->io + DMA_MODE_SET) & DMA_HALT)
+		if (au_readl(chan->io + DMA_MODE_READ) & DMA_HALT)
 			break;
-	if (i == DMA_HALT_POLL) {
-		printk(KERN_INFO "disable_dma: HALT poll expired!\n");
-	} else {
+	if (i == DMA_HALT_POLL)
+		printk(KERN_INFO "halt_dma: HALT poll expired!\n");
+}
+
+
+static __inline__ void disable_dma(unsigned int dmanr)
+{
+	struct dma_chan *chan = get_dma_chan(dmanr);
+	if (!chan)
+		return;
+
+	halt_dma(dmanr);
+
 		// now we can disable the buffers
 		au_writel(~DMA_GO, chan->io + DMA_MODE_CLEAR);
-	}
 }
 
+static __inline__ int dma_halted(unsigned int dmanr)
+{
+	struct dma_chan *chan = get_dma_chan(dmanr);
+	if (!chan)
+		return 1;
+	return (au_readl(chan->io + DMA_MODE_READ) & DMA_HALT) ? 1 : 0;
+}
+
+/* initialize a DMA channel */
+static __inline__ void init_dma(unsigned int dmanr)
+{
+	struct dma_chan *chan = get_dma_chan(dmanr);
+	u32 mode;
+	if (!chan)
+		return;
+
+	disable_dma(dmanr);
+
+	// set device FIFO address
+	au_writel(virt_to_phys((void *) chan->fifo_addr),
+		  chan->io + DMA_PERIPHERAL_ADDR);
+
+	mode = chan->mode | (chan->dev_id << DMA_DID_BIT);
+	if (chan->irq)
+		mode |= DMA_IE;
+
+	au_writel(~mode, chan->io + DMA_MODE_CLEAR);
+	au_writel(mode, chan->io + DMA_MODE_SET);
+}
 
 /*
  * set mode for a specific DMA channel
@@ -211,12 +248,21 @@
 	if (!chan)
 		return;
 	/*
-	 * chan->mode only holds endianess, direction, transfer size, device
-	 * FIFO width, and cacheability info for the channel. Make sure
-	 * anything else is masked off.
+	 * set_dma_mode is only allowed to change endianess, direction,
+	 * transfer size, device FIFO width, and coherency settings.
+	 * Make sure anything else is masked off.
 	 */
 	mode &= (DMA_BE | DMA_DR | DMA_TS8 | DMA_DW_MASK | DMA_NC);
-	chan->mode = mode;
+	chan->mode &= ~(DMA_BE | DMA_DR | DMA_TS8 | DMA_DW_MASK | DMA_NC);
+	chan->mode |= mode;
+}
+
+static __inline__ unsigned int get_dma_mode(unsigned int dmanr)
+{
+	struct dma_chan *chan = get_dma_chan(dmanr);
+	if (!chan)
+		return 0;
+	return chan->mode;
 }
 
 static __inline__ int get_dma_active_buffer(unsigned int dmanr)
@@ -224,7 +270,7 @@
 	struct dma_chan *chan = get_dma_chan(dmanr);
 	if (!chan)
 		return -1;
-	return (au_readl(chan->io + DMA_MODE_SET) & DMA_AB) ? 1 : 0;
+	return (au_readl(chan->io + DMA_MODE_READ) & DMA_AB) ? 1 : 0;
 }
 
 
@@ -345,7 +391,7 @@
 	if (!chan)
 		return 0;
 
-    return au_readl(chan->io + DMA_MODE_SET) & (DMA_D0 | DMA_D1);
+    return au_readl(chan->io + DMA_MODE_READ) & (DMA_D0 | DMA_D1);
 }
 
 
@@ -371,7 +417,7 @@
 	if (!chan)
 		return 0;
 
-	curBufCntReg = (au_readl(chan->io + DMA_MODE_SET) & DMA_AB) ?
+	curBufCntReg = (au_readl(chan->io + DMA_MODE_READ) & DMA_AB) ?
 	    DMA_BUFFER1_COUNT : DMA_BUFFER0_COUNT;
 
 	count = au_readl(chan->io + curBufCntReg) & DMA_COUNT_MASK;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/au1000_gpio.h linux-2.4.20/include/asm-mips/au1000_gpio.h
--- linux-2.4.19/include/asm-mips/au1000_gpio.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/au1000_gpio.h	2002-10-29 11:18:33.000000000 +0000
@@ -44,7 +44,7 @@
 #define AU1000GPIO_TRISTATE	_IOW (AU1000GPIO_IOC_MAGIC, 4, int)
 #define AU1000GPIO_AVAIL_MASK	_IOR (AU1000GPIO_IOC_MAGIC, 5, int)
 
-#ifdef __KERNEL__ 
+#ifdef __KERNEL__
 extern u32 get_au1000_avail_gpio_mask(void);
 extern int au1000gpio_tristate(u32 data);
 extern int au1000gpio_in(u32 *data);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/au1000_pcmcia.h linux-2.4.20/include/asm-mips/au1000_pcmcia.h
--- linux-2.4.19/include/asm-mips/au1000_pcmcia.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/au1000_pcmcia.h	2002-10-29 11:18:37.000000000 +0000
@@ -23,12 +23,11 @@
  *
  * ########################################################################
  *
- * 
+ *
  */
 #ifndef __ASM_AU1000_PCMCIA_H
 #define __ASM_AU1000_PCMCIA_H
 
-#include <linux/config.h>
 
 #define AU1000_PCMCIA_POLL_PERIOD    (2*HZ)
 #define AU1000_PCMCIA_IO_SPEED       (255)
@@ -60,6 +59,8 @@
 	unsigned int irq;
 };
 
+typedef u_int memaddr_t;	/* fix me */
+
 struct au1000_pcmcia_socket {
 	socket_state_t        cs_state;
 	struct pcmcia_state   k_state;
@@ -68,7 +69,8 @@
 	void                  *handler_info;
 	pccard_io_map         io_map[MAX_IO_WIN];
 	pccard_mem_map        mem_map[MAX_WIN];
-	u32                   virt_io, phys_attr, phys_mem;
+	u32                   virt_io;
+	memaddr_t             phys_attr, phys_mem;	/*FIX ME*/
 	unsigned short        speed_io, speed_attr, speed_mem;
 };
 
@@ -84,10 +86,10 @@
 	int (*configure_socket)(const struct pcmcia_configure *);
 };
 
-#ifdef CONFIG_MIPS_PB1000
-extern struct pcmcia_low_level pb1000_pcmcia_ops;
-#elif defined (CONFIG_MIPS_PB1500)
-extern struct pcmcia_low_level pb1500_pcmcia_ops;
+#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500)
+extern struct pcmcia_low_level pb1x00_pcmcia_ops;
+#else
+error unknown Au1000 board
 #endif
 
 #endif /* __ASM_AU1000_PCMCIA_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/au1000_usbdev.h linux-2.4.20/include/asm-mips/au1000_usbdev.h
--- linux-2.4.19/include/asm-mips/au1000_usbdev.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips/au1000_usbdev.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,73 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Au1000 USB Device-Side Driver
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *		stevel@mvista.com or source@mvista.com
+ *
+ *  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.
+ */
+
+#define USBDEV_REV 0x0110 // BCD
+#define USBDEV_EP0_MAX_PACKET_SIZE 64
+
+typedef enum {
+	ATTACHED = 0,
+	POWERED,
+	DEFAULT,
+	ADDRESS,
+	CONFIGURED
+} usbdev_state_t;
+
+typedef enum {
+	CB_NEW_STATE = 0,
+	CB_PKT_COMPLETE
+} usbdev_cb_type_t;
+
+
+typedef struct usbdev_pkt {
+	int                ep_addr;    // ep addr this packet routed to
+	int                size;       // size of payload in bytes
+	unsigned           status;     // packet status
+	struct usbdev_pkt* next;       // function layer can't touch this
+	u8                 payload[0]; // the payload
+} usbdev_pkt_t;
+
+#define PKT_STATUS_ACK  (1<<0)
+#define PKT_STATUS_NAK  (1<<1)
+#define PKT_STATUS_SU   (1<<2)
+
+extern int usbdev_init(struct usb_device_descriptor* dev_desc,
+		       struct usb_config_descriptor* config_desc,
+		       struct usb_interface_descriptor* if_desc,
+		       struct usb_endpoint_descriptor* ep_desc,
+		       struct usb_string_descriptor* str_desc[],
+		       void (*cb)(usbdev_cb_type_t, unsigned long, void *),
+		       void* cb_data);
+
+extern void usbdev_exit(void);
+
+extern int usbdev_alloc_packet  (int ep_addr, int data_size,
+				 usbdev_pkt_t** pkt);
+extern int usbdev_send_packet   (int ep_addr, usbdev_pkt_t* pkt);
+extern int usbdev_receive_packet(int ep_addr, usbdev_pkt_t** pkt);
+extern int usbdev_get_byte_count(int ep_addr);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/bcache.h linux-2.4.20/include/asm-mips/bcache.h
--- linux-2.4.19/include/asm-mips/bcache.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/bcache.h	2002-10-29 11:18:35.000000000 +0000
@@ -12,7 +12,7 @@
 #include <linux/config.h>
 
 /* Some R4000 / R4400 / R4600 / R5000 machines may have a non-dma-coherent,
-   chipset implemented caches.  On machines with other CPUs the CPU does the 
+   chipset implemented caches.  On machines with other CPUs the CPU does the
    cache thing itself. */
 struct bcache_ops {
 	void (*bc_enable)(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/bitops.h linux-2.4.20/include/asm-mips/bitops.h
--- linux-2.4.19/include/asm-mips/bitops.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/bitops.h	2002-10-29 11:18:32.000000000 +0000
@@ -159,7 +159,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is atomic and cannot be reordered.  
+ * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
 extern __inline__ int
@@ -191,7 +191,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is non-atomic and can be reordered.  
+ * This operation is non-atomic and can be reordered.
  * If two examples of this operation race, one can appear to succeed
  * but actually fail.  You must protect multiple accesses with a lock.
  */
@@ -213,7 +213,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is atomic and cannot be reordered.  
+ * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
 extern __inline__ int
@@ -246,7 +246,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is non-atomic and can be reordered.  
+ * This operation is non-atomic and can be reordered.
  * If two examples of this operation race, one can appear to succeed
  * but actually fail.  You must protect multiple accesses with a lock.
  */
@@ -268,7 +268,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is atomic and cannot be reordered.  
+ * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
 extern __inline__ int
@@ -300,7 +300,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is non-atomic and can be reordered.  
+ * This operation is non-atomic and can be reordered.
  * If two examples of this operation race, one can appear to succeed
  * but actually fail.  You must protect multiple accesses with a lock.
  */
@@ -427,7 +427,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is atomic and cannot be reordered.  
+ * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
 extern __inline__ int test_and_set_bit(int nr, volatile void * addr)
@@ -451,7 +451,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is non-atomic and can be reordered.  
+ * This operation is non-atomic and can be reordered.
  * If two examples of this operation race, one can appear to succeed
  * but actually fail.  You must protect multiple accesses with a lock.
  */
@@ -473,7 +473,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is atomic and cannot be reordered.  
+ * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
 extern __inline__ int test_and_clear_bit(int nr, volatile void * addr)
@@ -497,7 +497,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is non-atomic and can be reordered.  
+ * This operation is non-atomic and can be reordered.
  * If two examples of this operation race, one can appear to succeed
  * but actually fail.  You must protect multiple accesses with a lock.
  */
@@ -519,7 +519,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is atomic and cannot be reordered.  
+ * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
 extern __inline__ int test_and_change_bit(int nr, volatile void * addr)
@@ -543,7 +543,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is non-atomic and can be reordered.  
+ * This operation is non-atomic and can be reordered.
  * If two examples of this operation race, one can appear to succeed
  * but actually fail.  You must protect multiple accesses with a lock.
  */
@@ -644,7 +644,7 @@
 	unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
 	int set = 0, bit = offset & 31, res;
 	unsigned long dummy;
-	
+
 	if (bit) {
 		/*
 		 * Look for zero in first byte
@@ -891,7 +891,7 @@
 #define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr), (size))
 #define ext2_find_next_zero_bit(addr, size, offset) \
                 find_next_zero_bit((addr), (size), (offset))
- 
+
 #endif /* !(__MIPSEB__) */
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/bootinfo.h linux-2.4.20/include/asm-mips/bootinfo.h
--- linux-2.4.19/include/asm-mips/bootinfo.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/bootinfo.h	2002-10-29 11:18:34.000000000 +0000
@@ -49,7 +49,7 @@
 #define MACH_OLIVETTI_M700      2	/* Olivetti M700-10 (-15 ??)    */
 
 /*
- * Valid machtype for group DEC 
+ * Valid machtype for group DEC
  */
 #define MACH_DSUNKNOWN		0
 #define MACH_DS23100		1	/* DECstation 2100 or 3100	*/
@@ -96,10 +96,11 @@
 /*
  * Valid machtype for group NEC DDB
  */
-#define MACH_NEC_DDB5074	 0	/* NEC DDB Vrc-5074 */
-#define MACH_NEC_DDB5476         1      /* NEC DDB Vrc-5476 */
-#define MACH_NEC_DDB5477         2      /* NEC DDB Vrc-5477 */
-#define MACH_NEC_ROCKHOPPER      3      /* Rockhopper base board */
+#define MACH_NEC_DDB5074	0	/* NEC DDB Vrc-5074 */
+#define MACH_NEC_DDB5476	1	/* NEC DDB Vrc-5476 */
+#define MACH_NEC_DDB5477	2	/* NEC DDB Vrc-5477 */
+#define MACH_NEC_ROCKHOPPER	3	/* Rockhopper base board */
+#define MACH_NEC_ROCKHOPPERII	4	/* Rockhopper II base board */
 
 /*
  * Valid machtype for group BAGET
@@ -121,17 +122,18 @@
 /*
  * Valid machtype for group MOMENCO
  */
-#define MACH_MOMENCO_OCELOT	0
- 
+#define MACH_MOMENCO_OCELOT		0
+#define MACH_MOMENCO_OCELOT_G		1
+
 /*
  * Valid machtype for group ITE
  */
 #define MACH_QED_4N_S01B	0	/* ITE8172 based eval board */
- 
+
 /*
  * Valid machtype for group Globespan
  */
-#define MACH_IVR       0                  /* IVR eval board */
+#define MACH_IVR		0	/* IVR eval board */
 
 /*
  * Valid machtype for group PHILIPS
@@ -150,18 +152,21 @@
 #define MACH_PALLAS		0
 #define MACH_TOPAS		1
 #define MACH_JMR		2
-#define MACH_TOSHIBA_JMR3927    3      /* JMR-TX3927 CPU/IO board */
+#define MACH_TOSHIBA_JMR3927	3	/* JMR-TX3927 CPU/IO board */
 
 /*
  * Valid machtype for group Alchemy
  */
-#define MACH_PB1000	0	         /* Au1000-based eval board */
-#define MACH_PB1500	1	         /* Au1500-based eval board */
- 
+#define MACH_PB1000		0	/* Au1000-based eval board */
+#define MACH_PB1100		1	/* Au1100-based eval board */
+#define MACH_PB1500		2	/* Au1500-based eval board */
+
 /*
  * Valid machtype for group NEC_VR41XX
  */
-#define MACH_NEC_OSPREY                0       /* Osprey eval board */
+#define MACH_NEC_OSPREY		0	/* Osprey eval board */
+#define MACH_NEC_EAGLE		1	/* NEC Eagle/Hawk board */
+#define MACH_ZAO_CAPCELLA	2	/* ZAO Networks Capcella */
 
 #define CL_SIZE			(256)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/cacheops.h linux-2.4.20/include/asm-mips/cacheops.h
--- linux-2.4.19/include/asm-mips/cacheops.h	1997-06-26 19:33:39.000000000 +0000
+++ linux-2.4.20/include/asm-mips/cacheops.h	2002-10-29 11:18:34.000000000 +0000
@@ -35,6 +35,7 @@
 #define Hit_Writeback_Inv_D	0x15
 					/* 0x16 is unused */
 #define Hit_Writeback_Inv_SD	0x17
+#define R5K_Page_Invalidate_S	0x17
 #define Hit_Writeback_I		0x18
 #define Hit_Writeback_D		0x19
 					/* 0x1a is unused */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/checksum.h linux-2.4.20/include/asm-mips/checksum.h
--- linux-2.4.19/include/asm-mips/checksum.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/checksum.h	2002-10-29 11:18:32.000000000 +0000
@@ -84,7 +84,7 @@
 
 	return sum;
 }
- 
+
 /*
  *	This is a version of ip_compute_csum() optimized for IP headers,
  *	which always checksum on 4 octet boundaries.
@@ -200,7 +200,7 @@
 						     struct in6_addr *daddr,
 						     __u32 len,
 						     unsigned short proto,
-						     unsigned int sum) 
+						     unsigned int sum)
 {
 	__asm__(
 	".set\tnoreorder\t\t\t# csum_ipv6_magic\n\t"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/cobalt/cobalt.h linux-2.4.20/include/asm-mips/cobalt/cobalt.h
--- linux-2.4.19/include/asm-mips/cobalt/cobalt.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/cobalt/cobalt.h	2002-10-29 11:18:48.000000000 +0000
@@ -10,8 +10,8 @@
  * Copyright (C) 2001 Liam Davies (ldavies@agile.tv)
  *
  */
-#ifndef __ASM_MIPS_COBALT_H 
-#define __ASM_MIPS_COBALT_H 
+#ifndef __ASM_MIPS_COBALT_H
+#define __ASM_MIPS_COBALT_H
 
 /*
  * COBALT interrupt enable bits
@@ -46,6 +46,8 @@
 #define COBALT_PARALLEL_IRQ    5
 #define COBALT_FLOPPY_IRQ      6 /* needs to be consistent with floppy driver! */
 #define COBALT_SCSI_IRQ        7
+#define COBALT_SERIAL_IRQ      7
+#define COBALT_RAQ_SCSI_IRQ    4
 
 /*
  * PCI configuration space manifest constants.  These are wired into
@@ -63,32 +65,6 @@
 #define COBALT_PCICONF_PCISLOT  0x0A
 #define COBALT_PCICONF_ETH1     0x0C
 
-/*
- * Handling the VIA ISA host bridge.
- */
-
-#define        VIA_DELAY()                                             \
-{                                                              \
-       unsigned char ctr;                                      \
-       for (ctr=0;ctr<1;ctr++);                                \
-}
-
-#define VIA_PORT_WRITE(x,y)                                    \
-{                                                              \
-       *((volatile unsigned char *) (0xb0000000 | x)) = y;     \
-       VIA_DELAY();                                            \
-}
-
-#define VIA_PORT_READ(x)       (*((unsigned char *) (0xB0000000 | (x))))
-
-#define RESET_VIA_TIMER()                                      \
-       asm("sb\t%1,0x70(%0)\n\t"                               \
-           "lb\$0,0x71(%0)"                                    \
-           : /* No outputs */                                  \
-           : "r" (0xb0000000), "i" (0x0c));
-
-#define VIA_CMOS_ADDR 0x70
-#define VIA_CMOS_DATA 0x71
 
 /*
  * The Cobalt board id information.  The boards have an ID number wired
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/cpu.h linux-2.4.20/include/asm-mips/cpu.h
--- linux-2.4.19/include/asm-mips/cpu.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/cpu.h	2002-10-29 11:18:33.000000000 +0000
@@ -9,8 +9,8 @@
 
 #include <asm/cache.h>
 
-/* Assigned Company values for bits 23:16 of the PRId Register  
-   (CP0 register 15, select 0).  As of the MIPS32 and MIPS64 specs from 
+/* Assigned Company values for bits 23:16 of the PRId Register
+   (CP0 register 15, select 0).  As of the MIPS32 and MIPS64 specs from
    MTI, the PRId register is defined in this (backwards compatible)
    way:
 
@@ -21,7 +21,7 @@
 
    I don't have docs for all the previous processors, but my impression is
    that bits 16-23 have been 0 for all MIPS processors before the MIPS32/64
-   spec.  
+   spec.
 */
 
 #define PRID_COMP_LEGACY       0x000000
@@ -87,6 +87,12 @@
 #define PRID_REV_TX3912 	0x0010
 #define PRID_REV_TX3922 	0x0030
 #define PRID_REV_TX3927 	0x0040
+#define PRID_REV_VR4111		0x0050
+#define PRID_REV_VR4181		0x0050	/* Same as VR4111 */
+#define PRID_REV_VR4121		0x0060
+#define PRID_REV_VR4122		0x0070
+#define PRID_REV_VR4181A	0x0070	/* Same as VR4122 */
+#define PRID_REV_VR4131		0x0080
 
 /*
  * FPU implementation/revision register (CP1 control register 0).
@@ -100,6 +106,10 @@
 #define FPIR_IMP_NONE		0x0000
 
 #ifndef __ASSEMBLY__
+
+extern void cpu_probe(void);
+extern void cpu_report(void);
+
 /*
  * Capability and feature descriptor structure for MIPS CPU
  */
@@ -128,7 +138,8 @@
 	CPU_RM7000, CPU_R5432, CPU_4KC, CPU_5KC, CPU_R4310, CPU_SB1,
 	CPU_TX3912, CPU_TX3922, CPU_TX3927, CPU_AU1000, CPU_4KEC, CPU_4KSC,
 	CPU_VR41XX, CPU_R5500, CPU_TX49XX, CPU_TX39XX, CPU_AU1500, CPU_20KC,
-	CPU_LAST
+	CPU_VR4111, CPU_VR4121, CPU_VR4122, CPU_VR4131, CPU_VR4181, CPU_VR4181A,
+	CPU_AU1100, CPU_LAST
 };
 
 #endif /* !__ASSEMBLY__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/ddb5xxx/ddb5074.h linux-2.4.20/include/asm-mips/ddb5xxx/ddb5074.h
--- linux-2.4.19/include/asm-mips/ddb5xxx/ddb5074.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips/ddb5xxx/ddb5074.h	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,38 @@
+/*
+ *  include/asm-mips/ddb5074.h -- NEC DDB Vrc-5074 definitions
+ *
+ *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ *                     Sony Software Development Center Europe (SDCE), Brussels
+ */
+
+#ifndef _ASM_DDB5XXX_DDB5074_H
+#define _ASM_DDB5XXX_DDB5074_H
+
+#include <asm/nile4.h>
+
+#define DDB_SDRAM_SIZE      0x04000000      /* 64MB */
+
+#define DDB_PCI_IO_BASE     0x06000000
+#define DDB_PCI_IO_SIZE     0x02000000      /* 32 MB */
+
+#define DDB_PCI_MEM_BASE    0x08000000
+#define DDB_PCI_MEM_SIZE    0x08000000  /* 128 MB */
+
+#define DDB_PCI_CONFIG_BASE DDB_PCI_MEM_BASE
+#define DDB_PCI_CONFIG_SIZE DDB_PCI_MEM_SIZE
+
+#define NILE4_PCI_IO_BASE   0xa6000000
+#define NILE4_PCI_MEM_BASE  0xa8000000
+#define NILE4_PCI_CFG_BASE  NILE4_PCI_MEM_BASE
+#define DDB_PCI_IACK_BASE NILE4_PCI_IO_BASE
+
+#define NILE4_IRQ_BASE NUM_I8259_INTERRUPTS
+#define CPU_IRQ_BASE (NUM_NILE4_INTERRUPTS + NILE4_IRQ_BASE)
+#define CPU_NILE4_CASCADE 2
+
+extern void ddb5074_led_hex(int hex);
+extern void ddb5074_led_d2(int on);
+extern void ddb5074_led_d3(int on);
+
+extern void nile4_irq_setup(u32 base);
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/ddb5xxx/ddb5476.h linux-2.4.20/include/asm-mips/ddb5xxx/ddb5476.h
--- linux-2.4.19/include/asm-mips/ddb5xxx/ddb5476.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/ddb5xxx/ddb5476.h	2002-10-29 11:18:32.000000000 +0000
@@ -27,7 +27,7 @@
 #define	DDB_DCS2_BASE		0x05000000	/* flash 2 */
 #define	DDB_DCS2_SIZE		0x01000000	/* 16MB */
 
-#define DDB_PCI_IO_BASE		0x06000000      
+#define DDB_PCI_IO_BASE		0x06000000
 #define DDB_PCI_IO_SIZE		0x02000000      /* 32 MB */
 
 #define	DDB_PCI_MEM_BASE	0x08000000
@@ -70,7 +70,7 @@
  *  All PCI irq but INTC are active low.
  */
 
-/* 
+/*
  * irq number block assignment
  */
 
@@ -108,7 +108,7 @@
 /*
  * i2859 irq assignment
  */
-#define I8259_IRQ_RESERVED_0	0	
+#define I8259_IRQ_RESERVED_0	0
 #define I8259_IRQ_KEYBOARD	1	/* M1543 default */
 #define I8259_IRQ_CASCADE	2
 #define I8259_IRQ_UART_B	3	/* M1543 default, may conflict with RTC according to schematic diagram  */
@@ -139,7 +139,7 @@
 /*
  * low-level irq functions
  */
-#ifndef _LANGUAGE_ASSEMBLY
+#ifndef __ASSEMBLY__
 extern void nile4_map_irq(int nile4_irq, int cpu_irq);
 extern void nile4_map_irq_all(int cpu_irq);
 extern void nile4_enable_irq(int nile4_irq);
@@ -154,4 +154,4 @@
 extern void nile4_clear_irq_mask(u32 mask);
 extern u8 nile4_i8259_iack(void);
 extern void nile4_dump_irq_status(void);        /* Debug */
-#endif
+#endif /* !__ASSEMBLY__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/ddb5xxx/ddb5477.h linux-2.4.20/include/asm-mips/ddb5xxx/ddb5477.h
--- linux-2.4.19/include/asm-mips/ddb5xxx/ddb5477.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/ddb5xxx/ddb5477.h	2002-10-29 11:18:34.000000000 +0000
@@ -216,6 +216,7 @@
 /*
  * DDB5477 specific functions
  */
+#ifndef __ASSEMBLY__
 extern void ddb5477_irq_setup(void);
 
 /* route irq to cpu int pin */
@@ -224,10 +225,110 @@
 /* low-level routine for enabling vrc5477 irq, bypassing high-level */
 extern void ll_vrc5477_irq_enable(int vrc5477_irq);
 extern void ll_vrc5477_irq_disable(int vrc5477_irq);
+#endif /* !__ASSEMBLY__ */
 
-/* 
+/* PCI intr ack share PCIW0 with PCI IO */
+#define	DDB_PCI_IACK_BASE	DDB_PCI_IO_BASE
+
+/*
+ * Interrupt mapping
+ *
+ * We have three interrupt controllers:
+ *
+ *   . CPU itself - 8 sources
+ *   . i8259 - 16 sources
+ *   . vrc5477 - 32 sources
+ *
+ *  They connected as follows:
+ *    all vrc5477 interrupts are routed to cpu IP2 (by software setting)
+ *    all i8359 are routed to INTC in vrc5477 (by hardware connection)
+ *
+ *  All VRC5477 PCI interrupts are level-triggered (no ack needed).
+ *  All PCI irq but INTC are active low.
+ */
+
+/*
+ * irq number block assignment
+ */
+
+#define	NUM_CPU_IRQ		8
+#define	NUM_I8259_IRQ		16
+#define	NUM_VRC5477_IRQ		32
+
+#define	DDB_IRQ_BASE		0
+
+#define	I8259_IRQ_BASE		DDB_IRQ_BASE
+#define	VRC5477_IRQ_BASE	(I8259_IRQ_BASE + NUM_I8259_IRQ)
+#define	CPU_IRQ_BASE		(VRC5477_IRQ_BASE + NUM_VRC5477_IRQ)
+
+/*
+ * vrc5477 irq defs
+ */
+
+#define VRC5477_IRQ_CPCE	(0 + VRC5477_IRQ_BASE)	/* cpu parity error */
+#define VRC5477_IRQ_CNTD	(1 + VRC5477_IRQ_BASE)	/* cpu no target */
+#define VRC5477_IRQ_I2C		(2 + VRC5477_IRQ_BASE)	/* I2C */
+#define VRC5477_IRQ_DMA		(3 + VRC5477_IRQ_BASE)	/* DMA */
+#define VRC5477_IRQ_UART0	(4 + VRC5477_IRQ_BASE)
+#define VRC5477_IRQ_WDOG	(5 + VRC5477_IRQ_BASE)	/* watchdog timer */
+#define VRC5477_IRQ_SPT1	(6 + VRC5477_IRQ_BASE)    /* special purpose timer 1 */
+#define VRC5477_IRQ_LBRT	(7 + VRC5477_IRQ_BASE)	/* local bus read timeout */
+#define VRC5477_IRQ_INTA	(8 + VRC5477_IRQ_BASE)	/* PCI INT #A */
+#define VRC5477_IRQ_INTB	(9 + VRC5477_IRQ_BASE)	/* PCI INT #B */
+#define VRC5477_IRQ_INTC	(10 + VRC5477_IRQ_BASE)	/* PCI INT #C */
+#define VRC5477_IRQ_INTD	(11 + VRC5477_IRQ_BASE)	/* PCI INT #D */
+#define VRC5477_IRQ_INTE	(12 + VRC5477_IRQ_BASE)	/* PCI INT #E */
+#define VRC5477_IRQ_RESERVED_13	(13 + VRC5477_IRQ_BASE)	/* reserved  */
+#define VRC5477_IRQ_PCIS	(14 + VRC5477_IRQ_BASE)	/* PCI SERR #  */
+#define VRC5477_IRQ_PCI		(15 + VRC5477_IRQ_BASE)	/* PCI internal error */
+#define VRC5477_IRQ_IOPCI_INTA	(16 + VRC5477_IRQ_BASE)      /* USB-H */
+#define VRC5477_IRQ_IOPCI_INTB	(17 + VRC5477_IRQ_BASE)      /* USB-P */
+#define VRC5477_IRQ_IOPCI_INTC	(18 + VRC5477_IRQ_BASE)      /* AC97 */
+#define VRC5477_IRQ_IOPCI_INTD	(19 + VRC5477_IRQ_BASE)      /* Reserved */
+#define VRC5477_IRQ_UART1	(20 + VRC5477_IRQ_BASE)
+#define VRC5477_IRQ_SPT0	(21 + VRC5477_IRQ_BASE)      /* special purpose timer 0 */
+#define VRC5477_IRQ_GPT0	(22 + VRC5477_IRQ_BASE)      /* general purpose timer 0 */
+#define VRC5477_IRQ_GPT1	(23 + VRC5477_IRQ_BASE)      /* general purpose timer 1 */
+#define VRC5477_IRQ_GPT2	(24 + VRC5477_IRQ_BASE)      /* general purpose timer 2 */
+#define VRC5477_IRQ_GPT3	(25 + VRC5477_IRQ_BASE)      /* general purpose timer 3 */
+#define VRC5477_IRQ_GPIO	(26 + VRC5477_IRQ_BASE)
+#define VRC5477_IRQ_SIO0	(27 + VRC5477_IRQ_BASE)
+#define VRC5477_IRQ_SIO1        (28 + VRC5477_IRQ_BASE)
+#define VRC5477_IRQ_RESERVED_29 (29 + VRC5477_IRQ_BASE)      /* reserved */
+#define VRC5477_IRQ_IOPCISERR	(30 + VRC5477_IRQ_BASE)      /* IO PCI SERR # */
+#define VRC5477_IRQ_IOPCI	(31 + VRC5477_IRQ_BASE)
+
+/*
+ * i2859 irq assignment
+ */
+#define I8259_IRQ_RESERVED_0	(0 + I8259_IRQ_BASE)
+#define I8259_IRQ_KEYBOARD	(1 + I8259_IRQ_BASE)	/* M1543 default */
+#define I8259_IRQ_CASCADE	(2 + I8259_IRQ_BASE)
+#define I8259_IRQ_UART_B	(3 + I8259_IRQ_BASE)	/* M1543 default, may conflict with RTC according to schematic diagram  */
+#define I8259_IRQ_UART_A	(4 + I8259_IRQ_BASE)	/* M1543 default */
+#define I8259_IRQ_PARALLEL	(5 + I8259_IRQ_BASE)	/* M1543 default */
+#define I8259_IRQ_RESERVED_6	(6 + I8259_IRQ_BASE)
+#define I8259_IRQ_RESERVED_7	(7 + I8259_IRQ_BASE)
+#define I8259_IRQ_RTC		(8 + I8259_IRQ_BASE)	/* who set this? */
+#define I8259_IRQ_USB		(9 + I8259_IRQ_BASE)	/* ddb_setup */
+#define I8259_IRQ_PMU		(10 + I8259_IRQ_BASE)	/* ddb_setup */
+#define I8259_IRQ_RESERVED_11	(11 + I8259_IRQ_BASE)
+#define I8259_IRQ_RESERVED_12	(12 + I8259_IRQ_BASE)	/* m1543_irq_setup */
+#define I8259_IRQ_RESERVED_13	(13 + I8259_IRQ_BASE)
+#define I8259_IRQ_HDC1		(14 + I8259_IRQ_BASE)	/* default and ddb_setup */
+#define I8259_IRQ_HDC2		(15 + I8259_IRQ_BASE)	/* default */
+
+
+/*
+ * misc
+ */
+#define	VRC5477_I8259_CASCADE	(VRC5477_IRQ_INTC - VRC5477_IRQ_BASE)
+#define	CPU_VRC5477_CASCADE	2
+
+/*
  * debug routines
  */
+#ifndef __ASSEMBLY__
 #if defined(CONFIG_DEBUG)
 extern void vrc5477_show_pdar_regs(void);
 extern void vrc5477_show_pci_regs(void);
@@ -240,5 +341,6 @@
  * RAM size
  */
 extern int board_ram_size;
+#endif /* !__ASSEMBLY__ */
 
 #endif /* __ASM_DDB5XXX_DDB5477_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/ddb5xxx/ddb5xxx.h linux-2.4.20/include/asm-mips/ddb5xxx/ddb5xxx.h
--- linux-2.4.19/include/asm-mips/ddb5xxx/ddb5xxx.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/ddb5xxx/ddb5xxx.h	2002-10-29 11:18:30.000000000 +0000
@@ -31,7 +31,7 @@
  *
  *	uPD31577(VRC5477) VR5432-SDRAM/PCI Bridge (Luke)
  *	Preliminary Specification Decoment, Rev 1.1, 27 Dec, 2000
- *  
+ *
  */
 
 
@@ -174,8 +174,13 @@
 
 static inline void ddb_sync(void)
 {
+/* The DDB5074 doesn't seem to like these accesses. They kill the board on
+ * interrupt load
+ */
+#ifndef CONFIG_DDB5074
     volatile u32 *p = (volatile u32 *)0xbfc00000;
     (void)(*p);
+#endif
 }
 
 static inline void ddb_out32(u32 offset, u32 val)
@@ -222,9 +227,9 @@
  *  Physical Device Address Registers
  */
 
-extern u32 
+extern u32
 ddb_calc_pdar(u32 phys, u32 size, int width, int on_memory_bus, int pci_visible);
-extern void 
+extern void
 ddb_set_pdar(u32 pdar, u32 phys, u32 size, int width,
 	     int on_memory_bus, int pci_visible);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/debug.h linux-2.4.20/include/asm-mips/debug.h
--- linux-2.4.19/include/asm-mips/debug.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/debug.h	2002-10-29 11:18:31.000000000 +0000
@@ -17,7 +17,7 @@
 #include <linux/config.h>
 
 /*
- * run-time macros for catching spurious errors.  Eable CONFIG_DEBUG in 
+ * run-time macros for catching spurious errors.  Eable CONFIG_DEBUG in
  * kernel hacking config menu to use them.
  *
  * Use them as run-time debugging aid.  NEVER USE THEM AS ERROR HANDLING CODE!!!
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dec/interrupts.h linux-2.4.20/include/asm-mips/dec/interrupts.h
--- linux-2.4.19/include/asm-mips/dec/interrupts.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dec/interrupts.h	2002-10-29 11:18:37.000000000 +0000
@@ -1,4 +1,4 @@
-/*  
+/*
  * Miscellaneous definitions used to initialise the interrupt vector table
  * with the machine-specific interrupt routines.
  *
@@ -11,8 +11,8 @@
  * Copyright (C) 2001, 2002  Maciej W. Rozycki
  */
 
-#ifndef __ASM_DEC_INTERRUPTS_H 
-#define __ASM_DEC_INTERRUPTS_H 
+#ifndef __ASM_DEC_INTERRUPTS_H
+#define __ASM_DEC_INTERRUPTS_H
 
 #include <asm/mipsregs.h>
 
@@ -122,4 +122,4 @@
 
 #endif /* __ASSEMBLY__ */
 
-#endif 
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dec/ioasic_addrs.h linux-2.4.20/include/asm-mips/dec/ioasic_addrs.h
--- linux-2.4.19/include/asm-mips/dec/ioasic_addrs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dec/ioasic_addrs.h	2002-10-29 11:18:33.000000000 +0000
@@ -15,27 +15,27 @@
 #ifndef IOASIC_ADDRS_H
 #define IOASIC_ADDRS_H
 
-#define CHUNK_SIZE 0x00040000
+#define IOASIC_SLOT_SIZE 0x00040000
 
-#define SYSTEM_ROM 	(0*CHUNK_SIZE)		/* board ROM */
-#define IOCTL 		(1*CHUNK_SIZE)		/* I/O ASIC */
-#define ESAR 		(2*CHUNK_SIZE)		/* LANCE MAC address chip */
-#define LANCE 		(3*CHUNK_SIZE)		/* LANCE Ethernet */
-#define SCC0 		(4*CHUNK_SIZE)		/* SCC #0 */
-#define VDAC_HI		(5*CHUNK_SIZE)		/* VDAC (maxine) */
-#define SCC1 		(6*CHUNK_SIZE)		/* SCC #1 (3min, 3max+) */
-#define VDAC_LO		(7*CHUNK_SIZE)		/* VDAC (maxine) */
-#define TOY 		(8*CHUNK_SIZE)		/* RTC */
-#define ISDN 		(9*CHUNK_SIZE)		/* ISDN (maxine) */
-#define ERRADDR		(9*CHUNK_SIZE)		/* bus error address (3max+) */
-#define CHKSYN 		(10*CHUNK_SIZE)		/* ECC syndrome (3max+) */
-#define ACCESS_BUS	(10*CHUNK_SIZE)		/* Access.Bus (maxine) */
-#define MCR 		(11*CHUNK_SIZE)		/* memory control (3max+) */
-#define FLOPPY 		(11*CHUNK_SIZE)		/* FDC (maxine) */
-#define SCSI 		(12*CHUNK_SIZE)		/* ASC SCSI */
-#define FLOPPY_DMA 	(13*CHUNK_SIZE)		/* FDC DMA (maxine) */
-#define SCSI_DMA 	(14*CHUNK_SIZE)		/* ??? */
-#define RESERVED_4 	(15*CHUNK_SIZE)		/* unused? */
+#define SYSTEM_ROM 	(0*IOASIC_SLOT_SIZE)	/* board ROM */
+#define IOCTL 		(1*IOASIC_SLOT_SIZE)	/* I/O ASIC */
+#define ESAR 		(2*IOASIC_SLOT_SIZE)	/* LANCE MAC address chip */
+#define LANCE 		(3*IOASIC_SLOT_SIZE)	/* LANCE Ethernet */
+#define SCC0 		(4*IOASIC_SLOT_SIZE)	/* SCC #0 */
+#define VDAC_HI		(5*IOASIC_SLOT_SIZE)	/* VDAC (maxine) */
+#define SCC1 		(6*IOASIC_SLOT_SIZE)	/* SCC #1 (3min, 3max+) */
+#define VDAC_LO		(7*IOASIC_SLOT_SIZE)	/* VDAC (maxine) */
+#define TOY 		(8*IOASIC_SLOT_SIZE)	/* RTC */
+#define ISDN 		(9*IOASIC_SLOT_SIZE)	/* ISDN (maxine) */
+#define ERRADDR		(9*IOASIC_SLOT_SIZE)	/* bus error address (3max+) */
+#define CHKSYN 		(10*IOASIC_SLOT_SIZE)	/* ECC syndrome (3max+) */
+#define ACCESS_BUS	(10*IOASIC_SLOT_SIZE)	/* Access.Bus (maxine) */
+#define MCR 		(11*IOASIC_SLOT_SIZE)	/* memory control (3max+) */
+#define FLOPPY 		(11*IOASIC_SLOT_SIZE)	/* FDC (maxine) */
+#define SCSI 		(12*IOASIC_SLOT_SIZE)	/* ASC SCSI */
+#define FLOPPY_DMA 	(13*IOASIC_SLOT_SIZE)	/* FDC DMA (maxine) */
+#define SCSI_DMA 	(14*IOASIC_SLOT_SIZE)	/* ??? */
+#define RESERVED_4 	(15*IOASIC_SLOT_SIZE)	/* unused? */
 
 /*
  * Offsets for IOCTL registers (relative to (system_base + IOCTL))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dec/ioasic_ints.h linux-2.4.20/include/asm-mips/dec/ioasic_ints.h
--- linux-2.4.19/include/asm-mips/dec/ioasic_ints.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dec/ioasic_ints.h	2002-10-29 11:18:35.000000000 +0000
@@ -19,7 +19,7 @@
 #ifndef __ASM_DEC_IOASIC_INTS_H
 #define __ASM_DEC_IOASIC_INTS_H
 
-/* 
+/*
  * The upper 16 bits are a part of the I/O ASIC's internal DMA engine
  * and thus are common to all I/O ASIC machines.  The exception is
  * the Maxine, which makes use of the FLOPPY and ISDN bits (otherwise
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dec/kn01.h linux-2.4.20/include/asm-mips/dec/kn01.h
--- linux-2.4.19/include/asm-mips/dec/kn01.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dec/kn01.h	2002-10-29 11:18:35.000000000 +0000
@@ -10,14 +10,15 @@
  * are by courtesy of Chris Fraser.
  * Copyright (C) 2002  Maciej W. Rozycki
  */
-#ifndef __ASM_MIPS_DEC_KN01_H 
-#define __ASM_MIPS_DEC_KN01_H 
+#ifndef __ASM_MIPS_DEC_KN01_H
+#define __ASM_MIPS_DEC_KN01_H
 
 #include <asm/addrspace.h>
 
 /*
  * Some port addresses...
  */
+#define KN01_SLOT_SIZE	0x01000000
 
 #define KN01_LANCE_BASE (KSEG1ADDR(0x18000000)) /* 0xB8000000 */
 #define KN01_DZ11_BASE	(KSEG1ADDR(0x1c000000)) /* 0xBC000000 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dec/kn02.h linux-2.4.20/include/asm-mips/dec/kn02.h
--- linux-2.4.19/include/asm-mips/dec/kn02.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dec/kn02.h	2002-10-29 11:18:49.000000000 +0000
@@ -10,8 +10,8 @@
  * are by courtesy of Chris Fraser.
  * Copyright (C) 2002  Maciej W. Rozycki
  */
-#ifndef __ASM_MIPS_DEC_KN02_H 
-#define __ASM_MIPS_DEC_KN02_H 
+#ifndef __ASM_MIPS_DEC_KN02_H
+#define __ASM_MIPS_DEC_KN02_H
 
 #ifndef __ASSEMBLY__
 #include <linux/spinlock.h>
@@ -29,6 +29,8 @@
 /*
  * Some port addresses...
  */
+#define KN02_SLOT_SIZE	0x00080000
+
 #define KN02_RTC_BASE	KSEG1ADDR(0x1fe80000)
 #define KN02_DZ11_BASE	KSEG1ADDR(0x1fe00000)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dec/kn02ba.h linux-2.4.20/include/asm-mips/dec/kn02ba.h
--- linux-2.4.19/include/asm-mips/dec/kn02ba.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dec/kn02ba.h	2002-10-29 11:18:49.000000000 +0000
@@ -10,8 +10,8 @@
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
  */
-#ifndef __ASM_MIPS_DEC_KN02BA_H 
-#define __ASM_MIPS_DEC_KN02BA_H 
+#ifndef __ASM_MIPS_DEC_KN02BA_H
+#define __ASM_MIPS_DEC_KN02BA_H
 
 #include <asm/dec/kn02xa.h>		/* For common definitions. */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dec/kn02ca.h linux-2.4.20/include/asm-mips/dec/kn02ca.h
--- linux-2.4.19/include/asm-mips/dec/kn02ca.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dec/kn02ca.h	2002-10-29 11:18:34.000000000 +0000
@@ -10,8 +10,8 @@
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
  */
-#ifndef __ASM_MIPS_DEC_KN02CA_H 
-#define __ASM_MIPS_DEC_KN02CA_H 
+#ifndef __ASM_MIPS_DEC_KN02CA_H
+#define __ASM_MIPS_DEC_KN02CA_H
 
 #include <asm/dec/kn02xa.h>		/* For common definitions. */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dec/kn02xa.h linux-2.4.20/include/asm-mips/dec/kn02xa.h
--- linux-2.4.19/include/asm-mips/dec/kn02xa.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dec/kn02xa.h	2002-10-29 11:18:34.000000000 +0000
@@ -14,8 +14,8 @@
  * These are addresses which have to be known early in the boot process.
  * For other addresses refer to tc.h, ioasic_addrs.h and friends.
  */
-#ifndef __ASM_MIPS_DEC_KN02XA_H 
-#define __ASM_MIPS_DEC_KN02XA_H 
+#ifndef __ASM_MIPS_DEC_KN02XA_H
+#define __ASM_MIPS_DEC_KN02XA_H
 
 #include <asm/addrspace.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dec/kn03.h linux-2.4.20/include/asm-mips/dec/kn03.h
--- linux-2.4.19/include/asm-mips/dec/kn03.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dec/kn03.h	2002-10-29 11:18:40.000000000 +0000
@@ -15,8 +15,8 @@
  * These are addresses which have to be known early in the boot process.
  * For other addresses refer to tc.h ioasic_addrs.h and friends.
  */
-#ifndef __ASM_MIPS_DEC_KN03_H 
-#define __ASM_MIPS_DEC_KN03_H 
+#ifndef __ASM_MIPS_DEC_KN03_H
+#define __ASM_MIPS_DEC_KN03_H
 
 #include <asm/addrspace.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dec/kn05.h linux-2.4.20/include/asm-mips/dec/kn05.h
--- linux-2.4.19/include/asm-mips/dec/kn05.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dec/kn05.h	2002-10-29 11:18:48.000000000 +0000
@@ -27,22 +27,22 @@
  * passed to the I/O ASIC's decoder like with the KN03.  Others are
  * handled locally.  "Low" slots are always passed.
  */
-#define KN05_MB_ROM	(16*CHUNK_SIZE)		/* KN05 card ROM */
-#define KN05_IOCTL	(17*CHUNK_SIZE)		/* I/O ASIC */
-#define KN05_ESAR	(18*CHUNK_SIZE)		/* LANCE MAC address chip */
-#define KN05_LANCE	(19*CHUNK_SIZE)		/* LANCE Ethernet */
-#define KN05_MB_INT	(20*CHUNK_SIZE)		/* MB interrupt register? */
-#define KN05_MB_UNKN_0	(21*CHUNK_SIZE)		/* MB unknown register */
-#define KN05_MB_UNKN_1	(22*CHUNK_SIZE)		/* MB unknown register */
-#define KN05_MB_CSR	(23*CHUNK_SIZE)		/* MB control & status */
-#define KN05_RESERVED_0	(24*CHUNK_SIZE)		/* unused? */
-#define KN05_RESERVED_1	(25*CHUNK_SIZE)		/* unused? */
-#define KN05_RESERVED_2	(26*CHUNK_SIZE)		/* unused? */
-#define KN05_RESERVED_3	(27*CHUNK_SIZE)		/* unused? */
-#define KN05_SCSI	(28*CHUNK_SIZE)		/* ASC SCSI */
-#define KN05_RESERVED_4	(29*CHUNK_SIZE)		/* unused? */
-#define KN05_RESERVED_5	(30*CHUNK_SIZE)		/* unused? */
-#define KN05_RESERVED_6	(31*CHUNK_SIZE)		/* unused? */
+#define KN05_MB_ROM	(16*IOASIC_SLOT_SIZE)	/* KN05 card ROM */
+#define KN05_IOCTL	(17*IOASIC_SLOT_SIZE)	/* I/O ASIC */
+#define KN05_ESAR	(18*IOASIC_SLOT_SIZE)	/* LANCE MAC address chip */
+#define KN05_LANCE	(19*IOASIC_SLOT_SIZE)	/* LANCE Ethernet */
+#define KN05_MB_INT	(20*IOASIC_SLOT_SIZE)	/* MB interrupt register? */
+#define KN05_MB_UNKN_0	(21*IOASIC_SLOT_SIZE)	/* MB unknown register */
+#define KN05_MB_UNKN_1	(22*IOASIC_SLOT_SIZE)	/* MB unknown register */
+#define KN05_MB_CSR	(23*IOASIC_SLOT_SIZE)	/* MB control & status */
+#define KN05_RESERVED_0	(24*IOASIC_SLOT_SIZE)	/* unused? */
+#define KN05_RESERVED_1	(25*IOASIC_SLOT_SIZE)	/* unused? */
+#define KN05_RESERVED_2	(26*IOASIC_SLOT_SIZE)	/* unused? */
+#define KN05_RESERVED_3	(27*IOASIC_SLOT_SIZE)	/* unused? */
+#define KN05_SCSI	(28*IOASIC_SLOT_SIZE)	/* ASC SCSI */
+#define KN05_RESERVED_4	(29*IOASIC_SLOT_SIZE)	/* unused? */
+#define KN05_RESERVED_5	(30*IOASIC_SLOT_SIZE)	/* unused? */
+#define KN05_RESERVED_6	(31*IOASIC_SLOT_SIZE)	/* unused? */
 
 /*
  * Bits for the MB interrupt (?) register.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dec/kn230.h linux-2.4.20/include/asm-mips/dec/kn230.h
--- linux-2.4.19/include/asm-mips/dec/kn230.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dec/kn230.h	2002-10-29 11:18:34.000000000 +0000
@@ -10,8 +10,8 @@
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
  */
-#ifndef __ASM_MIPS_DEC_KN230_H 
-#define __ASM_MIPS_DEC_KN230_H 
+#ifndef __ASM_MIPS_DEC_KN230_H
+#define __ASM_MIPS_DEC_KN230_H
 
 /*
  * CPU interrupt bits.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dec/machtype.h linux-2.4.20/include/asm-mips/dec/machtype.h
--- linux-2.4.19/include/asm-mips/dec/machtype.h	2000-02-25 06:52:30.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dec/machtype.h	2002-10-29 11:18:33.000000000 +0000
@@ -8,8 +8,8 @@
  * Copyright (c) 1998, 2000 Harald Koerfgen
  */
 
-#ifndef __ASM_DEC_MACHTYPE_H 
-#define __ASM_DEC_MACHTYPE_H 
+#ifndef __ASM_DEC_MACHTYPE_H
+#define __ASM_DEC_MACHTYPE_H
 
 #include <asm/bootinfo.h>
 
@@ -17,7 +17,7 @@
 			 mips_machtype == MACH_DS5000_1XX || \
 			 mips_machtype == MACH_DS5000_XX  || \
 			 mips_machtype == MACH_DS5000_2X0)
-		      
+
 #define IOASIC		(mips_machtype == MACH_DS5000_1XX || \
 			 mips_machtype == MACH_DS5000_XX  || \
 			 mips_machtype == MACH_DS5000_2X0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dec/rtc-dec.h linux-2.4.20/include/asm-mips/dec/rtc-dec.h
--- linux-2.4.19/include/asm-mips/dec/rtc-dec.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dec/rtc-dec.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,32 @@
+/*
+ *	include/asm-mips/dec/rtc-dec.h
+ *
+ *	RTC definitions for DECstation style attached Dallas DS1287 chip.
+ *
+ *	Copyright (C) 2002  Maciej W. Rozycki
+ *
+ *	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.
+ */
+#ifndef __ASM_MIPS_DEC_RTC_DEC_H
+#define __ASM_MIPS_DEC_RTC_DEC_H
+
+#include <linux/types.h>
+
+#include <asm/addrspace.h>
+
+extern volatile u8 *dec_rtc_base;
+extern unsigned long dec_kn_slot_size;
+
+extern struct rtc_ops dec_rtc_ops;
+
+#define RTC_PORT(x)	CPHYSADDR(dec_rtc_base)
+#define RTC_IO_EXTENT	dec_kn_slot_size
+#define RTC_IOMAPPED	0
+#define RTC_IRQ		0
+
+#define RTC_DEC_YEAR	0x3f	/* Where we store the real year on DECs.  */
+
+#endif /* __ASM_MIPS_DEC_RTC_DEC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dec/tc.h linux-2.4.20/include/asm-mips/dec/tc.h
--- linux-2.4.19/include/asm-mips/dec/tc.h	1999-06-26 00:37:53.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dec/tc.h	2002-10-29 11:18:31.000000000 +0000
@@ -28,7 +28,7 @@
  */
 extern void release_tc_card(int);
 /*
- * Return base address of card in slot 
+ * Return base address of card in slot
  */
 extern unsigned long get_tc_base_addr(int);
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dec/tcinfo.h linux-2.4.20/include/asm-mips/dec/tcinfo.h
--- linux-2.4.19/include/asm-mips/dec/tcinfo.h	1999-06-26 00:37:53.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dec/tcinfo.h	2002-10-29 11:18:34.000000000 +0000
@@ -1,4 +1,4 @@
-/* 
+/*
  * Various TURBOchannel related stuff
  *
  * This file is subject to the terms and conditions of the GNU General Public
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dec/tcmodule.h linux-2.4.20/include/asm-mips/dec/tcmodule.h
--- linux-2.4.19/include/asm-mips/dec/tcmodule.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dec/tcmodule.h	2002-10-29 11:18:34.000000000 +0000
@@ -1,4 +1,4 @@
-/* 
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -17,7 +17,7 @@
  */
 #ifndef __ASM_DEC_TCMODULE_H
 #define __ASM_DEC_TCMODULE_H
- 
+
 #define OLDCARD 0x3c0000
 #define NEWCARD 0x000000
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/delay.h linux-2.4.20/include/asm-mips/delay.h
--- linux-2.4.19/include/asm-mips/delay.h	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/include/asm-mips/delay.h	2002-10-29 11:18:39.000000000 +0000
@@ -10,6 +10,7 @@
 #define _ASM_DELAY_H
 
 #include <linux/config.h>
+#include <linux/param.h>
 
 extern unsigned long loops_per_jiffy;
 
@@ -39,7 +40,11 @@
 {
 	unsigned long lo;
 
+#if (HZ == 100)
 	usecs *= 0x00068db8;		/* 2**32 / (1000000 / HZ) */
+#elif (HZ == 128)
+	usecs *= 0x0008637b;		/* 2**32 / (1000000 / HZ) */
+#endif
 	__asm__("multu\t%2,%3"
 		:"=h" (usecs), "=l" (lo)
 		:"r" (usecs),"r" (lpj));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/dma.h linux-2.4.20/include/asm-mips/dma.h
--- linux-2.4.19/include/asm-mips/dma.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/dma.h	2002-10-29 11:18:30.000000000 +0000
@@ -43,7 +43,7 @@
  *  - page registers for 5-7 don't use data bit 0, represent 128K pages
  *  - page registers for 0-3 use bit 0, represent 64K pages
  *
- * DMA transfers are limited to the lower 16MB of _physical_ memory.  
+ * DMA transfers are limited to the lower 16MB of _physical_ memory.
  * Note that addresses loaded into registers must be _physical_ addresses,
  * not logical addresses (which may differ if paging is active).
  *
@@ -53,7 +53,7 @@
  *    |  ...  |   |  ... |   |  ... |
  *    |  ...  |   |  ... |   |  ... |
  *    |  ...  |   |  ... |   |  ... |
- *   P7  ...  P0  A7 ... A0  A7 ... A0   
+ *   P7  ...  P0  A7 ... A0  A7 ... A0
  * |    Page    | Addr MSB | Addr LSB |   (DMA registers)
  *
  *  Address mapping for channels 5-7:
@@ -62,7 +62,7 @@
  *    |  ...  |   \   \   ... \  \  \  ... \  \
  *    |  ...  |    \   \   ... \  \  \  ... \  (not used)
  *    |  ...  |     \   \   ... \  \  \  ... \
- *   P7  ...  P1 (0) A7 A6  ... A0 A7 A6 ... A0   
+ *   P7  ...  P1 (0) A7 A6  ... A0 A7 A6 ... A0
  * |      Page      |  Addr MSB   |  Addr LSB  |   (DMA registers)
  *
  * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses
@@ -71,7 +71,7 @@
  *
  * Transfer count (_not # bytes_) is limited to 64K, represented as actual
  * count - 1 : 64K => 0xFFFF, 1 => 0x0000.  Thus, count is always 1 or more,
- * and up to 128K bytes may be transferred on channels 5-7 in one operation. 
+ * and up to 128K bytes may be transferred on channels 5-7 in one operation.
  *
  */
 
@@ -83,7 +83,13 @@
  * Deskstations or Acer PICA but not the much more versatile DMA logic used
  * for the local devices on Acer PICA or Magnums.
  */
+#ifdef CONFIG_SGI_IP22
+/* Horrible hack to have a correct DMA window on IP22 */
+#include <asm/sgi/sgimc.h>
+#define MAX_DMA_ADDRESS		(PAGE_OFFSET + SGIMC_SEG0_BADDR + 0x01000000)
+#else
 #define MAX_DMA_ADDRESS		(PAGE_OFFSET + 0x01000000)
+#endif
 
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE	0x00	/* 8 bit slave DMA, channels 0..3 */
@@ -142,6 +148,7 @@
 #define DMA_MODE_WRITE	0x48	/* memory to I/O, no autoinit, increment, single mode */
 #define DMA_MODE_CASCADE 0xC0   /* pass thru DREQ->HRQ, DACK<-HLDA only */
 
+#define DMA_AUTOINIT	0x10
 
 extern spinlock_t  dma_spin_lock;
 
@@ -286,7 +293,7 @@
 
 	count = 1 + dma_inb(io_port);
 	count += dma_inb(io_port) << 8;
-	
+
 	return (dmanr<=3)? count : (count<<1);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/elf.h linux-2.4.20/include/asm-mips/elf.h
--- linux-2.4.19/include/asm-mips/elf.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/elf.h	2002-10-29 11:18:39.000000000 +0000
@@ -16,10 +16,11 @@
 #define EF_MIPS_ARCH_3      0x20000000  /* -mips3 code.  */
 #define EF_MIPS_ARCH_4      0x30000000  /* -mips4 code.  */
 #define EF_MIPS_ARCH_5      0x40000000  /* -mips5 code.  */
-#define EF_MIPS_ARCH_32     0x60000000  /* MIPS32 code.  */
-#define EF_MIPS_ARCH_64     0x70000000  /* MIPS64 code.  */
-#define EF_MIPS_ARCH_32R2   0x80000000  /* MIPS32 code.  */
-#define EF_MIPS_ARCH_64R2   0x90000000  /* MIPS64 code.  */
+#define EF_MIPS_ARCH_32     0x50000000  /* MIPS32 code.  */
+#define EF_MIPS_ARCH_64     0x60000000  /* MIPS64 code.  */
+/* The ABI of a file. */
+#define EF_MIPS_ABI_O32     0x00001000  /* O32 ABI.  */
+#define EF_MIPS_ABI_O64     0x00002000  /* O32 extended for 64 bit.  */
 
 typedef unsigned long elf_greg_t;
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
@@ -37,10 +38,12 @@
 									\
 	if (__h->e_machine != EM_MIPS)					\
 		__res = 0;						\
-	if (((__h->e_flags & EF_MIPS_ARCH) != EF_MIPS_ARCH_1) &&       	\
-	    ((__h->e_flags & EF_MIPS_ARCH) != EF_MIPS_ARCH_2) &&       	\
-	    ((__h->e_flags & EF_MIPS_ARCH) != EF_MIPS_ARCH_32) &&      	\
-	    ((__h->e_flags & EF_MIPS_ARCH) != EF_MIPS_ARCH_32R2))      	\
+	if (__h->e_ident[EI_CLASS] != ELFCLASS32)			\
+		__res = 0;						\
+	if ((__h->e_flags & EF_MIPS_ABI2) != 0)				\
+		__res = 0;						\
+	if (((__h->e_flags & EF_MIPS_ABI) != 0) &&			\
+	    ((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32))		\
 		__res = 0;						\
 									\
 	__res;								\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/fcntl.h linux-2.4.20/include/asm-mips/fcntl.h
--- linux-2.4.19/include/asm-mips/fcntl.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/fcntl.h	2002-10-29 11:18:49.000000000 +0000
@@ -65,7 +65,7 @@
 /* operations for bsd flock(), also used by the kernel implementation */
 #define LOCK_SH		1	/* shared lock */
 #define LOCK_EX		2	/* exclusive lock */
-#define LOCK_NB		4	/* or'd with one of the above to prevent		XXXXXXXXXXXXXXXXXX
+#define LOCK_NB		4	/* or'd with one of the above to prevent
 				   blocking */
 #define LOCK_UN		8	/* remove lock */
 
@@ -74,14 +74,21 @@
 #define LOCK_WRITE	128	/* ... Which allows concurrent write operations */
 #define LOCK_RW		192	/* ... Which allows concurrent read & write ops */
 
+/*
+ * The flavours of struct flock.  "struct flock" is the ABI compliant
+ * variant.  Finally struct flock64 is the LFS variant of struct flock.  As
+ * a historic accident and inconsistence with the ABI definition it doesn't
+ * contain all the same fields as struct flock.
+ */
+
 typedef struct flock {
-	short l_type;
-	short l_whence;
+	short	l_type;
+	short	l_whence;
 	__kernel_off_t l_start;
 	__kernel_off_t l_len;
-	long  l_sysid;			/* ABI junk, unused on Linux */
+	long	l_sysid;
 	__kernel_pid_t l_pid;
-	long  pad[4];			/* ABI junk, unused on Linux */
+	long	pad[4];
 } flock_t;
 
 typedef struct flock64 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/galileo-boards/ev64120.h linux-2.4.20/include/asm-mips/galileo-boards/ev64120.h
--- linux-2.4.19/include/asm-mips/galileo-boards/ev64120.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/galileo-boards/ev64120.h	2002-10-29 11:18:31.000000000 +0000
@@ -15,7 +15,7 @@
  */
 #define GT64120_BASE    (KSEG1ADDR(0x14000000))
 #define MIPS_GT_BASE    GT64120_BASE
- 
+
 /*
  *   PCI Bus allocation
  */
@@ -23,12 +23,12 @@
 #define GT_PCI_MEM_SIZE    0x02000000
 #define GT_PCI_IO_BASE     0x10000000
 #define GT_PCI_IO_SIZE     0x02000000
-#define GT_ISA_IO_BASE     PCI_IO_BASE          
+#define GT_ISA_IO_BASE     PCI_IO_BASE
 
 /*
  *   Duart I/O ports.
  */
-#define EV64120_COM1_BASE_ADDR  (0x1d000000 + 0x20) 
+#define EV64120_COM1_BASE_ADDR  (0x1d000000 + 0x20)
 #define EV64120_COM2_BASE_ADDR  (0x1d000000 + 0x00)
 
 
@@ -46,7 +46,7 @@
 
 
 /*
- * Because of an error/peculiarity in the Galileo chip, we need to swap the 
+ * Because of an error/peculiarity in the Galileo chip, we need to swap the
  * bytes when running bigendian.
  */
 
@@ -54,6 +54,6 @@
              *(volatile u32 *)(MIPS_GT_BASE+ofs) = cpu_to_le32(data)
 #define GT_READ(ofs, data)   \
              *data = le32_to_cpu(*(volatile u32 *)(MIPS_GT_BASE+ofs))
-    
+
 
 #endif /* !(_MIPS_EV64120_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/galileo-boards/ev96100.h linux-2.4.20/include/asm-mips/galileo-boards/ev96100.h
--- linux-2.4.19/include/asm-mips/galileo-boards/ev96100.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/galileo-boards/ev96100.h	2002-10-29 11:18:49.000000000 +0000
@@ -11,7 +11,7 @@
  */
 #define GT64120_BASE    (KSEG1ADDR(0x14000000))
 #define MIPS_GT_BASE    GT64120_BASE
- 
+
 /*
  *   PCI Bus allocation
  */
@@ -19,12 +19,12 @@
 #define GT_PCI_MEM_SIZE    0x02000000
 #define GT_PCI_IO_BASE     0x10000000
 #define GT_PCI_IO_SIZE     0x02000000
-#define GT_ISA_IO_BASE     PCI_IO_BASE          
+#define GT_ISA_IO_BASE     PCI_IO_BASE
 
 /*
  *   Duart I/O ports.
  */
-#define EV96100_COM1_BASE_ADDR  (0xBD000000 + 0x20) 
+#define EV96100_COM1_BASE_ADDR  (0xBD000000 + 0x20)
 #define EV96100_COM2_BASE_ADDR  (0xBD000000 + 0x00)
 
 
@@ -42,7 +42,7 @@
 
 
 /*
- * Because of an error/peculiarity in the Galileo chip, we need to swap the 
+ * Because of an error/peculiarity in the Galileo chip, we need to swap the
  * bytes when running bigendian.
  */
 
@@ -50,6 +50,6 @@
              *(volatile u32 *)(MIPS_GT_BASE+ofs) = cpu_to_le32(data)
 #define GT_READ(ofs, data)   \
              data = le32_to_cpu(*(volatile u32 *)(MIPS_GT_BASE+ofs))
-    
+
 
 #endif /* !(_MIPS_EV96100_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/galileo-boards/ev96100int.h linux-2.4.20/include/asm-mips/galileo-boards/ev96100int.h
--- linux-2.4.19/include/asm-mips/galileo-boards/ev96100int.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/galileo-boards/ev96100int.h	2002-10-29 11:18:48.000000000 +0000
@@ -4,7 +4,7 @@
 #ifndef _MIPS_EV96100INT_H
 #define _MIPS_EV96100INT_H
 
-#define EV96100INT_UART_0    6     /* IP 6 */     
+#define EV96100INT_UART_0    6     /* IP 6 */
 #define EV96100INT_TIMER     7     /* IP 7 */
 
 extern void ev96100int_init(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/galileo-boards/evb64120A/cntmr.h linux-2.4.20/include/asm-mips/galileo-boards/evb64120A/cntmr.h
--- linux-2.4.19/include/asm-mips/galileo-boards/evb64120A/cntmr.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/galileo-boards/evb64120A/cntmr.h	2002-10-29 11:18:35.000000000 +0000
@@ -2,7 +2,7 @@
 
 /* Copyright - Galileo technology */
 
-#ifndef __INCtimerCounterDrvh 
+#ifndef __INCtimerCounterDrvh
 #define __INCtimerCounterDrvh
 
 /* includes */
@@ -31,12 +31,12 @@
 typedef enum counterTimer{CNTMR_0,CNTMR_1,CNTMR_2,CNTMR_3} CNTMR_NUM;
 typedef enum cntTmrOpModes{COUNTER, TIMER} CNT_TMR_OP_MODES;
 
-bool    cntTmrLoad(unsigned int countNum, unsigned int value);	
+bool    cntTmrLoad(unsigned int countNum, unsigned int value);
 bool    cntTmrSetMode(CNTMR_NUM countNum, CNT_TMR_OP_MODES opMode);
-bool    cntTmrEnable(CNTMR_NUM countNum);  
+bool    cntTmrEnable(CNTMR_NUM countNum);
 bool    cntTmrStart (CNTMR_NUM countNum,unsigned int countValue,
                    CNT_TMR_OP_MODES opMode);
-unsigned int    cntTmrDisable(CNTMR_NUM countNum);              
+unsigned int    cntTmrDisable(CNTMR_NUM countNum);
 unsigned int    cntTmrRead(CNTMR_NUM countNum);
 
 #endif /* __INCtimerCounterDrvh */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/galileo-boards/evb64120A/core.h linux-2.4.20/include/asm-mips/galileo-boards/evb64120A/core.h
--- linux-2.4.19/include/asm-mips/galileo-boards/evb64120A/core.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/galileo-boards/evb64120A/core.h	2002-10-29 11:18:32.000000000 +0000
@@ -4,7 +4,7 @@
  *
  * Copyright Galileo Technology.
  */
-#ifndef __INCcoreh 
+#ifndef __INCcoreh
 #define __INCcoreh
 
 #include <linux/types.h>
@@ -78,7 +78,7 @@
 typedef enum _bool{false,true} bool;
 
 #ifndef NULL
-#define NULL 0                                  
+#define NULL 0
 #endif
 
 /* The two following defines are according to MIPS architecture. */
@@ -111,7 +111,7 @@
 /* Write 32/16/8 bits Cacheable */
 #define WRITE_CHAR_CACHEABLE(address, data)				\
 	(*((u8 *)((address) | MIPS_CACHEABLE)) = (data))
-                
+
 #define WRITE_SHORT_CACHEABLE(address, data)				\
 	(*((u16 *)((address) | MIPS_CACHEABLE)) = (u16) data)
 
@@ -158,8 +158,8 @@
 	(*((u32 *)((address) | MIPS_CACHEABLE)))
 
 /*
- * SET_REG_BITS(regOffset,bits) - 
- * gets register offset and bits: a 32bit value. It set to logic '1' in the  
+ * SET_REG_BITS(regOffset,bits) -
+ * gets register offset and bits: a 32bit value. It set to logic '1' in the
  * internal register the bits which given as an input example:
  * SET_REG_BITS(0x840,BIT3 | BIT24 | BIT30) - set bits: 3,24 and 30 to logic
  * '1' in register 0x840 while the other bits stays as is.
@@ -170,7 +170,7 @@
 
 /*
  * RESET_REG_BITS(regOffset,bits) -
- * gets register offset and bits: a 32bit value. It set to logic '0' in the  
+ * gets register offset and bits: a 32bit value. It set to logic '0' in the
  * internal register the bits which given as an input example:
  * RESET_REG_BITS(0x840,BIT3 | BIT24 | BIT30) - set bits: 3,24 and 30 to logic
  * '0' in register 0x840 while the other bits stays as is.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/galileo-boards/evb64120A/dma.h linux-2.4.20/include/asm-mips/galileo-boards/evb64120A/dma.h
--- linux-2.4.19/include/asm-mips/galileo-boards/evb64120A/dma.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/galileo-boards/evb64120A/dma.h	2002-10-29 11:18:40.000000000 +0000
@@ -2,7 +2,7 @@
 
 /* Copyright Galileo Technology. */
 
-#ifndef __INCdmah 
+#ifndef __INCdmah
 #define __INCdmah
 
 /* includes */
@@ -55,11 +55,11 @@
 typedef enum prioChan01{ROUND_ROBIN01,CH_1,CH_0} PRIO_CHAN_0_1;
 typedef enum prioChan23{ROUND_ROBIN23,CH_3,CH_2} PRIO_CHAN_2_3;
 typedef enum prioGroup{ROUND_ROBIN,CH_2_3,CH_0_1} PRIO_GROUP;
-typedef enum prioOpt{RETURN_BUS,KEEP_BUS} PRIO_OPT; 
+typedef enum prioOpt{RETURN_BUS,KEEP_BUS} PRIO_OPT;
 
 typedef struct dmaRecored
 {
-    unsigned int    ByteCnt;                                            
+    unsigned int    ByteCnt;
     unsigned int    SrcAdd;
     unsigned int    DestAdd;
     unsigned int    NextRecPtr;
@@ -74,7 +74,7 @@
 bool	dmaCommand (DMA_ENGINE channel,unsigned int command);
 bool    isDmaChannelActive (DMA_ENGINE channel);
 
-bool    changeDmaPriority(PRIO_CHAN_0_1 prio_01, PRIO_CHAN_2_3 prio_23, 
+bool    changeDmaPriority(PRIO_CHAN_0_1 prio_01, PRIO_CHAN_2_3 prio_23,
                           PRIO_GROUP prioGrp, PRIO_OPT prioOpt);
 
 #endif /* __INCdmah */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/galileo-boards/evb64120A/eeprom_param.h linux-2.4.20/include/asm-mips/galileo-boards/evb64120A/eeprom_param.h
--- linux-2.4.19/include/asm-mips/galileo-boards/evb64120A/eeprom_param.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/galileo-boards/evb64120A/eeprom_param.h	2002-10-29 11:18:49.000000000 +0000
@@ -32,12 +32,12 @@
 struct eeprom_parameters {
   unsigned int boot_source;
   unsigned int operating_system;
-  
+
   /* network loader parametrs */
   unsigned int host_ip;
   unsigned int server_ip;
   char bootimage[64];
-  
+
   /* Board parameters */
   char eth0_mac[6];
   char eth1_mac[6];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/galileo-boards/evb64120A/flashdrv.h linux-2.4.20/include/asm-mips/galileo-boards/evb64120A/flashdrv.h
--- linux-2.4.19/include/asm-mips/galileo-boards/evb64120A/flashdrv.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/galileo-boards/evb64120A/flashdrv.h	2002-10-29 11:18:49.000000000 +0000
@@ -2,7 +2,7 @@
 
 /* Copyright Galileo Technology. */
 
-#ifndef __INCflashdrvh 
+#ifndef __INCflashdrvh
 #define __INCflashdrvh
 
 /* includes */
@@ -11,7 +11,7 @@
 
 /* defines */
 
-/* Supported Flash Manufactures */ 
+/* Supported Flash Manufactures */
 
 #define AMD_FLASH       0x01
 #define ST_FLASH        0x20
@@ -21,7 +21,7 @@
 /* Supported Flash Devices */
 
 /* AMD Devices */
-#define AM29F400BT      0x2223    
+#define AM29F400BT      0x2223
 #define AM29F400BB      0x22AB
 #define AM29LV800BT     0x22DA
 #define AM29LV400BT     0x22B9
@@ -34,12 +34,12 @@
 #define I28F640J3A      0x17
 #define I28F128J3A      0x18
 #define I28F320B3_B     0x8897
-#define I28F320B3_T     0x8896 
+#define I28F320B3_T     0x8896
 #define I28F160B3_B     0x8891
 #define I28F160B3_T     0x8890
 
-#define POINTER_TO_FLASH           flashParametrs[0] 
-#define FLASH_BASE_ADDRESS         flashParametrs[1] 
+#define POINTER_TO_FLASH           flashParametrs[0]
+#define FLASH_BASE_ADDRESS         flashParametrs[1]
 #define FLASH_WIDTH                flashParametrs[2] /* In Bytes */
 #define FLASH_MODE                 flashParametrs[3] /* In bits  */
 #define MANUFACTOR_ID              POINTER_TO_FLASH + 0
@@ -47,11 +47,11 @@
 #define NUMBER_OF_SECTORS          POINTER_TO_FLASH + 2
 #define FIRST_SECTOR_SIZE          POINTER_TO_FLASH + 3
 #define NUM_OF_DEVICES             FLASH_WIDTH / (FLASH_MODE / 8)
- 
+
 /* typedefs */
 
 typedef enum _FlashMode {PURE8,X8 = 8,X16 = 16} FLASHmode;
-/* PURE8 - when using a flash device whice can be configurated only as  
+/* PURE8 - when using a flash device whice can be configurated only as
             8 bit device. */
 /* X8    - when using a flash device which is 16 bit wide but configured to
            operate in 8 bit mode.*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/galileo-boards/evb64120A/i2o.h linux-2.4.20/include/asm-mips/galileo-boards/evb64120A/i2o.h
--- linux-2.4.19/include/asm-mips/galileo-boards/evb64120A/i2o.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/galileo-boards/evb64120A/i2o.h	2002-10-29 11:18:37.000000000 +0000
@@ -5,11 +5,11 @@
 #ifndef __INCi2oh
 #define __INCi2oh
 
-/* includes */            
-            
+/* includes */
+
 #include "core.h"
 
-/* typedefs */           
+/* typedefs */
 
 typedef enum _i2oMessageReg{MESSAGE_REG_0,MESSAGE_REG_1} I2O_MESSAGE_REG;
 typedef enum _cirQueSize{I20_16K = 0x1,I20_32K = 0x2,I20_64K = 0x4,\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/galileo-boards/evb64120A/pci.h linux-2.4.20/include/asm-mips/galileo-boards/evb64120A/pci.h
--- linux-2.4.19/include/asm-mips/galileo-boards/evb64120A/pci.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/galileo-boards/evb64120A/pci.h	2002-10-29 11:18:31.000000000 +0000
@@ -29,7 +29,7 @@
 
 #define PCI0_MEMORY_ENABLE(deviceNumber) pci0WriteConfigReg(                  \
           PCI_0STATUS_AND_COMMAND,deviceNumber,MEMORY_ENABLE |                \
-          pci0ReadConfigReg(PCI_0STATUS_AND_COMMAND,deviceNumber) )           
+          pci0ReadConfigReg(PCI_0STATUS_AND_COMMAND,deviceNumber) )
 
 #define PCI1_MEMORY_ENABLE(deviceNumber) pci1WriteConfigReg(                  \
           PCI_0STATUS_AND_COMMAND,deviceNumber,MEMORY_ENABLE |                \
@@ -59,9 +59,9 @@
           PCI_0STATUS_AND_COMMAND,deviceNumber,0xfffffff8  &                  \
           pci1ReadConfigReg(PCI_0STATUS_AND_COMMAND,deviceNumber))
 
-#define 	MASTER_ENABLE			BIT2  
-#define		MEMORY_ENABLE			BIT1  
-#define		I_O_ENABLE  			BIT0  
+#define 	MASTER_ENABLE			BIT2
+#define		MEMORY_ENABLE			BIT1
+#define		I_O_ENABLE  			BIT0
 #define     SELF                    0
 /* Agent on the PCI bus may have up to 6 BARS. */
 #define     BAR0                    0x10
@@ -70,7 +70,7 @@
 #define     BAR3                    0x1c
 #define     BAR4                    0x20
 #define     BAR5                    0x24
-   
+
 
 /* typedefs */
 
@@ -78,7 +78,7 @@
 {
     char            type[20];
     unsigned int    deviceNum;
-    unsigned int    venID;                                            
+    unsigned int    venID;
     unsigned int    deviceID;
     unsigned int    bar0Base;
     unsigned int    bar0Size;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/galileo-boards/gt96100.h linux-2.4.20/include/asm-mips/galileo-boards/gt96100.h
--- linux-2.4.19/include/asm-mips/galileo-boards/gt96100.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/galileo-boards/gt96100.h	2002-10-29 11:18:51.000000000 +0000
@@ -21,7 +21,7 @@
  * ########################################################################
  *
  * Register offsets of the MIPS GT96100 Advanced Communication Controller.
- * 
+ *
  */
 #ifndef _GT96100_H
 #define _GT96100_H
@@ -46,24 +46,24 @@
 #define GT96100_CPU_INTERF_CONFIG 0x000000
 
 /* Ethernet Ports */
-#define GT96100_ETH_PHY_ADDR_REG             0x080800 
-#define GT96100_ETH_SMI_REG                  0x080810 
+#define GT96100_ETH_PHY_ADDR_REG             0x080800
+#define GT96100_ETH_SMI_REG                  0x080810
 /*
   These are offsets to port 0 registers. Add GT96100_ETH_IO_SIZE to
   get offsets to port 1 registers.
 */
-#define GT96100_ETH_PORT_CONFIG          0x084800 
-#define GT96100_ETH_PORT_CONFIG_EXT      0x084808 
-#define GT96100_ETH_PORT_COMM            0x084810 
-#define GT96100_ETH_PORT_STATUS          0x084818 
-#define GT96100_ETH_SER_PARAM            0x084820 
-#define GT96100_ETH_HASH_TBL_PTR         0x084828 
-#define GT96100_ETH_FLOW_CNTRL_SRC_ADDR_L    0x084830 
-#define GT96100_ETH_FLOW_CNTRL_SRC_ADDR_H    0x084838 
-#define GT96100_ETH_SDMA_CONFIG          0x084840 
-#define GT96100_ETH_SDMA_COMM            0x084848 
-#define GT96100_ETH_INT_CAUSE            0x084850 
-#define GT96100_ETH_INT_MASK             0x084858 
+#define GT96100_ETH_PORT_CONFIG          0x084800
+#define GT96100_ETH_PORT_CONFIG_EXT      0x084808
+#define GT96100_ETH_PORT_COMM            0x084810
+#define GT96100_ETH_PORT_STATUS          0x084818
+#define GT96100_ETH_SER_PARAM            0x084820
+#define GT96100_ETH_HASH_TBL_PTR         0x084828
+#define GT96100_ETH_FLOW_CNTRL_SRC_ADDR_L    0x084830
+#define GT96100_ETH_FLOW_CNTRL_SRC_ADDR_H    0x084838
+#define GT96100_ETH_SDMA_CONFIG          0x084840
+#define GT96100_ETH_SDMA_COMM            0x084848
+#define GT96100_ETH_INT_CAUSE            0x084850
+#define GT96100_ETH_INT_MASK             0x084858
 #define GT96100_ETH_1ST_RX_DESC_PTR0         0x084880
 #define GT96100_ETH_1ST_RX_DESC_PTR1         0x084884
 #define GT96100_ETH_1ST_RX_DESC_PTR2         0x084888
@@ -74,142 +74,142 @@
 #define GT96100_ETH_CURR_RX_DESC_PTR3        0x0848AC
 #define GT96100_ETH_CURR_TX_DESC_PTR0        0x0848E0
 #define GT96100_ETH_CURR_TX_DESC_PTR1        0x0848E4
-#define GT96100_ETH_MIB_COUNT_BASE           0x085800 
+#define GT96100_ETH_MIB_COUNT_BASE           0x085800
 
 /* SDMAs */
 #define GT96100_SDMA_GROUP_CONFIG           0x101AF0
 /* SDMA Group 0 */
-#define GT96100_SDMA_G0_CHAN0_CONFIG        0x000900 
-#define GT96100_SDMA_G0_CHAN0_COMM          0x000908 
-#define GT96100_SDMA_G0_CHAN0_RX_DESC_BASE      0x008900 
+#define GT96100_SDMA_G0_CHAN0_CONFIG        0x000900
+#define GT96100_SDMA_G0_CHAN0_COMM          0x000908
+#define GT96100_SDMA_G0_CHAN0_RX_DESC_BASE      0x008900
 #define GT96100_SDMA_G0_CHAN0_CURR_RX_DESC_PTR  0x008910
-#define GT96100_SDMA_G0_CHAN0_TX_DESC_BASE      0x00C900 
+#define GT96100_SDMA_G0_CHAN0_TX_DESC_BASE      0x00C900
 #define GT96100_SDMA_G0_CHAN0_CURR_TX_DESC_PTR  0x00C910
 #define GT96100_SDMA_G0_CHAN0_1ST_TX_DESC_PTR   0x00C914
 #define GT96100_SDMA_G0_CHAN1_CONFIG        0x010900
 #define GT96100_SDMA_G0_CHAN1_COMM          0x010908
-#define GT96100_SDMA_G0_CHAN1_RX_DESC_BASE      0x018900 
+#define GT96100_SDMA_G0_CHAN1_RX_DESC_BASE      0x018900
 #define GT96100_SDMA_G0_CHAN1_CURR_RX_DESC_PTR  0x018910
-#define GT96100_SDMA_G0_CHAN1_TX_DESC_BASE      0x01C900 
+#define GT96100_SDMA_G0_CHAN1_TX_DESC_BASE      0x01C900
 #define GT96100_SDMA_G0_CHAN1_CURR_TX_DESC_PTR  0x01C910
 #define GT96100_SDMA_G0_CHAN1_1ST_TX_DESC_PTR   0x01C914
 #define GT96100_SDMA_G0_CHAN2_CONFIG        0x020900
 #define GT96100_SDMA_G0_CHAN2_COMM          0x020908
-#define GT96100_SDMA_G0_CHAN2_RX_DESC_BASE      0x028900 
+#define GT96100_SDMA_G0_CHAN2_RX_DESC_BASE      0x028900
 #define GT96100_SDMA_G0_CHAN2_CURR_RX_DESC_PTR  0x028910
-#define GT96100_SDMA_G0_CHAN2_TX_DESC_BASE      0x02C900 
+#define GT96100_SDMA_G0_CHAN2_TX_DESC_BASE      0x02C900
 #define GT96100_SDMA_G0_CHAN2_CURR_TX_DESC_PTR  0x02C910
 #define GT96100_SDMA_G0_CHAN2_1ST_TX_DESC_PTR   0x02C914
 #define GT96100_SDMA_G0_CHAN3_CONFIG        0x030900
 #define GT96100_SDMA_G0_CHAN3_COMM          0x030908
-#define GT96100_SDMA_G0_CHAN3_RX_DESC_BASE      0x038900 
+#define GT96100_SDMA_G0_CHAN3_RX_DESC_BASE      0x038900
 #define GT96100_SDMA_G0_CHAN3_CURR_RX_DESC_PTR  0x038910
-#define GT96100_SDMA_G0_CHAN3_TX_DESC_BASE      0x03C900 
+#define GT96100_SDMA_G0_CHAN3_TX_DESC_BASE      0x03C900
 #define GT96100_SDMA_G0_CHAN3_CURR_TX_DESC_PTR  0x03C910
 #define GT96100_SDMA_G0_CHAN3_1ST_TX_DESC_PTR   0x03C914
 #define GT96100_SDMA_G0_CHAN4_CONFIG        0x040900
 #define GT96100_SDMA_G0_CHAN4_COMM          0x040908
-#define GT96100_SDMA_G0_CHAN4_RX_DESC_BASE      0x048900 
+#define GT96100_SDMA_G0_CHAN4_RX_DESC_BASE      0x048900
 #define GT96100_SDMA_G0_CHAN4_CURR_RX_DESC_PTR  0x048910
-#define GT96100_SDMA_G0_CHAN4_TX_DESC_BASE      0x04C900 
+#define GT96100_SDMA_G0_CHAN4_TX_DESC_BASE      0x04C900
 #define GT96100_SDMA_G0_CHAN4_CURR_TX_DESC_PTR  0x04C910
 #define GT96100_SDMA_G0_CHAN4_1ST_TX_DESC_PTR   0x04C914
 #define GT96100_SDMA_G0_CHAN5_CONFIG        0x050900
 #define GT96100_SDMA_G0_CHAN5_COMM          0x050908
-#define GT96100_SDMA_G0_CHAN5_RX_DESC_BASE      0x058900 
+#define GT96100_SDMA_G0_CHAN5_RX_DESC_BASE      0x058900
 #define GT96100_SDMA_G0_CHAN5_CURR_RX_DESC_PTR  0x058910
-#define GT96100_SDMA_G0_CHAN5_TX_DESC_BASE      0x05C900 
+#define GT96100_SDMA_G0_CHAN5_TX_DESC_BASE      0x05C900
 #define GT96100_SDMA_G0_CHAN5_CURR_TX_DESC_PTR  0x05C910
 #define GT96100_SDMA_G0_CHAN5_1ST_TX_DESC_PTR   0x05C914
 #define GT96100_SDMA_G0_CHAN6_CONFIG        0x060900
 #define GT96100_SDMA_G0_CHAN6_COMM          0x060908
-#define GT96100_SDMA_G0_CHAN6_RX_DESC_BASE      0x068900 
+#define GT96100_SDMA_G0_CHAN6_RX_DESC_BASE      0x068900
 #define GT96100_SDMA_G0_CHAN6_CURR_RX_DESC_PTR  0x068910
-#define GT96100_SDMA_G0_CHAN6_TX_DESC_BASE      0x06C900 
+#define GT96100_SDMA_G0_CHAN6_TX_DESC_BASE      0x06C900
 #define GT96100_SDMA_G0_CHAN6_CURR_TX_DESC_PTR  0x06C910
 #define GT96100_SDMA_G0_CHAN6_1ST_TX_DESC_PTR   0x06C914
 #define GT96100_SDMA_G0_CHAN7_CONFIG        0x070900
 #define GT96100_SDMA_G0_CHAN7_COMM          0x070908
 #define GT96100_SDMA_G0_CHAN7_RX_DESC_BASE      0x078900
 #define GT96100_SDMA_G0_CHAN7_CURR_RX_DESC_PTR  0x078910
-#define GT96100_SDMA_G0_CHAN7_TX_DESC_BASE      0x07C900 
+#define GT96100_SDMA_G0_CHAN7_TX_DESC_BASE      0x07C900
 #define GT96100_SDMA_G0_CHAN7_CURR_TX_DESC_PTR  0x07C910
 #define GT96100_SDMA_G0_CHAN7_1ST_TX_DESC_PTR   0x07C914
 /* SDMA Group 1 */
 #define GT96100_SDMA_G1_CHAN0_CONFIG        0x100900
 #define GT96100_SDMA_G1_CHAN0_COMM          0x100908
-#define GT96100_SDMA_G1_CHAN0_RX_DESC_BASE      0x108900 
+#define GT96100_SDMA_G1_CHAN0_RX_DESC_BASE      0x108900
 #define GT96100_SDMA_G1_CHAN0_CURR_RX_DESC_PTR  0x108910
-#define GT96100_SDMA_G1_CHAN0_TX_DESC_BASE      0x10C900 
-#define GT96100_SDMA_G1_CHAN0_CURR_TX_DESC_PTR  0x10C910 
+#define GT96100_SDMA_G1_CHAN0_TX_DESC_BASE      0x10C900
+#define GT96100_SDMA_G1_CHAN0_CURR_TX_DESC_PTR  0x10C910
 #define GT96100_SDMA_G1_CHAN0_1ST_TX_DESC_PTR   0x10C914
 #define GT96100_SDMA_G1_CHAN1_CONFIG        0x110900
 #define GT96100_SDMA_G1_CHAN1_COMM          0x110908
-#define GT96100_SDMA_G1_CHAN1_RX_DESC_BASE      0x118900 
+#define GT96100_SDMA_G1_CHAN1_RX_DESC_BASE      0x118900
 #define GT96100_SDMA_G1_CHAN1_CURR_RX_DESC_PTR  0x118910
-#define GT96100_SDMA_G1_CHAN1_TX_DESC_BASE      0x11C900 
+#define GT96100_SDMA_G1_CHAN1_TX_DESC_BASE      0x11C900
 #define GT96100_SDMA_G1_CHAN1_CURR_TX_DESC_PTR  0x11C910
 #define GT96100_SDMA_G1_CHAN1_1ST_TX_DESC_PTR   0x11C914
 #define GT96100_SDMA_G1_CHAN2_CONFIG        0x120900
 #define GT96100_SDMA_G1_CHAN2_COMM          0x120908
-#define GT96100_SDMA_G1_CHAN2_RX_DESC_BASE      0x128900 
+#define GT96100_SDMA_G1_CHAN2_RX_DESC_BASE      0x128900
 #define GT96100_SDMA_G1_CHAN2_CURR_RX_DESC_PTR  0x128910
-#define GT96100_SDMA_G1_CHAN2_TX_DESC_BASE      0x12C900 
+#define GT96100_SDMA_G1_CHAN2_TX_DESC_BASE      0x12C900
 #define GT96100_SDMA_G1_CHAN2_CURR_TX_DESC_PTR  0x12C910
 #define GT96100_SDMA_G1_CHAN2_1ST_TX_DESC_PTR   0x12C914
 #define GT96100_SDMA_G1_CHAN3_CONFIG        0x130900
 #define GT96100_SDMA_G1_CHAN3_COMM          0x130908
-#define GT96100_SDMA_G1_CHAN3_RX_DESC_BASE      0x138900 
+#define GT96100_SDMA_G1_CHAN3_RX_DESC_BASE      0x138900
 #define GT96100_SDMA_G1_CHAN3_CURR_RX_DESC_PTR  0x138910
-#define GT96100_SDMA_G1_CHAN3_TX_DESC_BASE      0x13C900 
+#define GT96100_SDMA_G1_CHAN3_TX_DESC_BASE      0x13C900
 #define GT96100_SDMA_G1_CHAN3_CURR_TX_DESC_PTR  0x13C910
 #define GT96100_SDMA_G1_CHAN3_1ST_TX_DESC_PTR   0x13C914
 #define GT96100_SDMA_G1_CHAN4_CONFIG        0x140900
 #define GT96100_SDMA_G1_CHAN4_COMM          0x140908
-#define GT96100_SDMA_G1_CHAN4_RX_DESC_BASE      0x148900 
+#define GT96100_SDMA_G1_CHAN4_RX_DESC_BASE      0x148900
 #define GT96100_SDMA_G1_CHAN4_CURR_RX_DESC_PTR  0x148910
-#define GT96100_SDMA_G1_CHAN4_TX_DESC_BASE      0x14C900 
+#define GT96100_SDMA_G1_CHAN4_TX_DESC_BASE      0x14C900
 #define GT96100_SDMA_G1_CHAN4_CURR_TX_DESC_PTR  0x14C910
 #define GT96100_SDMA_G1_CHAN4_1ST_TX_DESC_PTR   0x14C914
 #define GT96100_SDMA_G1_CHAN5_CONFIG        0x150900
 #define GT96100_SDMA_G1_CHAN5_COMM          0x150908
-#define GT96100_SDMA_G1_CHAN5_RX_DESC_BASE      0x158900 
+#define GT96100_SDMA_G1_CHAN5_RX_DESC_BASE      0x158900
 #define GT96100_SDMA_G1_CHAN5_CURR_RX_DESC_PTR  0x158910
-#define GT96100_SDMA_G1_CHAN5_TX_DESC_BASE      0x15C900 
+#define GT96100_SDMA_G1_CHAN5_TX_DESC_BASE      0x15C900
 #define GT96100_SDMA_G1_CHAN5_CURR_TX_DESC_PTR  0x15C910
 #define GT96100_SDMA_G1_CHAN5_1ST_TX_DESC_PTR   0x15C914
 #define GT96100_SDMA_G1_CHAN6_CONFIG        0x160900
 #define GT96100_SDMA_G1_CHAN6_COMM          0x160908
-#define GT96100_SDMA_G1_CHAN6_RX_DESC_BASE      0x168900 
+#define GT96100_SDMA_G1_CHAN6_RX_DESC_BASE      0x168900
 #define GT96100_SDMA_G1_CHAN6_CURR_RX_DESC_PTR  0x168910
-#define GT96100_SDMA_G1_CHAN6_TX_DESC_BASE      0x16C900 
+#define GT96100_SDMA_G1_CHAN6_TX_DESC_BASE      0x16C900
 #define GT96100_SDMA_G1_CHAN6_CURR_TX_DESC_PTR  0x16C910
 #define GT96100_SDMA_G1_CHAN6_1ST_TX_DESC_PTR   0x16C914
 #define GT96100_SDMA_G1_CHAN7_CONFIG        0x170900
 #define GT96100_SDMA_G1_CHAN7_COMM          0x170908
-#define GT96100_SDMA_G1_CHAN7_RX_DESC_BASE      0x178900 
+#define GT96100_SDMA_G1_CHAN7_RX_DESC_BASE      0x178900
 #define GT96100_SDMA_G1_CHAN7_CURR_RX_DESC_PTR  0x178910
-#define GT96100_SDMA_G1_CHAN7_TX_DESC_BASE      0x17C900 
+#define GT96100_SDMA_G1_CHAN7_TX_DESC_BASE      0x17C900
 #define GT96100_SDMA_G1_CHAN7_CURR_TX_DESC_PTR  0x17C910
 #define GT96100_SDMA_G1_CHAN7_1ST_TX_DESC_PTR   0x17C914
 /*  MPSCs  */
-#define GT96100_MPSC0_MAIN_CONFIG_LOW   0x000A00 
-#define GT96100_MPSC0_MAIN_CONFIG_HIGH  0x000A04 
-#define GT96100_MPSC0_PROTOCOL_CONFIG   0x000A08 
+#define GT96100_MPSC0_MAIN_CONFIG_LOW   0x000A00
+#define GT96100_MPSC0_MAIN_CONFIG_HIGH  0x000A04
+#define GT96100_MPSC0_PROTOCOL_CONFIG   0x000A08
 #define GT96100_MPSC_CHAN0_REG1         0x000A0C
 #define GT96100_MPSC_CHAN0_REG2         0x000A10
 #define GT96100_MPSC_CHAN0_REG3         0x000A14
 #define GT96100_MPSC_CHAN0_REG4         0x000A18
 #define GT96100_MPSC_CHAN0_REG5         0x000A1C
-#define GT96100_MPSC_CHAN0_REG6         0x000A20 
+#define GT96100_MPSC_CHAN0_REG6         0x000A20
 #define GT96100_MPSC_CHAN0_REG7         0x000A24
 #define GT96100_MPSC_CHAN0_REG8         0x000A28
 #define GT96100_MPSC_CHAN0_REG9         0x000A2C
 #define GT96100_MPSC_CHAN0_REG10        0x000A30
 #define GT96100_MPSC_CHAN0_REG11        0x000A34
-#define GT96100_MPSC1_MAIN_CONFIG_LOW   0x008A00 
-#define GT96100_MPSC1_MAIN_CONFIG_HIGH  0x008A04 
-#define GT96100_MPSC1_PROTOCOL_CONFIG   0x008A08 
+#define GT96100_MPSC1_MAIN_CONFIG_LOW   0x008A00
+#define GT96100_MPSC1_MAIN_CONFIG_HIGH  0x008A04
+#define GT96100_MPSC1_PROTOCOL_CONFIG   0x008A08
 #define GT96100_MPSC_CHAN1_REG1         0x008A0C
 #define GT96100_MPSC_CHAN1_REG2         0x008A10
 #define GT96100_MPSC_CHAN1_REG3         0x008A14
@@ -221,23 +221,23 @@
 #define GT96100_MPSC_CHAN1_REG9         0x008A2C
 #define GT96100_MPSC_CHAN1_REG10        0x008A30
 #define GT96100_MPSC_CHAN1_REG11        0x008A34
-#define GT96100_MPSC2_MAIN_CONFIG_LOW   0x010A00 
-#define GT96100_MPSC2_MAIN_CONFIG_HIGH  0x010A04 
-#define GT96100_MPSC2_PROTOCOL_CONFIG   0x010A08 
+#define GT96100_MPSC2_MAIN_CONFIG_LOW   0x010A00
+#define GT96100_MPSC2_MAIN_CONFIG_HIGH  0x010A04
+#define GT96100_MPSC2_PROTOCOL_CONFIG   0x010A08
 #define GT96100_MPSC_CHAN2_REG1         0x010A0C
 #define GT96100_MPSC_CHAN2_REG2         0x010A10
 #define GT96100_MPSC_CHAN2_REG3         0x010A14
 #define GT96100_MPSC_CHAN2_REG4         0x010A18
 #define GT96100_MPSC_CHAN2_REG5         0x010A1C
-#define GT96100_MPSC_CHAN2_REG6         0x010A20 
+#define GT96100_MPSC_CHAN2_REG6         0x010A20
 #define GT96100_MPSC_CHAN2_REG7         0x010A24
 #define GT96100_MPSC_CHAN2_REG8         0x010A28
 #define GT96100_MPSC_CHAN2_REG9         0x010A2C
 #define GT96100_MPSC_CHAN2_REG10        0x010A30
 #define GT96100_MPSC_CHAN2_REG11        0x010A34
-#define GT96100_MPSC3_MAIN_CONFIG_LOW   0x018A00 
+#define GT96100_MPSC3_MAIN_CONFIG_LOW   0x018A00
 #define GT96100_MPSC3_MAIN_CONFIG_HIGH  0x018A04
-#define GT96100_MPSC3_PROTOCOL_CONFIG   0x018A08 
+#define GT96100_MPSC3_PROTOCOL_CONFIG   0x018A08
 #define GT96100_MPSC_CHAN3_REG1         0x018A0C
 #define GT96100_MPSC_CHAN3_REG2         0x018A10
 #define GT96100_MPSC_CHAN3_REG3         0x018A14
@@ -249,23 +249,23 @@
 #define GT96100_MPSC_CHAN3_REG9         0x018A2C
 #define GT96100_MPSC_CHAN3_REG10        0x018A30
 #define GT96100_MPSC_CHAN3_REG11        0x018A34
-#define GT96100_MPSC4_MAIN_CONFIG_LOW   0x020A00 
+#define GT96100_MPSC4_MAIN_CONFIG_LOW   0x020A00
 #define GT96100_MPSC4_MAIN_CONFIG_HIGH  0x020A04
-#define GT96100_MPSC4_PROTOCOL_CONFIG   0x020A08 
+#define GT96100_MPSC4_PROTOCOL_CONFIG   0x020A08
 #define GT96100_MPSC_CHAN4_REG1         0x020A0C
 #define GT96100_MPSC_CHAN4_REG2         0x020A10
 #define GT96100_MPSC_CHAN4_REG3         0x020A14
 #define GT96100_MPSC_CHAN4_REG4         0x020A18
 #define GT96100_MPSC_CHAN4_REG5         0x020A1C
-#define GT96100_MPSC_CHAN4_REG6         0x020A20 
-#define GT96100_MPSC_CHAN4_REG7         0x020A24 
-#define GT96100_MPSC_CHAN4_REG8         0x020A28 
-#define GT96100_MPSC_CHAN4_REG9         0x020A2C 
+#define GT96100_MPSC_CHAN4_REG6         0x020A20
+#define GT96100_MPSC_CHAN4_REG7         0x020A24
+#define GT96100_MPSC_CHAN4_REG8         0x020A28
+#define GT96100_MPSC_CHAN4_REG9         0x020A2C
 #define GT96100_MPSC_CHAN4_REG10        0x020A30
 #define GT96100_MPSC_CHAN4_REG11        0x020A34
-#define GT96100_MPSC5_MAIN_CONFIG_LOW   0x028A00 
+#define GT96100_MPSC5_MAIN_CONFIG_LOW   0x028A00
 #define GT96100_MPSC5_MAIN_CONFIG_HIGH  0x028A04
-#define GT96100_MPSC5_PROTOCOL_CONFIG   0x028A08 
+#define GT96100_MPSC5_PROTOCOL_CONFIG   0x028A08
 #define GT96100_MPSC_CHAN5_REG1         0x028A0C
 #define GT96100_MPSC_CHAN5_REG2         0x028A10
 #define GT96100_MPSC_CHAN5_REG3         0x028A14
@@ -277,9 +277,9 @@
 #define GT96100_MPSC_CHAN5_REG9         0x028A2C
 #define GT96100_MPSC_CHAN5_REG10        0x028A30
 #define GT96100_MPSC_CHAN5_REG11        0x028A34
-#define GT96100_MPSC6_MAIN_CONFIG_LOW   0x030A00 
+#define GT96100_MPSC6_MAIN_CONFIG_LOW   0x030A00
 #define GT96100_MPSC6_MAIN_CONFIG_HIGH  0x030A04
-#define GT96100_MPSC6_PROTOCOL_CONFIG   0x030A08 
+#define GT96100_MPSC6_PROTOCOL_CONFIG   0x030A08
 #define GT96100_MPSC_CHAN6_REG1         0x030A0C
 #define GT96100_MPSC_CHAN6_REG2         0x030A10
 #define GT96100_MPSC_CHAN6_REG3         0x030A14
@@ -291,9 +291,9 @@
 #define GT96100_MPSC_CHAN6_REG9         0x030A2C
 #define GT96100_MPSC_CHAN6_REG10        0x030A30
 #define GT96100_MPSC_CHAN6_REG11        0x030A34
-#define GT96100_MPSC7_MAIN_CONFIG_LOW   0x038A00 
+#define GT96100_MPSC7_MAIN_CONFIG_LOW   0x038A00
 #define GT96100_MPSC7_MAIN_CONFIG_HIGH  0x038A04
-#define GT96100_MPSC7_PROTOCOL_CONFIG   0x038A08 
+#define GT96100_MPSC7_PROTOCOL_CONFIG   0x038A08
 #define GT96100_MPSC_CHAN7_REG1         0x038A0C
 #define GT96100_MPSC_CHAN7_REG2         0x038A10
 #define GT96100_MPSC_CHAN7_REG3         0x038A14
@@ -308,14 +308,14 @@
 /*  FlexTDMs  */
 /* TDPR0 - Transmit Dual Port RAM. block size 0xff */
 #define GT96100_FXTDM0_TDPR0_BLK0_BASE  0x000B00
-#define GT96100_FXTDM0_TDPR0_BLK1_BASE  0x001B00 
-#define GT96100_FXTDM0_TDPR0_BLK2_BASE  0x002B00 
+#define GT96100_FXTDM0_TDPR0_BLK1_BASE  0x001B00
+#define GT96100_FXTDM0_TDPR0_BLK2_BASE  0x002B00
 #define GT96100_FXTDM0_TDPR0_BLK3_BASE  0x003B00
 /* RDPR0 - Receive Dual Port RAM. block size 0xff */
 #define GT96100_FXTDM0_RDPR0_BLK0_BASE  0x004B00
-#define GT96100_FXTDM0_RDPR0_BLK1_BASE  0x005B00 
-#define GT96100_FXTDM0_RDPR0_BLK2_BASE  0x006B00 
-#define GT96100_FXTDM0_RDPR0_BLK3_BASE  0x007B00 
+#define GT96100_FXTDM0_RDPR0_BLK1_BASE  0x005B00
+#define GT96100_FXTDM0_RDPR0_BLK2_BASE  0x006B00
+#define GT96100_FXTDM0_RDPR0_BLK3_BASE  0x007B00
 #define GT96100_FXTDM0_TX_READ_PTR      0x008B00
 #define GT96100_FXTDM0_RX_READ_PTR      0x008B04
 #define GT96100_FXTDM0_CONFIG       0x008B08
@@ -323,14 +323,14 @@
 #define GT96100_FXTDM0_AUX_CHANA_RX 0x008B10
 #define GT96100_FXTDM0_AUX_CHANB_TX 0x008B14
 #define GT96100_FXTDM0_AUX_CHANB_RX 0x008B18
-#define GT96100_FXTDM1_TDPR1_BLK0_BASE  0x010B00 
-#define GT96100_FXTDM1_TDPR1_BLK1_BASE  0x011B00 
-#define GT96100_FXTDM1_TDPR1_BLK2_BASE  0x012B00 
-#define GT96100_FXTDM1_TDPR1_BLK3_BASE  0x013B00 
-#define GT96100_FXTDM1_RDPR1_BLK0_BASE  0x014B00 
-#define GT96100_FXTDM1_RDPR1_BLK1_BASE  0x015B00 
-#define GT96100_FXTDM1_RDPR1_BLK2_BASE  0x016B00 
-#define GT96100_FXTDM1_RDPR1_BLK3_BASE  0x017B00 
+#define GT96100_FXTDM1_TDPR1_BLK0_BASE  0x010B00
+#define GT96100_FXTDM1_TDPR1_BLK1_BASE  0x011B00
+#define GT96100_FXTDM1_TDPR1_BLK2_BASE  0x012B00
+#define GT96100_FXTDM1_TDPR1_BLK3_BASE  0x013B00
+#define GT96100_FXTDM1_RDPR1_BLK0_BASE  0x014B00
+#define GT96100_FXTDM1_RDPR1_BLK1_BASE  0x015B00
+#define GT96100_FXTDM1_RDPR1_BLK2_BASE  0x016B00
+#define GT96100_FXTDM1_RDPR1_BLK3_BASE  0x017B00
 #define GT96100_FXTDM1_TX_READ_PTR      0x018B00
 #define GT96100_FXTDM1_RX_READ_PTR      0x018B04
 #define GT96100_FXTDM1_CONFIG       0x018B08
@@ -339,7 +339,7 @@
 #define GT96100_FLTDM1_AUX_CHANB_TX 0x018B14
 #define GT96100_FLTDM1_AUX_CHANB_RX 0x018B18
 #define GT96100_FLTDM2_TDPR2_BLK0_BASE  0x020B00
-#define GT96100_FLTDM2_TDPR2_BLK1_BASE  0x021B00 
+#define GT96100_FLTDM2_TDPR2_BLK1_BASE  0x021B00
 #define GT96100_FLTDM2_TDPR2_BLK2_BASE  0x022B00
 #define GT96100_FLTDM2_TDPR2_BLK3_BASE  0x023B00
 #define GT96100_FLTDM2_RDPR2_BLK0_BASE  0x024B00
@@ -369,46 +369,46 @@
 #define GT96100_FXTDM3_AUX_CHANB_TX 0x038B14
 #define GT96100_FXTDM3_AUX_CHANB_RX 0x038B18
 /*  Baud Rate Generators  */
-#define GT96100_BRG0_CONFIG     0x102A00 
-#define GT96100_BRG0_BAUD_TUNE  0x102A04 
-#define GT96100_BRG1_CONFIG     0x102A08 
-#define GT96100_BRG1_BAUD_TUNE  0x102A0C 
-#define GT96100_BRG2_CONFIG     0x102A10 
-#define GT96100_BRG2_BAUD_TUNE  0x102A14 
-#define GT96100_BRG3_CONFIG     0x102A18 
-#define GT96100_BRG3_BAUD_TUNE  0x102A1C 
-#define GT96100_BRG4_CONFIG     0x102A20 
-#define GT96100_BRG4_BAUD_TUNE  0x102A24 
-#define GT96100_BRG5_CONFIG     0x102A28 
-#define GT96100_BRG5_BAUD_TUNE  0x102A2C 
-#define GT96100_BRG6_CONFIG     0x102A30 
-#define GT96100_BRG6_BAUD_TUNE  0x102A34 
-#define GT96100_BRG7_CONFIG     0x102A38 
-#define GT96100_BRG7_BAUD_TUNE  0x102A3C 
+#define GT96100_BRG0_CONFIG     0x102A00
+#define GT96100_BRG0_BAUD_TUNE  0x102A04
+#define GT96100_BRG1_CONFIG     0x102A08
+#define GT96100_BRG1_BAUD_TUNE  0x102A0C
+#define GT96100_BRG2_CONFIG     0x102A10
+#define GT96100_BRG2_BAUD_TUNE  0x102A14
+#define GT96100_BRG3_CONFIG     0x102A18
+#define GT96100_BRG3_BAUD_TUNE  0x102A1C
+#define GT96100_BRG4_CONFIG     0x102A20
+#define GT96100_BRG4_BAUD_TUNE  0x102A24
+#define GT96100_BRG5_CONFIG     0x102A28
+#define GT96100_BRG5_BAUD_TUNE  0x102A2C
+#define GT96100_BRG6_CONFIG     0x102A30
+#define GT96100_BRG6_BAUD_TUNE  0x102A34
+#define GT96100_BRG7_CONFIG     0x102A38
+#define GT96100_BRG7_BAUD_TUNE  0x102A3C
 /*  Routing Registers  */
-#define GT96100_ROUTE_MAIN      0x101A00 
-#define GT96100_ROUTE_RX_CLOCK  0x101A10 
-#define GT96100_ROUTE_TX_CLOCK  0x101A20 
+#define GT96100_ROUTE_MAIN      0x101A00
+#define GT96100_ROUTE_RX_CLOCK  0x101A10
+#define GT96100_ROUTE_TX_CLOCK  0x101A20
 /*  General Purpose Ports  */
-#define GT96100_GPP_CONFIG0     0x100A00 
-#define GT96100_GPP_CONFIG1     0x100A04 
-#define GT96100_GPP_CONFIG2     0x100A08 
-#define GT96100_GPP_CONFIG3     0x100A0C 
-#define GT96100_GPP_IO0         0x100A20 
-#define GT96100_GPP_IO1         0x100A24 
-#define GT96100_GPP_IO2         0x100A28 
-#define GT96100_GPP_IO3         0x100A2C 
-#define GT96100_GPP_DATA0       0x100A40 
-#define GT96100_GPP_DATA1       0x100A44 
-#define GT96100_GPP_DATA2       0x100A48 
-#define GT96100_GPP_DATA3       0x100A4C 
-#define GT96100_GPP_LEVEL0      0x100A60 
-#define GT96100_GPP_LEVEL1      0x100A64 
-#define GT96100_GPP_LEVEL2      0x100A68 
-#define GT96100_GPP_LEVEL3      0x100A6C 
+#define GT96100_GPP_CONFIG0     0x100A00
+#define GT96100_GPP_CONFIG1     0x100A04
+#define GT96100_GPP_CONFIG2     0x100A08
+#define GT96100_GPP_CONFIG3     0x100A0C
+#define GT96100_GPP_IO0         0x100A20
+#define GT96100_GPP_IO1         0x100A24
+#define GT96100_GPP_IO2         0x100A28
+#define GT96100_GPP_IO3         0x100A2C
+#define GT96100_GPP_DATA0       0x100A40
+#define GT96100_GPP_DATA1       0x100A44
+#define GT96100_GPP_DATA2       0x100A48
+#define GT96100_GPP_DATA3       0x100A4C
+#define GT96100_GPP_LEVEL0      0x100A60
+#define GT96100_GPP_LEVEL1      0x100A64
+#define GT96100_GPP_LEVEL2      0x100A68
+#define GT96100_GPP_LEVEL3      0x100A6C
 /*  Watchdog  */
-#define GT96100_WD_CONFIG   0x101A80 
-#define GT96100_WD_VALUE    0x101A84 
+#define GT96100_WD_CONFIG   0x101A80
+#define GT96100_WD_VALUE    0x101A84
 /* Communication Unit Arbiter  */
 #define GT96100_COMM_UNIT_ARBTR_CONFIG 0x101AC0
 /*  PCI Arbiters  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/gdb-stub.h linux-2.4.20/include/asm-mips/gdb-stub.h
--- linux-2.4.19/include/asm-mips/gdb-stub.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/gdb-stub.h	2002-10-29 11:18:48.000000000 +0000
@@ -57,7 +57,7 @@
 #define GDB_FR_REG29		((GDB_FR_REG28) + 4)		/* 29 */
 #define GDB_FR_REG30		((GDB_FR_REG29) + 4)		/* 30 */
 #define GDB_FR_REG31		((GDB_FR_REG30) + 4)		/* 31 */
-	
+
 /*
  * Saved special registers
  */
@@ -180,7 +180,7 @@
 	 */
 	long	frame_ptr;
 	long    dummy;		/* unused */
-	
+
 	/*
 	 * saved cp0 registers
 	 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/gfx.h linux-2.4.20/include/asm-mips/gfx.h
--- linux-2.4.19/include/asm-mips/gfx.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/gfx.h	2002-10-29 11:18:32.000000000 +0000
@@ -6,7 +6,7 @@
  * This is the user-visible SGI GFX interface.
  *
  * This must be used verbatim into the GNU libc.  It does not include
- * any kernel-only bits on it.  
+ * any kernel-only bits on it.
  *
  * miguel@nuclecu.unam.mx
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/gt64120.h linux-2.4.20/include/asm-mips/gt64120.h
--- linux-2.4.19/include/asm-mips/gt64120.h	2001-09-09 17:43:01.000000000 +0000
+++ linux-2.4.20/include/asm-mips/gt64120.h	2002-10-29 11:18:48.000000000 +0000
@@ -60,7 +60,7 @@
 #define GT_PCI1M0REMAP_OFS	0x110
 #define GT_PCI1M1REMAP_OFS	0x118
 
-#define GT_SCS0LD_OFS		0x400	
+#define GT_SCS0LD_OFS		0x400
 #define GT_SCS0HD_OFS		0x404
 #define GT_SCS1LD_OFS		0x408
 #define GT_SCS1HD_OFS		0x40c
@@ -324,7 +324,7 @@
 #define GT_PCI0_BARE_SWSCS32DIS_SHF	1
 #define GT_PCI0_BARE_SWSCS32DIS_MSK	(MSK(1) << GT_PCI0_BARE_SWSCS32DIS_SHF)
 #define GT_PCI0_BARE_SWSCS32DIS_BIT	GT_PCI0_BARE_SWSCS32DIS_MSK
-	
+
 #define GT_PCI0_BARE_SWSCS10DIS_SHF	2
 #define GT_PCI0_BARE_SWSCS10DIS_MSK	(MSK(1) << GT_PCI0_BARE_SWSCS10DIS_SHF)
 #define GT_PCI0_BARE_SWSCS10DIS_BIT	GT_PCI0_BARE_SWSCS10DIS_MSK
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/highmem.h linux-2.4.20/include/asm-mips/highmem.h
--- linux-2.4.19/include/asm-mips/highmem.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/highmem.h	2002-10-29 11:18:37.000000000 +0000
@@ -8,7 +8,7 @@
  *		      Gerhard.Wichert@pdb.siemens.de
  *
  *
- * Redesigned the x86 32-bit VM architecture to deal with 
+ * Redesigned the x86 32-bit VM architecture to deal with
  * up to 16 Terabyte physical memory. With current x86 CPUs
  * we now support up to 64 Gigabytes physical RAM.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/io.h linux-2.4.20/include/asm-mips/io.h
--- linux-2.4.19/include/asm-mips/io.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/io.h	2002-10-29 11:18:38.000000000 +0000
@@ -18,6 +18,16 @@
 #include <asm/pgtable-bits.h>
 #include <asm/byteorder.h>
 
+#ifdef CONFIG_SGI_IP27
+extern unsigned long bus_to_baddr[256];
+
+#define bus_to_baddr(hwdev, addr) (bus_to_baddr[(hwdev)->bus->number] + (addr))
+#define baddr_to_bus(hwdev, addr) ((addr) - bus_to_baddr[(hwdev)->bus->number])
+#else
+#define bus_to_baddr(hwdev, addr) (addr)
+#define baddr_to_bus(hwdev, addr) (addr)
+#endif
+
 /*
  * Slowdown I/O port space accesses for antique hardware.
  */
@@ -30,7 +40,13 @@
 #if defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)
 
 #define __ioswab8(x) (x)
+#ifdef CONFIG_SGI_IP22
+/* IP22 seems braindead enough to swap 16bits values in hardware, but
+   not 32bits.  Go figure... Can't tell without documentation. */
+#define __ioswab16(x) (x)
+#else
 #define __ioswab16(x) swab16(x)
+#endif
 #define __ioswab32(x) swab32(x)
 
 #else
@@ -44,7 +60,7 @@
 /*
  * <Bacchus> Historically I wrote this stuff the same way as Linus did
  * because I was young and clueless.  And now it's so jucky that I
- * don't want to put my eyes on it again to get rid of it :-) 
+ * don't want to put my eyes on it again to get rid of it :-)
  *
  * I'll do it then, because this code offends both me and my compiler
  * - particularly the bits of inline asm which end up doing crap like
@@ -99,7 +115,7 @@
  *
  *     The returned physical address is the physical (CPU) mapping for
  *     the memory address given. It is only valid to use this function on
- *     addresses directly mapped or allocated via kmalloc. 
+ *     addresses directly mapped or allocated via kmalloc.
  *
  *     This function does not give bus mappings for DMA transfers. In
  *     almost all conceivable cases a device driver should not be using
@@ -171,7 +187,7 @@
  *     make bus memory CPU accessible via the readb/readw/readl/writeb/
  *     writew/writel functions and the other mmio helpers. The returned
  *     address is not guaranteed to be usable directly as a virtual
- *     address. 
+ *     address.
  */
 
 #define ioremap(offset, size)						\
@@ -186,11 +202,11 @@
  *     make bus memory CPU accessible via the readb/readw/readl/writeb/
  *     writew/writel functions and the other mmio helpers. The returned
  *     address is not guaranteed to be usable directly as a virtual
- *     address. 
+ *     address.
  *
  *     This version of ioremap ensures that the memory is marked uncachable
  *     on the CPU as well as honouring existing caching rules from things like
- *     the PCI bus. Note that there are other caches and buffers on many 
+ *     the PCI bus. Note that there are other caches and buffers on many
  *     busses. In paticular driver authors should read up on PCI writes
  *
  *     It's useful if some control registers are in such an area and
@@ -259,7 +275,7 @@
 
 /*
  *     check_signature         -       find BIOS signatures
- *     @io_addr: mmio address to check 
+ *     @io_addr: mmio address to check
  *     @signature:  signature block
  *     @length: length of signature
  *
@@ -285,7 +301,7 @@
 
 /*
  *     isa_check_signature             -       find BIOS signatures
- *     @io_addr: mmio address to check 
+ *     @io_addr: mmio address to check
  *     @signature:  signature block
  *     @length: length of signature
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/ioctls.h linux-2.4.20/include/asm-mips/ioctls.h
--- linux-2.4.19/include/asm-mips/ioctls.h	2001-09-09 17:43:01.000000000 +0000
+++ linux-2.4.20/include/asm-mips/ioctls.h	2002-10-29 11:18:49.000000000 +0000
@@ -12,7 +12,7 @@
 #include <asm/ioctl.h>
 
 #define TCGETA		0x5401
-#define TCSETA		0x5402
+#define TCSETA		0x5402	/* Clashes with SNDCTL_TMR_START sound ioctl */
 #define TCSETAW		0x5403
 #define TCSETAF		0x5404
 
@@ -66,7 +66,7 @@
 #define TIOCGETP        0x7408
 #define TIOCSETP        0x7409
 #define TIOCSETN        0x740a			/* TIOCSETP wo flush */
- 
+
 /* #define TIOCSETA	_IOW('t', 20, struct termios) set termios struct */
 /* #define TIOCSETAW	_IOW('t', 21, struct termios) drain output, set */
 /* #define TIOCSETAF	_IOW('t', 22, struct termios) drn out, fls in, set */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/ipc.h linux-2.4.20/include/asm-mips/ipc.h
--- linux-2.4.19/include/asm-mips/ipc.h	1999-06-26 00:37:53.000000000 +0000
+++ linux-2.4.20/include/asm-mips/ipc.h	2002-10-29 11:18:40.000000000 +0000
@@ -1,7 +1,7 @@
 #ifndef __ASM_MIPS_IPC_H
 #define __ASM_MIPS_IPC_H
 
-/* 
+/*
  * These are used to wrap system calls on MIPS.
  *
  * See arch/mips/kernel/sysmips.c for ugly details..
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/ipcbuf.h linux-2.4.20/include/asm-mips/ipcbuf.h
--- linux-2.4.19/include/asm-mips/ipcbuf.h	2000-02-25 06:52:30.000000000 +0000
+++ linux-2.4.20/include/asm-mips/ipcbuf.h	2002-10-29 11:18:50.000000000 +0000
@@ -1,7 +1,7 @@
 #ifndef _ASM_IPCBUF_H
 #define _ASM_IPCBUF_H
 
-/* 
+/*
  * The ipc64_perm structure for alpha architecture.
  * Note extra padding because this structure is passed back and forth
  * between kernel and user space.
@@ -18,7 +18,7 @@
 	__kernel_gid_t	gid;
 	__kernel_uid_t	cuid;
 	__kernel_gid_t	cgid;
-	__kernel_mode_t	mode; 
+	__kernel_mode_t	mode;
 	unsigned short	seq;
 	unsigned short	__pad1;
 	unsigned long	__unused1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/irq.h linux-2.4.20/include/asm-mips/irq.h
--- linux-2.4.19/include/asm-mips/irq.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/irq.h	2002-10-29 11:18:33.000000000 +0000
@@ -4,16 +4,16 @@
  * for more details.
  *
  * Copyright (C) 1994 by Waldorf GMBH, written by Ralf Baechle
- * Copyright (C) 1995, 96, 97, 98, 99, 2000, 2001 by Ralf Baechle
+ * Copyright (C) 1995, 96, 97, 98, 99, 2000, 01, 02 by Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2001 Kanoj Sarcar
  */
 #ifndef _ASM_IRQ_H
 #define _ASM_IRQ_H
 
 #include <linux/config.h>
 
-#define NR_IRQS 64		/* Largest number of ints of all machines.  */
-
-#define TIMER_IRQ 0
+#define NR_IRQS 128		/* Largest number of ints of all machines.  */
 
 #ifdef CONFIG_I8259
 static inline int irq_cannonicalize(int irq)
@@ -28,10 +28,10 @@
 extern int i8259_setup_irq(int irq, struct irqaction * new);
 extern void disable_irq(unsigned int);
 
-#ifndef CONFIG_NEW_IRQ
-#define disable_irq_nosync	disable_irq
-#else
+#ifdef CONFIG_NEW_IRQ
 extern void disable_irq_nosync(unsigned int);
+#else
+#define disable_irq_nosync	disable_irq
 #endif
 
 extern void enable_irq(unsigned int);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/kmap_types.h linux-2.4.20/include/asm-mips/kmap_types.h
--- linux-2.4.19/include/asm-mips/kmap_types.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/kmap_types.h	2002-10-29 11:18:37.000000000 +0000
@@ -3,7 +3,7 @@
 
 enum km_type {
 	KM_BOUNCE_READ,
-	KM_SKB_DATA,
+	KM_SKB_SUNRPC_DATA,
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/linux_logo.h linux-2.4.20/include/asm-mips/linux_logo.h
--- linux-2.4.19/include/asm-mips/linux_logo.h	2001-09-09 17:43:01.000000000 +0000
+++ linux-2.4.20/include/asm-mips/linux_logo.h	2002-10-29 11:18:51.000000000 +0000
@@ -17,7 +17,7 @@
  * Serial_console ascii image can be any size,
  * but should contain %s to display the version
  */
- 
+
 #include <linux/init.h>
 #include <linux/version.h>
 #include <linux/config.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/linux_logo_dec.h linux-2.4.20/include/asm-mips/linux_logo_dec.h
--- linux-2.4.19/include/asm-mips/linux_logo_dec.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/linux_logo_dec.h	2002-10-29 11:18:40.000000000 +0000
@@ -8,7 +8,7 @@
  * Copyright (C) 2001 Jan-Benedict Glaw <jbglaw@lug-owl.de>
  *
  */
- 
+
 #include <linux/init.h>
 #include <linux/version.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/mc146818rtc.h linux-2.4.20/include/asm-mips/mc146818rtc.h
--- linux-2.4.19/include/asm-mips/mc146818rtc.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/mc146818rtc.h	2002-10-29 11:18:48.000000000 +0000
@@ -6,35 +6,15 @@
  * Machine dependent access functions for RTC registers.
  *
  * Copyright (C) 1996, 1997, 1998, 2000 Ralf Baechle
+ * Copyright (C) 2002  Maciej W. Rozycki
  */
 #ifndef _ASM_MC146818RTC_H
 #define _ASM_MC146818RTC_H
 
 #include <linux/config.h>
+
 #include <asm/io.h>
 
-#ifndef RTC_PORT
-#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-#define RTC_PORT(x)	(0x14014800 + (x))
-#elif defined(CONFIG_MIPS_PB1500)
-#define RTC_PORT(x)	(0xAC000000 + (x))
-#else
-#define RTC_PORT(x)	(0x70 + (x))
-#endif
-#endif
-
-/*
- * The yet supported machines all access the RTC index register via
- * an ISA port access but the way to access the date register differs ...
- */
-#define CMOS_READ(addr) ({ \
-rtc_ops->rtc_read_data(addr); \
-})
-#define CMOS_WRITE(val, addr) ({ \
-rtc_ops->rtc_write_data(val, addr); \
-})
-#define RTC_ALWAYS_BCD \
-rtc_ops->rtc_bcd_mode()
 
 /*
  * This structure defines how to access various features of
@@ -49,17 +29,46 @@
 
 extern struct rtc_ops *rtc_ops;
 
+/*
+ * Most supported machines access the RTC index register via an ISA
+ * port access but the way to access the date register differs ...
+ * The DECstation directly maps the RTC memory in the CPU's address
+ * space with the chipset generating necessary index write/data access
+ * cycles automagically.
+ */
+#define CMOS_READ(addr) ({ \
+rtc_ops->rtc_read_data(addr); \
+})
+#define CMOS_WRITE(val, addr) ({ \
+rtc_ops->rtc_write_data(val, addr); \
+})
+#define RTC_ALWAYS_BCD \
+rtc_ops->rtc_bcd_mode()
+
+
 #ifdef CONFIG_DECSTATION
-#define RTC_IRQ 0
+
+#include <asm/dec/rtc-dec.h>
+
 #elif defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
+
 #include <asm/it8172/it8172_int.h>
-#define RTC_IRQ	IT8172_RTC_IRQ
-#elif defined(CONFIG_MIPS_PB1500)
-#undef RTC_IRQ
+
+#define RTC_PORT(x)	(0x14014800 + (x))
+#define RTC_IOMAPPED	0
+#define RTC_IRQ		IT8172_RTC_IRQ
+
+#elif defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
+
+#define RTC_PORT(x)	(0x0c000000 + (x))
+#define RTC_IOMAPPED	0
+#define RTC_IRQ		0
+
 #else
-#define RTC_IRQ	8
-#endif
 
-#define RTC_DEC_YEAR	0x3f	/* Where we store the real year on DECs.  */
+#define RTC_PORT(x)	(0x70 + (x))
+#define RTC_IRQ		8
+
+#endif
 
 #endif /* _ASM_MC146818RTC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/mips-boards/atlas.h linux-2.4.20/include/asm-mips/mips-boards/atlas.h
--- linux-2.4.19/include/asm-mips/mips-boards/atlas.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips/mips-boards/atlas.h	2002-10-29 11:18:37.000000000 +0000
@@ -27,7 +27,7 @@
 
 #include <asm/addrspace.h>
 
-/* 
+/*
  * Atlas RTC-device indirect register access.
  */
 #define ATLAS_RTC_ADR_REG       (KSEG1ADDR(0x1f000800))
@@ -43,7 +43,7 @@
  * Atlas UART register base.
  */
 #define ATLAS_UART_REGS_BASE    (0x1f000900)
-#define ATLAS_BASE_BAUD ( 3686400 / 16 ) 
+#define ATLAS_BASE_BAUD ( 3686400 / 16 )
 
 /*
  * Atlas PSU standby register.
@@ -54,7 +54,7 @@
 /*
  * We make a universal assumption about the way the bootloader (YAMON)
  * have located the Philips SAA9730 chip.
- * This is not ideal, but is needed for setting up remote debugging as 
+ * This is not ideal, but is needed for setting up remote debugging as
  * soon as possible.
  */
 #define ATLAS_SAA9730_REG  (KSEG1ADDR(0x08800000))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/mips-boards/atlasint.h linux-2.4.20/include/asm-mips/mips-boards/atlasint.h
--- linux-2.4.19/include/asm-mips/mips-boards/atlasint.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips/mips-boards/atlasint.h	2002-10-29 11:18:31.000000000 +0000
@@ -29,8 +29,8 @@
 #define ATLASINT_UART      0
 #define ATLASINT_END      32
 
-/* 
- * Atlas registers are memory mapped on 64-bit aligned boundaries and 
+/*
+ * Atlas registers are memory mapped on 64-bit aligned boundaries and
  * only word access are allowed.
  */
 struct atlas_ictrl_regs {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/mips-boards/bonito64.h linux-2.4.20/include/asm-mips/mips-boards/bonito64.h
--- linux-2.4.19/include/asm-mips/mips-boards/bonito64.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/mips-boards/bonito64.h	2002-10-29 11:18:30.000000000 +0000
@@ -11,7 +11,7 @@
  */
 
 /*
- * Bonito Register Map 
+ * Bonito Register Map
  * Copyright (c) 1999 Algorithmics Ltd
  *
  * Algorithmics gives permission for anyone to use and modify this file
@@ -20,7 +20,7 @@
  *
  * Updated copies of this and other files can be found at
  * ftp://ftp.algor.co.uk/pub/bonito/
- * 
+ *
  * Users of the Bonito controller are warmly recommended to contribute
  * any useful changes back to Algorithmics (mail to bonito@algor.co.uk).
  */
@@ -75,7 +75,7 @@
 #define BONITO_PCICFG_BASE		0x1fe80000
 #define BONITO_PCICFG_SIZE		0x00080000
 #define BONITO_PCICFG_TOP		(BONITO_PCICFG_BASE+BONITO_PCICFG_SIZE-1)
- 
+
 
 /* Bonito Register Bases */
 
@@ -184,7 +184,7 @@
 #define BONITO_PCIMAP_CFG		BONITO(BONITO_REGBASE + 0x18)
 
 /* 5. ICU & GPIO regs */
- 
+
 /* GPIO Regs - r/w */
 
 #define BONITO_GPIODATA_OFFSET          0x1c
@@ -231,7 +231,7 @@
 */
 
 /* 7. IDE DMA & Copier */
- 
+
 #define BONITO_CONFIGBASE		0x000
 #define BONITO_BONITOBASE		0x100
 #define BONITO_LDMABASE 		0x200
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/mips-boards/malta.h linux-2.4.20/include/asm-mips/mips-boards/malta.h
--- linux-2.4.19/include/asm-mips/mips-boards/malta.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/mips-boards/malta.h	2002-10-29 11:18:33.000000000 +0000
@@ -28,15 +28,15 @@
 #include <asm/addrspace.h>
 #include <asm/io.h>
 
-/* 
+/*
  * Malta I/O ports base address for the Galileo GT64120 and Algorithmics
- * Bonito system controllers. 
+ * Bonito system controllers.
  */
 #define MALTA_GT_PORT_BASE      (KSEG1ADDR(0x18000000))
 #define MALTA_BONITO_PORT_BASE  (KSEG1ADDR(0x1fd00000))
 #define MALTA_MSC_PORT_BASE     (KSEG1ADDR(0x18000000))
 
-/* 
+/*
  * Malta RTC-device indirect register access.
  */
 #define MALTA_RTC_ADR_REG       0x70
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/mips-boards/msc01_pci.h linux-2.4.20/include/asm-mips/mips-boards/msc01_pci.h
--- linux-2.4.19/include/asm-mips/mips-boards/msc01_pci.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/mips-boards/msc01_pci.h	2002-10-29 11:18:48.000000000 +0000
@@ -94,7 +94,7 @@
 #define MSC01_PCI_INTCFG_MWE_BIT        0x00000200
 #define MSC01_PCI_INTCFG_DTO_SHF        8
 #define MSC01_PCI_INTCFG_DTO_MSK        0x00000100
-#define MSC01_PCI_INTCFG_DTO_BIT        0x00000100 
+#define MSC01_PCI_INTCFG_DTO_BIT        0x00000100
 #define MSC01_PCI_INTCFG_MA_SHF         7
 #define MSC01_PCI_INTCFG_MA_MSK         0x00000080
 #define MSC01_PCI_INTCFG_MA_BIT         0x00000080
@@ -128,7 +128,7 @@
 #define MSC01_PCI_INTSTAT_MWE_BIT       0x00000200
 #define MSC01_PCI_INTSTAT_DTO_SHF       8
 #define MSC01_PCI_INTSTAT_DTO_MSK       0x00000100
-#define MSC01_PCI_INTSTAT_DTO_BIT       0x00000100 
+#define MSC01_PCI_INTSTAT_DTO_BIT       0x00000100
 #define MSC01_PCI_INTSTAT_MA_SHF        7
 #define MSC01_PCI_INTSTAT_MA_MSK        0x00000080
 #define MSC01_PCI_INTSTAT_MA_BIT        0x00000080
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/mips-boards/sead.h linux-2.4.20/include/asm-mips/mips-boards/sead.h
--- linux-2.4.19/include/asm-mips/mips-boards/sead.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips/mips-boards/sead.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,36 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ *
+ * Defines of the SEAD board specific address-MAP, registers, etc.
+ *
+ */
+#ifndef _MIPS_SEAD_H
+#define _MIPS_SEAD_H
+
+#include <asm/addrspace.h>
+
+/*
+ * SEAD UART register base.
+ */
+#define SEAD_UART0_REGS_BASE    (0x1f000800)
+#define SEAD_BASE_BAUD ( 3686400 / 16 )
+
+#endif /* !(_MIPS_SEAD_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/mips-boards/seadint.h linux-2.4.20/include/asm-mips/mips-boards/seadint.h
--- linux-2.4.19/include/asm-mips/mips-boards/seadint.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips/mips-boards/seadint.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,35 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ *
+ * Defines for the SEAD interrupt controller.
+ *
+ */
+#ifndef _MIPS_SEADINT_H
+#define _MIPS_SEADINT_H
+
+/* Number of IRQ supported */
+#define SEADINT_UART0     0
+#define SEADINT_UART1     1
+#define SEADINT_END       2
+
+extern void seadint_init(void);
+
+#endif /* !(_MIPS_SEADINT_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/mips32_cache.h linux-2.4.20/include/asm-mips/mips32_cache.h
--- linux-2.4.19/include/asm-mips/mips32_cache.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/mips32_cache.h	2002-10-29 11:18:49.000000000 +0000
@@ -22,7 +22,7 @@
  * ########################################################################
  *
  * Inline assembly cache operations.
- * 
+ *
  * This file is the original r4cache.c file with modification that makes the
  * cache handling more generic.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/mipsregs.h linux-2.4.20/include/asm-mips/mipsregs.h
--- linux-2.4.19/include/asm-mips/mipsregs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/mipsregs.h	2002-10-29 11:18:47.000000000 +0000
@@ -77,7 +77,7 @@
 #define CP0_IWATCH $18
 #define CP0_DWATCH $19
 
-/* 
+/*
  * Coprocessor 0 Set 1 register names
  */
 #define CP0_S1_DERRADDR0  $26
@@ -374,8 +374,10 @@
 #define CONF_CM_CACHABLE_CUW		6
 #define CONF_CM_CACHABLE_ACCELERATED	7
 #define CONF_CM_CMASK			7
+#define CONF_CU				(1 <<  3)
 #define CONF_DB				(1 <<  4)
 #define CONF_IB				(1 <<  5)
+#define CONF_SE 			(1 << 12)
 #define CONF_SC				(1 << 17)
 #define CONF_AC                         (1 << 23)
 #define CONF_HALT                       (1 << 25)
@@ -527,8 +529,8 @@
         ".set\tmips0"                                           \
         : : "r" (value))
 
-/* 
- * This should be changed when we get a compiler that support the MIPS32 ISA. 
+/*
+ * This should be changed when we get a compiler that support the MIPS32 ISA.
  */
 #define read_mips32_cp0_config1()                               \
 ({ int __res;                                                   \
@@ -623,6 +625,8 @@
 
 #if defined(CONFIG_64BIT_PHYS_ADDR) && !defined(CONFIG_CPU_MIPS32)
 
+#include <asm/system.h>
+
 /*
  * These versions are only needed for systems with more than 38 bits of
  * physical address space.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/mmu_context.h linux-2.4.20/include/asm-mips/mmu_context.h
--- linux-2.4.19/include/asm-mips/mmu_context.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/mmu_context.h	2002-10-29 11:18:40.000000000 +0000
@@ -19,7 +19,7 @@
 /*
  * For the fast tlb miss handlers, we currently keep a per cpu array
  * of pointers to the current pgd for each processor. Also, the proc.
- * id is stuffed into the context register. This should be changed to 
+ * id is stuffed into the context register. This should be changed to
  * use the processor id via current->processor, where current is stored
  * in watchhi/lo. The context register should be used to contiguously
  * map the page tables.
@@ -85,10 +85,10 @@
 #ifndef CONFIG_SMP
 	mm->context = 0;
 #else
-	mm->context = (unsigned long)kmalloc(smp_num_cpus * 
+	mm->context = (unsigned long)kmalloc(smp_num_cpus *
 				sizeof(unsigned long), GFP_KERNEL);
 	/*
- 	 * Init the "context" values so that a tlbpid allocation 
+ 	 * Init the "context" values so that a tlbpid allocation
 	 * happens on the first switch.
  	 */
 	if (mm->context == 0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/msgbuf.h linux-2.4.20/include/asm-mips/msgbuf.h
--- linux-2.4.19/include/asm-mips/msgbuf.h	2000-02-25 06:52:30.000000000 +0000
+++ linux-2.4.20/include/asm-mips/msgbuf.h	2002-10-29 11:18:36.000000000 +0000
@@ -1,7 +1,7 @@
 #ifndef _ASM_MSGBUF_H
 #define _ASM_MSGBUF_H
 
-/* 
+/*
  * The msqid64_ds structure for alpha architecture.
  * Note extra padding because this structure is passed back and forth
  * between kernel and user space.
@@ -13,15 +13,18 @@
 struct msqid64_ds {
 	struct ipc64_perm msg_perm;
 	__kernel_time_t msg_stime;	/* last msgsnd time */
+	unsigned long	__unused1;
 	__kernel_time_t msg_rtime;	/* last msgrcv time */
+	unsigned long	__unused2;
 	__kernel_time_t msg_ctime;	/* last change time */
+	unsigned long	__unused3;
 	unsigned long  msg_cbytes;	/* current number of bytes on queue */
 	unsigned long  msg_qnum;	/* number of messages in queue */
 	unsigned long  msg_qbytes;	/* max number of bytes on queue */
 	__kernel_pid_t msg_lspid;	/* pid of last msgsnd */
 	__kernel_pid_t msg_lrpid;	/* last receive pid */
-	unsigned long  __unused1;
-	unsigned long  __unused2;
+	unsigned long  __unused4;
+	unsigned long  __unused5;
 };
 
 #endif /* _ASM_MSGBUF_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/ng1hw.h linux-2.4.20/include/asm-mips/ng1hw.h
--- linux-2.4.19/include/asm-mips/ng1hw.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/ng1hw.h	2002-10-29 11:18:33.000000000 +0000
@@ -74,7 +74,7 @@
 #define DM0_XYOFFSET		NPORT_DMODE0_XYOFF
 #define DM0_CICLAMP		NPORT_DMODE0_CLAMP
 #define DM0_ENDPTFILTER		NPORT_DMODE0_ENDPF
-#define	DM0_YSTRIDE		NPORT_DMODE0_YSTR 
+#define	DM0_YSTRIDE		NPORT_DMODE0_YSTR
 
 #define DM1_PLANES_SHIFT	0
 /* The rest of the DM1 planes defines are in newport.h */
@@ -116,7 +116,7 @@
 
 #define DM1_SF_SHIFT		19
 #define DM1_SF_MASK   		NPORT_DMODE1_SFMASK
-#define DM1_SF			NPORT_DMODE1_SFMASK 
+#define DM1_SF			NPORT_DMODE1_SFMASK
 #define DM1_SF_ZERO		NPORT_DMODE1_SF0
 #define DM1_SF_ONE		NPORT_DMODE1_SF1
 #define DM1_SF_DC		NPORT_DMODE1_SFDC
@@ -125,8 +125,8 @@
 #define DM1_SF_MSA		NPORT_DMODE1_SFMSA
 
 #define DM1_DF_SHIFT		22	/* dfactor(2:0)	*/
-#define DM1_DF_MASK		NPORT_DMODE1_DFMASK 
-#define DM1_DF			NPORT_DMODE1_DFMASK 
+#define DM1_DF_MASK		NPORT_DMODE1_DFMASK
+#define DM1_DF			NPORT_DMODE1_DFMASK
 #define DM1_DF_ZERO		NPORT_DMODE1_DF0
 #define DM1_DF_ONE		NPORT_DMODE1_DF1
 #define DM1_DF_SC		NPORT_DMODE1_DFSC
@@ -174,23 +174,23 @@
 #define VRINT           	NPORT_STAT_VRINT
 #define VIDEOINT        	NPORT_STAT_VIDINT
 #define GFIFO_LEVEL_SHIFT       7
-#define GFIFO_LEVEL_MASK        NPORT_STAT_GLMSK 
+#define GFIFO_LEVEL_MASK        NPORT_STAT_GLMSK
 #define BFIFO_LEVEL_SHIFT       13
-#define BFIFO_LEVEL_MASK        NPORT_STAT_BLMSK 
+#define BFIFO_LEVEL_MASK        NPORT_STAT_BLMSK
 #define BFIFO_INT        	NPORT_STAT_BFIRQ
 #define GFIFO_INT        	NPORT_STAT_GFIRQ
 
-#define GIO32MODE		NPORT_CFG_G32MD 
+#define GIO32MODE		NPORT_CFG_G32MD
 #define BUSWIDTH		NPORT_CFG_BWIDTH
-#define EXTREGXCVR		NPORT_CFG_ERCVR 
+#define EXTREGXCVR		NPORT_CFG_ERCVR
 #define BFIFODEPTH_SHIFT	3
 #define BFIFODEPTH_MASK		NPORT_CFG_BDMSK
 #define BFIFOABOVEINT		NPORT_CFG_BFAINT
 #define GFIFODEPTH_SHIFT        8
-#define GFIFODEPTH_MASK		NPORT_CFG_GDMSK 
+#define GFIFODEPTH_MASK		NPORT_CFG_GDMSK
 #define GFIFOABOVEINT		NPORT_CFG_GFAINT
 #define TIMEOUT_SHIFT		14
-#define TIMEOUT_MASK		NPORT_CFG_TOMSK 
+#define TIMEOUT_MASK		NPORT_CFG_TOMSK
 #define VREFRESH_SHIFT		17
 #define VREFRESH_MASK		NPORT_CFG_VRMSK
 #define FB_TYPE			NPORT_CFG_FBTYP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/nile4.h linux-2.4.20/include/asm-mips/nile4.h
--- linux-2.4.19/include/asm-mips/nile4.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/nile4.h	2002-10-29 11:18:31.000000000 +0000
@@ -9,6 +9,9 @@
  *	NEC Vrc 5074 System Controller Data Sheet, June 1998
  */
 
+#ifndef _ASM_NILE4_H
+#define _ASM_NILE4_H
+
 #define NILE4_BASE		0xbfa00000
 #define NILE4_SIZE		0x00200000		/* 2 MB */
 
@@ -290,8 +293,8 @@
 
 extern void nile4_map_irq(int nile4_irq, int cpu_irq);
 extern void nile4_map_irq_all(int cpu_irq);
-extern void nile4_enable_irq(int nile4_irq);
-extern void nile4_disable_irq(int nile4_irq);
+extern void nile4_enable_irq(unsigned int nile4_irq);
+extern void nile4_disable_irq(unsigned int nile4_irq);
 extern void nile4_disable_irq_all(void);
 extern u16 nile4_get_irq_stat(int cpu_irq);
 extern void nile4_enable_irq_output(int cpu_irq);
@@ -303,3 +306,5 @@
 extern u8 nile4_i8259_iack(void);
 extern void nile4_dump_irq_status(void);	/* Debug */
 
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/page.h linux-2.4.20/include/asm-mips/page.h
--- linux-2.4.19/include/asm-mips/page.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/page.h	2002-10-29 11:18:37.000000000 +0000
@@ -115,6 +115,8 @@
  * We handle pages at KSEG0 for kernels with 32 bit address space.
  */
 #define PAGE_OFFSET	0x80000000UL
+#define UNCAC_BASE	0xa0000000UL
+
 #define __pa(x)		((unsigned long) (x) - PAGE_OFFSET)
 #define __va(x)		((void *)((unsigned long) (x) + PAGE_OFFSET))
 #define virt_to_page(kaddr)	(mem_map + (__pa(kaddr) >> PAGE_SHIFT))
@@ -123,6 +125,9 @@
 #define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
 				VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
+#define UNCAC_ADDR(addr)	((addr) - PAGE_OFFSET + UNCAC_BASE)
+#define CAC_ADDR(addr)		((addr) - UNCAC_BASE + PAGE_OFFSET)
+
 /*
  * Memory above this physical address will be considered highmem.
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/pb1000.h linux-2.4.20/include/asm-mips/pb1000.h
--- linux-2.4.19/include/asm-mips/pb1000.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/pb1000.h	2002-10-29 11:18:37.000000000 +0000
@@ -22,13 +22,14 @@
  *
  * ########################################################################
  *
- * 
+ *
  */
 #ifndef __ASM_PB1000_H
 #define __ASM_PB1000_H
 
 /* PCMCIA PB1000 specific defines */
-#define PCMCIA_MAX_SOCK 0 /* the second socket, 1, is not supported at this time */
+#define PCMCIA_MAX_SOCK 1
+#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK+1)
 
 #define PB1000_PCR     0xBE000000
   #define PCR_SLOT_0_VPP0  (1<<0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/pb1100.h linux-2.4.20/include/asm-mips/pb1100.h
--- linux-2.4.19/include/asm-mips/pb1100.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips/pb1100.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,85 @@
+/*
+ * Alchemy Semi PB1100 Referrence Board
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or source@mvista.com
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ *
+ *
+ */
+#ifndef __ASM_PB1100_H
+#define __ASM_PB1100_H
+
+#define PB1100_IDENT          0xAE000000
+#define PB1100_BOARD_STATUS   0xAE000004
+  #define PB1100_ROM_SEL         (1<<15)
+  #define PB1100_ROM_SIZ         (1<<14)
+  #define PB1100_SWAP_BOOT       (1<<13)
+  #define PB1100_FLASH_WP        (1<<12)
+  #define PB1100_ROM_H_STS       (1<<11)
+  #define PB1100_ROM_L_STS       (1<<10)
+  #define PB1100_FLASH_H_STS      (1<<9)
+  #define PB1100_FLASH_L_STS      (1<<8)
+  #define PB1100_SRAM_SIZ         (1<<7)
+  #define PB1100_TSC_BUSY         (1<<6)
+  #define PB1100_PCMCIA_VS_MASK   (3<<4)
+  #define PB1100_RS232_CD         (1<<3)
+  #define PB1100_RS232_CTS        (1<<2)
+  #define PB1100_RS232_DSR        (1<<1)
+  #define PB1100_RS232_RI         (1<<0)
+
+#define PB1100_IRDA_RS232     0xAE00000C
+  #define PB1100_IRDA_FULL       (0<<14) /* full power */
+  #define PB1100_IRDA_SHUTDOWN   (1<<14)
+  #define PB1100_IRDA_TT         (2<<14) /* 2/3 power */
+  #define PB1100_IRDA_OT         (3<<14) /* 1/3 power */
+  #define PB1100_IRDA_FIR        (1<<13)
+
+#define PB1100_MEM_PCMCIA     0xAE000010
+  #define PB1100_SD_WP1_RO       (1<<15) /* read only */
+  #define PB1100_SD_WP0_RO       (1<<14) /* read only */
+  #define PB1100_SD_PWR1         (1<<11) /* applies power to SD1 */
+  #define PB1100_SD_PWR0         (1<<10) /* applies power to SD0 */
+  #define PB1100_SEL_SD_CONN1     (1<<9)
+  #define PB1100_SEL_SD_CONN0     (1<<8)
+  #define PB1100_PC_DEASSERT_RST  (1<<7)
+  #define PB1100_PC_DRV_EN        (1<<4)
+
+#define PB1100_G_CONTROL      0xAE000014 /* graphics control */
+
+#define PB1100_RST_VDDI       0xAE00001C
+  #define PB1100_SOFT_RESET      (1<<15) /* clear to reset the board */
+  #define PB1100_VDDI_MASK        (0x1F)
+
+#define PB1100_LEDS           0xAE000018
+
+/* 11:8 is 4 discreet LEDs. Clearing a bit illuminates the LED.
+ * 7:0 is the LED Display's decimal points.
+ */
+#define PB1100_HEX_LED        0xAE000018
+
+/* PCMCIA PB1100 specific defines */
+#define PCMCIA_MAX_SOCK 0
+#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK+1)
+
+/* VPP/VCC */
+#define SET_VCC_VPP(VCC, VPP) (((VCC)<<2) | ((VPP)<<0))
+
+#endif /* __ASM_PB1100_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/pb1500.h linux-2.4.20/include/asm-mips/pb1500.h
--- linux-2.4.19/include/asm-mips/pb1500.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/pb1500.h	2002-10-29 11:18:48.000000000 +0000
@@ -22,7 +22,7 @@
  *
  * ########################################################################
  *
- * 
+ *
  */
 #ifndef __ASM_PB1500_H
 #define __ASM_PB1500_H
@@ -31,7 +31,7 @@
 #define PB1500_BOARD_STATUS   0xAE000004
 #define PB1500_PCI_PCMCIA     0xAE000010
   #define PC_DEASSERT_RST           0x80
-  #define PC_DRV_EN                 0x10 
+  #define PC_DRV_EN                 0x10
 #define PB1500_G_CONTROL      0xAE000014
 #define PB1500_RST_VDDI       0xAE00001C
 #define PB1500_LEDS           0xAE000018
@@ -41,6 +41,7 @@
 
 /* PCMCIA PB1500 specific defines */
 #define PCMCIA_MAX_SOCK 0
+#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK+1)
 
 /* VPP/VCC */
 #define SET_VCC_VPP(VCC, VPP) (((VCC)<<2) | ((VPP)<<0))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/pci.h linux-2.4.20/include/asm-mips/pci.h
--- linux-2.4.19/include/asm-mips/pci.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/pci.h	2002-10-29 11:18:33.000000000 +0000
@@ -7,8 +7,6 @@
 #define _ASM_PCI_H
 
 #include <linux/config.h>
-#include <linux/types.h>
-#include <asm/io.h>			/* for virt_to_bus()  */
 
 #ifdef __KERNEL__
 
@@ -40,7 +38,6 @@
  * MIPS has everything mapped statically.
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <asm/scatterlist.h>
@@ -57,6 +54,13 @@
 struct pci_dev;
 
 /*
+ * The PCI address space does equal the physical memory address space.  The
+ * networking and block device layers use this boolean for bounce buffer
+ * decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS	(1)
+
+/*
  * Allocate and map kernel buffer using consistent mode DMA for a device.
  * hwdev should be valid struct pci_dev pointer for PCI devices,
  * NULL for PCI-like buses (ISA, EISA).
@@ -89,14 +93,14 @@
 static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
 					size_t size, int direction)
 {
+	unsigned long addr = (unsigned long) ptr;
+
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
 
-#ifdef CONFIG_NONCOHERENT_IO
-	dma_cache_wback_inv((unsigned long)ptr, size);
-#endif
+	dma_cache_wback_inv(addr, size);
 
-	return virt_to_bus(ptr);
+	return bus_to_baddr(hwdev->bus->number, __pa(ptr));
 }
 
 /*
@@ -113,7 +117,12 @@
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
 
-	/* Nothing to do */
+	if (direction != PCI_DMA_TODEVICE) {
+		unsigned long addr;
+
+		addr = baddr_to_bus(hwdev, dma_addr) + PAGE_OFFSET;
+		dma_cache_wback_inv(addr, size);
+	}
 }
 
 /*
@@ -129,13 +138,10 @@
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
 
-	addr = (unsigned long) page_address(page);
-	addr += offset;
-#ifdef CONFIG_NONCOHERENT_IO
+	addr = (unsigned long) page_address(page) + offset;
 	dma_cache_wback_inv(addr, size);
-#endif
 
-	return virt_to_bus((void *)addr);
+	return bus_to_baddr(hwdev, page_to_phys(page) + offset);
 }
 
 static inline void pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address,
@@ -143,7 +149,13 @@
 {
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
-	/* Nothing to do */
+
+	if (direction != PCI_DMA_TODEVICE) {
+		unsigned long addr;
+
+		addr = baddr_to_bus(hwdev, dma_address) + PAGE_OFFSET;
+		dma_cache_wback_inv(addr, size);
+	}
 }
 
 /* pci_unmap_{page,single} is a nop so... */
@@ -173,18 +185,25 @@
 static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
 			     int nents, int direction)
 {
-#ifdef CONFIG_NONCOHERENT_IO
 	int i;
-#endif
 
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
 
-#ifdef CONFIG_NONCOHERENT_IO
-	/* Make sure that gcc doesn't leave the empty loop body.  */
-	for (i = 0; i < nents; i++, sg++)
-		dma_cache_wback_inv((unsigned long)sg->address, sg->length);
-#endif
+	for (i = 0; i < nents; i++, sg++) {
+		if (sg->address && sg->page)
+			out_of_line_bug();
+		else if (!sg->address && !sg->page)
+			out_of_line_bug();
+
+		if (sg->address) {
+			dma_cache_wback_inv((unsigned long)sg->address,
+			                    sg->length);
+			sg->dma_address = bus_to_baddr(hwdev, __pa(sg->address));
+		} else
+			sg->dma_address = page_to_bus(sg->page) +
+			                  sg->offset;
+	}
 
 	return nents;
 }
@@ -197,10 +216,24 @@
 static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
 				int nents, int direction)
 {
+	int i;
+
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
 
-	/* Nothing to do */
+	if (direction == PCI_DMA_TODEVICE)
+		return;
+
+	for (i = 0; i < nents; i++, sg++) {
+		if (sg->address && sg->page)
+			out_of_line_bug();
+		else if (!sg->address && !sg->page)
+			out_of_line_bug();
+
+		if (!sg->address)
+			continue;
+		dma_cache_wback_inv((unsigned long)sg->address, sg->length);
+	}
 }
 
 /*
@@ -217,12 +250,13 @@
 				       dma_addr_t dma_handle,
 				       size_t size, int direction)
 {
+	unsigned long addr;
+
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
 
-#ifdef CONFIG_NONCOHERENT_IO
-	dma_cache_wback_inv((unsigned long)bus_to_virt(dma_handle), size);
-#endif
+	addr = baddr_to_bus(hwdev, dma_handle) + PAGE_OFFSET;
+	dma_cache_wback_inv(addr, size);
 }
 
 /*
@@ -250,7 +284,8 @@
 #endif
 }
 
-/* Return whether the given PCI device DMA address mask can
+/*
+ * Return whether the given PCI device DMA address mask can
  * be supported properly.  For example, if your device can
  * only drive the low 24-bits during PCI bus mastering, then
  * you would pass 0x00ffffff as the mask to this function.
@@ -262,47 +297,54 @@
 	 * so we can't guarantee allocations that must be
 	 * within a tighter range than GFP_DMA..
 	 */
-	if (mask < 0x1fffffff)
+#ifdef CONFIG_ISA
+	if (mask < 0x00ffffff)
 		return 0;
+#endif
 
 	return 1;
 }
 
 /* This is always fine. */
-/* Well ...  this actually needs more thought ...  */
-#define pci_dac_dma_supported(pci_dev, mask)	(0)
+#define pci_dac_dma_supported(pci_dev, mask)	(1)
 
-#if 0
-static __inline__ dma64_addr_t
-pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
+static inline dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev,
+	struct page *page, unsigned long offset, int direction)
 {
-	return ((dma64_addr_t) page_to_bus(page) +
-		(dma64_addr_t) offset);
+	dma64_addr_t addr = page_to_phys(page) + offset;
+
+	return (dma64_addr_t) bus_to_baddr(hwdev->bus->number, addr);
 }
 
-static __inline__ struct page *
-pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
+static inline struct page *pci_dac_dma_to_page(struct pci_dev *pdev,
+	dma64_addr_t dma_addr)
 {
-	unsigned long poff = (dma_addr >> PAGE_SHIFT);
+	unsigned long poff = baddr_to_bus(hwdev, dma_addr) >> PAGE_SHIFT;
 
 	return mem_map + poff;
 }
 
-static __inline__ unsigned long
-pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
+static inline unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev,
+	dma64_addr_t dma_addr)
 {
-	return (dma_addr & ~PAGE_MASK);
+	return dma_addr & ~PAGE_MASK;
 }
 
-static __inline__ void
-pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr,
-                        size_t len, int direction)
+static inline void pci_dac_dma_sync_single(struct pci_dev *pdev,
+	dma64_addr_t dma_addr, size_t len, int direction)
 {
-	/* Nothing to do. */
+	unsigned long addr;
+
+	if (direction == PCI_DMA_NONE)
+		BUG();
+
+	addr = baddr_to_bus(hwdev->bus->number, dma_addr) + PAGE_OFFSET;
+	dma_cache_wback_inv(addr, len);
 }
-#endif
 
-/* Return the index of the PCI controller for device. */
+/*
+ * Return the index of the PCI controller for device.
+ */
 #define pci_controller_num(pdev)	(0)
 
 /*
@@ -312,7 +354,7 @@
  * returns, or alternatively stop on the first sg_dma_len(sg) which
  * is 0.
  */
-#define sg_dma_address(sg)	(virt_to_bus((sg)->address))
+#define sg_dma_address(sg)	((sg)->dma_address)
 #define sg_dma_len(sg)		((sg)->length)
 
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/pci_channel.h linux-2.4.20/include/asm-mips/pci_channel.h
--- linux-2.4.19/include/asm-mips/pci_channel.h	2001-09-09 17:43:01.000000000 +0000
+++ linux-2.4.20/include/asm-mips/pci_channel.h	2002-10-29 11:18:31.000000000 +0000
@@ -23,7 +23,7 @@
 	int last_devfn;
 };
 
-/* 
+/*
  * each board defines an array of pci_channels, that ends with all NULL entry
  */
 extern struct pci_channel mips_pci_channels[];
@@ -33,7 +33,7 @@
  */
 extern void pcibios_fixup_irqs(void);
 
-/* 
+/*
  * board supplied pci fixup routines
  */
 extern void pcibios_fixup_resources(struct pci_dev *dev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/pgtable-bits.h linux-2.4.20/include/asm-mips/pgtable-bits.h
--- linux-2.4.19/include/asm-mips/pgtable-bits.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/pgtable-bits.h	2002-10-29 11:18:36.000000000 +0000
@@ -3,16 +3,17 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000 by Ralf Baechle at alii
- * Copyright (C) 2001, 2002 by Ralf Baechle
- * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 1994 - 2002 by Ralf Baechle
+ * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc.
+ * Copyright (C) 2002  Maciej W. Rozycki
  */
-#ifndef _ASM_CACHINGMODES_H
-#define _ASM_CACHINGMODES_H
+#ifndef _ASM_PGTABLE_BITS_H
+#define _ASM_PGTABLE_BITS_H
 
 #include <linux/config.h>
 
-/* Note that we shift the lower 32bits of each EntryLo[01] entry
+/*
+ * Note that we shift the lower 32bits of each EntryLo[01] entry
  * 6 bits to the left. That way we can convert the PFN into the
  * physical address by a single 'and' operation and gain 6 additional
  * bits for storing information which isn't present in a normal
@@ -63,10 +64,10 @@
 /* No penalty for being coherent on the SB1, so just
    use it for "noncoherent" spaces, too.  Shouldn't hurt. */
 
-#define _CACHE_UNCACHED             (2<<9)  
-#define _CACHE_CACHABLE_COW         (5<<9)  
-#define _CACHE_CACHABLE_NONCOHERENT (5<<9)  
-#define _CACHE_UNCACHED_ACCELERATED (7<<9)  
+#define _CACHE_UNCACHED             (2<<9)
+#define _CACHE_CACHABLE_COW         (5<<9)
+#define _CACHE_CACHABLE_NONCOHERENT (5<<9)
+#define _CACHE_UNCACHED_ACCELERATED (7<<9)
 
 #else
 
@@ -74,9 +75,9 @@
 #define _CACHE_CACHABLE_WA          (1<<9)  /* R4600 only              */
 #define _CACHE_UNCACHED             (2<<9)  /* R4[0246]00              */
 #define _CACHE_CACHABLE_NONCOHERENT (3<<9)  /* R4[0246]00              */
-#define _CACHE_CACHABLE_CE          (4<<9)  /* R4[04]00 only           */
-#define _CACHE_CACHABLE_COW         (5<<9)  /* R4[04]00 only           */
-#define _CACHE_CACHABLE_CUW         (6<<9)  /* R4[04]00 only           */
+#define _CACHE_CACHABLE_CE          (4<<9)  /* R4[04]00MC only         */
+#define _CACHE_CACHABLE_COW         (5<<9)  /* R4[04]00MC only         */
+#define _CACHE_CACHABLE_CUW         (6<<9)  /* R4[04]00MC only         */
 #define _CACHE_UNCACHED_ACCELERATED (7<<9)  /* R10000 only             */
 
 #endif
@@ -89,10 +90,12 @@
 
 #ifdef CONFIG_MIPS_UNCACHED
 #define PAGE_CACHABLE_DEFAULT	_CACHE_UNCACHED
-#elif CONFIG_CPU_SB1
-#define PAGE_CACHABLE_DEFAULT	_CACHE_CACHABLE_COW
-#else
+#elif defined(CONFIG_NONCOHERENT_IO)
 #define PAGE_CACHABLE_DEFAULT	_CACHE_CACHABLE_NONCOHERENT
+#else
+#define PAGE_CACHABLE_DEFAULT	_CACHE_CACHABLE_COW
 #endif
 
-#endif /* _ASM_CACHINGMODES_H */
+#define CONF_CM_DEFAULT		(PAGE_CACHABLE_DEFAULT >> 9)
+
+#endif /* _ASM_PGTABLE_BITS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/pgtable.h linux-2.4.20/include/asm-mips/pgtable.h
--- linux-2.4.19/include/asm-mips/pgtable.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/pgtable.h	2002-10-29 11:18:35.000000000 +0000
@@ -73,7 +73,7 @@
 /*
  * - add_temporary_entry() add a temporary TLB entry. We use TLB entries
  *	starting at the top and working down. This is for populating the
- *	TLB before trap_init() puts the TLB miss handler in place. It 
+ *	TLB before trap_init() puts the TLB miss handler in place. It
  *	should be used only for entries matching the actual page tables,
  *	to prevent inconsistencies.
  */
@@ -240,7 +240,7 @@
 }
 
 /*
- * (pmds are folded into pgds so this doesnt get actually called,
+ * (pmds are folded into pgds so this doesn't get actually called,
  * but the define is needed for a generic inline function.)
  */
 #define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
@@ -436,7 +436,7 @@
 	return (pmd_t *) dir;
 }
 
-/* Find an entry in the third-level page table.. */ 
+/* Find an entry in the third-level page table.. */
 static inline pte_t *pte_offset(pmd_t * dir, unsigned long address)
 {
 	return (pte_t *) (pmd_page(*dir)) +
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/pmc/ev64120.h linux-2.4.20/include/asm-mips/pmc/ev64120.h
--- linux-2.4.19/include/asm-mips/pmc/ev64120.h	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/include/asm-mips/pmc/ev64120.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,59 +0,0 @@
-/*
- * This is a direct copy of the ev96100.h file, with a global search and
- * replace.  The numbers are the same.
- *
- * The reason I'm duplicating this is so that the 64120/96100
- * defines won't be confusing in the source code.
- */
-#ifndef _ASM_PMC_CP7000_H
-#define _ASM_PMC_CP7000_H
-
-#include <asm/addrspace.h>
-
-/*
- *   GT64120 config space base address
- */
-#define GT64120_BASE    (KSEG1ADDR(0x14000000))
-#define MIPS_GT_BASE    GT64120_BASE
- 
-/*
- *   PCI Bus allocation
- */
-#define GT_PCI_MEM_BASE    0x12000000
-#define GT_PCI_MEM_SIZE    0x02000000
-#define GT_PCI_IO_BASE     0x10000000
-#define GT_PCI_IO_SIZE     0x02000000
-#define GT_ISA_IO_BASE     PCI_IO_BASE          
-
-/*
- *   Duart I/O ports.
- */
-#define EV64120_COM1_BASE_ADDR  (0x1d000000 + 0x20) 
-#define EV64120_COM2_BASE_ADDR  (0x1d000000 + 0x00)
-
-
-/*
- *   EV64120 interrupt controller register base.
- */
-#define EV64120_ICTRL_REGS_BASE   (KSEG1ADDR(0x1f000000))
-
-/*
- *   EV64120 UART register base.
- */
-#define EV64120_UART0_REGS_BASE    (KSEG1ADDR(EV64120_COM1_BASE_ADDR))
-#define EV64120_UART1_REGS_BASE    (KSEG1ADDR(EV64120_COM2_BASE_ADDR))
-#define EV64120_BASE_BAUD ( 3686400 / 16 )
-
-
-/*
- * Because of an error/peculiarity in the Galileo chip, we need to swap the 
- * bytes when running bigendian.
- */
-
-#define GT_WRITE(ofs, data)  \
-	*(volatile u32 *)(MIPS_GT_BASE+ofs) = cpu_to_le32(data)
-#define GT_READ(ofs, data)   \
-	*data = le32_to_cpu(*(volatile u32 *)(MIPS_GT_BASE+ofs))
-    
-
-#endif /* _ASM_PMC_CP7000_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/pmc/ev64120int.h linux-2.4.20/include/asm-mips/pmc/ev64120int.h
--- linux-2.4.19/include/asm-mips/pmc/ev64120int.h	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/include/asm-mips/pmc/ev64120int.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,32 +0,0 @@
-#ifndef _ASM_PMC_CP7000INT_H
-#define _ASM_PMC_CP7000INT_H
-
-#define INT_CAUSE_MAIN 0
-#define INT_CAUSE_HIGH 1
-
-#define MAX_CAUSE_REGS 4
-#define MAX_CAUSE_REG_WIDTH 32
-
-void hook_irq_handler (int int_cause , int bit_num , void *isr_ptr);
-int disable_galileo_irq (int int_cause , int bit_num);
-int enable_galileo_irq (int int_cause , int bit_num);
-
-extern struct tq_struct irq_handlers[MAX_CAUSE_REGS][MAX_CAUSE_REG_WIDTH];
-
-/*
- * PCI interrupts will come in on either the INTA or INTD interrups lines,
- * which are mapped to the #2 and #5 interrupt pins of the MIPS.  On our
- * boards, they all either come in on IntD or they all come in on IntA, they
- * aren't mixed. There can be numerous PCI interrupts, so we keep a list of the
- * "requested" interrupt numbers and go through the list whenever we get an
- * IntA/D.
- *
- * All PCI interrupts have numbers >= 20 by arbitrary convention.  Any
- * interrupt < 8 is an interrupt that is maskable on MIPS.
- */
-
-#define TIMER	4
-#define INTA	2
-#define INTD	5
-
-#endif /* _ASM_PMC_CP7000INT_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/posix_types.h linux-2.4.20/include/asm-mips/posix_types.h
--- linux-2.4.19/include/asm-mips/posix_types.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/posix_types.h	2002-10-29 11:18:48.000000000 +0000
@@ -67,7 +67,7 @@
 
 #undef __FD_ISSET
 static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
-{ 
+{
 	unsigned long __tmp = __fd / __NFDBITS;
 	unsigned long __rem = __fd % __NFDBITS;
 	return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/prctl.h linux-2.4.20/include/asm-mips/prctl.h
--- linux-2.4.19/include/asm-mips/prctl.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/prctl.h	2002-10-29 11:18:38.000000000 +0000
@@ -12,14 +12,14 @@
 #define PRDA ((struct prda *) PRDA_ADDRESS)
 
 struct prda_sys {
-	pid_t t_pid; 
+	pid_t t_pid;
         u32   t_hint;
         u32   t_dlactseq;
         u32   t_fpflags;
         u32   t_prid;		/* processor type, $prid CP0 register */
         u32   t_dlendseq;
         u64   t_unused1[5];
-        pid_t t_rpid;   
+        pid_t t_rpid;
         s32   t_resched;
         u32   t_unused[8];
         u32   t_cpu;		/* current/last cpu */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/processor.h linux-2.4.20/include/asm-mips/processor.h
--- linux-2.4.19/include/asm-mips/processor.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/processor.h	2002-10-29 11:18:32.000000000 +0000
@@ -43,6 +43,7 @@
 extern void r3081_wait(void);
 extern void r39xx_wait(void);
 extern void r4k_wait(void);
+extern void au1k_wait(void);
 
 extern struct cpuinfo_mips cpu_data[];
 extern unsigned int vced_count, vcei_count;
@@ -55,12 +56,13 @@
 
 /*
  * Bus types (default is ISA, but people can check others with these..)
- * MCA_bus hardcoded to 0 for now.
- *
- * This needs to be extended since MIPS systems are being delivered with
- * numerous different types of bus systems.
  */
+#ifdef CONFIG_EISA
 extern int EISA_bus;
+#else
+#define EISA_bus (0)
+#endif
+
 #define MCA_bus 0
 #define MCA_bus__is_a_macro /* for versions in ksyms.c */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/riscos-syscall.h linux-2.4.20/include/asm-mips/riscos-syscall.h
--- linux-2.4.19/include/asm-mips/riscos-syscall.h	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/include/asm-mips/riscos-syscall.h	2002-10-29 11:18:48.000000000 +0000
@@ -220,7 +220,7 @@
 #define __NR_SVR4_reserved62		(__NR_SVR4 + 199)
 #define __NR_SVR4_reserved63		(__NR_SVR4 + 200)
 #define __NR_SVR4_aread			(__NR_SVR4 + 201)
-#define __NR_SVR4_awrite		(__NR_SVR4 + 202)	
+#define __NR_SVR4_awrite		(__NR_SVR4 + 202)
 #define __NR_SVR4_listio		(__NR_SVR4 + 203)
 #define __NR_SVR4_mips_acancel		(__NR_SVR4 + 204)
 #define __NR_SVR4_astatus		(__NR_SVR4 + 205)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/rrm.h linux-2.4.20/include/asm-mips/rrm.h
--- linux-2.4.19/include/asm-mips/rrm.h	1997-08-16 16:51:09.000000000 +0000
+++ linux-2.4.20/include/asm-mips/rrm.h	2002-10-29 11:18:34.000000000 +0000
@@ -77,7 +77,7 @@
  * RRM_BINDPROCTORN:
  *
  * Return value when the X server calls it: 0
- */ 
+ */
 struct RRM_BindProcToRN {
 	int      rnid;
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/scatterlist.h linux-2.4.20/include/asm-mips/scatterlist.h
--- linux-2.4.19/include/asm-mips/scatterlist.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/scatterlist.h	2002-10-29 11:18:33.000000000 +0000
@@ -2,17 +2,19 @@
 #define __ASM_SCATTERLIST_H
 
 struct scatterlist {
-	char * address;		/* Location data is to be transferred to */
+	char * address;		/* Location data is to be transferred to,
+				   NULL for highmem page */
 	struct page * page;	/* Location for highmem page, if any */
+	unsigned int offset;
+	dma_addr_t dma_address;
 	unsigned int length;
-	__u32 dvma_address;
 };
 
 struct mmu_sglist {
 	char *addr;
 	char *__dont_touch;
 	unsigned int len;
-	__u32 dvma_addr;
+	dma_addr_t dvma_addr;
 };
 
 #define ISA_DMA_THRESHOLD (0x00ffffff)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/semaphore-helper.h linux-2.4.20/include/asm-mips/semaphore-helper.h
--- linux-2.4.19/include/asm-mips/semaphore-helper.h	2001-09-09 17:43:01.000000000 +0000
+++ linux-2.4.20/include/asm-mips/semaphore-helper.h	2002-10-29 11:18:48.000000000 +0000
@@ -25,19 +25,18 @@
 
 #ifdef CONFIG_CPU_HAS_LLSC
 
-static inline int
-waking_non_zero(struct semaphore *sem)
+static inline int waking_non_zero(struct semaphore *sem)
 {
 	int ret, tmp;
 
 	__asm__ __volatile__(
-	"1:\tll\t%1, %2\n\t"
+	"1:\tll\t%1, %2\t\t\t# waking_non_zero\n\t"
 	"blez\t%1, 2f\n\t"
 	"subu\t%0, %1, 1\n\t"
 	"sc\t%0, %2\n\t"
-	"beqz\t%0, 1b\n\t"
+	"beqz\t%0, 1b\n"
 	"2:"
-	: "=r" (ret), "=r" (tmp), "=m" (sem->waking)
+	: "=r" (ret), "=r" (tmp), "+m" (sem->waking)
 	: "0"(0));
 
 	return ret;
@@ -74,22 +73,22 @@
  *	-EINTR	interrupted
  *
  * We must undo the sem->count down_interruptible decrement
- * simultaneously and atomicly with the sem->waking adjustment,
+ * simultaneously and atomically with the sem->waking adjustment,
  * otherwise we can race with wake_one_more.
  *
- * This is accomplished by doing a 64-bit ll/sc on the 2 32-bit words.
+ * This is accomplished by doing a 64-bit lld/scd on the 2 32-bit words.
  *
- * This is crazy.  Normally it stricly forbidden to use 64-bit operations
+ * This is crazy.  Normally it's strictly forbidden to use 64-bit operations
  * in the 32-bit MIPS kernel.  In this case it's however ok because if an
  * interrupt has destroyed the upper half of registers sc will fail.
- * Note also that this will not work for MIPS32 CPUS!
+ * Note also that this will not work for MIPS32 CPUs!
  *
  * Pseudocode:
  *
  * If(sem->waking > 0) {
  *	Decrement(sem->waking)
  *	Return(SUCCESS)
- * } else If(segnal_pending(tsk)) {
+ * } else If(signal_pending(tsk)) {
  *	Increment(sem->count)
  *	Return(-EINTR)
  * } else {
@@ -127,12 +126,11 @@
 }
 
 /*
- * waking_non_zero_trylock is unused.  we do everything in 
+ * waking_non_zero_trylock is unused.  we do everything in
  * down_trylock and let non-ll/sc hosts bounce around.
  */
 
-static inline int
-waking_non_zero_trylock(struct semaphore *sem)
+static inline int waking_non_zero_trylock(struct semaphore *sem)
 {
 #if WAITQUEUE_DEBUG
 	CHECK_MAGIC(sem->__magic);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/semaphore.h linux-2.4.20/include/asm-mips/semaphore.h
--- linux-2.4.19/include/asm-mips/semaphore.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/semaphore.h	2002-10-29 11:18:38.000000000 +0000
@@ -130,7 +130,7 @@
  * down_trylock returns 0 on success, 1 if we failed to get the lock.
  *
  * We must manipulate count and waking simultaneously and atomically.
- * Here, we this by using ll/sc on the pair of 32-bit words.  This
+ * Here, we do this by using lld/scd on the pair of 32-bit words.  This
  * won't work on MIPS32 platforms, however, and must be rewritten.
  *
  * Pseudocode:
@@ -194,4 +194,9 @@
 		__up(sem);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif /* _ASM_SEMAPHORE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sembuf.h linux-2.4.20/include/asm-mips/sembuf.h
--- linux-2.4.19/include/asm-mips/sembuf.h	2000-02-25 06:52:30.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sembuf.h	2002-10-29 11:18:36.000000000 +0000
@@ -1,7 +1,7 @@
 #ifndef _ASM_SEMBUF_H
 #define _ASM_SEMBUF_H
 
-/* 
+/*
  * The semid64_ds structure for the MIPS architecture.
  * Note extra padding because this structure is passed back and forth
  * between kernel and user space.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/serial.h linux-2.4.20/include/asm-mips/serial.h
--- linux-2.4.19/include/asm-mips/serial.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/serial.h	2002-10-29 11:18:47.000000000 +0000
@@ -84,11 +84,22 @@
 #define ATLAS_SERIAL_PORT_DEFNS
 #endif
 
+#ifdef CONFIG_MIPS_SEAD
+#include <asm/mips-boards/sead.h>
+#include <asm/mips-boards/seadint.h>
+#define SEAD_SERIAL_PORT_DEFNS			\
+	/* UART CLK   PORT IRQ     FLAGS        */			\
+	{ 0, SEAD_BASE_BAUD, SEAD_UART0_REGS_BASE, SEADINT_UART0, STD_COM_FLAGS },     /* ttyS0 */
+#else
+#define SEAD_SERIAL_PORT_DEFNS
+#endif
+
 #ifdef CONFIG_MIPS_COBALT
+#include <asm/cobalt/cobalt.h>
 #define COBALT_BASE_BAUD  (18432000 / 16)
 #define COBALT_SERIAL_PORT_DEFNS		\
 	/* UART CLK   PORT  IRQ  FLAGS    */ 		\
-	{ 0, COBALT_BASE_BAUD, 0xc800000, 7, STD_COM_FLAGS },   /* ttyS0 */
+	{ 0, COBALT_BASE_BAUD, 0xc800000, COBALT_SERIAL_IRQ, STD_COM_FLAGS },   /* ttyS0 */
 #else
 #define COBALT_SERIAL_PORT_DEFNS
 #endif
@@ -165,7 +176,7 @@
     { baud_base: JMR3927_BASE_BAUD, port: UART0_ADDR, irq: UART0_INT,  \
       flags: UART0_FLAGS, type: 1 },                        \
     { baud_base: JMR3927_BASE_BAUD, port: UART1_ADDR, irq: UART1_INT,  \
-      flags: UART1_FLAGS, type: 1 },     
+      flags: UART1_FLAGS, type: 1 },
 #else
 #define TXX927_SERIAL_PORT_DEFNS
 #endif
@@ -267,29 +278,53 @@
 #define MOMENCO_OCELOT_SERIAL_PORT_DEFNS
 #endif
 
+#ifdef CONFIG_MOMENCO_OCELOT_G
+/* Ordinary NS16552 duart with a 20MHz crystal.  */
+#define OCELOT_G_BASE_BAUD ( 20000000 / 16 )
+
+#define OCELOT_G_SERIAL1_IRQ	4
+#if 0
+#define OCELOT_G_SERIAL1_BASE	0xe0001020
+#else
+#define OCELOT_G_SERIAL1_BASE	0xfd000020
+#endif
+
+#define _OCELOT_G_SERIAL_INIT(int, base)				\
+	{ baud_base: OCELOT_G_BASE_BAUD, irq: int, flags: STD_COM_FLAGS,\
+	  iomem_base: (u8 *) base, iomem_reg_shift: 2,			\
+	  io_type: SERIAL_IO_MEM }
+#define MOMENCO_OCELOT_G_SERIAL_PORT_DEFNS				\
+	_OCELOT_G_SERIAL_INIT(OCELOT_G_SERIAL1_IRQ, OCELOT_G_SERIAL1_BASE)
+#else
+#define MOMENCO_OCELOT_G_SERIAL_PORT_DEFNS
+#endif
+
 #ifdef CONFIG_DDB5477
-#define DDB5477_SERIAL_PORT_DEFNS                                       \
-        { baud_base: BASE_BAUD, irq: 12, flags: STD_COM_FLAGS,          \
-          iomem_base: (u8*)0xbfa04200, iomem_reg_shift: 3,              \
+#include <asm/ddb5xxx/ddb5477.h>
+#define DDB5477_SERIAL_PORT_DEFNS                                             \
+        { baud_base: BASE_BAUD, irq: VRC5477_IRQ_UART0, flags: STD_COM_FLAGS, \
+          iomem_base: (u8*)0xbfa04200, iomem_reg_shift: 3,                    \
           io_type: SERIAL_IO_MEM},\
-        { baud_base: BASE_BAUD, irq: 28, flags: STD_COM_FLAGS,          \
-          iomem_base: (u8*)0xbfa04240, iomem_reg_shift: 3,              \
+        { baud_base: BASE_BAUD, irq: VRC5477_IRQ_UART1, flags: STD_COM_FLAGS, \
+          iomem_base: (u8*)0xbfa04240, iomem_reg_shift: 3,                    \
           io_type: SERIAL_IO_MEM},
 #else
 #define DDB5477_SERIAL_PORT_DEFNS
 #endif
 
-#define SERIAL_PORT_DFNS		\
-	IVR_SERIAL_PORT_DEFNS           \
-	ITE_SERIAL_PORT_DEFNS           \
-	ATLAS_SERIAL_PORT_DEFNS		\
-	COBALT_SERIAL_PORT_DEFNS	\
-	EV96100_SERIAL_PORT_DEFNS	\
-	JAZZ_SERIAL_PORT_DEFNS		\
-	STD_SERIAL_PORT_DEFNS		\
-	EXTRA_SERIAL_PORT_DEFNS		\
-	HUB6_SERIAL_PORT_DFNS		\
-	MOMENCO_OCELOT_SERIAL_PORT_DEFNS\
-	AU1000_SERIAL_PORT_DEFNS	\
-        TXX927_SERIAL_PORT_DEFNS        \
+#define SERIAL_PORT_DFNS			\
+	IVR_SERIAL_PORT_DEFNS           	\
+	ITE_SERIAL_PORT_DEFNS           	\
+	ATLAS_SERIAL_PORT_DEFNS			\
+	SEAD_SERIAL_PORT_DEFNS			\
+	COBALT_SERIAL_PORT_DEFNS		\
+	EV96100_SERIAL_PORT_DEFNS		\
+	JAZZ_SERIAL_PORT_DEFNS			\
+	STD_SERIAL_PORT_DEFNS			\
+	EXTRA_SERIAL_PORT_DEFNS			\
+	HUB6_SERIAL_PORT_DFNS			\
+	MOMENCO_OCELOT_SERIAL_PORT_DEFNS	\
+	MOMENCO_OCELOT_G_SERIAL_PORT_DEFNS	\
+	AU1000_SERIAL_PORT_DEFNS		\
+        TXX927_SERIAL_PORT_DEFNS        	\
 	DDB5477_SERIAL_PORT_DEFNS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sgi/sgigio.h linux-2.4.20/include/asm-mips/sgi/sgigio.h
--- linux-2.4.19/include/asm-mips/sgi/sgigio.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sgi/sgigio.h	2002-10-29 11:18:36.000000000 +0000
@@ -19,21 +19,21 @@
  *   1     EXP0      0x1f400000 - 0x1f5fffff   2MB
  *   2     EXP1      0x1f600000 - 0x1f9fffff   4MB
  *
- * There are un-slotted devices, HPC, I/O and misc devices, which are grouped 
+ * There are un-slotted devices, HPC, I/O and misc devices, which are grouped
  * into the HPC address space.
  *   -     MISC      0x1fb00000 - 0x1fbfffff   1MB
- *      
+ *
  * Following space is reserved and unused
  *   -     RESERVED  0x18000000 - 0x1effffff 112MB
  *
- * The GIO specification tends to use slot numbers while the MC specification 
+ * The GIO specification tends to use slot numbers while the MC specification
  * tends to use slot types.
  *
- * slot0  - the "graphics" (GFX) slot but there is no requirement that 
+ * slot0  - the "graphics" (GFX) slot but there is no requirement that
  *          a graphics dev may only use this slot
- * slot1  - this is the "expansion"-slot 0 (EXP0), do not confuse with 
+ * slot1  - this is the "expansion"-slot 0 (EXP0), do not confuse with
  *          slot 0 (GFX).
- * slot2  - this is the "expansion"-slot 1 (EXP1), do not confuse with 
+ * slot2  - this is the "expansion"-slot 1 (EXP1), do not confuse with
  *          slot 1 (EXP0).
  */
 
@@ -57,7 +57,7 @@
 	unsigned char	slot_number;
 	unsigned long	base_addr;
 	unsigned int	map_size;
-	
+
 	char		*name;
 	char		slot_name[5];
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sgi/sgihpc.h linux-2.4.20/include/asm-mips/sgi/sgihpc.h
--- linux-2.4.19/include/asm-mips/sgi/sgihpc.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sgi/sgihpc.h	2002-10-29 11:18:37.000000000 +0000
@@ -45,8 +45,8 @@
 	hpcreg pbdma_bptr;	/* pbus dma channel buffer ptr */
 	hpcreg pbdma_dptr;	/* pbus dma channel desc ptr */
 	char _unused1[PAGE_SIZE - (2 * sizeof(hpcreg))]; /* padding */
-	hpcreg pbdma_ctrl;	/* pbus dma channel control register has 
-				 * copletely different meaning for read 
+	hpcreg pbdma_ctrl;	/* pbus dma channel control register has
+				 * copletely different meaning for read
 				 * compared with write */
 	/* read */
 #define HPC3_PDMACTRL_INT	0x00000001 /* interrupt (cleared after read) */
@@ -235,7 +235,7 @@
 	hpcreg scsi1_ext[256];	/* SCSI channel 1 external regs */
 	char _unused4[0x07c00];	/* It'll only hurt a little... */
 
-	/* Ethernet external registers. Noone use them so we need some 
+	/* Ethernet external registers. Noone use them so we need some
 	 * padding instead.
 	 */
 	char _unused5[0x04000]; /* It'll hurt a lot if you leave this out */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sgi/sgint23.h linux-2.4.20/include/asm-mips/sgi/sgint23.h
--- linux-2.4.19/include/asm-mips/sgi/sgint23.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sgi/sgint23.h	2002-10-29 11:18:33.000000000 +0000
@@ -16,17 +16,18 @@
 /* These are the virtual IRQ numbers, we divide all IRQ's into
  * 'spaces', the 'space' determines where and how to enable/disable
  * that particular IRQ on an SGI machine. HPC DMA and MC DMA interrups
- * are not supported this way. Driver is supposed to allocate HPC/MC 
+ * are not supported this way. Driver is supposed to allocate HPC/MC
  * interrupt as shareable and then look to proper status bit (see
- * HAL2 driver). This will prevent many complications, trust me ;-) 
+ * HAL2 driver). This will prevent many complications, trust me ;-)
  *	--ladis
  */
-#define SGINT_CPU	 0	/* MIPS CPU define 8 interrupt sources */
-#define SGINT_LOCAL0	 8	/* INDY has 8 local0 irq levels */
-#define SGINT_LOCAL1	16	/* INDY has 8 local1 irq levels */
-#define SGINT_LOCAL2	24	/* INDY has 8 local2 vectored irq levels */
-#define SGINT_LOCAL3	32	/* INDY has 8 local3 vectored irq levels */
-#define SGINT_END	40	/* End of 'spaces' */
+#define SGINT_EISA	0	/* INDIGO 2 has 16 EISA irq levels */
+#define SGINT_CPU	16	/* MIPS CPU define 8 interrupt sources */
+#define SGINT_LOCAL0	24	/* INDY has 8 local0 irq levels */
+#define SGINT_LOCAL1	32	/* INDY has 8 local1 irq levels */
+#define SGINT_LOCAL2	40	/* INDY has 8 local2 vectored irq levels */
+#define SGINT_LOCAL3	48	/* INDY has 8 local3 vectored irq levels */
+#define SGINT_END	56	/* End of 'spaces' */
 
 /*
  * Individual interrupt definitions for the INDY and Indigo2
@@ -42,7 +43,7 @@
 #define SGI_TIMER_IRQ	SGINT_CPU + 7
 
 #define SGI_FIFO_IRQ	SGINT_LOCAL0 + 0	/* FIFO full */
-#define SGI_GIO_0_IRQ	SGI_FIFO_IRQ		/* GIO-0 */	
+#define SGI_GIO_0_IRQ	SGI_FIFO_IRQ		/* GIO-0 */
 #define SGI_WD93_0_IRQ	SGINT_LOCAL0 + 1	/* 1st onboard WD93 */
 #define SGI_WD93_1_IRQ	SGINT_LOCAL0 + 2	/* 2nd onboard WD93 */
 #define SGI_ENET_IRQ	SGINT_LOCAL0 + 3	/* onboard ethernet */
@@ -87,7 +88,7 @@
 #define ISTAT0_LPR	0x20
 #define ISTAT0_HPC2	0x40
 #define ISTAT0_LIO2	0x80
-	
+
 #ifdef __MIPSEB__
 	unsigned char _unused1[3];
 	volatile unsigned char imask0;	/* Interrupt mask zero */
@@ -107,7 +108,7 @@
 #define ISTAT1_AFAIL	0x20
 #define ISTAT1_VIDEO	0x40
 #define ISTAT1_GIO2	0x80
-	
+
 #ifdef __MIPSEB__
 	unsigned char _unused3[3];
 	volatile unsigned char imask1;		/* Interrupt mask one */
@@ -199,7 +200,7 @@
 #endif
 #define INT2_TCLEAR_T0CLR	0x1	/* Clear timer0 IRQ */
 #define INT2_TCLEAR_T1CLR	0x2	/* Clear timer1 IRQ */
-/* I am guesing there are only two unused registers here 
+/* I am guesing there are only two unused registers here
  * but I could be wrong...			- andrewb
  */
 /*	u32 _unused[3]; */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sgialib.h linux-2.4.20/include/asm-mips/sgialib.h
--- linux-2.4.19/include/asm-mips/sgialib.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sgialib.h	2002-10-29 11:18:49.000000000 +0000
@@ -1,7 +1,12 @@
 /*
- * sgialib.h: SGI ARCS firmware interface library for the Linux kernel.
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * SGI ARCS firmware interface library for the Linux kernel.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 2001, 2002 Ralf Baechle (ralf@gnu.org)
  */
 #ifndef _ASM_SGIALIB_H
 #define _ASM_SGIALIB_H
@@ -10,15 +15,19 @@
 
 extern struct linux_romvec *romvec;
 extern int prom_argc;
-extern char **prom_argv, **prom_envp;
+
+extern LONG *_prom_argv, *_prom_envp;
+
+/* A 32-bit ARC PROM pass arguments and environment as 32-bit pointer.
+   These macros take care of sign extension.  */
+#define prom_argv(index) ((char *) (long) _prom_argv[(index)])
+#define prom_argc(index) ((char *) (long) _prom_argc[(index)])
 
 extern int prom_flags;
-#define PROM_FLAG_ARCS  1
+#define PROM_FLAG_ARCS			1
+#define PROM_FLAG_USE_AS_CONSOLE	2
 
-/*
- * Init the PROM library and it's internal data structures.  Called
- * at boot time from head.S before start_kernel is invoked.
- */
+/* Init the PROM library and it's internal data structures. */
 extern void prom_init(int argc, char **argv, char **envp, int *prom_vec);
 
 /* Simple char-by-char console I/O. */
@@ -28,18 +37,31 @@
 /* Generic printf() using ARCS console I/O. */
 extern void prom_printf(char *fmt, ...);
 
+/* Memory descriptor management. */
+#define PROM_MAX_PMEMBLOCKS    32
+struct prom_pmemblock {
+	LONG	base;		/* Within KSEG0 or XKPHYS. */
+	ULONG size;		/* In bytes. */
+	ULONG type;		/* free or prom memory */
+};
+
+/* Get next memory descriptor after CURR, returns first descriptor
+ * in chain is CURR is NULL.
+ */
+extern struct linux_mdesc *prom_getmdesc(struct linux_mdesc *curr);
 #define PROM_NULL_MDESC   ((struct linux_mdesc *) 0)
 
 /* Called by prom_init to setup the physical memory pmemblock
  * array.
  */
 extern void prom_meminit(void);
+extern void prom_fixup_mem_map(unsigned long start_mem, unsigned long end_mem);
 
 /* PROM device tree library routines. */
 #define PROM_NULL_COMPONENT ((pcomponent *) 0)
 
 /* Get sibling component of THIS. */
-extern pcomponent *prom_getsibling(pcomponent *this);
+extern pcomponent *ArcGetPeer(pcomponent *this);
 
 /* Get child component of THIS. */
 extern pcomponent *ArcGetChild(pcomponent *this);
@@ -64,7 +86,7 @@
 extern void prom_identify_arch(void);
 
 /* Environment variable routines. */
-extern PCHAR ArcGetEnvironmentVariable(CHAR *name);
+extern PCHAR ArcGetEnvironmentVariable(PCHAR name);
 extern LONG ArcSetEnvironmentVariable(PCHAR name, PCHAR value);
 
 /* ARCS command line acquisition and parsing. */
@@ -79,9 +101,9 @@
 extern long prom_getvdirent(unsigned long fd, struct linux_vdirent *ent, unsigned long num, unsigned long *cnt);
 extern long prom_open(char *name, enum linux_omode md, unsigned long *fd);
 extern long prom_close(unsigned long fd);
-extern long prom_read(unsigned long fd, void *buf, unsigned long num, unsigned long *cnt);
+extern LONG ArcRead(ULONG fd, PVOID buf, ULONG num, PULONG cnt);
 extern long prom_getrstatus(unsigned long fd);
-extern long prom_write(unsigned long fd, void *buf, unsigned long num, unsigned long *cnt);
+extern LONG ArcWrite(ULONG fd, PVOID buf, ULONG num, PULONG cnt);
 extern long prom_seek(unsigned long fd, struct linux_bigint *off, enum linux_seekmode sm);
 extern long prom_mount(char *name, enum linux_mountops op);
 extern long prom_getfinfo(unsigned long fd, struct linux_finfo *buf);
@@ -93,13 +115,13 @@
 extern long prom_exec(char *name, long argc, char **argv, char **envp);
 
 /* Misc. routines. */
-extern void prom_halt(void) __attribute__((noreturn));
-extern void prom_powerdown(void) __attribute__((noreturn));
-extern void prom_restart(void) __attribute__((noreturn));
-extern void prom_reboot(void) __attribute__((noreturn));
-extern void ArcEnterInteractiveMode(void) __attribute__((noreturn));
-extern long prom_cfgsave(void);
-extern struct linux_sysid *prom_getsysid(void);
-extern void prom_cacheflush(void);
+extern VOID prom_halt(VOID) __attribute__((noreturn));
+extern VOID prom_powerdown(VOID) __attribute__((noreturn));
+extern VOID prom_restart(VOID) __attribute__((noreturn));
+extern VOID ArcReboot(VOID) __attribute__((noreturn));
+extern VOID ArcEnterInteractiveMode(VOID) __attribute__((noreturn));
+extern long prom_cfgsave(VOID);
+extern struct linux_sysid *prom_getsysid(VOID);
+extern VOID ArcFlushAllCaches(VOID);
 
 #endif /* _ASM_SGIALIB_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sgiarcs.h linux-2.4.20/include/asm-mips/sgiarcs.h
--- linux-2.4.19/include/asm-mips/sgiarcs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sgiarcs.h	2002-10-29 11:18:37.000000000 +0000
@@ -13,6 +13,7 @@
 #define _ASM_SGIARCS_H
 
 #include <linux/config.h>
+#include <asm/types.h>
 #include <asm/arc/types.h>
 
 /* Various ARCS error codes. */
@@ -115,7 +116,7 @@
 	arc_prog,    /* A loaded program resides here */
 	arc_atmp,    /* temporary storage area */
 	arc_aperm,   /* permanent storage */
-	arc_fcontig, /* Contiguous and free */    
+	arc_fcontig, /* Contiguous and free */
 };
 
 union linux_memtypes {
@@ -164,11 +165,11 @@
 /* This prom has a bolixed design. */
 struct linux_bigint {
 #ifdef __MIPSEL__
-	unsigned long lo;
-	long hi;
+	u32 lo;
+	s32 hi;
 #else /* !(__MIPSEL__) */
-	long hi;
-	unsigned long lo;
+	s32 hi;
+	u32 lo;
 #endif
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/shmbuf.h linux-2.4.20/include/asm-mips/shmbuf.h
--- linux-2.4.19/include/asm-mips/shmbuf.h	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/include/asm-mips/shmbuf.h	2002-10-29 11:18:40.000000000 +0000
@@ -1,7 +1,7 @@
 #ifndef _ASM_SHMBUF_H
 #define _ASM_SHMBUF_H
 
-/* 
+/*
  * The shmid64_ds structure for the MIPS architecture.
  * Note extra padding because this structure is passed back and forth
  * between kernel and user space.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/shmiq.h linux-2.4.20/include/asm-mips/shmiq.h
--- linux-2.4.19/include/asm-mips/shmiq.h	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.20/include/asm-mips/shmiq.h	2002-10-29 11:18:35.000000000 +0000
@@ -5,7 +5,7 @@
  *
  * This also contains some streams and idev bits.
  *
- * They may contain errors, please, refer to the source code of the Linux  
+ * They may contain errors, please, refer to the source code of the Linux
  * kernel for a definitive answer on what we have implemented
  *
  * Miguel.
@@ -91,7 +91,7 @@
  * head   is the user index into the events, user can modify this one.
  * tail   is managed by the kernel.
  * flags  is one of SHMIQ_OVERFLOW or SHMIQ_CORRUPTED
- *        if OVERFLOW is set it seems ioctl QUIOCSERVICED should be called 
+ *        if OVERFLOW is set it seems ioctl QUIOCSERVICED should be called
  *        to notify the kernel.
  * events where the kernel sticks the events.
  */
@@ -186,14 +186,14 @@
         unsigned        hwMaxRes;
         int             hwMinVal;
         int             hwMaxVal;
-	
+
         unsigned char   possibleModes;
 #define IDEV_ABSOLUTE           0x0
 #define IDEV_RELATIVE           0x1
 #define IDEV_EITHER             0x2
-	
+
         unsigned char   mode;	/* One of: IDEV_ABSOLUTE, IDEV_RELATIVE */
-	
+
         unsigned short  resolution;
         int             minVal;
         int             maxVal;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/64bit.h linux-2.4.20/include/asm-mips/sibyte/64bit.h
--- linux-2.4.19/include/asm-mips/sibyte/64bit.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/64bit.h	2002-10-29 11:18:31.000000000 +0000
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2000, 2001 Broadcom Corporation
+ * Copyright (C) 2002 Ralf Baechle
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -10,56 +11,58 @@
  * 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.
  */
 
-#ifndef _SB1_64BIT_H
-#define _SB1_64BIT_H
+#ifndef __ASM_SIBYTE_64BIT_H
+#define __ASM_SIBYTE_64BIT_H
 
+#include <linux/config.h>
 #include <linux/types.h>
+
+#ifdef CONFIG_MIPS32
+
 #include <asm/system.h>
 
 /*
  * This is annoying...we can't actually write the 64-bit IO register properly
  * without having access to 64-bit registers...  which doesn't work by default
  * in o32 format...grrr...
-*/
-
+ */
 static inline void out64(u64 val, unsigned long addr)
 {
-	u32 low, high, tmp;
+	u32 low, high;
 	unsigned long flags;
-
 	high = val >> 32;
 	low = val & 0xffffffff;
+	// save_flags(flags);
 	__save_and_cli(flags);
 	__asm__ __volatile__ (
-		".set push\t\t\t# out64n"
+		".set push\n"
 		".set noreorder\n"
 		".set noat\n"
 		".set mips4\n"
-		"   dsll32 %0, %2, 0   \n"
-		"   dsll32 $1, %1, 0   \n"
-		"   dsrl32 %0, %0, 0   \n"
-		"   or     $1, $1, %0  \n"
-		"   sd $1, (%3)\n"
+		"   dsll32 $2, %1, 0   \n"
+		"   dsll32 $1, %0, 0   \n"
+		"   dsrl32 $2, $2, 0   \n"
+		"   or     $1, $1, $2  \n"
+		"   sd $1, (%2)\n"
 		".set pop\n"
-		: "=&r" (tmp)
-		: "r" (high), "r" (low), "r" (addr));
+		::"r" (high), "r" (low), "r" (addr)
+		:"$1", "$2");
 	__restore_flags(flags);
 }
 
 static inline u64 in64(unsigned long addr)
 {
-	unsigned long flags;
 	u32 low, high;
-
+	unsigned long flags;
 	__save_and_cli(flags);
 	__asm__ __volatile__ (
-		".set push\t\t\t# in64\n"
+		".set push\n"
 		".set noreorder\n"
 		".set noat     \n"
 		".set mips4    \n"
@@ -67,11 +70,43 @@
 		"  dsra32 %0, %1, 0\n"
 		"  sll    %1, %1, 0\n"
 		".set pop\n"
-		: "=r" (high), "=r" (low)
-		: "r" (addr));
+		:"=r" (high), "=r" (low): "r" (addr));
 	__restore_flags(flags);
-
 	return (((u64)high) << 32) | low;
 }
 
-#endif /* _SB1_64BIT_H */
+#endif /* CONFIG_MIPS32 */
+
+#ifdef CONFIG_MIPS64
+
+/*
+ * These are provided so as to be able to use common
+ * driver code for the 32-bit and 64-bit trees
+ */
+extern inline void out64(u64 val, unsigned long addr)
+{
+	*(volatile unsigned long *)addr = val;
+}
+
+extern inline u64 in64(unsigned long addr)
+{
+	return *(volatile unsigned long *)addr;
+}
+
+#endif /* CONFIG_MIPS64 */
+
+/*
+ * Avoid interrupt mucking, just adjust the address for 4-byte access.
+ * Assume the addresses are 8-byte aligned.
+ */
+
+#ifdef __MIPSEB__
+#define __CSR_32_ADJUST 4
+#else
+#define __CSR_32_ADJUST 0
+#endif
+
+#define csr_out32(v,a) (*(u32 *)((unsigned long)(a) + __CSR_32_ADJUST) = (v))
+#define csr_in32(a)    (*(u32 *)((unsigned long)(a) + __CSR_32_ADJUST))
+
+#endif /* __ASM_SIBYTE_64BIT_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/board.h linux-2.4.20/include/asm-mips/sibyte/board.h
--- linux-2.4.19/include/asm-mips/sibyte/board.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/board.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2000, 2001 Broadcom Corporation
+ *
+ * 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.
+ */
+
+#ifndef _SIBYTE_BOARD_H
+#define _SIBYTE_BOARD_H
+
+#if defined(CONFIG_SIBYTE_PTSWARM) || defined(CONFIG_SIBYTE_SWARM)
+#include <asm/sibyte/swarm.h>
+#endif
+
+#endif
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/sb1250.h linux-2.4.20/include/asm-mips/sibyte/sb1250.h
--- linux-2.4.19/include/asm-mips/sibyte/sb1250.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/sb1250.h	2002-10-29 11:18:40.000000000 +0000
@@ -10,7 +10,7 @@
  * 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.
@@ -19,11 +19,21 @@
 #ifndef _ASM_SIBYTE_SB1250_H
 #define _ASM_SIBYTE_SB1250_H
 
+#ifndef __ASSEMBLY__
+
+#include <asm/addrspace.h>
+
+/* For revision/pass information */
+#include <asm/sibyte/sb1250_scd.h>
+extern unsigned int sb1250_pass;
+
 extern void sb1250_time_init(void);
+extern unsigned long sb1250_gettimeoffset(void);
 extern void sb1250_mask_irq(int cpu, int irq);
 extern void sb1250_unmask_irq(int cpu, int irq);
 extern void sb1250_smp_finish(void);
+#endif
 
-#define IO_SPACE_BASE 0xa0000000UL
+#define IO_SPACE_BASE KSEG1
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/sb1250_defs.h linux-2.4.20/include/asm-mips/sibyte/sb1250_defs.h
--- linux-2.4.19/include/asm-mips/sibyte/sb1250_defs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/sb1250_defs.h	2002-10-29 11:18:36.000000000 +0000
@@ -1,21 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
-    *  Global constants and macros		File: sb1250_defs.h	
-    *  
+    *
+    *  Global constants and macros		File: sb1250_defs.h
+    *
     *  This file contains macros and definitions used by the other
     *  include files.
     *
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -25,38 +27,38 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
 
 /*  *********************************************************************
     *  Naming schemes for constants in these files:
-    *  
-    *  M_xxx           MASK constant (identifies bits in a register). 
+    *
+    *  M_xxx           MASK constant (identifies bits in a register).
     *                  For multi-bit fields, all bits in the field will
     *                  be set.
     *
     *  K_xxx           "Code" constant (value for data in a multi-bit
     *                  field).  The value is right justified.
     *
-    *  V_xxx           "Value" constant.  This is the same as the 
+    *  V_xxx           "Value" constant.  This is the same as the
     *                  corresponding "K_xxx" constant, except it is
     *                  shifted to the correct position in the register.
     *
     *  S_xxx           SHIFT constant.  This is the number of bits that
-    *                  a field value (code) needs to be shifted 
+    *                  a field value (code) needs to be shifted
     *                  (towards the left) to put the value in the right
     *                  position for the register.
     *
-    *  A_xxx           ADDRESS constant.  This will be a physical 
+    *  A_xxx           ADDRESS constant.  This will be a physical
     *                  address.  Use the PHYS_TO_K1 macro to generate
     *                  a K1SEG address.
     *
     *  R_xxx           RELATIVE offset constant.  This is an offset from
     *                  an A_xxx constant (usually the first register in
     *                  a group).
-    *  
+    *
     *  G_xxx(X)        GET value.  This macro obtains a multi-bit field
     *                  from a register, masks it, and shifts it to
     *                  the bottom of the register (retrieving a K_xxx
@@ -74,7 +76,7 @@
 #define _SB1250_DEFS_H
 
 /*
- * Cast to 64-bit number.  Presumably the syntax is different in 
+ * Cast to 64-bit number.  Presumably the syntax is different in
  * assembly language.
  *
  * Note: you'll need to define uint32_t and uint64_t in your headers.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/sb1250_dma.h linux-2.4.20/include/asm-mips/sibyte/sb1250_dma.h
--- linux-2.4.19/include/asm-mips/sibyte/sb1250_dma.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/sb1250_dma.h	2002-10-29 11:18:33.000000000 +0000
@@ -1,24 +1,24 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  DMA definitions				File: sb1250_dma.h
-    *  
+    *
     *  This module contains constants and macros useful for
     *  programming the SB1250's DMA controllers, both the data mover
     *  and the Ethernet DMA.
-    *  
-    *  SB1250 specification level:  0.2
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -28,7 +28,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -43,9 +43,9 @@
     *  DMA Registers
     ********************************************************************* */
 
-/* 
+/*
  * Ethernet and Serial DMA Configuration Register 0  (Table 7-4)
- * Registers: DMA_CONFIG0_MAC_x_RX_CH_0 
+ * Registers: DMA_CONFIG0_MAC_x_RX_CH_0
  * Registers: DMA_CONFIG0_MAC_x_TX_CH_0
  * Registers: DMA_CONFIG0_SER_x_RX
  * Registers: DMA_CONFIG0_SER_x_TX
@@ -83,7 +83,7 @@
 
 /*
  * Ethernet and Serial DMA Configuration Register 2 (Table 7-5)
- * Registers: DMA_CONFIG1_MAC_x_RX_CH_0 
+ * Registers: DMA_CONFIG1_MAC_x_RX_CH_0
  * Registers: DMA_CONFIG1_DMA_x_TX_CH_0
  * Registers: DMA_CONFIG1_SER_x_RX
  * Registers: DMA_CONFIG1_SER_x_TX
@@ -131,11 +131,11 @@
 /*
  * DMA Descriptor Count Registers (Table 7-8)
  */
- 
+
 /* No bitfields */
 
 
-/* 
+/*
  * Current Descriptor Address Register (Table 7-11)
  */
 
@@ -202,13 +202,16 @@
 #define V_DMA_DSCRB_PKT_SIZE(x)     _SB_MAKEVALUE(x,S_DMA_DSCRB_PKT_SIZE)
 #define G_DMA_DSCRB_PKT_SIZE(x)     _SB_GETVALUE(x,S_DMA_DSCRB_PKT_SIZE,M_DMA_DSCRB_PKT_SIZE)
 
-/* 
+/*
  * Ethernet Descriptor Status Bits (Table 7-15)
  */
 
 #define M_DMA_ETHRX_BADIP4CS        _SB_MAKEMASK1(51)
 #define M_DMA_ETHRX_DSCRERR	    _SB_MAKEMASK1(52)
 
+/* Note: BADTCPCS is actually in DSCR_A */
+#define M_DMA_ETHRX_BADTCPCS	_SB_MAKEMASK1(0)	/* PASS2 */
+
 #define S_DMA_ETHRX_RXCH            53
 #define M_DMA_ETHRX_RXCH            _SB_MAKEMASK(2,S_DMA_ETHRX_RXCH)
 #define V_DMA_ETHRX_RXCH(x)         _SB_MAKEVALUE(x,S_DMA_ETHRX_RXCH)
@@ -241,7 +244,7 @@
 
 #define M_DMA_ETHTX_SOP	    	    _SB_MAKEMASK1(63)
 
-/* 
+/*
  * Ethernet Transmit Options (Table 7-17)
  */
 
@@ -294,7 +297,7 @@
     *  Data Mover Registers
     ********************************************************************* */
 
-/* 
+/*
  * Data Mover Descriptor Base Address Register (Table 7-22)
  * Register: DM_DSCR_BASE_0
  * Register: DM_DSCR_BASE_1
@@ -302,10 +305,10 @@
  * Register: DM_DSCR_BASE_3
  */
 
-#define M_DM_DSCR_BASE_MBZ          _SB_MAKEMASK(3,0)
+#define M_DM_DSCR_BASE_MBZ          _SB_MAKEMASK(4,0)
 
 /*  Note: Just mask the base address and then OR it in. */
-#define S_DM_DSCR_BASE_ADDR         _SB_MAKE64(3)
+#define S_DM_DSCR_BASE_ADDR         _SB_MAKE64(4)
 #define M_DM_DSCR_BASE_ADDR         _SB_MAKEMASK(36,S_DM_DSCR_BASE_ADDR)
 
 #define S_DM_DSCR_BASE_RINGSZ       _SB_MAKE64(40)
@@ -331,7 +334,7 @@
 #define M_DM_DSCR_BASE_ABORT        _SB_MAKEMASK1(62)
 #define M_DM_DSCR_BASE_ENABL        _SB_MAKEMASK1(63)
 
-/* 
+/*
  * Data Mover Descriptor Count Register (Table 7-25)
  */
 
@@ -364,7 +367,10 @@
 #define M_DM_DSCRA_UN_DEST          _SB_MAKEMASK1(40)
 #define M_DM_DSCRA_UN_SRC           _SB_MAKEMASK1(41)
 #define M_DM_DSCRA_INTERRUPT        _SB_MAKEMASK1(42)
-#define M_DM_DSCRA_THROTTLE         _SB_MAKEMASK1(43)
+/*#define M_DM_DSCRA_THROTTLE         _SB_MAKEMASK1(43) */ /* REMOVED PASS2 */
+
+#define M_DM_DSCRA_RD_BKOFF	    _SB_MAKEMASK1(52)		/* PASS2 */
+#define M_DM_DSCRA_WR_BKOFF	    _SB_MAKEMASK1(53)		/* PASS2 */
 
 #define S_DM_DSCRA_DIR_DEST         _SB_MAKE64(44)
 #define M_DM_DSCRA_DIR_DEST         _SB_MAKEMASK(2,S_DM_DSCRA_DIR_DEST)
@@ -398,7 +404,7 @@
 #define M_DM_DSCRA_L2C_DEST         _SB_MAKEMASK1(50)
 #define M_DM_DSCRA_L2C_SRC          _SB_MAKEMASK1(51)
 
-#define M_DM_DSCRA_RESERVED2        _SB_MAKEMASK(12,52)
+#define M_DM_DSCRA_RESERVED2        _SB_MAKEMASK(10,54)
 
 /*
  * Data Mover Descriptor Doubleword "B"  (Table 7-25)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/sb1250_genbus.h linux-2.4.20/include/asm-mips/sibyte/sb1250_genbus.h
--- linux-2.4.19/include/asm-mips/sibyte/sb1250_genbus.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/sb1250_genbus.h	2002-10-29 11:18:31.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  Generic Bus Constants                     File: sb1250_genbus.h
-    *  
-    *  This module contains constants and macros useful for 
+    *
+    *  This module contains constants and macros useful for
     *  manipulating the SB1250's Generic Bus interface
-    *  
-    *  SB1250 specification level:  01/02/2002
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -48,11 +48,13 @@
 #define M_IO_WIDTH_SEL		_SB_MAKEMASK(2,S_IO_WIDTH_SEL)
 #define K_IO_WIDTH_SEL_1	0
 #define K_IO_WIDTH_SEL_2	1
+#define K_IO_WIDTH_SEL_1L       2		/* PASS2 */
 #define K_IO_WIDTH_SEL_4	3
 #define V_IO_WIDTH_SEL(x)	_SB_MAKEVALUE(x,S_IO_WIDTH_SEL)
 #define G_IO_WIDTH_SEL(x)	_SB_GETVALUE(x,S_IO_WIDTH_SEL,M_IO_WIDTH_SEL)
 
 #define M_IO_PARITY_ENA		_SB_MAKEMASK1(4)
+#define M_IO_BURST_EN		_SB_MAKEMASK1(5)	/* PASS2 */
 #define M_IO_PARITY_ODD		_SB_MAKEMASK1(6)
 #define M_IO_NONMUX		_SB_MAKEMASK1(7)
 
@@ -92,11 +94,18 @@
 #define V_IO_ALE_WIDTH(x)	_SB_MAKEVALUE(x,S_IO_ALE_WIDTH)
 #define G_IO_ALE_WIDTH(x)	_SB_GETVALUE(x,S_IO_ALE_WIDTH,M_IO_ALE_WIDTH)
 
+#define M_IO_EARLY_CS	        _SB_MAKEMASK1(3)	/* PASS2 */
+
 #define S_IO_ALE_TO_CS		4
 #define M_IO_ALE_TO_CS		_SB_MAKEMASK(2,S_IO_ALE_TO_CS)
 #define V_IO_ALE_TO_CS(x)	_SB_MAKEVALUE(x,S_IO_ALE_TO_CS)
 #define G_IO_ALE_TO_CS(x)	_SB_GETVALUE(x,S_IO_ALE_TO_CS,M_IO_ALE_TO_CS)
 
+#define S_IO_BURST_WIDTH           _SB_MAKE64(6)			/* PASS2 */
+#define M_IO_BURST_WIDTH           _SB_MAKEMASK(2,S_IO_BURST_WIDTH)	/* PASS2 */
+#define V_IO_BURST_WIDTH(x)        _SB_MAKEVALUE(x,S_IO_BURST_WIDTH)	/* PASS2 */
+#define G_IO_BURST_WIDTH(x)        _SB_GETVALUE(x,S_IO_BURST_WIDTH,M_IO_BURST_WIDTH)	/* PASS2 */
+
 #define S_IO_CS_WIDTH		8
 #define M_IO_CS_WIDTH		_SB_MAKEMASK(5,S_IO_CS_WIDTH)
 #define V_IO_CS_WIDTH(x)	_SB_MAKEVALUE(x,S_IO_CS_WIDTH)
@@ -117,6 +126,8 @@
 #define V_IO_ALE_TO_WRITE(x)	_SB_MAKEVALUE(x,S_IO_ALE_TO_WRITE)
 #define G_IO_ALE_TO_WRITE(x)	_SB_GETVALUE(x,S_IO_ALE_TO_WRITE,M_IO_ALE_TO_WRITE)
 
+#define M_IO_RDY_SYNC	        _SB_MAKEMASK1(3)	/* PASS2 */
+
 #define S_IO_WRITE_WIDTH	4
 #define M_IO_WRITE_WIDTH	_SB_MAKEMASK(4,S_IO_WRITE_WIDTH)
 #define V_IO_WRITE_WIDTH(x)	_SB_MAKEVALUE(x,S_IO_WRITE_WIDTH)
@@ -155,6 +166,7 @@
 #define M_IO_TIMEOUT_INT	_SB_MAKEMASK1(10)
 #define M_IO_ILL_ADDR_INT	_SB_MAKEMASK1(11)
 #define M_IO_MULT_CS_INT	_SB_MAKEMASK1(12)
+#define M_IO_COH_ERR	        _SB_MAKEMASK1(14)	/* PASS2 */
 
 /*
  * PCMCIA configuration register (Table 12-6)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/sb1250_int.h linux-2.4.20/include/asm-mips/sibyte/sb1250_int.h
--- linux-2.4.19/include/asm-mips/sibyte/sb1250_int.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/sb1250_int.h	2002-10-29 11:18:32.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  Interrupt Mapper definitions		File: sb1250_int.h
-    *  
+    *
     *  This module contains constants for manipulating the SB1250's
     *  interrupt mapper and definitions for the interrupt sources.
-    *  
-    *  SB1250 specification level:  0.2
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -43,7 +43,7 @@
 
 /*
  * Interrupt sources (Table 4-8, UM 0.2)
- * 
+ *
  * First, the interrupt numbers.
  */
 
@@ -77,8 +77,8 @@
 #define K_INT_MBOX_1                27
 #define K_INT_MBOX_2                28
 #define K_INT_MBOX_3                29
-#define K_INT_SPARE_0               30
-#define K_INT_SPARE_1               31
+#define K_INT_CYCLE_CP0_INT	    30		/* PASS2 */
+#define K_INT_CYCLE_CP1_INT	    31		/* PASS2 */
 #define K_INT_GPIO_0                32
 #define K_INT_GPIO_1                33
 #define K_INT_GPIO_2                34
@@ -108,9 +108,9 @@
 #define K_INT_PCI_INTC              58
 #define K_INT_PCI_INTD              59
 #define K_INT_SPARE_2               60
-#define K_INT_SPARE_3               61
-#define K_INT_SPARE_4               62
-#define K_INT_SPARE_5               63
+#define K_INT_MAC_0_CH1		    61		/* PASS2 */
+#define K_INT_MAC_1_CH1		    62		/* PASS2 */
+#define K_INT_MAC_2_CH1		    63		/* PASS2 */
 
 /*
  * Mask values for each interrupt
@@ -146,8 +146,8 @@
 #define M_INT_MBOX_1                _SB_MAKEMASK1(K_INT_MBOX_1)
 #define M_INT_MBOX_2                _SB_MAKEMASK1(K_INT_MBOX_2)
 #define M_INT_MBOX_3                _SB_MAKEMASK1(K_INT_MBOX_3)
-#define M_INT_SPARE_0               _SB_MAKEMASK1(K_INT_SPARE_0)
-#define M_INT_SPARE_1               _SB_MAKEMASK1(K_INT_SPARE_1)
+#define M_INT_CYCLE_CP0_INT	    _SB_MAKEMASK1(K_INT_CYCLE_CP0_INT)	/* PASS2 */
+#define M_INT_CYCLE_CP1_INT	    _SB_MAKEMASK1(K_INT_CYCLE_CP1_INT)	/* PASS2 */
 #define M_INT_GPIO_0                _SB_MAKEMASK1(K_INT_GPIO_0)
 #define M_INT_GPIO_1                _SB_MAKEMASK1(K_INT_GPIO_1)
 #define M_INT_GPIO_2                _SB_MAKEMASK1(K_INT_GPIO_2)
@@ -177,9 +177,9 @@
 #define M_INT_PCI_INTC              _SB_MAKEMASK1(K_INT_PCI_INTC)
 #define M_INT_PCI_INTD              _SB_MAKEMASK1(K_INT_PCI_INTD)
 #define M_INT_SPARE_2               _SB_MAKEMASK1(K_INT_SPARE_2)
-#define M_INT_SPARE_3               _SB_MAKEMASK1(K_INT_SPARE_3)
-#define M_INT_SPARE_4               _SB_MAKEMASK1(K_INT_SPARE_4)
-#define M_INT_SPARE_5               _SB_MAKEMASK1(K_INT_SPARE_5)
+#define M_INT_MAC_0_CH1		    _SB_MAKEMASK1(K_INT_MAC_0_CH1)	/* PASS2 */
+#define M_INT_MAC_1_CH1		    _SB_MAKEMASK1(K_INT_MAC_1_CH1)	/* PASS2 */
+#define M_INT_MAC_2_CH1		    _SB_MAKEMASK1(K_INT_MAC_2_CH1)	/* PASS2 */
 
 /*
  * Interrupt mappings
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/sb1250_l2c.h linux-2.4.20/include/asm-mips/sibyte/sb1250_l2c.h
--- linux-2.4.19/include/asm-mips/sibyte/sb1250_l2c.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/sb1250_l2c.h	2002-10-29 11:18:48.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  L2 Cache constants and macros		File: sb1250_l2c.h
-    *  
+    *
     *  This module contains constants useful for manipulating the
     *  level 2 cache.
-    *  
-    *  SB1250 specification level:  0.2
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -76,6 +76,14 @@
 #define V_L2C_MGMT_INDEX(x)         _SB_MAKEVALUE(x,S_L2C_MGMT_INDEX)
 #define G_L2C_MGMT_INDEX(x)         _SB_GETVALUE(x,S_L2C_MGMT_INDEX,M_L2C_MGMT_INDEX)
 
+#define S_L2C_MGMT_QUADRANT         15
+#define M_L2C_MGMT_QUADRANT         _SB_MAKEMASK(2,S_L2C_MGMT_QUADRANT)
+#define V_L2C_MGMT_QUADRANT(x)      _SB_MAKEVALUE(x,S_L2C_MGMT_QUADRANT)
+#define G_L2C_MGMT_QUADRANT(x)      _SB_GETVALUE(x,S_L2C_MGMT_QUADRANT,M_L2C_MGMT_QUADRANT)
+
+#define S_L2C_MGMT_HALF		    16
+#define M_L2C_MGMT_HALF	            _SB_MAKEMASK(1,S_L2C_MGMT_HALF)
+
 #define S_L2C_MGMT_WAY              17
 #define M_L2C_MGMT_WAY              _SB_MAKEMASK(2,S_L2C_MGMT_WAY)
 #define V_L2C_MGMT_WAY(x)           _SB_MAKEVALUE(x,S_L2C_MGMT_WAY)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/sb1250_ldt.h linux-2.4.20/include/asm-mips/sibyte/sb1250_ldt.h
--- linux-2.4.19/include/asm-mips/sibyte/sb1250_ldt.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/sb1250_ldt.h	2002-10-29 11:18:36.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  LDT constants				File: sb1250_ldt.h
-    *  
-    *  This module contains constants and macros to describe 
-    *  the LDT interface on the SB1250.  
-    *  
-    *  SB1250 specification level:  0.2 plus errata
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  This module contains constants and macros to describe
+    *  the LDT interface on the SB1250.
+    *
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -70,6 +70,7 @@
 #define R_LDT_TYPE1_SRIRXNUM	0x0058
 #define R_LDT_TYPE1_ERRSTATUS   0x0068
 #define R_LDT_TYPE1_SRICTRL	0x006C
+#define R_LDT_TYPE1_ADDSTATUS	0x0070		/* PASS2 */
 #define R_LDT_TYPE1_TXBUFCNT	0x00C8
 #define R_LDT_TYPE1_EXPCRC	0x00DC
 #define R_LDT_TYPE1_RXCRC	0x00F0
@@ -152,13 +153,14 @@
 
 /*
  * LDT Status Register (Table 8-14).  Note that these constants
- * assume you've read the command and status register 
+ * assume you've read the command and status register
  * together (32-bit read at offset 0x04)
  *
  * These bits also apply to the secondary status
  * register (Table 8-15), offset 0x1C
  */
 
+#define M_LDT_STATUS_VGAEN		_SB_MAKEMASK1_32(3)	/* PASS2 */
 #define M_LDT_STATUS_CAPLIST		_SB_MAKEMASK1_32(20)
 #define M_LDT_STATUS_66MHZCAP		_SB_MAKEMASK1_32(21)
 #define M_LDT_STATUS_RESERVED2		_SB_MAKEMASK1_32(22)
@@ -177,8 +179,8 @@
 #define M_LDT_STATUS_DETPARERR		_SB_MAKEMASK1_32(31)
 
 /*
- * Bridge Control Register (Table 8-16).  Note that these 
- * constants assume you've read the register as a 32-bit 
+ * Bridge Control Register (Table 8-16).  Note that these
+ * constants assume you've read the register as a 32-bit
  * read (offset 0x3C)
  */
 
@@ -279,7 +281,10 @@
 #define M_LDT_SRICMD_SIPREADY		_SB_MAKEMASK1_32(16)
 #define M_LDT_SRICMD_SYNCPTRCTL		_SB_MAKEMASK1_32(17)
 #define M_LDT_SRICMD_REDUCESYNCZERO	_SB_MAKEMASK1_32(18)
-#define M_LDT_SRICMD_DISSTARVATIONCNT	_SB_MAKEMASK1_32(19)
+/*#define M_LDT_SRICMD_DISSTARVATIONCNT	_SB_MAKEMASK1_32(19) */ /* PASS1 */
+#define M_LDT_SRICMD_DISMULTTXVLD	_SB_MAKEMASK1_32(19)	/* PASS2 */
+#define M_LDT_SRICMD_EXPENDIAN		_SB_MAKEMASK1_32(26)	/* PASS2 */
+
 
 #define S_LDT_SRICMD_RXMARGIN		20
 #define M_LDT_SRICMD_RXMARGIN		_SB_MAKEMASK_32(5,S_LDT_SRICMD_RXMARGIN)
@@ -397,6 +402,14 @@
 #define V_LDT_TXBUFCNT_RDATA(x)		_SB_MAKEVALUE_32(x,S_LDT_TXBUFCNT_RDATA)
 #define G_LDT_TXBUFCNT_RDATA(x)		_SB_GETVALUE_32(x,S_LDT_TXBUFCNT_RDATA,M_LDT_TXBUFCNT_RDATA)
 
+/*
+ * Additional Status Register (PASS2)
+ */
+
+#define S_LDT_ADDSTATUS_TGTDONE		0
+#define M_LDT_ADDSTATUS_TGTDONE		_SB_MAKEMASK_32(8,S_LDT_ADDSTATUS_TGTDONE)
+#define V_LDT_ADDSTATUS_TGTDONE(x)	_SB_MAKEVALUE_32(x,S_LDT_ADDSTATUS_TGTDONE)
+#define G_LDT_ADDSTATUS_TGTDONE(x)	_SB_GETVALUE_32(x,S_LDT_ADDSTATUS_TGTDONE,M_LDT_ADDSTATUS_TGTDONE)
 
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/sb1250_mac.h linux-2.4.20/include/asm-mips/sibyte/sb1250_mac.h
--- linux-2.4.19/include/asm-mips/sibyte/sb1250_mac.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/sb1250_mac.h	2002-10-29 11:18:32.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  MAC constants and macros			File: sb1250_mac.h
-    *  
+    *
     *  This module contains constants and macros for the SB1250's
     *  ethernet controllers.
-    *  
-    *  SB1250 specification level:  0.2 plus errata as of 4/10/2001
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -49,8 +49,6 @@
  */
 
 
-/* Updated to spec 0.2 */
-
 #define M_MAC_RESERVED0             _SB_MAKEMASK1(0)
 #define M_MAC_TX_HOLD_SOP_EN        _SB_MAKEMASK1(1)
 #define M_MAC_RETRY_EN              _SB_MAKEMASK1(2)
@@ -130,7 +128,7 @@
 #define M_MAC_BYPASS_16             _SB_MAKEMASK1(42)
 #define M_MAC_BYPASS_FCS_CHK	    _SB_MAKEMASK1(43)
 
-#define M_MAC_RESERVED4	    	    _SB_MAKEMASK(2,44)
+#define M_MAC_RX_CH_SEL_MSB	    _SB_MAKEMASK1(44)		/* PASS2 */
 
 #define S_MAC_BYPASS_IFG            _SB_MAKE64(46)
 #define M_MAC_BYPASS_IFG            _SB_MAKEMASK(8,S_MAC_BYPASS_IFG)
@@ -202,12 +200,14 @@
  */
 
 #define S_MAC_TX_WR_THRSH           _SB_MAKE64(0)
-#define M_MAC_TX_WR_THRSH           _SB_MAKEMASK(6,S_MAC_TX_WR_THRSH)
+/* #define M_MAC_TX_WR_THRSH           _SB_MAKEMASK(6,S_MAC_TX_WR_THRSH) */ /* PASS1 */
+#define M_MAC_TX_WR_THRSH           _SB_MAKEMASK(7,S_MAC_TX_WR_THRSH)	    /* PASS2 */
 #define V_MAC_TX_WR_THRSH(x)        _SB_MAKEVALUE(x,S_MAC_TX_WR_THRSH)
 #define G_MAC_TX_WR_THRSH(x)        _SB_GETVALUE(x,S_MAC_TX_WR_THRSH,M_MAC_TX_WR_THRSH)
 
 #define S_MAC_TX_RD_THRSH           _SB_MAKE64(8)
-#define M_MAC_TX_RD_THRSH           _SB_MAKEMASK(6,S_MAC_TX_RD_THRSH)
+/* #define M_MAC_TX_RD_THRSH           _SB_MAKEMASK(6,S_MAC_TX_RD_THRSH) */ /* PASS1 */
+#define M_MAC_TX_RD_THRSH           _SB_MAKEMASK(7,S_MAC_TX_RD_THRSH)	    /* PASS2 */
 #define V_MAC_TX_RD_THRSH(x)        _SB_MAKEVALUE(x,S_MAC_TX_RD_THRSH)
 #define G_MAC_TX_RD_THRSH(x)        _SB_GETVALUE(x,S_MAC_TX_RD_THRSH,M_MAC_TX_RD_THRSH)
 
@@ -231,6 +231,11 @@
 #define V_MAC_RX_RL_THRSH(x)        _SB_MAKEVALUE(x,S_MAC_RX_RL_THRSH)
 #define G_MAC_RX_RL_THRSH(x)        _SB_GETVALUE(x,S_MAC_RX_RL_THRSH,M_MAC_RX_RL_THRSH)
 
+#define S_MAC_ENC_FC_THRSH           _SB_MAKE64(56)			/* PASS2 */
+#define M_MAC_ENC_FC_THRSH           _SB_MAKEMASK(6,S_MAC_ENC_FC_THRSH)	/* PASS2 */
+#define V_MAC_ENC_FC_THRSH(x)        _SB_MAKEVALUE(x,S_MAC_ENC_FC_THRSH) /* PASS2 */
+#define G_MAC_ENC_FC_THRSH(x)        _SB_GETVALUE(x,S_MAC_ENC_FC_THRSH,M_MAC_ENC_FC_THRSH) /* PASS2 */
+
 /*
  * MAC Frame Configuration Registers (Table 9-15)
  * Register: MAC_FRAME_CFG_0
@@ -280,20 +285,20 @@
 
 /*
  * These constants are used to configure the fields within the Frame
- * Configuration Register.  
+ * Configuration Register.
  */
 
-#define K_MAC_IFG_RX_10             _SB_MAKE64(18)
-#define K_MAC_IFG_RX_100            _SB_MAKE64(18)
-#define K_MAC_IFG_RX_1000           _SB_MAKE64(6)
+#define K_MAC_IFG_RX_10             _SB_MAKE64(0)	/* See table 176, not used */
+#define K_MAC_IFG_RX_100            _SB_MAKE64(0)
+#define K_MAC_IFG_RX_1000           _SB_MAKE64(0)
 
 #define K_MAC_IFG_TX_10             _SB_MAKE64(20)
 #define K_MAC_IFG_TX_100            _SB_MAKE64(20)
 #define K_MAC_IFG_TX_1000           _SB_MAKE64(8)
 
-#define K_MAC_IFG_THRSH_10          _SB_MAKE64(12)
-#define K_MAC_IFG_THRSH_100         _SB_MAKE64(12)
-#define K_MAC_IFG_THRSH_1000        _SB_MAKE64(4)
+#define K_MAC_IFG_THRSH_10          _SB_MAKE64(4)
+#define K_MAC_IFG_THRSH_100         _SB_MAKE64(4)
+#define K_MAC_IFG_THRSH_1000        _SB_MAKE64(0)
 
 #define K_MAC_SLOT_SIZE_10          _SB_MAKE64(0)
 #define K_MAC_SLOT_SIZE_100         _SB_MAKE64(0)
@@ -317,9 +322,11 @@
 
 #define K_MAC_MIN_FRAMESZ_DEFAULT   _SB_MAKE64(64)
 #define K_MAC_MAX_FRAMESZ_DEFAULT   _SB_MAKE64(1518)
+#define K_MAC_MAX_FRAMESZ_JUMBO     _SB_MAKE64(9216)
 
 #define V_MAC_MIN_FRAMESZ_DEFAULT   V_MAC_MIN_FRAMESZ(K_MAC_MIN_FRAMESZ_DEFAULT)
 #define V_MAC_MAX_FRAMESZ_DEFAULT   V_MAC_MAX_FRAMESZ(K_MAC_MAX_FRAMESZ_DEFAULT)
+#define V_MAC_MAX_FRAMESZ_JUMBO     V_MAC_MAX_FRAMESZ(K_MAC_MAX_FRAMESZ_JUMBO)
 
 /*
  * MAC VLAN Tag Registers (Table 9-16)
@@ -341,7 +348,7 @@
  * Register: MAC_INT_MASK_2
  */
 
-/* 
+/*
  * Use these constants to shift the appropriate channel
  * into the CH0 position so the same tests can be used
  * on each channel.
@@ -378,6 +385,7 @@
 #define M_MAC_LTCOL_ERR             _SB_MAKEMASK1(44)
 #define M_MAC_EXCOL_ERR             _SB_MAKEMASK1(45)
 #define M_MAC_CNTR_OVRFL_ERR        _SB_MAKEMASK1(46)
+#define M_MAC_SPLIT_EN		    _SB_MAKEMASK1(47) 	/* interrupt mask only */ /* PASS2 */
 
 #define S_MAC_COUNTER_ADDR          _SB_MAKE64(47)
 #define M_MAC_COUNTER_ADDR          _SB_MAKEMASK(5,S_MAC_COUNTER_ADDR)
@@ -498,6 +506,7 @@
 #define M_MAC_MCAST_INV         _SB_MAKEMASK1(4)
 #define M_MAC_BCAST_EN          _SB_MAKEMASK1(5)
 #define M_MAC_DIRECT_INV        _SB_MAKEMASK1(6)
+#define M_MAC_ALLMCAST_EN	_SB_MAKEMASK1(7)	/* PASS2 */
 
 #define S_MAC_IPHDR_OFFSET      _SB_MAKE64(8)
 #define M_MAC_IPHDR_OFFSET      _SB_MAKEMASK(8,S_MAC_IPHDR_OFFSET)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/sb1250_mc.h linux-2.4.20/include/asm-mips/sibyte/sb1250_mc.h
--- linux-2.4.19/include/asm-mips/sibyte/sb1250_mc.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/sb1250_mc.h	2002-10-29 11:18:30.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
-    *  Memory Controller constants              File: sb1250_mc.h       
-    *  
+    *
+    *  Memory Controller constants              File: sb1250_mc.h
+    *
     *  This module contains constants and macros useful for
     *  programming the memory controller.
-    *  
-    *  SB1250 specification level:  0.2
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -166,7 +166,7 @@
 
 #define K_MC_REF_RATE_100MHz         0x62
 #define K_MC_REF_RATE_133MHz         0x81
-#define K_MC_REF_RATE_200MHz         0xC4 
+#define K_MC_REF_RATE_200MHz         0xC4
 
 #define V_MC_REF_RATE_100MHz         V_MC_REF_RATE(K_MC_REF_RATE_100MHz)
 #define V_MC_REF_RATE_133MHz         V_MC_REF_RATE(K_MC_REF_RATE_133MHz)
@@ -224,7 +224,7 @@
                                      V_MC_ADDR_DRIVE_DEFAULT | \
                                      V_MC_DATA_DRIVE_DEFAULT | \
                                      V_MC_CLOCK_DRIVE_DEFAULT | \
-                                     V_MC_REF_RATE_DEFAULT 
+                                     V_MC_REF_RATE_DEFAULT
 
 
 
@@ -298,69 +298,80 @@
  * SDRAM Timing Register  (Table 6-15)
  */
 
-#define M_MC_w2rIDLE_TWOCYCLES	  _SB_MAKEMASK1(62)
+#define M_MC_w2rIDLE_TWOCYCLES	  _SB_MAKEMASK1(60)
 #define M_MC_r2wIDLE_TWOCYCLES	  _SB_MAKEMASK1(61)
-#define M_MC_r2rIDLE_TWOCYCLES	  _SB_MAKEMASK1(60)
+#define M_MC_r2rIDLE_TWOCYCLES	  _SB_MAKEMASK1(62)
 
 #define S_MC_tFIFO                56
 #define M_MC_tFIFO                _SB_MAKEMASK(4,S_MC_tFIFO)
 #define V_MC_tFIFO(x)             _SB_MAKEVALUE(x,S_MC_tFIFO)
+#define G_MC_tFIFO(x)             _SB_GETVALUE(x,S_MC_tFIFO,M_MC_tFIFO)
 #define K_MC_tFIFO_DEFAULT        1
 #define V_MC_tFIFO_DEFAULT        V_MC_tFIFO(K_MC_tFIFO_DEFAULT)
 
 #define S_MC_tRFC                 52
 #define M_MC_tRFC                 _SB_MAKEMASK(4,S_MC_tRFC)
 #define V_MC_tRFC(x)              _SB_MAKEVALUE(x,S_MC_tRFC)
+#define G_MC_tRFC(x)              _SB_GETVALUE(x,S_MC_tRFC,M_MC_tRFC)
 #define K_MC_tRFC_DEFAULT         12
 #define V_MC_tRFC_DEFAULT         V_MC_tRFC(K_MC_tRFC_DEFAULT)
 
 #define S_MC_tCwCr                40
 #define M_MC_tCwCr                _SB_MAKEMASK(4,S_MC_tCwCr)
 #define V_MC_tCwCr(x)             _SB_MAKEVALUE(x,S_MC_tCwCr)
+#define G_MC_tCwCr(x)             _SB_GETVALUE(x,S_MC_tCwCr,M_MC_tCwCr)
 #define K_MC_tCwCr_DEFAULT        4
 #define V_MC_tCwCr_DEFAULT        V_MC_tCwCr(K_MC_tCwCr_DEFAULT)
 
 #define S_MC_tRCr                 28
 #define M_MC_tRCr                 _SB_MAKEMASK(4,S_MC_tRCr)
 #define V_MC_tRCr(x)              _SB_MAKEVALUE(x,S_MC_tRCr)
+#define G_MC_tRCr(x)              _SB_GETVALUE(x,S_MC_tRCr,M_MC_tRCr)
 #define K_MC_tRCr_DEFAULT         9
 #define V_MC_tRCr_DEFAULT         V_MC_tRCr(K_MC_tRCr_DEFAULT)
 
 #define S_MC_tRCw                 24
 #define M_MC_tRCw                 _SB_MAKEMASK(4,S_MC_tRCw)
 #define V_MC_tRCw(x)              _SB_MAKEVALUE(x,S_MC_tRCw)
+#define G_MC_tRCw(x)              _SB_GETVALUE(x,S_MC_tRCw,M_MC_tRCw)
 #define K_MC_tRCw_DEFAULT         10
 #define V_MC_tRCw_DEFAULT         V_MC_tRCw(K_MC_tRCw_DEFAULT)
 
 #define S_MC_tRRD                 20
 #define M_MC_tRRD                 _SB_MAKEMASK(4,S_MC_tRRD)
 #define V_MC_tRRD(x)              _SB_MAKEVALUE(x,S_MC_tRRD)
+#define G_MC_tRRD(x)              _SB_GETVALUE(x,S_MC_tRRD,M_MC_tRRD)
 #define K_MC_tRRD_DEFAULT         2
 #define V_MC_tRRD_DEFAULT         V_MC_tRRD(K_MC_tRRD_DEFAULT)
 
 #define S_MC_tRP                  16
 #define M_MC_tRP                  _SB_MAKEMASK(4,S_MC_tRP)
 #define V_MC_tRP(x)               _SB_MAKEVALUE(x,S_MC_tRP)
+#define G_MC_tRP(x)               _SB_GETVALUE(x,S_MC_tRP,M_MC_tRP)
 #define K_MC_tRP_DEFAULT          4
 #define V_MC_tRP_DEFAULT          V_MC_tRP(K_MC_tRP_DEFAULT)
 
 #define S_MC_tCwD                 8
 #define M_MC_tCwD                 _SB_MAKEMASK(4,S_MC_tCwD)
 #define V_MC_tCwD(x)              _SB_MAKEVALUE(x,S_MC_tCwD)
+#define G_MC_tCwD(x)              _SB_GETVALUE(x,S_MC_tCwD,M_MC_tCwD)
 #define K_MC_tCwD_DEFAULT         1
 #define V_MC_tCwD_DEFAULT         V_MC_tCwD(K_MC_tCwD_DEFAULT)
 
 #define M_tCrDh                   _SB_MAKEMASK1(7)
+#define M_MC_tCrDh		  M_tCrDh
 
 #define S_MC_tCrD                 4
 #define M_MC_tCrD                 _SB_MAKEMASK(3,S_MC_tCrD)
 #define V_MC_tCrD(x)              _SB_MAKEVALUE(x,S_MC_tCrD)
+#define G_MC_tCrD(x)              _SB_GETVALUE(x,S_MC_tCrD,M_MC_tCrD)
 #define K_MC_tCrD_DEFAULT         2
 #define V_MC_tCrD_DEFAULT         V_MC_tCrD(K_MC_tCrD_DEFAULT)
 
 #define S_MC_tRCD                 0
 #define M_MC_tRCD                 _SB_MAKEMASK(4,S_MC_tRCD)
 #define V_MC_tRCD(x)              _SB_MAKEVALUE(x,S_MC_tRCD)
+#define G_MC_tRCD(x)              _SB_GETVALUE(x,S_MC_tRCD,M_MC_tRCD)
 #define K_MC_tRCD_DEFAULT         3
 #define V_MC_tRCD_DEFAULT         V_MC_tRCD(K_MC_tRCD_DEFAULT)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/sb1250_pci.h linux-2.4.20/include/asm-mips/sibyte/sb1250_pci.h
--- linux-2.4.19/include/asm-mips/sibyte/sb1250_pci.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/sb1250_pci.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,250 +0,0 @@
-/*  *********************************************************************
-    *  SB1250 Board Support Package
-    *  
-    *  PCI constants				File: sb1250_pci.h
-    *  
-    *  This module contains constants and macros to describe 
-    *  the PCI interface on the SB1250.  
-    *  
-    *  SB1250 specification level:  0.2
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
-    *
-    *  Copyright 2000,2001
-    *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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
-    ********************************************************************* */
-
-
-#ifndef _SB1250_PCI_H
-#define _SB1250_PCI_H
-
-#include "sb1250_defs.h"
-
-#define K_PCI_VENDOR_SIBYTE	0x166D
-#define K_PCI_DEVICE_SB1250	0x0001
-
-/*
- * PCI Interface Type 0 configuration header
- */
-
-#define R_PCI_TYPE0_DEVICEID	0x0000
-#define R_PCI_TYPE0_CMDSTATUS	0x0004
-#define R_PCI_TYPE0_CLASSREV	0x0008
-#define R_PCI_TYPE0_DEVHDR	0x000C
-#define R_PCI_TYPE0_BAR0	0x0010	/* translated via mapping table */
-#define R_PCI_TYPE0_BAR1	0x0014	/* reserved */
-#define R_PCI_TYPE0_BAR2	0x0018	/* mbox 0 */
-#define R_PCI_TYPE0_BAR3	0x001C	/* mbox 1 */
-#define R_PCI_TYPE0_BAR4	0x0020	/* low memory */
-#define R_PCI_TYPE0_BAR5	0x0024	/* high memory */
-#define R_PCI_TYPE0_CARDBUSCIS	0x0028
-#define R_PCI_TYPE0_SUBSYSID	0x002C
-#define R_PCI_TYPE0_ROMBASE	0x0030
-#define R_PCI_TYPE0_CAPPTR	0x0034	/* not used */
-#define R_PCI_TYPE0_RESERVED1	0x0038
-#define R_PCI_TYPE0_INTGRANT	0x003C	/* interrupt pin and grant latency */
-#define R_PCI_TYPE0_TIMEOUT	0x0040	/* FControl, Timeout */
-#define R_PCI_TYPE0_FCONTROL	0x0040	/* FControl, Timeout */
-#define R_PCI_TYPE0_MAPBASE	0x0044	/* 0x44 through 0x80 - map table */
-#define PCI_TYPE0_MAPENTRIES	32	/* 64 bytes, 32 entries */
-#define R_PCI_TYPE0_ERRORADDR	0x0084
-#define R_PCI_TYPE0_ADDSTATUS	0x0088
-#define R_PCI_TYPE0_SUBSYSSET	0x008C	/* only accessible from ZBBus */
-
-/*
- * PCI Device ID register
- */
-
-#define S_PCI_DEVICEID_VENDOR		0
-#define M_PCI_DEVICEID_VENDOR		_SB_MAKEMASK_32(16,S_PCI_DEVICEID_VENDOR)
-#define V_PCI_DEVICEID_VENDOR(x)	_SB_MAKEVALUE_32(x,S_PCI_DEVICEID_VENDOR)
-#define G_PCI_DEVICEID_VENDOR(x)	_SB_GETVALUE_32(x,S_PCI_DEVICEID_VENDOR,M_PCI_DEVICEID_VENDOR)
-
-#define S_PCI_DEVICEID_DEVICEID		16
-#define M_PCI_DEVICEID_DEVICEID		_SB_MAKEMASK_32(16,S_PCI_DEVICEID_DEVICEID)
-#define V_PCI_DEVICEID_DEVICEID(x)	_SB_MAKEVALUE_32(x,S_PCI_DEVICEID_DEVICEID)
-#define G_PCI_DEVICEID_DEVICEID(x)	_SB_GETVALUE_32(x,S_PCI_DEVICEID_DEVICEID,M_PCI_DEVICEID_DEVICEID)
-
-
-/*
- * PCI Command Register (Table 8-4)
- */
-
-#define M_PCI_CMD_IOSPACE_EN		_SB_MAKEMASK1_32(0)
-#define M_PCI_CMD_MEMSPACE_EN		_SB_MAKEMASK1_32(1)
-#define M_PCI_CMD_MASTER_EN		_SB_MAKEMASK1_32(2)
-#define M_PCI_CMD_SPECCYC_EN		_SB_MAKEMASK1_32(3)
-#define M_PCI_CMD_MEMWRINV_EN		_SB_MAKEMASK1_32(4)
-#define M_PCI_CMD_VGAPALSNP_EN		_SB_MAKEMASK1_32(5)
-#define M_PCI_CMD_PARERRRESP		_SB_MAKEMASK1_32(6)
-#define M_PCI_CMD_STEPCTRL		_SB_MAKEMASK1_32(7)
-#define M_PCI_CMD_SERR_EN		_SB_MAKEMASK1_32(8)
-#define M_PCI_CMD_FASTB2B_EN		_SB_MAKEMASK1_32(9)
-
-/*
- * PCI class and revision registers
- */
-
-#define S_PCI_CLASSREV_REV		0
-#define M_PCI_CLASSREV_REV		_SB_MAKEMASK_32(8,S_PCI_CLASSREV_REV)
-#define V_PCI_CLASSREV_REV(x)		_SB_MAKEVALUE_32(x,S_PCI_CLASSREV_REV)
-#define G_PCI_CLASSREV_REV(x)		_SB_GETVALUE_32(x,S_PCI_CLASSREV_REV,M_PCI_CLASSREV_REV)
-
-#define S_PCI_CLASSREV_CLASS		8
-#define M_PCI_CLASSREV_CLASS		_SB_MAKEMASK_32(24,S_PCI_CLASSREV_CLASS)
-#define V_PCI_CLASSREV_CLASS(x)		_SB_MAKEVALUE_32(x,S_PCI_CLASSREV_CLASS)
-#define G_PCI_CLASSREV_CLASS(x)		_SB_GETVALUE_32(x,S_PCI_CLASSREV_CLASS,M_PCI_CLASSREV_CLASS)
-
-#define K_PCI_REV			0x01
-#define K_PCI_CLASS			0x060000
-
-/*
- * Device Header (offset 0x0C)
- */
-
-#define S_PCI_DEVHDR_CLINESZ		0
-#define M_PCI_DEVHDR_CLINESZ		_SB_MAKEMASK_32(8,S_PCI_DEVHDR_CLINESZ)
-#define V_PCI_DEVHDR_CLINESZ(x)		_SB_MAKEVALUE_32(x,S_PCI_DEVHDR_CLINESZ)
-#define G_PCI_DEVHDR_CLINESZ(x)		_SB_GETVALUE_32(x,S_PCI_DEVHDR_CLINESZ,M_PCI_DEVHDR_CLINESZ)
-
-#define S_PCI_DEVHDR_LATTMR		8
-#define M_PCI_DEVHDR_LATTMR		_SB_MAKEMASK_32(8,S_PCI_DEVHDR_LATTMR)
-#define V_PCI_DEVHDR_LATTMR(x)		_SB_MAKEVALUE_32(x,S_PCI_DEVHDR_LATTMR)
-#define G_PCI_DEVHDR_LATTMR(x)		_SB_GETVALUE_32(x,S_PCI_DEVHDR_LATTMR,M_PCI_DEVHDR_LATTMR)
-
-#define S_PCI_DEVHDR_HDRTYPE		16
-#define M_PCI_DEVHDR_HDRTYPE		_SB_MAKEMASK_32(8,S_PCI_DEVHDR_HDRTYPE)
-#define V_PCI_DEVHDR_HDRTYPE(x)		_SB_MAKEVALUE_32(x,S_PCI_DEVHDR_HDRTYPE)
-#define G_PCI_DEVHDR_HDRTYPE(x)		_SB_GETVALUE_32(x,S_PCI_DEVHDR_HDRTYPE,M_PCI_DEVHDR_HDRTYPE)
-
-#define K_PCI_DEVHDR_HDRTYPE_TYPE0	0
-
-#define S_PCI_DEVHDR_BIST		24
-#define M_PCI_DEVHDR_BIST		_SB_MAKEMASK_32(8,S_PCI_DEVHDR_BIST)
-#define V_PCI_DEVHDR_BIST(x)		_SB_MAKEVALUE_32(x,S_PCI_DEVHDR_BIST)
-#define G_PCI_DEVHDR_BIST(x)		_SB_GETVALUE_32(x,S_PCI_DEVHDR_BIST,M_PCI_DEVHDR_BIST)
-
-/*
- * PCI Status Register (Table 8-5).  Note that these constants
- * assume you've read the command and status register 
- * together (32-bit read at offset 0x04)
- */
-
-#define M_PCI_STATUS_CAPLIST		_SB_MAKEMASK1_32(20)
-#define M_PCI_STATUS_66MHZCAP		_SB_MAKEMASK1_32(21)
-#define M_PCI_STATUS_RESERVED2		_SB_MAKEMASK1_32(22)
-#define M_PCI_STATUS_FASTB2BCAP		_SB_MAKEMASK1_32(23)
-#define M_PCI_STATUS_MSTRDPARERR	_SB_MAKEMASK1_32(24)
-
-#define S_PCI_STATUS_DEVSELTIMING	25
-#define M_PCI_STATUS_DEVSELTIMING	_SB_MAKEMASK_32(2,S_PCI_STATUS_DEVSELTIMING)
-#define V_PCI_STATUS_DEVSELTIMING(x)	_SB_MAKEVALUE_32(x,S_PCI_STATUS_DEVSELTIMING)
-#define G_PCI_STATUS_DEVSELTIMING(x)	_SB_GETVALUE_32(x,S_PCI_STATUS_DEVSELTIMING,M_PCI_STATUS_DEVSELTIMING)
-
-#define M_PCI_STATUS_SIGDTGTABORT	_SB_MAKEMASK1_32(27)
-#define M_PCI_STATUS_RCVDTGTABORT	_SB_MAKEMASK1_32(28)
-#define M_PCI_STATUS_RCVDMSTRABORT	_SB_MAKEMASK1_32(29)
-#define M_PCI_STATUS_SIGDSERR		_SB_MAKEMASK1_32(30)
-#define M_PCI_STATUS_DETPARERR		_SB_MAKEMASK1_32(31)
-
-/*
- * Device Header Register (Table 8-6, Table 8-7)
- */
-
-#define S_PCI_DEVHDR_CLINESZ		0
-#define M_PCI_DEVHDR_CLINESZ		_SB_MAKEMASK_32(8,S_PCI_DEVHDR_CLINESZ)
-#define V_PCI_DEVHDR_CLINESZ(x)		_SB_MAKEVALUE_32(x,S_PCI_DEVHDR_CLINESZ)
-#define G_PCI_DEVHDR_CLINESZ(x)		_SB_GETVALUE_32(x,S_PCI_DEVHDR_CLINESZ,M_PCI_DEVHDR_CLINESZ)
-
-#define S_PCI_DEVHDR_LATTIME		8
-#define M_PCI_DEVHDR_LATTIME		_SB_MAKEMASK_32(8,S_PCI_DEVHDR_LATTIME)
-#define V_PCI_DEVHDR_LATTIME(x)		_SB_MAKEVALUE_32(x,S_PCI_DEVHDR_LATTIME)
-#define G_PCI_DEVHDR_LATTIME(x)		_SB_GETVALUE_32(x,S_PCI_DEVHDR_LATTIME,M_PCI_DEVHDR_LATTIME)
-
-#define S_PCI_DEVHDR_HDRTYPE		16
-#define M_PCI_DEVHDR_HDRTYPE		_SB_MAKEMASK_32(8,S_PCI_DEVHDR_HDRTYPE)
-#define V_PCI_DEVHDR_HDRTYPE(x)		_SB_MAKEVALUE_32(x,S_PCI_DEVHDR_HDRTYPE)
-#define G_PCI_DEVHDR_HDRTYPE(x)		_SB_GETVALUE_32(x,S_PCI_DEVHDR_HDRTYPE,M_PCI_DEVHDR_HDRTYPE)
-
-#define S_PCI_DEVHDR_BIST		24
-#define M_PCI_DEVHDR_BIST		_SB_MAKEMASK_32(8,S_PCI_DEVHDR_BIST)
-#define V_PCI_DEVHDR_BIST(x)		_SB_MAKEVALUE_32(x,S_PCI_DEVHDR_BIST)
-#define G_PCI_DEVHDR_BIST(x)		_SB_GETVALUE_32(x,S_PCI_DEVHDR_BIST,M_PCI_DEVHDR_BIST)
-
-/*
- * Timeout and feature control Register (Table 8-8) (Table 8-9)
- * Note that these constants assume you've read the timeout/fcontrol register
- * together (32-bit read at offset 0x40)
- */
-
-#define S_PCI_TIMEOUT_TRDY		0
-#define M_PCI_TIMEOUT_TRDY		_SB_MAKEMASK_32(8,S_PCI_TIMEOUT_TRDY)
-#define V_PCI_TIMEOUT_TRDY(x)		_SB_MAKEVALUE_32(x,S_PCI_TIMEOUT_TRDY)
-#define G_PCI_TIMEOUT_TRDY(x)		_SB_GETVALUE_32(x,S_PCI_TIMEOUT_TRDY,M_PCI_TIMEOUT_TRDY)
-
-#define S_PCI_TIMEOUT_RETRY		8
-#define M_PCI_TIMEOUT_RETRY		_SB_MAKEMASK_32(8,S_PCI_TIMEOUT_RETRY)
-#define V_PCI_TIMEOUT_RETRY(x)		_SB_MAKEVALUE_32(x,S_PCI_TIMEOUT_RETRY)
-#define G_PCI_TIMEOUT_RETRY(x)		_SB_GETVALUE_32(x,S_PCI_TIMEOUT_RETRY,M_PCI_TIMEOUT_RETRY)
-
-#define M_PCI_FCONTROL_BAR4_EN		_SB_MAKEMASK1_32(16)
-#define M_PCI_FCONTROL_BAR5_EN		_SB_MAKEMASK1_32(17)
-#define M_PCI_FCONTROL_PTP_EN		_SB_MAKEMASK1_32(18)
-#define M_PCI_FCONTROL_ADAPT_RETRY_EN	_SB_MAKEMASK1_32(19)
-
-#define S_PCI_FCONTROL_MIN_TAR_RETRY	20
-#define M_PCI_FCONTROL_MIN_TAR_RETRY	_SB_MAKEMASK_32(3,S_PCI_FCONTROL_MIN_TAR_RETRY)
-#define V_PCI_FCONTROL_MIN_TAR_RETRY(x)	_SB_MAKEVALUE_32(x,S_PCI_FCONTROL_MIN_TAR_RETRY)
-#define G_PCI_FCONTROL_MIN_TAR_RETRY(x)	_SB_GETVALUE_32(x,S_PCI_FCONTROL_MIN_TAR_RETRY,M_PCI_FCONTROL_MIN_TAR_RETRY)
-
-#define S_PCI_FCONTROL_NOM_TAR_RETRY	23
-#define M_PCI_FCONTROL_NOM_TAR_RETRY	_SB_MAKEMASK_32(4,S_PCI_FCONTROL_NOM_TAR_RETRY)
-#define V_PCI_FCONTROL_NOM_TAR_RETRY(x)	_SB_MAKEVALUE_32(x,S_PCI_FCONTROL_NOM_TAR_RETRY)
-#define G_PCI_FCONTROL_NOM_TAR_RETRY(x)	_SB_GETVALUE_32(x,S_PCI_FCONTROL_NOM_TAR_RETRY,M_PCI_FCONTROL_NOM_TAR_RETRY)
-
-#define S_PCI_FCONTROL_MAX_TAR_RETRY	27
-#define M_PCI_FCONTROL_MAX_TAR_RETRY	_SB_MAKEMASK_32(5,S_PCI_FCONTROL_MAX_TAR_RETRY)
-#define V_PCI_FCONTROL_MAX_TAR_RETRY(x)	_SB_MAKEVALUE_32(x,S_PCI_FCONTROL_MAX_TAR_RETRY)
-#define G_PCI_FCONTROL_MAX_TAR_RETRY(x)	_SB_GETVALUE_32(x,S_PCI_FCONTROL_MAX_TAR_RETRY,M_PCI_FCONTROL_MAX_TAR_RETRY)
-
-/*
- * BAR0 Map Table Entry (Offsets 0x40-0x80) (Table 8-10)
- */
-
-#define M_PCI_BAR0MAP_ENABLE		_SB_MAKEMASK1_32(0)
-#define M_PCI_BAR0MAP_SENDLDT		_SB_MAKEMASK1_32(1)
-#define S_PCI_BAR0MAP_ADDR		12
-#define M_PCI_BAR0MAP_ADDR		_SB_MAKEMASK_32(20,S_PCI_BAR0MAP_ADDR)
-
-/*
- * Additional Status Register (Table 8-11)
- */
-
-#define M_PCI_ASTATUS_HOTPLUG_EN	_SB_MAKEMASK1_32(0)
-#define M_PCI_ASTATUS_SERR_DET		_SB_MAKEMASK1_32(1)
-#define M_PCI_ASTATUS_TRDYERR		_SB_MAKEMASK1_32(2)
-#define M_PCI_ASTATUS_RETRTYERR		_SB_MAKEMASK1_32(3)
-#define M_PCI_ASTATUS_TRDYINTMASK	_SB_MAKEMASK1_32(4)
-#define M_PCI_ASTATUS_RETRYINTMASK	_SB_MAKEMASK1_32(5)
-#define M_PCI_ASTATUS_SIGNALINTA	_SB_MAKEMASK1_32(6)
-
-#endif
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/sb1250_prof.h linux-2.4.20/include/asm-mips/sibyte/sb1250_prof.h
--- linux-2.4.19/include/asm-mips/sibyte/sb1250_prof.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/sb1250_prof.h	2002-10-29 11:18:33.000000000 +0000
@@ -10,7 +10,7 @@
  * 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.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/sb1250_regs.h linux-2.4.20/include/asm-mips/sibyte/sb1250_regs.h
--- linux-2.4.19/include/asm-mips/sibyte/sb1250_regs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/sb1250_regs.h	2002-10-29 11:18:49.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  Register Definitions                     File: sb1250_regs.h
-    *  
+    *
     *  This module contains the addresses of the on-chip peripherals
     *  on the SB1250.
-    *  
-    *  SB1250 specification level:  0.2
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  01/02/2002
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -40,20 +40,20 @@
 
 /*  *********************************************************************
     *  Some general notes:
-    *  
+    *
     *  For the most part, when there is more than one peripheral
     *  of the same type on the SOC, the constants below will be
     *  offsets from the base of each peripheral.  For example,
     *  the MAC registers are described as offsets from the first
     *  MAC register, and there will be a MAC_REGISTER() macro
-    *  to calculate the base address of a given MAC.  
-    *  
+    *  to calculate the base address of a given MAC.
+    *
     *  The information in this file is based on the SB1250 SOC
     *  manual version 0.2, July 2000.
     ********************************************************************* */
 
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * Memory Controller Registers
     ********************************************************************* */
 
@@ -97,7 +97,7 @@
 #define R_MC_TEST_ECC               0x0000000420
 #define R_MC_MCLK_CFG               0x0000000500
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * L2 Cache Control Registers
     ********************************************************************* */
 
@@ -107,7 +107,12 @@
 #define A_L2_MAKEDISABLE(x)         (A_L2_WAY_DISABLE | (((~(x))&0x0F) << 8))
 #define A_L2_MGMT_TAG_BASE          0x00D0000000
 
-/*  ********************************************************************* 
+#define A_L2_CACHE_DISABLE	   0x0010042000	/* PASS2 */
+#define A_L2_MAKECACHEDISABLE(x)   (A_L2_CACHE_DISABLE | (((x)&0x0F) << 8))	/* PASS2 */
+#define A_L2_MISC_CONFIG	   0x0010043000	/* PASS2 */
+
+
+/*  *********************************************************************
     * PCI Interface Registers
     ********************************************************************* */
 
@@ -115,7 +120,7 @@
 #define A_PCI_TYPE01_HEADER         0x00DE000800
 
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * Ethernet DMA and MACs
     ********************************************************************* */
 
@@ -162,7 +167,7 @@
             (R_MAC_DMA_CHANNEL_BASE(txrx,chan) +    \
             (reg))
 
-/* 
+/*
  * DMA channel registers, relative to A_MAC_DMA_CHANNEL_BASE
  */
 
@@ -220,6 +225,7 @@
 #define R_MAC_INT_MASK                  0x00000410
 #define R_MAC_TXD_CTL                   0x00000420
 #define R_MAC_MDIO                      0x00000428
+#define R_MAC_STATUS1		        0x00000430	/* PASS2 */
 #define R_MAC_DEBUG_STATUS              0x00000448
 
 #define MAC_HASH_COUNT			8
@@ -227,7 +233,7 @@
 #define MAC_CHMAP_COUNT			4
 
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * DUART Registers
     ********************************************************************* */
 
@@ -250,6 +256,11 @@
 #define R_DUART_RX_HOLD             0x160
 #define R_DUART_TX_HOLD             0x170
 
+#define R_DUART_FULL_CTL	    0x140	/* PASS2 */
+#define R_DUART_OPCR_X		    0x180	/* PASS2 */
+#define R_DUART_AUXCTL_X	    0x190	/* PASS2 */
+
+
 /*
  * The IMR and ISR can't be addressed with A_DUART_CHANREG,
  * so use this macro instead.
@@ -310,7 +321,16 @@
 #define A_DUART_INPORT_CHNG_A       0x00100603D0
 #define A_DUART_INPORT_CHNG_B       0x00100603E0
 
-/*  ********************************************************************* 
+#define A_DUART_FULL_CTL_A	    0x0010060140	/* PASS2 */
+#define A_DUART_FULL_CTL_B	    0x0010060240	/* PASS2 */
+
+#define A_DUART_OPCR_A	  	    0x0010060180	/* PASS2 */
+#define A_DUART_OPCR_B	  	    0x0010060280	/* PASS2 */
+
+#define A_DUART_INPORT_CHNG_DEBUG   0x00100603F0	/* PASS2 */
+
+
+/*  *********************************************************************
     * Synchronous Serial Registers
     ********************************************************************* */
 
@@ -344,7 +364,7 @@
             (reg))
 
 
-/* 
+/*
  * DMA channel registers, relative to A_SER_DMA_CHANNEL_BASE
  */
 
@@ -404,7 +424,7 @@
 #define R_SER_RMON_RX_ERRORS        0x000001F0
 #define R_SER_RMON_RX_BADADDR       0x000001F8
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * Generic Bus Registers
     ********************************************************************* */
 
@@ -456,7 +476,7 @@
 #define R_IO_PCMCIA_CFG             0x0A60
 #define R_IO_PCMCIA_STATUS          0x0A70
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * GPIO Registers
     ********************************************************************* */
 
@@ -480,7 +500,7 @@
 #define R_GPIO_PIN_CLR              0x30
 #define R_GPIO_PIN_SET              0x38
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * SMBus Registers
     ********************************************************************* */
 
@@ -516,7 +536,7 @@
 #define R_SMB_CONTROL               0x0000000060
 #define R_SMB_PEC                   0x0000000070
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * Timer Registers
     ********************************************************************* */
 
@@ -575,16 +595,21 @@
 #define A_SCD_TIMER_CNT_3           0x0010020188
 #define A_SCD_TIMER_CFG_3           0x0010020198
 
-/*  ********************************************************************* 
+#define A_SCD_SCRATCH		   0x0010020C10		/* PASS2 */
+
+#define A_SCD_ZBBUS_CYCLE_COUNT	   0x0010030000		/* PASS2 */
+#define A_SCD_ZBBUS_CYCLE_CP0	   0x0010020C00		/* PASS2 */
+#define A_SCD_ZBBUS_CYCLE_CP1	   0x0010020C08		/* PASS2 */
+
+
+/*  *********************************************************************
     * System Control Registers
     ********************************************************************* */
 
 #define A_SCD_SYSTEM_REVISION       0x0010020000
 #define A_SCD_SYSTEM_CFG            0x0010020008
 
-#define A_SCD_SCRATCH		    0x0010020C10	/* PASS2 */
-
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Address Trap Registers
     ********************************************************************* */
 
@@ -602,9 +627,10 @@
 #define A_ADDR_TRAP_CFG_1           0x0010020448
 #define A_ADDR_TRAP_CFG_2           0x0010020450
 #define A_ADDR_TRAP_CFG_3           0x0010020458
+#define A_ADDR_TRAP_REG_DEBUG	    0x0010020460	/* PASS2 */
 
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Interrupt Mapper Registers
     ********************************************************************* */
 
@@ -632,7 +658,7 @@
 #define R_IMR_INTERRUPT_MAP_BASE        0x0200
 #define R_IMR_INTERRUPT_MAP_COUNT       64
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Performance Counter Registers
     ********************************************************************* */
 
@@ -642,11 +668,12 @@
 #define A_SCD_PERF_CNT_2            0x00100204E0
 #define A_SCD_PERF_CNT_3            0x00100204E8
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Bus Watcher Registers
     ********************************************************************* */
 
 #define A_SCD_BUS_ERR_STATUS        0x0010020880
+#define A_SCD_BUS_ERR_STATUS_DEBUG  0x00100208D0	/* PASS2 */
 #define A_BUS_ERR_DATA_0            0x00100208A0
 #define A_BUS_ERR_DATA_1            0x00100208A8
 #define A_BUS_ERR_DATA_2            0x00100208B0
@@ -654,13 +681,13 @@
 #define A_BUS_L2_ERRORS             0x00100208C0
 #define A_BUS_MEM_IO_ERRORS         0x00100208C8
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Debug Controller Registers
     ********************************************************************* */
 
 #define A_SCD_JTAG_BASE             0x0010000000
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Trace Buffer Registers
     ********************************************************************* */
 
@@ -683,7 +710,7 @@
 #define A_SCD_TRACE_SEQUENCE_6      0x0010020A90
 #define A_SCD_TRACE_SEQUENCE_7      0x0010020A98
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Generic DMA Registers
     ********************************************************************* */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/sb1250_scd.h linux-2.4.20/include/asm-mips/sibyte/sb1250_scd.h
--- linux-2.4.19/include/asm-mips/sibyte/sb1250_scd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/sb1250_scd.h	2002-10-29 11:18:37.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  SCD Constants and Macros			File: sb1250_scd.h
-    *  
+    *
     *  This module contains constants and macros useful for
     *  manipulating the System Control and Debug module on the 1250.
-    *  
-    *  SB1250 specification level:  0.2  plus errata as of 11/7/2000
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -53,7 +53,8 @@
 
 #define K_SYS_REVISION_PASS1	    1
 #define K_SYS_REVISION_PASS2	    3
-#define K_SYS_REVISION_PASS3	    4 /* XXX Unknown */
+#define K_SYS_REVISION_PASS2_2	    16
+#define K_SYS_REVISION_PASS3	    32
 
 #define S_SYS_PART                  _SB_MAKE64(16)
 #define M_SYS_PART                  _SB_MAKEMASK(16,S_SYS_PART)
@@ -61,7 +62,7 @@
 #define G_SYS_PART(x)               _SB_GETVALUE(x,S_SYS_PART,M_SYS_PART)
 
 #define K_SYS_PART_SB1250           0x1250
-#define K_SYS_PART_SB1125           0x1125 
+#define K_SYS_PART_SB1125           0x1125
 
 #define S_SYS_WID                   _SB_MAKE64(32)
 #define M_SYS_WID                   _SB_MAKEMASK(32,S_SYS_WID)
@@ -153,6 +154,9 @@
 #define M_SYS_MISR_MODE             _SB_MAKEMASK1(61)
 #define M_SYS_MISR_RESET            _SB_MAKEMASK1(62)
 
+#define M_SYS_SW_FLAG		    _SB_MAKEMASK1(63)	/* PASS2 */
+
+
 /*
  * Mailbox Registers (Table 4-3)
  * Registers: SCD_MBOX_CPU_x
@@ -346,6 +350,7 @@
 #define M_SCD_TRACE_CFG_FREEZE_FULL     _SB_MAKEMASK1(5)
 #define M_SCD_TRACE_CFG_DEBUG_FULL      _SB_MAKEMASK1(6)
 #define M_SCD_TRACE_CFG_FULL            _SB_MAKEMASK1(7)
+#define M_SCD_TRACE_CFG_FORCECNT        _SB_MAKEMASK1(8)	/* PASS2 */
 
 #define S_SCD_TRACE_CFG_CUR_ADDR        10
 #define M_SCD_TRACE_CFG_CUR_ADDR        _SB_MAKEMASK(8,S_SCD_TRACE_CFG_CUR_ADDR)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/sb1250_smbus.h linux-2.4.20/include/asm-mips/sibyte/sb1250_smbus.h
--- linux-2.4.19/include/asm-mips/sibyte/sb1250_smbus.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/sb1250_smbus.h	2002-10-29 11:18:36.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  SMBUS Constants                          File: sb1250_smbus.h
-    *  
-    *  This module contains constants and macros useful for 
+    *
+    *  This module contains constants and macros useful for
     *  manipulating the SB1250's SMbus devices.
-    *  
-    *  SB1250 specification level:  0.2
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  01/02/2002
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -131,4 +131,44 @@
 #define M_SPEC_PEC                  _SB_MAKEMASK(8,S_SPEC_PEC)
 #define V_SPEC_MB(x)                _SB_MAKEVALUE(x,S_SPEC_PEC)
 
+
+/*  *********************************************************************
+    *  PASS2 Extensions to SMBus
+    ********************************************************************* */
+
+/* BEGIN PASS2 */
+
+#define S_SMB_CMDH                  8
+#define M_SMB_CMDH                  _SB_MAKEMASK(8,S_SMBH_CMD)
+#define V_SMB_CMDH(x)               _SB_MAKEVALUE(x,S_SMBH_CMD)
+
+#define M_SMB_EXTEND		    _SB_MAKEMASK1(14)
+
+#define M_SMB_DIR		    _SB_MAKEMASK1(13)
+
+#define S_SMB_DFMT                  8
+#define M_SMB_DFMT                  _SB_MAKEMASK(3,S_SMB_DFMT)
+#define V_SMB_DFMT(x)               _SB_MAKEVALUE(x,S_SMB_DFMT)
+#define G_SMB_DFMT(x)               _SB_GETVALUE(x,S_SMB_DFMT,M_SMB_DFMT)
+
+#define K_SMB_DFMT_1BYTE            0
+#define K_SMB_DFMT_2BYTE            1
+#define K_SMB_DFMT_3BYTE            2
+#define K_SMB_DFMT_4BYTE            3
+#define K_SMB_DFMT_NODATA           4
+#define K_SMB_DFMT_CMD4BYTE         5
+#define K_SMB_DFMT_CMD5BYTE         6
+#define K_SMB_DFMT_RESERVED         7
+
+#define V_SMB_DFMT_1BYTE	    V_SMB_DFMT(K_SMB_DFMT_1BYTE)
+#define V_SMB_DFMT_2BYTE	    V_SMB_DFMT(K_SMB_DFMT_2BYTE)
+#define V_SMB_DFMT_3BYTE	    V_SMB_DFMT(K_SMB_DFMT_3BYTE)
+#define V_SMB_DFMT_4BYTE	    V_SMB_DFMT(K_SMB_DFMT_4BYTE)
+#define V_SMB_DFMT_NODATA	    V_SMB_DFMT(K_SMB_DFMT_NODATA)
+#define V_SMB_DFMT_CMD4BYTE	    V_SMB_DFMT(K_SMB_DFMT_CMD4BYTE)
+#define V_SMB_DFMT_CMD5BYTE	    V_SMB_DFMT(K_SMB_DFMT_CMD5BYTE)
+#define V_SMB_DFMT_RESERVED	    V_SMB_DFMT(K_SMB_DFMT_RESERVED)
+
+/* END PASS2 */
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/sb1250_syncser.h linux-2.4.20/include/asm-mips/sibyte/sb1250_syncser.h
--- linux-2.4.19/include/asm-mips/sibyte/sb1250_syncser.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/sb1250_syncser.h	2002-10-29 11:18:48.000000000 +0000
@@ -6,18 +6,18 @@
     *  This module contains constants and macros useful for
     *  manipulating the SB1250's Synchronous Serial
     *
-    *  SB1250 specification level:  0.2
+    *  SB1250 specification level:  User's manual 1/02/02
     *
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
     *
     *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/sb1250_uart.h linux-2.4.20/include/asm-mips/sibyte/sb1250_uart.h
--- linux-2.4.19/include/asm-mips/sibyte/sb1250_uart.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/sb1250_uart.h	2002-10-29 11:18:36.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  UART Constants				File: sb1250_uart.h
-    *  
-    *  This module contains constants and macros useful for 
+    *
+    *  This module contains constants and macros useful for
     *  manipulating the SB1250's UARTs
     *
-    *  SB1250 specification level:  01/02/2002
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -37,7 +37,7 @@
 
 #include "sb1250_defs.h"
 
-/* ********************************************************************** 
+/* **********************************************************************
    * DUART Registers
    ********************************************************************** */
 
@@ -144,7 +144,7 @@
 #define V_DUART_MISC_CMD_START_BREAK     V_DUART_MISC_CMD(K_DUART_MISC_CMD_START_BREAK)
 #define V_DUART_MISC_CMD_STOP_BREAK      V_DUART_MISC_CMD(K_DUART_MISC_CMD_STOP_BREAK)
 
-#define M_DUART_CMD_RESERVED             _SB_MAKEMASK1(7) 
+#define M_DUART_CMD_RESERVED             _SB_MAKEMASK1(7)
 
 /*
  * DUART Status Register (Table 10-6)
@@ -164,7 +164,7 @@
 
 /*
  * DUART Baud Rate Register (Table 10-7)
- * Register: DUART_CLK_SEL_A 
+ * Register: DUART_CLK_SEL_A
  * Register: DUART_CLK_SEL_B
  */
 
@@ -229,6 +229,9 @@
 #define M_DUART_IP3_CHNG_ENA        _SB_MAKEMASK1(3)
 #define M_DUART_ACR_RESERVED        _SB_MAKEMASK(4,4)
 
+#define M_DUART_CTS_CHNG_ENA        _SB_MAKEMASK1(0)
+#define M_DUART_CIN_CHNG_ENA        _SB_MAKEMASK1(2)
+
 /*
  * DUART Interrupt Status Register (Table 10-16)
  * Register: DUART_ISR
@@ -327,9 +330,20 @@
     (chan == 0 ? M_DUART_OUT_PIN_CLR0 : M_DUART_OUT_PIN_CLR1)
 
 /*
- * XXX To be added: Synchronous Serial definitions
+ * Full Interrupt Control Register (PASS2)
  */
 
+#define S_DUART_SIG_FULL           _SB_MAKE64(0)
+#define M_DUART_SIG_FULL           _SB_MAKEMASK(4,S_DUART_SIG_FULL)
+#define V_DUART_SIG_FULL(x)        _SB_MAKEVALUE(x,S_DUART_SIG_FULL)
+#define G_DUART_SIG_FULL(x)        _SB_GETVALUE(x,S_DUART_SIG_FULL,M_DUART_SIG_FULL)
+
+#define S_DUART_INT_TIME           _SB_MAKE64(4)
+#define M_DUART_INT_TIME           _SB_MAKEMASK(4,S_DUART_INT_TIME)
+#define V_DUART_INT_TIME(x)        _SB_MAKEVALUE(x,S_DUART_INT_TIME)
+#define G_DUART_INT_TIME(x)        _SB_GETVALUE(x,S_DUART_INT_TIME,M_DUART_INT_TIME)
+
+
 /* ********************************************************************** */
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/swarm.h linux-2.4.20/include/asm-mips/sibyte/swarm.h
--- linux-2.4.19/include/asm-mips/sibyte/swarm.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/swarm.h	2002-10-29 11:18:40.000000000 +0000
@@ -10,20 +10,57 @@
  * 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.
  */
+#ifndef __ASM_SIBYTE_SWARM_H
+#define __ASM_SIBYTE_SWARM_H
 
-#ifndef _ASM_SIBYTE_SWARM_H
-#define _ASM_SIBYTE_SWARM_H
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/sb1250_int.h>
 
 #define KERNEL_RESERVED_MEM 0x100000
-#define LED_BASE_ADDR 0x100a0020
 
+#define LEDS_CS         3
+
+#ifdef CONFIG_SIBYTE_SWARM
+
+/* Generic bus chip selects */
+#define IDE_CS          4
+#define PCMCIA_CS       6
+
+/* GPIOs */
+#define K_GPIO_GB_IDE   4
+#define K_INT_GB_IDE    (K_INT_GPIO_0 + K_GPIO_GB_IDE)
+#define K_GPIO_PC_READY 9
+#define K_INT_PC_READY  (K_INT_GPIO_0 + K_GPIO_PC_READY)
+
+#endif
+
+#ifdef __ASSEMBLY__
+#define setleds(t0,t1,c0,c1,c2,c3) \
+	li	t0, (LED_BASE_ADDR|0xa0000000); \
+	li	t1, c0; \
+	sb	t1, 0x18(t0); \
+	li	t1, c1; \
+	sb	t1, 0x10(t0); \
+	li	t1, c2; \
+	sb	t1, 0x08(t0); \
+	li	t1, c3; \
+	sb	t1, 0x00(t0)
+#else
 void swarm_setup(void);
+void setleds(char *str);
 
-void setleds(char *str); 
+#define AT_spin \
+	__asm__ __volatile__ (		\
+		".set noat\n"		\
+		"li $at, 0\n"		\
+		"1: beqz $at, 1b\n"	\
+		".set at\n"		\
+		)
+#endif
 
-#endif /* _ASM_SIBYTE_SWARM_H */
+#endif /* __ASM_SIBYTE_SWARM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/sibyte/swarm_ide.h linux-2.4.20/include/asm-mips/sibyte/swarm_ide.h
--- linux-2.4.19/include/asm-mips/sibyte/swarm_ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/sibyte/swarm_ide.h	2002-10-29 11:18:40.000000000 +0000
@@ -10,7 +10,7 @@
  * 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.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/siginfo.h linux-2.4.20/include/asm-mips/siginfo.h
--- linux-2.4.19/include/asm-mips/siginfo.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/siginfo.h	2002-10-29 11:18:48.000000000 +0000
@@ -203,8 +203,8 @@
 
 /*
  * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
+ *
+ * It seems likely that SIGEV_THREAD will have to be handled from
  * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
  * thread manager then catches and does the appropriate nonsense.
  * However, everything is written out here so as to not get lost.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/signal.h linux-2.4.20/include/asm-mips/signal.h
--- linux-2.4.19/include/asm-mips/signal.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/signal.h	2002-10-29 11:18:36.000000000 +0000
@@ -88,7 +88,7 @@
 
 #define SA_RESTORER	0x04000000
 
-/* 
+/*
  * sigaltstack controls
  */
 #define SS_ONSTACK     1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/smp.h linux-2.4.20/include/asm-mips/smp.h
--- linux-2.4.19/include/asm-mips/smp.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/smp.h	2002-10-29 11:18:33.000000000 +0000
@@ -10,11 +10,11 @@
  * 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.
- */ 
+ */
 
 #ifndef __ASM_MIPS_SMP_H
 #define __ASM_MIPS_SMP_H
@@ -63,8 +63,8 @@
 
 #define CPUMASK_CLRALL(p)	(p) = 0
 #define CPUMASK_SETB(p, bit)	(p) |= 1 << (bit)
-#define CPUMASK_CLRB(p, bit)	(p) &= ~(1ULL << (bit))
-#define CPUMASK_TSTB(p, bit)	((p) & (1ULL << (bit)))
+#define CPUMASK_CLRB(p, bit)	(p) &= ~(1UL << (bit))
+#define CPUMASK_TSTB(p, bit)	((p) & (1UL << (bit)))
 
 #elif (NR_CPUS <= 128)
 
@@ -81,11 +81,11 @@
 
 #define	CPUMASK_CLRALL(p)	(p)._bits[0] = 0, (p)._bits[1] = 0
 #define CPUMASK_SETB(p, bit)	(p)._bits[CPUMASK_INDEX(bit)] |= \
-					(1ULL << CPUMASK_SHFT(bit))
+					(1UL << CPUMASK_SHFT(bit))
 #define CPUMASK_CLRB(p, bit)	(p)._bits[CPUMASK_INDEX(bit)] &= \
-					~(1ULL << CPUMASK_SHFT(bit))
+					~(1UL << CPUMASK_SHFT(bit))
 #define CPUMASK_TSTB(p, bit)	((p)._bits[CPUMASK_INDEX(bit)] & \
-					(1ULL << CPUMASK_SHFT(bit)))
+					(1UL << CPUMASK_SHFT(bit)))
 
 #else
 #error cpumask macros only defined for 128p kernels
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/socket.h linux-2.4.20/include/asm-mips/socket.h
--- linux-2.4.19/include/asm-mips/socket.h	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.20/include/asm-mips/socket.h	2002-10-29 11:18:34.000000000 +0000
@@ -4,7 +4,7 @@
 #include <asm/sockios.h>
 
 /*
- * For setsockoptions(2)
+ * For setsockopt(2)
  *
  * This defines are ABI conformant as far as Linux supports these ...
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/softirq.h linux-2.4.20/include/asm-mips/softirq.h
--- linux-2.4.19/include/asm-mips/softirq.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/softirq.h	2002-10-29 11:18:48.000000000 +0000
@@ -18,7 +18,7 @@
 	local_bh_count(cpu)++;
 	barrier();
 }
- 
+
 static inline void __cpu_bh_enable(int cpu)
 {
 	barrier();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/spinlock.h linux-2.4.20/include/asm-mips/spinlock.h
--- linux-2.4.19/include/asm-mips/spinlock.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/spinlock.h	2002-10-29 11:18:50.000000000 +0000
@@ -55,7 +55,7 @@
 	".set\tnoreorder\t\t\t# spin_unlock\n\t"
 	"sync\n\t"
 	"sw\t$0, %0\n\t"
-	".set\treorder"	
+	".set\treorder"
 	: "=m" (lock->lock)
 	: "m" (lock->lock)
 	: "memory");
@@ -92,7 +92,7 @@
 	"sc\t%1, %0\n\t"
 	"beqz\t%1, 1b\n\t"
 	" sync\n\t"
-	".set\treorder"	
+	".set\treorder"
 	: "=m" (rw->lock), "=&r" (tmp)
 	: "m" (rw->lock)
 	: "memory");
@@ -112,7 +112,7 @@
 	"sc\t%1, %0\n\t"
 	"beqz\t%1, 1b\n\t"
 	" sync\n\t"
-	".set\treorder"	
+	".set\treorder"
 	: "=m" (rw->lock), "=&r" (tmp)
 	: "m" (rw->lock)
 	: "memory");
@@ -130,7 +130,7 @@
 	"sc\t%1, %0\n\t"
 	"beqz\t%1, 1b\n\t"
 	" sync\n\t"
-	".set\treorder"	
+	".set\treorder"
 	: "=m" (rw->lock), "=&r" (tmp)
 	: "m" (rw->lock)
 	: "memory");
@@ -142,7 +142,7 @@
 	".set\tnoreorder\t\t\t# write_unlock\n\t"
 	"sync\n\t"
 	"sw\t$0, %0\n\t"
-	".set\treorder"	
+	".set\treorder"
 	: "=m" (rw->lock)
 	: "m" (rw->lock)
 	: "memory");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/stackframe.h linux-2.4.20/include/asm-mips/stackframe.h
--- linux-2.4.19/include/asm-mips/stackframe.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/stackframe.h	2002-10-29 11:18:31.000000000 +0000
@@ -55,14 +55,14 @@
                 srl     k0, k0, 23;                      \
 		sll     k0, k0, 2;                       \
                 addu    k1, k0;                          \
-                lw      k1, %lo(kernelsp)(k1);        
+                lw      k1, %lo(kernelsp)(k1);
 
 #else
 #  define GET_SAVED_SP                                   \
 		lui	k1, %hi(kernelsp);               \
-		lw	k1, %lo(kernelsp)(k1);           
+		lw	k1, %lo(kernelsp)(k1);
 #endif
- 
+
 #define SAVE_SOME                                        \
 		.set	push;                            \
 		.set	reorder;                         \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/string.h linux-2.4.20/include/asm-mips/string.h
--- linux-2.4.19/include/asm-mips/string.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/string.h	2002-10-29 11:18:30.000000000 +0000
@@ -109,7 +109,7 @@
 	"2:\n\t"
 #if defined(CONFIG_CPU_R3000)
 	"nop\n\t"
-#endif	
+#endif
 	"move\t%3,$1\n"
 	"3:\tsubu\t%3,$1\n\t"
 	".set\tat\n\t"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/system.h linux-2.4.20/include/asm-mips/system.h
--- linux-2.4.19/include/asm-mips/system.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/system.h	2002-10-29 11:18:39.000000000 +0000
@@ -8,7 +8,7 @@
  * Copyright (C) 1994 - 1999 by Ralf Baechle
  *
  * Changed set_except_vector declaration to allow return of previous
- * vector address value - necessary for "borrowing" vectors. 
+ * vector address value - necessary for "borrowing" vectors.
  *
  * Kevin D. Kissell, kevink@mips.org and Carsten Langgaard, carstenl@mips.com
  * Copyright (C) 2000 MIPS Technologies, Inc.
@@ -18,9 +18,12 @@
 
 #include <linux/config.h>
 #include <asm/sgidefs.h>
-#include <asm/ptrace.h>
+
 #include <linux/kernel.h>
 
+#include <asm/addrspace.h>
+#include <asm/ptrace.h>
+
 __asm__ (
 	".macro\t__sti\n\t"
 	".set\tpush\n\t"
@@ -101,7 +104,7 @@
 	"sll\t$0, $0, 1\t\t\t# nop\n\t"
 	"sll\t$0, $0, 1\t\t\t# nop\n\t"
 	"sll\t$0, $0, 1\t\t\t# nop\n\t"
-	".set\tpop\n\t"	
+	".set\tpop\n\t"
 	".endm");
 
 #define __save_and_cli(x)						\
@@ -145,7 +148,7 @@
 extern unsigned long __global_save_flags(void);
 extern void __global_restore_flags(unsigned long);
 #  define sti() __global_sti()
-#  define cli() __global_cli() 
+#  define cli() __global_cli()
 #  define save_flags(x) do { x = __global_save_flags(); } while (0)
 #  define restore_flags(x) __global_restore_flags(x)
 #  define save_and_cli(x) do { save_flags(x); cli(); } while(0)
@@ -166,32 +169,58 @@
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
 
-/*
- * These are probably defined overly paranoid ...
- */
+#ifdef CONFIG_CPU_HAS_SYNC
+#define __sync()				\
+	__asm__ __volatile__(			\
+		".set	push\n\t"		\
+		".set	noreorder\n\t"		\
+		".set	mips2\n\t"		\
+		"sync\n\t"			\
+		".set	pop"			\
+		: /* no output */		\
+		: /* no input */		\
+		: "memory")
+#else
+#define __sync()	do { } while(0)
+#endif
+
+#define __fast_iob()				\
+	__asm__ __volatile__(			\
+		".set	push\n\t"		\
+		".set	noreorder\n\t"		\
+		"lw	$0,%0\n\t"		\
+		"nop\n\t"			\
+		".set	pop"			\
+		: /* no output */		\
+		: "m" (*(int *)KSEG1)		\
+		: "memory")
+
+#define fast_wmb()	__sync()
+#define fast_rmb()	__sync()
+#define fast_mb()	__sync()
+#define fast_iob()				\
+	do {					\
+		__sync();			\
+		__fast_iob();			\
+	} while (0)
+
 #ifdef CONFIG_CPU_HAS_WB
 
 #include <asm/wbflush.h>
-#define rmb()	do { } while(0)
-#define wmb()	wbflush()
-#define mb()	wbflush()
-
-#else /* CONFIG_CPU_HAS_WB  */
-
-#define mb()						\
-__asm__ __volatile__(					\
-	"# prevent instructions being moved around\n\t"	\
-	".set\tnoreorder\n\t"				\
-	"# 8 nops to fool the R4400 pipeline\n\t"	\
-	"nop;nop;nop;nop;nop;nop;nop;nop\n\t"		\
-	".set\treorder"					\
-	: /* no output */				\
-	: /* no input */				\
-	: "memory")
-#define rmb() mb()
-#define wmb() mb()
 
-#endif /* CONFIG_CPU_HAS_WB  */
+#define wmb()		fast_wmb()
+#define rmb()		fast_rmb()
+#define mb()		wbflush();
+#define iob()		wbflush();
+
+#else /* !CONFIG_CPU_HAS_WB */
+
+#define wmb()		fast_wmb()
+#define rmb()		fast_rmb()
+#define mb()		fast_mb()
+#define iob()		fast_iob()
+
+#endif /* !CONFIG_CPU_HAS_WB */
 
 #ifdef CONFIG_SMP
 #define smp_mb()	mb()
@@ -218,6 +247,14 @@
 #endif /* !__ASSEMBLY__ */
 
 #define prepare_to_switch()	do { } while(0)
+
+struct task_struct;
+
+extern asmlinkage void lazy_fpu_switch(void *);
+extern asmlinkage void init_fpu(void);
+extern asmlinkage void save_fp(struct task_struct *);
+extern asmlinkage void restore_fp(struct task_struct *);
+
 #define switch_to(prev,next,last) \
 do { \
 	(last) = resume(prev, next); \
@@ -275,14 +312,14 @@
 
 extern void *set_except_vector(int n, void *addr);
 
-extern void __die(const char *, struct pt_regs *, const char *where,
-	unsigned long line) __attribute__((noreturn));
-extern void __die_if_kernel(const char *, struct pt_regs *, const char *where,
-	unsigned long line);
+extern void __die(const char *, struct pt_regs *, const char *file,
+	const char *func, unsigned long line) __attribute__((noreturn));
+extern void __die_if_kernel(const char *, struct pt_regs *, const char *file,
+	const char *func, unsigned long line);
 
 #define die(msg, regs)							\
-	__die(msg, regs, __FILE__ ":"__FUNCTION__, __LINE__)
+	__die(msg, regs, __FILE__ ":", __FUNCTION__, __LINE__)
 #define die_if_kernel(msg, regs)					\
-	__die_if_kernel(msg, regs, __FILE__ ":"__FUNCTION__, __LINE__)
+	__die_if_kernel(msg, regs, __FILE__ ":", __FUNCTION__, __LINE__)
 
 #endif /* _ASM_SYSTEM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/termios.h linux-2.4.20/include/asm-mips/termios.h
--- linux-2.4.19/include/asm-mips/termios.h	2001-09-09 17:43:01.000000000 +0000
+++ linux-2.4.20/include/asm-mips/termios.h	2002-10-29 11:18:35.000000000 +0000
@@ -84,6 +84,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* line disciplines */
 #define N_TTY		0
 #define N_SLIP		1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/time.h linux-2.4.20/include/asm-mips/time.h
--- linux-2.4.19/include/asm-mips/time.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/time.h	2002-10-29 11:18:34.000000000 +0000
@@ -23,7 +23,7 @@
 #include <linux/linkage.h>              /* for asmlinkage */
 #include <linux/rtc.h>                  /* for struct rtc_time */
 
-/* 
+/*
  * RTC ops.  By default, they point a no-RTC functions.
  *	rtc_get_time - mktime(year, mon, day, hour, min, sec) in seconds.
  *	rtc_set_time - reverse the above translation and set time to RTC.
@@ -39,7 +39,7 @@
 extern void to_tm(unsigned long tim, struct rtc_time * tm);
 
 /*
- * do_gettimeoffset(). By default, this func pointer points to 
+ * do_gettimeoffset(). By default, this func pointer points to
  * do_null_gettimeoffset(), which leads to the same resolution as HZ.
  * Higher resolution versions are vailable, which gives ~1us resolution.
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/timex.h linux-2.4.20/include/asm-mips/timex.h
--- linux-2.4.19/include/asm-mips/timex.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/timex.h	2002-10-29 11:18:50.000000000 +0000
@@ -21,7 +21,7 @@
  * Standard way to access the cycle counter.
  * Currently only used on SMP for scheduling.
  *
- * Only the low 32 bits are available as a continuously counting entity. 
+ * Only the low 32 bits are available as a continuously counting entity.
  * But this only means we'll force a reschedule every 8 seconds or so,
  * which isn't an evil thing.
  *
@@ -37,4 +37,7 @@
 }
 #endif /* __KERNEL__ */
 
+#define vxtime_lock()		do {} while (0)
+#define vxtime_unlock()		do {} while (0)
+
 #endif /*  __ASM_MIPS_TIMEX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/types.h linux-2.4.20/include/asm-mips/types.h
--- linux-2.4.19/include/asm-mips/types.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/types.h	2002-10-29 11:18:32.000000000 +0000
@@ -33,12 +33,12 @@
 typedef unsigned long __u64;
 
 #else
- 
+
 #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
 typedef __signed__ long long __s64;
 typedef unsigned long long __u64;
 #endif
- 
+
 #endif
 
 /*
@@ -71,10 +71,10 @@
 
 #define BITS_PER_LONG _MIPS_SZLONG
 
-#ifdef CONFIG_64BIT_PHYS_ADDR
-typedef u32 dma_addr_t;
-#else
+#if defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)
 typedef u64 dma_addr_t;
+#else
+typedef u32 dma_addr_t;
 #endif
 typedef u64 dma64_addr_t;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/umap.h linux-2.4.20/include/asm-mips/umap.h
--- linux-2.4.19/include/asm-mips/umap.h	1999-06-26 00:37:53.000000000 +0000
+++ linux-2.4.20/include/asm-mips/umap.h	2002-10-29 11:18:38.000000000 +0000
@@ -4,5 +4,5 @@
 void remove_mapping (struct task_struct *task, unsigned long start,
 unsigned long end);
 
-#endif 
+#endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/unaligned.h linux-2.4.20/include/asm-mips/unaligned.h
--- linux-2.4.19/include/asm-mips/unaligned.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/unaligned.h	2002-10-29 11:18:50.000000000 +0000
@@ -93,8 +93,8 @@
  * get_unaligned - get value from possibly mis-aligned location
  * @ptr: pointer to value
  *
- * This macro should be used for accessing values larger in size than 
- * single bytes at locations that are expected to be improperly aligned, 
+ * This macro should be used for accessing values larger in size than
+ * single bytes at locations that are expected to be improperly aligned,
  * e.g. retrieving a u16 value from a location not u16-aligned.
  *
  * Note that unaligned accesses can be very expensive on some architectures.
@@ -129,8 +129,8 @@
  * @val: value to place
  * @ptr: pointer to location
  *
- * This macro should be used for placing values larger in size than 
- * single bytes at locations that are expected to be improperly aligned, 
+ * This macro should be used for placing values larger in size than
+ * single bytes at locations that are expected to be improperly aligned,
  * e.g. writing a u16 value to a location not u16-aligned.
  *
  * Note that unaligned accesses can be very expensive on some architectures.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/vr41xx/capcella.h linux-2.4.20/include/asm-mips/vr41xx/capcella.h
--- linux-2.4.19/include/asm-mips/vr41xx/capcella.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips/vr41xx/capcella.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,61 @@
+/*
+ * FILE NAME
+ *	include/asm-mips/vr41xx/capcella.h
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Include file for ZAO Networks Capcella.
+ *
+ * Copyright 2002 Yoichi Yuasa
+ *                yuasa@hh.iij4u.or.jp
+ *
+ *  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.
+ */
+#ifndef __ZAO_CAPCELLA_H
+#define __ZAO_CAPCELLA_H
+
+#include <asm/addrspace.h>
+#include <asm/vr41xx/vr41xx.h>
+
+/*
+ * Board specific address mapping
+ */
+#define VR41XX_PCI_MEM1_BASE		0x10000000
+#define VR41XX_PCI_MEM1_SIZE		0x04000000
+#define VR41XX_PCI_MEM1_MASK		0x7c000000
+
+#define VR41XX_PCI_MEM2_BASE		0x14000000
+#define VR41XX_PCI_MEM2_SIZE		0x02000000
+#define VR41XX_PCI_MEM2_MASK		0x7e000000
+
+#define VR41XX_PCI_IO_BASE		0x16000000
+#define VR41XX_PCI_IO_SIZE		0x02000000
+#define VR41XX_PCI_IO_MASK		0x7e000000
+
+#define VR41XX_PCI_IO_START		0x01000000
+#define VR41XX_PCI_IO_END		0x01ffffff
+
+#define VR41XX_PCI_MEM_START		0x12000000
+#define VR41XX_PCI_MEM_END		0x15ffffff
+
+#define IO_PORT_BASE			KSEG1ADDR(VR41XX_PCI_IO_BASE)
+#define IO_PORT_RESOURCE_START		0
+#define IO_PORT_RESOURCE_END		VR41XX_PCI_IO_SIZE
+#define IO_MEM1_RESOURCE_START		VR41XX_PCI_MEM1_BASE
+#define IO_MEM1_RESOURCE_END		(VR41XX_PCI_MEM1_BASE + VR41XX_PCI_MEM1_SIZE)
+#define IO_MEM2_RESOURCE_START		VR41XX_PCI_MEM2_BASE
+#define IO_MEM2_RESOURCE_END		(VR41XX_PCI_MEM2_BASE + VR41XX_PCI_MEM2_SIZE)
+
+/*
+ * Interrupt Number
+ */
+#define RTL8139_1_IRQ			GIU_IRQ(4)
+#define RTL8139_2_IRQ			GIU_IRQ(5)
+#define PC104PLUS_INTA_IRQ		GIU_IRQ(2)
+#define PC104PLUS_INTB_IRQ		GIU_IRQ(3)
+#define PC104PLUS_INTC_IRQ		GIU_IRQ(4)
+#define PC104PLUS_INTD_IRQ		GIU_IRQ(5)
+
+#endif /* __ZAO_CAPCELLA_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/vr41xx/eagle.h linux-2.4.20/include/asm-mips/vr41xx/eagle.h
--- linux-2.4.19/include/asm-mips/vr41xx/eagle.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips/vr41xx/eagle.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,275 @@
+/*
+ * FILE NAME
+ *	include/asm-mips/vr41xx/eagle.h
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Include file for NEC Eagle board.
+ *
+ * Author: MontaVista Software, Inc.
+ *         yyuasa@mvista.com or source@mvista.com
+ *
+ * Copyright 2001,2002 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.
+ */
+#ifndef __NEC_EAGLE_H
+#define __NEC_EAGLE_H
+
+#include <asm/addrspace.h>
+#include <asm/vr41xx/vr41xx.h>
+
+/*
+ * Board specific address mapping
+ */
+#define VR41XX_PCI_MEM1_BASE		0x10000000
+#define VR41XX_PCI_MEM1_SIZE		0x04000000
+#define VR41XX_PCI_MEM1_MASK		0x7c000000
+
+#define VR41XX_PCI_MEM2_BASE		0x14000000
+#define VR41XX_PCI_MEM2_SIZE		0x02000000
+#define VR41XX_PCI_MEM2_MASK		0x7e000000
+
+#define VR41XX_PCI_IO_BASE		0x16000000
+#define VR41XX_PCI_IO_SIZE		0x02000000
+#define VR41XX_PCI_IO_MASK		0x7e000000
+
+#define VR41XX_PCI_IO_START		0x01000000
+#define VR41XX_PCI_IO_END		0x01ffffff
+
+#define VR41XX_PCI_MEM_START		0x12000000
+#define VR41XX_PCI_MEM_END		0x15ffffff
+
+#define IO_PORT_BASE			KSEG1ADDR(VR41XX_PCI_IO_BASE)
+#define IO_PORT_RESOURCE_START		0
+#define IO_PORT_RESOURCE_END		VR41XX_PCI_IO_SIZE
+#define IO_MEM1_RESOURCE_START		VR41XX_PCI_MEM1_BASE
+#define IO_MEM1_RESOURCE_END		(VR41XX_PCI_MEM1_BASE + VR41XX_PCI_MEM1_SIZE)
+#define IO_MEM2_RESOURCE_START		VR41XX_PCI_MEM2_BASE
+#define IO_MEM2_RESOURCE_END		(VR41XX_PCI_MEM2_BASE + VR41XX_PCI_MEM2_SIZE)
+
+/*
+ * General-Purpose I/O Pin Number
+ */
+#define VRC4173_PIN			1
+#define PCISLOT_PIN			4
+#define FPGA_PIN			5
+#define DCD_PIN				15
+
+/*
+ * Interrupt Number
+ */
+#define VRC4173_CASCADE_IRQ		GIU_IRQ(VRC4173_PIN)
+#define PCISLOT_IRQ			GIU_IRQ(PCISLOT_PIN)
+#define FPGA_CASCADE_IRQ		GIU_IRQ(FPGA_PIN)
+#define DCD_IRQ				GIU_IRQ(DCD_PIN)
+
+#define SDBINT_IRQ_BASE			89
+#define DEG_IRQ				(SDBINT_IRQ_BASE + 1)
+#define ENUM_IRQ			(SDBINT_IRQ_BASE + 2)
+#define SIO1INT_IRQ			(SDBINT_IRQ_BASE + 3)
+#define SIO2INT_IRQ			(SDBINT_IRQ_BASE + 4)
+#define PARINT_IRQ			(SDBINT_IRQ_BASE + 5)
+#define SDBINT_IRQ_LAST			PARINT_IRQ
+
+#define PCIINT_IRQ_BASE			97
+#define CP_INTA_IRQ			(PCIINT_IRQ_BASE + 0)
+#define CP_INTB_IRQ			(PCIINT_IRQ_BASE + 1)
+#define CP_INTC_IRQ			(PCIINT_IRQ_BASE + 2)
+#define CP_INTD_IRQ			(PCIINT_IRQ_BASE + 3)
+#define LANINTA_IRQ			(PCIINT_IRQ_BASE + 4)
+#define PCIINT_IRQ_LAST			LANINTA_IRQ
+
+
+/*
+ * On board Devices I/O Mapping
+ */
+#define NEC_EAGLE_SIO1RB		KSEG1ADDR(0x0DFFFEC0)
+#define NEC_EAGLE_SIO1TH		KSEG1ADDR(0x0DFFFEC0)
+#define NEC_EAGLE_SIO1IE		KSEG1ADDR(0x0DFFFEC2)
+#define NEC_EAGLE_SIO1IID		KSEG1ADDR(0x0DFFFEC4)
+#define NEC_EAGLE_SIO1FC		KSEG1ADDR(0x0DFFFEC4)
+#define NEC_EAGLE_SIO1LC		KSEG1ADDR(0x0DFFFEC6)
+#define NEC_EAGLE_SIO1MC		KSEG1ADDR(0x0DFFFEC8)
+#define NEC_EAGLE_SIO1LS		KSEG1ADDR(0x0DFFFECA)
+#define NEC_EAGLE_SIO1MS		KSEG1ADDR(0x0DFFFECC)
+#define NEC_EAGLE_SIO1SC		KSEG1ADDR(0x0DFFFECE)
+
+#define NEC_EAGLE_SIO2TH		KSEG1ADDR(0x0DFFFED0)
+#define NEC_EAGLE_SIO2IE		KSEG1ADDR(0x0DFFFED2)
+#define NEC_EAGLE_SIO2IID		KSEG1ADDR(0x0DFFFED4)
+#define NEC_EAGLE_SIO2FC		KSEG1ADDR(0x0DFFFED4)
+#define NEC_EAGLE_SIO2LC		KSEG1ADDR(0x0DFFFED6)
+#define NEC_EAGLE_SIO2MC		KSEG1ADDR(0x0DFFFED8)
+#define NEC_EAGLE_SIO2LS		KSEG1ADDR(0x0DFFFEDA)
+#define NEC_EAGLE_SIO2MS		KSEG1ADDR(0x0DFFFEDC)
+#define NEC_EAGLE_SIO2SC		KSEG1ADDR(0x0DFFFEDE)
+
+#define NEC_EAGLE_PIOPP_DATA		KSEG1ADDR(0x0DFFFEE0)
+#define NEC_EAGLE_PIOPP_STATUS		KSEG1ADDR(0x0DFFFEE2)
+#define NEC_EAGLE_PIOPP_CNT		KSEG1ADDR(0x0DFFFEE4)
+#define NEC_EAGLE_PIOPP_EPPADDR		KSEG1ADDR(0x0DFFFEE6)
+#define NEC_EAGLE_PIOPP_EPPDATA0	KSEG1ADDR(0x0DFFFEE8)
+#define NEC_EAGLE_PIOPP_EPPDATA1	KSEG1ADDR(0x0DFFFEEA)
+#define NEC_EAGLE_PIOPP_EPPDATA2	KSEG1ADDR(0x0DFFFEEC)
+
+#define NEC_EAGLE_PIOECP_DATA		KSEG1ADDR(0x0DFFFEF0)
+#define NEC_EAGLE_PIOECP_CONFIG		KSEG1ADDR(0x0DFFFEF2)
+#define NEC_EAGLE_PIOECP_EXTCNT		KSEG1ADDR(0x0DFFFEF4)
+
+
+/*
+ *  FLSHCNT Register
+ */
+#define NEC_EAGLE_FLSHCNT		KSEG1ADDR(0x0DFFFFA0)
+#define NEC_EAGLE_FLSHCNT_FRDY		0x80
+#define NEC_EAGLE_FLSHCNT_VPPE		0x40
+#define NEC_EAGLE_FLSHCNT_WP2		0x01
+
+
+/*
+ * FLSHBANK Register
+ */
+#define NEC_EAGLE_FLSHBANK		KSEG1ADDR(0x0DFFFFA4)
+#define NEC_EAGLE_FLSHBANK_S_BANK2	0x40
+#define NEC_EAGLE_FLSHBANK_S_BANK1	0x20
+#define NEC_EAGLE_FLSHBANK_BNKQ4	0x10
+#define NEC_EAGLE_FLSHBANK_BNKQ3	0x08
+#define NEC_EAGLE_FLSHBANK_BNKQ2	0x04
+#define NEC_EAGLE_FLSHBANK_BNKQ1	0x02
+#define NEC_EAGLE_FLSHBANK_BNKQ0	0x01
+
+
+/*
+ * SWITCH Setting Register
+ */
+#define NEC_EAGLE_SWTCHSET		KSEG1ADDR(0x0DFFFFA8)
+#define NEC_EAGLE_SWTCHSET_DP2SW4	0x80
+#define NEC_EAGLE_SWTCHSET_DP2SW3	0x40
+#define NEC_EAGLE_SWTCHSET_DP2SW2	0x20
+#define NEC_EAGLE_SWTCHSET_DP2SW1	0x10
+#define NEC_EAGLE_SWTCHSET_DP1SW4	0x08
+#define NEC_EAGLE_SWTCHSET_DP1SW3	0x04
+#define NEC_EAGLE_SWTCHSET_DP1SW2	0x02
+#define NEC_EAGLE_SWTCHSET_DP1SW1	0x01
+
+
+/*
+ * PPT Parallel Port Device Controller
+ */
+#define NEC_EAGLE_PPT_WRITE_DATA	KSEG1ADDR(0x0DFFFFB0)
+#define NEC_EAGLE_PPT_READ_DATA		KSEG1ADDR(0x0DFFFFB2)
+#define NEC_EAGLE_PPT_CNT		KSEG1ADDR(0x0DFFFFB4)
+#define NEC_EAGLE_PPT_CNT2		KSEG1ADDR(0x0DFFFFB4)
+
+/* Control Register */
+#define NEC_EAGLE_PPT_INTMSK		0x20
+#define NEC_EAGLE_PPT_PARIINT		0x10
+#define NEC_EAGLE_PPT_SELECTIN		0x08
+#define NEC_EAGLE_PPT_INIT		0x04
+#define NEC_EAGLE_PPT_AUTOFD		0x02
+#define NEC_EAGLE_PPT_STROBE		0x01
+
+/* Control Rgister 2 */
+#define NEC_EAGLE_PPT_PAREN		0x80
+#define NEC_EAGLE_PPT_AUTOEN		0x20
+#define NEC_EAGLE_PPT_BUSY		0x10
+#define NEC_EAGLE_PPT_ACK		0x08
+#define NEC_EAGLE_PPT_PE		0x04
+#define NEC_EAGLE_PPT_SELECT		0x02
+#define NEC_EAGLE_PPT_FAULT		0x01
+
+
+/*
+ * LEDWR Register
+ */
+#define NEC_EAGLE_LEDWR1		KSEG1ADDR(0x0DFFFFC0)
+#define NEC_EAGLE_LEDWR2		KSEG1ADDR(0x0DFFFFC4)
+
+
+/*
+ * SDBINT Register
+ */
+#define NEC_EAGLE_SDBINT		KSEG1ADDR(0x0DFFFFD0)
+#define NEC_EAGLE_SDBINT_PARINT		0x20
+#define NEC_EAGLE_SDBINT_SIO2INT	0x10
+#define NEC_EAGLE_SDBINT_SIO1INT	0x08
+#define NEC_EAGLE_SDBINT_ENUM		0x04
+#define NEC_EAGLE_SDBINT_DEG		0x02
+
+
+/*
+ * SDB INTMSK Register
+ */
+#define NEC_EAGLE_SDBINTMSK		KSEG1ADDR(0x0DFFFFD4)
+#define NEC_EAGLE_SDBINTMSK_MSKPAR	0x20
+#define NEC_EAGLE_SDBINTMSK_MSKSIO2	0x10
+#define NEC_EAGLE_SDBINTMSK_MSKSIO1	0x08
+#define NEC_EAGLE_SDBINTMSK_MSKENUM	0x04
+#define NEC_EAGLE_SDBINTMSK_MSKDEG	0x02
+
+
+/*
+ * RSTREG Register
+ */
+#define NEC_EAGLE_RSTREG		KSEG1ADDR(0x0DFFFFD8)
+#define NEC_EAGLE_RST_RSTSW		0x02
+#define NEC_EAGLE_RST_LEDOFF		0x01
+
+
+/*
+ * PCI INT Rgister
+ */
+#define NEC_EAGLE_PCIINTREG		KSEG1ADDR(0x0DFFFFDC)
+#define NEC_EAGLE_PCIINT_LANINT		0x10
+#define NEC_EAGLE_PCIINT_CP_INTD	0x08
+#define NEC_EAGLE_PCIINT_CP_INTC	0x04
+#define NEC_EAGLE_PCIINT_CP_INTB	0x02
+#define NEC_EAGLE_PCIINT_CP_INTA	0x01
+
+
+/*
+ * PCI INT Mask Register
+ */
+#define NEC_EAGLE_PCIINTMSKREG		KSEG1ADDR(0x0DFFFFE0)
+#define NEC_EAGLE_PCIINTMSK_MSKLANINT	0x10
+#define NEC_EAGLE_PCIINTMSK_MSKCP_INTD	0x08
+#define NEC_EAGLE_PCIINTMSK_MSKCP_INTC	0x04
+#define NEC_EAGLE_PCIINTMSK_MSKCP_INTB	0x02
+#define NEC_EAGLE_PCIINTMSK_MSKCP_INTA	0x01
+
+
+/*
+ * CLK Division Register
+ */
+#define NEC_EAGLE_CLKDIV		KSEG1ADDR(0x0DFFFFE4)
+#define NEC_EAGLE_CLKDIV_PCIDIV1	0x10
+#define NEC_EAGLE_CLKDIV_PCIDIV0	0x08
+#define NEC_EAGLE_CLKDIV_VTDIV2		0x04
+#define NEC_EAGLE_CLKDIV_VTDIV1		0x02
+#define NEC_EAGLE_CLKDIV_VTDIV0		0x01
+
+
+/*
+ * Source Revision Register
+ */
+#define NEC_EAGLE_REVISION		KSEG1ADDR(0x0DFFFFE8)
+
+#endif /* __NEC_EAGLE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/vr41xx/vr41xx.h linux-2.4.20/include/asm-mips/vr41xx/vr41xx.h
--- linux-2.4.19/include/asm-mips/vr41xx/vr41xx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips/vr41xx/vr41xx.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,148 @@
+/*
+ * include/asm-mips/vr41xx/vr41xx.h
+ *
+ * Include file for NEC VR4100 series.
+ *
+ * Copyright (C) 1999 Michael Klar
+ * Copyright (C) 2001, 2002 Paul Mundt
+ * Copyright (C) 2002 MontaVista Software, Inc.
+ * Copyright (C) 2002 TimeSys Corp.
+ *
+ * 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.
+ */
+#ifndef __NEC_VR41XX_H
+#define __NEC_VR41XX_H
+
+#include <linux/interrupt.h>
+
+/*
+ * CPU Revision
+ */
+/* VR4122 0x00000c70-0x00000c72 */
+#define PRID_VR4122_REV1_0	0x00000c70
+#define PRID_VR4122_REV2_0	0x00000c70
+#define PRID_VR4122_REV2_1	0x00000c70
+#define PRID_VR4122_REV3_0	0x00000c71
+#define PRID_VR4122_REV3_1	0x00000c72
+
+/* VR4181A 0x00000c73-0x00000c7f */
+#define PRID_VR4181A_REV1_0	0x00000c73
+#define PRID_VR4181A_REV1_1	0x00000c74
+
+/* VR4131 0x00000c80-0x00000c8f */
+#define PRID_VR4131_REV1_2	0x00000c80
+#define PRID_VR4131_REV2_0	0x00000c81
+#define PRID_VR4131_REV2_1	0x00000c82
+#define PRID_VR4131_REV2_2	0x00000c83
+
+
+/*
+ * Bus Control Uint
+ */
+extern void vr41xx_bcu_init(void);
+
+/*
+ * Clock Mask Unit
+ */
+extern void vr41xx_cmu_init(u16 mask);
+extern void vr41xx_clock_supply(u16 mask);
+extern void vr41xx_clock_mask(u16 mask);
+
+/*
+ * Interrupt Control Unit
+ */
+
+/* GIU Interrupt Numbers */
+#define GIU_IRQ(x)	(40 + (x))
+
+extern void (*board_irq_init)(void);
+extern int vr41xx_cascade_irq(unsigned int irq, int (*get_irq_number)(int irq));
+
+/*
+ * Gegeral-Purpose I/O Unit
+ */
+enum {
+	TRIGGER_LEVEL,
+	TRIGGER_EDGE
+};
+
+enum {
+	SIGNAL_THROUGH,
+	SIGNAL_HOLD
+};
+
+extern void vr41xx_set_irq_trigger(u8 pin, u8 trigger, u8 hold);
+
+enum {
+	LEVEL_LOW,
+	LEVEL_HIGH
+};
+
+extern void vr41xx_set_irq_level(u8 pin, u8 level);
+
+enum {
+	PIO_INPUT,
+	PIO_OUTPUT
+};
+
+enum {
+	DATA_LOW,
+	DATA_HIGH
+};
+
+/*
+ * Serial Interface Unit
+ */
+extern void vr41xx_siu_init(int interface, int module);
+extern void vr41xx_siu_ifselect(int interface, int module);
+extern int vr41xx_serial_ports;
+
+/* SIU interfaces */
+enum {
+	SIU_RS232C,
+	SIU_IRDA
+};
+
+/* IrDA interfaces */
+enum {
+	IRDA_SHARP = 1,
+	IRDA_TEMIC,
+	IRDA_HP
+};
+
+/*
+ * Debug Serial Interface Unit
+ */
+extern void vr41xx_dsiu_init(void);
+
+/*
+ * PCI Control Unit
+ */
+struct vr41xx_pci_address_space {
+	u32 internal_base;
+	u32 address_mask;
+	u32 pci_base;
+};
+
+struct vr41xx_pci_address_map {
+	struct vr41xx_pci_address_space *mem1;
+	struct vr41xx_pci_address_space *mem2;
+	struct vr41xx_pci_address_space *io;
+};
+
+extern void vr41xx_pciu_init(struct vr41xx_pci_address_map *map);
+
+/*
+ * MISC
+ */
+extern void vr41xx_time_init(void);
+extern void vr41xx_timer_setup(struct irqaction *irq);
+
+extern void vr41xx_restart(char *command);
+extern void vr41xx_halt(void);
+extern void vr41xx_power_off(void);
+
+#endif /* __NEC_VR41XX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/war.h linux-2.4.20/include/asm-mips/war.h
--- linux-2.4.19/include/asm-mips/war.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/war.h	2002-10-29 11:18:31.000000000 +0000
@@ -8,6 +8,8 @@
 #ifndef _ASM_WAR_H
 #define _ASM_WAR_H
 
+#include <linux/config.h>
+
 /*
  * Pleassures of the R4600 V1.x.  Cite from the IDT R4600 V1.7 errata:
  *
@@ -15,10 +17,10 @@
  *      Hit_Invalidate_D and Create_Dirty_Excl_D should only be
  *      executed if there is no other dcache activity. If the dcache is
  *      accessed for another instruction immeidately preceding when these
- *      cache instructions are executing, it is possible that the dcache 
- *      tag match outputs used by these cache instructions will be 
+ *      cache instructions are executing, it is possible that the dcache
+ *      tag match outputs used by these cache instructions will be
  *      incorrect. These cache instructions should be preceded by at least
- *      four instructions that are not any kind of load or store 
+ *      four instructions that are not any kind of load or store
  *      instruction.
  *
  *      This is not allowed:    lw
@@ -50,4 +52,19 @@
  */
 #define R4600_V2_HIT_CACHEOP_WAR
 
+#ifdef CONFIG_CPU_R5432
+
+/*
+ * When an interrupt happens on a CP0 register read instruction, CPU may
+ * lock up or read corrupted values of CP0 registers after it enters
+ * the exception handler.
+ *
+ * This workaround makes sure that we read a "safe" CP0 register as the
+ * first thing in the exception handler, which breaks one of the
+ * pre-conditions for this problem.
+ */
+#define	R5432_CP0_INTERRUPT_WAR
+
+#endif
+
 #endif /* _ASM_WAR_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips/wbflush.h linux-2.4.20/include/asm-mips/wbflush.h
--- linux-2.4.19/include/asm-mips/wbflush.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips/wbflush.h	2002-10-29 11:18:49.000000000 +0000
@@ -6,29 +6,30 @@
  * for more details.
  *
  * Copyright (c) 1998 Harald Koerfgen
+ * Copyright (C) 2002 Maciej W. Rozycki
  */
 #ifndef __ASM_MIPS_WBFLUSH_H
 #define __ASM_MIPS_WBFLUSH_H
 
 #include <linux/config.h>
 
-#if defined(CONFIG_CPU_HAS_WB)
-/*
- * R2000 or R3000
- */
-extern void (*__wbflush) (void);
+#ifdef CONFIG_CPU_HAS_WB
 
-#define wbflush() __wbflush()
+extern void (*__wbflush)(void);
+extern void wbflush_setup(void);
 
-#else
-/*
- * we don't need no stinkin' wbflush
- */
+#define wbflush()			\
+	do {				\
+		__sync();		\
+		__wbflush();		\
+	} while (0)
 
-#define wbflush()  do { } while(0)
+#else /* !CONFIG_CPU_HAS_WB */
 
-#endif
+#define wbflush_setup() do { } while (0)
 
-extern void wbflush_setup(void);
+#define wbflush() fast_iob()
+
+#endif /* !CONFIG_CPU_HAS_WB */
 
 #endif /* __ASM_MIPS_WBFLUSH_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/a.out.h linux-2.4.20/include/asm-mips64/a.out.h
--- linux-2.4.19/include/asm-mips64/a.out.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/a.out.h	2002-10-29 11:18:33.000000000 +0000
@@ -26,7 +26,7 @@
 
 #ifdef __KERNEL__
 
-#define STACK_TOP (current->thread.mflags & MF_32BIT ? 0x7fff8000 : TASK_SIZE)
+#define STACK_TOP (current->thread.mflags & MF_32BIT ? TASK_SIZE32 : TASK_SIZE)
 
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/addrspace.h linux-2.4.20/include/asm-mips64/addrspace.h
--- linux-2.4.19/include/asm-mips64/addrspace.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/addrspace.h	2002-10-29 11:18:31.000000000 +0000
@@ -85,7 +85,8 @@
 #if defined (CONFIG_CPU_R4300)						\
     || defined (CONFIG_CPU_R4X00)					\
     || defined (CONFIG_CPU_R5000)					\
-    || defined (CONFIG_CPU_NEVADA)
+    || defined (CONFIG_CPU_NEVADA)					\
+    || defined (CONFIG_CPU_MIPS64)
 #define	KUSIZE			0x0000010000000000	/* 2^^40 */
 #define	KUSIZE_64		0x0000010000000000	/* 2^^40 */
 #define	K0SIZE			0x0000001000000000	/* 2^^36 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/asm.h linux-2.4.20/include/asm-mips64/asm.h
--- linux-2.4.19/include/asm-mips64/asm.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/asm.h	2002-10-29 11:18:31.000000000 +0000
@@ -88,7 +88,7 @@
 #define	PANIC(msg)                                      \
 		.set	push;				\
 		.set	reorder;                        \
-		la	a0,8f;                          \
+		PTR_LA	a0,8f;                          \
 		jal	panic;                          \
 9:		b	9b;                             \
 		.set	pop;				\
@@ -100,7 +100,7 @@
 #define PRINT(string)                                   \
 		.set	push;				\
 		.set	reorder;                        \
-		la	a0,8f;                          \
+		PTR_LA	a0,8f;                          \
 		jal	printk;                         \
 		.set	pop;				\
 		TEXT(string)
@@ -165,7 +165,7 @@
 		.set	push;				\
 		.set	reorder;			\
 		bnez	rt,9f;                          \
-		move	rd,rt;                          \
+		move	rd,rs;                          \
 		.set	pop;				\
 9:
 #endif /* _MIPS_ISA == _MIPS_ISA_MIPS1 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/asmmacro.h linux-2.4.20/include/asm-mips64/asmmacro.h
--- linux-2.4.19/include/asm-mips64/asmmacro.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/asmmacro.h	2002-10-29 11:18:35.000000000 +0000
@@ -8,8 +8,22 @@
 #ifndef _ASM_ASMMACRO_H
 #define _ASM_ASMMACRO_H
 
+#include <linux/config.h>
 #include <asm/offset.h>
 
+#ifdef CONFIG_CPU_SB1
+#define FPU_ENABLE_HAZARD		\
+	.set    push;			\
+	.set	noreorder;		\
+	.set    mips2;			\
+	SSNOP;				\
+	bnezl   $0, .+4;		\
+	 SSNOP;				\
+	.set    pop
+#else
+#define FPU_ENABLE_HAZARD
+#endif
+
 	.macro	fpu_save_16even thread tmp
 	cfc1	\tmp, fcr31
 	sdc1	$f2,  (THREAD_FPU + 0x010)(\thread)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/bcache.h linux-2.4.20/include/asm-mips64/bcache.h
--- linux-2.4.19/include/asm-mips64/bcache.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/bcache.h	2002-10-29 11:18:39.000000000 +0000
@@ -12,7 +12,7 @@
 #include <linux/config.h>
 
 /* Some R4000 / R4400 / R4600 / R5000 machines may have a non-dma-coherent,
-   chipset implemented caches.  On machines with other CPUs the CPU does the 
+   chipset implemented caches.  On machines with other CPUs the CPU does the
    cache thing itself. */
 struct bcache_ops {
 	void (*bc_enable)(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/bitops.h linux-2.4.20/include/asm-mips64/bitops.h
--- linux-2.4.19/include/asm-mips64/bitops.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/bitops.h	2002-10-29 11:18:36.000000000 +0000
@@ -132,7 +132,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is atomic and cannot be reordered.  
+ * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
 static inline unsigned long test_and_set_bit(unsigned long nr,
@@ -164,7 +164,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is non-atomic and can be reordered.  
+ * This operation is non-atomic and can be reordered.
  * If two examples of this operation race, one can appear to succeed
  * but actually fail.  You must protect multiple accesses with a lock.
  */
@@ -186,7 +186,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is atomic and cannot be reordered.  
+ * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
 static inline unsigned long test_and_clear_bit(unsigned long nr,
@@ -219,7 +219,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is non-atomic and can be reordered.  
+ * This operation is non-atomic and can be reordered.
  * If two examples of this operation race, one can appear to succeed
  * but actually fail.  You must protect multiple accesses with a lock.
  */
@@ -241,7 +241,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is atomic and cannot be reordered.  
+ * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
 static inline unsigned long test_and_change_bit(unsigned long nr,
@@ -273,7 +273,7 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is non-atomic and can be reordered.  
+ * This operation is non-atomic and can be reordered.
  * If two examples of this operation race, one can appear to succeed
  * but actually fail.  You must protect multiple accesses with a lock.
  */
@@ -599,7 +599,7 @@
 #define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr), (size))
 #define ext2_find_next_zero_bit(addr, size, offset) \
                 find_next_zero_bit((addr), (size), (offset))
- 
+
 #endif /* !(__MIPSEB__) */
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/bootinfo.h linux-2.4.20/include/asm-mips64/bootinfo.h
--- linux-2.4.19/include/asm-mips64/bootinfo.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/bootinfo.h	2002-10-29 11:18:33.000000000 +0000
@@ -49,7 +49,7 @@
 #define MACH_OLIVETTI_M700      2	/* Olivetti M700-10 (-15 ??)    */
 
 /*
- * Valid machtype for group DEC 
+ * Valid machtype for group DEC
  */
 #define MACH_DSUNKNOWN		0
 #define MACH_DS23100		1	/* DECstation 2100 or 3100	*/
@@ -96,10 +96,11 @@
 /*
  * Valid machtype for group NEC DDB
  */
-#define MACH_NEC_DDB5074	 0	/* NEC DDB Vrc-5074 */
-#define MACH_NEC_DDB5476         1      /* NEC DDB Vrc-5476 */
-#define MACH_NEC_DDB5477         2      /* NEC DDB Vrc-5477 */
-#define MACH_NEC_ROCKHOPPER      3      /* Rockhopper base board */
+#define MACH_NEC_DDB5074	0	/* NEC DDB Vrc-5074 */
+#define MACH_NEC_DDB5476	1	/* NEC DDB Vrc-5476 */
+#define MACH_NEC_DDB5477	2	/* NEC DDB Vrc-5477 */
+#define MACH_NEC_ROCKHOPPER	3	/* Rockhopper base board */
+#define MACH_NEC_ROCKHOPPERII	4	/* Rockhopper II base board */
 
 /*
  * Valid machtype for group BAGET
@@ -121,17 +122,18 @@
 /*
  * Valid machtype for group MOMENCO
  */
-#define MACH_MOMENCO_OCELOT	0
- 
+#define MACH_MOMENCO_OCELOT		0
+#define MACH_MOMENCO_OCELOT_G		1
+
 /*
  * Valid machtype for group ITE
  */
 #define MACH_QED_4N_S01B	0	/* ITE8172 based eval board */
- 
+
 /*
  * Valid machtype for group Globespan
  */
-#define MACH_IVR       0                  /* IVR eval board */
+#define MACH_IVR		0	/* IVR eval board */
 
 /*
  * Valid machtype for group PHILIPS
@@ -150,18 +152,21 @@
 #define MACH_PALLAS		0
 #define MACH_TOPAS		1
 #define MACH_JMR		2
-#define MACH_TOSHIBA_JMR3927    3      /* JMR-TX3927 CPU/IO board */
+#define MACH_TOSHIBA_JMR3927	3	/* JMR-TX3927 CPU/IO board */
 
 /*
  * Valid machtype for group Alchemy
  */
-#define MACH_PB1000	0	         /* Au1000-based eval board */
-#define MACH_PB1500	1	         /* Au1500-based eval board */
- 
+#define MACH_PB1000		0	/* Au1000-based eval board */
+#define MACH_PB1100		1	/* Au1100-based eval board */
+#define MACH_PB1500		2	/* Au1500-based eval board */
+
 /*
  * Valid machtype for group NEC_VR41XX
  */
-#define MACH_NEC_OSPREY                0       /* Osprey eval board */
+#define MACH_NEC_OSPREY		0	/* Osprey eval board */
+#define MACH_NEC_EAGLE		1	/* NEC Eagle/Hawk board */
+#define MACH_ZAO_CAPCELLA	2	/* ZAO Networks Capcella */
 
 #define CL_SIZE			(256)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/cache.h linux-2.4.20/include/asm-mips64/cache.h
--- linux-2.4.19/include/asm-mips64/cache.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/cache.h	2002-10-29 11:18:40.000000000 +0000
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1997, 1998, 1999 Ralf Baechle
+ * Copyright (C) 1997, 98, 99, 2000 Ralf Baechle
  * Copyright (C) 1999 Silicon Graphics, Inc.
  */
 #ifndef _ASM_CACHE_H
@@ -23,7 +23,17 @@
 };
 #endif /* !__ASSEMBLY__ */
 
-/* bytes per L1 cache line */
-#define L1_CACHE_BYTES		(1 << CONFIG_L1_CACHE_SHIFT)
+/*
+ * Flag definitions
+ */
+#define MIPS_CACHE_NOT_PRESENT 0x00000001
+
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_R6000) || defined(CONFIG_CPU_TX39XX)
+#define L1_CACHE_BYTES		16
+#else
+#define L1_CACHE_BYTES 		32	/* A guess */
+#endif
+
+#define SMP_CACHE_BYTES		L1_CACHE_BYTES
 
 #endif /* _ASM_CACHE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/checksum.h linux-2.4.20/include/asm-mips64/checksum.h
--- linux-2.4.19/include/asm-mips64/checksum.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/checksum.h	2002-10-29 11:18:35.000000000 +0000
@@ -87,7 +87,7 @@
 
  	return sum;
 }
- 
+
 /*
  *	This is a version of ip_compute_csum() optimized for IP headers,
  *	which always checksum on 4 octet boundaries.
@@ -202,7 +202,7 @@
 						     struct in6_addr *daddr,
 						     __u32 len,
 						     unsigned short proto,
-						     unsigned int sum) 
+						     unsigned int sum)
 {
 	__asm__(
 	".set\tnoreorder\t\t\t# csum_ipv6_magic\n\t"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/cpu.h linux-2.4.20/include/asm-mips64/cpu.h
--- linux-2.4.19/include/asm-mips64/cpu.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/cpu.h	2002-10-29 11:18:33.000000000 +0000
@@ -9,8 +9,8 @@
 
 #include <asm/cache.h>
 
-/* Assigned Company values for bits 23:16 of the PRId Register  
-   (CP0 register 15, select 0).  As of the MIPS32 and MIPS64 specs from 
+/* Assigned Company values for bits 23:16 of the PRId Register
+   (CP0 register 15, select 0).  As of the MIPS32 and MIPS64 specs from
    MTI, the PRId register is defined in this (backwards compatible)
    way:
 
@@ -21,7 +21,7 @@
 
    I don't have docs for all the previous processors, but my impression is
    that bits 16-23 have been 0 for all MIPS processors before the MIPS32/64
-   spec.  
+   spec.
 */
 
 #define PRID_COMP_LEGACY       0x000000
@@ -87,6 +87,12 @@
 #define PRID_REV_TX3912 	0x0010
 #define PRID_REV_TX3922 	0x0030
 #define PRID_REV_TX3927 	0x0040
+#define PRID_REV_VR4111		0x0050
+#define PRID_REV_VR4181		0x0050	/* Same as VR4111 */
+#define PRID_REV_VR4121		0x0060
+#define PRID_REV_VR4122		0x0070
+#define PRID_REV_VR4181A	0x0070	/* Same as VR4122 */
+#define PRID_REV_VR4131		0x0080
 
 /*
  * FPU implementation/revision register (CP1 control register 0).
@@ -100,6 +106,10 @@
 #define FPIR_IMP_NONE		0x0000
 
 #ifndef __ASSEMBLY__
+
+extern void cpu_probe(void);
+extern void cpu_report(void);
+
 /*
  * Capability and feature descriptor structure for MIPS CPU
  */
@@ -128,7 +138,8 @@
 	CPU_RM7000, CPU_R5432, CPU_4KC, CPU_5KC, CPU_R4310, CPU_SB1,
 	CPU_TX3912, CPU_TX3922, CPU_TX3927, CPU_AU1000, CPU_4KEC, CPU_4KSC,
 	CPU_VR41XX, CPU_R5500, CPU_TX49XX, CPU_TX39XX, CPU_AU1500, CPU_20KC,
-	CPU_LAST
+	CPU_VR4111, CPU_VR4121, CPU_VR4122, CPU_VR4131, CPU_VR4181, CPU_VR4181A,
+	CPU_AU1100, CPU_LAST
 };
 
 #endif /* !__ASSEMBLY__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/delay.h linux-2.4.20/include/asm-mips64/delay.h
--- linux-2.4.19/include/asm-mips64/delay.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/delay.h	2002-10-29 11:18:50.000000000 +0000
@@ -11,6 +11,7 @@
 #define _ASM_DELAY_H
 
 #include <linux/config.h>
+#include <asm/param.h>
 
 extern unsigned long loops_per_jiffy;
 
@@ -40,7 +41,11 @@
 {
 	unsigned long lo;
 
+#if (HZ == 100)
 	usecs *= 0x00068db8bac710cbUL;		/* 2**64 / (1000000 / HZ) */
+#elif (HZ == 128)
+	usecs *= 0x0008637bd05af6c6UL;		/* 2**64 / (1000000 / HZ) */
+#endif
 	__asm__("dmultu\t%2,%3"
 		:"=h" (usecs), "=l" (lo)
 		:"r" (usecs),"r" (lpj));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/dma.h linux-2.4.20/include/asm-mips64/dma.h
--- linux-2.4.19/include/asm-mips64/dma.h	2000-07-12 22:15:10.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/dma.h	2002-10-29 11:18:32.000000000 +0000
@@ -43,7 +43,7 @@
  *  - page registers for 5-7 don't use data bit 0, represent 128K pages
  *  - page registers for 0-3 use bit 0, represent 64K pages
  *
- * DMA transfers are limited to the lower 16MB of _physical_ memory.  
+ * DMA transfers are limited to the lower 16MB of _physical_ memory.
  * Note that addresses loaded into registers must be _physical_ addresses,
  * not logical addresses (which may differ if paging is active).
  *
@@ -53,7 +53,7 @@
  *    |  ...  |   |  ... |   |  ... |
  *    |  ...  |   |  ... |   |  ... |
  *    |  ...  |   |  ... |   |  ... |
- *   P7  ...  P0  A7 ... A0  A7 ... A0   
+ *   P7  ...  P0  A7 ... A0  A7 ... A0
  * |    Page    | Addr MSB | Addr LSB |   (DMA registers)
  *
  *  Address mapping for channels 5-7:
@@ -62,7 +62,7 @@
  *    |  ...  |   \   \   ... \  \  \  ... \  \
  *    |  ...  |    \   \   ... \  \  \  ... \  (not used)
  *    |  ...  |     \   \   ... \  \  \  ... \
- *   P7  ...  P1 (0) A7 A6  ... A0 A7 A6 ... A0   
+ *   P7  ...  P1 (0) A7 A6  ... A0 A7 A6 ... A0
  * |      Page      |  Addr MSB   |  Addr LSB  |   (DMA registers)
  *
  * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses
@@ -71,7 +71,7 @@
  *
  * Transfer count (_not # bytes_) is limited to 64K, represented as actual
  * count - 1 : 64K => 0xFFFF, 1 => 0x0000.  Thus, count is always 1 or more,
- * and up to 128K bytes may be transferred on channels 5-7 in one operation. 
+ * and up to 128K bytes may be transferred on channels 5-7 in one operation.
  *
  */
 
@@ -83,7 +83,13 @@
  * Deskstations or Acer PICA but not the much more versatile DMA logic used
  * for the local devices on Acer PICA or Magnums.
  */
+#ifdef CONFIG_SGI_IP22
+/* Horrible hack to have a correct DMA window on IP22 */
+#include <asm/sgi/sgimc.h>
+#define MAX_DMA_ADDRESS		(PAGE_OFFSET + SGIMC_SEG0_BADDR + 0x01000000)
+#else
 #define MAX_DMA_ADDRESS		(PAGE_OFFSET + 0x01000000)
+#endif
 
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE	0x00	/* 8 bit slave DMA, channels 0..3 */
@@ -142,6 +148,7 @@
 #define DMA_MODE_WRITE	0x48	/* memory to I/O, no autoinit, increment, single mode */
 #define DMA_MODE_CASCADE 0xC0   /* pass thru DREQ->HRQ, DACK<-HLDA only */
 
+#define DMA_AUTOINIT	0x10
 
 extern spinlock_t  dma_spin_lock;
 
@@ -286,7 +293,7 @@
 
 	count = 1 + dma_inb(io_port);
 	count += dma_inb(io_port) << 8;
-	
+
 	return (dmanr<=3)? count : (count<<1);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/elf.h linux-2.4.20/include/asm-mips64/elf.h
--- linux-2.4.19/include/asm-mips64/elf.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/elf.h	2002-10-29 11:18:31.000000000 +0000
@@ -9,21 +9,23 @@
 #include <asm/ptrace.h>
 #include <asm/user.h>
 
-#ifndef ELF_ARCH
-/* ELF register definitions */
-#define ELF_NGREG	45
-#define ELF_NFPREG	33
-
-/* ELF header e_flags defines. MIPS architecture level. */
+/* ELF header e_flags defines. */
+/* MIPS architecture level. */
 #define EF_MIPS_ARCH_1      0x00000000  /* -mips1 code.  */
 #define EF_MIPS_ARCH_2      0x10000000  /* -mips2 code.  */
 #define EF_MIPS_ARCH_3      0x20000000  /* -mips3 code.  */
 #define EF_MIPS_ARCH_4      0x30000000  /* -mips4 code.  */
 #define EF_MIPS_ARCH_5      0x40000000  /* -mips5 code.  */
-#define EF_MIPS_ARCH_32     0x60000000  /* MIPS32 code.  */
-#define EF_MIPS_ARCH_64     0x70000000  /* MIPS64 code.  */
-#define EF_MIPS_ARCH_32R2   0x80000000  /* MIPS32 code.  */
-#define EF_MIPS_ARCH_64R2   0x90000000  /* MIPS64 code.  */
+#define EF_MIPS_ARCH_32     0x50000000  /* MIPS32 code.  */
+#define EF_MIPS_ARCH_64     0x60000000  /* MIPS64 code.  */
+/* The ABI of a file. */
+#define EF_MIPS_ABI_O32     0x00001000  /* O32 ABI.  */
+#define EF_MIPS_ABI_O64     0x00002000  /* O32 extended for 64 bit.  */
+
+#ifndef ELF_ARCH
+/* ELF register definitions */
+#define ELF_NGREG	45
+#define ELF_NFPREG	33
 
 typedef unsigned long elf_greg_t;
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
@@ -41,14 +43,9 @@
 									\
 	if (__h->e_machine != EM_MIPS)					\
 		__res = 0;						\
-	if (sizeof(elf_caddr_t) == 8 &&					\
-	    __h->e_ident[EI_CLASS] == ELFCLASS32)			\
-	        __res = 0;						\
-	if (((__h->e_flags & EF_MIPS_ARCH) != EF_MIPS_ARCH_1) &&	\
-	    ((__h->e_flags & EF_MIPS_ARCH) != EF_MIPS_ARCH_2) &&	\
-	    ((__h->e_flags & EF_MIPS_ARCH) != EF_MIPS_ARCH_32) &&	\
-	    ((__h->e_flags & EF_MIPS_ARCH) != EF_MIPS_ARCH_32R2))	\
-                __res = 0;						\
+	if ((__h->e_ident[EI_CLASS] == ELFCLASS32) &&			\
+	    ((__h->e_flags & EF_MIPS_ABI2) == 0))			\
+		__res = 0;						\
 									\
 	__res;								\
 })
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/exception.h linux-2.4.20/include/asm-mips64/exception.h
--- linux-2.4.19/include/asm-mips64/exception.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/exception.h	2002-10-29 11:18:33.000000000 +0000
@@ -70,7 +70,7 @@
 	__BUILD_\verbose \exception
 	move	a0, sp
 	jal	do_\handler
-	j	ret_from_sys_call
+	j	ret_from_exception
 	 nop
 	END(handle_\exception)
 	.endm
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/fcntl.h linux-2.4.20/include/asm-mips64/fcntl.h
--- linux-2.4.19/include/asm-mips64/fcntl.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/fcntl.h	2002-10-29 11:18:31.000000000 +0000
@@ -67,7 +67,7 @@
 /* operations for bsd flock(), also used by the kernel implementation */
 #define LOCK_SH		1	/* shared lock */
 #define LOCK_EX		2	/* exclusive lock */
-#define LOCK_NB		4	/* or'd with one of the above to prevent		XXXXXXXXXXXXXXXXXX
+#define LOCK_NB		4	/* or'd with one of the above to prevent
 				   blocking */
 #define LOCK_UN		8	/* remove lock */
 
@@ -81,12 +81,23 @@
 	short l_whence;
 	__kernel_off_t l_start;
 	__kernel_off_t l_len;
-	long  l_sysid;			/* XXXXXXXXXXXXXXXXXXXXXXXXX */
+	long  l_sysid;
 	__kernel_pid_t l_pid;
-	long  pad[4];			/* ZZZZZZZZZZZZZZZZZZZZZZZZZZ */
+	long  pad[4];
 } flock_t;
 
 #ifdef __KERNEL__
+struct flock32 {				/* for 32-bit compat code */
+	short	l_type;
+	short	l_whence;
+	__kernel_off_t32 l_start;
+	__kernel_off_t32 l_len;
+	__s32	l_sysid;
+	__kernel_pid_t32 l_pid;
+	short	__unused;
+	__s32	pad[4];
+};
+
 #define flock64		flock
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/gdb-stub.h linux-2.4.20/include/asm-mips64/gdb-stub.h
--- linux-2.4.19/include/asm-mips64/gdb-stub.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/gdb-stub.h	2002-10-29 11:18:40.000000000 +0000
@@ -57,7 +57,7 @@
 #define GDB_FR_REG29		((GDB_FR_REG28) + 4)		/* 29 */
 #define GDB_FR_REG30		((GDB_FR_REG29) + 4)		/* 30 */
 #define GDB_FR_REG31		((GDB_FR_REG30) + 4)		/* 31 */
-	
+
 /*
  * Saved special registers
  */
@@ -180,7 +180,7 @@
 	 */
 	long	frame_ptr;
 	long    dummy;		/* unused */
-	
+
 	/*
 	 * saved cp0 registers
 	 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/gfx.h linux-2.4.20/include/asm-mips64/gfx.h
--- linux-2.4.19/include/asm-mips64/gfx.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/gfx.h	2002-10-29 11:18:33.000000000 +0000
@@ -6,7 +6,7 @@
  * This is the user-visible SGI GFX interface.
  *
  * This must be used verbatim into the GNU libc.  It does not include
- * any kernel-only bits on it.  
+ * any kernel-only bits on it.
  *
  * miguel@nuclecu.unam.mx
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/gt64120.h linux-2.4.20/include/asm-mips64/gt64120.h
--- linux-2.4.19/include/asm-mips64/gt64120.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/gt64120.h	2002-10-29 11:18:33.000000000 +0000
@@ -60,7 +60,7 @@
 #define GT_PCI1M0REMAP_OFS	0x110
 #define GT_PCI1M1REMAP_OFS	0x118
 
-#define GT_SCS0LD_OFS		0x400	
+#define GT_SCS0LD_OFS		0x400
 #define GT_SCS0HD_OFS		0x404
 #define GT_SCS1LD_OFS		0x408
 #define GT_SCS1HD_OFS		0x40c
@@ -324,7 +324,7 @@
 #define GT_PCI0_BARE_SWSCS32DIS_SHF	1
 #define GT_PCI0_BARE_SWSCS32DIS_MSK	(MSK(1) << GT_PCI0_BARE_SWSCS32DIS_SHF)
 #define GT_PCI0_BARE_SWSCS32DIS_BIT	GT_PCI0_BARE_SWSCS32DIS_MSK
-	
+
 #define GT_PCI0_BARE_SWSCS10DIS_SHF	2
 #define GT_PCI0_BARE_SWSCS10DIS_MSK	(MSK(1) << GT_PCI0_BARE_SWSCS10DIS_SHF)
 #define GT_PCI0_BARE_SWSCS10DIS_BIT	GT_PCI0_BARE_SWSCS10DIS_MSK
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/ide.h linux-2.4.20/include/asm-mips64/ide.h
--- linux-2.4.19/include/asm-mips64/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/ide.h	2002-10-29 11:18:31.000000000 +0000
@@ -18,6 +18,7 @@
 #ifdef __KERNEL__
 
 #include <linux/config.h>
+#include <asm/io.h>
 
 #ifndef MAX_HWIFS
 # ifdef CONFIG_BLK_DEV_IDEPCI
@@ -79,11 +80,19 @@
 typedef union {
 	unsigned all			: 8;	/* all of the bits together */
 	struct {
+#ifdef __MIPSEB__
+		unsigned bit7           : 1;    /* always 1 */
+		unsigned lba            : 1;    /* using LBA instead of CHS */
+		unsigned bit5           : 1;    /* always 1 */
+		unsigned unit           : 1;    /* drive select number, 0 or 1 */
+		unsigned head           : 4;    /* always zeros here */
+#else
 		unsigned head		: 4;	/* always zeros here */
 		unsigned unit		: 1;	/* drive select number, 0 or 1 */
 		unsigned bit5		: 1;	/* always 1 */
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
+#endif
 	} b;
 } select_t;
 
@@ -139,54 +148,142 @@
 
 #if defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)
 
-#ifdef insl
-#undef insl
-#endif
-#ifdef outsl
-#undef outsl
-#endif
+/* get rid of defs from io.h - ide has its private and conflicting versions */
 #ifdef insw
 #undef insw
 #endif
 #ifdef outsw
 #undef outsw
 #endif
+#ifdef insl
+#undef insl
+#endif
+#ifdef outsl
+#undef outsl
+#endif
 
-#define insw(p,a,c)							\
-do {									\
-	unsigned short *ptr = (unsigned short *)(a);			\
-	unsigned int i = (c);						\
-	while (i--)							\
-		*ptr++ = inw(p);					\
-} while (0)
-#define insl(p,a,c)							\
-do {									\
-	unsigned long *ptr = (unsigned long *)(a);			\
-	unsigned int i = (c);						\
-	while (i--)							\
-		*ptr++ = inl(p);					\
-} while (0)
-#define outsw(p,a,c)							\
-do {									\
-	unsigned short *ptr = (unsigned short *)(a);			\
-	unsigned int i = (c);						\
-	while (i--)							\
-		outw(*ptr++, (p));					\
-} while (0)
-#define outsl(p,a,c) {							\
-	unsigned long *ptr = (unsigned long *)(a);			\
-	unsigned int i = (c);						\
-	while (i--)							\
-		outl(*ptr++, (p));					\
-} while (0)
+#define insw(port, addr, count) ide_insw(port, addr, count)
+#define insl(port, addr, count) ide_insl(port, addr, count)
+#define outsw(port, addr, count) ide_outsw(port, addr, count)
+#define outsl(port, addr, count) ide_outsl(port, addr, count)
 
-#endif /* defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)  */
+static inline void ide_insw(unsigned long port, void *addr, unsigned int count)
+{
+       while (count--) {
+               *(u16 *)addr = *(volatile u16 *)(mips_io_port_base + port);
+               addr += 2;
+       }
+}
+
+static inline void ide_outsw(unsigned long port, void *addr, unsigned int count)
+{
+       while (count--) {
+               *(volatile u16 *)(mips_io_port_base + (port)) = *(u16 *)addr;
+               addr += 2;
+       }
+}
+
+static inline void ide_insl(unsigned long port, void *addr, unsigned int count)
+{
+       while (count--) {
+               *(u32 *)addr = *(volatile u32 *)(mips_io_port_base + port);
+               addr += 4;
+       }
+}
+
+static inline void ide_outsl(unsigned long port, void *addr, unsigned int count)
+{
+       while (count--) {
+               *(volatile u32 *)(mips_io_port_base + (port)) = *(u32 *)addr;
+               addr += 4;
+       }
+}
+
+#define T_CHAR          (0x0000)        /* char:  don't touch  */
+#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
+#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
+#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
+
+#define T_MASK_TYPE     (0xc000)
+#define T_MASK_COUNT    (0x3fff)
+
+#define D_CHAR(cnt)     (T_CHAR  | (cnt))
+#define D_SHORT(cnt)    (T_SHORT | (cnt))
+#define D_INT(cnt)      (T_INT   | (cnt))
+#define D_TEXT(cnt)     (T_TEXT  | (cnt))
+
+static u_short driveid_types[] = {
+	D_SHORT(10),	/* config - vendor2 */
+	D_TEXT(20),	/* serial_no */
+	D_SHORT(3),	/* buf_type - ecc_bytes */
+	D_TEXT(48),	/* fw_rev - model */
+	D_CHAR(2),	/* max_multsect - vendor3 */
+	D_SHORT(1),	/* dword_io */
+	D_CHAR(2),	/* vendor4 - capability */
+	D_SHORT(1),	/* reserved50 */
+	D_CHAR(4),	/* vendor5 - tDMA */
+	D_SHORT(4),	/* field_valid - cur_sectors */
+	D_INT(1),	/* cur_capacity */
+	D_CHAR(2),	/* multsect - multsect_valid */
+	D_INT(1),	/* lba_capacity */
+	D_SHORT(194)	/* dma_1word - reservedyy */
+};
+
+#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
+
+static __inline__ void ide_fix_driveid(struct hd_driveid *id)
+{
+	u_char *p = (u_char *)id;
+	int i, j, cnt;
+	u_char t;
+
+	for (i = 0; i < num_driveid_types; i++) {
+		cnt = driveid_types[i] & T_MASK_COUNT;
+		switch (driveid_types[i] & T_MASK_TYPE) {
+		case T_CHAR:
+			p += cnt;
+			break;
+		case T_SHORT:
+			for (j = 0; j < cnt; j++) {
+				t = p[0];
+				p[0] = p[1];
+				p[1] = t;
+				p += 2;
+			}
+			break;
+		case T_INT:
+			for (j = 0; j < cnt; j++) {
+				t = p[0];
+				p[0] = p[3];
+				p[3] = t;
+				t = p[1];
+				p[1] = p[2];
+				p[2] = t;
+				p += 4;
+			}
+			break;
+		case T_TEXT:
+			for (j = 0; j < cnt; j += 2) {
+				t = p[0];
+				p[0] = p[1];
+				p[1] = t;
+				p += 2;
+			}
+			break;
+		};
+	}
+}
+
+#else /* defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)  */
+
+#define ide_fix_driveid(id)		do {} while (0)
+
+#endif
 
 /*
  * The following are not needed for the non-m68k ports
  */
 #define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/io.h linux-2.4.20/include/asm-mips64/io.h
--- linux-2.4.19/include/asm-mips64/io.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/io.h	2002-10-29 11:18:31.000000000 +0000
@@ -13,6 +13,7 @@
 #include <linux/config.h>
 #include <asm/addrspace.h>
 #include <asm/page.h>
+#include <asm/byteorder.h>
 
 #ifdef CONFIG_MIPS_ATLAS
 #include <asm/mips-boards/io.h>
@@ -35,11 +36,19 @@
 #endif
 
 #ifdef CONFIG_SIBYTE_SB1250
-#include <asm/sibyte/sb1250_io.h>
+#include <asm/sibyte/io.h>
 #endif
 
+#ifdef CONFIG_SGI_IP27
 extern unsigned long bus_to_baddr[256];
 
+#define bus_to_baddr(hwdev, addr) (bus_to_baddr[(hwdev)->bus->number] + (addr))
+#define baddr_to_bus(hwdev, addr) ((addr) - bus_to_baddr[(hwdev)->bus->number])
+#else
+#define bus_to_baddr(hwdev, addr) (addr)
+#define baddr_to_bus(hwdev, addr) (addr)
+#endif
+
 /*
  * Slowdown I/O port space accesses for antique hardware.
  */
@@ -52,7 +61,13 @@
 #if defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)
 
 #define __ioswab8(x) (x)
+#ifdef CONFIG_SGI_IP22
+/* IP22 seems braindead enough to swap 16bits values in hardware, but
+   not 32bits.  Go figure... Can't tell without documentation. */
+#define __ioswab16(x) (x)
+#else
 #define __ioswab16(x) swab16(x)
+#endif
 #define __ioswab32(x) swab32(x)
 
 #else
@@ -77,7 +92,7 @@
  *     make bus memory CPU accessible via the readb/readw/readl/writeb/
  *     writew/writel functions and the other mmio helpers. The returned
  *     address is not guaranteed to be usable directly as a virtual
- *     address. 
+ *     address.
  */
 static inline void * ioremap(unsigned long offset, unsigned long size)
 {
@@ -93,11 +108,11 @@
  *     make bus memory CPU accessible via the readb/readw/readl/writeb/
  *     writew/writel functions and the other mmio helpers. The returned
  *     address is not guaranteed to be usable directly as a virtual
- *     address. 
+ *     address.
  *
  *     This version of ioremap ensures that the memory is marked uncachable
  *     on the CPU as well as honouring existing caching rules from things like
- *     the PCI bus. Note that there are other caches and buffers on many 
+ *     the PCI bus. Note that there are other caches and buffers on many
  *     busses. In paticular driver authors should read up on PCI writes
  *
  *     It's useful if some control registers are in such an area and
@@ -112,26 +127,23 @@
 {
 }
 
-/*
- * This assumes sane hardware.  The Origin is.
- */
-#define readb(addr)		(*(volatile unsigned char *) (addr))
-#define readw(addr)		(*(volatile unsigned short *) (addr))
-#define readl(addr)		(*(volatile unsigned int *) (addr))
+#define readb(addr)		(*(volatile unsigned char *)(addr))
+#define readw(addr)		__ioswab16((*(volatile unsigned short *)(addr)))
+#define readl(addr)		__ioswab32((*(volatile unsigned int *)(addr)))
 
 #define __raw_readb(addr)	(*(volatile unsigned char *)(addr))
 #define __raw_readw(addr)	(*(volatile unsigned short *)(addr))
 #define __raw_readl(addr)	(*(volatile unsigned int *)(addr))
 
-#define writeb(b,addr)		(*(volatile unsigned char *) (addr) = (b))
-#define writew(w,addr)		(*(volatile unsigned short *) (addr) = (w))
-#define writel(l,addr)		(*(volatile unsigned int *) (addr) = (l))
+#define writeb(b,addr) ((*(volatile unsigned char *)(addr)) = (__ioswab8(b)))
+#define writew(b,addr) ((*(volatile unsigned short *)(addr)) = (__ioswab16(b)))
+#define writel(b,addr) ((*(volatile unsigned int *)(addr)) = (__ioswab32(b)))
 
 #define __raw_writeb(b,addr)	((*(volatile unsigned char *)(addr)) = (b))
 #define __raw_writew(w,addr)	((*(volatile unsigned short *)(addr)) = (w))
 #define __raw_writel(l,addr)	((*(volatile unsigned int *)(addr)) = (l))
 
-#define memset_io(a,b,c)	memset((void *) a,(b),(c))
+#define memset_io(a,b,c)	memset((void *)(a),(b),(c))
 #define memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
 #define memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
 
@@ -171,7 +183,7 @@
  *
  *     The returned physical address is the physical (CPU) mapping for
  *     the memory address given. It is only valid to use this function on
- *     addresses directly mapped or allocated via kmalloc. 
+ *     addresses directly mapped or allocated via kmalloc.
  *
  *     This function does not give bus mappings for DMA transfers. In
  *     almost all conceivable cases a device driver should not be using
@@ -253,7 +265,7 @@
 
 /*
  *     check_signature         -       find BIOS signatures
- *     @io_addr: mmio address to check 
+ *     @io_addr: mmio address to check
  *     @signature:  signature block
  *     @length: length of signature
  *
@@ -280,7 +292,7 @@
 
 /*
  *     isa_check_signature             -       find BIOS signatures
- *     @io_addr: mmio address to check 
+ *     @io_addr: mmio address to check
  *     @signature:  signature block
  *     @length: length of signature
  *
@@ -307,203 +319,130 @@
 	return retval;
 }
 
+#define outb(val,port)							\
+do {									\
+	*(volatile u8 *)(mips_io_port_base + (port)) = __ioswab8(val);	\
+} while(0)
+
+#define outw(val,port)							\
+do {									\
+	*(volatile u16 *)(mips_io_port_base + (port)) = __ioswab16(val);\
+} while(0)
+
+#define outl(val,port)							\
+do {									\
+	*(volatile u32 *)(mips_io_port_base + (port)) = __ioswab32(val);\
+} while(0)
+
+#define outb_p(val,port)						\
+do {									\
+	*(volatile u8 *)(mips_io_port_base + (port)) = __ioswab8(val);	\
+	SLOW_DOWN_IO;							\
+} while(0)
+
+#define outw_p(val,port)						\
+do {									\
+	*(volatile u16 *)(mips_io_port_base + (port)) = __ioswab16(val);\
+	SLOW_DOWN_IO;							\
+} while(0)
+
+#define outl_p(val,port)						\
+do {									\
+	*(volatile u32 *)(mips_io_port_base + (port)) = __ioswab32(val);\
+	SLOW_DOWN_IO;							\
+} while(0)
 
-/*
- * Talk about misusing macros..
- */
+static inline unsigned char inb(unsigned long port)
+{
+	return __ioswab8(*(volatile u8 *)(mips_io_port_base + port));
+}
+
+static inline unsigned short inw(unsigned long port)
+{
+	return __ioswab16(*(volatile u16 *)(mips_io_port_base + port));
+}
+
+static inline unsigned int inl(unsigned long port)
+{
+	return __ioswab32(*(volatile u32 *)(mips_io_port_base + port));
+}
+
+static inline unsigned char inb_p(unsigned long port)
+{
+	u8 __val;
 
-#define __OUT1(s) \
-static inline void __out##s(unsigned int value, unsigned long port) {
+	__val = *(volatile u8 *)(mips_io_port_base + port);
+	SLOW_DOWN_IO;
 
-#define __OUT2(m) \
-__asm__ __volatile__ ("s" #m "\t%0,%1(%2)"
+	return __ioswab8(__val);
+}
+
+static inline unsigned short inw_p(unsigned long port)
+{
+	u16 __val;
 
-#define __OUT(m,s) \
-__OUT1(s) __OUT2(m) : : "r" (value), "i" (0), "r" (mips_io_port_base+port)); } \
-__OUT1(s##c) __OUT2(m) : : "r" (value), "ir" (port), "r" (mips_io_port_base)); } \
-__OUT1(s##_p) __OUT2(m) : : "r" (value), "i" (0), "r" (mips_io_port_base+port)); \
-	SLOW_DOWN_IO; } \
-__OUT1(s##c_p) __OUT2(m) : : "r" (value), "ir" (port), "r" (mips_io_port_base)); \
-	SLOW_DOWN_IO; }
-
-#define __IN1(t,s) \
-static inline t __in##s(unsigned long port) { t _v;
-
-/*
- * Required nops will be inserted by the assembler
- */
-#define __IN2(m) \
-__asm__ __volatile__ ("l" #m "\t%0,%1(%2)"
-
-#define __IN(t,m,s) \
-__IN1(t,s) __IN2(m) : "=r" (_v) : "i" (0), "r" (mips_io_port_base+port)); return _v; } \
-__IN1(t,s##c) __IN2(m) : "=r" (_v) : "ir" (port), "r" (mips_io_port_base)); return _v; } \
-__IN1(t,s##_p) __IN2(m) : "=r" (_v) : "i" (0), "r" (mips_io_port_base+port)); SLOW_DOWN_IO; return _v; } \
-__IN1(t,s##c_p) __IN2(m) : "=r" (_v) : "ir" (port), "r" (mips_io_port_base)); SLOW_DOWN_IO; return _v; }
-
-#define __INS1(s) \
-static inline void __ins##s(unsigned long port, void * addr, unsigned long count) {
-
-#define __INS2(m) \
-if (count) \
-__asm__ __volatile__ ( \
-	".set\tnoreorder\n\t" \
-	".set\tnoat\n" \
-	"1:\tl" #m "\t$1, %4(%5)\n\t" \
-	"dsubu\t%1, 1\n\t" \
-	"s" #m "\t$1,(%0)\n\t" \
-	"bnez\t%1, 1b\n\t" \
-	"daddiu\t%0, %6\n\t" \
-	".set\tat\n\t" \
-	".set\treorder"
-
-#define __INS(m,s,i) \
-__INS1(s) __INS2(m) \
-	: "=r" (addr), "=r" (count) \
-	: "0" (addr), "1" (count), "i" (0), "r" (mips_io_port_base+port), \
-	  "I" (i));} \
-__INS1(s##c) __INS2(m) \
-	: "=r" (addr), "=r" (count) \
-	: "0" (addr), "1" (count), "ir" (port), "r" (mips_io_port_base), \
-	  "I" (i));}
-
-#define __OUTS1(s) \
-static inline void __outs##s(unsigned long port, const void * addr, unsigned long count) {
-
-#define __OUTS2(m) \
-if (count) \
-__asm__ __volatile__ ( \
-	".set\tnoreorder\n\t" \
-	".set\tnoat\n" \
-	"1:\tl" #m "\t$1, (%0)\n\t" \
-	"dsubu\t%1, 1\n\t" \
-	"s" #m "\t$1, %4(%5)\n\t" \
-	"bnez\t%1, 1b\n\t" \
-	"daddiu\t%0, %6\n\t" \
-	".set\tat\n\t" \
-	".set\treorder"
-
-#define __OUTS(m,s,i) \
-__OUTS1(s) __OUTS2(m) \
-	: "=r" (addr), "=r" (count) \
-	: "0" (addr), "1" (count), "i" (0), "r" (mips_io_port_base+port), \
-	  "I" (i));} \
-__OUTS1(s##c) __OUTS2(m) \
-	: "=r" (addr), "=r" (count) \
-	: "0" (addr), "1" (count), "ir" (port), "r" (mips_io_port_base), \
-	  "I" (i));}
-
-__IN(unsigned char,b,b)
-__IN(unsigned short,h,w)
-__IN(unsigned int,w,l)
-
-__OUT(b,b)
-__OUT(h,w)
-__OUT(w,l)
-
-__INS(b,b,1)
-__INS(h,w,2)
-__INS(w,l,4)
-
-__OUTS(b,b,1)
-__OUTS(h,w,2)
-__OUTS(w,l,4)
-
-/*
- * Note that due to the way __builtin_constant_p() works, you
- *  - can't use it inside an inline function (it will never be true)
- *  - you don't have to worry about side effects within the __builtin..
- */
-#define outb(val,port) \
-((__builtin_constant_p((port)^(3)) && ((port)^(3)) < 32768) ? \
-	__outbc((val),(port)^(3)) : \
-	__outb((val),(port)^(3)))
-
-#define inb(port) \
-((__builtin_constant_p((port)^(3)) && ((port)^(3)) < 32768) ? \
-	__inbc((port)^(3)) : \
-	__inb((port)^(3)))
-
-#define outb_p(val,port) \
-((__builtin_constant_p((port)^(3)) && ((port)^(3)) < 32768) ? \
-	__outbc_p((val),(port)^(3)) : \
-	__outb_p((val),(port)^(3)))
-
-#define inb_p(port) \
-((__builtin_constant_p((port)^(3)) && ((port)^(3)) < 32768) ? \
-	__inbc_p((port)^(3)) : \
-	__inb_p((port)^(3)))
-
-#define outw(val,port) \
-((__builtin_constant_p(((port)^(2))) && ((port)^(2)) < 32768) ? \
-	__outwc((val),((port)^(2))) : \
-	__outw((val),((port)^(2))))
-
-#define inw(port) \
-((__builtin_constant_p(((port)^(2))) && ((port)^(2)) < 32768) ? \
-	__inwc((port)^(2)) : \
-	__inw((port)^(2)))
-
-#define outw_p(val,port) \
-((__builtin_constant_p((port)^(2)) && ((port)^(2)) < 32768) ? \
-	__outwc_p((val),(port)^(2)) : \
-	__outw_p((val),(port)^(2)))
-
-#define inw_p(port) \
-((__builtin_constant_p((port)^(2)) && ((port)^(2)) < 32768) ? \
-	__inwc_p((port)^(2)) : \
-	__inw_p((port)^(2)))
-
-#define outl(val,port) \
-((__builtin_constant_p((port)) && (port) < 32768) ? \
-	__outlc((val),(port)) : \
-	__outl((val),(port)))
-
-#define inl(port) \
-((__builtin_constant_p((port)) && (port) < 32768) ? \
-	__inlc(port) : \
-	__inl(port))
-
-#define outl_p(val,port) \
-((__builtin_constant_p((port)) && (port) < 32768) ? \
-	__outlc_p((val),(port)) : \
-	__outl_p((val),(port)))
-
-#define inl_p(port) \
-((__builtin_constant_p((port)) && (port) < 32768) ? \
-	__inlc_p(port) : \
-	__inl_p(port))
-
-
-#define outsb(port,addr,count) \
-((__builtin_constant_p((port)) && (port) < 32768) ? \
-	__outsbc((port),(addr),(count)) : \
-	__outsb ((port),(addr),(count)))
-
-#define insb(port,addr,count) \
-((__builtin_constant_p((port)) && (port) < 32768) ? \
-	__insbc((port),(addr),(count)) : \
-	__insb((port),(addr),(count)))
-
-#define outsw(port,addr,count) \
-((__builtin_constant_p((port)) && (port) < 32768) ? \
-	__outswc((port),(addr),(count)) : \
-	__outsw ((port),(addr),(count)))
-
-#define insw(port,addr,count) \
-((__builtin_constant_p((port)) && (port) < 32768) ? \
-	__inswc((port),(addr),(count)) : \
-	__insw((port),(addr),(count)))
-
-#define outsl(port,addr,count) \
-((__builtin_constant_p((port)) && (port) < 32768) ? \
-	__outslc((port),(addr),(count)) : \
-	__outsl ((port),(addr),(count)))
-
-#define insl(port,addr,count) \
-((__builtin_constant_p((port)) && (port) < 32768) ? \
-	__inslc((port),(addr),(count)) : \
-	__insl((port),(addr),(count)))
+	__val = *(volatile u16 *)(mips_io_port_base + port);
+	SLOW_DOWN_IO;
+
+	return __ioswab16(__val);
+}
+
+static inline unsigned int inl_p(unsigned long port)
+{
+	u32 __val;
+
+	__val = *(volatile u32 *)(mips_io_port_base + port);
+	SLOW_DOWN_IO;
+	return __ioswab32(__val);
+}
+
+static inline void outsb(unsigned long port, void *addr, unsigned int count)
+{
+	while (count--) {
+		outb(*(u8 *)addr, port);
+		addr++;
+	}
+}
+
+static inline void insb(unsigned long port, void *addr, unsigned int count)
+{
+	while (count--) {
+		*(u8 *)addr = inb(port);
+		addr++;
+	}
+}
+
+static inline void outsw(unsigned long port, void *addr, unsigned int count)
+{
+	while (count--) {
+		outw(*(u16 *)addr, port);
+		addr += 2;
+	}
+}
+
+static inline void insw(unsigned long port, void *addr, unsigned int count)
+{
+	while (count--) {
+		*(u16 *)addr = inw(port);
+		addr += 2;
+	}
+}
+
+static inline void outsl(unsigned long port, void *addr, unsigned int count)
+{
+	while (count--) {
+		outl(*(u32 *)addr, port);
+		addr += 4;
+	}
+}
+
+static inline void insl(unsigned long port, void *addr, unsigned int count)
+{
+	while (count--) {
+		*(u32 *)addr = inl(port);
+		addr += 4;
+	}
+}
 
 /*
  * The caches on some architectures aren't dma-coherent and have need to
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/ioctls.h linux-2.4.20/include/asm-mips64/ioctls.h
--- linux-2.4.19/include/asm-mips64/ioctls.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/ioctls.h	2002-10-29 11:18:34.000000000 +0000
@@ -12,7 +12,7 @@
 #include <asm/ioctl.h>
 
 #define TCGETA		0x5401
-#define TCSETA		0x5402
+#define TCSETA		0x5402	/* Clashes with SNDCTL_TMR_START sound ioctl */
 #define TCSETAW		0x5403
 #define TCSETAF		0x5404
 
@@ -66,7 +66,7 @@
 #define TIOCGETP        0x7408
 #define TIOCSETP        0x7409
 #define TIOCSETN        0x740a			/* TIOCSETP wo flush */
- 
+
 /* #define TIOCSETA	_IOW('t', 20, struct termios) set termios struct */
 /* #define TIOCSETAW	_IOW('t', 21, struct termios) drain output, set */
 /* #define TIOCSETAF	_IOW('t', 22, struct termios) drn out, fls in, set */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/ip32/mace.h linux-2.4.20/include/asm-mips64/ip32/mace.h
--- linux-2.4.19/include/asm-mips64/ip32/mace.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/ip32/mace.h	2002-10-29 11:18:40.000000000 +0000
@@ -50,8 +50,8 @@
 #define MACEPCI_SWAPPED_VIEW		0
 #define MACEPCI_NATIVE_VIEW		0x40000000
 #define MACEPCI_IO			0x80000000
-/*#define MACEPCI_HI_MEMORY		0x0000000280000000UL * This mipght be just 0x0000000200000000UL 2G more :) (or maybe it is different between 1.1 & 1.5 */ 
-#define MACEPCI_HI_MEMORY		0x0000000200000000UL /* This mipght be just 0x0000000200000000UL 2G more :) (or maybe it is different between 1.1 & 1.5 */ 
+/*#define MACEPCI_HI_MEMORY		0x0000000280000000UL * This mipght be just 0x0000000200000000UL 2G more :) (or maybe it is different between 1.1 & 1.5 */
+#define MACEPCI_HI_MEMORY		0x0000000200000000UL /* This mipght be just 0x0000000200000000UL 2G more :) (or maybe it is different between 1.1 & 1.5 */
 #define MACEPCI_HI_IO			0x0000000100000000UL
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/ipc.h linux-2.4.20/include/asm-mips64/ipc.h
--- linux-2.4.19/include/asm-mips64/ipc.h	2000-02-25 06:53:35.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/ipc.h	2002-10-29 11:18:50.000000000 +0000
@@ -1,7 +1,7 @@
 #ifndef _ASM_IPC_H
 #define _ASM_IPC_H
 
-/* 
+/*
  * These are used to wrap system calls on MIPS32.
  *
  * See arch/mips/kernel/sysmips.c for ugly details..
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/ipcbuf.h linux-2.4.20/include/asm-mips64/ipcbuf.h
--- linux-2.4.19/include/asm-mips64/ipcbuf.h	2000-02-25 06:53:35.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/ipcbuf.h	2002-10-29 11:18:31.000000000 +0000
@@ -1,7 +1,7 @@
 #ifndef _ASM_IPCBUF_H
 #define _ASM_IPCBUF_H
 
-/* 
+/*
  * The ipc64_perm structure for alpha architecture.
  * Note extra padding because this structure is passed back and forth
  * between kernel and user space.
@@ -18,7 +18,7 @@
 	__kernel_gid_t	gid;
 	__kernel_uid_t	cuid;
 	__kernel_gid_t	cgid;
-	__kernel_mode_t	mode; 
+	__kernel_mode_t	mode;
 	unsigned short	seq;
 	unsigned short	__pad1;
 	unsigned long	__unused1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/irq.h linux-2.4.20/include/asm-mips64/irq.h
--- linux-2.4.19/include/asm-mips64/irq.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/irq.h	2002-10-29 11:18:36.000000000 +0000
@@ -4,7 +4,7 @@
  * for more details.
  *
  * Copyright (C) 1994 by Waldorf GMBH, written by Ralf Baechle
- * Copyright (C) 1995, 96, 97, 98, 1999, 2000 by Ralf Baechle
+ * Copyright (C) 1995, 96, 97, 98, 99, 2000, 01, 02 by Ralf Baechle
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  * Copyright (C) 2001 Kanoj Sarcar
  */
@@ -42,13 +42,21 @@
 #define irq_cannonicalize(irq) (irq)	/* Sane hardware, sane code ... */
 #endif
 
-
 struct irqaction;
 extern int i8259_setup_irq(int irq, struct irqaction * new);
 extern void disable_irq(unsigned int);
+
+#ifdef CONFIG_NEW_IRQ
+extern void disable_irq_nosync(unsigned int);
+#else
+#define disable_irq_nosync	disable_irq
+#endif
+
 extern void enable_irq(unsigned int);
 
 /* Machine specific interrupt initialization  */
 extern void (*irq_setup)(void);
 
+extern void init_generic_irq(void);
+
 #endif /* _ASM_IRQ_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/linux_logo.h linux-2.4.20/include/asm-mips64/linux_logo.h
--- linux-2.4.19/include/asm-mips64/linux_logo.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/linux_logo.h	2002-10-29 11:18:31.000000000 +0000
@@ -17,7 +17,7 @@
  * Serial_console ascii image can be any size,
  * but should contain %s to display the version
  */
- 
+
 #include <linux/init.h>
 #include <linux/version.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/mc146818rtc.h linux-2.4.20/include/asm-mips64/mc146818rtc.h
--- linux-2.4.19/include/asm-mips64/mc146818rtc.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/mc146818rtc.h	2002-10-29 11:18:33.000000000 +0000
@@ -12,9 +12,19 @@
 
 #include <asm/io.h>
 
-#ifndef RTC_PORT
-#define RTC_PORT(x)	(0x70 + (x))
-#endif
+
+/*
+ * This structure defines how to access various features of
+ * different machine types and how to access them.
+ */
+struct rtc_ops {
+	/* How to access the RTC register in a DS1287.  */
+	unsigned char (*rtc_read_data)(unsigned long addr);
+	void (*rtc_write_data)(unsigned char data, unsigned long addr);
+	int (*rtc_bcd_mode)(void);
+};
+
+extern struct rtc_ops *rtc_ops;
 
 /*
  * The yet supported machines all access the RTC index register via
@@ -29,19 +39,8 @@
 #define RTC_ALWAYS_BCD \
 rtc_ops->rtc_bcd_mode()
 
-/*
- * This structure defines how to access various features of
- * different machine types and how to access them.
- */
-struct rtc_ops {
-	/* How to access the RTC register in a DS1287.  */
-	unsigned char (*rtc_read_data)(unsigned long addr);
-	void (*rtc_write_data)(unsigned char data, unsigned long addr);
-	int (*rtc_bcd_mode)(void);
-};
 
-extern struct rtc_ops *rtc_ops;
-
-#define RTC_IRQ 8
+#define RTC_PORT(x)	(0x70 + (x))
+#define RTC_IRQ		8
 
 #endif /* _ASM_MC146818RTC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/mips-boards/atlas.h linux-2.4.20/include/asm-mips64/mips-boards/atlas.h
--- linux-2.4.19/include/asm-mips64/mips-boards/atlas.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/mips-boards/atlas.h	2002-10-29 11:18:40.000000000 +0000
@@ -27,7 +27,7 @@
 
 #include <asm/addrspace.h>
 
-/* 
+/*
  * Atlas RTC-device indirect register access.
  */
 #define ATLAS_RTC_ADR_REG       (KSEG1ADDR(0x1f000800))
@@ -43,7 +43,7 @@
  * Atlas UART register base.
  */
 #define ATLAS_UART_REGS_BASE    (0x1f000900)
-#define ATLAS_BASE_BAUD ( 3686400 / 16 ) 
+#define ATLAS_BASE_BAUD ( 3686400 / 16 )
 
 /*
  * Atlas PSU standby register.
@@ -54,7 +54,7 @@
 /*
  * We make a universal assumption about the way the bootloader (YAMON)
  * have located the Philips SAA9730 chip.
- * This is not ideal, but is needed for setting up remote debugging as 
+ * This is not ideal, but is needed for setting up remote debugging as
  * soon as possible.
  */
 #define ATLAS_SAA9730_REG  (KSEG1ADDR(0x08800000))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/mips-boards/atlasint.h linux-2.4.20/include/asm-mips64/mips-boards/atlasint.h
--- linux-2.4.19/include/asm-mips64/mips-boards/atlasint.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/mips-boards/atlasint.h	2002-10-29 11:18:50.000000000 +0000
@@ -29,8 +29,8 @@
 #define ATLASINT_UART      0
 #define ATLASINT_END      32
 
-/* 
- * Atlas registers are memory mapped on 64-bit aligned boundaries and 
+/*
+ * Atlas registers are memory mapped on 64-bit aligned boundaries and
  * only word access are allowed.
  */
 struct atlas_ictrl_regs {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/mips-boards/bonito64.h linux-2.4.20/include/asm-mips64/mips-boards/bonito64.h
--- linux-2.4.19/include/asm-mips64/mips-boards/bonito64.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/mips-boards/bonito64.h	2002-10-29 11:18:49.000000000 +0000
@@ -11,7 +11,7 @@
  */
 
 /*
- * Bonito Register Map 
+ * Bonito Register Map
  * Copyright (c) 1999 Algorithmics Ltd
  *
  * Algorithmics gives permission for anyone to use and modify this file
@@ -20,7 +20,7 @@
  *
  * Updated copies of this and other files can be found at
  * ftp://ftp.algor.co.uk/pub/bonito/
- * 
+ *
  * Users of the Bonito controller are warmly recommended to contribute
  * any useful changes back to Algorithmics (mail to bonito@algor.co.uk).
  */
@@ -75,7 +75,7 @@
 #define BONITO_PCICFG_BASE		0x1fe80000
 #define BONITO_PCICFG_SIZE		0x00080000
 #define BONITO_PCICFG_TOP		(BONITO_PCICFG_BASE+BONITO_PCICFG_SIZE-1)
- 
+
 
 /* Bonito Register Bases */
 
@@ -184,7 +184,7 @@
 #define BONITO_PCIMAP_CFG		BONITO(BONITO_REGBASE + 0x18)
 
 /* 5. ICU & GPIO regs */
- 
+
 /* GPIO Regs - r/w */
 
 #define BONITO_GPIODATA_OFFSET          0x1c
@@ -231,7 +231,7 @@
 */
 
 /* 7. IDE DMA & Copier */
- 
+
 #define BONITO_CONFIGBASE		0x000
 #define BONITO_BONITOBASE		0x100
 #define BONITO_LDMABASE 		0x200
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/mips-boards/gt64120.h linux-2.4.20/include/asm-mips64/mips-boards/gt64120.h
--- linux-2.4.19/include/asm-mips64/mips-boards/gt64120.h	2001-09-09 17:43:01.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/mips-boards/gt64120.h	2002-10-29 11:18:39.000000000 +0000
@@ -56,7 +56,7 @@
 #define GT_PCI1M1LD_OFS		    0x0b0
 #define GT_PCI1M1HD_OFS		    0x0b8
 
-#define GT_SCS0LD_OFS		    0x400	
+#define GT_SCS0LD_OFS		    0x400
 #define GT_SCS0HD_OFS		    0x404
 #define GT_SCS1LD_OFS		    0x408
 #define GT_SCS1HD_OFS		    0x40c
@@ -260,7 +260,7 @@
 #define GT_PCI0_BARE_SWSCS32DIS_SHF	1
 #define GT_PCI0_BARE_SWSCS32DIS_MSK	(MSK(1) << GT_PCI0_BARE_SWSCS32DIS_SHF)
 #define GT_PCI0_BARE_SWSCS32DIS_BIT	GT_PCI0_BARE_SWSCS32DIS_MSK
-	
+
 #define GT_PCI0_BARE_SWSCS10DIS_SHF	2
 #define GT_PCI0_BARE_SWSCS10DIS_MSK	(MSK(1) << GT_PCI0_BARE_SWSCS10DIS_SHF)
 #define GT_PCI0_BARE_SWSCS10DIS_BIT	GT_PCI0_BARE_SWSCS10DIS_MSK
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/mips-boards/malta.h linux-2.4.20/include/asm-mips64/mips-boards/malta.h
--- linux-2.4.19/include/asm-mips64/mips-boards/malta.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/mips-boards/malta.h	2002-10-29 11:18:36.000000000 +0000
@@ -28,15 +28,15 @@
 #include <asm/addrspace.h>
 #include <asm/io.h>
 
-/* 
+/*
  * Malta I/O ports base address for the Galileo GT64120 and Algorithmics
- * Bonito system controllers. 
+ * Bonito system controllers.
  */
 #define MALTA_GT_PORT_BASE      (KSEG1ADDR(0x18000000))
 #define MALTA_BONITO_PORT_BASE  (KSEG1ADDR(0x1fd00000))
 #define MALTA_MSC_PORT_BASE     (KSEG1ADDR(0x18000000))
 
-/* 
+/*
  * Malta RTC-device indirect register access.
  */
 #define MALTA_RTC_ADR_REG       0x70
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/mips-boards/msc01_pci.h linux-2.4.20/include/asm-mips64/mips-boards/msc01_pci.h
--- linux-2.4.19/include/asm-mips64/mips-boards/msc01_pci.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/mips-boards/msc01_pci.h	2002-10-29 11:18:34.000000000 +0000
@@ -94,7 +94,7 @@
 #define MSC01_PCI_INTCFG_MWE_BIT        0x00000200
 #define MSC01_PCI_INTCFG_DTO_SHF        8
 #define MSC01_PCI_INTCFG_DTO_MSK        0x00000100
-#define MSC01_PCI_INTCFG_DTO_BIT        0x00000100 
+#define MSC01_PCI_INTCFG_DTO_BIT        0x00000100
 #define MSC01_PCI_INTCFG_MA_SHF         7
 #define MSC01_PCI_INTCFG_MA_MSK         0x00000080
 #define MSC01_PCI_INTCFG_MA_BIT         0x00000080
@@ -128,7 +128,7 @@
 #define MSC01_PCI_INTSTAT_MWE_BIT       0x00000200
 #define MSC01_PCI_INTSTAT_DTO_SHF       8
 #define MSC01_PCI_INTSTAT_DTO_MSK       0x00000100
-#define MSC01_PCI_INTSTAT_DTO_BIT       0x00000100 
+#define MSC01_PCI_INTSTAT_DTO_BIT       0x00000100
 #define MSC01_PCI_INTSTAT_MA_SHF        7
 #define MSC01_PCI_INTSTAT_MA_MSK        0x00000080
 #define MSC01_PCI_INTSTAT_MA_BIT        0x00000080
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/mips-boards/sead.h linux-2.4.20/include/asm-mips64/mips-boards/sead.h
--- linux-2.4.19/include/asm-mips64/mips-boards/sead.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/mips-boards/sead.h	2002-10-29 11:18:47.000000000 +0000
@@ -0,0 +1,36 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ *
+ * Defines of the SEAD board specific address-MAP, registers, etc.
+ *
+ */
+#ifndef _MIPS_SEAD_H
+#define _MIPS_SEAD_H
+
+#include <asm/addrspace.h>
+
+/*
+ * SEAD UART register base.
+ */
+#define SEAD_UART0_REGS_BASE    (0x1f000800)
+#define SEAD_BASE_BAUD ( 3686400 / 16 )
+
+#endif /* !(_MIPS_SEAD_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/mips-boards/seadint.h linux-2.4.20/include/asm-mips64/mips-boards/seadint.h
--- linux-2.4.19/include/asm-mips64/mips-boards/seadint.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/mips-boards/seadint.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,35 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ *
+ * Defines for the SEAD interrupt controller.
+ *
+ */
+#ifndef _MIPS_SEADINT_H
+#define _MIPS_SEADINT_H
+
+/* Number of IRQ supported */
+#define SEADINT_UART0     0
+#define SEADINT_UART1     1
+#define SEADINT_END       2
+
+extern void seadint_init(void);
+
+#endif /* !(_MIPS_SEADINT_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/mips64_cache.h linux-2.4.20/include/asm-mips64/mips64_cache.h
--- linux-2.4.19/include/asm-mips64/mips64_cache.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/mips64_cache.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,305 @@
+/*
+ * mips64_cache.h
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ *
+ * Inline assembly cache operations.
+ *
+ * This file is the original r4cache.c file with modification that makes the
+ * cache handling more generic.
+ *
+ * FIXME: Handle split L2 caches.
+ *
+ */
+#ifndef _MIPS_MIPS64_CACHE_H
+#define _MIPS_MIPS64_CACHE_H
+
+#include <asm/asm.h>
+#include <asm/cacheops.h>
+
+static inline void flush_icache_line_indexed(unsigned long addr)
+{
+	unsigned long waystep = icache_size/mips_cpu.icache.ways;
+	unsigned int way;
+
+	for (way = 0; way < mips_cpu.icache.ways; way++)
+	{
+		__asm__ __volatile__(
+			".set noreorder\n\t"
+			"cache %1, (%0)\n\t"
+			".set reorder"
+			:
+			: "r" (addr),
+			"i" (Index_Invalidate_I));
+
+		addr += waystep;
+	}
+}
+
+static inline void flush_dcache_line_indexed(unsigned long addr)
+{
+	unsigned long waystep = dcache_size/mips_cpu.dcache.ways;
+	unsigned int way;
+
+	for (way = 0; way < mips_cpu.dcache.ways; way++)
+	{
+		__asm__ __volatile__(
+			".set noreorder\n\t"
+			"cache %1, (%0)\n\t"
+			".set reorder"
+			:
+			: "r" (addr),
+			"i" (Index_Writeback_Inv_D));
+
+		addr += waystep;
+	}
+}
+
+static inline void flush_scache_line_indexed(unsigned long addr)
+{
+	unsigned long waystep = scache_size/mips_cpu.scache.ways;
+	unsigned int way;
+
+	for (way = 0; way < mips_cpu.scache.ways; way++)
+	{
+		__asm__ __volatile__(
+			".set noreorder\n\t"
+			"cache %1, (%0)\n\t"
+			".set reorder"
+			:
+			: "r" (addr),
+			"i" (Index_Writeback_Inv_SD));
+
+		addr += waystep;
+	}
+}
+
+static inline void flush_icache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		"cache %1, (%0)\n\t"
+		".set reorder"
+		:
+		: "r" (addr),
+		  "i" (Hit_Invalidate_I));
+}
+
+static inline void flush_dcache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		"cache %1, (%0)\n\t"
+		".set reorder"
+		:
+		: "r" (addr),
+		  "i" (Hit_Writeback_Inv_D));
+}
+
+static inline void invalidate_dcache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		"cache %1, (%0)\n\t"
+		".set reorder"
+		:
+		: "r" (addr),
+		  "i" (Hit_Invalidate_D));
+}
+
+static inline void invalidate_scache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		"cache %1, (%0)\n\t"
+		".set reorder"
+		:
+		: "r" (addr),
+		  "i" (Hit_Invalidate_SD));
+}
+
+static inline void flush_scache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		"cache %1, (%0)\n\t"
+		".set reorder"
+		:
+		: "r" (addr),
+		  "i" (Hit_Writeback_Inv_SD));
+}
+
+/*
+ * The next two are for badland addresses like signal trampolines.
+ */
+static inline void protected_flush_icache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		"1:\tcache %1,(%0)\n"
+		"2:\t.set reorder\n\t"
+		".section\t__ex_table,\"a\"\n\t"
+		".dword\t1b,2b\n\t"
+		".previous"
+		:
+		: "r" (addr), "i" (Hit_Invalidate_I));
+}
+
+static inline void protected_writeback_dcache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		"1:\tcache %1,(%0)\n"
+		"2:\t.set reorder\n\t"
+		".section\t__ex_table,\"a\"\n\t"
+		".dword\t1b,2b\n\t"
+		".previous"
+		:
+		: "r" (addr), "i" (Hit_Writeback_D));
+}
+
+#define cache_unroll(base,op)			\
+	__asm__ __volatile__("			\
+		.set noreorder;			\
+		cache %1, (%0);			\
+		.set reorder"			\
+		:				\
+		: "r" (base),			\
+		  "i" (op));
+
+
+static inline void blast_dcache(void)
+{
+	unsigned long start = KSEG0;
+	unsigned long end = (start + dcache_size);
+
+	while(start < end) {
+		cache_unroll(start,Index_Writeback_Inv_D);
+		start += dc_lsize;
+	}
+}
+
+static inline void blast_dcache_page(unsigned long page)
+{
+	unsigned long start = page;
+	unsigned long end = (start + PAGE_SIZE);
+
+	while(start < end) {
+		cache_unroll(start,Hit_Writeback_Inv_D);
+		start += dc_lsize;
+	}
+}
+
+static inline void blast_dcache_page_indexed(unsigned long page)
+{
+	unsigned long start;
+	unsigned long end = (page + PAGE_SIZE);
+	unsigned long waystep = dcache_size/mips_cpu.dcache.ways;
+	unsigned int way;
+
+	for (way = 0; way < mips_cpu.dcache.ways; way++) {
+		start = page + way*waystep;
+		while(start < end) {
+			cache_unroll(start,Index_Writeback_Inv_D);
+			start += dc_lsize;
+		}
+	}
+}
+
+static inline void blast_icache(void)
+{
+	unsigned long start = KSEG0;
+	unsigned long end = (start + icache_size);
+
+	while(start < end) {
+		cache_unroll(start,Index_Invalidate_I);
+		start += ic_lsize;
+	}
+}
+
+static inline void blast_icache_page(unsigned long page)
+{
+	unsigned long start = page;
+	unsigned long end = (start + PAGE_SIZE);
+
+	while(start < end) {
+		cache_unroll(start,Hit_Invalidate_I);
+		start += ic_lsize;
+	}
+}
+
+static inline void blast_icache_page_indexed(unsigned long page)
+{
+	unsigned long start;
+	unsigned long end = (page + PAGE_SIZE);
+	unsigned long waystep = icache_size/mips_cpu.icache.ways;
+	unsigned int way;
+
+	for (way = 0; way < mips_cpu.icache.ways; way++) {
+		start = page + way*waystep;
+		while(start < end) {
+			cache_unroll(start,Index_Invalidate_I);
+			start += ic_lsize;
+		}
+	}
+}
+
+static inline void blast_scache(void)
+{
+	unsigned long start = KSEG0;
+	unsigned long end = KSEG0 + scache_size;
+
+	while(start < end) {
+		cache_unroll(start,Index_Writeback_Inv_SD);
+		start += sc_lsize;
+	}
+}
+
+static inline void blast_scache_page(unsigned long page)
+{
+	unsigned long start = page;
+	unsigned long end = page + PAGE_SIZE;
+
+	while(start < end) {
+		cache_unroll(start,Hit_Writeback_Inv_SD);
+		start += sc_lsize;
+	}
+}
+
+static inline void blast_scache_page_indexed(unsigned long page)
+{
+	unsigned long start;
+	unsigned long end = (page + PAGE_SIZE);
+	unsigned long waystep = scache_size/mips_cpu.scache.ways;
+	unsigned int way;
+
+	for (way = 0; way < mips_cpu.scache.ways; way++) {
+		start = page + way*waystep;
+		while(start < end) {
+			cache_unroll(start,Index_Writeback_Inv_SD);
+			start += sc_lsize;
+		}
+	}
+}
+
+#endif /* !(_MIPS_MIPS64_CACHE_H) */
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/mipsregs.h linux-2.4.20/include/asm-mips64/mipsregs.h
--- linux-2.4.19/include/asm-mips64/mipsregs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/mipsregs.h	2002-10-29 11:18:35.000000000 +0000
@@ -77,7 +77,7 @@
 #define CP0_IWATCH $18
 #define CP0_DWATCH $19
 
-/* 
+/*
  * Coprocessor 0 Set 1 register names
  */
 #define CP0_S1_DERRADDR0  $26
@@ -374,8 +374,10 @@
 #define CONF_CM_CACHABLE_CUW		6
 #define CONF_CM_CACHABLE_ACCELERATED	7
 #define CONF_CM_CMASK			7
+#define CONF_CU				(1 <<  3)
 #define CONF_DB				(1 <<  4)
 #define CONF_IB				(1 <<  5)
+#define CONF_SE				(1 << 12)
 #define CONF_SC				(1 << 17)
 #define CONF_AC                         (1 << 23)
 #define CONF_HALT                       (1 << 25)
@@ -504,8 +506,8 @@
         ".set\tmips0"                                           \
         : : "r" (value))
 
-/* 
- * This should be changed when we get a compiler that support the MIPS32 ISA. 
+/*
+ * This should be changed when we get a compiler that support the MIPS32 ISA.
  */
 #define read_mips32_cp0_config1()                               \
 ({ int __res;                                                   \
@@ -597,7 +599,7 @@
 {
 	unsigned long val;
 
-	__asm__ __volatile__(	
+	__asm__ __volatile__(
 		".set noreorder\n\t"
 		"dmfc0 %0, $2\n\t"
 		".set reorder"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/mmu_context.h linux-2.4.20/include/asm-mips64/mmu_context.h
--- linux-2.4.19/include/asm-mips64/mmu_context.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/mmu_context.h	2002-10-29 11:18:33.000000000 +0000
@@ -19,7 +19,7 @@
 /*
  * For the fast tlb miss handlers, we currently keep a per cpu array
  * of pointers to the current pgd for each processor. Also, the proc.
- * id is stuffed into the context register. This should be changed to 
+ * id is stuffed into the context register. This should be changed to
  * use the processor id via current->processor, where current is stored
  * in watchhi/lo. The context register should be used to contiguously
  * map the page tables.
@@ -76,10 +76,10 @@
 #ifndef CONFIG_SMP
 	mm->context = 0;
 #else
-	mm->context = (unsigned long)kmalloc(smp_num_cpus * 
+	mm->context = (unsigned long)kmalloc(smp_num_cpus *
 				sizeof(unsigned long), GFP_KERNEL);
 	/*
- 	 * Init the "context" values so that a tlbpid allocation 
+ 	 * Init the "context" values so that a tlbpid allocation
 	 * happens on the first switch.
  	 */
 	if (mm->context == 0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/msgbuf.h linux-2.4.20/include/asm-mips64/msgbuf.h
--- linux-2.4.19/include/asm-mips64/msgbuf.h	2000-02-25 06:53:35.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/msgbuf.h	2002-10-29 11:18:31.000000000 +0000
@@ -1,7 +1,7 @@
 #ifndef _ASM_MSGBUF_H
 #define _ASM_MSGBUF_H
 
-/* 
+/*
  * The msqid64_ds structure for alpha architecture.
  * Note extra padding because this structure is passed back and forth
  * between kernel and user space.
@@ -13,15 +13,18 @@
 struct msqid64_ds {
 	struct ipc64_perm msg_perm;
 	__kernel_time_t msg_stime;	/* last msgsnd time */
+	unsigned long	__unused1;
 	__kernel_time_t msg_rtime;	/* last msgrcv time */
+	unsigned long	__unused2;
 	__kernel_time_t msg_ctime;	/* last change time */
+	unsigned long	__unused3;
 	unsigned long  msg_cbytes;	/* current number of bytes on queue */
 	unsigned long  msg_qnum;	/* number of messages in queue */
 	unsigned long  msg_qbytes;	/* max number of bytes on queue */
 	__kernel_pid_t msg_lspid;	/* pid of last msgsnd */
 	__kernel_pid_t msg_lrpid;	/* last receive pid */
-	unsigned long  __unused1;
-	unsigned long  __unused2;
+	unsigned long  __unused4;
+	unsigned long  __unused5;
 };
 
 #endif /* _ASM_MSGBUF_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/page.h linux-2.4.20/include/asm-mips64/page.h
--- linux-2.4.19/include/asm-mips64/page.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/page.h	2002-10-29 11:18:31.000000000 +0000
@@ -32,6 +32,10 @@
 
 extern void (*_clear_page)(void * page);
 extern void (*_copy_page)(void * to, void * from);
+extern void mips64_clear_page_dc(unsigned long page);
+extern void mips64_clear_page_sc(unsigned long page);
+extern void mips64_copy_page_dc(unsigned long to, unsigned long from);
+extern void mips64_copy_page_sc(unsigned long to, unsigned long from);
 
 #define clear_page(page)	_clear_page(page)
 #define copy_page(to, from)	_copy_page(to, from)
@@ -51,6 +55,8 @@
 #define pgd_val(x)	((x).pgd)
 #define pgprot_val(x)	((x).pgprot)
 
+#define ptep_buddy(x)	((pte_t *)((unsigned long)(x) ^ sizeof(pte_t)))
+
 #define __pte(x)	((pte_t) { (x) } )
 #define __pmd(x)	((pmd_t) { (x) } )
 #define __pgd(x)	((pgd_t) { (x) } )
@@ -83,12 +89,15 @@
 #if defined(CONFIG_SGI_IP22) || defined(CONFIG_MIPS_ATLAS) || \
     defined(CONFIG_MIPS_MALTA)
 #define PAGE_OFFSET	0xffffffff80000000UL
+#define UNCAC_BASE	0xffffffffa0000000UL
 #endif
 #if defined(CONFIG_SGI_IP32)
 #define PAGE_OFFSET	0x9800000000000000UL
+#define UNCAC_BASE	0x9000000000000000UL
 #endif
 #if defined(CONFIG_SGI_IP27)
 #define PAGE_OFFSET	0xa800000000000000UL
+#define UNCAC_BASE	0x9000000000000000UL
 #endif
 #if defined(CONFIG_SIBYTE_SB1250)
 #define PAGE_OFFSET	0xa800000000000000UL
@@ -101,6 +110,9 @@
 #define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
 #endif
 
+#define UNCAC_ADDR(addr)	((addr) - PAGE_OFFSET + UNCAC_BASE)
+#define CAC_ADDR(addr)		((addr) - UNCAC_BASE + PAGE_OFFSET)
+
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/pci/bridge.h linux-2.4.20/include/asm-mips64/pci/bridge.h
--- linux-2.4.19/include/asm-mips64/pci/bridge.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/pci/bridge.h	2002-10-29 11:18:36.000000000 +0000
@@ -612,7 +612,7 @@
 /* Bridge INT_DEV register bits definition */
 #define BRIDGE_INT_DEV_SHFT(n)		((n)*3)
 #define BRIDGE_INT_DEV_MASK(n)		(0x7 << BRIDGE_INT_DEV_SHFT(n))
-#define BRIDGE_INT_DEV_SET(_dev, _line) (_dev << BRIDGE_INT_DEV_SHFT(_line))	
+#define BRIDGE_INT_DEV_SET(_dev, _line) (_dev << BRIDGE_INT_DEV_SHFT(_line))
 
 /* Bridge interrupt(x) register bits definition */
 #define BRIDGE_INT_ADDR_HOST		0x0003FF00
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/pci.h linux-2.4.20/include/asm-mips64/pci.h
--- linux-2.4.19/include/asm-mips64/pci.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/pci.h	2002-10-29 11:18:33.000000000 +0000
@@ -7,8 +7,6 @@
 #define _ASM_PCI_H
 
 #include <linux/config.h>
-#include <linux/types.h>
-#include <asm/io.h>			/* for virt_to_bus()  */
 
 #ifdef __KERNEL__
 
@@ -40,13 +38,19 @@
  * MIPS has everything mapped statically.
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <asm/scatterlist.h>
 #include <linux/string.h>
 #include <asm/io.h>
 
+#if (defined(CONFIG_DDB5074) || defined(CONFIG_DDB5476))
+#undef PCIBIOS_MIN_IO
+#undef PCIBIOS_MIN_MEM
+#define PCIBIOS_MIN_IO		0x0100000
+#define PCIBIOS_MIN_MEM		0x1000000
+#endif
+
 struct pci_dev;
 
 /*
@@ -79,38 +83,6 @@
 extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
 				void *vaddr, dma_addr_t dma_handle);
 
-
-#ifdef CONFIG_MAPPED_PCI_IO
-
-extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size,
-                                 int direction);
-extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
-                             size_t size, int direction);
-extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,
-                      int direction);
-extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-                         int nents, int direction);
-extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle,
-                                size_t size, int direction);
-extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-                            int nelems, int direction);
-
-/* pci_unmap_{single,page} is not a nop, thus... */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
-	dma_addr_t ADDR_NAME;
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
-	__u32 LEN_NAME;
-#define pci_unmap_addr(PTR, ADDR_NAME)			\
-	((PTR)->ADDR_NAME)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
-	(((PTR)->ADDR_NAME) = (VAL))
-#define pci_unmap_len(PTR, LEN_NAME)			\
-	((PTR)->LEN_NAME)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
-	(((PTR)->LEN_NAME) = (VAL))
-
-#else /* CONFIG_MAPPED_PCI_IO  */
-
 /*
  * Map a single buffer of the indicated size for DMA in streaming mode.
  * The 32-bit bus address to use is returned.
@@ -121,13 +93,14 @@
 static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
 					size_t size, int direction)
 {
+	unsigned long addr = (unsigned long) ptr;
+
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
 
-#ifdef CONFIG_NONCOHERENT_IO
-	dma_cache_wback_inv((unsigned long)ptr, size);
-#endif
-	return virt_to_bus(ptr);
+	dma_cache_wback_inv(addr, size);
+
+	return bus_to_baddr(hwdev->bus->number, __pa(ptr));
 }
 
 /*
@@ -144,16 +117,13 @@
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
 
-	/* Nothing to do */
-}
+	if (direction != PCI_DMA_TODEVICE) {
+		unsigned long addr;
 
-/* pci_unmap_{page,single} is a nop so... */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
-#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
-#define pci_unmap_len(PTR, LEN_NAME)		(0)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
+		addr = baddr_to_bus(hwdev, dma_addr) + PAGE_OFFSET;
+		dma_cache_wback_inv(addr, size);
+	}
+}
 
 /*
  * pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical
@@ -169,11 +139,9 @@
 		out_of_line_bug();
 
 	addr = (unsigned long) page_address(page) + offset;
-#ifdef CONFIG_NONCOHERENT_IO
 	dma_cache_wback_inv(addr, size);
-#endif
 
-	return virt_to_bus(addr);
+	return bus_to_baddr(hwdev, page_to_phys(page) + offset);
 }
 
 static inline void pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address,
@@ -181,9 +149,23 @@
 {
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
-	/* Nothing to do */
+
+	if (direction != PCI_DMA_TODEVICE) {
+		unsigned long addr;
+
+		addr = baddr_to_bus(hwdev, dma_address) + PAGE_OFFSET;
+		dma_cache_wback_inv(addr, size);
+	}
 }
 
+/* pci_unmap_{page,single} is a nop so... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)		(0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
+
 /*
  * Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
@@ -208,12 +190,19 @@
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
 
-	/* Make sure that gcc doesn't leave the empty loop body.  */
 	for (i = 0; i < nents; i++, sg++) {
-#ifdef CONFIG_NONCOHERENT_IO
-		dma_cache_wback_inv((unsigned long)sg->address, sg->length);
-#endif
-		sg->dma_address = (char *)(__pa(sg->address));
+		if (sg->address && sg->page)
+			out_of_line_bug();
+		else if (!sg->address && !sg->page)
+			out_of_line_bug();
+
+		if (sg->address) {
+			dma_cache_wback_inv((unsigned long)sg->address,
+			                    sg->length);
+			sg->dma_address = bus_to_baddr(hwdev, __pa(sg->address));
+		} else
+			sg->dma_address = page_to_bus(sg->page) +
+			                  sg->offset;
 	}
 
 	return nents;
@@ -227,10 +216,24 @@
 static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
 				int nents, int direction)
 {
+	int i;
+
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
 
-	/* Nothing to do */
+	if (direction == PCI_DMA_TODEVICE)
+		return;
+
+	for (i = 0; i < nents; i++, sg++) {
+		if (sg->address && sg->page)
+			out_of_line_bug();
+		else if (!sg->address && !sg->page)
+			out_of_line_bug();
+
+		if (!sg->address)
+			continue;
+		dma_cache_wback_inv((unsigned long)sg->address, sg->length);
+	}
 }
 
 /*
@@ -247,11 +250,13 @@
 				       dma_addr_t dma_handle,
 				       size_t size, int direction)
 {
+	unsigned long addr;
+
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
-#ifdef CONFIG_NONCOHERENT_IO
-	dma_cache_wback_inv((unsigned long)__va(dma_handle - bus_to_baddr[hwdev->bus->number]), size);
-#endif
+
+	addr = baddr_to_bus(hwdev, dma_handle) + PAGE_OFFSET;
+	dma_cache_wback_inv(addr, size);
 }
 
 /*
@@ -272,14 +277,19 @@
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
 
-	/*  Make sure that gcc doesn't leave the empty loop body.  */
+	/* Make sure that gcc doesn't leave the empty loop body.  */
 #ifdef CONFIG_NONCOHERENT_IO
 	for (i = 0; i < nelems; i++, sg++)
 		dma_cache_wback_inv((unsigned long)sg->address, sg->length);
 #endif
 }
-#endif /* CONFIG_MAPPED_PCI_IO  */
 
+/*
+ * Return whether the given PCI device DMA address mask can
+ * be supported properly.  For example, if your device can
+ * only drive the low 24-bits during PCI bus mastering, then
+ * you would pass 0x00ffffff as the mask to this function.
+ */
 static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
 {
 	/*
@@ -287,45 +297,50 @@
 	 * so we can't guarantee allocations that must be
 	 * within a tighter range than GFP_DMA..
 	 */
+#ifdef CONFIG_ISA
 	if (mask < 0x00ffffff)
 		return 0;
+#endif
 
 	return 1;
 }
 
 /* This is always fine. */
-/* Well ...  this actually needs more thought ...  */
-#define pci_dac_dma_supported(pci_dev, mask)	(0)
+#define pci_dac_dma_supported(pci_dev, mask)	(1)
 
-#if 0
-static __inline__ dma64_addr_t
-pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
+static inline dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev,
+	struct page *page, unsigned long offset, int direction)
 {
-	return ((dma64_addr_t) page_to_bus(page) +
-		(dma64_addr_t) offset);
+	dma64_addr_t addr = page_to_phys(page) + offset;
+
+	return (dma64_addr_t) bus_to_baddr(hwdev->bus->number, addr);
 }
 
-static __inline__ struct page *
-pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
+static inline struct page *pci_dac_dma_to_page(struct pci_dev *pdev,
+	dma64_addr_t dma_addr)
 {
-	unsigned long poff = (dma_addr >> PAGE_SHIFT);
+	unsigned long poff = baddr_to_bus(hwdev, dma_addr) >> PAGE_SHIFT;
 
 	return mem_map + poff;
 }
 
-static __inline__ unsigned long
-pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
+static inline unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev,
+	dma64_addr_t dma_addr)
 {
-	return (dma_addr & ~PAGE_MASK);
+	return dma_addr & ~PAGE_MASK;
 }
 
-static __inline__ void
-pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr,
-                        size_t len, int direction)
+static inline void pci_dac_dma_sync_single(struct pci_dev *pdev,
+	dma64_addr_t dma_addr, size_t len, int direction)
 {
-	/* Nothing to do. */
+	unsigned long addr;
+
+	if (direction == PCI_DMA_NONE)
+		BUG();
+
+	addr = baddr_to_bus(hwdev->bus->number, dma_addr) + PAGE_OFFSET;
+	dma_cache_wback_inv(addr, len);
 }
-#endif
 
 /*
  * Return the index of the PCI controller for device.
@@ -339,7 +354,7 @@
  * returns, or alternatively stop on the first sg_dma_len(sg) which
  * is 0.
  */
-#define sg_dma_address(sg)	((unsigned long)((sg)->address))
+#define sg_dma_address(sg)	((sg)->dma_address)
 #define sg_dma_len(sg)		((sg)->length)
 
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/pgalloc.h linux-2.4.20/include/asm-mips64/pgalloc.h
--- linux-2.4.19/include/asm-mips64/pgalloc.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/pgalloc.h	2002-10-29 11:18:35.000000000 +0000
@@ -193,7 +193,7 @@
 #define pgd_free(pgd)           free_pgd_fast(pgd)
 #define pgd_alloc(mm)           get_pgd_fast()
 
-extern pte_t kptbl[(PAGE_SIZE<<KPTBL_PAGE_ORDER)/sizeof(pte_t)];
+extern pte_t kptbl[(PAGE_SIZE << PGD_ORDER)/sizeof(pte_t)];
 extern pmd_t kpmdtbl[PTRS_PER_PMD];
 
 extern int do_check_pgt_cache(int, int);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/pgtable-bits.h linux-2.4.20/include/asm-mips64/pgtable-bits.h
--- linux-2.4.19/include/asm-mips64/pgtable-bits.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/pgtable-bits.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,101 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994 - 2002 by Ralf Baechle
+ * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc.
+ * Copyright (C) 2002  Maciej W. Rozycki
+ */
+#ifndef _ASM_PGTABLE_BITS_H
+#define _ASM_PGTABLE_BITS_H
+
+#include <linux/config.h>
+
+/*
+ * Note that we shift the lower 32bits of each EntryLo[01] entry
+ * 6 bits to the left. That way we can convert the PFN into the
+ * physical address by a single 'and' operation and gain 6 additional
+ * bits for storing information which isn't present in a normal
+ * MIPS page table.
+ *
+ * Similar to the Alpha port, we need to keep track of the ref
+ * and mod bits in software.  We have a software "yeah you can read
+ * from this page" bit, and a hardware one which actually lets the
+ * process read from the page.  On the same token we have a software
+ * writable bit and the real hardware one which actually lets the
+ * process write to the page, this keeps a mod bit via the hardware
+ * dirty bit.
+ *
+ * Certain revisions of the R4000 and R5000 have a bug where if a
+ * certain sequence occurs in the last 3 instructions of an executable
+ * page, and the following page is not mapped, the cpu can do
+ * unpredictable things.  The code (when it is written) to deal with
+ * this problem will be in the update_mmu_cache() code for the r4k.
+ */
+#define _PAGE_PRESENT               (1<<0)  /* implemented in software */
+#define _PAGE_READ                  (1<<1)  /* implemented in software */
+#define _PAGE_WRITE                 (1<<2)  /* implemented in software */
+#define _PAGE_ACCESSED              (1<<3)  /* implemented in software */
+#define _PAGE_MODIFIED              (1<<4)  /* implemented in software */
+
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
+
+#define _PAGE_GLOBAL                (1<<8)
+#define _PAGE_VALID                 (1<<9)
+#define _PAGE_SILENT_READ           (1<<9)  /* synonym                 */
+#define _PAGE_DIRTY                 (1<<10) /* The MIPS dirty bit      */
+#define _PAGE_SILENT_WRITE          (1<<10)
+#define _CACHE_UNCACHED             (1<<11)
+#define _CACHE_MASK                 (1<<11)
+#define _CACHE_CACHABLE_NONCOHERENT 0
+
+#else
+#define _PAGE_R4KBUG                (1<<5)  /* workaround for r4k bug  */
+#define _PAGE_GLOBAL                (1<<6)
+#define _PAGE_VALID                 (1<<7)
+#define _PAGE_SILENT_READ           (1<<7)  /* synonym                 */
+#define _PAGE_DIRTY                 (1<<8)  /* The MIPS dirty bit      */
+#define _PAGE_SILENT_WRITE          (1<<8)
+#define _CACHE_MASK                 (7<<9)
+
+#if defined(CONFIG_CPU_SB1)
+
+/* No penalty for being coherent on the SB1, so just
+   use it for "noncoherent" spaces, too.  Shouldn't hurt. */
+
+#define _CACHE_UNCACHED             (2<<9)
+#define _CACHE_CACHABLE_COW         (5<<9)
+#define _CACHE_CACHABLE_NONCOHERENT (5<<9)
+#define _CACHE_UNCACHED_ACCELERATED (7<<9)
+
+#else
+
+#define _CACHE_CACHABLE_NO_WA       (0<<9)  /* R4600 only              */
+#define _CACHE_CACHABLE_WA          (1<<9)  /* R4600 only              */
+#define _CACHE_UNCACHED             (2<<9)  /* R4[0246]00              */
+#define _CACHE_CACHABLE_NONCOHERENT (3<<9)  /* R4[0246]00              */
+#define _CACHE_CACHABLE_CE          (4<<9)  /* R4[04]00MC only         */
+#define _CACHE_CACHABLE_COW         (5<<9)  /* R4[04]00MC only         */
+#define _CACHE_CACHABLE_CUW         (6<<9)  /* R4[04]00MC only         */
+#define _CACHE_UNCACHED_ACCELERATED (7<<9)  /* R10000 only             */
+
+#endif
+#endif
+
+#define __READABLE	(_PAGE_READ | _PAGE_SILENT_READ | _PAGE_ACCESSED)
+#define __WRITEABLE	(_PAGE_WRITE | _PAGE_SILENT_WRITE | _PAGE_MODIFIED)
+
+#define _PAGE_CHG_MASK  (PAGE_MASK | _PAGE_ACCESSED | _PAGE_MODIFIED | _CACHE_MASK)
+
+#ifdef CONFIG_MIPS_UNCACHED
+#define PAGE_CACHABLE_DEFAULT	_CACHE_UNCACHED
+#elif defined(CONFIG_NONCOHERENT_IO)
+#define PAGE_CACHABLE_DEFAULT	_CACHE_CACHABLE_NONCOHERENT
+#else
+#define PAGE_CACHABLE_DEFAULT	_CACHE_CACHABLE_COW
+#endif
+
+#define CONF_CM_DEFAULT		(PAGE_CACHABLE_DEFAULT >> 9)
+
+#endif /* _ASM_PGTABLE_BITS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/pgtable.h linux-2.4.20/include/asm-mips64/pgtable.h
--- linux-2.4.19/include/asm-mips64/pgtable.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/pgtable.h	2002-10-29 11:18:40.000000000 +0000
@@ -57,8 +57,8 @@
  * routines are not needed. Only the icache on a processor is not
  * coherent with the dcache of the _same_ processor, so we must flush
  * the icache so that it does not contain stale contents of physical
- * memory. No flushes are needed for dma coherency, since the o200s 
- * are io coherent. The only place where we might be overoptimizing 
+ * memory. No flushes are needed for dma coherency, since the o200s
+ * are io coherent. The only place where we might be overoptimizing
  * out icache flushes are from mprotect (when PROT_EXEC is added).
  */
 extern void andes_flush_icache_page(unsigned long);
@@ -77,10 +77,6 @@
 
 #else
 
-extern void (*_flush_icache_all)(void);
-extern void (*_flush_icache_range)(unsigned long start, unsigned long end);
-extern void (*_flush_icache_page)(struct vm_area_struct *vma, struct page *page);
-
 #define flush_cache_mm(mm)		_flush_cache_mm(mm)
 #define flush_cache_range(mm,start,end)	_flush_cache_range(mm,start,end)
 #define flush_cache_page(vma,page)	_flush_cache_page(vma, page)
@@ -89,12 +85,6 @@
 #define flush_icache_user_range(vma, page, addr, len) \
 	flush_icache_page((vma), (page))
 #define flush_icache_page(vma, page)	_flush_icache_page(vma, page)
-#ifdef CONFIG_VTAG_ICACHE
-#define flush_icache_all()		_flush_icache_all()
-#else
-#define flush_icache_all()		do { } while(0)
-#endif
-
 
 #endif /* !CONFIG_CPU_R10000 */
 
@@ -114,17 +104,17 @@
  * pair of 4K pages, giving 1024 (== PTRS_PER_PMD) 8 byte pointers to
  * page tables. Each page table is a single 4K page, giving 512 (==
  * PTRS_PER_PTE) 8 byte ptes. Each pgde is initialized to point to
- * invalid_pmd_table, each pmde is initialized to point to 
+ * invalid_pmd_table, each pmde is initialized to point to
  * invalid_pte_table, each pte is initialized to 0. When memory is low,
  * and a pmd table or a page table allocation fails, empty_bad_pmd_table
  * and empty_bad_page_table is returned back to higher layer code, so
- * that the failure is recognized later on. Linux does not seem to 
+ * that the failure is recognized later on. Linux does not seem to
  * handle these failures very well though. The empty_bad_page_table has
  * invalid pte entries in it, to force page faults.
- * Vmalloc handling: vmalloc uses swapper_pg_dir[0] (returned by 
- * pgd_offset_k), which is initalized to point to kpmdtbl. kpmdtbl is 
- * the only single page pmd in the system. kpmdtbl entries point into 
- * kptbl[] array. We reserve 1<<KPTBL_PAGE_ORDER pages to hold the
+ * Vmalloc handling: vmalloc uses swapper_pg_dir[0] (returned by
+ * pgd_offset_k), which is initalized to point to kpmdtbl. kpmdtbl is
+ * the only single page pmd in the system. kpmdtbl entries point into
+ * kptbl[] array. We reserve 1 << PGD_ORDER pages to hold the
  * vmalloc range translations, which the fault handler looks at.
  */
 
@@ -145,72 +135,19 @@
 #define PTRS_PER_PGD	1024
 #define PTRS_PER_PMD	1024
 #define PTRS_PER_PTE	512
-#define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
+#define PGD_ORDER		1
+
+#define USER_PTRS_PER_PGD	(TASK_SIZE / PGDIR_SIZE)
 #define FIRST_USER_PGD_NR	0
 
-#define KPTBL_PAGE_ORDER  1
-#define VMALLOC_START     XKSEG
-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END       \
-	(VMALLOC_START + ((1 << KPTBL_PAGE_ORDER) * PTRS_PER_PTE * PAGE_SIZE))
-
-/* Note that we shift the lower 32bits of each EntryLo[01] entry
- * 6 bits to the left. That way we can convert the PFN into the
- * physical address by a single 'and' operation and gain 6 additional
- * bits for storing information which isn't present in a normal
- * MIPS page table.
- *
- * Similar to the Alpha port, we need to keep track of the ref
- * and mod bits in software.  We have a software "yeah you can read
- * from this page" bit, and a hardware one which actually lets the
- * process read from the page.  On the same token we have a software
- * writable bit and the real hardware one which actually lets the
- * process write to the page, this keeps a mod bit via the hardware
- * dirty bit.
- *
- * Certain revisions of the R4000 and R5000 have a bug where if a
- * certain sequence occurs in the last 3 instructions of an executable
- * page, and the following page is not mapped, the cpu can do
- * unpredictable things.  The code (when it is written) to deal with
- * this problem will be in the update_mmu_cache() code for the r4k.
- */
-#define _PAGE_PRESENT               (1<<0)  /* implemented in software */
-#define _PAGE_READ                  (1<<1)  /* implemented in software */
-#define _PAGE_WRITE                 (1<<2)  /* implemented in software */
-#define _PAGE_ACCESSED              (1<<3)  /* implemented in software */
-#define _PAGE_MODIFIED              (1<<4)  /* implemented in software */
-#define _PAGE_R4KBUG                (1<<5)  /* workaround for r4k bug  */
-#define _PAGE_GLOBAL                (1<<6)
-#define _PAGE_VALID                 (1<<7)
-#define _PAGE_SILENT_READ           (1<<7)  /* synonym                 */
-#define _PAGE_DIRTY                 (1<<8)  /* The MIPS dirty bit      */
-#define _PAGE_SILENT_WRITE          (1<<8)
-#define _CACHE_CACHABLE_NO_WA       (0<<9)  /* R4600 only              */
-#define _CACHE_CACHABLE_WA          (1<<9)  /* R4600 only              */
-#define _CACHE_UNCACHED             (2<<9)  /* R4[0246]00              */
-#define _CACHE_CACHABLE_NONCOHERENT (3<<9)  /* R4[0246]00              */
-#define _CACHE_CACHABLE_CE          (4<<9)  /* R4[04]00 only           */
-#define _CACHE_CACHABLE_COW         (5<<9)  /* R4[04]00 only           */
-#define _CACHE_CACHABLE_CUW         (6<<9)  /* R4[04]00 only           */
-#define _CACHE_UNCACHED_ACCELERATED (7<<9)  /* R10000 only             */
-#define _CACHE_MASK                 (7<<9)
-
-#define __READABLE	(_PAGE_READ | _PAGE_SILENT_READ | _PAGE_ACCESSED)
-#define __WRITEABLE	(_PAGE_WRITE | _PAGE_SILENT_WRITE | _PAGE_MODIFIED)
-
-#define _PAGE_CHG_MASK  (PAGE_MASK | _PAGE_ACCESSED | _PAGE_MODIFIED | _CACHE_MASK)
-
-#ifdef CONFIG_MIPS_UNCACHED
-#define PAGE_CACHABLE_DEFAULT _CACHE_UNCACHED
-#else /* ! UNCACHED */
-#ifdef CONFIG_SGI_IP22
-#define PAGE_CACHABLE_DEFAULT _CACHE_CACHABLE_NONCOHERENT
-#else /* ! IP22 */
-#define PAGE_CACHABLE_DEFAULT _CACHE_CACHABLE_COW
-#endif /* IP22 */
-#endif /* UNCACHED */
+#define VMALLOC_START		XKSEG
+#define VMALLOC_VMADDR(x)	((unsigned long)(x))
+#define VMALLOC_END	\
+	(VMALLOC_START + ((1 << PGD_ORDER) * PTRS_PER_PTE * PAGE_SIZE))
+
+#include <asm/pgtable-bits.h>
 
-#define PAGE_NONE	__pgprot(_PAGE_PRESENT | PAGE_CACHABLE_DEFAULT)
+#define PAGE_NONE	__pgprot(_PAGE_PRESENT | _CACHE_CACHABLE_NONCOHERENT)
 #define PAGE_SHARED     __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
 			PAGE_CACHABLE_DEFAULT)
 #define PAGE_COPY       __pgprot(_PAGE_PRESENT | _PAGE_READ | \
@@ -220,7 +157,7 @@
 #define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \
 			_PAGE_GLOBAL | PAGE_CACHABLE_DEFAULT)
 #define PAGE_USERIO     __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
-			_CACHE_UNCACHED)
+			PAGE_CACHABLE_DEFAULT)
 #define PAGE_KERNEL_UNCACHED __pgprot(_PAGE_PRESENT | __READABLE | \
 			__WRITEABLE | _PAGE_GLOBAL | _CACHE_UNCACHED)
 
@@ -298,7 +235,7 @@
 
 static inline int pte_none(pte_t pte)
 {
-	return !pte_val(pte);
+	return !(pte_val(pte) & ~_PAGE_GLOBAL);
 }
 
 static inline int pte_present(pte_t pte)
@@ -314,15 +251,32 @@
 static inline void set_pte(pte_t *ptep, pte_t pteval)
 {
 	*ptep = pteval;
+#if !defined(CONFIG_CPU_R3000) && !defined(CONFIG_CPU_TX39XX)
+	if (pte_val(pteval) & _PAGE_GLOBAL) {
+		pte_t *buddy = ptep_buddy(ptep);
+		/*
+		 * Make sure the buddy is global too (if it's !none,
+		 * it better already be global)
+		 */
+		if (pte_none(*buddy))
+			pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL;
+	}
+#endif
 }
 
 static inline void pte_clear(pte_t *ptep)
 {
-	set_pte(ptep, __pte(0));
+#if !defined(CONFIG_CPU_R3000) && !defined(CONFIG_CPU_TX39XX)
+	/* Preserve global status for the pair */
+	if (pte_val(*ptep_buddy(ptep)) & _PAGE_GLOBAL)
+		set_pte(ptep, __pte(_PAGE_GLOBAL));
+	else
+#endif
+		set_pte(ptep, __pte(0));
 }
 
 /*
- * (pmds are folded into pgds so this doesnt get actually called,
+ * (pmds are folded into pgds so this doesn't get actually called,
  * but the define is needed for a generic inline function.)
  */
 #define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
@@ -531,7 +485,7 @@
 	       ((address >> PMD_SHIFT) & (PTRS_PER_PMD - 1));
 }
 
-/* Find an entry in the third-level page table.. */ 
+/* Find an entry in the third-level page table.. */
 static inline pte_t *pte_offset(pmd_t * dir, unsigned long address)
 {
 	return (pte_t *) (pmd_page(*dir)) +
@@ -583,6 +537,8 @@
  */
 #define HAVE_ARCH_UNMAPPED_AREA
 
+#define io_remap_page_range remap_page_range
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_PGTABLE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/posix_types.h linux-2.4.20/include/asm-mips64/posix_types.h
--- linux-2.4.19/include/asm-mips64/posix_types.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/posix_types.h	2002-10-29 11:18:35.000000000 +0000
@@ -88,7 +88,7 @@
 
 #undef __FD_ISSET
 static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
-{ 
+{
 	unsigned long __tmp = __fd / __NFDBITS;
 	unsigned long __rem = __fd % __NFDBITS;
 	return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/processor.h linux-2.4.20/include/asm-mips64/processor.h
--- linux-2.4.19/include/asm-mips64/processor.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/processor.h	2002-10-29 11:18:47.000000000 +0000
@@ -74,6 +74,7 @@
 extern void r3081_wait(void);
 extern void r39xx_wait(void);
 extern void r4k_wait(void);
+extern void au1k_wait(void);
 
 extern unsigned int vced_count, vcei_count;
 extern struct cpuinfo_mips cpu_data[];
@@ -86,12 +87,13 @@
 
 /*
  * Bus types (default is ISA, but people can check others with these..)
- * MCA_bus hardcoded to 0 for now.
- *
- * This needs to be extended since MIPS systems are being delivered with
- * numerous different types of bus systems.
  */
+#ifdef CONFIG_EISA
 extern int EISA_bus;
+#else
+#define EISA_bus (0)
+#endif
+
 #define MCA_bus 0
 #define MCA_bus__is_a_macro /* for versions in ksyms.c */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/r4kcacheops.h linux-2.4.20/include/asm-mips64/r4kcacheops.h
--- linux-2.4.19/include/asm-mips64/r4kcacheops.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/r4kcacheops.h	2002-10-29 11:18:49.000000000 +0000
@@ -35,6 +35,7 @@
 #define Hit_Writeback_Inv_D	0x15
 					/* 0x16 is unused */
 #define Hit_Writeback_Inv_SD	0x17
+#define R5K_Page_Invalidate_S	0x17
 #define Hit_Writeback_I		0x18
 #define Hit_Writeback_D		0x19
 					/* 0x1a is unused */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/riscos-syscall.h linux-2.4.20/include/asm-mips64/riscos-syscall.h
--- linux-2.4.19/include/asm-mips64/riscos-syscall.h	2000-11-29 05:42:04.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/riscos-syscall.h	2002-10-29 11:18:39.000000000 +0000
@@ -220,7 +220,7 @@
 #define __NR_SVR4_reserved62		(__NR_SVR4 + 199)
 #define __NR_SVR4_reserved63		(__NR_SVR4 + 200)
 #define __NR_SVR4_aread			(__NR_SVR4 + 201)
-#define __NR_SVR4_awrite		(__NR_SVR4 + 202)	
+#define __NR_SVR4_awrite		(__NR_SVR4 + 202)
 #define __NR_SVR4_listio		(__NR_SVR4 + 203)
 #define __NR_SVR4_mips_acancel		(__NR_SVR4 + 204)
 #define __NR_SVR4_astatus		(__NR_SVR4 + 205)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/rrm.h linux-2.4.20/include/asm-mips64/rrm.h
--- linux-2.4.19/include/asm-mips64/rrm.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/rrm.h	2002-10-29 11:18:36.000000000 +0000
@@ -77,7 +77,7 @@
  * RRM_BINDPROCTORN:
  *
  * Return value when the X server calls it: 0
- */ 
+ */
 struct RRM_BindProcToRN {
 	int      rnid;
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/scatterlist.h linux-2.4.20/include/asm-mips64/scatterlist.h
--- linux-2.4.19/include/asm-mips64/scatterlist.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/scatterlist.h	2002-10-29 11:18:36.000000000 +0000
@@ -1,21 +1,22 @@
-#ifndef __ASM_MIPS64_SCATTERLIST_H
-#define __ASM_MIPS64_SCATTERLIST_H
+#ifndef __ASM_SCATTERLIST_H
+#define __ASM_SCATTERLIST_H
 
 struct scatterlist {
-	char *  address;	/* Location data is to be transferred to */
-	struct page *page;
-	unsigned int length;
-
-	__u32 dma_address;
+	char * address;		/* Location data is to be transferred to,
+				   NULL for highmem page */
+	struct page * page;	/* Location for highmem page, if any */
+	unsigned int offset;
+	dma_addr_t dma_address;
+	unsigned long length;
 };
 
 struct mmu_sglist {
-        char *addr;
-        char *__dont_touch;
-        unsigned int len;
-        __u32 dma_addr;
+	char *addr;
+	char *__dont_touch;
+	unsigned long len;
+	dma_addr_t dvma_addr;
 };
 
-#define ISA_DMA_THRESHOLD (0x00ffffffUL)
+#define ISA_DMA_THRESHOLD (0x00ffffff)
 
-#endif /* __ASM_MIPS64_SCATTERLIST_H */
+#endif /* __ASM_SCATTERLIST_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/semaphore-helper.h linux-2.4.20/include/asm-mips64/semaphore-helper.h
--- linux-2.4.19/include/asm-mips64/semaphore-helper.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/semaphore-helper.h	2002-10-29 11:18:31.000000000 +0000
@@ -17,20 +17,18 @@
 	atomic_inc(&sem->waking);
 }
 
-static inline int
-waking_non_zero(struct semaphore *sem)
+static inline int waking_non_zero(struct semaphore *sem)
 {
 	int ret, tmp;
 
 	__asm__ __volatile__(
-	"1:\tll\t%1, %2\n\t"
+	"1:\tll\t%1, %2\t\t\t# waking_non_zero\n\t"
 	"blez\t%1, 2f\n\t"
 	"subu\t%0, %1, 1\n\t"
 	"sc\t%0, %2\n\t"
-	"beqz\t%0, 1b\n\t"
+	"beqz\t%0, 1b\n"
 	"2:"
-	".text"
-	: "=r" (ret), "=r" (tmp), "=m" (sem->waking)
+	: "=r" (ret), "=r" (tmp), "+m" (sem->waking)
 	: "0" (0));
 
 	return ret;
@@ -43,17 +41,17 @@
  *	-EINTR	interrupted
  *
  * We must undo the sem->count down_interruptible decrement
- * simultaneously and atomicly with the sem->waking adjustment,
+ * simultaneously and atomically with the sem->waking adjustment,
  * otherwise we can race with wake_one_more.
  *
- * This is accomplished by doing a 64-bit ll/sc on the 2 32-bit words.
+ * This is accomplished by doing a 64-bit lld/scd on the 2 32-bit words.
  *
  * Pseudocode:
  *
  * If(sem->waking > 0) {
  *	Decrement(sem->waking)
  *	Return(SUCCESS)
- * } else If(segnal_pending(tsk)) {
+ * } else If(signal_pending(tsk)) {
  *	Increment(sem->count)
  *	Return(-EINTR)
  * } else {
@@ -102,7 +100,7 @@
 	"b\t2f\n"
 	"1:\tbeqz\t%3, 2f\n\t"
 	"li\t%0, %4\n\t"
-	/* 
+	/*
 	 * It would be nice to assume that sem->count
 	 * is != -1, but we will guard against that case
 	 */
@@ -124,12 +122,11 @@
 }
 
 /*
- * waking_non_zero_trylock is unused.  we do everything in 
+ * waking_non_zero_trylock is unused.  we do everything in
  * down_trylock and let non-ll/sc hosts bounce around.
  */
 
-static inline int
-waking_non_zero_trylock(struct semaphore *sem)
+static inline int waking_non_zero_trylock(struct semaphore *sem)
 {
 #if WAITQUEUE_DEBUG
 	CHECK_MAGIC(sem->__magic);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/semaphore.h linux-2.4.20/include/asm-mips64/semaphore.h
--- linux-2.4.19/include/asm-mips64/semaphore.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/semaphore.h	2002-10-29 11:18:48.000000000 +0000
@@ -109,7 +109,7 @@
  * down_trylock returns 0 on success, 1 if we failed to get the lock.
  *
  * We must manipulate count and waking simultaneously and atomically.
- * Here, we this by using ll/sc on the pair of 32-bit words.
+ * Here, we do this by using lld/scd on the pair of 32-bit words.
  *
  * Pseudocode:
  *
@@ -170,4 +170,9 @@
 		__up(sem);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif /* _ASM_SEMAPHORE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sembuf.h linux-2.4.20/include/asm-mips64/sembuf.h
--- linux-2.4.19/include/asm-mips64/sembuf.h	2000-02-25 06:53:35.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sembuf.h	2002-10-29 11:18:35.000000000 +0000
@@ -1,7 +1,7 @@
 #ifndef _ASM_SEMBUF_H
 #define _ASM_SEMBUF_H
 
-/* 
+/*
  * The semid64_ds structure for the MIPS architecture.
  * Note extra padding because this structure is passed back and forth
  * between kernel and user space.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/serial.h linux-2.4.20/include/asm-mips64/serial.h
--- linux-2.4.19/include/asm-mips64/serial.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/serial.h	2002-10-29 11:18:36.000000000 +0000
@@ -20,6 +20,39 @@
  */
 #define BASE_BAUD (1843200 / 16)
 
+#ifdef CONFIG_HAVE_STD_PC_SERIAL_PORT
+
+/* Standard COM flags (except for COM4, because of the 8514 problem) */
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+#endif
+
+#define STD_SERIAL_PORT_DEFNS			\
+	/* UART CLK   PORT IRQ     FLAGS        */			\
+	{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },	/* ttyS0 */	\
+	{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },	/* ttyS1 */	\
+	{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },	/* ttyS2 */	\
+	{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },	/* ttyS3 */
+
+#else /* CONFIG_HAVE_STD_PC_SERIAL_PORTS */
+#define STD_SERIAL_PORT_DEFNS
+#endif /* CONFIG_HAVE_STD_PC_SERIAL_PORTS */
+
+#ifdef CONFIG_MIPS_SEAD
+#include <asm/mips-boards/sead.h>
+#include <asm/mips-boards/seadint.h>
+#define SEAD_SERIAL_PORT_DEFNS                  \
+	/* UART CLK   PORT IRQ     FLAGS        */                      \
+	{ 0, SEAD_BASE_BAUD, SEAD_UART0_REGS_BASE, SEADINT_UART0, STD_COM_FLAGS },     /* ttyS0 */
+#else
+#define SEAD_SERIAL_PORT_DEFNS
+#endif
+
+
 #ifdef CONFIG_SGI_IP27
 
 /*
@@ -39,8 +72,8 @@
  *
  * The first one to do a register_console becomes the preferred console
  * (if there is no kernel command line console= directive). /dev/console
- * (ie 5, 1) is then "aliased" into the device number returned by the 
- * "device" routine referred to in this console structure 
+ * (ie 5, 1) is then "aliased" into the device number returned by the
+ * "device" routine referred to in this console structure
  * (ip27prom_console_dev).
  *
  * Also look in ip27-pci.c:pci_fixuop_ioc3() for some comments on working
@@ -87,14 +120,16 @@
           flags: STD_COM_FLAGS,				\
           iomem_base: (u8*)MACE_BASE+MACEISA_SER2_BASE,	\
           iomem_reg_shift: 8,				\
-          io_type: SERIAL_IO_MEM},                      
+          io_type: SERIAL_IO_MEM},
 #else
 #define IP32_SERIAL_PORT_DEFNS
 #endif /* CONFIG_SGI_IP31 */
 
 #define SERIAL_PORT_DFNS				\
 	IP27_SERIAL_PORT_DEFNS				\
-	IP32_SERIAL_PORT_DEFNS
+	IP32_SERIAL_PORT_DEFNS				\
+	SEAD_SERIAL_PORT_DEFNS				\
+	STD_SERIAL_PORT_DEFNS
 
 #define RS_TABLE_SIZE	64
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sgi/sgigio.h linux-2.4.20/include/asm-mips64/sgi/sgigio.h
--- linux-2.4.19/include/asm-mips64/sgi/sgigio.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sgi/sgigio.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,69 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * sgigio.h: Definitions for GIO bus found on SGI IP22 (and others by linux
+ *           unsupported) machines.
+ *
+ * Copyright (C) 2002 Ladislav Michl
+ */
+#ifndef _ASM_SGI_SGIGIO_H
+#define _ASM_SGI_SGIGIO_H
+
+/*
+ * There is 10MB of GIO address space for GIO64 slot devices
+ * slot#   slot type address range            size
+ * -----   --------- ----------------------- -----
+ *   0     GFX       0x1f000000 - 0x1f3fffff   4MB
+ *   1     EXP0      0x1f400000 - 0x1f5fffff   2MB
+ *   2     EXP1      0x1f600000 - 0x1f9fffff   4MB
+ *
+ * There are un-slotted devices, HPC, I/O and misc devices, which are grouped
+ * into the HPC address space.
+ *   -     MISC      0x1fb00000 - 0x1fbfffff   1MB
+ *
+ * Following space is reserved and unused
+ *   -     RESERVED  0x18000000 - 0x1effffff 112MB
+ *
+ * The GIO specification tends to use slot numbers while the MC specification
+ * tends to use slot types.
+ *
+ * slot0  - the "graphics" (GFX) slot but there is no requirement that
+ *          a graphics dev may only use this slot
+ * slot1  - this is the "expansion"-slot 0 (EXP0), do not confuse with
+ *          slot 0 (GFX).
+ * slot2  - this is the "expansion"-slot 1 (EXP1), do not confuse with
+ *          slot 1 (EXP0).
+ */
+
+#define GIO_SLOT_GFX	0
+#define GIO_SLOT_GIO1	1
+#define GIO_SLOT_GIO2	2
+#define GIO_NUM_SLOTS	3
+
+#define GIO_ANY_ID	0xff
+
+#define GIO_VALID_ID_ONLY	0x01
+#define GIO_IFACE_64		0x02
+#define GIO_HAS_ROM		0x04
+
+struct gio_dev {
+	unsigned char	device;
+	unsigned char	revision;
+	unsigned short	vendor;
+	unsigned char	flags;
+
+	unsigned char	slot_number;
+	unsigned long	base_addr;
+	unsigned int	map_size;
+
+	char		*name;
+	char		slot_name[5];
+};
+
+extern struct gio_dev* gio_find_device(unsigned char device, const struct gio_dev *from);
+
+extern void sgigio_init(void);
+
+#endif /* _ASM_SGI_SGIGIO_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sgi/sgihpc.h linux-2.4.20/include/asm-mips64/sgi/sgihpc.h
--- linux-2.4.19/include/asm-mips64/sgi/sgihpc.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sgi/sgihpc.h	2002-10-29 11:18:37.000000000 +0000
@@ -45,8 +45,8 @@
 	hpcreg pbdma_bptr;	/* pbus dma channel buffer ptr */
 	hpcreg pbdma_dptr;	/* pbus dma channel desc ptr */
 	char _unused1[PAGE_SIZE - (2 * sizeof(hpcreg))]; /* padding */
-	hpcreg pbdma_ctrl;	/* pbus dma channel control register has 
-				 * copletely different meaning for read 
+	hpcreg pbdma_ctrl;	/* pbus dma channel control register has
+				 * copletely different meaning for read
 				 * compared with write */
 	/* read */
 #define HPC3_PDMACTRL_INT	0x00000001 /* interrupt (cleared after read) */
@@ -235,7 +235,7 @@
 	hpcreg scsi1_ext[256];	/* SCSI channel 1 external regs */
 	char _unused4[0x07c00];	/* It'll only hurt a little... */
 
-	/* Ethernet external registers. Noone use them so we need some 
+	/* Ethernet external registers. Noone use them so we need some
 	 * padding instead.
 	 */
 	char _unused5[0x04000]; /* It'll hurt a lot if you leave this out */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sgi/sgint23.h linux-2.4.20/include/asm-mips64/sgi/sgint23.h
--- linux-2.4.19/include/asm-mips64/sgi/sgint23.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sgi/sgint23.h	2002-10-29 11:18:38.000000000 +0000
@@ -16,17 +16,18 @@
 /* These are the virtual IRQ numbers, we divide all IRQ's into
  * 'spaces', the 'space' determines where and how to enable/disable
  * that particular IRQ on an SGI machine. HPC DMA and MC DMA interrups
- * are not supported this way. Driver is supposed to allocate HPC/MC 
+ * are not supported this way. Driver is supposed to allocate HPC/MC
  * interrupt as shareable and then look to proper status bit (see
- * HAL2 driver). This will prevent many complications, trust me ;-) 
+ * HAL2 driver). This will prevent many complications, trust me ;-)
  *	--ladis
  */
-#define SGINT_CPU	 0	/* MIPS CPU define 8 interrupt sources */
-#define SGINT_LOCAL0	 8	/* INDY has 8 local0 irq levels */
-#define SGINT_LOCAL1	16	/* INDY has 8 local1 irq levels */
-#define SGINT_LOCAL2	24	/* INDY has 8 local2 vectored irq levels */
-#define SGINT_LOCAL3	32	/* INDY has 8 local3 vectored irq levels */
-#define SGINT_END	40	/* End of 'spaces' */
+#define SGINT_EISA	0	/* INDIGO 2 has 16 EISA irq levels */
+#define SGINT_CPU	16	/* MIPS CPU define 8 interrupt sources */
+#define SGINT_LOCAL0	24	/* INDY has 8 local0 irq levels */
+#define SGINT_LOCAL1	32	/* INDY has 8 local1 irq levels */
+#define SGINT_LOCAL2	40	/* INDY has 8 local2 vectored irq levels */
+#define SGINT_LOCAL3	48	/* INDY has 8 local3 vectored irq levels */
+#define SGINT_END	56	/* End of 'spaces' */
 
 /*
  * Individual interrupt definitions for the INDY and Indigo2
@@ -42,7 +43,7 @@
 #define SGI_TIMER_IRQ	SGINT_CPU + 7
 
 #define SGI_FIFO_IRQ	SGINT_LOCAL0 + 0	/* FIFO full */
-#define SGI_GIO_0_IRQ	SGI_FIFO_IRQ		/* GIO-0 */	
+#define SGI_GIO_0_IRQ	SGI_FIFO_IRQ		/* GIO-0 */
 #define SGI_WD93_0_IRQ	SGINT_LOCAL0 + 1	/* 1st onboard WD93 */
 #define SGI_WD93_1_IRQ	SGINT_LOCAL0 + 2	/* 2nd onboard WD93 */
 #define SGI_ENET_IRQ	SGINT_LOCAL0 + 3	/* onboard ethernet */
@@ -87,7 +88,7 @@
 #define ISTAT0_LPR	0x20
 #define ISTAT0_HPC2	0x40
 #define ISTAT0_LIO2	0x80
-	
+
 #ifdef __MIPSEB__
 	unsigned char _unused1[3];
 	volatile unsigned char imask0;	/* Interrupt mask zero */
@@ -107,7 +108,7 @@
 #define ISTAT1_AFAIL	0x20
 #define ISTAT1_VIDEO	0x40
 #define ISTAT1_GIO2	0x80
-	
+
 #ifdef __MIPSEB__
 	unsigned char _unused3[3];
 	volatile unsigned char imask1;		/* Interrupt mask one */
@@ -199,7 +200,7 @@
 #endif
 #define INT2_TCLEAR_T0CLR	0x1	/* Clear timer0 IRQ */
 #define INT2_TCLEAR_T1CLR	0x2	/* Clear timer1 IRQ */
-/* I am guesing there are only two unused registers here 
+/* I am guesing there are only two unused registers here
  * but I could be wrong...			- andrewb
  */
 /*	u32 _unused[3]; */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sgialib.h linux-2.4.20/include/asm-mips64/sgialib.h
--- linux-2.4.19/include/asm-mips64/sgialib.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sgialib.h	2002-10-29 11:18:35.000000000 +0000
@@ -6,7 +6,7 @@
  * SGI ARCS firmware interface library for the Linux kernel.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- * Copyright (C) 2001 Ralf Baechle (ralf@gnu.org)
+ * Copyright (C) 2001, 2002 Ralf Baechle (ralf@gnu.org)
  */
 #ifndef _ASM_SGIALIB_H
 #define _ASM_SGIALIB_H
@@ -24,12 +24,11 @@
 #define prom_argc(index) ((char *) (long) _prom_argc[(index)])
 
 extern int prom_flags;
-#define PROM_FLAG_ARCS  1
+#define PROM_FLAG_ARCS			1
+#define PROM_FLAG_USE_AS_CONSOLE	2
 
-/* Init the PROM library and it's internal data structures.  Called
- * at boot time from head.S before start_kernel is invoked.
- */
-extern int prom_init(int argc, char **argv, char **envp);
+/* Init the PROM library and it's internal data structures. */
+extern void prom_init(int argc, char **argv, char **envp, int *prom_vec);
 
 /* Simple char-by-char console I/O. */
 extern void prom_putchar(char c);
@@ -41,9 +40,9 @@
 /* Memory descriptor management. */
 #define PROM_MAX_PMEMBLOCKS    32
 struct prom_pmemblock {
-	LONG	base;		/* Within KSEG0 or XKPHYS. */
+	LONG base;		/* Within KSEG0 or XKPHYS. */
 	ULONG size;		/* In bytes. */
-        ULONG type;		/* free or prom memory */
+	ULONG type;		/* free or prom memory */
 };
 
 /* Get next memory descriptor after CURR, returns first descriptor
@@ -58,9 +57,6 @@
 extern void prom_meminit(void);
 extern void prom_fixup_mem_map(unsigned long start_mem, unsigned long end_mem);
 
-/* Returns pointer to PROM physical memory block array. */
-extern struct prom_pmemblock *prom_getpblock_array(void);
-
 /* PROM device tree library routines. */
 #define PROM_NULL_COMPONENT ((pcomponent *) 0)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sgiarcs.h linux-2.4.20/include/asm-mips64/sgiarcs.h
--- linux-2.4.19/include/asm-mips64/sgiarcs.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sgiarcs.h	2002-10-29 11:18:38.000000000 +0000
@@ -13,6 +13,7 @@
 #define _ASM_SGIARCS_H
 
 #include <linux/config.h>
+#include <asm/types.h>
 #include <asm/arc/types.h>
 
 /* Various ARCS error codes. */
@@ -115,7 +116,7 @@
 	arc_prog,    /* A loaded program resides here */
 	arc_atmp,    /* temporary storage area */
 	arc_aperm,   /* permanent storage */
-	arc_fcontig, /* Contiguous and free */    
+	arc_fcontig, /* Contiguous and free */
 };
 
 union linux_memtypes {
@@ -164,11 +165,11 @@
 /* This prom has a bolixed design. */
 struct linux_bigint {
 #ifdef __MIPSEL__
-	unsigned long lo;
-	long hi;
+	u32 lo;
+	s32 hi;
 #else /* !(__MIPSEL__) */
-	long hi;
-	unsigned long lo;
+	s32 hi;
+	u32 lo;
 #endif
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/shmbuf.h linux-2.4.20/include/asm-mips64/shmbuf.h
--- linux-2.4.19/include/asm-mips64/shmbuf.h	2000-02-25 06:53:35.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/shmbuf.h	2002-10-29 11:18:32.000000000 +0000
@@ -1,7 +1,7 @@
 #ifndef _ASM_SHMBUF_H
 #define _ASM_SHMBUF_H
 
-/* 
+/*
  * The shmid64_ds structure for the MIPS architecture.
  * Note extra padding because this structure is passed back and forth
  * between kernel and user space.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/shmiq.h linux-2.4.20/include/asm-mips64/shmiq.h
--- linux-2.4.19/include/asm-mips64/shmiq.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/shmiq.h	2002-10-29 11:18:31.000000000 +0000
@@ -9,7 +9,7 @@
  *
  * This also contains some streams and idev bits.
  *
- * They may contain errors, please, refer to the source code of the Linux  
+ * They may contain errors, please, refer to the source code of the Linux
  * kernel for a definitive answer on what we have implemented
  *
  * Miguel.
@@ -97,7 +97,7 @@
  * head   is the user index into the events, user can modify this one.
  * tail   is managed by the kernel.
  * flags  is one of SHMIQ_OVERFLOW or SHMIQ_CORRUPTED
- *        if OVERFLOW is set it seems ioctl QUIOCSERVICED should be called 
+ *        if OVERFLOW is set it seems ioctl QUIOCSERVICED should be called
  *        to notify the kernel.
  * events where the kernel sticks the events.
  */
@@ -192,14 +192,14 @@
         unsigned        hwMaxRes;
         int             hwMinVal;
         int             hwMaxVal;
-	
+
         unsigned char   possibleModes;
 #define IDEV_ABSOLUTE           0x0
 #define IDEV_RELATIVE           0x1
 #define IDEV_EITHER             0x2
-	
+
         unsigned char   mode;	/* One of: IDEV_ABSOLUTE, IDEV_RELATIVE */
-	
+
         unsigned short  resolution;
         int             minVal;
         int             maxVal;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/64bit.h linux-2.4.20/include/asm-mips64/sibyte/64bit.h
--- linux-2.4.19/include/asm-mips64/sibyte/64bit.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/64bit.h	2002-10-29 11:18:31.000000000 +0000
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2001 Broadcom Corporation
+ * Copyright (C) 2000, 2001 Broadcom Corporation
+ * Copyright (C) 2002 Ralf Baechle
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -10,20 +11,78 @@
  * 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.
  */
 
-#ifndef _ASM_SIBYTE_64BIT_H
-#define _ASM_SIBYTE_64BIT_H
+#ifndef __ASM_SIBYTE_64BIT_H
+#define __ASM_SIBYTE_64BIT_H
 
+#include <linux/config.h>
 #include <linux/types.h>
 
-/* These are provided so as to be able to use common
-   driver code for the 32-bit and 64-bit trees */
+#ifdef CONFIG_MIPS32
+
+#include <asm/system.h>
+
+/*
+ * This is annoying...we can't actually write the 64-bit IO register properly
+ * without having access to 64-bit registers...  which doesn't work by default
+ * in o32 format...grrr...
+ */
+static inline void out64(u64 val, unsigned long addr)
+{
+	u32 low, high;
+	unsigned long flags;
+	high = val >> 32;
+	low = val & 0xffffffff;
+	// save_flags(flags);
+	__save_and_cli(flags);
+	__asm__ __volatile__ (
+		".set push\n"
+		".set noreorder\n"
+		".set noat\n"
+		".set mips4\n"
+		"   dsll32 $2, %1, 0   \n"
+		"   dsll32 $1, %0, 0   \n"
+		"   dsrl32 $2, $2, 0   \n"
+		"   or     $1, $1, $2  \n"
+		"   sd $1, (%2)\n"
+		".set pop\n"
+		::"r" (high), "r" (low), "r" (addr)
+		:"$1", "$2");
+	__restore_flags(flags);
+}
+
+static inline u64 in64(unsigned long addr)
+{
+	u32 low, high;
+	unsigned long flags;
+	__save_and_cli(flags);
+	__asm__ __volatile__ (
+		".set push\n"
+		".set noreorder\n"
+		".set noat     \n"
+		".set mips4    \n"
+		"  ld     %1, (%2)\n"
+		"  dsra32 %0, %1, 0\n"
+		"  sll    %1, %1, 0\n"
+		".set pop\n"
+		:"=r" (high), "=r" (low): "r" (addr));
+	__restore_flags(flags);
+	return (((u64)high) << 32) | low;
+}
+
+#endif /* CONFIG_MIPS32 */
+
+#ifdef CONFIG_MIPS64
 
+/*
+ * These are provided so as to be able to use common
+ * driver code for the 32-bit and 64-bit trees
+ */
 extern inline void out64(u64 val, unsigned long addr)
 {
 	*(volatile unsigned long *)addr = val;
@@ -34,4 +93,20 @@
 	return *(volatile unsigned long *)addr;
 }
 
-#endif /* _ASM_SIBYTE_64BIT_H */
+#endif /* CONFIG_MIPS64 */
+
+/*
+ * Avoid interrupt mucking, just adjust the address for 4-byte access.
+ * Assume the addresses are 8-byte aligned.
+ */
+
+#ifdef __MIPSEB__
+#define __CSR_32_ADJUST 4
+#else
+#define __CSR_32_ADJUST 0
+#endif
+
+#define csr_out32(v,a) (*(u32 *)((unsigned long)(a) + __CSR_32_ADJUST) = (v))
+#define csr_in32(a)    (*(u32 *)((unsigned long)(a) + __CSR_32_ADJUST))
+
+#endif /* __ASM_SIBYTE_64BIT_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/board.h linux-2.4.20/include/asm-mips64/sibyte/board.h
--- linux-2.4.19/include/asm-mips64/sibyte/board.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/board.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2000, 2001 Broadcom Corporation
+ *
+ * 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.
+ */
+
+#ifndef _SIBYTE_BOARD_H
+#define _SIBYTE_BOARD_H
+
+#if defined(CONFIG_SIBYTE_PTSWARM) || defined(CONFIG_SIBYTE_SWARM)
+#include <asm/sibyte/swarm.h>
+#endif
+
+#endif
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/io.h linux-2.4.20/include/asm-mips64/sibyte/io.h
--- linux-2.4.19/include/asm-mips64/sibyte/io.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/io.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,21 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000 Ralf Baechle
+ * Copyright (C) 2000 Silicon Graphics, Inc.
+ */
+#ifndef _ASM_SGI_IO_H
+#define _ASM_SGI_IO_H
+
+#include <asm/addrspace.h>
+
+#define IO_SPACE_BASE K1BASE
+
+/* For Indigo2.  */
+#define IO_SPACE_LIMIT 0xffff
+
+/* XXX ISA specific functions go here here.  */
+
+#endif /* _ASM_SGI_IO_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250.h linux-2.4.20/include/asm-mips64/sibyte/sb1250.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250.h	2002-10-29 11:18:32.000000000 +0000
@@ -10,7 +10,7 @@
  * 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.
@@ -19,9 +19,21 @@
 #ifndef _ASM_SIBYTE_SB1250_H
 #define _ASM_SIBYTE_SB1250_H
 
+#ifndef __ASSEMBLY__
+
+#include <asm/addrspace.h>
+
+/* For revision/pass information */
+#include <asm/sibyte/sb1250_scd.h>
+extern unsigned int sb1250_pass;
+
 extern void sb1250_time_init(void);
+extern unsigned long sb1250_gettimeoffset(void);
 extern void sb1250_mask_irq(int cpu, int irq);
 extern void sb1250_unmask_irq(int cpu, int irq);
 extern void sb1250_smp_finish(void);
+#endif
+
+#define IO_SPACE_BASE KSEG1
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250_defs.h linux-2.4.20/include/asm-mips64/sibyte/sb1250_defs.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250_defs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250_defs.h	2002-10-29 11:18:31.000000000 +0000
@@ -1,21 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
-    *  Global constants and macros		File: sb1250_defs.h	
-    *  
+    *
+    *  Global constants and macros		File: sb1250_defs.h
+    *
     *  This file contains macros and definitions used by the other
     *  include files.
     *
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -25,38 +27,38 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
 
 /*  *********************************************************************
     *  Naming schemes for constants in these files:
-    *  
-    *  M_xxx           MASK constant (identifies bits in a register). 
+    *
+    *  M_xxx           MASK constant (identifies bits in a register).
     *                  For multi-bit fields, all bits in the field will
     *                  be set.
     *
     *  K_xxx           "Code" constant (value for data in a multi-bit
     *                  field).  The value is right justified.
     *
-    *  V_xxx           "Value" constant.  This is the same as the 
+    *  V_xxx           "Value" constant.  This is the same as the
     *                  corresponding "K_xxx" constant, except it is
     *                  shifted to the correct position in the register.
     *
     *  S_xxx           SHIFT constant.  This is the number of bits that
-    *                  a field value (code) needs to be shifted 
+    *                  a field value (code) needs to be shifted
     *                  (towards the left) to put the value in the right
     *                  position for the register.
     *
-    *  A_xxx           ADDRESS constant.  This will be a physical 
+    *  A_xxx           ADDRESS constant.  This will be a physical
     *                  address.  Use the PHYS_TO_K1 macro to generate
     *                  a K1SEG address.
     *
     *  R_xxx           RELATIVE offset constant.  This is an offset from
     *                  an A_xxx constant (usually the first register in
     *                  a group).
-    *  
+    *
     *  G_xxx(X)        GET value.  This macro obtains a multi-bit field
     *                  from a register, masks it, and shifts it to
     *                  the bottom of the register (retrieving a K_xxx
@@ -74,7 +76,7 @@
 #define _SB1250_DEFS_H
 
 /*
- * Cast to 64-bit number.  Presumably the syntax is different in 
+ * Cast to 64-bit number.  Presumably the syntax is different in
  * assembly language.
  *
  * Note: you'll need to define uint32_t and uint64_t in your headers.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250_dma.h linux-2.4.20/include/asm-mips64/sibyte/sb1250_dma.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250_dma.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250_dma.h	2002-10-29 11:18:48.000000000 +0000
@@ -1,24 +1,24 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  DMA definitions				File: sb1250_dma.h
-    *  
+    *
     *  This module contains constants and macros useful for
     *  programming the SB1250's DMA controllers, both the data mover
     *  and the Ethernet DMA.
-    *  
-    *  SB1250 specification level:  0.2
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -28,7 +28,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -43,9 +43,9 @@
     *  DMA Registers
     ********************************************************************* */
 
-/* 
+/*
  * Ethernet and Serial DMA Configuration Register 0  (Table 7-4)
- * Registers: DMA_CONFIG0_MAC_x_RX_CH_0 
+ * Registers: DMA_CONFIG0_MAC_x_RX_CH_0
  * Registers: DMA_CONFIG0_MAC_x_TX_CH_0
  * Registers: DMA_CONFIG0_SER_x_RX
  * Registers: DMA_CONFIG0_SER_x_TX
@@ -83,7 +83,7 @@
 
 /*
  * Ethernet and Serial DMA Configuration Register 2 (Table 7-5)
- * Registers: DMA_CONFIG1_MAC_x_RX_CH_0 
+ * Registers: DMA_CONFIG1_MAC_x_RX_CH_0
  * Registers: DMA_CONFIG1_DMA_x_TX_CH_0
  * Registers: DMA_CONFIG1_SER_x_RX
  * Registers: DMA_CONFIG1_SER_x_TX
@@ -131,11 +131,11 @@
 /*
  * DMA Descriptor Count Registers (Table 7-8)
  */
- 
+
 /* No bitfields */
 
 
-/* 
+/*
  * Current Descriptor Address Register (Table 7-11)
  */
 
@@ -202,13 +202,16 @@
 #define V_DMA_DSCRB_PKT_SIZE(x)     _SB_MAKEVALUE(x,S_DMA_DSCRB_PKT_SIZE)
 #define G_DMA_DSCRB_PKT_SIZE(x)     _SB_GETVALUE(x,S_DMA_DSCRB_PKT_SIZE,M_DMA_DSCRB_PKT_SIZE)
 
-/* 
+/*
  * Ethernet Descriptor Status Bits (Table 7-15)
  */
 
 #define M_DMA_ETHRX_BADIP4CS        _SB_MAKEMASK1(51)
 #define M_DMA_ETHRX_DSCRERR	    _SB_MAKEMASK1(52)
 
+/* Note: BADTCPCS is actually in DSCR_A */
+#define M_DMA_ETHRX_BADTCPCS	_SB_MAKEMASK1(0)	/* PASS2 */
+
 #define S_DMA_ETHRX_RXCH            53
 #define M_DMA_ETHRX_RXCH            _SB_MAKEMASK(2,S_DMA_ETHRX_RXCH)
 #define V_DMA_ETHRX_RXCH(x)         _SB_MAKEVALUE(x,S_DMA_ETHRX_RXCH)
@@ -241,7 +244,7 @@
 
 #define M_DMA_ETHTX_SOP	    	    _SB_MAKEMASK1(63)
 
-/* 
+/*
  * Ethernet Transmit Options (Table 7-17)
  */
 
@@ -294,7 +297,7 @@
     *  Data Mover Registers
     ********************************************************************* */
 
-/* 
+/*
  * Data Mover Descriptor Base Address Register (Table 7-22)
  * Register: DM_DSCR_BASE_0
  * Register: DM_DSCR_BASE_1
@@ -302,10 +305,10 @@
  * Register: DM_DSCR_BASE_3
  */
 
-#define M_DM_DSCR_BASE_MBZ          _SB_MAKEMASK(3,0)
+#define M_DM_DSCR_BASE_MBZ          _SB_MAKEMASK(4,0)
 
 /*  Note: Just mask the base address and then OR it in. */
-#define S_DM_DSCR_BASE_ADDR         _SB_MAKE64(3)
+#define S_DM_DSCR_BASE_ADDR         _SB_MAKE64(4)
 #define M_DM_DSCR_BASE_ADDR         _SB_MAKEMASK(36,S_DM_DSCR_BASE_ADDR)
 
 #define S_DM_DSCR_BASE_RINGSZ       _SB_MAKE64(40)
@@ -331,7 +334,7 @@
 #define M_DM_DSCR_BASE_ABORT        _SB_MAKEMASK1(62)
 #define M_DM_DSCR_BASE_ENABL        _SB_MAKEMASK1(63)
 
-/* 
+/*
  * Data Mover Descriptor Count Register (Table 7-25)
  */
 
@@ -364,7 +367,10 @@
 #define M_DM_DSCRA_UN_DEST          _SB_MAKEMASK1(40)
 #define M_DM_DSCRA_UN_SRC           _SB_MAKEMASK1(41)
 #define M_DM_DSCRA_INTERRUPT        _SB_MAKEMASK1(42)
-#define M_DM_DSCRA_THROTTLE         _SB_MAKEMASK1(43)
+/*#define M_DM_DSCRA_THROTTLE         _SB_MAKEMASK1(43) */ /* REMOVED PASS2 */
+
+#define M_DM_DSCRA_RD_BKOFF	    _SB_MAKEMASK1(52)		/* PASS2 */
+#define M_DM_DSCRA_WR_BKOFF	    _SB_MAKEMASK1(53)		/* PASS2 */
 
 #define S_DM_DSCRA_DIR_DEST         _SB_MAKE64(44)
 #define M_DM_DSCRA_DIR_DEST         _SB_MAKEMASK(2,S_DM_DSCRA_DIR_DEST)
@@ -398,7 +404,7 @@
 #define M_DM_DSCRA_L2C_DEST         _SB_MAKEMASK1(50)
 #define M_DM_DSCRA_L2C_SRC          _SB_MAKEMASK1(51)
 
-#define M_DM_DSCRA_RESERVED2        _SB_MAKEMASK(12,52)
+#define M_DM_DSCRA_RESERVED2        _SB_MAKEMASK(10,54)
 
 /*
  * Data Mover Descriptor Doubleword "B"  (Table 7-25)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250_genbus.h linux-2.4.20/include/asm-mips64/sibyte/sb1250_genbus.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250_genbus.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250_genbus.h	2002-10-29 11:18:34.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  Generic Bus Constants                     File: sb1250_genbus.h
-    *  
-    *  This module contains constants and macros useful for 
+    *
+    *  This module contains constants and macros useful for
     *  manipulating the SB1250's Generic Bus interface
-    *  
-    *  SB1250 specification level:  01/02/2002
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -48,11 +48,13 @@
 #define M_IO_WIDTH_SEL		_SB_MAKEMASK(2,S_IO_WIDTH_SEL)
 #define K_IO_WIDTH_SEL_1	0
 #define K_IO_WIDTH_SEL_2	1
+#define K_IO_WIDTH_SEL_1L       2		/* PASS2 */
 #define K_IO_WIDTH_SEL_4	3
 #define V_IO_WIDTH_SEL(x)	_SB_MAKEVALUE(x,S_IO_WIDTH_SEL)
 #define G_IO_WIDTH_SEL(x)	_SB_GETVALUE(x,S_IO_WIDTH_SEL,M_IO_WIDTH_SEL)
 
 #define M_IO_PARITY_ENA		_SB_MAKEMASK1(4)
+#define M_IO_BURST_EN		_SB_MAKEMASK1(5)	/* PASS2 */
 #define M_IO_PARITY_ODD		_SB_MAKEMASK1(6)
 #define M_IO_NONMUX		_SB_MAKEMASK1(7)
 
@@ -92,11 +94,18 @@
 #define V_IO_ALE_WIDTH(x)	_SB_MAKEVALUE(x,S_IO_ALE_WIDTH)
 #define G_IO_ALE_WIDTH(x)	_SB_GETVALUE(x,S_IO_ALE_WIDTH,M_IO_ALE_WIDTH)
 
+#define M_IO_EARLY_CS	        _SB_MAKEMASK1(3)	/* PASS2 */
+
 #define S_IO_ALE_TO_CS		4
 #define M_IO_ALE_TO_CS		_SB_MAKEMASK(2,S_IO_ALE_TO_CS)
 #define V_IO_ALE_TO_CS(x)	_SB_MAKEVALUE(x,S_IO_ALE_TO_CS)
 #define G_IO_ALE_TO_CS(x)	_SB_GETVALUE(x,S_IO_ALE_TO_CS,M_IO_ALE_TO_CS)
 
+#define S_IO_BURST_WIDTH           _SB_MAKE64(6)			/* PASS2 */
+#define M_IO_BURST_WIDTH           _SB_MAKEMASK(2,S_IO_BURST_WIDTH)	/* PASS2 */
+#define V_IO_BURST_WIDTH(x)        _SB_MAKEVALUE(x,S_IO_BURST_WIDTH)	/* PASS2 */
+#define G_IO_BURST_WIDTH(x)        _SB_GETVALUE(x,S_IO_BURST_WIDTH,M_IO_BURST_WIDTH)	/* PASS2 */
+
 #define S_IO_CS_WIDTH		8
 #define M_IO_CS_WIDTH		_SB_MAKEMASK(5,S_IO_CS_WIDTH)
 #define V_IO_CS_WIDTH(x)	_SB_MAKEVALUE(x,S_IO_CS_WIDTH)
@@ -117,6 +126,8 @@
 #define V_IO_ALE_TO_WRITE(x)	_SB_MAKEVALUE(x,S_IO_ALE_TO_WRITE)
 #define G_IO_ALE_TO_WRITE(x)	_SB_GETVALUE(x,S_IO_ALE_TO_WRITE,M_IO_ALE_TO_WRITE)
 
+#define M_IO_RDY_SYNC	        _SB_MAKEMASK1(3)	/* PASS2 */
+
 #define S_IO_WRITE_WIDTH	4
 #define M_IO_WRITE_WIDTH	_SB_MAKEMASK(4,S_IO_WRITE_WIDTH)
 #define V_IO_WRITE_WIDTH(x)	_SB_MAKEVALUE(x,S_IO_WRITE_WIDTH)
@@ -155,6 +166,7 @@
 #define M_IO_TIMEOUT_INT	_SB_MAKEMASK1(10)
 #define M_IO_ILL_ADDR_INT	_SB_MAKEMASK1(11)
 #define M_IO_MULT_CS_INT	_SB_MAKEMASK1(12)
+#define M_IO_COH_ERR	        _SB_MAKEMASK1(14)	/* PASS2 */
 
 /*
  * PCMCIA configuration register (Table 12-6)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250_int.h linux-2.4.20/include/asm-mips64/sibyte/sb1250_int.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250_int.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250_int.h	2002-10-29 11:18:51.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  Interrupt Mapper definitions		File: sb1250_int.h
-    *  
+    *
     *  This module contains constants for manipulating the SB1250's
     *  interrupt mapper and definitions for the interrupt sources.
-    *  
-    *  SB1250 specification level:  0.2
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -43,7 +43,7 @@
 
 /*
  * Interrupt sources (Table 4-8, UM 0.2)
- * 
+ *
  * First, the interrupt numbers.
  */
 
@@ -77,8 +77,8 @@
 #define K_INT_MBOX_1                27
 #define K_INT_MBOX_2                28
 #define K_INT_MBOX_3                29
-#define K_INT_SPARE_0               30
-#define K_INT_SPARE_1               31
+#define K_INT_CYCLE_CP0_INT	    30		/* PASS2 */
+#define K_INT_CYCLE_CP1_INT	    31		/* PASS2 */
 #define K_INT_GPIO_0                32
 #define K_INT_GPIO_1                33
 #define K_INT_GPIO_2                34
@@ -108,9 +108,9 @@
 #define K_INT_PCI_INTC              58
 #define K_INT_PCI_INTD              59
 #define K_INT_SPARE_2               60
-#define K_INT_SPARE_3               61
-#define K_INT_SPARE_4               62
-#define K_INT_SPARE_5               63
+#define K_INT_MAC_0_CH1		    61		/* PASS2 */
+#define K_INT_MAC_1_CH1		    62		/* PASS2 */
+#define K_INT_MAC_2_CH1		    63		/* PASS2 */
 
 /*
  * Mask values for each interrupt
@@ -146,8 +146,8 @@
 #define M_INT_MBOX_1                _SB_MAKEMASK1(K_INT_MBOX_1)
 #define M_INT_MBOX_2                _SB_MAKEMASK1(K_INT_MBOX_2)
 #define M_INT_MBOX_3                _SB_MAKEMASK1(K_INT_MBOX_3)
-#define M_INT_SPARE_0               _SB_MAKEMASK1(K_INT_SPARE_0)
-#define M_INT_SPARE_1               _SB_MAKEMASK1(K_INT_SPARE_1)
+#define M_INT_CYCLE_CP0_INT	    _SB_MAKEMASK1(K_INT_CYCLE_CP0_INT)	/* PASS2 */
+#define M_INT_CYCLE_CP1_INT	    _SB_MAKEMASK1(K_INT_CYCLE_CP1_INT)	/* PASS2 */
 #define M_INT_GPIO_0                _SB_MAKEMASK1(K_INT_GPIO_0)
 #define M_INT_GPIO_1                _SB_MAKEMASK1(K_INT_GPIO_1)
 #define M_INT_GPIO_2                _SB_MAKEMASK1(K_INT_GPIO_2)
@@ -177,9 +177,9 @@
 #define M_INT_PCI_INTC              _SB_MAKEMASK1(K_INT_PCI_INTC)
 #define M_INT_PCI_INTD              _SB_MAKEMASK1(K_INT_PCI_INTD)
 #define M_INT_SPARE_2               _SB_MAKEMASK1(K_INT_SPARE_2)
-#define M_INT_SPARE_3               _SB_MAKEMASK1(K_INT_SPARE_3)
-#define M_INT_SPARE_4               _SB_MAKEMASK1(K_INT_SPARE_4)
-#define M_INT_SPARE_5               _SB_MAKEMASK1(K_INT_SPARE_5)
+#define M_INT_MAC_0_CH1		    _SB_MAKEMASK1(K_INT_MAC_0_CH1)	/* PASS2 */
+#define M_INT_MAC_1_CH1		    _SB_MAKEMASK1(K_INT_MAC_1_CH1)	/* PASS2 */
+#define M_INT_MAC_2_CH1		    _SB_MAKEMASK1(K_INT_MAC_2_CH1)	/* PASS2 */
 
 /*
  * Interrupt mappings
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250_io.h linux-2.4.20/include/asm-mips64/sibyte/sb1250_io.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250_io.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250_io.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,21 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000 Ralf Baechle
- * Copyright (C) 2000 Silicon Graphics, Inc.
- */
-#ifndef _ASM_SGI_IO_H
-#define _ASM_SGI_IO_H
-
-#include <asm/addrspace.h>
-
-#define IO_SPACE_BASE K1BASE
-
-/* For Indigo2.  */
-#define IO_SPACE_LIMIT 0xffff
-
-/* XXX ISA specific functions go here here.  */
-
-#endif /* _ASM_SGI_IO_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250_l2c.h linux-2.4.20/include/asm-mips64/sibyte/sb1250_l2c.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250_l2c.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250_l2c.h	2002-10-29 11:18:35.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  L2 Cache constants and macros		File: sb1250_l2c.h
-    *  
+    *
     *  This module contains constants useful for manipulating the
     *  level 2 cache.
-    *  
-    *  SB1250 specification level:  0.2
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -76,6 +76,14 @@
 #define V_L2C_MGMT_INDEX(x)         _SB_MAKEVALUE(x,S_L2C_MGMT_INDEX)
 #define G_L2C_MGMT_INDEX(x)         _SB_GETVALUE(x,S_L2C_MGMT_INDEX,M_L2C_MGMT_INDEX)
 
+#define S_L2C_MGMT_QUADRANT         15
+#define M_L2C_MGMT_QUADRANT         _SB_MAKEMASK(2,S_L2C_MGMT_QUADRANT)
+#define V_L2C_MGMT_QUADRANT(x)      _SB_MAKEVALUE(x,S_L2C_MGMT_QUADRANT)
+#define G_L2C_MGMT_QUADRANT(x)      _SB_GETVALUE(x,S_L2C_MGMT_QUADRANT,M_L2C_MGMT_QUADRANT)
+
+#define S_L2C_MGMT_HALF		    16
+#define M_L2C_MGMT_HALF	            _SB_MAKEMASK(1,S_L2C_MGMT_HALF)
+
 #define S_L2C_MGMT_WAY              17
 #define M_L2C_MGMT_WAY              _SB_MAKEMASK(2,S_L2C_MGMT_WAY)
 #define V_L2C_MGMT_WAY(x)           _SB_MAKEVALUE(x,S_L2C_MGMT_WAY)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250_ldt.h linux-2.4.20/include/asm-mips64/sibyte/sb1250_ldt.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250_ldt.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250_ldt.h	2002-10-29 11:18:37.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  LDT constants				File: sb1250_ldt.h
-    *  
-    *  This module contains constants and macros to describe 
-    *  the LDT interface on the SB1250.  
-    *  
-    *  SB1250 specification level:  0.2 plus errata
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  This module contains constants and macros to describe
+    *  the LDT interface on the SB1250.
+    *
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -70,6 +70,7 @@
 #define R_LDT_TYPE1_SRIRXNUM	0x0058
 #define R_LDT_TYPE1_ERRSTATUS   0x0068
 #define R_LDT_TYPE1_SRICTRL	0x006C
+#define R_LDT_TYPE1_ADDSTATUS	0x0070		/* PASS2 */
 #define R_LDT_TYPE1_TXBUFCNT	0x00C8
 #define R_LDT_TYPE1_EXPCRC	0x00DC
 #define R_LDT_TYPE1_RXCRC	0x00F0
@@ -152,13 +153,14 @@
 
 /*
  * LDT Status Register (Table 8-14).  Note that these constants
- * assume you've read the command and status register 
+ * assume you've read the command and status register
  * together (32-bit read at offset 0x04)
  *
  * These bits also apply to the secondary status
  * register (Table 8-15), offset 0x1C
  */
 
+#define M_LDT_STATUS_VGAEN		_SB_MAKEMASK1_32(3)	/* PASS2 */
 #define M_LDT_STATUS_CAPLIST		_SB_MAKEMASK1_32(20)
 #define M_LDT_STATUS_66MHZCAP		_SB_MAKEMASK1_32(21)
 #define M_LDT_STATUS_RESERVED2		_SB_MAKEMASK1_32(22)
@@ -177,8 +179,8 @@
 #define M_LDT_STATUS_DETPARERR		_SB_MAKEMASK1_32(31)
 
 /*
- * Bridge Control Register (Table 8-16).  Note that these 
- * constants assume you've read the register as a 32-bit 
+ * Bridge Control Register (Table 8-16).  Note that these
+ * constants assume you've read the register as a 32-bit
  * read (offset 0x3C)
  */
 
@@ -279,7 +281,10 @@
 #define M_LDT_SRICMD_SIPREADY		_SB_MAKEMASK1_32(16)
 #define M_LDT_SRICMD_SYNCPTRCTL		_SB_MAKEMASK1_32(17)
 #define M_LDT_SRICMD_REDUCESYNCZERO	_SB_MAKEMASK1_32(18)
-#define M_LDT_SRICMD_DISSTARVATIONCNT	_SB_MAKEMASK1_32(19)
+/*#define M_LDT_SRICMD_DISSTARVATIONCNT	_SB_MAKEMASK1_32(19) */ /* PASS1 */
+#define M_LDT_SRICMD_DISMULTTXVLD	_SB_MAKEMASK1_32(19)	/* PASS2 */
+#define M_LDT_SRICMD_EXPENDIAN		_SB_MAKEMASK1_32(26)	/* PASS2 */
+
 
 #define S_LDT_SRICMD_RXMARGIN		20
 #define M_LDT_SRICMD_RXMARGIN		_SB_MAKEMASK_32(5,S_LDT_SRICMD_RXMARGIN)
@@ -397,6 +402,14 @@
 #define V_LDT_TXBUFCNT_RDATA(x)		_SB_MAKEVALUE_32(x,S_LDT_TXBUFCNT_RDATA)
 #define G_LDT_TXBUFCNT_RDATA(x)		_SB_GETVALUE_32(x,S_LDT_TXBUFCNT_RDATA,M_LDT_TXBUFCNT_RDATA)
 
+/*
+ * Additional Status Register (PASS2)
+ */
+
+#define S_LDT_ADDSTATUS_TGTDONE		0
+#define M_LDT_ADDSTATUS_TGTDONE		_SB_MAKEMASK_32(8,S_LDT_ADDSTATUS_TGTDONE)
+#define V_LDT_ADDSTATUS_TGTDONE(x)	_SB_MAKEVALUE_32(x,S_LDT_ADDSTATUS_TGTDONE)
+#define G_LDT_ADDSTATUS_TGTDONE(x)	_SB_GETVALUE_32(x,S_LDT_ADDSTATUS_TGTDONE,M_LDT_ADDSTATUS_TGTDONE)
 
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250_mac.h linux-2.4.20/include/asm-mips64/sibyte/sb1250_mac.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250_mac.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250_mac.h	2002-10-29 11:18:35.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  MAC constants and macros			File: sb1250_mac.h
-    *  
+    *
     *  This module contains constants and macros for the SB1250's
     *  ethernet controllers.
-    *  
-    *  SB1250 specification level:  0.2 plus errata as of 4/10/2001
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -49,8 +49,6 @@
  */
 
 
-/* Updated to spec 0.2 */
-
 #define M_MAC_RESERVED0             _SB_MAKEMASK1(0)
 #define M_MAC_TX_HOLD_SOP_EN        _SB_MAKEMASK1(1)
 #define M_MAC_RETRY_EN              _SB_MAKEMASK1(2)
@@ -130,7 +128,7 @@
 #define M_MAC_BYPASS_16             _SB_MAKEMASK1(42)
 #define M_MAC_BYPASS_FCS_CHK	    _SB_MAKEMASK1(43)
 
-#define M_MAC_RESERVED4	    	    _SB_MAKEMASK(2,44)
+#define M_MAC_RX_CH_SEL_MSB	    _SB_MAKEMASK1(44)		/* PASS2 */
 
 #define S_MAC_BYPASS_IFG            _SB_MAKE64(46)
 #define M_MAC_BYPASS_IFG            _SB_MAKEMASK(8,S_MAC_BYPASS_IFG)
@@ -202,12 +200,14 @@
  */
 
 #define S_MAC_TX_WR_THRSH           _SB_MAKE64(0)
-#define M_MAC_TX_WR_THRSH           _SB_MAKEMASK(6,S_MAC_TX_WR_THRSH)
+/* #define M_MAC_TX_WR_THRSH           _SB_MAKEMASK(6,S_MAC_TX_WR_THRSH) */ /* PASS1 */
+#define M_MAC_TX_WR_THRSH           _SB_MAKEMASK(7,S_MAC_TX_WR_THRSH)	    /* PASS2 */
 #define V_MAC_TX_WR_THRSH(x)        _SB_MAKEVALUE(x,S_MAC_TX_WR_THRSH)
 #define G_MAC_TX_WR_THRSH(x)        _SB_GETVALUE(x,S_MAC_TX_WR_THRSH,M_MAC_TX_WR_THRSH)
 
 #define S_MAC_TX_RD_THRSH           _SB_MAKE64(8)
-#define M_MAC_TX_RD_THRSH           _SB_MAKEMASK(6,S_MAC_TX_RD_THRSH)
+/* #define M_MAC_TX_RD_THRSH           _SB_MAKEMASK(6,S_MAC_TX_RD_THRSH) */ /* PASS1 */
+#define M_MAC_TX_RD_THRSH           _SB_MAKEMASK(7,S_MAC_TX_RD_THRSH)	    /* PASS2 */
 #define V_MAC_TX_RD_THRSH(x)        _SB_MAKEVALUE(x,S_MAC_TX_RD_THRSH)
 #define G_MAC_TX_RD_THRSH(x)        _SB_GETVALUE(x,S_MAC_TX_RD_THRSH,M_MAC_TX_RD_THRSH)
 
@@ -231,6 +231,11 @@
 #define V_MAC_RX_RL_THRSH(x)        _SB_MAKEVALUE(x,S_MAC_RX_RL_THRSH)
 #define G_MAC_RX_RL_THRSH(x)        _SB_GETVALUE(x,S_MAC_RX_RL_THRSH,M_MAC_RX_RL_THRSH)
 
+#define S_MAC_ENC_FC_THRSH           _SB_MAKE64(56)			/* PASS2 */
+#define M_MAC_ENC_FC_THRSH           _SB_MAKEMASK(6,S_MAC_ENC_FC_THRSH)	/* PASS2 */
+#define V_MAC_ENC_FC_THRSH(x)        _SB_MAKEVALUE(x,S_MAC_ENC_FC_THRSH) /* PASS2 */
+#define G_MAC_ENC_FC_THRSH(x)        _SB_GETVALUE(x,S_MAC_ENC_FC_THRSH,M_MAC_ENC_FC_THRSH) /* PASS2 */
+
 /*
  * MAC Frame Configuration Registers (Table 9-15)
  * Register: MAC_FRAME_CFG_0
@@ -280,20 +285,20 @@
 
 /*
  * These constants are used to configure the fields within the Frame
- * Configuration Register.  
+ * Configuration Register.
  */
 
-#define K_MAC_IFG_RX_10             _SB_MAKE64(18)
-#define K_MAC_IFG_RX_100            _SB_MAKE64(18)
-#define K_MAC_IFG_RX_1000           _SB_MAKE64(6)
+#define K_MAC_IFG_RX_10             _SB_MAKE64(0)	/* See table 176, not used */
+#define K_MAC_IFG_RX_100            _SB_MAKE64(0)
+#define K_MAC_IFG_RX_1000           _SB_MAKE64(0)
 
 #define K_MAC_IFG_TX_10             _SB_MAKE64(20)
 #define K_MAC_IFG_TX_100            _SB_MAKE64(20)
 #define K_MAC_IFG_TX_1000           _SB_MAKE64(8)
 
-#define K_MAC_IFG_THRSH_10          _SB_MAKE64(12)
-#define K_MAC_IFG_THRSH_100         _SB_MAKE64(12)
-#define K_MAC_IFG_THRSH_1000        _SB_MAKE64(4)
+#define K_MAC_IFG_THRSH_10          _SB_MAKE64(4)
+#define K_MAC_IFG_THRSH_100         _SB_MAKE64(4)
+#define K_MAC_IFG_THRSH_1000        _SB_MAKE64(0)
 
 #define K_MAC_SLOT_SIZE_10          _SB_MAKE64(0)
 #define K_MAC_SLOT_SIZE_100         _SB_MAKE64(0)
@@ -317,9 +322,11 @@
 
 #define K_MAC_MIN_FRAMESZ_DEFAULT   _SB_MAKE64(64)
 #define K_MAC_MAX_FRAMESZ_DEFAULT   _SB_MAKE64(1518)
+#define K_MAC_MAX_FRAMESZ_JUMBO     _SB_MAKE64(9216)
 
 #define V_MAC_MIN_FRAMESZ_DEFAULT   V_MAC_MIN_FRAMESZ(K_MAC_MIN_FRAMESZ_DEFAULT)
 #define V_MAC_MAX_FRAMESZ_DEFAULT   V_MAC_MAX_FRAMESZ(K_MAC_MAX_FRAMESZ_DEFAULT)
+#define V_MAC_MAX_FRAMESZ_JUMBO     V_MAC_MAX_FRAMESZ(K_MAC_MAX_FRAMESZ_JUMBO)
 
 /*
  * MAC VLAN Tag Registers (Table 9-16)
@@ -341,7 +348,7 @@
  * Register: MAC_INT_MASK_2
  */
 
-/* 
+/*
  * Use these constants to shift the appropriate channel
  * into the CH0 position so the same tests can be used
  * on each channel.
@@ -378,6 +385,7 @@
 #define M_MAC_LTCOL_ERR             _SB_MAKEMASK1(44)
 #define M_MAC_EXCOL_ERR             _SB_MAKEMASK1(45)
 #define M_MAC_CNTR_OVRFL_ERR        _SB_MAKEMASK1(46)
+#define M_MAC_SPLIT_EN		    _SB_MAKEMASK1(47) 	/* interrupt mask only */ /* PASS2 */
 
 #define S_MAC_COUNTER_ADDR          _SB_MAKE64(47)
 #define M_MAC_COUNTER_ADDR          _SB_MAKEMASK(5,S_MAC_COUNTER_ADDR)
@@ -498,6 +506,7 @@
 #define M_MAC_MCAST_INV         _SB_MAKEMASK1(4)
 #define M_MAC_BCAST_EN          _SB_MAKEMASK1(5)
 #define M_MAC_DIRECT_INV        _SB_MAKEMASK1(6)
+#define M_MAC_ALLMCAST_EN	_SB_MAKEMASK1(7)	/* PASS2 */
 
 #define S_MAC_IPHDR_OFFSET      _SB_MAKE64(8)
 #define M_MAC_IPHDR_OFFSET      _SB_MAKEMASK(8,S_MAC_IPHDR_OFFSET)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250_mc.h linux-2.4.20/include/asm-mips64/sibyte/sb1250_mc.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250_mc.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250_mc.h	2002-10-29 11:18:31.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
-    *  Memory Controller constants              File: sb1250_mc.h       
-    *  
+    *
+    *  Memory Controller constants              File: sb1250_mc.h
+    *
     *  This module contains constants and macros useful for
     *  programming the memory controller.
-    *  
-    *  SB1250 specification level:  0.2
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -166,7 +166,7 @@
 
 #define K_MC_REF_RATE_100MHz         0x62
 #define K_MC_REF_RATE_133MHz         0x81
-#define K_MC_REF_RATE_200MHz         0xC4 
+#define K_MC_REF_RATE_200MHz         0xC4
 
 #define V_MC_REF_RATE_100MHz         V_MC_REF_RATE(K_MC_REF_RATE_100MHz)
 #define V_MC_REF_RATE_133MHz         V_MC_REF_RATE(K_MC_REF_RATE_133MHz)
@@ -224,7 +224,7 @@
                                      V_MC_ADDR_DRIVE_DEFAULT | \
                                      V_MC_DATA_DRIVE_DEFAULT | \
                                      V_MC_CLOCK_DRIVE_DEFAULT | \
-                                     V_MC_REF_RATE_DEFAULT 
+                                     V_MC_REF_RATE_DEFAULT
 
 
 
@@ -298,69 +298,80 @@
  * SDRAM Timing Register  (Table 6-15)
  */
 
-#define M_MC_w2rIDLE_TWOCYCLES	  _SB_MAKEMASK1(62)
+#define M_MC_w2rIDLE_TWOCYCLES	  _SB_MAKEMASK1(60)
 #define M_MC_r2wIDLE_TWOCYCLES	  _SB_MAKEMASK1(61)
-#define M_MC_r2rIDLE_TWOCYCLES	  _SB_MAKEMASK1(60)
+#define M_MC_r2rIDLE_TWOCYCLES	  _SB_MAKEMASK1(62)
 
 #define S_MC_tFIFO                56
 #define M_MC_tFIFO                _SB_MAKEMASK(4,S_MC_tFIFO)
 #define V_MC_tFIFO(x)             _SB_MAKEVALUE(x,S_MC_tFIFO)
+#define G_MC_tFIFO(x)             _SB_GETVALUE(x,S_MC_tFIFO,M_MC_tFIFO)
 #define K_MC_tFIFO_DEFAULT        1
 #define V_MC_tFIFO_DEFAULT        V_MC_tFIFO(K_MC_tFIFO_DEFAULT)
 
 #define S_MC_tRFC                 52
 #define M_MC_tRFC                 _SB_MAKEMASK(4,S_MC_tRFC)
 #define V_MC_tRFC(x)              _SB_MAKEVALUE(x,S_MC_tRFC)
+#define G_MC_tRFC(x)              _SB_GETVALUE(x,S_MC_tRFC,M_MC_tRFC)
 #define K_MC_tRFC_DEFAULT         12
 #define V_MC_tRFC_DEFAULT         V_MC_tRFC(K_MC_tRFC_DEFAULT)
 
 #define S_MC_tCwCr                40
 #define M_MC_tCwCr                _SB_MAKEMASK(4,S_MC_tCwCr)
 #define V_MC_tCwCr(x)             _SB_MAKEVALUE(x,S_MC_tCwCr)
+#define G_MC_tCwCr(x)             _SB_GETVALUE(x,S_MC_tCwCr,M_MC_tCwCr)
 #define K_MC_tCwCr_DEFAULT        4
 #define V_MC_tCwCr_DEFAULT        V_MC_tCwCr(K_MC_tCwCr_DEFAULT)
 
 #define S_MC_tRCr                 28
 #define M_MC_tRCr                 _SB_MAKEMASK(4,S_MC_tRCr)
 #define V_MC_tRCr(x)              _SB_MAKEVALUE(x,S_MC_tRCr)
+#define G_MC_tRCr(x)              _SB_GETVALUE(x,S_MC_tRCr,M_MC_tRCr)
 #define K_MC_tRCr_DEFAULT         9
 #define V_MC_tRCr_DEFAULT         V_MC_tRCr(K_MC_tRCr_DEFAULT)
 
 #define S_MC_tRCw                 24
 #define M_MC_tRCw                 _SB_MAKEMASK(4,S_MC_tRCw)
 #define V_MC_tRCw(x)              _SB_MAKEVALUE(x,S_MC_tRCw)
+#define G_MC_tRCw(x)              _SB_GETVALUE(x,S_MC_tRCw,M_MC_tRCw)
 #define K_MC_tRCw_DEFAULT         10
 #define V_MC_tRCw_DEFAULT         V_MC_tRCw(K_MC_tRCw_DEFAULT)
 
 #define S_MC_tRRD                 20
 #define M_MC_tRRD                 _SB_MAKEMASK(4,S_MC_tRRD)
 #define V_MC_tRRD(x)              _SB_MAKEVALUE(x,S_MC_tRRD)
+#define G_MC_tRRD(x)              _SB_GETVALUE(x,S_MC_tRRD,M_MC_tRRD)
 #define K_MC_tRRD_DEFAULT         2
 #define V_MC_tRRD_DEFAULT         V_MC_tRRD(K_MC_tRRD_DEFAULT)
 
 #define S_MC_tRP                  16
 #define M_MC_tRP                  _SB_MAKEMASK(4,S_MC_tRP)
 #define V_MC_tRP(x)               _SB_MAKEVALUE(x,S_MC_tRP)
+#define G_MC_tRP(x)               _SB_GETVALUE(x,S_MC_tRP,M_MC_tRP)
 #define K_MC_tRP_DEFAULT          4
 #define V_MC_tRP_DEFAULT          V_MC_tRP(K_MC_tRP_DEFAULT)
 
 #define S_MC_tCwD                 8
 #define M_MC_tCwD                 _SB_MAKEMASK(4,S_MC_tCwD)
 #define V_MC_tCwD(x)              _SB_MAKEVALUE(x,S_MC_tCwD)
+#define G_MC_tCwD(x)              _SB_GETVALUE(x,S_MC_tCwD,M_MC_tCwD)
 #define K_MC_tCwD_DEFAULT         1
 #define V_MC_tCwD_DEFAULT         V_MC_tCwD(K_MC_tCwD_DEFAULT)
 
 #define M_tCrDh                   _SB_MAKEMASK1(7)
+#define M_MC_tCrDh		  M_tCrDh
 
 #define S_MC_tCrD                 4
 #define M_MC_tCrD                 _SB_MAKEMASK(3,S_MC_tCrD)
 #define V_MC_tCrD(x)              _SB_MAKEVALUE(x,S_MC_tCrD)
+#define G_MC_tCrD(x)              _SB_GETVALUE(x,S_MC_tCrD,M_MC_tCrD)
 #define K_MC_tCrD_DEFAULT         2
 #define V_MC_tCrD_DEFAULT         V_MC_tCrD(K_MC_tCrD_DEFAULT)
 
 #define S_MC_tRCD                 0
 #define M_MC_tRCD                 _SB_MAKEMASK(4,S_MC_tRCD)
 #define V_MC_tRCD(x)              _SB_MAKEVALUE(x,S_MC_tRCD)
+#define G_MC_tRCD(x)              _SB_GETVALUE(x,S_MC_tRCD,M_MC_tRCD)
 #define K_MC_tRCD_DEFAULT         3
 #define V_MC_tRCD_DEFAULT         V_MC_tRCD(K_MC_tRCD_DEFAULT)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250_pci.h linux-2.4.20/include/asm-mips64/sibyte/sb1250_pci.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250_pci.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250_pci.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,250 +0,0 @@
-/*  *********************************************************************
-    *  SB1250 Board Support Package
-    *  
-    *  PCI constants				File: sb1250_pci.h
-    *  
-    *  This module contains constants and macros to describe 
-    *  the PCI interface on the SB1250.  
-    *  
-    *  SB1250 specification level:  0.2
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
-    *
-    *  Copyright 2000,2001
-    *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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
-    ********************************************************************* */
-
-
-#ifndef _SB1250_PCI_H
-#define _SB1250_PCI_H
-
-#include "sb1250_defs.h"
-
-#define K_PCI_VENDOR_SIBYTE	0x166D
-#define K_PCI_DEVICE_SB1250	0x0001
-
-/*
- * PCI Interface Type 0 configuration header
- */
-
-#define R_PCI_TYPE0_DEVICEID	0x0000
-#define R_PCI_TYPE0_CMDSTATUS	0x0004
-#define R_PCI_TYPE0_CLASSREV	0x0008
-#define R_PCI_TYPE0_DEVHDR	0x000C
-#define R_PCI_TYPE0_BAR0	0x0010	/* translated via mapping table */
-#define R_PCI_TYPE0_BAR1	0x0014	/* reserved */
-#define R_PCI_TYPE0_BAR2	0x0018	/* mbox 0 */
-#define R_PCI_TYPE0_BAR3	0x001C	/* mbox 1 */
-#define R_PCI_TYPE0_BAR4	0x0020	/* low memory */
-#define R_PCI_TYPE0_BAR5	0x0024	/* high memory */
-#define R_PCI_TYPE0_CARDBUSCIS	0x0028
-#define R_PCI_TYPE0_SUBSYSID	0x002C
-#define R_PCI_TYPE0_ROMBASE	0x0030
-#define R_PCI_TYPE0_CAPPTR	0x0034	/* not used */
-#define R_PCI_TYPE0_RESERVED1	0x0038
-#define R_PCI_TYPE0_INTGRANT	0x003C	/* interrupt pin and grant latency */
-#define R_PCI_TYPE0_TIMEOUT	0x0040	/* FControl, Timeout */
-#define R_PCI_TYPE0_FCONTROL	0x0040	/* FControl, Timeout */
-#define R_PCI_TYPE0_MAPBASE	0x0044	/* 0x44 through 0x80 - map table */
-#define PCI_TYPE0_MAPENTRIES	32	/* 64 bytes, 32 entries */
-#define R_PCI_TYPE0_ERRORADDR	0x0084
-#define R_PCI_TYPE0_ADDSTATUS	0x0088
-#define R_PCI_TYPE0_SUBSYSSET	0x008C	/* only accessible from ZBBus */
-
-/*
- * PCI Device ID register
- */
-
-#define S_PCI_DEVICEID_VENDOR		0
-#define M_PCI_DEVICEID_VENDOR		_SB_MAKEMASK_32(16,S_PCI_DEVICEID_VENDOR)
-#define V_PCI_DEVICEID_VENDOR(x)	_SB_MAKEVALUE_32(x,S_PCI_DEVICEID_VENDOR)
-#define G_PCI_DEVICEID_VENDOR(x)	_SB_GETVALUE_32(x,S_PCI_DEVICEID_VENDOR,M_PCI_DEVICEID_VENDOR)
-
-#define S_PCI_DEVICEID_DEVICEID		16
-#define M_PCI_DEVICEID_DEVICEID		_SB_MAKEMASK_32(16,S_PCI_DEVICEID_DEVICEID)
-#define V_PCI_DEVICEID_DEVICEID(x)	_SB_MAKEVALUE_32(x,S_PCI_DEVICEID_DEVICEID)
-#define G_PCI_DEVICEID_DEVICEID(x)	_SB_GETVALUE_32(x,S_PCI_DEVICEID_DEVICEID,M_PCI_DEVICEID_DEVICEID)
-
-
-/*
- * PCI Command Register (Table 8-4)
- */
-
-#define M_PCI_CMD_IOSPACE_EN		_SB_MAKEMASK1_32(0)
-#define M_PCI_CMD_MEMSPACE_EN		_SB_MAKEMASK1_32(1)
-#define M_PCI_CMD_MASTER_EN		_SB_MAKEMASK1_32(2)
-#define M_PCI_CMD_SPECCYC_EN		_SB_MAKEMASK1_32(3)
-#define M_PCI_CMD_MEMWRINV_EN		_SB_MAKEMASK1_32(4)
-#define M_PCI_CMD_VGAPALSNP_EN		_SB_MAKEMASK1_32(5)
-#define M_PCI_CMD_PARERRRESP		_SB_MAKEMASK1_32(6)
-#define M_PCI_CMD_STEPCTRL		_SB_MAKEMASK1_32(7)
-#define M_PCI_CMD_SERR_EN		_SB_MAKEMASK1_32(8)
-#define M_PCI_CMD_FASTB2B_EN		_SB_MAKEMASK1_32(9)
-
-/*
- * PCI class and revision registers
- */
-
-#define S_PCI_CLASSREV_REV		0
-#define M_PCI_CLASSREV_REV		_SB_MAKEMASK_32(8,S_PCI_CLASSREV_REV)
-#define V_PCI_CLASSREV_REV(x)		_SB_MAKEVALUE_32(x,S_PCI_CLASSREV_REV)
-#define G_PCI_CLASSREV_REV(x)		_SB_GETVALUE_32(x,S_PCI_CLASSREV_REV,M_PCI_CLASSREV_REV)
-
-#define S_PCI_CLASSREV_CLASS		8
-#define M_PCI_CLASSREV_CLASS		_SB_MAKEMASK_32(24,S_PCI_CLASSREV_CLASS)
-#define V_PCI_CLASSREV_CLASS(x)		_SB_MAKEVALUE_32(x,S_PCI_CLASSREV_CLASS)
-#define G_PCI_CLASSREV_CLASS(x)		_SB_GETVALUE_32(x,S_PCI_CLASSREV_CLASS,M_PCI_CLASSREV_CLASS)
-
-#define K_PCI_REV			0x01
-#define K_PCI_CLASS			0x060000
-
-/*
- * Device Header (offset 0x0C)
- */
-
-#define S_PCI_DEVHDR_CLINESZ		0
-#define M_PCI_DEVHDR_CLINESZ		_SB_MAKEMASK_32(8,S_PCI_DEVHDR_CLINESZ)
-#define V_PCI_DEVHDR_CLINESZ(x)		_SB_MAKEVALUE_32(x,S_PCI_DEVHDR_CLINESZ)
-#define G_PCI_DEVHDR_CLINESZ(x)		_SB_GETVALUE_32(x,S_PCI_DEVHDR_CLINESZ,M_PCI_DEVHDR_CLINESZ)
-
-#define S_PCI_DEVHDR_LATTMR		8
-#define M_PCI_DEVHDR_LATTMR		_SB_MAKEMASK_32(8,S_PCI_DEVHDR_LATTMR)
-#define V_PCI_DEVHDR_LATTMR(x)		_SB_MAKEVALUE_32(x,S_PCI_DEVHDR_LATTMR)
-#define G_PCI_DEVHDR_LATTMR(x)		_SB_GETVALUE_32(x,S_PCI_DEVHDR_LATTMR,M_PCI_DEVHDR_LATTMR)
-
-#define S_PCI_DEVHDR_HDRTYPE		16
-#define M_PCI_DEVHDR_HDRTYPE		_SB_MAKEMASK_32(8,S_PCI_DEVHDR_HDRTYPE)
-#define V_PCI_DEVHDR_HDRTYPE(x)		_SB_MAKEVALUE_32(x,S_PCI_DEVHDR_HDRTYPE)
-#define G_PCI_DEVHDR_HDRTYPE(x)		_SB_GETVALUE_32(x,S_PCI_DEVHDR_HDRTYPE,M_PCI_DEVHDR_HDRTYPE)
-
-#define K_PCI_DEVHDR_HDRTYPE_TYPE0	0
-
-#define S_PCI_DEVHDR_BIST		24
-#define M_PCI_DEVHDR_BIST		_SB_MAKEMASK_32(8,S_PCI_DEVHDR_BIST)
-#define V_PCI_DEVHDR_BIST(x)		_SB_MAKEVALUE_32(x,S_PCI_DEVHDR_BIST)
-#define G_PCI_DEVHDR_BIST(x)		_SB_GETVALUE_32(x,S_PCI_DEVHDR_BIST,M_PCI_DEVHDR_BIST)
-
-/*
- * PCI Status Register (Table 8-5).  Note that these constants
- * assume you've read the command and status register 
- * together (32-bit read at offset 0x04)
- */
-
-#define M_PCI_STATUS_CAPLIST		_SB_MAKEMASK1_32(20)
-#define M_PCI_STATUS_66MHZCAP		_SB_MAKEMASK1_32(21)
-#define M_PCI_STATUS_RESERVED2		_SB_MAKEMASK1_32(22)
-#define M_PCI_STATUS_FASTB2BCAP		_SB_MAKEMASK1_32(23)
-#define M_PCI_STATUS_MSTRDPARERR	_SB_MAKEMASK1_32(24)
-
-#define S_PCI_STATUS_DEVSELTIMING	25
-#define M_PCI_STATUS_DEVSELTIMING	_SB_MAKEMASK_32(2,S_PCI_STATUS_DEVSELTIMING)
-#define V_PCI_STATUS_DEVSELTIMING(x)	_SB_MAKEVALUE_32(x,S_PCI_STATUS_DEVSELTIMING)
-#define G_PCI_STATUS_DEVSELTIMING(x)	_SB_GETVALUE_32(x,S_PCI_STATUS_DEVSELTIMING,M_PCI_STATUS_DEVSELTIMING)
-
-#define M_PCI_STATUS_SIGDTGTABORT	_SB_MAKEMASK1_32(27)
-#define M_PCI_STATUS_RCVDTGTABORT	_SB_MAKEMASK1_32(28)
-#define M_PCI_STATUS_RCVDMSTRABORT	_SB_MAKEMASK1_32(29)
-#define M_PCI_STATUS_SIGDSERR		_SB_MAKEMASK1_32(30)
-#define M_PCI_STATUS_DETPARERR		_SB_MAKEMASK1_32(31)
-
-/*
- * Device Header Register (Table 8-6, Table 8-7)
- */
-
-#define S_PCI_DEVHDR_CLINESZ		0
-#define M_PCI_DEVHDR_CLINESZ		_SB_MAKEMASK_32(8,S_PCI_DEVHDR_CLINESZ)
-#define V_PCI_DEVHDR_CLINESZ(x)		_SB_MAKEVALUE_32(x,S_PCI_DEVHDR_CLINESZ)
-#define G_PCI_DEVHDR_CLINESZ(x)		_SB_GETVALUE_32(x,S_PCI_DEVHDR_CLINESZ,M_PCI_DEVHDR_CLINESZ)
-
-#define S_PCI_DEVHDR_LATTIME		8
-#define M_PCI_DEVHDR_LATTIME		_SB_MAKEMASK_32(8,S_PCI_DEVHDR_LATTIME)
-#define V_PCI_DEVHDR_LATTIME(x)		_SB_MAKEVALUE_32(x,S_PCI_DEVHDR_LATTIME)
-#define G_PCI_DEVHDR_LATTIME(x)		_SB_GETVALUE_32(x,S_PCI_DEVHDR_LATTIME,M_PCI_DEVHDR_LATTIME)
-
-#define S_PCI_DEVHDR_HDRTYPE		16
-#define M_PCI_DEVHDR_HDRTYPE		_SB_MAKEMASK_32(8,S_PCI_DEVHDR_HDRTYPE)
-#define V_PCI_DEVHDR_HDRTYPE(x)		_SB_MAKEVALUE_32(x,S_PCI_DEVHDR_HDRTYPE)
-#define G_PCI_DEVHDR_HDRTYPE(x)		_SB_GETVALUE_32(x,S_PCI_DEVHDR_HDRTYPE,M_PCI_DEVHDR_HDRTYPE)
-
-#define S_PCI_DEVHDR_BIST		24
-#define M_PCI_DEVHDR_BIST		_SB_MAKEMASK_32(8,S_PCI_DEVHDR_BIST)
-#define V_PCI_DEVHDR_BIST(x)		_SB_MAKEVALUE_32(x,S_PCI_DEVHDR_BIST)
-#define G_PCI_DEVHDR_BIST(x)		_SB_GETVALUE_32(x,S_PCI_DEVHDR_BIST,M_PCI_DEVHDR_BIST)
-
-/*
- * Timeout and feature control Register (Table 8-8) (Table 8-9)
- * Note that these constants assume you've read the timeout/fcontrol register
- * together (32-bit read at offset 0x40)
- */
-
-#define S_PCI_TIMEOUT_TRDY		0
-#define M_PCI_TIMEOUT_TRDY		_SB_MAKEMASK_32(8,S_PCI_TIMEOUT_TRDY)
-#define V_PCI_TIMEOUT_TRDY(x)		_SB_MAKEVALUE_32(x,S_PCI_TIMEOUT_TRDY)
-#define G_PCI_TIMEOUT_TRDY(x)		_SB_GETVALUE_32(x,S_PCI_TIMEOUT_TRDY,M_PCI_TIMEOUT_TRDY)
-
-#define S_PCI_TIMEOUT_RETRY		8
-#define M_PCI_TIMEOUT_RETRY		_SB_MAKEMASK_32(8,S_PCI_TIMEOUT_RETRY)
-#define V_PCI_TIMEOUT_RETRY(x)		_SB_MAKEVALUE_32(x,S_PCI_TIMEOUT_RETRY)
-#define G_PCI_TIMEOUT_RETRY(x)		_SB_GETVALUE_32(x,S_PCI_TIMEOUT_RETRY,M_PCI_TIMEOUT_RETRY)
-
-#define M_PCI_FCONTROL_BAR4_EN		_SB_MAKEMASK1_32(16)
-#define M_PCI_FCONTROL_BAR5_EN		_SB_MAKEMASK1_32(17)
-#define M_PCI_FCONTROL_PTP_EN		_SB_MAKEMASK1_32(18)
-#define M_PCI_FCONTROL_ADAPT_RETRY_EN	_SB_MAKEMASK1_32(19)
-
-#define S_PCI_FCONTROL_MIN_TAR_RETRY	20
-#define M_PCI_FCONTROL_MIN_TAR_RETRY	_SB_MAKEMASK_32(3,S_PCI_FCONTROL_MIN_TAR_RETRY)
-#define V_PCI_FCONTROL_MIN_TAR_RETRY(x)	_SB_MAKEVALUE_32(x,S_PCI_FCONTROL_MIN_TAR_RETRY)
-#define G_PCI_FCONTROL_MIN_TAR_RETRY(x)	_SB_GETVALUE_32(x,S_PCI_FCONTROL_MIN_TAR_RETRY,M_PCI_FCONTROL_MIN_TAR_RETRY)
-
-#define S_PCI_FCONTROL_NOM_TAR_RETRY	23
-#define M_PCI_FCONTROL_NOM_TAR_RETRY	_SB_MAKEMASK_32(4,S_PCI_FCONTROL_NOM_TAR_RETRY)
-#define V_PCI_FCONTROL_NOM_TAR_RETRY(x)	_SB_MAKEVALUE_32(x,S_PCI_FCONTROL_NOM_TAR_RETRY)
-#define G_PCI_FCONTROL_NOM_TAR_RETRY(x)	_SB_GETVALUE_32(x,S_PCI_FCONTROL_NOM_TAR_RETRY,M_PCI_FCONTROL_NOM_TAR_RETRY)
-
-#define S_PCI_FCONTROL_MAX_TAR_RETRY	27
-#define M_PCI_FCONTROL_MAX_TAR_RETRY	_SB_MAKEMASK_32(5,S_PCI_FCONTROL_MAX_TAR_RETRY)
-#define V_PCI_FCONTROL_MAX_TAR_RETRY(x)	_SB_MAKEVALUE_32(x,S_PCI_FCONTROL_MAX_TAR_RETRY)
-#define G_PCI_FCONTROL_MAX_TAR_RETRY(x)	_SB_GETVALUE_32(x,S_PCI_FCONTROL_MAX_TAR_RETRY,M_PCI_FCONTROL_MAX_TAR_RETRY)
-
-/*
- * BAR0 Map Table Entry (Offsets 0x40-0x80) (Table 8-10)
- */
-
-#define M_PCI_BAR0MAP_ENABLE		_SB_MAKEMASK1_32(0)
-#define M_PCI_BAR0MAP_SENDLDT		_SB_MAKEMASK1_32(1)
-#define S_PCI_BAR0MAP_ADDR		12
-#define M_PCI_BAR0MAP_ADDR		_SB_MAKEMASK_32(20,S_PCI_BAR0MAP_ADDR)
-
-/*
- * Additional Status Register (Table 8-11)
- */
-
-#define M_PCI_ASTATUS_HOTPLUG_EN	_SB_MAKEMASK1_32(0)
-#define M_PCI_ASTATUS_SERR_DET		_SB_MAKEMASK1_32(1)
-#define M_PCI_ASTATUS_TRDYERR		_SB_MAKEMASK1_32(2)
-#define M_PCI_ASTATUS_RETRTYERR		_SB_MAKEMASK1_32(3)
-#define M_PCI_ASTATUS_TRDYINTMASK	_SB_MAKEMASK1_32(4)
-#define M_PCI_ASTATUS_RETRYINTMASK	_SB_MAKEMASK1_32(5)
-#define M_PCI_ASTATUS_SIGNALINTA	_SB_MAKEMASK1_32(6)
-
-#endif
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250_prof.h linux-2.4.20/include/asm-mips64/sibyte/sb1250_prof.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250_prof.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250_prof.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2001 Broadcom Corporation
+ *
+ * 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.
+ */
+
+/*
+ *
+ * Definitions for the sb1250_prof pseudo device.
+ *
+ */
+//#include <sys/param.h>
+//#include <sys/device.h>
+
+#ifndef SB1250_PROF_H
+#define SB1250_PROF_H 1
+
+#define MAXCPUS 1
+#define NEWPIDSIZE 160
+/* The two definitions below must match those in pgather.c */
+#define MAX_COUNTERS 4
+#define MAX_SLOTS 8
+
+#define STATS
+
+typedef struct {
+  u_int8_t  event;
+  u_int8_t  hwcode;     /* pcarch-specific bits identifying desired event */
+  u_int64_t period;     /* 40-bit sampling period during slot */
+} sbprof_mux_counter_t;
+
+typedef struct {
+  sbprof_mux_counter_t
+                counter[MAX_COUNTERS];	/* data for setting up counter */
+  u_int8_t	n;			/* number of counters to use in slot */
+} sbprof_mux_slot_t;
+
+typedef struct {
+  sbprof_mux_slot_t slots[MAX_SLOTS];
+} sbprof_mux_slots;
+
+typedef struct {
+  u_int64_t total;	/* total number of interrupts */
+  u_int64_t dropped;	/* total interrupts when buffers were full */
+  u_int64_t value;	/* initial counter value when slot next entered */
+  u_int32_t start_period_low;	/* counter val for starting a period */
+  u_int8_t  start_period_high;
+  u_int8_t  event;      /* pcarch-specific event_t */
+  u_int8_t  hwcode;	/* pcarch-specific code for event */
+  u_int8_t  inuse;	/* Is counter X slot actually used? */
+} event_counter_state_t;
+
+typedef struct {
+  u_int32_t total;	 /* total for current run of slot */
+  u_int32_t dropped;	 /* dropped for current run of slot */
+  u_int64_t start_period;/* counter value to start a full period */
+} active_counter_state_t;
+
+struct _cpudata1 {
+  /******* page-aligned boundary *********************************************/
+  u_int32_t last_pid;	/* Pid for last sample in buffer (-1 initially) */
+  u_int8_t  curbuf;	/* 2 -> both buffers full at end of last interrupt
+			   1 -> use buffer[1]
+			   0 -> use buffer[0] */
+  u_int8_t  nextbuf;	/* the index of the next buffer to be filled */
+  u_int8_t  nnewpid[2]; /* number of entries set in new_pid[i] */
+  u_int32_t next;       /* index of next free entry in curbuf */
+  int32_t   last_event; /* index of byte just past last event DP_D_EVENTS
+			   message in curbuf that needs the number of events
+			   filled in.  -1 means there is no such message and
+			   that such a message must be entered before
+			   adding event samples.
+			 */
+  /* 16-byte boundary */
+  volatile u_int32_t full[2];
+                        /* full[i] > 0 means buffer[i] needs emptying.
+			   0 to nonzero done by sbprofintr().
+			   nonzero to zero by sbprofioctl().
+			   When nonzero, full[i] is the number of bytes
+			   set in buffer[i].
+			*/
+  u_int32_t threshold;  /* when does the current multiplexing slot expire? */
+  u_int8_t slotid;      /* index into slots[] of current multiplexing slot */
+  u_int8_t nslots;	/* number of slots */
+  u_int8_t needs_scan;
+  u_int8_t pad[1];
+  /******* 32-byte boundary *********************************************/
+  active_counter_state_t cur_slot[MAX_COUNTERS];
+  /******* 32-byte boundary *********************************************/
+  event_counter_state_t event_counter_state[MAX_SLOTS][MAX_COUNTERS];
+  /******* 32-byte boundary *********************************************/
+  u_int32_t overshot[MAX_SLOTS];
+
+  u_int32_t newpid[2][NEWPIDSIZE];  /* new_pid[i][] contains indices of
+				       buffer[i][] where a new_pid message
+				       is encoded and needs to have the
+				       image_id, base addr, and num_inst
+				       fields set by the user-level daemon */
+#ifdef STATS
+  u_int64_t newpidlimit;
+  u_int64_t buflimit;
+#endif
+};
+
+#define SBPROF_BUFSIZE (32*1024 - (sizeof(struct _cpudata1)+1)/2)
+
+typedef struct _cpudata {
+  struct _cpudata1 x;
+  u_int8_t buffer[2][SBPROF_BUFSIZE];
+} cpudata_t;
+
+#define SBPROF_START    _IOW('S', 0x1, sbprof_mux_slots)
+#define SBPROF_STOP     _IO('S', 0x2)
+#define SBPROF_BUFFULL  _IOWR('S', 0x3, int)
+#define SBPROF_BUFEMPTY _IOW('S', 0x4, int)
+
+#if NEWPIDSIZE > 254
+#error "newpidsize too big"
+#endif
+
+#endif /* SB1250_PROF_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250_regs.h linux-2.4.20/include/asm-mips64/sibyte/sb1250_regs.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250_regs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250_regs.h	2002-10-29 11:18:32.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  Register Definitions                     File: sb1250_regs.h
-    *  
+    *
     *  This module contains the addresses of the on-chip peripherals
     *  on the SB1250.
-    *  
-    *  SB1250 specification level:  0.2
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  01/02/2002
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -40,20 +40,20 @@
 
 /*  *********************************************************************
     *  Some general notes:
-    *  
+    *
     *  For the most part, when there is more than one peripheral
     *  of the same type on the SOC, the constants below will be
     *  offsets from the base of each peripheral.  For example,
     *  the MAC registers are described as offsets from the first
     *  MAC register, and there will be a MAC_REGISTER() macro
-    *  to calculate the base address of a given MAC.  
-    *  
+    *  to calculate the base address of a given MAC.
+    *
     *  The information in this file is based on the SB1250 SOC
     *  manual version 0.2, July 2000.
     ********************************************************************* */
 
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * Memory Controller Registers
     ********************************************************************* */
 
@@ -97,7 +97,7 @@
 #define R_MC_TEST_ECC               0x0000000420
 #define R_MC_MCLK_CFG               0x0000000500
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * L2 Cache Control Registers
     ********************************************************************* */
 
@@ -107,7 +107,12 @@
 #define A_L2_MAKEDISABLE(x)         (A_L2_WAY_DISABLE | (((~(x))&0x0F) << 8))
 #define A_L2_MGMT_TAG_BASE          0x00D0000000
 
-/*  ********************************************************************* 
+#define A_L2_CACHE_DISABLE	   0x0010042000	/* PASS2 */
+#define A_L2_MAKECACHEDISABLE(x)   (A_L2_CACHE_DISABLE | (((x)&0x0F) << 8))	/* PASS2 */
+#define A_L2_MISC_CONFIG	   0x0010043000	/* PASS2 */
+
+
+/*  *********************************************************************
     * PCI Interface Registers
     ********************************************************************* */
 
@@ -115,7 +120,7 @@
 #define A_PCI_TYPE01_HEADER         0x00DE000800
 
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * Ethernet DMA and MACs
     ********************************************************************* */
 
@@ -162,7 +167,7 @@
             (R_MAC_DMA_CHANNEL_BASE(txrx,chan) +    \
             (reg))
 
-/* 
+/*
  * DMA channel registers, relative to A_MAC_DMA_CHANNEL_BASE
  */
 
@@ -220,6 +225,7 @@
 #define R_MAC_INT_MASK                  0x00000410
 #define R_MAC_TXD_CTL                   0x00000420
 #define R_MAC_MDIO                      0x00000428
+#define R_MAC_STATUS1		        0x00000430	/* PASS2 */
 #define R_MAC_DEBUG_STATUS              0x00000448
 
 #define MAC_HASH_COUNT			8
@@ -227,7 +233,7 @@
 #define MAC_CHMAP_COUNT			4
 
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * DUART Registers
     ********************************************************************* */
 
@@ -250,6 +256,11 @@
 #define R_DUART_RX_HOLD             0x160
 #define R_DUART_TX_HOLD             0x170
 
+#define R_DUART_FULL_CTL	    0x140	/* PASS2 */
+#define R_DUART_OPCR_X		    0x180	/* PASS2 */
+#define R_DUART_AUXCTL_X	    0x190	/* PASS2 */
+
+
 /*
  * The IMR and ISR can't be addressed with A_DUART_CHANREG,
  * so use this macro instead.
@@ -310,7 +321,16 @@
 #define A_DUART_INPORT_CHNG_A       0x00100603D0
 #define A_DUART_INPORT_CHNG_B       0x00100603E0
 
-/*  ********************************************************************* 
+#define A_DUART_FULL_CTL_A	    0x0010060140	/* PASS2 */
+#define A_DUART_FULL_CTL_B	    0x0010060240	/* PASS2 */
+
+#define A_DUART_OPCR_A	  	    0x0010060180	/* PASS2 */
+#define A_DUART_OPCR_B	  	    0x0010060280	/* PASS2 */
+
+#define A_DUART_INPORT_CHNG_DEBUG   0x00100603F0	/* PASS2 */
+
+
+/*  *********************************************************************
     * Synchronous Serial Registers
     ********************************************************************* */
 
@@ -344,7 +364,7 @@
             (reg))
 
 
-/* 
+/*
  * DMA channel registers, relative to A_SER_DMA_CHANNEL_BASE
  */
 
@@ -404,7 +424,7 @@
 #define R_SER_RMON_RX_ERRORS        0x000001F0
 #define R_SER_RMON_RX_BADADDR       0x000001F8
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * Generic Bus Registers
     ********************************************************************* */
 
@@ -456,7 +476,7 @@
 #define R_IO_PCMCIA_CFG             0x0A60
 #define R_IO_PCMCIA_STATUS          0x0A70
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * GPIO Registers
     ********************************************************************* */
 
@@ -480,7 +500,7 @@
 #define R_GPIO_PIN_CLR              0x30
 #define R_GPIO_PIN_SET              0x38
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * SMBus Registers
     ********************************************************************* */
 
@@ -516,7 +536,7 @@
 #define R_SMB_CONTROL               0x0000000060
 #define R_SMB_PEC                   0x0000000070
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * Timer Registers
     ********************************************************************* */
 
@@ -575,16 +595,21 @@
 #define A_SCD_TIMER_CNT_3           0x0010020188
 #define A_SCD_TIMER_CFG_3           0x0010020198
 
-/*  ********************************************************************* 
+#define A_SCD_SCRATCH		   0x0010020C10		/* PASS2 */
+
+#define A_SCD_ZBBUS_CYCLE_COUNT	   0x0010030000		/* PASS2 */
+#define A_SCD_ZBBUS_CYCLE_CP0	   0x0010020C00		/* PASS2 */
+#define A_SCD_ZBBUS_CYCLE_CP1	   0x0010020C08		/* PASS2 */
+
+
+/*  *********************************************************************
     * System Control Registers
     ********************************************************************* */
 
 #define A_SCD_SYSTEM_REVISION       0x0010020000
 #define A_SCD_SYSTEM_CFG            0x0010020008
 
-#define A_SCD_SCRATCH		    0x0010020C10	/* PASS2 */
-
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Address Trap Registers
     ********************************************************************* */
 
@@ -602,9 +627,10 @@
 #define A_ADDR_TRAP_CFG_1           0x0010020448
 #define A_ADDR_TRAP_CFG_2           0x0010020450
 #define A_ADDR_TRAP_CFG_3           0x0010020458
+#define A_ADDR_TRAP_REG_DEBUG	    0x0010020460	/* PASS2 */
 
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Interrupt Mapper Registers
     ********************************************************************* */
 
@@ -632,7 +658,7 @@
 #define R_IMR_INTERRUPT_MAP_BASE        0x0200
 #define R_IMR_INTERRUPT_MAP_COUNT       64
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Performance Counter Registers
     ********************************************************************* */
 
@@ -642,11 +668,12 @@
 #define A_SCD_PERF_CNT_2            0x00100204E0
 #define A_SCD_PERF_CNT_3            0x00100204E8
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Bus Watcher Registers
     ********************************************************************* */
 
 #define A_SCD_BUS_ERR_STATUS        0x0010020880
+#define A_SCD_BUS_ERR_STATUS_DEBUG  0x00100208D0	/* PASS2 */
 #define A_BUS_ERR_DATA_0            0x00100208A0
 #define A_BUS_ERR_DATA_1            0x00100208A8
 #define A_BUS_ERR_DATA_2            0x00100208B0
@@ -654,13 +681,13 @@
 #define A_BUS_L2_ERRORS             0x00100208C0
 #define A_BUS_MEM_IO_ERRORS         0x00100208C8
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Debug Controller Registers
     ********************************************************************* */
 
 #define A_SCD_JTAG_BASE             0x0010000000
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Trace Buffer Registers
     ********************************************************************* */
 
@@ -683,7 +710,7 @@
 #define A_SCD_TRACE_SEQUENCE_6      0x0010020A90
 #define A_SCD_TRACE_SEQUENCE_7      0x0010020A98
 
-/*  ********************************************************************* 
+/*  *********************************************************************
     * System Generic DMA Registers
     ********************************************************************* */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250_scd.h linux-2.4.20/include/asm-mips64/sibyte/sb1250_scd.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250_scd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250_scd.h	2002-10-29 11:18:33.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  SCD Constants and Macros			File: sb1250_scd.h
-    *  
+    *
     *  This module contains constants and macros useful for
     *  manipulating the System Control and Debug module on the 1250.
-    *  
-    *  SB1250 specification level:  0.2  plus errata as of 11/7/2000
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -53,7 +53,8 @@
 
 #define K_SYS_REVISION_PASS1	    1
 #define K_SYS_REVISION_PASS2	    3
-#define K_SYS_REVISION_PASS3	    4 /* XXX Unknown */
+#define K_SYS_REVISION_PASS2_2	    16
+#define K_SYS_REVISION_PASS3	    32
 
 #define S_SYS_PART                  _SB_MAKE64(16)
 #define M_SYS_PART                  _SB_MAKEMASK(16,S_SYS_PART)
@@ -61,7 +62,7 @@
 #define G_SYS_PART(x)               _SB_GETVALUE(x,S_SYS_PART,M_SYS_PART)
 
 #define K_SYS_PART_SB1250           0x1250
-#define K_SYS_PART_SB1125           0x1125 
+#define K_SYS_PART_SB1125           0x1125
 
 #define S_SYS_WID                   _SB_MAKE64(32)
 #define M_SYS_WID                   _SB_MAKEMASK(32,S_SYS_WID)
@@ -153,6 +154,9 @@
 #define M_SYS_MISR_MODE             _SB_MAKEMASK1(61)
 #define M_SYS_MISR_RESET            _SB_MAKEMASK1(62)
 
+#define M_SYS_SW_FLAG		    _SB_MAKEMASK1(63)	/* PASS2 */
+
+
 /*
  * Mailbox Registers (Table 4-3)
  * Registers: SCD_MBOX_CPU_x
@@ -346,6 +350,7 @@
 #define M_SCD_TRACE_CFG_FREEZE_FULL     _SB_MAKEMASK1(5)
 #define M_SCD_TRACE_CFG_DEBUG_FULL      _SB_MAKEMASK1(6)
 #define M_SCD_TRACE_CFG_FULL            _SB_MAKEMASK1(7)
+#define M_SCD_TRACE_CFG_FORCECNT        _SB_MAKEMASK1(8)	/* PASS2 */
 
 #define S_SCD_TRACE_CFG_CUR_ADDR        10
 #define M_SCD_TRACE_CFG_CUR_ADDR        _SB_MAKEMASK(8,S_SCD_TRACE_CFG_CUR_ADDR)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250_smbus.h linux-2.4.20/include/asm-mips64/sibyte/sb1250_smbus.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250_smbus.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250_smbus.h	2002-10-29 11:18:35.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  SMBUS Constants                          File: sb1250_smbus.h
-    *  
-    *  This module contains constants and macros useful for 
+    *
+    *  This module contains constants and macros useful for
     *  manipulating the SB1250's SMbus devices.
-    *  
-    *  SB1250 specification level:  0.2
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *
+    *  SB1250 specification level:  01/02/2002
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -131,4 +131,44 @@
 #define M_SPEC_PEC                  _SB_MAKEMASK(8,S_SPEC_PEC)
 #define V_SPEC_MB(x)                _SB_MAKEVALUE(x,S_SPEC_PEC)
 
+
+/*  *********************************************************************
+    *  PASS2 Extensions to SMBus
+    ********************************************************************* */
+
+/* BEGIN PASS2 */
+
+#define S_SMB_CMDH                  8
+#define M_SMB_CMDH                  _SB_MAKEMASK(8,S_SMBH_CMD)
+#define V_SMB_CMDH(x)               _SB_MAKEVALUE(x,S_SMBH_CMD)
+
+#define M_SMB_EXTEND		    _SB_MAKEMASK1(14)
+
+#define M_SMB_DIR		    _SB_MAKEMASK1(13)
+
+#define S_SMB_DFMT                  8
+#define M_SMB_DFMT                  _SB_MAKEMASK(3,S_SMB_DFMT)
+#define V_SMB_DFMT(x)               _SB_MAKEVALUE(x,S_SMB_DFMT)
+#define G_SMB_DFMT(x)               _SB_GETVALUE(x,S_SMB_DFMT,M_SMB_DFMT)
+
+#define K_SMB_DFMT_1BYTE            0
+#define K_SMB_DFMT_2BYTE            1
+#define K_SMB_DFMT_3BYTE            2
+#define K_SMB_DFMT_4BYTE            3
+#define K_SMB_DFMT_NODATA           4
+#define K_SMB_DFMT_CMD4BYTE         5
+#define K_SMB_DFMT_CMD5BYTE         6
+#define K_SMB_DFMT_RESERVED         7
+
+#define V_SMB_DFMT_1BYTE	    V_SMB_DFMT(K_SMB_DFMT_1BYTE)
+#define V_SMB_DFMT_2BYTE	    V_SMB_DFMT(K_SMB_DFMT_2BYTE)
+#define V_SMB_DFMT_3BYTE	    V_SMB_DFMT(K_SMB_DFMT_3BYTE)
+#define V_SMB_DFMT_4BYTE	    V_SMB_DFMT(K_SMB_DFMT_4BYTE)
+#define V_SMB_DFMT_NODATA	    V_SMB_DFMT(K_SMB_DFMT_NODATA)
+#define V_SMB_DFMT_CMD4BYTE	    V_SMB_DFMT(K_SMB_DFMT_CMD4BYTE)
+#define V_SMB_DFMT_CMD5BYTE	    V_SMB_DFMT(K_SMB_DFMT_CMD5BYTE)
+#define V_SMB_DFMT_RESERVED	    V_SMB_DFMT(K_SMB_DFMT_RESERVED)
+
+/* END PASS2 */
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250_syncser.h linux-2.4.20/include/asm-mips64/sibyte/sb1250_syncser.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250_syncser.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250_syncser.h	2002-10-29 11:18:39.000000000 +0000
@@ -6,18 +6,18 @@
     *  This module contains constants and macros useful for
     *  manipulating the SB1250's Synchronous Serial
     *
-    *  SB1250 specification level:  0.2
+    *  SB1250 specification level:  User's manual 1/02/02
     *
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
     *
     *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250_uart.h linux-2.4.20/include/asm-mips64/sibyte/sb1250_uart.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250_uart.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250_uart.h	2002-10-29 11:18:49.000000000 +0000
@@ -1,23 +1,23 @@
 /*  *********************************************************************
     *  SB1250 Board Support Package
-    *  
+    *
     *  UART Constants				File: sb1250_uart.h
-    *  
-    *  This module contains constants and macros useful for 
+    *
+    *  This module contains constants and macros useful for
     *  manipulating the SB1250's UARTs
     *
-    *  SB1250 specification level:  01/02/2002
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
+    *  SB1250 specification level:  User's manual 1/02/02
+    *
+    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
+    *
+    *********************************************************************
     *
     *  Copyright 2000,2001
     *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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 
+    *
+    *  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,
@@ -27,7 +27,7 @@
     *
     *  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, 
+    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     *  MA 02111-1307 USA
     ********************************************************************* */
 
@@ -37,7 +37,7 @@
 
 #include "sb1250_defs.h"
 
-/* ********************************************************************** 
+/* **********************************************************************
    * DUART Registers
    ********************************************************************** */
 
@@ -144,7 +144,7 @@
 #define V_DUART_MISC_CMD_START_BREAK     V_DUART_MISC_CMD(K_DUART_MISC_CMD_START_BREAK)
 #define V_DUART_MISC_CMD_STOP_BREAK      V_DUART_MISC_CMD(K_DUART_MISC_CMD_STOP_BREAK)
 
-#define M_DUART_CMD_RESERVED             _SB_MAKEMASK1(7) 
+#define M_DUART_CMD_RESERVED             _SB_MAKEMASK1(7)
 
 /*
  * DUART Status Register (Table 10-6)
@@ -164,7 +164,7 @@
 
 /*
  * DUART Baud Rate Register (Table 10-7)
- * Register: DUART_CLK_SEL_A 
+ * Register: DUART_CLK_SEL_A
  * Register: DUART_CLK_SEL_B
  */
 
@@ -229,6 +229,9 @@
 #define M_DUART_IP3_CHNG_ENA        _SB_MAKEMASK1(3)
 #define M_DUART_ACR_RESERVED        _SB_MAKEMASK(4,4)
 
+#define M_DUART_CTS_CHNG_ENA        _SB_MAKEMASK1(0)
+#define M_DUART_CIN_CHNG_ENA        _SB_MAKEMASK1(2)
+
 /*
  * DUART Interrupt Status Register (Table 10-16)
  * Register: DUART_ISR
@@ -327,9 +330,20 @@
     (chan == 0 ? M_DUART_OUT_PIN_CLR0 : M_DUART_OUT_PIN_CLR1)
 
 /*
- * XXX To be added: Synchronous Serial definitions
+ * Full Interrupt Control Register (PASS2)
  */
 
+#define S_DUART_SIG_FULL           _SB_MAKE64(0)
+#define M_DUART_SIG_FULL           _SB_MAKEMASK(4,S_DUART_SIG_FULL)
+#define V_DUART_SIG_FULL(x)        _SB_MAKEVALUE(x,S_DUART_SIG_FULL)
+#define G_DUART_SIG_FULL(x)        _SB_GETVALUE(x,S_DUART_SIG_FULL,M_DUART_SIG_FULL)
+
+#define S_DUART_INT_TIME           _SB_MAKE64(4)
+#define M_DUART_INT_TIME           _SB_MAKEMASK(4,S_DUART_INT_TIME)
+#define V_DUART_INT_TIME(x)        _SB_MAKEVALUE(x,S_DUART_INT_TIME)
+#define G_DUART_INT_TIME(x)        _SB_GETVALUE(x,S_DUART_INT_TIME,M_DUART_INT_TIME)
+
+
 /* ********************************************************************** */
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sb1250regs.h linux-2.4.20/include/asm-mips64/sibyte/sb1250regs.h
--- linux-2.4.19/include/asm-mips64/sibyte/sb1250regs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sb1250regs.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2001 Broadcom Corporation
- *
- * 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.
- */
-
-/* Register definitions and offsets for the SB1250 integrated peripherals */
-
-/* Base addresses for each of the cpus */
-#include <asm/addrspace.h>
-
-#define SB1250_SCD_BASE        (KSEG1 + 0x10020000)
-
-/* All the SCD registers are duplicated for each cpu. */
-#define SB1250_CPU0_OFS                 0
-#define SB1250_CPU1_OFS            0x2000
-
-#define SB1250_INT_DIAG         (SB1250_SCD_BASE + 0x10)
-#define SB1250_INT_LDT_SET      (SB1250_SCD_BASE + 0x48)
-#define SB1250_INT_LDT          (SB1250_SCD_BASE + 0x18)
-#define SB1250_INT_LDT_CLR      (SB1250_SCD_BASE + 0x20)
-#define SB1250_INT_MASK         (SB1250_SCD_BASE + 0x28)
-#define SB1250_INT_STATUS       (SB1250_SCD_BASE + 0x100)
-#define SB1250_INT_SRC_STATUS   (SB1250_SCD_BASE + 0x040)
-#define SB1250_INT_TRC          (SB1250_SCD_BASE + 0x38)
-#define SB1250_INT_MAP          (SB1250_SCD_BASE + 0x200)
-
-/* General purpose timer configuration registers */
-#define SB1250_GPT_CFG0         (SB1250_SCD_BASE + 0x090)
-#define SB1250_GPT_CFG1         (SB1250_SCD_BASE + 0x098)
-#define SB1250_GPT_CFG2         (SB1250_SCD_BASE + 0x190)
-#define SB1250_GPT_CFG3         (SB1250_SCD_BASE + 0x198)
-
-#define SB1250_GPT_INT_MAP0     (SB1250_INT_MAP + (2<<3))
-#define SB1250_GPT_INT_MAP1     (SB1250_INT_MAP + (3<<3))
-#define SB1250_GPT_INT_MAP2     (SB1250_INT_MAP + (4<<3))
-#define SB1250_GPT_INT_MAP3     (SB1250_INT_MAP + (5<<3))
-
-/* General purpose timer configuration bitfields */
-#define SB1250_GPT_CFG_ENABLE      0x1
-#define SB1250_GPT_CFG_CONTINUOUS  0x2
-
-/* General purpose timer count initialization registers */
-#define SB1250_GPT_INIT_CNT0    (SB1250_SCD_BASE + 0x070)
-#define SB1250_GPT_INIT_CNT1    (SB1250_SCD_BASE + 0x078)
-#define SB1250_GPT_INIT_CNT2    (SB1250_SCD_BASE + 0x170)
-#define SB1250_GPT_INIT_CNT3    (SB1250_SCD_BASE + 0x178)
-
-/* Interrupt map values */
-#define SB1250_MAP_IP2             0
-#define SB1250_MAP_IP3             1
-#define SB1250_MAP_IP4             2
-#define SB1250_MAP_IP5             3
-#define SB1250_MAP_IP6             4
-#define SB1250_MAP_IP7             5
-#define SB1250_MAP_NMI             6
-#define SB1250_MAP_DEBUG           7
-
-
-/* Owners of the various interrupts at the scd level.  Note this
-   is the pre mapping values. */
-
-#define SB1250_INT_WATCHDOG_0            0
-#define SB1250_INT_WATCHDOG_1            1
-#define SB1250_INT_TIMER_0               2
-#define SB1250_INT_TIMER_1               3
-#define SB1250_INT_TIMER_2               4
-#define SB1250_INT_TIMER_3               5
-#define SB1250_INT_SMB_0                 6
-#define SB1250_INT_SMB_1                 7
-#define SB1250_INT_UART_0                8
-#define SB1250_INT_UART_1                9
-
-/* FIXME!  Need to add the rest */
- 
-
-/*
- * There are 2 UARTS.  Technically you can access them via
- * some unified registers, but the seperated interfaces are 
- * much cleaner 
- */
-
-#define SB1250_UART_0_OFS            0x000  
-#define SB1250_UART_1_OFS            0x100  
-
-#define SB1250_DUART_MODE_1   (KSEG1 + 0x10060100)
-#define SB1250_DUART_MODE_2   (KSEG1 + 0x10060110)
-#define SB1250_DUART_CMD      (KSEG1 + 0x10060150)
-#define SB1250_DUART_STATUS   (KSEG1 + 0x10060120)
-#define SB1250_DUART_BAUD     (KSEG1 + 0x10060130)
-#define SB1250_DUART_RX       (KSEG1 + 0x10060160)
-#define SB1250_DUART_TX       (KSEG1 + 0x10060170)
-#define SB1250_DUART_CLK_SEL  (KSEG1 + 0x10060130)
-#define SB1250_DUART_IMR0     (KSEG1 + 0x10060330)
-#define SB1250_DUART_IMR1     (KSEG1 + 0x10060350)
-
-/* 
- *   Mode register 1 fields 
- */
-/* Bits per character */
-#define SB1250_DM1_8BPC        0x0
-#define SB1250_DM1_7BPR        0x1
-
-/* Parity type */
-#define SB1250_DM1_EVEN_PAR    0x0
-#define SB1250_DM1_LOW_PAR     0x0
-#define SB1250_DM1_ODD_PAR     0x4
-#define SB1250_DM1_HIGH_PAR    0x4
-
-/* Parity mode */
-#define SB1250_DM1_PAR          0x0
-#define SB1250_DM1_FIXED_PAR    0x8
-#define SB1250_DM1_NO_PAR      0x10
-
-/* Recieve IRQ select */
-#define SB1250_DM1_IRQ_READY   0x00
-#define SB1250_DM1_IRQ_FULL    0x40
-
-/* RTS flow control */
-#define SB1250_DM1_RTS         0x80
-
-/* 
- *   Mode register 2 fields 
- */
-/* Stop bit length */
-#define SB1250_DM2_1_STOP_BIT  0x0
-#define SB1250_DM2_2_STOP_BITS 0x8
-
-/* Transmitter CTS flow control enable */
-#define SB1250_DM2_CTS         0x10
-
-/* DUART Channel mode */
-#define SB1250_DM2_LCL_LOOP    0x80
-#define SB1250_DM2_RMT_LOOP    0xc0
-
-/*
- * Command register fields 
- */
-/* Any of these can be written */
-#define SB1250_DC_RX_EN        0x1
-#define SB1250_DC_RX_DIS       0x2
-#define SB1250_DC_TX_EN        0x4
-#define SB1250_DC_TX_DIS       0x8
-
-/* Command field possibilities.  At most one of these should be written 
-   at a time */
-#define SB1250_DC_RX_RST      0x20
-#define SB1250_DC_TX_RST      0x30
-#define SB1250_DC_BRK_CHG_RST 0x50
-#define SB1250_DC_BRK_START   0x60
-#define SB1250_DC_BRK_STOP    0x70
-
-/* FINISH ME */
-
-#define SB1250_DS_TX_RDY       0x4
-#define SB1250_DS_RX_RDY       0x1
-#define SB1250_DS_TX_EMT       0x8
-
-/* DUART interrupt source masks for ISR */
-#define SB1250_DIM_TX          0x1
-#define SB1250_DIM_RX          0x2
-#define SB1250_DIM_BRK         0x4
-#define SB1250_DIM_IN          0x8
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/sbmips.h linux-2.4.20/include/asm-mips64/sibyte/sbmips.h
--- linux-2.4.19/include/asm-mips64/sibyte/sbmips.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/sbmips.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,654 +0,0 @@
-/*  *********************************************************************
-    *  SB1250 Board Support Package
-    *  
-    *  MIPS64 CPU definitions			File: sbmips.h
-    * 
-    *  This module contains constants and macros specific to the
-    *  SB1 MIPS64 core.
-    *  
-    *  Author:  Mitch Lichtenberg (mitch@sibyte.com)
-    *  
-    *********************************************************************  
-    *
-    *  Copyright 2000,2001
-    *  Broadcom Corporation. All rights reserved.
-    *  
-    *  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
-    ********************************************************************* */
-
-#ifndef _SB_MIPS_H
-#define _SB_MIPS_H
-
-/*  *********************************************************************
-    *  Configure language
-    ********************************************************************* */
-
-#if defined(__ASSEMBLY__)
-#define _ATYPE_
-#define _ATYPE32_
-#define _ATYPE64_
-#else
-#define _ATYPE_		(__SIZE_TYPE__)
-#define _ATYPE32_	(int)
-#define _ATYPE64_	(long long)
-#endif
-
-
-/*  *********************************************************************
-    *  Bitfield macros
-    ********************************************************************* */
-
-/*
- * Make a mask for 1 bit at position 'n'
- */
-
-#define _MM_MAKEMASK1(n) (1 << (n))
-
-/*
- * Make a mask for 'v' bits at position 'n'
- */
-
-#define _MM_MAKEMASK(v,n) (((1<<(v))-1) << (n))
-
-/*
- * Make a value at 'v' at bit position 'n'
- */
-
-#define _MM_MAKEVALUE(v,n) ((v) << (n))
-
-/*
- * Retrieve a value from 'v' at bit position 'n' with 'm' mask bits
- */
-
-#define _MM_GETVALUE(v,n,m) (((v) & (m)) >> (n))
-
-
-
-/*  *********************************************************************
-    *  32-bit MIPS Address Spaces
-    ********************************************************************* */
-
-#ifdef __ASSEMBLY__
-#define _ACAST32_
-#define _ACAST64_
-#else
-#define _ACAST32_	_ATYPE_ _ATYPE32_	/* widen if necessary */
-#define _ACAST64_		_ATYPE64_	/* do _not_ narrow */
-#endif
-
-/* 32-bit address map */
-#define UBASE		0x00000000		/* user+ mapped */
-#define USIZE		0x80000000
-#define K0BASE 		(_ACAST32_ 0x80000000)	/* kernel unmapped cached */
-#define K0SIZE 		0x20000000
-#define K1BASE 		(_ACAST32_ 0xa0000000)	/* kernel unmapped uncached */
-#define K1SIZE 		0x20000000
-#define KSBASE 		(_ACAST32_ 0xc0000000)	/* supervisor+ mapped */
-#define KSSIZE 		0x20000000
-#define K3BASE 		(_ACAST32_ 0xe0000000)	/* kernel mapped */
-#define K3SIZE 		0x20000000
-
-/* 64-bit address map additions to the above (sign-extended) ranges */
-#define XUBASE		(_ACAST64_ 0x0000000080000000)	/* user+ mapped */
-#define XUSIZE		(_ACAST64_ 0x00000FFF80000000)
-#define XSSEGBASE       (_ACAST64_ 0x4000000000000000)	/* supervisor+ mapped */
-#define XSSEGSIZE	(_ACAST64_ 0x0000100000000000)
-#define XKPHYSBASE      (_ACAST64_ 0x8000000000000000)	/* kernel unmapped */
-#define XKPHYSSIZE	(_ACAST64_ 0x0000100000000000)
-#define XKSEGBASE       (_ACAST64_ 0xC000000000000000)	/* kernel mapped */
-#define XKSEGSIZE	(_ACAST64_ 0x00000FFF80000000)
-
-#define GEN_VECT 	(_ACAST32_ 0x80000080)
-#define UTLB_VECT 	(_ACAST32_ 0x80000000)
-
-/*  *********************************************************************
-    *  Address space coercion macros
-    ********************************************************************* */
-
-#define PHYS_TO_K0(pa)	(K0BASE | (pa))
-#define PHYS_TO_K1(pa)	(K1BASE | (pa))
-#define K0_TO_PHYS(va)	((va) & (K0SIZE-1))
-#define K1_TO_PHYS(va)	((va) & (K1SIZE-1))
-#define K0_TO_K1(va)	((va) | K1SIZE)
-#define K1_TO_K0(va)	((va) & ~K1SIZE)
-
-#define PHYS_TO_XK1(p) (_ACAST64_ (0xffffffffa0000000 | (p)))
-#define XK1_TO_PHYS(p) ((p) & (K1SIZE-1))
-#define PHYS_TO_XKPHYS(cca,p) (_SB_MAKEMASK1(63) | (_SB_MAKE64(cca) << 59) | (p))
-#define PHYS_TO_XKSEG_UNCACHED(p)  PHYS_TO_XKPHYS(K_CALG_UNCACHED,(p))
-#define PHYS_TO_XKSEG_CACHED(p)    PHYS_TO_XKPHYS(K_CALG_COH_SHAREABLE,(p))
-#define XKPHYS_TO_PHYS(p) ((p) & _SB_MAKEMASK(0,59))
-
-
-#if !defined(__ASSEMBLY__)
-#define mips_wbflush()  __asm__ __volatile__ ("sync" : : : "memory")
-#define	ISK0SEG(va)	((va) >= K0BASE && (va) <= (K0BASE + K0SIZE - 1))
-#define	ISK1SEG(va)	((va) >= K1BASE && (va) <= (K1BASE + K1SIZE - 1))
-#endif
-
-/*  *********************************************************************
-    *  Register aliases
-    ********************************************************************* */
-
-#if defined(__ASSEMBLY__)
-#define zero		$0
-#define	AT		$1		/* assembler temporaries */
-#define	v0		$2		/* value holders */
-#define	v1		$3
-#define	a0		$4		/* arguments */
-#define	a1		$5
-#define	a2		$6
-#define	a3		$7
-#define	t0		$8		/* temporaries */
-#define	t1		$9
-#define	t2		$10
-#define	t3		$11
-#define	t4		$12
-#define	t5		$13
-#define	t6		$14
-#define	t7		$15
-#define ta0		$12
-#define ta1		$13
-#define ta2		$14
-#define ta3		$15
-#define	s0		$16		/* saved registers */
-#define	s1		$17
-#define	s2		$18
-#define	s3		$19
-#define	s4		$20
-#define	s5		$21
-#define	s6		$22
-#define	s7		$23
-#define	t8		$24		/* temporaries */
-#define	t9		$25
-#define	k0		$26		/* kernel registers */
-#define	k1		$27
-#define	gp		$28		/* global pointer */
-#define	sp		$29		/* stack pointer */
-#define	s8		$30		/* saved register */
-#define	fp		$30		/* frame pointer */
-#define	ra		$31		/* return address */
-#endif
-
-/*  *********************************************************************
-    *  CP0 Registers 
-    ********************************************************************* */
-
-#if defined(__ASSEMBLY__)
-#define C0_INX		$0		/* CP0: TLB Index */
-#define C0_RAND		$1		/* CP0: TLB Random */
-#define C0_TLBLO0	$2		/* CP0: TLB EntryLo0 */
-#define C0_TLBLO	C0_TLBLO0	/* CP0: TLB EntryLo0 */
-#define C0_TLBLO1	$3		/* CP0: TLB EntryLo1 */
-#define C0_CTEXT	$4		/* CP0: Context */
-#define C0_PGMASK	$5		/* CP0: TLB PageMask */
-#define C0_WIRED	$6		/* CP0: TLB Wired */
-#define C0_BADVADDR	$8		/* CP0: Bad Virtual Address */
-#define C0_COUNT 	$9		/* CP0: Count */
-#define C0_TLBHI	$10		/* CP0: TLB EntryHi */
-#define C0_COMPARE	$11		/* CP0: Compare */
-#define C0_SR		$12		/* CP0: Processor Status */
-#define C0_STATUS	C0_SR		/* CP0: Processor Status */
-#define C0_CAUSE	$13		/* CP0: Exception Cause */
-#define C0_EPC		$14		/* CP0: Exception PC */
-#define C0_PRID		$15		/* CP0: Processor Revision Indentifier */
-#define C0_CONFIG	$16		/* CP0: Config */
-#define C0_LLADDR	$17		/* CP0: LLAddr */
-#define C0_WATCHLO	$18		/* CP0: WatchpointLo */
-#define C0_WATCHHI	$19		/* CP0: WatchpointHi */
-#define C0_XCTEXT	$20		/* CP0: XContext */
-#define C0_ECC		$26		/* CP0: ECC */
-#define C0_CACHEERR	$27		/* CP0: CacheErr */
-#define C0_TAGLO	$28		/* CP0: TagLo */
-#define C0_TAGHI	$29		/* CP0: TagHi */
-#define C0_ERREPC	$30		/* CP0: ErrorEPC */
-#else
-#define C0_INX		0		/* CP0: TLB Index */
-#define C0_RAND		1		/* CP0: TLB Random */
-#define C0_TLBLO0	2		/* CP0: TLB EntryLo0 */
-#define C0_TLBLO	C0_TLBLO0	/* CP0: TLB EntryLo0 */
-#define C0_TLBLO1	3		/* CP0: TLB EntryLo1 */
-#define C0_CTEXT	4		/* CP0: Context */
-#define C0_PGMASK	5		/* CP0: TLB PageMask */
-#define C0_WIRED	6		/* CP0: TLB Wired */
-#define C0_BADVADDR	8		/* CP0: Bad Virtual Address */
-#define C0_COUNT 	9		/* CP0: Count */
-#define C0_TLBHI	10		/* CP0: TLB EntryHi */
-#define C0_COMPARE	11		/* CP0: Compare */
-#define C0_SR		12		/* CP0: Processor Status */
-#define C0_STATUS	C0_SR		/* CP0: Processor Status */
-#define C0_CAUSE	13		/* CP0: Exception Cause */
-#define C0_EPC		14		/* CP0: Exception PC */
-#define C0_PRID		15		/* CP0: Processor Revision Indentifier */
-#define C0_CONFIG	16		/* CP0: Config */
-#define C0_LLADDR	17		/* CP0: LLAddr */
-#define C0_WATCHLO	18		/* CP0: WatchpointLo */
-#define C0_WATCHHI	19		/* CP0: WatchpointHi */
-#define C0_XCTEXT	20		/* CP0: XContext */
-#define C0_ECC		26		/* CP0: ECC */
-#define C0_CACHEERR	27		/* CP0: CacheErr */
-#define C0_TAGLO	28		/* CP0: TagLo */
-#define C0_TAGHI	29		/* CP0: TagHi */
-#define C0_ERREPC	30		/* CP0: ErrorEPC */
-#endif
-
-/*  *********************************************************************
-    *  CP1 (floating point) control registers
-    ********************************************************************* */
-
-#define FPA_IRR		0		/* CP1: Implementation/Revision */
-#define FPA_CSR		31		/* CP1: Control/Status */
-
-/*  *********************************************************************
-    *  Macros for generating assembly language routines
-    ********************************************************************* */
-
-#if defined(__ASSEMBLY__)
-
-/* global leaf function (does not call other functions) */
-#define LEAF(name)		\
-  	.globl	name;		\
-  	.ent	name;		\
-name:
-
-/* global alternate entry to (local or global) leaf function */
-#define XLEAF(name)		\
-  	.globl	name;		\
-  	.aent	name;		\
-name:
-
-/* end of a global function */
-#define END(name)		\
-  	.size	name,.-name;	\
-  	.end	name
-
-/* local leaf function (does not call other functions) */
-#define SLEAF(name)		\
-  	.ent	name;		\
-name:
-
-/* local alternate entry to (local or global) leaf function */
-#define SXLEAF(name)		\
-  	.aent	name;		\
-name:
-
-/* end of a local function */
-#define SEND(name)		\
-  	END(name)
-
-/* define & export a symbol */
-#define EXPORT(name)		\
-  	.globl name;		\
-name:
-
-/* import a symbol */
-#define	IMPORT(name, size)	\
-	.extern	name,size
-
-/* define a zero-fill common block (BSS if not overridden) with a global name */
-#define COMM(name,size)		\
-	.comm	name,size
-
-/* define a zero-fill common block (BSS if not overridden) with a local name */
-#define LCOMM(name,size)		\
-  	.lcomm	name,size
-
-#endif
-
-
-/* Floating-Point Control register bits */
-#define CSR_C		0x00800000
-#define CSR_EXC		0x0003f000
-#define CSR_EE		0x00020000
-#define CSR_EV		0x00010000
-#define CSR_EZ		0x00008000
-#define CSR_EO		0x00004000
-#define CSR_EU		0x00002000
-#define CSR_EI		0x00001000
-#define CSR_TV		0x00000800
-#define CSR_TZ		0x00000400
-#define CSR_TO		0x00000200
-#define CSR_TU		0x00000100
-#define CSR_TI		0x00000080
-#define CSR_SV		0x00000040
-#define CSR_SZ		0x00000020
-#define CSR_SO		0x00000010
-#define CSR_SU		0x00000008
-#define CSR_SI		0x00000004
-#define CSR_RM		0x00000003
-
-/* Status Register */
-#define M_SR_CUMASK	_MM_MAKEMASK(4,28)	/* coprocessor usable bits */
-#define M_SR_CU3	_MM_MAKEMASK1(31)	/* coprocessor 3 usable */
-#define M_SR_CU2	_MM_MAKEMASK1(30)	/* coprocessor 2 usable */
-#define M_SR_CU1	_MM_MAKEMASK1(29)	/* coprocessor 1 usable */
-#define M_SR_CU0	_MM_MAKEMASK1(28)	/* coprocessor 0 usable */
-
-#define M_SR_RP		_MM_MAKEMASK1(27)	/* reduced power mode */
-#define M_SR_FR		_MM_MAKEMASK1(26)	/* fpu regs any data */
-#define M_SR_RE		_MM_MAKEMASK1(25)	/* reverse endian */
-#define M_SR_MX		_MM_MAKEMASK1(24)	/* MDMX */
-#define M_SR_PX		_MM_MAKEMASK1(23)	/* 64-bit ops in user mode */
-#define M_SR_BEV	_MM_MAKEMASK1(22)	/* boot exception vectors */
-#define M_SR_TS		_MM_MAKEMASK1(21)	/* TLB is shut down */
-#define M_SR_SR		_MM_MAKEMASK1(20)	/* soft reset */
-#define M_SR_NMI	_MM_MAKEMASK1(19)	/* nonmaskable interrupt */
-
-#define M_SR_IMASK	_MM_MAKEMASK(8,8)	/* all interrupt mask bits */
-
-#define M_SR_IBIT8	_MM_MAKEMASK1(15)	/* individual bits */
-#define M_SR_IBIT7	_MM_MAKEMASK1(14)
-#define M_SR_IBIT6	_MM_MAKEMASK1(13)
-#define M_SR_IBIT5	_MM_MAKEMASK1(12)
-#define M_SR_IBIT4	_MM_MAKEMASK1(11)
-#define M_SR_IBIT3	_MM_MAKEMASK1(10)
-#define M_SR_IBIT2	_MM_MAKEMASK1(9)
-#define M_SR_IBIT1	_MM_MAKEMASK1(8)
-
-#define M_SR_IMASK8	0			/* masks for nested int levels */
-#define M_SR_IMASK7	_MM_MAKEMASK(1,15)
-#define M_SR_IMASK6	_MM_MAKEMASK(2,14)
-#define M_SR_IMASK5	_MM_MAKEMASK(3,13)
-#define M_SR_IMASK4	_MM_MAKEMASK(4,12)
-#define M_SR_IMASK3	_MM_MAKEMASK(5,11)
-#define M_SR_IMASK2	_MM_MAKEMASK(6,10)
-#define M_SR_IMASK1	_MM_MAKEMASK(7,9)
-#define M_SR_IMASK0	_MM_MAKEMASK(8,8)
-
-#define M_SR_KX		_MM_MAKEMASK1(7)	/* 64-bit access for kernel */
-#define M_SR_SX		_MM_MAKEMASK1(6)	/* .. for supervisor */
-#define M_SR_UX		_MM_MAKEMASK1(5)	/* .. for user */
-
-#define S_SR_KSU	3			/* base operating mode mode */
-#define M_SR_KSU	_MM_MAKEMASK(2,S_SR_KSU)
-#define V_SR_KSU(x)	_MM_MAKEVALUE(x,S_SR_KSU)
-#define G_SR_KSU(x)	_MM_GETVALUE(x,S_SR_KSU,M_SR_KSU)
-#define K_SR_KSU_KERNEL	0
-#define K_SR_KSU_SUPR	1
-#define K_SR_KSU_USER	2
-
-#define M_SR_UM		_MM_MAKEMASK1(4)
-#define M_SR_ERL	_MM_MAKEMASK1(2)
-#define M_SR_EXL	_MM_MAKEMASK1(1)
-#define M_SR_IE		_MM_MAKEMASK1(0)
-
-/* 
- * Cause Register 
- */
-#define M_CAUSE_BD	_MM_MAKEMASK1(31) /* exception in BD slot */
-
-#define S_CAUSE_CE	28		/* coprocessor error */
-#define M_CAUSE_CE	_MM_MAKEMASK(2,S_CAUSE_CE)
-#define V_CAUSE_CE(x)	_MM_MAKEVALUE(x,S_CAUSE_CE)
-#define G_CAUSE_CE(x)	_MM_GETVALUE(x,S_CAUSE_CE,M_CAUSE_CE)
-
-#define M_CAUSE_IV	_MM_MAKEMASK1(23) /* special interrupt */
-#define M_CAUSE_WP      _MM_MAKEMASK1(22) /* watch interrupt deferred */
-
-#define S_CAUSE_IPMASK	8
-#define M_CAUSE_IPMASK	_MM_MAKEMASK(8,S_CAUSE_IPMASK)
-#define M_CAUSE_IP8	_MM_MAKEMASK1(15)	/* hardware interrupts */
-#define M_CAUSE_IP7	_MM_MAKEMASK1(14)
-#define M_CAUSE_IP6	_MM_MAKEMASK1(13)
-#define M_CAUSE_IP5	_MM_MAKEMASK1(12)
-#define M_CAUSE_IP4	_MM_MAKEMASK1(11)
-#define M_CAUSE_IP3	_MM_MAKEMASK1(10)
-#define M_CAUSE_SW2	_MM_MAKEMASK1(9)	/* software interrupts */
-#define M_CAUSE_SW1	_MM_MAKEMASK1(8)
-
-#define S_CAUSE_EXC	2
-#define M_CAUSE_EXC	_MM_MAKEMASK(5,S_CAUSE_EXC)
-#define V_CAUSE_EXC(x)	_MM_MAKEVALUE(x,S_CAUSE_EXC)
-#define G_CAUSE_EXC(x)	_MM_GETVALUE(x,S_CAUSE_EXC,M_CAUSE_EXC)
-
-/* Exception Code */
-#define K_CAUSE_EXC_INT		0	/* External interrupt */
-#define K_CAUSE_EXC_MOD		1	/* TLB modification */
-#define K_CAUSE_EXC_TLBL	2    	/* TLB miss (Load or Ifetch) */
-#define K_CAUSE_EXC_TLBS	3	/* TLB miss (Save) */
-#define K_CAUSE_EXC_ADEL	4    	/* Address error (Load or Ifetch) */
-#define K_CAUSE_EXC_ADES	5	/* Address error (Save) */
-#define K_CAUSE_EXC_IBE		6	/* Bus error (Ifetch) */
-#define K_CAUSE_EXC_DBE		7	/* Bus error (data load or store) */
-#define K_CAUSE_EXC_SYS		8	/* System call */
-#define K_CAUSE_EXC_BP		9	/* Break point */
-#define K_CAUSE_EXC_RI		10	/* Reserved instruction */
-#define K_CAUSE_EXC_CPU		11	/* Coprocessor unusable */
-#define K_CAUSE_EXC_OVF		12	/* Arithmetic overflow */
-#define K_CAUSE_EXC_TRAP	13	/* Trap exception */
-#define K_CAUSE_EXC_VCEI	14	/* Virtual Coherency Exception (I) */
-#define K_CAUSE_EXC_FPE		15	/* Floating Point Exception */
-#define K_CAUSE_EXC_CP2		16	/* Cp2 Exception */
-#define K_CAUSE_EXC_WATCH	23	/* Watchpoint exception */
-#define K_CAUSE_EXC_VCED	31	/* Virtual Coherency Exception (D) */
-
-#define	K_NTLBENTRIES	64
-
-#define HI_HALF(x)	((x) >> 16)
-#define LO_HALF(x)	((x) & 0xffff)
-
-/* FPU stuff */
-
-#if defined(__ASSEMBLY__)
-#define C1_CSR		$31
-#define C1_FRID		$0
-#else
-#define C1_CSR		31
-#define C1_FRID		0
-#endif
-
-#define S_FCSR_CAUSE	12
-#define M_FCSR_CAUSE	_MM_MAKEMASK(5,S_FCSR_CAUSE)
-#define V_FCSR_CAUSE(x)	_MM_MAKEVALUE(x,S_FCSR_CAUSE)
-#define G_FCSR_CAUSE(x)	_MM_GETVALUE(x,S_FCSR_CAUSE,M_FCSR_CAUSE)
-
-#define S_FCSR_ENABLES	7
-#define M_FCSR_ENABLES	_MM_MAKEMASK(5,S_FCSR_ENABLES)
-#define V_FCSR_ENABLES(x) _MM_MAKEVALUE(x,S_FCSR_ENABLES)
-#define G_FCSR_ENABLES(x) _MM_GETVALUE(x,S_FCSR_ENABLES,M_FCSR_ENABLES)
-
-#define S_FCSR_FLAGS	2
-#define M_FCSR_FLAGS	_MM_MAKEMASK(5,S_FCSR_FLAGS)
-#define V_FCSR_FLAGS(x)	_MM_MAKEVALUE(x,S_FCSR_FLAGS)
-#define G_FCSR_FLAGS(x)	_MM_GETVALUE(x,S_FCSR_FLAGS,M_FCSR_FLAGS)
-
-
-/*
- * MIPS64 Config Register (select 0)
- */
-#define M_CFG_CFG1	_MM_MAKEMASK1(31)	/* config1 select1 is impl */
-#define M_CFG_BE        _MM_MAKEMASK1(15)	/* big-endian mode */
-
-#define S_CFG_AT	13			/* Architecture Type */
-#define M_CFG_AT	_MM_MAKEMASK(2,S_CFG_AT)
-#define V_CFG_AT(x)	_MM_MAKEVALUE(x,S_CFG_AT)
-#define G_CFG_AT(x)	_MM_GETVALUE(x,S_CFG_AT,M_CFG_AT)
-#define K_CFG_AT_MIPS32	0
-#define K_CFG_AT_MIPS64_32 1
-#define K_CFG_AT_MIPS64	2
-
-#define S_CFG_AR	10			/* Architecture Revision */
-#define M_CFG_AR        _MM_MAKEMASK(3,S_CFG_AR)
-#define V_CFG_AR(x)	_MM_MAKEVALUE(x,S_CFG_AR)
-#define G_CFG_AR(x)	_MM_GETVALUE(x,S_CFG_AR,M_CFG_AR)
-#define K_CFG_AR_REV1	0
-
-#define S_CFG_MMU	7			/* MMU Type */
-#define M_CFG_MMU       _MM_MAKEMASK(3,S_CFG_MMU)
-#define V_CFG_MMU(x)	_MM_MAKEVALUE(x,S_CFG_MMU)
-#define G_CFG_MMU(x)	_MM_GETVALUE(x,S_CFG_MMU,M_CFG_MMU)
-#define K_CFG_MMU_NONE	0
-#define K_CFG_MMU_TLB	1
-#define K_CFG_MMU_BAT	2
-#define K_CFG_MMU_FIXED	3
-
-#define S_CFG_K0COH	0			/* K0seg coherency */
-#define M_CFG_K0COH	_MM_MAKEMASK(3,S_CFG_K0COH)
-#define V_CFG_K0COH(x)	_MM_MAKEVALUE(x,S_CFG_K0COH)
-#define G_CFG_K0COH(x)	_MM_GETVALUE(x,S_CFG_K0COH,M_CFG_K0COH)
-#define K_CFG_K0COH_UNCACHED	2
-#define K_CFG_K0COH_CACHEABLE	3
-#define K_CFG_K0COH_COHERENT	5
-
-/*
- * MIPS64 Config Register (select 1)
- */
-
-#define M_CFG_CFG2	_MM_MAKEMASK1(31)	/* config2 select2 is impl */
-
-#define S_CFG_MMUSIZE	25
-#define M_CFG_MMUSIZE	_MM_MAKEMASK(6,S_CFG_MMUSIZE)
-
-#define S_CFG_IS	22
-#define M_CFG_IS	_MM_MAKEMASK(3,S_CFG_IS)
-#define V_CFG_IS(x)	_MM_MAKEVALUE(x,S_CFG_IS)
-#define G_CFG_IS(x)	_MM_GETVALUE(x,S_CFG_IS,M_CFG_IS)
-
-#define S_CFG_IL	19
-#define M_CFG_IL	_MM_MAKEMASK(S_CFG_IL,3)
-#define V_CFG_IL(x)	_MM_MAKEVALUE(x,S_CFG_IL)
-#define G_CFG_IL(x)	_MM_GETVALUE(x,S_CFG_IL,M_CFG_IL)
-
-#define S_CFG_IA	16
-#define M_CFG_IA	_MM_MAKEMASK(3,S_CFG_IA)
-#define V_CFG_IA(x)	_MM_MAKEVALUE(x,S_CFG_IA)
-#define G_CFG_IA(x)	_MM_GETVALUE(x,S_CFG_IA,M_CFG_IA)
-
-#define S_CFG_DS	13
-#define M_CFG_DS	_MM_MAKEMASK(3,S_CFG_DS)
-#define V_CFG_DS(x)	_MM_MAKEVALUE(x,S_CFG_DS)
-#define G_CFG_DS(x)	_MM_GETVALUE(x,S_CFG_DS,M_CFG_DS)
-
-#define S_CFG_DL	10
-#define M_CFG_DL	_MM_MAKEMASK(3,S_CFG_DL)
-#define V_CFG_DL(x)	_MM_MAKEVALUE(x,S_CFG_DL)
-#define G_CFG_DL(x)	_MM_GETVALUE(x,S_CFG_DL,M_CFG_DL)
-
-#define S_CFG_DA	7
-#define M_CFG_DA	_MM_MAKEMASK(3,S_CFG_DA)
-#define V_CFG_DA(x)	_MM_MAKEVALUE(x,S_CFG_DA)
-#define G_CFG_DA(x)	_MM_GETVALUE(x,S_CFG_DA,M_CFG_DA)
-
-#define M_CFG_PC	_MM_MAKEMASK1(4)	/* perf ctrs present */
-#define M_CFG_WR	_MM_MAKEMASK1(3)	/* watch regs present */
-#define M_CFG_CA	_MM_MAKEMASK1(2)	/* MIPS16 present */
-#define M_CFG_EP	_MM_MAKEMASK1(1)	/* EJTAG present */
-#define M_CFG_FP	_MM_MAKEMASK1(0)	/* FPU present */
-
-
-
-/* 
- * Primary Cache TagLo 
- */
-
-#define S_TAGLO_PTAG	8
-#define M_TAGLO_PTAG 	_MM_MAKEMASK(56,S_TAGLO_PTAG)
-
-#define S_TAGLO_PSTATE	6
-#define M_TAGLO_PSTATE	_MM_MAKEMASK(2,S_TAGLO_PSTATE)
-#define V_TAGLO_PSTATE(x) _MM_MAKEVALUE(x,S_TAGLO_PSTATE)
-#define G_TAGLO_PSTATE(x) _MM_GETVALUE(x,S_TAGLO_PSTATE,M_TAGLO_PSTATE)
-#define K_TAGLO_PSTATE_INVAL		0
-#define K_TAGLO_PSTATE_SHARED		1
-#define K_TAGLO_PSTATE_CLEAN_EXCL	2
-#define K_TAGLO_PSTATE_DIRTY_EXCL	3
-
-#define M_TAGLO_LOCK	_MM_MAKEMASK1(5)
-#define M_TAGLO_PARITY	_MM_MAKEMASK1(0)
-
-
-/*
- * CP0 CacheErr register
- */
-#define M_CERR_DATA	_MM_MAKEMASK1(31)	/* err in D space */
-#define M_CERR_SCACHE	_MM_MAKEMASK1(30)	/* err in l2, not l1 */
-#define M_CERR_DERR	_MM_MAKEMASK1(29)	/* data error */
-#define M_CERR_TERR	_MM_MAKEMASK1(28)	/* tag error */
-#define M_CERR_EXTRQ	_MM_MAKEMASK1(27)	/* external req caused err */
-#define M_CERR_BPAR	_MM_MAKEMASK1(26)	/* bus parity err */
-#define M_CERR_ADATA	_MM_MAKEMASK1(25)	/* additional data */
-#define M_CERR_IDX	_MM_MAKEMASK(22,0)
-
-
-
-/*
- * Primary Cache operations
- */
-#define Index_Invalidate_I               0x0         /* 0       0 */
-#define Index_Writeback_Inv_D            0x1         /* 0       1 */
-#define Index_Invalidate_SI              0x2         /* 0       2 */
-#define Index_Writeback_Inv_SD           0x3         /* 0       3 */
-#define Index_Load_Tag_I                 0x4         /* 1       0 */
-#define Index_Load_Tag_D                 0x5         /* 1       1 */
-#define Index_Load_Tag_SI                0x6         /* 1       2 */
-#define Index_Load_Tag_SD                0x7         /* 1       3 */
-#define Index_Store_Tag_I                0x8         /* 2       0 */
-#define Index_Store_Tag_D                0x9         /* 2       1 */
-#define Index_Store_Tag_SI               0xA         /* 2       2 */
-#define Index_Store_Tag_SD               0xB         /* 2       3 */
-#define Create_Dirty_Exc_D               0xD         /* 3       1 */
-#define Create_Dirty_Exc_SD              0xF         /* 3       3 */
-#define Hit_Invalidate_I                 0x10        /* 4       0 */
-#define Hit_Invalidate_D                 0x11        /* 4       1 */
-#define Hit_Invalidate_SI                0x12        /* 4       2 */
-#define Hit_Invalidate_SD                0x13        /* 4       3 */
-#define Fill_I                           0x14        /* 5       0 */
-#define Hit_Writeback_Inv_D              0x15        /* 5       1 */
-#define Hit_Writeback_Inv_SD             0x17        /* 5       3 */
-#define Hit_Writeback_I                  0x18        /* 6       0 */
-#define Hit_Writeback_D                  0x19        /* 6       1 */
-#define Hit_Writeback_SD                 0x1B        /* 6       3 */
-#define Hit_Set_Virtual_SI               0x1E        /* 7       2 */
-#define Hit_Set_Virtual_SD               0x1F        /* 7       3 */
-
-/* Watchpoint Register */
-#define M_WATCH_PA		0xfffffff8
-#define M_WATCH_R		0x00000002
-#define M_WATCH_W		0x00000001
-
-
-/* TLB entries */
-#define M_TLBHI_ASID		_MM_MAKEMASK(0,8)
-#define M_TLBHI_VPN2		_MM_MAKEMASK(27,13)
-
-#define M_TLBLO_G		_MM_MAKEMASK1(0)
-#define M_TLBLO_V		_MM_MAKEMASK1(1)
-#define M_TLBLO_D		_MM_MAKEMASK1(2)
-
-#define S_TLBLO_CALG		3
-#define M_TLBLO_CALG		_MM_MAKEMASK(3,S_TLBLO_CALG)
-#define V_TLBLO_CALG(x) 	_MM_MAKEVALUE(x,S_TLBLO_CALG)
-#define G_TLBLO_CALG(x) 	_MM_GETVALUE(x,S_TLBLO_CALG,M_TLBLO_CALG)
-
-#define K_CALG_COH_EXCL1_NOL2	0
-#define K_CALG_COH_SHRL1_NOL2	1
-#define K_CALG_UNCACHED		2
-#define K_CALG_NONCOHERENT	3
-#define K_CALG_COH_EXCL		4
-#define K_CALG_COH_SHAREABLE	5
-#define K_CALG_NOTUSED		6
-#define K_CALG_UNCACHED_ACCEL	7
-
-#define S_TLBLO_PFNMASK		6
-#define M_TLBLO_PFNMASK		_MM_MAKEMASK(24,S_TLBLO_PFNMASK)
-#define V_TLBLO_PFNMASK(x) 	_MM_MAKEVALUE(x,S_TLBLO_PFNMASK)
-#define G_TLBLO_PFNMASK(x) 	_MM_GETVALUE(x,S_TLBLO_PFNMASK,M_TLBLO_PFNMASK)
-
-
-
-#endif /* _SB_MIPS_H */
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/swarm.h linux-2.4.20/include/asm-mips64/sibyte/swarm.h
--- linux-2.4.19/include/asm-mips64/sibyte/swarm.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/swarm.h	2002-10-29 11:18:50.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001 Broadcom Corporation
+ * Copyright (C) 2000, 2001 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -10,19 +10,57 @@
  * 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.
  */
+#ifndef __ASM_SIBYTE_SWARM_H
+#define __ASM_SIBYTE_SWARM_H
 
-#ifndef _ASM_SIBYTE_SWARM_H
-#define _ASM_SIBYTE_SWARM_H
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/sb1250_int.h>
 
 #define KERNEL_RESERVED_MEM 0x100000
-#define LED_BASE_ADDR 0x100a0020
 
+#define LEDS_CS         3
+
+#ifdef CONFIG_SIBYTE_SWARM
+
+/* Generic bus chip selects */
+#define IDE_CS          4
+#define PCMCIA_CS       6
+
+/* GPIOs */
+#define K_GPIO_GB_IDE   4
+#define K_INT_GB_IDE    (K_INT_GPIO_0 + K_GPIO_GB_IDE)
+#define K_GPIO_PC_READY 9
+#define K_INT_PC_READY  (K_INT_GPIO_0 + K_GPIO_PC_READY)
+
+#endif
+
+#ifdef __ASSEMBLY__
+#define setleds(t0,t1,c0,c1,c2,c3) \
+	li	t0, (LED_BASE_ADDR|0xa0000000); \
+	li	t1, c0; \
+	sb	t1, 0x18(t0); \
+	li	t1, c1; \
+	sb	t1, 0x10(t0); \
+	li	t1, c2; \
+	sb	t1, 0x08(t0); \
+	li	t1, c3; \
+	sb	t1, 0x00(t0)
+#else
 void swarm_setup(void);
-void setleds(char *str); 
+void setleds(char *str);
+
+#define AT_spin \
+	__asm__ __volatile__ (		\
+		".set noat\n"		\
+		"li $at, 0\n"		\
+		"1: beqz $at, 1b\n"	\
+		".set at\n"		\
+		)
+#endif
 
-#endif /* _ASM_SIBYTE_SWARM_H */
+#endif /* __ASM_SIBYTE_SWARM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sibyte/swarm_ide.h linux-2.4.20/include/asm-mips64/sibyte/swarm_ide.h
--- linux-2.4.19/include/asm-mips64/sibyte/swarm_ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sibyte/swarm_ide.h	2002-10-29 11:18:50.000000000 +0000
@@ -10,7 +10,7 @@
  * 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.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sigcontext.h linux-2.4.20/include/asm-mips64/sigcontext.h
--- linux-2.4.19/include/asm-mips64/sigcontext.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sigcontext.h	2002-10-29 11:18:31.000000000 +0000
@@ -23,7 +23,7 @@
 	unsigned int       sc_ownedfp;
 	unsigned int       sc_fpc_csr;
 	unsigned int       sc_fpc_eir;
-
+	unsigned int       sc_used_math;
 	unsigned int       sc_cause;
 	unsigned int       sc_badvaddr;
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/siginfo.h linux-2.4.20/include/asm-mips64/siginfo.h
--- linux-2.4.19/include/asm-mips64/siginfo.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/siginfo.h	2002-10-29 11:18:35.000000000 +0000
@@ -18,11 +18,21 @@
 	void *sival_ptr;
 } sigval_t;
 
+#ifdef __KERNEL__
+
+typedef union sigval32 {
+	int sival_int;
+	s32 sival_ptr;
+} sigval_t32;
+
+#endif /* __KERNEL__ */
+
 /* This structure matches IRIX 32/n32 ABIs for binary compatibility but
    has Linux extensions.  */
 
 #define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
+#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 4)
+#define SI_PAD_SIZE32	((SI_MAX_SIZE/sizeof(int)) - 3)
 
 typedef struct siginfo {
 	int si_signo;
@@ -82,6 +92,68 @@
 	} _sifields;
 } siginfo_t;
 
+#ifdef __KERNEL__
+
+typedef struct siginfo32 {
+	int si_signo;
+	int si_code;
+	int si_errno;
+
+	union {
+		int _pad[SI_PAD_SIZE32];
+
+		/* kill() */
+		struct {
+			__kernel_pid_t32 _pid;	/* sender's pid */
+			__kernel_uid_t32 _uid;	/* sender's uid */
+		} _kill;
+
+		/* SIGCHLD */
+		struct {
+			__kernel_pid_t32 _pid;	/* which child */
+			__kernel_uid_t32 _uid;	/* sender's uid */
+			__kernel_clock_t32 _utime;
+			int _status;		/* exit code */
+			__kernel_clock_t32 _stime;
+		} _sigchld;
+
+		/* IRIX SIGCHLD */
+		struct {
+			__kernel_pid_t32 _pid;	/* which child */
+			__kernel_clock_t32 _utime;
+			int _status;		/* exit code */
+			__kernel_clock_t32 _stime;
+		} _irix_sigchld;
+
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		struct {
+			s32 _addr; /* faulting insn/memory ref. */
+		} _sigfault;
+
+		/* SIGPOLL, SIGXFSZ (To do ...)  */
+		struct {
+			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			int _fd;
+		} _sigpoll;
+
+		/* POSIX.1b timers */
+		struct {
+			unsigned int _timer1;
+			unsigned int _timer2;
+		} _timer;
+
+		/* POSIX.1b signals */
+		struct {
+			__kernel_pid_t32 _pid;	/* sender's pid */
+			__kernel_uid_t32 _uid;	/* sender's uid */
+			sigval_t32 _sigval;
+		} _rt;
+
+	} _sifields;
+} siginfo_t32;
+
+#endif /* __KERNEL__ */
+
 /*
  * How these fields are to be accessed.
  */
@@ -204,8 +276,8 @@
 
 /*
  * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
+ *
+ * It seems likely that SIGEV_THREAD will have to be handled from
  * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
  * thread manager then catches and does the appropriate nonsense.
  * However, everything is written out here so as to not get lost.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/signal.h linux-2.4.20/include/asm-mips64/signal.h
--- linux-2.4.19/include/asm-mips64/signal.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/signal.h	2002-10-29 11:18:34.000000000 +0000
@@ -89,7 +89,7 @@
 
 #define SA_RESTORER	0x04000000
 
-/* 
+/*
  * sigaltstack controls
  */
 #define SS_ONSTACK     1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/smp.h linux-2.4.20/include/asm-mips64/smp.h
--- linux-2.4.19/include/asm-mips64/smp.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/smp.h	2002-10-29 11:18:36.000000000 +0000
@@ -42,8 +42,8 @@
 
 #define CPUMASK_CLRALL(p)	(p) = 0
 #define CPUMASK_SETB(p, bit)	(p) |= 1UL << (bit)
-#define CPUMASK_CLRB(p, bit)	(p) &= ~(1ULL << (bit))
-#define CPUMASK_TSTB(p, bit)	((p) & (1ULL << (bit)))
+#define CPUMASK_CLRB(p, bit)	(p) &= ~(1UL << (bit))
+#define CPUMASK_TSTB(p, bit)	((p) & (1UL << (bit)))
 
 #elif (NR_CPUS <= 128)
 
@@ -60,11 +60,11 @@
 
 #define	CPUMASK_CLRALL(p)	(p)._bits[0] = 0, (p)._bits[1] = 0
 #define CPUMASK_SETB(p, bit)	(p)._bits[CPUMASK_INDEX(bit)] |= \
-					(1ULL << CPUMASK_SHFT(bit))
+					(1UL << CPUMASK_SHFT(bit))
 #define CPUMASK_CLRB(p, bit)	(p)._bits[CPUMASK_INDEX(bit)] &= \
-					~(1ULL << CPUMASK_SHFT(bit))
+					~(1UL << CPUMASK_SHFT(bit))
 #define CPUMASK_TSTB(p, bit)	((p)._bits[CPUMASK_INDEX(bit)] & \
-					(1ULL << CPUMASK_SHFT(bit)))
+					(1UL << CPUMASK_SHFT(bit)))
 
 #else
 #error cpumask macros only defined for 128p kernels
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sn/gda.h linux-2.4.20/include/asm-mips64/sn/gda.h
--- linux-2.4.19/include/asm-mips64/sn/gda.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sn/gda.h	2002-10-29 11:18:37.000000000 +0000
@@ -9,7 +9,7 @@
  *
  * gda.h -- Contains the data structure for the global data area,
  * 	The GDA contains information communicated between the
- *	PROM, SYMMON, and the kernel. 
+ *	PROM, SYMMON, and the kernel.
  */
 #ifndef _ASM_SN_GDA_H
 #define _ASM_SN_GDA_H
@@ -23,9 +23,9 @@
  *
  * Version #	| Change
  * -------------+-------------------------------------------------------
- * 	1	| Initial SN0 version 
+ * 	1	| Initial SN0 version
  * 	2	| Prom sets g_partid field to the partition number. 0 IS
- *		| a valid partition #. 
+ *		| a valid partition #.
  */
 
 #define GDA_VERSION	2	/* Current GDA version # */
@@ -70,7 +70,7 @@
 #endif /* !__ASSEMBLY__ */
 /*
  * Define:	PART_GDA_VERSION
- * Purpose:	Define the minimum version of the GDA required, lower 
+ * Purpose:	Define the minimum version of the GDA required, lower
  *		revisions assume GDA is NOT set up, and read partition
  *		information from the board info.
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sn/intr.h linux-2.4.20/include/asm-mips64/sn/intr.h
--- linux-2.4.19/include/asm-mips64/sn/intr.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sn/intr.h	2002-10-29 11:18:31.000000000 +0000
@@ -31,7 +31,7 @@
 		REMOTE_HUB_S((_hub), PI_INT_PEND_MOD, (0x100|(_level)))
 
 /*
- * When clearing the interrupt, make sure this clear does make it 
+ * When clearing the interrupt, make sure this clear does make it
  * to the hub. Otherwise we could end up losing interrupts.
  * We do an uncached load of the int_pend0 register to ensure this.
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sn/intr_public.h linux-2.4.20/include/asm-mips64/sn/intr_public.h
--- linux-2.4.19/include/asm-mips64/sn/intr_public.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sn/intr_public.h	2002-10-29 11:18:37.000000000 +0000
@@ -1,4 +1,4 @@
-/* 
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -40,11 +40,11 @@
 	 * in the lowest-numbered masks (i.e., 0, 1, 2...).
 	 */
 	/* INT_PEND0: */
-	hubreg_t		intpend0_masks[N_INTPEND0_MASKS]; 
+	hubreg_t		intpend0_masks[N_INTPEND0_MASKS];
 	/* INT_PEND1: */
 	hubreg_t		intpend1_masks[N_INTPEND1_MASKS];
 	/* INT_PEND0: */
-	struct intr_vecblk_s	*dispatch0;	
+	struct intr_vecblk_s	*dispatch0;
 	/* INT_PEND1: */
 	struct intr_vecblk_s	*dispatch1;
 } hub_intmasks_t;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sn/io.h linux-2.4.20/include/asm-mips64/sn/io.h
--- linux-2.4.19/include/asm-mips64/sn/io.h	2000-07-12 22:15:10.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sn/io.h	2002-10-29 11:18:36.000000000 +0000
@@ -56,9 +56,9 @@
 #define IIO_ITTE_GET(nasid, bigwin) REMOTE_HUB_ADDR((nasid), IIO_ITTE(bigwin))
 
 /*
- * Macro which takes the widget number, and returns the 
+ * Macro which takes the widget number, and returns the
  * IO PRB address of that widget.
- * value _x is expected to be a widget number in the range 
+ * value _x is expected to be a widget number in the range
  * 0, 8 - 0xF
  */
 #define	IIO_IOPRB(_x)	(IIO_IOPRB_0 + ( ( (_x) < HUB_WIDGET_ID_MIN ? \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sn/klconfig.h linux-2.4.20/include/asm-mips64/sn/klconfig.h
--- linux-2.4.19/include/asm-mips64/sn/klconfig.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sn/klconfig.h	2002-10-29 11:18:31.000000000 +0000
@@ -19,9 +19,9 @@
 
 /*
  * WARNING:
- *	Certain assembly language routines (notably xxxxx.s) in the IP27PROM 
- *	will depend on the format of the data structures in this file.  In 
- *      most cases, rearranging the fields can seriously break things.   
+ *	Certain assembly language routines (notably xxxxx.s) in the IP27PROM
+ *	will depend on the format of the data structures in this file.  In
+ *      most cases, rearranging the fields can seriously break things.
  *      Adding fields in the beginning or middle can also break things.
  *      Add fields if necessary, to the end of a struct in such a way
  *      that offsets of existing fields do not change.
@@ -76,11 +76,11 @@
 
 #define	MAX_MODULE_ID		255
 #define SIZE_PAD		4096 /* 4k padding for structures */
-/* 
- * 1 NODE brd, 2 Router brd (1 8p, 1 meta), 6 Widgets, 
- * 2 Midplanes assuming no pci card cages 
+/*
+ * 1 NODE brd, 2 Router brd (1 8p, 1 meta), 6 Widgets,
+ * 2 Midplanes assuming no pci card cages
  */
-#define MAX_SLOTS_PER_NODE	(1 + 2 + 6 + 2) 
+#define MAX_SLOTS_PER_NODE	(1 + 2 + 6 + 2)
 
 /* XXX if each node is guranteed to have some memory */
 
@@ -117,7 +117,7 @@
 
 /* Structures to manage various data storage areas */
 /* The numbers must be contiguous since the array index i
-   is used in the code to allocate various areas. 
+   is used in the code to allocate various areas.
 */
 
 #define BOARD_STRUCT 		0
@@ -240,7 +240,7 @@
 
 /*
  * The KLCONFIG area is organized as a LINKED LIST of BOARDs. A BOARD
- * can be either 'LOCAL' or 'REMOTE'. LOCAL means it is attached to 
+ * can be either 'LOCAL' or 'REMOTE'. LOCAL means it is attached to
  * the LOCAL/current NODE. REMOTE means it is attached to a different
  * node.(TBD - Need a way to treat ROUTER boards.)
  *
@@ -250,20 +250,20 @@
  * Figure below). The first byte of the rboard or lboard structure
  * is used to find out its type - no unions are used.
  * If it is a lboard, then the config info of this board will be found
- * on the local node. (LOCAL NODE BASE + offset value gives pointer to 
+ * on the local node. (LOCAL NODE BASE + offset value gives pointer to
  * the structure.
  * If it is a rboard, the local structure contains the node number
  * and the offset of the beginning of the LINKED LIST on the remote node.
  * The details of the hardware on a remote node can be built locally,
- * if required, by reading the LINKED LIST on the remote node and 
+ * if required, by reading the LINKED LIST on the remote node and
  * ignoring all the rboards on that node.
  *
- * The local node uses the REMOTE NODE NUMBER + OFFSET to point to the 
- * First board info on the remote node. The remote node list is 
+ * The local node uses the REMOTE NODE NUMBER + OFFSET to point to the
+ * First board info on the remote node. The remote node list is
  * traversed as the local list, using the REMOTE BASE ADDRESS and not
  * the local base address and ignoring all rboard values.
  *
- * 
+ *
  KLCONFIG
 
  +------------+      +------------+      +------------+      +------------+
@@ -290,7 +290,7 @@
                       +--------------------------------+
 
  *
- * Each BOARD consists of COMPONENTs and the BOARD structure has 
+ * Each BOARD consists of COMPONENTs and the BOARD structure has
  * pointers (offsets) to its COMPONENT structure.
  * The COMPONENT structure has version info, size and speed info, revision,
  * error info and the NIC info. This structure can accomodate any
@@ -298,19 +298,19 @@
  *
  * The ERRORINFO part of each BOARD has error information
  * that describes errors about the BOARD itself. It also has flags to
- * indicate the COMPONENT(s) on the board that have errors. The error 
- * information specific to the COMPONENT is present in the respective 
+ * indicate the COMPONENT(s) on the board that have errors. The error
+ * information specific to the COMPONENT is present in the respective
  * COMPONENT structure.
  *
- * The ERRORINFO structure is also treated like a COMPONENT, ie. the 
+ * The ERRORINFO structure is also treated like a COMPONENT, ie. the
  * BOARD has pointers(offset) to the ERRORINFO structure. The rboard
- * structure also has a pointer to the ERRORINFO structure. This is 
+ * structure also has a pointer to the ERRORINFO structure. This is
  * the place to store ERRORINFO about a REMOTE NODE, if the HUB on
- * that NODE is not working or if the REMOTE MEMORY is BAD. In cases where 
+ * that NODE is not working or if the REMOTE MEMORY is BAD. In cases where
  * only the CPU of the REMOTE NODE is disabled, the ERRORINFO pointer can
- * be a NODE NUMBER, REMOTE OFFSET combination, pointing to error info 
+ * be a NODE NUMBER, REMOTE OFFSET combination, pointing to error info
  * which is present on the REMOTE NODE.(TBD)
- * REMOTE ERRINFO can be stored on any of the nearest nodes 
+ * REMOTE ERRINFO can be stored on any of the nearest nodes
  * or on all the nearest nodes.(TBD)
  * Like BOARD structures, REMOTE ERRINFO structures can be built locally
  * using the rboard errinfo pointer.
@@ -319,9 +319,9 @@
  * interface routines are provided (TBD). The important thing to remember while
  * manipulating the structures, is that, the NODE number information should
  * be used. If the NODE is non-zero (remote) then each offset should
- * be added to the REMOTE BASE ADDR else it should be added to the LOCAL BASE ADDR. 
+ * be added to the REMOTE BASE ADDR else it should be added to the LOCAL BASE ADDR.
  * This includes offsets for BOARDS, COMPONENTS and ERRORINFO.
- * 
+ *
  * Note that these structures do not provide much info about connectivity.
  * That info will be part of HWGRAPH, which is an extension of the cfg_t
  * data structure. (ref IP27prom/cfg.h) It has to be extended to include
@@ -342,11 +342,11 @@
  * IP27 BOARD classes
  */
 
-#define KLCLASS_MASK	0xf0   
+#define KLCLASS_MASK	0xf0
 #define KLCLASS_NONE	0x00
 #define KLCLASS_NODE	0x10             /* CPU, Memory and HUB board */
-#define KLCLASS_CPU	KLCLASS_NODE	
-#define KLCLASS_IO	0x20             /* BaseIO, 4 ch SCSI, ethernet, FDDI 
+#define KLCLASS_CPU	KLCLASS_NODE
+#define KLCLASS_IO	0x20             /* BaseIO, 4 ch SCSI, ethernet, FDDI
 					    and the non-graphics widget boards */
 #define KLCLASS_ROUTER	0x30             /* Router board */
 #define KLCLASS_MIDPLANE 0x40            /* We need to treat this as a board
@@ -420,7 +420,7 @@
  * out the board name from the NIC string. For values less than
  * 8 the name of the board needs to be hard coded in a few places.
  * When bringup started nic names had not standardized and so we
- * had to hard code. (For people interested in history.) 
+ * had to hard code. (For people interested in history.)
  */
 #define KLTYPE_XTHD   	(KLCLASS_PSEUDO_GFX | 0x9)
 
@@ -431,7 +431,7 @@
 				 (l->brd_flags & SECOND_NIC_PRESENT))
 #define IS_MIO_IOC3(l,n)	(IS_MIO_PRESENT(l) && (n > 2))
 
-/* 
+/*
  * board structures
  */
 
@@ -511,10 +511,10 @@
 
 
 /*
- * Generic info structure. This stores common info about a 
+ * Generic info structure. This stores common info about a
  * component.
  */
- 
+
 typedef struct klinfo_s {                  /* Generic info */
         unsigned char   struct_type;       /* type of this structure */
         unsigned char   struct_version;    /* version of this structure */
@@ -540,9 +540,9 @@
 /*
  * Component structures.
  * Following are the currently identified components:
- * 	CPU, HUB, MEM_BANK, 
+ * 	CPU, HUB, MEM_BANK,
  * 	XBOW(consists of 16 WIDGETs, each of which can be HUB or GRAPHICS or BRIDGE)
- * 	BRIDGE, IOC3, SuperIO, SCSI, FDDI 
+ * 	BRIDGE, IOC3, SuperIO, SCSI, FDDI
  * 	ROUTER
  * 	GRAPHICS
  */
@@ -614,9 +614,9 @@
 typedef u64 *router_t;
 
 /*
- * The port info in ip27_cfg area translates to a lboart_t in the 
+ * The port info in ip27_cfg area translates to a lboart_t in the
  * KLCONFIG area. But since KLCONFIG does not use pointers, lboart_t
- * is stored in terms of a nasid and a offset from start of KLCONFIG 
+ * is stored in terms of a nasid and a offset from start of KLCONFIG
  * area  on that nasid.
  */
 typedef struct klport_s {
@@ -692,7 +692,7 @@
 } klmod_serial_num_t;
 
 /* Macros needed to access serial number structure in lboard_t.
-   Hard coded values are necessary since we cannot treat 
+   Hard coded values are necessary since we cannot treat
    serial number struct as a component without losing compatibility
    between prom versions. */
 
@@ -789,7 +789,7 @@
 	klconf_off_t    gfx_mfg_nic;
 } klgfx_t;
 
-typedef struct klxthd_s {   
+typedef struct klxthd_s {
 	klinfo_t 	xthd_info ;
 	klconf_off_t	xthd_mfg_nic ;        /* MFG NIC string */
 } klxthd_t ;
@@ -815,9 +815,9 @@
 
 typedef struct klscsi_s {                          /* SCSI Controller */
 	klinfo_t 	scsi_info ;
-    	scsi_t       	scsi_specific   ; 
+    	scsi_t       	scsi_specific   ;
 	unsigned char 	scsi_numdevs ;
-	klconf_off_t	scsi_devinfo[MAX_SCSI_DEVS] ; 
+	klconf_off_t	scsi_devinfo[MAX_SCSI_DEVS] ;
 } klscsi_t ;
 
 typedef struct klscdev_s {                          /* SCSI device */
@@ -842,20 +842,20 @@
 
 typedef struct klmsdev_s {                          /* mouse device */
         klinfo_t        msdev_info ;
-        void 		*msdev_cfg ; 
+        void 		*msdev_cfg ;
 } klmsdev_t ;
 
 #define MAX_FDDI_DEVS 10 /* XXX Is this true */
 
 typedef struct klfddi_s {                          /* FDDI */
 	klinfo_t 	fddi_info ;
-    	fddi_t        	fddi_specific ;       
+    	fddi_t        	fddi_specific ;
 	klconf_off_t	fddi_devinfo[MAX_FDDI_DEVS] ;
 } klfddi_t ;
 
 typedef struct klmio_s {                          /* MIO */
 	klinfo_t 	mio_info ;
-    	mio_t       	mio_specific   ; 
+    	mio_t       	mio_specific   ;
 } klmio_t ;
 
 
@@ -890,17 +890,17 @@
 
 /*
  * TBD - Can the ARCS and device driver related info also be included in the
- * KLCONFIG area. On the IO4PROM, prom device driver info is part of cfgnode_t 
+ * KLCONFIG area. On the IO4PROM, prom device driver info is part of cfgnode_t
  * structure, viz private to the IO4prom.
  */
 
-/* 
- * TBD - Allocation issues. 
+/*
+ * TBD - Allocation issues.
  *
- * Do we need to Mark off sepatate heaps for lboard_t, rboard_t, component, 
- * errinfo and allocate from them, or have a single heap and allocate all 
+ * Do we need to Mark off sepatate heaps for lboard_t, rboard_t, component,
+ * errinfo and allocate from them, or have a single heap and allocate all
  * structures from it. Debug is easier in the former method since we can
- * dump all similar structs in one command, but there will be lots of holes, 
+ * dump all similar structs in one command, but there will be lots of holes,
  * in memory and max limits are needed for number of structures.
  * Another way to make it organized, is to have a union of all components
  * and allocate a aligned chunk of memory greater than the biggest
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sn/kldir.h linux-2.4.20/include/asm-mips64/sn/kldir.h
--- linux-2.4.19/include/asm-mips64/sn/kldir.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sn/kldir.h	2002-10-29 11:18:39.000000000 +0000
@@ -199,7 +199,7 @@
 #define IP27_NMI_KREGS_OFFSET		0x11400
 #define IP27_NMI_KREGS_CPU_SIZE		0x200
 /*
- * save area of kernel nmi regs in eframe format 
+ * save area of kernel nmi regs in eframe format
  */
 #define IP27_NMI_EFRAME_OFFSET		0x11800
 #define IP27_NMI_EFRAME_SIZE		0x200
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sn/mapped_kernel.h linux-2.4.20/include/asm-mips64/sn/mapped_kernel.h
--- linux-2.4.19/include/asm-mips64/sn/mapped_kernel.h	2001-02-05 05:48:46.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sn/mapped_kernel.h	2002-10-29 11:18:40.000000000 +0000
@@ -6,18 +6,18 @@
 #define __ASM_SN_MAPPED_KERNEL_H
 
 /*
- * Note on how mapped kernels work: the text and data section is 
- * compiled at cksseg segment (LOADADDR = 0xc001c000), and the 
- * init/setup/data section gets a 16M virtual address bump in the 
- * ld.script file (so that tlblo0 and tlblo1 maps the sections). 
- * The vmlinux.64 section addresses are put in the xkseg range 
- * using the change-addresses makefile option. Use elfdump -of 
- * on IRIX to see where the sections go. The Origin loader loads 
- * the two sections contiguously in physical memory. The loader 
- * sets the entry point into kernel_entry using a xkphys address, 
- * but instead of using 0xa800000001160000, it uses the address 
- * 0xa800000000160000, which is where it physically loaded that 
- * code. So no jumps can be done before we have switched to using 
+ * Note on how mapped kernels work: the text and data section is
+ * compiled at cksseg segment (LOADADDR = 0xc001c000), and the
+ * init/setup/data section gets a 16M virtual address bump in the
+ * ld.script file (so that tlblo0 and tlblo1 maps the sections).
+ * The vmlinux.64 section addresses are put in the xkseg range
+ * using the change-addresses makefile option. Use elfdump -of
+ * on IRIX to see where the sections go. The Origin loader loads
+ * the two sections contiguously in physical memory. The loader
+ * sets the entry point into kernel_entry using a xkphys address,
+ * but instead of using 0xa800000001160000, it uses the address
+ * 0xa800000000160000, which is where it physically loaded that
+ * code. So no jumps can be done before we have switched to using
  * cksseg addresses.
  */
 #include <linux/config.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sn/nmi.h linux-2.4.20/include/asm-mips64/sn/nmi.h
--- linux-2.4.19/include/asm-mips64/sn/nmi.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sn/nmi.h	2002-10-29 11:18:48.000000000 +0000
@@ -1,4 +1,4 @@
-/* 
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -8,7 +8,7 @@
 #ifndef __ASM_SN_NMI_H
 #define __ASM_SN_NMI_H
 
-#ident "$Revision: 1.2.4.1 $"
+#ident "$Revision: 1.2.4.2 $"
 
 #include <asm/sn/addrs.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sn/sn0/arch.h linux-2.4.20/include/asm-mips64/sn/sn0/arch.h
--- linux-2.4.19/include/asm-mips64/sn/sn0/arch.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sn/sn0/arch.h	2002-10-29 11:18:40.000000000 +0000
@@ -49,7 +49,7 @@
 #define MAX_PREMIUM_REGIONS     MAX_REGIONS
 
 /*
- * MAX_PARITIONS refers to the maximum number of logically defined 
+ * MAX_PARITIONS refers to the maximum number of logically defined
  * partitions the system can support.
  */
 #define MAX_PARTITIONS		MAX_REGIONS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sn/sn0/hubio.h linux-2.4.20/include/asm-mips64/sn/sn0/hubio.h
--- linux-2.4.19/include/asm-mips64/sn/sn0/hubio.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sn/sn0/hubio.h	2002-10-29 11:18:33.000000000 +0000
@@ -18,7 +18,7 @@
  * In general, the longer software name should be used when available.
  */
 
-/* 
+/*
  * Slightly friendlier names for some common registers.
  * The hardware definitions follow.
  */
@@ -26,7 +26,7 @@
 #define IIO_WIDGET_STAT		IIO_WSTAT    /* Widget status register */
 #define IIO_WIDGET_CTRL		IIO_WCR	     /* Widget control register */
 #define IIO_WIDGET_TOUT		IIO_WRTO     /* Widget request timeout */
-#define IIO_WIDGET_FLUSH	IIO_WTFR     /* Widget target flush */ 
+#define IIO_WIDGET_FLUSH	IIO_WTFR     /* Widget target flush */
 #define IIO_PROTECT		IIO_ILAPR    /* IO interface protection */
 #define IIO_PROTECT_OVRRD	IIO_ILAPO    /* IO protect override */
 #define IIO_OUTWIDGET_ACCESS	IIO_IOWA     /* Outbound widget access */
@@ -67,8 +67,8 @@
 
 /*
  * The following definitions use the names defined in the IO interface
- * document for ease of reference.  When possible, software should 
- * generally use the the longer but clearer names defined above.
+ * document for ease of reference.  When possible, software should
+ * generally use the longer but clearer names defined above.
  */
 
 #define IIO_BASE	0x400000
@@ -198,7 +198,7 @@
 } hubii_wcr_t;
 
 #define	iwcr_dir_con	wcr_fields_s.wcr_dir_con
-	    
+
 typedef union hubii_wstat_u {
 	u64      reg_value;
 	struct {
@@ -215,13 +215,13 @@
 	} wstat_fields_s;
 } hubii_wstat_t;
 
-		
+
 typedef union hubii_ilcsr_u {
 	u64	icsr_reg_value;
 	struct {
 		u64 	icsr_rsvd: 	22,	/* unused */
                    	icsr_max_burst:	10,	/* max burst */
-                        icsr_rsvd4:	 6,	/* reserved */	          
+                        icsr_rsvd4:	 6,	/* reserved */
                    	icsr_max_retry:	10,	/* max retry */
                         icsr_rsvd3:	 2,	/* reserved */
                         icsr_lnk_stat:	 2,	/* link status */
@@ -285,7 +285,7 @@
 
 typedef union io_perf_cnt {
 	u64	perf_cnt;
-	struct { 
+	struct {
 		u64	perf_rsvd1 : 32,
   			        perf_rsvd2 : 12,
   			        perf_cnt   : 20;
@@ -299,9 +299,9 @@
 
 #define IIO_LLP_CB_MAX	0xffff
 #define IIO_LLP_SN_MAX	0xffff
-	    
+
 /* IO PRB Entries */
-#define	IIO_NUM_IPRBS	(9)		
+#define	IIO_NUM_IPRBS	(9)
 #define IIO_IOPRB_0	0x400198	/* PRB entry 0 */
 #define IIO_IOPRB_8	0x4001a0	/* PRB entry 8 */
 #define IIO_IOPRB_9	0x4001a8	/* PRB entry 9 */
@@ -320,7 +320,7 @@
 #define IIO_IECLR	0x4001f8	/* IO error clear */
 #define IIO_IBCN        0x400200        /* IO BTE CRB count */
 
-/* 
+/*
  * IIO_IMEM Register fields.
  */
 #define IIO_IMEM_W0ESD  0x1             /* Widget 0 shut down due to error */
@@ -366,7 +366,7 @@
 #define IIO_ICMR_CLR_RPPD	(1UL << 13)
 #define IIO_ICMR_CLR_RQPD	(1UL << 12)
 
-/* 
+/*
  * IIO PIO Deallocation register field masks : (IIO_IPDR)
  */
 #define	IIO_IPDR_PND	(1 << 4)
@@ -377,7 +377,7 @@
 #define	IIO_ICDR_PND	(1 << 4)
 
 /*
- * IIO CRB control register Fields: IIO_ICCR 
+ * IIO CRB control register Fields: IIO_ICCR
  */
 #define	IIO_ICCR_PENDING	(0x10000)
 #define	IIO_ICCR_CMD_MASK	(0xFF)
@@ -385,7 +385,7 @@
 #define	IIO_ICCR_CMD_NOP	(0x0)	/* No Op */
 #define	IIO_ICCR_CMD_WAKE	(0x100) /* Reactivate CRB entry and process */
 #define	IIO_ICCR_CMD_TIMEOUT	(0x200)	/* Make CRB timeout & mark invalid */
-#define	IIO_ICCR_CMD_EJECT	(0x400)	/* Contents of entry written to memory 
+#define	IIO_ICCR_CMD_EJECT	(0x400)	/* Contents of entry written to memory
 					 * via a WB
 					 */
 #define	IIO_ICCR_CMD_FLUSH	(0x800)
@@ -423,15 +423,15 @@
  *
  * Many of the fields in CRB are status bits used by hardware
  * for implementation of the protocol. It's very dangerous to
- * mess around with the CRB registers. 
- * 
+ * mess around with the CRB registers.
+ *
  * It's OK to read the CRB registers and try to make sense out of the
- * fields in CRB. 
+ * fields in CRB.
  *
- * Updating CRB requires all activities in Hub IIO to be quiesced. 
+ * Updating CRB requires all activities in Hub IIO to be quiesced.
  * otherwise, a write to CRB could corrupt other CRB entries.
  * CRBs are here only as a back door peek to hub IIO's status.
- * Quiescing implies  no dmas no PIOs 
+ * Quiescing implies  no dmas no PIOs
  * either directly from the cpu or from sn0net.
  * this is not something that can be done easily. So, AVOID updating
  * CRBs.
@@ -465,7 +465,7 @@
    NI_STATUS_REV_ID register. */
 typedef union h1_icrba_u {
 	u64	reg_value;
-	
+
 	struct {
 		u64 	resvd: 	6,
 			unused:	1,	/* Unused but RW!!	*/
@@ -505,11 +505,11 @@
 #define	IIO_ICRB_ADDR_SHFT	2	/* Shift to get proper address */
 
 /*
- * values for "ecode" field 
+ * values for "ecode" field
  */
 #define	IIO_ICRB_ECODE_DERR	0	/* Directory error due to IIO access */
 #define	IIO_ICRB_ECODE_PERR	1	/* Poison error on IO access */
-#define	IIO_ICRB_ECODE_WERR	2	/* Write error by IIO access 
+#define	IIO_ICRB_ECODE_WERR	2	/* Write error by IIO access
 					 * e.g. WINV to a Read only line.
 					 */
 #define	IIO_ICRB_ECODE_AERR	3	/* Access error caused by IIO access */
@@ -537,15 +537,15 @@
 				 * 3: Reserved.
 				 */
 		srcnode: 9,	/* Source Node ID		*/
-		srcinit: 2,	/* Source Initiator: 
+		srcinit: 2,	/* Source Initiator:
 				 * See below for field values.
 				 */
 		useold:	1,	/* Use OLD command for processing */
 		imsgtype: 2,	/* Incoming message type
-				 * see below for field values 
+				 * see below for field values
 				 */
 		imsg: 	8,	/* Incoming message 	*/
-		initator: 3,	/* Initiator of original request 
+		initator: 3,	/* Initiator of original request
 				 * See below for field values.
 				 */
 		reqtype: 5,	/* Identifies type of request
@@ -579,18 +579,18 @@
 					 * 3: Reserved.
 					 */
 			srcnode: 9,	/* Source Node ID		*/
-			srcinit: 2,	/* Source Initiator: 
+			srcinit: 2,	/* Source Initiator:
 					 * See below for field values.
 					 */
 			useold:	1,	/* Use OLD command for processing */
 			imsgtype: 2,	/* Incoming message type
-					 * see below for field values 
+					 * see below for field values
 					 */
 			imsg: 	8,	/* Incoming message 	*/
-			initator: 3,	/* Initiator of original request 
+			initator: 3,	/* Initiator of original request
 					 * See below for field values.
 					 */
-			rsvd2: 	1,	
+			rsvd2: 	1,
 			pcache: 1,	/* entry belongs to partial cache */
 			reqtype: 5,	/* Identifies type of request
 					 * See below for field values.
@@ -676,8 +676,8 @@
 #define	IIO_ICRB_REQ_WB		16	/* Request is Write back	*/
 #define	IIO_ICRB_REQ_DEX	17	/* Retained DEX Cache line	*/
 
-/* 
- * Fields in CRB Register C 
+/*
+ * Fields in CRB Register C
  */
 
 #ifndef __ASSEMBLY__
@@ -690,7 +690,7 @@
 			pricnt: 4,	/* Priority count sent with Read req */
 			pripsc: 4,	/* Priority Pre scalar 	*/
 			bteop:	1,	/* BTE Operation 	*/
-			push_be: 34,	/* Push address Byte enable 
+			push_be: 34,	/* Push address Byte enable
 					 * Holds push addr, if CRB is for BTE
 					 * If CRB belongs to Partial cache,
 					 * this contains byte enables bits
@@ -725,7 +725,7 @@
 	    u64	rsvd:	38,
 		toutvld: 1,	/* Timeout in progress for this CRB */
 		ctxtvld: 1,	/* Context field below is valid	*/
-		rsvd2:	1,	
+		rsvd2:	1,
 		context: 15, 	/* Bit vector:
 				 * Has a bit set for each CRB entry
 				 * which needs to be deallocated
@@ -762,7 +762,7 @@
 #define IIO_IBCT_0	0x410018	/* BTE control/terminate 0 */
 #define IIO_IBNA_0	0x410020	/* BTE notification address 0 */
 #define IIO_IBNR_0	IIO_IBNA_0
-#define IIO_IBIA_0	0x410028	/* BTE interrupt address 0 */	
+#define IIO_IBIA_0	0x410028	/* BTE interrupt address 0 */
 
 #define IIO_IBLS_1	0x420000	/* BTE length/status 1 */
 #define IIO_IBSA_1	0x420008	/* BTE source address 1 */
@@ -770,7 +770,7 @@
 #define IIO_IBCT_1	0x420018	/* BTE control/terminate 1 */
 #define IIO_IBNA_1	0x420020	/* BTE notification address 1 */
 #define IIO_IBNR_1	IIO_IBNA_1
-#define IIO_IBIA_1	0x420028	/* BTE interrupt address 1 */	
+#define IIO_IBIA_1	0x420028	/* BTE interrupt address 1 */
 
 /*
  * More miscellaneous registers
@@ -795,7 +795,7 @@
 #define IECLR_PRB_0		(1 << 0)   /* clear err bit in PRB_0 reg */
 
 /*
- * IO PIO Read Table Entry format 
+ * IO PIO Read Table Entry format
  */
 
 #ifndef __ASSEMBLY__
@@ -830,7 +830,7 @@
 
 #ifndef __ASSEMBLY__
 /*
- * Note: Fields bnakctr, anakctr, xtalkctrmode, ovflow fields are 
+ * Note: Fields bnakctr, anakctr, xtalkctrmode, ovflow fields are
  * "Status" fields, and should only be used in case of clean up after errors.
  */
 
@@ -932,8 +932,8 @@
 	} iin_fmt;
 } hubii_idsr_t;
 #endif /* !__ASSEMBLY__ */
-	
-/* 
+
+/*
  * IO BTE Length/Status (IIO_IBLS) register bit field definitions
  */
 #define IBLS_BUSY		(0x1 << 20)
@@ -965,18 +965,18 @@
 #define HUB_WIDGET_ID_MIN	0x8
 #define HUB_WIDGET_ID_MAX	0xf
 
-#define HUB_WIDGET_PART_NUM	0xc101	
+#define HUB_WIDGET_PART_NUM	0xc101
 #define MAX_HUBS_PER_XBOW	2
 
-/* 
- * Get a hub's widget id from widget control register 
+/*
+ * Get a hub's widget id from widget control register
  */
-#define IIO_WCR_WID_GET(nasid)	(REMOTE_HUB_L(nasid, III_WCR) & 0xf) 
+#define IIO_WCR_WID_GET(nasid)	(REMOTE_HUB_L(nasid, III_WCR) & 0xf)
 #define IIO_WST_ERROR_MASK	(UINT64_CAST 1 << 32) /* Widget status error */
 
 /*
  * Number of credits Hub widget has while sending req/response to
- * xbow. 
+ * xbow.
  * Value of 3 is required by Xbow 1.1
  * We may be able to increase this to 4 with Xbow 1.2.
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sn/sn0/hubmd.h linux-2.4.20/include/asm-mips64/sn/sn0/hubmd.h
--- linux-2.4.19/include/asm-mips64/sn/sn0/hubmd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sn/sn0/hubmd.h	2002-10-29 11:18:38.000000000 +0000
@@ -228,7 +228,7 @@
 #define MSU_SN0_SLOTID_MASK	(UINT64_CAST 7)
 #define MSU_SN00_SLOTID_SHFT	7
 #define MSU_SN00_SLOTID_MASK	(UINT64_CAST 0x80)
-	
+
 #define	MSU_PIMM_PSC_SHFT	4
 #define	MSU_PIMM_PSC_MASK	(0xf << MSU_PIMM_PSC_SHFT)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sn/sn0/hubpi.h linux-2.4.20/include/asm-mips64/sn/sn0/hubpi.h
--- linux-2.4.19/include/asm-mips64/sn/sn0/hubpi.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sn/sn0/hubpi.h	2002-10-29 11:18:33.000000000 +0000
@@ -136,8 +136,8 @@
 #define PI_ERR_INT_PEND		0x000400 /* Error Interrupt Pending	    */
 #define PI_ERR_INT_MASK_A	0x000408 /* Error Interrupt mask for CPU A  */
 #define PI_ERR_INT_MASK_B	0x000410 /* Error Interrupt mask for CPU B  */
-#define PI_ERR_STACK_ADDR_A	0x000418 /* Error stack address for CPU A   */ 
-#define PI_ERR_STACK_ADDR_B	0x000420 /* Error stack address for CPU B   */ 
+#define PI_ERR_STACK_ADDR_A	0x000418 /* Error stack address for CPU A   */
+#define PI_ERR_STACK_ADDR_B	0x000420 /* Error stack address for CPU B   */
 #define PI_ERR_STACK_SIZE	0x000428 /* Error Stack Size 		    */
 #define PI_ERR_STATUS0_A	0x000430 /* Error Status 0A 		    */
 #define PI_ERR_STATUS0_A_RCLR	0x000438 /* Error Status 0A clear on read   */
@@ -193,7 +193,7 @@
 
 
 /*
- * The following three macros define all possible error int pends. 
+ * The following three macros define all possible error int pends.
  */
 
 #define PI_FATAL_ERR_CPU_A	(PI_ERR_SYSSTATE_TAG_A 	| \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/sn/sn0/sn0_fru.h linux-2.4.20/include/asm-mips64/sn/sn0/sn0_fru.h
--- linux-2.4.19/include/asm-mips64/sn/sn0/sn0_fru.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/sn/sn0/sn0_fru.h	2002-10-29 11:18:33.000000000 +0000
@@ -17,11 +17,11 @@
 typedef unsigned char confidence_t;
 
 typedef struct kf_mem_s {
-	confidence_t km_confidence; /* confidence level that the memory is bad 
-				     * is this necessary ? 
+	confidence_t km_confidence; /* confidence level that the memory is bad
+				     * is this necessary ?
 				     */
-	confidence_t km_dimm[MAX_DIMMS];   
-	                            /* confidence level that dimm[i] is bad 
+	confidence_t km_dimm[MAX_DIMMS];
+	                            /* confidence level that dimm[i] is bad
 				     *I think this is the right number
 				     */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/socket.h linux-2.4.20/include/asm-mips64/socket.h
--- linux-2.4.19/include/asm-mips64/socket.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/socket.h	2002-10-29 11:18:33.000000000 +0000
@@ -12,7 +12,7 @@
 #include <asm/sockios.h>
 
 /*
- * For setsockoptions(2)
+ * For setsockopt(2)
  *
  * This defines are ABI conformant as far as Linux supports these ...
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/softirq.h linux-2.4.20/include/asm-mips64/softirq.h
--- linux-2.4.19/include/asm-mips64/softirq.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/softirq.h	2002-10-29 11:18:48.000000000 +0000
@@ -18,7 +18,7 @@
 	local_bh_count(cpu)++;
 	barrier();
 }
- 
+
 static inline void __cpu_bh_enable(int cpu)
 {
 	barrier();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/spinlock.h linux-2.4.20/include/asm-mips64/spinlock.h
--- linux-2.4.19/include/asm-mips64/spinlock.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/spinlock.h	2002-10-29 11:18:39.000000000 +0000
@@ -55,7 +55,7 @@
 	".set\tnoreorder\t\t\t# spin_unlock\n\t"
 	"sync\n\t"
 	"sw\t$0, %0\n\t"
-	".set\treorder"	
+	".set\treorder"
 	: "=m" (lock->lock)
 	: "m" (lock->lock)
 	: "memory");
@@ -109,7 +109,7 @@
 	"sc\t%1, %0\n\t"
 	"beqz\t%1, 1b\n\t"
 	" sync\n\t"
-	".set\treorder"	
+	".set\treorder"
 	: "=m" (rw->lock), "=&r" (tmp)
 	: "m" (rw->lock)
 	: "memory");
@@ -129,7 +129,7 @@
 	"sc\t%1, %0\n\t"
 	"beqz\t%1, 1b\n\t"
 	" sync\n\t"
-	".set\treorder"	
+	".set\treorder"
 	: "=m" (rw->lock), "=&r" (tmp)
 	: "m" (rw->lock)
 	: "memory");
@@ -147,7 +147,7 @@
 	"sc\t%1, %0\n\t"
 	"beqz\t%1, 1b\n\t"
 	" sync\n\t"
-	".set\treorder"	
+	".set\treorder"
 	: "=m" (rw->lock), "=&r" (tmp)
 	: "m" (rw->lock)
 	: "memory");
@@ -159,7 +159,7 @@
 	".set\tnoreorder\t\t\t# write_unlock\n\t"
 	"sync\n\t"
 	"sw\t$0, %0\n\t"
-	".set\treorder"	
+	".set\treorder"
 	: "=m" (rw->lock)
 	: "m" (rw->lock)
 	: "memory");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/stackframe.h linux-2.4.20/include/asm-mips64/stackframe.h
--- linux-2.4.19/include/asm-mips64/stackframe.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/stackframe.h	2002-10-29 11:18:34.000000000 +0000
@@ -77,6 +77,9 @@
 
 #ifdef CONFIG_SMP
 		.macro	get_saved_sp	/* R10000 variation */
+#ifdef CONFIG_CPU_SB1
+		dmfc0	k1, CP0_WATCHLO
+#else
 		mfc0	k0, CP0_WATCHLO
 		mfc0	k1, CP0_WATCHHI
 		dsll32	k0, k0, 0	/* Get rid of sign extension */
@@ -85,12 +88,17 @@
 		or	k1, k1, k0
 		li	k0, K0BASE
 		or	k1, k1, k0
+#endif
 		.endm
 
 		.macro	set_saved_sp	stackp temp
+#ifdef CONFIG_CPU_SB1
+		dmtc0	\stackp, CP0_WATCHLO
+#else
 		mtc0	\stackp, CP0_WATCHLO
 		dsrl32	\temp, \stackp, 0
 		mtc0	\temp, CP0_WATCHHI
+#endif
 		.endm
 
 		.macro	declare_saved_sp
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/system.h linux-2.4.20/include/asm-mips64/system.h
--- linux-2.4.19/include/asm-mips64/system.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/system.h	2002-10-29 11:18:39.000000000 +0000
@@ -12,9 +12,12 @@
 
 #include <linux/config.h>
 #include <asm/sgidefs.h>
-#include <asm/ptrace.h>
+
 #include <linux/kernel.h>
 
+#include <asm/addrspace.h>
+#include <asm/ptrace.h>
+
 __asm__ (
 	".macro\t__sti\n\t"
 	".set\tpush\n\t"
@@ -96,7 +99,7 @@
 	"sll\t$0, $0, 1\t\t\t# nop\n\t"
 	"sll\t$0, $0, 1\t\t\t# nop\n\t"
 	"sll\t$0, $0, 1\t\t\t# nop\n\t"
-	".set\tpop\n\t"	
+	".set\tpop\n\t"
 	".endm");
 
 #define __save_and_cli(x)						\
@@ -161,20 +164,37 @@
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
 
-/*
- * These are probably defined overly paranoid ...
- */
-#define mb()						\
-__asm__ __volatile__(					\
-	"# prevent instructions being moved around\n\t"	\
-	".set\tnoreorder\n\t"				\
-	"sync\n\t"					\
-	".set\treorder"					\
-	: /* no output */				\
-	: /* no input */				\
-	: "memory")
-#define rmb() mb()
-#define wmb() mb()
+#define __sync()				\
+	__asm__ __volatile__(			\
+		".set	push\n\t"		\
+		".set	noreorder\n\t"		\
+		"sync\n\t"			\
+		".set	pop"			\
+		: /* no output */		\
+		: /* no input */		\
+		: "memory")
+
+#define fast_wmb()	__sync()
+#define fast_rmb()	__sync()
+#define fast_mb()	__sync()
+#define fast_iob()				\
+	do {					\
+		__sync();			\
+		__asm__ __volatile__(		\
+			".set	push\n\t"	\
+			".set	noreorder\n\t"	\
+			"lw	$0,%0\n\t"	\
+			"nop\n\t"		\
+			".set	pop"		\
+			: /* no output */	\
+			: "m" (*(int *)KSEG1)	\
+			: "memory");		\
+	} while (0)
+
+#define wmb()		fast_wmb()
+#define rmb()		fast_rmb()
+#define mb()		fast_mb()
+#define iob()		fast_iob()
 
 #ifdef CONFIG_SMP
 #define smp_mb()	mb()
@@ -200,6 +220,8 @@
 
 #define prepare_to_switch()	do { } while(0)
 
+struct task_struct;
+
 extern asmlinkage void lazy_fpu_switch(void *, void *);
 extern asmlinkage void init_fpu(void);
 extern asmlinkage void save_fp(struct task_struct *);
@@ -282,6 +304,16 @@
 	return x;
 }
 
-extern void set_except_vector(int n, void *addr);
+extern void *set_except_vector(int n, void *addr);
+
+extern void __die(const char *, struct pt_regs *, const char *file,
+	const char *func, unsigned long line) __attribute__((noreturn));
+extern void __die_if_kernel(const char *, struct pt_regs *, const char *file,
+	const char *func, unsigned long line);
+
+#define die(msg, regs)							\
+	__die(msg, regs, __FILE__ ":", __FUNCTION__, __LINE__)
+#define die_if_kernel(msg, regs)					\
+	__die_if_kernel(msg, regs, __FILE__ ":", __FUNCTION__, __LINE__)
 
 #endif /* _ASM_SYSTEM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/termios.h linux-2.4.20/include/asm-mips64/termios.h
--- linux-2.4.19/include/asm-mips64/termios.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/termios.h	2002-10-29 11:18:49.000000000 +0000
@@ -85,6 +85,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* line disciplines */
 #define N_TTY		0
 #define N_SLIP		1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/time.h linux-2.4.20/include/asm-mips64/time.h
--- linux-2.4.19/include/asm-mips64/time.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/time.h	2002-10-29 11:18:36.000000000 +0000
@@ -23,7 +23,7 @@
 #include <linux/linkage.h>              /* for asmlinkage */
 #include <linux/rtc.h>                  /* for struct rtc_time */
 
-/* 
+/*
  * RTC ops.  By default, they point a no-RTC functions.
  *	rtc_get_time - mktime(year, mon, day, hour, min, sec) in seconds.
  *	rtc_set_time - reverse the above translation and set time to RTC.
@@ -39,7 +39,7 @@
 extern void to_tm(unsigned long tim, struct rtc_time * tm);
 
 /*
- * do_gettimeoffset(). By default, this func pointer points to 
+ * do_gettimeoffset(). By default, this func pointer points to
  * do_null_gettimeoffset(), which leads to the same resolution as HZ.
  * Higher resolution versions are vailable, which gives ~1us resolution.
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/timex.h linux-2.4.20/include/asm-mips64/timex.h
--- linux-2.4.19/include/asm-mips64/timex.h	2001-09-09 17:43:02.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/timex.h	2002-10-29 11:18:36.000000000 +0000
@@ -20,7 +20,7 @@
  * Standard way to access the cycle counter.
  * Currently only used on SMP for scheduling.
  *
- * Only the low 32 bits are available as a continuously counting entity. 
+ * Only the low 32 bits are available as a continuously counting entity.
  * But this only means we'll force a reschedule every 8 seconds or so,
  * which isn't an evil thing.
  *
@@ -43,4 +43,7 @@
 	return val;
 }
 
+#define vxtime_lock()		do {} while (0)
+#define vxtime_unlock()		do {} while (0)
+
 #endif /*  _ASM_TIMEX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/types.h linux-2.4.20/include/asm-mips64/types.h
--- linux-2.4.19/include/asm-mips64/types.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/types.h	2002-10-29 11:18:50.000000000 +0000
@@ -31,12 +31,12 @@
 typedef unsigned long __u64;
 
 #else
- 
+
 #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
 typedef __signed__ long long __s64;
 typedef unsigned long long __u64;
 #endif
- 
+
 #endif
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/uaccess.h linux-2.4.20/include/asm-mips64/uaccess.h
--- linux-2.4.19/include/asm-mips64/uaccess.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/uaccess.h	2002-10-29 11:18:36.000000000 +0000
@@ -425,7 +425,7 @@
 	__asm__ __volatile__(
 		"move\t$4, %1\n\t"
 		"move\t$5, %2\n\t"
-		__MODULE_JAL(__strlen_user_nocheck_asm)
+		__MODULE_JAL(__strnlen_user_nocheck_asm)
 		"move\t%0, $2"
 		: "=r" (res)
 		: "r" (s), "r" (n)
@@ -441,7 +441,7 @@
 	__asm__ __volatile__(
 		"move\t$4, %1\n\t"
 		"move\t$5, %2\n\t"
-		__MODULE_JAL(__strlen_user_asm)
+		__MODULE_JAL(__strnlen_user_asm)
 		"move\t%0, $2"
 		: "=r" (res)
 		: "r" (s), "r" (n)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/unaligned.h linux-2.4.20/include/asm-mips64/unaligned.h
--- linux-2.4.19/include/asm-mips64/unaligned.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/unaligned.h	2002-10-29 11:18:49.000000000 +0000
@@ -88,8 +88,8 @@
  * get_unaligned - get value from possibly mis-aligned location
  * @ptr: pointer to value
  *
- * This macro should be used for accessing values larger in size than 
- * single bytes at locations that are expected to be improperly aligned, 
+ * This macro should be used for accessing values larger in size than
+ * single bytes at locations that are expected to be improperly aligned,
  * e.g. retrieving a u16 value from a location not u16-aligned.
  *
  * Note that unaligned accesses can be very expensive on some architectures.
@@ -124,8 +124,8 @@
  * @val: value to place
  * @ptr: pointer to location
  *
- * This macro should be used for placing values larger in size than 
- * single bytes at locations that are expected to be improperly aligned, 
+ * This macro should be used for placing values larger in size than
+ * single bytes at locations that are expected to be improperly aligned,
  * e.g. writing a u16 value to a location not u16-aligned.
  *
  * Note that unaligned accesses can be very expensive on some architectures.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/war.h linux-2.4.20/include/asm-mips64/war.h
--- linux-2.4.19/include/asm-mips64/war.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/war.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,70 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002 by Ralf Baechle
+ */
+#ifndef _ASM_WAR_H
+#define _ASM_WAR_H
+
+#include <linux/config.h>
+
+/*
+ * Pleassures of the R4600 V1.x.  Cite from the IDT R4600 V1.7 errata:
+ *
+ *  18. The CACHE instructions Hit_Writeback_Invalidate_D, Hit_Writeback_D,
+ *      Hit_Invalidate_D and Create_Dirty_Excl_D should only be
+ *      executed if there is no other dcache activity. If the dcache is
+ *      accessed for another instruction immeidately preceding when these
+ *      cache instructions are executing, it is possible that the dcache
+ *      tag match outputs used by these cache instructions will be
+ *      incorrect. These cache instructions should be preceded by at least
+ *      four instructions that are not any kind of load or store
+ *      instruction.
+ *
+ *      This is not allowed:    lw
+ *                              nop
+ *                              nop
+ *                              nop
+ *                              cache       Hit_Writeback_Invalidate_D
+ *
+ *      This is allowed:        lw
+ *                              nop
+ *                              nop
+ *                              nop
+ *                              nop
+ *                              cache       Hit_Writeback_Invalidate_D
+ */
+#undef R4600_V1_HIT_DCACHE_WAR	/* Not used yet in 64-bit kernel */
+
+
+/*
+ * Writeback and invalidate the primary cache dcache before DMA.
+ *
+ * R4600 v2.0 bug: "The CACHE instructions Hit_Writeback_Inv_D,
+ * Hit_Writeback_D, Hit_Invalidate_D and Create_Dirty_Exclusive_D will only
+ * operate correctly if the internal data cache refill buffer is empty.  These
+ * CACHE instructions should be separated from any potential data cache miss
+ * by a load instruction to an uncached address to empty the response buffer."
+ * (Revision 2.0 device errata from IDT available on http://www.idt.com/
+ * in .pdf format.)
+ */
+#undef R4600_V2_HIT_CACHEOP_WAR	/* Not used yet in 64-bit kernel */
+
+#ifdef CONFIG_CPU_R5432
+
+/*
+ * When an interrupt happens on a CP0 register read instruction, CPU may
+ * lock up or read corrupted values of CP0 registers after it enters
+ * the exception handler.
+ *
+ * This workaround makes sure that we read a "safe" CP0 register as the
+ * first thing in the exception handler, which breaks one of the
+ * pre-conditions for this problem.
+ */
+#define	R5432_CP0_INTERRUPT_WAR
+
+#endif
+
+#endif /* _ASM_WAR_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-mips64/wbflush.h linux-2.4.20/include/asm-mips64/wbflush.h
--- linux-2.4.19/include/asm-mips64/wbflush.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-mips64/wbflush.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,18 @@
+/*
+ * Header file for using the wbflush routine
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 1998 Harald Koerfgen
+ * Copyright (C) 2002 Maciej W. Rozycki
+ */
+#ifndef __ASM_MIPS64_WBFLUSH_H
+#define __ASM_MIPS64_WBFLUSH_H
+
+#define wbflush_setup() do { } while (0)
+
+#define wbflush() fast_iob()
+
+#endif /* __ASM_MIPS64_WBFLUSH_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/assembly.h linux-2.4.20/include/asm-parisc/assembly.h
--- linux-2.4.19/include/asm-parisc/assembly.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/assembly.h	2002-10-29 11:18:31.000000000 +0000
@@ -36,17 +36,34 @@
 	gp	=	27
 	ipsw	=	22
 
-#if __PAGE_OFFSET == 0xc0000000
-	.macro	tophys	gr
-	zdep	\gr, 31, 30, \gr
+	/*
+	 * We provide two versions of each macro to convert from physical
+	 * to virtual and vice versa. The "_r1" versions take one argument
+	 * register, but trashes r1 to do the conversion. The other
+	 * version takes two arguments: a src and destination register.
+	 * However, the source and destination registers can not be
+	 * the same register.
+	 */
+
+	.macro  tophys  grvirt, grphys
+	ldil    L%(__PAGE_OFFSET), \grphys
+	sub     \grvirt, \grphys, \grphys
 	.endm
 	
-	.macro	tovirt	gr
-	depi	3,1,2,\gr
+	.macro  tovirt  grphys, grvirt
+	ldil    L%(__PAGE_OFFSET), \grvirt
+	add     \grphys, \grvirt, \grvirt
+	.endm
+
+	.macro  tophys_r1  gr
+	ldil    L%(__PAGE_OFFSET), %r1
+	sub     \gr, %r1, \gr
+	.endm
+	
+	.macro  tovirt_r1  gr
+	ldil    L%(__PAGE_OFFSET), %r1
+	add     \gr, %r1, \gr
 	.endm
-#else
-#error	unknown __PAGE_OFFSET
-#endif
 
 	.macro delay value
 	ldil	L%\value, 1
@@ -59,11 +76,21 @@
 	.macro	debug value
 	.endm
 
-#ifdef __LP64__
-# define LDIL_FIXUP(reg) depdi 0,31,32,reg
-#else
-# define LDIL_FIXUP(reg)
-#endif
+
+	/* Shift Left - note the r and t can NOT be the same! */
+	.macro shl r, sa, t
+	dep,z	\r, 31-\sa, 32-\sa, \t
+	.endm
+
+	/* The PA 2.0 shift left */
+	.macro shlw r, sa, t
+	depw,z	\r, 31-\sa, 32-\sa, \t
+	.endm
+
+	/* And the PA 2.0W shift left */
+	.macro shld r, sa, t
+	depd,z	\r, 63-\sa, 64-\sa, \t
+	.endm
 
 	/* load 32-bit 'value' into 'reg' compensating for the ldil
 	 * sign-extension when running in wide mode.
@@ -72,7 +99,6 @@
 	.macro	load32 value, reg
 	ldil	L%\value, \reg
 	ldo	R%\value(\reg), \reg
-	LDIL_FIXUP(\reg)
 	.endm
 
 #ifdef __LP64__
@@ -89,7 +115,6 @@
 #ifdef __LP64__
 	ldil		L%__gp, %r27
 	ldo		R%__gp(%r27), %r27
-	LDIL_FIXUP(%r27)
 #else
 	ldil		L%$global$, %r27
 	ldo		R%$global$(%r27), %r27
@@ -102,6 +127,7 @@
 #define REST_CR(r, where) LDREG where, %r1 ! mtctl %r1, r
 
 	.macro	save_general	regs
+	STREG %r1, PT_GR1 (\regs)
 	STREG %r2, PT_GR2 (\regs)
 	STREG %r3, PT_GR3 (\regs)
 	STREG %r4, PT_GR4 (\regs)
@@ -126,15 +152,16 @@
 	STREG %r23, PT_GR23(\regs)
 	STREG %r24, PT_GR24(\regs)
 	STREG %r25, PT_GR25(\regs)
-	/* r26 is clobbered by cr19 and assumed to be saved before hand */
+	/* r26 is saved in get_stack and used to preserve a value across virt_map */
 	STREG %r27, PT_GR27(\regs)
 	STREG %r28, PT_GR28(\regs)
-	/* r29 is already saved and points to PT_xxx struct */
+	/* r29 is saved in get_stack and used to point to saved registers */
 	/* r30 stack pointer saved in get_stack */
 	STREG %r31, PT_GR31(\regs)
 	.endm
 
 	.macro	rest_general	regs
+	/* r1 used as a temp in rest_stack and is restored there */
 	LDREG PT_GR2 (\regs), %r2
 	LDREG PT_GR3 (\regs), %r3
 	LDREG PT_GR4 (\regs), %r4
@@ -162,6 +189,7 @@
 	LDREG PT_GR26(\regs), %r26
 	LDREG PT_GR27(\regs), %r27
 	LDREG PT_GR28(\regs), %r28
+	/* r29 points to register save area, and is restored in rest_stack */
 	/* r30 stack pointer restored in rest_stack */
 	LDREG PT_GR31(\regs), %r31
 	.endm
@@ -238,8 +266,8 @@
 
 #ifdef __LP64__
 	.macro	callee_save
-	ldo	144(%r30), %r30
-	std	  %r3,	-144(%r30)
+	std,ma	  %r3,	144(%r30)
+	mfctl	  %cr27, %r3
 	std	  %r4,	-136(%r30)
 	std	  %r5,	-128(%r30)
 	std	  %r6,	-120(%r30)
@@ -255,9 +283,11 @@
 	std	 %r16,	 -40(%r30)
 	std	 %r17,	 -32(%r30)
 	std	 %r18,	 -24(%r30)
+	std	  %r3,	 -16(%r30)
 	.endm
 
 	.macro	callee_rest
+	ldd	 -16(%r30),    %r3
 	ldd	 -24(%r30),   %r18
 	ldd	 -32(%r30),   %r17
 	ldd	 -40(%r30),   %r16
@@ -273,52 +303,54 @@
 	ldd	-120(%r30),    %r6
 	ldd	-128(%r30),    %r5
 	ldd	-136(%r30),    %r4
-	ldd	-144(%r30),    %r3
-	ldo	-144(%r30),   %r30
+	mtctl	%r3, %cr27
+	ldd,mb	-144(%r30),    %r3
 	.endm
 
-#else /* __LP64__ */
+#else /* ! __LP64__ */
 
 	.macro	callee_save
-	ldo	128(30), 30
-	stw	 3,	-128(30)
-	stw	 4,	-124(30)
-	stw	 5,	-120(30)
-	stw	 6,	-116(30)
-	stw	 7,	-112(30)
-	stw	 8,	-108(30)
-	stw	 9,	-104(30)
-	stw	 10,	-100(30)
-	stw	 11,	 -96(30)
-	stw	 12,	 -92(30)
-	stw	 13,	 -88(30)
-	stw	 14,	 -84(30)
-	stw	 15,	 -80(30)
-	stw	 16,	 -76(30)
-	stw	 17,	 -72(30)
-	stw	 18,	 -68(30)
+	stw,ma	 %r3,	128(%r30)
+	mfctl	 %cr27, %r3
+	stw	 %r4,	-124(%r30)
+	stw	 %r5,	-120(%r30)
+	stw	 %r6,	-116(%r30)
+	stw	 %r7,	-112(%r30)
+	stw	 %r8,	-108(%r30)
+	stw	 %r9,	-104(%r30)
+	stw	 %r10,	-100(%r30)
+	stw	 %r11,	 -96(%r30)
+	stw	 %r12,	 -92(%r30)
+	stw	 %r13,	 -88(%r30)
+	stw	 %r14,	 -84(%r30)
+	stw	 %r15,	 -80(%r30)
+	stw	 %r16,	 -76(%r30)
+	stw	 %r17,	 -72(%r30)
+	stw	 %r18,	 -68(%r30)
+	stw	  %r3,	 -64(%r30)
 	.endm
 
 	.macro	callee_rest
-	ldw	 -68(30),   18
-	ldw	 -72(30),   17
-	ldw	 -76(30),   16
-	ldw	 -80(30),   15
-	ldw	 -84(30),   14
-	ldw	 -88(30),   13
-	ldw	 -92(30),   12
-	ldw	 -96(30),   11
-	ldw	-100(30),   10
-	ldw	-104(30),    9
-	ldw	-108(30),    8
-	ldw	-112(30),    7
-	ldw	-116(30),    6
-	ldw	-120(30),    5
-	ldw	-124(30),    4
-	ldw	-128(30),    3
-	ldo	-128(30),   30
+	ldw	 -64(%r30),    %r3
+	ldw	 -68(%r30),   %r18
+	ldw	 -72(%r30),   %r17
+	ldw	 -76(%r30),   %r16
+	ldw	 -80(%r30),   %r15
+	ldw	 -84(%r30),   %r14
+	ldw	 -88(%r30),   %r13
+	ldw	 -92(%r30),   %r12
+	ldw	 -96(%r30),   %r11
+	ldw	-100(%r30),   %r10
+	ldw	-104(%r30),   %r9
+	ldw	-108(%r30),   %r8
+	ldw	-112(%r30),   %r7
+	ldw	-116(%r30),   %r6
+	ldw	-120(%r30),   %r5
+	ldw	-124(%r30),   %r4
+	mtctl	%r3, %cr27
+	ldw,mb	-128(%r30),   %r3
 	.endm
-#endif /* __LP64__ */
+#endif /* ! __LP64__ */
 
 	.macro	save_specials	regs
 
@@ -339,14 +371,25 @@
 	mtctl	 %r0,	%cr18
 	SAVE_CR  (%cr18, PT_IAOQ1(\regs))
 
+#ifdef __LP64__
+	/* cr11 (sar) is a funny one.  5 bits on PA1.1 and 6 bit on PA2.0
+	 * For PA2.0 mtsar or mtctl always write 6 bits, but mfctl only
+	 * reads 5 bits.  Use mfctl,w to read all six bits.  Otherwise
+	 * we loose the 6th bit on a save/restore over interrupt.
+	 */
+	mfctl,w  %cr11, %r1
+	STREG    %r1, PT_SAR (\regs)
+#else
 	SAVE_CR  (%cr11, PT_SAR  (\regs))
-	SAVE_CR  (%cr22, PT_PSW  (\regs))
+#endif
 	SAVE_CR  (%cr19, PT_IIR  (\regs))
-	SAVE_CR  (%cr28, PT_GR1  (\regs))
-	SAVE_CR  (%cr31, PT_GR29 (\regs))
 
-	STREG	%r26,	PT_GR26 (\regs)
-	mfctl	%cr29,	%r26
+	/*
+	 * Code immediately following this macro (in intr_save) relies
+	 * on r8 containing ipsw.
+	 */
+	mfctl    %cr22, %r8
+	STREG    %r8,   PT_PSW(\regs)
 	.endm
 
 	.macro	rest_specials	regs
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/atomic.h linux-2.4.20/include/asm-parisc/atomic.h
--- linux-2.4.19/include/asm-parisc/atomic.h	2000-12-06 19:46:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/atomic.h	2002-10-29 11:18:36.000000000 +0000
@@ -15,10 +15,12 @@
  */
 
 #ifdef CONFIG_SMP
-/* we have an array of spinlocks for our atomic_ts, and a hash function
- * to get the right index */
-#  define ATOMIC_HASH_SIZE 1
-#  define ATOMIC_HASH(a) (&__atomic_hash[0])
+/* Use an array of spinlocks for our atomic_ts.
+** Hash function to index into a different SPINLOCK.
+** Since "a" is usually an address, ">>8" makes one spinlock per 64-bytes.
+*/
+#  define ATOMIC_HASH_SIZE 4
+#  define ATOMIC_HASH(a) (&__atomic_hash[(((unsigned long) a)>>8)&(ATOMIC_HASH_SIZE-1)])
 
 extern spinlock_t __atomic_hash[ATOMIC_HASH_SIZE];
 /* copied from <asm/spinlock.h> and modified */
@@ -44,12 +46,101 @@
 /* Note that we need not lock read accesses - aligned word writes/reads
  * are atomic, so a reader never sees unconsistent values.
  *
- * Cache-line alignment would conflict with, for example, linux/module.h */
+ * Cache-line alignment would conflict with, for example, linux/module.h
+ */
 
 typedef struct {
 	volatile int counter;
 } atomic_t;
 
+
+/*
+** xchg/cmpxchg moved from asm/system.h - ggg
+*/
+
+#if 1
+/* This should get optimized out since it's never called.
+** Or get a link error if xchg is used "wrong".
+*/
+extern void __xchg_called_with_bad_pointer(void);
+#else
+static inline void __xchg_called_with_bad_pointer(void)
+{
+	extern void panic(const char * fmt, ...);
+	panic("xchg called with bad pointer");
+}
+#endif
+
+/* __xchg32/64 defined in arch/parisc/lib/bitops.c */
+extern unsigned long __xchg8(char, char *);
+extern unsigned long __xchg32(int, int *);
+#ifdef __LP64__
+extern unsigned long __xchg64(unsigned long, unsigned long *);
+#endif
+
+/* optimizer better get rid of switch since size is a constant */
+static __inline__ unsigned long __xchg(unsigned long x, __volatile__ void * ptr,
+                                       int size)
+{
+
+	switch(size) {
+#ifdef __LP64__
+	case 8: return __xchg64(x,(unsigned long *) ptr);
+#endif
+	case 4: return __xchg32((int) x, (int *) ptr);
+	case 1: return __xchg8((char) x, (char *) ptr);
+	}
+	__xchg_called_with_bad_pointer();
+	return x;
+}
+
+
+/*
+** REVISIT - Abandoned use of LDCW in xchg() for now:
+** o need to test sizeof(*ptr) to avoid clearing adjacent bytes
+** o and while we are at it, could __LP64__ code use LDCD too?
+**
+**	if (__builtin_constant_p(x) && (x == NULL))
+**		if (((unsigned long)p & 0xf) == 0)
+**			return __ldcw(p);
+*/
+#define xchg(ptr,x) \
+	((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+
+#define __HAVE_ARCH_CMPXCHG	1
+
+/* bug catcher for when unsupported size is used - won't link */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+/* __cmpxchg_u32/u64 defined in arch/parisc/lib/bitops.c */
+extern unsigned long __cmpxchg_u32(volatile unsigned int *m, unsigned int old, unsigned int new_);
+extern unsigned long __cmpxchg_u64(volatile unsigned long *ptr, unsigned long old, unsigned long new_);
+
+/* don't worry...optimizer will get rid of most of this */
+static __inline__ unsigned long
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
+{
+	switch(size) {
+#ifdef __LP64__
+	case 8: return __cmpxchg_u64((unsigned long *)ptr, old, new_);
+#endif
+	case 4: return __cmpxchg_u32((unsigned int *)ptr, (unsigned int) old, (unsigned int) new_);
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg(ptr,o,n)						 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
+
+
+
 /* It's possible to reduce all atomic operations to either
  * __atomic_add_return, __atomic_set and __atomic_ret (the latter
  * is there only for consistency). */
@@ -75,7 +166,7 @@
 
 	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(v), flags);
 }
-	
+
 static __inline__ int __atomic_read(atomic_t *v)
 {
 	return v->counter;
@@ -100,4 +191,9 @@
 
 #define ATOMIC_INIT(i)	{ (i) }
 
+#define smp_mb__before_atomic_dec()	smp_mb()
+#define smp_mb__after_atomic_dec()	smp_mb()
+#define smp_mb__before_atomic_inc()	smp_mb()
+#define smp_mb__after_atomic_inc()	smp_mb()
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/bitops.h linux-2.4.20/include/asm-parisc/bitops.h
--- linux-2.4.19/include/asm-parisc/bitops.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/bitops.h	2002-10-29 11:18:31.000000000 +0000
@@ -6,6 +6,12 @@
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
 
+/*
+ * HP-PARISC specific bit operations
+ * for a detailed description of the functions please refer
+ * to include/asm-i386/bitops.h or kerneldoc
+ */
+
 #ifdef __LP64__
 #   define SHIFT_PER_LONG 6
 #ifndef BITS_PER_LONG
@@ -20,6 +26,69 @@
 
 #define CHOP_SHIFTCOUNT(x) ((x) & (BITS_PER_LONG - 1))
 
+
+#define smp_mb__before_clear_bit()      smp_mb()
+#define smp_mb__after_clear_bit()       smp_mb()
+
+static __inline__ void set_bit(int nr, void * address)
+{
+	unsigned long mask;
+	unsigned long *addr = (unsigned long *) address;
+	unsigned long flags;
+
+	addr += (nr >> SHIFT_PER_LONG);
+	mask = 1L << CHOP_SHIFTCOUNT(nr);
+	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
+	*addr |= mask;
+	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
+}
+
+static __inline__ void __set_bit(int nr, void * address)
+{
+	unsigned long mask;
+	unsigned long *addr = (unsigned long *) address;
+
+	addr += (nr >> SHIFT_PER_LONG);
+	mask = 1L << CHOP_SHIFTCOUNT(nr);
+	*addr |= mask;
+}
+
+static __inline__ void clear_bit(int nr, void * address)
+{
+	unsigned long mask;
+	unsigned long *addr = (unsigned long *) address;
+	unsigned long flags;
+
+	addr += (nr >> SHIFT_PER_LONG);
+	mask = 1L << CHOP_SHIFTCOUNT(nr);
+	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
+	*addr &= ~mask;
+	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
+}
+
+static __inline__ void change_bit(int nr, void * address)
+{
+	unsigned long mask;
+	unsigned long *addr = (unsigned long *) address;
+	unsigned long flags;
+
+	addr += (nr >> SHIFT_PER_LONG);
+	mask = 1L << CHOP_SHIFTCOUNT(nr);
+	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
+	*addr ^= mask;
+	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
+}
+
+static __inline__ void __change_bit(int nr, void * address)
+{
+	unsigned long mask;
+	unsigned long *addr = (unsigned long *) address;
+
+	addr += (nr >> SHIFT_PER_LONG);
+	mask = 1L << CHOP_SHIFTCOUNT(nr);
+	*addr ^= mask;
+}
+
 static __inline__ int test_and_set_bit(int nr, void * address)
 {
 	unsigned long mask;
@@ -28,14 +97,26 @@
 	unsigned long flags;
 
 	addr += (nr >> SHIFT_PER_LONG);
+	mask = 1L << CHOP_SHIFTCOUNT(nr);
 	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
+	oldbit = (*addr & mask) ? 1 : 0;
+	*addr |= mask;
+	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
+
+	return oldbit;
+}
+
+static __inline__ int __test_and_set_bit(int nr, void * address)
+{
+	unsigned long mask;
+	unsigned long *addr = (unsigned long *) address;
+	int oldbit;
 
+	addr += (nr >> SHIFT_PER_LONG);
 	mask = 1L << CHOP_SHIFTCOUNT(nr);
 	oldbit = (*addr & mask) ? 1 : 0;
 	*addr |= mask;
 
-	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
-
 	return oldbit;
 }
 
@@ -47,14 +128,26 @@
 	unsigned long flags;
 
 	addr += (nr >> SHIFT_PER_LONG);
+	mask = 1L << CHOP_SHIFTCOUNT(nr);
 	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
+	oldbit = (*addr & mask) ? 1 : 0;
+	*addr &= ~mask;
+	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
 
+	return oldbit;
+}
+
+static __inline__ int __test_and_clear_bit(int nr, void * address)
+{
+	unsigned long mask;
+	unsigned long *addr = (unsigned long *) address;
+	int oldbit;
+
+	addr += (nr >> SHIFT_PER_LONG);
 	mask = 1L << CHOP_SHIFTCOUNT(nr);
 	oldbit = (*addr & mask) ? 1 : 0;
 	*addr &= ~mask;
 
-	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
-
 	return oldbit;
 }
 
@@ -66,20 +159,30 @@
 	unsigned long flags;
 
 	addr += (nr >> SHIFT_PER_LONG);
-	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
-
 	mask = 1L << CHOP_SHIFTCOUNT(nr);
+	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
 	oldbit = (*addr & mask) ? 1 : 0;
 	*addr ^= mask;
-
 	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
 
 	return oldbit;
 }
 
-/* again, the read-only case doesn't have to do any locking */
+static __inline__ int __test_and_change_bit(int nr, void * address)
+{
+	unsigned long mask;
+	unsigned long *addr = (unsigned long *) address;
+	int oldbit;
 
-static __inline__ int test_bit(int nr, const volatile void *address)
+	addr += (nr >> SHIFT_PER_LONG);
+	mask = 1L << CHOP_SHIFTCOUNT(nr);
+	oldbit = (*addr & mask) ? 1 : 0;
+	*addr ^= mask;
+
+	return oldbit;
+}
+
+static __inline__ int test_bit(int nr, const void *address)
 {
 	unsigned long mask;
 	unsigned long *addr = (unsigned long *) address;
@@ -90,21 +193,12 @@
 	return !!(*addr & mask);
 }
 
-/* sparc does this, other arch's don't -- what's the right answer? XXX */
-#define smp_mb__before_clear_bit()	do { } while(0)
-#define smp_mb__after_clear_bit()	do { } while(0)
-#define set_bit(nr,addr)	((void)test_and_set_bit(nr,addr))
-#define clear_bit(nr,addr)	((void)test_and_clear_bit(nr,addr))
-#define change_bit(nr,addr)	((void)test_and_change_bit(nr,addr))
-
-/* XXX We'd need some binary search here */
-
 extern __inline__ unsigned long ffz(unsigned long word)
 {
 	unsigned long result;
 
 	result = 0;
-	while(word & 1) {
+	while (word & 1) {
 		result++;
 		word >>= 1;
 	}
@@ -182,8 +276,13 @@
  * test_and_{set,clear}_bit guarantee atomicity without
  * disabling interrupts.
  */
+#ifdef __LP64__
+#define ext2_set_bit(nr, addr)		test_and_set_bit((nr) ^ 0x38, addr)
+#define ext2_clear_bit(nr, addr)	test_and_clear_bit((nr) ^ 0x38, addr)
+#else
 #define ext2_set_bit(nr, addr)		test_and_set_bit((nr) ^ 0x18, addr)
 #define ext2_clear_bit(nr, addr)	test_and_clear_bit((nr) ^ 0x18, addr)
+#endif
 
 #endif	/* __KERNEL__ */
 
@@ -239,8 +338,9 @@
 }
 
 /* Bitmap functions for the minix filesystem.  */
-#define minix_set_bit(nr,addr) ext2_set_bit(nr,addr)
-#define minix_clear_bit(nr,addr) ext2_clear_bit(nr,addr)
+#define minix_test_and_set_bit(nr,addr) ext2_set_bit(nr,addr)
+#define minix_set_bit(nr,addr) ((void)ext2_set_bit(nr,addr))
+#define minix_test_and_clear_bit(nr,addr) ext2_clear_bit(nr,addr)
 #define minix_test_bit(nr,addr) ext2_test_bit(nr,addr)
 #define minix_find_first_zero_bit(addr,size) ext2_find_first_zero_bit(addr,size)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/bootdata.h linux-2.4.20/include/asm-parisc/bootdata.h
--- linux-2.4.19/include/asm-parisc/bootdata.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/bootdata.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,16 +0,0 @@
-#ifndef _PARISC_BOOTDATA_H
-#define _PARISC_BOOTDATA_H
-
-/* structure given from bootloader... */
-typedef struct {
-    unsigned 	data_valid_signature,
-		initrd_start,
-		initrd_end;
-    char	commandline[1024];
-} bootdata_t;
-
-#define BOOTDATA_DATA_VALID_SIGNATURE 0xC0400000
-
-#define BOOTDATA_PTR ((bootdata_t*) 0xC0400000)
-
-#endif 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/cache.h linux-2.4.20/include/asm-parisc/cache.h
--- linux-2.4.19/include/asm-parisc/cache.h	2000-12-06 19:46:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/cache.h	2002-10-29 11:18:33.000000000 +0000
@@ -5,27 +5,18 @@
 #ifndef __ARCH_PARISC_CACHE_H
 #define __ARCH_PARISC_CACHE_H
 
+#include <linux/config.h>
+
+#ifndef __ASSEMBLY__
 /*
-** XXX FIXME : L1_CACHE_BYTES (cacheline size) should be a boot time thing.
-** 
-** 32-bit on PA2.0 is not covered well by the #ifdef __LP64__ below.
-** PA2.0 processors have 64-byte cachelines.
-**
-** The issue is mostly cacheline ping-ponging on SMP boxes.
-** To avoid this, code should define stuff to be per CPU on cacheline
-** aligned boundaries. This can make a 2x or more difference in perf
-** depending on how badly the thrashing is.
-**
-** We don't need to worry about I/O since all PA2.0 boxes (except T600)
-** are I/O coherent. That means flushing less than you needed to generally
-** doesn't matter - the I/O MMU will read/modify/write the cacheline.
-**
-** (Digression: it is possible to program I/O MMU's to not first read
-** a cacheline for inbound data - ie just grab ownership and start writing.
-** While it improves I/O throughput, you gotta know the device driver
-** is well behaved and can deal with the issues.)
-*/
-#if defined(__LP64__)
+ * PA 2.0 processors have 64-byte cachelines; PA 1.1 processors have
+ * 32-byte cachelines.  The default configuration is not for SMP anyway,
+ * so if you're building for SMP, you should select the appropriate
+ * processor type.  There is a potential livelock danger when running
+ * a machine with this value set too small, but it's more probable you'll
+ * just ruin performance.
+ */
+#ifdef CONFIG_PA20
 #define L1_CACHE_BYTES 64
 #else
 #define L1_CACHE_BYTES 32
@@ -37,22 +28,47 @@
 
 #define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES)))
 
-extern void init_cache(void);		/* initializes cache-flushing */
-extern void flush_data_cache(void);	/* flushes data-cache only */
-extern void flush_instruction_cache(void);/* flushes code-cache only */
-extern void flush_all_caches(void);	/* flushes code and data-cache */
+extern void flush_data_cache_local(void);  /* flushes local data-cache only */
+extern void flush_instruction_cache_local(void); /* flushes local code-cache only */
+#ifdef CONFIG_SMP
+extern void flush_data_cache(void); /* flushes data-cache only (all processors) */
+#else
+#define flush_data_cache flush_data_cache_local
+#define flush_instruction_cache flush_instruction_cache_local
+#endif
 
+extern void cache_init(void);		/* initializes cache-flushing */
+extern void flush_all_caches(void);     /* flush everything (tlb & cache) */
 extern int get_cache_info(char *);
-
+extern void flush_user_icache_range_asm(unsigned long, unsigned long);
+extern void flush_kernel_icache_range_asm(unsigned long, unsigned long);
+extern void flush_user_dcache_range_asm(unsigned long, unsigned long);
+extern void flush_kernel_dcache_range_asm(unsigned long, unsigned long);
+extern void flush_kernel_dcache_page(void *);
+extern void flush_kernel_icache_page(void *);
+extern void disable_sr_hashing(void);   /* turns off space register hashing */
+extern void disable_sr_hashing_asm(int); /* low level support for above */
+extern void free_sid(unsigned long);
+unsigned long alloc_sid(void);
+
+struct seq_file;
+extern void show_cache_info(struct seq_file *m);
+
+extern int split_tlb;
+extern int dcache_stride;
+extern int icache_stride;
 extern struct pdc_cache_info cache_info;
 
-#define fdce(addr) asm volatile("fdce 0(%0)" : : "r" (addr))
-#define fice(addr) asm volatile("fice 0(%%sr1,%0)" : : "r" (addr))
-
-#define pdtlbe(addr) asm volatile("pdtlbe 0(%%sr1,%0)" : : "r" (addr))
+#define pdtlb(addr)         asm volatile("pdtlb 0(%%sr1,%0)" : : "r" (addr));
+#define pitlb(addr)         asm volatile("pitlb 0(%%sr1,%0)" : : "r" (addr));
 #define pdtlb_kernel(addr)  asm volatile("pdtlb 0(%0)" : : "r" (addr));
-#define pitlbe(addr) asm volatile("pitlbe 0(%%sr1,%0)" : : "r" (addr))
 
-#define kernel_fdc(addr) asm volatile("fdc 0(%%sr0, %0)" : : "r" (addr))
+#endif /* ! __ASSEMBLY__ */
+
+/* Classes of processor wrt: disabling space register hashing */
+
+#define SRHASH_PCXST    0   /* pcxs, pcxt, pcxt_ */
+#define SRHASH_PCXL     1   /* pcxl */
+#define SRHASH_PA20     2   /* pcxu, pcxu_, pcxw, pcxw_ */
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/checksum.h linux-2.4.20/include/asm-parisc/checksum.h
--- linux-2.4.19/include/asm-parisc/checksum.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/checksum.h	2002-10-29 11:18:33.000000000 +0000
@@ -61,32 +61,31 @@
 	unsigned int sum;
 
 
-	__asm__ __volatile__ ("
-	ldws,ma		4(%1), %0
-	addi		-4, %2, %2
-	comib,>=	0, %2, 2f
-	
-	ldws,ma		4(%1), %%r19
-	add		%0, %%r19, %0
-	ldws,ma		4(%1), %%r19
-	addc		%0, %%r19, %0
-	ldws,ma		4(%1), %%r19
-	addc		%0, %%r19, %0
-1:	ldws,ma		4(%1), %%r19
-	addib,<>	-1, %2, 1b
-	addc		%0, %%r19, %0
-	addc		%0, %%r0, %0
-
-	zdepi		-1, 31, 16, %%r19
-	and		%0, %%r19, %%r20
-	extru		%0, 15, 16, %%r21
-	add		%%r20, %%r21, %0
-	and		%0, %%r19, %%r20
-	extru		%0, 15, 16, %%r21
-	add		%%r20, %%r21, %0
-	subi		-1, %0, %0
-2:
-	"
+	__asm__ __volatile__ (
+"	ldws,ma		4(%1), %0\n"
+"	addi		-4, %2, %2\n"
+"	comib,>=	0, %2, 2f\n"
+"\n"
+"	ldws,ma		4(%1), %%r19\n"
+"	add		%0, %%r19, %0\n"
+"	ldws,ma		4(%1), %%r19\n"
+"	addc		%0, %%r19, %0\n"
+"	ldws,ma		4(%1), %%r19\n"
+"	addc		%0, %%r19, %0\n"
+"1:	ldws,ma		4(%1), %%r19\n"
+"	addib,<>	-1, %2, 1b\n"
+"	addc		%0, %%r19, %0\n"
+"	addc		%0, %%r0, %0\n"
+"\n"
+"	zdepi		-1, 31, 16, %%r19\n"
+"	and		%0, %%r19, %%r20\n"
+"	extru		%0, 15, 16, %%r21\n"
+"	add		%%r20, %%r21, %0\n"
+"	and		%0, %%r19, %%r20\n"
+"	extru		%0, 15, 16, %%r21\n"
+"	add		%%r20, %%r21, %0\n"
+"	subi		-1, %0, %0\n"
+"2:\n"
 	: "=r" (sum), "=r" (iph), "=r" (ihl)
 	: "1" (iph), "2" (ihl)
 	: "r19", "r20", "r21" );
@@ -99,9 +98,12 @@
  */
 static inline unsigned int csum_fold(unsigned int sum)
 {
-	sum = (sum & 0xffff) + (sum >> 16);
-	sum = (sum & 0xffff) + (sum >> 16);
-	return ~sum;
+	/* add the swapped two 16-bit halves of sum,
+	   a possible carry from adding the two 16-bit halves,
+	   will carry from the lower half into the upper half,
+	   giving us the correct sum in the upper half. */
+	sum += (sum << 16) + (sum >> 16);
+	return (~sum) >> 16;
 }
  
 static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
@@ -110,11 +112,11 @@
 					       unsigned short proto,
 					       unsigned int sum) 
 {
-	__asm__("
-		add  %1, %0, %0
-		addc %2, %0, %0
-		addc %3, %0, %0
-		addc %%r0, %0, %0 "
+	__asm__(
+	"	add  %1, %0, %0\n"
+	"	addc %2, %0, %0\n"
+	"	addc %3, %0, %0\n"
+	"	addc %%r0, %0, %0\n"
 		: "=r" (sum)
 		: "r" (daddr), "r"(saddr), "r"((proto<<16)+len), "0"(sum));
     return sum;
@@ -141,6 +143,7 @@
 	 return csum_fold (csum_partial(buf, len, 0));
 }
 
+
 #define _HAVE_ARCH_IPV6_CSUM
 static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
 						     struct in6_addr *daddr,
@@ -148,7 +151,62 @@
 						     unsigned short proto,
 						     unsigned int sum) 
 {
-	BUG();
+	__asm__ __volatile__ (
+
+#if BITS_PER_LONG > 32
+
+	/*
+	** We can execute two loads and two adds per cycle on PA 8000.
+	** But add insn's get serialized waiting for the carry bit.
+	** Try to keep 4 registers with "live" values ahead of the ALU.
+	*/
+
+"	ldd,ma		8(%1), %%r19\n"	/* get 1st saddr word */
+"	ldd,ma		8(%2), %%r20\n"	/* get 1st daddr word */
+"	add		%8, %3, %3\n"/* add 16-bit proto + len */
+"	add		%%r19, %0, %0\n"
+"	ldd,ma		8(%1), %%r21\n"	/* 2cd saddr */
+"	ldd,ma		8(%2), %%r22\n"	/* 2cd daddr */
+"	add,dc		%%r20, %0, %0\n"
+"	add,dc		%%r21, %0, %0\n"
+"	add,dc		%%r22, %0, %0\n"
+"	add,dc		%3, %0, %0\n"  /* fold in proto+len | carry bit */
+"	extrd,u		%0, 31, 32, %%r19\n"	/* copy upper half down */
+"	depdi		0, 31, 32, %0\n"	/* clear upper half */
+"	add		%%r19, %0, %0\n"	/* fold into 32-bits */
+"	addc		0, %0, %0\n"		/* add carry */
+
+#else
+
+	/*
+	** For PA 1.x, the insn order doesn't matter as much.
+	** Insn stream is serialized on the carry bit here too.
+	** result from the previous operation (eg r0 + x)
+	*/
+
+"	ldw,ma		4(%1), %%r19\n"	/* get 1st saddr word */
+"	ldw,ma		4(%2), %%r20\n"	/* get 1st daddr word */
+"	add		%8, %3, %3\n"	/* add 16-bit proto + len */
+"	add		%%r19, %0, %0\n"
+"	ldw,ma		4(%1), %%r21\n"	/* 2cd saddr */
+"	addc		%%r20, %0, %0\n"
+"	ldw,ma		4(%2), %%r22\n"	/* 2cd daddr */
+"	addc		%%r21, %0, %0\n"
+"	ldw,ma		4(%1), %%r19\n"	/* 3rd saddr */
+"	addc		%%r22, %0, %0\n"
+"	ldw,ma		4(%2), %%r20\n"	/* 3rd daddr */
+"	addc		%%r19, %0, %0\n"
+"	ldw,ma		4(%1), %%r21\n"	/* 4th saddr */
+"	addc		%%r20, %0, %0\n"
+"	ldw,ma		4(%2), %%r22\n"	/* 4th daddr */
+"	addc		%%r21, %0, %0\n"
+"	addc		%%r22, %0, %0\n"
+"	addc		%3, %0, %0\n"	/* fold in proto+len, catch carry */
+
+#endif
+	: "=r" (sum), "=r" (saddr), "=r" (daddr), "=r" (len)
+	: "0" (sum), "1" (saddr), "2" (daddr), "3" (len), "r" (proto)
+	: "r19", "r20", "r21", "r22");
 	return csum_fold(sum);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/current.h linux-2.4.20/include/asm-parisc/current.h
--- linux-2.4.19/include/asm-parisc/current.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/current.h	2002-10-29 11:18:48.000000000 +0000
@@ -7,11 +7,10 @@
 
 static inline struct task_struct * get_current(void)
 {
-	struct task_struct *current;
+	register unsigned long cr;
 
-	asm("copy 30,%0" : "=r" (current));
-	
-	return (struct task_struct *)((long) current & ~(THREAD_SIZE-1));
+	__asm__ __volatile__("mfctl %%cr30,%0" : "=r" (cr) );
+	return (struct task_struct *)cr;
 }
  
 #define current get_current()
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/delay.h linux-2.4.20/include/asm-parisc/delay.h
--- linux-2.4.19/include/asm-parisc/delay.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/delay.h	2002-10-29 11:18:40.000000000 +0000
@@ -11,13 +11,11 @@
  * Delay routines
  */
 
-extern unsigned long loops_per_sec;
-
 static __inline__ void __delay(unsigned long loops) {
 	asm volatile(
-	"	.balignl	64,0x34000034
-		addib,UV -1,%0,.
-		nop"
+	"	.balignl	64,0x34000034\n"
+	"	addib,UV -1,%0,.\n"
+	"	nop\n"
 		: "=r" (loops) : "0" (loops));
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/dma.h linux-2.4.20/include/asm-parisc/dma.h
--- linux-2.4.19/include/asm-parisc/dma.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/dma.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,192 @@
+/* $Id: dma.h,v 1.2 1999/04/27 00:46:18 deller Exp $
+ * linux/include/asm/dma.h: Defines for using and allocating dma channels.
+ * Written by Hennus Bergman, 1992.
+ * High DMA channel support & info by Hannu Savolainen
+ * and John Boyd, Nov. 1992.
+ * (c) Copyright 2000, Grant Grundler
+ */
+
+#ifndef _ASM_DMA_H
+#define _ASM_DMA_H
+
+#include <linux/config.h>
+#include <asm/io.h>		/* need byte IO */
+#include <asm/system.h>	
+
+#define dma_outb	outb
+#define dma_inb		inb
+
+/*
+** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up
+** (or rather not merge) DMA's into managable chunks.
+** On parisc, this is more of the software/tuning constraint
+** rather than the HW. I/O MMU allocation alogorithms can be
+** faster with smaller size is (to some degree).
+*/
+#define DMA_CHUNK_SIZE	(BITS_PER_LONG*PAGE_SIZE)
+
+/* The maximum address that we can perform a DMA transfer to on this platform
+** New dynamic DMA interfaces should obsolete this....
+*/
+#define MAX_DMA_ADDRESS (~0UL)
+
+
+/*
+** We don't have DMA channels... well V-class does but the
+** Dynamic DMA Mapping interface will support them... right? :^)
+** Note: this is not relevant right now for PA-RISC, but we cannot 
+** leave this as undefined because some things (e.g. sound)
+** won't compile :-(
+*/
+#define MAX_DMA_CHANNELS 8
+#define DMA_MODE_READ    1
+#define DMA_MODE_WRITE   2
+#define DMA_AUTOINIT     0x10
+
+/* 8237 DMA controllers */
+#define IO_DMA1_BASE	0x00	/* 8 bit slave DMA, channels 0..3 */
+#define IO_DMA2_BASE	0xC0	/* 16 bit master DMA, ch 4(=slave input)..7 */
+
+/* DMA controller registers */
+#define DMA1_CMD_REG		0x08	/* command register (w) */
+#define DMA1_STAT_REG		0x08	/* status register (r) */
+#define DMA1_REQ_REG            0x09    /* request register (w) */
+#define DMA1_MASK_REG		0x0A	/* single-channel mask (w) */
+#define DMA1_MODE_REG		0x0B	/* mode register (w) */
+#define DMA1_CLEAR_FF_REG	0x0C	/* clear pointer flip-flop (w) */
+#define DMA1_TEMP_REG           0x0D    /* Temporary Register (r) */
+#define DMA1_RESET_REG		0x0D	/* Master Clear (w) */
+#define DMA1_CLR_MASK_REG       0x0E    /* Clear Mask */
+#define DMA1_MASK_ALL_REG       0x0F    /* all-channels mask (w) */
+#define DMA1_EXT_MODE_REG	(0x400 | DMA1_MODE_REG)
+
+#define DMA2_CMD_REG		0xD0	/* command register (w) */
+#define DMA2_STAT_REG		0xD0	/* status register (r) */
+#define DMA2_REQ_REG            0xD2    /* request register (w) */
+#define DMA2_MASK_REG		0xD4	/* single-channel mask (w) */
+#define DMA2_MODE_REG		0xD6	/* mode register (w) */
+#define DMA2_CLEAR_FF_REG	0xD8	/* clear pointer flip-flop (w) */
+#define DMA2_TEMP_REG           0xDA    /* Temporary Register (r) */
+#define DMA2_RESET_REG		0xDA	/* Master Clear (w) */
+#define DMA2_CLR_MASK_REG       0xDC    /* Clear Mask */
+#define DMA2_MASK_ALL_REG       0xDE    /* all-channels mask (w) */
+#define DMA2_EXT_MODE_REG	(0x400 | DMA2_MODE_REG)
+
+extern spinlock_t dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&dma_spin_lock, flags);
+	return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+	spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
+
+
+/* Get DMA residue count. After a DMA transfer, this
+ * should return zero. Reading this while a DMA transfer is
+ * still in progress will return unpredictable results.
+ * If called before the channel has been used, it may return 1.
+ * Otherwise, it returns the number of _bytes_ left to transfer.
+ *
+ * Assumes DMA flip-flop is clear.
+ */
+static __inline__ int get_dma_residue(unsigned int dmanr)
+{
+	unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
+					 : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;
+
+	/* using short to get 16-bit wrap around */
+	unsigned short count;
+
+	count = 1 + dma_inb(io_port);
+	count += dma_inb(io_port) << 8;
+	
+	return (dmanr<=3)? count : (count<<1);
+}
+
+/* enable/disable a specific DMA channel */
+static __inline__ void enable_dma(unsigned int dmanr)
+{
+#ifdef CONFIG_SUPERIO
+	if (dmanr<=3)
+		dma_outb(dmanr,  DMA1_MASK_REG);
+	else
+		dma_outb(dmanr & 3,  DMA2_MASK_REG);
+#endif
+}
+
+static __inline__ void disable_dma(unsigned int dmanr)
+{
+#ifdef CONFIG_SUPERIO
+	if (dmanr<=3)
+		dma_outb(dmanr | 4,  DMA1_MASK_REG);
+	else
+		dma_outb((dmanr & 3) | 4,  DMA2_MASK_REG);
+#endif
+}
+
+/* Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ * Use this once to initialize the FF to a known state.
+ * After that, keep track of it. :-)
+ * --- In order to do that, the DMA routines below should ---
+ * --- only be used while holding the DMA lock ! ---
+ */
+static __inline__ void clear_dma_ff(unsigned int dmanr)
+{
+}
+
+/* set mode (above) for a specific DMA channel */
+static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
+{
+}
+
+/* Set only the page register bits of the transfer address.
+ * This is used for successive transfers when we know the contents of
+ * the lower 16 bits of the DMA current address register, but a 64k boundary
+ * may have been crossed.
+ */
+static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
+{
+}
+
+
+/* Set transfer address & page bits for specific DMA channel.
+ * Assumes dma flipflop is clear.
+ */
+static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
+{
+}
+
+
+/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for
+ * a specific DMA channel.
+ * You must ensure the parameters are valid.
+ * NOTE: from a manual: "the number of transfers is one more
+ * than the initial word count"! This is taken into account.
+ * Assumes dma flip-flop is clear.
+ * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7.
+ */
+static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
+{
+}
+
+
+
+/* These are in kernel/dma.c: */
+extern int request_dma(unsigned int dmanr, const char * device_id);	/* reserve a DMA channel */
+extern void free_dma(unsigned int dmanr);	/* release it again */
+extern int get_dma_list(char *buf);		/* proc/dma support  */
+
+#ifdef CONFIG_PCI
+extern int isa_dma_bridge_buggy;
+#else
+#define isa_dma_bridge_buggy 	(0)
+#endif
+
+#endif /* _ASM_DMA_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/eisa_bus.h linux-2.4.20/include/asm-parisc/eisa_bus.h
--- linux-2.4.19/include/asm-parisc/eisa_bus.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/eisa_bus.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,23 @@
+/*
+ * eisa_bus.h interface between the eisa BA driver and the bus enumerator
+ *
+ * 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.
+ *
+ * Copyright (c) 2002 Daniel Engstrom <5116@telia.com>
+ *
+ */
+
+#ifndef ASM_EISA_H
+#define ASM_EISA_H
+
+extern void eisa_make_irq_level(int num);
+extern void eisa_make_irq_edge(int num);
+extern int eisa_enumerator(unsigned long eeprom_addr,
+			   struct resource *io_parent, 
+			   struct resource *mem_parent);
+extern int eisa_eeprom_init(unsigned long addr);
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/eisa_eeprom.h linux-2.4.20/include/asm-parisc/eisa_eeprom.h
--- linux-2.4.19/include/asm-parisc/eisa_eeprom.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/eisa_eeprom.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,151 @@
+/*
+ * eisa_eeprom.h - provide support for EISA adapters in PA-RISC machines
+ *
+ * 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.
+ *
+ * Copyright (c) 2001, 2002 Daniel Engstrom <5116@telia.com>
+ *
+ */
+
+#ifndef ASM_EISA_EEPROM_H
+#define ASM_EISA_EEPROM_H
+
+#define HPEE_MAX_LENGTH       0x2000	/* maximum eeprom length */
+
+#define HPEE_SLOT_INFO(slot) (20+(48*slot))
+
+struct eeprom_header 
+{
+   
+	u_int32_t num_writes;       /* number of writes */
+ 	u_int8_t  flags;            /* flags, usage? */
+	u_int8_t  ver_maj;
+	u_int8_t  ver_min;
+	u_int8_t  num_slots;        /* number of EISA slots in system */
+	u_int16_t csum;             /* checksum, I dont know how to calulate this */
+	u_int8_t  pad[10];
+} __attribute__ ((packed));
+
+
+struct eeprom_eisa_slot_info
+{
+	u_int32_t eisa_slot_id;
+	u_int32_t config_data_offset;
+	u_int32_t num_writes;
+	u_int16_t csum;
+	u_int16_t num_functions;
+	u_int16_t config_data_length;
+	
+	/* bits 0..3 are the duplicate slot id */ 
+#define HPEE_SLOT_INFO_EMBEDDED  0x10
+#define HPEE_SLOT_INFO_VIRTUAL   0x20
+#define HPEE_SLOT_INFO_NO_READID 0x40
+#define HPEE_SLOT_INFO_DUPLICATE 0x80
+	u_int8_t slot_info;
+	
+#define HPEE_SLOT_FEATURES_ENABLE         0x01
+#define HPEE_SLOT_FEATURES_IOCHK          0x02
+#define HPEE_SLOT_FEATURES_CFG_INCOMPLETE 0x80
+	u_int8_t slot_features;
+	
+	u_int8_t  ver_min;
+	u_int8_t  ver_maj;
+	
+#define HPEE_FUNCTION_INFO_HAVE_TYPE      0x01
+#define HPEE_FUNCTION_INFO_HAVE_MEMORY    0x02
+#define HPEE_FUNCTION_INFO_HAVE_IRQ       0x04
+#define HPEE_FUNCTION_INFO_HAVE_DMA       0x08
+#define HPEE_FUNCTION_INFO_HAVE_PORT      0x10
+#define HPEE_FUNCTION_INFO_HAVE_PORT_INIT 0x20
+/* I think there are two slighty different 
+ * versions of the function_info field 
+ * one int the fixed header and one optional 
+ * in the parsed slot data area */
+#define HPEE_FUNCTION_INFO_HAVE_FUNCTION  0x01
+#define HPEE_FUNCTION_INFO_F_DISABLED     0x80
+#define HPEE_FUNCTION_INFO_CFG_FREE_FORM  0x40
+	u_int8_t  function_info;
+
+#define HPEE_FLAG_BOARD_IS_ISA		  0x01 /* flag and minor version for isa board */
+	u_int8_t  flags;
+	u_int8_t  pad[24];
+} __attribute__ ((packed));
+
+
+#define HPEE_MEMORY_MAX_ENT   9
+/* memory descriptor: byte 0 */
+#define HPEE_MEMORY_WRITABLE  0x01
+#define HPEE_MEMORY_CACHABLE  0x02
+#define HPEE_MEMORY_TYPE_MASK 0x18
+#define HPEE_MEMORY_TYPE_SYS  0x00
+#define HPEE_MEMORY_TYPE_EXP  0x08
+#define HPEE_MEMORY_TYPE_VIR  0x10
+#define HPEE_MEMORY_TYPE_OTH  0x18
+#define HPEE_MEMORY_SHARED    0x20
+#define HPEE_MEMORY_MORE      0x80
+
+/* memory descriptor: byte 1 */
+#define HPEE_MEMORY_WIDTH_MASK 0x03
+#define HPEE_MEMORY_WIDTH_BYTE 0x00
+#define HPEE_MEMORY_WIDTH_WORD 0x01
+#define HPEE_MEMORY_WIDTH_DWORD 0x02
+#define HPEE_MEMORY_DECODE_MASK 0x0c
+#define HPEE_MEMORY_DECODE_20BITS 0x00
+#define HPEE_MEMORY_DECODE_24BITS 0x04
+#define HPEE_MEMORY_DECODE_32BITS 0x08
+/* byte 2 and 3 are a 16bit LE value
+ * containging the memory size in kilobytes */
+/* byte 4,5,6 are a 24bit LE value
+ * containing the memory base address */
+
+
+#define HPEE_IRQ_MAX_ENT      7
+/* Interrupt entry: byte 0 */
+#define HPEE_IRQ_CHANNEL_MASK 0xf
+#define HPEE_IRQ_TRIG_LEVEL   0x20
+#define HPEE_IRQ_MORE         0x80
+/* byte 1 seems to be unused */
+
+#define HPEE_DMA_MAX_ENT     4
+
+/* dma entry: byte 0 */
+#define HPEE_DMA_CHANNEL_MASK 7
+#define HPEE_DMA_SIZE_MASK	0xc
+#define HPEE_DMA_SIZE_BYTE	0x0
+#define HPEE_DMA_SIZE_WORD	0x4
+#define HPEE_DMA_SIZE_DWORD	0x8
+#define HPEE_DMA_SHARED      0x40
+#define HPEE_DMA_MORE        0x80
+
+/* dma entry: byte 1 */
+#define HPEE_DMA_TIMING_MASK 0x30
+#define HPEE_DMA_TIMING_ISA	0x0
+#define HPEE_DMA_TIMING_TYPEA 0x10
+#define HPEE_DMA_TIMING_TYPEB 0x20
+#define HPEE_DMA_TIMING_TYPEC 0x30
+
+#define HPEE_PORT_MAX_ENT 20
+/* port entry byte 0 */
+#define HPEE_PORT_SIZE_MASK 0x1f
+#define HPEE_PORT_SHARED    0x40
+#define HPEE_PORT_MORE      0x80
+/* byte 1 and 2 is a 16bit LE value
+ * conating the start port number */
+
+#define HPEE_PORT_INIT_MAX_LEN     60 /* in bytes here */
+/* port init entry byte 0 */
+#define HPEE_PORT_INIT_WIDTH_MASK  0x3
+#define HPEE_PORT_INIT_WIDTH_BYTE  0x0
+#define HPEE_PORT_INIT_WIDTH_WORD  0x1
+#define HPEE_PORT_INIT_WIDTH_DWORD 0x2
+#define HPEE_PORT_INIT_MASK        0x4
+#define HPEE_PORT_INIT_MORE        0x80
+
+#define HPEE_SELECTION_MAX_ENT 26
+
+#define HPEE_TYPE_MAX_LEN    80
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/elf.h linux-2.4.20/include/asm-parisc/elf.h
--- linux-2.4.19/include/asm-parisc/elf.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/elf.h	2002-10-29 11:18:49.000000000 +0000
@@ -9,19 +9,13 @@
 
 #define EM_PARISC 15
 
-#define ELF_NGREG 32
-#define ELF_NFPREG 32
-
-typedef unsigned long elf_greg_t;
-typedef elf_greg_t elf_gregset_t[ELF_NGREG];
-
-typedef double elf_fpreg_t;
-typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
-
-#define ELF_CORE_COPY_REGS(gregs, regs) \
-	memcpy(gregs, regs, \
-	       sizeof(struct pt_regs) < sizeof(elf_gregset_t)? \
-	       sizeof(struct pt_regs): sizeof(elf_gregset_t));
+/*
+ * The following definitions are those for 32-bit ELF binaries on a 32-bit kernel
+ * and for 64-bit binaries on a 64-bit kernel.  To run 32-bit binaries on a 64-bit
+ * kernel, arch/parisc64/kernel/binfmt_elf32.c defines these macros appropriately
+ * and then #includes binfmt_elf.c, which then includes this file.
+ */
+#ifndef ELF_CLASS
 
 /*
  * This is used to ensure we don't load something for the wrong architecture.
@@ -30,16 +24,84 @@
  * the following macros are for the default case. However, for the 64
  * bit kernel we also support 32 bit parisc binaries. To do that
  * arch/parisc64/kernel/binfmt_elf32.c defines its own set of these
- * macros, and then if includes fs/binfmt_elf.c to provide an alternate
+ * macros, and then it includes fs/binfmt_elf.c to provide an alternate
  * elf binary handler for 32 bit binaries (on the 64 bit kernel).
  */
-
 #ifdef __LP64__
 #define ELF_CLASS       ELFCLASS64
 #else
 #define ELF_CLASS	ELFCLASS32
 #endif
 
+typedef unsigned long elf_greg_t;
+
+/* This yields a string that ld.so will use to load implementation
+   specific libraries for optimization.  This is more specific in
+   intent than poking at uname or /proc/cpuinfo.
+
+   For the moment, we have only optimizations for the Intel generations,
+   but that could change... */
+
+#define ELF_PLATFORM  ("PARISC\0" /*+((boot_cpu_data.x86-3)*5) */)
+
+#ifdef __KERNEL__
+#define SET_PERSONALITY(ex, ibcs2) \
+	current->personality = PER_LINUX
+#endif
+
+/*
+ * Fill in general registers in a core dump.  This saves pretty
+ * much the same registers as hp-ux, although in a different order.
+ * Registers marked # below are not currently saved in pt_regs, so
+ * we use their current values here.
+ *
+ * 	gr0..gr31
+ * 	sr0..sr7
+ * 	iaoq0..iaoq1
+ * 	iasq0..iasq1
+ * 	cr11 (sar)
+ * 	cr19 (iir)
+ * 	cr20 (isr)
+ * 	cr21 (ior)
+ *  #	cr22 (ipsw)
+ *  #	cr0 (recovery counter)
+ *  #	cr24..cr31 (temporary registers)
+ *  #	cr8,9,12,13 (protection IDs)
+ *  #	cr10 (scr/ccr)
+ *  #	cr15 (ext int enable mask)
+ *
+ */
+
+#define ELF_CORE_COPY_REGS(dst, pt)	\
+	memset(dst, 0, sizeof(dst));	/* don't leak any "random" bits */ \
+	memcpy(dst + 0, pt->gr, 32 * sizeof(elf_greg_t)); \
+	memcpy(dst + 32, pt->sr, 8 * sizeof(elf_greg_t)); \
+	memcpy(dst + 40, pt->iaoq, 2 * sizeof(elf_greg_t)); \
+	memcpy(dst + 42, pt->iasq, 2 * sizeof(elf_greg_t)); \
+	dst[44] = pt->sar;   dst[45] = pt->iir; \
+	dst[46] = pt->isr;   dst[47] = pt->ior; \
+	dst[48] = mfctl(22); dst[49] = mfctl(0); \
+	dst[50] = mfctl(24); dst[51] = mfctl(25); \
+	dst[52] = mfctl(26); dst[53] = mfctl(27); \
+	dst[54] = mfctl(28); dst[55] = mfctl(29); \
+	dst[56] = mfctl(30); dst[57] = mfctl(31); \
+	dst[58] = mfctl( 8); dst[59] = mfctl( 9); \
+	dst[60] = mfctl(12); dst[61] = mfctl(13); \
+	dst[62] = mfctl(10); dst[63] = mfctl(15);
+
+#endif /* ! ELF_CLASS */
+
+#define ELF_NGREG 80	/* We only need 64 at present, but leave space
+			   for expansion. */
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+#define ELF_NFPREG 32
+typedef double elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+struct pt_regs;	/* forward declaration... */
+
+
 #define elf_check_arch(x) ((x)->e_machine == EM_PARISC && (x)->e_ident[EI_CLASS] == ELF_CLASS)
 
 /*
@@ -80,18 +142,4 @@
 #define ELF_HWCAP	0
 /* (boot_cpu_data.x86_capability) */
 
-/* This yields a string that ld.so will use to load implementation
-   specific libraries for optimization.  This is more specific in
-   intent than poking at uname or /proc/cpuinfo.
-
-   For the moment, we have only optimizations for the Intel generations,
-   but that could change... */
-
-#define ELF_PLATFORM  ("PARISC\0" /*+((boot_cpu_data.x86-3)*5) */)
-
-#ifdef __KERNEL__
-#define SET_PERSONALITY(ex, ibcs2) \
-	current->personality = PER_LINUX
-#endif
-
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/fcntl.h linux-2.4.20/include/asm-parisc/fcntl.h
--- linux-2.4.19/include/asm-parisc/fcntl.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/fcntl.h	2002-10-29 11:18:48.000000000 +0000
@@ -24,6 +24,7 @@
 #define O_DIRECT	00040000 /* direct disk access hint - currently ignored */
 #define O_DIRECTORY	00010000 /* must be a directory */
 #define O_NOFOLLOW	00000200 /* don't follow links */
+#define O_INVISIBLE	04000000 /* invisible I/O, for DMAPI/XDSM */
 
 #define F_DUPFD		0	/* dup */
 #define F_GETFD		1	/* get f_flags */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/fixmap.h linux-2.4.20/include/asm-parisc/fixmap.h
--- linux-2.4.19/include/asm-parisc/fixmap.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/fixmap.h	2002-10-29 11:18:48.000000000 +0000
@@ -1,8 +1,12 @@
 #ifndef _ASM_FIXMAP_H
 #define _ASM_FIXMAP_H
 
-#define FIXADDR_TOP	(0xffffe000UL)
-#define FIXADDR_SIZE	(0 << PAGE_SHIFT)
-#define FIXADDR_START	(FIXADDR_TOP - FIXADDR_SIZE)
+/*
+ * Allocate a 8 Mb temporary mapping area for copy_user_page/clear_user_page.
+ * This area needs to be aligned on a 8 Mb boundary.
+ */
+
+#define TMPALIAS_MAP_START (__PAGE_OFFSET - 0x01000000)
+#define FIXADDR_START   ((unsigned long)TMPALIAS_MAP_START)
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/floppy.h linux-2.4.20/include/asm-parisc/floppy.h
--- linux-2.4.19/include/asm-parisc/floppy.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/floppy.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,266 @@
+/*
+ * Architecture specific parts of the Floppy driver
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1995
+ */
+#ifndef __ASM_PARISC_FLOPPY_H
+#define __ASM_PARISC_FLOPPY_H
+
+#include <linux/vmalloc.h>
+
+
+/*
+ * The DMA channel used by the floppy controller cannot access data at
+ * addresses >= 16MB
+ *
+ * Went back to the 1MB limit, as some people had problems with the floppy
+ * driver otherwise. It doesn't matter much for performance anyway, as most
+ * floppy accesses go through the track buffer.
+ */
+#define _CROSS_64KB(a,s,vdma) \
+(!vdma && ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64))
+
+#define CROSS_64KB(a,s) _CROSS_64KB(a,s,use_virtual_dma & 1)
+
+
+#define SW fd_routine[use_virtual_dma&1]
+#define CSW fd_routine[can_use_virtual_dma & 1]
+
+
+#define fd_inb(port)			inb_p(port)
+#define fd_outb(port,value)		outb_p(port,value)
+
+#define fd_request_dma()        CSW._request_dma(FLOPPY_DMA,"floppy")
+#define fd_free_dma()           CSW._free_dma(FLOPPY_DMA)
+#define fd_enable_irq()         enable_irq(FLOPPY_IRQ)
+#define fd_disable_irq()        disable_irq(FLOPPY_IRQ)
+#define fd_free_irq()		free_irq(FLOPPY_IRQ, NULL)
+#define fd_get_dma_residue()    SW._get_dma_residue(FLOPPY_DMA)
+#define fd_dma_mem_alloc(size)	SW._dma_mem_alloc(size)
+#define fd_dma_setup(addr, size, mode, io) SW._dma_setup(addr, size, mode, io)
+
+#define FLOPPY_CAN_FALLBACK_ON_NODMA
+
+static int virtual_dma_count=0;
+static int virtual_dma_residue=0;
+static char *virtual_dma_addr=0;
+static int virtual_dma_mode=0;
+static int doing_pdma=0;
+
+static void floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
+{
+	register unsigned char st;
+
+#undef TRACE_FLPY_INT
+#define NO_FLOPPY_ASSEMBLER
+
+#ifdef TRACE_FLPY_INT
+	static int calls=0;
+	static int bytes=0;
+	static int dma_wait=0;
+#endif
+	if(!doing_pdma) {
+		floppy_interrupt(irq, dev_id, regs);
+		return;
+	}
+
+#ifdef TRACE_FLPY_INT
+	if(!calls)
+		bytes = virtual_dma_count;
+#endif
+
+	{
+		register int lcount;
+		register char *lptr;
+
+		st = 1;
+		for(lcount=virtual_dma_count, lptr=virtual_dma_addr; 
+		    lcount; lcount--, lptr++) {
+			st=inb(virtual_dma_port+4) & 0xa0 ;
+			if(st != 0xa0) 
+				break;
+			if(virtual_dma_mode)
+				outb_p(*lptr, virtual_dma_port+5);
+			else
+				*lptr = inb_p(virtual_dma_port+5);
+		}
+		virtual_dma_count = lcount;
+		virtual_dma_addr = lptr;
+		st = inb(virtual_dma_port+4);
+	}
+
+#ifdef TRACE_FLPY_INT
+	calls++;
+#endif
+	if(st == 0x20)
+		return;
+	if(!(st & 0x20)) {
+		virtual_dma_residue += virtual_dma_count;
+		virtual_dma_count=0;
+#ifdef TRACE_FLPY_INT
+		printk("count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n", 
+		       virtual_dma_count, virtual_dma_residue, calls, bytes,
+		       dma_wait);
+		calls = 0;
+		dma_wait=0;
+#endif
+		doing_pdma = 0;
+		floppy_interrupt(irq, dev_id, regs);
+		return;
+	}
+#ifdef TRACE_FLPY_INT
+	if(!virtual_dma_count)
+		dma_wait++;
+#endif
+}
+
+static void fd_disable_dma(void)
+{
+	if(! (can_use_virtual_dma & 1))
+		disable_dma(FLOPPY_DMA);
+	doing_pdma = 0;
+	virtual_dma_residue += virtual_dma_count;
+	virtual_dma_count=0;
+}
+
+static int vdma_request_dma(unsigned int dmanr, const char * device_id)
+{
+	return 0;
+}
+
+static void vdma_nop(unsigned int dummy)
+{
+}
+
+
+static int vdma_get_dma_residue(unsigned int dummy)
+{
+	return virtual_dma_count + virtual_dma_residue;
+}
+
+
+static int fd_request_irq(void)
+{
+	if(can_use_virtual_dma)
+		return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
+						   "floppy", NULL);
+	else
+		return request_irq(FLOPPY_IRQ, floppy_interrupt,
+						   SA_INTERRUPT|SA_SAMPLE_RANDOM,
+						   "floppy", NULL);	
+
+}
+
+static unsigned long dma_mem_alloc(unsigned long size)
+{
+	return __get_dma_pages(GFP_KERNEL,__get_order(size));
+}
+
+
+static unsigned long vdma_mem_alloc(unsigned long size)
+{
+	return (unsigned long) vmalloc(size);
+
+}
+
+#define nodma_mem_alloc(size) vdma_mem_alloc(size)
+
+static void _fd_dma_mem_free(unsigned long addr, unsigned long size)
+{
+	if((unsigned int) addr >= (unsigned int) high_memory)
+		return vfree((void *)addr);
+	else
+		free_pages(addr, __get_order(size));		
+}
+
+#define fd_dma_mem_free(addr, size)  _fd_dma_mem_free(addr, size) 
+
+static void _fd_chose_dma_mode(char *addr, unsigned long size)
+{
+	if(can_use_virtual_dma == 2) {
+		if((unsigned int) addr >= (unsigned int) high_memory ||
+		   virt_to_bus(addr) >= 0x1000000 ||
+		   _CROSS_64KB(addr, size, 0))
+			use_virtual_dma = 1;
+		else
+			use_virtual_dma = 0;
+	} else {
+		use_virtual_dma = can_use_virtual_dma & 1;
+	}
+}
+
+#define fd_chose_dma_mode(addr, size) _fd_chose_dma_mode(addr, size)
+
+
+static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
+{
+	doing_pdma = 1;
+	virtual_dma_port = io;
+	virtual_dma_mode = (mode  == DMA_MODE_WRITE);
+	virtual_dma_addr = addr;
+	virtual_dma_count = size;
+	virtual_dma_residue = 0;
+	return 0;
+}
+
+static int hard_dma_setup(char *addr, unsigned long size, int mode, int io)
+{
+#ifdef FLOPPY_SANITY_CHECK
+	if (CROSS_64KB(addr, size)) {
+		printk("DMA crossing 64-K boundary %p-%p\n", addr, addr+size);
+		return -1;
+	}
+#endif
+	/* actual, physical DMA */
+	doing_pdma = 0;
+	clear_dma_ff(FLOPPY_DMA);
+	set_dma_mode(FLOPPY_DMA,mode);
+	set_dma_addr(FLOPPY_DMA,virt_to_bus(addr));
+	set_dma_count(FLOPPY_DMA,size);
+	enable_dma(FLOPPY_DMA);
+	return 0;
+}
+
+struct fd_routine_l {
+	int (*_request_dma)(unsigned int dmanr, const char * device_id);
+	void (*_free_dma)(unsigned int dmanr);
+	int (*_get_dma_residue)(unsigned int dummy);
+	unsigned long (*_dma_mem_alloc) (unsigned long size);
+	int (*_dma_setup)(char *addr, unsigned long size, int mode, int io);
+} fd_routine[] = {
+	{
+		request_dma,
+		free_dma,
+		get_dma_residue,
+		dma_mem_alloc,
+		hard_dma_setup
+	},
+	{
+		vdma_request_dma,
+		vdma_nop,
+		vdma_get_dma_residue,
+		vdma_mem_alloc,
+		vdma_dma_setup
+	}
+};
+
+
+static int FDC1 = 0x3f0;
+static int FDC2 = -1;
+
+#define FLOPPY0_TYPE	((CMOS_READ(0x10) >> 4) & 15)
+#define FLOPPY1_TYPE	(CMOS_READ(0x10) & 15)
+
+#define N_FDC 1
+#define N_DRIVE 8
+
+#define FLOPPY_MOTOR_MASK 0xf0
+
+#define AUTO_DMA
+
+
+#endif /* __ASM_PARISC_FLOPPY_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/grfioctl.h linux-2.4.20/include/asm-parisc/grfioctl.h
--- linux-2.4.19/include/asm-parisc/grfioctl.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/grfioctl.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,95 @@
+/*
+ * Architecture specific parts of HP's STI (framebuffer) driver
+ * structures are HP-UX compatible for XFree86 usage 
+ */ 
+
+#ifndef __ASM_PARISC_GRFIOCTL_H
+#define __ASM_PARISC_GRFIOCTL_H
+
+/* upper 32 bits of graphics id (HP/UX identifier) */
+
+#define GRFGATOR		8
+#define S9000_ID_S300		9
+#define GRFBOBCAT		9
+#define	GRFCATSEYE		9
+#define S9000_ID_98720		10
+#define GRFRBOX			10
+#define S9000_ID_98550		11
+#define GRFFIREEYE		11
+#define S9000_ID_A1096A		12
+#define GRFHYPERION		12
+#define S9000_ID_FRI		13
+#define S9000_ID_98730		14
+#define GRFDAVINCI		14
+#define S9000_ID_98705		0x26C08070	/* Tigershark */
+#define S9000_ID_98736		0x26D148AB
+#define S9000_ID_A1659A		0x26D1482A	/* CRX 8 plane color (=ELK) */
+#define S9000_ID_ELK		S9000_ID_A1659A
+#define S9000_ID_A1439A		0x26D148EE	/* CRX24 = CRX+ (24-plane color) */
+#define S9000_ID_A1924A		0x26D1488C	/* GRX gray-scale */
+#define S9000_ID_ELM		S9000_ID_A1924A
+#define S9000_ID_98765		0x27480DEF
+#define S9000_ID_ELK_768	0x27482101
+#define S9000_ID_STINGER	0x27A4A402
+#define S9000_ID_TIMBER		0x27F12392	/* Bushmaster (710) Graphics */
+#define S9000_ID_TOMCAT		0x27FCCB6D	/* dual-headed ELK (Dual CRX) */
+#define S9000_ID_ARTIST		0x2B4DED6D	/* Artist (Gecko/712 & 715) onboard Graphics */
+#define S9000_ID_HCRX		0x2BCB015A	/* Hyperdrive/Hyperbowl (A4071A) Graphics */
+#define CRX24_OVERLAY_PLANES	0x920825AA	/* Overlay planes on CRX24 */
+
+#define CRT_ID_ELK_1024		S9000_ID_ELK_768 /* Elk 1024x768  CRX */
+#define CRT_ID_ELK_1280		S9000_ID_A1659A	/* Elk 1280x1024 CRX */
+#define CRT_ID_ELK_1024DB	0x27849CA5      /* Elk 1024x768 double buffer */
+#define CRT_ID_ELK_GS		S9000_ID_A1924A	/* Elk 1280x1024 GreyScale    */
+#define CRT_ID_CRX24		S9000_ID_A1439A	/* Piranha */
+#define CRT_ID_VISUALIZE_EG	0x2D08C0A7      /* Graffiti (built-in B132+/B160L) */
+#define CRT_ID_THUNDER		0x2F23E5FC      /* Thunder 1 VISUALIZE 48*/
+#define CRT_ID_THUNDER2		0x2F8D570E      /* Thunder 2 VISUALIZE 48 XP*/
+#define CRT_ID_HCRX		S9000_ID_HCRX	/* Hyperdrive HCRX */
+#define CRT_ID_CRX48Z		S9000_ID_STINGER /* Stinger */
+#define CRT_ID_DUAL_CRX		S9000_ID_TOMCAT	/* Tomcat */
+#define CRT_ID_PVRX		S9000_ID_98705	/* Tigershark */
+#define CRT_ID_TIMBER		S9000_ID_TIMBER	/* Timber (710 builtin) */
+#define CRT_ID_TVRX		S9000_ID_98765	/* TVRX (gto/falcon) */
+#define CRT_ID_ARTIST		S9000_ID_ARTIST	/* Artist */
+#define CRT_ID_SUMMIT		0x2FC1066B      /* Summit FX2, FX4, FX6 ... */
+
+/* structure for ioctl(GCDESCRIBE) */
+
+#define gaddr_t unsigned long	/* FIXME: PA2.0 (64bit) portable ? */
+
+struct	grf_fbinfo {
+	unsigned int	id;		/* upper 32 bits of graphics id */
+	unsigned int	mapsize;	/* mapped size of framebuffer */
+	unsigned int	dwidth, dlength;/* x and y sizes */
+	unsigned int	width, length;	/* total x and total y size */
+	unsigned int	xlen;		/* x pitch size */
+	unsigned int	bpp, bppu;	/* bits per pixel and used bpp */
+	unsigned int	npl, nplbytes;	/* # of planes and bytes per plane */
+	char		name[32];	/* name of the device (from ROM) */
+	unsigned int	attr;		/* attributes */
+	gaddr_t 	fbbase, regbase;/* framebuffer and register base addr */
+	gaddr_t		regions[6];	/* region bases */
+};
+
+#define	GCID		_IOR('G', 0, int)
+#define	GCON		_IO('G', 1)
+#define	GCOFF		_IO('G', 2)
+#define	GCAON		_IO('G', 3)
+#define	GCAOFF		_IO('G', 4)
+#define	GCMAP		_IOWR('G', 5, int)
+#define	GCUNMAP		_IOWR('G', 6, int)
+#define	GCMAP_HPUX	_IO('G', 5)
+#define	GCUNMAP_HPUX	_IO('G', 6)
+#define	GCLOCK		_IO('G', 7)
+#define	GCUNLOCK	_IO('G', 8)
+#define	GCLOCK_MINIMUM	_IO('G', 9)
+#define	GCUNLOCK_MINIMUM _IO('G', 10)
+#define	GCSTATIC_CMAP	_IO('G', 11)
+#define	GCVARIABLE_CMAP _IO('G', 12)
+#define GCTERM		_IOWR('G',20,int)	/* multi-headed Tomcat */ 
+#define GCDESCRIBE	_IOR('G', 21, struct grf_fbinfo)
+#define GCFASTLOCK	_IO('G', 26)
+
+#endif /* __ASM_PARISC_GRFIOCTL_H */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/gsc.h linux-2.4.20/include/asm-parisc/gsc.h
--- linux-2.4.19/include/asm-parisc/gsc.h	2000-12-06 19:46:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/gsc.h	2002-10-29 11:18:49.000000000 +0000
@@ -3,49 +3,17 @@
 #ifdef __KERNEL__
 
 #include <linux/types.h>
-#include <asm/hardware.h>	/* for struct hp_device */
+#include <asm/io.h> /* temporary for __raw_{read,write} */
 
-/*
- * The convention used for inb/outb etc. is that names starting with
- * two underscores are the inline versions, names starting with a
- * single underscore are proper functions, and names starting with a
- * letter are macros that map in some way to inline or proper function
- * versions.  Not all that pretty, but before you change it, be sure
- * to convince yourself that it won't break anything (in particular
- * module support).
+/* Please, call ioremap and use {read,write}[bwl] instead.  These functions
+ * are not very fast.
  */
-extern   u8 _gsc_readb(void *);
-extern  u16 _gsc_readw(void *);
-extern  u32 _gsc_readl(void *);
-extern  u64 _gsc_readq(void *);
-extern void _gsc_writeb(u8, void *);
-extern void _gsc_writew(u16,void *);
-extern void _gsc_writel(u32,void *);
-extern void _gsc_writeq(u64,void *);
-
-#define gsc_readb(a)	_gsc_readb((void *)(a))
-#define gsc_readw(a)	_gsc_readw((void *)(a))
-#define gsc_readl(a)	_gsc_readl((void *)(a))
-#define gsc_readq(a)	_gsc_readq((void *)(a))
-#define gsc_writeb(v,a)	_gsc_writeb((v),(void *)(a))
-#define gsc_writew(v,a)	_gsc_writew((v),(void *)(a))
-#define gsc_writel(v,a)	_gsc_writel((v),(void *)(a))
-#define gsc_writeq(v,a)	_gsc_writeq((v),(void *)(a))
-
-struct gsc_dev {
-	struct gsc_bus	*bus;		/* bus this device is on */
-	struct gsc_dev	*next;		/* chain of all devices */
-	struct gsc_dev	*next_bus;	/* chain of all devices on a bus */
-	struct gsc_dev	*next_submod;	/* chain of all devices on a module */
-
-	unsigned	irq;		/* irq generated by this device */
-	void		*hpa;		/* hard physical address */
-
-	u16		hversion;
-	u8		spa;		/* SPA requirements */
-	u8		type;
-	u32		sversion;
-};
+#define gsc_readb(x) __raw_readb((unsigned long)x)
+#define gsc_readw(x) __raw_readw((unsigned long)x)
+#define gsc_readl(x) __raw_readl((unsigned long)x)
+#define gsc_writeb(x, y) __raw_writeb(x, (unsigned long)y)
+#define gsc_writew(x, y) __raw_writew(x, (unsigned long)y)
+#define gsc_writel(x, y) __raw_writel(x, (unsigned long)y)
 
 struct gsc_irq {
 	unsigned long txn_addr;	/* IRQ "target" */
@@ -59,21 +27,7 @@
 extern int gsc_alloc_irq(struct gsc_irq *dev);	/* dev needs an irq */
 extern int gsc_claim_irq(struct gsc_irq *dev, int irq);	/* dev needs this irq */
 
-struct gsc_bus {
-	void		*hpa;		/* HPA of device 0, function 0 of this bus */
-};
-
-/*
- * There is one gsc_dev structure for each slot-number/function-number
- * combination:
- */
-
-struct gsc_dev *gsc_find_device(u16 hversion, struct gsc_dev *from);
-
 extern void probe_serial_gsc(void);
 
-/* returns a virtual irq for device at dev->hpa (works for all LASI/ASP/WAX) */
-extern int busdevice_alloc_irq( struct hp_device *dev );
-
 #endif /* __KERNEL__ */
 #endif /* LINUX_GSC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/hardirq.h linux-2.4.20/include/asm-parisc/hardirq.h
--- linux-2.4.19/include/asm-parisc/hardirq.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/hardirq.h	2002-10-29 11:18:50.000000000 +0000
@@ -1,21 +1,29 @@
-/* hardirq.h: 32-bit Sparc hard IRQ support.
+/* hardirq.h: PA-RISC hard IRQ support.
  *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998-99 Anton Blanchard (anton@progsoc.uts.edu.au)
+ * Copyright (C) 2001 Matthew Wilcox <matthew@wil.cx>
+ *
+ * The locking is really quite interesting.  There's a cpu-local
+ * count of how many interrupts are being handled, and a global
+ * lock.  An interrupt can only be serviced if the global lock
+ * is free.  You can't be sure no more interrupts are being
+ * serviced until you've acquired the lock and then checked
+ * all the per-cpu interrupt counts are all zero.  It's a specialised
+ * br_lock, and that's exactly how Sparc does it.  We don't because
+ * it's more locking for us.  This way is lock-free in the interrupt path.
  */
 
-#ifndef __PARISC_HARDIRQ_H
-#define __PARISC_HARDIRQ_H
+#ifndef _PARISC_HARDIRQ_H
+#define _PARISC_HARDIRQ_H
 
 #include <linux/config.h>
 #include <linux/threads.h>
 
 typedef struct {
-	unsigned int __softirq_active;
-	unsigned int __softirq_mask;
+	unsigned long __softirq_pending; /* set_bit is used on this */
 	unsigned int __local_irq_count;
 	unsigned int __local_bh_count;
 	unsigned int __syscall_count;
+	struct task_struct * __ksoftirqd_task;
 } ____cacheline_aligned irq_cpustat_t;
 
 #include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
@@ -42,14 +50,24 @@
 
 #else
 
+#include <asm/system.h>
 #include <asm/atomic.h>
 #include <linux/spinlock.h>
-#include <asm/system.h>
 #include <asm/smp.h>
 
-extern unsigned char global_irq_holder;
+extern int global_irq_holder;
 extern spinlock_t global_irq_lock;
-extern atomic_t global_irq_count;
+
+static inline int irqs_running (void)
+{
+	int i;
+
+	for (i = 0; i < smp_num_cpus; i++)
+		if (local_irq_count(i))
+			return 1;
+	return 0;
+}
+
 
 static inline void release_irqlock(int cpu)
 {
@@ -60,22 +78,22 @@
 	}
 }
 
-static inline void irq_enter(int cpu)
+static inline void irq_enter(int cpu, int irq)
 {
 	++local_irq_count(cpu);
-	atomic_inc(&global_irq_count);
+
+	while (spin_is_locked(&global_irq_lock))
+		barrier();
 }
 
-static inline void irq_exit(int cpu)
+static inline void irq_exit(int cpu, int irq)
 {
-	atomic_dec(&global_irq_count);
 	--local_irq_count(cpu);
 }
 
 static inline int hardirq_trylock(int cpu)
 {
-	return (! atomic_read(&global_irq_count) &&
-		! spin_is_locked (&global_irq_lock));
+	return !local_irq_count(cpu) && !spin_is_locked (&global_irq_lock);
 }
 
 #define hardirq_endlock(cpu)	do { } while (0)
@@ -84,4 +102,4 @@
 
 #endif /* CONFIG_SMP */
 
-#endif /* __PARISC_HARDIRQ_H */
+#endif /* _PARISC_HARDIRQ_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/hardware.h linux-2.4.20/include/asm-parisc/hardware.h
--- linux-2.4.19/include/asm-parisc/hardware.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/hardware.h	2002-10-29 11:18:34.000000000 +0000
@@ -1,35 +1,51 @@
-#ifndef _PARISC_HP_MACHINES_H_ 
-#define _PARISC_HP_MACHINES_H_ 
+#ifndef _PARISC_HARDWARE_H
+#define _PARISC_HARDWARE_H
 
-struct hp_hardware {
-	unsigned short hw_type:5;		/* HPHW_xxx */
-	unsigned short hversion;
-	unsigned long  sversion:28;
-	unsigned short opt;
-	char *name; 
+#include <asm/pdc.h>
+
+struct parisc_device_id {
+	unsigned char	hw_type;	/* 5 bits used */
+	unsigned char	hversion_rev;	/* 4 bits */
+	unsigned short	hversion;	/* 12 bits */
+	unsigned int	sversion;	/* 20 bits */
 };
 
-struct hp_device {
-	unsigned short hw_type:5;	/* HPHW_xxx */
-	unsigned short hversion;	/* HP-UX uses  hv_model:12 */
-	unsigned int   sversion;	/* HP-UX uses sv_model:20 sv_opt:8 */
-	unsigned short opt;
-	unsigned int hversion_rev;
-	unsigned int sversion_rev;
-	struct hp_hardware * reference;  /* This is a pointer to the
-                                            reference */
-	unsigned int managed; /* this is if the device has a driver for it */
-	void * hpa;
+#define HWTYPE_ANY_ID	0xff
+#define HVERSION_REV_ANY_ID	0xff
+#define HVERSION_ANY_ID	0xffff
+#define SVERSION_ANY_ID	0xffffffffU
+
+struct hp_hardware {
+	unsigned short	hw_type:5;	/* HPHW_xxx */
+	unsigned short	hversion;
+	unsigned long	sversion:28;
+	unsigned short	opt;
+	const char	name[80];	/* The hardware description */
+};
 
+struct parisc_device {
+	unsigned long   hpa;		/* Hard Physical Address */
+	struct parisc_device_id id;
+	struct parisc_device *parent;
+	struct parisc_device *sibling;
+	struct parisc_device *child;
+	struct parisc_driver *driver;	/* Driver for this device */
+	void		*sysdata;	/* Driver instance private data */
+	char		name[80];	/* The hardware description */
+	int		irq;
+
+	char		hw_path;        /* The module number on this bus */
+	unsigned int	num_addrs;	/* some devices have additional address ranges. */
+	unsigned long	*addr;          /* which will be stored here */
+ 
 #ifdef __LP64__
 	/* parms for pdc_pat_cell_module() call */
-	unsigned long  pcell_loc;	/* Physical Cell location */
-	unsigned long  mod_index;	/* PAT specific - Misc Module info */
+	unsigned long	pcell_loc;	/* Physical Cell location */
+	unsigned long	mod_index;	/* PAT specific - Misc Module info */
 
 	/* generic info returned from pdc_pat_cell_module() */
-	unsigned long  mod_info;	/* PAT specific - Misc Module info */
-	unsigned long  pmod_loc;	/* physical Module location */
-	unsigned long  mod_path;	/* Module HW path */
+	unsigned long	mod_info;	/* PAT specific - Misc Module info */
+	unsigned long	pmod_loc;	/* physical Module location */
 #endif
 };
 
@@ -43,33 +59,56 @@
 	pcxu	= 6, /* pa8000		pa 2.0  */
 	pcxu_	= 7, /* pa8200	(u+)	pa 2.0  */
 	pcxw	= 8, /* pa8500		pa 2.0  */
-	pcxw_	= 9  /* pa8600	(w+)	pa 2.0  */
+	pcxw_	= 9, /* pa8600	(w+)	pa 2.0  */
+	pcxw2	= 10 /* pa8700		pa 2.0  */
 };
 
 extern char *cpu_name_version[][2]; /* mapping from enum cpu_type to strings */
 
-struct pa_iodc_driver {
-	unsigned short hw_type:5;		/* HPHW_xxx */
-	unsigned short hversion;
-	unsigned short hversion_rev;
-	unsigned long  sversion:28;
-	unsigned short sversion_rev;
-	unsigned short opt;
-	unsigned int check;  /* Components that are significant */
+struct parisc_driver {
+	struct parisc_driver *next;
 	char *name; 
-	char *version; 
-	int (* callback)(struct hp_device *d, struct pa_iodc_driver *dri);
+	const struct parisc_device_id *id_table;
+	int (*probe) (struct parisc_device *dev); /* New device discovered */
 };
 
-#define DRIVER_CHECK_HWTYPE          1
-#define DRIVER_CHECK_HVERSION        2
-#define DRIVER_CHECK_SVERSION        4
-#define DRIVER_CHECK_OPT             8
-/* The following two are useless right now */
-#define DRIVER_CHECK_HVERSION_REV   16
-#define DRIVER_CHECK_SVERSION_REV   32
-#define DRIVER_CHECK_EVERYTHING     63
+struct io_module {
+        volatile uint32_t nothing;		/* reg 0 */
+        volatile uint32_t io_eim;
+        volatile uint32_t io_dc_adata;
+        volatile uint32_t io_ii_cdata;
+        volatile uint32_t io_dma_link;		/* reg 4 */
+        volatile uint32_t io_dma_command;
+        volatile uint32_t io_dma_address;
+        volatile uint32_t io_dma_count;
+        volatile uint32_t io_flex;		/* reg 8 */
+        volatile uint32_t io_spa_address;
+        volatile uint32_t reserved1[2];
+        volatile uint32_t io_command;		/* reg 12 */
+        volatile uint32_t io_status;
+        volatile uint32_t io_control;
+        volatile uint32_t io_data;
+        volatile uint32_t reserved2;		/* reg 16 */
+        volatile uint32_t chain_addr;
+        volatile uint32_t sub_mask_clr;
+        volatile uint32_t reserved3[13];
+        volatile uint32_t undefined[480];
+        volatile uint32_t unpriv[512];
+};
 
+struct bc_module {
+        volatile uint32_t unused1[12];
+        volatile uint32_t io_command;
+        volatile uint32_t io_status;
+        volatile uint32_t io_control;
+        volatile uint32_t unused2[1];
+        volatile uint32_t io_err_resp;
+        volatile uint32_t io_err_info;
+        volatile uint32_t io_err_req;
+        volatile uint32_t unused3[11];
+        volatile uint32_t io_io_low;
+        volatile uint32_t io_io_high;
+};
 
 #define HPHW_NPROC     0 
 #define HPHW_MEMORY    1       
@@ -88,16 +127,33 @@
 #define HPHW_FABRIC    14
 #define HPHW_FAULTY    31
 
-extern struct hp_hardware hp_hardware_list[];
-
-char *parisc_getHWtype(	unsigned short hw_type );
 
-/* Attention: first hversion, then sversion...! */
-char *parisc_getHWdescription(	unsigned short hw_type,
-                                unsigned long hversion,  /* have to be long ! */
-				unsigned long sversion );
+/* hardware.c: */
+extern const char *parisc_hardware_description(struct parisc_device_id *id);
+extern enum cpu_type parisc_get_cpu_type(unsigned long hversion);
+
+struct pci_dev;
+
+/* drivers.c: */
+extern struct parisc_device *alloc_pa_dev(unsigned long hpa,
+		struct hardware_path *path);
+extern int register_parisc_device(struct parisc_device *dev);
+extern int register_parisc_driver(struct parisc_driver *driver);
+extern int count_parisc_driver(struct parisc_driver *driver);
+extern int unregister_parisc_driver(struct parisc_driver *driver);
+extern void walk_central_bus(void);
+extern void fixup_child_irqs(struct parisc_device *parent, int irqbase,
+		int (*choose)(struct parisc_device *parent));
+extern void print_subdevices(struct parisc_device *dev);
+extern const struct parisc_device *find_pa_parent_type(const struct parisc_device *, int);
+extern void print_parisc_devices(void);
+extern char *print_pa_hwpath(struct parisc_device *dev, char *path);
+extern char *print_pci_hwpath(struct pci_dev *dev, char *path);
+extern void get_pci_node_path(struct pci_dev *dev, struct hardware_path *path);
+
+
+/* inventory.c: */
+extern void do_memory_inventory(void);
+extern void do_device_inventory(void);
 
-enum cpu_type parisc_get_cpu_type( unsigned long hversion );
-
-extern int register_driver(struct pa_iodc_driver *driver);
-#endif
+#endif /* _PARISC_HARDWARE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/hil.h linux-2.4.20/include/asm-parisc/hil.h
--- linux-2.4.19/include/asm-parisc/hil.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/hil.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,26 +0,0 @@
-#ifndef _ASM_HIL_H
-#define _ASM_HIL_H
-
-/*
- *	linux/asm-parisc/hil.h
- *
- *	(c) 1999 Matthew Wilcox
- */
-
-extern unsigned long hil_base;	/* declared in drivers/gsc/hil.c */
-extern unsigned int hil_irq;
-
-#define HILBASE			hil_base /* 0xf0821000 (old) or 0xf0201000 (new) */
-#define HIL_DATA		0x800
-#define HIL_CMD			0x801
-
-#define HIL_IRQ			hil_irq
-
-#define hil_busy()		(gsc_readb(HILBASE + HIL_CMD) & HIL_BUSY)
-#define hil_data_available()	(gsc_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY)
-#define hil_status()		(gsc_readb(HILBASE + HIL_CMD))
-#define hil_command(x)		do { gsc_writeb((x), HILBASE + HIL_CMD); } while (0)
-#define hil_read_data()		(gsc_readb(HILBASE + HIL_DATA))
-#define hil_write_data(x)	do { gsc_writeb((x), HILBASE + HIL_DATA); } while (0)
-
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/ide.h linux-2.4.20/include/asm-parisc/ide.h
--- linux-2.4.19/include/asm-parisc/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/ide.h	2002-10-29 11:18:37.000000000 +0000
@@ -5,31 +5,29 @@
  */
 
 /*
- *  This file contains the i386 architecture specific IDE code.
+ *  This file contains the PARISC architecture specific IDE code.
  */
 
-#ifndef __ASMi386_IDE_H
-#define __ASMi386_IDE_H
+#ifndef __ASM_PARISC_IDE_H
+#define __ASM_PARISC_IDE_H
 
 #ifdef __KERNEL__
 
 #include <linux/config.h>
+#include <asm/superio.h>
 
 #ifndef MAX_HWIFS
-#define MAX_HWIFS	10
+#define MAX_HWIFS	2
 #endif
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
-		case 0x1f0: return 14;
-		case 0x170: return 15;
-		case 0x1e8: return 11;
-		case 0x168: return 10;
-		case 0x1e0: return 8;
-		case 0x160: return 12;
+#ifdef CONFIG_SUPERIO
+		case 0x1f0: 
+		case 0x170:
+			return superio_get_ide_irq();
+#endif /* CONFIG_SUPERIO */
 		default:
 			return 0;
 	}
@@ -38,12 +36,10 @@
 static __inline__ ide_ioreg_t ide_default_io_base(int index)
 {
 	switch (index) {
-		case 0:	return 0x1f0;
-		case 1:	return 0x170;
-		case 2: return 0x1e8;
-		case 3: return 0x168;
-		case 4: return 0x1e0;
-		case 5: return 0x160;
+#ifdef CONFIG_SUPERIO 
+		case 0:	return (superio_get_ide_irq() ? 0x1f0 : 0);
+		case 1:	return (superio_get_ide_irq() ? 0x170 : 0);
+#endif /* CONFIG_SUPERIO */
 		default:
 			return 0;
 	}
@@ -65,6 +61,7 @@
 	}
 	if (irq != NULL)
 		*irq = 0;
+	hw->io_ports[IDE_IRQ_OFFSET] = 0;
 }
 
 static __inline__ void ide_init_default_hwifs(void)
@@ -81,43 +78,94 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
 #define ide_check_region(from,extent)		check_region((from), (extent))
 #define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
 #define ide_release_region(from,extent)		release_region((from), (extent))
 
+#define T_CHAR          (0x0000)        /* char:  don't touch  */
+#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
+#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
+#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
+
+#define T_MASK_TYPE     (0xc000)
+#define T_MASK_COUNT    (0x3fff)
+
+#define D_CHAR(cnt)     (T_CHAR  | (cnt))
+#define D_SHORT(cnt)    (T_SHORT | (cnt))
+#define D_INT(cnt)      (T_INT   | (cnt))
+#define D_TEXT(cnt)     (T_TEXT  | (cnt))
+
+static u_short driveid_types[] = {
+	D_SHORT(10),	/* config - vendor2 */
+	D_TEXT(20),	/* serial_no */
+	D_SHORT(3),	/* buf_type - ecc_bytes */
+	D_TEXT(48),	/* fw_rev - model */
+	D_CHAR(2),	/* max_multsect - vendor3 */
+	D_SHORT(1),	/* dword_io */
+	D_CHAR(2),	/* vendor4 - capability */
+	D_SHORT(1),	/* reserved50 */
+	D_CHAR(4),	/* vendor5 - tDMA */
+	D_SHORT(4),	/* field_valid - cur_sectors */
+	D_INT(1),	/* cur_capacity */
+	D_CHAR(2),	/* multsect - multsect_valid */
+	D_INT(1),	/* lba_capacity */
+	D_SHORT(194)	/* dma_1word - reservedyy */
+};
+
+#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
+
+static __inline__ void ide_fix_driveid(struct hd_driveid *id)
+{
+	u_char *p = (u_char *)id;
+	int i, j, cnt;
+	u_char t;
+
+	for (i = 0; i < num_driveid_types; i++) {
+		cnt = driveid_types[i] & T_MASK_COUNT;
+		switch (driveid_types[i] & T_MASK_TYPE) {
+		case T_CHAR:
+			p += cnt;
+			break;
+		case T_SHORT:
+			for (j = 0; j < cnt; j++) {
+				t = p[0];
+				p[0] = p[1];
+				p[1] = t;
+				p += 2;
+			}
+			break;
+		case T_INT:
+			for (j = 0; j < cnt; j++) {
+				t = p[0];
+				p[0] = p[3];
+				p[3] = t;
+				t = p[1];
+				p[1] = p[2];
+				p[2] = t;
+				p += 4;
+			}
+			break;
+		case T_TEXT:
+			for (j = 0; j < cnt; j += 2) {
+				t = p[0];
+				p[0] = p[1];
+				p[1] = t;
+				p += 2;
+			}
+			break;
+		};
+	}
+}
+
 /*
  * The following are not needed for the non-m68k ports
  */
 #define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
 #endif /* __KERNEL__ */
 
-#endif /* __ASMi386_IDE_H */
+#endif /* __ASM_PARISC_IDE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/io.h linux-2.4.20/include/asm-parisc/io.h
--- linux-2.4.19/include/asm-parisc/io.h	2000-12-06 19:46:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/io.h	2002-10-29 11:18:33.000000000 +0000
@@ -1,15 +1,195 @@
 #ifndef _ASM_IO_H
 #define _ASM_IO_H
 
+/* USE_HPPA_IOREMAP IS THE MAGIC FLAG TO ENABLE OR DISABLE REAL IOREMAP() FUNCTIONALITY */
+/* FOR 712 or 715 MACHINES THIS SHOULD BE ENABLED, 
+   NEWER MACHINES STILL HAVE SOME ISSUES IN THE SCSI AND/OR NETWORK DRIVERS AND 
+   BECAUSE OF THAT I WILL LEAVE IT DISABLED FOR NOW <deller@gmx.de> */
+/* WHEN THOSE ISSUES ARE SOLVED, USE_HPPA_IOREMAP WILL GO AWAY */
+#define USE_HPPA_IOREMAP 0
+
+
 #include <linux/config.h>
 #include <linux/types.h>
-#include <asm/gsc.h>
+#include <asm/pgtable.h>
 
 #define virt_to_phys(a) ((unsigned long)__pa(a))
 #define phys_to_virt(a) __va(a)
 #define virt_to_bus virt_to_phys
 #define bus_to_virt phys_to_virt
 
+/* Memory mapped IO */
+
+extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+
+extern inline void * ioremap(unsigned long offset, unsigned long size)
+{
+	return __ioremap(offset, size, 0);
+}
+
+/*
+ * This one maps high address device memory and turns off caching for that area.
+ * it's useful if some control registers are in such an area and write combining
+ * or read caching is not desirable:
+ */
+extern inline void * ioremap_nocache (unsigned long offset, unsigned long size)
+{
+        return __ioremap(offset, size, _PAGE_NO_CACHE /* _PAGE_PCD */);
+}
+
+extern void iounmap(void *addr);
+
+/*
+ * __raw_ variants have no defined meaning.  on hppa, it means `i was
+ * too lazy to ioremap first'.  kind of like isa_, except that there's
+ * no additional base address to add on.
+ */
+extern __inline__ unsigned char __raw_readb(unsigned long addr)
+{
+	long flags;
+	unsigned char ret;
+
+	__asm__ __volatile__(
+	"	rsm	2,%0\n"
+	"	ldbx	0(%2),%1\n"
+	"	mtsm	%0\n"
+	: "=&r" (flags), "=r" (ret) : "r" (addr) );
+
+	return ret;
+}
+
+extern __inline__ unsigned short __raw_readw(unsigned long addr)
+{
+	long flags;
+	unsigned short ret;
+
+	__asm__ __volatile__(
+	"	rsm	2,%0\n"
+	"	ldhx	0(%2),%1\n"
+	"	mtsm	%0\n"
+	: "=&r" (flags), "=r" (ret) : "r" (addr) );
+
+	return ret;
+}
+
+extern __inline__ unsigned int __raw_readl(unsigned long addr)
+{
+	u32 ret;
+
+	__asm__ __volatile__(
+	"	ldwax	0(%1),%0\n"
+	: "=r" (ret) : "r" (addr) );
+
+	return ret;
+}
+
+extern __inline__ unsigned long long __raw_readq(unsigned long addr)
+{
+	unsigned long long ret;
+#ifdef __LP64__
+	__asm__ __volatile__(
+	"	ldda	0(%1),%0\n"
+	:  "=r" (ret) : "r" (addr) );
+#else
+	/* two reads may have side effects.. */
+	ret = ((u64) __raw_readl(addr)) << 32;
+	ret |= __raw_readl(addr+4);
+#endif
+	return ret;
+}
+
+extern __inline__ void __raw_writeb(unsigned char val, unsigned long addr)
+{
+	long flags;
+	__asm__ __volatile__(
+	"	rsm	2,%0\n"
+	"	stbs	%1,0(%2)\n"
+	"	mtsm	%0\n"
+	: "=&r" (flags) :  "r" (val), "r" (addr) );
+}
+
+extern __inline__ void __raw_writew(unsigned short val, unsigned long addr)
+{
+	long flags;
+	__asm__ __volatile__(
+	"	rsm	2,%0\n"
+	"	sths	%1,0(%2)\n"
+	"	mtsm	%0\n"
+	: "=&r" (flags) :  "r" (val), "r" (addr) );
+}
+
+extern __inline__ void __raw_writel(unsigned int val, unsigned long addr)
+{
+	__asm__ __volatile__(
+	"	stwas	%0,0(%1)\n"
+	: :  "r" (val), "r" (addr) );
+}
+
+extern __inline__ void __raw_writeq(unsigned long long val, unsigned long addr)
+{
+#ifdef __LP64__
+	__asm__ __volatile__(
+	"	stda	%0,0(%1)\n"
+	: :  "r" (val), "r" (addr) );
+#else
+	/* two writes may have side effects.. */
+	__raw_writel(val >> 32, addr);
+	__raw_writel(val, addr+4);
+#endif
+}
+
+#if USE_HPPA_IOREMAP
+#define readb(addr) (*(volatile unsigned char *) (addr))
+#define readw(addr) (*(volatile unsigned short *) (addr))
+#define readl(addr) (*(volatile unsigned int *) (addr))
+#define readq(addr) (*(volatile u64 *) (addr))
+#define writeb(b,addr) (*(volatile unsigned char *) (addr) = (b))
+#define writew(b,addr) (*(volatile unsigned short *) (addr) = (b))
+#define writel(b,addr) (*(volatile unsigned int *) (addr) = (b))
+#define writeq(b,addr) (*(volatile u64 *) (addr) = (b))
+#else /* !USE_HPPA_IOREMAP */
+#define readb(addr) __raw_readb((unsigned long)(addr))
+#define readw(addr) le16_to_cpu(__raw_readw((unsigned long)(addr)))
+#define readl(addr) le32_to_cpu(__raw_readl((unsigned long)(addr)))
+#define readq(addr) le64_to_cpu(__raw_readq((unsigned long)(addr)))
+#define writeb(b,addr) __raw_writeb(b,(unsigned long)(addr))
+#define writew(b,addr) __raw_writew(cpu_to_le16(b),(unsigned long)(addr))
+#define writel(b,addr) __raw_writel(cpu_to_le32(b),(unsigned long)(addr))
+#define writeq(b,addr) __raw_writeq(cpu_to_le64(b),(unsigned long)(addr))
+#endif /* !USE_HPPA_IOREMAP */
+
+extern void memcpy_fromio(void *dest, unsigned long src, int count);
+extern void memcpy_toio(unsigned long dest, const void *src, int count);
+extern void memset_io(unsigned long dest, char fill, int count);
+
+/* Support old drivers which don't ioremap.
+ * NB this interface is scheduled to disappear in 2.5
+ */
+
+#define EISA_BASE 0xfffffffffc000000UL
+#define isa_readb(a) readb(EISA_BASE | (a))
+#define isa_readw(a) readw(EISA_BASE | (a))
+#define isa_readl(a) readl(EISA_BASE | (a))
+#define isa_writeb(b,a) writeb((b), EISA_BASE | (a))
+#define isa_writew(b,a) writew((b), EISA_BASE | (a))
+#define isa_writel(b,a) writel((b), EISA_BASE | (a))
+#define isa_memset_io(a,b,c) memset_io(EISA_BASE | (a), (b), (c))
+#define isa_memcpy_fromio(a,b,c) memcpy_fromio((a), EISA_BASE | (b), (c))
+#define isa_memcpy_toio(a,b,c) memcpy_toio(EISA_BASE | (a), (b), (c))
+
+/*
+ * XXX - We don't have csum_partial_copy_fromio() yet, so we cheat here and 
+ * just copy it. The net code will then do the checksum later. Presently 
+ * only used by some shared memory 8390 Ethernet cards anyway.
+ */
+
+#define eth_io_copy_and_sum(skb,src,len,unused) \
+  memcpy_fromio((skb)->data,(src),(len))
+#define isa_eth_io_copy_and_sum(skb,src,len,unused) \
+  isa_memcpy_fromio((skb)->data,(src),(len))
+
+/* Port-space IO */
+
 #define inb_p inb
 #define inw_p inw
 #define inl_p inl
@@ -17,42 +197,66 @@
 #define outw_p outw
 #define outl_p outl
 
-#define readb gsc_readb
-#define readw gsc_readw
-#define readl gsc_readl
-#define writeb gsc_writeb
-#define writew gsc_writew
-#define writel gsc_writel
-
+extern unsigned char eisa_in8(unsigned short port);
+extern unsigned short eisa_in16(unsigned short port);
+extern unsigned int eisa_in32(unsigned short port);
+extern void eisa_out8(unsigned char data, unsigned short port);
+extern void eisa_out16(unsigned short data, unsigned short port);
+extern void eisa_out32(unsigned int data, unsigned short port);
+
+#if defined(CONFIG_PCI)
+extern unsigned char inb(int addr);
+extern unsigned short inw(int addr);
+extern unsigned int inl(int addr);
+
+extern void outb(unsigned char b, int addr);
+extern void outw(unsigned short b, int addr);
+extern void outl(unsigned int b, int addr);
+#elif defined(CONFIG_EISA)
+#define inb eisa_in8
+#define inw eisa_in16
+#define inl eisa_in32
+#define outb eisa_out8
+#define outw eisa_out16
+#define outl eisa_out32
+#else
+static inline char inb(unsigned long addr)
+{
+	BUG();
+	return -1;
+}
 
-#if defined(CONFIG_PCI) || defined(CONFIG_ISA)
-/*
- *	So we get clear link errors 
- */
-extern u8 inb(unsigned long addr);
-extern u16 inw(unsigned long addr);
-extern u32 inl(unsigned long addr);
-
-extern void outb(unsigned char b, unsigned long addr);
-extern void outw(unsigned short b, unsigned long addr);
-extern void outl(u32 b, unsigned long addr);
+static inline short inw(unsigned long addr)
+{
+	BUG();
+	return -1;
+}
 
-static inline void memcpy_toio(void *dest, void *src, int count) 
+static inline int inl(unsigned long addr)
 {
-	while(count--)
-		writeb(*((char *)src)++, (char *)dest++);
+	BUG();
+	return -1;
 }
 
+#define outb(x, y)	BUG()
+#define outw(x, y)	BUG()
+#define outl(x, y)	BUG()
 #endif
 
+/*
+ * String versions of in/out ops:
+ */
+extern void insb (unsigned long port, void *dst, unsigned long count);
+extern void insw (unsigned long port, void *dst, unsigned long count);
+extern void insl (unsigned long port, void *dst, unsigned long count);
+extern void outsb (unsigned long port, const void *src, unsigned long count);
+extern void outsw (unsigned long port, const void *src, unsigned long count);
+extern void outsl (unsigned long port, const void *src, unsigned long count);
+
+
 /* IO Port space is :      BBiiii   where BB is HBA number. */
 #define IO_SPACE_LIMIT 0x00ffffff
 
-/* Right now we don't support Dino-on-a-card and V class which do PCI MMIO
- * through address/data registers. */
-
-#define ioremap(__offset, __size)	((void *)(__offset))
-#define iounmap(__addr)
 
 #define dma_cache_inv(_start,_size)		do { flush_kernel_dcache_range(_start,_size); } while(0)
 #define dma_cache_wback(_start,_size)		do { flush_kernel_dcache_range(_start,_size); } while (0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/ioctls.h linux-2.4.20/include/asm-parisc/ioctls.h
--- linux-2.4.19/include/asm-parisc/ioctls.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/ioctls.h	2002-10-29 11:18:33.000000000 +0000
@@ -67,6 +67,7 @@
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
 #define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+#define FIOQSIZE	0x5460	/* Get exact space used by quota */
 
 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/iosapic.h linux-2.4.20/include/asm-parisc/iosapic.h
--- linux-2.4.19/include/asm-parisc/iosapic.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/iosapic.h	2002-10-29 11:18:36.000000000 +0000
@@ -15,7 +15,7 @@
 ** fixup_irq is to initialize PCI IRQ line support and
 ** virtualize pcidev->irq value. To be called by pci_fixup_bus().
 */
-extern void *iosapic_register(void *hpa);
+extern void *iosapic_register(unsigned long hpa);
 extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev);
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/ipcbuf.h linux-2.4.20/include/asm-parisc/ipcbuf.h
--- linux-2.4.19/include/asm-parisc/ipcbuf.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/ipcbuf.h	2002-10-29 11:18:49.000000000 +0000
@@ -2,10 +2,26 @@
 #define __PARISC_IPCBUF_H__
 
 /*
- * The ipc64_perm structure for PA-RISC is identical to kern_ipc_perm
- * as we have always had 32-bit UIDs and GIDs in the kernel.
+ * The ipc64_perm structure for PA-RISC is almost identical to
+ * kern_ipc_perm as we have always had 32-bit UIDs and GIDs in the kernel.
+ * 'seq' has been changed from long to int so that it's the same size
+ * on 64-bit kernels as on 32-bit ones.
  */
 
-#define ipc64_perm	kern_ipc_perm
+struct ipc64_perm
+{
+	key_t           key;
+	uid_t           uid;
+	gid_t           gid;
+	uid_t           cuid;
+	gid_t           cgid;
+	unsigned short int	__pad1;
+	mode_t          mode;
+	unsigned short int	__pad2;
+	unsigned short int	seq;
+	unsigned int	__pad3;
+	unsigned long long int __unused1;
+	unsigned long long int __unused2;
+};
 
 #endif /* __PARISC_IPCBUF_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/irq.h linux-2.4.20/include/asm-parisc/irq.h
--- linux-2.4.19/include/asm-parisc/irq.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/irq.h	2002-10-29 11:18:37.000000000 +0000
@@ -1,13 +1,5 @@
-#ifndef _ASM_IRQ_H
-#define _ASM_IRQ_H
-
-#include <linux/string.h>
-#include <asm/ptrace.h>
-#include <linux/interrupt.h>
-
-#include <asm/types.h>
 /*
- *	linux/include/asm/irq.h
+ *	linux/include/asm-parisc/irq.h
  *
  *	(C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar,
  *		Copyright 1999 SuSE GmbH
@@ -16,33 +8,39 @@
  *	<tomsoft@informatik.tu-chemnitz.de>
  */
 
-#define CPU_IRQ_REGION	 1
-#define TIMER_IRQ	 (IRQ_FROM_REGION(CPU_IRQ_REGION) | 0)
-#define	IPI_IRQ		 (IRQ_FROM_REGION(CPU_IRQ_REGION) | 1)
-
-/* This should be 31 for PA1.1 binaries and 63 for PA-2.0 wide mode) */
-#define MAX_CPU_IRQ	(BITS_PER_LONG - 1)
-
-#if 1    /* set to 1 to get the new irq offsets, or ...   */
-# if BITS_PER_LONG == 32
-#  define IRQ_REGION_SHIFT 5
-# else
-#  define IRQ_REGION_SHIFT 6
-# endif
-#else   /* 256 irq-entries per region (wastes memory, maybe gains speed? :-))*/
-# define IRQ_REGION_SHIFT 8
-#endif 
-
-#define IRQ_PER_REGION  (1 << IRQ_REGION_SHIFT)
-#define NR_IRQ_REGS	8
-#define NR_IRQS		(NR_IRQ_REGS * IRQ_PER_REGION)
+#ifndef _ASM_PARISC_IRQ_H
+#define _ASM_PARISC_IRQ_H
+
+#include <asm/ptrace.h>
+#include <asm/types.h>
+
+#include <linux/string.h>
+#include <linux/interrupt.h>
+
+
+#define CPU_IRQ_REGION		1
+#define TIMER_IRQ		(IRQ_FROM_REGION(CPU_IRQ_REGION) | 0)
+#define	IPI_IRQ			(IRQ_FROM_REGION(CPU_IRQ_REGION) | 1)
+
+/* This should be 31 for PA1.1 binaries and 63 for PA-2.0 wide mode */
+#define MAX_CPU_IRQ		(BITS_PER_LONG - 1)
+
+#if BITS_PER_LONG == 32
+#  define IRQ_REGION_SHIFT 	5
+#else
+#  define IRQ_REGION_SHIFT 	6
+#endif
+
+#define IRQ_PER_REGION		(1 << IRQ_REGION_SHIFT)
+#define NR_IRQ_REGS		16
+#define NR_IRQS			(NR_IRQ_REGS * IRQ_PER_REGION)
 
 #define IRQ_REGION(irq) 	((irq) >> IRQ_REGION_SHIFT)
 #define IRQ_OFFSET(irq)		((irq) & ((1<<IRQ_REGION_SHIFT)-1))
 #define	IRQ_FROM_REGION(reg)	((reg) << IRQ_REGION_SHIFT)
 
-#define IRQ_REG_DIS	   1	/* support disable_irq / enable_irq */
-#define IRQ_REG_MASK	   2	/* require IRQs to be masked */
+#define EISA_IRQ_REGION		0 /* region 0 needs to be reserved for EISA */
+#define EISA_MAX_IRQS		16 /* max. (E)ISA irq line */
 
 struct irq_region_ops {
 	void (*disable_irq)(void *dev, int irq);
@@ -54,8 +52,8 @@
 struct irq_region_data {
 	void *dev;
 	const char *name;
-	unsigned flags;
 	int irqbase;
+	unsigned int status[IRQ_PER_REGION]; /* IRQ status */
 };
 
 struct irq_region {
@@ -69,21 +67,31 @@
 
 static __inline__ int irq_cannonicalize(int irq)
 {
+#ifdef CONFIG_EISA
+	return (irq == (IRQ_FROM_REGION(EISA_IRQ_REGION)+2) 
+		? (IRQ_FROM_REGION(EISA_IRQ_REGION)+9) : irq);
+#else
 	return irq;
+#endif
 }
 
 extern void disable_irq(int);
+#define disable_irq_nosync(i) disable_irq(i)
 extern void enable_irq(int);
 
+extern void do_irq(struct irqaction *a, int i, struct pt_regs *p);
 extern void do_irq_mask(unsigned long mask, struct irq_region *region,
 	struct pt_regs *regs);
 
 extern struct irq_region *alloc_irq_region(int count, struct irq_region_ops *ops,
-	unsigned long flags, const char *name, void *dev);
+	const char *name, void *dev);
 
 extern int txn_alloc_irq(void);
 extern int txn_claim_irq(int);
 extern unsigned int txn_alloc_data(int, unsigned int);
 extern unsigned long txn_alloc_addr(int);
 
-#endif /* _ASM_IRQ_H */
+/* soft power switch support (power.c) */
+extern struct tasklet_struct power_tasklet;
+
+#endif	/* _ASM_PARISC_IRQ_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/keyboard.h linux-2.4.20/include/asm-parisc/keyboard.h
--- linux-2.4.19/include/asm-parisc/keyboard.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/keyboard.h	2002-10-29 11:18:32.000000000 +0000
@@ -1,4 +1,13 @@
 /*
+ *  WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *  ---------------------------------------------------------------
+ *  This file will be removed as soon as we have converted
+ *  hp_psaux.c and hp_keyb.c to the input layer !
+ *  
+ */
+
+
+/*
  *  linux/include/asm-parisc/keyboard.h
  *
  *  Original by Geert Uytterhoeven
@@ -21,6 +30,9 @@
 #ifdef __KERNEL__
 #ifdef CONFIG_VT
 
+#include <linux/kernel.h>
+#include <linux/kd.h>
+
 /*  These are basically the generic functions / variables.  The only
  *  unexpected detail is the initialization sequence for the keyboard
  *  driver is something like this:
@@ -58,6 +70,7 @@
 #define	kbd_sysrq_xlate		(kbd_ops->sysrq_xlate)
 extern unsigned char hp_ps2kbd_sysrq_xlate[128]; 	/* from drivers/char/hp_keyb.c */
 
+extern void unregister_kbd_ops(void);
 extern void register_kbd_ops(struct kbd_ops *ops);
 
 #endif /* CONFIG_VT */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/led.h linux-2.4.20/include/asm-parisc/led.h
--- linux-2.4.19/include/asm-parisc/led.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/led.h	2002-10-29 11:18:36.000000000 +0000
@@ -1,7 +1,6 @@
 #ifndef LED_H
 #define LED_H
 
-
 #define	LED7		0x80		/* top (or furthest right) LED */
 #define	LED6		0x40
 #define	LED5		0x20
@@ -16,18 +15,27 @@
 #define	LED_DISK_IO	LED2		/* for disk activity */
 #define	LED_HEARTBEAT	LED3		/* heartbeat */
 
+/* values for pdc_chassis_lcd_info_ret_block.model: */
+#define DISPLAY_MODEL_LCD  0		/* KittyHawk LED or LCD */
+#define DISPLAY_MODEL_NONE 1		/* no LED or LCD */
+#define DISPLAY_MODEL_LASI 2		/* LASI style 8 bit LED */
+#define DISPLAY_MODEL_OLD_ASP 0x7F	/* faked: ASP style 8 x 1 bit LED (only very old ASP versions) */
+
+#define LED_CMD_REG_NONE NULL		/* NULL == no addr for the cmd register */
 
-/* irq function */
-extern void led_interrupt_func(void);
+/* led tasklet struct */
+extern struct tasklet_struct led_tasklet;
 
-/* LASI & ASP specific LED initialization funcs */
-extern void __init lasi_led_init( unsigned long lasi_hpa );
-extern void __init asp_led_init( unsigned long led_ptr );
+/* register_led_driver() */
+int __init register_led_driver( int model, char *cmd_reg, char *data_reg );
 
 /* registers the LED regions for procfs */
-extern void __init register_led_regions(void);
+void __init register_led_regions(void);
+
+/* writes a string to the LCD display (if possible on this h/w) */
+int lcd_print(char *str);
 
-/* main LED initialization function (uses the PDC) */ 
-extern int __init led_init(void);
+/* main LED initialization function (uses PDC) */ 
+int __init led_init(void);
 
 #endif /* LED_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/md.h linux-2.4.20/include/asm-parisc/md.h
--- linux-2.4.19/include/asm-parisc/md.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/md.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,13 +0,0 @@
-/* $Id: md.h,v 1.1.1.1 1999/03/15 19:41:02 pjlahaie Exp $
- * md.h: High speed xor_block operation for RAID4/5 
- *
- */
- 
-#ifndef __ASM_MD_H
-#define __ASM_MD_H
-
-/* #define HAVE_ARCH_XORBLOCK */
-
-#define MD_XORBLOCK_ALIGNMENT	sizeof(long)
-
-#endif /* __ASM_MD_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/mmu.h linux-2.4.20/include/asm-parisc/mmu.h
--- linux-2.4.19/include/asm-parisc/mmu.h	2000-12-29 22:07:23.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/mmu.h	2002-10-29 11:18:35.000000000 +0000
@@ -1,68 +1,7 @@
-/*
- * parisc mmu structures 
- */
-
 #ifndef _PARISC_MMU_H_
 #define _PARISC_MMU_H_
 
-#ifndef __ASSEMBLY__
-
-/* Default "unsigned long" context */
+/* On parisc, we store the space id here */
 typedef unsigned long mm_context_t;
 
-/* Hardware Page Table Entry */
-typedef struct _PTE {
-	unsigned long v:1;	/* Entry is valid */
-	unsigned long tag:31;	/* Unique Tag */
-
-	unsigned long r:1;	/* referenced */
-	unsigned long os_1:1;	/*  */
-	unsigned long t:1;	/* page reference trap */
-	unsigned long d:1;	/* dirty */
-	unsigned long b:1;	/* break */
-	unsigned long type:3;	/* access type */
-	unsigned long pl1:2;	/* PL1 (execute) */
-	unsigned long pl2:2;	/* PL2 (write) */
-	unsigned long u:1;	/* uncacheable */
-	unsigned long id:1;	/* access id */
-	unsigned long os_2:1;	/*  */
-
-	unsigned long os_3:3;	/*  */
-	unsigned long res_1:4;	/*  */
-	unsigned long phys:20;	/* physical page number */
-	unsigned long os_4:2;	/*  */
-	unsigned long res_2:3;	/*  */
-
-	unsigned long next;	/* pointer to next page */
-} PTE; 
-
-/*
- * Simulated two-level MMU.  This structure is used by the kernel
- * to keep track of MMU mappings and is used to update/maintain
- * the hardware HASH table which is really a cache of mappings.
- *
- * The simulated structures mimic the hardware available on other
- * platforms, notably the 80x86 and 680x0.
- */
-
-typedef struct _pte {
-   	unsigned long page_num:20;
-   	unsigned long flags:12;		/* Page flags (some unused bits) */
-} pte;
-
-#define PD_SHIFT (10+12)		/* Page directory */
-#define PD_MASK  0x02FF
-#define PT_SHIFT (12)			/* Page Table */
-#define PT_MASK  0x02FF
-#define PG_SHIFT (12)			/* Page Entry */
-
-/* MMU context */
-
-typedef struct _MMU_context {
-	long	pid[4];
-	pte	**pmap;		/* Two-level page-map structure */
-} MMU_context;
-
-#endif /* __ASSEMBLY__ */
-
 #endif /* _PARISC_MMU_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/mmu_context.h linux-2.4.20/include/asm-parisc/mmu_context.h
--- linux-2.4.19/include/asm-parisc/mmu_context.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/mmu_context.h	2002-10-29 11:18:34.000000000 +0000
@@ -1,6 +1,8 @@
 #ifndef __PARISC_MMU_CONTEXT_H
 #define __PARISC_MMU_CONTEXT_H
 
+#include <asm/pgalloc.h>
+
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
 {
 }
@@ -14,17 +16,10 @@
 static inline int
 init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
-	/*
-	 * Init_new_context can be called for a cloned mm, so we
-	 * only allocate a space id if one hasn't been allocated
-	 * yet AND mm != &init_mm (cloned kernel thread which
-	 * will run in the kernel space with spaceid 0).
-	 */
-
-	if ((mm != &init_mm) && (mm->context == 0)) {
-		mm->context = alloc_sid();
-	}
+	if (atomic_read(&mm->mm_users) != 1)
+	    BUG();
 
+	mm->context = alloc_sid();
 	return 0;
 }
 
@@ -39,11 +34,8 @@
 {
 
 	if (prev != next) {
-		/* Re-load page tables */
-		tsk->thread.pg_tables = __pa(next->pgd);
-
-		mtctl(tsk->thread.pg_tables, 25);
-		mtsp(next->context,3);
+		mtctl(__pa(next->pgd), 25);
+		load_context(next->context);
 	}
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/mmzone.h linux-2.4.20/include/asm-parisc/mmzone.h
--- linux-2.4.19/include/asm-parisc/mmzone.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/mmzone.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,31 @@
+#ifndef _PARISC_MMZONE_H
+#define _PARISC_MMZONE_H
+
+struct node_map_data {
+    pg_data_t pg_data;
+    struct page *adj_node_mem_map;
+};
+
+extern struct node_map_data node_data[];
+extern unsigned char *chunkmap;
+
+#define BADCHUNK                ((unsigned char)0xff)
+#define CHUNKSZ                 (256*1024*1024)
+#define CHUNKSHIFT              28
+#define CHUNKMASK               (~(CHUNKSZ - 1))
+#define CHUNKNUM(paddr)         ((paddr) >> CHUNKSHIFT)
+
+#define NODE_DATA(nid)          (&node_data[nid].pg_data)
+#define NODE_MEM_MAP(nid)       (NODE_DATA(nid)->node_mem_map)
+#define ADJ_NODE_MEM_MAP(nid)   (node_data[nid].adj_node_mem_map)
+
+#define phys_to_page(paddr) \
+	(ADJ_NODE_MEM_MAP(chunkmap[CHUNKNUM((paddr))]) \
+	+ ((paddr) >> PAGE_SHIFT))
+
+#define virt_to_page(kvaddr) phys_to_page(__pa(kvaddr))
+
+/* This is kind of bogus, need to investigate performance of doing it right */
+#define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
+
+#endif /* !_PARISC_MMZONE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/module.h linux-2.4.20/include/asm-parisc/module.h
--- linux-2.4.19/include/asm-parisc/module.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/module.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,12 @@
+#ifndef _ASM_PARISC_MODULE_H
+#define _ASM_PARISC_MODULE_H
+/*
+ * This file contains the parisc architecture specific module code.
+ */
+
+#define module_map(x)		vmalloc(x)
+#define module_unmap(x)		vfree(x)
+#define module_arch_init(x)	(0)
+#define arch_init_modules(x)	do { } while (0)
+
+#endif /* _ASM_PARISC_MODULE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/msgbuf.h linux-2.4.20/include/asm-parisc/msgbuf.h
--- linux-2.4.19/include/asm-parisc/msgbuf.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/msgbuf.h	2002-10-29 11:18:34.000000000 +0000
@@ -13,11 +13,17 @@
 
 struct msqid64_ds {
 	struct ipc64_perm msg_perm;
+#ifndef __LP64__
 	unsigned int   __pad1;
+#endif
 	__kernel_time_t msg_stime;	/* last msgsnd time */
+#ifndef __LP64__
 	unsigned int   __pad2;
+#endif
 	__kernel_time_t msg_rtime;	/* last msgrcv time */
+#ifndef __LP64__
 	unsigned int   __pad3;
+#endif
 	__kernel_time_t msg_ctime;	/* last change time */
 	unsigned int  msg_cbytes;	/* current number of bytes on queue */
 	unsigned int  msg_qnum;	/* number of messages in queue */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/page.h linux-2.4.20/include/asm-parisc/page.h
--- linux-2.4.19/include/asm-parisc/page.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/page.h	2002-10-29 11:18:34.000000000 +0000
@@ -9,11 +9,28 @@
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
+#include <asm/cache.h>
+
 #define clear_page(page)	memset((void *)(page), 0, PAGE_SIZE)
-#define copy_page(to,from)	memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+#define copy_page(to,from)      copy_user_page_asm((void *)(to), (void *)(from))
+
+extern void purge_kernel_dcache_page(unsigned long);
+extern void copy_user_page_asm(void *to, void *from);
+extern void clear_user_page_asm(void *page, unsigned long vaddr);
 
-#define clear_user_page(page, vaddr) clear_page(page)
-#define copy_user_page(to, from, vaddr) copy_page(to, from)
+static inline void
+copy_user_page(void *to, void *from, unsigned long vaddr)
+{
+	copy_user_page_asm(to, from);
+	flush_kernel_dcache_page(to);
+}
+
+static inline void
+clear_user_page(void *page, unsigned long vaddr)
+{
+	purge_kernel_dcache_page((unsigned long)page);
+	clear_user_page_asm(page, vaddr);
+}
 
 /*
  * These are used to make use of C type-checking..
@@ -47,6 +64,20 @@
 	return order;
 }
 
+#ifdef __LP64__
+#define MAX_PHYSMEM_RANGES 8 /* Fix the size for now (current known max is 3) */
+#else
+#define MAX_PHYSMEM_RANGES 1 /* First range is only range that fits in 32 bits */
+#endif
+
+typedef struct __physmem_range {
+	unsigned long start_pfn;
+	unsigned long pages;       /* PAGE_SIZE pages */
+} physmem_range_t;
+
+extern physmem_range_t pmem_ranges[];
+extern int npmem_ranges;
+
 #endif /* !__ASSEMBLY__ */
 
 /* to align the pointer to the (next) page boundary */
@@ -68,7 +99,7 @@
 
 
 #define LINUX_GATEWAY_SPACE     0
-#define __PAGE_OFFSET		(0xc0000000)
+#define __PAGE_OFFSET           (0x10000000)
 
 #define PAGE_OFFSET		((unsigned long)__PAGE_OFFSET)
 /* These macros don't work for 64-bit C code -- don't allow in C at all */
@@ -78,8 +109,10 @@
 #endif
 #define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
 #define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
-#define	virt_to_page(kaddr)	(mem_map + (__pa(kaddr) >> PAGE_SHIFT))
+#ifndef CONFIG_DISCONTIGMEM
+#define virt_to_page(kaddr)     (mem_map + (__pa(kaddr) >> PAGE_SHIFT))
 #define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
+#endif  /* !CONFIG_DISCONTIGMEM */
 
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/pci.h linux-2.4.20/include/asm-parisc/pci.h
--- linux-2.4.19/include/asm-parisc/pci.h	2002-02-25 19:38:12.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/pci.h	2002-10-29 11:18:34.000000000 +0000
@@ -3,9 +3,6 @@
 
 #include <asm/scatterlist.h>
 
-#define MIN_PCI_PORT 0x000000
-#define MAX_PCI_PORT 0xffffff
-
 /*
 ** HP PCI platforms generally support multiple bus adapters.
 **    (workstations 1-~4, servers 2-~32)
@@ -19,7 +16,7 @@
 #define PCI_MAX_BUSSES	256
 
 /* [soapbox on]
-** Who the hell can develope stuff without ASSERT or VASSERT?
+** Who the hell can develop stuff without ASSERT or VASSERT?
 ** No one understands all the modules across all platforms.
 ** For linux add another dimension - processor architectures.
 **
@@ -49,18 +46,40 @@
 ** Data needed by pcibios layer belongs here.
 */
 struct pci_hba_data {
-	struct pci_hba_data *next;	/* global chain of HBAs */
-	char           *base_addr;	/* aka Host Physical Address */
-	struct hp_device *iodc_info;	/* Info from PA bus walk */
+	unsigned long	base_addr;	/* aka Host Physical Address */
+	const struct parisc_device *dev; /* device from PA bus walk */
 	struct pci_bus *hba_bus;	/* primary PCI bus below HBA */
 	int		hba_num;	/* I/O port space access "key" */
 	struct resource bus_num;	/* PCI bus numbers */
 	struct resource io_space;	/* PIOP */
-	struct resource mem_space;	/* LMMIO */
-	unsigned long   mem_space_offset;  /* VCLASS support */
+	struct resource lmmio_space;	/* bus addresses < 4Gb */
+	struct resource elmmio_space;	/* additional bus addresses < 4Gb */
+	unsigned long   lmmio_space_offset;  /* CPU view - PCI view */
+	void *          iommu;          /* IOMMU this device is under */
 	/* REVISIT - spinlock to protect resources? */
 };
 
+#define HBA_DATA(d)		((struct pci_hba_data *) (d))
+
+/* 
+** We support 2^16 I/O ports per HBA.  These are set up in the form
+** 0xbbxxxx, where bb is the bus number and xxxx is the I/O port
+** space address.
+*/
+#define HBA_PORT_SPACE_BITS	16
+
+#define HBA_PORT_BASE(h)	((h) << HBA_PORT_SPACE_BITS)
+#define HBA_PORT_SPACE_SIZE	(1UL << HBA_PORT_SPACE_BITS)
+
+#define PCI_PORT_HBA(a)		((a) >> HBA_PORT_SPACE_BITS)
+#define PCI_PORT_ADDR(a)	((a) & (HBA_PORT_SPACE_SIZE - 1))
+
+/*
+** Convert between PCI (IO_VIEW) addresses and processor (PA_VIEW) addresses.
+** Note that we currently support only LMMIO.
+*/
+#define PCI_BUS_ADDR(hba,a)	((a) - hba->lmmio_space_offset)
+#define PCI_HOST_ADDR(hba,a)	((a) + hba->lmmio_space_offset)
 
 /*
 ** KLUGE: linux/pci.h include asm/pci.h BEFORE declaring struct pci_bus
@@ -106,9 +125,6 @@
 	void (*fixup_bus)(struct pci_bus *bus);
 };
 
-extern void pcibios_size_bridge(struct pci_bus *, struct pbus_set_ranges_data *);
-
-
 /*
 ** See Documentation/DMA-mapping.txt
 */
@@ -127,8 +143,8 @@
 
 /*
 ** We could live without the hppa_dma_ops indirection if we didn't want
-** to support 4 different dma models with one binary or they were
-** all loadable modules:
+** to support 4 different coherent dma models with one binary (they will
+** someday be loadable modules):
 **     I/O MMU        consistent method           dma_sync behavior
 **  =============   ======================       =======================
 **  a) PA-7x00LC    uncachable host memory          flush/purge
@@ -144,8 +160,11 @@
 */
 
 extern struct pci_dma_ops *hppa_dma_ops;
+
+#ifdef CONFIG_PA11
 extern struct pci_dma_ops pcxl_dma_ops;
 extern struct pci_dma_ops pcx_dma_ops;
+#endif
 
 /*
 ** Oops hard if we haven't setup hppa_dma_ops by the time the first driver
@@ -155,7 +174,9 @@
 */
 static inline int pci_dma_panic(char *msg)
 {
+	extern void panic(const char *, ...);	/* linux/kernel.h */
 	panic(msg);
+	/* NOTREACHED */
 	return -1;
 }
 
@@ -196,16 +217,32 @@
 	hppa_dma_ops->dma_sync_sg(p, sg, n, d); \
 	}
 
+/* No highmem on parisc, plus we have an IOMMU, so mapping pages is easy. */
+#define pci_map_page(dev, page, off, size, dir) \
+	pci_map_single(dev, (page_address(page) + (off)), size, dir)
+#define pci_unmap_page(dev,addr,sz,dir) pci_unmap_single(dev,addr,sz,dir)
+
+/* Don't support DAC yet. */
+#define pci_dac_dma_supported(pci_dev, mask)	(0)
+
 /*
 ** Stuff declared in arch/parisc/kernel/pci.c
 */
 extern struct pci_port_ops *pci_port;
 extern struct pci_bios_ops *pci_bios;
 extern int pci_post_reset_delay;	/* delay after de-asserting #RESET */
+extern int pci_hba_count;
+extern struct pci_hba_data *parisc_pci_hba[];
 
+#ifdef CONFIG_PCI
 extern void pcibios_register_hba(struct pci_hba_data *);
+extern void pcibios_set_master(struct pci_dev *);
 extern void pcibios_assign_unassigned_resources(struct pci_bus *);
-
+#else
+extern inline void pcibios_register_hba(struct pci_hba_data *x)
+{
+}
+#endif
 
 /*
 ** used by drivers/pci/pci.c:pci_do_scan_bus()
@@ -216,12 +253,7 @@
 **   To date, only alpha sets this to one. We'll need to set this
 **   to zero for legacy platforms and one for PAT platforms.
 */
-#ifdef __LP64__
-extern int pdc_pat;  /* arch/parisc/kernel/inventory.c */
-#define pcibios_assign_all_busses()	pdc_pat
-#else
-#define pcibios_assign_all_busses()	0
-#endif
+#define pcibios_assign_all_busses()     (pdc_type == PDC_TYPE_PAT)
 
 #define PCIBIOS_MIN_IO          0x10
 #define PCIBIOS_MIN_MEM         0x1000 /* NBPG - but pci/setup-res.c dies */
@@ -229,4 +261,32 @@
 /* Return the index of the PCI controller for device PDEV. */
 #define pci_controller_num(PDEV)	(0)
 
+#define GET_IOC(dev) ((struct ioc *)(HBA_DATA(dev->sysdata)->iommu))
+
+#ifdef CONFIG_IOMMU_CCIO
+struct parisc_device;
+struct ioc;
+void * ccio_get_iommu(const struct parisc_device *dev);
+struct pci_dev * ccio_get_fake(const struct parisc_device *dev);
+int ccio_request_resource(const struct parisc_device *dev,
+		struct resource *res);
+int ccio_allocate_resource(const struct parisc_device *dev,
+		struct resource *res, unsigned long size,
+		unsigned long min, unsigned long max, unsigned long align,
+		void (*alignf)(void *, struct resource *, unsigned long),
+		void *alignf_data);
+#else /* !CONFIG_IOMMU_CCIO */
+#define ccio_get_iommu(dev) NULL
+#define ccio_get_fake(dev) NULL
+#define ccio_request_resource(dev, res) request_resource(&iomem_resource, res)
+#define ccio_allocate_resource(dev, res, size, min, max, align, alignf, data) \
+		allocate_resource(&iomem_resource, res, size, min, max, \
+				align, alignf, data)
+#endif /* !CONFIG_IOMMU_CCIO */
+
+#ifdef CONFIG_IOMMU_SBA
+struct parisc_device;
+void * sba_get_iommu(struct parisc_device *dev);
+#endif
+
 #endif /* __ASM_PARISC_PCI_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/pdc.h linux-2.4.20/include/asm-parisc/pdc.h
--- linux-2.4.19/include/asm-parisc/pdc.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/pdc.h	2002-10-29 11:18:30.000000000 +0000
@@ -2,8 +2,27 @@
 #define _PARISC_PDC_H
 
 /*
-    PDC entry points...
-*/
+ *	PDC return values ...
+ *	All PDC calls return a subset of these errors. 
+ */
+
+#define PDC_WARN		  3	/* Call completed with a warning */
+#define PDC_REQ_ERR_1		  2	/* See above			 */
+#define PDC_REQ_ERR_0		  1	/* Call would generate a requestor error */
+#define PDC_OK			  0	/* Call completed successfully	*/
+#define PDC_BAD_PROC		 -1	/* Called non-existent procedure*/
+#define PDC_BAD_OPTION		 -2	/* Called with non-existent option */
+#define PDC_ERROR		 -3	/* Call could not complete without an error */
+#define PDC_NE_MOD		 -5	/* Module not found		*/
+#define PDC_NE_CELL_MOD		 -7	/* Cell module not found	*/
+#define PDC_INVALID_ARG		-10	/* Called with an invalid argument */
+#define PDC_BUS_POW_WARN	-12	/* Call could not complete in allowed power budget */
+#define PDC_NOT_NARROW		-17	/* Narrow mode not supported	*/
+
+
+/*
+ *	PDC entry points...
+ */
 
 #define PDC_POW_FAIL	1		/* perform a power-fail		*/
 #define PDC_POW_FAIL_PREPARE	0	/* prepare for powerfail	*/
@@ -12,7 +31,7 @@
 #define PDC_CHASSIS_DISP	0	/* update chassis display	*/
 #define PDC_CHASSIS_WARN	1	/* return chassis warnings	*/
 #define PDC_CHASSIS_DISPWARN	2	/* update&return chassis status */
-#define PDC_RETURN_CHASSIS_INFO 128	/* HVERSION dependend: return chassis LED/LCD info  */
+#define PDC_RETURN_CHASSIS_INFO 128	/* HVERSION dependent: return chassis LED/LCD info  */
 
 #define PDC_PIM         3               /* Get PIM data                 */
 #define PDC_PIM_HPMC            0       /* Transfer HPMC data           */
@@ -26,52 +45,74 @@
 #define PDC_MODEL_BOOTID	1	/* set the BOOT_ID		*/
 #define PDC_MODEL_VERSIONS	2	/* returns cpu-internal versions*/
 #define PDC_MODEL_SYSMODEL	3	/* return system model info	*/
-#define PDC_MODEL_ENSPEC	4	/* ??? */
-#define PDC_MODEL_DISPEC	5	/* ??? */
+#define PDC_MODEL_ENSPEC	4	/* enable specific option	*/
+#define PDC_MODEL_DISPEC	5	/* disable specific option	*/
 #define PDC_MODEL_CPU_ID	6	/* returns cpu-id (only newer machines!) */
 #define PDC_MODEL_CAPABILITIES	7	/* returns OS32/OS64-flags	*/
 #define PDC_MODEL_GET_BOOT__OP	8	/* returns boot test options	*/
 #define PDC_MODEL_SET_BOOT__OP	9	/* set boot test options	*/
 
+#define PA89_INSTRUCTION_SET	0x4	/* capatibilies returned	*/
+#define PA90_INSTRUCTION_SET	0x8
+
 #define PDC_CACHE	5		/* return/set cache (& TLB) info*/
 #define PDC_CACHE_INFO		0	/* returns information 		*/
 #define PDC_CACHE_SET_COH	1	/* set coherence state		*/
 #define PDC_CACHE_RET_SPID	2	/* returns space-ID bits	*/
 
-#define PDC_HPA	 6       	/* return HPA of processor */
-#define PDC_HPA_PROCESSOR       0
-#define PDC_HPA_MODULES	 1
-
-#define PDC_IODC	8       /* talk to IODC */
-#define PDC_IODC_READ	   0       /* read IODC entry point */
-/*      PDC_IODC_RI_*		      INDEX parameter of PDC_IODC_READ   */
-#define PDC_IODC_RI_DATA_BYTES	0	/* IODC Data Bytes		    */
-/*				1, 2	   obsolete - HVERSION dependent      */
-#define PDC_IODC_RI_INIT	3	/* Initialize module		  */
+#define PDC_HPA		6		/* return HPA of processor	*/
+#define PDC_HPA_PROCESSOR	0
+#define PDC_HPA_MODULES		1
+
+#define PDC_COPROC	7		/* Co-Processor (usually FP unit(s)) */
+#define PDC_COPROC_CFG		0	/* Co-Processor Cfg (FP unit(s) enabled?) */
+
+#define PDC_IODC	8		/* talk to IODC			*/
+#define PDC_IODC_READ		0	/* read IODC entry point	*/
+/*      PDC_IODC_RI_			 * INDEX parameter of PDC_IODC_READ */
+#define PDC_IODC_RI_DATA_BYTES	0	/* IODC Data Bytes		*/
+/*				1, 2	   obsolete - HVERSION dependent*/
+#define PDC_IODC_RI_INIT	3	/* Initialize module		*/
 #define PDC_IODC_RI_IO		4	/* Module input/output		*/
 #define PDC_IODC_RI_SPA		5	/* Module input/output		*/
 #define PDC_IODC_RI_CONFIG	6	/* Module input/output		*/
-/*				7	  obsolete - HVERSION dependent      */
+/*				7	  obsolete - HVERSION dependent */
 #define PDC_IODC_RI_TEST	8	/* Module input/output		*/
 #define PDC_IODC_RI_TLB		9	/* Module input/output		*/
-#define PDC_IODC_NINIT	  2       /* non-destructive init */
-#define PDC_IODC_DINIT	  3       /* destructive init */
-#define PDC_IODC_MEMERR	 4       /* check for memory errors */
-#define PDC_IODC_INDEX_DATA     0       /* get first 16 bytes from mod IODC */
-#define PDC_IODC_BUS_ERROR      -4      /* bus error return value */
-#define PDC_IODC_INVALID_INDEX  -5      /* invalid index return value */
-#define PDC_IODC_COUNT	  -6      /* count is too small */
-
-#define	PDC_TOD		9		/* time-of-day clock (TOD) */
-#define	PDC_TOD_READ		0	/* read TOD  */
-#define	PDC_TOD_WRITE		1	/* write TOD */
-#define	PDC_TOD_ITIMER		2	/* calibrate Interval Timer (CR16) */
+#define PDC_IODC_NINIT		2	/* non-destructive init		*/
+#define PDC_IODC_DINIT		3	/* destructive init		*/
+#define PDC_IODC_MEMERR		4	/* check for memory errors	*/
+#define PDC_IODC_INDEX_DATA	0	/* get first 16 bytes from mod IODC */
+#define PDC_IODC_BUS_ERROR	-4	/* bus error return value	*/
+#define PDC_IODC_INVALID_INDEX	-5	/* invalid index return value	*/
+#define PDC_IODC_COUNT		-6	/* count is too small		*/
+
+#define PDC_TOD		9		/* time-of-day clock (TOD)	*/
+#define PDC_TOD_READ		0	/* read TOD			*/
+#define PDC_TOD_WRITE		1	/* write TOD			*/
+#define PDC_TOD_ITIMER		2	/* calibrate Interval Timer (CR16) */
+
+#define PDC_STABLE	10		/* stable storage (sprockets)	*/
+#define PDC_STABLE_READ		0
+#define PDC_STABLE_WRITE	1
+#define PDC_STABLE_RETURN_SIZE	2
+#define PDC_STABLE_VERIFY_CONTENTS 3
+#define PDC_STABLE_INITIALIZE	4
 
-#define PDC_ADD_VALID	12    		/* Memory validation PDC call */
-#define PDC_ADD_VALID_VERIFY  0    	/* Make PDC_ADD_VALID verify region */
+#define PDC_NVOLATILE	11		/* often not implemented	*/
+
+#define PDC_ADD_VALID	12		/* Memory validation PDC call	*/
+#define PDC_ADD_VALID_VERIFY	0	/* Make PDC_ADD_VALID verify region */
 
 #define PDC_INSTR	15		/* get instr to invoke PDCE_CHECK() */
 
+#define PDC_PROC	16		/* (sprockets)			*/
+
+#define PDC_CONFIG	16		/* (sprockets)			*/
+#define PDC_CONFIG_DECONFIG	0
+#define PDC_CONFIG_DRECONFIG	1
+#define PDC_CONFIG_DRETURN_CONFIG 2
+
 #define PDC_BLOCK_TLB	18		/* manage hardware block-TLB	*/
 #define PDC_BTLB_INFO		0	/* returns parameter 		*/
 #define PDC_BTLB_INSERT		1	/* insert BTLB entry		*/
@@ -82,92 +123,373 @@
 #define PDC_TLB_INFO		0	/* returns parameter 		*/
 #define PDC_TLB_SETUP		1	/* set up miss handling 	*/
 
-#define PDC_SYSTEM_MAP	22		/* find system modules */
+#define PDC_MEM		20		/* Manage memory		*/
+#define PDC_MEM_MEMINFO		0
+#define PDC_MEM_ADD_PAGE	1
+#define PDC_MEM_CLEAR_PDT	2
+#define PDC_MEM_READ_PDT	3
+#define PDC_MEM_RESET_CLEAR	4
+#define PDC_MEM_GOODMEM		5
+#define PDC_MEM_TABLE		128	/* Non contig mem map (sprockets) */
+#define PDC_MEM_RETURN_ADDRESS_TABLE	PDC_MEM_TABLE
+#define PDC_MEM_GET_MEMORY_SYSTEM_TABLES_SIZE	131
+#define PDC_MEM_GET_MEMORY_SYSTEM_TABLES	132
+#define PDC_MEM_GET_PHYSICAL_LOCATION_FROM_MEMORY_ADDRESS 133
+
+#define PDC_MEM_RET_SBE_REPLACED	5	/* PDC_MEM return values */
+#define PDC_MEM_RET_DUPLICATE_ENTRY	4
+#define PDC_MEM_RET_BUF_SIZE_SMALL	1
+#define PDC_MEM_RET_PDT_FULL		-11
+#define PDC_MEM_RET_INVALID_PHYSICAL_LOCATION ~0ULL
+
+#ifndef __ASSEMBLY__
+typedef struct {
+    unsigned long long	baseAddr;
+    unsigned int	pages;
+    unsigned int	reserved;
+} MemAddrTable_t;
+#endif
+
+
+#define PDC_PSW		21		/* Get/Set default System Mask  */
+#define PDC_PSW_MASK		0	/* Return mask                  */
+#define PDC_PSW_GET_DEFAULTS	1	/* Return defaults              */
+#define PDC_PSW_SET_DEFAULTS	2	/* Set default                  */
+#define PDC_PSW_ENDIAN_BIT	1	/* set for big endian           */
+#define PDC_PSW_WIDE_BIT	2	/* set for wide mode            */ 
+
+#define PDC_SYSTEM_MAP	22		/* find system modules		*/
 #define PDC_FIND_MODULE 	0
+#define PDC_FIND_ADDRESS	1
+#define PDC_TRANSLATE_PATH	2
+
+#define PDC_SOFT_POWER	23		/* soft power switch		*/
+#define PDC_SOFT_POWER_INFO	0	/* return info about the soft power switch */
+#define PDC_SOFT_POWER_ENABLE	1	/* enable/disable soft power switch */
 
 
 /* HVERSION dependent */
 
-#define PDC_IO			135	/* log error info, reset IO system  */
+/* The PDC_MEM_MAP calls */
+#define PDC_MEM_MAP	128		/* on s700: return page info	*/
+#define PDC_MEM_MAP_HPA		0	/* returns hpa of a module	*/
 
-#define PDC_BROADCAST_RESET	136	/* reset all processors	     */
-#define PDC_DO_RESET            0UL	/* option: perform a broadcast reset */
-#define PDC_DO_FIRM_TEST_RESET  1UL	/* Do broadcast reset with bitmap */
-#define PDC_BR_RECONFIGURATION  2UL	/* reset w/reconfiguration */
-#define PDC_FIRM_TEST_MAGIC 	0xab9ec36fUL    /* for this reboot only */
+#define PDC_EEPROM	129		/* EEPROM access		*/
+#define PDC_EEPROM_READ_WORD	0
+#define PDC_EEPROM_WRITE_WORD	1
+#define PDC_EEPROM_READ_BYTE	2
+#define PDC_EEPROM_WRITE_BYTE	3
+#define PDC_EEPROM_EEPROM_PASSWORD -1000
+
+#define PDC_NVM		130		/* NVM (non-volatile memory) access */
+#define PDC_NVM_READ_WORD	0
+#define PDC_NVM_WRITE_WORD	1
+#define PDC_NVM_READ_BYTE	2
+#define PDC_NVM_WRITE_BYTE	3
+
+#define PDC_SEED_ERROR	132		/* (sprockets)			*/
+
+#define PDC_IO		135		/* log error info, reset IO system */
+#define PDC_IO_READ_AND_CLEAR_ERRORS	0
+#define PDC_IO_READ_AND_LOG_ERRORS	1
+#define PDC_IO_SUSPEND_USB		2
+/* sets bits 6&7 (little endian) of the HcControl Register */
+#define PDC_IO_USB_SUSPEND	0xC000000000000000
+#define PDC_IO_EEPROM_IO_ERR_TABLE_FULL	-5	/* return value */
+#define PDC_IO_NO_SUSPEND		-6	/* return value */
+
+#define PDC_BROADCAST_RESET 136		/* reset all processors		*/
+#define PDC_DO_RESET		0	/* option: perform a broadcast reset */
+#define PDC_DO_FIRM_TEST_RESET	1	/* Do broadcast reset with bitmap */
+#define PDC_BR_RECONFIGURATION	2	/* reset w/reconfiguration	*/
+#define PDC_FIRM_TEST_MAGIC	0xab9ec36fUL    /* for this reboot only	*/
 
-#define PDC_LAN_STATION_ID      138     /* Hversion dependent mechanism for */
-#define PDC_LAN_STATION_ID_READ 0       /* getting the lan station address  */
+#define PDC_LAN_STATION_ID 138		/* Hversion dependent mechanism for */
+#define PDC_LAN_STATION_ID_READ	0	/* getting the lan station address  */
 
 #define	PDC_LAN_STATION_ID_SIZE	6
 
-/* Legacy PDC definitions for same stuff */
-#define PDC_PCI_INDEX		   147UL
-#define PDC_PCI_GET_INT_TBL_SIZE	13UL
-#define PDC_PCI_GET_INT_TBL	     14UL
-
-/* generic error codes returned by all PDC-functions */
-
-#define PDC_WARN	    3  /* Call completed with a warning */
-#define PDC_REQ_ERR_1       2  /* See above */
-#define PDC_REQ_ERR_0       1  /* Call would generate a requestor error */
-#define PDC_OK	      0  /* Call completed successfully */
-#define PDC_BAD_PROC	   -1  /* Called non-existant procedure */
-#define PDC_BAD_OPTION     -2  /* Called with non-existant option */
-#define PDC_ERROR	  -3  /* Call could not complete without an error */
-#define PDC_INVALID_ARG   -10  /* Called with an invalid argument */
-#define PDC_BUS_POW_WARN  -12  /* Call could not complete in allowed power budget */
-
-
-/* The following are from the HPUX .h files, and are just for
-compatibility */
-
-#define PDC_RET_OK       0L	/* Call completed successfully */
-#define PDC_RET_NE_PROC -1L	/* Non-existent procedure */
-#define PDC_RET_NE_OPT  -2L	/* non-existant option - arg1 */
-#define PDC_RET_NE_MOD  -5L	/* Module not found */
-#define PDC_RET_NE_CELL_MOD -7L	/* Cell module not found */
-#define PDC_RET_INV_ARG	-10L	/* Invalid argument */
-#define PDC_RET_NOT_NARROW -17L /* Narrow mode not supported */
-
-
-/* Error codes for PDC_ADD_VALID */
-
-#define PDC_ADD_VALID_WARN	    3  /* Call completed with a warning */
-#define PDC_ADD_VALID_REQ_ERR_1       2  /* See above */
-#define PDC_ADD_VALID_REQ_ERR_0       1  /* Call would generate a requestor error */
-#define PDC_ADD_VALID_OK	      0  /* Call completed successfully */
-#define PDC_ADD_VALID_BAD_OPTION     -2  /* Called with non-existant option */
-#define PDC_ADD_VALID_ERROR	  -3  /* Call could not complete without an error */
-#define PDC_ADD_VALID_INVALID_ARG   -10  /* Called with an invalid argument */
-#define PDC_ADD_VALID_BUS_POW_WARN  -12  /* Call could not complete in allowed power budget */
+#define PDC_CHECK_RANGES 139		/* (sprockets)			*/
 
-/* The PDC_MEM_MAP calls */
+#define PDC_NV_SECTIONS	141		/* (sprockets)			*/
+
+#define PDC_PERFORMANCE	142		/* performance monitoring	*/
+
+#define PDC_SYSTEM_INFO	143		/* system information		*/
+#define PDC_SYSINFO_RETURN_INFO_SIZE	0
+#define PDC_SYSINFO_RRETURN_SYS_INFO	1
+#define PDC_SYSINFO_RRETURN_ERRORS	2
+#define PDC_SYSINFO_RRETURN_WARNINGS	3
+#define PDC_SYSINFO_RETURN_REVISIONS	4
+#define PDC_SYSINFO_RRETURN_DIAGNOSE	5
+#define PDC_SYSINFO_RRETURN_HV_DIAGNOSE	1005
+
+#define PDC_RDR		144		/* (sprockets)			*/
+#define PDC_RDR_READ_BUFFER	0
+#define PDC_RDR_READ_SINGLE	1
+#define PDC_RDR_WRITE_SINGLE	2
+
+#define PDC_INTRIGUE	145 		/* (sprockets)			*/
+#define PDC_INTRIGUE_WRITE_BUFFER 	 0
+#define PDC_INTRIGUE_GET_SCRATCH_BUFSIZE 1
+#define PDC_INTRIGUE_START_CPU_COUNTERS	 2
+#define PDC_INTRIGUE_STOP_CPU_COUNTERS	 3
+
+#define PDC_STI		146 		/* STI access			*/
+/* same as PDC_PCI_XXX values (see below) */
+
+/* Legacy PDC definitions for same stuff */
+#define PDC_PCI_INDEX	147
+#define PDC_PCI_INTERFACE_INFO		0
+#define PDC_PCI_SLOT_INFO		1
+#define PDC_PCI_INFLIGHT_BYTES		2
+#define PDC_PCI_READ_CONFIG		3
+#define PDC_PCI_WRITE_CONFIG		4
+#define PDC_PCI_READ_PCI_IO		5
+#define PDC_PCI_WRITE_PCI_IO		6
+#define PDC_PCI_READ_CONFIG_DELAY	7
+#define PDC_PCI_UPDATE_CONFIG_DELAY	8
+#define PDC_PCI_PCI_PATH_TO_PCI_HPA	9
+#define PDC_PCI_PCI_HPA_TO_PCI_PATH	10
+#define PDC_PCI_PCI_PATH_TO_PCI_BUS	11
+#define PDC_PCI_PCI_RESERVED		12
+#define PDC_PCI_PCI_INT_ROUTE_SIZE	13
+#define PDC_PCI_GET_INT_TBL_SIZE	PDC_PCI_PCI_INT_ROUTE_SIZE
+#define PDC_PCI_PCI_INT_ROUTE		14
+#define PDC_PCI_GET_INT_TBL		PDC_PCI_PCI_INT_ROUTE 
+#define PDC_PCI_READ_MON_TYPE		15
+#define PDC_PCI_WRITE_MON_TYPE		16
+
+
+/* Get SCSI Interface Card info:  SDTR, SCSI ID, mode (SE vs LVD) */
+#define PDC_INITIATOR	163
+#define PDC_GET_INITIATOR	0
+#define PDC_SET_INITIATOR	1
+#define PDC_DELETE_INITIATOR	2
+#define PDC_RETURN_TABLE_SIZE	3
+#define PDC_RETURN_TABLE	4
+
+#define PDC_LINK	165 		/* (sprockets)			*/
+#define PDC_LINK_PCI_ENTRY_POINTS	0  /* list (Arg1) = 0 */
+#define PDC_LINK_USB_ENTRY_POINTS	1  /* list (Arg1) = 1 */
 
-#define PDC_MEM_MAP	    128
-#define PDC_MEM_MAP_HPA		0
 
 /* constants for OS (NVM...) */
-#define OS_ID_NONE	0
-#define OS_ID_HPUX	1
-#define OS_ID_MPEXL	2
-#define OS_ID_OSF	3
-#define OS_ID_LINUX	OS_ID_HPUX
+#define OS_ID_NONE		0	/* Undefined OS ID	*/
+#define OS_ID_HPUX		1	/* HP-UX OS		*/
+#define OS_ID_LINUX		OS_ID_HPUX /* just use the same value as hpux */
+#define OS_ID_MPEXL		2	/* MPE XL OS		*/
+#define OS_ID_OSF		3	/* OSF OS		*/
+#define OS_ID_HPRT		4	/* HP-RT OS		*/
+#define OS_ID_NOVEL		5	/* NOVELL OS		*/
+#define OS_ID_NT		6	/* NT OS		*/
+
 
 /* constants for PDC_CHASSIS */
-#define OSTAT_OFF		      0
-#define OSTAT_FLT		      1 
-#define OSTAT_TEST		     2
-#define OSTAT_INIT		     3
-#define OSTAT_SHUT		     4
-#define OSTAT_WARN		     5
-#define OSTAT_RUN		      6
-#define OSTAT_ON		       7
+#define OSTAT_OFF		0
+#define OSTAT_FLT		1 
+#define OSTAT_TEST		2
+#define OSTAT_INIT		3
+#define OSTAT_SHUT		4
+#define OSTAT_WARN		5
+#define OSTAT_RUN		6
+#define OSTAT_ON		7
+
+#ifdef __LP64__
+/* PDC PAT CELL */
+#define PDC_PAT_CELL	64L		/* Interface for gaining and 
+					 * manipulating cell state within PD */
+#define PDC_PAT_CELL_GET_NUMBER	   0L	/* Return Cell number		*/
+#define PDC_PAT_CELL_GET_INFO      1L	/* Returns info about Cell	*/
+#define PDC_PAT_CELL_MODULE        2L	/* Returns info about Module	*/
+#define PDC_PAT_CELL_SET_ATTENTION 9L	/* Set Cell Attention indicator	*/
+#define PDC_PAT_CELL_NUMBER_TO_LOC 10L	/* Cell Number -> Location	*/
+#define PDC_PAT_CELL_WALK_FABRIC   11L	/* Walk the Fabric		*/
+#define PDC_PAT_CELL_GET_RDT_SIZE  12L	/* Return Route Distance Table Sizes */
+#define PDC_PAT_CELL_GET_RDT       13L	/* Return Route Distance Tables	*/
+#define PDC_PAT_CELL_GET_LOCAL_PDH_SZ  14L /* Read Local PDH Buffer Size*/
+#define PDC_PAT_CELL_SET_LOCAL_PDH     15L /* Write Local PDH Buffer	*/
+#define PDC_PAT_CELL_GET_REMOTE_PDH_SZ 16L /* Return Remote PDH Buffer Size */
+#define PDC_PAT_CELL_GET_REMOTE_PDH    17L /* Read Remote PDH Buffer	*/
+#define PDC_PAT_CELL_GET_DBG_INFO  128L	/* Return DBG Buffer Info	*/
+#define PDC_PAT_CELL_CHANGE_ALIAS  129L	/* Change Non-Equivalent Alias Checking */
+
+/*
+** Arg to PDC_PAT_CELL_MODULE memaddr[4]
+**
+** Addresses on the Merced Bus != all Runway Bus addresses.
+** This is intended for programming SBA/LBA chips range registers.
+*/
+#define IO_VIEW			0UL
+#define PA_VIEW			1UL
+
+/* PDC_PAT_CELL_MODULE entity type values */
+#define PAT_ENTITY_CA		0	/* central agent	*/
+#define PAT_ENTITY_PROC		1	/* processor		*/
+#define PAT_ENTITY_MEM		2	/* memory controller	*/
+#define PAT_ENTITY_SBA		3	/* system bus adapter	*/
+#define PAT_ENTITY_LBA		4	/* local bus adapter	*/
+#define PAT_ENTITY_PBC		5	/* processor bus converter */
+#define PAT_ENTITY_XBC		6	/* crossbar fabric connect */
+#define PAT_ENTITY_RC		7	/* fabric interconnect	*/
+
+/* PDC_PAT_CELL_MODULE address range type values */
+#define PAT_PBNUM		0	/* PCI Bus Number	*/
+#define PAT_LMMIO		1	/* < 4G MMIO Space	*/
+#define PAT_GMMIO		2	/* > 4G MMIO Space	*/
+#define PAT_NPIOP		3	/* Non Postable I/O Port Space */
+#define PAT_PIOP		4	/* Postable I/O Port Space */
+#define PAT_AHPA		5	/* Additional HPA Space	*/
+#define PAT_UFO			6	/* HPA Space (UFO for Mariposa) */
+#define PAT_GNIP		7	/* GNI Reserved Space	*/
+
+
+/* PDC PAT CHASSIS LOG */
+#define PDC_PAT_CHASSIS_LOG	65L	/* Platform logging & forward
+					 ** progress functions	*/
+#define PDC_PAT_CHASSIS_WRITE_LOG	0L /* Write Log Entry	*/
+#define PDC_PAT_CHASSIS_READ_LOG	1L /* Read  Log Entry	*/
+
+
+/* PDC PAT CPU  */
+#define PDC_PAT_CPU		67L	/* Interface to CPU configuration
+					 * within the protection domain */
+#define PDC_PAT_CPU_INFO		0L /* Return CPU config info	*/
+#define PDC_PAT_CPU_DELETE		1L /* Delete CPU		*/
+#define PDC_PAT_CPU_ADD			2L /* Add    CPU		*/
+#define PDC_PAT_CPU_GET_NUMBER		3L /* Return CPU Number		*/
+#define PDC_PAT_CPU_GET_HPA		4L /* Return CPU HPA		*/
+#define PDC_PAT_CPU_STOP            	5L /* Stop   CPU		*/
+#define PDC_PAT_CPU_RENDEZVOUS      	6L /* Rendezvous CPU		*/
+#define PDC_PAT_CPU_GET_CLOCK_INFO  	7L /* Return CPU Clock info	*/
+#define PDC_PAT_CPU_GET_RENDEZVOUS_STATE 8L /* Return Rendezvous State	*/
+#define PDC_PAT_CPU_PLUNGE_FABRIC	128L /* Plunge Fabric		*/
+#define PDC_PAT_CPU_UPDATE_CACHE_CLEANSING 129L /* Manipulate Cache 
+                                                 * Cleansing Mode	*/
+
+/*  PDC PAT EVENT */
+#define PDC_PAT_EVENT		68L	/* Interface to Platform Events */
+#define PDC_PAT_EVENT_GET_CAPS		0L /* Get Capabilities		*/
+#define PDC_PAT_EVENT_SET_MODE		1L /* Set Notification Mode	*/
+#define PDC_PAT_EVENT_SCAN		2L /* Scan Event		*/
+#define PDC_PAT_EVENT_HANDLE		3L /* Handle Event		*/
+#define PDC_PAT_EVENT_GET_NB_CALL	4L /* Get Non-Blocking call Args*/
+
+/*  PDC PAT HPMC */
+#define PDC_PAT_HPMC		70L	/* Cause processor to go into spin
+					 ** loop, and wait for wake up from
+					 ** Monarch Processor		*/
+#define PDC_PAT_HPMC_RENDEZ_CPU		0L /* go into spin loop		*/
+#define PDC_PAT_HPMC_SET_PARAMS		1L /* Allows OS to specify intr which PDC 
+                                        * will use to interrupt OS during machine
+                                        * check rendezvous		*/
+
+/* parameters for PDC_PAT_HPMC_SET_PARAMS */
+#define HPMC_SET_PARAMS_INTR		1L /* Rendezvous Interrupt	*/
+#define HPMC_SET_PARAMS_WAKE		2L /* Wake up processor		*/
+
+/*  PDC PAT IO */
+#define PDC_PAT_IO		71L	/* On-line services for I/O modules */
+#define PDC_PAT_IO_GET_SLOT_STATUS	 5L /* Get Slot Status Info	*/
+#define PDC_PAT_IO_GET_LOC_FROM_HARDWARE 6L /* Get Physical Location from */
+                                            /* Hardware Path		*/
+#define PDC_PAT_IO_GET_HARDWARE_FROM_LOC 7L /* Get Hardware Path from 
+                                             * Physical Location	*/
+#define PDC_PAT_IO_GET_PCI_CONFIG_FROM_HW 11L /* Get PCI Configuration
+                                               * Address from Hardware Path */
+#define PDC_PAT_IO_GET_HW_FROM_PCI_CONFIG 12L /* Get Hardware Path 
+                                               * from PCI Configuration Address */
+#define PDC_PAT_IO_READ_HOST_BRIDGE_INFO  13L /* Read Host Bridge State Info */
+#define PDC_PAT_IO_CLEAR_HOST_BRIDGE_INFO 14L /* Clear Host Bridge State Info*/
+#define PDC_PAT_IO_GET_PCI_ROUTING_TABLE_SIZE 15L /* Get PCI INT Routing Table 
+                                                   * Size		*/
+#define PDC_PAT_IO_GET_PCI_ROUTING_TABLE  16L /* Get PCI INT Routing Table */
+#define PDC_PAT_IO_GET_HINT_TABLE_SIZE    17L /* Get Hint Table Size	*/
+#define PDC_PAT_IO_GET_HINT_TABLE	18L /* Get Hint Table		*/
+#define PDC_PAT_IO_PCI_CONFIG_READ	19L /* PCI Config Read		*/
+#define PDC_PAT_IO_PCI_CONFIG_WRITE	20L /* PCI Config Write		*/
+#define PDC_PAT_IO_GET_NUM_IO_SLOTS	21L /* Get Number of I/O Bay Slots in 
+                                       		  * Cabinet		*/
+#define PDC_PAT_IO_GET_LOC_IO_SLOTS	22L /* Get Physical Location of I/O */
+                                   	    /* Bay Slots in Cabinet	*/
+#define PDC_PAT_IO_BAY_STATUS_INFO	28L /* Get I/O Bay Slot Status Info */
+#define PDC_PAT_IO_GET_PROC_VIEW	29L /* Get Processor view of IO address */
+#define PDC_PAT_IO_PROG_SBA_DIR_RANGE	30L /* Program directed range	*/
+
+/* PDC PAT MEM */
+#define PDC_PAT_MEM		72L  /* Manage memory page deallocation */
+#define PDC_PAT_MEM_PD_INFO     	0L /* Return PDT info for PD	*/
+#define PDC_PAT_MEM_PD_CLEAR    	1L /* Clear PDT for PD		*/
+#define PDC_PAT_MEM_PD_READ     	2L /* Read PDT entries for PD	*/
+#define PDC_PAT_MEM_PD_RESET    	3L /* Reset clear bit for PD	*/
+#define PDC_PAT_MEM_CELL_INFO   	5L /* Return PDT info For Cell	*/
+#define PDC_PAT_MEM_CELL_CLEAR  	6L /* Clear PDT For Cell	*/
+#define PDC_PAT_MEM_CELL_READ   	7L /* Read PDT entries For Cell	*/
+#define PDC_PAT_MEM_CELL_RESET  	8L /* Reset clear bit For Cell	*/
+#define PDC_PAT_MEM_SETGM	  	9L /* Set Golden Memory value	*/
+#define PDC_PAT_MEM_ADD_PAGE    	10L /* ADDs a page to the cell	*/
+#define PDC_PAT_MEM_ADDRESS     	11L /* Get Physical Location From*/
+					    /* Memory Address		*/
+#define PDC_PAT_MEM_GET_TXT_SIZE   	12L /* Get Formatted Text Size	*/
+#define PDC_PAT_MEM_GET_PD_TXT     	13L /* Get PD Formatted Text	*/
+#define PDC_PAT_MEM_GET_CELL_TXT   	14L /* Get Cell Formatted Text	*/
+#define PDC_PAT_MEM_RD_STATE_INFO  	15L /* Read Mem Module State Info*/
+#define PDC_PAT_MEM_CLR_STATE_INFO 	16L /*Clear Mem Module State Info*/
+#define PDC_PAT_MEM_CLEAN_RANGE    	128L /*Clean Mem in specific range*/
+#define PDC_PAT_MEM_GET_TBL_SIZE   	131L /* Get Memory Table Size	*/
+#define PDC_PAT_MEM_GET_TBL        	132L /* Get Memory Table	*/
+
+/* PDC PAT NVOLATILE */
+#define PDC_PAT_NVOLATILE	73L	   /* Access Non-Volatile Memory*/
+#define PDC_PAT_NVOLATILE_READ		0L /* Read Non-Volatile Memory	*/
+#define PDC_PAT_NVOLATILE_WRITE		1L /* Write Non-Volatile Memory	*/
+#define PDC_PAT_NVOLATILE_GET_SIZE	2L /* Return size of NVM	*/
+#define PDC_PAT_NVOLATILE_VERIFY	3L /* Verify contents of NVM	*/
+#define PDC_PAT_NVOLATILE_INIT		4L /* Initialize NVM		*/
+
+/* PDC PAT PD */
+#define PDC_PAT_PD		74L	    /* Protection Domain Info	*/
+#define PDC_PAT_PD_GET_ADDR_MAP		0L  /* Get Address Map		*/
+
+/* PDC_PAT_PD_GET_ADDR_MAP entry types */
+#define PAT_MEMORY_DESCRIPTOR		1
+
+/* PDC_PAT_PD_GET_ADDR_MAP memory types */
+#define PAT_MEMTYPE_MEMORY		0
+#define PAT_MEMTYPE_FIRMWARE		4
+
+/* PDC_PAT_PD_GET_ADDR_MAP memory usage */
+#define PAT_MEMUSE_GENERAL		0
+#define PAT_MEMUSE_GI			128
+#define PAT_MEMUSE_GNI			129
+#endif /* __LP64__ */
 
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
 
+extern int pdc_type;
+
+/* Values for pdc_type */
+#define PDC_TYPE_ILLEGAL	-1
+#define PDC_TYPE_PAT		 0 /* 64-bit PAT-PDC */
+#define PDC_TYPE_SYSTEM_MAP	 1 /* 32-bit, but supports PDC_SYSTEM_MAP */
+#define PDC_TYPE_SNAKE		 2 /* Doesn't support SYSTEM_MAP */
+
+#define is_pdc_pat()    (pdc_type == PDC_TYPE_PAT)
+
+struct pdc_chassis_info {       /* for PDC_CHASSIS_INFO */
+	unsigned long actcnt;   /* actual number of bytes returned */
+	unsigned long maxcnt;   /* maximum number of bytes that could be returned */
+};
+
+struct pdc_coproc_cfg {         /* for PDC_COPROC_CFG */
+        unsigned long ccr_functional;
+        unsigned long ccr_present;
+        unsigned long revision;
+        unsigned long model;
+};
+
 struct pdc_model {		/* for PDC_MODEL */
 	unsigned long hversion;
 	unsigned long sversion;
@@ -178,33 +500,22 @@
 	unsigned long arch_rev;
 	unsigned long pot_key;
 	unsigned long curr_key;
-	unsigned long pad[32-9];
-} __attribute__((aligned(8))) ;
-
-
-#if 0
-struct pdc_chassis_warn {		/* for PDC_CHASSIS */
-	unsigned long warn;
-	unsigned long pad[32-1];
-} __attribute__((aligned(8))) ;
-#endif
+};
 
-struct pdc_model_sysmodel {	/* for PDC_MODEL_SYSMODEL */
-	unsigned long mod_len;
-	unsigned long pad[32-1];
-} __attribute__((aligned(8))) ;
+/* Values for PDC_MODEL_CAPABILITES non-equivalent virtual aliasing support */
 
-struct pdc_model_cpuid	 {	/* for PDC_MODEL_CPU_ID */
-	unsigned long cpuid;
-	unsigned long pad[32-1];
-} __attribute__((aligned(8))) ;
+#define PDC_MODEL_IOPDIR_FDC            (1 << 2)        /* see sba_iommu.c */
+#define PDC_MODEL_NVA_MASK		(3 << 4)
+#define PDC_MODEL_NVA_SUPPORTED		(0 << 4)
+#define PDC_MODEL_NVA_SLOW		(1 << 4)
+#define PDC_MODEL_NVA_UNSUPPORTED	(3 << 4)
 
 struct pdc_cache_cf {		/* for PDC_CACHE  (I/D-caches) */
     unsigned long
 #ifdef __LP64__
 		cc_padW:32,
 #endif
-		cc_alias:4,	/* alias boundaries for virtual adresses   */
+		cc_alias:4,	/* alias boundaries for virtual addresses   */
 		cc_block: 4,	/* to determine most efficient stride */
 		cc_line	: 3,	/* maximum amount written back as a result of store (multiple of 16 bytes) */
 		cc_pad0 : 2,	/* reserved */
@@ -263,14 +574,7 @@
 	unsigned long	dt_off_stride;
 	unsigned long	dt_off_count;
 	unsigned long	dt_loop;
-	/* padded to 32 entries... */
-	unsigned long 	pad[32-30];
-} __attribute__((aligned(8))) ;
-
-struct pdc_hpa {      /* PDC_HPA */
-	unsigned long	hpa;
-	unsigned long	filler[31];
-} __attribute__((aligned(8))) ;
+};
 
 #if 0
 /* If you start using the next struct, you'll have to adjust it to
@@ -287,14 +591,14 @@
 	unsigned char	rev;
 	unsigned char	dep;
 	unsigned char	features;
-	unsigned char	filler1;
+	unsigned char	pad1;
 	unsigned int	checksum:16;
 	unsigned int	length:16;
-	unsigned int    filler[15];
+	unsigned int    pad[15];
 } __attribute__((aligned(8))) ;
 #endif
 
-#ifndef __LP64__
+#ifndef CONFIG_PA20
 /* no BLTBs in pa2.0 processors */
 struct pdc_btlb_info_range {
 	__u8 res00;
@@ -308,53 +612,95 @@
 	unsigned int max_size;	/* maximum size of BTLB in pages */
 	struct pdc_btlb_info_range fixed_range_info;
 	struct pdc_btlb_info_range variable_range_info;
-	unsigned int pad[32-4];
-} __attribute__((aligned(8))) ;
-#endif
+};
 
-struct pdc_tlb {		/* for PDC_TLB */
-	unsigned long min_size;
-	unsigned long max_size;
-	unsigned long pad[32-2];
-} __attribute__((aligned(8))) ;
+#endif /* !CONFIG_PA20 */
+
+#ifdef __LP64__
+struct pdc_memory_table_raddr { /* PDC_MEM/PDC_MEM_TABLE (return info) */
+	unsigned long entries_returned;
+	unsigned long entries_total;
+};
+
+struct pdc_memory_table {       /* PDC_MEM/PDC_MEM_TABLE (arguments) */
+	unsigned long paddr;
+	unsigned int  pages;
+	unsigned int  reserved;
+};
+#endif /* __LP64__ */
 
-struct pdc_system_map { /* PDC_SYTEM_MAP/FIND_MODULE */
-	void * mod_addr;
+struct pdc_system_map_mod_info { /* PDC_SYSTEM_MAP/FIND_MODULE */
+	unsigned long mod_addr;
 	unsigned long mod_pgs;
 	unsigned long add_addrs;
-	unsigned long filler[29];
-} __attribute__((aligned(8))) ;
+};
 
-/*
- * Device path specifications used by PDC.
- */
-struct pdc_module_path {
+struct pdc_system_map_addr_info { /* PDC_SYSTEM_MAP/FIND_ADDRESS */
+	unsigned long mod_addr;
+	unsigned long mod_pgs;
+};
+
+struct hardware_path {
 	char  flags;	/* see bit definitions below */
 	char  bc[6];	/* Bus Converter routing info to a specific */
 			/* I/O adaptor (< 0 means none, > 63 resvd) */
 	char  mod;	/* fixed field of specified module */
-	unsigned int layers[6]; /* device-specific info (ctlr #, unit # ...) */
-} __attribute__((aligned(8))) ;
+};
 
-#ifndef __LP64__
-/* Probably needs 64-bit porting -PB */
-struct pdc_memory_map {	/* PDC_MEMORY_MAP */
-	unsigned int hpa;	/* mod's register set address */
-	unsigned int more_pgs;	/* number of additional I/O pgs */
-} __attribute__((aligned(8))) ;
+/*
+ * Device path specifications used by PDC.
+ */
+struct pdc_module_path {
+	struct hardware_path path;
+	unsigned int layers[6]; /* device-specific info (ctlr #, unit # ...) */
+};
 
-struct pdc_lan_station_id {	/* PDC_LAN_STATION_ID */
-	unsigned char addr[PDC_LAN_STATION_ID_SIZE];
-	unsigned char pad0[2];
-	int pad1[30];
+#ifndef CONFIG_PA20
+/* Only used on some pre-PA2.0 boxes */
+struct pdc_memory_map {		/* PDC_MEMORY_MAP */
+	unsigned long hpa;	/* mod's register set address */
+	unsigned long more_pgs;	/* number of additional I/O pgs */
 };
 #endif
 
 struct pdc_tod {
 	unsigned long tod_sec; 
 	unsigned long tod_usec;
-	long pad[30];
-} __attribute__((aligned(8))) ;
+};
+
+#ifdef __LP64__
+struct pdc_pat_cell_num {
+	unsigned long cell_num;
+	unsigned long cell_loc;
+};
+
+struct pdc_pat_cpu_num {
+	unsigned long cpu_num;
+	unsigned long cpu_loc;
+};
+
+struct pdc_pat_pd_addr_map_entry {
+	unsigned char entry_type;       /* 1 = Memory Descriptor Entry Type */
+	unsigned char reserve1[5];
+	unsigned char memory_type;
+	unsigned char memory_usage;
+	unsigned long paddr;
+	unsigned int  pages;            /* Length in 4K pages */
+	unsigned int  reserve2;
+	unsigned long cell_map;
+};
+
+/* FIXME: mod[508] should really be a union of the various mod components */
+struct pdc_pat_cell_mod_maddr_block {	/* PDC_PAT_CELL_MODULE */
+	unsigned long cba;              /* function 0 configuration space address */
+	unsigned long mod_info;         /* module information */
+	unsigned long mod_location;     /* physical location of the module */
+	struct hardware_path mod_path;	/* hardware path */
+	unsigned long mod[508];		/* PAT cell module components */
+};
+
+typedef struct pdc_pat_cell_mod_maddr_block pdc_pat_cell_mod_maddr_block_t;
+#endif /* __LP64__ */
 
 /* architected results from PDC_PIM/transfer hpmc on a PA1.1 machine */
 
@@ -490,7 +836,7 @@
 
 #ifndef __ASSEMBLY__
 
-#define	PAGE0	((struct zeropage *)0xc0000000)
+#define PAGE0   ((struct zeropage *)__PAGE_OFFSET)
 
 struct zeropage {
 	/* [0x000] initialize vectors (VEC) */
@@ -557,71 +903,105 @@
 #define BOOT_CONSOLE_PATH_OFFSET 0x3a8
 
 #ifndef __ASSEMBLY__
+void pdc_console_init(void);	/* in pdc_console.c */
+void pdc_console_restart(void);
 
-struct pdc_pat_io_num {
-	unsigned long num;
-	unsigned long reserved[31];
-};
-
-
-
-extern void pdc_console_init(void);
-extern int  pdc_getc(void);	/* wait for char */
-extern void pdc_putc(unsigned char);	/* print char */
-
+void setup_pdc(void);		/* in inventory.c */
 
 /* wrapper-functions from pdc.c */
 
-int pdc_add_valid(void *address);
-int pdc_hpa_processor(void *address);
-#if 0
-int pdc_hpa_modules(void *address);
-#endif
-int pdc_iodc_read(void *address, void *hpa, unsigned int index,
+int pdc_add_valid(unsigned long address);
+int pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len);
+int pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info);
+int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index,
 		  void *iodc_data, unsigned int iodc_data_size);
-int pdc_system_map_find_mods(void *pdc_mod_info, void *mod_path, int index);
+int pdc_system_map_find_mods(struct pdc_system_map_mod_info *pdc_mod_info,
+			     struct pdc_module_path *mod_path, long mod_index);
+int pdc_system_map_find_addrs(struct pdc_system_map_addr_info *pdc_addr_info, 
+			      long mod_index, long addr_index);
 int pdc_model_info(struct pdc_model *model);
-int pdc_model_sysmodel(char  *name);
-int pdc_model_cpuid(struct pdc_model_cpuid *cpu_id);
-int pdc_model_versions(struct pdc_model_cpuid *cpu_id, int id);
+int pdc_model_sysmodel(char *name);
+int pdc_model_cpuid(unsigned long *cpu_id);
+int pdc_model_versions(unsigned long *versions, int id);
+int pdc_model_capabilities(unsigned long *capabilities);
 int pdc_cache_info(struct pdc_cache_info *cache);
-#ifndef __LP64__
-int pdc_btlb_info( struct pdc_btlb_info *btlb);
-int pdc_lan_station_id( char *lan_addr, void *net_hpa);
-#endif
-int pdc_mem_map_hpa(void *r_addr, void *mod_path);
-
-extern int pdc_chassis_disp(unsigned long disp);
-extern int pdc_chassis_info(void *pdc_result, void *chassis_info, unsigned long len);
+#ifndef CONFIG_PA20
+int pdc_btlb_info(struct pdc_btlb_info *btlb);
+int pdc_mem_map_hpa(struct pdc_memory_map *r_addr, struct pdc_module_path *mod_path);
+#endif /* !CONFIG_PA20 */
+int pdc_lan_station_id(char *lan_addr, unsigned long net_hpa);
 
-#ifdef __LP64__
-int pdc_pat_get_irt_size(void *r_addr, unsigned long cell_num);
-int pdc_pat_get_irt(void *r_addr, unsigned long cell_num);
-#else
-/* No PAT support for 32-bit kernels...sorry */
-#define pdc_pat_get_irt_size(r_addr, cell_numn)	PDC_RET_NE_PROC
-#define pdc_pat_get_irt(r_addr, cell_num)	PDC_RET_NE_PROC
-#endif
-int pdc_pci_irt_size(void *r_addr, void *hpa);
-int pdc_pci_irt(void *r_addr, void *hpa, void *tbl);
+int pdc_pci_irt_size(unsigned long *num_entries, unsigned long hpa);
+int pdc_pci_irt(unsigned long num_entries, unsigned long hpa, void *tbl);
 
+int pdc_get_initiator(struct hardware_path *hwpath, unsigned char *scsi_id, unsigned long *period, char *width, char *mode);
 int pdc_tod_read(struct pdc_tod *tod);
 int pdc_tod_set(unsigned long sec, unsigned long usec);
 
-/* on all currently-supported platforms, IODC I/O calls are always
- * 32-bit calls, and MEM_PDC calls are always the same width as the OS.
- * This means Cxxx boxes can't run wide kernels right now. -PB
- *
- * Note that some PAT boxes may have 64-bit IODC I/O...
- */
 #ifdef __LP64__
-#   define mem_pdc_call(args...) real64_call(0L, ##args)
-#else
-#   define mem_pdc_call(args...) real32_call(0L, ##args)
+int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr,
+		struct pdc_memory_table *tbl, unsigned long entries);
 #endif
-/* yes 'int', not 'long' -- IODC I/O is always 32-bit stuff */
-extern long real64_call(unsigned long function, ...);
-extern long real32_call(unsigned long function, ...);
+
+int pdc_do_firm_test_reset(unsigned long ftc_bitmap);
+int pdc_do_reset(void);
+int pdc_soft_power_info(unsigned long *power_reg);
+int pdc_soft_power_button(int sw_control);
+void pdc_suspend_usb(void);
+int pdc_iodc_getc(void);
+void pdc_iodc_putc(unsigned char c);
+void pdc_iodc_outc(unsigned char c);
+
+void pdc_emergency_unlock(void);
+int pdc_sti_call(unsigned long func, unsigned long flags,
+                 unsigned long inptr, unsigned long outputr,
+                 unsigned long glob_cfg);
+
+#ifdef __LP64__
+int pdc_pat_cell_get_number(struct pdc_pat_cell_num *cell_info);
+int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long mod,
+			unsigned long view_type, void *mem_addr);
+int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, void *hpa);
+int pdc_pat_get_irt_size(unsigned long *num_entries, unsigned long cell_num);
+int pdc_pat_get_irt(void *r_addr, unsigned long cell_num);
+int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr, 
+			    unsigned long count, unsigned long offset);
+
+/********************************************************************
+* PDC_PAT_CELL[Return Cell Module] memaddr[0] conf_base_addr
+* ----------------------------------------------------------
+* Bit  0 to 51 - conf_base_addr
+* Bit 52 to 62 - reserved
+* Bit       63 - endianess bit
+********************************************************************/
+#define PAT_GET_CBA(value) ((value) & 0xfffffffffffff000UL)
+
+/********************************************************************
+* PDC_PAT_CELL[Return Cell Module] memaddr[1] mod_info
+* ----------------------------------------------------
+* Bit  0 to  7 - entity type
+*    0 = central agent,            1 = processor,
+*    2 = memory controller,        3 = system bus adapter,
+*    4 = local bus adapter,        5 = processor bus converter,
+*    6 = crossbar fabric connect,  7 = fabric interconnect,
+*    8 to 254 reserved,            255 = unknown.
+* Bit  8 to 15 - DVI
+* Bit 16 to 23 - IOC functions
+* Bit 24 to 39 - reserved
+* Bit 40 to 63 - mod_pages
+*    number of 4K pages a module occupies starting at conf_base_addr
+********************************************************************/
+#define PAT_GET_ENTITY(value)	(((value) >> 56) & 0xffUL)
+#define PAT_GET_DVI(value)	(((value) >> 48) & 0xffUL)
+#define PAT_GET_IOC(value)	(((value) >> 40) & 0xffUL)
+#define PAT_GET_MOD_PAGES(value)(((value) & 0xffffffUL)
+
+#else /* !__LP64__ */
+/* No PAT support for 32-bit kernels...sorry */
+#define pdc_pat_get_irt_size(num_entries, cell_numn)	PDC_BAD_PROC
+#define pdc_pat_get_irt(r_addr, cell_num)	PDC_BAD_PROC
+#endif /* !__LP64__ */
+
 extern void pdc_init(void);
 
 #endif /* __ASSEMBLY__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/pdcpat.h linux-2.4.20/include/asm-parisc/pdcpat.h
--- linux-2.4.19/include/asm-parisc/pdcpat.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/pdcpat.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,247 +0,0 @@
-#ifndef __PARISC_PATPDC_H
-#define __PARISC_PATPDC_H
-
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) Hewlett Packard (Paul Bame <bame@puffin.external.hp.com>)
- * Copyright 2000 (c) Grant Grundler <grundler@puffin.external.hp.com>
- */
-
-
-/* PDC PAT CELL */
-#define PDC_PAT_CELL           	64L   /* Interface for gaining and 
-                                         * manipulatin g cell state within PD */
-#define PDC_PAT_CELL_GET_NUMBER    0L   /* Return Cell number */
-#define PDC_PAT_CELL_GET_INFO      1L   /* Returns info about Cell */
-#define PDC_PAT_CELL_MODULE        2L   /* Returns info about Module */
-#define PDC_PAT_CELL_SET_ATTENTION 9L   /* Set Cell Attention indicator */
-#define PDC_PAT_CELL_NUMBER_TO_LOC 10L   /* Cell Number -> Location */
-#define PDC_PAT_CELL_WALK_FABRIC   11L   /* Walk the Fabric */
-#define PDC_PAT_CELL_GET_RDT_SIZE  12L   /* Return Route Distance Table Sizes */
-#define PDC_PAT_CELL_GET_RDT       13L   /* Return Route Distance Tables */
-#define PDC_PAT_CELL_GET_LOCAL_PDH_SZ 14L /* Read Local PDH Buffer Size */
-#define PDC_PAT_CELL_SET_LOCAL_PDH    15L  /* Write Local PDH Buffer */
-#define PDC_PAT_CELL_GET_REMOTE_PDH_SZ 16L /* Return Remote PDH Buffer Size */
-#define PDC_PAT_CELL_GET_REMOTE_PDH 17L /* Read Remote PDH Buffer */
-#define PDC_PAT_CELL_GET_DBG_INFO   128L  /* Return DBG Buffer Info */
-#define PDC_PAT_CELL_CHANGE_ALIAS   129L  /* Change Non-Equivalent Alias Chacking */
-
-
-/*
-** Arg to PDC_PAT_CELL_MODULE memaddr[4]
-**
-** Addresses on the Merced Bus != all Runway Bus addresses.
-** This is intended for programming SBA/LBA chips range registers.
-*/
-#define IO_VIEW      0UL
-#define PA_VIEW      1UL
-
-/* PDC_PAT_CELL_MODULE entity type values */
-#define	PAT_ENTITY_CA	0	/* central agent */
-#define	PAT_ENTITY_PROC	1	/* processor */
-#define	PAT_ENTITY_MEM	2	/* memory controller */
-#define	PAT_ENTITY_SBA	3	/* system bus adapter */
-#define	PAT_ENTITY_LBA	4	/* local bus adapter */
-#define	PAT_ENTITY_PBC	5	/* processor bus converter */
-#define	PAT_ENTITY_XBC	6	/* crossbar fabric connect */
-#define	PAT_ENTITY_RC	7	/* fabric interconnect */
-
-/* PDC_PAT_CELL_MODULE address range type values */
-#define PAT_PBNUM           0         /* PCI Bus Number */
-#define PAT_LMMIO           1         /* < 4G MMIO Space */
-#define PAT_GMMIO           2         /* > 4G MMIO Space */
-#define PAT_NPIOP           3         /* Non Postable I/O Port Space */
-#define PAT_PIOP            4         /* Postable I/O Port Space */
-#define PAT_AHPA            5         /* Addional HPA Space */
-#define PAT_UFO             6         /* HPA Space (UFO for Mariposa) */
-#define PAT_GNIP            7         /* GNI Reserved Space */
-
-
-/* PDC PAT CHASSIS LOG */
-
-#define PDC_PAT_CHASSIS_LOG		65L /* Platform logging & forward
-					    ** progress functions */
-#define PDC_PAT_CHASSIS_WRITE_LOG    	0L /* Write Log Entry */
-#define PDC_PAT_CHASSIS_READ_LOG     	1L /* Read  Log Entry */
-
-/* PDC PAT CPU  */
-
-#define PDC_PAT_CPU                	67L /* Interface to CPU configuration
-                                        	* within the protection domain */
-#define PDC_PAT_CPU_INFO            	0L /* Return CPU config info */
-#define PDC_PAT_CPU_DELETE          	1L /* Delete CPU */
-#define PDC_PAT_CPU_ADD             	2L /* Add    CPU */
-#define PDC_PAT_CPU_GET_NUMBER      	3L /* Return CPU Number */
-#define PDC_PAT_CPU_GET_HPA         	4L /* Return CPU HPA */
-#define PDC_PAT_CPU_STOP            	5L /* Stop   CPU */
-#define PDC_PAT_CPU_RENDEZVOUS      	6L /* Rendezvous CPU */
-#define PDC_PAT_CPU_GET_CLOCK_INFO  	7L /* Return CPU Clock info */
-#define PDC_PAT_CPU_GET_RENDEZVOUS_STATE 8L /* Return Rendezvous State */
-#define PDC_PAT_CPU_PLUNGE_FABRIC 	128L /* Plunge Fabric */
-#define PDC_PAT_CPU_UPDATE_CACHE_CLEANSING 129L /* Manipulate Cache 
-                                                 * Cleansing Mode */
-/*  PDC PAT EVENT */
-
-#define PDC_PAT_EVENT              	68L /* Interface to Platform Events */
-#define PDC_PAT_EVENT_GET_CAPS     	0L /* Get Capabilities */
-#define PDC_PAT_EVENT_SET_MODE     	1L /* Set Notification Mode */
-#define PDC_PAT_EVENT_SCAN         	2L /* Scan Event */
-#define PDC_PAT_EVENT_HANDLE       	3L /* Handle Event */
-#define PDC_PAT_EVENT_GET_NB_CALL  	4L /* Get Non-Blocking call Args */
-
-/*  PDC PAT HPMC */
-
-#define PDC_PAT_HPMC               70L /* Cause processor to go into spin
-				       ** loop, and wait for wake up from
-				       ** Monarch Processor */
-#define PDC_PAT_HPMC_RENDEZ_CPU     0L /* go into spin loop */
-#define PDC_PAT_HPMC_SET_PARAMS     1L /* Allows OS to specify intr which PDC 
-                                        * will use to interupt OS during machine
-                                        * check rendezvous */
-
-/* parameters for PDC_PAT_HPMC_SET_PARAMS: */
-#define HPMC_SET_PARAMS_INTR 	    1L /* Rendezvous Interrupt */
-#define HPMC_SET_PARAMS_WAKE 	    2L /* Wake up processor */
-
-/*  PDC PAT IO */
-
-#define PDC_PAT_IO                  71L /* On-line services for I/O modules */
-#define PDC_PAT_IO_GET_SLOT_STATUS   	5L /* Get Slot Status Info*/
-#define PDC_PAT_IO_GET_LOC_FROM_HARDWARE 6L /* Get Physical Location from */
-                                            /* Hardware Path */
-#define PDC_PAT_IO_GET_HARDWARE_FROM_LOC 7L /* Get Hardware Path from 
-                                             * Physical Location */
-#define PDC_PAT_IO_GET_PCI_CONFIG_FROM_HW 11L /* Get PCI Configuration
-                                               * Address from Hardware Path */
-#define PDC_PAT_IO_GET_HW_FROM_PCI_CONFIG 12L /* Get Hardware Path 
-                                               * from PCI Configuration Address */
-#define PDC_PAT_IO_READ_HOST_BRIDGE_INFO 13L  /* Read Host Bridge State Info */
-#define PDC_PAT_IO_CLEAR_HOST_BRIDGE_INFO 14L /* Clear Host Bridge State Info*/
-#define PDC_PAT_IO_GET_PCI_ROUTING_TABLE_SIZE 15L /* Get PCI INT Routing Table 
-                                                   * Size */
-#define PDC_PAT_IO_GET_PCI_ROUTING_TABLE  16L /* Get PCI INT Routing Table */
-#define PDC_PAT_IO_GET_HINT_TABLE_SIZE 	17L /* Get Hint Table Size */
-#define PDC_PAT_IO_GET_HINT_TABLE   	18L /* Get Hint Table */
-#define PDC_PAT_IO_PCI_CONFIG_READ  	19L /* PCI Config Read */
-#define PDC_PAT_IO_PCI_CONFIG_WRITE 	20L /* PCI Config Write */
-#define PDC_PAT_IO_GET_NUM_IO_SLOTS 	21L /* Get Number of I/O Bay Slots in 
-                                       		  * Cabinet */
-#define PDC_PAT_IO_GET_LOC_IO_SLOTS 	22L /* Get Physical Location of I/O */
-                                   		     /* Bay Slots in Cabinet */
-#define PDC_PAT_IO_BAY_STATUS_INFO  	28L /* Get I/O Bay Slot Status Info */
-#define PDC_PAT_IO_GET_PROC_VIEW        29L /* Get Processor view of IO address */
-#define PDC_PAT_IO_PROG_SBA_DIR_RANGE   30L /* Program directed range */
-
-/* PDC PAT MEM */
-
-#define PDC_PAT_MEM             	72L /* Manage memory page deallocation */
-#define PDC_PAT_MEM_PD_INFO     	0L /* Return PDT info for PD       */
-#define PDC_PAT_MEM_PD_CLEAR    	1L /* Clear PDT for PD             */
-#define PDC_PAT_MEM_PD_READ     	2L /* Read PDT entries for PD      */
-#define PDC_PAT_MEM_PD_RESET    	3L /* Reset clear bit for PD       */
-#define PDC_PAT_MEM_CELL_INFO   	5L /* Return PDT info For Cell     */
-#define PDC_PAT_MEM_CELL_CLEAR  	6L /* Clear PDT For Cell           */
-#define PDC_PAT_MEM_CELL_READ   	7L /* Read PDT entries For Cell    */
-#define PDC_PAT_MEM_CELL_RESET  	8L /* Reset clear bit For Cell     */
-#define PDC_PAT_MEM_SETGM	  	9L /* Set Golden Memory value      */
-#define PDC_PAT_MEM_ADD_PAGE    	10L /* ADDs a page to the cell      */
-#define PDC_PAT_MEM_ADDRESS     	11L /* Get Physical Location From   */
-                                    		 /* Memory Address               */
-#define PDC_PAT_MEM_GET_TXT_SIZE   	12L /* Get Formatted Text Size   */
-#define PDC_PAT_MEM_GET_PD_TXT     	13L /* Get PD Formatted Text     */
-#define PDC_PAT_MEM_GET_CELL_TXT   	14L /* Get Cell Formatted Text   */
-#define PDC_PAT_MEM_RD_STATE_INFO  	15L /* Read Mem Module State Info*/
-#define PDC_PAT_MEM_CLR_STATE_INFO 	16L /*Clear Mem Module State Info*/
-#define PDC_PAT_MEM_CLEAN_RANGE    	128L /*Clean Mem in specific range*/
-#define PDC_PAT_MEM_GET_TBL_SIZE   	131L /* Get Memory Table Size     */
-#define PDC_PAT_MEM_GET_TBL        	132L /* Get Memory Table          */
-
-/* PDC PAT NVOLATILE */
-
-#define PDC_PAT_NVOLATILE          	73L /* Access Non-Volatile Memory */
-#define PDC_PAT_NVOLATILE_READ      	0L /* Read Non-Volatile Memory   */
-#define PDC_PAT_NVOLATILE_WRITE     	1L /* Write Non-Volatile Memory  */
-#define PDC_PAT_NVOLATILE_GET_SIZE  	2L /* Return size of NVM         */
-#define PDC_PAT_NVOLATILE_VERIFY    	3L /* Verify contents of NVM     */
-#define PDC_PAT_NVOLATILE_INIT      	4L /* Initialize NVM             */
-
-#ifndef __ASSEMBLY__
-#include <linux/types.h>
-
-/*
-** PDC_PAT_CELL_GET_INFO return block
-*/
-typedef struct pdc_pat_cell_info_rtn_block {
-	unsigned long cpu_info;
-	unsigned long cell_info;
-	unsigned long cell_location;
-	unsigned long reo_location;
-	unsigned long mem_size;
-	unsigned long dimm_status;
-	unsigned long pdc_rev;
-	unsigned long fabric_info0;
-	unsigned long fabric_info1;
-	unsigned long fabric_info2;
-	unsigned long fabric_info3;
-	unsigned long reserved[21];
-} pdc_pat_cell_info_rtn_block_t;
-
-
-/* FIXME: mod[508] should really be a union of the various mod components */
-struct pdc_pat_cell_mod_maddr_block {	/* PDC_PAT_CELL_MODULE */
-	unsigned long cba;              /* function 0 configuration space address */
-	unsigned long mod_info;         /* module information */
-	unsigned long mod_location;     /* physical location of the module */
-	unsigned long mod_path;         /* module path (device path - layers) */
-	unsigned long mod[508];		/* PAT cell module components */
-} __attribute__((aligned(8))) ;
-
-typedef struct pdc_pat_cell_mod_maddr_block pdc_pat_cell_mod_maddr_block_t;
-
-
-extern int pdc_pat_cell_get_number(void *);
-extern int pdc_pat_cell_module(void *, unsigned long, unsigned long, unsigned long, void *);
-extern int pdc_pat_cell_num_to_loc(void *, unsigned long);
-
-/* Flag to indicate this is a PAT box...don't use this unless you
-** really have to...it might go away some day.
-*/
-#ifdef __LP64__
-extern int pdc_pat;     /* arch/parisc/kernel/inventory.c */
-#endif
-
-/********************************************************************
-* PDC_PAT_CELL[Return Cell Module] memaddr[0] conf_base_addr
-* ----------------------------------------------------------
-* Bit  0 to 51 - conf_base_addr
-* Bit 52 to 62 - reserved
-* Bit       63 - endianess bit
-********************************************************************/
-#define PAT_GET_CBA(value) ((value) & 0xfffffffffffff000UL)
-
-/********************************************************************
-* PDC_PAT_CELL[Return Cell Module] memaddr[1] mod_info
-* ----------------------------------------------------
-* Bit  0 to  7 - entity type
-*    0 = central agent,            1 = processor,
-*    2 = memory controller,        3 = system bus adapter,
-*    4 = local bus adapter,        5 = processor bus converter,
-*    6 = crossbar fabric connect,  7 = fabric interconnect,
-*    8 to 254 reserved,            255 = unknown.
-* Bit  8 to 15 - DVI
-* Bit 16 to 23 - IOC functions
-* Bit 24 to 39 - reserved
-* Bit 40 to 63 - mod_pages
-*    number of 4K pages a module occupies starting at conf_base_addr
-********************************************************************/
-#define PAT_GET_ENTITY(value)	(((value) >> 56) & 0xffUL)
-#define PAT_GET_DVI(value)	(((value) >> 48) & 0xffUL)
-#define PAT_GET_IOC(value)	(((value) >> 40) & 0xffUL)
-#define PAT_GET_MOD_PAGES(value)(((value) & 0xffffffUL)
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* ! __PARISC_PATPDC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/perf.h linux-2.4.20/include/asm-parisc/perf.h
--- linux-2.4.19/include/asm-parisc/perf.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/perf.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,74 @@
+#ifndef _ASM_PERF_H_
+#define _ASM_PERF_H_
+
+/* ioctls */
+#define PA_PERF_ON	_IO('p', 1)
+#define PA_PERF_OFF	_IOR('p', 2, unsigned int)
+#define PA_PERF_VERSION	_IOR('p', 3, int)
+
+#define PA_PERF_DEV	"perf"
+#define PA_PERF_MINOR	146
+
+/* Interface types */
+#define UNKNOWN_INTF    255
+#define ONYX_INTF         0
+#define CUDA_INTF         1
+
+/* Common Onyx and Cuda images */
+#define CPI                 0
+#define BUSUTIL             1
+#define TLBMISS             2
+#define TLBHANDMISS         3
+#define PTKN                4
+#define PNTKN               5
+#define IMISS               6
+#define DMISS               7
+#define DMISS_ACCESS        8 
+#define BIG_CPI 	    9
+#define BIG_LS		   10  
+#define BR_ABORT	   11
+#define ISNT		   12 
+#define QUADRANT           13
+#define RW_PDFET           14
+#define RW_WDFET           15
+#define SHLIB_CPI          16
+
+/* Cuda only Images */
+#define FLOPS              17
+#define CACHEMISS          18 
+#define BRANCHES           19             
+#define CRSTACK            20 
+#define I_CACHE_SPEC       21 
+#define MAX_CUDA_IMAGES    22 
+
+/* Onyx only Images */
+#define ADDR_INV_ABORT_ALU 17
+#define BRAD_STALL	   18 
+#define CNTL_IN_PIPEL	   19 
+#define DSNT_XFH	   20 
+#define FET_SIG1	   21 
+#define FET_SIG2	   22 
+#define G7_1		   23 
+#define G7_2		   24 
+#define G7_3 		   25
+#define G7_4		   26
+#define MPB_LABORT         27
+#define PANIC              28
+#define RARE_INST          29 
+#define RW_DFET            30 
+#define RW_IFET            31 
+#define RW_SDFET           32 
+#define SPEC_IFET          33 
+#define ST_COND0           34 
+#define ST_COND1           35 
+#define ST_COND2           36
+#define ST_COND3           37
+#define ST_COND4           38
+#define ST_UNPRED0         39 
+#define ST_UNPRED1         40 
+#define UNPRED             41 
+#define GO_STORE           42
+#define SHLIB_CALL         43
+#define MAX_ONYX_IMAGES    44
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/pgalloc.h linux-2.4.20/include/asm-parisc/pgalloc.h
--- linux-2.4.19/include/asm-parisc/pgalloc.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/pgalloc.h	2002-10-29 11:18:50.000000000 +0000
@@ -11,395 +11,293 @@
 #include <asm/pgtable.h>
 #include <asm/cache.h>
 
+#define flush_kernel_dcache_range(start,size) \
+	flush_kernel_dcache_range_asm((start), (start)+(size));
 
-/* Internal use D/I cache flushing routines... */
-/* XXX: these functions must not access memory between f[di]ce instructions. */
-
-static inline void __flush_dcache_range(unsigned long start, unsigned long size)
+static inline void
+flush_page_to_ram(struct page *page)
 {
-#if 0
-	register unsigned long count = (size / L1_CACHE_BYTES);
-	register unsigned long loop = cache_info.dc_loop;
-	register unsigned long i, j;
+}
 
-	if (size > 64 * 1024) {
-		/* Just punt and clear the whole damn thing */
-		flush_data_cache();
-		return;
-	}
+extern void flush_cache_all_local(void);
 
-	for(i = 0; i <= count; i++, start += L1_CACHE_BYTES)
-		for(j = 0; j < loop; j++)
-			fdce(start);
+#ifdef CONFIG_SMP
+static inline void flush_cache_all(void)
+{
+	smp_call_function((void (*)(void *))flush_cache_all_local, NULL, 1, 1);
+	flush_cache_all_local();
+}
 #else
-	flush_data_cache();
+#define flush_cache_all flush_cache_all_local
 #endif
-}
 
+#ifdef CONFIG_SMP
+#define flush_cache_mm(mm) flush_cache_all()
+#else
+#define flush_cache_mm(mm) flush_cache_all_local()
+#endif
 
-static inline void __flush_icache_range(unsigned long start, unsigned long size)
-{
-#if 0
-	register unsigned long count = (size / L1_CACHE_BYTES);
-	register unsigned long loop = cache_info.ic_loop;
-	register unsigned long i, j;
+/* The following value needs to be tuned and probably scaled with the
+ * cache size.
+ */
 
-	if (size > 64 * 1024) {
-		/* Just punt and clear the whole damn thing */
-		flush_instruction_cache();
-		return;
-	}
+#define FLUSH_THRESHOLD 0x80000
 
-	for(i = 0; i <= count; i++, start += L1_CACHE_BYTES)
-		for(j = 0; j < loop; j++)
-			fice(start);
+static inline void
+flush_user_dcache_range(unsigned long start, unsigned long end)
+{
+#ifdef CONFIG_SMP
+	flush_user_dcache_range_asm(start,end);
 #else
-	flush_instruction_cache();
+	if ((end - start) < FLUSH_THRESHOLD)
+		flush_user_dcache_range_asm(start,end);
+	else
+		flush_data_cache();
 #endif
 }
 
 static inline void
-flush_kernel_dcache_range(unsigned long start, unsigned long size)
+flush_user_icache_range(unsigned long start, unsigned long end)
 {
-	register unsigned long end = start + size;
-	register unsigned long i;
-
-	start &= ~(L1_CACHE_BYTES - 1);
-	for (i = start; i < end; i += L1_CACHE_BYTES) {
-		kernel_fdc(i);
-	}
-	asm volatile("sync" : : );
-	asm volatile("syncdma" : : );
+#ifdef CONFIG_SMP
+	flush_user_icache_range_asm(start,end);
+#else
+	if ((end - start) < FLUSH_THRESHOLD)
+		flush_user_icache_range_asm(start,end);
+	else
+		flush_instruction_cache();
+#endif
 }
 
-extern void __flush_page_to_ram(unsigned long address);
+static inline void
+flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+	int sr3;
 
-#define flush_cache_all()			flush_all_caches()
-#define flush_cache_mm(foo)			flush_all_caches()
+	if (!mm->context) {
+		BUG();
+		return;
+	}
 
-#if 0
-/* This is how I think the cache flushing should be done -- mrw */
-extern inline void flush_cache_mm(struct mm_struct *mm) {
-	if (mm == current->mm) {
-		flush_user_dcache_range(mm->start_data, mm->end_data);
-		flush_user_icache_range(mm->start_code, mm->end_code);
+	sr3 = mfsp(3);
+	if (mm->context == sr3) {
+		flush_user_dcache_range(start,end);
+		flush_user_icache_range(start,end);
 	} else {
-		flush_other_dcache_range(mm->context, mm->start_data, mm->end_data);
-		flush_other_icache_range(mm->context, mm->start_code, mm->end_code);
+		flush_cache_all();
 	}
 }
-#endif
-
-#define flush_cache_range(mm, start, end) do { \
-                __flush_dcache_range(start, (unsigned long)end - (unsigned long)start); \
-                __flush_icache_range(start, (unsigned long)end - (unsigned long)start); \
-} while(0)
-
-#define flush_cache_page(vma, vmaddr) do { \
-                __flush_dcache_range(vmaddr, PAGE_SIZE); \
-                __flush_icache_range(vmaddr, PAGE_SIZE); \
-} while(0)
-
-#define flush_page_to_ram(page)	\
-        __flush_page_to_ram((unsigned long)page_address(page))
-
-#define flush_icache_range(start, end) \
-        __flush_icache_range(start, end - start)
-
-#define flush_icache_user_range(vma, page, addr, len) \
-	flush_icache_page((vma), (page))
 
-#define flush_icache_page(vma, page) \
-	__flush_icache_range(page_address(page), PAGE_SIZE)
-
-#define flush_dcache_page(page) \
-	__flush_dcache_range(page_address(page), PAGE_SIZE)
-
-/* TLB flushing routines.... */
-
-extern void flush_data_tlb(void);
-extern void flush_instruction_tlb(void);
-
-#define flush_tlb() do { \
-        flush_data_tlb(); \
-	flush_instruction_tlb(); \
-} while(0);
+static inline void
+flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+	int sr3;
 
-#define flush_tlb_all() 	flush_tlb()	/* XXX p[id]tlb */
+	if (!vma->vm_mm->context) {
+		BUG();
+		return;
+	}
 
-extern __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
-}
- 
-static inline void flush_instruction_tlb_range(unsigned long start,
-					unsigned long size)
-{
-#if 0
-	register unsigned long count = (size / PAGE_SIZE);
-	register unsigned long loop = cache_info.it_loop;
-	register unsigned long i, j;
-	
-	for(i = 0; i <= count; i++, start += PAGE_SIZE)
-		for(j = 0; j < loop; j++)
-			pitlbe(start);
-#else
-	flush_instruction_tlb();
-#endif
+	sr3 = mfsp(3);
+	if (vma->vm_mm->context == sr3) {
+		flush_user_dcache_range(vmaddr,vmaddr + PAGE_SIZE);
+		if (vma->vm_flags & VM_EXEC)
+			flush_user_icache_range(vmaddr,vmaddr + PAGE_SIZE);
+	} else {
+		if (vma->vm_flags & VM_EXEC)
+			flush_cache_all();
+		else
+			flush_data_cache();
+	}
 }
 
-static inline void flush_data_tlb_range(unsigned long start,
-					unsigned long size)
+static inline void flush_dcache_page(struct page *page)
 {
-#if 0
-	register unsigned long count = (size / PAGE_SIZE);
-	register unsigned long loop = cache_info.dt_loop;
-	register unsigned long i, j;
-	
-	for(i = 0; i <= count; i++, start += PAGE_SIZE)
-		for(j = 0; j < loop; j++)
-			pdtlbe(start);
-#else
-	flush_data_tlb();
-#endif
+	if (page->mapping && !page->mapping->i_mmap &&
+			!page->mapping->i_mmap_shared) {
+		set_bit(PG_dcache_dirty, &page->flags);
+	} else {
+		flush_kernel_dcache_page(page_address(page));
+	}
 }
 
+#define flush_icache_page(vma,page)	do { flush_kernel_dcache_page(page_address(page)); flush_kernel_icache_page(page_address(page)); } while (0)
 
+#define flush_icache_range(s,e)		do { flush_kernel_dcache_range_asm(s,e); flush_kernel_icache_range_asm(s,e); } while (0)
 
-static inline void __flush_tlb_range(unsigned long space, unsigned long start,
-		       unsigned long size)
-{
-	unsigned long old_sr1;
-
-	if(!size)
-		return;
+/* TLB flushing routines.... */
 
-	old_sr1 = mfsp(1);
-	mtsp(space, 1);
-	
-	flush_data_tlb_range(start, size);
-	flush_instruction_tlb_range(start, size);
+extern void flush_tlb_all(void);
 
-	mtsp(old_sr1, 1);
+static inline void load_context(mm_context_t context)
+{
+	mtsp(context, 3);
+#if SPACEID_SHIFT == 0
+	mtctl(context << 1,8);
+#else
+	mtctl(context >> (SPACEID_SHIFT - 1),8);
+#endif
 }
 
-extern void __flush_tlb_space(unsigned long space);
+/*
+ * flush_tlb_mm()
+ *
+ * XXX This code is NOT valid for HP-UX compatibility processes,
+ * (although it will probably work 99% of the time). HP-UX
+ * processes are free to play with the space id's and save them
+ * over long periods of time, etc. so we have to preserve the
+ * space and just flush the entire tlb. We need to check the
+ * personality in order to do that, but the personality is not
+ * currently being set correctly.
+ *
+ * Of course, Linux processes could do the same thing, but
+ * we don't support that (and the compilers, dynamic linker,
+ * etc. do not do that).
+ */
 
 static inline void flush_tlb_mm(struct mm_struct *mm)
 {
-#if 0
-	__flush_tlb_space(mm->context);
+	if (mm == &init_mm) BUG(); /* Should never happen */
+
+#ifdef CONFIG_SMP
+	flush_tlb_all();
 #else
-	flush_tlb();
+	if (mm) {
+		if (mm->context != 0)
+			free_sid(mm->context);
+		mm->context = alloc_sid();
+		if (mm == current->active_mm)
+			load_context(mm->context);
+	}
 #endif
 }
 
+extern __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+}
+ 
 static inline void flush_tlb_page(struct vm_area_struct *vma,
 	unsigned long addr)
 {
-	__flush_tlb_range(vma->vm_mm->context, addr, PAGE_SIZE);
-		
+	/* For one page, it's not worth testing the split_tlb variable */
+
+	mtsp(vma->vm_mm->context,1);
+	pdtlb(addr);
+	pitlb(addr);
 }
 
 static inline void flush_tlb_range(struct mm_struct *mm,
 	unsigned long start, unsigned long end)
 {
-	__flush_tlb_range(mm->context, start, end - start);
-}
-
-/*
- * NOTE: Many of the below macros use PT_NLEVELS because
- *       it is convenient that PT_NLEVELS == LOG2(pte size in bytes),
- *       i.e. we use 3 level page tables when we use 8 byte pte's
- *       (for 64 bit) and 2 level page tables when we use 4 byte pte's
- */
-
-#ifdef __LP64__
-#define PT_NLEVELS 3
-#define PT_INITIAL 4 /* Number of initial page tables */
-#else
-#define PT_NLEVELS 2
-#define PT_INITIAL 2 /* Number of initial page tables */
-#endif
-
-/* Definitions for 1st level */
-
-#define PGDIR_SHIFT  (PAGE_SHIFT + (PT_NLEVELS - 1)*(PAGE_SHIFT - PT_NLEVELS))
-#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
-#define PGDIR_MASK	(~(PGDIR_SIZE-1))
-#define PTRS_PER_PGD    (1UL << (PAGE_SHIFT - PT_NLEVELS))
-#define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
-
-/* Definitions for 2nd level */
-
-#define PMD_SHIFT       (PAGE_SHIFT + (PAGE_SHIFT - PT_NLEVELS))
-#define PMD_SIZE	(1UL << PMD_SHIFT)
-#define PMD_MASK	(~(PMD_SIZE-1))
-#if PT_NLEVELS == 3
-#define PTRS_PER_PMD    (1UL << (PAGE_SHIFT - PT_NLEVELS))
-#else
-#define PTRS_PER_PMD    1
-#endif
-
-/* Definitions for 3rd level */
-
-#define PTRS_PER_PTE    (1UL << (PAGE_SHIFT - PT_NLEVELS))
+	unsigned long npages;
 
+	npages = ((end - (start & PAGE_MASK)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+	if (npages >= 512)  /* XXX arbitrary, should be tuned */
+		flush_tlb_all();
+	else {
 
-#define get_pgd_fast get_pgd_slow
-#define free_pgd_fast free_pgd_slow
+		mtsp(mm->context,1);
+		if (split_tlb) {
+			while (npages--) {
+				pdtlb(start);
+				pitlb(start);
+				start += PAGE_SIZE;
+			}
+		} else {
+			while (npages--) {
+				pdtlb(start);
+				start += PAGE_SIZE;
+			}
+		}
+	}
+}
 
-extern __inline__ pgd_t *get_pgd_slow(void)
+static inline pgd_t *pgd_alloc_one_fast (void)
 {
-	extern unsigned long gateway_pgd_offset;
-	extern unsigned long gateway_pgd_entry;
-	pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL);
-
-	if (ret) {
-	    memset (ret, 0, PTRS_PER_PGD * sizeof(pgd_t));
-
-	    /* Install HP-UX and Linux gateway page translations */
+	return NULL; /* not implemented */
+}
 
-	    pgd_val(*(ret + gateway_pgd_offset)) = gateway_pgd_entry;
+static inline pgd_t *pgd_alloc (struct mm_struct *mm)
+{
+	/* the VM system never calls pgd_alloc_one_fast(), so we do it here. */
+	pgd_t *pgd = pgd_alloc_one_fast();
+	if (!pgd) {
+		pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
+		if (pgd)
+			clear_page(pgd);
 	}
-	return ret;
+	return pgd;
 }
 
-extern __inline__ void free_pgd_slow(pgd_t *pgd)
+static inline void pgd_free(pgd_t *pgd)
 {
 	free_page((unsigned long)pgd);
 }
 
-#if PT_NLEVELS == 3
+#ifdef __LP64__
 
 /* Three Level Page Table Support for pmd's */
 
-extern __inline__ pmd_t *get_pmd_fast(void)
+static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
 {
-	return NULL; /* la la */
+	pgd_val(*pgd) = _PAGE_TABLE + __pa((unsigned long)pmd);
 }
 
-#if 0
-extern __inline__ void free_pmd_fast(pmd_t *pmd)
+static inline pmd_t *pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address)
 {
+	return NULL; /* la la */
 }
-#else
-#define free_pmd_fast free_pmd_slow
-#endif
 
-extern __inline__ pmd_t *get_pmd_slow(void)
+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
 {
 	pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
-
 	if (pmd)
 		clear_page(pmd);
 	return pmd;
 }
 
-extern __inline__ void free_pmd_slow(pmd_t *pmd)
+static inline void pmd_free(pmd_t *pmd)
 {
 	free_page((unsigned long)pmd);
 }
 
-extern void __bad_pgd(pgd_t *pgd);
-
-extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
-{
-	address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
-
-	if (pgd_none(*pgd))
-		goto getnew;
-	if (pgd_bad(*pgd))
-		goto fix;
-	return (pmd_t *) pgd_page(*pgd) + address;
-getnew:
-{
-	pmd_t *page = get_pmd_fast();
-	
-	if (!page)
-		page = get_pmd_slow();
-	if (page) {
-		if (pgd_none(*pgd)) {
-		    pgd_val(*pgd) = _PAGE_TABLE + __pa((unsigned long)page);
-		    return page + address;
-		}
-		else
-		    free_pmd_fast(page);
-	}
-	else {
-		return NULL;
-	}
-}
-fix:
-	__bad_pgd(pgd);
-	return NULL;
-}
-
 #else
 
 /* Two Level Page Table Support for pmd's */
 
-extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
-{
-	return (pmd_t *) pgd;
-}
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
 
-extern inline void free_pmd_fast(pmd_t * pmd)
-{
-}
+#define pmd_alloc_one_fast(mm, addr)	({ BUG(); ((pmd_t *)1); })
+#define pmd_alloc_one(mm, addr)		({ BUG(); ((pmd_t *)2); })
+#define pmd_free(x)			do { } while (0)
+#define pgd_populate(mm, pmd, pte)	BUG()
 
 #endif
 
-extern __inline__ pte_t *get_pte_fast(void)
+static inline void pmd_populate (struct mm_struct *mm, pmd_t *pmd_entry, pte_t *pte)
 {
-	return NULL; /* la la */
+	pmd_val(*pmd_entry) = _PAGE_TABLE + __pa((unsigned long)pte);
 }
 
-#if 0
-extern __inline__ void free_pte_fast(pte_t *pte)
+static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
 {
+	return NULL; /* la la */
 }
-#else
-#define free_pte_fast free_pte_slow
-#endif
 
-extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
-
-extern __inline__ void free_pte_slow(pte_t *pte)
+static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-	free_page((unsigned long)pte);
+	pte_t *pte = (pte_t *) __get_free_page(GFP_KERNEL);
+	if (pte)
+		clear_page(pte);
+	return pte;
 }
 
-#define pmd_alloc_kernel	pmd_alloc
-#define pte_alloc_kernel	pte_alloc
-
-#define pte_free(pte)		free_pte_fast(pte)
-#define pmd_free(pmd)           free_pmd_fast(pmd)
-#define pgd_free(pgd)		free_pgd_fast(pgd)
-#define pgd_alloc(mm)		get_pgd_fast()
-
-extern void __bad_pmd(pmd_t *pmd);
-
-extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
-{
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-
-	if (pmd_none(*pmd))
-		goto getnew;
-	if (pmd_bad(*pmd))
-		goto fix;
-	return (pte_t *) pmd_page(*pmd) + address;
-getnew:
-{
-	pte_t *page = get_pte_fast();
-	
-	if (!page)
-		return get_pte_slow(pmd, address);
-	pmd_val(*pmd) = _PAGE_TABLE + __pa((unsigned long)page);
-	return page + address;
-}
-fix:
-	__bad_pmd(pmd);
-	return NULL;
+static inline void pte_free(pte_t *pte)
+{
+	free_page((unsigned long)pte);
 }
 
 extern int do_check_pgt_cache(int, int);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/pgtable.h linux-2.4.20/include/asm-parisc/pgtable.h
--- linux-2.4.19/include/asm-parisc/pgtable.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/pgtable.h	2002-10-29 11:18:36.000000000 +0000
@@ -1,43 +1,19 @@
 #ifndef _PARISC_PGTABLE_H
 #define _PARISC_PGTABLE_H
 
+#include <asm/fixmap.h>
+
 #ifndef __ASSEMBLY__
 /*
  * we simulate an x86-style page table for the linux mm code
  */
 
+#include <linux/spinlock.h>
 #include <asm/processor.h>
-#include <asm/fixmap.h>
 #include <asm/cache.h>
+#include <asm/bitops.h>
 
-/* To make 53c7xx.c happy */
-
-#define IOMAP_FULL_CACHING	2		/* used for 'what' below */
-#define IOMAP_NOCACHE_SER	3
-
-extern void kernel_set_cachemode(unsigned long addr,
-				    unsigned long size, int what);
-
-/*
- * cache_clear() semantics: Clear any cache entries for the area in question,
- * without writing back dirty entries first. This is useful if the data will
- * be overwritten anyway, e.g. by DMA to memory. The range is defined by a
- * _physical_ address.
- */
-#define cache_clear(paddr, len)			do { } while (0)
-/*
- * cache_push() semantics: Write back any dirty cache data in the given area,
- * and invalidate the range in the instruction cache. It needs not (but may)
- * invalidate those entries also in the data cache. The range is defined by a
- * _physical_ address.
- */
-#define cache_push(paddr, len) \
-	do { \
-		unsigned long vaddr = phys_to_virt(paddr); \
-		flush_cache_range(&init_mm, vaddr, vaddr + len); \
-	} while(0)
-#define cache_push_v(vaddr, len) \
-			flush_cache_range(&init_mm, vaddr, vaddr + len)
+#define ARCH_STACK_GROWSUP
 
 /*
  * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
@@ -63,8 +39,6 @@
                 *(pteptr) = (pteval);                           \
         } while(0)
 
-
-
 #endif /* !__ASSEMBLY__ */
 
 #define pte_ERROR(e) \
@@ -74,11 +48,62 @@
 #define pgd_ERROR(e) \
 	printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
 
+ /* Note: If you change ISTACK_SIZE, you need to change the corresponding
+  * values in vmlinux.lds and vmlinux64.lds (init_istack section). Also,
+  * the "order" and size need to agree.
+  */
+
+#define  ISTACK_SIZE  32768 /* Interrupt Stack Size */
+#define  ISTACK_ORDER 3
+
+/*
+ * NOTE: Many of the below macros use PT_NLEVELS because
+ *       it is convenient that PT_NLEVELS == LOG2(pte size in bytes),
+ *       i.e. we use 3 level page tables when we use 8 byte pte's
+ *       (for 64 bit) and 2 level page tables when we use 4 byte pte's
+ */
+
+#ifdef __LP64__
+#define PT_NLEVELS 3
+#define PT_INITIAL 4 /* Number of initial page tables */
+#else
+#define PT_NLEVELS 2
+#define PT_INITIAL 2 /* Number of initial page tables */
+#endif
+
+#define MAX_ADDRBITS (PAGE_SHIFT + (PT_NLEVELS)*(PAGE_SHIFT - PT_NLEVELS))
+#define MAX_ADDRESS (1UL << MAX_ADDRBITS)
+
+#define SPACEID_SHIFT (MAX_ADDRBITS - 32)
+
+/* Definitions for 1st level */
+
+#define PGDIR_SHIFT  (PAGE_SHIFT + (PT_NLEVELS - 1)*(PAGE_SHIFT - PT_NLEVELS))
+#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+#define PTRS_PER_PGD    (1UL << (PAGE_SHIFT - PT_NLEVELS))
+#define USER_PTRS_PER_PGD       PTRS_PER_PGD
+
+/* Definitions for 2nd level */
+#define pgtable_cache_init()	do { } while (0)
+
+#define PMD_SHIFT       (PAGE_SHIFT + (PAGE_SHIFT - PT_NLEVELS))
+#define PMD_SIZE	(1UL << PMD_SHIFT)
+#define PMD_MASK	(~(PMD_SIZE-1))
+#if PT_NLEVELS == 3
+#define PTRS_PER_PMD    (1UL << (PAGE_SHIFT - PT_NLEVELS))
+#else
+#define PTRS_PER_PMD    1
+#endif
+
+/* Definitions for 3rd level */
+
+#define PTRS_PER_PTE    (1UL << (PAGE_SHIFT - PT_NLEVELS))
+
 /*
  * pgd entries used up by user/kernel:
  */
 
-#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
 #define FIRST_USER_PGD_NR	0
 
 #ifndef __ASSEMBLY__
@@ -89,35 +114,43 @@
 #define VMALLOC_END	(FIXADDR_START)
 #endif
 
-#define _PAGE_READ	0x001	/* read access allowed */
-#define _PAGE_WRITE	0x002	/* write access allowed */
-#define _PAGE_EXEC	0x004	/* execute access allowed */
-#define _PAGE_GATEWAY	0x008	/* privilege promotion allowed */
-#define _PAGE_GATEWAY_BIT 28	/* _PAGE_GATEWAY & _PAGE_GATEWAY_BIT need */
-				/* to agree. One could be defined in relation */
-				/* to the other, but that's kind of ugly. */
-
-				/* 0x010 reserved (B bit) */
-#define _PAGE_DIRTY	0x020	/* D: dirty */
-				/* 0x040 reserved (T bit) */
-#define _PAGE_NO_CACHE  0x080   /* Software: Uncacheable */
-#define _PAGE_NO_CACHE_BIT 24   /* Needs to agree with _PAGE_NO_CACHE above */
-#define _PAGE_ACCESSED	0x100	/* R: page cache referenced */
-#define _PAGE_PRESENT   0x200   /* Software: pte contains a translation */
-#define _PAGE_PRESENT_BIT  22   /* Needs to agree with _PAGE_PRESENT above */
-#define _PAGE_USER      0x400   /* Software: User accessable page */
-#define _PAGE_USER_BIT     21   /* Needs to agree with _PAGE_USER above */
-				/* 0x800 still available */
-
-#ifdef __ASSEMBLY__
-#define _PGB_(x)	(1 << (63 - (x)))
-#define __PAGE_O	_PGB_(13)
-#define __PAGE_U	_PGB_(12)
-#define __PAGE_T	_PGB_(2)
-#define __PAGE_D	_PGB_(3)
-#define __PAGE_B	_PGB_(4)
-#define __PAGE_P	_PGB_(14)
-#endif
+/* NB: The tlb miss handlers make certain assumptions about the order */
+/*     of the following bits, so be careful (One example, bits 25-31  */
+/*     are moved together in one instruction).                        */
+
+#define _PAGE_READ_BIT     31   /* (0x001) read access allowed */
+#define _PAGE_WRITE_BIT    30   /* (0x002) write access allowed */
+#define _PAGE_EXEC_BIT     29   /* (0x004) execute access allowed */
+#define _PAGE_GATEWAY_BIT  28   /* (0x008) privilege promotion allowed */
+#define _PAGE_DMB_BIT      27   /* (0x010) Data Memory Break enable (B bit) */
+#define _PAGE_DIRTY_BIT    26   /* (0x020) Page Dirty (D bit) */
+#define _PAGE_REFTRAP_BIT  25   /* (0x040) Page Ref. Trap enable (T bit) */
+#define _PAGE_NO_CACHE_BIT 24   /* (0x080) Uncached Page (U bit) */
+#define _PAGE_ACCESSED_BIT 23   /* (0x100) Software: Page Accessed */
+#define _PAGE_PRESENT_BIT  22   /* (0x200) Software: translation valid */
+#define _PAGE_FLUSH_BIT    21   /* (0x400) Software: translation valid */
+				/*             for cache flushing only */
+#define _PAGE_USER_BIT     20   /* (0x800) Software: User accessable page */
+
+/* N.B. The bits are defined in terms of a 32 bit word above, so the */
+/*      following macro is ok for both 32 and 64 bit.                */
+
+#define xlate_pabit(x) (31 - x)
+
+#define _PAGE_READ     (1 << xlate_pabit(_PAGE_READ_BIT))
+#define _PAGE_WRITE    (1 << xlate_pabit(_PAGE_WRITE_BIT))
+#define _PAGE_RW       (_PAGE_READ | _PAGE_WRITE)
+#define _PAGE_EXEC     (1 << xlate_pabit(_PAGE_EXEC_BIT))
+#define _PAGE_GATEWAY  (1 << xlate_pabit(_PAGE_GATEWAY_BIT))
+#define _PAGE_DMB      (1 << xlate_pabit(_PAGE_DMB_BIT))
+#define _PAGE_DIRTY    (1 << xlate_pabit(_PAGE_DIRTY_BIT))
+#define _PAGE_REFTRAP  (1 << xlate_pabit(_PAGE_REFTRAP_BIT))
+#define _PAGE_NO_CACHE (1 << xlate_pabit(_PAGE_NO_CACHE_BIT))
+#define _PAGE_ACCESSED (1 << xlate_pabit(_PAGE_ACCESSED_BIT))
+#define _PAGE_PRESENT  (1 << xlate_pabit(_PAGE_PRESENT_BIT))
+#define _PAGE_FLUSH    (1 << xlate_pabit(_PAGE_FLUSH_BIT))
+#define _PAGE_USER     (1 << xlate_pabit(_PAGE_USER_BIT))
+
 #define _PAGE_TABLE	(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE |  _PAGE_DIRTY | _PAGE_ACCESSED)
 #define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _PAGE_KERNEL	(_PAGE_PRESENT | _PAGE_EXEC | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED)
@@ -138,6 +171,7 @@
 #define PAGE_KERNEL_RO	__pgprot(_PAGE_PRESENT | _PAGE_EXEC | _PAGE_READ | _PAGE_DIRTY | _PAGE_ACCESSED)
 #define PAGE_KERNEL_UNC	__pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE)
 #define PAGE_GATEWAY    __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_GATEWAY| _PAGE_READ)
+#define PAGE_FLUSH      __pgprot(_PAGE_FLUSH)
 
 
 /*
@@ -167,7 +201,7 @@
 #define __S110  PAGE_RWX
 #define __S111  PAGE_RWX
 
-extern unsigned long swapper_pg_dir[]; /* declared in init_task.c */
+extern pgd_t swapper_pg_dir[]; /* declared in init_task.c */
 
 /* initial page tables for 0-8MB for kernel */
 
@@ -178,23 +212,15 @@
 extern unsigned long *empty_zero_page;
 
 /*
- * BAD_PAGETABLE is used when we need a bogus page-table, while
- * BAD_PAGE is used for a bogus page.
- *
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
  */
-extern pte_t __bad_page(void);
-extern pte_t * __bad_pagetable(void);
 
-#define BAD_PAGETABLE __bad_pagetable()
-#define BAD_PAGE __bad_page()
 #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
 
-#define pte_none(x)	(!pte_val(x))
+#define pte_none(x)     ((pte_val(x) == 0) || (pte_val(x) & _PAGE_FLUSH))
 #define pte_present(x)	(pte_val(x) & _PAGE_PRESENT)
 #define pte_clear(xp)	do { pte_val(*(xp)) = 0; } while (0)
-#define pte_pagenr(x)	((unsigned long)((pte_val(x) >> PAGE_SHIFT)))
 
 #define pmd_none(x)	(!pmd_val(x))
 #define pmd_bad(x)	((pmd_val(x) & ~PAGE_MASK) != _PAGE_TABLE)
@@ -255,12 +281,21 @@
 	__pte;								\
 })
 
-#define mk_pte(page,pgprot) \
+#ifdef CONFIG_DISCONTIGMEM
+#define PAGE_TO_PA(page) \
+		((((page)-(page)->zone->zone_mem_map) << PAGE_SHIFT) \
+		+ ((page)->zone->zone_start_paddr))
+#else
+#define PAGE_TO_PA(page) ((page - mem_map) << PAGE_SHIFT)
+#endif
+
+#define mk_pte(page, pgprot)						\
 ({									\
-	pte_t __pte;							\
+	pte_t __pte;                                                    \
+									\
+	pte_val(__pte) = ((unsigned long)(PAGE_TO_PA(page))) |		\
+						pgprot_val(pgprot);	\
 									\
-	pte_val(__pte) = ((page)-mem_map)*PAGE_SIZE +			\
-				pgprot_val(pgprot);			\
 	__pte;								\
 })
 
@@ -271,13 +306,14 @@
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
 
-/*
- * Permanent address of a page. Obviously must never be
- * called on a highmem page.
- */
-#define __page_address(page) ({ if (PageHighMem(page)) BUG(); PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT); })
-#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
-#define pte_page(x) (mem_map+pte_pagenr(x))
+/* Permanent address of a page.  On parisc we don't have highmem. */
+
+#ifdef CONFIG_DISCONTIGMEM
+#define pte_page(x) (phys_to_page(pte_val(x)))
+#else
+#define pte_page(x) (mem_map+(pte_val(x) >> PAGE_SHIFT))
+#endif
+
 
 #define pmd_page(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
 
@@ -305,26 +341,98 @@
 
 extern void paging_init (void);
 
-extern inline void update_mmu_cache(struct vm_area_struct * vma,
-	unsigned long address, pte_t pte)
-{
-}
+/* Used for deferring calls to flush_dcache_page() */
+
+#define PG_dcache_dirty         PG_arch_1
+
+struct vm_area_struct; /* forward declaration (include/linux/mm.h) */
+extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
 
 /* Encode and de-code a swap entry */
 
-#define SWP_TYPE(x)                     ((x).val & 0x3f)
-#define SWP_OFFSET(x)                   ( (((x).val >> 6) &  0x7) | \
-					  (((x).val >> 7) & ~0x7) )
+#define SWP_TYPE(x)                     ((x).val & 0x1f)
+#define SWP_OFFSET(x)                   ( (((x).val >> 5) &  0xf) | \
+					  (((x).val >> 7) & ~0xf) )
 #define SWP_ENTRY(type, offset)         ((swp_entry_t) { (type) | \
-					    ((offset &  0x7) << 6) | \
-					    ((offset & ~0x7) << 7) })
+					    ((offset &  0xf) << 5) | \
+					    ((offset & ~0xf) << 7) })
 #define pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) })
 #define swp_entry_to_pte(x)		((pte_t) { (x).val })
 
-#define module_map	vmalloc
-#define module_unmap	vfree
+static inline int ptep_test_and_clear_young(pte_t *ptep)
+{
+#ifdef CONFIG_SMP
+	return test_and_clear_bit(xlate_pabit(_PAGE_ACCESSED_BIT), ptep);
+#else
+	pte_t pte = *ptep;
+	if (!pte_young(pte))
+		return 0;
+	set_pte(ptep, pte_mkold(pte));
+	return 1;
+#endif
+}
+
+static inline int ptep_test_and_clear_dirty(pte_t *ptep)
+{
+#ifdef CONFIG_SMP
+	return test_and_clear_bit(xlate_pabit(_PAGE_DIRTY_BIT), ptep);
+#else
+	pte_t pte = *ptep;
+	if (!pte_dirty(pte))
+		return 0;
+	set_pte(ptep, pte_mkclean(pte));
+	return 1;
+#endif
+}
+
+#ifdef CONFIG_SMP
+extern spinlock_t pa_dbit_lock;
+#else
+static int pa_dbit_lock; /* dummy to keep the compilers happy */
+#endif
+
+static inline pte_t ptep_get_and_clear(pte_t *ptep)
+{
+	pte_t old_pte;
+	pte_t pte;
+
+	spin_lock(&pa_dbit_lock);
+	pte = old_pte = *ptep;
+	pte_val(pte) &= ~_PAGE_PRESENT;
+	pte_val(pte) |= _PAGE_FLUSH;
+	set_pte(ptep,pte);
+	spin_unlock(&pa_dbit_lock);
+
+	return old_pte;
+}
+
+static inline void ptep_set_wrprotect(pte_t *ptep)
+{
+#ifdef CONFIG_SMP
+	unsigned long new, old;
+
+	do {
+		old = pte_val(*ptep);
+		new = pte_val(pte_wrprotect(__pte (old)));
+	} while (cmpxchg((unsigned long *) ptep, old, new) != old);
+#else
+	pte_t old_pte = *ptep;
+	set_pte(ptep, pte_wrprotect(old_pte));
+#endif
+}
+
+static inline void ptep_mkdirty(pte_t *ptep)
+{
+#ifdef CONFIG_SMP
+	set_bit(xlate_pabit(_PAGE_DIRTY_BIT), ptep);
+#else
+	pte_t old_pte = *ptep;
+	set_pte(ptep, pte_mkdirty(old_pte));
+#endif
+}
+
+#define pte_same(A,B)	(pte_val(A) == pte_val(B))
 
-#include <asm-generic/pgtable.h>
 
 #endif /* !__ASSEMBLY__ */
 
@@ -333,9 +441,8 @@
 
 #define io_remap_page_range remap_page_range
 
-/*
- * No page table caches to initialise
- */
-#define pgtable_cache_init()	do { } while (0)
+/* We provide our own get_unmapped_area to provide cache coherency */
+
+#define HAVE_ARCH_UNMAPPED_AREA
 
-#endif /* _PARISC_PAGE_H */
+#endif /* _PARISC_PGTABLE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/posix_types.h linux-2.4.20/include/asm-parisc/posix_types.h
--- linux-2.4.19/include/asm-parisc/posix_types.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/posix_types.h	2002-10-29 11:18:35.000000000 +0000
@@ -19,10 +19,17 @@
 typedef int			__kernel_clock_t;
 typedef int			__kernel_daddr_t;
 /* Note these change from narrow to wide kernels */
+#ifdef __LP64__
 typedef unsigned long		__kernel_size_t;
 typedef long			__kernel_ssize_t;
 typedef long			__kernel_ptrdiff_t;
 typedef long			__kernel_time_t;
+#else
+typedef unsigned int		__kernel_size_t;
+typedef int			__kernel_ssize_t;
+typedef int			__kernel_ptrdiff_t;
+typedef int			__kernel_time_t;
+#endif
 typedef char *			__kernel_caddr_t;
 
 typedef unsigned short		__kernel_uid16_t;
@@ -44,6 +51,10 @@
 #endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
 } __kernel_fsid_t;
 
+/* compatibility stuff */
+typedef __kernel_uid_t __kernel_old_uid_t;
+typedef __kernel_gid_t __kernel_old_gid_t;
+
 #if defined(__KERNEL__) && defined(__LP64__)
 /* Now 32bit compatibility types */
 typedef unsigned int		__kernel_dev_t32;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/processor.h linux-2.4.20/include/asm-parisc/processor.h
--- linux-2.4.19/include/asm-parisc/processor.h	2001-10-05 19:11:05.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/processor.h	2002-10-29 11:18:48.000000000 +0000
@@ -2,6 +2,7 @@
  * include/asm-parisc/processor.h
  *
  * Copyright (C) 1994 Linus Torvalds
+ * Copyright (C) 2001 Grant Grundler
  */
 
 #ifndef __ASM_PARISC_PROCESSOR_H
@@ -15,6 +16,7 @@
 #include <asm/pdc.h>
 #include <asm/ptrace.h>
 #include <asm/types.h>
+#include <asm/system.h>
 #endif /* __ASSEMBLY__ */
 
 /*
@@ -30,8 +32,11 @@
 
 #define current_text_addr() ({ void *pc; __asm__("\n\tblr 0,%0\n\tnop":"=r" (pc)); pc; })
 
-#define TASK_SIZE	    (PAGE_OFFSET)
-#define TASK_UNMAPPED_BASE  (TASK_SIZE / 3)
+#define TASK_SIZE               (current->thread.task_size)
+#define DEFAULT_TASK_SIZE       (0xFFF00000UL)
+
+#define TASK_UNMAPPED_BASE      (current->thread.map_base)
+#define DEFAULT_MAP_BASE        (0x40000000UL)
 
 #ifndef __ASSEMBLY__
 
@@ -50,17 +55,14 @@
 
 	struct {
 		struct pdc_model model;
-		struct pdc_model_cpuid /* ARGH */ versions;
-		struct pdc_model_cpuid cpuid;
-#if 0
-		struct pdc_model_caps caps;
-#endif
+		unsigned long versions;
+		unsigned long cpuid;
+		unsigned long capabilities;
 		char   sys_model_name[81]; /* PDC-ROM returnes this model name */
 	} pdc;
 
-	char	 	*model_name;
-	char		*cpu_name;
-	char		*family_name;
+	char		*cpu_name;	/* e.g. "PA7300LC (PCX-L2)" */
+	char		*family_name;	/* e.g. "1.1e" */
 };
 
 
@@ -68,29 +70,41 @@
 ** Per CPU data structure - ie varies per CPU.
 */
 struct cpuinfo_parisc {
-	unsigned cpuid;
 
 	struct irq_region *region;
-
-	unsigned long it_value; /* Interval Timer value at last timer interrupt */
-	unsigned long it_delta; /* Interval Timer delta (tic_10ms / HZ * 100) */
-
-	unsigned long hpa;	/* Host Physical address */
-	unsigned long txn_addr;	/* External Interrupt Register or id_eid */
-
-	unsigned long bh_count;		/* number of times bh was invoked */
-	unsigned long irq_count;	/* number of IRQ's since boot */
-	unsigned long irq_max_cr16;	/* longest time to handle a single IRQ */
+	unsigned long it_value;     /* Interval Timer value at last timer Intr */
+	unsigned long it_delta;     /* Interval Timer delta (tic_10ms / HZ * 100) */
+	unsigned long irq_count;    /* number of IRQ's since boot */
+	unsigned long irq_max_cr16; /* longest time to handle a single IRQ */
+	unsigned long cpuid;        /* aka slot_number or set to NO_PROC_ID */
+	unsigned long hpa;          /* Host Physical address */
+	unsigned long txn_addr;     /* MMIO addr of EIR or id_eid */
+#ifdef CONFIG_SMP
+	spinlock_t lock;            /* synchronization for ipi's */
+	unsigned long pending_ipi;  /* bitmap of type ipi_message_type */
+	unsigned long ipi_count;    /* number ipi Interrupts */
+#endif
+	unsigned long bh_count;     /* number of times bh was invoked */
+	unsigned long prof_counter; /* per CPU profiling support */
+	unsigned long prof_multiplier;	/* per CPU profiling support */
+	unsigned long fp_rev;
+	unsigned long fp_model;
+	unsigned int state;
+	struct parisc_device *dev;
 };
 
 extern struct system_cpuinfo_parisc boot_cpu_data;
 extern struct cpuinfo_parisc cpu_data[NR_CPUS];
 #define current_cpu_data cpu_data[smp_processor_id()]
 
-extern void identify_cpu(struct cpuinfo_parisc *);
+#define CPU_HVERSION ((boot_cpu_data.hversion >> 4) & 0x0FFF)
+
+#ifdef CONFIG_EISA
+extern int EISA_bus;
+#else
+#define EISA_bus 0
+#endif
 
-#define EISA_bus 0 /* we don't have ISA support yet */
-#define EISA_bus__is_a_macro /* for versions in ksyms.c */
 #define MCA_bus 0
 #define MCA_bus__is_a_macro /* for versions in ksyms.c */
 
@@ -100,31 +114,32 @@
 
 struct thread_struct {
 	struct pt_regs regs;
-	unsigned long  pg_tables;
+	unsigned long  task_size;
+	unsigned long  map_base;
 	unsigned long  flags;
 }; 
 
 /* Thread struct flags. */
 #define PARISC_KERNEL_DEATH	(1UL << 31)	/* see die_if_kernel()... */
 
-#define INIT_THREAD { {			\
-	{ 0, 0, 0, 0, 0, 0, 0, 0,	\
-	  0, 0, 0, 0, 0, 0, 0, 0,	\
-	  0, 0, 0, 0, 0, 0, 0, 0,	\
-	  0, 0, 0, 0, 0, 0, 0, 0 },	\
-	{ 0, 0, 0, 0, 0, 0, 0, 0,	\
-	  0, 0, 0, 0, 0, 0, 0, 0,	\
-	  0, 0, 0, 0, 0, 0, 0, 0,	\
-	  0, 0, 0, 0, 0, 0, 0, 0 },	\
-	{ 0, 0, 0, 0, 0, 0, 0, 0 },	\
-	{ 0, 0}, { 0, 0}, 0, 0, 0, 0	\
-	}, __pa((unsigned long) swapper_pg_dir) }
+#define INIT_THREAD { \
+	regs:	{	gr: { 0, }, \
+			fr: { 0, }, \
+			sr: { 0, }, \
+			iasq: { 0, }, \
+			iaoq: { 0, }, \
+			cr27: 0, \
+		}, \
+	task_size:      DEFAULT_TASK_SIZE, \
+	map_base:       DEFAULT_MAP_BASE, \
+	flags:          0 \
+	}
 
 /*
  * Return saved PC of a blocked thread.  This is used by ps mostly.
  */
 
-extern inline unsigned long thread_saved_pc(struct thread_struct *t)
+static inline unsigned long thread_saved_pc(struct thread_struct *t)
 {
 	return 0xabcdef;
 }
@@ -145,6 +160,34 @@
  * implementation, not for the architecture).
  */
 
+#define start_thread_som(regs, new_pc, new_sp) do {	\
+	unsigned long *sp = (unsigned long *)new_sp;	\
+	__u32 spaceid = (__u32)current->mm->context;	\
+	unsigned long pc = (unsigned long)new_pc;	\
+	/* offset pc for priv. level */			\
+	pc |= 3;					\
+							\
+	set_fs(USER_DS);				\
+	regs->iasq[0] = spaceid;			\
+	regs->iasq[1] = spaceid;			\
+	regs->iaoq[0] = pc;				\
+	regs->iaoq[1] = pc + 4;                         \
+	regs->sr[2] = LINUX_GATEWAY_SPACE;              \
+	regs->sr[3] = 0xffff;				\
+	regs->sr[4] = spaceid;				\
+	regs->sr[5] = spaceid;				\
+	regs->sr[6] = spaceid;				\
+	regs->sr[7] = spaceid;				\
+	regs->gr[ 0] = USER_PSW;                        \
+	regs->gr[30] = ((new_sp)+63)&~63;		\
+	regs->gr[31] = pc;				\
+							\
+	get_user(regs->gr[26],&sp[0]);			\
+	get_user(regs->gr[25],&sp[-1]); 		\
+	get_user(regs->gr[24],&sp[-2]); 		\
+	get_user(regs->gr[23],&sp[-3]); 		\
+} while(0)
+
 /* The ELF abi wants things done a "wee bit" differently than
  * som does.  Supporting this behavior here avoids
  * having our own version of create_elf_tables.
@@ -163,22 +206,44 @@
    |         32 bytes of magic       |
    |---------------------------------|
    | 32 bytes argument/sp save area  |
-   |---------------------------------|  ((current->mm->env_end) + 63 & ~63)
-   |         N bytes of slack        |
-   |---------------------------------|
-   |      envvar and arg strings     |
-   |---------------------------------|
+   |---------------------------------| (bprm->p)
    |	    ELF auxiliary info	     |
    |         (up to 28 words)        |
    |---------------------------------|
-   |  Environment variable pointers  |
-   |         upwards to NULL	     |
+   |		   NULL		     |
    |---------------------------------|
-   |        Argument pointers        |
-   |         upwards to NULL	     |
+   |	   Environment pointers	     |
+   |---------------------------------|
+   |		   NULL		     |
    |---------------------------------|
+   |        Argument pointers        |
+   |---------------------------------| <- argv
    |          argc (1 word)          |
-   -----------------------------------
+   |---------------------------------| <- bprm->exec (HACK!)
+   |         N bytes of slack        |
+   |---------------------------------|
+   |	filename passed to execve    |
+   |---------------------------------| (mm->env_end)
+   |           env strings           |
+   |---------------------------------| (mm->env_start, mm->arg_end)
+   |           arg strings           |
+   |---------------------------------|
+   | additional faked arg strings if |
+   | we're invoked via binfmt_script |
+   |---------------------------------| (mm->arg_start)
+   stack base is at TASK_SIZE - rlim_max.
+
+on downward growing arches, it looks like this:
+   stack base at TASK_SIZE
+   | filename passed to execve
+   | env strings
+   | arg strings
+   | faked arg strings
+   | slack
+   | ELF
+   | envps
+   | argvs
+   | argc
 
  *  The pleasant part of this is that if we need to skip arguments we
  *  can just decrement argc and move argv, because the stack pointer
@@ -186,154 +251,91 @@
  *  argument vectors.
  *
  * Note that the S/390 people took the easy way out and hacked their
- * GCC to make the stack grow downwards.  */
-
-#define start_thread_som(regs, new_pc, new_sp) do {		\
-	unsigned long *sp = (unsigned long *)new_sp;	\
-	__u32 spaceid = (__u32)current->mm->context;	\
-	unsigned long pc = (unsigned long)new_pc;	\
-	/* offset pc for priv. level */			\
-	pc |= 3;					\
-							\
-	set_fs(USER_DS);				\
-	regs->iasq[0] = spaceid;			\
-	regs->iasq[1] = spaceid;			\
-	regs->iaoq[0] = pc;				\
-	regs->iaoq[1] = pc;				\
-	regs->sr[2] = LINUX_GATEWAY_SPACE;              \
-	regs->sr[3] = 0xffff;				\
-	regs->sr[4] = spaceid;				\
-	regs->sr[5] = spaceid;				\
-	regs->sr[6] = spaceid;				\
-	regs->sr[7] = spaceid;				\
-	regs->gr[ 0] = USER_INIT_PSW;			\
-	regs->gr[30] = ((new_sp)+63)&~63;		\
-	regs->gr[31] = pc;				\
-							\
-	get_user(regs->gr[26],&sp[0]);			\
-	get_user(regs->gr[25],&sp[-1]); 		\
-	get_user(regs->gr[24],&sp[-2]); 		\
-	get_user(regs->gr[23],&sp[-3]); 		\
-							\
-	regs->cr30 = (u32) current;			\
-} while(0)
-
-
-#define start_thread(regs, new_pc, new_sp) do {		\
-	unsigned long *sp = (unsigned long *)new_sp;	\
-	__u32 spaceid = (__u32)current->mm->context;	\
-        unsigned long pc = (unsigned long)new_pc;       \
-        /* offset pc for priv. level */                 \
-        pc |= 3;                                        \
-							\
-							\
-	set_fs(USER_DS);				\
-	regs->iasq[0] = spaceid;			\
-	regs->iasq[1] = spaceid;			\
-	regs->iaoq[0] = pc;				\
-	regs->iaoq[1] = pc; 	               		\
-	regs->sr[2] = LINUX_GATEWAY_SPACE;              \
-	regs->sr[3] = 0xffff;				\
-	regs->sr[4] = spaceid;				\
-	regs->sr[5] = spaceid;				\
-	regs->sr[6] = spaceid;				\
-	regs->sr[7] = spaceid;				\
-	regs->gr[ 0] = USER_INIT_PSW;			\
-	regs->fr[ 0] = 0LL;                            	\
-	regs->fr[ 1] = 0LL;                            	\
-	regs->fr[ 2] = 0LL;                            	\
-	regs->fr[ 3] = 0LL;                            	\
-	regs->gr[30] = ((current->mm->env_end)+63)&~63;	\
-	regs->gr[31] = pc;				\
-							\
-	get_user(regs->gr[25],&sp[0]);			\
-	regs->gr[24] = (unsigned long) &sp[1];		\
-	regs->gr[23] = 0;                            	\
-							\
-	regs->cr30 = (u32) current;			\
-} while(0)
-
-#ifdef __LP64__
-
-/*
- * For 64 bit kernels we need a version of start thread for 32 bit
- * elf files.
- *
- * FIXME: It should be possible to not duplicate the above code
- *        by playing games with concatenation to form both
- *        macros at compile time. The only difference between
- *        this macro and the above is the name and the types
- *        for sp and pc.
+ * GCC to make the stack grow downwards.
  */
 
-#define start_thread32(regs, new_pc, new_sp) do {         \
-	__u32 *sp = (__u32 *)new_sp;                    \
+#define start_thread(regs, new_pc, new_sp) do {		\
+	elf_addr_t *sp = (elf_addr_t *)new_sp;		\
 	__u32 spaceid = (__u32)current->mm->context;	\
-	__u32 pc = (__u32)new_pc;                       \
-        /* offset pc for priv. level */                 \
-        pc |= 3;                                        \
+	elf_addr_t pc = (elf_addr_t)new_pc | 3;		\
+	elf_caddr_t *argv = (elf_caddr_t *)bprm->exec + 1;	\
 							\
 	set_fs(USER_DS);				\
 	regs->iasq[0] = spaceid;			\
 	regs->iasq[1] = spaceid;			\
 	regs->iaoq[0] = pc;				\
-	regs->iaoq[1] = pc; 	               		\
+	regs->iaoq[1] = pc + 4;                         \
 	regs->sr[2] = LINUX_GATEWAY_SPACE;              \
 	regs->sr[3] = 0xffff;				\
 	regs->sr[4] = spaceid;				\
 	regs->sr[5] = spaceid;				\
 	regs->sr[6] = spaceid;				\
 	regs->sr[7] = spaceid;				\
-	regs->gr[ 0] = USER_INIT_PSW;			\
+	regs->gr[ 0] = USER_PSW;                        \
 	regs->fr[ 0] = 0LL;                            	\
 	regs->fr[ 1] = 0LL;                            	\
 	regs->fr[ 2] = 0LL;                            	\
 	regs->fr[ 3] = 0LL;                            	\
-	regs->gr[30] = ((current->mm->env_end)+63)&~63;	\
+	regs->gr[30] = ((unsigned long)sp + 63) &~ 63;	\
 	regs->gr[31] = pc;				\
 							\
-	get_user(regs->gr[25],&sp[0]);			\
-	regs->gr[24] = (unsigned long) &sp[1];		\
-	regs->gr[23] = 0;                            	\
-							\
-	regs->cr30 = (u32) current;			\
+	get_user(regs->gr[25], (argv - 1));		\
+	regs->gr[24] = (long) argv;			\
+	regs->gr[23] = 0;				\
 } while(0)
 
-#endif
-
 struct task_struct;
+struct mm_struct;
 
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
-#define copy_segments(tsk, mm)	do { } while (0)
+extern void map_hpux_gateway_page(struct task_struct *tsk, struct mm_struct *mm);
+
+#define copy_segments(tsk, mm)  do { \
+					if (tsk->personality == PER_HPUX)  \
+					    map_hpux_gateway_page(tsk,mm); \
+				} while (0)
 #define release_segments(mm)	do { } while (0)
 
-extern inline unsigned long get_wchan(struct task_struct *p)
+static inline unsigned long get_wchan(struct task_struct *p)
 {
 	return 0xdeadbeef; /* XXX */
 }
 
-#define KSTK_EIP(tsk)	(0xdeadbeef)
-#define KSTK_ESP(tsk)	(0xdeadbeef)
+#define KSTK_EIP(tsk)	((tsk)->thread.regs.iaoq[0])
+#define KSTK_ESP(tsk)	((tsk)->thread.regs.gr[30])
+
+#endif /* __ASSEMBLY__ */
+
+#ifdef  CONFIG_PA20
+#define ARCH_HAS_PREFETCH
+extern inline void prefetch(const void *addr)
+{
+	__asm__("ldw 0(%0), %%r0" : : "r" (addr));
+}
+
+#define ARCH_HAS_PREFETCHW
+extern inline void prefetchw(const void *addr)
+{
+	__asm__("ldd 0(%0), %%r0" : : "r" (addr));
+}
+#endif
 
 /* Be sure to hunt all references to this down when you change the size of
  * the kernel stack */
 
-#endif /* __ASSEMBLY__ */
-
 #define THREAD_SIZE	(4*PAGE_SIZE)
 
 #define alloc_task_struct() \
-	((struct task_struct *) __get_free_pages(GFP_KERNEL,2))
-#define free_task_struct(p)     free_pages((unsigned long)(p),2)
-#define get_task_struct(tsk)      atomic_inc(&virt_to_page(tsk)->count)
+	((struct task_struct *)	__get_free_pages(GFP_KERNEL,2))
+#define free_task_struct(p)	free_pages((unsigned long)(p),2)
+#define get_task_struct(tsk)	atomic_inc(&virt_to_page(tsk)->count)
 
 #define init_task (init_task_union.task) 
 #define init_stack (init_task_union.stack)
 
 #define cpu_relax()	do { } while (0)
 
-
 #endif /* __ASM_PARISC_PROCESSOR_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/psw.h linux-2.4.20/include/asm-parisc/psw.h
--- linux-2.4.19/include/asm-parisc/psw.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/psw.h	2002-10-29 11:18:31.000000000 +0000
@@ -9,6 +9,8 @@
 #define	PSW_G	0x00000040	/* PA1.x only */
 #define PSW_O	0x00000080	/* PA2.0 only */
 
+#define PSW_CB	0x0000ff00
+
 #define	PSW_M	0x00010000
 #define	PSW_V	0x00020000
 #define	PSW_C	0x00040000
@@ -23,10 +25,15 @@
 #define	PSW_S	0x02000000
 #define	PSW_E	0x04000000
 #define PSW_W	0x08000000	/* PA2.0 only */
+#define PSW_W_BIT       36      /* PA2.0 only */
 
 #define	PSW_Z	0x40000000	/* PA1.x only */
 #define	PSW_Y	0x80000000	/* PA1.x only */
 
+#ifdef __LP64__
+#define PSW_HI_CB 0x000000ff    /* PA2.0 only */
+#endif
+
 /* PSW bits to be used with ssm/rsm */
 #define PSW_SM_I        0x1
 #define PSW_SM_D        0x2
@@ -40,15 +47,16 @@
 #define PSW_SM_W        0x200
 
 #ifdef __LP64__
-#  define USER_PSW	(PSW_C | PSW_D | PSW_Q | PSW_I)
-#  define USER_INIT_PSW	(PSW_C | PSW_D | PSW_Q | PSW_I | PSW_N)
-#  define KERNEL_PSW	(PSW_C | PSW_D | PSW_Q | PSW_W)
-#  define PDC_PSW	(PSW_Q | PSW_W)
+#  define USER_PSW      (PSW_C | PSW_Q | PSW_P | PSW_D | PSW_I)
+#  define KERNEL_PSW    (PSW_W | PSW_C | PSW_Q | PSW_P | PSW_D)
+#  define REAL_MODE_PSW (PSW_W | PSW_Q)
+#  define USER_PSW_MASK (PSW_W | PSW_T | PSW_N | PSW_X | PSW_B | PSW_V | PSW_CB)
+#  define USER_PSW_HI_MASK (PSW_HI_CB)
 #else
-#  define USER_PSW	(PSW_C | PSW_D | PSW_Q | PSW_I | PSW_P)
-#  define USER_INIT_PSW	(PSW_C | PSW_D | PSW_Q | PSW_I | PSW_N)
-#  define KERNEL_PSW	(PSW_C | PSW_D | PSW_Q)
-#  define PDC_PSW	(PSW_Q)
+#  define USER_PSW      (PSW_C | PSW_Q | PSW_P | PSW_D | PSW_I)
+#  define KERNEL_PSW    (PSW_C | PSW_Q | PSW_P | PSW_D)
+#  define REAL_MODE_PSW (PSW_Q)
+#  define USER_PSW_MASK (PSW_T | PSW_N | PSW_X | PSW_B | PSW_V | PSW_CB)
 #endif
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/ptrace.h linux-2.4.20/include/asm-parisc/ptrace.h
--- linux-2.4.19/include/asm-parisc/ptrace.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/ptrace.h	2002-10-29 11:18:40.000000000 +0000
@@ -8,7 +8,12 @@
 #include <linux/types.h>
 
 /* This struct defines the way the registers are stored on the 
-   stack during a system call. */
+ * stack during a system call.
+ *
+ * N.B. gdb/strace care about the size and offsets within this
+ * structure. If you change things, you may break object compatibility
+ * for those applications.
+ */
 
 struct pt_regs {
 	unsigned long gr[32];	/* PSW is in gr[0] */
@@ -16,11 +21,8 @@
 	unsigned long sr[ 8];
 	unsigned long iasq[2];
 	unsigned long iaoq[2];
-	unsigned long cr24;
-	unsigned long cr25;
-	unsigned long cr26;
 	unsigned long cr27;
-	unsigned long cr30;
+	unsigned long pad0;     /* available for other uses */
 	unsigned long orig_r28;
 	unsigned long ksp;
 	unsigned long kpc;
@@ -29,7 +31,6 @@
 	unsigned long isr;	/* CR20 */
 	unsigned long ior;	/* CR21 */
 	unsigned long ipsw;	/* CR22 */
-	unsigned long cr_pid[4]; /* CR8,9,12,13 */
 };
 
 #define task_regs(task) ((struct pt_regs *) ((char *)(task) + TASK_REGS))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/real.h linux-2.4.20/include/asm-parisc/real.h
--- linux-2.4.19/include/asm-parisc/real.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/real.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,5 +0,0 @@
-#ifndef _PARISC_REAL_H
-#define _PARISC_REAL_H
-
-
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/rmap.h linux-2.4.20/include/asm-parisc/rmap.h
--- linux-2.4.19/include/asm-parisc/rmap.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/rmap.h	2002-10-29 11:18:38.000000000 +0000
@@ -0,0 +1,7 @@
+#ifndef _PARISC_RMAP_H
+#define _PARISC_RMAP_H
+
+/* nothing to see, move along */
+#include <asm-generic/rmap.h>
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/rt_sigframe.h linux-2.4.20/include/asm-parisc/rt_sigframe.h
--- linux-2.4.19/include/asm-parisc/rt_sigframe.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/rt_sigframe.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,19 @@
+#ifndef _ASM_PARISC_RT_SIGFRAME_H
+#define _ASM_PARISC_RT_SIGFRAME_H
+
+struct rt_sigframe {
+	unsigned int tramp[4];
+	struct siginfo info;
+	struct ucontext uc;
+};
+
+/*
+ * The 32-bit ABI wants at least 48 bytes for a function call frame:
+ * 16 bytes for arg0-arg3, and 32 bytes for magic (the only part of
+ * which Linux/parisc uses is sp-20 for the saved return pointer...)
+ * Then, the stack pointer must be rounded to a cache line (64 bytes).
+ */
+#define PARISC_RT_SIGFRAME_SIZE					\
+	(((sizeof(struct rt_sigframe) + 48) + 63) & -64)
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/scatterlist.h linux-2.4.20/include/asm-parisc/scatterlist.h
--- linux-2.4.19/include/asm-parisc/scatterlist.h	2001-10-12 22:35:54.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/scatterlist.h	2002-10-29 11:18:48.000000000 +0000
@@ -1,8 +1,20 @@
 #ifndef _ASM_PARISC_SCATTERLIST_H
 #define _ASM_PARISC_SCATTERLIST_H
 
+#include <asm/page.h>
+
 struct scatterlist {
-	char *  address;    /* Location data is to be transferred to */
+	/* This will disappear in 2.5.x */
+	char *address;
+
+	/* page/offset only valid if ADDRESS member is NULL.
+	** Needed to support CONFIG_HIGHMEM on x386.
+	** I still think davem is a dork for forcing other
+	** arches to add this to 2.4.x. -ggg
+	*/
+	struct page *page;
+	unsigned int offset;
+
 	unsigned int length;
 
 	/* an IOVA can be 64-bits on some PA-Risc platforms. */
@@ -10,6 +22,9 @@
 	__u32      iova_length; /* bytes mapped */
 };
 
+#define sg_virt_addr(sg) (((sg)->address) ? ((sg)->address) : \
+		((sg)->page->virtual + (sg)->offset))
+
 #define sg_dma_address(sg) ((sg)->iova)
 #define sg_dma_len(sg)     ((sg)->iova_length)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/semaphore-helper.h linux-2.4.20/include/asm-parisc/semaphore-helper.h
--- linux-2.4.19/include/asm-parisc/semaphore-helper.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/semaphore-helper.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,89 +0,0 @@
-#ifndef _ASM_PARISC_SEMAPHORE_HELPER_H
-#define _ASM_PARISC_SEMAPHORE_HELPER_H
-
-/*
- * SMP- and interrupt-safe semaphores helper functions.
- *
- * (C) Copyright 1996 Linus Torvalds
- * (C) Copyright 1999 Andrea Arcangeli
- */
-
-/*
- * These two _must_ execute atomically wrt each other.
- *
- * This is trivially done with load_locked/store_cond,
- * which we have.  Let the rest of the losers suck eggs.
- */
-static __inline__ void wake_one_more(struct semaphore * sem)
-{
-	atomic_inc((atomic_t *)&sem->waking);
-}
-
-static __inline__ int waking_non_zero(struct semaphore *sem)
-{
-	unsigned long flags;
-	int ret = 0;
-
-	spin_lock_irqsave(&semaphore_wake_lock, flags);
-	if (sem->waking > 0) {
-		sem->waking--;
-		ret = 1;
-	}
-	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
-	return ret;
-}
-
-/*
- * waking_non_zero_interruptible:
- *	1	got the lock
- *	0	go to sleep
- *	-EINTR	interrupted
- *
- * We must undo the sem->count down_interruptible() increment while we are
- * protected by the spinlock in order to make atomic this atomic_inc() with the
- * atomic_read() in wake_one_more(), otherwise we can race. -arca
- */
-static __inline__ int waking_non_zero_interruptible(struct semaphore *sem,
-						struct task_struct *tsk)
-{
-	unsigned long flags;
-	int ret = 0;
-
-	spin_lock_irqsave(&semaphore_wake_lock, flags);
-	if (sem->waking > 0) {
-		sem->waking--;
-		ret = 1;
-	} else if (signal_pending(tsk)) {
-		atomic_inc(&sem->count);
-		ret = -EINTR;
-	}
-	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
-	return ret;
-}
-
-/*
- * waking_non_zero_trylock:
- *	1	failed to lock
- *	0	got the lock
- *
- * We must undo the sem->count down_trylock() increment while we are
- * protected by the spinlock in order to make atomic this atomic_inc() with the
- * atomic_read() in wake_one_more(), otherwise we can race. -arca
- */
-static __inline__ int waking_non_zero_trylock(struct semaphore *sem)
-{
-	unsigned long flags;
-	int ret = 1;
-
-	spin_lock_irqsave(&semaphore_wake_lock, flags);
-	if (sem->waking <= 0)
-		atomic_inc(&sem->count);
-	else {
-		sem->waking--;
-		ret = 0;
-	}
-	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
-	return ret;
-}
-
-#endif /* _ASM_PARISC_SEMAPHORE_HELPER_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/semaphore.h linux-2.4.20/include/asm-parisc/semaphore.h
--- linux-2.4.19/include/asm-parisc/semaphore.h	2002-02-25 19:38:12.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/semaphore.h	2002-10-29 11:18:31.000000000 +0000
@@ -1,26 +1,30 @@
 #ifndef _ASM_PARISC_SEMAPHORE_H
 #define _ASM_PARISC_SEMAPHORE_H
 
-#include <linux/linkage.h>
-
 /*
  * SMP- and interrupt-safe semaphores.
  *
  * (C) Copyright 1996 Linus Torvalds
  *
- * SuperH verison by Niibe Yutaka
+ * PA-RISC version by Matthew Wilcox
  *
  */
 
 #include <linux/spinlock.h>
+#include <linux/wait.h>
 #include <linux/rwsem.h>
 
 #include <asm/system.h>
-#include <asm/atomic.h>
 
+/*
+ * The `count' is initialised to the number of people who are allowed to
+ * take the lock.  (Normally we want a mutex, so this is `1').  if
+ * `count' is positive, the lock can be taken.  if it's 0, no-one is
+ * waiting on it.  if it's -1, at least one task is waiting.
+ */
 struct semaphore {
-	atomic_t count;
-	int waking;
+	spinlock_t	sentry;
+	int		count;
 	wait_queue_head_t wait;
 #if WAITQUEUE_DEBUG
 	long __magic;
@@ -35,7 +39,7 @@
 #endif
 
 #define __SEMAPHORE_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
+{ SPIN_LOCK_UNLOCKED, count, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
 	__SEM_DEBUG_INIT(name) }
 
 #define __MUTEX_INITIALIZER(name) \
@@ -49,18 +53,7 @@
 
 extern inline void sema_init (struct semaphore *sem, int val)
 {
-/*
- *	*sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
- *
- * i'd rather use the more flexible initialization above, but sadly
- * GCC 2.7.2.3 emits a bogus warning. EGCS doesnt. Oh well.
- */
-	atomic_set(&sem->count, val);
-	sem->waking = 0;
-	init_waitqueue_head(&sem->wait);
-#if WAITQUEUE_DEBUG
-	sem->__magic = (long)&sem->__magic;
-#endif
+	*sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
 }
 
 static inline void init_MUTEX (struct semaphore *sem)
@@ -73,17 +66,18 @@
 	sema_init(sem, 0);
 }
 
-asmlinkage void __down_failed(void /* special register calling convention */);
-asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
-asmlinkage int  __down_failed_trylock(void  /* params in registers */);
-asmlinkage void __up_wakeup(void /* special register calling convention */);
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return sem->count;
+}
 
 asmlinkage void __down(struct semaphore * sem);
 asmlinkage int  __down_interruptible(struct semaphore * sem);
-asmlinkage int  __down_trylock(struct semaphore * sem);
 asmlinkage void __up(struct semaphore * sem);
 
-extern spinlock_t semaphore_wake_lock;
+/* Semaphores can be `tried' from irq context.  So we have to disable
+ * interrupts while we're messing with the semaphore.  Sorry.
+ */
 
 extern __inline__ void down(struct semaphore * sem)
 {
@@ -91,8 +85,13 @@
 	CHECK_MAGIC(sem->__magic);
 #endif
 
-	if (atomic_dec_return(&sem->count) < 0)
+	spin_lock_irq(&sem->sentry);
+	if (sem->count > 0) {
+		sem->count--;
+	} else {
 		__down(sem);
+	}
+	spin_unlock_irq(&sem->sentry);
 }
 
 extern __inline__ int down_interruptible(struct semaphore * sem)
@@ -102,21 +101,33 @@
 	CHECK_MAGIC(sem->__magic);
 #endif
 
-	if (atomic_dec_return(&sem->count) < 0)
+	spin_lock_irq(&sem->sentry);
+	if (sem->count > 0) {
+		sem->count--;
+	} else {
 		ret = __down_interruptible(sem);
+	}
+	spin_unlock_irq(&sem->sentry);
 	return ret;
 }
 
+/*
+ * down_trylock returns 0 on success, 1 if we failed to get the lock.
+ * May not sleep, but must preserve irq state
+ */
 extern __inline__ int down_trylock(struct semaphore * sem)
 {
-	int ret = 0;
+	int flags, count;
 #if WAITQUEUE_DEBUG
 	CHECK_MAGIC(sem->__magic);
 #endif
 
-	if (atomic_dec_return(&sem->count) < 0)
-		ret = __down_trylock(sem);
-	return ret;
+	spin_lock_irqsave(&sem->sentry, flags);
+	count = sem->count - 1;
+	if (count >= 0)
+		sem->count = count;
+	spin_unlock_irqrestore(&sem->sentry, flags);
+	return (count < 0);
 }
 
 /*
@@ -125,11 +136,17 @@
  */
 extern __inline__ void up(struct semaphore * sem)
 {
+	int flags;
 #if WAITQUEUE_DEBUG
 	CHECK_MAGIC(sem->__magic);
 #endif
-	if (atomic_inc_return(&sem->count) <= 0)
+	spin_lock_irqsave(&sem->sentry, flags);
+	if (sem->count < 0) {
 		__up(sem);
+	} else {
+		sem->count++;
+	}
+	spin_unlock_irqrestore(&sem->sentry, flags);
 }
 
 #endif /* _ASM_PARISC_SEMAPHORE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/sembuf.h linux-2.4.20/include/asm-parisc/sembuf.h
--- linux-2.4.19/include/asm-parisc/sembuf.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/sembuf.h	2002-10-29 11:18:31.000000000 +0000
@@ -13,9 +13,13 @@
 
 struct semid64_ds {
 	struct ipc64_perm sem_perm;		/* permissions .. see ipc.h */
+#ifndef __LP64__
 	unsigned int	__pad1;
+#endif
 	__kernel_time_t	sem_otime;		/* last semop time */
+#ifndef __LP64__
 	unsigned int	__pad2;
+#endif
 	__kernel_time_t	sem_ctime;		/* last change time */
 	unsigned int	sem_nsems;		/* no. of semaphores in array */
 	unsigned int	__unused1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/shmbuf.h linux-2.4.20/include/asm-parisc/shmbuf.h
--- linux-2.4.19/include/asm-parisc/shmbuf.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/shmbuf.h	2002-10-29 11:18:30.000000000 +0000
@@ -13,12 +13,21 @@
 
 struct shmid64_ds {
 	struct ipc64_perm	shm_perm;	/* operation perms */
+#ifndef __LP64__
 	unsigned int		__pad1;
+#endif
 	__kernel_time_t		shm_atime;	/* last attach time */
+#ifndef __LP64__
 	unsigned int		__pad2;
+#endif
 	__kernel_time_t		shm_dtime;	/* last detach time */
+#ifndef __LP64__
 	unsigned int		__pad3;
+#endif
 	__kernel_time_t		shm_ctime;	/* last change time */
+#ifndef __LP64__
+	unsigned int		__pad4;
+#endif
 	size_t			shm_segsz;	/* size of segment (bytes) */
 	__kernel_pid_t		shm_cpid;	/* pid of creator */
 	__kernel_pid_t		shm_lpid;	/* pid of last operator */
@@ -28,11 +37,10 @@
 };
 
 #ifdef __LP64__
-#warning shminfo64 is an undocumented struct
 /* The 'unsigned int' (formerly 'unsigned long') data types below will
  * ensure that a 32-bit app calling shmctl(*,IPC_INFO,*) will work on
  * a wide kernel, but if some of these values are meant to contain pointers
- * they may need to be 'long long' instead. -PB
+ * they may need to be 'long long' instead. -PB XXX FIXME
  */
 #endif
 struct shminfo64 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/shmparam.h linux-2.4.20/include/asm-parisc/shmparam.h
--- linux-2.4.19/include/asm-parisc/shmparam.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/shmparam.h	2002-10-29 11:18:34.000000000 +0000
@@ -1,6 +1,6 @@
 #ifndef _ASMPARISC_SHMPARAM_H
 #define _ASMPARISC_SHMPARAM_H
 
-#define	SHMLBA PAGE_SIZE		 /* attach addr a multiple of this */
+#define SHMLBA 0x00400000   /* attach addr needs to be 4 Mb aligned */
 
 #endif /* _ASMPARISC_SHMPARAM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/smp.h linux-2.4.20/include/asm-parisc/smp.h
--- linux-2.4.19/include/asm-parisc/smp.h	2000-12-06 19:46:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/smp.h	2002-10-29 11:18:35.000000000 +0000
@@ -3,8 +3,55 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_SMP
-extern volatile unsigned long cpu_online_map;  /* Bitmap of available cpu's */
-#endif
+#if defined(CONFIG_SMP)
+
+/* Page Zero Location PDC will look for the address to branch to when we poke
+** slave CPUs still in "Icache loop".
+*/
+#define PDC_OS_BOOT_RENDEZVOUS     0x10
+#define PDC_OS_BOOT_RENDEZVOUS_HI  0x28
+
+#ifndef ASSEMBLY
+#include <linux/threads.h>	/* for NR_CPUS */
+typedef unsigned long address_t;
+
+extern volatile unsigned long cpu_online_map;
+
+
+/*
+ *	Private routines/data
+ *
+ *	physical and logical are equivalent until we support CPU hotplug.
+ */
+#define cpu_number_map(cpu)	(cpu)
+#define cpu_logical_map(cpu)	(cpu)
+
+extern void smp_send_reschedule(int cpu);
 
+#endif /* !ASSEMBLY */
+
+/*
+ *	This magic constant controls our willingness to transfer
+ *      a process across CPUs. Such a transfer incurs cache and tlb
+ *      misses. The current value is inherited from i386. Still needs
+ *      to be tuned for parisc.
+ */
+ 
+#define PROC_CHANGE_PENALTY	15		/* Schedule penalty */
+
+#undef ENTRY_SYS_CPUS
+#ifdef ENTRY_SYS_CPUS
+#define STATE_RENDEZVOUS			0
+#define STATE_STOPPED 				1 
+#define STATE_RUNNING				2
+#define STATE_HALTED				3
 #endif
+
+#define smp_processor_id() (current->processor)
+
+#endif /* CONFIG_SMP */
+
+#define NO_PROC_ID		0xFF		/* No processor magic marker */
+#define ANY_PROC_ID		0xFF		/* Any processor magic marker */
+
+#endif /*  __ASM_SMP_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/smplock.h linux-2.4.20/include/asm-parisc/smplock.h
--- linux-2.4.19/include/asm-parisc/smplock.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/smplock.h	2002-10-29 11:18:32.000000000 +0000
@@ -8,6 +8,8 @@
 
 extern spinlock_t kernel_flag;
 
+#define kernel_locked() spin_is_locked(&kernel_flag)
+
 /*
  * Release global kernel lock and global interrupt lock
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/socket.h linux-2.4.20/include/asm-parisc/socket.h
--- linux-2.4.19/include/asm-parisc/socket.h	2001-06-21 04:00:55.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/socket.h	2002-10-29 11:18:33.000000000 +0000
@@ -3,7 +3,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	0xffff
 
 #define SO_DEBUG	0x0001
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/softirq.h linux-2.4.20/include/asm-parisc/softirq.h
--- linux-2.4.19/include/asm-parisc/softirq.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/softirq.h	2002-10-29 11:18:51.000000000 +0000
@@ -8,6 +8,7 @@
 #define cpu_bh_enable(cpu)	do { barrier(); local_bh_count(cpu)--; } while (0)
 
 #define local_bh_disable()	cpu_bh_disable(smp_processor_id())
+#define __local_bh_enable()	local_bh_enable()
 #define local_bh_enable()	cpu_bh_enable(smp_processor_id())
 
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/spinlock.h linux-2.4.20/include/asm-parisc/spinlock.h
--- linux-2.4.19/include/asm-parisc/spinlock.h	2002-02-25 19:38:12.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/spinlock.h	2002-10-29 11:18:36.000000000 +0000
@@ -3,23 +3,33 @@
 
 #include <asm/system.h>
 
-/* we seem to be the only architecture that uses 0 to mean locked - but we
- * have to.  prumpf */
+/* Note that PA-RISC has to use `1' to mean unlocked and `0' to mean locked
+ * since it only has load-and-zero.
+ */
 
 #undef SPIN_LOCK_UNLOCKED
 #define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
 
 #define spin_lock_init(x)	do { (x)->lock = 1; } while(0)
 
-#define spin_unlock_wait(x)	do { barrier(); } while(((volatile spinlock_t *)(x))->lock == 1)
+#define spin_is_locked(x) ((x)->lock == 0)
+
+#define spin_unlock_wait(x)	do { barrier(); } while(((volatile spinlock_t *)(x))->lock == 0)
 
+#if 1
+#define spin_lock(x) do { \
+	while (__ldcw (&(x)->lock) == 0) \
+		while (((x)->lock) == 0) ; } while (0)
+
+#else
 #define spin_lock(x) \
 	do { while(__ldcw(&(x)->lock) == 0); } while(0)
+#endif
 	
 #define spin_unlock(x) \
 	do { (x)->lock = 1; } while(0)
 
-#define spin_trylock(x) (__ldcw(&(x)->lock) == 1)
+#define spin_trylock(x) (__ldcw(&(x)->lock) != 0)
 
 /*
  * Read-write spinlocks, allowing multiple readers
@@ -32,6 +42,8 @@
 
 #define RW_LOCK_UNLOCKED (rwlock_t) { SPIN_LOCK_UNLOCKED, 0 }
 
+#define rwlock_init(lp)	do { *(lp) = RW_LOCK_UNLOCKED; } while (0)
+
 /* read_lock, read_unlock are pretty straightforward.  Of course it somehow
  * sucks we end up saving/restoring flags twice for read_lock_irqsave aso. */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/stat.h linux-2.4.20/include/asm-parisc/stat.h
--- linux-2.4.19/include/asm-parisc/stat.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/stat.h	2002-10-29 11:18:32.000000000 +0000
@@ -66,6 +66,33 @@
 	gid_t		st_gid;
 	unsigned int	st_spare4[3];
 };
-#define stat64	hpux_stat64
+
+/* This is the struct that 32-bit userspace applications are expecting.
+ * How 64-bit apps are going to be compiled, I have no idea.  But at least
+ * this way, we don't have a wrapper in the kernel.
+ */
+struct stat64 {
+	unsigned long long	st_dev;
+	unsigned int		__pad1;
+
+	unsigned int		__st_ino;	/* Not actually filled in */
+	unsigned int		st_mode;
+	unsigned int		st_nlink;
+	unsigned int		st_uid;
+	unsigned int		st_gid;
+	unsigned long long	st_rdev;
+	unsigned int		__pad2;
+	signed long long	st_size;
+	signed int		st_blksize;
+
+	signed long long	st_blocks;
+	signed int		st_atime;
+	unsigned int		__unused1;
+	signed int		st_mtime;
+	unsigned int		__unused2;
+	signed int		st_ctime;
+	unsigned int		__unused3;
+	unsigned long long	st_ino;
+};
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/string.h linux-2.4.20/include/asm-parisc/string.h
--- linux-2.4.19/include/asm-parisc/string.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/string.h	2002-10-29 11:18:49.000000000 +0000
@@ -1,2 +1,3 @@
 
-/* This left blank until we do parisc optimizations */
+#define __HAVE_ARCH_MEMSET
+extern void * memset(void *, int, size_t);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/superio.h linux-2.4.20/include/asm-parisc/superio.h
--- linux-2.4.19/include/asm-parisc/superio.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/superio.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,81 @@
+#ifndef _PARISC_SUPERIO_H
+#define _PARISC_SUPERIO_H
+
+/* Offsets to configuration and base address registers */
+#define IC_PIC1    0x20		/* PCI I/O address of master 8259 */
+#define IC_PIC2    0xA0		/* PCI I/O address of slave */
+#define SIO_CR     0x5A		/* Configuration Register */
+#define SIO_ACPIBAR 0x88		/* ACPI BAR */
+#define SIO_FDCBAR 0x90		/* Floppy Disk Controller BAR */
+#define SIO_SP1BAR 0x94		/* Serial 1 BAR */
+#define SIO_SP2BAR 0x98		/* Serial 2 BAR */
+#define SIO_PPBAR  0x9C		/* Parallel BAR */
+
+/* Interrupt triggers and routing */
+#define TRIGGER_1  0x67		/* Edge/level trigger register 1 */
+#define TRIGGER_2  0x68		/* Edge/level trigger register 2 */
+#define IR_SER     0x69		/* Serial 1 [0:3] and Serial 2 [4:7] */
+#define IR_PFD     0x6a		/* Parallel [0:3] and Floppy [4:7] */
+#define IR_IDE     0x6b		/* IDE1 [0:3] and IDE2 [4:7] */
+#define IR_USB     0x6d         /* USB [4:7] */
+#define IR_LOW     0x69		/* Lowest interrupt routing reg */
+#define IR_HIGH    0x71		/* Highest interrupt routing reg */
+
+/* 8259 operational control words */
+#define OCW2_EOI   0x20		/* Non-specific EOI */
+#define OCW2_SEOI  0x60		/* Specific EOI */
+#define OCW3_IIR   0x0A		/* Read request register */
+#define OCW3_ISR   0x0B		/* Read service register */
+#define OCW3_POLL  0x0C		/* Poll the PIC for an interrupt vector */
+
+/* Interrupt lines. Only PIC1 is used */
+#define USB_IRQ    1		/* USB */
+#define SP1_IRQ    3		/* Serial port 1 */
+#define SP2_IRQ    4		/* Serial port 2 */
+#define PAR_IRQ    5		/* Parallel port */
+#define FDC_IRQ    6		/* Floppy controller */
+#define IDE_IRQ    7		/* IDE (pri+sec) */
+
+/* ACPI registers */
+#define USB_REG_CR	0x1f	/* USB Regulator Control Register */
+
+#define SUPERIO_NIRQS   8
+
+struct superio_device {
+	u16 fdc_base;
+	u16 sp1_base;
+	u16 sp2_base;
+	u16 pp_base;
+	u16 acpi_base;
+	int iosapic_irq;
+	int iosapic_irq_enabled;
+	struct irq_region *irq_region;
+	struct pci_dev *lio_pdev;       /* pci device for legacy IO fn */
+};
+
+/*
+ * Does NS make a 87415 based plug in PCI card? If so, because of this
+ * macro we currently don't support it being plugged into a machine
+ * that contains a SuperIO chip AND has CONFIG_SUPERIO enabled.
+ *
+ * This could be fixed by checking to see if function 1 exists, and
+ * if it is SuperIO Legacy IO; but really now, is this combination
+ * going to EVER happen?
+ */
+
+#define SUPERIO_IDE_FN 0 /* Function number of IDE controller */
+#define SUPERIO_LIO_FN 1 /* Function number of Legacy IO controller */
+#define SUPERIO_USB_FN 2 /* Function number of USB controller */
+
+#define is_superio_device(x) \
+	(((x)->vendor == PCI_VENDOR_ID_NS) && \
+	(  ((x)->device == PCI_DEVICE_ID_NS_87415) \
+	|| ((x)->device == PCI_DEVICE_ID_NS_87560_LIO) \
+	|| ((x)->device == PCI_DEVICE_ID_NS_87560_USB) ) )
+
+extern void superio_inform_irq(int irq);
+extern void superio_serial_init(void);		/* called by rs_init() */
+extern int superio_fixup_irq(struct pci_dev *pcidev); /* called by iosapic */
+extern int superio_get_ide_irq(void);
+
+#endif /* _PARISC_SUPERIO_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/system.h linux-2.4.20/include/asm-parisc/system.h
--- linux-2.4.19/include/asm-parisc/system.h	2000-12-06 19:46:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/system.h	2002-10-29 11:18:32.000000000 +0000
@@ -35,7 +35,11 @@
 	unsigned int i:1;
 };
 
+#ifdef __LP64__
+#define pa_psw(task) ((struct pa_psw *) ((char *) (task) + TASK_PT_PSW + 4))
+#else
 #define pa_psw(task) ((struct pa_psw *) ((char *) (task) + TASK_PT_PSW))
+#endif
 
 struct task_struct;
 
@@ -46,20 +50,7 @@
 	(last) = _switch_to(prev, next);			\
 } while(0)
 
-/* borrowed this from sparc64 -- probably the SMP case is hosed for us */
-#ifdef CONFIG_SMP
-#define smp_mb()	mb()
-#define smp_rmb()	rmb()
-#define smp_wmb()	wmb()
-#else
-/* This is simply the barrier() macro from linux/kernel.h but when serial.c
- * uses tqueue.h uses smp_mb() defined using barrier(), linux/kernel.h
- * hasn't yet been included yet so it fails, thus repeating the macro here.
- */
-#define smp_mb()	__asm__ __volatile__("":::"memory");
-#define smp_rmb()	__asm__ __volatile__("":::"memory");
-#define smp_wmb()	__asm__ __volatile__("":::"memory");
-#endif
+
 
 /* interrupt control */
 #define __save_flags(x)	__asm__ __volatile__("ssm 0, %0" : "=r" (x) : : "memory")
@@ -69,17 +60,31 @@
 
 #define local_irq_save(x) \
 	__asm__ __volatile__("rsm %1,%0" : "=r" (x) :"i" (PSW_I) : "memory" )
+#define local_irq_set(x) \
+	__asm__ __volatile__("ssm %1,%0" : "=r" (x) :"i" (PSW_I) : "memory" )
 #define local_irq_restore(x) \
 	__asm__ __volatile__("mtsm %0" : : "r" (x) : "memory" )
 #define local_irq_disable() __cli()
 #define local_irq_enable()  __sti()
 
 #ifdef CONFIG_SMP
+extern void __global_cli(void);
+extern void __global_sti(void);
+extern unsigned long __global_save_flags(void);
+extern void __global_restore_flags(unsigned long);
+
+#define cli() __global_cli()
+#define sti() __global_sti()
+#define save_flags(x) ((x)=__global_save_flags())
+#define restore_flags(x) __global_restore_flags(x)
+ 
 #else
+
 #define cli() __cli()
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
+
 #endif
 
 
@@ -120,21 +125,43 @@
 		: "r" (gr), "i" (cr))
 
 
-#define mb()  __asm__ __volatile__ ("sync" : : :"memory")
-#define wmb() mb()
+/*
+** This is simply the barrier() macro from linux/kernel.h but when serial.c
+** uses tqueue.h uses smp_mb() defined using barrier(), linux/kernel.h
+** hasn't yet been included yet so it fails, thus repeating the macro here.
+**
+** PA-RISC architecture allows for weakly ordered memory accesses although
+** none of the processors use it. There is a strong ordered bit that is
+** set in the O-bit of the page directory entry. Operating systems that
+** can not tolerate out of order accesses should set this bit when mapping
+** pages. The O-bit of the PSW should also be set to 1 (I don't believe any
+** of the processor implemented the PSW O-bit). The PCX-W ERS states that
+** the TLB O-bit is not implemented so the page directory does not need to
+** have the O-bit set when mapping pages (section 3.1). This section also
+** states that the PSW Y, Z, G, and O bits are not implemented.
+** So it looks like nothing needs to be done for parisc-linux (yet).
+** (thanks to chada for the above comment -ggg)
+**
+** The __asm__ op below simple prevents gcc/ld from reordering
+** instructions across the mb() "call".
+*/
+#define mb()		__asm__ __volatile__("":::"memory");	/* barrier() */
+#define rmb()		mb()
+#define wmb()		mb()
+#define smp_mb()	mb()
+#define smp_wmb()	mb()
 
-extern unsigned long __xchg(unsigned long, unsigned long *, int);
+#define set_mb(var, value) do { var = value; mb(); } while (0)
 
-#define xchg(ptr,x) \
- (__typeof__(*(ptr)))__xchg((unsigned long)(x),(unsigned long*)(ptr),sizeof(*(ptr)))
 
-/* LDCW, the only atomic read-write operation PA-RISC has.  Sigh. */
+/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.  */
 #define __ldcw(a) ({ \
 	unsigned __ret; \
 	__asm__ __volatile__("ldcw 0(%1),%0" : "=r" (__ret) : "r" (a)); \
 	__ret; \
 })
 
+
 #ifdef CONFIG_SMP
 /*
  * Your basic SMP spinlocks, allowing only a single CPU anywhere
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/termios.h linux-2.4.20/include/asm-parisc/termios.h
--- linux-2.4.19/include/asm-parisc/termios.h	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/termios.h	2002-10-29 11:18:33.000000000 +0000
@@ -37,6 +37,9 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+/* IRDA support - PA-RISC uses OUT1 as hardware flow control bit. */
+#define TIOCM_MODEM_BITS        (TIOCM_OUT2 | TIOCM_OUT1)
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
 /* line disciplines */
@@ -53,6 +56,8 @@
 #define N_PROFIBUS_FDL	10	/* Reserved for Profibus <Dave@mvhi.com> */
 #define N_IRDA		11	/* Linux IR - http://irda.sourceforge.net/ */
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
+#define N_HDLC		13	/* synchronous HDLC */
+#define N_SYNC_PPP	14
 #define N_HCI		15  /* Bluetooth HCI UART */
 
 #ifdef __KERNEL__
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/timex.h linux-2.4.20/include/asm-parisc/timex.h
--- linux-2.4.19/include/asm-parisc/timex.h	2000-12-06 19:46:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/timex.h	2002-10-29 11:18:40.000000000 +0000
@@ -18,4 +18,7 @@
 	return mfctl(16);
 }
 
+#define vxtime_lock()		do {} while (0)
+#define vxtime_unlock()		do {} while (0)
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/tlb.h linux-2.4.20/include/asm-parisc/tlb.h
--- linux-2.4.19/include/asm-parisc/tlb.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/tlb.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/traps.h linux-2.4.20/include/asm-parisc/traps.h
--- linux-2.4.19/include/asm-parisc/traps.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/traps.h	2002-10-29 11:18:33.000000000 +0000
@@ -1,4 +1,16 @@
 #ifndef __ASM_TRAPS_H
 #define __ASM_TRAPS_H
 
+#ifdef __KERNEL__
+struct pt_regs;
+
+/* traps.c */
+void parisc_terminate(char *msg, struct pt_regs *regs,
+		int code, unsigned long offset);
+
+/* mm/fault.c */
+void do_page_fault(struct pt_regs *regs, unsigned long code,
+		unsigned long address);
+#endif
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/types.h linux-2.4.20/include/asm-parisc/types.h
--- linux-2.4.19/include/asm-parisc/types.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/types.h	2002-10-29 11:18:33.000000000 +0000
@@ -48,6 +48,7 @@
 /* Dma addresses are 32-bits wide.  */
 
 typedef u32 dma_addr_t;
+typedef u64 dma64_addr_t;
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/uaccess.h linux-2.4.20/include/asm-parisc/uaccess.h
--- linux-2.4.19/include/asm-parisc/uaccess.h	2000-12-06 19:46:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/uaccess.h	2002-10-29 11:18:34.000000000 +0000
@@ -34,6 +34,18 @@
 #define put_user __put_user
 #define get_user __get_user
 
+#if BITS_PER_LONG == 32
+#define LDD_KERNEL(ptr)		BUG()
+#define LDD_USER(ptr)		BUG()
+#define STD_KERNEL(x, ptr)	BUG()
+#define STD_USER(x, ptr)	BUG()
+#else
+#define LDD_KERNEL(ptr) __get_kernel_asm("ldd",ptr)
+#define LDD_USER(ptr) __get_user_asm("ldd",ptr)
+#define STD_KERNEL(x, ptr) __put_kernel_asm("std",x,ptr)
+#define STD_USER(x, ptr) __put_user_asm("std",x,ptr)
+#endif
+
 /*
  * The exception table contains two values: the first is an address
  * for an instruction that is allowed to fault, and the second is
@@ -46,7 +58,7 @@
 
 struct exception_table_entry {
 	unsigned long addr;  /* address of insn that is allowed to fault.   */
-	int skip;            /* pcoq skip | r9 clear flag | r8 -EFAULT flag */
+	long skip;           /* pcoq skip | r9 clear flag | r8 -EFAULT flag */
 };
 
 extern const struct exception_table_entry 
@@ -62,7 +74,7 @@
 	    case 1: __get_kernel_asm("ldb",ptr); break; \
 	    case 2: __get_kernel_asm("ldh",ptr); break; \
 	    case 4: __get_kernel_asm("ldw",ptr); break; \
-	    case 8: __get_kernel_asm("ldd",ptr); break; \
+	    case 8: LDD_KERNEL(ptr); break;		\
 	    default: BUG(); break;                      \
 	    }                                           \
 	}                                               \
@@ -71,7 +83,7 @@
 	    case 1: __get_user_asm("ldb",ptr); break;   \
 	    case 2: __get_user_asm("ldh",ptr); break;   \
 	    case 4: __get_user_asm("ldw",ptr); break;   \
-	    case 8: __get_user_asm("ldd",ptr); break;   \
+	    case 8: LDD_USER(ptr);  break;		\
 	    default: BUG(); break;                      \
 	    }                                           \
 	}                                               \
@@ -80,6 +92,27 @@
 	__gu_err;                                       \
 })
 
+#ifdef __LP64__
+#define __get_kernel_asm(ldx,ptr)                       \
+	__asm__("\n1:\t" ldx "\t0(%2),%0\n"             \
+		"2:\n"					\
+		"\t.section __ex_table,\"a\"\n"         \
+		 "\t.dword\t1b\n"                       \
+		 "\t.dword\t(2b-1b)+3\n"                \
+		 "\t.previous"                          \
+		: "=r"(__gu_val), "=r"(__gu_err)        \
+		: "r"(ptr), "1"(__gu_err));
+
+#define __get_user_asm(ldx,ptr)                         \
+	__asm__("\n1:\t" ldx "\t0(%%sr3,%2),%0\n"       \
+		"2:\n"					\
+		"\t.section __ex_table,\"a\"\n"         \
+		 "\t.dword\t1b\n"                       \
+		 "\t.dword\t(2b-1b)+3\n"                \
+		 "\t.previous"                          \
+		: "=r"(__gu_val), "=r"(__gu_err)        \
+		: "r"(ptr), "1"(__gu_err));
+#else
 #define __get_kernel_asm(ldx,ptr)                       \
 	__asm__("\n1:\t" ldx "\t0(%2),%0\n"             \
 		"2:\n"					\
@@ -99,7 +132,7 @@
 		 "\t.previous"                          \
 		: "=r"(__gu_val), "=r"(__gu_err)        \
 		: "r"(ptr), "1"(__gu_err));
-
+#endif
 
 #define __put_user(x,ptr)                                       \
 ({								\
@@ -110,7 +143,7 @@
 	    case 1: __put_kernel_asm("stb",x,ptr); break;       \
 	    case 2: __put_kernel_asm("sth",x,ptr); break;       \
 	    case 4: __put_kernel_asm("stw",x,ptr); break;       \
-	    case 8: __put_kernel_asm("std",x,ptr); break;       \
+	    case 8: STD_KERNEL(x,ptr); break;			\
 	    default: BUG(); break;                              \
 	    }                                                   \
 	}                                                       \
@@ -119,7 +152,7 @@
 	    case 1: __put_user_asm("stb",x,ptr); break;         \
 	    case 2: __put_user_asm("sth",x,ptr); break;         \
 	    case 4: __put_user_asm("stw",x,ptr); break;         \
-	    case 8: __put_user_asm("std",x,ptr); break;         \
+	    case 8: STD_USER(x,ptr); break;			\
 	    default: BUG(); break;                              \
 	    }                                                   \
 	}                                                       \
@@ -133,6 +166,29 @@
  * gcc knows about, so there are no aliasing issues.
  */
 
+#ifdef __LP64__
+#define __put_kernel_asm(stx,x,ptr)                         \
+	__asm__ __volatile__ (                              \
+		"\n1:\t" stx "\t%2,0(%1)\n"                 \
+		"2:\n"					    \
+		"\t.section __ex_table,\"a\"\n"             \
+		 "\t.dword\t1b\n"                           \
+		 "\t.dword\t(2b-1b)+1\n"                    \
+		 "\t.previous"                              \
+		: "=r"(__pu_err)                            \
+		: "r"(ptr), "r"(x), "0"(__pu_err))
+
+#define __put_user_asm(stx,x,ptr)                           \
+	__asm__ __volatile__ (                              \
+		"\n1:\t" stx "\t%2,0(%%sr3,%1)\n"           \
+		"2:\n"					    \
+		"\t.section __ex_table,\"a\"\n"             \
+		 "\t.dword\t1b\n"                           \
+		 "\t.dword\t(2b-1b)+1\n"                    \
+		 "\t.previous"                              \
+		: "=r"(__pu_err)                            \
+		: "r"(ptr), "r"(x), "0"(__pu_err))
+#else
 #define __put_kernel_asm(stx,x,ptr)                         \
 	__asm__ __volatile__ (                              \
 		"\n1:\t" stx "\t%2,0(%1)\n"                 \
@@ -154,6 +210,7 @@
 		 "\t.previous"                              \
 		: "=r"(__pu_err)                            \
 		: "r"(ptr), "r"(x), "0"(__pu_err))
+#endif
 
 
 /*
@@ -174,16 +231,11 @@
 #define strnlen_user lstrnlen_user
 #define strlen_user(str) lstrnlen_user(str, 0x7fffffffL)
 #define clear_user lclear_user
+#define __clear_user lclear_user
 
 #define copy_from_user lcopy_from_user
 #define __copy_from_user lcopy_from_user
 #define copy_to_user lcopy_to_user
 #define __copy_to_user lcopy_to_user
 
-#define copy_to_user_ret(to,from,n,retval) \
-    ({ if (lcopy_to_user(to,from,n)) return retval; })
-
-#define copy_from_user_ret(to,from,n,retval) \
-    ({ if (lcopy_from_user(to,from,n)) return retval; })
-
 #endif /* __PARISC_UACCESS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/unaligned.h linux-2.4.20/include/asm-parisc/unaligned.h
--- linux-2.4.19/include/asm-parisc/unaligned.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/unaligned.h	2002-10-29 11:18:49.000000000 +0000
@@ -17,4 +17,11 @@
      memmove((ptr), &__tmp, sizeof(*(ptr)));		\
      (void)0; })
 
-#endif /* _ASM_PARISC_UNALIGNED_H */
+
+#ifdef __KERNEL__
+struct pt_regs;
+void handle_unaligned(struct pt_regs *regs);
+int check_unaligned(struct pt_regs *regs);
+#endif
+
+#endif /* _ASM_PARISC_UNALIGNED_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/unistd.h linux-2.4.20/include/asm-parisc/unistd.h
--- linux-2.4.19/include/asm-parisc/unistd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/unistd.h	2002-10-29 11:18:31.000000000 +0000
@@ -579,7 +579,7 @@
 #define __NR_uselib              (__NR_Linux + 86)
 #define __NR_swapon              (__NR_Linux + 87)
 #define __NR_reboot              (__NR_Linux + 88)
-#define __NR_readdir             (__NR_Linux + 89)
+#define __NR_mmap2             (__NR_Linux + 89)
 #define __NR_mmap                (__NR_Linux + 90)
 #define __NR_munmap              (__NR_Linux + 91)
 #define __NR_truncate            (__NR_Linux + 92)
@@ -591,8 +591,8 @@
 #define __NR_recv                (__NR_Linux + 98)
 #define __NR_statfs              (__NR_Linux + 99)
 #define __NR_fstatfs            (__NR_Linux + 100)
-#define __NR_ioperm             (__NR_Linux + 101)
-#define __NR_socketcall         (__NR_Linux + 102)
+#define __NR_stat64           (__NR_Linux + 101)
+/* #define __NR_socketcall         (__NR_Linux + 102) */
 #define __NR_syslog             (__NR_Linux + 103)
 #define __NR_setitimer          (__NR_Linux + 104)
 #define __NR_getitimer          (__NR_Linux + 105)
@@ -602,7 +602,7 @@
 #define __NR_pwrite             (__NR_Linux + 109)
 #define __NR_getcwd             (__NR_Linux + 110)
 #define __NR_vhangup            (__NR_Linux + 111)
-#define __NR_idle               (__NR_Linux + 112)
+#define __NR_fstat64            (__NR_Linux + 112)
 #define __NR_vfork              (__NR_Linux + 113)
 #define __NR_wait4              (__NR_Linux + 114)
 #define __NR_swapoff            (__NR_Linux + 115)
@@ -689,14 +689,24 @@
 
 #define __NR_getpmsg            (__NR_Linux + 196)      /* some people actually want streams */
 #define __NR_putpmsg            (__NR_Linux + 197)      /* some people actually want streams */
-#define __NR_gettid             (__NR_Linux + 198)
-#define __NR_tkill              (__NR_Linux + 199)
 
-#define __NR_Linux_syscalls     199
+#define __NR_lstat64            (__NR_Linux + 198)
+#define __NR_truncate64         (__NR_Linux + 199)
+#define __NR_ftruncate64        (__NR_Linux + 200)
+#define __NR_getdents64         (__NR_Linux + 201)
+#define __NR_fcntl64            (__NR_Linux + 202)
+#define __NR_attrctl            (__NR_Linux + 203)
+#define __NR_acl_get            (__NR_Linux + 204)
+#define __NR_acl_set            (__NR_Linux + 205)
+#define __NR_gettid             (__NR_Linux + 206)
+#define __NR_readahead          (__NR_Linux + 207)
+
+#define __NR_Linux_syscalls     207
 
 #define HPUX_GATEWAY_ADDR       0xC0000004
 #define LINUX_GATEWAY_ADDR      0x100
-#define LINUX_GATEWAY_STR       "0x100"
+
+#ifndef __ASSEMBLY__
 
 /* The old syscall code here didn't work, and it looks like it's only used
  * by applications such as fdisk which for some reason need to produce
@@ -725,7 +735,7 @@
         }                                                       \
         if (__sys_res >= (unsigned long)-4095) {                \
 		errno = -__sys_res;				\
-                __sys_res == (unsigned long)-1;                 \
+                __sys_res = (unsigned long)-1;                 \
         }                                                       \
         __sys_res;                                              \
 })
@@ -796,7 +806,7 @@
 }
 
 
-/* mmap takes 6 arguments */
+/* mmap & mmap2 take 6 arguments */
 
 #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \
 type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) \
@@ -804,13 +814,8 @@
     return K_INLINE_SYSCALL(name, 6, arg1, arg2, arg3, arg4, arg5, arg6);	\
 }
 
-#ifdef __KERNEL_SYSCALLS__
 
-static inline int idle(void)
-{
-	extern int sys_idle(void);
-	return sys_idle();
-}
+#ifdef __KERNEL_SYSCALLS__
 
 static inline int pause(void)
 {
@@ -854,6 +859,13 @@
 	return sys_dup(fd);
 }
 
+static inline int execve(char *filename, char * argv [],
+	char * envp[])
+{
+	extern int __execve(char *, char **, char **, struct task_struct *);
+	return __execve(filename, argv, envp, current);
+}
+
 static inline int open(const char *file, int flag, int mode)
 {
 	extern long sys_open(const char *, int, int);
@@ -873,7 +885,6 @@
 
 static inline pid_t waitpid(pid_t pid, int *wait_stat, int options)
 {
-	extern int sys_wait4(int, int *, int, struct rusage *);
 	return sys_wait4((int)pid, wait_stat, options, NULL);
 }
 
@@ -885,18 +896,12 @@
 
 static inline pid_t wait(int * wait_stat)
 {
-	extern int sys_wait4(int, int *, int, struct rusage *);
 	return sys_wait4(-1, wait_stat, 0, NULL);
 }
 
-static inline int execve(char *filename, char * argv [],
-	char * envp[])
-{
-	extern int __execve(char *, char **, char **, struct task_struct *);
-	return __execve(filename, argv, envp, current);
-}
+#endif	/* __KERNEL_SYSCALLS__ */
 
-#endif
+#endif /* __ASSEMBLY__ */
 
 #undef STR
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-parisc/xor.h linux-2.4.20/include/asm-parisc/xor.h
--- linux-2.4.19/include/asm-parisc/xor.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-parisc/xor.h	2002-10-29 11:18:47.000000000 +0000
@@ -0,0 +1 @@
+#include <asm-generic/xor.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/amigaints.h linux-2.4.20/include/asm-ppc/amigaints.h
--- linux-2.4.19/include/asm-ppc/amigaints.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/amigaints.h	2002-10-29 11:18:31.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.amigaints.h 1.5 05/17/01 18:14:24 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
 ** amigaints.h -- Amiga Linux interrupt handling structs and prototypes
@@ -110,12 +110,8 @@
 #define IF_DSKBLK   0x0002	/* diskblock DMA finished */
 #define IF_TBE	    0x0001	/* serial transmit buffer empty interrupt */
 
-struct irq_server {
-	unsigned short count, reentrance;
-};
-
 extern void amiga_do_irq(int irq, struct pt_regs *fp);
-extern void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server);
+extern void amiga_do_irq_list(int irq, struct pt_regs *fp);
 
 /* CIA interrupt control register bits */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/board.h linux-2.4.20/include/asm-ppc/board.h
--- linux-2.4.19/include/asm-ppc/board.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/board.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,47 +0,0 @@
-/*
- * BK Id: SCCS/s.board.h 1.5 05/17/01 18:14:24 cort
- */
-/*
- *
- *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: board.h
- *
- *    Description:
- *	A generic include file which pulls in appropriate include files
- *      for specific board types based on configuration settings.
- *
- */
-
-#ifdef __KERNEL__
-#ifndef __BOARD_H__
-#define	__BOARD_H__
-
-#include <linux/config.h>
-
-#if defined(CONFIG_OAK)
-#include <asm/oak.h>
-#endif
-
-#if defined(CONFIG_WALNUT)
-#include <asm/walnut.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * The "residual" board information structure the boot loader passes
- * into the kernel.
- */
-
-extern unsigned char __res[];
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __BOARD_H__ */
-#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/bootinfo.h linux-2.4.20/include/asm-ppc/bootinfo.h
--- linux-2.4.19/include/asm-ppc/bootinfo.h	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/bootinfo.h	2002-10-29 11:18:38.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.bootinfo.h 1.11 08/17/01 15:23:17 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Non-machine dependent bootinfo structure.  Basic idea
@@ -33,6 +33,10 @@
 #define BI_MACHTYPE		0x1016
 #define BI_MEMSIZE		0x1017
 
+extern struct bi_record *find_bootinfo(void);
+extern void parse_bootinfo(struct bi_record *rec);
+extern unsigned long boot_mem_size;
+
 #endif /* CONFIG_APUS */
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/bseip.h linux-2.4.20/include/asm-ppc/bseip.h
--- linux-2.4.19/include/asm-ppc/bseip.h	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/bseip.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,42 +0,0 @@
-/*
- * BK Id: SCCS/s.bseip.h 1.10 08/17/01 15:23:17 paulus
- */
-
-/*
- * A collection of structures, addresses, and values associated with
- * the Bright Star Engineering ip-Engine board.  Copied from the MBX stuff.
- *
- * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
- */
-#ifndef __MACH_BSEIP_DEFS
-#define __MACH_BSEIP_DEFS
-
-#ifndef __ASSEMBLY__
-/* A Board Information structure that is given to a program when
- * prom starts it up.
- */
-typedef struct bd_info {
-	unsigned int	bi_memstart;	/* Memory start address */
-	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
-	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
-	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
-	unsigned char	bi_enetaddr[6];
-	unsigned int	bi_baudrate;
-} bd_t;
-
-extern bd_t m8xx_board_info;
-
-/* Memory map is configured by the PROM startup.
- * All we need to get started is the IMMR.
- */
-#define IMAP_ADDR		((uint)0xff000000)
-#define IMAP_SIZE		((uint)(64 * 1024))
-#define PCMCIA_MEM_ADDR		((uint)0x04000000)
-#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
-#endif	/* !__ASSEMBLY__ */
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS	0
-
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/cputable.h linux-2.4.20/include/asm-ppc/cputable.h
--- linux-2.4.19/include/asm-ppc/cputable.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/cputable.h	2002-10-29 11:18:39.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.cputable.h 1.4 03/19/02 15:04:39 benh
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  include/asm-ppc/cputable.h
@@ -32,6 +32,10 @@
 /* This structure can grow, it's real size is used by head.S code
  * via the mkdefs mecanism.
  */
+struct cpu_spec;
+
+typedef	void (*cpu_setup_t)(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+
 struct cpu_spec {
 	/* CPU is matched via (PVR & pvr_mask) == pvr_value */
 	unsigned int	pvr_mask;
@@ -48,7 +52,7 @@
 	/* this is called to initialize various CPU bits like L1 cache,
 	 * BHT, SPD, etc... from head.S before branching to identify_machine
 	 */
-	void		(*cpu_setup)(int cpu_nr);
+	cpu_setup_t	cpu_setup;
 };
 
 extern struct cpu_spec		cpu_specs[];
@@ -69,6 +73,9 @@
 #define CPU_FTR_HPTE_TABLE		0x00000200
 #define CPU_FTR_CAN_NAP			0x00000400
 #define CPU_FTR_L3CR			0x00000800
+#define CPU_FTR_L3_DISABLE_NAP		0x00001000
+#define CPU_FTR_NAP_DISABLE_L2_PR	0x00002000
+#define CPU_FTR_DUAL_PLL_750FX		0x00004000
 
 #ifdef __ASSEMBLY__
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/est8260.h linux-2.4.20/include/asm-ppc/est8260.h
--- linux-2.4.19/include/asm-ppc/est8260.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/est8260.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,31 +0,0 @@
-/*
- * BK Id: SCCS/s.est8260.h 1.5 05/17/01 18:14:24 cort
- */
-
-/* Board information for the EST8260, which should be generic for
- * all 8260 boards.  The IMMR is now given to us so the hard define
- * will soon be removed.  All of the clock values are computed from
- * the configuration SCMR and the Power-On-Reset word.
- */
-
-#define IMAP_ADDR	((uint)0xf0000000)
-
-
-/* A Board Information structure that is given to a program when
- * prom starts it up.
- */
-typedef struct bd_info {
-	unsigned int	bi_memstart;	/* Memory start address */
-	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
-	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
-	unsigned int	bi_busfreq;	/* Bus Freq, in MHz */
-	unsigned int	bi_cpmfreq;	/* CPM Freq, in MHz */
-	unsigned int	bi_brgfreq;	/* BRG Freq, in MHz */
-	unsigned int	bi_vco;		/* VCO Out from PLL */
-	unsigned int	bi_baudrate;	/* Default console baud rate */
-	unsigned int	bi_immr;	/* IMMR when called from boot rom */
-	unsigned char	bi_enetaddr[6];
-} bd_t;
-
-extern bd_t m8xx_board_info;
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/fads.h linux-2.4.20/include/asm-ppc/fads.h
--- linux-2.4.19/include/asm-ppc/fads.h	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/fads.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,61 +0,0 @@
-/*
- * BK Id: SCCS/s.fads.h 1.14 10/26/01 10:14:09 trini
- */
-
-/*
- * A collection of structures, addresses, and values associated with
- * the Motorola 860T FADS board.  Copied from the MBX stuff.
- *
- * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
- */
-#ifdef __KERNEL__
-#ifndef __ASM_FADS_H__
-#define __ASM_FADS_H__
-
-#include <linux/config.h>
-
-#include <asm/ppcboot.h>
-
-/* Memory map is configured by the PROM startup.
- * I tried to follow the FADS manual, although the startup PROM
- * dictates this and we simply have to move some of the physical
- * addresses for Linux.
- */
-#define BCSR_ADDR		((uint)0xff010000)
-#define BCSR_SIZE		((uint)(64 * 1024))
-#define	BCSR0			((uint)0xff010000)
-#define	BCSR1			((uint)0xff010004)
-#define	BCSR2			((uint)0xff010008)
-#define	BCSR3			((uint)0xff01000c)
-#define	BCSR4			((uint)0xff010010)
-
-#define IMAP_ADDR		((uint)0xff000000)
-#define IMAP_SIZE		((uint)(64 * 1024))
-
-#define PCMCIA_MEM_ADDR		((uint)0xff020000)
-#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
-
-/* Bits of interest in the BCSRs.
- */
-#define BCSR1_ETHEN		((uint)0x20000000)
-#define BCSR1_RS232EN_1		((uint)0x01000000)
-#define BCSR1_RS232EN_2		((uint)0x00040000)
-#define BCSR4_ETHLOOP		((uint)0x80000000)	/* EEST Loopback */
-#define BCSR4_EEFDX		((uint)0x40000000)	/* EEST FDX enable */
-#define BCSR4_FETH_EN		((uint)0x08000000)	/* PHY enable */
-#define BCSR4_FETHCFG0		((uint)0x04000000)	/* PHY autoneg mode */
-#define BCSR4_FETHCFG1		((uint)0x00400000)	/* PHY autoneg mode */
-#define BCSR4_FETHFDE		((uint)0x02000000)	/* PHY FDX advertise */
-#define BCSR4_FETHRST		((uint)0x00200000)	/* PHY Reset */
-
-/* Interrupt level assignments.
- */
-#define FEC_INTERRUPT	SIU_LEVEL1	/* FEC interrupt */
-#define PHY_INTERRUPT	SIU_IRQ2	/* PHY link change interrupt */
-
-/* We don't use the 8259.
- */
-#define NR_8259_INTS	0
-
-#endif /* __ASM_FADS_H__ */
-#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/floppy.h linux-2.4.20/include/asm-ppc/floppy.h
--- linux-2.4.19/include/asm-ppc/floppy.h	2001-10-25 20:53:55.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/floppy.h	2002-10-29 11:18:37.000000000 +0000
@@ -33,11 +33,6 @@
 				            "floppy", NULL)
 #define fd_free_irq()           free_irq(FLOPPY_IRQ, NULL);
 
-__inline__ void virtual_dma_init(void)
-{
-	/* Nothing to do on PowerPC */
-}
-
 static int FDC1 = 0x3f0;
 static int FDC2 = -1;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/gemini.h linux-2.4.20/include/asm-ppc/gemini.h
--- linux-2.4.19/include/asm-ppc/gemini.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/gemini.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,171 +0,0 @@
-/*
- * BK Id: SCCS/s.gemini.h 1.5 05/17/01 18:14:24 cort
- */
-/*
- *  include/asm-ppc/gemini.h
- *
- *
- *  Onboard registers and descriptions for Synergy Microsystems' 
- *  "Gemini" boards.
- *
- */
-#ifdef __KERNEL__
-#ifndef __PPC_GEMINI_H
-#define __PPC_GEMINI_H
-
-/*  Registers  */
-
-#define GEMINI_SERIAL_B     (0xffeffb00)
-#define GEMINI_SERIAL_A     (0xffeffb08)
-#define GEMINI_USWITCH      (0xffeffd00)
-#define GEMINI_BREV         (0xffeffe00)
-#define GEMINI_BECO         (0xffeffe08)
-#define GEMINI_FEAT         (0xffeffe10)
-#define GEMINI_BSTAT        (0xffeffe18)
-#define GEMINI_CPUSTAT      (0xffeffe20)
-#define GEMINI_L2CFG        (0xffeffe30)
-#define GEMINI_MEMCFG       (0xffeffe38)
-#define GEMINI_FLROM        (0xffeffe40)
-#define GEMINI_P0PCI        (0xffeffe48)
-#define GEMINI_FLWIN        (0xffeffe50)
-#define GEMINI_P0INTMASK    (0xffeffe60)
-#define GEMINI_P0INTAP      (0xffeffe68)
-#define GEMINI_PCIERR       (0xffeffe70)
-#define GEMINI_LEDBASE      (0xffeffe80)
-#define GEMINI_RTC          (0xffe9fff8)
-#define GEMINI_LEDS         8
-#define GEMINI_SWITCHES     8
-
-
-/* Flash ROM bit definitions */
-#define GEMINI_FLS_WEN      (1<<0)
-#define GEMINI_FLS_JMP      (1<<6)
-#define GEMINI_FLS_BOOT     (1<<7)
-
-/* Memory bit definitions */
-#define GEMINI_MEM_TYPE_MASK 0xc0
-#define GEMINI_MEM_SIZE_MASK 0x38
-#define GEMINI_MEM_BANK_MASK 0x07
-
-/* L2 cache bit definitions */
-#define GEMINI_L2_SIZE_MASK  0xc0
-#define GEMINI_L2_RATIO_MASK 0x03
-
-/* Timebase register bit definitons */
-#define GEMINI_TIMEB0_EN     (1<<0)
-#define GEMINI_TIMEB1_EN     (1<<1)
-#define GEMINI_TIMEB2_EN     (1<<2)
-#define GEMINI_TIMEB3_EN     (1<<3)
-
-/* CPU status bit definitions */
-#define GEMINI_CPU_ID_MASK   0x03
-#define GEMINI_CPU_COUNT_MASK 0x0c
-#define GEMINI_CPU0_HALTED   (1<<4)
-#define GEMINI_CPU1_HALTED   (1<<5)
-#define GEMINI_CPU2_HALTED   (1<<6)
-#define GEMINI_CPU3_HALTED   (1<<7)
-
-/* Board status bit definitions */
-#define GEMINI_BRD_FAIL      (1<<0)   /* FAIL led is lit */
-#define GEMINI_BRD_BUS_MASK  0x0c     /* PowerPC bus speed */
-
-/* Board family/feature bit descriptions */
-#define GEMINI_FEAT_HAS_FLASH (1<<0)
-#define GEMINI_FEAT_HAS_ETH   (1<<1)
-#define GEMINI_FEAT_HAS_SCSI  (1<<2)
-#define GEMINI_FEAT_HAS_P0    (1<<3)
-#define GEMINI_FEAT_FAM_MASK  0xf0
-
-/* Mod/ECO bit definitions */
-#define GEMINI_ECO_LEVEL_MASK 0x0f
-#define GEMINI_MOD_MASK       0xf0
-
-/* Type/revision bit definitions */
-#define GEMINI_REV_MASK       0x0f
-#define GEMINI_TYPE_MASK      0xf0
-
-/* User switch definitions */
-#define GEMINI_SWITCH_VERBOSE    1     /* adds "debug" to boot cmd line */
-#define GEMINI_SWITCH_SINGLE_USER 7    /* boots into "single-user" mode */
-
-#define SGS_RTC_CONTROL  0
-#define SGS_RTC_SECONDS  1
-#define SGS_RTC_MINUTES  2
-#define SGS_RTC_HOURS    3
-#define SGS_RTC_DAY      4
-#define SGS_RTC_DAY_OF_MONTH 5
-#define SGS_RTC_MONTH    6
-#define SGS_RTC_YEAR     7
-
-#define SGS_RTC_SET  0x80
-#define SGS_RTC_IS_STOPPED 0x80
-
-#define GRACKLE_CONFIG_ADDR_ADDR  (0xfec00000)
-#define GRACKLE_CONFIG_DATA_ADDR  (0xfee00000)
-
-#define GEMINI_BOOT_INIT  (0xfff00100)
-
-#ifndef __ASSEMBLY__
-
-static inline void grackle_write( unsigned long addr, unsigned long data )
-{
-  __asm__ __volatile__(
-  " stwbrx %1, 0, %0\n \
-    sync\n \
-    stwbrx %3, 0, %2\n \
-    sync "
-  : /* no output */
-  : "r" (GRACKLE_CONFIG_ADDR_ADDR), "r" (addr),
-    "r" (GRACKLE_CONFIG_DATA_ADDR), "r" (data));
-}
-
-static inline unsigned long grackle_read( unsigned long addr )
-{
-  unsigned long val;
-
-  __asm__ __volatile__(
-  " stwbrx %1, 0, %2\n \
-    sync\n \
-    lwbrx %0, 0, %3\n \
-    sync "
-  : "=r" (val)
-  : "r" (addr), "r" (GRACKLE_CONFIG_ADDR_ADDR),
-    "r" (GRACKLE_CONFIG_DATA_ADDR));
-
-  return val;
-}
-
-static inline void gemini_led_on( int led )
-{
-  if (led >= 0 && led < GEMINI_LEDS)
-    *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 1;
-}
-
-static inline void gemini_led_off(int led)
-{
-  if (led >= 0 && led < GEMINI_LEDS)
-    *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 0;
-}
-
-static inline int gemini_led_val(int led)
-{
-  int val = 0;
-  if (led >= 0 && led < GEMINI_LEDS)
-    val = *(unsigned char *)(GEMINI_LEDBASE + (led<<3));
-  return (val & 0x1);
-}
-
-/* returns processor id from the board */
-static inline int gemini_processor(void)
-{
-  unsigned char cpu = *(unsigned char *)(GEMINI_CPUSTAT);
-  return (int) ((cpu == 0) ? 4 : (cpu & GEMINI_CPU_ID_MASK));
-}
-
-
-extern void _gemini_reboot(void);
-extern void gemini_prom_init(void);
-extern void gemini_init_l2(void);
-#endif /* __ASSEMBLY__ */
-#endif
-#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/gemini_serial.h linux-2.4.20/include/asm-ppc/gemini_serial.h
--- linux-2.4.19/include/asm-ppc/gemini_serial.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/gemini_serial.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,44 +0,0 @@
-/*
- * BK Id: SCCS/s.gemini_serial.h 1.5 05/17/01 18:14:24 cort
- */
-#ifdef __KERNEL__
-#ifndef __ASMPPC_GEMINI_SERIAL_H
-#define __ASMPPC_GEMINI_SERIAL_H
-
-#include <linux/config.h>
-#include <asm/gemini.h>
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define RS_TABLE_SIZE  64
-#else
-#define RS_TABLE_SIZE  4
-#endif
-
-/* Rate for the 24.576 Mhz clock for the onboard serial chip */
-#define BASE_BAUD  (24576000 / 16)
-
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF)
-#endif
-
-#define STD_SERIAL_PORT_DEFNS \
-        { 0, BASE_BAUD, GEMINI_SERIAL_A, 15, STD_COM_FLAGS }, /* ttyS0 */ \
-        { 0, BASE_BAUD, GEMINI_SERIAL_B, 14, STD_COM_FLAGS }, /* ttyS1 */ \
-
-#ifdef CONFIG_GEMINI_PU32
-#define PU32_SERIAL_PORT_DEFNS \
-        { 0, BASE_BAUD, NULL, 0, STD_COM_FLAGS },
-#else
-#define PU32_SERIAL_PORT_DEFNS
-#endif
-
-#define SERIAL_PORT_DFNS \
-        STD_SERIAL_PORT_DEFNS \
-        PU32_SERIAL_PORT_DEFNS
-
-#endif
-#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/gg2.h linux-2.4.20/include/asm-ppc/gg2.h
--- linux-2.4.19/include/asm-ppc/gg2.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/gg2.h	2002-10-29 11:18:33.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.gg2.h 1.5 05/17/01 18:14:24 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  asm-ppc/gg2.h -- VLSI VAS96011/12 `Golden Gate 2' register definitions
@@ -37,6 +37,8 @@
      *  GG2 specific PCI Registers
      */
 
+extern unsigned long gg2_pci_config_base;	/* kernel virtual address */
+
 #define GG2_PCI_BUSNO		0x40	/* Bus number */
 #define GG2_PCI_SUBBUSNO	0x41	/* Subordinate bus number */
 #define GG2_PCI_DISCCTR		0x42	/* Disconnect counter */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/hardirq.h linux-2.4.20/include/asm-ppc/hardirq.h
--- linux-2.4.19/include/asm-ppc/hardirq.h	2001-07-18 14:14:01.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/hardirq.h	2002-10-29 11:18:31.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.hardirq.h 1.12 07/10/01 11:26:58 trini
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #ifdef __KERNEL__
 #ifndef __ASM_HARDIRQ_H
@@ -21,11 +21,15 @@
 	unsigned int __syscall_count;
 	struct task_struct * __ksoftirqd_task;
 	unsigned int __last_jiffy_stamp;
+	unsigned int __heartbeat_count;
+	unsigned int __heartbeat_reset;
 } ____cacheline_aligned irq_cpustat_t;
 
 #include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
 
 #define last_jiffy_stamp(cpu) __IRQ_STAT((cpu), __last_jiffy_stamp)
+#define heartbeat_count(cpu) __IRQ_STAT((cpu), __heartbeat_count)
+#define heartbeat_reset(cpu) __IRQ_STAT((cpu), __heartbeat_reset)
 /*
  * Are we in an interrupt context? Either doing bottom half
  * or hardware interrupt processing?
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/hw_irq.h linux-2.4.20/include/asm-ppc/hw_irq.h
--- linux-2.4.19/include/asm-ppc/hw_irq.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/hw_irq.h	2002-10-29 11:18:49.000000000 +0000
@@ -10,7 +10,8 @@
 
 extern unsigned long timer_interrupt_intercept;
 extern unsigned long do_IRQ_intercept;
-int timer_interrupt(struct pt_regs *);
+extern int timer_interrupt(struct pt_regs *);
+extern void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
 
 extern void __sti(void);
 extern void __cli(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/i8259.h linux-2.4.20/include/asm-ppc/i8259.h
--- linux-2.4.19/include/asm-ppc/i8259.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/i8259.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,16 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+
+#ifndef _PPC_KERNEL_i8259_H
+#define _PPC_KERNEL_i8259_H
+
+#include <linux/irq.h>
+
+extern struct hw_interrupt_type i8259_pic;
+
+void i8259_init(unsigned long int_ack);
+int i8259_irq(struct pt_regs *regs);
+int i8259_poll(struct pt_regs *regs);
+
+#endif /* _PPC_KERNEL_i8259_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/irq.h linux-2.4.20/include/asm-ppc/irq.h
--- linux-2.4.19/include/asm-ppc/irq.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/irq.h	2002-10-29 11:18:33.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.irq.h 1.9 05/17/01 18:14:24 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #ifdef __KERNEL__
 #ifndef _ASM_IRQ_H
@@ -124,48 +124,6 @@
 }
 
 #else /* CONFIG_4xx + CONFIG_8xx */
-
-#if defined(CONFIG_APUS)
-/*
- * This structure is used to chain together the ISRs for a particular
- * interrupt source (if it supports chaining).
- */
-typedef struct irq_node {
-	void		(*handler)(int, void *, struct pt_regs *);
-	unsigned long	flags;
-	void		*dev_id;
-	const char	*devname;
-	struct irq_node *next;
-} irq_node_t;
-
-/*
- * This structure has only 4 elements for speed reasons
- */
-typedef struct irq_handler {
-	void		(*handler)(int, void *, struct pt_regs *);
-	unsigned long	flags;
-	void		*dev_id;
-	const char	*devname;
-} irq_handler_t;
-
-/* count of spurious interrupts */
-extern volatile unsigned int num_spurious;
-
-extern int sys_request_irq(unsigned int, 
-	void (*)(int, void *, struct pt_regs *), 
-	unsigned long, const char *, void *);
-extern void sys_free_irq(unsigned int, void *);
-
-/*
- * This function returns a new irq_node_t
- */
-extern irq_node_t *new_irq_node(void);
-
-/* Number of m68k interrupts */
-#define SYS_IRQS 8
-
-#endif /* CONFIG_APUS */
-
 /*
  * this is the # irq's for all ppc arch's (pmac/chrp/prep)
  * so it is the max of them all
@@ -211,19 +169,14 @@
 static __inline__ int irq_cannonicalize(int irq)
 {
 	if (ppc_md.irq_cannonicalize)
-	{
 		return ppc_md.irq_cannonicalize(irq);
-	}
-	else
-	{
-		return irq;
-	}
+	return irq;
 }
 
 #endif
 
 #define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
-/* pendatic: these are long because they are used with set_bit --RR */
+/* pedantic: these are long because they are used with set_bit --RR */
 extern unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
 extern unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
 extern atomic_t ppc_n_lost_interrupts;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/ivms8.h linux-2.4.20/include/asm-ppc/ivms8.h
--- linux-2.4.19/include/asm-ppc/ivms8.h	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/ivms8.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,59 +0,0 @@
-/*
- * BK Id: SCCS/s.ivms8.h 1.8 10/26/01 10:14:09 trini
- */
-/*
- * Speech Design Integrated Voicemail board specific definitions
- * - IVMS8  (small,  8 channels)
- * - IVML24 (large, 24 channels)
- *
- * In 2.5 when we force a new bootloader, we can merge these two, and add
- * in _MACH_'s for them. -- Tom
- *
- * Copyright (c) 2000, 2001 Wolfgang Denk (wd@denx.de)
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_IVMS8_H__
-#define __ASM_IVMS8_H__
-
-#include <linux/config.h>
-
-#include <asm/ppcboot.h>
-
-#define IVMS_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR */
-#define IVMS_IMAP_SIZE	(64 * 1024)	/* size of mapped area */
-
-#define IMAP_ADDR	IVMS_IMMR_BASE	/* phys. base address of IMMR area */
-#define IMAP_SIZE	IVMS_IMAP_SIZE	/* mapped size of IMMR area */
-
-#define PCMCIA_MEM_ADDR	((uint)0xFE100000)
-#define PCMCIA_MEM_SIZE	((uint)(64 * 1024))
-
-#define FEC_INTERRUPT	 9		/* = SIU_LEVEL4 */
-#define IDE0_INTERRUPT	10		/* = IRQ5 */
-#define CPM_INTERRUPT	11		/* = SIU_LEVEL5 (was: SIU_LEVEL2) */
-#define PHY_INTERRUPT	12		/* = IRQ6 */
-
-/* override the default number of IDE hardware interfaces */
-#define MAX_HWIFS	1
-
-/*
- * Definitions for IDE0 Interface
- */
-#define IDE0_BASE_OFFSET		0x0000	/* Offset in PCMCIA memory */
-#define IDE0_DATA_REG_OFFSET		0x0000
-#define IDE0_ERROR_REG_OFFSET		0x0081
-#define IDE0_NSECTOR_REG_OFFSET		0x0082
-#define IDE0_SECTOR_REG_OFFSET		0x0083
-#define IDE0_LCYL_REG_OFFSET		0x0084
-#define IDE0_HCYL_REG_OFFSET		0x0085
-#define IDE0_SELECT_REG_OFFSET		0x0086
-#define IDE0_STATUS_REG_OFFSET		0x0087
-#define IDE0_CONTROL_REG_OFFSET		0x0106
-#define IDE0_IRQ_REG_OFFSET		0x000A	/* not used */
-
-/* We don't use the 8259. */
-#define NR_8259_INTS	0
-
-#endif /* __ASM_IVMS8_H__ */
-#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/keyboard.h linux-2.4.20/include/asm-ppc/keyboard.h
--- linux-2.4.19/include/asm-ppc/keyboard.h	2001-08-30 03:49:36.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/keyboard.h	2002-10-29 11:18:49.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.keyboard.h 1.11 08/29/01 10:07:29 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  linux/include/asm-ppc/keyboard.h
@@ -25,8 +25,14 @@
 #include <linux/ioport.h>
 #include <linux/kd.h>
 #include <asm/io.h>
+/* IBM Spruce platform is different. */
+#ifdef CONFIG_SPRUCE
+#include <platforms/spruce.h>
+#endif
 
+#ifndef KEYBOARD_IRQ
 #define KEYBOARD_IRQ			1
+#endif
 #define DISABLE_KBD_DURING_INTERRUPTS	0
 #define INIT_KBD
 
@@ -85,10 +91,12 @@
                                              "keyboard", NULL)
 
 /* How to access the keyboard macros on this platform.  */
+#ifndef kbd_read_input
 #define kbd_read_input() inb(KBD_DATA_REG)
 #define kbd_read_status() inb(KBD_STATUS_REG)
 #define kbd_write_output(val) outb(val, KBD_DATA_REG)
 #define kbd_write_command(val) outb(val, KBD_CNTL_REG)
+#endif
 
 /* Some stoneage hardware needs delays after some operations.  */
 #define kbd_pause() do { } while(0)
@@ -96,8 +104,9 @@
 /*
  * Machine specific bits for the PS/2 driver
  */
-
+#ifndef AUX_IRQ	
 #define AUX_IRQ 12
+#endif
 
 #define aux_request_irq(hand, dev_id)					\
 	request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
@@ -105,5 +114,4 @@
 #define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
 
 #endif /* __KERNEL__ */
-
 #endif /* __ASMPPC_KEYBOARD_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/kmap_types.h linux-2.4.20/include/asm-ppc/kmap_types.h
--- linux-2.4.19/include/asm-ppc/kmap_types.h	2001-09-17 20:16:30.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/kmap_types.h	2002-10-29 11:18:34.000000000 +0000
@@ -7,10 +7,11 @@
 
 enum km_type {
 	KM_BOUNCE_READ,
-	KM_SKB_DATA,
+	KM_SKB_SUNRPC_DATA,
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
+	KM_BH_IRQ,
 	KM_TYPE_NR
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/machdep.h linux-2.4.20/include/asm-ppc/machdep.h
--- linux-2.4.19/include/asm-ppc/machdep.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/machdep.h	2002-10-29 11:18:35.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.machdep.h 1.31 03/19/02 14:19:28 benh
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #ifdef __KERNEL__
 #ifndef _PPC_MACHDEP_H
@@ -43,10 +43,7 @@
 	int		(*set_rtc_time)(unsigned long nowtime);
 	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 -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/mbx.h linux-2.4.20/include/asm-ppc/mbx.h
--- linux-2.4.19/include/asm-ppc/mbx.h	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/mbx.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,98 +0,0 @@
-/*
- * BK Id: SCCS/s.mbx.h 1.11 08/17/01 15:23:17 paulus
- */
-/*
- * A collection of structures, addresses, and values associated with
- * the Motorola MBX boards.  This was originally created for the
- * MBX860, and probably needs revisions for other boards (like the 821).
- * When this file gets out of control, we can split it up into more
- * meaningful pieces.
- *
- * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
- */
-#ifdef __KERNEL__
-#ifndef __MACH_MBX_DEFS
-#define __MACH_MBX_DEFS
-
-#ifndef __ASSEMBLY__
-/* A Board Information structure that is given to a program when
- * EPPC-Bug starts it up.
- */
-typedef struct bd_info {
-	unsigned int	bi_tag;		/* Should be 0x42444944 "BDID" */
-	unsigned int	bi_size;	/* Size of this structure */
-	unsigned int	bi_revision;	/* revision of this structure */
-	unsigned int	bi_bdate;	/* EPPCbug date, i.e. 0x11061997 */
-	unsigned int	bi_memstart;	/* Memory start address */
-	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
-	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
-	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
-	unsigned int	bi_clun;	/* Boot device controller */
-	unsigned int	bi_dlun;	/* Boot device logical dev */
-
-	/* These fields are not part of the board information structure
-	 * provided by the boot rom.  They are filled in by embed_config.c
-	 * so we have the information consistent with other platforms.
-	 */
-	unsigned char	bi_enetaddr[6];
-	unsigned int	bi_baudrate;
-} bd_t;
-
-/* Memory map for the MBX as configured by EPPC-Bug.  We could reprogram
- * The SIU and PCI bridge, and try to use larger MMU pages, but the
- * performance gain is not measureable and it certainly complicates the
- * generic MMU model.
- *
- * In a effort to minimize memory usage for embedded applications, any
- * PCI driver or ISA driver must request or map the region required by
- * the device.  For convenience (and since we can map up to 4 Mbytes with
- * a single page table page), the MMU initialization will map the
- * NVRAM, Status/Control registers, CPM Dual Port RAM, and the PCI
- * Bridge CSRs 1:1 into the kernel address space.
- */
-#define PCI_ISA_IO_ADDR		((unsigned)0x80000000)
-#define PCI_ISA_IO_SIZE		((uint)(512 * 1024 * 1024))
-#define PCI_IDE_ADDR		((unsigned)0x81000000)
-#define PCI_ISA_MEM_ADDR	((unsigned)0xc0000000)
-#define PCI_ISA_MEM_SIZE	((uint)(512 * 1024 * 1024))
-#define PCMCIA_MEM_ADDR		((uint)0xe0000000)
-#define PCMCIA_MEM_SIZE		((uint)(64 * 1024 * 1024))
-#define PCMCIA_DMA_ADDR		((uint)0xe4000000)
-#define PCMCIA_DMA_SIZE		((uint)(64 * 1024 * 1024))
-#define PCMCIA_ATTRB_ADDR	((uint)0xe8000000)
-#define PCMCIA_ATTRB_SIZE	((uint)(64 * 1024 * 1024))
-#define PCMCIA_IO_ADDR		((uint)0xec000000)
-#define PCMCIA_IO_SIZE		((uint)(64 * 1024 * 1024))
-#define NVRAM_ADDR		((uint)0xfa000000)
-#define NVRAM_SIZE		((uint)(1 * 1024 * 1024))
-#define MBX_CSR_ADDR		((uint)0xfa100000)
-#define MBX_CSR_SIZE		((uint)(1 * 1024 * 1024))
-#define IMAP_ADDR		((uint)0xfa200000)
-#define IMAP_SIZE		((uint)(64 * 1024))
-#define PCI_CSR_ADDR		((uint)0xfa210000)
-#define PCI_CSR_SIZE		((uint)(64 * 1024))
-
-/* Map additional physical space into well known virtual addresses.  Due
- * to virtual address mapping, these physical addresses are not accessible
- * in a 1:1 virtual to physical mapping.
- */
-#define ISA_IO_VIRT_ADDR	((uint)0xfa220000)
-#define ISA_IO_VIRT_SIZE	((uint)64 * 1024)
-
-/* Interrupt assignments.
- * These are defined (and fixed) by the MBX hardware implementation.
- */
-#define POWER_FAIL_INT	SIU_IRQ0	/* Power fail */
-#define TEMP_HILO_INT	SIU_IRQ1	/* Temperature sensor */
-#define QSPAN_INT	SIU_IRQ2	/* PCI Bridge (DMA CTLR?) */
-#define ISA_BRIDGE_INT	SIU_IRQ3	/* All those PC things */
-#define COMM_L_INT	SIU_IRQ6	/* MBX Comm expansion connector pin */
-#define STOP_ABRT_INT	SIU_IRQ7	/* Stop/Abort header pin */
-#endif /* !__ASSEMBLY__ */
-
-/* The MBX uses the 8259.
-*/
-#define NR_8259_INTS	16
-
-#endif
-#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/mpc8260.h linux-2.4.20/include/asm-ppc/mpc8260.h
--- linux-2.4.19/include/asm-ppc/mpc8260.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/mpc8260.h	2002-10-29 11:18:31.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.mpc8260.h 1.5 05/17/01 18:14:25 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 
 /* This is the single file included by all MPC8260 build options.
@@ -17,7 +17,7 @@
 #ifdef CONFIG_8260
 
 #ifdef CONFIG_EST8260
-#include <asm/est8260.h>
+#include <platforms/est8260.h>
 #endif
 
 /* I don't yet have the ISA or PCI stuff done....no 8260 with
@@ -43,5 +43,5 @@
 		       void *dev_id);
 
 #endif /* CONFIG_8260 */
-#endif
+#endif /* !__CONFIG_8260_DEFS */
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/mpc8xx.h linux-2.4.20/include/asm-ppc/mpc8xx.h
--- linux-2.4.19/include/asm-ppc/mpc8xx.h	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/mpc8xx.h	2002-10-29 11:18:49.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.mpc8xx.h 1.15 11/01/01 12:48:53 trini
+ * BK Id: %F% %I% %G% %U% %#%
  */
 
 /* This is the single file included by all MPC8xx build options.
@@ -17,40 +17,37 @@
 #ifdef CONFIG_8xx
 
 #ifdef CONFIG_MBX
-#include <asm/mbx.h>
+#include <platforms/mbx.h>
 #endif
 
 #ifdef CONFIG_FADS
-#include <asm/fads.h>
+#include <platforms/fads.h>
 #endif
 
 #ifdef CONFIG_RPXLITE
-#include <asm/rpxlite.h>
+#include <platforms/rpxlite.h>
 #endif
 
 #ifdef CONFIG_BSEIP
-#include <asm/bseip.h>
+#include <platforms/bseip.h>
 #endif
 
 #ifdef CONFIG_RPXCLASSIC
-#include <asm/rpxclassic.h>
+#include <platforms/rpxclassic.h>
 #endif
 
 #if defined(CONFIG_TQM8xxL)
-#include <asm/tqm8xx.h>
+#include <platforms/tqm8xx.h>
 #endif
 
 #if defined(CONFIG_SPD823TS)
-#include <asm/spd8xx.h>
+#include <platforms/spd8xx.h>
 #endif
 
 #if defined(CONFIG_IVMS8) || defined(CONFIG_IVML24)
-#include <asm/ivms8.h>
+#include <platforms/ivms8.h>
 #endif
 
-/* I need this to get pt_regs.......
-*/
-#include <asm/ptrace.h>
 
 /* Currently, all 8xx boards that support a processor to PCI/ISA bridge
  * use the same memory map.
@@ -83,6 +80,7 @@
  */
 extern unsigned char __res[];
 
+struct pt_regs;
 extern int request_8xxirq(unsigned int irq,
 		       void (*handler)(int, void *, struct pt_regs *),
 		       unsigned long flags, 
@@ -90,5 +88,5 @@
 		       void *dev_id);
 #endif /* !__ASSEMBLY__ */
 #endif /* CONFIG_8xx */
-#endif
+#endif /* __CONFIG_8xx_DEFS */
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/oak.h linux-2.4.20/include/asm-ppc/oak.h
--- linux-2.4.19/include/asm-ppc/oak.h	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/oak.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,65 +0,0 @@
-/*
- * BK Id: SCCS/s.oak.h 1.12 10/11/01 13:05:07 trini
- */
-/*
- *
- *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: oak.h
- *
- *    Description:
- *	Macros, definitions, and data structures specific to the IBM PowerPC
- *      403G{A,B,C,CX} "Oak" evaluation board. Anything specific to the pro-
- *      cessor itself is defined elsewhere.
- *
- */
-
-#ifdef __KERNEL__
-#ifndef	__OAK_H__
-#define	__OAK_H__
-
-#define _IO_BASE	0
-#define _ISA_MEM_BASE	0
-#define PCI_DRAM_OFFSET	0
-
-/* Memory map for the "Oak" evaluation board */
-
-#define	PPC403SPU_IO_BASE      	0x40000000	/* 403 On-chip serial port */
-#define	PPC403SPU_IO_SIZE      	0x00000008
-#define	OAKSERIAL_IO_BASE	0x7E000000	/* NS16550DV serial port */
-#define	OAKSERIAL_IO_SIZE	0x00000008
-#define	OAKNET_IO_BASE		0xF4000000	/* NS83902AV Ethernet */
-#define	OAKNET_IO_SIZE		0x00000040
-#define	OAKPROM_IO_BASE		0xFFFE0000	/* AMD 29F010 Flash ROM */
-#define	OAKPROM_IO_SIZE		0x00020000
-
-
-/* Interrupt assignments fixed by the hardware implementation */
-
-/* This is annoying kbuild-2.4 problem. -- Tom */
-
-#define	PPC403SPU_RX_INT	4	/* AIC_INT4 */
-#define	PPC403SPU_TX_INT	5	/* AIC_INT5 */
-#define	OAKNET_INT		27	/* AIC_INT27 */
-#define	OAKSERIAL_INT		28	/* AIC_INT28 */
-
-#ifndef __ASSEMBLY__
-/*
- * Data structure defining board information maintained by the boot
- * ROM on IBM's "Oak" evaluation board. An effort has been made to
- * keep the field names consistent with the 8xx 'bd_t' board info
- * structures.
- */
-
-typedef struct board_info {
-	unsigned char	 bi_s_version[4];	/* Version of this structure */
-	unsigned char	 bi_r_version[30];	/* Version of the IBM ROM */
-	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
-	unsigned char	 bi_enetaddr[6];	/* Ethernet MAC address */
-	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
-	unsigned int	 bi_busfreq;		/* Bus speed, in Hz */
-} bd_t;
-
-#endif /* !__ASSEMBLY__ */
-#endif /* __OAK_H__ */
-#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/open_pic.h linux-2.4.20/include/asm-ppc/open_pic.h
--- linux-2.4.19/include/asm-ppc/open_pic.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/open_pic.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,70 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/kernel/open_pic.h -- OpenPIC Interrupt Handling
+ *
+ *  Copyright (C) 1997 Geert Uytterhoeven
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive
+ *  for more details.
+ *  
+ */
+
+#ifndef _PPC_KERNEL_OPEN_PIC_H
+#define _PPC_KERNEL_OPEN_PIC_H
+
+#include <linux/config.h>
+#include <linux/irq.h>
+
+#define OPENPIC_SIZE	0x40000
+
+/*
+ *  Non-offset'ed vector numbers
+ */
+
+#define OPENPIC_VEC_TIMER	64	/* and up */
+#define OPENPIC_VEC_IPI		72	/* and up */
+#define OPENPIC_VEC_SPURIOUS	127
+
+/* OpenPIC IRQ controller structure */
+extern struct hw_interrupt_type open_pic;
+
+/* OpenPIC IPI controller structure */
+#ifdef CONFIG_SMP
+extern struct hw_interrupt_type open_pic_ipi;
+#endif /* CONFIG_SMP */
+
+extern u_int OpenPIC_NumInitSenses;
+extern u_char *OpenPIC_InitSenses;
+extern void* OpenPIC_Addr;
+
+/* Exported functions */
+extern void openpic_set_sources(int first_irq, int num_irqs, void *isr);
+extern void openpic_init(int, int, unsigned char *, int);
+extern u_int openpic_irq(void);
+extern void openpic_eoi(void);
+extern void openpic_request_IPIs(void);
+extern void do_openpic_setup_cpu(void);
+extern int openpic_get_irq(struct pt_regs *regs);
+extern void openpic_reset_processor_phys(u_int cpumask);
+extern void openpic_setup_ISU(int isu_num, unsigned long addr);
+extern void openpic_cause_IPI(u_int ipi, u_int cpumask);
+extern void smp_openpic_message_pass(int target, int msg, unsigned long data,
+				     int wait);
+
+extern inline int openpic_to_irq(int irq)
+{
+	/* IRQ 0 usually means 'disabled'.. don't mess with it 
+	 * exceptions to this (sandpoint maybe?) 
+	 * shouldn't use openpic_to_irq 
+	 */
+	if (irq != 0){
+		return irq += NUM_8259_INTERRUPTS;
+	} else {
+		return 0;
+	}
+}
+/*extern int open_pic_irq_offset;*/
+#endif /* _PPC_KERNEL_OPEN_PIC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/pci-bridge.h linux-2.4.20/include/asm-ppc/pci-bridge.h
--- linux-2.4.19/include/asm-ppc/pci-bridge.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/pci-bridge.h	2002-10-29 11:18:32.000000000 +0000
@@ -1,10 +1,13 @@
 /*
- * BK Id: SCCS/s.pci-bridge.h 1.11 05/21/01 01:31:30 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #ifdef __KERNEL__
 #ifndef _ASM_PCI_BRIDGE_H
 #define _ASM_PCI_BRIDGE_H
 
+#include <linux/ioport.h>
+#include <linux/pci.h>
+
 struct device_node;
 struct pci_controller;
 
@@ -16,12 +19,20 @@
 extern unsigned long pci_bus_io_base_phys(unsigned int bus);
 extern unsigned long pci_bus_mem_base_phys(unsigned int bus);
 
+/* Allocate a new PCI host bridge structure */
+extern struct pci_controller* pcibios_alloc_controller(void);
+
+/* Helper function for setting up resources */
+extern void pci_init_resource(struct resource *res, unsigned long start,
+			      unsigned long end, int flags, char *name);
+
 /*
  * PCI <-> OF matching functions 
  */
 extern int pci_device_from_OF_node(struct device_node *node,
 				   u8* bus, u8* devfn);
 extern struct device_node* pci_device_to_OF_node(struct pci_dev *);
+extern void pci_create_OF_bus_map(void);
 
 /* Get the PCI host controller for a bus */
 extern struct pci_controller* pci_bus_to_hose(int bus);
@@ -65,6 +76,12 @@
 	struct resource	io_resource;
 	struct resource mem_resources[3];
 	int mem_resource_count;
+
+	/* Host bridge I/O and Memory space
+	 * Used for BAR placement algorithms
+	 */
+	struct resource io_space;
+	struct resource mem_space;
 };
 
 /* These are used for config access before all the PCI probing
@@ -76,5 +93,41 @@
 int early_write_config_word(struct pci_controller *hose, int bus, int dev_fn, int where, u16 val);
 int early_write_config_dword(struct pci_controller *hose, int bus, int dev_fn, int where, u32 val);
 
+extern void setup_indirect_pci(struct pci_controller* hose, u32 cfg_addr,
+		u32 cfg_data);
+extern void setup_grackle(struct pci_controller *hose);
+
+extern unsigned char common_swizzle(struct pci_dev *, unsigned char *);
+
+/*
+ *   The following code swizzles for exactly one bridge.  The routine
+ *   common_swizzle below handles multiple bridges.  But there are a
+ *   some boards that don't follow the PCI spec's suggestion so we
+ *   break this piece out separately.
+ */
+static inline unsigned char bridge_swizzle(unsigned char pin,
+		unsigned char idsel) 
+{
+	return (((pin-1) + idsel) % 4) + 1;
+}
+
+/*
+ * The following macro is used to lookup irqs in a standard table
+ * format for those PPC systems that do not already have PCI
+ * interrupts properly routed.
+ */
+/* FIXME - double check this */
+#define PCI_IRQ_TABLE_LOOKUP						    \
+({ long _ctl_ = -1; 							    \
+   if (idsel >= min_idsel && idsel <= max_idsel && pin <= irqs_per_slot)    \
+     _ctl_ = pci_irq_table[idsel - min_idsel][pin-1];			    \
+   _ctl_; })
+
+/*
+ * Scan the buses below a given PCI host bridge and assign suitable
+ * resources to all devices found.
+ */
+extern int pciauto_bus_scan(struct pci_controller *, int);
+
 #endif
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/pci.h linux-2.4.20/include/asm-ppc/pci.h
--- linux-2.4.19/include/asm-ppc/pci.h	2002-02-25 19:38:12.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/pci.h	2002-10-29 11:18:49.000000000 +0000
@@ -12,8 +12,13 @@
 #define IOBASE_ISA_IO		3
 #define IOBASE_ISA_MEM		4
 
+/*
+ * Set this to 1 if you want the kernel to re-assign all PCI
+ * bus numbers
+ */
+extern int pci_assign_all_busses;
 
-extern int pcibios_assign_all_busses(void);
+#define pcibios_assign_all_busses()	(pci_assign_all_busses)
 
 #define PCIBIOS_MIN_IO		0x1000
 #define PCIBIOS_MIN_MEM		0x10000000
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/pgtable.h linux-2.4.20/include/asm-ppc/pgtable.h
--- linux-2.4.19/include/asm-ppc/pgtable.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/pgtable.h	2002-10-29 11:18:34.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pgtable.h 1.21 03/12/02 11:49:48 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #ifdef __KERNEL__
 #ifndef _PPC_PGTABLE_H
@@ -529,10 +529,10 @@
 /* Values for nocacheflag and cmode */
 /* These are not used by the APUS kernel_map, but prevents
    compilation errors. */
-#define	KERNELMAP_FULL_CACHING		0
-#define	KERNELMAP_NOCACHE_SER		1
-#define	KERNELMAP_NOCACHE_NONSER	2
-#define	KERNELMAP_NO_COPYBACK		3
+#define	IOMAP_FULL_CACHING	0
+#define	IOMAP_NOCACHE_SER	1
+#define	IOMAP_NOCACHE_NONSER	2
+#define	IOMAP_NO_COPYBACK	3
 
 /*
  * Map some physical address range into the kernel address space.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/pmac_feature.h linux-2.4.20/include/asm-ppc/pmac_feature.h
--- linux-2.4.19/include/asm-ppc/pmac_feature.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/pmac_feature.h	2002-10-29 11:18:34.000000000 +0000
@@ -87,8 +87,13 @@
 #define PMAC_TYPE_TITANIUM		0x47	/* Titanium PowerBook */
 #define PMAC_TYPE_TITANIUM2		0x48	/* Titanium II PowerBook */
 #define PMAC_TYPE_TITANIUM3		0x49	/* Titanium III PowerBook (with L3) */
+#define PMAC_TYPE_EMAC			0x50	/* eMac */
 #define PMAC_TYPE_UNKNOWN_CORE99	0x5f
 
+/* MacRisc2 with UniNorth 2.0 */
+#define PMAC_TYPE_RACKMAC		0x80	/* XServe */
+#define PMAC_TYPE_WINDTUNNEL		0x81	
+
 /* MacRISC2 machines based on the Pangea chipset
  */
 #define PMAC_TYPE_PANGEA_IMAC		0x100	/* Flower Power iMac */
@@ -102,6 +107,7 @@
 
 #define PMAC_MB_CAN_SLEEP		0x00000001
 #define PMAC_MB_HAS_FW_POWER		0x00000002
+#define PMAC_MB_OLD_CORE99		0x00000004
 
 /*
  * Feature calls supported on pmac
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/ppc4xx.h linux-2.4.20/include/asm-ppc/ppc4xx.h
--- linux-2.4.19/include/asm-ppc/ppc4xx.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/ppc4xx.h	2002-10-29 11:18:48.000000000 +0000
@@ -22,22 +22,22 @@
 #ifndef __ASSEMBLY__
 
 #if defined(CONFIG_OAK)
-#include <asm/oak.h>
+#include <platforms/oak.h>
 #endif
 
 #if defined(CONFIG_WALNUT)
-#include <asm/walnut.h>
+#include <platforms/walnut.h>
 #endif
 
 /* IO_BASE is for PCI I/O.
  * ISA not supported, just here to resolve copilation.
  */
 
+#ifndef _IO_BASE
 #define _IO_BASE	0xe8000000	/* The PCI address window */
 #define _ISA_MEM_BASE	0
 #define PCI_DRAM_OFFSET	0
-
-extern unsigned long isa_io_base;
+#endif
 
 /*
  * The "residual" board information structure the boot loader passes
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/ppc4xx_pic.h linux-2.4.20/include/asm-ppc/ppc4xx_pic.h
--- linux-2.4.19/include/asm-ppc/ppc4xx_pic.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/ppc4xx_pic.h	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,29 @@
+/*
+ * BK Id: SCCS/s.ppc4xx_pic.h 1.8 06/15/01 13:56:56 paulus
+ */
+/*
+ *
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: ppc4xx_pic.h
+ *
+ *    Description:
+ *      Interrupt controller driver for PowerPC 4xx-based processors.
+ */
+
+#ifndef	__PPC4XX_PIC_H__
+#define	__PPC4XX_PIC_H__
+
+#include <linux/config.h>
+
+/* External Global Variables */
+
+extern struct hw_interrupt_type *ppc4xx_pic;
+
+
+/* Function Prototypes */
+
+extern void	 ppc4xx_pic_init(void);
+extern int	 ppc4xx_pic_get_irq(struct pt_regs *regs);
+
+#endif /* __PPC4XX_PIC_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/ppc_asm.h linux-2.4.20/include/asm-ppc/ppc_asm.h
--- linux-2.4.19/include/asm-ppc/ppc_asm.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/ppc_asm.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,280 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * include/asm-ppc/ppc_asm.h
+ *
+ * Definitions used by various bits of low-level assembly code on PowerPC.
+ *
+ * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan.
+ *
+ *  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.
+ */
+
+#include <linux/config.h>
+
+/*
+ * Macros for storing registers into and loading registers from
+ * exception frames.
+ */
+#define SAVE_GPR(n, base)	stw	n,GPR0+4*(n)(base)
+#define SAVE_2GPRS(n, base)	SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+#define SAVE_4GPRS(n, base)	SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+#define SAVE_8GPRS(n, base)	SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+#define SAVE_10GPRS(n, base)	SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+#define REST_GPR(n, base)	lwz	n,GPR0+4*(n)(base)
+#define REST_2GPRS(n, base)	REST_GPR(n, base); REST_GPR(n+1, base)
+#define REST_4GPRS(n, base)	REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+#define REST_8GPRS(n, base)	REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+#define REST_10GPRS(n, base)	REST_8GPRS(n, base); REST_2GPRS(n+8, base)
+
+#define SAVE_FPR(n, base)	stfd	n,THREAD_FPR0+8*(n)(base)
+#define SAVE_2FPRS(n, base)	SAVE_FPR(n, base); SAVE_FPR(n+1, base)
+#define SAVE_4FPRS(n, base)	SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
+#define SAVE_8FPRS(n, base)	SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base)
+#define SAVE_16FPRS(n, base)	SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base)
+#define SAVE_32FPRS(n, base)	SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base)
+#define REST_FPR(n, base)	lfd	n,THREAD_FPR0+8*(n)(base)
+#define REST_2FPRS(n, base)	REST_FPR(n, base); REST_FPR(n+1, base)
+#define REST_4FPRS(n, base)	REST_2FPRS(n, base); REST_2FPRS(n+2, base)
+#define REST_8FPRS(n, base)	REST_4FPRS(n, base); REST_4FPRS(n+4, base)
+#define REST_16FPRS(n, base)	REST_8FPRS(n, base); REST_8FPRS(n+8, base)
+#define REST_32FPRS(n, base)	REST_16FPRS(n, base); REST_16FPRS(n+16, base)
+
+/*
+ * Once a version of gas that understands the AltiVec instructions
+ * is freely available, we can do this the normal way...  - paulus
+ */
+#define LVX(r,a,b)	.long	(31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(103<<1)
+#define STVX(r,a,b)	.long	(31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(231<<1)
+#define MFVSCR(r)	.long	(4<<26)+((r)<<21)+(770<<1)
+#define MTVSCR(r)	.long	(4<<26)+((r)<<11)+(802<<1)
+#define DSSALL		.long	(0x1f<<26)+(0x10<<21)+(0x336<<1)
+
+#define SAVE_VR(n,b,base)	li b,THREAD_VR0+(16*(n)); STVX(n,b,base)
+#define SAVE_2VR(n,b,base)	SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) 
+#define SAVE_4VR(n,b,base)	SAVE_2VR(n,b,base); SAVE_2VR(n+2,b,base) 
+#define SAVE_8VR(n,b,base)	SAVE_4VR(n,b,base); SAVE_4VR(n+4,b,base) 
+#define SAVE_16VR(n,b,base)	SAVE_8VR(n,b,base); SAVE_8VR(n+8,b,base)
+#define SAVE_32VR(n,b,base)	SAVE_16VR(n,b,base); SAVE_16VR(n+16,b,base)
+#define REST_VR(n,b,base)	li b,THREAD_VR0+(16*(n)); LVX(n,b,base)
+#define REST_2VR(n,b,base)	REST_VR(n,b,base); REST_VR(n+1,b,base) 
+#define REST_4VR(n,b,base)	REST_2VR(n,b,base); REST_2VR(n+2,b,base) 
+#define REST_8VR(n,b,base)	REST_4VR(n,b,base); REST_4VR(n+4,b,base) 
+#define REST_16VR(n,b,base)	REST_8VR(n,b,base); REST_8VR(n+8,b,base) 
+#define REST_32VR(n,b,base)	REST_16VR(n,b,base); REST_16VR(n+16,b,base)
+
+#ifdef CONFIG_PPC601_SYNC_FIX
+#define SYNC				\
+BEGIN_FTR_SECTION			\
+	sync;				\
+	isync;				\
+END_FTR_SECTION_IFSET(CPU_FTR_601)
+#define SYNC_601			\
+BEGIN_FTR_SECTION			\
+	sync;				\
+END_FTR_SECTION_IFSET(CPU_FTR_601)
+#define ISYNC_601			\
+BEGIN_FTR_SECTION			\
+	isync;				\
+END_FTR_SECTION_IFSET(CPU_FTR_601)
+#else
+#define	SYNC
+#define SYNC_601
+#define ISYNC_601
+#endif
+
+#ifndef CONFIG_SMP
+#define TLBSYNC
+#else /* CONFIG_SMP */
+/* tlbsync is not implemented on 601 */
+#define TLBSYNC				\
+BEGIN_FTR_SECTION			\
+	tlbsync;			\
+	sync;				\
+END_FTR_SECTION_IFCLR(CPU_FTR_601)
+#endif
+
+/*
+ * This instruction is not implemented on the PPC 603 or 601; however, on
+ * the 403GCX and 405GP tlbia IS defined and tlbie is not.
+ * All of these instructions exist in the 8xx, they have magical powers,
+ * and they must be used.
+ */
+
+#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
+#define tlbia					\
+	li	r4,1024;			\
+	mtctr	r4;				\
+	lis	r4,KERNELBASE@h;		\
+0:	tlbie	r4;				\
+	addi	r4,r4,0x1000;			\
+	bdnz	0b
+#endif
+
+/*
+ * On APUS (Amiga PowerPC cpu upgrade board), we don't know the
+ * physical base address of RAM at compile time.
+ */
+#define tophys(rd,rs)				\
+0:	addis	rd,rs,-KERNELBASE@h;		\
+	.section ".vtop_fixup","aw";		\
+	.align  1;				\
+	.long   0b;				\
+	.previous
+
+#define tovirt(rd,rs)				\
+0:	addis	rd,rs,KERNELBASE@h;		\
+	.section ".ptov_fixup","aw";		\
+	.align  1;				\
+	.long   0b;				\
+	.previous
+
+/*
+ * On 64-bit cpus, we use the rfid instruction instead of rfi, but
+ * we then have to make sure we preserve the top 32 bits except for
+ * the 64-bit mode bit, which we clear.
+ */
+#ifdef CONFIG_PPC64BRIDGE
+#define	FIX_SRR1(ra, rb)	\
+	mr	rb,ra;		\
+	mfmsr	ra;		\
+	clrldi	ra,ra,1;		/* turn off 64-bit mode */ \
+	rldimi	ra,rb,0,32
+#define	RFI		.long	0x4c000024	/* rfid instruction */
+#define MTMSRD(r)	.long	(0x7c000164 + ((r) << 21))	/* mtmsrd */
+#define CLR_TOP32(r)	rlwinm	(r),(r),0,0,31	/* clear top 32 bits */
+
+#else
+#define FIX_SRR1(ra, rb)
+#define	RFI		rfi
+#define MTMSRD(r)	mtmsr	r
+#define CLR_TOP32(r)
+#endif /* CONFIG_PPC64BRIDGE */
+
+/* The boring bits... */
+
+/* Condition Register Bit Fields */
+
+#define	cr0	0
+#define	cr1	1
+#define	cr2	2
+#define	cr3	3
+#define	cr4	4
+#define	cr5	5
+#define	cr6	6
+#define	cr7	7
+
+
+/* General Purpose Registers (GPRs) */
+
+#define	r0	0
+#define	r1	1
+#define	r2	2
+#define	r3	3
+#define	r4	4
+#define	r5	5
+#define	r6	6
+#define	r7	7
+#define	r8	8
+#define	r9	9
+#define	r10	10
+#define	r11	11
+#define	r12	12
+#define	r13	13
+#define	r14	14
+#define	r15	15
+#define	r16	16
+#define	r17	17
+#define	r18	18
+#define	r19	19
+#define	r20	20
+#define	r21	21
+#define	r22	22
+#define	r23	23
+#define	r24	24
+#define	r25	25
+#define	r26	26
+#define	r27	27
+#define	r28	28
+#define	r29	29
+#define	r30	30
+#define	r31	31
+
+
+/* Floating Point Registers (FPRs) */
+
+#define	fr0	0
+#define	fr1	1
+#define	fr2	2
+#define	fr3	3
+#define	fr4	4
+#define	fr5	5
+#define	fr6	6
+#define	fr7	7
+#define	fr8	8
+#define	fr9	9
+#define	fr10	10
+#define	fr11	11
+#define	fr12	12
+#define	fr13	13
+#define	fr14	14
+#define	fr15	15
+#define	fr16	16
+#define	fr17	17
+#define	fr18	18
+#define	fr19	19
+#define	fr20	20
+#define	fr21	21
+#define	fr22	22
+#define	fr23	23
+#define	fr24	24
+#define	fr25	25
+#define	fr26	26
+#define	fr27	27
+#define	fr28	28
+#define	fr29	29
+#define	fr30	30
+#define	fr31	31
+
+#define	vr0	0
+#define	vr1	1
+#define	vr2	2
+#define	vr3	3
+#define	vr4	4
+#define	vr5	5
+#define	vr6	6
+#define	vr7	7
+#define	vr8	8
+#define	vr9	9
+#define	vr10	10
+#define	vr11	11
+#define	vr12	12
+#define	vr13	13
+#define	vr14	14
+#define	vr15	15
+#define	vr16	16
+#define	vr17	17
+#define	vr18	18
+#define	vr19	19
+#define	vr20	20
+#define	vr21	21
+#define	vr22	22
+#define	vr23	23
+#define	vr24	24
+#define	vr25	25
+#define	vr26	26
+#define	vr27	27
+#define	vr28	28
+#define	vr29	29
+#define	vr30	30
+#define	vr31	31
+
+/* some stab codes */
+#define N_FUN	36
+#define N_RSYM	64
+#define N_SLINE	68
+#define N_SO	100
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/processor.h linux-2.4.20/include/asm-ppc/processor.h
--- linux-2.4.19/include/asm-ppc/processor.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/processor.h	2002-10-29 11:18:31.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.processor.h 1.37 05/06/02 01:37:30 benh
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #ifdef __KERNEL__
 #ifndef __ASM_PPC_PROCESSOR_H
@@ -102,6 +102,15 @@
 #define	SPRN_DBAT2U	0x21C	/* Data BAT 2 Upper Register */
 #define	SPRN_DBAT3L	0x21F	/* Data BAT 3 Lower Register */
 #define	SPRN_DBAT3U	0x21E	/* Data BAT 3 Upper Register */
+#define	SPRN_DBAT4L	0x239	/* Data BAT 4 Lower Register */
+#define	SPRN_DBAT4U	0x238	/* Data BAT 4 Upper Register */
+#define	SPRN_DBAT5L	0x23B	/* Data BAT 5 Lower Register */
+#define	SPRN_DBAT5U	0x23A	/* Data BAT 5 Upper Register */
+#define	SPRN_DBAT6L	0x23D	/* Data BAT 6 Lower Register */
+#define	SPRN_DBAT6U	0x23C	/* Data BAT 6 Upper Register */
+#define	SPRN_DBAT7L	0x23F	/* Data BAT 7 Lower Register */
+#define	SPRN_DBAT7U	0x23E	/* Data BAT 7 Upper Register */
+
 #define	SPRN_DBCR	0x3F2	/* Debug Control Regsiter */
 #define	  DBCR_EDM	0x80000000
 #define	  DBCR_IDM	0x40000000
@@ -191,7 +200,7 @@
 #define	  HID0_EBD	(1<<28)		/* Enable Bus Data Parity */
 #define	  HID0_SBCLK	(1<<27)
 #define	  HID0_EICE	(1<<26)
-#define	  HID0_TBEN	(1<<26)		/* Timebase enable - 745x */
+#define	  HID0_TBEN	(1<<26)		/* Timebase enable - 74xx and 82xx */
 #define	  HID0_ECLK	(1<<25)
 #define	  HID0_PAR	(1<<24)
 #define	  HID0_STEN	(1<<24)		/* Software table search enable - 745x */
@@ -230,6 +239,14 @@
 #define	SPRN_IBAT2U	0x214	/* Instruction BAT 2 Upper Register */
 #define	SPRN_IBAT3L	0x217	/* Instruction BAT 3 Lower Register */
 #define	SPRN_IBAT3U	0x216	/* Instruction BAT 3 Upper Register */
+#define	SPRN_IBAT4L	0x231	/* Instruction BAT 4 Lower Register */
+#define	SPRN_IBAT4U	0x230	/* Instruction BAT 4 Upper Register */
+#define	SPRN_IBAT5L	0x233	/* Instruction BAT 5 Lower Register */
+#define	SPRN_IBAT5U	0x232	/* Instruction BAT 5 Upper Register */
+#define	SPRN_IBAT6L	0x235	/* Instruction BAT 6 Lower Register */
+#define	SPRN_IBAT6U	0x234	/* Instruction BAT 6 Upper Register */
+#define	SPRN_IBAT7L	0x237	/* Instruction BAT 7 Lower Register */
+#define	SPRN_IBAT7U	0x236	/* Instruction BAT 7 Upper Register */
 #define	SPRN_ICCR	0x3FB	/* Instruction Cache Cacheability Register */
 #define	  ICCR_NOCACHE		0	/* Noncacheable */
 #define	  ICCR_CACHE		1	/* Cacheable */
@@ -398,6 +415,14 @@
 #define	DBAT2U	SPRN_DBAT2U	/* Data BAT 2 Upper Register */
 #define	DBAT3L	SPRN_DBAT3L	/* Data BAT 3 Lower Register */
 #define	DBAT3U	SPRN_DBAT3U	/* Data BAT 3 Upper Register */
+#define	DBAT4L	SPRN_DBAT4L	/* Data BAT 4 Lower Register */
+#define	DBAT4U	SPRN_DBAT4U	/* Data BAT 4 Upper Register */
+#define	DBAT5L	SPRN_DBAT5L	/* Data BAT 5 Lower Register */
+#define	DBAT5U	SPRN_DBAT5U	/* Data BAT 5 Upper Register */
+#define	DBAT6L	SPRN_DBAT6L	/* Data BAT 6 Lower Register */
+#define	DBAT6U	SPRN_DBAT6U	/* Data BAT 6 Upper Register */
+#define	DBAT7L	SPRN_DBAT7L	/* Data BAT 7 Lower Register */
+#define	DBAT7U	SPRN_DBAT7U	/* Data BAT 7 Upper Register */
 #define	DCMP	SPRN_DCMP      	/* Data TLB Compare Register */
 #define	DEC	SPRN_DEC       	/* Decrement Register */
 #define	DMISS	SPRN_DMISS     	/* Data TLB Miss Register */
@@ -416,6 +441,14 @@
 #define	IBAT2U	SPRN_IBAT2U	/* Instruction BAT 2 Upper Register */
 #define	IBAT3L	SPRN_IBAT3L	/* Instruction BAT 3 Lower Register */
 #define	IBAT3U	SPRN_IBAT3U	/* Instruction BAT 3 Upper Register */
+#define	IBAT4L	SPRN_IBAT4L	/* Instruction BAT 4 Lower Register */
+#define	IBAT4U	SPRN_IBAT4U	/* Instruction BAT 4 Upper Register */
+#define	IBAT5L	SPRN_IBAT5L	/* Instruction BAT 5 Lower Register */
+#define	IBAT5U	SPRN_IBAT5U	/* Instruction BAT 5 Upper Register */
+#define	IBAT6L	SPRN_IBAT6L	/* Instruction BAT 6 Lower Register */
+#define	IBAT6U	SPRN_IBAT6U	/* Instruction BAT 6 Upper Register */
+#define	IBAT7L	SPRN_IBAT7L	/* Instruction BAT 7 Lower Register */
+#define	IBAT7U	SPRN_IBAT7U	/* Instruction BAT 7 Upper Register */
 #define	ICMP	SPRN_ICMP	/* Instruction TLB Compare Register */
 #define	IMISS	SPRN_IMISS	/* Instruction TLB Miss Register */
 #define	IMMR	SPRN_IMMR      	/* PPC 860/821 Internal Memory Map Register */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/prom.h linux-2.4.20/include/asm-ppc/prom.h
--- linux-2.4.19/include/asm-ppc/prom.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/prom.h	2002-10-29 11:18:49.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.prom.h 1.24 04/09/02 21:01:58 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Definitions for talking to the Open Firmware PROM on
@@ -77,6 +77,7 @@
 extern struct device_node *find_compatible_devices(const char *type,
 						   const char *compat);
 extern struct device_node *find_all_nodes(void);
+extern struct device_node *find_phandle(phandle);
 extern int device_is_compatible(struct device_node *device, const char *);
 extern int machine_is_compatible(const char *compat);
 extern unsigned char *get_property(struct device_node *node, const char *name,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/rpxclassic.h linux-2.4.20/include/asm-ppc/rpxclassic.h
--- linux-2.4.19/include/asm-ppc/rpxclassic.h	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/rpxclassic.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,104 +0,0 @@
-/*
- * BK Id: SCCS/s.rpxclassic.h 1.11 08/17/01 15:23:17 paulus
- */
-
-/*
- * A collection of structures, addresses, and values associated with
- * the RPCG RPX-Classic board.  Copied from the RPX-Lite stuff.
- *
- * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
- */
-#ifdef __KERNEL__
-#ifndef __MACH_RPX_DEFS
-#define __MACH_RPX_DEFS
-
-#include <linux/config.h>
-
-#ifndef __ASSEMBLY__
-/* A Board Information structure that is given to a program when
- * prom starts it up.
- */
-typedef struct bd_info {
-	unsigned int	bi_memstart;	/* Memory start address */
-	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
-	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
-	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
-	unsigned char	bi_enetaddr[6];
-	unsigned int	bi_baudrate;
-} bd_t;
-
-extern bd_t m8xx_board_info;
-
-/* Memory map is configured by the PROM startup.
- * We just map a few things we need.  The CSR is actually 4 byte-wide
- * registers that can be accessed as 8-, 16-, or 32-bit values.
- */
-#define PCI_ISA_IO_ADDR		((unsigned)0x80000000)
-#define PCI_ISA_IO_SIZE		((uint)(512 * 1024 * 1024))
-#define PCI_ISA_MEM_ADDR	((unsigned)0xc0000000)
-#define PCI_ISA_MEM_SIZE	((uint)(512 * 1024 * 1024))
-#define RPX_CSR_ADDR		((uint)0xfa400000)
-#define RPX_CSR_SIZE		((uint)(4 * 1024))
-#define IMAP_ADDR		((uint)0xfa200000)
-#define IMAP_SIZE		((uint)(64 * 1024))
-#define PCI_CSR_ADDR		((uint)0x80000000)
-#define PCI_CSR_SIZE		((uint)(64 * 1024))
-#define PCMCIA_MEM_ADDR		((uint)0xe0000000)
-#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
-#define PCMCIA_IO_ADDR		((uint)0xe4000000)
-#define PCMCIA_IO_SIZE		((uint)(4 * 1024))
-#define PCMCIA_ATTRB_ADDR	((uint)0xe8000000)
-#define PCMCIA_ATTRB_SIZE	((uint)(4 * 1024))
-
-/* Things of interest in the CSR.
-*/
-#define BCSR0_ETHEN		((uint)0x80000000)
-#define BCSR0_ETHLPBK		((uint)0x40000000)
-#define BCSR0_COLTESTDIS	((uint)0x20000000)
-#define BCSR0_FULLDPLXDIS	((uint)0x10000000)
-#define BCSR0_ENFLSHSEL		((uint)0x04000000)
-#define BCSR0_FLASH_SEL		((uint)0x02000000)
-#define BCSR0_ENMONXCVR		((uint)0x01000000)
-
-#define BCSR0_PCMCIAVOLT	((uint)0x000f0000)	/* CLLF */
-#define BCSR0_PCMCIA3VOLT	((uint)0x000a0000)	/* CLLF */
-#define BCSR0_PCMCIA5VOLT	((uint)0x00060000)	/* CLLF */
-
-#define BCSR1_IPB5SEL           ((uint)0x00100000)
-#define BCSR1_PCVCTL4           ((uint)0x00080000)
-#define BCSR1_PCVCTL5           ((uint)0x00040000)
-#define BCSR1_PCVCTL6           ((uint)0x00020000)
-#define BCSR1_PCVCTL7           ((uint)0x00010000)
-
-#define BCSR2_EN232XCVR		((uint)0x00008000)
-#define BCSR2_QSPACESEL		((uint)0x00004000)
-#define BCSR2_FETHLEDMODE	((uint)0x00000800)	/* CLLF */
-
-#if defined(CONFIG_HTDMSOUND)
-#include <asm/rpxhiox.h>
-#endif
-
-/* define IO_BASE for pcmcia, CLLF only */
-#if !defined(CONFIG_PCI)
-#define _IO_BASE 0x80000000
-#define _IO_BASE_SIZE 0x1000
-
-/* for pcmcia sandisk */
-#ifdef CONFIG_IDE
-#define MAX_HWIFS 1
-#define ide_request_irq(irq,hand,flg,dev,id)    request_8xxirq((irq),(hand),(flg),(dev),(id))
-#endif
-#endif
-
-/* Interrupt level assignments.
-*/
-#define FEC_INTERRUPT	SIU_LEVEL1	/* FEC interrupt */
-
-#endif /* !__ASSEMBLY__ */
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS	0
-
-#endif
-#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/rpxhiox.h linux-2.4.20/include/asm-ppc/rpxhiox.h
--- linux-2.4.19/include/asm-ppc/rpxhiox.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/rpxhiox.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,45 +0,0 @@
-/*
- * BK Id: SCCS/s.rpxhiox.h 1.3 05/17/01 18:14:25 cort
- */
-
-/*
- * The Embedded Planet HIOX expansion card definitions.
- * There were a few different versions of these cards, but only
- * the one that escaped real production is defined here.
- *
- * Copyright (c) 2000 Dan Malek (dmalek@jlc.net)
- */
-#ifndef __MACH_RPX_HIOX_DEFS
-#define __MACH_RPX_HIOX_DEFS
-
-#define HIOX_CSR_ADDR		((uint)0xfac00000)
-#define HIOX_CSR_SIZE		((uint)(4 * 1024))
-#define HIOX_CSR0_ADDR		HIOX_CSR_ADDR
-#define HIOX_CSR4_ADDR		((uint)0xfac00004)
-
-#define HIOX_CSR0_DEFAULT	((uint)0x380f3c00)
-#define HIOX_CSR0_ENSCC2	((uint)0x80000000)
-#define HIOX_CSR0_ENSMC2	((uint)0x04000000)
-#define HIOX_CSR0_ENVDOCLK	((uint)0x02000000)
-#define HIOX_CSR0_VDORST_HL	((uint)0x01000000)
-#define HIOX_CSR0_RS232SEL	((uint)0x0000c000)
-#define HIOX_CSR0_SCC3SEL	((uint)0x0000c000)
-#define HIOX_CSR0_SMC1SEL	((uint)0x00008000)
-#define HIOX_CSR0_SCC1SEL	((uint)0x00004000)
-#define HIOX_CSR0_ENTOUCH	((uint)0x00000080)
-#define HIOX_CSR0_PDOWN100	((uint)0x00000060)
-#define HIOX_CSR0_PDOWN10	((uint)0x00000040)
-#define HIOX_CSR0_PDOWN1	((uint)0x00000020)
-#define HIOX_CSR0_TSELSPI	((uint)0x00000010)
-#define HIOX_CSR0_TIRQSTAT	((uint)0x00000008)
-#define HIOX_CSR4_DEFAULT	((uint)0x00000000)
-#define HIOX_CSR4_ENTIRQ2	((uint)0x20000000)
-#define HIOX_CSR4_ENTIRQ3	((uint)0x10000000)
-#define HIOX_CSR4_ENAUDIO	((uint)0x00000080)
-#define HIOX_CSR4_RSTAUDIO	((uint)0x00000040)	/* 0 == reset */
-#define HIOX_CSR4_AUDCLKHI	((uint)0x00000020)
-#define HIOX_CSR4_AUDSPISEL	((uint)0x00000010)
-#define HIOX_CSR4_AUDIRQSTAT	((uint)0x00000008)
-#define HIOX_CSR4_AUDCLKSEL	((uint)0x00000007)
-
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/rpxlite.h linux-2.4.20/include/asm-ppc/rpxlite.h
--- linux-2.4.19/include/asm-ppc/rpxlite.h	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/rpxlite.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,84 +0,0 @@
-/*
- * BK Id: SCCS/s.rpxlite.h 1.11 08/17/01 15:23:17 paulus
- */
-
-/*
- * A collection of structures, addresses, and values associated with
- * the RPCG RPX-Lite board.  Copied from the MBX stuff.
- *
- * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
- */
-#ifdef __KERNEL__
-#ifndef __MACH_RPX_DEFS
-#define __MACH_RPX_DEFS
-
-#include <linux/config.h>
-
-#ifndef __ASSEMBLY__
-/* A Board Information structure that is given to a program when
- * prom starts it up.
- */
-typedef struct bd_info {
-	unsigned int	bi_memstart;	/* Memory start address */
-	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
-	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
-	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
-	unsigned char	bi_enetaddr[6];
-	unsigned int	bi_baudrate;
-} bd_t;
-
-extern bd_t m8xx_board_info;
-
-/* Memory map is configured by the PROM startup.
- * We just map a few things we need.  The CSR is actually 4 byte-wide
- * registers that can be accessed as 8-, 16-, or 32-bit values.
- */
-#define RPX_CSR_ADDR		((uint)0xfa400000)
-#define RPX_CSR_SIZE		((uint)(4 * 1024))
-#define IMAP_ADDR		((uint)0xfa200000)
-#define IMAP_SIZE		((uint)(64 * 1024))
-#define PCMCIA_MEM_ADDR		((uint)0x04000000)
-#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
-#define PCMCIA_IO_ADDR		((uint)0x04400000)
-#define PCMCIA_IO_SIZE		((uint)(4 * 1024))
-
-/* Things of interest in the CSR.
-*/
-#define BCSR0_ETHEN		((uint)0x80000000)
-#define BCSR0_ETHLPBK		((uint)0x40000000)
-#define BCSR0_COLTESTDIS	((uint)0x20000000)
-#define BCSR0_FULLDPLXDIS	((uint)0x10000000)
-#define BCSR0_LEDOFF		((uint)0x08000000)
-#define BCSR0_USBDISABLE	((uint)0x04000000)
-#define BCSR0_USBHISPEED	((uint)0x02000000)
-#define BCSR0_USBPWREN		((uint)0x01000000)
-#define BCSR0_PCMCIAVOLT	((uint)0x000f0000)
-#define BCSR0_PCMCIA3VOLT	((uint)0x000a0000)
-#define BCSR0_PCMCIA5VOLT	((uint)0x00060000)
-
-#define BCSR1_IPB5SEL          ((uint)0x00100000)
-#define BCSR1_PCVCTL4          ((uint)0x00080000)
-#define BCSR1_PCVCTL5          ((uint)0x00040000)
-#define BCSR1_PCVCTL6          ((uint)0x00020000)
-#define BCSR1_PCVCTL7          ((uint)0x00010000)
-
-#if defined(CONFIG_HTDMSOUND)
-#include <asm/rpxhiox.h>
-#endif
-#endif /* !__ASSEMBLY__ */
-
-/* define IO_BASE for pcmcia */
-#define _IO_BASE 0x80000000
-#define _IO_BASE_SIZE 0x1000
-
-#ifdef CONFIG_IDE
-#define MAX_HWIFS 1
-#define ide_request_irq(irq,hand,flg,dev,id)    request_8xxirq((irq),(hand),(flg),(dev),(id))
-#endif
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS	0
-
-#endif
-#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/rwsem.h linux-2.4.20/include/asm-ppc/rwsem.h
--- linux-2.4.19/include/asm-ppc/rwsem.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/rwsem.h	2002-10-29 11:18:50.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.rwsem.h 1.6 05/17/01 18:14:25 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * include/asm-ppc/rwsem.h: R/W semaphores for PPC using the stuff
@@ -77,6 +77,20 @@
 		rwsem_down_read_failed(sem);
 }
 
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	while ((tmp = sem->count) >= 0) {
+		if (tmp == cmpxchg(&sem->count, tmp,
+				   tmp + RWSEM_ACTIVE_READ_BIAS)) {
+			smp_wmb();
+			return 1;
+		}
+	}
+	return 0;
+}
+
 /*
  * lock for writing
  */
@@ -92,6 +106,16 @@
 		rwsem_down_write_failed(sem);
 }
 
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
+		      RWSEM_ACTIVE_WRITE_BIAS);
+	smp_wmb();
+	return tmp == RWSEM_UNLOCKED_VALUE;
+}
+
 /*
  * unlock after reading
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/semaphore.h linux-2.4.20/include/asm-ppc/semaphore.h
--- linux-2.4.19/include/asm-ppc/semaphore.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/semaphore.h	2002-10-29 11:18:48.000000000 +0000
@@ -133,6 +133,11 @@
 		__up(sem);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* !(_PPC_SEMAPHORE_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/serial.h linux-2.4.20/include/asm-ppc/serial.h
--- linux-2.4.19/include/asm-ppc/serial.h	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/serial.h	2002-10-29 11:18:50.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.serial.h 1.15 10/23/01 08:09:35 trini
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * include/asm-ppc/serial.h
@@ -11,8 +11,10 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_GEMINI
-#include <asm/gemini_serial.h>
+#if defined(CONFIG_GEMINI)
+#include <platforms/gemini_serial.h>
+#elif defined(CONFIG_SPRUCE)
+#include <platforms/spruce.h>
 #elif defined(CONFIG_4xx)
 #include <asm/ppc4xx_serial.h>
 #else
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/socket.h linux-2.4.20/include/asm-ppc/socket.h
--- linux-2.4.19/include/asm-ppc/socket.h	2001-06-21 04:00:55.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/socket.h	2002-10-29 11:18:39.000000000 +0000
@@ -12,7 +12,7 @@
 #define SIOCATMARK	0x8905
 #define SIOCGSTAMP	0x8906		/* Get stamp */
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	1
 
 #define SO_DEBUG	1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/spd8xx.h linux-2.4.20/include/asm-ppc/spd8xx.h
--- linux-2.4.19/include/asm-ppc/spd8xx.h	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/spd8xx.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,69 +0,0 @@
-/*
- * BK Id: SCCS/s.spd8xx.h 1.8 10/27/01 13:39:41 trini
- */
-/*
- * Speech Design SPD8xxTS board specific definitions
- * 
- * Copyright (c) 2000,2001 Wolfgang Denk (wd@denx.de)
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_SPD8XX_H__
-#define __ASM_SPD8XX_H__
-
-#include <linux/config.h>
- 
-#include <asm/ppcboot.h>
-
-#define SPD_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR */
-#define SPD_IMAP_SIZE	(64 * 1024)	/* size of mapped area */
-
-#define IMAP_ADDR	SPD_IMMR_BASE	/* physical base address of IMMR area */
-#define IMAP_SIZE	SPD_IMAP_SIZE	/* mapped size of IMMR area */
-
-#define PCMCIA_MEM_ADDR	((uint)0xFE100000)
-#define PCMCIA_MEM_SIZE	((uint)(64 * 1024))
-
-#define IDE0_INTERRUPT	10		/* = IRQ5 */
-#define IDE1_INTERRUPT	12		/* = IRQ6 */
-#define CPM_INTERRUPT	13		/* = SIU_LEVEL6 (was: SIU_LEVEL2) */
-
-/* override the default number of IDE hardware interfaces */
-#define MAX_HWIFS	2
-
-/*
- * Definitions for IDE0 Interface
- */
-#define IDE0_BASE_OFFSET		0x0000	/* Offset in PCMCIA memory */
-#define IDE0_DATA_REG_OFFSET		0x0000
-#define IDE0_ERROR_REG_OFFSET		0x0081
-#define IDE0_NSECTOR_REG_OFFSET		0x0082
-#define IDE0_SECTOR_REG_OFFSET		0x0083
-#define IDE0_LCYL_REG_OFFSET		0x0084
-#define IDE0_HCYL_REG_OFFSET		0x0085
-#define IDE0_SELECT_REG_OFFSET		0x0086
-#define IDE0_STATUS_REG_OFFSET		0x0087
-#define IDE0_CONTROL_REG_OFFSET		0x0106
-#define IDE0_IRQ_REG_OFFSET		0x000A	/* not used */
-
-/*
- * Definitions for IDE1 Interface
- */
-#define IDE1_BASE_OFFSET		0x0C00	/* Offset in PCMCIA memory */
-#define IDE1_DATA_REG_OFFSET		0x0000
-#define IDE1_ERROR_REG_OFFSET		0x0081
-#define IDE1_NSECTOR_REG_OFFSET		0x0082
-#define IDE1_SECTOR_REG_OFFSET		0x0083
-#define IDE1_LCYL_REG_OFFSET		0x0084
-#define IDE1_HCYL_REG_OFFSET		0x0085
-#define IDE1_SELECT_REG_OFFSET		0x0086
-#define IDE1_STATUS_REG_OFFSET		0x0087
-#define IDE1_CONTROL_REG_OFFSET		0x0106
-#define IDE1_IRQ_REG_OFFSET		0x000A	/* not used */
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS	0
-
-#endif /* __ASM_SPD8XX_H__ */
-#endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/spinlock.h linux-2.4.20/include/asm-ppc/spinlock.h
--- linux-2.4.19/include/asm-ppc/spinlock.h	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/spinlock.h	2002-10-29 11:18:37.000000000 +0000
@@ -1,12 +1,16 @@
 /*
- * BK Id: SCCS/s.spinlock.h 1.9 08/21/01 16:07:48 trini
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #ifndef __ASM_SPINLOCK_H
 #define __ASM_SPINLOCK_H
 
 #include <asm/system.h>
 
-#undef SPINLOCK_DEBUG
+#if defined(CONFIG_DEBUG_SPINLOCK)
+#define SPINLOCK_DEBUG 1
+#else
+#define SPINLOCK_DEBUG 0
+#endif
 
 /*
  * Simple spin lock operations.
@@ -14,7 +18,7 @@
 
 typedef struct {
 	volatile unsigned long lock;
-#ifdef SPINLOCK_DEBUG
+#if SPINLOCK_DEBUG
 	volatile unsigned long owner_pc;
 	volatile unsigned long owner_cpu;
 #endif
@@ -33,7 +37,17 @@
 #define spin_is_locked(x)	((x)->lock != 0)
 #define spin_unlock_wait(x)	do { barrier(); } while(spin_is_locked(x))
 
-#ifndef SPINLOCK_DEBUG
+#if SPINLOCK_DEBUG
+
+extern void _spin_lock(spinlock_t *lock);
+extern void _spin_unlock(spinlock_t *lock);
+extern int spin_trylock(spinlock_t *lock);
+extern unsigned long __spin_trylock(volatile unsigned long *lock);
+
+#define spin_lock(lp)			_spin_lock(lp)
+#define spin_unlock(lp)			_spin_unlock(lp)
+
+#else /* ! SPINLOCK_DEBUG */
 
 static inline void spin_lock(spinlock_t *lock)
 {
@@ -63,16 +77,6 @@
 
 #define spin_trylock(lock) (!test_and_set_bit(0,(lock)))
 
-#else
-
-extern void _spin_lock(spinlock_t *lock);
-extern void _spin_unlock(spinlock_t *lock);
-extern int spin_trylock(spinlock_t *lock);
-extern unsigned long __spin_trylock(volatile unsigned long *lock);
-
-#define spin_lock(lp)			_spin_lock(lp)
-#define spin_unlock(lp)			_spin_unlock(lp)
-
 #endif
 
 /*
@@ -87,7 +91,7 @@
  */
 typedef struct {
 	volatile unsigned long lock;
-#ifdef SPINLOCK_DEBUG
+#if SPINLOCK_DEBUG
 	volatile unsigned long owner_pc;
 #endif
 } rwlock_t;
@@ -101,7 +105,19 @@
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0 RWLOCK_DEBUG_INIT }
 #define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
 
-#ifndef SPINLOCK_DEBUG
+#if SPINLOCK_DEBUG
+
+extern void _read_lock(rwlock_t *rw);
+extern void _read_unlock(rwlock_t *rw);
+extern void _write_lock(rwlock_t *rw);
+extern void _write_unlock(rwlock_t *rw);
+
+#define read_lock(rw)		_read_lock(rw)
+#define write_lock(rw)		_write_lock(rw)
+#define write_unlock(rw)	_write_unlock(rw)
+#define read_unlock(rw)		_read_unlock(rw)
+
+#else /* ! SPINLOCK_DEBUG */
 
 static __inline__ void read_lock(rwlock_t *rw)
 {
@@ -164,18 +180,6 @@
 	rw->lock = 0;
 }
 
-#else
-
-extern void _read_lock(rwlock_t *rw);
-extern void _read_unlock(rwlock_t *rw);
-extern void _write_lock(rwlock_t *rw);
-extern void _write_unlock(rwlock_t *rw);
-
-#define read_lock(rw)		_read_lock(rw)
-#define write_lock(rw)		_write_lock(rw)
-#define write_unlock(rw)	_write_unlock(rw)
-#define read_unlock(rw)		_read_unlock(rw)
-
 #endif
 
 #endif /* __ASM_SPINLOCK_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/termios.h linux-2.4.20/include/asm-ppc/termios.h
--- linux-2.4.19/include/asm-ppc/termios.h	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/termios.h	2002-10-29 11:18:51.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.termios.h 1.8 05/17/01 18:14:26 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #ifndef _PPC_TERMIOS_H
 #define _PPC_TERMIOS_H
@@ -173,6 +173,7 @@
 #define TIOCM_OUT1	0x2000
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
+#define TIOCM_MODEM_BITS TIOCM_OUT2
 
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 #define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/timex.h linux-2.4.20/include/asm-ppc/timex.h
--- linux-2.4.19/include/asm-ppc/timex.h	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/timex.h	2002-10-29 11:18:47.000000000 +0000
@@ -46,4 +46,8 @@
 }
 
 #endif
+
+#define vxtime_lock()		do {} while (0)
+#define vxtime_unlock()		do {} while (0)
+
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/todc.h linux-2.4.20/include/asm-ppc/todc.h
--- linux-2.4.19/include/asm-ppc/todc.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/todc.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,452 @@
+/*
+ * include/asm-ppc/todc.h
+ *
+ * Definitions for the M48Txx and mc146818 series of Time of day/Real Time
+ * Clock chips.
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001 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.
+ */
+
+/*
+ * Support for the M48T37/M48T59/.../mc146818 Real Time Clock chips.
+ * Purpose is to make one generic file that handles all of these chips instead
+ * of every platform implementing the same code over & over again.
+ */
+
+#ifndef __PPC_KERNEL_TODC_H
+#define __PPC_KERNEL_TODC_H
+
+typedef struct {
+	uint rtc_type;		/* your particular chip */
+
+	/*
+	 * Following are the addresses of the AS0, AS1, and DATA registers
+	 * of these chips.  Note that these are board-specific.
+	 */
+	unsigned char *nvram_as0;
+	unsigned char *nvram_as1;
+	unsigned char *nvram_data;
+
+	/*
+	 * Define bits to stop external set of regs from changing so
+	 * the chip can be read/written reliably.
+	 */
+	unsigned char enable_read;
+	unsigned char enable_write;
+
+	/*
+	 * Following is the number of AS0 address bits.  This is normally
+	 * 8 but some bad hardware routes address lines incorrectly.
+	 */
+	int as0_bits;
+
+	int nvram_size;	/* Size of NVRAM on chip */
+	int sw_flags;	/* Software control flags */
+
+	/* Following are the register offsets for the particular chip */
+	int year;
+	int month;
+	int day_of_month;
+	int day_of_week;
+	int hours;
+	int minutes;
+	int seconds;
+	int control_b;
+	int control_a;
+	int watchdog;
+	int interrupts;
+	int alarm_date;
+	int alarm_hour;
+	int alarm_minutes;
+	int alarm_seconds;
+	int century;
+	int flags;
+
+	/*
+	 * Some RTC chips have their NVRAM buried behind a addr/data pair of
+	 * regs on the first level/clock registers.  The following fields
+	 * are the addresses for those addr/data regs.
+	 */
+	int nvram_addr_reg;
+	int nvram_data_reg;
+} todc_info_t;
+
+/*
+ * Define the types of TODC/RTC variants that are supported in
+ * arch/ppc/kernel/todc_time.c
+ * Make a new one of these for any chip somehow differs from what's already
+ * defined.  That way, if you ever need to put in code to touch those
+ * bits/registers in todc_time.c, you can put it inside an
+ * 'if (todc_info->rtc_type ==  TODC_TYPE_XXX)' so you won't break
+ * anyone else.
+ */
+#define	TODC_TYPE_MK48T35		1
+#define	TODC_TYPE_MK48T37		2
+#define	TODC_TYPE_MK48T59		3
+#define	TODC_TYPE_DS1693		4	/* Dallas DS1693 RTC */
+#define	TODC_TYPE_DS1743		5	/* Dallas DS1743 RTC */
+#define	TODC_TYPE_DS1746		6	/* Dallas DS1746 RTC */
+#define	TODC_TYPE_DS1747		7	/* Dallas DS1747 RTC */
+#define	TODC_TYPE_DS1501		8	/* Dallas DS1501 RTC */
+#define TODC_TYPE_DS1643		9	/* Dallas DS1643 RTC */
+#define TODC_TYPE_PC97307		10	/* PC97307 internal RTC */
+#define TODC_TYPE_DS1557		11	/* Dallas DS1557 RTC */
+#define	TODC_TYPE_MC146818		100	/* Leave room for m48txx's */
+
+/*
+ * Bit to clear/set to enable reads/writes to the chip
+ */
+#define	TODC_MK48TXX_CNTL_A_R		0x40
+#define	TODC_MK48TXX_CNTL_A_W		0x80
+#define	TODC_MK48TXX_DAY_CB		0x80
+
+#define	TODC_DS1501_CNTL_B_TE		0x80
+
+/*
+ * Define flag bits used by todc routines.
+ */
+#define	TODC_FLAG_2_LEVEL_NVRAM		0x00000001
+
+/*
+ * Define the values for the various RTC's that should to into the todc_info
+ * table.
+ * Note: The XXX_NVRAM_SIZE, XXX_NVRAM_ADDR_REG, and XXX_NVRAM_DATA_REG only
+ * matter if XXX_SW_FLAGS has TODC_FLAG_2_LEVEL_NVRAM set.
+ */
+#define	TODC_TYPE_MK48T35_NVRAM_SIZE		0x7ff8
+#define	TODC_TYPE_MK48T35_SW_FLAGS		0
+#define	TODC_TYPE_MK48T35_YEAR			0x7fff
+#define	TODC_TYPE_MK48T35_MONTH			0x7ffe
+#define	TODC_TYPE_MK48T35_DOM			0x7ffd	/* Day of Month */
+#define	TODC_TYPE_MK48T35_DOW			0x7ffc	/* Day of Week */
+#define	TODC_TYPE_MK48T35_HOURS			0x7ffb
+#define	TODC_TYPE_MK48T35_MINUTES		0x7ffa
+#define	TODC_TYPE_MK48T35_SECONDS		0x7ff9
+#define	TODC_TYPE_MK48T35_CNTL_B		0x7ff9
+#define	TODC_TYPE_MK48T35_CNTL_A		0x7ff8
+#define	TODC_TYPE_MK48T35_WATCHDOG		0x0000
+#define	TODC_TYPE_MK48T35_INTERRUPTS		0x0000
+#define	TODC_TYPE_MK48T35_ALARM_DATE		0x0000
+#define	TODC_TYPE_MK48T35_ALARM_HOUR		0x0000
+#define	TODC_TYPE_MK48T35_ALARM_MINUTES		0x0000
+#define	TODC_TYPE_MK48T35_ALARM_SECONDS		0x0000
+#define	TODC_TYPE_MK48T35_CENTURY		0x0000
+#define	TODC_TYPE_MK48T35_FLAGS			0x0000
+#define	TODC_TYPE_MK48T35_NVRAM_ADDR_REG	0
+#define	TODC_TYPE_MK48T35_NVRAM_DATA_REG	0
+
+#define	TODC_TYPE_MK48T37_NVRAM_SIZE		0x7ff0
+#define	TODC_TYPE_MK48T37_SW_FLAGS		0
+#define	TODC_TYPE_MK48T37_YEAR			0x7fff
+#define	TODC_TYPE_MK48T37_MONTH			0x7ffe
+#define	TODC_TYPE_MK48T37_DOM			0x7ffd	/* Day of Month */
+#define	TODC_TYPE_MK48T37_DOW			0x7ffc	/* Day of Week */
+#define	TODC_TYPE_MK48T37_HOURS			0x7ffb
+#define	TODC_TYPE_MK48T37_MINUTES		0x7ffa
+#define	TODC_TYPE_MK48T37_SECONDS		0x7ff9
+#define	TODC_TYPE_MK48T37_CNTL_B		0x7ff9
+#define	TODC_TYPE_MK48T37_CNTL_A		0x7ff8
+#define	TODC_TYPE_MK48T37_WATCHDOG		0x7ff7
+#define	TODC_TYPE_MK48T37_INTERRUPTS		0x7ff6
+#define	TODC_TYPE_MK48T37_ALARM_DATE		0x7ff5
+#define	TODC_TYPE_MK48T37_ALARM_HOUR		0x7ff4
+#define	TODC_TYPE_MK48T37_ALARM_MINUTES		0x7ff3
+#define	TODC_TYPE_MK48T37_ALARM_SECONDS		0x7ff2
+#define	TODC_TYPE_MK48T37_CENTURY		0x7ff1
+#define	TODC_TYPE_MK48T37_FLAGS			0x7ff0
+#define	TODC_TYPE_MK48T37_NVRAM_ADDR_REG	0
+#define	TODC_TYPE_MK48T37_NVRAM_DATA_REG	0
+
+#define	TODC_TYPE_MK48T59_NVRAM_SIZE		0x1ff0
+#define	TODC_TYPE_MK48T59_SW_FLAGS		0
+#define	TODC_TYPE_MK48T59_YEAR			0x1fff
+#define	TODC_TYPE_MK48T59_MONTH			0x1ffe
+#define	TODC_TYPE_MK48T59_DOM			0x1ffd	/* Day of Month */
+#define	TODC_TYPE_MK48T59_DOW			0x1ffc	/* Day of Week */
+#define	TODC_TYPE_MK48T59_HOURS			0x1ffb
+#define	TODC_TYPE_MK48T59_MINUTES		0x1ffa
+#define	TODC_TYPE_MK48T59_SECONDS		0x1ff9
+#define	TODC_TYPE_MK48T59_CNTL_B		0x1ff9
+#define	TODC_TYPE_MK48T59_CNTL_A		0x1ff8
+#define	TODC_TYPE_MK48T59_WATCHDOG		0x1fff
+#define	TODC_TYPE_MK48T59_INTERRUPTS		0x1fff
+#define	TODC_TYPE_MK48T59_ALARM_DATE		0x1fff
+#define	TODC_TYPE_MK48T59_ALARM_HOUR		0x1fff
+#define	TODC_TYPE_MK48T59_ALARM_MINUTES		0x1fff
+#define	TODC_TYPE_MK48T59_ALARM_SECONDS		0x1fff
+#define	TODC_TYPE_MK48T59_CENTURY		0x1fff
+#define	TODC_TYPE_MK48T59_FLAGS			0x1fff
+#define	TODC_TYPE_MK48T59_NVRAM_ADDR_REG	0
+#define	TODC_TYPE_MK48T59_NVRAM_DATA_REG	0
+
+#define	TODC_TYPE_DS1501_NVRAM_SIZE	0x100
+#define	TODC_TYPE_DS1501_SW_FLAGS	TODC_FLAG_2_LEVEL_NVRAM
+#define	TODC_TYPE_DS1501_YEAR		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x06)
+#define	TODC_TYPE_DS1501_MONTH		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x05)
+#define	TODC_TYPE_DS1501_DOM		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x04)
+#define	TODC_TYPE_DS1501_DOW		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x03)
+#define	TODC_TYPE_DS1501_HOURS		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x02)
+#define	TODC_TYPE_DS1501_MINUTES	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x01)
+#define	TODC_TYPE_DS1501_SECONDS	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x00)
+#define	TODC_TYPE_DS1501_CNTL_B		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x0f)
+#define	TODC_TYPE_DS1501_CNTL_A		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x0f)
+#define	TODC_TYPE_DS1501_WATCHDOG	(TODC_TYPE_DS1501_NVRAM_SIZE + 0xff)
+#define	TODC_TYPE_DS1501_INTERRUPTS	(TODC_TYPE_DS1501_NVRAM_SIZE + 0xff)
+#define	TODC_TYPE_DS1501_ALARM_DATE	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x0b)
+#define	TODC_TYPE_DS1501_ALARM_HOUR	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x0a)
+#define	TODC_TYPE_DS1501_ALARM_MINUTES	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x09)
+#define	TODC_TYPE_DS1501_ALARM_SECONDS	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x08)
+#define	TODC_TYPE_DS1501_CENTURY	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x07)
+#define	TODC_TYPE_DS1501_FLAGS		(TODC_TYPE_DS1501_NVRAM_SIZE + 0xff)
+#define	TODC_TYPE_DS1501_NVRAM_ADDR_REG	0x10
+#define	TODC_TYPE_DS1501_NVRAM_DATA_REG	0x13
+
+#define	TODC_TYPE_DS1557_NVRAM_SIZE		0x7fff0
+#define	TODC_TYPE_DS1557_SW_FLAGS		0
+#define	TODC_TYPE_DS1557_YEAR			0x7ffff
+#define	TODC_TYPE_DS1557_MONTH			0x7fffe
+#define	TODC_TYPE_DS1557_DOM			0x7fffd	/* Day of Month */
+#define	TODC_TYPE_DS1557_DOW			0x7fffc	/* Day of Week */
+#define	TODC_TYPE_DS1557_HOURS			0x7fffb
+#define	TODC_TYPE_DS1557_MINUTES		0x7fffa
+#define	TODC_TYPE_DS1557_SECONDS		0x7fff9
+#define	TODC_TYPE_DS1557_CNTL_B			0x7fff9
+#define	TODC_TYPE_DS1557_CNTL_A			0x7fff8	/* control_a R/W regs */
+#define	TODC_TYPE_DS1557_WATCHDOG		0x7fff7
+#define	TODC_TYPE_DS1557_INTERRUPTS		0x7fff6
+#define	TODC_TYPE_DS1557_ALARM_DATE		0x7fff5
+#define	TODC_TYPE_DS1557_ALARM_HOUR		0x7fff4
+#define	TODC_TYPE_DS1557_ALARM_MINUTES		0x7fff3
+#define	TODC_TYPE_DS1557_ALARM_SECONDS		0x7fff2
+#define	TODC_TYPE_DS1557_CENTURY		0x7fff8
+#define	TODC_TYPE_DS1557_FLAGS			0x7fff0
+#define	TODC_TYPE_DS1557_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1557_NVRAM_DATA_REG		0
+
+#define	TODC_TYPE_DS1643_NVRAM_SIZE		0x1ff8
+#define	TODC_TYPE_DS1643_SW_FLAGS		0
+#define	TODC_TYPE_DS1643_YEAR			0x1fff
+#define	TODC_TYPE_DS1643_MONTH			0x1ffe
+#define	TODC_TYPE_DS1643_DOM			0x1ffd	/* Day of Month */
+#define	TODC_TYPE_DS1643_DOW			0x1ffc	/* Day of Week */
+#define	TODC_TYPE_DS1643_HOURS			0x1ffb
+#define	TODC_TYPE_DS1643_MINUTES		0x1ffa
+#define	TODC_TYPE_DS1643_SECONDS		0x1ff9
+#define	TODC_TYPE_DS1643_CNTL_B			0x1ff9
+#define	TODC_TYPE_DS1643_CNTL_A			0x1ff8	/* control_a R/W regs */
+#define	TODC_TYPE_DS1643_WATCHDOG		0x1fff
+#define	TODC_TYPE_DS1643_INTERRUPTS		0x1fff
+#define	TODC_TYPE_DS1643_ALARM_DATE		0x1fff
+#define	TODC_TYPE_DS1643_ALARM_HOUR		0x1fff
+#define	TODC_TYPE_DS1643_ALARM_MINUTES		0x1fff
+#define	TODC_TYPE_DS1643_ALARM_SECONDS		0x1fff
+#define	TODC_TYPE_DS1643_CENTURY		0x1ff8
+#define	TODC_TYPE_DS1643_FLAGS			0x1fff
+#define	TODC_TYPE_DS1643_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1643_NVRAM_DATA_REG		0
+
+#define	TODC_TYPE_DS1693_NVRAM_SIZE		0 /* Not handled yet */
+#define	TODC_TYPE_DS1693_SW_FLAGS		0
+#define	TODC_TYPE_DS1693_YEAR			0x09
+#define	TODC_TYPE_DS1693_MONTH			0x08
+#define	TODC_TYPE_DS1693_DOM			0x07	/* Day of Month */
+#define	TODC_TYPE_DS1693_DOW			0x06	/* Day of Week */
+#define	TODC_TYPE_DS1693_HOURS			0x04
+#define	TODC_TYPE_DS1693_MINUTES		0x02
+#define	TODC_TYPE_DS1693_SECONDS		0x00
+#define	TODC_TYPE_DS1693_CNTL_B			0x0b
+#define	TODC_TYPE_DS1693_CNTL_A			0x0a
+#define	TODC_TYPE_DS1693_WATCHDOG		0xff
+#define	TODC_TYPE_DS1693_INTERRUPTS		0xff
+#define	TODC_TYPE_DS1693_ALARM_DATE		0x49
+#define	TODC_TYPE_DS1693_ALARM_HOUR		0x05
+#define	TODC_TYPE_DS1693_ALARM_MINUTES		0x03
+#define	TODC_TYPE_DS1693_ALARM_SECONDS		0x01
+#define	TODC_TYPE_DS1693_CENTURY		0x48
+#define	TODC_TYPE_DS1693_FLAGS			0xff
+#define	TODC_TYPE_DS1693_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1693_NVRAM_DATA_REG		0
+
+#define	TODC_TYPE_DS1743_NVRAM_SIZE		0x1ff8
+#define	TODC_TYPE_DS1743_SW_FLAGS		0
+#define	TODC_TYPE_DS1743_YEAR			0x1fff
+#define	TODC_TYPE_DS1743_MONTH			0x1ffe
+#define	TODC_TYPE_DS1743_DOM			0x1ffd	/* Day of Month */
+#define	TODC_TYPE_DS1743_DOW			0x1ffc	/* Day of Week */
+#define	TODC_TYPE_DS1743_HOURS			0x1ffb
+#define	TODC_TYPE_DS1743_MINUTES		0x1ffa
+#define	TODC_TYPE_DS1743_SECONDS		0x1ff9
+#define	TODC_TYPE_DS1743_CNTL_B			0x1ff9
+#define	TODC_TYPE_DS1743_CNTL_A			0x1ff8	/* control_a R/W regs */
+#define	TODC_TYPE_DS1743_WATCHDOG		0x1fff
+#define	TODC_TYPE_DS1743_INTERRUPTS		0x1fff
+#define	TODC_TYPE_DS1743_ALARM_DATE		0x1fff
+#define	TODC_TYPE_DS1743_ALARM_HOUR		0x1fff
+#define	TODC_TYPE_DS1743_ALARM_MINUTES		0x1fff
+#define	TODC_TYPE_DS1743_ALARM_SECONDS		0x1fff
+#define	TODC_TYPE_DS1743_CENTURY		0x1ff8
+#define	TODC_TYPE_DS1743_FLAGS			0x1fff
+#define	TODC_TYPE_DS1743_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1743_NVRAM_DATA_REG		0
+
+#define	TODC_TYPE_DS1746_NVRAM_SIZE		0x1fff8
+#define	TODC_TYPE_DS1746_SW_FLAGS		0
+#define	TODC_TYPE_DS1746_YEAR			0x1ffff
+#define	TODC_TYPE_DS1746_MONTH			0x1fffe
+#define	TODC_TYPE_DS1746_DOM			0x1fffd	/* Day of Month */
+#define	TODC_TYPE_DS1746_DOW			0x1fffc	/* Day of Week */
+#define	TODC_TYPE_DS1746_HOURS			0x1fffb
+#define	TODC_TYPE_DS1746_MINUTES		0x1fffa
+#define	TODC_TYPE_DS1746_SECONDS		0x1fff9
+#define	TODC_TYPE_DS1746_CNTL_B			0x1fff9
+#define	TODC_TYPE_DS1746_CNTL_A			0x1fff8	/* control_a R/W regs */
+#define	TODC_TYPE_DS1746_WATCHDOG		0x00000
+#define	TODC_TYPE_DS1746_INTERRUPTS		0x00000
+#define	TODC_TYPE_DS1746_ALARM_DATE		0x00000
+#define	TODC_TYPE_DS1746_ALARM_HOUR		0x00000
+#define	TODC_TYPE_DS1746_ALARM_MINUTES		0x00000
+#define	TODC_TYPE_DS1746_ALARM_SECONDS		0x00000
+#define	TODC_TYPE_DS1746_CENTURY		0x00000
+#define	TODC_TYPE_DS1746_FLAGS			0x00000
+#define	TODC_TYPE_DS1746_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1746_NVRAM_DATA_REG		0
+
+#define	TODC_TYPE_DS1747_NVRAM_SIZE		0x7fff8
+#define	TODC_TYPE_DS1747_SW_FLAGS		0
+#define	TODC_TYPE_DS1747_YEAR			0x7ffff
+#define	TODC_TYPE_DS1747_MONTH			0x7fffe
+#define	TODC_TYPE_DS1747_DOM			0x7fffd	/* Day of Month */
+#define	TODC_TYPE_DS1747_DOW			0x7fffc	/* Day of Week */
+#define	TODC_TYPE_DS1747_HOURS			0x7fffb
+#define	TODC_TYPE_DS1747_MINUTES		0x7fffa
+#define	TODC_TYPE_DS1747_SECONDS		0x7fff9
+#define	TODC_TYPE_DS1747_CNTL_B			0x7fff9
+#define	TODC_TYPE_DS1747_CNTL_A			0x7fff8	/* control_a R/W regs */
+#define	TODC_TYPE_DS1747_WATCHDOG		0x00000
+#define	TODC_TYPE_DS1747_INTERRUPTS		0x00000
+#define	TODC_TYPE_DS1747_ALARM_DATE		0x00000
+#define	TODC_TYPE_DS1747_ALARM_HOUR		0x00000
+#define	TODC_TYPE_DS1747_ALARM_MINUTES		0x00000
+#define	TODC_TYPE_DS1747_ALARM_SECONDS		0x00000
+#define	TODC_TYPE_DS1747_CENTURY		0x00000
+#define	TODC_TYPE_DS1747_FLAGS			0x00000
+#define	TODC_TYPE_DS1747_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1747_NVRAM_DATA_REG		0
+
+#define	TODC_TYPE_MC146818_NVRAM_SIZE		0	/* XXXX */
+#define	TODC_TYPE_MC146818_SW_FLAGS		0
+#define	TODC_TYPE_MC146818_YEAR			0x09
+#define	TODC_TYPE_MC146818_MONTH		0x08
+#define	TODC_TYPE_MC146818_DOM			0x07	/* Day of Month */
+#define	TODC_TYPE_MC146818_DOW			0x06	/* Day of Week */
+#define	TODC_TYPE_MC146818_HOURS		0x04
+#define	TODC_TYPE_MC146818_MINUTES		0x02
+#define	TODC_TYPE_MC146818_SECONDS		0x00
+#define	TODC_TYPE_MC146818_CNTL_B		0x0a
+#define	TODC_TYPE_MC146818_CNTL_A		0x0b	/* control_a R/W regs */
+#define	TODC_TYPE_MC146818_WATCHDOG		0x0c
+#define	TODC_TYPE_MC146818_INTERRUPTS		0x0d
+#define	TODC_TYPE_MC146818_ALARM_DATE		0xff
+#define	TODC_TYPE_MC146818_ALARM_HOUR		0x05
+#define	TODC_TYPE_MC146818_ALARM_MINUTES	0x03
+#define	TODC_TYPE_MC146818_ALARM_SECONDS	0x01
+#define	TODC_TYPE_MC146818_CENTURY		0xff
+#define	TODC_TYPE_MC146818_FLAGS		0xff
+#define	TODC_TYPE_MC146818_NVRAM_ADDR_REG	0
+#define	TODC_TYPE_MC146818_NVRAM_DATA_REG	0
+
+#define	TODC_TYPE_PC97307_NVRAM_SIZE		0	/* No NVRAM? */
+#define	TODC_TYPE_PC97307_SW_FLAGS		0
+#define	TODC_TYPE_PC97307_YEAR			0x09
+#define	TODC_TYPE_PC97307_MONTH			0x08
+#define	TODC_TYPE_PC97307_DOM			0x07	/* Day of Month */
+#define	TODC_TYPE_PC97307_DOW			0x06	/* Day of Week */
+#define	TODC_TYPE_PC97307_HOURS			0x04
+#define	TODC_TYPE_PC97307_MINUTES		0x02
+#define	TODC_TYPE_PC97307_SECONDS		0x00
+#define	TODC_TYPE_PC97307_CNTL_B		0x0a
+#define	TODC_TYPE_PC97307_CNTL_A		0x0b	/* control_a R/W regs */
+#define	TODC_TYPE_PC97307_WATCHDOG		0x0c
+#define	TODC_TYPE_PC97307_INTERRUPTS		0x0d
+#define	TODC_TYPE_PC97307_ALARM_DATE		0xff
+#define	TODC_TYPE_PC97307_ALARM_HOUR		0x05
+#define	TODC_TYPE_PC97307_ALARM_MINUTES		0x03
+#define	TODC_TYPE_PC97307_ALARM_SECONDS		0x01
+#define	TODC_TYPE_PC97307_CENTURY		0xff
+#define	TODC_TYPE_PC97307_FLAGS			0xff
+#define	TODC_TYPE_PC97307_NVRAM_ADDR_REG	0
+#define	TODC_TYPE_PC97307_NVRAM_DATA_REG	0
+
+/*
+ * Define macros to allocate and init the todc_info_t table that will
+ * be used by the todc_time.c routines.
+ */
+#define	TODC_ALLOC()							\
+	static todc_info_t todc_info_alloc;				\
+	todc_info_t *todc_info = &todc_info_alloc;
+
+#define	TODC_INIT(clock_type, as0, as1, data, bits) {			\
+	todc_info->rtc_type = clock_type;				\
+									\
+	todc_info->nvram_as0  = (unsigned char *)(as0);			\
+	todc_info->nvram_as1  = (unsigned char *)(as1);			\
+	todc_info->nvram_data = (unsigned char *)(data);		\
+									\
+	todc_info->as0_bits = (bits);					\
+									\
+	todc_info->nvram_size     = clock_type ##_NVRAM_SIZE;		\
+	todc_info->sw_flags       = clock_type ##_SW_FLAGS;		\
+									\
+	todc_info->year           = clock_type ##_YEAR;			\
+	todc_info->month          = clock_type ##_MONTH;		\
+	todc_info->day_of_month   = clock_type ##_DOM;			\
+	todc_info->day_of_week    = clock_type ##_DOW;			\
+	todc_info->hours          = clock_type ##_HOURS;		\
+	todc_info->minutes        = clock_type ##_MINUTES;		\
+	todc_info->seconds        = clock_type ##_SECONDS;		\
+	todc_info->control_b      = clock_type ##_CNTL_B;		\
+	todc_info->control_a      = clock_type ##_CNTL_A;		\
+	todc_info->watchdog       = clock_type ##_WATCHDOG;		\
+	todc_info->interrupts     = clock_type ##_INTERRUPTS;		\
+	todc_info->alarm_date     = clock_type ##_ALARM_DATE;		\
+	todc_info->alarm_hour     = clock_type ##_ALARM_HOUR;		\
+	todc_info->alarm_minutes  = clock_type ##_ALARM_MINUTES;	\
+	todc_info->alarm_seconds  = clock_type ##_ALARM_SECONDS;	\
+	todc_info->century        = clock_type ##_CENTURY;		\
+	todc_info->flags          = clock_type ##_FLAGS;		\
+									\
+	todc_info->nvram_addr_reg = clock_type ##_NVRAM_ADDR_REG;	\
+	todc_info->nvram_data_reg = clock_type ##_NVRAM_DATA_REG;	\
+}
+
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
+#endif
+
+extern todc_info_t *todc_info;
+
+unsigned char todc_direct_read_val(int addr);
+void todc_direct_write_val(int addr, unsigned char val);
+unsigned char todc_m48txx_read_val(int addr);
+void todc_m48txx_write_val(int addr, unsigned char val);
+unsigned char todc_mc146818_read_val(int addr);
+void todc_mc146818_write_val(int addr, unsigned char val);
+
+long todc_time_init(void);
+unsigned long todc_get_rtc_time(void);
+int todc_set_rtc_time(unsigned long nowtime);
+void todc_calibrate_decr(void);
+
+#endif				/* __PPC_KERNEL_TODC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/tqm8xx.h linux-2.4.20/include/asm-ppc/tqm8xx.h
--- linux-2.4.19/include/asm-ppc/tqm8xx.h	2001-09-08 19:39:33.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/tqm8xx.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,54 +0,0 @@
-/*
- * BK Id: SCCS/s.tqm8xx.h 1.8 08/30/01 09:01:04 trini
- */
-/*
- * TQM8xx(L) board specific definitions
- * 
- * Copyright (c) 1999,2000,2001 Wolfgang Denk (wd@denx.de)
- */
-
-#ifndef __MACH_TQM8xx_H
-#define __MACH_TQM8xx_H
-
-#include <linux/config.h>
- 
-#include <asm/ppcboot.h>
-
-#define	TQM_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR */
-#define	TQM_IMAP_SIZE	(64 * 1024)	/* size of mapped area */
-
-#define	IMAP_ADDR	TQM_IMMR_BASE	/* physical base address of IMMR area */
-#define IMAP_SIZE	TQM_IMAP_SIZE	/* mapped size of IMMR area */
-
-/*-----------------------------------------------------------------------
- * PCMCIA stuff
- *-----------------------------------------------------------------------
- *
- */
-#define PCMCIA_MEM_SIZE		( 64 << 20 )
-
-#define	MAX_HWIFS	1	/* overwrite default in include/asm-ppc/ide.h */
-
-/*
- * Definitions for IDE0 Interface
- */
-#define IDE0_BASE_OFFSET		0
-#define IDE0_DATA_REG_OFFSET		(PCMCIA_MEM_SIZE + 0x320)
-#define IDE0_ERROR_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 1)
-#define IDE0_NSECTOR_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 2)
-#define IDE0_SECTOR_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 3)
-#define IDE0_LCYL_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 4)
-#define IDE0_HCYL_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 5)
-#define IDE0_SELECT_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 6)
-#define IDE0_STATUS_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 7)
-#define IDE0_CONTROL_REG_OFFSET		0x0106
-#define IDE0_IRQ_REG_OFFSET		0x000A	/* not used */
-
-#define	IDE0_INTERRUPT			13
-
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS	0
-
-#endif	/* __MACH_TQM8xx_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/unistd.h linux-2.4.20/include/asm-ppc/unistd.h
--- linux-2.4.19/include/asm-ppc/unistd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/unistd.h	2002-10-29 11:18:34.000000000 +0000
@@ -216,6 +216,31 @@
 #define __NR_mincore		206
 #define __NR_gettid		207
 #define __NR_tkill		208
+#define __NR_setxattr		209
+#define __NR_lsetxattr		210
+#define __NR_fsetxattr		211
+#define __NR_getxattr		212
+#define __NR_lgetxattr		213
+#define __NR_fgetxattr		214
+#define __NR_listxattr		215
+#define __NR_llistxattr		216
+#define __NR_flistxattr		217
+#define __NR_removexattr	218
+#define __NR_lremovexattr	219
+#define __NR_fremovexattr	220
+#if 0
+#define __NR_futex		221
+#define __NR_sched_setaffinity	222
+#define __NR_sched_getaffinity	223
+#define __NR_security		224
+#define __NR_tuxcall		225
+#define __NR_sendfile64		226
+#define __NR_io_setup		227
+#define __NR_io_destroy		228
+#define __NR_io_getevents	229
+#define __NR_io_submit		230
+#define __NR_io_cancel		231
+#endif
 
 #define __NR(n)	#n
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc/xics.h linux-2.4.20/include/asm-ppc/xics.h
--- linux-2.4.19/include/asm-ppc/xics.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/xics.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,24 @@
+/*
+ * BK Id: SCCS/s.xics.h 1.5 05/17/01 18:14:22 cort
+ */
+/*
+ * arch/ppc/kernel/xics.h
+ *
+ * Copyright 2000 IBM Corporation.
+ *
+ *  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.
+ */
+
+#ifndef _PPC_KERNEL_XICS_H
+#define _PPC_KERNEL_XICS_H
+
+extern struct hw_interrupt_type xics_pic;
+extern struct hw_interrupt_type xics_8259_pic;
+
+void xics_init_IRQ(void);
+int xics_get_irq(struct pt_regs *);
+
+#endif /* _PPC_KERNEL_XICS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/byteorder.h linux-2.4.20/include/asm-ppc64/byteorder.h
--- linux-2.4.19/include/asm-ppc64/byteorder.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/byteorder.h	2002-10-29 11:18:31.000000000 +0000
@@ -2,8 +2,6 @@
 #define _PPC64_BYTEORDER_H
 
 /*
- *  
- *
  * 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
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/delay.h linux-2.4.20/include/asm-ppc64/delay.h
--- linux-2.4.19/include/asm-ppc64/delay.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/delay.h	2002-10-29 11:18:48.000000000 +0000
@@ -13,6 +13,7 @@
  * Anton Blanchard.
  */
 
+#ifndef __ASSEMBLY__
 extern unsigned long tb_ticks_per_usec;
 
 /* define these here to prevent circular dependencies */ 
@@ -42,5 +43,6 @@
 	__delay(loops);
 	__HMT_medium();
 }
+#endif /* !__ASSEMBLY__ */
 
 #endif /* _PPC64_DELAY_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/dump.h linux-2.4.20/include/asm-ppc64/dump.h
--- linux-2.4.19/include/asm-ppc64/dump.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/dump.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,112 @@
+/*
+ * Kernel header file for Linux crash dumps.
+ *
+ * Created by: Todd Inglett <tinglett@vnet.ibm.com>
+ *
+ * Copyright 2002 International Business Machines
+ *
+ * This code is released under version 2 of the GNU GPL.
+ */
+
+/* This header file holds the architecture specific crash dump header */
+#ifndef _ASM_DUMP_H
+#define _ASM_DUMP_H
+
+/* necessary header files */
+#include <asm/ptrace.h>                          /* for pt_regs             */
+#include <linux/threads.h>
+
+/* definitions */
+#define DUMP_ASM_MAGIC_NUMBER     0xdeaddeadULL  /* magic number            */
+#define DUMP_ASM_VERSION_NUMBER   0x1            /* version number          */
+
+
+/*
+ * Structure: dump_header_asm_t
+ *  Function: This is the header for architecture-specific stuff.  It
+ *            follows right after the dump header.
+ */
+typedef struct _dump_header_asm_s {
+
+        /* the dump magic number -- unique to verify dump is valid */
+        uint64_t             dha_magic_number;
+
+        /* the version number of this dump */
+        uint32_t             dha_version;
+
+        /* the size of this header (in case we can't read it) */
+        uint32_t             dha_header_size;
+
+	/* the dump registers */
+	struct pt_regs       dha_regs;
+
+	/* smp specific */
+	uint32_t	     dha_smp_num_cpus;
+	int		     dha_dumping_cpu;	
+	struct pt_regs	     dha_smp_regs[NR_CPUS];
+	void *		     dha_smp_current_task[NR_CPUS];
+	void *		     dha_stack[NR_CPUS];
+} dump_header_asm_t;
+
+#ifdef __KERNEL__
+static inline void get_current_regs(struct pt_regs *regs)
+{
+	__asm__ __volatile__ (
+		"std	0,0(%0)\n"
+		"std	1,8(%0)\n"
+		"std	2,16(%0)\n"
+		"std	3,24(%0)\n"
+		"std	4,32(%0)\n"
+		"std	5,40(%0)\n"
+		"std	6,48(%0)\n"
+		"std	7,56(%0)\n"
+		"std	8,64(%0)\n"
+		"std	9,72(%0)\n"
+		"std	10,80(%0)\n"
+		"std	11,88(%0)\n"
+		"std	12,96(%0)\n"
+		"std	13,104(%0)\n"
+		"std	14,112(%0)\n"
+		"std	15,120(%0)\n"
+		"std	16,128(%0)\n"
+		"std	17,136(%0)\n"
+		"std	18,144(%0)\n"
+		"std	19,152(%0)\n"
+		"std	20,160(%0)\n"
+		"std	21,168(%0)\n"
+		"std	22,176(%0)\n"
+		"std	23,184(%0)\n"
+		"std	24,192(%0)\n"
+		"std	25,200(%0)\n"
+		"std	26,208(%0)\n"
+		"std	27,216(%0)\n"
+		"std	28,224(%0)\n"
+		"std	29,232(%0)\n"
+		"std	30,240(%0)\n"
+		"std	31,248(%0)\n"
+		"mfmsr	0\n"
+		"std	0, 264(%0)\n"
+		"mfctr	0\n"
+		"std	0, 280(%0)\n"
+		"mflr	0\n"
+		"std	0, 288(%0)\n"
+		"bl	1f\n"
+	"1:	 mflr	5\n"
+		"std	5, 256(%0)\n"
+		"mtlr	0\n"
+		"mfxer	0\n"
+		"std	0, 296(%0)\n"
+			      : : "b" (&regs));
+}
+
+extern volatile int dump_in_progress;
+extern dump_header_asm_t dump_header_asm;
+
+#ifdef CONFIG_SMP
+extern void dump_send_ipi(int (*dump_ipi_callback)(struct pt_regs *));
+#else
+#define dump_send_ipi()
+#endif
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_DUMP_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/eeh.h linux-2.4.20/include/asm-ppc64/eeh.h
--- linux-2.4.19/include/asm-ppc64/eeh.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/eeh.h	2002-10-29 11:18:35.000000000 +0000
@@ -149,4 +149,38 @@
 	memcpy(vdest, src, n);
 }
 
+static inline void eeh_insb(volatile u8 *addr, void *buf, int n) {
+	volatile u8 *vaddr = (volatile u8 *)IO_TOKEN_TO_ADDR(addr);
+	_insb(vaddr, buf, n);
+	/* ToDo: look for ff's in buf[n] */
+}
+
+static inline void eeh_outsb(volatile u8 *addr, const void *buf, int n) {
+	volatile u8 *vaddr = (volatile u8 *)IO_TOKEN_TO_ADDR(addr);
+	_outsb(vaddr, buf, n);
+}
+
+static inline void eeh_insw_ns(volatile u16 *addr, void *buf, int n) {
+	volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
+	_insw_ns(vaddr, buf, n);
+	/* ToDo: look for ffff's in buf[n] */
+}
+
+static inline void eeh_outsw_ns(volatile u16 *addr, const void *buf, int n) {
+	volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
+	_outsw_ns(vaddr, buf, n);
+}
+
+static inline void eeh_insl_ns(volatile u32 *addr, void *buf, int n) {
+	volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
+	_insl_ns(vaddr, buf, n);
+	/* ToDo: look for ffffffff's in buf[n] */
+}
+
+static inline void eeh_outsl_ns(volatile u32 *addr, const void *buf, int n) {
+	volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
+	_outsl_ns(vaddr, buf, n);
+}
+
+
 #endif /* _EEH_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/fcntl.h linux-2.4.20/include/asm-ppc64/fcntl.h
--- linux-2.4.19/include/asm-ppc64/fcntl.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/fcntl.h	2002-10-29 11:18:31.000000000 +0000
@@ -26,7 +26,7 @@
 #define O_DIRECTORY      040000	/* must be a directory */
 #define O_NOFOLLOW      0100000	/* don't follow links */
 #define O_LARGEFILE     0200000
-#define O_DIRECT	0400000	/* direct disk access hint - currently ignored */
+#define O_DIRECT	0400000	/* direct disk access hint */
 
 #define F_DUPFD		0	/* dup */
 #define F_GETFD		1	/* get close_on_exec */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/floppy.h linux-2.4.20/include/asm-ppc64/floppy.h
--- linux-2.4.19/include/asm-ppc64/floppy.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/floppy.h	2002-10-29 11:18:34.000000000 +0000
@@ -76,11 +76,6 @@
 
 #endif /* CONFIG_PCI */
 
-__inline__ void virtual_dma_init(void)
-{
-	/* Nothing to do on PowerPC */
-}
-
 static int FDC1 = 0x3f0;
 static int FDC2 = -1;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/hvcall.h linux-2.4.20/include/asm-ppc64/hvcall.h
--- linux-2.4.19/include/asm-ppc64/hvcall.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/hvcall.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,85 @@
+
+#define H_Success	0
+#define H_Busy		1	/* Hardware busy -- retry later */
+#define H_Hardware	-1	/* Hardware error */
+#define H_Function	-2	/* Function not supported */
+#define H_Privilege	-3	/* Caller not privileged */
+#define H_Parameter	-4	/* Parameter invalid, out-of-range or conflicting */
+#define H_Bad_Mode	-5	/* Illegal msr value */
+#define H_PTEG_Full	-6	/* PTEG is full */
+#define H_Not_Found	-7	/* PTE was not found" */
+#define H_Reserved_DABR	-8	/* DABR address is reserved by the hypervisor on this processor" */
+
+/* Flags */
+#define H_LARGE_PAGE		(1UL<<(63-16))
+#define H_EXACT		    (1UL<<(63-24))	/* Use exact PTE or return H_PTEG_FULL */
+#define H_R_XLATE		(1UL<<(63-25))	/* include a valid logical page num in the pte if the valid bit is set */
+#define H_READ_4		(1UL<<(63-26))	/* Return 4 PTEs */
+#define H_AVPN			(1UL<<(63-32))	/* An avpn is provided as a sanity test */
+#define H_ANDCOND		(1UL<<(63-33))
+#define H_ICACHE_INVALIDATE	(1UL<<(63-40))	/* icbi, etc.  (ignored for IO pages) */
+#define H_ICACHE_SYNCHRONIZE	(1UL<<(63-41))	/* dcbst, icbi, etc (ignored for IO pages */
+#define H_ZERO_PAGE		(1UL<<(63-48))	/* zero the page before mapping (ignored for IO pages) */
+#define H_COPY_PAGE		(1UL<<(63-49))
+#define H_N			(1UL<<(63-61))
+#define H_PP1			(1UL<<(63-62))
+#define H_PP2			(1UL<<(63-63))
+
+
+
+/* pSeries hypervisor opcodes */
+#define H_REMOVE		0x04
+#define H_ENTER			0x08
+#define H_READ			0x0c
+#define H_CLEAR_MOD		0x10
+#define H_CLEAR_REF		0x14
+#define H_PROTECT		0x18
+#define H_GET_TCE		0x1c
+#define H_PUT_TCE		0x20
+#define H_SET_SPRG0		0x24
+#define H_SET_DABR		0x28
+#define H_PAGE_INIT		0x2c
+#define H_SET_ASR		0x30
+#define H_ASR_ON		0x34
+#define H_ASR_OFF		0x38
+#define H_LOGICAL_CI_LOAD	0x3c
+#define H_LOGICAL_CI_STORE	0x40
+#define H_LOGICAL_CACHE_LOAD	0x44
+#define H_LOGICAL_CACHE_STORE	0x48
+#define H_LOGICAL_ICBI		0x4c
+#define H_LOGICAL_DCBF		0x50
+#define H_GET_TERM_CHAR		0x54
+#define H_PUT_TERM_CHAR		0x58
+#define H_REAL_TO_LOGICAL	0x5c
+#define H_HYPERVISOR_DATA	0x60
+#define H_EOI			0x64
+#define H_CPPR			0x68
+#define H_IPI			0x6c
+#define H_IPOLL			0x70
+#define H_XIRR			0x74
+
+#define HSC			".long 0x44000022\n"
+#define H_ENTER_r3		"li	3, 0x08\n"
+
+/* plpar_hcall() -- Generic call interface using above opcodes
+ *
+ * The actual call interface is a hypervisor call instruction with
+ * the opcode in R3 and input args in R4-R7.
+ * Status is returned in R3 with variable output values in R4-R11.
+ * Only H_PTE_READ with H_READ_4 uses R6-R11 so we ignore it for now
+ * and return only two out args which MUST ALWAYS BE PROVIDED.
+ */
+long plpar_hcall(unsigned long opcode,
+		 unsigned long arg1,
+		 unsigned long arg2,
+		 unsigned long arg3,
+		 unsigned long arg4,
+		 unsigned long *out1,
+		 unsigned long *out2,
+		 unsigned long *out3);
+
+/* Same as plpar_hcall but for those opcodes that return no values
+ * other than status.  Slightly more efficient.
+ */
+long plpar_hcall_norets(unsigned long opcode, ...);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/iSeries/HvCall.h linux-2.4.20/include/asm-ppc64/iSeries/HvCall.h
--- linux-2.4.19/include/asm-ppc64/iSeries/HvCall.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/iSeries/HvCall.h	2002-10-29 11:18:40.000000000 +0000
@@ -130,6 +130,9 @@
 #define HvCallBaseRouter28				HvCallBase + 28
 #define HvCallBaseRouter29				HvCallBase + 29
 #define HvCallBaseRouter30				HvCallBase + 30
+
+#define HvCallCcSetDABR  				HvCallCc + 7
+
 //=====================================================================================
 static inline void		HvCall_setVirtualDecr(void)
 {
@@ -197,6 +200,10 @@
 	HvCall0( HvCallBaseTerminateMachineSrc );
 }
 
+static inline void HvCall_setDABR(unsigned long val)
+{
+	HvCall1(HvCallCcSetDABR, val);
+}
 
 #endif // _HVCALL_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/iSeries/HvCallSc.h linux-2.4.20/include/asm-ppc64/iSeries/HvCallSc.h
--- linux-2.4.19/include/asm-ppc64/iSeries/HvCallSc.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/iSeries/HvCallSc.h	2002-10-29 11:18:40.000000000 +0000
@@ -25,6 +25,7 @@
 #define _HVCALLSC_H
 
 #define HvCallBase		0x8000000000000000
+#define HvCallCc		0x8001000000000000
 #define HvCallCfg		0x8002000000000000
 #define HvCallEvent		0x8003000000000000
 #define HvCallHpt		0x8004000000000000
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/iSeries/ItExtVpdPanel.h linux-2.4.20/include/asm-ppc64/iSeries/ItExtVpdPanel.h
--- linux-2.4.19/include/asm-ppc64/iSeries/ItExtVpdPanel.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/iSeries/ItExtVpdPanel.h	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,60 @@
+/*
+ * ItExtVpdPanel.h
+ * Copyright (C) 2002  Dave Boutcher IBM Corporation
+ * 
+ * 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 struct maps the panel information 
+ *
+ * Warning:
+ *	This data must match the architecture for the panel information
+ *
+ */
+
+
+/*-------------------------------------------------------------------
+ * Standard Includes
+ *------------------------------------------------------------------- 
+*/
+#ifndef	_PPC_TYPES_H
+#include	<asm/types.h>
+#endif
+
+#ifndef _ITEXTVPDPANEL_H
+#define _ITEXTVPDPANEL_H
+struct ItExtVpdPanel
+{
+  // Definition of the Extended Vpd On Panel Data Area
+  char                      systemSerial[8];
+  char                      mfgID[4];
+  char                      reserved1[24];
+  char                      machineType[4];
+  char                      systemID[6];
+  char                      somUniqueCnt[4];
+  char                      serialNumberCount;
+  char                      reserved2[7];
+  u16                       bbu3;
+  u16                       bbu2;
+  u16                       bbu1;
+  char                      xLocationLabel[8];
+  u8                        xRsvd1[6];
+  u16                       xFrameId;
+  u8                        xRsvd2[48];
+};
+
+#endif /* _ITEXTVPDPANEL_H  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/iSeries/LparData.h linux-2.4.20/include/asm-ppc64/iSeries/LparData.h
--- linux-2.4.19/include/asm-ppc64/iSeries/LparData.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/iSeries/LparData.h	2002-10-29 11:18:50.000000000 +0000
@@ -37,6 +37,7 @@
 #include <asm/iSeries/LparMap.h>
 #include <asm/iSeries/ItVpdAreas.h>
 #include <asm/iSeries/ItIplParmsReal.h>
+#include <asm/iSeries/ItExtVpdPanel.h>
 #include <asm/iSeries/ItLpQueue.h>
 #include <asm/iSeries/IoHriProcessorVpd.h>
 #include <asm/page.h>
@@ -45,6 +46,7 @@
 extern struct HvReleaseData hvReleaseData;
 extern struct ItLpNaca	itLpNaca;
 extern struct ItIplParmsReal xItIplParmsReal;
+extern struct ItExtVpdPanel xItExtVpdPanel;
 extern struct IoHriProcessorVpd xIoHriProcessorVpd[];
 extern struct ItLpQueue xItLpQueue;
 extern struct ItVpdAreas itVpdAreas;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/iSeries/iSeries_pci.h linux-2.4.20/include/asm-ppc64/iSeries/iSeries_pci.h
--- linux-2.4.19/include/asm-ppc64/iSeries/iSeries_pci.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/iSeries/iSeries_pci.h	2002-10-29 11:18:48.000000000 +0000
@@ -89,7 +89,8 @@
 	int              Flags;          /* Possible flags(disable/bist)*/
 	u16              Vendor;         /* Vendor ID                   */
 	u8               LogicalSlot;    /* Hv Slot Index for Tces      */
-	struct TceTable* DevTceTable;    /* Device TCE Table            */ 
+	struct TceTable* DevTceTable;    /* Device TCE Table            */
+	spinlock_t       IoLock;	 /* Lock to single thread device*/
 	u8               PhbId;          /* Phb Card is on.             */
 	u16              Board;          /* Board Number                */
 	u8               FrameId;	 /* iSeries spcn Frame Id       */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/io.h linux-2.4.20/include/asm-ppc64/io.h
--- linux-2.4.19/include/asm-ppc64/io.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/io.h	2002-10-29 11:18:48.000000000 +0000
@@ -40,7 +40,7 @@
 #define writeb(data, addr)	iSeries_Write_Byte(data,((void*)(addr)))
 #define writew(data, addr)	iSeries_Write_Word(data,((void*)(addr)))
 #define writel(data, addr)	iSeries_Write_Long(data,((void*)(addr)))
-#define memset_io(a,b,c)	iSeries_memset((void *)(a),(b),(c))
+#define memset_io(a,b,c)	iSeries_memset_io((void *)(a),(b),(c))
 #define memcpy_fromio(a,b,c)	iSeries_memcpy_fromio((void *)(a), (void *)(b), (c))
 #define memcpy_toio(a,b,c)	iSeries_memcpy_toio((void *)(a), (void *)(b), (c))
 #define inb(addr)		readb(((unsigned long)(addr)))  
@@ -57,7 +57,7 @@
 #define writeb(data, addr)	eeh_writeb((data), ((void*)(addr)))
 #define writew(data, addr)	eeh_writew((data), ((void*)(addr)))
 #define writel(data, addr)	eeh_writel((data), ((void*)(addr)))
-#define memset_io(a,b,c)	eeh_memset((void *)(a),(b),(c))
+#define memset_io(a,b,c)	eeh_memset_io((void *)(a),(b),(c))
 #define memcpy_fromio(a,b,c)	eeh_memcpy_fromio((a),(void *)(b),(c))
 #define memcpy_toio(a,b,c)	eeh_memcpy_toio((void *)(a),(b),(c))
 #define inb(port)		_inb((unsigned long)port)
@@ -66,6 +66,18 @@
 #define outw(val, port)		_outw(val, (unsigned long)port)
 #define inl(port)		_inl((unsigned long)port)
 #define outl(val, port)		_outl(val, (unsigned long)port)
+
+/*
+ * The insw/outsw/insl/outsl macros don't do byte-swapping.
+ * They are only used in practice for transferring buffers which
+ * are arrays of bytes, and byte-swapping is not appropriate in
+ * that case.  - paulus */
+#define insb(port, buf, ns)	eeh_insb((u8 *)(port), (buf), (ns))
+#define outsb(port, buf, ns)	eeh_outsb((u8 *)(port), (buf), (ns))
+#define insw(port, buf, ns)	eeh_insw_ns((u16 *)(port), (buf), (ns))
+#define outsw(port, buf, ns)	eeh_outsw_ns((u16 *)(port), (buf), (ns))
+#define insl(port, buf, nl)	eeh_insl_ns((u32 *)(port), (buf), (nl))
+#define outsl(port, buf, nl)	eeh_outsl_ns((u32 *)(port), (buf), (nl))
 #endif
 
 
@@ -80,18 +92,6 @@
 #define inl_p(port)             inl(port)
 #define outl_p(val, port)       (udelay(1), outl((val, (port)))
 
-/*
- * The insw/outsw/insl/outsl macros don't do byte-swapping.
- * They are only used in practice for transferring buffers which
- * are arrays of bytes, and byte-swapping is not appropriate in
- * that case.  - paulus */
-#define _IOMAP_VADDR(port) (IS_MAPPED_VADDR(port) ? (port) : (port)+_IO_BASE)
-#define insb(port, buf, ns)	_insb((u8 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define outsb(port, buf, ns)	_outsb((u8 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define insw(port, buf, ns)	_insw_ns((u16 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define outsw(port, buf, ns)	_outsw_ns((u16 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define insl(port, buf, nl)	_insl_ns((u32 *)(_IOMAP_VADDR(port)), (buf), (nl))
-#define outsl(port, buf, nl)	_outsl_ns((u32 *)(_IOMAP_VADDR(port)), (buf), (nl))
 
 extern void _insb(volatile u8 *port, void *buf, int ns);
 extern void _outsb(volatile u8 *port, const void *buf, int ns);
@@ -109,10 +109,10 @@
  * Neither do the standard versions now, these are just here
  * for older code.
  */
-#define insw_ns(port, buf, ns)	_insw_ns((u16 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define outsw_ns(port, buf, ns)	_outsw_ns((u16 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define insl_ns(port, buf, nl)	_insl_ns((u32 *)(_IOMAP_VADDR(port)), (buf), (nl))
-#define outsl_ns(port, buf, nl)	_outsl_ns((u32 *)(_IOMAP_VADDR(port)), (buf), (nl))
+#define insw_ns(port, buf, ns)	insw(port, buf, ns)
+#define outsw_ns(port, buf, ns)	outsw(port, buf, ns)
+#define insl_ns(port, buf, nl)	insl(port, buf, nl)
+#define outsl_ns(port, buf, nl)	outsl(port, buf, nl)
 
 
 #define IO_SPACE_LIMIT ~(0UL)
@@ -134,7 +134,7 @@
  * Change virtual addresses to physical addresses and vv, for
  * addresses in the area where the kernel has the RAM mapped.
  */
-extern inline unsigned long virt_to_phys(volatile void * address)
+static inline unsigned long virt_to_phys(volatile void * address)
 {
 #ifdef __IO_DEBUG
 	printk("virt_to_phys: 0x%08lx -> 0x%08lx\n", 
@@ -144,17 +144,22 @@
 	return __pa((unsigned long)address);
 }
 
-extern inline void * phys_to_virt(unsigned long address)
+static inline void * phys_to_virt(unsigned long address)
 {
 #ifdef __IO_DEBUG
 	printk("phys_to_virt: 0x%08lx -> 0x%08lx\n", address, __va(address));
 #endif
 	return (void *) __va(address);
 }
+ 
+/*
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
 
 #endif /* __KERNEL__ */
 
-extern inline void iosync(void)
+static inline void iosync(void)
 {
         __asm__ __volatile__ ("sync" : : : "memory");
 }
@@ -172,7 +177,7 @@
  * excess of syncs before the MMIO operations will make things work.  On 
  * sstar, sync time is << than mmio time, so this should not be a big impact.
  */
-extern inline int in_8(volatile unsigned char *addr)
+static inline int in_8(volatile unsigned char *addr)
 {
 	int ret;
 
@@ -180,12 +185,12 @@
 	return ret;
 }
 
-extern inline void out_8(volatile unsigned char *addr, int val)
+static inline void out_8(volatile unsigned char *addr, int val)
 {
 	__asm__ __volatile__("sync; stb%U0%X0 %1,%0; sync" : "=m" (*addr) : "r" (val));
 }
 
-extern inline int in_le16(volatile unsigned short *addr)
+static inline int in_le16(volatile unsigned short *addr)
 {
 	int ret;
 
@@ -194,7 +199,7 @@
 	return ret;
 }
 
-extern inline int in_be16(volatile unsigned short *addr)
+static inline int in_be16(volatile unsigned short *addr)
 {
 	int ret;
 
@@ -202,18 +207,18 @@
 	return ret;
 }
 
-extern inline void out_le16(volatile unsigned short *addr, int val)
+static inline void out_le16(volatile unsigned short *addr, int val)
 {
 	__asm__ __volatile__("sync; sthbrx %1,0,%2; sync" : "=m" (*addr) :
 			      "r" (val), "r" (addr));
 }
 
-extern inline void out_be16(volatile unsigned short *addr, int val)
+static inline void out_be16(volatile unsigned short *addr, int val)
 {
 	__asm__ __volatile__("sync; sth%U0%X0 %1,%0; sync" : "=m" (*addr) : "r" (val));
 }
 
-extern inline unsigned in_le32(volatile unsigned *addr)
+static inline unsigned in_le32(volatile unsigned *addr)
 {
 	unsigned ret;
 
@@ -222,7 +227,7 @@
 	return ret;
 }
 
-extern inline unsigned in_be32(volatile unsigned *addr)
+static inline unsigned in_be32(volatile unsigned *addr)
 {
 	unsigned ret;
 
@@ -230,13 +235,13 @@
 	return ret;
 }
 
-extern inline void out_le32(volatile unsigned *addr, int val)
+static inline void out_le32(volatile unsigned *addr, int val)
 {
 	__asm__ __volatile__("sync; stwbrx %1,0,%2; sync" : "=m" (*addr) :
 			     "r" (val), "r" (addr));
 }
 
-extern inline void out_be32(volatile unsigned *addr, int val)
+static inline void out_be32(volatile unsigned *addr, int val)
 {
 	__asm__ __volatile__("sync; stw%U0%X0 %1,%0; sync" : "=m" (*addr) : "r" (val));
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/lmb.h linux-2.4.20/include/asm-ppc64/lmb.h
--- linux-2.4.19/include/asm-ppc64/lmb.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/lmb.h	2002-10-29 11:18:49.000000000 +0000
@@ -27,6 +27,9 @@
 #define LMB_MEMORY_AREA	1
 #define LMB_IO_AREA	2
 
+#define LMB_ALLOC_ANYWHERE	0
+#define LMB_ALLOC_FIRST4GBYTE	(1UL<<32)
+
 struct lmb_property {
 	unsigned long base;
 	unsigned long physbase;
@@ -44,6 +47,7 @@
 
 struct lmb {
 	unsigned long debug;
+	unsigned long rmo_size;
 	struct lmb_region memory;
 	struct lmb_region reserved;
 };
@@ -58,6 +62,7 @@
 #endif /* CONFIG_MSCHUNKS */
 extern long lmb_reserve(unsigned long, unsigned long);
 extern unsigned long lmb_alloc(unsigned long, unsigned long);
+extern unsigned long lmb_alloc_base(unsigned long, unsigned long, unsigned long);
 extern unsigned long lmb_phys_mem_size(void);
 extern unsigned long lmb_end_of_DRAM(void);
 extern unsigned long lmb_abs_to_phys(unsigned long);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/machdep.h linux-2.4.20/include/asm-ppc64/machdep.h
--- linux-2.4.19/include/asm-ppc64/machdep.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/machdep.h	2002-10-29 11:18:33.000000000 +0000
@@ -10,7 +10,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/seq_file.h>
 
 struct pt_regs;
 struct pci_bus;	
@@ -21,29 +20,24 @@
 struct rtc_time;
 
 struct machdep_calls {
-	/* High use functions in the first cachelines, low use functions
-	 * follow.  DRENG collect profile data.
-	 */
-	void            (*hpte_invalidate)(unsigned long slot);
-
-	void            (*hpte_updatepp)(long slot, 
+	void            (*hpte_invalidate)(unsigned long slot,
+					   unsigned long secondary,  
+					   unsigned long va, 
+					   int large, int local);
+	long            (*hpte_updatepp)(unsigned long slot,
+					 unsigned long secondary,  
 					 unsigned long newpp, 
-					 unsigned long va);
+					 unsigned long va,
+					 int large);
 	void            (*hpte_updateboltedpp)(unsigned long newpp, 
 					       unsigned long ea);
-	unsigned long	(*hpte_getword0)(unsigned long slot);
-
-	long		(*hpte_find)( unsigned long vpn );
-
-	long		(*hpte_selectslot)(unsigned long vpn); 
-
-	void		(*hpte_create_valid)(unsigned long slot,
-					     unsigned long vpn,
-					     unsigned long prpn,
-					     unsigned hash, 
-					     void * ptep,
-					     unsigned hpteflags, 
-					     unsigned bolted);
+	long		(*hpte_insert)(unsigned long vpn,
+				       unsigned long prpn,
+				       unsigned long hpteflags, 
+				       int bolted,
+				       int large);
+	long		(*hpte_remove)(unsigned long hpte_group);
+	
 	void		(*tce_build)(struct TceTable * tbl,
 				     long tcenum,
 				     unsigned long uaddr,
@@ -69,7 +63,6 @@
 	void		(*init_IRQ)(void);
 	void		(*init_ras_IRQ)(void);
 	int		(*get_irq)(struct pt_regs *);
-	void		(*post_irq)( struct pt_regs *, int );
 	
 	/* A general init function, called by ppc_init in init/main.c.
 	   May be NULL. */
@@ -87,6 +80,7 @@
 
   	void		(*progress)(char *, unsigned short);
 
+
 	unsigned char 	(*nvram_read_val)(int addr);
 	void		(*nvram_write_val)(int addr, unsigned char val);
 
@@ -146,5 +140,22 @@
 
 extern void setup_pci_ptrs(void);
 
+
+/* Functions to produce codes on the leds.
+ * The SRC code should be unique for the message category and should
+ * be limited to the lower 24 bits (the upper 8 are set by these funcs),
+ * and (for boot & dump) should be sorted numerically in the order
+ * the events occur.
+ */
+/* Print a boot progress message. */
+void ppc64_boot_msg(unsigned int src, const char *msg);
+/* Print a termination message (print only -- does not stop the kernel) */
+void ppc64_terminate_msg(unsigned int src, const char *msg);
+/* Print something that needs attention (device error, etc) */
+void ppc64_attention_msg(unsigned int src, const char *msg);
+/* Print a dump progress message. */
+void ppc64_dump_msg(unsigned int src, const char *msg);
+
+
 #endif /* _PPC_MACHDEP_H */
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/mmu.h linux-2.4.20/include/asm-ppc64/mmu.h
--- linux-2.4.19/include/asm-ppc64/mmu.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/mmu.h	2002-10-29 11:18:37.000000000 +0000
@@ -107,7 +107,7 @@
 	unsigned long avpn:57; /* vsid | api == avpn  */
 	unsigned long :     2; /* Software use */
 	unsigned long bolted: 1; /* HPTE is "bolted" */
-	unsigned long :     1; /* Software use */
+	unsigned long lock: 1; /* lock on pSeries SMP */
 	unsigned long l:    1; /* Virtual page is large (L=1) or 4 KB (L=0) */
 	unsigned long h:    1; /* Hash function identifier */
 	unsigned long v:    1; /* Valid (v=1) or invalid (v=0) */
@@ -128,7 +128,7 @@
 
 typedef struct {
 	unsigned long pp0:  1; /* Page protection bit 0 */
-	unsigned long :     1; /* Reserved */
+	unsigned long ts:   1; /* Tag set bit */
 	unsigned long rpn: 50; /* Real page number */
 	unsigned long :     2; /* Reserved */
 	unsigned long ac:   1; /* Address compare */ 
@@ -156,21 +156,8 @@
 
 	union {
 		unsigned long dword1;
-		struct {
-			unsigned long pp0:  1; /* Page protection bit 0 */
-			unsigned long ts:   1; /* Tag set bit */ 
-			unsigned long rpn: 50; /* Real page number */
-			unsigned long :     2; /* Unused */
-			unsigned long ac:   1; /* Address compare bit */
-			unsigned long r:    1; /* Referenced */
-			unsigned long c:    1; /* Changed */
-			unsigned long w:    1; /* Write-thru cache mode */
-			unsigned long i:    1; /* Cache inhibited */
-			unsigned long m:    1; /* Memory coherence */
-			unsigned long g:    1; /* Guarded */
-			unsigned long n:    1; /* No-execute page if N=1 */
-			unsigned long pp:   2; /* Page protection bit 1:2 */
-		} dw1;
+		Hpte_dword1 dw1;
+		Hpte_dword1_flags flags;
 	} dw1;
 } HPTE; 
 
@@ -204,6 +191,8 @@
 #define PT_SHIFT (12)			/* Page Table */
 #define PT_MASK  0x02FF
 
+#define LARGE_PAGE_SHIFT 24
+
 static inline unsigned long hpt_hash(unsigned long vpn, int large)
 {
 	unsigned long vsid;
@@ -222,16 +211,24 @@
 
 #define PG_SHIFT (12)			/* Page Entry */
 
-extern __inline__ void _tlbie( unsigned long va )
+/*
+ * Invalidate a TLB entry.  Assumes a context syncronizing 
+ * instruction preceeded this call (for example taking the
+ * TLB lock).
+ */
+static inline void _tlbie(unsigned long va, int large)
 {
-	__asm__ __volatile__ ( " \n\
-		clrldi	%0,%0,16 \n\
-		ptesync		 \n\
-		tlbie	%0	 \n\
-		eieio		 \n\
-		tlbsync		 \n\
-		ptesync"
-		: : "r" (va) : "memory" );
+	asm volatile("ptesync": : :"memory");
+
+	if (large) {
+		asm volatile("clrldi	%0,%0,16\n\
+			      tlbie	%0,1" : : "r"(va) : "memory");
+	} else {
+		asm volatile("clrldi	%0,%0,16\n\
+			      tlbie	%0,0" : : "r"(va) : "memory");
+	}
+
+	asm volatile("eieio; tlbsync; ptesync": : :"memory");
 }
  
 #endif /* __ASSEMBLY__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/naca.h linux-2.4.20/include/asm-ppc64/naca.h
--- linux-2.4.19/include/asm-ppc64/naca.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/naca.h	2002-10-29 11:18:32.000000000 +0000
@@ -13,28 +13,63 @@
 #include <asm/types.h>
 
 struct naca_struct {
-	void *xItVpdAreas;
-	void *xRamDisk;
-	u64 xRamDiskSize;		/* In pages */
-	struct paca_struct *paca;	/* Ptr to an array of pacas */
-	u64 debug_switch;		/* Bits to control debug printing */
-	u16 processorCount;		/* # of physical processors */
-	u16 dCacheL1LineSize;		/* Line size of L1 DCache in bytes */
-	u16 dCacheL1LogLineSize;	/* Log-2 of DCache line size */
-	u16 dCacheL1LinesPerPage;	/* DCache lines per page */
-	u16 iCacheL1LineSize;		/* Line size of L1 ICache in bytes */
-	u16 iCacheL1LogLineSize;	/* Log-2 of ICache line size */
-	u16 iCacheL1LinesPerPage;	/* ICache lines per page */
-	u16 slb_size;			/* SLB size in entries */
-	u64 physicalMemorySize;		/* Size of real memory in bytes */
-	u64 pftSize;			/* Log base 2 of page table size */
-	u64 serialPortAddr;		/* Phyical address of serial port */
-	u8 interrupt_controller;	/* Type of interrupt controller */ 
-	u8 resv0;    			/* Type of interrupt controller */
-	u16 platform;			/* Platform flags */
-	u8 resv1[12];			/* Padding */
+	/*==================================================================
+	 * Cache line 1: 0x0000 - 0x007F
+	 * Kernel only data - undefined for user space
+	 *==================================================================
+	 */
+	void *xItVpdAreas;              /* VPD Data                  0x00 */
+	void *xRamDisk;                 /* iSeries ramdisk           0x08 */
+	u64   xRamDiskSize;		/* In pages                  0x10 */
+	struct paca_struct *paca;	/* Ptr to an array of pacas  0x18 */
+	u64 debug_switch;		/* Debug print control       0x20 */
+	u64 banner;                     /* Ptr to banner string      0x28 */
+	u64 log;                        /* Ptr to log buffer         0x30 */
+	u64 serialPortAddr;		/* Phy addr of serial port   0x38 */
+	u64 interrupt_controller;	/* Type of int controller    0x40 */ 
+	u64 slb_size;			/* SLB size in entries       0x48 */
+	u64 pftSize;			/* Log 2 of page table size  0x50 */
+	u64 resv0[5];                   /* Reserved           0x58 - 0x7F */
+
+	/*==================================================================
+	 * Cache line 2: 0x0080 - 0x00FF
+	 * Kernel / User data
+	 *==================================================================
+	 */
+	u8  eye_catcher[6];             /* Eyecatcher: PPC64         0x00 */
+	u16 version;                    /* Version number            0x06 */
+	u16 platform;			/* Platform flags            0x08 */
+	u16 processor;			/* Processor type            0x0A */
+	u32 processorCount;		/* # of physical processors  0x0C */
+	u64 physicalMemorySize;		/* Size of real memory(B)    0x10 */
+
+	u16 dCacheL1Size;	        /* L1 d-cache size           0x18 */
+	u16 dCacheL1LineSize;		/* L1 d-cache line size      0x1A */
+	u16 dCacheL1LogLineSize;	/* L1 d-cache line size Log2 0x1C */
+	u16 dCacheL1LinesPerPage;	/* L1 d-cache lines / page   0x1E */
+	u16 dCacheL1Assoc;              /* L1 d-cache associativity  0x20 */
+
+	u16 iCacheL1Size;	        /* L1 i-cache size           0x22 */
+	u16 iCacheL1LineSize;		/* L1 i-cache line size      0x24 */
+	u16 iCacheL1LogLineSize;	/* L1 i-cache line size Log2 0x26 */
+	u16 iCacheL1LinesPerPage;	/* L1 i-cache lines / page   0x28 */
+	u16 iCacheL1Assoc;              /* L1 i-cache associativity  0x2A */
+
+	u16 cacheL2Size;	        /* L2 cache size             0x2C */
+	u16 cacheL2Assoc;	        /* L2 cache associativity    0x2E */
+
+	u64 tb_orig_stamp;              /* Timebase at boot          0x30 */
+	u64 tb_ticks_per_sec;           /* Timebase tics / sec       0x38 */
+	u64 tb_to_xs;                   /* Inverse of TB to 2^20     0x40 */
+	u64 stamp_xsec;                 /*                           0x48 */
+	volatile u64 tb_update_count;   /* Timebase atomicity ctr    0x50 */
+	u32 tz_minuteswest;             /* Minutes west of Greenwich 0x58 */
+	u32 tz_dsttime;                 /* Type of dst correction    0x5C */
+
+	u64 resv1[4];                   /* Reserverd          0x60 - 0x7F */
 };
 
+
 extern struct naca_struct *naca;
 
 #endif /* _NACA_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/paca.h linux-2.4.20/include/asm-ppc64/paca.h
--- linux-2.4.19/include/asm-ppc64/paca.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/paca.h	2002-10-29 11:18:49.000000000 +0000
@@ -84,8 +84,7 @@
 	u8 xSegments[STAB_CACHE_SIZE];	/* Cache of used stab entries		0x68,0x70 */
 	u8 xProcEnabled;		/* 1=soft enabled			0x78 */
 	u8 xHrdIntCount;		/* Count of active hardware interrupts  0x79  */
-	u8 prof_enabled;		/* 1=iSeries profiling enabled          0x7A */
-	u8 resv1[5];			/*					0x7B-0x7F */
+	u8 resv1[6];			/*					0x7B-0x7F */
 
 /*=====================================================================================
  * CACHE_LINE_2 0x0080 - 0x00FF
@@ -97,13 +96,7 @@
 	u64 pgtable_cache_sz;		/*					0x18 */
 	u64 next_jiffy_update_tb;	/* TB value for next jiffy update	0x20 */
 	u32 lpEvent_count;		/* lpEvents processed			0x28 */
-	u32 prof_multiplier;		/*					0x2C */
-	u32 prof_counter;		/*					0x30 */
-	u32 prof_shift;			/* iSeries shift for profile bucket size0x34 */
-	u32 *prof_buffer;		/* iSeries profiling buffer		0x38 */
-	u32 *prof_stext;		/* iSeries start of kernel text		0x40 */
-	u32 prof_len;			/* iSeries length of profile buffer -1	0x48 */
-	u8  rsvd2[128-76];		/*					0x4C */
+	u8  rsvd2[128-5*8-1*4];		/*					0x68 */
 
 /*=====================================================================================
  * CACHE_LINE_3 0x0100 - 0x017F
@@ -135,10 +128,29 @@
 	u8 rsvd5[256-16-sizeof(struct rtas_args)];
 
 /*=====================================================================================
- * CACHE_LINE_19-30 0x0800 - 0x0EFF Reserved
+ * CACHE_LINE_19 - 20 Profile Data
  *=====================================================================================
  */
-	u8 rsvd6[0x600];
+	u32 pmc[12];                    /* Default pmc value		*/	
+	u64 pmcc[8];                    /* Cumulative pmc counts        */
+	u64 rsvd5a[2];
+
+	u32 prof_multiplier;		/*					 */
+	u32 prof_shift;			/* iSeries shift for profile bucket size */
+	u32 *prof_buffer;		/* iSeries profiling buffer		 */
+	u32 *prof_stext;		/* iSeries start of kernel text		 */
+	u32 *prof_etext;		/* iSeries start of kernel text		 */
+	u32 prof_len;			/* iSeries length of profile buffer -1	 */
+	u8  prof_mode;                  /* */
+	u8  rsvv5b[3];
+	u64 prof_counter;		/*					 */
+	u8  rsvd5c[128-8*6];
+
+/*=====================================================================================
+ * CACHE_LINE_20-30
+ *=====================================================================================
+ */
+	u8 rsvd6[0x500];
 
 /*=====================================================================================
  * CACHE_LINE_31 0x0F00 - 0x0F7F Exception stack
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/page.h linux-2.4.20/include/asm-ppc64/page.h
--- linux-2.4.19/include/asm-ppc64/page.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/page.h	2002-10-29 11:18:48.000000000 +0000
@@ -123,6 +123,14 @@
 	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
 	xmon(0); \
 } while (0)
+#elif defined(CONFIG_KDB)
+#include <asm/ptrace.h>
+#include <linux/kdb.h>
+/* extern void kdb(kdb_reason_t reason, int error, kdb_eframe_t ef); */
+#define BUG() do { \
+      printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+      kdb(KDB_REASON_OOPS, 0, (kdb_eframe_t) 0); \
+} while (0)
 #else
 #define BUG() do { \
 	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
@@ -132,15 +140,8 @@
 
 #define PAGE_BUG(page) do { BUG(); } while (0)
 
-/*
- * XXX A bug in the current ppc64 compiler prevents an optimisation
- * where a divide is replaced by a multiply by shifted inverse. For
- * the moment use page->virtaul
- */
-#define WANT_PAGE_VIRTUAL 1
-
 /* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
+static inline int get_order(unsigned long size)
 {
 	int order;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/pci.h linux-2.4.20/include/asm-ppc64/pci.h
--- linux-2.4.19/include/asm-ppc64/pci.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/pci.h	2002-10-29 11:18:34.000000000 +0000
@@ -25,12 +25,12 @@
 #define PCIBIOS_MIN_IO		0x1000
 #define PCIBIOS_MIN_MEM		0x10000000
 
-extern inline void pcibios_set_master(struct pci_dev *dev)
+static inline void pcibios_set_master(struct pci_dev *dev)
 {
 	/* No special bus mastering setup handling */
 }
 
-extern inline void pcibios_penalize_isa_irq(int irq)
+static inline void pcibios_penalize_isa_irq(int irq)
 {
 	/* We don't do dynamic PCI IRQ allocation */
 }
@@ -78,7 +78,7 @@
 
 extern void pSeries_pcibios_init_early(void);
 
-extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
+static inline void pci_dma_sync_single(struct pci_dev *hwdev,
 				       dma_addr_t dma_handle,
 				       size_t size, int direction)
 {
@@ -87,7 +87,7 @@
 	/* nothing to do */
 }
 
-extern inline void pci_dma_sync_sg(struct pci_dev *hwdev,
+static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
 				   struct scatterlist *sg,
 				   int nelems, int direction)
 {
@@ -101,7 +101,7 @@
  * only drive the low 24-bits during PCI bus mastering, then
  * you would pass 0x00ffffff as the mask to this function.
  */
-extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
+static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
 {
 	return 1;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/perfmon.h linux-2.4.20/include/asm-ppc64/perfmon.h
--- linux-2.4.19/include/asm-ppc64/perfmon.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/perfmon.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,94 @@
+/*
+ * This file contains the code to configure and utilize the ppc64 pmc hardware
+ * Copyright (C) 2002 David Engebretsen <engebret@us.ibm.com>
+ */
+
+#ifndef __KERNEL__
+#define INLINE_SYSCALL(arg1, arg2)       \
+  ({                                            \
+    register long r0 __asm__ ("r0");     \
+    register long r3 __asm__ ("r3"); \
+    register long r4 __asm__ ("r4"); \
+    long ret, err;                              \
+    r0 = 208; \
+    r3 = (long) (arg1); \
+    r4 = (long) (arg2); \
+    __asm__ ("sc\n\t"                           \
+             "mfcr      %1\n\t"                 \
+             : "=r" (r3), "=r" (err)            \
+             : "r" (r0), "r" (r3), "r" (r4) \
+             : "cc", "memory");                 \
+    ret = r3;                                   \
+  })
+#endif
+
+#ifndef __ASSEMBLY__
+struct perfmon_base_struct {
+	u64 profile_buffer;
+	u64 profile_length;
+	u64 trace_buffer;
+	u64 trace_length;
+	u64 trace_end;
+	u64 state;
+};
+
+struct pmc_header {
+	int type;
+	int pid;
+	int resv[30];
+};
+
+struct pmc_struct {
+        int pmc[11];
+};
+
+struct pmc_info_struct {
+	unsigned int mode, cpu;
+
+	unsigned int  pmc_base[11];
+	unsigned long pmc_cumulative[8];
+};
+
+struct perfmon_struct {
+	struct pmc_header header;
+
+	union {
+		struct pmc_struct      pmc;
+		struct pmc_info_struct pmc_info;
+ 	} vdata;
+};
+
+enum {
+	PMC_OP_ALLOC         = 1,
+	PMC_OP_FREE          = 2,
+	PMC_OP_CLEAR         = 4,
+	PMC_OP_DUMP          = 5,
+	PMC_OP_DUMP_HARDWARE = 6,
+	PMC_OP_DECR_PROFILE  = 20,
+	PMC_OP_PMC_PROFILE   = 21,
+	PMC_OP_SET           = 30,
+	PMC_OP_SET_USER      = 31,
+	PMC_OP_END           = 30
+};
+
+
+#define	PMC_TRACE_CMD 0xFF
+
+enum {
+	PMC_TYPE_DERC_PROFILE  = 1,
+	PMC_TYPE_CYCLE         = 2,
+	PMC_TYPE_PROFILE       = 3,
+	PMC_TYPE_DCACHE        = 4,
+	PMC_TYPE_L2_MISS       = 5,
+	PMC_TYPE_LWARCX        = 6,
+	PMC_TYPE_END           = 6
+};
+#endif
+
+#define	PMC_STATE_INITIAL         0x00
+#define	PMC_STATE_READY           0x01
+#define	PMC_STATE_DECR_PROFILE    0x10
+#define	PMC_STATE_PROFILE_KERN    0x11
+#define	PMC_STATE_TRACE_KERN      0x20
+#define	PMC_STATE_TRACE_USER      0x21
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/pgtable.h linux-2.4.20/include/asm-ppc64/pgtable.h
--- linux-2.4.19/include/asm-ppc64/pgtable.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/pgtable.h	2002-10-29 11:18:31.000000000 +0000
@@ -12,11 +12,6 @@
 #include <asm/page.h>
 #endif /* __ASSEMBLY__ */
 
-/* Certain architectures need to do special things when pte's
- * within a page table are directly modified.  Thus, the following
- * hook is made available.
- */
-
 /* PMD_SHIFT determines what a second-level page table entry can map */
 #define PMD_SHIFT	(PAGE_SHIFT + PAGE_SHIFT - 3)
 #define PMD_SIZE	(1UL << PMD_SHIFT)
@@ -232,47 +227,41 @@
 /* to find an entry in the ioremap page-table-directory */
 #define pgd_offset_i(address) (ioremap_pgd + pgd_index(address))
 
-/*
- * Given a pointer to an mem_map[] entry, return the kernel virtual
- * address corresponding to that page.
- */
-#define page_address(page) ((page)->virtual)
-
 #define pages_to_mb(x)		((x) >> (20-PAGE_SHIFT))
 
 /*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-extern inline int pte_read(pte_t pte)  { return pte_val(pte) & _PAGE_USER;}
-extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW;}
-extern inline int pte_exec(pte_t pte)  { return pte_val(pte) & _PAGE_EXEC;}
-extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
-extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
+static inline int pte_read(pte_t pte)  { return pte_val(pte) & _PAGE_USER;}
+static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW;}
+static inline int pte_exec(pte_t pte)  { return pte_val(pte) & _PAGE_EXEC;}
+static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
+static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
 
-extern inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
-extern inline void pte_cache(pte_t pte)   { pte_val(pte) &= ~_PAGE_NO_CACHE; }
+static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
+static inline void pte_cache(pte_t pte)   { pte_val(pte) &= ~_PAGE_NO_CACHE; }
 
-extern inline pte_t pte_rdprotect(pte_t pte) {
+static inline pte_t pte_rdprotect(pte_t pte) {
 	pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_exprotect(pte_t pte) {
+static inline pte_t pte_exprotect(pte_t pte) {
 	pte_val(pte) &= ~_PAGE_EXEC; return pte; }
-extern inline pte_t pte_wrprotect(pte_t pte) {
+static inline pte_t pte_wrprotect(pte_t pte) {
 	pte_val(pte) &= ~(_PAGE_RW); return pte; }
-extern inline pte_t pte_mkclean(pte_t pte) {
+static inline pte_t pte_mkclean(pte_t pte) {
 	pte_val(pte) &= ~(_PAGE_DIRTY); return pte; }
-extern inline pte_t pte_mkold(pte_t pte) {
+static inline pte_t pte_mkold(pte_t pte) {
 	pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
 
-extern inline pte_t pte_mkread(pte_t pte) {
+static inline pte_t pte_mkread(pte_t pte) {
 	pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkexec(pte_t pte) {
+static inline pte_t pte_mkexec(pte_t pte) {
 	pte_val(pte) |= _PAGE_USER | _PAGE_EXEC; return pte; }
-extern inline pte_t pte_mkwrite(pte_t pte) {
+static inline pte_t pte_mkwrite(pte_t pte) {
 	pte_val(pte) |= _PAGE_RW; return pte; }
-extern inline pte_t pte_mkdirty(pte_t pte) {
+static inline pte_t pte_mkdirty(pte_t pte) {
 	pte_val(pte) |= _PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkyoung(pte_t pte) {
+static inline pte_t pte_mkyoung(pte_t pte) {
 	pte_val(pte) |= _PAGE_ACCESSED; return pte; }
 
 /* Atomic PTE updates */
@@ -349,8 +338,8 @@
 #define flush_tlb_page local_flush_tlb_page
 #define flush_tlb_range local_flush_tlb_range
 
-extern inline void flush_tlb_pgtables(struct mm_struct *mm,
-				unsigned long start, unsigned long end)
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+				      unsigned long start, unsigned long end)
 {
 	/* PPC has hw page tables. */
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/pmc.h linux-2.4.20/include/asm-ppc64/pmc.h
--- linux-2.4.19/include/asm-ppc64/pmc.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/pmc.h	2002-10-29 11:18:31.000000000 +0000
@@ -98,18 +98,6 @@
 #define PMC_SW_SYSTEM(F)      do {;} while (0)
 #endif
 
-#define MMCR0 795
-#define MMCR1 798
-#define MMCRA 786
-#define PMC1  787
-#define PMC2  788
-#define PMC3  789
-#define PMC4  790
-#define PMC5  791
-#define PMC6  792
-#define PMC7  793
-#define PMC8  794
-
 #define PMC_CONTROL_CPI 1
 #define PMC_CONTROL_TLB 2
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/ppcdebug.h linux-2.4.20/include/asm-ppc64/ppcdebug.h
--- linux-2.4.19/include/asm-ppc64/ppcdebug.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/ppcdebug.h	2002-10-29 11:18:36.000000000 +0000
@@ -51,6 +51,8 @@
 #define PPCDBG_SMP           PPCDBG_BITVAL(19)
 #define PPCDBG_BOOT          PPCDBG_BITVAL(20)
 #define PPCDBG_BUSWALK       PPCDBG_BITVAL(21)
+#define PPCDBG_PROM	     PPCDBG_BITVAL(22)
+#define PPCDBG_RTAS	     PPCDBG_BITVAL(23)
 #define PPCDBG_HTABSTRESS    PPCDBG_BITVAL(62)
 #define PPCDBG_HTABSIZE      PPCDBG_BITVAL(63)
 #define PPCDBG_NONE          (0UL)
@@ -74,7 +76,8 @@
 	"signal",	"signal_xmon",
 	"binfmt32",	"binfmt64",	"binfmt_xmon",	"binfmt_32addr",
 	"alignfixup",   "tceinit",      "tce",          "phb_init",     
-	"smp",          "boot",         "buswalk"
+	"smp",          "boot",         "buswalk",	"prom",
+	"rtas"
 };
 #else
 extern char *trace_names[64];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/processor.h linux-2.4.20/include/asm-ppc64/processor.h
--- linux-2.4.19/include/asm-ppc64/processor.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/processor.h	2002-10-29 11:18:34.000000000 +0000
@@ -18,6 +18,7 @@
 #endif
 #include <asm/ptrace.h>
 #include <asm/types.h>
+#include <asm/delay.h>
 
 /*
  * Default implementation of macro that returns current
@@ -97,7 +98,7 @@
 #define FPSCR_VX	0x20000000	/* Invalid operation summary */
 #define FPSCR_OX	0x10000000	/* Overflow exception summary */
 #define FPSCR_UX	0x08000000	/* Underflow exception summary */
-#define FPSCR_ZX	0x04000000	/* Zero-devide exception summary */
+#define FPSCR_ZX	0x04000000	/* Zero-divide exception summary */
 #define FPSCR_XX	0x02000000	/* Inexact exception summary */
 #define FPSCR_VXSNAN	0x01000000	/* Invalid op for SNaN */
 #define FPSCR_VXISI	0x00800000	/* Invalid op for Inv - Inv */
@@ -247,8 +248,6 @@
 #define	SPRN_IMMR	0x27E  	/* Internal Memory Map Register */
 #define	SPRN_L2CR	0x3F9	/* Level 2 Cache Control Regsiter */
 #define	SPRN_LR		0x008	/* Link Register */
-#define	SPRN_MMCR0	0x3B8	/* Monitor Mode Control Register 0 */
-#define	SPRN_MMCR1	0x3BC	/* Monitor Mode Control Register 1 */
 #define	SPRN_PBL1	0x3FC	/* Protection Bound Lower 1 */
 #define	SPRN_PBL2	0x3FE	/* Protection Bound Lower 2 */
 #define	SPRN_PBU1	0x3FD	/* Protection Bound Upper 1 */
@@ -256,18 +255,12 @@
 #define	SPRN_PID	0x3B1	/* Process ID */
 #define	SPRN_PIR	0x3FF	/* Processor Identification Register */
 #define	SPRN_PIT	0x3DB	/* Programmable Interval Timer */
-#define	SPRN_PMC1	0x3B9	/* Performance Counter Register 1 */
-#define	SPRN_PMC2	0x3BA	/* Performance Counter Register 2 */
-#define	SPRN_PMC3	0x3BD	/* Performance Counter Register 3 */
-#define	SPRN_PMC4	0x3BE	/* Performance Counter Register 4 */
 #define	SPRN_PVR	0x11F	/* Processor Version Register */
 #define	SPRN_RPA	0x3D6	/* Required Physical Address Register */
-#define	SPRN_SDA	0x3BF	/* Sampled Data Address Register */
 #define	SPRN_SDR1	0x019	/* MMU Hash Base Register */
 #define	SPRN_SGR	0x3B9	/* Storage Guarded Register */
 #define	  SGR_NORMAL		0
 #define	  SGR_GUARDED		1
-#define	SPRN_SIA	0x3BB	/* Sampled Instruction Address Register */
 #define	SPRN_SPRG0	0x110	/* Special Purpose Register General 0 */
 #define	SPRN_SPRG1	0x111	/* Special Purpose Register General 1 */
 #define	SPRN_SPRG2	0x112	/* Special Purpose Register General 2 */
@@ -324,13 +317,6 @@
 #define	    WRS_SYSTEM		3		/* WDT forced system reset */
 #define	  TSR_PIS		0x08000000	/* PIT Interrupt Status */
 #define	  TSR_FIS		0x04000000	/* FIT Interrupt Status */
-#define	SPRN_UMMCR0	0x3A8	/* User Monitor Mode Control Register 0 */
-#define	SPRN_UMMCR1	0x3AC	/* User Monitor Mode Control Register 0 */
-#define	SPRN_UPMC1	0x3A9	/* User Performance Counter Register 1 */
-#define	SPRN_UPMC2	0x3AA	/* User Performance Counter Register 2 */
-#define	SPRN_UPMC3	0x3AD	/* User Performance Counter Register 3 */
-#define	SPRN_UPMC4	0x3AE	/* User Performance Counter Register 4 */
-#define	SPRN_USIA	0x3AB	/* User Sampled Instruction Address Register */
 #define	SPRN_XER	0x001	/* Fixed Point Exception Register */
 #define	SPRN_ZPR	0x3B0	/* Zone Protection Register */
 
@@ -396,7 +382,19 @@
 #define	THRM2	SPRN_THRM2	/* Thermal Management Register 2 */
 #define	THRM3	SPRN_THRM3	/* Thermal Management Register 3 */
 #define	XER	SPRN_XER
-
+#define PMC1	0x313
+#define PMC2	0x314
+#define PMC3	0x315
+#define PMC4	0x316
+#define PMC5	0x317
+#define PMC6	0x318
+#define PMC7	0x319
+#define PMC8	0x31a
+#define MMCR0	0x31b
+#define MMCR1	0x31e
+#define MMCRA	0x312
+#define SIAR	0x30c
+#define SDAR	0x30d
 
 /* Device Control Registers */
 
@@ -483,10 +481,12 @@
 #define	PVR_REV(pvr)  (((pvr) >>   0) & 0xFFFF)	/* Revison field */
 
 /* Processor Version Numbers */
+#define	PV_NORTHSTAR	0x0033
 #define	PV_PULSAR	0x0034
 #define	PV_POWER4	0x0035
 #define	PV_ICESTAR	0x0036
 #define	PV_SSTAR	0x0037
+#define	PV_POWER4p	0x0038
 #define	PV_630        	0x0040
 #define	PV_630p	        0x0041
 
@@ -717,7 +717,7 @@
 #define init_task	(init_task_union.task)
 #define init_stack	(init_task_union.stack)
 
-#define cpu_relax()     do { } while (0)
+#define cpu_relax()     udelay(1)
 
 /*
  * Prefetch macros.
@@ -726,18 +726,30 @@
 #define ARCH_HAS_PREFETCHW
 #define ARCH_HAS_SPINLOCK_PREFETCH
 
-extern inline void prefetch(const void *x)
+static inline void prefetch(const void *x)
 {
 	__asm__ __volatile__ ("dcbt 0,%0" : : "r" (x));
 }
 
-extern inline void prefetchw(const void *x)
+static inline void prefetchw(const void *x)
 {
 	__asm__ __volatile__ ("dcbtst 0,%0" : : "r" (x));
 }
 
 #define spin_lock_prefetch(x)	prefetchw(x)
 
+#define cpu_has_largepage()	(__is_processor(PV_POWER4) || \
+				 __is_processor(PV_POWER4p))
+
+#define cpu_has_slb()		(__is_processor(PV_POWER4) || \
+				 __is_processor(PV_POWER4p))
+
+#define cpu_has_tlbiel()	(__is_processor(PV_POWER4) || \
+				 __is_processor(PV_POWER4p))
+
+#define cpu_has_noexecute()	(__is_processor(PV_POWER4) || \
+				 __is_processor(PV_POWER4p))
+
 #endif /* ASSEMBLY */
 
 #endif /* __ASM_PPC64_PROCESSOR_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/prom.h linux-2.4.20/include/asm-ppc64/prom.h
--- linux-2.4.19/include/asm-ppc64/prom.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/prom.h	2002-10-29 11:18:34.000000000 +0000
@@ -128,7 +128,6 @@
 	int	busno;			/* for pci devices */
 	int	devfn;			/* for pci devices */
 	struct  pci_controller *phb;	/* for pci devices */
-	int	status;			/* current status of device */
 	struct	TceTable *tce_table;	/* for phb's or bridges */
 #define DN_STATUS_BIST_FAILED (1<<0)
 	struct	property *properties;
@@ -195,8 +194,5 @@
 extern int prom_n_addr_cells(struct device_node* np);
 extern int prom_n_size_cells(struct device_node* np);
 extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
-extern void prom_drawstring(const char *c);
-extern void prom_drawhex(unsigned long v);
-extern void prom_drawchar(char c);
 
 #endif /* _PPC64_PROM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/rtas.h linux-2.4.20/include/asm-ppc64/rtas.h
--- linux-2.4.19/include/asm-ppc64/rtas.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/rtas.h	2002-10-29 11:18:36.000000000 +0000
@@ -2,6 +2,7 @@
 #define _PPC64_RTAS_H
 
 #include <linux/spinlock.h>
+#include <asm/page.h>
 
 /*
  * Definitions for talking to the RTAS on CHRP machines.
@@ -16,6 +17,8 @@
  */
 
 #define RTAS_UNKNOWN_SERVICE (-1)
+#define RTAS_INSTANTIATE_MAX (1UL<<30) /* Don't instantiate rtas at/above this value */
+
 /*
  * In general to call RTAS use rtas_token("string") to lookup
  * an RTAS token for the given string (e.g. "event-scan").
@@ -128,6 +131,29 @@
 	unsigned char buffer[1];		/* allocated by klimit bump */
 };
 
+struct flash_block {
+	char *data;
+	unsigned long length;
+};
+
+/* This struct is very similar but not identical to
+ * that needed by the rtas flash update.
+ * All we need to do for rtas is rewrite num_blocks
+ * into a version/length and translate the pointers
+ * to absolute.
+ */
+#define FLASH_BLOCKS_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct flash_block))
+struct flash_block_list {
+	unsigned long num_blocks;
+	struct flash_block_list *next;
+	struct flash_block blocks[FLASH_BLOCKS_PER_NODE];
+};
+struct flash_block_list_header { /* just the header of flash_block_list */
+	unsigned long num_blocks;
+	struct flash_block_list *next;
+};
+extern struct flash_block_list_header rtas_firmware_flash_list;
+
 extern struct rtas_t rtas;
 
 extern void enter_rtas(struct rtas_args *);
@@ -140,4 +166,7 @@
 extern void rtas_power_off(void);
 extern void rtas_halt(void);
 
+extern struct proc_dir_entry *rtas_proc_dir;
+
+
 #endif /* _PPC64_RTAS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/semaphore.h linux-2.4.20/include/asm-ppc64/semaphore.h
--- linux-2.4.19/include/asm-ppc64/semaphore.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/semaphore.h	2002-10-29 11:18:32.000000000 +0000
@@ -2,14 +2,8 @@
 #define _PPC64_SEMAPHORE_H
 
 /*
- * Swiped from asm-sparc/semaphore.h and modified
- * -- Cort (cort@cs.nmt.edu)
- *
- * Stole some rw spinlock-based semaphore stuff from asm-alpha/semaphore.h
- * -- Ani Joshi (ajoshi@unixbox.com)
- *
  * Remove spinlock-based RW semaphores; RW semaphore definitions are
- * now in rwsem.h and we use the the generic lib/rwsem.c implementation.
+ * now in rwsem.h and we use the generic lib/rwsem.c implementation.
  * Rework semaphores to use atomic_dec_if_positive.
  * -- Paul Mackerras (paulus@samba.org)
  */
@@ -78,7 +72,7 @@
 extern int  __down_interruptible(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
 
-extern inline void down(struct semaphore * sem)
+static inline void down(struct semaphore * sem)
 {
 #if WAITQUEUE_DEBUG
 	CHECK_MAGIC(sem->__magic);
@@ -92,7 +86,7 @@
 	smp_wmb();
 }
 
-extern inline int down_interruptible(struct semaphore * sem)
+static inline int down_interruptible(struct semaphore * sem)
 {
 	int ret = 0;
 
@@ -106,7 +100,7 @@
 	return ret;
 }
 
-extern inline int down_trylock(struct semaphore * sem)
+static inline int down_trylock(struct semaphore * sem)
 {
 	int ret;
 
@@ -119,7 +113,7 @@
 	return ret;
 }
 
-extern inline void up(struct semaphore * sem)
+static inline void up(struct semaphore * sem)
 {
 #if WAITQUEUE_DEBUG
 	CHECK_MAGIC(sem->__magic);
@@ -130,6 +124,11 @@
 		__up(sem);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* !(_PPC64_SEMAPHORE_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/siginfo.h linux-2.4.20/include/asm-ppc64/siginfo.h
--- linux-2.4.19/include/asm-ppc64/siginfo.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/siginfo.h	2002-10-29 11:18:40.000000000 +0000
@@ -224,7 +224,7 @@
 #ifdef __KERNEL__
 #include <linux/string.h>
 
-extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
+static inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
 {
 	if (from->si_code < 0)
 		memcpy(to, from, sizeof(siginfo_t));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/smplock.h linux-2.4.20/include/asm-ppc64/smplock.h
--- linux-2.4.19/include/asm-ppc64/smplock.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/smplock.h	2002-10-29 11:18:40.000000000 +0000
@@ -43,13 +43,13 @@
  * so we only need to worry about other
  * CPU's.
  */
-extern __inline__ void lock_kernel(void)
+static inline void lock_kernel(void)
 {
 	if (!++current->lock_depth)
 		spin_lock(&kernel_flag);
 }
 
-extern __inline__ void unlock_kernel(void)
+static inline void unlock_kernel(void)
 {
 	if (--current->lock_depth < 0)
 		spin_unlock(&kernel_flag);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/softirq.h linux-2.4.20/include/asm-ppc64/softirq.h
--- linux-2.4.19/include/asm-ppc64/softirq.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/softirq.h	2002-10-29 11:18:49.000000000 +0000
@@ -8,22 +8,20 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-
 #define local_bh_disable()	do { local_bh_count(smp_processor_id())++; barrier(); } while (0)
 #define __local_bh_enable()	do { barrier(); local_bh_count(smp_processor_id())--; } while (0)
 
 #define local_bh_enable()  \
 do {                                                    \
+	barrier();					\
         if (!--local_bh_count(smp_processor_id())       \
             && softirq_pending(smp_processor_id())) {   \
                 do_softirq();                           \
         }                                               \
 } while (0)
 
-
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
 
 #endif	/* __ASM_SOFTIRQ_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/system.h linux-2.4.20/include/asm-ppc64/system.h
--- linux-2.4.19/include/asm-ppc64/system.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/system.h	2002-10-29 11:18:37.000000000 +0000
@@ -16,13 +16,6 @@
 #include <asm/memory.h>
 
 /*
- * System defines.
- */
-#define KERNEL_START_PHYS	0x800000 
-#define KERNEL_START	        (PAGE_OFFSET+KERNEL_START_PHYS)
-#define START_ADDR	        (PAGE_OFFSET+KERNEL_START_PHYS+0x00000)
-
-/*
  * Memory barrier.
  * The sync instruction guarantees that all memory accesses initiated
  * by this processor have been performed (with respect to all other
@@ -68,13 +61,8 @@
 extern int _get_PVR(void);
 extern long _get_L2CR(void);
 extern void _set_L2CR(unsigned long);
-extern void via_cuda_init(void);
-extern void pmac_nvram_init(void);
-extern void pmac_find_display(void);
 extern void giveup_fpu(struct task_struct *);
 extern void enable_kernel_fp(void);
-extern void giveup_altivec(struct task_struct *);
-extern void load_up_altivec(struct task_struct *);
 extern void cvt_fd(float *from, double *to, unsigned long *fpscr);
 extern void cvt_df(double *from, float *to, unsigned long *fpscr);
 extern int abs(int);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/termios.h linux-2.4.20/include/asm-ppc64/termios.h
--- linux-2.4.19/include/asm-ppc64/termios.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/termios.h	2002-10-29 11:18:49.000000000 +0000
@@ -192,6 +192,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 #define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/time.h linux-2.4.20/include/asm-ppc64/time.h
--- linux-2.4.19/include/asm-ppc64/time.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/time.h	2002-10-29 11:18:34.000000000 +0000
@@ -26,33 +26,12 @@
 extern unsigned long tb_ticks_per_usec;
 extern unsigned long tb_ticks_per_sec;
 extern unsigned long tb_to_xs;
-extern unsigned      tb_to_us;
 extern unsigned long tb_last_stamp;
 
 struct rtc_time;
 extern void to_tm(int tim, struct rtc_time * tm);
 extern time_t last_rtc_update;
 
-/*
- * By putting all of this stuff into a single struct we 
- * reduce the number of cache lines touched by do_gettimeofday.
- * Both by collecting all of the data in one cache line and
- * by touching only one TOC entry
- */
-struct gettimeofday_vars {
-	unsigned long tb_to_xs;
-	unsigned long stamp_xsec;
-};
-
-struct gettimeofday_struct {
-	unsigned long tb_orig_stamp;
-	unsigned long tb_ticks_per_sec;
-	struct gettimeofday_vars vars[2];
-	struct gettimeofday_vars * volatile varp;
-	unsigned      var_idx;
-	unsigned      tb_to_us;
-};
-
 struct div_result {
 	unsigned long result_high;
 	unsigned long result_low;
@@ -73,30 +52,28 @@
 
 static __inline__ void set_dec(int val)
 {
+#ifdef CONFIG_PPC_ISERIES
 	struct paca_struct *lpaca = get_paca();
 	int cur_dec;
 
-	if ( lpaca->xLpPaca.xSharedProc ) {
+	if (lpaca->xLpPaca.xSharedProc) {
 		lpaca->xLpPaca.xVirtualDecr = val;
 		cur_dec = get_dec();
-		if ( cur_dec > val )
+		if (cur_dec > val)
 			HvCall_setVirtualDecr();
-	} else {
+	} else
+#endif
 		mtspr(SPRN_DEC, val);
-	}
 }
 
-extern __inline__ unsigned long tb_ticks_since(unsigned long tstamp) {
+static inline unsigned long tb_ticks_since(unsigned long tstamp)
+{
 	return get_tb() - tstamp;
 }
 
-#define mulhwu(x,y) \
-({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;})
 #define mulhdu(x,y) \
 ({unsigned long z; asm ("mulhdu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;})
 
-
-unsigned mulhwu_scale_factor(unsigned, unsigned);
 void div128_by_32( unsigned long dividend_high, unsigned long dividend_low,
 		   unsigned divisor, struct div_result *dr );
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/timex.h linux-2.4.20/include/asm-ppc64/timex.h
--- linux-2.4.19/include/asm-ppc64/timex.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/timex.h	2002-10-29 11:18:34.000000000 +0000
@@ -28,4 +28,7 @@
 	return ret;
 }
 
+#define vxtime_lock()          do {} while (0)
+#define vxtime_unlock()                do {} while (0)
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/types.h linux-2.4.20/include/asm-ppc64/types.h
--- linux-2.4.19/include/asm-ppc64/types.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/types.h	2002-10-29 11:18:34.000000000 +0000
@@ -62,6 +62,7 @@
 /* PCI dma addresses are 32-bits wide.  Ignore PCI64 for now, since
    we'll typically be sending it all through iommu tables anyway.  */
 typedef u32 dma_addr_t;
+typedef u64 dma64_addr_t;
 
 #endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/uaccess.h linux-2.4.20/include/asm-ppc64/uaccess.h
--- linux-2.4.19/include/asm-ppc64/uaccess.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/uaccess.h	2002-10-29 11:18:31.000000000 +0000
@@ -38,7 +38,7 @@
 #define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
 #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
 
-extern inline int verify_area(int type, const void * addr, unsigned long size)
+static inline int verify_area(int type, const void * addr, unsigned long size)
 {
 	return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
@@ -124,9 +124,6 @@
 	}							\
 } while (0)
 
-struct __large_struct { unsigned long buf[100]; };
-#define __m(x) (*(struct __large_struct *)(x))
-
 /*
  * We don't tell gcc that we are accessing memory, but this is OK
  * because we do not write to any memory gcc knows about, so there
@@ -200,7 +197,7 @@
 
 extern unsigned long __copy_tofrom_user(void *to, const void *from, unsigned long size);
 
-extern inline unsigned long
+static inline unsigned long
 copy_from_user(void *to, const void *from, unsigned long n)
 {
 	unsigned long over;
@@ -214,7 +211,7 @@
 	return n;
 }
 
-extern inline unsigned long
+static inline unsigned long
 copy_to_user(void *to, const void *from, unsigned long n)
 {
 	unsigned long over;
@@ -235,17 +232,21 @@
 
 extern unsigned long __clear_user(void *addr, unsigned long size);
 
-extern inline unsigned long
+static inline unsigned long
 clear_user(void *addr, unsigned long size)
 {
 	if (access_ok(VERIFY_WRITE, addr, size))
 		return __clear_user(addr, size);
-	return size? -EFAULT: 0;
+	if ((unsigned long)addr < TASK_SIZE) {
+		unsigned long over = (unsigned long)addr + size - TASK_SIZE;
+		return __clear_user(addr, size - over) + over;
+	}
+	return size;
 }
 
 extern int __strncpy_from_user(char *dst, const char *src, long count);
 
-extern inline long
+static inline long
 strncpy_from_user(char *dst, const char *src, long count)
 {
 	if (access_ok(VERIFY_READ, src, 1))
@@ -269,7 +270,7 @@
  * The `top' parameter to __strnlen_user is to make sure that
  * we can never overflow from the user area into kernel space.
  */
-extern __inline__ int strnlen_user(const char *str, long len)
+static inline int strnlen_user(const char *str, long len)
 {
 	unsigned long top = __kernel_ok? ~0UL: TASK_SIZE - 1;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/udbg.h linux-2.4.20/include/asm-ppc64/udbg.h
--- linux-2.4.19/include/asm-ppc64/udbg.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/udbg.h	2002-10-29 11:18:34.000000000 +0000
@@ -17,6 +17,8 @@
 void udbg_puts(const char *s);
 int udbg_write(const char *s, int n);
 int udbg_read(char *buf, int buflen);
+struct console;
+void udbg_console_write(struct console *con, const char *s, unsigned int n);
 void udbg_puthex(unsigned long val);
 void udbg_printSP(const char *s);
 void udbg_printf(const char *fmt, ...);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/user_exports.h linux-2.4.20/include/asm-ppc64/user_exports.h
--- linux-2.4.19/include/asm-ppc64/user_exports.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/user_exports.h	2002-10-29 11:18:47.000000000 +0000
@@ -0,0 +1,82 @@
+#ifndef _USER_EXPORTS_H
+#define _USER_EXPORTS_H
+
+/* 
+ * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com
+ *   Copyright (C) 2002 Dave Engebretsen & Mike Corrigan
+ *
+ * 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.
+ */
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+#ifdef __powerpc64__
+typedef unsigned long u64;
+#else
+typedef unsigned long long u64;
+#endif
+
+struct user_exports {
+	/*==================================================================
+	 * Cache line 1: 0x0000 - 0x007F
+	 * Kernel only data - undefined for user space
+	 *==================================================================
+	 */
+	u64 undefined[16]; 
+
+	/*==================================================================
+	 * Cache line 2: 0x0080 - 0x00FF
+	 * Kernel / User data
+	 *==================================================================
+	 */
+	u8  eye_catcher[6];      /* Eyecatcher: PPC64         0x00 */
+	u16 version;             /* Version number            0x06 */
+	u16 platform;	         /* Platform type             0x08 */
+	u16 processor;		 /* Processor type            0x0A */
+	u32 processorCount;	 /* # of physical processors  0x0C */
+	u64 physicalMemorySize;	 /* Size of real memory(B)    0x10 */
+
+	u16 dCacheL1Size;	 /* L1 d-cache size           0x18 */
+	u16 dCacheL1LineSize;	 /* L1 d-cache line size      0x1A */
+	u16 dCacheL1LogLineSize; /* L1 d-cache line size Log2 0x1C */
+	u16 dCacheL1LinesPerPage;/* L1 d-cache lines / page   0x1E */
+	u16 dCacheL1Assoc;       /* L1 d-cache associativity  0x20 */
+
+	u16 iCacheL1Size;	 /* L1 i-cache size           0x22 */
+	u16 iCacheL1LineSize;	 /* L1 i-cache line size      0x24 */
+	u16 iCacheL1LogLineSize; /* L1 i-cache line size Log2 0x26 */
+	u16 iCacheL1LinesPerPage;/* L1 i-cache lines / page   0x28 */
+	u16 iCacheL1Assoc;       /* L1 i-cache associativity  0x2A */
+
+	u16 cacheL2Size;	 /* L2 cache size             0x2C */
+	u16 cacheL2Assoc;	 /* L2 cache associativity    0x2E */
+
+	u64 tb_orig_stamp;       /* Timebase at boot          0x30 */
+	u64 tb_ticks_per_sec;    /* Timebase tics / sec       0x38 */
+	u64 tb_to_xs;            /* Inverse of TB to 2^20     0x40 */
+	u64 stamp_xsec;          /*                           0x48 */
+	volatile u64 tb_update_count; /* Timebase atomicity   0x50 */
+	u32 tz_minuteswest;      /* Minutes west of Greenwich 0x58 */
+	u32 tz_dsttime;          /* Type of dst correction    0x5C */
+
+	u64 resv1[4];            /* Reserverd          0x60 - 0x7F */
+};
+
+/* Platform types */
+#define PLATFORM_PSERIES      0x0100
+#define PLATFORM_PSERIES_LPAR 0x0101
+#define PLATFORM_ISERIES_LPAR 0x0201
+
+/* Processor types */
+#define PV_PULSAR       0x0034
+#define PV_POWER4       0x0035
+#define PV_ICESTAR      0x0036
+#define PV_SSTAR        0x0037
+#define PV_630          0x0040
+#define PV_630p         0x0041
+
+#endif /* USER_EXPORTS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-ppc64/vga.h linux-2.4.20/include/asm-ppc64/vga.h
--- linux-2.4.19/include/asm-ppc64/vga.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-ppc64/vga.h	2002-10-29 11:18:33.000000000 +0000
@@ -26,12 +26,12 @@
  *  <linux/vt_buffer.h> has already done the right job for us.
  */
 
-extern inline void scr_writew(u16 val, volatile u16 *addr)
+static inline void scr_writew(u16 val, volatile u16 *addr)
 {
     st_le16(addr, val);
 }
 
-extern inline u16 scr_readw(volatile const u16 *addr)
+static inline u16 scr_readw(volatile const u16 *addr)
 {
     return ld_le16(addr);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390/irq.h linux-2.4.20/include/asm-s390/irq.h
--- linux-2.4.19/include/asm-s390/irq.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-s390/irq.h	2002-10-29 11:18:35.000000000 +0000
@@ -10,6 +10,7 @@
  */
 #define __MAX_SUBCHANNELS 65536
 #define NR_IRQS           __MAX_SUBCHANNELS
+#define NR_CHPIDS 256
 
 #define LPM_ANYPATH 0xff /* doesn't really belong here, Ingo? */
 
@@ -362,6 +363,92 @@
   /* extended part */
       ciw_t    ciw[MAX_CIWS];      /* variable # of CIWs */
    }  __attribute__ ((packed,aligned(4))) senseid_t;
+/*
+ * where we put the ssd info
+ */
+typedef struct _ssd_info {
+	__u8   valid:1;
+	__u8   type:7;          /* subchannel type */
+	__u8   chpid[8];        /* chpids */
+	__u16  fla[8];          /* full link addresses */
+} __attribute__ ((packed)) ssd_info_t;
+
+/*
+ * area for store event information
+ */
+typedef struct chsc_area_t {
+	struct {
+		/* word 0 */
+		__u16 command_code1;
+		__u16 command_code2;
+		union {
+			struct {
+				/* word 1 */
+				__u32 reserved1;
+				/* word 2 */
+				__u32 reserved2;
+			} __attribute__ ((packed,aligned(8))) sei_req;
+			struct {
+				/* word 1 */
+				__u16 reserved1;
+				__u16 f_sch;     /* first subchannel */
+				/* word 2 */
+				__u16 reserved2;
+				__u16 l_sch;    /* last subchannel */
+			} __attribute__ ((packed,aligned(8))) ssd_req;
+		} request_block_data;
+		/* word 3 */
+		__u32 reserved3;
+	} __attribute__ ((packed,aligned(8))) request_block;
+	struct {
+		/* word 0 */
+		__u16 length;
+		__u16 response_code;
+		/* word 1 */
+		__u32 reserved1;
+		union {
+			struct {
+				/* word 2 */
+				__u8  flags;
+				__u8  vf;         /* validity flags */
+				__u8  rs;         /* reporting source */
+				__u8  cc;         /* content code */
+				/* word 3 */
+				__u16 fla;        /* full link address */
+				__u16 rsid;       /* reporting source id */
+				/* word 4 */
+				__u32 reserved2;
+				/* word 5 */
+				__u32 reserved3;
+				/* word 6 */
+				__u32 ccdf;       /* content-code dependent field */
+				/* word 7 */
+				__u32 reserved4;
+				/* word 8 */
+				__u32 reserved5;
+				/* word 9 */
+				__u32 reserved6;
+			} __attribute__ ((packed,aligned(8))) sei_res;
+			struct {
+				/* word 2 */
+				__u8 sch_valid : 1;
+				__u8 dev_valid : 1;
+				__u8 st        : 3; /* subchannel type */
+				__u8 zeroes    : 3;
+				__u8  unit_addr;  /* unit address */
+				__u16 devno;      /* device number */
+				/* word 3 */
+				__u8 path_mask;  
+				__u8 fla_valid_mask;
+				__u16 sch;        /* subchannel */
+				/* words 4-5 */
+				__u8 chpid[8];    /* chpids 0-7 */
+				/* words 6-9 */
+				__u16 fla[8];     /* full link addresses 0-7 */
+			} __attribute__ ((packed,aligned(8))) ssd_res;
+		} response_block_data;
+	} __attribute__ ((packed,aligned(8))) response_block;
+} __attribute__ ((packed,aligned(PAGE_SIZE))) chsc_area_t;
 
 #endif /* __KERNEL__ */
 /*
@@ -409,12 +496,14 @@
 #define DEVSTAT_PCI                0x00000200
 #define DEVSTAT_SUSPENDED          0x00000400
 #define DEVSTAT_UNKNOWN_DEV        0x00000800
+#define DEVSTAT_UNFRIENDLY_DEV     0x00001000
 #define DEVSTAT_FINAL_STATUS       0x80000000
 
 #define DEVINFO_NOT_OPER           DEVSTAT_NOT_OPER
 #define DEVINFO_UNKNOWN_DEV        DEVSTAT_UNKNOWN_DEV
 #define DEVINFO_DEVICE_OWNED       DEVSTAT_DEVICE_OWNED
 #define DEVINFO_QDIO_CAPABLE       0x40000000
+#define DEVINFO_UNFRIENDLY_DEV     DEVSTAT_UNFRIENDLY_DEV
 
 #define INTPARM_STATUS_PENDING     0xFFFFFFFF
 #ifdef __KERNEL__
@@ -491,6 +580,7 @@
                                         /* ... for suspended CCWs */
 #define DOIO_TIMEOUT             0x0080 /* 3 secs. timeout for sync. I/O */
 #define DOIO_DONT_CALL_INTHDLR   0x0100 /* don't call interrupt handler */
+#define DOIO_CANCEL_ON_TIMEOUT   0x0200 /* cancel I/O if it timed out */
 
 /*
  * do_IO()
@@ -562,6 +652,8 @@
 
 int  s390_DevicePathVerification( int irq, __u8 domask );
 
+int s390_trigger_resense(int irq);
+
 int s390_request_irq_special( int                      irq,
                               io_handler_func_t        io_handler,
                               not_oper_handler_func_t  not_oper_handler,
@@ -738,6 +830,21 @@
         return ccode;
 }
 
+extern __inline__ int xsch(int irq)
+{
+	int ccode;
+	
+	__asm__ __volatile__(
+                "   lr    1,%1\n"
+                "   .insn rre,0xb2760000,%1,0\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (irq | 0x10000L)
+                : "cc", "1" );
+	return ccode;
+}
+
 extern __inline__ int iac( void)
 {
         int ccode;
@@ -800,6 +907,20 @@
                 : "cc" );
         return ccode;
 }
+extern __inline__ int chsc( chsc_area_t * chsc_area)
+{
+	int cc;
+	
+	__asm__ __volatile__ (
+	        ".insn	rre,0xb25f0000,%1,0	\n\t"
+		"ipm	%0	\n\t"
+		"srl	%0,28	\n\t"
+		: "=d" (cc) 
+		: "d" (chsc_area) 
+		: "cc" );
+	
+	return cc;
+}
 
 /*
  * Various low-level irq details needed by irq.c, process.c,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390/pgtable.h linux-2.4.20/include/asm-s390/pgtable.h
--- linux-2.4.19/include/asm-s390/pgtable.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-s390/pgtable.h	2002-10-29 11:18:35.000000000 +0000
@@ -156,7 +156,8 @@
 
 /* Bits in the page table entry */
 #define _PAGE_PRESENT   0x001          /* Software                         */
-#define _PAGE_MKCLEAR   0x002          /* Software                         */
+#define _PAGE_MKCLEAN   0x002          /* Software                         */
+#define _PAGE_ISCLEAN   0x004	       /* Software			   */
 #define _PAGE_RO        0x200          /* HW read-only                     */
 #define _PAGE_INVALID   0x400          /* HW invalid                       */
 
@@ -189,12 +190,14 @@
 /*
  * No mapping available
  */
-#define PAGE_INVALID  __pgprot(_PAGE_INVALID)
-#define PAGE_NONE     __pgprot(_PAGE_PRESENT | _PAGE_INVALID)
-#define PAGE_COPY     __pgprot(_PAGE_PRESENT | _PAGE_RO)
-#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_RO)
-#define PAGE_SHARED   __pgprot(_PAGE_PRESENT)
-#define PAGE_KERNEL   __pgprot(_PAGE_PRESENT)
+#define PAGE_INVALID	  __pgprot(_PAGE_INVALID)
+#define PAGE_NONE_SHARED  __pgprot(_PAGE_PRESENT|_PAGE_INVALID)
+#define PAGE_NONE_PRIVATE __pgprot(_PAGE_PRESENT|_PAGE_INVALID|_PAGE_ISCLEAN)
+#define PAGE_RO_SHARED	  __pgprot(_PAGE_PRESENT|_PAGE_RO)
+#define PAGE_RO_PRIVATE	  __pgprot(_PAGE_PRESENT|_PAGE_RO|_PAGE_ISCLEAN)
+#define PAGE_COPY	  __pgprot(_PAGE_PRESENT|_PAGE_RO|_PAGE_ISCLEAN)
+#define PAGE_SHARED	  __pgprot(_PAGE_PRESENT)
+#define PAGE_KERNEL	  __pgprot(_PAGE_PRESENT)
 
 /*
  * The S390 can't do page protection for execute, and considers that the
@@ -202,21 +205,21 @@
  * the closest we can get..
  */
          /*xwr*/
-#define __P000  PAGE_NONE
-#define __P001  PAGE_READONLY
+#define __P000  PAGE_NONE_PRIVATE
+#define __P001  PAGE_RO_PRIVATE
 #define __P010  PAGE_COPY
 #define __P011  PAGE_COPY
-#define __P100  PAGE_READONLY
-#define __P101  PAGE_READONLY
+#define __P100  PAGE_RO_PRIVATE
+#define __P101  PAGE_RO_PRIVATE
 #define __P110  PAGE_COPY
 #define __P111  PAGE_COPY
 
-#define __S000  PAGE_NONE
-#define __S001  PAGE_READONLY
+#define __S000  PAGE_NONE_SHARED
+#define __S001  PAGE_RO_SHARED
 #define __S010  PAGE_SHARED
 #define __S011  PAGE_SHARED
-#define __S100  PAGE_READONLY
-#define __S101  PAGE_READONLY
+#define __S100  PAGE_RO_SHARED
+#define __S101  PAGE_RO_SHARED
 #define __S110  PAGE_SHARED
 #define __S111  PAGE_SHARED
 
@@ -227,10 +230,10 @@
  */
 extern inline void set_pte(pte_t *pteptr, pte_t pteval)
 {
-	if ((pte_val(pteval) & (_PAGE_MKCLEAR|_PAGE_INVALID))
-	    == _PAGE_MKCLEAR) 
+	if ((pte_val(pteval) & (_PAGE_MKCLEAN|_PAGE_INVALID))
+	    == _PAGE_MKCLEAN) 
 	{
-		pte_val(pteval) &= ~_PAGE_MKCLEAR;
+		pte_val(pteval) &= ~_PAGE_MKCLEAN;
                
 		asm volatile ("sske %0,%1" 
 				: : "d" (0), "a" (pte_val(pteval)));
@@ -277,6 +280,8 @@
 {
 	int skey;
 
+	if (pte_val(pte) & _PAGE_ISCLEAN)
+		return 0;
 	asm volatile ("iske %0,%1" : "=d" (skey) : "a" (pte_val(pte)));
 	return skey & _PAGE_CHANGED;
 }
@@ -315,7 +320,8 @@
  */
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
-	pte_val(pte) = (pte_val(pte) & PAGE_MASK) | pgprot_val(newprot);
+	pte_val(pte) &= PAGE_MASK | _PAGE_ISCLEAN;
+	pte_val(pte) |= pgprot_val(newprot) & ~_PAGE_ISCLEAN;
 	return pte;
 }
 
@@ -342,13 +348,11 @@
 
 extern inline pte_t pte_mkdirty(pte_t pte)
 {
-	/* We can't set the changed bit atomically. For now we
-         * set (!) the page referenced bit. */
-	asm volatile ("sske %0,%1" 
-	              : : "d" (_PAGE_CHANGED|_PAGE_REFERENCED),
-		          "a" (pte_val(pte)));
-
-	pte_val(pte) &= ~_PAGE_MKCLEAR;
+	/* We do not explicitly set the dirty bit because the
+	 * sske instruction is slow. It is faster to let the
+	 * next instruction set the dirty bit.
+	 */
+	pte_val(pte) &= ~(_PAGE_MKCLEAN | _PAGE_ISCLEAN);
 	return pte;
 }
 
@@ -382,6 +386,8 @@
 {
 	int skey;
 
+	if (pte_val(*ptep) & _PAGE_ISCLEAN)
+		return 0;
 	asm volatile ("iske %0,%1" : "=d" (skey) : "a" (*ptep));
 	if ((skey & _PAGE_CHANGED) == 0)
 		return 0;
@@ -414,7 +420,7 @@
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
-extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
+static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
 {
 	pte_t __pte;
 	pte_val(__pte) = physpage + pgprot_val(pgprot);
@@ -424,17 +430,15 @@
 #define mk_pte(pg, pgprot)                                                \
 ({                                                                        \
 	struct page *__page = (pg);                                       \
+	pgprot_t __pgprot = (pgprot);					  \
 	unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT);  \
-	pte_t __pte = mk_pte_phys(__physpage, (pgprot));                  \
-	                                                                  \
-	if (__page != ZERO_PAGE(__physpage)) {                            \
-		int __users = page_count(__page);                         \
-		__users -= !!__page->buffers + !!__page->mapping;         \
-	                                                                  \
-		if (__users == 1)                                         \
-			pte_val(__pte) |= _PAGE_MKCLEAR;                  \
-        }                                                                 \
+	pte_t __pte = mk_pte_phys(__physpage, __pgprot);                  \
 	                                                                  \
+	if (!(pgprot_val(__pgprot) & _PAGE_ISCLEAN)) {			  \
+		int __users = !!__page->buffers + !!__page->mapping;      \
+		if (__users + page_count(__page) == 1)                    \
+			pte_val(__pte) |= _PAGE_MKCLEAN;                  \
+	}								  \
 	__pte;                                                            \
 })
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390/s390_ext.h linux-2.4.20/include/asm-s390/s390_ext.h
--- linux-2.4.19/include/asm-s390/s390_ext.h	2001-02-13 22:13:44.000000000 +0000
+++ linux-2.4.20/include/asm-s390/s390_ext.h	2002-10-29 11:18:34.000000000 +0000
@@ -25,6 +25,10 @@
 extern ext_int_info_t *ext_int_hash[];
 
 int register_external_interrupt(__u16 code, ext_int_handler_t handler);
+int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+				      ext_int_info_t *info);
 int unregister_external_interrupt(__u16 code, ext_int_handler_t handler);
+int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+					ext_int_info_t *info);
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390/s390io.h linux-2.4.20/include/asm-s390/s390io.h
--- linux-2.4.19/include/asm-s390/s390io.h	2001-04-12 02:02:28.000000000 +0000
+++ linux-2.4.20/include/asm-s390/s390io.h	2002-10-29 11:18:49.000000000 +0000
@@ -18,10 +18,13 @@
 typedef struct _ioinfo {
      unsigned int  irq;           /* aka. subchannel number */
      spinlock_t    irq_lock;      /* irq lock */
+     void          *private_data; /* pointer to private data */
 
      struct _ioinfo *prev;
      struct _ioinfo *next;
 
+     __u8          st;            /* subchannel type */
+
      union {
         unsigned int info;
         struct {
@@ -53,7 +56,8 @@
            unsigned int  newreq    : 1;  /* new register interface */
            unsigned int  dval      : 1;  /* device number valid */
            unsigned int  unknown   : 1;  /* unknown device - if SenseID failed */
-           unsigned int  unused    : (sizeof(unsigned int)*8 - 24); /* unused */
+	   unsigned int  unfriendly: 1;  /* device is locked by someone else */
+           unsigned int  unused    : (sizeof(unsigned int)*8 - 25); /* unused */
               } __attribute__ ((packed)) flags;
         } ui;
 
@@ -75,6 +79,7 @@
      unsigned long qintparm;      /* queued interruption parameter  */
      unsigned long qflag;         /* queued flags */
      __u8          qlpm;          /* queued logical path mask */
+     ssd_info_t    ssd_info;      /* subchannel description */
 
    } __attribute__ ((aligned(8))) ioinfo_t;
 
@@ -89,6 +94,12 @@
 #define IOINFO_FLAGS_REPALL  0x00800000
 
 extern ioinfo_t *ioinfo[];
+int s390_set_private_data(int irq, void * data);
+void * s390_get_private_data(int irq);
+
+#define CHSC_SEI_ACC_CHPID        1
+#define CHSC_SEI_ACC_LINKADDR     2
+#define CHSC_SEI_ACC_FULLLINKADDR 3
 
 #endif  /* __s390io_h */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390/s390mach.h linux-2.4.20/include/asm-s390/s390mach.h
--- linux-2.4.19/include/asm-s390/s390mach.h	2001-02-13 22:13:44.000000000 +0000
+++ linux-2.4.20/include/asm-s390/s390mach.h	2002-10-29 11:18:35.000000000 +0000
@@ -13,10 +13,23 @@
 #include <asm/types.h>
 
 typedef struct _mci {
-	__u32	to_be_defined_1 :  9;
-	__u32 cp              :  1; /* channel-report pending */
-	__u32	to_be_defined_2 : 22;
-	__u32	to_be_defined_3;
+	__u32   sd              :  1; /* 00 system damage */
+	__u32   pd              :  1; /* 01 instruction-processing damage */
+	__u32   sr              :  1; /* 02 system recovery */
+	__u32   to_be_defined_1 :  4; /* 03-06 */
+	__u32   dg              :  1; /* 07 degradation */
+	__u32   w               :  1; /* 08 warning pending */
+	__u32   cp              :  1; /* 09 channel-report pending */
+	__u32   to_be_defined_2 :  6; /* 10-15 */
+	__u32   se              :  1; /* 16 storage error uncorrected */
+	__u32   sc              :  1; /* 17 storage error corrected */
+	__u32   ke              :  1; /* 18 storage-key error uncorrected */
+	__u32   ds              :  1; /* 19 storage degradation */
+	__u32	to_be_defined_3 :  4; /* 20-23 */
+	__u32   fa              :  1; /* 24 failing storage address validity */
+	__u32   to_be_defined_4 :  7; /* 25-31 */
+	__u32   ie              :  1; /* 32 indirect storage error */
+	__u32	to_be_defined_5 : 31; /* 33-63 */
 	} mci_t;
 
 //
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390/semaphore.h linux-2.4.20/include/asm-s390/semaphore.h
--- linux-2.4.19/include/asm-s390/semaphore.h	2001-04-18 00:19:31.000000000 +0000
+++ linux-2.4.20/include/asm-s390/semaphore.h	2002-10-29 11:18:31.000000000 +0000
@@ -92,4 +92,9 @@
 		__up(sem);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390/sigp.h linux-2.4.20/include/asm-s390/sigp.h
--- linux-2.4.19/include/asm-s390/sigp.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-s390/sigp.h	2002-10-29 11:18:48.000000000 +0000
@@ -59,9 +59,6 @@
 typedef enum
 {
 	ec_schedule=0,
-        ec_restart,
-        ec_halt,
-        ec_power_off,
 	ec_call_function,
 	ec_bit_last
 } ec_bit_sig;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390/smp.h linux-2.4.20/include/asm-s390/smp.h
--- linux-2.4.19/include/asm-s390/smp.h	2001-10-11 16:43:38.000000000 +0000
+++ linux-2.4.20/include/asm-s390/smp.h	2002-10-29 11:18:47.000000000 +0000
@@ -64,7 +64,5 @@
 
 #define cpu_logical_map(cpu) (cpu)
 
-void smp_local_timer_interrupt(struct pt_regs * regs);
-
 #endif
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390/socket.h linux-2.4.20/include/asm-s390/socket.h
--- linux-2.4.19/include/asm-s390/socket.h	2001-06-21 04:00:55.000000000 +0000
+++ linux-2.4.20/include/asm-s390/socket.h	2002-10-29 11:18:32.000000000 +0000
@@ -11,7 +11,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	1
 
 #define SO_DEBUG	1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390/system.h linux-2.4.20/include/asm-s390/system.h
--- linux-2.4.19/include/asm-s390/system.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-s390/system.h	2002-10-29 11:18:40.000000000 +0000
@@ -249,6 +249,11 @@
 extern void save_fp_regs(s390_fp_regs *fpregs);
 extern int restore_fp_regs1(s390_fp_regs *fpregs);
 extern void restore_fp_regs(s390_fp_regs *fpregs);
+
+extern void (*_machine_restart)(char *command);
+extern void (*_machine_halt)(void);
+extern void (*_machine_power_off)(void);
+
 #endif
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390/timex.h linux-2.4.20/include/asm-s390/timex.h
--- linux-2.4.19/include/asm-s390/timex.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-s390/timex.h	2002-10-29 11:18:31.000000000 +0000
@@ -37,4 +37,7 @@
 	return clk;
 }
 
+#define vxtime_lock()		do {} while (0)
+#define vxtime_unlock()		do {} while (0)
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/elf.h linux-2.4.20/include/asm-s390x/elf.h
--- linux-2.4.19/include/asm-s390x/elf.h	2001-04-12 02:02:29.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/elf.h	2002-10-29 11:18:48.000000000 +0000
@@ -77,7 +77,13 @@
 #define ELF_PLATFORM (NULL)
 
 #ifdef __KERNEL__
-#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
+#define SET_PERSONALITY(ex, ibcs2)			\
+do {							\
+	if (ibcs2)					\
+		set_personality(PER_SVR4);		\
+	else if (current->personality != PER_LINUX32)	\
+		set_personality(PER_LINUX);		\
+} while (0)
 #endif
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/irq.h linux-2.4.20/include/asm-s390x/irq.h
--- linux-2.4.19/include/asm-s390x/irq.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/irq.h	2002-10-29 11:18:38.000000000 +0000
@@ -10,6 +10,7 @@
  */
 #define __MAX_SUBCHANNELS 65536
 #define NR_IRQS           __MAX_SUBCHANNELS
+#define NR_CHPIDS 256
 
 #define LPM_ANYPATH 0xff /* doesn't really belong here, Ingo? */
 
@@ -363,6 +364,93 @@
       ciw_t    ciw[MAX_CIWS];      /* variable # of CIWs */
    }  __attribute__ ((packed,aligned(4))) senseid_t;
 
+/*
+ * where we put the ssd info
+ */
+typedef struct _ssd_info {
+	__u8   valid:1;
+	__u8   type:7;          /* subchannel type */
+	__u8   chpid[8];        /* chpids */
+	__u16  fla[8];          /* full link addresses */
+} __attribute__ ((packed)) ssd_info_t;
+
+/*
+ * area for store event information
+ */
+typedef struct chsc_area_t {
+	struct {
+		/* word 0 */
+		__u16 command_code1;
+		__u16 command_code2;
+		union {
+			struct {
+				/* word 1 */
+				__u32 reserved1;
+				/* word 2 */
+				__u32 reserved2;
+			} __attribute__ ((packed,aligned(8))) sei_req;
+			struct {
+				/* word 1 */
+				__u16 reserved1;
+				__u16 f_sch;     /* first subchannel */
+				/* word 2 */
+				__u16 reserved2;
+				__u16 l_sch;    /* last subchannel */
+			} __attribute__ ((packed,aligned(8))) ssd_req;
+		} request_block_data;
+		/* word 3 */
+		__u32 reserved3;
+	} __attribute__ ((packed,aligned(8))) request_block;
+	struct {
+		/* word 0 */
+		__u16 length;
+		__u16 response_code;
+		/* word 1 */
+		__u32 reserved1;
+		union {
+			struct {
+				/* word 2 */
+				__u8  flags;
+				__u8  vf;         /* validity flags */
+				__u8  rs;         /* reporting source */
+				__u8  cc;         /* content code */
+				/* word 3 */
+				__u16 fla;        /* full link address */
+				__u16 rsid;       /* reporting source id */
+				/* word 4 */
+				__u32 reserved2;
+				/* word 5 */
+				__u32 reserved3;
+				/* word 6 */
+				__u32 ccdf;       /* content-code dependent field */
+				/* word 7 */
+				__u32 reserved4;
+				/* word 8 */
+				__u32 reserved5;
+				/* word 9 */
+				__u32 reserved6;
+			} __attribute__ ((packed,aligned(8))) sei_res;
+			struct {
+				/* word 2 */
+				__u8 sch_valid : 1;
+				__u8 dev_valid : 1;
+				__u8 st        : 3; /* subchannel type */
+				__u8 zeroes    : 3;
+				__u8  unit_addr;  /* unit address */
+				__u16 devno;      /* device number */
+				/* word 3 */
+				__u8 path_mask;  
+				__u8 fla_valid_mask;
+				__u16 sch;        /* subchannel */
+				/* words 4-5 */
+				__u8 chpid[8];    /* chpids 0-7 */
+				/* words 6-9 */
+				__u16 fla[8];     /* full link addresses 0-7 */
+			} __attribute__ ((packed,aligned(8))) ssd_res;
+		} response_block_data;
+	} __attribute__ ((packed,aligned(8))) response_block;
+} __attribute__ ((packed,aligned(PAGE_SIZE))) chsc_area_t;
+
 #endif /* __KERNEL__ */
 /*
  * sense data
@@ -409,12 +497,14 @@
 #define DEVSTAT_PCI                0x00000200
 #define DEVSTAT_SUSPENDED          0x00000400
 #define DEVSTAT_UNKNOWN_DEV        0x00000800
+#define DEVSTAT_UNFRIENDLY_DEV     0x00001000
 #define DEVSTAT_FINAL_STATUS       0x80000000
 
 #define DEVINFO_NOT_OPER           DEVSTAT_NOT_OPER
 #define DEVINFO_UNKNOWN_DEV        DEVSTAT_UNKNOWN_DEV
 #define DEVINFO_DEVICE_OWNED       DEVSTAT_DEVICE_OWNED
 #define DEVINFO_QDIO_CAPABLE       0x40000000
+#define DEVINFO_UNFRIENDLY_DEV     DEVSTAT_UNFRIENDLY_DEV
 
 #define INTPARM_STATUS_PENDING     0xFFFFFFFF
 #ifdef __KERNEL__
@@ -491,6 +581,7 @@
                                         /* ... for suspended CCWs */
 #define DOIO_TIMEOUT             0x0080 /* 3 secs. timeout for sync. I/O */
 #define DOIO_DONT_CALL_INTHDLR   0x0100 /* don't call interrupt handler */
+#define DOIO_CANCEL_ON_TIMEOUT   0x0200 /* cancel I/O if it timed out */
 
 /*
  * do_IO()
@@ -562,6 +653,8 @@
 
 int  s390_DevicePathVerification( int irq, __u8 domask );
 
+int s390_trigger_resense(int irq);
+
 int s390_request_irq_special( int                      irq,
                               io_handler_func_t        io_handler,
                               not_oper_handler_func_t  not_oper_handler,
@@ -738,6 +831,21 @@
         return ccode;
 }
 
+extern __inline__ int xsch(int irq)
+{
+	int ccode;
+	
+	__asm__ __volatile__(
+                "   lr    1,%1\n"
+                "   .insn rre,0xb2760000,%1,0\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (irq | 0x10000L)
+                : "cc", "1" );
+	return ccode;
+}
+
 extern __inline__ int iac( void)
 {
         int ccode;
@@ -801,6 +909,21 @@
         return ccode;
 }
 
+extern __inline__ int chsc( chsc_area_t * chsc_area)
+{
+	int cc;
+	
+	__asm__ __volatile__ (
+	        ".insn	rre,0xb25f0000,%1,0	\n\t"
+		"ipm	%0	\n\t"
+		"srl	%0,28	\n\t"
+		: "=d" (cc) 
+		: "d" (chsc_area) 
+		: "cc" );
+	
+	return cc;
+}
+
 /*
  * Various low-level irq details needed by irq.c, process.c,
  * time.c, io_apic.c and smp.c
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/lowcore.h linux-2.4.20/include/asm-s390x/lowcore.h
--- linux-2.4.19/include/asm-s390x/lowcore.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/lowcore.h	2002-10-29 11:18:49.000000000 +0000
@@ -38,6 +38,8 @@
 #define __LC_IO_INT_WORD                0x0C0
 #define __LC_MCCK_CODE                  0x0E8
 
+#define __LC_DIAG44_OPCODE		0x214
+
 #define __LC_SAVE_AREA                  0xC00
 #define __LC_KERNEL_STACK               0xD40
 #define __LC_ASYNC_STACK                0xD48
@@ -146,7 +148,8 @@
 	psw_t        io_new_psw;               /* 0x1f0 */
         psw_t        return_psw;               /* 0x200 */
 	__u32        sync_io_word;             /* 0x210 */
-        __u8         pad8[0xc00-0x214];        /* 0x214 */
+	__u32        diag44_opcode;            /* 0x214 */
+        __u8         pad8[0xc00-0x218];        /* 0x218 */
         /* System info area */
 	__u64        save_area[16];            /* 0xc00 */
         __u8         pad9[0xd40-0xc80];        /* 0xc80 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/page.h linux-2.4.20/include/asm-s390x/page.h
--- linux-2.4.19/include/asm-s390x/page.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/page.h	2002-10-29 11:18:31.000000000 +0000
@@ -91,13 +91,22 @@
         unsigned long pmd0;
         unsigned long pmd1; 
         } pmd_t;
-typedef struct { unsigned long pgd; } pgd_t;
+typedef unsigned int pgd_t;
 typedef struct { unsigned long pgprot; } pgprot_t;
 
 #define pte_val(x)      ((x).pte)
 #define pmd_val(x)      ((x).pmd0)
 #define pmd_val1(x)     ((x).pmd1)
-#define pgd_val(x)      ((x).pgd)
+
+static inline unsigned long __pgd_val(pgd_t *pgdp)
+{
+	unsigned long addr = (unsigned long) pgdp;
+	unsigned long *pgd_slot = (unsigned long *) (addr & -8);
+
+	return *pgd_slot + ((addr & 4) << 11);
+}
+#define pgd_val(pgd) __pgd_val(&(pgd))
+
 #define pgprot_val(x)   ((x).pgprot)
 
 #define __pte(x)        ((pte_t) { (x) } )
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/pgalloc.h linux-2.4.20/include/asm-s390x/pgalloc.h
--- linux-2.4.19/include/asm-s390x/pgalloc.h	2001-07-25 21:12:02.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/pgalloc.h	2002-10-29 11:18:33.000000000 +0000
@@ -16,6 +16,7 @@
 #include <linux/config.h>
 #include <asm/processor.h>
 #include <linux/threads.h>
+#include <linux/slab.h>
 
 #define pgd_quicklist (S390_lowcore.cpu_data.pgd_quick)
 #define pmd_quicklist (S390_lowcore.cpu_data.pmd_quick)
@@ -36,7 +37,7 @@
 	pgd_t *ret;
         int i;
 
-	ret = (pgd_t *) __get_free_pages(GFP_KERNEL, 2);
+	ret = (pgd_t *) __get_free_pages(GFP_KERNEL, 1);
 	if (ret != NULL)
 	        for (i = 0; i < PTRS_PER_PGD; i++) 
 	                pgd_clear(ret + i);
@@ -50,7 +51,7 @@
 	if (ret != NULL) {
 		pgd_quicklist = (unsigned long *)(*ret);
 		ret[0] = ret[1];
-		pgtable_cache_size -= 4;
+		pgtable_cache_size -= 2;
 	}
 	return (pgd_t *) ret;
 }
@@ -69,20 +70,17 @@
 {
 	*(unsigned long *) pgd = (unsigned long) pgd_quicklist;
 	pgd_quicklist = (unsigned long *) pgd;
-	pgtable_cache_size += 4;
+	pgtable_cache_size += 2;
 }
 
 extern __inline__ void free_pgd_slow (pgd_t *pgd)
 {
-        free_pages((unsigned long) pgd, 2);
+	free_pages((unsigned long) pgd, 1);
 }
 
 #define pgd_free(pgd)		free_pgd_fast(pgd)
 
-extern inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
-{
-	pgd_val(*pgd) = _PGD_ENTRY | __pa(pmd);
-}
+extern pmd_t *pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd);
 
 /*
  * page middle directory allocation/free routines.
@@ -92,7 +90,7 @@
 	pmd_t *pmd;
         int i;
 
-	pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, 2);
+	pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, 1);
 	if (pmd != NULL) {
 		for (i=0; i < PTRS_PER_PMD; i++)
 			pmd_clear(pmd+i);
@@ -108,21 +106,25 @@
 	if (ret != NULL) {
 		pmd_quicklist = (unsigned long *)(*ret);
 		ret[0] = ret[1];
-		pgtable_cache_size -= 4;
+		pgtable_cache_size -= 2;
 	}
 	return (pmd_t *) ret;
 }
 
+extern void pmd_free_order2(pmd_t *);
 extern __inline__ void pmd_free_fast (pmd_t *pmd)
 {
-	*(unsigned long *) pmd = (unsigned long) pmd_quicklist;
-	pmd_quicklist = (unsigned long *) pmd;
-	pgtable_cache_size += 4;
+	if (test_bit(PG_arch_1, &virt_to_page(pmd)->flags) == 0) {
+		*(unsigned long *) pmd = (unsigned long) pmd_quicklist;
+		pmd_quicklist = (unsigned long *) pmd;
+		pgtable_cache_size += 2;
+	} else
+		pmd_free_order2(pmd);
 }
 
 extern __inline__ void pmd_free_slow (pmd_t *pmd)
 {
-	free_pages((unsigned long) pmd, 2);
+	free_pages((unsigned long) pmd, 1);
 }
 
 #define pmd_free(pmd)		pmd_free_fast(pmd)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/pgtable.h linux-2.4.20/include/asm-s390x/pgtable.h
--- linux-2.4.19/include/asm-s390x/pgtable.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/pgtable.h	2002-10-29 11:18:39.000000000 +0000
@@ -63,7 +63,7 @@
 #define PMD_MASK        (~(PMD_SIZE-1))
 
 /* PGDIR_SHIFT determines what a third-level page table entry can map */
-#define PGDIR_SHIFT     31
+#define PGDIR_SHIFT     30
 #define PGDIR_SIZE      (1UL << PGDIR_SHIFT)
 #define PGDIR_MASK      (~(PGDIR_SIZE-1))
 
@@ -72,7 +72,7 @@
  * currently we use a 3 level lookup
  */
 #define PTRS_PER_PTE    512
-#define PTRS_PER_PMD    1024
+#define PTRS_PER_PMD    512
 #define PTRS_PER_PGD    2048
 
 /*
@@ -103,7 +103,7 @@
 #define VMALLOC_START   (((unsigned long) high_memory + VMALLOC_OFFSET) \
                          & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END     (0x40000000000L)
+#define VMALLOC_END     (0x20000000000L)
 
 
 /*
@@ -158,23 +158,26 @@
 
 /* Bits in the page table entry */
 #define _PAGE_PRESENT   0x001          /* Software                         */
-#define _PAGE_MKCLEAR   0x002          /* Software                         */
+#define _PAGE_MKCLEAN   0x002          /* Software                         */
+#define _PAGE_ISCLEAN   0x004          /* Software                         */
 #define _PAGE_RO        0x200          /* HW read-only                     */
 #define _PAGE_INVALID   0x400          /* HW invalid                       */
 
 /* Bits in the segment table entry */
-#define _PMD_ENTRY_INV   0x20          /* invalid segment table entry      */
-#define _PMD_ENTRY       0x00        
+#define _PMD_ENTRY_INV	0x20		/* invalid segment table entry      */
+#define _PMD_ENTRY	0x00        
 
 /* Bits in the region third table entry */
-#define _PGD_ENTRY_INV   0x20          /* invalid region table entry       */
-#define _PGD_ENTRY       0x07
+#define _PGD_ENTRY_INV	0x20		/* region table entry invalid bit  */
+#define _PGD_ENTRY_MASK 0x04		/* region third table entry mask   */
+#define _PGD_ENTRY_LEN(x) ((x)&3)       /* region table length bits        */
+#define _PGD_ENTRY_OFF(x) (((x)&3)<<6)  /* region table offset bits        */
 
 /*
  * User and kernel page directory
  */
 #define _REGION_THIRD       0x4
-#define _REGION_THIRD_LEN   0x3 
+#define _REGION_THIRD_LEN   0x1 
 #define _REGION_TABLE       (_REGION_THIRD|_REGION_THIRD_LEN|0x40|0x100)
 #define _KERN_REGION_TABLE  (_REGION_THIRD|_REGION_THIRD_LEN)
 
@@ -185,33 +188,35 @@
 /*
  * No mapping available
  */
-#define PAGE_INVALID    __pgprot(_PAGE_INVALID)
-#define PAGE_NONE       __pgprot(_PAGE_PRESENT | _PAGE_INVALID)
-#define PAGE_COPY       __pgprot(_PAGE_PRESENT | _PAGE_RO)
-#define PAGE_READONLY   __pgprot(_PAGE_PRESENT | _PAGE_RO)
-#define PAGE_SHARED     __pgprot(_PAGE_PRESENT )
-#define PAGE_KERNEL     __pgprot(_PAGE_PRESENT )
+#define PAGE_INVALID	  __pgprot(_PAGE_INVALID)
+#define PAGE_NONE_SHARED  __pgprot(_PAGE_PRESENT|_PAGE_INVALID)
+#define PAGE_NONE_PRIVATE __pgprot(_PAGE_PRESENT|_PAGE_INVALID|_PAGE_ISCLEAN)
+#define PAGE_RO_SHARED	  __pgprot(_PAGE_PRESENT|_PAGE_RO)
+#define PAGE_RO_PRIVATE	  __pgprot(_PAGE_PRESENT|_PAGE_RO|_PAGE_ISCLEAN)
+#define PAGE_COPY	  __pgprot(_PAGE_PRESENT|_PAGE_RO|_PAGE_ISCLEAN)
+#define PAGE_SHARED	  __pgprot(_PAGE_PRESENT)
+#define PAGE_KERNEL	  __pgprot(_PAGE_PRESENT)
 
 /*
  * The S390 can't do page protection for execute, and considers that the
  * same are read. Also, write permissions imply read permissions. This is
  * the closest we can get..
  */
-#define __P000  PAGE_NONE
-#define __P001  PAGE_READONLY
+#define __P000  PAGE_NONE_PRIVATE
+#define __P001  PAGE_RO_PRIVATE
 #define __P010  PAGE_COPY
 #define __P011  PAGE_COPY
-#define __P100  PAGE_READONLY
-#define __P101  PAGE_READONLY
+#define __P100  PAGE_RO_PRIVATE
+#define __P101  PAGE_RO_PRIVATE
 #define __P110  PAGE_COPY
 #define __P111  PAGE_COPY
 
-#define __S000  PAGE_NONE
-#define __S001  PAGE_READONLY
+#define __S000  PAGE_NONE_SHARED
+#define __S001  PAGE_RO_SHARED
 #define __S010  PAGE_SHARED
 #define __S011  PAGE_SHARED
-#define __S100  PAGE_READONLY
-#define __S101  PAGE_READONLY
+#define __S100  PAGE_RO_SHARED
+#define __S101  PAGE_RO_SHARED
 #define __S110  PAGE_SHARED
 #define __S111  PAGE_SHARED
 
@@ -222,10 +227,10 @@
  */
 extern inline void set_pte(pte_t *pteptr, pte_t pteval)
 {
-	if ((pte_val(pteval) & (_PAGE_MKCLEAR|_PAGE_INVALID))
-	    == _PAGE_MKCLEAR) 
+	if ((pte_val(pteval) & (_PAGE_MKCLEAN|_PAGE_INVALID))
+	    == _PAGE_MKCLEAN) 
 	{
-		pte_val(pteval) &= ~_PAGE_MKCLEAR;
+		pte_val(pteval) &= ~_PAGE_MKCLEAN;
                
 		asm volatile ("sske %0,%1" 
 				: : "d" (0), "a" (pte_val(pteval)));
@@ -239,20 +244,37 @@
 /*
  * pgd/pmd/pte query functions
  */
-extern inline int pgd_present(pgd_t pgd)
+extern inline int __pgd_present(pgd_t *pgd)
 {
-	return (pgd_val(pgd) & ~PAGE_MASK) == _PGD_ENTRY;
+	unsigned long addr = (unsigned long) pgd;
+	unsigned long *pgd_slot = (unsigned long *) (addr & -8);
+	unsigned long offset = (addr & 4) >> 1;
+
+	if (*pgd_slot & _PGD_ENTRY_INV)
+		return 0;
+	if ((*pgd_slot & _PGD_ENTRY_OFF(3)) > _PGD_ENTRY_OFF(offset))
+		return 0;
+	if ((*pgd_slot & _PGD_ENTRY_LEN(3)) < _PGD_ENTRY_LEN(offset))
+		return 0;
+	return 1;
 }
+#define pgd_present(pgd) __pgd_present(&(pgd))
 
-extern inline int pgd_none(pgd_t pgd)
+extern inline int __pgd_none(pgd_t *pgd)
 {
-	return pgd_val(pgd) & _PGD_ENTRY_INV;
+	return !__pgd_present(pgd);
 }
+#define pgd_none(pgd) __pgd_none(&(pgd))
 
-extern inline int pgd_bad(pgd_t pgd)
+extern inline int __pgd_bad(pgd_t *pgd)
 {
-	return (pgd_val(pgd) & (~PAGE_MASK & ~_PGD_ENTRY_INV)) != _PGD_ENTRY;
+	unsigned long addr = (unsigned long) pgd;
+	unsigned long *pgd_slot = (unsigned long *) (addr & -8);
+
+	return (*pgd_slot & (~PAGE_MASK & ~_PGD_ENTRY_INV & ~_PGD_ENTRY_MASK &
+		             ~_PGD_ENTRY_LEN(3) & ~_PGD_ENTRY_OFF(3))) != 0;
 }
+#define pgd_bad(pgd) __pgd_bad(&(pgd))
 
 extern inline int pmd_present(pmd_t pmd)
 {
@@ -295,6 +317,8 @@
 {
 	int skey;
 
+	if (pte_val(pte) & _PAGE_ISCLEAN)
+		return 0;
 	asm volatile ("iske %0,%1" : "=d" (skey) : "a" (pte_val(pte)));
 	return skey & _PAGE_CHANGED;
 }
@@ -312,7 +336,27 @@
  */
 extern inline void pgd_clear(pgd_t * pgdp)
 {
-	pgd_val(*pgdp) = _PGD_ENTRY_INV | _PGD_ENTRY;
+	unsigned long addr = (unsigned long) pgdp;
+	unsigned long *pgd_slot = (unsigned long *) (addr & -8);
+	unsigned long offset = addr & 4;
+
+	if (*pgd_slot & _PGD_ENTRY_INV) {
+		*pgd_slot = _PGD_ENTRY_INV;
+		return;
+	}
+	if (offset == 0 && (*pgd_slot & _PGD_ENTRY_LEN(2)) != 0) {
+		/* Clear lower pmd, upper pmd still used. */
+		*pgd_slot = (*pgd_slot & PAGE_MASK) | _PGD_ENTRY_MASK |
+			    _PGD_ENTRY_OFF(2) | _PGD_ENTRY_LEN(3);
+		return;
+	}
+	if (offset == 4 && (*pgd_slot & _PGD_ENTRY_OFF(2)) == 0) {
+		/* Clear upped pmd, lower pmd still used. */
+		*pgd_slot = (*pgd_slot & PAGE_MASK) | _PGD_ENTRY_MASK |
+			    _PGD_ENTRY_OFF(0) | _PGD_ENTRY_LEN(1);
+		return;
+	}
+	*pgd_slot = _PGD_ENTRY_INV;
 }
 
 extern inline void pmd_clear(pmd_t * pmdp)
@@ -334,7 +378,8 @@
  */
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
-	pte_val(pte) = (pte_val(pte) & PAGE_MASK) | pgprot_val(newprot);
+	pte_val(pte) &= PAGE_MASK | _PAGE_ISCLEAN;
+	pte_val(pte) |= pgprot_val(newprot) & ~_PAGE_ISCLEAN;
 	return pte; 
 }
 
@@ -361,13 +406,11 @@
 
 extern inline pte_t pte_mkdirty(pte_t pte)
 { 
-	/* We can't set the changed bit atomically either. For now we
-         * set (!) the page referenced bit. */
-	asm volatile ("sske %0,%1" 
-	              : : "d" (_PAGE_CHANGED|_PAGE_REFERENCED),
-		          "a" (pte_val(pte)));
-
-	pte_val(pte) &= ~_PAGE_MKCLEAR;
+	/* We do not explicitly set the dirty bit because the
+	 * sske instruction is slow. It is faster to let the
+	 * next instruction set the dirty bit.
+	 */
+	pte_val(pte) &= ~(_PAGE_MKCLEAN | _PAGE_ISCLEAN);
 	return pte;
 }
 
@@ -401,6 +444,8 @@
 {
 	int skey;
 
+	if (pte_val(*ptep) & _PAGE_ISCLEAN)
+		return 0;
 	asm volatile ("iske %0,%1" : "=d" (skey) : "a" (*ptep));
 	if ((skey & _PAGE_CHANGED) == 0)
 		return 0;
@@ -443,17 +488,15 @@
 #define mk_pte(pg, pgprot)                                                \
 ({                                                                        \
 	struct page *__page = (pg);                                       \
+	pgprot_t __pgprot = (pgprot);					  \
 	unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT);  \
-	pte_t __pte = mk_pte_phys(__physpage, (pgprot));                  \
-	                                                                  \
-	if (__page != ZERO_PAGE(__physpage)) {                            \
-		int __users = page_count(__page);                         \
-		__users -= !!__page->buffers + !!__page->mapping;         \
-	                                                                  \
-		if (__users == 1)                                         \
-			pte_val(__pte) |= _PAGE_MKCLEAR;                  \
-        }                                                                 \
-	                                                                  \
+	pte_t __pte = mk_pte_phys(__physpage, __pgprot);                  \
+ 	                                                                  \
+	if (!(pgprot_val(__pgprot) & _PAGE_ISCLEAN)) {			  \
+		int __users = !!__page->buffers + !!__page->mapping;      \
+		if (__users + page_count(__page) == 1)                    \
+			pte_val(__pte) |= _PAGE_MKCLEAN;                  \
+	}								  \
 	__pte;                                                            \
 })
 
@@ -466,15 +509,15 @@
 #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
 #define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
 
-#define pgd_page(pmd) \
-        ((unsigned long) __va(pgd_val(pmd) & PAGE_MASK))
+#define pgd_page(pgd) \
+        ((unsigned long) __va(__pgd_val(pgd) & PAGE_MASK))
 
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
 /* Find an entry in the second-level page table.. */
 #define pmd_offset(dir,addr) \
-	((pmd_t *) pgd_page(*(dir)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
+	((pmd_t *) pgd_page(dir) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
 
 /* Find an entry in the third-level page table.. */
 #define pte_offset(dir,addr) \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/processor.h linux-2.4.20/include/asm-s390x/processor.h
--- linux-2.4.19/include/asm-s390x/processor.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/processor.h	2002-10-29 11:18:35.000000000 +0000
@@ -16,6 +16,7 @@
 #include <asm/page.h>
 #include <asm/ptrace.h>
 
+#ifdef __KERNEL__
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
@@ -59,7 +60,7 @@
 /*
  * User space process size: 4TB (default).
  */
-#define TASK_SIZE       (0x40000000000UL)
+#define TASK_SIZE       (0x20000000000UL)
 #define TASK31_SIZE     (0x80000000UL)
 
 /* This decides where the kernel will search for a free chunk of vm
@@ -155,13 +156,9 @@
 #define KSTK_ESP(tsk)	(__KSTK_PTREGS(tsk)->gprs[15])
 
 /* Allocation and freeing of basic task resources. */
-/*
- * NOTE! The task struct and the stack go together
- */
-#define alloc_task_struct() \
-        ((struct task_struct *) __get_free_pages(GFP_KERNEL,2))
-#define free_task_struct(p)     free_pages((unsigned long)(p),2)
-#define get_task_struct(tsk)      atomic_inc(&virt_to_page(tsk)->count)
+extern struct task_struct *alloc_task_struct(void);
+extern void free_task_struct(struct task_struct *tsk);
+extern void get_task_struct(struct task_struct *tsk);
 
 #define init_task       (init_task_union.task)
 #define init_stack      (init_task_union.stack)
@@ -267,5 +264,7 @@
                       : : "a" (dw_psw), "a" (&ctl_buf) : "cc", "0", "1");
 }
 
+#endif
+
 #endif                                 /* __ASM_S390_PROCESSOR_H           */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/s390_ext.h linux-2.4.20/include/asm-s390x/s390_ext.h
--- linux-2.4.19/include/asm-s390x/s390_ext.h	2001-02-13 22:13:44.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/s390_ext.h	2002-10-29 11:18:39.000000000 +0000
@@ -25,6 +25,10 @@
 extern ext_int_info_t *ext_int_hash[];
 
 int register_external_interrupt(__u16 code, ext_int_handler_t handler);
+int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+				      ext_int_info_t *info);
 int unregister_external_interrupt(__u16 code, ext_int_handler_t handler);
+int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+					ext_int_info_t *info);
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/s390io.h linux-2.4.20/include/asm-s390x/s390io.h
--- linux-2.4.19/include/asm-s390x/s390io.h	2001-04-12 02:02:29.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/s390io.h	2002-10-29 11:18:48.000000000 +0000
@@ -18,10 +18,13 @@
 typedef struct _ioinfo {
      unsigned int  irq;           /* aka. subchannel number */
      spinlock_t    irq_lock;      /* irq lock */
+     void          *private_data; /* pointer to private data */
 
      struct _ioinfo *prev;
      struct _ioinfo *next;
 
+     __u8          st;            /* subchannel type */	
+
      union {
         unsigned int info;
         struct {
@@ -53,7 +56,8 @@
            unsigned int  newreq    : 1;  /* new register interface */
            unsigned int  dval      : 1;  /* device number valid */
            unsigned int  unknown   : 1;  /* unknown device - if SenseID failed */
-           unsigned int  unused    : (sizeof(unsigned int)*8 - 24); /* unused */
+	   unsigned int  unfriendly: 1;  /* device is locked by someone else */
+           unsigned int  unused    : (sizeof(unsigned int)*8 - 25); /* unused */
               } __attribute__ ((packed)) flags;
         } ui;
 
@@ -75,6 +79,7 @@
      unsigned long qintparm;      /* queued interruption parameter  */
      unsigned long qflag;         /* queued flags */
      __u8          qlpm;          /* queued logical path mask */
+     ssd_info_t    ssd_info;      /* subchannel description */
 
    } __attribute__ ((aligned(8))) ioinfo_t;
 
@@ -89,6 +94,12 @@
 #define IOINFO_FLAGS_REPALL  0x00800000
 
 extern ioinfo_t *ioinfo[];
+int s390_set_private_data(int irq, void * data);
+void * s390_get_private_data(int irq);
+
+#define CHSC_SEI_ACC_CHPID        1
+#define CHSC_SEI_ACC_LINKADDR     2
+#define CHSC_SEI_ACC_FULLLINKADDR 3
 
 #endif  /* __s390io_h */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/s390mach.h linux-2.4.20/include/asm-s390x/s390mach.h
--- linux-2.4.19/include/asm-s390x/s390mach.h	2001-02-13 22:13:44.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/s390mach.h	2002-10-29 11:18:40.000000000 +0000
@@ -13,10 +13,23 @@
 #include <asm/types.h>
 
 typedef struct _mci {
-	__u32	to_be_defined_1 :  9;
-	__u32 cp              :  1; /* channel-report pending */
-	__u32	to_be_defined_2 : 22;
-	__u32	to_be_defined_3;
+	__u32   sd              :  1; /* 00 system damage */
+	__u32   pd              :  1; /* 01 instruction-processing damage */
+	__u32   sr              :  1; /* 02 system recovery */
+	__u32   to_be_defined_1 :  4; /* 03-06 */
+	__u32   dg              :  1; /* 07 degradation */
+	__u32   w               :  1; /* 08 warning pending */
+	__u32   cp              :  1; /* 09 channel-report pending */
+	__u32   to_be_defined_2 :  6; /* 10-15 */
+	__u32   se              :  1; /* 16 storage error uncorrected */
+	__u32   sc              :  1; /* 17 storage error corrected */
+	__u32   ke              :  1; /* 18 storage-key error uncorrected */
+	__u32   ds              :  1; /* 19 storage degradation */
+	__u32	to_be_defined_3 :  4; /* 20-23 */
+	__u32   fa              :  1; /* 24 failing storage address validity */
+	__u32   to_be_defined_4 :  7; /* 25-31 */
+	__u32   ie              :  1; /* 32 indirect storage error */
+	__u32	to_be_defined_5 : 31; /* 33-63 */
 	} mci_t;
 
 //
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/semaphore.h linux-2.4.20/include/asm-s390x/semaphore.h
--- linux-2.4.19/include/asm-s390x/semaphore.h	2001-04-18 00:19:31.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/semaphore.h	2002-10-29 11:18:33.000000000 +0000
@@ -92,4 +92,9 @@
 		__up(sem);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/setup.h linux-2.4.20/include/asm-s390x/setup.h
--- linux-2.4.19/include/asm-s390x/setup.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/setup.h	2002-10-29 11:18:32.000000000 +0000
@@ -25,11 +25,12 @@
  */
 extern unsigned long machine_flags;
 
-#define MACHINE_IS_VM    (machine_flags & 1)
-#define MACHINE_IS_P390  (machine_flags & 4)
-#define MACHINE_HAS_MVPG (machine_flags & 16)
+#define MACHINE_IS_VM		(machine_flags & 1)
+#define MACHINE_IS_P390		(machine_flags & 4)
+#define MACHINE_HAS_MVPG	(machine_flags & 16)
+#define MACHINE_HAS_DIAG44	(machine_flags & 32)
 
-#define MACHINE_HAS_HWC  (!MACHINE_IS_P390)
+#define MACHINE_HAS_HWC		(!MACHINE_IS_P390)
 
 /*
  * Console mode. Override with conmode=
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/sigp.h linux-2.4.20/include/asm-s390x/sigp.h
--- linux-2.4.19/include/asm-s390x/sigp.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/sigp.h	2002-10-29 11:18:39.000000000 +0000
@@ -59,9 +59,6 @@
 typedef enum
 {
 	ec_schedule=0,
-        ec_restart,
-        ec_halt,
-        ec_power_off,
 	ec_call_function,
 	ec_bit_last
 } ec_bit_sig;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/smp.h linux-2.4.20/include/asm-s390x/smp.h
--- linux-2.4.19/include/asm-s390x/smp.h	2001-10-11 16:43:38.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/smp.h	2002-10-29 11:18:40.000000000 +0000
@@ -64,7 +64,5 @@
 
 #define cpu_logical_map(cpu) (cpu)
 
-void smp_local_timer_interrupt(struct pt_regs * regs);
-
 #endif
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/spinlock.h linux-2.4.20/include/asm-s390x/spinlock.h
--- linux-2.4.19/include/asm-s390x/spinlock.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/spinlock.h	2002-10-29 11:18:33.000000000 +0000
@@ -12,6 +12,20 @@
 #define __ASM_SPINLOCK_H
 
 /*
+ * Grmph, take care of %&#! user space programs that include
+ * asm/spinlock.h. The diagnose is only available in kernel
+ * context.
+ */
+#ifdef __KERNEL__
+#include <asm/lowcore.h>
+#define __DIAG44_INSN "ex"
+#define __DIAG44_OPERAND __LC_DIAG44_OPCODE
+#else
+#define __DIAG44_INSN "#"
+#define __DIAG44_OPERAND 0
+#endif
+
+/*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
  * on the local processor, one does not.
  *
@@ -31,12 +45,13 @@
 {
 	unsigned long reg1, reg2;
         __asm__ __volatile("    bras  %1,1f\n"
-                           "0:  # diag  0,0,68\n"
+                           "0:  " __DIAG44_INSN " 0,%3\n"
                            "1:  slr   %0,%0\n"
                            "    cs    %0,%1,0(%2)\n"
                            "    jl    0b\n"
                            : "=&d" (reg1), "=&d" (reg2)
-                           : "a" (&lp->lock) : "cc", "memory" );
+                           : "a" (&lp->lock), "i" (__DIAG44_OPERAND)
+			   : "cc", "memory" );
 }
 
 extern inline int spin_trylock(spinlock_t *lp)
@@ -79,40 +94,44 @@
 #define read_lock(rw)   \
         asm volatile("   lg    2,0(%0)\n"   \
                      "   j     1f\n"     \
-                     "0: # diag  0,0,68\n" \
+                     "0: " __DIAG44_INSN " 0,%1\n" \
                      "1: nihh  2,0x7fff\n" /* clear high (=write) bit */ \
                      "   la    3,1(2)\n"   /* one more reader */  \
                      "   csg   2,3,0(%0)\n" /* try to write new value */ \
                      "   jl    0b"       \
-                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" )
+                     : : "a" (&(rw)->lock), "i" (__DIAG44_OPERAND) \
+		     : "2", "3", "cc", "memory" )
 
 #define read_unlock(rw) \
         asm volatile("   lg    2,0(%0)\n"   \
                      "   j     1f\n"     \
-                     "0: # diag  0,0,68\n" \
+                     "0: " __DIAG44_INSN " 0,%1\n" \
                      "1: lgr   3,2\n"    \
                      "   bctgr 3,0\n"    /* one less reader */ \
                      "   csg   2,3,0(%0)\n" \
                      "   jl    0b"       \
-                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" )
+                     : : "a" (&(rw)->lock), "i" (__DIAG44_OPERAND) \
+		     : "2", "3", "cc", "memory" )
 
 #define write_lock(rw) \
         asm volatile("   llihh 3,0x8000\n" /* new lock value = 0x80...0 */ \
                      "   j     1f\n"       \
-                     "0: # diag  0,0,68\n"   \
+                     "0: " __DIAG44_INSN " 0,%1\n"   \
                      "1: slgr  2,2\n"      /* old lock value must be 0 */ \
                      "   csg   2,3,0(%0)\n" \
                      "   jl    0b"         \
-                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" )
+                     : : "a" (&(rw)->lock), "i" (__DIAG44_OPERAND) \
+		     : "2", "3", "cc", "memory" )
 
 #define write_unlock(rw) \
         asm volatile("   slgr  3,3\n"      /* new lock value = 0 */ \
                      "   j     1f\n"       \
-                     "0: # diag  0,0,68\n"   \
+                     "0: " __DIAG44_INSN " 0,%1\n"   \
                      "1: llihh 2,0x8000\n" /* old lock value must be 0x8..0 */\
                      "   csg   2,3,0(%0)\n"   \
                      "   jl    0b"         \
-                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" )
+                     : : "a" (&(rw)->lock), "i" (__DIAG44_OPERAND) \
+		     : "2", "3", "cc", "memory" )
 
 #endif /* __ASM_SPINLOCK_H */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/system.h linux-2.4.20/include/asm-s390x/system.h
--- linux-2.4.19/include/asm-s390x/system.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/system.h	2002-10-29 11:18:50.000000000 +0000
@@ -253,12 +253,17 @@
 #endif
 
 #ifdef __KERNEL__
-extern struct task_struct *resume(void *,void *);
+extern struct task_struct *resume(void *, void *);
 
 extern int save_fp_regs1(s390_fp_regs *fpregs);
 extern void save_fp_regs(s390_fp_regs *fpregs);
 extern int restore_fp_regs1(s390_fp_regs *fpregs);
 extern void restore_fp_regs(s390_fp_regs *fpregs);
+
+extern void (*_machine_restart)(char *command);
+extern void (*_machine_halt)(void);
+extern void (*_machine_power_off)(void);
+
 #endif
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-s390x/timex.h linux-2.4.20/include/asm-s390x/timex.h
--- linux-2.4.19/include/asm-s390x/timex.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-s390x/timex.h	2002-10-29 11:18:34.000000000 +0000
@@ -37,4 +37,7 @@
 	return clock;
 }
 
+#define vxtime_lock()		do {} while (0)
+#define vxtime_unlock()		do {} while (0)
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sh/pgtable-2level.h linux-2.4.20/include/asm-sh/pgtable-2level.h
--- linux-2.4.19/include/asm-sh/pgtable-2level.h	2001-09-08 19:29:09.000000000 +0000
+++ linux-2.4.20/include/asm-sh/pgtable-2level.h	2002-10-29 11:18:39.000000000 +0000
@@ -42,7 +42,7 @@
  */
 #define set_pte(pteptr, pteval) (*(pteptr) = pteval)
 /*
- * (pmds are folded into pgds so this doesnt get actually called,
+ * (pmds are folded into pgds so this doesn't get actually called,
  * but the define is needed for a generic inline function.)
  */
 #define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sh/semaphore.h linux-2.4.20/include/asm-sh/semaphore.h
--- linux-2.4.19/include/asm-sh/semaphore.h	2001-09-08 19:29:09.000000000 +0000
+++ linux-2.4.20/include/asm-sh/semaphore.h	2002-10-29 11:18:40.000000000 +0000
@@ -135,5 +135,10 @@
 		__up(sem);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif
 #endif /* __ASM_SH_SEMAPHORE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sh/socket.h linux-2.4.20/include/asm-sh/socket.h
--- linux-2.4.19/include/asm-sh/socket.h	2001-06-21 04:00:55.000000000 +0000
+++ linux-2.4.20/include/asm-sh/socket.h	2002-10-29 11:18:40.000000000 +0000
@@ -3,7 +3,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	1
 
 #define SO_DEBUG	1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sh/termios.h linux-2.4.20/include/asm-sh/termios.h
--- linux-2.4.19/include/asm-sh/termios.h	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.20/include/asm-sh/termios.h	2002-10-29 11:18:39.000000000 +0000
@@ -37,6 +37,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
 /* line disciplines */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sh/timex.h linux-2.4.20/include/asm-sh/timex.h
--- linux-2.4.19/include/asm-sh/timex.h	2001-01-04 21:19:13.000000000 +0000
+++ linux-2.4.20/include/asm-sh/timex.h	2002-10-29 11:18:31.000000000 +0000
@@ -21,4 +21,7 @@
 	return 0;
 }
 
+#define vxtime_lock()		do {} while (0)
+#define vxtime_unlock()		do {} while (0)
+
 #endif /* __ASM_SH_TIMEX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/btfixup.h linux-2.4.20/include/asm-sparc/btfixup.h
--- linux-2.4.19/include/asm-sparc/btfixup.h	1998-04-15 00:44:23.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/btfixup.h	2002-10-29 11:18:40.000000000 +0000
@@ -16,7 +16,22 @@
 extern unsigned int ___illegal_use_of_BTFIXUP_SETHI_in_module(void);
 extern unsigned int ___illegal_use_of_BTFIXUP_HALF_in_module(void);
 extern unsigned int ___illegal_use_of_BTFIXUP_INT_in_module(void);
-#endif
+
+#define BTFIXUP_SIMM13(__name) ___illegal_use_of_BTFIXUP_SIMM13_in_module()
+#define BTFIXUP_HALF(__name) ___illegal_use_of_BTFIXUP_HALF_in_module()
+#define BTFIXUP_SETHI(__name) ___illegal_use_of_BTFIXUP_SETHI_in_module()
+#define BTFIXUP_INT(__name) ___illegal_use_of_BTFIXUP_INT_in_module()
+#define BTFIXUP_BLACKBOX(__name) ___illegal_use_of_BTFIXUP_BLACKBOX_in_module
+
+#else
+
+#define BTFIXUP_SIMM13(__name) ___sf_##__name()
+#define BTFIXUP_HALF(__name) ___af_##__name()
+#define BTFIXUP_SETHI(__name) ___hf_##__name()
+#define BTFIXUP_INT(__name) ((unsigned int)&___i_##__name)
+/* This must be written in assembly and present in a sethi */
+#define BTFIXUP_BLACKBOX(__name) ___b_##__name
+#endif /* MODULE */
 
 /* Fixup call xx */
 
@@ -30,12 +45,6 @@
 
 #define BTFIXUPDEF_BLACKBOX(__name)							\
 	extern unsigned ___bs_##__name[2];
-#ifdef MODULE
-#define BTFIXUP_BLACKBOX(__name) ___illegal_use_of_BTFIXUP_BLACKBOX_in_module
-#else
-/* This must be written in assembly and present in a sethi */
-#define BTFIXUP_BLACKBOX(__name) ___b_##__name
-#endif
 
 /* Put bottom 13bits into some register variable */
 
@@ -55,11 +64,6 @@
 		__asm__ ("or %%g0, ___s_" #__name "__btset_" #__val ", %0" : "=r"(ret));\
 		return ret;								\
 	}
-#ifdef MODULE
-#define BTFIXUP_SIMM13(__name) ___illegal_use_of_BTFIXUP_SIMM13_in_module()
-#else
-#define BTFIXUP_SIMM13(__name) ___sf_##__name()
-#endif
 
 /* Put either bottom 13 bits, or upper 22 bits into some register variable
  * (depending on the value, this will lead into sethi FIX, reg; or
@@ -82,11 +86,6 @@
 		__asm__ ("or %%g0, ___a_" #__name "__btset_" #__val ", %0" : "=r"(ret));\
 		return ret;								\
 	}
-#ifdef MODULE
-#define BTFIXUP_HALF(__name) ___illegal_use_of_BTFIXUP_HALF_in_module()
-#else
-#define BTFIXUP_HALF(__name) ___af_##__name()
-#endif
 
 /* Put upper 22 bits into some register variable */
 
@@ -107,22 +106,12 @@
 			 "=r"(ret));							\
 		return ret;								\
 	}
-#ifdef MODULE
-#define BTFIXUP_SETHI(__name) ___illegal_use_of_BTFIXUP_SETHI_in_module()
-#else
-#define BTFIXUP_SETHI(__name) ___hf_##__name()
-#endif
 
 /* Put a full 32bit integer into some register variable */
 
 #define BTFIXUPDEF_INT(__name)								\
 	extern unsigned char ___i_##__name;						\
 	extern unsigned ___is_##__name[2];
-#ifdef MODULE
-#define BTFIXUP_INT(__name) ___illegal_use_of_BTFIXUP_INT_in_module()
-#else
-#define BTFIXUP_INT(__name) ((unsigned int)&___i_##__name)
-#endif
 
 #define BTFIXUPCALL_NORM	0x00000000			/* Always call */
 #define BTFIXUPCALL_NOP		0x01000000			/* Possibly optimize to nop */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/clock.h linux-2.4.20/include/asm-sparc/clock.h
--- linux-2.4.19/include/asm-sparc/clock.h	1996-11-09 08:29:13.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/clock.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,11 +0,0 @@
-/* $Id: clock.h,v 1.3 1995/11/25 02:31:25 davem Exp $
- * clock.h:  Definitions for clock operations on the Sparc.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-#ifndef _SPARC_CLOCK_H
-#define _SPARC_CLOCK_H
-
-/* Foo for now. */
-
-#endif /* !(_SPARC_CLOCK_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/eeprom.h linux-2.4.20/include/asm-sparc/eeprom.h
--- linux-2.4.19/include/asm-sparc/eeprom.h	1996-11-09 08:29:21.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/eeprom.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,9 +0,0 @@
-/* $Id: eeprom.h,v 1.3 1995/11/25 02:31:38 davem Exp $
- * eeprom.h:  Definitions for the Sun eeprom.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-/* The EEPROM and the Mostek Mk48t02 use the same IO address space
- * for their registers/data areas.  The IDPROM lives here too.
- */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/floppy.h linux-2.4.20/include/asm-sparc/floppy.h
--- linux-2.4.19/include/asm-sparc/floppy.h	2001-10-25 20:53:55.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/floppy.h	2002-10-29 11:18:31.000000000 +0000
@@ -217,11 +217,6 @@
 unsigned long pdma_areasize;
 
 /* Common routines to all controller types on the Sparc. */
-static __inline__ void virtual_dma_init(void)
-{
-	/* nothing... */
-}
-
 static __inline__ void sun_fd_disable_dma(void)
 {
 	doing_pdma = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/highmem.h linux-2.4.20/include/asm-sparc/highmem.h
--- linux-2.4.19/include/asm-sparc/highmem.h	2001-10-17 21:16:39.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/highmem.h	2002-10-29 11:18:51.000000000 +0000
@@ -20,15 +20,16 @@
 
 #ifdef __KERNEL__
 
-#include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/vaddrs.h>
 #include <asm/kmap_types.h>
-#include <asm/pgtable.h>
 
 /* undef for production */
 #define HIGHMEM_DEBUG 1
 
+/* in mm/highmem.c */
+extern void *kmap_high(struct page *page);
+extern void kunmap_high(struct page *page);
+
 /* declarations for highmem.c */
 extern unsigned long highstart_pfn, highend_pfn;
 
@@ -36,6 +37,12 @@
 extern pgprot_t kmap_prot;
 extern pte_t *pkmap_page_table;
 
+/* This gets set in {srmmu,sun4c}_paging_init() */
+extern unsigned long fix_kmap_begin;
+
+/* Only used and set with srmmu? */
+extern unsigned long pkmap_base;
+
 extern void kmap_init(void) __init;
 
 /*
@@ -45,12 +52,13 @@
  */
 #define LAST_PKMAP 1024
 
-#define LAST_PKMAP_MASK (LAST_PKMAP-1)
-#define PKMAP_NR(virt)  ((virt-PKMAP_BASE) >> PAGE_SHIFT)
-#define PKMAP_ADDR(nr)  (PKMAP_BASE + ((nr) << PAGE_SHIFT))
-
-extern void *kmap_high(struct page *page);
-extern void kunmap_high(struct page *page);
+#define LAST_PKMAP_MASK		(LAST_PKMAP - 1)
+#define PKMAP_NR(virt)		((virt - pkmap_base) >> PAGE_SHIFT)
+#define PKMAP_ADDR(nr)		(pkmap_base + ((nr) << PAGE_SHIFT))
+
+/* in arch/sparc/mm/highmem.c */
+void *kmap_atomic(struct page *page, enum km_type type);
+void kunmap_atomic(void *kvaddr, enum km_type type);
 
 static inline void *kmap(struct page *page)
 {
@@ -70,78 +78,6 @@
 	kunmap_high(page);
 }
 
-/*
- * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap
- * gives a more generic (and caching) interface. But kmap_atomic can
- * be used in IRQ contexts, so in some (very limited) cases we need
- * it.
- */
-static inline void *kmap_atomic(struct page *page, enum km_type type)
-{
-	unsigned long idx;
-	unsigned long vaddr;
-
-	if (page < highmem_start_page)
-		return page_address(page);
-
-	idx = type + KM_TYPE_NR*smp_processor_id();
-	vaddr = FIX_KMAP_BEGIN + idx * PAGE_SIZE;
-
-/* XXX Fix - Anton */
-#if 0
-	__flush_cache_one(vaddr);
-#else
-	flush_cache_all();
-#endif
-
-#if HIGHMEM_DEBUG
-	if (!pte_none(*(kmap_pte+idx)))
-		BUG();
-#endif
-	set_pte(kmap_pte+idx, mk_pte(page, kmap_prot));
-/* XXX Fix - Anton */
-#if 0
-	__flush_tlb_one(vaddr);
-#else
-	flush_tlb_all();
-#endif
-
-	return (void*) vaddr;
-}
-
-static inline void kunmap_atomic(void *kvaddr, enum km_type type)
-{
-	unsigned long vaddr = (unsigned long) kvaddr;
-	unsigned long idx = type + KM_TYPE_NR*smp_processor_id();
-
-	if (vaddr < FIX_KMAP_BEGIN) // FIXME
-		return;
-
-	if (vaddr != FIX_KMAP_BEGIN + idx * PAGE_SIZE)
-		BUG();
-
-/* XXX Fix - Anton */
-#if 0
-	__flush_cache_one(vaddr);
-#else
-	flush_cache_all();
-#endif
-
-#ifdef HIGHMEM_DEBUG
-	/*
-	 * force other mappings to Oops if they'll try to access
-	 * this pte without first remap it
-	 */
-	pte_clear(kmap_pte+idx);
-/* XXX Fix - Anton */
-#if 0
-	__flush_tlb_one(vaddr);
-#else
-	flush_tlb_all();
-#endif
-#endif
-}
-
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_HIGHMEM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/io.h linux-2.4.20/include/asm-sparc/io.h
--- linux-2.4.19/include/asm-sparc/io.h	2001-11-13 17:16:05.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/io.h	2002-10-29 11:18:33.000000000 +0000
@@ -13,6 +13,7 @@
 
 #define virt_to_bus virt_to_phys
 #define bus_to_virt phys_to_virt
+#define page_to_phys(page)     ((((page) - mem_map) << PAGE_SHIFT)+phys_base)
 
 static __inline__ u32 flip_dword (u32 d)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/kmap_types.h linux-2.4.20/include/asm-sparc/kmap_types.h
--- linux-2.4.19/include/asm-sparc/kmap_types.h	2001-09-17 20:16:30.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/kmap_types.h	2002-10-29 11:18:34.000000000 +0000
@@ -3,10 +3,11 @@
 
 enum km_type {
 	KM_BOUNCE_READ,
-	KM_SKB_DATA,
+	KM_SKB_SUNRPC_DATA,
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
+	KM_BH_IRQ,
 	KM_TYPE_NR
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/pci.h linux-2.4.20/include/asm-sparc/pci.h
--- linux-2.4.19/include/asm-sparc/pci.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/pci.h	2002-10-29 11:18:49.000000000 +0000
@@ -27,6 +27,12 @@
 /* Dynamic DMA mapping stuff.
  */
 
+/* The PCI address space does not equal the physical memory
+ * address space.  The networking and block device layers use
+ * this boolean for bounce buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS     (0)
+
 #include <asm/scatterlist.h>
 
 struct pci_dev;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/pconf.h linux-2.4.20/include/asm-sparc/pconf.h
--- linux-2.4.19/include/asm-sparc/pconf.h	1996-11-10 23:16:16.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/pconf.h	2002-10-29 11:18:35.000000000 +0000
@@ -8,7 +8,6 @@
 #ifndef _SPARC_PCONF_H
 #define _SPARC_PCONF_H
 
-#include <linux/fs.h>
 #include <linux/limits.h>
 
 #define _PCONF_LINK       1 /* Max number of links to an object        */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/semaphore.h linux-2.4.20/include/asm-sparc/semaphore.h
--- linux-2.4.19/include/asm-sparc/semaphore.h	2001-10-30 23:08:11.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/semaphore.h	2002-10-29 11:18:51.000000000 +0000
@@ -213,6 +213,11 @@
 	: "g3", "g4", "g7", "memory", "cc");
 }	
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* !(_SPARC_SEMAPHORE_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/socket.h linux-2.4.20/include/asm-sparc/socket.h
--- linux-2.4.19/include/asm-sparc/socket.h	2001-06-21 04:00:55.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/socket.h	2002-10-29 11:18:32.000000000 +0000
@@ -4,7 +4,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	0xffff
 
 #define SO_DEBUG	0x0001
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/termbits.h linux-2.4.20/include/asm-sparc/termbits.h
--- linux-2.4.19/include/asm-sparc/termbits.h	2000-02-22 00:32:27.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/termbits.h	2002-10-29 11:18:35.000000000 +0000
@@ -210,6 +210,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 #define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/timex.h linux-2.4.20/include/asm-sparc/timex.h
--- linux-2.4.19/include/asm-sparc/timex.h	1999-03-11 00:53:37.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/timex.h	2002-10-29 11:18:33.000000000 +0000
@@ -17,4 +17,7 @@
 extern cycles_t cacheflush_time;
 #define get_cycles()	(0)
 
+#define vxtime_lock()		do {} while (0)
+#define vxtime_unlock()		do {} while (0)
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/types.h linux-2.4.20/include/asm-sparc/types.h
--- linux-2.4.19/include/asm-sparc/types.h	2000-02-01 07:37:19.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/types.h	2002-10-29 11:18:48.000000000 +0000
@@ -46,6 +46,7 @@
 #define BITS_PER_LONG 32
 
 typedef u32 dma_addr_t;
+typedef u32 dma64_addr_t;
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/ultra.h linux-2.4.20/include/asm-sparc/ultra.h
--- linux-2.4.19/include/asm-sparc/ultra.h	1996-11-09 08:30:21.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/ultra.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,52 +0,0 @@
-/* $Id: ultra.h,v 1.2 1995/11/25 02:33:10 davem Exp $
- * ultra.h: Definitions and defines for the TI V9 UltraSparc.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef _SPARC_ULTRA_H
-#define _SPARC_ULTRA_H
-
-/* Spitfire MMU control register:
- *
- * ----------------------------------------------------------
- * |        | IMPL  | VERS  |     |  MID  |                 |
- * ----------------------------------------------------------
- *  64        31-28   27-24  23-22  21-17   16             0
- *
- * IMPL: Implementation of this Spitfire.
- * VERS: Version of this Spitfire.
- * MID: Module ID of this processor.
- */
-
-#define SPITFIRE_MIDMASK     0x00000000003e0000
-
-/* Spitfire Load Store Unit control register:
- *
- * ---------------------------------------------------------------------
- * | RSV | PWR | PWW | VWR | VWW | RSV | PMASK | DME | IME | DCE | ICE |
- * ---------------------------------------------------------------------
- *  63-25  24    23     22    21    20   19-4      3     2     1     0
- *
- * PWR: Physical Watchpoint Read enable: 0=off 1=on
- * PWW: Physical Watchpoint Write enable: 0=off 1=on
- * VWR: Virtual Watchpoint Read enable: 0=off 1=on
- * VWW: Virtual Watchpoint Write enable: 0=off 1=on
- * PMASK: Parity MASK  ???
- * DME: Data MMU Enable: 0=off 1=on
- * IME: Instruction MMU Enable: 0=off 1=on
- * DCE: Data Cache Enable: 0=off 1=on
- * ICE: Instruction Cache Enable: 0=off 1=on
- */
-
-#define SPITFIRE_LSU_PWR      0x01000000
-#define SPITFIRE_LSU_PWW      0x00800000
-#define SPITFIRE_LSU_VWR      0x00400000
-#define SPITFIRE_LSU_VWW      0x00200000
-#define SPITFIRE_LSU_PMASK    0x000ffff0
-#define SPITFIRE_LSU_DME      0x00000008
-#define SPITFIRE_LSU_IME      0x00000004
-#define SPITFIRE_LSU_DCE      0x00000002
-#define SPITFIRE_LSU_ICE      0x00000001
-
-#endif /* !(_SPARC_ULTRA_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/vac-ops.h linux-2.4.20/include/asm-sparc/vac-ops.h
--- linux-2.4.19/include/asm-sparc/vac-ops.h	1998-04-15 00:44:24.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/vac-ops.h	2002-10-29 11:18:35.000000000 +0000
@@ -107,8 +107,6 @@
 
 extern struct sun4c_vac_props sun4c_vacinfo;
 
-extern void sun4c_flush_all(void);
-
 /* sun4c_enable_vac() enables the sun4c virtual address cache. */
 extern __inline__ void sun4c_enable_vac(void)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc/vaddrs.h linux-2.4.20/include/asm-sparc/vaddrs.h
--- linux-2.4.19/include/asm-sparc/vaddrs.h	2001-07-06 23:46:22.000000000 +0000
+++ linux-2.4.20/include/asm-sparc/vaddrs.h	2002-10-29 11:18:32.000000000 +0000
@@ -14,23 +14,26 @@
 
 #define SRMMU_MAXMEM		0x0c000000
 
-#define SRMMU_NOCACHE_VADDR	0xfc000000	/* KERNBASE + SRMMU_MAXMEM */
-/* XXX Make this dynamic based on ram size - Anton */
-#define SRMMU_NOCACHE_NPAGES	256
-#define SRMMU_NOCACHE_SIZE	(SRMMU_NOCACHE_NPAGES * PAGE_SIZE)
-#define SRMMU_NOCACHE_END	(SRMMU_NOCACHE_VADDR + SRMMU_NOCACHE_SIZE)
+#define SRMMU_NOCACHE_VADDR	(KERNBASE + SRMMU_MAXMEM)
+				/* = 0x0fc000000 */
 
-#define FIX_KMAP_BEGIN		0xfc100000
-#define FIX_KMAP_END (FIX_KMAP_BEGIN + ((KM_TYPE_NR*NR_CPUS)-1)*PAGE_SIZE)
-
-#define PKMAP_BASE		0xfc140000
-#define PKMAP_BASE_END		(PKMAP_BASE+LAST_PKMAP*PAGE_SIZE)
+/* The following constant is used in mm/srmmu.c::srmmu_nocache_calcsize()
+ * to determine the amount of memory that will be reserved as nocache:
+ *
+ * 256 pages will be taken as nocache per each
+ * SRMMU_NOCACHE_ALCRATIO MB of system memory.
+ *
+ * limits enforced:	nocache minimum = 256 pages
+ *			nocache maximum = 1280 pages
+ */
+#define SRMMU_NOCACHE_ALCRATIO	64	/* 256 pages per 64MB of system RAM */
 
 #define SUN4M_IOBASE_VADDR	0xfd000000 /* Base for mapping pages */
 #define IOBASE_VADDR		0xfe000000
 #define IOBASE_END		0xfe300000
 
 #define VMALLOC_START		0xfe300000
+
 /* XXX Alter this when I get around to fixing sun4c - Anton */
 #define VMALLOC_END		0xffc00000
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc64/asi.h linux-2.4.20/include/asm-sparc64/asi.h
--- linux-2.4.19/include/asm-sparc64/asi.h	2001-04-12 19:10:25.000000000 +0000
+++ linux-2.4.20/include/asm-sparc64/asi.h	2002-10-29 11:18:34.000000000 +0000
@@ -40,6 +40,7 @@
 #define ASI_WCACHE_DATA		0x39 /* (III) WCache data RAM diag		*/
 #define ASI_WCACHE_TAG		0x3a /* (III) WCache tag RAM diag		*/
 #define ASI_WCACHE_SNOOP_TAG	0x3b /* (III) WCache snoop tag RAM diag		*/
+#define ASI_SRAM_FAST_INIT	0x40 /* (III+) Fast SRAM init			*/
 #define ASI_DCACHE_INVALIDATE	0x42 /* (III) DCache Invalidate diag		*/
 #define ASI_DCACHE_UTAG		0x43 /* (III) DCache uTag diag			*/
 #define ASI_DCACHE_SNOOP_TAG	0x44 /* (III) DCache snoop tag RAM diag		*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc64/dcr.h linux-2.4.20/include/asm-sparc64/dcr.h
--- linux-2.4.19/include/asm-sparc64/dcr.h	2001-03-26 02:14:21.000000000 +0000
+++ linux-2.4.20/include/asm-sparc64/dcr.h	2002-10-29 11:18:50.000000000 +0000
@@ -2,11 +2,13 @@
 #ifndef _SPARC64_DCR_H
 #define _SPARC64_DCR_H
 
-/* UltraSparc-III Dispatch Control Register, ASR 0x12 */
+/* UltraSparc-III/III+ Dispatch Control Register, ASR 0x12 */
+#define DCR_DPE		0x0000000000001000 /* III+: D$ Parity Error Enable	*/
 #define DCR_OBS		0x0000000000000fc0 /* Observability Bus Controls	*/
 #define DCR_BPE		0x0000000000000020 /* Branch Predict Enable		*/
 #define DCR_RPE		0x0000000000000010 /* Return Address Prediction Enable	*/
 #define DCR_SI		0x0000000000000008 /* Single Instruction Disable	*/
+#define DCR_IPE		0x0000000000000004 /* III+: I$ Parity Error Enable	*/
 #define DCR_IFPOE	0x0000000000000002 /* IRQ FP Operation Enable		*/
 #define DCR_MS		0x0000000000000001 /* Multi-Scalar dispatch		*/
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc64/elf.h linux-2.4.20/include/asm-sparc64/elf.h
--- linux-2.4.19/include/asm-sparc64/elf.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-sparc64/elf.h	2002-10-29 11:18:36.000000000 +0000
@@ -90,7 +90,8 @@
 #define ELF_HWCAP	((HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \
 			  HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV | \
 			  HWCAP_SPARC_V9) | \
-			 ((tlb_type == cheetah) ? HWCAP_SPARC_ULTRA3 : 0))
+			 ((tlb_type == cheetah || tlb_type == cheetah_plus) ? \
+			  HWCAP_SPARC_ULTRA3 : 0))
 
 /* This yields a string that ld.so will use to load implementation
    specific libraries for optimization.  This is more specific in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc64/head.h linux-2.4.20/include/asm-sparc64/head.h
--- linux-2.4.19/include/asm-sparc64/head.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-sparc64/head.h	2002-10-29 11:18:37.000000000 +0000
@@ -8,4 +8,41 @@
 
 #define	PTREGS_OFF	(STACK_BIAS + REGWIN_SZ)
 
+#define __CHEETAH_ID	0x003e0014
+
+#define CHEETAH_MANUF		0x003e
+#define CHEETAH_IMPL		0x0014
+#define CHEETAH_PLUS_IMPL	0x0015
+
+#define BRANCH_IF_CHEETAH_BASE(tmp1,tmp2,label)	\
+	rdpr	%ver, %tmp1;			\
+	sethi	%hi(__CHEETAH_ID), %tmp2;	\
+	srlx	%tmp1, 32, %tmp1;		\
+	or	%tmp2, %lo(__CHEETAH_ID), %tmp2;\
+	cmp	%tmp1, %tmp2;			\
+	be,pn	%icc, label;			\
+	 nop;
+
+#define BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(tmp1,tmp2,label)	\
+	rdpr	%ver, %tmp1;			\
+	srlx	%tmp1, (32 + 16), %tmp2;	\
+	cmp	%tmp2, CHEETAH_MANUF;		\
+	bne,pt	%xcc, 99f;			\
+	 sllx	%tmp1, 16, %tmp1;		\
+	srlx	%tmp1, (32 + 16), %tmp2;	\
+	cmp	%tmp2, CHEETAH_PLUS_IMPL;	\
+	bgeu,pt	%xcc, label;			\
+99:	 nop;
+
+#define BRANCH_IF_ANY_CHEETAH(tmp1,tmp2,label)	\
+	rdpr	%ver, %tmp1;			\
+	srlx	%tmp1, (32 + 16), %tmp2;	\
+	cmp	%tmp2, CHEETAH_MANUF;		\
+	bne,pt	%xcc, 99f;			\
+	 sllx	%tmp1, 16, %tmp1;		\
+	srlx	%tmp1, (32 + 16), %tmp2;	\
+	cmp	%tmp2, CHEETAH_IMPL;		\
+	bgeu,pt	%xcc, label;			\
+99:	 nop;
+
 #endif /* !(_SPARC64_HEAD_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc64/oplib.h linux-2.4.20/include/asm-sparc64/oplib.h
--- linux-2.4.19/include/asm-sparc64/oplib.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.20/include/asm-sparc64/oplib.h	2002-10-29 11:18:49.000000000 +0000
@@ -113,6 +113,9 @@
  */
 extern void prom_halt(void) __attribute__ ((noreturn));
 
+/* Halt and power-off the machine. */
+extern void prom_halt_power_off(void) __attribute__ ((noreturn));
+
 /* Set the PROM 'sync' callback function to the passed function pointer.
  * When the user gives the 'sync' command at the prom prompt while the
  * kernel is still active, the prom will call this routine.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc64/pconf.h linux-2.4.20/include/asm-sparc64/pconf.h
--- linux-2.4.19/include/asm-sparc64/pconf.h	1996-12-13 09:37:47.000000000 +0000
+++ linux-2.4.20/include/asm-sparc64/pconf.h	2002-10-29 11:18:32.000000000 +0000
@@ -8,7 +8,6 @@
 #ifndef _SPARC64_PCONF_H
 #define _SPARC64_PCONF_H
 
-#include <linux/fs.h>
 #include <linux/limits.h>
 
 #define _PCONF_LINK       1 /* Max number of links to an object        */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc64/rwsem.h linux-2.4.20/include/asm-sparc64/rwsem.h
--- linux-2.4.19/include/asm-sparc64/rwsem.h	2001-12-21 17:42:03.000000000 +0000
+++ linux-2.4.20/include/asm-sparc64/rwsem.h	2002-10-29 11:18:33.000000000 +0000
@@ -79,6 +79,31 @@
 		: "g5", "g7", "memory", "cc");
 }
 
+static __inline__ int __down_read_trylock(struct rw_semaphore *sem)
+{
+	int result;
+
+	__asm__ __volatile__(
+		"! beginning __down_read_trylock\n"
+		"1:\tlduw	[%1], %%g5\n\t"
+		"add		%%g5, 1, %%g7\n\t"
+		"cmp		%%g7, 0\n\t"
+		"bl,pn		%%icc, 2f\n\t"
+		" mov		0, %0\n\t"
+		"cas		[%1], %%g5, %%g7\n\t"
+		"cmp		%%g5, %%g7\n\t"
+		"bne,pn		%%icc, 1b\n\t"
+		" mov		1, %0\n\t"
+		"membar		#StoreLoad | #StoreStore\n"
+		"2:\n\t"
+		"! ending __down_read_trylock"
+		: "=&r" (result)
+                : "r" (sem)
+		: "g5", "g7", "memory", "cc");
+
+	return result;
+}
+
 static inline void __down_write(struct rw_semaphore *sem)
 {
 	__asm__ __volatile__(
@@ -111,6 +136,33 @@
 		: "g1", "g5", "g7", "memory", "cc");
 }
 
+static __inline__ int __down_write_trylock(struct rw_semaphore *sem)
+{
+	int result;
+
+	__asm__ __volatile__(
+		"! beginning __down_write_trylock\n\t"
+		"sethi		%%hi(%2), %%g1\n\t"
+		"or		%%g1, %%lo(%2), %%g1\n"
+		"1:\tlduw	[%1], %%g5\n\t"
+		"cmp		%%g5, 0\n\t"
+		"bne,pn		%%icc, 2f\n\t"
+		" mov		0, %0\n\t"
+		"add		%%g5, %%g1, %%g7\n\t"
+		"cas		[%1], %%g5, %%g7\n\t"
+		"cmp		%%g5, %%g7\n\t"
+		"bne,pn		%%icc, 1b\n\t"
+		" mov		1, %0\n\t"
+		"membar		#StoreLoad | #StoreStore\n"
+		"2:\n\t"
+		"! ending __down_write_trylock"
+		: "=&r" (result)
+		: "r" (sem), "i" (RWSEM_ACTIVE_WRITE_BIAS)
+		: "g1", "g5", "g7", "memory", "cc");
+
+	return result;
+}
+
 static inline void __up_read(struct rw_semaphore *sem)
 {
 	__asm__ __volatile__(
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc64/semaphore.h linux-2.4.20/include/asm-sparc64/semaphore.h
--- linux-2.4.19/include/asm-sparc64/semaphore.h	2001-12-21 17:42:03.000000000 +0000
+++ linux-2.4.20/include/asm-sparc64/semaphore.h	2002-10-29 11:18:36.000000000 +0000
@@ -226,6 +226,11 @@
 	: "g5", "g7", "memory", "cc");
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* !(_SPARC64_SEMAPHORE_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc64/smp.h linux-2.4.20/include/asm-sparc64/smp.h
--- linux-2.4.19/include/asm-sparc64/smp.h	2001-12-21 17:42:03.000000000 +0000
+++ linux-2.4.20/include/asm-sparc64/smp.h	2002-10-29 11:18:36.000000000 +0000
@@ -86,7 +86,7 @@
 
 extern __inline__ int hard_smp_processor_id(void)
 {
-	if (tlb_type == cheetah) {
+	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		unsigned long safari_config;
 		__asm__ __volatile__("ldxa [%%g0] %1, %0"
 				     : "=r" (safari_config)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc64/socket.h linux-2.4.20/include/asm-sparc64/socket.h
--- linux-2.4.19/include/asm-sparc64/socket.h	2001-06-21 04:00:55.000000000 +0000
+++ linux-2.4.20/include/asm-sparc64/socket.h	2002-10-29 11:18:36.000000000 +0000
@@ -4,7 +4,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	0xffff
 
 #define SO_DEBUG	0x0001
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc64/spitfire.h linux-2.4.20/include/asm-sparc64/spitfire.h
--- linux-2.4.19/include/asm-sparc64/spitfire.h	2001-12-21 17:42:03.000000000 +0000
+++ linux-2.4.20/include/asm-sparc64/spitfire.h	2002-10-29 11:18:35.000000000 +0000
@@ -22,6 +22,7 @@
 #define TSB_EXTENSION_P		0x0000000000000048 /* Ultra-III and later		*/
 #define TSB_EXTENSION_S		0x0000000000000050 /* Ultra-III and later, D-TLB only	*/
 #define TSB_EXTENSION_N		0x0000000000000058 /* Ultra-III and later		*/
+#define TLB_TAG_ACCESS_EXT	0x0000000000000060 /* Ultra-III+ and later		*/
 
 /* These registers only exist as one entity, and are accessed
  * via ASI_DMMU only.
@@ -38,12 +39,13 @@
 
 enum ultra_tlb_layout {
 	spitfire = 0,
-	cheetah = 1
+	cheetah = 1,
+	cheetah_plus = 2,
 };
 
 extern enum ultra_tlb_layout tlb_type;
 
-#define SPARC64_USE_STICK	(tlb_type == cheetah)
+#define SPARC64_USE_STICK	(tlb_type != spitfire)
 
 #define CHEETAH_HIGHEST_LOCKED_TLBENT	(16 - 1)
 
@@ -433,35 +435,35 @@
 			       "i" (ASI_ITLB_DATA_ACCESS));
 }
 
-extern __inline__ unsigned long cheetah_get_dtlb_data(int entry)
+extern __inline__ unsigned long cheetah_get_dtlb_data(int entry, int tlb)
 {
 	unsigned long data;
 
 	__asm__ __volatile__("ldxa	[%1] %2, %%g0\n\t"
 			     "ldxa	[%1] %2, %0"
 			     : "=r" (data)
-			     : "r" ((2 << 16) | (entry << 3)), "i" (ASI_DTLB_DATA_ACCESS));
+			     : "r" ((tlb << 16) | (entry << 3)), "i" (ASI_DTLB_DATA_ACCESS));
 
 	return data;
 }
 
-extern __inline__ unsigned long cheetah_get_dtlb_tag(int entry)
+extern __inline__ unsigned long cheetah_get_dtlb_tag(int entry, int tlb)
 {
 	unsigned long tag;
 
 	__asm__ __volatile__("ldxa	[%1] %2, %0"
 			     : "=r" (tag)
-			     : "r" ((2 << 16) | (entry << 3)), "i" (ASI_DTLB_TAG_READ));
+			     : "r" ((tlb << 16) | (entry << 3)), "i" (ASI_DTLB_TAG_READ));
 	return tag;
 }
 
-extern __inline__ void cheetah_put_dtlb_data(int entry, unsigned long data)
+extern __inline__ void cheetah_put_dtlb_data(int entry, unsigned long data, int tlb)
 {
 	__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
 			     "membar	#Sync"
 			     : /* No outputs */
 			     : "r" (data),
-			       "r" ((2 << 16) | (entry << 3)),
+			       "r" ((tlb << 16) | (entry << 3)),
 			       "i" (ASI_DTLB_DATA_ACCESS));
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc64/termbits.h linux-2.4.20/include/asm-sparc64/termbits.h
--- linux-2.4.19/include/asm-sparc64/termbits.h	2000-02-22 00:32:27.000000000 +0000
+++ linux-2.4.20/include/asm-sparc64/termbits.h	2002-10-29 11:18:34.000000000 +0000
@@ -211,6 +211,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 #define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-sparc64/timex.h linux-2.4.20/include/asm-sparc64/timex.h
--- linux-2.4.19/include/asm-sparc64/timex.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/asm-sparc64/timex.h	2002-10-29 11:18:47.000000000 +0000
@@ -20,4 +20,7 @@
 	ret; \
 })
 
+#define vxtime_lock()		do {} while (0)
+#define vxtime_unlock()		do {} while (0)
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/a.out.h linux-2.4.20/include/asm-x86_64/a.out.h
--- linux-2.4.19/include/asm-x86_64/a.out.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/a.out.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,30 @@
+#ifndef __X8664_A_OUT_H__
+#define __X8664_A_OUT_H__
+
+
+/* Note. a.out is not supported in 64bit mode. This is just here to 
+   still let some old things compile. */ 
+
+struct exec
+{
+  unsigned long a_info;		/* Use macros N_MAGIC, etc for access */
+  unsigned a_text;		/* length of text, in bytes */
+  unsigned a_data;		/* length of data, in bytes */
+  unsigned a_bss;		/* length of uninitialized data area for file, in bytes */
+  unsigned a_syms;		/* length of symbol table data in file, in bytes */
+  unsigned a_entry;		/* start address */
+  unsigned a_trsize;		/* length of relocation info for text, in bytes */
+  unsigned a_drsize;		/* length of relocation info for data, in bytes */
+};
+
+#define N_TRSIZE(a)	((a).a_trsize)
+#define N_DRSIZE(a)	((a).a_drsize)
+#define N_SYMSIZE(a)	((a).a_syms)
+
+#ifdef __KERNEL__
+
+#define STACK_TOP	TASK_SIZE
+
+#endif
+
+#endif /* __A_OUT_GNU_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/apic.h linux-2.4.20/include/asm-x86_64/apic.h
--- linux-2.4.19/include/asm-x86_64/apic.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/apic.h	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,105 @@
+#ifndef __ASM_APIC_H
+#define __ASM_APIC_H
+
+#include <linux/config.h>
+#include <linux/pm.h>
+#include <asm/apicdef.h>
+#include <asm/system.h>
+
+#ifdef CONFIG_X86_LOCAL_APIC
+
+#define APIC_DEBUG 0
+
+#if APIC_DEBUG
+#define Dprintk(x...) printk(x)
+#else
+#define Dprintk(x...)
+#endif
+
+/*
+ * Basic functions accessing APICs.
+ */
+
+static __inline void apic_write(unsigned long reg, unsigned int v)
+{
+	*((volatile unsigned int *)(APIC_BASE+reg)) = v;
+	barrier();
+}
+
+static __inline void apic_write_atomic(unsigned long reg, unsigned int v)
+{
+	xchg((volatile unsigned int *)(APIC_BASE+reg), v);
+}
+
+static __inline unsigned int apic_read(unsigned long reg)
+{
+	return *((volatile unsigned int *)(APIC_BASE+reg));
+}
+
+static __inline__ void apic_wait_icr_idle(void)
+{
+	while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY );
+}
+
+#ifdef CONFIG_X86_GOOD_APIC
+# define FORCE_READ_AROUND_WRITE 0
+# define apic_read_around(x)
+# define apic_write_around(x,y) apic_write((x),(y))
+#else
+# define FORCE_READ_AROUND_WRITE 1
+# define apic_read_around(x) apic_read(x)
+# define apic_write_around(x,y) apic_write_atomic((x),(y))
+#endif
+
+static inline void ack_APIC_irq(void)
+{
+	/*
+	 * ack_APIC_irq() actually gets compiled as a single instruction:
+	 * - a single rmw on Pentium/82489DX
+	 * - a single write on P6+ cores (CONFIG_X86_GOOD_APIC)
+	 * ... yummie.
+	 */
+
+	/* Docs say use 0 for future compatibility */
+	apic_write_around(APIC_EOI, 0);
+}
+
+extern int get_maxlvt (void);
+extern void clear_local_APIC (void);
+extern void connect_bsp_APIC (void);
+extern void disconnect_bsp_APIC (void);
+extern void disable_local_APIC (void);
+extern int verify_local_APIC (void);
+extern void cache_APIC_registers (void);
+extern void sync_Arb_IDs (void);
+extern void init_bsp_APIC (void);
+extern void setup_local_APIC (void);
+extern void init_apic_mappings (void);
+extern void smp_local_timer_interrupt (struct pt_regs * regs);
+extern void setup_APIC_clocks (void);
+extern void setup_apic_nmi_watchdog (void);
+extern inline void nmi_watchdog_tick (struct pt_regs * regs);
+extern int APIC_init_uniprocessor (void);
+extern void disable_APIC_timer(void);
+extern void enable_APIC_timer(void);
+
+extern struct pm_dev *apic_pm_register (pm_dev_t, unsigned long, pm_callback);
+extern void apic_pm_unregister (struct pm_dev*);
+
+extern unsigned int apic_timer_irqs [NR_CPUS];
+extern int check_nmi_watchdog (void);
+extern void enable_NMI_through_LVT0 (void * dummy);
+
+extern unsigned int nmi_watchdog;
+#define NMI_NONE	0
+#define NMI_IO_APIC	1
+#define NMI_LOCAL_APIC	2
+#define NMI_INVALID	3
+
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+#define clustered_apic_mode 0
+#define esr_disable 0
+extern unsigned boot_cpu_id;
+
+#endif /* __ASM_APIC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/apicdef.h linux-2.4.20/include/asm-x86_64/apicdef.h
--- linux-2.4.19/include/asm-x86_64/apicdef.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/apicdef.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,363 @@
+#ifndef __ASM_APICDEF_H
+#define __ASM_APICDEF_H
+
+/*
+ * Constants for various Intel APICs. (local APIC, IOAPIC, etc.)
+ *
+ * Alan Cox <Alan.Cox@linux.org>, 1995.
+ * Ingo Molnar <mingo@redhat.com>, 1999, 2000
+ */
+
+#define		APIC_DEFAULT_PHYS_BASE	0xfee00000
+ 
+#define		APIC_ID		0x20
+#define			APIC_ID_MASK		(0x0F<<24)
+#define			GET_APIC_ID(x)		(((x)>>24)&0x0F)
+#define		APIC_LVR	0x30
+#define			APIC_LVR_MASK		0xFF00FF
+#define			GET_APIC_VERSION(x)	((x)&0xFF)
+#define			GET_APIC_MAXLVT(x)	(((x)>>16)&0xFF)
+#define			APIC_INTEGRATED(x)	((x)&0xF0)
+#define		APIC_TASKPRI	0x80
+#define			APIC_TPRI_MASK		0xFF
+#define		APIC_ARBPRI	0x90
+#define			APIC_ARBPRI_MASK	0xFF
+#define		APIC_PROCPRI	0xA0
+#define		APIC_EOI	0xB0
+#define			APIC_EIO_ACK		0x0		/* Write this to the EOI register */
+#define		APIC_RRR	0xC0
+#define		APIC_LDR	0xD0
+#define			APIC_LDR_MASK		(0xFF<<24)
+#define			GET_APIC_LOGICAL_ID(x)	(((x)>>24)&0xFF)
+#define			SET_APIC_LOGICAL_ID(x)	(((x)<<24))
+#define			APIC_ALL_CPUS		0xFF
+#define		APIC_DFR	0xE0
+#define		APIC_SPIV	0xF0
+#define			APIC_SPIV_FOCUS_DISABLED	(1<<9)
+#define			APIC_SPIV_APIC_ENABLED		(1<<8)
+#define		APIC_ISR	0x100
+#define		APIC_TMR	0x180
+#define 	APIC_IRR	0x200
+#define 	APIC_ESR	0x280
+#define			APIC_ESR_SEND_CS	0x00001
+#define			APIC_ESR_RECV_CS	0x00002
+#define			APIC_ESR_SEND_ACC	0x00004
+#define			APIC_ESR_RECV_ACC	0x00008
+#define			APIC_ESR_SENDILL	0x00020
+#define			APIC_ESR_RECVILL	0x00040
+#define			APIC_ESR_ILLREGA	0x00080
+#define		APIC_ICR	0x300
+#define			APIC_DEST_SELF		0x40000
+#define			APIC_DEST_ALLINC	0x80000
+#define			APIC_DEST_ALLBUT	0xC0000
+#define			APIC_ICR_RR_MASK	0x30000
+#define			APIC_ICR_RR_INVALID	0x00000
+#define			APIC_ICR_RR_INPROG	0x10000
+#define			APIC_ICR_RR_VALID	0x20000
+#define			APIC_INT_LEVELTRIG	0x08000
+#define			APIC_INT_ASSERT		0x04000
+#define			APIC_ICR_BUSY		0x01000
+#define			APIC_DEST_LOGICAL	0x00800
+#define			APIC_DM_FIXED		0x00000
+#define			APIC_DM_LOWEST		0x00100
+#define			APIC_DM_SMI		0x00200
+#define			APIC_DM_REMRD		0x00300
+#define			APIC_DM_NMI		0x00400
+#define			APIC_DM_INIT		0x00500
+#define			APIC_DM_STARTUP		0x00600
+#define			APIC_DM_EXTINT		0x00700
+#define			APIC_VECTOR_MASK	0x000FF
+#define		APIC_ICR2	0x310
+#define			GET_APIC_DEST_FIELD(x)	(((x)>>24)&0xFF)
+#define			SET_APIC_DEST_FIELD(x)	((x)<<24)
+#define		APIC_LVTT	0x320
+#define		APIC_LVTPC	0x340
+#define		APIC_LVT0	0x350
+#define			APIC_LVT_TIMER_BASE_MASK	(0x3<<18)
+#define			GET_APIC_TIMER_BASE(x)		(((x)>>18)&0x3)
+#define			SET_APIC_TIMER_BASE(x)		(((x)<<18))
+#define			APIC_TIMER_BASE_CLKIN		0x0
+#define			APIC_TIMER_BASE_TMBASE		0x1
+#define			APIC_TIMER_BASE_DIV		0x2
+#define			APIC_LVT_TIMER_PERIODIC		(1<<17)
+#define			APIC_LVT_MASKED			(1<<16)
+#define			APIC_LVT_LEVEL_TRIGGER		(1<<15)
+#define			APIC_LVT_REMOTE_IRR		(1<<14)
+#define			APIC_INPUT_POLARITY		(1<<13)
+#define			APIC_SEND_PENDING		(1<<12)
+#define			GET_APIC_DELIVERY_MODE(x)	(((x)>>8)&0x7)
+#define			SET_APIC_DELIVERY_MODE(x,y)	(((x)&~0x700)|((y)<<8))
+#define				APIC_MODE_FIXED		0x0
+#define				APIC_MODE_NMI		0x4
+#define				APIC_MODE_EXINT		0x7
+#define 	APIC_LVT1	0x360
+#define		APIC_LVTERR	0x370
+#define		APIC_TMICT	0x380
+#define		APIC_TMCCT	0x390
+#define		APIC_TDCR	0x3E0
+#define			APIC_TDR_DIV_TMBASE	(1<<2)
+#define			APIC_TDR_DIV_1		0xB
+#define			APIC_TDR_DIV_2		0x0
+#define			APIC_TDR_DIV_4		0x1
+#define			APIC_TDR_DIV_8		0x2
+#define			APIC_TDR_DIV_16		0x3
+#define			APIC_TDR_DIV_32		0x8
+#define			APIC_TDR_DIV_64		0x9
+#define			APIC_TDR_DIV_128	0xA
+
+#define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
+
+#define MAX_IO_APICS 8
+
+/*
+ * the local APIC register structure, memory mapped. Not terribly well
+ * tested, but we might eventually use this one in the future - the
+ * problem why we cannot use it right now is the P5 APIC, it has an
+ * errata which cannot take 8-bit reads and writes, only 32-bit ones ...
+ */
+#define u32 unsigned int
+
+#define lapic ((volatile struct local_apic *)APIC_BASE)
+
+struct local_apic {
+
+/*000*/	struct { u32 __reserved[4]; } __reserved_01;
+
+/*010*/	struct { u32 __reserved[4]; } __reserved_02;
+
+/*020*/	struct { /* APIC ID Register */
+		u32   __reserved_1	: 24,
+			phys_apic_id	:  4,
+			__reserved_2	:  4;
+		u32 __reserved[3];
+	} id;
+
+/*030*/	const
+	struct { /* APIC Version Register */
+		u32   version		:  8,
+			__reserved_1	:  8,
+			max_lvt		:  8,
+			__reserved_2	:  8;
+		u32 __reserved[3];
+	} version;
+
+/*040*/	struct { u32 __reserved[4]; } __reserved_03;
+
+/*050*/	struct { u32 __reserved[4]; } __reserved_04;
+
+/*060*/	struct { u32 __reserved[4]; } __reserved_05;
+
+/*070*/	struct { u32 __reserved[4]; } __reserved_06;
+
+/*080*/	struct { /* Task Priority Register */
+		u32   priority	:  8,
+			__reserved_1	: 24;
+		u32 __reserved_2[3];
+	} tpr;
+
+/*090*/	const
+	struct { /* Arbitration Priority Register */
+		u32   priority	:  8,
+			__reserved_1	: 24;
+		u32 __reserved_2[3];
+	} apr;
+
+/*0A0*/	const
+	struct { /* Processor Priority Register */
+		u32   priority	:  8,
+			__reserved_1	: 24;
+		u32 __reserved_2[3];
+	} ppr;
+
+/*0B0*/	struct { /* End Of Interrupt Register */
+		u32   eoi;
+		u32 __reserved[3];
+	} eoi;
+
+/*0C0*/	struct { u32 __reserved[4]; } __reserved_07;
+
+/*0D0*/	struct { /* Logical Destination Register */
+		u32   __reserved_1	: 24,
+			logical_dest	:  8;
+		u32 __reserved_2[3];
+	} ldr;
+
+/*0E0*/	struct { /* Destination Format Register */
+		u32   __reserved_1	: 28,
+			model		:  4;
+		u32 __reserved_2[3];
+	} dfr;
+
+/*0F0*/	struct { /* Spurious Interrupt Vector Register */
+		u32	spurious_vector	:  8,
+			apic_enabled	:  1,
+			focus_cpu	:  1,
+			__reserved_2	: 22;
+		u32 __reserved_3[3];
+	} svr;
+
+/*100*/	struct { /* In Service Register */
+/*170*/		u32 bitfield;
+		u32 __reserved[3];
+	} isr [8];
+
+/*180*/	struct { /* Trigger Mode Register */
+/*1F0*/		u32 bitfield;
+		u32 __reserved[3];
+	} tmr [8];
+
+/*200*/	struct { /* Interrupt Request Register */
+/*270*/		u32 bitfield;
+		u32 __reserved[3];
+	} irr [8];
+
+/*280*/	union { /* Error Status Register */
+		struct {
+			u32   send_cs_error			:  1,
+				receive_cs_error		:  1,
+				send_accept_error		:  1,
+				receive_accept_error		:  1,
+				__reserved_1			:  1,
+				send_illegal_vector		:  1,
+				receive_illegal_vector		:  1,
+				illegal_register_address	:  1,
+				__reserved_2			: 24;
+			u32 __reserved_3[3];
+		} error_bits;
+		struct {
+			u32 errors;
+			u32 __reserved_3[3];
+		} all_errors;
+	} esr;
+
+/*290*/	struct { u32 __reserved[4]; } __reserved_08;
+
+/*2A0*/	struct { u32 __reserved[4]; } __reserved_09;
+
+/*2B0*/	struct { u32 __reserved[4]; } __reserved_10;
+
+/*2C0*/	struct { u32 __reserved[4]; } __reserved_11;
+
+/*2D0*/	struct { u32 __reserved[4]; } __reserved_12;
+
+/*2E0*/	struct { u32 __reserved[4]; } __reserved_13;
+
+/*2F0*/	struct { u32 __reserved[4]; } __reserved_14;
+
+/*300*/	struct { /* Interrupt Command Register 1 */
+		u32   vector			:  8,
+			delivery_mode		:  3,
+			destination_mode	:  1,
+			delivery_status		:  1,
+			__reserved_1		:  1,
+			level			:  1,
+			trigger			:  1,
+			__reserved_2		:  2,
+			shorthand		:  2,
+			__reserved_3		:  12;
+		u32 __reserved_4[3];
+	} icr1;
+
+/*310*/	struct { /* Interrupt Command Register 2 */
+		union {
+			u32   __reserved_1	: 24,
+				phys_dest	:  4,
+				__reserved_2	:  4;
+			u32   __reserved_3	: 24,
+				logical_dest	:  8;
+		} dest;
+		u32 __reserved_4[3];
+	} icr2;
+
+/*320*/	struct { /* LVT - Timer */
+		u32   vector		:  8,
+			__reserved_1	:  4,
+			delivery_status	:  1,
+			__reserved_2	:  3,
+			mask		:  1,
+			timer_mode	:  1,
+			__reserved_3	: 14;
+		u32 __reserved_4[3];
+	} lvt_timer;
+
+/*330*/	struct { u32 __reserved[4]; } __reserved_15;
+
+/*340*/	struct { /* LVT - Performance Counter */
+		u32   vector		:  8,
+			delivery_mode	:  3,
+			__reserved_1	:  1,
+			delivery_status	:  1,
+			__reserved_2	:  3,
+			mask		:  1,
+			__reserved_3	: 15;
+		u32 __reserved_4[3];
+	} lvt_pc;
+
+/*350*/	struct { /* LVT - LINT0 */
+		u32   vector		:  8,
+			delivery_mode	:  3,
+			__reserved_1	:  1,
+			delivery_status	:  1,
+			polarity	:  1,
+			remote_irr	:  1,
+			trigger		:  1,
+			mask		:  1,
+			__reserved_2	: 15;
+		u32 __reserved_3[3];
+	} lvt_lint0;
+
+/*360*/	struct { /* LVT - LINT1 */
+		u32   vector		:  8,
+			delivery_mode	:  3,
+			__reserved_1	:  1,
+			delivery_status	:  1,
+			polarity	:  1,
+			remote_irr	:  1,
+			trigger		:  1,
+			mask		:  1,
+			__reserved_2	: 15;
+		u32 __reserved_3[3];
+	} lvt_lint1;
+
+/*370*/	struct { /* LVT - Error */
+		u32   vector		:  8,
+			__reserved_1	:  4,
+			delivery_status	:  1,
+			__reserved_2	:  3,
+			mask		:  1,
+			__reserved_3	: 15;
+		u32 __reserved_4[3];
+	} lvt_error;
+
+/*380*/	struct { /* Timer Initial Count Register */
+		u32   initial_count;
+		u32 __reserved_2[3];
+	} timer_icr;
+
+/*390*/	const
+	struct { /* Timer Current Count Register */
+		u32   curr_count;
+		u32 __reserved_2[3];
+	} timer_ccr;
+
+/*3A0*/	struct { u32 __reserved[4]; } __reserved_16;
+
+/*3B0*/	struct { u32 __reserved[4]; } __reserved_17;
+
+/*3C0*/	struct { u32 __reserved[4]; } __reserved_18;
+
+/*3D0*/	struct { u32 __reserved[4]; } __reserved_19;
+
+/*3E0*/	struct { /* Timer Divide Configuration Register */
+		u32   divisor		:  4,
+			__reserved_1	: 28;
+		u32 __reserved_2[3];
+	} timer_dcr;
+
+/*3F0*/	struct { u32 __reserved[4]; } __reserved_20;
+
+} __attribute__ ((packed));
+
+#undef u32
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/asm-macros.i linux-2.4.20/include/asm-x86_64/asm-macros.i
--- linux-2.4.19/include/asm-x86_64/asm-macros.i	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/asm-macros.i	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,12 @@
+
+	.macro SAVE_CALLEE_CLOBBERED
+	cld
+	pushq %rdi
+	pushq %rsi
+	pushq %rdx
+	pushq %rcx
+	pushq %rbx
+	pushq %rax
+	pushq %r8
+	pushq %r9" 
+	.endm
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/atomic.h linux-2.4.20/include/asm-x86_64/atomic.h
--- linux-2.4.19/include/asm-x86_64/atomic.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/atomic.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,206 @@
+#ifndef __ARCH_X86_64_ATOMIC__
+#define __ARCH_X86_64_ATOMIC__
+
+#include <linux/config.h>
+
+/* atomic_t should be 32 bit signed type */
+
+/*
+ * Atomic operations that C can't guarantee us.  Useful for
+ * resource counting etc..
+ */
+
+#ifdef CONFIG_SMP
+#define LOCK "lock ; "
+#else
+#define LOCK ""
+#endif
+
+/*
+ * Make sure gcc doesn't try to be clever and move things around
+ * on us. We need to use _exactly_ the address the user gave us,
+ * not some alias that contains the same information.
+ */
+typedef struct { volatile int counter; } atomic_t;
+
+#define ATOMIC_INIT(i)	{ (i) }
+
+/**
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically reads the value of @v.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
+#define atomic_read(v)		((v)->counter)
+
+/**
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ * 
+ * Atomically sets the value of @v to @i.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
+#define atomic_set(v,i)		(((v)->counter) = (i))
+
+/**
+ * atomic_add - add integer to atomic variable
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically adds @i to @v.  Note that the guaranteed useful range
+ * of an atomic_t is only 24 bits.
+ */
+static __inline__ void atomic_add(int i, atomic_t *v)
+{
+	__asm__ __volatile__(
+		LOCK "addl %1,%0"
+		:"=m" (v->counter)
+		:"ir" (i), "m" (v->counter));
+}
+
+/**
+ * atomic_sub - subtract the atomic variable
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically subtracts @i from @v.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+static __inline__ void atomic_sub(int i, atomic_t *v)
+{
+	__asm__ __volatile__(
+		LOCK "subl %1,%0"
+		:"=m" (v->counter)
+		:"ir" (i), "m" (v->counter));
+}
+
+/**
+ * atomic_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically subtracts @i from @v and returns
+ * true if the result is zero, or false for all
+ * other cases.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+static __inline__ int atomic_sub_and_test(int i, atomic_t *v)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		LOCK "subl %2,%0; sete %1"
+		:"=m" (v->counter), "=qm" (c)
+		:"ir" (i), "m" (v->counter) : "memory");
+	return c;
+}
+
+/**
+ * atomic_inc - increment atomic variable
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically increments @v by 1.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
+static __inline__ void atomic_inc(atomic_t *v)
+{
+	__asm__ __volatile__(
+		LOCK "incl %0"
+		:"=m" (v->counter)
+		:"m" (v->counter));
+}
+
+/**
+ * atomic_dec - decrement atomic variable
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically decrements @v by 1.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
+static __inline__ void atomic_dec(atomic_t *v)
+{
+	__asm__ __volatile__(
+		LOCK "decl %0"
+		:"=m" (v->counter)
+		:"m" (v->counter));
+}
+
+/**
+ * atomic_dec_and_test - decrement and test
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically decrements @v by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
+static __inline__ int atomic_dec_and_test(atomic_t *v)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		LOCK "decl %0; sete %1"
+		:"=m" (v->counter), "=qm" (c)
+		:"m" (v->counter) : "memory");
+	return c != 0;
+}
+
+/**
+ * atomic_inc_and_test - increment and test 
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically increments @v by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
+static __inline__ int atomic_inc_and_test(atomic_t *v)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		LOCK "incl %0; sete %1"
+		:"=m" (v->counter), "=qm" (c)
+		:"m" (v->counter) : "memory");
+	return c != 0;
+}
+
+/**
+ * atomic_add_negative - add and test if negative
+ * @v: pointer of type atomic_t
+ * @i: integer value to add
+ * 
+ * Atomically adds @i to @v and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
+static __inline__ int atomic_add_negative(int i, atomic_t *v)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		LOCK "addl %2,%0; sets %1"
+		:"=m" (v->counter), "=qm" (c)
+		:"ir" (i), "m" (v->counter) : "memory");
+	return c;
+}
+
+/* These are x86-specific, used by some header files */
+#define atomic_clear_mask(mask, addr) \
+__asm__ __volatile__(LOCK "andl %0,%1" \
+: : "r" (~(mask)),"m" (*addr) : "memory")
+
+#define atomic_set_mask(mask, addr) \
+__asm__ __volatile__(LOCK "orl %0,%1" \
+: : "r" ((unsigned)mask),"m" (*addr) : "memory")
+
+/* Atomic operations are already serializing on x86 */
+#define smp_mb__before_atomic_dec()	barrier()
+#define smp_mb__after_atomic_dec()	barrier()
+#define smp_mb__before_atomic_inc()	barrier()
+#define smp_mb__after_atomic_inc()	barrier()
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/bitops.h linux-2.4.20/include/asm-x86_64/bitops.h
--- linux-2.4.19/include/asm-x86_64/bitops.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/bitops.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,409 @@
+#ifndef _X86_64_BITOPS_H
+#define _X86_64_BITOPS_H
+
+/*
+ * Copyright 1992, Linus Torvalds.
+ */
+
+#include <linux/config.h>
+
+/*
+ * These have to be done with inline assembly: that way the bit-setting
+ * is guaranteed to be atomic. All bit operations return 0 if the bit
+ * was cleared before the operation and != 0 if it was not.
+ *
+ * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
+ */
+
+#ifdef CONFIG_SMP
+#define LOCK_PREFIX "lock ; "
+#else
+#define LOCK_PREFIX ""
+#endif
+
+#define ADDR (*(volatile long *) addr)
+
+/**
+ * set_bit - Atomically set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * This function is atomic and may not be reordered.  See __set_bit()
+ * if you do not require the atomic guarantees.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+static __inline__ void set_bit(long nr, volatile void * addr)
+{
+	__asm__ __volatile__( LOCK_PREFIX
+		"btsq %1,%0"
+		:"=m" (ADDR)
+		:"dIr" (nr));
+}
+
+/**
+ * __set_bit - Set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike set_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static __inline__ void __set_bit(long nr, volatile void * addr)
+{
+	__asm__(
+		"btsq %1,%0"
+		:"=m" (ADDR)
+		:"dIr" (nr));
+}
+
+/**
+ * clear_bit - Clears a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * clear_bit() is atomic and may not be reordered.  However, it does
+ * not contain a memory barrier, so if it is used for locking purposes,
+ * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
+ * in order to ensure changes are visible on other processors.
+ */
+static __inline__ void clear_bit(long nr, volatile void * addr)
+{
+	__asm__ __volatile__( LOCK_PREFIX
+		"btrq %1,%0"
+		:"=m" (ADDR)
+		:"dIr" (nr));
+}
+#define smp_mb__before_clear_bit()	barrier()
+#define smp_mb__after_clear_bit()	barrier()
+
+/**
+ * __change_bit - Toggle a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike change_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static __inline__ void __change_bit(long nr, volatile void * addr)
+{
+	__asm__ __volatile__(
+		"btcq %1,%0"
+		:"=m" (ADDR)
+		:"dIr" (nr));
+}
+
+/**
+ * change_bit - Toggle a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * change_bit() is atomic and may not be reordered.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+static __inline__ void change_bit(long nr, volatile void * addr)
+{
+	__asm__ __volatile__( LOCK_PREFIX
+		"btcq %1,%0"
+		:"=m" (ADDR)
+		:"dIr" (nr));
+}
+
+/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
+static __inline__ int test_and_set_bit(long nr, volatile void * addr)
+{
+        long oldbit;
+
+	__asm__ __volatile__( LOCK_PREFIX
+		"btsq %2,%1\n\tsbbq %0,%0"
+		:"=r" (oldbit),"=m" (ADDR)
+		:"dIr" (nr) : "memory");
+	return oldbit;
+}
+
+/**
+ * __test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.  
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+static __inline__ int __test_and_set_bit(long nr, volatile void * addr)
+{
+	long oldbit;
+
+	__asm__(
+		"btsq %2,%1\n\tsbbq %0,%0"
+		:"=r" (oldbit),"=m" (ADDR)
+		:"dIr" (nr));
+	return oldbit;
+}
+
+/**
+ * test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
+static __inline__ int test_and_clear_bit(long nr, volatile void * addr)
+{
+	long oldbit;
+
+	__asm__ __volatile__( LOCK_PREFIX
+		"btrq %2,%1\n\tsbbq %0,%0"
+		:"=r" (oldbit),"=m" (ADDR)
+		:"dIr" (nr) : "memory");
+	return oldbit;
+}
+
+/**
+ * __test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.  
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+static __inline__ int __test_and_clear_bit(long nr, volatile void * addr)
+{
+	long oldbit;
+
+	__asm__(
+		"btrq %2,%1\n\tsbbq %0,%0"
+		:"=r" (oldbit),"=m" (ADDR)
+		:"dIr" (nr));
+	return oldbit;
+}
+
+/* WARNING: non atomic and it can be reordered! */
+static __inline__ int __test_and_change_bit(long nr, volatile void * addr)
+{
+	long oldbit;
+
+	__asm__ __volatile__(
+		"btcq %2,%1\n\tsbbq %0,%0"
+		:"=r" (oldbit),"=m" (ADDR)
+		:"dIr" (nr) : "memory");
+	return oldbit;
+}
+
+/**
+ * test_and_change_bit - Change a bit and return its new value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
+static __inline__ int test_and_change_bit(long nr, volatile void * addr)
+{
+	long oldbit;
+
+	__asm__ __volatile__( LOCK_PREFIX
+		"btcq %2,%1\n\tsbbq %0,%0"
+		:"=r" (oldbit),"=m" (ADDR)
+		:"dIr" (nr) : "memory");
+	return oldbit;
+}
+
+#if 0 /* Fool kernel-doc since it doesn't do macros yet */
+/**
+ * test_bit - Determine whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
+ */
+static int test_bit(int nr, const volatile void * addr);
+#endif
+
+static __inline__ int constant_test_bit(long nr, const volatile void * addr)
+{
+	return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
+}
+
+static __inline__ int variable_test_bit(long nr, volatile void * addr)
+{
+	long oldbit;
+
+	__asm__ __volatile__(
+		"btq %2,%1\n\tsbbq %0,%0"
+		:"=r" (oldbit)
+		:"m" (ADDR),"dIr" (nr));
+	return oldbit;
+}
+
+#define test_bit(nr,addr) \
+(__builtin_constant_p(nr) ? \
+ constant_test_bit((nr),(addr)) : \
+ variable_test_bit((nr),(addr)))
+
+/**
+ * find_first_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum bitnumber to search
+ *
+ * Returns the bit-number of the first zero bit, not the number of the byte
+ * containing a bit. -1 when none found.
+ */
+static __inline__ int find_first_zero_bit(void * addr, unsigned size)
+{
+	int d0, d1, d2;
+	int res;
+
+	if (!size)
+		return 0;
+	__asm__ __volatile__(
+		"movl $-1,%%eax\n\t"
+		"xorl %%edx,%%edx\n\t"
+		"repe; scasl\n\t"
+		"je 1f\n\t"
+		"xorl -4(%%rdi),%%eax\n\t"
+		"subq $4,%%rdi\n\t"
+		"bsfl %%eax,%%edx\n"
+		"1:\tsubq %%rbx,%%rdi\n\t"
+		"shlq $3,%%rdi\n\t"
+		"addq %%rdi,%%rdx"
+		:"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)
+		:"1" ((size + 31) >> 5), "2" (addr), "b" (addr) : "memory");
+	return res;
+}
+
+/**
+ * find_next_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
+{
+	unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
+	int set = 0, bit = offset & 31, res;
+	
+	if (bit) {
+		/*
+		 * Look for zero in first byte
+		 */
+		__asm__("bsfl %1,%0\n\t"
+			"jne 1f\n\t"
+			"movl $32, %0\n"
+			"1:"
+			: "=r" (set)
+			: "r" (~(*p >> bit)));
+		if (set < (32 - bit))
+			return set + offset;
+		set = 32 - bit;
+		p++;
+	}
+	/*
+	 * No zero yet, search remaining full bytes for a zero
+	 */
+	res = find_first_zero_bit (p, size - 32 * (p - (unsigned int *) addr));
+	return (offset + set + res);
+}
+
+/* 
+ * Find string of zero bits in a bitmap. -1 when not found.
+ */ 
+extern unsigned long 
+find_next_zero_string(unsigned long *bitmap, long start, long nbits, int len);
+
+static inline void set_bit_string(unsigned long *bitmap, unsigned long i, 
+				  int len) 
+{ 
+	unsigned long end = i + len; 
+	while (i < end) {
+		__set_bit(i, bitmap); 
+		i++;
+	}
+} 
+
+static inline void clear_bit_string(unsigned long *bitmap, unsigned long i, 
+				    int len) 
+{ 
+	unsigned long end = i + len; 
+	while (i < end) {
+		clear_bit(i, bitmap); 
+		i++;
+	}
+} 
+
+/**
+ * ffz - find first zero in word.
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+static __inline__ unsigned long ffz(unsigned long word)
+{
+	__asm__("bsfq %1,%0"
+		:"=r" (word)
+		:"r" (~word));
+	return word;
+}
+
+#ifdef __KERNEL__
+
+/**
+ * ffs - find first bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+static __inline__ int ffs(int x)
+{
+	int r;
+
+	__asm__("bsfl %1,%0\n\t"
+		"jnz 1f\n\t"
+		"movl $-1,%0\n"
+		"1:" : "=r" (r) : "rm" (x));
+	return r+1;
+}
+
+/**
+ * hweightN - returns the hamming weight of a N-bit word
+ * @x: the word to weigh
+ *
+ * The Hamming Weight of a number is the total number of bits set in it.
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+#endif /* __KERNEL__ */
+
+#ifdef __KERNEL__
+
+#define ext2_set_bit                 __test_and_set_bit
+#define ext2_clear_bit               __test_and_clear_bit
+#define ext2_test_bit                test_bit
+#define ext2_find_first_zero_bit     find_first_zero_bit
+#define ext2_find_next_zero_bit      find_next_zero_bit
+
+/* Bitmap functions for the minix filesystem.  */
+#define minix_test_and_set_bit(nr,addr) __test_and_set_bit(nr,addr)
+#define minix_set_bit(nr,addr) __set_bit(nr,addr)
+#define minix_test_and_clear_bit(nr,addr) __test_and_clear_bit(nr,addr)
+#define minix_test_bit(nr,addr) test_bit(nr,addr)
+#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
+
+#endif /* __KERNEL__ */
+
+#endif /* _X86_64_BITOPS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/boot.h linux-2.4.20/include/asm-x86_64/boot.h
--- linux-2.4.19/include/asm-x86_64/boot.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/boot.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,15 @@
+#ifndef _LINUX_BOOT_H
+#define _LINUX_BOOT_H
+
+/* Don't touch these, unless you really know what you're doing. */
+#define DEF_INITSEG	0x9000
+#define DEF_SYSSEG	0x1000
+#define DEF_SETUPSEG	0x9020
+#define DEF_SYSSIZE	0x7F00
+
+/* Internal svga startup constants */
+#define NORMAL_VGA	0xffff		/* 80x25 mode */
+#define EXTENDED_VGA	0xfffe		/* 80x50 mode */
+#define ASK_VGA		0xfffd		/* ask for it at bootup */
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/bootsetup.h linux-2.4.20/include/asm-x86_64/bootsetup.h
--- linux-2.4.19/include/asm-x86_64/bootsetup.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/bootsetup.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,33 @@
+
+#ifndef _X86_64_BOOTSETUP_H
+#define _X86_64_BOOTSETUP_H 1
+
+extern char x86_boot_params[2048];
+
+/*
+ * This is set up by the setup-routine at boot-time
+ */
+#define PARAM	((unsigned char *)x86_boot_params)
+#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
+#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
+#define ALT_MEM_K (*(unsigned int *) (PARAM+0x1e0))
+#define E820_MAP_NR (*(char*) (PARAM+E820NR))
+#define E820_MAP    ((struct e820entry *) (PARAM+E820MAP))
+#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
+#define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
+#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
+#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
+#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
+#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
+#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
+#define KERNEL_START (*(unsigned int *) (PARAM+0x214))
+#define INITRD_START (*(unsigned int *) (PARAM+0x218))
+#define INITRD_SIZE (*(unsigned int *) (PARAM+0x21c))
+#define COMMAND_LINE saved_command_line
+#define COMMAND_LINE_SIZE 256
+
+#define RAMDISK_IMAGE_START_MASK  	0x07FF
+#define RAMDISK_PROMPT_FLAG		0x8000
+#define RAMDISK_LOAD_FLAG		0x4000	
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/bugs.h linux-2.4.20/include/asm-x86_64/bugs.h
--- linux-2.4.19/include/asm-x86_64/bugs.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/bugs.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,34 @@
+/*
+ *  include/asm-x86_64/bugs.h
+ *
+ *  Copyright (C) 1994  Linus Torvalds
+ *  Copyright (C) 2000  SuSE
+ *
+ * This is included by init/main.c to check for architecture-dependent bugs.
+ *
+ * Needs:
+ *	void check_bugs(void);
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/i387.h>
+#include <asm/msr.h>
+#include <asm/pda.h>
+
+static inline void check_fpu(void)
+{
+	extern void __bad_fxsave_alignment(void);
+	if (offsetof(struct task_struct, thread.i387.fxsave) & 15)
+		__bad_fxsave_alignment();
+
+	/* This should not be here */	
+	set_in_cr4(X86_CR4_OSFXSR);
+	set_in_cr4(X86_CR4_OSXMMEXCPT);
+}
+
+static void __init check_bugs(void)
+{
+	identify_cpu(&boot_cpu_data);
+	check_fpu();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/byteorder.h linux-2.4.20/include/asm-x86_64/byteorder.h
--- linux-2.4.19/include/asm-x86_64/byteorder.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/byteorder.h	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,32 @@
+#ifndef _X86_64_BYTEORDER_H
+#define _X86_64_BYTEORDER_H
+
+#include <asm/types.h>
+
+#ifdef __GNUC__
+
+static __inline__ __const__ __u64 ___arch__swab64(__u64 x)
+{
+	__asm__("bswapq %0" : "=r" (x) : "0" (x));
+	return x;
+}
+
+static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
+{
+	__asm__("bswapl %0" : "=r" (x) : "0" (x));
+	return x;
+}
+
+/* Do not define swab16.  Gcc is smart enought to recognize "C" version and
+   convert it into rotation or exhange.  */
+
+#define __arch__swab32(x) ___arch__swab32(x)
+#define __arch__swab64(x) ___arch__swab64(x)
+
+#endif /* __GNUC__ */
+
+#define __BYTEORDER_HAS_U64__
+
+#include <linux/byteorder/little_endian.h>
+
+#endif /* _X86_64_BYTEORDER_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/cache.h linux-2.4.20/include/asm-x86_64/cache.h
--- linux-2.4.19/include/asm-x86_64/cache.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/cache.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,13 @@
+/*
+ * include/asm-x8664/cache.h
+ */
+#ifndef __ARCH_X8664_CACHE_H
+#define __ARCH_X8664_CACHE_H
+
+#include <linux/config.h>
+
+/* L1 cache line size */
+#define L1_CACHE_SHIFT	(CONFIG_X86_L1_CACHE_SHIFT)
+#define L1_CACHE_BYTES	(1 << L1_CACHE_SHIFT)
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/calling.h linux-2.4.20/include/asm-x86_64/calling.h
--- linux-2.4.19/include/asm-x86_64/calling.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/calling.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,140 @@
+/* 
+ * Some macros to handle stack frames in assembly.
+ */ 
+
+#include <linux/config.h>
+
+#define R15 0
+#define R14 8
+#define R13 16
+#define R12 24
+#define RBP 36
+#define RBX 40
+/* arguments: interrupts/non tracing syscalls only save upto here*/
+#define R11 48
+#define R10 56	
+#define R9 64
+#define R8 72
+#define RAX 80
+#define RCX 88
+#define RDX 96
+#define RSI 104
+#define RDI 112
+#define ORIG_RAX 120       /* + error_code */ 
+/* end of arguments */ 	
+/* cpu exception frame or undefined in case of fast syscall. */
+#define RIP 128
+#define CS 136
+#define EFLAGS 144
+#define RSP 152
+#define SS 160
+#define ARGOFFSET R11
+
+	.macro SAVE_ARGS addskip=0,norcx=0 	
+	subq  $9*8+\addskip,%rsp
+	movq  %rdi,8*8(%rsp) 
+	movq  %rsi,7*8(%rsp) 
+	movq  %rdx,6*8(%rsp)
+	.if \norcx
+	.else
+	movq  %rcx,5*8(%rsp)
+	.endif
+	movq  %rax,4*8(%rsp) 
+	movq  %r8,3*8(%rsp) 
+	movq  %r9,2*8(%rsp) 
+	movq  %r10,1*8(%rsp) 
+	movq  %r11,(%rsp) 
+	.endm
+
+#define ARG_SKIP 9*8
+	.macro RESTORE_ARGS skiprax=0,addskip=0,skiprcx=0
+	movq (%rsp),%r11
+	movq 1*8(%rsp),%r10
+	movq 2*8(%rsp),%r9
+	movq 3*8(%rsp),%r8
+	.if \skiprax
+	.else
+	movq 4*8(%rsp),%rax
+	.endif
+	.if \skiprcx
+	.else
+	movq 5*8(%rsp),%rcx
+	.endif
+	movq 6*8(%rsp),%rdx
+	movq 7*8(%rsp),%rsi
+	movq 8*8(%rsp),%rdi
+	.if ARG_SKIP+\addskip > 0
+	addq $ARG_SKIP+\addskip,%rsp
+	.endif
+	.endm	
+
+	.macro LOAD_ARGS offset
+	movq \offset(%rsp),%r11
+	movq \offset+8(%rsp),%r10
+	movq \offset+16(%rsp),%r9
+	movq \offset+24(%rsp),%r8
+	movq \offset+40(%rsp),%rcx
+	movq \offset+48(%rsp),%rdx
+	movq \offset+56(%rsp),%rsi
+	movq \offset+64(%rsp),%rdi
+	movq \offset+72(%rsp),%rax
+	.endm
+			
+	.macro SAVE_REST
+	subq $6*8,%rsp
+	movq %rbx,5*8(%rsp) 
+	movq %rbp,4*8(%rsp) 
+	movq %r12,3*8(%rsp) 
+	movq %r13,2*8(%rsp) 
+	movq %r14,1*8(%rsp) 
+	movq %r15,(%rsp) 
+	.endm		
+
+#define REST_SKIP 6*8
+	.macro RESTORE_REST
+	movq (%rsp),%r15
+	movq 1*8(%rsp),%r14
+	movq 2*8(%rsp),%r13
+	movq 3*8(%rsp),%r12
+	movq 4*8(%rsp),%rbp
+	movq 5*8(%rsp),%rbx
+	addq $REST_SKIP,%rsp
+	.endm
+		
+	.macro SAVE_ALL
+	SAVE_ARGS
+	SAVE_REST
+	.endm
+		
+	.macro RESTORE_ALL addskip=0
+	RESTORE_REST
+	RESTORE_ARGS 0,\addskip
+	.endm
+
+	/* push in order ss, rsp, eflags, cs, rip */
+	.macro FAKE_STACK_FRAME child_rip
+	xorl %eax,%eax
+	subq $6*8,%rsp
+	movq %rax,5*8(%rsp)  /* ss */
+	movq %rax,4*8(%rsp)  /* rsp */
+	movq $(1<<9),3*8(%rsp)  /* eflags - enable interrupts */
+	movq $__KERNEL_CS,2*8(%rsp) /* cs */
+	movq \child_rip,1*8(%rsp)  /* rip */ 
+	movq %rax,(%rsp)   /* orig_rax */ 
+	.endm
+
+	.macro UNFAKE_STACK_FRAME
+	addq $8*6, %rsp
+	.endm
+
+	.macro icebp
+	.byte 0xf1
+	.endm	
+
+#ifdef CONFIG_FRAME_POINTER
+#define ENTER enter
+#define LEAVE leave
+#else
+#define ENTER
+#define LEAVE
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/checksum.h linux-2.4.20/include/asm-x86_64/checksum.h
--- linux-2.4.19/include/asm-x86_64/checksum.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/checksum.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,182 @@
+#ifndef _X86_64_CHECKSUM_H
+#define _X86_64_CHECKSUM_H
+
+/* 
+ * Checksums for x86-64 
+ * Copyright 2002 by Andi Kleen, SuSE Labs 
+ * with some code from asm-i386/checksum.h
+ */ 
+
+#include <linux/compiler.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+/** 
+ * csum_fold - Fold and invert a 32bit checksum.
+ * sum: 32bit unfolded sum
+ * 
+ * Fold a 32bit running checksum to 16bit and invert it. This is usually
+ * the last step before putting a checksum into a packet.
+ * Make sure not to mix with 64bit checksums.
+ */
+static inline unsigned int csum_fold(unsigned int sum)
+{
+	__asm__(
+		"  addl %1,%0\n"
+		"  adcl $0xffff,%0"
+		: "=r" (sum)
+		: "r" (sum << 16), "0" (sum & 0xffff0000)
+	);
+	return (~sum) >> 16;
+}
+
+/*
+ *	This is a version of ip_compute_csum() optimized for IP headers,
+ *	which always checksum on 4 octet boundaries.
+ *
+ *	By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
+ *	Arnt Gulbrandsen.
+ */
+
+/**
+ * ip_fast_csum - Compute the IPv4 header checksum efficiently.
+ * iph: ipv4 header
+ * ihl: length of header / 4
+ */ 
+static inline unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl) 
+{
+	unsigned int sum;
+
+	asm(	"  movl (%1), %0\n"
+		"  subl $4, %2\n"
+		"  jbe 2f\n"
+		"  addl 4(%1), %0\n"
+		"  adcl 8(%1), %0\n"
+		"  adcl 12(%1), %0\n"
+		"1: adcl 16(%1), %0\n"
+		"  lea 4(%1), %1\n"
+		"  decl %2\n"
+		"  jne	1b\n"
+		"  adcl $0, %0\n"
+		"  movl %0, %2\n"
+		"  shrl $16, %0\n"
+		"  addw %w2, %w0\n"
+		"  adcl $0, %0\n"
+		"  notl %0\n"
+		"2:"
+	/* Since the input registers which are loaded with iph and ipl
+	   are modified, we must also specify them as outputs, or gcc
+	   will assume they contain their original values. */
+	: "=r" (sum), "=r" (iph), "=r" (ihl)
+	: "1" (iph), "2" (ihl));
+	return(sum);
+}
+
+/** 
+ * csum_tcpup_nofold - Compute an IPv4 pseudo header checksum.
+ * @saddr: source address
+ * @daddr: destination address
+ * @len: length of packet
+ * @proto: ip protocol of packet
+ * @sum: initial sum to be added in (32bit unfolded) 
+ * 
+ * Returns the pseudo header checksum the input data. Result is 
+ * 32bit unfolded.
+ */
+static inline unsigned long 
+csum_tcpudp_nofold(unsigned saddr, unsigned daddr, unsigned short len,
+		   unsigned short proto, unsigned int sum) 
+{
+	asm("  addl %1, %0\n"
+	    "  adcl %2, %0\n"
+	    "  adcl %3, %0\n"
+	    "  adcl $0, %0\n"
+		: "=r" (sum)
+	    : "g" (daddr), "g" (saddr), "g" ((ntohs(len)<<16)+proto*256), "0" (sum));
+    return sum;
+}
+
+
+/** 
+ * csum_tcpup_magic - Compute an IPv4 pseudo header checksum.
+ * @saddr: source address
+ * @daddr: destination address
+ * @len: length of packet
+ * @proto: ip protocol of packet
+ * @sum: initial sum to be added in (32bit unfolded) 
+ * 
+ * Returns the 16bit pseudo header checksum the input data already
+ * complemented and ready to be filled in.
+ */
+static inline unsigned short int 
+csum_tcpudp_magic(unsigned long saddr, unsigned long daddr,
+		  unsigned short len, unsigned short proto, unsigned int sum) 
+{
+	return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
+/** 
+ * csum_partial - Compute an internet checksum.
+ * @buff: buffer to be checksummed
+ * @len: length of buffer.
+ * @sum: initial sum to be added in (32bit unfolded)
+ *
+ * Returns the 32bit unfolded internet checksum of the buffer.
+ * Before filling it in it needs to be csum_fold()'ed.
+ * buff should be aligned to a 64bit boundary if possible.
+ */ 
+extern unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum);
+
+#define  _HAVE_ARCH_COPY_AND_CSUM_FROM_USER 1
+#define HAVE_CSUM_COPY_USER 1
+
+
+/* Do not call this directly. Use the wrappers below */
+extern unsigned long csum_partial_copy_generic(const char *src, const char *dst, 
+					       unsigned len,
+					       unsigned sum, 
+					       int *src_err_ptr, int *dst_err_ptr);
+
+
+extern unsigned int csum_partial_copy_from_user(const char *src, char *dst, 
+				       int len, unsigned int isum, int *errp);
+extern unsigned int csum_partial_copy_to_user(const char *src, char *dst, 
+				      int len, unsigned int isum, int *errp);
+extern unsigned int csum_partial_copy_nocheck(const char *src, char *dst, int len, 
+					      unsigned int sum);
+
+/* Old names. To be removed. */
+#define csum_and_copy_to_user csum_partial_copy_to_user
+#define csum_and_copy_from_user csum_partial_copy_from_user
+
+/** 
+ * ip_compute_csum - Compute an 16bit IP checksum.
+ * @buff: buffer address.
+ * @len: length of buffer.
+ *
+ * Returns the 16bit folded/inverted checksum of the passed buffer.
+ * Ready to fill in.
+ */
+extern unsigned short ip_compute_csum(unsigned char * buff, int len);
+
+/**
+ * csum_ipv6_magic - Compute checksum of an IPv6 pseudo header.
+ * @saddr: source address
+ * @daddr: destination address
+ * @len: length of packet
+ * @proto: protocol of packet
+ * @sum: initial sum (32bit unfolded) to be added in
+ *
+ * Computes an IPv6 pseudo header checksum. This sum is added the checksum 
+ * into UDP/TCP packets and contains some link layer information.
+ * Returns the unfolded 32bit checksum.
+ */
+
+struct in6_addr;
+
+#define _HAVE_ARCH_IPV6_CSUM 1
+extern unsigned short 
+csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr,
+		__u32 len, unsigned short proto, unsigned int sum);
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/cpufeature.h linux-2.4.20/include/asm-x86_64/cpufeature.h
--- linux-2.4.19/include/asm-x86_64/cpufeature.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/cpufeature.h	2002-10-29 11:18:51.000000000 +0000
@@ -0,0 +1,73 @@
+/*
+ * cpufeature.h
+ *
+ * Defines x86 CPU feature bits
+ */
+
+#ifndef __ASM_X8664_CPUFEATURE_H
+#define __ASM_X8664_CPUFEATURE_H
+
+/* Sample usage: CPU_FEATURE_P(cpu.x86_capability, FPU) */
+#define CPU_FEATURE_P(CAP, FEATURE) test_bit(CAP, X86_FEATURE_##FEATURE ##_BIT)
+
+#define NCAPINTS	4	/* Currently we have 4 32-bit words worth of info */
+
+/* Intel-defined CPU features, CPUID level 0x00000001, word 0 */
+#define X86_FEATURE_FPU		(0*32+ 0) /* Onboard FPU */
+#define X86_FEATURE_VME		(0*32+ 1) /* Virtual Mode Extensions */
+#define X86_FEATURE_DE		(0*32+ 2) /* Debugging Extensions */
+#define X86_FEATURE_PSE 	(0*32+ 3) /* Page Size Extensions */
+#define X86_FEATURE_TSC		(0*32+ 4) /* Time Stamp Counter */
+#define X86_FEATURE_MSR		(0*32+ 5) /* Model-Specific Registers, RDMSR, WRMSR */
+#define X86_FEATURE_PAE		(0*32+ 6) /* Physical Address Extensions */
+#define X86_FEATURE_MCE		(0*32+ 7) /* Machine Check Architecture */
+#define X86_FEATURE_CX8		(0*32+ 8) /* CMPXCHG8 instruction */
+#define X86_FEATURE_APIC	(0*32+ 9) /* Onboard APIC */
+#define X86_FEATURE_SEP		(0*32+11) /* SYSENTER/SYSEXIT */
+#define X86_FEATURE_MTRR	(0*32+12) /* Memory Type Range Registers */
+#define X86_FEATURE_PGE		(0*32+13) /* Page Global Enable */
+#define X86_FEATURE_MCA		(0*32+14) /* Machine Check Architecture */
+#define X86_FEATURE_CMOV	(0*32+15) /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
+#define X86_FEATURE_PAT		(0*32+16) /* Page Attribute Table */
+#define X86_FEATURE_PSE36	(0*32+17) /* 36-bit PSEs */
+#define X86_FEATURE_PN		(0*32+18) /* Processor serial number */
+#define X86_FEATURE_CLFLSH	(0*32+19) /* Supports the CLFLUSH instruction */
+#define X86_FEATURE_DTES	(0*32+21) /* Debug Trace Store */
+#define X86_FEATURE_ACPI	(0*32+22) /* ACPI via MSR */
+#define X86_FEATURE_MMX		(0*32+23) /* Multimedia Extensions */
+#define X86_FEATURE_FXSR	(0*32+24) /* FXSAVE and FXRSTOR instructions (fast save and restore */
+				          /* of FPU context), and CR4.OSFXSR available */
+#define X86_FEATURE_XMM		(0*32+25) /* Streaming SIMD Extensions */
+#define X86_FEATURE_XMM2	(0*32+26) /* Streaming SIMD Extensions-2 */
+#define X86_FEATURE_SELFSNOOP	(0*32+27) /* CPU self snoop */
+#define X86_FEATURE_ACC		(0*32+29) /* Automatic clock control */
+#define X86_FEATURE_IA64	(0*32+30) /* IA-64 processor */
+
+/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
+/* Don't duplicate feature flags which are redundant with Intel! */
+#define X86_FEATURE_SYSCALL	(1*32+11) /* SYSCALL/SYSRET */
+#define X86_FEATURE_MMXEXT	(1*32+22) /* AMD MMX extensions */
+#define X86_FEATURE_LM		(1*32+29) /* Long Mode (x86-64) */
+#define X86_FEATURE_3DNOWEXT	(1*32+30) /* AMD 3DNow! extensions */
+#define X86_FEATURE_3DNOW	(1*32+31) /* 3DNow! */
+
+/* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */
+#define X86_FEATURE_RECOVERY	(2*32+ 0) /* CPU in recovery mode */
+#define X86_FEATURE_LONGRUN	(2*32+ 1) /* Longrun power control */
+#define X86_FEATURE_LRTI	(2*32+ 3) /* LongRun table interface */
+
+/* Other features, Linux-defined mapping, word 3 */
+/* This range is used for feature bits which conflict or are synthesized */
+#define X86_FEATURE_CXMMX	(3*32+ 0) /* Cyrix MMX extensions */
+#define X86_FEATURE_K6_MTRR	(3*32+ 1) /* AMD K6 nonstandard MTRRs */
+#define X86_FEATURE_CYRIX_ARR	(3*32+ 2) /* Cyrix ARRs (= MTRRs) */
+#define X86_FEATURE_CENTAUR_MCR	(3*32+ 3) /* Centaur MCRs (= MTRRs) */
+
+#endif /* __ASM_X8664_CPUFEATURE_H */
+
+/* 
+ * Local Variables:
+ * mode:c
+ * comment-column:42
+ * End:
+ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/current.h linux-2.4.20/include/asm-x86_64/current.h
--- linux-2.4.19/include/asm-x86_64/current.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/current.h	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,37 @@
+#ifndef _X86_64_CURRENT_H
+#define _X86_64_CURRENT_H
+
+#if !defined(__ASSEMBLY__) 
+struct task_struct;
+
+#include <asm/pda.h>
+
+static inline struct task_struct *get_current(void) 
+{ 
+	struct task_struct *t = read_pda(pcurrent); 
+	return t;
+} 
+
+
+static inline struct task_struct *stack_current(void)
+{
+	struct task_struct *current;
+	__asm__("andq %%rsp,%0; ":"=r" (current) 
+		: "0" (~(unsigned long)(THREAD_SIZE-1)));
+	return current;
+}
+
+
+#define current get_current()
+
+#else
+
+#ifndef ASM_OFFSET_H
+#include <asm/offset.h> 
+#endif
+
+#define GET_CURRENT(reg) movq %gs:(pda_pcurrent),reg
+
+#endif
+
+#endif /* !(_X86_64_CURRENT_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/debugreg.h linux-2.4.20/include/asm-x86_64/debugreg.h
--- linux-2.4.19/include/asm-x86_64/debugreg.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/debugreg.h	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,65 @@
+#ifndef _X86_64_DEBUGREG_H
+#define _X86_64_DEBUGREG_H
+
+
+/* Indicate the register numbers for a number of the specific
+   debug registers.  Registers 0-3 contain the addresses we wish to trap on */
+#define DR_FIRSTADDR 0        /* u_debugreg[DR_FIRSTADDR] */
+#define DR_LASTADDR 3         /* u_debugreg[DR_LASTADDR]  */
+
+#define DR_STATUS 6           /* u_debugreg[DR_STATUS]     */
+#define DR_CONTROL 7          /* u_debugreg[DR_CONTROL] */
+
+/* Define a few things for the status register.  We can use this to determine
+   which debugging register was responsible for the trap.  The other bits
+   are either reserved or not of interest to us. */
+
+#define DR_TRAP0	(0x1)		/* db0 */
+#define DR_TRAP1	(0x2)		/* db1 */
+#define DR_TRAP2	(0x4)		/* db2 */
+#define DR_TRAP3	(0x8)		/* db3 */
+
+#define DR_STEP		(0x4000)	/* single-step */
+#define DR_SWITCH	(0x8000)	/* task switch */
+
+/* Now define a bunch of things for manipulating the control register.
+   The top two bytes of the control register consist of 4 fields of 4
+   bits - each field corresponds to one of the four debug registers,
+   and indicates what types of access we trap on, and how large the data
+   field is that we are looking at */
+
+#define DR_CONTROL_SHIFT 16 /* Skip this many bits in ctl register */
+#define DR_CONTROL_SIZE 4   /* 4 control bits per register */
+
+#define DR_RW_EXECUTE (0x0)   /* Settings for the access types to trap on */
+#define DR_RW_WRITE (0x1)
+#define DR_RW_READ (0x3)
+
+#define DR_LEN_1 (0x0) /* Settings for data length to trap on */
+#define DR_LEN_2 (0x4)
+#define DR_LEN_4 (0xC)
+#define DR_LEN_8 (0x8)
+
+/* The low byte to the control register determine which registers are
+   enabled.  There are 4 fields of two bits.  One bit is "local", meaning
+   that the processor will reset the bit after a task switch and the other
+   is global meaning that we have to explicitly reset the bit.  With linux,
+   you can use either one, since we explicitly zero the register when we enter
+   kernel mode. */
+
+#define DR_LOCAL_ENABLE_SHIFT 0    /* Extra shift to the local enable bit */
+#define DR_GLOBAL_ENABLE_SHIFT 1   /* Extra shift to the global enable bit */
+#define DR_ENABLE_SIZE 2           /* 2 enable bits per register */
+
+#define DR_LOCAL_ENABLE_MASK (0x55)  /* Set  local bits for all 4 regs */
+#define DR_GLOBAL_ENABLE_MASK (0xAA) /* Set global bits for all 4 regs */
+
+/* The second byte to the control register has a few special things.
+   We can slow the instruction pipeline for instructions coming via the
+   gdt or the ldt if we want to.  I am not sure why this is an advantage */
+
+#define DR_CONTROL_RESERVED (0xFC00) /* Reserved by Intel */
+#define DR_LOCAL_SLOWDOWN (0x100)   /* Local slow the pipeline */
+#define DR_GLOBAL_SLOWDOWN (0x200)  /* Global slow the pipeline */
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/delay.h linux-2.4.20/include/asm-x86_64/delay.h
--- linux-2.4.19/include/asm-x86_64/delay.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/delay.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,20 @@
+#ifndef _X8664_DELAY_H
+#define _X8664_DELAY_H
+
+/*
+ * Copyright (C) 1993 Linus Torvalds
+ *
+ * Delay routines calling functions in arch/i386/lib/delay.c
+ */
+ 
+extern void __bad_udelay(void);
+
+extern void __udelay(unsigned long usecs);
+extern void __const_udelay(unsigned long usecs);
+extern void __delay(unsigned long loops);
+
+#define udelay(n) (__builtin_constant_p(n) ? \
+	((n) > 20000 ? __bad_udelay() : __const_udelay((n) * 0x10c6ul)) : \
+	__udelay(n))
+
+#endif /* defined(_X8664_DELAY_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/desc.h linux-2.4.20/include/asm-x86_64/desc.h
--- linux-2.4.19/include/asm-x86_64/desc.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/desc.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,158 @@
+/* Written 2000 by Andi Kleen */ 
+#ifndef __ARCH_DESC_H
+#define __ARCH_DESC_H
+
+#include <linux/threads.h>
+#include <asm/ldt.h>
+
+#ifndef __ASSEMBLY__
+
+#define __TSS_INDEX(n)  ((n)*64)
+#define __LDT_INDEX(n)  ((n)*64)
+
+extern __u8 gdt_table[];
+extern __u8 gdt_end[];
+
+enum { 
+	GATE_INTERRUPT = 0xE, 
+	GATE_TRAP = 0xF, 	
+	GATE_CALL = 0xC,
+}; 	
+
+// 16byte gate
+struct gate_struct {          
+	u16 offset_low;
+	u16 segment; 
+	unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1;
+	u16 offset_middle;
+	u32 offset_high;
+	u32 zero1; 
+} __attribute__((packed));
+
+// 8 byte segment descriptor
+struct desc_struct { 
+	u16 limit0;
+	u16 base0;
+	unsigned base1 : 8, type : 4, s : 1, dpl : 2, p : 1;
+	unsigned limit : 4, avl : 1, l : 1, d : 1, g : 1, base2 : 8;
+} __attribute__((packed)); 
+
+// LDT or TSS descriptor in the GDT. 16 bytes.
+struct ldttss_desc { 
+	u16 limit0;
+	u16 base0;
+	unsigned base1 : 8, type : 5, dpl : 2, p : 1;
+	unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8;
+	u32 base3;
+	u32 zero1; 
+} __attribute__((packed)); 
+
+
+struct per_cpu_gdt {
+	struct ldttss_desc tss;
+	struct ldttss_desc ldt; 
+} ____cacheline_aligned; 
+
+extern struct per_cpu_gdt gdt_cpu_table[]; 
+
+#define PTR_LOW(x) ((unsigned long)(x) & 0xFFFF) 
+#define PTR_MIDDLE(x) (((unsigned long)(x) >> 16) & 0xFFFF)
+#define PTR_HIGH(x) ((unsigned long)(x) >> 32)
+
+enum { 
+	DESC_TSS = 0x9,
+	DESC_LDT = 0x2,
+}; 
+
+struct desc_ptr {
+	unsigned short size;
+	unsigned long address;
+} __attribute__((packed)) ;
+
+#define __GDT_HEAD_SIZE 64
+#define __CPU_DESC_INDEX(x,field) \
+	((x) * sizeof(struct per_cpu_gdt) + offsetof(struct per_cpu_gdt, field) + __GDT_HEAD_SIZE)
+
+#define load_TR(cpu) asm volatile("ltr %w0"::"r" (__CPU_DESC_INDEX(cpu, tss)));
+#define __load_LDT(cpu) asm volatile("lldt %w0"::"r" (__CPU_DESC_INDEX(cpu, ldt)));
+#define clear_LDT(n)  asm volatile("lldt %w0"::"r" (0))
+
+extern struct gate_struct idt_table[]; 
+
+#define copy_16byte(dst,src)  memcpy((dst), (src), 16)
+
+static inline void _set_gate(void *adr, unsigned type, unsigned long func, unsigned dpl, unsigned ist)  
+{
+	struct gate_struct s; 	
+	s.offset_low = PTR_LOW(func); 
+	s.segment = __KERNEL_CS;
+	s.ist = ist; 
+	s.p = 1;
+	s.dpl = dpl; 
+	s.zero0 = 0;
+	s.zero1 = 0; 
+	s.type = type; 
+	s.offset_middle = PTR_MIDDLE(func); 
+	s.offset_high = PTR_HIGH(func); 
+	copy_16byte(adr, &s);
+} 
+
+static inline void set_intr_gate(int nr, void *func) 
+{ 
+	_set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, 0); 
+} 
+
+static inline void set_intr_gate_ist(int nr, void *func, unsigned ist) 
+{ 
+	_set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, ist); 
+} 
+
+static inline void set_system_gate(int nr, void *func) 
+{ 
+	_set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, 0); 
+} 
+
+static inline void set_tssldt_descriptor(struct ldttss_desc *dst, unsigned long ptr, unsigned type, 
+					 unsigned size) 
+{ 
+	memset(dst,0,16); 
+	dst->limit0 = size & 0xFFFF;
+	dst->base0 = PTR_LOW(ptr); 
+	dst->base1 = PTR_MIDDLE(ptr) & 0xFF; 
+	dst->type = type;
+	dst->p = 1; 
+	dst->limit1 = 0xF;
+	dst->base2 = (PTR_MIDDLE(ptr) >> 8) & 0xFF; 
+	dst->base3 = PTR_HIGH(ptr); 
+}
+
+static inline void set_tss_desc(unsigned n, void *addr)
+{ 
+	set_tssldt_descriptor((void *)&gdt_table + __CPU_DESC_INDEX(n,tss), (unsigned long)addr, DESC_TSS, sizeof(struct tss_struct)); 
+} 
+
+static inline void set_ldt_desc(unsigned n, void *addr, int size)
+{ 
+	set_tssldt_descriptor((void *)&gdt_table + __CPU_DESC_INDEX(n,ldt), (unsigned long)addr, DESC_LDT, size); 
+}	
+
+/*
+ * load one particular LDT into the current CPU
+ */
+static inline void load_LDT (struct mm_struct *mm)
+{
+	int cpu = smp_processor_id();
+	void *segments = mm->context.segments;
+
+	if (!segments) {
+		clear_LDT(cpu);
+		return;
+	}
+		
+	set_ldt_desc(cpu, segments, LDT_ENTRIES);
+	__load_LDT(cpu);
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/div64.h linux-2.4.20/include/asm-x86_64/div64.h
--- linux-2.4.19/include/asm-x86_64/div64.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/div64.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,14 @@
+#ifndef __X86_64_DIV64
+#define __X86_64_DIV64
+
+/*
+ * Hey, we're already 64-bit, no
+ * need to play games..
+ */
+#define do_div(n,base) ({ \
+	int __res; \
+	__res = ((unsigned long) (n)) % (unsigned) (base); \
+	(n) = ((unsigned long) (n)) / (unsigned) (base); \
+	__res; })
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/dma.h linux-2.4.20/include/asm-x86_64/dma.h
--- linux-2.4.19/include/asm-x86_64/dma.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/dma.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,298 @@
+/* $Id: dma.h,v 1.1.1.1 2001/04/19 20:00:38 ak Exp $
+ * linux/include/asm/dma.h: Defines for using and allocating dma channels.
+ * Written by Hennus Bergman, 1992.
+ * High DMA channel support & info by Hannu Savolainen
+ * and John Boyd, Nov. 1992.
+ */
+
+#ifndef _ASM_DMA_H
+#define _ASM_DMA_H
+
+#include <linux/config.h>
+#include <linux/spinlock.h>	/* And spinlocks */
+#include <asm/io.h>		/* need byte IO */
+#include <linux/delay.h>
+
+
+#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
+#define dma_outb	outb_p
+#else
+#define dma_outb	outb
+#endif
+
+#define dma_inb		inb
+
+/*
+ * NOTES about DMA transfers:
+ *
+ *  controller 1: channels 0-3, byte operations, ports 00-1F
+ *  controller 2: channels 4-7, word operations, ports C0-DF
+ *
+ *  - ALL registers are 8 bits only, regardless of transfer size
+ *  - channel 4 is not used - cascades 1 into 2.
+ *  - channels 0-3 are byte - addresses/counts are for physical bytes
+ *  - channels 5-7 are word - addresses/counts are for physical words
+ *  - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries
+ *  - transfer count loaded to registers is 1 less than actual count
+ *  - controller 2 offsets are all even (2x offsets for controller 1)
+ *  - page registers for 5-7 don't use data bit 0, represent 128K pages
+ *  - page registers for 0-3 use bit 0, represent 64K pages
+ *
+ * DMA transfers are limited to the lower 16MB of _physical_ memory.  
+ * Note that addresses loaded into registers must be _physical_ addresses,
+ * not logical addresses (which may differ if paging is active).
+ *
+ *  Address mapping for channels 0-3:
+ *
+ *   A23 ... A16 A15 ... A8  A7 ... A0    (Physical addresses)
+ *    |  ...  |   |  ... |   |  ... |
+ *    |  ...  |   |  ... |   |  ... |
+ *    |  ...  |   |  ... |   |  ... |
+ *   P7  ...  P0  A7 ... A0  A7 ... A0   
+ * |    Page    | Addr MSB | Addr LSB |   (DMA registers)
+ *
+ *  Address mapping for channels 5-7:
+ *
+ *   A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0    (Physical addresses)
+ *    |  ...  |   \   \   ... \  \  \  ... \  \
+ *    |  ...  |    \   \   ... \  \  \  ... \  (not used)
+ *    |  ...  |     \   \   ... \  \  \  ... \
+ *   P7  ...  P1 (0) A7 A6  ... A0 A7 A6 ... A0   
+ * |      Page      |  Addr MSB   |  Addr LSB  |   (DMA registers)
+ *
+ * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses
+ * and counts _must_ be word-aligned (the lowest address bit is _ignored_ at
+ * the hardware level, so odd-byte transfers aren't possible).
+ *
+ * Transfer count (_not # bytes_) is limited to 64K, represented as actual
+ * count - 1 : 64K => 0xFFFF, 1 => 0x0000.  Thus, count is always 1 or more,
+ * and up to 128K bytes may be transferred on channels 5-7 in one operation. 
+ *
+ */
+
+#define MAX_DMA_CHANNELS	8
+
+/* The maximum address that we can perform a DMA transfer to on this platform */
+#define MAX_DMA_ADDRESS      (PAGE_OFFSET+0x1000000)
+
+/* 8237 DMA controllers */
+#define IO_DMA1_BASE	0x00	/* 8 bit slave DMA, channels 0..3 */
+#define IO_DMA2_BASE	0xC0	/* 16 bit master DMA, ch 4(=slave input)..7 */
+
+/* DMA controller registers */
+#define DMA1_CMD_REG		0x08	/* command register (w) */
+#define DMA1_STAT_REG		0x08	/* status register (r) */
+#define DMA1_REQ_REG            0x09    /* request register (w) */
+#define DMA1_MASK_REG		0x0A	/* single-channel mask (w) */
+#define DMA1_MODE_REG		0x0B	/* mode register (w) */
+#define DMA1_CLEAR_FF_REG	0x0C	/* clear pointer flip-flop (w) */
+#define DMA1_TEMP_REG           0x0D    /* Temporary Register (r) */
+#define DMA1_RESET_REG		0x0D	/* Master Clear (w) */
+#define DMA1_CLR_MASK_REG       0x0E    /* Clear Mask */
+#define DMA1_MASK_ALL_REG       0x0F    /* all-channels mask (w) */
+
+#define DMA2_CMD_REG		0xD0	/* command register (w) */
+#define DMA2_STAT_REG		0xD0	/* status register (r) */
+#define DMA2_REQ_REG            0xD2    /* request register (w) */
+#define DMA2_MASK_REG		0xD4	/* single-channel mask (w) */
+#define DMA2_MODE_REG		0xD6	/* mode register (w) */
+#define DMA2_CLEAR_FF_REG	0xD8	/* clear pointer flip-flop (w) */
+#define DMA2_TEMP_REG           0xDA    /* Temporary Register (r) */
+#define DMA2_RESET_REG		0xDA	/* Master Clear (w) */
+#define DMA2_CLR_MASK_REG       0xDC    /* Clear Mask */
+#define DMA2_MASK_ALL_REG       0xDE    /* all-channels mask (w) */
+
+#define DMA_ADDR_0              0x00    /* DMA address registers */
+#define DMA_ADDR_1              0x02
+#define DMA_ADDR_2              0x04
+#define DMA_ADDR_3              0x06
+#define DMA_ADDR_4              0xC0
+#define DMA_ADDR_5              0xC4
+#define DMA_ADDR_6              0xC8
+#define DMA_ADDR_7              0xCC
+
+#define DMA_CNT_0               0x01    /* DMA count registers */
+#define DMA_CNT_1               0x03
+#define DMA_CNT_2               0x05
+#define DMA_CNT_3               0x07
+#define DMA_CNT_4               0xC2
+#define DMA_CNT_5               0xC6
+#define DMA_CNT_6               0xCA
+#define DMA_CNT_7               0xCE
+
+#define DMA_PAGE_0              0x87    /* DMA page registers */
+#define DMA_PAGE_1              0x83
+#define DMA_PAGE_2              0x81
+#define DMA_PAGE_3              0x82
+#define DMA_PAGE_5              0x8B
+#define DMA_PAGE_6              0x89
+#define DMA_PAGE_7              0x8A
+
+#define DMA_MODE_READ	0x44	/* I/O to memory, no autoinit, increment, single mode */
+#define DMA_MODE_WRITE	0x48	/* memory to I/O, no autoinit, increment, single mode */
+#define DMA_MODE_CASCADE 0xC0   /* pass thru DREQ->HRQ, DACK<-HLDA only */
+
+#define DMA_AUTOINIT	0x10
+
+
+extern spinlock_t  dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&dma_spin_lock, flags);
+	return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+	spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
+
+/* enable/disable a specific DMA channel */
+static __inline__ void enable_dma(unsigned int dmanr)
+{
+	if (dmanr<=3)
+		dma_outb(dmanr,  DMA1_MASK_REG);
+	else
+		dma_outb(dmanr & 3,  DMA2_MASK_REG);
+}
+
+static __inline__ void disable_dma(unsigned int dmanr)
+{
+	if (dmanr<=3)
+		dma_outb(dmanr | 4,  DMA1_MASK_REG);
+	else
+		dma_outb((dmanr & 3) | 4,  DMA2_MASK_REG);
+}
+
+/* Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ * Use this once to initialize the FF to a known state.
+ * After that, keep track of it. :-)
+ * --- In order to do that, the DMA routines below should ---
+ * --- only be used while holding the DMA lock ! ---
+ */
+static __inline__ void clear_dma_ff(unsigned int dmanr)
+{
+	if (dmanr<=3)
+		dma_outb(0,  DMA1_CLEAR_FF_REG);
+	else
+		dma_outb(0,  DMA2_CLEAR_FF_REG);
+}
+
+/* set mode (above) for a specific DMA channel */
+static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
+{
+	if (dmanr<=3)
+		dma_outb(mode | dmanr,  DMA1_MODE_REG);
+	else
+		dma_outb(mode | (dmanr&3),  DMA2_MODE_REG);
+}
+
+/* Set only the page register bits of the transfer address.
+ * This is used for successive transfers when we know the contents of
+ * the lower 16 bits of the DMA current address register, but a 64k boundary
+ * may have been crossed.
+ */
+static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
+{
+	switch(dmanr) {
+		case 0:
+			dma_outb(pagenr, DMA_PAGE_0);
+			break;
+		case 1:
+			dma_outb(pagenr, DMA_PAGE_1);
+			break;
+		case 2:
+			dma_outb(pagenr, DMA_PAGE_2);
+			break;
+		case 3:
+			dma_outb(pagenr, DMA_PAGE_3);
+			break;
+		case 5:
+			dma_outb(pagenr & 0xfe, DMA_PAGE_5);
+			break;
+		case 6:
+			dma_outb(pagenr & 0xfe, DMA_PAGE_6);
+			break;
+		case 7:
+			dma_outb(pagenr & 0xfe, DMA_PAGE_7);
+			break;
+	}
+}
+
+
+/* Set transfer address & page bits for specific DMA channel.
+ * Assumes dma flipflop is clear.
+ */
+static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
+{
+	set_dma_page(dmanr, a>>16);
+	if (dmanr <= 3)  {
+	    dma_outb( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
+            dma_outb( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
+	}  else  {
+	    dma_outb( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
+	    dma_outb( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
+	}
+}
+
+
+/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for
+ * a specific DMA channel.
+ * You must ensure the parameters are valid.
+ * NOTE: from a manual: "the number of transfers is one more
+ * than the initial word count"! This is taken into account.
+ * Assumes dma flip-flop is clear.
+ * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7.
+ */
+static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
+{
+        count--;
+	if (dmanr <= 3)  {
+	    dma_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
+	    dma_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
+        } else {
+	    dma_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
+	    dma_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
+        }
+}
+
+
+/* Get DMA residue count. After a DMA transfer, this
+ * should return zero. Reading this while a DMA transfer is
+ * still in progress will return unpredictable results.
+ * If called before the channel has been used, it may return 1.
+ * Otherwise, it returns the number of _bytes_ left to transfer.
+ *
+ * Assumes DMA flip-flop is clear.
+ */
+static __inline__ int get_dma_residue(unsigned int dmanr)
+{
+	unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
+					 : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;
+
+	/* using short to get 16-bit wrap around */
+	unsigned short count;
+
+	count = 1 + dma_inb(io_port);
+	count += dma_inb(io_port) << 8;
+	
+	return (dmanr<=3)? count : (count<<1);
+}
+
+
+/* These are in kernel/dma.c: */
+extern int request_dma(unsigned int dmanr, const char * device_id);	/* reserve a DMA channel */
+extern void free_dma(unsigned int dmanr);	/* release it again */
+
+/* From PCI */
+
+#ifdef CONFIG_PCI
+extern int isa_dma_bridge_buggy;
+#else
+#define isa_dma_bridge_buggy 	(0)
+#endif
+
+#endif /* _ASM_DMA_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/e820.h linux-2.4.20/include/asm-x86_64/e820.h
--- linux-2.4.19/include/asm-x86_64/e820.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/e820.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,62 @@
+/*
+ * structures and definitions for the int 15, ax=e820 memory map
+ * scheme.
+ *
+ * In a nutshell, setup.S populates a scratch table in the
+ * empty_zero_block that contains a list of usable address/size
+ * duples.  setup.c, this information is transferred into the e820map,
+ * and in init.c/numa.c, that new information is used to mark pages
+ * reserved or not.
+ */
+#ifndef __E820_HEADER
+#define __E820_HEADER
+
+#include <linux/mmzone.h>
+
+#define E820MAP	0x2d0		/* our map */
+#define E820MAX	32		/* number of entries in E820MAP */
+#define E820NR	0x1e8		/* # entries in E820MAP */
+
+#define E820_RAM	1
+#define E820_RESERVED	2
+#define E820_ACPI	3 /* usable as RAM once ACPI tables have been read */
+#define E820_NVS	4
+
+#define HIGH_MEMORY	(1024*1024)
+
+#define LOWMEMSIZE()	(0x9f000)
+
+#define MAXMEM		(120UL * 1024 * 1024 * 1024 * 1024)  /* 120TB */ 
+
+
+#ifndef __ASSEMBLY__
+struct e820entry {
+	u64 addr;	/* start of memory segment */
+	u64 size;	/* size of memory segment */
+	u32 type;	/* type of memory segment */
+} __attribute__((packed));
+
+struct e820map {
+	int nr_map;
+	struct e820entry map[E820MAX];
+};
+
+extern unsigned long find_e820_area(unsigned long start, unsigned long end, 
+				    unsigned size);
+extern void add_memory_region(unsigned long start, unsigned long size, 
+			      int type);
+extern void setup_memory_region(void);
+extern void contig_e820_setup(void); 
+extern void e820_end_of_ram(void);
+extern void e820_reserve_resources(void);
+extern void e820_print_map(char *who);
+extern int e820_mapped(unsigned long start, unsigned long end, int type);
+
+extern void e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end);
+
+extern void parse_mem_cmdline (char ** cmdline_p);
+
+extern struct e820map e820;
+#endif/*!__ASSEMBLY__*/
+
+#endif/*__E820_HEADER*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/elf.h linux-2.4.20/include/asm-x86_64/elf.h
--- linux-2.4.19/include/asm-x86_64/elf.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/elf.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,128 @@
+#ifndef __ASM_X86_64_ELF_H
+#define __ASM_X86_64_ELF_H
+
+/*
+ * ELF register definitions..
+ */
+
+#include <asm/ptrace.h>
+#include <asm/user.h>
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef struct user_i387_struct elf_fpregset_t;
+typedef struct user_fxsr_struct elf_fpxregset_t;
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) \
+	((x)->e_machine == EM_X86_64)
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS	ELFCLASS64
+#define ELF_DATA	ELFDATA2LSB
+#define ELF_ARCH	EM_X86_64
+
+/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program starts %edx
+   contains a pointer to a function which might be registered using `atexit'.
+   This provides a mean for the dynamic linker to call DT_FINI functions for
+   shared libraries that have been loaded before the code runs.
+
+   A value of 0 tells we have no such handler. 
+
+   We might as well make sure everything else is cleared too (except for %esp),
+   just to make things more deterministic.
+ */
+#define ELF_PLAT_INIT(_r)	do { \
+	struct task_struct *cur = current; \
+	(_r)->rbx = 0; (_r)->rcx = 0; (_r)->rdx = 0; \
+	(_r)->rsi = 0; (_r)->rdi = 0; (_r)->rbp = 0; \
+	(_r)->rax = 0;				\
+	(_r)->r8 = 0;				\
+	(_r)->r9 = 0;				\
+	(_r)->r10 = 0;				\
+	(_r)->r11 = 0;				\
+	(_r)->r12 = 0;				\
+	(_r)->r13 = 0;				\
+	(_r)->r14 = 0;				\
+	(_r)->r15 = 0;				\
+        cur->thread.fs = 0; cur->thread.gs = 0; \
+	cur->thread.fsindex = 0; cur->thread.gsindex = 0; \
+        cur->thread.ds = 0; cur->thread.es = 0;  \
+	cur->thread.flags &= ~THREAD_IA32; \
+} while (0)
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE	4096
+
+/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
+   use of this is to invoke "./ld.so someprog" to test out a new version of
+   the loader.  We need to make sure that it is out of the way of the program
+   that it will "exec", and that there is sufficient room for the brk.  */
+
+#define ELF_ET_DYN_BASE         (2 * TASK_SIZE / 3)
+
+/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
+   now struct_user_regs, they are different). Assumes current is the process
+   getting dumped. */
+
+#define ELF_CORE_COPY_REGS(pr_reg, regs)  do { \
+	unsigned v;						\
+	(pr_reg)[0] = (regs)->r15;				\
+	(pr_reg)[1] = (regs)->r14;				\
+	(pr_reg)[2] = (regs)->r13;				\
+	(pr_reg)[3] = (regs)->r12;				\
+	(pr_reg)[4] = (regs)->rbp;				\
+	(pr_reg)[5] = (regs)->rbx;				\
+	(pr_reg)[6] = (regs)->r11;				\
+	(pr_reg)[7] = (regs)->r10;				\
+	(pr_reg)[8] = (regs)->r9;				\
+	(pr_reg)[9] = (regs)->r8;				\
+	(pr_reg)[10] = (regs)->rax;				\
+	(pr_reg)[11] = (regs)->rcx;				\
+	(pr_reg)[12] = (regs)->rdx;				\
+	(pr_reg)[13] = (regs)->rsi;				\
+	(pr_reg)[14] = (regs)->rdi;				\
+	(pr_reg)[15] = (regs)->orig_rax;			\
+	(pr_reg)[16] = (regs)->rip;				\
+	(pr_reg)[17] = (regs)->cs;				\
+	(pr_reg)[18] = (regs)->eflags;				\
+	(pr_reg)[19] = (regs)->rsp;				\
+	(pr_reg)[20] = (regs)->ss;				\
+	(pr_reg)[21] = current->thread.fs;			\
+	(pr_reg)[22] = current->thread.gs;			\
+	asm("movl %%ds,%0" : "=r" (v)); (pr_reg)[23] = v;	\
+	asm("movl %%es,%0" : "=r" (v)); (pr_reg)[24] = v;	\
+	asm("movl %%fs,%0" : "=r" (v)); (pr_reg)[25] = v;	\
+	asm("movl %%gs,%0" : "=r" (v)); (pr_reg)[26] = v;	\
+} while(0);
+
+/* This yields a mask that user programs can use to figure out what
+   instruction set this CPU supports.  This could be done in user space,
+   but it's not easy, and we've already done it here.  */
+
+#define ELF_HWCAP	(boot_cpu_data.x86_capability[0])
+
+/* This yields a string that ld.so will use to load implementation
+   specific libraries for optimization.  This is more specific in
+   intent than poking at uname or /proc/cpuinfo.
+
+   For the moment, we have only optimizations for the Intel generations,
+   but that could change... */
+
+/* I'm not sure if we can use '-' here */
+#define ELF_PLATFORM  ("x86_64")
+
+#ifdef __KERNEL__
+extern void set_personality_64bit(void);
+#define SET_PERSONALITY(ex, ibcs2) set_personality_64bit()
+	
+#endif
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/errno.h linux-2.4.20/include/asm-x86_64/errno.h
--- linux-2.4.19/include/asm-x86_64/errno.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/errno.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,132 @@
+#ifndef _X8664_ERRNO_H
+#define _X8664_ERRNO_H
+
+#define	EPERM		 1	/* Operation not permitted */
+#define	ENOENT		 2	/* No such file or directory */
+#define	ESRCH		 3	/* No such process */
+#define	EINTR		 4	/* Interrupted system call */
+#define	EIO		 5	/* I/O error */
+#define	ENXIO		 6	/* No such device or address */
+#define	E2BIG		 7	/* Argument list too long */
+#define	ENOEXEC		 8	/* Exec format error */
+#define	EBADF		 9	/* Bad file number */
+#define	ECHILD		10	/* No child processes */
+#define	EAGAIN		11	/* Try again */
+#define	ENOMEM		12	/* Out of memory */
+#define	EACCES		13	/* Permission denied */
+#define	EFAULT		14	/* Bad address */
+#define	ENOTBLK		15	/* Block device required */
+#define	EBUSY		16	/* Device or resource busy */
+#define	EEXIST		17	/* File exists */
+#define	EXDEV		18	/* Cross-device link */
+#define	ENODEV		19	/* No such device */
+#define	ENOTDIR		20	/* Not a directory */
+#define	EISDIR		21	/* Is a directory */
+#define	EINVAL		22	/* Invalid argument */
+#define	ENFILE		23	/* File table overflow */
+#define	EMFILE		24	/* Too many open files */
+#define	ENOTTY		25	/* Not a typewriter */
+#define	ETXTBSY		26	/* Text file busy */
+#define	EFBIG		27	/* File too large */
+#define	ENOSPC		28	/* No space left on device */
+#define	ESPIPE		29	/* Illegal seek */
+#define	EROFS		30	/* Read-only file system */
+#define	EMLINK		31	/* Too many links */
+#define	EPIPE		32	/* Broken pipe */
+#define	EDOM		33	/* Math argument out of domain of func */
+#define	ERANGE		34	/* Math result not representable */
+#define	EDEADLK		35	/* Resource deadlock would occur */
+#define	ENAMETOOLONG	36	/* File name too long */
+#define	ENOLCK		37	/* No record locks available */
+#define	ENOSYS		38	/* Function not implemented */
+#define	ENOTEMPTY	39	/* Directory not empty */
+#define	ELOOP		40	/* Too many symbolic links encountered */
+#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
+#define	ENOMSG		42	/* No message of desired type */
+#define	EIDRM		43	/* Identifier removed */
+#define	ECHRNG		44	/* Channel number out of range */
+#define	EL2NSYNC	45	/* Level 2 not synchronized */
+#define	EL3HLT		46	/* Level 3 halted */
+#define	EL3RST		47	/* Level 3 reset */
+#define	ELNRNG		48	/* Link number out of range */
+#define	EUNATCH		49	/* Protocol driver not attached */
+#define	ENOCSI		50	/* No CSI structure available */
+#define	EL2HLT		51	/* Level 2 halted */
+#define	EBADE		52	/* Invalid exchange */
+#define	EBADR		53	/* Invalid request descriptor */
+#define	EXFULL		54	/* Exchange full */
+#define	ENOANO		55	/* No anode */
+#define	EBADRQC		56	/* Invalid request code */
+#define	EBADSLT		57	/* Invalid slot */
+
+#define	EDEADLOCK	EDEADLK
+
+#define	EBFONT		59	/* Bad font file format */
+#define	ENOSTR		60	/* Device not a stream */
+#define	ENODATA		61	/* No data available */
+#define	ETIME		62	/* Timer expired */
+#define	ENOSR		63	/* Out of streams resources */
+#define	ENONET		64	/* Machine is not on the network */
+#define	ENOPKG		65	/* Package not installed */
+#define	EREMOTE		66	/* Object is remote */
+#define	ENOLINK		67	/* Link has been severed */
+#define	EADV		68	/* Advertise error */
+#define	ESRMNT		69	/* Srmount error */
+#define	ECOMM		70	/* Communication error on send */
+#define	EPROTO		71	/* Protocol error */
+#define	EMULTIHOP	72	/* Multihop attempted */
+#define	EDOTDOT		73	/* RFS specific error */
+#define	EBADMSG		74	/* Not a data message */
+#define	EOVERFLOW	75	/* Value too large for defined data type */
+#define	ENOTUNIQ	76	/* Name not unique on network */
+#define	EBADFD		77	/* File descriptor in bad state */
+#define	EREMCHG		78	/* Remote address changed */
+#define	ELIBACC		79	/* Can not access a needed shared library */
+#define	ELIBBAD		80	/* Accessing a corrupted shared library */
+#define	ELIBSCN		81	/* .lib section in a.out corrupted */
+#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
+#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
+#define	EILSEQ		84	/* Illegal byte sequence */
+#define	ERESTART	85	/* Interrupted system call should be restarted */
+#define	ESTRPIPE	86	/* Streams pipe error */
+#define	EUSERS		87	/* Too many users */
+#define	ENOTSOCK	88	/* Socket operation on non-socket */
+#define	EDESTADDRREQ	89	/* Destination address required */
+#define	EMSGSIZE	90	/* Message too long */
+#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
+#define	ENOPROTOOPT	92	/* Protocol not available */
+#define	EPROTONOSUPPORT	93	/* Protocol not supported */
+#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
+#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
+#define	EPFNOSUPPORT	96	/* Protocol family not supported */
+#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
+#define	EADDRINUSE	98	/* Address already in use */
+#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
+#define	ENETDOWN	100	/* Network is down */
+#define	ENETUNREACH	101	/* Network is unreachable */
+#define	ENETRESET	102	/* Network dropped connection because of reset */
+#define	ECONNABORTED	103	/* Software caused connection abort */
+#define	ECONNRESET	104	/* Connection reset by peer */
+#define	ENOBUFS		105	/* No buffer space available */
+#define	EISCONN		106	/* Transport endpoint is already connected */
+#define	ENOTCONN	107	/* Transport endpoint is not connected */
+#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
+#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
+#define	ETIMEDOUT	110	/* Connection timed out */
+#define	ECONNREFUSED	111	/* Connection refused */
+#define	EHOSTDOWN	112	/* Host is down */
+#define	EHOSTUNREACH	113	/* No route to host */
+#define	EALREADY	114	/* Operation already in progress */
+#define	EINPROGRESS	115	/* Operation now in progress */
+#define	ESTALE		116	/* Stale NFS file handle */
+#define	EUCLEAN		117	/* Structure needs cleaning */
+#define	ENOTNAM		118	/* Not a XENIX named type file */
+#define	ENAVAIL		119	/* No XENIX semaphores available */
+#define	EISNAM		120	/* Is a named type file */
+#define	EREMOTEIO	121	/* Remote I/O error */
+#define	EDQUOT		122	/* Quota exceeded */
+
+#define	ENOMEDIUM	123	/* No medium found */
+#define	EMEDIUMTYPE	124	/* Wrong medium type */
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/fcntl.h linux-2.4.20/include/asm-x86_64/fcntl.h
--- linux-2.4.19/include/asm-x86_64/fcntl.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/fcntl.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,79 @@
+#ifndef _X86_64_FCNTL_H
+#define _X86_64_FCNTL_H
+
+/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
+   located on an ext2 file system */
+#define O_ACCMODE	   0003
+#define O_RDONLY	     00
+#define O_WRONLY	     01
+#define O_RDWR		     02
+#define O_CREAT		   0100	/* not fcntl */
+#define O_EXCL		   0200	/* not fcntl */
+#define O_NOCTTY	   0400	/* not fcntl */
+#define O_TRUNC		  01000	/* not fcntl */
+#define O_APPEND	  02000
+#define O_NONBLOCK	  04000
+#define O_NDELAY	O_NONBLOCK
+#define O_SYNC		 010000
+#define FASYNC		 020000	/* fcntl, for BSD compatibility */
+#define O_DIRECT	 040000	/* direct disk access hint */
+#define O_LARGEFILE	0100000
+#define O_DIRECTORY	0200000	/* must be a directory */
+#define O_NOFOLLOW	0400000 /* don't follow links */
+
+#define F_DUPFD		0	/* dup */
+#define F_GETFD		1	/* get close_on_exec */
+#define F_SETFD		2	/* set/clear close_on_exec */
+#define F_GETFL		3	/* get file->f_flags */
+#define F_SETFL		4	/* set file->f_flags */
+#define F_GETLK		5
+#define F_SETLK		6
+#define F_SETLKW	7
+
+#define F_SETOWN	8	/*  for sockets. */
+#define F_GETOWN	9	/*  for sockets. */
+#define F_SETSIG	10	/*  for sockets. */
+#define F_GETSIG	11	/*  for sockets. */
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC	1	/* actually anything with low bit set goes */
+
+/* for posix fcntl() and lockf() */
+#define F_RDLCK		0
+#define F_WRLCK		1
+#define F_UNLCK		2
+
+/* for old implementation of bsd flock () */
+#define F_EXLCK		4	/* or 3 */
+#define F_SHLCK		8	/* or 4 */
+
+/* for leases */
+#define F_INPROGRESS	16
+
+/* operations for bsd flock(), also used by the kernel implementation */
+#define LOCK_SH		1	/* shared lock */
+#define LOCK_EX		2	/* exclusive lock */
+#define LOCK_NB		4	/* or'd with one of the above to prevent
+				   blocking */
+#define LOCK_UN		8	/* remove lock */
+
+#define LOCK_MAND	32	/* This is a mandatory flock */
+#define LOCK_READ	64	/* ... Which allows concurrent read operations */
+#define LOCK_WRITE	128	/* ... Which allows concurrent write operations */
+#define LOCK_RW		192	/* ... Which allows concurrent read & write ops */
+
+struct flock {
+	short  l_type;
+	short  l_whence;
+	off_t l_start;
+	off_t l_len;
+	pid_t  l_pid;
+};
+
+#define F_LINUX_SPECIFIC_BASE	1024
+
+#ifdef __KERNEL__
+#define flock64	flock
+#endif
+
+#endif /* !_X86_64_FCNTL_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/fixmap.h linux-2.4.20/include/asm-x86_64/fixmap.h
--- linux-2.4.19/include/asm-x86_64/fixmap.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/fixmap.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,93 @@
+/*
+ * fixmap.h: compile-time virtual memory allocation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1998 Ingo Molnar
+ *
+ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
+ */
+
+#ifndef _ASM_FIXMAP_H
+#define _ASM_FIXMAP_H
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <asm/apicdef.h>
+#include <asm/page.h>
+#include <asm/vsyscall.h>
+
+/*
+ * Here we define all the compile-time 'special' virtual
+ * addresses. The point is to have a constant address at
+ * compile time, but to set the physical address only
+ * in the boot process.
+ *
+ * these 'compile-time allocated' memory buffers are
+ * fixed-size 4k pages. (or larger if used with an increment
+ * highger than 1) use fixmap_set(idx,phys) to associate
+ * physical memory with fixmap indices.
+ *
+ * TLB entries of such buffers will not be flushed across
+ * task switches.
+ */
+
+enum fixed_addresses {
+	VSYSCALL_LAST_PAGE,
+	VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE + ((VSYSCALL_END-VSYSCALL_START) >> PAGE_SHIFT) - 1,
+	VSYSCALL_HPET,
+	FIX_HPET_BASE,
+#ifdef CONFIG_X86_LOCAL_APIC
+	FIX_APIC_BASE,	/* local (CPU) APIC) -- required for SMP or not */
+#endif
+#ifdef CONFIG_X86_IO_APIC
+	FIX_IO_APIC_BASE_0,
+	FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1,
+#endif
+	__end_of_fixed_addresses
+};
+
+extern void __set_fixmap (enum fixed_addresses idx,
+					unsigned long phys, pgprot_t flags);
+
+#define set_fixmap(idx, phys) \
+		__set_fixmap(idx, phys, PAGE_KERNEL)
+/*
+ * Some hardware wants to get fixmapped without caching.
+ */
+#define set_fixmap_nocache(idx, phys) \
+		__set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
+
+#define FIXADDR_TOP	(VSYSCALL_END-PAGE_SIZE)
+#define FIXADDR_SIZE	(__end_of_fixed_addresses << PAGE_SHIFT)
+#define FIXADDR_START	(FIXADDR_TOP - FIXADDR_SIZE)
+
+#define __fix_to_virt(x)	(FIXADDR_TOP - ((x) << PAGE_SHIFT))
+
+extern void __this_fixmap_does_not_exist(void);
+
+/*
+ * 'index to address' translation. If anyone tries to use the idx
+ * directly without tranlation, we catch the bug with a NULL-deference
+ * kernel oops. Illegal ranges of incoming indices are caught too.
+ */
+extern inline unsigned long fix_to_virt(const unsigned int idx)
+{
+	/*
+	 * this branch gets completely eliminated after inlining,
+	 * except when someone tries to use fixaddr indices in an
+	 * illegal way. (such as mixing up address types or using
+	 * out-of-range indices).
+	 *
+	 * If it doesn't get removed, the linker will complain
+	 * loudly with a reasonably clear error message..
+	 */
+	if (idx >= __end_of_fixed_addresses)
+		__this_fixmap_does_not_exist();
+
+        return __fix_to_virt(idx);
+}
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/floppy.h linux-2.4.20/include/asm-x86_64/floppy.h
--- linux-2.4.19/include/asm-x86_64/floppy.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/floppy.h	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,286 @@
+/*
+ * Architecture specific parts of the Floppy driver
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1995
+ */
+#ifndef __ASM_X86_64_FLOPPY_H
+#define __ASM_X86_64_FLOPPY_H
+
+#include <linux/vmalloc.h>
+
+
+/*
+ * The DMA channel used by the floppy controller cannot access data at
+ * addresses >= 16MB
+ *
+ * Went back to the 1MB limit, as some people had problems with the floppy
+ * driver otherwise. It doesn't matter much for performance anyway, as most
+ * floppy accesses go through the track buffer.
+ */
+#define _CROSS_64KB(a,s,vdma) \
+(!vdma && ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64))
+
+#define CROSS_64KB(a,s) _CROSS_64KB(a,s,use_virtual_dma & 1)
+
+
+#define SW fd_routine[use_virtual_dma&1]
+#define CSW fd_routine[can_use_virtual_dma & 1]
+
+
+#define fd_inb(port)			inb_p(port)
+#define fd_outb(port,value)		outb_p(port,value)
+
+#define fd_request_dma()        CSW._request_dma(FLOPPY_DMA,"floppy")
+#define fd_free_dma()           CSW._free_dma(FLOPPY_DMA)
+#define fd_enable_irq()         enable_irq(FLOPPY_IRQ)
+#define fd_disable_irq()        disable_irq(FLOPPY_IRQ)
+#define fd_free_irq()		free_irq(FLOPPY_IRQ, NULL)
+#define fd_get_dma_residue()    SW._get_dma_residue(FLOPPY_DMA)
+#define fd_dma_mem_alloc(size)	SW._dma_mem_alloc(size)
+#define fd_dma_setup(addr, size, mode, io) SW._dma_setup(addr, size, mode, io)
+
+#define FLOPPY_CAN_FALLBACK_ON_NODMA
+
+static int virtual_dma_count;
+static int virtual_dma_residue;
+static char *virtual_dma_addr;
+static int virtual_dma_mode;
+static int doing_pdma;
+
+static void floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
+{
+	register unsigned char st;
+
+#undef TRACE_FLPY_INT
+
+#ifdef TRACE_FLPY_INT
+	static int calls=0;
+	static int bytes=0;
+	static int dma_wait=0;
+#endif
+	if(!doing_pdma) {
+		floppy_interrupt(irq, dev_id, regs);
+		return;
+	}
+
+#ifdef TRACE_FLPY_INT
+	if(!calls)
+		bytes = virtual_dma_count;
+#endif
+
+	{
+		register int lcount;
+		register char *lptr;
+
+		st = 1;
+		for(lcount=virtual_dma_count, lptr=virtual_dma_addr; 
+		    lcount; lcount--, lptr++) {
+			st=inb(virtual_dma_port+4) & 0xa0 ;
+			if(st != 0xa0) 
+				break;
+			if(virtual_dma_mode)
+				outb_p(*lptr, virtual_dma_port+5);
+			else
+				*lptr = inb_p(virtual_dma_port+5);
+		}
+		virtual_dma_count = lcount;
+		virtual_dma_addr = lptr;
+		st = inb(virtual_dma_port+4);
+	}
+
+#ifdef TRACE_FLPY_INT
+	calls++;
+#endif
+	if(st == 0x20)
+		return;
+	if(!(st & 0x20)) {
+		virtual_dma_residue += virtual_dma_count;
+		virtual_dma_count=0;
+#ifdef TRACE_FLPY_INT
+		printk("count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n", 
+		       virtual_dma_count, virtual_dma_residue, calls, bytes,
+		       dma_wait);
+		calls = 0;
+		dma_wait=0;
+#endif
+		doing_pdma = 0;
+		floppy_interrupt(irq, dev_id, regs);
+		return;
+	}
+#ifdef TRACE_FLPY_INT
+	if(!virtual_dma_count)
+		dma_wait++;
+#endif
+}
+
+static void fd_disable_dma(void)
+{
+	if(! (can_use_virtual_dma & 1))
+		disable_dma(FLOPPY_DMA);
+	doing_pdma = 0;
+	virtual_dma_residue += virtual_dma_count;
+	virtual_dma_count=0;
+}
+
+static int vdma_request_dma(unsigned int dmanr, const char * device_id)
+{
+	return 0;
+}
+
+static void vdma_nop(unsigned int dummy)
+{
+}
+
+
+static int vdma_get_dma_residue(unsigned int dummy)
+{
+	return virtual_dma_count + virtual_dma_residue;
+}
+
+
+static int fd_request_irq(void)
+{
+	if(can_use_virtual_dma)
+		return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
+						   "floppy", NULL);
+	else
+		return request_irq(FLOPPY_IRQ, floppy_interrupt,
+						   SA_INTERRUPT|SA_SAMPLE_RANDOM,
+						   "floppy", NULL);	
+
+}
+
+static unsigned long dma_mem_alloc(unsigned long size)
+{
+	return __get_dma_pages(GFP_KERNEL,get_order(size));
+}
+
+
+static unsigned long vdma_mem_alloc(unsigned long size)
+{
+	return (unsigned long) vmalloc(size);
+
+}
+
+#define nodma_mem_alloc(size) vdma_mem_alloc(size)
+
+static void _fd_dma_mem_free(unsigned long addr, unsigned long size)
+{
+	if((unsigned long) addr >= (unsigned long) high_memory)
+		return vfree((void *)addr);
+	else
+		free_pages(addr, get_order(size));		
+}
+
+#define fd_dma_mem_free(addr, size)  _fd_dma_mem_free(addr, size) 
+
+static void _fd_chose_dma_mode(char *addr, unsigned long size)
+{
+	if(can_use_virtual_dma == 2) {
+		if((unsigned long) addr >= (unsigned long) high_memory ||
+		   virt_to_bus(addr) >= 0x1000000 ||
+		   _CROSS_64KB(addr, size, 0))
+			use_virtual_dma = 1;
+		else
+			use_virtual_dma = 0;
+	} else {
+		use_virtual_dma = can_use_virtual_dma & 1;
+	}
+}
+
+#define fd_chose_dma_mode(addr, size) _fd_chose_dma_mode(addr, size)
+
+
+static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
+{
+	doing_pdma = 1;
+	virtual_dma_port = io;
+	virtual_dma_mode = (mode  == DMA_MODE_WRITE);
+	virtual_dma_addr = addr;
+	virtual_dma_count = size;
+	virtual_dma_residue = 0;
+	return 0;
+}
+
+static int hard_dma_setup(char *addr, unsigned long size, int mode, int io)
+{
+#ifdef FLOPPY_SANITY_CHECK
+	if (CROSS_64KB(addr, size)) {
+		printk("DMA crossing 64-K boundary %p-%p\n", addr, addr+size);
+		return -1;
+	}
+#endif
+	/* actual, physical DMA */
+	doing_pdma = 0;
+	clear_dma_ff(FLOPPY_DMA);
+	set_dma_mode(FLOPPY_DMA,mode);
+	set_dma_addr(FLOPPY_DMA,virt_to_bus(addr));
+	set_dma_count(FLOPPY_DMA,size);
+	enable_dma(FLOPPY_DMA);
+	return 0;
+}
+
+struct fd_routine_l {
+	int (*_request_dma)(unsigned int dmanr, const char * device_id);
+	void (*_free_dma)(unsigned int dmanr);
+	int (*_get_dma_residue)(unsigned int dummy);
+	unsigned long (*_dma_mem_alloc) (unsigned long size);
+	int (*_dma_setup)(char *addr, unsigned long size, int mode, int io);
+} fd_routine[] = {
+	{
+		request_dma,
+		free_dma,
+		get_dma_residue,
+		dma_mem_alloc,
+		hard_dma_setup
+	},
+	{
+		vdma_request_dma,
+		vdma_nop,
+		vdma_get_dma_residue,
+		vdma_mem_alloc,
+		vdma_dma_setup
+	}
+};
+
+
+static int FDC1 = 0x3f0;
+static int FDC2 = -1;
+
+/*
+ * Floppy types are stored in the rtc's CMOS RAM and so rtc_lock
+ * is needed to prevent corrupted CMOS RAM in case "insmod floppy"
+ * coincides with another rtc CMOS user.		Paul G.
+ */
+#define FLOPPY0_TYPE	({				\
+	unsigned long flags;				\
+	unsigned char val;				\
+	spin_lock_irqsave(&rtc_lock, flags);		\
+	val = (CMOS_READ(0x10) >> 4) & 15;		\
+	spin_unlock_irqrestore(&rtc_lock, flags);	\
+	val;						\
+})
+
+#define FLOPPY1_TYPE	({				\
+	unsigned long flags;				\
+	unsigned char val;				\
+	spin_lock_irqsave(&rtc_lock, flags);		\
+	val = CMOS_READ(0x10) & 15;			\
+	spin_unlock_irqrestore(&rtc_lock, flags);	\
+	val;						\
+})
+
+#define N_FDC 2
+#define N_DRIVE 8
+
+#define FLOPPY_MOTOR_MASK 0xf0
+
+#define AUTO_DMA
+
+#define EXTRA_FLOPPY_PARAMS
+
+#endif /* __ASM_X86_64_FLOPPY_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/fpu32.h linux-2.4.20/include/asm-x86_64/fpu32.h
--- linux-2.4.19/include/asm-x86_64/fpu32.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/fpu32.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,10 @@
+#ifndef _FPU32_H
+#define _FPU32_H 1
+
+struct _fpstate_ia32;
+
+int restore_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 *buf, int fsave);
+int save_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 *buf, 
+		   struct pt_regs *regs, int fsave);
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/hardirq.h linux-2.4.20/include/asm-x86_64/hardirq.h
--- linux-2.4.19/include/asm-x86_64/hardirq.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/hardirq.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,91 @@
+#ifndef __ASM_HARDIRQ_H
+#define __ASM_HARDIRQ_H
+
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/irq.h>
+
+/* assembly code in softirq.h is sensitive to the offsets of these fields */
+typedef struct {
+	unsigned int __softirq_pending;
+	unsigned int __local_irq_count;
+	unsigned int __local_bh_count;
+	unsigned int __syscall_count;
+	struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
+	unsigned int __nmi_count;	/* arch dependent */
+} ____cacheline_aligned irq_cpustat_t;
+
+#include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
+
+/*
+ * Are we in an interrupt context? Either doing bottom half
+ * or hardware interrupt processing?
+ */
+#define in_interrupt() ({ int __cpu = smp_processor_id(); \
+	(local_irq_count(__cpu) + local_bh_count(__cpu) != 0); })
+
+#define in_irq() (local_irq_count(smp_processor_id()) != 0)
+
+#ifndef CONFIG_SMP
+
+#define hardirq_trylock(cpu)	(local_irq_count(cpu) == 0)
+#define hardirq_endlock(cpu)	do { } while (0)
+
+#define irq_enter(cpu, irq)	(local_irq_count(cpu)++)
+#define irq_exit(cpu, irq)	(local_irq_count(cpu)--)
+
+#define synchronize_irq()	barrier()
+
+#else
+
+#include <asm/atomic.h>
+#include <asm/smp.h>
+
+extern unsigned char global_irq_holder;
+extern unsigned volatile long global_irq_lock; /* long for set_bit -RR */
+
+static inline int irqs_running (void)
+{
+	int i;
+
+	for (i = 0; i < smp_num_cpus; i++)
+		if (local_irq_count(i))
+			return 1;
+	return 0;
+}
+
+static inline void release_irqlock(int cpu)
+{
+	/* if we didn't own the irq lock, just ignore.. */
+	if (global_irq_holder == (unsigned char) cpu) {
+		global_irq_holder = NO_PROC_ID;
+		clear_bit(0,&global_irq_lock);
+	}
+}
+
+static inline void irq_enter(int cpu, int irq)
+{
+	++local_irq_count(cpu);
+
+	while (test_bit(0,&global_irq_lock)) {
+		cpu_relax();
+	}
+}
+
+static inline void irq_exit(int cpu, int irq)
+{
+	--local_irq_count(cpu);
+}
+
+static inline int hardirq_trylock(int cpu)
+{
+	return !local_irq_count(cpu) && !test_bit(0,&global_irq_lock);
+}
+
+#define hardirq_endlock(cpu)	do { } while (0)
+
+extern void synchronize_irq(void);
+
+#endif /* CONFIG_SMP */
+
+#endif /* __ASM_HARDIRQ_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/hdreg.h linux-2.4.20/include/asm-x86_64/hdreg.h
--- linux-2.4.19/include/asm-x86_64/hdreg.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/hdreg.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,12 @@
+/*
+ *  linux/include/asm-x86_64/hdreg.h
+ *
+ *  Copyright (C) 1994-1996  Linus Torvalds & authors
+ */
+
+#ifndef __ASMx86_64_HDREG_H
+#define __ASMx86_64_HDREG_H
+
+typedef unsigned short ide_ioreg_t;
+
+#endif /* __ASMx86_64_HDREG_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/hw_irq.h linux-2.4.20/include/asm-x86_64/hw_irq.h
--- linux-2.4.19/include/asm-x86_64/hw_irq.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/hw_irq.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,205 @@
+#ifndef _ASM_HW_IRQ_H
+#define _ASM_HW_IRQ_H
+
+/*
+ *	linux/include/asm/hw_irq.h
+ *
+ *	(C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
+ *
+ *	moved some of the old arch/i386/kernel/irq.h to here. VY
+ *
+ *	IRQ/IPI changes taken from work by Thomas Radke
+ *	<tomsoft@informatik.tu-chemnitz.de>
+ *
+ *	hacked by Andi Kleen for x86-64.
+ * 
+ *  $Id: hw_irq.h,v 1.29 2002/04/15 23:43:12 ak Exp $
+ */
+
+#include <linux/config.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+
+/*
+ * IDT vectors usable for external interrupt sources start
+ * at 0x20:
+ */
+#define FIRST_EXTERNAL_VECTOR	0x20
+
+#define IA32_SYSCALL_VECTOR	0x80
+#define KDBENTER_VECTOR		0x81
+
+
+/*
+ * Vectors 0x20-0x2f are used for ISA interrupts.
+ */
+
+/*
+ * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
+ *
+ *  some of the following vectors are 'rare', they are merged
+ *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
+ *  TLB, reschedule and local APIC vectors are performance-critical.
+ *
+ *  Vectors 0xf0-0xf9 are free (reserved for future Linux use).
+ */
+#define SPURIOUS_APIC_VECTOR	0xff
+#define ERROR_APIC_VECTOR	0xfe
+#define INVALIDATE_TLB_VECTOR	0xfd
+#define RESCHEDULE_VECTOR	0xfc
+#define KDB_VECTOR		0xfa
+#define CALL_FUNCTION_VECTOR	0xfb
+#define KDB_VECTOR              0xfa
+
+/*
+ * Local APIC timer IRQ vector is on a different priority level,
+ * to work around the 'lost local interrupt if more than 2 IRQ
+ * sources per level' errata.
+ */
+#define LOCAL_TIMER_VECTOR	0xef
+
+/*
+ * First APIC vector available to drivers: (vectors 0x30-0xee)
+ * we start at 0x31 to spread out vectors evenly between priority
+ * levels. (0x80 is the syscall vector)
+ */
+#define FIRST_DEVICE_VECTOR	0x31
+#define FIRST_SYSTEM_VECTOR	0xef
+
+extern int irq_vector[NR_IRQS];
+#define IO_APIC_VECTOR(irq)	irq_vector[irq]
+
+/*
+ * Various low-level irq details needed by irq.c, process.c,
+ * time.c, io_apic.c and smp.c
+ *
+ * Interrupt entry/exit code at both C and assembly level
+ */
+
+extern void mask_irq(unsigned int irq);
+extern void unmask_irq(unsigned int irq);
+extern void disable_8259A_irq(unsigned int irq);
+extern void enable_8259A_irq(unsigned int irq);
+extern int i8259A_irq_pending(unsigned int irq);
+extern void make_8259A_irq(unsigned int irq);
+extern void init_8259A(int aeoi);
+extern void FASTCALL(send_IPI_self(int vector));
+extern void init_VISWS_APIC_irqs(void);
+extern void setup_IO_APIC(void);
+extern void disable_IO_APIC(void);
+extern void print_IO_APIC(void);
+extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
+extern void send_IPI(int dest, int vector);
+
+extern unsigned long io_apic_irqs;
+
+extern atomic_t irq_err_count;
+extern atomic_t irq_mis_count;
+
+extern char _stext, _etext;
+
+#define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
+
+#define __STR(x) #x
+#define STR(x) __STR(x)
+
+#include <asm/ptrace.h>
+#ifndef ASM_OFFSET_H
+#include <asm/offset.h>
+#endif
+
+/* IF:off, stack contains irq number on origrax */ 
+#define IRQ_ENTER								\
+"	cld ;"									\
+"	pushq %rdi ;"								\
+"	pushq %rsi ;"								\
+"	pushq %rdx ;"								\
+"	pushq %rcx ;"								\
+"	pushq %rax ;"								\
+"	pushq %r8 ;"								\
+"	pushq %r9 ;"								\
+"	pushq %r10 ;"								\
+"	pushq %r11 ;"								\
+"	leaq -48(%rsp),%rdi	;"						\
+"	testl $3,136(%rdi)	;"						\
+"	je 1f ;"								\
+"	swapgs ;"								\
+"1:	addl $1,%gs: " STR(pda_irqcount) ";"					\
+"	movq %gs: " STR(pda_irqstackptr) ",%rax ;"				\
+"	cmoveq %rax,%rsp ;"							\
+"	pushq %rdi ;" 
+
+#define IRQ_NAME2(nr) nr##_interrupt(void)
+#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
+
+/*
+ *	SMP has a few special interrupts for IPI messages
+ */
+
+	/* there is a second layer of macro just to get the symbolic
+	   name for the vector evaluated. This change is for RTLinux */
+#define BUILD_SMP_INTERRUPT(x,v) XBUILD_SMP_INTERRUPT(x,v)
+#define XBUILD_SMP_INTERRUPT(x,v)\
+asmlinkage void x(void); \
+asmlinkage void call_##x(void); \
+__asm__( \
+"\n"__ALIGN_STR"\n" \
+SYMBOL_NAME_STR(x) ":\n\t" \
+	"push $" #v "-256;" \
+	IRQ_ENTER \
+	"call " SYMBOL_NAME_STR(smp_##x) " ; " \
+	"jmp ret_from_intr")
+
+#define BUILD_COMMON_IRQ()
+
+#define BUILD_IRQ(nr) \
+asmlinkage void IRQ_NAME(nr); \
+__asm__( \
+"\n"__ALIGN_STR "\n" \
+SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
+	"push $" #nr "-256 ; " \
+	"jmp common_interrupt");
+
+extern unsigned long prof_cpu_mask;
+extern unsigned int * prof_buffer;
+extern unsigned long prof_len;
+extern unsigned long prof_shift;
+
+/*
+ * x86 profiling function, SMP safe. We might want to do this in
+ * assembly totally?
+ */
+static inline void x86_do_profile (unsigned long eip)
+{
+	if (!prof_buffer)
+		return;
+
+	/*
+	 * Only measure the CPUs specified by /proc/irq/prof_cpu_mask.
+	 * (default is all CPUs.)
+	 */
+	if (!((1<<smp_processor_id()) & prof_cpu_mask))
+		return;
+
+	eip -= (unsigned long) &_stext;
+	eip >>= prof_shift;
+	/*
+	 * Don't ignore out-of-bounds EIP values silently,
+	 * put them into the last histogram slot, so if
+	 * present, they will show up as a sharp peak.
+	 */
+	if (eip > prof_len-1)
+		eip = prof_len-1;
+	atomic_inc((atomic_t *)&prof_buffer[eip]);
+}
+
+#ifdef CONFIG_SMP /*more of this file should probably be ifdefed SMP */
+static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {
+	if (IO_APIC_IRQ(i))
+		send_IPI_self(IO_APIC_VECTOR(i));
+}
+#else
+static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
+#endif
+
+#endif /* _ASM_HW_IRQ_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/i387.h linux-2.4.20/include/asm-x86_64/i387.h
--- linux-2.4.19/include/asm-x86_64/i387.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/i387.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,151 @@
+/*
+ * include/asm-x86_64/i387.h
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ *
+ * Pentium III FXSR, SSE support
+ * General FPU state handling cleanups
+ *	Gareth Hughes <gareth@valinux.com>, May 2000
+ * x86-64 work by Andi Kleen 2002
+ */
+
+#ifndef __ASM_X86_64_I387_H
+#define __ASM_X86_64_I387_H
+
+#include <linux/sched.h>
+#include <asm/processor.h>
+#include <asm/sigcontext.h>
+#include <asm/user.h>
+
+extern void init_fpu(void);
+int save_i387( struct _fpstate *buf);
+
+/*
+ * FPU lazy state save handling...
+ */
+
+#define kernel_fpu_end() stts()
+
+#define unlazy_fpu( tsk ) do { \
+	if ( tsk->flags & PF_USEDFPU ) \
+		save_init_fpu( tsk ); \
+} while (0)
+
+#define clear_fpu( tsk ) do { \
+	if ( tsk->flags & PF_USEDFPU ) { \
+		asm volatile("fwait"); \
+		tsk->flags &= ~PF_USEDFPU; \
+		stts(); \
+	} \
+} while (0)
+
+#define load_mxcsr( val ) do { \
+		unsigned long __mxcsr = ((unsigned long)(val) & 0xffbf); \
+		asm volatile( "ldmxcsr %0" : : "m" (__mxcsr) ); \
+} while (0)
+
+/*
+ * ptrace request handers...
+ */
+extern int get_fpregs( struct user_i387_struct *buf,
+		       struct task_struct *tsk );
+extern int set_fpregs( struct task_struct *tsk,
+		       struct user_i387_struct *buf );
+
+/*
+ * FPU state for core dumps...
+ */
+extern int dump_fpu( struct pt_regs *regs,
+		     struct user_i387_struct *fpu );
+
+/* 
+ * i387 state interaction
+ */
+#define get_fpu_mxcsr(t) ((t)->thread.i387.fxsave.mxcsr)
+#define get_fpu_cwd(t) ((t)->thread.i387.fxsave.cwd)
+#define get_fpu_fxsr_twd(t) ((t)->thread.i387.fxsave.twd)
+#define get_fpu_swd(t) ((t)->thread.i387.fxsave.swd)
+#define set_fpu_cwd(t,val) ((t)->thread.i387.fxsave.cwd = (val))
+#define set_fpu_swd(t,val) ((t)->thread.i387.fxsave.swd = (val))
+#define set_fpu_fxsr_twd(t,val) ((t)->thread.i387.fxsave.twd = (val))
+#define set_fpu_mxcsr(t,val) ((t)->thread.i387.fxsave.mxcsr = (val)&0xffbf)
+
+static inline int restore_fpu_checking(struct i387_fxsave_struct *fx) 
+{ 
+	int err;
+	asm volatile("1:  rex64 ; fxrstor (%[fx])\n\t"
+		     "2:\n"
+		     ".section .fixup,\"ax\"\n"
+		     "3:  movl $-1,%[err]\n"
+		     "    jmp  2b\n"
+		     ".previous\n"
+		     ".section __ex_table,\"a\"\n"
+		     "   .align 8\n"
+		     "   .quad  1b,3b\n"
+		     ".previous"
+		     : [err] "=r" (err)
+		     : [fx] "r" (fx), "0" (0)); 
+	return err;
+} 
+
+static inline int save_i387_checking(struct i387_fxsave_struct *fx) 
+{ 
+	int err;
+	asm volatile("1:  rex64 ; fxsave (%[fx])\n\t"
+		     "2:\n"
+		     ".section .fixup,\"ax\"\n"
+		     "3:  movl $-1,%[err]\n"
+		     "    jmp  2b\n"
+		     ".previous\n"
+		     ".section __ex_table,\"a\"\n"
+		     "   .align 8\n"
+		     "   .quad  1b,3b\n"
+		     ".previous"
+		     : [err] "=r" (err)
+		     : [fx] "r" (fx), "0" (0)); 
+	return err;
+} 
+
+static inline void kernel_fpu_begin(void)
+{
+	struct task_struct *tsk = current;
+	if (tsk->flags & PF_USEDFPU) {
+		asm volatile("fxsave %0 ; fnclex"
+			      : "=m" (tsk->thread.i387.fxsave));
+		tsk->flags &= ~PF_USEDFPU;
+		return;
+	}
+	clts();
+}
+
+static inline void save_init_fpu( struct task_struct *tsk )
+{
+	asm volatile( "fxsave %0 ; fnclex"
+		      : "=m" (tsk->thread.i387.fxsave));
+	tsk->flags &= ~PF_USEDFPU;
+	stts();
+}
+
+/* 
+ * This restores directly out of user space. Exceptions are handled.
+ */ 
+static inline int restore_i387(struct _fpstate *buf)
+{
+	return restore_fpu_checking((struct i387_fxsave_struct *)buf);
+}
+
+
+static inline void empty_fpu(struct task_struct *child)
+{
+	if (!child->used_math) {
+		/* Simulate an empty FPU. */
+		memset(&child->thread.i387.fxsave,0,sizeof(struct i387_fxsave_struct));
+		child->thread.i387.fxsave.cwd = 0x037f; 
+		child->thread.i387.fxsave.swd = 0;
+		child->thread.i387.fxsave.twd = 0; 
+		child->thread.i387.fxsave.mxcsr = 0x1f80;
+	}
+	child->used_math = 1; 
+}		
+
+#endif /* __ASM_X86_64_I387_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/ia32.h linux-2.4.20/include/asm-x86_64/ia32.h
--- linux-2.4.19/include/asm-x86_64/ia32.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/ia32.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,245 @@
+#ifndef _ASM_X86_64_IA32_H
+#define _ASM_X86_64_IA32_H
+
+#include <linux/config.h>
+
+#ifdef CONFIG_IA32_EMULATION
+
+/*
+ * 32 bit structures for IA32 support.
+ */
+
+/* 32bit compatibility types */
+typedef unsigned int	       __kernel_size_t32;
+typedef int		       __kernel_ssize_t32;
+typedef int		       __kernel_ptrdiff_t32;
+typedef int		       __kernel_time_t32;
+typedef int		       __kernel_clock_t32;
+typedef int		       __kernel_pid_t32;
+typedef unsigned short	       __kernel_ipc_pid_t32;
+typedef unsigned short	       __kernel_uid_t32;
+typedef unsigned 	       __kernel_uid32_t32;
+typedef unsigned short	       __kernel_gid_t32;
+typedef unsigned 	       __kernel_gid32_t32;
+typedef unsigned short	       __kernel_dev_t32;
+typedef unsigned int	       __kernel_ino_t32;
+typedef unsigned short	       __kernel_mode_t32;
+typedef unsigned short	       __kernel_umode_t32;
+typedef short		       __kernel_nlink_t32;
+typedef int		       __kernel_daddr_t32;
+typedef int		       __kernel_off_t32;
+typedef unsigned int	       __kernel_caddr_t32;
+typedef long		       __kernel_loff_t32;
+typedef __kernel_fsid_t	       __kernel_fsid_t32;
+
+
+/* fcntl.h */
+struct flock32 {
+       short l_type;
+       short l_whence;
+       __kernel_off_t32 l_start;
+       __kernel_off_t32 l_len;
+       __kernel_pid_t32 l_pid;
+};
+
+
+struct ia32_flock64 {
+	short  l_type;
+	short  l_whence;
+	loff_t l_start;  /* unnatural alignment */
+	loff_t l_len;
+	pid_t  l_pid;
+} __attribute__((packed));
+
+#define F_GETLK64	12	/*  using 'struct flock64' */
+#define F_SETLK64	13
+#define F_SETLKW64	14
+
+#include <asm/sigcontext32.h>
+
+/* signal.h */
+#define _IA32_NSIG	       64
+#define _IA32_NSIG_BPW	       32
+#define _IA32_NSIG_WORDS	       (_IA32_NSIG / _IA32_NSIG_BPW)
+
+typedef struct {
+       unsigned int sig[_IA32_NSIG_WORDS];
+} sigset32_t;
+
+struct sigaction32 {
+       unsigned int  sa_handler;	/* Really a pointer, but need to deal 
+					     with 32 bits */
+       unsigned int sa_flags;
+       unsigned int sa_restorer;	/* Another 32 bit pointer */
+       sigset32_t sa_mask;		/* A 32 bit mask */
+};
+
+typedef unsigned int old_sigset32_t;	/* at least 32 bits */
+
+struct old_sigaction32 {
+       unsigned int  sa_handler;	/* Really a pointer, but need to deal 
+					     with 32 bits */
+       old_sigset32_t sa_mask;		/* A 32 bit mask */
+       unsigned int sa_flags;
+       unsigned int sa_restorer;	/* Another 32 bit pointer */
+};
+
+typedef struct sigaltstack_ia32 {
+	unsigned int	ss_sp;
+	int		ss_flags;
+	unsigned int	ss_size;
+} stack_ia32_t;
+
+struct ucontext_ia32 {
+	unsigned int	  uc_flags;
+	unsigned int 	  uc_link;
+	stack_ia32_t	  uc_stack;
+	struct sigcontext_ia32 uc_mcontext;
+	sigset32_t	  uc_sigmask;	/* mask last for extensibility */
+};
+
+struct stat32 {
+       unsigned short st_dev;
+       unsigned short __pad1;
+       unsigned int st_ino;
+       unsigned short st_mode;
+       unsigned short st_nlink;
+       unsigned short st_uid;
+       unsigned short st_gid;
+       unsigned short st_rdev;
+       unsigned short __pad2;
+       unsigned int  st_size;
+       unsigned int  st_blksize;
+       unsigned int  st_blocks;
+       unsigned int  st_atime;
+       unsigned int  __unused1;
+       unsigned int  st_mtime;
+       unsigned int  __unused2;
+       unsigned int  st_ctime;
+       unsigned int  __unused3;
+       unsigned int  __unused4;
+       unsigned int  __unused5;
+};
+
+
+/* This matches struct stat64 in glibc2.2, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct stat64 {
+	unsigned long long	st_dev;
+	unsigned char		__pad0[4];
+
+#define STAT64_HAS_BROKEN_ST_INO	1
+	unsigned int		__st_ino;
+
+	unsigned int		st_mode;
+	unsigned int		st_nlink;
+
+	unsigned int		st_uid;
+	unsigned int		st_gid;
+
+	unsigned long long	st_rdev;
+	unsigned char		__pad3[4];
+
+	long long		st_size;
+	unsigned int		st_blksize;
+
+	long long		st_blocks;/* Number 512-byte blocks allocated. */
+
+	unsigned long long	st_atime;
+	unsigned long long	st_mtime;
+	unsigned long long	st_ctime;
+
+	unsigned long long	st_ino;
+} __attribute__((packed));
+
+
+struct statfs32 {
+       int f_type;
+       int f_bsize;
+       int f_blocks;
+       int f_bfree;
+       int f_bavail;
+       int f_files;
+       int f_ffree;
+       __kernel_fsid_t32 f_fsid;
+       int f_namelen;  /* SunOS ignores this field. */
+       int f_spare[6];
+};
+
+typedef union sigval32 {
+	int sival_int;
+	unsigned int sival_ptr;
+} sigval_t32;
+
+typedef struct siginfo32 {
+	int si_signo;
+	int si_errno;
+	int si_code;
+
+	union {
+		int _pad[((128/sizeof(int)) - 3)];
+
+		/* kill() */
+		struct {
+			unsigned int _pid;	/* sender's pid */
+			unsigned int _uid;	/* sender's uid */
+		} _kill;
+
+		/* POSIX.1b timers */
+		struct {
+			unsigned int _timer1;
+			unsigned int _timer2;
+		} _timer;
+
+		/* POSIX.1b signals */
+		struct {
+			unsigned int _pid;	/* sender's pid */
+			unsigned int _uid;	/* sender's uid */
+			sigval_t32 _sigval;
+		} _rt;
+
+		/* SIGCHLD */
+		struct {
+			unsigned int _pid;	/* which child */
+			unsigned int _uid;	/* sender's uid */
+			int _status;		/* exit code */
+			__kernel_clock_t32 _utime;
+			__kernel_clock_t32 _stime;
+		} _sigchld;
+
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		struct {
+			unsigned int _addr;	/* faulting insn/memory ref. */
+		} _sigfault;
+
+		/* SIGPOLL */
+		struct {
+			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			int _fd;
+		} _sigpoll;
+	} _sifields;
+} siginfo_t32;
+
+
+struct ustat32 {
+	__u32	f_tfree;
+	__kernel_ino_t32		f_tinode;
+	char			f_fname[6];
+	char			f_fpack[6];
+};
+
+struct iovec32 { 
+	unsigned int iov_base; 
+	int iov_len; 
+};
+
+
+#ifdef __KERNEL__
+struct iovec *get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type);
+#endif
+
+
+#endif /* !CONFIG_IA32_SUPPORT */
+ 
+#endif 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/ia32_unistd.h linux-2.4.20/include/asm-x86_64/ia32_unistd.h
--- linux-2.4.19/include/asm-x86_64/ia32_unistd.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/ia32_unistd.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,253 @@
+#ifndef _ASM_X86_64_IA32_UNISTD_H_
+#define _ASM_X86_64_IA32_UNISTD_H_
+
+/*
+ * This file contains the system call numbers of the ia32 port,
+ * this is for the kernel only.
+ */
+
+#define __NR_ia32_exit		  1
+#define __NR_ia32_fork		  2
+#define __NR_ia32_read		  3
+#define __NR_ia32_write		  4
+#define __NR_ia32_open		  5
+#define __NR_ia32_close		  6
+#define __NR_ia32_waitpid		  7
+#define __NR_ia32_creat		  8
+#define __NR_ia32_link		  9
+#define __NR_ia32_unlink		 10
+#define __NR_ia32_execve		 11
+#define __NR_ia32_chdir		 12
+#define __NR_ia32_time		 13
+#define __NR_ia32_mknod		 14
+#define __NR_ia32_chmod		 15
+#define __NR_ia32_lchown		 16
+#define __NR_ia32_break		 17
+#define __NR_ia32_oldstat		 18
+#define __NR_ia32_lseek		 19
+#define __NR_ia32_getpid		 20
+#define __NR_ia32_mount		 21
+#define __NR_ia32_umount		 22
+#define __NR_ia32_setuid		 23
+#define __NR_ia32_getuid		 24
+#define __NR_ia32_stime		 25
+#define __NR_ia32_ptrace		 26
+#define __NR_ia32_alarm		 27
+#define __NR_ia32_oldfstat		 28
+#define __NR_ia32_pause		 29
+#define __NR_ia32_utime		 30
+#define __NR_ia32_stty		 31
+#define __NR_ia32_gtty		 32
+#define __NR_ia32_access		 33
+#define __NR_ia32_nice		 34
+#define __NR_ia32_ftime		 35
+#define __NR_ia32_sync		 36
+#define __NR_ia32_kill		 37
+#define __NR_ia32_rename		 38
+#define __NR_ia32_mkdir		 39
+#define __NR_ia32_rmdir		 40
+#define __NR_ia32_dup		 41
+#define __NR_ia32_pipe		 42
+#define __NR_ia32_times		 43
+#define __NR_ia32_prof		 44
+#define __NR_ia32_brk		 45
+#define __NR_ia32_setgid		 46
+#define __NR_ia32_getgid		 47
+#define __NR_ia32_signal		 48
+#define __NR_ia32_geteuid		 49
+#define __NR_ia32_getegid		 50
+#define __NR_ia32_acct		 51
+#define __NR_ia32_umount2		 52
+#define __NR_ia32_lock		 53
+#define __NR_ia32_ioctl		 54
+#define __NR_ia32_fcntl		 55
+#define __NR_ia32_mpx		 56
+#define __NR_ia32_setpgid		 57
+#define __NR_ia32_ulimit		 58
+#define __NR_ia32_oldolduname	 59
+#define __NR_ia32_umask		 60
+#define __NR_ia32_chroot		 61
+#define __NR_ia32_ustat		 62
+#define __NR_ia32_dup2		 63
+#define __NR_ia32_getppid		 64
+#define __NR_ia32_getpgrp		 65
+#define __NR_ia32_setsid		 66
+#define __NR_ia32_sigaction		 67
+#define __NR_ia32_sgetmask		 68
+#define __NR_ia32_ssetmask		 69
+#define __NR_ia32_setreuid		 70
+#define __NR_ia32_setregid		 71
+#define __NR_ia32_sigsuspend		 72
+#define __NR_ia32_sigpending		 73
+#define __NR_ia32_sethostname	 74
+#define __NR_ia32_setrlimit		 75
+#define __NR_ia32_getrlimit		 76	/* Back compatible 2Gig limited rlimit */
+#define __NR_ia32_getrusage		 77
+#define __NR_ia32_gettimeofday	 78
+#define __NR_ia32_settimeofday	 79
+#define __NR_ia32_getgroups		 80
+#define __NR_ia32_setgroups		 81
+#define __NR_ia32_select		 82
+#define __NR_ia32_symlink		 83
+#define __NR_ia32_oldlstat		 84
+#define __NR_ia32_readlink		 85
+#define __NR_ia32_uselib		 86
+#define __NR_ia32_swapon		 87
+#define __NR_ia32_reboot		 88
+#define __NR_ia32_readdir		 89
+#define __NR_ia32_mmap		 90
+#define __NR_ia32_munmap		 91
+#define __NR_ia32_truncate		 92
+#define __NR_ia32_ftruncate		 93
+#define __NR_ia32_fchmod		 94
+#define __NR_ia32_fchown		 95
+#define __NR_ia32_getpriority	 96
+#define __NR_ia32_setpriority	 97
+#define __NR_ia32_profil		 98
+#define __NR_ia32_statfs		 99
+#define __NR_ia32_fstatfs		100
+#define __NR_ia32_ioperm		101
+#define __NR_ia32_socketcall		102
+#define __NR_ia32_syslog		103
+#define __NR_ia32_setitimer		104
+#define __NR_ia32_getitimer		105
+#define __NR_ia32_stat		106
+#define __NR_ia32_lstat		107
+#define __NR_ia32_fstat		108
+#define __NR_ia32_olduname		109
+#define __NR_ia32_iopl		110
+#define __NR_ia32_vhangup		111
+#define __NR_ia32_idle		112
+#define __NR_ia32_vm86old		113
+#define __NR_ia32_wait4		114
+#define __NR_ia32_swapoff		115
+#define __NR_ia32_sysinfo		116
+#define __NR_ia32_ipc		117
+#define __NR_ia32_fsync		118
+#define __NR_ia32_sigreturn		119
+#define __NR_ia32_clone		120
+#define __NR_ia32_setdomainname	121
+#define __NR_ia32_uname		122
+#define __NR_ia32_modify_ldt		123
+#define __NR_ia32_adjtimex		124
+#define __NR_ia32_mprotect		125
+#define __NR_ia32_sigprocmask	126
+#define __NR_ia32_create_module	127
+#define __NR_ia32_init_module	128
+#define __NR_ia32_delete_module	129
+#define __NR_ia32_get_kernel_syms	130
+#define __NR_ia32_quotactl		131
+#define __NR_ia32_getpgid		132
+#define __NR_ia32_fchdir		133
+#define __NR_ia32_bdflush		134
+#define __NR_ia32_sysfs		135
+#define __NR_ia32_personality	136
+#define __NR_ia32_afs_syscall	137 /* Syscall for Andrew File System */
+#define __NR_ia32_setfsuid		138
+#define __NR_ia32_setfsgid		139
+#define __NR_ia32__llseek		140
+#define __NR_ia32_getdents		141
+#define __NR_ia32__newselect		142
+#define __NR_ia32_flock		143
+#define __NR_ia32_msync		144
+#define __NR_ia32_readv		145
+#define __NR_ia32_writev		146
+#define __NR_ia32_getsid		147
+#define __NR_ia32_fdatasync		148
+#define __NR_ia32__sysctl		149
+#define __NR_ia32_mlock		150
+#define __NR_ia32_munlock		151
+#define __NR_ia32_mlockall		152
+#define __NR_ia32_munlockall		153
+#define __NR_ia32_sched_setparam		154
+#define __NR_ia32_sched_getparam		155
+#define __NR_ia32_sched_setscheduler		156
+#define __NR_ia32_sched_getscheduler		157
+#define __NR_ia32_sched_yield		158
+#define __NR_ia32_sched_get_priority_max	159
+#define __NR_ia32_sched_get_priority_min	160
+#define __NR_ia32_sched_rr_get_interval	161
+#define __NR_ia32_nanosleep		162
+#define __NR_ia32_mremap		163
+#define __NR_ia32_setresuid		164
+#define __NR_ia32_getresuid		165
+#define __NR_ia32_vm86		166
+#define __NR_ia32_query_module	167
+#define __NR_ia32_poll		168
+#define __NR_ia32_nfsservctl		169
+#define __NR_ia32_setresgid		170
+#define __NR_ia32_getresgid		171
+#define __NR_ia32_prctl              172
+#define __NR_ia32_rt_sigreturn	173
+#define __NR_ia32_rt_sigaction	174
+#define __NR_ia32_rt_sigprocmask	175
+#define __NR_ia32_rt_sigpending	176
+#define __NR_ia32_rt_sigtimedwait	177
+#define __NR_ia32_rt_sigqueueinfo	178
+#define __NR_ia32_rt_sigsuspend	179
+#define __NR_ia32_pread		180
+#define __NR_ia32_pwrite		181
+#define __NR_ia32_chown		182
+#define __NR_ia32_getcwd		183
+#define __NR_ia32_capget		184
+#define __NR_ia32_capset		185
+#define __NR_ia32_sigaltstack	186
+#define __NR_ia32_sendfile		187
+#define __NR_ia32_getpmsg		188	/* some people actually want streams */
+#define __NR_ia32_putpmsg		189	/* some people actually want streams */
+#define __NR_ia32_vfork		190
+#define __NR_ia32_ugetrlimit		191	/* SuS compliant getrlimit */
+#define __NR_ia32_mmap2		192
+#define __NR_ia32_truncate64		193
+#define __NR_ia32_ftruncate64	194
+#define __NR_ia32_stat64		195
+#define __NR_ia32_lstat64		196
+#define __NR_ia32_fstat64		197
+#define __NR_ia32_lchown32		198
+#define __NR_ia32_getuid32		199
+#define __NR_ia32_getgid32		200
+#define __NR_ia32_geteuid32		201
+#define __NR_ia32_getegid32		202
+#define __NR_ia32_setreuid32		203
+#define __NR_ia32_setregid32		204
+#define __NR_ia32_getgroups32	205
+#define __NR_ia32_setgroups32	206
+#define __NR_ia32_fchown32		207
+#define __NR_ia32_setresuid32	208
+#define __NR_ia32_getresuid32	209
+#define __NR_ia32_setresgid32	210
+#define __NR_ia32_getresgid32	211
+#define __NR_ia32_chown32		212
+#define __NR_ia32_setuid32		213
+#define __NR_ia32_setgid32		214
+#define __NR_ia32_setfsuid32		215
+#define __NR_ia32_setfsgid32		216
+#define __NR_ia32_pivot_root		217
+#define __NR_ia32_mincore		218
+#define __NR_ia32_madvise		219
+#define __NR_ia32_madvise1		219	/* delete when C lib stub is removed */
+#define __NR_ia32_getdents64		220
+#define __NR_ia32_fcntl64		221
+#define __NR_ia32_tuxcall		222
+#define __NR_ia32_security		223
+#define __NR_ia32_gettid		224
+#define __NR_ia32_readahead		225
+#define __NR_ia32_sendfile64		239
+#define __NR_ia32_futex		240
+#define __NR_ia32_sched_setaffinity	241
+#define __NR_ia32_sched_getaffinity	242
+#define __NR_ia32_set_thread_area	243
+#define __NR_ia32_get_thread_area	244
+#define __NR_ia32_io_setup		245
+#define __NR_ia32_io_destroy		246
+#define __NR_ia32_io_getevents	247
+#define __NR_ia32_io_submit		248
+#define __NR_ia32_io_cancel		249
+#define __NR_ia32_alloc_hugepages	250
+#define __NR_ia32_free_hugepages	251
+#define __NR_ia32_exit_group		252
+
+
+#define IA32_NR_syscalls 260
+
+#endif /* _ASM_X86_64_IA32_UNISTD_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/ide.h linux-2.4.20/include/asm-x86_64/ide.h
--- linux-2.4.19/include/asm-x86_64/ide.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/ide.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,128 @@
+/*
+ *  linux/include/asm-x86_64/ide.h
+ *
+ *  Copyright (C) 1994-1996  Linus Torvalds & authors
+ */
+
+/*
+ *  This file contains the x86_64 architecture specific IDE code.
+ */
+
+#ifndef __ASMx86_64_IDE_H
+#define __ASMx86_64_IDE_H
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+
+#ifndef MAX_HWIFS
+# ifdef CONFIG_BLK_DEV_IDEPCI
+#define MAX_HWIFS	10
+# else
+#define MAX_HWIFS	6
+# endif
+#endif
+
+#define ide__sti()	__sti()
+
+static __inline__ int ide_default_irq(ide_ioreg_t base)
+{
+	switch (base) {
+		case 0x1f0: return 14;
+		case 0x170: return 15;
+		case 0x1e8: return 11;
+		case 0x168: return 10;
+		case 0x1e0: return 8;
+		case 0x160: return 12;
+		default:
+			return 0;
+	}
+}
+
+static __inline__ ide_ioreg_t ide_default_io_base(int index)
+{
+	switch (index) {
+		case 0:	return 0x1f0;
+		case 1:	return 0x170;
+		case 2: return 0x1e8;
+		case 3: return 0x168;
+		case 4: return 0x1e0;
+		case 5: return 0x160;
+		default:
+			return 0;
+	}
+}
+
+static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+{
+	ide_ioreg_t reg = data_port;
+	int i;
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw->io_ports[i] = reg;
+		reg += 1;
+	}
+	if (ctrl_port) {
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+	} else {
+		hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
+	}
+	if (irq != NULL)
+		*irq = 0;
+	hw->io_ports[IDE_IRQ_OFFSET] = 0;
+}
+
+static __inline__ void ide_init_default_hwifs(void)
+{
+#ifndef CONFIG_BLK_DEV_IDEPCI
+	hw_regs_t hw;
+	int index;
+
+	for(index = 0; index < MAX_HWIFS; index++) {
+		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
+		hw.irq = ide_default_irq(ide_default_io_base(index));
+		ide_register_hw(&hw, NULL);
+	}
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+}
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned head		: 4;	/* always zeros here */
+		unsigned unit		: 1;	/* drive select number, 0 or 1 */
+		unsigned bit5		: 1;	/* always 1 */
+		unsigned lba		: 1;	/* using LBA instead of CHS */
+		unsigned bit7		: 1;	/* always 1 */
+	} b;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
+
+#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
+#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
+#define ide_check_region(from,extent)		check_region((from), (extent))
+#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
+#define ide_release_region(from,extent)		release_region((from), (extent))
+
+/*
+ * The following are not needed for the non-m68k ports
+ */
+#define ide_ack_intr(hwif)		(1)
+#define ide_fix_driveid(id)		do {} while (0)
+#define ide_release_lock(lock)		do {} while (0)
+#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASMx86_64_IDE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/init.h linux-2.4.20/include/asm-x86_64/init.h
--- linux-2.4.19/include/asm-x86_64/init.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/init.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1 @@
+#error "<asm/init.h> should never be used - use <linux/init.h> instead"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/io.h linux-2.4.20/include/asm-x86_64/io.h
--- linux-2.4.19/include/asm-x86_64/io.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/io.h	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,271 @@
+#ifndef _ASM_IO_H
+#define _ASM_IO_H
+
+#include <linux/config.h>
+
+/*
+ * This file contains the definitions for the x86 IO instructions
+ * inb/inw/inl/outb/outw/outl and the "string versions" of the same
+ * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
+ * versions of the single-IO instructions (inb_p/inw_p/..).
+ *
+ * This file is not meant to be obfuscating: it's just complicated
+ * to (a) handle it all in a way that makes gcc able to optimize it
+ * as well as possible and (b) trying to avoid writing the same thing
+ * over and over again with slight variations and possibly making a
+ * mistake somewhere.
+ */
+
+/*
+ * Thanks to James van Artsdalen for a better timing-fix than
+ * the two short jumps: using outb's to a nonexistent port seems
+ * to guarantee better timings even on fast machines.
+ *
+ * On the other hand, I'd like to be sure of a non-existent port:
+ * I feel a bit unsafe about using 0x80 (should be safe, though)
+ *
+ *		Linus
+ */
+
+ /*
+  *  Bit simplified and optimized by Jan Hubicka
+  *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999.
+  *
+  *  isa_memset_io, isa_memcpy_fromio, isa_memcpy_toio added,
+  *  isa_read[wl] and isa_write[wl] fixed
+  *  - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+  */
+
+#ifdef SLOW_IO_BY_JUMPING
+#define __SLOW_DOWN_IO "\njmp 1f\n1:\tjmp 1f\n1:"
+#else
+#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
+#endif
+
+#ifdef REALLY_SLOW_IO
+#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
+#else
+#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
+#endif
+
+/*
+ * Talk about misusing macros..
+ */
+#define __OUT1(s,x) \
+extern inline void out##s(unsigned x value, unsigned short port) {
+
+#define __OUT2(s,s1,s2) \
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+
+#define __OUT(s,s1,x) \
+__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
+
+#define __IN1(s) \
+extern inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
+
+#define __IN2(s,s1,s2) \
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+
+#define __IN(s,s1,i...) \
+__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+
+#define __INS(s) \
+extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("rep ; ins" #s \
+: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+#define __OUTS(s) \
+extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("rep ; outs" #s \
+: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+#define RETURN_TYPE unsigned char
+__IN(b,"")
+#undef RETURN_TYPE
+#define RETURN_TYPE unsigned short
+__IN(w,"")
+#undef RETURN_TYPE
+#define RETURN_TYPE unsigned int
+__IN(l,"")
+#undef RETURN_TYPE
+
+__OUT(b,"b",char)
+__OUT(w,"w",short)
+__OUT(l,,int)
+
+__INS(b)
+__INS(w)
+__INS(l)
+
+__OUTS(b)
+__OUTS(w)
+__OUTS(l)
+
+#define IO_SPACE_LIMIT 0xffff
+
+#ifdef __KERNEL__
+
+#include <linux/vmalloc.h>
+
+/*
+ * Temporary debugging check to catch old code using
+ * unmapped ISA addresses. Will be removed in 2.4.
+ */
+#ifdef CONFIG_IO_DEBUG
+  extern void *__io_virt_debug(unsigned long x, const char *file, int line);
+  extern unsigned long __io_phys_debug(unsigned long x, const char *file, int line);
+  #define __io_virt(x) __io_virt_debug((unsigned long)(x), __FILE__, __LINE__)
+//#define __io_phys(x) __io_phys_debug((unsigned long)(x), __FILE__, __LINE__)
+#else
+  #define __io_virt(x) ((void *)(x))
+//#define __io_phys(x) __pa(x)
+#endif
+
+/*
+ * Change virtual addresses to physical addresses and vv.
+ * These are pretty trivial
+ */
+extern inline unsigned long virt_to_phys(volatile void * address)
+{
+	return __pa(address);
+}
+
+extern inline void * phys_to_virt(unsigned long address)
+{
+	return __va(address);
+}
+
+/*
+ * Change "struct page" to physical address.
+ */
+#ifdef CONFIG_DISCONTIGMEM
+#include <asm/mmzone.h>
+#else
+#define page_to_phys(page)	(((page) - mem_map) << PAGE_SHIFT)
+#endif
+
+extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+
+extern inline void * ioremap (unsigned long offset, unsigned long size)
+{
+	return __ioremap(offset, size, 0);
+}
+
+/*
+ * This one maps high address device memory and turns off caching for that area.
+ * it's useful if some control registers are in such an area and write combining
+ * or read caching is not desirable:
+ */
+extern inline void * ioremap_nocache (unsigned long offset, unsigned long size)
+{
+        return __ioremap(offset, size, _PAGE_PCD);
+}
+
+extern void iounmap(void *addr);
+
+/*
+ * IO bus memory addresses are also 1:1 with the physical address
+ */
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+#define page_to_bus page_to_phys
+
+/*
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently. On the x86 architecture, we just read/write the
+ * memory location directly.
+ */
+
+#define readb(addr) (*(volatile unsigned char *) __io_virt(addr))
+#define readw(addr) (*(volatile unsigned short *) __io_virt(addr))
+#define readl(addr) (*(volatile unsigned int *) __io_virt(addr))
+#define __raw_readb readb
+#define __raw_readw readw
+#define __raw_readl readl
+
+#define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b))
+#define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b))
+#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))
+#define __raw_writeb writeb
+#define __raw_writew writew
+#define __raw_writel writel
+
+void *memcpy_fromio(void*,const void*,unsigned); 
+void *memcpy_toio(void*,const void*,unsigned); 
+
+#define memset_io(a,b,c)	memset(__io_virt(a),(b),(c))
+
+/*
+ * ISA space is 'always mapped' on a typical x86 system, no need to
+ * explicitly ioremap() it. The fact that the ISA IO space is mapped
+ * to PAGE_OFFSET is pure coincidence - it does not mean ISA values
+ * are physical addresses. The following constant pointer can be
+ * used as the IO-area pointer (it can be iounmapped as well, so the
+ * analogy with PCI is quite large):
+ */
+#define __ISA_IO_base ((char *)(PAGE_OFFSET))
+
+#define isa_readb(a) readb(__ISA_IO_base + (a))
+#define isa_readw(a) readw(__ISA_IO_base + (a))
+#define isa_readl(a) readl(__ISA_IO_base + (a))
+#define isa_writeb(b,a) writeb(b,__ISA_IO_base + (a))
+#define isa_writew(w,a) writew(w,__ISA_IO_base + (a))
+#define isa_writel(l,a) writel(l,__ISA_IO_base + (a))
+#define isa_memset_io(a,b,c)		memset_io(__ISA_IO_base + (a),(b),(c))
+#define isa_memcpy_fromio(a,b,c)	memcpy_fromio((a),__ISA_IO_base + (b),(c))
+#define isa_memcpy_toio(a,b,c)		memcpy_toio(__ISA_IO_base + (a),(b),(c))
+
+
+/*
+ * Again, x86-64 does not require mem IO specific function.
+ */
+
+#define eth_io_copy_and_sum(a,b,c,d)		eth_copy_and_sum((a),__io_virt(b),(c),(d))
+#define isa_eth_io_copy_and_sum(a,b,c,d)	eth_copy_and_sum((a),__io_virt(__ISA_IO_base + (b)),(c),(d))
+
+static inline int check_signature(unsigned long io_addr,
+	const unsigned char *signature, int length)
+{
+	int retval = 0;
+	do {
+		if (readb(io_addr) != *signature)
+			goto out;
+		io_addr++;
+		signature++;
+		length--;
+	} while (length);
+	retval = 1;
+out:
+	return retval;
+}
+
+static inline int isa_check_signature(unsigned long io_addr,
+	const unsigned char *signature, int length)
+{
+	int retval = 0;
+	do {
+		if (isa_readb(io_addr) != *signature)
+			goto out;
+		io_addr++;
+		signature++;
+		length--;
+	} while (length);
+	retval = 1;
+out:
+	return retval;
+}
+
+/* Nothing to do */
+
+#define dma_cache_inv(_start,_size)		do { } while (0)
+#define dma_cache_wback(_start,_size)		do { } while (0)
+#define dma_cache_wback_inv(_start,_size)	do { } while (0)
+
+#define flush_write_buffers() 
+
+#endif /* __KERNEL__ */
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/io_apic.h linux-2.4.20/include/asm-x86_64/io_apic.h
--- linux-2.4.19/include/asm-x86_64/io_apic.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/io_apic.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,148 @@
+#ifndef __ASM_IO_APIC_H
+#define __ASM_IO_APIC_H
+
+#include <linux/config.h>
+#include <asm/types.h>
+
+/*
+ * Intel IO-APIC support for SMP and UP systems.
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar
+ */
+
+#ifdef CONFIG_X86_IO_APIC
+
+#define APIC_MISMATCH_DEBUG
+
+#define IO_APIC_BASE(idx) \
+		((volatile int *)(__fix_to_virt(FIX_IO_APIC_BASE_0 + idx) \
+		+ (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK)))
+
+/*
+ * The structure of the IO-APIC:
+ */
+struct IO_APIC_reg_00 {
+	__u32	__reserved_2	: 24,
+		ID		:  4,
+		__reserved_1	:  4;
+} __attribute__ ((packed));
+
+struct IO_APIC_reg_01 {
+	__u32	version		:  8,
+		__reserved_2	:  7,
+		PRQ		:  1,
+		entries		:  8,
+		__reserved_1	:  8;
+} __attribute__ ((packed));
+
+struct IO_APIC_reg_02 {
+	__u32	__reserved_2	: 24,
+		arbitration	:  4,
+		__reserved_1	:  4;
+} __attribute__ ((packed));
+
+/*
+ * # of IO-APICs and # of IRQ routing registers
+ */
+extern int nr_ioapics;
+extern int nr_ioapic_registers[MAX_IO_APICS];
+
+enum ioapic_irq_destination_types {
+	dest_Fixed = 0,
+	dest_LowestPrio = 1,
+	dest_SMI = 2,
+	dest__reserved_1 = 3,
+	dest_NMI = 4,
+	dest_INIT = 5,
+	dest__reserved_2 = 6,
+	dest_ExtINT = 7
+};
+
+struct IO_APIC_route_entry {
+	__u32	vector		:  8,
+		delivery_mode	:  3,	/* 000: FIXED
+					 * 001: lowest prio
+					 * 111: ExtINT
+					 */
+		dest_mode	:  1,	/* 0: physical, 1: logical */
+		delivery_status	:  1,
+		polarity	:  1,
+		irr		:  1,
+		trigger		:  1,	/* 0: edge, 1: level */
+		mask		:  1,	/* 0: enabled, 1: disabled */
+		__reserved_2	: 15;
+
+	union {		struct { __u32
+					__reserved_1	: 24,
+					physical_dest	:  4,
+					__reserved_2	:  4;
+			} physical;
+
+			struct { __u32
+					__reserved_1	: 24,
+					logical_dest	:  8;
+			} logical;
+	} dest;
+
+} __attribute__ ((packed));
+
+/*
+ * MP-BIOS irq configuration table structures:
+ */
+
+/* I/O APIC entries */
+extern struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
+
+/* # of MP IRQ source entries */
+extern int mp_irq_entries;
+
+/* MP IRQ source entries */
+extern struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+
+/* non-0 if default (table-less) MP configuration */
+extern int mpc_default_type;
+
+static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
+{
+	*IO_APIC_BASE(apic) = reg;
+	return *(IO_APIC_BASE(apic)+4);
+}
+
+static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
+{
+	*IO_APIC_BASE(apic) = reg;
+	*(IO_APIC_BASE(apic)+4) = value;
+}
+
+/*
+ * Re-write a value: to be used for read-modify-write
+ * cycles where the read already set up the index register.
+ */
+static inline void io_apic_modify(unsigned int apic, unsigned int value)
+{
+	*(IO_APIC_BASE(apic)+4) = value;
+}
+
+/*
+ * Synchronize the IO-APIC and the CPU by doing
+ * a dummy read from the IO-APIC
+ */
+static inline void io_apic_sync(unsigned int apic)
+{
+	(void) *(IO_APIC_BASE(apic)+4);
+}
+
+/* 1 if "noapic" boot option passed */
+extern int skip_ioapic_setup;
+
+/*
+ * If we use the IO-APIC for IRQ routing, disable automatic
+ * assignment of PCI IRQ's.
+ */
+#define io_apic_assign_pci_irqs (mp_irq_entries && !skip_ioapic_setup)
+
+#else  /* !CONFIG_X86_IO_APIC */
+#define io_apic_assign_pci_irqs 0
+#endif
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/ioctl.h linux-2.4.20/include/asm-x86_64/ioctl.h
--- linux-2.4.19/include/asm-x86_64/ioctl.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/ioctl.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,75 @@
+/* $Id: ioctl.h,v 1.2 2001/07/04 09:08:13 ak Exp $
+ *
+ * linux/ioctl.h for Linux by H.H. Bergman.
+ */
+
+#ifndef _ASMX8664_IOCTL_H
+#define _ASMX8664_IOCTL_H
+
+/* ioctl command encoding: 32 bits total, command in lower 16 bits,
+ * size of the parameter structure in the lower 14 bits of the
+ * upper 16 bits.
+ * Encoding the size of the parameter structure in the ioctl request
+ * is useful for catching programs compiled with old versions
+ * and to avoid overwriting user space outside the user buffer area.
+ * The highest 2 bits are reserved for indicating the ``access mode''.
+ * NOTE: This limits the max parameter size to 16kB -1 !
+ */
+
+/*
+ * The following is for compatibility across the various Linux
+ * platforms.  The i386 ioctl numbering scheme doesn't really enforce
+ * a type field.  De facto, however, the top 8 bits of the lower 16
+ * bits are indeed used as a type field, so we might just as well make
+ * this explicit here.  Please be sure to use the decoding macros
+ * below from now on.
+ */
+#define _IOC_NRBITS	8
+#define _IOC_TYPEBITS	8
+#define _IOC_SIZEBITS	14
+#define _IOC_DIRBITS	2
+
+#define _IOC_NRMASK	((1 << _IOC_NRBITS)-1)
+#define _IOC_TYPEMASK	((1 << _IOC_TYPEBITS)-1)
+#define _IOC_SIZEMASK	((1 << _IOC_SIZEBITS)-1)
+#define _IOC_DIRMASK	((1 << _IOC_DIRBITS)-1)
+
+#define _IOC_NRSHIFT	0
+#define _IOC_TYPESHIFT	(_IOC_NRSHIFT+_IOC_NRBITS)
+#define _IOC_SIZESHIFT	(_IOC_TYPESHIFT+_IOC_TYPEBITS)
+#define _IOC_DIRSHIFT	(_IOC_SIZESHIFT+_IOC_SIZEBITS)
+
+/*
+ * Direction bits.
+ */
+#define _IOC_NONE	0U
+#define _IOC_WRITE	1U
+#define _IOC_READ	2U
+
+#define _IOC(dir,type,nr,size) \
+	(((dir)  << _IOC_DIRSHIFT) | \
+	 ((type) << _IOC_TYPESHIFT) | \
+	 ((nr)   << _IOC_NRSHIFT) | \
+	 ((size) << _IOC_SIZESHIFT))
+
+/* used to create numbers */
+#define _IO(type,nr)		_IOC(_IOC_NONE,(type),(nr),0)
+#define _IOR(type,nr,size)	_IOC(_IOC_READ,(type),(nr),sizeof(size))
+#define _IOW(type,nr,size)	_IOC(_IOC_WRITE,(type),(nr),sizeof(size))
+#define _IOWR(type,nr,size)	_IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
+
+/* used to decode ioctl numbers.. */
+#define _IOC_DIR(nr)		(((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+#define _IOC_TYPE(nr)		(((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
+#define _IOC_NR(nr)		(((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
+#define _IOC_SIZE(nr)		(((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
+
+/* ...and for the drivers/sound files... */
+
+#define IOC_IN		(_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT		(_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT	((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK	(_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT	(_IOC_SIZESHIFT)
+
+#endif /* _ASMX8664_IOCTL_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/ioctl32.h linux-2.4.20/include/asm-x86_64/ioctl32.h
--- linux-2.4.19/include/asm-x86_64/ioctl32.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/ioctl32.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,23 @@
+#ifndef IOCTL32_H
+#define IOCTL32_H 1
+
+struct file;
+
+int sys_ioctl(unsigned int, unsigned int, unsigned long);
+
+/* 
+ * Register an 32bit ioctl translation handler for ioctl cmd.
+ *
+ * handler == NULL: use 64bit ioctl handler.
+ * arguments to handler:  fd: file descriptor
+ *                        cmd: ioctl command.
+ *                        arg: ioctl argument
+ *                        struct file *file: file descriptor pointer.
+ */ 
+
+extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
+
+extern int unregister_ioctl32_conversion(unsigned int cmd);
+
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/ioctls.h linux-2.4.20/include/asm-x86_64/ioctls.h
--- linux-2.4.19/include/asm-x86_64/ioctls.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/ioctls.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,82 @@
+#ifndef __ARCH_X8664_IOCTLS_H__
+#define __ARCH_X8664_IOCTLS_H__
+
+#include <asm/ioctl.h>
+
+/* 0x54 is just a magic number to make these relatively unique ('T') */
+
+#define TCGETS		0x5401
+#define TCSETS		0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */
+#define TCSETSW		0x5403
+#define TCSETSF		0x5404
+#define TCGETA		0x5405
+#define TCSETA		0x5406
+#define TCSETAW		0x5407
+#define TCSETAF		0x5408
+#define TCSBRK		0x5409
+#define TCXONC		0x540A
+#define TCFLSH		0x540B
+#define TIOCEXCL	0x540C
+#define TIOCNXCL	0x540D
+#define TIOCSCTTY	0x540E
+#define TIOCGPGRP	0x540F
+#define TIOCSPGRP	0x5410
+#define TIOCOUTQ	0x5411
+#define TIOCSTI		0x5412
+#define TIOCGWINSZ	0x5413
+#define TIOCSWINSZ	0x5414
+#define TIOCMGET	0x5415
+#define TIOCMBIS	0x5416
+#define TIOCMBIC	0x5417
+#define TIOCMSET	0x5418
+#define TIOCGSOFTCAR	0x5419
+#define TIOCSSOFTCAR	0x541A
+#define FIONREAD	0x541B
+#define TIOCINQ		FIONREAD
+#define TIOCLINUX	0x541C
+#define TIOCCONS	0x541D
+#define TIOCGSERIAL	0x541E
+#define TIOCSSERIAL	0x541F
+#define TIOCPKT		0x5420
+#define FIONBIO		0x5421
+#define TIOCNOTTY	0x5422
+#define TIOCSETD	0x5423
+#define TIOCGETD	0x5424
+#define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TIOCTTYGSTRUCT	0x5426  /* For debugging only */
+#define TIOCSBRK	0x5427  /* BSD compatibility */
+#define TIOCCBRK	0x5428  /* BSD compatibility */
+#define TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
+#define FIOCLEX		0x5451
+#define FIOASYNC	0x5452
+#define TIOCSERCONFIG	0x5453
+#define TIOCSERGWILD	0x5454
+#define TIOCSERSWILD	0x5455
+#define TIOCGLCKTRMIOS	0x5456
+#define TIOCSLCKTRMIOS	0x5457
+#define TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+#define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
+#define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+
+/* Used for packet mode */
+#define TIOCPKT_DATA		 0
+#define TIOCPKT_FLUSHREAD	 1
+#define TIOCPKT_FLUSHWRITE	 2
+#define TIOCPKT_STOP		 4
+#define TIOCPKT_START		 8
+#define TIOCPKT_NOSTOP		16
+#define TIOCPKT_DOSTOP		32
+
+#define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/ipc.h linux-2.4.20/include/asm-x86_64/ipc.h
--- linux-2.4.19/include/asm-x86_64/ipc.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/ipc.h	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,7 @@
+#ifndef __x86_64_IPC_H__
+#define __x86_64_IPC_H__
+
+/* dummy */
+
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/ipcbuf.h linux-2.4.20/include/asm-x86_64/ipcbuf.h
--- linux-2.4.19/include/asm-x86_64/ipcbuf.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/ipcbuf.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,29 @@
+#ifndef __x86_64_IPCBUF_H__
+#define __x86_64_IPCBUF_H__
+
+/*
+ * The ipc64_perm structure for x86-64 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 32-bit mode_t and seq
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct ipc64_perm
+{
+	__kernel_key_t		key;
+	__kernel_uid32_t	uid;
+	__kernel_gid32_t	gid;
+	__kernel_uid32_t	cuid;
+	__kernel_gid32_t	cgid;
+	__kernel_mode_t		mode;
+	unsigned short		__pad1;
+	unsigned short		seq;
+	unsigned short		__pad2;
+	unsigned long		__unused1;
+	unsigned long		__unused2;
+};
+
+#endif /* __x86_64_IPCBUF_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/irq.h linux-2.4.20/include/asm-x86_64/irq.h
--- linux-2.4.19/include/asm-x86_64/irq.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/irq.h	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,39 @@
+#ifndef _ASM_IRQ_H
+#define _ASM_IRQ_H
+
+/*
+ *	linux/include/asm/irq.h
+ *
+ *	(C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
+ *
+ *	IRQ/IPI changes taken from work by Thomas Radke
+ *	<tomsoft@informatik.tu-chemnitz.de>
+ */
+
+#define TIMER_IRQ 0
+
+/*
+ * 16 8259A IRQ's, 208 potential APIC interrupt sources.
+ * Right now the APIC is mostly only used for SMP.
+ * 256 vectors is an architectural limit. (we can have
+ * more than 256 devices theoretically, but they will
+ * have to use shared interrupts)
+ * Since vectors 0x00-0x1f are used/reserved for the CPU,
+ * the usable vector space is 0x20-0xff (224 vectors)
+ */
+#ifdef CONFIG_X86_IO_APIC
+#define NR_IRQS 224
+#else
+#define NR_IRQS 16
+#endif
+
+static __inline__ int irq_cannonicalize(int irq)
+{
+	return ((irq == 2) ? 9 : irq);
+}
+
+extern void disable_irq(unsigned int);
+extern void disable_irq_nosync(unsigned int);
+extern void enable_irq(unsigned int);
+
+#endif /* _ASM_IRQ_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/kdebug.h linux-2.4.20/include/asm-x86_64/kdebug.h
--- linux-2.4.19/include/asm-x86_64/kdebug.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/kdebug.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,42 @@
+#ifndef _X86_64_KDEBUG_H
+#define _X86_64_KDEBUG_H 1
+
+#include <linux/notifier.h>
+
+struct pt_regs;
+
+struct die_args { 
+	struct pt_regs *regs;
+	const char *str;
+	long err; 
+}; 
+
+extern struct notifier_block *die_chain;
+
+/* Grossly misnamed. */
+enum die_val { 
+	DIE_OOPS = 1,
+	DIE_INT3,
+	DIE_DEBUG,
+	DIE_PANIC,
+	DIE_NMI,
+	DIE_DIE,
+	DIE_CALL,
+	DIE_CPUINIT,	/* not really a die, but .. */
+	DIE_TRAPINIT,	/* not really a die, but .. */
+	DIE_STOP, 
+}; 
+
+static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err)
+{ 
+	struct die_args args = { regs: regs, str: str, err: err }; 
+	return notifier_call_chain(&die_chain, val, &args); 
+} 
+
+extern int printk_address(unsigned long address);
+extern void die(const char *,struct pt_regs *,long);
+extern void show_stack(unsigned long* esp);
+extern void show_registers(struct pt_regs *regs);
+extern void dump_pagetable(unsigned long);
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/keyboard.h linux-2.4.20/include/asm-x86_64/keyboard.h
--- linux-2.4.19/include/asm-x86_64/keyboard.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/keyboard.h	2002-10-29 11:18:38.000000000 +0000
@@ -0,0 +1,71 @@
+/*
+ *  linux/include/asm-x8664/keyboard.h
+ *
+ *  Created 3 Nov 1996 by Geert Uytterhoeven
+ */
+
+/*
+ *  This file contains the x8664 architecture specific keyboard definitions
+ */
+
+#ifndef _X8664_KEYBOARD_H
+#define _X8664_KEYBOARD_H
+
+#ifdef __KERNEL__
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/kd.h>
+#include <linux/pm.h>
+#include <asm/io.h>
+
+#define KEYBOARD_IRQ			1
+#define DISABLE_KBD_DURING_INTERRUPTS	0
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern int pckbd_pm_resume(struct pm_dev *dev, pm_request_t rqst, void *data);
+extern unsigned char pckbd_sysrq_xlate[128];
+
+#define kbd_setkeycode		pckbd_setkeycode
+#define kbd_getkeycode		pckbd_getkeycode
+#define kbd_translate		pckbd_translate
+#define kbd_unexpected_up	pckbd_unexpected_up
+#define kbd_leds		pckbd_leds
+#define kbd_init_hw		pckbd_init_hw
+#define kbd_sysrq_xlate		pckbd_sysrq_xlate
+
+#define SYSRQ_KEY 0x54
+
+/* resource allocation */
+#define kbd_request_region()
+#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
+                                             "keyboard", NULL)
+
+/* How to access the keyboard macros on this platform.  */
+#define kbd_read_input() inb(KBD_DATA_REG)
+#define kbd_read_status() inb(KBD_STATUS_REG)
+#define kbd_write_output(val) outb(val, KBD_DATA_REG)
+#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
+
+/* Some stoneage hardware needs delays after some operations.  */
+#define kbd_pause() do { } while(0)
+
+/*
+ * Machine specific bits for the PS/2 driver
+ */
+
+#define AUX_IRQ 12
+
+#define aux_request_irq(hand, dev_id)					\
+	request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
+
+#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
+
+#endif /* __KERNEL__ */
+#endif /* _X8664_KEYBOARD_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/kmap_types.h linux-2.4.20/include/asm-x86_64/kmap_types.h
--- linux-2.4.19/include/asm-x86_64/kmap_types.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/kmap_types.h	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,14 @@
+#ifndef _ASM_KMAP_TYPES_H
+#define _ASM_KMAP_TYPES_H
+
+enum km_type {
+	KM_BOUNCE_READ,
+	KM_SKB_SUNRPC_DATA,
+	KM_SKB_DATA_SOFTIRQ,
+	KM_USER0,
+	KM_USER1,
+	KM_BH_IRQ,
+	KM_TYPE_NR
+};
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/ldt.h linux-2.4.20/include/asm-x86_64/ldt.h
--- linux-2.4.19/include/asm-x86_64/ldt.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/ldt.h	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,36 @@
+/*
+ * ldt.h
+ *
+ * Definitions of structures used with the modify_ldt system call.
+ */
+#ifndef _LINUX_LDT_H
+#define _LINUX_LDT_H
+
+/* Maximum number of LDT entries supported. */
+#define LDT_ENTRIES	8192
+/* The size of each LDT entry. */
+#define LDT_ENTRY_SIZE	8
+
+#ifndef __ASSEMBLY__
+/* Note on 64bit base and limit is ignored and you cannot set
+   DS/ES/CS not to the default values if you still want to do syscalls. This
+   call is more for 32bit mode therefore. */
+struct modify_ldt_ldt_s {
+	unsigned int  entry_number;
+	unsigned int  base_addr;
+	unsigned int  limit;
+	unsigned int  seg_32bit:1;
+	unsigned int  contents:2;
+	unsigned int  read_exec_only:1;
+	unsigned int  limit_in_pages:1;
+	unsigned int  seg_not_present:1;
+	unsigned int  useable:1;
+	unsigned int  lm:1;
+};
+
+#define MODIFY_LDT_CONTENTS_DATA	0
+#define MODIFY_LDT_CONTENTS_STACK	1
+#define MODIFY_LDT_CONTENTS_CODE	2
+
+#endif /* !__ASSEMBLY__ */
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/linux_logo.h linux-2.4.20/include/asm-x86_64/linux_logo.h
--- linux-2.4.19/include/asm-x86_64/linux_logo.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/linux_logo.h	2002-10-29 11:18:47.000000000 +0000
@@ -0,0 +1,29 @@
+/* $Id: linux_logo.h,v 1.4 2001/07/05 23:44:45 ak Exp $
+ * include/asm-x86_64/linux_logo.h: This is a linux logo
+ *                                to be displayed on boot.
+ *
+ * Copyright (C) 1996 Larry Ewing (lewing@isc.tamu.edu)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * You can put anything here, but:
+ * LINUX_LOGO_COLORS has to be less than 224
+ * image size has to be 80x80
+ * values have to start from 0x20
+ * (i.e. RGB(linux_logo_red[0],
+ *	     linux_logo_green[0],
+ *	     linux_logo_blue[0]) is color 0x20)
+ * BW image has to be 80x80 as well, with MS bit
+ * on the left
+ * Serial_console ascii image can be any size,
+ * but should contain %s to display the version
+ */
+ 
+#include <linux/init.h>
+#include <linux/version.h>
+
+/* We should create logo of penguin with a big hammer (-: --pavel */
+
+#define linux_logo_banner "Linux/x86-64 version " UTS_RELEASE
+
+#include <linux/linux_logo.h>
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/locks.h linux-2.4.20/include/asm-x86_64/locks.h
--- linux-2.4.19/include/asm-x86_64/locks.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/locks.h	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,135 @@
+/*
+ *	SMP locks primitives for building ix86 locks
+ *	(not yet used).
+ *
+ *		Alan Cox, alan@redhat.com, 1995
+ */
+ 
+/*
+ *	This would be much easier but far less clear and easy
+ *	to borrow for other processors if it was just assembler.
+ */
+
+extern __inline__ void prim_spin_lock(struct spinlock *sp)
+{
+	int processor=smp_processor_id();
+	
+	/*
+	 *	Grab the lock bit
+	 */
+	 
+	while(lock_set_bit(0,&sp->lock))
+	{
+		/*
+		 *	Failed, but that's cos we own it!
+		 */
+		 
+		if(sp->cpu==processor)
+		{
+			sp->users++;
+			return 0;
+		}
+		/*
+		 *	Spin in the cache S state if possible
+		 */
+		while(sp->lock)
+		{
+			/*
+			 *	Wait for any invalidates to go off
+			 */
+			 
+			if(smp_invalidate_needed&(1<<processor))
+				while(lock_clear_bit(processor,&smp_invalidate_needed))
+					local_flush_tlb();
+			sp->spins++;
+		}
+		/*
+		 *	Someone wrote the line, we go 'I' and get
+		 *	the cache entry. Now try to regrab
+		 */
+	}
+	sp->users++;sp->cpu=processor;
+	return 1;
+}
+
+/*
+ *	Release a spin lock
+ */
+ 
+extern __inline__ int prim_spin_unlock(struct spinlock *sp)
+{
+	/* This is safe. The decrement is still guarded by the lock. A multilock would
+	   not be safe this way */
+	if(!--sp->users)
+	{
+		sp->cpu= NO_PROC_ID;lock_clear_bit(0,&sp->lock);
+		return 1;
+	}
+	return 0;
+}
+
+
+/*
+ *	Non blocking lock grab
+ */
+ 
+extern __inline__ int prim_spin_lock_nb(struct spinlock *sp)
+{
+	if(lock_set_bit(0,&sp->lock))
+		return 0;		/* Locked already */
+	sp->users++;
+	return 1;			/* We got the lock */
+}
+
+
+/*
+ *	These wrap the locking primitives up for usage
+ */
+ 
+extern __inline__ void spinlock(struct spinlock *sp)
+{
+	if(sp->priority<current->lock_order)
+		panic("lock order violation: %s (%d)\n", sp->name, current->lock_order);
+	if(prim_spin_lock(sp))
+	{
+		/*
+		 *	We got a new lock. Update the priority chain
+		 */
+		sp->oldpri=current->lock_order;
+		current->lock_order=sp->priority;
+	}
+}
+
+extern __inline__ void spinunlock(struct spinlock *sp)
+{
+	int pri;
+	if(current->lock_order!=sp->priority)
+		panic("lock release order violation %s (%d)\n", sp->name, current->lock_order);
+	pri=sp->oldpri;
+	if(prim_spin_unlock(sp))
+	{
+		/*
+		 *	Update the debugging lock priority chain. We dumped
+		 *	our last right to the lock.
+		 */
+		current->lock_order=sp->pri;
+	}	
+}
+
+extern __inline__ void spintestlock(struct spinlock *sp)
+{
+	/*
+	 *	We do no sanity checks, it's legal to optimistically
+	 *	get a lower lock.
+	 */
+	prim_spin_lock_nb(sp);
+}
+
+extern __inline__ void spintestunlock(struct spinlock *sp)
+{
+	/*
+	 *	A testlock doesn't update the lock chain so we
+	 *	must not update it on free
+	 */
+	prim_spin_unlock(sp);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/mc146818rtc.h linux-2.4.20/include/asm-x86_64/mc146818rtc.h
--- linux-2.4.19/include/asm-x86_64/mc146818rtc.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/mc146818rtc.h	2002-10-29 11:18:30.000000000 +0000
@@ -0,0 +1,34 @@
+/*
+ * Machine dependent access functions for RTC registers.
+ */
+#ifndef _ASM_MC146818RTC_H
+#define _ASM_MC146818RTC_H
+
+#include <asm/io.h>
+
+#ifndef RTC_PORT
+#define RTC_PORT(x)	(0x70 + (x))
+#define RTC_ALWAYS_BCD	1	/* RTC operates in binary mode */
+#endif
+
+/*
+ * The yet supported machines all access the RTC index register via
+ * an ISA port access but the way to access the date register differs ...
+ */
+#define CMOS_READ(addr) ({ \
+outb_p((addr),RTC_PORT(0)); \
+inb_p(RTC_PORT(1)); \
+})
+#define CMOS_WRITE(val, addr) ({ \
+outb_p((addr),RTC_PORT(0)); \
+outb_p((val),RTC_PORT(1)); \
+})
+
+#ifndef CONFIG_HPET_TIMER
+#define RTC_IRQ 8
+#else
+/* Temporary workaround due to IRQ routing problem. */
+#define RTC_IRQ 0
+#endif
+
+#endif /* _ASM_MC146818RTC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/mman.h linux-2.4.20/include/asm-x86_64/mman.h
--- linux-2.4.19/include/asm-x86_64/mman.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/mman.h	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,39 @@
+#ifndef __X8664_MMAN_H__
+#define __X8664_MMAN_H__
+
+#define PROT_READ	0x1		/* page can be read */
+#define PROT_WRITE	0x2		/* page can be written */
+#define PROT_EXEC	0x4		/* page can be executed */
+#define PROT_NONE	0x0		/* page can not be accessed */
+
+#define MAP_SHARED	0x01		/* Share changes */
+#define MAP_PRIVATE	0x02		/* Changes are private */
+#define MAP_TYPE	0x0f		/* Mask for type of mapping */
+#define MAP_FIXED	0x10		/* Interpret addr exactly */
+#define MAP_ANONYMOUS	0x20		/* don't use a file */
+#define MAP_32BIT	0x40		/* only give out 32bit addresses */
+
+#define MAP_GROWSDOWN	0x0100		/* stack-like segment */
+#define MAP_DENYWRITE	0x0800		/* ETXTBSY */
+#define MAP_EXECUTABLE	0x1000		/* mark it as an executable */
+#define MAP_LOCKED	0x2000		/* pages are locked */
+#define MAP_NORESERVE	0x4000		/* don't check for reservations */
+
+#define MS_ASYNC	1		/* sync memory asynchronously */
+#define MS_INVALIDATE	2		/* invalidate the caches */
+#define MS_SYNC		4		/* synchronous memory sync */
+
+#define MCL_CURRENT	1		/* lock all current mappings */
+#define MCL_FUTURE	2		/* lock all future mappings */
+
+#define MADV_NORMAL	0x0		/* default page-in behavior */
+#define MADV_RANDOM	0x1		/* page-in minimum required */
+#define MADV_SEQUENTIAL	0x2		/* read-ahead aggressively */
+#define MADV_WILLNEED	0x3		/* pre-fault pages */
+#define MADV_DONTNEED	0x4		/* discard these pages */
+
+/* compatibility flags */
+#define MAP_ANON	MAP_ANONYMOUS
+#define MAP_FILE	0
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/mmu.h linux-2.4.20/include/asm-x86_64/mmu.h
--- linux-2.4.19/include/asm-x86_64/mmu.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/mmu.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,16 @@
+#ifndef __x86_64_MMU_H
+#define __x86_64_MMU_H
+
+#include <linux/spinlock.h>
+
+/*
+ * The x86_64 doesn't have a mmu context, but
+ * we put the segment information here.
+ */
+typedef struct { 
+	void *segments;
+	unsigned long cpuvalid;
+	rwlock_t ldtlock;
+} mm_context_t;
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/mmu_context.h linux-2.4.20/include/asm-x86_64/mmu_context.h
--- linux-2.4.19/include/asm-x86_64/mmu_context.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/mmu_context.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,73 @@
+#ifndef __X86_64_MMU_CONTEXT_H
+#define __X86_64_MMU_CONTEXT_H
+
+#include <linux/config.h>
+#include <asm/desc.h>
+#include <asm/atomic.h>
+#include <asm/pgalloc.h>
+#include <asm/pda.h>
+#include <asm/pgtable.h>
+#include <linux/spinlock.h>
+
+/*
+ * possibly do the LDT unload here?
+ */
+#define destroy_context(mm)	    do { } while(0)
+#define init_new_context(tsk,mm)    ({ rwlock_init(&(mm)->context.ldtlock); 0; })
+
+#ifdef CONFIG_SMP
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
+{
+	if(cpu_tlbstate[cpu].state == TLBSTATE_OK)
+		cpu_tlbstate[cpu].state = TLBSTATE_LAZY;	
+}
+#else
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
+{
+}
+#endif
+
+#define activate_mm(prev, next) \
+	switch_mm((prev),(next),NULL,smp_processor_id())
+
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
+			     struct task_struct *tsk, unsigned cpu)
+{
+	if (prev != next) {
+		/* stop flush ipis for the previous mm */
+		clear_bit(cpu, &prev->cpu_vm_mask);
+		/*
+		 * Re-load LDT if necessary
+		 */
+		if (prev->context.segments != next->context.segments)
+			load_LDT(next);
+#ifdef CONFIG_SMP
+		cpu_tlbstate[cpu].state = TLBSTATE_OK;
+		cpu_tlbstate[cpu].active_mm = next;
+#endif
+		set_bit(cpu, &next->cpu_vm_mask);
+		set_bit(cpu, &next->context.cpuvalid);
+		/* Re-load page tables */
+		*read_pda(level4_pgt) = __pa(next->pgd) | _PAGE_TABLE;
+		__flush_tlb();
+	}
+#ifdef CONFIG_SMP
+	else {
+		cpu_tlbstate[cpu].state = TLBSTATE_OK;
+		if(cpu_tlbstate[cpu].active_mm != next)
+			out_of_line_bug();
+		if(!test_and_set_bit(cpu, &next->cpu_vm_mask)) {
+			/* We were in lazy tlb mode and leave_mm disabled 
+			 * tlb flush IPI delivery. We must flush our tlb.
+			 */
+			local_flush_tlb();
+		}
+		if (!test_and_set_bit(cpu, &next->context.cpuvalid))
+			load_LDT(next);
+	}
+#endif
+}
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/mmx.h linux-2.4.20/include/asm-x86_64/mmx.h
--- linux-2.4.19/include/asm-x86_64/mmx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/mmx.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,14 @@
+#ifndef _ASM_MMX_H
+#define _ASM_MMX_H
+
+/*
+ *	MMX 3Dnow! helper operations
+ */
+
+#include <linux/types.h>
+ 
+extern void *_mmx_memcpy(void *to, const void *from, size_t size);
+extern void mmx_clear_page(void *page);
+extern void mmx_copy_page(void *to, void *from);
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/mmzone.h linux-2.4.20/include/asm-x86_64/mmzone.h
--- linux-2.4.19/include/asm-x86_64/mmzone.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/mmzone.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,170 @@
+/*
+ * Written by Kanoj Sarcar (kanoj@sgi.com) Aug 99
+ * Adapted for K8/x86-64 Jul 2002 by Andi Kleen.
+ */
+#ifndef _ASM_MMZONE_H_
+#define _ASM_MMZONE_H_
+
+#include <linux/config.h>
+
+typedef struct plat_pglist_data {
+	pg_data_t	gendata;
+	unsigned long   start_pfn, end_pfn;
+} plat_pg_data_t;
+
+struct bootmem_data_t;
+
+/*
+ * Following are macros that are specific to this numa platform.
+ * 
+ * XXX check what the compiler generates for all this
+ */
+
+extern plat_pg_data_t *plat_node_data[];
+
+#define MAXNODE 8 
+#define MAX_NUMNODES MAXNODE
+#define NODEMAPSIZE 0xff
+
+/* Simple perfect hash to map physical addresses to node numbers */
+extern int memnode_shift; 
+extern u8  memnodemap[NODEMAPSIZE]; 
+extern int maxnode;
+
+#if 0
+#define VIRTUAL_BUG_ON(x) do { if (x) out_of_line_bug(); } while(0)
+#else
+#define VIRTUAL_BUG_ON(x) do {} while (0) 
+#endif
+
+/* VALID_PAGE below hardcodes the same algorithm*/
+static inline int phys_to_nid(unsigned long addr) 
+{ 
+	int nid; 
+	VIRTUAL_BUG_ON((addr >> memnode_shift) >= NODEMAPSIZE);
+	nid = memnodemap[addr >> memnode_shift]; 
+	VIRTUAL_BUG_ON(nid > maxnode); 
+	return nid; 
+} 
+
+#define PLAT_NODE_DATA(n)		(plat_node_data[(n)])
+#define PLAT_NODE_DATA_STARTNR(n)	\
+	(PLAT_NODE_DATA(n)->gendata.node_start_mapnr)
+#define PLAT_NODE_DATA_SIZE(n)		(PLAT_NODE_DATA(n)->gendata.node_size)
+
+#define PLAT_NODE_DATA_LOCALNR(p, n)	\
+	(((p) - PLAT_NODE_DATA(n)->gendata.node_start_paddr) >> PAGE_SHIFT)
+
+#ifdef CONFIG_DISCONTIGMEM
+
+/*
+ * Following are macros that each numa implmentation must define.
+ */
+
+/*
+ * Given a kernel address, find the home node of the underlying memory.
+ */
+#define KVADDR_TO_NID(kaddr)	phys_to_nid(__pa(kaddr))
+
+/*
+ * Return a pointer to the node data for node n.
+ */
+#define NODE_DATA(n)	(&((PLAT_NODE_DATA(n))->gendata))
+
+/*
+ * NODE_MEM_MAP gives the kaddr for the mem_map of the node.
+ */
+#define NODE_MEM_MAP(nid)	(NODE_DATA(nid)->node_mem_map)
+
+/*
+ * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory
+ * and returns the the mem_map of that node.
+ */
+#define ADDR_TO_MAPBASE(kaddr) \
+			NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(kaddr)))
+
+/*
+ * Given a kaddr, LOCAL_BASE_ADDR finds the owning node of the memory
+ * and returns the kaddr corresponding to first physical page in the
+ * node's mem_map.
+ */
+#define LOCAL_BASE_ADDR(kaddr)	((unsigned long)__va(NODE_DATA(KVADDR_TO_NID(kaddr))->node_start_paddr))
+
+#define LOCAL_MAP_NR(kvaddr) \
+	(((unsigned long)(kvaddr)-LOCAL_BASE_ADDR(kvaddr)) >> PAGE_SHIFT)
+
+#define BAD_PAGE 0xffffffffffff
+
+/* this really should be optimized a bit */
+static inline unsigned long 
+paddr_to_local_pfn(unsigned long phys_addr, struct page **mem_map, int check) 
+{ 
+	unsigned long nid;
+	if (check) { /* we rely on gcc optimizing this way for most cases */ 
+		unsigned long index = phys_addr >> memnode_shift; 
+		if (index >= NODEMAPSIZE || memnodemap[index] == 0xff) { 
+			*mem_map = NULL;
+			return BAD_PAGE;
+		} 
+		nid = memnodemap[index];
+	} else { 
+		nid = phys_to_nid(phys_addr); 
+	} 			   
+	plat_pg_data_t *plat_pgdat = plat_node_data[nid]; 
+	unsigned long pfn = phys_addr >> PAGE_SHIFT; 
+	VIRTUAL_BUG_ON(pfn >= plat_pgdat->end_pfn);
+	VIRTUAL_BUG_ON(pfn < plat_pgdat->start_pfn);
+	*mem_map = plat_pgdat->gendata.node_mem_map; 
+	return pfn - plat_pgdat->start_pfn;
+} 
+#define virt_to_page(kaddr) \
+	({ struct page *lmemmap; \
+	   unsigned long lpfn = paddr_to_local_pfn(__pa(kaddr),&lmemmap,0); \
+	   lmemmap + lpfn;  })
+
+/* needs to handle bad addresses too */
+#define pte_page(pte) \
+	({ struct page *lmemmap; \
+	   unsigned long addr = pte_val(pte) & PHYSICAL_PAGE_MASK; \
+	   unsigned long lpfn = paddr_to_local_pfn(addr,&lmemmap,1); \
+	   lmemmap + lpfn;  })
+
+#define pfn_to_page(pfn)	virt_to_page(__va((unsigned long)(pfn) << PAGE_SHIFT))
+#define page_to_pfn(page)	({ \
+	int nodeid = phys_to_nid(__pa(page));  \
+	plat_pg_data_t *nd = PLAT_NODE_DATA(nodeid); \
+	(page - nd->gendata.node_mem_map) + nd->start_pfn; \
+})
+
+#define VALID_PAGE(page_ptr) ({ \
+	int ok = 0; 						\
+	unsigned long phys = __pa(page_ptr); 			\
+        unsigned long index = phys >> memnode_shift; 		\
+	if (index <= NODEMAPSIZE) { 					  \
+		unsigned nodeid = memnodemap[index]; 			  \
+		pg_data_t *nd = NODE_DATA(nodeid); 			  \
+		struct page *lmemmap = nd->node_mem_map;		  \
+		ok = (nodeid != 0xff) && \
+		     (page_ptr >= lmemmap && page_ptr < lmemmap + nd->node_size); \
+	} 			\
+	ok; 			\
+})
+
+#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
+
+
+
+extern void setup_node_bootmem(int nodeid, unsigned long start_, unsigned long end_);
+
+
+#ifdef CONFIG_NUMA
+extern int fake_node;
+#define cputonode(cpu) (fake_node ? 0 : (cpu))
+#define numa_node_id()	cputonode(smp_processor_id())
+#endif /* CONFIG_NUMA */
+
+#define MAX_NR_NODES 8
+
+#endif /* CONFIG_DISCONTIGMEM */
+
+#endif /* _ASM_MMZONE_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/module.h linux-2.4.20/include/asm-x86_64/module.h
--- linux-2.4.19/include/asm-x86_64/module.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/module.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,15 @@
+#ifndef _ASM_X8664_MODULE_H
+#define _ASM_X8664_MODULE_H
+
+/*
+ * This file contains the x8664 architecture specific module code.
+ * Modules need to be mapped near the kernel code to allow 32bit relocations.
+ */
+
+extern void *module_map(unsigned long);
+extern void module_unmap(void *);
+
+#define module_arch_init(x)	(0)
+#define arch_init_modules(x)	do { } while (0)
+
+#endif 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/mpspec.h linux-2.4.20/include/asm-x86_64/mpspec.h
--- linux-2.4.19/include/asm-x86_64/mpspec.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/mpspec.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,191 @@
+#ifndef __ASM_MPSPEC_H
+#define __ASM_MPSPEC_H
+
+/*
+ * Structure definitions for SMP machines following the
+ * Intel Multiprocessing Specification 1.1 and 1.4.
+ */
+
+/*
+ * This tag identifies where the SMP configuration
+ * information is. 
+ */
+ 
+#define SMP_MAGIC_IDENT	(('_'<<24)|('P'<<16)|('M'<<8)|'_')
+
+/*
+ * a maximum of 16 APICs with the current APIC ID architecture.
+ */
+#define MAX_APICS 16
+
+struct intel_mp_floating
+{
+	char mpf_signature[4];		/* "_MP_" 			*/
+	unsigned int mpf_physptr;	/* Configuration table address	*/
+	unsigned char mpf_length;	/* Our length (paragraphs)	*/
+	unsigned char mpf_specification;/* Specification version	*/
+	unsigned char mpf_checksum;	/* Checksum (makes sum 0)	*/
+	unsigned char mpf_feature1;	/* Standard or configuration ? 	*/
+	unsigned char mpf_feature2;	/* Bit7 set for IMCR|PIC	*/
+	unsigned char mpf_feature3;	/* Unused (0)			*/
+	unsigned char mpf_feature4;	/* Unused (0)			*/
+	unsigned char mpf_feature5;	/* Unused (0)			*/
+};
+
+struct mp_config_table
+{
+	char mpc_signature[4];
+#define MPC_SIGNATURE "PCMP"
+	unsigned short mpc_length;	/* Size of table */
+	char  mpc_spec;			/* 0x01 */
+	char  mpc_checksum;
+	char  mpc_oem[8];
+	char  mpc_productid[12];
+	unsigned int mpc_oemptr;	/* 0 if not present */
+	unsigned short mpc_oemsize;	/* 0 if not present */
+	unsigned short mpc_oemcount;
+	unsigned int mpc_lapic;	/* APIC address */
+	unsigned int reserved;
+};
+
+/* Followed by entries */
+
+#define	MP_PROCESSOR	0
+#define	MP_BUS		1
+#define	MP_IOAPIC	2
+#define	MP_INTSRC	3
+#define	MP_LINTSRC	4
+
+struct mpc_config_processor
+{
+	unsigned char mpc_type;
+	unsigned char mpc_apicid;	/* Local APIC number */
+	unsigned char mpc_apicver;	/* Its versions */
+	unsigned char mpc_cpuflag;
+#define CPU_ENABLED		1	/* Processor is available */
+#define CPU_BOOTPROCESSOR	2	/* Processor is the BP */
+	unsigned int mpc_cpufeature;		
+#define CPU_STEPPING_MASK 0x0F
+#define CPU_MODEL_MASK	0xF0
+#define CPU_FAMILY_MASK	0xF00
+	unsigned int mpc_featureflag;	/* CPUID feature value */
+	unsigned int mpc_reserved[2];
+};
+
+struct mpc_config_bus
+{
+	unsigned char mpc_type;
+	unsigned char mpc_busid;
+	unsigned char mpc_bustype[6] __attribute((packed));
+};
+
+/* List of Bus Type string values, Intel MP Spec. */
+#define BUSTYPE_EISA	"EISA"
+#define BUSTYPE_ISA	"ISA"
+#define BUSTYPE_INTERN	"INTERN"	/* Internal BUS */
+#define BUSTYPE_MCA	"MCA"
+#define BUSTYPE_VL	"VL"		/* Local bus */
+#define BUSTYPE_PCI	"PCI"
+#define BUSTYPE_PCMCIA	"PCMCIA"
+#define BUSTYPE_CBUS	"CBUS"
+#define BUSTYPE_CBUSII	"CBUSII"
+#define BUSTYPE_FUTURE	"FUTURE"
+#define BUSTYPE_MBI	"MBI"
+#define BUSTYPE_MBII	"MBII"
+#define BUSTYPE_MPI	"MPI"
+#define BUSTYPE_MPSA	"MPSA"
+#define BUSTYPE_NUBUS	"NUBUS"
+#define BUSTYPE_TC	"TC"
+#define BUSTYPE_VME	"VME"
+#define BUSTYPE_XPRESS	"XPRESS"
+
+struct mpc_config_ioapic
+{
+	unsigned char mpc_type;
+	unsigned char mpc_apicid;
+	unsigned char mpc_apicver;
+	unsigned char mpc_flags;
+#define MPC_APIC_USABLE		0x01
+	unsigned int mpc_apicaddr;
+};
+
+struct mpc_config_intsrc
+{
+	unsigned char mpc_type;
+	unsigned char mpc_irqtype;
+	unsigned short mpc_irqflag;
+	unsigned char mpc_srcbus;
+	unsigned char mpc_srcbusirq;
+	unsigned char mpc_dstapic;
+	unsigned char mpc_dstirq;
+};
+
+enum mp_irq_source_types {
+	mp_INT = 0,
+	mp_NMI = 1,
+	mp_SMI = 2,
+	mp_ExtINT = 3
+};
+
+#define MP_IRQDIR_DEFAULT	0
+#define MP_IRQDIR_HIGH		1
+#define MP_IRQDIR_LOW		3
+
+
+struct mpc_config_lintsrc
+{
+	unsigned char mpc_type;
+	unsigned char mpc_irqtype;
+	unsigned short mpc_irqflag;
+	unsigned char mpc_srcbusid;
+	unsigned char mpc_srcbusirq;
+	unsigned char mpc_destapic;	
+#define MP_APIC_ALL	0xFF
+	unsigned char mpc_destapiclint;
+};
+
+/*
+ *	Default configurations
+ *
+ *	1	2 CPU ISA 82489DX
+ *	2	2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining
+ *	3	2 CPU EISA 82489DX
+ *	4	2 CPU MCA 82489DX
+ *	5	2 CPU ISA+PCI
+ *	6	2 CPU EISA+PCI
+ *	7	2 CPU MCA+PCI
+ */
+
+#define MAX_MP_BUSSES 257
+#define MAX_IRQ_SOURCES (MAX_MP_BUSSES*4)
+enum mp_bustype {
+	MP_BUS_ISA = 1,
+	MP_BUS_EISA,
+	MP_BUS_PCI,
+	MP_BUS_MCA
+};
+extern int mp_bus_id_to_type [MAX_MP_BUSSES];
+extern int mp_bus_id_to_node [MAX_MP_BUSSES];
+extern int mp_bus_id_to_local [MAX_MP_BUSSES];
+extern int quad_local_to_mp_bus_id [NR_CPUS/4][4];
+extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
+
+extern unsigned int boot_cpu_physical_apicid;
+extern unsigned long phys_cpu_present_map;
+extern int smp_found_config;
+extern void find_smp_config (void);
+extern void get_smp_config (void);
+extern int nr_ioapics;
+extern int apic_version [MAX_APICS];
+extern int mp_bus_id_to_type [MAX_MP_BUSSES];
+extern int mp_irq_entries;
+extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
+extern int mpc_default_type;
+extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
+extern int mp_current_pci_id;
+extern unsigned long mp_lapic_addr;
+extern int pic_mode;
+extern int using_apic_timer;
+
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/msgbuf.h linux-2.4.20/include/asm-x86_64/msgbuf.h
--- linux-2.4.19/include/asm-x86_64/msgbuf.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/msgbuf.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,27 @@
+#ifndef _X8664_MSGBUF_H
+#define _X8664_MSGBUF_H
+
+/* 
+ * The msqid64_ds structure for x86-64 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 64-bit values
+ */
+
+struct msqid64_ds {
+	struct ipc64_perm msg_perm;
+	__kernel_time_t msg_stime;	/* last msgsnd time */
+	__kernel_time_t msg_rtime;	/* last msgrcv time */
+	__kernel_time_t msg_ctime;	/* last change time */
+	unsigned long  msg_cbytes;	/* current number of bytes on queue */
+	unsigned long  msg_qnum;	/* number of messages in queue */
+	unsigned long  msg_qbytes;	/* max number of bytes on queue */
+	__kernel_pid_t msg_lspid;	/* pid of last msgsnd */
+	__kernel_pid_t msg_lrpid;	/* last receive pid */
+	unsigned long  __unused4;
+	unsigned long  __unused5;
+};
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/msr.h linux-2.4.20/include/asm-x86_64/msr.h
--- linux-2.4.19/include/asm-x86_64/msr.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/msr.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,188 @@
+#ifndef X86_64_MSR_H
+#define X86_64_MSR_H 1
+
+#ifndef __ASSEMBLY__
+/*
+ * Access to machine-specific registers (available on 586 and better only)
+ * Note: the rd* operations modify the parameters directly (without using
+ * pointer indirection), this allows gcc to optimize better
+ */
+
+#define rdmsr(msr,val1,val2) \
+       __asm__ __volatile__("rdmsr" \
+			    : "=a" (val1), "=d" (val2) \
+			    : "c" (msr))
+
+
+#define rdmsrl(msr,val) do { unsigned long a__,b__; \
+       __asm__ __volatile__("rdmsr" \
+			    : "=a" (a__), "=d" (b__) \
+			    : "c" (msr)); \
+       val = a__ | (b__<<32); \
+} while(0); 
+
+#define wrmsr(msr,val1,val2) \
+     __asm__ __volatile__("wrmsr" \
+			  : /* no outputs */ \
+			  : "c" (msr), "a" (val1), "d" (val2))
+
+#define wrmsrl(msr,val) wrmsr(msr,(__u32)((__u64)(val)),((__u64)(val))>>32) 
+
+/* wrmsrl with exception handling */
+#define checking_wrmsrl(msr,val) ({ int ret__;					\
+	asm volatile("2: wrmsr ; xorl %0,%0\n"					\
+		     "1:\n\t"							\
+		     ".section .fixup,\"ax\"\n\t"				\
+		     "3:  movl %4,%0 ; jmp 1b\n\t"				\
+		     ".previous\n\t"						\
+ 		     ".section __ex_table,\"a\"\n"				\
+		     "   .align 8\n\t"						\
+		     "   .quad 	2b,3b\n\t"					\
+		     ".previous"						\
+		     : "=a" (ret__)						\
+		     : "c" (msr), "0" ((__u32)val), "d" ((val)>>32), "i" (-EFAULT));\
+	ret__; })
+
+#define rdtsc(low,high) \
+     __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
+
+#define rdtscl(low) \
+     __asm__ __volatile__ ("rdtsc" : "=a" (low) : : "edx")
+
+#define rdtscll(val) do { \
+     unsigned int a,d; \
+     asm volatile("rdtsc" : "=a" (a), "=d" (d)); \
+     (val) = ((unsigned long)a) | (((unsigned long)d)<<32); \
+} while(0)
+
+#define rdpmc(counter,low,high) \
+     __asm__ __volatile__("rdpmc" \
+			  : "=a" (low), "=d" (high) \
+			  : "c" (counter))
+
+#define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
+
+#define rdpmc(counter,low,high) \
+     __asm__ __volatile__("rdpmc" \
+			  : "=a" (low), "=d" (high) \
+			  : "c" (counter))
+
+#endif
+
+/* AMD/K8 specific MSRs */ 
+#define MSR_EFER 0xc0000080		/* extended feature register */
+#define MSR_STAR 0xc0000081		/* legacy mode SYSCALL target */
+#define MSR_LSTAR 0xc0000082 		/* long mode SYSCALL target */
+#define MSR_CSTAR 0xc0000083		/* compatibility mode SYSCALL target */
+#define MSR_SYSCALL_MASK 0xc0000084	/* EFLAGS mask for syscall */
+#define MSR_FS_BASE 0xc0000100		/* 64bit GS base */
+#define MSR_GS_BASE 0xc0000101		/* 64bit FS base */
+#define MSR_KERNEL_GS_BASE  0xc0000102	/* SwapGS GS shadow (or USER_GS from kernel) */ 
+/* EFER bits: */ 
+#define _EFER_SCE 0  /* SYSCALL/SYSRET */
+#define _EFER_LME 8  /* Long mode enable */
+#define _EFER_LMA 10 /* Long mode active (read-only) */
+#define _EFER_NX 11  /* No execute enable */
+
+#define EFER_SCE (1<<_EFER_SCE)
+#define EFER_LME (1<<EFER_LME)
+#define EFER_LMA (1<<EFER_LMA)
+#define EFER_NX (1<<_EFER_NX)
+
+/* Intel MSRs. Some also available on other CPUs */
+#define MSR_IA32_PLATFORM_ID	0x17
+
+#define MSR_IA32_PERFCTR0      0xc1
+#define MSR_IA32_PERFCTR1      0xc2
+
+#define MSR_MTRRcap		0x0fe
+#define MSR_IA32_BBL_CR_CTL        0x119
+
+#define MSR_IA32_MCG_CAP       0x179
+#define MSR_IA32_MCG_STATUS        0x17a
+#define MSR_IA32_MCG_CTL       0x17b
+
+#define MSR_IA32_EVNTSEL0      0x186
+#define MSR_IA32_EVNTSEL1      0x187
+
+#define MSR_IA32_DEBUGCTLMSR       0x1d9
+#define MSR_IA32_LASTBRANCHFROMIP  0x1db
+#define MSR_IA32_LASTBRANCHTOIP        0x1dc
+#define MSR_IA32_LASTINTFROMIP     0x1dd
+#define MSR_IA32_LASTINTTOIP       0x1de
+
+#define MSR_MTRRfix64K_00000	0x250
+#define MSR_MTRRfix16K_80000	0x258
+#define MSR_MTRRfix16K_A0000	0x259
+#define MSR_MTRRfix4K_C0000	0x268
+#define MSR_MTRRfix4K_C8000	0x269
+#define MSR_MTRRfix4K_D0000	0x26a
+#define MSR_MTRRfix4K_D8000	0x26b
+#define MSR_MTRRfix4K_E0000	0x26c
+#define MSR_MTRRfix4K_E8000	0x26d
+#define MSR_MTRRfix4K_F0000	0x26e
+#define MSR_MTRRfix4K_F8000	0x26f
+#define MSR_MTRRdefType		0x2ff
+
+#define MSR_IA32_MC0_CTL       0x400
+#define MSR_IA32_MC0_STATUS        0x401
+#define MSR_IA32_MC0_ADDR      0x402
+#define MSR_IA32_MC0_MISC      0x403
+
+#define MSR_P6_PERFCTR0			0xc1
+#define MSR_P6_PERFCTR1			0xc2
+#define MSR_P6_EVNTSEL0			0x186
+#define MSR_P6_EVNTSEL1			0x187
+
+/* K7/K8 MSRs. Not complete. See the architecture manual for a more complete list. */
+#define MSR_K7_EVNTSEL0            0xC0010000
+#define MSR_K7_PERFCTR0            0xC0010004
+#define MSR_K7_EVNTSEL1            0xC0010001
+#define MSR_K7_PERFCTR1            0xC0010005
+#define MSR_K7_EVNTSEL2            0xC0010002
+#define MSR_K7_PERFCTR2            0xC0010006
+#define MSR_K7_EVNTSEL3            0xC0010003
+#define MSR_K7_PERFCTR3            0xC0010007
+#define MSR_K8_TOP_MEM1		   0xC001001A
+#define MSR_K8_TOP_MEM2		   0xC001001D
+#define MSR_K8_SYSCFG		   0xC0000010	
+
+/* K6 MSRs */
+#define MSR_K6_EFER			0xC0000080
+#define MSR_K6_STAR			0xC0000081
+#define MSR_K6_WHCR			0xC0000082
+#define MSR_K6_UWCCR			0xC0000085
+#define MSR_K6_PSOR			0xC0000087
+#define MSR_K6_PFIR			0xC0000088
+
+/* Centaur-Hauls/IDT defined MSRs. */
+#define MSR_IDT_FCR1			0x107
+#define MSR_IDT_FCR2			0x108
+#define MSR_IDT_FCR3			0x109
+#define MSR_IDT_FCR4			0x10a
+
+#define MSR_IDT_MCR0			0x110
+#define MSR_IDT_MCR1			0x111
+#define MSR_IDT_MCR2			0x112
+#define MSR_IDT_MCR3			0x113
+#define MSR_IDT_MCR4			0x114
+#define MSR_IDT_MCR5			0x115
+#define MSR_IDT_MCR6			0x116
+#define MSR_IDT_MCR7			0x117
+#define MSR_IDT_MCR_CTRL		0x120
+
+/* VIA Cyrix defined MSRs*/
+#define MSR_VIA_FCR			0x1107
+
+/* Intel defined MSRs. */
+#define MSR_IA32_P5_MC_ADDR		0
+#define MSR_IA32_P5_MC_TYPE		1
+#define MSR_IA32_PLATFORM_ID		0x17
+#define MSR_IA32_EBL_CR_POWERON		0x2a
+
+#define MSR_IA32_APICBASE               0x1b
+#define MSR_IA32_APICBASE_BSP           (1<<8)
+#define MSR_IA32_APICBASE_ENABLE        (1<<11)
+#define MSR_IA32_APICBASE_BASE          (0xfffff<<12)
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/mtrr.h linux-2.4.20/include/asm-x86_64/mtrr.h
--- linux-2.4.19/include/asm-x86_64/mtrr.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/mtrr.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,120 @@
+/*  Generic MTRR (Memory Type Range Register) ioctls.
+
+    Copyright (C) 1997-1999  Richard Gooch
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
+    The postal address is:
+      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
+*/
+#ifndef _LINUX_MTRR_H
+#define _LINUX_MTRR_H
+
+#include <linux/config.h>
+#include <linux/ioctl.h>
+
+#define	MTRR_IOCTL_BASE	'M'
+
+struct mtrr_sentry
+{
+    unsigned long base;    /*  Base address     */
+    unsigned int size;    /*  Size of region   */
+    unsigned int type;     /*  Type of region   */
+};
+
+struct mtrr_gentry
+{
+    unsigned long base;    /*  Base address     */
+    unsigned int size;    /*  Size of region   */
+    unsigned int regnum;   /*  Register number  */
+    unsigned int type;     /*  Type of region   */
+};
+
+/*  These are the various ioctls  */
+#define MTRRIOC_ADD_ENTRY        _IOW(MTRR_IOCTL_BASE,  0, struct mtrr_sentry)
+#define MTRRIOC_SET_ENTRY        _IOW(MTRR_IOCTL_BASE,  1, struct mtrr_sentry)
+#define MTRRIOC_DEL_ENTRY        _IOW(MTRR_IOCTL_BASE,  2, struct mtrr_sentry)
+#define MTRRIOC_GET_ENTRY        _IOWR(MTRR_IOCTL_BASE, 3, struct mtrr_gentry)
+#define MTRRIOC_KILL_ENTRY       _IOW(MTRR_IOCTL_BASE,  4, struct mtrr_sentry)
+#define MTRRIOC_ADD_PAGE_ENTRY   _IOW(MTRR_IOCTL_BASE,  5, struct mtrr_sentry)
+#define MTRRIOC_SET_PAGE_ENTRY   _IOW(MTRR_IOCTL_BASE,  6, struct mtrr_sentry)
+#define MTRRIOC_DEL_PAGE_ENTRY   _IOW(MTRR_IOCTL_BASE,  7, struct mtrr_sentry)
+#define MTRRIOC_GET_PAGE_ENTRY   _IOWR(MTRR_IOCTL_BASE, 8, struct mtrr_gentry)
+#define MTRRIOC_KILL_PAGE_ENTRY  _IOW(MTRR_IOCTL_BASE,  9, struct mtrr_sentry)
+
+/*  These are the region types  */
+#define MTRR_TYPE_UNCACHABLE 0
+#define MTRR_TYPE_WRCOMB     1
+/*#define MTRR_TYPE_         2*/
+/*#define MTRR_TYPE_         3*/
+#define MTRR_TYPE_WRTHROUGH  4
+#define MTRR_TYPE_WRPROT     5
+#define MTRR_TYPE_WRBACK     6
+#define MTRR_NUM_TYPES       7
+
+#ifdef MTRR_NEED_STRINGS
+static char *mtrr_strings[MTRR_NUM_TYPES] =
+{
+    "uncachable",               /* 0 */
+    "write-combining",          /* 1 */
+    "?",                        /* 2 */
+    "?",                        /* 3 */
+    "write-through",            /* 4 */
+    "write-protect",            /* 5 */
+    "write-back",               /* 6 */
+};
+#endif
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+
+/*  The following functions are for use by other drivers  */
+#ifdef CONFIG_MTRR
+extern int mtrr_add (__u64 base, __u32 size, unsigned int type, char increment);
+extern int mtrr_add_page (__u64 base, __u32 size, unsigned int type, char increment);
+extern int mtrr_del (int reg, __u64 base, __u32 size);
+extern int mtrr_del_page (int reg, __u64 base, __u32 size);
+#else
+static __inline__ int mtrr_add (__u64 base, __u32 size,
+				unsigned int type, char increment)
+{
+    return -ENODEV;
+}
+static __inline__ int mtrr_add_page (__u64 base, __u32 size,
+				unsigned int type, char increment)
+{
+    return -ENODEV;
+}
+static __inline__ int mtrr_del (int reg, __u64 base, __u32 size)
+{
+    return -ENODEV;
+}
+static __inline__ int mtrr_del_page (int reg, __u64 base, __u32 size)
+{
+    return -ENODEV;
+}
+#endif
+
+/*  The following functions are for initialisation: don't use them!  */
+extern int mtrr_init (void);
+#if defined(CONFIG_SMP) && defined(CONFIG_MTRR)
+extern void mtrr_init_boot_cpu (void);
+extern void mtrr_init_secondary_cpu (void);
+#endif
+
+#endif
+
+#endif  /*  _LINUX_MTRR_H  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/namei.h linux-2.4.20/include/asm-x86_64/namei.h
--- linux-2.4.19/include/asm-x86_64/namei.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/namei.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,11 @@
+#ifndef __X8664_NAMEI_H
+#define __X8664_NAMEI_H
+
+/* This dummy routine maybe changed to something useful
+ * for /usr/gnemul/ emulation stuff.
+ * Look at asm-sparc/namei.h for details.
+ */
+
+#define __emul_prefix() NULL
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/page.h linux-2.4.20/include/asm-x86_64/page.h
--- linux-2.4.19/include/asm-x86_64/page.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/page.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,143 @@
+#ifndef _X86_64_PAGE_H
+#define _X86_64_PAGE_H
+
+/* PAGE_SHIFT determines the page size */
+#define PAGE_SHIFT	12
+#ifdef __ASSEMBLY__
+#define PAGE_SIZE	(0x1 << PAGE_SHIFT)
+#else
+#define PAGE_SIZE	(1UL << PAGE_SHIFT)
+#endif
+#define PAGE_MASK	(~(PAGE_SIZE-1))
+
+#define __PHYSICAL_MASK		0x0000ffffffffffffUL
+#define PHYSICAL_PAGE_MASK	0x0000fffffffff000UL
+
+#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
+#define LARGE_PAGE_SIZE (1UL << PMD_SHIFT)
+
+#define LARGE_PFN	(LARGE_PAGE_SIZE / PAGE_SIZE)
+
+#define KERNEL_TEXT_SIZE  (40UL*1024*1024)
+#define KERNEL_TEXT_START 0xffffffff80000000UL 
+
+/* Changing the next two defines should be enough to increase the kernel stack */
+/* We still hope 8K is enough, but ... */
+#define THREAD_ORDER    1
+#define THREAD_SIZE    (2*PAGE_SIZE)
+
+#define INIT_TASK_SIZE THREAD_SIZE
+#define CURRENT_MASK (~(THREAD_SIZE-1))
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+void clear_page(void *);
+void copy_page(void *, void *); 
+
+#define clear_user_page(page, vaddr)	clear_page(page)
+#define copy_user_page(to, from, vaddr)	copy_page(to, from)
+
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long pmd; } pmd_t;
+typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned long pml4; } pml4_t;
+#define PTE_MASK	PAGE_MASK
+
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+#define pte_val(x)	((x).pte)
+#define pmd_val(x)	((x).pmd)
+#define pgd_val(x)	((x).pgd)
+#define pml4_val(x)	((x).pml4)
+#define pgprot_val(x)	((x).pgprot)
+
+#define __pte(x) ((pte_t) { (x) } )
+#define __pmd(x) ((pmd_t) { (x) } )
+#define __pgd(x) ((pgd_t) { (x) } )
+#define __level4(x) ((level4_t) { (x) } )
+#define __pgprot(x)	((pgprot_t) { (x) } )
+ 
+#endif /* !__ASSEMBLY__ */
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
+
+/* See Documentation/X86_64/mm.txt for a description of the layout. */
+#define __START_KERNEL		0xffffffff80100000
+#define __START_KERNEL_map	0xffffffff80000000
+#define __PAGE_OFFSET           0x0000010000000000
+
+#ifndef __ASSEMBLY__
+
+#include <linux/config.h>
+#include <linux/stringify.h>
+
+
+/*
+ * Tell the user there is some problem.  The exception handler decodes this frame.
+ */
+struct bug_frame { 
+       unsigned char ud2[2];          
+       char *filename;    /* should use 32bit offset instead, but the assembler doesn't like it */ 
+       unsigned short line; 
+} __attribute__((packed)); 
+#define BUG() asm volatile("ud2 ; .quad %c1 ; .short %c0" :: "i"(__LINE__), \
+		"i" (__stringify(KBUILD_BASENAME)))
+#define HEADER_BUG() asm volatile("ud2 ; .quad %c1 ; .short %c0" :: "i"(__LINE__), \
+		"i" (__stringify(__FILE__)))
+#define PAGE_BUG(page) BUG()
+
+/* Pure 2^n version of get_order */
+extern __inline__ int get_order(unsigned long size)
+{
+	int order;
+
+	size = (size-1) >> (PAGE_SHIFT-1);
+	order = -1;
+	do {
+		size >>= 1;
+		order++;
+	} while (size);
+	return order;
+}
+
+#endif /* __ASSEMBLY__ */
+
+#define PAGE_OFFSET		((unsigned long)__PAGE_OFFSET)
+
+/* Note: __pa(&symbol_visible_to_c) should be always replaced with __pa_symbol.
+   Otherwise you risk miscompilation. */ 
+#define __pa(x)			(((unsigned long)(x)>=__START_KERNEL_map)?(unsigned long)(x) - (unsigned long)__START_KERNEL_map:(unsigned long)(x) - PAGE_OFFSET)
+/* __pa_symbol should use for C visible symbols, but only for them. 
+   This seems to be the official gcc blessed way to do such arithmetic. */ 
+#define __pa_symbol(x)		\
+	({unsigned long v;  \
+	  asm("" : "=r" (v) : "0" (x)); \
+	 v - __START_KERNEL_map; })
+#define __pa_maybe_symbol(x)		\
+	({unsigned long v;  \
+	  asm("" : "=r" (v) : "0" (x)); \
+	  __pa(v); })
+
+#define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
+#ifndef CONFIG_DISCONTIGMEM
+#define virt_to_page(kaddr)	(mem_map + (__pa(kaddr) >> PAGE_SHIFT))
+#define pfn_to_page(pfn)	(mem_map + (pfn)) 
+#define page_to_pfn(page)   ((page) - mem_map)
+#define page_to_phys(page)	(((page) - mem_map) << PAGE_SHIFT)
+#define VALID_PAGE(page)	(((page) - mem_map) < max_mapnr)
+#endif
+
+#define phys_to_pfn(phys)	((phys) >> PAGE_SHIFT)
+
+
+#define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
+				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#endif /* __KERNEL__ */
+
+#endif /* _X86_64_PAGE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/param.h linux-2.4.20/include/asm-x86_64/param.h
--- linux-2.4.19/include/asm-x86_64/param.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/param.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,24 @@
+#ifndef _ASMx86_64_PARAM_H
+#define _ASMx86_64_PARAM_H
+
+#ifndef HZ
+#define HZ 100
+#endif
+
+#define EXEC_PAGESIZE	4096
+
+#ifndef NGROUPS
+#define NGROUPS		32
+#endif
+
+#ifndef NOGROUP
+#define NOGROUP		(-1)
+#endif
+
+#define MAXHOSTNAMELEN	64	/* max length of hostname */
+
+#ifdef __KERNEL__
+# define CLOCKS_PER_SEC	100	/* frequency at which times() counts */
+#endif
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/parport.h linux-2.4.20/include/asm-x86_64/parport.h
--- linux-2.4.19/include/asm-x86_64/parport.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/parport.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,18 @@
+/*
+ * parport.h: ia32-specific parport initialisation
+ *
+ * Copyright (C) 1999, 2000  Tim Waugh <tim@cyberelk.demon.co.uk>
+ *
+ * This file should only be included by drivers/parport/parport_pc.c.
+ */
+
+#ifndef _ASM_X8664_PARPORT_H
+#define _ASM_X8664_PARPORT_H 1
+
+static int __devinit parport_pc_find_isa_ports (int autoirq, int autodma);
+static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma)
+{
+	return parport_pc_find_isa_ports (autoirq, autodma);
+}
+
+#endif 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/pci-direct.h linux-2.4.20/include/asm-x86_64/pci-direct.h
--- linux-2.4.19/include/asm-x86_64/pci-direct.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/pci-direct.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,29 @@
+#ifndef ASM_PCI_DIRECT_H
+#define ASM_PCI_DIRECT_H 1
+
+#include <linux/types.h>
+#include <asm/io.h>
+
+/* Direct PCI access. This is used for PCI accesses in early boot before
+   the PCI subsystem works. */ 
+
+#define PDprintk(x...)
+
+static inline u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset)
+{
+	u32 v; 
+	outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
+	v = inl(0xcfc); 
+	PDprintk("%x reading from %x: %x\n", slot, offset, v);
+	return v;
+}
+
+static inline void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset,
+				    u32 val)
+{
+	PDprintk("%x writing to %x: %x\n", slot, offset, val); 
+	outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
+	outl(val, 0xcfc); 
+}
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/pci.h linux-2.4.20/include/asm-x86_64/pci.h
--- linux-2.4.19/include/asm-x86_64/pci.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/pci.h	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,275 @@
+#ifndef __x8664_PCI_H
+#define __x8664_PCI_H
+
+#include <linux/config.h>
+#include <asm/io.h>
+
+#ifdef __KERNEL__
+
+extern dma_addr_t bad_dma_address;
+
+/* Can be used to override the logic in pci_scan_bus for skipping
+   already-configured bus numbers - to be used for buggy BIOSes
+   or architectures with incomplete PCI setup by the loader */
+
+#ifdef CONFIG_PCI
+extern unsigned int pcibios_assign_all_busses(void);
+#else
+#define pcibios_assign_all_busses()	0
+#endif
+
+extern unsigned long pci_mem_start;
+#define PCIBIOS_MIN_IO		0x1000
+#define PCIBIOS_MIN_MEM		(pci_mem_start)
+
+void pcibios_set_master(struct pci_dev *dev);
+void pcibios_penalize_isa_irq(int irq);
+struct irq_routing_table *pcibios_get_irq_routing_table(void);
+int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/scatterlist.h>
+#include <linux/string.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/mmzone.h>
+
+struct pci_dev;
+
+/* Allocate and map kernel buffer using consistent mode DMA for a device.
+ * hwdev should be valid struct pci_dev pointer for PCI devices,
+ * NULL for PCI-like buses (ISA, EISA).
+ * Returns non-NULL cpu-view pointer to the buffer if successful and
+ * sets *dma_addrp to the pci side dma address as well, else *dma_addrp
+ * is undefined.
+ */
+extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+				  dma_addr_t *dma_handle);
+
+/* Free and unmap a consistent DMA buffer.
+ * cpu_addr is what was returned from pci_alloc_consistent,
+ * size must be the same as what as passed into pci_alloc_consistent,
+ * and likewise dma_addr must be the same as what *dma_addrp was set to.
+ *
+ * References to the memory and mappings associated with cpu_addr/dma_addr
+ * past this call are illegal.
+ */
+extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+				void *vaddr, dma_addr_t dma_handle);
+
+#ifdef CONFIG_GART_IOMMU
+
+/* Map a single buffer of the indicated size for DMA in streaming mode.
+ * The 32-bit bus address to use is returned.
+ *
+ * Once the device is given the dma address, the device owns this memory
+ * until either pci_unmap_single or pci_dma_sync_single is performed.
+ */
+extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+			  size_t size, int direction);
+
+extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t addr,
+				   size_t size, int direction);
+
+/*
+ * pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical
+ * to pci_map_single, but takes a struct page instead of a virtual address
+ */
+
+#define pci_map_page(dev,page,offset,size,dir) \
+	pci_map_single((dev), page_address(page)+(offset), (size), (dir)) 
+
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+
+static inline void pci_dma_sync_single(struct pci_dev *hwdev, 
+				       dma_addr_t dma_handle,
+				       size_t size, int direction)
+{
+	BUG_ON(direction == PCI_DMA_NONE); 
+} 
+
+static inline void pci_dma_sync_sg(struct pci_dev *hwdev, 
+				   struct scatterlist *sg,
+				   int nelems, int direction)
+{ 
+	BUG_ON(direction == PCI_DMA_NONE); 
+} 
+
+/* The PCI address space does equal the physical memory
+ * address space.  The networking and block device layers use
+ * this boolean for bounce buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS	(0)
+
+
+#else
+static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+					size_t size, int direction)
+{
+	dma_addr_t addr; 
+
+	if (direction == PCI_DMA_NONE)
+		out_of_line_bug();	
+	addr = virt_to_bus(ptr); 
+
+	/* 
+	 * This is gross, but what should I do.
+	 * Unfortunately drivers do not test the return value of this.
+	 */
+	if ((addr+size) & ~hwdev->dma_mask) 
+		out_of_line_bug(); 
+	return addr;
+}
+
+static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+				    size_t size, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		out_of_line_bug();
+	/* Nothing to do */
+}
+
+static inline dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page,
+				      unsigned long offset, size_t size, int direction)
+{
+	dma_addr_t addr;
+	if (direction == PCI_DMA_NONE)
+		out_of_line_bug();	
+ 	addr = page_to_pfn(page) * PAGE_SIZE + offset;
+	if ((addr+size) & ~hwdev->dma_mask) 
+		out_of_line_bug();
+	return addr;
+}
+
+/* pci_unmap_{page,single} is a nop so... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)		(0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
+	
+/* Make physical memory consistent for a single
+ * streaming mode DMA translation after a transfer.
+ *
+ * If you perform a pci_map_single() but wish to interrogate the
+ * buffer using the cpu, yet do not wish to teardown the PCI dma
+ * mapping, you must call this function before doing so.  At the
+ * next point you give the PCI dma address back to the card, the
+ * device again owns the buffer.
+ */
+static inline void pci_dma_sync_single(struct pci_dev *hwdev,
+				       dma_addr_t dma_handle,
+				       size_t size, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		out_of_line_bug();
+	flush_write_buffers();
+}
+
+/* Make physical memory consistent for a set of streaming
+ * mode DMA translations after a transfer.
+ *
+ * The same as pci_dma_sync_single but for a scatter-gather list,
+ * same rules and usage.
+ */
+static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
+				   struct scatterlist *sg,
+				   int nelems, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		out_of_line_bug();
+	flush_write_buffers();
+}
+
+#define PCI_DMA_BUS_IS_PHYS	1
+
+#endif
+
+extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+		      int nents, int direction);
+extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+			 int nents, int direction);
+
+
+#define pci_unmap_page pci_unmap_single
+
+/* Return whether the given PCI device DMA address mask can
+ * be supported properly.  For example, if your device can
+ * only drive the low 24-bits during PCI bus mastering, then
+ * you would pass 0x00ffffff as the mask to this function.
+ */
+static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
+{
+        /*
+         * we fall back to GFP_DMA when the mask isn't all 1s,
+         * so we can't guarantee allocations that must be
+         * within a tighter range than GFP_DMA..
+         */
+        if(mask < 0x00ffffff)
+                return 0;
+
+	return 1;
+}
+
+/* This is always fine. */
+#define pci_dac_dma_supported(pci_dev, mask)	(1)
+
+static __inline__ dma64_addr_t
+pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
+{
+	return ((dma64_addr_t) page_to_bus(page) +
+		(dma64_addr_t) offset);
+}
+
+static __inline__ struct page *
+pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
+{
+	return pfn_to_page(phys_to_pfn(dma_addr)); 
+}
+
+static __inline__ unsigned long
+pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
+{
+	return (dma_addr & ~PAGE_MASK);
+}
+
+static __inline__ void
+pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
+{
+	flush_write_buffers();
+}
+
+/* These macros should be used after a pci_map_sg call has been done
+ * to get bus addresses of each of the SG entries and their lengths.
+ * You should only work with the number of sg entries pci_map_sg
+ * returns.
+ */
+#define sg_dma_address(sg)	((sg)->dma_address)
+#define sg_dma_len(sg)		((sg)->length)
+
+/* Return the index of the PCI controller for device. */
+static inline int pci_controller_num(struct pci_dev *dev)
+{
+	return 0;
+}
+
+#define HAVE_PCI_MMAP
+extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+			       enum pci_mmap_state mmap_state, int write_combine);
+
+#endif /* __KERNEL__ */
+
+#endif /* __x8664_PCI_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/pda.h linux-2.4.20/include/asm-x86_64/pda.h
--- linux-2.4.19/include/asm-x86_64/pda.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/pda.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,74 @@
+#ifndef X86_64_PDA_H
+#define X86_64_PDA_H
+
+#include <linux/stddef.h>
+#ifndef ASM_OFFSET_H
+#include <asm/offset.h>
+#endif
+#include <linux/cache.h>
+
+/* Per processor datastructure. %gs points to it while the kernel runs */ 
+/* To use a new field with the *_pda macros it needs to be added to tools/offset.c */
+struct x8664_pda {
+	unsigned long kernelstack;  /* TOS for current process */ 
+	unsigned long oldrsp; 	    /* user rsp for system call */
+	unsigned long irqrsp;	    /* Old rsp for interrupts. */ 
+	struct task_struct *pcurrent;	/* Current process */
+        int irqcount;		    /* Irq nesting counter. Starts with -1 */  	
+	int cpunumber;		    /* Logical CPU number */
+	/* XXX: could be a single list */
+	unsigned long *pgd_quick;
+	unsigned long *pmd_quick;
+	unsigned long *pte_quick;
+	unsigned long pgtable_cache_sz;
+	char *irqstackptr;	/* top of irqstack */
+	unsigned long volatile *level4_pgt; 
+} ____cacheline_aligned;
+
+#define PDA_STACKOFFSET (5*8)
+
+#define IRQSTACK_ORDER 2
+#define IRQSTACKSIZE (PAGE_SIZE << IRQSTACK_ORDER) 
+
+extern struct x8664_pda cpu_pda[];
+
+/* 
+ * There is no fast way to get the base address of the PDA, all the accesses
+ * have to mention %fs/%gs.  So it needs to be done this Torvaldian way.
+ */ 
+#define sizeof_field(type,field)  (sizeof(((type *)0)->field))
+#define typeof_field(type,field)  typeof(((type *)0)->field)
+#ifndef __STR
+#define __STR(x) #x
+#endif
+#define __STR2(x) __STR(x) 
+
+extern void __bad_pda_field(void);
+
+#define pda_to_op(op,field,val) do { \
+       switch (sizeof_field(struct x8664_pda, field)) { 		\
+       case 2: asm volatile(op "w %0,%%gs:" __STR2(pda_ ## field) ::"r" (val):"memory"); break;	\
+       case 4: asm volatile(op "l %0,%%gs:" __STR2(pda_ ## field) ::"r" (val):"memory"); break;	\
+       case 8: asm volatile(op "q %0,%%gs:" __STR2(pda_ ## field) ::"r" (val):"memory"); break;	\
+       default: __bad_pda_field(); 					\
+       } \
+       } while (0)
+
+
+#define pda_from_op(op,field) ({ \
+       typedef typeof_field(struct x8664_pda, field) T__; T__ ret__; \
+       switch (sizeof_field(struct x8664_pda, field)) { 		\
+       case 2: asm volatile(op "w %%gs:" __STR2(pda_ ## field) ",%0":"=r" (ret__)::"memory"); break;	\
+       case 4: asm volatile(op "l %%gs:" __STR2(pda_ ## field) ",%0":"=r" (ret__)::"memory"); break;	\
+       case 8: asm volatile(op "q %%gs:" __STR2(pda_ ## field) ",%0":"=r" (ret__)::"memory"); break;	\
+       default: __bad_pda_field(); 					\
+       } \
+       ret__; })
+
+
+#define read_pda(field) pda_from_op("mov",field)
+#define write_pda(field,val) pda_to_op("mov",field,val)
+#define add_pda(field,val) pda_to_op("add",field,val)
+#define sub_pda(field,val) pda_to_op("sub",field,val)
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/pgalloc.h linux-2.4.20/include/asm-x86_64/pgalloc.h
--- linux-2.4.19/include/asm-x86_64/pgalloc.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/pgalloc.h	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,219 @@
+#ifndef _X86_64_PGALLOC_H
+#define _X86_64_PGALLOC_H
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/fixmap.h>
+#include <asm/pda.h>
+#include <linux/threads.h>
+#include <linux/mm.h>
+#include <asm/page.h>
+
+#define inc_pgcache_size() add_pda(pgtable_cache_sz,1UL)
+#define dec_pgcache_size() sub_pda(pgtable_cache_sz,1UL)
+
+#define pmd_populate(mm, pmd, pte) \
+		set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte)))
+#define pgd_populate(mm, pgd, pmd) \
+		set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pmd)))
+
+extern __inline__ pmd_t *get_pmd_slow(void)
+{
+	return (pmd_t *)get_zeroed_page(GFP_KERNEL);
+}
+
+extern __inline__ pmd_t *get_pmd_fast(void)
+{
+	unsigned long *ret;
+
+	if ((ret = read_pda(pmd_quick)) != NULL) {
+		write_pda(pmd_quick, (unsigned long *)(*ret));
+		ret[0] = 0;
+		dec_pgcache_size();
+	} else
+		ret = (unsigned long *)get_pmd_slow();
+	return (pmd_t *)ret;
+}
+
+extern __inline__ void pmd_free(pmd_t *pmd)
+{
+	*(unsigned long *)pmd = (unsigned long) read_pda(pmd_quick);
+	write_pda(pmd_quick,(unsigned long *) pmd);
+	inc_pgcache_size();
+}
+
+extern __inline__ void pmd_free_slow(pmd_t *pmd)
+{
+	if ((unsigned long)pmd & (PAGE_SIZE-1)) 
+		out_of_line_bug(); 
+	free_page((unsigned long)pmd);
+}
+
+static inline pmd_t *pmd_alloc_one_fast (struct mm_struct *mm, unsigned long addr)
+{
+	unsigned long *ret = (unsigned long *)read_pda(pmd_quick);
+
+	if (ret != NULL) {
+		write_pda(pmd_quick, (unsigned long *)(*ret));
+		ret[0] = 0;
+		dec_pgcache_size();
+	}
+	return (pmd_t *)ret;
+}
+
+static inline pmd_t *pmd_alloc_one (struct mm_struct *mm, unsigned long addr)
+{
+	return (pmd_t *)get_zeroed_page(GFP_KERNEL); 
+}
+
+static inline pgd_t *pgd_alloc_one_fast (void)
+{
+	unsigned long *ret = read_pda(pgd_quick);
+
+	if (ret) {
+		write_pda(pgd_quick,(unsigned long *)(*ret));
+		ret[0] = 0;
+		dec_pgcache_size();
+	}
+	return (pgd_t *) ret;
+}
+
+static inline pgd_t *pgd_alloc (struct mm_struct *mm)
+{
+	/* the VM system never calls pgd_alloc_one_fast(), so we do it here. */
+	pgd_t *pgd = pgd_alloc_one_fast();
+
+	if (pgd == NULL)
+		pgd = (pgd_t *)get_zeroed_page(GFP_KERNEL); 
+	return pgd;
+}
+
+static inline void pgd_free (pgd_t *pgd)
+{
+	*(unsigned long *)pgd = (unsigned long) read_pda(pgd_quick);
+	write_pda(pgd_quick,(unsigned long *) pgd);
+	inc_pgcache_size();
+}
+
+
+static inline void pgd_free_slow (pgd_t *pgd)
+{
+	if ((unsigned long)pgd & (PAGE_SIZE-1)) 
+		out_of_line_bug(); 
+	free_page((unsigned long)pgd);
+}
+
+
+static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+	return (pte_t *)get_zeroed_page(GFP_KERNEL); 
+}
+
+extern __inline__ pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+{
+	unsigned long *ret;
+
+	if ((ret = read_pda(pte_quick)) != NULL) {  
+		write_pda(pte_quick, (unsigned long *)(*ret));
+		ret[0] = ret[1];
+		dec_pgcache_size();
+	}
+	return (pte_t *)ret;
+}
+
+/* Should really implement gc for free page table pages. This could be done with 
+   a reference count in struct page. */
+
+extern __inline__ void pte_free(pte_t *pte)
+{	
+	*(unsigned long *)pte = (unsigned long) read_pda(pte_quick);
+	write_pda(pte_quick, (unsigned long *) pte); 
+	inc_pgcache_size();
+}
+
+extern __inline__ void pte_free_slow(pte_t *pte)
+{
+	if ((unsigned long)pte & (PAGE_SIZE-1))
+		out_of_line_bug();
+	free_page((unsigned long)pte); 
+}
+
+
+extern int do_check_pgt_cache(int, int);
+
+/*
+ * TLB flushing:
+ *
+ *  - flush_tlb() flushes the current mm struct TLBs
+ *  - flush_tlb_all() flushes all processes TLBs
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
+ */
+
+#ifndef CONFIG_SMP
+
+#define flush_tlb() __flush_tlb()
+#define flush_tlb_all() __flush_tlb_all()
+#define local_flush_tlb() __flush_tlb()
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+	if (mm == current->active_mm)
+		__flush_tlb();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+	unsigned long addr)
+{
+	if (vma->vm_mm == current->active_mm)
+		__flush_tlb_one(addr);
+}
+
+static inline void flush_tlb_range(struct mm_struct *mm,
+	unsigned long start, unsigned long end)
+{
+	if (mm == current->active_mm)
+		__flush_tlb();
+}
+
+#else
+
+#include <asm/smp.h>
+
+#define local_flush_tlb() \
+	__flush_tlb()
+
+extern void flush_tlb_all(void);
+extern void flush_tlb_current_task(void);
+extern void flush_tlb_mm(struct mm_struct *);
+extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
+
+#define flush_tlb()	flush_tlb_current_task()
+
+static inline void flush_tlb_range(struct mm_struct * mm, unsigned long start, unsigned long end)
+{
+	flush_tlb_mm(mm);
+}
+
+#define TLBSTATE_OK	1
+#define TLBSTATE_LAZY	2
+
+struct tlb_state
+{
+	struct mm_struct *active_mm;
+	int state;
+};
+extern struct tlb_state cpu_tlbstate[NR_CPUS];
+
+
+#endif
+
+extern inline void flush_tlb_pgtables(struct mm_struct *mm,
+				      unsigned long start, unsigned long end)
+{
+	flush_tlb_mm(mm);
+}
+
+#endif /* _X86_64_PGALLOC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/pgtable.h linux-2.4.20/include/asm-x86_64/pgtable.h
--- linux-2.4.19/include/asm-x86_64/pgtable.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/pgtable.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,438 @@
+#ifndef _X86_64_PGTABLE_H
+#define _X86_64_PGTABLE_H
+
+/*
+ * This file contains the functions and defines necessary to modify and use
+ * the x86-64 page table tree.
+ * 
+ * x86-64 has a 4 level table setup. Generic linux MM only supports
+ * three levels. The fourth level is currently a single static page that
+ * is shared by everybody and just contains a pointer to the current
+ * three level page setup on the beginning and some kernel mappings at 
+ * the end. For more details see Documentation/x86_64/mm.txt
+ */
+#ifndef __ASSEMBLY__
+#include <asm/processor.h>
+#include <asm/fixmap.h>
+#include <asm/bitops.h>
+#include <asm/pda.h>
+#include <linux/threads.h>
+#include <linux/config.h>
+
+extern pgd_t level3_kernel_pgt[512];
+extern pgd_t level3_physmem_pgt[512];
+extern pgd_t level3_ident_pgt[512];
+extern pmd_t level2_kernel_pgt[512];
+extern pml4_t init_level4_pgt[];
+extern pgd_t boot_vmalloc_pgt[];
+
+extern void paging_init(void);
+
+#define swapper_pg_dir NULL
+
+/* Caches aren't brain-dead on the intel. */
+#define flush_cache_all()			do { } while (0)
+#define flush_cache_mm(mm)			do { } while (0)
+#define flush_cache_range(mm, start, end)	do { } while (0)
+#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_page_to_ram(page)			do { } while (0)
+#define flush_dcache_page(page)			do { } while (0)
+#define flush_icache_range(start, end)		do { } while (0)
+#define flush_icache_page(vma,pg)		do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
+
+#define __flush_tlb()							\
+	do {								\
+		unsigned long tmpreg;					\
+									\
+		__asm__ __volatile__(					\
+			"movq %%cr3, %0;  # flush TLB \n"		\
+			"movq %0, %%cr3;              \n"		\
+			: "=r" (tmpreg)					\
+			:: "memory");					\
+	} while (0)
+
+/*
+ * Global pages have to be flushed a bit differently. Not a real
+ * performance problem because this does not happen often.
+ */
+#define __flush_tlb_global()						\
+	do {								\
+		unsigned long tmpreg;					\
+									\
+		__asm__ __volatile__(					\
+			"movq %1, %%cr4;  # turn off PGE     \n"	\
+			"movq %%cr3, %0;  # flush TLB        \n"	\
+			"movq %0, %%cr3;                     \n"	\
+			"movq %2, %%cr4;  # turn PGE back on \n"	\
+			: "=&r" (tmpreg)				\
+			: "r" (mmu_cr4_features & ~(u64)X86_CR4_PGE),	\
+			  "r" (mmu_cr4_features)			\
+			: "memory");					\
+	} while (0)
+
+#define __flush_tlb_all() __flush_tlb_global()
+
+#define __flush_tlb_one(addr) __asm__ __volatile__("invlpg %0": :"m" (*(char *) addr))
+
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern unsigned long empty_zero_page[1024];
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+#endif /* !__ASSEMBLY__ */
+
+#define PML4_SHIFT	39
+#define PTRS_PER_PML4	512
+
+/*
+ * PGDIR_SHIFT determines what a 3rd level page table entry can map
+ */
+#define PGDIR_SHIFT	30
+#define PTRS_PER_PGD	512
+
+/*
+ * PMD_SHIFT determines the size of the area a middle-level
+ * page table can map
+ */
+#define PMD_SHIFT	21
+#define PTRS_PER_PMD	512
+
+/*
+ * entries per page directory level
+ */
+#define PTRS_PER_PTE	512
+
+#define pte_ERROR(e) \
+	printk("%s:%d: bad pte %p(%016lx).\n", __FILE__, __LINE__, &(e), pte_val(e))
+#define pmd_ERROR(e) \
+	printk("%s:%d: bad pmd %p(%016lx).\n", __FILE__, __LINE__, &(e), pmd_val(e))
+#define pgd_ERROR(e) \
+	printk("%s:%d: bad pgd %p(%016lx).\n", __FILE__, __LINE__, &(e), pgd_val(e))
+
+#define pml4_none(x)	(!pml4_val(x))
+#define pgd_none(x)	(!pgd_val(x))
+
+
+extern inline int pgd_present(pgd_t pgd)	{ return !pgd_none(pgd); }
+
+static inline void set_pte(pte_t *dst, pte_t val)
+{
+	pte_val(*dst) = pte_val(val);
+} 
+
+static inline void set_pmd(pmd_t *dst, pmd_t val)
+{
+	pmd_val(*dst) = pmd_val(val);
+} 
+
+static inline void set_pgd(pgd_t *dst, pgd_t val)
+{
+	pgd_val(*dst) = pgd_val(val);
+} 
+
+static inline void set_pml4(pml4_t *dst, pml4_t val) 
+{ 
+	pml4_val(*dst) = pml4_val(val);
+} 
+
+extern inline void __pgd_clear (pgd_t * pgd)
+{
+	set_pgd(pgd, __pgd(0));
+}
+
+extern inline void pgd_clear (pgd_t * pgd)
+{
+	__pgd_clear(pgd);
+	__flush_tlb();
+}
+
+#define pgd_page(pgd) \
+((unsigned long) __va(pgd_val(pgd) & PHYSICAL_PAGE_MASK))
+#define __mk_pgd(address,prot) ((pgd_t) { (address) | pgprot_val(prot) })
+
+/* Find an entry in the second-level page table.. */
+#define pmd_offset(dir, address) ((pmd_t *) pgd_page(*(dir)) + \
+			__pmd_offset(address))
+#define __mk_pmd(address,prot) ((pmd_t) { (address) | pgprot_val(prot) })
+
+#define ptep_get_and_clear(xp)	__pte(xchg(&(xp)->pte, 0))
+#define pte_same(a, b)		((a).pte == (b).pte)
+#define __mk_pte(page_nr,pgprot) __pte(((page_nr) << PAGE_SHIFT) | pgprot_val(pgprot))
+
+#define PML4_SIZE	(1UL << PML4_SHIFT)
+#define PML4_MASK	(~(PML4_SIZE-1))
+#define PMD_SIZE	(1UL << PMD_SHIFT)
+#define PMD_MASK	(~(PMD_SIZE-1))
+#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+
+#define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
+#define FIRST_USER_PGD_NR	0
+
+#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
+#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
+
+#define BOOT_USER_L4_PTRS 1
+#define BOOT_KERNEL_L4_PTRS 511	/* But we will do it in 4rd level */
+
+
+
+#ifndef __ASSEMBLY__
+/* IO mappings are the 509th slot in the PML4. We map them high up to make sure
+   they never appear in the node hash table in DISCONTIG configs. */
+#define IOMAP_START      0xfffffe8000000000
+
+/* vmalloc space occupies the 510th slot in the PML4. You can have upto 512GB of
+   vmalloc/ioremap space. */ 
+
+#define VMALLOC_START	 0xffffff0000000000
+#define VMALLOC_END      0xffffff7fffffffff
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+
+#define MODULES_VADDR    0xffffffffa0000000
+#define MODULES_END      0xffffffffafffffff
+#define MODULES_LEN   (MODULES_END - MODULES_VADDR)
+
+#define _PAGE_BIT_PRESENT	0
+#define _PAGE_BIT_RW		1
+#define _PAGE_BIT_USER		2
+#define _PAGE_BIT_PWT		3	/* Write Through */
+#define _PAGE_BIT_PCD		4	/* Cache disable */
+#define _PAGE_BIT_ACCESSED	5
+#define _PAGE_BIT_DIRTY		6
+#define _PAGE_BIT_PSE		7	/* 2MB page */
+#define _PAGE_BIT_GLOBAL	8	/* Global TLB entry PPro+ */
+#define _PAGE_BIT_NX           63       /* No execute: only valid after cpuid check */
+
+#define _PAGE_PRESENT	0x001
+#define _PAGE_RW	0x002
+#define _PAGE_USER	0x004
+#define _PAGE_PWT	0x008
+#define _PAGE_PCD	0x010
+#define _PAGE_ACCESSED	0x020
+#define _PAGE_DIRTY	0x040
+#define _PAGE_PSE	0x080	/* 2MB page */
+#define _PAGE_GLOBAL	0x100	/* Global TLB entry */
+#define _PAGE_PGE	_PAGE_GLOBAL
+#define _PAGE_NX        (1UL<<_PAGE_BIT_NX)
+
+#define _PAGE_PROTNONE	0x080	/* If not present */
+
+#define _PAGE_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _KERNPG_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+
+#define KERNPG_TABLE	__pgprot(_KERNPG_TABLE)
+
+#define _PAGE_CHG_MASK	(PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+
+#define PAGE_NONE	__pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
+#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+
+#define PAGE_LARGE (_PAGE_PSE|_PAGE_PRESENT) 
+
+#define __PAGE_KERNEL \
+	(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define __PAGE_KERNEL_NOCACHE   (__PAGE_KERNEL | _PAGE_PCD)
+#define __PAGE_KERNEL_RO        (__PAGE_KERNEL & ~_PAGE_RW)
+#define __PAGE_KERNEL_VSYSCALL	(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define __PAGE_KERNEL_LARGE     (__PAGE_KERNEL | _PAGE_PSE)
+#define __PAGE_KERNEL_LARGE_NOCACHE     (__PAGE_KERNEL_LARGE | _PAGE_PCD)
+#define __PAGE_KERNEL_EXECUTABLE (__PAGE_KERNEL & ~_PAGE_NX)
+#define __PAGE_USER_NOCACHE_RO	\
+	(_PAGE_PRESENT | _PAGE_USER | _PAGE_DIRTY | _PAGE_ACCESSED) 
+
+extern unsigned long __supported_pte_mask; 
+#define __PTE_SUPP(x) __pgprot((x) & __supported_pte_mask)
+
+#define PAGE_KERNEL __PTE_SUPP((__PAGE_KERNEL|_PAGE_GLOBAL) )
+#define PAGE_KERNEL_RO __PTE_SUPP(__PAGE_KERNEL_RO|_PAGE_GLOBAL)
+#define PAGE_KERNEL_NOCACHE __PTE_SUPP(__PAGE_KERNEL_NOCACHE|_PAGE_GLOBAL)
+#define PAGE_KERNEL_VSYSCALL __PTE_SUPP(__PAGE_KERNEL_VSYSCALL|_PAGE_GLOBAL)
+#define PAGE_KERNEL_LARGE __PTE_SUPP(__PAGE_KERNEL_LARGE|_PAGE_GLOBAL)
+#define PAGE_KERNEL_LARGE_NOCACHE __PTE_SUPP(__PAGE_KERNEL_LARGE_NOCACHE|_PAGE_GLOBAL)
+#define PAGE_USER_NOCACHE_RO __PTE_SUPP(__PAGE_USER_NOCACHE_RO|_PAGE_GLOBAL)
+#define PAGE_KERNEL_EXECUTABLE __PTE_SUPP(__PAGE_KERNEL_EXECUTABLE|_PAGE_GLOBAL)
+
+/*         xwr */
+#define __P000	PAGE_NONE
+#define __P001	PAGE_READONLY
+#define __P010	PAGE_COPY
+#define __P011	PAGE_COPY
+#define __P100	PAGE_READONLY
+#define __P101	PAGE_READONLY
+#define __P110	PAGE_COPY
+#define __P111	PAGE_COPY
+
+/*         xwr */
+#define __S000	PAGE_NONE
+#define __S001	PAGE_READONLY
+#define __S010	PAGE_SHARED
+#define __S011	PAGE_SHARED
+#define __S100	PAGE_READONLY
+#define __S101	PAGE_READONLY
+#define __S110	PAGE_SHARED
+#define __S111	PAGE_SHARED
+
+static inline unsigned long pgd_bad(pgd_t pgd) 
+{ 
+	unsigned long val = pgd_val(pgd);
+	val &= ~PAGE_MASK; 
+	val &= ~(_PAGE_USER | _PAGE_DIRTY); 
+	return val & ~(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED);  	
+} 
+
+/*
+ * Handling allocation failures during page table setup.
+ */
+extern void __handle_bad_pmd(pmd_t * pmd);
+extern void __handle_bad_pmd_kernel(pmd_t * pmd);
+
+#define pte_none(x)	(!pte_val(x))
+#define pte_present(x)	(pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
+#define pte_clear(xp)	do { set_pte(xp, __pte(0)); } while (0)
+
+#define pmd_none(x)	(!pmd_val(x))
+#define pmd_present(x)	(pmd_val(x) & _PAGE_PRESENT)
+#define pmd_clear(xp)	do { set_pmd(xp, __pmd(0)); } while (0)
+#define	pmd_bad(x)	\
+	((pmd_val(x) & (~PAGE_MASK & (~_PAGE_USER))) != _KERNPG_TABLE )
+
+#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
+
+#ifndef CONFIG_DISCONTIGMEM
+#define pte_page(x) (pfn_to_page((pte_val(x) & PHYSICAL_PAGE_MASK) >> PAGE_SHIFT))
+#endif
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+extern inline int pte_read(pte_t pte)		{ return pte_val(pte) & _PAGE_USER; }
+extern inline int pte_exec(pte_t pte)		{ return pte_val(pte) & _PAGE_USER; }
+extern inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
+extern inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
+extern inline int pte_write(pte_t pte)		{ return pte_val(pte) & _PAGE_RW; }
+
+extern inline pte_t pte_rdprotect(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; }
+extern inline pte_t pte_exprotect(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; }
+extern inline pte_t pte_mkclean(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
+extern inline pte_t pte_mkold(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED)); return pte; }
+extern inline pte_t pte_wrprotect(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_RW)); return pte; }
+extern inline pte_t pte_mkread(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_USER)); return pte; }
+extern inline pte_t pte_mkexec(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_USER)); return pte; }
+extern inline pte_t pte_mkdirty(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
+extern inline pte_t pte_mkyoung(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; }
+static inline  int ptep_test_and_clear_dirty(pte_t *ptep)	{ return test_and_clear_bit(_PAGE_BIT_DIRTY, ptep); }
+static inline  int ptep_test_and_clear_young(pte_t *ptep)	{ return test_and_clear_bit(_PAGE_BIT_ACCESSED, ptep); }
+static inline void ptep_set_wrprotect(pte_t *ptep)		{ clear_bit(_PAGE_BIT_RW, ptep); }
+static inline void ptep_mkdirty(pte_t *ptep)			{ set_bit(_PAGE_BIT_DIRTY, ptep); }
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+
+#define mk_pte(page,pgprot) 							 \
+({ 										 \
+	pte_t __pte; 								 \
+	unsigned long __val = page_to_phys(page);  			 \
+	__val |= pgprot_val(pgprot);						 \
+ 	set_pte(&__pte, __pte(__val));						 \
+ 	__pte;									 \
+}) 
+
+/* This takes a physical page address that is used by the remapping functions */
+static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
+{ 
+	pte_t __pte; 
+	set_pte(&__pte, __pte(physpage + pgprot_val(pgprot))); 
+	return __pte;
+}
+
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{ 
+	set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot))); 
+	return pte; 
+}
+
+#define page_pte(page) page_pte_prot(page, __pgprot(0))
+#define __pmd_page(pmd) (__va(pmd_val(pmd) & PHYSICAL_PAGE_MASK))
+
+/* to find an entry in a page-table-directory. */
+#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
+
+#define __pgd_offset_k(pgd, address) ((pgd) + pgd_index(address))
+
+#define current_pgd_offset_k(address) \
+	__pgd_offset_k((pgd_t *)read_pda(level4_pgt), address)
+
+/* This accesses the reference page table of the boot cpu. 
+   Other CPUs get synced lazily via the page fault handler. */
+#define pgd_offset_k(address) \
+	__pgd_offset_k( \
+       (pgd_t *)__va(pml4_val(init_level4_pgt[pml4_index(address)]) & PAGE_MASK), address)
+
+#define __pmd_offset(address) \
+		(((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
+
+/* Find an entry in the third-level page table.. */
+#define __pte_offset(address) \
+		((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset(dir, address) ((pte_t *) __pmd_page(*(dir)) + \
+			__pte_offset(address))
+
+/* never use these in the common code */
+#define pml4_page(level4) ((unsigned long) __va(pml4_val(level4) & PAGE_MASK))
+#define pml4_index(address) (((address) >> PML4_SHIFT) & (PTRS_PER_PML4-1))
+#define pml4_offset_k(address) ((pml4_t *)read_pda(level4_pgt) + pml4_index(address))
+#define level3_offset_k(dir, address) ((pgd_t *) pml4_page(*(dir)) + pgd_index(address))
+#define mk_kernel_pml4(address,prot) ((pml4_t){(address) | pgprot_val(prot)})
+
+
+/*
+ * x86 doesn't have any external MMU info: the kernel page
+ * tables contain all the necessary information.
+ */
+#define update_mmu_cache(vma,address,pte) do { } while (0)
+
+/* Encode and de-code a swap entry */
+#define SWP_TYPE(x)			(((x).val >> 1) & 0x3f)
+#define SWP_OFFSET(x)			((x).val >> 8)
+#define SWP_ENTRY(type, offset)		((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
+#define pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) })
+#define swp_entry_to_pte(x)		((pte_t) { (x).val })
+
+struct page;
+/* 
+ * Change attributes of an kernel page.
+ */
+struct page;
+extern int change_page_attr(struct page *page, int numpages, pgprot_t prot);
+
+/* 
+ * Map or remap large pages in the kernel mapping.
+ * Only valid during kernel initilization (__init) 
+ */
+extern void __map_kernel_range(void *, int, pgprot_t);
+#define map_kernel_range(adr,size) __map_kernel_range(adr,size,PAGE_KERNEL_LARGE)
+
+#endif /* !__ASSEMBLY__ */
+
+/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
+#define PageSkip(page)		(0)
+#define kern_addr_valid(kaddr)  ((kaddr)>>PAGE_SHIFT < max_mapnr)
+
+#define io_remap_page_range remap_page_range
+
+#define HAVE_ARCH_UNMAPPED_AREA
+
+#define pgtable_cache_init()   do { } while (0)
+
+
+#endif /* _X86_64_PGTABLE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/poll.h linux-2.4.20/include/asm-x86_64/poll.h
--- linux-2.4.19/include/asm-x86_64/poll.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/poll.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,25 @@
+#ifndef __x86_64_POLL_H
+#define __x86_64_POLL_H
+
+/* These are specified by iBCS2 */
+#define POLLIN		0x0001
+#define POLLPRI		0x0002
+#define POLLOUT		0x0004
+#define POLLERR		0x0008
+#define POLLHUP		0x0010
+#define POLLNVAL	0x0020
+
+/* The rest seem to be more-or-less nonstandard. Check them! */
+#define POLLRDNORM	0x0040
+#define POLLRDBAND	0x0080
+#define POLLWRNORM	0x0100
+#define POLLWRBAND	0x0200
+#define POLLMSG		0x0400
+
+struct pollfd {
+	int fd;
+	short events;
+	short revents;
+};
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/posix_types.h linux-2.4.20/include/asm-x86_64/posix_types.h
--- linux-2.4.19/include/asm-x86_64/posix_types.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/posix_types.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,116 @@
+#ifndef _ASM_X86_64_POSIX_TYPES_H
+#define _ASM_X86_64_POSIX_TYPES_H
+
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc.  Also, we cannot
+ * assume GCC is being used.
+ */
+
+typedef unsigned long	__kernel_dev_t;
+typedef unsigned long	__kernel_ino_t;
+typedef unsigned int	__kernel_mode_t;
+typedef unsigned long	__kernel_nlink_t;
+typedef long		__kernel_off_t;
+typedef int		__kernel_pid_t;
+typedef int		__kernel_ipc_pid_t;
+typedef unsigned int	__kernel_uid_t;
+typedef unsigned int	__kernel_gid_t;
+typedef unsigned long	__kernel_size_t;
+typedef long		__kernel_ssize_t;
+typedef long		__kernel_ptrdiff_t;
+typedef long		__kernel_time_t;
+typedef long		__kernel_suseconds_t;
+typedef long		__kernel_clock_t;
+typedef int		__kernel_daddr_t;
+typedef char *		__kernel_caddr_t;
+typedef unsigned short	__kernel_uid16_t;
+typedef unsigned short	__kernel_gid16_t;
+
+#ifdef __GNUC__
+typedef long long	__kernel_loff_t;
+#endif
+
+typedef struct {
+	int	val[2];
+} __kernel_fsid_t;
+
+typedef __kernel_uid_t __kernel_old_uid_t;
+typedef __kernel_gid_t __kernel_old_gid_t;
+typedef __kernel_uid_t __kernel_uid32_t;
+typedef __kernel_gid_t __kernel_gid32_t;
+
+#ifdef __KERNEL__
+
+#undef __FD_SET
+static __inline__ void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp)
+{
+	unsigned long _tmp = fd / __NFDBITS;
+	unsigned long _rem = fd % __NFDBITS;
+	fdsetp->fds_bits[_tmp] |= (1UL<<_rem);
+}
+
+#undef __FD_CLR
+static __inline__ void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp)
+{
+	unsigned long _tmp = fd / __NFDBITS;
+	unsigned long _rem = fd % __NFDBITS;
+	fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem);
+}
+
+#undef __FD_ISSET
+static __inline__ int __FD_ISSET(unsigned long fd, __const__ __kernel_fd_set *p)
+{
+	unsigned long _tmp = fd / __NFDBITS;
+	unsigned long _rem = fd % __NFDBITS;
+	return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0;
+}
+
+/*
+ * This will unroll the loop for the normal constant cases (8 or 32 longs,
+ * for 256 and 1024-bit fd_sets respectively)
+ */
+#undef __FD_ZERO
+static __inline__ void __FD_ZERO(__kernel_fd_set *p)
+{
+	unsigned long *tmp = p->fds_bits;
+	int i;
+
+	if (__builtin_constant_p(__FDSET_LONGS)) {
+		switch (__FDSET_LONGS) {
+			case 32:
+			  tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
+			  tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
+			  tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0;
+			  tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0;
+			  tmp[16] = 0; tmp[17] = 0; tmp[18] = 0; tmp[19] = 0;
+			  tmp[20] = 0; tmp[21] = 0; tmp[22] = 0; tmp[23] = 0;
+			  tmp[24] = 0; tmp[25] = 0; tmp[26] = 0; tmp[27] = 0;
+			  tmp[28] = 0; tmp[29] = 0; tmp[30] = 0; tmp[31] = 0;
+			  return;
+			case 16:
+			  tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
+			  tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
+			  tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0;
+			  tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0;
+			  return;
+			case 8:
+			  tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
+			  tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
+			  return;
+			case 4:
+			  tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
+			  return;
+		}
+	}
+	i = __FDSET_LONGS;
+	while (i) {
+		i--;
+		*tmp = 0;
+		tmp++;
+	}
+}
+
+#endif /* defined(__KERNEL__) */
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/prctl.h linux-2.4.20/include/asm-x86_64/prctl.h
--- linux-2.4.19/include/asm-x86_64/prctl.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/prctl.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,10 @@
+#ifndef X86_64_PRCTL_H
+#define X86_64_PRCTL_H 1
+
+#define ARCH_SET_GS 0x1001
+#define ARCH_SET_FS 0x1002
+#define ARCH_GET_FS 0x1003
+#define ARCH_GET_GS 0x1004
+
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/processor.h linux-2.4.20/include/asm-x86_64/processor.h
--- linux-2.4.19/include/asm-x86_64/processor.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/processor.h	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,408 @@
+/*
+ * include/asm-x86_64/processor.h
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ */
+
+#ifndef __ASM_X86_64_PROCESSOR_H
+#define __ASM_X86_64_PROCESSOR_H
+
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/types.h>
+#include <asm/sigcontext.h>
+#include <asm/cpufeature.h>
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <asm/msr.h>
+#include <asm/current.h>
+#include <asm/system.h>
+
+#define TF_MASK		0x00000100
+#define IF_MASK		0x00000200
+#define IOPL_MASK	0x00003000
+#define NT_MASK		0x00004000
+#define VM_MASK		0x00020000
+#define AC_MASK		0x00040000
+#define VIF_MASK	0x00080000	/* virtual interrupt flag */
+#define VIP_MASK	0x00100000	/* virtual interrupt pending */
+#define ID_MASK		0x00200000
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ void *pc; asm volatile("leaq 1f(%%rip),%0\n1:":"=r"(pc)); pc; })
+
+/*
+ *  CPU type and hardware bug flags. Kept separately for each CPU.
+ */
+
+struct cpuinfo_x86 {
+	__u8	x86;		/* CPU family */
+	__u8	x86_vendor;	/* CPU vendor */
+	__u8	x86_model;
+	__u8	x86_mask;
+	int	cpuid_level;	/* Maximum supported CPUID level, -1=no CPUID */
+	__u32	x86_capability[NCAPINTS];
+	char	x86_vendor_id[16];
+	char	x86_model_id[64];
+	int 	x86_cache_size;  /* in KB - valid for CPUS which support this
+				    call  */
+	int	x86_clflush_size;
+	int	x86_tlbsize;	/* number of 4K pages in DTLB/ITLB combined(in pages)*/
+	unsigned long loops_per_jiffy;
+} ____cacheline_aligned;
+
+#define X86_VENDOR_INTEL 0
+#define X86_VENDOR_CYRIX 1
+#define X86_VENDOR_AMD 2
+#define X86_VENDOR_UMC 3
+#define X86_VENDOR_NEXGEN 4
+#define X86_VENDOR_CENTAUR 5
+#define X86_VENDOR_RISE 6
+#define X86_VENDOR_TRANSMETA 7
+#define X86_VENDOR_UNKNOWN 0xff
+
+extern struct cpuinfo_x86 boot_cpu_data;
+extern struct tss_struct init_tss[NR_CPUS];
+
+#ifdef CONFIG_SMP
+extern struct cpuinfo_x86 cpu_data[];
+#define current_cpu_data cpu_data[smp_processor_id()]
+#else
+#define cpu_data (&boot_cpu_data)
+#define current_cpu_data boot_cpu_data
+#endif
+
+#define cpu_has_pge 1
+#define cpu_has_pse 1
+#define cpu_has_pae 1
+#define cpu_has_tsc 1
+#define cpu_has_de 1
+#define cpu_has_vme 1
+#define cpu_has_fxsr 1
+#define cpu_has_xmm 1
+#define cpu_has_apic 1
+
+extern char ignore_irq13;
+
+extern void identify_cpu(struct cpuinfo_x86 *);
+extern void print_cpu_info(struct cpuinfo_x86 *);
+extern void dodgy_tsc(void);
+
+/*
+ * EFLAGS bits
+ */
+#define X86_EFLAGS_CF	0x00000001 /* Carry Flag */
+#define X86_EFLAGS_PF	0x00000004 /* Parity Flag */
+#define X86_EFLAGS_AF	0x00000010 /* Auxillary carry Flag */
+#define X86_EFLAGS_ZF	0x00000040 /* Zero Flag */
+#define X86_EFLAGS_SF	0x00000080 /* Sign Flag */
+#define X86_EFLAGS_TF	0x00000100 /* Trap Flag */
+#define X86_EFLAGS_IF	0x00000200 /* Interrupt Flag */
+#define X86_EFLAGS_DF	0x00000400 /* Direction Flag */
+#define X86_EFLAGS_OF	0x00000800 /* Overflow Flag */
+#define X86_EFLAGS_IOPL	0x00003000 /* IOPL mask */
+#define X86_EFLAGS_NT	0x00004000 /* Nested Task */
+#define X86_EFLAGS_RF	0x00010000 /* Resume Flag */
+#define X86_EFLAGS_VM	0x00020000 /* Virtual Mode */
+#define X86_EFLAGS_AC	0x00040000 /* Alignment Check */
+#define X86_EFLAGS_VIF	0x00080000 /* Virtual Interrupt Flag */
+#define X86_EFLAGS_VIP	0x00100000 /* Virtual Interrupt Pending */
+#define X86_EFLAGS_ID	0x00200000 /* CPUID detection flag */
+
+/*
+ *	Generic CPUID function
+ * 	FIXME: This really belongs to msr.h
+ */
+extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
+{
+	__asm__("cpuid"
+		: "=a" (*eax),
+		  "=b" (*ebx),
+		  "=c" (*ecx),
+		  "=d" (*edx)
+		: "0" (op));
+}
+
+/*
+ * CPUID functions returning a single datum
+ */
+extern inline unsigned int cpuid_eax(unsigned int op)
+{
+	unsigned int eax;
+
+	__asm__("cpuid"
+		: "=a" (eax)
+		: "0" (op)
+		: "bx", "cx", "dx");
+	return eax;
+}
+extern inline unsigned int cpuid_ebx(unsigned int op)
+{
+	unsigned int eax, ebx;
+
+	__asm__("cpuid"
+		: "=a" (eax), "=b" (ebx)
+		: "0" (op)
+		: "cx", "dx" );
+	return ebx;
+}
+extern inline unsigned int cpuid_ecx(unsigned int op)
+{
+	unsigned int eax, ecx;
+
+	__asm__("cpuid"
+		: "=a" (eax), "=c" (ecx)
+		: "0" (op)
+		: "bx", "dx" );
+	return ecx;
+}
+extern inline unsigned int cpuid_edx(unsigned int op)
+{
+	unsigned int eax, edx;
+
+	__asm__("cpuid"
+		: "=a" (eax), "=d" (edx)
+		: "0" (op)
+		: "bx", "cx");
+	return edx;
+}
+
+/*
+ * Intel CPU features in CR4
+ */
+#define X86_CR4_VME		0x0001	/* enable vm86 extensions */
+#define X86_CR4_PVI		0x0002	/* virtual interrupts flag enable */
+#define X86_CR4_TSD		0x0004	/* disable time stamp at ipl 3 */
+#define X86_CR4_DE		0x0008	/* enable debugging extensions */
+#define X86_CR4_PSE		0x0010	/* enable page size extensions */
+#define X86_CR4_PAE		0x0020	/* enable physical address extensions */
+#define X86_CR4_MCE		0x0040	/* Machine check enable */
+#define X86_CR4_PGE		0x0080	/* enable global pages */
+#define X86_CR4_PCE		0x0100	/* enable performance counters at ipl 3 */
+#define X86_CR4_OSFXSR		0x0200	/* enable fast FPU save and restore */
+#define X86_CR4_OSXMMEXCPT	0x0400	/* enable unmasked SSE exceptions */
+
+/*
+ * Save the cr4 feature set we're using (ie
+ * Pentium 4MB enable and PPro Global page
+ * enable), so that any CPU's that boot up
+ * after us can get the correct flags.
+ */
+extern unsigned long mmu_cr4_features;
+
+static inline void set_in_cr4 (unsigned long mask)
+{
+	mmu_cr4_features |= mask;
+	__asm__("movq %%cr4,%%rax\n\t"
+		"orq %0,%%rax\n\t"
+		"movq %%rax,%%cr4\n"
+		: : "irg" (mask)
+		:"ax");
+}
+
+static inline void clear_in_cr4 (unsigned long mask)
+{
+	mmu_cr4_features &= ~mask;
+	__asm__("movq %%cr4,%%rax\n\t"
+		"andq %0,%%rax\n\t"
+		"movq %%rax,%%cr4\n"
+		: : "irg" (~mask)
+		:"ax");
+}
+
+/*
+ *      Cyrix CPU configuration register indexes
+ */
+#define CX86_CCR0 0xc0
+#define CX86_CCR1 0xc1
+#define CX86_CCR2 0xc2
+#define CX86_CCR3 0xc3
+#define CX86_CCR4 0xe8
+#define CX86_CCR5 0xe9
+#define CX86_CCR6 0xea
+#define CX86_CCR7 0xeb
+#define CX86_DIR0 0xfe
+#define CX86_DIR1 0xff
+#define CX86_ARR_BASE 0xc4
+#define CX86_RCR_BASE 0xdc
+
+/*
+ *      Cyrix CPU indexed register access macros
+ */
+
+#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
+
+#define setCx86(reg, data) do { \
+	outb((reg), 0x22); \
+	outb((data), 0x23); \
+} while (0)
+
+/*
+ * Bus types
+ */
+#define EISA_bus 0
+#define MCA_bus 0
+#define MCA_bus__is_a_macro
+
+
+/*
+ * User space process size: 512GB - 1GB (default).
+ */
+#define TASK_SIZE	(0x0000007fc0000000)
+
+/* This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_32 0x40000000
+#define TASK_UNMAPPED_64 (TASK_SIZE/3) 
+#define TASK_UNMAPPED_BASE	\
+	((current->thread.flags & THREAD_IA32) ? TASK_UNMAPPED_32 : TASK_UNMAPPED_64)  
+
+/*
+ * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
+ */
+#define IO_BITMAP_SIZE	32
+#define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap)
+#define INVALID_IO_BITMAP_OFFSET 0x8000
+
+struct i387_fxsave_struct {
+	u16	cwd;
+	u16	swd;
+	u16	twd;
+	u16	fop;
+	u64	rip;
+	u64	rdp; 
+	u32	mxcsr;
+	u32	mxcsr_mask;
+	u32	st_space[32];	/* 8*16 bytes for each FP-reg = 128 bytes */
+	u32	xmm_space[64];	/* 16*16 bytes for each XMM-reg = 128 bytes */
+	u32	padding[24];
+} __attribute__ ((aligned (16)));
+
+union i387_union {
+	struct i387_fxsave_struct	fxsave;
+};
+
+typedef struct {
+	unsigned long seg;
+} mm_segment_t;
+
+struct tss_struct {
+	u32 reserved1;
+	u64 rsp0;	
+	u64 rsp1;
+	u64 rsp2;
+	u64 reserved2;
+	u64 ist[7];
+	u32 reserved3;
+	u32 reserved4;
+	u16 reserved5;
+	u16 io_map_base;
+	u32 io_bitmap[IO_BITMAP_SIZE];
+} __attribute__((packed));
+
+struct thread_struct {
+	unsigned long	rsp0;
+	unsigned long	rip;
+	unsigned long	rsp;
+	unsigned long 	userrsp;	/* Copy from PDA */ 
+	unsigned long	fs;
+	unsigned long	gs;
+	unsigned short	es, ds, fsindex, gsindex;	
+	enum { 
+		THREAD_IA32 = 0x0001,
+	} flags;
+/* Hardware debugging registers */
+	unsigned long	debugreg[8];  /* %%db0-7 debug registers */
+/* fault info */
+	unsigned long	cr2, trap_no, error_code;
+/* floating point info */
+	union i387_union	i387;
+	u32	*io_bitmap_ptr;
+};
+
+#define INIT_THREAD  {						\
+}
+
+#define INIT_MMAP \
+{ &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
+
+#define STACKFAULT_STACK 1
+#define DOUBLEFAULT_STACK 2 
+#define NMI_STACK 3 
+#define N_EXCEPTION_STACKS 3  /* hw limit: 7 */
+#define EXCEPTION_STKSZ 1024
+
+#define start_thread(regs,new_rip,new_rsp) do { \
+	__asm__("movl %0,%%fs; movl %0,%%es; movl %0,%%ds": :"r" (0));		 \
+	wrmsrl(MSR_KERNEL_GS_BASE, 0);						 \
+	(regs)->rip = (new_rip);						 \
+	(regs)->rsp = (new_rsp);						 \
+	write_pda(oldrsp, (new_rsp));						 \
+	(regs)->cs = __USER_CS;							 \
+	(regs)->ss = __USER_DS;							 \
+	(regs)->eflags = 0x200;							 \
+	set_fs(USER_DS);							 \
+} while(0) 
+
+struct task_struct;
+struct mm_struct;
+
+/* Free all resources held by a thread. */
+extern void release_thread(struct task_struct *);
+/*
+ * create a kernel thread without removing it from tasklists
+ */
+extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+
+/* Copy and release all segment info associated with a VM */
+extern void copy_segments(struct task_struct *p, struct mm_struct * mm);
+extern void release_segments(struct mm_struct * mm);
+
+/*
+ * Return saved PC of a blocked thread.
+ * What is this good for? it will be always the scheduler or ret_from_fork.
+ */
+
+extern inline unsigned long thread_saved_pc(struct thread_struct *t)
+{ 
+	return *(unsigned long *)(t->rsp - 8);
+} 
+
+extern unsigned long get_wchan(struct task_struct *p);
+#define KSTK_EIP(tsk) \
+	(((struct pt_regs *)(tsk->thread.rsp0 - sizeof(struct pt_regs)))->rip)
+#define KSTK_ESP(tsk) -1 /* sorry. doesn't work for syscall. */
+
+/* Note: most of the infrastructure to separate stack and task_struct
+   are already there. When you run out of stack try this first. */
+#define alloc_task_struct() \
+	((struct task_struct *) __get_free_pages(GFP_KERNEL,THREAD_ORDER))
+#define free_task_struct(p) free_pages((unsigned long) (p), 1)
+#define get_task_struct(tsk)      atomic_inc(&virt_to_page(tsk)->count)
+
+#define init_task	(init_task_union.task)
+#define init_stack	(init_task_union.stack)
+
+/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
+extern inline void rep_nop(void)
+{
+	__asm__ __volatile__("rep;nop");
+}
+
+#define cpu_has_fpu 1
+
+#define ARCH_HAS_PREFETCH
+#define ARCH_HAS_PREFETCHW
+#define ARCH_HAS_SPINLOCK_PREFETCH
+
+#define prefetch(x) __builtin_prefetch((x),0)
+#define prefetchw(x) __builtin_prefetch((x),1)
+#define spin_lock_prefetch(x)  prefetchw(x)
+#define cpu_relax()   rep_nop()
+
+
+#endif /* __ASM_X86_64_PROCESSOR_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/proto.h linux-2.4.20/include/asm-x86_64/proto.h
--- linux-2.4.19/include/asm-x86_64/proto.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/proto.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,44 @@
+#ifndef _ASM_X8664_PROTO_H
+#define _ASM_X8664_PROTO_H 1
+
+/* misc architecture specific prototypes */
+
+struct cpuinfo_x86; 
+
+extern void get_cpu_vendor(struct cpuinfo_x86*);
+extern void start_kernel(void);
+extern void pda_init(int); 
+
+extern void mcheck_init(struct cpuinfo_x86 *c);
+extern void init_memory_mapping(void);
+
+extern void system_call(void); 
+extern void ia32_cstar_target(void); 
+extern void calibrate_delay(void);
+extern void cpu_idle(void);
+extern void sys_ni_syscall(void);
+extern void config_acpi_tables(void);
+extern void ia32_syscall(void);
+extern void iommu_hole_init(void);
+
+extern void do_softirq_thunk(void);
+
+extern int setup_early_printk(char *); 
+extern void early_printk(const char *fmt, ...) __attribute__((format(printf,1,2)));
+
+extern int k8_scan_nodes(unsigned long start, unsigned long end);
+
+extern int numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn);
+extern unsigned long numa_free_all_bootmem(void);
+
+extern void reserve_bootmem_generic(unsigned long phys, unsigned len);
+extern void free_bootmem_generic(unsigned long phys, unsigned len);
+
+extern unsigned long start_pfn, end_pfn; 
+
+extern void show_stack(unsigned long * rsp);
+
+#define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))
+#define round_down(x,y) ((x) & ~((y)-1))
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/ptrace.h linux-2.4.20/include/asm-x86_64/ptrace.h
--- linux-2.4.19/include/asm-x86_64/ptrace.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/ptrace.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,114 @@
+#ifndef _X86_64_PTRACE_H
+#define _X86_64_PTRACE_H
+
+#if defined(__ASSEMBLY__) || defined(__FRAME_OFFSETS) 
+#define R15 0
+#define R14 8
+#define R13 16
+#define R12 24
+#define RBP 36
+#define RBX 40
+/* arguments: interrupts/non tracing syscalls only save upto here*/
+#define R11 48
+#define R10 56	
+#define R9 64
+#define R8 72
+#define RAX 80
+#define RCX 88
+#define RDX 96
+#define RSI 104
+#define RDI 112
+#define ORIG_RAX 120       /* = ERROR */ 
+/* end of arguments */ 	
+/* cpu exception frame or undefined in case of fast syscall. */
+#define RIP 128
+#define CS 136
+#define EFLAGS 144
+#define RSP 152
+#define SS 160
+#define ARGOFFSET R11
+#endif /* __ASSEMBLY__ */
+
+/* top of stack page */ 
+#define FRAME_SIZE 168
+
+#define PTRACE_SETOPTIONS         21
+
+/* options set using PTRACE_SETOPTIONS */
+#define PTRACE_O_TRACESYSGOOD     0x00000001
+
+/* Dummy values for ptrace */ 
+#define FS 1000 
+#define GS 1008
+
+#ifndef __ASSEMBLY__ 
+
+struct pt_regs {
+	unsigned long r15;
+	unsigned long r14;
+	unsigned long r13;
+	unsigned long r12;
+	unsigned long rbp;
+	unsigned long rbx;
+/* arguments: non interrupts/non tracing syscalls only save upto here*/
+ 	unsigned long r11;
+	unsigned long r10;	
+	unsigned long r9;
+	unsigned long r8;
+	unsigned long rax;
+	unsigned long rcx;
+	unsigned long rdx;
+	unsigned long rsi;
+	unsigned long rdi;
+	unsigned long orig_rax;
+/* end of arguments */ 	
+/* cpu exception frame or undefined */
+	unsigned long rip;
+	unsigned long cs;
+	unsigned long eflags; 
+	unsigned long rsp; 
+	unsigned long ss;
+/* top of stack page */ 
+};
+
+#endif
+
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETREGS            12
+#define PTRACE_SETREGS            13
+#define PTRACE_GETFPREGS          14
+#define PTRACE_SETFPREGS          15
+#define PTRACE_GETFPXREGS         18
+#define PTRACE_SETFPXREGS         19
+
+#if defined(__KERNEL__) && !defined(__ASSEMBLY__) 
+#define user_mode(regs) (!!((regs)->cs & 3))
+#define instruction_pointer(regs) ((regs)->rip)
+extern void show_regs(struct pt_regs *);
+
+enum {
+        EF_CF   = 0x00000001,
+        EF_PF   = 0x00000004,
+        EF_AF   = 0x00000010,
+        EF_ZF   = 0x00000040,
+        EF_SF   = 0x00000080,
+        EF_TF   = 0x00000100,
+        EF_IE   = 0x00000200,
+        EF_DF   = 0x00000400,
+        EF_OF   = 0x00000800,
+        EF_IOPL = 0x00003000,
+        EF_IOPL_RING0 = 0x00000000,
+        EF_IOPL_RING1 = 0x00001000,
+        EF_IOPL_RING2 = 0x00002000,
+        EF_NT   = 0x00004000,   /* nested task */
+        EF_RF   = 0x00010000,   /* resume */
+        EF_VM   = 0x00020000,   /* virtual mode */
+        EF_AC   = 0x00040000,   /* alignment */
+        EF_VIF  = 0x00080000,   /* virtual interrupt */
+        EF_VIP  = 0x00100000,   /* virtual interrupt pending */
+        EF_ID   = 0x00200000,   /* id */
+};
+
+#endif
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/resource.h linux-2.4.20/include/asm-x86_64/resource.h
--- linux-2.4.19/include/asm-x86_64/resource.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/resource.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,47 @@
+#ifndef _X8664_RESOURCE_H
+#define _X8664_RESOURCE_H
+
+/*
+ * Resource limits
+ */
+
+#define RLIMIT_CPU	0		/* CPU time in ms */
+#define RLIMIT_FSIZE	1		/* Maximum filesize */
+#define RLIMIT_DATA	2		/* max data size */
+#define RLIMIT_STACK	3		/* max stack size */
+#define RLIMIT_CORE	4		/* max core file size */
+#define RLIMIT_RSS	5		/* max resident set size */
+#define RLIMIT_NPROC	6		/* max number of processes */
+#define RLIMIT_NOFILE	7		/* max number of open files */
+#define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
+#define RLIMIT_AS	9		/* address space limit */
+#define RLIMIT_LOCKS	10		/* maximum file locks held */
+
+#define RLIM_NLIMITS	11
+
+/*
+ * SuS says limits have to be unsigned.
+ * Which makes a ton more sense anyway.
+ */
+#define RLIM_INFINITY	(~0UL)
+
+#ifdef __KERNEL__
+
+#define INIT_RLIMITS					\
+{							\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{      _STK_LIM, RLIM_INFINITY },		\
+	{             0, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{             0,             0 },		\
+	{      INR_OPEN,     INR_OPEN  },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+        { RLIM_INFINITY, RLIM_INFINITY },		\
+}
+
+#endif /* __KERNEL__ */
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/rwlock.h linux-2.4.20/include/asm-x86_64/rwlock.h
--- linux-2.4.19/include/asm-x86_64/rwlock.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/rwlock.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,86 @@
+/* include/asm-x86_64/rwlock.h
+ *
+ *	Helpers used by both rw spinlocks and rw semaphores.
+ *
+ *	Based in part on code from semaphore.h and
+ *	spinlock.h Copyright 1996 Linus Torvalds.
+ *
+ *	Copyright 1999 Red Hat, Inc.
+ *	Copyright 2001,2002 SuSE labs 
+ *
+ *	Written by Benjamin LaHaise.
+ *
+ *	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.
+ */
+#ifndef _ASM_X86_64_RWLOCK_H
+#define _ASM_X86_64_RWLOCK_H
+
+#include <linux/stringify.h>
+
+#define RW_LOCK_BIAS		 0x01000000
+#define RW_LOCK_BIAS_STR	"0x01000000"
+
+#define __build_read_lock_ptr(rw, helper)   \
+	asm volatile(LOCK "subl $1,(%0)\n\t" \
+		     "js 2f\n" \
+		     "1:\n" \
+		    LOCK_SECTION_START("") \
+		     "2:\tcall " helper "\n\t" \
+		     "jmp 1b\n" \
+		    LOCK_SECTION_END \
+		     ::"a" (rw) : "memory")
+
+#define __build_read_lock_const(rw, helper)   \
+	asm volatile(LOCK "subl $1,%0\n\t" \
+		     "js 2f\n" \
+		     "1:\n" \
+		    LOCK_SECTION_START("") \
+		     "2:\tpushq %%rax\n\t" \
+		     "leaq %0,%%rax\n\t" \
+		     "call " helper "\n\t" \
+		     "popq %%rax\n\t" \
+		     "jmp 1b\n" \
+		    LOCK_SECTION_END \
+		     :"=m" (*((volatile int *)rw))::"memory")
+
+#define __build_read_lock(rw, helper)	do { \
+						if (__builtin_constant_p(rw)) \
+							__build_read_lock_const(rw, helper); \
+						else \
+							__build_read_lock_ptr(rw, helper); \
+					} while (0)
+
+#define __build_write_lock_ptr(rw, helper) \
+	asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
+		     "jnz 2f\n" \
+		     "1:\n" \
+		     LOCK_SECTION_START("") \
+		     "2:\tcall " helper "\n\t" \
+		     "jmp 1b\n" \
+		     LOCK_SECTION_END \
+		     ::"a" (rw) : "memory")
+
+#define __build_write_lock_const(rw, helper) \
+	asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
+		     "jnz 2f\n" \
+		     "1:\n" \
+		    LOCK_SECTION_START("") \
+		     "2:\tpushq %%rax\n\t" \
+		     "leaq %0,%%rax\n\t" \
+		     "call " helper "\n\t" \
+		     "popq %%rax\n\t" \
+		     "jmp 1b\n" \
+		    LOCK_SECTION_END \
+		     :"=m" (*((volatile long *)rw))::"memory")
+
+#define __build_write_lock(rw, helper)	do { \
+						if (__builtin_constant_p(rw)) \
+							__build_write_lock_const(rw, helper); \
+						else \
+							__build_write_lock_ptr(rw, helper); \
+					} while (0)
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/rwsem.h linux-2.4.20/include/asm-x86_64/rwsem.h
--- linux-2.4.19/include/asm-x86_64/rwsem.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/rwsem.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,255 @@
+/* rwsem.h: R/W semaphores implemented using XADD/CMPXCHG for x86_64+
+ *
+ * Written by David Howells (dhowells@redhat.com).
+ * Ported by Andi Kleen <ak@suse.de> to x86-64.
+ *
+ * Derived from asm-i386/semaphore.h and asm-i386/rwsem.h
+ *
+ * Trylock by Brian Watson (Brian.J.Watson@compaq.com).
+ *
+ * The MSW of the count is the negated number of active writers and waiting
+ * lockers, and the LSW is the total number of active locks
+ *
+ * The lock count is initialized to 0 (no active and no waiting lockers).
+ *
+ * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an
+ * uncontended lock. This can be determined because XADD returns the old value.
+ * Readers increment by 1 and see a positive value when uncontended, negative
+ * if there are writers (and maybe) readers waiting (in which case it goes to
+ * sleep).
+ *
+ * The value of WAITING_BIAS supports up to 32766 waiting processes. This can
+ * be extended to 65534 by manually checking the whole MSW rather than relying
+ * on the S flag.
+ *
+ * The value of ACTIVE_BIAS supports up to 65535 active processes.
+ *
+ * This should be totally fair - if anything is waiting, a process that wants a
+ * lock will go to the back of the queue. When the currently active lock is
+ * released, if there's a writer at the front of the queue, then that and only
+ * that will be woken up; if there's a bunch of consequtive readers at the
+ * front, then they'll all be woken up, but no other readers will be.
+ */
+
+#ifndef _X8664_RWSEM_H
+#define _X8664_RWSEM_H
+
+#ifndef _LINUX_RWSEM_H
+#error please dont include asm/rwsem.h directly, use linux/rwsem.h instead
+#endif
+
+#ifdef __KERNEL__
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+struct rwsem_waiter;
+
+extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
+
+/*
+ * the semaphore definition
+ */
+struct rw_semaphore {
+	signed int		count;
+#define RWSEM_UNLOCKED_VALUE		0x00000000
+#define RWSEM_ACTIVE_BIAS		0x00000001
+#define RWSEM_ACTIVE_MASK		0x0000ffff
+#define RWSEM_WAITING_BIAS		(-0x00010000)
+#define RWSEM_ACTIVE_READ_BIAS		RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS		(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+	spinlock_t		wait_lock;
+	struct list_head	wait_list;
+#if RWSEM_DEBUG
+	int			debug;
+#endif
+};
+
+/*
+ * initialisation
+ */
+#if RWSEM_DEBUG
+#define __RWSEM_DEBUG_INIT      , 0
+#else
+#define __RWSEM_DEBUG_INIT	/* */
+#endif
+
+#define __RWSEM_INITIALIZER(name) \
+{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \
+	__RWSEM_DEBUG_INIT }
+
+#define DECLARE_RWSEM(name) \
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+static inline void init_rwsem(struct rw_semaphore *sem)
+{
+	sem->count = RWSEM_UNLOCKED_VALUE;
+	spin_lock_init(&sem->wait_lock);
+	INIT_LIST_HEAD(&sem->wait_list);
+#if RWSEM_DEBUG
+	sem->debug = 0;
+#endif
+}
+
+/*
+ * lock for reading
+ */
+static inline void __down_read(struct rw_semaphore *sem)
+{
+	__asm__ __volatile__(
+		"# beginning down_read\n\t"
+LOCK_PREFIX	"  incl      (%%rdi)\n\t" /* adds 0x00000001, returns the old value */
+		"  js        2f\n\t" /* jump if we weren't granted the lock */
+		"1:\n\t"
+		LOCK_SECTION_START("") \
+		"2:\n\t"
+		"  call      rwsem_down_read_failed_thunk\n\t"
+		"  jmp       1b\n"
+		LOCK_SECTION_END \
+		"# ending down_read\n\t"
+		: "+m"(sem->count)
+		: "D"(sem)
+		: "memory", "cc");
+}
+
+
+/*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	__s32 result, tmp;
+	__asm__ __volatile__(
+		"# beginning __down_read_trylock\n\t"
+		"  movl      %0,%1\n\t"
+		"1:\n\t"
+		"  movl	     %1,%2\n\t"
+		"  addl      %3,%2\n\t"
+		"  jle	     2f\n\t"
+LOCK_PREFIX	"  cmpxchgl  %2,%0\n\t"
+		"  jnz	     1b\n\t"
+		"2:\n\t"
+		"# ending __down_read_trylock\n\t"
+		: "+m"(sem->count), "=&a"(result), "=&r"(tmp)
+		: "i"(RWSEM_ACTIVE_READ_BIAS)
+		: "memory", "cc");
+	return result>=0 ? 1 : 0;
+}
+
+/*
+ * lock for writing
+ */
+static inline void __down_write(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	tmp = RWSEM_ACTIVE_WRITE_BIAS;
+	__asm__ __volatile__(
+		"# beginning down_write\n\t"
+LOCK_PREFIX	"  xaddl      %0,(%%rdi)\n\t" /* subtract 0x0000ffff, returns the old value */
+		"  testl     %0,%0\n\t" /* was the count 0 before? */
+		"  jnz       2f\n\t" /* jump if we weren't granted the lock */
+		"1:\n\t"
+		LOCK_SECTION_START("")
+		"2:\n\t"
+		"  call      rwsem_down_write_failed_thunk\n\t"
+		"  jmp       1b\n"
+		LOCK_SECTION_END
+		"# ending down_write"
+		: "=&r" (tmp) 
+		: "0"(tmp), "D"(sem)
+		: "memory", "cc");
+}
+
+/*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	signed long ret = cmpxchg(&sem->count,
+				  RWSEM_UNLOCKED_VALUE, 
+				  RWSEM_ACTIVE_WRITE_BIAS);
+	if (ret == RWSEM_UNLOCKED_VALUE)
+		return 1;
+	return 0;
+}
+
+/*
+ * unlock after reading
+ */
+static inline void __up_read(struct rw_semaphore *sem)
+{
+	__s32 tmp = -RWSEM_ACTIVE_READ_BIAS;
+	__asm__ __volatile__(
+		"# beginning __up_read\n\t"
+LOCK_PREFIX	"  xaddl      %%edx,(%%rdi)\n\t" /* subtracts 1, returns the old value */
+		"  js        2f\n\t" /* jump if the lock is being waited upon */
+		"1:\n\t"
+		LOCK_SECTION_START("")
+		"2:\n\t"
+		"  decw      %%dx\n\t" /* do nothing if still outstanding active readers */
+		"  jnz       1b\n\t"
+		"  call      rwsem_wake_thunk\n\t"
+		"  jmp       1b\n"
+		LOCK_SECTION_END
+		"# ending __up_read\n"
+		: "+m"(sem->count), "+d"(tmp)
+		: "D"(sem)
+		: "memory", "cc");
+}
+
+/*
+ * unlock after writing
+ */
+static inline void __up_write(struct rw_semaphore *sem)
+{
+	__asm__ __volatile__(
+		"# beginning __up_write\n\t"
+		"  movl      %2,%%edx\n\t"
+LOCK_PREFIX	"  xaddl     %%edx,(%%rdi)\n\t" /* tries to transition 0xffff0001 -> 0x00000000 */
+		"  jnz       2f\n\t" /* jump if the lock is being waited upon */
+		"1:\n\t"
+		LOCK_SECTION_START("")
+		"2:\n\t"
+		"  decw      %%dx\n\t" /* did the active count reduce to 0? */
+		"  jnz       1b\n\t" /* jump back if not */
+		"  call      rwsem_wake_thunk\n\t"
+		"  jmp       1b\n"
+		LOCK_SECTION_END
+		"# ending __up_write\n"
+		: "+m"(sem->count)
+		: "D"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS)
+		: "memory", "cc", "rdx");
+}
+
+/*
+ * implement atomic add functionality
+ */
+static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
+{
+	__asm__ __volatile__(
+LOCK_PREFIX	"addl %1,%0"
+		:"=m"(sem->count)
+		:"ir"(delta), "m"(sem->count));
+}
+
+/*
+ * implement exchange and add functionality
+ */
+static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
+{
+	int tmp = delta;
+
+	__asm__ __volatile__(
+LOCK_PREFIX	"xaddl %0,(%2)"
+		: "=r"(tmp), "=m"(sem->count)
+		: "r"(sem), "m"(sem->count), "0" (tmp)
+		: "memory");
+
+	return tmp+delta;
+}
+
+#endif /* __KERNEL__ */
+#endif /* _X8664_RWSEM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/scatterlist.h linux-2.4.20/include/asm-x86_64/scatterlist.h
--- linux-2.4.19/include/asm-x86_64/scatterlist.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/scatterlist.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,34 @@
+#ifndef _X8664_SCATTERLIST_H
+#define _X8664_SCATTERLIST_H
+
+/*
+ * Drivers must set either ->address or (preferred) ->page and ->offset
+ * to indicate where data must be transferred to/from.
+ *
+ * Using ->page is recommended since it handles highmem data as well as
+ * low mem. ->address is restricted to data which has a virtual mapping, and
+ * it will go away in the future. Updating to ->page can be automated very
+ * easily -- something like
+ *
+ * sg->address = some_ptr;
+ *
+ * can be rewritten as
+ *
+ * sg->page = virt_to_page(some_ptr);
+ * sg->offset = (unsigned long) some_ptr & ~PAGE_MASK;
+ *
+ * and that's it. There's no excuse for not highmem enabling YOUR driver. /jens
+ */
+struct scatterlist {
+    char *  address;    /* Location data is to be transferred to, NULL for
+			 * highmem page */
+    struct page * page; /* Location for highmem page, if any */
+    unsigned int offset;/* for highmem, page offset */
+
+    dma_addr_t dma_address;
+    unsigned int length;
+};
+
+#define ISA_DMA_THRESHOLD (0x00ffffff)
+
+#endif 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/segment.h linux-2.4.20/include/asm-x86_64/segment.h
--- linux-2.4.19/include/asm-x86_64/segment.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/segment.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,21 @@
+#ifndef _ASM_SEGMENT_H
+#define _ASM_SEGMENT_H
+
+#define __KERNEL_CS	0x10
+#define __KERNEL_DS	0x18
+
+#define __KERNEL32_CS   0x38
+
+/* 
+ * we cannot use the same code segment descriptor for user and kernel
+ * even not in the long flat model, because of different DPL /kkeil 
+ * The segment offset needs to contain a RPL. Grr. -AK
+ * GDT layout to get 64bit syscall right (sysret hardcodes gdt offsets) 
+ */
+
+#define __USER32_CS   0x23   /* 4*8+3 */ 
+#define __USER_DS     0x2b   /* 5*8+3 */ 
+#define __USER_CS     0x33   /* 6*8+3 */ 
+#define __USER32_DS	__USER_DS 
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/semaphore.h linux-2.4.20/include/asm-x86_64/semaphore.h
--- linux-2.4.19/include/asm-x86_64/semaphore.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/semaphore.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,235 @@
+#ifndef _X86_64_SEMAPHORE_H
+#define _X86_64_SEMAPHORE_H
+
+#include <linux/linkage.h>
+
+#ifdef __KERNEL__
+
+/*
+ * SMP- and interrupt-safe semaphores..
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ *
+ * Modified 1996-12-23 by Dave Grothe <dave@gcom.com> to fix bugs in
+ *                     the original code and to make semaphore waits
+ *                     interruptible so that processes waiting on
+ *                     semaphores can be killed.
+ * Modified 1999-02-14 by Andrea Arcangeli, split the sched.c helper
+ *		       functions in asm/sempahore-helper.h while fixing a
+ *		       potential and subtle race discovered by Ulrich Schmid
+ *		       in down_interruptible(). Since I started to play here I
+ *		       also implemented the `trylock' semaphore operation.
+ *          1999-07-02 Artur Skawina <skawina@geocities.com>
+ *                     Optimized "0(ecx)" -> "(ecx)" (the assembler does not
+ *                     do this). Changed calling sequences from push/jmp to
+ *                     traditional call/ret.
+ * Modified 2001-01-01 Andreas Franck <afranck@gmx.de>
+ *		       Some hacks to ensure compatibility with recent
+ *		       GCC snapshots, to avoid stack corruption when compiling
+ *		       with -fomit-frame-pointer. It's not sure if this will
+ *		       be fixed in GCC, as our previous implementation was a
+ *		       bit dubious.
+ *
+ * If you would like to see an analysis of this implementation, please
+ * ftp to gcom.com and download the file
+ * /pub/linux/src/semaphore/semaphore-2.0.24.tar.gz.
+ *
+ */
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/rwlock.h>
+#include <linux/wait.h>
+#include <linux/rwsem.h>
+#include <linux/stringify.h>
+
+struct semaphore {
+	atomic_t count;
+	int sleepers;
+	wait_queue_head_t wait;
+#if WAITQUEUE_DEBUG
+	long __magic;
+#endif
+};
+
+#if WAITQUEUE_DEBUG
+# define __SEM_DEBUG_INIT(name) \
+		, (int)&(name).__magic
+#else
+# define __SEM_DEBUG_INIT(name)
+#endif
+
+#define __SEMAPHORE_INITIALIZER(name,count) \
+{ ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
+	__SEM_DEBUG_INIT(name) }
+
+#define __MUTEX_INITIALIZER(name) \
+	__SEMAPHORE_INITIALIZER(name,1)
+
+#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
+	struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
+
+#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
+#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
+
+static inline void sema_init (struct semaphore *sem, int val)
+{
+/*
+ *	*sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
+ *
+ * i'd rather use the more flexible initialization above, but sadly
+ * GCC 2.7.2.3 emits a bogus warning. EGCS doesnt. Oh well.
+ */
+	atomic_set(&sem->count, val);
+	sem->sleepers = 0;
+	init_waitqueue_head(&sem->wait);
+#if WAITQUEUE_DEBUG
+	sem->__magic = (int)&sem->__magic;
+#endif
+}
+
+static inline void init_MUTEX (struct semaphore *sem)
+{
+	sema_init(sem, 1);
+}
+
+static inline void init_MUTEX_LOCKED (struct semaphore *sem)
+{
+	sema_init(sem, 0);
+}
+
+asmlinkage void __down_failed(void /* special register calling convention */);
+asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
+asmlinkage int  __down_failed_trylock(void  /* params in registers */);
+asmlinkage void __up_wakeup(void /* special register calling convention */);
+
+asmlinkage void __down(struct semaphore * sem);
+asmlinkage int  __down_interruptible(struct semaphore * sem);
+asmlinkage int  __down_trylock(struct semaphore * sem);
+asmlinkage void __up(struct semaphore * sem);
+
+/*
+ * This is ugly, but we want the default case to fall through.
+ * "__down_failed" is a special asm handler that calls the C
+ * routine that actually waits. See arch/x86_64/kernel/semaphore.c
+ */
+static inline void down(struct semaphore * sem)
+{
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+
+	__asm__ __volatile__(
+		"# atomic down operation\n\t"
+		LOCK "decl %0\n\t"     /* --sem->count */
+		"js 2f\n"
+		"1:\n"
+                ".subsection 1\n" \
+                ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
+                "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
+                ".endif\n" \
+		"2:\tcall __down_failed\n\t"
+		"jmp 1b\n"
+		".subsection 0"
+		:"=m" (sem->count)
+		:"D" (sem)
+		:"memory");
+}
+
+/*
+ * Interruptible try to acquire a semaphore.  If we obtained
+ * it, return zero.  If we were interrupted, returns -EINTR
+ */
+static inline int down_interruptible(struct semaphore * sem)
+{
+	int result;
+
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+
+	__asm__ __volatile__(
+		"# atomic interruptible down operation\n\t"
+		LOCK "decl %1\n\t"     /* --sem->count */
+		"js 2f\n\t"
+		"xorl %0,%0\n"
+		"1:\n"
+                ".subsection 1\n" \
+               ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
+                "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
+                ".endif\n" \
+		"2:\tcall __down_failed_interruptible\n\t"
+		"jmp 1b\n"
+		".subsection 0"
+		:"=a" (result), "=m" (sem->count)
+		:"D" (sem)
+		:"memory");
+	return result;
+}
+
+/*
+ * Non-blockingly attempt to down() a semaphore.
+ * Returns zero if we acquired it
+ */
+static inline int down_trylock(struct semaphore * sem)
+{
+	int result;
+
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+
+	__asm__ __volatile__(
+		"# atomic interruptible down operation\n\t"
+		LOCK "decl %1\n\t"     /* --sem->count */
+		"js 2f\n\t"
+		"xorl %0,%0\n"
+		"1:\n"
+                ".subsection 1\n" \
+                ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
+                "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
+                ".endif\n" \
+		"2:\tcall __down_failed_trylock\n\t"
+		"jmp 1b\n"
+		".subsection 0"
+		:"=a" (result), "=m" (sem->count)
+		:"D" (sem)
+		:"memory","cc");
+	return result;
+}
+
+/*
+ * Note! This is subtle. We jump to wake people up only if
+ * the semaphore was negative (== somebody was waiting on it).
+ * The default case (no contention) will result in NO
+ * jumps for both down() and up().
+ */
+static inline void up(struct semaphore * sem)
+{
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+	__asm__ __volatile__(
+		"# atomic up operation\n\t"
+		LOCK "incl %0\n\t"     /* ++sem->count */
+		"jle 2f\n"
+		"1:\n"
+                ".subsection 1\n" \
+                ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
+                "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
+                ".endif\n" \
+		"2:\tcall __up_wakeup\n\t"
+		"jmp 1b\n"
+		".subsection 0"
+		:"=m" (sem->count)
+		:"D" (sem)
+		:"memory");
+}
+
+static inline int sem_getcount(struct semaphore *sem)
+{
+       return atomic_read(&sem->count);
+}
+
+#endif /* __KERNEL__ */
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/sembuf.h linux-2.4.20/include/asm-x86_64/sembuf.h
--- linux-2.4.19/include/asm-x86_64/sembuf.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/sembuf.h	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,25 @@
+#ifndef _X86_64_SEMBUF_H
+#define _X86_64_SEMBUF_H
+
+/* 
+ * The semid64_ds structure for x86_64 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct semid64_ds {
+	struct ipc64_perm sem_perm;		/* permissions .. see ipc.h */
+	__kernel_time_t	sem_otime;		/* last semop time */
+	unsigned long	__unused1;
+	__kernel_time_t	sem_ctime;		/* last change time */
+	unsigned long	__unused2;
+	unsigned long	sem_nsems;		/* no. of semaphores in array */
+	unsigned long	__unused3;
+	unsigned long	__unused4;
+};
+
+#endif /* _X86_64_SEMBUF_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/serial.h linux-2.4.20/include/asm-x86_64/serial.h
--- linux-2.4.19/include/asm-x86_64/serial.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/serial.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,147 @@
+/*
+ * include/asm-x86_64/serial.h
+ */
+
+#include <linux/config.h>
+
+/*
+ * This assumes you have a 1.8432 MHz clock for your UART.
+ *
+ * It'd be nice if someone built a serial card with a 24.576 MHz
+ * clock, since the 16550A is capable of handling a top speed of 1.5
+ * megabits/second; but this requires the faster clock.
+ */
+#define BASE_BAUD ( 1843200 / 16 )
+
+/* Standard COM flags (except for COM4, because of the 8514 problem) */
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+#endif
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define FOURPORT_FLAGS ASYNC_FOURPORT
+#define ACCENT_FLAGS 0
+#define BOCA_FLAGS 0
+#define HUB6_FLAGS 0
+#define RS_TABLE_SIZE	64
+#else
+#define RS_TABLE_SIZE
+#endif
+
+#define MCA_COM_FLAGS	(STD_COM_FLAGS|ASYNC_BOOT_ONLYMCA)
+
+/*
+ * The following define the access methods for the HUB6 card. All
+ * access is through two ports for all 24 possible chips. The card is
+ * selected through the high 2 bits, the port on that card with the
+ * "middle" 3 bits, and the register on that port with the bottom
+ * 3 bits.
+ *
+ * While the access port and interrupt is configurable, the default
+ * port locations are 0x302 for the port control register, and 0x303
+ * for the data read/write register. Normally, the interrupt is at irq3
+ * but can be anything from 3 to 7 inclusive. Note that using 3 will
+ * require disabling com2.
+ */
+
+#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
+
+#define STD_SERIAL_PORT_DEFNS			\
+	/* UART CLK   PORT IRQ     FLAGS        */			\
+	{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },	/* ttyS0 */	\
+	{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },	/* ttyS1 */	\
+	{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },	/* ttyS2 */	\
+	{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },	/* ttyS3 */
+
+/*
+ * HCDP_SERIAL_PORT_DEFNS should be placed in exactly the same slot 
+ * in rs_table as defined by HCDP_SERIAL_CONSOLE_PORT in 
+ * include/linux/serial.h
+ */
+#define HCDP_SERIAL_PORT_DEFNS	\
+	{ 0, BASE_BAUD, -1, 0, STD_COM_FLAGS},		/* ttySx device
+							   in comments sucks.
+							   You add an entry
+							   and you get to edit 
+							   boatloads of these 
+							   comments. Not worth
+							   it */
+
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define EXTRA_SERIAL_PORT_DEFNS			\
+	{ 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, 	/* ttyS4 */	\
+	{ 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },	/* ttyS5 */	\
+	{ 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },	/* ttyS6 */	\
+	{ 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },	/* ttyS7 */	\
+	{ 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },	/* ttyS8 */	\
+	{ 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },	/* ttyS9 */	\
+	{ 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },	/* ttyS10 */	\
+	{ 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },	/* ttyS11 */	\
+	{ 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },	/* ttyS12 */	\
+	{ 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },	/* ttyS13 */	\
+	{ 0, BASE_BAUD, 0x000, 0, 0 },	/* ttyS14 (spare) */		\
+	{ 0, BASE_BAUD, 0x000, 0, 0 },	/* ttyS15 (spare) */		\
+	{ 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },	/* ttyS16 */	\
+	{ 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },	/* ttyS17 */	\
+	{ 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },	/* ttyS18 */	\
+	{ 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },	/* ttyS19 */	\
+	{ 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },	/* ttyS20 */	\
+	{ 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },	/* ttyS21 */	\
+	{ 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },	/* ttyS22 */	\
+	{ 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },	/* ttyS23 */	\
+	{ 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },	/* ttyS24 */	\
+	{ 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },	/* ttyS25 */	\
+	{ 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },	/* ttyS26 */	\
+	{ 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },	/* ttyS27 */	\
+	{ 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },	/* ttyS28 */	\
+	{ 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },	/* ttyS29 */	\
+	{ 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },	/* ttyS30 */	\
+	{ 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },	/* ttyS31 */
+#else
+#define EXTRA_SERIAL_PORT_DEFNS
+#endif
+
+/* You can have up to four HUB6's in the system, but I've only
+ * included two cards here for a total of twelve ports.
+ */
+#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS))
+#define HUB6_SERIAL_PORT_DFNS		\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) },  /* ttyS32 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) },  /* ttyS33 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) },  /* ttyS34 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) },  /* ttyS35 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) },  /* ttyS36 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) },  /* ttyS37 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) },  /* ttyS38 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) },  /* ttyS39 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) },  /* ttyS40 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) },  /* ttyS41 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) },  /* ttyS42 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) },  /* ttyS43 */
+#else
+#define HUB6_SERIAL_PORT_DFNS
+#endif
+
+#ifdef CONFIG_MCA
+#define MCA_SERIAL_PORT_DFNS			\
+	{ 0, BASE_BAUD, 0x3220, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x3228, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x4220, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x4228, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x5220, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x5228, 3, MCA_COM_FLAGS },
+#else
+#define MCA_SERIAL_PORT_DFNS
+#endif
+
+#define SERIAL_PORT_DFNS		\
+	STD_SERIAL_PORT_DEFNS		\
+	EXTRA_SERIAL_PORT_DEFNS		\
+	HUB6_SERIAL_PORT_DFNS		\
+	MCA_SERIAL_PORT_DFNS		\
+	HCDP_SERIAL_PORT_DEFNS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/setup.h linux-2.4.20/include/asm-x86_64/setup.h
--- linux-2.4.19/include/asm-x86_64/setup.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/setup.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,10 @@
+/*
+ *	Just a place holder. We don't want to have to test x86 before
+ *	we include stuff
+ */
+
+#ifndef _x8664_SETUP_H
+#define _x8664_SETUP_H
+
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/shmbuf.h linux-2.4.20/include/asm-x86_64/shmbuf.h
--- linux-2.4.19/include/asm-x86_64/shmbuf.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/shmbuf.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,38 @@
+#ifndef _X8664_SHMBUF_H
+#define _X8664_SHMBUF_H
+
+/* 
+ * The shmid64_ds structure for x8664 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 64-bit values
+ */
+
+struct shmid64_ds {
+	struct ipc64_perm	shm_perm;	/* operation perms */
+	size_t			shm_segsz;	/* size of segment (bytes) */
+	__kernel_time_t		shm_atime;	/* last attach time */
+	__kernel_time_t		shm_dtime;	/* last detach time */
+	__kernel_time_t		shm_ctime;	/* last change time */
+	__kernel_pid_t		shm_cpid;	/* pid of creator */
+	__kernel_pid_t		shm_lpid;	/* pid of last operator */
+	unsigned long		shm_nattch;	/* no. of current attaches */
+	unsigned long		__unused4;
+	unsigned long		__unused5;
+};
+
+struct shminfo64 {
+	unsigned long	shmmax;
+	unsigned long	shmmin;
+	unsigned long	shmmni;
+	unsigned long	shmseg;
+	unsigned long	shmall;
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+	unsigned long	__unused3;
+	unsigned long	__unused4;
+};
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/shmparam.h linux-2.4.20/include/asm-x86_64/shmparam.h
--- linux-2.4.19/include/asm-x86_64/shmparam.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/shmparam.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,6 @@
+#ifndef _ASMX8664_SHMPARAM_H
+#define _ASMX8664_SHMPARAM_H
+
+#define	SHMLBA PAGE_SIZE		 /* attach addr a multiple of this */
+
+#endif /* _ASMX8664_SHMPARAM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/sigcontext.h linux-2.4.20/include/asm-x86_64/sigcontext.h
--- linux-2.4.19/include/asm-x86_64/sigcontext.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/sigcontext.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,54 @@
+#ifndef _ASM_X86_64_SIGCONTEXT_H
+#define _ASM_X86_64_SIGCONTEXT_H
+
+#include <asm/types.h>
+
+/* FXSAVE frame */
+/* Note: reserved1/2 may someday contain valuable data. Always save/restore
+   them when you change signal frames. */
+struct _fpstate {
+	__u16	cwd;
+	__u16	swd;
+	__u16	twd;	/* Note this is not the same as the 32bit/x87/FSAVE twd */
+	__u16	fop;
+	__u64	rip;
+	__u64	rdp; 
+	__u32	mxcsr;
+	__u32	mxcsr_mask;
+	__u32	st_space[32];	/* 8*16 bytes for each FP-reg */
+	__u32	xmm_space[64];	/* 16*16 bytes for each XMM-reg  */
+	__u32	reserved2[24];
+};
+
+struct sigcontext { 
+	unsigned long r8;
+	unsigned long r9;
+	unsigned long r10;
+	unsigned long r11;
+	unsigned long r12;
+	unsigned long r13;
+	unsigned long r14;
+	unsigned long r15;
+	unsigned long rdi;
+	unsigned long rsi;
+	unsigned long rbp;
+	unsigned long rbx;
+	unsigned long rdx;
+	unsigned long rax;
+	unsigned long rcx;
+	unsigned long rsp;
+	unsigned long rip;
+	unsigned long eflags;		/* RFLAGS */
+	unsigned short cs;
+	unsigned short gs;
+	unsigned short fs;
+	unsigned short __pad0; 
+	unsigned long err;
+	unsigned long trapno;
+	unsigned long oldmask;
+	unsigned long cr2;
+	struct _fpstate *fpstate;	/* zero when no FPU context */
+	unsigned long reserved1[8];
+};
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/sigcontext32.h linux-2.4.20/include/asm-x86_64/sigcontext32.h
--- linux-2.4.19/include/asm-x86_64/sigcontext32.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/sigcontext32.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,71 @@
+#ifndef _SIGCONTEXT32_H
+#define _SIGCONTEXT32_H 1
+
+/* signal context for 32bit programs. */
+
+#define X86_FXSR_MAGIC		0x0000
+
+struct _fpreg {
+	unsigned short significand[4];
+	unsigned short exponent;
+};
+
+struct _fpxreg {
+	unsigned short significand[4];
+	unsigned short exponent;
+	unsigned short padding[3];
+};
+
+struct _xmmreg {
+	__u32	element[4];
+};
+
+/* FSAVE frame with extensions */
+struct _fpstate_ia32 {
+	/* Regular FPU environment */
+	__u32 	cw;
+	__u32	sw;
+	__u32	tag;	/* not compatible to 64bit twd */
+	__u32	ipoff;			
+	__u32	cssel;
+	__u32	dataoff;
+	__u32	datasel;
+	struct _fpreg	_st[8];
+	unsigned short	status;
+	unsigned short	magic;		/* 0xffff = regular FPU data only */
+
+	/* FXSR FPU environment */
+	__u32	_fxsr_env[6];
+	__u32	mxcsr;
+	__u32	reserved;
+	struct _fpxreg	_fxsr_st[8];
+	struct _xmmreg	_xmm[8];	/* It's actually 16 */ 
+	__u32	padding[56];
+};
+
+struct sigcontext_ia32 {
+       unsigned short gs, __gsh;
+       unsigned short fs, __fsh;
+       unsigned short es, __esh;
+       unsigned short ds, __dsh;
+       unsigned int edi;
+       unsigned int esi;
+       unsigned int ebp;
+       unsigned int esp;
+       unsigned int ebx;
+       unsigned int edx;
+       unsigned int ecx;
+       unsigned int eax;
+       unsigned int trapno;
+       unsigned int err;
+       unsigned int eip;
+       unsigned short cs, __csh;
+       unsigned int eflags;
+       unsigned int esp_at_signal;
+       unsigned short ss, __ssh;
+       unsigned int fpstate;		/* really (struct _fpstate_ia32 *) */
+       unsigned int oldmask;
+       unsigned int cr2;
+};
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/siginfo.h linux-2.4.20/include/asm-x86_64/siginfo.h
--- linux-2.4.19/include/asm-x86_64/siginfo.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/siginfo.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,232 @@
+#ifndef _X8664_SIGINFO_H
+#define _X8664_SIGINFO_H
+
+#include <linux/types.h>
+
+typedef union sigval {
+	int sival_int;
+	void *sival_ptr;
+} sigval_t;
+
+#define SI_MAX_SIZE	128
+#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
+
+typedef struct siginfo {
+	int si_signo;
+	int si_errno;
+	int si_code;
+
+	union {
+		int _pad[SI_PAD_SIZE];
+
+		/* kill() */
+		struct {
+			pid_t _pid;		/* sender's pid */
+			uid_t _uid;		/* sender's uid */
+		} _kill;
+
+		/* POSIX.1b timers */
+		struct {
+			unsigned int _timer1;
+			unsigned int _timer2;
+		} _timer;
+
+		/* POSIX.1b signals */
+		struct {
+			pid_t _pid;		/* sender's pid */
+			uid_t _uid;		/* sender's uid */
+			sigval_t _sigval;
+		} _rt;
+
+		/* SIGCHLD */
+		struct {
+			pid_t _pid;		/* which child */
+			uid_t _uid;		/* sender's uid */
+			int _status;		/* exit code */
+			clock_t _utime;
+			clock_t _stime;
+		} _sigchld;
+
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		struct {
+			void *_addr; /* faulting insn/memory ref. */
+		} _sigfault;
+
+		/* SIGPOLL */
+		struct {
+			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			int _fd;
+		} _sigpoll;
+	} _sifields;
+} siginfo_t;
+
+/*
+ * How these fields are to be accessed.
+ */
+#define si_pid		_sifields._kill._pid
+#define si_uid		_sifields._kill._uid
+#define si_status	_sifields._sigchld._status
+#define si_utime	_sifields._sigchld._utime
+#define si_stime	_sifields._sigchld._stime
+#define si_value	_sifields._rt._sigval
+#define si_int		_sifields._rt._sigval.sival_int
+#define si_ptr		_sifields._rt._sigval.sival_ptr
+#define si_addr		_sifields._sigfault._addr
+#define si_band		_sifields._sigpoll._band
+#define si_fd		_sifields._sigpoll._fd
+
+#ifdef __KERNEL__
+#define __SI_MASK	0xffff0000
+#define __SI_KILL	(0 << 16)
+#define __SI_TIMER	(1 << 16)
+#define __SI_POLL	(2 << 16)
+#define __SI_FAULT	(3 << 16)
+#define __SI_CHLD	(4 << 16)
+#define __SI_RT		(5 << 16)
+#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
+#else
+#define __SI_KILL	0
+#define __SI_TIMER	0
+#define __SI_POLL	0
+#define __SI_FAULT	0
+#define __SI_CHLD	0
+#define __SI_RT		0
+#define __SI_CODE(T,N)	(N)
+#endif
+
+/*
+ * si_code values
+ * Digital reserves positive values for kernel-generated signals.
+ * ... And Linux ignores that convention -AK.
+ */
+#define SI_USER		0		/* sent by kill, sigsend, raise */
+#define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
+#define SI_QUEUE	-1		/* sent by sigqueue */
+#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
+#define SI_MESGQ	-3		/* sent by real time mesq state change */
+#define SI_ASYNCIO	-4		/* sent by AIO completion */
+#define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
+
+#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
+#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
+
+/*
+ * SIGILL si_codes
+ */
+#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
+#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
+#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
+#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
+#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
+#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
+#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
+#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
+#define NSIGILL		8
+
+/*
+ * SIGFPE si_codes
+ */
+#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
+#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
+#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
+#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
+#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
+#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
+#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
+#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
+#define NSIGFPE		8
+
+/*
+ * SIGSEGV si_codes
+ */
+#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
+#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
+#define NSIGSEGV	2
+
+/*
+ * SIGBUS si_codes
+ */
+#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
+#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
+#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
+#define NSIGBUS		3
+
+/*
+ * SIGTRAP si_codes
+ */
+#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
+#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
+#define NSIGTRAP	2
+
+/*
+ * SIGCHLD si_codes
+ */
+#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
+#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
+#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
+#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
+#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
+#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
+#define NSIGCHLD	6
+
+/*
+ * SIGPOLL si_codes
+ */
+#define POLL_IN		(__SI_POLL|1)	/* data input available */
+#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
+#define POLL_MSG	(__SI_POLL|3)	/* input message available */
+#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
+#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
+#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
+#define NSIGPOLL	6
+
+/*
+ * sigevent definitions
+ * 
+ * It seems likely that SIGEV_THREAD will have to be handled from 
+ * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
+ * thread manager then catches and does the appropriate nonsense.
+ * However, everything is written out here so as to not get lost.
+ */
+#define SIGEV_SIGNAL	0	/* notify via signal */
+#define SIGEV_NONE	1	/* other notification: meaningless */
+#define SIGEV_THREAD	2	/* deliver via thread creation */
+
+#define SIGEV_MAX_SIZE	64
+#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
+
+typedef struct sigevent {
+	sigval_t sigev_value;
+	int sigev_signo;
+	int sigev_notify;
+	union {
+		int _pad[SIGEV_PAD_SIZE];
+
+		struct {
+			void (*_function)(sigval_t);
+			void *_attribute;	/* really pthread_attr_t */
+		} _sigev_thread;
+	} _sigev_un;
+} sigevent_t;
+
+#define sigev_notify_function	_sigev_un._sigev_thread._function
+#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
+
+#ifdef __KERNEL__
+#include <linux/string.h>
+
+extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
+{
+	if (from->si_code < 0)
+		memcpy(to, from, sizeof(siginfo_t));
+	else
+		/* _sigchld is currently the largest know union member */
+		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
+}
+
+extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
+
+#endif /* __KERNEL__ */
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/signal.h linux-2.4.20/include/asm-x86_64/signal.h
--- linux-2.4.19/include/asm-x86_64/signal.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/signal.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,197 @@
+#ifndef _ASMx86_64_SIGNAL_H
+#define _ASMx86_64_SIGNAL_H
+
+#include <linux/types.h>
+
+/* Avoid too many header ordering problems.  */
+struct siginfo;
+
+#ifdef __KERNEL__
+/* Most things should be clean enough to redefine this at will, if care
+   is taken to make libc match.  */
+
+#define _NSIG		64
+#define _NSIG_BPW	64
+#define _NSIG_WORDS	(_NSIG / _NSIG_BPW)
+
+typedef unsigned long old_sigset_t;		/* at least 32 bits */
+
+typedef struct {
+	unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+#else
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+#define NSIG		32
+typedef unsigned long sigset_t;
+
+#endif /* __KERNEL__ */
+
+#define SIGHUP		 1
+#define SIGINT		 2
+#define SIGQUIT		 3
+#define SIGILL		 4
+#define SIGTRAP		 5
+#define SIGABRT		 6
+#define SIGIOT		 6
+#define SIGBUS		 7
+#define SIGFPE		 8
+#define SIGKILL		 9
+#define SIGUSR1		10
+#define SIGSEGV		11
+#define SIGUSR2		12
+#define SIGPIPE		13
+#define SIGALRM		14
+#define SIGTERM		15
+#define SIGSTKFLT	16
+#define SIGCHLD		17
+#define SIGCONT		18
+#define SIGSTOP		19
+#define SIGTSTP		20
+#define SIGTTIN		21
+#define SIGTTOU		22
+#define SIGURG		23
+#define SIGXCPU		24
+#define SIGXFSZ		25
+#define SIGVTALRM	26
+#define SIGPROF		27
+#define SIGWINCH	28
+#define SIGIO		29
+#define SIGPOLL		SIGIO
+/*
+#define SIGLOST		29
+*/
+#define SIGPWR		30
+#define SIGSYS		31
+#define	SIGUNUSED	31
+
+/* These should not be considered constants from userland.  */
+#define SIGRTMIN	32
+#define SIGRTMAX	(_NSIG-1)
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP	0x00000001
+#define SA_NOCLDWAIT	0x00000002 /* not supported yet */
+#define SA_SIGINFO	0x00000004
+#define SA_ONSTACK	0x08000000
+#define SA_RESTART	0x10000000
+#define SA_NODEFER	0x40000000
+#define SA_RESETHAND	0x80000000
+
+#define SA_NOMASK	SA_NODEFER
+#define SA_ONESHOT	SA_RESETHAND
+#define SA_INTERRUPT	0x20000000 /* dummy -- ignored */
+
+#define SA_RESTORER	0x04000000
+
+/*
+ * sigaltstack controls
+ */
+#define SS_ONSTACK	1
+#define SS_DISABLE	2
+
+#define MINSIGSTKSZ	2048
+#define SIGSTKSZ	8192
+
+#ifdef __KERNEL__
+
+/*
+ * These values of sa_flags are used only by the kernel as part of the
+ * irq handling routines.
+ *
+ * SA_INTERRUPT is also used by the irq handling routines.
+ * SA_SHIRQ is for shared interrupt support on PCI and EISA.
+ */
+#define SA_PROBE		SA_ONESHOT
+#define SA_SAMPLE_RANDOM	SA_RESTART
+#define SA_SHIRQ		0x04000000
+#endif
+
+#define SIG_BLOCK          0	/* for blocking signals */
+#define SIG_UNBLOCK        1	/* for unblocking signals */
+#define SIG_SETMASK        2	/* for setting the signal mask */
+
+/* Type of a signal handler.  */
+typedef void (*__sighandler_t)(int);
+
+#define SIG_DFL	((__sighandler_t)0)	/* default signal handling */
+#define SIG_IGN	((__sighandler_t)1)	/* ignore signal */
+#define SIG_ERR	((__sighandler_t)-1)	/* error return from signal */
+
+struct sigaction {
+	__sighandler_t sa_handler;
+	unsigned long sa_flags;
+	void (*sa_restorer)(void);
+	sigset_t sa_mask;		/* mask last for extensibility */
+};
+
+struct k_sigaction {
+	struct sigaction sa;
+};
+
+typedef struct sigaltstack {
+	void *ss_sp;
+	int ss_flags;
+	size_t ss_size;
+} stack_t;
+
+#ifdef __KERNEL__
+#include <asm/sigcontext.h>
+
+#undef __HAVE_ARCH_SIG_BITOPS
+#if 0
+
+extern __inline__ void sigaddset(sigset_t *set, int _sig)
+{
+	__asm__("btsq %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc");
+}
+
+extern __inline__ void sigdelset(sigset_t *set, int _sig)
+{
+	__asm__("btrq %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc");
+}
+
+extern __inline__ int __const_sigismember(sigset_t *set, int _sig)
+{
+	unsigned long sig = _sig - 1;
+	return 1 & (set->sig[sig / _NSIG_BPW] >> (sig & ~(_NSIG_BPW-1)));
+}
+
+extern __inline__ int __gen_sigismember(sigset_t *set, int _sig)
+{
+	int ret;
+	__asm__("btq %2,%1\n\tsbbq %0,%0"
+		: "=r"(ret) : "m"(*set), "Ir"(_sig-1) : "cc");
+	return ret;
+}
+
+#define sigismember(set,sig)			\
+	(__builtin_constant_p(sig) ?		\
+	 __const_sigismember((set),(sig)) :	\
+	 __gen_sigismember((set),(sig)))
+
+#define sigmask(sig)	(1UL << ((sig) - 1))
+
+extern __inline__ int sigfindinword(unsigned long word)
+{
+	__asm__("bsfq %1,%0" : "=r"(word) : "rm"(word) : "cc");
+	return word;
+}
+#endif
+#endif /* __KERNEL__ */
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/smp.h linux-2.4.20/include/asm-x86_64/smp.h
--- linux-2.4.19/include/asm-x86_64/smp.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/smp.h	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,116 @@
+#ifndef __ASM_SMP_H
+#define __ASM_SMP_H
+
+/*
+ * We need the APIC definitions automatically as part of 'smp.h'
+ */
+#ifndef __ASSEMBLY__
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/ptrace.h>
+#endif
+
+#ifdef CONFIG_X86_LOCAL_APIC
+#ifndef __ASSEMBLY__
+#include <asm/fixmap.h>
+#include <asm/bitops.h>
+#include <asm/mpspec.h>
+#ifdef CONFIG_X86_IO_APIC
+#include <asm/io_apic.h>
+#endif
+#include <asm/apic.h>
+#endif
+#endif
+
+#ifdef CONFIG_SMP
+#ifndef ASSEMBLY
+
+#include <asm/pda.h>
+
+/*
+ * Private routines/data
+ */
+ 
+extern void smp_alloc_memory(void);
+extern unsigned long phys_cpu_present_map;
+extern unsigned long cpu_online_map;
+extern volatile unsigned long smp_invalidate_needed;
+extern int pic_mode;
+extern void smp_flush_tlb(void);
+extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
+extern void smp_send_reschedule(int cpu);
+extern void smp_invalidate_rcv(void);		/* Process an NMI */
+extern void (*mtrr_hook) (void);
+extern void zap_low_mappings (void);
+
+/*
+ * On x86 all CPUs are mapped 1:1 to the APIC space.
+ * This simplifies scheduling and IPI sending and
+ * compresses data structures.
+ */
+extern inline int cpu_logical_map(int cpu)
+{
+	return cpu;
+}
+extern inline int cpu_number_map(int cpu)
+{
+	return cpu;
+}
+
+/*
+ * Some lowlevel functions might want to know about
+ * the real APIC ID <-> CPU # mapping.
+ */
+extern volatile int x86_apicid_to_cpu[NR_CPUS];
+extern volatile int x86_cpu_to_apicid[NR_CPUS];
+
+/*
+ * General functions that each host system must provide.
+ */
+ 
+extern void smp_boot_cpus(void);
+extern void smp_store_cpu_info(int id);		/* Store per CPU info (like the initial udelay numbers */
+
+/*
+ * This function is needed by all SMP systems. It must _always_ be valid
+ * from the initial startup. We map APIC_BASE very early in page_setup(),
+ * so this is correct in the x86 case.
+ */
+
+#define smp_processor_id() read_pda(cpunumber)
+
+#define stack_smp_processor_id() (stack_current()->processor)
+
+
+extern __inline int hard_smp_processor_id(void)
+{
+	/* we don't want to mark this access volatile - bad code generation */
+	return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
+}
+
+#endif /* !ASSEMBLY */
+
+#define NO_PROC_ID		0xFF		/* No processor magic marker */
+
+/*
+ *	This magic constant controls our willingness to transfer
+ *	a process across CPUs. Such a transfer incurs misses on the L1
+ *	cache, and on a P6 or P5 with multiple L2 caches L2 hits. My
+ *	gut feeling is this will vary by board in value. For a board
+ *	with separate L2 cache it probably depends also on the RSS, and
+ *	for a board with shared L2 cache it ought to decay fast as other
+ *	processes are run.
+ */
+ 
+#define PROC_CHANGE_PENALTY	15		/* Schedule penalty */
+
+
+
+#endif
+#define INT_DELIVERY_MODE 1     /* logical delivery */
+#define TARGET_CPUS 1
+
+#ifndef CONFIG_SMP
+#define stack_smp_processor_id() 0
+#endif
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/smplock.h linux-2.4.20/include/asm-x86_64/smplock.h
--- linux-2.4.19/include/asm-x86_64/smplock.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/smplock.h	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,74 @@
+/*
+ * <asm/smplock.h>
+ */
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <asm/current.h>
+
+extern spinlock_cacheline_t kernel_flag_cacheline;  
+#define kernel_flag kernel_flag_cacheline.lock      
+
+#define kernel_locked()		spin_is_locked(&kernel_flag)
+
+/*
+ * Release global kernel lock and global interrupt lock
+ */
+#define release_kernel_lock(task, cpu) \
+do { \
+	if (task->lock_depth >= 0) \
+		spin_unlock(&kernel_flag); \
+	release_irqlock(cpu); \
+	__sti(); \
+} while (0)
+
+/*
+ * Re-acquire the kernel lock
+ */
+#define reacquire_kernel_lock(task) \
+do { \
+	if (task->lock_depth >= 0) \
+		spin_lock(&kernel_flag); \
+} while (0)
+
+
+/*
+ * Getting the big kernel lock.
+ *
+ * This cannot happen asynchronously,
+ * so we only need to worry about other
+ * CPU's.
+ */
+extern __inline__ void lock_kernel(void)
+{
+#if 1
+	if (!++current->lock_depth)
+		spin_lock(&kernel_flag);
+#else
+	__asm__ __volatile__(
+		"incl %1\n\t"
+		"jne 9f"
+		spin_lock_string
+		"\n9:"
+		:"=m" (__dummy_lock(&kernel_flag)),
+		 "=m" (current->lock_depth));
+#endif
+}
+
+extern __inline__ void unlock_kernel(void)
+{
+	if (current->lock_depth < 0)
+		out_of_line_bug();
+#if 1
+	if (--current->lock_depth < 0)
+		spin_unlock(&kernel_flag);
+#else
+	__asm__ __volatile__(
+		"decl %1\n\t"
+		"jns 9f\n\t"
+		spin_unlock_string
+		"\n9:"
+		:"=m" (__dummy_lock(&kernel_flag)),
+		 "=m" (current->lock_depth));
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/socket.h linux-2.4.20/include/asm-x86_64/socket.h
--- linux-2.4.19/include/asm-x86_64/socket.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/socket.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,64 @@
+#ifndef _ASM_SOCKET_H
+#define _ASM_SOCKET_H
+
+#include <asm/sockios.h>
+
+/* For setsockoptions(2) */
+#define SOL_SOCKET	1
+
+#define SO_DEBUG	1
+#define SO_REUSEADDR	2
+#define SO_TYPE		3
+#define SO_ERROR	4
+#define SO_DONTROUTE	5
+#define SO_BROADCAST	6
+#define SO_SNDBUF	7
+#define SO_RCVBUF	8
+#define SO_KEEPALIVE	9
+#define SO_OOBINLINE	10
+#define SO_NO_CHECK	11
+#define SO_PRIORITY	12
+#define SO_LINGER	13
+#define SO_BSDCOMPAT	14
+/* To add :#define SO_REUSEPORT 15 */
+#define SO_PASSCRED	16
+#define SO_PEERCRED	17
+#define SO_RCVLOWAT	18
+#define SO_SNDLOWAT	19
+#define SO_RCVTIMEO	20
+#define SO_SNDTIMEO	21
+
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION		22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT	23
+#define SO_SECURITY_ENCRYPTION_NETWORK		24
+
+#define SO_BINDTODEVICE	25
+
+/* Socket filtering */
+#define SO_ATTACH_FILTER        26
+#define SO_DETACH_FILTER        27
+
+#define SO_PEERNAME		28
+#define SO_TIMESTAMP		29
+#define SCM_TIMESTAMP		SO_TIMESTAMP
+
+#define SO_ACCEPTCONN		30
+
+/* Nasty libc5 fixup - bletch */
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+/* Socket types. */
+#define SOCK_STREAM	1		/* stream (connection) socket	*/
+#define SOCK_DGRAM	2		/* datagram (conn.less) socket	*/
+#define SOCK_RAW	3		/* raw socket			*/
+#define SOCK_RDM	4		/* reliably-delivered message	*/
+#define SOCK_SEQPACKET	5		/* sequential packet socket	*/
+#define SOCK_PACKET	10		/* linux specific way of	*/
+					/* getting packets at the dev	*/
+					/* level.  For writing rarp and	*/
+					/* other similar things on the	*/
+					/* user level.			*/
+#define	SOCK_MAX	(SOCK_PACKET+1)
+#endif
+
+#endif /* _ASM_SOCKET_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/socket32.h linux-2.4.20/include/asm-x86_64/socket32.h
--- linux-2.4.19/include/asm-x86_64/socket32.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/socket32.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,70 @@
+#ifndef SOCKET32_H
+#define SOCKET32_H 1
+
+/* XXX This really belongs in some header file... -DaveM */
+#define MAX_SOCK_ADDR	128		/* 108 for Unix domain - 
+					   16 for IP, 16 for IPX,
+					   24 for IPv6,
+					   about 80 for AX.25 */
+
+extern struct socket *sockfd_lookup(int fd, int *err);
+
+/* XXX This as well... */
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+	fput(sock->file);
+}
+
+struct msghdr32 {
+        u32               msg_name;
+        int               msg_namelen;
+        u32               msg_iov;
+        __kernel_size_t32 msg_iovlen;
+        u32               msg_control;
+        __kernel_size_t32 msg_controllen;
+        unsigned          msg_flags;
+};
+
+struct cmsghdr32 {
+        __kernel_size_t32 cmsg_len;
+        int               cmsg_level;
+        int               cmsg_type;
+};
+
+/* Bleech... */
+#define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen))
+#define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) cmsg32_nxthdr((mhdr), (cmsg), (cmsglen))
+
+#define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) )
+
+#define CMSG32_DATA(cmsg)	((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32))))
+#define CMSG32_SPACE(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len))
+#define CMSG32_LEN(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len))
+
+#define __CMSG32_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr32) ? \
+				    (struct cmsghdr32 *)(ctl) : \
+				    (struct cmsghdr32 *)NULL)
+#define CMSG32_FIRSTHDR(msg)	__CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+
+__inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size,
+					      struct cmsghdr32 *__cmsg, int __cmsg_len)
+{
+	struct cmsghdr32 * __ptr;
+
+	__ptr = (struct cmsghdr32 *)(((unsigned char *) __cmsg) +
+				     CMSG32_ALIGN(__cmsg_len));
+	if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
+		return NULL;
+
+	return __ptr;
+}
+
+__inline__ struct cmsghdr32 *cmsg32_nxthdr (struct msghdr *__msg,
+					    struct cmsghdr32 *__cmsg,
+					    int __cmsg_len)
+{
+	return __cmsg32_nxthdr(__msg->msg_control, __msg->msg_controllen,
+			       __cmsg, __cmsg_len);
+}
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/sockios.h linux-2.4.20/include/asm-x86_64/sockios.h
--- linux-2.4.19/include/asm-x86_64/sockios.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/sockios.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,12 @@
+#ifndef __ARCH_X8664_SOCKIOS__
+#define __ARCH_X8664_SOCKIOS__
+
+/* Socket-level I/O control calls. */
+#define FIOSETOWN 	0x8901
+#define SIOCSPGRP	0x8902
+#define FIOGETOWN	0x8903
+#define SIOCGPGRP	0x8904
+#define SIOCATMARK	0x8905
+#define SIOCGSTAMP	0x8906		/* Get stamp */
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/softirq.h linux-2.4.20/include/asm-x86_64/softirq.h
--- linux-2.4.19/include/asm-x86_64/softirq.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/softirq.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,51 @@
+#ifndef __ASM_SOFTIRQ_H
+#define __ASM_SOFTIRQ_H
+
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+
+#define __cpu_bh_enable(cpu) \
+		do { barrier(); local_bh_count(cpu)--; } while (0)
+#define cpu_bh_disable(cpu) \
+		do { local_bh_count(cpu)++; barrier(); } while (0)
+
+#define local_bh_disable()	cpu_bh_disable(smp_processor_id())
+#define __local_bh_enable()	__cpu_bh_enable(smp_processor_id())
+
+#define in_softirq() (local_bh_count(smp_processor_id()) != 0)
+
+/*
+ * NOTE: this assembly code assumes:
+ *
+ *    (char *)&local_bh_count - 8 == (char *)&softirq_pending
+ *
+ * If you change the offsets in irq_stat then you have to
+ * update this code as well.
+ */
+#define local_bh_enable()						\
+do {									\
+	unsigned int *ptr = &local_bh_count(smp_processor_id());	\
+									\
+	barrier();							\
+	if (!--*ptr)							\
+		__asm__ __volatile__ (					\
+			"cmpl $0, -8(%0);"				\
+			"jnz 2f;"					\
+			"1:;"						\
+									\
+                   ".subsection 1\n" \
+                   ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
+                   "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
+                   ".endif\n" \
+			"2:"	\
+			"call do_softirq_thunk;"		\
+			""		\
+			"jmp 1b;"					\
+			".subsection 0;"				\
+									\
+		: /* no output */					\
+		: "r" (ptr)				\
+		/* no registers clobbered */ );				\
+} while (0)
+
+#endif	/* __ASM_SOFTIRQ_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/spinlock.h linux-2.4.20/include/asm-x86_64/spinlock.h
--- linux-2.4.19/include/asm-x86_64/spinlock.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/spinlock.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,182 @@
+#ifndef __ASM_SPINLOCK_H
+#define __ASM_SPINLOCK_H
+
+#include <asm/atomic.h>
+#include <asm/rwlock.h>
+#include <asm/page.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+
+extern int printk(const char * fmt, ...)
+	__attribute__ ((format (printf, 1, 2)));
+
+/* It seems that people are forgetting to
+ * initialize their spinlocks properly, tsk tsk.
+ * Remember to turn this off in 2.4. -ben
+ */
+#if defined(CONFIG_DEBUG_SPINLOCK)
+#define SPINLOCK_DEBUG	1
+#else
+#define SPINLOCK_DEBUG	0
+#endif
+
+/*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+ */
+
+typedef struct {
+	volatile unsigned int lock;
+#if SPINLOCK_DEBUG
+	unsigned magic;
+#endif
+} spinlock_t;
+
+#define SPINLOCK_MAGIC	0xdead4ead
+
+#if SPINLOCK_DEBUG
+#define SPINLOCK_MAGIC_INIT	, SPINLOCK_MAGIC
+#else
+#define SPINLOCK_MAGIC_INIT	/* */
+#endif
+
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 SPINLOCK_MAGIC_INIT }
+
+#define spin_lock_init(x)	do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
+
+/*
+ * Simple spin lock operations.  There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ */
+
+#define spin_is_locked(x)	(*(volatile signed char *)(&(x)->lock) <= 0)
+#define spin_unlock_wait(x)	do { barrier(); } while(spin_is_locked(x))
+
+#define spin_lock_string \
+	"\n1:\t" \
+	"lock ; decb %0\n\t" \
+	"js 2f\n" \
+	".section .text.lock,\"ax\"\n" \
+	"2:\t" \
+	"cmpb $0,%0\n\t" \
+	"rep;nop\n\t" \
+	"jle 2b\n\t" \
+	"jmp 1b\n" \
+	".previous"
+
+/*
+ * This works. Despite all the confusion.
+ */
+#define spin_unlock_string \
+	"movb $1,%0"
+
+static inline int spin_trylock(spinlock_t *lock)
+{
+	char oldval;
+	__asm__ __volatile__(
+		"xchgb %b0,%1"
+		:"=q" (oldval), "=m" (lock->lock)
+		:"0" (0) : "memory");
+	return oldval > 0;
+}
+
+static inline void spin_lock(spinlock_t *lock)
+{
+#if SPINLOCK_DEBUG
+	__label__ here;
+here:
+	if (lock->magic != SPINLOCK_MAGIC) {
+printk("eip: %p\n", &&here);
+		out_of_line_bug();
+	}
+#endif
+	__asm__ __volatile__(
+		spin_lock_string
+		:"=m" (lock->lock) : : "memory");
+}
+
+static inline void spin_unlock(spinlock_t *lock)
+{
+#if SPINLOCK_DEBUG
+	if (lock->magic != SPINLOCK_MAGIC)
+		out_of_line_bug();
+	if (!spin_is_locked(lock))
+		out_of_line_bug();
+#endif
+	__asm__ __volatile__(
+		spin_unlock_string
+		:"=m" (lock->lock) : : "memory");
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * NOTE! it is quite common to have readers in interrupts
+ * but no interrupt writers. For those circumstances we
+ * can "mix" irq-safe locks - any writer needs to get a
+ * irq-safe write-lock, but readers can get non-irqsafe
+ * read-locks.
+ */
+typedef struct {
+	volatile unsigned int lock;
+#if SPINLOCK_DEBUG
+	unsigned magic;
+#endif
+} rwlock_t;
+
+#define RWLOCK_MAGIC	0xdeaf1eed
+
+#if SPINLOCK_DEBUG
+#define RWLOCK_MAGIC_INIT	, RWLOCK_MAGIC
+#else
+#define RWLOCK_MAGIC_INIT	/* */
+#endif
+
+#define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT }
+
+#define rwlock_init(x)	do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+
+/*
+ * On x86, we implement read-write locks as a 32-bit counter
+ * with the high bit (sign) being the "contended" bit.
+ *
+ * The inline assembly is non-obvious. Think about it.
+ *
+ * Changed to use the same technique as rw semaphores.  See
+ * semaphore.h for details.  -ben
+ */
+/* the spinlock helpers are in arch/x86_64/kernel/semaphore.S */
+
+extern inline void read_lock(rwlock_t *rw)
+{
+#if SPINLOCK_DEBUG
+	if (rw->magic != RWLOCK_MAGIC)
+		out_of_line_bug();
+#endif
+	__build_read_lock(rw, "__read_lock_failed");
+}
+
+static inline void write_lock(rwlock_t *rw)
+{
+#if SPINLOCK_DEBUG
+	if (rw->magic != RWLOCK_MAGIC)
+		out_of_line_bug();
+#endif
+	__build_write_lock(rw, "__write_lock_failed");
+}
+
+#define read_unlock(rw)		asm volatile("lock ; incl %0" :"=m" ((rw)->lock) : : "memory")
+#define write_unlock(rw)	asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ",%0":"=m" ((rw)->lock) : : "memory")
+
+static inline int write_trylock(rwlock_t *lock)
+{
+	atomic_t *count = (atomic_t *)lock;
+	if (atomic_sub_and_test(RW_LOCK_BIAS, count))
+		return 1;
+	atomic_add(RW_LOCK_BIAS, count);
+	return 0;
+}
+
+#endif /* __ASM_SPINLOCK_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/stat.h linux-2.4.20/include/asm-x86_64/stat.h
--- linux-2.4.19/include/asm-x86_64/stat.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/stat.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,27 @@
+#ifndef _ASM_X86_64_STAT_H
+#define _ASM_X86_64_STAT_H
+
+struct stat {
+	unsigned long	st_dev;
+	unsigned long	st_ino;
+	unsigned long	st_nlink;
+
+	unsigned int	st_mode;
+	unsigned int	st_uid;
+	unsigned int	st_gid;
+	unsigned int	__pad0;
+	unsigned long	st_rdev;
+	long		st_size;
+	long		st_blksize;
+	long		st_blocks;	/* Number 512-byte blocks allocated. */
+
+	unsigned long	st_atime;
+	unsigned long	__reserved0;	/* reserved for atime.nanoseconds */
+	unsigned long	st_mtime;
+	unsigned long	__reserved1;	/* reserved for atime.nanoseconds */
+	unsigned long	st_ctime;
+	unsigned long	__reserved2;	/* reserved for atime.nanoseconds */
+  	long		__unused[3];
+};
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/statfs.h linux-2.4.20/include/asm-x86_64/statfs.h
--- linux-2.4.19/include/asm-x86_64/statfs.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/statfs.h	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,25 @@
+#ifndef _X86_64_STATFS_H
+#define _X86_64_STATFS_H
+
+#ifndef __KERNEL_STRICT_NAMES
+
+#include <linux/types.h>
+
+typedef __kernel_fsid_t	fsid_t;
+
+#endif
+
+struct statfs {
+	long f_type;
+	long f_bsize;
+	long f_blocks;
+	long f_bfree;
+	long f_bavail;
+	long f_files;
+	long f_ffree;
+	__kernel_fsid_t f_fsid;
+	long f_namelen;
+	long f_spare[6];
+};
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/string.h linux-2.4.20/include/asm-x86_64/string.h
--- linux-2.4.19/include/asm-x86_64/string.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/string.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,52 @@
+#ifndef _X86_64_STRING_H_
+#define _X86_64_STRING_H_
+
+#ifdef __KERNEL__
+
+#define struct_cpy(x,y) (*(x)=*(y))
+
+/* Written 2002 by Andi Kleen */ 
+
+/* Only used for special circumstances. Stolen from i386/string.h */ 
+static inline void * __inline_memcpy(void * to, const void * from, size_t n)
+{
+unsigned long d0, d1, d2;
+__asm__ __volatile__(
+	"rep ; movsl\n\t"
+	"testb $2,%b4\n\t"
+	"je 1f\n\t"
+	"movsw\n"
+	"1:\ttestb $1,%b4\n\t"
+	"je 2f\n\t"
+	"movsb\n"
+	"2:"
+	: "=&c" (d0), "=&D" (d1), "=&S" (d2)
+	:"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
+	: "memory");
+return (to);
+}
+
+/* Even with __builtin_ the compiler may decide to use the out of line
+   function. */
+
+#define __HAVE_ARCH_MEMCPY 1
+extern void *__memcpy(void *to, const void *from, size_t len); 
+#define memcpy(dst,src,len) \
+	({ size_t __len = (len);				\
+	   void *__ret;						\
+	   if (__builtin_constant_p(len) && __len >= 64)	\
+		 __ret = __memcpy((dst),(src),__len);		\
+	   else							\
+		 __ret = __builtin_memcpy((dst),(src),__len);	\
+	   __ret; }) 
+
+
+#define __HAVE_ARCH_MEMSET
+#define memset __builtin_memset
+
+#define __HAVE_ARCH_MEMMOVE
+void * memmove(void * dest,const void *src,size_t count);
+
+#endif /* __KERNEL__ */
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/system.h linux-2.4.20/include/asm-x86_64/system.h
--- linux-2.4.19/include/asm-x86_64/system.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/system.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,285 @@
+#ifndef __ASM_SYSTEM_H
+#define __ASM_SYSTEM_H
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_SMP
+#define LOCK_PREFIX "lock ; "
+#else
+#define LOCK_PREFIX ""
+#endif
+
+#define prepare_to_switch() do {} while(0)
+
+#define __STR(x) #x
+#define STR(x) __STR(x)
+
+#define __PUSH(x) "pushq %%" __STR(x) "\n\t"
+#define __POP(x)  "popq  %%" __STR(x) "\n\t"
+
+/* frame pointer must be last for get_wchan */
+#define SAVE_CONTEXT \
+	__PUSH(rsi) __PUSH(rdi) \
+    __PUSH(r12) __PUSH(r13) __PUSH(r14) __PUSH(r15)  \
+	__PUSH(rdx) __PUSH(rcx) __PUSH(r8) __PUSH(r9) __PUSH(r10) __PUSH(r11)  \
+	__PUSH(rbx) __PUSH(rbp) 
+#define RESTORE_CONTEXT \
+	__POP(rbp) __POP(rbx) \
+	__POP(r11) __POP(r10) __POP(r9) __POP(r8) __POP(rcx) __POP(rdx) \
+	__POP(r15) __POP(r14) __POP(r13) __POP(r12) \
+	__POP(rdi) __POP(rsi)
+
+#define switch_to(prev,next,last) do { void *l; \
+	asm volatile(SAVE_CONTEXT					\
+		     "movq %%rsp,%0\n\t"	/* save RSP */		\
+		     "movq %3,%%rsp\n\t"	/* restore RSP */	\
+		     "leaq 1f(%%rip),%%rax\n\t"				\
+		     "movq %%rax,%1\n\t"	/* save RIP */		\
+		     "pushq %4\n\t"		/* setup new RIP */	\
+		     "jmp __switch_to\n\t"				\
+		     "1:\n\t"						\
+		     RESTORE_CONTEXT					\
+		     :"=m" (prev->thread.rsp),"=m" (prev->thread.rip), "=a" (l) \
+		     :"m" (next->thread.rsp),"m" (next->thread.rip),	\
+		      "S" (next), "D" (prev)				\
+		     :"memory","cc");					\
+	last = l; 							\
+} while(0)
+		     
+extern void load_gs_index(unsigned); 
+
+/*
+ * Load a segment. Fall back on loading the zero
+ * segment if something goes wrong..
+ */
+#define loadsegment(seg,value)	\
+	asm volatile("\n"			\
+		"1:\t"				\
+		"movl %0,%%" #seg "\n"		\
+		"2:\n"				\
+		".section .fixup,\"ax\"\n"	\
+		"3:\t"				\
+		"pushq $0 ; popq %% " #seg "\n\t"	\
+		"jmp 2b\n"			\
+		".previous\n"			\
+		".section __ex_table,\"a\"\n\t"	\
+		".align 4\n\t"			\
+		".quad 1b,3b\n"			\
+		".previous"			\
+		: :"r" ((int)(value)))
+
+#define set_debug(value,register) \
+                __asm__("movq %0,%%db" #register  \
+		: /* no output */ \
+		:"r" ((unsigned long) value))
+
+
+/*
+ * Clear and set 'TS' bit respectively
+ */
+#define clts() __asm__ __volatile__ ("clts")
+#define read_cr0() ({ \
+	unsigned long __dummy; \
+	__asm__( \
+		"movq %%cr0,%0\n\t" \
+		:"=r" (__dummy)); \
+	__dummy; \
+})
+#define write_cr0(x) \
+	__asm__("movq %0,%%cr0": :"r" (x));
+
+#define read_cr4() ({ \
+	unsigned long __dummy; \
+	__asm__( \
+		"movq %%cr4,%0\n\t" \
+		:"=r" (__dummy)); \
+	__dummy; \
+})
+#define write_cr4(x) \
+	__asm__("movq %0,%%cr4": :"r" (x));
+#define stts() write_cr0(8 | read_cr0())
+
+#define wbinvd() \
+	__asm__ __volatile__ ("wbinvd": : :"memory");
+
+#endif	/* __KERNEL__ */
+
+#define nop() __asm__ __volatile__ ("nop")
+
+#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
+
+#define tas(ptr) (xchg((ptr),1))
+
+#define __xg(x) ((volatile long *)(x))
+
+extern inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
+{
+	*ptr = val;
+}
+
+#define _set_64bit set_64bit
+
+/*
+ * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
+ * Note 2: xchg has side effect, so that attribute volatile is necessary,
+ *	  but generally the primitive is invalid, *ptr is output argument. --ANK
+ */
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+{
+	switch (size) {
+		case 1:
+			__asm__ __volatile__("xchgb %b0,%1"
+				:"=q" (x)
+				:"m" (*__xg(ptr)), "0" (x)
+				:"memory");
+			break;
+		case 2:
+			__asm__ __volatile__("xchgw %w0,%1"
+				:"=r" (x)
+				:"m" (*__xg(ptr)), "0" (x)
+				:"memory");
+			break;
+		case 4:
+			__asm__ __volatile__("xchgl %k0,%1"
+				:"=r" (x)
+				:"m" (*__xg(ptr)), "0" (x)
+				:"memory");
+			break;
+		case 8:
+			__asm__ __volatile__("xchgq %0,%1"
+				:"=r" (x)
+				:"m" (*__xg(ptr)), "0" (x)
+				:"memory");
+			break;
+	}
+	return x;
+}
+
+/*
+ * Atomic compare and exchange.  Compare OLD with MEM, if identical,
+ * store NEW in MEM.  Return the initial value in MEM.  Success is
+ * indicated by comparing RETURN with OLD.
+ */
+
+#define __HAVE_ARCH_CMPXCHG 1
+
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+				      unsigned long new, int size)
+{
+	unsigned long prev;
+	switch (size) {
+	case 1:
+		__asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 2:
+		__asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 4:
+		__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %k1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 8:
+		__asm__ __volatile__(LOCK_PREFIX "cmpxchgq %1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	}
+	return old;
+}
+
+#define cmpxchg(ptr,o,n)\
+	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+					(unsigned long)(n),sizeof(*(ptr))))
+
+
+#ifdef CONFIG_SMP
+#define smp_mb()	mb()
+#define smp_rmb()	rmb()
+#define smp_wmb()	wmb()
+#else
+#define smp_mb()	barrier()
+#define smp_rmb()	barrier()
+#define smp_wmb()	barrier()
+#endif
+
+    
+/*
+ * Force strict CPU ordering.
+ * And yes, this is required on UP too when we're talking
+ * to devices.
+ *
+ * For now, "wmb()" doesn't actually do anything, as all
+ * Intel CPU's follow what Intel calls a *Processor Order*,
+ * in which all writes are seen in the program order even
+ * outside the CPU.
+ *
+ * I expect future Intel CPU's to have a weaker ordering,
+ * but I'd also expect them to finally get their act together
+ * and add some real memory barriers if so.
+ */
+#define mb() 	asm volatile("mfence":::"memory")
+#define rmb()	asm volatile("lfence":::"memory")
+#define wmb()	asm volatile("sfence":::"memory")
+#define set_mb(var, value) do { xchg(&var, value); } while (0)
+#define set_wmb(var, value) do { var = value; wmb(); } while (0)
+
+#define warn_if_not_ulong(x) do { unsigned long foo; (void) (&(x) == &foo); } while (0)
+
+/* interrupt control.. */
+#define __save_flags(x)		do { warn_if_not_ulong(x); __asm__ __volatile__("# save_flags \n\t pushfq ; popq %q0":"=g" (x): /* no input */ :"memory"); } while (0)
+#define __restore_flags(x) 	__asm__ __volatile__("# restore_flags \n\t pushq %0 ; popfq": /* no output */ :"g" (x):"memory", "cc")
+#define __cli() 		__asm__ __volatile__("cli": : :"memory")
+#define __sti()			__asm__ __volatile__("sti": : :"memory")
+/* used in the idle loop; sti takes one instruction cycle to complete */
+#define safe_halt()		__asm__ __volatile__("sti; hlt": : :"memory")
+
+/* For spinlocks etc */
+#define local_irq_save(x) 	do { warn_if_not_ulong(x); __asm__ __volatile__("# local_irq_save \n\t pushfq ; popq %0 ; cli":"=g" (x): /* no input */ :"memory"); } while (0)
+#define local_irq_restore(x)	__asm__ __volatile__("# local_irq_restore \n\t pushq %0 ; popfq": /* no output */ :"g" (x):"memory")
+#define local_irq_disable()	__cli()
+#define local_irq_enable()	__sti()
+
+#ifdef CONFIG_SMP
+
+extern void __global_cli(void);
+extern void __global_sti(void);
+extern unsigned long __global_save_flags(void);
+extern void __global_restore_flags(unsigned long);
+#define cli() __global_cli()
+#define sti() __global_sti()
+#define save_flags(x) ((x)=__global_save_flags())
+#define restore_flags(x) __global_restore_flags(x)
+
+#else
+
+#define cli() __cli()
+#define sti() __sti()
+#define save_flags(x) __save_flags(x)
+#define restore_flags(x) __restore_flags(x)
+
+#endif
+
+/* Default simics "magic" breakpoint */
+#define icebp() asm volatile("xchg %%bx,%%bx" ::: "ebx")
+
+/*
+ * disable hlt during certain critical i/o operations
+ */
+#define HAVE_DISABLE_HLT
+void disable_hlt(void);
+void enable_hlt(void);
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/termbits.h linux-2.4.20/include/asm-x86_64/termbits.h
--- linux-2.4.19/include/asm-x86_64/termbits.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/termbits.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,172 @@
+#ifndef __ARCH_X8664_TERMBITS_H__
+#define __ARCH_X8664_TERMBITS_H__
+
+#include <linux/posix_types.h>
+
+typedef unsigned char	cc_t;
+typedef unsigned int	speed_t;
+typedef unsigned int	tcflag_t;
+
+#define NCCS 19
+struct termios {
+	tcflag_t c_iflag;		/* input mode flags */
+	tcflag_t c_oflag;		/* output mode flags */
+	tcflag_t c_cflag;		/* control mode flags */
+	tcflag_t c_lflag;		/* local mode flags */
+	cc_t c_line;			/* line discipline */
+	cc_t c_cc[NCCS];		/* control characters */
+};
+
+/* c_cc characters */
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VTIME 5
+#define VMIN 6
+#define VSWTC 7
+#define VSTART 8
+#define VSTOP 9
+#define VSUSP 10
+#define VEOL 11
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE 14
+#define VLNEXT 15
+#define VEOL2 16
+
+/* c_iflag bits */
+#define IGNBRK	0000001
+#define BRKINT	0000002
+#define IGNPAR	0000004
+#define PARMRK	0000010
+#define INPCK	0000020
+#define ISTRIP	0000040
+#define INLCR	0000100
+#define IGNCR	0000200
+#define ICRNL	0000400
+#define IUCLC	0001000
+#define IXON	0002000
+#define IXANY	0004000
+#define IXOFF	0010000
+#define IMAXBEL	0020000
+
+/* c_oflag bits */
+#define OPOST	0000001
+#define OLCUC	0000002
+#define ONLCR	0000004
+#define OCRNL	0000010
+#define ONOCR	0000020
+#define ONLRET	0000040
+#define OFILL	0000100
+#define OFDEL	0000200
+#define NLDLY	0000400
+#define   NL0	0000000
+#define   NL1	0000400
+#define CRDLY	0003000
+#define   CR0	0000000
+#define   CR1	0001000
+#define   CR2	0002000
+#define   CR3	0003000
+#define TABDLY	0014000
+#define   TAB0	0000000
+#define   TAB1	0004000
+#define   TAB2	0010000
+#define   TAB3	0014000
+#define   XTABS	0014000
+#define BSDLY	0020000
+#define   BS0	0000000
+#define   BS1	0020000
+#define VTDLY	0040000
+#define   VT0	0000000
+#define   VT1	0040000
+#define FFDLY	0100000
+#define   FF0	0000000
+#define   FF1	0100000
+
+/* c_cflag bit meaning */
+#define CBAUD	0010017
+#define  B0	0000000		/* hang up */
+#define  B50	0000001
+#define  B75	0000002
+#define  B110	0000003
+#define  B134	0000004
+#define  B150	0000005
+#define  B200	0000006
+#define  B300	0000007
+#define  B600	0000010
+#define  B1200	0000011
+#define  B1800	0000012
+#define  B2400	0000013
+#define  B4800	0000014
+#define  B9600	0000015
+#define  B19200	0000016
+#define  B38400	0000017
+#define EXTA B19200
+#define EXTB B38400
+#define CSIZE	0000060
+#define   CS5	0000000
+#define   CS6	0000020
+#define   CS7	0000040
+#define   CS8	0000060
+#define CSTOPB	0000100
+#define CREAD	0000200
+#define PARENB	0000400
+#define PARODD	0001000
+#define HUPCL	0002000
+#define CLOCAL	0004000
+#define CBAUDEX 0010000
+#define    B57600 0010001
+#define   B115200 0010002
+#define   B230400 0010003
+#define   B460800 0010004
+#define   B500000 0010005
+#define   B576000 0010006
+#define   B921600 0010007
+#define  B1000000 0010010
+#define  B1152000 0010011
+#define  B1500000 0010012
+#define  B2000000 0010013
+#define  B2500000 0010014
+#define  B3000000 0010015
+#define  B3500000 0010016
+#define  B4000000 0010017
+#define CIBAUD	  002003600000	/* input baud rate (not used) */
+#define CMSPAR	  010000000000		/* mark or space (stick) parity */
+#define CRTSCTS	  020000000000		/* flow control */
+
+/* c_lflag bits */
+#define ISIG	0000001
+#define ICANON	0000002
+#define XCASE	0000004
+#define ECHO	0000010
+#define ECHOE	0000020
+#define ECHOK	0000040
+#define ECHONL	0000100
+#define NOFLSH	0000200
+#define TOSTOP	0000400
+#define ECHOCTL	0001000
+#define ECHOPRT	0002000
+#define ECHOKE	0004000
+#define FLUSHO	0010000
+#define PENDIN	0040000
+#define IEXTEN	0100000
+
+/* tcflow() and TCXONC use these */
+#define	TCOOFF		0
+#define	TCOON		1
+#define	TCIOFF		2
+#define	TCION		3
+
+/* tcflush() and TCFLSH use these */
+#define	TCIFLUSH	0
+#define	TCOFLUSH	1
+#define	TCIOFLUSH	2
+
+/* tcsetattr uses these */
+#define	TCSANOW		0
+#define	TCSADRAIN	1
+#define	TCSAFLUSH	2
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/termios.h linux-2.4.20/include/asm-x86_64/termios.h
--- linux-2.4.19/include/asm-x86_64/termios.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/termios.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,108 @@
+#ifndef _X8664_TERMIOS_H
+#define _X8664_TERMIOS_H
+
+#include <asm/termbits.h>
+#include <asm/ioctls.h>
+
+struct winsize {
+	unsigned short ws_row;
+	unsigned short ws_col;
+	unsigned short ws_xpixel;
+	unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+	unsigned short c_iflag;		/* input mode flags */
+	unsigned short c_oflag;		/* output mode flags */
+	unsigned short c_cflag;		/* control mode flags */
+	unsigned short c_lflag;		/* local mode flags */
+	unsigned char c_line;		/* line discipline */
+	unsigned char c_cc[NCC];	/* control characters */
+};
+
+/* modem lines */
+#define TIOCM_LE	0x001
+#define TIOCM_DTR	0x002
+#define TIOCM_RTS	0x004
+#define TIOCM_ST	0x008
+#define TIOCM_SR	0x010
+#define TIOCM_CTS	0x020
+#define TIOCM_CAR	0x040
+#define TIOCM_RNG	0x080
+#define TIOCM_DSR	0x100
+#define TIOCM_CD	TIOCM_CAR
+#define TIOCM_RI	TIOCM_RNG
+#define TIOCM_OUT1	0x2000
+#define TIOCM_OUT2	0x4000
+#define TIOCM_LOOP	0x8000
+
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
+/* line disciplines */
+#define N_TTY		0
+#define N_SLIP		1
+#define N_MOUSE		2
+#define N_PPP		3
+#define N_STRIP		4
+#define N_AX25		5
+#define N_X25		6	/* X.25 async */
+#define N_6PACK		7
+#define N_MASC		8	/* Reserved for Mobitex module <kaz@cafe.net> */
+#define N_R3964		9	/* Reserved for Simatic R3964 module */
+#define N_PROFIBUS_FDL	10	/* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA		11	/* Linux IR - http://irda.sourceforge.net/ */
+#define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
+#define N_HDLC		13	/* synchronous HDLC */
+#define N_SYNC_PPP	14	/* synchronous PPP */
+#define N_HCI		15  /* Bluetooth HCI UART */
+
+#ifdef __KERNEL__
+
+/*	intr=^C		quit=^\		erase=del	kill=^U
+	eof=^D		vtime=\0	vmin=\1		sxtc=\0
+	start=^Q	stop=^S		susp=^Z		eol=\0
+	reprint=^R	discard=^U	werase=^W	lnext=^V
+	eol2=\0
+*/
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+
+/*
+ * Translate a "termio" structure into a "termios". Ugh.
+ */
+#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
+	unsigned short __tmp; \
+	get_user(__tmp,&(termio)->x); \
+	*(unsigned short *) &(termios)->x = __tmp; \
+}
+
+#define user_termio_to_kernel_termios(termios, termio) \
+({ \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
+	copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+})
+
+/*
+ * Translate a "termios" structure into a "termio". Ugh.
+ */
+#define kernel_termios_to_user_termio(termio, termios) \
+({ \
+	put_user((termios)->c_iflag, &(termio)->c_iflag); \
+	put_user((termios)->c_oflag, &(termio)->c_oflag); \
+	put_user((termios)->c_cflag, &(termio)->c_cflag); \
+	put_user((termios)->c_lflag, &(termio)->c_lflag); \
+	put_user((termios)->c_line,  &(termio)->c_line); \
+	copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
+})
+
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+
+#endif	/* __KERNEL__ */
+
+#endif	/* _X8664_TERMIOS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/timex.h linux-2.4.20/include/asm-x86_64/timex.h
--- linux-2.4.19/include/asm-x86_64/timex.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/timex.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,66 @@
+/*
+ * linux/include/asm-x8664/timex.h
+ *
+ * x8664 architecture timex specifications
+ */
+#ifndef _ASMx8664_TIMEX_H
+#define _ASMx8664_TIMEX_H
+
+#include <linux/config.h>
+#include <asm/msr.h>
+#include <asm/vsyscall.h>
+
+#define CLOCK_TICK_RATE (hpet.address ? hpet.hz : 1193182L)
+#define FINETUNE	((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
+			1000000 / CLOCK_TICK_RATE) << (SHIFT_SCALE - SHIFT_HZ)) / HZ)
+
+/*
+ * We only use the low 32 bits, and we'd simply better make sure
+ * that we reschedule before that wraps. Scheduling at least every
+ * four billion cycles just basically sounds like a good idea,
+ * regardless of how fast the machine is.
+ */
+typedef unsigned long long cycles_t;
+
+extern cycles_t cacheflush_time;
+
+static inline cycles_t get_cycles (void)
+{
+	unsigned long long ret;
+	rdtscll(ret);
+	return ret;
+}
+
+extern unsigned int cpu_khz;
+
+/*
+ * Documentation on HPET can be found at:
+ *      http://www.intel.com/ial/home/sp/pcmmspec.htm
+ *      ftp://download.intel.com/ial/home/sp/mmts098.pdf
+ */
+
+#define HPET_ID		0x000
+#define HPET_PERIOD	0x004
+#define HPET_CFG	0x010
+#define HPET_STATUS	0x020
+#define HPET_COUNTER	0x0f0
+#define HPET_T0_CFG	0x100
+#define HPET_T0_CMP	0x108
+#define HPET_T0_ROUTE	0x110
+
+#define HPET_ID_VENDOR	0xffff0000
+#define HPET_ID_LEGSUP	0x00008000
+#define HPET_ID_NUMBER	0x00000f00
+#define HPET_ID_REV	0x000000ff
+
+#define HPET_CFG_ENABLE	0x001
+#define HPET_CFG_LEGACY	0x002
+
+#define HPET_T0_ENABLE		0x004
+#define HPET_T0_PERIODIC	0x008
+#define HPET_T0_SETVAL		0x040
+#define HPET_T0_32BIT		0x100
+
+extern struct hpet_data hpet;
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/tlb.h linux-2.4.20/include/asm-x86_64/tlb.h
--- linux-2.4.19/include/asm-x86_64/tlb.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/tlb.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/types.h linux-2.4.20/include/asm-x86_64/types.h
--- linux-2.4.19/include/asm-x86_64/types.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/types.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,47 @@
+#ifndef _X86_64_TYPES_H
+#define _X86_64_TYPES_H
+
+typedef unsigned short umode_t;
+
+/*
+ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
+ * header files exported to user space
+ */
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+typedef __signed__ long long __s64;
+typedef unsigned long long __u64;
+
+/*
+ * These aren't exported outside the kernel to avoid name space clashes
+ */
+#ifdef __KERNEL__
+
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+#define BITS_PER_LONG 64
+
+typedef u64 dma64_addr_t;
+typedef u64 dma_addr_t;
+
+#endif /* __KERNEL__ */
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/uaccess.h linux-2.4.20/include/asm-x86_64/uaccess.h
--- linux-2.4.19/include/asm-x86_64/uaccess.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/uaccess.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,254 @@
+#ifndef __X86_64_UACCESS_H
+#define __X86_64_UACCESS_H
+
+/*
+ * User space memory access functions
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/prefetch.h>
+#include <asm/page.h>
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1
+
+/*
+ * The fs value determines whether argument validity checking should be
+ * performed or not.  If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons, these macros are grossly misnamed.
+ */
+
+#define MAKE_MM_SEG(s)	((mm_segment_t) { (s) })
+
+#define KERNEL_DS	MAKE_MM_SEG(0xFFFFFFFFFFFFFFFF)
+#define USER_DS		MAKE_MM_SEG(PAGE_OFFSET)
+
+#define get_ds()	(KERNEL_DS)
+#define get_fs()	(current->addr_limit)
+#define set_fs(x)	(current->addr_limit = (x))
+
+#define segment_eq(a,b)	((a).seg == (b).seg)
+
+#define __addr_ok(addr) (!((unsigned long)(addr) & (current->addr_limit.seg)))
+
+/*
+ * Uhhuh, this needs 65-bit arithmetic. We have a carry..
+ */
+#define __range_not_ok(addr,size) ({ \
+	unsigned long flag,sum; \
+	asm("# range_ok\n\r" \
+		"addq %3,%1 ; sbbq %0,%0 ; cmpq %1,%4 ; sbbq $0,%0"  \
+		:"=&r" (flag), "=r" (sum) \
+		:"1" (addr),"g" ((long)(size)),"g" (current->addr_limit.seg)); \
+	flag; })
+
+#define access_ok(type,addr,size) (__range_not_ok(addr,size) == 0)
+
+extern inline int verify_area(int type, const void * addr, unsigned long size)
+{
+	return access_ok(type,addr,size) ? 0 : -EFAULT;
+}
+
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue.  No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path.  This means when everything is well,
+ * we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry
+{
+	unsigned long insn, fixup;
+};
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+
+/*
+ * These are the main single-value transfer routines.  They automatically
+ * use the right size if we just have the right pointer type.
+ *
+ * This gets kind of ugly. We want to return _two_ values in "get_user()"
+ * and yet we don't want to do any pointers, because that is too much
+ * of a performance impact. Thus we have a few rather ugly macros here,
+ * and hide all the uglyness from the user.
+ *
+ * The "__xxx" versions of the user access functions are versions that
+ * do not verify the address space, that must have been done previously
+ * with a separate "access_ok()" call (this is used when we do multiple
+ * accesses to the same area of user memory).
+ */
+
+extern void __get_user_1(void);
+extern void __get_user_2(void);
+extern void __get_user_4(void);
+extern void __get_user_8(void);
+
+#define __get_user_x(size,ret,x,ptr) \
+	__asm__ __volatile__("call __get_user_" #size \
+		:"=a" (ret),"=d" (x) \
+		:"0" (ptr) \
+		:"rbx")
+
+/* Careful: we have to cast the result to the type of the pointer for sign reasons */
+#define get_user(x,ptr)							\
+({	long __ret_gu,__val_gu;						\
+	switch(sizeof (*(ptr))) {					\
+	case 1:  __get_user_x(1,__ret_gu,__val_gu,ptr); break;		\
+	case 2:  __get_user_x(2,__ret_gu,__val_gu,ptr); break;		\
+	case 4:  __get_user_x(4,__ret_gu,__val_gu,ptr); break;		\
+	case 8:  __get_user_x(8,__ret_gu,__val_gu,ptr); break;		\
+	default: __get_user_bad(); break;				\
+	}								\
+	(x) = (__typeof__(*(ptr)))__val_gu;				\
+	__ret_gu;							\
+})
+
+extern void __put_user_1(void);
+extern void __put_user_2(void);
+extern void __put_user_4(void);
+extern void __put_user_8(void);
+
+extern void __put_user_bad(void);
+
+#define __put_user_x(size,ret,x,ptr)					\
+	__asm__ __volatile__("call __put_user_" #size			\
+		:"=a" (ret)						\
+		:"0" (ptr),"d" (x)					\
+		:"rbx")
+
+#define put_user(x,ptr)							\
+  __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+#define __get_user(x,ptr) \
+  __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+#define __put_user(x,ptr) \
+  __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+#define __put_user_nocheck(x,ptr,size)			\
+({							\
+	long __pu_err;					\
+	__put_user_size((x),(ptr),(size),__pu_err);	\
+	__pu_err;					\
+})
+
+
+#define __put_user_check(x,ptr,size)			\
+({							\
+	long __pu_err = -EFAULT;			\
+	__typeof__(*(ptr)) *__pu_addr = (ptr);		\
+	if (access_ok(VERIFY_WRITE,__pu_addr,size))	\
+		__put_user_size((x),__pu_addr,(size),__pu_err);	\
+	__pu_err;					\
+})
+
+#define __put_user_size(x,ptr,size,retval)				\
+do {									\
+	retval = 0;							\
+	switch (size) {							\
+	  case 1: __put_user_asm(x,ptr,retval,"b","b","iq"); break;	\
+	  case 2: __put_user_asm(x,ptr,retval,"w","w","ir"); break;	\
+	  case 4: __put_user_asm(x,ptr,retval,"l","k","ir"); break;	\
+	  case 8: __put_user_asm(x,ptr,retval,"q","","ir"); break;	\
+	  default: __put_user_bad();					\
+	}								\
+} while (0)
+
+/* FIXME: this hack is definitely wrong -AK */
+struct __large_struct { unsigned long buf[100]; };
+#define __m(x) (*(struct __large_struct *)(x))
+
+/*
+ * Tell gcc we read from memory instead of writing: this is because
+ * we do not write to any memory gcc knows about, so there are no
+ * aliasing issues.
+ */
+#define __put_user_asm(x, addr, err, itype, rtype, ltype)	\
+	__asm__ __volatile__(				\
+		"1:	mov"itype" %"rtype"1,%2\n"	\
+		"2:\n"							\
+		".section .fixup,\"ax\"\n"		\
+		"3:	movq %3,%0\n"				\
+		"	jmp 2b\n"					\
+		".previous\n"					\
+		".section __ex_table,\"a\"\n"	\
+		"	.align 8\n"					\
+		"	.quad 1b,3b\n"				\
+		".previous"						\
+		: "=r"(err)						\
+		: ltype (x), "m"(__m(addr)), "i"(-EFAULT), "0"(err))
+
+
+#define __get_user_nocheck(x,ptr,size)				\
+({								\
+	long __gu_err, __gu_val;				\
+	__get_user_size(__gu_val,(ptr),(size),__gu_err);	\
+	(x) = (__typeof__(*(ptr)))__gu_val;			\
+	__gu_err;						\
+})
+
+extern long __get_user_bad(void);
+
+#define __get_user_size(x,ptr,size,retval)				\
+do {									\
+	retval = 0;							\
+	switch (size) {							\
+	  case 1: __get_user_asm(x,ptr,retval,"b","b","=q"); break;	\
+	  case 2: __get_user_asm(x,ptr,retval,"w","w","=r"); break;	\
+	  case 4: __get_user_asm(x,ptr,retval,"l","k","=r"); break;	\
+	  case 8: __get_user_asm(x,ptr,retval,"q","","=r"); break;	\
+	  default: (x) = __get_user_bad();				\
+	}								\
+} while (0)
+
+#define __get_user_asm(x, addr, err, itype, rtype, ltype)	\
+	__asm__ __volatile__(					\
+		"1:	mov"itype" %2,%"rtype"1\n"		\
+		"2:\n"						\
+		".section .fixup,\"ax\"\n"			\
+		"3:	mov %3,%0\n"				\
+		"	xor"itype" %"rtype"1,%"rtype"1\n"	\
+		"	jmp 2b\n"				\
+		".previous\n"					\
+		".section __ex_table,\"a\"\n"			\
+		"	.align 8\n"				\
+		"	.quad 1b,3b\n"				\
+		".previous"					\
+		: "=r"(err), ltype (x)				\
+		: "m"(__m(addr)), "i"(-EFAULT), "0"(err))
+
+/*
+ * Copy To/From Userspace
+ * 
+ * This relies on an optimized common worker function.
+ * 
+ * Could do special inline versions for small constant copies, but avoid this
+ * for now. It's not clear it is worth it. 
+ */
+
+extern unsigned long copy_user_generic(void *to, const void *from, unsigned len); 
+
+extern unsigned long copy_to_user(void *to, const void *from, unsigned len); 
+extern unsigned long copy_from_user(void *to, const void *from, unsigned len); 
+#define __copy_to_user copy_user_generic
+#define __copy_from_user copy_user_generic
+
+long strncpy_from_user(char *dst, const char *src, long count);
+long __strncpy_from_user(char *dst, const char *src, long count);
+#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
+long strnlen_user(const char *str, long n);
+unsigned long clear_user(void *mem, unsigned long len);
+unsigned long __clear_user(void *mem, unsigned long len);
+
+#endif /* __X86_64_UACCESS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/ucontext.h linux-2.4.20/include/asm-x86_64/ucontext.h
--- linux-2.4.19/include/asm-x86_64/ucontext.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/ucontext.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,12 @@
+#ifndef _ASMX8664_UCONTEXT_H
+#define _ASMX8664_UCONTEXT_H
+
+struct ucontext {
+	unsigned long	  uc_flags;
+	struct ucontext  *uc_link;
+	stack_t		  uc_stack;
+	struct sigcontext uc_mcontext;
+	sigset_t	  uc_sigmask;	/* mask last for extensibility */
+};
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/unaligned.h linux-2.4.20/include/asm-x86_64/unaligned.h
--- linux-2.4.19/include/asm-x86_64/unaligned.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/unaligned.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,37 @@
+#ifndef __X8664_UNALIGNED_H
+#define __X8664_UNALIGNED_H
+
+/*
+ * The x86-64 can do unaligned accesses itself. 
+ *
+ * The strange macros are there to make sure these can't
+ * be misused in a way that makes them not work on other
+ * architectures where unaligned accesses aren't as simple.
+ */
+
+/**
+ * get_unaligned - get value from possibly mis-aligned location
+ * @ptr: pointer to value
+ *
+ * This macro should be used for accessing values larger in size than 
+ * single bytes at locations that are expected to be improperly aligned, 
+ * e.g. retrieving a u16 value from a location not u16-aligned.
+ *
+ * Note that unaligned accesses can be very expensive on some architectures.
+ */
+#define get_unaligned(ptr) (*(ptr))
+
+/**
+ * put_unaligned - put value to a possibly mis-aligned location
+ * @val: value to place
+ * @ptr: pointer to location
+ *
+ * This macro should be used for placing values larger in size than 
+ * single bytes at locations that are expected to be improperly aligned, 
+ * e.g. writing a u16 value to a location not u16-aligned.
+ *
+ * Note that unaligned accesses can be very expensive on some architectures.
+ */
+#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/unistd.h linux-2.4.20/include/asm-x86_64/unistd.h
--- linux-2.4.19/include/asm-x86_64/unistd.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/unistd.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,686 @@
+#ifndef _ASM_X86_64_UNISTD_H_
+#define _ASM_X86_64_UNISTD_H_
+
+#ifndef __SYSCALL
+#define __SYSCALL(a,b) 
+#endif
+
+/*
+ * This file contains the system call numbers.
+ * 
+ * Note: holes are not allowed.
+ */
+
+/* at least 8 syscall per cacheline */
+#define __NR_read                                0
+__SYSCALL(__NR_read, sys_read)
+#define __NR_write                               1
+__SYSCALL(__NR_write, sys_write)
+#define __NR_open                                2
+__SYSCALL(__NR_open, sys_open)
+#define __NR_close                               3
+__SYSCALL(__NR_close, sys_close)
+#define __NR_stat                                4
+__SYSCALL(__NR_stat, sys_newstat)
+#define __NR_fstat                               5
+__SYSCALL(__NR_fstat, sys_newfstat)
+#define __NR_lstat                               6
+__SYSCALL(__NR_lstat, sys_newlstat)
+#define __NR_poll                                7
+__SYSCALL(__NR_poll, sys_poll)
+
+#define __NR_lseek                               8
+__SYSCALL(__NR_lseek, sys_lseek)
+#define __NR_mmap                                9
+__SYSCALL(__NR_mmap, sys_mmap)
+#define __NR_mprotect                           10
+__SYSCALL(__NR_mprotect, sys_mprotect)
+#define __NR_munmap                             11
+__SYSCALL(__NR_munmap, sys_munmap)
+#define __NR_brk                                12
+__SYSCALL(__NR_brk, sys_brk)
+#define __NR_rt_sigaction                       13
+__SYSCALL(__NR_rt_sigaction, sys_rt_sigaction)
+#define __NR_rt_sigprocmask                     14
+__SYSCALL(__NR_rt_sigprocmask, sys_rt_sigprocmask)
+#define __NR_rt_sigreturn                       15
+__SYSCALL(__NR_rt_sigreturn, stub_rt_sigreturn)
+
+#define __NR_ioctl                              16
+__SYSCALL(__NR_ioctl, sys_ioctl)
+#define __NR_pread                              17
+__SYSCALL(__NR_pread, sys_pread)
+#define __NR_pwrite                             18
+__SYSCALL(__NR_pwrite, sys_pwrite)
+#define __NR_readv                              19
+__SYSCALL(__NR_readv, sys_readv)
+#define __NR_writev                             20
+__SYSCALL(__NR_writev, sys_writev)
+#define __NR_access                             21
+__SYSCALL(__NR_access, sys_access)
+#define __NR_pipe                               22
+__SYSCALL(__NR_pipe, sys_pipe)
+#define __NR_select                             23
+__SYSCALL(__NR_select, sys_select)
+
+#define __NR_sched_yield                        24
+__SYSCALL(__NR_sched_yield, sys_sched_yield)
+#define __NR_mremap                             25
+__SYSCALL(__NR_mremap, sys_mremap)
+#define __NR_msync                              26
+__SYSCALL(__NR_msync, sys_msync)
+#define __NR_mincore                            27
+__SYSCALL(__NR_mincore, sys_mincore)
+#define __NR_madvise                            28
+__SYSCALL(__NR_madvise, sys_madvise)
+#define __NR_shmget                             29
+__SYSCALL(__NR_shmget, sys_shmget)
+#define __NR_shmat                              30
+__SYSCALL(__NR_shmat, wrap_sys_shmat)
+#define __NR_shmctl                             31
+__SYSCALL(__NR_shmctl, sys_shmctl)
+
+#define __NR_dup                                32
+__SYSCALL(__NR_dup, sys_dup)
+#define __NR_dup2                               33
+__SYSCALL(__NR_dup2, sys_dup2)
+#define __NR_pause                              34
+__SYSCALL(__NR_pause, sys_pause)
+#define __NR_nanosleep                          35
+__SYSCALL(__NR_nanosleep, sys_nanosleep)
+#define __NR_getitimer                          36
+__SYSCALL(__NR_getitimer, sys_getitimer)
+#define __NR_alarm                              37
+__SYSCALL(__NR_alarm, sys_alarm)
+#define __NR_setitimer                          38
+__SYSCALL(__NR_setitimer, sys_setitimer)
+#define __NR_getpid                             39
+__SYSCALL(__NR_getpid, sys_getpid)
+
+#define __NR_sendfile                           40
+__SYSCALL(__NR_sendfile, sys_sendfile)
+#define __NR_socket                             41
+__SYSCALL(__NR_socket, sys_socket)
+#define __NR_connect                            42
+__SYSCALL(__NR_connect, sys_connect)
+#define __NR_accept                             43
+__SYSCALL(__NR_accept, sys_accept)
+#define __NR_sendto                             44
+__SYSCALL(__NR_sendto, sys_sendto)
+#define __NR_recvfrom                           45
+__SYSCALL(__NR_recvfrom, sys_recvfrom)
+#define __NR_sendmsg                            46
+__SYSCALL(__NR_sendmsg, sys_sendmsg)
+#define __NR_recvmsg                            47
+__SYSCALL(__NR_recvmsg, sys_recvmsg)
+
+#define __NR_shutdown                           48
+__SYSCALL(__NR_shutdown, sys_shutdown)
+#define __NR_bind                               49
+__SYSCALL(__NR_bind, sys_bind)
+#define __NR_listen                             50
+__SYSCALL(__NR_listen, sys_listen)
+#define __NR_getsockname                        51
+__SYSCALL(__NR_getsockname, sys_getsockname)
+#define __NR_getpeername                        52
+__SYSCALL(__NR_getpeername, sys_getpeername)
+#define __NR_socketpair                         53
+__SYSCALL(__NR_socketpair, sys_socketpair)
+#define __NR_setsockopt                         54
+__SYSCALL(__NR_setsockopt, sys_setsockopt)
+#define __NR_getsockopt                         55
+__SYSCALL(__NR_getsockopt, sys_getsockopt)
+
+#define __NR_clone                              56
+__SYSCALL(__NR_clone, stub_clone)
+#define __NR_fork                               57
+__SYSCALL(__NR_fork, stub_fork) 
+#define __NR_vfork                              58
+__SYSCALL(__NR_vfork, stub_vfork)
+#define __NR_execve                             59
+__SYSCALL(__NR_execve, stub_execve)
+#define __NR_exit                               60
+__SYSCALL(__NR_exit, sys_exit)
+#define __NR_wait4                              61
+__SYSCALL(__NR_wait4, sys_wait4)
+#define __NR_kill                               62
+__SYSCALL(__NR_kill, sys_kill)
+#define __NR_uname                              63
+__SYSCALL(__NR_uname, sys_uname)
+
+#define __NR_semget                             64
+__SYSCALL(__NR_semget, sys_semget)
+#define __NR_semop                              65
+__SYSCALL(__NR_semop, sys_semop)
+#define __NR_semctl                             66
+__SYSCALL(__NR_semctl, sys_semctl)
+#define __NR_shmdt                              67
+__SYSCALL(__NR_shmdt, sys_shmdt)
+#define __NR_msgget                             68
+__SYSCALL(__NR_msgget, sys_msgget)
+#define __NR_msgsnd                             69
+__SYSCALL(__NR_msgsnd, sys_msgsnd)
+#define __NR_msgrcv                             70
+__SYSCALL(__NR_msgrcv, sys_msgrcv)
+#define __NR_msgctl                             71
+__SYSCALL(__NR_msgctl, sys_msgctl)
+
+#define __NR_fcntl                              72
+__SYSCALL(__NR_fcntl, sys_fcntl)
+#define __NR_flock                              73
+__SYSCALL(__NR_flock, sys_flock)
+#define __NR_fsync                              74
+__SYSCALL(__NR_fsync, sys_fsync)
+#define __NR_fdatasync                          75
+__SYSCALL(__NR_fdatasync, sys_fdatasync)
+#define __NR_truncate                           76
+__SYSCALL(__NR_truncate, sys_truncate)
+#define __NR_ftruncate                          77
+__SYSCALL(__NR_ftruncate, sys_ftruncate)
+#define __NR_getdents                           78
+__SYSCALL(__NR_getdents, sys_getdents)
+#define __NR_getcwd                             79
+__SYSCALL(__NR_getcwd, sys_getcwd)
+
+#define __NR_chdir                              80
+__SYSCALL(__NR_chdir, sys_chdir)
+#define __NR_fchdir                             81
+__SYSCALL(__NR_fchdir, sys_fchdir)
+#define __NR_rename                             82
+__SYSCALL(__NR_rename, sys_rename)
+#define __NR_mkdir                              83
+__SYSCALL(__NR_mkdir, sys_mkdir)
+#define __NR_rmdir                              84
+__SYSCALL(__NR_rmdir, sys_rmdir)
+#define __NR_creat                              85
+__SYSCALL(__NR_creat, sys_creat)
+#define __NR_link                               86
+__SYSCALL(__NR_link, sys_link)
+#define __NR_unlink                             87
+__SYSCALL(__NR_unlink, sys_unlink)
+
+#define __NR_symlink                            88
+__SYSCALL(__NR_symlink, sys_symlink)
+#define __NR_readlink                           89
+__SYSCALL(__NR_readlink, sys_readlink)
+#define __NR_chmod                              90
+__SYSCALL(__NR_chmod, sys_chmod)
+#define __NR_fchmod                             91
+__SYSCALL(__NR_fchmod, sys_fchmod)
+#define __NR_chown                              92
+__SYSCALL(__NR_chown, sys_chown)
+#define __NR_fchown                             93
+__SYSCALL(__NR_fchown, sys_fchown)
+#define __NR_lchown                             94
+__SYSCALL(__NR_lchown, sys_lchown)
+#define __NR_umask                              95
+__SYSCALL(__NR_umask, sys_umask)
+
+#define __NR_gettimeofday                       96
+__SYSCALL(__NR_gettimeofday, sys_gettimeofday)
+#define __NR_getrlimit                          97
+__SYSCALL(__NR_getrlimit, sys_getrlimit)
+#define __NR_getrusage                          98
+__SYSCALL(__NR_getrusage, sys_getrusage)
+#define __NR_sysinfo                            99
+__SYSCALL(__NR_sysinfo, sys_sysinfo)
+#define __NR_times                             100
+__SYSCALL(__NR_times, sys_times)
+#define __NR_ptrace                            101
+__SYSCALL(__NR_ptrace, sys_ptrace)
+#define __NR_getuid                            102
+__SYSCALL(__NR_getuid, sys_getuid)
+#define __NR_syslog                            103
+__SYSCALL(__NR_syslog, sys_syslog)
+
+/* at the very end the stuff that never runs during the benchmarks */
+#define __NR_getgid                            104
+__SYSCALL(__NR_getgid, sys_getgid)
+#define __NR_setuid                            105
+__SYSCALL(__NR_setuid, sys_setuid)
+#define __NR_setgid                            106
+__SYSCALL(__NR_setgid, sys_setgid)
+#define __NR_geteuid                           107
+__SYSCALL(__NR_geteuid, sys_geteuid)
+#define __NR_getegid                           108
+__SYSCALL(__NR_getegid, sys_getegid)
+#define __NR_setpgid                           109
+__SYSCALL(__NR_setpgid, sys_setpgid)
+#define __NR_getppid                           110
+__SYSCALL(__NR_getppid, sys_getppid)
+#define __NR_getpgrp                           111
+__SYSCALL(__NR_getpgrp, sys_getpgrp)
+
+#define __NR_setsid                            112
+__SYSCALL(__NR_setsid, sys_setsid)
+#define __NR_setreuid                          113
+__SYSCALL(__NR_setreuid, sys_setreuid)
+#define __NR_setregid                          114
+__SYSCALL(__NR_setregid, sys_setregid)
+#define __NR_getgroups                         115
+__SYSCALL(__NR_getgroups, sys_getgroups)
+#define __NR_setgroups                         116
+__SYSCALL(__NR_setgroups, sys_setgroups)
+#define __NR_setresuid                         117
+__SYSCALL(__NR_setresuid, sys_setresuid)
+#define __NR_getresuid                         118
+__SYSCALL(__NR_getresuid, sys_getresuid)
+#define __NR_setresgid                         119
+__SYSCALL(__NR_setresgid, sys_setresgid)
+
+#define __NR_getresgid                         120
+__SYSCALL(__NR_getresgid, sys_getresgid)
+#define __NR_getpgid                           121
+__SYSCALL(__NR_getpgid, sys_getpgid)
+#define __NR_setfsuid                          122
+__SYSCALL(__NR_setfsuid, sys_setfsuid)
+#define __NR_setfsgid                          123
+__SYSCALL(__NR_setfsgid, sys_setfsgid)
+#define __NR_getsid                            124
+__SYSCALL(__NR_getsid, sys_getsid)
+#define __NR_capget                            125
+__SYSCALL(__NR_capget, sys_capget)
+#define __NR_capset                            126
+__SYSCALL(__NR_capset, sys_capset)
+
+#define __NR_rt_sigpending                     127
+__SYSCALL(__NR_rt_sigpending, sys_rt_sigpending)
+#define __NR_rt_sigtimedwait                   128
+__SYSCALL(__NR_rt_sigtimedwait, sys_rt_sigtimedwait)
+#define __NR_rt_sigqueueinfo                   129
+__SYSCALL(__NR_rt_sigqueueinfo, sys_rt_sigqueueinfo)
+#define __NR_rt_sigsuspend                     130
+__SYSCALL(__NR_rt_sigsuspend, stub_rt_sigsuspend)
+#define __NR_sigaltstack                       131
+__SYSCALL(__NR_sigaltstack, stub_sigaltstack)
+#define __NR_utime                             132
+__SYSCALL(__NR_utime, sys_utime)
+#define __NR_mknod                             133
+__SYSCALL(__NR_mknod, sys_mknod)
+
+#define __NR_uselib                            134
+__SYSCALL(__NR_uselib, sys_uselib)
+#define __NR_personality                       135
+__SYSCALL(__NR_personality, sys_personality)
+
+#define __NR_ustat                             136
+__SYSCALL(__NR_ustat, sys_ustat)
+#define __NR_statfs                            137
+__SYSCALL(__NR_statfs, sys_statfs)
+#define __NR_fstatfs                           138
+__SYSCALL(__NR_fstatfs, sys_fstatfs)
+#define __NR_sysfs                             139
+__SYSCALL(__NR_sysfs, sys_sysfs)
+
+#define __NR_getpriority                       140
+__SYSCALL(__NR_getpriority, sys_getpriority)
+#define __NR_setpriority                       141
+__SYSCALL(__NR_setpriority, sys_setpriority)
+#define __NR_sched_setparam                    142
+__SYSCALL(__NR_sched_setparam, sys_sched_setparam)
+#define __NR_sched_getparam                    143
+__SYSCALL(__NR_sched_getparam, sys_sched_getparam)
+#define __NR_sched_setscheduler                144
+__SYSCALL(__NR_sched_setscheduler, sys_sched_setscheduler)
+#define __NR_sched_getscheduler                145
+__SYSCALL(__NR_sched_getscheduler, sys_sched_getscheduler)
+#define __NR_sched_get_priority_max            146
+__SYSCALL(__NR_sched_get_priority_max, sys_sched_get_priority_max)
+#define __NR_sched_get_priority_min            147
+__SYSCALL(__NR_sched_get_priority_min, sys_sched_get_priority_min)
+#define __NR_sched_rr_get_interval             148
+__SYSCALL(__NR_sched_rr_get_interval, sys_sched_rr_get_interval)
+
+#define __NR_mlock                             149
+__SYSCALL(__NR_mlock, sys_mlock)
+#define __NR_munlock                           150
+__SYSCALL(__NR_munlock, sys_munlock)
+#define __NR_mlockall                          151
+__SYSCALL(__NR_mlockall, sys_mlockall)
+#define __NR_munlockall                        152
+__SYSCALL(__NR_munlockall, sys_munlockall)
+
+#define __NR_vhangup                           153
+__SYSCALL(__NR_vhangup, sys_vhangup)
+
+#define __NR_modify_ldt                        154
+__SYSCALL(__NR_modify_ldt, sys_modify_ldt)
+
+#define __NR_pivot_root                        155
+__SYSCALL(__NR_pivot_root, sys_pivot_root)
+
+#define __NR__sysctl                           156
+__SYSCALL(__NR__sysctl, sys_sysctl)
+
+#define __NR_prctl                             157
+__SYSCALL(__NR_prctl, sys_prctl)
+#define __NR_arch_prctl                        158
+__SYSCALL(__NR_arch_prctl,	sys_arch_prctl) 
+
+#define __NR_adjtimex                          159
+__SYSCALL(__NR_adjtimex, sys_adjtimex)
+
+#define __NR_setrlimit                         160
+__SYSCALL(__NR_setrlimit, sys_setrlimit)
+
+#define __NR_chroot                            161
+__SYSCALL(__NR_chroot, sys_chroot)
+
+#define __NR_sync                              162
+__SYSCALL(__NR_sync, sys_sync)
+
+#define __NR_acct                              163
+__SYSCALL(__NR_acct, sys_acct)
+
+#define __NR_settimeofday                      164
+__SYSCALL(__NR_settimeofday, sys_settimeofday)
+
+#define __NR_mount                             165
+__SYSCALL(__NR_mount, sys_mount)
+#define __NR_umount2                           166
+__SYSCALL(__NR_umount2, sys_umount)
+
+#define __NR_swapon                            167
+__SYSCALL(__NR_swapon, sys_swapon)
+#define __NR_swapoff                           168
+__SYSCALL(__NR_swapoff, sys_swapoff)
+
+#define __NR_reboot                            169
+__SYSCALL(__NR_reboot, sys_reboot)
+
+#define __NR_sethostname                       170
+__SYSCALL(__NR_sethostname, sys_sethostname)
+#define __NR_setdomainname                     171
+__SYSCALL(__NR_setdomainname, sys_setdomainname)
+
+#define __NR_iopl                              172
+__SYSCALL(__NR_iopl, stub_iopl)
+#define __NR_ioperm                            173
+__SYSCALL(__NR_ioperm, sys_ioperm)
+
+#define __NR_create_module                     174
+__SYSCALL(__NR_create_module, sys_create_module)
+#define __NR_init_module                       175
+__SYSCALL(__NR_init_module, sys_init_module)
+#define __NR_delete_module                     176
+__SYSCALL(__NR_delete_module, sys_delete_module)
+#define __NR_get_kernel_syms                   177
+__SYSCALL(__NR_get_kernel_syms, sys_get_kernel_syms)
+#define __NR_query_module                      178
+__SYSCALL(__NR_query_module, sys_query_module)
+
+#define __NR_quotactl                          179
+__SYSCALL(__NR_quotactl, sys_quotactl)
+
+#define __NR_nfsservctl                        180
+__SYSCALL(__NR_nfsservctl, sys_nfsservctl)
+
+#define __NR_getpmsg                           181
+__SYSCALL(__NR_getpmsg, sys_ni_syscall)
+#define __NR_putpmsg                           182
+__SYSCALL(__NR_putpmsg, sys_ni_syscall)
+
+#define __NR_afs_syscall                       183
+__SYSCALL(__NR_afs_syscall, sys_ni_syscall)
+
+#define __NR_tuxcall      		184 /* reserved for tux */
+__SYSCALL(__NR_tuxcall, sys_ni_syscall)
+
+#define __NR_security			185 /* reserved for security */
+__SYSCALL(__NR_security, sys_ni_syscall)
+
+#define __NR_gettid		186
+__SYSCALL(__NR_gettid, sys_gettid)
+
+#define __NR_readahead		187
+__SYSCALL(__NR_readahead, sys_readahead)
+
+#define __NR_setxattr		188
+__SYSCALL(__NR_setxattr, sys_ni_syscall)
+#define __NR_lsetxattr		189
+__SYSCALL(__NR_lsetxattr, sys_ni_syscall)
+#define __NR_fsetxattr		190
+__SYSCALL(__NR_fsetxattr, sys_ni_syscall)
+#define __NR_getxattr		191
+__SYSCALL(__NR_getxattr, sys_ni_syscall)
+#define __NR_lgetxattr		192
+__SYSCALL(__NR_lgetxattr, sys_ni_syscall)
+#define __NR_fgetxattr		193
+__SYSCALL(__NR_fgetxattr, sys_ni_syscall) 
+#define __NR_listxattr		194
+__SYSCALL(__NR_listxattr, sys_ni_syscall) 
+#define __NR_llistxattr		195
+__SYSCALL(__NR_llistxattr, sys_ni_syscall) 
+#define __NR_flistxattr		196
+__SYSCALL(__NR_flistxattr, sys_ni_syscall) 
+#define __NR_removexattr	197
+__SYSCALL(__NR_removexattr, sys_ni_syscall) 
+#define __NR_lremovexattr	198
+__SYSCALL(__NR_lremovexattr, sys_ni_syscall) 
+#define __NR_fremovexattr	199
+__SYSCALL(__NR_fremovexattr, sys_ni_syscall) 
+#define __NR_tkill	200	/* 2.5 only */
+__SYSCALL(__NR_tkill, sys_ni_syscall) 
+#define __NR_time		201
+__SYSCALL(__NR_time, sys_time)
+#define __NR_futex		202 /* 2.5 only */
+__SYSCALL(__NR_futex, sys_ni_syscall)
+#define __NR_sched_setaffinity    203
+__SYSCALL(__NR_sched_setaffinity, sys_ni_syscall)
+#define __NR_sched_getaffinity     204
+__SYSCALL(__NR_sched_getaffinity, sys_ni_syscall)
+#define __NR_set_thread_area	205
+__SYSCALL(__NR_set_thread_area, sys_ni_syscall)
+#define __NR_io_setup	206
+__SYSCALL(__NR_io_setup, sys_ni_syscall)
+#define __NR_io_destroy	207
+__SYSCALL(__NR_io_destroy, sys_ni_syscall)
+#define __NR_io_getevents	208
+__SYSCALL(__NR_io_getevents, sys_ni_syscall)
+#define __NR_io_submit	209
+__SYSCALL(__NR_io_submit, sys_ni_syscall)
+#define __NR_io_cancel	210
+__SYSCALL(__NR_io_cancel, sys_ni_syscall)
+#define __NR_get_thread_area	211
+__SYSCALL(__NR_get_thread_area, sys_ni_syscall)
+
+#define __NR_syscall_max __NR_get_thread_area
+
+#ifndef __NO_STUBS
+
+#define __syscall_clobber "r11","rcx","memory" 
+
+#define __syscall_return(type, res) \
+do { \
+	if ((unsigned long)(res) >= (unsigned long)(-127)) { \
+		errno = -(res); \
+		res = -1; \
+	} \
+	return (type) (res); \
+} while (0)
+
+#ifndef __KERNEL_SYSCALLS__
+
+#define __syscall "syscall"
+
+
+#define _syscall0(type,name) \
+type name(void) \
+{ \
+long __res; \
+__asm__ volatile (__syscall \
+	: "=a" (__res) \
+	: "0" (__NR_##name) : __syscall_clobber ); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall1(type,name,type1,arg1) \
+type name(type1 arg1) \
+{ \
+long __res; \
+__asm__ volatile (__syscall \
+	: "=a" (__res) \
+	: "0" (__NR_##name),"D" ((long)(arg1)) : __syscall_clobber ); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2) \
+type name(type1 arg1,type2 arg2) \
+{ \
+long __res; \
+__asm__ volatile (__syscall \
+	: "=a" (__res) \
+	: "0" (__NR_##name),"D" ((long)(arg1)),"S" ((long)(arg2)) : __syscall_clobber ); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
+type name(type1 arg1,type2 arg2,type3 arg3) \
+{ \
+long __res; \
+__asm__ volatile (__syscall \
+	: "=a" (__res) \
+	: "0" (__NR_##name),"D" ((long)(arg1)),"S" ((long)(arg2)), \
+		  "d" ((long)(arg3)) : __syscall_clobber); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
+type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
+{ \
+long __res; \
+__asm__ volatile ("movq %5,%%r10 ;" __syscall \
+	: "=a" (__res) \
+	: "0" (__NR_##name),"D" ((long)(arg1)),"S" ((long)(arg2)), \
+	  "d" ((long)(arg3)),"g" ((long)(arg4)) : __syscall_clobber,"r10" ); \
+__syscall_return(type,__res); \
+} 
+
+#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
+	  type5,arg5) \
+type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
+{ \
+long __res; \
+__asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; " __syscall \
+	: "=a" (__res) \
+	: "0" (__NR_##name),"D" ((long)(arg1)),"S" ((long)(arg2)), \
+	  "d" ((long)(arg3)),"g" ((long)(arg4)),"g" ((long)(arg5)) : \
+	__syscall_clobber,"r8","r10" ); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
+	  type5,arg5,type6,arg6) \
+type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \
+{ \
+long __res; \
+__asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; movq %7,%%r9" __syscall \
+	: "=a" (__res) \
+	: "0" (__NR_##name),"D" ((long)(arg1)),"S" ((long)(arg2)), \
+	  "d" ((long)(arg3)),"g" ((long)(arg4)),"g" ((long)(arg5), \
+	  "g" ((long)(arg6),) : \
+	__syscall_clobber,"r8","r10","r9" ); \
+__syscall_return(type,__res); \
+}
+
+#else /* __KERNEL_SYSCALLS__ */
+
+/*
+ * we need this inline - forking from kernel space will result
+ * in NO COPY ON WRITE (!!!), until an execve is executed. This
+ * is no problem, but for the stack. This is handled by not letting
+ * main() use the stack at all after fork(). Thus, no function
+ * calls - which means inline code for fork too, as otherwise we
+ * would use the stack upon exit from 'fork()'.
+ *
+ * Actually only pause and fork are needed inline, so that there
+ * won't be any messing with the stack from main(), but we define
+ * some others too.
+ */
+#define __NR__exit __NR_exit
+
+extern long sys_pause(void);
+static inline long pause(void)
+{
+	return sys_pause();
+}
+
+extern long sys_sync(void);
+static inline long sync(void)
+{
+	return sys_sync();
+}
+
+extern pid_t sys_setsid(void);
+static inline pid_t setsid(void)
+{
+	return sys_setsid();
+}
+
+extern ssize_t sys_write(unsigned int, char *, size_t);
+static inline ssize_t write(unsigned int fd, char * buf, size_t count)
+{
+	return sys_write(fd, buf, count);
+}
+
+extern ssize_t sys_read(unsigned int, char *, size_t);
+static inline ssize_t read(unsigned int fd, char * buf, size_t count)
+{
+	return sys_read(fd, buf, count);
+}
+
+extern off_t sys_lseek(unsigned int, off_t, unsigned int);
+static inline off_t lseek(unsigned int fd, off_t offset, unsigned int origin)
+{
+	return sys_lseek(fd, offset, origin);
+}
+
+extern long sys_dup(unsigned int);
+static inline long dup(unsigned int fd)
+{
+	return sys_dup(fd);
+}
+
+/* implemented in asm in arch/x86_64/kernel/entry.S */
+extern long execve(char *, char **, char **);
+
+extern long sys_open(const char *, int, int);
+static inline long open(const char * filename, int flags, int mode)
+{
+	return sys_open(filename, flags, mode);
+}
+
+extern long sys_close(unsigned int);
+static inline long close(unsigned int fd)
+{
+	return sys_close(fd);
+}
+
+extern long sys_exit(int) __attribute__((noreturn));
+extern inline long exit(int error_code)
+{
+	sys_exit(error_code);
+}
+
+extern long sys_delete_module(const char *);
+static inline long delete_module(const char *name_user)
+{
+	return sys_delete_module(name_user);
+}
+
+extern long sys_wait4(pid_t, unsigned int *, int, struct rusage *);
+static inline pid_t waitpid(int pid, int * wait_stat, int flags)
+{
+	return sys_wait4(pid, wait_stat, flags, NULL);
+}
+
+static inline pid_t wait(int * wait_stat)
+{
+	return waitpid(-1,wait_stat,0);
+}
+
+#endif /* __KERNEL_SYSCALLS__ */
+
+#endif /* __NO_STUBS */
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/user.h linux-2.4.20/include/asm-x86_64/user.h
--- linux-2.4.19/include/asm-x86_64/user.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/user.h	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,111 @@
+#ifndef _X86_64_USER_H
+#define _X86_64_USER_H
+
+#include <asm/types.h>
+#include <asm/page.h>
+#include <linux/ptrace.h>
+/* Core file format: The core file is written in such a way that gdb
+   can understand it and provide useful information to the user.
+   There are quite a number of obstacles to being able to view the
+   contents of the floating point registers, and until these are
+   solved you will not be able to view the contents of them.
+   Actually, you can read in the core file and look at the contents of
+   the user struct to find out what the floating point registers
+   contain.
+
+   The actual file contents are as follows:
+   UPAGE: 1 page consisting of a user struct that tells gdb what is present
+   in the file.  Directly after this is a copy of the task_struct, which
+   is currently not used by gdb, but it may come in useful at some point.
+   All of the registers are stored as part of the upage.  The upage should
+   always be only one page.
+   DATA: The data area is stored.  We use current->end_text to
+   current->brk to pick up all of the user variables, plus any memory
+   that may have been malloced.  No attempt is made to determine if a page
+   is demand-zero or if a page is totally unused, we just cover the entire
+   range.  All of the addresses are rounded in such a way that an integral
+   number of pages is written.
+   STACK: We need the stack information in order to get a meaningful
+   backtrace.  We need to write the data from (esp) to
+   current->start_stack, so we round each of these off in order to be able
+   to write an integer number of pages.
+   The minimum core file size is 3 pages, or 12288 bytes.  */
+
+/*
+ * Pentium III FXSR, SSE support
+ *	Gareth Hughes <gareth@valinux.com>, May 2000
+ *
+ * Provide support for the GDB 5.0+ PTRACE_{GET|SET}FPXREGS requests for
+ * interacting with the FXSR-format floating point environment.  Floating
+ * point data can be accessed in the regular format in the usual manner,
+ * and both the standard and SIMD floating point data can be accessed via
+ * the new ptrace requests.  In either case, changes to the FPU environment
+ * will be reflected in the task's state as expected.
+ * 
+ * x86-64 support by Andi Kleen.
+ */
+
+/* This matches the 64bit FXSAVE format as defined by AMD. It is the same
+   as the 32bit format defined by Intel, except that the selector:offset pairs for
+   data and eip are replaced with flat 64bit pointers. */ 
+struct user_i387_struct {
+	unsigned short	cwd;
+	unsigned short	swd;
+	unsigned short	twd; /* Note this is not the same as the 32bit/x87/FSAVE twd */
+	unsigned short	fop;
+	u64	rip;
+	u64	rdp;
+	u32	mxcsr;
+	u32	mxcsr_mask;
+	u32	st_space[32];	/* 8*16 bytes for each FP-reg = 128 bytes */
+	u32	xmm_space[64];	/* 16*16 bytes for each XMM-reg = 256 bytes */
+	u32	padding[24];
+};
+
+/*
+ * Segment register layout in coredumps.
+ */
+struct user_regs_struct {
+	unsigned long r15,r14,r13,r12,rbp,rbx,r11,r10;
+	unsigned long r9,r8,rax,rcx,rdx,rsi,rdi,orig_rax;
+	unsigned long rip,cs,eflags;
+	unsigned long rsp,ss;
+  	unsigned long fs_base, gs_base;
+	unsigned long ds,es,fs,gs; 
+}; 
+
+/* When the kernel dumps core, it starts by dumping the user struct -
+   this will be used by gdb to figure out where the data and stack segments
+   are within the file, and what virtual addresses to use. */
+struct user{
+/* We start with the registers, to mimic the way that "memory" is returned
+   from the ptrace(3,...) function.  */
+  struct user_regs_struct regs;		/* Where the registers are actually stored */
+/* ptrace does not yet supply these.  Someday.... */
+  int u_fpvalid;		/* True if math co-processor being used. */
+                                /* for this mess. Not yet used. */
+  struct user_i387_struct i387;	/* Math Co-processor registers. */
+/* The rest of this junk is to help gdb figure out what goes where */
+  unsigned long int u_tsize;	/* Text segment size (pages). */
+  unsigned long int u_dsize;	/* Data segment size (pages). */
+  unsigned long int u_ssize;	/* Stack segment size (pages). */
+  unsigned long start_code;     /* Starting virtual address of text. */
+  unsigned long start_stack;	/* Starting virtual address of stack area.
+				   This is actually the bottom of the stack,
+				   the top of the stack is always found in the
+				   esp register.  */
+  long int signal;     		/* Signal that caused the core dump. */
+  int reserved;			/* No longer used */
+  struct user_pt_regs * u_ar0;	/* Used by gdb to help find the values for */
+				/* the registers. */
+  struct user_i387_struct* u_fpstate;	/* Math Co-processor pointer. */
+  unsigned long magic;		/* To uniquely identify a core file */
+  char u_comm[32];		/* User command that was responsible */
+  unsigned long u_debugreg[8];
+};
+#define NBPG PAGE_SIZE
+#define UPAGES 1
+#define HOST_TEXT_START_ADDR (u.start_code)
+#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+
+#endif /* _X86_64_USER_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/user32.h linux-2.4.20/include/asm-x86_64/user32.h
--- linux-2.4.19/include/asm-x86_64/user32.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/user32.h	2002-10-29 11:18:51.000000000 +0000
@@ -0,0 +1,69 @@
+#ifndef USER32_H
+#define USER32_H 1
+
+/* IA32 compatible user structures for ptrace. These should be used for 32bit coredumps too. */
+
+struct user_i387_ia32_struct {
+	u32	cwd;
+	u32	swd;
+	u32	twd;
+	u32	fip;
+	u32	fcs;
+	u32	foo;
+	u32	fos;
+	u32	st_space[20];   /* 8*10 bytes for each FP-reg = 80 bytes */
+};
+
+/* FSAVE frame with extensions */
+struct user32_fxsr_struct {
+	unsigned short	cwd;
+	unsigned short	swd;
+	unsigned short	twd;	/* not compatible to 64bit twd */
+	unsigned short	fop;
+	int	fip;
+	int	fcs;
+	int	foo;
+	int	fos;
+	int	mxcsr;
+	int	reserved;
+	int	st_space[32];	/* 8*16 bytes for each FP-reg = 128 bytes */
+	int	xmm_space[32];	/* 8*16 bytes for each XMM-reg = 128 bytes */
+	int	padding[56];
+};
+
+struct user_regs_struct32 {
+	__u32 ebx, ecx, edx, esi, edi, ebp, eax;
+	unsigned short ds, __ds, es, __es;
+	unsigned short fs, __fs, gs, __gs;
+	__u32 orig_eax, eip;
+	unsigned short cs, __cs;
+	__u32 eflags, esp;
+	unsigned short ss, __ss;
+};
+
+struct user32 {
+  struct user_regs_struct32 regs;		/* Where the registers are actually stored */
+  int u_fpvalid;		/* True if math co-processor being used. */
+                                /* for this mess. Not yet used. */
+  struct user_i387_ia32_struct i387;	/* Math Co-processor registers. */
+/* The rest of this junk is to help gdb figure out what goes where */
+  __u32 u_tsize;	/* Text segment size (pages). */
+  __u32 u_dsize;	/* Data segment size (pages). */
+  __u32 u_ssize;	/* Stack segment size (pages). */
+  __u32 start_code;     /* Starting virtual address of text. */
+  __u32 start_stack;	/* Starting virtual address of stack area.
+				   This is actually the bottom of the stack,
+				   the top of the stack is always found in the
+				   esp register.  */
+  __u32 signal;     		/* Signal that caused the core dump. */
+  int reserved;			/* No __u32er used */
+  __u32 u_ar0;	/* Used by gdb to help find the values for */
+				/* the registers. */
+  __u32 u_fpstate;	/* Math Co-processor pointer. */
+  __u32 magic;		/* To uniquely identify a core file */
+  char u_comm[32];		/* User command that was responsible */
+  int u_debugreg[8];
+};
+
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/vga.h linux-2.4.20/include/asm-x86_64/vga.h
--- linux-2.4.19/include/asm-x86_64/vga.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/vga.h	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,20 @@
+/*
+ *	Access to VGA videoram
+ *
+ *	(c) 1998 Martin Mares <mj@ucw.cz>
+ */
+
+#ifndef _LINUX_ASM_VGA_H_
+#define _LINUX_ASM_VGA_H_
+
+/*
+ *	On the PC, we can just recalculate addresses and then
+ *	access the videoram directly without any black magic.
+ */
+
+#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x)
+
+#define vga_readb(x) (*(x))
+#define vga_writeb(x,y) (*(y) = (x))
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/vsyscall.h linux-2.4.20/include/asm-x86_64/vsyscall.h
--- linux-2.4.19/include/asm-x86_64/vsyscall.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/vsyscall.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,57 @@
+#ifndef _ASM_X86_64_VSYSCALL_H_
+#define _ASM_X86_64_VSYSCALL_H_
+
+#include <linux/time.h>
+
+enum vsyscall_num {
+	__NR_vgettimeofday,
+	__NR_vtime,
+};
+
+#define VSYSCALL_START (-10UL << 20)
+#define VSYSCALL_SIZE 1024
+#define VSYSCALL_END (-2UL << 20)
+#define VSYSCALL_ADDR(vsyscall_nr) (VSYSCALL_START+VSYSCALL_SIZE*(vsyscall_nr))
+
+#ifdef __KERNEL__
+
+#define __section_hpet __attribute__ ((unused, __section__ (".hpet"), aligned(16)))
+#define __section_wall_jiffies __attribute__ ((unused, __section__ (".wall_jiffies"), aligned(16)))
+#define __section_jiffies __attribute__ ((unused, __section__ (".jiffies"), aligned(16)))
+#define __section_sys_tz __attribute__ ((unused, __section__ (".sys_tz"), aligned(16)))
+#define __section_xtime __attribute__ ((unused, __section__ (".xtime"), aligned(16)))
+#define __section_vxtime_sequence __attribute__ ((unused, __section__ (".vxtime_sequence"), aligned(16)))
+
+struct hpet_data {
+	long address;		/* base address */
+	unsigned long hz;	/* HPET clocks / sec */
+	int trigger;		/* value at last interrupt */
+	int last;
+	int offset;
+	unsigned long last_tsc;
+	long ticks;
+};
+
+#define hpet_readl(a)           readl(fix_to_virt(FIX_HPET_BASE) + a)
+#define hpet_writel(d,a)        writel(d, fix_to_virt(FIX_HPET_BASE) + a)
+
+/* vsyscall space (readonly) */
+extern long __vxtime_sequence[2];
+extern struct hpet_data __hpet;
+extern struct timeval __xtime;
+extern volatile unsigned long __jiffies;
+extern unsigned long __wall_jiffies;
+extern struct timezone __sys_tz;
+
+/* kernel space (writeable) */
+extern long vxtime_sequence[2];
+extern struct hpet_data hpet;
+extern unsigned long wall_jiffies;
+extern struct timezone sys_tz;
+
+#define vxtime_lock() do { vxtime_sequence[0]++; wmb(); } while(0)
+#define vxtime_unlock() do { wmb(); vxtime_sequence[1]++; } while (0)
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_X86_64_VSYSCALL_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/asm-x86_64/xor.h linux-2.4.20/include/asm-x86_64/xor.h
--- linux-2.4.19/include/asm-x86_64/xor.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-x86_64/xor.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,350 @@
+/*
+ * include/asm-x86_64/xor.h
+ *
+ * Optimized RAID-5 checksumming functions for MMX and SSE.
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * Cache avoiding checksumming functions utilizing KNI instructions
+ * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo)
+ */
+
+/*
+ * Based on
+ * High-speed RAID5 checksumming functions utilizing SSE instructions.
+ * Copyright (C) 1998 Ingo Molnar.
+ */
+
+/* 
+ * x86-64 changes / gcc fixes from Andi Kleen. 
+ * Copyright 2002 Andi Kleen, SuSE Labs.
+ *
+ * This hasn't been optimized for the hammer yet, but there are likely
+ * no advantages to be gotten from x86-64 here anyways.
+ */
+
+typedef struct { unsigned long a,b; } __attribute__((aligned(16))) xmm_store_t;
+
+/* Doesn't use gcc to save the XMM registers, because there is no easy way to 
+   tell it to do a clts before the register saving. */
+#define XMMS_SAVE				\
+	asm volatile ( 			\
+		"movq %%cr0,%0		;\n\t"	\
+		"clts			;\n\t"	\
+		"movups %%xmm0,(%1)	;\n\t"	\
+		"movups %%xmm1,0x10(%1)	;\n\t"	\
+		"movups %%xmm2,0x20(%1)	;\n\t"	\
+		"movups %%xmm3,0x30(%1)	;\n\t"	\
+		: "=&r" (cr0)			\
+		: "r" (xmm_save) 		\
+		: "memory")
+
+#define XMMS_RESTORE				\
+	asm volatile ( 			\
+		"sfence			;\n\t"	\
+		"movups (%1),%%xmm0	;\n\t"	\
+		"movups 0x10(%1),%%xmm1	;\n\t"	\
+		"movups 0x20(%1),%%xmm2	;\n\t"	\
+		"movups 0x30(%1),%%xmm3	;\n\t"	\
+		"movq 	%0,%%cr0	;\n\t"	\
+		:				\
+		: "r" (cr0), "r" (xmm_save)	\
+		: "memory")
+
+#define OFFS(x)		"16*("#x")"
+#define PF_OFFS(x)	"256+16*("#x")"
+#define	PF0(x)		"	prefetchnta "PF_OFFS(x)"(%[p1])		;\n"
+#define LD(x,y)		"       movaps   "OFFS(x)"(%[p1]), %%xmm"#y"	;\n"
+#define ST(x,y)		"       movaps %%xmm"#y",   "OFFS(x)"(%[p1])	;\n"
+#define PF1(x)		"	prefetchnta "PF_OFFS(x)"(%[p2])		;\n"
+#define PF2(x)		"	prefetchnta "PF_OFFS(x)"(%[p3])		;\n"
+#define PF3(x)		"	prefetchnta "PF_OFFS(x)"(%[p4])		;\n"
+#define PF4(x)		"	prefetchnta "PF_OFFS(x)"(%[p5])		;\n"
+#define PF5(x)		"	prefetchnta "PF_OFFS(x)"(%[p6])		;\n"
+#define XO1(x,y)	"       xorps   "OFFS(x)"(%[p2]), %%xmm"#y"	;\n"
+#define XO2(x,y)	"       xorps   "OFFS(x)"(%[p3]), %%xmm"#y"	;\n"
+#define XO3(x,y)	"       xorps   "OFFS(x)"(%[p4]), %%xmm"#y"	;\n"
+#define XO4(x,y)	"       xorps   "OFFS(x)"(%[p5]), %%xmm"#y"	;\n"
+#define XO5(x,y)	"       xorps   "OFFS(x)"(%[p6]), %%xmm"#y"	;\n"
+
+
+static void
+xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+        unsigned int lines = bytes >> 8;
+	unsigned long cr0;
+	xmm_store_t xmm_save[4];
+
+	XMMS_SAVE;
+
+        asm volatile (
+#undef BLOCK
+#define BLOCK(i) \
+		LD(i,0)					\
+			LD(i+1,1)			\
+		PF1(i)					\
+				PF1(i+2)		\
+				LD(i+2,2)		\
+					LD(i+3,3)	\
+		PF0(i+4)				\
+				PF0(i+6)		\
+		XO1(i,0)				\
+			XO1(i+1,1)			\
+				XO1(i+2,2)		\
+					XO1(i+3,3)	\
+		ST(i,0)					\
+			ST(i+1,1)			\
+				ST(i+2,2)		\
+					ST(i+3,3)	\
+
+
+		PF0(0)
+				PF0(2)
+
+	" .align 32			;\n"
+        " 1:                            ;\n"
+
+		BLOCK(0)
+		BLOCK(4)
+		BLOCK(8)
+		BLOCK(12)
+
+        "       addq %[inc], %[p1]           ;\n"
+        "       addq %[inc], %[p2]           ;\n"
+		"		decl %[cnt] ; jnz 1b"
+	: [p1] "+r" (p1), [p2] "+r" (p2), [cnt] "+r" (lines)
+	: [inc] "r" (256UL) 
+        : "memory");
+
+	XMMS_RESTORE;
+}
+
+static void
+xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	  unsigned long *p3)
+{
+	unsigned int lines = bytes >> 8;
+	xmm_store_t xmm_save[4];
+	unsigned long cr0;
+
+	XMMS_SAVE;
+
+        __asm__ __volatile__ (
+#undef BLOCK
+#define BLOCK(i) \
+		PF1(i)					\
+				PF1(i+2)		\
+		LD(i,0)					\
+			LD(i+1,1)			\
+				LD(i+2,2)		\
+					LD(i+3,3)	\
+		PF2(i)					\
+				PF2(i+2)		\
+		PF0(i+4)				\
+				PF0(i+6)		\
+		XO1(i,0)				\
+			XO1(i+1,1)			\
+				XO1(i+2,2)		\
+					XO1(i+3,3)	\
+		XO2(i,0)				\
+			XO2(i+1,1)			\
+				XO2(i+2,2)		\
+					XO2(i+3,3)	\
+		ST(i,0)					\
+			ST(i+1,1)			\
+				ST(i+2,2)		\
+					ST(i+3,3)	\
+
+
+		PF0(0)
+				PF0(2)
+
+	" .align 32			;\n"
+        " 1:                            ;\n"
+
+		BLOCK(0)
+		BLOCK(4)
+		BLOCK(8)
+		BLOCK(12)
+
+        "       addq %[inc], %[p1]           ;\n"
+        "       addq %[inc], %[p2]          ;\n"
+        "       addq %[inc], %[p3]           ;\n"
+		"		decl %[cnt] ; jnz 1b"
+	: [cnt] "+r" (lines),
+	  [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3)
+	: [inc] "r" (256UL)
+	: "memory"); 
+	XMMS_RESTORE;
+}
+
+static void
+xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	  unsigned long *p3, unsigned long *p4)
+{
+	unsigned int lines = bytes >> 8;
+	xmm_store_t xmm_save[4]; 
+	unsigned long cr0;
+
+	XMMS_SAVE;
+
+        __asm__ __volatile__ (
+#undef BLOCK
+#define BLOCK(i) \
+		PF1(i)					\
+				PF1(i+2)		\
+		LD(i,0)					\
+			LD(i+1,1)			\
+				LD(i+2,2)		\
+					LD(i+3,3)	\
+		PF2(i)					\
+				PF2(i+2)		\
+		XO1(i,0)				\
+			XO1(i+1,1)			\
+				XO1(i+2,2)		\
+					XO1(i+3,3)	\
+		PF3(i)					\
+				PF3(i+2)		\
+		PF0(i+4)				\
+				PF0(i+6)		\
+		XO2(i,0)				\
+			XO2(i+1,1)			\
+				XO2(i+2,2)		\
+					XO2(i+3,3)	\
+		XO3(i,0)				\
+			XO3(i+1,1)			\
+				XO3(i+2,2)		\
+					XO3(i+3,3)	\
+		ST(i,0)					\
+			ST(i+1,1)			\
+				ST(i+2,2)		\
+					ST(i+3,3)	\
+
+
+		PF0(0)
+				PF0(2)
+
+	" .align 32			;\n"
+        " 1:                            ;\n"
+
+		BLOCK(0)
+		BLOCK(4)
+		BLOCK(8)
+		BLOCK(12)
+
+        "       addq %[inc], %[p1]           ;\n"
+        "       addq %[inc], %[p2]           ;\n"
+        "       addq %[inc], %[p3]           ;\n"
+        "       addq %[inc], %[p4]           ;\n"
+	"	decl %[cnt] ; jnz 1b"
+	: [cnt] "+c" (lines),
+	  [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4)
+	: [inc] "r" (256UL)
+        : "memory" );
+
+	XMMS_RESTORE;
+}
+
+static void
+xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	  unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+        unsigned int lines = bytes >> 8;
+	xmm_store_t xmm_save[4];
+	unsigned long cr0;
+
+	XMMS_SAVE;
+
+        __asm__ __volatile__ (
+#undef BLOCK
+#define BLOCK(i) \
+		PF1(i)					\
+				PF1(i+2)		\
+		LD(i,0)					\
+			LD(i+1,1)			\
+				LD(i+2,2)		\
+					LD(i+3,3)	\
+		PF2(i)					\
+				PF2(i+2)		\
+		XO1(i,0)				\
+			XO1(i+1,1)			\
+				XO1(i+2,2)		\
+					XO1(i+3,3)	\
+		PF3(i)					\
+				PF3(i+2)		\
+		XO2(i,0)				\
+			XO2(i+1,1)			\
+				XO2(i+2,2)		\
+					XO2(i+3,3)	\
+		PF4(i)					\
+				PF4(i+2)		\
+		PF0(i+4)				\
+				PF0(i+6)		\
+		XO3(i,0)				\
+			XO3(i+1,1)			\
+				XO3(i+2,2)		\
+					XO3(i+3,3)	\
+		XO4(i,0)				\
+			XO4(i+1,1)			\
+				XO4(i+2,2)		\
+					XO4(i+3,3)	\
+		ST(i,0)					\
+			ST(i+1,1)			\
+				ST(i+2,2)		\
+					ST(i+3,3)	\
+
+
+		PF0(0)
+				PF0(2)
+
+	" .align 32			;\n"
+        " 1:                            ;\n"
+
+		BLOCK(0)
+		BLOCK(4)
+		BLOCK(8)
+		BLOCK(12)
+
+        "       addq %[inc], %[p1]           ;\n"
+        "       addq %[inc], %[p2]           ;\n"
+        "       addq %[inc], %[p3]           ;\n"
+        "       addq %[inc], %[p4]           ;\n"
+        "       addq %[inc], %[p5]           ;\n"
+	"	decl %[cnt] ; jnz 1b"
+	: [cnt] "+c" (lines),
+  	  [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4), 
+	  [p5] "+r" (p5)
+	: [inc] "r" (256UL)
+	: "memory");
+
+	XMMS_RESTORE;
+}
+
+static struct xor_block_template xor_block_sse = {
+        name: "generic_sse",
+        do_2: xor_sse_2,
+        do_3: xor_sse_3,
+        do_4: xor_sse_4,
+        do_5: xor_sse_5,
+};
+
+#undef XOR_TRY_TEMPLATES
+#define XOR_TRY_TEMPLATES				\
+	do {						\
+		xor_speed(&xor_block_sse);	\
+	} while (0)
+
+/* We force the use of the SSE xor block because it can write around L2.
+   We may also be able to load into the L1 only depending on how the cpu
+   deals with a load to a line that is being prefetched.  */
+#define XOR_SELECT_TEMPLATE(FASTEST) (&xor_block_sse)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/agp_backend.h linux-2.4.20/include/linux/agp_backend.h
--- linux-2.4.19/include/linux/agp_backend.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/agp_backend.h	2002-10-29 11:18:35.000000000 +0000
@@ -65,6 +65,7 @@
 	AMD_IRONGATE,
 	AMD_761,
 	AMD_762,
+	AMD_8151,
 	ALI_M1541,
 	ALI_M1621,
 	ALI_M1631,
@@ -161,7 +162,7 @@
  * 
  */
 
-extern void agp_copy_info(agp_kern_info *);
+extern int agp_copy_info(agp_kern_info *);
 
 /*
  * agp_copy_info :
@@ -257,7 +258,7 @@
 	void       (*enable)(u32);
 	int        (*acquire)(void);
 	void       (*release)(void);
-	void       (*copy_info)(agp_kern_info *);
+	int        (*copy_info)(agp_kern_info *);
 } drm_agp_t;
 
 extern const drm_agp_t *drm_agp_p;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/auto_fs.h linux-2.4.20/include/linux/auto_fs.h
--- linux-2.4.19/include/linux/auto_fs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/auto_fs.h	2002-10-29 11:18:30.000000000 +0000
@@ -45,7 +45,7 @@
  * If so, 32-bit user-space code should be backwards compatible.
  */
 
-#if defined(__sparc__) || defined(__mips__) || defined(__s390__)
+#if defined(__sparc__) || defined(__mips__) || defined(__s390__) || defined(__x86_64__)
 typedef unsigned int autofs_wqt_t;
 #else
 typedef unsigned long autofs_wqt_t;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/blkdev.h linux-2.4.20/include/linux/blkdev.h
--- linux-2.4.19/include/linux/blkdev.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/blkdev.h	2002-10-29 11:18:34.000000000 +0000
@@ -6,6 +6,9 @@
 #include <linux/genhd.h>
 #include <linux/tqueue.h>
 #include <linux/list.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
 
 struct request_queue;
 typedef struct request_queue request_queue_t;
@@ -36,7 +39,7 @@
 	unsigned long hard_sector, hard_nr_sectors;
 	unsigned int nr_segments;
 	unsigned int nr_hw_segments;
-	unsigned long current_nr_sectors;
+	unsigned long current_nr_sectors, hard_cur_sectors;
 	void * special;
 	char * buffer;
 	struct completion * waiting;
@@ -123,6 +126,8 @@
 	 */
 	char			head_active;
 
+	unsigned long		bounce_pfn;
+
 	/*
 	 * Is meant to protect the queue in the future instead of
 	 * io_request_lock
@@ -135,6 +140,38 @@
 	wait_queue_head_t	wait_for_requests[2];
 };
 
+extern unsigned long blk_max_low_pfn, blk_max_pfn;
+
+#define BLK_BOUNCE_HIGH		(blk_max_low_pfn << PAGE_SHIFT)
+#define BLK_BOUNCE_ANY		(blk_max_pfn << PAGE_SHIFT)
+
+extern void blk_queue_bounce_limit(request_queue_t *, u64);
+
+#ifdef CONFIG_HIGHMEM
+extern struct buffer_head *create_bounce(int, struct buffer_head *);
+extern inline struct buffer_head *blk_queue_bounce(request_queue_t *q, int rw,
+						   struct buffer_head *bh)
+{
+	struct page *page = bh->b_page;
+
+#ifndef CONFIG_DISCONTIGMEM
+	if (page - mem_map <= q->bounce_pfn)
+#else
+	if ((page - page_zone(page)->zone_mem_map) + (page_zone(page)->zone_start_paddr >> PAGE_SHIFT) <= q->bounce_pfn)
+#endif
+		return bh;
+
+	return create_bounce(rw, bh);
+}
+#else
+#define blk_queue_bounce(q, rw, bh)	(bh)
+#endif
+
+#define bh_phys(bh)		(page_to_phys((bh)->b_page) + bh_offset((bh)))
+
+#define BH_CONTIG(b1, b2)	(bh_phys((b1)) + (b1)->b_size == bh_phys((b2)))
+#define BH_PHYS_4G(b1, b2)	((bh_phys((b1)) | 0xffffffff) == ((bh_phys((b2)) + (b2)->b_size - 1) | 0xffffffff))
+
 struct blk_dev_struct {
 	/*
 	 * queue_proc has to be atomic
@@ -174,6 +211,7 @@
 extern void blk_queue_headactive(request_queue_t *, int);
 extern void blk_queue_make_request(request_queue_t *, make_request_fn *);
 extern void generic_unplug_device(void *);
+extern inline int blk_seg_merge_ok(struct buffer_head *, struct buffer_head *);
 
 extern int * blk_size[MAX_BLKDEV];
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/bootmem.h linux-2.4.20/include/linux/bootmem.h
--- linux-2.4.19/include/linux/bootmem.h	2001-11-22 19:47:23.000000000 +0000
+++ linux-2.4.20/include/linux/bootmem.h	2002-10-29 11:18:49.000000000 +0000
@@ -16,6 +16,7 @@
 
 extern unsigned long max_low_pfn;
 extern unsigned long min_low_pfn;
+extern unsigned long max_pfn;
 
 /*
  * node_bootmem_map is a map pointer - the bits represent all physical 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/brlock.h linux-2.4.20/include/linux/brlock.h
--- linux-2.4.19/include/linux/brlock.h	2001-11-22 19:46:19.000000000 +0000
+++ linux-2.4.20/include/linux/brlock.h	2002-10-29 11:18:37.000000000 +0000
@@ -19,7 +19,7 @@
  *
  *                 David S. Miller <davem@redhat.com>
  *
- * David has an implementation that doesnt use atomic operations in
+ * David has an implementation that doesn't use atomic operations in
  * the read branch via memory ordering tricks - i guess we need to
  * split this up into a per-arch thing? The atomicity issue is a
  * secondary item in profiles, at least on x86 platforms.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/byteorder/big_endian.h linux-2.4.20/include/linux/byteorder/big_endian.h
--- linux-2.4.19/include/linux/byteorder/big_endian.h	2000-10-16 20:36:08.000000000 +0000
+++ linux-2.4.20/include/linux/byteorder/big_endian.h	2002-10-29 11:18:37.000000000 +0000
@@ -18,48 +18,64 @@
 #define __constant_le64_to_cpu(x) ___constant_swab64((x))
 #define __constant_cpu_to_le32(x) ___constant_swab32((x))
 #define __constant_le32_to_cpu(x) ___constant_swab32((x))
+#define __constant_cpu_to_le24(x) ___constant_swab24((x))
+#define __constant_le24_to_cpu(x) ___constant_swab24((x))
 #define __constant_cpu_to_le16(x) ___constant_swab16((x))
 #define __constant_le16_to_cpu(x) ___constant_swab16((x))
 #define __constant_cpu_to_be64(x) ((__u64)(x))
 #define __constant_be64_to_cpu(x) ((__u64)(x))
 #define __constant_cpu_to_be32(x) ((__u32)(x))
 #define __constant_be32_to_cpu(x) ((__u32)(x))
+#define __constant_cpu_to_be24(x) ((__u32)(x))
+#define __constant_be24_to_cpu(x) ((__u32)(x))
 #define __constant_cpu_to_be16(x) ((__u16)(x))
 #define __constant_be16_to_cpu(x) ((__u16)(x))
 #define __cpu_to_le64(x) __swab64((x))
 #define __le64_to_cpu(x) __swab64((x))
 #define __cpu_to_le32(x) __swab32((x))
 #define __le32_to_cpu(x) __swab32((x))
+#define __cpu_to_le24(x) __swab24((x))
+#define __le24_to_cpu(x) __swab24((x))
 #define __cpu_to_le16(x) __swab16((x))
 #define __le16_to_cpu(x) __swab16((x))
 #define __cpu_to_be64(x) ((__u64)(x))
 #define __be64_to_cpu(x) ((__u64)(x))
 #define __cpu_to_be32(x) ((__u32)(x))
 #define __be32_to_cpu(x) ((__u32)(x))
+#define __cpu_to_be24(x) ((__u32)(x))
+#define __be24_to_cpu(x) ((__u32)(x))
 #define __cpu_to_be16(x) ((__u16)(x))
 #define __be16_to_cpu(x) ((__u16)(x))
 #define __cpu_to_le64p(x) __swab64p((x))
 #define __le64_to_cpup(x) __swab64p((x))
 #define __cpu_to_le32p(x) __swab32p((x))
 #define __le32_to_cpup(x) __swab32p((x))
+#define __cpu_to_le24p(x) __swab24p((x))
+#define __le24_to_cpup(x) __swab24p((x))
 #define __cpu_to_le16p(x) __swab16p((x))
 #define __le16_to_cpup(x) __swab16p((x))
 #define __cpu_to_be64p(x) (*(__u64*)(x))
 #define __be64_to_cpup(x) (*(__u64*)(x))
 #define __cpu_to_be32p(x) (*(__u32*)(x))
 #define __be32_to_cpup(x) (*(__u32*)(x))
+#define __cpu_to_be24p(x) (*(__u24*)(x))
+#define __be24_to_cpup(x) (*(__u24*)(x))
 #define __cpu_to_be16p(x) (*(__u16*)(x))
 #define __be16_to_cpup(x) (*(__u16*)(x))
 #define __cpu_to_le64s(x) __swab64s((x))
 #define __le64_to_cpus(x) __swab64s((x))
 #define __cpu_to_le32s(x) __swab32s((x))
 #define __le32_to_cpus(x) __swab32s((x))
+#define __cpu_to_le24s(x) __swab24s((x))
+#define __le24_to_cpus(x) __swab24s((x))
 #define __cpu_to_le16s(x) __swab16s((x))
 #define __le16_to_cpus(x) __swab16s((x))
 #define __cpu_to_be64s(x) do {} while (0)
 #define __be64_to_cpus(x) do {} while (0)
 #define __cpu_to_be32s(x) do {} while (0)
 #define __be32_to_cpus(x) do {} while (0)
+#define __cpu_to_be24s(x) do {} while (0)
+#define __be24_to_cpus(x) do {} while (0)
 #define __cpu_to_be16s(x) do {} while (0)
 #define __be16_to_cpus(x) do {} while (0)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/byteorder/little_endian.h linux-2.4.20/include/linux/byteorder/little_endian.h
--- linux-2.4.19/include/linux/byteorder/little_endian.h	2001-07-26 21:14:16.000000000 +0000
+++ linux-2.4.20/include/linux/byteorder/little_endian.h	2002-10-29 11:18:48.000000000 +0000
@@ -18,48 +18,64 @@
 #define __constant_le64_to_cpu(x) ((__u64)(x))
 #define __constant_cpu_to_le32(x) ((__u32)(x))
 #define __constant_le32_to_cpu(x) ((__u32)(x))
+#define __constant_cpu_to_le24(x) ((__u32)(x))
+#define __constant_le24_to_cpu(x) ((__u32)(x))
 #define __constant_cpu_to_le16(x) ((__u16)(x))
 #define __constant_le16_to_cpu(x) ((__u16)(x))
 #define __constant_cpu_to_be64(x) ___constant_swab64((x))
 #define __constant_be64_to_cpu(x) ___constant_swab64((x))
 #define __constant_cpu_to_be32(x) ___constant_swab32((x))
 #define __constant_be32_to_cpu(x) ___constant_swab32((x))
+#define __constant_cpu_to_be24(x) ___constant_swab24((x))
+#define __constant_be24_to_cpu(x) ___constant_swab24((x))
 #define __constant_cpu_to_be16(x) ___constant_swab16((x))
 #define __constant_be16_to_cpu(x) ___constant_swab16((x))
 #define __cpu_to_le64(x) ((__u64)(x))
 #define __le64_to_cpu(x) ((__u64)(x))
 #define __cpu_to_le32(x) ((__u32)(x))
 #define __le32_to_cpu(x) ((__u32)(x))
+#define __cpu_to_le24(x) ((__u32)(x))
+#define __le24_to_cpu(x) ((__u32)(x))
 #define __cpu_to_le16(x) ((__u16)(x))
 #define __le16_to_cpu(x) ((__u16)(x))
 #define __cpu_to_be64(x) __swab64((x))
 #define __be64_to_cpu(x) __swab64((x))
 #define __cpu_to_be32(x) __swab32((x))
 #define __be32_to_cpu(x) __swab32((x))
+#define __cpu_to_be24(x) __swab24((x))
+#define __be24_to_cpu(x) __swab24((x))
 #define __cpu_to_be16(x) __swab16((x))
 #define __be16_to_cpu(x) __swab16((x))
 #define __cpu_to_le64p(x) (*(__u64*)(x))
 #define __le64_to_cpup(x) (*(__u64*)(x))
 #define __cpu_to_le32p(x) (*(__u32*)(x))
 #define __le32_to_cpup(x) (*(__u32*)(x))
+#define __cpu_to_le24p(x) (*(__u32*)(x))
+#define __le24_to_cpup(x) (*(__u32*)(x))
 #define __cpu_to_le16p(x) (*(__u16*)(x))
 #define __le16_to_cpup(x) (*(__u16*)(x))
 #define __cpu_to_be64p(x) __swab64p((x))
 #define __be64_to_cpup(x) __swab64p((x))
 #define __cpu_to_be32p(x) __swab32p((x))
 #define __be32_to_cpup(x) __swab32p((x))
+#define __cpu_to_be24p(x) __swab24p((x))
+#define __be24_to_cpup(x) __swab24p((x))
 #define __cpu_to_be16p(x) __swab16p((x))
 #define __be16_to_cpup(x) __swab16p((x))
 #define __cpu_to_le64s(x) do {} while (0)
 #define __le64_to_cpus(x) do {} while (0)
 #define __cpu_to_le32s(x) do {} while (0)
 #define __le32_to_cpus(x) do {} while (0)
+#define __cpu_to_le24s(x) do {} while (0)
+#define __le24_to_cpus(x) do {} while (0)
 #define __cpu_to_le16s(x) do {} while (0)
 #define __le16_to_cpus(x) do {} while (0)
 #define __cpu_to_be64s(x) __swab64s((x))
 #define __be64_to_cpus(x) __swab64s((x))
 #define __cpu_to_be32s(x) __swab32s((x))
 #define __be32_to_cpus(x) __swab32s((x))
+#define __cpu_to_be24s(x) __swab24s((x))
+#define __be24_to_cpus(x) __swab24s((x))
 #define __cpu_to_be16s(x) __swab16s((x))
 #define __be16_to_cpus(x) __swab16s((x))
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/byteorder/swab.h linux-2.4.20/include/linux/byteorder/swab.h
--- linux-2.4.19/include/linux/byteorder/swab.h	2001-07-26 20:45:47.000000000 +0000
+++ linux-2.4.20/include/linux/byteorder/swab.h	2002-10-29 11:18:40.000000000 +0000
@@ -26,6 +26,15 @@
 		(((__u16)(__x) & (__u16)0xff00U) >> 8) )); \
 })
 
+#define ___swab24(x) \
+({ \
+	__u32 __x = (x); \
+	((__u32)( \
+		((__x & (__u32)0x000000ffUL) << 16) | \
+		 (__x & (__u32)0x0000ff00UL)        | \
+		((__x & (__u32)0x00ff0000UL) >> 16) )); \
+})
+
 #define ___swab32(x) \
 ({ \
 	__u32 __x = (x); \
@@ -54,6 +63,11 @@
 	((__u16)( \
 		(((__u16)(x) & (__u16)0x00ffU) << 8) | \
 		(((__u16)(x) & (__u16)0xff00U) >> 8) ))
+#define ___constant_swab24(x) \
+	((__u32)( \
+		(((__u32)(x) & (__u32)0x000000ffU) << 16) | \
+		(((__u32)(x) & (__u32)0x0000ff00U)	  | \
+		(((__u32)(x) & (__u32)0x00ff0000U) >> 16) ))
 #define ___constant_swab32(x) \
 	((__u32)( \
 		(((__u32)(x) & (__u32)0x000000ffUL) << 24) | \
@@ -77,6 +91,9 @@
 #ifndef __arch__swab16
 #  define __arch__swab16(x) ({ __u16 __tmp = (x) ; ___swab16(__tmp); })
 #endif
+#ifndef __arch__swab24
+#  define __arch__swab24(x) ({ __u32 __tmp = (x) ; ___swab24(__tmp); })
+#endif
 #ifndef __arch__swab32
 #  define __arch__swab32(x) ({ __u32 __tmp = (x) ; ___swab32(__tmp); })
 #endif
@@ -87,6 +104,9 @@
 #ifndef __arch__swab16p
 #  define __arch__swab16p(x) __arch__swab16(*(x))
 #endif
+#ifndef __arch__swab24p
+#  define __arch__swab24p(x) __arch__swab24(*(x))
+#endif
 #ifndef __arch__swab32p
 #  define __arch__swab32p(x) __arch__swab32(*(x))
 #endif
@@ -97,6 +117,9 @@
 #ifndef __arch__swab16s
 #  define __arch__swab16s(x) do { *(x) = __arch__swab16p((x)); } while (0)
 #endif
+#ifndef __arch__swab24s
+#  define __arch__swab24s(x) do { *(x) = __arch__swab24p((x)); } while (0)
+#endif
 #ifndef __arch__swab32s
 #  define __arch__swab32s(x) do { *(x) = __arch__swab32p((x)); } while (0)
 #endif
@@ -113,6 +136,10 @@
 (__builtin_constant_p((__u16)(x)) ? \
  ___swab16((x)) : \
  __fswab16((x)))
+#  define __swab24(x) \
+(__builtin_constant_p((__u32)(x)) ? \
+ ___swab24((x)) : \
+ __fswab24((x)))
 #  define __swab32(x) \
 (__builtin_constant_p((__u32)(x)) ? \
  ___swab32((x)) : \
@@ -123,6 +150,7 @@
  __fswab64((x)))
 #else
 #  define __swab16(x) __fswab16(x)
+#  define __swab24(x) __fswab24(x)
 #  define __swab32(x) __fswab32(x)
 #  define __swab64(x) __fswab64(x)
 #endif /* OPTIMIZE */
@@ -141,6 +169,19 @@
 	__arch__swab16s(addr);
 }
 
+static __inline__ __const__ __u32 __fswab24(__u32 x)
+{
+	return __arch__swab24(x);
+}
+static __inline__ __u32 __swab24p(__u32 *x)
+{
+	return __arch__swab24p(x);
+}
+static __inline__ void __swab24s(__u32 *addr)
+{
+	__arch__swab24s(addr);
+}
+
 static __inline__ __const__ __u32 __fswab32(__u32 x)
 {
 	return __arch__swab32(x);
@@ -177,12 +218,15 @@
 
 #if defined(__KERNEL__)
 #define swab16 __swab16
+#define swab24 __swab24
 #define swab32 __swab32
 #define swab64 __swab64
 #define swab16p __swab16p
+#define swab24p __swab24p
 #define swab32p __swab32p
 #define swab64p __swab64p
 #define swab16s __swab16s
+#define swab24s __swab24s
 #define swab32s __swab32s
 #define swab64s __swab64s
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/cobalt-nvram.h linux-2.4.20/include/linux/cobalt-nvram.h
--- linux-2.4.19/include/linux/cobalt-nvram.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/cobalt-nvram.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,109 @@
+/*
+ * $Id: cobalt-nvram.h,v 1.20 2001/10/17 23:16:55 thockin Exp $
+ * cobalt-nvram.h : defines for the various fields in the cobalt NVRAM
+ *
+ * Copyright 2001,2002 Sun Microsystems, Inc.
+ */
+
+#ifndef COBALT_NVRAM_H
+#define COBALT_NVRAM_H
+
+#include <linux/nvram.h>
+
+#define COBT_CMOS_INFO_MAX		0x7f	/* top address allowed */
+#define COBT_CMOS_BIOS_DRIVE_INFO	0x12	/* drive info would go here */
+
+#define COBT_CMOS_CKS_START		NVRAM_OFFSET(0x0e)
+#define COBT_CMOS_CKS_END		NVRAM_OFFSET(0x7f)
+
+/* flag bytes - 16 flags for now, leave room for more */
+#define COBT_CMOS_FLAG_BYTE_0		NVRAM_OFFSET(0x10)
+#define COBT_CMOS_FLAG_BYTE_1		NVRAM_OFFSET(0x11)
+
+/* flags in flag bytes - up to 16 */
+#define COBT_CMOS_FLAG_MIN		0x0001
+#define COBT_CMOS_CONSOLE_FLAG		0x0001 /* console on/off */
+#define COBT_CMOS_DEBUG_FLAG		0x0002 /* ROM debug messages */
+#define COBT_CMOS_AUTO_PROMPT_FLAG	0x0004 /* boot to ROM prompt? */
+#define COBT_CMOS_CLEAN_BOOT_FLAG	0x0008 /* set by a clean shutdown */
+#define COBT_CMOS_HW_NOPROBE_FLAG	0x0010 /* go easy on the probing */
+#define COBT_CMOS_SYSFAULT_FLAG		0x0020 /* system fault detected */
+#define COBT_CMOS_OOPSPANIC_FLAG	0x0040 /* panic on oops */
+#define COBT_CMOS_DELAY_CACHE_FLAG	0x0080 /* delay cache initialization */
+#define COBT_CMOS_NOLOGO_FLAG		0x0100 /* hide "C" logo @ boot */
+#define COBT_CMOS_VERSION_FLAG		0x0200 /* the version field is valid */
+#define COBT_CMOS_FLAG_MAX		0x0200
+
+/* leave byte 0x12 blank - Linux looks for drive info here */
+
+/* CMOS structure version, valid if COBT_CMOS_VERSION_FLAG is true */
+#define COBT_CMOS_VERSION		NVRAM_OFFSET(0x13)
+#define COBT_CMOS_VER_BTOCODE		1 /* min. version needed for btocode */
+
+/* index of default boot method */
+#define COBT_CMOS_BOOT_METHOD		NVRAM_OFFSET(0x20)
+#define COBT_CMOS_BOOT_METHOD_DISK	0
+#define COBT_CMOS_BOOT_METHOD_ROM	1
+#define COBT_CMOS_BOOT_METHOD_NET	2
+
+#define COBT_CMOS_BOOT_DEV_MIN		NVRAM_OFFSET(0x21)
+/* major #, minor # of first through fourth boot device */
+#define COBT_CMOS_BOOT_DEV0_MAJ		NVRAM_OFFSET(0x21)
+#define COBT_CMOS_BOOT_DEV0_MIN		NVRAM_OFFSET(0x22)
+#define COBT_CMOS_BOOT_DEV1_MAJ		NVRAM_OFFSET(0x23)
+#define COBT_CMOS_BOOT_DEV1_MIN		NVRAM_OFFSET(0x24)
+#define COBT_CMOS_BOOT_DEV2_MAJ		NVRAM_OFFSET(0x25)
+#define COBT_CMOS_BOOT_DEV2_MIN		NVRAM_OFFSET(0x26)
+#define COBT_CMOS_BOOT_DEV3_MAJ		NVRAM_OFFSET(0x27)
+#define COBT_CMOS_BOOT_DEV3_MIN		NVRAM_OFFSET(0x28)
+#define COBT_CMOS_BOOT_DEV_MAX		NVRAM_OFFSET(0x28)
+
+/* checksum of bytes 0xe-0x7f */
+#define COBT_CMOS_CHECKSUM		NVRAM_OFFSET(0x2e)
+
+/* running uptime counter, units of 5 minutes (32 bits =~ 41000 years) */
+#define COBT_CMOS_UPTIME_0		NVRAM_OFFSET(0x30)
+#define COBT_CMOS_UPTIME_1		NVRAM_OFFSET(0x31)
+#define COBT_CMOS_UPTIME_2		NVRAM_OFFSET(0x32)
+#define COBT_CMOS_UPTIME_3		NVRAM_OFFSET(0x33)
+
+/* count of successful boots (32 bits) */
+#define COBT_CMOS_BOOTCOUNT_0		NVRAM_OFFSET(0x38)
+#define COBT_CMOS_BOOTCOUNT_1		NVRAM_OFFSET(0x39)
+#define COBT_CMOS_BOOTCOUNT_2		NVRAM_OFFSET(0x3a)
+#define COBT_CMOS_BOOTCOUNT_3		NVRAM_OFFSET(0x3b)
+
+/* 13 bytes: system serial number, same as on the back of the system */
+#define COBT_CMOS_SYS_SERNUM_LEN	13
+#define COBT_CMOS_SYS_SERNUM_0		NVRAM_OFFSET(0x40)
+#define COBT_CMOS_SYS_SERNUM_1		NVRAM_OFFSET(0x41)
+#define COBT_CMOS_SYS_SERNUM_2		NVRAM_OFFSET(0x42)
+#define COBT_CMOS_SYS_SERNUM_3		NVRAM_OFFSET(0x43)
+#define COBT_CMOS_SYS_SERNUM_4		NVRAM_OFFSET(0x44)
+#define COBT_CMOS_SYS_SERNUM_5		NVRAM_OFFSET(0x45)
+#define COBT_CMOS_SYS_SERNUM_6		NVRAM_OFFSET(0x46)
+#define COBT_CMOS_SYS_SERNUM_7		NVRAM_OFFSET(0x47)
+#define COBT_CMOS_SYS_SERNUM_8		NVRAM_OFFSET(0x48)
+#define COBT_CMOS_SYS_SERNUM_9		NVRAM_OFFSET(0x49)
+#define COBT_CMOS_SYS_SERNUM_10		NVRAM_OFFSET(0x4a)
+#define COBT_CMOS_SYS_SERNUM_11		NVRAM_OFFSET(0x4b)
+#define COBT_CMOS_SYS_SERNUM_12		NVRAM_OFFSET(0x4c)
+/* checksum for serial num - 1 byte */
+#define COBT_CMOS_SYS_SERNUM_CSUM	NVRAM_OFFSET(0x4f)
+
+#define COBT_CMOS_ROM_REV_MAJ		NVRAM_OFFSET(0x50)
+#define COBT_CMOS_ROM_REV_MIN		NVRAM_OFFSET(0x51)
+#define COBT_CMOS_ROM_REV_REV		NVRAM_OFFSET(0x52)
+
+#define COBT_CMOS_BTO_CODE_0		NVRAM_OFFSET(0x53)
+#define COBT_CMOS_BTO_CODE_1		NVRAM_OFFSET(0x54)
+#define COBT_CMOS_BTO_CODE_2		NVRAM_OFFSET(0x55)
+#define COBT_CMOS_BTO_CODE_3		NVRAM_OFFSET(0x56)
+
+#define COBT_CMOS_BTO_IP_CSUM		NVRAM_OFFSET(0x57)
+#define COBT_CMOS_BTO_IP_0		NVRAM_OFFSET(0x58)
+#define COBT_CMOS_BTO_IP_1		NVRAM_OFFSET(0x59)
+#define COBT_CMOS_BTO_IP_2		NVRAM_OFFSET(0x5a)
+#define COBT_CMOS_BTO_IP_3		NVRAM_OFFSET(0x5b)
+
+#endif /* COBALT_NVRAM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/dcache.h linux-2.4.20/include/linux/dcache.h
--- linux-2.4.19/include/linux/dcache.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/dcache.h	2002-10-29 11:18:40.000000000 +0000
@@ -5,6 +5,7 @@
 
 #include <asm/atomic.h>
 #include <linux/mount.h>
+#include <linux/kernel.h>
 
 /*
  * linux/include/linux/dcache.h
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/dio.h linux-2.4.20/include/linux/dio.h
--- linux-2.4.19/include/linux/dio.h	1998-06-13 20:14:32.000000000 +0000
+++ linux-2.4.20/include/linux/dio.h	2002-10-29 11:18:50.000000000 +0000
@@ -72,16 +72,16 @@
 #define DIO_SCINHOLE(scode) (((scode) >= 32) && ((scode) < DIOII_SCBASE))
 
 /* macros to read device IDs, given base address */
-#define DIO_ID(baseaddr) readb((baseaddr) + DIO_IDOFF)
-#define DIO_SECID(baseaddr) readb((baseaddr) + DIO_SECIDOFF)
+#define DIO_ID(baseaddr) in_8((baseaddr) + DIO_IDOFF)
+#define DIO_SECID(baseaddr) in_8((baseaddr) + DIO_SECIDOFF)
 
 /* extract the interrupt level */
-#define DIO_IPL(baseaddr) (((readb((baseaddr) + DIO_IPLOFF) >> 4) & 0x03) + 3)
+#define DIO_IPL(baseaddr) (((in_8((baseaddr) + DIO_IPLOFF) >> 4) & 0x03) + 3)
 
 /* find the size of a DIO-II board's address space.
  * DIO boards are all fixed length.
  */
-#define DIOII_SIZE(baseaddr) ((readb((baseaddr) + DIOII_SIZEOFF) + 1) * 0x100000)
+#define DIOII_SIZE(baseaddr) ((in_8((baseaddr) + DIOII_SIZEOFF) + 1) * 0x100000)
 
 /* general purpose macro for both DIO and DIO-II */
 #define DIO_SIZE(scode, base) (DIO_ISDIOII((scode)) ? DIOII_SIZE((base)) : DIO_DEVSIZE)
@@ -109,7 +109,7 @@
 #define DIO_ID_DCMREM   0x85 /* 98642A serial MUX */
 #define DIO_DESC_DCMREM "98642A DCMREM serial MUX"
 #define DIO_ID_LAN      0x15 /* 98643A LAN */
-#define DIO_DESC_LAN "98643A LAN"
+#define DIO_DESC_LAN "98643A LANCE ethernet"
 #define DIO_ID_FHPIB    0x08 /* 98625A/98625B fast HP-IB */
 #define DIO_DESC_FHPIB "98625A/98625B fast HPIB"
 #define DIO_ID_NHPIB    0x80 /* 98624A HP-IB (normal ie slow) */
@@ -196,6 +196,7 @@
 extern int dio_find(int deviceid);
 extern void *dio_scodetoviraddr(int scode);
 extern int dio_scodetoipl(int scode);
+extern const char *dio_scodetoname(int scode);
 extern void dio_config_board(int scode);
 extern void dio_unconfig_board(int scode);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/efi.h linux-2.4.20/include/linux/efi.h
--- linux-2.4.19/include/linux/efi.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/efi.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,284 @@
+#ifndef _LINUX_EFI_H
+#define _LINUX_EFI_H
+
+/*
+ * Extensible Firmware Interface
+ * Based on 'Extensible Firmware Interface Specification' version 0.9, April 30, 1999
+ *
+ * Copyright (C) 1999 VA Linux Systems
+ * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+ * Copyright (C) 1999, 2002 Hewlett-Packard Co.
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ *	Stephane Eranian <eranian@hpl.hp.com>
+ */
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+
+#include <asm/page.h>
+#include <asm/system.h>
+
+#define EFI_SUCCESS		0
+#define EFI_LOAD_ERROR          (1L | (1L << 63))
+#define EFI_INVALID_PARAMETER	(2L | (1L << 63))
+#define EFI_UNSUPPORTED		(3L | (1L << 63))
+#define EFI_BAD_BUFFER_SIZE     (4L | (1L << 63))
+#define EFI_BUFFER_TOO_SMALL	(5L | (1L << 63))
+#define EFI_NOT_FOUND          (14L | (1L << 63))
+
+typedef unsigned long efi_status_t;
+typedef u8 efi_bool_t;
+typedef u16 efi_char16_t;		/* UNICODE character */
+
+
+typedef struct {
+	u8 b[16];
+} efi_guid_t;
+
+#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \
+((efi_guid_t) \
+{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
+  (b) & 0xff, ((b) >> 8) & 0xff, \
+  (c) & 0xff, ((c) >> 8) & 0xff, \
+  (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
+
+/*
+ * Generic EFI table header
+ */
+typedef	struct {
+	u64 signature;
+	u32 revision;
+	u32 headersize;
+	u32 crc32;
+	u32 reserved;
+} efi_table_hdr_t;
+
+/*
+ * Memory map descriptor:
+ */
+
+/* Memory types: */
+#define EFI_RESERVED_TYPE		 0
+#define EFI_LOADER_CODE			 1
+#define EFI_LOADER_DATA			 2
+#define EFI_BOOT_SERVICES_CODE		 3
+#define EFI_BOOT_SERVICES_DATA		 4
+#define EFI_RUNTIME_SERVICES_CODE	 5
+#define EFI_RUNTIME_SERVICES_DATA	 6
+#define EFI_CONVENTIONAL_MEMORY		 7
+#define EFI_UNUSABLE_MEMORY		 8
+#define EFI_ACPI_RECLAIM_MEMORY		 9
+#define EFI_ACPI_MEMORY_NVS		10
+#define EFI_MEMORY_MAPPED_IO		11
+#define EFI_MEMORY_MAPPED_IO_PORT_SPACE	12
+#define EFI_PAL_CODE			13
+#define EFI_MAX_MEMORY_TYPE		14
+
+/* Attribute values: */
+#define EFI_MEMORY_UC		0x0000000000000001	/* uncached */
+#define EFI_MEMORY_WC		0x0000000000000002	/* write-coalescing */
+#define EFI_MEMORY_WT		0x0000000000000004	/* write-through */
+#define EFI_MEMORY_WB		0x0000000000000008	/* write-back */
+#define EFI_MEMORY_WP		0x0000000000001000	/* write-protect */
+#define EFI_MEMORY_RP		0x0000000000002000	/* read-protect */
+#define EFI_MEMORY_XP		0x0000000000004000	/* execute-protect */
+#define EFI_MEMORY_RUNTIME	0x8000000000000000	/* range requires runtime mapping */
+#define EFI_MEMORY_DESCRIPTOR_VERSION	1
+
+#define EFI_PAGE_SHIFT		12
+
+typedef struct {
+	u32 type;
+	u32 pad;
+	u64 phys_addr;
+	u64 virt_addr;
+	u64 num_pages;
+	u64 attribute;
+} efi_memory_desc_t;
+
+typedef int efi_freemem_callback_t (u64 start, u64 end, void *arg);
+
+/*
+ * Types and defines for Time Services
+ */
+#define EFI_TIME_ADJUST_DAYLIGHT 0x1
+#define EFI_TIME_IN_DAYLIGHT     0x2
+#define EFI_UNSPECIFIED_TIMEZONE 0x07ff
+
+typedef struct {
+	u16 year;
+	u8 month;
+	u8 day;
+	u8 hour;
+	u8 minute;
+	u8 second;
+	u8 pad1;
+	u32 nanosecond;
+	s16 timezone;
+	u8 daylight;
+	u8 pad2;
+} efi_time_t;
+
+typedef struct {
+	u32 resolution;
+	u32 accuracy;
+	u8 sets_to_zero;
+} efi_time_cap_t;
+
+/*
+ * Types and defines for EFI ResetSystem
+ */
+#define EFI_RESET_COLD 0
+#define EFI_RESET_WARM 1
+
+/*
+ * EFI Runtime Services table
+ */
+#define EFI_RUNTIME_SERVICES_SIGNATURE 0x5652453544e5552
+#define EFI_RUNTIME_SERVICES_REVISION  0x00010000
+
+typedef struct {
+	efi_table_hdr_t hdr;
+	u64 get_time;
+	u64 set_time;
+	u64 get_wakeup_time;
+	u64 set_wakeup_time;
+	u64 set_virtual_address_map;
+	u64 convert_pointer;
+	u64 get_variable;
+	u64 get_next_variable;
+	u64 set_variable;
+	u64 get_next_high_mono_count;
+	u64 reset_system;
+} efi_runtime_services_t;
+
+typedef efi_status_t efi_get_time_t (efi_time_t *tm, efi_time_cap_t *tc);
+typedef efi_status_t efi_set_time_t (efi_time_t *tm);
+typedef efi_status_t efi_get_wakeup_time_t (efi_bool_t *enabled, efi_bool_t *pending,
+					    efi_time_t *tm);
+typedef efi_status_t efi_set_wakeup_time_t (efi_bool_t enabled, efi_time_t *tm);
+typedef efi_status_t efi_get_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
+					 unsigned long *data_size, void *data);
+typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char16_t *name,
+					      efi_guid_t *vendor);
+typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 attr,
+					 unsigned long data_size, void *data);
+typedef efi_status_t efi_get_next_high_mono_count_t (u64 *count);
+typedef void efi_reset_system_t (int reset_type, efi_status_t status,
+				 unsigned long data_size, efi_char16_t *data);
+
+/*
+ *  EFI Configuration Table and GUID definitions
+ */
+#define NULL_GUID \
+    EFI_GUID(  0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 )
+
+#define MPS_TABLE_GUID    \
+    EFI_GUID(  0xeb9d2d2f, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d )
+
+#define ACPI_TABLE_GUID    \
+    EFI_GUID(  0xeb9d2d30, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d )
+
+#define ACPI_20_TABLE_GUID    \
+    EFI_GUID(  0x8868e871, 0xe4f1, 0x11d3, 0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 )
+
+#define SMBIOS_TABLE_GUID    \
+    EFI_GUID(  0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d )
+
+#define SAL_SYSTEM_TABLE_GUID    \
+    EFI_GUID(  0xeb9d2d32, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d )
+
+#define HCDP_TABLE_GUID	\
+    EFI_GUID(  0xf951938d, 0x620b, 0x42ef, 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98 )
+
+typedef struct {
+	efi_guid_t guid;
+	u64 table;
+} efi_config_table_t;
+
+#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249
+#define EFI_SYSTEM_TABLE_REVISION  ((1 << 16) | 00)
+
+typedef struct {
+	efi_table_hdr_t hdr;
+	u64 fw_vendor;		/* physical addr of CHAR16 vendor string */
+	u32 fw_revision;
+	u64 con_in_handle;
+	u64 con_in;
+	u64 con_out_handle;
+	u64 con_out;
+	u64 stderr_handle;
+	u64 stderr;
+	u64 runtime;
+	u64 boottime;
+	u64 nr_tables;
+	u64 tables;
+} efi_system_table_t;
+
+/*
+ * All runtime access to EFI goes through this structure:
+ */
+extern struct efi {
+	efi_system_table_t *systab;	/* EFI system table */
+	void *mps;			/* MPS table */
+	void *acpi;			/* ACPI table  (IA64 ext 0.71) */
+	void *acpi20;			/* ACPI table  (ACPI 2.0) */
+	void *smbios;			/* SM BIOS table */
+	void *sal_systab;		/* SAL system table */
+	void *hcdp;			/* HCDP table */
+	void *boot_info;		/* boot info table */
+	efi_get_time_t *get_time;
+	efi_set_time_t *set_time;
+	efi_get_wakeup_time_t *get_wakeup_time;
+	efi_set_wakeup_time_t *set_wakeup_time;
+	efi_get_variable_t *get_variable;
+	efi_get_next_variable_t *get_next_variable;
+	efi_set_variable_t *set_variable;
+	efi_get_next_high_mono_count_t *get_next_high_mono_count;
+	efi_reset_system_t *reset_system;
+} efi;
+
+static inline int
+efi_guidcmp (efi_guid_t left, efi_guid_t right)
+{
+	return memcmp(&left, &right, sizeof (efi_guid_t));
+}
+
+static inline char *
+efi_guid_unparse(efi_guid_t *guid, char *out)
+{
+	sprintf(out, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+		guid->b[3], guid->b[2], guid->b[1], guid->b[0],
+		guid->b[5], guid->b[4], guid->b[7], guid->b[6],
+		guid->b[8], guid->b[9], guid->b[10], guid->b[11],
+		guid->b[12], guid->b[13], guid->b[14], guid->b[15]);
+        return out;
+}
+
+extern void efi_init (void);
+extern void efi_map_pal_code (void);
+extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
+extern void efi_gettimeofday (struct timeval *tv);
+extern void efi_enter_virtual_mode (void);	/* switch EFI to virtual mode, if possible */
+extern u64 efi_get_iobase (void);
+extern u32 efi_mem_type (unsigned long phys_addr);
+extern u64 efi_mem_attributes (unsigned long phys_addr);
+
+/*
+ * Variable Attributes
+ */
+#define EFI_VARIABLE_NON_VOLATILE       0x0000000000000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
+#define EFI_VARIABLE_RUNTIME_ACCESS     0x0000000000000004
+
+
+/*
+ * efi_dir is allocated in arch/ia64/kernel/efi.c.
+ */
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry *efi_dir;
+#endif
+
+#endif /* _LINUX_EFI_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/elevator.h linux-2.4.20/include/linux/elevator.h
--- linux-2.4.19/include/linux/elevator.h	2001-02-16 00:58:34.000000000 +0000
+++ linux-2.4.20/include/linux/elevator.h	2002-10-29 11:18:32.000000000 +0000
@@ -18,7 +18,6 @@
 	int write_latency;
 
 	elevator_merge_fn *elevator_merge_fn;
-	elevator_merge_cleanup_fn *elevator_merge_cleanup_fn;
 	elevator_merge_req_fn *elevator_merge_req_fn;
 
 	unsigned int queue_ID;
@@ -81,23 +80,23 @@
 	return latency;
 }
 
+#define ELV_LINUS_SEEK_COST	16
+
 #define ELEVATOR_NOOP							\
 ((elevator_t) {								\
 	0,				/* read_latency */		\
 	0,				/* write_latency */		\
 									\
 	elevator_noop_merge,		/* elevator_merge_fn */		\
-	elevator_noop_merge_cleanup,	/* elevator_merge_cleanup_fn */	\
 	elevator_noop_merge_req,	/* elevator_merge_req_fn */	\
 	})
 
 #define ELEVATOR_LINUS							\
 ((elevator_t) {								\
-	8192,				/* read passovers */		\
-	16384,				/* write passovers */		\
+	2048,				/* read passovers */		\
+	8192,				/* write passovers */		\
 									\
 	elevator_linus_merge,		/* elevator_merge_fn */		\
-	elevator_linus_merge_cleanup,	/* elevator_merge_cleanup_fn */	\
 	elevator_linus_merge_req,	/* elevator_merge_req_fn */	\
 	})
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/elf.h linux-2.4.20/include/linux/elf.h
--- linux-2.4.19/include/linux/elf.h	2001-11-22 19:48:29.000000000 +0000
+++ linux-2.4.20/include/linux/elf.h	2002-10-29 11:18:33.000000000 +0000
@@ -75,7 +75,7 @@
 
 #define EM_IA_64	50	/* HP/Intel IA-64 */
 
-#define EM_X8664	62	/* AMD x86-64 */
+#define EM_X86_64	62	/* AMD x86-64 */
 
 #define EM_S390		22	/* IBM S/390 */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/ethtool.h linux-2.4.20/include/linux/ethtool.h
--- linux-2.4.19/include/linux/ethtool.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/ethtool.h	2002-10-29 11:18:35.000000000 +0000
@@ -39,7 +39,8 @@
 	char	bus_info[ETHTOOL_BUSINFO_LEN];	/* Bus info for this IF. */
 				/* For PCI devices, use pci_dev->slot_name. */
 	char	reserved1[32];
-	char	reserved2[20];
+	char	reserved2[16];
+	u32	n_stats;	/* number of u64's from ETHTOOL_GSTATS */
 	u32	testinfo_len;
 	u32	eedump_len;	/* Size of data from ETHTOOL_GEEPROM (bytes) */
 	u32	regdump_len;	/* Size of data from ETHTOOL_GREGS (bytes) */
@@ -242,6 +243,13 @@
 	u64	data[0];
 };
 
+/* for dumping NIC-specific statistics */
+struct ethtool_stats {
+	u32	cmd;		/* ETHTOOL_GSTATS */
+	u32	n_stats;	/* number of u64's being returned */
+	u64	data[0];
+};
+
 /* CMDs currently supported */
 #define ETHTOOL_GSET		0x00000001 /* Get settings. */
 #define ETHTOOL_SSET		0x00000002 /* Set settings, privileged. */
@@ -272,6 +280,7 @@
 #define ETHTOOL_TEST		0x0000001a /* execute NIC self-test, priv. */
 #define ETHTOOL_GSTRINGS	0x0000001b /* get specified string set */
 #define ETHTOOL_PHYS_ID		0x0000001c /* identify the NIC */
+#define ETHTOOL_GSTATS		0x0000001d /* get NIC-specific statistics */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET		ETHTOOL_GSET
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/ext3_fs.h linux-2.4.20/include/linux/ext3_fs.h
--- linux-2.4.19/include/linux/ext3_fs.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.20/include/linux/ext3_fs.h	2002-10-29 11:18:32.000000000 +0000
@@ -36,8 +36,8 @@
 /*
  * The second extended file system version
  */
-#define EXT3FS_DATE		"10 Jan 2002"
-#define EXT3FS_VERSION		"2.4-0.9.17"
+#define EXT3FS_DATE		"19 August 2002"
+#define EXT3FS_VERSION		"2.4-0.9.19"
 
 /*
  * Debug code
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/fs.h linux-2.4.20/include/linux/fs.h
--- linux-2.4.19/include/linux/fs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/fs.h	2002-10-29 11:18:35.000000000 +0000
@@ -206,6 +206,7 @@
 extern void buffer_init(unsigned long);
 extern void inode_init(unsigned long);
 extern void mnt_init(unsigned long);
+extern void files_init(unsigned long mempages);
 
 /* bh state bits */
 enum bh_state_bits {
@@ -595,6 +596,7 @@
 	void (*fl_remove)(struct file_lock *);	/* lock removal callback */
 
 	struct fasync_struct *	fl_fasync; /* for lease break notifications */
+	unsigned long fl_break_time;	/* for nonblocking lease breaks */
 
 	union {
 		struct nfs_lock_info	nfs_fl;
@@ -864,6 +866,10 @@
 	int (*revalidate) (struct dentry *);
 	int (*setattr) (struct dentry *, struct iattr *);
 	int (*getattr) (struct dentry *, struct iattr *);
+	int (*setxattr) (struct dentry *, const char *, void *, size_t, int);
+	ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
+	ssize_t (*listxattr) (struct dentry *, char *, size_t);
+	int (*removexattr) (struct dentry *, const char *);
 };
 
 struct seq_file;
@@ -995,7 +1001,6 @@
 extern struct vfsmount *kern_mount(struct file_system_type *);
 extern int may_umount(struct vfsmount *);
 extern long do_mount(char *, char *, char *, unsigned long, void *);
-extern void umount_tree(struct vfsmount *);
 
 #define kern_umount mntput
 
@@ -1051,7 +1056,7 @@
 
 static inline int get_lease(struct inode *inode, unsigned int mode)
 {
-	if (inode->i_flock && (inode->i_flock->fl_flags & FL_LEASE))
+	if (inode->i_flock)
 		return __get_lease(inode, mode);
 	return 0;
 }
@@ -1327,6 +1332,7 @@
 extern int FASTCALL(__user_walk(const char *, unsigned, struct nameidata *));
 extern int FASTCALL(path_init(const char *, unsigned, struct nameidata *));
 extern int FASTCALL(path_walk(const char *, struct nameidata *));
+extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *));
 extern int FASTCALL(link_path_walk(const char *, struct nameidata *));
 extern void path_release(struct nameidata *);
 extern int follow_down(struct vfsmount **, struct dentry **);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/fsfilter.h linux-2.4.20/include/linux/fsfilter.h
--- linux-2.4.19/include/linux/fsfilter.h	2001-11-11 18:20:21.000000000 +0000
+++ linux-2.4.20/include/linux/fsfilter.h	2002-10-29 11:18:31.000000000 +0000
@@ -1,3 +1,7 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ */
+
 #ifndef __FILTER_H_
 #define __FILTER_H_ 1
 
@@ -59,12 +63,13 @@
         struct snapshot_ops *o_snops;
 };
 
-#define FILTER_FS_TYPES 5
+#define FILTER_FS_TYPES 6
 #define FILTER_FS_EXT2 0
 #define FILTER_FS_EXT3 1
 #define FILTER_FS_REISERFS 2
 #define FILTER_FS_XFS 3
 #define FILTER_FS_OBDFS 4
+#define FILTER_FS_TMPFS 5
 extern struct filter_fs filter_oppar[FILTER_FS_TYPES];
 
 struct filter_fs *filter_get_filter_fs(const char *cache_type);
@@ -96,7 +101,7 @@
 #define PRESTO_DEBUG
 #ifdef PRESTO_DEBUG
 /* debugging masks */
-#define D_SUPER     1   /* print results returned by Venus */
+#define D_SUPER     1  
 #define D_INODE     2   /* print entry and exit into procedure */
 #define D_FILE      4
 #define D_CACHE     8   /* cache debugging */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/genhd.h linux-2.4.20/include/linux/genhd.h
--- linux-2.4.19/include/linux/genhd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/genhd.h	2002-10-29 11:18:33.000000000 +0000
@@ -62,8 +62,10 @@
 	unsigned long start_sect;
 	unsigned long nr_sects;
 	devfs_handle_t de;              /* primary (master) devfs entry  */
-	int number;                     /* stupid old code wastes space  */
-
+#ifdef CONFIG_DEVFS_FS
+	int number;
+#endif /* CONFIG_DEVFS_FS */
+#ifdef CONFIG_BLK_STATS
 	/* Performance stats: */
 	unsigned int ios_in_flight;
 	unsigned int io_ticks;
@@ -79,6 +81,7 @@
 	unsigned int wr_merges;
 	unsigned int wr_ticks;
 	unsigned int wr_sectors;	
+#endif /* CONFIG_BLK_STATS */
 };
 
 #define GENHD_FL_REMOVABLE  1
@@ -259,18 +262,22 @@
 
 char *disk_name (struct gendisk *hd, int minor, char *buf);
 
-/*
- * disk_round_stats is used to round off the IO statistics for a disk
- * for a complete clock tick.
- */
-void disk_round_stats(struct hd_struct *hd);
-
 /* 
  * Account for the completion of an IO request (used by drivers which 
  * bypass the normal end_request processing) 
  */
 struct request;
-void req_finished_io(struct request *);
+
+#ifdef CONFIG_BLK_STATS
+extern void disk_round_stats(struct hd_struct *hd);
+extern void req_new_io(struct request *req, int merge, int sectors);
+extern void req_merged_io(struct request *req);
+extern void req_finished_io(struct request *req);
+#else
+static inline void req_new_io(struct request *req, int merge, int sectors) { }
+static inline void req_merged_io(struct request *req) { }
+static inline void req_finished_io(struct request *req) { }
+#endif /* CONFIG_BLK_STATS */
 
 extern void devfs_register_partitions (struct gendisk *dev, int minor,
 				       int unregister);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/hiddev.h linux-2.4.20/include/linux/hiddev.h
--- linux-2.4.19/include/linux/hiddev.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/hiddev.h	2002-10-29 11:18:35.000000000 +0000
@@ -183,7 +183,7 @@
 int __init hiddev_init(void);
 void __exit hiddev_exit(void);
 #else
-static inline void *hiddev_connect(struct hid_device *hid) { return NULL; }
+static inline int hiddev_connect(struct hid_device *hid) { return -1; }
 static inline void hiddev_disconnect(struct hid_device *hid) { }
 static inline void hiddev_hid_event(struct hid_device *hid, unsigned int usage, int value) { }
 static inline int hiddev_init(void) { return 0; }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/highmem.h linux-2.4.20/include/linux/highmem.h
--- linux-2.4.19/include/linux/highmem.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/highmem.h	2002-10-29 11:18:34.000000000 +0000
@@ -13,8 +13,7 @@
 /* declarations for linux/mm/highmem.c */
 unsigned int nr_free_highpages(void);
 
-extern struct buffer_head * create_bounce(int rw, struct buffer_head * bh_orig);
-
+extern struct buffer_head *create_bounce(int rw, struct buffer_head * bh_orig);
 
 static inline char *bh_kmap(struct buffer_head *bh)
 {
@@ -26,6 +25,42 @@
 	kunmap(bh->b_page);
 }
 
+/*
+ * remember to add offset! and never ever reenable interrupts between a
+ * bh_kmap_irq and bh_kunmap_irq!!
+ */
+static inline char *bh_kmap_irq(struct buffer_head *bh, unsigned long *flags)
+{
+	unsigned long addr;
+
+	__save_flags(*flags);
+
+	/*
+	 * could be low
+	 */
+	if (!PageHighMem(bh->b_page))
+		return bh->b_data;
+
+	/*
+	 * it's a highmem page
+	 */
+	__cli();
+	addr = (unsigned long) kmap_atomic(bh->b_page, KM_BH_IRQ);
+
+	if (addr & ~PAGE_MASK)
+		BUG();
+
+	return (char *) addr + bh_offset(bh);
+}
+
+static inline void bh_kunmap_irq(char *buffer, unsigned long *flags)
+{
+	unsigned long ptr = (unsigned long) buffer & PAGE_MASK;
+
+	kunmap_atomic((void *) ptr, KM_BH_IRQ);
+	__restore_flags(*flags);
+}
+
 #else /* CONFIG_HIGHMEM */
 
 static inline unsigned int nr_free_highpages(void) { return 0; }
@@ -37,8 +72,10 @@
 #define kmap_atomic(page,idx)		kmap(page)
 #define kunmap_atomic(page,idx)		kunmap(page)
 
-#define bh_kmap(bh)	((bh)->b_data)
-#define bh_kunmap(bh)	do { } while (0)
+#define bh_kmap(bh)			((bh)->b_data)
+#define bh_kunmap(bh)			do { } while (0)
+#define bh_kmap_irq(bh, flags)		((bh)->b_data)
+#define bh_kunmap_irq(bh, flags)	do { *(flags) = 0; } while (0)
 
 #endif /* CONFIG_HIGHMEM */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/hil.h linux-2.4.20/include/linux/hil.h
--- linux-2.4.19/include/linux/hil.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/hil.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,405 @@
+/*
+ * Hewlett Packard Human Interface Loop (HP-HIL) Protocol -- header.
+ *
+ * Copyright (c) 2001 Brian S. Julin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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
+ *
+ * References:
+ * HP-HIL Technical Reference Manual.  Hewlett Packard Product No. 45918A
+ *
+ * A note of thanks to HP for providing and shipping reference materials
+ * free of charge to help in the development of HIL support for Linux.
+ *
+ */
+
+#include <asm/types.h>
+
+/* Physical constants relevant to raw loop/device timing. 
+ */ 
+
+#define HIL_CLOCK		8MHZ
+#define HIL_EK1_CLOCK		30HZ
+#define HIL_EK2_CLOCK		60HZ
+
+#define HIL_TIMEOUT_DEV         5	/* ms */
+#define HIL_TIMEOUT_DEVS	10	/* ms */
+#define HIL_TIMEOUT_NORESP	10	/* ms */
+#define HIL_TIMEOUT_DEVS_DATA	16	/* ms */
+#define HIL_TIMEOUT_SELFTEST	200	/* ms */
+
+
+/* Actual wire line coding.  These will only be useful if someone is 
+ * implementing a software MLC to run HIL devices on a non-parisc machine.
+ */
+
+#define HIL_WIRE_PACKET_LEN	15
+enum hil_wire_bitpos {
+	HIL_WIRE_START		= 0,
+	HIL_WIRE_ADDR2,
+	HIL_WIRE_ADDR1,
+	HIL_WIRE_ADDR0,
+	HIL_WIRE_COMMAND,
+	HIL_WIRE_DATA7,
+	HIL_WIRE_DATA6,
+	HIL_WIRE_DATA5,
+	HIL_WIRE_DATA4,
+	HIL_WIRE_DATA3,
+	HIL_WIRE_DATA2,
+	HIL_WIRE_DATA1,
+	HIL_WIRE_DATA0,
+	HIL_WIRE_PARITY,
+	HIL_WIRE_STOP
+};
+
+/* HP documentation uses these bit positions to refer to commands;
+ * we will call these "packets".
+ */
+enum hil_pkt_bitpos {
+	HIL_PKT_CMD		= 0x00000800,
+	HIL_PKT_ADDR2		= 0x00000400,
+	HIL_PKT_ADDR1		= 0x00000200,
+	HIL_PKT_ADDR0		= 0x00000100,
+	HIL_PKT_ADDR_MASK	= 0x00000700,
+	HIL_PKT_ADDR_SHIFT	= 8,
+	HIL_PKT_DATA7		= 0x00000080,
+	HIL_PKT_DATA6		= 0x00000040,
+	HIL_PKT_DATA5		= 0x00000020,
+	HIL_PKT_DATA4		= 0x00000010,
+	HIL_PKT_DATA3		= 0x00000008,
+	HIL_PKT_DATA2		= 0x00000004,
+	HIL_PKT_DATA1		= 0x00000002,
+	HIL_PKT_DATA0		= 0x00000001,
+	HIL_PKT_DATA_MASK	= 0x000000FF,
+	HIL_PKT_DATA_SHIFT	= 0
+};
+
+/* The HIL MLC also has several error/status/control bits.  We extend the 
+ * "packet" to include these when direct access to the MLC is available,
+ * or emulate them in cases where they are not available. 
+ *
+ * This way the device driver knows that the underlying MLC driver
+ * has had to deal with loop errors.
+ */
+enum hil_error_bitpos {
+	HIL_ERR_OB	= 0x00000800, /* MLC is busy sending an auto-poll, 
+					 or we have filled up the output 
+					 buffer and must wait. */
+	HIL_ERR_INT	= 0x00010000, /* A normal interrupt has occurred. */
+	HIL_ERR_NMI	= 0x00020000, /* An NMI has occurred. */
+	HIL_ERR_LERR	= 0x00040000, /* A poll didn't come back. */
+	HIL_ERR_PERR	= 0x01000000, /* There was a Parity Error. */
+	HIL_ERR_FERR	= 0x02000000, /* There was a Framing Error. */
+	HIL_ERR_FOF	= 0x04000000  /* Input FIFO Overflowed. */
+};
+
+enum hil_control_bitpos {
+	HIL_CTRL_TEST	= 0x00010000,
+	HIL_CTRL_IPF	= 0x00040000,
+	HIL_CTRL_APE	= 0x02000000
+};
+
+/* Bits 30,31 are unused, we use them to control write behavior. */
+#define HIL_DO_ALTER_CTRL  0x40000000 /* Write MSW of packet to control 
+                                          before writing LSW to loop */
+#define HIL_CTRL_ONLY      0xc0000000 /* *Only* alter the control registers */
+
+/* This gives us a 32-bit "packet" 
+ */
+typedef u32 hil_packet;
+
+
+/* HIL Loop commands 
+ */
+enum hil_command {
+	HIL_CMD_IFC	= 0x00,	/* Interface Clear */
+	HIL_CMD_EPT	= 0x01,	/* Enter Pass-Thru Mode */
+	HIL_CMD_ELB	= 0x02,	/* Enter Loop-Back Mode */
+	HIL_CMD_IDD	= 0x03,	/* Identify and Describe */
+	HIL_CMD_DSR	= 0x04,	/* Device Soft Reset */
+	HIL_CMD_PST	= 0x05,	/* Perform Self Test */
+	HIL_CMD_RRG	= 0x06,	/* Read Register */
+	HIL_CMD_WRG	= 0x07,	/* Write Register */
+	HIL_CMD_ACF	= 0x08,	/* Auto Configure */
+	HIL_CMDID_ACF	= 0x07,	/* Auto Configure bits with incremented ID */
+	HIL_CMD_POL	= 0x10,	/* Poll */
+	HIL_CMDCT_POL	= 0x0f,	/* Poll command bits with item count  */
+	HIL_CMD_RPL	= 0x20,	/* RePoll */
+	HIL_CMDCT_RPL	= 0x0f,	/* RePoll command bits with item count */
+	HIL_CMD_RNM	= 0x30,	/* Report Name */
+	HIL_CMD_RST	= 0x31,	/* Report Status */
+	HIL_CMD_EXD	= 0x32,	/* Extended Describe */
+	HIL_CMD_RSC	= 0x33,	/* Report Security Code */
+
+	/* 0x34 to 0x3c reserved for future use  */
+
+	HIL_CMD_DKA	= 0x3d,	/* Disable Keyswitch Autorepeat */
+	HIL_CMD_EK1	= 0x3e,	/* Enable Keyswitch Autorepeat 1 */
+	HIL_CMD_EK2	= 0x3f,	/* Enable Keyswitch Autorepeat 2 */
+	HIL_CMD_PR1	= 0x40,	/* Prompt1 */  
+	HIL_CMD_PR2	= 0x41,	/* Prompt2 */
+	HIL_CMD_PR3	= 0x42,	/* Prompt3 */
+	HIL_CMD_PR4	= 0x43,	/* Prompt4 */
+	HIL_CMD_PR5	= 0x44,	/* Prompt5 */
+	HIL_CMD_PR6	= 0x45,	/* Prompt6 */
+	HIL_CMD_PR7	= 0x46,	/* Prompt7 */
+	HIL_CMD_PRM	= 0x47,	/* Prompt (General Purpose) */
+	HIL_CMD_AK1	= 0x48,	/* Acknowlege1 */  
+	HIL_CMD_AK2	= 0x49,	/* Acknowlege2 */
+	HIL_CMD_AK3	= 0x4a,	/* Acknowlege3 */
+	HIL_CMD_AK4	= 0x4b,	/* Acknowlege4 */
+	HIL_CMD_AK5	= 0x4c,	/* Acknowlege5 */
+	HIL_CMD_AK6	= 0x4d,	/* Acknowlege6 */
+	HIL_CMD_AK7	= 0x4e,	/* Acknowlege7 */
+	HIL_CMD_ACK	= 0x4f,	/* Acknowlege (General Purpose) */
+
+	/* 0x50 to 0x78 reserved for future use  */
+	/* 0x80 to 0xEF device-specific commands */
+	/* 0xf0 to 0xf9 reserved for future use  */
+
+	HIL_CMD_RIO	= 0xfa,	/* Register I/O Error */
+	HIL_CMD_SHR	= 0xfb,	/* System Hard Reset */
+	HIL_CMD_TER	= 0xfc,	/* Transmission Error */
+	HIL_CMD_CAE	= 0xfd,	/* Configuration Address Error */
+	HIL_CMD_DHR	= 0xfe,	/* Device Hard Reset */
+
+	/* 0xff is prohibited from use. */
+};
+
+
+/* 
+ * Response "records" to HIL commands
+ */
+
+/* Device ID byte 
+ */
+#define HIL_IDD_DID_TYPE_MASK		0xe0	/* Primary type bits */
+#define HIL_IDD_DID_TYPE_KB_INTEGRAL	0xa0	/* Integral keyboard */
+#define HIL_IDD_DID_TYPE_KB_ITF		0xc0	/* ITD keyboard */
+#define HIL_IDD_DID_TYPE_KB_RSVD	0xe0	/* Reserved keyboard type */
+#define HIL_IDD_DID_TYPE_KB_LANG_MASK	0x1f	/* Keyboard locale bits */
+#define HIL_IDD_DID_KBLANG_USE_ESD	0x00	/* Use ESD Locale instead */
+#define HIL_IDD_DID_TYPE_ABS		0x80    /* Absolute Positioners */
+#define HIL_IDD_DID_ABS_RSVD1_MASK	0xf8	/* Reserved */
+#define HIL_IDD_DID_ABS_RSVD1		0x98
+#define HIL_IDD_DID_ABS_TABLET_MASK	0xf8	/* Tablets and digitizers */
+#define HIL_IDD_DID_ABS_TABLET		0x90
+#define HIL_IDD_DID_ABS_TSCREEN_MASK	0xfc	/* Touch screens */
+#define HIL_IDD_DID_ABS_TSCREEN		0x8c
+#define HIL_IDD_DID_ABS_RSVD2_MASK	0xfc	/* Reserved */
+#define HIL_IDD_DID_ABS_RSVD2		0x88
+#define HIL_IDD_DID_ABS_RSVD3_MASK	0xfc	/* Reserved */
+#define HIL_IDD_DID_ABS_RSVD3		0x80
+#define HIL_IDD_DID_TYPE_REL		0x60    /* Relative Positioners */
+#define HIL_IDD_DID_REL_RSVD1_MASK	0xf0	/* Reserved */
+#define HIL_IDD_DID_REL_RSVD1		0x70
+#define HIL_IDD_DID_REL_RSVD2_MASK	0xfc	/* Reserved */
+#define HIL_IDD_DID_REL_RSVD2		0x6c
+#define HIL_IDD_DID_REL_MOUSE_MASK	0xfc	/* Mouse */
+#define HIL_IDD_DID_REL_MOUSE		0x68
+#define HIL_IDD_DID_REL_QUAD_MASK	0xf8	/* Other Quadrature Devices */
+#define HIL_IDD_DID_REL_QUAD		0x60
+#define HIL_IDD_DID_TYPE_CHAR		0x40    /* Character Entry */
+#define HIL_IDD_DID_CHAR_BARCODE_MASK	0xfc	/* Barcode Reader */
+#define HIL_IDD_DID_CHAR_BARCODE	0x5c
+#define HIL_IDD_DID_CHAR_RSVD1_MASK	0xfc	/* Reserved */
+#define HIL_IDD_DID_CHAR_RSVD1		0x58
+#define HIL_IDD_DID_CHAR_RSVD2_MASK	0xf8	/* Reserved */
+#define HIL_IDD_DID_CHAR_RSVD2		0x50
+#define HIL_IDD_DID_CHAR_RSVD3_MASK	0xf0	/* Reserved */
+#define HIL_IDD_DID_CHAR_RSVD3		0x40
+#define HIL_IDD_DID_TYPE_OTHER		0x20    /* Miscellaneous */
+#define HIL_IDD_DID_OTHER_RSVD1_MASK	0xf0	/* Reserved */
+#define HIL_IDD_DID_OTHER_RSVD1		0x30
+#define HIL_IDD_DID_OTHER_BARCODE_MASK	0xfc	/* Tone Generator */
+#define HIL_IDD_DID_OTHER_BARCODE	0x2c
+#define HIL_IDD_DID_OTHER_RSVD2_MASK	0xfc	/* Reserved */
+#define HIL_IDD_DID_OTHER_RSVD2		0x28
+#define HIL_IDD_DID_OTHER_RSVD3_MASK	0xf8	/* Reserved */
+#define HIL_IDD_DID_OTHER_RSVD3		0x20
+#define HIL_IDD_DID_TYPE_KEYPAD		0x00	/* Vectra Keyboard */
+
+/* IDD record header 
+ */
+#define HIL_IDD_HEADER_AXSET_MASK	0x03    /* Number of axis in a set */
+#define HIL_IDD_HEADER_RSC		0x04	/* Supports RSC command */
+#define HIL_IDD_HEADER_EXD		0x08	/* Supports EXD command */
+#define HIL_IDD_HEADER_IOD		0x10	/* IOD byte to follow */
+#define HIL_IDD_HEADER_16BIT		0x20	/* 16 (vs. 8) bit resolution */
+#define HIL_IDD_HEADER_ABS		0x40	/* Reports Absolute Position */
+#define HIL_IDD_HEADER_2X_AXIS		0x80	/* Two sets of 1-3 axis */
+
+/* I/O Descriptor
+ */
+#define HIL_IDD_IOD_NBUTTON_MASK	0x07	/* Number of buttons */
+#define HIL_IDD_IOD_PROXIMITY		0x08	/* Proximity in/out events */
+#define HIL_IDD_IOD_PROMPT_MASK		0x70	/* Number of prompts/acks */
+#define HIL_IDD_IOD_PROMPT_SHIFT	4
+#define HIL_IDD_IOD_PROMPT		0x80	/* Generic prompt/ack */
+
+#define HIL_IDD_NUM_AXES_PER_SET(header_packet) \
+((header_packet) & HIL_IDD_HEADER_AXSET_MASK)
+
+#define HIL_IDD_NUM_AXSETS(header_packet) \
+(2 - !((header_packet) & HIL_IDD_HEADER_2X_AXIS))
+
+#define HIL_IDD_LEN(header_packet) \
+((4 - !(header_packet & HIL_IDD_HEADER_IOD) -			\
+  2 * !(HIL_IDD_NUM_AXES_PER_SET(header_packet))) +		\
+  2 * HIL_IDD_NUM_AXES_PER_SET(header_packet) *			\
+ !!((header_packet) & HIL_IDD_HEADER_ABS))
+
+/* The following HIL_IDD_* macros assume you have an array of 
+ * packets and/or unpacked 8-bit data in the order that they 
+ * were received.
+ */
+
+#define HIL_IDD_AXIS_COUNTS_PER_M(header_ptr) \
+(!(HIL_IDD_NUM_AXSETS(*(header_ptr))) ? -1 :			\
+(((*(header_ptr + 1) & HIL_PKT_DATA_MASK) +			\
+  ((*(header_ptr + 2) & HIL_PKT_DATA_MASK)) << 8)		\
+* ((*(header_ptr) & HIL_IDD_HEADER_16BIT) ? 100 : 1)))
+
+#define HIL_IDD_AXIS_MAX(header_ptr, __axnum) \
+((!(*(header_ptr) & HIL_IDD_HEADER_ABS) ||			\
+  (HIL_IDD_NUM_AXES_PER_SET(*(header_ptr)) <= __axnum)) ? 0 :	\
+ ((HIL_PKT_DATA_MASK & *((header_ptr) + 3 + 2 * __axnum)) +	\
+  ((HIL_PKT_DATA_MASK & *((header_ptr) + 4 + 2 * __axnum)) << 8)))
+
+#define HIL_IDD_IOD(header_ptr) \
+(*(header_ptr + HIL_IDD_LEN((*header_ptr)) - 1))
+
+#define HIL_IDD_HAS_GEN_PROMPT(header_ptr) \
+((*header_ptr & HIL_IDD_HEADER_IOD) &&				\
+ (HIL_IDD_IOD(header_ptr) & HIL_IDD_IOD_PROMPT))
+
+#define HIL_IDD_HAS_GEN_PROXIMITY(header_ptr) \
+((*header_ptr & HIL_IDD_HEADER_IOD) &&				\
+ (HIL_IDD_IOD(header_ptr) & HIL_IDD_IOD_PROXIMITY))
+
+#define HIL_IDD_NUM_BUTTONS(header_ptr) \
+((*header_ptr & HIL_IDD_HEADER_IOD) ?				\
+ (HIL_IDD_IOD(header_ptr) & HIL_IDD_IOD_NBUTTON_MASK) : 0)
+
+#define HIL_IDD_NUM_PROMPTS(header_ptr) \
+((*header_ptr & HIL_IDD_HEADER_IOD) ?				\
+ ((HIL_IDD_IOD(header_ptr) & HIL_IDD_IOD_NPROMPT_MASK)		\
+  >> HIL_IDD_IOD_PROMPT_SHIFT) : 0)
+
+/* The response to HIL EXD commands -- the "extended describe record" */
+#define	HIL_EXD_HEADER_WRG		0x03	/* Supports type2 WRG */
+#define HIL_EXD_HEADER_WRG_TYPE1	0x01	/* Supports type1 WRG */
+#define	HIL_EXD_HEADER_WRG_TYPE2	0x02	/* Supports type2 WRG */
+#define	HIL_EXD_HEADER_RRG		0x04	/* Supports RRG command */
+#define	HIL_EXD_HEADER_RNM		0x10	/* Supports RNM command */
+#define HIL_EXD_HEADER_RST		0x20	/* Supports RST command */
+#define HIL_EXD_HEADER_LOCALE		0x40	/* Contains locale code */
+
+#define HIL_EXD_NUM_RRG(header_ptr) \
+((*header_ptr & HIL_EXD_HEADER_RRG) ? \
+ (*(header_ptr + 1) & HIL_PKT_DATA_MASK) : 0)
+
+#define HIL_EXD_NUM_WWG(header_ptr) \
+((*header_ptr & HIL_EXD_HEADER_WRG) ?				\
+ (*(header_ptr + 2 - !(*header_ptr & HIL_EXD_HEADER_RRG)) &	\
+    HIL_PKT_DATA_MASK) : 0)
+
+#define HIL_EXD_LEN(header_ptr) \
+(!!(*header_ptr & HIL_EXD_HEADER_RRG) +				\
+ !!(*header_ptr & HIL_EXD_HEADER_WRG) +				\
+ !!(*header_ptr & HIL_EXD_HEADER_LOCALE) +			\
+ 2 * !!(*header_ptr & HIL_EXD_HEADER_WRG_TYPE2) + 1)
+
+#define HIL_EXD_LOCALE(header_ptr) \
+(!(*header_ptr & HIL_EXD_HEADER_LOCALE) ? -1 :			\
+ (*(header_ptr + HIL_EXD_LEN(header_ptr) - 1) & HIL_PKT_DATA_MASK))
+
+#define HIL_EXD_WRG_TYPE2_LEN(header_ptr) \
+(!(*header_ptr & HIL_EXD_HEADER_WRG_TYPE2) ? -1	:			\
+ (*(header_ptr + HIL_EXD_LEN(header_ptr) - 2 -                  	\
+    !!(*header_ptr & HIL_EXD_HEADER_LOCALE)) & HIL_PKT_DATA_MASK) +	\
+ ((*(header_ptr + HIL_EXD_LEN(header_ptr) - 1 -				\
+     !!(*header_ptr & HIL_EXD_HEADER_LOCALE)) & HIL_PKT_DATA_MASK) << 8))
+
+/* Device locale codes. */ 
+
+/* Last defined locale code.  Everything above this is "Reserved",
+   and note that this same table applies to the Device ID Byte where 
+   keyboards may have a nationality code which is only 5 bits. */
+#define HIL_LOCALE_MAX 0x1f
+
+/* Map to hopefully useful strings.  I was trying to make these look
+   like locale.aliases strings do; maybe that isn't the right table to
+   emulate.  In either case, I didn't have much to work on. */
+#define HIL_LOCALE_MAP \
+"",			/* 0x00 Reserved */		\
+"",			/* 0x01 Reserved */		\
+"",			/* 0x02 Reserved */		\
+"swiss.french",		/* 0x03 Swiss/French */		\
+"portuguese",		/* 0x04 Portuguese */		\
+"arabic",		/* 0x05 Arabic */		\
+"hebrew",		/* 0x06 Hebrew */		\
+"english.canadian",	/* 0x07 Canadian English */	\
+"turkish",		/* 0x08 Turkish */		\
+"greek",		/* 0x09 Greek */		\
+"thai",			/* 0x0a Thai (Thailand) */	\
+"italian",		/* 0x0b Italian */		\
+"korean",		/* 0x0c Hangul (Korea) */	\
+"dutch",		/* 0x0d Dutch */		\
+"swedish",		/* 0x0e Swedish */		\
+"german",		/* 0x0f German */		\
+"chinese",		/* 0x10 Chinese-PRC */		\
+"chinese",		/* 0x11 Chinese-ROC */		\
+"swiss.french",		/* 0x12 Swiss/French II */	\
+"spanish",		/* 0x13 Spanish */		\
+"swiss.german",		/* 0x14 Swiss/German II */	\
+"flemish",		/* 0x15 Belgian (Flemish) */	\
+"finnish",		/* 0x16 Finnish	*/		\
+"english.uk",		/* 0x17 United Kingdom */	\
+"french.canadian",	/* 0x18 French/Canadian */	\
+"swiss.german",		/* 0x19 Swiss/German */		\
+"norwegian",		/* 0x1a Norwegian */		\
+"french",		/* 0x1b French */		\
+"danish",		/* 0x1c Danish */		\
+"japanese",		/* 0x1d Katakana */		\
+"spanish",		/* 0x1e Latin American/Spanish*/\
+"english.us"		/* 0x1f United States */	\
+
+
+/* Response to POL command, the "poll record header" */
+
+#define HIL_POL_NUM_AXES_MASK	0x03	/* Number of axis reported */
+#define HIL_POL_CTS		0x04	/* Device ready to receive data */
+#define HIL_POL_STATUS_PENDING	0x08	/* Device has status to report */
+#define HIL_POL_CHARTYPE_MASK	0x70	/* Type of character data to follow */
+#define HIL_POL_CHARTYPE_NONE	0x00	/* No character data to follow */
+#define HIL_POL_CHARTYPE_RSVD1	0x10	/* Reserved Set 1 */
+#define HIL_POL_CHARTYPE_ASCII	0x20	/* U.S. ASCII */
+#define HIL_POL_CHARTYPE_BINARY	0x30	/* Binary data */
+#define HIL_POL_CHARTYPE_SET1	0x40	/* Keycode Set 1 */
+#define HIL_POL_CHARTYPE_RSVD2	0x50	/* Reserved Set 2 */
+#define HIL_POL_CHARTYPE_SET2	0x60	/* Keycode Set 2 */
+#define HIL_POL_CHARTYPE_SET3	0x70	/* Keycode Set 3 */
+#define HIL_POL_AXIS_ALT	0x80	/* Data is from axis set 2 */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/hil_mlc.h linux-2.4.20/include/linux/hil_mlc.h
--- linux-2.4.19/include/linux/hil_mlc.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/hil_mlc.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,171 @@
+/*
+ * HP Human Interface Loop Master Link Controller driver.
+ *
+ * Copyright (c) 2001 Brian S. Julin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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
+ *
+ * References:
+ * HP-HIL Technical Reference Manual.  Hewlett Packard Product No. 45918A
+ *
+ */
+
+#include <linux/hil.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <asm/semaphore.h>
+#include <linux/serio.h>
+#include <linux/list.h>
+
+typedef struct hil_mlc hil_mlc;
+
+/* The HIL has a complicated state engine.
+ * We define the structure of nodes in the state engine here.
+ */
+enum hilse_act {
+  	/* HILSE_OUT prepares to receive input if the next node
+	 * is an IN or EXPECT, and then sends the given packet.
+	 */
+	HILSE_OUT = 0,
+
+  	/* HILSE_CTS checks if the loop is busy. */
+	HILSE_CTS,
+
+	/* HILSE_OUT_LAST sends the given command packet to 
+	 * the last configured/running device on the loop.
+	 */
+	HILSE_OUT_LAST,
+
+	/* HILSE_OUT_DISC sends the given command packet to
+	 * the next device past the last configured/running one.
+	 */
+	HILSE_OUT_DISC,
+
+	/* HILSE_FUNC runs a callback function with given arguments.
+	 * a positive return value causes the "ugly" branch to be taken.
+	 */
+	HILSE_FUNC,
+
+  	/* HILSE_IN simply expects any non-errored packet to arrive 
+	 * within arg usecs.
+	 */
+	HILSE_IN		= 0x100,
+
+  	/* HILSE_EXPECT expects a particular packet to arrive 
+	 * within arg usecs, any other packet is considered an error.
+	 */
+	HILSE_EXPECT,
+
+  	/* HILSE_EXPECT_LAST as above but dev field should be last 
+	 * discovered/operational device.
+	 */
+	HILSE_EXPECT_LAST,
+
+  	/* HILSE_EXPECT_LAST as above but dev field should be first 
+	 * undiscovered/inoperational device.
+	 */
+	HILSE_EXPECT_DISC
+};
+
+typedef int	(hilse_func) (hil_mlc *mlc, int arg);
+struct hilse_node {
+	enum hilse_act		act;	/* How to process this node         */
+	union {
+		hilse_func	*func;	/* Function to call if HILSE_FUNC   */
+		hil_packet	packet;	/* Packet to send or to compare     */
+	} object;
+	int			arg;	/* Timeout in usec or parm for func */
+	int			good;	/* Node to jump to on success       */
+	int			bad;	/* Node to jump to on error         */
+	int			ugly;	/* Node to jump to on timeout       */
+};
+
+/* Methods for back-end drivers, e.g. hp_sdc_mlc */
+typedef int	(hil_mlc_cts) (hil_mlc *mlc);
+typedef void	(hil_mlc_out) (hil_mlc *mlc);
+typedef int	(hil_mlc_in)  (hil_mlc *mlc, suseconds_t timeout);
+
+struct hil_mlc_devinfo {
+	uint8_t	idd[16];	/* Device ID Byte and Describe Record */
+	uint8_t	rsc[16];	/* Security Code Header and Record */
+	uint8_t	exd[16];	/* Extended Describe Record */
+	uint8_t	rnm[16];	/* Device name as returned by RNM command */
+};
+
+struct hil_mlc_serio_map {
+	hil_mlc *mlc;
+	int di_revmap;
+	int didx;
+};
+
+/* How many (possibly old/detached) devices the we try to keep track of */
+#define HIL_MLC_DEVMEM 16
+
+struct hil_mlc {
+	struct list_head	list;	/* hil_mlc is organized as linked list */
+
+	rwlock_t		lock;
+
+	void *priv; /* Data specific to a particular type of MLC */
+
+	int 			seidx;	/* Current node in state engine */
+	int			istarted, ostarted;
+
+	hil_mlc_cts		*cts;
+	struct semaphore	csem;   /* Raised when loop idle */
+
+	hil_mlc_out		*out;
+	struct semaphore	osem;   /* Raised when outpacket dispatched */
+	hil_packet		opacket;
+
+	hil_mlc_in		*in;
+	struct semaphore	isem;   /* Raised when a packet arrives */
+	hil_packet		ipacket[16];
+	hil_packet		imatch;
+	int			icount;
+	struct timeval		instart;
+	suseconds_t		intimeout;
+
+	int			ddi;	/* Last operational device id */
+	int			lcv;	/* LCV to throttle loops */
+	struct timeval		lcv_tv; /* Time loop was started */
+
+	int			di_map[7]; /* Maps below items to live devs */
+	struct hil_mlc_devinfo	di[HIL_MLC_DEVMEM];
+	struct serio		serio[HIL_MLC_DEVMEM];
+	struct hil_mlc_serio_map serio_map[HIL_MLC_DEVMEM];
+	hil_packet		serio_opacket[HIL_MLC_DEVMEM];
+	int			serio_oidx[HIL_MLC_DEVMEM];
+	struct hil_mlc_devinfo	di_scratch; /* Temporary area */
+
+	void			(*inc_use_count)(void);
+	void			(*dec_use_count)(void);
+
+	int			opercnt;
+
+	struct tasklet_struct	*tasklet;
+};
+
+int hil_mlc_register(hil_mlc *mlc);
+int hil_mlc_unregister(hil_mlc *mlc);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/hp_sdc.h linux-2.4.20/include/linux/hp_sdc.h
--- linux-2.4.19/include/linux/hp_sdc.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/hp_sdc.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,296 @@
+/*
+ * HP i8042 System Device Controller -- header
+ *
+ * Copyright (c) 2001 Brian S. Julin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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
+ *
+ * References:
+ * 
+ * HP-HIL Technical Reference Manual.  Hewlett Packard Product No. 45918A
+ *
+ * System Device Controller Microprocessor Firmware Theory of Operation
+ * 	for Part Number 1820-4784 Revision B.  Dwg No. A-1820-4784-2
+ *
+ */
+
+#ifndef _LINUX_HP_SDC_H
+#define _LINUX_HP_SDC_H
+
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <asm/hardware.h>
+
+
+/* No 4X status reads take longer than this (in usec).
+ */
+#define HP_SDC_MAX_REG_DELAY 20000
+
+typedef void (hp_sdc_irqhook) (int irq, void *dev_id, 
+			       uint8_t status, uint8_t data);
+
+int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback);
+int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback);
+int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback);
+int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback);
+int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback);
+int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback);
+
+typedef struct {
+	int actidx;	/* Start of act.  Acts are atomic WRT I/O to SDC */
+	int idx;	/* Index within the act */
+	int endidx;	/* transaction is over and done if idx == endidx */
+	uint8_t *seq;	/* commands/data for the transaction */
+	union {
+	  hp_sdc_irqhook   *irqhook;	/* Callback, isr or tasklet context */
+	  struct semaphore *semaphore;	/* Semaphore to sleep on. */
+	} act;
+} hp_sdc_transaction;
+int hp_sdc_enqueue_transaction(hp_sdc_transaction *this);
+int hp_sdc_dequeue_transaction(hp_sdc_transaction *this);
+
+/* The HP_SDC_ACT* values are peculiar to this driver.
+ * Nuance: never HP_SDC_ACT_DATAIN | HP_SDC_ACT_DEALLOC, use another
+ * act to perform the dealloc.
+ */
+#define HP_SDC_ACT_PRECMD	0x01		/* Send a command first */
+#define HP_SDC_ACT_DATAREG	0x02		/* Set data registers */
+#define HP_SDC_ACT_DATAOUT	0x04		/* Send data bytes */
+#define HP_SDC_ACT_POSTCMD      0x08            /* Send command after */
+#define HP_SDC_ACT_DATAIN	0x10		/* Collect data after */
+#define HP_SDC_ACT_DURING	0x1f
+#define HP_SDC_ACT_SEMAPHORE    0x20            /* Raise semaphore after */
+#define HP_SDC_ACT_CALLBACK	0x40		/* Pass data to IRQ handler */
+#define HP_SDC_ACT_DEALLOC	0x80		/* Destroy transaction after */
+#define HP_SDC_ACT_AFTER	0xe0
+#define HP_SDC_ACT_DEAD		0x60		/* Act timed out. */
+
+/* Rest of the flags are straightforward representation of the SDC interface */
+#define HP_SDC_STATUS_IBF	0x02	/* Input buffer full */
+
+#define HP_SDC_STATUS_IRQMASK	0xf0	/* Bits containing "level 1" irq */
+#define HP_SDC_STATUS_PERIODIC  0x10    /* Periodic 10ms timer */
+#define HP_SDC_STATUS_USERTIMER 0x20    /* "Special purpose" timer */
+#define HP_SDC_STATUS_TIMER     0x30    /* Both PERIODIC and USERTIMER */
+#define HP_SDC_STATUS_REG	0x40	/* Data from an i8042 register */
+#define HP_SDC_STATUS_HILCMD    0x50	/* Command from HIL MLC */
+#define HP_SDC_STATUS_HILDATA   0x60	/* Data from HIL MLC */
+#define HP_SDC_STATUS_PUP	0x70	/* Sucessful power-up self test */
+#define HP_SDC_STATUS_KCOOKED	0x80	/* Key from cooked kbd */
+#define HP_SDC_STATUS_KRPG	0xc0	/* Key from Repeat Gen */
+#define HP_SDC_STATUS_KMOD_SUP	0x10	/* Shift key is up */
+#define HP_SDC_STATUS_KMOD_CUP	0x20	/* Control key is up */
+
+#define HP_SDC_NMISTATUS_FHS	0x40	/* NMI is a fast handshake irq */
+
+/* Internal i8042 registers (there are more, but they are not too useful). */
+
+#define HP_SDC_USE		0x02	/* Resource usage (including OB bit) */
+#define HP_SDC_IM		0x04	/* Interrupt mask */
+#define HP_SDC_CFG		0x11	/* Configuration register */
+#define HP_SDC_KBLANGUAGE	0x12	/* Keyboard language */
+
+#define HP_SDC_D0		0x70	/* General purpose data buffer 0 */
+#define HP_SDC_D1		0x71	/* General purpose data buffer 1 */
+#define HP_SDC_D2		0x72	/* General purpose data buffer 2 */
+#define HP_SDC_D3		0x73	/* General purpose data buffer 3 */
+#define HP_SDC_VT1		0x74	/* Timer for voice 1 */
+#define HP_SDC_VT2		0x75	/* Timer for voice 2 */
+#define HP_SDC_VT3		0x76	/* Timer for voice 3 */
+#define HP_SDC_VT4		0x77	/* Timer for voice 4 */
+#define HP_SDC_KBN		0x78	/* Which HIL devs are Nimitz */
+#define HP_SDC_KBC		0x79	/* Which HIL devs are cooked kbds */
+#define HP_SDC_LPS		0x7a	/* i8042's view of HIL status */
+#define HP_SDC_LPC		0x7b	/* i8042's view of HIL "control" */
+#define HP_SDC_RSV  		0x7c	/* Reserved "for testing" */
+#define HP_SDC_LPR		0x7d    /* i8042 count of HIL reconfigs */
+#define HP_SDC_XTD		0x7e    /* "Extended Configuration" register */
+#define HP_SDC_STR		0x7f    /* i8042 self-test result */
+
+/* Bitfields for above registers */
+#define HP_SDC_USE_LOOP		0x04	/* Command is currently on the loop. */
+
+#define HP_SDC_IM_MASK          0x1f    /* these bits not part of cmd/status */
+#define HP_SDC_IM_FH		0x10	/* Mask the fast handshake irq */
+#define HP_SDC_IM_PT		0x08	/* Mask the periodic timer irq */
+#define HP_SDC_IM_TIMERS	0x04	/* Mask the MT/DT/CT irq */
+#define HP_SDC_IM_RESET		0x02	/* Mask the reset key irq */
+#define HP_SDC_IM_HIL		0x01	/* Mask the HIL MLC irq */
+
+#define HP_SDC_CFG_ROLLOVER	0x08	/* WTF is "N-key rollover"? */
+#define HP_SDC_CFG_KBD		0x10	/* There is a keyboard */
+#define HP_SDC_CFG_NEW		0x20	/* Supports/uses HIL MLC */
+#define HP_SDC_CFG_KBD_OLD	0x03	/* keyboard code for non-HIL */
+#define HP_SDC_CFG_KBD_NEW	0x07	/* keyboard code from HIL autoconfig */
+#define HP_SDC_CFG_REV		0x40	/* Code revision bit */
+#define HP_SDC_CFG_IDPROM	0x80	/* IDPROM present in kbd (not HIL) */
+
+#define HP_SDC_LPS_NDEV		0x07	/* # devices autoconfigured on HIL */
+#define HP_SDC_LPS_ACSUCC	0x08	/* loop autoconfigured successfully */
+#define HP_SDC_LPS_ACFAIL	0x80	/* last loop autoconfigure failed */
+
+#define HP_SDC_LPC_APE_IPF	0x01	/* HIL MLC APE/IPF (autopoll) set */
+#define HP_SDC_LPC_ARCONERR	0x02	/* i8042 autoreconfigs loop on err */
+#define HP_SDC_LPC_ARCQUIET	0x03	/* i8042 doesn't report autoreconfigs*/
+#define HP_SDC_LPC_COOK		0x10	/* i8042 cooks devices in _KBN */
+#define HP_SDC_LPC_RC		0x80	/* causes autoreconfig */
+
+#define HP_SDC_XTD_REV		0x07	/* contains revision code */
+#define HP_SDC_XTD_REV_STRINGS(val, str) \
+switch (val) {						\
+	case 0x1: str = "1820-3712"; break;		\
+	case 0x2: str = "1820-4379"; break;		\
+	case 0x3: str = "1820-4784"; break;		\
+	default: str = "unknown";			\
+};
+#define HP_SDC_XTD_BEEPER	0x08	/* TI SN76494 beeper available */
+#define HP_SDC_XTD_BBRTC	0x20	/* OKI MSM-58321 BBRTC present */
+
+#define HP_SDC_CMD_LOAD_RT	0x31	/* Load real time (from 8042) */
+#define HP_SDC_CMD_LOAD_FHS	0x36	/* Load the fast handshake timer */
+#define HP_SDC_CMD_LOAD_MT	0x38	/* Load the match timer */
+#define HP_SDC_CMD_LOAD_DT	0x3B	/* Load the delay timer */
+#define HP_SDC_CMD_LOAD_CT	0x3E	/* Load the cycle timer */
+
+#define HP_SDC_CMD_SET_IM	0x40    /* 010xxxxx == set irq mask */
+
+/* The documents provided do not explicitly state that all registers betweem 
+ * 0x01 and 0x1f inclusive can be read by sending their register index as a 
+ * command, but this is implied and appears to be the case.
+ */
+#define HP_SDC_CMD_READ_RAM	0x00	/* Load from i8042 RAM (autoinc) */
+#define HP_SDC_CMD_READ_USE	0x02	/* Undocumented! Load from usage reg */
+#define HP_SDC_CMD_READ_IM	0x04	/* Load current interrupt mask */
+#define HP_SDC_CMD_READ_KCC	0x11	/* Load primary kbd config code */
+#define HP_SDC_CMD_READ_KLC	0x12	/* Load primary kbd language code */
+#define HP_SDC_CMD_READ_T1	0x13	/* Load timer output buffer byte 1 */
+#define HP_SDC_CMD_READ_T2	0x14	/* Load timer output buffer byte 1 */
+#define HP_SDC_CMD_READ_T3	0x15	/* Load timer output buffer byte 1 */
+#define HP_SDC_CMD_READ_T4	0x16	/* Load timer output buffer byte 1 */
+#define HP_SDC_CMD_READ_T5	0x17	/* Load timer output buffer byte 1 */
+#define HP_SDC_CMD_READ_D0	0xf0	/* Load from i8042 RAM location 0x70 */
+#define HP_SDC_CMD_READ_D1	0xf1	/* Load from i8042 RAM location 0x71 */
+#define HP_SDC_CMD_READ_D2	0xf2	/* Load from i8042 RAM location 0x72 */
+#define HP_SDC_CMD_READ_D3	0xf3	/* Load from i8042 RAM location 0x73 */
+#define HP_SDC_CMD_READ_VT1	0xf4	/* Load from i8042 RAM location 0x74 */
+#define HP_SDC_CMD_READ_VT2	0xf5	/* Load from i8042 RAM location 0x75 */
+#define HP_SDC_CMD_READ_VT3	0xf6	/* Load from i8042 RAM location 0x76 */
+#define HP_SDC_CMD_READ_VT4	0xf7	/* Load from i8042 RAM location 0x77 */
+#define HP_SDC_CMD_READ_KBN	0xf8	/* Load from i8042 RAM location 0x78 */
+#define HP_SDC_CMD_READ_KBC	0xf9	/* Load from i8042 RAM location 0x79 */
+#define HP_SDC_CMD_READ_LPS	0xfa	/* Load from i8042 RAM location 0x7a */
+#define HP_SDC_CMD_READ_LPC	0xfb	/* Load from i8042 RAM location 0x7b */
+#define HP_SDC_CMD_READ_RSV	0xfc	/* Load from i8042 RAM location 0x7c */
+#define HP_SDC_CMD_READ_LPR	0xfd	/* Load from i8042 RAM location 0x7d */
+#define HP_SDC_CMD_READ_XTD	0xfe	/* Load from i8042 RAM location 0x7e */
+#define HP_SDC_CMD_READ_STR	0xff	/* Load from i8042 RAM location 0x7f */
+
+#define HP_SDC_CMD_SET_ARD	0xA0	/* Set emulated autorepeat delay */
+#define HP_SDC_CMD_SET_ARR	0xA2	/* Set emulated autorepeat rate */
+#define HP_SDC_CMD_SET_BELL	0xA3	/* Set voice 3 params for "beep" cmd */
+#define HP_SDC_CMD_SET_RPGR	0xA6	/* Set "RPG" irq rate (doesn't work) */
+#define HP_SDC_CMD_SET_RTMS	0xAD	/* Set the RTC time (milliseconds) */
+#define HP_SDC_CMD_SET_RTD	0xAF	/* Set the RTC time (days) */
+#define HP_SDC_CMD_SET_FHS	0xB2	/* Set fast handshake timer */
+#define HP_SDC_CMD_SET_MT	0xB4	/* Set match timer */
+#define HP_SDC_CMD_SET_DT	0xB7	/* Set delay timer */
+#define HP_SDC_CMD_SET_CT	0xBA	/* Set cycle timer */
+#define HP_SDC_CMD_SET_RAMP	0xC1	/* Reset READ_RAM autoinc counter */
+#define HP_SDC_CMD_SET_D0	0xe0	/* Load to i8042 RAM location 0x70 */
+#define HP_SDC_CMD_SET_D1	0xe1	/* Load to i8042 RAM location 0x71 */
+#define HP_SDC_CMD_SET_D2	0xe2	/* Load to i8042 RAM location 0x72 */
+#define HP_SDC_CMD_SET_D3	0xe3	/* Load to i8042 RAM location 0x73 */
+#define HP_SDC_CMD_SET_VT1	0xe4	/* Load to i8042 RAM location 0x74 */
+#define HP_SDC_CMD_SET_VT2	0xe5	/* Load to i8042 RAM location 0x75 */
+#define HP_SDC_CMD_SET_VT3	0xe6	/* Load to i8042 RAM location 0x76 */
+#define HP_SDC_CMD_SET_VT4	0xe7	/* Load to i8042 RAM location 0x77 */
+#define HP_SDC_CMD_SET_KBN	0xe8	/* Load to i8042 RAM location 0x78 */
+#define HP_SDC_CMD_SET_KBC	0xe9	/* Load to i8042 RAM location 0x79 */
+#define HP_SDC_CMD_SET_LPS	0xea	/* Load to i8042 RAM location 0x7a */
+#define HP_SDC_CMD_SET_LPC	0xeb	/* Load to i8042 RAM location 0x7b */
+#define HP_SDC_CMD_SET_RSV	0xec	/* Load to i8042 RAM location 0x7c */
+#define HP_SDC_CMD_SET_LPR	0xed	/* Load to i8042 RAM location 0x7d */
+#define HP_SDC_CMD_SET_XTD	0xee	/* Load to i8042 RAM location 0x7e */
+#define HP_SDC_CMD_SET_STR	0xef	/* Load to i8042 RAM location 0x7f */
+
+#define HP_SDC_CMD_DO_RTCW	0xc2	/* i8042 RAM 0x70 --> RTC */
+#define HP_SDC_CMD_DO_RTCR	0xc3	/* RTC[0x70 0:3] --> irq/status/data */
+#define HP_SDC_CMD_DO_BEEP	0xc4	/* i8042 RAM 0x70-74  --> beeper,VT3 */
+#define HP_SDC_CMD_DO_HIL	0xc5	/* i8042 RAM 0x70-73 --> 
+					   HIL MLC R0,R1 i8042 HIL watchdog */
+
+/* Values used to (de)mangle input/output to/from the HIL MLC */
+#define HP_SDC_DATA		0x40	/* Data from an 8042 register */
+#define HP_SDC_HIL_CMD		0x50	/* Data from HIL MLC R1/8042 */
+#define HP_SDC_HIL_R1MASK	0x0f	/* Contents of HIL MLC R1 0:3 */
+#define HP_SDC_HIL_AUTO		0x10	/* Set if POL results from i8042 */   
+#define HP_SDC_HIL_ISERR	0x80	/* Has meaning as in next 4 values */
+#define HP_SDC_HIL_RC_DONE	0x80	/* i8042 auto-configured loop */
+#define HP_SDC_HIL_ERR		0x81	/* HIL MLC R2 had a bit set */
+#define HP_SDC_HIL_TO		0x82	/* i8042 HIL watchdog expired */
+#define HP_SDC_HIL_RC		0x84	/* i8042 is auto-configuring loop */
+#define HP_SDC_HIL_DAT		0x60	/* Data from HIL MLC R0 */
+
+
+typedef struct {
+	rwlock_t	ibf_lock;
+	rwlock_t	lock;		/* user/tasklet lock */
+	rwlock_t	rtq_lock;	/* isr/tasklet lock */
+	rwlock_t	hook_lock;	/* isr/user lock for handler add/del */
+
+	unsigned int	irq, nmi;	/* Our IRQ lines */
+	unsigned long	base_io, status_io, data_io; /* Our IO ports */
+
+	uint8_t		im;		/* Interrupt mask */
+	int		set_im; 	/* Interrupt mask needs to be set. */
+
+	int		ibf;		/* Last known status of IBF flag */
+	uint8_t		wi;		/* current i8042 write index */
+	uint8_t		r7[4];          /* current i8042[0x70 - 0x74] values */
+	uint8_t		r11, r7e;	/* Values from version/revision regs */
+
+	hp_sdc_irqhook	*timer, *reg, *hil, *pup, *cooked;
+
+#define HP_SDC_QUEUE_LEN 16
+	hp_sdc_transaction *tq[HP_SDC_QUEUE_LEN]; /* All pending read/writes */
+
+	int		rcurr, rqty;	/* Current read transact in process */
+	struct timeval	rtv;		/* Time when current read started */
+	int		wcurr;		/* Current write transact in process */
+
+#ifdef __hppa__
+	struct parisc_device	*dev;
+	int		dev_err;	/* carries status from registration */
+#else
+#error No support for device registration on this arch yet.
+#endif
+
+	struct timer_list kicker;	/* Keeps below task alive */
+	struct tasklet_struct	task;
+
+} hp_i8042_sdc;
+
+#endif /* _LINUX_HP_SDC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/ide.h linux-2.4.20/include/linux/ide.h
--- linux-2.4.19/include/linux/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/ide.h	2002-10-29 11:18:34.000000000 +0000
@@ -552,6 +552,7 @@
 	unsigned	reset      : 1;	/* reset after probe */
 	unsigned	autodma    : 1;	/* automatically try to enable DMA at boot */
 	unsigned	udma_four  : 1;	/* 1=ATA-66 capable, 0=default */
+	unsigned	no_highio  : 1; /* don't trust pci dma mask, bounce */
 	byte		channel;	/* for dual-port chips: 0=primary, 1=secondary */
 #ifdef CONFIG_BLK_DEV_IDEPCI
 	struct pci_dev	*pci_dev;	/* for pci chipsets */
@@ -874,6 +875,21 @@
 } ide_action_t;
 
 /*
+ * temporarily mapping a (possible) highmem bio
+ */
+#define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
+
+extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
+{
+	return bh_kmap_irq(rq->bh, flags) + ide_rq_offset(rq);
+}
+
+extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
+{
+	bh_kunmap_irq(buffer, flags);
+}
+
+/*
  * This function issues a special IDE device request
  * onto the request queue.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/if_ether.h linux-2.4.20/include/linux/if_ether.h
--- linux-2.4.19/include/linux/if_ether.h	2001-10-30 23:08:12.000000000 +0000
+++ linux-2.4.20/include/linux/if_ether.h	2002-10-29 11:18:48.000000000 +0000
@@ -95,6 +95,6 @@
 	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
 	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
 	unsigned short	h_proto;		/* packet type ID field	*/
-};
+} __attribute__((packed));
 
 #endif	/* _LINUX_IF_ETHER_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/if_vlan.h linux-2.4.20/include/linux/if_vlan.h
--- linux-2.4.19/include/linux/if_vlan.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/if_vlan.h	2002-10-29 11:18:34.000000000 +0000
@@ -141,9 +141,10 @@
 	(VLAN_TX_SKB_CB(__skb)->magic == VLAN_TX_COOKIE_MAGIC)
 #define vlan_tx_tag_get(__skb)	(VLAN_TX_SKB_CB(__skb)->vlan_tag)
 
-/* VLAN rx hw acceleration helper.  This acts like netif_rx().  */
-static inline int vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
-				  unsigned short vlan_tag)
+/* VLAN rx hw acceleration helper.  This acts like netif_{rx,receive_skb}(). */
+static inline int __vlan_hwaccel_rx(struct sk_buff *skb,
+				    struct vlan_group *grp,
+				    unsigned short vlan_tag, int polling)
 {
 	struct net_device_stats *stats;
 
@@ -182,9 +183,22 @@
 		break;
 	};
 
-	return netif_rx(skb);
+	return (polling ? netif_receive_skb(skb) : netif_rx(skb));
 }
 
+static inline int vlan_hwaccel_rx(struct sk_buff *skb,
+				  struct vlan_group *grp,
+				  unsigned short vlan_tag)
+{
+	return __vlan_hwaccel_rx(skb, grp, vlan_tag, 0);
+}
+
+static inline int vlan_hwaccel_receive_skb(struct sk_buff *skb,
+					   struct vlan_group *grp,
+					   unsigned short vlan_tag)
+{
+	return __vlan_hwaccel_rx(skb, grp, vlan_tag, 1);
+}
 #endif /* __KERNEL__ */
 
 /* VLAN IOCTLs are found in sockios.h */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/igmp.h linux-2.4.20/include/linux/igmp.h
--- linux-2.4.19/include/linux/igmp.h	2001-04-12 19:11:39.000000000 +0000
+++ linux-2.4.20/include/linux/igmp.h	2002-10-29 11:18:48.000000000 +0000
@@ -113,7 +113,7 @@
 extern void ip_mc_destroy_dev(struct in_device *);
 extern void ip_mc_up(struct in_device *);
 extern void ip_mc_down(struct in_device *);
-extern int ip_mc_dec_group(struct in_device *in_dev, u32 addr);
+extern void ip_mc_dec_group(struct in_device *in_dev, u32 addr);
 extern void ip_mc_inc_group(struct in_device *in_dev, u32 addr);
 #endif
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/input.h linux-2.4.20/include/linux/input.h
--- linux-2.4.19/include/linux/input.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/input.h	2002-10-29 11:18:39.000000000 +0000
@@ -471,6 +471,7 @@
 #define BUS_PCI			0x01
 #define BUS_ISAPNP		0x02
 #define BUS_USB			0x03
+#define BUS_HIL                 0x04
 
 #define BUS_ISA			0x10
 #define BUS_I8042		0x11
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/intermezzo_fs.h linux-2.4.20/include/linux/intermezzo_fs.h
--- linux-2.4.19/include/linux/intermezzo_fs.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.20/include/linux/intermezzo_fs.h	2002-10-29 11:18:39.000000000 +0000
@@ -1,211 +1,358 @@
-/*
- *
- *  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.
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
+ *  Copyright (C) 2001, 2002 Cluster File Systems, Inc.
+ *  Copyright (C) 2001 Tacitus Systems, Inc.
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
  *  Copyright (C) 2000 TurboLinux, Inc.
  *  Copyright (C) 2000 Los Alamos National Laboratory.
- *  Copyright (C) 2001 Tacitus Systems, Inc.
- *  Copyright (C) 2001 Cluster File Systems, Inc. 
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef __INTERMEZZO_FS_H_
 #define __INTERMEZZO_FS_H_ 1
 
+#include <linux/intermezzo_lib.h>
+#include <linux/intermezzo_idl.h>
+
+
 #ifdef __KERNEL__
-#include <linux/smp.h>
-#include <linux/fsfilter.h>
+typedef __u8 uuid_t[16];
+#else
+# include <uuid/uuid.h>
+#endif
+
+struct lento_vfs_context {
+        __u64 kml_offset;
+        __u64 updated_time;
+        __u64 remote_ino;
+        __u64 remote_generation;
+        __u32 slot_offset;
+        __u32 recno;
+        __u32 flags;
+        uuid_t uuid;
+        struct presto_version remote_version;
+};
+
+static inline int izo_ioctl_is_invalid(struct izo_ioctl_data *data);
+
+#ifdef __KERNEL__
+# include <linux/smp.h>
+# include <linux/fsfilter.h>
+# include <linux/slab.h>
+# include <linux/vmalloc.h>
+# include <linux/smp_lock.h>
 
 /* fixups for fs.h */
-#ifndef fs_down
-#define fs_down(sem) down(sem)
-#endif
+# ifndef fs_down
+#  define fs_down(sem) down(sem)
+# endif
+
+# ifndef fs_up
+#  define fs_up(sem) up(sem)
+# endif
+
+# define KML_IDLE                        0
+# define KML_DECODE                      1
+# define KML_OPTIMIZE                    2
+# define KML_REINT                       3
+
+# define KML_OPEN_REINT                  0x0100
+# define KML_REINT_BEGIN                 0x0200
+# define KML_BACKFETCH                   0x0400
+# define KML_REINT_END                   0x0800
+# define KML_CLOSE_REINT                 0x1000
+# define KML_REINT_MAXBUF                (64 * 1024)
 
-#ifndef fs_up
-#define fs_up(sem) up(sem)
-#endif
+# define CACHE_CLIENT_RO       0x4
+# define CACHE_LENTO_RO        0x8
 
-/* We will be more tolerant than the default ea patch with attr name sizes and
- * the size of value. If these come via VFS from the default ea patches, the
- * corresponding character strings will be truncated anyway. During journalling- * we journal length for both name and value. See journal_set_ext_attr.
- */
-#define PRESTO_EXT_ATTR_NAME_MAX 128
-#define PRESTO_EXT_ATTR_VALUE_MAX 8192
+/* global variables */
+extern int presto_debug;
+extern int presto_print_entry;
+extern long presto_kmemory;
+extern long presto_vmemory;
 
-#define KML_IDLE                        0
-#define KML_DECODE                      1
-#define KML_OPTIMIZE                    2
-#define KML_REINT                       3
-
-#define KML_OPEN_REINT                  0x0100
-#define KML_REINT_BEGIN                 0x0200
-#define KML_BACKFETCH                   0x0400
-#define KML_REINT_END                   0x0800
-#define KML_CLOSE_REINT                 0x1000
-#define FSET_GET_KMLDATA(fset)          fset->fset_kmldata
-#define KML_REINT_MAXBUF              	(64 * 1024)
-
-struct  kml_fsdata
-{
-        int                kml_state;
-
-        /* kml optimize support */
-        struct list_head   kml_kop_cache;
-
-        /* kml reint support */
-        int                kml_reint_state;
-        struct list_head   kml_reint_cache;
-        struct list_head  *kml_reint_current;
-        int                kml_maxsize;  /* max buffer */
-        int                kml_len;
-        char *             kml_buf;
-        loff_t             kml_reintpos;
-        int                kml_count;
-};
+# define PRESTO_DEBUG
+# ifdef PRESTO_DEBUG
+/* debugging masks */
+#  define D_SUPER       1
+#  define D_INODE       2
+#  define D_FILE        4
+#  define D_CACHE       8  /* cache debugging */
+#  define D_MALLOC     16  /* print malloc, de-alloc information */
+#  define D_JOURNAL    32
+#  define D_UPCALL     64  /* up and downcall debugging */
+#  define D_PSDEV     128
+#  define D_PIOCTL    256
+#  define D_SPECIAL   512
+#  define D_TIMING   1024
+#  define D_DOWNCALL 2048
+#  define D_KML      4096
+#  define D_FSDATA   8192
 
-/* super.c */
-struct presto_cache *presto_find_cache(kdev_t dev) ;
-extern struct file_system_type presto_fs_type;
-extern int init_intermezzo_fs(void);
+#  define CDEBUG(mask, format, a...)                                    \
+        do {                                                            \
+                if (presto_debug & mask) {                              \
+                        printk("(%s:%s,l. %d %d): " format, __FILE__,   \
+                               __FUNCTION__, __LINE__, current->pid     \
+                               , ## a);                                 \
+                }                                                       \
+        } while (0)
 
-#define CACHE_TYPE_LENGTH       16
+#define CERROR(format, a...)                                            \
+do {                                                                    \
+        printk("(%s:%s,l. %d %d): " format, __FILE__, __FUNCTION__,     \
+               __LINE__, current->pid , ## a);                          \
+} while (0)
 
-int presto_ispresto(struct inode *);
+#  define ENTRY                                                         \
+        if (presto_print_entry)                                         \
+                printk("Process %d entered %s\n", current->pid, __FUNCTION__)
+
+#  define EXIT                                                          \
+        if (presto_print_entry)                                         \
+                printk("Process %d leaving %s at %d\n", current->pid,   \
+                       __FUNCTION__, __LINE__)
+
+#  define presto_kmem_inc(ptr, size) presto_kmemory += (size)
+#  define presto_kmem_dec(ptr, size) presto_kmemory -= (size)
+#  define presto_vmem_inc(ptr, size) presto_vmemory += (size)
+#  define presto_vmem_dec(ptr, size) presto_vmemory -= (size)
+# else /* !PRESTO_DEBUG */
+#  define CDEBUG(mask, format, a...) do {} while (0)
+#  define ENTRY do {} while (0)
+#  define EXIT do {} while (0)
+#  define presto_kmem_inc(ptr, size) do {} while (0)
+#  define presto_kmem_dec(ptr, size) do {} while (0)
+#  define presto_vmem_inc(ptr, size) do {} while (0)
+#  define presto_vmem_dec(ptr, size) do {} while (0)
+# endif /* PRESTO_DEBUG */
+
+
+struct run_ctxt {
+        struct vfsmount *pwdmnt;
+        struct dentry   *pwd;
+        struct vfsmount *rootmnt;
+        struct dentry   *root;
+        uid_t            fsuid;
+        gid_t            fsgid;
+        mm_segment_t     fs;
+	int              ngroups;
+	gid_t	         groups[NGROUPS];
+
+};
 
-#define CACHE_CLIENT_RO       0x4
-#define CACHE_LENTO_RO        0x8
-#define CACHE_FSETROOT_SET     0x10
+static inline void push_ctxt(struct run_ctxt *save, struct run_ctxt *new)
+{
+        int i;
+        save->fs = get_fs();
+        save->pwd = dget(current->fs->pwd);
+        save->pwdmnt = mntget(current->fs->pwdmnt);
+        save->fsgid = current->fsgid;
+        save->fsuid = current->fsuid;
+        save->root = current->fs->root;
+        save->rootmnt = current->fs->rootmnt;
+        save->ngroups = current->ngroups;
+        for (i = 0; i< current->ngroups; i++) 
+                save->groups[i] = current->groups[i];
+
+        set_fs(new->fs);
+        lock_kernel();
+        set_fs_pwd(current->fs, new->pwdmnt, new->pwd);
+        if (new->root)
+                set_fs_root(current->fs, new->rootmnt, new->root);
+        unlock_kernel();
+        current->fsuid = new->fsuid;
+        current->fsgid = new->fsgid;
+        if (new->ngroups > 0) {
+                current->ngroups = new->ngroups;
+                for (i = 0; i< new->ngroups; i++) 
+                        current->groups[i] = new->groups[i];
+        }
+        
+}
+
+static inline void pop_ctxt(struct run_ctxt *saved)
+{
+        int i;
 
+        set_fs(saved->fs);
+        lock_kernel();
+        set_fs_pwd(current->fs, saved->pwdmnt, saved->pwd);
+        if (saved->root)
+                set_fs_root(current->fs, saved->rootmnt, saved->root);
+        unlock_kernel();
+        current->fsuid = saved->fsuid;
+        current->fsgid = saved->fsgid;
+        current->ngroups = saved->ngroups;
+        for (i = 0; i< saved->ngroups; i++) 
+                current->groups[i] = saved->groups[i];
+
+        mntput(saved->pwdmnt);
+        dput(saved->pwd);
+}
+
+static inline struct presto_dentry_data *presto_d2d(struct dentry *dentry)
+{
+        return (struct presto_dentry_data *)(dentry->d_fsdata);
+}
 
 struct presto_cache {
-        spinlock_t         cache_lock; 
-	loff_t             cache_reserved;
-        struct list_head cache_chain; /* for the dev/cache hash */
+        spinlock_t          cache_lock;
+        loff_t              cache_reserved;
+        struct  vfsmount   *cache_vfsmount;
+        struct super_block *cache_sb;
+        struct  dentry     *cache_root;
+        struct list_head    cache_chain; /* for the dev/cache hash */
 
         int   cache_flags;
-        char *cache_root_fileset;  /* fileset mounted on cache "/"  */
 
         kdev_t cache_dev;            /* underlying block device */
-	struct super_block *cache_sb;
-        struct dentry *cache_mtde;  /* unix mtpt of cache XXX NOT VALID XXX */
-        char *cache_mtpt;           /*  again */
 
         char *cache_type;            /* filesystem type of cache */
         struct filter_fs *cache_filter;
 
-        struct upc_comm *cache_psdev;  /* points to /dev/intermezzo? we use */
-        struct list_head cache_psdev_chain; 
-
+        struct upc_channel *cache_psdev;  /* points to channel used */
+        struct list_head cache_channel_list; 
         struct list_head cache_fset_list; /* filesets mounted in cache */
 };
 
-
-
-
-/* file sets */
-#define CHUNK_BITS  16
-
 struct presto_log_fd {
-        rwlock_t         fd_lock; 
-        loff_t           fd_offset;  /* offset where next record should go */ 
+        rwlock_t         fd_lock;
+        loff_t           fd_offset;  /* offset where next record should go */
         struct file    *fd_file;
         int             fd_truncating;
-        unsigned int   fd_recno;   /* last recno written */ 
+        unsigned int   fd_recno;   /* last recno written */
         struct list_head  fd_reservations;
 };
 
+/* file sets */
+# define CHUNK_BITS  16
+
 struct presto_file_set {
         struct list_head fset_list;
         struct presto_log_fd fset_kml;
         struct presto_log_fd fset_lml;
-        struct file *fset_last_rcvd;
-        struct dentry *fset_mtpt;
-        struct nameidata fset_nd; 
+        struct presto_log_fd fset_rcvd;
+        struct list_head *fset_clients;  /* cache of clients */
+        struct dentry *fset_dentry;
+        struct vfsmount *fset_mnt;
         struct presto_cache *fset_cache;
 
         unsigned int fset_lento_recno;  /* last recno mentioned to lento */
         loff_t fset_lento_off;    /* last offset mentioned to lento */
+        loff_t fset_kml_logical_off; /* logical offset of kml file byte 0 */
         char * fset_name;
 
         int fset_flags;
+        int fset_chunkbits;
+        char *fset_reint_buf; /* temporary buffer holds kml during reint */
+
+        spinlock_t fset_permit_lock;
         int fset_permit_count;
-        int fset_permit_cookie;
-        int fset_chunkbits; 
-        int fset_data; /* replaces the dentry d_data field for fsetroots */
-	struct  kml_fsdata *fset_kmldata;
-	loff_t  fset_file_maxio;  /* writing more than this causes a close */ 
+        int fset_permit_upcall_count;
+        /* This queue is used both for processes waiting for the kernel to give
+         * up the permit as well as processes waiting for the kernel to be given
+         * the permit, depending on the state of FSET_HASPERMIT. */
+        wait_queue_head_t fset_permit_queue;
+
+        loff_t  fset_file_maxio;  /* writing more than this causes a close */
+        unsigned long int kml_truncate_size;
 };
 
 /* This is the default number of bytes written before a close is recorded*/
 #define FSET_DEFAULT_MAX_FILEIO (1024<<10)
 
+struct dentry *presto_tmpfs_ilookup(struct inode *dir, struct dentry *dentry, 
+                                    ino_t ino, unsigned int generation);
+struct dentry *presto_iget_ilookup(struct inode *dir, struct dentry *dentry, 
+                                    ino_t ino, unsigned int generation);
+struct dentry *presto_add_ilookup_dentry(struct dentry *parent,
+                                         struct dentry *real);
+
 struct journal_ops {
+        int (*tr_all_data)(struct inode *);
         loff_t (*tr_avail)(struct presto_cache *fset, struct super_block *);
         void *(*tr_start)(struct presto_file_set *, struct inode *, int op);
         void (*tr_commit)(struct presto_file_set *, void *handle);
         void (*tr_journal_data)(struct inode *);
+        struct dentry *(*tr_ilookup)(struct inode *dir, struct dentry *dentry, ino_t ino, unsigned int generation);
+        struct dentry *(*tr_add_ilookup)(struct dentry *parent, struct dentry *real);
 };
 
-
 extern struct journal_ops presto_ext2_journal_ops;
 extern struct journal_ops presto_ext3_journal_ops;
+extern struct journal_ops presto_tmpfs_journal_ops;
 extern struct journal_ops presto_xfs_journal_ops;
 extern struct journal_ops presto_reiserfs_journal_ops;
 extern struct journal_ops presto_obdfs_journal_ops;
-struct lento_vfs_context {
-        __u32 slot_offset;
-        __u32 recno;
-        __u64 kml_offset;
-        __u32 flags;
-        __u32 updated_time;
-};
-
 
-#define LENTO_FL_KML            0x0001
-#define LENTO_FL_EXPECT         0x0002
-#define LENTO_FL_VFSCHECK       0x0004
-#define LENTO_FL_JUSTLOG        0x0008
-#define LENTO_FL_WRITE_KML      0x0010
-#define LENTO_FL_CANCEL_LML     0x0020
-#define LENTO_FL_WRITE_EXPECT   0x0040
-#define LENTO_FL_IGNORE_TIME    0x0080
+# define LENTO_FL_KML            0x0001
+# define LENTO_FL_EXPECT         0x0002
+# define LENTO_FL_VFSCHECK       0x0004
+# define LENTO_FL_JUSTLOG        0x0008
+# define LENTO_FL_WRITE_KML      0x0010
+# define LENTO_FL_CANCEL_LML     0x0020
+# define LENTO_FL_WRITE_EXPECT   0x0040
+# define LENTO_FL_IGNORE_TIME    0x0080
+# define LENTO_FL_TOUCH_PARENT   0x0100
+# define LENTO_FL_TOUCH_NEWOBJ   0x0200
+# define LENTO_FL_SET_DDFILEID   0x0400
 
-struct presto_cache *presto_get_cache(struct inode *inode) ;
+struct presto_cache *presto_get_cache(struct inode *inode);
 int presto_sprint_mounts(char *buf, int buflen, int minor);
 struct presto_file_set *presto_fset(struct dentry *de);
 int presto_journal(struct dentry *dentry, char *buf, size_t size);
 int presto_fwrite(struct file *file, const char *str, int len, loff_t *off);
+int presto_ispresto(struct inode *);
+
+/* super.c */
+extern struct file_system_type presto_fs_type;
+extern int init_intermezzo_fs(void);
+
+/* fileset.c */
+extern int izo_prepare_fileset(struct dentry *root, char *fsetname);
+char * izo_make_path(struct presto_file_set *fset, char *name);
+struct file *izo_fset_open(struct presto_file_set *fset, char *name, int flags, int mode);
 
 /* psdev.c */
+int izo_psdev_get_free_channel(void);
 int presto_psdev_init(void);
+int izo_psdev_setpid(int minor);
 extern void presto_psdev_cleanup(void);
 inline int presto_lento_up(int minor);
+int izo_psdev_setchannel(struct file *file, int fd);
 
 /* inode.c */
 extern struct super_operations presto_super_ops;
-extern int presto_excluded_gid; 
-#define PRESTO_EXCL_GID 4711
 void presto_set_ops(struct inode *inode, struct  filter_fs *filter);
-void presto_read_inode(struct inode *inode);
-void presto_put_super(struct super_block *);
-
-/* journal.c */
-void presto_trans_commit(struct presto_file_set *fset, void *handle);
-void *presto_trans_start(struct presto_file_set *fset, struct inode *inode,
-                           int op);
 
 /* dcache.c */
-void presto_frob_dop(struct dentry *de) ;
-char * presto_path(struct dentry *dentry, struct dentry *root,
-                   char *buffer, int buflen);
+void presto_frob_dop(struct dentry *de);
+char *presto_path(struct dentry *dentry, struct dentry *root,
+                  char *buffer, int buflen);
+inline struct presto_dentry_data *izo_alloc_ddata(void);
+int presto_set_dd(struct dentry *);
+int presto_init_ddata_cache(void);
+void presto_cleanup_ddata_cache(void);
 extern struct dentry_operations presto_dentry_ops;
 
-
-
 /* dir.c */
 extern struct inode_operations presto_dir_iops;
 extern struct inode_operations presto_file_iops;
@@ -214,97 +361,103 @@
 extern struct file_operations presto_file_fops;
 extern struct file_operations presto_sym_fops;
 int presto_setattr(struct dentry *de, struct iattr *iattr);
-extern int presto_ilookup_uid; 
-#define PRESTO_ILOOKUP_MAGIC "...ino:"
-#define PRESTO_ILOOKUP_SEP ':'
-
+int presto_settime(struct presto_file_set *fset, struct dentry *newobj,
+                   struct dentry *parent, struct dentry *target,
+                   struct lento_vfs_context *ctx, int valid);
+int presto_ioctl(struct inode *inode, struct file *file,
+                 unsigned int cmd, unsigned long arg);
+
+extern int presto_ilookup_uid;
+# define PRESTO_ILOOKUP_MAGIC "...ino:"
+# define PRESTO_ILOOKUP_SEP ':'
+int izo_dentry_is_ilookup(struct dentry *, ino_t *id, unsigned int *generation);
 struct dentry *presto_lookup(struct inode * dir, struct dentry *dentry);
 
-/* file.c */
-struct presto_reservation_data {
-        unsigned int ri_recno; 
-        loff_t ri_offset;
-        loff_t ri_size;
-        struct list_head ri_list;
+struct presto_dentry_data {
+        int dd_count; /* how mnay dentries are using this dentry */
+        struct presto_file_set *dd_fset;
+        struct dentry *dd_inodentry; 
+        loff_t dd_kml_offset;
+        int dd_flags;
+        __u64 remote_ino;
+        __u64 remote_generation;
 };
 
-
-struct presto_file_data { 
+struct presto_file_data {
         int fd_do_lml;
         loff_t fd_lml_offset;
-        uid_t fd_fsuid;
-        gid_t fd_fsgid;
+        size_t fd_bytes_written;
+        /* authorization related data of file at open time */
         uid_t fd_uid;
         gid_t fd_gid;
         mode_t fd_mode;
+        /* identification data of calling process */
+        uid_t fd_fsuid;
+        gid_t fd_fsgid;
         int fd_ngroups;
-        size_t fd_bytes_written; /* Number of bytes written so far on this fd*/
         gid_t fd_groups[NGROUPS_MAX];
+        /* information how to complete the close operation */
+        struct lento_vfs_context fd_info;
+        struct presto_version fd_version;
 };
 
-
 /* presto.c and Lento::Downcall */
-struct presto_version {
-        __u64 pv_mtime;
-        __u64 pv_ctime;
-        __u64 pv_size;
-};
+
 int presto_walk(const char *name, struct nameidata *nd);
-int presto_clear_fsetroot(char *path);
-int presto_clear_all_fsetroots(char *path);
-int  presto_get_kmlsize(char *path, size_t *size);
-int  presto_get_lastrecno(char *path, off_t *size);
-int presto_set_fsetroot(char *path, char *fsetname, unsigned int fsetid,
+int izo_clear_fsetroot(struct dentry *dentry);
+int izo_clear_all_fsetroots(struct presto_cache *cache);
+int presto_get_kmlsize(char *path, __u64 *size);
+int presto_get_lastrecno(char *path, off_t *size);
+int presto_set_fsetroot(struct dentry *dentry, char *fsetname,
                        unsigned int flags);
-int presto_has_all_data(struct inode *inode);
+int presto_set_fsetroot_from_ioc(struct dentry *dentry, char *fsetname,
+                                 unsigned int flags);
 inline int presto_is_read_only(struct presto_file_set *);
 int presto_truncate_lml(struct presto_file_set *fset);
 int lento_write_lml(char *path,
-                     __u64 remote_ino, 
+                     __u64 remote_ino,
                      __u32 remote_generation,
                      __u32 remote_version,
                     struct presto_version *remote_file_version);
-int lento_reset_fset(char *path, __u64 offset, __u32 recno);
 int lento_complete_closes(char *path);
-int lento_cancel_lml(char *path,
-                     __u64 lml_offset, 
-                     __u64 remote_ino, 
-                     __u32 remote_generation,
-                     __u32 remote_version, 
-                     struct lento_vfs_context *info);
 inline int presto_f2m(struct presto_file_set *fset);
-
+int presto_prep(struct dentry *, struct presto_cache **,
+                       struct presto_file_set **);
 /* cache.c */
+extern struct presto_cache *presto_cache_init(void);
+extern inline void presto_cache_add(struct presto_cache *cache, kdev_t dev);
+extern inline void presto_cache_init_hash(void);
+
+struct presto_cache *presto_cache_find(kdev_t dev);
+
 #define PRESTO_REQLOW  (3 * 4096)
 #define PRESTO_REQHIGH (6 * 4096)
 void presto_release_space(struct presto_cache *cache, loff_t req);
 int presto_reserve_space(struct presto_cache *cache, loff_t req);
 
-/* NOTE: PRESTO_FSETROOT MUST be 0x1:
-   - if this bit is set dentry->d_fsdata points to a file_set
-   - the address of the file_set if d_fsdata - 1
-*/
-
-#define PRESTO_FSETROOT         0x00000001 /* dentry is fileset root */
 #define PRESTO_DATA             0x00000002 /* cached data is valid */
 #define PRESTO_ATTR             0x00000004 /* attributes cached */
-
-#define EISFSETROOT             0x2001
-
+#define PRESTO_DONT_JOURNAL     0x00000008 /* things like .intermezzo/ */
 
 struct presto_file_set *presto_path2fileset(const char *name);
-int presto_permit_downcall(const char *path, int *cookie);
+int izo_revoke_permit(struct dentry *, uuid_t uuid);
 int presto_chk(struct dentry *dentry, int flag);
 void presto_set(struct dentry *dentry, int flag);
 int presto_get_permit(struct inode *inode);
 int presto_put_permit(struct inode *inode);
-int presto_mark_dentry(const char *path, int and, int or, int *res);
-int presto_mark_cache(const char *path, int and_bits, int or_bits, int *);
-int presto_mark_fset(const char *path, int and_bits, int or_bits, int *);
+int presto_set_max_kml_size(const char *path, unsigned long max_size);
+int izo_mark_dentry(struct dentry *dentry, int and, int or, int *res);
+int izo_mark_cache(struct dentry *dentry, int and_bits, int or_bits, int *);
+int izo_mark_fset(struct dentry *dentry, int and_bits, int or_bits, int *);
 void presto_getversion(struct presto_version *pv, struct inode *inode);
 int presto_i2m(struct inode *inode);
 int presto_c2m(struct presto_cache *cache);
 
+
+/* file.c */
+int izo_purge_file(struct presto_file_set *fset, char *file);
+int presto_adjust_lml(struct file *file, struct lento_vfs_context *info);
+
 /* journal.c */
 struct rec_info {
         loff_t offset;
@@ -312,21 +465,47 @@
         int recno;
         int is_kml;
 };
+
 void presto_trans_commit(struct presto_file_set *fset, void *handle);
 void *presto_trans_start(struct presto_file_set *fset, struct inode *inode,
-                           int op);
-int presto_clear_lml_close(struct presto_file_set *fset, 
+                         int op);
+int presto_fread(struct file *file, char *str, int len, loff_t *off);
+int presto_clear_lml_close(struct presto_file_set *fset,
                            loff_t  lml_offset);
-int presto_write_lml_close(struct rec_info *rec,
-                           struct presto_file_set *fset, 
-                           struct file *file,
-                           __u64 remote_ino,
-                           __u32 remote_generation,
-                           __u32 remote_version,
-                           struct presto_version *new_file_ver);
-int presto_complete_lml(struct presto_file_set *fset); 
+int presto_complete_lml(struct presto_file_set *fset);
+int presto_read_kml_logical_offset(struct rec_info *recinfo,
+                                   struct presto_file_set *fset);
+int presto_write_kml_logical_offset(struct presto_file_set *fset);
+struct file *presto_copy_kml_tail(struct presto_file_set *fset,
+                                  unsigned long int start);
+int presto_finish_kml_truncate(struct presto_file_set *fset,
+                               unsigned long int offset);
+int izo_lookup_file(struct presto_file_set *fset, char *path,
+                    struct nameidata *nd);
+int izo_do_truncate(struct presto_file_set *fset, struct dentry *dentry,
+                    loff_t length,  loff_t size_check);
+int izo_log_close(struct presto_log_fd *logfd);
+struct file *izo_log_open(struct presto_file_set *fset, char *name, int flags);
+int izo_init_kml_file(struct presto_file_set *, struct presto_log_fd *);
+int izo_init_lml_file(struct presto_file_set *, struct presto_log_fd *);
+int izo_init_last_rcvd_file(struct presto_file_set *, struct presto_log_fd *);
 
 /* vfs.c */
+
+/* Extra data needed in the KML for rollback operations; this structure is
+ * passed around during the KML-writing process. */
+struct izo_rollback_data {
+        __u32 rb_mode;
+        __u32 rb_rdev;
+        __u64 rb_uid;
+        __u64 rb_gid;
+};
+
+int presto_write_last_rcvd(struct rec_info *recinfo,
+                           struct presto_file_set *fset,
+                           struct lento_vfs_context *info);
+void izo_get_rollback_data(struct inode *inode, struct izo_rollback_data *rb);
+int presto_do_close(struct presto_file_set *fset, struct file *file);
 int presto_do_setattr(struct presto_file_set *fset, struct dentry *dentry,
                       struct iattr *iattr, struct lento_vfs_context *info);
 int presto_do_create(struct presto_file_set *fset, struct dentry *dir,
@@ -348,9 +527,11 @@
 int presto_do_mknod(struct presto_file_set *fset, struct dentry *dir,
                     struct dentry *dentry, int mode, dev_t dev,
                     struct lento_vfs_context *info);
-int presto_do_rename(struct presto_file_set *fset, struct dentry *old_dir,
-                     struct dentry *old_dentry, struct dentry *new_dir,
-                     struct dentry *new_dentry, struct lento_vfs_context *info);
+int do_rename(struct presto_file_set *fset, struct dentry *old_dir,
+              struct dentry *old_dentry, struct dentry *new_dir,
+              struct dentry *new_dentry, struct lento_vfs_context *info);
+int presto_do_statfs (struct presto_file_set *fset,
+                      struct statfs * buf);
 
 int lento_setattr(const char *name, struct iattr *iattr,
                   struct lento_vfs_context *info);
@@ -367,8 +548,6 @@
 int lento_rename(const char *oldname, const char *newname,
                  struct lento_vfs_context *info);
 int lento_iopen(const char *name, ino_t ino, unsigned int generation,int flags);
-int lento_close(unsigned int fd, struct lento_vfs_context *info);
-
 
 /* journal.c */
 
@@ -376,12 +555,16 @@
 
 __inline__ int presto_no_journal(struct presto_file_set *fset);
 int journal_fetch(int minor);
-int presto_journal_write(struct rec_info *rec, struct presto_file_set *fset,
-                         struct file *file);
+int presto_log(struct presto_file_set *fset, struct rec_info *rec,
+               const char *buf, size_t size,
+               const char *string1, int len1, 
+               const char *string2, int len2,
+               const char *string3, int len3);
+int presto_get_fileid(int minor, struct presto_file_set *fset,
+                      struct dentry *dentry);
 int presto_journal_setattr(struct rec_info *rec, struct presto_file_set *fset,
-                           struct dentry *dentry,
-                           struct presto_version *old_ver,
-                           struct iattr *iattr);
+                           struct dentry *dentry, struct presto_version *old_ver,
+                           struct izo_rollback_data *, struct iattr *iattr);
 int presto_journal_create(struct rec_info *rec, struct presto_file_set *fset,
                           struct dentry *dentry,
                           struct presto_version *tgt_dir_ver,
@@ -391,10 +574,11 @@
                         struct presto_version *tgt_dir_ver,
                         struct presto_version *new_link_ver);
 int presto_journal_unlink(struct rec_info *rec, struct presto_file_set *fset,
-                          struct dentry *dentry,
+                          struct dentry *dir,
                           struct presto_version *tgt_dir_ver,
-                          struct presto_version *old_file_ver, int len,
-                          const char *name);
+                          struct presto_version *old_file_ver,
+                          struct izo_rollback_data *, struct dentry *dentry,
+                          char *old_target, int old_targetlen);
 int presto_journal_symlink(struct rec_info *rec, struct presto_file_set *fset,
                            struct dentry *dentry, const char *target,
                            struct presto_version *tgt_dir_ver,
@@ -406,8 +590,8 @@
 int presto_journal_rmdir(struct rec_info *rec, struct presto_file_set *fset,
                          struct dentry *dentry,
                          struct presto_version *tgt_dir_ver,
-                         struct presto_version *old_dir_ver, int len,
-                         const char *name);
+                         struct presto_version *old_dir_ver,
+                         struct izo_rollback_data *, int len, const char *name);
 int presto_journal_mknod(struct rec_info *rec, struct presto_file_set *fset,
                          struct dentry *dentry,
                          struct presto_version *tgt_dir_ver,
@@ -417,302 +601,324 @@
                           struct dentry *src, struct dentry *tgt,
                           struct presto_version *src_dir_ver,
                           struct presto_version *tgt_dir_ver);
-int presto_journal_open(struct rec_info *rec, struct presto_file_set *fset,
-                        struct dentry *dentry, struct presto_version *old_ver);
-int presto_journal_close(struct rec_info *rec, struct presto_file_set *fset,
-                         struct file *file, 
-			 struct dentry *dentry, 
-			 struct presto_version *new_ver);
-int presto_close_journal_file(struct presto_file_set *fset);
+int presto_journal_open(struct rec_info *, struct presto_file_set *,
+                        struct dentry *, struct presto_version *old_ver);
+int presto_journal_close(struct rec_info *rec, struct presto_file_set *,
+                         struct file *, struct dentry *,
+                         struct presto_version *old_file_ver,
+                         struct presto_version *new_file_ver);
+int presto_write_lml_close(struct rec_info *rec,
+                           struct presto_file_set *fset, 
+                           struct file *file,
+                           __u64 remote_ino,
+                           __u64 remote_generation,
+                           struct presto_version *remote_version,
+                           struct presto_version *new_file_ver);
 void presto_log_op(void *data, int len);
-int presto_write_last_rcvd(struct rec_info *recinfo,
-                           struct presto_file_set *fset,
-                           struct lento_vfs_context *info);
-
-/* journal_ext3.c */
-struct ext3_journal_data {
-        struct file *jd_file;
-};
-extern struct ext3_journal_data e3jd;
-
-
+loff_t presto_kml_offset(struct presto_file_set *fset);
 
+/* upcall.c */
+#define SYNCHRONOUS 0
+#define ASYNCHRONOUS 1
+/* asynchronous calls */
+int izo_upc_kml(int minor, __u64 offset, __u32 first_recno, __u64 length,
+                __u32 last_recno, char *fsetname);
+int izo_upc_kml_truncate(int minor, __u64 length, __u32 last_recno,
+                         char *fsetname);
+int izo_upc_go_fetch_kml(int minor, char *fsetname, uuid_t uuid, __u64 kmlsize);
+int izo_upc_backfetch(int minor, char *path, char *fileset, 
+                      struct lento_vfs_context *);
+
+/* synchronous calls */
+int izo_upc_get_fileid(int minor, __u32 reclen, char *rec, 
+                       __u32 pathlen, char *path, char *fsetname);
+int izo_upc_permit(int minor, struct dentry *, __u32 pathlen, char *path,
+                   char *fset);
+int izo_upc_open(int minor, __u32 pathlen, char *path, char *fsetname, 
+                 struct lento_vfs_context *info);
+int izo_upc_connect(int minor, __u64 ip_address, __u64 port, __u8 uuid[16],
+                    int client_flag);
+int izo_upc_revoke_permit(int minor, char *fsetname, uuid_t uuid);
+int izo_upc_set_kmlsize(int minor, char *fsetname, uuid_t uuid, __u64 kmlsize);
+int izo_upc_client_make_branch(int minor, char *fsetname);
+int izo_upc_server_make_branch(int minor, char *fsetname);
+int izo_upc_branch_undo(int minor, char *fsetname, char *branchname);
+int izo_upc_branch_redo(int minor, char *fsetname, char *branchname);
+int izo_upc_repstatus(int minor,  char * fsetname, struct izo_rcvd_rec *lr_server);
+
+/* general mechanism */
+int izo_upc_upcall(int minor, int *size, struct izo_upcall_hdr *, int async);
+
+/* replicator.c */
+int izo_repstatus(struct presto_file_set *fset, __u64 client_kmlsize, 
+                  struct izo_rcvd_rec *lr_client, struct izo_rcvd_rec *lr_server);
+int izo_rep_cache_init(struct presto_file_set *);
+loff_t izo_rcvd_get(struct izo_rcvd_rec *, struct presto_file_set *, char *uuid);
+loff_t izo_rcvd_write(struct presto_file_set *, struct izo_rcvd_rec *);
+loff_t izo_rcvd_upd_remote(struct presto_file_set *fset, char * uuid,  __u64 remote_recno,
+                           __u64 remote_offset);
 
 /* sysctl.c */
 int init_intermezzo_sysctl(void);
 void cleanup_intermezzo_sysctl(void);
 
 /* ext_attr.c */
-#ifdef CONFIG_FS_EXT_ATTR
-/* XXX: Borrowed from vfs.c. Once the ea patch is into CVS 
- * move this prototype -SHP
- */
-int presto_do_set_ext_attr(struct presto_file_set *fset,
-                           struct dentry *dentry,
-                           const char *name, void *buffer,
-                           size_t buffer_len, int flags, mode_t *mode,
-                           struct lento_vfs_context *info);
-int presto_set_ext_attr(struct inode *inode,
-                        const char *name, void *buffer,
-                        size_t buffer_len, int flags);
-int lento_set_ext_attr(const char *path, const char *name,
-                       void *buffer, size_t buffer_len, int flags,
-                       mode_t mode, struct lento_vfs_context *info);
-/* XXX: Borrowed from journal.c. Once the ea patch is into CVS 
- * move this prototype -SHP
+/* We will be more tolerant than the default ea patch with attr name sizes and
+ * the size of value. If these come via VFS from the default ea patches, the
+ * corresponding character strings will be truncated anyway. During journalling- * we journal length for both name and value. See journal_set_ext_attr.
  */
-int presto_journal_set_ext_attr (struct rec_info *rec,
-                                 struct presto_file_set *fset,
-                                 struct dentry *dentry,
-                                 struct presto_version *ver, const char *name,
-                                 const char *buffer, int buffer_len,
-                                 int flags);
-#endif
-
-
-/* global variables */
-extern int presto_debug;
-extern int presto_print_entry;
-
-#define PRESTO_DEBUG
-#ifdef PRESTO_DEBUG
-/* debugging masks */
-#define D_SUPER     1   /* print results returned by Venus */
-#define D_INODE     2   /* print entry and exit into procedure */
-#define D_FILE      4
-#define D_CACHE     8   /* cache debugging */
-#define D_MALLOC    16  /* print malloc, de-alloc information */
-#define D_JOURNAL   32
-#define D_UPCALL    64  /* up and downcall debugging */
-#define D_PSDEV    128
-#define D_PIOCTL   256
-#define D_SPECIAL  512
-#define D_TIMING  1024
-#define D_DOWNCALL 2048
-#define D_KML      4096
-
-#define CDEBUG(mask, format, a...)                                      \
-        do {                                                            \
-                if (presto_debug & mask) {                              \
-                        printk("(%s:%s,l. %d %d): ", __FILE__, __FUNCTION__, __LINE__, current->pid);   \
-                        printk(format, ##a); }                          \
-        } while (0)
-
-#define ENTRY                                                           \
-        if(presto_print_entry)                                          \
-                printk("Process %d entered %s\n", current->pid, __FUNCTION__)
-
-#define EXIT                                                            \
-        if(presto_print_entry)                                          \
-                printk("Process %d leaving %s at %d\n", current->pid,   \
-                       __FUNCTION__,__LINE__)
-
-extern long presto_kmemory;
-extern long presto_vmemory;
-
-#define presto_kmem_inc(ptr, size) presto_kmemory += (size)
-#define presto_kmem_dec(ptr, size) presto_kmemory -= (size)
-#define presto_vmem_inc(ptr, size) presto_vmemory += (size)
-#define presto_vmem_dec(ptr, size) presto_vmemory -= (size)
-#else /* !PRESTO_DEBUG */
-#define CDEBUG(mask, format, a...) do {} while (0)
-#define ENTRY do {} while (0)
-#define EXIT do {} while (0)
-#define presto_kmem_inc(ptr, size) do {} while (0)
-#define presto_kmem_dec(ptr, size) do {} while (0)
-#define presto_vmem_inc(ptr, size) do {} while (0)
-#define presto_vmem_dec(ptr, size) do {} while (0)
-#endif /* PRESTO_DEBUG */
-
+#define PRESTO_EXT_ATTR_NAME_MAX 128
+#define PRESTO_EXT_ATTR_VALUE_MAX 8192
 
-#define PRESTO_ALLOC(ptr, cast, size)                                   \
+#define PRESTO_ALLOC(ptr, size)                                         \
 do {                                                                    \
-    if (size <= 4096) {                                                 \
-        ptr = (cast)kmalloc((unsigned long) size, GFP_KERNEL);          \
-        CDEBUG(D_MALLOC, "kmalloced: %ld at %p.\n", (long)size, ptr);   \
-        presto_kmem_inc(ptr, size);                                     \
-    } else {                                                            \
-        ptr = (cast)vmalloc((unsigned long) size);                      \
-        CDEBUG(D_MALLOC, "vmalloced: %ld at %p.\n", (long)size, ptr);   \
-        presto_vmem_inc(ptr, size);                                     \
-    }                                                                   \
-    if ((ptr) == 0)                                                     \
-        printk("PRESTO: out of memory at %s:%d\n", __FILE__, __LINE__); \
-    else                                                                \
-        memset( ptr, 0, size );                                         \
+        long s = (size);                                                \
+        (ptr) = kmalloc(s, GFP_KERNEL);                                 \
+        if ((ptr) == NULL)                                              \
+                CERROR("IZO: out of memory at %s:%d (trying to "        \
+                       "allocate %ld)\n", __FILE__, __LINE__, s);       \
+        else {                                                          \
+                presto_kmem_inc((ptr), s);                              \
+                memset((ptr), 0, s);                                    \
+        }                                                               \
+        CDEBUG(D_MALLOC, "kmalloced: %ld at %p (tot %ld).\n",           \
+               s, (ptr), presto_kmemory);                               \
 } while (0)
 
-
-
-#define PRESTO_FREE(ptr,size)                                           \
+#define PRESTO_FREE(ptr, size)                                          \
 do {                                                                    \
-    if (!ptr) {                                                         \
-        printk("PRESTO: free NULL pointer (%ld bytes) at %s:%d\n",      \
-               (long)size, __FILE__, __LINE__);                         \
-        break;                                                          \
-    }                                                                   \
-    if (size <= 4096) {                                                 \
-        CDEBUG(D_MALLOC, "kfreed: %ld at %p.\n", (long)size, ptr);      \
-        presto_kmem_dec(ptr, size);                                     \
-        kfree((ptr));                                         \
-    } else {                                                            \
-        CDEBUG(D_MALLOC, "vfreed: %ld at %p.\n", (long)size, ptr);      \
-        presto_vmem_dec(ptr, size);                                     \
-        vfree((ptr));                                                   \
-    }                                                                   \
+        long s = (size);                                                \
+        if ((ptr) == NULL) {                                            \
+                CERROR("IZO: free NULL pointer (%ld bytes) at "         \
+                       "%s:%d\n", s, __FILE__, __LINE__);               \
+                break;                                                  \
+        }                                                               \
+        kfree(ptr);                                                     \
+        CDEBUG(D_MALLOC, "kfreed: %ld at %p (tot %ld).\n",              \
+               s, (ptr), presto_kmemory);                               \
+        presto_kmem_dec((ptr), s);                                      \
 } while (0)
 
-#define MYPATHLEN(buffer,path) (buffer + PAGE_SIZE - path - 1)
-
-#else /* __KERNEL__ */
-#include <asm/types.h>
-#include <sys/ioctl.h>
-struct lento_vfs_context {
-        __u32 slot_offset;
-        __u32 recno;
-        __u64 kml_offset;
-        __u32 flags;
-        __u32 updated_time;
-};
-#endif /* __KERNEL__*/
-
-
-/* marking flags for fsets */
-#define FSET_CLIENT_RO 0x00000001
-#define FSET_LENTO_RO  0x00000002
-#define FSET_HASPERMIT  0x00000004 /* we have a permit to WB */
-#define FSET_INSYNC     0x00000008 /* this fileset is in sync */
-#define FSET_PERMIT_WAITING 0x00000010 /* Lento is waiting for permit */
-#define FSET_STEAL_PERMIT 0x00000020 /* take permit if Lento is dead */
-#define FSET_JCLOSE_ON_WRITE 0x00000040 /* Journal closes on writes */
-
-
-/* what to mark indicator (ioctl parameter) */ 
-#define MARK_DENTRY   101
-#define MARK_FSET     102
-#define MARK_CACHE    103
-#define MARK_GETFL    104
+static inline int dentry_name_cmp(struct dentry *dentry, char *name)
+{
+        return (strlen(name) == dentry->d_name.len &&
+                memcmp(name, dentry->d_name.name, dentry->d_name.len) == 0);
+}
 
+static inline char *strdup(char *str)
+{
+        char *tmp;
+        tmp = kmalloc(strlen(str) + 1, GFP_KERNEL);
+        if (tmp)
+                memcpy(tmp, str, strlen(str) + 1);
+               
+        return tmp;
+}
 
+/* buffer MUST be at least the size of izo_ioctl_hdr */
+static inline int izo_ioctl_getdata(char *buf, char *end, void *arg)
+{
+        struct izo_ioctl_hdr *hdr;
+        struct izo_ioctl_data *data;
+        int err;
+        ENTRY;
+
+        hdr = (struct izo_ioctl_hdr *)buf;
+        data = (struct izo_ioctl_data *)buf;
+
+        err = copy_from_user(buf, (void *)arg, sizeof(*hdr));
+        if ( err ) {
+                EXIT;
+                return err;
+        }
+
+        if (hdr->ioc_version != IZO_IOCTL_VERSION) {
+                CERROR("IZO: version mismatch kernel vs application\n");
+                return -EINVAL;
+        }
+
+        if (hdr->ioc_len + buf >= end) {
+                CERROR("IZO: user buffer exceeds kernel buffer\n");
+                return -EINVAL;
+        }
+
+        if (hdr->ioc_len < sizeof(struct izo_ioctl_data)) {
+                CERROR("IZO: user buffer too small for ioctl\n");
+                return -EINVAL;
+        }
+
+        err = copy_from_user(buf, (void *)arg, hdr->ioc_len);
+        if ( err ) {
+                EXIT;
+                return err;
+        }
+
+        if (izo_ioctl_is_invalid(data)) {
+                CERROR("IZO: ioctl not correctly formatted\n");
+                return -EINVAL;
+        }
+
+        if (data->ioc_inllen1) {
+                data->ioc_inlbuf1 = &data->ioc_bulk[0];
+        }
+
+        if (data->ioc_inllen2) {
+                data->ioc_inlbuf2 = &data->ioc_bulk[0] +
+                        size_round(data->ioc_inllen1);
+        }
+
+        EXIT;
+        return 0;
+}
+
+# define MYPATHLEN(buffer, path) ((buffer) + PAGE_SIZE - (path))
+
+# define free kfree
+# define malloc(a) kmalloc(a, GFP_KERNEL)
+# define printf printk
+int kml_reint_rec(struct file *dir, struct izo_ioctl_data *data);
+int izo_get_fileid(struct file *dir, struct izo_ioctl_data *data);
+int izo_set_fileid(struct file *dir, struct izo_ioctl_data *data);
 
-struct readmount {
-        int io_len;  /* this is IN & OUT: true length of str is returned */
-        char *io_string;
-};
+#else /* __KERNEL__ */
+# include <stdlib.h>
+# include <stdio.h>
+# include <sys/types.h>
+# include <sys/ioctl.h>
+# include <string.h>
+
+# define printk printf
+# ifndef CERROR
+#   define CERROR printf
+# endif
+# define kmalloc(a,b) malloc(a)
+
+void init_fsreintdata (void);
+int kml_fsreint(struct kml_rec *rec, char *basedir);
+int kml_iocreint(__u32 size, char *ptr, __u32 offset, int dird,
+                 uuid_t uuid, __u32 generate_kml);
 
-/* modeled after setsockopt */
-/* so if you have no /proc, oh well. */
-/* for now it's all ints. We may grow this later for non-ints. */
-struct psdev_opt {
-        int optname;
-        int optval;
-};
+static inline int izo_ioctl_packlen(struct izo_ioctl_data *data);
 
-struct lento_input {
-        char *name;
-        struct lento_vfs_context info;
-};
+static inline void izo_ioctl_init(struct izo_ioctl_data *data)
+{
+        memset(data, 0, sizeof(*data));
+        data->ioc_len = sizeof(*data);
+        data->ioc_version = IZO_IOCTL_VERSION;
+}
 
-struct lento_input_attr {
-        char *name;
-#if BITS_PER_LONG < 64
-        __u32 dummy;    /* XXX on 64-bit platforms, this is not needed */
-#endif
-        __u32 valid;
-        __u32 mode;
-        __u32 uid;
-        __u32 gid;
-        __u64 size;
-        __s64 atime;
-        __s64 mtime;
-        __s64 ctime;
-        __u32 attr_flags;
-        struct lento_vfs_context info;
-};
+static inline int
+izo_ioctl_pack(struct izo_ioctl_data *data, char **pbuf, int max)
+{
+        char *ptr;
+        struct izo_ioctl_data *overlay;
+        data->ioc_len = izo_ioctl_packlen(data);
+        data->ioc_version = IZO_IOCTL_VERSION;
+
+        if (*pbuf && izo_ioctl_packlen(data) > max)
+                return 1;
+        if (*pbuf == NULL)
+                *pbuf = malloc(data->ioc_len);
+        if (*pbuf == NULL)
+                return 1;
+        overlay = (struct izo_ioctl_data *)*pbuf;
+        memcpy(*pbuf, data, sizeof(*data));
+
+        ptr = overlay->ioc_bulk;
+        if (data->ioc_inlbuf1)
+                LOGL(data->ioc_inlbuf1, data->ioc_inllen1, ptr);
+        if (data->ioc_inlbuf2)
+                LOGL(data->ioc_inlbuf2, data->ioc_inllen2, ptr);
+        if (izo_ioctl_is_invalid(overlay))
+                return 1;
 
-struct lento_input_mode {
-        char *name;
-        __u32 mode;
-        struct lento_vfs_context info;
-};
+        return 0;
+}
 
-struct lento_input_old_new {
-        char *oldname;
-        char *newname;
-        struct lento_vfs_context info;
-};
+#endif /* __KERNEL__*/
 
-struct lento_input_dev {
-        char *name;
-        __u32 mode;
-        __u32 major;
-        __u32 minor;
-        struct lento_vfs_context info;
-};
+#define IZO_ERROR_NAME 1
+#define IZO_ERROR_UPDATE 2
+#define IZO_ERROR_DELETE 3
+#define IZO_ERROR_RENAME 4
 
-struct lento_input_iopen {
-        char *name;
-#if BITS_PER_LONG < 64
-        __u32 dummy;    /* XXX on 64-bit platforms, this is not needed */
+static inline char *izo_error(int err)
+{
+#ifndef __KERNEL__
+        if (err <= 0)
+                return strerror(-err);
 #endif
-        __u64 ino;
-        __u32 generation;
-        __u32 flags;
-        __s32 fd;
-};
+        switch (err) {
+        case IZO_ERROR_NAME:
+                return "InterMezzo name/name conflict";
+        case IZO_ERROR_UPDATE:
+                return "InterMezzo update/update conflict";
+        case IZO_ERROR_DELETE:
+                return "InterMezzo update/delete conflict";
+        case IZO_ERROR_RENAME:
+                return "InterMezzo rename/rename conflict";
+        }
+        return "Unknown InterMezzo error";
+}
 
-struct lento_input_close {
-        __u32 fd;
-        struct lento_vfs_context info;
-};
-
-/* XXX: check for alignment */
-struct lento_input_ext_attr {
-        char  *path;
-        char  *name;
-        __u32 name_len;
-        char  *buffer;
-        __u32 buffer_len;
-        __u32 flags;
-        __u32 mode;
-        struct lento_vfs_context info;
-};
+static inline int izo_ioctl_packlen(struct izo_ioctl_data *data)
+{
+        int len = sizeof(struct izo_ioctl_data);
+        len += size_round(data->ioc_inllen1);
+        len += size_round(data->ioc_inllen2);
+        return len;
+}
 
-/* XXX should PRESTO_GET_* actually be of type _IOR, since we are reading? */
-#define PRESTO_GETMOUNT         _IOW ('p',0x03, struct readmount *)
-#define PRESTO_SETPID           _IOW ('p',0x04, struct readmount *)
-#define PRESTO_CLOSE_JOURNALF   _IOW ('p',0x06, struct readmount *)
-#define PRESTO_SET_FSETROOT     _IOW ('p',0x07, struct readmount *)
-#define PRESTO_CLEAR_FSETROOT   _IOW ('p',0x08, struct readmount *)
-#define PRESTO_SETOPT           _IOW ('p',0x09, struct psdev_opt *)
-#define PRESTO_GETOPT           _IOW ('p',0x0a, struct psdev_opt *)
-#define PRESTO_GET_KMLSIZE      _IOW ('p',0x0b, struct psdev_opt *)
-#define PRESTO_GET_RECNO        _IOW ('p',0x0c, struct psdev_opt *)
-#define PRESTO_VFS_SETATTR      _IOW ('p',0x10, struct lento_input_attr *)
-#define PRESTO_VFS_CREATE       _IOW ('p',0x11, struct lento_input_mode *)
-#define PRESTO_VFS_LINK         _IOW ('p',0x12, struct lento_input_old_new *)
-#define PRESTO_VFS_UNLINK       _IOW ('p',0x13, struct lento_input *)
-#define PRESTO_VFS_SYMLINK      _IOW ('p',0x14, struct lento_input_old_new *)
-#define PRESTO_VFS_MKDIR        _IOW ('p',0x15, struct lento_input_mode *)
-#define PRESTO_VFS_RMDIR        _IOW ('p',0x16, struct lento_input *)
-#define PRESTO_VFS_MKNOD        _IOW ('p',0x17, struct lento_input_dev *)
-#define PRESTO_VFS_RENAME       _IOW ('p',0x18, struct lento_input_old_new *)
-#define PRESTO_VFS_CLOSE        _IOW ('p',0x1a, struct lento_input_close *)
-#define PRESTO_VFS_IOPEN        _IOW ('p',0x1b, struct lento_input_iopen *)
-#define PRESTO_VFS_SETEXTATTR   _IOW ('p',0x1c, struct lento_input_ext_attr *)
-#define PRESTO_VFS_DELEXTATTR   _IOW ('p',0x1d, struct lento_input_ext_attr *)
-
-#define PRESTO_MARK             _IOW ('p',0x20, struct lento_input_open *)
-#define PRESTO_RELEASE_PERMIT   _IOW ('p',0x21, struct lento_input_open *)
-#define PRESTO_CLEAR_ALL_FSETROOTS  _IOW ('p',0x22, struct readmount *)
-#define PRESTO_BACKFETCH_LML    _IOW ('p',0x23, struct readmount *)
-#define PRESTO_REINT            _IOW ('p',0x24, struct readmount *)
-#define PRESTO_CANCEL_LML       _IOW ('p',0x25, struct readmount *)
-#define PRESTO_RESET_FSET       _IOW ('p',0x26, struct readmount *)
-#define PRESTO_COMPLETE_CLOSES  _IOW ('p',0x27, struct readmount *)
-
-#define PRESTO_REINT_BEGIN      _IOW ('p',0x30, struct readmount *)
-#define PRESTO_DO_REINT         _IOW ('p',0x31, struct readmount *)
-#define PRESTO_REINT_END        _IOW ('p',0x32, struct readmount *)
+static inline int izo_ioctl_is_invalid(struct izo_ioctl_data *data)
+{
+        if (data->ioc_len > (1<<30)) {
+                CERROR("IZO ioctl: ioc_len larger than 1<<30\n");
+                return 1;
+        }
+        if (data->ioc_inllen1 > (1<<30)) {
+                CERROR("IZO ioctl: ioc_inllen1 larger than 1<<30\n");
+                return 1;
+        }
+        if (data->ioc_inllen2 > (1<<30)) {
+                CERROR("IZO ioctl: ioc_inllen2 larger than 1<<30\n");
+                return 1;
+        }
+        if (data->ioc_inlbuf1 && !data->ioc_inllen1) {
+                CERROR("IZO ioctl: inlbuf1 pointer but 0 length\n");
+                return 1;
+        }
+        if (data->ioc_inlbuf2 && !data->ioc_inllen2) {
+                CERROR("IZO ioctl: inlbuf2 pointer but 0 length\n");
+                return 1;
+        }
+        if (data->ioc_pbuf1 && !data->ioc_plen1) {
+                CERROR("IZO ioctl: pbuf1 pointer but 0 length\n");
+                return 1;
+        }
+        if (data->ioc_pbuf2 && !data->ioc_plen2) {
+                CERROR("IZO ioctl: pbuf2 pointer but 0 length\n");
+                return 1;
+        }
+        if (izo_ioctl_packlen(data) != data->ioc_len ) {
+                CERROR("IZO ioctl: packlen exceeds ioc_len\n");
+                return 1;
+        }
+        if (data->ioc_inllen1 &&
+            data->ioc_bulk[data->ioc_inllen1 - 1] != '\0') {
+                CERROR("IZO ioctl: inlbuf1 not 0 terminated\n");
+                return 1;
+        }
+        if (data->ioc_inllen2 &&
+            data->ioc_bulk[size_round(data->ioc_inllen1) + data->ioc_inllen2
+                           - 1] != '\0') {
+                CERROR("IZO ioctl: inlbuf2 not 0 terminated\n");
+                return 1;
+        }
+        return 0;
+}
+
+/* kml_unpack.c */
+char *kml_print_rec(struct kml_rec *rec, int brief);
+int kml_unpack(struct kml_rec *rec, char **buf, char *end);
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/intermezzo_idl.h linux-2.4.20/include/linux/intermezzo_idl.h
--- linux-2.4.19/include/linux/intermezzo_idl.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/intermezzo_idl.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,300 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2001, 2002 Cluster File Systems, Inc.
+ *  Copyright (C) 2001 Tacit Networks, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __INTERMEZZO_IDL_H__
+#define __INTERMEZZO_IDL_H__
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/* this file contains all data structures used in InterMezzo's interfaces:
+ * - upcalls
+ * - ioctl's
+ * - KML records
+ * - RCVD records
+ * - rpc's
+ */ 
+
+/* UPCALL */
+#define INTERMEZZO_MINOR 248   
+
+
+#define IZO_UPC_VERSION 0x00010002
+#define IZO_UPC_PERMIT        1
+#define IZO_UPC_CONNECT       2
+#define IZO_UPC_GO_FETCH_KML  3
+#define IZO_UPC_OPEN          4
+#define IZO_UPC_REVOKE_PERMIT 5
+#define IZO_UPC_KML           6
+#define IZO_UPC_BACKFETCH     7
+#define IZO_UPC_KML_TRUNC     8
+#define IZO_UPC_SET_KMLSIZE   9
+#define IZO_UPC_BRANCH_UNDO   10
+#define IZO_UPC_BRANCH_REDO   11
+#define IZO_UPC_GET_FILEID    12
+#define IZO_UPC_CLIENT_MAKE_BRANCH    13
+#define IZO_UPC_SERVER_MAKE_BRANCH    14
+#define IZO_UPC_REPSTATUS    15
+
+#define IZO_UPC_LARGEST_OPCODE 15
+
+struct izo_upcall_hdr {
+        __u32 u_len;
+        __u32 u_version;
+        __u32 u_opc;
+        __u32 u_uniq;
+        __u32 u_pid;
+        __u32 u_uid;
+        __u32 u_pathlen;
+        __u32 u_fsetlen;
+        __u64 u_offset;
+        __u64 u_length;
+        __u32 u_first_recno;
+        __u32 u_last_recno;
+        __u32 u_async;
+        __u32 u_reclen;
+        __u8  u_uuid[16];
+};
+
+/* This structure _must_ sit at the beginning of the buffer */
+struct izo_upcall_resp {
+        __u32 opcode;
+        __u32 unique;    
+        __u32 result;
+};
+
+
+/* IOCTL */
+
+#define IZO_IOCTL_VERSION 0x00010003
+
+/* maximum size supported for ioc_pbuf1 */
+#define KML_MAX_BUF (64*1024)
+
+struct izo_ioctl_hdr { 
+        __u32  ioc_len;
+        __u32  ioc_version;
+};
+
+struct izo_ioctl_data {
+        __u32 ioc_len;
+        __u32 ioc_version;
+        __u32 ioc_izodev;
+        __u32 ioc_kmlrecno;
+        __u64 ioc_kmlsize;
+        __u32 ioc_flags;
+        __s32 ioc_inofd;
+        __u64 ioc_ino;
+        __u64 ioc_generation;
+        __u32 ioc_mark_what;
+        __u32 ioc_and_flag;
+        __u32 ioc_or_flag;
+        __u32 ioc_dev;
+        __u32 ioc_offset;
+        __u32 ioc_slot;
+        __u64 ioc_uid;
+        __u8  ioc_uuid[16];
+
+        __u32 ioc_inllen1;   /* path */
+        char *ioc_inlbuf1;
+        __u32 ioc_inllen2;   /* fileset */
+        char *ioc_inlbuf2;
+
+        __u32 ioc_plen1;     /* buffers in user space (KML) */
+        char *ioc_pbuf1;
+        __u32 ioc_plen2;     /* buffers in user space (KML) */
+        char *ioc_pbuf2;
+
+        char  ioc_bulk[0];
+};
+
+#define IZO_IOC_DEVICE          _IOW ('p',0x50, void *)
+#define IZO_IOC_REINTKML        _IOW ('p',0x51, void *)
+#define IZO_IOC_GET_RCVD        _IOW ('p',0x52, void *)
+#define IZO_IOC_SET_IOCTL_UID   _IOW ('p',0x53, void *)
+#define IZO_IOC_GET_KML_SIZE    _IOW ('p',0x54, void *)
+#define IZO_IOC_PURGE_FILE_DATA _IOW ('p',0x55, void *)
+#define IZO_IOC_CONNECT         _IOW ('p',0x56, void *)
+#define IZO_IOC_GO_FETCH_KML    _IOW ('p',0x57, void *)
+#define IZO_IOC_MARK            _IOW ('p',0x58, void *)
+#define IZO_IOC_CLEAR_FSET      _IOW ('p',0x59, void *)
+#define IZO_IOC_CLEAR_ALL_FSETS _IOW ('p',0x60, void *)
+#define IZO_IOC_SET_FSET        _IOW ('p',0x61, void *)
+#define IZO_IOC_REVOKE_PERMIT   _IOW ('p',0x62, void *)
+#define IZO_IOC_SET_KMLSIZE     _IOW ('p',0x63, void *)
+#define IZO_IOC_CLIENT_MAKE_BRANCH _IOW ('p',0x64, void *)
+#define IZO_IOC_SERVER_MAKE_BRANCH _IOW ('p',0x65, void *)
+#define IZO_IOC_BRANCH_UNDO    _IOW ('p',0x66, void *)
+#define IZO_IOC_BRANCH_REDO    _IOW ('p',0x67, void *)
+#define IZO_IOC_SET_PID        _IOW ('p',0x68, void *)
+#define IZO_IOC_SET_CHANNEL    _IOW ('p',0x69, void *)
+#define IZO_IOC_GET_CHANNEL    _IOW ('p',0x70, void *)
+#define IZO_IOC_GET_FILEID    _IOW ('p',0x71, void *)
+#define IZO_IOC_ADJUST_LML    _IOW ('p',0x72, void *)
+#define IZO_IOC_SET_FILEID    _IOW ('p',0x73, void *)
+#define IZO_IOC_REPSTATUS    _IOW ('p',0x74, void *)
+
+/* marking flags for fsets */
+#define FSET_CLIENT_RO        0x00000001
+#define FSET_LENTO_RO         0x00000002
+#define FSET_HASPERMIT        0x00000004 /* we have a permit to WB */
+#define FSET_INSYNC           0x00000008 /* this fileset is in sync */
+#define FSET_PERMIT_WAITING   0x00000010 /* Lento is waiting for permit */
+#define FSET_STEAL_PERMIT     0x00000020 /* take permit if Lento is dead */
+#define FSET_JCLOSE_ON_WRITE  0x00000040 /* Journal closes on writes */
+#define FSET_DATA_ON_DEMAND   0x00000080 /* update data on file_open() */
+#define FSET_PERMIT_EXCLUSIVE 0x00000100 /* only one permitholder allowed */
+#define FSET_HAS_BRANCHES     0x00000200 /* this fileset contains branches */
+#define FSET_IS_BRANCH        0x00000400 /* this fileset is a branch */
+#define FSET_FLAT_BRANCH      0x00000800 /* this fileset is ROOT with branches */
+
+/* what to mark indicator (ioctl parameter) */
+#define MARK_DENTRY   101
+#define MARK_FSET     102
+#define MARK_CACHE    103
+#define MARK_GETFL    104
+
+/* KML */
+
+#define KML_MAJOR_VERSION 0x00010000
+#define KML_MINOR_VERSION 0x00000002
+#define KML_OPCODE_NOOP          0
+#define KML_OPCODE_CREATE        1
+#define KML_OPCODE_MKDIR         2
+#define KML_OPCODE_UNLINK        3
+#define KML_OPCODE_RMDIR         4
+#define KML_OPCODE_CLOSE         5
+#define KML_OPCODE_SYMLINK       6
+#define KML_OPCODE_RENAME        7
+#define KML_OPCODE_SETATTR       8
+#define KML_OPCODE_LINK          9
+#define KML_OPCODE_OPEN          10
+#define KML_OPCODE_MKNOD         11
+#define KML_OPCODE_WRITE         12
+#define KML_OPCODE_RELEASE       13
+#define KML_OPCODE_TRUNC         14
+#define KML_OPCODE_SETEXTATTR    15
+#define KML_OPCODE_DELEXTATTR    16
+#define KML_OPCODE_KML_TRUNC     17
+#define KML_OPCODE_GET_FILEID    18
+#define KML_OPCODE_NUM           19
+/* new stuff */
+struct presto_version {
+        __u64 pv_mtime;
+        __u64 pv_ctime;
+        __u64 pv_size;
+};
+
+struct kml_prefix_hdr {
+        __u32                    len;
+        __u32                    version;
+        __u32                    pid;
+        __u32                    auid;
+        __u32                    fsuid;
+        __u32                    fsgid;
+        __u32                    opcode;
+        __u32                    ngroups;
+};
+
+struct kml_prefix { 
+        struct kml_prefix_hdr    *hdr;
+        __u32                    *groups;
+};
+
+struct kml_suffix { 
+        __u32                    prevrec;
+        __u32                    recno;
+        __u32                    time;
+        __u32                    len;
+};
+
+struct kml_rec {
+        char                   *buf;
+        struct kml_prefix       prefix;
+        __u64                   offset;
+        char                   *path;
+        int                     pathlen;
+        char                   *name;
+        int                     namelen;
+        char                   *target;
+        int                     targetlen;
+        struct presto_version  *old_objectv;
+        struct presto_version  *new_objectv;
+        struct presto_version  *old_parentv;
+        struct presto_version  *new_parentv;
+        struct presto_version  *old_targetv;
+        struct presto_version  *new_targetv;
+        __u32                   valid;
+        __u32                   mode;
+        __u32                   uid;
+        __u32                   gid;
+        __u64                   size;
+        __u32                   mtime;
+        __u32                   ctime;
+        __u32                   flags;
+        __u32                   ino;
+        __u32                   rdev;
+        __u32                   major;
+        __u32                   minor;
+        __u32                   generation;
+        __u32                   old_mode;
+        __u32                   old_rdev;
+        __u64                   old_uid;
+        __u64                   old_gid;
+        char                   *old_target;
+        int                     old_targetlen;
+        struct kml_suffix      *suffix;
+};
+
+
+/* RCVD */ 
+
+/* izo_rcvd_rec fills the .intermezzo/fset/last_rcvd file and provides data about
+ * our view of reintegration offsets for a given peer.
+ *
+ * The only exception is the last_rcvd record which has a UUID consisting of all
+ * zeroes; this record's lr_local_offset field is the logical byte offset of our
+ * KML, which is updated when KML truncation takes place.  All other fields are
+ * reserved. */
+
+/* XXX - document how clean shutdowns are recorded */
+
+struct izo_rcvd_rec { 
+        __u8    lr_uuid[16];       /* which peer? */
+        __u64   lr_remote_recno;   /* last confirmed remote recno  */
+        __u64   lr_remote_offset;  /* last confirmed remote offset */
+        __u64   lr_local_recno;    /* last locally reinted recno   */
+        __u64   lr_local_offset;   /* last locally reinted offset  */
+        __u64   lr_last_ctime;     /* the largest ctime that has reintegrated */
+};
+
+/* Cache purge database
+ *
+ * Each DB entry is this structure followed by the path name, no trailing NUL. */
+struct izo_purge_entry {
+        __u64 p_atime;
+        __u32 p_pathlen;
+};
+
+/* RPC */
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/intermezzo_lib.h linux-2.4.20/include/linux/intermezzo_lib.h
--- linux-2.4.19/include/linux/intermezzo_lib.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/intermezzo_lib.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,168 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Data structures unpacking/packing macros & inlines
+ *
+ */
+
+#ifndef _INTERMEZZO_LIB_H
+#define _INTERMEZZO_LIB_H
+
+#ifdef __KERNEL__
+# include <linux/types.h>
+#else
+# include <string.h>
+# include <sys/types.h>
+#endif
+
+#undef MIN
+#define MIN(a,b) (((a)<(b)) ? (a): (b))
+#undef MAX
+#define MAX(a,b) (((a)>(b)) ? (a): (b))
+#define MKSTR(ptr) ((ptr))? (ptr) : ""
+
+static inline int size_round (int val)
+{
+	return (val + 3) & (~0x3);
+}
+
+static inline int size_round0(int val)
+{
+        if (!val) 
+                return 0;
+	return (val + 1 + 3) & (~0x3);
+}
+
+static inline size_t round_strlen(char *fset)
+{
+	return size_round(strlen(fset) + 1);
+}
+
+#ifdef __KERNEL__
+# define NTOH__u32(var) le32_to_cpu(var)
+# define NTOH__u64(var) le64_to_cpu(var)
+# define HTON__u32(var) cpu_to_le32(var)
+# define HTON__u64(var) cpu_to_le64(var)
+#else
+# include <glib.h>
+# define NTOH__u32(var) GUINT32_FROM_LE(var)
+# define NTOH__u64(var) GUINT64_FROM_LE(var)
+# define HTON__u32(var) GUINT32_TO_LE(var)
+# define HTON__u64(var) GUINT64_TO_LE(var)
+#endif
+
+/* 
+ * copy sizeof(type) bytes from pointer to var and move ptr forward.
+ * return EFAULT if pointer goes beyond end
+ */
+#define UNLOGV(var,type,ptr,end)                \
+do {                                            \
+        var = *(type *)ptr;                     \
+        ptr += sizeof(type);                    \
+        if (ptr > end )                         \
+                return -EFAULT;                 \
+} while (0)
+
+/* the following two macros convert to little endian */
+/* type MUST be __u32 or __u64 */
+#define LUNLOGV(var,type,ptr,end)               \
+do {                                            \
+        var = NTOH##type(*(type *)ptr);         \
+        ptr += sizeof(type);                    \
+        if (ptr > end )                         \
+                return -EFAULT;                 \
+} while (0)
+
+/* now log values */
+#define LOGV(var,type,ptr)                      \
+do {                                            \
+        *((type *)ptr) = var;                   \
+        ptr += sizeof(type);                    \
+} while (0)
+
+/* and in network order */
+#define LLOGV(var,type,ptr)                     \
+do {                                            \
+        *((type *)ptr) = HTON##type(var);       \
+        ptr += sizeof(type);                    \
+} while (0)
+
+
+/* 
+ * set var to point at (type *)ptr, move ptr forward with sizeof(type)
+ * return from function with EFAULT if ptr goes beyond end
+ */
+#define UNLOGP(var,type,ptr,end)                \
+do {                                            \
+        var = (type *)ptr;                      \
+        ptr += sizeof(type);                    \
+        if (ptr > end )                         \
+                return -EFAULT;                 \
+} while (0)
+
+#define LOGP(var,type,ptr)                      \
+do {                                            \
+        memcpy(ptr, var, sizeof(type));         \
+        ptr += sizeof(type);                    \
+} while (0)
+
+/* 
+ * set var to point at (char *)ptr, move ptr forward by size_round(len);
+ * return from function with EFAULT if ptr goes beyond end
+ */
+#define UNLOGL(var,type,len,ptr,end)                    \
+do {                                                    \
+        if (len == 0)                                   \
+                var = (type *)0;                        \
+        else {                                          \
+                var = (type *)ptr;                      \
+                ptr += size_round(len * sizeof(type));  \
+        }                                               \
+        if (ptr > end )                                 \
+                return -EFAULT;                         \
+} while (0)
+
+#define UNLOGL0(var,type,len,ptr,end)                           \
+do {                                                            \
+        UNLOGL(var,type,len+1,ptr,end);                         \
+        if ( *((char *)ptr - size_round(len+1) + len) != '\0')  \
+                        return -EFAULT;                         \
+} while (0)
+
+#define LOGL(var,len,ptr)                               \
+do {                                                    \
+        size_t __fill = size_round(len);                \
+        /* Prevent data leakage. */                     \
+        if (__fill > 0)                                 \
+                memset((char *)ptr, 0, __fill);         \
+        memcpy((char *)ptr, (const char *)var, len);    \
+        ptr += __fill;                                  \
+} while (0)
+
+#define LOGL0(var,len,ptr)                              \
+do {                                                    \
+        if (!len) break;                                \
+        memcpy((char *)ptr, (const char *)var, len);    \
+        *((char *)(ptr) + len) = 0;                     \
+        ptr += size_round(len + 1);                     \
+} while (0)
+
+#endif /* _INTERMEZZO_LIB_H */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/intermezzo_psdev.h linux-2.4.20/include/linux/intermezzo_psdev.h
--- linux-2.4.19/include/linux/intermezzo_psdev.h	2001-11-11 18:20:21.000000000 +0000
+++ linux-2.4.20/include/linux/intermezzo_psdev.h	2002-10-29 11:18:40.000000000 +0000
@@ -1,57 +1,42 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ */
+
 #ifndef __PRESTO_PSDEV_H
 #define __PRESTO_PSDEV_H
 
-#ifdef PRESTO_DEVEL
-# define PRESTO_FS_NAME "izofs"
-# define PRESTO_PSDEV_NAME "/dev/izo"
-# define PRESTO_PSDEV_MAJOR 186
-#else
-# define PRESTO_FS_NAME "InterMezzo"
-# define PRESTO_PSDEV_NAME "/dev/intermezzo"
-# define PRESTO_PSDEV_MAJOR 185
-#endif
-
-#define MAX_PRESTODEV 16
-
+#define MAX_CHANNEL 16
+#define PROCNAME_SIZE 32
+#include <linux/locks.h>
+#include <linux/smp_lock.h>
 #include <linux/version.h>
 
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
-#define wait_queue_head_t  struct wait_queue *
-#define DECLARE_WAITQUEUE(name,task) \
-        struct wait_queue name = { task, NULL }
-#define init_waitqueue_head(arg) 
-#else
-#ifndef __initfunc
-#define __initfunc(arg) arg
-#endif
-#endif
-
-
-/* represents state of a /dev/presto */
+/* represents state of an instance reached with /dev/intermezzo */
 /* communication pending & processing queues */
-struct upc_comm {
+struct upc_channel {
         unsigned int         uc_seq;
-        wait_queue_head_t    uc_waitq;     /* Lento wait queue */
-        struct list_head    uc_pending;
-        struct list_head    uc_processing;
-        int                  uc_pid;       /* Lento's pid */
-        int                  uc_hard; /* allows signals during upcalls */
+        wait_queue_head_t    uc_waitq;    /* Lento wait queue */
+        struct list_head     uc_pending;
+        struct list_head     uc_processing;
+        spinlock_t            uc_lock;
+        int                  uc_pid;      /* Lento's pid */
+        int                  uc_hard;     /* allows signals during upcalls */
         int                  uc_no_filter;
         int                  uc_no_journal;
         int                  uc_no_upcall;
-        int                  uc_timeout; /* . sec: signals will dequeue upc */
+        int                  uc_timeout;  /* . sec: signals will dequeue upc */
         long                 uc_errorval; /* for testing I/O failures */
         struct list_head     uc_cache_list;
-        int                   uc_minor;
-        char *                uc_devname;
+        int                  uc_minor;
 };
 
-#define ISLENTO(minor) (current->pid == upc_comms[minor].uc_pid \
-                || current->p_pptr->pid == upc_comms[minor].uc_pid)
+#define ISLENTO(minor) (current->pid == izo_channels[minor].uc_pid \
+                || current->p_pptr->pid == izo_channels[minor].uc_pid \
+                || current->p_pptr->p_pptr->pid == izo_channels[minor].uc_pid)
 
-extern struct upc_comm upc_comms[MAX_PRESTODEV];
+extern struct upc_channel izo_channels[MAX_CHANNEL];
 
-/* messages between presto filesystem in kernel and Venus */
+/* message types between presto filesystem in kernel */
 #define REQ_READ   1
 #define REQ_WRITE  2
 #define REQ_ASYNC  4
@@ -60,10 +45,10 @@
 struct upc_req {
         struct list_head   rq_chain;
         caddr_t            rq_data;
-        u_short            rq_flags;
-        u_short            rq_bufsize;
-        u_short            rq_rep_size;
-        u_short            rq_opcode;  /* copied from data to save lookup */
+        int                rq_flags;
+        int                rq_bufsize;
+        int                rq_rep_size;
+        int                rq_opcode;  /* copied from data to save lookup */
         int                rq_unique;
         wait_queue_head_t  rq_sleep;   /* process' wait queue */
         unsigned long      rq_posttime;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/iobuf.h linux-2.4.20/include/linux/iobuf.h
--- linux-2.4.19/include/linux/iobuf.h	2001-11-22 19:46:26.000000000 +0000
+++ linux-2.4.20/include/linux/iobuf.h	2002-10-29 11:18:35.000000000 +0000
@@ -37,19 +37,11 @@
 	int		offset;		/* Offset to start of valid data */
 	int		length;		/* Number of valid bytes of data */
 
-	/* Keep separate track of the physical addresses and page
-	 * structs involved.  If we do IO to a memory-mapped device
-	 * region, there won't necessarily be page structs defined for
-	 * every address. */
-
-	struct page **	maplist;
-
 	unsigned int	locked : 1;	/* If set, pages has been locked */
-	
-	/* Always embed enough struct pages for atomic IO */
-	struct page *	map_array[KIO_STATIC_PAGES];
-	struct buffer_head * bh[KIO_MAX_SECTORS];
-	unsigned long blocks[KIO_MAX_SECTORS];
+
+	struct page **  maplist;
+	struct buffer_head ** bh;
+	unsigned long * blocks;
 
 	/* Dynamic state for IO completion: */
 	atomic_t	io_count;	/* IOs still in progress */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/ioport.h linux-2.4.20/include/linux/ioport.h
--- linux-2.4.19/include/linux/ioport.h	2000-11-28 01:51:34.000000000 +0000
+++ linux-2.4.20/include/linux/ioport.h	2002-10-29 11:18:34.000000000 +0000
@@ -92,7 +92,8 @@
 			     unsigned long size,
 			     unsigned long min, unsigned long max,
 			     unsigned long align,
-			     void (*alignf)(void *, struct resource *, unsigned long),
+			     void (*alignf)(void *, struct resource *,
+					    unsigned long, unsigned long),
 			     void *alignf_data);
 
 /* Convenience shorthand with allocation */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/irda.h linux-2.4.20/include/linux/irda.h
--- linux-2.4.19/include/linux/irda.h	2001-11-09 22:11:15.000000000 +0000
+++ linux-2.4.20/include/linux/irda.h	2002-10-29 11:18:32.000000000 +0000
@@ -67,6 +67,9 @@
 	IRDA_AIRPORT_DONGLE      = 6,
 	IRDA_OLD_BELKIN_DONGLE   = 7,
 	IRDA_EP7211_IR           = 8,
+	IRDA_MCP2120_DONGLE      = 9,
+	IRDA_ACT200L_DONGLE      = 10,
+	IRDA_MA600_DONGLE        = 11,
 } IRDA_DONGLE;
 
 /* Protocol types to be used for SOCK_DGRAM */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/jbd.h linux-2.4.20/include/linux/jbd.h
--- linux-2.4.19/include/linux/jbd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/jbd.h	2002-10-29 11:18:49.000000000 +0000
@@ -32,6 +32,14 @@
 
 #define journal_oom_retry 1
 
+/*
+ * Define JBD_PARANOID_WRITES to cause a kernel BUG() check if ext3
+ * finds a buffer unexpectedly dirty.  This is useful for debugging, but
+ * can cause spurious kernel panics if there are applications such as
+ * tune2fs modifying our buffer_heads behind our backs.
+ */
+#undef JBD_PARANOID_WRITES
+
 #ifdef CONFIG_JBD_DEBUG
 /*
  * Define JBD_EXPENSIVE_CHECKING to enable more expensive internal
@@ -249,6 +257,13 @@
 	return bh->b_private;
 }
 
+#define HAVE_JOURNAL_CALLBACK_STATUS
+struct journal_callback {
+	struct list_head jcb_list;
+	void (*jcb_func)(struct journal_callback *jcb, int error);
+	/* user data goes here */
+};
+
 struct jbd_revoke_table_s;
 
 /* The handle_t type represents a single atomic update being performed
@@ -279,6 +294,12 @@
 	   operations */
 	int			h_err;
 
+	/* List of application registered callbacks for this handle.
+	 * The function(s) will be called after the transaction that
+	 * this handle is part of has been committed to disk.
+	 */
+	struct list_head	h_jcb;
+
 	/* Flags */
 	unsigned int	h_sync:		1;	/* sync-on-close */
 	unsigned int	h_jdata:	1;	/* force data journaling */
@@ -398,6 +419,10 @@
 
 	/* How many handles used this transaction? */
 	int t_handle_count;
+
+	/* List of registered callback functions for this transaction.
+	 * Called when the transaction is committed. */
+	struct list_head	t_jcb;
 };
 
 
@@ -646,6 +671,9 @@
 extern int	 journal_try_to_free_buffers(journal_t *, struct page *, int);
 extern int	 journal_stop(handle_t *);
 extern int	 journal_flush (journal_t *);
+extern void	 journal_callback_set(handle_t *handle,
+				      void (*fn)(struct journal_callback *,int),
+				      struct journal_callback *jcb);
 
 extern void	 journal_lock_updates (journal_t *);
 extern void	 journal_unlock_updates (journal_t *);
@@ -730,6 +758,10 @@
 	schedule();						      \
 } while (1)
 
+extern void __jbd_unexpected_dirty_buffer(char *, int, struct journal_head *);
+#define jbd_unexpected_dirty_buffer(jh) \
+	__jbd_unexpected_dirty_buffer(__FUNCTION__, __LINE__, (jh))
+	
 /*
  * is_journal_abort
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/kernel.h linux-2.4.20/include/linux/kernel.h
--- linux-2.4.19/include/linux/kernel.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/kernel.h	2002-10-29 11:18:31.000000000 +0000
@@ -12,6 +12,7 @@
 #include <linux/stddef.h>
 #include <linux/types.h>
 #include <linux/compiler.h>
+#include <asm/byteorder.h>
 
 /* Optimization barrier */
 /* The "volatile" is due to gcc bugs */
@@ -107,6 +108,8 @@
 extern int tainted;
 extern const char *print_tainted(void);
 
+extern void dump_stack(void);
+
 #if DEBUG
 #define pr_debug(fmt,arg...) \
 	printk(KERN_DEBUG fmt,##arg)
@@ -128,11 +131,17 @@
 	((unsigned char *)&addr)[2], \
 	((unsigned char *)&addr)[3]
 
+#if defined(__LITTLE_ENDIAN)
 #define HIPQUAD(addr) \
 	((unsigned char *)&addr)[3], \
 	((unsigned char *)&addr)[2], \
 	((unsigned char *)&addr)[1], \
 	((unsigned char *)&addr)[0]
+#elif defined(__BIG_ENDIAN)
+#define HIPQUAD	NIPQUAD
+#else
+#error "Please fix asm/byteorder.h"
+#endif /* __LITTLE_ENDIAN */
 
 /*
  * min()/max() macros that also do
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/kernel_stat.h linux-2.4.20/include/linux/kernel_stat.h
--- linux-2.4.19/include/linux/kernel_stat.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/kernel_stat.h	2002-10-29 11:18:39.000000000 +0000
@@ -26,7 +26,9 @@
 	unsigned int dk_drive_wblk[DK_MAX_MAJOR][DK_MAX_DISK];
 	unsigned int pgpgin, pgpgout;
 	unsigned int pswpin, pswpout;
-#if !defined(CONFIG_ARCH_S390)
+#if defined (__hppa__) 
+	unsigned int irqs[NR_IRQ_REGS][IRQ_PER_REGION];
+#elif !defined(CONFIG_ARCH_S390)
 	unsigned int irqs[NR_CPUS][NR_IRQS];
 #endif
 	unsigned int context_swtch;
@@ -34,12 +36,22 @@
 
 extern struct kernel_stat kstat;
 
-#if !defined(CONFIG_ARCH_S390)
+extern unsigned long nr_context_switches(void);
+
+#if defined (__hppa__) 
 /*
  * Number of interrupts per specific IRQ source, since bootup
  */
 static inline int kstat_irqs (int irq)
 {
+	return kstat.irqs[IRQ_REGION(irq)][IRQ_OFFSET(irq)];
+}
+#elif !defined(CONFIG_ARCH_S390)
+/*
+ * Number of interrupts per specific IRQ source, since bootup
+ */
+extern inline int kstat_irqs (int irq)
+{
 	int i, sum=0;
 
 	for (i = 0 ; i < smp_num_cpus ; i++)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/limits.h linux-2.4.20/include/linux/limits.h
--- linux-2.4.19/include/linux/limits.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.20/include/linux/limits.h	2002-10-29 11:18:49.000000000 +0000
@@ -13,6 +13,9 @@
 #define NAME_MAX         255	/* # chars in a file name */
 #define PATH_MAX        4096	/* # chars in a path name including nul */
 #define PIPE_BUF        4096	/* # bytes in atomic write to a pipe */
+#define XATTR_NAME_MAX   255	/* # chars in an extended attribute name */
+#define XATTR_SIZE_MAX 65536	/* size of an extended attribute value (64k) */
+#define XATTR_LIST_MAX 65536	/* size of extended attribute namelist (64k) */
 
 #define RTSIG_MAX	  32
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/list.h linux-2.4.20/include/linux/list.h
--- linux-2.4.19/include/linux/list.h	2001-12-21 17:42:03.000000000 +0000
+++ linux-2.4.20/include/linux/list.h	2002-10-29 11:18:31.000000000 +0000
@@ -34,9 +34,9 @@
  * This is only for internal list manipulation where we know
  * the prev/next entries already!
  */
-static __inline__ void __list_add(struct list_head * new,
-	struct list_head * prev,
-	struct list_head * next)
+static inline void __list_add(struct list_head *new,
+			      struct list_head *prev,
+			      struct list_head *next)
 {
 	next->prev = new;
 	new->next = next;
@@ -52,7 +52,7 @@
  * Insert a new entry after the specified head.
  * This is good for implementing stacks.
  */
-static __inline__ void list_add(struct list_head *new, struct list_head *head)
+static inline void list_add(struct list_head *new, struct list_head *head)
 {
 	__list_add(new, head, head->next);
 }
@@ -65,7 +65,7 @@
  * Insert a new entry before the specified head.
  * This is useful for implementing queues.
  */
-static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
 {
 	__list_add(new, head->prev, head);
 }
@@ -77,8 +77,7 @@
  * This is only for internal list manipulation where we know
  * the prev/next entries already!
  */
-static __inline__ void __list_del(struct list_head * prev,
-				  struct list_head * next)
+static inline void __list_del(struct list_head *prev, struct list_head *next)
 {
 	next->prev = prev;
 	prev->next = next;
@@ -89,48 +88,93 @@
  * @entry: the element to delete from the list.
  * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
  */
-static __inline__ void list_del(struct list_head *entry)
+static inline void list_del(struct list_head *entry)
 {
 	__list_del(entry->prev, entry->next);
+	entry->next = (void *) 0;
+	entry->prev = (void *) 0;
 }
 
 /**
  * list_del_init - deletes entry from list and reinitialize it.
  * @entry: the element to delete from the list.
  */
-static __inline__ void list_del_init(struct list_head *entry)
+static inline void list_del_init(struct list_head *entry)
 {
 	__list_del(entry->prev, entry->next);
 	INIT_LIST_HEAD(entry); 
 }
 
 /**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+				  struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add_tail(list, head);
+}
+
+/**
  * list_empty - tests whether a list is empty
  * @head: the list to test.
  */
-static __inline__ int list_empty(struct list_head *head)
+static inline int list_empty(struct list_head *head)
 {
 	return head->next == head;
 }
 
+static inline void __list_splice(struct list_head *list,
+				 struct list_head *head)
+{
+	struct list_head *first = list->next;
+	struct list_head *last = list->prev;
+	struct list_head *at = head->next;
+
+	first->prev = head;
+	head->next = first;
+
+	last->next = at;
+	at->prev = last;
+}
+
 /**
  * list_splice - join two lists
  * @list: the new list to add.
  * @head: the place to add it in the first list.
  */
-static __inline__ void list_splice(struct list_head *list, struct list_head *head)
+static inline void list_splice(struct list_head *list, struct list_head *head)
 {
-	struct list_head *first = list->next;
-
-	if (first != list) {
-		struct list_head *last = list->prev;
-		struct list_head *at = head->next;
-
-		first->prev = head;
-		head->next = first;
+	if (!list_empty(list))
+		__list_splice(list, head);
+}
 
-		last->next = at;
-		at->prev = last;
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+				    struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head);
+		INIT_LIST_HEAD(list);
 	}
 }
 
@@ -151,6 +195,14 @@
 #define list_for_each(pos, head) \
 	for (pos = (head)->next, prefetch(pos->next); pos != (head); \
         	pos = pos->next, prefetch(pos->next))
+/**
+ * list_for_each_prev	-	iterate over a list backwards
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+	for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
+        	pos = pos->prev, prefetch(pos->prev))
         	
 /**
  * list_for_each_safe	-	iterate over a list safe against removal of list entry
@@ -163,14 +215,17 @@
 		pos = n, n = pos->next)
 
 /**
- * list_for_each_prev	-	iterate over a list in reverse order
- * @pos:	the &struct list_head to use as a loop counter.
+ * list_for_each_entry	-	iterate over list of given type
+ * @pos:	the type * to use as a loop counter.
  * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
  */
-#define list_for_each_prev(pos, head) \
-	for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
-        	pos = pos->prev, prefetch(pos->prev))
-        	
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		     prefetch(pos->member.next);			\
+	     &pos->member != (head); 					\
+	     pos = list_entry(pos->member.next, typeof(*pos), member),	\
+		     prefetch(pos->member.next))
 
 #endif /* __KERNEL__ || _LVM_H_INCLUDE */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/lvm.h linux-2.4.20/include/linux/lvm.h
--- linux-2.4.19/include/linux/lvm.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/lvm.h	2002-10-29 11:18:32.000000000 +0000
@@ -3,13 +3,14 @@
  * kernel/lvm.h
  * tools/lib/lvm.h
  *
- * Copyright (C) 1997 - 2001  Heinz Mauelshagen, Sistina Software
+ * Copyright (C) 1997 - 2002  Heinz Mauelshagen, Sistina Software
  *
  * February-November 1997
  * May-July 1998
  * January-March,July,September,October,Dezember 1999
  * January,February,July,November 2000
  * January-March,June,July 2001
+ * May 2002
  *
  * lvm is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -79,8 +80,8 @@
 #ifndef _LVM_H_INCLUDE
 #define _LVM_H_INCLUDE
 
-#define LVM_RELEASE_NAME "1.0.3"
-#define LVM_RELEASE_DATE "19/02/2002"
+#define LVM_RELEASE_NAME "1.0.5+"
+#define LVM_RELEASE_DATE "22/07/2002"
 
 #define	_LVM_KERNEL_H_VERSION	"LVM "LVM_RELEASE_NAME" ("LVM_RELEASE_DATE")"
 
@@ -208,40 +209,35 @@
 /*
  * VGDA: default disk spaces and offsets
  *
- *   There's space after the structures for later extensions.
- *   The physical volume structure holds offset and size definitions
- *   for itself (well, kind of redundant ;-) and all other structure{s| arrays};
- *
- *   In recent versions since LVM 0.9.1 we align to 4k offsets in order to ease
- *   future kernel reads of the metadata.
- *
- *   offset               what                               size
- *   ---------------      --------------------------------   ------------
- *   0                    physical volume structure          pv->pv_on_disk.size
- *                                                           (~500 byte)
- *   pv->vg_on_disk.base  volume group structure             pv->vg_on_disk.size
- *
- *   pv->uuidlist_on_disk.base                               128 byte each
- *                        uuidlist of physical volumes
- *                        holding one uuid per physical volume
+ *   there's space after the structures for later extensions.
  *
- *   pv->lv_on_disk.base  logical volume structures;         pv->lv_on_disk.size
- *                        one structure per logical volume   (~300 byte each)
+ *   offset            what                                size
+ *   ---------------   ----------------------------------  ------------
+ *   0                 physical volume structure           ~500 byte
  *
- *   pv->pe_on_disk.base  physical extent alloc. structs     pv->pe_on_disk.size
- *                        one strcuture per physical extent  (4 byte each)
+ *   1K                volume group structure              ~200 byte
  *
- *   End of disk -        first physical extent              default 4 megabyte
+ *   6K                namelist of physical volumes        128 byte each
+ *
+ *   6k + n * ~300byte n logical volume structures         ~300 byte each
+ *
+ *   + m * 4byte       m physical extent alloc. structs    4 byte each
+ *
+ *   End of disk -     first physical extent               typically 4 megabyte
  *   PE total *
  *   PE size
- *   (rounded to 64k offset today)
  *
- *   pv->pe_on_disk.base + pv->pe_on_disk.size == start of first physical extent
  *
  */
 
 /* DONT TOUCH THESE !!! */
 
+
+
+
+
+
+
 /*
  * LVM_PE_T_MAX corresponds to:
  *
@@ -253,7 +249,7 @@
  *
  * Maximum PE size of 16GB gives a maximum logical volume size of 1024 TB.
  *
- * AFAIK, the actual kernels limit this to 2 TB.
+ * AFAIK, the actual kernels limit this to 1 TB.
  *
  * Should be a sufficient spectrum ;*)
  */
@@ -273,7 +269,7 @@
 #define	LVM_MAX_MIRRORS    	2	/* future use */
 #define	LVM_MIN_READ_AHEAD	0	/* minimum read ahead sectors */
 #define	LVM_DEFAULT_READ_AHEAD	1024	/* sectors for 512k scsi segments */
-#define	LVM_MAX_READ_AHEAD	10000	/* maximum read ahead sectors */
+#define	LVM_MAX_READ_AHEAD	1024	/* maximum read ahead sectors */
 #define	LVM_MAX_LV_IO_TIMEOUT	60	/* seconds I/O timeout (future use) */
 #define	LVM_PARTITION           0xfe	/* LVM partition id */
 #define	LVM_NEW_PARTITION       0x8e	/* new LVM partition id (10/09/1999) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/mii.h linux-2.4.20/include/linux/mii.h
--- linux-2.4.19/include/linux/mii.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.20/include/linux/mii.h	2002-10-29 11:18:31.000000000 +0000
@@ -107,9 +107,11 @@
 struct mii_if_info {
 	int phy_id;
 	int advertising;
+	int phy_id_mask;
+	int reg_num_mask;
 
-	unsigned int full_duplex : 1;
-	unsigned int duplex_lock : 1;
+	unsigned int full_duplex : 1;	/* is full duplex? */
+	unsigned int force_media : 1;	/* is autoneg. disabled? */
 
 	struct net_device *dev;
 	int (*mdio_read) (struct net_device *dev, int phy_id, int location);
@@ -117,11 +119,20 @@
 };
 
 struct ethtool_cmd;
+struct mii_ioctl_data;
+
+extern int mii_link_ok (struct mii_if_info *mii);
+extern int mii_nway_restart (struct mii_if_info *mii);
+extern int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd);
+extern int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd);
+extern void mii_check_link (struct mii_if_info *mii);
+extern unsigned int mii_check_media (struct mii_if_info *mii,
+				     unsigned int ok_to_print,
+				     unsigned int init_media);
+extern int generic_mii_ioctl(struct mii_if_info *mii_if,
+                      	     struct mii_ioctl_data *mii_data, int cmd,
+			     unsigned int *duplex_changed);
 
-int mii_link_ok (struct mii_if_info *mii);
-int mii_nway_restart (struct mii_if_info *mii);
-int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd);
-int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd);
 
 
 /* This structure is used in all SIOCxMIIxxx ioctl calls */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/mmzone.h linux-2.4.20/include/linux/mmzone.h
--- linux-2.4.19/include/linux/mmzone.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/mmzone.h	2002-10-29 11:18:31.000000000 +0000
@@ -158,6 +158,60 @@
 
 extern pg_data_t contig_page_data;
 
+/**
+ * for_each_pgdat - helper macro to iterate over all nodes
+ * @pgdat - pg_data_t * variable
+ *
+ * Meant to help with common loops of the form
+ * pgdat = pgdat_list;
+ * while(pgdat) {
+ * 	...
+ * 	pgdat = pgdat->node_next;
+ * }
+ */
+#define for_each_pgdat(pgdat) \
+	for (pgdat = pgdat_list; pgdat; pgdat = pgdat->node_next)
+
+
+/*
+ * next_zone - helper magic for for_each_zone()
+ * Thanks to William Lee Irwin III for this piece of ingenuity.
+ */
+static inline zone_t *next_zone(zone_t *zone)
+{
+	pg_data_t *pgdat = zone->zone_pgdat;
+
+	if (zone - pgdat->node_zones < MAX_NR_ZONES - 1)
+		zone++;
+
+	else if (pgdat->node_next) {
+		pgdat = pgdat->node_next;
+		zone = pgdat->node_zones;
+	} else
+		zone = NULL;
+
+	return zone;
+}
+
+/**
+ * for_each_zone - helper macro to iterate over all memory zones
+ * @zone - zone_t * variable
+ *
+ * The user only needs to declare the zone variable, for_each_zone
+ * fills it in. This basically means for_each_zone() is an
+ * easier to read version of this piece of code:
+ *
+ * for(pgdat = pgdat_list; pgdat; pgdat = pgdat->node_next)
+ * 	for(i = 0; i < MAX_NR_ZONES; ++i) {
+ * 		zone_t * z = pgdat->node_zones + i;
+ * 		...
+ * 	}
+ * }
+ */
+#define for_each_zone(zone) \
+	for(zone = pgdat_list->node_zones; zone; zone = next_zone(zone))
+
+
 #ifndef CONFIG_DISCONTIGMEM
 
 #define NODE_DATA(nid)		(&contig_page_data)
@@ -169,7 +223,9 @@
 #include <asm/mmzone.h>
 
 /* page->zone is currently 8 bits ... */
+#ifndef MAX_NR_NODES
 #define MAX_NR_NODES		(255 / MAX_NR_ZONES)
+#endif
 
 #endif /* !CONFIG_DISCONTIGMEM */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/mtd/ftl.h linux-2.4.20/include/linux/mtd/ftl.h
--- linux-2.4.19/include/linux/mtd/ftl.h	2001-10-04 22:13:18.000000000 +0000
+++ linux-2.4.20/include/linux/mtd/ftl.h	2002-10-29 11:18:33.000000000 +0000
@@ -15,7 +15,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/namespace.h linux-2.4.20/include/linux/namespace.h
--- linux-2.4.19/include/linux/namespace.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/namespace.h	2002-10-29 11:18:36.000000000 +0000
@@ -9,6 +9,8 @@
 	struct rw_semaphore	sem;
 };
 
+extern void umount_tree(struct vfsmount *);
+
 static inline void put_namespace(struct namespace *namespace)
 {
 	if (atomic_dec_and_test(&namespace->count)) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netdevice.h linux-2.4.20/include/linux/netdevice.h
--- linux-2.4.19/include/linux/netdevice.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/netdevice.h	2002-10-29 11:18:39.000000000 +0000
@@ -162,7 +162,7 @@
 	unsigned fastroute_deferred_out;
 	unsigned fastroute_latency_reduction;
 	unsigned cpu_collision;
-} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
+} ____cacheline_aligned;
 
 extern struct netif_rx_stats netdev_rx_stat[];
 
@@ -206,7 +206,8 @@
 	__LINK_STATE_START,
 	__LINK_STATE_PRESENT,
 	__LINK_STATE_SCHED,
-	__LINK_STATE_NOCARRIER
+	__LINK_STATE_NOCARRIER,
+	__LINK_STATE_RX_SCHED
 };
 
 
@@ -330,6 +331,10 @@
 	void                    *ip6_ptr;       /* IPv6 specific data */
 	void			*ec_ptr;	/* Econet specific data	*/
 
+	struct list_head	poll_list;	/* Link to poll list	*/
+	int			quota;
+	int			weight;
+
 	struct Qdisc		*qdisc;
 	struct Qdisc		*qdisc_sleeping;
 	struct Qdisc		*qdisc_list;
@@ -373,6 +378,8 @@
 	int			(*stop)(struct net_device *dev);
 	int			(*hard_start_xmit) (struct sk_buff *skb,
 						    struct net_device *dev);
+#define HAVE_NETDEV_POLL
+	int			(*poll) (struct net_device *dev, int *quota);
 	int			(*hard_header) (struct sk_buff *skb,
 						struct net_device *dev,
 						unsigned short type,
@@ -492,9 +499,12 @@
 	int			cng_level;
 	int			avg_blog;
 	struct sk_buff_head	input_pkt_queue;
+	struct list_head	poll_list;
 	struct net_device	*output_queue;
 	struct sk_buff		*completion_queue;
-} __attribute__((__aligned__(SMP_CACHE_BYTES)));
+
+	struct net_device	blog_dev;	/* Sorry. 8) */
+} ____cacheline_aligned;
 
 
 extern struct softnet_data softnet_data[NR_CPUS];
@@ -547,6 +557,7 @@
 	return test_bit(__LINK_STATE_START, &dev->state);
 }
 
+
 /* Use this variant when it is known for sure that it
  * is executing from interrupt context.
  */
@@ -575,9 +586,10 @@
 		dev_kfree_skb(skb);
 }
 
-extern void		net_call_rx_atomic(void (*fn)(void));
 #define HAVE_NETIF_RX 1
 extern int		netif_rx(struct sk_buff *skb);
+#define HAVE_NETIF_RECEIVE_SKB 1
+extern int		netif_receive_skb(struct sk_buff *skb);
 extern int		dev_ioctl(unsigned int cmd, void *);
 extern int		dev_change_flags(struct net_device *, unsigned);
 extern void		dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev);
@@ -699,6 +711,78 @@
 #define netif_msg_hw(p)		((p)->msg_enable & NETIF_MSG_HW)
 #define netif_msg_wol(p)	((p)->msg_enable & NETIF_MSG_WOL)
 
+/* Schedule rx intr now? */
+
+static inline int netif_rx_schedule_prep(struct net_device *dev)
+{
+	return netif_running(dev) &&
+		!test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state);
+}
+
+/* Add interface to tail of rx poll list. This assumes that _prep has
+ * already been called and returned 1.
+ */
+
+static inline void __netif_rx_schedule(struct net_device *dev)
+{
+	unsigned long flags;
+	int cpu = smp_processor_id();
+
+	local_irq_save(flags);
+	dev_hold(dev);
+	list_add_tail(&dev->poll_list, &softnet_data[cpu].poll_list);
+	if (dev->quota < 0)
+		dev->quota += dev->weight;
+	else
+		dev->quota = dev->weight;
+	__cpu_raise_softirq(cpu, NET_RX_SOFTIRQ);
+	local_irq_restore(flags);
+}
+
+/* Try to reschedule poll. Called by irq handler. */
+
+static inline void netif_rx_schedule(struct net_device *dev)
+{
+	if (netif_rx_schedule_prep(dev))
+		__netif_rx_schedule(dev);
+}
+
+/* Try to reschedule poll. Called by dev->poll() after netif_rx_complete().
+ * Do not inline this?
+ */
+static inline int netif_rx_reschedule(struct net_device *dev, int undo)
+{
+	if (netif_rx_schedule_prep(dev)) {
+		unsigned long flags;
+		int cpu = smp_processor_id();
+
+		dev->quota += undo;
+
+		local_irq_save(flags);
+		list_add_tail(&dev->poll_list, &softnet_data[cpu].poll_list);
+		__cpu_raise_softirq(cpu, NET_RX_SOFTIRQ);
+		local_irq_restore(flags);
+		return 1;
+	}
+	return 0;
+}
+
+/* Remove interface from poll list: it must be in the poll list
+ * on current cpu. This primitive is called by dev->poll(), when
+ * it completes the work. The device cannot be out of poll list at this
+ * moment, it is BUG().
+ */
+static inline void netif_rx_complete(struct net_device *dev)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (!test_bit(__LINK_STATE_RX_SCHED, &dev->state)) BUG();
+	list_del(&dev->poll_list);
+	clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
+	local_irq_restore(flags);
+}
+
 /* These functions live elsewhere (drivers/net/net_init.c, but related) */
 
 extern void		ether_setup(struct net_device *dev);
@@ -723,6 +807,7 @@
 extern int		netdev_register_fc(struct net_device *dev, void (*stimul)(struct net_device *dev));
 extern void		netdev_unregister_fc(int bit);
 extern int		netdev_max_backlog;
+extern int		weight_p;
 extern unsigned long	netdev_fc_xoff;
 extern atomic_t netdev_dropping;
 extern int		netdev_set_master(struct net_device *dev, struct net_device *master);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ip_conntrack.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack.h	2002-10-29 11:18:38.000000000 +0000
@@ -6,6 +6,7 @@
 
 #include <linux/config.h>
 #include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
+#include <asm/atomic.h>
 
 enum ip_conntrack_info
 {
@@ -42,12 +43,57 @@
 	IPS_ASSURED = (1 << IPS_ASSURED_BIT),
 };
 
+#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
+
+/* per conntrack: protocol private data */
+union ip_conntrack_proto {
+	/* insert conntrack proto private data here */
+	struct ip_ct_tcp tcp;
+	struct ip_ct_icmp icmp;
+};
+
+union ip_conntrack_expect_proto {
+	/* insert expect proto private data here */
+};
+
+/* Add protocol helper include file here */
+#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
+
+/* per expectation: application helper private data */
+union ip_conntrack_expect_help {
+	/* insert conntrack helper private data (expect) here */
+	struct ip_ct_ftp_expect exp_ftp_info;
+	struct ip_ct_irc_expect exp_irc_info;
+
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+	union {
+		/* insert nat helper private data (expect) here */
+	} nat;
+#endif
+};
+
+/* per conntrack: application helper private data */
+union ip_conntrack_help {
+	/* insert conntrack helper private data (master) here */
+	struct ip_ct_ftp_master ct_ftp_info;
+	struct ip_ct_irc_master ct_irc_info;
+};
+
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+#include <linux/netfilter_ipv4/ip_nat.h>
+
+/* per conntrack: nat application helper private data */
+union ip_conntrack_nat_help {
+	/* insert nat helper private data here */
+};
+#endif
+
 #ifdef __KERNEL__
 
 #include <linux/types.h>
 #include <linux/skbuff.h>
-#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
-#include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
 
 #ifdef CONFIG_NF_DEBUG
 #define IP_NF_ASSERT(x)							\
@@ -64,26 +110,45 @@
 
 struct ip_conntrack_expect
 {
-	/* Internal linked list */
+	/* Internal linked list (global expectation list) */
 	struct list_head list;
 
+	/* reference count */
+	atomic_t use;
+
+	/* expectation list for this master */
+	struct list_head expected_list;
+
+	/* The conntrack of the master connection */
+	struct ip_conntrack *expectant;
+
+	/* The conntrack of the sibling connection, set after
+	 * expectation arrived */
+	struct ip_conntrack *sibling;
+
+	/* Tuple saved for conntrack */
+	struct ip_conntrack_tuple ct_tuple;
+
+	/* Timer function; deletes the expectation. */
+	struct timer_list timeout;
+
+	/* Data filled out by the conntrack helpers follow: */
+
 	/* We expect this tuple, with the following mask */
 	struct ip_conntrack_tuple tuple, mask;
 
 	/* Function to call after setup and insertion */
 	int (*expectfn)(struct ip_conntrack *new);
 
-	/* The conntrack we are part of (set iff we're live) */
-	struct ip_conntrack *expectant;
-};
+	/* At which sequence number did this expectation occur */
+	u_int32_t seq;
+  
+	union ip_conntrack_expect_proto proto;
 
-#ifdef CONFIG_IP_NF_NAT_NEEDED
-#include <linux/netfilter_ipv4/ip_nat.h>
-#endif
-
-#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
-#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
+	union ip_conntrack_expect_help help;
+};
 
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 struct ip_conntrack
 {
 	/* Usage count in here is 1 for hash table/destruct timer, 1 per skb,
@@ -101,10 +166,13 @@
 
 	/* If we're expecting another related connection, this will be
            in expected linked list */
-	struct ip_conntrack_expect expected;
+	struct list_head sibling_list;
+	
+	/* Current number of expected connections */
+	unsigned int expecting;
 
-	/* If we were expected by another connection, this will be it */
-	struct nf_ct_info master;
+	/* If we were expected by an expectation, this will be it */
+	struct ip_conntrack_expect *master;
 
 	/* Helper, if any. */
 	struct ip_conntrack_helper *helper;
@@ -115,22 +183,14 @@
 
 	/* Storage reserved for other modules: */
 
-	union {
-		struct ip_ct_tcp tcp;
-		struct ip_ct_icmp icmp;
-	} proto;
+	union ip_conntrack_proto proto;
 
-	union {
-		struct ip_ct_ftp ct_ftp_info;
-		struct ip_ct_irc ct_irc_info;
-	} help;
+	union ip_conntrack_help help;
 
 #ifdef CONFIG_IP_NF_NAT_NEEDED
 	struct {
 		struct ip_nat_info info;
-		union {
-			/* insert nat helper private data here */
-		} help;
+		union ip_conntrack_nat_help help;
 #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
 	defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
 		int masq_index;
@@ -140,6 +200,9 @@
 
 };
 
+/* get master conntrack via master expectation */
+#define master_ct(conntr) (conntr->master ? conntr->master->expectant : NULL)
+
 /* Alter reply tuple (maybe alter helper).  If it's already taken,
    return 0 and don't do alteration. */
 extern int
@@ -156,6 +219,16 @@
 extern struct ip_conntrack *
 ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo);
 
+/* decrement reference count on a conntrack */
+extern inline void ip_conntrack_put(struct ip_conntrack *ct);
+
+/* find unconfirmed expectation based on tuple */
+struct ip_conntrack_expect *
+ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple);
+
+/* decrement reference count on an expectation */
+void ip_conntrack_expect_put(struct ip_conntrack_expect *exp);
+
 extern struct module *ip_conntrack_module;
 
 extern int invert_tuplepr(struct ip_conntrack_tuple *inverse,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ip_conntrack_core.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_core.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ip_conntrack_core.h	2001-04-27 21:15:01.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_core.h	2002-10-29 11:18:51.000000000 +0000
@@ -15,9 +15,9 @@
 extern void ip_conntrack_cleanup(void);
 
 struct ip_conntrack_protocol;
-extern struct ip_conntrack_protocol *find_proto(u_int8_t protocol);
+extern struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol);
 /* Like above, but you already have conntrack read lock. */
-extern struct ip_conntrack_protocol *__find_proto(u_int8_t protocol);
+extern struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol);
 extern struct list_head protocol_list;
 
 /* Returns conntrack if it dealt with ICMP, and filled in skb->nfct */
@@ -45,7 +45,7 @@
 }
 
 extern struct list_head *ip_conntrack_hash;
-extern struct list_head expect_list;
+extern struct list_head ip_conntrack_expect_list;
 DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
 #endif /* _IP_CONNTRACK_CORE_H */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ip_conntrack_ftp.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	2001-04-25 22:00:28.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	2002-10-29 11:18:51.000000000 +0000
@@ -2,15 +2,17 @@
 #define _IP_CONNTRACK_FTP_H
 /* FTP tracking. */
 
-#ifndef __KERNEL__
-#error Only in kernel.
-#endif
+#ifdef __KERNEL__
 
 #include <linux/netfilter_ipv4/lockhelp.h>
 
 /* Protects ftp part of conntracks */
 DECLARE_LOCK_EXTERN(ip_ftp_lock);
 
+#define FTP_PORT	21
+
+#endif /* __KERNEL__ */
+
 enum ip_ct_ftp_type
 {
 	/* PORT command from client */
@@ -23,18 +25,20 @@
 	IP_CT_FTP_EPSV,
 };
 
-/* We record seq number and length of ftp ip/port text here: all in
-   host order. */
-struct ip_ct_ftp
+/* This structure is per expected connection */
+struct ip_ct_ftp_expect
 {
-	/* This tells NAT that this is an ftp connection */
-	int is_ftp;
-	u_int32_t seq;
-	/* 0 means not found yet */
-	u_int32_t len;
-	enum ip_ct_ftp_type ftptype;
-	/* Port that was to be used */
-	u_int16_t port;
+	/* We record seq number and length of ftp ip/port text here: all in
+	 * host order. */
+
+ 	/* sequence number of IP address in packet is in ip_conntrack_expect */
+	u_int32_t len;			/* length of IP address */
+	enum ip_ct_ftp_type ftptype;	/* PORT or PASV ? */
+	u_int16_t port; 		/* TCP port that was to be used */
+};
+
+/* This structure exists only once per master */
+struct ip_ct_ftp_master {
 	/* Next valid seq position for cmd matching after newline */
 	u_int32_t seq_aft_nl[IP_CT_DIR_MAX];
 	/* 0 means seq_match_aft_nl not set */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ip_conntrack_helper.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_helper.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ip_conntrack_helper.h	2000-12-11 21:31:23.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_helper.h	2002-10-29 11:18:33.000000000 +0000
@@ -5,10 +5,19 @@
 
 struct module;
 
+/* Reuse expectation when max_expected reached */
+#define IP_CT_HELPER_F_REUSE_EXPECT	0x01
+
 struct ip_conntrack_helper
 {	
-	/* Internal use. */
-	struct list_head list;
+	struct list_head list; 		/* Internal use. */
+
+	const char *name;		/* name of the module */
+	unsigned char flags;		/* Flags (see above) */
+	struct module *me;		/* pointer to self */
+	unsigned int max_expected;	/* Maximum number of concurrent 
+					 * expected connections */
+	unsigned int timeout;		/* timeout for expecteds */
 
 	/* Mask of things we will help (compared against server response) */
 	struct ip_conntrack_tuple tuple;
@@ -24,11 +33,13 @@
 extern int ip_conntrack_helper_register(struct ip_conntrack_helper *);
 extern void ip_conntrack_helper_unregister(struct ip_conntrack_helper *);
 
-/* Add an expected connection: can only have one per connection */
+extern struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple);
+
+/* Add an expected connection: can have more than one per connection */
 extern int ip_conntrack_expect_related(struct ip_conntrack *related_to,
-				       const struct ip_conntrack_tuple *tuple,
-				       const struct ip_conntrack_tuple *mask,
-				       int (*expectfn)(struct ip_conntrack *));
-extern void ip_conntrack_unexpect_related(struct ip_conntrack *related_to);
+				       struct ip_conntrack_expect *exp);
+extern int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
+				      struct ip_conntrack_tuple *newtuple);
+extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp);
 
 #endif /*_IP_CONNTRACK_HELPER_H*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ip_conntrack_irc.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_irc.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ip_conntrack_irc.h	2001-10-30 23:08:12.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_irc.h	2002-10-29 11:18:37.000000000 +0000
@@ -14,13 +14,28 @@
 #ifndef _IP_CONNTRACK_IRC_H
 #define _IP_CONNTRACK_IRC_H
 
-#ifndef __KERNEL__
-#error Only in kernel.
-#endif
+/* We record seq number and length of irc ip/port text here: all in
+   host order. */
+
+/* This structure is per expected connection */
+struct ip_ct_irc_expect
+{
+	/* length of IP address */
+	u_int32_t len;
+	/* Port that was to be used */
+	u_int16_t port;
+};
+
+/* This structure exists only once per master */
+struct ip_ct_irc_master {
+};
+
+
+#ifdef __KERNEL__
 
 #include <linux/netfilter_ipv4/lockhelp.h>
 
-#define IP_CONNTR_IRC	2
+#define IRC_PORT	6667
 
 struct dccproto {
 	char* match;
@@ -30,18 +45,6 @@
 /* Protects irc part of conntracks */
 DECLARE_LOCK_EXTERN(ip_irc_lock);
 
-/* We record seq number and length of irc ip/port text here: all in
-   host order. */
-struct ip_ct_irc
-{
-	/* This tells NAT that this is an IRC connection */
-	int is_irc;
-	/* sequence number where address part of DCC command begins */
-	u_int32_t seq;
-	/* 0 means not found yet */
-	u_int32_t len;
-	/* Port that was to be used */
-	u_int16_t port;
-};
+#endif /* __KERNEL__ */
 
 #endif /* _IP_CONNTRACK_IRC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ip_conntrack_protocol.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	2002-10-29 11:18:50.000000000 +0000
@@ -45,6 +45,10 @@
 	/* Called when a conntrack entry is destroyed */
 	void (*destroy)(struct ip_conntrack *conntrack);
 
+	/* Has to decide if a expectation matches one packet or not */
+	int (*exp_matches_pkt)(struct ip_conntrack_expect *exp,
+			       struct sk_buff **pskb);
+
 	/* Module (if any) which this is connected to. */
 	struct module *me;
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ip_conntrack_tcp.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_tcp.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ip_conntrack_tcp.h	2000-08-04 20:07:24.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_tcp.h	2002-10-29 11:18:37.000000000 +0000
@@ -2,10 +2,6 @@
 #define _IP_CONNTRACK_TCP_H
 /* TCP tracking. */
 
-#ifndef __KERNEL__
-#error Only in kernel.
-#endif
-
 enum tcp_conntrack {
 	TCP_CONNTRACK_NONE,
 	TCP_CONNTRACK_ESTABLISHED,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ip_nat.h linux-2.4.20/include/linux/netfilter_ipv4/ip_nat.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ip_nat.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ip_nat.h	2002-10-29 11:18:50.000000000 +0000
@@ -60,22 +60,6 @@
 	struct ip_nat_range range[1];
 };
 
-#ifdef __KERNEL__
-#include <linux/list.h>
-#include <linux/netfilter_ipv4/lockhelp.h>
-
-/* Protects NAT hash tables, and NAT-private part of conntracks. */
-DECLARE_RWLOCK_EXTERN(ip_nat_lock);
-
-/* Hashes for by-source and IP/protocol. */
-struct ip_nat_hash
-{
-	struct list_head list;
-
-	/* conntrack we're embedded in: NULL if not in hash. */
-	struct ip_conntrack *conntrack;
-};
-
 /* Worst case: local-out manip + 1 post-routing, and reverse dirn. */
 #define IP_NAT_MAX_MANIPS (2*3)
 
@@ -93,7 +77,23 @@
 	/* Manipulations to occur at each conntrack in this dirn. */
 	struct ip_conntrack_manip manip;
 };
-	
+
+#ifdef __KERNEL__
+#include <linux/list.h>
+#include <linux/netfilter_ipv4/lockhelp.h>
+
+/* Protects NAT hash tables, and NAT-private part of conntracks. */
+DECLARE_RWLOCK_EXTERN(ip_nat_lock);
+
+/* Hashes for by-source and IP/protocol. */
+struct ip_nat_hash
+{
+	struct list_head list;
+
+	/* conntrack we're embedded in: NULL if not in hash. */
+	struct ip_conntrack *conntrack;
+};
+
 /* The structure embedded in the conntrack structure. */
 struct ip_nat_info
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ip_nat_helper.h linux-2.4.20/include/linux/netfilter_ipv4/ip_nat_helper.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ip_nat_helper.h	2001-04-25 22:00:28.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ip_nat_helper.h	2002-10-29 11:18:35.000000000 +0000
@@ -6,23 +6,37 @@
 
 struct sk_buff;
 
+/* Flags */
+/* NAT helper must be called on every packet (for TCP) */
+#define IP_NAT_HELPER_F_ALWAYS		0x01
+/* Standalone NAT helper, without a conntrack part */
+#define IP_NAT_HELPER_F_STANDALONE	0x02
+
 struct ip_nat_helper
 {
-	/* Internal use */
-	struct list_head list;
+	struct list_head list;		/* Internal use */
 
+	const char *name;		/* name of the module */
+	unsigned char flags;		/* Flags (see above) */
+	struct module *me;		/* pointer to self */
+	
 	/* Mask of things we will help: vs. tuple from server */
 	struct ip_conntrack_tuple tuple;
 	struct ip_conntrack_tuple mask;
 	
 	/* Helper function: returns verdict */
 	unsigned int (*help)(struct ip_conntrack *ct,
+			     struct ip_conntrack_expect *exp,
 			     struct ip_nat_info *info,
 			     enum ip_conntrack_info ctinfo,
 			     unsigned int hooknum,
 			     struct sk_buff **pskb);
 
-	const char *name;
+	/* Returns verdict and sets up NAT for this connection */
+	unsigned int (*expect)(struct sk_buff **pskb,
+			       unsigned int hooknum,
+			       struct ip_conntrack *ct,
+			       struct ip_nat_info *info);
 };
 
 extern struct list_head helpers;
@@ -39,5 +53,5 @@
 extern int ip_nat_seq_adjust(struct sk_buff *skb,
 				struct ip_conntrack *ct,
 				enum ip_conntrack_info ctinfo);
-extern void ip_nat_delete_sack(struct sk_buff *skb, struct tcphdr *tcph);
+extern void ip_nat_delete_sack(struct sk_buff *skb);
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ip_nat_rule.h linux-2.4.20/include/linux/netfilter_ipv4/ip_nat_rule.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ip_nat_rule.h	2000-12-11 21:31:32.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ip_nat_rule.h	2002-10-29 11:18:37.000000000 +0000
@@ -5,24 +5,7 @@
 #include <linux/netfilter_ipv4/ip_nat.h>
 
 #ifdef __KERNEL__
-/* Want to be told when we first NAT an expected packet for a conntrack? */
-struct ip_nat_expect
-{
-	struct list_head list;
 
-	/* Returns 1 (and sets verdict) if it has setup NAT for this
-           connection */
-	int (*expect)(struct sk_buff **pskb,
-		      unsigned int hooknum,
-		      struct ip_conntrack *ct,
-		      struct ip_nat_info *info,
-		      struct ip_conntrack *master,
-		      struct ip_nat_info *masterinfo,
-		      unsigned int *verdict);
-};
-
-extern int ip_nat_expect_register(struct ip_nat_expect *expect);
-extern void ip_nat_expect_unregister(struct ip_nat_expect *expect);
 extern int ip_nat_rule_init(void) __init;
 extern void ip_nat_rule_cleanup(void);
 extern int ip_nat_rule_find(struct sk_buff **pskb,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ipt_DSCP.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_DSCP.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ipt_DSCP.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_DSCP.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,20 @@
+/* iptables module for setting the IPv4 DSCP field
+ *
+ * (C) 2002 Harald Welte <laforge@gnumonks.org>
+ * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * See RFC2474 for a description of the DSCP field within the IP Header.
+ *
+ * ipt_DSCP.h,v 1.7 2002/03/14 12:03:13 laforge Exp
+*/
+#ifndef _IPT_DSCP_TARGET_H
+#define _IPT_DSCP_TARGET_H
+#include <linux/netfilter_ipv4/ipt_dscp.h>
+
+/* target info */
+struct ipt_DSCP_info {
+	u_int8_t dscp;
+};
+
+#endif /* _IPT_DSCP_TARGET_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ipt_ECN.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_ECN.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ipt_ECN.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_ECN.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,31 @@
+/* Header file for iptables ipt_ECN target
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * ipt_ECN.h,v 1.3 2002/05/29 12:17:40 laforge Exp
+*/
+#ifndef _IPT_ECN_TARGET_H
+#define _IPT_ECN_TARGET_H
+#include <linux/netfilter_ipv4/ipt_DSCP.h>
+
+#define IPT_ECN_IP_MASK	(~IPT_DSCP_MASK)
+
+#define IPT_ECN_OP_SET_IP	0x01	/* set ECN bits of IPv4 header */
+#define IPT_ECN_OP_SET_ECE	0x10	/* set ECE bit of TCP header */
+#define IPT_ECN_OP_SET_CWR	0x20	/* set CWR bit of TCP header */
+
+#define IPT_ECN_OP_MASK		0xce
+
+struct ipt_ECN_info {
+	u_int8_t operation;	/* bitset of operations */
+	u_int8_t ip_ect;	/* ECT codepoint of IPv4 header, pre-shifted */
+	union {
+		struct {
+			u_int8_t ece:1, cwr:1; /* TCP ECT bits */
+		} tcp;
+	} proto;
+};
+
+#endif /* _IPT_ECN_TARGET_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ipt_conntrack.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_conntrack.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ipt_conntrack.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_conntrack.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,38 @@
+/* Header file for kernel module to match connection tracking information.
+ * GPL (C) 2001  Marc Boucher (marc@mbsi.ca).
+ */
+
+#ifndef _IPT_CONNTRACK_H
+#define _IPT_CONNTRACK_H
+
+#define IPT_CONNTRACK_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
+#define IPT_CONNTRACK_STATE_INVALID (1 << 0)
+
+#define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
+#define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
+
+/* flags, invflags: */
+#define IPT_CONNTRACK_STATE	0x01
+#define IPT_CONNTRACK_PROTO	0x02
+#define IPT_CONNTRACK_ORIGSRC	0x04
+#define IPT_CONNTRACK_ORIGDST	0x08
+#define IPT_CONNTRACK_REPLSRC	0x10
+#define IPT_CONNTRACK_REPLDST	0x20
+#define IPT_CONNTRACK_STATUS	0x40
+#define IPT_CONNTRACK_EXPIRES	0x80
+
+struct ipt_conntrack_info
+{
+	unsigned int statemask, statusmask;
+
+	struct ip_conntrack_tuple tuple[IP_CT_DIR_MAX];
+	struct in_addr sipmsk[IP_CT_DIR_MAX], dipmsk[IP_CT_DIR_MAX];
+
+	unsigned long expires_min, expires_max;
+
+	/* Flags word */
+	u_int8_t flags;
+	/* Inverse flags */
+	u_int8_t invflags;
+};
+#endif /*_IPT_CONNTRACK_H*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ipt_dscp.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_dscp.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ipt_dscp.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_dscp.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,23 @@
+/* iptables module for matching the IPv4 DSCP field
+ *
+ * (C) 2002 Harald Welte <laforge@gnumonks.org>
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * See RFC2474 for a description of the DSCP field within the IP Header.
+ *
+ * ipt_dscp.h,v 1.3 2002/08/05 19:00:21 laforge Exp
+*/
+#ifndef _IPT_DSCP_H
+#define _IPT_DSCP_H
+
+#define IPT_DSCP_MASK	0xfc	/* 11111100 */
+#define IPT_DSCP_SHIFT	2
+#define IPT_DSCP_MAX	0x3f	/* 00111111 */
+
+/* match info */
+struct ipt_dscp_info {
+	u_int8_t dscp;
+	u_int8_t invert;
+};
+
+#endif /* _IPT_DSCP_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ipt_ecn.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_ecn.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ipt_ecn.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_ecn.h	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,33 @@
+/* iptables module for matching the ECN header in IPv4 and TCP header
+ *
+ * (C) 2002 Harald Welte <laforge@gnumonks.org>
+ *
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * ipt_ecn.h,v 1.4 2002/08/05 19:39:00 laforge Exp
+*/
+#ifndef _IPT_ECN_H
+#define _IPT_ECN_H
+#include <linux/netfilter_ipv4/ipt_dscp.h>
+
+#define IPT_ECN_IP_MASK	(~IPT_DSCP_MASK)
+
+#define IPT_ECN_OP_MATCH_IP	0x01
+#define IPT_ECN_OP_MATCH_ECE	0x10
+#define IPT_ECN_OP_MATCH_CWR	0x20
+
+#define IPT_ECN_OP_MATCH_MASK	0xce
+
+/* match info */
+struct ipt_ecn_info {
+	u_int8_t operation;
+	u_int8_t invert;
+	u_int8_t ip_ect;
+	union {
+		struct {
+			u_int8_t ect;
+		} tcp;
+	} proto;
+};
+
+#endif /* _IPT_ECN_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ipt_helper.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_helper.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ipt_helper.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_helper.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,8 @@
+#ifndef _IPT_HELPER_H
+#define _IPT_HELPER_H
+
+struct ipt_helper_info {
+	int invert;
+	char name[30];
+};
+#endif /* _IPT_HELPER_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ipt_owner.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_owner.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ipt_owner.h	2000-03-17 18:56:20.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_owner.h	2002-10-29 11:18:32.000000000 +0000
@@ -6,12 +6,14 @@
 #define IPT_OWNER_GID	0x02
 #define IPT_OWNER_PID	0x04
 #define IPT_OWNER_SID	0x08
+#define IPT_OWNER_COMM	0x10
 
 struct ipt_owner_info {
     uid_t uid;
     gid_t gid;
     pid_t pid;
     pid_t sid;
+    char comm[16];
     u_int8_t match, invert;	/* flags */
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv4/ipt_pkttype.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_pkttype.h
--- linux-2.4.19/include/linux/netfilter_ipv4/ipt_pkttype.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_pkttype.h	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,8 @@
+#ifndef _IPT_PKTTYPE_H
+#define _IPT_PKTTYPE_H
+
+struct ipt_pkttype_info {
+	int	pkttype;
+	int	invert;
+};
+#endif /*_IPT_PKTTYPE_H*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netfilter_ipv6/ip6t_length.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_length.h
--- linux-2.4.19/include/linux/netfilter_ipv6/ip6t_length.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_length.h	2002-10-29 11:18:36.000000000 +0000
@@ -0,0 +1,10 @@
+#ifndef _IP6T_LENGTH_H
+#define _IP6T_LENGTH_H
+
+struct ip6t_length_info {
+	u_int16_t  min, max;
+	u_int8_t   invert;
+};
+
+#endif /*_IP6T_LENGTH_H*/
+	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/netlink.h linux-2.4.20/include/linux/netlink.h
--- linux-2.4.19/include/linux/netlink.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.20/include/linux/netlink.h	2002-10-29 11:18:36.000000000 +0000
@@ -110,6 +110,8 @@
 extern void netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
 			      __u32 group, int allocation);
 extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code);
+extern int netlink_register_notifier(struct notifier_block *nb);
+extern int netlink_unregister_notifier(struct notifier_block *nb);
 
 /*
  *	skb should fit one page. This choice is good for headerless malloc.
@@ -129,6 +131,12 @@
 	long		args[4];
 };
 
+struct netlink_notify
+{
+	int pid;
+	int protocol;
+};
+
 static __inline__ struct nlmsghdr *
 __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len)
 {
@@ -153,6 +161,10 @@
 			      int (*dump)(struct sk_buff *skb, struct netlink_callback*),
 			      int (*done)(struct netlink_callback*));
 
+#define NL_NONROOT_RECV 0x1
+#define NL_NONROOT_SEND 0x2
+extern void netlink_set_nonroot(int protocol, unsigned flag);
+
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/nfs_fs.h linux-2.4.20/include/linux/nfs_fs.h
--- linux-2.4.19/include/linux/nfs_fs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/nfs_fs.h	2002-10-29 11:18:37.000000000 +0000
@@ -273,8 +273,8 @@
  * linux/fs/mount_clnt.c
  * (Used only by nfsroot module)
  */
-extern int  nfs_mount(struct sockaddr_in *, char *, struct nfs_fh *);
-extern int  nfs3_mount(struct sockaddr_in *, char *, struct nfs_fh *);
+extern int  nfsroot_mount(struct sockaddr_in *, char *, struct nfs_fh *,
+		int, int);
 
 /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
 extern u32 root_nfs_parse_addr(char *name); /*__init*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/nfs_xdr.h linux-2.4.20/include/linux/nfs_xdr.h
--- linux-2.4.19/include/linux/nfs_xdr.h	2001-01-29 20:07:43.000000000 +0000
+++ linux-2.4.20/include/linux/nfs_xdr.h	2002-10-29 11:18:35.000000000 +0000
@@ -1,9 +1,6 @@
 #ifndef _LINUX_NFS_XDR_H
 #define _LINUX_NFS_XDR_H
 
-extern struct rpc_program	nfs_program;
-extern struct rpc_stat		nfs_rpcstat;
-
 struct nfs_fattr {
 	unsigned short		valid;		/* which fields are valid */
 	__u64			pre_size;	/* pre_op_attr.size	  */
@@ -68,8 +65,8 @@
 	struct nfs_fh *		fh;
 	__u64			offset;
 	__u32			count;
-	unsigned int            nriov;
-	struct iovec            iov[NFS_READ_MAXIOV];
+	unsigned int		pgbase;
+	struct page **		pages;
 };
 
 struct nfs_readres {
@@ -87,8 +84,8 @@
 	__u64			offset;
 	__u32			count;
 	enum nfs3_stable_how	stable;
-	unsigned int		nriov;
-	struct iovec		iov[NFS_WRITE_MAXIOV];
+	unsigned int		pgbase;
+	struct page **		pages;
 };
 
 struct nfs_writeverf {
@@ -165,8 +162,8 @@
 struct nfs_readdirargs {
 	struct nfs_fh *		fh;
 	__u32			cookie;
-	void *			buffer;
-	unsigned int		bufsiz;
+	unsigned int		count;
+	struct page **		pages;
 };
 
 struct nfs_diropok {
@@ -176,18 +173,8 @@
 
 struct nfs_readlinkargs {
 	struct nfs_fh *		fh;
-	void *			buffer;
-	unsigned int		bufsiz;
-};
-
-struct nfs_readlinkres {
-	void *			buffer;
-	unsigned int		bufsiz;
-};
-
-struct nfs_readdirres {
-	void *			buffer;
-	unsigned int		bufsiz;
+	unsigned int		count;
+	struct page **		pages;
 };
 
 struct nfs3_sattrargs {
@@ -262,9 +249,9 @@
 	struct nfs_fh *		fh;
 	__u64			cookie;
 	__u32			verf[2];
-	void *			buffer;
-	unsigned int		bufsiz;
 	int			plus;
+	unsigned int            count;
+	struct page **		pages;
 };
 
 struct nfs3_diropres {
@@ -280,14 +267,8 @@
 
 struct nfs3_readlinkargs {
 	struct nfs_fh *		fh;
-	void *			buffer;
-	unsigned int		bufsiz;
-};
-
-struct nfs3_readlinkres {
-	struct nfs_fattr *	fattr;
-	void *			buffer;
-	unsigned int		bufsiz;
+	unsigned int		count;
+	struct page **		pages;
 };
 
 struct nfs3_renameres {
@@ -303,8 +284,6 @@
 struct nfs3_readdirres {
 	struct nfs_fattr *	dir_attr;
 	__u32 *			verf;
-	void *			buffer;
-	unsigned int		bufsiz;
 	int			plus;
 };
 
@@ -322,15 +301,15 @@
 	int	(*lookup)  (struct inode *, struct qstr *,
 			    struct nfs_fh *, struct nfs_fattr *);
 	int	(*access)  (struct inode *, int , int);
-	int	(*readlink)(struct inode *, void *, unsigned int);
+	int	(*readlink)(struct inode *, struct page *);
 	int	(*read)    (struct inode *, struct rpc_cred *,
 			    struct nfs_fattr *,
-			    int, loff_t, unsigned int,
-			    void *buffer, int *eofp);
+			    int, unsigned int, unsigned int,
+			    struct page *, int *eofp);
 	int	(*write)   (struct inode *, struct rpc_cred *,
 			    struct nfs_fattr *,
-			    int, loff_t, unsigned int,
-			    void *buffer, struct nfs_writeverf *verfp);
+			    int, unsigned int, unsigned int,
+			    struct page *, struct nfs_writeverf *verfp);
 	int	(*commit)  (struct inode *, struct nfs_fattr *,
 			    unsigned long, unsigned int);
 	int	(*create)  (struct inode *, struct qstr *, struct iattr *,
@@ -349,7 +328,7 @@
 			    struct nfs_fh *, struct nfs_fattr *);
 	int	(*rmdir)   (struct inode *, struct qstr *);
 	int	(*readdir) (struct inode *, struct rpc_cred *,
-			    u64, void *, unsigned int, int);
+			    u64, struct page *, unsigned int, int);
 	int	(*mknod)   (struct inode *, struct qstr *, struct iattr *,
 			    dev_t, struct nfs_fh *, struct nfs_fattr *);
 	int	(*statfs)  (struct nfs_server *, struct nfs_fh *,
@@ -372,5 +351,6 @@
 extern struct rpc_version	nfs_version2;
 extern struct rpc_version	nfs_version3;
 extern struct rpc_program	nfs_program;
+extern struct rpc_stat		nfs_rpcstat;
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/nfsd/export.h linux-2.4.20/include/linux/nfsd/export.h
--- linux-2.4.19/include/linux/nfsd/export.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/nfsd/export.h	2002-10-29 11:18:31.000000000 +0000
@@ -39,7 +39,8 @@
 #define NFSEXP_NOSUBTREECHECK	0x0400
 #define	NFSEXP_NOAUTHNLM	0x0800		/* Don't authenticate NLM requests - just trust */
 #define NFSEXP_MSNFS		0x1000	/* do silly things that MS clients expect */
-#define NFSEXP_ALLFLAGS		0x1FFF
+#define NFSEXP_FSID		0x2000
+#define NFSEXP_ALLFLAGS		0x3FFF
 
 
 #ifdef __KERNEL__
@@ -55,11 +56,13 @@
 	struct in_addr		cl_addr[NFSCLNT_ADDRMAX];
 	struct svc_uidmap *	cl_umap;
 	struct list_head	cl_export[NFSCLNT_EXPMAX];
+	struct list_head	cl_expfsid[NFSCLNT_EXPMAX];
 	struct list_head	cl_list;
 };
 
 struct svc_export {
 	struct list_head	ex_hash;
+	struct list_head	ex_fsid_hash;
 	struct list_head	ex_list;
 	char			ex_path[NFS_MAXPATHLEN+1];
 	struct svc_export *	ex_parent;
@@ -71,6 +74,7 @@
 	ino_t			ex_ino;
 	uid_t			ex_anon_uid;
 	gid_t			ex_anon_gid;
+	int			ex_fsid;
 };
 
 #define EX_SECURE(exp)		(!((exp)->ex_flags & NFSEXP_INSECURE_PORT))
@@ -92,6 +96,7 @@
 struct svc_client *	exp_getclient(struct sockaddr_in *sin);
 void			exp_putclient(struct svc_client *clp);
 struct svc_export *	exp_get(struct svc_client *clp, kdev_t dev, ino_t ino);
+struct svc_export *	exp_get_fsid(struct svc_client *clp, int fsid);
 int			exp_rootfh(struct svc_client *, kdev_t, ino_t,
 					char *path, struct knfsd_fh *, int maxsize);
 int			nfserrno(int errno);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/nfsd/nfsd.h linux-2.4.20/include/linux/nfsd/nfsd.h
--- linux-2.4.19/include/linux/nfsd/nfsd.h	2001-11-22 19:47:20.000000000 +0000
+++ linux-2.4.20/include/linux/nfsd/nfsd.h	2002-10-29 11:18:39.000000000 +0000
@@ -37,7 +37,8 @@
 #define MAY_TRUNC		16
 #define MAY_LOCK		32
 #define MAY_OWNER_OVERRIDE	64
-#if (MAY_SATTR | MAY_TRUNC | MAY_LOCK | MAX_OWNER_OVERRIDE) & (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_OWNER_OVERRIDE)
+#define _NFSD_IRIX_BOGOSITY	128
+#if (MAY_SATTR | MAY_TRUNC | MAY_LOCK | MAY_OWNER_OVERRIDE | _NFSD_IRIX_BOGOSITY) & (MAY_READ | MAY_WRITE | MAY_EXEC)
 # error "please use a different value for MAY_SATTR or MAY_TRUNC or MAY_LOCK or MAY_OWNER_OVERRIDE."
 #endif
 #define MAY_CREATE		(MAY_EXEC|MAY_WRITE)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/notifier.h linux-2.4.20/include/linux/notifier.h
--- linux-2.4.19/include/linux/notifier.h	2001-02-09 22:46:13.000000000 +0000
+++ linux-2.4.20/include/linux/notifier.h	2002-10-29 11:18:32.000000000 +0000
@@ -58,5 +58,7 @@
 #define SYS_HALT	0x0002	/* Notify of system halt */
 #define SYS_POWER_OFF	0x0003	/* Notify of system power off */
 
+#define NETLINK_URELEASE	0x0001	/* Unicast netlink socket released */
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_NOTIFIER_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/nubus.h linux-2.4.20/include/linux/nubus.h
--- linux-2.4.19/include/linux/nubus.h	2001-07-26 21:01:01.000000000 +0000
+++ linux-2.4.20/include/linux/nubus.h	2002-10-29 11:18:34.000000000 +0000
@@ -12,6 +12,10 @@
 #ifndef LINUX_NUBUS_H
 #define LINUX_NUBUS_H
 
+#ifdef __KERNEL__
+#include <asm/nubus.h>
+#endif
+
 enum nubus_category {
 	NUBUS_CAT_BOARD          = 0x0001,
 	NUBUS_CAT_DISPLAY        = 0x0003,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/nvram.h linux-2.4.20/include/linux/nvram.h
--- linux-2.4.19/include/linux/nvram.h	1999-10-29 17:58:00.000000000 +0000
+++ linux-2.4.20/include/linux/nvram.h	2002-10-29 11:18:36.000000000 +0000
@@ -4,14 +4,24 @@
 #include <linux/ioctl.h>
 
 /* /dev/nvram ioctls */
-#define NVRAM_INIT		_IO('p', 0x40) /* initialize NVRAM and set checksum */
-#define	NVRAM_SETCKS	_IO('p', 0x41) /* recalculate checksum */
+#define NVRAM_INIT	_IO('p', 0x40) /* initialize NVRAM and set checksum */
+#define NVRAM_SETCKS	_IO('p', 0x41) /* recalculate checksum */
+
+/* for all current systems, this is where NVRAM starts */
+#define NVRAM_FIRST_BYTE    14
+/* all these functions expect an NVRAM offset, not an absolute */
+#define NVRAM_OFFSET(x)   ((x)-NVRAM_FIRST_BYTE)
 
 #ifdef __KERNEL__
-extern unsigned char nvram_read_byte( int i );
-extern void nvram_write_byte( unsigned char c, int i );
-extern int nvram_check_checksum( void );
-extern void nvram_set_checksum( void );
+/* __foo is foo without grabbing the rtc_lock - get it yourself */
+extern unsigned char __nvram_read_byte(int i);
+extern unsigned char nvram_read_byte(int i);
+extern void __nvram_write_byte(unsigned char c, int i);
+extern void nvram_write_byte(unsigned char c, int i);
+extern int __nvram_check_checksum(void);
+extern int nvram_check_checksum(void);
+extern void __nvram_set_checksum(void);
+extern void nvram_set_checksum(void);
 #endif
 
 #endif  /* _LINUX_NVRAM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/pagemap.h linux-2.4.20/include/linux/pagemap.h
--- linux-2.4.19/include/linux/pagemap.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.20/include/linux/pagemap.h	2002-10-29 11:18:31.000000000 +0000
@@ -97,7 +97,15 @@
 		___wait_on_page(page);
 }
 
-extern struct page * grab_cache_page (struct address_space *, unsigned long);
+/*
+ * Returns locked page at given index in given cache, creating it if needed.
+ */
+static inline struct page *grab_cache_page(struct address_space *mapping, unsigned long index)
+{
+	return find_or_create_page(mapping, index, mapping->gfp_mask);
+}
+
+
 extern struct page * grab_cache_page_nowait (struct address_space *, unsigned long);
 
 typedef int filler_t(void *, struct page*);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/parport.h linux-2.4.20/include/linux/parport.h
--- linux-2.4.19/include/linux/parport.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/parport.h	2002-10-29 11:18:38.000000000 +0000
@@ -544,7 +544,7 @@
 extern void inc_parport_count(void);
 
 /* If PC hardware is the only type supported, we can optimise a bit.  */
-#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !(defined(CONFIG_USB_USS720) || defined(CONFIG_USB_USS720_MODULE)) && !(defined(CONFIG_PARPORT_SUNBPP) || defined(CONFIG_PARPORT_SUNBPP_MODULE)) && !defined(CONFIG_PARPORT_OTHER)
+#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !(defined(CONFIG_USB_USS720) || defined(CONFIG_USB_USS720_MODULE)) && !(defined(CONFIG_PARPORT_SUNBPP) || defined(CONFIG_PARPORT_SUNBPP_MODULE)) && !(defined(CONFIG_PARPORT_GSC) || defined(CONFIG_PARPORT_GSC_MODULE)) && !defined(CONFIG_PARPORT_OTHER)
 
 #undef PARPORT_NEED_GENERIC_OPS
 #include <linux/parport_pc.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/pci.h linux-2.4.20/include/linux/pci.h
--- linux-2.4.19/include/linux/pci.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/pci.h	2002-10-29 11:18:40.000000000 +0000
@@ -382,6 +382,9 @@
 	int		ro;		/* ISAPnP: read only */
 	unsigned short	regs;		/* ISAPnP: supported registers */
 
+	/* These fields are used by common fixups */
+	unsigned short	transparent:1;	/* Transparent PCI bridge */
+
 	int (*prepare)(struct pci_dev *dev);	/* ISAPnP hooks */
 	int (*activate)(struct pci_dev *dev);
 	int (*deactivate)(struct pci_dev *dev);
@@ -436,6 +439,7 @@
 extern struct list_head pci_root_buses;	/* list of all known PCI buses */
 extern struct list_head pci_devices;	/* list of all devices */
 
+extern struct proc_dir_entry *proc_bus_pci_dir;
 /*
  * Error values that may be returned by PCI functions.
  */
@@ -460,9 +464,9 @@
 
 struct pbus_set_ranges_data
 {
-	int found_vga;
 	unsigned long io_start, io_end;
 	unsigned long mem_start, mem_end;
+	unsigned long prefetch_start, prefetch_end;
 };
 
 struct pci_device_id {
@@ -493,11 +497,12 @@
 
 void pcibios_init(void);
 void pcibios_fixup_bus(struct pci_bus *);
-int pcibios_enable_device(struct pci_dev *);
+int pcibios_enable_device(struct pci_dev *, int mask);
 char *pcibios_setup (char *str);
 
 /* Used only when drivers/pci/setup.c is used */
-void pcibios_align_resource(void *, struct resource *, unsigned long);
+void pcibios_align_resource(void *, struct resource *,
+			    unsigned long, unsigned long);
 void pcibios_update_resource(struct pci_dev *, struct resource *,
 			     struct resource *, int);
 void pcibios_update_irq(struct pci_dev *, int irq);
@@ -559,6 +564,7 @@
 int pci_write_config_dword(struct pci_dev *dev, int where, u32 val);
 
 int pci_enable_device(struct pci_dev *dev);
+int pci_enable_device_bars(struct pci_dev *dev, int mask);
 void pci_disable_device(struct pci_dev *dev);
 void pci_set_master(struct pci_dev *dev);
 #define HAVE_PCI_SET_MWI
@@ -580,13 +586,15 @@
 int pci_claim_resource(struct pci_dev *, int);
 void pci_assign_unassigned_resources(void);
 void pdev_enable_device(struct pci_dev *);
-void pdev_sort_resources(struct pci_dev *, struct resource_list *, u32);
+void pdev_sort_resources(struct pci_dev *, struct resource_list *);
 unsigned long pci_bridge_check_io(struct pci_dev *);
 void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
 		    int (*)(struct pci_dev *, u8, u8));
-#define HAVE_PCI_REQ_REGIONS
+#define HAVE_PCI_REQ_REGIONS	2
 int pci_request_regions(struct pci_dev *, char *);
 void pci_release_regions(struct pci_dev *);
+int pci_request_region(struct pci_dev *, int, char *);
+void pci_release_region(struct pci_dev *, int);
 
 /* New-style probing supporting hot-pluggable devices */
 int pci_register_driver(struct pci_driver *);
@@ -648,6 +656,7 @@
 { return NULL; }
 
 static inline void pci_set_master(struct pci_dev *dev) { }
+static inline int pci_enable_device_bars(struct pci_dev *dev, int mask) { return -EBUSY; }
 static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; }
 static inline void pci_disable_device(struct pci_dev *dev) { }
 static inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/pci_gameport.h linux-2.4.20/include/linux/pci_gameport.h
--- linux-2.4.19/include/linux/pci_gameport.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/pci_gameport.h	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,39 @@
+#ifndef __LINUX_PCI_GAMEPORT_H
+#define __LINUX_PCI_GAMEPORT_H
+
+/*
+ *	Public interfaces for attaching a PCI gameport directly to the
+ *	soundcard when it shares the same PCI ident
+ */
+ 
+#define PCIGAME_4DWAVE		0
+#define PCIGAME_VORTEX		1
+#define PCIGAME_VORTEX2		2
+
+
+struct pcigame_data {
+	int gcr;	/* Gameport control register */
+	int legacy;	/* Legacy port location */
+	int axes;	/* Axes start */
+	int axsize;	/* Axis field size */
+	int axmax;	/* Axis field max value */
+	int adcmode;	/* Value to enable ADC mode in GCR */
+};
+
+struct pcigame {
+	struct gameport gameport;
+	struct pci_dev *dev;
+        unsigned char *base;
+	struct pcigame_data *data;
+};
+
+
+#if defined(CONFIG_INPUT_PCIGAME) || defined(CONFIG_INPUT_PCIGAME_MODULE)
+extern struct pcigame *pcigame_attach(struct pci_dev *dev, int type);
+extern void pcigame_detach(struct pcigame *game);
+#else
+#define pcigame_attach(a,b)	NULL
+#define pcigame_detach(a)
+#endif
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/pci_ids.h linux-2.4.20/include/linux/pci_ids.h
--- linux-2.4.19/include/linux/pci_ids.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/pci_ids.h	2002-10-29 11:18:39.000000000 +0000
@@ -392,6 +392,8 @@
 #define PCI_DEVICE_ID_AMD_VIPER_7443	0x7443
 #define PCI_DEVICE_ID_AMD_VIPER_7448	0x7448
 #define PCI_DEVICE_ID_AMD_VIPER_7449	0x7449
+#define PCI_DEVICE_ID_AMD_8111_IDE     0x7469
+#define PCI_DEVICE_ID_AMD_8111_AC97    0x746d
 
 #define PCI_VENDOR_ID_TRIDENT		0x1023
 #define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX	0x2000
@@ -475,6 +477,7 @@
 #define PCI_DEVICE_ID_SI_635		0x0635
 #define PCI_DEVICE_ID_SI_640		0x0640
 #define PCI_DEVICE_ID_SI_645		0x0645
+#define PCI_DEVICE_ID_SI_646        0x0646
 #define PCI_DEVICE_ID_SI_650		0x0650
 #define PCI_DEVICE_ID_SI_730		0x0730
 #define PCI_DEVICE_ID_SI_630_VGA	0x6300
@@ -509,6 +512,8 @@
 #define PCI_DEVICE_ID_HP_DIVA1		0x1049
 #define PCI_DEVICE_ID_HP_DIVA2		0x104A
 #define PCI_DEVICE_ID_HP_SP2_0		0x104B
+#define PCI_DEVICE_ID_HP_REO_SBA	0x10f0
+#define PCI_DEVICE_ID_HP_REO_IOC	0x10f1
 #define PCI_DEVICE_ID_HP_ZX1_SBA	0x1229
 #define PCI_DEVICE_ID_HP_ZX1_IOC	0x122a
 #define PCI_DEVICE_ID_HP_ZX1_LBA	0x122e
@@ -596,6 +601,7 @@
 #define PCI_VENDOR_ID_MOTOROLA_OOPS	0x1507
 #define PCI_DEVICE_ID_MOTOROLA_MPC105	0x0001
 #define PCI_DEVICE_ID_MOTOROLA_MPC106	0x0002
+#define PCI_DEVICE_ID_MOTOROLA_MPC107	0x0004
 #define PCI_DEVICE_ID_MOTOROLA_RAVEN	0x4801
 #define PCI_DEVICE_ID_MOTOROLA_FALCON	0x4802
 #define PCI_DEVICE_ID_MOTOROLA_HAWK	0x4803
@@ -811,6 +817,7 @@
 #define PCI_DEVICE_ID_AL_M1523		0x1523
 #define PCI_DEVICE_ID_AL_M1531		0x1531
 #define PCI_DEVICE_ID_AL_M1533		0x1533
+#define PCI_DEVICE_ID_AL_M1535 		0x1535
 #define PCI_DEVICE_ID_AL_M1541		0x1541
 #define PCI_DEVICE_ID_AL_M1621          0x1621
 #define PCI_DEVICE_ID_AL_M1631          0x1631
@@ -912,6 +919,7 @@
 #define PCI_DEVICE_ID_REALTEK_8029	0x8029
 #define PCI_DEVICE_ID_REALTEK_8129	0x8129
 #define PCI_DEVICE_ID_REALTEK_8139	0x8139
+#define PCI_DEVICE_ID_REALTEK_8169	0x8169
 
 #define PCI_VENDOR_ID_XILINX		0x10ee
 #define PCI_DEVICE_ID_TURBOPAM		0x4020
@@ -1056,6 +1064,7 @@
 #define PCI_DEVICE_ID_EICON_DIVA20PRO_U	0xe003
 #define PCI_DEVICE_ID_EICON_DIVA20_U	0xe004
 #define PCI_DEVICE_ID_EICON_DIVA201	0xe005
+#define PCI_DEVICE_ID_EICON_DIVA202	0xe00b
 #define PCI_DEVICE_ID_EICON_MAESTRA	0xe010
 #define PCI_DEVICE_ID_EICON_MAESTRAQ	0xe012
 #define PCI_DEVICE_ID_EICON_MAESTRAQ_U	0xe013
@@ -1531,6 +1540,7 @@
 #define PCI_DEVICE_ID_TIGON3_5701	0x1645
 #define PCI_DEVICE_ID_TIGON3_5702	0x1646
 #define PCI_DEVICE_ID_TIGON3_5703	0x1647
+#define PCI_DEVICE_ID_TIGON3_5704	0x1648
 #define PCI_DEVICE_ID_TIGON3_5702FE	0x164d
 #define PCI_DEVICE_ID_TIGON3_5702X	0x16a6
 #define PCI_DEVICE_ID_TIGON3_5703X	0x16a7
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/pkt_sched.h linux-2.4.20/include/linux/pkt_sched.h
--- linux-2.4.19/include/linux/pkt_sched.h	2000-02-28 02:45:10.000000000 +0000
+++ linux-2.4.20/include/linux/pkt_sched.h	2002-10-29 11:18:49.000000000 +0000
@@ -248,6 +248,48 @@
        __u8            grio;
 };
 
+/* HTB section */
+#define TC_HTB_NUMPRIO		8
+#define TC_HTB_MAXDEPTH		8
+#define TC_HTB_PROTOVER		3 /* the same as HTB and TC's major */
+
+struct tc_htb_opt
+{
+	struct tc_ratespec 	rate;
+	struct tc_ratespec 	ceil;
+	__u32	buffer;
+	__u32	cbuffer;
+	__u32	quantum;
+	__u32	level;		/* out only */
+	__u32	prio;
+};
+struct tc_htb_glob
+{
+	__u32 version;		/* to match HTB/TC */
+    	__u32 rate2quantum;	/* bps->quantum divisor */
+    	__u32 defcls;		/* default class number */
+	__u32 debug;		/* debug flags */
+
+	/* stats */
+	__u32 direct_pkts; /* count of non shapped packets */
+};
+enum
+{
+	TCA_HTB_UNSPEC,
+	TCA_HTB_PARMS,
+	TCA_HTB_INIT,
+	TCA_HTB_CTAB,
+	TCA_HTB_RTAB,
+};
+struct tc_htb_xstats
+{
+	__u32 lends;
+	__u32 borrows;
+	__u32 giants;	/* too big packets (rate will not be accurate) */
+	__u32 tokens;
+	__u32 ctokens;
+};
+
 /* CBQ section */
 
 #define TC_CBQ_MAXPRIO		8
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/raid/md_compatible.h linux-2.4.20/include/linux/raid/md_compatible.h
--- linux-2.4.19/include/linux/raid/md_compatible.h	2001-11-22 19:48:07.000000000 +0000
+++ linux-2.4.20/include/linux/raid/md_compatible.h	2002-10-29 11:18:36.000000000 +0000
@@ -34,7 +34,7 @@
 	return test_bit(X86_FEATURE_MMX,  &boot_cpu_data.x86_capability);
 }
 #else
-#define md_cpu_has_mmx(x)	(0)
+#define md_cpu_has_mmx()       (0)
 #endif
 
 /* 002 */
@@ -99,7 +99,6 @@
 #define md_test_and_clear_bit test_and_clear_bit
 
 /* 018 */
-#define md_atomic_read atomic_read
 #define md_atomic_set atomic_set
 
 /* 019 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/raid/md_k.h linux-2.4.20/include/linux/raid/md_k.h
--- linux-2.4.19/include/linux/raid/md_k.h	2001-11-26 13:29:17.000000000 +0000
+++ linux-2.4.20/include/linux/raid/md_k.h	2002-10-29 11:18:32.000000000 +0000
@@ -59,7 +59,7 @@
 typedef struct mdk_rdev_s mdk_rdev_t;
 
 #if (MINORBITS != 8)
-#error MD doesnt handle bigger kdev yet
+#error MD does not handle bigger kdev yet
 #endif
 
 #define MAX_MD_DEVS  (1<<MINORBITS)	/* Max number of md dev */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/reiserfs_fs.h linux-2.4.20/include/linux/reiserfs_fs.h
--- linux-2.4.19/include/linux/reiserfs_fs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/reiserfs_fs.h	2002-10-29 11:18:36.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details
+ * Copyright 1996-2002 Hans Reiser, see reiserfs/README for licensing and copyright details
  */
 
 				/* this file has an amazingly stupid
@@ -55,7 +55,8 @@
 #define USE_INODE_GENERATION_COUNTER
 
 #define REISERFS_PREALLOCATE
-#define PREALLOCATION_SIZE 8
+#define DISPLACE_NEW_PACKING_LOCALITIES
+#define PREALLOCATION_SIZE 9
 
 /* n must be power of 2 */
 #define _ROUND_UP(x,n) (((x)+(n)-1u) & ~((n)-1u))
@@ -75,9 +76,9 @@
 /** always check a condition and panic if it's false. */
 #define RASSERT( cond, format, args... )					\
 if( !( cond ) ) 								\
-  reiserfs_panic( 0, "reiserfs[%i]: assertion " #cond " failed at "		\
-		  __FILE__ ":%i:" __FUNCTION__ ": " format "\n",		\
-		  in_interrupt() ? -1 : current -> pid, __LINE__ , ##args )
+  reiserfs_panic( 0, "reiserfs[%i]: assertion " #cond " failed at "	\
+		  __FILE__ ":%i:%s: " format "\n",		\
+		  in_interrupt() ? -1 : current -> pid, __LINE__ , __FUNCTION__ , ##args )
 
 #if defined( CONFIG_REISERFS_CHECK )
 #define RFALSE( cond, format, args... ) RASSERT( !( cond ), format, ##args )
@@ -184,7 +185,7 @@
    time cost for a 4 block file and saves an amount of space that is
    less significant as a percentage of space, or so goes the hypothesis.
    -Hans */
-#define STORE_TAIL_IN_UNFM(n_file_size,n_tail_size,n_block_size) \
+#define STORE_TAIL_IN_UNFM_S1(n_file_size,n_tail_size,n_block_size) \
 (\
   (!(n_tail_size)) || \
   (((n_tail_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) || \
@@ -197,6 +198,18 @@
      ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) ) \
 )
 
+/* Another strategy for tails, this one means only create a tail if all the
+   file would fit into one DIRECT item.
+   Primary intention for this one is to increase performance by decreasing
+   seeking.
+*/   
+#define STORE_TAIL_IN_UNFM_S2(n_file_size,n_tail_size,n_block_size) \
+(\
+  (!(n_tail_size)) || \
+  (((n_file_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) ) \
+)
+
+
 
 /*
  * values for s_state field
@@ -953,9 +966,7 @@
 #define B_I_E_NAME(bh,ih,entry_num) ((char *)(bh->b_data + ih_location(ih) + deh_location(B_I_DEH(bh,ih)+(entry_num))))
 
 // two entries per block (at least)
-//#define REISERFS_MAX_NAME_LEN(block_size) 
-//((block_size - BLKH_SIZE - IH_SIZE - DEH_SIZE * 2) / 2)
-#define REISERFS_MAX_NAME_LEN(block_size) 255
+#define REISERFS_MAX_NAME(block_size) 255
 
 
 /* this structure is used for operations on directory entries. It is
@@ -1325,6 +1336,10 @@
 
   int fs_gen;                  /* saved value of `reiserfs_generation' counter
 			          see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+  struct key  key;	      /* key pointer, to pass to block allocator or
+				 another low-level subsystem */
+#endif
 } ;
 
 /* These are modes of balancing */
@@ -1530,6 +1545,8 @@
 /* After several hours of tedious analysis, the following hash
  * function won.  Do not mess with it... -DaveM
  */
+/* The two definitions below were borrowed from fs/buffer.c file of Linux kernel
+ * sources and are not licensed by Namesys to its non-GPL license customers */
 #define _jhashfn(dev,block)	\
 	((((dev)<<(JBH_HASH_SHIFT - 6)) ^ ((dev)<<(JBH_HASH_SHIFT - 9))) ^ \
 	 (((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12))))
@@ -1558,7 +1575,7 @@
 int push_journal_writer(char *w) ;
 int pop_journal_writer(int windex) ;
 int journal_transaction_should_end(struct reiserfs_transaction_handle *, int) ;
-int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev, unsigned long bl, int size, int searchall, unsigned long *next) ;
+int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev, int bmap_nr, int bit_nr, int size, int searchall, unsigned int *next) ;
 int journal_begin(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
 struct super_block *reiserfs_get_super(kdev_t dev) ;
 void flush_async_commits(struct super_block *p_s_sb) ;
@@ -1576,7 +1593,7 @@
 
 				/* why is this kerplunked right here? */
 static inline int reiserfs_buffer_prepared(const struct buffer_head *bh) {
-  if (bh && test_bit(BH_JPrepared, ( struct buffer_head * ) &bh->b_state))
+  if (bh && test_bit(BH_JPrepared, &( (struct buffer_head *)bh)->b_state))
     return 1 ;
   else
     return 0 ;
@@ -1585,7 +1602,7 @@
 /* buffer was journaled, waiting to get to disk */
 static inline int buffer_journal_dirty(const struct buffer_head *bh) {
   if (bh)
-    return test_bit(BH_JDirty_wait, ( struct buffer_head * ) &bh->b_state) ;
+    return test_bit(BH_JDirty_wait, &( (struct buffer_head *)bh)->b_state) ;
   else
     return 0 ;
 }
@@ -1706,8 +1723,8 @@
 #define file_size(inode) ((inode)->i_size)
 #define tail_size(inode) (file_size (inode) & (block_size (inode) - 1))
 
-#define tail_has_to_be_packed(inode) (!dont_have_tails ((inode)->i_sb) &&\
-!STORE_TAIL_IN_UNFM(file_size (inode), tail_size(inode), block_size (inode)))
+#define tail_has_to_be_packed(inode) (have_large_tails ((inode)->i_sb)?\
+!STORE_TAIL_IN_UNFM_S1(file_size (inode), tail_size(inode), block_size (inode)):have_small_tails ((inode)->i_sb)?!STORE_TAIL_IN_UNFM_S2(file_size (inode), tail_size(inode), block_size (inode)):0 )
 
 void padd_item (char * item, int total_length, int length);
 
@@ -1733,7 +1750,7 @@
 
 
 struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th, 
-				   const struct inode * dir, int mode, 
+				   struct inode * dir, int mode, 
 				   const char * symname, int item_len,
 				   struct dentry *dentry, struct inode *inode, int * err);
 int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode);
@@ -1909,22 +1926,88 @@
 struct buffer_head * get_FEB (struct tree_balance *);
 
 /* bitmap.c */
+
+/* structure contains hints for block allocator, and it is a container for
+ * arguments, such as node, search path, transaction_handle, etc. */
+ struct __reiserfs_blocknr_hint {
+     struct inode * inode;		/* inode passed to allocator, if we allocate unf. nodes */
+     long block;			/* file offset, in blocks */
+     struct key key;
+     struct path * path;		/* search path, used by allocator to deternine search_start by
+					 * various ways */
+     struct reiserfs_transaction_handle * th; /* transaction handle is needed to log super blocks and
+					       * bitmap blocks changes  */
+     b_blocknr_t beg, end;
+     b_blocknr_t search_start;		/* a field used to transfer search start value (block number)
+					 * between different block allocator procedures
+					 * (determine_search_start() and others) */
+    int prealloc_size;			/* is set in determine_prealloc_size() function, used by underlayed
+					 * function that do actual allocation */
+
+    int formatted_node:1;		/* the allocator uses different polices for getting disk space for
+					 * formatted/unformatted blocks with/without preallocation */
+    int preallocate:1;
+};
+
+typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t;
+
+int reiserfs_parse_alloc_options (struct super_block *, char *);
 int is_reusable (struct super_block * s, unsigned long block, int bit_value);
 void reiserfs_free_block (struct reiserfs_transaction_handle *th, unsigned long);
-int reiserfs_new_blocknrs (struct reiserfs_transaction_handle *th,
-			   unsigned long * pblocknrs, unsigned long start_from, int amount_needed);
-int reiserfs_new_unf_blocknrs (struct reiserfs_transaction_handle *th,
-			       unsigned long * pblocknr, unsigned long start_from);
+int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t * , int, int);
+extern inline int reiserfs_new_form_blocknrs (struct tree_balance * tb,
+					      b_blocknr_t *new_blocknrs, int amount_needed)
+{
+    reiserfs_blocknr_hint_t hint = {
+	th:tb->transaction_handle,
+	path: tb->tb_path,
+	inode: NULL,
+	key: tb->key,
+	block: 0,
+	formatted_node:1
+    };
+    return reiserfs_allocate_blocknrs(&hint, new_blocknrs, amount_needed, 0);
+}
+
+extern inline int reiserfs_new_unf_blocknrs (struct reiserfs_transaction_handle *th,
+					     struct inode *inode,
+					     b_blocknr_t *new_blocknrs,
+					     struct path * path, long block)
+{
+    reiserfs_blocknr_hint_t hint = {
+	th: th,
+	path: path,
+	inode: inode,
+	block: block,
+	formatted_node: 0,
+	preallocate: 0
+    };
+    return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
+}
+
 #ifdef REISERFS_PREALLOCATE
-int reiserfs_new_unf_blocknrs2 (struct reiserfs_transaction_handle *th, 
-				struct inode * inode,
-				unsigned long * pblocknr, 
-				unsigned long start_from);
+extern inline int reiserfs_new_unf_blocknrs2(struct reiserfs_transaction_handle *th,
+					     struct inode * inode,
+					     b_blocknr_t *new_blocknrs,
+					     struct path * path, long block)
+{
+    reiserfs_blocknr_hint_t hint = {
+	th: th,
+	path: path,
+	inode: inode,
+	block: block,
+	formatted_node: 0,
+	preallocate: 1
+    };
+    return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
+}
 
 void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th, 
 				struct inode * inode);
 void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th);
 #endif
+void reiserfs_claim_blocks_to_be_allocated( struct super_block *sb, int blocks);
+void reiserfs_release_claimed_blocks( struct super_block *sb, int blocks);
 
 /* hashes.c */
 __u32 keyed_hash (const signed char *msg, int len);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/reiserfs_fs_i.h linux-2.4.20/include/linux/reiserfs_fs_i.h
--- linux-2.4.19/include/linux/reiserfs_fs_i.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/reiserfs_fs_i.h	2002-10-29 11:18:35.000000000 +0000
@@ -1,3 +1,6 @@
+/*
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
+ */
 #ifndef _REISER_FS_I
 #define _REISER_FS_I
 
@@ -41,6 +44,10 @@
     struct list_head i_prealloc_list;	/* per-transaction list of inodes which
 					 * have preallocated blocks */
   
+    int new_packing_locality:1;		/* new_packig_locality is created; new blocks
+					 * for the contents of this directory should be
+					 * displaced */
+
     /* we use these for fsync or O_SYNC to decide which transaction
     ** needs to be committed in order for this inode to be properly
     ** flushed */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/reiserfs_fs_sb.h linux-2.4.20/include/linux/reiserfs_fs_sb.h
--- linux-2.4.19/include/linux/reiserfs_fs_sb.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/reiserfs_fs_sb.h	2002-10-29 11:18:48.000000000 +0000
@@ -1,4 +1,4 @@
-/* Copyright 1996-2000 Hans Reiser, see reiserfs/README for licensing
+/* Copyright 1996-2002 Hans Reiser, see reiserfs/README for licensing
  * and copyright details */
 
 #ifndef _LINUX_REISER_FS_SB
@@ -241,6 +241,8 @@
   unsigned long t_trans_id ;    /* sanity check, equals the current trans id */
   struct super_block *t_super ; /* super for this FS when journal_begin was 
                                    called. saves calls to reiserfs_get_super */
+  int displace_new_blocks:1;	/* if new block allocation occurres, that block
+				   should be displaced from others */
 } ;
 
 /*
@@ -324,6 +326,14 @@
 
 typedef __u32 (*hashf_t) (const signed char *, int);
 
+struct reiserfs_bitmap_info
+{
+    // FIXME: Won't work with block sizes > 8K
+    __u16  first_zero_hint;
+    __u16  free_count;
+    struct buffer_head *bh; /* the actual bitmap */
+};
+
 struct proc_dir_entry;
 
 #if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO )
@@ -368,14 +378,15 @@
   stat_cnt_t need_r_neighbor[ 5 ];
 
   stat_cnt_t free_block;
-  struct __find_forward_stats {
+  struct __scan_bitmap_stats {
 	stat_cnt_t call;
 	stat_cnt_t wait;
 	stat_cnt_t bmap;
 	stat_cnt_t retry;
 	stat_cnt_t in_journal_hint;
-	stat_cnt_t in_journal_out;
-  } find_forward;
+	stat_cnt_t in_journal_nohint;
+	stat_cnt_t stolen;
+  } scan_bitmap;
   struct __journal_stats {
 	stat_cnt_t in_journal;
 	stat_cnt_t in_journal_bitmap;
@@ -405,7 +416,7 @@
 				/* both the comment and the choice of
                                    name are unclear for s_rs -Hans */
     struct reiserfs_super_block * s_rs;           /* Pointer to the super block in the buffer */
-    struct buffer_head ** s_ap_bitmap;       /* array of buffers, holding block bitmap */
+    struct reiserfs_bitmap_info * s_ap_bitmap;
     struct reiserfs_journal *s_journal ;		/* pointer to journal information */
     unsigned short s_mount_state;                 /* reiserfs state (valid, invalid) */
   
@@ -418,6 +429,16 @@
                                    here (currently - NOTAIL, NOLOG,
                                    REPLAYONLY) */
 
+    struct {			/* This is a structure that describes block allocator options */
+	unsigned long bits;	/* Bitfield for enable/disable kind of options */
+	unsigned long large_file_size; /* size started from which we consider file to be a large one(in blocks) */
+	int border;		/* percentage of disk, border takes */
+	int preallocmin;	/* Minimal file size (in blocks) starting from which we do preallocations */
+	int preallocsize;	/* Number of blocks we try to prealloc when file
+				   reaches preallocmin size (in blocks) or
+				   prealloc_list is empty. */
+    } s_alloc_options;
+
 				/* Comment? -Hans */
     wait_queue_head_t s_wait;
 				/* To be obsoleted soon by per buffer seals.. -Hans */
@@ -444,6 +465,7 @@
     int s_is_unlinked_ok;
     reiserfs_proc_info_data_t s_proc_info_data;
     struct proc_dir_entry *procdir;
+    int reserved_blocks; /* amount of blocks reserved for further allocations */
 };
 
 /* Definitions of reiserfs on-disk properties: */
@@ -451,7 +473,8 @@
 #define REISERFS_3_6 1
 
 /* Mount options */
-#define NOTAIL 0  /* -o notail: no tails will be created in a session */
+#define REISERFS_LARGETAIL 0  /* large tails will be created in a session */
+#define REISERFS_SMALLTAIL 17  /* small (for files less than block size) tails will be created in a session */
 #define REPLAYONLY 3 /* replay journal and return 0. Use by fsck */
 #define REISERFS_NOLOG 4      /* -o nolog: turn journalling off */
 #define REISERFS_CONVERT 5    /* -o conv: causes conversion of old
@@ -499,7 +522,8 @@
 #define reiserfs_hashed_relocation(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_HASHED_RELOCATION))
 #define reiserfs_test4(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_TEST4))
 
-#define dont_have_tails(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << NOTAIL))
+#define have_large_tails(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_LARGETAIL))
+#define have_small_tails(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_SMALLTAIL))
 #define replay_only(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REPLAYONLY))
 #define reiserfs_dont_log(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_NOLOG))
 #define reiserfs_attrs(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_ATTRS))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/rtnetlink.h linux-2.4.20/include/linux/rtnetlink.h
--- linux-2.4.19/include/linux/rtnetlink.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/rtnetlink.h	2002-10-29 11:18:35.000000000 +0000
@@ -440,12 +440,14 @@
 #define IFLA_COST IFLA_COST
 	IFLA_PRIORITY,
 #define IFLA_PRIORITY IFLA_PRIORITY
-	IFLA_MASTER
+	IFLA_MASTER,
 #define IFLA_MASTER IFLA_MASTER
+	IFLA_WIRELESS,		/* Wireless Extension event - see wireless.h */
+#define IFLA_WIRELESS IFLA_WIRELESS
 };
 
 
-#define IFLA_MAX IFLA_MASTER
+#define IFLA_MAX IFLA_WIRELESS
 
 #define IFLA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
 #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/rwsem-spinlock.h linux-2.4.20/include/linux/rwsem-spinlock.h
--- linux-2.4.19/include/linux/rwsem-spinlock.h	2001-11-22 19:46:19.000000000 +0000
+++ linux-2.4.20/include/linux/rwsem-spinlock.h	2002-10-29 11:18:48.000000000 +0000
@@ -3,6 +3,8 @@
  * Copyright (c) 2001   David Howells (dhowells@redhat.com).
  * - Derived partially from ideas by Andrea Arcangeli <andrea@suse.de>
  * - Derived also from comments by Linus
+ *
+ * Trylock by Brian Watson (Brian.J.Watson@compaq.com).
  */
 
 #ifndef _LINUX_RWSEM_SPINLOCK_H
@@ -54,7 +56,9 @@
 
 extern void FASTCALL(init_rwsem(struct rw_semaphore *sem));
 extern void FASTCALL(__down_read(struct rw_semaphore *sem));
+extern int FASTCALL(__down_read_trylock(struct rw_semaphore *sem));
 extern void FASTCALL(__down_write(struct rw_semaphore *sem));
+extern int FASTCALL(__down_write_trylock(struct rw_semaphore *sem));
 extern void FASTCALL(__up_read(struct rw_semaphore *sem));
 extern void FASTCALL(__up_write(struct rw_semaphore *sem));
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/rwsem.h linux-2.4.20/include/linux/rwsem.h
--- linux-2.4.19/include/linux/rwsem.h	2001-11-22 19:46:19.000000000 +0000
+++ linux-2.4.20/include/linux/rwsem.h	2002-10-29 11:18:36.000000000 +0000
@@ -2,6 +2,8 @@
  *
  * Written by David Howells (dhowells@redhat.com).
  * Derived from asm-i386/semaphore.h
+ *
+ * Trylock by Brian Watson (Brian.J.Watson@compaq.com).
  */
 
 #ifndef _LINUX_RWSEM_H
@@ -46,6 +48,18 @@
 }
 
 /*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+static inline int down_read_trylock(struct rw_semaphore *sem)
+{
+	int ret;
+	rwsemtrace(sem,"Entering down_read_trylock");
+	ret = __down_read_trylock(sem);
+	rwsemtrace(sem,"Leaving down_read_trylock");
+	return ret;
+}
+
+/*
  * lock for writing
  */
 static inline void down_write(struct rw_semaphore *sem)
@@ -56,6 +70,18 @@
 }
 
 /*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+static inline int down_write_trylock(struct rw_semaphore *sem)
+{
+	int ret;
+	rwsemtrace(sem,"Entering down_write_trylock");
+	ret = __down_write_trylock(sem);
+	rwsemtrace(sem,"Leaving down_write_trylock");
+	return ret;
+}
+
+/*
  * release a read lock
  */
 static inline void up_read(struct rw_semaphore *sem)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/sched.h linux-2.4.20/include/linux/sched.h
--- linux-2.4.19/include/linux/sched.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/sched.h	2002-10-29 11:18:33.000000000 +0000
@@ -458,8 +458,7 @@
 #define MAX_COUNTER	(20*HZ/100)
 #define DEF_NICE	(0)
 
-asmlinkage long sys_sched_yield(void);
-#define yield()	sys_sched_yield()
+extern void yield(void);
 
 /*
  * The default (Linux) execution domain.
@@ -611,7 +610,7 @@
 #define wake_up_interruptible_nr(x, nr)	__wake_up((x),TASK_INTERRUPTIBLE, nr)
 #define wake_up_interruptible_all(x)	__wake_up((x),TASK_INTERRUPTIBLE, 0)
 #define wake_up_interruptible_sync(x)	__wake_up_sync((x),TASK_INTERRUPTIBLE, 1)
-#define wake_up_interruptible_sync_nr(x) __wake_up_sync((x),TASK_INTERRUPTIBLE,  nr)
+#define wake_up_interruptible_sync_nr(x, nr) __wake_up_sync((x),TASK_INTERRUPTIBLE,  nr)
 asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru);
 
 extern int in_group_p(gid_t);
@@ -944,6 +943,17 @@
 	return res;
 }
 
-#endif /* __KERNEL__ */
+static inline int need_resched(void)
+{
+	return (unlikely(current->need_resched));
+}
 
+extern void __cond_resched(void);
+static inline void cond_resched(void)
+{
+	if (need_resched())
+		__cond_resched();
+}
+
+#endif /* __KERNEL__ */
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/serio.h linux-2.4.20/include/linux/serio.h
--- linux-2.4.19/include/linux/serio.h	2001-08-12 18:13:59.000000000 +0000
+++ linux-2.4.20/include/linux/serio.h	2002-10-29 11:18:32.000000000 +0000
@@ -87,6 +87,7 @@
 #define SERIO_XT	0x00000000UL
 #define SERIO_8042	0x01000000UL
 #define SERIO_RS232	0x02000000UL
+#define SERIO_HIL_MLC	0x03000000UL
 
 #define SERIO_PROTO	0xFFUL
 #define SERIO_MSC	0x01
@@ -108,6 +109,7 @@
 #define SERIO_STOWAWAY	0x20
 #define SERIO_H3600	0x21
 #define SERIO_PS2SER	0x22
+#define SERIO_HIL	0x25
 
 #define SERIO_ID	0xff00UL
 #define SERIO_EXTRA	0xff0000UL
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/sisfb.h linux-2.4.20/include/linux/sisfb.h
--- linux-2.4.19/include/linux/sisfb.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.20/include/linux/sisfb.h	2002-10-29 11:18:33.000000000 +0000
@@ -1,6 +1,11 @@
 #ifndef _LINUX_SISFB
 #define _LINUX_SISFB
 
+#include <linux/spinlock.h>
+
+#include <asm/ioctl.h>
+#include <asm/types.h>
+
 #define DISPTYPE_CRT1       0x00000008L
 #define DISPTYPE_CRT2       0x00000004L
 #define DISPTYPE_LCD        0x00000002L
@@ -20,7 +25,7 @@
 #define HASVB_303       	0x40
 #define HASVB_CHRONTEL  	0x80
 
-/* Never change the order of the following enum */
+/* TW: *Never* change the order of the following enum */
 typedef enum _SIS_CHIP_TYPE {
 	SIS_VGALegacy = 0,
 	SIS_300,
@@ -38,6 +43,12 @@
 	MAX_SIS_CHIP
 } SIS_CHIP_TYPE;
 
+typedef enum _VGA_ENGINE {
+	UNKNOWN_VGA = 0,
+	SIS_300_VGA,
+	SIS_315_VGA,
+} VGA_ENGINE;
+
 typedef enum _TVTYPE {
 	TVMODE_NTSC = 0,
 	TVMODE_PAL,
@@ -83,22 +94,25 @@
 };
 
 struct video_info {
-	int    chip_id;
+	int           chip_id;
 	unsigned int  video_size;
 	unsigned long video_base;
-	char  *video_vbase;
+	char  *       video_vbase;
 	unsigned long mmio_base;
-	char  *mmio_vbase; 
+	char  *       mmio_vbase;
 	unsigned long vga_base;
 	unsigned long mtrr;
+	unsigned long heapstart;
 
 	int    video_bpp;
+	int    video_cmap_len;
 	int    video_width;
 	int    video_height;
 	int    video_vwidth;
 	int    video_vheight;
 	int    org_x;
 	int    org_y;
+	int    video_linelength;
 	unsigned int refresh_rate;
 
 	unsigned long disp_state;
@@ -109,9 +123,46 @@
 	SIS_CHIP_TYPE chip;
 	unsigned char revision_id;
 
+        unsigned short DstColor;		/* TW: For 2d acceleration */
+	unsigned long  SiS310_AccelDepth;
+	unsigned long  CommandReg;
+
+	spinlock_t     lockaccel;
+
 	char reserved[256];
 };
 
+
+/* TW: Addtional IOCTL for communication sisfb <> X driver                 */
+/*     If changing this, vgatypes.h must also be changed (for X driver)    */
+
+/* TW: ioctl for identifying and giving some info (esp. memory heap start) */
+#define SISFB_GET_INFO	  _IOR('n',0xF8,sizeof(__u32))
+
+/* TW: Structure argument for SISFB_GET_INFO ioctl  */
+typedef struct _SISFB_INFO sisfb_info, *psisfb_info;
+
+struct _SISFB_INFO {
+	unsigned long sisfb_id;         /* for identifying sisfb */
+#ifndef SISFB_ID
+#define SISFB_ID	  0x53495346    /* Identify myself with 'SISF' */
+#endif
+ 	int    chip_id;			/* PCI ID of detected chip */
+	int    memory;			/* video memory in KB which sisfb manages */
+	int    heapstart;               /* heap start (= sisfb "mem" argument) in KB */
+	unsigned char fbvidmode;	/* current sisfb mode */
+	
+	unsigned char sisfb_version;
+	unsigned char sisfb_revision;
+	unsigned char sisfb_patchlevel;
+
+	unsigned char sisfb_caps;	/* Sisfb capabilities */
+
+	int    sisfb_tqlen;		/* turbo queue length (in KB) */
+
+	char reserved[249]; 		/* for future use */
+};
+
 #ifdef __KERNEL__
 extern struct video_info ivideo;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/slab.h linux-2.4.20/include/linux/slab.h
--- linux-2.4.19/include/linux/slab.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/include/linux/slab.h	2002-10-29 11:18:40.000000000 +0000
@@ -57,6 +57,7 @@
 extern int kmem_cache_shrink(kmem_cache_t *);
 extern void *kmem_cache_alloc(kmem_cache_t *, int);
 extern void kmem_cache_free(kmem_cache_t *, void *);
+extern unsigned int kmem_cache_size(kmem_cache_t *);
 
 extern void *kmalloc(size_t, int);
 extern void kfree(const void *);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/smb_mount.h linux-2.4.20/include/linux/smb_mount.h
--- linux-2.4.19/include/linux/smb_mount.h	2001-02-17 00:03:24.000000000 +0000
+++ linux-2.4.20/include/linux/smb_mount.h	2002-10-29 11:18:31.000000000 +0000
@@ -50,8 +50,8 @@
 
 	u32 flags;
 
-        /* maximum age in jiffies (inode, dentry and dircache) */
-	int ttl;
+	int ttl;	/* maximum age in jiffies (inode, dentry & dircache) */
+	int timeo;	/* timeout for requests */
 
 	struct smb_nls_codepage codepage;
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/som.h linux-2.4.20/include/linux/som.h
--- linux-2.4.19/include/linux/som.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/som.h	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,154 @@
+#ifndef _LINUX_SOM_H
+#define _LINUX_SOM_H
+
+/* File format definition for SOM executables / shared libraries */
+
+/* we need struct timespec */
+#include <linux/time.h>
+
+#define SOM_PAGESIZE 4096
+
+/* this is the SOM header */
+struct som_hdr {
+	short		system_id;		/* magic number - system */
+	short		a_magic;		/* magic number - file type */
+	unsigned int	version_id;		/* versiod ID: YYMMDDHH */
+	struct timespec	file_time;		/* system clock */
+	unsigned int	entry_space;		/* space for entry point */
+	unsigned int	entry_subspace;		/* subspace for entry point */
+	unsigned int	entry_offset;		/* offset of entry point */
+	unsigned int	aux_header_location;	/* auxiliary header location */
+	unsigned int	aux_header_size;	/* auxiliary header size */
+	unsigned int	som_length;		/* length of entire SOM */
+	unsigned int	presumed_dp;		/* compiler's DP value */
+	unsigned int	space_location;		/* space dictionary location */
+	unsigned int	space_total;		/* number of space entries */
+	unsigned int	subspace_location;	/* subspace entries location */
+	unsigned int	subspace_total;		/* number of subspace entries */
+	unsigned int	loader_fixup_location;	/* MPE/iX loader fixup */
+	unsigned int	loader_fixup_total;	/* number of fixup records */
+	unsigned int	space_strings_location;	/* (sub)space names */
+	unsigned int	space_strings_size;	/* size of strings area */
+	unsigned int	init_array_location;	/* reserved */
+	unsigned int	init_array_total;	/* reserved */
+	unsigned int	compiler_location;	/* module dictionary */
+	unsigned int	compiler_total;		/* number of modules */
+	unsigned int	symbol_location;	/* symbol dictionary */
+	unsigned int	symbol_total;		/* number of symbols */
+	unsigned int	fixup_request_location;	/* fixup requests */
+	unsigned int	fixup_request_total;	/* number of fixup requests */
+	unsigned int	symbol_strings_location;/* module & symbol names area */
+	unsigned int	symbol_strings_size;	/* size of strings area */
+	unsigned int	unloadable_sp_location;	/* unloadable spaces location */
+	unsigned int	unloadable_sp_size;	/* size of data */
+	unsigned int	checksum;
+};
+
+/* values for system_id */
+
+#define SOM_SID_PARISC_1_0	0x020b
+#define SOM_SID_PARISC_1_1	0x0210
+#define SOM_SID_PARISC_2_0	0x0214
+
+/* values for a_magic */
+
+#define SOM_LIB_EXEC		0x0104
+#define SOM_RELOCATABLE		0x0106
+#define SOM_EXEC_NONSHARE	0x0107
+#define SOM_EXEC_SHARE		0x0108
+#define SOM_EXEC_DEMAND		0x010B
+#define SOM_LIB_DYN		0x010D
+#define SOM_LIB_SHARE		0x010E
+#define SOM_LIB_RELOC		0x0619
+
+/* values for version_id.  Decimal not hex, yes.  Grr. */
+
+#define SOM_ID_OLD		85082112
+#define SOM_ID_NEW		87102412
+
+struct aux_id {
+	unsigned int	mandatory :1;	/* the linker must understand this */
+	unsigned int	copy	  :1;	/* Must be copied by the linker */
+	unsigned int	append	  :1;	/* Must be merged by the linker */
+	unsigned int	ignore	  :1;	/* Discard section if unknown */
+	unsigned int	reserved  :12;
+	unsigned int	type	  :16;	/* Header type */
+	unsigned int	length;		/* length of _following_ data */
+};
+
+/* The Exec Auxiliary Header.  Called The HP-UX Header within HP apparently. */
+struct som_exec_auxhdr {
+	struct aux_id	som_auxhdr;
+	int		exec_tsize;	/* Text size in bytes */
+	int		exec_tmem;	/* Address to load text at */
+	int		exec_tfile;	/* Location of text in file */
+	int		exec_dsize;	/* Data size in bytes */
+	int		exec_dmem;	/* Address to load data at */
+	int		exec_dfile;	/* Location of data in file */
+	int		exec_bsize;	/* Uninitialised data (bss) */
+	int		exec_entry;	/* Address to start executing */
+	int		exec_flags;	/* loader flags */
+	int		exec_bfill;	/* initialisation value for bss */
+};
+
+/* Oh, the things people do to avoid casts.  Shame it'll break with gcc's
+ * new aliasing rules really.
+ */
+union name_pt {
+	char *		n_name;
+	unsigned int	n_strx;
+};
+
+/* The Space Dictionary */
+struct space_dictionary_record {
+	union name_pt	name;			/* index to subspace name */
+	unsigned int	is_loadable	:1;	/* loadable */
+	unsigned int	is_defined	:1;	/* defined within file */
+	unsigned int	is_private	:1;	/* not sharable */
+	unsigned int	has_intermediate_code :1; /* contains intermediate code */
+	unsigned int	is_tspecific	:1;	/* thread specific */
+	unsigned int	reserved	:11;	/* for future expansion */
+	unsigned int	sort_key	:8;	/* for linker */
+	unsigned int	reserved2	:8;	/* for future expansion */
+
+	int		space_number;		/* index */
+	int		subspace_index;		/* index into subspace dict */
+	unsigned int	subspace_quantity;	/* number of subspaces */
+	int		loader_fix_index;	/* for loader */
+	unsigned int	loader_fix_quantity;	/* for loader */
+	int		init_pointer_index;	/* data pointer array index */
+	unsigned int	init_pointer_quantity;	/* number of data pointers */
+};
+
+/* The Subspace Dictionary */
+struct subspace_dictionary_record {
+	int		space_index;
+	unsigned int	access_control_bits :7;
+	unsigned int	memory_resident	:1;
+	unsigned int	dup_common	:1;
+	unsigned int	is_common	:1;
+	unsigned int	quadrant	:2;
+	unsigned int	initially_frozen :1;
+	unsigned int	is_first	:1;
+	unsigned int	code_only	:1;
+	unsigned int	sort_key	:8;
+	unsigned int	replicate_init	:1;
+	unsigned int	continuation	:1;
+	unsigned int	is_tspecific	:1;
+	unsigned int	is_comdat	:1;
+	unsigned int	reserved	:4;
+
+	int		file_loc_init_value;
+	unsigned int	initialization_length;
+	unsigned int	subspace_start;
+	unsigned int	subspace_length;
+
+	unsigned int	reserved2	:5;
+	unsigned int	alignment	:27;
+
+	union name_pt	name;
+	int		fixup_request_index;
+	unsigned int	fixup_request_quantity;
+};
+
+#endif /* _LINUX_SOM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/sonypi.h linux-2.4.20/include/linux/sonypi.h
--- linux-2.4.19/include/linux/sonypi.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.20/include/linux/sonypi.h	2002-10-29 11:18:37.000000000 +0000
@@ -75,6 +75,7 @@
 #define SONYPI_EVENT_LID_OPENED			37
 #define SONYPI_EVENT_BLUETOOTH_ON		38
 #define SONYPI_EVENT_BLUETOOTH_OFF		39
+#define SONYPI_EVENT_HELP_PRESSED		40
 
 /* get/set brightness */
 #define SONYPI_IOCGBRT		_IOR('v', 0, __u8)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/spinlock.h linux-2.4.20/include/linux/spinlock.h
--- linux-2.4.19/include/linux/spinlock.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/include/linux/spinlock.h	2002-10-29 11:18:40.000000000 +0000
@@ -68,9 +68,10 @@
 /*
  * Your basic spinlocks, allowing only a single CPU anywhere
  *
- * Most gcc versions have a nasty bug with empty initializers.
+ * Some older gcc versions had a nasty bug with empty initializers.
+ * (XXX: could someone please confirm whether egcs 1.1 still has this bug?)
  */
-#if (__GNUC__ > 2)
+#if (__GNUC__ > 2 || __GNUC_MINOR__ > 95)
   typedef struct { } spinlock_t;
   #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
 #else
@@ -131,9 +132,10 @@
  * irq-safe write-lock, but readers can get non-irqsafe
  * read-locks.
  *
- * Most gcc versions have a nasty bug with empty initializers.
+ * Some older gcc versions had a nasty bug with empty initializers.
+ * (XXX: could someone please confirm whether egcs 1.1 still has this bug?)
  */
-#if (__GNUC__ > 2)
+#if (__GNUC__ > 2 || __GNUC_MINOR__ > 91)
   typedef struct { } rwlock_t;
   #define RW_LOCK_UNLOCKED (rwlock_t) { }
 #else
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/sunrpc/clnt.h linux-2.4.20/include/linux/sunrpc/clnt.h
--- linux-2.4.19/include/linux/sunrpc/clnt.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.20/include/linux/sunrpc/clnt.h	2002-10-29 11:18:48.000000000 +0000
@@ -15,6 +15,7 @@
 #include <linux/sunrpc/auth.h>
 #include <linux/sunrpc/stats.h>
 #include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/timer.h>
 
 /*
  * This defines an RPC port mapping
@@ -51,6 +52,8 @@
 	unsigned int		cl_flags;	/* misc client flags */
 	unsigned long		cl_hardmax;	/* max hard timeout */
 
+	struct rpc_rtt		cl_rtt;		/* RTO estimator data */
+
 	struct rpc_portmap	cl_pmap;	/* port mapping */
 	struct rpc_wait_queue	cl_bindwait;	/* waiting on getport() */
 
@@ -90,6 +93,7 @@
 	kxdrproc_t		p_decode;	/* XDR decode function */
 	unsigned int		p_bufsiz;	/* req. buffer size */
 	unsigned int		p_count;	/* call count */
+	unsigned int		p_timer;	/* Which RTT timer to use */
 };
 
 #define rpcproc_bufsiz(clnt, proc)	((clnt)->cl_procinfo[proc].p_bufsiz)
@@ -97,6 +101,7 @@
 #define rpcproc_decode(clnt, proc)	((clnt)->cl_procinfo[proc].p_decode)
 #define rpcproc_name(clnt, proc)	((clnt)->cl_procinfo[proc].p_procname)
 #define rpcproc_count(clnt, proc)	((clnt)->cl_procinfo[proc].p_count)
+#define rpcproc_timer(clnt, proc)	((clnt)->cl_procinfo[proc].p_timer)
 
 #define RPC_CONGESTED(clnt)	(RPCXPRT_CONGESTED((clnt)->cl_xprt))
 #define RPC_PEERADDR(clnt)	(&(clnt)->cl_xprt->addr)
@@ -121,6 +126,7 @@
 void		rpc_restart_call(struct rpc_task *);
 void		rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset);
 void		rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset);
+void		rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
 
 static __inline__
 int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/sunrpc/sched.h linux-2.4.20/include/linux/sunrpc/sched.h
--- linux-2.4.19/include/linux/sunrpc/sched.h	2001-11-22 19:46:19.000000000 +0000
+++ linux-2.4.20/include/linux/sunrpc/sched.h	2002-10-29 11:18:33.000000000 +0000
@@ -34,13 +34,11 @@
  * This is the RPC task struct
  */
 struct rpc_task {
-	struct rpc_task *	tk_prev;	/* wait queue links */
-	struct rpc_task *	tk_next;
+	struct list_head	tk_list;	/* wait queue links */
 #ifdef RPC_DEBUG
 	unsigned long		tk_magic;	/* 0xf00baa */
 #endif
-	struct rpc_task *	tk_next_task;	/* global list of tasks */
-	struct rpc_task *	tk_prev_task;	/* global list of tasks */
+	struct list_head	tk_task;	/* global list of tasks */
 	struct rpc_clnt *	tk_client;	/* RPC client */
 	struct rpc_rqst *	tk_rqstp;	/* RPC request */
 	int			tk_status;	/* result of last operation */
@@ -77,9 +75,7 @@
 	wait_queue_head_t	tk_wait;	/* sync: sleep on this q */
 	unsigned long		tk_timeout;	/* timeout for rpc_sleep() */
 	unsigned short		tk_flags;	/* misc flags */
-	unsigned short		tk_lock;	/* Task lock counter */
-	unsigned char		tk_active   : 1,/* Task has been activated */
-				tk_wakeup   : 1;/* Task waiting to wake up */
+	unsigned char		tk_active   : 1;/* Task has been activated */
 	unsigned long		tk_runstate;	/* Task run status */
 #ifdef RPC_DEBUG
 	unsigned short		tk_pid;		/* debugging aid */
@@ -88,6 +84,20 @@
 #define tk_auth			tk_client->cl_auth
 #define tk_xprt			tk_client->cl_xprt
 
+/* support walking a list of tasks on a wait queue */
+#define	task_for_each(task, pos, head) \
+	list_for_each(pos, head) \
+		if ((task=list_entry(pos, struct rpc_task, tk_list)),1)
+
+#define	task_for_first(task, head) \
+	if (!list_empty(head) &&  \
+	    ((task=list_entry((head)->next, struct rpc_task, tk_list)),1))
+
+/* .. and walking list of all tasks */
+#define	alltask_for_each(task, pos, head) \
+	list_for_each(pos, head) \
+		if ((task=list_entry(pos, struct rpc_task, tk_task)),1)
+
 typedef void			(*rpc_action)(struct rpc_task *);
 
 /*
@@ -133,16 +143,24 @@
  * RPC synchronization objects
  */
 struct rpc_wait_queue {
-	struct rpc_task *	task;
+	struct list_head	tasks;
 #ifdef RPC_DEBUG
 	char *			name;
 #endif
 };
 
 #ifndef RPC_DEBUG
-# define RPC_INIT_WAITQ(name)	((struct rpc_wait_queue) { NULL })
+# define RPC_WAITQ_INIT(var,qname) ((struct rpc_wait_queue) {LIST_HEAD_INIT(var)})
+# define RPC_WAITQ(var,qname)      struct rpc_wait_queue var = RPC_WAITQ_INIT(var.tasks,qname)
+# define INIT_RPC_WAITQ(ptr,qname) do { \
+	INIT_LIST_HEAD(&(ptr)->tasks); \
+	} while(0)
 #else
-# define RPC_INIT_WAITQ(name)	((struct rpc_wait_queue) { NULL, name })
+# define RPC_WAITQ_INIT(var,qname) ((struct rpc_wait_queue) {LIST_HEAD_INIT(var.tasks), qname})
+# define RPC_WAITQ(var,qname)      struct rpc_wait_queue var = RPC_WAITQ_INIT(var,qname)
+# define INIT_RPC_WAITQ(ptr,qname) do { \
+	INIT_LIST_HEAD(&(ptr)->tasks); (ptr)->name = qname; \
+	} while(0)
 #endif
 
 /*
@@ -161,15 +179,11 @@
 void		rpc_remove_wait_queue(struct rpc_task *);
 void		rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *,
 					rpc_action action, rpc_action timer);
-void		rpc_sleep_locked(struct rpc_wait_queue *, struct rpc_task *,
-				 rpc_action action, rpc_action timer);
 void		rpc_add_timer(struct rpc_task *, rpc_action);
 void		rpc_wake_up_task(struct rpc_task *);
 void		rpc_wake_up(struct rpc_wait_queue *);
 struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
 void		rpc_wake_up_status(struct rpc_wait_queue *, int);
-int		__rpc_lock_task(struct rpc_task *);
-void		rpc_unlock_task(struct rpc_task *);
 void		rpc_delay(struct rpc_task *, unsigned long);
 void *		rpc_allocate(unsigned int flags, unsigned int);
 void		rpc_free(void *);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/sunrpc/svc.h linux-2.4.20/include/linux/sunrpc/svc.h
--- linux-2.4.19/include/linux/sunrpc/svc.h	2001-11-22 19:47:20.000000000 +0000
+++ linux-2.4.20/include/linux/sunrpc/svc.h	2002-10-29 11:18:48.000000000 +0000
@@ -26,8 +26,8 @@
  * We currently do not support more than one RPC program per daemon.
  */
 struct svc_serv {
-	struct svc_rqst *	sv_threads;	/* idle server threads */
-	struct svc_sock *	sv_sockets;	/* pending sockets */
+	struct list_head	sv_threads;	/* idle server threads */
+	struct list_head	sv_sockets;	/* pending sockets */
 	struct svc_program *	sv_program;	/* RPC program */
 	struct svc_stat *	sv_stats;	/* RPC statistics */
 	spinlock_t		sv_lock;
@@ -35,7 +35,9 @@
 	unsigned int		sv_bufsz;	/* datagram buffer size */
 	unsigned int		sv_xdrsize;	/* XDR buffer size */
 
-	struct svc_sock *	sv_allsocks;	/* all sockets */
+	struct list_head	sv_permsocks;	/* all permanent sockets */
+	struct list_head	sv_tempsocks;	/* all temporary sockets */
+	int			sv_tmpcnt;	/* count of temporary sockets */
 
 	char *			sv_name;	/* service name */
 };
@@ -88,8 +90,7 @@
  * NOTE: First two items must be prev/next.
  */
 struct svc_rqst {
-	struct svc_rqst *	rq_prev;	/* idle list */
-	struct svc_rqst *	rq_next;
+	struct list_head	rq_list;	/* idle list */
 	struct svc_sock *	rq_sock;	/* socket */
 	struct sockaddr_in	rq_addr;	/* peer address */
 	int			rq_addrlen;
@@ -114,9 +115,17 @@
 	void *			rq_argp;	/* decoded arguments */
 	void *			rq_resp;	/* xdr'd results */
 
+	int			rq_reserved;	/* space on socket outq
+						 * reserved for this request
+						 */
+
 	/* Catering to nfsd */
 	struct svc_client *	rq_client;	/* RPC peer info */
 	struct svc_cacherep *	rq_cacherep;	/* cache info */
+	struct knfsd_fh *	rq_reffh;	/* Referrence filehandle, used to
+						 * determine what device number
+						 * to report (real or virtual)
+						 */
 
 	wait_queue_head_t	rq_wait;	/* synchronozation */
 };
@@ -162,6 +171,7 @@
 	unsigned int		pc_ressize;	/* result struct size */
 	unsigned int		pc_count;	/* call count */
 	unsigned int		pc_cachetype;	/* cache info (NFS) */
+	unsigned int		pc_xdrressize;	/* maximum size of XDR reply */
 };
 
 /*
@@ -179,5 +189,6 @@
 int		   svc_process(struct svc_serv *, struct svc_rqst *);
 int		   svc_register(struct svc_serv *, int, unsigned short);
 void		   svc_wake_up(struct svc_serv *);
+void		   svc_reserve(struct svc_rqst *rqstp, int space);
 
 #endif /* SUNRPC_SVC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/sunrpc/svcsock.h linux-2.4.20/include/linux/sunrpc/svcsock.h
--- linux-2.4.19/include/linux/sunrpc/svcsock.h	2001-11-22 19:47:20.000000000 +0000
+++ linux-2.4.20/include/linux/sunrpc/svcsock.h	2002-10-29 11:18:35.000000000 +0000
@@ -13,38 +13,39 @@
 
 /*
  * RPC server socket.
- * NOTE: First two items must be prev/next.
  */
 struct svc_sock {
-	struct svc_sock *	sk_prev;	/* list of ready sockets */
-	struct svc_sock *	sk_next;
-	struct svc_sock *	sk_list;	/* list of all sockets */
+	struct list_head	sk_ready;	/* list of ready sockets */
+	struct list_head	sk_list;	/* list of all sockets */
 	struct socket *		sk_sock;	/* berkeley socket layer */
 	struct sock *		sk_sk;		/* INET layer */
-	spinlock_t		sk_lock;
 
 	struct svc_serv *	sk_server;	/* service for this socket */
-	unsigned char		sk_inuse;	/* use count */
-	unsigned char		sk_busy;	/* enqueued/receiving */
-	unsigned char		sk_conn;	/* conn pending */
-	unsigned char		sk_close;	/* dead or dying */
-	int			sk_data;	/* data pending */
-	unsigned int		sk_temp : 1,	/* temp socket */
-				sk_qued : 1,	/* on serv->sk_sockets */
-				sk_dead : 1;	/* socket closed */
+	unsigned int		sk_inuse;	/* use count */
+	unsigned long		sk_flags;
+#define	SK_BUSY		0			/* enqueued/receiving */
+#define	SK_CONN		1			/* conn pending */
+#define	SK_CLOSE	2			/* dead or dying */
+#define	SK_DATA		3			/* data pending */
+#define	SK_TEMP		4			/* temp (TCP) socket */
+#define	SK_QUED		5			/* on serv->sk_sockets */
+#define	SK_DEAD		6			/* socket closed */
+#define	SK_CHNGBUF	7			/* need to change snd/rcv buffer sizes */
+
+	int			sk_reserved;	/* space on outq that is reserved */
+
 	int			(*sk_recvfrom)(struct svc_rqst *rqstp);
 	int			(*sk_sendto)(struct svc_rqst *rqstp);
 
 	/* We keep the old state_change and data_ready CB's here */
 	void			(*sk_ostate)(struct sock *);
 	void			(*sk_odata)(struct sock *, int bytes);
+	void			(*sk_owspace)(struct sock *);
 
 	/* private TCP part */
 	int			sk_reclen;	/* length of record */
 	int			sk_tcplen;	/* current read length */
-
-	/* Debugging */
-	struct svc_rqst *	sk_rqstp;
+	time_t			sk_lastrecv;	/* time of last received request */
 };
 
 /*
@@ -55,5 +56,6 @@
 int		svc_recv(struct svc_serv *, struct svc_rqst *, long);
 int		svc_send(struct svc_rqst *);
 void		svc_drop(struct svc_rqst *);
+void		svc_sock_update_bufs(struct svc_serv *serv);
 
 #endif /* SUNRPC_SVCSOCK_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/sunrpc/timer.h linux-2.4.20/include/linux/sunrpc/timer.h
--- linux-2.4.19/include/linux/sunrpc/timer.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/sunrpc/timer.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,41 @@
+/*
+ *  linux/include/linux/sunrpc/timer.h
+ *
+ *  Declarations for the RPC transport timer.
+ *
+ *  Copyright (C) 2002 Trond Myklebust <trond.myklebust@fys.uio.no>
+ */
+
+#ifndef _LINUX_SUNRPC_TIMER_H
+#define _LINUX_SUNRPC_TIMER_H
+
+#include <asm/atomic.h>
+
+struct rpc_rtt {
+	long timeo;		/* default timeout value */
+	long srtt[5];		/* smoothed round trip time << 3 */
+	long sdrtt[5];		/* soothed medium deviation of RTT */
+	atomic_t  ntimeouts;	/* Global count of the number of timeouts */
+};
+
+
+extern void rpc_init_rtt(struct rpc_rtt *rt, long timeo);
+extern void rpc_update_rtt(struct rpc_rtt *rt, int timer, long m);
+extern long rpc_calc_rto(struct rpc_rtt *rt, int timer);
+
+static inline void rpc_inc_timeo(struct rpc_rtt *rt)
+{
+	atomic_inc(&rt->ntimeouts);
+}
+
+static inline void rpc_clear_timeo(struct rpc_rtt *rt)
+{
+	atomic_set(&rt->ntimeouts, 0);
+}
+
+static inline int rpc_ntimeo(struct rpc_rtt *rt)
+{
+	return atomic_read(&rt->ntimeouts);
+}
+
+#endif /* _LINUX_SUNRPC_TIMER_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/sunrpc/types.h linux-2.4.20/include/linux/sunrpc/types.h
--- linux-2.4.19/include/linux/sunrpc/types.h	2001-11-22 19:46:19.000000000 +0000
+++ linux-2.4.20/include/linux/sunrpc/types.h	2002-10-29 11:18:35.000000000 +0000
@@ -12,60 +12,7 @@
 #include <linux/timer.h>
 #include <linux/tqueue.h>
 #include <linux/sunrpc/debug.h>
-
-/*
- * These are the RPC list manipulation primitives used everywhere.
- */
-struct rpc_listitem	{
-	struct rpc_listitem *	prev;
-	struct rpc_listitem *	next;
-};
-
-static __inline__ void
-__rpc_append_list(struct rpc_listitem **q, struct rpc_listitem *item)
-{
-	struct rpc_listitem	*next, *prev;
-
-	if (!(next = *q)) {
-		*q = item->next = item->prev = item;
-	} else {
-		prev = next->prev;
-		prev->next = item;
-		next->prev = item;
-		item->next = next;
-		item->prev = prev;
-	}
-}
-
-static __inline__ void
-__rpc_insert_list(struct rpc_listitem **q, struct rpc_listitem *item)
-{
-	__rpc_append_list(q, item);
-	*q = item;
-}
-
-static __inline__ void
-__rpc_remove_list(struct rpc_listitem **q, struct rpc_listitem *item)
-{
-	struct rpc_listitem	*prev = item->prev,
-				*next = item->next;
-
-	if (item != prev) {
-		next->prev = prev;
-		prev->next = next;
-	} else {
-		next = NULL;
-	}
-	if (*q == item)
-		*q = next;
-}
-
-#define rpc_insert_list(q, i) \
-      __rpc_insert_list((struct rpc_listitem **) q, (struct rpc_listitem *) i)
-#define rpc_append_list(q, i) \
-      __rpc_append_list((struct rpc_listitem **) q, (struct rpc_listitem *) i)
-#define rpc_remove_list(q, i) \
-      __rpc_remove_list((struct rpc_listitem **) q, (struct rpc_listitem *) i)
+#include <linux/list.h>
 
 /*
  * Shorthands
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/sunrpc/xdr.h linux-2.4.20/include/linux/sunrpc/xdr.h
--- linux-2.4.19/include/linux/sunrpc/xdr.h	2001-11-22 19:47:20.000000000 +0000
+++ linux-2.4.20/include/linux/sunrpc/xdr.h	2002-10-29 11:18:51.000000000 +0000
@@ -34,6 +34,31 @@
 typedef int	(*kxdrproc_t)(void *rqstp, u32 *data, void *obj);
 
 /*
+ * Basic structure for transmission/reception of a client XDR message.
+ * Features a header (for a linear buffer containing RPC headers
+ * and the data payload for short messages), and then an array of
+ * pages.
+ * The tail iovec allows you to append data after the page array. Its
+ * main interest is for appending padding to the pages in order to
+ * satisfy the int_32-alignment requirements in RFC1832.
+ *
+ * For the future, we might want to string several of these together
+ * in a list if anybody wants to make use of NFSv4 COMPOUND
+ * operations and/or has a need for scatter/gather involving pages.
+ */
+struct xdr_buf {
+	struct iovec	head[1],	/* RPC header + non-page data */
+			tail[1];	/* Appended after page data */
+
+	struct page **	pages;		/* Array of contiguous pages */
+	unsigned int	page_base,	/* Start of page data */
+			page_len;	/* Length of page data */
+
+	unsigned int	len;		/* Total length of data */
+
+};
+
+/*
  * pre-xdr'ed macros.
  */
 
@@ -67,6 +92,11 @@
 u32 *	xdr_decode_netobj(u32 *p, struct xdr_netobj *);
 u32 *	xdr_decode_netobj_fixed(u32 *p, void *obj, unsigned int len);
 
+void	xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int,
+			 unsigned int);
+void	xdr_inline_pages(struct xdr_buf *, unsigned int,
+			 struct page **, unsigned int, unsigned int);
+
 /*
  * Decode 64bit quantities (NFSv3 support)
  */
@@ -98,6 +128,39 @@
 void xdr_shift_iovec(struct iovec *, int, size_t);
 void xdr_zero_iovec(struct iovec *, int, size_t);
 
+/*
+ * Maximum number of iov's we use.
+ */
+#define MAX_IOVEC	(12)
+
+/*
+ * XDR buffer helper functions
+ */
+extern int xdr_kmap(struct iovec *, struct xdr_buf *, unsigned int);
+extern void xdr_kunmap(struct xdr_buf *, unsigned int);
+extern void xdr_shift_buf(struct xdr_buf *, size_t);
+
+/*
+ * Helper structure for copying from an sk_buff.
+ */
+typedef struct {
+	struct sk_buff	*skb;
+	unsigned int	offset;
+	size_t		count;
+	unsigned int	csum;
+} skb_reader_t;
+
+typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len);
+
+extern void xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int,
+		skb_reader_t *, skb_read_actor_t);
+
+extern int xdr_copy_skb(struct xdr_buf *xdr, unsigned int base,
+		struct sk_buff *skb, unsigned int offset);
+
+extern int xdr_copy_and_csum_skb(struct xdr_buf *xdr, unsigned int base,
+		struct sk_buff *skb, unsigned int offset, unsigned int csum);
+
 #endif /* __KERNEL__ */
 
 #endif /* _SUNRPC_XDR_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/sunrpc/xprt.h linux-2.4.20/include/linux/sunrpc/xprt.h
--- linux-2.4.19/include/linux/sunrpc/xprt.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/include/linux/sunrpc/xprt.h	2002-10-29 11:18:49.000000000 +0000
@@ -13,17 +13,13 @@
 #include <linux/socket.h>
 #include <linux/in.h>
 #include <linux/sunrpc/sched.h>
-
-/*
- * Maximum number of iov's we use.
- */
-#define MAX_IOVEC	10
+#include <linux/sunrpc/xdr.h>
 
 /*
  * The transport code maintains an estimate on the maximum number of out-
  * standing RPC requests, using a smoothed version of the congestion
  * avoidance implemented in 44BSD. This is basically the Van Jacobson
- * slow start algorithm: If a retransmit occurs, the congestion window is
+ * congestion algorithm: If a retransmit occurs, the congestion window is
  * halved; otherwise, it is incremented by 1/cwnd when
  *
  *	-	a reply is received and
@@ -36,15 +32,13 @@
  * Note: on machines with low memory we should probably use a smaller
  * MAXREQS value: At 32 outstanding reqs with 8 megs of RAM, fragment
  * reassembly will frequently run out of memory.
- * Come Linux 2.3, we'll handle fragments directly.
  */
-#define RPC_MAXCONG		16
-#define RPC_MAXREQS		(RPC_MAXCONG + 1)
-#define RPC_CWNDSCALE		256
+#define RPC_MAXCONG		(16)
+#define RPC_MAXREQS		RPC_MAXCONG
+#define RPC_CWNDSCALE		(256)
 #define RPC_MAXCWND		(RPC_MAXCONG * RPC_CWNDSCALE)
 #define RPC_INITCWND		RPC_CWNDSCALE
-#define RPCXPRT_CONGESTED(xprt) \
-	((xprt)->cong >= (xprt)->cwnd)
+#define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd)
 
 /* Default timeout values */
 #define RPC_MAX_UDP_TIMEOUT	(60*HZ)
@@ -70,15 +64,6 @@
 };
 
 /*
- * This is the RPC buffer
- */
-struct rpc_iov {
-	struct iovec		io_vec[MAX_IOVEC];
-	unsigned int		io_nr;
-	unsigned int		io_len;
-};
-
-/*
  * This describes a complete RPC request
  */
 struct rpc_rqst {
@@ -87,8 +72,8 @@
 	 */
 	struct rpc_xprt *	rq_xprt;		/* RPC client */
 	struct rpc_timeout	rq_timeout;		/* timeout parms */
-	struct rpc_iov		rq_snd_buf;		/* send buffer */
-	struct rpc_iov		rq_rcv_buf;		/* recv buffer */
+	struct xdr_buf		rq_snd_buf;		/* send buffer */
+	struct xdr_buf		rq_rcv_buf;		/* recv buffer */
 
 	/*
 	 * This is the private part
@@ -96,7 +81,10 @@
 	struct rpc_task *	rq_task;	/* RPC task data */
 	__u32			rq_xid;		/* request XID */
 	struct rpc_rqst *	rq_next;	/* free list */
-	volatile unsigned char	rq_received : 1;/* receive completed */
+	int			rq_cong;	/* has incremented xprt->cong */
+	int			rq_received;	/* receive completed */
+
+	struct list_head	rq_list;
 
 	/*
 	 * For authentication (e.g. auth_des)
@@ -109,16 +97,14 @@
 	
 	u32			rq_bytes_sent;	/* Bytes we have sent */
 
-#ifdef RPC_PROFILE
-	unsigned long		rq_xtime;	/* when transmitted */
-#endif
+	long			rq_xtime;	/* when transmitted */
+	int			rq_ntimeo;
+	int			rq_nresend;
 };
-#define rq_svec			rq_snd_buf.io_vec
-#define rq_snr			rq_snd_buf.io_nr
-#define rq_slen			rq_snd_buf.io_len
-#define rq_rvec			rq_rcv_buf.io_vec
-#define rq_rnr			rq_rcv_buf.io_nr
-#define rq_rlen			rq_rcv_buf.io_len
+#define rq_svec			rq_snd_buf.head
+#define rq_slen			rq_snd_buf.len
+#define rq_rvec			rq_rcv_buf.head
+#define rq_rlen			rq_rcv_buf.len
 
 #define XPRT_LAST_FRAG		(1 << 0)
 #define XPRT_COPY_RECM		(1 << 1)
@@ -135,9 +121,12 @@
 
 	unsigned long		cong;		/* current congestion */
 	unsigned long		cwnd;		/* congestion window */
-	unsigned long		congtime;	/* hold cwnd until then */
+
+	unsigned int		rcvsize,	/* socket receive buffer size */
+				sndsize;	/* socket send buffer size */
 
 	struct rpc_wait_queue	sending;	/* requests waiting to send */
+	struct rpc_wait_queue	resend;		/* requests waiting to resend */
 	struct rpc_wait_queue	pending;	/* requests in flight */
 	struct rpc_wait_queue	backlog;	/* waiting for slot */
 	struct rpc_rqst *	free;		/* free slots */
@@ -164,6 +153,8 @@
 	spinlock_t		xprt_lock;	/* lock xprt info */
 	struct rpc_task *	snd_task;	/* Task blocked in send */
 
+	struct list_head	recv;
+
 
 	void			(*old_data_ready)(struct sock *, int);
 	void			(*old_state_change)(struct sock *);
@@ -189,13 +180,9 @@
 void			xprt_release(struct rpc_task *);
 void			xprt_reconnect(struct rpc_task *);
 int			xprt_clear_backlog(struct rpc_xprt *);
+void			xprt_sock_setbufsize(struct rpc_xprt *);
 
-#define XPRT_WSPACE	0
-#define XPRT_CONNECT	1
-
-#define xprt_wspace(xp)			(test_bit(XPRT_WSPACE, &(xp)->sockstate))
-#define xprt_test_and_set_wspace(xp)	(test_and_set_bit(XPRT_WSPACE, &(xp)->sockstate))
-#define xprt_clear_wspace(xp)		(clear_bit(XPRT_WSPACE, &(xp)->sockstate))
+#define XPRT_CONNECT	0
 
 #define xprt_connected(xp)		(!(xp)->stream || test_bit(XPRT_CONNECT, &(xp)->sockstate))
 #define xprt_set_connected(xp)		(set_bit(XPRT_CONNECT, &(xp)->sockstate))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/swap.h linux-2.4.20/include/linux/swap.h
--- linux-2.4.19/include/linux/swap.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/include/linux/swap.h	2002-10-29 11:18:32.000000000 +0000
@@ -87,7 +87,6 @@
 extern unsigned int nr_free_buffer_pages(void);
 extern int nr_active_pages;
 extern int nr_inactive_pages;
-extern atomic_t nr_async_pages;
 extern atomic_t page_cache_size;
 extern atomic_t buffermem_pages;
 
@@ -114,7 +113,8 @@
 
 /* linux/mm/vmscan.c */
 extern wait_queue_head_t kswapd_wait;
-extern int FASTCALL(try_to_free_pages(zone_t *, unsigned int, unsigned int));
+extern int FASTCALL(try_to_free_pages_zone(zone_t *, unsigned int));
+extern int FASTCALL(try_to_free_pages(unsigned int));
 
 /* linux/mm/page_io.c */
 extern void rw_swap_page(int, struct page *);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/synclink.h linux-2.4.20/include/linux/synclink.h
--- linux-2.4.19/include/linux/synclink.h	2001-05-01 23:05:00.000000000 +0000
+++ linux-2.4.20/include/linux/synclink.h	2002-10-29 11:18:49.000000000 +0000
@@ -1,17 +1,17 @@
 /*
  * SyncLink Multiprotocol Serial Adapter Driver
  *
- * $Id: synclink.h,v 3.5 2001/03/26 17:04:36 ez Exp $
+ * $Id: synclink.h,v 3.6 2002/02/20 21:58:20 paulkf Exp $
  *
  * Copyright (C) 1998-2000 by Microgate Corporation
- * 
- * Redistribution of this file is permitted under 
+ *
+ * Redistribution of this file is permitted under
  * the terms of the GNU Public License (GPL)
  */
 
 #ifndef _SYNCLINK_H_
 #define _SYNCLINK_H_
-#define SYNCLINK_H_VERSION 3.5
+#define SYNCLINK_H_VERSION 3.6
 
 #define BOOLEAN int
 #define TRUE 1
@@ -128,13 +128,18 @@
 #define MGSL_BUS_TYPE_EISA	2
 #define MGSL_BUS_TYPE_PCI	5
 
+#define MGSL_INTERFACE_DISABLE  0
+#define MGSL_INTERFACE_RS232    1
+#define MGSL_INTERFACE_V35      2
+#define MGSL_INTERFACE_RS422    3
+
 typedef struct _MGSL_PARAMS
 {
 	/* Common */
 
 	unsigned long	mode;		/* Asynchronous or HDLC */
 	unsigned char	loopback;	/* internal loopback mode */
-	
+
 	/* HDLC Only */
 
 	unsigned short	flags;
@@ -247,6 +252,8 @@
  * MGSL_IOCGSTATS	return current statistics
  * MGSL_IOCWAITEVENT	wait for specified event to occur
  * MGSL_LOOPTXDONE	transmit in HDLC LoopMode done
+ * MGSL_IOCSIF          set the serial interface type
+ * MGSL_IOCGIF          get the serial interface type
  */
 #define MGSL_MAGIC_IOC	'm'
 #define MGSL_IOCSPARAMS		_IOW(MGSL_MAGIC_IOC,0,struct _MGSL_PARAMS)
@@ -260,5 +267,7 @@
 #define MGSL_IOCWAITEVENT	_IOWR(MGSL_MAGIC_IOC,8,int)
 #define MGSL_IOCCLRMODCOUNT	_IO(MGSL_MAGIC_IOC,15)
 #define MGSL_IOCLOOPTXDONE	_IO(MGSL_MAGIC_IOC,9)
+#define MGSL_IOCSIF		_IO(MGSL_MAGIC_IOC,10)
+#define MGSL_IOCGIF		_IO(MGSL_MAGIC_IOC,11)
 
 #endif /* _SYNCLINK_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/sysctl.h linux-2.4.20/include/linux/sysctl.h
--- linux-2.4.19/include/linux/sysctl.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/include/linux/sysctl.h	2002-10-29 11:18:31.000000000 +0000
@@ -205,7 +205,8 @@
 	NET_CORE_NO_CONG_THRESH=13,
 	NET_CORE_NO_CONG=14,
 	NET_CORE_LO_CONG=15,
-	NET_CORE_MOD_CONG=16
+	NET_CORE_MOD_CONG=16,
+	NET_CORE_DEV_WEIGHT=17
 };
 
 /* /proc/sys/net/ethernet */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/ticable.h linux-2.4.20/include/linux/ticable.h
--- linux-2.4.19/include/linux/ticable.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/ticable.h	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,42 @@
+/* Hey EMACS -*- linux-c -*-
+ *
+ * tipar/tiser/tiusb - low level driver for handling link cables
+ * designed for Texas Instruments graphing calculators.
+ *
+ * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org>
+ *
+ * Redistribution of this file is permitted under the terms of the GNU
+ * Public License (GPL)
+ */
+
+#ifndef _TICABLE_H 
+#define _TICABLE_H 1
+
+/* Internal default constants for the kernel module */
+#define TIMAXTIME 15      /* 1.5 seconds       */
+#define IO_DELAY  10      /* 10 micro-seconds  */
+
+/* Major & minor number for character devices */
+#define TIPAR_MAJOR  115 /* 0 to 7 */
+#define TIPAR_MINOR    0
+
+#define TISER_MAJOR  115 /* 8 to 15 */
+#define TISER_MINOR    8
+
+#define TIUSB_MAJOR  115  /* 16 to 31 */
+#define TIUSB_MINOR   16
+
+/*
+ * Request values for the 'ioctl' function.
+ */
+#define IOCTL_TIPAR_DELAY     _IOW('p', 0xa8, int) /* set delay   */
+#define IOCTL_TIPAR_TIMEOUT   _IOW('p', 0xa9, int) /* set timeout */
+
+#define IOCTL_TISER_DELAY     _IOW('p', 0xa0, int) /* set delay   */
+#define IOCTL_TISER_TIMEOUT   _IOW('p', 0xa1, int) /* set timeout */
+
+#define IOCTL_TIUSB_TIMEOUT        _IOW('N', 0x20, int) /* set timeout */
+#define IOCTL_TIUSB_RESET_DEVICE   _IOW('N', 0x21, int) /* reset device */
+#define IOCTL_TIUSB_RESET_PIPES    _IOW('N', 0x22, int) /* reset both pipes*/
+
+#endif /* TICABLE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/tty.h linux-2.4.20/include/linux/tty.h
--- linux-2.4.19/include/linux/tty.h	2001-11-22 19:46:19.000000000 +0000
+++ linux-2.4.20/include/linux/tty.h	2002-10-29 11:18:47.000000000 +0000
@@ -57,38 +57,38 @@
  */
 
 struct screen_info {
-	unsigned char  orig_x;			/* 0x00 */
-	unsigned char  orig_y;			/* 0x01 */
-	unsigned short dontuse1;		/* 0x02 -- EXT_MEM_K sits here */
-	unsigned short orig_video_page;		/* 0x04 */
-	unsigned char  orig_video_mode;		/* 0x06 */
-	unsigned char  orig_video_cols;		/* 0x07 */
-	unsigned short unused2;			/* 0x08 */
-	unsigned short orig_video_ega_bx;	/* 0x0a */
-	unsigned short unused3;			/* 0x0c */
-	unsigned char  orig_video_lines;	/* 0x0e */
-	unsigned char  orig_video_isVGA;	/* 0x0f */
-	unsigned short orig_video_points;	/* 0x10 */
+	u8  orig_x;		/* 0x00 */
+	u8  orig_y;		/* 0x01 */
+	u16 dontuse1;		/* 0x02 -- EXT_MEM_K sits here */
+	u16 orig_video_page;	/* 0x04 */
+	u8  orig_video_mode;	/* 0x06 */
+	u8  orig_video_cols;	/* 0x07 */
+	u16 unused2;		/* 0x08 */
+	u16 orig_video_ega_bx;	/* 0x0a */
+	u16 unused3;		/* 0x0c */
+	u8  orig_video_lines;	/* 0x0e */
+	u8  orig_video_isVGA;	/* 0x0f */
+	u16 orig_video_points;	/* 0x10 */
 
 	/* VESA graphic mode -- linear frame buffer */
-	unsigned short lfb_width;		/* 0x12 */
-	unsigned short lfb_height;		/* 0x14 */
-	unsigned short lfb_depth;		/* 0x16 */
-	unsigned long  lfb_base;		/* 0x18 */
-	unsigned long  lfb_size;		/* 0x1c */
-	unsigned short dontuse2, dontuse3;	/* 0x20 -- CL_MAGIC and CL_OFFSET here */
-	unsigned short lfb_linelength;		/* 0x24 */
-	unsigned char  red_size;		/* 0x26 */
-	unsigned char  red_pos;			/* 0x27 */
-	unsigned char  green_size;		/* 0x28 */
-	unsigned char  green_pos;		/* 0x29 */
-	unsigned char  blue_size;		/* 0x2a */
-	unsigned char  blue_pos;		/* 0x2b */
-	unsigned char  rsvd_size;		/* 0x2c */
-	unsigned char  rsvd_pos;		/* 0x2d */
-	unsigned short vesapm_seg;		/* 0x2e */
-	unsigned short vesapm_off;		/* 0x30 */
-	unsigned short pages;			/* 0x32 */
+	u16 lfb_width;				/* 0x12 */
+	u16 lfb_height;		/* 0x14 */
+	u16 lfb_depth;		/* 0x16 */
+	u32 lfb_base;		/* 0x18 */
+	u32 lfb_size;		/* 0x1c */
+	u16 dontuse2, dontuse3;	/* 0x20 -- CL_MAGIC and CL_OFFSET here */
+	u16 lfb_linelength;	/* 0x24 */
+	u8  red_size;		/* 0x26 */
+	u8  red_pos;		/* 0x27 */
+	u8  green_size;		/* 0x28 */
+	u8  green_pos;		/* 0x29 */
+	u8  blue_size;		/* 0x2a */
+	u8  blue_pos;		/* 0x2b */
+	u8  rsvd_size;		/* 0x2c */
+	u8  rsvd_pos;		/* 0x2d */
+	u16 vesapm_seg;		/* 0x2e */
+	u16 vesapm_off;		/* 0x30 */
+	u16 pages;		/* 0x32 */
 						/* 0x34 -- 0x3f reserved for future expansion */
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/usb.h linux-2.4.20/include/linux/usb.h
--- linux-2.4.19/include/linux/usb.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/include/linux/usb.h	2002-10-29 11:18:39.000000000 +0000
@@ -16,8 +16,8 @@
 #define USB_CLASS_MASS_STORAGE		8
 #define USB_CLASS_HUB			9
 #define USB_CLASS_CDC_DATA		0x0a
-#define USB_CLASS_CSCID		0x0b /* chip+ smart card */
-#define USB_CLASS_CONTENT_SEC		0x0d /* content security */
+#define USB_CLASS_CSCID			0x0b	/* chip+ smart card */
+#define USB_CLASS_CONTENT_SEC		0x0d	/* content security */
 #define USB_CLASS_APP_SPEC		0xfe
 #define USB_CLASS_VENDOR_SPEC		0xff
 
@@ -42,8 +42,8 @@
 /*
  * USB directions
  */
-#define USB_DIR_OUT			0
-#define USB_DIR_IN			0x80
+#define USB_DIR_OUT			0		/* to device */
+#define USB_DIR_IN			0x80		/* to host */
 
 /*
  * Descriptor types
@@ -85,23 +85,23 @@
 /*
  * USB Packet IDs (PIDs)
  */
-#define USB_PID_UNDEF_0                        0xf0
-#define USB_PID_OUT                            0xe1
-#define USB_PID_ACK                            0xd2
-#define USB_PID_DATA0                          0xc3
-#define USB_PID_PING                           0xb4	/* USB 2.0 */
-#define USB_PID_SOF                            0xa5
-#define USB_PID_NYET                           0x96	/* USB 2.0 */
-#define USB_PID_DATA2                          0x87	/* USB 2.0 */
-#define USB_PID_SPLIT                          0x78	/* USB 2.0 */
-#define USB_PID_IN                             0x69
-#define USB_PID_NAK                            0x5a
-#define USB_PID_DATA1                          0x4b
-#define USB_PID_PREAMBLE                       0x3c	/* Token mode */
-#define USB_PID_ERR                            0x3c	/* USB 2.0: handshake mode */
-#define USB_PID_SETUP                          0x2d
-#define USB_PID_STALL                          0x1e
-#define USB_PID_MDATA                          0x0f	/* USB 2.0 */
+#define USB_PID_UNDEF_0			0xf0
+#define USB_PID_OUT			0xe1
+#define USB_PID_ACK			0xd2
+#define USB_PID_DATA0			0xc3
+#define USB_PID_PING			0xb4	/* USB 2.0 */
+#define USB_PID_SOF			0xa5
+#define USB_PID_NYET			0x96	/* USB 2.0 */
+#define USB_PID_DATA2			0x87	/* USB 2.0 */
+#define USB_PID_SPLIT			0x78	/* USB 2.0 */
+#define USB_PID_IN			0x69
+#define USB_PID_NAK			0x5a
+#define USB_PID_DATA1			0x4b
+#define USB_PID_PREAMBLE		0x3c	/* Token mode */
+#define USB_PID_ERR			0x3c	/* USB 2.0: handshake mode */
+#define USB_PID_SETUP			0x2d
+#define USB_PID_STALL			0x1e
+#define USB_PID_MDATA			0x0f	/* USB 2.0 */
 
 /*
  * Standard requests
@@ -152,13 +152,26 @@
 		mdelay(ms);
 }
 
-typedef struct {
-	__u8 requesttype;
-	__u8 request;
-	__u16 value;
-	__u16 index;
-	__u16 length;
-} devrequest __attribute__ ((packed));
+/**
+ * struct usb_ctrlrequest - structure used to make USB device control requests easier to create and decode
+ * @bRequestType: matches the USB bmRequestType field
+ * @bRequest: matches the USB bRequest field
+ * @wValue: matches the USB wValue field
+ * @wIndex: matches the USB wIndex field
+ * @wLength: matches the USB wLength field
+ *
+ * This structure is used to send control requests to a USB device.  It matches
+ * the different fields of the USB 2.0 Spec section 9.3, table 9-2.  See the
+ * USB spec for a fuller description of the different fields, and what they are
+ * used for.
+ */
+struct usb_ctrlrequest {
+	__u8 bRequestType;
+	__u8 bRequest;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+} __attribute__ ((packed));
 
 /*
  * USB-status codes:
@@ -174,10 +187,10 @@
 #define USB_ST_BUFFEROVERRUN	(-ECOMM)
 #define USB_ST_BUFFERUNDERRUN	(-ENOSR)
 #define USB_ST_INTERNALERROR	(-EPROTO) 			/* unknown error */
-#define USB_ST_SHORT_PACKET    	(-EREMOTEIO)
-#define USB_ST_PARTIAL_ERROR  	(-EXDEV)			/* ISO transfer only partially completed */
-#define USB_ST_URB_KILLED     	(-ENOENT)			/* URB canceled by user */
-#define USB_ST_URB_PENDING       (-EINPROGRESS)
+#define USB_ST_SHORT_PACKET	(-EREMOTEIO)
+#define USB_ST_PARTIAL_ERROR	(-EXDEV)			/* ISO transfer only partially completed */
+#define USB_ST_URB_KILLED	(-ENOENT)			/* URB canceled by user */
+#define USB_ST_URB_PENDING	(-EINPROGRESS)
 #define USB_ST_REMOVED		(-ENODEV) 			/* device not existing or removed */
 #define USB_ST_TIMEOUT		(-ETIMEDOUT)			/* communication timed out, also in urb->status**/
 #define USB_ST_NOTSUPPORTED	(-ENOSYS)			
@@ -385,7 +398,53 @@
 	unsigned long	driver_info;
 };
 
+/**
+ * struct usb_driver - identifies USB driver to usbcore
+ * @owner: Pointer to the module owner of this driver; initialize
+ *      it using THIS_MODULE.
+ * @name: The driver name should be unique among USB drivers,
+ *      and should normally be the same as the module name.
+ * @probe: Called to see if the driver is willing to manage a particular
+ *      interface on a device.  The probe routine returns a handle that 
+ *      will later be provided to disconnect(), or a null pointer to
+ *      indicate that the driver will not handle the interface.
+ *      The handle is normally a pointer to driver-specific data.
+ *      If the probe() routine needs to access the interface
+ *      structure itself, use usb_ifnum_to_if() to make sure it's using
+ *      the right one.
+ * @disconnect: Called when the interface is no longer accessible, usually
+ *      because its device has been (or is being) disconnected.  The
+ *      handle passed is what was returned by probe(), or was provided
+ *      to usb_driver_claim_interface().
+ * @ioctl: Used for drivers that want to talk to userspace through
+ *      the "usbfs" filesystem.  This lets devices provide ways to
+ *      expose information to user space regardless of where they
+ *      do (or don't) show up otherwise in the filesystem.
+ * @fops: pointer to a fops structure if the driver wants to use the USB
+ *	major number.
+ * @minor: the starting minor number for this driver, if the fops
+ *	pointer is set.
+ * @id_table: USB drivers use ID table to support hotplugging.
+ *      Export this with MODULE_DEVICE_TABLE(usb,...), or use NULL to
+ *      say that probe() should be called for any unclaimed interface.
+ *
+ * USB drivers must provide a name, probe() and disconnect() methods,
+ * and an id_table.  Other driver fields are optional.
+ *
+ * The id_table is used in hotplugging.  It holds a set of descriptors,
+ * and specialized data may be associated with each entry.  That table
+ * is used by both user and kernel mode hotplugging support.
+ * The probe() and disconnect() methods are called in a context where
+ * they can sleep, but they should avoid abusing the privilege.  Most
+ * work to connect to a device should be done when the device is opened,
+ * and undone at the last close.  The disconnect code needs to address
+ * concurrency issues with respect to open() and close() methods, as
+ * well as forcing all pending I/O requests to complete (by unlinking
+ * them as necessary, and blocking until the unlinks complete).
+ */
 struct usb_driver {
+	struct module *owner;
+
 	const char *name;
 
 	void *(*probe)(
@@ -402,18 +461,9 @@
 
 	struct semaphore serialize;
 
-	/* ioctl -- userspace apps can talk to drivers through usbdevfs */
 	int (*ioctl)(struct usb_device *dev, unsigned int code, void *buf);
 
-	/* support for "new-style" USB hotplugging
-	 * binding policy can be driven from user mode too
-	 */
 	const struct usb_device_id *id_table;
-
-	/* suspend before the bus suspends;
-	 * disconnect or resume when the bus resumes */
-	// void (*suspend)(struct usb_device *dev);
-	// void (*resume)(struct usb_device *dev);
 };
 	
 /*----------------------------------------------------------------------------* 
@@ -423,28 +473,31 @@
 /*
  * urb->transfer_flags:
  */
-#define USB_DISABLE_SPD         0x0001
-#define USB_ISO_ASAP            0x0002
-#define USB_ASYNC_UNLINK        0x0008
-#define USB_QUEUE_BULK          0x0010
+#define USB_DISABLE_SPD		0x0001
+#define URB_SHORT_NOT_OK	USB_DISABLE_SPD
+#define USB_ISO_ASAP		0x0002
+#define USB_ASYNC_UNLINK	0x0008
+#define USB_QUEUE_BULK		0x0010
 #define USB_NO_FSBR		0x0020
-#define USB_ZERO_PACKET         0x0040  // Finish bulk OUTs always with zero length packet
+#define USB_ZERO_PACKET		0x0040  // Finish bulk OUTs always with zero length packet
 #define URB_NO_INTERRUPT	0x0080	/* HINT: no non-error interrupt needed */
 					/* ... less overhead for QUEUE_BULK */
 #define USB_TIMEOUT_KILLED	0x1000	// only set by HCD!
 
-typedef struct
+struct iso_packet_descriptor
 {
 	unsigned int offset;
 	unsigned int length;		// expected length
 	unsigned int actual_length;
 	unsigned int status;
-} iso_packet_descriptor_t, *piso_packet_descriptor_t;
+};
+
+#define usb_iso_packet_descriptor	iso_packet_descriptor
 
 struct urb;
 typedef void (*usb_complete_t)(struct urb *);
 
-typedef struct urb
+struct urb
 {
 	spinlock_t lock;		// lock for the URB
 	void *hcpriv;			// private data for host controller
@@ -455,10 +508,12 @@
 	int status;			// returned status
 	unsigned int transfer_flags;	// USB_DISABLE_SPD | USB_ISO_ASAP | etc.
 	void *transfer_buffer;		// associated data buffer
+	dma_addr_t transfer_dma;	// dma addr for transfer_buffer
 	int transfer_buffer_length;	// data buffer length
 	int actual_length;              // actual data buffer length	
 	int bandwidth;			// bandwidth for this transfer request (INT or ISO)
 	unsigned char *setup_packet;	// setup packet (control only)
+	dma_addr_t setup_dma;		// dma addr for setup_packet
 	//
 	int start_frame;		// start frame (iso/irq only)
 	int number_of_packets;		// number of packets in this request (iso)
@@ -469,8 +524,8 @@
 	void *context;			// context for completion routine
 	usb_complete_t complete;	// pointer to completion routine
 	//
-	iso_packet_descriptor_t iso_frame_desc[0];
-} urb_t, *purb_t;
+	struct iso_packet_descriptor iso_frame_desc[0];
+};
 
 /**
  * FILL_CONTROL_URB - macro to help initialize a control urb
@@ -675,11 +730,11 @@
 	urb->start_frame = -1;
 }
 
-purb_t usb_alloc_urb(int iso_packets);
-void usb_free_urb (purb_t purb);
-int usb_submit_urb(purb_t purb);
-int usb_unlink_urb(purb_t purb);
-int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd,  void *data, int len, int timeout);
+struct urb *usb_alloc_urb(int iso_packets);
+void usb_free_urb (struct urb *urb);
+int usb_submit_urb(struct urb *urb);
+int usb_unlink_urb(struct urb *urb);
+int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, struct usb_ctrlrequest *cmd,  void *data, int len, int timeout);
 int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout);
 
 /*-------------------------------------------------------------------*
@@ -710,6 +765,7 @@
  */
 struct usb_bus {
 	int busnum;			/* Bus number (in order of reg) */
+	char *bus_name;			/* stable id (PCI slot_name etc) */
 
 #ifdef DEVNUM_ROUND_ROBIN
 	int devnum_next;                /* Next open device number in round-robin allocation */
@@ -758,7 +814,8 @@
 #define USB_MAXCHILDREN		(16)
 
 struct usb_device {
-	int devnum;			/* Device number on USB bus */
+	int		devnum;		/* Address on USB bus */
+	char		devpath [16];	/* Use in messages: /port/port/... */
 
 	enum {
 		USB_SPEED_UNKNOWN = 0,			/* enumerating */
@@ -833,10 +890,6 @@
 extern void usb_inc_dev_use(struct usb_device *);
 #define usb_dec_dev_use usb_free_dev
 
-extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
-extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc);
-extern void usb_release_bandwidth(struct usb_device *dev, struct urb *urb, int isoc);
-
 extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout);
 
 extern int usb_root_hub_string(int id, int serial, char *type, __u8 *data, int len);
@@ -847,6 +900,42 @@
 
 int usb_get_current_frame_number (struct usb_device *usb_dev);
 
+
+/**
+ * usb_make_path - returns stable device path in the usb tree
+ * @dev: the device whose path is being constructed
+ * @buf: where to put the string
+ * @size: how big is "buf"?
+ *
+ * Returns length of the string (> 0) or negative if size was too small.
+ *
+ * This identifier is intended to be "stable", reflecting physical paths in
+ * hardware such as physical bus addresses for host controllers or ports on
+ * USB hubs.  That makes it stay the same until systems are physically
+ * reconfigured, by re-cabling a tree of USB devices or by moving USB host
+ * controllers.  Adding and removing devices, including virtual root hubs
+ * in host controller driver modules, does not change these path identifers;
+ * neither does rebooting or re-enumerating.  These are more useful identifiers
+ * than changeable ("unstable") ones like bus numbers or device addresses.
+ * (The stability of the id depends on stability of the bus_name associated
+ * with the bus the device uses; that is normally stable.)
+ *
+ * With a partial exception for devices connected to USB 2.0 root hubs, these
+ * identifiers are also predictable.  So long as the device tree isn't changed,
+ * plugging any USB device into a given hub port always gives it the same path.
+ * Because of the use of "companion" controllers, devices connected to ports on
+ * USB 2.0 root hubs (EHCI host controllers) will get one path ID if they are
+ * high speed, and a different one if they are full or low speed.
+ */
+static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size)
+{
+	int actual;
+	actual = snprintf (buf, size, "usb-%s-%s",
+		dev->bus->bus_name, dev->devpath);
+	return (actual >= size) ? -1 : actual;
+}
+
+
 /*
  * Calling this entity a "pipe" is glorifying it. A USB pipe
  * is something embarrassingly simple: it basically consists
@@ -973,26 +1062,6 @@
 	__usb_get_extra_descriptor((ifpoint)->extra,(ifpoint)->extralen,type,(void**)ptr)
 
 /*
- * Some USB bandwidth allocation constants.
- */
-#define BW_HOST_DELAY	1000L		/* nanoseconds */
-#define BW_HUB_LS_SETUP	333L		/* nanoseconds */
-                        /* 4 full-speed bit times (est.) */
-
-#define FRAME_TIME_BITS         12000L		/* frame = 1 millisecond */
-#define FRAME_TIME_MAX_BITS_ALLOC	(90L * FRAME_TIME_BITS / 100L)
-#define FRAME_TIME_USECS	1000L
-#define FRAME_TIME_MAX_USECS_ALLOC	(90L * FRAME_TIME_USECS / 100L)
-
-#define BitTime(bytecount)  (7 * 8 * bytecount / 6)  /* with integer truncation */
-		/* Trying not to use worst-case bit-stuffing
-                   of (7/6 * 8 * bytecount) = 9.33 * bytecount */
-		/* bytecount = data payload byte count */
-
-#define NS_TO_US(ns)	((ns + 500L) / 1000L)
-			/* convert & round nanoseconds to microseconds */
-
-/*
  * Debugging helpers..
  */
 void usb_show_device_descriptor(struct usb_device_descriptor *);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/vmalloc.h linux-2.4.20/include/linux/vmalloc.h
--- linux-2.4.19/include/linux/vmalloc.h	2001-11-22 19:46:20.000000000 +0000
+++ linux-2.4.20/include/linux/vmalloc.h	2002-10-29 11:18:50.000000000 +0000
@@ -5,6 +5,7 @@
 #include <linux/mm.h>
 #include <linux/spinlock.h>
 
+#include <linux/highmem.h>	/* several arch define VMALLOC_END via PKMAP_BASE */
 #include <asm/pgtable.h>
 
 /* bits in vm_struct->flags */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/vt_kern.h linux-2.4.20/include/linux/vt_kern.h
--- linux-2.4.19/include/linux/vt_kern.h	2001-11-22 19:47:07.000000000 +0000
+++ linux-2.4.20/include/linux/vt_kern.h	2002-10-29 11:18:36.000000000 +0000
@@ -90,6 +90,5 @@
 int vt_waitactive(int vt);
 void change_console(unsigned int);
 void reset_vc(unsigned int new_console);
-int vt_waitactive(int vt);
 
 #endif /* _VT_KERN_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/watchdog.h linux-2.4.20/include/linux/watchdog.h
--- linux-2.4.19/include/linux/watchdog.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.20/include/linux/watchdog.h	2002-10-29 11:18:49.000000000 +0000
@@ -38,7 +38,8 @@
 #define	WDIOF_POWERUNDER	0x0010	/* Power bad/power fault */
 #define	WDIOF_CARDRESET		0x0020	/* Card previously reset the CPU */
 #define WDIOF_POWEROVER		0x0040	/* Power over voltage */
-#define WDIOF_SETTIMEOUT	0x0080  /* Set timeout (in seconds) */
+#define WDIOF_SETTIMEOUT	0x0080	/* Set timeout (in seconds) */
+#define WDIOF_MAGICCLOSE	0x0100	/* Supports magic close char */
 #define	WDIOF_KEEPALIVEPING	0x8000	/* Keep alive ping reply */
 
 #define	WDIOS_DISABLECARD	0x0001	/* Turn off the watchdog timer */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/wireless.h linux-2.4.20/include/linux/wireless.h
--- linux-2.4.19/include/linux/wireless.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/include/linux/wireless.h	2002-10-29 11:18:49.000000000 +0000
@@ -1,10 +1,10 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :	13	6.12.01
+ * Version :	14	25.1.02
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
  */
 
 #ifndef _LINUX_WIRELESS_H
@@ -40,7 +40,7 @@
  *	# include/linux/netdevice.h (one place)
  *	# include/linux/proc_fs.h (one place)
  *
- * New driver API (2001 -> onward) :
+ * New driver API (2002 -> onward) :
  * -------------------------------
  * This file is only concerned with the user space API and common definitions.
  * The new driver API is defined and documented in :
@@ -49,6 +49,11 @@
  * Note as well that /proc/net/wireless implementation has now moved in :
  *	# include/linux/wireless.c
  *
+ * Wireless Events (2002 -> onward) :
+ * --------------------------------
+ * Events are defined at the end of this file, and implemented in :
+ *	# include/linux/wireless.c
+ *
  * Other comments :
  * --------------
  * Do not add here things that are redundant with other mechanisms
@@ -75,7 +80,7 @@
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT	13
+#define WIRELESS_EXT	14
 
 /*
  * Changes :
@@ -141,6 +146,13 @@
  *	- Document creation of new driver API.
  *	- Extract union iwreq_data from struct iwreq (for new driver API).
  *	- Rename SIOCSIWNAME as SIOCSIWCOMMIT
+ *
+ * V13 to V14
+ * ----------
+ *	- Wireless Events support : define struct iw_event
+ *	- Define additional specific event numbers
+ *	- Add "addr" and "param" fields in union iwreq_data
+ *	- AP scanning stuff (SIOCSIWSCAN and friends)
  */
 
 /**************************** CONSTANTS ****************************/
@@ -175,6 +187,8 @@
 #define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
 #define SIOCGIWAP	0x8B15		/* get access point MAC addresses */
 #define SIOCGIWAPLIST	0x8B17		/* get list of access point in range */
+#define SIOCSIWSCAN	0x8B18		/* trigger scanning */
+#define SIOCGIWSCAN	0x8B19		/* get scanning results */
 
 /* 802.11 specific support */
 #define SIOCSIWESSID	0x8B1A		/* set ESSID (network name) */
@@ -238,6 +252,15 @@
 #define IW_IS_SET(cmd)	(!((cmd) & 0x1))
 #define IW_IS_GET(cmd)	((cmd) & 0x1)
 
+/* ----------------------- WIRELESS EVENTS ----------------------- */
+/* Those are *NOT* ioctls, do not issue request on them !!! */
+/* Most events use the same identifier as ioctl requests */
+
+#define IWEVTXDROP	0x8C00		/* Packet dropped to excessive retry */
+#define IWEVQUAL	0x8C01		/* Quality part of statistics */
+
+#define IWEVFIRST	0x8C00
+
 /* ------------------------- PRIVATE INFO ------------------------- */
 /*
  * The following is used with SIOCGIWPRIV. It allow a driver to define
@@ -340,6 +363,19 @@
 #define IW_RETRY_MAX		0x0002	/* Value is a maximum */
 #define IW_RETRY_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
 
+/* Scanning request flags */
+#define IW_SCAN_DEFAULT		0x0000	/* Default scan of the driver */
+#define IW_SCAN_ALL_ESSID	0x0001	/* Scan all ESSIDs */
+#define IW_SCAN_THIS_ESSID	0x0002	/* Scan only this ESSID */
+#define IW_SCAN_ALL_FREQ	0x0004	/* Scan all Frequencies */
+#define IW_SCAN_THIS_FREQ	0x0008	/* Scan only this Frequency */
+#define IW_SCAN_ALL_MODE	0x0010	/* Scan all Modes */
+#define IW_SCAN_THIS_MODE	0x0020	/* Scan only this Mode */
+#define IW_SCAN_ALL_RATE	0x0040	/* Scan all Bit-Rates */
+#define IW_SCAN_THIS_RATE	0x0080	/* Scan only this Bit-Rate */
+/* Maximum size of returned data */
+#define IW_SCAN_MAX_DATA	4096	/* In bytes */
+
 /****************************** TYPES ******************************/
 
 /* --------------------------- SUBTYPES --------------------------- */
@@ -466,9 +502,12 @@
 
 	struct iw_point	encoding;	/* Encoding stuff : tokens */
 	struct iw_param	power;		/* PM duration/timeout */
+	struct iw_quality qual;		/* Quality part of statistics */
 
 	struct sockaddr	ap_addr;	/* Access point address */
+	struct sockaddr	addr;		/* Destination address (hw) */
 
+	struct iw_param	param;		/* Other small parameters */
 	struct iw_point	data;		/* Other large parameters */
 };
 
@@ -596,4 +635,35 @@
 	char		name[IFNAMSIZ];	/* Name of the extension */
 };
 
+/* ----------------------- WIRELESS EVENTS ----------------------- */
+/*
+ * Wireless events are carried through the rtnetlink socket to user
+ * space. They are encapsulated in the IFLA_WIRELESS field of
+ * a RTM_NEWLINK message.
+ */
+
+/*
+ * A Wireless Event. Contains basically the same data as the ioctl...
+ */
+struct iw_event
+{
+	__u16		len;			/* Real lenght of this stuff */
+	__u16		cmd;			/* Wireless IOCTL */
+	union iwreq_data	u;		/* IOCTL fixed payload */
+};
+
+/* Size of the Event prefix (including padding and alignement junk) */
+#define IW_EV_LCP_LEN	(sizeof(struct iw_event) - sizeof(union iwreq_data))
+/* Size of the various events */
+#define IW_EV_CHAR_LEN	(IW_EV_LCP_LEN + IFNAMSIZ)
+#define IW_EV_UINT_LEN	(IW_EV_LCP_LEN + sizeof(__u32))
+#define IW_EV_FREQ_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_freq))
+#define IW_EV_POINT_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_point))
+#define IW_EV_PARAM_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_param))
+#define IW_EV_ADDR_LEN	(IW_EV_LCP_LEN + sizeof(struct sockaddr))
+#define IW_EV_QUAL_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_quality))
+
+/* Note : in the case of iw_point, the extra data will come at the
+ * end of the event */
+
 #endif	/* _LINUX_WIRELESS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/xattr.h linux-2.4.20/include/linux/xattr.h
--- linux-2.4.19/include/linux/xattr.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/xattr.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,15 @@
+/*
+  File: linux/xattr.h
+
+  Extended attributes handling.
+
+  Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
+  Copyright (c) 2001-2002 Silicon Graphics, Inc.  All Rights Reserved.
+*/
+#ifndef _LINUX_XATTR_H
+#define _LINUX_XATTR_H
+
+#define XATTR_CREATE	0x1	/* set the value, fail if attr already exists */
+#define XATTR_REPLACE	0x2	/* set the value, fail if attr does not exist */
+
+#endif	/* _LINUX_XATTR_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/zconf.h linux-2.4.20/include/linux/zconf.h
--- linux-2.4.19/include/linux/zconf.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/zconf.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,90 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id$ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+#if defined(__GNUC__) || defined(__386__) || defined(i386)
+#  ifndef __32BIT__
+#    define __32BIT__
+#  endif
+#endif
+
+#if defined(__STDC__) || defined(__cplusplus)
+#  ifndef STDC
+#    define STDC
+#  endif
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  define MAX_MEM_LEVEL 9
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef FAR
+#   define FAR
+#endif
+
+typedef unsigned char  Byte;  /* 8 bits */
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+typedef Byte  FAR Bytef;
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+typedef void FAR *voidpf;
+typedef void     *voidp;
+
+#include <linux/types.h> /* for off_t */
+#include <linux/unistd.h>    /* for SEEK_* and off_t */
+#define z_off_t  off_t
+
+#endif /* _ZCONF_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/zlib.h linux-2.4.20/include/linux/zlib.h
--- linux-2.4.19/include/linux/zlib.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/zlib.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,654 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.1.3, July 9th, 1998
+
+  Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#include <linux/zconf.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.1.3"
+
+/* 
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms will be added later and will have the same
+  stream interface.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio.
+
+     The library does not install any signal handler. The decoder checks
+  the consistency of the compressed data, so the library should never
+  crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    void     *workspace; /* memory allocated for this stream */
+
+    int     data_type;  /* best guess about the data type: ascii or binary */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_PACKET_FLUSH  2
+#define Z_SYNC_FLUSH    3
+#define Z_FULL_FLUSH    4
+#define Z_FINISH        5
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlib_zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+   This check is automatically made by deflateInit and inflateInit.
+ */
+
+ZEXTERN int ZEXPORT zlib_deflate_workspacesize OF((void));
+/*
+   Returns the number of bytes that needs to be allocated for a per-
+   stream workspace.  A pointer to this number of bytes should be
+   returned in stream->workspace before calling zlib_deflateInit().
+*/
+
+/* 
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT zlib_deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce some
+  output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows. deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far. (In particular
+  avail_in is zero after the call if enough output space has been provided
+  before the call.)  Flushing may degrade compression for some compression
+  algorithms and so it should be used only when necessary.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+  the compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out).
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+  
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update data_type if it can make a good guess about
+  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero).
+*/
+
+
+ZEXTERN int ZEXPORT zlib_deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+ZEXTERN int ZEXPORT zlib_inflate_workspacesize OF((void));
+/*
+   Returns the number of bytes that needs to be allocated for a per-
+   stream workspace.  A pointer to this number of bytes should be
+   returned in stream->workspace before calling zlib_inflateInit().
+*/
+
+/* 
+ZEXTERN int ZEXPORT zlib_inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression. The fields
+   next_in, avail_in, and workspace must be initialized before by
+   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+   value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller.  msg is set to null if there is no error
+   message. inflateInit does not perform any decompression apart from reading
+   the zlib header if present: this will be done by inflate().  (So next_in and
+   avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT zlib_inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may some
+  introduce some output latency (reading input without producing any output)
+  except when forced to flush.
+
+  The detailed semantics are as follows. inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
+  output as possible to the output buffer. The flushing behavior of inflate is
+  not specified for values of the flush parameter other than Z_SYNC_FLUSH
+  and Z_FINISH, but the current implementation actually flushes as much output
+  as possible anyway.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster routine
+  may be used for the single inflate() call.
+
+     If a preset dictionary is needed at this point (see inflateSetDictionary
+  below), inflate sets strm-adler to the adler32 checksum of the
+  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise 
+  it sets strm->adler to the adler32 checksum of all output produced
+  so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
+  an error code as described below. At the end of the stream, inflate()
+  checks that its computed adler32 checksum is equal to that saved by the
+  compressor and returns Z_STREAM_END only if the checksum is correct.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect
+  adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
+  (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
+  enough memory, Z_BUF_ERROR if no progress is possible or if there was not
+  enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
+  case, the application may then call inflateSync to look for a good
+  compression block.
+*/
+
+
+ZEXTERN int ZEXPORT zlib_inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*   
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library. Larger values of this parameter result in better
+   compression at the expense of memory usage. The default value is 15 if
+   deflateInit is used instead.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match).  Filtered data consists mostly of small values with a
+   somewhat random distribution. In this case, the compression algorithm is
+   tuned to compress them better. The effect of Z_FILTERED is to force more
+   Huffman coding and less string matching; it is somewhat intermediate
+   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+   the compression ratio but not the correctness of the compressed output even
+   if it is not set appropriately.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+   method). msg is set to null if there is no error message.  deflateInit2 does
+   not perform any compression: this will be done by deflate().
+*/
+                            
+ZEXTERN int ZEXPORT zlib_deflateSetDictionary OF((z_streamp strm,
+						     const Bytef *dictionary,
+						     uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output. This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any
+   call of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size in
+   deflate or deflate2. Thus the strings most likely to be useful should be
+   put at the end of the dictionary, not at the front.
+
+     Upon return of this function, strm->adler is set to the Adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The Adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.)
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort). deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT zlib_deflateCopy OF((z_streamp dest,
+					    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT zlib_deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT zlib_deflateParams OF((z_streamp strm,
+					      int level,
+					      int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different
+   strategy. If the compression level is changed, the input available so far
+   is compressed with the old level (and may be flushed); the new level will
+   take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+/*   
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter. The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library. The default value is 15 if inflateInit is used
+   instead. If a compressed stream with a larger window size is given as
+   input, inflate() will return with the error code Z_DATA_ERROR instead of
+   trying to allocate a larger window.
+
+      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
+   memLevel). msg is set to null if there is no error message.  inflateInit2
+   does not perform any decompression apart from reading the zlib header if
+   present: this will be done by inflate(). (So next_in and avail_in may be
+   modified, but next_out and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT zlib_inflateSetDictionary OF((z_streamp strm,
+						     const Bytef *dictionary,
+						     uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence. This function must be called immediately after a call of inflate
+   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the Adler32 value returned by this call of
+   inflate. The compressor and decompressor must use exactly the same
+   dictionary (see deflateSetDictionary).
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect Adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT zlib_inflateSync OF((z_streamp strm));
+/* 
+    Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT zlib_inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int ZEXPORT zlib_inflateIncomp OF((z_stream *strm));
+/*
+     This function adds the data at next_in (avail_in bytes) to the output
+   history without performing any output.  There must be no pending output,
+   and the decompressor must be expecting to see the start of a block.
+   Calling this function is equivalent to decompressing a stored block
+   containing the data at next_in (except that the data is not output).
+*/
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT zlib_deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT zlib_inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT zlib_deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT zlib_inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+#define zlib_deflateInit(strm, level) \
+        zlib_deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define zlib_inflateInit(strm) \
+        zlib_inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define zlib_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        zlib_deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define zlib_inflateInit2(strm, windowBits) \
+        zlib_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char   * ZEXPORT zlib_zError           OF((int err));
+ZEXTERN int            ZEXPORT zlib_inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT zlib_get_crc_table    OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/zlib_fs.h linux-2.4.20/include/linux/zlib_fs.h
--- linux-2.4.19/include/linux/zlib_fs.h	2001-11-05 21:40:59.000000000 +0000
+++ linux-2.4.20/include/linux/zlib_fs.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,679 +0,0 @@
-/* zlib.h -- interface of the 'zlib' general purpose compression library
-  version 1.1.3, July 9th, 1998
-
-  Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  Jean-loup Gailly        Mark Adler
-  jloup@gzip.org          madler@alumni.caltech.edu
-
-
-  The data format used by the zlib library is described by RFCs (Request for
-  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
-  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
-*/
-
-#ifndef _ZLIB_H
-#define _ZLIB_H
-
-#include "zconf.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define ZLIB_VERSION "1.1.3"
-
-/* 
-     The 'zlib' compression library provides in-memory compression and
-  decompression functions, including integrity checks of the uncompressed
-  data.  This version of the library supports only one compression method
-  (deflation) but other algorithms will be added later and will have the same
-  stream interface.
-
-     Compression can be done in a single step if the buffers are large
-  enough (for example if an input file is mmap'ed), or can be done by
-  repeated calls of the compression function.  In the latter case, the
-  application must provide more input and/or consume the output
-  (providing more output space) before each call.
-
-     The library also supports reading and writing files in gzip (.gz) format
-  with an interface similar to that of stdio.
-
-     The library does not install any signal handler. The decoder checks
-  the consistency of the compressed data, so the library should never
-  crash even in case of corrupted input.
-*/
-
-typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
-typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
-
-struct internal_state;
-
-typedef struct z_stream_s {
-    Bytef    *next_in;  /* next input byte */
-    uInt     avail_in;  /* number of bytes available at next_in */
-    uLong    total_in;  /* total nb of input bytes read so far */
-
-    Bytef    *next_out; /* next output byte should be put there */
-    uInt     avail_out; /* remaining free space at next_out */
-    uLong    total_out; /* total nb of bytes output so far */
-
-    char     *msg;      /* last error message, NULL if no error */
-    struct internal_state FAR *state; /* not visible by applications */
-
-    void     *workspace; /* memory allocated for this stream */
-
-    int     data_type;  /* best guess about the data type: ascii or binary */
-    uLong   adler;      /* adler32 value of the uncompressed data */
-    uLong   reserved;   /* reserved for future use */
-} z_stream;
-
-typedef z_stream FAR *z_streamp;
-
-/*
-   The application must update next_in and avail_in when avail_in has
-   dropped to zero. It must update next_out and avail_out when avail_out
-   has dropped to zero. The application must initialize zalloc, zfree and
-   opaque before calling the init function. All other fields are set by the
-   compression library and must not be updated by the application.
-
-   The opaque value provided by the application will be passed as the first
-   parameter for calls of zalloc and zfree. This can be useful for custom
-   memory management. The compression library attaches no meaning to the
-   opaque value.
-
-   zalloc must return Z_NULL if there is not enough memory for the object.
-   If zlib is used in a multi-threaded application, zalloc and zfree must be
-   thread safe.
-
-   On 16-bit systems, the functions zalloc and zfree must be able to allocate
-   exactly 65536 bytes, but will not be required to allocate more than this
-   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
-   pointers returned by zalloc for objects of exactly 65536 bytes *must*
-   have their offset normalized to zero. The default allocation function
-   provided by this library ensures this (see zutil.c). To reduce memory
-   requirements and avoid any allocation of 64K objects, at the expense of
-   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
-
-   The fields total_in and total_out can be used for statistics or
-   progress reports. After compression, total_in holds the total size of
-   the uncompressed data and may be saved for use in the decompressor
-   (particularly if the decompressor wants to decompress everything in
-   a single step).
-*/
-
-                        /* constants */
-
-#define Z_NO_FLUSH      0
-#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
-#define Z_SYNC_FLUSH    2
-#define Z_FULL_FLUSH    3
-#define Z_FINISH        4
-/* Allowed flush values; see deflate() below for details */
-
-#define Z_OK            0
-#define Z_STREAM_END    1
-#define Z_NEED_DICT     2
-#define Z_ERRNO        (-1)
-#define Z_STREAM_ERROR (-2)
-#define Z_DATA_ERROR   (-3)
-#define Z_MEM_ERROR    (-4)
-#define Z_BUF_ERROR    (-5)
-#define Z_VERSION_ERROR (-6)
-/* Return codes for the compression/decompression functions. Negative
- * values are errors, positive values are used for special but normal events.
- */
-
-#define Z_NO_COMPRESSION         0
-#define Z_BEST_SPEED             1
-#define Z_BEST_COMPRESSION       9
-#define Z_DEFAULT_COMPRESSION  (-1)
-/* compression levels */
-
-#define Z_FILTERED            1
-#define Z_HUFFMAN_ONLY        2
-#define Z_DEFAULT_STRATEGY    0
-/* compression strategy; see deflateInit2() below for details */
-
-#define Z_BINARY   0
-#define Z_ASCII    1
-#define Z_UNKNOWN  2
-/* Possible values of the data_type field */
-
-#define Z_DEFLATED   8
-/* The deflate compression method (the only one supported in this version) */
-
-#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
-
-                        /* basic functions */
-
-ZEXTERN const char * ZEXPORT zlib_fs_zlibVersion OF((void));
-/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
-   If the first character differs, the library code actually used is
-   not compatible with the zlib.h header file used by the application.
-   This check is automatically made by deflateInit and inflateInit.
- */
-
-/* 
-ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
-
-     Initializes the internal stream state for compression. The fields
-   zalloc, zfree and opaque must be initialized before by the caller.
-   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
-   use default allocation functions.
-
-     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
-   1 gives best speed, 9 gives best compression, 0 gives no compression at
-   all (the input data is simply copied a block at a time).
-   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
-   compression (currently equivalent to level 6).
-
-     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
-   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
-   with the version assumed by the caller (ZLIB_VERSION).
-   msg is set to null if there is no error message.  deflateInit does not
-   perform any compression: this will be done by deflate().
-*/
-
-
-ZEXTERN int ZEXPORT zlib_fs_deflate OF((z_streamp strm, int flush));
-/*
-    deflate compresses as much data as possible, and stops when the input
-  buffer becomes empty or the output buffer becomes full. It may introduce some
-  output latency (reading input without producing any output) except when
-  forced to flush.
-
-    The detailed semantics are as follows. deflate performs one or both of the
-  following actions:
-
-  - Compress more input starting at next_in and update next_in and avail_in
-    accordingly. If not all input can be processed (because there is not
-    enough room in the output buffer), next_in and avail_in are updated and
-    processing will resume at this point for the next call of deflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly. This action is forced if the parameter flush is non zero.
-    Forcing flush frequently degrades the compression ratio, so this parameter
-    should be set only when necessary (in interactive applications).
-    Some output may be provided even if flush is not set.
-
-  Before the call of deflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating avail_in or avail_out accordingly; avail_out
-  should never be zero before the call. The application can consume the
-  compressed output when it wants, for example when the output buffer is full
-  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
-  and with zero avail_out, it must be called again after making room in the
-  output buffer because there might be more output pending.
-
-    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
-  flushed to the output buffer and the output is aligned on a byte boundary, so
-  that the decompressor can get all input data available so far. (In particular
-  avail_in is zero after the call if enough output space has been provided
-  before the call.)  Flushing may degrade compression for some compression
-  algorithms and so it should be used only when necessary.
-
-    If flush is set to Z_FULL_FLUSH, all output is flushed as with
-  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
-  restart from this point if previous compressed data has been damaged or if
-  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
-  the compression.
-
-    If deflate returns with avail_out == 0, this function must be called again
-  with the same value of the flush parameter and more output space (updated
-  avail_out), until the flush is complete (deflate returns with non-zero
-  avail_out).
-
-    If the parameter flush is set to Z_FINISH, pending input is processed,
-  pending output is flushed and deflate returns with Z_STREAM_END if there
-  was enough output space; if deflate returns with Z_OK, this function must be
-  called again with Z_FINISH and more output space (updated avail_out) but no
-  more input data, until it returns with Z_STREAM_END or an error. After
-  deflate has returned Z_STREAM_END, the only possible operations on the
-  stream are deflateReset or deflateEnd.
-  
-    Z_FINISH can be used immediately after deflateInit if all the compression
-  is to be done in a single step. In this case, avail_out must be at least
-  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
-  Z_STREAM_END, then it must be called again as described above.
-
-    deflate() sets strm->adler to the adler32 checksum of all input read
-  so far (that is, total_in bytes).
-
-    deflate() may update data_type if it can make a good guess about
-  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
-  binary. This field is only for information purposes and does not affect
-  the compression algorithm in any manner.
-
-    deflate() returns Z_OK if some progress has been made (more input
-  processed or more output produced), Z_STREAM_END if all input has been
-  consumed and all output has been produced (only when flush is set to
-  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
-  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
-  (for example avail_in or avail_out was zero).
-*/
-
-
-ZEXTERN int ZEXPORT zlib_fs_deflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
-   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
-   prematurely (some input or output was discarded). In the error case,
-   msg may be set but then points to a static string (which must not be
-   deallocated).
-*/
-
-
-ZEXTERN int ZEXPORT zlib_fs_inflate_workspacesize OF((void));
-/*
-   Returns the number of bytes that needs to be allocated for a per-
-   stream workspace.  A pointer to this number of bytes should be
-   returned in stream->workspace before calling zlib_fs_inflateInit().
-*/
-
-/* 
-ZEXTERN int ZEXPORT zlib_fs_inflateInit OF((z_streamp strm));
-
-     Initializes the internal stream state for decompression. The fields
-   next_in, avail_in, and workspace must be initialized before by
-   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
-   value depends on the compression method), inflateInit determines the
-   compression method from the zlib header and allocates all data structures
-   accordingly; otherwise the allocation will be deferred to the first call of
-   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
-   use default allocation functions.
-
-     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
-   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
-   version assumed by the caller.  msg is set to null if there is no error
-   message. inflateInit does not perform any decompression apart from reading
-   the zlib header if present: this will be done by inflate().  (So next_in and
-   avail_in may be modified, but next_out and avail_out are unchanged.)
-*/
-
-
-ZEXTERN int ZEXPORT zlib_fs_inflate OF((z_streamp strm, int flush));
-/*
-    inflate decompresses as much data as possible, and stops when the input
-  buffer becomes empty or the output buffer becomes full. It may some
-  introduce some output latency (reading input without producing any output)
-  except when forced to flush.
-
-  The detailed semantics are as follows. inflate performs one or both of the
-  following actions:
-
-  - Decompress more input starting at next_in and update next_in and avail_in
-    accordingly. If not all input can be processed (because there is not
-    enough room in the output buffer), next_in is updated and processing
-    will resume at this point for the next call of inflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly.  inflate() provides as much output as possible, until there
-    is no more input data or no more space in the output buffer (see below
-    about the flush parameter).
-
-  Before the call of inflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating the next_* and avail_* values accordingly.
-  The application can consume the uncompressed output when it wants, for
-  example when the output buffer is full (avail_out == 0), or after each
-  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
-  must be called again after making room in the output buffer because there
-  might be more output pending.
-
-    If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
-  output as possible to the output buffer. The flushing behavior of inflate is
-  not specified for values of the flush parameter other than Z_SYNC_FLUSH
-  and Z_FINISH, but the current implementation actually flushes as much output
-  as possible anyway.
-
-    inflate() should normally be called until it returns Z_STREAM_END or an
-  error. However if all decompression is to be performed in a single step
-  (a single call of inflate), the parameter flush should be set to
-  Z_FINISH. In this case all pending input is processed and all pending
-  output is flushed; avail_out must be large enough to hold all the
-  uncompressed data. (The size of the uncompressed data may have been saved
-  by the compressor for this purpose.) The next operation on this stream must
-  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
-  is never required, but can be used to inform inflate that a faster routine
-  may be used for the single inflate() call.
-
-     If a preset dictionary is needed at this point (see inflateSetDictionary
-  below), inflate sets strm-adler to the adler32 checksum of the
-  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise 
-  it sets strm->adler to the adler32 checksum of all output produced
-  so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
-  an error code as described below. At the end of the stream, inflate()
-  checks that its computed adler32 checksum is equal to that saved by the
-  compressor and returns Z_STREAM_END only if the checksum is correct.
-
-    inflate() returns Z_OK if some progress has been made (more input processed
-  or more output produced), Z_STREAM_END if the end of the compressed data has
-  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
-  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
-  corrupted (input stream not conforming to the zlib format or incorrect
-  adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
-  (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
-  enough memory, Z_BUF_ERROR if no progress is possible or if there was not
-  enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
-  case, the application may then call inflateSync to look for a good
-  compression block.
-*/
-
-
-ZEXTERN int ZEXPORT zlib_fs_inflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
-   was inconsistent. In the error case, msg may be set but then points to a
-   static string (which must not be deallocated).
-*/
-
-                        /* Advanced functions */
-
-/*
-    The following functions are needed only in some special applications.
-*/
-
-/*   
-ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
-                                     int  level,
-                                     int  method,
-                                     int  windowBits,
-                                     int  memLevel,
-                                     int  strategy));
-
-     This is another version of deflateInit with more compression options. The
-   fields next_in, zalloc, zfree and opaque must be initialized before by
-   the caller.
-
-     The method parameter is the compression method. It must be Z_DEFLATED in
-   this version of the library.
-
-     The windowBits parameter is the base two logarithm of the window size
-   (the size of the history buffer).  It should be in the range 8..15 for this
-   version of the library. Larger values of this parameter result in better
-   compression at the expense of memory usage. The default value is 15 if
-   deflateInit is used instead.
-
-     The memLevel parameter specifies how much memory should be allocated
-   for the internal compression state. memLevel=1 uses minimum memory but
-   is slow and reduces compression ratio; memLevel=9 uses maximum memory
-   for optimal speed. The default value is 8. See zconf.h for total memory
-   usage as a function of windowBits and memLevel.
-
-     The strategy parameter is used to tune the compression algorithm. Use the
-   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
-   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
-   string match).  Filtered data consists mostly of small values with a
-   somewhat random distribution. In this case, the compression algorithm is
-   tuned to compress them better. The effect of Z_FILTERED is to force more
-   Huffman coding and less string matching; it is somewhat intermediate
-   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
-   the compression ratio but not the correctness of the compressed output even
-   if it is not set appropriately.
-
-      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
-   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
-   method). msg is set to null if there is no error message.  deflateInit2 does
-   not perform any compression: this will be done by deflate().
-*/
-                            
-ZEXTERN int ZEXPORT zlib_fs_deflateSetDictionary OF((z_streamp strm,
-						     const Bytef *dictionary,
-						     uInt  dictLength));
-/*
-     Initializes the compression dictionary from the given byte sequence
-   without producing any compressed output. This function must be called
-   immediately after deflateInit, deflateInit2 or deflateReset, before any
-   call of deflate. The compressor and decompressor must use exactly the same
-   dictionary (see inflateSetDictionary).
-
-     The dictionary should consist of strings (byte sequences) that are likely
-   to be encountered later in the data to be compressed, with the most commonly
-   used strings preferably put towards the end of the dictionary. Using a
-   dictionary is most useful when the data to be compressed is short and can be
-   predicted with good accuracy; the data can then be compressed better than
-   with the default empty dictionary.
-
-     Depending on the size of the compression data structures selected by
-   deflateInit or deflateInit2, a part of the dictionary may in effect be
-   discarded, for example if the dictionary is larger than the window size in
-   deflate or deflate2. Thus the strings most likely to be useful should be
-   put at the end of the dictionary, not at the front.
-
-     Upon return of this function, strm->adler is set to the Adler32 value
-   of the dictionary; the decompressor may later use this value to determine
-   which dictionary has been used by the compressor. (The Adler32 value
-   applies to the whole dictionary even if only a subset of the dictionary is
-   actually used by the compressor.)
-
-     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state is
-   inconsistent (for example if deflate has already been called for this stream
-   or if the compression method is bsort). deflateSetDictionary does not
-   perform any compression: this will be done by deflate().
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_deflateCopy OF((z_streamp dest,
-					    z_streamp source));
-/*
-     Sets the destination stream as a complete copy of the source stream.
-
-     This function can be useful when several compression strategies will be
-   tried, for example when there are several ways of pre-processing the input
-   data with a filter. The streams that will be discarded should then be freed
-   by calling deflateEnd.  Note that deflateCopy duplicates the internal
-   compression state which can be quite large, so this strategy is slow and
-   can consume lots of memory.
-
-     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
-   (such as zalloc being NULL). msg is left unchanged in both source and
-   destination.
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_deflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to deflateEnd followed by deflateInit,
-   but does not free and reallocate all the internal compression state.
-   The stream will keep the same compression level and any other attributes
-   that may have been set by deflateInit2.
-
-      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent (such as zalloc or state being NULL).
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_deflateParams OF((z_streamp strm,
-					      int level,
-					      int strategy));
-/*
-     Dynamically update the compression level and compression strategy.  The
-   interpretation of level and strategy is as in deflateInit2.  This can be
-   used to switch between compression and straight copy of the input data, or
-   to switch to a different kind of input data requiring a different
-   strategy. If the compression level is changed, the input available so far
-   is compressed with the old level (and may be flushed); the new level will
-   take effect only at the next call of deflate().
-
-     Before the call of deflateParams, the stream state must be set as for
-   a call of deflate(), since the currently available input may have to
-   be compressed and flushed. In particular, strm->avail_out must be non-zero.
-
-     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
-   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
-   if strm->avail_out was zero.
-*/
-
-/*   
-ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
-                                     int  windowBits));
-
-     This is another version of inflateInit with an extra parameter. The
-   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
-   before by the caller.
-
-     The windowBits parameter is the base two logarithm of the maximum window
-   size (the size of the history buffer).  It should be in the range 8..15 for
-   this version of the library. The default value is 15 if inflateInit is used
-   instead. If a compressed stream with a larger window size is given as
-   input, inflate() will return with the error code Z_DATA_ERROR instead of
-   trying to allocate a larger window.
-
-      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
-   memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
-   memLevel). msg is set to null if there is no error message.  inflateInit2
-   does not perform any decompression apart from reading the zlib header if
-   present: this will be done by inflate(). (So next_in and avail_in may be
-   modified, but next_out and avail_out are unchanged.)
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_inflateSetDictionary OF((z_streamp strm,
-						     const Bytef *dictionary,
-						     uInt  dictLength));
-/*
-     Initializes the decompression dictionary from the given uncompressed byte
-   sequence. This function must be called immediately after a call of inflate
-   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
-   can be determined from the Adler32 value returned by this call of
-   inflate. The compressor and decompressor must use exactly the same
-   dictionary (see deflateSetDictionary).
-
-     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state is
-   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
-   expected one (incorrect Adler32 value). inflateSetDictionary does not
-   perform any decompression: this will be done by subsequent calls of
-   inflate().
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_inflateSync OF((z_streamp strm));
-/* 
-    Skips invalid compressed data until a full flush point (see above the
-  description of deflate with Z_FULL_FLUSH) can be found, or until all
-  available input is skipped. No output is provided.
-
-    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
-  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
-  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
-  case, the application may save the current current value of total_in which
-  indicates where valid compressed data was found. In the error case, the
-  application may repeatedly call inflateSync, providing more input each time,
-  until success or end of the input data.
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_inflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to inflateEnd followed by inflateInit,
-   but does not free and reallocate all the internal decompression state.
-   The stream will keep attributes that may have been set by inflateInit2.
-
-      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent (such as zalloc or state being NULL).
-*/
-
-                        /* checksum functions */
-
-/*
-     These functions are not related to compression but are exported
-   anyway because they might be useful in applications using the
-   compression library.
-*/
-
-ZEXTERN uLong ZEXPORT zlib_fs_adler32 OF((uLong adler, const Bytef *buf, uInt len));
-
-/*
-     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
-   return the updated checksum. If buf is NULL, this function returns
-   the required initial value for the checksum.
-   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
-   much faster. Usage example:
-
-     uLong adler = adler32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       adler = adler32(adler, buffer, length);
-     }
-     if (adler != original_adler) error();
-*/
-
-ZEXTERN uLong ZEXPORT zlib_fs_crc32   OF((uLong crc, const Bytef *buf, uInt len));
-/*
-     Update a running crc with the bytes buf[0..len-1] and return the updated
-   crc. If buf is NULL, this function returns the required initial value
-   for the crc. Pre- and post-conditioning (one's complement) is performed
-   within this function so it shouldn't be done by the application.
-   Usage example:
-
-     uLong crc = crc32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       crc = crc32(crc, buffer, length);
-     }
-     if (crc != original_crc) error();
-*/
-
-
-                        /* various hacks, don't look :) */
-
-/* deflateInit and inflateInit are macros to allow checking the zlib version
- * and the compiler's view of z_stream:
- */
-ZEXTERN int ZEXPORT zlib_fs_deflateInit_ OF((z_streamp strm, int level,
-                                     const char *version, int stream_size));
-ZEXTERN int ZEXPORT zlib_fs_inflateInit_ OF((z_streamp strm,
-                                     const char *version, int stream_size));
-ZEXTERN int ZEXPORT zlib_fs_deflateInit2_ OF((z_streamp strm, int  level, int  method,
-                                      int windowBits, int memLevel,
-                                      int strategy, const char *version,
-                                      int stream_size));
-ZEXTERN int ZEXPORT zlib_fs_inflateInit2_ OF((z_streamp strm, int  windowBits,
-                                      const char *version, int stream_size));
-#define zlib_fs_deflateInit(strm, level) \
-        zlib_fs_deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
-#define zlib_fs_inflateInit(strm) \
-        zlib_fs_inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
-#define zlib_fs_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
-        zlib_fs_deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
-                      (strategy), ZLIB_VERSION, sizeof(z_stream))
-#define zlib_fs_inflateInit2(strm, windowBits) \
-        zlib_fs_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
-
-
-#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
-    struct internal_state {int dummy;}; /* hack for buggy compilers */
-#endif
-
-ZEXTERN const char   * ZEXPORT zlib_fs_zError           OF((int err));
-ZEXTERN int            ZEXPORT zlib_fs_inflateSyncPoint OF((z_streamp z));
-ZEXTERN const uLongf * ZEXPORT zlib_fs_get_crc_table    OF((void));
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ZLIB_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/linux/zutil.h linux-2.4.20/include/linux/zutil.h
--- linux-2.4.19/include/linux/zutil.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/linux/zutil.h	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,126 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: zutil.h,v 1.1 2000/01/01 03:32:23 davem Exp $ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include <linux/zlib.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+        /* common constants */
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+        /* Common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+         /* functions */
+
+typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
+				       uInt len));
+
+
+                        /* checksum functions */
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* ========================================================================= */
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+static inline uLong zlib_adler32(uLong adler,
+				 const Bytef *buf,
+				 uInt len)
+{
+    unsigned long s1 = adler & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == Z_NULL) return 1L;
+
+    while (len > 0) {
+        k = len < NMAX ? len : NMAX;
+        len -= k;
+        while (k >= 16) {
+            DO16(buf);
+	    buf += 16;
+            k -= 16;
+        }
+        if (k != 0) do {
+            s1 += *buf++;
+	    s2 += s1;
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 16) | s1;
+}
+
+#endif /* _Z_UTIL_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/net/bluetooth/hci.h linux-2.4.20/include/net/bluetooth/hci.h
--- linux-2.4.19/include/net/bluetooth/hci.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/include/net/bluetooth/hci.h	2002-10-29 11:18:37.000000000 +0000
@@ -23,7 +23,7 @@
 */
 
 /*
- *  $Id: hci.h,v 1.4 2002/04/18 22:26:15 maxk Exp $
+ *  $Id: hci.h,v 1.5 2002/06/27 17:29:30 maxk Exp $
  */
 
 #ifndef __HCI_H
@@ -113,10 +113,10 @@
 #define ACL_PTYPE_MASK	(~SCO_PTYPE_MASK)
 
 /* ACL flags */
-#define ACL_CONT		0x0001
-#define ACL_START		0x0002
-#define ACL_ACTIVE_BCAST	0x0010
-#define ACL_PICO_BCAST		0x0020
+#define ACL_CONT		0x01
+#define ACL_START		0x02
+#define ACL_ACTIVE_BCAST	0x04
+#define ACL_PICO_BCAST		0x08
 
 /* Baseband links */
 #define SCO_LINK	0x00
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/net/bluetooth/hci_core.h linux-2.4.20/include/net/bluetooth/hci_core.h
--- linux-2.4.19/include/net/bluetooth/hci_core.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/include/net/bluetooth/hci_core.h	2002-10-29 11:18:48.000000000 +0000
@@ -23,7 +23,7 @@
 */
 
 /* 
- * $Id: hci_core.h,v 1.4 2002/06/25 22:04:43 maxk Exp $ 
+ * $Id: hci_core.h,v 1.5 2002/06/27 04:56:30 maxk Exp $ 
  */
 
 #ifndef __HCI_CORE_H
@@ -149,7 +149,7 @@
 
 extern struct hci_proto *hci_proto[];
 extern struct list_head hdev_list;
-extern spinlock_t hdev_list_lock;
+extern rwlock_t hdev_list_lock;
 
 /* ----- Inquiry cache ----- */
 #define INQUIRY_CACHE_AGE_MAX   (HZ*30)   // 30 seconds
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/net/dsfield.h linux-2.4.20/include/net/dsfield.h
--- linux-2.4.19/include/net/dsfield.h	2000-12-11 21:30:40.000000000 +0000
+++ linux-2.4.20/include/net/dsfield.h	2002-10-29 11:18:49.000000000 +0000
@@ -51,29 +51,4 @@
 }
 
 
-#if 0 /* put this later into asm-i386 or such ... */
-
-static inline void ip_change_dsfield(struct iphdr *iph,__u16 dsfield)
-{
-	__u16 check;
-
-	__asm__ __volatile__("
-		movw	10(%1),%0
-		xchg	%b0,%h0
-		addb	1(%1),%b0
-		adcb	$0,%h0
-		adcw	$1,%0
-		cmc
-		sbbw	%2,%0
-		sbbw	$0,%0
-		movb	%b2,1(%1)
-		xchg	%b0,%h0
-		movw	%0,10(%1)"
-	    : "=&r" (check)
-	    : "r" (iph), "r" (dsfield)
-	    : "cc");
-}
-
-#endif
-
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/net/irda/discovery.h linux-2.4.20/include/net/irda/discovery.h
--- linux-2.4.19/include/net/irda/discovery.h	2001-06-20 00:03:47.000000000 +0000
+++ linux-2.4.20/include/net/irda/discovery.h	2002-10-29 11:18:49.000000000 +0000
@@ -36,9 +36,17 @@
 #include <net/irda/irda.h>
 #include <net/irda/irqueue.h>
 
-#define DISCOVERY_EXPIRE_TIMEOUT 6*HZ
+#define DISCOVERY_EXPIRE_TIMEOUT (2*sysctl_discovery_timeout*HZ)
 #define DISCOVERY_DEFAULT_SLOTS  0
 
+/* Types of discovery */
+typedef enum {
+	DISCOVERY_LOG,		/* What's in our discovery log */
+	DISCOVERY_ACTIVE,	/* Doing our own discovery on the medium */
+	DISCOVERY_PASSIVE,	/* Peer doing discovery on the medium */
+	EXPIRY_TIMEOUT,		/* Entry expired due to timeout */
+} DISCOVERY_MODE;
+
 #define NICKNAME_MAX_LEN 21
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/net/irda/ircomm_tty.h linux-2.4.20/include/net/irda/ircomm_tty.h
--- linux-2.4.19/include/net/irda/ircomm_tty.h	2000-12-11 21:33:16.000000000 +0000
+++ linux-2.4.20/include/net/irda/ircomm_tty.h	2002-10-29 11:18:39.000000000 +0000
@@ -44,6 +44,11 @@
 #define IRCOMM_TTY_MAJOR 161
 #define IRCOMM_TTY_MINOR 0
 
+/* This is used as an initial value to max_header_size before the proper
+ * value is filled in (5 for ttp, 4 for lmp). This allow us to detect
+ * the state of the underlying connection. - Jean II */
+#define IRCOMM_TTY_HDR_UNITIALISED	32
+
 /*
  * IrCOMM TTY driver state
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/net/irda/irlan_client.h linux-2.4.20/include/net/irda/irlan_client.h
--- linux-2.4.19/include/net/irda/irlan_client.h	2000-12-11 21:33:09.000000000 +0000
+++ linux-2.4.20/include/net/irda/irlan_client.h	2002-10-29 11:18:35.000000000 +0000
@@ -34,7 +34,7 @@
 #include <net/irda/irlan_event.h>
 
 void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout);
-void irlan_client_discovery_indication(discovery_t *, void *);
+void irlan_client_discovery_indication(discovery_t *, DISCOVERY_MODE, void *);
 void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr);
 
 void irlan_client_open_ctrl_tsap( struct irlan_cb *self);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/net/irda/irlmp.h linux-2.4.20/include/net/irda/irlmp.h
--- linux-2.4.19/include/net/irda/irlmp.h	2001-12-21 17:42:04.000000000 +0000
+++ linux-2.4.20/include/net/irda/irlmp.h	2002-10-29 11:18:31.000000000 +0000
@@ -72,7 +72,7 @@
 	S_END,
 } SERVICE;
 
-typedef void (*DISCOVERY_CALLBACK1) (discovery_t *, void *);
+typedef void (*DISCOVERY_CALLBACK1) (discovery_t *, DISCOVERY_MODE, void *);
 typedef void (*DISCOVERY_CALLBACK2) (hashbin_t *, void *);
 
 typedef struct {
@@ -214,7 +214,7 @@
 				 struct sk_buff *userdata);
 int  irlmp_disconnect_request(struct lsap_cb *, struct sk_buff *userdata);
 
-void irlmp_discovery_confirm(hashbin_t *discovery_log);
+void irlmp_discovery_confirm(hashbin_t *discovery_log, DISCOVERY_MODE);
 void irlmp_discovery_request(int nslots);
 struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask, int nslots);
 void irlmp_do_expiry(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/net/iw_handler.h linux-2.4.20/include/net/iw_handler.h
--- linux-2.4.19/include/net/iw_handler.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/include/net/iw_handler.h	2002-10-29 11:18:38.000000000 +0000
@@ -1,10 +1,10 @@
 /*
  * This file define the new driver API for Wireless Extensions
  *
- * Version :	2	6.12.01
+ * Version :	3	17.1.02
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
  */
 
 #ifndef _IW_HANDLER_H
@@ -33,7 +33,7 @@
  *	o The user space interface is tied to ioctl because of the use
  *	  copy_to/from_user.
  *
- * New driver API (2001 -> onward) :
+ * New driver API (2002 -> onward) :
  * -------------------------------
  * The new driver API is just a bunch of standard functions (handlers),
  * each handling a specific Wireless Extension. The driver just export
@@ -206,7 +206,18 @@
  * will be needed...
  * I just plan to increment with each new version.
  */
-#define IW_HANDLER_VERSION	2
+#define IW_HANDLER_VERSION	3
+
+/*
+ * Changes :
+ *
+ * V2 to V3
+ * --------
+ *	- Move event definition in <linux/wireless.h>
+ *	- Add Wireless Event support :
+ *		o wireless_send_event() prototype
+ *		o iwe_stream_add_event/point() inline functions
+ */
 
 /**************************** CONSTANTS ****************************/
 
@@ -225,6 +236,7 @@
 #define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
 #define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
 #define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
+#define IW_HEADER_TYPE_QUAL	9	/* struct iw_quality */
 
 /* Handling flags */
 /* Most are not implemented. I just use them as a reminder of some
@@ -233,7 +245,8 @@
 /* Wrapper level flags */
 #define IW_DESCR_FLAG_DUMP	0x0001	/* Not part of the dump command */
 #define IW_DESCR_FLAG_EVENT	0x0002	/* Generate an event on SET */
-#define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET request is ROOT only */
+#define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET : request is ROOT only */
+				/* SET : Omit payload from generated iwevent */
 /* Driver level flags */
 #define IW_DESCR_FLAG_WAIT	0x0100	/* Wait for driver event */
 
@@ -303,25 +316,6 @@
 	 * 'struct net_device' to here, to minimise bloat. */
 };
 
-/* ----------------------- WIRELESS EVENTS ----------------------- */
-/*
- * Currently we don't support events, so let's just plan for the
- * future...
- */
-
-/*
- * A Wireless Event.
- */
-// How do we define short header ? We don't want a flag on length.
-// Probably a flag on event ? Highest bit to zero...
-struct iw_event
-{
-	__u16		length;			/* Lenght of this stuff */
-	__u16		event;			/* Wireless IOCTL */
-	union	iwreq_data	header;		/* IOCTL fixed payload */
-	char		extra[0];		/* Optional IOCTL data */
-};
-
 /* ---------------------- IOCTL DESCRIPTION ---------------------- */
 /*
  * One of the main goal of the new interface is to deal entirely with
@@ -369,6 +363,88 @@
 extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
 
 /* Second : functions that may be called by driver modules */
-/* None yet */
 
-#endif	/* _LINUX_WIRELESS_H */
+/* Send a single event to user space */
+extern void wireless_send_event(struct net_device *	dev,
+				unsigned int		cmd,
+				union iwreq_data *	wrqu,
+				char *			extra);
+
+/* We may need a function to send a stream of events to user space.
+ * More on that later... */
+
+/************************* INLINE FUNTIONS *************************/
+/*
+ * Function that are so simple that it's more efficient inlining them
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to add an Wireless Event to a stream of events.
+ */
+static inline char *
+iwe_stream_add_event(char *	stream,		/* Stream of events */
+		     char *	ends,		/* End of stream */
+		     struct iw_event *iwe,	/* Payload */
+		     int	event_len)	/* Real size of payload */
+{
+	/* Check if it's possible */
+	if((stream + event_len) < ends) {
+		iwe->len = event_len;
+		memcpy(stream, (char *) iwe, event_len);
+		stream += event_len;
+	}
+	return stream;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to add an short Wireless Event containing a pointer to a
+ * stream of events.
+ */
+static inline char *
+iwe_stream_add_point(char *	stream,		/* Stream of events */
+		     char *	ends,		/* End of stream */
+		     struct iw_event *iwe,	/* Payload */
+		     char *	extra)
+{
+	int	event_len = IW_EV_POINT_LEN + iwe->u.data.length;
+	/* Check if it's possible */
+	if((stream + event_len) < ends) {
+		iwe->len = event_len;
+		memcpy(stream, (char *) iwe, IW_EV_POINT_LEN);
+		memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length);
+		stream += event_len;
+	}
+	return stream;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to add a value to a Wireless Event in a stream of events.
+ * Be careful, this one is tricky to use properly :
+ * At the first run, you need to have (value = event + IW_EV_LCP_LEN).
+ */
+static inline char *
+iwe_stream_add_value(char *	event,		/* Event in the stream */
+		     char *	value,		/* Value in event */
+		     char *	ends,		/* End of stream */
+		     struct iw_event *iwe,	/* Payload */
+		     int	event_len)	/* Real size of payload */
+{
+	/* Don't duplicate LCP */
+	event_len -= IW_EV_LCP_LEN;
+
+	/* Check if it's possible */
+	if((value + event_len) < ends) {
+		/* Add new value */
+		memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len);
+		value += event_len;
+		/* Patch LCP */
+		iwe->len = value - event;
+		memcpy(event, (char *) iwe, IW_EV_LCP_LEN);
+	}
+	return value;
+}
+
+#endif	/* _IW_HANDLER_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/net/ndisc.h linux-2.4.20/include/net/ndisc.h
--- linux-2.4.19/include/net/ndisc.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/include/net/ndisc.h	2002-10-29 11:18:34.000000000 +0000
@@ -51,6 +51,25 @@
 	__u32			retrans_timer;
 };
 
+struct nd_opt_hdr {
+	__u8		nd_opt_type;
+	__u8		nd_opt_len;
+} __attribute__((__packed__));
+
+struct ndisc_options {
+	struct nd_opt_hdr *nd_opt_array[7];
+	struct nd_opt_hdr *nd_opt_piend;
+};
+
+#define nd_opts_src_lladdr	nd_opt_array[ND_OPT_SOURCE_LL_ADDR]
+#define nd_opts_tgt_lladdr	nd_opt_array[ND_OPT_TARGET_LL_ADDR]
+#define nd_opts_pi		nd_opt_array[ND_OPT_PREFIX_INFO]
+#define nd_opts_pi_end		nd_opt_piend
+#define nd_opts_rh		nd_opt_array[ND_OPT_REDIRECT_HDR]
+#define nd_opts_mtu		nd_opt_array[ND_OPT_MTU]
+
+extern struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, struct nd_opt_hdr *end);
+extern struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, struct ndisc_options *ndopts);
 
 extern int			ndisc_init(struct net_proto_family *ops);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/net/tcp.h linux-2.4.20/include/net/tcp.h
--- linux-2.4.19/include/net/tcp.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/include/net/tcp.h	2002-10-29 11:18:33.000000000 +0000
@@ -27,6 +27,7 @@
 #include <linux/config.h>
 #include <linux/tcp.h>
 #include <linux/slab.h>
+#include <linux/cache.h>
 #include <net/checksum.h>
 #include <net/sock.h>
 
@@ -117,8 +118,7 @@
 	 * Now align to a new cache line as all the following members
 	 * are often dirty.
 	 */
-	rwlock_t __tcp_lhash_lock
-		__attribute__((__aligned__(SMP_CACHE_BYTES)));
+	rwlock_t __tcp_lhash_lock ____cacheline_aligned;
 	atomic_t __tcp_lhash_users;
 	wait_queue_head_t __tcp_lhash_wait;
 	spinlock_t __tcp_portalloc_lock;
@@ -447,7 +447,6 @@
 extern int sysctl_tcp_retrans_collapse;
 extern int sysctl_tcp_stdurg;
 extern int sysctl_tcp_rfc1337;
-extern int sysctl_tcp_tw_recycle;
 extern int sysctl_tcp_abort_on_overflow;
 extern int sysctl_tcp_max_orphans;
 extern int sysctl_tcp_max_tw_buckets;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/scsi/scsi.h linux-2.4.20/include/scsi/scsi.h
--- linux-2.4.19/include/scsi/scsi.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.20/include/scsi/scsi.h	2002-10-29 11:18:50.000000000 +0000
@@ -89,6 +89,8 @@
 #define SEND_VOLUME_TAG       0xb6
 #define WRITE_LONG_2          0xea
 
+#define SCSI_RETRY_10(c) ((c) == READ_6 || (c) == WRITE_6 || (c) == SEEK_6)
+
 /*
  *  Status codes
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/scsi/sg.h linux-2.4.20/include/scsi/sg.h
--- linux-2.4.19/include/scsi/sg.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/include/scsi/sg.h	2002-10-29 11:18:39.000000000 +0000
@@ -11,9 +11,12 @@
 Version 2 and 3 extensions to driver:
 *       Copyright (C) 1998 - 2002 Douglas Gilbert
 
-    Version: 3.1.23 (20020318)
+    Version: 3.1.24 (20020505)
     This version is for 2.4 series kernels.
 
+    Changes since 3.1.23 (20020318)
+	- off by one fix for last scatter gather element
+	- zero buffer obtained for non-root users
     Changes since 3.1.22 (20011208)
 	- change EACCES to EPERM when O_RDONLY is insufficient
 	- suppress newlines in host string ( /proc/scsi/sg/host_strs output)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/include/video/fbcon.h linux-2.4.20/include/video/fbcon.h
--- linux-2.4.19/include/video/fbcon.h	2001-09-13 23:25:07.000000000 +0000
+++ linux-2.4.20/include/video/fbcon.h	2002-10-29 11:18:34.000000000 +0000
@@ -206,7 +206,8 @@
 #define fb_writel sbus_writel
 #define fb_memset sbus_memset_io
 
-#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__)
+#elif defined(__i386__) || defined(__alpha__) || \
+      defined(__x86_64__) || defined(__hppa__)
 
 #define fb_readb __raw_readb
 #define fb_readw __raw_readw
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/init/do_mounts.c linux-2.4.20/init/do_mounts.c
--- linux-2.4.19/init/do_mounts.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/init/do_mounts.c	2002-10-29 11:18:36.000000000 +0000
@@ -20,16 +20,17 @@
 
 extern int get_filesystem_list(char * buf);
 
-asmlinkage long sys_mount(char *dev_name, char *dir_name, char *type,
+extern asmlinkage long sys_mount(char *dev_name, char *dir_name, char *type,
 	 unsigned long flags, void *data);
-asmlinkage long sys_mkdir(char *name, int mode);
-asmlinkage long sys_chdir(char *name);
-asmlinkage long sys_chroot(char *name);
-asmlinkage long sys_unlink(char *name);
-asmlinkage long sys_symlink(char *old, char *new);
-asmlinkage long sys_mknod(char *name, int mode, dev_t dev);
-asmlinkage long sys_umount(char *name, int flags);
-asmlinkage long sys_ioctl(int fd, int cmd, unsigned long arg);
+extern asmlinkage long sys_mkdir(const char *name, int mode);
+extern asmlinkage long sys_chdir(const char *name);
+extern asmlinkage long sys_fchdir(int fd);
+extern asmlinkage long sys_chroot(const char *name);
+extern asmlinkage long sys_unlink(const char *name);
+extern asmlinkage long sys_symlink(const char *old, const char *new);
+extern asmlinkage long sys_mknod(const char *name, int mode, dev_t dev);
+extern asmlinkage long sys_umount(char *name, int flags);
+extern asmlinkage long sys_ioctl(int fd, int cmd, unsigned long arg);
 
 #ifdef CONFIG_BLK_DEV_INITRD
 unsigned int real_root_dev;	/* do_proc_dointvec cannot handle kdev_t */
@@ -180,6 +181,13 @@
 	{ "ida/c0d13p",0x48D0 },
 	{ "ida/c0d14p",0x48E0 },
 	{ "ida/c0d15p",0x48F0 },
+	{ "ida/c1d0p",0x4900 },
+	{ "ida/c2d0p",0x4A00 },
+	{ "ida/c3d0p",0x4B00 },
+	{ "ida/c4d0p",0x4C00 },
+	{ "ida/c5d0p",0x4D00 },
+	{ "ida/c6d0p",0x4E00 },
+	{ "ida/c7d0p",0x4F00 }, 
 #endif
 #if defined(CONFIG_BLK_CPQ_CISS_DA) || defined(CONFIG_BLK_CPQ_CISS_DA_MODULE)
 	{ "cciss/c0d0p",0x6800 },
@@ -198,6 +206,13 @@
 	{ "cciss/c0d13p",0x68D0 },
 	{ "cciss/c0d14p",0x68E0 },
 	{ "cciss/c0d15p",0x68F0 },
+	{ "cciss/c1d0p",0x6900 },
+	{ "cciss/c2d0p",0x6A00 },
+	{ "cciss/c3d0p",0x6B00 },
+	{ "cciss/c4d0p",0x6C00 },
+	{ "cciss/c5d0p",0x6D00 },
+	{ "cciss/c6d0p",0x6E00 },
+	{ "cciss/c7d0p",0x6F00 },
 #endif
 	{ "ataraid/d0p",0x7200 },
 	{ "ataraid/d1p",0x7210 },
@@ -229,7 +244,8 @@
 
 kdev_t __init name_to_kdev_t(char *line)
 {
-	int base = 0;
+	int base = 0, offs;
+	char *end;
 
 	if (strncmp(line,"/dev/",5) == 0) {
 		struct dev_name_struct *dev = root_dev_names;
@@ -244,7 +260,10 @@
 			dev++;
 		} while (dev->name);
 	}
-	return to_kdev_t(base + simple_strtoul(line,NULL,base?10:16));
+	offs = simple_strtoul(line, &end, base?10:16);
+	if (*end)
+		offs = 0;
+	return to_kdev_t(base + offs);
 }
 
 static int __init root_dev_setup(char *line)
@@ -741,18 +760,17 @@
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
+static int old_fd, root_fd;
 static int do_linuxrc(void * shell)
 {
 	static char *argv[] = { "linuxrc", NULL, };
 	extern char * envp_init[];
 
-	sys_chdir("/root");
-	sys_mount(".", "/", NULL, MS_MOVE, NULL);
-	sys_chroot(".");
-
-	mount_devfs_fs ();
-
-	close(0);close(1);close(2);
+	close(old_fd);
+	close(root_fd);
+	close(0);
+	close(1);
+	close(2);
 	setsid();
 	(void) open("/dev/console",O_RDWR,0);
 	(void) dup(0);
@@ -770,19 +788,29 @@
 	int i, pid;
 
 	create_dev("/dev/root.old", ram0, NULL);
+	/* mount initrd on rootfs' /root */
 	mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY);
 	sys_mkdir("/old", 0700);
-	sys_chdir("/old");
+	root_fd = open("/", 0, 0);
+	old_fd = open("/old", 0, 0);
+	/* move initrd over / and chdir/chroot in initrd root */
+	sys_chdir("/root");
+	sys_mount(".", "/", NULL, MS_MOVE, NULL);
+	sys_chroot(".");
+	mount_devfs_fs ();
 
 	pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
 	if (pid > 0) {
-		while (pid != wait(&i)) {
-			current->policy |= SCHED_YIELD;
-			schedule();
-		}
+		while (pid != wait(&i))
+			yield();
 	}
 
-	sys_mount("..", ".", NULL, MS_MOVE, NULL);
+	/* move initrd to rootfs' /old */
+	sys_fchdir(old_fd);
+	sys_mount("/", ".", NULL, MS_MOVE, NULL);
+	/* switch root and cwd back to / of rootfs */
+	sys_fchdir(root_fd);
+	sys_chroot(".");
 	sys_umount("/old/dev", 0);
 
 	if (real_root_dev == ram0) {
@@ -862,7 +890,7 @@
 	mount_devfs_fs ();
 }
 
-#ifdef BUILD_CRAMDISK
+#if defined(BUILD_CRAMDISK) && defined(CONFIG_BLK_DEV_RAM)
 
 /*
  * gzip declarations
@@ -1007,4 +1035,4 @@
 	return result;
 }
 
-#endif  /* BUILD_CRAMDISK */
+#endif  /* BUILD_CRAMDISK && CONFIG_BLK_DEV_RAM */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/ipc/msg.c linux-2.4.20/ipc/msg.c
--- linux-2.4.19/ipc/msg.c	2001-09-14 21:17:00.000000000 +0000
+++ linux-2.4.20/ipc/msg.c	2002-10-29 11:18:31.000000000 +0000
@@ -597,7 +597,7 @@
 	return 0;
 }
 
-int inline pipelined_send(struct msg_queue* msq, struct msg_msg* msg)
+static int inline pipelined_send(struct msg_queue* msq, struct msg_msg* msg)
 {
 	struct list_head* tmp;
 
@@ -706,7 +706,7 @@
 	return err;
 }
 
-int inline convert_mode(long* msgtyp, int msgflg)
+static int inline convert_mode(long* msgtyp, int msgflg)
 {
 	/* 
 	 *  find message of correct type.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/ipc/sem.c linux-2.4.20/ipc/sem.c
--- linux-2.4.19/ipc/sem.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/ipc/sem.c	2002-10-29 11:18:37.000000000 +0000
@@ -440,7 +440,7 @@
 	}
 }
 
-int semctl_nolock(int semid, int semnum, int cmd, int version, union semun arg)
+static int semctl_nolock(int semid, int semnum, int cmd, int version, union semun arg)
 {
 	int err = -EINVAL;
 
@@ -512,7 +512,7 @@
 	return err;
 }
 
-int semctl_main(int semid, int semnum, int cmd, int version, union semun arg)
+static int semctl_main(int semid, int semnum, int cmd, int version, union semun arg)
 {
 	struct sem_array *sma;
 	struct sem* curr;
@@ -699,7 +699,7 @@
 	}
 }
 
-int semctl_down(int semid, int semnum, int cmd, int version, union semun arg)
+static int semctl_down(int semid, int semnum, int cmd, int version, union semun arg)
 {
 	struct sem_array *sma;
 	int err;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/ipc/util.c linux-2.4.20/ipc/util.c
--- linux-2.4.19/ipc/util.c	2001-08-13 00:37:53.000000000 +0000
+++ linux-2.4.20/ipc/util.c	2002-10-29 11:18:39.000000000 +0000
@@ -312,7 +312,7 @@
 	out->seq	= in->seq;
 }
 
-#ifndef __ia64__
+#if !defined(__ia64__) && !defined(__hppa__)
 
 /**
  *	ipc_parse_version	-	IPC call version
@@ -325,6 +325,10 @@
  
 int ipc_parse_version (int *cmd)
 {
+#ifdef __x86_64__
+	if (!(current->thread.flags & THREAD_IA32))
+		return IPC_64; 
+#endif
 	if (*cmd & IPC_64) {
 		*cmd ^= IPC_64;
 		return IPC_64;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/ipc/util.h linux-2.4.20/ipc/util.h
--- linux-2.4.19/ipc/util.h	2001-02-19 18:18:18.000000000 +0000
+++ linux-2.4.20/ipc/util.h	2002-10-29 11:18:48.000000000 +0000
@@ -99,8 +99,8 @@
 void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
 void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
 
-#ifdef __ia64__
-  /* On IA-64, we always use the "64-bit version" of the IPC structures.  */ 
+#if defined(__ia64__) || defined(__hppa__)
+  /* On IA-64 and PA-RISC, we always use the "64-bit version" of the IPC structures.  */ 
 # define ipc_parse_version(cmd)	IPC_64
 #else
 int ipc_parse_version (int *cmd);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/kernel/exit.c linux-2.4.20/kernel/exit.c
--- linux-2.4.19/kernel/exit.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/kernel/exit.c	2002-10-29 11:18:36.000000000 +0000
@@ -158,21 +158,10 @@
  */
 static inline void forget_original_parent(struct task_struct * father)
 {
-	struct task_struct * p, *reaper;
+	struct task_struct * p;
 
 	read_lock(&tasklist_lock);
 
-	/* Next in our thread group, if they're not already exiting */
-	reaper = father;
-	do {
-		reaper = next_thread(reaper);
-		if (!(reaper->flags & PF_EXITING))
-			break;
-	} while (reaper != father);
-
-	if (reaper == father)
-		reaper = child_reaper;
-
 	for_each_task(p) {
 		if (p->p_opptr == father) {
 			/* We dont want people slaying init */
@@ -180,10 +169,7 @@
 			p->self_exec_id++;
 
 			/* Make sure we're not reparenting to ourselves */
-			if (p == reaper)
-				p->p_opptr = child_reaper;
-			else
-				p->p_opptr = reaper;
+			p->p_opptr = child_reaper;
 
 			if (p->pdeath_signal) send_sig(p->pdeath_signal, p, 0);
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/kernel/fork.c linux-2.4.20/kernel/fork.c
--- linux-2.4.19/kernel/fork.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/kernel/fork.c	2002-10-29 11:18:33.000000000 +0000
@@ -707,7 +707,7 @@
 
 	/*
 	 * "share" dynamic priority between parent and child, thus the
-	 * total amount of dynamic priorities in the system doesnt change,
+	 * total amount of dynamic priorities in the system doesn't change,
 	 * more scheduling fairness. This is only important in the first
 	 * timeslice, on the long run the scheduling behaviour is unchanged.
 	 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/kernel/ksyms.c linux-2.4.20/kernel/ksyms.c
--- linux-2.4.19/kernel/ksyms.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/kernel/ksyms.c	2002-10-29 11:18:31.000000000 +0000
@@ -47,6 +47,7 @@
 #include <linux/in6.h>
 #include <linux/completion.h>
 #include <linux/seq_file.h>
+#include <linux/dnotify.h>
 #include <asm/checksum.h>
 
 #if defined(CONFIG_PROC_FS)
@@ -104,6 +105,7 @@
 EXPORT_SYMBOL(kmem_cache_shrink);
 EXPORT_SYMBOL(kmem_cache_alloc);
 EXPORT_SYMBOL(kmem_cache_free);
+EXPORT_SYMBOL(kmem_cache_size);
 EXPORT_SYMBOL(kmalloc);
 EXPORT_SYMBOL(kfree);
 EXPORT_SYMBOL(vfree);
@@ -122,6 +124,8 @@
 EXPORT_SYMBOL(kunmap_high);
 EXPORT_SYMBOL(highmem_start_page);
 EXPORT_SYMBOL(create_bounce);
+EXPORT_SYMBOL(kmap_prot);
+EXPORT_SYMBOL(kmap_pte);
 #endif
 
 /* filesystem internal functions */
@@ -258,7 +262,7 @@
 EXPORT_SYMBOL(ROOT_DEV);
 EXPORT_SYMBOL(__find_get_page);
 EXPORT_SYMBOL(__find_lock_page);
-EXPORT_SYMBOL(grab_cache_page);
+EXPORT_SYMBOL(find_or_create_page);
 EXPORT_SYMBOL(grab_cache_page_nowait);
 EXPORT_SYMBOL(read_cache_page);
 EXPORT_SYMBOL(set_page_dirty);
@@ -447,7 +451,8 @@
 EXPORT_SYMBOL(interruptible_sleep_on_timeout);
 EXPORT_SYMBOL(schedule);
 EXPORT_SYMBOL(schedule_timeout);
-EXPORT_SYMBOL(sys_sched_yield);
+EXPORT_SYMBOL(yield);
+EXPORT_SYMBOL(__cond_resched);
 EXPORT_SYMBOL(jiffies);
 EXPORT_SYMBOL(xtime);
 EXPORT_SYMBOL(do_gettimeofday);
@@ -527,6 +532,7 @@
 EXPORT_SYMBOL(is_bad_inode);
 EXPORT_SYMBOL(event);
 EXPORT_SYMBOL(brw_page);
+EXPORT_SYMBOL(__inode_dir_notify);
 
 #ifdef CONFIG_UID16
 EXPORT_SYMBOL(overflowuid);
@@ -570,3 +576,6 @@
 
 EXPORT_SYMBOL(tasklist_lock);
 EXPORT_SYMBOL(pidhash);
+
+/* debug */
+EXPORT_SYMBOL(dump_stack);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/kernel/panic.c linux-2.4.20/kernel/panic.c
--- linux-2.4.19/kernel/panic.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/kernel/panic.c	2002-10-29 11:18:39.000000000 +0000
@@ -96,7 +96,7 @@
 #endif
 	sti();
 	for(;;) {
-#if defined(__i386__) && defined(CONFIG_VT) 
+#if defined(CONFIG_X86) && defined(CONFIG_VT) 
 		extern void panic_blink(void);
 		panic_blink(); 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/kernel/pm.c linux-2.4.20/kernel/pm.c
--- linux-2.4.19/kernel/pm.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/kernel/pm.c	2002-10-29 11:18:34.000000000 +0000
@@ -30,7 +30,7 @@
  *	Locking notes:
  *		pm_devs_lock can be a semaphore providing pm ops are not called
  *	from an interrupt handler (already a bad idea so no change here). Each
- *	change must be protected so that an unlink of an entry doesnt clash
+ *	change must be protected so that an unlink of an entry doesn't clash
  *	with a pm send - which is permitted to sleep in the current architecture
  *
  *	Module unloads clashing with pm events now work out safely, the module 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/kernel/resource.c linux-2.4.20/kernel/resource.c
--- linux-2.4.19/kernel/resource.c	2001-05-22 01:10:36.000000000 +0000
+++ linux-2.4.20/kernel/resource.c	2002-10-29 11:18:33.000000000 +0000
@@ -152,7 +152,8 @@
 			 unsigned long size,
 			 unsigned long min, unsigned long max,
 			 unsigned long align,
-			 void (*alignf)(void *, struct resource *, unsigned long),
+			 void (*alignf)(void *, struct resource *,
+					unsigned long, unsigned long),
 			 void *alignf_data)
 {
 	struct resource *this = root->child;
@@ -169,7 +170,7 @@
 			new->end = max;
 		new->start = (new->start + align - 1) & ~(align - 1);
 		if (alignf)
-			alignf(alignf_data, new, size);
+			alignf(alignf_data, new, size, align);
 		if (new->start < new->end && new->end - new->start + 1 >= size) {
 			new->end = new->start + size - 1;
 			return 0;
@@ -189,7 +190,8 @@
 		      unsigned long size,
 		      unsigned long min, unsigned long max,
 		      unsigned long align,
-		      void (*alignf)(void *, struct resource *, unsigned long),
+		      void (*alignf)(void *, struct resource *,
+				     unsigned long, unsigned long),
 		      void *alignf_data)
 {
 	int err;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/kernel/sched.c linux-2.4.20/kernel/sched.c
--- linux-2.4.19/kernel/sched.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/kernel/sched.c	2002-10-29 11:18:35.000000000 +0000
@@ -318,13 +318,17 @@
 /*
  * Careful!
  *
- * This has to add the process to the _beginning_ of the
- * run-queue, not the end. See the comment about "This is
- * subtle" in the scheduler proper..
+ * This has to add the process to the _end_ of the 
+ * run-queue, not the beginning. The goodness value will
+ * determine whether this process will run next. This is
+ * important to get SCHED_FIFO and SCHED_RR right, where
+ * a process that is either pre-empted or its time slice
+ * has expired, should be moved to the tail of the run 
+ * queue for its priority - Bhavesh Davda
  */
 static inline void add_to_runqueue(struct task_struct * p)
 {
-	list_add(&p->run_list, &runqueue_head);
+	list_add_tail(&p->run_list, &runqueue_head);
 	nr_running++;
 }
 
@@ -334,12 +338,6 @@
 	list_add_tail(&p->run_list, &runqueue_head);
 }
 
-static inline void move_first_runqueue(struct task_struct * p)
-{
-	list_del(&p->run_list);
-	list_add(&p->run_list, &runqueue_head);
-}
-
 /*
  * Wake up a process. Put it on the run-queue if it's not
  * already there.  The "current" process is always on the
@@ -955,8 +953,6 @@
 	retval = 0;
 	p->policy = policy;
 	p->rt_priority = lp.sched_priority;
-	if (task_on_runqueue(p))
-		move_first_runqueue(p);
 
 	current->need_resched = 1;
 
@@ -1071,6 +1067,25 @@
 	return 0;
 }
 
+/**
+ * yield - yield the current processor to other threads.
+ *
+ * this is a shortcut for kernel-space yielding - it marks the
+ * thread runnable and calls sys_sched_yield().
+ */
+void yield(void)
+{
+	set_current_state(TASK_RUNNING);
+	sys_sched_yield();
+	schedule();
+}
+
+void __cond_resched(void)
+{
+	set_current_state(TASK_RUNNING);
+	schedule();
+}
+
 asmlinkage long sys_sched_get_priority_max(int policy)
 {
 	int ret = -EINVAL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/kernel/softirq.c linux-2.4.20/kernel/softirq.c
--- linux-2.4.19/kernel/softirq.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/kernel/softirq.c	2002-10-29 11:18:35.000000000 +0000
@@ -40,7 +40,7 @@
    - Bottom halves: globally serialized, grr...
  */
 
-irq_cpustat_t irq_stat[NR_CPUS];
+irq_cpustat_t irq_stat[NR_CPUS] ____cacheline_aligned;
 
 static struct softirq_action softirq_vec[32] __cacheline_aligned;
 
@@ -260,8 +260,7 @@
 	while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
 		current->state = TASK_RUNNING;
 		do {
-			current->policy |= SCHED_YIELD;
-			schedule();
+			yield();
 		} while (test_bit(TASKLET_STATE_SCHED, &t->state));
 	}
 	tasklet_unlock_wait(t);
@@ -405,10 +404,8 @@
 				  CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0)
 			printk("spawn_ksoftirqd() failed for cpu %d\n", cpu);
 		else {
-			while (!ksoftirqd_task(cpu_logical_map(cpu))) {
-				current->policy |= SCHED_YIELD;
-				schedule();
-			}
+			while (!ksoftirqd_task(cpu_logical_map(cpu)))
+				yield();
 		}
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/kernel/time.c linux-2.4.20/kernel/time.c
--- linux-2.4.19/kernel/time.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/kernel/time.c	2002-10-29 11:18:34.000000000 +0000
@@ -80,8 +80,10 @@
 	if (get_user(value, tptr))
 		return -EFAULT;
 	write_lock_irq(&xtime_lock);
+	vxtime_lock();
 	xtime.tv_sec = value;
 	xtime.tv_usec = 0;
+	vxtime_unlock();
 	time_adjust = 0;	/* stop active adjtime() */
 	time_status |= STA_UNSYNC;
 	time_maxerror = NTP_PHASE_LIMIT;
@@ -126,7 +128,9 @@
 inline static void warp_clock(void)
 {
 	write_lock_irq(&xtime_lock);
+	vxtime_lock();
 	xtime.tv_sec += sys_tz.tz_minuteswest * 60;
+	vxtime_unlock();
 	write_unlock_irq(&xtime_lock);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/kernel/timer.c linux-2.4.20/kernel/timer.c
--- linux-2.4.19/kernel/timer.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/kernel/timer.c	2002-10-29 11:18:35.000000000 +0000
@@ -601,7 +601,14 @@
 	if (p->pid) {
 		if (--p->counter <= 0) {
 			p->counter = 0;
-			p->need_resched = 1;
+			/*
+			 * SCHED_FIFO is priority preemption, so this is 
+			 * not the place to decide whether to reschedule a
+			 * SCHED_FIFO task or not - Bhavesh Davda
+			 */
+			if (p->policy != SCHED_FIFO) {
+				p->need_resched = 1;
+			}
 		}
 		if (p->nice > 0)
 			kstat.per_cpu_nice[cpu] += user_tick;
@@ -671,12 +678,14 @@
 	 * need to save/restore the flags of the local CPU here. -arca
 	 */
 	write_lock_irq(&xtime_lock);
+	vxtime_lock();
 
 	ticks = jiffies - wall_jiffies;
 	if (ticks) {
 		wall_jiffies += ticks;
 		update_wall_time(ticks);
 	}
+	vxtime_unlock();
 	write_unlock_irq(&xtime_lock);
 	calc_load(ticks);
 }
@@ -731,10 +740,18 @@
  * The Alpha uses getxpid, getxuid, and getxgid instead.  Maybe this
  * should be moved into arch/i386 instead?
  */
- 
+
+/**
+ * sys_getpid - return the thread group id of the current process
+ *
+ * Note, despite the name, this returns the tgid not the pid.  The tgid and
+ * the pid are identical unless CLONE_THREAD was specified on clone() in
+ * which case the tgid is the same in all threads of the same group.
+ *
+ * This is SMP safe as current->tgid does not change.
+ */
 asmlinkage long sys_getpid(void)
 {
-	/* This is SMP safe - current->pid doesn't change */
 	return current->tgid;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/Config.in linux-2.4.20/lib/Config.in
--- linux-2.4.19/lib/Config.in	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/Config.in	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,38 @@
+#
+# Library configuration
+#
+mainmenu_option next_comment
+comment 'Library routines'
+
+#
+# Do we need the compression support?
+#
+if [ "$CONFIG_CRAMFS" = "y" -o \
+     "$CONFIG_PPP_DEFLATE" = "y" -o \
+     "$CONFIG_JFFS2_FS" = "y" -o \
+     "$CONFIG_ZISOFS_FS" = "y" ]; then
+   define_tristate CONFIG_ZLIB_INFLATE y
+else
+  if [ "$CONFIG_CRAMFS" = "m" -o \
+       "$CONFIG_PPP_DEFLATE" = "m" -o \
+       "$CONFIG_JFFS2_FS" = "m" -o \
+       "$CONFIG_ZISOFS_FS" = "m" ]; then
+     define_tristate CONFIG_ZLIB_INFLATE m
+  else
+     tristate 'zlib decompression support' CONFIG_ZLIB_INFLATE
+  fi
+fi
+
+if [ "$CONFIG_PPP_DEFLATE" = "y" -o \
+     "$CONFIG_JFFS2_FS" = "y" ]; then
+   define_tristate CONFIG_ZLIB_DEFLATE y
+else
+  if [ "$CONFIG_PPP_DEFLATE" = "m" -o \
+       "$CONFIG_JFFS2_FS" = "m" ]; then
+     define_tristate CONFIG_ZLIB_DEFLATE m
+  else
+     tristate 'zlib compression support' CONFIG_ZLIB_DEFLATE
+  fi
+fi
+
+endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/Makefile linux-2.4.20/lib/Makefile
--- linux-2.4.19/lib/Makefile	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/lib/Makefile	2002-10-29 11:18:32.000000000 +0000
@@ -10,7 +10,8 @@
 
 export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o rbtree.o
 
-obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o
+obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o \
+	 bust_spinlocks.o rbtree.o dump_stack.o
 
 obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
 obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
@@ -19,4 +20,10 @@
   obj-y += dec_and_lock.o
 endif
 
+subdir-$(CONFIG_ZLIB_INFLATE) += zlib_inflate
+subdir-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate
+
+# Include the subdirs, if necessary.
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/dump_stack.c linux-2.4.20/lib/dump_stack.c
--- linux-2.4.19/lib/dump_stack.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/dump_stack.c	2002-10-29 11:18:38.000000000 +0000
@@ -0,0 +1,13 @@
+/*
+ * Provide a default dump_stack() function for architectures
+ * which don't implement their own.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+void dump_stack(void)
+{
+	printk(KERN_NOTICE
+		"This architecture does not implement dump_stack()\n");
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/inflate.c linux-2.4.20/lib/inflate.c
--- linux-2.4.19/lib/inflate.c	2001-03-07 03:44:37.000000000 +0000
+++ linux-2.4.20/lib/inflate.c	2002-10-29 11:18:40.000000000 +0000
@@ -1009,7 +1009,7 @@
 
 static ulg crc_32_tab[256];
 static ulg crc;		/* initialized in makecrc() so it'll reside in bss */
-#define CRC_VALUE (crc ^ 0xffffffffL)
+#define CRC_VALUE (crc ^ 0xffffffffUL)
 
 /*
  * Code to compute the CRC-32 table. Borrowed from 
@@ -1049,7 +1049,7 @@
   }
 
   /* this is initialized here so this code could reside in ROM */
-  crc = (ulg)0xffffffffL; /* shift register contents */
+  crc = (ulg)0xffffffffUL; /* shift register contents */
 }
 
 /* gzip flag byte */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/rwsem-spinlock.c linux-2.4.20/lib/rwsem-spinlock.c
--- linux-2.4.19/lib/rwsem-spinlock.c	2001-04-25 20:31:03.000000000 +0000
+++ linux-2.4.20/lib/rwsem-spinlock.c	2002-10-29 11:18:33.000000000 +0000
@@ -4,6 +4,8 @@
  * Copyright (c) 2001   David Howells (dhowells@redhat.com).
  * - Derived partially from idea by Andrea Arcangeli <andrea@suse.de>
  * - Derived also from comments by Linus
+ *
+ * Trylock by Brian Watson (Brian.J.Watson@compaq.com).
  */
 #include <linux/rwsem.h>
 #include <linux/sched.h>
@@ -149,6 +151,28 @@
 }
 
 /*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+int __down_read_trylock(struct rw_semaphore *sem)
+{
+	int ret = 0;
+	rwsemtrace(sem,"Entering __down_read_trylock");
+
+	spin_lock(&sem->wait_lock);
+
+	if (sem->activity>=0 && list_empty(&sem->wait_list)) {
+		/* granted */
+		sem->activity++;
+		ret = 1;
+	}
+
+	spin_unlock(&sem->wait_lock);
+
+	rwsemtrace(sem,"Leaving __down_read_trylock");
+	return ret;
+}
+
+/*
  * get a write lock on the semaphore
  * - note that we increment the waiting count anyway to indicate an exclusive lock
  */
@@ -195,6 +219,28 @@
 }
 
 /*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+int __down_write_trylock(struct rw_semaphore *sem)
+{
+	int ret = 0;
+	rwsemtrace(sem,"Entering __down_write_trylock");
+
+	spin_lock(&sem->wait_lock);
+
+	if (sem->activity==0 && list_empty(&sem->wait_list)) {
+		/* granted */
+		sem->activity = -1;
+		ret = 1;
+	}
+
+	spin_unlock(&sem->wait_lock);
+
+	rwsemtrace(sem,"Leaving __down_write_trylock");
+	return ret;
+}
+
+/*
  * release a read lock on the semaphore
  */
 void __up_read(struct rw_semaphore *sem)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_deflate/Makefile linux-2.4.20/lib/zlib_deflate/Makefile
--- linux-2.4.19/lib/zlib_deflate/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_deflate/Makefile	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,18 @@
+#
+# This is a modified version of zlib, which does all memory
+# allocation ahead of time.
+#
+# This is the compression code, see zlib_inflate for the
+# decompression code.
+#
+
+O_TARGET    := zlib_deflate.o
+
+export-objs := deflate_syms.o
+
+obj-y := deflate.o deftree.o deflate_syms.o
+obj-m := $(O_TARGET)
+
+EXTRA_CFLAGS += -I $(TOPDIR)/lib/zlib_deflate
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_deflate/deflate.c linux-2.4.20/lib/zlib_deflate/deflate.c
--- linux-2.4.19/lib/zlib_deflate/deflate.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_deflate/deflate.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,1250 @@
+/* +++ deflate.c */
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many people for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ *      Available in ftp://ds.internic.net/rfc/rfc1951.txt
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/zutil.h>
+#include "defutil.h"
+
+
+/* ===========================================================================
+ *  Function prototypes.
+ */
+typedef enum {
+    need_more,      /* block not completed, need more input or more output */
+    block_done,     /* block flush performed */
+    finish_started, /* finish started, need only more output at next deflate */
+    finish_done     /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window    OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast   OF((deflate_state *s, int flush));
+local block_state deflate_slow   OF((deflate_state *s, int flush));
+local void lm_init        OF((deflate_state *s));
+local void putShortMSB    OF((deflate_state *s, uInt b));
+local void flush_pending  OF((z_streamp strm));
+local int read_buf        OF((z_streamp strm, Bytef *buf, unsigned size));
+local uInt longest_match  OF((deflate_state *s, IPos cur_match));
+
+#ifdef DEBUG_ZLIB
+local  void check_match OF((deflate_state *s, IPos start, IPos match,
+                            int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+   compress_func func;
+} config;
+
+local const config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}, /* maximum speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8, deflate_fast},
+/* 3 */ {4,    6, 32,   32, deflate_fast},
+
+/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32, deflate_slow},
+/* 6 */ {8,   16, 128, 128, deflate_slow},
+/* 7 */ {8,   32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of str are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+    s->head[s->hash_size-1] = NIL; \
+    memset((charf *)s->head, 0, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int zlib_deflateInit_(strm, level, version, stream_size)
+    z_streamp strm;
+    int level;
+    const char *version;
+    int stream_size;
+{
+    return zlib_deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS,
+			      DEF_MEM_LEVEL,
+			      Z_DEFAULT_STRATEGY, version, stream_size);
+    /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int zlib_deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+		       version, stream_size)
+    z_streamp strm;
+    int  level;
+    int  method;
+    int  windowBits;
+    int  memLevel;
+    int  strategy;
+    const char *version;
+    int stream_size;
+{
+    deflate_state *s;
+    int noheader = 0;
+    static char* my_version = ZLIB_VERSION;
+    deflate_workspace *mem;
+
+    ushf *overlay;
+    /* We overlay pending_buf and d_buf+l_buf. This works since the average
+     * output size for (length,distance) codes is <= 24 bits.
+     */
+
+    if (version == Z_NULL || version[0] != my_version[0] ||
+        stream_size != sizeof(z_stream)) {
+	return Z_VERSION_ERROR;
+    }
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->msg = Z_NULL;
+
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+
+    mem = (deflate_workspace *) strm->workspace;
+
+    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
+        noheader = 1;
+        windowBits = -windowBits;
+    }
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+	strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+        return Z_STREAM_ERROR;
+    }
+    s = (deflate_state *) &(mem->deflate_memory);
+    strm->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+
+    s->noheader = noheader;
+    s->w_bits = windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) mem->window_memory;
+    s->prev   = (Posf *)  mem->prev_memory;
+    s->head   = (Posf *)  mem->head_memory;
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    overlay = (ushf *) mem->overlay_memory;
+    s->pending_buf = (uchf *) overlay;
+    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+    s->level = level;
+    s->strategy = strategy;
+    s->method = (Byte)method;
+
+    return zlib_deflateReset(strm);
+}
+
+/* ========================================================================= */
+int zlib_deflateSetDictionary (strm, dictionary, dictLength)
+    z_streamp strm;
+    const Bytef *dictionary;
+    uInt  dictLength;
+{
+    deflate_state *s;
+    uInt length = dictLength;
+    uInt n;
+    IPos hash_head = 0;
+
+    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
+	return Z_STREAM_ERROR;
+
+    s = (deflate_state *) strm->state;
+    if (s->status != INIT_STATE) return Z_STREAM_ERROR;
+
+    strm->adler = zlib_adler32(strm->adler, dictionary, dictLength);
+
+    if (length < MIN_MATCH) return Z_OK;
+    if (length > MAX_DIST(s)) {
+	length = MAX_DIST(s);
+#ifndef USE_DICT_HEAD
+	dictionary += dictLength - length; /* use the tail of the dictionary */
+#endif
+    }
+    memcpy((charf *)s->window, dictionary, length);
+    s->strstart = length;
+    s->block_start = (long)length;
+
+    /* Insert all strings in the hash table (except for the last two bytes).
+     * s->lookahead stays null, so s->ins_h will be recomputed at the next
+     * call of fill_window.
+     */
+    s->ins_h = s->window[0];
+    UPDATE_HASH(s, s->ins_h, s->window[1]);
+    for (n = 0; n <= length - MIN_MATCH; n++) {
+	INSERT_STRING(s, n, hash_head);
+    }
+    if (hash_head) hash_head = 0;  /* to make compiler happy */
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int zlib_deflateReset (strm)
+    z_streamp strm;
+{
+    deflate_state *s;
+    
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return Z_STREAM_ERROR;
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL;
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->noheader < 0) {
+        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
+    }
+    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
+    strm->adler = 1;
+    s->last_flush = Z_NO_FLUSH;
+
+    zlib_tr_init(s);
+    lm_init(s);
+
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int zlib_deflateParams(strm, level, strategy)
+    z_streamp strm;
+    int level;
+    int strategy;
+{
+    deflate_state *s;
+    compress_func func;
+    int err = Z_OK;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = (deflate_state *) strm->state;
+
+    if (level == Z_DEFAULT_COMPRESSION) {
+	level = 6;
+    }
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+	return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if (func != configuration_table[level].func && strm->total_in != 0) {
+	/* Flush the last buffer: */
+	err = zlib_deflate(strm, Z_PARTIAL_FLUSH);
+    }
+    if (s->level != level) {
+	s->level = level;
+	s->max_lazy_match   = configuration_table[level].max_lazy;
+	s->good_match       = configuration_table[level].good_length;
+	s->nice_match       = configuration_table[level].nice_length;
+	s->max_chain_length = configuration_table[level].max_chain;
+    }
+    s->strategy = strategy;
+    return err;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+    deflate_state *s;
+    uInt b;
+{
+    put_byte(s, (Byte)(b >> 8));
+    put_byte(s, (Byte)(b & 0xff));
+}   
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+    z_streamp strm;
+{
+    deflate_state *s = (deflate_state *) strm->state;
+    unsigned len = s->pending;
+
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    if (strm->next_out != Z_NULL) {
+	memcpy(strm->next_out, s->pending_out, len);
+	strm->next_out += len;
+    }
+    s->pending_out += len;
+    strm->total_out += len;
+    strm->avail_out  -= len;
+    s->pending -= len;
+    if (s->pending == 0) {
+        s->pending_out = s->pending_buf;
+    }
+}
+
+/* ========================================================================= */
+int zlib_deflate (strm, flush)
+    z_streamp strm;
+    int flush;
+{
+    int old_flush; /* value of flush param for previous deflate call */
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+	flush > Z_FINISH || flush < 0) {
+        return Z_STREAM_ERROR;
+    }
+    s = (deflate_state *) strm->state;
+
+    if ((strm->next_in == Z_NULL && strm->avail_in != 0) ||
+	(s->status == FINISH_STATE && flush != Z_FINISH)) {
+        return Z_STREAM_ERROR;
+    }
+    if (strm->avail_out == 0) return Z_BUF_ERROR;
+
+    s->strm = strm; /* just in case */
+    old_flush = s->last_flush;
+    s->last_flush = flush;
+
+    /* Write the zlib header */
+    if (s->status == INIT_STATE) {
+
+        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+        uInt level_flags = (s->level-1) >> 1;
+
+        if (level_flags > 3) level_flags = 3;
+        header |= (level_flags << 6);
+	if (s->strstart != 0) header |= PRESET_DICT;
+        header += 31 - (header % 31);
+
+        s->status = BUSY_STATE;
+        putShortMSB(s, header);
+
+	/* Save the adler32 of the preset dictionary: */
+	if (s->strstart != 0) {
+	    putShortMSB(s, (uInt)(strm->adler >> 16));
+	    putShortMSB(s, (uInt)(strm->adler & 0xffff));
+	}
+	strm->adler = 1L;
+    }
+
+    /* Flush as much pending output as possible */
+    if (s->pending != 0) {
+        flush_pending(strm);
+        if (strm->avail_out == 0) {
+	    /* Since avail_out is 0, deflate will be called again with
+	     * more output space, but possibly with both pending and
+	     * avail_in equal to zero. There won't be anything to do,
+	     * but this is not an error situation so make sure we
+	     * return OK instead of BUF_ERROR at next call of deflate:
+             */
+	    s->last_flush = -1;
+	    return Z_OK;
+	}
+
+    /* Make sure there is something to do and avoid duplicate consecutive
+     * flushes. For repeated and useless calls with Z_FINISH, we keep
+     * returning Z_STREAM_END instead of Z_BUFF_ERROR.
+     */
+    } else if (strm->avail_in == 0 && flush <= old_flush &&
+	       flush != Z_FINISH) {
+        return Z_BUF_ERROR;
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (s->status == FINISH_STATE && strm->avail_in != 0) {
+        return Z_BUF_ERROR;
+    }
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || s->lookahead != 0 ||
+        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+        block_state bstate;
+
+	bstate = (*(configuration_table[s->level].func))(s, flush);
+
+        if (bstate == finish_started || bstate == finish_done) {
+            s->status = FINISH_STATE;
+        }
+        if (bstate == need_more || bstate == finish_started) {
+	    if (strm->avail_out == 0) {
+	        s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+	    }
+	    return Z_OK;
+	    /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+	     * of deflate should use the same flush parameter to make sure
+	     * that the flush is complete. So we don't have to output an
+	     * empty block here, this will be done at next call. This also
+	     * ensures that for a very small output buffer, we emit at most
+	     * one empty block.
+	     */
+	}
+        if (bstate == block_done) {
+            if (flush == Z_PARTIAL_FLUSH) {
+                zlib_tr_align(s);
+	    } else if (flush == Z_PACKET_FLUSH) {
+		/* Output just the 3-bit `stored' block type value,
+		   but not a zero length. */
+		zlib_tr_stored_type_only(s);
+            } else { /* FULL_FLUSH or SYNC_FLUSH */
+                zlib_tr_stored_block(s, (char*)0, 0L, 0);
+                /* For a full flush, this empty block will be recognized
+                 * as a special marker by inflate_sync().
+                 */
+                if (flush == Z_FULL_FLUSH) {
+                    CLEAR_HASH(s);             /* forget history */
+                }
+            }
+            flush_pending(strm);
+	    if (strm->avail_out == 0) {
+	      s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+	      return Z_OK;
+	    }
+        }
+    }
+    Assert(strm->avail_out > 0, "bug2");
+
+    if (flush != Z_FINISH) return Z_OK;
+    if (s->noheader) return Z_STREAM_END;
+
+    /* Write the zlib trailer (adler32) */
+    putShortMSB(s, (uInt)(strm->adler >> 16));
+    putShortMSB(s, (uInt)(strm->adler & 0xffff));
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    s->noheader = -1; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int zlib_deflateEnd (strm)
+    z_streamp strm;
+{
+    int status;
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = (deflate_state *) strm->state;
+
+    status = s->status;
+    if (status != INIT_STATE && status != BUSY_STATE &&
+	status != FINISH_STATE) {
+      return Z_STREAM_ERROR;
+    }
+
+    strm->state = Z_NULL;
+
+    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ */
+int zlib_deflateCopy (dest, source)
+    z_streamp dest;
+    z_streamp source;
+{
+#ifdef MAXSEG_64K
+    return Z_STREAM_ERROR;
+#else
+    deflate_state *ds;
+    deflate_state *ss;
+    ushf *overlay;
+    deflate_workspace *mem;
+
+
+    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+        return Z_STREAM_ERROR;
+    }
+
+    ss = (deflate_state *) source->state;
+
+    *dest = *source;
+
+    mem = (deflate_workspace *) dest->workspace;
+
+    ds = &(mem->deflate_memory);
+
+    dest->state = (struct internal_state FAR *) ds;
+    *ds = *ss;
+    ds->strm = dest;
+
+    ds->window = (Bytef *) mem->window_memory;
+    ds->prev   = (Posf *)  mem->prev_memory;
+    ds->head   = (Posf *)  mem->head_memory;
+    overlay = (ushf *) mem->overlay_memory;
+    ds->pending_buf = (uchf *) overlay;
+
+    memcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+    memcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+    memcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+    memcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+    ds->l_desc.dyn_tree = ds->dyn_ltree;
+    ds->d_desc.dyn_tree = ds->dyn_dtree;
+    ds->bl_desc.dyn_tree = ds->bl_tree;
+
+    return Z_OK;
+#endif
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.  All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+    z_streamp strm;
+    Bytef *buf;
+    unsigned size;
+{
+    unsigned len = strm->avail_in;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    if (!((deflate_state *)(strm->state))->noheader) {
+        strm->adler = zlib_adler32(strm->adler, strm->next_in, len);
+    }
+    memcpy(buf, strm->next_in, len);
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+    deflate_state *s;
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->ins_h = 0;
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = s->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    register Byte scan_end1  = scan[best_len-1];
+    register Byte scan_end   = scan[best_len];
+#endif
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2:
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ushf*)(match+best_len-1) != scan_end ||
+            *(ushf*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        Assert(scan[2] == match[2], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ushf*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & wmask]) > limit
+             && --chain_length != 0);
+
+    if ((uInt)best_len <= s->lookahead) return best_len;
+    return s->lookahead;
+}
+
+#ifdef DEBUG_ZLIB
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+    deflate_state *s;
+    IPos start, match;
+    int length;
+{
+    /* check that the match is indeed a match */
+    if (memcmp((charf *)s->window + match,
+                (charf *)s->window + start, length) != EQUAL) {
+        fprintf(stderr, " start %u, match %u, length %d\n",
+		start, match, length);
+        do {
+	    fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+	} while (--length != 0);
+        z_error("invalid match");
+    }
+    if (z_verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(s->window[start++], stderr); } while (--length != 0);
+    }
+}
+#else
+#  define check_match(s, start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ *    At least one byte has been read, or avail_in == 0; reads are
+ *    performed for at least two bytes (required for the zip translate_eol
+ *    option -- not supported here).
+ */
+local void fill_window(s)
+    deflate_state *s;
+{
+    register unsigned n, m;
+    register Posf *p;
+    unsigned more;    /* Amount of free space at the end of the window. */
+    uInt wsize = s->w_size;
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+            more = wsize;
+
+        } else if (more == (unsigned)(-1)) {
+            /* Very unlikely, but possible on 16 bit machine if strstart == 0
+             * and lookahead == 1 (input done one byte at time)
+             */
+            more--;
+
+        /* If the window is almost full and there is insufficient lookahead,
+         * move the upper half to the lower one to make room in the upper half.
+         */
+        } else if (s->strstart >= wsize+MAX_DIST(s)) {
+
+            memcpy((charf *)s->window, (charf *)s->window+wsize,
+                   (unsigned)wsize);
+            s->match_start -= wsize;
+            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
+            s->block_start -= (long) wsize;
+
+            /* Slide the hash table (could be avoided with 32 bit values
+               at the expense of memory usage). We slide even when level == 0
+               to keep the hash table consistent if we switch back to level > 0
+               later. (Using level 0 permanently is not an optimal usage of
+               zlib, so we don't care about this pathological case.)
+             */
+            n = s->hash_size;
+            p = &s->head[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+            } while (--n);
+
+            n = wsize;
+            p = &s->prev[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+                /* If n is not on any hash chain, prev[n] is garbage but
+                 * its value will never be used.
+                 */
+            } while (--n);
+            more += wsize;
+        }
+        if (s->strm->avail_in == 0) return;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the BIG_MEM or MMAP case (not yet supported),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+        s->lookahead += n;
+
+        /* Initialize the hash value now that we have some input: */
+        if (s->lookahead >= MIN_MATCH) {
+            s->ins_h = s->window[s->strstart];
+            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+            Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+        }
+        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+         * but this is not important since only literal bytes will be emitted.
+         */
+
+    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+   zlib_tr_flush_block(s, (s->block_start >= 0L ? \
+                   (charf *)&s->window[(unsigned)s->block_start] : \
+                   (charf *)Z_NULL), \
+		(ulg)((long)s->strstart - s->block_start), \
+		(eof)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+   FLUSH_BLOCK_ONLY(s, eof); \
+   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+     * to pending_buf_size, and each stored block has a 5 byte header:
+     */
+    ulg max_block_size = 0xffff;
+    ulg max_start;
+
+    if (max_block_size > s->pending_buf_size - 5) {
+        max_block_size = s->pending_buf_size - 5;
+    }
+
+    /* Copy as much as possible from input to output: */
+    for (;;) {
+        /* Fill the window as much as possible: */
+        if (s->lookahead <= 1) {
+
+            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+		   s->block_start >= (long)s->w_size, "slide too late");
+
+            fill_window(s);
+            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+	Assert(s->block_start >= 0L, "block gone");
+
+	s->strstart += s->lookahead;
+	s->lookahead = 0;
+
+	/* Emit a stored block if pending_buf will be full: */
+ 	max_start = s->block_start + max_block_size;
+        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+	    /* strstart == 0 is possible when wraparound on 16-bit machine */
+	    s->lookahead = (uInt)(s->strstart - max_start);
+	    s->strstart = (uInt)max_start;
+            FLUSH_BLOCK(s, 0);
+	}
+	/* Flush if we may have to slide, otherwise block_start may become
+         * negative and the data will be gone:
+         */
+        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+            FLUSH_BLOCK(s, 0);
+	}
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL; /* head of the hash chain */
+    int bflush;           /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+	        return need_more;
+	    }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+        }
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->match_start, s->match_length);
+
+            bflush = zlib_tr_tally(s, s->strstart - s->match_start,
+                               s->match_length - MIN_MATCH);
+
+            s->lookahead -= s->match_length;
+
+            /* Insert new strings in the hash table only if the match length
+             * is not too large. This saves time but degrades compression.
+             */
+            if (s->match_length <= s->max_insert_length &&
+                s->lookahead >= MIN_MATCH) {
+                s->match_length--; /* string at strstart already in hash table */
+                do {
+                    s->strstart++;
+                    INSERT_STRING(s, s->strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                } while (--s->match_length != 0);
+                s->strstart++; 
+            } else {
+                s->strstart += s->match_length;
+                s->match_length = 0;
+                s->ins_h = s->window[s->strstart];
+                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+                 * matter since it will be recomputed at next deflate call.
+                 */
+            }
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            bflush = zlib_tr_tally (s, 0, s->window[s->strstart]);
+            s->lookahead--;
+            s->strstart++; 
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL;    /* head of hash chain */
+    int bflush;              /* set if current block must be flushed */
+
+    /* Process the input block. */
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+	        return need_more;
+	    }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        s->prev_length = s->match_length, s->prev_match = s->match_start;
+        s->match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+            s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
+                 (s->match_length == MIN_MATCH &&
+                  s->strstart - s->match_start > TOO_FAR))) {
+
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                s->match_length = MIN_MATCH-1;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+            /* Do not insert strings in hash table beyond this. */
+
+            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+            bflush = zlib_tr_tally(s, s->strstart -1 - s->prev_match,
+				   s->prev_length - MIN_MATCH);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted. If there is not
+             * enough lookahead, the last two strings are not inserted in
+             * the hash table.
+             */
+            s->lookahead -= s->prev_length-1;
+            s->prev_length -= 2;
+            do {
+                if (++s->strstart <= max_insert) {
+                    INSERT_STRING(s, s->strstart, hash_head);
+                }
+            } while (--s->prev_length != 0);
+            s->match_available = 0;
+            s->match_length = MIN_MATCH-1;
+            s->strstart++;
+
+            if (bflush) FLUSH_BLOCK(s, 0);
+
+        } else if (s->match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c", s->window[s->strstart-1]));
+            if (zlib_tr_tally (s, 0, s->window[s->strstart-1])) {
+                FLUSH_BLOCK_ONLY(s, 0);
+            }
+            s->strstart++;
+            s->lookahead--;
+            if (s->strm->avail_out == 0) return need_more;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            s->match_available = 1;
+            s->strstart++;
+            s->lookahead--;
+        }
+    }
+    Assert (flush != Z_NO_FLUSH, "no flush?");
+    if (s->match_available) {
+        Tracevv((stderr,"%c", s->window[s->strstart-1]));
+        zlib_tr_tally (s, 0, s->window[s->strstart-1]);
+        s->match_available = 0;
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+ZEXTERN int ZEXPORT zlib_deflate_workspacesize ()
+{
+    return sizeof(deflate_workspace);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_deflate/deflate_syms.c linux-2.4.20/lib/zlib_deflate/deflate_syms.c
--- linux-2.4.19/lib/zlib_deflate/deflate_syms.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_deflate/deflate_syms.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,21 @@
+/*
+ * linux/lib/zlib_deflate/deflate_syms.c
+ *
+ * Exported symbols for the deflate functionality.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/zlib.h>
+
+EXPORT_SYMBOL(zlib_deflate_workspacesize);
+EXPORT_SYMBOL(zlib_deflate);
+EXPORT_SYMBOL(zlib_deflateInit_);
+EXPORT_SYMBOL(zlib_deflateInit2_);
+EXPORT_SYMBOL(zlib_deflateEnd);
+EXPORT_SYMBOL(zlib_deflateReset);
+EXPORT_SYMBOL(zlib_deflateCopy);
+EXPORT_SYMBOL(zlib_deflateParams);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_deflate/deftree.c linux-2.4.20/lib/zlib_deflate/deftree.c
--- linux-2.4.19/lib/zlib_deflate/deftree.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_deflate/deftree.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,1096 @@
+/* +++ trees.c */
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-1996 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values).  The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */
+
+/* #include "deflate.h" */
+
+#include <linux/zutil.h>
+#include "defutil.h"
+
+#ifdef DEBUG_ZLIB
+#  include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see zlib_tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+local uch dist_code[512];
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+local uch length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+struct static_tree_desc_s {
+    const ct_data *static_tree;  /* static tree or NULL */
+    const intf *extra_bits;      /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+};
+
+local static_tree_desc  static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc  static_d_desc =
+{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
+
+local static_tree_desc  static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block     OF((deflate_state *s));
+local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
+local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree     OF((deflate_state *s, tree_desc *desc));
+local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local int  build_bl_tree  OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+                              int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+                              ct_data *dtree));
+local void set_data_type  OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup      OF((deflate_state *s));
+local void bi_flush       OF((deflate_state *s));
+local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
+                              int header));
+
+#ifndef DEBUG_ZLIB
+#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG_ZLIB */
+#  define send_code(s, c, tree) \
+     { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+#define d_code(dist) \
+   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ */
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG_ZLIB
+local void send_bits      OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+    deflate_state *s;
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+    Tracevv((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    s->bits_sent += (ulg)length;
+
+    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+     * unused bits in value.
+     */
+    if (s->bi_valid > (int)Buf_size - length) {
+        s->bi_buf |= (value << s->bi_valid);
+        put_short(s, s->bi_buf);
+        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+        s->bi_valid += length - Buf_size;
+    } else {
+        s->bi_buf |= value << s->bi_valid;
+        s->bi_valid += length;
+    }
+}
+#else /* !DEBUG_ZLIB */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+  if (s->bi_valid > (int)Buf_size - len) {\
+    int val = value;\
+    s->bi_buf |= (val << s->bi_valid);\
+    put_short(s, s->bi_buf);\
+    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+    s->bi_valid += len - Buf_size;\
+  } else {\
+    s->bi_buf |= (value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* DEBUG_ZLIB */
+
+
+#define MAX(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables. In a multi-threaded environment,
+ * this function may be called by two threads concurrently, but this is
+ * harmless since both invocations do exactly the same thing.
+ */
+local void tr_static_init()
+{
+    static int static_init_done = 0;
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    if (static_init_done) return;
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "tr_static_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+    }
+    static_init_done = 1;
+}
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void zlib_tr_init(s)
+    deflate_state *s;
+{
+    tr_static_init();
+
+    s->compressed_len = 0L;
+
+    s->l_desc.dyn_tree = s->dyn_ltree;
+    s->l_desc.stat_desc = &static_l_desc;
+
+    s->d_desc.dyn_tree = s->dyn_dtree;
+    s->d_desc.stat_desc = &static_d_desc;
+
+    s->bl_desc.dyn_tree = s->bl_tree;
+    s->bl_desc.stat_desc = &static_bl_desc;
+
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG_ZLIB
+    s->bits_sent = 0L;
+#endif
+
+    /* Initialize the first block of the first file: */
+    init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+    deflate_state *s;
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+    s->dyn_ltree[END_BLOCK].Freq = 1;
+    s->opt_len = s->static_len = 0L;
+    s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+    top = s->heap[SMALLEST]; \
+    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+    pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+    deflate_state *s;
+    ct_data *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    int v = s->heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= s->heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < s->heap_len &&
+            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+            j++;
+        }
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+        /* Exchange v with the smallest son */
+        s->heap[k] = s->heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen(s, desc)
+    deflate_state *s;
+    tree_desc *desc;    /* the tree descriptor */
+{
+    ct_data *tree        = desc->dyn_tree;
+    int max_code         = desc->max_code;
+    const ct_data *stree = desc->stat_desc->static_tree;
+    const intf *extra    = desc->stat_desc->extra_bits;
+    int base             = desc->stat_desc->extra_base;
+    int max_length       = desc->stat_desc->max_length;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+        n = s->heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        s->bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        s->opt_len += (ulg)f * (bits + xbits);
+        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (s->bl_count[bits] == 0) bits--;
+        s->bl_count[bits]--;      /* move one leaf down the tree */
+        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        s->bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = s->bl_count[bits];
+        while (n != 0) {
+            m = s->heap[--h];
+            if (m > max_code) continue;
+            if (tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                s->opt_len += ((long)bits - (long)tree[m].Len)
+                              *(long)tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+    ct_data *tree;             /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+    ushf *bl_count;            /* number of codes at each bit length */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    ush code = 0;              /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = bi_reverse(next_code[len]++, len);
+
+        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+    deflate_state *s;
+    tree_desc *desc; /* the tree descriptor */
+{
+    ct_data *tree         = desc->dyn_tree;
+    const ct_data *stree  = desc->stat_desc->static_tree;
+    int elems             = desc->stat_desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node;          /* new node being created */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            s->heap[++(s->heap_len)] = max_code = n;
+            s->depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (s->heap_len < 2) {
+        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+        tree[node].Freq = 1;
+        s->depth[node] = 0;
+        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+        /* node is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    node = elems;              /* next internal node of the tree */
+    do {
+        pqremove(s, tree, n);  /* n = node of least frequency */
+        m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+        s->heap[--(s->heap_max)] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == s->bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        s->heap[SMALLEST] = node++;
+        pqdownheap(s, tree, SMALLEST);
+
+    } while (s->heap_len >= 2);
+
+    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen(s, (tree_desc *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree;   /* the tree to be scanned */
+    int max_code;    /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            s->bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+            s->bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            s->bl_tree[REPZ_3_10].Freq++;
+        } else {
+            s->bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(s, curlen, s->bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+        } else {
+            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+    deflate_state *s;
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree(s, (tree_desc *)(&(s->bl_desc)));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    s->opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+            s->opt_len, s->static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+    deflate_state *s;
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+    send_bits(s, dcodes-1,   5);
+    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void zlib_tr_stored_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
+    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+    s->compressed_len += (stored_len + 4) << 3;
+
+    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* Send just the `stored block' type code without any length bytes or data.
+ */
+void zlib_tr_stored_type_only(s)
+    deflate_state *s;
+{
+    send_bits(s, (STORED_BLOCK << 1), 3);
+    bi_windup(s);
+    s->compressed_len = (s->compressed_len + 3) & ~7L;
+}
+
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void zlib_tr_align(s)
+    deflate_state *s;
+{
+    send_bits(s, STATIC_TREES<<1, 3);
+    send_code(s, END_BLOCK, static_ltree);
+    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+    bi_flush(s);
+    /* Of the 10 bits for the empty block, we have already sent
+     * (10 - bi_valid) bits. The lookahead for the last real code (before
+     * the EOB of the previous block) was thus at least one plus the length
+     * of the EOB plus what we have just sent of the empty static block.
+     */
+    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+        send_bits(s, STATIC_TREES<<1, 3);
+        send_code(s, END_BLOCK, static_ltree);
+        s->compressed_len += 10L;
+        bi_flush(s);
+    }
+    s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length for the file so far.
+ */
+ulg zlib_tr_flush_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex = 0;  /* index of last bit length code of non zero freq */
+
+    /* Build the Huffman trees unless a stored block is forced */
+    if (s->level > 0) {
+
+	 /* Check if the file is ascii or binary */
+	if (s->data_type == Z_UNKNOWN) set_data_type(s);
+
+	/* Construct the literal and distance trees */
+	build_tree(s, (tree_desc *)(&(s->l_desc)));
+	Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+		s->static_len));
+
+	build_tree(s, (tree_desc *)(&(s->d_desc)));
+	Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+		s->static_len));
+	/* At this point, opt_len and static_len are the total bit lengths of
+	 * the compressed block data, excluding the tree representations.
+	 */
+
+	/* Build the bit length tree for the above two trees, and get the index
+	 * in bl_order of the last bit length code to send.
+	 */
+	max_blindex = build_bl_tree(s);
+
+	/* Determine the best encoding. Compute first the block length in bytes*/
+	opt_lenb = (s->opt_len+3+7)>>3;
+	static_lenb = (s->static_len+3+7)>>3;
+
+	Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+		opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+		s->last_lit));
+
+	if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    } else {
+        Assert(buf != (char*)0, "lost buf");
+	opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+    }
+
+    /* If compression failed and this is the first and last block,
+     * and if the .zip file can be seeked (to rewrite the local header),
+     * the whole file is transformed into a stored file:
+     */
+#ifdef STORED_FILE_OK
+#  ifdef FORCE_STORED_FILE
+    if (eof && s->compressed_len == 0L) { /* force stored file */
+#  else
+    if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) {
+#  endif
+        /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+        if (buf == (charf*)0) error ("block vanished");
+
+        copy_block(s, buf, (unsigned)stored_len, 0); /* without header */
+        s->compressed_len = stored_len << 3;
+        s->method = STORED;
+    } else
+#endif /* STORED_FILE_OK */
+
+#ifdef FORCE_STORED
+    if (buf != (char*)0) { /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        zlib_tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+    } else if (static_lenb >= 0) { /* force static trees */
+#else
+    } else if (static_lenb == opt_lenb) {
+#endif
+        send_bits(s, (STATIC_TREES<<1)+eof, 3);
+        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+        s->compressed_len += 3 + s->static_len;
+    } else {
+        send_bits(s, (DYN_TREES<<1)+eof, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+        s->compressed_len += 3 + s->opt_len;
+    }
+    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+    init_block(s);
+
+    if (eof) {
+        bi_windup(s);
+        s->compressed_len += 7;  /* align on byte boundary */
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+           s->compressed_len-7*eof));
+
+    return s->compressed_len >> 3;
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int zlib_tr_tally (s, dist, lc)
+    deflate_state *s;
+    unsigned dist;  /* distance of matched string */
+    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    s->d_buf[s->last_lit] = (ush)dist;
+    s->l_buf[s->last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        s->dyn_ltree[lc].Freq++;
+    } else {
+        s->matches++;
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST(s) &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "zlib_tr_tally: bad match");
+
+        s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
+        s->dyn_dtree[d_code(dist)].Freq++;
+    }
+
+    /* Try to guess if it is profitable to stop the current block here */
+    if ((s->last_lit & 0xfff) == 0 && s->level > 2) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)s->last_lit*8L;
+        ulg in_length = (ulg)((long)s->strstart - s->block_start);
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)s->dyn_dtree[dcode].Freq *
+                (5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+               s->last_lit, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+    }
+    return (s->last_lit == s->lit_bufsize-1);
+    /* We avoid equality with lit_bufsize because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+    deflate_state *s;
+    ct_data *ltree; /* literal tree */
+    ct_data *dtree; /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (s->last_lit != 0) do {
+        dist = s->d_buf[lx];
+        lc = s->l_buf[lx++];
+        if (dist == 0) {
+            send_code(s, lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = length_code[lc];
+            send_code(s, code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(s, lc, extra);       /* send the extra length bits */
+            }
+            dist--; /* dist is now the match distance - 1 */
+            code = d_code(dist);
+            Assert (code < D_CODES, "bad d_code");
+
+            send_code(s, code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= base_dist[code];
+                send_bits(s, dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+
+        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+        Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+    s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_data_type(s)
+    deflate_state *s;
+{
+    int n = 0;
+    unsigned ascii_freq = 0;
+    unsigned bin_freq = 0;
+    while (n < 7)        bin_freq += s->dyn_ltree[n++].Freq;
+    while (n < 128)    ascii_freq += s->dyn_ltree[n++].Freq;
+    while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+    s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+    deflate_state *s;
+    charf    *buf;    /* the input data */
+    unsigned len;     /* its length */
+    int      header;  /* true if block header must be written */
+{
+    bi_windup(s);        /* align on byte boundary */
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+
+    if (header) {
+        put_short(s, (ush)len);   
+        put_short(s, (ush)~len);
+#ifdef DEBUG_ZLIB
+        s->bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG_ZLIB
+    s->bits_sent += (ulg)len<<3;
+#endif
+    /* bundle up the put_byte(s, *buf++) calls */
+    memcpy(&s->pending_buf[s->pending], buf, len);
+    s->pending += len;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_deflate/defutil.h linux-2.4.20/lib/zlib_deflate/defutil.h
--- linux-2.4.19/lib/zlib_deflate/defutil.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_deflate/defutil.h	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,335 @@
+
+
+
+#define Assert(err, str) 
+#define Trace(dummy) 
+#define Tracev(dummy) 
+#define Tracecv(err, dummy) 
+#define Tracevv(dummy) 
+
+
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE    42
+#define BUSY_STATE   113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+typedef struct static_tree_desc_s  static_tree_desc;
+
+typedef struct tree_desc_s {
+    ct_data *dyn_tree;           /* the dynamic tree */
+    int     max_code;            /* largest code with non zero frequency */
+    static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct deflate_state {
+    z_streamp strm;      /* pointer back to this zlib stream */
+    int   status;        /* as the name implies */
+    Bytef *pending_buf;  /* output still pending */
+    ulg   pending_buf_size; /* size of pending_buf */
+    Bytef *pending_out;  /* next pending byte to output to the stream */
+    int   pending;       /* nb of bytes in the pending buffer */
+    int   noheader;      /* suppress zlib header and adler32 */
+    Byte  data_type;     /* UNKNOWN, BINARY or ASCII */
+    Byte  method;        /* STORED (for zip only) or DEFLATED */
+    int   last_flush;    /* value of flush param for previous deflate call */
+
+                /* used by deflate.c: */
+
+    uInt  w_size;        /* LZ77 window size (32K by default) */
+    uInt  w_bits;        /* log2(w_size)  (8..16) */
+    uInt  w_mask;        /* w_size - 1 */
+
+    Bytef *window;
+    /* Sliding window. Input bytes are read into the second half of the window,
+     * and move to the first half later to keep a dictionary of at least wSize
+     * bytes. With this organization, matches are limited to a distance of
+     * wSize-MAX_MATCH bytes, but this ensures that IO is always
+     * performed with a length multiple of the block size. Also, it limits
+     * the window size to 64K, which is quite useful on MSDOS.
+     * To do: use the user input buffer as sliding window.
+     */
+
+    ulg window_size;
+    /* Actual size of window: 2*wSize, except when the user input buffer
+     * is directly used as sliding window.
+     */
+
+    Posf *prev;
+    /* Link to older string with same hash index. To limit the size of this
+     * array to 64K, this link is maintained only for the last 32K strings.
+     * An index in this array is thus a window index modulo 32K.
+     */
+
+    Posf *head; /* Heads of the hash chains or NIL. */
+
+    uInt  ins_h;          /* hash index of string to be inserted */
+    uInt  hash_size;      /* number of elements in hash table */
+    uInt  hash_bits;      /* log2(hash_size) */
+    uInt  hash_mask;      /* hash_size-1 */
+
+    uInt  hash_shift;
+    /* Number of bits by which ins_h must be shifted at each input
+     * step. It must be such that after MIN_MATCH steps, the oldest
+     * byte no longer takes part in the hash key, that is:
+     *   hash_shift * MIN_MATCH >= hash_bits
+     */
+
+    long block_start;
+    /* Window position at the beginning of the current output block. Gets
+     * negative when the window is moved backwards.
+     */
+
+    uInt match_length;           /* length of best match */
+    IPos prev_match;             /* previous match */
+    int match_available;         /* set if previous match exists */
+    uInt strstart;               /* start of string to insert */
+    uInt match_start;            /* start of matching string */
+    uInt lookahead;              /* number of valid bytes ahead in window */
+
+    uInt prev_length;
+    /* Length of the best match at previous step. Matches not greater than this
+     * are discarded. This is used in the lazy match evaluation.
+     */
+
+    uInt max_chain_length;
+    /* To speed up deflation, hash chains are never searched beyond this
+     * length.  A higher limit improves compression ratio but degrades the
+     * speed.
+     */
+
+    uInt max_lazy_match;
+    /* Attempt to find a better match only when the current match is strictly
+     * smaller than this value. This mechanism is used only for compression
+     * levels >= 4.
+     */
+#   define max_insert_length  max_lazy_match
+    /* Insert new strings in the hash table only if the match length is not
+     * greater than this length. This saves time but degrades compression.
+     * max_insert_length is used only for compression levels <= 3.
+     */
+
+    int level;    /* compression level (1..9) */
+    int strategy; /* favor or force Huffman coding*/
+
+    uInt good_match;
+    /* Use a faster search when the previous match is longer than this */
+
+    int nice_match; /* Stop searching when current match exceeds this */
+
+                /* used by trees.c: */
+    /* Didn't use ct_data typedef below to supress compiler warning */
+    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
+
+    struct tree_desc_s l_desc;               /* desc. for literal tree */
+    struct tree_desc_s d_desc;               /* desc. for distance tree */
+    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
+
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
+    int heap_len;               /* number of elements in the heap */
+    int heap_max;               /* element of largest frequency */
+    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+     * The same heap array is used to build all trees.
+     */
+
+    uch depth[2*L_CODES+1];
+    /* Depth of each subtree used as tie breaker for trees of equal frequency
+     */
+
+    uchf *l_buf;          /* buffer for literals or lengths */
+
+    uInt  lit_bufsize;
+    /* Size of match buffer for literals/lengths.  There are 4 reasons for
+     * limiting lit_bufsize to 64K:
+     *   - frequencies can be kept in 16 bit counters
+     *   - if compression is not successful for the first block, all input
+     *     data is still in the window so we can still emit a stored block even
+     *     when input comes from standard input.  (This can also be done for
+     *     all blocks if lit_bufsize is not greater than 32K.)
+     *   - if compression is not successful for a file smaller than 64K, we can
+     *     even emit a stored file instead of a stored block (saving 5 bytes).
+     *     This is applicable only for zip (not gzip or zlib).
+     *   - creating new Huffman trees less frequently may not provide fast
+     *     adaptation to changes in the input data statistics. (Take for
+     *     example a binary file with poorly compressible code followed by
+     *     a highly compressible string table.) Smaller buffer sizes give
+     *     fast adaptation but have of course the overhead of transmitting
+     *     trees more frequently.
+     *   - I can't count above 4
+     */
+
+    uInt last_lit;      /* running index in l_buf */
+
+    ushf *d_buf;
+    /* Buffer for distances. To simplify the code, d_buf and l_buf have
+     * the same number of elements. To use different lengths, an extra flag
+     * array would be necessary.
+     */
+
+    ulg opt_len;        /* bit length of current block with optimal trees */
+    ulg static_len;     /* bit length of current block with static trees */
+    ulg compressed_len; /* total bit length of compressed file */
+    uInt matches;       /* number of string matches in current block */
+    int last_eob_len;   /* bit length of EOB code for last block */
+
+#ifdef DEBUG_ZLIB
+    ulg bits_sent;      /* bit length of the compressed data */
+#endif
+
+    ush bi_buf;
+    /* Output buffer. bits are inserted starting at the bottom (least
+     * significant bits).
+     */
+    int bi_valid;
+    /* Number of valid bits in bi_buf.  All bits above the last valid bit
+     * are always zero.
+     */
+
+} FAR deflate_state;
+
+typedef struct deflate_workspace {
+    /* State memory for the deflator */
+    deflate_state deflate_memory;
+    Byte window_memory[2 * (1 << MAX_WBITS)];
+    Pos prev_memory[1 << MAX_WBITS];
+    Pos head_memory[1 << (MAX_MEM_LEVEL + 7)];
+    char overlay_memory[(1 << (MAX_MEM_LEVEL + 6)) * (sizeof(ush)+2)];
+} deflate_workspace;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+        /* in trees.c */
+void zlib_tr_init         OF((deflate_state *s));
+int  zlib_tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
+ulg  zlib_tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
+			      int eof));
+void zlib_tr_align        OF((deflate_state *s));
+void zlib_tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+			      int eof));
+void zlib_tr_stored_type_only OF((deflate_state *));
+
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+    put_byte(s, (uch)((w) & 0xff)); \
+    put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+static inline unsigned bi_reverse(unsigned code, /* the value to invert */
+				  int len)       /* its bit length */
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+static inline void bi_flush(deflate_state *s)
+{
+    if (s->bi_valid == 16) {
+        put_short(s, s->bi_buf);
+        s->bi_buf = 0;
+        s->bi_valid = 0;
+    } else if (s->bi_valid >= 8) {
+        put_byte(s, (Byte)s->bi_buf);
+        s->bi_buf >>= 8;
+        s->bi_valid -= 8;
+    }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+static inline void bi_windup(deflate_state *s)
+{
+    if (s->bi_valid > 8) {
+        put_short(s, s->bi_buf);
+    } else if (s->bi_valid > 0) {
+        put_byte(s, (Byte)s->bi_buf);
+    }
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef DEBUG_ZLIB
+    s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_inflate/Makefile linux-2.4.20/lib/zlib_inflate/Makefile
--- linux-2.4.19/lib/zlib_inflate/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_inflate/Makefile	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,26 @@
+#
+# This is a modified version of zlib, which does all memory
+# allocation ahead of time.
+#
+# This is only the decompression, see zlib_deflate for the
+# the compression
+#
+# Decompression needs to be serialized for each memory
+# allocation.
+#
+# (The upsides of the simplification is that you can't get in
+# any nasty situations wrt memory management, and that the
+# uncompression can be done without blocking on allocation).
+#
+
+O_TARGET    := zlib_inflate.o
+
+export-objs := inflate_syms.o
+
+obj-y := infblock.o infcodes.o inffast.o inflate.o \
+	 inftrees.o infutil.o inflate_syms.o
+obj-m := $(O_TARGET)
+
+EXTRA_CFLAGS += -I $(TOPDIR)/lib/zlib_inflate
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_inflate/infblock.c linux-2.4.20/lib/zlib_inflate/infblock.c
--- linux-2.4.19/lib/zlib_inflate/infblock.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_inflate/infblock.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,355 @@
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/zutil.h>
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state;
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local const uInt border[] = { /* Order of the bit length code lengths */
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarily, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+ */
+
+
+void zlib_inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+  if (c != Z_NULL)
+    *c = s->check;
+  if (s->mode == CODES)
+    zlib_inflate_codes_free(s->sub.decode.codes, z);
+  s->mode = TYPE;
+  s->bitk = 0;
+  s->bitb = 0;
+  s->read = s->write = s->window;
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
+}
+
+inflate_blocks_statef *zlib_inflate_blocks_new(z, c, w)
+z_streamp z;
+check_func c;
+uInt w;
+{
+  inflate_blocks_statef *s;
+
+  s = &WS(z)->working_blocks_state;
+  s->hufts = WS(z)->working_hufts;
+  s->window = WS(z)->working_window;
+  s->end = s->window + w;
+  s->checkfn = c;
+  s->mode = TYPE;
+  zlib_inflate_blocks_reset(s, z, Z_NULL);
+  return s;
+}
+
+
+int zlib_inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt t;               /* temporary storage */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input based on current state */
+  while (1) switch (s->mode)
+  {
+    case TYPE:
+      NEEDBITS(3)
+      t = (uInt)b & 7;
+      s->last = t & 1;
+      switch (t >> 1)
+      {
+        case 0:                         /* stored */
+          DUMPBITS(3)
+          t = k & 7;                    /* go to byte boundary */
+          DUMPBITS(t)
+          s->mode = LENS;               /* get length of stored block */
+          break;
+        case 1:                         /* fixed */
+          {
+            uInt bl, bd;
+            inflate_huft *tl, *td;
+
+            zlib_inflate_trees_fixed(&bl, &bd, &tl, &td, z);
+            s->sub.decode.codes = zlib_inflate_codes_new(bl, bd, tl, td, z);
+            if (s->sub.decode.codes == Z_NULL)
+            {
+              r = Z_MEM_ERROR;
+              LEAVE
+            }
+          }
+          DUMPBITS(3)
+          s->mode = CODES;
+          break;
+        case 2:                         /* dynamic */
+          DUMPBITS(3)
+          s->mode = TABLE;
+          break;
+        case 3:                         /* illegal */
+          DUMPBITS(3)
+          s->mode = B_BAD;
+          z->msg = (char*)"invalid block type";
+          r = Z_DATA_ERROR;
+          LEAVE
+      }
+      break;
+    case LENS:
+      NEEDBITS(32)
+      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+      {
+        s->mode = B_BAD;
+        z->msg = (char*)"invalid stored block lengths";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+      s->sub.left = (uInt)b & 0xffff;
+      b = k = 0;                      /* dump bits */
+      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+      break;
+    case STORED:
+      if (n == 0)
+        LEAVE
+      NEEDOUT
+      t = s->sub.left;
+      if (t > n) t = n;
+      if (t > m) t = m;
+      memcpy(q, p, t);
+      p += t;  n -= t;
+      q += t;  m -= t;
+      if ((s->sub.left -= t) != 0)
+        break;
+      s->mode = s->last ? DRY : TYPE;
+      break;
+    case TABLE:
+      NEEDBITS(14)
+      s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+      {
+        s->mode = B_BAD;
+        z->msg = (char*)"too many length or distance symbols";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+#endif
+      {
+      	s->sub.trees.blens = WS(z)->working_blens;
+      }
+      DUMPBITS(14)
+      s->sub.trees.index = 0;
+      s->mode = BTREE;
+    case BTREE:
+      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+      {
+        NEEDBITS(3)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+        DUMPBITS(3)
+      }
+      while (s->sub.trees.index < 19)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+      s->sub.trees.bb = 7;
+      t = zlib_inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+				  &s->sub.trees.tb, s->hufts, z);
+      if (t != Z_OK)
+      {
+        r = t;
+        if (r == Z_DATA_ERROR)
+          s->mode = B_BAD;
+        LEAVE
+      }
+      s->sub.trees.index = 0;
+      s->mode = DTREE;
+    case DTREE:
+      while (t = s->sub.trees.table,
+             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+      {
+        inflate_huft *h;
+        uInt i, j, c;
+
+        t = s->sub.trees.bb;
+        NEEDBITS(t)
+        h = s->sub.trees.tb + ((uInt)b & zlib_inflate_mask[t]);
+        t = h->bits;
+        c = h->base;
+        if (c < 16)
+        {
+          DUMPBITS(t)
+          s->sub.trees.blens[s->sub.trees.index++] = c;
+        }
+        else /* c == 16..18 */
+        {
+          i = c == 18 ? 7 : c - 14;
+          j = c == 18 ? 11 : 3;
+          NEEDBITS(t + i)
+          DUMPBITS(t)
+          j += (uInt)b & zlib_inflate_mask[i];
+          DUMPBITS(i)
+          i = s->sub.trees.index;
+          t = s->sub.trees.table;
+          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+              (c == 16 && i < 1))
+          {
+            s->mode = B_BAD;
+            z->msg = (char*)"invalid bit length repeat";
+            r = Z_DATA_ERROR;
+            LEAVE
+          }
+          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+          do {
+            s->sub.trees.blens[i++] = c;
+          } while (--j);
+          s->sub.trees.index = i;
+        }
+      }
+      s->sub.trees.tb = Z_NULL;
+      {
+        uInt bl, bd;
+        inflate_huft *tl, *td;
+        inflate_codes_statef *c;
+
+        bl = 9;         /* must be <= 9 for lookahead assumptions */
+        bd = 6;         /* must be <= 9 for lookahead assumptions */
+        t = s->sub.trees.table;
+        t = zlib_inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+				       s->sub.trees.blens, &bl, &bd, &tl, &td,
+				       s->hufts, z);
+        if (t != Z_OK)
+        {
+          if (t == (uInt)Z_DATA_ERROR)
+            s->mode = B_BAD;
+          r = t;
+          LEAVE
+        }
+        if ((c = zlib_inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+        {
+          r = Z_MEM_ERROR;
+          LEAVE
+        }
+        s->sub.decode.codes = c;
+      }
+      s->mode = CODES;
+    case CODES:
+      UPDATE
+      if ((r = zlib_inflate_codes(s, z, r)) != Z_STREAM_END)
+        return zlib_inflate_flush(s, z, r);
+      r = Z_OK;
+      zlib_inflate_codes_free(s->sub.decode.codes, z);
+      LOAD
+      if (!s->last)
+      {
+        s->mode = TYPE;
+        break;
+      }
+      s->mode = DRY;
+    case DRY:
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      s->mode = B_DONE;
+    case B_DONE:
+      r = Z_STREAM_END;
+      LEAVE
+    case B_BAD:
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+int zlib_inflate_blocks_free(s, z)
+inflate_blocks_statef *s;
+z_streamp z;
+{
+  zlib_inflate_blocks_reset(s, z, Z_NULL);
+  return Z_OK;
+}
+
+
+void zlib_inflate_set_dictionary(s, d, n)
+inflate_blocks_statef *s;
+const Bytef *d;
+uInt  n;
+{
+  memcpy(s->window, d, n);
+  s->read = s->write = s->window + n;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. 
+ * IN assertion: s != Z_NULL
+ */
+int zlib_inflate_blocks_sync_point(s)
+inflate_blocks_statef *s;
+{
+  return s->mode == LENS;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_inflate/infblock.h linux-2.4.20/lib/zlib_inflate/infblock.h
--- linux-2.4.19/lib/zlib_inflate/infblock.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_inflate/infblock.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,44 @@
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFBLOCK_H
+#define _INFBLOCK_H
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+extern inflate_blocks_statef * zlib_inflate_blocks_new OF((
+    z_streamp z,
+    check_func c,               /* check function */
+    uInt w));                   /* window size */
+
+extern int zlib_inflate_blocks OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));                      /* initial return code */
+
+extern void zlib_inflate_blocks_reset OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    uLongf *));                  /* check value on output */
+
+extern int zlib_inflate_blocks_free OF((
+    inflate_blocks_statef *,
+    z_streamp));
+
+extern void zlib_inflate_set_dictionary OF((
+    inflate_blocks_statef *s,
+    const Bytef *d,  /* dictionary */
+    uInt  n));       /* dictionary length */
+
+extern int zlib_inflate_blocks_sync_point OF((
+    inflate_blocks_statef *s));
+
+#endif /* _INFBLOCK_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_inflate/infcodes.c linux-2.4.20/lib/zlib_inflate/infcodes.c
--- linux-2.4.19/lib/zlib_inflate/infcodes.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_inflate/infcodes.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,204 @@
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/zutil.h>
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+inflate_codes_statef *zlib_inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+z_streamp z;
+{
+  inflate_codes_statef *c;
+
+  c = &WS(z)->working_state;
+  {
+    c->mode = START;
+    c->lbits = (Byte)bl;
+    c->dbits = (Byte)bd;
+    c->ltree = tl;
+    c->dtree = td;
+  }
+  return c;
+}
+
+
+int zlib_inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt j;               /* temporary storage */
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  Bytef *f;             /* pointer to copy strings from */
+  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input and output based on current state */
+  while (1) switch (c->mode)
+  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+    case START:         /* x: set up for LEN */
+#ifndef SLOW
+      if (m >= 258 && n >= 10)
+      {
+        UPDATE
+        r = zlib_inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+        LOAD
+        if (r != Z_OK)
+        {
+          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+          break;
+        }
+      }
+#endif /* !SLOW */
+      c->sub.code.need = c->lbits;
+      c->sub.code.tree = c->ltree;
+      c->mode = LEN;
+    case LEN:           /* i: get length/literal/eob next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & zlib_inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e == 0)               /* literal */
+      {
+        c->sub.lit = t->base;
+        c->mode = LIT;
+        break;
+      }
+      if (e & 16)               /* length */
+      {
+        c->sub.copy.get = e & 15;
+        c->len = t->base;
+        c->mode = LENEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t + t->base;
+        break;
+      }
+      if (e & 32)               /* end of block */
+      {
+        c->mode = WASH;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid literal/length code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case LENEXT:        /* i: getting length extra (have base) */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->len += (uInt)b & zlib_inflate_mask[j];
+      DUMPBITS(j)
+      c->sub.code.need = c->dbits;
+      c->sub.code.tree = c->dtree;
+      c->mode = DIST;
+    case DIST:          /* i: get distance next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & zlib_inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e & 16)               /* distance */
+      {
+        c->sub.copy.get = e & 15;
+        c->sub.copy.dist = t->base;
+        c->mode = DISTEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t + t->base;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid distance code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case DISTEXT:       /* i: getting distance extra */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->sub.copy.dist += (uInt)b & zlib_inflate_mask[j];
+      DUMPBITS(j)
+      c->mode = COPY;
+    case COPY:          /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+      f = (uInt)(q - s->window) < c->sub.copy.dist ?
+          s->end - (c->sub.copy.dist - (q - s->window)) :
+          q - c->sub.copy.dist;
+#else
+      f = q - c->sub.copy.dist;
+      if ((uInt)(q - s->window) < c->sub.copy.dist)
+        f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
+#endif
+      while (c->len)
+      {
+        NEEDOUT
+        OUTBYTE(*f++)
+        if (f == s->end)
+          f = s->window;
+        c->len--;
+      }
+      c->mode = START;
+      break;
+    case LIT:           /* o: got literal, waiting for output space */
+      NEEDOUT
+      OUTBYTE(c->sub.lit)
+      c->mode = START;
+      break;
+    case WASH:          /* o: got eob, possibly more output */
+      if (k > 7)        /* return unused byte, if any */
+      {
+        k -= 8;
+        n++;
+        p--;            /* can always return one */
+      }
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      c->mode = END;
+    case END:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADCODE:       /* x: got error */
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+#ifdef NEED_DUMMY_RETURN
+  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
+#endif
+}
+
+
+void zlib_inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_streamp z;
+{
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_inflate/infcodes.h linux-2.4.20/lib/zlib_inflate/infcodes.h
--- linux-2.4.19/lib/zlib_inflate/infcodes.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_inflate/infcodes.h	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,33 @@
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFCODES_H
+#define _INFCODES_H
+
+#include "infblock.h"
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+extern inflate_codes_statef *zlib_inflate_codes_new OF((
+    uInt, uInt,
+    inflate_huft *, inflate_huft *,
+    z_streamp ));
+
+extern int zlib_inflate_codes OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+extern void zlib_inflate_codes_free OF((
+    inflate_codes_statef *,
+    z_streamp ));
+
+#endif /* _INFCODES_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_inflate/inffast.c linux-2.4.20/lib/zlib_inflate/inffast.c
--- linux-2.4.19/lib/zlib_inflate/inffast.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_inflate/inffast.c	2002-10-29 11:18:40.000000000 +0000
@@ -0,0 +1,161 @@
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/zutil.h>
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+struct inflate_codes_state;
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
+
+/* Called with number of bytes left to write in window at least 258
+   (the maximum string length) and number of input bytes available
+   at least ten.  The ten bytes are six bytes for the longest length/
+   distance pair plus four bytes for overloading the bit buffer. */
+
+int zlib_inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+inflate_blocks_statef *s;
+z_streamp z;
+{
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  uInt ml;              /* mask for literal/length tree */
+  uInt md;              /* mask for distance tree */
+  uInt c;               /* bytes to copy */
+  uInt d;               /* distance back to copy from */
+  Bytef *r;             /* copy source pointer */
+
+  /* load input, output, bit values */
+  LOAD
+
+  /* initialize masks */
+  ml = zlib_inflate_mask[bl];
+  md = zlib_inflate_mask[bd];
+
+  /* do until not enough input or output space for fast loop */
+  do {                          /* assume called with m >= 258 && n >= 10 */
+    /* get literal/length code */
+    GRABBITS(20)                /* max bits for literal/length code */
+    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+    {
+      DUMPBITS(t->bits)
+      *q++ = (Byte)t->base;
+      m--;
+      continue;
+    }
+    do {
+      DUMPBITS(t->bits)
+      if (e & 16)
+      {
+        /* get extra bits for length */
+        e &= 15;
+        c = t->base + ((uInt)b & zlib_inflate_mask[e]);
+        DUMPBITS(e)
+
+        /* decode distance base of block to copy */
+        GRABBITS(15);           /* max bits for distance code */
+        e = (t = td + ((uInt)b & md))->exop;
+        do {
+          DUMPBITS(t->bits)
+          if (e & 16)
+          {
+            /* get extra bits to add to distance base */
+            e &= 15;
+            GRABBITS(e)         /* get extra bits (up to 13) */
+            d = t->base + ((uInt)b & zlib_inflate_mask[e]);
+            DUMPBITS(e)
+
+            /* do the copy */
+            m -= c;
+            if ((uInt)(q - s->window) >= d)     /* offset before dest */
+            {                                   /*  just copy */
+              r = q - d;
+              *q++ = *r++;  c--;        /* minimum count is three, */
+              *q++ = *r++;  c--;        /*  so unroll loop a little */
+            }
+            else                        /* else offset after destination */
+            {
+              e = d - (uInt)(q - s->window); /* bytes from offset to end */
+              r = s->end - e;           /* pointer to offset */
+              if (c > e)                /* if source crosses, */
+              {
+                c -= e;                 /* copy to end of window */
+                do {
+                  *q++ = *r++;
+                } while (--e);
+                r = s->window;          /* copy rest from start of window */
+              }
+            }
+            do {                        /* copy all or what's left */
+              *q++ = *r++;
+            } while (--c);
+            break;
+          }
+          else if ((e & 64) == 0)
+          {
+            t += t->base;
+            e = (t += ((uInt)b & zlib_inflate_mask[e]))->exop;
+          }
+          else
+          {
+            z->msg = (char*)"invalid distance code";
+            UNGRAB
+            UPDATE
+            return Z_DATA_ERROR;
+          }
+        } while (1);
+        break;
+      }
+      if ((e & 64) == 0)
+      {
+        t += t->base;
+        if ((e = (t += ((uInt)b & zlib_inflate_mask[e]))->exop) == 0)
+        {
+          DUMPBITS(t->bits)
+          *q++ = (Byte)t->base;
+          m--;
+          break;
+        }
+      }
+      else if (e & 32)
+      {
+        UNGRAB
+        UPDATE
+        return Z_STREAM_END;
+      }
+      else
+      {
+        z->msg = (char*)"invalid literal/length code";
+        UNGRAB
+        UPDATE
+        return Z_DATA_ERROR;
+      }
+    } while (1);
+  } while (m >= 258 && n >= 10);
+
+  /* not enough input or output--restore pointers and return */
+  UNGRAB
+  UPDATE
+  return Z_OK;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_inflate/inffast.h linux-2.4.20/lib/zlib_inflate/inffast.h
--- linux-2.4.19/lib/zlib_inflate/inffast.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_inflate/inffast.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,17 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+extern int zlib_inflate_fast OF((
+    uInt,
+    uInt,
+    inflate_huft *,
+    inflate_huft *,
+    inflate_blocks_statef *,
+    z_streamp ));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_inflate/inffixed.h linux-2.4.20/lib/zlib_inflate/inffixed.h
--- linux-2.4.19/lib/zlib_inflate/inffixed.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_inflate/inffixed.h	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,151 @@
+/* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by the maketree.c program
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+local uInt fixed_bl = 9;
+local uInt fixed_bd = 5;
+local inflate_huft fixed_tl[] = {
+    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
+    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
+    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
+    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
+    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
+    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
+    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
+    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
+    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
+    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
+    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
+    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
+    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
+    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
+    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
+    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
+    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
+    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
+    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
+    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
+    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
+    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
+    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
+    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
+    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
+    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
+    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
+    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
+    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
+    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
+    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
+    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
+    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
+    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
+    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
+    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
+    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
+    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
+    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
+    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
+    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
+    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
+    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
+    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
+    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
+    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
+    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
+    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
+    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
+    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
+    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
+    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
+    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
+    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
+    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
+    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
+    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
+    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
+    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
+    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
+    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
+    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
+    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
+    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
+    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
+    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
+    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
+    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
+    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
+    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
+    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
+    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
+    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
+    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
+    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
+    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
+    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
+    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
+    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
+    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
+    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
+    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
+    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
+    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
+    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
+    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
+    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
+    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
+    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
+    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
+    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
+    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
+    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
+    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
+    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
+    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
+    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
+    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
+    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
+    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
+    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
+    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
+    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
+    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
+    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
+    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
+    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
+    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
+    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
+    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
+    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
+    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
+  };
+local inflate_huft fixed_td[] = {
+    {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
+    {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
+    {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
+    {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
+    {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
+    {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
+    {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
+    {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
+  };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_inflate/inflate.c linux-2.4.20/lib/zlib_inflate/inflate.c
--- linux-2.4.19/lib/zlib_inflate/inflate.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_inflate/inflate.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,382 @@
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/module.h>
+#include <linux/zutil.h>
+#include "infblock.h"
+#include "infutil.h"
+
+int ZEXPORT zlib_inflate_workspacesize(void)
+{
+  return sizeof(struct inflate_workspace);
+}
+
+
+int ZEXPORT zlib_inflateReset(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL || z->workspace == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->total_in = z->total_out = 0;
+  z->msg = Z_NULL;
+  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+  zlib_inflate_blocks_reset(z->state->blocks, z, Z_NULL);
+  return Z_OK;
+}
+
+
+int ZEXPORT zlib_inflateEnd(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL || z->workspace == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->blocks != Z_NULL)
+    zlib_inflate_blocks_free(z->state->blocks, z);
+  z->state = Z_NULL;
+  return Z_OK;
+}
+
+
+int ZEXPORT zlib_inflateInit2_(z, w, version, stream_size)
+z_streamp z;
+int w;
+const char *version;
+int stream_size;
+{
+  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+      stream_size != sizeof(z_stream) || z->workspace == Z_NULL)
+      return Z_VERSION_ERROR;
+
+  /* initialize state */
+  if (z == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->msg = Z_NULL;
+  z->state = &WS(z)->internal_state;
+  z->state->blocks = Z_NULL;
+
+  /* handle undocumented nowrap option (no zlib header or check) */
+  z->state->nowrap = 0;
+  if (w < 0)
+  {
+    w = - w;
+    z->state->nowrap = 1;
+  }
+
+  /* set window size */
+  if (w < 8 || w > 15)
+  {
+    zlib_inflateEnd(z);
+    return Z_STREAM_ERROR;
+  }
+  z->state->wbits = (uInt)w;
+
+  /* create inflate_blocks state */
+  if ((z->state->blocks =
+      zlib_inflate_blocks_new(z, z->state->nowrap ? Z_NULL : zlib_adler32, (uInt)1 << w))
+      == Z_NULL)
+  {
+    zlib_inflateEnd(z);
+    return Z_MEM_ERROR;
+  }
+
+  /* reset state */
+  zlib_inflateReset(z);
+  return Z_OK;
+}
+
+
+/*
+ * At the end of a Deflate-compressed PPP packet, we expect to have seen
+ * a `stored' block type value but not the (zero) length bytes.
+ */
+static int zlib_inflate_packet_flush(inflate_blocks_statef *s)
+{
+    if (s->mode != LENS)
+	return Z_DATA_ERROR;
+    s->mode = TYPE;
+    return Z_OK;
+}
+
+
+int ZEXPORT zlib_inflateInit_(z, version, stream_size)
+z_streamp z;
+const char *version;
+int stream_size;
+{
+  return zlib_inflateInit2_(z, DEF_WBITS, version, stream_size);
+}
+
+#undef NEEDBYTE
+#undef NEXTBYTE
+#define NEEDBYTE {if(z->avail_in==0)goto empty;r=trv;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int ZEXPORT zlib_inflate(z, f)
+z_streamp z;
+int f;
+{
+  int r, trv;
+  uInt b;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
+    return Z_STREAM_ERROR;
+  trv = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
+  r = Z_BUF_ERROR;
+  while (1) switch (z->state->mode)
+  {
+    case METHOD:
+      NEEDBYTE
+      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+      {
+        z->state->mode = I_BAD;
+        z->msg = (char*)"unknown compression method";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+      {
+        z->state->mode = I_BAD;
+        z->msg = (char*)"invalid window size";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = FLAG;
+    case FLAG:
+      NEEDBYTE
+      b = NEXTBYTE;
+      if (((z->state->sub.method << 8) + b) % 31)
+      {
+        z->state->mode = I_BAD;
+        z->msg = (char*)"incorrect header check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if (!(b & PRESET_DICT))
+      {
+        z->state->mode = BLOCKS;
+        break;
+      }
+      z->state->mode = DICT4;
+    case DICT4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = DICT3;
+    case DICT3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = DICT2;
+    case DICT2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = DICT1;
+    case DICT1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+      z->adler = z->state->sub.check.need;
+      z->state->mode = DICT0;
+      return Z_NEED_DICT;
+    case DICT0:
+      z->state->mode = I_BAD;
+      z->msg = (char*)"need dictionary";
+      z->state->sub.marker = 0;       /* can try inflateSync */
+      return Z_STREAM_ERROR;
+    case BLOCKS:
+      r = zlib_inflate_blocks(z->state->blocks, z, r);
+      if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
+	  r = zlib_inflate_packet_flush(z->state->blocks);
+      if (r == Z_DATA_ERROR)
+      {
+        z->state->mode = I_BAD;
+        z->state->sub.marker = 0;       /* can try inflateSync */
+        break;
+      }
+      if (r == Z_OK)
+        r = trv;
+      if (r != Z_STREAM_END)
+        return r;
+      r = trv;
+      zlib_inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+      if (z->state->nowrap)
+      {
+        z->state->mode = I_DONE;
+        break;
+      }
+      z->state->mode = CHECK4;
+    case CHECK4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = CHECK3;
+    case CHECK3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = CHECK2;
+    case CHECK2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = CHECK1;
+    case CHECK1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+
+      if (z->state->sub.check.was != z->state->sub.check.need)
+      {
+        z->state->mode = I_BAD;
+        z->msg = (char*)"incorrect data check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = I_DONE;
+    case I_DONE:
+      return Z_STREAM_END;
+    case I_BAD:
+      return Z_DATA_ERROR;
+    default:
+      return Z_STREAM_ERROR;
+  }
+ empty:
+  if (f != Z_PACKET_FLUSH)
+    return r;
+  z->state->mode = I_BAD;
+  z->msg = (char *)"need more for packet flush";
+  z->state->sub.marker = 0;       /* can try inflateSync */
+  return Z_DATA_ERROR;
+}
+
+
+int ZEXPORT zlib_inflateSync(z)
+z_streamp z;
+{
+  uInt n;       /* number of bytes to look at */
+  Bytef *p;     /* pointer to bytes */
+  uInt m;       /* number of marker bytes found in a row */
+  uLong r, w;   /* temporaries to save total_in and total_out */
+
+  /* set up */
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->mode != I_BAD)
+  {
+    z->state->mode = I_BAD;
+    z->state->sub.marker = 0;
+  }
+  if ((n = z->avail_in) == 0)
+    return Z_BUF_ERROR;
+  p = z->next_in;
+  m = z->state->sub.marker;
+
+  /* search */
+  while (n && m < 4)
+  {
+    static const Byte mark[4] = {0, 0, 0xff, 0xff};
+    if (*p == mark[m])
+      m++;
+    else if (*p)
+      m = 0;
+    else
+      m = 4 - m;
+    p++, n--;
+  }
+
+  /* restore */
+  z->total_in += p - z->next_in;
+  z->next_in = p;
+  z->avail_in = n;
+  z->state->sub.marker = m;
+
+  /* return no joy or set up to restart on a new block */
+  if (m != 4)
+    return Z_DATA_ERROR;
+  r = z->total_in;  w = z->total_out;
+  zlib_inflateReset(z);
+  z->total_in = r;  z->total_out = w;
+  z->state->mode = BLOCKS;
+  return Z_OK;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
+ * but removes the length bytes of the resulting empty stored block. When
+ * decompressing, PPP checks that at the end of input packet, inflate is
+ * waiting for these length bytes.
+ */
+int ZEXPORT zlib_inflateSyncPoint(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
+    return Z_STREAM_ERROR;
+  return zlib_inflate_blocks_sync_point(z->state->blocks);
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+static int zlib_inflate_addhistory(inflate_blocks_statef *s,
+				      z_stream              *z)
+{
+    uLong b;              /* bit buffer */  /* NOT USED HERE */
+    uInt k;               /* bits in bit buffer */ /* NOT USED HERE */
+    uInt t;               /* temporary storage */
+    Bytef *p;             /* input data pointer */
+    uInt n;               /* bytes available there */
+    Bytef *q;             /* output window write pointer */
+    uInt m;               /* bytes to end of window or read pointer */
+
+    if (s->read != s->write)
+	return Z_STREAM_ERROR;
+    if (s->mode != TYPE)
+	return Z_DATA_ERROR;
+
+    /* we're ready to rock */
+    LOAD
+    /* while there is input ready, copy to output buffer, moving
+     * pointers as needed.
+     */
+    while (n) {
+	t = n;  /* how many to do */
+	/* is there room until end of buffer? */
+	if (t > m) t = m;
+	/* update check information */
+	if (s->checkfn != Z_NULL)
+	    s->check = (*s->checkfn)(s->check, q, t);
+	memcpy(q, p, t);
+	q += t;
+	p += t;
+	n -= t;
+	z->total_out += t;
+	s->read = q;    /* drag read pointer forward */
+/*      WWRAP  */ 	/* expand WWRAP macro by hand to handle s->read */
+	if (q == s->end) {
+	    s->read = q = s->window;
+	    m = WAVAIL;
+	}
+    }
+    UPDATE
+    return Z_OK;
+}
+
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+
+int ZEXPORT zlib_inflateIncomp(z)
+z_stream *z;
+{
+    if (z->state->mode != BLOCKS)
+	return Z_DATA_ERROR;
+    return zlib_inflate_addhistory(z->state->blocks, z);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_inflate/inflate_syms.c linux-2.4.20/lib/zlib_inflate/inflate_syms.c
--- linux-2.4.19/lib/zlib_inflate/inflate_syms.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_inflate/inflate_syms.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,22 @@
+/*
+ * linux/lib/zlib_inflate/inflate_syms.c
+ *
+ * Exported symbols for the inflate functionality.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/zlib.h>
+
+EXPORT_SYMBOL(zlib_inflate_workspacesize);
+EXPORT_SYMBOL(zlib_inflate);
+EXPORT_SYMBOL(zlib_inflateInit_);
+EXPORT_SYMBOL(zlib_inflateInit2_);
+EXPORT_SYMBOL(zlib_inflateEnd);
+EXPORT_SYMBOL(zlib_inflateSync);
+EXPORT_SYMBOL(zlib_inflateReset);
+EXPORT_SYMBOL(zlib_inflateSyncPoint);
+EXPORT_SYMBOL(zlib_inflateIncomp); 
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_inflate/inftrees.c linux-2.4.20/lib/zlib_inflate/inftrees.c
--- linux-2.4.19/lib/zlib_inflate/inftrees.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_inflate/inftrees.c	2002-10-29 11:18:39.000000000 +0000
@@ -0,0 +1,391 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/zutil.h>
+#include "inftrees.h"
+#include "infutil.h"
+
+static const char inflate_copyright[] =
+   " inflate 1.1.3 Copyright 1995-1998 Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+struct internal_state;
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+    uIntf *,            /* code lengths in bits */
+    uInt,               /* number of codes */
+    uInt,               /* number of "simple" codes */
+    const uIntf *,      /* list of base values for non-simple codes */
+    const uIntf *,      /* list of extra bits for non-simple codes */
+    inflate_huft * FAR*,/* result: starting table */
+    uIntf *,            /* maximum lookup bits (returns actual) */
+    inflate_huft *,     /* space for trees */
+    uInt *,             /* hufts used in space */
+    uIntf * ));         /* space for values */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* see note #13 above about 258 */
+local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
+local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577};
+local const uInt cpdext[30] = { /* Extra bits for distance codes */
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15         /* maximum bit length of any code */
+
+local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
+uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
+uInt n;                 /* number of codes (assumed <= 288) */
+uInt s;                 /* number of simple-valued codes (0..s-1) */
+const uIntf *d;         /* list of base values for non-simple codes */
+const uIntf *e;         /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t;  /* result: starting table */
+uIntf *m;               /* maximum lookup bits, returns actual */
+inflate_huft *hp;       /* space for trees */
+uInt *hn;               /* hufts used in space */
+uIntf *v;               /* working area: values in order of bit length */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
+   if the given code set is incomplete (the tables are still built in this
+   case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
+   lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+  uInt a;                       /* counter for codes of length k */
+  uInt c[BMAX+1];               /* bit length count table */
+  uInt f;                       /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register uInt i;              /* counter, current code */
+  register uInt j;              /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  uInt mask;                    /* (1 << w) - 1, to avoid cc -O bug on HP */
+  register uIntf *p;            /* pointer into c[], b[], or v[] */
+  inflate_huft *q;              /* points to current table */
+  struct inflate_huft_s r;      /* table entry for structure assignment */
+  inflate_huft *u[BMAX];        /* table stack */
+  register int w;               /* bits before this table == (l * h) */
+  uInt x[BMAX+1];               /* bit offsets, then code stack */
+  uIntf *xp;                    /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  uInt z;                       /* number of entries in current table */
+
+
+  /* Generate counts for each bit length */
+  p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+  C4                            /* clear c[]--assume BMAX+1 is 16 */
+  p = b;  i = n;
+  do {
+    c[*p++]++;                  /* assume all entries <= BMAX */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (inflate_huft *)Z_NULL;
+    *m = 0;
+    return Z_OK;
+  }
+
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((uInt)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((uInt)l > i)
+    l = i;
+  *m = l;
+
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return Z_DATA_ERROR;
+  if ((y -= c[i]) < 0)
+    return Z_DATA_ERROR;
+  c[i] += y;
+
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+
+  /* Make a table of values in order of bit lengths */
+  p = b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+  n = x[g];                     /* set n to length of v */
+
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
+  q = (inflate_huft *)Z_NULL;   /* ditto */
+  z = 0;                        /* ditto */
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+    a = c[k];
+    while (a--)
+    {
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = g - w;
+        z = z > (uInt)l ? l : z;        /* table size upper limit */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          if (j < z)
+            while (++j < z)     /* try smaller tables up to z bits */
+            {
+              if ((f <<= 1) <= *++xp)
+                break;          /* enough codes to use up j bits */
+              f -= *xp;         /* else deduct codes from patterns */
+            }
+        }
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate new table */
+        if (*hn + z > MANY)     /* (note: doesn't matter for fixed) */
+          return Z_MEM_ERROR;   /* not enough memory */
+        u[h] = q = hp + *hn;
+        *hn += z;
+
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.bits = (Byte)l;     /* bits to dump before this table */
+          r.exop = (Byte)j;     /* bits in this table */
+          j = i >> (w - l);
+          r.base = (uInt)(q - u[h-1] - j);   /* offset to this table */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+        else
+          *t = q;               /* first table is returned result */
+      }
+
+      /* set up table entry in r */
+      r.bits = (Byte)(k - w);
+      if (p >= v + n)
+        r.exop = 128 + 64;      /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
+        r.base = *p++;          /* simple code is just the value */
+      }
+      else
+      {
+        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
+        r.base = d[*p++ - s];
+      }
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      mask = (1 << w) - 1;      /* needed on HP, cc -O bug */
+      while ((i & mask) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+        mask = (1 << w) - 1;
+      }
+    }
+  }
+
+
+  /* Return Z_BUF_ERROR if we were given an incomplete table */
+  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+int zlib_inflate_trees_bits(c, bb, tb, hp, z)
+uIntf *c;               /* 19 code lengths */
+uIntf *bb;              /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+inflate_huft *hp;       /* space for trees */
+z_streamp z;            /* for messages */
+{
+  int r;
+  uInt hn = 0;          /* hufts used in space */
+  uIntf *v;             /* work area for huft_build */
+  
+  v = WS(z)->tree_work_area_1;
+  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
+                 tb, bb, hp, &hn, v);
+  if (r == Z_DATA_ERROR)
+    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
+  else if (r == Z_BUF_ERROR || *bb == 0)
+  {
+    z->msg = (char*)"incomplete dynamic bit lengths tree";
+    r = Z_DATA_ERROR;
+  }
+  return r;
+}
+
+int zlib_inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
+uInt nl;                /* number of literal/length codes */
+uInt nd;                /* number of distance codes */
+uIntf *c;               /* that many (total) code lengths */
+uIntf *bl;              /* literal desired/actual bit depth */
+uIntf *bd;              /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+inflate_huft *hp;       /* space for trees */
+z_streamp z;            /* for messages */
+{
+  int r;
+  uInt hn = 0;          /* hufts used in space */
+  uIntf *v;             /* work area for huft_build */
+
+  /* allocate work area */
+  v = WS(z)->tree_work_area_2;
+
+  /* build literal/length tree */
+  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
+  if (r != Z_OK || *bl == 0)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed literal/length tree";
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    return r;
+  }
+
+  /* build distance tree */
+  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
+  if (r != Z_OK || (*bd == 0 && nl > 257))
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed distance tree";
+    else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+      r = Z_OK;
+    }
+#else
+      z->msg = (char*)"incomplete distance tree";
+      r = Z_DATA_ERROR;
+    }
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"empty distance tree with lengths";
+      r = Z_DATA_ERROR;
+    }
+    return r;
+#endif
+  }
+
+  /* done */
+  return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+#include "inffixed.h"
+
+
+int zlib_inflate_trees_fixed(bl, bd, tl, td, z)
+uIntf *bl;               /* literal desired/actual bit depth */
+uIntf *bd;               /* distance desired/actual bit depth */
+inflate_huft * FAR *tl;  /* literal/length tree result */
+inflate_huft * FAR *td;  /* distance tree result */
+z_streamp z;             /* for memory allocation */
+{
+  *bl = fixed_bl;
+  *bd = fixed_bd;
+  *tl = fixed_tl;
+  *td = fixed_td;
+  return Z_OK;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_inflate/inftrees.h linux-2.4.20/lib/zlib_inflate/inftrees.h
--- linux-2.4.19/lib/zlib_inflate/inftrees.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_inflate/inftrees.h	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,63 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+#ifndef _INFTREES_H
+#define _INFTREES_H
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+  union {
+    struct {
+      Byte Exop;        /* number of extra bits or operation */
+      Byte Bits;        /* number of bits in this code or subcode */
+    } what;
+    uInt pad;           /* pad structure to a power of 2 (4 bytes for */
+  } word;               /*  16-bit, 8 bytes for 32-bit int's) */
+  uInt base;            /* literal, length base, distance base,
+                           or table offset */
+};
+
+/* Maximum size of dynamic tree.  The maximum found in a long but non-
+   exhaustive search was 1004 huft structures (850 for length/literals
+   and 154 for distances, the latter actually the result of an
+   exhaustive search).  The actual maximum is not known, but the
+   value below is more than safe. */
+#define MANY 1440
+
+extern int zlib_inflate_trees_bits OF((
+    uIntf *,                    /* 19 code lengths */
+    uIntf *,                    /* bits tree desired/actual depth */
+    inflate_huft * FAR *,       /* bits tree result */
+    inflate_huft *,             /* space for trees */
+    z_streamp));                /* for messages */
+
+extern int zlib_inflate_trees_dynamic OF((
+    uInt,                       /* number of literal/length codes */
+    uInt,                       /* number of distance codes */
+    uIntf *,                    /* that many (total) code lengths */
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    inflate_huft *,             /* space for trees */
+    z_streamp));                /* for messages */
+
+extern int zlib_inflate_trees_fixed OF((
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    z_streamp));                /* for memory allocation */
+
+#endif /* _INFTREES_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_inflate/infutil.c linux-2.4.20/lib/zlib_inflate/infutil.c
--- linux-2.4.19/lib/zlib_inflate/infutil.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_inflate/infutil.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,87 @@
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/zutil.h>
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state;
+
+/* And'ing with mask[n] masks the lower n bits */
+uInt zlib_inflate_mask[17] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+
+/* copy as much as possible from the sliding window to the output area */
+int zlib_inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt n;
+  Bytef *p;
+  Bytef *q;
+
+  /* local copies of source and destination pointers */
+  p = z->next_out;
+  q = s->read;
+
+  /* compute number of bytes to copy as far as end of window */
+  n = (uInt)((q <= s->write ? s->write : s->end) - q);
+  if (n > z->avail_out) n = z->avail_out;
+  if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+  /* update counters */
+  z->avail_out -= n;
+  z->total_out += n;
+
+  /* update check information */
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+  /* copy as far as end of window */
+  memcpy(p, q, n);
+  p += n;
+  q += n;
+
+  /* see if more to copy at beginning of window */
+  if (q == s->end)
+  {
+    /* wrap pointers */
+    q = s->window;
+    if (s->write == s->end)
+      s->write = s->window;
+
+    /* compute bytes to copy */
+    n = (uInt)(s->write - q);
+    if (n > z->avail_out) n = z->avail_out;
+    if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+    /* update counters */
+    z->avail_out -= n;
+    z->total_out += n;
+
+    /* update check information */
+    if (s->checkfn != Z_NULL)
+      z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+    /* copy */
+    memcpy(p, q, n);
+    p += n;
+    q += n;
+  }
+
+  /* update pointers */
+  z->next_out = p;
+  s->read = q;
+
+  /* done */
+  return r;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/lib/zlib_inflate/infutil.h linux-2.4.20/lib/zlib_inflate/infutil.h
--- linux-2.4.19/lib/zlib_inflate/infutil.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/lib/zlib_inflate/infutil.h	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,197 @@
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFUTIL_H
+#define _INFUTIL_H
+
+#include <linux/zconf.h>
+#include "inftrees.h"
+#include "infcodes.h"
+
+typedef enum {
+      TYPE,     /* get type bits (3, including end bit) */
+      LENS,     /* get lengths for stored */
+      STORED,   /* processing stored block */
+      TABLE,    /* get table lengths */
+      BTREE,    /* get bit lengths tree for a dynamic block */
+      DTREE,    /* get length, distance trees for a dynamic block */
+      CODES,    /* processing fixed or dynamic block */
+      DRY,      /* output remaining window bytes */
+      B_DONE,   /* finished last block, done */
+      B_BAD}    /* got a data error--stuck here */
+inflate_block_mode;
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+  /* mode */
+  inflate_block_mode  mode;     /* current inflate_block mode */
+
+  /* mode dependent information */
+  union {
+    uInt left;          /* if STORED, bytes left to copy */
+    struct {
+      uInt table;               /* table lengths (14 bits) */
+      uInt index;               /* index into blens (or border) */
+      uIntf *blens;             /* bit lengths of codes */
+      uInt bb;                  /* bit length tree depth */
+      inflate_huft *tb;         /* bit length decoding tree */
+    } trees;            /* if DTREE, decoding info for trees */
+    struct {
+      inflate_codes_statef 
+         *codes;
+    } decode;           /* if CODES, current state */
+  } sub;                /* submode */
+  uInt last;            /* true if this block is the last block */
+
+  /* mode independent information */
+  uInt bitk;            /* bits in bit buffer */
+  uLong bitb;           /* bit buffer */
+  inflate_huft *hufts;  /* single malloc for tree space */
+  Bytef *window;        /* sliding window */
+  Bytef *end;           /* one byte after sliding window */
+  Bytef *read;          /* window read pointer */
+  Bytef *write;         /* window write pointer */
+  check_func checkfn;   /* check function */
+  uLong check;          /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/*   update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return zlib_inflate_flush(s,z,r);}
+/*   get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/*   output bytes */
+#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
+#define FLUSH {UPDOUT r=zlib_inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/*   load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
+extern uInt zlib_inflate_mask[17];
+
+/* copy as much as possible from the sliding window to the output area */
+extern int zlib_inflate_flush OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+/* inflate private state */
+typedef enum {
+      METHOD,   /* waiting for method byte */
+      FLAG,     /* waiting for flag byte */
+      DICT4,    /* four dictionary check bytes to go */
+      DICT3,    /* three dictionary check bytes to go */
+      DICT2,    /* two dictionary check bytes to go */
+      DICT1,    /* one dictionary check byte to go */
+      DICT0,    /* waiting for inflateSetDictionary */
+      BLOCKS,   /* decompressing blocks */
+      CHECK4,   /* four check bytes to go */
+      CHECK3,   /* three check bytes to go */
+      CHECK2,   /* two check bytes to go */
+      CHECK1,   /* one check byte to go */
+      I_DONE,   /* finished check, done */
+      I_BAD}    /* got an error--stay here */
+inflate_mode;
+
+struct internal_state {
+
+  /* mode */
+  inflate_mode  mode;   /* current inflate mode */
+
+  /* mode dependent information */
+  union {
+    uInt method;        /* if FLAGS, method byte */
+    struct {
+      uLong was;                /* computed check value */
+      uLong need;               /* stream check value */
+    } check;            /* if CHECK, check values to compare */
+    uInt marker;        /* if BAD, inflateSync's marker bytes count */
+  } sub;        /* submode */
+
+  /* mode independent information */
+  int  nowrap;          /* flag for no wrapper */
+  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
+  inflate_blocks_statef 
+    *blocks;            /* current inflate_blocks state */
+
+};
+
+/* inflate codes private state */
+typedef enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+      START,    /* x: set up for LEN */
+      LEN,      /* i: get length/literal/eob next */
+      LENEXT,   /* i: getting length extra (have base) */
+      DIST,     /* i: get distance next */
+      DISTEXT,  /* i: getting distance extra */
+      COPY,     /* o: copying bytes in window, waiting for space */
+      LIT,      /* o: got literal, waiting for output space */
+      WASH,     /* o: got eob, possibly still output waiting */
+      END,      /* x: got eob and all data flushed */
+      BADCODE}  /* x: got error */
+inflate_codes_mode;
+
+struct inflate_codes_state {
+
+  /* mode */
+  inflate_codes_mode mode;      /* current inflate_codes mode */
+
+  /* mode dependent information */
+  uInt len;
+  union {
+    struct {
+      inflate_huft *tree;       /* pointer into tree */
+      uInt need;                /* bits needed */
+    } code;             /* if LEN or DIST, where in tree */
+    uInt lit;           /* if LIT, literal */
+    struct {
+      uInt get;                 /* bits to get for extra */
+      uInt dist;                /* distance back to copy from */
+    } copy;             /* if EXT or COPY, where and how much */
+  } sub;                /* submode */
+
+  /* mode independent information */
+  Byte lbits;           /* ltree bits decoded per branch */
+  Byte dbits;           /* dtree bits decoder per branch */
+  inflate_huft *ltree;          /* literal/length/eob tree */
+  inflate_huft *dtree;          /* distance tree */
+
+};
+
+/* memory allocation for inflation */
+
+struct inflate_workspace {
+	inflate_codes_statef working_state;
+	struct inflate_blocks_state working_blocks_state;
+	struct internal_state internal_state;
+	unsigned int tree_work_area_1[19];
+	unsigned int tree_work_area_2[288];
+	unsigned working_blens[258 + 0x1f + 0x1f];
+	inflate_huft working_hufts[MANY];
+	unsigned char working_window[1 << MAX_WBITS];
+};
+
+#define WS(z) ((struct inflate_workspace *)(z->workspace))
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/mm/bootmem.c linux-2.4.20/mm/bootmem.c
--- linux-2.4.19/mm/bootmem.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/mm/bootmem.c	2002-10-29 11:18:36.000000000 +0000
@@ -26,6 +26,7 @@
  */
 unsigned long max_low_pfn;
 unsigned long min_low_pfn;
+unsigned long max_pfn;
 
 /* return the number of _pages_ that will be allocated for the boot bitmap */
 unsigned long __init bootmem_bootmap_pages (unsigned long pages)
@@ -324,15 +325,14 @@
 
 void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal)
 {
-	pg_data_t *pgdat = pgdat_list;
+	pg_data_t *pgdat;
 	void *ptr;
 
-	while (pgdat) {
+	for_each_pgdat(pgdat)
 		if ((ptr = __alloc_bootmem_core(pgdat->bdata, size,
 						align, goal)))
 			return(ptr);
-		pgdat = pgdat->node_next;
-	}
+
 	/*
 	 * Whoops, we cannot satisfy the allocation request.
 	 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/mm/filemap.c linux-2.4.20/mm/filemap.c
--- linux-2.4.19/mm/filemap.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/mm/filemap.c	2002-10-29 11:18:36.000000000 +0000
@@ -154,11 +154,14 @@
 
 		if (mapping) {
 			spin_lock(&pagecache_lock);
-			list_del(&page->list);
-			list_add(&page->list, &mapping->dirty_pages);
+			mapping = page->mapping;
+			if (mapping) {	/* may have been truncated */
+				list_del(&page->list);
+				list_add(&page->list, &mapping->dirty_pages);
+			}
 			spin_unlock(&pagecache_lock);
 
-			if (mapping->host)
+			if (mapping && mapping->host)
 				mark_inode_dirty_pages(mapping->host);
 		}
 	}
@@ -800,7 +803,6 @@
 	/* On some cpus multiply is faster, on others gcc will do shifts */
 	hash *= GOLDEN_RATIO_PRIME;
 #endif
-
 	hash >>= zone->wait_table_shift;
 
 	return &wait[hash];
@@ -812,6 +814,21 @@
  * This must be called with the caller "holding" the page,
  * ie with increased "page->count" so that the page won't
  * go away during the wait..
+ *
+ * The waiting strategy is to get on a waitqueue determined
+ * by hashing. Waiters will then collide, and the newly woken
+ * task must then determine whether it was woken for the page
+ * it really wanted, and go back to sleep on the waitqueue if
+ * that wasn't it. With the waitqueue semantics, it never leaves
+ * the waitqueue unless it calls, so the loop moves forward one
+ * iteration every time there is
+ * (1) a collision 
+ * and
+ * (2) one of the colliding pages is woken
+ *
+ * This is the thundering herd problem, but it is expected to
+ * be very rare due to the few pages that are actually being
+ * waited on at any given time and the quality of the hash function.
  */
 void ___wait_on_page(struct page *page)
 {
@@ -832,7 +849,11 @@
 }
 
 /*
- * Unlock the page and wake up sleepers in ___wait_on_page.
+ * unlock_page() is the other half of the story just above
+ * __wait_on_page(). Here a couple of quick checks are done
+ * and a couple of flags are set on the page, and then all
+ * of the waiters for all of the pages in the appropriate
+ * wait queue are woken.
  */
 void unlock_page(struct page *page)
 {
@@ -842,6 +863,13 @@
 	if (!test_and_clear_bit(PG_locked, &(page)->flags))
 		BUG();
 	smp_mb__after_clear_bit(); 
+
+	/*
+	 * Although the default semantics of wake_up() are
+	 * to wake all, here the specific function is used
+	 * to make it even more explicit that a number of
+	 * pages are being waited on here.
+	 */
 	if (waitqueue_active(waitqueue))
 		wake_up_all(waitqueue);
 }
@@ -1001,15 +1029,6 @@
 }
 
 /*
- * Returns locked page at given index in given cache, creating it if needed.
- */
-struct page *grab_cache_page(struct address_space *mapping, unsigned long index)
-{
-	return find_or_create_page(mapping, index, mapping->gfp_mask);
-}
-
-
-/*
  * Same as grab_cache_page, but do not wait if the page is unavailable.
  * This is intended for speculative data generators, where the data can
  * be regenerated if the page couldn't be grabbed.  This routine should
@@ -1291,21 +1310,16 @@
 /*
  * Mark a page as having seen activity.
  *
- * If it was already so marked, move it
- * to the active queue and drop the referenced
- * bit. Otherwise, just mark it for future
- * action..
+ * If it was already so marked, move it to the active queue and drop
+ * the referenced bit.  Otherwise, just mark it for future action..
  */
 void mark_page_accessed(struct page *page)
 {
 	if (!PageActive(page) && PageReferenced(page)) {
 		activate_page(page);
 		ClearPageReferenced(page);
-		return;
-	}
-
-	/* Mark the page referenced, AFTER checking for previous usage.. */
-	SetPageReferenced(page);
+	} else
+		SetPageReferenced(page);
 }
 
 /*
@@ -1534,6 +1548,7 @@
 	struct kiobuf * iobuf;
 	struct address_space * mapping = filp->f_dentry->d_inode->i_mapping;
 	struct inode * inode = mapping->host;
+	loff_t size = inode->i_size;
 
 	new_iobuf = 0;
 	iobuf = filp->f_iobuf;
@@ -1559,6 +1574,9 @@
 	if (!mapping->a_ops->direct_IO)
 		goto out_free;
 
+	if ((rw == READ) && (offset + count > size))
+		count = size - offset;
+
 	/*
 	 * Flush to disk exclusively the _data_, metadata must remain
 	 * completly asynchronous or performance will go to /dev/null.
@@ -1589,6 +1607,7 @@
 		if (retval >= 0) {
 			count -= retval;
 			buf += retval;
+			/* warning: weird semantics here, we're reporting a read behind the end of the file */
 			progress += retval;
 		}
 
@@ -1678,8 +1697,6 @@
 			goto out; /* skip atime */
 		size = inode->i_size;
 		if (pos < size) {
-			if (pos + count > size)
-				count = size - pos;
 			retval = generic_file_direct_IO(READ, filp, buf, count, pos);
 			if (retval > 0)
 				*ppos = pos + retval;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/mm/highmem.c linux-2.4.20/mm/highmem.c
--- linux-2.4.19/mm/highmem.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/mm/highmem.c	2002-10-29 11:18:48.000000000 +0000
@@ -332,7 +332,7 @@
 	if (page)
 		return page;
 	/*
-	 * No luck. First, kick the VM so it doesnt idle around while
+	 * No luck. First, kick the VM so it doesn't idle around while
 	 * we are using up our emergency rations.
 	 */
 	wakeup_bdflush();
@@ -355,9 +355,7 @@
 	/* we need to wait I/O completion */
 	run_task_queue(&tq_disk);
 
-	current->policy |= SCHED_YIELD;
-	__set_current_state(TASK_RUNNING);
-	schedule();
+	yield();
 	goto repeat_alloc;
 }
 
@@ -370,7 +368,7 @@
 	if (bh)
 		return bh;
 	/*
-	 * No luck. First, kick the VM so it doesnt idle around while
+	 * No luck. First, kick the VM so it doesn't idle around while
 	 * we are using up our emergency rations.
 	 */
 	wakeup_bdflush();
@@ -393,9 +391,7 @@
 	/* we need to wait I/O completion */
 	run_task_queue(&tq_disk);
 
-	current->policy |= SCHED_YIELD;
-	__set_current_state(TASK_RUNNING);
-	schedule();
+	yield();
 	goto repeat_alloc;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/mm/memory.c linux-2.4.20/mm/memory.c
--- linux-2.4.19/mm/memory.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/mm/memory.c	2002-10-29 11:18:40.000000000 +0000
@@ -146,7 +146,6 @@
 void clear_page_tables(struct mm_struct *mm, unsigned long first, int nr)
 {
 	pgd_t * page_dir = mm->pgd;
-	unsigned long	last = first + nr;
 
 	spin_lock(&mm->page_table_lock);
 	page_dir += first;
@@ -156,8 +155,6 @@
 	} while (--nr);
 	spin_unlock(&mm->page_table_lock);
 
-	flush_tlb_pgtables(mm, first * PGDIR_SIZE, last * PGDIR_SIZE);
-	
 	/* keep the page table cache within bounds */
 	check_pgt_cache();
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/mm/mmap.c linux-2.4.20/mm/mmap.c
--- linux-2.4.19/mm/mmap.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/mm/mmap.c	2002-10-29 11:18:32.000000000 +0000
@@ -908,6 +908,7 @@
 	end_index = pgd_index(last);
 	if (end_index > start_index) {
 		clear_page_tables(mm, start_index, end_index - start_index);
+		flush_tlb_pgtables(mm, first & PGDIR_MASK, last & PGDIR_MASK);
 	}
 }
 
@@ -1152,13 +1153,14 @@
 		kmem_cache_free(vm_area_cachep, mpnt);
 		mpnt = next;
 	}
-	flush_tlb_mm(mm);
 
 	/* This is just debugging */
 	if (mm->map_count)
 		BUG();
 
 	clear_page_tables(mm, FIRST_USER_PGD_NR, USER_PTRS_PER_PGD);
+
+	flush_tlb_mm(mm);
 }
 
 /* Insert vm structure into process list sorted by address
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/mm/oom_kill.c linux-2.4.20/mm/oom_kill.c
--- linux-2.4.19/mm/oom_kill.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/mm/oom_kill.c	2002-10-29 11:18:31.000000000 +0000
@@ -188,8 +188,7 @@
 	 * killing itself before someone else gets the chance to ask
 	 * for more memory.
 	 */
-	current->policy |= SCHED_YIELD;
-	schedule();
+	yield();
 	return;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/mm/page_alloc.c linux-2.4.20/mm/page_alloc.c
--- linux-2.4.19/mm/page_alloc.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/mm/page_alloc.c	2002-10-29 11:18:32.000000000 +0000
@@ -29,7 +29,12 @@
 LIST_HEAD(active_list);
 pg_data_t *pgdat_list;
 
-/* Used to look up the address of the struct zone encoded in page->zone */
+/*
+ *
+ * The zone_table array is used to look up the address of the
+ * struct zone corresponding to a given zone number (ZONE_DMA,
+ * ZONE_NORMAL, or ZONE_HIGHMEM).
+ */
 zone_t *zone_table[MAX_NR_ZONES*MAX_NR_NODES];
 EXPORT_SYMBOL(zone_table);
 
@@ -50,8 +55,10 @@
 
 /*
  * Freeing function for a buddy system allocator.
+ * Contrary to prior comments, this is *NOT* hairy, and there
+ * is no reason for anyone not to understand it.
  *
- * The concept of a buddy system is to maintain direct-mapped table
+ * The concept of a buddy system is to maintain direct-mapped tables
  * (containing bit values) for memory blocks of various "orders".
  * The bottom level table contains the map for the smallest allocatable
  * units of memory (here, pages), and each level above it describes
@@ -79,11 +86,15 @@
 	struct page *base;
 	zone_t *zone;
 
-	/* Yes, think what happens when other parts of the kernel take 
+	/*
+	 * Yes, think what happens when other parts of the kernel take 
 	 * a reference to a page in order to pin it for io. -ben
 	 */
-	if (PageLRU(page))
+	if (PageLRU(page)) {
+		if (unlikely(in_interrupt()))
+			BUG();
 		lru_cache_del(page);
+	}
 
 	if (page->buffers)
 		BUG();
@@ -252,7 +263,7 @@
 	current->allocation_order = order;
 	current->flags |= PF_MEMALLOC | PF_FREE_PAGES;
 
-	__freed = try_to_free_pages(classzone, gfp_mask, order);
+	__freed = try_to_free_pages_zone(classzone, gfp_mask);
 
 	current->flags &= ~(PF_MEMALLOC | PF_FREE_PAGES);
 
@@ -407,9 +418,7 @@
 		return NULL;
 
 	/* Yield for kswapd, and try again */
-	current->policy |= SCHED_YIELD;
-	__set_current_state(TASK_RUNNING);
-	schedule();
+	yield();
 	goto rebalance;
 }
 
@@ -456,16 +465,12 @@
  */
 unsigned int nr_free_pages (void)
 {
-	unsigned int sum;
+	unsigned int sum = 0;
 	zone_t *zone;
-	pg_data_t *pgdat = pgdat_list;
 
-	sum = 0;
-	while (pgdat) {
-		for (zone = pgdat->node_zones; zone < pgdat->node_zones + MAX_NR_ZONES; zone++)
-			sum += zone->free_pages;
-		pgdat = pgdat->node_next;
-	}
+	for_each_zone(zone)
+		sum += zone->free_pages;
+
 	return sum;
 }
 
@@ -474,10 +479,10 @@
  */
 unsigned int nr_free_buffer_pages (void)
 {
-	pg_data_t *pgdat = pgdat_list;
+	pg_data_t *pgdat;
 	unsigned int sum = 0;
 
-	do {
+	for_each_pgdat(pgdat) {
 		zonelist_t *zonelist = pgdat->node_zonelists + (GFP_USER & GFP_ZONEMASK);
 		zone_t **zonep = zonelist->zones;
 		zone_t *zone;
@@ -488,9 +493,7 @@
 			if (size > high)
 				sum += size - high;
 		}
-
-		pgdat = pgdat->node_next;
-	} while (pgdat);
+	}
 
 	return sum;
 }
@@ -498,13 +501,12 @@
 #if CONFIG_HIGHMEM
 unsigned int nr_free_highpages (void)
 {
-	pg_data_t *pgdat = pgdat_list;
+	pg_data_t *pgdat;
 	unsigned int pages = 0;
 
-	while (pgdat) {
+	for_each_pgdat(pgdat)
 		pages += pgdat->node_zones[ZONE_HIGHMEM].free_pages;
-		pgdat = pgdat->node_next;
-	}
+
 	return pages;
 }
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/mm/page_io.c linux-2.4.20/mm/page_io.c
--- linux-2.4.19/mm/page_io.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/mm/page_io.c	2002-10-29 11:18:33.000000000 +0000
@@ -72,11 +72,6 @@
 
  	/* block_size == PAGE_SIZE/zones_used */
  	brw_page(rw, page, dev, zones, block_size);
-
- 	/* Note! For consistency we do all of the logic,
- 	 * decrementing the page count, and unlocking the page in the
- 	 * swap lock map - in the IO completion handler.
- 	 */
 	return 1;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/mm/shmem.c linux-2.4.20/mm/shmem.c
--- linux-2.4.19/mm/shmem.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/mm/shmem.c	2002-10-29 11:18:39.000000000 +0000
@@ -34,6 +34,14 @@
 #define TMPFS_MAGIC	0x01021994
 
 #define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long))
+#define BLOCKS_PER_PAGE  (PAGE_CACHE_SIZE/512)
+
+#define SHMEM_MAX_INDEX  (SHMEM_NR_DIRECT + ENTRIES_PER_PAGE * (ENTRIES_PER_PAGE/2) * (ENTRIES_PER_PAGE+1))
+#define SHMEM_MAX_BYTES  ((unsigned long long)SHMEM_MAX_INDEX << PAGE_CACHE_SHIFT)
+#define VM_ACCT(size)    (((size) + PAGE_CACHE_SIZE - 1) >> PAGE_SHIFT)
+
+/* Pretend that each entry is of this size in directory's i_size */
+#define BOGO_DIRENT_SIZE 20
 
 #define SHMEM_SB(sb) (&sb->u.shmem_sb)
 
@@ -50,8 +58,6 @@
 
 static struct page *shmem_getpage_locked(struct shmem_inode_info *, struct inode *, unsigned long);
 
-#define BLOCKS_PER_PAGE (PAGE_CACHE_SIZE/512)
-
 /*
  * shmem_recalc_inode - recalculate the size of an inode
  *
@@ -127,9 +133,6 @@
  * 	      	       +-> 48-51
  * 	      	       +-> 52-55
  */
-
-#define SHMEM_MAX_BLOCKS (SHMEM_NR_DIRECT + ENTRIES_PER_PAGE * ENTRIES_PER_PAGE/2*(ENTRIES_PER_PAGE+1))
-
 static swp_entry_t * shmem_swp_entry (struct shmem_inode_info *info, unsigned long index, unsigned long page) 
 {
 	unsigned long offset;
@@ -182,7 +185,7 @@
 	unsigned long page = 0;
 	swp_entry_t * res;
 
-	if (index >= SHMEM_MAX_BLOCKS)
+	if (index >= SHMEM_MAX_INDEX)
 		return ERR_PTR(-EFBIG);
 
 	if (info->next_index <= index)
@@ -358,11 +361,11 @@
 {
 	struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
 
-	inode->i_size = 0;
-	if (inode->i_op->truncate == shmem_truncate){ 
+	if (inode->i_op->truncate == shmem_truncate) {
 		spin_lock (&shmem_ilock);
 		list_del (&SHMEM_I(inode)->list);
 		spin_unlock (&shmem_ilock);
+		inode->i_size = 0;
 		shmem_truncate (inode);
 	}
 	spin_lock (&sbinfo->stat_lock);
@@ -557,7 +560,7 @@
 		unsigned long flags;
 
 		/* Look it up and read it in.. */
-		page = find_get_page(&swapper_space, entry->val);
+		page = lookup_swap_cache(*entry);
 		if (!page) {
 			swp_entry_t swap = *entry;
 			spin_unlock (&info->lock);
@@ -612,6 +615,7 @@
 		if (!page)
 			return ERR_PTR(-ENOMEM);
 		clear_highpage(page);
+		flush_dcache_page(page);
 		inode->i_blocks += BLOCKS_PER_PAGE;
 		add_to_page_cache (page, mapping, idx);
 	}
@@ -731,11 +735,13 @@
 			inode->i_op = &shmem_inode_operations;
 			inode->i_fop = &shmem_file_operations;
 			spin_lock (&shmem_ilock);
-			list_add_tail(&SHMEM_I(inode)->list, &shmem_inodes);
+			list_add_tail(&info->list, &shmem_inodes);
 			spin_unlock (&shmem_ilock);
 			break;
 		case S_IFDIR:
 			inode->i_nlink++;
+			/* Some things misbehave if size == 0 on a directory */
+			inode->i_size = 2 * BOGO_DIRENT_SIZE;
 			inode->i_op = &shmem_dir_inode_operations;
 			inode->i_fop = &dcache_dir_ops;
 			break;
@@ -999,7 +1005,7 @@
 	buf->f_files = sbinfo->max_inodes;
 	buf->f_ffree = sbinfo->free_inodes;
 	spin_unlock (&sbinfo->stat_lock);
-	buf->f_namelen = 255;
+	buf->f_namelen = NAME_MAX;
 	return 0;
 }
 
@@ -1022,6 +1028,7 @@
 	int error = -ENOSPC;
 
 	if (inode) {
+		dir->i_size += BOGO_DIRENT_SIZE;
 		dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 		d_instantiate(dentry, inode);
 		dget(dentry); /* Extra count - pin the dentry in core */
@@ -1055,6 +1062,7 @@
 	if (S_ISDIR(inode->i_mode))
 		return -EPERM;
 
+	dir->i_size += BOGO_DIRENT_SIZE;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	inode->i_nlink++;
 	atomic_inc(&inode->i_count);	/* New dentry reference */
@@ -1099,6 +1107,8 @@
 static int shmem_unlink(struct inode * dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
+
+	dir->i_size -= BOGO_DIRENT_SIZE;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	inode->i_nlink--;
 	dput(dentry);	/* Undo the count from "create" - this does all the work */
@@ -1122,65 +1132,63 @@
  */
 static int shmem_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry)
 {
-	struct inode *inode;
+	struct inode *inode = old_dentry->d_inode;
+	int they_are_dirs = S_ISDIR(inode->i_mode);
 
 	if (!shmem_empty(new_dentry)) 
 		return -ENOTEMPTY;
 
-	inode = new_dentry->d_inode;
-	if (inode) {
-		inode->i_ctime = CURRENT_TIME;
-		inode->i_nlink--;
-		dput(new_dentry);
-	}
-	inode = old_dentry->d_inode;
-	if (S_ISDIR(inode->i_mode)) {
+	if (new_dentry->d_inode) {
+		(void) shmem_unlink(new_dir, new_dentry);
+		if (they_are_dirs)
+			old_dir->i_nlink--;
+	} else if (they_are_dirs) {
 		old_dir->i_nlink--;
 		new_dir->i_nlink++;
 	}
 
-	inode->i_ctime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+	old_dir->i_size -= BOGO_DIRENT_SIZE;
+	new_dir->i_size += BOGO_DIRENT_SIZE;
+	old_dir->i_ctime = old_dir->i_mtime =
+	new_dir->i_ctime = new_dir->i_mtime =
+	inode->i_ctime = CURRENT_TIME;
 	return 0;
 }
 
 static int shmem_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
 {
-	int error;
 	int len;
 	struct inode *inode;
 	struct page *page;
 	char *kaddr;
 	struct shmem_inode_info * info;
 
-	error = shmem_mknod(dir, dentry, S_IFLNK | S_IRWXUGO, 0);
-	if (error)
-		return error;
-
 	len = strlen(symname) + 1;
-	inode = dentry->d_inode;
+	if (len > PAGE_CACHE_SIZE)
+		return -ENAMETOOLONG;
+
+	inode = shmem_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0);
+	if (!inode)
+		return -ENOSPC;
+
 	info = SHMEM_I(inode);
 	inode->i_size = len-1;
-	inode->i_op = &shmem_symlink_inline_operations;
-
 	if (len <= sizeof(struct shmem_inode_info)) {
 		/* do it inline */
 		memcpy(info, symname, len);
+		inode->i_op = &shmem_symlink_inline_operations;
 	} else {
-		if (len > PAGE_CACHE_SIZE) {
-			error = -ENAMETOOLONG;
-			goto rmnod;
-		}
-		inode->i_op = &shmem_symlink_inode_operations;
-		spin_lock (&shmem_ilock);
-		list_add_tail(&info->list, &shmem_inodes);
-		spin_unlock (&shmem_ilock);
 		down(&info->sem);
 		page = shmem_getpage_locked(info, inode, 0);
 		if (IS_ERR(page)) {
 			up(&info->sem);
-			error = PTR_ERR(page);
-			goto rmnod;
+			iput(inode);
+			return PTR_ERR(page);
 		}
+		inode->i_op = &shmem_symlink_inode_operations;
+		spin_lock (&shmem_ilock);
+		list_add_tail(&info->list, &shmem_inodes);
+		spin_unlock (&shmem_ilock);
 		kaddr = kmap(page);
 		memcpy(kaddr, symname, len);
 		kunmap(page);
@@ -1189,13 +1197,11 @@
 		page_cache_release(page);
 		up(&info->sem);
 	}
+	dir->i_size += BOGO_DIRENT_SIZE;
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+	d_instantiate(dentry, inode);
+	dget(dentry);
 	return 0;
-
-rmnod:
-	if (!shmem_unlink(dir, dentry))
-		d_delete(dentry);
-	return error;
 }
 
 static int shmem_readlink_inline(struct dentry *dentry, char *buffer, int buflen)
@@ -1355,7 +1361,7 @@
 	sbinfo->free_blocks = blocks;
 	sbinfo->max_inodes = inodes;
 	sbinfo->free_inodes = inodes;
-	sb->s_maxbytes = (unsigned long long) SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT;
+	sb->s_maxbytes = SHMEM_MAX_BYTES;
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
 	sb->s_magic = TMPFS_MAGIC;
@@ -1489,10 +1495,10 @@
 	struct qstr this;
 	int vm_enough_memory(long pages);
 
-	if (size > (unsigned long long) SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT)
+	if (size > SHMEM_MAX_BYTES)
 		return ERR_PTR(-EINVAL);
 
-	if (!vm_enough_memory((size) >> PAGE_CACHE_SHIFT))
+	if (!vm_enough_memory(VM_ACCT(size)))
 		return ERR_PTR(-ENOMEM);
 
 	this.name = name;
@@ -1514,13 +1520,12 @@
 		goto close_file;
 
 	d_instantiate(dentry, inode);
-	dentry->d_inode->i_size = size;
-	shmem_truncate(inode);
+	inode->i_size = size;
+	inode->i_nlink = 0;	/* It is unlinked */
 	file->f_vfsmnt = mntget(shm_mnt);
 	file->f_dentry = dentry;
 	file->f_op = &shmem_file_operations;
 	file->f_mode = FMODE_WRITE | FMODE_READ;
-	inode->i_nlink = 0;	/* It is unlinked */
 	return(file);
 
 close_file:
@@ -1529,6 +1534,7 @@
 	dput (dentry);
 	return ERR_PTR(error);	
 }
+
 /*
  * shmem_zero_setup - setup a shared anonymous mapping
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/mm/slab.c linux-2.4.20/mm/slab.c
--- linux-2.4.19/mm/slab.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/mm/slab.c	2002-10-29 11:18:34.000000000 +0000
@@ -123,7 +123,7 @@
  * Bufctl's are used for linking objs within a slab
  * linked offsets.
  *
- * This implementaion relies on "struct page" for locating the cache &
+ * This implementation relies on "struct page" for locating the cache &
  * slab an object belongs to.
  * This allows the bufctl structure to be small (one int), but limits
  * the number of objects a slab (not a cache) can contain when off-slab
@@ -970,8 +970,6 @@
 	if (!cachep || in_interrupt() || !is_chained_kmem_cache(cachep))
 		BUG();
 
-	drain_cpu_caches(cachep);
-  
 	spin_lock_irq(&cachep->spinlock);
 	ret = __kmem_cache_shrink_locked(cachep);
 	spin_unlock_irq(&cachep->spinlock);
@@ -1608,6 +1606,15 @@
 	local_irq_restore(flags);
 }
 
+unsigned int kmem_cache_size(kmem_cache_t *cachep)
+{
+#if DEBUG
+	if (cachep->flags & SLAB_RED_ZONE)
+		return (cachep->objsize - 2*BYTES_PER_WORD);
+#endif
+	return cachep->objsize;
+}
+
 kmem_cache_t * kmem_find_general_cachep (size_t size, int gfpflags)
 {
 	cache_sizes_t *csizep = cache_sizes;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/mm/swap.c linux-2.4.20/mm/swap.c
--- linux-2.4.19/mm/swap.c	2001-11-07 06:44:20.000000000 +0000
+++ linux-2.4.20/mm/swap.c	2002-10-29 11:18:38.000000000 +0000
@@ -57,9 +57,10 @@
  */
 void lru_cache_add(struct page * page)
 {
-	if (!TestSetPageLRU(page)) {
+	if (!PageLRU(page)) {
 		spin_lock(&pagemap_lru_lock);
-		add_page_to_inactive_list(page);
+		if (!TestSetPageLRU(page))
+			add_page_to_inactive_list(page);
 		spin_unlock(&pagemap_lru_lock);
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/mm/swap_state.c linux-2.4.20/mm/swap_state.c
--- linux-2.4.19/mm/swap_state.c	2001-10-31 23:31:03.000000000 +0000
+++ linux-2.4.20/mm/swap_state.c	2002-10-29 11:18:39.000000000 +0000
@@ -117,7 +117,8 @@
 	if (!PageLocked(page))
 		BUG();
 
-	block_flushpage(page, 0);
+	if (unlikely(!block_flushpage(page, 0)))
+		BUG();	/* an anonymous page cannot have page->buffers set */
 
 	entry.val = page->index;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/mm/vmalloc.c linux-2.4.20/mm/vmalloc.c
--- linux-2.4.19/mm/vmalloc.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.20/mm/vmalloc.c	2002-10-29 11:18:48.000000000 +0000
@@ -177,6 +177,8 @@
 	if (!area)
 		return NULL;
 	size += PAGE_SIZE;
+	if(!size)
+		return NULL;
 	addr = VMALLOC_START;
 	write_lock(&vmlist_lock);
 	for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/mm/vmscan.c linux-2.4.20/mm/vmscan.c
--- linux-2.4.19/mm/vmscan.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/mm/vmscan.c	2002-10-29 11:18:33.000000000 +0000
@@ -1,6 +1,9 @@
 /*
  *  linux/mm/vmscan.c
  *
+ *  The pageout daemon, decides which pages to evict (swap out) and
+ *  does the actual work of freeing them.
+ *
  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
  *
  *  Swap reorganised 29.12.95, Stephen Tweedie.
@@ -581,7 +584,7 @@
 	return nr_pages;
 }
 
-int try_to_free_pages(zone_t *classzone, unsigned int gfp_mask, unsigned int order)
+int try_to_free_pages_zone(zone_t *classzone, unsigned int gfp_mask)
 {
 	int priority = DEF_PRIORITY;
 	int nr_pages = SWAP_CLUSTER_MAX;
@@ -601,6 +604,25 @@
 	return 0;
 }
 
+int try_to_free_pages(unsigned int gfp_mask)
+{
+	pg_data_t *pgdat;
+	zonelist_t *zonelist;
+	unsigned long pf_free_pages;
+	int error = 0;
+
+	pf_free_pages = current->flags & PF_FREE_PAGES;
+	current->flags &= ~PF_FREE_PAGES;
+
+	for_each_pgdat(pgdat) {
+		zonelist = pgdat->node_zonelists + (gfp_mask & GFP_ZONEMASK);
+		error |= try_to_free_pages_zone(zonelist->zones[0], gfp_mask);
+	}
+
+	current->flags |= pf_free_pages;
+	return error;
+}
+
 DECLARE_WAIT_QUEUE_HEAD(kswapd_wait);
 
 static int check_classzone_need_balance(zone_t * classzone)
@@ -627,7 +649,7 @@
 			schedule();
 		if (!zone->need_balance)
 			continue;
-		if (!try_to_free_pages(zone, GFP_KSWAPD, 0)) {
+		if (!try_to_free_pages_zone(zone, GFP_KSWAPD)) {
 			zone->need_balance = 0;
 			__set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(HZ);
@@ -649,10 +671,9 @@
 
 	do {
 		need_more_balance = 0;
-		pgdat = pgdat_list;
-		do
+
+		for_each_pgdat(pgdat)
 			need_more_balance |= kswapd_balance_pgdat(pgdat);
-		while ((pgdat = pgdat->node_next));
 	} while (need_more_balance);
 }
 
@@ -675,12 +696,10 @@
 {
 	pg_data_t * pgdat;
 
-	pgdat = pgdat_list;
-	do {
-		if (kswapd_can_sleep_pgdat(pgdat))
-			continue;
-		return 0;
-	} while ((pgdat = pgdat->node_next));
+	for_each_pgdat(pgdat) {
+		if (!kswapd_can_sleep_pgdat(pgdat))
+			return 0;
+	}
 
 	return 1;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/8021q/vlan.c linux-2.4.20/net/8021q/vlan.c
--- linux-2.4.19/net/8021q/vlan.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/8021q/vlan.c	2002-10-29 11:18:49.000000000 +0000
@@ -91,9 +91,9 @@
 	/* proc file system initialization */
 	err = vlan_proc_init();
 	if (err < 0) {
-		printk(KERN_ERR __FUNCTION__
-		       "%s: can't create entry in proc filesystem!\n",
-		       VLAN_NAME);
+		printk(KERN_ERR 
+		       "%s %s: can't create entry in proc filesystem!\n",
+		       __FUNCTION__, VLAN_NAME);
 		return 1;
 	}
 
@@ -203,11 +203,11 @@
 	int i, ret;
 
 #ifdef VLAN_DEBUG
-	printk(VLAN_DBG __FUNCTION__ ": VID: %i\n", vlan_id);
+	printk(VLAN_DBG "%s: VID: %i\n", __FUNCTION__, vlan_id);
 #endif
 
 	/* sanity check */
-	if ((vlan_id >= VLAN_VID_MASK) || (vlan_id <= 0))
+	if (vlan_id >= VLAN_VID_MASK)
 		return -EINVAL;
 
 	spin_lock_bh(&vlan_group_lock);
@@ -289,16 +289,16 @@
 			if (ret == 1)
 				ret = 0;
 		} else {
-			printk(VLAN_ERR __FUNCTION__
-			       ": ERROR:	Tried to remove a non-vlan device "
+			printk(VLAN_ERR 
+			       "%s: ERROR:	Tried to remove a non-vlan device "
 			       "with VLAN code, name: %s  priv_flags: %hX\n",
-			       dev->name, dev->priv_flags);
+			       __FUNCTION__, dev->name, dev->priv_flags);
 			dev_put(dev);
 			ret = -EPERM;
 		}
 	} else {
 #ifdef VLAN_DEBUG
-		printk(VLAN_DBG __FUNCTION__ ": WARNING: Could not find dev.\n");
+		printk(VLAN_DBG "%s: WARNING: Could not find dev.\n", __FUNCTION__);
 #endif
 		ret = -EINVAL;
 	}
@@ -320,8 +320,8 @@
 	int r;
 
 #ifdef VLAN_DEBUG
-	printk(VLAN_DBG __FUNCTION__ ": if_name -:%s:-	vid: %i\n",
-	       eth_IF_name, VLAN_ID);
+	printk(VLAN_DBG "%s: if_name -:%s:-	vid: %i\n",
+		__FUNCTION__, eth_IF_name, VLAN_ID);
 #endif
 
 	if (VLAN_ID >= VLAN_VID_MASK)
@@ -333,24 +333,24 @@
 		goto out_ret_null;
 
 	if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {
-		printk(VLAN_DBG __FUNCTION__ ": VLANs not supported on %s.\n",
-		       real_dev->name);
+		printk(VLAN_DBG "%s: VLANs not supported on %s.\n",
+			__FUNCTION__, real_dev->name);
 		goto out_put_dev;
 	}
 
 	if ((real_dev->features & NETIF_F_HW_VLAN_RX) &&
 	    (real_dev->vlan_rx_register == NULL ||
 	     real_dev->vlan_rx_kill_vid == NULL)) {
-		printk(VLAN_DBG __FUNCTION__ ": Device %s has buggy VLAN hw accel.\n",
-		       real_dev->name);
+		printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",
+			__FUNCTION__, real_dev->name);
 		goto out_put_dev;
 	}
 
 	if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) &&
 	    (real_dev->vlan_rx_add_vid == NULL ||
 	     real_dev->vlan_rx_kill_vid == NULL)) {
-		printk(VLAN_DBG __FUNCTION__ ": Device %s has buggy VLAN hw accel.\n",
-		       real_dev->name);
+		printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",
+			__FUNCTION__, real_dev->name);
 		goto out_put_dev;
 	}
 
@@ -371,7 +371,7 @@
 
 	if (r) {
 		/* was already registered. */
-		printk(VLAN_DBG __FUNCTION__ ": ALREADY had VLAN registered\n");
+		printk(VLAN_DBG "%s: ALREADY had VLAN registered\n", __FUNCTION__);
 		goto out_unlock;
 	}
 
@@ -626,7 +626,7 @@
 			ret = unregister_vlan_dev(dev,
 						  VLAN_DEV_INFO(vlandev)->vlan_id);
 
-			unregister_netdev(vlandev);
+			unregister_netdevice(vlandev);
 
 			/* Group was destroyed? */
 			if (ret == 1)
@@ -665,7 +665,7 @@
 	args.u.device2[23] = 0;
 
 #ifdef VLAN_DEBUG
-	printk(VLAN_DBG __FUNCTION__ ": args.cmd: %x\n", args.cmd);
+	printk(VLAN_DBG "%s: args.cmd: %x\n", __FUNCTION__, args.cmd);
 #endif
 
 	switch (args.cmd) {
@@ -728,8 +728,8 @@
 
 	default:
 		/* pass on to underlying device instead?? */
-		printk(VLAN_DBG __FUNCTION__ ": Unknown VLAN CMD: %x \n",
-		       args.cmd);
+		printk(VLAN_DBG "%s: Unknown VLAN CMD: %x \n",
+			__FUNCTION__, args.cmd);
 		return -EINVAL;
 	};
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/8021q/vlan_dev.c linux-2.4.20/net/8021q/vlan_dev.c
--- linux-2.4.19/net/8021q/vlan_dev.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/8021q/vlan_dev.c	2002-10-29 11:18:50.000000000 +0000
@@ -125,8 +125,8 @@
 	vid = (vlan_TCI & VLAN_VID_MASK);
 
 #ifdef VLAN_DEBUG
-	printk(VLAN_DBG __FUNCTION__ ": skb: %p vlan_id: %hx\n",
-	       skb, vid);
+	printk(VLAN_DBG "%s: skb: %p vlan_id: %hx\n",
+		__FUNCTION__, skb, vid);
 #endif
 
 	/* Ok, we will find the correct VLAN device, strip the header,
@@ -146,8 +146,8 @@
 		spin_unlock_bh(&vlan_group_lock);
 
 #ifdef VLAN_DEBUG
-		printk(VLAN_DBG __FUNCTION__ ": ERROR:	No net_device for VID: %i on dev: %s [%i]\n",
-		       (unsigned int)(vid), dev->name, dev->ifindex);
+		printk(VLAN_DBG "%s: ERROR: No net_device for VID: %i on dev: %s [%i]\n",
+			__FUNCTION__, (unsigned int)(vid), dev->name, dev->ifindex);
 #endif
 		kfree_skb(skb);
 		return -1;
@@ -170,8 +170,10 @@
 		spin_unlock_bh(&vlan_group_lock);
 
 #ifdef VLAN_DEBUG
-		printk(VLAN_DBG __FUNCTION__ ": dropping skb: %p because came in on wrong device, dev: %s  real_dev: %s, skb_dev: %s\n",
-		       skb, dev->name, VLAN_DEV_INFO(skb->dev)->real_dev->name, skb->dev->name);
+		printk(VLAN_DBG "%s: dropping skb: %p because came in on wrong device, dev: %s  real_dev: %s, skb_dev: %s\n",
+			__FUNCTION__ skb, dev->name, 
+			VLAN_DEV_INFO(skb->dev)->real_dev->name, 
+			skb->dev->name);
 #endif
 		kfree_skb(skb);
 		stats->rx_errors++;
@@ -184,8 +186,9 @@
 	skb->priority = vlan_get_ingress_priority(skb->dev, ntohs(vhdr->h_vlan_TCI));
 
 #ifdef VLAN_DEBUG
-	printk(VLAN_DBG __FUNCTION__ ": priority: %lu  for TCI: %hu (hbo)\n",
-	       (unsigned long)(skb->priority), ntohs(vhdr->h_vlan_TCI));
+	printk(VLAN_DBG "%s: priority: %lu  for TCI: %hu (hbo)\n",
+		__FUNCTION__, (unsigned long)(skb->priority), 
+		ntohs(vhdr->h_vlan_TCI));
 #endif
 
 	/* The ethernet driver already did the pkt_type calculations
@@ -331,8 +334,8 @@
 	struct net_device *vdev = dev; /* save this for the bottom of the method */
 
 #ifdef VLAN_DEBUG
-	printk(VLAN_DBG __FUNCTION__ ": skb: %p type: %hx len: %x vlan_id: %hx, daddr: %p\n",
-	       skb, type, len, VLAN_DEV_INFO(dev)->vlan_id, daddr);
+	printk(VLAN_DBG "%s: skb: %p type: %hx len: %x vlan_id: %hx, daddr: %p\n",
+		__FUNCTION__, skb, type, len, VLAN_DEV_INFO(dev)->vlan_id, daddr);
 #endif
 
 	/* build vlan header only if re_order_header flag is NOT set.  This
@@ -402,7 +405,7 @@
 		}
 		VLAN_DEV_INFO(vdev)->cnt_inc_headroom_on_tx++;
 #ifdef VLAN_DEBUG
-		printk(VLAN_DBG __FUNCTION__ ": %s: had to grow skb.\n", vdev->name);
+		printk(VLAN_DBG "%s: %s: had to grow skb.\n", __FUNCTION__, vdev->name);
 #endif
 	}
 
@@ -445,8 +448,8 @@
 		VLAN_DEV_INFO(dev)->cnt_encap_on_xmit++;
 
 #ifdef VLAN_DEBUG
-		printk(VLAN_DBG __FUNCTION__ ": proto to encap: 0x%hx (hbo)\n",
-		       htons(veth->h_vlan_proto));
+		printk(VLAN_DBG "%s: proto to encap: 0x%hx (hbo)\n",
+			__FUNCTION__, htons(veth->h_vlan_proto));
 #endif
 
 		if (skb_headroom(skb) < VLAN_HLEN) {
@@ -455,14 +458,14 @@
 			kfree_skb(sk_tmp);
 			if (skb == NULL) {
 				stats->tx_dropped++;
-				return -ENOMEM;
+				return 0;
 			}
 			VLAN_DEV_INFO(dev)->cnt_inc_headroom_on_tx++;
 		} else {
 			if (!(skb = skb_unshare(skb, GFP_ATOMIC))) {
 				printk(KERN_ERR "vlan: failed to unshare skbuff\n");
 				stats->tx_dropped++;
-				return -ENOMEM;
+				return 0;
 			}
 		}
 		veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
@@ -489,8 +492,8 @@
 	skb->dev = VLAN_DEV_INFO(dev)->real_dev;
 
 #ifdef VLAN_DEBUG
-	printk(VLAN_DBG __FUNCTION__ ": about to send skb: %p to dev: %s\n",
-	       skb, skb->dev->name);
+	printk(VLAN_DBG "%s: about to send skb: %p to dev: %s\n",
+		__FUNCTION__, skb, skb->dev->name);
 	printk(VLAN_DBG "  %2hx.%2hx.%2hx.%2xh.%2hx.%2hx %2hx.%2hx.%2hx.%2hx.%2hx.%2hx %4hx %4hx %4hx\n",
 	       veth->h_dest[0], veth->h_dest[1], veth->h_dest[2], veth->h_dest[3], veth->h_dest[4], veth->h_dest[5],
 	       veth->h_source[0], veth->h_source[1], veth->h_source[2], veth->h_source[3], veth->h_source[4], veth->h_source[5],
@@ -570,6 +573,7 @@
 					dev_put(dev);
 					return 0;
 				}
+				mp = mp->next;
 			}
 
 			/* Create a new mapping then. */
@@ -609,19 +613,20 @@
 				dev_put(dev);
 				return 0;
 			} else {
-				printk(KERN_ERR __FUNCTION__ ": flag %i is not valid.\n",
-				       (int)(flag));
+				printk(KERN_ERR  "%s: flag %i is not valid.\n",
+					__FUNCTION__, (int)(flag));
 				dev_put(dev);
 				return -EINVAL;
 			}
 		} else {
-			printk(KERN_ERR __FUNCTION__
-			       ": %s is not a vlan device, priv_flags: %hX.\n",
-			       dev->name, dev->priv_flags);
+			printk(KERN_ERR 
+			       "%s: %s is not a vlan device, priv_flags: %hX.\n",
+			       __FUNCTION__, dev->name, dev->priv_flags);
 			dev_put(dev);
 		}
 	} else {
-		printk(KERN_ERR __FUNCTION__ ": Could not find device: %s\n", dev_name);
+		printk(KERN_ERR  "%s: Could not find device: %s\n", 
+			__FUNCTION__, dev_name);
 	}
 
 	return -EINVAL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/8021q/vlanproc.c linux-2.4.20/net/8021q/vlanproc.c
--- linux-2.4.19/net/8021q/vlanproc.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/8021q/vlanproc.c	2002-10-29 11:18:36.000000000 +0000
@@ -188,14 +188,14 @@
 int vlan_proc_rem_dev(struct net_device *vlandev)
 {
 	if (!vlandev) {
-		printk(VLAN_ERR __FUNCTION__ ": invalid argument: %p\n",
-		       vlandev);
+		printk(VLAN_ERR "%s: invalid argument: %p\n",
+			__FUNCTION__, vlandev);
 		return -EINVAL;
 	}
 
 	if (!(vlandev->priv_flags & IFF_802_1Q_VLAN)) {
-		printk(VLAN_DBG __FUNCTION__ ": invalid argument, device: %s is not a VLAN device, priv_flags: 0x%4hX.\n",
-		       vlandev->name, vlandev->priv_flags);
+		printk(VLAN_DBG "%s: invalid argument, device: %s is not a VLAN device, priv_flags: 0x%4hX.\n",
+			__FUNCTION__, vlandev->name, vlandev->priv_flags);
 		return -EINVAL;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/atm/proc.c linux-2.4.20/net/atm/proc.c
--- linux-2.4.19/net/atm/proc.c	2001-07-04 18:50:38.000000000 +0000
+++ linux-2.4.20/net/atm/proc.c	2002-10-29 11:18:35.000000000 +0000
@@ -551,9 +551,12 @@
 	digits = 0;
 	for (num = dev->number; num; num /= 10) digits++;
 	if (!digits) digits++;
-	dev->proc_name = kmalloc(strlen(dev->type)+digits+2,GFP_KERNEL);
-	if (!dev->proc_name) goto fail1;
+
+	dev->proc_name = kmalloc(strlen(dev->type) + digits + 2, GFP_ATOMIC);
+	if (!dev->proc_name)
+		goto fail1;
 	sprintf(dev->proc_name,"%s:%d",dev->type, dev->number);
+
 	dev->proc_entry = create_proc_entry(dev->proc_name, 0, atm_proc_root);
 	if (!dev->proc_entry)
 		goto fail0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/atm/resources.c linux-2.4.20/net/atm/resources.c
--- linux-2.4.19/net/atm/resources.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/atm/resources.c	2002-10-29 11:18:39.000000000 +0000
@@ -27,15 +27,14 @@
 struct atm_vcc *nodev_vccs = NULL;
 extern spinlock_t atm_dev_lock;
 
-/* Caller must hold atm_dev_lock. */
-static struct atm_dev *__alloc_atm_dev(const char *type)
+
+static struct atm_dev *alloc_atm_dev(const char *type)
 {
 	struct atm_dev *dev;
 
 	dev = kmalloc(sizeof(*dev), GFP_ATOMIC);
-	if (!dev)
-		return NULL;
-	memset(dev, 0, sizeof(*dev));
+	if (!dev) return NULL;
+	memset(dev,0,sizeof(*dev));
 	dev->type = type;
 	dev->signal = ATM_PHY_SIG_UNKNOWN;
 	dev->link_rate = ATM_OC3_PCR;
@@ -43,118 +42,100 @@
 
 	dev->prev = last_dev;
 
-	if (atm_devs)
-		last_dev->next = dev;
-	else
-		atm_devs = dev;
+	if (atm_devs) last_dev->next = dev;
+	else atm_devs = dev;
 	last_dev = dev;
-
 	return dev;
 }
 
-/* Caller must hold atm_dev_lock. */
-static void __free_atm_dev(struct atm_dev *dev)
-{
-	if (dev->prev)
-		dev->prev->next = dev->next;
-	else
-		atm_devs = dev->next;
-
-	if (dev->next)
-		dev->next->prev = dev->prev;
-	else
-		last_dev = dev->prev;
 
+static void free_atm_dev(struct atm_dev *dev)
+{
+	if (dev->prev) dev->prev->next = dev->next;
+	else atm_devs = dev->next;
+	if (dev->next) dev->next->prev = dev->prev;
+	else last_dev = dev->prev;
 	kfree(dev);
 }
 
-/* Caller must hold atm_dev_lock. */
 struct atm_dev *atm_find_dev(int number)
 {
 	struct atm_dev *dev;
 
 	for (dev = atm_devs; dev; dev = dev->next)
-		if (dev->ops && dev->number == number)
-			return dev;
+		if (dev->ops && dev->number == number) return dev;
 	return NULL;
 }
 
-struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
-				 int number, atm_dev_flags_t *flags)
+struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
+    int number,atm_dev_flags_t *flags)
 {
-	struct atm_dev *dev;
+	struct atm_dev *dev = NULL;
 
 	spin_lock(&atm_dev_lock);
 
-	dev = __alloc_atm_dev(type);
+	dev = alloc_atm_dev(type);
 	if (!dev) {
 		printk(KERN_ERR "atm_dev_register: no space for dev %s\n",
-		       type);
+		    type);
 		goto done;
 	}
 	if (number != -1) {
 		if (atm_find_dev(number)) {
-			__free_atm_dev(dev);
-			dev = NULL;
-			goto done;
+			free_atm_dev(dev);
+			return NULL;
 		}
 		dev->number = number;
 	} else {
 		dev->number = 0;
-		while (atm_find_dev(dev->number))
-			dev->number++;
+		while (atm_find_dev(dev->number)) dev->number++;
 	}
 	dev->vccs = dev->last = NULL;
 	dev->dev_data = NULL;
 	barrier();
 	dev->ops = ops;
-	if (flags)
+	if (flags) 
 		dev->flags = *flags;
-	else
-		memset(&dev->flags, 0, sizeof(dev->flags));
-	memset(&dev->stats, 0, sizeof(dev->stats));
-
+	else 
+		memset(&dev->flags,0,sizeof(dev->flags));
+	memset((void *) &dev->stats,0,sizeof(dev->stats));
 #ifdef CONFIG_PROC_FS
-	if (ops->proc_read) {
+	if (ops->proc_read)
 		if (atm_proc_dev_register(dev) < 0) {
 			printk(KERN_ERR "atm_dev_register: "
-			       "atm_proc_dev_register failed for dev %s\n",
-			       type);
-			__free_atm_dev(dev);
-			dev = NULL;
+			    "atm_proc_dev_register failed for dev %s\n",type);
+			free_atm_dev(dev);
 			goto done;
 		}
-	}
 #endif
 
 done:
-	spin_unlock(&atm_dev_lock);		
-
+	spin_unlock(&atm_dev_lock);
 	return dev;
 }
 
+
 void atm_dev_deregister(struct atm_dev *dev)
 {
 #ifdef CONFIG_PROC_FS
-	if (dev->ops->proc_read)
-		atm_proc_dev_deregister(dev);
+	if (dev->ops->proc_read) atm_proc_dev_deregister(dev);
 #endif
 	spin_lock(&atm_dev_lock);
-	__free_atm_dev(dev);
+	free_atm_dev(dev);
 	spin_unlock(&atm_dev_lock);
 }
 
 void shutdown_atm_dev(struct atm_dev *dev)
 {
 	if (dev->vccs) {
-		set_bit(ATM_DF_CLOSE, &dev->flags);
+		set_bit(ATM_DF_CLOSE,&dev->flags);
 		return;
 	}
-	if (dev->ops->dev_close)
-		dev->ops->dev_close(dev);
+	if (dev->ops->dev_close) dev->ops->dev_close(dev);
 	atm_dev_deregister(dev);
 }
 
+
 /* Handler for sk->destruct, invoked by sk_free() */
 static void atm_free_sock(struct sock *sk)
 {
@@ -167,48 +148,44 @@
 	struct atm_vcc *vcc;
 
 	sk = sk_alloc(family, GFP_KERNEL, 1);
-	if (!sk)
-		return NULL;
+	if (!sk) return NULL;
 	vcc = sk->protinfo.af_atm = kmalloc(sizeof(*vcc),GFP_KERNEL);
 	if (!vcc) {
 		sk_free(sk);
 		return NULL;
 	}
-	sock_init_data(NULL, sk);
+	sock_init_data(NULL,sk);
 	sk->destruct = atm_free_sock;
 	memset(vcc,0,sizeof(*vcc));
 	vcc->sk = sk;
-	if (nodev_vccs)
-		nodev_vccs->prev = vcc;
+	if (nodev_vccs) nodev_vccs->prev = vcc;
 	vcc->prev = NULL;
 	vcc->next = nodev_vccs;
 	nodev_vccs = vcc;
 	return sk;
 }
 
+
 static void unlink_vcc(struct atm_vcc *vcc,struct atm_dev *hold_dev)
 {
-	if (vcc->prev)
-		vcc->prev->next = vcc->next;
-	else if (vcc->dev)
-		vcc->dev->vccs = vcc->next;
-	else
-		nodev_vccs = vcc->next;
-	if (vcc->next)
-		vcc->next->prev = vcc->prev;
-	else if (vcc->dev)
-		vcc->dev->last = vcc->prev;
+	if (vcc->prev) vcc->prev->next = vcc->next;
+	else if (vcc->dev) vcc->dev->vccs = vcc->next;
+	    else nodev_vccs = vcc->next;
+	if (vcc->next) vcc->next->prev = vcc->prev;
+	else if (vcc->dev) vcc->dev->last = vcc->prev;
 	if (vcc->dev && vcc->dev != hold_dev && !vcc->dev->vccs &&
 	    test_bit(ATM_DF_CLOSE,&vcc->dev->flags))
 		shutdown_atm_dev(vcc->dev);
 }
 
+
 void free_atm_vcc_sk(struct sock *sk)
 {
-	unlink_vcc(sk->protinfo.af_atm, NULL);
+	unlink_vcc(sk->protinfo.af_atm,NULL);
 	sk_free(sk);
 }
 
+
 void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev)
 {
 	unlink_vcc(vcc,dev);
@@ -216,20 +193,19 @@
 	if (dev) {
 		vcc->next = NULL;
 		vcc->prev = dev->last;
-		if (dev->vccs)
-			dev->last->next = vcc;
-		else
-			dev->vccs = vcc;
+		if (dev->vccs) dev->last->next = vcc;
+		else dev->vccs = vcc;
 		dev->last = vcc;
-	} else {
-		if (nodev_vccs)
-			nodev_vccs->prev = vcc;
+	}
+	else {
+		if (nodev_vccs) nodev_vccs->prev = vcc;
 		vcc->next = nodev_vccs;
 		vcc->prev = NULL;
 		nodev_vccs = vcc;
 	}
 }
 
+
 EXPORT_SYMBOL(atm_dev_register);
 EXPORT_SYMBOL(atm_dev_deregister);
 EXPORT_SYMBOL(atm_find_dev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/Config.in linux-2.4.20/net/bluetooth/Config.in
--- linux-2.4.19/net/bluetooth/Config.in	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/bluetooth/Config.in	2002-10-29 11:18:49.000000000 +0000
@@ -10,6 +10,7 @@
    if [ "$CONFIG_BLUEZ" != "n" ]; then
       dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ
       dep_tristate 'SCO links support' CONFIG_BLUEZ_SCO $CONFIG_BLUEZ
+      source net/bluetooth/bnep/Config.in
       source drivers/bluetooth/Config.in
    fi
    endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/Makefile linux-2.4.20/net/bluetooth/Makefile
--- linux-2.4.19/net/bluetooth/Makefile	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/bluetooth/Makefile	2002-10-29 11:18:34.000000000 +0000
@@ -1,16 +1,23 @@
 #
 # Makefile for the Bluetooth subsystem
 #
-O_TARGET	:= bluetooth.o
+O_TARGET    := bluetooth.o
 
-list-multi	:= bluez.o
-export-objs	:= syms.o
-bluez-objs	:= af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o
+list-multi  := bluez.o
+export-objs := syms.o
+
+bluez-objs  := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o
 
 obj-$(CONFIG_BLUEZ) += bluez.o
 obj-$(CONFIG_BLUEZ_L2CAP) += l2cap.o
 obj-$(CONFIG_BLUEZ_SCO) += sco.o
 
+subdir-$(CONFIG_BLUEZ_BNEP) += bnep
+
+ifeq ($(CONFIG_BLUEZ_BNEP),y)
+obj-y += bnep/bnep.o
+endif
+
 include $(TOPDIR)/Rules.make
 
 bluez.o: $(bluez-objs)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/af_bluetooth.c linux-2.4.20/net/bluetooth/af_bluetooth.c
--- linux-2.4.19/net/bluetooth/af_bluetooth.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/bluetooth/af_bluetooth.c	2002-10-29 11:18:34.000000000 +0000
@@ -25,9 +25,9 @@
 /*
  * BlueZ Bluetooth address family and sockets.
  *
- * $Id: af_bluetooth.c,v 1.6 2002/06/25 22:03:39 maxk Exp $
+ * $Id: af_bluetooth.c,v 1.8 2002/07/22 20:32:54 maxk Exp $
  */
-#define VERSION "2.1"
+#define VERSION "2.2"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -111,18 +111,18 @@
 
 void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk)
 {
-	write_lock(&l->lock);
+	write_lock_bh(&l->lock);
 	sk->next = l->head;
 	l->head = sk;
 	sock_hold(sk);
-	write_unlock(&l->lock);
+	write_unlock_bh(&l->lock);
 }
 
 void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *sk)
 {
 	struct sock **skp;
 
-	write_lock(&l->lock);
+	write_lock_bh(&l->lock);
 	for (skp = &l->head; *skp; skp = &((*skp)->next)) {
 		if (*skp == sk) {
 			*skp = sk->next;
@@ -130,7 +130,7 @@
 			break;
 		}
 	}
-	write_unlock(&l->lock);
+	write_unlock_bh(&l->lock);
 }
 
 void bluez_accept_enqueue(struct sock *parent, struct sock *sk)
@@ -242,6 +242,9 @@
 	if (sk->state == BT_CLOSED)
 		mask |= POLLHUP;
 
+	if (sk->state == BT_CONNECT || sk->state == BT_CONNECT2)
+		return mask;
+	
 	if (sock_writeable(sk))
 		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
 	else
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/bnep/Config.in linux-2.4.20/net/bluetooth/bnep/Config.in
--- linux-2.4.19/net/bluetooth/bnep/Config.in	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/bluetooth/bnep/Config.in	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,6 @@
+
+dep_tristate 'BNEP protocol support' CONFIG_BLUEZ_BNEP $CONFIG_BLUEZ_L2CAP
+if [ "$CONFIG_BLUEZ_BNEP" != "n" ]; then
+   bool '  Multicast filter support' CONFIG_BNEP_MC_FILTER
+   bool '  Protocol filter support'  CONFIG_BNEP_PROTO_FILTER
+fi
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/bnep/Makefile linux-2.4.20/net/bluetooth/bnep/Makefile
--- linux-2.4.19/net/bluetooth/bnep/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/bluetooth/bnep/Makefile	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,10 @@
+#
+# Makefile for BNEP protocol
+#
+
+O_TARGET := bnep.o
+
+obj-y	 := core.o sock.o netdev.o crc32.o
+obj-m    += $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/bnep/bnep.h linux-2.4.20/net/bluetooth/bnep/bnep.h
--- linux-2.4.19/net/bluetooth/bnep/bnep.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/bluetooth/bnep/bnep.h	2002-10-29 11:18:50.000000000 +0000
@@ -0,0 +1,185 @@
+/*
+  BNEP protocol definition for Linux Bluetooth stack (BlueZ).
+  Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
+	
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License, version 2, as
+  published by the Free Software Foundation.
+
+  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
+*/
+
+/*
+ * $Id: bnep2.h,v 1.9 2002/07/14 07:09:19 maxk Exp $
+ */
+
+#ifndef _BNEP_H
+#define _BNEP_H
+
+#include <linux/types.h>
+#include <net/bluetooth/bluetooth.h>
+
+#include "crc32.h"
+
+// Limits
+#define BNEP_MAX_PROTO_FILTERS     5
+#define BNEP_MAX_MULTICAST_FILTERS 20
+
+// UUIDs
+#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB
+#define BNEP_UUID16    0x02
+#define BNEP_UUID32    0x04
+#define BNEP_UUID128   0x16
+
+#define BNEP_SVC_PANU  0x1115
+#define BNEP_SVC_NAP   0x1116
+#define BNEP_SVC_GN    0x1117
+
+// Packet types
+#define BNEP_GENERAL               0x00
+#define BNEP_CONTROL               0x01
+#define BNEP_COMPRESSED            0x02
+#define BNEP_COMPRESSED_SRC_ONLY   0x03
+#define BNEP_COMPRESSED_DST_ONLY   0x04
+
+// Control types
+#define BNEP_CMD_NOT_UNDERSTOOD    0x00
+#define BNEP_SETUP_CONN_REQ        0x01
+#define BNEP_SETUP_CONN_RSP        0x02
+#define BNEP_FILTER_NET_TYPE_SET   0x03
+#define BNEP_FILTER_NET_TYPE_RSP   0x04
+#define BNEP_FILTER_MULTI_ADDR_SET 0x05
+#define BNEP_FILTER_MULTI_ADDR_RSP 0x06
+
+// Extension types
+#define BNEP_EXT_CONTROL           0x00
+
+// Response messages 
+#define BNEP_SUCCESS               0x00
+
+#define BNEP_CONN_INVALID_DST      0x01
+#define BNEP_CONN_INVALID_SRC      0x02
+#define BNEP_CONN_INVALID_SVC      0x03
+#define BNEP_CONN_NOT_ALLOWED      0x04
+
+#define BNEP_FILTER_UNSUPPORTED_REQ    0x01
+#define BNEP_FILTER_INVALID_RANGE      0x02
+#define BNEP_FILTER_INVALID_MCADDR     0x02
+#define BNEP_FILTER_LIMIT_REACHED      0x03
+#define BNEP_FILTER_DENIED_SECURITY    0x04
+
+// L2CAP settings
+#define BNEP_MTU         1691
+#define BNEP_PSM	 0x0f
+#define BNEP_FLUSH_TO    0xffff
+#define BNEP_CONNECT_TO  15
+#define BNEP_FILTER_TO   15
+
+// Headers 
+#define BNEP_TYPE_MASK	 0x7f
+#define BNEP_EXT_HEADER	 0x80
+
+struct bnep_setup_conn_req {
+	__u8  type;
+	__u8  ctrl;
+	__u8  uuid_size;
+	__u8  service[0];
+} __attribute__((packed));
+
+struct bnep_set_filter_req {
+	__u8  type;
+	__u8  ctrl;
+	__u16 len;
+	__u8  list[0];
+} __attribute__((packed));
+
+struct bnep_control_rsp {
+	__u8  type;
+	__u8  ctrl;
+	__u16 resp;
+} __attribute__((packed));
+
+struct bnep_ext_hdr {
+	__u8  type;
+	__u8  len;
+	__u8  data[0];
+} __attribute__((packed));
+
+// Ioctl interface
+#define BNEPCONADD      1
+#define BNEPCONDEL      2
+#define BNEPGETCONLIST  3
+#define BNEPGETCONINFO  4
+
+struct bnep_conadd_req {
+	int   sock;       // Connected socket
+	__u32 flags;
+	__u16 role;
+	char  device[16]; // Name of the Ethernet device
+};
+
+struct bnep_condel_req {
+	__u32 flags;
+	__u8  dst[ETH_ALEN];
+};
+
+struct bnep_coninfo {
+	__u32 flags;
+	__u16 role;
+	__u16 state;	
+	__u8  dst[ETH_ALEN];
+	char  device[16];
+};
+
+struct bnep_conlist_req {
+	__u32  cnum;
+	struct bnep_coninfo *ci;
+};
+
+struct bnep_proto_filter {
+	__u16 start;
+	__u16 end;
+};
+
+int bnep_add_connection(struct bnep_conadd_req *req, struct socket *sock);
+int bnep_del_connection(struct bnep_condel_req *req);
+int bnep_get_conlist(struct bnep_conlist_req *req);
+int bnep_get_coninfo(struct bnep_coninfo *ci);
+
+// BNEP sessions
+struct bnep_session {
+	struct list_head list;
+	
+	unsigned int  role;
+        unsigned long state;
+        unsigned long flags;
+	atomic_t      killed;
+
+	struct ethhdr eh;
+	struct msghdr msg;
+
+	struct bnep_proto_filter proto_filter[BNEP_MAX_PROTO_FILTERS];
+	u64    mc_filter;
+	
+	struct socket    *sock;
+	struct net_device dev;
+	struct net_device_stats stats;
+};
+
+int bnep_net_init(struct net_device *dev);
+int bnep_sock_init(void);
+int bnep_sock_cleanup(void);
+
+static inline int bnep_mc_hash(__u8 *addr)
+{
+        return (bnep_crc32(~0, addr, ETH_ALEN) >> 26);
+}
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/bnep/core.c linux-2.4.20/net/bluetooth/bnep/core.c
--- linux-2.4.19/net/bluetooth/bnep/core.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/bluetooth/bnep/core.c	2002-10-29 11:18:51.000000000 +0000
@@ -0,0 +1,706 @@
+/* 
+   BNEP implementation for Linux Bluetooth stack (BlueZ).
+   Copyright (C) 2001-2002 Inventel Systemes
+   Written 2001-2002 by
+	Clment Moreau <clement.moreau@inventel.fr>
+	David Libault  <david.libault@inventel.fr>
+
+   Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * $Id: core.c,v 1.18 2002/07/14 07:09:19 maxk Exp $
+ */ 
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/smp_lock.h>
+#include <linux/net.h>
+#include <net/sock.h>
+
+#include <linux/socket.h>
+#include <linux/file.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/unaligned.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/l2cap.h>
+
+#include "bnep.h"
+
+#ifndef CONFIG_BNEP_DEBUG
+#undef  BT_DBG
+#define BT_DBG(D...)
+#endif
+
+#define VERSION "1.0"
+
+static LIST_HEAD(bnep_session_list);
+static DECLARE_RWSEM(bnep_session_sem);
+
+static struct bnep_session *__bnep_get_session(__u8 *dst)
+{
+	struct bnep_session *s;
+	struct list_head *p;
+
+	BT_DBG("");
+
+	list_for_each(p, &bnep_session_list) {
+		s = list_entry(p, struct bnep_session, list);	
+		if (!memcmp(dst, s->eh.h_source, ETH_ALEN))
+			return s;
+	}
+	return NULL;
+}
+
+static void __bnep_link_session(struct bnep_session *s)
+{
+	MOD_INC_USE_COUNT;
+	list_add(&s->list, &bnep_session_list);	
+}
+
+static void __bnep_unlink_session(struct bnep_session *s)
+{
+	list_del(&s->list);
+	MOD_DEC_USE_COUNT;
+}
+
+static int bnep_send(struct bnep_session *s, void *data, size_t len)
+{
+	struct socket *sock = s->sock;
+	struct iovec iv = { data, len };
+	s->msg.msg_iov    = &iv;
+	s->msg.msg_iovlen = 1;
+	return sock->ops->sendmsg(sock, &s->msg, len, NULL);
+}
+
+static int bnep_send_rsp(struct bnep_session *s, __u8 ctrl, __u16 resp)
+{
+	struct bnep_control_rsp rsp;
+	rsp.type = BNEP_CONTROL;
+	rsp.ctrl = ctrl;
+	rsp.resp = htons(resp);
+	return bnep_send(s, &rsp, sizeof(rsp));
+}
+
+static int bnep_ctrl_set_netfilter(struct bnep_session *s, struct sk_buff *skb)
+{
+	__u16 *data;
+	int n;
+	
+	data = (void *) skb->data;
+	if (!skb_pull(skb, 2))
+		return -EILSEQ;
+	n = ntohs(get_unaligned(data));
+
+	data = (void *) skb->data;
+	if (!skb_pull(skb, n))
+		return -EILSEQ;
+
+	BT_DBG("filter len %d", n);
+
+#ifdef CONFIG_BNEP_PROTO_FILTER
+	n /= 4;
+	if (n <= BNEP_MAX_PROTO_FILTERS) {
+		struct bnep_proto_filter *f = s->proto_filter;
+		int i;
+
+		for (i = 0; i < n; i++) {
+			f[i].start = get_unaligned(data++);
+			f[i].end   = get_unaligned(data++);
+
+			BT_DBG("proto filter start %d end %d",
+				f[i].start, f[i].end);
+		}
+		if (i < BNEP_MAX_PROTO_FILTERS)
+			memset(f + i, 0, sizeof(*f));
+
+		bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
+	} else {
+		bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
+	}
+#else
+	bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
+#endif
+	return 0;
+}
+
+static int bnep_ctrl_set_mcfilter(struct bnep_session *s, struct sk_buff *skb)
+{
+	u8 *data;
+	int n;
+	
+	data = (void *) skb->data;
+	if (!skb_pull(skb, 2))
+		return -EILSEQ;
+	n = ntohs(get_unaligned((u16 *) data));
+
+	data = (void *) skb->data;
+	if (!skb_pull(skb, n))
+		return -EILSEQ;
+
+	BT_DBG("filter len %d", n);
+
+#ifdef CONFIG_BNEP_MC_FILTER
+	n /= (ETH_ALEN * 2);
+
+	if (n > 0) {
+		s->mc_filter = 0;
+
+		/* Always send broadcast */
+		set_bit(bnep_mc_hash(s->dev.broadcast), &s->mc_filter);
+
+		/* Add address ranges to the multicast hash */
+		for (; n > 0; n--) {
+			u8 a1[6], *a2;
+
+			memcpy(a1, data, ETH_ALEN); data += ETH_ALEN;
+			a2 = data; data += ETH_ALEN;
+	
+			BT_DBG("mc filter %s -> %s",
+				batostr((void *) a1), batostr((void *) a2));
+
+			#define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); }
+
+			/* Iterate from a1 to a2 */
+			set_bit(bnep_mc_hash(a1), &s->mc_filter);
+			while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
+				INCA(a1);
+				set_bit(bnep_mc_hash(a1), &s->mc_filter);
+			}
+		}
+	}
+
+	BT_DBG("mc filter hash 0x%llx", s->mc_filter);
+
+	bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
+#else
+	bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
+#endif
+	return 0;
+}
+
+static int bnep_rx_control(struct bnep_session *s, struct sk_buff *skb)
+{
+	int err = 0;
+	__u8 cmd = *(__u8 *) skb->data;
+	skb_pull(skb, 1);
+	
+	switch (cmd) {
+	case BNEP_CMD_NOT_UNDERSTOOD:
+	case BNEP_SETUP_CONN_REQ:
+	case BNEP_SETUP_CONN_RSP:
+	case BNEP_FILTER_NET_TYPE_RSP:
+	case BNEP_FILTER_MULTI_ADDR_RSP:
+		/* Ignore these for now */
+		break;
+		
+	case BNEP_FILTER_NET_TYPE_SET:
+		err = bnep_ctrl_set_netfilter(s, skb);
+		break;
+
+	case BNEP_FILTER_MULTI_ADDR_SET:
+		err = bnep_ctrl_set_mcfilter(s, skb);
+		break;
+
+	default: {
+			__u8 pkt[3];
+			pkt[0] = BNEP_CONTROL;
+			pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
+			pkt[2] = cmd;
+			bnep_send(s, pkt, sizeof(pkt));
+		}
+		break;
+	}
+
+	return err;
+}
+
+static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
+{
+	struct bnep_ext_hdr *h;
+	int err = 0;
+
+	do {
+		h = (void *) skb->data;
+		if (!skb_pull(skb, sizeof(*h))) {
+			err = -EILSEQ;
+			break;
+		}
+
+		BT_DBG("type 0x%x len %d", h->type, h->len);
+		
+		switch (h->type & BNEP_TYPE_MASK) {
+		case BNEP_EXT_CONTROL:
+			err = bnep_rx_control(s, skb);
+			break;
+
+		default:
+			/* Unknown extension */
+			if (!skb_pull(skb, h->len))
+				err = -EILSEQ;
+			break;
+		}
+	} while (!err && (h->type & BNEP_EXT_HEADER));
+	
+	return err;
+}
+
+static __u8 __bnep_rx_hlen[] = {
+	ETH_HLEN,     /* BNEP_GENERAL */
+	0,            /* BNEP_CONTROL */
+	2,            /* BNEP_COMPRESSED */
+	ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
+	ETH_ALEN + 2  /* BNEP_COMPRESSED_DST_ONLY */
+};
+#define BNEP_RX_TYPES	(sizeof(__bnep_rx_hlen) - 1)
+
+static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
+{
+	struct net_device *dev = &s->dev;
+	struct sk_buff *nskb;
+	__u8 type;
+
+	dev->last_rx = jiffies;
+	s->stats.rx_bytes += skb->len;
+
+	type = *(__u8 *) skb->data; skb_pull(skb, 1);
+
+	if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES)
+		goto badframe;
+	
+	if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
+		bnep_rx_control(s, skb);
+		kfree_skb(skb);
+		return 0;
+	}
+
+	skb->mac.raw = skb->data;
+
+	/* Verify and pull out header */
+	if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
+		goto badframe;
+
+	s->eh.h_proto = get_unaligned((__u16 *) (skb->data - 2));
+
+	if (type & BNEP_EXT_HEADER) {
+		if (bnep_rx_extension(s, skb) < 0)
+			goto badframe;
+	}
+
+	/* Strip 802.1p header */
+	if (ntohs(s->eh.h_proto) == 0x8100) {
+		if (!skb_pull(skb, 4))
+			goto badframe;
+		s->eh.h_proto = get_unaligned((__u16 *) (skb->data - 2));
+	}
+	
+	/* We have to alloc new skb and copy data here :(. Because original skb
+	 * may not be modified and because of the alignment requirements. */
+	nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
+	if (!nskb) {
+		s->stats.rx_dropped++;
+		kfree_skb(skb);
+		return -ENOMEM;
+	}
+	skb_reserve(nskb, 2);
+
+	/* Decompress header and construct ether frame */
+	switch (type & BNEP_TYPE_MASK) {
+	case BNEP_COMPRESSED:
+		memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
+		break;
+	
+	case BNEP_COMPRESSED_SRC_ONLY:
+		memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
+		memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
+		put_unaligned(s->eh.h_proto, (__u16 *) __skb_put(nskb, 2));
+		break;
+
+	case BNEP_COMPRESSED_DST_ONLY:
+		memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
+		memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source, ETH_ALEN + 2);
+		break;
+
+	case BNEP_GENERAL:
+		memcpy(__skb_put(nskb, ETH_ALEN * 2), skb->mac.raw, ETH_ALEN * 2);
+		put_unaligned(s->eh.h_proto, (__u16 *) __skb_put(nskb, 2));
+		break;
+	}
+
+	memcpy(__skb_put(nskb, skb->len), skb->data, skb->len);
+	kfree_skb(skb);
+	
+	s->stats.rx_packets++;
+	nskb->dev       = dev;
+	nskb->ip_summed = CHECKSUM_UNNECESSARY;
+	nskb->protocol  = eth_type_trans(nskb, dev);
+	netif_rx_ni(nskb);
+	return 0;
+
+badframe:
+	s->stats.rx_errors++;
+	kfree_skb(skb);
+	return 0;
+}
+
+static __u8 __bnep_tx_types[] = {
+	BNEP_GENERAL,
+	BNEP_COMPRESSED_SRC_ONLY,
+	BNEP_COMPRESSED_DST_ONLY,
+	BNEP_COMPRESSED
+};
+
+static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
+{
+	struct ethhdr *eh = (void *) skb->data;
+	struct socket *sock = s->sock;
+	struct iovec iv[3];
+	int len = 0, il = 0;
+	__u8 type = 0;
+
+	BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
+
+	if (!skb->dev) {
+		/* Control frame sent by us */
+		goto send;
+	}
+
+	iv[il++] = (struct iovec) { &type, 1 };
+	len++;
+
+	if (!memcmp(eh->h_dest, s->eh.h_source, ETH_ALEN))
+		type |= 0x01;
+
+	if (!memcmp(eh->h_source, s->eh.h_dest, ETH_ALEN))
+		type |= 0x02;
+
+	if (type)
+		skb_pull(skb, ETH_ALEN * 2);
+
+	type = __bnep_tx_types[type];
+	switch (type) {
+	case BNEP_COMPRESSED_SRC_ONLY:
+		iv[il++] = (struct iovec) { eh->h_source, ETH_ALEN };
+		len += ETH_ALEN;
+		break;
+		
+	case BNEP_COMPRESSED_DST_ONLY:
+		iv[il++] = (struct iovec) { eh->h_dest, ETH_ALEN };
+		len += ETH_ALEN;
+		break;
+	}
+
+send:
+	iv[il++] = (struct iovec) { skb->data, skb->len };
+	len += skb->len;
+	
+	/* FIXME: linearize skb */
+	
+	s->msg.msg_iov    = iv;
+	s->msg.msg_iovlen = il;
+	len = sock->ops->sendmsg(sock, &s->msg, len, NULL);
+	kfree_skb(skb);
+
+	if (len > 0) {
+		s->stats.tx_bytes += len;
+		s->stats.tx_packets++;
+		return 0;
+	}
+
+	return len;
+}
+
+static int bnep_session(void *arg)
+{
+	struct bnep_session *s = arg;
+	struct net_device *dev = &s->dev;
+	struct sock *sk = s->sock->sk;
+	struct sk_buff *skb;
+	wait_queue_t wait;
+
+	BT_DBG("");
+
+        daemonize(); reparent_to_init();
+
+        sprintf(current->comm, "kbnepd %s", dev->name);
+	
+        sigfillset(&current->blocked);
+	flush_signals(current);
+
+	current->nice = -15;
+
+        set_fs(KERNEL_DS);
+
+	init_waitqueue_entry(&wait, current);
+	add_wait_queue(sk->sleep, &wait);
+	while (!atomic_read(&s->killed)) {
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		// RX
+		while ((skb = skb_dequeue(&sk->receive_queue))) {
+			skb_orphan(skb);
+			bnep_rx_frame(s, skb);
+		}
+
+		if (sk->state != BT_CONNECTED)
+			break;
+	
+		// TX
+		while ((skb = skb_dequeue(&sk->write_queue)))
+			if (bnep_tx_frame(s, skb))
+				break;
+		netif_wake_queue(dev);
+	
+		schedule();
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+
+	/* Cleanup session */
+	down_write(&bnep_session_sem);
+
+	/* Delete network device */
+	unregister_netdev(dev);
+
+	/* Release the socket */
+	fput(s->sock->file);
+
+	__bnep_unlink_session(s);
+
+	up_write(&bnep_session_sem);
+	kfree(s);
+	return 0;
+}
+
+int bnep_add_connection(struct bnep_conadd_req *req, struct socket *sock)
+{
+	struct net_device *dev;
+	struct bnep_session *s, *ss;
+	__u8 dst[ETH_ALEN], src[ETH_ALEN];
+	int err;
+
+	BT_DBG("");
+
+	baswap((void *) dst, &bluez_pi(sock->sk)->dst);
+	baswap((void *) src, &bluez_pi(sock->sk)->src);
+
+	s = kmalloc(sizeof(struct bnep_session), GFP_KERNEL);
+	if (!s) 
+		return -ENOMEM;
+	memset(s, 0, sizeof(struct bnep_session));
+
+	down_write(&bnep_session_sem);
+
+	ss = __bnep_get_session(dst);
+	if (ss && ss->state == BT_CONNECTED) {
+		err = -EEXIST;
+		goto failed;
+	}
+
+	dev = &s->dev;
+	
+	if (*req->device)
+		strcpy(dev->name, req->device);
+	else
+		strcpy(dev->name, "bnep%d");
+
+	/* This is rx header therefor addresses are swaped.
+	 * ie eh.h_dest is our local address. */
+	memcpy(s->eh.h_dest,   &src, ETH_ALEN);
+	memcpy(s->eh.h_source, &dst, ETH_ALEN);
+
+	s->sock  = sock;
+	s->role  = req->role;
+	s->state = BT_CONNECTED;
+	
+	s->msg.msg_flags = MSG_NOSIGNAL;
+
+#ifdef CONFIG_BNEP_MC_FILTER
+	/* Set default mc filter */
+	set_bit(bnep_mc_hash(dev->broadcast), &s->mc_filter);
+#endif
+	
+#ifdef CONFIG_BNEP_PROTO_FILTER
+	/* Set default protocol filter */
+
+	/* (IPv4, ARP)  */
+	s->proto_filter[0].start = htons(0x0800);
+	s->proto_filter[0].end   = htons(0x0806);
+	/* (RARP, AppleTalk) */
+	s->proto_filter[1].start = htons(0x8035);
+	s->proto_filter[1].end   = htons(0x80F3);
+	/* (IPX, IPv6) */
+	s->proto_filter[2].start = htons(0x8137);
+	s->proto_filter[2].end   = htons(0x86DD);
+#endif
+	
+	dev->init = bnep_net_init;
+	dev->priv = s;
+	err = register_netdev(dev);
+	if (err) {
+		goto failed;
+	}
+
+	__bnep_link_session(s);
+	
+	err = kernel_thread(bnep_session, s, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	if (err < 0) {
+		/* Session thread start failed, gotta cleanup. */
+		unregister_netdev(dev);
+		__bnep_unlink_session(s);
+		goto failed;
+	}
+
+	up_write(&bnep_session_sem);
+	strcpy(req->device, dev->name);
+	return 0;
+
+failed:
+	up_write(&bnep_session_sem);
+	kfree(s);
+	return err;
+}
+
+int bnep_del_connection(struct bnep_condel_req *req)
+{
+	struct bnep_session *s;
+	int  err = 0;
+
+	BT_DBG("");
+
+	down_read(&bnep_session_sem);
+
+	s = __bnep_get_session(req->dst);
+	if (s) {
+		/* Wakeup user-space which is polling for socket errors.
+		 * This is temporary hack untill we have shutdown in L2CAP */
+		s->sock->sk->err = EUNATCH;
+		
+		/* Kill session thread */
+		atomic_inc(&s->killed);
+		wake_up_interruptible(s->sock->sk->sleep);
+	} else
+		err = -ENOENT;
+
+	up_read(&bnep_session_sem);
+	return err;
+}
+
+static void __bnep_copy_ci(struct bnep_coninfo *ci, struct bnep_session *s)
+{
+	memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
+	strcpy(ci->device, s->dev.name);
+	ci->flags = s->flags;
+	ci->state = s->state;
+	ci->role  = s->role;
+}
+
+int bnep_get_conlist(struct bnep_conlist_req *req)
+{
+	struct list_head *p;
+	int err = 0, n = 0;
+
+	down_read(&bnep_session_sem);
+
+	list_for_each(p, &bnep_session_list) {
+		struct bnep_session *s;
+		struct bnep_coninfo ci;
+
+		s = list_entry(p, struct bnep_session, list);
+
+		__bnep_copy_ci(&ci, s);
+		
+		if (copy_to_user(req->ci, &ci, sizeof(ci))) {
+			err = -EFAULT;
+			break;
+		}
+
+		if (++n >= req->cnum)
+			break;
+
+		req->ci++;
+	}
+	req->cnum = n;
+
+	up_read(&bnep_session_sem);
+	return err;
+}
+
+int bnep_get_coninfo(struct bnep_coninfo *ci)
+{
+	struct bnep_session *s;
+	int err = 0;
+
+	down_read(&bnep_session_sem);
+
+	s = __bnep_get_session(ci->dst);
+	if (s)
+		__bnep_copy_ci(ci, s);
+	else
+		err = -ENOENT;
+
+	up_read(&bnep_session_sem);
+	return err;
+}
+
+static int __init bnep_init_module(void)
+{
+	BT_INFO("BNEP: BNEP2 ver %s\n"
+		"BNEP: Copyright (C) 2002 Inventel\n"
+		"BNEP: Written 2001,2002 by\n"
+		"BNEP: \tClement Moreau <clement.moreau@inventel.fr> "
+			"David Libault <david.libault@inventel.fr>\n"
+		"BNEP: Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>",
+			VERSION);
+
+	bnep_sock_init();
+
+	bnep_crc32_init();
+
+	return 0;
+}
+
+static void __exit bnep_cleanup_module(void)
+{
+	bnep_sock_cleanup();
+
+	bnep_crc32_cleanup();
+}
+
+module_init(bnep_init_module);
+module_exit(bnep_cleanup_module);
+
+MODULE_DESCRIPTION("BNEP2 ver " VERSION);
+MODULE_AUTHOR("David Libault <david.libault@inventel.fr> Maxim Krasnyanskiy <maxk@qualcomm.com>");
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/bnep/crc32.c linux-2.4.20/net/bluetooth/bnep/crc32.c
--- linux-2.4.19/net/bluetooth/bnep/crc32.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/bluetooth/bnep/crc32.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,59 @@
+/* 
+ * Based on linux-2.5/lib/crc32 by Matt Domsch <Matt_Domsch@dell.com>
+ *
+ * FIXME: Remove in 2.5  
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/atomic.h>
+
+#include "crc32.h"
+
+#define CRCPOLY_BE 0x04c11db7
+#define CRC_BE_BITS 8
+
+static u32 *bnep_crc32_table;
+
+/*
+ * This code is in the public domain; copyright abandoned.
+ * Liability for non-performance of this code is limited to the amount
+ * you paid for it.  Since it is distributed for free, your refund will
+ * be very very small.  If it breaks, you get to keep both pieces.
+ */
+u32 bnep_crc32(u32 crc, unsigned char const *p, size_t len)
+{
+	while (len--)
+		crc = (crc << 8) ^ bnep_crc32_table[(crc >> 24) ^ *p++];
+	
+	return crc;
+}
+
+int __init bnep_crc32_init(void)
+{
+	unsigned i, j;
+	u32 crc = 0x80000000;
+
+	bnep_crc32_table = kmalloc((1 << CRC_BE_BITS) * sizeof(u32), GFP_KERNEL);
+	if (!bnep_crc32_table)
+		return -ENOMEM;
+
+	bnep_crc32_table[0] = 0;
+
+	for (i = 1; i < 1 << CRC_BE_BITS; i <<= 1) {
+		crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
+		for (j = 0; j < i; j++)
+			bnep_crc32_table[i + j] = crc ^ bnep_crc32_table[j];
+	}
+	return 0;
+}
+
+void __exit bnep_crc32_cleanup(void)
+{
+	if (bnep_crc32_table)
+		kfree(bnep_crc32_table);
+	bnep_crc32_table = NULL;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/bnep/crc32.h linux-2.4.20/net/bluetooth/bnep/crc32.h
--- linux-2.4.19/net/bluetooth/bnep/crc32.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/bluetooth/bnep/crc32.h	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,10 @@
+/*
+ * crc32.h
+ * See crc32.c for license and changes
+ *
+ * FIXME: Remove in 2.5
+ */
+
+int  bnep_crc32_init(void);
+void bnep_crc32_cleanup(void);
+u32  bnep_crc32(u32 crc, unsigned char const *p, size_t len);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/bnep/netdev.c linux-2.4.20/net/bluetooth/bnep/netdev.c
--- linux-2.4.19/net/bluetooth/bnep/netdev.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/bluetooth/bnep/netdev.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,250 @@
+/* 
+   BNEP implementation for Linux Bluetooth stack (BlueZ).
+   Copyright (C) 2001-2002 Inventel Systemes
+   Written 2001-2002 by
+	Clment Moreau <clement.moreau@inventel.fr>
+	David Libault  <david.libault@inventel.fr>
+
+   Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * $Id: netdev.c,v 1.7 2002/07/14 05:39:26 maxk Exp $
+ */ 
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/socket.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/wait.h>
+
+#include <asm/unaligned.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
+
+#include "bnep.h"
+
+#ifndef CONFIG_BNEP_DEBUG
+#undef  BT_DBG
+#define BT_DBG( A... )
+#endif
+
+#define BNEP_TX_QUEUE_LEN 20
+
+static int bnep_net_open(struct net_device *dev)
+{
+	netif_start_queue(dev);
+	return 0;
+}
+
+static int bnep_net_close(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	return 0;
+}
+
+static struct net_device_stats *bnep_net_get_stats(struct net_device *dev)
+{
+	struct bnep_session *s = dev->priv;
+	return &s->stats;
+}
+
+static void bnep_net_set_mc_list(struct net_device *dev)
+{
+#ifdef CONFIG_BNEP_MC_FILTER
+	struct bnep_session *s = dev->priv;
+	struct sock *sk = s->sock->sk;
+	struct bnep_set_filter_req *r;
+	struct sk_buff *skb;
+	int size;
+
+	BT_DBG("%s mc_count %d", dev->name, dev->mc_count);
+
+	size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2;
+	skb  = alloc_skb(size, GFP_ATOMIC);
+	if (!skb) {
+		BT_ERR("%s Multicast list allocation failed", dev->name);
+		return;
+	}
+
+	r = (void *) skb->data;
+	__skb_put(skb, sizeof(*r));
+
+	r->type = BNEP_CONTROL;
+	r->ctrl = BNEP_FILTER_MULTI_ADDR_SET;
+
+        if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
+		u8 start[ETH_ALEN] = { 0x01 };
+
+		/* Request all addresses */
+		memcpy(__skb_put(skb, ETH_ALEN), start, ETH_ALEN);
+		memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
+		r->len = htons(ETH_ALEN * 2);
+	} else {
+                struct dev_mc_list *dmi = dev->mc_list;
+		int i, len = skb->len;
+
+		if (dev->flags & IFF_BROADCAST) {
+			memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
+			memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
+		}	
+		
+		/* FIXME: We should group addresses here. */
+
+		for (i = 0; i < dev->mc_count && i < BNEP_MAX_MULTICAST_FILTERS; i++) {
+			memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
+			memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
+			dmi = dmi->next;
+		}
+		r->len = htons(skb->len - len);
+	}
+
+	skb_queue_tail(&sk->write_queue, skb);
+	wake_up_interruptible(sk->sleep);
+#endif
+}
+
+static int bnep_net_set_mac_addr(struct net_device *dev, void *arg)
+{
+	BT_DBG("%s", dev->name);
+	return 0;
+}
+
+static void bnep_net_timeout(struct net_device *dev)
+{
+	BT_DBG("net_timeout");
+	netif_wake_queue(dev);
+}
+
+static int bnep_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	return -EINVAL;
+}
+
+#ifdef CONFIG_BNEP_MC_FILTER
+static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
+{
+	struct ethhdr *eh = (void *) skb->data;
+
+	if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), &s->mc_filter))
+		return 1;
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_BNEP_PROTO_FILTER
+/* Determine ether protocol. Based on eth_type_trans. */
+static inline __u16 bnep_net_eth_proto(struct sk_buff *skb)
+{
+	struct ethhdr *eh = (void *) skb->data;
+	
+	if (ntohs(eh->h_proto) >= 1536)
+		return eh->h_proto;
+		
+	if (get_unaligned((__u16 *) skb->data) == 0xFFFF)
+		return htons(ETH_P_802_3);
+		
+	return htons(ETH_P_802_2);
+}
+
+static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
+{
+	__u16 proto = bnep_net_eth_proto(skb);
+	struct bnep_proto_filter *f = s->proto_filter;
+	int i;
+	
+	for (i = 0; i < BNEP_MAX_PROTO_FILTERS && f[i].end; i++) {
+		if (proto >= f[i].start && proto <= f[i].end)
+			return 0;
+	}
+
+	BT_DBG("BNEP: filtered skb %p, proto 0x%.4x", skb, proto);
+	return 1;
+}
+#endif
+
+static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct bnep_session *s = dev->priv;
+	struct sock *sk = s->sock->sk;
+
+	BT_DBG("skb %p, dev %p", skb, dev);
+
+#ifdef CONFIG_BNEP_MC_FILTER
+	if (bnep_net_mc_filter(skb, s)) {
+		kfree_skb(skb);
+		return 0;
+	}
+#endif
+	
+#ifdef CONFIG_BNEP_PROTO_FILTER
+	if (bnep_net_proto_filter(skb, s)) {
+		kfree_skb(skb);
+		return 0;
+	}
+#endif
+	
+	/*
+	 * We cannot send L2CAP packets from here as we are potentially in a bh.
+	 * So we have to queue them and wake up session thread which is sleeping
+	 * on the sk->sleep.
+	 */
+	dev->trans_start = jiffies;
+	skb_queue_tail(&sk->write_queue, skb);
+	wake_up_interruptible(sk->sleep);
+
+	if (skb_queue_len(&sk->write_queue) >= BNEP_TX_QUEUE_LEN) {
+		BT_DBG("tx queue is full");
+
+		/* Stop queuing.
+		 * Session thread will do netif_wake_queue() */
+		netif_stop_queue(dev);
+	}
+
+	return 0;
+}
+
+int bnep_net_init(struct net_device *dev)
+{
+	struct bnep_session *s = dev->priv;
+
+	memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
+	dev->addr_len = ETH_ALEN;
+
+	ether_setup(dev);
+
+	dev->open            = bnep_net_open;
+	dev->stop            = bnep_net_close;
+	dev->hard_start_xmit = bnep_net_xmit;
+	dev->get_stats       = bnep_net_get_stats;
+	dev->do_ioctl        = bnep_net_ioctl;
+	dev->set_mac_address = bnep_net_set_mac_addr;
+	dev->set_multicast_list = bnep_net_set_mc_list;
+
+	dev->watchdog_timeo  = HZ * 2;
+	dev->tx_timeout      = bnep_net_timeout;
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/bnep/sock.c linux-2.4.20/net/bluetooth/bnep/sock.c
--- linux-2.4.19/net/bluetooth/bnep/sock.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/bluetooth/bnep/sock.c	2002-10-29 11:18:32.000000000 +0000
@@ -0,0 +1,238 @@
+/* 
+   BNEP implementation for Linux Bluetooth stack (BlueZ).
+   Copyright (C) 2001-2002 Inventel Systemes
+   Written 2001-2002 by
+	David Libault  <david.libault@inventel.fr>
+
+   Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * $Id: sock.c,v 1.3 2002/07/10 22:59:52 maxk Exp $
+ */ 
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/ioctl.h>
+#include <linux/file.h>
+#include <net/sock.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include "bnep.h"
+
+#ifndef CONFIG_BNEP_DEBUG
+#undef  BT_DBG
+#define BT_DBG( A... )
+#endif
+
+static inline struct socket *socki_lookup(struct inode *inode)
+{
+	return &inode->u.socket_i;
+}
+
+static struct socket *sockfd_lookup(int fd, int *err)
+{
+	struct file *file;
+	struct inode *inode;
+	struct socket *sock;
+
+	if (!(file = fget(fd))) {
+		*err = -EBADF;
+		return NULL;
+	}
+
+	inode = file->f_dentry->d_inode;
+	if (!inode->i_sock || !(sock = socki_lookup(inode))) {
+		*err = -ENOTSOCK;
+		fput(file);
+		return NULL;
+	}
+
+	if (sock->file != file) {
+		printk(KERN_ERR "socki_lookup: socket file changed!\n");
+		sock->file = file;
+	}
+	return sock;
+}
+ 
+static int bnep_sock_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+
+	BT_DBG("sock %p sk %p", sock, sk);
+
+	if (!sk)
+		return 0;
+
+	sock_orphan(sk);
+	sock_put(sk);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	struct bnep_conlist_req cl;
+	struct bnep_conadd_req  ca;
+	struct bnep_condel_req  cd;
+	struct bnep_coninfo ci;
+	struct socket *nsock;
+	int err;
+
+	BT_DBG("cmd %x arg %lx", cmd, arg);
+
+	switch (cmd) {
+	case BNEPCONADD:
+		if (!capable(CAP_NET_ADMIN))
+			return -EACCES;
+
+		if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
+			return -EFAULT;
+	
+		nsock = sockfd_lookup(ca.sock, &err);
+		if (!nsock)
+			return err;
+
+		if (nsock->sk->state != BT_CONNECTED)
+			return -EBADFD;
+
+		err = bnep_add_connection(&ca, nsock);
+		if (!err) {
+    			if (copy_to_user((void *) arg, &ca, sizeof(ca)))
+				err = -EFAULT;
+		} else
+			fput(nsock->file);
+
+		return err;
+	
+	case BNEPCONDEL:
+		if (!capable(CAP_NET_ADMIN))
+			return -EACCES;
+
+		if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
+			return -EFAULT;
+	
+		return bnep_del_connection(&cd);
+
+	case BNEPGETCONLIST:
+		if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
+			return -EFAULT;
+
+		if (cl.cnum <= 0)
+			return -EINVAL;
+	
+		err = bnep_get_conlist(&cl);
+		if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
+			return -EFAULT;
+
+		return err;
+
+	case BNEPGETCONINFO:
+		if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
+			return -EFAULT;
+
+		err = bnep_get_coninfo(&ci);
+		if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
+			return -EFAULT;
+
+		return err;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct proto_ops bnep_sock_ops = {
+	family:     PF_BLUETOOTH,
+	release:    bnep_sock_release,
+	ioctl:      bnep_sock_ioctl,
+	bind:       sock_no_bind,
+	getname:    sock_no_getname,
+	sendmsg:    sock_no_sendmsg,
+	recvmsg:    sock_no_recvmsg,
+	poll:       sock_no_poll,
+	listen:     sock_no_listen,
+	shutdown:   sock_no_shutdown,
+	setsockopt: sock_no_setsockopt,
+	getsockopt: sock_no_getsockopt,
+	connect:    sock_no_connect,
+	socketpair: sock_no_socketpair,
+	accept:     sock_no_accept,
+	mmap:       sock_no_mmap
+};
+
+static int bnep_sock_create(struct socket *sock, int protocol)
+{
+	struct sock *sk;
+
+	BT_DBG("sock %p", sock);
+
+	if (sock->type != SOCK_RAW)
+		return -ESOCKTNOSUPPORT;
+
+	sock->ops = &bnep_sock_ops;
+
+	if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1)))
+		return -ENOMEM;
+
+	MOD_INC_USE_COUNT;
+
+	sock->state = SS_UNCONNECTED;
+	sock_init_data(sock, sk);
+
+	sk->destruct = NULL;
+	sk->protocol = protocol;
+
+	return 0;
+}
+
+static struct net_proto_family bnep_sock_family_ops = {
+	family: PF_BLUETOOTH,
+	create: bnep_sock_create
+};
+
+int bnep_sock_init(void)
+{
+	bluez_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
+	return 0;
+}
+
+int bnep_sock_cleanup(void)
+{
+	if (bluez_sock_unregister(BTPROTO_BNEP))
+		BT_ERR("Can't unregister BNEP socket");
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/hci_conn.c linux-2.4.20/net/bluetooth/hci_conn.c
--- linux-2.4.19/net/bluetooth/hci_conn.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/bluetooth/hci_conn.c	2002-10-29 11:18:40.000000000 +0000
@@ -25,7 +25,7 @@
 /*
  * HCI Connection handling.
  *
- * $Id: hci_conn.c,v 1.3 2002/06/25 22:03:39 maxk Exp $
+ * $Id: hci_conn.c,v 1.5 2002/07/17 18:46:25 maxk Exp $
  */
 
 #include <linux/config.h>
@@ -73,7 +73,7 @@
 	bacpy(&cp.bdaddr, &conn->dst);
 
 	if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) &&
-			inquiry_entry_age(ie) > INQUIRY_ENTRY_AGE_MAX) {
+			inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
 		cp.pscan_rep_mode = ie->info.pscan_rep_mode;
 		cp.pscan_mode     = ie->info.pscan_mode;
 		cp.clock_offset   = ie->info.clock_offset | __cpu_to_le16(0x8000);
@@ -217,7 +217,7 @@
 
 	BT_DBG("%s -> %s", batostr(src), batostr(dst));
 
-	spin_lock_bh(&hdev_list_lock);
+	read_lock_bh(&hdev_list_lock);
 
 	list_for_each(p, &hdev_list) {
 		struct hci_dev *d;
@@ -245,7 +245,7 @@
 	if (hdev)
 		hci_dev_hold(hdev);
 
-	spin_unlock_bh(&hdev_list_lock);
+	read_unlock_bh(&hdev_list_lock);
 	return hdev;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/hci_core.c linux-2.4.20/net/bluetooth/hci_core.c
--- linux-2.4.19/net/bluetooth/hci_core.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/bluetooth/hci_core.c	2002-10-29 11:18:35.000000000 +0000
@@ -25,11 +25,12 @@
 /*
  * BlueZ HCI Core.
  *
- * $Id: hci_core.c,v 1.7 2002/06/25 22:03:39 maxk Exp $
+ * $Id: hci_core.c,v 1.14 2002/08/26 16:57:57 maxk Exp $
  */
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/kmod.h>
 
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -66,7 +67,7 @@
 
 /* HCI device list */
 LIST_HEAD(hdev_list);
-spinlock_t hdev_list_lock;
+rwlock_t hdev_list_lock = RW_LOCK_UNLOCKED;
 
 /* HCI protocols */
 #define HCI_MAX_PROTO	2
@@ -93,6 +94,32 @@
 	notifier_call_chain(&hci_notifier, event, hdev);
 }
 
+/* ---- HCI hotplug support ---- */
+
+#ifdef CONFIG_HOTPLUG
+
+static int hci_run_hotplug(char *dev, char *action)
+{
+	char *argv[3], *envp[5], dstr[20], astr[32];
+
+	sprintf(dstr, "DEVICE=%s", dev);
+	sprintf(astr, "ACTION=%s", action);
+
+        argv[0] = hotplug_path;
+        argv[1] = "bluetooth";
+        argv[2] = NULL;
+
+	envp[0] = "HOME=/";
+	envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+	envp[2] = dstr;
+	envp[3] = astr;
+	envp[4] = NULL;
+	
+	return call_usermodehelper(argv[0], argv, envp);
+}
+#else
+#define hci_run_hotplug(A...)
+#endif
 
 /* ---- HCI requests ---- */
 
@@ -270,7 +297,7 @@
 	if (index < 0)
 		return NULL;
 
-	spin_lock(&hdev_list_lock);
+	read_lock(&hdev_list_lock);
 	list_for_each(p, &hdev_list) {
 		hdev = list_entry(p, struct hci_dev, list);
 		if (hdev->id == index) {
@@ -280,7 +307,7 @@
 	}
 	hdev = NULL;
 done:
-	spin_unlock(&hdev_list_lock);
+	read_unlock(&hdev_list_lock);
 	return hdev;
 }
 
@@ -699,7 +726,7 @@
 		return -ENOMEM;
 	dr = dl->dev_req;
 
-	spin_lock_bh(&hdev_list_lock);
+	read_lock_bh(&hdev_list_lock);
 	list_for_each(p, &hdev_list) {
 		struct hci_dev *hdev;
 		hdev = list_entry(p, struct hci_dev, list);
@@ -708,7 +735,7 @@
 		if (++n >= dev_num)
 			break;
 	}
-	spin_unlock_bh(&hdev_list_lock);
+	read_unlock_bh(&hdev_list_lock);
 
 	dl->dev_num = n;
 	size = n * sizeof(struct hci_dev_req) + sizeof(__u16);
@@ -768,7 +795,7 @@
 	if (!hdev->open || !hdev->close || !hdev->destruct)
 		return -EINVAL;
 
-	spin_lock_bh(&hdev_list_lock);
+	write_lock_bh(&hdev_list_lock);
 
 	/* Find first available device id */
 	list_for_each(p, &hdev_list) {
@@ -806,12 +833,13 @@
 	memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
 
 	atomic_set(&hdev->promisc, 0);
-		
-	hci_notify(hdev, HCI_DEV_REG);
 
 	MOD_INC_USE_COUNT;
 
-	spin_unlock_bh(&hdev_list_lock);
+	write_unlock_bh(&hdev_list_lock);
+
+	hci_notify(hdev, HCI_DEV_REG);
+	hci_run_hotplug(hdev->name, "register");
 
 	return id;
 }
@@ -821,13 +849,15 @@
 {
 	BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
 
-	spin_lock_bh(&hdev_list_lock);
+	write_lock_bh(&hdev_list_lock);
 	list_del(&hdev->list);
-	spin_unlock_bh(&hdev_list_lock);
+	write_unlock_bh(&hdev_list_lock);
 
 	hci_dev_do_close(hdev);
 
 	hci_notify(hdev, HCI_DEV_UNREG);
+	hci_run_hotplug(hdev->name, "unregister");
+
 	hci_dev_put(hdev);
 
 	MOD_DEC_USE_COUNT;
@@ -1134,6 +1164,25 @@
 	return conn;
 }
 
+static inline void hci_acl_tx_to(struct hci_dev *hdev)
+{
+	struct conn_hash *h = &hdev->conn_hash;
+	struct list_head *p;
+	struct hci_conn  *c;
+
+	BT_ERR("%s ACL tx timeout", hdev->name);
+
+	/* Kill stalled connections */
+	list_for_each(p, &h->list) {
+		c = list_entry(p, struct hci_conn, list);
+		if (c->type == ACL_LINK && c->sent) {
+			BT_ERR("%s killing stalled ACL connection %s",
+				hdev->name, batostr(&c->dst));
+			hci_acl_disconn(c, 0x13);
+		}
+	}
+}
+
 static inline void hci_sched_acl(struct hci_dev *hdev)
 {
 	struct hci_conn *conn;
@@ -1144,10 +1193,8 @@
 
 	/* ACL tx timeout must be longer than maximum
 	 * link supervision timeout (40.9 seconds) */
-	if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > (HZ * 45)) {
-		BT_ERR("%s ACL tx timeout", hdev->name);
-		hdev->acl_cnt++;
-	}
+	if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > (HZ * 45))
+		hci_acl_tx_to(hdev);
 
 	while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
 		while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
@@ -1366,9 +1413,6 @@
 
 int hci_core_init(void)
 {
-	/* Init locks */
-	spin_lock_init(&hdev_list_lock);
-
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/hci_event.c linux-2.4.20/net/bluetooth/hci_event.c
--- linux-2.4.19/net/bluetooth/hci_event.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/bluetooth/hci_event.c	2002-10-29 11:18:49.000000000 +0000
@@ -25,7 +25,7 @@
 /*
  * HCI Events.
  *
- * $Id: hci_event.c,v 1.3 2002/04/17 17:37:16 maxk Exp $
+ * $Id: hci_event.c,v 1.4 2002/07/27 18:14:38 maxk Exp $
  */
 
 #include <linux/config.h>
@@ -352,16 +352,12 @@
 			hci_dev_lock(hdev);
 	
 			acl = conn_hash_lookup_handle(hdev, handle);
-			if (!acl || !(sco = acl->link)) {
-				hci_dev_unlock(hdev);
-				break;
+			if (acl && (sco = acl->link)) {
+				sco->state = BT_CLOSED;
+				hci_proto_connect_cfm(sco, status);
+				hci_conn_del(sco);
 			}
 
-			sco->state = BT_CLOSED;
-
-			hci_proto_connect_cfm(sco, status);
-			hci_conn_del(sco);
-
 			hci_dev_unlock(hdev);
 		}
 		break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/hci_sock.c linux-2.4.20/net/bluetooth/hci_sock.c
--- linux-2.4.19/net/bluetooth/hci_sock.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/bluetooth/hci_sock.c	2002-10-29 11:18:31.000000000 +0000
@@ -25,7 +25,7 @@
 /*
  * BlueZ HCI socket layer.
  *
- * $Id: hci_sock.c,v 1.4 2002/04/18 22:26:14 maxk Exp $
+ * $Id: hci_sock.c,v 1.5 2002/07/22 20:32:54 maxk Exp $
  */
 
 #include <linux/config.h>
@@ -129,7 +129,6 @@
 
 		if (sock_queue_rcv_skb(sk, nskb))
 			kfree_skb(nskb);
-		
 	}
 	read_unlock(&hci_sk_list.lock);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/l2cap.c linux-2.4.20/net/bluetooth/l2cap.c
--- linux-2.4.19/net/bluetooth/l2cap.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/bluetooth/l2cap.c	2002-10-29 11:18:39.000000000 +0000
@@ -25,9 +25,9 @@
 /*
  * BlueZ L2CAP core and sockets.
  *
- * $Id: l2cap.c,v 1.8 2002/04/19 00:01:39 maxk Exp $
+ * $Id: l2cap.c,v 1.15 2002/09/09 01:14:52 maxk Exp $
  */
-#define VERSION "2.0"
+#define VERSION "2.1"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -51,6 +51,7 @@
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -234,32 +235,26 @@
 }
 
 /* -------- Socket interface ---------- */
-static struct sock *__l2cap_get_sock_by_addr(struct sockaddr_l2 *addr)
+static struct sock *__l2cap_get_sock_by_addr(__u16 psm, bdaddr_t *src)
 {
-	bdaddr_t *src = &addr->l2_bdaddr;
-	__u16 psm = addr->l2_psm;
 	struct sock *sk;
-
 	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
 		if (l2cap_pi(sk)->psm == psm &&
-		    !bacmp(&bluez_pi(sk)->src, src))
+				!bacmp(&bluez_pi(sk)->src, src))
 			break;
 	}
-
 	return sk;
 }
 
-/* Find socket listening on psm and source bdaddr.
+/* Find socket with psm and source bdaddr.
  * Returns closest match.
  */
-static struct sock *l2cap_get_sock_listen(bdaddr_t *src, __u16 psm)
+static struct sock *__l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src)
 {
 	struct sock *sk, *sk1 = NULL;
 
-	read_lock(&l2cap_sk_list.lock);
-
 	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-		if (sk->state != BT_LISTEN)
+		if (state && sk->state != state)
 			continue;
 
 		if (l2cap_pi(sk)->psm == psm) {
@@ -272,9 +267,19 @@
 				sk1 = sk;
 		}
 	}
+	return sk ? sk : sk1;
+}
 
+/* Find socket with given address (psm, src).
+ * Returns locked socket */
+static inline struct sock *l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src)
+{
+	struct sock *s;
+	read_lock(&l2cap_sk_list.lock);
+	s = __l2cap_get_sock_by_psm(state, psm, src);
+	if (s) bh_lock_sock(s);
 	read_unlock(&l2cap_sk_list.lock);
-	return sk ? sk : sk1;
+	return s;
 }
 
 static void l2cap_sock_destruct(struct sock *sk)
@@ -330,6 +335,7 @@
 
 	case BT_CONNECTED:
 	case BT_CONFIG:
+	case BT_CONNECT2:
 		if (sk->type == SOCK_SEQPACKET) {
 			struct l2cap_conn *conn = l2cap_pi(sk)->conn;
 			l2cap_disconn_req req;
@@ -346,7 +352,6 @@
 		break;
 
 	case BT_CONNECT:
-	case BT_CONNECT2:
 	case BT_DISCONN:
 		l2cap_chan_del(sk, reason);
 		break;
@@ -377,7 +382,6 @@
 
 	if (parent) {
 		sk->type = parent->type;
-
 		pi->imtu = l2cap_pi(parent)->imtu;
 		pi->omtu = l2cap_pi(parent)->omtu;
 		pi->link_mode = l2cap_pi(parent)->link_mode;
@@ -425,7 +429,7 @@
 
 	sock->state = SS_UNCONNECTED;
 
-	if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_RAW)
+	if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
 		return -ESOCKTNOSUPPORT;
 
 	sock->ops = &l2cap_sock_ops;
@@ -455,20 +459,17 @@
 		goto done;
 	}
 
-	write_lock(&l2cap_sk_list.lock);
-
-	if (la->l2_psm && __l2cap_get_sock_by_addr(la)) {
+	write_lock_bh(&l2cap_sk_list.lock);
+	if (la->l2_psm && __l2cap_get_sock_by_addr(la->l2_psm, &la->l2_bdaddr)) {
 		err = -EADDRINUSE;
-		goto unlock;
+	} else {
+		/* Save source address */
+		bacpy(&bluez_pi(sk)->src, &la->l2_bdaddr);
+		l2cap_pi(sk)->psm = la->l2_psm;
+		sk->state = BT_BOUND;
 	}
 
-	/* Save source address */
-	bacpy(&bluez_pi(sk)->src, &la->l2_bdaddr);
-	l2cap_pi(sk)->psm = la->l2_psm;
-	sk->state = BT_BOUND;
-
-unlock:
-	write_unlock(&l2cap_sk_list.lock);
+	write_unlock_bh(&l2cap_sk_list.lock);
 
 done:
 	release_sock(sk);
@@ -631,7 +632,6 @@
 		bacpy(&la->l2_bdaddr, &bluez_pi(sk)->src);
 
 	la->l2_psm = l2cap_pi(sk)->psm;
-
 	return 0;
 }
 
@@ -648,6 +648,10 @@
 	if (msg->msg_flags & MSG_OOB)
 		return -EOPNOTSUPP;
 
+	/* Check outgoing MTU */
+	if (len > l2cap_pi(sk)->omtu)
+		return -EINVAL;
+
 	lock_sock(sk);
 
 	if (sk->state == BT_CONNECTED)
@@ -693,7 +697,7 @@
 	default:
 		err = -ENOPROTOOPT;
 		break;
-	};
+	}
 
 	release_sock(sk);
 	return err;
@@ -745,20 +749,37 @@
 	default:
 		err = -ENOPROTOOPT;
 		break;
-	};
+	}
 
 	release_sock(sk);
 	return err;
 }
 
+static int l2cap_sock_shutdown(struct socket *sock, int how)
+{
+	struct sock *sk = sock->sk;
+
+	BT_DBG("sock %p, sk %p", sock, sk);
+
+	if (!sk) return 0;
+
+	l2cap_sock_clear_timer(sk);
+
+	lock_sock(sk);
+	sk->shutdown = SHUTDOWN_MASK;
+	__l2cap_sock_close(sk, ECONNRESET);
+	release_sock(sk);
+
+	return 0;
+}
+
 static int l2cap_sock_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
 
 	BT_DBG("sock %p, sk %p", sock, sk);
 
-	if (!sk)
-		return 0;
+	if (!sk) return 0;
 
 	sock_orphan(sk);
 	l2cap_sock_close(sk);
@@ -769,24 +790,20 @@
 static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
 {
 	struct sock *s;
-
 	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
 		if (l2cap_pi(s)->dcid == cid)
 			break;
 	}
-
 	return s;
 }
 
 static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
 {
 	struct sock *s;
-
 	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
 		if (l2cap_pi(s)->scid == cid)
 			break;
 	}
-
 	return s;
 }
 
@@ -852,10 +869,15 @@
 	l2cap_pi(sk)->conn = conn;
 
 	if (sk->type == SOCK_SEQPACKET) {
-		/* Alloc CID for normal socket */
+		/* Alloc CID for connection-oriented socket */
 		l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
+	} else if (sk->type == SOCK_DGRAM) {
+		/* Connectionless socket */
+		l2cap_pi(sk)->scid = 0x0002;
+		l2cap_pi(sk)->dcid = 0x0002;
+		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
 	} else {
-		/* Raw socket can send only signalling messages */
+		/* Raw socket can send/recv signalling messages only */
 		l2cap_pi(sk)->scid = 0x0001;
 		l2cap_pi(sk)->dcid = 0x0001;
 		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
@@ -986,25 +1008,31 @@
 {
 	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
 	struct sk_buff *skb, **frag;
-	int err, size, count, sent=0;
+	int err, hlen, count, sent=0;
 	l2cap_hdr *lh;
 
-	/* Check outgoing MTU */
-	if (len > l2cap_pi(sk)->omtu)
-		return -EINVAL;
-
 	BT_DBG("sk %p len %d", sk, len);
 
 	/* First fragment (with L2CAP header) */
-	count = MIN(conn->mtu - L2CAP_HDR_SIZE, len);
-	size  = L2CAP_HDR_SIZE + count;
-	if (!(skb = bluez_skb_send_alloc(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)))
+	if (sk->type == SOCK_DGRAM)
+		hlen = L2CAP_HDR_SIZE + 2;
+	else
+		hlen = L2CAP_HDR_SIZE;
+
+	count = MIN(conn->mtu - hlen, len);
+
+	skb = bluez_skb_send_alloc(sk, hlen + count,
+			msg->msg_flags & MSG_DONTWAIT, &err);
+	if (!skb)
 		return err;
 
 	/* Create L2CAP header */
 	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-	lh->len = __cpu_to_le16(len);
 	lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+	lh->len = __cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
+
+	if (sk->type == SOCK_DGRAM)
+		put_unaligned(l2cap_pi(sk)->psm, (__u16 *) skb_put(skb, 2));
 
 	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
 		err = -EFAULT;
@@ -1317,37 +1345,41 @@
 	BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
 
 	/* Check if we have socket listening on psm */
-	if (!(parent = l2cap_get_sock_listen(conn->src, psm))) {
+	parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src);
+	if (!parent) {
 		result = L2CAP_CR_BAD_PSM;
-		goto resp;
+		goto sendresp;
 	}
 
-	write_lock(&list->lock);
-	bh_lock_sock(parent);
-
 	result = L2CAP_CR_NO_MEM;
 
-	/* Check if we already have channel with that dcid */
-	if (__l2cap_get_chan_by_dcid(list, scid))
-		goto unlock;
-
 	/* Check for backlog size */
 	if (parent->ack_backlog > parent->max_ack_backlog) {
 		BT_DBG("backlog full %d", parent->ack_backlog); 
-		goto unlock;
+		goto response;
 	}
 
-	if (!(sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC)))
-		goto unlock;
+	sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC);
+	if (!sk)
+		goto response;
 
-	l2cap_sock_init(sk, parent);
+	write_lock(&list->lock);
 
+	/* Check if we already have channel with that dcid */
+	if (__l2cap_get_chan_by_dcid(list, scid)) {
+		write_unlock(&list->lock);
+		sk->zapped = 1;
+		l2cap_sock_kill(sk);
+		goto response;
+	}
+
+	hci_conn_hold(conn->hcon);
+
+	l2cap_sock_init(sk, parent);
 	bacpy(&bluez_pi(sk)->src, conn->src);
 	bacpy(&bluez_pi(sk)->dst, conn->dst);
 	l2cap_pi(sk)->psm  = psm;
 	l2cap_pi(sk)->dcid = scid;
-	
-	hci_conn_hold(conn->hcon);
 
 	__l2cap_chan_add(conn, sk, parent);
 	dcid = l2cap_pi(sk)->scid;
@@ -1362,20 +1394,22 @@
 	
 	if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) {
 		if (!hci_conn_encrypt(conn->hcon))
-			goto unlock;
+			goto done;
 	} else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) {
 		if (!hci_conn_auth(conn->hcon))
-			goto unlock;
+			goto done;
 	}
 
 	sk->state = BT_CONFIG;
 	result = status = 0;
 
-unlock:
-	bh_unlock_sock(parent);
+done:
 	write_unlock(&list->lock);
 
-resp:
+response:
+	bh_unlock_sock(parent);
+
+sendresp:
 	rsp.scid   = __cpu_to_le16(scid);
 	rsp.dcid   = __cpu_to_le16(dcid);
 	rsp.result = __cpu_to_le16(result);
@@ -1680,10 +1714,37 @@
 	return 0;
 }
 
+static inline int l2cap_conless_channel(struct l2cap_conn *conn, __u16 psm, struct sk_buff *skb)
+{
+	struct sock *sk;
+
+	sk = l2cap_get_sock_by_psm(0, psm, conn->src);
+	if (!sk)
+		goto drop;
+
+	BT_DBG("sk %p, len %d", sk, skb->len);
+
+	if (sk->state != BT_BOUND && sk->state != BT_CONNECTED)
+		goto drop;
+
+	if (l2cap_pi(sk)->imtu < skb->len)
+		goto drop;
+
+	if (!sock_queue_rcv_skb(sk, skb))
+		goto done;
+
+drop:
+	kfree_skb(skb);
+
+done:
+	if (sk) bh_unlock_sock(sk);
+	return 0;
+}
+
 static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	l2cap_hdr *lh = (l2cap_hdr *) skb->data;
-	__u16 cid, len;
+	__u16 cid, psm, len;
 
 	skb_pull(skb, L2CAP_HDR_SIZE);
 	cid = __le16_to_cpu(lh->cid);
@@ -1691,10 +1752,21 @@
 
 	BT_DBG("len %d, cid 0x%4.4x", len, cid);
 
-	if (cid == 0x0001)
+	switch (cid) {
+	case 0x0001:
 		l2cap_sig_channel(conn, skb);
-	else	
+		break;
+
+	case 0x0002:
+		psm = get_unaligned((__u16 *) skb->data);
+		skb_pull(skb, 2);
+		l2cap_conless_channel(conn, psm, skb);
+		break;
+		
+	default:
 		l2cap_data_channel(conn, cid, skb);
+		break;
+	}
 }
 
 /* ------------ L2CAP interface with lower layer (HCI) ------------- */
@@ -1861,8 +1933,8 @@
 	BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
 
 	if (flags & ACL_START) {
-		int flen, tlen, size;
-		l2cap_hdr *lh;
+		l2cap_hdr *hdr;
+		int len;
 
 		if (conn->rx_len) {
 			BT_ERR("Unexpected start frame (len %d)", skb->len);
@@ -1871,30 +1943,28 @@
 			conn->rx_len = 0;
 		}
 
-		if (skb->len < L2CAP_HDR_SIZE) {
+		if (skb->len < 2) {
 			BT_ERR("Frame is too small (len %d)", skb->len);
 			goto drop;
 		}
 
-		lh = (l2cap_hdr *)skb->data;
-		tlen = __le16_to_cpu(lh->len);
-		flen = skb->len - L2CAP_HDR_SIZE;
+		hdr = (l2cap_hdr *) skb->data;
+		len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
 
-		BT_DBG("Start: total len %d, frag len %d", tlen, flen);
+		BT_DBG("Start: total len %d, frag len %d", len, skb->len);
 
-		if (flen == tlen) {
+		if (len == skb->len) {
 			/* Complete frame received */
 			l2cap_recv_frame(conn, skb);
 			return 0;
 		}
 
 		/* Allocate skb for the complete frame (with header) */
-		size = L2CAP_HDR_SIZE + tlen;
-		if (!(conn->rx_skb = bluez_skb_alloc(size, GFP_ATOMIC)))
+		if (!(conn->rx_skb = bluez_skb_alloc(len, GFP_ATOMIC)))
 			goto drop;
 
 		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
-		conn->rx_len = tlen - flen;
+		conn->rx_len = len - skb->len;
 	} else {
 		BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
 
@@ -1934,7 +2004,7 @@
 	struct sock *sk;
 	char *ptr = buf;
 
-	write_lock(&list->lock);
+	read_lock_bh(&list->lock);
 
 	for (sk = list->head; sk; sk = sk->next) {
 		pi = l2cap_pi(sk);
@@ -1944,7 +2014,7 @@
 				pi->link_mode);
 	}
 
-	write_unlock(&list->lock);
+	read_unlock_bh(&list->lock);
 
 	ptr += sprintf(ptr, "\n");
 	return ptr - buf;
@@ -1987,7 +2057,7 @@
 	poll:		bluez_sock_poll,
 	socketpair:	sock_no_socketpair,
 	ioctl:		sock_no_ioctl,
-	shutdown:	sock_no_shutdown,
+	shutdown:	l2cap_sock_shutdown,
 	setsockopt:	l2cap_sock_setsockopt,
 	getsockopt:	l2cap_sock_getsockopt,
 	mmap:		sock_no_mmap
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bluetooth/sco.c linux-2.4.20/net/bluetooth/sco.c
--- linux-2.4.19/net/bluetooth/sco.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/bluetooth/sco.c	2002-10-29 11:18:50.000000000 +0000
@@ -25,9 +25,9 @@
 /*
  * BlueZ SCO sockets.
  *
- * $Id: sco.c,v 1.3 2002/04/17 17:37:16 maxk Exp $
+ * $Id: sco.c,v 1.4 2002/07/22 20:32:54 maxk Exp $
  */
-#define VERSION "0.2"
+#define VERSION "0.3"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -464,19 +464,17 @@
 		goto done;
 	}
 
-	write_lock(&sco_sk_list.lock);
+	write_lock_bh(&sco_sk_list.lock);
 
 	if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) {
 		err = -EADDRINUSE;
-		goto unlock;
+	} else {
+		/* Save source address */
+		bacpy(&bluez_pi(sk)->src, &sa->sco_bdaddr);
+		sk->state = BT_BOUND;
 	}
 
-	/* Save source address */
-	bacpy(&bluez_pi(sk)->src, &sa->sco_bdaddr);
-	sk->state = BT_BOUND;
-
-unlock:
-	write_unlock(&sco_sk_list.lock);
+	write_unlock_bh(&sco_sk_list.lock);
 
 done:
 	release_sock(sk);
@@ -897,7 +895,7 @@
 	struct sock *sk;
 	char *ptr = buf;
 
-	write_lock(&list->lock);
+	write_lock_bh(&list->lock);
 
 	for (sk = list->head; sk; sk = sk->next) {
 		pi = sco_pi(sk);
@@ -906,7 +904,7 @@
 				sk->state); 
 	}
 
-	write_unlock(&list->lock);
+	write_unlock_bh(&list->lock);
 
 	ptr += sprintf(ptr, "\n");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bridge/br.c linux-2.4.20/net/bridge/br.c
--- linux-2.4.19/net/bridge/br.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.20/net/bridge/br.c	2002-10-29 11:18:33.000000000 +0000
@@ -21,6 +21,7 @@
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 #include <linux/if_bridge.h>
+#include <linux/brlock.h>
 #include <asm/uaccess.h>
 #include "br_private.h"
 
@@ -53,11 +54,6 @@
 	return 0;
 }
 
-static void __br_clear_frame_hook(void)
-{
-	br_handle_frame_hook = NULL;
-}
-
 static void __br_clear_ioctl_hook(void)
 {
 	br_ioctl_hook = NULL;
@@ -67,7 +63,11 @@
 {
 	unregister_netdevice_notifier(&br_device_notifier);
 	br_call_ioctl_atomic(__br_clear_ioctl_hook);
-	net_call_rx_atomic(__br_clear_frame_hook);
+
+	br_write_lock_bh(BR_NETPROTO_LOCK);
+	br_handle_frame_hook = NULL;
+	br_write_unlock_bh(BR_NETPROTO_LOCK);
+
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
 	br_fdb_get_hook = NULL;
 	br_fdb_put_hook = NULL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bridge/br_if.c linux-2.4.20/net/bridge/br_if.c
--- linux-2.4.19/net/bridge/br_if.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.20/net/bridge/br_if.c	2002-10-29 11:18:50.000000000 +0000
@@ -18,6 +18,7 @@
 #include <linux/if_bridge.h>
 #include <linux/inetdevice.h>
 #include <linux/rtnetlink.h>
+#include <linux/brlock.h>
 #include <asm/uaccess.h>
 #include "br_private.h"
 
@@ -37,7 +38,7 @@
 	return 100;
 }
 
-/* called under bridge lock */
+/* called under BR_NETPROTO_LOCK and bridge lock */
 static int __br_del_if(struct net_bridge *br, struct net_device *dev)
 {
 	struct net_bridge_port *p;
@@ -86,10 +87,12 @@
 
 static void del_ifs(struct net_bridge *br)
 {
-	write_lock_bh(&br->lock);
+	br_write_lock_bh(BR_NETPROTO_LOCK);
+	write_lock(&br->lock);
 	while (br->port_list != NULL)
 		__br_del_if(br, br->port_list->dev);
-	write_unlock_bh(&br->lock);
+	write_unlock(&br->lock);
+	br_write_unlock_bh(BR_NETPROTO_LOCK);
 }
 
 static struct net_bridge *new_nb(char *name)
@@ -252,10 +255,12 @@
 {
 	int retval;
 
-	write_lock_bh(&br->lock);
+	br_write_lock_bh(BR_NETPROTO_LOCK);
+	write_lock(&br->lock);
 	retval = __br_del_if(br, dev);
 	br_stp_recalculate_bridge_id(br);
-	write_unlock_bh(&br->lock);
+	write_unlock(&br->lock);
+	br_write_unlock_bh(BR_NETPROTO_LOCK);
 
 	return retval;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/bridge/br_stp.c linux-2.4.20/net/bridge/br_stp.c
--- linux-2.4.19/net/bridge/br_stp.c	2000-06-19 20:45:51.000000000 +0000
+++ linux-2.4.20/net/bridge/br_stp.c	2002-10-29 11:18:34.000000000 +0000
@@ -369,10 +369,19 @@
 static void br_make_forwarding(struct net_bridge_port *p)
 {
 	if (p->state == BR_STATE_BLOCKING) {
-		printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
-		       p->br->dev.name, p->port_no, p->dev->name, "listening");
+		if (p->br->stp_enabled) {
+			printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
+			       p->br->dev.name, p->port_no, p->dev->name,
+			       "listening");
+
+			p->state = BR_STATE_LISTENING;
+		} else {
+			printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
+			       p->br->dev.name, p->port_no, p->dev->name,
+			       "learning");
 
-		p->state = BR_STATE_LISTENING;
+			p->state = BR_STATE_LEARNING;
+		}
 		br_timer_set(&p->forward_delay_timer, jiffies);
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/core/dev.c linux-2.4.20/net/core/dev.c
--- linux-2.4.19/net/core/dev.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/core/dev.c	2002-10-29 11:18:48.000000000 +0000
@@ -14,7 +14,7 @@
  *	Additional Authors:
  *		Florian la Roche <rzsfl@rz.uni-sb.de>
  *		Alan Cox <gw4pts@gw4pts.ampr.org>
- *		David Hinds <dhinds@allegro.stanford.edu>
+ *		David Hinds <dahinds@users.sourceforge.net>
  *		Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
  *		Adam Sulmicki <adam@cfar.umd.edu>
  *              Pekka Riikonen <priikone@poesidon.pspt.fi>
@@ -700,10 +700,14 @@
 	 *	Call device private open method
 	 */
 	if (try_inc_mod_count(dev->owner)) {
+		set_bit(__LINK_STATE_START, &dev->state);
 		if (dev->open) {
 			ret = dev->open(dev);
-			if (ret != 0 && dev->owner)
-				__MOD_DEC_USE_COUNT(dev->owner);
+			if (ret != 0) {
+				clear_bit(__LINK_STATE_START, &dev->state);
+				if (dev->owner)
+					__MOD_DEC_USE_COUNT(dev->owner);
+			}
 		}
 	} else {
 		ret = -ENODEV;
@@ -720,8 +724,6 @@
 		 */
 		dev->flags |= IFF_UP;
 
-		set_bit(__LINK_STATE_START, &dev->state);
-
 		/*
 		 *	Initialize multicasting status 
 		 */
@@ -798,6 +800,19 @@
 
 	clear_bit(__LINK_STATE_START, &dev->state);
 
+	/* Synchronize to scheduled poll. We cannot touch poll list,
+	 * it can be even on different cpu. So just clear netif_running(),
+	 * and wait when poll really will happen. Actually, the best place
+	 * for this is inside dev->stop() after device stopped its irq
+	 * engine, but this requires more changes in devices. */
+
+	smp_mb__after_clear_bit(); /* Commit netif_running(). */
+	while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) {
+		/* No hurry. */
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
+	}
+
 	/*
 	 *	Call the device specific close. This cannot fail.
 	 *	Only if device is UP
@@ -899,7 +914,7 @@
 
 			if (skb2->nh.raw < skb2->data || skb2->nh.raw > skb2->tail) {
 				if (net_ratelimit())
-					printk(KERN_DEBUG "protocol %04x is buggy, dev %s\n", skb2->protocol, dev->name);
+					printk(KERN_CRIT "protocol %04x is buggy, dev %s\n", skb2->protocol, dev->name);
 				skb2->nh.raw = skb2->data;
 			}
 
@@ -1051,13 +1066,13 @@
 			dev->xmit_lock_owner = -1;
 			spin_unlock_bh(&dev->xmit_lock);
 			if (net_ratelimit())
-				printk(KERN_DEBUG "Virtual device %s asks to queue packet!\n", dev->name);
+				printk(KERN_CRIT "Virtual device %s asks to queue packet!\n", dev->name);
 			kfree_skb(skb);
 			return -ENETDOWN;
 		} else {
 			/* Recursion is detected! It is possible, unfortunately */
 			if (net_ratelimit())
-				printk(KERN_DEBUG "Dead loop on virtual device %s, fix it urgently!\n", dev->name);
+				printk(KERN_CRIT "Dead loop on virtual device %s, fix it urgently!\n", dev->name);
 		}
 	}
 	spin_unlock_bh(&dev->queue_lock);
@@ -1072,6 +1087,7 @@
   =======================================================================*/
 
 int netdev_max_backlog = 300;
+int weight_p = 64;            /* old backlog weight */
 /* These numbers are selected based on intuition and some
  * experimentatiom, if you have more scientific way of doing this
  * please go ahead and fix things.
@@ -1237,13 +1253,11 @@
 enqueue:
 			dev_hold(skb->dev);
 			__skb_queue_tail(&queue->input_pkt_queue,skb);
-			/* Runs from irqs or BH's, no need to wake BH */
-			cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);
 			local_irq_restore(flags);
 #ifndef OFFLINE_SAMPLE
 			get_sample_stats(this_cpu);
 #endif
-			return softnet_data[this_cpu].cng_level;
+			return queue->cng_level;
 		}
 
 		if (queue->throttle) {
@@ -1253,6 +1267,8 @@
 				netdev_wakeup();
 #endif
 		}
+
+		netif_rx_schedule(&queue->blog_dev);
 		goto enqueue;
 	}
 
@@ -1308,19 +1324,12 @@
 	return ret;
 }
 
-/* Reparent skb to master device. This function is called
- * only from net_rx_action under BR_NETPROTO_LOCK. It is misuse
- * of BR_NETPROTO_LOCK, but it is OK for now.
- */
 static __inline__ void skb_bond(struct sk_buff *skb)
 {
 	struct net_device *dev = skb->dev;
-	
-	if (dev->master) {
-		dev_hold(dev->master);
+
+	if (dev->master)
 		skb->dev = dev->master;
-		dev_put(dev);
-	}
 }
 
 static void net_tx_action(struct softirq_action *h)
@@ -1369,20 +1378,6 @@
 	}
 }
 
-/**
- *	net_call_rx_atomic
- *	@fn: function to call
- *
- *	Make a function call that is atomic with respect to the protocol
- *	layers.
- */
- 
-void net_call_rx_atomic(void (*fn)(void))
-{
-	br_write_lock_bh(BR_NETPROTO_LOCK);
-	fn();
-	br_write_unlock_bh(BR_NETPROTO_LOCK);
-}
 
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL;
@@ -1408,129 +1403,147 @@
 
 
 #ifdef CONFIG_NET_DIVERT
-static inline void handle_diverter(struct sk_buff *skb)
+static inline int handle_diverter(struct sk_buff *skb)
 {
 	/* if diversion is supported on device, then divert */
 	if (skb->dev->divert && skb->dev->divert->divert)
 		divert_frame(skb);
+	return 0;
 }
 #endif   /* CONFIG_NET_DIVERT */
 
-
-static void net_rx_action(struct softirq_action *h)
+int netif_receive_skb(struct sk_buff *skb)
 {
-	int this_cpu = smp_processor_id();
-	struct softnet_data *queue = &softnet_data[this_cpu];
-	unsigned long start_time = jiffies;
-	int bugdet = netdev_max_backlog;
-
-	br_read_lock(BR_NETPROTO_LOCK);
-
-	for (;;) {
-		struct sk_buff *skb;
-		struct net_device *rx_dev;
-
-		local_irq_disable();
-		skb = __skb_dequeue(&queue->input_pkt_queue);
-		local_irq_enable();
+	struct packet_type *ptype, *pt_prev;
+	int ret = NET_RX_DROP;
+	unsigned short type = skb->protocol;
 
-		if (skb == NULL)
-			break;
+	if (skb->stamp.tv_sec == 0)
+		do_gettimeofday(&skb->stamp);
 
-		skb_bond(skb);
+	skb_bond(skb);
 
-		rx_dev = skb->dev;
+	netdev_rx_stat[smp_processor_id()].total++;
 
 #ifdef CONFIG_NET_FASTROUTE
-		if (skb->pkt_type == PACKET_FASTROUTE) {
-			netdev_rx_stat[this_cpu].fastroute_deferred_out++;
-			dev_queue_xmit(skb);
-			dev_put(rx_dev);
-			continue;
-		}
+	if (skb->pkt_type == PACKET_FASTROUTE) {
+		netdev_rx_stat[smp_processor_id()].fastroute_deferred_out++;
+		return dev_queue_xmit(skb);
+	}
 #endif
-		skb->h.raw = skb->nh.raw = skb->data;
-		{
-			struct packet_type *ptype, *pt_prev;
-			unsigned short type = skb->protocol;
 
-			pt_prev = NULL;
-			for (ptype = ptype_all; ptype; ptype = ptype->next) {
-				if (!ptype->dev || ptype->dev == skb->dev) {
-					if (pt_prev) {
-						if (!pt_prev->data) {
-							deliver_to_old_ones(pt_prev, skb, 0);
-						} else {
-							atomic_inc(&skb->users);
-							pt_prev->func(skb,
-								      skb->dev,
-								      pt_prev);
-						}
-					}
-					pt_prev = ptype;
+	skb->h.raw = skb->nh.raw = skb->data;
+
+	pt_prev = NULL;
+	for (ptype = ptype_all; ptype; ptype = ptype->next) {
+		if (!ptype->dev || ptype->dev == skb->dev) {
+			if (pt_prev) {
+				if (!pt_prev->data) {
+					ret = deliver_to_old_ones(pt_prev, skb, 0);
+				} else {
+					atomic_inc(&skb->users);
+					ret = pt_prev->func(skb, skb->dev, pt_prev);
 				}
 			}
+			pt_prev = ptype;
+		}
+	}
 
 #ifdef CONFIG_NET_DIVERT
-			if (skb->dev->divert && skb->dev->divert->divert)
-				handle_diverter(skb);
+	if (skb->dev->divert && skb->dev->divert->divert)
+		ret = handle_diverter(skb);
 #endif /* CONFIG_NET_DIVERT */
-
 			
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-			if (skb->dev->br_port != NULL &&
-			    br_handle_frame_hook != NULL) {
-				handle_bridge(skb, pt_prev);
-				dev_put(rx_dev);
-				continue;
-			}
+	if (skb->dev->br_port != NULL &&
+	    br_handle_frame_hook != NULL) {
+		return handle_bridge(skb, pt_prev);
+	}
 #endif
 
-			for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) {
-				if (ptype->type == type &&
-				    (!ptype->dev || ptype->dev == skb->dev)) {
-					if (pt_prev) {
-						if (!pt_prev->data)
-							deliver_to_old_ones(pt_prev, skb, 0);
-						else {
-							atomic_inc(&skb->users);
-							pt_prev->func(skb,
-								      skb->dev,
-								      pt_prev);
-						}
-					}
-					pt_prev = ptype;
+	for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) {
+		if (ptype->type == type &&
+		    (!ptype->dev || ptype->dev == skb->dev)) {
+			if (pt_prev) {
+				if (!pt_prev->data) {
+					ret = deliver_to_old_ones(pt_prev, skb, 0);
+				} else {
+					atomic_inc(&skb->users);
+					ret = pt_prev->func(skb, skb->dev, pt_prev);
 				}
 			}
+			pt_prev = ptype;
+		}
+	}
 
-			if (pt_prev) {
-				if (!pt_prev->data)
-					deliver_to_old_ones(pt_prev, skb, 1);
-				else
-					pt_prev->func(skb, skb->dev, pt_prev);
-			} else
-				kfree_skb(skb);
+	if (pt_prev) {
+		if (!pt_prev->data) {
+			ret = deliver_to_old_ones(pt_prev, skb, 1);
+		} else {
+			ret = pt_prev->func(skb, skb->dev, pt_prev);
 		}
+	} else {
+		kfree_skb(skb);
+		/* Jamal, now you will not able to escape explaining
+		 * me how you were going to use this. :-)
+		 */
+		ret = NET_RX_DROP;
+	}
+
+	return ret;
+}
 
-		dev_put(rx_dev);
+static int process_backlog(struct net_device *blog_dev, int *budget)
+{
+	int work = 0;
+	int quota = min(blog_dev->quota, *budget);
+	int this_cpu = smp_processor_id();
+	struct softnet_data *queue = &softnet_data[this_cpu];
+	unsigned long start_time = jiffies;
 
-		if (bugdet-- < 0 || jiffies - start_time > 1)
-			goto softnet_break;
+	for (;;) {
+		struct sk_buff *skb;
+		struct net_device *dev;
+
+		local_irq_disable();
+		skb = __skb_dequeue(&queue->input_pkt_queue);
+		if (skb == NULL)
+			goto job_done;
+		local_irq_enable();
+
+		dev = skb->dev;
+
+		netif_receive_skb(skb);
+
+		dev_put(dev);
+
+		work++;
+
+		if (work >= quota || jiffies - start_time > 1)
+			break;
 
 #ifdef CONFIG_NET_HW_FLOWCONTROL
-	if (queue->throttle && queue->input_pkt_queue.qlen < no_cong_thresh ) {
-		if (atomic_dec_and_test(&netdev_dropping)) {
-			queue->throttle = 0;
-			netdev_wakeup();
-			goto softnet_break;
+		if (queue->throttle && queue->input_pkt_queue.qlen < no_cong_thresh ) {
+			if (atomic_dec_and_test(&netdev_dropping)) {
+				queue->throttle = 0;
+				netdev_wakeup();
+				break;
+			}
 		}
-	}
 #endif
-
 	}
-	br_read_unlock(BR_NETPROTO_LOCK);
 
-	local_irq_disable();
+	blog_dev->quota -= work;
+	*budget -= work;
+	return -1;
+
+job_done:
+	blog_dev->quota -= work;
+	*budget -= work;
+
+	list_del(&blog_dev->poll_list);
+	clear_bit(__LINK_STATE_RX_SCHED, &blog_dev->state);
+
 	if (queue->throttle) {
 		queue->throttle = 0;
 #ifdef CONFIG_NET_HW_FLOWCONTROL
@@ -1539,21 +1552,53 @@
 #endif
 	}
 	local_irq_enable();
+	return 0;
+}
 
-	NET_PROFILE_LEAVE(softnet_process);
-	return;
+static void net_rx_action(struct softirq_action *h)
+{
+	int this_cpu = smp_processor_id();
+	struct softnet_data *queue = &softnet_data[this_cpu];
+	unsigned long start_time = jiffies;
+	int budget = netdev_max_backlog;
 
-softnet_break:
+	br_read_lock(BR_NETPROTO_LOCK);
+	local_irq_disable();
+
+	while (!list_empty(&queue->poll_list)) {
+		struct net_device *dev;
+
+		if (budget <= 0 || jiffies - start_time > 1)
+			goto softnet_break;
+
+		local_irq_enable();
+
+		dev = list_entry(queue->poll_list.next, struct net_device, poll_list);
+
+		if (dev->quota <= 0 || dev->poll(dev, &budget)) {
+			local_irq_disable();
+			list_del(&dev->poll_list);
+			list_add_tail(&dev->poll_list, &queue->poll_list);
+			if (dev->quota < 0)
+				dev->quota += dev->weight;
+			else
+				dev->quota = dev->weight;
+		} else {
+			dev_put(dev);
+			local_irq_disable();
+		}
+	}
+
+	local_irq_enable();
 	br_read_unlock(BR_NETPROTO_LOCK);
+	return;
 
-	local_irq_disable();
+softnet_break:
 	netdev_rx_stat[this_cpu].time_squeeze++;
-	/* This already runs in BH context, no need to wake up BH's */
-	cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);
-	local_irq_enable();
+	__cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);
 
-	NET_PROFILE_LEAVE(softnet_process);
-	return;
+	local_irq_enable();
+	br_read_unlock(BR_NETPROTO_LOCK);
 }
 
 static gifconf_func_t * gifconf_list [NPROTO];
@@ -2607,6 +2652,7 @@
 
 extern void net_device_init(void);
 extern void ip_auto_config(void);
+struct proc_dir_entry *proc_net_drivers;
 #ifdef CONFIG_NET_DIVERT
 extern void dv_init(void);
 #endif /* CONFIG_NET_DIVERT */
@@ -2624,6 +2670,7 @@
 	if (!dev_boot_phase)
 		return 0;
 
+
 #ifdef CONFIG_NET_DIVERT
 	dv_init();
 #endif /* CONFIG_NET_DIVERT */
@@ -2641,8 +2688,13 @@
 		queue->cng_level = 0;
 		queue->avg_blog = 10; /* arbitrary non-zero */
 		queue->completion_queue = NULL;
+		INIT_LIST_HEAD(&queue->poll_list);
+		set_bit(__LINK_STATE_START, &queue->blog_dev.state);
+		queue->blog_dev.weight = weight_p;
+		queue->blog_dev.poll = process_backlog;
+		atomic_set(&queue->blog_dev.refcnt, 1);
 	}
-	
+
 #ifdef CONFIG_NET_PROFILE
 	net_profile_init();
 	NET_PROFILE_REGISTER(dev_queue_xmit);
@@ -2725,6 +2777,7 @@
 #ifdef CONFIG_PROC_FS
 	proc_net_create("dev", 0, dev_get_info);
 	create_proc_read_entry("net/softnet_stat", 0, 0, dev_proc_stats, NULL);
+	proc_net_drivers = proc_mkdir("net/drivers", 0);
 #ifdef WIRELESS_EXT
 	/* Available in net/core/wireless.c */
 	proc_net_create("wireless", 0, dev_get_wireless_info);
@@ -2742,7 +2795,6 @@
 #ifdef CONFIG_NET_SCHED
 	pktsched_init();
 #endif
-
 	/*
 	 *	Initialise network devices
 	 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/core/dst.c linux-2.4.20/net/core/dst.c
--- linux-2.4.19/net/core/dst.c	2000-11-29 05:53:45.000000000 +0000
+++ linux-2.4.20/net/core/dst.c	2002-10-29 11:18:48.000000000 +0000
@@ -5,8 +5,7 @@
  *
  */
 
-#include <asm/system.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -29,7 +28,9 @@
  * 4) All operations modify state, so a spinlock is used.
  */
 static struct dst_entry 	*dst_garbage_list;
+#if RT_CACHE_DEBUG >= 2 
 static atomic_t			 dst_total = ATOMIC_INIT(0);
+#endif
 static spinlock_t		 dst_lock = SPIN_LOCK_UNLOCKED;
 
 static unsigned long dst_gc_timer_expires;
@@ -108,7 +109,9 @@
 	dst->lastuse = jiffies;
 	dst->input = dst_discard;
 	dst->output = dst_blackhole;
+#if RT_CACHE_DEBUG >= 2 
 	atomic_inc(&dst_total);
+#endif
 	atomic_inc(&ops->entries);
 	return dst;
 }
@@ -158,7 +161,9 @@
 		dst->ops->destroy(dst);
 	if (dst->dev)
 		dev_put(dst->dev);
+#if RT_CACHE_DEBUG >= 2 
 	atomic_dec(&dst_total);
+#endif
 	kmem_cache_free(dst->ops->kmem_cachep, dst);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/core/pktgen.c linux-2.4.20/net/core/pktgen.c
--- linux-2.4.19/net/core/pktgen.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/core/pktgen.c	2002-10-29 11:18:33.000000000 +0000
@@ -1,4 +1,5 @@
-/* $Id: pktgen.c,v 1.1.2.1 2002/03/01 12:15:05 davem Exp $
+/* -*-linux-c-*-
+ * $Id: pktgen.c,v 1.8 2002/07/15 19:30:17 robert Exp $
  * pktgen.c: Packet Generator for performance evaluation.
  *
  * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se>
@@ -19,6 +20,31 @@
  * Integrated.  020301 --DaveM
  * Added multiskb option 020301 --DaveM
  * Scaling of results. 020417--sigurdur@linpro.no
+ * Significant re-work of the module:
+ *   *  Updated to support generation over multiple interfaces at once
+ *       by creating 32 /proc/net/pg* files.  Each file can be manipulated
+ *       individually.
+ *   *  Converted many counters to __u64 to allow longer runs.
+ *   *  Allow configuration of ranges, like min/max IP address, MACs,
+ *       and UDP-ports, for both source and destination, and can
+ *       set to use a random distribution or sequentially walk the range.
+ *   *  Can now change some values after starting.
+ *   *  Place 12-byte packet in UDP payload with magic number,
+ *       sequence number, and timestamp.  Will write receiver next.
+ *   *  The new changes seem to have a performance impact of around 1%,
+ *       as far as I can tell.
+ *   --Ben Greear <greearb@candelatech.com>
+ *
+ * Renamed multiskb to clone_skb and cleaned up sending core for two distinct 
+ * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0 
+ * as a "fastpath" with a configurable number of clones after alloc's.
+ *
+ * clone_skb=0 means all packets are allocated this also means ranges time 
+ * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100 
+ * clones.
+ *
+ * Also moved to /proc/net/pktgen/ 
+ * --ro 
  *
  * See Documentation/networking/pktgen.txt for how to use this.
  */
@@ -41,6 +67,7 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
+#include <asm/uaccess.h>
 
 #include <linux/in.h>
 #include <linux/ip.h>
@@ -56,73 +83,207 @@
 
 #define cycles()	((u32)get_cycles())
 
+
+#define VERSION "pktgen version 1.2"
 static char version[] __initdata = 
-  "pktgen.c: v1.1 020418: Packet Generator for packet performance testing.\n";
+  "pktgen.c: v1.2: Packet Generator for packet performance testing.\n";
+
+/* Used to help with determining the pkts on receive */
+
+#define PKTGEN_MAGIC 0xbe9be955
+
+
+/* Keep information per interface */
+struct pktgen_info {
+        /* Parameters */
+
+        /* If min != max, then we will either do a linear iteration, or
+         * we will do a random selection from within the range.
+         */
+        __u32 flags;     
+
+#define F_IPSRC_RND   (1<<0)  /* IP-Src Random  */
+#define F_IPDST_RND   (1<<1)  /* IP-Dst Random  */
+#define F_UDPSRC_RND  (1<<2)  /* UDP-Src Random */
+#define F_UDPDST_RND  (1<<3)  /* UDP-Dst Random */
+#define F_MACSRC_RND  (1<<4)  /* MAC-Src Random */
+#define F_MACDST_RND  (1<<5)  /* MAC-Dst Random */
+#define F_SET_SRCMAC  (1<<6)  /* Specify-Src-Mac 
+				 (default is to use Interface's MAC Addr) */
+#define F_SET_SRCIP   (1<<7)  /*  Specify-Src-IP
+				  (default is to use Interface's IP Addr) */ 
+
+        
+        int pkt_size;    /* = ETH_ZLEN; */
+        int nfrags;
+        __u32 ipg;       /* Default Interpacket gap in nsec */
+        __u64 count;     /* Default No packets to send */
+        __u64 sofar;     /* How many pkts we've sent so far */
+        __u64 errors;    /* Errors when trying to transmit, pkts will be re-sent */
+        struct timeval started_at;
+        struct timeval stopped_at;
+        __u64 idle_acc;
+        __u32 seq_num;
+        
+        int clone_skb;   /* Use multiple SKBs during packet gen.  If this number
+                          * is greater than 1, then that many coppies of the same
+                          * packet will be sent before a new packet is allocated.
+                          * For instance, if you want to send 1024 identical packets
+                          * before creating a new packet, set clone_skb to 1024.
+                          */
+        int busy;
+        int do_run_run;   /* if this changes to false, the test will stop */
+        
+        char outdev[32];
+        char dst_min[32];
+        char dst_max[32];
+        char src_min[32];
+        char src_max[32];
+
+        /* If we're doing ranges, random or incremental, then this
+         * defines the min/max for those ranges.
+         */
+        __u32 saddr_min; /* inclusive, source IP address */
+        __u32 saddr_max; /* exclusive, source IP address */
+        __u32 daddr_min; /* inclusive, dest IP address */
+        __u32 daddr_max; /* exclusive, dest IP address */
+
+        __u16 udp_src_min; /* inclusive, source UDP port */
+        __u16 udp_src_max; /* exclusive, source UDP port */
+        __u16 udp_dst_min; /* inclusive, dest UDP port */
+        __u16 udp_dst_max; /* exclusive, dest UDP port */
+
+        __u32 src_mac_count; /* How many MACs to iterate through */
+        __u32 dst_mac_count; /* How many MACs to iterate through */
+        
+        unsigned char dst_mac[6];
+        unsigned char src_mac[6];
+        
+        __u32 cur_dst_mac_offset;
+        __u32 cur_src_mac_offset;
+        __u32 cur_saddr;
+        __u32 cur_daddr;
+        __u16 cur_udp_dst;
+        __u16 cur_udp_src;
+        
+        __u8 hh[14];
+        /* = { 
+           0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, 
+           
+           We fill in SRC address later
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x08, 0x00
+           };
+        */
+        __u16 pad; /* pad out the hh struct to an even 16 bytes */
+        char result[512];
+
+        /* proc file names */
+        char fname[80];
+        char busy_fname[80];
+        
+        struct proc_dir_entry *proc_ent;
+        struct proc_dir_entry *busy_proc_ent;
+};
 
-/* Parameters */
-static char pg_outdev[32], pg_dst[32];
-static int pkt_size = ETH_ZLEN;
-static int nfrags = 0;
-static __u32 pg_count = 100000;  /* Default No packets to send */
-static __u32 pg_ipg = 0;  /* Default Interpacket gap in nsec */
-static int pg_multiskb = 0; /* Use multiple SKBs during packet gen. */
+struct pktgen_hdr {
+        __u32 pgh_magic;
+        __u32 seq_num;
+        struct timeval timestamp;
+};
 
+static int cpu_speed;
 static int debug;
-static int forced_stop;
-static int pg_cpu_speed;
-static int pg_busy;
 
-static __u8 hh[14] = { 
+/* Module parameters, defaults. */
+static int count_d = 100000;
+static int ipg_d = 0;
+static int clone_skb_d = 0;
 
-  /* Overrun by /proc config  */
 
-    0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, 
+#define MAX_PKTGEN 8
+static struct pktgen_info pginfos[MAX_PKTGEN];
 
-    /* We fill in SRC address later */
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x08, 0x00
-};
 
-static unsigned char *pg_dstmac = hh;
-static char pg_result[512];
+/** Convert to miliseconds */
+inline __u64 tv_to_ms(const struct timeval* tv) {
+        __u64 ms = tv->tv_usec / 1000;
+        ms += (__u64)tv->tv_sec * (__u64)1000;
+        return ms;
+}
+
+inline __u64 getCurMs(void) {
+        struct timeval tv;
+        do_gettimeofday(&tv);
+        return tv_to_ms(&tv);
+}
+
+#define PG_PROC_DIR "pktgen"
+static struct proc_dir_entry *proc_dir = 0;
 
-static struct net_device *pg_setup_inject(u32 *saddrp)
+static struct net_device *setup_inject(struct pktgen_info* info)
 {
 	struct net_device *odev;
-	int p1, p2;
-	u32 saddr;
 
 	rtnl_lock();
-	odev = __dev_get_by_name(pg_outdev);
+	odev = __dev_get_by_name(info->outdev);
 	if (!odev) {
-		sprintf(pg_result, "No such netdevice: \"%s\"", pg_outdev);
+		sprintf(info->result, "No such netdevice: \"%s\"", info->outdev);
 		goto out_unlock;
 	}
 
 	if (odev->type != ARPHRD_ETHER) {
-		sprintf(pg_result, "Not ethernet device: \"%s\"", pg_outdev);
+		sprintf(info->result, "Not ethernet device: \"%s\"", info->outdev);
 		goto out_unlock;
 	}
 
 	if (!netif_running(odev)) {
-		sprintf(pg_result, "Device is down: \"%s\"", pg_outdev);
+		sprintf(info->result, "Device is down: \"%s\"", info->outdev);
 		goto out_unlock;
 	}
 
-	for (p1 = 6, p2 = 0; p1 < odev->addr_len + 6; p1++)
-		hh[p1] = odev->dev_addr[p2++];
-
-	saddr = 0;
-	if (odev->ip_ptr) {
-		struct in_device *in_dev = odev->ip_ptr;
-
-		if (in_dev->ifa_list)
-			saddr = in_dev->ifa_list->ifa_address;
-	}
+        /* Default to the interface's mac if not explicitly set. */
+        if (!(info->flags & F_SET_SRCMAC)) {
+                memcpy(&(info->hh[6]), odev->dev_addr, 6);
+        }
+        else {
+                memcpy(&(info->hh[6]), info->src_mac, 6);
+        }
+
+        /* Set up Dest MAC */
+        memcpy(&(info->hh[0]), info->dst_mac, 6);
+        
+	info->saddr_min = 0;
+	info->saddr_max = 0;
+        if (strlen(info->src_min) == 0) {
+                if (odev->ip_ptr) {
+                        struct in_device *in_dev = odev->ip_ptr;
+
+                        if (in_dev->ifa_list) {
+                                info->saddr_min = in_dev->ifa_list->ifa_address;
+                                info->saddr_max = info->saddr_min;
+                        }
+                }
+	}
+        else {
+                info->saddr_min = in_aton(info->src_min);
+                info->saddr_max = in_aton(info->src_max);
+        }
+
+        info->daddr_min = in_aton(info->dst_min);
+        info->daddr_max = in_aton(info->dst_max);
+
+        /* Initialize current values. */
+        info->cur_dst_mac_offset = 0;
+        info->cur_src_mac_offset = 0;
+        info->cur_saddr = info->saddr_min;
+        info->cur_daddr = info->daddr_min;
+        info->cur_udp_dst = info->udp_dst_min;
+        info->cur_udp_src = info->udp_src_min;
+        
 	atomic_inc(&odev->refcnt);
 	rtnl_unlock();
 
-	*saddrp = saddr;
 	return odev;
 
 out_unlock:
@@ -130,9 +291,7 @@
 	return NULL;
 }
 
-static u32 idle_acc_lo, idle_acc_hi;
-
-static void nanospin(int pg_ipg)
+static void nanospin(int ipg, struct pktgen_info* info)
 {
 	u32 idle_start, idle;
 
@@ -141,12 +300,10 @@
 	for (;;) {
 		barrier();
 		idle = cycles() - idle_start;
-		if (idle * 1000 >= pg_ipg * pg_cpu_speed)
+		if (idle * 1000 >= ipg * cpu_speed)
 			break;
 	}
-	idle_acc_lo += idle;
-	if (idle_acc_lo < idle)
-		idle_acc_hi++;
+	info->idle_acc += idle;
 }
 
 static int calc_mhz(void)
@@ -172,22 +329,141 @@
 
 	for (i = 0; i < 3; i++) {
 		int res = calc_mhz();
-		if (res > pg_cpu_speed)
-			pg_cpu_speed = res;
+		if (res > cpu_speed)
+			cpu_speed = res;
 	}
 }
 
-static struct sk_buff *fill_packet(struct net_device *odev, __u32 saddr)
+
+/* Increment/randomize headers according to flags and current values
+ * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
+ */
+static void mod_cur_headers(struct pktgen_info* info) {        
+        __u32 imn;
+        __u32 imx;
+        
+	/*  Deal with source MAC */
+        if (info->src_mac_count > 1) {
+                __u32 mc;
+                __u32 tmp;
+                if (info->flags & F_MACSRC_RND) {
+                        mc = net_random() % (info->src_mac_count);
+                }
+                else {
+                        mc = info->cur_src_mac_offset++;
+                        if (info->cur_src_mac_offset > info->src_mac_count) {
+                                info->cur_src_mac_offset = 0;
+                        }
+                }
+
+                tmp = info->src_mac[5] + (mc & 0xFF);
+                info->hh[11] = tmp;
+                tmp = (info->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
+                info->hh[10] = tmp;
+                tmp = (info->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
+                info->hh[9] = tmp;
+                tmp = (info->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
+                info->hh[8] = tmp;
+                tmp = (info->src_mac[1] + (tmp >> 8));
+                info->hh[7] = tmp;        
+        }
+
+        /*  Deal with Destination MAC */
+        if (info->dst_mac_count > 1) {
+                __u32 mc;
+                __u32 tmp;
+                if (info->flags & F_MACDST_RND) {
+                        mc = net_random() % (info->dst_mac_count);
+                }
+                else {
+                        mc = info->cur_dst_mac_offset++;
+                        if (info->cur_dst_mac_offset > info->dst_mac_count) {
+                                info->cur_dst_mac_offset = 0;
+                        }
+                }
+
+                tmp = info->dst_mac[5] + (mc & 0xFF);
+                info->hh[5] = tmp;
+                tmp = (info->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
+                info->hh[4] = tmp;
+                tmp = (info->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
+                info->hh[3] = tmp;
+                tmp = (info->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
+                info->hh[2] = tmp;
+                tmp = (info->dst_mac[1] + (tmp >> 8));
+                info->hh[1] = tmp;        
+        }
+
+        if (info->udp_src_min < info->udp_src_max) {
+                if (info->flags & F_UDPSRC_RND) {
+                        info->cur_udp_src = ((net_random() % (info->udp_src_max - info->udp_src_min))
+                                             + info->udp_src_min);
+                }
+                else {
+                     info->cur_udp_src++;
+                     if (info->cur_udp_src >= info->udp_src_max) {
+                             info->cur_udp_src = info->udp_src_min;
+                     }
+                }
+        }
+
+        if (info->udp_dst_min < info->udp_dst_max) {
+                if (info->flags & F_UDPDST_RND) {
+                        info->cur_udp_dst = ((net_random() % (info->udp_dst_max - info->udp_dst_min))
+                                             + info->udp_dst_min);
+                }
+                else {
+                     info->cur_udp_dst++;
+                     if (info->cur_udp_dst >= info->udp_dst_max) {
+                             info->cur_udp_dst = info->udp_dst_min;
+                     }
+                }
+        }
+
+        if ((imn = ntohl(info->saddr_min)) < (imx = ntohl(info->saddr_max))) {
+                __u32 t;
+                if (info->flags & F_IPSRC_RND) {
+                        t = ((net_random() % (imx - imn)) + imn);
+                }
+                else {
+                     t = ntohl(info->cur_saddr);
+                     t++;
+                     if (t >= imx) {
+                             t = imn;
+                     }
+                }
+                info->cur_saddr = htonl(t);
+        }
+
+        if ((imn = ntohl(info->daddr_min)) < (imx = ntohl(info->daddr_max))) {
+                __u32 t;
+                if (info->flags & F_IPDST_RND) {
+                        t = ((net_random() % (imx - imn)) + imn);
+                }
+                else {
+                     t = ntohl(info->cur_daddr);
+                     t++;
+                     if (t >= imx) {
+                             t = imn;
+                     }
+                }
+                info->cur_daddr = htonl(t);
+        }
+}/* mod_cur_headers */
+
+
+static struct sk_buff *fill_packet(struct net_device *odev, struct pktgen_info* info)
 {
-	struct sk_buff *skb;
+	struct sk_buff *skb = NULL;
 	__u8 *eth;
 	struct udphdr *udph;
 	int datalen, iplen;
 	struct iphdr *iph;
-
-	skb = alloc_skb(pkt_size + 64 + 16, GFP_ATOMIC);
+        struct pktgen_hdr *pgh = NULL;
+        
+	skb = alloc_skb(info->pkt_size + 64 + 16, GFP_ATOMIC);
 	if (!skb) {
-		sprintf(pg_result, "No memory");
+		sprintf(info->result, "No memory");
 		return NULL;
 	}
 
@@ -198,15 +474,20 @@
 	iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
 	udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
 
-	/*  Copy the ethernet header  */
-	memcpy(eth, hh, 14);
-
-	datalen = pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */
-	if (datalen < 0)
-		datalen = 0;
-
-	udph->source = htons(9);
-	udph->dest = htons(9);
+        /* Update any of the values, used when we're incrementing various
+         * fields.
+         */
+        mod_cur_headers(info);
+
+	memcpy(eth, info->hh, 14);
+        
+	datalen = info->pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */
+	if (datalen < sizeof(struct pktgen_hdr)) {
+		datalen = sizeof(struct pktgen_hdr);
+        }
+        
+	udph->source = htons(info->cur_udp_src);
+	udph->dest = htons(info->cur_udp_dst);
 	udph->len = htons(datalen + 8); /* DATA + udphdr */
 	udph->check = 0;  /* No checksum */
 
@@ -215,8 +496,8 @@
 	iph->ttl = 3;
 	iph->tos = 0;
 	iph->protocol = IPPROTO_UDP; /* UDP */
-	iph->saddr = saddr;
-	iph->daddr = in_aton(pg_dst);
+	iph->saddr = info->cur_saddr;
+	iph->daddr = info->cur_daddr;
 	iph->frag_off = 0;
 	iplen = 20 + 8 + datalen;
 	iph->tot_len = htons(iplen);
@@ -227,12 +508,15 @@
 	skb->dev = odev;
 	skb->pkt_type = PACKET_HOST;
 
-	if (nfrags <= 0) {
-		skb_put(skb, datalen);
+	if (info->nfrags <= 0) {
+                pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
 	} else {
-		int frags = nfrags;
+		int frags = info->nfrags;
 		int i;
 
+                /* TODO: Verify this is OK...it sure is ugly. --Ben */
+                pgh = (struct pktgen_hdr*)(((char*)(udph)) + 8);
+                
 		if (frags > MAX_SKB_FRAGS)
 			frags = MAX_SKB_FRAGS;
 		if (datalen > frags*PAGE_SIZE) {
@@ -276,79 +560,126 @@
 		}
 	}
 
+        /* Stamp the time, and sequence number, convert them to network byte order */
+        if (pgh) {
+                pgh->pgh_magic = htonl(PKTGEN_MAGIC);
+                do_gettimeofday(&(pgh->timestamp));
+                pgh->timestamp.tv_usec = htonl(pgh->timestamp.tv_usec);
+                pgh->timestamp.tv_sec = htonl(pgh->timestamp.tv_sec);
+                pgh->seq_num = htonl(info->seq_num);
+        }
+        
 	return skb;
 }
 
 
-static void pg_inject(void)
+static void inject(struct pktgen_info* info)
 {
-	u32 saddr;
-	struct net_device *odev;
-	struct sk_buff *skb;
-	struct timeval start, stop;
-	u32 total, idle;
-	u32 pc, lcount;
-	char *p = pg_result;
-	u32  pkt_rate, data_rate;
-	char rate_unit;
+	struct net_device *odev = NULL;
+	struct sk_buff *skb = NULL;
+	__u64 total = 0;
+        __u64 idle = 0;
+	__u64 lcount = 0;
+        int nr_frags = 0;
+	int last_ok = 1;           /* Was last skb sent? 
+	                            * Or a failed transmit of some sort?  This will keep
+                                    * sequence numbers in order, for example.
+                                    */
+        __u64 fp = 0;
+        __u32 fp_tmp = 0;
 
-	odev = pg_setup_inject(&saddr);
+	odev = setup_inject(info);
 	if (!odev)
 		return;
 
-	skb = fill_packet(odev, saddr);
-	if (skb == NULL)
-		goto out_reldev;
-
-	forced_stop = 0;
-	idle_acc_hi = 0;
-	idle_acc_lo = 0;
-	pc = 0;
-	lcount = pg_count;
-	do_gettimeofday(&start);
+        info->do_run_run = 1; /* Cranke yeself! */
+	info->idle_acc = 0;
+	info->sofar = 0;
+	lcount = info->count;
+
+
+        /* Build our initial pkt and place it as a re-try pkt. */
+	skb = fill_packet(odev, info);
+	if (skb == NULL) goto out_reldev;
+
+	do_gettimeofday(&(info->started_at));
+
+	while(info->do_run_run) {
+
+                /* Set a time-stamp, so build a new pkt each time */
+
+                if (last_ok) {
+                        if (++fp_tmp >= info->clone_skb ) {
+                                kfree_skb(skb);
+                                skb = fill_packet(odev, info);
+                                if (skb == NULL) {
+                                        break;
+                                }
+                                fp++;
+                                fp_tmp = 0; /* reset counter */
+                        }
+                        atomic_inc(&skb->users);
+                }
 
-	for(;;) {
+                nr_frags = skb_shinfo(skb)->nr_frags;
+                   
 		spin_lock_bh(&odev->xmit_lock);
 		if (!netif_queue_stopped(odev)) {
-			struct sk_buff *skb2 = skb;
 
-			if (pg_multiskb)
-				skb2 = skb_copy(skb, GFP_ATOMIC);
-			else
-				atomic_inc(&skb->users);
-			if (!skb2)
-				goto skip;
-			if (odev->hard_start_xmit(skb2, odev)) {
-				kfree_skb(skb2);
-				if (net_ratelimit())
-					printk(KERN_INFO "Hard xmit error\n");
+			if (odev->hard_start_xmit(skb, odev)) {
+				if (net_ratelimit()) {
+                                   printk(KERN_INFO "Hard xmit error\n");
+                                }
+                                info->errors++;
+				last_ok = 0;
 			}
-			pc++;
+                        else {
+		           last_ok = 1;	
+                           info->sofar++;
+                           info->seq_num++;
+                        }
 		}
-	skip:
+		else {
+                        /* Re-try it next time */
+			last_ok = 0;
+                }
+                
+
 		spin_unlock_bh(&odev->xmit_lock);
 
-		if (pg_ipg)
-			nanospin(pg_ipg);
-		if (forced_stop)
-			goto out_intr;
-		if (signal_pending(current))
-			goto out_intr;
+		if (info->ipg) {
+                        /* Try not to busy-spin if we have larger sleep times.
+                         * TODO:  Investigate better ways to do this.
+                         */
+                        if (info->ipg < 10000) { /* 10 usecs or less */
+                                nanospin(info->ipg, info);
+                        }
+                        else if (info->ipg < 10000000) { /* 10ms or less */
+                                udelay(info->ipg / 1000);
+                        }
+                        else {
+                                mdelay(info->ipg / 1000000);
+                        }
+                }
+                
+		if (signal_pending(current)) {
+                        break;
+                }
 
-		if (--lcount == 0) {
+                /* If lcount is zero, then run forever */
+		if ((lcount != 0) && (--lcount == 0)) {
 			if (atomic_read(&skb->users) != 1) {
 				u32 idle_start, idle;
 
 				idle_start = cycles();
 				while (atomic_read(&skb->users) != 1) {
-					if (signal_pending(current))
-						goto out_intr;
+					if (signal_pending(current)) {
+                                                break;
+                                        }
 					schedule();
 				}
 				idle = cycles() - idle_start;
-				idle_acc_lo += idle;
-				if (idle_acc_lo < idle)
-					idle_acc_hi++;
+				info->idle_acc += idle;
 			}
 			break;
 		}
@@ -358,110 +689,160 @@
 
 			idle_start = cycles();
 			do {
-				if (signal_pending(current))
-					goto out_intr;
-				if (!netif_running(odev))
-					goto out_intr;
+				if (signal_pending(current)) {
+                                        info->do_run_run = 0;
+                                        break;
+                                }
+				if (!netif_running(odev)) {
+                                        info->do_run_run = 0;
+					break;
+                                }
 				if (current->need_resched)
 					schedule();
 				else
 					do_softirq();
 			} while (netif_queue_stopped(odev));
 			idle = cycles() - idle_start;
-			idle_acc_lo += idle;
-			if (idle_acc_lo < idle)
-				idle_acc_hi++;
+			info->idle_acc += idle;
 		}
-	}
+	}/* while we should be running */
 
-	do_gettimeofday(&stop);
+	do_gettimeofday(&(info->stopped_at));
 
-	total = (stop.tv_sec - start.tv_sec) * 1000000 +
-		stop.tv_usec - start.tv_usec;
+	total = (info->stopped_at.tv_sec - info->started_at.tv_sec) * 1000000 +
+		info->stopped_at.tv_usec - info->started_at.tv_usec;
 
-	if (total == 0) total = 1;  /* division by zero protection */
- 
-	idle = (((idle_acc_hi<<20)/pg_cpu_speed)<<12)+idle_acc_lo/pg_cpu_speed;
+	idle = (__u32)(info->idle_acc)/(__u32)(cpu_speed);
 
-	
-	/* 
-	   Rounding errors is around 1% on pkt_rate when total
-	   is just over 100.000. When total is big (total >=
-	   4.295 sec) pc need to be more than 430 to keep
-	   rounding errors below 1%. Shouldn't be a problem:)
-	   
-	   */
-
-	if (total < 100000) 
-		pkt_rate = (pc*1000000)/total;
-	else if (total < 0xFFFFFFFF/1000)        /* overflow protection: 2^32/1000 */
-		pkt_rate = (pc*1000)/(total/1000);		  
-	else if (total <  0xFFFFFFFF/100)     
-		pkt_rate = (pc*100)/(total/10000);		  
-	else if (total < 0xFFFFFFFF/10)     
-		pkt_rate = (pc*10)/(total/100000);		  
-	else
-		pkt_rate = (pc/(total/1000000));
-	
-	data_rate = (pkt_rate*pkt_size);
-	if (data_rate > 1024*1024 ) {   /* 10 MB/s */
-		data_rate = data_rate / (1024*1024);
-		rate_unit = 'M';
-	} else {
-		data_rate = data_rate / 1024;
-		rate_unit = 'K';
+        {
+		char *p = info->result;
+                __u64 pps = (__u32)(info->sofar * 1000) / ((__u32)(total) / 1000);
+                __u64 bps = pps * 8 * (info->pkt_size + 4); /* take 32bit ethernet CRC into account */
+		p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags) %llupps %lluMb/sec (%llubps)  errors: %llu",
+			     (unsigned long long) total,
+			     (unsigned long long) (total - idle),
+			     (unsigned long long) idle,
+			     (unsigned long long) info->sofar,
+                             skb->len + 4, /* Add 4 to account for the ethernet checksum */
+                             nr_frags,
+			     (unsigned long long) pps,
+			     (unsigned long long) (bps / (u64) 1024 / (u64) 1024),
+			     (unsigned long long) bps,
+			     (unsigned long long) info->errors
+			     );
 	}
-	
-	p += sprintf(p, "OK: %u(c%u+d%u) usec, %u (%dbyte,%dfrags) %upps %u%cB/sec",
-		     total, total-idle, idle,
-		     pc, skb->len, skb_shinfo(skb)->nr_frags,
-		     pkt_rate, data_rate, rate_unit
-		);
-	
-
-out_relskb:
-	kfree_skb(skb);
+        
 out_reldev:
-        dev_put(odev);
+        if (odev) {
+                dev_put(odev);
+                odev = NULL;
+        }
+
+        /* TODO:  Is this worth printing out (other than for debug?) */
+        printk("fp = %llu\n", (unsigned long long) fp);
 	return;
 
-out_intr:
-	sprintf(pg_result, "Interrupted");
-	goto out_relskb;
 }
 
-/* proc/net/pg */
-
-static struct proc_dir_entry *pg_proc_ent = 0;
-static struct proc_dir_entry *pg_busy_proc_ent = 0;
+/* proc/net/pktgen/pg */
 
-static int proc_pg_busy_read(char *buf , char **start, off_t offset,
+static int proc_busy_read(char *buf , char **start, off_t offset,
 			     int len, int *eof, void *data)
 {
 	char *p;
+        int idx = (int)(long)(data);
+        struct pktgen_info* info = NULL;
+        
+        if ((idx < 0) || (idx >= MAX_PKTGEN)) {
+                printk("ERROR: idx: %i is out of range in proc_write\n", idx);
+                return -EINVAL;
+        }
+        info = &(pginfos[idx]);
   
 	p = buf;
-	p += sprintf(p, "%d\n", pg_busy);
+	p += sprintf(p, "%d\n", info->busy);
 	*eof = 1;
   
 	return p-buf;
 }
 
-static int proc_pg_read(char *buf , char **start, off_t offset,
+static int proc_read(char *buf , char **start, off_t offset,
 			int len, int *eof, void *data)
 {
 	char *p;
 	int i;
+        int idx = (int)(long)(data);
+        struct pktgen_info* info = NULL;
+        __u64 sa;
+        __u64 stopped;
+        __u64 now = getCurMs();
+        
+        if ((idx < 0) || (idx >= MAX_PKTGEN)) {
+                printk("ERROR: idx: %i is out of range in proc_write\n", idx);
+                return -EINVAL;
+        }
+        info = &(pginfos[idx]);
   
 	p = buf;
-	p += sprintf(p, "Params: count=%u pkt_size=%u frags %d ipg %u multiskb %d odev \"%s\" dst %s dstmac ",
-		     pg_count, pkt_size, nfrags, pg_ipg, pg_multiskb,
-		     pg_outdev, pg_dst);
-	for (i = 0; i < 6; i++)
-		p += sprintf(p, "%02X%s", pg_dstmac[i], i == 5 ? "\n" : ":");
-
-	if (pg_result[0])
-		p += sprintf(p, "Result: %s\n", pg_result);
+        p += sprintf(p, "%s\n", VERSION); /* Help with parsing compatibility */
+	p += sprintf(p, "Params: count %llu  pkt_size: %u  frags: %d  ipg: %u  clone_skb: %d odev \"%s\"\n",
+		     (unsigned long long) info->count,
+		     info->pkt_size, info->nfrags, info->ipg,
+                     info->clone_skb, info->outdev);
+        p += sprintf(p, "     dst_min: %s  dst_max: %s  src_min: %s  src_max: %s\n",
+                     info->dst_min, info->dst_max, info->src_min, info->src_max);
+        p += sprintf(p, "     src_mac: ");
+	for (i = 0; i < 6; i++) {
+		p += sprintf(p, "%02X%s", info->src_mac[i], i == 5 ? "  " : ":");
+        }
+        p += sprintf(p, "dst_mac: ");
+	for (i = 0; i < 6; i++) {
+		p += sprintf(p, "%02X%s", info->dst_mac[i], i == 5 ? "\n" : ":");
+        }
+        p += sprintf(p, "     udp_src_min: %d  udp_src_max: %d  udp_dst_min: %d  udp_dst_max: %d\n",
+                     info->udp_src_min, info->udp_src_max, info->udp_dst_min,
+                     info->udp_dst_max);
+        p += sprintf(p, "     src_mac_count: %d  dst_mac_count: %d\n     Flags: ",
+                     info->src_mac_count, info->dst_mac_count);
+        if (info->flags &  F_IPSRC_RND) {
+                p += sprintf(p, "IPSRC_RND  ");
+        }
+        if (info->flags & F_IPDST_RND) {
+                p += sprintf(p, "IPDST_RND  ");
+        }
+        if (info->flags & F_UDPSRC_RND) {
+                p += sprintf(p, "UDPSRC_RND  ");
+        }
+        if (info->flags & F_UDPDST_RND) {
+                p += sprintf(p, "UDPDST_RND  ");
+        }
+        if (info->flags & F_MACSRC_RND) {
+                p += sprintf(p, "MACSRC_RND  ");
+        }
+        if (info->flags & F_MACDST_RND) {
+                p += sprintf(p, "MACDST_RND  ");
+        }
+        p += sprintf(p, "\n");
+        
+        sa = tv_to_ms(&(info->started_at));
+        stopped = tv_to_ms(&(info->stopped_at));
+        if (info->do_run_run) {
+                stopped = now; /* not really stopped, more like last-running-at */
+        }
+        p += sprintf(p, "Current:\n     pkts-sofar: %llu  errors: %llu\n     started: %llums  stopped: %llums  now: %llums  idle: %lluns\n",
+                     (unsigned long long) info->sofar,
+		     (unsigned long long) info->errors,
+		     (unsigned long long) sa,
+		     (unsigned long long) stopped,
+		     (unsigned long long) now,
+		     (unsigned long long) info->idle_acc);
+        p += sprintf(p, "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
+                     info->seq_num, info->cur_dst_mac_offset, info->cur_src_mac_offset);
+        p += sprintf(p, "     cur_saddr: 0x%x  cur_daddr: 0x%x  cur_udp_dst: %d  cur_udp_src: %d\n",
+                     info->cur_saddr, info->cur_daddr, info->cur_udp_dst, info->cur_udp_src);
+        
+	if (info->result[0])
+		p += sprintf(p, "Result: %s\n", info->result);
 	else
 		p += sprintf(p, "Result: Idle\n");
 	*eof = 1;
@@ -469,12 +850,16 @@
 	return p - buf;
 }
 
-static int count_trail_chars(const char *buffer, unsigned int maxlen)
+static int count_trail_chars(const char *user_buffer, unsigned int maxlen)
 {
 	int i;
 
 	for (i = 0; i < maxlen; i++) {
-		switch (buffer[i]) {
+		char c;
+
+		if (get_user(c, &user_buffer[i]))
+			return -EFAULT;
+		switch (c) {
 		case '\"':
 		case '\n':
 		case '\r':
@@ -490,7 +875,7 @@
 	return i;
 }
 
-static unsigned long num_arg(const char *buffer, unsigned long maxlen, 
+static unsigned long num_arg(const char *user_buffer, unsigned long maxlen,
 			     unsigned long *num)
 {
 	int i = 0;
@@ -498,21 +883,29 @@
 	*num = 0;
   
 	for(; i < maxlen; i++) {
-		if ((buffer[i] >= '0') && (buffer[i] <= '9')) {
+		char c;
+
+		if (get_user(c, &user_buffer[i]))
+			return -EFAULT;
+		if ((c >= '0') && (c <= '9')) {
 			*num *= 10;
-			*num += buffer[i] -'0';
+			*num += c -'0';
 		} else
 			break;
 	}
 	return i;
 }
 
-static int strn_len(const char *buffer, unsigned int maxlen)
+static int strn_len(const char *user_buffer, unsigned int maxlen)
 {
 	int i = 0;
 
 	for(; i < maxlen; i++) {
-		switch (buffer[i]) {
+		char c;
+
+		if (get_user(c, &user_buffer[i]))
+			return -EFAULT;
+		switch (c) {
 		case '\"':
 		case '\n':
 		case '\r':
@@ -520,123 +913,296 @@
 		case ' ':
 			goto done_str;
 		default:
+			break;
 		};
 	}
 done_str:
 	return i;
 }
 
-static int proc_pg_write(struct file *file, const char *buffer,
+static int proc_write(struct file *file, const char *user_buffer,
 			 unsigned long count, void *data)
 {
 	int i = 0, max, len;
 	char name[16], valstr[32];
 	unsigned long value = 0;
-  
+        int idx = (int)(long)(data);
+        struct pktgen_info* info = NULL;
+        char* result = NULL;
+	int tmp;
+        
+        if ((idx < 0) || (idx >= MAX_PKTGEN)) {
+                printk("ERROR: idx: %i is out of range in proc_write\n", idx);
+                return -EINVAL;
+        }
+        info = &(pginfos[idx]);
+        result = &(info->result[0]);
+        
 	if (count < 1) {
-		sprintf(pg_result, "Wrong command format");
+		sprintf(result, "Wrong command format");
 		return -EINVAL;
 	}
   
 	max = count - i;
-	i += count_trail_chars(&buffer[i], max);
+	tmp = count_trail_chars(&user_buffer[i], max);
+	if (tmp < 0)
+		return tmp;
+	i += tmp;
   
 	/* Read variable name */
 
-	len = strn_len(&buffer[i], sizeof(name) - 1);
+	len = strn_len(&user_buffer[i], sizeof(name) - 1);
+	if (len < 0)
+		return len;
 	memset(name, 0, sizeof(name));
-	strncpy(name, &buffer[i], len);
+	copy_from_user(name, &user_buffer[i], len);
 	i += len;
   
 	max = count -i;
-	len = count_trail_chars(&buffer[i], max);
+	len = count_trail_chars(&user_buffer[i], max);
+	if (len < 0)
+		return len;
 	i += len;
 
 	if (debug)
 		printk("pg: %s,%lu\n", name, count);
 
-	/* Only stop is allowed when we are running */
-  
 	if (!strcmp(name, "stop")) {
-		forced_stop = 1;
-		if (pg_busy)
-			strcpy(pg_result, "Stopping");
+		if (info->do_run_run) {
+			strcpy(result, "Stopping");
+                }
+                else {
+                        strcpy(result, "Already stopped...\n");
+                }
+                info->do_run_run = 0;
 		return count;
 	}
 
-	if (pg_busy) {
-		strcpy(pg_result, "Busy");
-		return -EINVAL;
-	}
-
 	if (!strcmp(name, "pkt_size")) {
-		len = num_arg(&buffer[i], 10, &value);
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
 		i += len;
 		if (value < 14+20+8)
 			value = 14+20+8;
-		pkt_size = value;
-		sprintf(pg_result, "OK: pkt_size=%u", pkt_size);
+		info->pkt_size = value;
+		sprintf(result, "OK: pkt_size=%u", info->pkt_size);
 		return count;
 	}
 	if (!strcmp(name, "frags")) {
-		len = num_arg(&buffer[i], 10, &value);
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
 		i += len;
-		nfrags = value;
-		sprintf(pg_result, "OK: frags=%u", nfrags);
+		info->nfrags = value;
+		sprintf(result, "OK: frags=%u", info->nfrags);
 		return count;
 	}
 	if (!strcmp(name, "ipg")) {
-		len = num_arg(&buffer[i], 10, &value);
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+		info->ipg = value;
+		sprintf(result, "OK: ipg=%u", info->ipg);
+		return count;
+	}
+ 	if (!strcmp(name, "udp_src_min")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+	 	info->udp_src_min = value;
+		sprintf(result, "OK: udp_src_min=%u", info->udp_src_min);
+		return count;
+	}
+ 	if (!strcmp(name, "udp_dst_min")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+	 	info->udp_dst_min = value;
+		sprintf(result, "OK: udp_dst_min=%u", info->udp_dst_min);
+		return count;
+	}
+ 	if (!strcmp(name, "udp_src_max")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+	 	info->udp_src_max = value;
+		sprintf(result, "OK: udp_src_max=%u", info->udp_src_max);
+		return count;
+	}
+ 	if (!strcmp(name, "udp_dst_max")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
 		i += len;
-		pg_ipg = value;
-		sprintf(pg_result, "OK: ipg=%u", pg_ipg);
+	 	info->udp_dst_max = value;
+		sprintf(result, "OK: udp_dst_max=%u", info->udp_dst_max);
 		return count;
 	}
-	if (!strcmp(name, "multiskb")) {
-		len = num_arg(&buffer[i], 10, &value);
+	if (!strcmp(name, "clone_skb")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
 		i += len;
-		pg_multiskb = (value ? 1 : 0);
-		sprintf(pg_result, "OK: multiskb=%d", pg_multiskb);
+                info->clone_skb = value;
+	
+		sprintf(result, "OK: clone_skb=%d", info->clone_skb);
 		return count;
 	}
 	if (!strcmp(name, "count")) {
-		len = num_arg(&buffer[i], 10, &value);
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+		info->count = value;
+		sprintf(result, "OK: count=%llu", (unsigned long long) info->count);
+		return count;
+	}
+	if (!strcmp(name, "src_mac_count")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+		info->src_mac_count = value;
+		sprintf(result, "OK: src_mac_count=%d", info->src_mac_count);
+		return count;
+	}
+	if (!strcmp(name, "dst_mac_count")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
 		i += len;
-		if (value != 0) {
-			pg_count = value;
-			sprintf(pg_result, "OK: count=%u", pg_count);
-		} else 
-			sprintf(pg_result, "ERROR: no point in sending 0 packets. Leaving count=%u", pg_count);
+		info->dst_mac_count = value;
+		sprintf(result, "OK: dst_mac_count=%d", info->dst_mac_count);
 		return count;
 	}
 	if (!strcmp(name, "odev")) {
-		len = strn_len(&buffer[i], sizeof(pg_outdev) - 1);
-		memset(pg_outdev, 0, sizeof(pg_outdev));
-		strncpy(pg_outdev, &buffer[i], len);
+		len = strn_len(&user_buffer[i], sizeof(info->outdev) - 1);
+		if (len < 0)
+			return len;
+		memset(info->outdev, 0, sizeof(info->outdev));
+		copy_from_user(info->outdev, &user_buffer[i], len);
+		i += len;
+		sprintf(result, "OK: odev=%s", info->outdev);
+		return count;
+	}
+	if (!strcmp(name, "flag")) {
+                char f[32];
+                memset(f, 0, 32);
+		len = strn_len(&user_buffer[i], sizeof(f) - 1);
+		if (len < 0)
+			return len;
+		copy_from_user(f, &user_buffer[i], len);
+		i += len;
+                if (strcmp(f, "IPSRC_RND") == 0) {
+                        info->flags |= F_IPSRC_RND;
+                }
+                else if (strcmp(f, "!IPSRC_RND") == 0) {
+                        info->flags &= ~F_IPSRC_RND;
+                }
+                else if (strcmp(f, "IPDST_RND") == 0) {
+                        info->flags |= F_IPDST_RND;
+                }
+                else if (strcmp(f, "!IPDST_RND") == 0) {
+                        info->flags &= ~F_IPDST_RND;
+                }
+                else if (strcmp(f, "UDPSRC_RND") == 0) {
+                        info->flags |= F_UDPSRC_RND;
+                }
+                else if (strcmp(f, "!UDPSRC_RND") == 0) {
+                        info->flags &= ~F_UDPSRC_RND;
+                }
+                else if (strcmp(f, "UDPDST_RND") == 0) {
+                        info->flags |= F_UDPDST_RND;
+                }
+                else if (strcmp(f, "!UDPDST_RND") == 0) {
+                        info->flags &= ~F_UDPDST_RND;
+                }
+                else if (strcmp(f, "MACSRC_RND") == 0) {
+                        info->flags |= F_MACSRC_RND;
+                }
+                else if (strcmp(f, "!MACSRC_RND") == 0) {
+                        info->flags &= ~F_MACSRC_RND;
+                }
+                else if (strcmp(f, "MACDST_RND") == 0) {
+                        info->flags |= F_MACDST_RND;
+                }
+                else if (strcmp(f, "!MACDST_RND") == 0) {
+                        info->flags &= ~F_MACDST_RND;
+                }
+                else {
+                        sprintf(result, "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
+                                f,
+                                "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n");
+                        return count;
+                }
+		sprintf(result, "OK: flags=0x%x", info->flags);
+		return count;
+	}
+	if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
+		len = strn_len(&user_buffer[i], sizeof(info->dst_min) - 1);
+		if (len < 0)
+			return len;
+		memset(info->dst_min, 0, sizeof(info->dst_min));
+		copy_from_user(info->dst_min, &user_buffer[i], len);
+		if(debug)
+			printk("pg: dst_min set to: %s\n", info->dst_min);
 		i += len;
-		sprintf(pg_result, "OK: odev=%s", pg_outdev);
+		sprintf(result, "OK: dst_min=%s", info->dst_min);
 		return count;
 	}
-	if (!strcmp(name, "dst")) {
-		len = strn_len(&buffer[i], sizeof(pg_dst) - 1);
-		memset(pg_dst, 0, sizeof(pg_dst));
-		strncpy(pg_dst, &buffer[i], len);
+	if (!strcmp(name, "dst_max")) {
+		len = strn_len(&user_buffer[i], sizeof(info->dst_max) - 1);
+		if (len < 0)
+			return len;
+		memset(info->dst_max, 0, sizeof(info->dst_max));
+		copy_from_user(info->dst_max, &user_buffer[i], len);
 		if(debug)
-			printk("pg: dst set to: %s\n", pg_dst);
+			printk("pg: dst_max set to: %s\n", info->dst_max);
 		i += len;
-		sprintf(pg_result, "OK: dst=%s", pg_dst);
+		sprintf(result, "OK: dst_max=%s", info->dst_max);
+		return count;
+	}
+	if (!strcmp(name, "src_min")) {
+		len = strn_len(&user_buffer[i], sizeof(info->src_min) - 1);
+		if (len < 0)
+			return len;
+		memset(info->src_min, 0, sizeof(info->src_min));
+		copy_from_user(info->src_min, &user_buffer[i], len);
+		if(debug)
+			printk("pg: src_min set to: %s\n", info->src_min);
+		i += len;
+		sprintf(result, "OK: src_min=%s", info->src_min);
+		return count;
+	}
+	if (!strcmp(name, "src_max")) {
+		len = strn_len(&user_buffer[i], sizeof(info->src_max) - 1);
+		if (len < 0)
+			return len;
+		memset(info->src_max, 0, sizeof(info->src_max));
+		copy_from_user(info->src_max, &user_buffer[i], len);
+		if(debug)
+			printk("pg: src_max set to: %s\n", info->src_max);
+		i += len;
+		sprintf(result, "OK: src_max=%s", info->src_max);
 		return count;
 	}
 	if (!strcmp(name, "dstmac")) {
 		char *v = valstr;
-		unsigned char *m = pg_dstmac;
+		unsigned char *m = info->dst_mac;
 
-		len = strn_len(&buffer[i], sizeof(valstr) - 1);
+		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
+		if (len < 0)
+			return len;
 		memset(valstr, 0, sizeof(valstr));
-		strncpy(valstr, &buffer[i], len);
+		copy_from_user(valstr, &user_buffer[i], len);
 		i += len;
 
-		for(*m = 0;*v && m < pg_dstmac + 6; v++) {
+		for(*m = 0;*v && m < info->dst_mac + 6; v++) {
 			if (*v >= '0' && *v <= '9') {
 				*m *= 16;
 				*m += *v - '0';
@@ -654,66 +1220,171 @@
 				*m = 0;
 			}
 		}	  
-		sprintf(pg_result, "OK: dstmac");
+		sprintf(result, "OK: dstmac");
+		return count;
+	}
+	if (!strcmp(name, "srcmac")) {
+		char *v = valstr;
+		unsigned char *m = info->src_mac;
+
+		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
+		if (len < 0)
+			return len;
+		memset(valstr, 0, sizeof(valstr));
+		copy_from_user(valstr, &user_buffer[i], len);
+		i += len;
+
+		for(*m = 0;*v && m < info->src_mac + 6; v++) {
+			if (*v >= '0' && *v <= '9') {
+				*m *= 16;
+				*m += *v - '0';
+			}
+			if (*v >= 'A' && *v <= 'F') {
+				*m *= 16;
+				*m += *v - 'A' + 10;
+			}
+			if (*v >= 'a' && *v <= 'f') {
+				*m *= 16;
+				*m += *v - 'a' + 10;
+			}
+			if (*v == ':') {
+				m++;
+				*m = 0;
+			}
+		}	  
+		sprintf(result, "OK: srcmac");
 		return count;
 	}
 
 	if (!strcmp(name, "inject") || !strcmp(name, "start")) {
 		MOD_INC_USE_COUNT;
-		pg_busy = 1;
-		strcpy(pg_result, "Starting");
-		pg_inject();
-		pg_busy = 0;
+                if (info->busy) {
+                        strcpy(info->result, "Already running...\n");
+                }
+                else {
+                        info->busy = 1;
+                        strcpy(info->result, "Starting");
+                        inject(info);
+                        info->busy = 0;
+                }
 		MOD_DEC_USE_COUNT;
 		return count;
 	}
 
-	sprintf(pg_result, "No such parameter \"%s\"", name);
+	sprintf(info->result, "No such parameter \"%s\"", name);
 	return -EINVAL;
 }
 
-static int __init pg_init(void)
+
+int create_proc_dir(void)
+{
+        int     len;
+        /*  does proc_dir already exists */
+        len = strlen(PG_PROC_DIR);
+
+        for (proc_dir = proc_net->subdir; proc_dir;
+             proc_dir=proc_dir->next) {
+                if ((proc_dir->namelen == len) &&
+                    (! memcmp(proc_dir->name, PG_PROC_DIR, len)))
+                        break;
+        }
+        if (!proc_dir)
+                proc_dir = create_proc_entry(PG_PROC_DIR, S_IFDIR, proc_net);
+        if (!proc_dir) return -ENODEV;
+        return 1;
+}
+
+int remove_proc_dir(void)
 {
+        remove_proc_entry(PG_PROC_DIR, proc_net);
+        return 1;
+}
+
+static int __init init(void)
+{
+        int i;
 	printk(version);
 	cycles_calibrate();
-	if (pg_cpu_speed == 0) {
+	if (cpu_speed == 0) {
 		printk("pktgen: Error: your machine does not have working cycle counter.\n");
 		return -EINVAL;
 	}
-	pg_proc_ent = create_proc_entry("net/pg", 0600, 0);
-	if (!pg_proc_ent) {
-		printk("pktgen: Error: cannot create net/pg procfs entry.\n");
-		return -ENOMEM;
-	}
-	pg_proc_ent->read_proc = proc_pg_read;
-	pg_proc_ent->write_proc = proc_pg_write;
-	pg_proc_ent->data = 0;
 
-	pg_busy_proc_ent = create_proc_entry("net/pg_busy", 0, 0);
-	if (!pg_busy_proc_ent) {
-		printk("pktgen: Error: cannot create net/pg_busy procfs entry.\n");
-		remove_proc_entry("net/pg", NULL);
-		return -ENOMEM;
-	}
-	pg_busy_proc_ent->read_proc = proc_pg_busy_read;
-	pg_busy_proc_ent->data = 0;
+	create_proc_dir();
 
-	return 0;
+        for (i = 0; i<MAX_PKTGEN; i++) {
+                memset(&(pginfos[i]), 0, sizeof(pginfos[i]));
+                pginfos[i].pkt_size = ETH_ZLEN;
+                pginfos[i].nfrags = 0;
+                pginfos[i].clone_skb = clone_skb_d;
+                pginfos[i].ipg = ipg_d;
+                pginfos[i].count = count_d;
+                pginfos[i].sofar = 0;
+                pginfos[i].hh[12] = 0x08; /* fill in protocol.  Rest is filled in later. */
+                pginfos[i].hh[13] = 0x00;
+                pginfos[i].udp_src_min = 9; /* sink NULL */
+                pginfos[i].udp_src_max = 9;
+                pginfos[i].udp_dst_min = 9;
+                pginfos[i].udp_dst_max = 9;
+                
+                sprintf(pginfos[i].fname, "net/%s/pg%i", PG_PROC_DIR, i);
+                pginfos[i].proc_ent = create_proc_entry(pginfos[i].fname, 0600, 0);
+                if (!pginfos[i].proc_ent) {
+                        printk("pktgen: Error: cannot create net/%s/pg procfs entry.\n", PG_PROC_DIR);
+                        goto cleanup_mem;
+                }
+                pginfos[i].proc_ent->read_proc = proc_read;
+                pginfos[i].proc_ent->write_proc = proc_write;
+                pginfos[i].proc_ent->data = (void*)(long)(i);
+
+                sprintf(pginfos[i].busy_fname, "net/%s/pg_busy%i",  PG_PROC_DIR, i);
+                pginfos[i].busy_proc_ent = create_proc_entry(pginfos[i].busy_fname, 0, 0);
+                if (!pginfos[i].busy_proc_ent) {
+                        printk("pktgen: Error: cannot create net/%s/pg_busy procfs entry.\n", PG_PROC_DIR);
+                        goto cleanup_mem;
+                }
+                pginfos[i].busy_proc_ent->read_proc = proc_busy_read;
+                pginfos[i].busy_proc_ent->data = (void*)(long)(i);
+        }
+        return 0;
+        
+cleanup_mem:
+        for (i = 0; i<MAX_PKTGEN; i++) {
+                if (strlen(pginfos[i].fname)) {
+                        remove_proc_entry(pginfos[i].fname, NULL);
+                }
+                if (strlen(pginfos[i].busy_fname)) {
+                        remove_proc_entry(pginfos[i].busy_fname, NULL);
+                }
+        }
+	return -ENOMEM;
 }
 
-static void __exit pg_cleanup(void)
+
+static void __exit cleanup(void)
 {
-	remove_proc_entry("net/pg", NULL);
-	remove_proc_entry("net/pg_busy", NULL);
+        int i;
+        for (i = 0; i<MAX_PKTGEN; i++) {
+                if (strlen(pginfos[i].fname)) {
+                        remove_proc_entry(pginfos[i].fname, NULL);
+                }
+                if (strlen(pginfos[i].busy_fname)) {
+                        remove_proc_entry(pginfos[i].busy_fname, NULL);
+                }
+        }
+	remove_proc_dir();
 }
 
-module_init(pg_init);
-module_exit(pg_cleanup);
+module_init(init);
+module_exit(cleanup);
 
 MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se");
 MODULE_DESCRIPTION("Packet Generator tool");
 MODULE_LICENSE("GPL");
-MODULE_PARM(pg_count, "i");
-MODULE_PARM(pg_ipg, "i");
-MODULE_PARM(pg_cpu_speed, "i");
-MODULE_PARM(pg_multiskb, "i");
+MODULE_PARM(count_d, "i");
+MODULE_PARM(ipg_d, "i");
+MODULE_PARM(cpu_speed, "i");
+MODULE_PARM(clone_skb_d, "i");
+
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/core/rtnetlink.c linux-2.4.20/net/core/rtnetlink.c
--- linux-2.4.19/net/core/rtnetlink.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.20/net/core/rtnetlink.c	2002-10-29 11:18:48.000000000 +0000
@@ -523,6 +523,7 @@
 	rtnl = netlink_kernel_create(NETLINK_ROUTE, rtnetlink_rcv);
 	if (rtnl == NULL)
 		panic("rtnetlink_init: cannot initialize rtnetlink\n");
+	netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV);
 	register_netdevice_notifier(&rtnetlink_dev_notifier);
 	rtnetlink_links[PF_UNSPEC] = link_rtnetlink_table;
 	rtnetlink_links[PF_PACKET] = link_rtnetlink_table;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/core/sysctl_net_core.c linux-2.4.20/net/core/sysctl_net_core.c
--- linux-2.4.19/net/core/sysctl_net_core.c	2000-10-10 17:33:52.000000000 +0000
+++ linux-2.4.20/net/core/sysctl_net_core.c	2002-10-29 11:18:37.000000000 +0000
@@ -12,6 +12,7 @@
 #ifdef CONFIG_SYSCTL
 
 extern int netdev_max_backlog;
+extern int weight_p;
 extern int no_cong_thresh;
 extern int no_cong;
 extern int lo_cong;
@@ -47,6 +48,9 @@
 	{NET_CORE_RMEM_DEFAULT, "rmem_default",
 	 &sysctl_rmem_default, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
+	{NET_CORE_DEV_WEIGHT, "dev_weight",
+	 &weight_p, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
 	{NET_CORE_MAX_BACKLOG, "netdev_max_backlog",
 	 &netdev_max_backlog, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/core/wireless.c linux-2.4.20/net/core/wireless.c
--- linux-2.4.19/net/core/wireless.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/core/wireless.c	2002-10-29 11:18:34.000000000 +0000
@@ -2,7 +2,7 @@
  * This file implement the Wireless Extensions APIs.
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
  *
  * (As all part of the Linux kernel, this file is GPL)
  */
@@ -25,6 +25,16 @@
  *	o Added iw_handler handling ;-)
  *	o Added standard ioctl description
  *	o Initial dumb commit strategy based on orinoco.c
+ *
+ * v3 - 19.12.01 - Jean II
+ *	o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call
+ *	o Add event dispatcher function
+ *	o Add event description
+ *	o Propagate events as rtnetlink IFLA_WIRELESS option
+ *	o Generate event on selected SET requests
+ *
+ * v4 - 18.04.01 - Jean II
+ *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
  */
 
 /***************************** INCLUDES *****************************/
@@ -33,6 +43,7 @@
 #include <linux/config.h>		/* Not needed ??? */
 #include <linux/types.h>		/* off_t */
 #include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
+#include <linux/rtnetlink.h>		/* rtnetlink stuff */
 
 #include <linux/wireless.h>		/* Pretty obvious */
 #include <net/iw_handler.h>		/* New driver API */
@@ -44,14 +55,23 @@
 
 /* Debuging stuff */
 #undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
+#undef WE_EVENT_DEBUG		/* Debug Event dispatcher */
+
+/* Options */
+#define WE_EVENT_NETLINK	/* Propagate events using rtnetlink */
+#define WE_SET_EVENT		/* Generate an event on some set commands */
 
 /************************* GLOBAL VARIABLES *************************/
 /*
  * You should not use global variables, because or re-entrancy.
  * On our case, it's only const, so it's OK...
  */
+/*
+ * Meta-data about all the standard Wireless Extension request we
+ * know about.
+ */
 static const struct iw_ioctl_description	standard_ioctl[] = {
-	/* SIOCSIWCOMMIT (internal) */
+	/* SIOCSIWCOMMIT */
 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
 	/* SIOCGIWNAME */
 	{ IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
@@ -99,18 +119,18 @@
 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
 	/* SIOCGIWAPLIST */
 	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
-	/* -- hole -- */
-	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-	/* -- hole -- */
-	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCSIWSCAN */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWSCAN */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0},
 	/* SIOCSIWESSID */
-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT},
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT},
 	/* SIOCGIWESSID */
-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP},
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_DUMP},
 	/* SIOCSIWNICKN */
-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
 	/* SIOCGIWNICKN */
-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
 	/* -- hole -- */
 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
 	/* -- hole -- */
@@ -136,7 +156,7 @@
 	/* SIOCGIWRETRY */
 	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
 	/* SIOCSIWENCODE */
-	{ IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
 	/* SIOCGIWENCODE */
 	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT},
 	/* SIOCSIWPOWER */
@@ -144,9 +164,38 @@
 	/* SIOCGIWPOWER */
 	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
 };
+static const int standard_ioctl_num = (sizeof(standard_ioctl) /
+				       sizeof(struct iw_ioctl_description));
+
+/*
+ * Meta-data about all the additional standard Wireless Extension events
+ * we know about.
+ */
+static const struct iw_ioctl_description	standard_event[] = {
+	/* IWEVTXDROP */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+	/* IWEVQUAL */
+	{ IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
+};
+static const int standard_event_num = (sizeof(standard_event) /
+				       sizeof(struct iw_ioctl_description));
 
 /* Size (in bytes) of the various private data types */
-char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
+static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
+
+/* Size (in bytes) of various events */
+static const int event_type_size[] = {
+	IW_EV_LCP_LEN,
+	0,
+	IW_EV_CHAR_LEN,
+	0,
+	IW_EV_UINT_LEN,
+	IW_EV_FREQ_LEN,
+	IW_EV_POINT_LEN,		/* Without variable payload */
+	IW_EV_PARAM_LEN,
+	IW_EV_ADDR_LEN,
+	IW_EV_QUAL_LEN,
+};
 
 /************************ COMMON SUBROUTINES ************************/
 /*
@@ -162,7 +211,8 @@
 static inline iw_handler get_handler(struct net_device *dev,
 				     unsigned int cmd)
 {
-	unsigned int	index;		/* MUST be unsigned */
+	/* Don't "optimise" the following variable, it will crash */
+	unsigned int	index;		/* *MUST* be unsigned */
 
 	/* Check if we have some wireless handlers defined */
 	if(dev->wireless_handlers == NULL)
@@ -269,9 +319,9 @@
 			       stats->status,
 			       stats->qual.qual,
 			       stats->qual.updated & 1 ? '.' : ' ',
-			       stats->qual.level,
+			       ((__u8) stats->qual.level),
 			       stats->qual.updated & 2 ? '.' : ' ',
-			       stats->qual.noise,
+			       ((__u8) stats->qual.noise),
 			       stats->qual.updated & 4 ? '.' : ' ',
 			       stats->discard.nwid,
 			       stats->discard.code,
@@ -423,12 +473,14 @@
 	int					ret = -EINVAL;
 
 	/* Get the description of the IOCTL */
+	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
+		return -EOPNOTSUPP;
 	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
 
 #ifdef WE_IOCTL_DEBUG
-	printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n",
+	printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n",
 	       ifr->ifr_name, cmd);
-	printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
+	printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
 #endif	/* WE_IOCTL_DEBUG */
 
 	/* Prepare the call */
@@ -437,8 +489,16 @@
 
 	/* Check if we have a pointer to user space data or not */
 	if(descr->header_type != IW_HEADER_TYPE_POINT) {
+
 		/* No extra arguments. Trivial to handle */
 		ret = handler(dev, &info, &(iwr->u), NULL);
+
+#ifdef WE_SET_EVENT
+		/* Generate an event to notify listeners of the change */
+		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
+		   ((ret == 0) || (ret == -EIWCOMMIT)))
+			wireless_send_event(dev, cmd, &(iwr->u), NULL);
+#endif	/* WE_SET_EVENT */
 	} else {
 		char *	extra;
 		int	err;
@@ -466,8 +526,8 @@
 		}
 
 #ifdef WE_IOCTL_DEBUG
-		printk(KERN_DEBUG "Malloc %d bytes\n",
-		       descr->max_tokens * descr->token_size);
+		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
+		       dev->name, descr->max_tokens * descr->token_size);
 #endif	/* WE_IOCTL_DEBUG */
 
 		/* Always allocate for max space. Easier, and won't last
@@ -488,7 +548,8 @@
 				return -EFAULT;
 			}
 #ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "Got %d bytes\n",
+			printk(KERN_DEBUG "%s (WE) : Got %d bytes\n",
+			       dev->name,
 			       iwr->u.data.length * descr->token_size);
 #endif	/* WE_IOCTL_DEBUG */
 		}
@@ -504,11 +565,26 @@
 			if (err)
 				ret =  -EFAULT;				   
 #ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "Wrote %d bytes\n",
+			printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n",
+			       dev->name,
 			       iwr->u.data.length * descr->token_size);
 #endif	/* WE_IOCTL_DEBUG */
 		}
 
+#ifdef WE_SET_EVENT
+		/* Generate an event to notify listeners of the change */
+		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
+		   ((ret == 0) || (ret == -EIWCOMMIT))) {
+			if(descr->flags & IW_DESCR_FLAG_RESTRICT)
+				/* If the event is restricted, don't
+				 * export the payload */
+				wireless_send_event(dev, cmd, &(iwr->u), NULL);
+			else
+				wireless_send_event(dev, cmd, &(iwr->u),
+						    extra);
+		}
+#endif	/* WE_SET_EVENT */
+
 		/* Cleanup - I told you it wasn't that long ;-) */
 		kfree(extra);
 	}
@@ -558,11 +634,12 @@
 		}
 
 #ifdef WE_IOCTL_DEBUG
-	printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n",
+	printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n",
 	       ifr->ifr_name, cmd);
 	if(descr) {
-		printk(KERN_DEBUG "Name %s, set %X, get %X\n",
-		       descr->name, descr->set_args, descr->get_args);
+		printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n",
+		       dev->name, descr->name,
+		       descr->set_args, descr->get_args);
 	}
 #endif	/* WE_IOCTL_DEBUG */
 
@@ -617,7 +694,8 @@
 		}
 
 #ifdef WE_IOCTL_DEBUG
-		printk(KERN_DEBUG "Malloc %d bytes\n", extra_size);
+		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
+		       dev->name, extra_size);
 #endif	/* WE_IOCTL_DEBUG */
 
 		/* Always allocate for max space. Easier, and won't last
@@ -636,7 +714,8 @@
 				return -EFAULT;
 			}
 #ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length);
+			printk(KERN_DEBUG "%s (WE) : Got %d elem\n",
+			       dev->name, iwr->u.data.length);
 #endif	/* WE_IOCTL_DEBUG */
 		}
 
@@ -650,8 +729,8 @@
 			if (err)
 				ret =  -EFAULT;				   
 #ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "Wrote %d elem\n",
-			       iwr->u.data.length);
+			printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n",
+			       dev->name, iwr->u.data.length);
 #endif	/* WE_IOCTL_DEBUG */
 		}
 
@@ -731,3 +810,177 @@
 	/* Not reached */
 	return -EINVAL;
 }
+
+/************************* EVENT PROCESSING *************************/
+/*
+ * Process events generated by the wireless layer or the driver.
+ * Most often, the event will be propagated through rtnetlink
+ */
+
+#ifdef WE_EVENT_NETLINK
+/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here.
+ * It is declared in <linux/rtnetlink.h> */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Fill a rtnetlink message with our event data.
+ * Note that we propage only the specified event and don't dump the
+ * current wireless config. Dumping the wireless config is far too
+ * expensive (for each parameter, the driver need to query the hardware).
+ */
+static inline int rtnetlink_fill_iwinfo(struct sk_buff *	skb,
+					struct net_device *	dev,
+					int			type,
+					char *			event,
+					int			event_len)
+{
+	struct ifinfomsg *r;
+	struct nlmsghdr  *nlh;
+	unsigned char	 *b = skb->tail;
+
+	nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
+	r = NLMSG_DATA(nlh);
+	r->ifi_family = AF_UNSPEC;
+	r->ifi_type = dev->type;
+	r->ifi_index = dev->ifindex;
+	r->ifi_flags = dev->flags;
+	r->ifi_change = 0;	/* Wireless changes don't affect those flags */
+
+	/* Add the wireless events in the netlink packet */
+	RTA_PUT(skb, IFLA_WIRELESS,
+		event_len, event);
+
+	nlh->nlmsg_len = skb->tail - b;
+	return skb->len;
+
+nlmsg_failure:
+rtattr_failure:
+	skb_trim(skb, b - skb->data);
+	return -1;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Create and broadcast and send it on the standard rtnetlink socket
+ * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
+ * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
+ * within a RTM_NEWLINK event.
+ */
+static inline void rtmsg_iwinfo(struct net_device *	dev,
+				char *			event,
+				int			event_len)
+{
+	struct sk_buff *skb;
+	int size = NLMSG_GOODSIZE;
+
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		return;
+
+	if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
+				  event, event_len) < 0) {
+		kfree_skb(skb);
+		return;
+	}
+	NETLINK_CB(skb).dst_groups = RTMGRP_LINK;
+	netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC);
+}
+#endif	/* WE_EVENT_NETLINK */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Main event dispatcher. Called from other parts and drivers.
+ * Send the event on the apropriate channels.
+ * May be called from interrupt context.
+ */
+void wireless_send_event(struct net_device *	dev,
+			 unsigned int		cmd,
+			 union iwreq_data *	wrqu,
+			 char *			extra)
+{
+	const struct iw_ioctl_description *	descr = NULL;
+	int extra_len = 0;
+	struct iw_event  *event;		/* Mallocated whole event */
+	int event_len;				/* Its size */
+	int hdr_len;				/* Size of the event header */
+	/* Don't "optimise" the following variable, it will crash */
+	unsigned	cmd_index;		/* *MUST* be unsigned */
+
+	/* Get the description of the IOCTL */
+	if(cmd <= SIOCIWLAST) {
+		cmd_index = cmd - SIOCIWFIRST;
+		if(cmd_index < standard_ioctl_num)
+			descr = &(standard_ioctl[cmd_index]);
+	} else {
+		cmd_index = cmd - IWEVFIRST;
+		if(cmd_index < standard_event_num)
+			descr = &(standard_event[cmd_index]);
+	}
+	/* Don't accept unknown events */
+	if(descr == NULL) {
+		/* Note : we don't return an error to the driver, because
+		 * the driver would not know what to do about it. It can't
+		 * return an error to the user, because the event is not
+		 * initiated by a user request.
+		 * The best the driver could do is to log an error message.
+		 * We will do it ourselves instead...
+		 */
+	  	printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n",
+		       dev->name, cmd);
+		return;
+	}
+#ifdef WE_EVENT_DEBUG
+	printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n",
+	       dev->name, cmd);
+	printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
+#endif	/* WE_EVENT_DEBUG */
+
+	/* Check extra parameters and set extra_len */
+	if(descr->header_type == IW_HEADER_TYPE_POINT) {
+		/* Check if number of token fits within bounds */
+		if(wrqu->data.length > descr->max_tokens) {
+		  	printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
+			return;
+		}
+		if(wrqu->data.length < descr->min_tokens) {
+		  	printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
+			return;
+		}
+		/* Calculate extra_len - extra is NULL for restricted events */
+		if(extra != NULL)
+			extra_len = wrqu->data.length * descr->token_size;
+#ifdef WE_EVENT_DEBUG
+		printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len);
+#endif	/* WE_EVENT_DEBUG */
+	}
+
+	/* Total length of the event */
+	hdr_len = event_type_size[descr->header_type];
+	event_len = hdr_len + extra_len;
+
+#ifdef WE_EVENT_DEBUG
+	printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len);
+#endif	/* WE_EVENT_DEBUG */
+
+	/* Create temporary buffer to hold the event */
+	event = kmalloc(event_len, GFP_ATOMIC);
+	if(event == NULL)
+		return;
+
+	/* Fill event */
+	event->len = event_len;
+	event->cmd = cmd;
+	memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN);
+	if(extra != NULL)
+		memcpy(((char *) event) + hdr_len, extra, extra_len);
+
+#ifdef WE_EVENT_NETLINK
+	/* rtnetlink event channel */
+	rtmsg_iwinfo(dev, (char *) event, event_len);
+#endif	/* WE_EVENT_NETLINK */
+
+	/* Cleanup */
+	kfree(event);
+
+	return;		/* Always success, I guess ;-) */
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/decnet/af_decnet.c linux-2.4.20/net/decnet/af_decnet.c
--- linux-2.4.19/net/decnet/af_decnet.c	2001-12-21 17:42:05.000000000 +0000
+++ linux-2.4.20/net/decnet/af_decnet.c	2002-10-29 11:18:30.000000000 +0000
@@ -2234,7 +2234,7 @@
 MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
 #endif
 
-static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.15-pre5s (C) 1995-2001 Linux DECnet Project Team\n";
+static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.20-pre1s (C) 1995-2002 Linux DECnet Project Team\n";
 
 static int __init decnet_init(void)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/decnet/dn_route.c linux-2.4.20/net/decnet/dn_route.c
--- linux-2.4.19/net/decnet/dn_route.c	2001-12-21 17:42:05.000000000 +0000
+++ linux-2.4.20/net/decnet/dn_route.c	2002-10-29 11:18:50.000000000 +0000
@@ -35,6 +35,8 @@
  *                                 are numbered!
  *              Steve Whitehouse : Added return-to-sender functions. Added
  *                                 backlog congestion level return codes.
+ *		Steve Whitehouse : Fixed bug where routes were set up with
+ *                                 no ref count on net devices.
  *                                 
  */
 
@@ -801,6 +803,8 @@
 
 	rt->u.dst.neighbour = neigh;
 	rt->u.dst.dev = neigh ? neigh->dev : NULL;
+	if (rt->u.dst.dev)
+		dev_hold(rt->u.dst.dev);
 	rt->u.dst.lastuse = jiffies;
 	rt->u.dst.output = dn_output;
 	rt->u.dst.input  = dn_rt_bug;
@@ -978,6 +982,8 @@
 
 	rt->u.dst.neighbour = neigh;
 	rt->u.dst.dev = neigh ? neigh->dev : NULL;
+	if (rt->u.dst.dev)
+		dev_hold(rt->u.dst.dev);
 	rt->u.dst.lastuse = jiffies;
 	rt->u.dst.output = dnrt_output;
 	rt->u.dst.input = dnrt_input;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/arp.c linux-2.4.20/net/ipv4/arp.c
--- linux-2.4.19/net/ipv4/arp.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/arp.c	2002-10-29 11:18:36.000000000 +0000
@@ -513,7 +513,7 @@
 	skb->nh.raw = skb->data;
 	arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4));
 	skb->dev = dev;
-	skb->protocol = __constant_htons (ETH_P_ARP);
+	skb->protocol = htons (ETH_P_ARP);
 	if (src_hw == NULL)
 		src_hw = dev->dev_addr;
 	if (dest_hw == NULL)
@@ -539,33 +539,33 @@
 	switch (dev->type) {
 	default:
 		arp->ar_hrd = htons(dev->type);
-		arp->ar_pro = __constant_htons(ETH_P_IP);
+		arp->ar_pro = htons(ETH_P_IP);
 		break;
 
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 	case ARPHRD_AX25:
-		arp->ar_hrd = __constant_htons(ARPHRD_AX25);
-		arp->ar_pro = __constant_htons(AX25_P_IP);
+		arp->ar_hrd = htons(ARPHRD_AX25);
+		arp->ar_pro = htons(AX25_P_IP);
 		break;
 
 #if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
 	case ARPHRD_NETROM:
-		arp->ar_hrd = __constant_htons(ARPHRD_NETROM);
-		arp->ar_pro = __constant_htons(AX25_P_IP);
+		arp->ar_hrd = htons(ARPHRD_NETROM);
+		arp->ar_pro = htons(AX25_P_IP);
 		break;
 #endif
 #endif
 
 #ifdef CONFIG_FDDI
 	case ARPHRD_FDDI:
-		arp->ar_hrd = __constant_htons(ARPHRD_ETHER);
-		arp->ar_pro = __constant_htons(ETH_P_IP);
+		arp->ar_hrd = htons(ARPHRD_ETHER);
+		arp->ar_pro = htons(ETH_P_IP);
 		break;
 #endif
 #ifdef CONFIG_TR
 	case ARPHRD_IEEE802_TR:
-		arp->ar_hrd = __constant_htons(ARPHRD_IEEE802);
-		arp->ar_pro = __constant_htons(ETH_P_IP);
+		arp->ar_hrd = htons(ARPHRD_IEEE802);
+		arp->ar_pro = htons(ETH_P_IP);
 		break;
 #endif
 	}
@@ -629,7 +629,7 @@
 
 	switch (dev_type) {
 	default:	
-		if (arp->ar_pro != __constant_htons(ETH_P_IP))
+		if (arp->ar_pro != htons(ETH_P_IP))
 			goto out;
 		if (htons(dev_type) != arp->ar_hrd)
 			goto out;
@@ -640,10 +640,10 @@
 		 * ETHERNET devices will accept ARP hardware types of either
 		 * 1 (Ethernet) or 6 (IEEE 802.2).
 		 */
-		if (arp->ar_hrd != __constant_htons(ARPHRD_ETHER) &&
-		    arp->ar_hrd != __constant_htons(ARPHRD_IEEE802))
+		if (arp->ar_hrd != htons(ARPHRD_ETHER) &&
+		    arp->ar_hrd != htons(ARPHRD_IEEE802))
 			goto out;
-		if (arp->ar_pro != __constant_htons(ETH_P_IP))
+		if (arp->ar_pro != htons(ETH_P_IP))
 			goto out;
 		break;
 #endif
@@ -653,10 +653,10 @@
 		 * Token ring devices will accept ARP hardware types of either
 		 * 1 (Ethernet) or 6 (IEEE 802.2).
 		 */
-		if (arp->ar_hrd != __constant_htons(ARPHRD_ETHER) &&
-		    arp->ar_hrd != __constant_htons(ARPHRD_IEEE802))
+		if (arp->ar_hrd != htons(ARPHRD_ETHER) &&
+		    arp->ar_hrd != htons(ARPHRD_IEEE802))
 			goto out;
-		if (arp->ar_pro != __constant_htons(ETH_P_IP))
+		if (arp->ar_pro != htons(ETH_P_IP))
 			goto out;
 		break;
 #endif
@@ -667,10 +667,10 @@
 		 * of 1 (Ethernet).  However, to be more robust, we'll accept hardware
 		 * types of either 1 (Ethernet) or 6 (IEEE 802.2).
 		 */
-		if (arp->ar_hrd != __constant_htons(ARPHRD_ETHER) &&
-		    arp->ar_hrd != __constant_htons(ARPHRD_IEEE802))
+		if (arp->ar_hrd != htons(ARPHRD_ETHER) &&
+		    arp->ar_hrd != htons(ARPHRD_IEEE802))
 			goto out;
-		if (arp->ar_pro != __constant_htons(ETH_P_IP))
+		if (arp->ar_pro != htons(ETH_P_IP))
 			goto out;
 		break;
 #endif
@@ -681,25 +681,25 @@
 		 * 802 devices) should accept ARP hardware types of 6 (IEEE 802)
 		 * and 1 (Ethernet).
 		 */
-		if (arp->ar_hrd != __constant_htons(ARPHRD_ETHER) &&
-		    arp->ar_hrd != __constant_htons(ARPHRD_IEEE802))
+		if (arp->ar_hrd != htons(ARPHRD_ETHER) &&
+		    arp->ar_hrd != htons(ARPHRD_IEEE802))
 			goto out;
-		if (arp->ar_pro != __constant_htons(ETH_P_IP))
+		if (arp->ar_pro != htons(ETH_P_IP))
 			goto out;
 		break;
 #endif
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 	case ARPHRD_AX25:
-		if (arp->ar_pro != __constant_htons(AX25_P_IP))
+		if (arp->ar_pro != htons(AX25_P_IP))
 			goto out;
-		if (arp->ar_hrd != __constant_htons(ARPHRD_AX25))
+		if (arp->ar_hrd != htons(ARPHRD_AX25))
 			goto out;
 		break;
 #if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
 	case ARPHRD_NETROM:
-		if (arp->ar_pro != __constant_htons(AX25_P_IP))
+		if (arp->ar_pro != htons(AX25_P_IP))
 			goto out;
-		if (arp->ar_hrd != __constant_htons(ARPHRD_NETROM))
+		if (arp->ar_hrd != htons(ARPHRD_NETROM))
 			goto out;
 		break;
 #endif
@@ -708,8 +708,8 @@
 
 	/* Understand only these message types */
 
-	if (arp->ar_op != __constant_htons(ARPOP_REPLY) &&
-	    arp->ar_op != __constant_htons(ARPOP_REQUEST))
+	if (arp->ar_op != htons(ARPOP_REPLY) &&
+	    arp->ar_op != htons(ARPOP_REQUEST))
 		goto out;
 
 /*
@@ -754,13 +754,13 @@
 
 	/* Special case: IPv4 duplicate address detection packet (RFC2131) */
 	if (sip == 0) {
-		if (arp->ar_op == __constant_htons(ARPOP_REQUEST) &&
+		if (arp->ar_op == htons(ARPOP_REQUEST) &&
 		    inet_addr_type(tip) == RTN_LOCAL)
 			arp_send(ARPOP_REPLY,ETH_P_ARP,tip,dev,tip,sha,dev->dev_addr,dev->dev_addr);
 		goto out;
 	}
 
-	if (arp->ar_op == __constant_htons(ARPOP_REQUEST) &&
+	if (arp->ar_op == htons(ARPOP_REQUEST) &&
 	    ip_route_input(skb, tip, sip, 0, dev) == 0) {
 
 		rt = (struct rtable*)skb->dst;
@@ -810,7 +810,7 @@
 	   devices (strip is candidate)
 	 */
 	if (n == NULL &&
-	    arp->ar_op == __constant_htons(ARPOP_REPLY) &&
+	    arp->ar_op == htons(ARPOP_REPLY) &&
 	    inet_addr_type(sip) == RTN_UNICAST)
 		n = __neigh_lookup(&arp_tbl, &sip, dev, -1);
 #endif
@@ -830,7 +830,7 @@
 		/* Broadcast replies and request packets
 		   do not assert neighbour reachability.
 		 */
-		if (arp->ar_op != __constant_htons(ARPOP_REPLY) ||
+		if (arp->ar_op != htons(ARPOP_REPLY) ||
 		    skb->pkt_type != PACKET_HOST)
 			state = NUD_STALE;
 		neigh_update(n, sha, state, override, 1);
@@ -1050,7 +1050,7 @@
 	    (r.arp_flags & (ATF_NETMASK|ATF_DONTPUB)))
 		return -EINVAL;
 	if (!(r.arp_flags & ATF_NETMASK))
-		((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr=__constant_htonl(0xFFFFFFFFUL);
+		((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr=htonl(0xFFFFFFFFUL);
 
 	rtnl_lock();
 	if (r.arp_dev[0]) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/igmp.c linux-2.4.20/net/ipv4/igmp.c
--- linux-2.4.19/net/ipv4/igmp.c	2001-07-28 19:12:38.000000000 +0000
+++ linux-2.4.20/net/ipv4/igmp.c	2002-10-29 11:18:40.000000000 +0000
@@ -229,7 +229,7 @@
 	iph->version  = 4;
 	iph->ihl      = (sizeof(struct iphdr)+4)>>2;
 	iph->tos      = 0;
-	iph->frag_off = __constant_htons(IP_DF);
+	iph->frag_off = htons(IP_DF);
 	iph->ttl      = 1;
 	iph->daddr    = dst;
 	iph->saddr    = rt->rt_src;
@@ -530,9 +530,8 @@
  *	A socket has left a multicast group on device dev
  */
 
-int ip_mc_dec_group(struct in_device *in_dev, u32 addr)
+void ip_mc_dec_group(struct in_device *in_dev, u32 addr)
 {
-	int err = -ESRCH;
 	struct ip_mc_list *i, **ip;
 	
 	ASSERT_RTNL();
@@ -549,13 +548,11 @@
 					ip_rt_multicast_event(in_dev);
 
 				ip_ma_put(i);
-				return 0;
+				return;
 			}
-			err = 0;
 			break;
 		}
 	}
-	return -ESRCH;
 }
 
 /* Device going down */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/ip_gre.c linux-2.4.20/net/ipv4/ip_gre.c
--- linux-2.4.19/net/ipv4/ip_gre.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/ip_gre.c	2002-10-29 11:18:49.000000000 +0000
@@ -412,7 +412,7 @@
 	struct sk_buff *skb2;
 	struct rtable *rt;
 
-	if (p[1] != __constant_htons(ETH_P_IP))
+	if (p[1] != htons(ETH_P_IP))
 		return;
 
 	flags = p[0];
@@ -535,10 +535,10 @@
 static inline void ipgre_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
 {
 	if (INET_ECN_is_ce(iph->tos)) {
-		if (skb->protocol == __constant_htons(ETH_P_IP)) {
+		if (skb->protocol == htons(ETH_P_IP)) {
 			if (INET_ECN_is_not_ce(skb->nh.iph->tos))
 				IP_ECN_set_ce(skb->nh.iph);
-		} else if (skb->protocol == __constant_htons(ETH_P_IPV6)) {
+		} else if (skb->protocol == htons(ETH_P_IPV6)) {
 			if (INET_ECN_is_not_ce(ip6_get_dsfield(skb->nh.ipv6h)))
 				IP6_ECN_set_ce(skb->nh.ipv6h);
 		}
@@ -549,9 +549,9 @@
 ipgre_ecn_encapsulate(u8 tos, struct iphdr *old_iph, struct sk_buff *skb)
 {
 	u8 inner = 0;
-	if (skb->protocol == __constant_htons(ETH_P_IP))
+	if (skb->protocol == htons(ETH_P_IP))
 		inner = old_iph->tos;
-	else if (skb->protocol == __constant_htons(ETH_P_IPV6))
+	else if (skb->protocol == htons(ETH_P_IPV6))
 		inner = ip6_get_dsfield((struct ipv6hdr*)old_iph);
 	return INET_ECN_encapsulate(tos, inner);
 }
@@ -708,13 +708,13 @@
 			goto tx_error;
 		}
 
-		if (skb->protocol == __constant_htons(ETH_P_IP)) {
+		if (skb->protocol == htons(ETH_P_IP)) {
 			rt = (struct rtable*)skb->dst;
 			if ((dst = rt->rt_gateway) == 0)
 				goto tx_error_icmp;
 		}
 #ifdef CONFIG_IPV6
-		else if (skb->protocol == __constant_htons(ETH_P_IPV6)) {
+		else if (skb->protocol == htons(ETH_P_IPV6)) {
 			struct in6_addr *addr6;
 			int addr_type;
 			struct neighbour *neigh = skb->dst->neighbour;
@@ -742,7 +742,7 @@
 
 	tos = tiph->tos;
 	if (tos&1) {
-		if (skb->protocol == __constant_htons(ETH_P_IP))
+		if (skb->protocol == htons(ETH_P_IP))
 			tos = old_iph->tos;
 		tos &= ~1;
 	}
@@ -765,13 +765,13 @@
 	else
 		mtu = skb->dst ? skb->dst->pmtu : dev->mtu;
 
-	if (skb->protocol == __constant_htons(ETH_P_IP)) {
+	if (skb->protocol == htons(ETH_P_IP)) {
 		if (skb->dst && mtu < skb->dst->pmtu && mtu >= 68)
 			skb->dst->pmtu = mtu;
 
-		df |= (old_iph->frag_off&__constant_htons(IP_DF));
+		df |= (old_iph->frag_off&htons(IP_DF));
 
-		if ((old_iph->frag_off&__constant_htons(IP_DF)) &&
+		if ((old_iph->frag_off&htons(IP_DF)) &&
 		    mtu < ntohs(old_iph->tot_len)) {
 			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
 			ip_rt_put(rt);
@@ -779,7 +779,7 @@
 		}
 	}
 #ifdef CONFIG_IPV6
-	else if (skb->protocol == __constant_htons(ETH_P_IPV6)) {
+	else if (skb->protocol == htons(ETH_P_IPV6)) {
 		struct rt6_info *rt6 = (struct rt6_info*)skb->dst;
 
 		if (rt6 && mtu < rt6->u.dst.pmtu && mtu >= IPV6_MIN_MTU) {
@@ -845,10 +845,10 @@
 	iph->saddr		=	rt->rt_src;
 
 	if ((iph->ttl = tiph->ttl) == 0) {
-		if (skb->protocol == __constant_htons(ETH_P_IP))
+		if (skb->protocol == htons(ETH_P_IP))
 			iph->ttl = old_iph->ttl;
 #ifdef CONFIG_IPV6
-		else if (skb->protocol == __constant_htons(ETH_P_IPV6))
+		else if (skb->protocol == htons(ETH_P_IPV6))
 			iph->ttl = ((struct ipv6hdr*)old_iph)->hop_limit;
 #endif
 		else
@@ -936,11 +936,11 @@
 
 		err = -EINVAL;
 		if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE ||
-		    p.iph.ihl != 5 || (p.iph.frag_off&__constant_htons(~IP_DF)) ||
+		    p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)) ||
 		    ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING)))
 			goto done;
 		if (p.iph.ttl)
-			p.iph.frag_off |= __constant_htons(IP_DF);
+			p.iph.frag_off |= htons(IP_DF);
 
 		if (!(p.i_flags&GRE_KEY))
 			p.i_key = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/ip_options.c linux-2.4.20/net/ipv4/ip_options.c
--- linux-2.4.19/net/ipv4/ip_options.c	2001-09-07 18:01:21.000000000 +0000
+++ linux-2.4.20/net/ipv4/ip_options.c	2002-10-29 11:18:33.000000000 +0000
@@ -266,7 +266,7 @@
 	for (l = opt->optlen; l > 0; ) {
 		switch (*optptr) {
 		      case IPOPT_END:
-			for (optptr++, l--; l>0; l--) {
+			for (optptr++, l--; l>0; optptr++, l--) {
 				if (*optptr != IPOPT_END) {
 					*optptr = IPOPT_END;
 					opt->is_changed = 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/ip_output.c linux-2.4.20/net/ipv4/ip_output.c
--- linux-2.4.19/net/ipv4/ip_output.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/ip_output.c	2002-10-29 11:18:40.000000000 +0000
@@ -186,7 +186,7 @@
 	struct net_device *dev = skb->dst->dev;
 
 	skb->dev = dev;
-	skb->protocol = __constant_htons(ETH_P_IP);
+	skb->protocol = htons(ETH_P_IP);
 
 	return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
 		       ip_finish_output2);
@@ -208,7 +208,7 @@
 #endif
 
 	skb->dev = dev;
-	skb->protocol = __constant_htons(ETH_P_IP);
+	skb->protocol = htons(ETH_P_IP);
 
 	/*
 	 *	Multicasts are looped back for other local users
@@ -382,7 +382,7 @@
 	*((__u16 *)iph)	= htons((4 << 12) | (5 << 8) | (sk->protinfo.af_inet.tos & 0xff));
 	iph->tot_len = htons(skb->len);
 	if (ip_dont_fragment(sk, &rt->u.dst))
-		iph->frag_off = __constant_htons(IP_DF);
+		iph->frag_off = htons(IP_DF);
 	else
 		iph->frag_off = 0;
 	iph->ttl      = sk->protinfo.af_inet.ttl;
@@ -520,8 +520,18 @@
 		/*
 		 *	Get the memory we require with some space left for alignment.
 		 */
-
-		skb = sock_alloc_send_skb(sk, fraglen+hh_len+15, flags&MSG_DONTWAIT, &err);
+		if (!(flags & MSG_DONTWAIT) || nfrags == 0) {
+			skb = sock_alloc_send_skb(sk, fraglen + hh_len + 15,
+						  (flags & MSG_DONTWAIT), &err);
+		} else {
+			/* On a non-blocking write, we check for send buffer
+			 * usage on the first fragment only.
+			 */
+			skb = sock_wmalloc(sk, fraglen + hh_len + 15, 1,
+					   sk->allocation);
+			if (!skb)
+				err = -ENOBUFS;
+		}
 		if (skb == NULL)
 			goto error;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/ipconfig.c linux-2.4.20/net/ipv4/ipconfig.c
--- linux-2.4.19/net/ipv4/ipconfig.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/ipconfig.c	2002-10-29 11:18:32.000000000 +0000
@@ -26,6 +26,9 @@
  *
  *  Merged changes from 2.2.19 into 2.4.3
  *              -- Eric Biederman <ebiederman@lnxi.com>, 22 April Aug 2001
+ *
+ *  Multipe Nameservers in /proc/net/pnp
+ *              --  Josef Siemes <jsiemes@web.de>, Aug 2002
  */
 
 #include <linux/config.h>
@@ -90,6 +93,8 @@
 #define CONF_TIMEOUT_RANDOM	(HZ)	/* Maximum amount of randomization */
 #define CONF_TIMEOUT_MULT	*7/4	/* Rate of timeout growth */
 #define CONF_TIMEOUT_MAX	(HZ*30)	/* Maximum allowed timeout */
+#define CONF_NAMESERVERS_MAX   3       /* Maximum number of nameservers  
+                                           - '3' from resolv.h */
 
 
 /*
@@ -131,7 +136,7 @@
 /* Persistent data: */
 
 int ic_proto_used;			/* Protocol used, if any */
-u32 ic_nameserver = INADDR_NONE;	/* DNS Server IP address */
+u32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */
 u8 ic_domain[64];		/* DNS (not NIS) domain name */
 
 /*
@@ -356,11 +361,11 @@
 
 	if (ic_netmask == INADDR_NONE) {
 		if (IN_CLASSA(ntohl(ic_myaddr)))
-			ic_netmask = __constant_htonl(IN_CLASSA_NET);
+			ic_netmask = htonl(IN_CLASSA_NET);
 		else if (IN_CLASSB(ntohl(ic_myaddr)))
-			ic_netmask = __constant_htonl(IN_CLASSB_NET);
+			ic_netmask = htonl(IN_CLASSB_NET);
 		else if (IN_CLASSC(ntohl(ic_myaddr)))
-			ic_netmask = __constant_htonl(IN_CLASSC_NET);
+			ic_netmask = htonl(IN_CLASSC_NET);
 		else {
 			printk(KERN_ERR "IP-Config: Unable to guess netmask for address %u.%u.%u.%u\n",
 				NIPQUAD(ic_myaddr));
@@ -426,11 +431,11 @@
 		goto drop;
 
 	/* If it's not a RARP reply, delete it. */
-	if (rarp->ar_op != __constant_htons(ARPOP_RREPLY))
+	if (rarp->ar_op != htons(ARPOP_RREPLY))
 		goto drop;
 
 	/* If it's not Ethernet, delete it. */
-	if (rarp->ar_pro != __constant_htons(ETH_P_IP))
+	if (rarp->ar_pro != htons(ETH_P_IP))
 		goto drop;
 
 	/* Extract variable-width fields */
@@ -468,7 +473,7 @@
 
 
 /*
- *  Send RARP request packet over a signle interface.
+ *  Send RARP request packet over a single interface.
  */
 static void __init ic_rarp_send_if(struct ic_device *d)
 {
@@ -624,6 +629,11 @@
  */
 static inline void ic_bootp_init(void)
 {
+	int i;
+
+	for (i = 0; i < CONF_NAMESERVERS_MAX; i++)
+		ic_nameservers[i] = INADDR_NONE;
+
 	dev_add_pack(&bootp_packet_type);
 }
 
@@ -661,15 +671,15 @@
 	h->version = 4;
 	h->ihl = 5;
 	h->tot_len = htons(sizeof(struct bootp_pkt));
-	h->frag_off = __constant_htons(IP_DF);
+	h->frag_off = htons(IP_DF);
 	h->ttl = 64;
 	h->protocol = IPPROTO_UDP;
 	h->daddr = INADDR_BROADCAST;
 	h->check = ip_fast_csum((unsigned char *) h, h->ihl);
 
 	/* Construct UDP header */
-	b->udph.source = __constant_htons(68);
-	b->udph.dest = __constant_htons(67);
+	b->udph.source = htons(68);
+	b->udph.dest = htons(67);
 	b->udph.len = htons(sizeof(struct bootp_pkt) - sizeof(struct iphdr));
 	/* UDP checksum not calculated -- explicitly allowed in BOOTP RFC */
 
@@ -700,7 +710,7 @@
 
 	/* Chain packet down the line... */
 	skb->dev = dev;
-	skb->protocol = __constant_htons(ETH_P_IP);
+	skb->protocol = htons(ETH_P_IP);
 	if ((dev->hard_header &&
 	     dev->hard_header(skb, dev, ntohs(skb->protocol), dev->broadcast, dev->dev_addr, skb->len) < 0) ||
 	    dev_queue_xmit(skb) < 0)
@@ -728,6 +738,9 @@
  */
 static void __init ic_do_bootp_ext(u8 *ext)
 {
+	u8 servers;
+	int i;
+
 #ifdef IPCONFIG_DEBUG
 	u8 *c;
 
@@ -747,8 +760,13 @@
 				memcpy(&ic_gateway, ext+1, 4);
 			break;
 		case 6:		/* DNS server */
-			if (ic_nameserver == INADDR_NONE)
-				memcpy(&ic_nameserver, ext+1, 4);
+			servers= *ext/4;
+			if (servers > CONF_NAMESERVERS_MAX)
+				servers = CONF_NAMESERVERS_MAX;
+			for (i = 0; i < servers; i++) {
+				if (ic_nameservers[i] == INADDR_NONE)
+					memcpy(&ic_nameservers[i], ext+1+4*i, 4);
+			}
 			break;
 		case 12:	/* Host name */
 			ic_bootp_string(system_utsname.nodename, ext+1, *ext, __NEW_UTS_LEN);
@@ -800,13 +818,13 @@
 	    ip_fast_csum((char *) h, h->ihl) != 0 ||
 	    skb->len < ntohs(h->tot_len) ||
 	    h->protocol != IPPROTO_UDP ||
-	    b->udph.source != __constant_htons(67) ||
-	    b->udph.dest != __constant_htons(68) ||
+	    b->udph.source != htons(67) ||
+	    b->udph.dest != htons(68) ||
 	    ntohs(h->tot_len) < ntohs(b->udph.len) + sizeof(struct iphdr))
 		goto drop;
 
 	/* Fragments are not supported */
-	if (h->frag_off & __constant_htons(IP_OFFSET | IP_MF)) {
+	if (h->frag_off & htons(IP_OFFSET | IP_MF)) {
 		printk(KERN_ERR "DHCP/BOOTP: Ignoring fragmented reply.\n");
 		goto drop;
 	}
@@ -913,8 +931,8 @@
 	ic_servaddr = b->server_ip;
 	if (ic_gateway == INADDR_NONE && b->relay_ip)
 		ic_gateway = b->relay_ip;
-	if (ic_nameserver == INADDR_NONE)
-		ic_nameserver = ic_servaddr;
+	if (ic_nameservers[0] == INADDR_NONE)
+		ic_nameservers[0] = ic_servaddr;
 	ic_got_reply = IC_BOOTP;
 
 drop:
@@ -1077,6 +1095,7 @@
 			off_t offset, int length)
 {
 	int len;
+	int i;
 
 	if (ic_proto_used & IC_PROTO)
 	    sprintf(buffer, "#PROTO: %s\n",
@@ -1089,9 +1108,12 @@
 	if (ic_domain[0])
 		len += sprintf(buffer + len,
 			       "domain %s\n", ic_domain);
-	if (ic_nameserver != INADDR_NONE)
-		len += sprintf(buffer + len,
-			       "nameserver %u.%u.%u.%u\n", NIPQUAD(ic_nameserver));
+	for (i = 0; i < CONF_NAMESERVERS_MAX; i++) {
+		if (ic_nameservers[i] != INADDR_NONE)
+			len += sprintf(buffer + len,
+				       "nameserver %u.%u.%u.%u\n",
+				       NIPQUAD(ic_nameservers[i]));
+	}
 
 	if (offset > len)
 		offset = len;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/ipip.c linux-2.4.20/net/ipv4/ipip.c
--- linux-2.4.19/net/ipv4/ipip.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/ipip.c	2002-10-29 11:18:48.000000000 +0000
@@ -483,7 +483,7 @@
 	skb->mac.raw = skb->nh.raw;
 	skb->nh.raw = skb->data;
 	memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
-	skb->protocol = __constant_htons(ETH_P_IP);
+	skb->protocol = htons(ETH_P_IP);
 	skb->pkt_type = PACKET_HOST;
 
 	read_lock(&ipip_lock);
@@ -544,7 +544,7 @@
 		goto tx_error;
 	}
 
-	if (skb->protocol != __constant_htons(ETH_P_IP))
+	if (skb->protocol != htons(ETH_P_IP))
 		goto tx_error;
 
 	if (tos&1)
@@ -585,9 +585,9 @@
 	if (skb->dst && mtu < skb->dst->pmtu)
 		skb->dst->pmtu = mtu;
 
-	df |= (old_iph->frag_off&__constant_htons(IP_DF));
+	df |= (old_iph->frag_off&htons(IP_DF));
 
-	if ((old_iph->frag_off&__constant_htons(IP_DF)) && mtu < ntohs(old_iph->tot_len)) {
+	if ((old_iph->frag_off&htons(IP_DF)) && mtu < ntohs(old_iph->tot_len)) {
 		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
 		ip_rt_put(rt);
 		goto tx_error;
@@ -703,10 +703,10 @@
 
 		err = -EINVAL;
 		if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPIP ||
-		    p.iph.ihl != 5 || (p.iph.frag_off&__constant_htons(~IP_DF)))
+		    p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
 			goto done;
 		if (p.iph.ttl)
-			p.iph.frag_off |= __constant_htons(IP_DF);
+			p.iph.frag_off |= htons(IP_DF);
 
 		t = ipip_tunnel_locate(&p, cmd == SIOCADDTUNNEL);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/ipmr.c linux-2.4.20/net/ipv4/ipmr.c
--- linux-2.4.19/net/ipv4/ipmr.c	2001-12-21 17:42:05.000000000 +0000
+++ linux-2.4.20/net/ipv4/ipmr.c	2002-10-29 11:18:40.000000000 +0000
@@ -1434,7 +1434,7 @@
 	skb->nh.iph = (struct iphdr *)skb->data;
 	skb->dev = reg_dev;
 	memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
-	skb->protocol = __constant_htons(ETH_P_IP);
+	skb->protocol = htons(ETH_P_IP);
 	skb->ip_summed = 0;
 	skb->pkt_type = PACKET_HOST;
 	dst_release(skb->dst);
@@ -1501,7 +1501,7 @@
 	skb->nh.iph = (struct iphdr *)skb->data;
 	skb->dev = reg_dev;
 	memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
-	skb->protocol = __constant_htons(ETH_P_IP);
+	skb->protocol = htons(ETH_P_IP);
 	skb->ip_summed = 0;
 	skb->pkt_type = PACKET_HOST;
 	dst_release(skb->dst);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/Config.in linux-2.4.20/net/ipv4/netfilter/Config.in
--- linux-2.4.19/net/ipv4/netfilter/Config.in	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/Config.in	2002-10-29 11:18:40.000000000 +0000
@@ -18,15 +18,24 @@
 # The simple matches.
   dep_tristate '  limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES
   dep_tristate '  MAC address match support' CONFIG_IP_NF_MATCH_MAC $CONFIG_IP_NF_IPTABLES
+  dep_tristate '  Packet type match support' CONFIG_IP_NF_MATCH_PKTTYPE $CONFIG_IP_NF_IPTABLES
   dep_tristate '  netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
   dep_tristate '  Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
+  dep_tristate '  ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES
+ 
+  dep_tristate '  DSCP match support' CONFIG_IP_NF_MATCH_DSCP $CONFIG_IP_NF_IPTABLES
+ 
   dep_tristate '  AH/ESP match support' CONFIG_IP_NF_MATCH_AH_ESP $CONFIG_IP_NF_IPTABLES
   dep_tristate '  LENGTH match support' CONFIG_IP_NF_MATCH_LENGTH $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TTL match support' CONFIG_IP_NF_MATCH_TTL $CONFIG_IP_NF_IPTABLES
   dep_tristate '  tcpmss match support' CONFIG_IP_NF_MATCH_TCPMSS $CONFIG_IP_NF_IPTABLES
   if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
+    dep_tristate '  Helper match support' CONFIG_IP_NF_MATCH_HELPER $CONFIG_IP_NF_IPTABLES
+  fi
+  if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
     dep_tristate '  Connection state match support' CONFIG_IP_NF_MATCH_STATE $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES 
+    dep_tristate '  Connection tracking match support' CONFIG_IP_NF_MATCH_CONNTRACK $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES 
   fi
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
     dep_tristate '  Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES
@@ -73,6 +82,10 @@
   dep_tristate '  Packet mangling' CONFIG_IP_NF_MANGLE $CONFIG_IP_NF_IPTABLES 
   if [ "$CONFIG_IP_NF_MANGLE" != "n" ]; then
     dep_tristate '    TOS target support' CONFIG_IP_NF_TARGET_TOS $CONFIG_IP_NF_MANGLE
+    dep_tristate '    ECN target support' CONFIG_IP_NF_TARGET_ECN $CONFIG_IP_NF_MANGLE
+ 
+    dep_tristate '    DSCP target support' CONFIG_IP_NF_TARGET_DSCP $CONFIG_IP_NF_MANGLE
+ 
     dep_tristate '    MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
   fi
   dep_tristate '  LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/Makefile linux-2.4.20/net/ipv4/netfilter/Makefile
--- linux-2.4.19/net/ipv4/netfilter/Makefile	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/Makefile	2002-10-29 11:18:34.000000000 +0000
@@ -9,18 +9,18 @@
 
 O_TARGET := netfilter.o
 
-export-objs = ip_conntrack_standalone.o ip_conntrack_ftp.o ip_fw_compat.o ip_nat_standalone.o ip_tables.o arp_tables.o
+export-objs = ip_conntrack_standalone.o ip_fw_compat.o ip_nat_standalone.o ip_tables.o arp_tables.o
 
 # Multipart objects.
 list-multi		:= ip_conntrack.o iptable_nat.o ipfwadm.o ipchains.o
 
 # objects for the conntrack and NAT core (used by standalone and backw. compat)
 ip_nf_conntrack-objs	:= ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o
-ip_nf_nat-objs		:= ip_nat_core.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
+ip_nf_nat-objs		:= ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
 
 # objects for the standalone - connection tracking / NAT
 ip_conntrack-objs	:= ip_conntrack_standalone.o $(ip_nf_conntrack-objs)
-iptable_nat-objs	:= ip_nat_standalone.o ip_nat_rule.o ip_nat_helper.o $(ip_nf_nat-objs)
+iptable_nat-objs	:= ip_nat_standalone.o ip_nat_rule.o $(ip_nf_nat-objs)
 
 # objects for backwards compatibility mode
 ip_nf_compat-objs	:= ip_fw_compat.o ip_fw_compat_redir.o ip_fw_compat_masq.o $(ip_nf_conntrack-objs) $(ip_nf_nat-objs)
@@ -33,7 +33,14 @@
 
 # connection tracking helpers
 obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
+ifdef CONFIG_IP_NF_NAT_FTP
+	export-objs += ip_conntrack_ftp.o
+endif
+
 obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
+ifdef CONFIG_IP_NF_NAT_IRC
+	export-objs += ip_conntrack_irc.o
+endif
 
 # NAT helpers 
 obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
@@ -48,18 +55,24 @@
 obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
 
 # matches
+obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
 obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
 obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
 obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
+
+obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
 obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
+obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
+obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o
 obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
 
 obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
 
 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
 obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
+obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
 obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
 obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
 
@@ -67,6 +80,8 @@
 obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
 obj-$(CONFIG_IP_NF_TARGET_MIRROR) += ipt_MIRROR.o
 obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o
+obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
+obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o
 obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
 obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.4.19/net/ipv4/netfilter/ip_conntrack_core.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_core.c	2002-10-29 11:18:30.000000000 +0000
@@ -3,7 +3,15 @@
    extension. */
 
 /* (c) 1999 Paul `Rusty' Russell.  Licenced under the GNU General
-   Public Licence. */
+ * Public Licence. 
+ *
+ * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
+ * 	- new API and handling of conntrack/nat helpers
+ * 	- now capable of multiple expectations for one master
+ * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
+ * 	- add usage/reference counts to ip_conntrack_expect
+ *	- export ip_conntrack[_expect]_{find_get,put} functions
+ * */
 
 #ifdef MODULE
 #define __NO_VERSION__
@@ -37,6 +45,8 @@
 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
 #include <linux/netfilter_ipv4/listhelp.h>
 
+#define IP_CONNTRACK_VERSION	"2.1"
+
 #if 0
 #define DEBUGP printk
 #else
@@ -44,9 +54,10 @@
 #endif
 
 DECLARE_RWLOCK(ip_conntrack_lock);
+DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
 
 void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
-LIST_HEAD(expect_list);
+LIST_HEAD(ip_conntrack_expect_list);
 LIST_HEAD(protocol_list);
 static LIST_HEAD(helpers);
 unsigned int ip_conntrack_htable_size = 0;
@@ -63,7 +74,7 @@
 	return protocol == curr->proto;
 }
 
-struct ip_conntrack_protocol *__find_proto(u_int8_t protocol)
+struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol)
 {
 	struct ip_conntrack_protocol *p;
 
@@ -76,17 +87,18 @@
 	return p;
 }
 
-struct ip_conntrack_protocol *find_proto(u_int8_t protocol)
+struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
 {
 	struct ip_conntrack_protocol *p;
 
 	READ_LOCK(&ip_conntrack_lock);
-	p = __find_proto(protocol);
+	p = __ip_ct_find_proto(protocol);
 	READ_UNLOCK(&ip_conntrack_lock);
 	return p;
 }
 
-static inline void ip_conntrack_put(struct ip_conntrack *ct)
+inline void 
+ip_conntrack_put(struct ip_conntrack *ct)
 {
 	IP_NF_ASSERT(ct);
 	IP_NF_ASSERT(ct->infos[0].master);
@@ -150,9 +162,135 @@
 	return protocol->invert_tuple(inverse, orig);
 }
 
+
+/* ip_conntrack_expect helper functions */
+
+/* Compare tuple parts depending on mask. */
+static inline int expect_cmp(const struct ip_conntrack_expect *i,
+			     const struct ip_conntrack_tuple *tuple)
+{
+	MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
+	return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
+}
+
+static void
+destroy_expect(struct ip_conntrack_expect *exp)
+{
+	DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(exp->use));
+	IP_NF_ASSERT(atomic_read(exp->use));
+	IP_NF_ASSERT(!timer_pending(&exp->timeout));
+
+	kfree(exp);
+}
+
+
+inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
+{
+	IP_NF_ASSERT(exp);
+
+	if (atomic_dec_and_test(&exp->use)) {
+		/* usage count dropped to zero */
+		destroy_expect(exp);
+	}
+}
+
+static inline struct ip_conntrack_expect *
+__ip_ct_expect_find(const struct ip_conntrack_tuple *tuple)
+{
+	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
+	MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
+	return LIST_FIND(&ip_conntrack_expect_list, expect_cmp, 
+			 struct ip_conntrack_expect *, tuple);
+}
+
+/* Find a expectation corresponding to a tuple. */
+struct ip_conntrack_expect *
+ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
+{
+	struct ip_conntrack_expect *exp;
+
+	READ_LOCK(&ip_conntrack_lock);
+	READ_LOCK(&ip_conntrack_expect_tuple_lock);
+	exp = __ip_ct_expect_find(tuple);
+	if (exp)
+		atomic_inc(&exp->use);
+	READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
+	READ_UNLOCK(&ip_conntrack_lock);
+
+	return exp;
+}
+
+/* remove one specific expectation from all lists and drop refcount,
+ * does _NOT_ delete the timer. */
+static void __unexpect_related(struct ip_conntrack_expect *expect)
+{
+	DEBUGP("unexpect_related(%p)\n", expect);
+	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
+
+	/* we're not allowed to unexpect a confirmed expectation! */
+	IP_NF_ASSERT(!expect->sibling);
+
+	/* delete from global and local lists */
+	list_del(&expect->list);
+	list_del(&expect->expected_list);
+
+	/* decrement expect-count of master conntrack */
+	if (expect->expectant)
+		expect->expectant->expecting--;
+
+	ip_conntrack_expect_put(expect);
+}
+
+/* remove one specific expecatation from all lists, drop refcount
+ * and expire timer. 
+ * This function can _NOT_ be called for confirmed expects! */
+static void unexpect_related(struct ip_conntrack_expect *expect)
+{
+	IP_NF_ASSERT(expect->expectant);
+	IP_NF_ASSERT(expect->expectant->helper);
+	/* if we are supposed to have a timer, but we can't delete
+	 * it: race condition.  __unexpect_related will
+	 * be calledd by timeout function */
+	if (expect->expectant->helper->timeout
+	    && !del_timer(&expect->timeout))
+		return;
+
+	__unexpect_related(expect);
+}
+
+/* delete all unconfirmed expectations for this conntrack */
+static void remove_expectations(struct ip_conntrack *ct)
+{
+	struct list_head *exp_entry, *next;
+	struct ip_conntrack_expect *exp;
+
+	DEBUGP("remove_expectations(%p)\n", ct);
+
+	for (exp_entry = ct->sibling_list.next;
+	     exp_entry != &ct->sibling_list; exp_entry = next) {
+		next = exp_entry->next;
+		exp = list_entry(exp_entry, struct ip_conntrack_expect,
+				 expected_list);
+
+		/* we skip established expectations, as we want to delete
+		 * the un-established ones only */
+		if (exp->sibling) {
+			DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
+			continue;
+		}
+
+		IP_NF_ASSERT(list_inlist(&ip_conntrack_expect_list, exp));
+		IP_NF_ASSERT(exp->expectant == ct);
+
+		/* delete expectation from global and private lists */
+		unexpect_related(exp);
+	}
+}
+
 static void
 clean_from_lists(struct ip_conntrack *ct)
 {
+	DEBUGP("clean_from_lists(%p)\n", ct);
 	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
 	/* Remove from both hash lists: must not NULL out next ptrs,
            otherwise we'll look unconfirmed.  Fortunately, LIST_DELETE
@@ -163,12 +301,9 @@
 	LIST_DELETE(&ip_conntrack_hash
 		    [hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)],
 		    &ct->tuplehash[IP_CT_DIR_REPLY]);
-	/* If our expected is in the list, take it out. */
-	if (ct->expected.expectant) {
-		IP_NF_ASSERT(list_inlist(&expect_list, &ct->expected));
-		IP_NF_ASSERT(ct->expected.expectant == ct);
-		LIST_DELETE(&expect_list, &ct->expected);
-	}
+
+	/* Destroy all un-established, pending expectations */
+	remove_expectations(ct);
 }
 
 static void
@@ -177,21 +312,34 @@
 	struct ip_conntrack *ct = (struct ip_conntrack *)nfct;
 	struct ip_conntrack_protocol *proto;
 
+	DEBUGP("destroy_conntrack(%p)\n", ct);
 	IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
 	IP_NF_ASSERT(!timer_pending(&ct->timeout));
 
-	if (ct->master.master)
-		nf_conntrack_put(&ct->master);
+	if (ct->master && master_ct(ct))
+		ip_conntrack_put(master_ct(ct));
 
 	/* To make sure we don't get any weird locking issues here:
 	 * destroy_conntrack() MUST NOT be called with a write lock
 	 * to ip_conntrack_lock!!! -HW */
-	proto = find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
+	proto = ip_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
 	if (proto && proto->destroy)
 		proto->destroy(ct);
 
 	if (ip_conntrack_destroyed)
 		ip_conntrack_destroyed(ct);
+
+	WRITE_LOCK(&ip_conntrack_lock);
+	/* Delete our master expectation */
+	if (ct->master) {
+		/* can't call __unexpect_related here,
+		 * since it would screw up expect_list */
+		list_del(&ct->master->expected_list);
+		kfree(ct->master);
+	}
+	WRITE_UNLOCK(&ip_conntrack_lock);
+
+	DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
 	kmem_cache_free(ip_conntrack_cachep, ct);
 	atomic_dec(&ip_conntrack_count);
 }
@@ -315,7 +463,7 @@
 			     &ct->tuplehash[IP_CT_DIR_REPLY]);
 		/* Timer relative to confirmation time, not original
 		   setting time, otherwise we'd get timer wrap in
-		   wierd delay cases. */
+		   weird delay cases. */
 		ct->timeout.expires += jiffies;
 		add_timer(&ct->timeout);
 		atomic_inc(&ct->ct_general.use);
@@ -389,7 +537,7 @@
 		return NULL;
 	}
 
-	innerproto = find_proto(inner->protocol);
+	innerproto = ip_ct_find_proto(inner->protocol);
 	/* Are they talking about one of our connections? */
 	if (inner->ihl * 4 + 8 > datalen
 	    || !get_tuple(inner, datalen, &origtuple, innerproto)) {
@@ -469,11 +617,11 @@
 	return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
 }
 
-/* Compare parts depending on mask. */
-static inline int expect_cmp(const struct ip_conntrack_expect *i,
-			     const struct ip_conntrack_tuple *tuple)
+struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
 {
-	return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
+	return LIST_FIND(&helpers, helper_cmp,
+			 struct ip_conntrack_helper *,
+			 tuple);
 }
 
 /* Allocate a new conntrack: we return -ENOMEM if classification
@@ -521,7 +669,7 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
-	memset(conntrack, 0, sizeof(struct ip_conntrack));
+	memset(conntrack, 0, sizeof(*conntrack));
 	atomic_set(&conntrack->ct_general.use, 1);
 	conntrack->ct_general.destroy = destroy_conntrack;
 	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
@@ -540,31 +688,44 @@
 	conntrack->timeout.data = (unsigned long)conntrack;
 	conntrack->timeout.function = death_by_timeout;
 
+	INIT_LIST_HEAD(&conntrack->sibling_list);
+
 	/* Mark clearly that it's not in the hash table. */
 	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list.next = NULL;
 
-	/* Write lock required for deletion of expected.  Without
-           this, a read-lock would do. */
 	WRITE_LOCK(&ip_conntrack_lock);
-	conntrack->helper = LIST_FIND(&helpers, helper_cmp,
-				      struct ip_conntrack_helper *,
-				      &repl_tuple);
 	/* Need finding and deleting of expected ONLY if we win race */
-	expected = LIST_FIND(&expect_list, expect_cmp,
+	READ_LOCK(&ip_conntrack_expect_tuple_lock);
+	expected = LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
 			     struct ip_conntrack_expect *, tuple);
+	READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
+
+	/* Look up the conntrack helper for master connections only */
+	if (!expected)
+		conntrack->helper = ip_ct_find_helper(&repl_tuple);
+
+	/* If the expectation is dying, then this is a looser. */
+	if (expected
+	    && expected->expectant->helper->timeout
+	    && ! del_timer(&expected->timeout))
+		expected = NULL;
+
 	/* If master is not in hash table yet (ie. packet hasn't left
 	   this machine yet), how can other end know about expected?
 	   Hence these are not the droids you are looking for (if
 	   master ct never got confirmed, we'd hold a reference to it
 	   and weird things would happen to future packets). */
 	if (expected && is_confirmed(expected->expectant)) {
+		DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
+			conntrack, expected);
 		/* Welcome, Mr. Bond.  We've been expecting you... */
+		IP_NF_ASSERT(master_ct(conntrack));
 		conntrack->status = IPS_EXPECTED;
-		conntrack->master.master = &expected->expectant->ct_general;
-		IP_NF_ASSERT(conntrack->master.master);
-		LIST_DELETE(&expect_list, expected);
-		expected->expectant = NULL;
-		nf_conntrack_get(&conntrack->master);
+		conntrack->master = expected;
+		expected->sibling = conntrack;
+		LIST_DELETE(&ip_conntrack_expect_list, expected);
+		expected->expectant->expecting--;
+		nf_conntrack_get(&master_ct(conntrack)->infos[0]);
 	}
 	atomic_inc(&ip_conntrack_count);
 	WRITE_UNLOCK(&ip_conntrack_lock);
@@ -669,7 +830,7 @@
 			return NF_STOLEN;
 	}
 
-	proto = find_proto((*pskb)->nh.iph->protocol);
+	proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
 
 	/* It may be an icmp error... */
 	if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP 
@@ -713,66 +874,229 @@
 int invert_tuplepr(struct ip_conntrack_tuple *inverse,
 		   const struct ip_conntrack_tuple *orig)
 {
-	return invert_tuple(inverse, orig, find_proto(orig->dst.protonum));
+	return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
 }
 
-static void unexpect_related(struct ip_conntrack *related_to)
-{
-	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
-	list_del(&related_to->expected.list);
-	related_to->expected.expectant = NULL;
+static inline int resent_expect(const struct ip_conntrack_expect *i,
+			        const struct ip_conntrack_tuple *tuple,
+			        const struct ip_conntrack_tuple *mask)
+{
+	DEBUGP("resent_expect\n");
+	DEBUGP("   tuple:   "); DUMP_TUPLE(&i->tuple);
+	DEBUGP("ct_tuple:   "); DUMP_TUPLE(&i->ct_tuple);
+	DEBUGP("test tuple: "); DUMP_TUPLE(tuple);
+	return (((i->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&i->tuple, tuple))
+	         || (i->ct_tuple.dst.protonum && ip_ct_tuple_equal(&i->ct_tuple, tuple)))
+		&& ip_ct_tuple_equal(&i->mask, mask));
 }
 
 /* Would two expected things clash? */
 static inline int expect_clash(const struct ip_conntrack_expect *i,
-			       const struct ip_conntrack_expect *new)
+			       const struct ip_conntrack_tuple *tuple,
+			       const struct ip_conntrack_tuple *mask)
 {
 	/* Part covered by intersection of masks must be unequal,
            otherwise they clash */
 	struct ip_conntrack_tuple intersect_mask
-		= { { i->mask.src.ip & new->mask.src.ip,
-		      { i->mask.src.u.all & new->mask.src.u.all } },
-		    { i->mask.dst.ip & new->mask.dst.ip,
-		      { i->mask.dst.u.all & new->mask.dst.u.all },
-		      i->mask.dst.protonum & new->mask.dst.protonum } };
+		= { { i->mask.src.ip & mask->src.ip,
+		      { i->mask.src.u.all & mask->src.u.all } },
+		    { i->mask.dst.ip & mask->dst.ip,
+		      { i->mask.dst.u.all & mask->dst.u.all },
+		      i->mask.dst.protonum & mask->dst.protonum } };
+
+	return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
+}
+
+inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
+{
+	WRITE_LOCK(&ip_conntrack_lock);
+	unexpect_related(expect);
+	WRITE_UNLOCK(&ip_conntrack_lock);
+}
+	
+static void expectation_timed_out(unsigned long ul_expect)
+{
+	struct ip_conntrack_expect *expect = (void *) ul_expect;
 
-	return ip_ct_tuple_mask_cmp(&i->tuple, &new->tuple, &intersect_mask);
+	DEBUGP("expectation %p timed out\n", expect);	
+	WRITE_LOCK(&ip_conntrack_lock);
+	__unexpect_related(expect);
+	WRITE_UNLOCK(&ip_conntrack_lock);
 }
 
 /* Add a related connection. */
 int ip_conntrack_expect_related(struct ip_conntrack *related_to,
-				const struct ip_conntrack_tuple *tuple,
-				const struct ip_conntrack_tuple *mask,
-				int (*expectfn)(struct ip_conntrack *))
+				struct ip_conntrack_expect *expect)
 {
+	struct ip_conntrack_expect *old, *new;
+	int ret = 0;
+
 	WRITE_LOCK(&ip_conntrack_lock);
-	if (related_to->expected.expectant)
-		unexpect_related(related_to);
+	/* Because of the write lock, no reader can walk the lists,
+	 * so there is no need to use the tuple lock too */
+
+	DEBUGP("ip_conntrack_expect_related %p\n", related_to);
+	DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
+	DEBUGP("mask:  "); DUMP_TUPLE(&expect->mask);
+
+	old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
+		        struct ip_conntrack_expect *, &expect->tuple, 
+			&expect->mask);
+	if (old) {
+		/* Helper private data may contain offsets but no pointers
+		   pointing into the payload - otherwise we should have to copy 
+		   the data filled out by the helper over the old one */
+		DEBUGP("expect_related: resent packet\n");
+		if (related_to->helper->timeout) {
+			if (!del_timer(&old->timeout)) {
+				/* expectation is dying. Fall through */
+				old = NULL;
+			} else {
+				old->timeout.expires = jiffies + 
+					related_to->helper->timeout * HZ;
+				add_timer(&old->timeout);
+			}
+		}
+
+		if (old) {
+			WRITE_UNLOCK(&ip_conntrack_lock);
+			return -EEXIST;
+		}
+	} else if (related_to->helper->max_expected && 
+		   related_to->expecting >= related_to->helper->max_expected) {
+		struct list_head *cur_item;
+		/* old == NULL */
+	    	if (net_ratelimit())
+		    	printk(KERN_WARNING 
+		    	       "ip_conntrack: max number of expected "
+			       "connections %i of %s reached for "
+			       "%u.%u.%u.%u->%u.%u.%u.%u%s\n",
+		    	       related_to->helper->max_expected, 
+		    	       related_to->helper->name,
+		    	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
+		    	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip),
+		    	       related_to->helper->flags & IP_CT_HELPER_F_REUSE_EXPECT ?
+		    	       ", reusing" : "");
+		if (!(related_to->helper->flags & 
+		      IP_CT_HELPER_F_REUSE_EXPECT)) {
+			WRITE_UNLOCK(&ip_conntrack_lock);
+			return -EPERM;
+		}
 
-	related_to->expected.tuple = *tuple;
-	related_to->expected.mask = *mask;
-	related_to->expected.expectfn = expectfn;
+		/* choose the the oldest expectation to evict */
+		list_for_each(cur_item, &related_to->sibling_list) { 
+			struct ip_conntrack_expect *cur;
+
+			cur = list_entry(cur_item, 
+					 struct ip_conntrack_expect,
+					 expected_list);
+			if (cur->sibling == NULL) {
+				old = cur;
+				break;
+			}
+		}
 
-	if (LIST_FIND(&expect_list, expect_clash,
-		      struct ip_conntrack_expect *, &related_to->expected)) {
+		/* (!old) cannot happen, since related_to->expecting is the
+		 * number of unconfirmed expects */
+		IP_NF_ASSERT(old);
+
+		/* newnat14 does not reuse the real allocated memory
+		 * structures but rather unexpects the old and
+		 * allocates a new.  unexpect_related will decrement
+		 * related_to->expecting. 
+		 */
+		unexpect_related(old);
+		ret = -EPERM;
+	} else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash,
+			     struct ip_conntrack_expect *, &expect->tuple, 
+			     &expect->mask)) {
 		WRITE_UNLOCK(&ip_conntrack_lock);
+		DEBUGP("expect_related: busy!\n");
 		return -EBUSY;
 	}
+	
+	new = (struct ip_conntrack_expect *) 
+	      kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
+	if (!new) {
+		WRITE_UNLOCK(&ip_conntrack_lock);
+		DEBUGP("expect_relaed: OOM allocating expect\n");
+		return -ENOMEM;
+	}
+	
+	/* Zero out the new structure, then fill out it with the data */
+	DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
+	memset(new, 0, sizeof(*expect));
+	INIT_LIST_HEAD(&new->list);
+	INIT_LIST_HEAD(&new->expected_list);
+	memcpy(new, expect, sizeof(*expect));
+	new->expectant = related_to;
+	new->sibling = NULL;
+	/* increase usage count. This sucks. The memset above overwrites
+	 * old usage count [if still present] and we increase to one.  Only
+	 * works because everything is done under ip_conntrack_lock() */
+	atomic_inc(&new->use);
+	
+	/* add to expected list for this connection */	
+	list_add(&new->expected_list, &related_to->sibling_list);
+	/* add to global list of expectations */
+	list_prepend(&ip_conntrack_expect_list, &new->list);
+	/* add and start timer if required */
+	if (related_to->helper->timeout) {
+		init_timer(&new->timeout);
+		new->timeout.data = (unsigned long)new;
+		new->timeout.function = expectation_timed_out;
+		new->timeout.expires = jiffies + 
+					related_to->helper->timeout * HZ;
+		add_timer(&new->timeout);
+	}
+	related_to->expecting++;
 
-	list_prepend(&expect_list, &related_to->expected);
-	related_to->expected.expectant = related_to;
 	WRITE_UNLOCK(&ip_conntrack_lock);
 
-	return 0;
+	return ret;
 }
 
-void ip_conntrack_unexpect_related(struct ip_conntrack *related_to)
+/* Change tuple in an existing expectation */
+int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
+			       struct ip_conntrack_tuple *newtuple)
 {
-	WRITE_LOCK(&ip_conntrack_lock);
-	unexpect_related(related_to);
-	WRITE_UNLOCK(&ip_conntrack_lock);
-}
+	int ret;
+
+	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
+	WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
+
+	DEBUGP("change_expect:\n");
+	DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
+	DEBUGP("exp mask:  "); DUMP_TUPLE(&expect->mask);
+	DEBUGP("newtuple:  "); DUMP_TUPLE(newtuple);
+	if (expect->ct_tuple.dst.protonum == 0) {
+		/* Never seen before */
+		DEBUGP("change expect: never seen before\n");
+		if (!ip_ct_tuple_equal(&expect->tuple, newtuple) 
+		    && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
+			         struct ip_conntrack_expect *, newtuple, &expect->mask)) {
+			/* Force NAT to find an unused tuple */
+			ret = -1;
+		} else {
+			memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
+			memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
+			ret = 0;
+		}
+	} else {
+		/* Resent packet */
+		DEBUGP("change expect: resent packet\n");
+		if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
+			ret = 0;
+		} else {
+			/* Force NAT to choose again the same port */
+			ret = -1;
+		}
+	}
+	WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
 	
+	return ret;
+}
+
 /* Alter reply tuple (maybe alter helper).  If it's already taken,
    return 0 and don't do alteration. */
 int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
@@ -790,10 +1114,12 @@
 	DUMP_TUPLE(newreply);
 
 	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
-	conntrack->helper = LIST_FIND(&helpers, helper_cmp,
-				      struct ip_conntrack_helper *,
-				      newreply);
+	if (!conntrack->master)
+		conntrack->helper = LIST_FIND(&helpers, helper_cmp,
+					      struct ip_conntrack_helper *,
+					      newreply);
 	WRITE_UNLOCK(&ip_conntrack_lock);
+
 	return 1;
 }
 
@@ -812,14 +1138,10 @@
 			 const struct ip_conntrack_helper *me)
 {
 	if (i->ctrack->helper == me) {
-		i->ctrack->helper = NULL;
 		/* Get rid of any expected. */
-		if (i->ctrack->expected.expectant) {
-			IP_NF_ASSERT(i->ctrack->expected.expectant
-				     == i->ctrack);
-			LIST_DELETE(&expect_list, &i->ctrack->expected);
-			i->ctrack->expected.expectant = NULL;
-		}
+		remove_expectations(i->ctrack);
+		/* And *then* set helper to NULL */
+		i->ctrack->helper = NULL;
 	}
 	return 0;
 }
@@ -1100,18 +1422,22 @@
 	}
 	ip_conntrack_max = 8 * ip_conntrack_htable_size;
 
-	printk("ip_conntrack (%u buckets, %d max)\n",
-	       ip_conntrack_htable_size, ip_conntrack_max);
+	printk("ip_conntrack version %s (%u buckets, %d max)"
+	       " - %d bytes per conntrack\n", IP_CONNTRACK_VERSION,
+	       ip_conntrack_htable_size, ip_conntrack_max,
+	       sizeof(struct ip_conntrack));
 
 	ret = nf_register_sockopt(&so_getorigdst);
-	if (ret != 0)
+	if (ret != 0) {
+		printk(KERN_ERR "Unable to register netfilter socket option\n");
 		return ret;
+	}
 
 	ip_conntrack_hash = vmalloc(sizeof(struct list_head)
 				    * ip_conntrack_htable_size);
 	if (!ip_conntrack_hash) {
-		nf_unregister_sockopt(&so_getorigdst);
-		return -ENOMEM;
+		printk(KERN_ERR "Unable to create ip_conntrack_hash\n");
+		goto err_unreg_sockopt;
 	}
 
 	ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
@@ -1119,11 +1445,8 @@
 	                                        SLAB_HWCACHE_ALIGN, NULL, NULL);
 	if (!ip_conntrack_cachep) {
 		printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
-		vfree(ip_conntrack_hash);
-		nf_unregister_sockopt(&so_getorigdst);
-		return -ENOMEM;
+		goto err_free_hash;
 	}
-	
 	/* Don't NEED lock here, but good form anyway. */
 	WRITE_LOCK(&ip_conntrack_lock);
 	/* Sew in builtin protocols. */
@@ -1142,14 +1465,20 @@
 	ip_conntrack_sysctl_header
 		= register_sysctl_table(ip_conntrack_root_table, 0);
 	if (ip_conntrack_sysctl_header == NULL) {
-		kmem_cache_destroy(ip_conntrack_cachep);
-		vfree(ip_conntrack_hash);
-		nf_unregister_sockopt(&so_getorigdst);
-		return -ENOMEM;
+		goto err_free_ct_cachep;
 	}
 #endif /*CONFIG_SYSCTL*/
 
 	/* For use by ipt_REJECT */
 	ip_ct_attach = ip_conntrack_attach;
 	return ret;
+
+err_free_ct_cachep:
+	kmem_cache_destroy(ip_conntrack_cachep);
+err_free_hash:
+	vfree(ip_conntrack_hash);
+err_unreg_sockopt:
+	nf_unregister_sockopt(&so_getorigdst);
+
+	return -ENOMEM;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_conntrack_ftp.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_ftp.c
--- linux-2.4.19/net/ipv4/netfilter/ip_conntrack_ftp.c	2001-10-30 23:08:12.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_ftp.c	2002-10-29 11:18:34.000000000 +0000
@@ -1,4 +1,5 @@
 /* FTP extension for IP connection tracking. */
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/netfilter.h>
 #include <linux/ip.h>
@@ -15,7 +16,7 @@
 
 #define MAX_PORTS 8
 static int ports[MAX_PORTS];
-static int ports_c;
+static int ports_c = 0;
 #ifdef MODULE_PARM
 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
 #endif
@@ -242,8 +243,10 @@
 	u_int32_t array[6] = { 0 };
 	int dir = CTINFO2DIR(ctinfo);
 	unsigned int matchlen, matchoff;
-	struct ip_conntrack_tuple t, mask;
-	struct ip_ct_ftp *info = &ct->help.ct_ftp_info;
+	struct ip_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info;
+	struct ip_conntrack_expect expect, *exp = &expect;
+	struct ip_ct_ftp_expect *exp_ftp_info = &exp->help.exp_ftp_info;
+
 	unsigned int i;
 	int found = 0;
 
@@ -271,8 +274,8 @@
 	}
 
 	LOCK_BH(&ip_ftp_lock);
-	old_seq_aft_nl_set = info->seq_aft_nl_set[dir];
-	old_seq_aft_nl = info->seq_aft_nl[dir];
+	old_seq_aft_nl_set = ct_ftp_info->seq_aft_nl_set[dir];
+	old_seq_aft_nl = ct_ftp_info->seq_aft_nl[dir];
 
 	DEBUGP("conntrack_ftp: datalen %u\n", datalen);
 	if ((datalen > 0) && (data[datalen-1] == '\n')) {
@@ -281,8 +284,9 @@
 		    || after(ntohl(tcph->seq) + datalen, old_seq_aft_nl)) {
 			DEBUGP("conntrack_ftp: updating nl to %u\n",
 			       ntohl(tcph->seq) + datalen);
-			info->seq_aft_nl[dir] = ntohl(tcph->seq) + datalen;
-			info->seq_aft_nl_set[dir] = 1;
+			ct_ftp_info->seq_aft_nl[dir] = 
+						ntohl(tcph->seq) + datalen;
+			ct_ftp_info->seq_aft_nl_set[dir] = 1;
 		}
 	}
 	UNLOCK_BH(&ip_ftp_lock);
@@ -330,16 +334,17 @@
 	DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
 	       (int)matchlen, data + matchoff,
 	       matchlen, ntohl(tcph->seq) + matchoff);
+	       
+	memset(&expect, 0, sizeof(expect));
 
 	/* Update the ftp info */
 	LOCK_BH(&ip_ftp_lock);
 	if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
 	    == ct->tuplehash[dir].tuple.src.ip) {
-		info->is_ftp = 21;
-		info->seq = ntohl(tcph->seq) + matchoff;
-		info->len = matchlen;
-		info->ftptype = search[i].ftptype;
-		info->port = array[4] << 8 | array[5];
+		exp->seq = ntohl(tcph->seq) + matchoff;
+		exp_ftp_info->len = matchlen;
+		exp_ftp_info->ftptype = search[i].ftptype;
+		exp_ftp_info->port = array[4] << 8 | array[5];
 	} else {
 		/* Enrico Scholz's passive FTP to partially RNAT'd ftp
 		   server: it really wants us to connect to a
@@ -356,18 +361,21 @@
 		if (!loose) goto out;
 	}
 
-	t = ((struct ip_conntrack_tuple)
+	exp->tuple = ((struct ip_conntrack_tuple)
 		{ { ct->tuplehash[!dir].tuple.src.ip,
 		    { 0 } },
 		  { htonl((array[0] << 24) | (array[1] << 16)
 			  | (array[2] << 8) | array[3]),
 		    { htons(array[4] << 8 | array[5]) },
 		    IPPROTO_TCP }});
-	mask = ((struct ip_conntrack_tuple)
+	exp->mask = ((struct ip_conntrack_tuple)
 		{ { 0xFFFFFFFF, { 0 } },
 		  { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
+
+	exp->expectfn = NULL;
+
 	/* Ignore failure; should only happen with NAT */
-	ip_conntrack_expect_related(ct, &t, &mask, NULL);
+	ip_conntrack_expect_related(ct, &expect);
  out:
 	UNLOCK_BH(&ip_ftp_lock);
 
@@ -375,12 +383,13 @@
 }
 
 static struct ip_conntrack_helper ftp[MAX_PORTS];
+static char ftp_names[MAX_PORTS][10];
 
 /* Not __exit: called from init() */
 static void fini(void)
 {
 	int i;
-	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+	for (i = 0; i < ports_c; i++) {
 		DEBUGP("ip_ct_ftp: unregistering helper for port %d\n",
 				ports[i]);
 		ip_conntrack_helper_unregister(&ftp[i]);
@@ -390,9 +399,10 @@
 static int __init init(void)
 {
 	int i, ret;
+	char *tmpname;
 
 	if (ports[0] == 0)
-		ports[0] = 21;
+		ports[0] = FTP_PORT;
 
 	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
 		memset(&ftp[i], 0, sizeof(struct ip_conntrack_helper));
@@ -400,7 +410,19 @@
 		ftp[i].tuple.dst.protonum = IPPROTO_TCP;
 		ftp[i].mask.src.u.tcp.port = 0xFFFF;
 		ftp[i].mask.dst.protonum = 0xFFFF;
+		ftp[i].max_expected = 1;
+		ftp[i].timeout = 0;
+		ftp[i].flags = IP_CT_HELPER_F_REUSE_EXPECT;
+		ftp[i].me = ip_conntrack_ftp;
 		ftp[i].help = help;
+
+		tmpname = &ftp_names[i][0];
+		if (ports[i] == FTP_PORT)
+			sprintf(tmpname, "ftp");
+		else
+			sprintf(tmpname, "ftp-%d", ports[i]);
+		ftp[i].name = tmpname;
+
 		DEBUGP("ip_ct_ftp: registering helper for port %d\n", 
 				ports[i]);
 		ret = ip_conntrack_helper_register(&ftp[i]);
@@ -414,10 +436,10 @@
 	return 0;
 }
 
-
+#ifdef CONFIG_IP_NF_NAT_NEEDED
 EXPORT_SYMBOL(ip_ftp_lock);
-EXPORT_SYMBOL(ip_conntrack_ftp);
-MODULE_LICENSE("GPL");
+#endif
 
+MODULE_LICENSE("GPL");
 module_init(init);
 module_exit(fini);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_conntrack_irc.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_irc.c
--- linux-2.4.19/net/ipv4/netfilter/ip_conntrack_irc.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_irc.c	2002-10-29 11:18:34.000000000 +0000
@@ -11,12 +11,18 @@
  **
  *	Module load syntax:
  * 	insmod ip_conntrack_irc.o ports=port1,port2,...port<MAX_PORTS>
+ *			    max_dcc_channels=n dcc_timeout=secs
  *	
  * 	please give the ports of all IRC servers You wish to connect to.
- *	If You don't specify ports, the default will be port 6667
+ *	If You don't specify ports, the default will be port 6667.
+ *	With max_dcc_channels you can define the maximum number of not
+ *	yet answered DCC channels per IRC session (default 8).
+ *	With dcc_timeout you can specify how long the system waits for 
+ *	an expected DCC channel (default 300 seconds).
  *
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/netfilter.h>
 #include <linux/ip.h>
@@ -29,7 +35,9 @@
 
 #define MAX_PORTS 8
 static int ports[MAX_PORTS];
-static int ports_n_c = 0;
+static int ports_c = 0;
+static int max_dcc_channels = 8;
+static unsigned int dcc_timeout = 300;
 
 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
 MODULE_DESCRIPTION("IRC (DCC) connection tracking module");
@@ -37,6 +45,10 @@
 #ifdef MODULE_PARM
 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
 MODULE_PARM_DESC(ports, "port numbers of IRC servers");
+MODULE_PARM(max_dcc_channels, "i");
+MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session");
+MODULE_PARM(dcc_timeout, "i");
+MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels");
 #endif
 
 #define NUM_DCCPROTO 	5
@@ -103,23 +115,15 @@
 	u_int32_t tcplen = len - iph->ihl * 4;
 	u_int32_t datalen = tcplen - tcph->doff * 4;
 	int dir = CTINFO2DIR(ctinfo);
-	struct ip_conntrack_tuple t, mask;
+	struct ip_conntrack_expect expect, *exp = &expect;
+	struct ip_ct_irc_expect *exp_irc_info = &exp->help.exp_irc_info;
 
 	u_int32_t dcc_ip;
 	u_int16_t dcc_port;
 	int i;
 	char *addr_beg_p, *addr_end_p;
 
-	struct ip_ct_irc *info = &ct->help.ct_irc_info;
-
-	mask = ((struct ip_conntrack_tuple)
-		{ { 0, { 0 } },
-		  { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
-
 	DEBUGP("entered\n");
-	/* Can't track connections formed before we registered */
-	if (!info)
-		return NF_ACCEPT;
 
 	/* If packet is coming from IRC server */
 	if (dir == IP_CT_DIR_REPLY)
@@ -189,33 +193,37 @@
 
 				continue;
 			}
+			
+			memset(&expect, 0, sizeof(expect));
 
 			LOCK_BH(&ip_irc_lock);
 
 			/* save position of address in dcc string,
 			 * neccessary for NAT */
-			info->is_irc = IP_CONNTR_IRC;
 			DEBUGP("tcph->seq = %u\n", tcph->seq);
-			info->seq = ntohl(tcph->seq) + (addr_beg_p - _data);
-			info->len = (addr_end_p - addr_beg_p);
-			info->port = dcc_port;
+			exp->seq = ntohl(tcph->seq) + (addr_beg_p - _data);
+			exp_irc_info->len = (addr_end_p - addr_beg_p);
+			exp_irc_info->port = dcc_port;
 			DEBUGP("wrote info seq=%u (ofs=%u), len=%d\n",
-				info->seq, (addr_end_p - _data), info->len);
+				exp->seq, (addr_end_p - _data), exp_irc_info->len);
 
-			memset(&t, 0, sizeof(t));
-			t.src.ip = 0;
-			t.src.u.tcp.port = 0;
-			t.dst.ip = htonl(dcc_ip);
-			t.dst.u.tcp.port = htons(info->port);
-			t.dst.protonum = IPPROTO_TCP;
+			exp->tuple = ((struct ip_conntrack_tuple)
+				{ { 0, { 0 } },
+				  { htonl(dcc_ip), { htons(dcc_port) },
+				    IPPROTO_TCP }});
+			exp->mask = ((struct ip_conntrack_tuple)
+				{ { 0, { 0 } },
+				  { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
+
+			exp->expectfn = NULL;
 
 			DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
-				NIPQUAD(t.src.ip),
-				ntohs(t.src.u.tcp.port),
-				NIPQUAD(t.dst.ip),
-				ntohs(t.dst.u.tcp.port));
+				NIPQUAD(exp->tuple.src.ip),
+				ntohs(exp->tuple.src.u.tcp.port),
+				NIPQUAD(exp->tuple.dst.ip),
+				ntohs(exp->tuple.dst.u.tcp.port));
 
-			ip_conntrack_expect_related(ct, &t, &mask, NULL);
+			ip_conntrack_expect_related(ct, &expect);
 			UNLOCK_BH(&ip_irc_lock);
 
 			return NF_ACCEPT;
@@ -226,29 +234,53 @@
 }
 
 static struct ip_conntrack_helper irc_helpers[MAX_PORTS];
+static char irc_names[MAX_PORTS][10];
 
 static void fini(void);
 
 static int __init init(void)
 {
 	int i, ret;
+	struct ip_conntrack_helper *hlpr;
+	char *tmpname;
 
+	if (max_dcc_channels < 1) {
+		printk("ip_conntrack_irc: max_dcc_channels must be a positive integer\n");
+		return -EBUSY;
+	}
+	if (dcc_timeout < 0) {
+		printk("ip_conntrack_irc: dcc_timeout must be a positive integer\n");
+		return -EBUSY;
+	}
+	
 	/* If no port given, default to standard irc port */
 	if (ports[0] == 0)
-		ports[0] = 6667;
+		ports[0] = IRC_PORT;
 
 	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
-		memset(&irc_helpers[i], 0,
+		hlpr = &irc_helpers[i];
+		memset(hlpr, 0,
 		       sizeof(struct ip_conntrack_helper));
-		irc_helpers[i].tuple.src.u.tcp.port = htons(ports[i]);
-		irc_helpers[i].tuple.dst.protonum = IPPROTO_TCP;
-		irc_helpers[i].mask.src.u.tcp.port = 0xFFFF;
-		irc_helpers[i].mask.dst.protonum = 0xFFFF;
-		irc_helpers[i].help = help;
+		hlpr->tuple.src.u.tcp.port = htons(ports[i]);
+		hlpr->tuple.dst.protonum = IPPROTO_TCP;
+		hlpr->mask.src.u.tcp.port = 0xFFFF;
+		hlpr->mask.dst.protonum = 0xFFFF;
+		hlpr->max_expected = max_dcc_channels;
+		hlpr->timeout = dcc_timeout;
+		hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT;
+		hlpr->me = ip_conntrack_irc;
+		hlpr->help = help;
+
+		tmpname = &irc_names[i][0];
+		if (ports[i] == IRC_PORT)
+			sprintf(tmpname, "irc");
+		else
+			sprintf(tmpname, "irc-%d", i);
+		hlpr->name = tmpname;
 
 		DEBUGP("port #%d: %d\n", i, ports[i]);
 
-		ret = ip_conntrack_helper_register(&irc_helpers[i]);
+		ret = ip_conntrack_helper_register(hlpr);
 
 		if (ret) {
 			printk("ip_conntrack_irc: ERROR registering port %d\n",
@@ -256,7 +288,7 @@
 			fini();
 			return -EBUSY;
 		}
-		ports_n_c++;
+		ports_c++;
 	}
 	return 0;
 }
@@ -266,12 +298,16 @@
 static void fini(void)
 {
 	int i;
-	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+	for (i = 0; i < ports_c; i++) {
 		DEBUGP("unregistering port %d\n",
 		       ports[i]);
 		ip_conntrack_helper_unregister(&irc_helpers[i]);
 	}
 }
 
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+EXPORT_SYMBOL(ip_irc_lock);
+#endif
+
 module_init(init);
 module_exit(fini);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_conntrack_proto_generic.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_generic.c
--- linux-2.4.19/net/ipv4/netfilter/ip_conntrack_proto_generic.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_generic.c	2002-10-29 11:18:36.000000000 +0000
@@ -57,5 +57,5 @@
 struct ip_conntrack_protocol ip_conntrack_generic_protocol
 = { { NULL, NULL }, 0, "unknown",
     generic_pkt_to_tuple, generic_invert_tuple, generic_print_tuple,
-    generic_print_conntrack, established, new, NULL, NULL };
+    generic_print_conntrack, established, new, NULL, NULL, NULL };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_conntrack_proto_icmp.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
--- linux-2.4.19/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	2002-10-29 11:18:31.000000000 +0000
@@ -113,4 +113,4 @@
 struct ip_conntrack_protocol ip_conntrack_protocol_icmp
 = { { NULL, NULL }, IPPROTO_ICMP, "icmp",
     icmp_pkt_to_tuple, icmp_invert_tuple, icmp_print_tuple,
-    icmp_print_conntrack, icmp_packet, icmp_new, NULL, NULL };
+    icmp_print_conntrack, icmp_packet, icmp_new, NULL, NULL, NULL };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.4.19/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2002-10-29 11:18:50.000000000 +0000
@@ -7,6 +7,10 @@
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
+#include <linux/string.h>
+
+#include <net/tcp.h>
+
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
 #include <linux/netfilter_ipv4/lockhelp.h>
@@ -227,7 +231,19 @@
 	return 1;
 }
 
+static int tcp_exp_matches_pkt(struct ip_conntrack_expect *exp,
+			       struct sk_buff **pskb)
+{
+	struct iphdr *iph = (*pskb)->nh.iph;
+	struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
+	unsigned int datalen;
+
+	datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4;
+
+	return between(exp->seq, ntohl(tcph->seq), ntohl(tcph->seq) + datalen);
+}
+
 struct ip_conntrack_protocol ip_conntrack_protocol_tcp
 = { { NULL, NULL }, IPPROTO_TCP, "tcp",
     tcp_pkt_to_tuple, tcp_invert_tuple, tcp_print_tuple, tcp_print_conntrack,
-    tcp_packet, tcp_new, NULL, NULL };
+    tcp_packet, tcp_new, NULL, tcp_exp_matches_pkt, NULL };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_conntrack_proto_udp.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_udp.c
--- linux-2.4.19/net/ipv4/netfilter/ip_conntrack_proto_udp.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_udp.c	2002-10-29 11:18:30.000000000 +0000
@@ -71,4 +71,4 @@
 struct ip_conntrack_protocol ip_conntrack_protocol_udp
 = { { NULL, NULL }, IPPROTO_UDP, "udp",
     udp_pkt_to_tuple, udp_invert_tuple, udp_print_tuple, udp_print_conntrack,
-    udp_packet, udp_new, NULL, NULL };
+    udp_packet, udp_new, NULL, NULL, NULL };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_standalone.c
--- linux-2.4.19/net/ipv4/netfilter/ip_conntrack_standalone.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_standalone.c	2002-10-29 11:18:40.000000000 +0000
@@ -62,10 +62,16 @@
 {
 	unsigned int len;
 
-	len = sprintf(buffer, "EXPECTING: proto=%u ",
-		      expect->tuple.dst.protonum);
+	if (expect->expectant->helper->timeout)
+		len = sprintf(buffer, "EXPECTING: %lu ",
+			      timer_pending(&expect->timeout)
+			      ? (expect->timeout.expires - jiffies)/HZ : 0);
+	else
+		len = sprintf(buffer, "EXPECTING: - ");
+	len += sprintf(buffer + len, "use=%u proto=%u ",
+		      atomic_read(&expect->use), expect->tuple.dst.protonum);
 	len += print_tuple(buffer + len, &expect->tuple,
-			   __find_proto(expect->tuple.dst.protonum));
+			   __ip_ct_find_proto(expect->tuple.dst.protonum));
 	len += sprintf(buffer + len, "\n");
 	return len;
 }
@@ -75,7 +81,7 @@
 {
 	unsigned int len;
 	struct ip_conntrack_protocol *proto
-		= __find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
+		= __ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
 			       .tuple.dst.protonum);
 
 	len = sprintf(buffer, "%-8s %u %lu ",
@@ -147,7 +153,8 @@
 	}
 
 	/* Now iterate through expecteds. */
-	for (e = expect_list.next; e != &expect_list; e = e->next) {
+	for (e = ip_conntrack_expect_list.next; 
+	     e != &ip_conntrack_expect_list; e = e->next) {
 		unsigned int last_len;
 		struct ip_conntrack_expect *expect
 			= (struct ip_conntrack_expect *)e;
@@ -314,7 +321,7 @@
 {
 	WRITE_LOCK(&ip_conntrack_lock);
 
-	/* find_proto() returns proto_generic in case there is no protocol 
+	/* ip_ct_find_proto() returns proto_generic in case there is no protocol 
 	 * helper. So this should be enough - HW */
 	LIST_DELETE(&protocol_list, proto);
 	WRITE_UNLOCK(&ip_conntrack_lock);
@@ -353,8 +360,19 @@
 EXPORT_SYMBOL(ip_conntrack_helper_unregister);
 EXPORT_SYMBOL(ip_ct_selective_cleanup);
 EXPORT_SYMBOL(ip_ct_refresh);
+EXPORT_SYMBOL(ip_ct_find_proto);
+EXPORT_SYMBOL(__ip_ct_find_proto);
+EXPORT_SYMBOL(ip_ct_find_helper);
 EXPORT_SYMBOL(ip_conntrack_expect_related);
+EXPORT_SYMBOL(ip_conntrack_change_expect);
 EXPORT_SYMBOL(ip_conntrack_unexpect_related);
+EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get);
+EXPORT_SYMBOL_GPL(ip_conntrack_expect_put);
 EXPORT_SYMBOL(ip_conntrack_tuple_taken);
 EXPORT_SYMBOL(ip_ct_gather_frags);
 EXPORT_SYMBOL(ip_conntrack_htable_size);
+EXPORT_SYMBOL(ip_conntrack_expect_list);
+EXPORT_SYMBOL(ip_conntrack_lock);
+EXPORT_SYMBOL(ip_conntrack_hash);
+EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
+EXPORT_SYMBOL_GPL(ip_conntrack_put);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_fw_compat_masq.c linux-2.4.20/net/ipv4/netfilter/ip_fw_compat_masq.c
--- linux-2.4.19/net/ipv4/netfilter/ip_fw_compat_masq.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_fw_compat_masq.c	2002-10-29 11:18:35.000000000 +0000
@@ -130,7 +130,7 @@
 	struct ip_conntrack *ct;
 	int ret;
 
-	protocol = find_proto(iph->protocol);
+	protocol = ip_ct_find_proto(iph->protocol);
 
 	/* We don't feed packets to conntrack system unless we know
            they're part of an connection already established by an
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_nat_core.c linux-2.4.20/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.4.19/net/ipv4/netfilter/ip_nat_core.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_nat_core.c	2002-10-29 11:18:33.000000000 +0000
@@ -21,10 +21,14 @@
 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
 
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
 #include <linux/netfilter_ipv4/ip_nat.h>
 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
 #include <linux/netfilter_ipv4/ip_nat_core.h>
 #include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 #include <linux/netfilter_ipv4/listhelp.h>
 
 #if 0
@@ -34,6 +38,7 @@
 #endif
 
 DECLARE_RWLOCK(ip_nat_lock);
+DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
 
 /* Calculated at init based on memory size */
 static unsigned int ip_nat_htable_size;
@@ -198,6 +203,7 @@
 		return NULL;
 }
 
+#ifdef CONFIG_IP_NF_NAT_LOCAL
 /* If it's really a local destination manip, it may need to do a
    source manip too. */
 static int
@@ -216,6 +222,7 @@
 	ip_rt_put(rt);
 	return 1;
 }
+#endif
 
 /* Simple way to iterate through all. */
 static inline int fake_cmp(const struct ip_nat_hash *i,
@@ -628,8 +635,9 @@
 	}
 
 	/* If there's a helper, assign it; based on new tuple. */
-	info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
-				 &reply);
+	if (!conntrack->master)
+		info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
+					 &reply);
 
 	/* It's done. */
 	info->initialized |= (1 << HOOK2MANIP(hooknum));
@@ -724,6 +732,20 @@
 #endif
 }
 
+static inline int exp_for_packet(struct ip_conntrack_expect *exp,
+			         struct sk_buff **pskb)
+{
+	struct ip_conntrack_protocol *proto;
+	int ret = 1;
+
+	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
+	proto = __ip_ct_find_proto((*pskb)->nh.iph->protocol);
+	if (proto->exp_matches_pkt)
+		ret = proto->exp_matches_pkt(exp, pskb);
+
+	return ret;
+}
+
 /* Do packet manipulations according to binding. */
 unsigned int
 do_bindings(struct ip_conntrack *ct,
@@ -735,6 +757,7 @@
 	unsigned int i;
 	struct ip_nat_helper *helper;
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+	int is_tcp = (*pskb)->nh.iph->protocol == IPPROTO_TCP;
 
 	/* Need nat lock to protect against modification, but neither
 	   conntrack (referenced) and helper (deleted with
@@ -773,11 +796,66 @@
 	READ_UNLOCK(&ip_nat_lock);
 
 	if (helper) {
+		struct ip_conntrack_expect *exp = NULL;
+		struct list_head *cur_item;
+		int ret = NF_ACCEPT;
+
+		DEBUGP("do_bindings: helper existing for (%p)\n", ct);
+
 		/* Always defragged for helpers */
 		IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
-			       & __constant_htons(IP_MF|IP_OFFSET)));
-		return helper->help(ct, info, ctinfo, hooknum, pskb);
-	} else return NF_ACCEPT;
+			       & htons(IP_MF|IP_OFFSET)));
+
+		/* Have to grab read lock before sibling_list traversal */
+		READ_LOCK(&ip_conntrack_lock);
+		list_for_each(cur_item, &ct->sibling_list) { 
+			exp = list_entry(cur_item, struct ip_conntrack_expect, 
+					 expected_list);
+					 
+			/* if this expectation is already established, skip */
+			if (exp->sibling)
+				continue;
+
+			if (exp_for_packet(exp, pskb)) {
+				/* FIXME: May be true multiple times in the case of UDP!! */
+				DEBUGP("calling nat helper (exp=%p) for packet\n",
+					exp);
+				ret = helper->help(ct, exp, info, ctinfo, 
+						   hooknum, pskb);
+				if (ret != NF_ACCEPT) {
+					READ_UNLOCK(&ip_conntrack_lock);
+					return ret;
+				}
+			}
+		}
+		/* Helper might want to manip the packet even when there is no expectation */
+		if (!exp && helper->flags & IP_NAT_HELPER_F_ALWAYS) {
+			DEBUGP("calling nat helper for packet without expectation\n");
+			ret = helper->help(ct, NULL, info, ctinfo, 
+					   hooknum, pskb);
+			if (ret != NF_ACCEPT) {
+				READ_UNLOCK(&ip_conntrack_lock);
+				return ret;
+			}
+		}
+		READ_UNLOCK(&ip_conntrack_lock);
+		
+		/* Adjust sequence number only once per packet 
+		 * (helper is called at all hooks) */
+		if (is_tcp && (hooknum == NF_IP_POST_ROUTING
+			       || hooknum == NF_IP_LOCAL_IN)) {
+			DEBUGP("ip_nat_core: adjusting sequence number\n");
+			/* future: put this in a l4-proto specific function,
+			 * and call this function here. */
+			ip_nat_seq_adjust(*pskb, ct, ctinfo);
+		}
+
+		return ret;
+
+	} else 
+		return NF_ACCEPT;
+
+	/* not reached */
 }
 
 unsigned int
@@ -816,7 +894,7 @@
 	/* Note: May not be from a NAT'd host, but probably safest to
 	   do translation always as if it came from the host itself
 	   (even though a "host unreachable" coming from the host
-	   itself is a bit wierd).
+	   itself is a bit weird).
 
 	   More explanation: some people use NAT for anonymizing.
 	   Also, CERT recommends dropping all packets from private IP
@@ -920,4 +998,5 @@
 {
 	ip_ct_selective_cleanup(&clean_nat, NULL);
 	ip_conntrack_destroyed = NULL;
+	vfree(bysource);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_nat_ftp.c linux-2.4.20/net/ipv4/netfilter/ip_nat_ftp.c
--- linux-2.4.19/net/ipv4/netfilter/ip_nat_ftp.c	2001-10-30 23:08:12.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_nat_ftp.c	2002-10-29 11:18:33.000000000 +0000
@@ -28,38 +28,30 @@
 
 /* FIXME: Time out? --RR */
 
-static int
+static unsigned int
 ftp_nat_expected(struct sk_buff **pskb,
 		 unsigned int hooknum,
 		 struct ip_conntrack *ct,
-		 struct ip_nat_info *info,
-		 struct ip_conntrack *master,
-		 struct ip_nat_info *masterinfo,
-		 unsigned int *verdict)
+		 struct ip_nat_info *info)
 {
 	struct ip_nat_multi_range mr;
 	u_int32_t newdstip, newsrcip, newip;
-	struct ip_ct_ftp *ftpinfo;
+	struct ip_ct_ftp_expect *exp_ftp_info;
 
+	struct ip_conntrack *master = master_ct(ct);
+	
 	IP_NF_ASSERT(info);
 	IP_NF_ASSERT(master);
-	IP_NF_ASSERT(masterinfo);
 
 	IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
 
 	DEBUGP("nat_expected: We have a connection!\n");
-	/* Master must be an ftp connection */
-	ftpinfo = &master->help.ct_ftp_info;
+	exp_ftp_info = &ct->master->help.exp_ftp_info;
 
 	LOCK_BH(&ip_ftp_lock);
-	if (ftpinfo->is_ftp != 21) {
-		UNLOCK_BH(&ip_ftp_lock);
-		DEBUGP("nat_expected: master not ftp\n");
-		return 0;
-	}
 
-	if (ftpinfo->ftptype == IP_CT_FTP_PORT
-	    || ftpinfo->ftptype == IP_CT_FTP_EPRT) {
+	if (exp_ftp_info->ftptype == IP_CT_FTP_PORT
+	    || exp_ftp_info->ftptype == IP_CT_FTP_EPRT) {
 		/* PORT command: make connection go to the client. */
 		newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
 		newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
@@ -92,11 +84,9 @@
 		mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
 		mr.range[0].min = mr.range[0].max
 			= ((union ip_conntrack_manip_proto)
-				{ htons(ftpinfo->port) });
+				{ htons(exp_ftp_info->port) });
 	}
-	*verdict = ip_nat_setup_info(ct, &mr, hooknum);
-
-	return 1;
+	return ip_nat_setup_info(ct, &mr, hooknum);
 }
 
 static int
@@ -176,27 +166,22 @@
     [IP_CT_FTP_EPSV] mangle_epsv_packet
 };
 
-static int ftp_data_fixup(const struct ip_ct_ftp *ct_ftp_info,
+static int ftp_data_fixup(const struct ip_ct_ftp_expect *ct_ftp_info,
 			  struct ip_conntrack *ct,
-			  unsigned int datalen,
 			  struct sk_buff **pskb,
-			  enum ip_conntrack_info ctinfo)
+			  enum ip_conntrack_info ctinfo,
+			  struct ip_conntrack_expect *expect)
 {
 	u_int32_t newip;
 	struct iphdr *iph = (*pskb)->nh.iph;
 	struct tcphdr *tcph = (void *)iph + iph->ihl*4;
 	u_int16_t port;
-	struct ip_conntrack_tuple tuple;
-	/* Don't care about source port */
-	const struct ip_conntrack_tuple mask
-		= { { 0xFFFFFFFF, { 0 } },
-		    { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF } };
+	struct ip_conntrack_tuple newtuple;
 
-	memset(&tuple, 0, sizeof(tuple));
 	MUST_BE_LOCKED(&ip_ftp_lock);
-	DEBUGP("FTP_NAT: seq %u + %u in %u + %u\n",
-	       ct_ftp_info->seq, ct_ftp_info->len,
-	       ntohl(tcph->seq), datalen);
+	DEBUGP("FTP_NAT: seq %u + %u in %u\n",
+	       expect->seq, ct_ftp_info->len,
+	       ntohl(tcph->seq));
 
 	/* Change address inside packet to match way we're mapping
 	   this connection. */
@@ -206,29 +191,34 @@
 		   is */
 		newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
 		/* Expect something from client->server */
-		tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
-		tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+		newtuple.src.ip = 
+			ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
+		newtuple.dst.ip = 
+			ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
 	} else {
 		/* PORT command: must be where server thinks client is */
 		newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
 		/* Expect something from server->client */
-		tuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
-		tuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
+		newtuple.src.ip = 
+			ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
+		newtuple.dst.ip = 
+			ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
 	}
-	tuple.dst.protonum = IPPROTO_TCP;
+	newtuple.dst.protonum = IPPROTO_TCP;
+	newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port;
 
 	/* Try to get same port: if not, try to change it. */
 	for (port = ct_ftp_info->port; port != 0; port++) {
-		tuple.dst.u.tcp.port = htons(port);
+		newtuple.dst.u.tcp.port = htons(port);
 
-		if (ip_conntrack_expect_related(ct, &tuple, &mask, NULL) == 0)
+		if (ip_conntrack_change_expect(expect, &newtuple) == 0)
 			break;
 	}
 	if (port == 0)
 		return 0;
 
 	if (!mangle[ct_ftp_info->ftptype](pskb, newip, port,
-					  ct_ftp_info->seq - ntohl(tcph->seq),
+					  expect->seq - ntohl(tcph->seq),
 					  ct_ftp_info->len, ct, ctinfo))
 		return 0;
 
@@ -236,6 +226,7 @@
 }
 
 static unsigned int help(struct ip_conntrack *ct,
+			 struct ip_conntrack_expect *exp,
 			 struct ip_nat_info *info,
 			 enum ip_conntrack_info ctinfo,
 			 unsigned int hooknum,
@@ -245,13 +236,12 @@
 	struct tcphdr *tcph = (void *)iph + iph->ihl*4;
 	unsigned int datalen;
 	int dir;
-	int score;
-	struct ip_ct_ftp *ct_ftp_info
-		= &ct->help.ct_ftp_info;
-
-	/* Delete SACK_OK on initial TCP SYNs. */
-	if (tcph->syn && !tcph->ack)
-		ip_nat_delete_sack(*pskb, tcph);
+	struct ip_ct_ftp_expect *ct_ftp_info;
+
+	if (!exp)
+		DEBUGP("ip_nat_ftp: no exp!!");
+
+	ct_ftp_info = &exp->help.exp_ftp_info;
 
 	/* Only mangle things once: original direction in POST_ROUTING
 	   and reply direction on PRE_ROUTING. */
@@ -267,103 +257,87 @@
 	}
 
 	datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
-	score = 0;
 	LOCK_BH(&ip_ftp_lock);
-	if (ct_ftp_info->len) {
-		/* If it's in the right range... */
-		score += between(ct_ftp_info->seq, ntohl(tcph->seq),
-				 ntohl(tcph->seq) + datalen);
-		score += between(ct_ftp_info->seq + ct_ftp_info->len,
-				 ntohl(tcph->seq),
-				 ntohl(tcph->seq) + datalen);
-		if (score == 1) {
-			/* Half a match?  This means a partial retransmisison.
-			   It's a cracker being funky. */
-			if (net_ratelimit()) {
-				printk("FTP_NAT: partial packet %u/%u in %u/%u\n",
-				       ct_ftp_info->seq, ct_ftp_info->len,
-				       ntohl(tcph->seq),
-				       ntohl(tcph->seq) + datalen);
-			}
+	/* If it's in the right range... */
+	if (between(exp->seq + ct_ftp_info->len,
+		    ntohl(tcph->seq),
+		    ntohl(tcph->seq) + datalen)) {
+		if (!ftp_data_fixup(ct_ftp_info, ct, pskb, ctinfo, exp)) {
 			UNLOCK_BH(&ip_ftp_lock);
 			return NF_DROP;
-		} else if (score == 2) {
-			if (!ftp_data_fixup(ct_ftp_info, ct, datalen,
-					    pskb, ctinfo)) {
-				UNLOCK_BH(&ip_ftp_lock);
-				return NF_DROP;
-			}
-			/* skb may have been reallocated */
-			iph = (*pskb)->nh.iph;
-			tcph = (void *)iph + iph->ihl*4;
 		}
+	} else {
+		/* Half a match?  This means a partial retransmisison.
+		   It's a cracker being funky. */
+		if (net_ratelimit()) {
+			printk("FTP_NAT: partial packet %u/%u in %u/%u\n",
+			       exp->seq, ct_ftp_info->len,
+			       ntohl(tcph->seq),
+			       ntohl(tcph->seq) + datalen);
+		}
+		UNLOCK_BH(&ip_ftp_lock);
+		return NF_DROP;
 	}
-
 	UNLOCK_BH(&ip_ftp_lock);
 
-	ip_nat_seq_adjust(*pskb, ct, ctinfo);
-
 	return NF_ACCEPT;
 }
 
 static struct ip_nat_helper ftp[MAX_PORTS];
-static char ftp_names[MAX_PORTS][6];
-
-static struct ip_nat_expect ftp_expect
-= { { NULL, NULL }, ftp_nat_expected };
+static char ftp_names[MAX_PORTS][10];
 
 /* Not __exit: called from init() */
 static void fini(void)
 {
 	int i;
 
-	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+	for (i = 0; i < ports_c; i++) {
 		DEBUGP("ip_nat_ftp: unregistering port %d\n", ports[i]);
 		ip_nat_helper_unregister(&ftp[i]);
 	}
-
-	ip_nat_expect_unregister(&ftp_expect);
 }
 
 static int __init init(void)
 {
-	int i, ret;
+	int i, ret = 0;
 	char *tmpname;
 
-	ret = ip_nat_expect_register(&ftp_expect);
-	if (ret == 0) {
-		if (ports[0] == 0)
-			ports[0] = 21;
-
-		for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
-
-			memset(&ftp[i], 0, sizeof(struct ip_nat_helper));
-
-			ftp[i].tuple.dst.protonum = IPPROTO_TCP;
-			ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
-			ftp[i].mask.dst.protonum = 0xFFFF;
-			ftp[i].mask.src.u.tcp.port = 0xFFFF;
-			ftp[i].help = help;
-
-			tmpname = &ftp_names[i][0];
-			sprintf(tmpname, "ftp%2.2d", i);
-			ftp[i].name = tmpname;
-
-			DEBUGP("ip_nat_ftp: Trying to register for port %d\n",
-					ports[i]);
-			ret = ip_nat_helper_register(&ftp[i]);
-
-			if (ret) {
-				printk("ip_nat_ftp: error registering helper for port %d\n", ports[i]);
-				fini();
-				return ret;
-			}
-			ports_c++;
-		}
+	if (ports[0] == 0)
+		ports[0] = FTP_PORT;
 
-	} else {
-		ip_nat_expect_unregister(&ftp_expect);
+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+
+		memset(&ftp[i], 0, sizeof(struct ip_nat_helper));
+
+		ftp[i].tuple.dst.protonum = IPPROTO_TCP;
+		ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
+		ftp[i].mask.dst.protonum = 0xFFFF;
+		ftp[i].mask.src.u.tcp.port = 0xFFFF;
+		ftp[i].help = help;
+		ftp[i].me = THIS_MODULE;
+		ftp[i].flags = 0;
+		ftp[i].expect = ftp_nat_expected;
+
+		tmpname = &ftp_names[i][0];
+		if (ports[i] == FTP_PORT)
+			sprintf(tmpname, "ftp");
+		else
+			sprintf(tmpname, "ftp-%d", i);
+		ftp[i].name = tmpname;
+
+		DEBUGP("ip_nat_ftp: Trying to register for port %d\n",
+				ports[i]);
+		ret = ip_nat_helper_register(&ftp[i]);
+
+		if (ret) {
+			printk("ip_nat_ftp: error registering "
+			       "helper for port %d\n", ports[i]);
+			fini();
+			return ret;
+		}
+		ports_c++;
 	}
+
 	return ret;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_nat_helper.c linux-2.4.20/net/ipv4/netfilter/ip_nat_helper.c
--- linux-2.4.19/net/ipv4/netfilter/ip_nat_helper.c	2001-12-21 17:42:05.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_nat_helper.c	2002-10-29 11:18:33.000000000 +0000
@@ -1,11 +1,18 @@
 /* ip_nat_mangle.c - generic support functions for NAT helpers 
  *
- * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
  *
  * distributed under the terms of GNU GPL
+ *
+ * 	14 Jan 2002 Harald Welte <laforge@gnumonks.org>:
+ *		- add support for SACK adjustment 
+ *	14 Mar 2002 Harald Welte <laforge@gnumonks.org>:
+ *		- merge SACK support into newnat API
  */
 #include <linux/version.h>
+#include <linux/config.h>
 #include <linux/module.h>
+#include <linux/kmod.h>
 #include <linux/types.h>
 #include <linux/timer.h>
 #include <linux/skbuff.h>
@@ -19,6 +26,8 @@
 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
 
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 #include <linux/netfilter_ipv4/ip_nat.h>
 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
 #include <linux/netfilter_ipv4/ip_nat_core.h>
@@ -32,7 +41,7 @@
 #define DEBUGP(format, args...)
 #define DUMP_OFFSET(x)
 #endif
-	
+
 DECLARE_LOCK(ip_nat_seqofs_lock);
 			 
 static inline int 
@@ -199,6 +208,103 @@
 	return 1;
 }
 
+/* Adjust one found SACK option including checksum correction */
+static void
+sack_adjust(struct tcphdr *tcph, 
+	    unsigned char *ptr, 
+	    struct ip_nat_seq *natseq)
+{
+	struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2);
+	int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3;
+	int i;
+
+	for (i = 0; i < num_sacks; i++, sp++) {
+		u_int32_t new_start_seq, new_end_seq;
+
+		if (after(ntohl(sp->start_seq) - natseq->offset_before,
+			  natseq->correction_pos))
+			new_start_seq = ntohl(sp->start_seq) 
+					- natseq->offset_after;
+		else
+			new_start_seq = ntohl(sp->start_seq) 
+					- natseq->offset_before;
+		new_start_seq = htonl(new_start_seq);
+
+		if (after(ntohl(sp->end_seq) - natseq->offset_before,
+			  natseq->correction_pos))
+			new_end_seq = ntohl(sp->end_seq)
+				      - natseq->offset_after;
+		else
+			new_end_seq = ntohl(sp->end_seq)
+				      - natseq->offset_before;
+		new_end_seq = htonl(new_end_seq);
+
+		DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
+			ntohl(sp->start_seq), new_start_seq,
+			ntohl(sp->end_seq), new_end_seq);
+
+		tcph->check = 
+			ip_nat_cheat_check(~sp->start_seq, new_start_seq,
+					   ip_nat_cheat_check(~sp->end_seq, 
+						   	      new_end_seq,
+							      tcph->check));
+
+		sp->start_seq = new_start_seq;
+		sp->end_seq = new_end_seq;
+	}
+}
+			
+
+/* TCP SACK sequence number adjustment, return 0 if sack found and adjusted */
+static inline int
+ip_nat_sack_adjust(struct sk_buff *skb,
+			struct ip_conntrack *ct,
+			enum ip_conntrack_info ctinfo)
+{
+	struct iphdr *iph;
+	struct tcphdr *tcph;
+	unsigned char *ptr;
+	int length, dir, sack_adjusted = 0;
+
+	iph = skb->nh.iph;
+	tcph = (void *)iph + iph->ihl*4;
+	length = (tcph->doff*4)-sizeof(struct tcphdr);
+	ptr = (unsigned char *)(tcph+1);
+
+	dir = CTINFO2DIR(ctinfo);
+
+	while (length > 0) {
+		int opcode = *ptr++;
+		int opsize;
+
+		switch (opcode) {
+		case TCPOPT_EOL:
+			return !sack_adjusted;
+		case TCPOPT_NOP:
+			length--;
+			continue;
+		default:
+			opsize = *ptr++;
+			if (opsize > length) /* no partial opts */
+				return !sack_adjusted;
+			if (opcode == TCPOPT_SACK) {
+				/* found SACK */
+				if((opsize >= (TCPOLEN_SACK_BASE
+					       +TCPOLEN_SACK_PERBLOCK)) &&
+				   !((opsize - TCPOLEN_SACK_BASE)
+				     % TCPOLEN_SACK_PERBLOCK))
+					sack_adjust(tcph, ptr-2,
+						    &ct->nat.info.seq[!dir]);
+				
+				sack_adjusted = 1;
+			}
+			ptr += opsize-2;
+			length -= opsize;
+		}
+	}
+	return !sack_adjusted;
+}
+
 /* TCP sequence number adjustment */
 int 
 ip_nat_seq_adjust(struct sk_buff *skb, 
@@ -243,51 +349,9 @@
 	tcph->seq = newseq;
 	tcph->ack_seq = newack;
 
-	return 0;
-}
-
-/* Grrr... SACK.  Fuck me even harder.  Don't want to fix it on the
-   fly, so blow it away. */
-void
-ip_nat_delete_sack(struct sk_buff *skb, struct tcphdr *tcph)
-{
-	unsigned int i;
-	u_int8_t *opt = (u_int8_t *)tcph;
-
-	DEBUGP("Seeking SACKPERM in SYN packet (doff = %u).\n",
-	       tcph->doff * 4);
-	for (i = sizeof(struct tcphdr); i < tcph->doff * 4;) {
-		DEBUGP("%u ", opt[i]);
-		switch (opt[i]) {
-		case TCPOPT_NOP:
-		case TCPOPT_EOL:
-			i++;
-			break;
+	ip_nat_sack_adjust(skb, ct, ctinfo);
 
-		case TCPOPT_SACK_PERM:
-			goto found_opt;
-
-		default:
-			/* Worst that can happen: it will take us over. */
-			i += opt[i+1] ?: 1;
-		}
-	}
-	DEBUGP("\n");
-	return;
-
- found_opt:
-	DEBUGP("\n");
-	DEBUGP("Found SACKPERM at offset %u.\n", i);
-
-	/* Must be within TCP header, and valid SACK perm. */
-	if (i + opt[i+1] <= tcph->doff*4 && opt[i+1] == 2) {
-		/* Replace with NOPs. */
-		tcph->check
-			= ip_nat_cheat_check(*((u_int16_t *)(opt + i))^0xFFFF,
-					     (TCPOPT_NOP<<8)|TCPOPT_NOP, tcph->check);
-		opt[i] = opt[i+1] = TCPOPT_NOP;
-	}
-	else DEBUGP("Something wrong with SACK_PERM.\n");
+	return 0;
 }
 
 static inline int
@@ -297,10 +361,51 @@
 	return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
 }
 
+#define MODULE_MAX_NAMELEN		32
+
 int ip_nat_helper_register(struct ip_nat_helper *me)
 {
 	int ret = 0;
 
+	if (me->me && !(me->flags & IP_NAT_HELPER_F_STANDALONE)) {
+		struct ip_conntrack_helper *ct_helper;
+		
+		if ((ct_helper = ip_ct_find_helper(&me->tuple))
+		    && ct_helper->me) {
+			__MOD_INC_USE_COUNT(ct_helper->me);
+		} else {
+
+			/* We are a NAT helper for protocol X.  If we need
+			 * respective conntrack helper for protoccol X, compute
+			 * conntrack helper name and try to load module */
+			char name[MODULE_MAX_NAMELEN];
+			const char *tmp = me->me->name;
+			
+			if (strlen(tmp) + 6 > MODULE_MAX_NAMELEN) {
+				printk(__FUNCTION__ ": unable to "
+				       "compute conntrack helper name "
+				       "from %s\n", tmp);
+				return -EBUSY;
+			}
+			tmp += 6;
+			sprintf(name, "ip_conntrack%s", tmp);
+#ifdef CONFIG_KMOD
+			if (!request_module(name)
+			    && (ct_helper = ip_ct_find_helper(&me->tuple))
+			    && ct_helper->me) {
+				__MOD_INC_USE_COUNT(ct_helper->me);
+			} else {
+				printk("unable to load module %s\n", name);
+				return -EBUSY;
+			}
+#else
+			printk("unable to load module %s automatically "
+			       "because kernel was compiled without kernel "
+			       "module loader support\n", name);
+			return -EBUSY;
+#endif
+		}
+	}
 	WRITE_LOCK(&ip_nat_lock);
 	if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple))
 		ret = -EBUSY;
@@ -327,8 +432,14 @@
 
 void ip_nat_helper_unregister(struct ip_nat_helper *me)
 {
+	int found = 0;
+	
 	WRITE_LOCK(&ip_nat_lock);
-	LIST_DELETE(&helpers, me);
+	/* Autoloading conntrack helper might have failed */
+	if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple)) {
+		LIST_DELETE(&helpers, me);
+		found = 1;
+	}
 	WRITE_UNLOCK(&ip_nat_lock);
 
 	/* Someone could be still looking at the helper in a bh. */
@@ -344,5 +455,19 @@
 	   worse. --RR */
 	ip_ct_selective_cleanup(kill_helper, me);
 
-	MOD_DEC_USE_COUNT;
+	if (found)
+		MOD_DEC_USE_COUNT;
+
+	/* If we are no standalone NAT helper, we need to decrement usage count
+	 * on our conntrack helper */
+	if (me->me && !(me->flags & IP_NAT_HELPER_F_STANDALONE)) {
+		struct ip_conntrack_helper *ct_helper;
+		
+		if ((ct_helper = ip_ct_find_helper(&me->tuple))
+		    && ct_helper->me) {
+			__MOD_DEC_USE_COUNT(ct_helper->me);
+		} else 
+			printk(__FUNCTION__ ": unable to decrement usage count"
+			       " of conntrack helper %s\n", me->me->name);
+	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_nat_irc.c linux-2.4.20/net/ipv4/netfilter/ip_nat_irc.c
--- linux-2.4.19/net/ipv4/netfilter/ip_nat_irc.c	2001-12-21 17:42:05.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_nat_irc.c	2002-10-29 11:18:51.000000000 +0000
@@ -51,42 +51,29 @@
 
 /* FIXME: Time out? --RR */
 
-static int
+static unsigned int
 irc_nat_expected(struct sk_buff **pskb,
 		 unsigned int hooknum,
 		 struct ip_conntrack *ct,
-		 struct ip_nat_info *info,
-		 struct ip_conntrack *master,
-		 struct ip_nat_info *masterinfo, unsigned int *verdict)
+		 struct ip_nat_info *info)
 {
 	struct ip_nat_multi_range mr;
 	u_int32_t newdstip, newsrcip, newip;
-	struct ip_ct_irc *ircinfo;
+
+	struct ip_conntrack *master = master_ct(ct);
 
 	IP_NF_ASSERT(info);
 	IP_NF_ASSERT(master);
-	IP_NF_ASSERT(masterinfo);
 
 	IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
 
 	DEBUGP("nat_expected: We have a connection!\n");
 
-	/* Master must be an irc connection */
-	ircinfo = &master->help.ct_irc_info;
-	LOCK_BH(&ip_irc_lock);
-	if (ircinfo->is_irc != IP_CONNTR_IRC) {
-		UNLOCK_BH(&ip_irc_lock);
-		DEBUGP("nat_expected: master not irc\n");
-		return 0;
-	}
-
 	newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
 	newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
 	DEBUGP("nat_expected: DCC cmd. %u.%u.%u.%u->%u.%u.%u.%u\n",
 	       NIPQUAD(newsrcip), NIPQUAD(newdstip));
 
-	UNLOCK_BH(&ip_irc_lock);
-
 	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
 		newip = newsrcip;
 	else
@@ -99,16 +86,14 @@
 	mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
 	mr.range[0].min_ip = mr.range[0].max_ip = newip;
 
-	*verdict = ip_nat_setup_info(ct, &mr, hooknum);
-
-	return 1;
+	return ip_nat_setup_info(ct, &mr, hooknum);
 }
 
-static int irc_data_fixup(const struct ip_ct_irc *ct_irc_info,
+static int irc_data_fixup(const struct ip_ct_irc_expect *ct_irc_info,
 			  struct ip_conntrack *ct,
-			  unsigned int datalen,
 			  struct sk_buff **pskb,
-			  enum ip_conntrack_info ctinfo)
+			  enum ip_conntrack_info ctinfo,
+			  struct ip_conntrack_expect *expect)
 {
 	u_int32_t newip;
 	struct ip_conntrack_tuple t;
@@ -121,9 +106,9 @@
 
 	MUST_BE_LOCKED(&ip_irc_lock);
 
-	DEBUGP("IRC_NAT: info (seq %u + %u) packet(seq %u + %u)\n",
-	       ct_irc_info->seq, ct_irc_info->len,
-	       ntohl(tcph->seq), datalen);
+	DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n",
+	       expect->seq, ct_irc_info->len,
+	       ntohl(tcph->seq));
 
 	newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
 
@@ -133,13 +118,11 @@
 	   only set in ip_conntrack_irc, with ip_irc_lock held
 	   writable */
 
-	t = ct->expected.tuple;
+	t = expect->tuple;
 	t.dst.ip = newip;
 	for (port = ct_irc_info->port; port != 0; port++) {
 		t.dst.u.tcp.port = htons(port);
-		if (ip_conntrack_expect_related(ct, &t,
-						&ct->expected.mask,
-						NULL) == 0) {
+		if (ip_conntrack_change_expect(expect, &t) == 0) {
 			DEBUGP("using port %d", port);
 			break;
 		}
@@ -166,26 +149,28 @@
 	       buffer, NIPQUAD(newip), port);
 
 	return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 
-					ct_irc_info->seq - ntohl(tcph->seq),
+					expect->seq - ntohl(tcph->seq),
 					ct_irc_info->len, buffer, 
 					strlen(buffer));
 }
 
 static unsigned int help(struct ip_conntrack *ct,
+			 struct ip_conntrack_expect *exp,
 			 struct ip_nat_info *info,
 			 enum ip_conntrack_info ctinfo,
-			 unsigned int hooknum, struct sk_buff **pskb)
+			 unsigned int hooknum, 
+			 struct sk_buff **pskb)
 {
 	struct iphdr *iph = (*pskb)->nh.iph;
 	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
 	unsigned int datalen;
 	int dir;
-	int score;
-	struct ip_ct_irc *ct_irc_info = &ct->help.ct_irc_info;
+	struct ip_ct_irc_expect *ct_irc_info;
 
-	/* Delete SACK_OK on initial TCP SYNs. */
-	if (tcph->syn && !tcph->ack)
-		ip_nat_delete_sack(*pskb, tcph);
+	if (!exp)
+		DEBUGP("ip_nat_irc: no exp!!");
+		
+	ct_irc_info = &exp->help.exp_irc_info;
 
 	/* Only mangle things once: original direction in POST_ROUTING
 	   and reply direction on PRE_ROUTING. */
@@ -202,55 +187,35 @@
 	DEBUGP("got beyond not touching\n");
 
 	datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
-	score = 0;
 	LOCK_BH(&ip_irc_lock);
-	if (ct_irc_info->len) {
-		DEBUGP("got beyond ct_irc_info->len\n");
-
-		/* If it's in the right range... */
-		score += between(ct_irc_info->seq, ntohl(tcph->seq),
-				 ntohl(tcph->seq) + datalen);
-		score += between(ct_irc_info->seq + ct_irc_info->len,
-				 ntohl(tcph->seq),
-				 ntohl(tcph->seq) + datalen);
-		if (score == 1) {
-			/* Half a match?  This means a partial retransmisison.
-			   It's a cracker being funky. */
-			if (net_ratelimit()) {
-				printk
-				    ("IRC_NAT: partial packet %u/%u in %u/%u\n",
-				     ct_irc_info->seq, ct_irc_info->len,
-				     ntohl(tcph->seq),
-				     ntohl(tcph->seq) + datalen);
-			}
+	/* Check wether the whole IP/address pattern is carried in the payload */
+	if (between(exp->seq + ct_irc_info->len,
+		    ntohl(tcph->seq),
+		    ntohl(tcph->seq) + datalen)) {
+		if (!irc_data_fixup(ct_irc_info, ct, pskb, ctinfo, exp)) {
 			UNLOCK_BH(&ip_irc_lock);
 			return NF_DROP;
-		} else if (score == 2) {
-			DEBUGP("IRC_NAT: score=2, calling fixup\n");
-			if (!irc_data_fixup(ct_irc_info, ct, datalen,
-					    pskb, ctinfo)) {
-				UNLOCK_BH(&ip_irc_lock);
-				return NF_DROP;
-			}
-			/* skb may have been reallocated */
-			iph = (*pskb)->nh.iph;
-			tcph = (void *) iph + iph->ihl * 4;
 		}
+	} else { 
+		/* Half a match?  This means a partial retransmisison.
+		   It's a cracker being funky. */
+		if (net_ratelimit()) {
+			printk
+			    ("IRC_NAT: partial packet %u/%u in %u/%u\n",
+			     exp->seq, ct_irc_info->len,
+			     ntohl(tcph->seq),
+			     ntohl(tcph->seq) + datalen);
+		}
+		UNLOCK_BH(&ip_irc_lock);
+		return NF_DROP;
 	}
-
 	UNLOCK_BH(&ip_irc_lock);
 
-	ip_nat_seq_adjust(*pskb, ct, ctinfo);
-
 	return NF_ACCEPT;
 }
 
 static struct ip_nat_helper ip_nat_irc_helpers[MAX_PORTS];
-static char ip_nih_names[MAX_PORTS][6];
-
-static struct ip_nat_expect irc_expect
-    = { {NULL, NULL}, irc_nat_expected };
-
+static char irc_names[MAX_PORTS][10];
 
 /* This function is intentionally _NOT_ defined as  __exit, because
  * it is needed by init() */
@@ -262,52 +227,54 @@
 		DEBUGP("ip_nat_irc: unregistering helper for port %d\n",
 		       ports[i]);
 		ip_nat_helper_unregister(&ip_nat_irc_helpers[i]);
-	}
-	ip_nat_expect_unregister(&irc_expect);
+	} 
 }
+
 static int __init init(void)
 {
-	int ret;
+	int ret = 0;
 	int i;
 	struct ip_nat_helper *hlpr;
 	char *tmpname;
 
-	ret = ip_nat_expect_register(&irc_expect);
-	if (ret == 0) {
-
-		if (ports[0] == 0) {
-			ports[0] = 6667;
-		}
+	if (ports[0] == 0) {
+		ports[0] = IRC_PORT;
+	}
 
-		for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) {
-			hlpr = &ip_nat_irc_helpers[i];
-			memset(hlpr, 0,
-			       sizeof(struct ip_nat_helper));
-
-			hlpr->tuple.dst.protonum = IPPROTO_TCP;
-			hlpr->tuple.src.u.tcp.port = htons(ports[i]);
-			hlpr->mask.src.u.tcp.port = 0xFFFF;
-			hlpr->mask.dst.protonum = 0xFFFF;
-			hlpr->help = help;
-
-			tmpname = &ip_nih_names[i][0];
-			sprintf(tmpname, "irc%2.2d", i);
-
-			hlpr->name = tmpname;
-			DEBUGP
-			    ("ip_nat_irc: Trying to register helper for port %d: name %s\n",
-			     ports[i], hlpr->name);
-			ret = ip_nat_helper_register(hlpr);
-
-			if (ret) {
-				printk
-				    ("ip_nat_irc: error registering helper for port %d\n",
-				     ports[i]);
-				fini();
-				return 1;
-			}
-			ports_c++;
+	for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) {
+		hlpr = &ip_nat_irc_helpers[i];
+		memset(hlpr, 0,
+		       sizeof(struct ip_nat_helper));
+
+		hlpr->tuple.dst.protonum = IPPROTO_TCP;
+		hlpr->tuple.src.u.tcp.port = htons(ports[i]);
+		hlpr->mask.src.u.tcp.port = 0xFFFF;
+		hlpr->mask.dst.protonum = 0xFFFF;
+		hlpr->help = help;
+		hlpr->flags = 0;
+		hlpr->me = THIS_MODULE;
+		hlpr->expect = irc_nat_expected;
+
+		tmpname = &irc_names[i][0];
+		if (ports[i] == IRC_PORT)
+			sprintf(tmpname, "irc");
+		else
+			sprintf(tmpname, "irc-%d", i);
+		hlpr->name = tmpname;
+
+		DEBUGP
+		    ("ip_nat_irc: Trying to register helper for port %d: name %s\n",
+		     ports[i], hlpr->name);
+		ret = ip_nat_helper_register(hlpr);
+
+		if (ret) {
+			printk
+			    ("ip_nat_irc: error registering helper for port %d\n",
+			     ports[i]);
+			fini();
+			return 1;
 		}
+		ports_c++;
 	}
 	return ret;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_nat_proto_tcp.c linux-2.4.20/net/ipv4/netfilter/ip_nat_proto_tcp.c
--- linux-2.4.19/net/ipv4/netfilter/ip_nat_proto_tcp.c	2001-08-07 15:30:50.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_nat_proto_tcp.c	2002-10-29 11:18:31.000000000 +0000
@@ -4,7 +4,6 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/if.h>
-
 #include <linux/netfilter_ipv4/ip_nat.h>
 #include <linux/netfilter_ipv4/ip_nat_rule.h>
 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_nat_proto_unknown.c linux-2.4.20/net/ipv4/netfilter/ip_nat_proto_unknown.c
--- linux-2.4.19/net/ipv4/netfilter/ip_nat_proto_unknown.c	2000-03-17 18:56:20.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_nat_proto_unknown.c	2002-10-29 11:18:30.000000000 +0000
@@ -1,5 +1,5 @@
 /* The "unknown" protocol.  This is what is used for protocols we
- * don't understand.  It's returned by find_proto().
+ * don't understand.  It's returned by ip_ct_find_proto().
  */
 
 #include <linux/types.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_nat_rule.c linux-2.4.20/net/ipv4/netfilter/ip_nat_rule.c
--- linux-2.4.19/net/ipv4/netfilter/ip_nat_rule.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_nat_rule.c	2002-10-29 11:18:39.000000000 +0000
@@ -106,8 +106,6 @@
 = { { NULL, NULL }, "nat", &nat_initial_table.repl,
     NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
-LIST_HEAD(nat_expect_list);
-
 /* Source NAT */
 static unsigned int ipt_snat_target(struct sk_buff **pskb,
 				    unsigned int hooknum,
@@ -254,19 +252,6 @@
 	return ip_nat_setup_info(conntrack, &mr, hooknum);
 }
 
-static inline int call_expect(const struct ip_nat_expect *i,
-			      struct sk_buff **pskb,
-			      unsigned int hooknum,
-			      struct ip_conntrack *ct,
-			      struct ip_nat_info *info,
-			      struct ip_conntrack *master,
-			      struct ip_nat_info *masterinfo,
-			      unsigned int *verdict)
-{
-	return i->expect(pskb, hooknum, ct, info, master, masterinfo,
-			 verdict);
-}
-
 int ip_nat_rule_find(struct sk_buff **pskb,
 		     unsigned int hooknum,
 		     const struct net_device *in,
@@ -276,19 +261,8 @@
 {
 	int ret;
 
-	/* Master won't vanish while this ctrack still alive */
-	if (ct->master.master) {
-		struct ip_conntrack *master;
-
-		master = (struct ip_conntrack *)ct->master.master;
-		if (LIST_FIND(&nat_expect_list,
-			      call_expect,
-			      struct ip_nat_expect *,
-			      pskb, hooknum, ct, info,
-			      master, &master->nat.info, &ret))
-			return ret;
-	}
 	ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL);
+
 	if (ret == NF_ACCEPT) {
 		if (!(info->initialized & (1 << HOOK2MANIP(hooknum))))
 			/* NUL mapping */
@@ -297,22 +271,6 @@
 	return ret;
 }
 
-int ip_nat_expect_register(struct ip_nat_expect *expect)
-{
-	WRITE_LOCK(&ip_nat_lock);
-	list_prepend(&nat_expect_list, expect);
-	WRITE_UNLOCK(&ip_nat_lock);
-
-	return 0;
-}
-
-void ip_nat_expect_unregister(struct ip_nat_expect *expect)
-{
-	WRITE_LOCK(&ip_nat_lock);
-	LIST_DELETE(&nat_expect_list, expect);
-	WRITE_UNLOCK(&ip_nat_lock);
-}
-
 static struct ipt_target ipt_snat_reg
 = { { NULL, NULL }, "SNAT", ipt_snat_target, ipt_snat_checkentry, NULL };
 static struct ipt_target ipt_dnat_reg
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_nat_snmp_basic.c linux-2.4.20/net/ipv4/netfilter/ip_nat_snmp_basic.c
--- linux-2.4.19/net/ipv4/netfilter/ip_nat_snmp_basic.c	2001-10-30 23:08:12.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_nat_snmp_basic.c	2002-10-29 11:18:35.000000000 +0000
@@ -1243,6 +1243,7 @@
  * NAT helper function, packets arrive here from NAT code.
  */
 static unsigned int nat_help(struct ip_conntrack *ct,
+			     struct ip_conntrack_expect *exp,
                              struct ip_nat_info *info,
                              enum ip_conntrack_info ctinfo,
                              unsigned int hooknum,
@@ -1259,9 +1260,9 @@
 	 * on post routing (SNAT).
 	 */
 	if (!((dir == IP_CT_DIR_REPLY && hooknum == NF_IP_PRE_ROUTING &&
-			udph->source == __constant_ntohs(SNMP_PORT)) ||
+			udph->source == ntohs(SNMP_PORT)) ||
 	      (dir == IP_CT_DIR_ORIGINAL && hooknum == NF_IP_POST_ROUTING &&
-	      		udph->dest == __constant_ntohs(SNMP_TRAP_PORT)))) {
+	      		udph->dest == ntohs(SNMP_TRAP_PORT)))) {
 		spin_unlock_bh(&snmp_lock);
 		return NF_ACCEPT;
 	}
@@ -1303,19 +1304,27 @@
 	return NF_DROP;
 }
 
-static struct ip_nat_helper snmp = { { NULL, NULL },
+static struct ip_nat_helper snmp = { 
+	{ NULL, NULL },
+	"snmp",
+	IP_NAT_HELPER_F_STANDALONE,
+	THIS_MODULE,
 	{ { 0, { __constant_htons(SNMP_PORT) } },
 	  { 0, { 0 }, IPPROTO_UDP } },
 	{ { 0, { 0xFFFF } },
 	  { 0, { 0 }, 0xFFFF } },
-	  nat_help, "snmp" };
+	nat_help, NULL };
  
-static struct ip_nat_helper snmp_trap = { { NULL, NULL },
+static struct ip_nat_helper snmp_trap = { 
+	{ NULL, NULL },
+	"snmp_trap",
+	IP_NAT_HELPER_F_STANDALONE,
+	THIS_MODULE,
 	{ { 0, { __constant_htons(SNMP_TRAP_PORT) } },
 	  { 0, { 0 }, IPPROTO_UDP } },
 	{ { 0, { 0xFFFF } },
 	  { 0, { 0 }, 0xFFFF } },
-	nat_help, "snmp_trap" };
+	nat_help, NULL };
 
 /*****************************************************************************
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_nat_standalone.c linux-2.4.20/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.4.19/net/ipv4/netfilter/ip_nat_standalone.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_nat_standalone.c	2002-10-29 11:18:35.000000000 +0000
@@ -5,7 +5,12 @@
 */
 
 /* (c) 1999 Paul `Rusty' Russell.  Licenced under the GNU General
-   Public Licence. */
+ * Public Licence.
+ *
+ * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
+ * 	- new API and handling of conntrack/nat helpers
+ * 	- now capable of multiple expectations for one master
+ * */
 
 #include <linux/config.h>
 #include <linux/types.h>
@@ -44,6 +49,15 @@
 			         : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN"  \
 				    : "*ERROR*")))
 
+static inline int call_expect(struct ip_conntrack *master,
+			      struct sk_buff **pskb,
+			      unsigned int hooknum,
+			      struct ip_conntrack *ct,
+			      struct ip_nat_info *info)
+{
+	return master->nat.info.helper->expect(pskb, hooknum, ct, info);
+}
+
 static unsigned int
 ip_nat_fn(unsigned int hooknum,
 	  struct sk_buff **pskb,
@@ -60,7 +74,7 @@
 	/* We never see fragments: conntrack defrags on pre-routing
 	   and local-out, and ip_nat_out protects post-routing. */
 	IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
-		       & __constant_htons(IP_MF|IP_OFFSET)));
+		       & htons(IP_MF|IP_OFFSET)));
 
 	(*pskb)->nfcache |= NFC_UNKNOWN;
 
@@ -110,8 +124,16 @@
 			int in_hashes = info->initialized;
 			unsigned int ret;
 
-			ret = ip_nat_rule_find(pskb, hooknum, in, out,
-					       ct, info);
+			if (ct->master
+			    && master_ct(ct)->nat.info.helper
+			    && master_ct(ct)->nat.info.helper->expect) {
+				ret = call_expect(master_ct(ct), pskb, 
+						  hooknum, ct, info);
+			} else {
+				ret = ip_nat_rule_find(pskb, hooknum, in, out,
+						       ct, info);
+			}
+
 			if (ret != NF_ACCEPT) {
 				WRITE_UNLOCK(&ip_nat_lock);
 				return ret;
@@ -163,7 +185,7 @@
 
 	   I'm starting to have nightmares about fragments.  */
 
-	if ((*pskb)->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
+	if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
 		*pskb = ip_ct_gather_frags(*pskb);
 
 		if (!*pskb)
@@ -334,11 +356,7 @@
 EXPORT_SYMBOL(ip_nat_protocol_unregister);
 EXPORT_SYMBOL(ip_nat_helper_register);
 EXPORT_SYMBOL(ip_nat_helper_unregister);
-EXPORT_SYMBOL(ip_nat_expect_register);
-EXPORT_SYMBOL(ip_nat_expect_unregister);
 EXPORT_SYMBOL(ip_nat_cheat_check);
 EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
-EXPORT_SYMBOL(ip_nat_seq_adjust);
-EXPORT_SYMBOL(ip_nat_delete_sack);
 EXPORT_SYMBOL(ip_nat_used_tuple);
 MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_queue.c linux-2.4.20/net/ipv4/netfilter/ip_queue.c
--- linux-2.4.19/net/ipv4/netfilter/ip_queue.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_queue.c	2002-10-29 11:18:48.000000000 +0000
@@ -2,13 +2,14 @@
  * This is a module which is used for queueing IPv4 packets and
  * communicating with userspace via netlink.
  *
- * (C) 2000 James Morris, this code is GPL.
+ * (C) 2000-2002 James Morris, this code is GPL.
  *
  * 2000-03-27: Simplified code (thanks to Andi Kleen for clues).
  * 2000-05-20: Fixed notifier problems (following Miguel Freitas' report).
  * 2000-06-19: Fixed so nfmark is copied to metadata (reported by Sebastian 
  *             Zander).
  * 2000-08-01: Added Nick Williams' MAC support.
+ * 2002-06-25: Code cleanup.
  *
  */
 #include <linux/module.h>
@@ -18,205 +19,310 @@
 #include <linux/notifier.h>
 #include <linux/netdevice.h>
 #include <linux/netfilter.h>
+#include <linux/netfilter_ipv4/ip_queue.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netlink.h>
 #include <linux/spinlock.h>
-#include <linux/rtnetlink.h>
+#include <linux/brlock.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
 #include <net/sock.h>
 #include <net/route.h>
 
-#include <linux/netfilter_ipv4/ip_queue.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-
 #define IPQ_QMAX_DEFAULT 1024
 #define IPQ_PROC_FS_NAME "ip_queue"
 #define NET_IPQ_QMAX 2088
 #define NET_IPQ_QMAX_NAME "ip_queue_maxlen"
 
-typedef struct ipq_rt_info {
+struct ipq_rt_info {
 	__u8 tos;
 	__u32 daddr;
 	__u32 saddr;
-} ipq_rt_info_t;
+};
 
-typedef struct ipq_queue_element {
-	struct list_head list;		/* Links element into queue */
-	int verdict;			/* Current verdict */
-	struct nf_info *info;		/* Extra info from netfilter */
-	struct sk_buff *skb;		/* Packet inside */
-	ipq_rt_info_t rt_info;		/* May need post-mangle routing */
-} ipq_queue_element_t;
-
-typedef int (*ipq_send_cb_t)(ipq_queue_element_t *e);
-
-typedef struct ipq_peer {
-	pid_t pid;			/* PID of userland peer */
-	unsigned char died;		/* We think the peer died */
-	unsigned char copy_mode;	/* Copy packet as well as metadata? */
-	size_t copy_range;		/* Range past metadata to copy */
-	ipq_send_cb_t send;		/* Callback for sending data to peer */
-} ipq_peer_t;
-
-typedef struct ipq_queue {
- 	int len;			/* Current queue len */
- 	int *maxlen;			/* Maximum queue len, via sysctl */
- 	unsigned char flushing;		/* If queue is being flushed */
- 	unsigned char terminate;	/* If the queue is being terminated */
- 	struct list_head list;		/* Head of packet queue */
- 	spinlock_t lock;		/* Queue spinlock */
- 	ipq_peer_t peer;		/* Userland peer */
-} ipq_queue_t;
+struct ipq_queue_entry {
+	struct list_head list;
+	struct nf_info *info;
+	struct sk_buff *skb;
+	struct ipq_rt_info rt_info;
+};
 
-/****************************************************************************
- *
- * Packet queue
- *
- ****************************************************************************/
-/* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */
-static ipq_queue_element_t *
-ipq_dequeue(ipq_queue_t *q,
-            int (*cmp)(ipq_queue_element_t *, unsigned long),
-            unsigned long data)
-{
-	struct list_head *i;
-
-	spin_lock_bh(&q->lock);
-	for (i = q->list.prev; i != &q->list; i = i->prev) {
-		ipq_queue_element_t *e = (ipq_queue_element_t *)i;
-		
-		if (!cmp || cmp(e, data)) {
-			list_del(&e->list);
-			q->len--;
-			spin_unlock_bh(&q->lock);
-			return e;
-		}
+typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long);
+
+static unsigned char copy_mode = IPQ_COPY_NONE;
+static unsigned int queue_maxlen = IPQ_QMAX_DEFAULT;
+static rwlock_t queue_lock = RW_LOCK_UNLOCKED;
+static int peer_pid;
+static unsigned int copy_range;
+static unsigned int queue_total;
+static struct sock *ipqnl;
+static LIST_HEAD(queue_list);
+static DECLARE_MUTEX(ipqnl_sem);
+
+static void
+ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
+{
+	nf_reinject(entry->skb, entry->info, verdict);
+	kfree(entry);
+}
+
+static inline int
+__ipq_enqueue_entry(struct ipq_queue_entry *entry)
+{
+       if (queue_total >= queue_maxlen) {
+               if (net_ratelimit()) 
+                       printk(KERN_WARNING "ip_queue: full at %d entries, "
+                              "dropping packet(s).\n", queue_total);
+               return -ENOSPC;
+       }
+       list_add(&entry->list, &queue_list);
+       queue_total++;
+       return 0;
+}
+
+/*
+ * Find and return a queued entry matched by cmpfn, or return the last
+ * entry if cmpfn is NULL.
+ */
+static inline struct ipq_queue_entry *
+__ipq_find_entry(ipq_cmpfn cmpfn, unsigned long data)
+{
+	struct list_head *p;
+
+	list_for_each_prev(p, &queue_list) {
+		struct ipq_queue_entry *entry = (struct ipq_queue_entry *)p;
+		
+		if (!cmpfn || cmpfn(entry, data))
+			return entry;
 	}
-	spin_unlock_bh(&q->lock);
 	return NULL;
 }
 
-/* Flush all packets */
-static void ipq_flush(ipq_queue_t *q)
+static inline void
+__ipq_dequeue_entry(struct ipq_queue_entry *entry)
 {
-	ipq_queue_element_t *e;
-	
-	spin_lock_bh(&q->lock);
-	q->flushing = 1;
-	spin_unlock_bh(&q->lock);
-	while ((e = ipq_dequeue(q, NULL, 0))) {
-		e->verdict = NF_DROP;
-		nf_reinject(e->skb, e->info, e->verdict);
-		kfree(e);
-	}
-	spin_lock_bh(&q->lock);
-	q->flushing = 0;
-	spin_unlock_bh(&q->lock);
-}
-
-static ipq_queue_t *ipq_create_queue(nf_queue_outfn_t outfn,
-                                     ipq_send_cb_t send_cb,
-                                     int *errp, int *sysctl_qmax)
+	list_del(&entry->list);
+	queue_total--;
+}
+
+static inline struct ipq_queue_entry *
+__ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
 {
-	int status;
-	ipq_queue_t *q;
+	struct ipq_queue_entry *entry;
 
-	*errp = 0;
-	q = kmalloc(sizeof(ipq_queue_t), GFP_KERNEL);
-	if (q == NULL) {
-		*errp = -ENOMEM;
+	entry = __ipq_find_entry(cmpfn, data);
+	if (entry == NULL)
 		return NULL;
+
+	__ipq_dequeue_entry(entry);
+	return entry;
+}
+
+
+static inline void
+__ipq_flush(int verdict)
+{
+	struct ipq_queue_entry *entry;
+	
+	while ((entry = __ipq_find_dequeue_entry(NULL, 0)))
+		ipq_issue_verdict(entry, verdict);
+}
+
+static inline int
+__ipq_set_mode(unsigned char mode, unsigned int range)
+{
+	int status = 0;
+	
+	switch(mode) {
+	case IPQ_COPY_NONE:
+	case IPQ_COPY_META:
+		copy_mode = mode;
+		copy_range = 0;
+		break;
+		
+	case IPQ_COPY_PACKET:
+		copy_mode = mode;
+		copy_range = range;
+		if (copy_range > 0xFFFF)
+			copy_range = 0xFFFF;
+		break;
+		
+	default:
+		status = -EINVAL;
+
 	}
-	q->peer.pid = 0;
-	q->peer.died = 0;
-	q->peer.copy_mode = IPQ_COPY_NONE;
-	q->peer.copy_range = 0;
-	q->peer.send = send_cb;
-	q->len = 0;
-	q->maxlen = sysctl_qmax;
-	q->flushing = 0;
-	q->terminate = 0;
-	INIT_LIST_HEAD(&q->list);
-	spin_lock_init(&q->lock);
-	status = nf_register_queue_handler(PF_INET, outfn, q);
-	if (status < 0) {
-		*errp = -EBUSY;
-		kfree(q);
+	return status;
+}
+
+static inline void
+__ipq_reset(void)
+{
+	peer_pid = 0;
+	__ipq_set_mode(IPQ_COPY_NONE, 0);
+	__ipq_flush(NF_DROP);
+}
+
+static struct ipq_queue_entry *
+ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
+{
+	struct ipq_queue_entry *entry;
+	
+	write_lock_bh(&queue_lock);
+	entry = __ipq_find_dequeue_entry(cmpfn, data);
+	write_unlock_bh(&queue_lock);
+	return entry;
+}
+
+static void
+ipq_flush(int verdict)
+{
+	write_lock_bh(&queue_lock);
+	__ipq_flush(verdict);
+	write_unlock_bh(&queue_lock);
+}
+
+static struct sk_buff *
+ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
+{
+	unsigned char *old_tail;
+	size_t size = 0;
+	size_t data_len = 0;
+	struct sk_buff *skb;
+	struct ipq_packet_msg *pmsg;
+	struct nlmsghdr *nlh;
+
+	read_lock_bh(&queue_lock);
+	
+	switch (copy_mode) {
+	case IPQ_COPY_META:
+	case IPQ_COPY_NONE:
+		size = NLMSG_SPACE(sizeof(*pmsg));
+		data_len = 0;
+		break;
+	
+	case IPQ_COPY_PACKET:
+		if (copy_range == 0 || copy_range > entry->skb->len)
+			data_len = entry->skb->len;
+		else
+			data_len = copy_range;
+		
+		size = NLMSG_SPACE(sizeof(*pmsg) + data_len);
+		break;
+	
+	default:
+		*errp = -EINVAL;
+		read_unlock_bh(&queue_lock);
 		return NULL;
 	}
-	return q;
+
+	read_unlock_bh(&queue_lock);
+
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		goto nlmsg_failure;
+		
+	old_tail= skb->tail;
+	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
+	pmsg = NLMSG_DATA(nlh);
+	memset(pmsg, 0, sizeof(*pmsg));
+
+	pmsg->packet_id       = (unsigned long )entry;
+	pmsg->data_len        = data_len;
+	pmsg->timestamp_sec   = entry->skb->stamp.tv_sec;
+	pmsg->timestamp_usec  = entry->skb->stamp.tv_usec;
+	pmsg->mark            = entry->skb->nfmark;
+	pmsg->hook            = entry->info->hook;
+	pmsg->hw_protocol     = entry->skb->protocol;
+	
+	if (entry->info->indev)
+		strcpy(pmsg->indev_name, entry->info->indev->name);
+	else
+		pmsg->indev_name[0] = '\0';
+	
+	if (entry->info->outdev)
+		strcpy(pmsg->outdev_name, entry->info->outdev->name);
+	else
+		pmsg->outdev_name[0] = '\0';
+	
+	if (entry->info->indev && entry->skb->dev) {
+		pmsg->hw_type = entry->skb->dev->type;
+		if (entry->skb->dev->hard_header_parse)
+			pmsg->hw_addrlen =
+				entry->skb->dev->hard_header_parse(entry->skb,
+				                                   pmsg->hw_addr);
+	}
+	
+	if (data_len)
+		memcpy(pmsg->payload, entry->skb->data, data_len);
+		
+	nlh->nlmsg_len = skb->tail - old_tail;
+	return skb;
+
+nlmsg_failure:
+	if (skb)
+		kfree_skb(skb);
+	*errp = -EINVAL;
+	printk(KERN_ERR "ip_queue: error creating packet message\n");
+	return NULL;
 }
 
-static int ipq_enqueue(ipq_queue_t *q,
-                       struct sk_buff *skb, struct nf_info *info)
+static int
+ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data)
 {
-	ipq_queue_element_t *e;
-	int status;
-	
-	e = kmalloc(sizeof(*e), GFP_ATOMIC);
-	if (e == NULL) {
-		printk(KERN_ERR "ip_queue: OOM in enqueue\n");
+	int status = -EINVAL;
+	struct sk_buff *nskb;
+	struct ipq_queue_entry *entry;
+
+	if (copy_mode == IPQ_COPY_NONE)
+		return -EAGAIN;
+
+	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+	if (entry == NULL) {
+		printk(KERN_ERR "ip_queue: OOM in ipq_enqueue_packet()\n");
 		return -ENOMEM;
 	}
 
-	e->verdict = NF_DROP;
-	e->info = info;
-	e->skb = skb;
+	entry->info = info;
+	entry->skb = skb;
 
-	if (e->info->hook == NF_IP_LOCAL_OUT) {
+	if (entry->info->hook == NF_IP_LOCAL_OUT) {
 		struct iphdr *iph = skb->nh.iph;
 
-		e->rt_info.tos = iph->tos;
-		e->rt_info.daddr = iph->daddr;
-		e->rt_info.saddr = iph->saddr;
-	}
-
-	spin_lock_bh(&q->lock);
-	if (q->len >= *q->maxlen) {
-		spin_unlock_bh(&q->lock);
-		if (net_ratelimit()) 
-			printk(KERN_WARNING "ip_queue: full at %d entries, "
-			       "dropping packet(s).\n", q->len);
-		goto free_drop;
-	}
-	if (q->flushing || q->peer.copy_mode == IPQ_COPY_NONE
-	    || q->peer.pid == 0 || q->peer.died || q->terminate) {
-		spin_unlock_bh(&q->lock);
-		goto free_drop;
-	}
-	status = q->peer.send(e);
-	if (status > 0) {
-		list_add(&e->list, &q->list);
-		q->len++;
-		spin_unlock_bh(&q->lock);
-		return status;
-	}
-	spin_unlock_bh(&q->lock);
-	if (status == -ECONNREFUSED) {
-		printk(KERN_INFO "ip_queue: peer %d died, "
-		       "resetting state and flushing queue\n", q->peer.pid);
-			q->peer.died = 1;
-			q->peer.pid = 0;
-			q->peer.copy_mode = IPQ_COPY_NONE;
-			q->peer.copy_range = 0;
-			ipq_flush(q);
-	}
-free_drop:
-	kfree(e);
-	return -EBUSY;
-}
+		entry->rt_info.tos = iph->tos;
+		entry->rt_info.daddr = iph->daddr;
+		entry->rt_info.saddr = iph->saddr;
+	}
 
-static void ipq_destroy_queue(ipq_queue_t *q)
-{
-	nf_unregister_queue_handler(PF_INET);
-	spin_lock_bh(&q->lock);
-	q->terminate = 1;
-	spin_unlock_bh(&q->lock);
-	ipq_flush(q);
-	kfree(q);
+	nskb = ipq_build_packet_message(entry, &status);
+	if (nskb == NULL)
+		goto err_out_free;
+		
+	write_lock_bh(&queue_lock);
+	
+	if (!peer_pid)
+		goto err_out_unlock;
+
+	status = netlink_unicast(ipqnl, nskb, peer_pid, MSG_DONTWAIT);
+	if (status < 0)
+		goto err_out_unlock;
+	
+	status = __ipq_enqueue_entry(entry);
+	if (status < 0)
+		goto err_out_unlock;
+
+	write_unlock_bh(&queue_lock);
+	return status;
+	
+err_out_unlock:
+	write_unlock_bh(&queue_lock);
+
+err_out_free:
+	kfree(entry);
+	return status;
 }
 
-static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e)
+static int
+ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
 {
 	int diff;
 	struct iphdr *user_iph = (struct iphdr *)v->payload;
@@ -266,296 +372,216 @@
 	return 0;
 }
 
-static inline int id_cmp(ipq_queue_element_t *e, unsigned long id)
+static inline int
+id_cmp(struct ipq_queue_entry *e, unsigned long id)
 {
 	return (id == (unsigned long )e);
 }
 
-static int ipq_set_verdict(ipq_queue_t *q,
-                           ipq_verdict_msg_t *v, unsigned int len)
+static int
+ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
 {
-	ipq_queue_element_t *e;
+	struct ipq_queue_entry *entry;
 
-	if (v->value > NF_MAX_VERDICT)
+	if (vmsg->value > NF_MAX_VERDICT)
 		return -EINVAL;
-	e = ipq_dequeue(q, id_cmp, v->id);
-	if (e == NULL)
+
+	entry = ipq_find_dequeue_entry(id_cmp, vmsg->id);
+	if (entry == NULL)
 		return -ENOENT;
 	else {
-		e->verdict = v->value;
-		if (v->data_len && v->data_len == len)
-			if (ipq_mangle_ipv4(v, e) < 0)
-				e->verdict = NF_DROP;
-		nf_reinject(e->skb, e->info, e->verdict);
-		kfree(e);
+		int verdict = vmsg->value;
+		
+		if (vmsg->data_len && vmsg->data_len == len)
+			if (ipq_mangle_ipv4(vmsg, entry) < 0)
+				verdict = NF_DROP;
+		
+		ipq_issue_verdict(entry, verdict);
 		return 0;
 	}
 }
 
-static int ipq_receive_peer(ipq_queue_t *q, ipq_peer_msg_t *m,
-                            unsigned char type, unsigned int len)
+static int
+ipq_set_mode(unsigned char mode, unsigned int range)
 {
+	int status;
+
+	write_lock_bh(&queue_lock);
+	status = __ipq_set_mode(mode, range);
+	write_unlock_bh(&queue_lock);
+	return status;
+}
 
+static int
+ipq_receive_peer(struct ipq_peer_msg *pmsg,
+                 unsigned char type, unsigned int len)
+{
 	int status = 0;
-	int busy;
-		
-	spin_lock_bh(&q->lock);
-	busy = (q->terminate || q->flushing);
-	spin_unlock_bh(&q->lock);
-	if (busy)
-		return -EBUSY;
-	if (len < sizeof(ipq_peer_msg_t))
+
+	if (len < sizeof(*pmsg))
 		return -EINVAL;
+
 	switch (type) {
-		case IPQM_MODE:
-			switch (m->msg.mode.value) {
-				case IPQ_COPY_META:
-					q->peer.copy_mode = IPQ_COPY_META;
-					q->peer.copy_range = 0;
-					break;
-				case IPQ_COPY_PACKET:
-					q->peer.copy_mode = IPQ_COPY_PACKET;
-					q->peer.copy_range = m->msg.mode.range;
-					if (q->peer.copy_range > 0xFFFF)
-						q->peer.copy_range = 0xFFFF;
-					break;
-				default:
-					status = -EINVAL;
-			}
-			break;
-		case IPQM_VERDICT:
-			if (m->msg.verdict.value > NF_MAX_VERDICT)
-				status = -EINVAL;
-			else
-				status = ipq_set_verdict(q,
-				                         &m->msg.verdict,
-				                         len - sizeof(*m));
+	case IPQM_MODE:
+		status = ipq_set_mode(pmsg->msg.mode.value,
+		                      pmsg->msg.mode.range);
+		break;
+		
+	case IPQM_VERDICT:
+		if (pmsg->msg.verdict.value > NF_MAX_VERDICT)
+			status = -EINVAL;
+		else
+			status = ipq_set_verdict(&pmsg->msg.verdict,
+			                         len - sizeof(*pmsg));
 			break;
-		default:
-			 status = -EINVAL;
+	default:
+		status = -EINVAL;
 	}
 	return status;
 }
 
-static inline int dev_cmp(ipq_queue_element_t *e, unsigned long ifindex)
+static int
+dev_cmp(struct ipq_queue_entry *entry, unsigned long ifindex)
 {
-	if (e->info->indev)
-		if (e->info->indev->ifindex == ifindex)
+	if (entry->info->indev)
+		if (entry->info->indev->ifindex == ifindex)
 			return 1;
-	if (e->info->outdev)
-		if (e->info->outdev->ifindex == ifindex)
+			
+	if (entry->info->outdev)
+		if (entry->info->outdev->ifindex == ifindex)
 			return 1;
+
 	return 0;
 }
 
-/* Drop any queued packets associated with device ifindex */
-static void ipq_dev_drop(ipq_queue_t *q, int ifindex)
+static void
+ipq_dev_drop(int ifindex)
 {
-	ipq_queue_element_t *e;
+	struct ipq_queue_entry *entry;
 	
-	while ((e = ipq_dequeue(q, dev_cmp, ifindex))) {
-		e->verdict = NF_DROP;
-		nf_reinject(e->skb, e->info, e->verdict);
-		kfree(e);
-	}
-}
-
-/****************************************************************************
- *
- * Netfilter interface
- *
- ****************************************************************************/
-
-/*
- * Packets arrive here from netfilter for queuing to userspace.
- * All of them must be fed back via nf_reinject() or Alexey will kill Rusty.
- */
-static int netfilter_receive(struct sk_buff *skb,
-                             struct nf_info *info, void *data)
-{
-	return ipq_enqueue((ipq_queue_t *)data, skb, info);
-}
-
-/****************************************************************************
- *
- * Netlink interface.
- *
- ****************************************************************************/
-
-static struct sock *nfnl = NULL;
-ipq_queue_t *nlq = NULL;
-
-static struct sk_buff *netlink_build_message(ipq_queue_element_t *e, int *errp)
-{
-	unsigned char *old_tail;
-	size_t size = 0;
-	size_t data_len = 0;
-	struct sk_buff *skb;
-	ipq_packet_msg_t *pm;
-	struct nlmsghdr *nlh;
-
-	switch (nlq->peer.copy_mode) {
-		size_t copy_range;
-
-		case IPQ_COPY_META:
-			size = NLMSG_SPACE(sizeof(*pm));
-			data_len = 0;
-			break;
-		case IPQ_COPY_PACKET:
-			copy_range = nlq->peer.copy_range;
-			if (copy_range == 0 || copy_range > e->skb->len)
-				data_len = e->skb->len;
-			else
-				data_len = copy_range;
-			size = NLMSG_SPACE(sizeof(*pm) + data_len);
-			
-			break;
-		case IPQ_COPY_NONE:
-		default:
-			*errp = -EINVAL;
-			return NULL;
-	}
-	skb = alloc_skb(size, GFP_ATOMIC);
-	if (!skb)
-		goto nlmsg_failure;
-	old_tail = skb->tail;
-	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
-	pm = NLMSG_DATA(nlh);
-	memset(pm, 0, sizeof(*pm));
-	pm->packet_id = (unsigned long )e;
-	pm->data_len = data_len;
-	pm->timestamp_sec = e->skb->stamp.tv_sec;
-	pm->timestamp_usec = e->skb->stamp.tv_usec;
-	pm->mark = e->skb->nfmark;
-	pm->hook = e->info->hook;
-	if (e->info->indev) strcpy(pm->indev_name, e->info->indev->name);
-	else pm->indev_name[0] = '\0';
-	if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
-	else pm->outdev_name[0] = '\0';
-	pm->hw_protocol = e->skb->protocol;
-	if (e->info->indev && e->skb->dev) {
-		pm->hw_type = e->skb->dev->type;
-		if (e->skb->dev->hard_header_parse)
-			pm->hw_addrlen =
-				e->skb->dev->hard_header_parse(e->skb,
-				                               pm->hw_addr);
-	}
-	if (data_len)
-		memcpy(pm->payload, e->skb->data, data_len);
-	nlh->nlmsg_len = skb->tail - old_tail;
-	NETLINK_CB(skb).dst_groups = 0;
-	return skb;
-nlmsg_failure:
-	if (skb)
-		kfree_skb(skb);
-	*errp = 0;
-	printk(KERN_ERR "ip_queue: error creating netlink message\n");
-	return NULL;
-}
-
-static int netlink_send_peer(ipq_queue_element_t *e)
-{
-	int status = 0;
-	struct sk_buff *skb;
-
-	skb = netlink_build_message(e, &status);
-	if (skb == NULL)
-		return status;
-	return netlink_unicast(nfnl, skb, nlq->peer.pid, MSG_DONTWAIT);
+	while ((entry = ipq_find_dequeue_entry(dev_cmp, ifindex)) != NULL)
+		ipq_issue_verdict(entry, NF_DROP);
 }
 
 #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
 
-static __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
+static inline void
+ipq_rcv_skb(struct sk_buff *skb)
 {
-	int status, type;
+	int status, type, pid, flags, nlmsglen, skblen;
 	struct nlmsghdr *nlh;
 
-	if (skb->len < sizeof(struct nlmsghdr))
+	skblen = skb->len;
+	if (skblen < sizeof(*nlh))
 		return;
 
 	nlh = (struct nlmsghdr *)skb->data;
-	if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
-	    || skb->len < nlh->nlmsg_len)
-	    	return;
-
-	if(nlh->nlmsg_pid <= 0
-	    || !(nlh->nlmsg_flags & NLM_F_REQUEST)
-	    || nlh->nlmsg_flags & NLM_F_MULTI)
+	nlmsglen = nlh->nlmsg_len;
+	if (nlmsglen < sizeof(*nlh) || skblen < nlmsglen)
+		return;
+
+	pid = nlh->nlmsg_pid;
+	flags = nlh->nlmsg_flags;
+	
+	if(pid <= 0 || !(flags & NLM_F_REQUEST) || flags & NLM_F_MULTI)
 		RCV_SKB_FAIL(-EINVAL);
-	if (nlh->nlmsg_flags & MSG_TRUNC)
+		
+	if (flags & MSG_TRUNC)
 		RCV_SKB_FAIL(-ECOMM);
+		
 	type = nlh->nlmsg_type;
 	if (type < NLMSG_NOOP || type >= IPQM_MAX)
 		RCV_SKB_FAIL(-EINVAL);
+		
 	if (type <= IPQM_BASE)
 		return;
+		
 	if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
 		RCV_SKB_FAIL(-EPERM);
-	if (nlq->peer.pid && !nlq->peer.died
-	    && (nlq->peer.pid != nlh->nlmsg_pid)) {
-	    	printk(KERN_WARNING "ip_queue: peer pid changed from %d to "
-	    	      "%d, flushing queue\n", nlq->peer.pid, nlh->nlmsg_pid);
-		ipq_flush(nlq);
-	}	
-	nlq->peer.pid = nlh->nlmsg_pid;
-	nlq->peer.died = 0;
-	status = ipq_receive_peer(nlq, NLMSG_DATA(nlh),
-	                          type, skb->len - NLMSG_LENGTH(0));
+	
+	write_lock_bh(&queue_lock);
+	
+	if (peer_pid) {
+		if (peer_pid != pid) {
+			write_unlock_bh(&queue_lock);
+			RCV_SKB_FAIL(-EBUSY);
+		}
+	}
+	else
+		peer_pid = pid;
+		
+	write_unlock_bh(&queue_lock);
+	
+	status = ipq_receive_peer(NLMSG_DATA(nlh), type,
+	                          skblen - NLMSG_LENGTH(0));
 	if (status < 0)
 		RCV_SKB_FAIL(status);
-	if (nlh->nlmsg_flags & NLM_F_ACK)
+		
+	if (flags & NLM_F_ACK)
 		netlink_ack(skb, nlh, 0);
         return;
 }
 
-/* Note: we are only dealing with single part messages at the moment. */
-static void netlink_receive_user_sk(struct sock *sk, int len)
+static void
+ipq_rcv_sk(struct sock *sk, int len)
 {
 	do {
 		struct sk_buff *skb;
 
-		if (rtnl_shlock_nowait())
+		if (down_trylock(&ipqnl_sem))
 			return;
+			
 		while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
-			netlink_receive_user_skb(skb);
+			ipq_rcv_skb(skb);
 			kfree_skb(skb);
 		}
-		up(&rtnl_sem);
-	} while (nfnl && nfnl->receive_queue.qlen);
-}
+		
+		up(&ipqnl_sem);
 
-/****************************************************************************
- *
- * System events
- *
- ****************************************************************************/
+	} while (ipqnl && ipqnl->receive_queue.qlen);
+}
 
-static int receive_event(struct notifier_block *this,
-                         unsigned long event, void *ptr)
+static int
+ipq_rcv_dev_event(struct notifier_block *this,
+                  unsigned long event, void *ptr)
 {
 	struct net_device *dev = ptr;
 
 	/* Drop any packets associated with the downed device */
 	if (event == NETDEV_DOWN)
-		ipq_dev_drop(nlq, dev->ifindex);
+		ipq_dev_drop(dev->ifindex);
 	return NOTIFY_DONE;
 }
 
-struct notifier_block ipq_dev_notifier = {
-	receive_event,
+static struct notifier_block ipq_dev_notifier = {
+	ipq_rcv_dev_event,
 	NULL,
 	0
 };
 
-/****************************************************************************
- *
- * Sysctl - queue tuning.
- *
- ****************************************************************************/
+static int
+ipq_rcv_nl_event(struct notifier_block *this,
+                 unsigned long event, void *ptr)
+{
+	struct netlink_notify *n = ptr;
+
+	if (event == NETLINK_URELEASE &&
+	    n->protocol == NETLINK_FIREWALL && n->pid) {
+		write_lock_bh(&queue_lock);
+		if (n->pid == peer_pid)
+			__ipq_reset();
+		write_unlock_bh(&queue_lock);
+	}
+	return NOTIFY_DONE;
+}
 
-static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
+static struct notifier_block ipq_nl_notifier = {
+	ipq_rcv_nl_event,
+	NULL,
+	0
+};
 
+static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
 static struct ctl_table_header *ipq_sysctl_header;
 
 static ctl_table ipq_table[] = {
@@ -574,35 +600,27 @@
 	{ 0 }
 };
 
-/****************************************************************************
- *
- * Procfs - debugging info.
- *
- ****************************************************************************/
-
-static int ipq_get_info(char *buffer, char **start, off_t offset, int length)
+static int
+ipq_get_info(char *buffer, char **start, off_t offset, int length)
 {
 	int len;
 
-	spin_lock_bh(&nlq->lock);
+	read_lock_bh(&queue_lock);
+	
 	len = sprintf(buffer,
-	              "Peer pid            : %d\n"
-	              "Peer died           : %d\n"
-	              "Peer copy mode      : %d\n"
-	              "Peer copy range     : %Zu\n"
-	              "Queue length        : %d\n"
-	              "Queue max. length   : %d\n"
-	              "Queue flushing      : %d\n"
-	              "Queue terminate     : %d\n",
-	              nlq->peer.pid,
-	              nlq->peer.died,
-	              nlq->peer.copy_mode,
-	              nlq->peer.copy_range,
-	              nlq->len,
-	              *nlq->maxlen,
-	              nlq->flushing,
-	              nlq->terminate);
-	spin_unlock_bh(&nlq->lock);
+	              "Peer PID          : %d\n"
+	              "Copy mode         : %hu\n"
+	              "Copy range        : %u\n"
+	              "Queue length      : %u\n"
+	              "Queue max. length : %u\n",
+	              peer_pid,
+	              copy_mode,
+	              copy_range,
+	              queue_total,
+	              queue_maxlen);
+
+	read_unlock_bh(&queue_lock);
+	
 	*start = buffer + offset;
 	len -= offset;
 	if (len > length)
@@ -612,53 +630,74 @@
 	return len;
 }
 
-/****************************************************************************
- *
- * Module stuff.
- *
- ****************************************************************************/
-
-static int __init init(void)
+static int
+init_or_cleanup(int init)
 {
-	int status = 0;
+	int status = -ENOMEM;
 	struct proc_dir_entry *proc;
 	
-	nfnl = netlink_kernel_create(NETLINK_FIREWALL, netlink_receive_user_sk);
-	if (nfnl == NULL) {
-		printk(KERN_ERR "ip_queue: initialisation failed: unable to "
-		       "create kernel netlink socket\n");
-		return -ENOMEM;
-	}
-	nlq = ipq_create_queue(netfilter_receive,
-	                       netlink_send_peer, &status, &sysctl_maxlen);
-	if (nlq == NULL) {
-		printk(KERN_ERR "ip_queue: initialisation failed: unable to "
-		       "create queue\n");
-		sock_release(nfnl->socket);
-		return status;
+	if (!init)
+		goto cleanup;
+
+	netlink_register_notifier(&ipq_nl_notifier);
+	ipqnl = netlink_kernel_create(NETLINK_FIREWALL, ipq_rcv_sk);
+	if (ipqnl == NULL) {
+		printk(KERN_ERR "ip_queue: failed to create netlink socket\n");
+		goto cleanup_netlink_notifier;
 	}
+
 	proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ipq_get_info);
-	if (proc) proc->owner = THIS_MODULE;
+	if (proc)
+		proc->owner = THIS_MODULE;
 	else {
-		ipq_destroy_queue(nlq);
-		sock_release(nfnl->socket);
-		return -ENOMEM;
+		printk(KERN_ERR "ip_queue: failed to create proc entry\n");
+		goto cleanup_ipqnl;
 	}
+	
 	register_netdevice_notifier(&ipq_dev_notifier);
 	ipq_sysctl_header = register_sysctl_table(ipq_root_table, 0);
+	
+	status = nf_register_queue_handler(PF_INET, ipq_enqueue_packet, NULL);
+	if (status < 0) {
+		printk(KERN_ERR "ip_queue: failed to register queue handler\n");
+		goto cleanup_sysctl;
+	}
+	return status;
+
+cleanup:
+	nf_unregister_queue_handler(PF_INET);
+	br_write_lock_bh(BR_NETPROTO_LOCK);
+	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	ipq_flush(NF_DROP);
+	
+cleanup_sysctl:
+	unregister_sysctl_table(ipq_sysctl_header);
+	unregister_netdevice_notifier(&ipq_dev_notifier);
+	proc_net_remove(IPQ_PROC_FS_NAME);
+	
+cleanup_ipqnl:
+	sock_release(ipqnl->socket);
+	down(&ipqnl_sem);
+	up(&ipqnl_sem);
+	
+cleanup_netlink_notifier:
+	netlink_unregister_notifier(&ipq_nl_notifier);
 	return status;
 }
 
+static int __init init(void)
+{
+	
+	return init_or_cleanup(1);
+}
+
 static void __exit fini(void)
 {
-	unregister_sysctl_table(ipq_sysctl_header);
-	proc_net_remove(IPQ_PROC_FS_NAME);
-	unregister_netdevice_notifier(&ipq_dev_notifier);
-	ipq_destroy_queue(nlq);
-	sock_release(nfnl->socket);
+	init_or_cleanup(0);
 }
 
 MODULE_DESCRIPTION("IPv4 packet queue handler");
+MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
 MODULE_LICENSE("GPL");
 
 module_init(init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ip_tables.c linux-2.4.20/net/ipv4/netfilter/ip_tables.c
--- linux-2.4.19/net/ipv4/netfilter/ip_tables.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ip_tables.c	2002-10-29 11:18:34.000000000 +0000
@@ -9,6 +9,7 @@
  * 	  a table
  */
 #include <linux/config.h>
+#include <linux/cache.h>
 #include <linux/skbuff.h>
 #include <linux/kmod.h>
 #include <linux/vmalloc.h>
@@ -97,7 +98,7 @@
 	unsigned int underflow[NF_IP_NUMHOOKS];
 
 	/* ipt_entry tables: one per CPU */
-	char entries[0] __attribute__((aligned(SMP_CACHE_BYTES)));
+	char entries[0] ____cacheline_aligned;
 };
 
 static LIST_HEAD(ipt_target);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ipchains_core.c linux-2.4.20/net/ipv4/netfilter/ipchains_core.c
--- linux-2.4.19/net/ipv4/netfilter/ipchains_core.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ipchains_core.c	2002-10-29 11:18:35.000000000 +0000
@@ -1252,7 +1252,7 @@
 		return NULL;
 	}
 
-	fwkern = kmalloc(SIZEOF_STRUCT_IP_FW_KERNEL, GFP_KERNEL);
+	fwkern = kmalloc(SIZEOF_STRUCT_IP_FW_KERNEL, GFP_ATOMIC);
 	if (!fwkern) {
 		duprintf("convert_ipfw: kmalloc failed!\n");
 		*errno = ENOMEM;
@@ -1779,4 +1779,4 @@
 #endif
 	return ret;
 }
-MODULE_LICENSE("BSD without advertisement clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ipt_DSCP.c linux-2.4.20/net/ipv4/netfilter/ipt_DSCP.c
--- linux-2.4.19/net/ipv4/netfilter/ipt_DSCP.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ipt_DSCP.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,108 @@
+/* iptables module for setting the IPv4 DSCP field, Version 1.8
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * See RFC2474 for a description of the DSCP field within the IP Header.
+ *
+ * ipt_DSCP.c,v 1.8 2002/08/06 18:41:57 laforge Exp
+*/
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_DSCP.h>
+
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IP tables DSCP modification module");
+MODULE_LICENSE("GPL");
+
+static unsigned int
+target(struct sk_buff **pskb,
+       unsigned int hooknum,
+       const struct net_device *in,
+       const struct net_device *out,
+       const void *targinfo,
+       void *userinfo)
+{
+	struct iphdr *iph = (*pskb)->nh.iph;
+	const struct ipt_DSCP_info *dinfo = targinfo;
+	u_int8_t sh_dscp = ((dinfo->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK);
+
+
+	if ((iph->tos & IPT_DSCP_MASK) != sh_dscp) {
+		u_int16_t diffs[2];
+
+		/* raw socket (tcpdump) may have clone of incoming
+		 * skb: don't disturb it --RR */
+		if (skb_cloned(*pskb) && !(*pskb)->sk) {
+			struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+			if (!nskb)
+				return NF_DROP;
+			kfree_skb(*pskb);
+			*pskb = nskb;
+			iph = (*pskb)->nh.iph;
+		}
+
+		diffs[0] = htons(iph->tos) ^ 0xFFFF;
+		iph->tos = (iph->tos & ~IPT_DSCP_MASK) | sh_dscp;
+		diffs[1] = htons(iph->tos);
+		iph->check = csum_fold(csum_partial((char *)diffs,
+		                                    sizeof(diffs),
+		                                    iph->check^0xFFFF));
+		(*pskb)->nfcache |= NFC_ALTERED;
+	}
+	return IPT_CONTINUE;
+}
+
+static int
+checkentry(const char *tablename,
+	   const struct ipt_entry *e,
+           void *targinfo,
+           unsigned int targinfosize,
+           unsigned int hook_mask)
+{
+	const u_int8_t dscp = ((struct ipt_DSCP_info *)targinfo)->dscp;
+
+	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_DSCP_info))) {
+		printk(KERN_WARNING "DSCP: targinfosize %u != %Zu\n",
+		       targinfosize,
+		       IPT_ALIGN(sizeof(struct ipt_DSCP_info)));
+		return 0;
+	}
+
+	if (strcmp(tablename, "mangle") != 0) {
+		printk(KERN_WARNING "DSCP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
+		return 0;
+	}
+
+	if ((dscp > IPT_DSCP_MAX)) {
+		printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_target ipt_dscp_reg
+= { { NULL, NULL }, "DSCP", target, checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	if (ipt_register_target(&ipt_dscp_reg))
+		return -EINVAL;
+
+	return 0;
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_target(&ipt_dscp_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ipt_ECN.c linux-2.4.20/net/ipv4/netfilter/ipt_ECN.c
--- linux-2.4.19/net/ipv4/netfilter/ipt_ECN.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ipt_ECN.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,183 @@
+/* iptables module for the IPv4 and TCP ECN bits, Version 1.2
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ * 
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * ipt_ECN.c,v 1.4 2002/08/05 19:36:51 laforge Exp
+*/
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_ECN.h>
+
+MODULE_LICENSE("GPL");
+
+/* set ECT codepoint from IP header.
+ * 	return 0 in case there was no ECT codepoint
+ * 	return 1 in case ECT codepoint has been overwritten
+ * 	return < 0 in case there was error */
+static int inline
+set_ect_ip(struct sk_buff **pskb, struct iphdr *iph,
+	   const struct ipt_ECN_info *einfo)
+{
+	if ((iph->tos & IPT_ECN_IP_MASK)
+	    != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
+		u_int16_t diffs[2];
+
+		/* raw socket (tcpdump) may have clone of incoming
+		 * skb: don't disturb it --RR */
+		if (skb_cloned(*pskb) && !(*pskb)->sk) {
+			struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+			if (!nskb)
+				return NF_DROP;
+			kfree_skb(*pskb);
+			*pskb = nskb;
+			iph = (*pskb)->nh.iph;
+		}
+
+		diffs[0] = htons(iph->tos) ^ 0xFFFF;
+		iph->tos = iph->tos & ~IPT_ECN_IP_MASK;
+		iph->tos = iph->tos | (einfo->ip_ect & IPT_ECN_IP_MASK);
+		diffs[1] = htons(iph->tos);
+		iph->check = csum_fold(csum_partial((char *)diffs,
+		                                    sizeof(diffs),
+		                                    iph->check^0xFFFF));
+		(*pskb)->nfcache |= NFC_ALTERED;
+
+		return 1;
+	} 
+	return 0;
+}
+
+static int inline
+set_ect_tcp(struct sk_buff **pskb, struct iphdr *iph,
+	    const struct ipt_ECN_info *einfo)
+{
+
+	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
+	u_int16_t *tcpflags = (u_int16_t *)tcph + 6;
+	u_int16_t diffs[2];
+
+	/* raw socket (tcpdump) may have clone of incoming
+	 * skb: don't disturb it --RR */
+	if (skb_cloned(*pskb) && !(*pskb)->sk) {
+		struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+		if (!nskb)
+			return NF_DROP;
+		kfree_skb(*pskb);
+		*pskb = nskb;
+		iph = (*pskb)->nh.iph;
+	}
+
+	diffs[0] = *tcpflags;
+
+	if (einfo->operation & IPT_ECN_OP_SET_ECE
+	    && tcph->ece != einfo->proto.tcp.ece) {
+		tcph->ece = einfo->proto.tcp.ece;
+	}
+
+	if (einfo->operation & IPT_ECN_OP_SET_CWR
+	    && tcph->cwr != einfo->proto.tcp.cwr) {
+		tcph->cwr = einfo->proto.tcp.cwr;
+	}
+	
+	if (diffs[0] != *tcpflags) {
+		diffs[0] = htons(diffs[0]) ^ 0xFFFF;
+		diffs[1] = htons(*tcpflags);
+		tcph->check = csum_fold(csum_partial((char *)diffs,
+		                                    sizeof(diffs),
+		                                    tcph->check^0xFFFF));
+		(*pskb)->nfcache |= NFC_ALTERED;
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static unsigned int
+target(struct sk_buff **pskb,
+       unsigned int hooknum,
+       const struct net_device *in,
+       const struct net_device *out,
+       const void *targinfo,
+       void *userinfo)
+{
+	struct iphdr *iph = (*pskb)->nh.iph;
+	const struct ipt_ECN_info *einfo = targinfo;
+
+	if (einfo->operation & IPT_ECN_OP_SET_IP)
+		set_ect_ip(pskb, iph, einfo);
+
+	if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR)
+	    && iph->protocol == IPPROTO_TCP)
+		set_ect_tcp(pskb, iph, einfo);
+
+	return IPT_CONTINUE;
+}
+
+static int
+checkentry(const char *tablename,
+	   const struct ipt_entry *e,
+           void *targinfo,
+           unsigned int targinfosize,
+           unsigned int hook_mask)
+{
+	const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo;
+
+	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ECN_info))) {
+		printk(KERN_WARNING "ECN: targinfosize %u != %Zu\n",
+		       targinfosize,
+		       IPT_ALIGN(sizeof(struct ipt_ECN_info)));
+		return 0;
+	}
+
+	if (strcmp(tablename, "mangle") != 0) {
+		printk(KERN_WARNING "ECN: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
+		return 0;
+	}
+
+	if (einfo->operation & IPT_ECN_OP_MASK) {
+		printk(KERN_WARNING "ECN: unsupported ECN operation %x\n",
+			einfo->operation);
+		return 0;
+	}
+	if (einfo->ip_ect & ~IPT_ECN_IP_MASK) {
+		printk(KERN_WARNING "ECN: new ECT codepoint %x out of mask\n",
+			einfo->ip_ect);
+		return 0;
+	}
+
+	if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR))
+	    && e->ip.proto != IPPROTO_TCP) {
+		printk(KERN_WARNING "ECN: cannot use TCP operations on a "
+		       "non-tcp rule\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_target ipt_ecn_reg
+= { { NULL, NULL }, "ECN", target, checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	if (ipt_register_target(&ipt_ecn_reg))
+		return -EINVAL;
+
+	return 0;
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_target(&ipt_ecn_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ipt_REJECT.c linux-2.4.20/net/ipv4/netfilter/ipt_REJECT.c
--- linux-2.4.19/net/ipv4/netfilter/ipt_REJECT.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ipt_REJECT.c	2002-10-29 11:18:35.000000000 +0000
@@ -75,6 +75,7 @@
 #ifdef CONFIG_NETFILTER_DEBUG
 	nskb->nf_debug = 0;
 #endif
+	nskb->nfmark = 0;
 
 	tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ipt_ULOG.c linux-2.4.20/net/ipv4/netfilter/ipt_ULOG.c
--- linux-2.4.19/net/ipv4/netfilter/ipt_ULOG.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ipt_ULOG.c	2002-10-29 11:18:48.000000000 +0000
@@ -10,6 +10,8 @@
  *            nlgroup now global (sysctl)
  * 2001/04/19 ulog-queue reworked, now fixed buffer size specified at
  * 	      module loadtime -HW
+ * 2002/07/07 remove broken nflog_rcv() function -HW
+ * 2002/08/29 fix shifted/unshifted nlgroup bug -HW
  *
  * Released under the terms of the GPL
  *
@@ -29,7 +31,7 @@
  *   Specify, after how many clock ticks (intel: 100 per second) the queue
  * should be flushed even if it is not full yet.
  *
- * ipt_ULOG.c,v 1.18 2002/04/16 07:33:00 laforge Exp
+ * ipt_ULOG.c,v 1.21 2002/08/29 10:54:34 laforge Exp
  */
 
 #include <linux/module.h>
@@ -48,8 +50,11 @@
 #include <linux/netfilter_ipv4/ipt_ULOG.h>
 #include <linux/netfilter_ipv4/lockhelp.h>
 #include <net/sock.h>
+#include <linux/bitops.h>
 
 MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IP tables userspace logging module");
 
 #define ULOG_NL_EVENT		111		/* Harald's favorite number */
 #define ULOG_MAXNLGROUPS	32		/* numer of nlgroups */
@@ -63,10 +68,6 @@
 
 #define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0)
 
-MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
-MODULE_DESCRIPTION("IP tables userspace logging module");
-
-
 static unsigned int nlbufsiz = 4096;
 MODULE_PARM(nlbufsiz, "i");
 MODULE_PARM_DESC(nlbufsiz, "netlink buffer size");
@@ -91,9 +92,9 @@
 DECLARE_LOCK(ulog_lock);	/* spinlock */
 
 /* send one ulog_buff_t to userspace */
-static void ulog_send(unsigned int nlgroup)
+static void ulog_send(unsigned int nlgroupnum)
 {
-	ulog_buff_t *ub = &ulog_buffers[nlgroup];
+	ulog_buff_t *ub = &ulog_buffers[nlgroupnum];
 
 	if (timer_pending(&ub->timer)) {
 		DEBUGP("ipt_ULOG: ulog_send: timer was pending, deleting\n");
@@ -104,10 +105,10 @@
 	if (ub->qlen > 1)
 		ub->lastnlh->nlmsg_type = NLMSG_DONE;
 
-	NETLINK_CB(ub->skb).dst_groups = nlgroup;
+	NETLINK_CB(ub->skb).dst_groups = (1 << nlgroupnum);
 	DEBUGP("ipt_ULOG: throwing %d packets to netlink mask %u\n",
 		ub->qlen, nlgroup);
-	netlink_broadcast(nflognl, ub->skb, 0, nlgroup, GFP_ATOMIC);
+	netlink_broadcast(nflognl, ub->skb, 0, (1 << nlgroupnum), GFP_ATOMIC);
 
 	ub->qlen = 0;
 	ub->skb = NULL;
@@ -128,11 +129,6 @@
 	UNLOCK_BH(&ulog_lock);
 }
 
-static void nflog_rcv(struct sock *sk, int len)
-{
-	printk("ipt_ULOG:nflog_rcv() did receive netlink message ?!?\n");
-}
-
 struct sk_buff *ulog_alloc_skb(unsigned int size)
 {
 	struct sk_buff *skb;
@@ -169,6 +165,11 @@
 	struct nlmsghdr *nlh;
 	struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
 
+	/* ffs == find first bit set, necessary because userspace
+	 * is already shifting groupnumber, but we need unshifted.
+	 * ffs() returns [1..32], we need [0..31] */
+	unsigned int groupnum = ffs(loginfo->nl_group) - 1;
+
 	/* calculate the size of the skb needed */
 	if ((loginfo->copy_range == 0) ||
 	    (loginfo->copy_range > (*pskb)->len)) {
@@ -179,7 +180,7 @@
 
 	size = NLMSG_SPACE(sizeof(*pm) + copy_len);
 
-	ub = &ulog_buffers[loginfo->nl_group];
+	ub = &ulog_buffers[groupnum];
 	
 	LOCK_BH(&ulog_lock);
 
@@ -191,7 +192,7 @@
 		/* either the queue len is too high or we don't have 
 		 * enough room in nlskb left. send it to userspace. */
 
-		ulog_send(loginfo->nl_group);
+		ulog_send(groupnum);
 
 		if (!(ub->skb = ulog_alloc_skb(size)))
 			goto alloc_failure;
@@ -325,7 +326,7 @@
 		ulog_buffers[i].timer.data = i;
 	}
 
-	nflognl = netlink_kernel_create(NETLINK_NFLOG, nflog_rcv);
+	nflognl = netlink_kernel_create(NETLINK_NFLOG, NULL);
 	if (!nflognl)
 		return -ENOMEM;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ipt_ah.c linux-2.4.20/net/ipv4/netfilter/ipt_ah.c
--- linux-2.4.19/net/ipv4/netfilter/ipt_ah.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ipt_ah.c	2002-10-29 11:18:49.000000000 +0000
@@ -91,12 +91,12 @@
 static struct ipt_match ah_match
 = { { NULL, NULL }, "ah", &match, &checkentry, NULL, THIS_MODULE };
 
-int __init init(void)
+static int __init init(void)
 {
 	return ipt_register_match(&ah_match);
 }
 
-void __exit cleanup(void)
+static void __exit cleanup(void)
 {
 	ipt_unregister_match(&ah_match);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ipt_conntrack.c linux-2.4.20/net/ipv4/netfilter/ipt_conntrack.c
--- linux-2.4.19/net/ipv4/netfilter/ipt_conntrack.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ipt_conntrack.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,123 @@
+/* Kernel module to match connection tracking information.
+ * Superset of Rusty's minimalistic state match.
+ * GPL (C) 2001  Marc Boucher (marc@mbsi.ca).
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_conntrack.h>
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct ipt_conntrack_info *sinfo = matchinfo;
+	struct ip_conntrack *ct;
+	enum ip_conntrack_info ctinfo;
+	unsigned int statebit;
+
+	ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
+
+#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
+
+	statebit = ct ? IPT_CONNTRACK_STATE_INVALID : IPT_CONNTRACK_STATE_BIT(ctinfo);
+	if(sinfo->flags & IPT_CONNTRACK_STATE) {
+		if (ct) {
+			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
+			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip)
+				statebit |= IPT_CONNTRACK_STATE_SNAT;
+
+			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip !=
+			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip)
+				statebit |= IPT_CONNTRACK_STATE_DNAT;
+		}
+
+		if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_PROTO) {
+		if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
+                	return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_STATUS) {
+		if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
+		unsigned long expires;
+
+		if(!ct)
+			return 0;
+
+		expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
+
+		if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
+			return 0;
+	}
+
+	return 1;
+}
+
+static int check(const char *tablename,
+		 const struct ipt_ip *ip,
+		 void *matchinfo,
+		 unsigned int matchsize,
+		 unsigned int hook_mask)
+{
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_conntrack_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ipt_match conntrack_match
+= { { NULL, NULL }, "conntrack", &match, &check, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	/* NULL if ip_conntrack not a module */
+	if (ip_conntrack_module)
+		__MOD_INC_USE_COUNT(ip_conntrack_module);
+	return ipt_register_match(&conntrack_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&conntrack_match);
+	if (ip_conntrack_module)
+		__MOD_DEC_USE_COUNT(ip_conntrack_module);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ipt_dscp.c linux-2.4.20/net/ipv4/netfilter/ipt_dscp.c
--- linux-2.4.19/net/ipv4/netfilter/ipt_dscp.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ipt_dscp.c	2002-10-29 11:18:34.000000000 +0000
@@ -0,0 +1,58 @@
+/* IP tables module for matching the value of the IPv4 DSCP field
+ *
+ * ipt_dscp.c,v 1.3 2002/08/05 19:00:21 laforge Exp
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This software is distributed under the terms  GNU GPL
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv4/ipt_dscp.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IP tables DSCP matching module");
+MODULE_LICENSE("GPL");
+
+static int match(const struct sk_buff *skb, const struct net_device *in,
+		 const struct net_device *out, const void *matchinfo,
+		 int offset, const void *hdr, u_int16_t datalen,
+		 int *hotdrop)
+{
+	const struct ipt_dscp_info *info = matchinfo;
+	const struct iphdr *iph = skb->nh.iph;
+
+	u_int8_t sh_dscp = ((info->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK);
+
+	return ((iph->tos&IPT_DSCP_MASK) == sh_dscp) ^ info->invert;
+}
+
+static int checkentry(const char *tablename, const struct ipt_ip *ip,
+		      void *matchinfo, unsigned int matchsize,
+		      unsigned int hook_mask)
+{
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_dscp_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ipt_match dscp_match = { { NULL, NULL }, "dscp", &match,
+		&checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_match(&dscp_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&dscp_match);
+
+}
+
+module_init(init);
+module_exit(fini);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ipt_ecn.c linux-2.4.20/net/ipv4/netfilter/ipt_ecn.c
--- linux-2.4.19/net/ipv4/netfilter/ipt_ecn.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ipt_ecn.c	2002-10-29 11:18:49.000000000 +0000
@@ -0,0 +1,118 @@
+/* IP tables module for matching the value of the IPv4 and TCP ECN bits
+ *
+ * ipt_ecn.c,v 1.3 2002/05/29 15:09:00 laforge Exp
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This software is distributed under the terms GNU GPL v2
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/tcp.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_ecn.h>
+
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IP tables ECN matching module");
+MODULE_LICENSE("GPL");
+
+static inline int match_ip(const struct sk_buff *skb,
+			   const struct iphdr *iph,
+			   const struct ipt_ecn_info *einfo)
+{
+	return ((iph->tos&IPT_ECN_IP_MASK) == einfo->ip_ect);
+}
+
+static inline int match_tcp(const struct sk_buff *skb,
+			    const struct iphdr *iph,
+			    const struct ipt_ecn_info *einfo)
+{
+	struct tcphdr *tcph = (void *)iph + iph->ihl*4;
+
+	if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
+		if (einfo->invert & IPT_ECN_OP_MATCH_ECE) {
+			if (tcph->ece == 1)
+				return 0;
+		} else {
+			if (tcph->ece == 0)
+				return 0;
+		}
+	}
+
+	if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
+		if (einfo->invert & IPT_ECN_OP_MATCH_CWR) {
+			if (tcph->cwr == 1)
+				return 0;
+		} else {
+			if (tcph->cwr == 0)
+				return 0;
+		}
+	}
+
+	return 1;
+}
+
+static int match(const struct sk_buff *skb, const struct net_device *in,
+		 const struct net_device *out, const void *matchinfo,
+		 int offset, const void *hdr, u_int16_t datalen,
+		 int *hotdrop)
+{
+	const struct ipt_ecn_info *info = matchinfo;
+	const struct iphdr *iph = skb->nh.iph;
+
+	if (info->operation & IPT_ECN_OP_MATCH_IP)
+		if (!match_ip(skb, iph, info))
+			return 0;
+
+	if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) {
+		if (iph->protocol != IPPROTO_TCP)
+			return 0;
+		if (!match_tcp(skb, iph, info))
+			return 0;
+	}
+
+	return 1;
+}
+
+static int checkentry(const char *tablename, const struct ipt_ip *ip,
+		      void *matchinfo, unsigned int matchsize,
+		      unsigned int hook_mask)
+{
+	const struct ipt_ecn_info *info = matchinfo;
+
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_ecn_info)))
+		return 0;
+
+	if (info->operation & IPT_ECN_OP_MATCH_MASK)
+		return 0;
+
+	if (info->invert & IPT_ECN_OP_MATCH_MASK)
+		return 0;
+
+	if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)
+	    && ip->proto != IPPROTO_TCP) {
+		printk(KERN_WARNING "ipt_ecn: can't match TCP bits in rule for"
+		       " non-tcp packets\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_match ecn_match = { { NULL, NULL }, "ecn", &match,
+		&checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_match(&ecn_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&ecn_match);
+}
+
+module_init(init);
+module_exit(fini);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ipt_helper.c linux-2.4.20/net/ipv4/netfilter/ipt_helper.c
--- linux-2.4.19/net/ipv4/netfilter/ipt_helper.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ipt_helper.c	2002-10-29 11:18:35.000000000 +0000
@@ -0,0 +1,112 @@
+/*
+ * iptables module to match on related connections
+ *   (c) 2001 Martin Josefsson <gandalf@wlug.westbo.se>
+ *
+ * Released under the terms of GNU GPLv2.
+ *
+ *   19 Mar 2002 Harald Welte <laforge@gnumonks.org>:
+ *   		 - Port to newnat infrastructure
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_helper.h>
+
+MODULE_LICENSE("GPL");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct ipt_helper_info *info = matchinfo;
+	struct ip_conntrack_expect *exp;
+	struct ip_conntrack *ct;
+	enum ip_conntrack_info ctinfo;
+	
+	ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
+	if (!ct) {
+		DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
+		return 0;
+	}
+
+	if (!ct->master) {
+		DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
+		return 0;
+	}
+
+	exp = ct->master;
+	if (!exp->expectant) {
+		DEBUGP("ipt_helper: expectation %p without expectant !?!\n", 
+			exp);
+		return 0;
+	}
+
+	if (!exp->expectant->helper) {
+		DEBUGP("ipt_helper: master ct %p has no helper\n", 
+			exp->expectant);
+		return 0;
+	}
+
+	DEBUGP("master's name = %s , info->name = %s\n", 
+		exp->expectant->helper->name, info->name);
+
+	return !strncmp(exp->expectant->helper->name, info->name, 
+			strlen(exp->expectant->helper->name)) ^ info->invert;
+}
+
+static int check(const char *tablename,
+		 const struct ipt_ip *ip,
+		 void *matchinfo,
+		 unsigned int matchsize,
+		 unsigned int hook_mask)
+{
+	struct ipt_helper_info *info = matchinfo;
+
+	info->name[29] = '\0';
+
+	/* verify size */
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_helper_info)))
+		return 0;
+
+	/* verify that we actually should match anything */
+	if ( strlen(info->name) == 0 )
+		return 0;
+	
+	return 1;
+}
+
+static struct ipt_match helper_match
+= { { NULL, NULL }, "helper", &match, &check, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	/* NULL if ip_conntrack not a module */
+	if (ip_conntrack_module)
+		__MOD_INC_USE_COUNT(ip_conntrack_module);
+	return ipt_register_match(&helper_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&helper_match);
+	if (ip_conntrack_module)
+		__MOD_DEC_USE_COUNT(ip_conntrack_module);
+}
+
+module_init(init);
+module_exit(fini);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ipt_owner.c linux-2.4.20/net/ipv4/netfilter/ipt_owner.c
--- linux-2.4.19/net/ipv4/netfilter/ipt_owner.c	2001-09-30 19:26:08.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ipt_owner.c	2002-10-29 11:18:38.000000000 +0000
@@ -12,6 +12,38 @@
 #include <linux/netfilter_ipv4/ip_tables.h>
 
 static int
+match_comm(const struct sk_buff *skb, const char *comm)
+{
+	struct task_struct *p;
+	struct files_struct *files;
+	int i;
+
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if(strncmp(p->comm, comm, sizeof(p->comm)))
+			continue;
+
+		task_lock(p);
+		files = p->files;
+		if(files) {
+			read_lock(&files->file_lock);
+			for (i=0; i < files->max_fds; i++) {
+				if (fcheck_files(files, i) == skb->sk->socket->file) {
+					read_unlock(&files->file_lock);
+					task_unlock(p);
+					read_unlock(&tasklist_lock);
+					return 1;
+				}
+			}
+			read_unlock(&files->file_lock);
+		}
+		task_unlock(p);
+	}
+	read_unlock(&tasklist_lock);
+	return 0;
+}
+
+static int
 match_pid(const struct sk_buff *skb, pid_t pid)
 {
 	struct task_struct *p;
@@ -115,6 +147,12 @@
 			return 0;
 	}
 
+	if(info->match & IPT_OWNER_COMM) {
+		if (!match_comm(skb, info->comm) ^
+		    !!(info->invert & IPT_OWNER_COMM))
+			return 0;
+	}
+
 	return 1;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ipt_pkttype.c linux-2.4.20/net/ipv4/netfilter/ipt_pkttype.c
--- linux-2.4.19/net/ipv4/netfilter/ipt_pkttype.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ipt_pkttype.c	2002-10-29 11:18:48.000000000 +0000
@@ -0,0 +1,59 @@
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+
+#include <linux/netfilter_ipv4/ipt_pkttype.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+MODULE_LICENSE("GPL");
+
+static int match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+    const struct ipt_pkttype_info *info = matchinfo;
+
+    return (skb->pkt_type == info->pkttype) ^ info->invert;
+}
+
+static int checkentry(const char *tablename,
+		   const struct ipt_ip *ip,
+		   void *matchinfo,
+		   unsigned int matchsize,
+		   unsigned int hook_mask)
+{
+/*
+	if (hook_mask
+	    & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN)
+		| (1 << NF_IP_FORWARD))) {
+		printk("ipt_pkttype: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
+		return 0;
+	}
+*/
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_pkttype_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ipt_match pkttype_match
+= { { NULL, NULL }, "pkttype", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_match(&pkttype_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&pkttype_match);
+}
+
+module_init(init);
+module_exit(fini);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/netfilter/ipt_unclean.c linux-2.4.20/net/ipv4/netfilter/ipt_unclean.c
--- linux-2.4.19/net/ipv4/netfilter/ipt_unclean.c	2001-12-21 17:42:05.000000000 +0000
+++ linux-2.4.20/net/ipv4/netfilter/ipt_unclean.c	2002-10-29 11:18:48.000000000 +0000
@@ -211,15 +211,14 @@
 
 	/* Bad checksum?  Don't print, just say it's unclean. */
 	/* FIXME: SRC ROUTE packets won't match checksum --RR */
-	if (!more_frags && !embedded
+	if (!more_frags && !embedded && udph->check
 	    && csum_tcpudp_magic(iph->saddr, iph->daddr, datalen, IPPROTO_UDP,
 				 csum_partial((char *)udph, datalen, 0)) != 0)
 		return 0;
 
-	/* CHECK: Ports can't be zero. */
-	if (!udph->source || !udph->dest) {
-		limpk("UDP zero ports %u/%u\n",
-		      ntohs(udph->source), ntohs(udph->dest));
+	/* CHECK: Destination port can't be zero. */
+	if (!udph->dest) {
+		limpk("UDP zero destination port\n");
 		return 0;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/proc.c linux-2.4.20/net/ipv4/proc.c
--- linux-2.4.19/net/ipv4/proc.c	2001-05-16 17:21:45.000000000 +0000
+++ linux-2.4.20/net/ipv4/proc.c	2002-10-29 11:18:31.000000000 +0000
@@ -128,7 +128,7 @@
 	len += sprintf (buffer + len,
 		"\nIcmp: InMsgs InErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps\n"
 		  "Icmp:");
-	for (i=0; i<offsetof(struct icmp_mib, __pad)/sizeof(unsigned long); i++)
+	for (i=0; i<offsetof(struct icmp_mib, dummy)/sizeof(unsigned long); i++)
 		len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)icmp_statistics, sizeof(struct icmp_mib), i));
 
 	len += sprintf (buffer + len,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/route.c linux-2.4.20/net/ipv4/route.c
--- linux-2.4.19/net/ipv4/route.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/route.c	2002-10-29 11:18:51.000000000 +0000
@@ -248,7 +248,8 @@
 				r->u.dst.__use,
 				0,
 				(unsigned long)r->rt_src,
-				(int)r->u.dst.advmss + 40,
+				(r->u.dst.advmss ?
+				 (int) r->u.dst.advmss + 40 : 0),
 				r->u.dst.window,
 				(int)((r->u.dst.rtt >> 3) + r->u.dst.rttvar),
 				r->key.tos,
@@ -1246,7 +1247,7 @@
 		return -EINVAL;
 
 	if (MULTICAST(saddr) || BADCLASS(saddr) || LOOPBACK(saddr) ||
-	    skb->protocol != __constant_htons(ETH_P_IP))
+	    skb->protocol != htons(ETH_P_IP))
 		goto e_inval;
 
 	if (ZERONET(saddr)) {
@@ -1457,7 +1458,7 @@
 	     inet_addr_onlink(out_dev, saddr, FIB_RES_GW(res))))
 		flags |= RTCF_DOREDIRECT;
 
-	if (skb->protocol != __constant_htons(ETH_P_IP)) {
+	if (skb->protocol != htons(ETH_P_IP)) {
 		/* Not IP (i.e. ARP). Do not create route, if it is
 		 * invalid for proxy arp. DNAT routes are always valid.
 		 */
@@ -1522,7 +1523,7 @@
 out:	return err;
 
 brd_input:
-	if (skb->protocol != __constant_htons(ETH_P_IP))
+	if (skb->protocol != htons(ETH_P_IP))
 		goto e_inval;
 
 	if (ZERONET(saddr))
@@ -2156,7 +2157,7 @@
 		err = -ENODEV;
 		if (!dev)
 			goto out;
-		skb->protocol	= __constant_htons(ETH_P_IP);
+		skb->protocol	= htons(ETH_P_IP);
 		skb->dev	= dev;
 		local_bh_disable();
 		err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev);
@@ -2418,10 +2419,15 @@
 #ifdef CONFIG_NET_CLS_ROUTE
 struct ip_rt_acct *ip_rt_acct;
 
+/* This code sucks.  But you should have seen it before! --RR */
+
+/* IP route accounting ptr for this logical cpu number. */
+#define IP_RT_ACCT_CPU(i) (ip_rt_acct + cpu_logical_map(i) * 256)
+
 static int ip_rt_acct_read(char *buffer, char **start, off_t offset,
 			   int length, int *eof, void *data)
 {
-	*start = buffer;
+	unsigned int i;
 
 	if ((offset & 3) || (length & 3))
 		return -EIO;
@@ -2435,35 +2441,18 @@
 		length = sizeof(struct ip_rt_acct) * 256 - offset;
 		*eof = 1;
 	}
-	if (length > 0) {
-		u32 *dst = (u32*)buffer;
-		u32 *src = (u32*)(((u8*)ip_rt_acct) + offset);
-
-		memcpy(dst, src, length);
-
-#ifdef CONFIG_SMP
-		if (smp_num_cpus > 1 || cpu_logical_map(0) != 0) {
-			int i;
-			int cnt = length / 4;
-
-			for (i = 0; i < smp_num_cpus; i++) {
-				int cpu = cpu_logical_map(i);
-				int k;
 
-				if (cpu == 0)
-					continue;
-
-				src = (u32*)(((u8*)ip_rt_acct) + offset +
-					cpu * 256 * sizeof(struct ip_rt_acct));
+	/* Copy first cpu. */
+	*start = buffer;
+	memcpy(buffer, IP_RT_ACCT_CPU(0), length);
 
-				for (k = 0; k < cnt; k++)
-					dst[k] += src[k];
-			}
-		}
-#endif
-		return length;
+	/* Add the other cpus in, one int at a time */
+	for (i = 1; i < smp_num_cpus; i++) {
+		unsigned int j;
+		for (j = 0; j < length/4; j++)
+			((u32*)buffer)[j] += ((u32*)IP_RT_ACCT_CPU(i))[j];
 	}
-	return 0;
+	return length;
 }
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/tcp.c linux-2.4.20/net/ipv4/tcp.c
--- linux-2.4.19/net/ipv4/tcp.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/tcp.c	2002-10-29 11:18:35.000000000 +0000
@@ -1508,7 +1508,7 @@
 			break;
 
 		/* We need to check signals first, to get correct SIGURG
-		 * handling. FIXME: Need to check this doesnt impact 1003.1g
+		 * handling. FIXME: Need to check this doesn't impact 1003.1g
 		 * and move it down to the bottom of the loop
 		 */
 		if (signal_pending(current)) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/tcp_diag.c linux-2.4.20/net/ipv4/tcp_diag.c
--- linux-2.4.19/net/ipv4/tcp_diag.c	2001-12-21 17:42:05.000000000 +0000
+++ linux-2.4.20/net/ipv4/tcp_diag.c	2002-10-29 11:18:40.000000000 +0000
@@ -69,7 +69,8 @@
 	r->id.tcpdiag_src[0] = sk->rcv_saddr;
 	r->id.tcpdiag_dst[0] = sk->daddr;
 	r->id.tcpdiag_if = sk->bound_dev_if;
-	*((struct sock **)&r->id.tcpdiag_cookie) = sk;
+	r->id.tcpdiag_cookie[0] = (u32)(unsigned long)sk;
+	r->id.tcpdiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
 
 	if (r->tcpdiag_state == TCP_TIME_WAIT) {
 		struct tcp_tw_bucket *tw = (struct tcp_tw_bucket*)sk;
@@ -229,7 +230,8 @@
 	err = -ESTALE;
 	if ((req->id.tcpdiag_cookie[0] != TCPDIAG_NOCOOKIE ||
 	     req->id.tcpdiag_cookie[1] != TCPDIAG_NOCOOKIE) &&
-	    sk != *((struct sock **)&req->id.tcpdiag_cookie[0]))
+	    ((u32)(unsigned long)sk != req->id.tcpdiag_cookie[0] ||
+	     (u32)((((unsigned long)sk) >> 31) >> 1) != req->id.tcpdiag_cookie[1]))
 		goto out;
 
 	err = -ENOMEM;
@@ -346,7 +348,7 @@
 				break;
 			if (sk->family == AF_INET6 && cond->family == AF_INET) {
 				if (addr[0] == 0 && addr[1] == 0 &&
-				    addr[2] == __constant_htonl(0xffff) &&
+				    addr[2] == htonl(0xffff) &&
 				    bitstring_match(addr+3, cond->addr, cond->prefix_len))
 					break;
 			}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/tcp_input.c linux-2.4.20/net/ipv4/tcp_input.c
--- linux-2.4.19/net/ipv4/tcp_input.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/tcp_input.c	2002-10-29 11:18:34.000000000 +0000
@@ -2083,8 +2083,8 @@
 	} else if (tp->tstamp_ok &&
 		   th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) {
 		__u32 *ptr = (__u32 *)(th + 1);
-		if (*ptr == __constant_ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
-					     | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
+		if (*ptr == ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+				  | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
 			tp->saw_tstamp = 1;
 			++ptr;
 			tp->rcv_tsval = ntohl(*ptr);
@@ -3252,8 +3252,8 @@
 			__u32 *ptr = (__u32 *)(th + 1);
 
 			/* No? Slow path! */
-			if (*ptr != __constant_ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
-						     | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP))
+			if (*ptr != ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+					   | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP))
 				goto slow_path;
 
 			tp->saw_tstamp = 1;
@@ -3266,17 +3266,24 @@
 			if ((s32)(tp->rcv_tsval - tp->ts_recent) < 0)
 				goto slow_path;
 
-			/* Predicted packet is in window by definition.
-			 * seq == rcv_nxt and rcv_wup <= rcv_nxt.
-			 * Hence, check seq<=rcv_wup reduces to:
+			/* DO NOT update ts_recent here, if checksum fails
+			 * and timestamp was corrupted part, it will result
+			 * in a hung connection since we will drop all
+			 * future packets due to the PAWS test.
 			 */
-			if (tp->rcv_nxt == tp->rcv_wup)
-				tcp_store_ts_recent(tp);
 		}
 
 		if (len <= tcp_header_len) {
 			/* Bulk data transfer: sender */
 			if (len == tcp_header_len) {
+				/* Predicted packet is in window by definition.
+				 * seq == rcv_nxt and rcv_wup <= rcv_nxt.
+				 * Hence, check seq<=rcv_wup reduces to:
+				 */
+				if (tcp_header_len ==
+				    (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) &&
+				    tp->rcv_nxt == tp->rcv_wup)
+					tcp_store_ts_recent(tp);
 				/* We know that such packets are checksummed
 				 * on entry.
 				 */
@@ -3302,12 +3309,30 @@
 					tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
 					NET_INC_STATS_BH(TCPHPHitsToUser);
 					eaten = 1;
+					/* Predicted packet is in window by definition.
+					 * seq == rcv_nxt and rcv_wup <= rcv_nxt.
+					 * Hence, check seq<=rcv_wup reduces to:
+					 */
+					if (tcp_header_len ==
+					    (sizeof(struct tcphdr) +
+					     TCPOLEN_TSTAMP_ALIGNED) &&
+					    tp->rcv_nxt == tp->rcv_wup)
+						tcp_store_ts_recent(tp);
 				}
 			}
 			if (!eaten) {
 				if (tcp_checksum_complete_user(sk, skb))
 					goto csum_error;
 
+				/* Predicted packet is in window by definition.
+				 * seq == rcv_nxt and rcv_wup <= rcv_nxt.
+				 * Hence, check seq<=rcv_wup reduces to:
+				 */
+				if (tcp_header_len ==
+				    (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) &&
+				    tp->rcv_nxt == tp->rcv_wup)
+					tcp_store_ts_recent(tp);
+
 				if ((int)skb->truesize > sk->forward_alloc)
 					goto step5;
 
@@ -3667,6 +3692,9 @@
 		if(th->ack)
 			return 1;
 
+		if(th->rst)
+			goto discard;
+
 		if(th->syn) {
 			if(tp->af_specific->conn_request(sk, skb) < 0)
 				return 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/tcp_ipv4.c linux-2.4.20/net/ipv4/tcp_ipv4.c
--- linux-2.4.19/net/ipv4/tcp_ipv4.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/tcp_ipv4.c	2002-10-29 11:18:36.000000000 +0000
@@ -1210,10 +1210,10 @@
 	arg.iov[0].iov_len  = sizeof(rep.th);
 	arg.n_iov = 1;
 	if (ts) {
-		rep.tsopt[0] = __constant_htonl((TCPOPT_NOP << 24) |
-						(TCPOPT_NOP << 16) |
-						(TCPOPT_TIMESTAMP << 8) |
-						TCPOLEN_TIMESTAMP);
+		rep.tsopt[0] = htonl((TCPOPT_NOP << 24) |
+				     (TCPOPT_NOP << 16) |
+				     (TCPOPT_TIMESTAMP << 8) |
+				     TCPOLEN_TIMESTAMP);
 		rep.tsopt[1] = htonl(tcp_time_stamp);
 		rep.tsopt[2] = htonl(ts);
 		arg.iov[0].iov_len = sizeof(rep);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/tcp_minisocks.c linux-2.4.20/net/ipv4/tcp_minisocks.c
--- linux-2.4.19/net/ipv4/tcp_minisocks.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/tcp_minisocks.c	2002-10-29 11:18:34.000000000 +0000
@@ -894,13 +894,13 @@
 	 *                  and the incoming segment acknowledges something not yet
 	 *                  sent (the segment carries an unaccaptable ACK) ...
 	 *                  a reset is sent."
+	 *
+	 * Invalid ACK: reset will be sent by listening socket
 	 */
-	if (!(flg & TCP_FLAG_ACK))
-		return NULL;
-
-	/* Invalid ACK: reset will be sent by listening socket */
-	if (TCP_SKB_CB(skb)->ack_seq != req->snt_isn+1)
+	if ((flg & TCP_FLAG_ACK) &&
+	    (TCP_SKB_CB(skb)->ack_seq != req->snt_isn+1))
 		return sk;
+
 	/* Also, it would be not so bad idea to check rcv_tsecr, which
 	 * is essentially ACK extension and too early or too late values
 	 * should cause reset in unsynchronized states.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv4/tcp_output.c linux-2.4.20/net/ipv4/tcp_output.c
--- linux-2.4.19/net/ipv4/tcp_output.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv4/tcp_output.c	2002-10-29 11:18:49.000000000 +0000
@@ -1010,8 +1010,7 @@
 			skb = alloc_skb(MAX_TCP_HEADER, GFP_KERNEL);
 			if (skb)
 				break;
-			current->policy |= SCHED_YIELD;
-			schedule();
+			yield();
 		}
 
 		/* Reserve space for headers and prepare control bits. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/addrconf.c linux-2.4.20/net/ipv6/addrconf.c
--- linux-2.4.19/net/ipv6/addrconf.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv6/addrconf.c	2002-10-29 11:18:38.000000000 +0000
@@ -26,6 +26,8 @@
  *						packets.
  *	yoshfuji@USAGI			:       Fixed interval between DAD
  *						packets.
+ *	YOSHIFUJI Hideaki @USAGI	:	improved accuracy of
+ *						address validation timer.
  */
 
 #include <linux/config.h>
@@ -93,6 +95,7 @@
 void addrconf_verify(unsigned long);
 
 static struct timer_list addr_chk_timer = { function: addrconf_verify };
+static spinlock_t addrconf_verify_lock = SPIN_LOCK_UNLOCKED;
 
 static int addrconf_ifdown(struct net_device *dev, int how);
 
@@ -141,14 +144,14 @@
 	/* Consider all addresses with the first three bits different of
 	   000 and 111 as unicasts.
 	 */
-	if ((st & __constant_htonl(0xE0000000)) != __constant_htonl(0x00000000) &&
-	    (st & __constant_htonl(0xE0000000)) != __constant_htonl(0xE0000000))
+	if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
+	    (st & htonl(0xE0000000)) != htonl(0xE0000000))
 		return IPV6_ADDR_UNICAST;
 
-	if ((st & __constant_htonl(0xFF000000)) == __constant_htonl(0xFF000000)) {
+	if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
 		int type = IPV6_ADDR_MULTICAST;
 
-		switch((st & __constant_htonl(0x00FF0000))) {
+		switch((st & htonl(0x00FF0000))) {
 			case __constant_htonl(0x00010000):
 				type |= IPV6_ADDR_LOOPBACK;
 				break;
@@ -164,24 +167,24 @@
 		return type;
 	}
 	
-	if ((st & __constant_htonl(0xFFC00000)) == __constant_htonl(0xFE800000))
+	if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
 		return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST);
 
-	if ((st & __constant_htonl(0xFFC00000)) == __constant_htonl(0xFEC00000))
+	if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
 		return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST);
 
 	if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
 		if (addr->s6_addr32[2] == 0) {
-			if (addr->in6_u.u6_addr32[3] == 0)
+			if (addr->s6_addr32[3] == 0)
 				return IPV6_ADDR_ANY;
 
-			if (addr->s6_addr32[3] == __constant_htonl(0x00000001))
+			if (addr->s6_addr32[3] == htonl(0x00000001))
 				return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST);
 
 			return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST);
 		}
 
-		if (addr->s6_addr32[2] == __constant_htonl(0x0000ffff))
+		if (addr->s6_addr32[2] == htonl(0x0000ffff))
 			return IPV6_ADDR_MAPPED;
 	}
 
@@ -752,7 +755,7 @@
 
 	memset(&rtmsg, 0, sizeof(rtmsg));
 	ipv6_addr_set(&rtmsg.rtmsg_dst,
-		      __constant_htonl(0xFF000000), 0, 0, 0);
+		      htonl(0xFF000000), 0, 0, 0);
 	rtmsg.rtmsg_dst_len = 8;
 	rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
 	rtmsg.rtmsg_ifindex = dev->ifindex;
@@ -782,7 +785,7 @@
 {
 	struct in6_addr addr;
 
-	ipv6_addr_set(&addr,  __constant_htonl(0xFE800000), 0, 0, 0);
+	ipv6_addr_set(&addr,  htonl(0xFE800000), 0, 0, 0);
 	addrconf_prefix_route(&addr, 10, dev, 0, RTF_ADDRCONF);
 }
 
@@ -1120,7 +1123,7 @@
 	memcpy(&addr.s6_addr32[3], idev->dev->dev_addr, 4);
 
 	if (idev->dev->flags&IFF_POINTOPOINT) {
-		addr.s6_addr32[0] = __constant_htonl(0xfe800000);
+		addr.s6_addr32[0] = htonl(0xfe800000);
 		scope = IFA_LINK;
 	} else {
 		scope = IPV6_ADDR_COMPATv4;
@@ -1187,7 +1190,7 @@
 	ASSERT_RTNL();
 
 	memset(&addr, 0, sizeof(struct in6_addr));
-	addr.s6_addr[15] = 1;
+	addr.s6_addr32[3] = htonl(0x00000001);
 
 	if ((idev = ipv6_find_idev(dev)) == NULL) {
 		printk(KERN_DEBUG "init loopback: add_dev failed\n");
@@ -1234,9 +1237,7 @@
 		return;
 
 	memset(&addr, 0, sizeof(struct in6_addr));
-
-	addr.s6_addr[0] = 0xFE;
-	addr.s6_addr[1] = 0x80;
+	addr.s6_addr32[0] = htonl(0xFE800000);
 
 	if (ipv6_generate_eui64(addr.s6_addr + 8, dev) == 0)
 		addrconf_add_linklocal(idev, &addr);
@@ -1272,9 +1273,8 @@
 int addrconf_notify(struct notifier_block *this, unsigned long event, 
 		    void * data)
 {
-	struct net_device *dev;
-
-	dev = (struct net_device *) data;
+	struct net_device *dev = (struct net_device *) data;
+	struct inet6_dev *idev = __in6_dev_get(dev);
 
 	switch(event) {
 	case NETDEV_UP:
@@ -1291,16 +1291,27 @@
 			addrconf_dev_config(dev);
 			break;
 		};
+		if (idev) {
+			/* If the MTU changed during the interface down, when the 
+			   interface up, the changed MTU must be reflected in the 
+			   idev as well as routers.
+			 */
+			if (idev->cnf.mtu6 != dev->mtu && dev->mtu >= IPV6_MIN_MTU) {
+				rt6_mtu_change(dev, dev->mtu);
+				idev->cnf.mtu6 = dev->mtu;
+			}
+			/* If the changed mtu during down is lower than IPV6_MIN_MTU
+			   stop IPv6 on this interface.
+			 */
+			if (dev->mtu < IPV6_MIN_MTU)
+				addrconf_ifdown(dev, event != NETDEV_DOWN);
+		}
 		break;
 
 	case NETDEV_CHANGEMTU:
-		if (dev->mtu >= IPV6_MIN_MTU) {
-			struct inet6_dev *idev;
-
-			if ((idev = __in6_dev_get(dev)) == NULL)
-				break;
-			idev->cnf.mtu6 = dev->mtu;
+		if ( idev && dev->mtu >= IPV6_MIN_MTU) {
 			rt6_mtu_change(dev, dev->mtu);
+			idev->cnf.mtu6 = dev->mtu;
 			break;
 		}
 
@@ -1616,9 +1627,15 @@
 void addrconf_verify(unsigned long foo)
 {
 	struct inet6_ifaddr *ifp;
-	unsigned long now = jiffies;
+	unsigned long now, next;
 	int i;
 
+	spin_lock_bh(&addrconf_verify_lock);
+	now = jiffies;
+	next = now + ADDR_CHECK_FREQUENCY;
+
+	del_timer(&addr_chk_timer);
+
 	for (i=0; i < IN6_ADDR_HSIZE; i++) {
 
 restart:
@@ -1629,21 +1646,27 @@
 			if (ifp->flags & IFA_F_PERMANENT)
 				continue;
 
+			spin_lock(&ifp->lock);
 			age = (now - ifp->tstamp) / HZ;
 
-			if (age > ifp->valid_lft) {
+			if (age >= ifp->valid_lft) {
+				spin_unlock(&ifp->lock);
 				in6_ifa_hold(ifp);
 				write_unlock(&addrconf_hash_lock);
 				ipv6_del_addr(ifp);
 				goto restart;
-			} else if (age > ifp->prefered_lft) {
+			} else if (age >= ifp->prefered_lft) {
+				/* jiffies - ifp->tsamp > age >= ifp->prefered_lft */
 				int deprecate = 0;
 
-				spin_lock(&ifp->lock);
 				if (!(ifp->flags&IFA_F_DEPRECATED)) {
 					deprecate = 1;
 					ifp->flags |= IFA_F_DEPRECATED;
 				}
+
+				if (time_before(ifp->tstamp + ifp->valid_lft * HZ, next))
+					next = ifp->tstamp + ifp->valid_lft * HZ;
+
 				spin_unlock(&ifp->lock);
 
 				if (deprecate) {
@@ -1654,12 +1677,19 @@
 					in6_ifa_put(ifp);
 					goto restart;
 				}
+			} else {
+				/* ifp->prefered_lft <= ifp->valid_lft */
+				if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
+					next = ifp->tstamp + ifp->prefered_lft * HZ;
+				spin_unlock(&ifp->lock);
 			}
 		}
 		write_unlock(&addrconf_hash_lock);
 	}
 
-	mod_timer(&addr_chk_timer, jiffies + ADDR_CHECK_FREQUENCY);
+	addr_chk_timer.expires = time_before(next, jiffies + HZ) ? jiffies + HZ : next;
+	add_timer(&addr_chk_timer);
+	spin_unlock_bh(&addrconf_verify_lock);
 }
 
 static int
@@ -2033,8 +2063,7 @@
 	proc_net_create("if_inet6", 0, iface_proc_info);
 #endif
 	
-	addr_chk_timer.expires = jiffies + ADDR_CHECK_FREQUENCY;
-	add_timer(&addr_chk_timer);
+	addrconf_verify(0);
 	rtnetlink_links[PF_INET6] = inet6_rtnetlink_table;
 #ifdef CONFIG_SYSCTL
 	addrconf_sysctl.sysctl_header =
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/datagram.c linux-2.4.20/net/ipv6/datagram.c
--- linux-2.4.19/net/ipv6/datagram.c	2001-09-07 18:01:21.000000000 +0000
+++ linux-2.4.20/net/ipv6/datagram.c	2002-10-29 11:18:33.000000000 +0000
@@ -147,7 +147,7 @@
 			}
 		} else {
 			ipv6_addr_set(&sin->sin6_addr, 0, 0,
-				      __constant_htonl(0xffff),
+				      htonl(0xffff),
 				      *(u32*)(skb->nh.raw + serr->addr_offset));
 		}
 	}
@@ -168,7 +168,7 @@
 			}
 		} else {
 			ipv6_addr_set(&sin->sin6_addr, 0, 0,
-				      __constant_htonl(0xffff),
+				      htonl(0xffff),
 				      skb->nh.iph->saddr);
 			if (sk->protinfo.af_inet.cmsg_flags)
 				ip_cmsg_recv(msg, skb);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/icmp.c linux-2.4.20/net/ipv6/icmp.c
--- linux-2.4.19/net/ipv6/icmp.c	2001-09-20 21:12:56.000000000 +0000
+++ linux-2.4.20/net/ipv6/icmp.c	2002-10-29 11:18:35.000000000 +0000
@@ -198,7 +198,7 @@
 		u8 type;
 		if (skb_copy_bits(skb, ptr+offsetof(struct icmp6hdr, icmp6_type),
 				  &type, 1)
-		    || !(type & 0x80))
+		    || !(type & ICMPV6_INFOMSG_MASK))
 			return 1;
 	}
 	return 0;
@@ -216,7 +216,7 @@
 	int res = 0;
 
 	/* Informational messages are not limited. */
-	if (type & 0x80)
+	if (type & ICMPV6_INFOMSG_MASK)
 		return 1;
 
 	/* Do not limit pmtu discovery, it would break it. */
@@ -519,22 +519,22 @@
 				    skb_checksum(skb, 0, skb->len, 0))) {
 			if (net_ratelimit())
 				printk(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
-				       ntohs(saddr->in6_u.u6_addr16[0]),
-				       ntohs(saddr->in6_u.u6_addr16[1]),
-				       ntohs(saddr->in6_u.u6_addr16[2]),
-				       ntohs(saddr->in6_u.u6_addr16[3]),
-				       ntohs(saddr->in6_u.u6_addr16[4]),
-				       ntohs(saddr->in6_u.u6_addr16[5]),
-				       ntohs(saddr->in6_u.u6_addr16[6]),
-				       ntohs(saddr->in6_u.u6_addr16[7]),
-				       ntohs(daddr->in6_u.u6_addr16[0]),
-				       ntohs(daddr->in6_u.u6_addr16[1]),
-				       ntohs(daddr->in6_u.u6_addr16[2]),
-				       ntohs(daddr->in6_u.u6_addr16[3]),
-				       ntohs(daddr->in6_u.u6_addr16[4]),
-				       ntohs(daddr->in6_u.u6_addr16[5]),
-				       ntohs(daddr->in6_u.u6_addr16[6]),
-				       ntohs(daddr->in6_u.u6_addr16[7]));
+				       ntohs(saddr->s6_addr16[0]),
+				       ntohs(saddr->s6_addr16[1]),
+				       ntohs(saddr->s6_addr16[2]),
+				       ntohs(saddr->s6_addr16[3]),
+				       ntohs(saddr->s6_addr16[4]),
+				       ntohs(saddr->s6_addr16[5]),
+				       ntohs(saddr->s6_addr16[6]),
+				       ntohs(saddr->s6_addr16[7]),
+				       ntohs(daddr->s6_addr16[0]),
+				       ntohs(daddr->s6_addr16[1]),
+				       ntohs(daddr->s6_addr16[2]),
+				       ntohs(daddr->s6_addr16[3]),
+				       ntohs(daddr->s6_addr16[4]),
+				       ntohs(daddr->s6_addr16[5]),
+				       ntohs(daddr->s6_addr16[6]),
+				       ntohs(daddr->s6_addr16[7]));
 			goto discard_it;
 		}
 	}
@@ -613,7 +613,7 @@
 			printk(KERN_DEBUG "icmpv6: msg of unkown type\n");
 
 		/* informational */
-		if (type & 0x80)
+		if (type & ICMPV6_INFOMSG_MASK)
 			break;
 
 		/* 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/ip6_fib.c linux-2.4.20/net/ipv6/ip6_fib.c
--- linux-2.4.19/net/ipv6/ip6_fib.c	2001-12-21 17:42:05.000000000 +0000
+++ linux-2.4.20/net/ipv6/ip6_fib.c	2002-10-29 11:18:35.000000000 +0000
@@ -13,6 +13,12 @@
  *      2 of the License, or (at your option) any later version.
  */
 
+/*
+ * 	Changes:
+ * 	Yuji SEKIYA @USAGI:	Support default route on router node;
+ * 				remove ip6_null_entry from the top of
+ * 				routing table.
+ */
 #include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -248,9 +254,6 @@
 
 	fn = root;
 
-	if (plen == 0)
-		return fn;
-
 	do {
 		key = (struct rt6key *)((u8 *)fn->leaf + offset);
 
@@ -427,6 +430,17 @@
 
 	ins = &fn->leaf;
 
+	if (fn->fn_flags&RTN_TL_ROOT &&
+	    fn->leaf == &ip6_null_entry &&
+	    !(rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF | RTF_ALLONLINK)) ){
+		/*
+		 * The top fib of ip6 routing table includes ip6_null_entry.
+		 */
+		fn->leaf = rt;
+		rt->u.next = NULL;
+		goto out;
+	}
+
 	for (iter = fn->leaf; iter; iter=iter->u.next) {
 		/*
 		 *	Search for duplicates
@@ -462,6 +476,7 @@
 	 *	insert node
 	 */
 
+out:
 	rt->u.next = iter;
 	*ins = rt;
 	rt->rt6i_node = fn;
@@ -675,7 +690,7 @@
 
 	fn = fib6_lookup_1(root, args);
 
-	if (fn == NULL)
+	if (fn == NULL || fn->fn_flags & RTN_TL_ROOT)
 		fn = root;
 
 	return fn;
@@ -897,6 +912,9 @@
 
 	rt->u.next = NULL;
 
+	if (fn->leaf == NULL && fn->fn_flags&RTN_TL_ROOT)
+		fn->leaf = &ip6_null_entry;
+
 	/* If it was last route, expunge its radix tree node */
 	if (fn->leaf == NULL) {
 		fn->fn_flags &= ~RTN_RTINFO;
@@ -1155,15 +1173,6 @@
 	   only if they are not in use now.
 	 */
 
-	if (rt->rt6i_flags & RTF_CACHE) {
-		if (atomic_read(&rt->u.dst.__refcnt) == 0 &&
-		    (long)(now - rt->u.dst.lastuse) >= gc_args.timeout) {
-			RT6_TRACE("aging clone %p\n", rt);
-			return -1;
-		}
-		gc_args.more++;
-	}
-
 	/*
 	 *	check addrconf expiration here.
 	 *	They are expired even if they are in use.
@@ -1175,6 +1184,13 @@
 			return -1;
 		}
 		gc_args.more++;
+	} else if (rt->rt6i_flags & RTF_CACHE) {
+		if (atomic_read(&rt->u.dst.__refcnt) == 0 &&
+		    (long)(now - rt->u.dst.lastuse) >= gc_args.timeout) {
+			RT6_TRACE("aging clone %p\n", rt);
+			return -1;
+		}
+		gc_args.more++;
 	}
 
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/ip6_output.c linux-2.4.20/net/ipv6/ip6_output.c
--- linux-2.4.19/net/ipv6/ip6_output.c	2001-09-20 21:12:56.000000000 +0000
+++ linux-2.4.20/net/ipv6/ip6_output.c	2002-10-29 11:18:32.000000000 +0000
@@ -101,7 +101,7 @@
 	struct dst_entry *dst = skb->dst;
 	struct net_device *dev = dst->dev;
 
-	skb->protocol = __constant_htons(ETH_P_IPV6);
+	skb->protocol = htons(ETH_P_IPV6);
 	skb->dev = dev;
 
 	if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) {
@@ -221,7 +221,7 @@
 	 *	Fill in the IPv6 header
 	 */
 
-	*(u32*)hdr = __constant_htonl(0x60000000) | fl->fl6_flowlabel;
+	*(u32*)hdr = htonl(0x60000000) | fl->fl6_flowlabel;
 	hlimit = -1;
 	if (np)
 		hlimit = np->hop_limit;
@@ -262,7 +262,7 @@
 	struct ipv6hdr *hdr;
 	int totlen;
 
-	skb->protocol = __constant_htons(ETH_P_IPV6);
+	skb->protocol = htons(ETH_P_IPV6);
 	skb->dev = dev;
 
 	totlen = len + sizeof(struct ipv6hdr);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/ndisc.c linux-2.4.20/net/ipv6/ndisc.c
--- linux-2.4.19/net/ipv6/ndisc.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv6/ndisc.c	2002-10-29 11:18:32.000000000 +0000
@@ -22,6 +22,7 @@
  *	Alexey Kuznetsov		:	state machine reworked
  *						and moved to net/core.
  *	Pekka Savola			:	RFC2461 validation
+ *	YOSHIFUJI Hideaki @USAGI	:	Verify ND options properly
  */
 
 /* Set to 3 to get tracing... */
@@ -154,6 +155,67 @@
 	return opt + space;
 }
 
+struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
+				     struct nd_opt_hdr *end)
+{
+	int type;
+	if (!cur || !end || cur >= end)
+		return NULL;
+	type = cur->nd_opt_type;
+	do {
+		cur = ((void *)cur) + (cur->nd_opt_len << 3);
+	} while(cur < end && cur->nd_opt_type != type);
+	return (cur <= end && cur->nd_opt_type == type ? cur : NULL);
+}
+
+struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
+					  struct ndisc_options *ndopts)
+{
+	struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
+
+	if (!nd_opt || opt_len < 0 || !ndopts)
+		return NULL;
+	memset(ndopts, 0, sizeof(*ndopts));
+	while (opt_len) {
+		int l;
+		if (opt_len < sizeof(struct nd_opt_hdr))
+			return NULL;
+		l = nd_opt->nd_opt_len << 3;
+		if (opt_len < l || l == 0)
+			return NULL;
+		switch (nd_opt->nd_opt_type) {
+		case ND_OPT_SOURCE_LL_ADDR:
+		case ND_OPT_TARGET_LL_ADDR:
+		case ND_OPT_MTU:
+		case ND_OPT_REDIRECT_HDR:
+			if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
+				ND_PRINTK2((KERN_WARNING
+					    "ndisc_parse_options(): duplicated ND6 option found: type=%d\n",
+					    nd_opt->nd_opt_type));
+			} else {
+				ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
+			}
+			break;
+		case ND_OPT_PREFIX_INFO:
+			ndopts->nd_opts_pi_end = nd_opt;
+			if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0)
+				ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
+			break;
+		default:
+			/*
+			 * Unknown options must be silently ignored,
+			 * to accomodate future extension to the protocol.
+			 */
+			ND_PRINTK2(KERN_WARNING
+				   "ndisc_parse_options(): ignored unsupported option; type=%d, len=%d\n",
+				   nd_opt->nd_opt_type, nd_opt->nd_opt_len);
+		}
+		opt_len -= l;
+		nd_opt = ((void *)nd_opt) + l;
+	}
+	return ndopts;
+}
+
 int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
 {
 	switch (dev->type) {
@@ -484,27 +546,6 @@
 }
 		   
 
-static u8 * ndisc_find_option(u8 *opt, int opt_len, int len, int option)
-{
-	while (opt_len <= len) {
-		int l = opt[1]<<3;
-
-		if (opt[0] == option && l >= opt_len)
-			return opt + 2;
-
-		if (l == 0) {
-			if (net_ratelimit())
-			    printk(KERN_WARNING "ndisc: option has 0 len\n");
-			return NULL;
-		}
-
-		opt += l;
-		len -= l;
-	}
-	return NULL;
-}
-
-
 static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
 {
 	/*
@@ -542,13 +583,6 @@
 	}
 }
 
-
-static void ndisc_update(struct neighbour *neigh, u8* opt, int len, int type)
-{
-	opt = ndisc_find_option(opt, neigh->dev->addr_len+2, len, type);
-	neigh_update(neigh, opt, NUD_STALE, 1, 1);
-}
-
 static void ndisc_router_discovery(struct sk_buff *skb)
 {
         struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
@@ -556,6 +590,7 @@
 	struct inet6_dev *in6_dev;
 	struct rt6_info *rt;
 	int lifetime;
+	struct ndisc_options ndopts;
 	int optlen;
 
 	__u8 * opt = (__u8 *)(ra_msg + 1);
@@ -587,6 +622,13 @@
 		return;
 	}
 
+	if (!ndisc_parse_options(opt, optlen, &ndopts)) {
+		if (net_ratelimit())
+			ND_PRINTK2(KERN_WARNING
+				   "ICMP6 RA: invalid ND option, ignored.\n");
+		return;
+	}
+
 	if (in6_dev->if_flags & IF_RS_SENT) {
 		/*
 		 *	flag that an RA was received after an RS was sent
@@ -670,63 +712,60 @@
 	 *	Process options.
 	 */
 
-        while (optlen > 0) {
-                int len = (opt[1] << 3);
-
-		if (len == 0) {
-			ND_PRINTK0("RA: opt has 0 len\n");
-			break;
+	if (rt && (neigh = rt->rt6i_nexthop) != NULL) {
+		u8 *lladdr = NULL;
+		int lladdrlen;
+		if (ndopts.nd_opts_src_lladdr) {
+			lladdr = (u8*)((ndopts.nd_opts_src_lladdr)+1);
+			lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
+			if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len)) {
+				if (net_ratelimit())
+					ND_PRINTK2(KERN_WARNING
+						   "ICMP6 RA: Invalid lladdr length.\n");
+				goto out;
+			}
 		}
+		neigh_update(neigh, lladdr, NUD_STALE, 1, 1);
+	}
 
-                switch(*opt) {
-                case ND_OPT_SOURCE_LL_ADDR:
+	if (ndopts.nd_opts_pi) {
+		struct nd_opt_hdr *p;
+		for (p = ndopts.nd_opts_pi;
+		     p;
+		     p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
+			addrconf_prefix_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3);
+		}
+	}
 
-			if (rt == NULL)
-				break;
-			
-			if ((neigh = rt->rt6i_nexthop) != NULL &&
-			    skb->dev->addr_len + 2 >= len)
-				neigh_update(neigh, opt+2, NUD_STALE, 1, 1);
-			break;
+	if (ndopts.nd_opts_mtu) {
+		u32 mtu;
 
-                case ND_OPT_PREFIX_INFO:
-			addrconf_prefix_rcv(skb->dev, opt, len);
-                        break;
-
-                case ND_OPT_MTU:
-			{
-				int mtu;
-				
-				mtu = htonl(*(__u32 *)(opt+4));
-
-				if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
-					ND_PRINTK0("NDISC: router "
-						   "announcement with mtu = %d\n",
-						   mtu);
-					break;
-				}
+		memcpy(&mtu, ((u8*)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
+		mtu = ntohl(mtu);
 
-				if (in6_dev->cnf.mtu6 != mtu) {
-					in6_dev->cnf.mtu6 = mtu;
+		if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
+			if (net_ratelimit()) {
+				ND_PRINTK0("NDISC: router announcement with mtu = %d\n",
+					   mtu);
+			}
+		}
 
-					if (rt)
-						rt->u.dst.pmtu = mtu;
+		if (in6_dev->cnf.mtu6 != mtu) {
+			in6_dev->cnf.mtu6 = mtu;
 
-					rt6_mtu_change(skb->dev, mtu);
-				}
-			}
-                        break;
+			if (rt)
+				rt->u.dst.pmtu = mtu;
 
-		case ND_OPT_TARGET_LL_ADDR:
-		case ND_OPT_REDIRECT_HDR:
-			ND_PRINTK0("got illegal option with RA");
-			break;
-		default:
-			ND_PRINTK0("unkown option in RA\n");
-                };
-                optlen -= len;
-                opt += len;
-        }
+			rt6_mtu_change(skb->dev, mtu);
+		}
+	}
+			
+	if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
+		if (net_ratelimit())
+			ND_PRINTK0(KERN_WARNING
+				   "ICMP6 RA: got illegal option with RA");
+	}
+out:
 	if (rt)
 		dst_release(&rt->u.dst);
 	in6_dev_put(in6_dev);
@@ -740,7 +779,10 @@
 	struct in6_addr *target;	/* new first hop to destination */
 	struct neighbour *neigh;
 	int on_link = 0;
+	struct ndisc_options ndopts;
 	int optlen;
+	u8 *lladdr = NULL;
+	int lladdrlen;
 
 	if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
 		if (net_ratelimit())
@@ -788,6 +830,24 @@
 	 *	first-hop router for the specified ICMP Destination Address.
 	 */
 		
+	if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) {
+		if (net_ratelimit())
+			ND_PRINTK2(KERN_WARNING
+				   "ICMP6 Redirect: invalid ND options, rejected.\n");
+		in6_dev_put(in6_dev);
+		return;
+	}
+	if (ndopts.nd_opts_tgt_lladdr) {
+		lladdr = (u8*)(ndopts.nd_opts_tgt_lladdr + 1);
+		lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
+		if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len)) {
+			if (net_ratelimit())
+				ND_PRINTK2(KERN_WARNING
+					   "ICMP6 Redirect: invalid lladdr length.\n");
+			in6_dev_put(in6_dev);
+			return;
+		}
+	}
 	/* passed validation tests */
 
 	/*
@@ -796,7 +856,7 @@
 
 	neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1);
 	if (neigh) {
-		ndisc_update(neigh, (u8*)(dest + 1), optlen, ND_OPT_TARGET_LL_ADDR);
+		neigh_update(neigh, lladdr, NUD_STALE, 1, 1);
 		if (neigh->nud_state&NUD_VALID)
 			rt6_redirect(dest, &skb->nh.ipv6h->saddr, neigh, on_link);
 		else
@@ -922,31 +982,6 @@
 	ICMP6_INC_STATS(Icmp6OutMsgs);
 }
 
-static __inline__ struct neighbour *
-ndisc_recv_ns(struct in6_addr *saddr, struct sk_buff *skb)
-{
-	u8 *opt;
-
-	opt = skb->h.raw;
-	opt += sizeof(struct nd_msg);
-	opt = ndisc_find_option(opt, skb->dev->addr_len+2, skb->tail - opt, ND_OPT_SOURCE_LL_ADDR);
-
-	return neigh_event_ns(&nd_tbl, opt, saddr, skb->dev);
-}
-
-static __inline__ int ndisc_recv_na(struct neighbour *neigh, struct sk_buff *skb)
-{
-	u8 *opt;
-	struct nd_msg *msg = (struct nd_msg*) skb->h.raw;
-
-	opt = ndisc_find_option(msg->opt, skb->dev->addr_len+2,
-				skb->tail - msg->opt, ND_OPT_TARGET_LL_ADDR);
-
-	return neigh_update(neigh, opt,
-			    msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
-			    msg->icmph.icmp6_override, 1);
-}
-
 static void pndisc_redo(struct sk_buff *skb)
 {
 	ndisc_rcv(skb);
@@ -978,13 +1013,15 @@
 		return 0;
 	}
 
-	/* XXX: RFC2461 Validation of [all ndisc messages]:
-	 *	All included ndisc options MUST be of non-zero length
-	 *	(Some checking in ndisc_find_option)
-	 */
-
 	switch (msg->icmph.icmp6_type) {
 	case NDISC_NEIGHBOUR_SOLICITATION:
+	    {
+		struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
+		u8 *lladdr = NULL;
+		int lladdrlen = 0;
+		u32 ndoptlen = skb->tail - msg->opt;
+		struct ndisc_options ndopts;
+
 		if (skb->len < sizeof(struct nd_msg)) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP NS: packet too short\n");
@@ -997,6 +1034,22 @@
 			return 0;
 		}
 
+		if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
+			if (net_ratelimit())
+				printk(KERN_WARNING "ICMP NS: invalid ND option, ignored.\n");
+			return 0;
+		}
+
+		if (ndopts.nd_opts_src_lladdr) {
+			lladdr = (u8*)(ndopts.nd_opts_src_lladdr + 1);
+			lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
+			if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len)) {
+				if (net_ratelimit())
+					printk(KERN_WARNING "ICMP NS: bad lladdr length.\n");
+				return 0;
+			}
+		}
+
 		/* XXX: RFC2461 7.1.1:
 		 * 	If the IP source address is the unspecified address, there
 		 *	MUST NOT be source link-layer address option in the message.
@@ -1063,7 +1116,7 @@
 				 *	for the source adddress
 				 */
 
-				neigh = ndisc_recv_ns(saddr, skb);
+				neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, skb->dev);
 
 				if (neigh || !dev->hard_header) {
 					ndisc_send_na(dev, neigh, saddr, &ifp->addr, 
@@ -1093,7 +1146,8 @@
 					else
 						nd_tbl.stats.rcv_probes_ucast++;
 
-					neigh = ndisc_recv_ns(saddr, skb);
+					
+					neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, skb->dev);
 
 					if (neigh) {
 						ndisc_send_na(dev, neigh, saddr, &msg->target,
@@ -1113,8 +1167,16 @@
 			
 		}
 		return 0;
+	    }
 
 	case NDISC_NEIGHBOUR_ADVERTISEMENT:
+	    {
+		struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
+		u8 *lladdr = NULL;
+		int lladdrlen = 0;
+		u32 ndoptlen = skb->tail - msg->opt;
+		struct ndisc_options ndopts;
+
 		if (skb->len < sizeof(struct nd_msg)) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP NA: packet too short\n");
@@ -1133,6 +1195,20 @@
 			return 0;
 		}
 		
+		if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
+			if (net_ratelimit())
+				printk(KERN_WARNING "ICMP NS: invalid ND option, ignored.\n");
+			return 0;
+		}
+		if (ndopts.nd_opts_tgt_lladdr) {
+			lladdr = (u8*)(ndopts.nd_opts_tgt_lladdr + 1);
+			lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
+			if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len)) {
+				if (net_ratelimit())
+					printk(KERN_WARNING "NDISC NA: invalid lladdr length.\n");
+				return 0;
+			}
+		}
 		if ((ifp = ipv6_get_ifaddr(&msg->target, dev))) {
 			if (ifp->flags & IFA_F_TENTATIVE) {
 				addrconf_dad_failure(ifp);
@@ -1159,9 +1235,6 @@
 					struct rt6_info *rt;
 					rt = rt6_get_dflt_router(saddr, skb->dev);
 					if (rt) {
-						/* It is safe only because
-						   we aer in BH */
-						dst_release(&rt->u.dst);
 						ip6_del_rt(rt);
 					}
 				}
@@ -1170,10 +1243,13 @@
 					neigh->flags |= NTF_ROUTER;
 			}
 
-			ndisc_recv_na(neigh, skb);
+			neigh_update(neigh, lladdr,
+				     msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
+				     msg->icmph.icmp6_override, 1);
 			neigh_release(neigh);
 		}
 		break;
+	    }
 
 	case NDISC_ROUTER_ADVERTISEMENT:
 		ndisc_router_discovery(skb);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/netfilter/Config.in linux-2.4.20/net/ipv6/netfilter/Config.in
--- linux-2.4.19/net/ipv6/netfilter/Config.in	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.20/net/ipv6/netfilter/Config.in	2002-10-29 11:18:32.000000000 +0000
@@ -24,6 +24,10 @@
   fi
 #  dep_tristate '  MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES
   dep_tristate '  netfilter MARK match support' CONFIG_IP6_NF_MATCH_MARK $CONFIG_IP6_NF_IPTABLES
+  dep_tristate '  Packet Length match support' CONFIG_IP6_NF_MATCH_LENGTH $CONFIG_IP6_NF_IPTABLES
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    dep_tristate '  EUI64 address check (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_EUI64 $CONFIG_IP6_NF_IPTABLES
+  fi
 #  dep_tristate '  Multiple port match support' CONFIG_IP6_NF_MATCH_MULTIPORT $CONFIG_IP6_NF_IPTABLES
 #  dep_tristate '  TOS match support' CONFIG_IP6_NF_MATCH_TOS $CONFIG_IP6_NF_IPTABLES
 #  if [ "$CONFIG_IP6_NF_CONNTRACK" != "n" ]; then
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/netfilter/Makefile linux-2.4.20/net/ipv6/netfilter/Makefile
--- linux-2.4.19/net/ipv6/netfilter/Makefile	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.20/net/ipv6/netfilter/Makefile	2002-10-29 11:18:32.000000000 +0000
@@ -15,7 +15,9 @@
 obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
 obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o
 obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
+obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
 obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
+obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
 obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
 obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/netfilter/ip6_queue.c linux-2.4.20/net/ipv6/netfilter/ip6_queue.c
--- linux-2.4.19/net/ipv6/netfilter/ip6_queue.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv6/netfilter/ip6_queue.c	2002-10-29 11:18:35.000000000 +0000
@@ -15,7 +15,7 @@
  *             real coder of this.
  *             Few changes needed, mainly the hard_routing code and
  *             the netlink socket protocol (we're NETLINK_IP6_FW).
- *
+ * 2002-06-25: Code cleanup. [JM: ported cleanup over from ip_queue.c]
  */
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -26,18 +26,12 @@
 #include <linux/netfilter.h>
 #include <linux/netlink.h>
 #include <linux/spinlock.h>
-#include <linux/rtnetlink.h>
+#include <linux/brlock.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
 #include <net/sock.h>
 #include <net/ipv6.h>
 #include <net/ip6_route.h>
-
-/* We're still usign the following structs. No need to change them: */
-/*   ipq_packet_msg                                                 */
-/*   ipq_mode_msg                                                   */
-/*   ipq_verdict_msg                                                */
-/*   ipq_peer_msg                                                   */
 #include <linux/netfilter_ipv4/ip_queue.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
@@ -47,184 +41,289 @@
 #define NET_IPQ_QMAX 2088
 #define NET_IPQ_QMAX_NAME "ip6_queue_maxlen"
 
-typedef struct ip6q_rt_info {
+struct ipq_rt_info {
 	struct in6_addr daddr;
 	struct in6_addr saddr;
-} ip6q_rt_info_t;
+};
 
-typedef struct ip6q_queue_element {
-	struct list_head list;		/* Links element into queue */
-	int verdict;			/* Current verdict */
-	struct nf_info *info;		/* Extra info from netfilter */
-	struct sk_buff *skb;		/* Packet inside */
-	ip6q_rt_info_t rt_info;		/* May need post-mangle routing */
-} ip6q_queue_element_t;
-
-typedef int (*ip6q_send_cb_t)(ip6q_queue_element_t *e);
-
-typedef struct ip6q_peer {
-	pid_t pid;			/* PID of userland peer */
-	unsigned char died;		/* We think the peer died */
-	unsigned char copy_mode;	/* Copy packet as well as metadata? */
-	size_t copy_range;		/* Range past metadata to copy */
-	ip6q_send_cb_t send;		/* Callback for sending data to peer */
-} ip6q_peer_t;
-
-typedef struct ip6q_queue {
- 	int len;			/* Current queue len */
- 	int *maxlen;			/* Maximum queue len, via sysctl */
- 	unsigned char flushing;		/* If queue is being flushed */
- 	unsigned char terminate;	/* If the queue is being terminated */
- 	struct list_head list;		/* Head of packet queue */
- 	spinlock_t lock;		/* Queue spinlock */
- 	ip6q_peer_t peer;		/* Userland peer */
-} ip6q_queue_t;
+struct ipq_queue_entry {
+	struct list_head list;
+	struct nf_info *info;
+	struct sk_buff *skb;
+	struct ipq_rt_info rt_info;
+};
 
-/****************************************************************************
- *
- * Packet queue
- *
- ****************************************************************************/
-/* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */
-static ip6q_queue_element_t *
-ip6q_dequeue(ip6q_queue_t *q,
-            int (*cmp)(ip6q_queue_element_t *, unsigned long),
-            unsigned long data)
-{
-	struct list_head *i;
-
-	spin_lock_bh(&q->lock);
-	for (i = q->list.prev; i != &q->list; i = i->prev) {
-		ip6q_queue_element_t *e = (ip6q_queue_element_t *)i;
-		
-		if (!cmp || cmp(e, data)) {
-			list_del(&e->list);
-			q->len--;
-			spin_unlock_bh(&q->lock);
-			return e;
-		}
+typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long);
+
+static unsigned char copy_mode = IPQ_COPY_NONE;
+static unsigned int queue_maxlen = IPQ_QMAX_DEFAULT;
+static rwlock_t queue_lock = RW_LOCK_UNLOCKED;
+static int peer_pid;
+static unsigned int copy_range;
+static unsigned int queue_total;
+static struct sock *ipqnl;
+static LIST_HEAD(queue_list);
+static DECLARE_MUTEX(ipqnl_sem);
+
+static void
+ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
+{
+	nf_reinject(entry->skb, entry->info, verdict);
+	kfree(entry);
+}
+
+static inline int
+__ipq_enqueue_entry(struct ipq_queue_entry *entry)
+{
+       if (queue_total >= queue_maxlen) {
+               if (net_ratelimit()) 
+                       printk(KERN_WARNING "ip6_queue: full at %d entries, "
+                              "dropping packet(s).\n", queue_total);
+               return -ENOSPC;
+       }
+       list_add(&entry->list, &queue_list);
+       queue_total++;
+       return 0;
+}
+
+/*
+ * Find and return a queued entry matched by cmpfn, or return the last
+ * entry if cmpfn is NULL.
+ */
+static inline struct ipq_queue_entry *
+__ipq_find_entry(ipq_cmpfn cmpfn, unsigned long data)
+{
+	struct list_head *p;
+
+	list_for_each_prev(p, &queue_list) {
+		struct ipq_queue_entry *entry = (struct ipq_queue_entry *)p;
+		
+		if (!cmpfn || cmpfn(entry, data))
+			return entry;
 	}
-	spin_unlock_bh(&q->lock);
 	return NULL;
 }
 
-/* Flush all packets */
-static void ip6q_flush(ip6q_queue_t *q)
+static inline void
+__ipq_dequeue_entry(struct ipq_queue_entry *entry)
 {
-	ip6q_queue_element_t *e;
-	
-	spin_lock_bh(&q->lock);
-	q->flushing = 1;
-	spin_unlock_bh(&q->lock);
-	while ((e = ip6q_dequeue(q, NULL, 0))) {
-		e->verdict = NF_DROP;
-		nf_reinject(e->skb, e->info, e->verdict);
-		kfree(e);
-	}
-	spin_lock_bh(&q->lock);
-	q->flushing = 0;
-	spin_unlock_bh(&q->lock);
-}
-
-static ip6q_queue_t *ip6q_create_queue(nf_queue_outfn_t outfn,
-                                     ip6q_send_cb_t send_cb,
-                                     int *errp, int *sysctl_qmax)
+	list_del(&entry->list);
+	queue_total--;
+}
+
+static inline struct ipq_queue_entry *
+__ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
 {
-	int status;
-	ip6q_queue_t *q;
+	struct ipq_queue_entry *entry;
 
-	*errp = 0;
-	q = kmalloc(sizeof(ip6q_queue_t), GFP_KERNEL);
-	if (q == NULL) {
-		*errp = -ENOMEM;
+	entry = __ipq_find_entry(cmpfn, data);
+	if (entry == NULL)
 		return NULL;
+
+	__ipq_dequeue_entry(entry);
+	return entry;
+}
+
+
+static inline void
+__ipq_flush(int verdict)
+{
+	struct ipq_queue_entry *entry;
+	
+	while ((entry = __ipq_find_dequeue_entry(NULL, 0)))
+		ipq_issue_verdict(entry, verdict);
+}
+
+static inline int
+__ipq_set_mode(unsigned char mode, unsigned int range)
+{
+	int status = 0;
+	
+	switch(mode) {
+	case IPQ_COPY_NONE:
+	case IPQ_COPY_META:
+		copy_mode = mode;
+		copy_range = 0;
+		break;
+		
+	case IPQ_COPY_PACKET:
+		copy_mode = mode;
+		copy_range = range;
+		if (copy_range > 0xFFFF)
+			copy_range = 0xFFFF;
+		break;
+		
+	default:
+		status = -EINVAL;
+
 	}
-	q->peer.pid = 0;
-	q->peer.died = 0;
-	q->peer.copy_mode = IPQ_COPY_NONE;
-	q->peer.copy_range = 0;
-	q->peer.send = send_cb;
-	q->len = 0;
-	q->maxlen = sysctl_qmax;
-	q->flushing = 0;
-	q->terminate = 0;
-	INIT_LIST_HEAD(&q->list);
-	spin_lock_init(&q->lock);
-	status = nf_register_queue_handler(PF_INET6, outfn, q);
-	if (status < 0) {
-		*errp = -EBUSY;
-		kfree(q);
+	return status;
+}
+
+static inline void
+__ipq_reset(void)
+{
+	peer_pid = 0;
+	__ipq_set_mode(IPQ_COPY_NONE, 0);
+	__ipq_flush(NF_DROP);
+}
+
+static struct ipq_queue_entry *
+ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
+{
+	struct ipq_queue_entry *entry;
+	
+	write_lock_bh(&queue_lock);
+	entry = __ipq_find_dequeue_entry(cmpfn, data);
+	write_unlock_bh(&queue_lock);
+	return entry;
+}
+
+static void
+ipq_flush(int verdict)
+{
+	write_lock_bh(&queue_lock);
+	__ipq_flush(verdict);
+	write_unlock_bh(&queue_lock);
+}
+
+static struct sk_buff *
+ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
+{
+	unsigned char *old_tail;
+	size_t size = 0;
+	size_t data_len = 0;
+	struct sk_buff *skb;
+	struct ipq_packet_msg *pmsg;
+	struct nlmsghdr *nlh;
+
+	read_lock_bh(&queue_lock);
+	
+	switch (copy_mode) {
+	case IPQ_COPY_META:
+	case IPQ_COPY_NONE:
+		size = NLMSG_SPACE(sizeof(*pmsg));
+		data_len = 0;
+		break;
+	
+	case IPQ_COPY_PACKET:
+		if (copy_range == 0 || copy_range > entry->skb->len)
+			data_len = entry->skb->len;
+		else
+			data_len = copy_range;
+		
+		size = NLMSG_SPACE(sizeof(*pmsg) + data_len);
+		break;
+	
+	default:
+		*errp = -EINVAL;
+		read_unlock_bh(&queue_lock);
 		return NULL;
 	}
-	return q;
+
+	read_unlock_bh(&queue_lock);
+
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		goto nlmsg_failure;
+		
+	old_tail= skb->tail;
+	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
+	pmsg = NLMSG_DATA(nlh);
+	memset(pmsg, 0, sizeof(*pmsg));
+
+	pmsg->packet_id       = (unsigned long )entry;
+	pmsg->data_len        = data_len;
+	pmsg->timestamp_sec   = entry->skb->stamp.tv_sec;
+	pmsg->timestamp_usec  = entry->skb->stamp.tv_usec;
+	pmsg->mark            = entry->skb->nfmark;
+	pmsg->hook            = entry->info->hook;
+	pmsg->hw_protocol     = entry->skb->protocol;
+	
+	if (entry->info->indev)
+		strcpy(pmsg->indev_name, entry->info->indev->name);
+	else
+		pmsg->indev_name[0] = '\0';
+	
+	if (entry->info->outdev)
+		strcpy(pmsg->outdev_name, entry->info->outdev->name);
+	else
+		pmsg->outdev_name[0] = '\0';
+	
+	if (entry->info->indev && entry->skb->dev) {
+		pmsg->hw_type = entry->skb->dev->type;
+		if (entry->skb->dev->hard_header_parse)
+			pmsg->hw_addrlen =
+				entry->skb->dev->hard_header_parse(entry->skb,
+				                                   pmsg->hw_addr);
+	}
+	
+	if (data_len)
+		memcpy(pmsg->payload, entry->skb->data, data_len);
+		
+	nlh->nlmsg_len = skb->tail - old_tail;
+	return skb;
+
+nlmsg_failure:
+	if (skb)
+		kfree_skb(skb);
+	*errp = -EINVAL;
+	printk(KERN_ERR "ip6_queue: error creating packet message\n");
+	return NULL;
 }
 
-static int ip6q_enqueue(ip6q_queue_t *q,
-                       struct sk_buff *skb, struct nf_info *info)
+static int
+ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data)
 {
-	ip6q_queue_element_t *e;
-	int status;
-	
-	e = kmalloc(sizeof(*e), GFP_ATOMIC);
-	if (e == NULL) {
-		printk(KERN_ERR "ip6_queue: OOM in enqueue\n");
+	int status = -EINVAL;
+	struct sk_buff *nskb;
+	struct ipq_queue_entry *entry;
+
+	if (copy_mode == IPQ_COPY_NONE)
+		return -EAGAIN;
+
+	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+	if (entry == NULL) {
+		printk(KERN_ERR "ip6_queue: OOM in ipq_enqueue_packet()\n");
 		return -ENOMEM;
 	}
 
-	e->verdict = NF_DROP;
-	e->info = info;
-	e->skb = skb;
+	entry->info = info;
+	entry->skb = skb;
 
-	if (e->info->hook == NF_IP_LOCAL_OUT) {
+	if (entry->info->hook == NF_IP_LOCAL_OUT) {
 		struct ipv6hdr *iph = skb->nh.ipv6h;
 
-		e->rt_info.daddr = iph->daddr;
-		e->rt_info.saddr = iph->saddr;
+		entry->rt_info.daddr = iph->daddr;
+		entry->rt_info.saddr = iph->saddr;
 	}
 
-	spin_lock_bh(&q->lock);
-	if (q->len >= *q->maxlen) {
-		spin_unlock_bh(&q->lock);
-		if (net_ratelimit()) 
-			printk(KERN_WARNING "ip6_queue: full at %d entries, "
-			       "dropping packet(s).\n", q->len);
-		goto free_drop;
-	}
-	if (q->flushing || q->peer.copy_mode == IPQ_COPY_NONE
-	    || q->peer.pid == 0 || q->peer.died || q->terminate) {
-		spin_unlock_bh(&q->lock);
-		goto free_drop;
-	}
-	status = q->peer.send(e);
-	if (status > 0) {
-		list_add(&e->list, &q->list);
-		q->len++;
-		spin_unlock_bh(&q->lock);
-		return status;
-	}
-	spin_unlock_bh(&q->lock);
-	if (status == -ECONNREFUSED) {
-		printk(KERN_INFO "ip6_queue: peer %d died, "
-		       "resetting state and flushing queue\n", q->peer.pid);
-			q->peer.died = 1;
-			q->peer.pid = 0;
-			q->peer.copy_mode = IPQ_COPY_NONE;
-			q->peer.copy_range = 0;
-			ip6q_flush(q);
-	}
-free_drop:
-	kfree(e);
-	return -EBUSY;
-}
+	nskb = ipq_build_packet_message(entry, &status);
+	if (nskb == NULL)
+		goto err_out_free;
+		
+	write_lock_bh(&queue_lock);
+	
+	if (!peer_pid)
+		goto err_out_unlock;
 
-static void ip6q_destroy_queue(ip6q_queue_t *q)
-{
-	nf_unregister_queue_handler(PF_INET6);
-	spin_lock_bh(&q->lock);
-	q->terminate = 1;
-	spin_unlock_bh(&q->lock);
-	ip6q_flush(q);
-	kfree(q);
+	status = netlink_unicast(ipqnl, nskb, peer_pid, MSG_DONTWAIT);
+	if (status < 0)
+		goto err_out_unlock;
+	
+	status = __ipq_enqueue_entry(entry);
+	if (status < 0)
+		goto err_out_unlock;
+
+	write_unlock_bh(&queue_lock);
+	return status;
+	
+err_out_unlock:
+	write_unlock_bh(&queue_lock);
+
+err_out_free:
+	kfree(entry);
+	return status;
 }
 
 /*
@@ -236,7 +335,8 @@
  *
  * If that one is modified, this one should be modified too.
  */
-static int route6_me_harder(struct sk_buff *skb)
+static int
+route6_me_harder(struct sk_buff *skb)
 {
 	struct ipv6hdr *iph = skb->nh.ipv6h;
 	struct dst_entry *dst;
@@ -264,7 +364,9 @@
 	skb->dst = dst;
 	return 0;
 }
-static int ip6q_mangle_ipv6(ipq_verdict_msg_t *v, ip6q_queue_element_t *e)
+
+static int
+ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
 {
 	int diff;
 	struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload;
@@ -306,357 +408,262 @@
 	 */
 	if (e->info->hook == NF_IP_LOCAL_OUT) {
 		struct ipv6hdr *iph = e->skb->nh.ipv6h;
-		if (!(   iph->daddr.in6_u.u6_addr32[0] == e->rt_info.daddr.in6_u.u6_addr32[0]
-                      && iph->daddr.in6_u.u6_addr32[1] == e->rt_info.daddr.in6_u.u6_addr32[1]
-                      && iph->daddr.in6_u.u6_addr32[2] == e->rt_info.daddr.in6_u.u6_addr32[2]
-                      && iph->daddr.in6_u.u6_addr32[3] == e->rt_info.daddr.in6_u.u6_addr32[3]
-		      && iph->saddr.in6_u.u6_addr32[0] == e->rt_info.saddr.in6_u.u6_addr32[0]
-		      && iph->saddr.in6_u.u6_addr32[1] == e->rt_info.saddr.in6_u.u6_addr32[1]
-		      && iph->saddr.in6_u.u6_addr32[2] == e->rt_info.saddr.in6_u.u6_addr32[2]
-		      && iph->saddr.in6_u.u6_addr32[3] == e->rt_info.saddr.in6_u.u6_addr32[3]))
+		if (ipv6_addr_cmp(&iph->daddr, &e->rt_info.daddr) ||
+		    ipv6_addr_cmp(&iph->saddr, &e->rt_info.saddr))
 			return route6_me_harder(e->skb);
 	}
 	return 0;
 }
 
-static inline int id_cmp(ip6q_queue_element_t *e, unsigned long id)
+static inline int
+id_cmp(struct ipq_queue_entry *e, unsigned long id)
 {
 	return (id == (unsigned long )e);
 }
 
-static int ip6q_set_verdict(ip6q_queue_t *q,
-                           ipq_verdict_msg_t *v, unsigned int len)
+static int
+ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
 {
-	ip6q_queue_element_t *e;
+	struct ipq_queue_entry *entry;
 
-	if (v->value > NF_MAX_VERDICT)
+	if (vmsg->value > NF_MAX_VERDICT)
 		return -EINVAL;
-	e = ip6q_dequeue(q, id_cmp, v->id);
-	if (e == NULL)
+
+	entry = ipq_find_dequeue_entry(id_cmp, vmsg->id);
+	if (entry == NULL)
 		return -ENOENT;
 	else {
-		e->verdict = v->value;
-		if (v->data_len && v->data_len == len)
-			if (ip6q_mangle_ipv6(v, e) < 0)
-				e->verdict = NF_DROP;
-		nf_reinject(e->skb, e->info, e->verdict);
-		kfree(e);
+		int verdict = vmsg->value;
+		
+		if (vmsg->data_len && vmsg->data_len == len)
+			if (ipq_mangle_ipv6(vmsg, entry) < 0)
+				verdict = NF_DROP;
+		
+		ipq_issue_verdict(entry, verdict);
 		return 0;
 	}
 }
 
-static int ip6q_receive_peer(ip6q_queue_t* q, ipq_peer_msg_t *m,
-                            unsigned char type, unsigned int len)
+static int
+ipq_set_mode(unsigned char mode, unsigned int range)
 {
+	int status;
+
+	write_lock_bh(&queue_lock);
+	status = __ipq_set_mode(mode, range);
+	write_unlock_bh(&queue_lock);
+	return status;
+}
 
+static int
+ipq_receive_peer(struct ipq_peer_msg *pmsg,
+                 unsigned char type, unsigned int len)
+{
 	int status = 0;
-	int busy;
-		
-	spin_lock_bh(&q->lock);
-	busy = (q->terminate || q->flushing);
-	spin_unlock_bh(&q->lock);
-	if (busy)
-		return -EBUSY;
-	if (len < sizeof(ipq_peer_msg_t))
+
+	if (len < sizeof(*pmsg))
 		return -EINVAL;
+
 	switch (type) {
-		case IPQM_MODE:
-			switch (m->msg.mode.value) {
-				case IPQ_COPY_META:
-					q->peer.copy_mode = IPQ_COPY_META;
-					q->peer.copy_range = 0;
-					break;
-				case IPQ_COPY_PACKET:
-					q->peer.copy_mode = IPQ_COPY_PACKET;
-					q->peer.copy_range = m->msg.mode.range;
-					if (q->peer.copy_range > 0xFFFF)
-						q->peer.copy_range = 0xFFFF;
-					break;
-				default:
-					status = -EINVAL;
-			}
-			break;
-		case IPQM_VERDICT:
-			if (m->msg.verdict.value > NF_MAX_VERDICT)
-				status = -EINVAL;
-			else
-				status = ip6q_set_verdict(q,
-				                         &m->msg.verdict,
-				                         len - sizeof(*m));
+	case IPQM_MODE:
+		status = ipq_set_mode(pmsg->msg.mode.value,
+		                      pmsg->msg.mode.range);
+		break;
+		
+	case IPQM_VERDICT:
+		if (pmsg->msg.verdict.value > NF_MAX_VERDICT)
+			status = -EINVAL;
+		else
+			status = ipq_set_verdict(&pmsg->msg.verdict,
+			                         len - sizeof(*pmsg));
 			break;
-		default:
-			 status = -EINVAL;
+	default:
+		status = -EINVAL;
 	}
 	return status;
 }
 
-static inline int dev_cmp(ip6q_queue_element_t *e, unsigned long ifindex)
+static int
+dev_cmp(struct ipq_queue_entry *entry, unsigned long ifindex)
 {
-	if (e->info->indev)
-		if (e->info->indev->ifindex == ifindex)
+	if (entry->info->indev)
+		if (entry->info->indev->ifindex == ifindex)
 			return 1;
-	if (e->info->outdev)
-		if (e->info->outdev->ifindex == ifindex)
+			
+	if (entry->info->outdev)
+		if (entry->info->outdev->ifindex == ifindex)
 			return 1;
+
 	return 0;
 }
 
-/* Drop any queued packets associated with device ifindex */
-static void ip6q_dev_drop(ip6q_queue_t *q, int ifindex)
+static void
+ipq_dev_drop(int ifindex)
 {
-	ip6q_queue_element_t *e;
+	struct ipq_queue_entry *entry;
 	
-	while ((e = ip6q_dequeue(q, dev_cmp, ifindex))) {
-		e->verdict = NF_DROP;
-		nf_reinject(e->skb, e->info, e->verdict);
-		kfree(e);
-	}
-}
-
-/****************************************************************************
- *
- * Netfilter interface
- *
- ****************************************************************************/
-
-/*
- * Packets arrive here from netfilter for queuing to userspace.
- * All of them must be fed back via nf_reinject() or Alexey will kill Rusty.
- */
-static int netfilter6_receive(struct sk_buff *skb,
-                             struct nf_info *info, void *data)
-{
-	return ip6q_enqueue((ip6q_queue_t *)data, skb, info);
-}
-
-/****************************************************************************
- *
- * Netlink interface.
- *
- ****************************************************************************/
-
-static struct sock *nfnl = NULL;
-/* This is not a static one, so we should not repeat its name */
-ip6q_queue_t *nlq6 = NULL;
-
-static struct sk_buff *netlink_build_message(ip6q_queue_element_t *e, int *errp)
-{
-	unsigned char *old_tail;
-	size_t size = 0;
-	size_t data_len = 0;
-	struct sk_buff *skb;
-	ipq_packet_msg_t *pm;
-	struct nlmsghdr *nlh;
-
-	switch (nlq6->peer.copy_mode) {
-		size_t copy_range;
-
-		case IPQ_COPY_META:
-			size = NLMSG_SPACE(sizeof(*pm));
-			data_len = 0;
-			break;
-		case IPQ_COPY_PACKET:
-			copy_range = nlq6->peer.copy_range;
-			if (copy_range == 0 || copy_range > e->skb->len)
-				data_len = e->skb->len;
-			else
-				data_len = copy_range;
-			size = NLMSG_SPACE(sizeof(*pm) + data_len);
-			
-			break;
-		case IPQ_COPY_NONE:
-		default:
-			*errp = -EINVAL;
-			return NULL;
-	}
-	skb = alloc_skb(size, GFP_ATOMIC);
-	if (!skb)
-		goto nlmsg_failure;
-	old_tail = skb->tail;
-	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
-	pm = NLMSG_DATA(nlh);
-	memset(pm, 0, sizeof(*pm));
-	pm->packet_id = (unsigned long )e;
-	pm->data_len = data_len;
-	pm->timestamp_sec = e->skb->stamp.tv_sec;
-	pm->timestamp_usec = e->skb->stamp.tv_usec;
-	pm->mark = e->skb->nfmark;
-	pm->hook = e->info->hook;
-	if (e->info->indev) strcpy(pm->indev_name, e->info->indev->name);
-	else pm->indev_name[0] = '\0';
-	if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
-	else pm->outdev_name[0] = '\0';
-	pm->hw_protocol = e->skb->protocol;
-	if (e->info->indev && e->skb->dev) {
-		pm->hw_type = e->skb->dev->type;
-		if (e->skb->dev->hard_header_parse)
-			pm->hw_addrlen =
-				e->skb->dev->hard_header_parse(e->skb,
-				                               pm->hw_addr);
-	}
-	if (data_len)
-		memcpy(pm->payload, e->skb->data, data_len);
-	nlh->nlmsg_len = skb->tail - old_tail;
-	NETLINK_CB(skb).dst_groups = 0;
-	return skb;
-nlmsg_failure:
-	if (skb)
-		kfree_skb(skb);
-	*errp = 0;
-	printk(KERN_ERR "ip6_queue: error creating netlink message\n");
-	return NULL;
-}
-
-static int netlink_send_peer(ip6q_queue_element_t *e)
-{
-	int status = 0;
-	struct sk_buff *skb;
-
-	skb = netlink_build_message(e, &status);
-	if (skb == NULL)
-		return status;
-	return netlink_unicast(nfnl, skb, nlq6->peer.pid, MSG_DONTWAIT);
+	while ((entry = ipq_find_dequeue_entry(dev_cmp, ifindex)) != NULL)
+		ipq_issue_verdict(entry, NF_DROP);
 }
 
 #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
 
-static __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
+static inline void
+ipq_rcv_skb(struct sk_buff *skb)
 {
-	int status, type;
+	int status, type, pid, flags, nlmsglen, skblen;
 	struct nlmsghdr *nlh;
 
-	if (skb->len < sizeof(struct nlmsghdr))
+	skblen = skb->len;
+	if (skblen < sizeof(*nlh))
 		return;
 
 	nlh = (struct nlmsghdr *)skb->data;
-	if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
-	    || skb->len < nlh->nlmsg_len)
-	    	return;
-
-	if(nlh->nlmsg_pid <= 0
-	    || !(nlh->nlmsg_flags & NLM_F_REQUEST)
-	    || nlh->nlmsg_flags & NLM_F_MULTI)
+	nlmsglen = nlh->nlmsg_len;
+	if (nlmsglen < sizeof(*nlh) || skblen < nlmsglen)
+		return;
+
+	pid = nlh->nlmsg_pid;
+	flags = nlh->nlmsg_flags;
+	
+	if(pid <= 0 || !(flags & NLM_F_REQUEST) || flags & NLM_F_MULTI)
 		RCV_SKB_FAIL(-EINVAL);
-	if (nlh->nlmsg_flags & MSG_TRUNC)
+		
+	if (flags & MSG_TRUNC)
 		RCV_SKB_FAIL(-ECOMM);
+		
 	type = nlh->nlmsg_type;
 	if (type < NLMSG_NOOP || type >= IPQM_MAX)
 		RCV_SKB_FAIL(-EINVAL);
+		
 	if (type <= IPQM_BASE)
 		return;
+		
 	if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
 		RCV_SKB_FAIL(-EPERM);
-	if (nlq6->peer.pid && !nlq6->peer.died
-	    && (nlq6->peer.pid != nlh->nlmsg_pid)) {
-	    	printk(KERN_WARNING "ip6_queue: peer pid changed from %d to "
-	    	      "%d, flushing queue\n", nlq6->peer.pid, nlh->nlmsg_pid);
-		ip6q_flush(nlq6);
-	}	
-	nlq6->peer.pid = nlh->nlmsg_pid;
-	nlq6->peer.died = 0;
-	status = ip6q_receive_peer(nlq6, NLMSG_DATA(nlh),
-	                          type, skb->len - NLMSG_LENGTH(0));
+	
+	write_lock_bh(&queue_lock);
+	
+	if (peer_pid) {
+		if (peer_pid != pid) {
+			write_unlock_bh(&queue_lock);
+			RCV_SKB_FAIL(-EBUSY);
+		}
+	}
+	else
+		peer_pid = pid;
+		
+	write_unlock_bh(&queue_lock);
+	
+	status = ipq_receive_peer(NLMSG_DATA(nlh), type,
+	                          skblen - NLMSG_LENGTH(0));
 	if (status < 0)
 		RCV_SKB_FAIL(status);
-	if (nlh->nlmsg_flags & NLM_F_ACK)
+		
+	if (flags & NLM_F_ACK)
 		netlink_ack(skb, nlh, 0);
         return;
 }
 
-/* Note: we are only dealing with single part messages at the moment. */
-static void netlink_receive_user_sk(struct sock *sk, int len)
+static void
+ipq_rcv_sk(struct sock *sk, int len)
 {
 	do {
 		struct sk_buff *skb;
 
-		if (rtnl_shlock_nowait())
+		if (down_trylock(&ipqnl_sem))
 			return;
+			
 		while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
-			netlink_receive_user_skb(skb);
+			ipq_rcv_skb(skb);
 			kfree_skb(skb);
 		}
-		up(&rtnl_sem);
-	} while (nfnl && nfnl->receive_queue.qlen);
-}
+		
+		up(&ipqnl_sem);
 
-/****************************************************************************
- *
- * System events
- *
- ****************************************************************************/
+	} while (ipqnl && ipqnl->receive_queue.qlen);
+}
 
-static int receive_event(struct notifier_block *this,
-                         unsigned long event, void *ptr)
+static int
+ipq_rcv_dev_event(struct notifier_block *this,
+                  unsigned long event, void *ptr)
 {
 	struct net_device *dev = ptr;
 
 	/* Drop any packets associated with the downed device */
 	if (event == NETDEV_DOWN)
-		ip6q_dev_drop(nlq6, dev->ifindex);
+		ipq_dev_drop(dev->ifindex);
 	return NOTIFY_DONE;
 }
 
-struct notifier_block ip6q_dev_notifier = {
-	receive_event,
+static struct notifier_block ipq_dev_notifier = {
+	ipq_rcv_dev_event,
 	NULL,
 	0
 };
 
-/****************************************************************************
- *
- * Sysctl - queue tuning.
- *
- ****************************************************************************/
+static int
+ipq_rcv_nl_event(struct notifier_block *this,
+                 unsigned long event, void *ptr)
+{
+	struct netlink_notify *n = ptr;
+
+	if (event == NETLINK_URELEASE &&
+	    n->protocol == NETLINK_IP6_FW && n->pid) {
+		write_lock_bh(&queue_lock);
+		if (n->pid == peer_pid)
+			__ipq_reset();
+		write_unlock_bh(&queue_lock);
+	}
+	return NOTIFY_DONE;
+}
 
-static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
+static struct notifier_block ipq_nl_notifier = {
+	ipq_rcv_nl_event,
+	NULL,
+	0
+};
 
-static struct ctl_table_header *ip6q_sysctl_header;
+static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
+static struct ctl_table_header *ipq_sysctl_header;
 
-static ctl_table ip6q_table[] = {
+static ctl_table ipq_table[] = {
 	{ NET_IPQ_QMAX, NET_IPQ_QMAX_NAME, &sysctl_maxlen,
 	  sizeof(sysctl_maxlen), 0644,  NULL, proc_dointvec },
  	{ 0 }
 };
 
-static ctl_table ip6q_dir_table[] = {
-	{NET_IPV6, "ipv6", NULL, 0, 0555, ip6q_table, 0, 0, 0, 0, 0},
+static ctl_table ipq_dir_table[] = {
+	{NET_IPV6, "ipv6", NULL, 0, 0555, ipq_table, 0, 0, 0, 0, 0},
 	{ 0 }
 };
 
-static ctl_table ip6q_root_table[] = {
-	{CTL_NET, "net", NULL, 0, 0555, ip6q_dir_table, 0, 0, 0, 0, 0},
+static ctl_table ipq_root_table[] = {
+	{CTL_NET, "net", NULL, 0, 0555, ipq_dir_table, 0, 0, 0, 0, 0},
 	{ 0 }
 };
 
-/****************************************************************************
- *
- * Procfs - debugging info.
- *
- ****************************************************************************/
-
-static int ip6q_get_info(char *buffer, char **start, off_t offset, int length)
+static int
+ipq_get_info(char *buffer, char **start, off_t offset, int length)
 {
 	int len;
 
-	spin_lock_bh(&nlq6->lock);
+	read_lock_bh(&queue_lock);
+	
 	len = sprintf(buffer,
-	              "Peer pid            : %d\n"
-	              "Peer died           : %d\n"
-	              "Peer copy mode      : %d\n"
-	              "Peer copy range     : %Zu\n"
-	              "Queue length        : %d\n"
-	              "Queue max. length   : %d\n"
-	              "Queue flushing      : %d\n"
-	              "Queue terminate     : %d\n",
-	              nlq6->peer.pid,
-	              nlq6->peer.died,
-	              nlq6->peer.copy_mode,
-	              nlq6->peer.copy_range,
-	              nlq6->len,
-	              *nlq6->maxlen,
-	              nlq6->flushing,
-	              nlq6->terminate);
-	spin_unlock_bh(&nlq6->lock);
+	              "Peer PID          : %d\n"
+	              "Copy mode         : %hu\n"
+	              "Copy range        : %u\n"
+	              "Queue length      : %u\n"
+	              "Queue max. length : %u\n",
+	              peer_pid,
+	              copy_mode,
+	              copy_range,
+	              queue_total,
+	              queue_maxlen);
+
+	read_unlock_bh(&queue_lock);
+	
 	*start = buffer + offset;
 	len -= offset;
 	if (len > length)
@@ -666,52 +673,70 @@
 	return len;
 }
 
-/****************************************************************************
- *
- * Module stuff.
- *
- ****************************************************************************/
-
-static int __init init(void)
+static int
+init_or_cleanup(int init)
 {
-	int status = 0;
+	int status = -ENOMEM;
 	struct proc_dir_entry *proc;
 	
-        /* We must create the NETLINK_IP6_FW protocol service */
-	nfnl = netlink_kernel_create(NETLINK_IP6_FW, netlink_receive_user_sk);
-	if (nfnl == NULL) {
-		printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
-		       "create kernel netlink socket\n");
-		return -ENOMEM;
+	if (!init)
+		goto cleanup;
+
+	netlink_register_notifier(&ipq_nl_notifier);
+	ipqnl = netlink_kernel_create(NETLINK_IP6_FW, ipq_rcv_sk);
+	if (ipqnl == NULL) {
+		printk(KERN_ERR "ip6_queue: failed to create netlink socket\n");
+		goto cleanup_netlink_notifier;
 	}
-	nlq6 = ip6q_create_queue(netfilter6_receive,
-	                       netlink_send_peer, &status, &sysctl_maxlen);
-	if (nlq6 == NULL) {
-		printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
-		       "create queue\n");
-		sock_release(nfnl->socket);
-		return status;
-	}
-        /* The file will be /proc/net/ip6_queue */
-	proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ip6q_get_info);
-	if (proc) proc->owner = THIS_MODULE;
+
+	proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ipq_get_info);
+	if (proc)
+		proc->owner = THIS_MODULE;
 	else {
-		ip6q_destroy_queue(nlq6);
-		sock_release(nfnl->socket);
-		return -ENOMEM;
+		printk(KERN_ERR "ip6_queue: failed to create proc entry\n");
+		goto cleanup_ipqnl;
+	}
+	
+	register_netdevice_notifier(&ipq_dev_notifier);
+	ipq_sysctl_header = register_sysctl_table(ipq_root_table, 0);
+	
+	status = nf_register_queue_handler(PF_INET6, ipq_enqueue_packet, NULL);
+	if (status < 0) {
+		printk(KERN_ERR "ip6_queue: failed to register queue handler\n");
+		goto cleanup_sysctl;
 	}
-	register_netdevice_notifier(&ip6q_dev_notifier);
-	ip6q_sysctl_header = register_sysctl_table(ip6q_root_table, 0);
+	return status;
+
+cleanup:
+	nf_unregister_queue_handler(PF_INET6);
+	br_write_lock_bh(BR_NETPROTO_LOCK);
+	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	ipq_flush(NF_DROP);
+	
+cleanup_sysctl:
+	unregister_sysctl_table(ipq_sysctl_header);
+	unregister_netdevice_notifier(&ipq_dev_notifier);
+	proc_net_remove(IPQ_PROC_FS_NAME);
+	
+cleanup_ipqnl:
+	sock_release(ipqnl->socket);
+	down(&ipqnl_sem);
+	up(&ipqnl_sem);
+	
+cleanup_netlink_notifier:
+	netlink_unregister_notifier(&ipq_nl_notifier);
 	return status;
 }
 
+static int __init init(void)
+{
+	
+	return init_or_cleanup(1);
+}
+
 static void __exit fini(void)
 {
-	unregister_sysctl_table(ip6q_sysctl_header);
-	proc_net_remove(IPQ_PROC_FS_NAME);
-	unregister_netdevice_notifier(&ip6q_dev_notifier);
-	ip6q_destroy_queue(nlq6);
-	sock_release(nfnl->socket);
+	init_or_cleanup(0);
 }
 
 MODULE_DESCRIPTION("IPv6 packet queue handler");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/netfilter/ip6_tables.c linux-2.4.20/net/ipv6/netfilter/ip6_tables.c
--- linux-2.4.19/net/ipv6/netfilter/ip6_tables.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv6/netfilter/ip6_tables.c	2002-10-29 11:18:36.000000000 +0000
@@ -7,6 +7,8 @@
  * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
  * 	- increase module usage count as soon as we have rules inside
  * 	  a table
+ * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu>
+ *      - new extension header parser code
  */
 #include <linux/config.h>
 #include <linux/skbuff.h>
@@ -25,6 +27,7 @@
 #include <linux/netfilter_ipv6/ip6_tables.h>
 
 #define IPV6_HDR_LEN	(sizeof(struct ipv6hdr))
+#define IPV6_OPTHDR_LEN	(sizeof(struct ipv6_opt_hdr))
 
 /*#define DEBUG_IP_FIREWALL*/
 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
@@ -133,43 +136,23 @@
 	return 0;
 }
 
-/* takes in current header and pointer to the header */
-/* if another header exists, sets hdrptr to the next header
-   and returns the new header value, else returns 0 */
-static u_int8_t ip6_nexthdr(u_int8_t currenthdr, u_int8_t *hdrptr)
-{
-	int i;
-	u_int8_t hdrlen, nexthdr = 0;
-	switch(currenthdr){
-		case IPPROTO_AH:
-		/* whoever decided to do the length of AUTH for ipv6
-		in 32bit units unlike other headers should be beaten...
-		repeatedly...with a large stick...no, an even LARGER
-		stick...no, you're still not thinking big enough */
-			nexthdr = *hdrptr;
-			hdrlen = hdrptr[i] * 4 + 8;
-			hdrptr = hdrptr + hdrlen;
-			break;
-		/*stupid rfc2402 */
-		case IPPROTO_DSTOPTS:
-		case IPPROTO_ROUTING:
-		case IPPROTO_HOPOPTS:
-			nexthdr = *hdrptr;
-			hdrlen = hdrptr[1] * 8 + 8;
-			hdrptr = hdrptr + hdrlen;
-			break;
-		case IPPROTO_FRAGMENT:
-			nexthdr = *hdrptr;
-			hdrptr = hdrptr + 8;
-			break;
-	}	
-	return nexthdr;
-
+/* Check for an extension */
+int 
+ip6t_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == IPPROTO_HOPOPTS)   ||
+                 (nexthdr == IPPROTO_ROUTING)   ||
+                 (nexthdr == IPPROTO_FRAGMENT)  ||
+                 (nexthdr == IPPROTO_ESP)       ||
+                 (nexthdr == IPPROTO_AH)        ||
+                 (nexthdr == IPPROTO_NONE)      ||
+                 (nexthdr == IPPROTO_DSTOPTS) );
 }
 
 /* Returns whether matches rule or not. */
 static inline int
-ip6_packet_match(const struct ipv6hdr *ipv6,
+ip6_packet_match(const struct sk_buff *skb,
+		 const struct ipv6hdr *ipv6,
 		 const char *indev,
 		 const char *outdev,
 		 const struct ip6t_ip6 *ip6info,
@@ -227,17 +210,58 @@
 	/* look for the desired protocol header */
 	if((ip6info->flags & IP6T_F_PROTO)) {
 		u_int8_t currenthdr = ipv6->nexthdr;
-		u_int8_t *hdrptr;
-		hdrptr = (u_int8_t *)(ipv6 + 1);
-		do {
-			if (ip6info->proto == currenthdr) {
-				if(ip6info->invflags & IP6T_INV_PROTO)
-					return 0;
-				return 1;
+		struct ipv6_opt_hdr *hdrptr;
+		u_int16_t ptr;		/* Header offset in skb */
+		u_int16_t hdrlen;	/* Header */
+
+		ptr = IPV6_HDR_LEN;
+
+		while (ip6t_ext_hdr(currenthdr)) {
+	                /* Is there enough space for the next ext header? */
+	                if (skb->len - ptr < IPV6_OPTHDR_LEN)
+	                        return 0;
+
+			/* NONE or ESP: there isn't protocol part */
+			/* If we want to count these packets in '-p all',
+			 * we will change the return 0 to 1*/
+			if ((currenthdr == IPPROTO_NONE) || 
+				(currenthdr == IPPROTO_ESP))
+				return 0;
+
+	                hdrptr = (struct ipv6_opt_hdr *)(skb->data + ptr);
+
+			/* Size calculation */
+	                if (currenthdr == IPPROTO_FRAGMENT) {
+	                        hdrlen = 8;
+	                } else if (currenthdr == IPPROTO_AH)
+	                        hdrlen = (hdrptr->hdrlen+2)<<2;
+	                else
+	                        hdrlen = ipv6_optlen(hdrptr);
+
+			currenthdr = hdrptr->nexthdr;
+	                ptr += hdrlen;
+			/* ptr is too large */
+	                if ( ptr > skb->len ) 
+				return 0;
+		}
+
+		/* currenthdr contains the protocol header */
+
+		dprintf("Packet protocol %hi ?= %s%hi.\n",
+				currenthdr, 
+				ip6info->invflags & IP6T_INV_PROTO ? "!":"",
+				ip6info->proto);
+
+		if (ip6info->proto == currenthdr) {
+			if(ip6info->invflags & IP6T_INV_PROTO) {
+				return 0;
 			}
-			currenthdr = ip6_nexthdr(currenthdr, hdrptr);
-		} while(currenthdr);
-		if (!(ip6info->invflags & IP6T_INV_PROTO))
+			return 1;
+		}
+
+		/* We need match for the '-p all', too! */
+		if ((ip6info->proto != 0) &&
+			!(ip6info->invflags & IP6T_INV_PROTO))
 			return 0;
 	}
 	return 1;
@@ -360,7 +384,8 @@
 		IP_NF_ASSERT(e);
 		IP_NF_ASSERT(back);
 		(*pskb)->nfcache |= e->nfcache;
-		if (ip6_packet_match(ipv6, indev, outdev, &e->ipv6, offset)) {
+		if (ip6_packet_match(*pskb, ipv6, indev, outdev, 
+			&e->ipv6, offset)) {
 			struct ip6t_entry_target *t;
 
 			if (IP6T_MATCH_ITERATE(e, do_match,
@@ -743,7 +768,7 @@
 	t = ip6t_get_target(e);
 	target = find_target_lock(t->u.user.name, &ret, &ip6t_mutex);
 	if (!target) {
-	  //		duprintf("check_entry: `%s' not found\n", t->u.name);
+		duprintf("check_entry: `%s' not found\n", t->u.user.name);
 		goto cleanup_matches;
 	}
 	if (target->me)
@@ -1469,6 +1494,9 @@
 	duprintf("table->private->number = %u\n",
 		 table->private->number);
 
+	/* save number of initial entries */
+	table->private->initial_entries = table->private->number;
+
 	table->lock = RW_LOCK_UNLOCKED;
 	list_prepend(&ip6t_tables, table);
 
@@ -1827,6 +1855,7 @@
 EXPORT_SYMBOL(ip6t_unregister_match);
 EXPORT_SYMBOL(ip6t_register_target);
 EXPORT_SYMBOL(ip6t_unregister_target);
+EXPORT_SYMBOL(ip6t_ext_hdr);
 
 module_init(init);
 module_exit(fini);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/netfilter/ip6t_LOG.c linux-2.4.20/net/ipv6/netfilter/ip6t_LOG.c
--- linux-2.4.19/net/ipv6/netfilter/ip6t_LOG.c	2001-11-05 17:53:07.000000000 +0000
+++ linux-2.4.20/net/ipv6/netfilter/ip6t_LOG.c	2002-10-29 11:18:36.000000000 +0000
@@ -112,7 +112,7 @@
 			printk("FRAG:%u ", ntohs(fhdr->frag_off) & 0xFFF8);
 
 			/* Max length: 11 "INCOMPLETE " */
-			if (fhdr->frag_off & __constant_htons(0x0001))
+			if (fhdr->frag_off & htons(0x0001))
 				printk("INCOMPLETE ");
 
 			printk("ID:%08x ", fhdr->identification);
@@ -289,12 +289,39 @@
 		/* MAC logging for input chain only. */
 		printk("MAC=");
 		if ((*pskb)->dev && (*pskb)->dev->hard_header_len && (*pskb)->mac.raw != (void*)ipv6h) {
-			int i;
-			unsigned char *p = (*pskb)->mac.raw;
-			for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
+			if ((*pskb)->dev->type != ARPHRD_SIT){
+			  int i;
+			  unsigned char *p = (*pskb)->mac.raw;
+			  for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
 				printk("%02x%c", *p,
-				       i==(*pskb)->dev->hard_header_len - 1
-				       ? ' ':':');
+			       		i==(*pskb)->dev->hard_header_len - 1
+			       		? ' ':':');
+			} else {
+			  int i;
+			  unsigned char *p = (*pskb)->mac.raw;
+			  if ( p - (ETH_ALEN*2+2) > (*pskb)->head ){
+			    p -= (ETH_ALEN+2);
+			    for (i = 0; i < (ETH_ALEN); i++,p++)
+				printk("%02x%s", *p,
+					i == ETH_ALEN-1 ? "->" : ":");
+			    p -= (ETH_ALEN*2);
+			    for (i = 0; i < (ETH_ALEN); i++,p++)
+				printk("%02x%c", *p,
+					i == ETH_ALEN-1 ? ' ' : ':');
+			  }
+			  
+			  if (((*pskb)->dev->addr_len == 4) &&
+			      (*pskb)->dev->hard_header_len > 20){
+			    printk("TUNNEL=");
+			    p = (*pskb)->mac.raw + 12;
+			    for (i = 0; i < 4; i++,p++)
+				printk("%3d%s", *p,
+					i == 3 ? "->" : ".");
+			    for (i = 0; i < 4; i++,p++)
+				printk("%3d%c", *p,
+					i == 3 ? ' ' : '.');
+			  }
+			}
 		} else
 			printk(" ");
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/netfilter/ip6t_eui64.c linux-2.4.20/net/ipv6/netfilter/ip6t_eui64.c
--- linux-2.4.19/net/ipv6/netfilter/ip6t_eui64.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/ipv6/netfilter/ip6t_eui64.c	2002-10-29 11:18:33.000000000 +0000
@@ -0,0 +1,89 @@
+/* Kernel module to match EUI64 address parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/if_ether.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+
+    unsigned char eui64[8];
+    int i=0;
+
+     if ( !(skb->mac.raw >= skb->head
+                && (skb->mac.raw + ETH_HLEN) <= skb->data)
+                && offset != 0) {
+                        *hotdrop = 1;
+                        return 0;
+                }
+    
+    memset(eui64, 0, sizeof(eui64));
+
+    if (skb->mac.ethernet->h_proto == ntohs(ETH_P_IPV6)) {
+      if (skb->nh.ipv6h->version == 0x6) { 
+         memcpy(eui64, skb->mac.ethernet->h_source, 3);
+         memcpy(eui64 + 5, skb->mac.ethernet->h_source + 3, 3);
+	 eui64[3]=0xff;
+	 eui64[4]=0xfe;
+	 eui64[0] |= 0x02;
+
+	 i=0;
+	 while ((skb->nh.ipv6h->saddr.in6_u.u6_addr8[8+i] ==
+			 eui64[i]) && (i<8)) i++;
+
+	 if ( i == 8 )
+	 	return 1;
+      }
+    }
+
+    return 0;
+}
+
+static int
+ip6t_eui64_checkentry(const char *tablename,
+		   const struct ip6t_ip6 *ip,
+		   void *matchinfo,
+		   unsigned int matchsize,
+		   unsigned int hook_mask)
+{
+	if (hook_mask
+	    & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
+		(1 << NF_IP6_PRE_ROUTING) )) {
+		printk("ip6t_eui64: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
+		return 0;
+	}
+
+	if (matchsize != IP6T_ALIGN(sizeof(int)))
+		return 0;
+
+	return 1;
+}
+
+static struct ip6t_match eui64_match
+= { { NULL, NULL }, "eui64", &match, &ip6t_eui64_checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ip6t_register_match(&eui64_match);
+}
+
+static void __exit fini(void)
+{
+	ip6t_unregister_match(&eui64_match);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_DESCRIPTION("IPv6 EUI64 address checking match");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/netfilter/ip6t_length.c linux-2.4.20/net/ipv6/netfilter/ip6t_length.c
--- linux-2.4.19/net/ipv6/netfilter/ip6t_length.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/ipv6/netfilter/ip6t_length.c	2002-10-29 11:18:47.000000000 +0000
@@ -0,0 +1,51 @@
+/* Length Match - IPv6 Port */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv6/ip6t_length.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct ip6t_length_info *info = matchinfo;
+	u_int16_t pktlen = ntohs(skb->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr);
+	
+	return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
+}
+
+static int
+checkentry(const char *tablename,
+           const struct ip6t_ip6 *ip,
+           void *matchinfo,
+           unsigned int matchsize,
+           unsigned int hook_mask)
+{
+	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_length_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ip6t_match length_match
+= { { NULL, NULL }, "length", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ip6t_register_match(&length_match);
+}
+
+static void __exit fini(void)
+{
+	ip6t_unregister_match(&length_match);
+}
+
+module_init(init);
+module_exit(fini);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/reassembly.c linux-2.4.20/net/ipv6/reassembly.c
--- linux-2.4.19/net/ipv6/reassembly.c	2001-04-12 19:11:39.000000000 +0000
+++ linux-2.4.20/net/ipv6/reassembly.c	2002-10-29 11:18:36.000000000 +0000
@@ -372,7 +372,7 @@
  				     csum_partial(skb->nh.raw, (u8*)(fhdr+1)-skb->nh.raw, 0));
 
 	/* Is this the final fragment? */
-	if (!(fhdr->frag_off & __constant_htons(0x0001))) {
+	if (!(fhdr->frag_off & htons(0x0001))) {
 		/* If we already have some bits beyond end
 		 * or have different end, the segment is corrupted.
 		 */
@@ -648,7 +648,7 @@
 	hdr = skb->nh.ipv6h;
 	fhdr = (struct frag_hdr *)skb->h.raw;
 
-	if (!(fhdr->frag_off & __constant_htons(0xFFF9))) {
+	if (!(fhdr->frag_off & htons(0xFFF9))) {
 		/* It is not a fragmented frame */
 		skb->h.raw += sizeof(struct frag_hdr);
 		IP6_INC_STATS_BH(Ip6ReasmOKs);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/route.c linux-2.4.20/net/ipv6/route.c
--- linux-2.4.19/net/ipv6/route.c	2001-12-21 17:42:05.000000000 +0000
+++ linux-2.4.20/net/ipv6/route.c	2002-10-29 11:18:34.000000000 +0000
@@ -976,7 +976,11 @@
 		if (net_ratelimit())
 			printk(KERN_DEBUG "rt6_pmtu_discovery: invalid MTU value %d\n",
 			       pmtu);
-		return;
+		/* According to RFC1981, the PMTU is set to the IPv6 minimum
+		   link MTU if the node receives a Packet Too Big message
+		   reporting next-hop MTU that is less than the IPv6 minimum MTU.
+		 */	
+		pmtu = IPV6_MIN_MTU;
 	}
 
 	rt = rt6_lookup(daddr, saddr, dev->ifindex, 0);
@@ -1014,7 +1018,13 @@
 		nrt = rt6_cow(rt, daddr, saddr);
 		if (!nrt->u.dst.error) {
 			nrt->u.dst.pmtu = pmtu;
-			dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);
+			/* According to RFC 1981, detecting PMTU increase shouldn't be
+			   happened within 5 mins, the recommended timer is 10 mins.
+			   Here this route expiration time is set to ip6_rt_mtu_expires 
+			   which is 10 mins. After 10 mins the decreased pmtu is expired
+			   and detecting PMTU increase will be automatically happened.
+			 */
+			dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
 			nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
 			dst_release(&nrt->u.dst);
 		}
@@ -1026,7 +1036,7 @@
 		nrt->rt6i_dst.plen = 128;
 		nrt->u.dst.flags |= DST_HOST;
 		nrt->rt6i_nexthop = neigh_clone(rt->rt6i_nexthop);
-		dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);
+		dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
 		nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES;
 		nrt->u.dst.pmtu = pmtu;
 		rt6_ins(nrt);
@@ -1380,15 +1390,32 @@
 static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
 {
 	struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
-
+	struct inet6_dev *idev;
 	/* In IPv6 pmtu discovery is not optional,
 	   so that RTAX_MTU lock cannot disable it.
 	   We still use this lock to block changes
 	   caused by addrconf/ndisc.
 	*/
+	idev = __in6_dev_get(arg->dev);
+	/* For administrative MTU increase, there is no way to discover 
+	   IPv6 PMTU increase, so PMTU increase should be updated here.
+	   Since RFC 1981 doesn't include administrative MTU increase
+	   update PMTU increase is a MUST. (i.e. jumbo frame)
+	 */
+	/*
+	   If new MTU is less than route PMTU, this new MTU will be the 
+	   lowest MTU in the path, update the route PMTU to refect PMTU 
+	   decreases; if new MTU is greater than route PMTU, and the 
+	   old MTU is the lowest MTU in the path, update the route PMTU 
+	   to refect the increase. In this case if the other nodes' MTU
+	   also have the lowest MTU, TOO BIG MESSAGE will be lead to 
+	   PMTU discouvery. 
+	 */
 	if (rt->rt6i_dev == arg->dev &&
-	    rt->u.dst.pmtu > arg->mtu &&
-	    !(rt->u.dst.mxlock&(1<<RTAX_MTU)))
+	    !(rt->u.dst.mxlock&(1<<RTAX_MTU)) &&
+	      (rt->u.dst.pmtu > arg->mtu ||
+	       (rt->u.dst.pmtu < arg->mtu &&
+		rt->u.dst.pmtu == idev->cnf.mtu6)))
 		rt->u.dst.pmtu = arg->mtu;
 	rt->u.dst.advmss = max_t(unsigned int, arg->mtu - 60, ip6_rt_min_advmss);
 	if (rt->u.dst.advmss > 65535-20)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/sit.c linux-2.4.20/net/ipv6/sit.c
--- linux-2.4.19/net/ipv6/sit.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv6/sit.c	2002-10-29 11:18:50.000000000 +0000
@@ -396,7 +396,7 @@
 		skb->mac.raw = skb->nh.raw;
 		skb->nh.raw = skb->data;
 		memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
-		skb->protocol = __constant_htons(ETH_P_IPV6);
+		skb->protocol = htons(ETH_P_IPV6);
 		skb->pkt_type = PACKET_HOST;
 		tunnel->stat.rx_packets++;
 		tunnel->stat.rx_bytes += skb->len;
@@ -470,7 +470,7 @@
 		goto tx_error;
 	}
 
-	if (skb->protocol != __constant_htons(ETH_P_IPV6))
+	if (skb->protocol != htons(ETH_P_IPV6))
 		goto tx_error;
 
 	if (!dst)
@@ -588,7 +588,7 @@
 	iph->version		=	4;
 	iph->ihl		=	sizeof(struct iphdr)>>2;
 	if (mtu > IPV6_MIN_MTU)
-		iph->frag_off	=	__constant_htons(IP_DF);
+		iph->frag_off	=	htons(IP_DF);
 	else
 		iph->frag_off	=	0;
 
@@ -659,10 +659,10 @@
 
 		err = -EINVAL;
 		if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPV6 ||
-		    p.iph.ihl != 5 || (p.iph.frag_off&__constant_htons(~IP_DF)))
+		    p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
 			goto done;
 		if (p.iph.ttl)
-			p.iph.frag_off |= __constant_htons(IP_DF);
+			p.iph.frag_off |= htons(IP_DF);
 
 		t = ipip6_tunnel_locate(&p, cmd == SIOCADDTUNNEL);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/tcp_ipv6.c linux-2.4.20/net/ipv6/tcp_ipv6.c
--- linux-2.4.19/net/ipv6/tcp_ipv6.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv6/tcp_ipv6.c	2002-10-29 11:18:31.000000000 +0000
@@ -402,7 +402,7 @@
 
 static __u32 tcp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
 {
-	if (skb->protocol == __constant_htons(ETH_P_IPV6)) {
+	if (skb->protocol == htons(ETH_P_IPV6)) {
 		return secure_tcpv6_sequence_number(skb->nh.ipv6h->daddr.s6_addr32,
 						    skb->nh.ipv6h->saddr.s6_addr32,
 						    skb->h.th->dest,
@@ -617,9 +617,9 @@
 			sk->backlog_rcv = tcp_v6_do_rcv;
 			goto failure;
 		} else {
-			ipv6_addr_set(&np->saddr, 0, 0, __constant_htonl(0x0000FFFF),
+			ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
 				      sk->saddr);
-			ipv6_addr_set(&np->rcv_saddr, 0, 0, __constant_htonl(0x0000FFFF),
+			ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
 				      sk->rcv_saddr);
 		}
 
@@ -1031,10 +1031,10 @@
 	
 	if (ts) {
 		u32 *ptr = (u32*)(t1 + 1);
-		*ptr++ = __constant_htonl((TCPOPT_NOP << 24) |
-					  (TCPOPT_NOP << 16) |
-					  (TCPOPT_TIMESTAMP << 8) |
-					  TCPOLEN_TIMESTAMP);
+		*ptr++ = htonl((TCPOPT_NOP << 24) |
+			       (TCPOPT_NOP << 16) |
+			       (TCPOPT_TIMESTAMP << 8) |
+			       TCPOLEN_TIMESTAMP);
 		*ptr++ = htonl(tcp_time_stamp);
 		*ptr = htonl(ts);
 	}
@@ -1145,7 +1145,7 @@
 	struct open_request *req = NULL;
 	__u32 isn = TCP_SKB_CB(skb)->when;
 
-	if (skb->protocol == __constant_htons(ETH_P_IP))
+	if (skb->protocol == htons(ETH_P_IP))
 		return tcp_v4_conn_request(sk, skb);
 
 	/* FIXME: do the same check for anycast */
@@ -1224,7 +1224,7 @@
 	struct sock *newsk;
 	struct ipv6_txoptions *opt;
 
-	if (skb->protocol == __constant_htons(ETH_P_IP)) {
+	if (skb->protocol == htons(ETH_P_IP)) {
 		/*
 		 *	v6 mapped
 		 */
@@ -1236,10 +1236,10 @@
 
 		np = &newsk->net_pinfo.af_inet6;
 
-		ipv6_addr_set(&np->daddr, 0, 0, __constant_htonl(0x0000FFFF),
+		ipv6_addr_set(&np->daddr, 0, 0, htonl(0x0000FFFF),
 			      newsk->daddr);
 
-		ipv6_addr_set(&np->saddr, 0, 0, __constant_htonl(0x0000FFFF),
+		ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
 			      newsk->saddr);
 
 		ipv6_addr_copy(&np->rcv_saddr, &np->saddr);
@@ -1425,7 +1425,7 @@
 	   tcp_v6_hnd_req and tcp_v6_send_reset().   --ANK
 	 */
 
-	if (skb->protocol == __constant_htons(ETH_P_IP))
+	if (skb->protocol == htons(ETH_P_IP))
 		return tcp_v4_do_rcv(sk, skb);
 
 #ifdef CONFIG_FILTER
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/ipv6/udp.c linux-2.4.20/net/ipv6/udp.c
--- linux-2.4.19/net/ipv6/udp.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/ipv6/udp.c	2002-10-29 11:18:35.000000000 +0000
@@ -267,18 +267,18 @@
 			return err;
 		
 		ipv6_addr_set(&np->daddr, 0, 0, 
-			      __constant_htonl(0x0000ffff),
+			      htonl(0x0000ffff),
 			      sk->daddr);
 
 		if(ipv6_addr_any(&np->saddr)) {
 			ipv6_addr_set(&np->saddr, 0, 0, 
-				      __constant_htonl(0x0000ffff),
+				      htonl(0x0000ffff),
 				      sk->saddr);
 		}
 
 		if(ipv6_addr_any(&np->rcv_saddr)) {
 			ipv6_addr_set(&np->rcv_saddr, 0, 0, 
-				      __constant_htonl(0x0000ffff),
+				      htonl(0x0000ffff),
 				      sk->rcv_saddr);
 		}
 		return 0;
@@ -420,9 +420,9 @@
 		sin6->sin6_flowinfo = 0;
 		sin6->sin6_scope_id = 0;
 
-		if (skb->protocol == __constant_htons(ETH_P_IP)) {
+		if (skb->protocol == htons(ETH_P_IP)) {
 			ipv6_addr_set(&sin6->sin6_addr, 0, 0,
-				      __constant_htonl(0xffff), skb->nh.iph->saddr);
+				      htonl(0xffff), skb->nh.iph->saddr);
 			if (sk->protinfo.af_inet.cmsg_flags)
 				ip_cmsg_recv(msg, skb);
 		} else {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/af_irda.c linux-2.4.20/net/irda/af_irda.c
--- linux-2.4.19/net/irda/af_irda.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/irda/af_irda.c	2002-10-29 11:18:36.000000000 +0000
@@ -414,6 +414,7 @@
  * hint bits), and then wake up any process waiting for answer...
  */
 static void irda_selective_discovery_indication(discovery_t *discovery,
+						DISCOVERY_MODE mode,
 						void *priv)
 {
 	struct irda_sock *self;
@@ -1290,6 +1291,9 @@
 		/* Check if we are still connected */
 		if (sk->state != TCP_ESTABLISHED)
 			return -ENOTCONN;
+		/* Handle signals */
+		if (signal_pending(current)) 
+			return -ERESTARTSYS;
 	}
 
 	/* Check that we don't send out to big frames */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/discovery.c linux-2.4.20/net/irda/discovery.c
--- linux-2.4.19/net/irda/discovery.c	2000-11-12 02:11:23.000000000 +0000
+++ linux-2.4.20/net/irda/discovery.c	2002-10-29 11:18:35.000000000 +0000
@@ -108,7 +108,7 @@
 {
 	discovery_t *discovery;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	/*
 	 *  If log is missing this means that IrLAP was unable to perform the
@@ -144,7 +144,7 @@
 	discovery_t *discovery, *curr;
 	unsigned long flags;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	spin_lock_irqsave(&irlmp->log_lock, flags);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/ircomm/ircomm_tty.c linux-2.4.20/net/irda/ircomm/ircomm_tty.c
--- linux-2.4.19/net/irda/ircomm/ircomm_tty.c	2001-09-30 19:26:09.000000000 +0000
+++ linux-2.4.20/net/irda/ircomm/ircomm_tty.c	2002-10-29 11:18:36.000000000 +0000
@@ -93,7 +93,7 @@
 {	
 	ircomm_tty = hashbin_new(HB_LOCAL); 
 	if (ircomm_tty == NULL) {
-		ERROR(__FUNCTION__ "(), can't allocate hashbin!\n");
+		ERROR("%s(), can't allocate hashbin!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 
@@ -136,7 +136,7 @@
 	driver.read_proc       = ircomm_tty_read_proc;
 #endif /* CONFIG_PROC_FS */
 	if (tty_register_driver(&driver)) {
-		ERROR(__FUNCTION__ "Couldn't register serial driver\n");
+		ERROR("%s: Couldn't register serial driver\n", __FUNCTION__);
 		return -1;
 	}
 	return 0;
@@ -145,7 +145,7 @@
 #ifdef MODULE
 static void __ircomm_tty_cleanup(struct ircomm_tty_cb *self)
 {
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -166,11 +166,11 @@
 {
 	int ret;
 
-	IRDA_DEBUG(4, __FUNCTION__"()\n");	
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ret = tty_unregister_driver(&driver);
         if (ret) {
-                ERROR(__FUNCTION__ "(), failed to unregister driver\n");
+                ERROR("%s, failed to unregister driver\n", __FUNCTION__);
 		return;
 	}
 
@@ -189,14 +189,14 @@
 	notify_t notify;
 	int ret;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	/* Already open */
 	if (self->flags & ASYNC_INITIALIZED) {
-		IRDA_DEBUG(2, __FUNCTION__ "(), already open so break out!\n");
+		IRDA_DEBUG(2, "%s(), already open so break out!\n", __FUNCTION__);
 		return 0;
 	}
 
@@ -226,7 +226,7 @@
 	/* Connect IrCOMM link with remote device */
 	ret = ircomm_tty_attach_cable(self);
 	if (ret < 0) {
-		ERROR(__FUNCTION__ "(), error attaching cable!\n");
+		ERROR("%s(), error attaching cable!\n", __FUNCTION__);
 		return ret;
 	}
 
@@ -250,7 +250,7 @@
 	unsigned long	flags;
 	struct tty_struct *tty;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	tty = self->tty;
 
@@ -282,18 +282,18 @@
 			return -EBUSY;
 		self->flags |= ASYNC_NORMAL_ACTIVE;
 
-		IRDA_DEBUG(1, __FUNCTION__ "(), O_NONBLOCK requested!\n");
+		IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __FUNCTION__);
 		return 0;
 	}
 
 	if (self->flags & ASYNC_CALLOUT_ACTIVE) {
 		if (self->normal_termios.c_cflag & CLOCAL) {
-			IRDA_DEBUG(1, __FUNCTION__ "(), doing CLOCAL!\n");
+			IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __FUNCTION__);
 			do_clocal = 1;
 		}
 	} else {
 		if (tty->termios->c_cflag & CLOCAL) {
-			IRDA_DEBUG(1, __FUNCTION__ "(), doing CLOCAL!\n");
+			IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __FUNCTION__);
 			do_clocal = 1;
 		}
 	}
@@ -390,7 +390,7 @@
 	int line;
 	int ret;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	MOD_INC_USE_COUNT;
 	line = MINOR(tty->device) - tty->driver.minor_start;
@@ -405,7 +405,7 @@
 		/* No, so make new instance */
 		self = kmalloc(sizeof(struct ircomm_tty_cb), GFP_KERNEL);
 		if (self == NULL) {
-			ERROR(__FUNCTION__"(), kmalloc failed!\n");
+			ERROR("%s(), kmalloc failed!\n", __FUNCTION__);
 			MOD_DEC_USE_COUNT;
 			return -ENOMEM;
 		}
@@ -417,7 +417,7 @@
 		self->line = line;
 		self->tqueue.routine = ircomm_tty_do_softint;
 		self->tqueue.data = self;
-		self->max_header_size = 5;
+		self->max_header_size = IRCOMM_TTY_HDR_UNITIALISED;
 		self->max_data_size = 64-self->max_header_size;
 		self->close_delay = 5*HZ/10;
 		self->closing_wait = 30*HZ;
@@ -443,8 +443,8 @@
 	tty->driver_data = self;
 	self->tty = tty;
 
-	IRDA_DEBUG(1, __FUNCTION__"(), %s%d, count = %d\n", tty->driver.name, 
-		   self->line, self->open_count);
+	IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __FUNCTION__,
+		tty->driver.name, self->line, self->open_count);
 
 	/* Not really used by us, but lets do it anyway */
 	self->tty->low_latency = (self->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
@@ -470,9 +470,9 @@
 		self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;
 		self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */
 		self->settings.dce = IRCOMM_CTS | IRCOMM_CD; /* Default line settings */
-		IRDA_DEBUG(2, __FUNCTION__ "(), IrCOMM device\n");
+		IRDA_DEBUG(2, "%s(), IrCOMM device\n", __FUNCTION__);
 	} else {
-		IRDA_DEBUG(2, __FUNCTION__ "(), IrLPT device\n");
+		IRDA_DEBUG(2, "%s(), IrLPT device\n", __FUNCTION__);
 		self->service_type = IRCOMM_3_WIRE_RAW;
 		self->settings.service_type = IRCOMM_3_WIRE_RAW; /* Default */
 	}
@@ -484,9 +484,8 @@
 	ret = ircomm_tty_block_til_ready(self, filp);
 	if (ret) {
 		/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
-		IRDA_DEBUG(2, __FUNCTION__ 
-		      "(), returning after block_til_ready with %d\n",
-		      ret);
+		IRDA_DEBUG(2, "%s(), returning after block_til_ready with %d\n",
+			__FUNCTION__, ret);
 
 		return ret;
 	}
@@ -508,7 +507,7 @@
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
 	unsigned long flags;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	if (!tty)
 		return;
@@ -520,7 +519,7 @@
 		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 
-		IRDA_DEBUG(0, __FUNCTION__ "(), returning 1\n");
+		IRDA_DEBUG(0, "%s(), returning 1\n", __FUNCTION__);
 		return;
 	}
 
@@ -535,23 +534,22 @@
 		 * one, we've got real problems, since it means the
 		 * serial port won't be shutdown.
 		 */
-		IRDA_DEBUG(0, __FUNCTION__ "(), bad serial port count; "
+		IRDA_DEBUG(0, "%s(), bad serial port count; "
 			   "tty->count is 1, state->count is %d\n", 
-			   self->open_count);
+			   __FUNCTION__, self->open_count);
 		self->open_count = 1;
 	}
 
 	if (--self->open_count < 0) {
-		ERROR(__FUNCTION__ 
-		      "(), bad serial port count for ttys%d: %d\n",
-		      self->line, self->open_count);
+		ERROR("%s(), bad serial port count for ttys%d: %d\n",
+			__FUNCTION__, self->line, self->open_count);
 		self->open_count = 0;
 	}
 	if (self->open_count) {
 		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 
-		IRDA_DEBUG(0, __FUNCTION__ "(), open count > 0\n");
+		IRDA_DEBUG(0, "%s(), open count > 0\n", __FUNCTION__);
 		return;
 	}
 	self->flags |= ASYNC_CLOSING;
@@ -625,7 +623,7 @@
 	unsigned long flags;
 	struct sk_buff *skb, *ctrl_skb;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	if (!self || self->magic != IRCOMM_TTY_MAGIC)
 		return;
@@ -690,12 +688,26 @@
 	int len = 0;
 	int size;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), count=%d, hw_stopped=%d\n", count,
-		   tty->hw_stopped);
+	IRDA_DEBUG(2, "%s(), count=%d, hw_stopped=%d\n", 
+		__FUNCTION__, count, tty->hw_stopped);
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
+	/* We may receive packets from the TTY even before we have finished
+	 * our setup. Not cool.
+	 * The problem is that we would allocate a skb with bogus header and
+	 * data size, and when adding data to it later we would get
+	 * confused.
+	 * Better to not accept data until we are properly setup. Use bogus
+	 * header size to check that (safest way to detect it).
+	 * Jean II */
+	if (self->max_header_size == IRCOMM_TTY_HDR_UNITIALISED) {
+		/* TTY will retry */
+		IRDA_DEBUG(2, __FUNCTION__ "() : not initialised\n");
+		return len;
+	}
+
 	save_flags(flags);
 	cli();
 
@@ -792,8 +804,12 @@
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
-	/* Check if we are allowed to transmit any data */
-	if (tty->hw_stopped)
+	/* Check if we are allowed to transmit any data.
+	 * hw_stopped is the regular flow control.
+	 * max_header_size tells us if the channel is initialised or not.
+	 * Jean II */
+	if ((tty->hw_stopped) ||
+	    (self->max_header_size == IRCOMM_TTY_HDR_UNITIALISED))
 		ret = 0;
 	else {
 		save_flags(flags);
@@ -804,7 +820,7 @@
 			ret = self->max_data_size;
 		restore_flags(flags);
 	}
-	IRDA_DEBUG(2, __FUNCTION__ "(), ret=%d\n", ret);
+	IRDA_DEBUG(2, "%s(), ret=%d\n", __FUNCTION__, ret);
 
 	return ret;
 }
@@ -820,7 +836,7 @@
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
 	unsigned long orig_jiffies, poll_time;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -852,7 +868,7 @@
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -883,7 +899,7 @@
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -898,7 +914,7 @@
 		self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS);
 
 		ircomm_param_request(self, IRCOMM_DTE, TRUE);
-		IRDA_DEBUG(1, __FUNCTION__"(), FLOW_START\n");
+		IRDA_DEBUG(1, "%s(), FLOW_START\n", __FUNCTION__);
 	}
         ircomm_flow_request(self->ircomm, FLOW_START);
 }
@@ -936,7 +952,7 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 	
 	if (!(self->flags & ASYNC_INITIALIZED))
 		return;
@@ -980,7 +996,7 @@
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
 
-	IRDA_DEBUG(0, __FUNCTION__"()\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -1005,7 +1021,7 @@
  */
 static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch)
 {
-	IRDA_DEBUG(0, __FUNCTION__"(), not impl\n");
+	IRDA_DEBUG(0, "%s(), not impl\n", __FUNCTION__);
 }
 
 /*
@@ -1049,7 +1065,7 @@
 	struct tty_struct *tty;
 	int status;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -1062,17 +1078,15 @@
 		/*wake_up_interruptible(&self->delta_msr_wait);*/
 	}
 	if ((self->flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) {
-		IRDA_DEBUG(2, __FUNCTION__ 
-			   "(), ircomm%d CD now %s...\n", self->line,
-			   (status & IRCOMM_CD) ? "on" : "off");
+		IRDA_DEBUG(2, "%s(), ircomm%d CD now %s...\n", 
+			__FUNCTION__, self->line, (status & IRCOMM_CD) ? "on" : "off");
 
 		if (status & IRCOMM_CD) {
 			wake_up_interruptible(&self->open_wait);
 		} else if (!((self->flags & ASYNC_CALLOUT_ACTIVE) &&
 			   (self->flags & ASYNC_CALLOUT_NOHUP))) 
 		{
-			IRDA_DEBUG(2, __FUNCTION__ 
-				   "(), Doing serial hangup..\n");
+			IRDA_DEBUG(2, "%s(), Doing serial hangup..\n", __FUNCTION__);
 			if (tty)
 				tty_hangup(tty);
 
@@ -1083,8 +1097,7 @@
 	if (self->flags & ASYNC_CTS_FLOW) {
 		if (tty->hw_stopped) {
 			if (status & IRCOMM_CTS) {
-				IRDA_DEBUG(2, __FUNCTION__ 
-					   "(), CTS tx start...\n");
+				IRDA_DEBUG(2, "%s(), CTS tx start...\n", __FUNCTION__);
 				tty->hw_stopped = 0;
 				
 				/* Wake up processes blocked on open */
@@ -1096,8 +1109,7 @@
 			}
 		} else {
 			if (!(status & IRCOMM_CTS)) {
-				IRDA_DEBUG(2, __FUNCTION__ 
-					   "(), CTS tx stop...\n");
+				IRDA_DEBUG(2, "%s(), CTS tx stop...\n", __FUNCTION__);
 				tty->hw_stopped = 1;
 			}
 		}
@@ -1115,14 +1127,14 @@
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 
-	IRDA_DEBUG(2, __FUNCTION__"()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 	
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 	ASSERT(skb != NULL, return -1;);
 
 	if (!self->tty) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), no tty!\n");
+		IRDA_DEBUG(0, "%s(), no tty!\n", __FUNCTION__);
 		dev_kfree_skb(skb);
 		return 0;
 	}
@@ -1134,7 +1146,7 @@
 	 * params, we can just as well declare the hardware for running.
 	 */
 	if (self->tty->hw_stopped && (self->flow == FLOW_START)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), polling for line settings!\n");
+		IRDA_DEBUG(0, "%s(), polling for line settings!\n", __FUNCTION__);
 		ircomm_param_request(self, IRCOMM_POLL, TRUE);
 
 		/* We can just as well declare the hardware for running */
@@ -1165,7 +1177,7 @@
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 	int clen;
 
-	IRDA_DEBUG(4, __FUNCTION__"()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 	
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
@@ -1200,7 +1212,7 @@
 
 	switch (cmd) {
 	case FLOW_START:
-		IRDA_DEBUG(2, __FUNCTION__ "(), hw start!\n");
+		IRDA_DEBUG(2, "%s(), hw start!\n", __FUNCTION__);
 		tty->hw_stopped = 0;
 
 		/* ircomm_tty_do_softint will take care of the rest */
@@ -1209,7 +1221,7 @@
 		break;
 	default:  /* If we get here, something is very wrong, better stop */
 	case FLOW_STOP:
-		IRDA_DEBUG(2, __FUNCTION__ "(), hw stopped!\n");
+		IRDA_DEBUG(2, "%s(), hw stopped!\n", __FUNCTION__);
 		tty->hw_stopped = 1;
 		break;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/ircomm/ircomm_tty_attach.c linux-2.4.20/net/irda/ircomm/ircomm_tty_attach.c
--- linux-2.4.19/net/irda/ircomm/ircomm_tty_attach.c	2001-07-25 21:12:03.000000000 +0000
+++ linux-2.4.20/net/irda/ircomm/ircomm_tty_attach.c	2002-10-29 11:18:37.000000000 +0000
@@ -47,6 +47,7 @@
 
 static void ircomm_tty_ias_register(struct ircomm_tty_cb *self);
 static void ircomm_tty_discovery_indication(discovery_t *discovery,
+					    DISCOVERY_MODE mode,
 					    void *priv);
 static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, 
 					struct ias_value *value, void *priv);
@@ -305,6 +306,7 @@
  *
  */
 static void ircomm_tty_discovery_indication(discovery_t *discovery,
+					    DISCOVERY_MODE mode,
 					    void *priv)
 {
 	struct ircomm_tty_cb *self;
@@ -312,6 +314,20 @@
 
 	IRDA_DEBUG(2, __FUNCTION__"()\n");
 
+	/* Important note :
+	 * We need to drop all passive discoveries.
+	 * The LSAP management of IrComm is deficient and doesn't deal
+	 * with the case of two instance connecting to each other
+	 * simultaneously (it will deadlock in LMP).
+	 * The proper fix would be to use the same technique as in IrNET,
+	 * to have one server socket and separate instances for the
+	 * connecting/connected socket.
+	 * The workaround is to drop passive discovery, which drastically
+	 * reduce the probability of this happening.
+	 * Jean II */
+	if(mode == DISCOVERY_PASSIVE)
+		return;
+
 	info.daddr = discovery->daddr;
 	info.saddr = discovery->saddr;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/ircomm/ircomm_tty_ioctl.c linux-2.4.20/net/irda/ircomm/ircomm_tty_ioctl.c
--- linux-2.4.19/net/irda/ircomm/ircomm_tty_ioctl.c	2001-07-04 18:50:38.000000000 +0000
+++ linux-2.4.20/net/irda/ircomm/ircomm_tty_ioctl.c	2002-10-29 11:18:31.000000000 +0000
@@ -94,6 +94,9 @@
 	if (cflag & CRTSCTS) {
 		self->flags |= ASYNC_CTS_FLOW;
 		self->settings.flow_control |= IRCOMM_RTS_CTS_IN;
+		/* This got me. Bummer. Jean II */
+		if (self->service_type == IRCOMM_3_WIRE_RAW)
+			WARNING(__FUNCTION__ "(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n");
 	} else {
 		self->flags &= ~ASYNC_CTS_FLOW;
 		self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/iriap.c linux-2.4.20/net/irda/iriap.c
--- linux-2.4.19/net/irda/iriap.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.20/net/irda/iriap.c	2002-10-29 11:18:35.000000000 +0000
@@ -98,7 +98,7 @@
 
 	objects = hashbin_new(HB_LOCAL);
 	if (!objects) {
-		WARNING(__FUNCTION__ "(), Can't allocate objects hashbin!\n");
+		WARNING("%s(), Can't allocate objects hashbin!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 
@@ -128,7 +128,7 @@
 	 */
 	server = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
 	if (!server) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), unable to open server\n");
+		IRDA_DEBUG(0, "%s(), unable to open server\n", __FUNCTION__);
 		return -1;
 	}
 	iriap_register_lsap(server, LSAP_IAS, IAS_SERVER);
@@ -160,11 +160,11 @@
 {
 	struct iriap_cb *self;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	self = kmalloc(sizeof(struct iriap_cb), GFP_ATOMIC);
 	if (!self) {
-		WARNING(__FUNCTION__ "(), Unable to kmalloc!\n");
+		WARNING("%s(), Unable to kmalloc!\n", __FUNCTION__);
 		return NULL;
 	}
 
@@ -202,7 +202,7 @@
  */
 static void __iriap_close(struct iriap_cb *self)
 {
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IAS_MAGIC, return;);
@@ -226,7 +226,7 @@
 {
 	struct iriap_cb *entry;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IAS_MAGIC, return;);
@@ -246,7 +246,7 @@
 {
 	notify_t notify;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	irda_notify_init(&notify);
 	notify.connect_confirm       = iriap_connect_confirm;
@@ -261,7 +261,7 @@
 
 	self->lsap = irlmp_open_lsap(slsap_sel, &notify, 0);
 	if (self->lsap == NULL) {
-		ERROR(__FUNCTION__ "(), Unable to allocated LSAP!\n");
+		ERROR("%s(), Unable to allocated LSAP!\n", __FUNCTION__);
 		return -1;
 	}
 	self->slsap_sel = self->lsap->slsap_sel;
@@ -281,7 +281,7 @@
 {
 	struct iriap_cb *self;
 
-	IRDA_DEBUG(4, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]);
+	IRDA_DEBUG(4, "%s(), reason=%s\n", __FUNCTION__, lmp_reasons[reason]);
 
 	self = (struct iriap_cb *) instance;
 
@@ -293,7 +293,7 @@
 	del_timer(&self->watchdog_timer);
 
 	if (self->mode == IAS_CLIENT) {
-		IRDA_DEBUG(4, __FUNCTION__ "(), disconnect as client\n");
+		IRDA_DEBUG(4, "%s(), disconnect as client\n", __FUNCTION__);
 
 
 		iriap_do_client_event(self, IAP_LM_DISCONNECT_INDICATION, 
@@ -306,7 +306,7 @@
 		if (self->confirm)
  			self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
 	} else {
-		IRDA_DEBUG(4, __FUNCTION__ "(), disconnect as server\n");
+		IRDA_DEBUG(4, "%s(), disconnect as server\n", __FUNCTION__);
 		iriap_do_server_event(self, IAP_LM_DISCONNECT_INDICATION, 
 				      NULL);
 		iriap_close(self);
@@ -326,15 +326,15 @@
 {
 	struct sk_buff *skb;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IAS_MAGIC, return;);
 
 	skb = dev_alloc_skb(64);
 	if (skb == NULL) {
-		IRDA_DEBUG(0, __FUNCTION__
-		      "(), Could not allocate an sk_buff of length %d\n", 64);
+		IRDA_DEBUG(0, "%s(), Could not allocate an sk_buff of length %d\n", 
+			__FUNCTION__, 64);
 		return;
 	}
 
@@ -348,27 +348,27 @@
 
 void iriap_getinfobasedetails_request(void) 
 {
-	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n");
+	IRDA_DEBUG(0, "%s(), Not implemented!\n", __FUNCTION__);
 }
 
 void iriap_getinfobasedetails_confirm(void) 
 {
-	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n");
+	IRDA_DEBUG(0, "%s(), Not implemented!\n", __FUNCTION__);
 }
 
 void iriap_getobjects_request(void) 
 {
-	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n");
+	IRDA_DEBUG(0, "%s(), Not implemented!\n", __FUNCTION__);
 }
 
 void iriap_getobjects_confirm(void) 
 {
-	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n");
+	IRDA_DEBUG(0, "%s(), Not implemented!\n", __FUNCTION__);
 }
 
 void iriap_getvalue(void) 
 {
-	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n");
+	IRDA_DEBUG(0, "%s(), Not implemented!\n", __FUNCTION__);
 }
 
 /*
@@ -458,13 +458,13 @@
 	/* Get length, MSB first */
 	len = be16_to_cpu(get_unaligned((__u16 *)(fp+n))); n += 2;
 
-	IRDA_DEBUG(4, __FUNCTION__ "(), len=%d\n", len);
+	IRDA_DEBUG(4, "%s(), len=%d\n", __FUNCTION__, len);
 
 	/* Get object ID, MSB first */
 	obj_id = be16_to_cpu(get_unaligned((__u16 *)(fp+n))); n += 2;
 
 	type = fp[n++];
-	IRDA_DEBUG(4, __FUNCTION__ "(), Value type = %d\n", type);
+	IRDA_DEBUG(4, "%s(), Value type = %d\n", __FUNCTION__, type);
 
 	switch (type) {
 	case IAS_INTEGER:
@@ -473,7 +473,7 @@
 		value = irias_new_integer_value(tmp_cpu32);
 
 		/*  Legal values restricted to 0x01-0x6f, page 15 irttp */
-		IRDA_DEBUG(4, __FUNCTION__ "(), lsap=%d\n", value->t.integer); 
+		IRDA_DEBUG(4, "%s(), lsap=%d\n", __FUNCTION__, value->t.integer); 
 		break;
 	case IAS_STRING:
 		charset = fp[n++];
@@ -492,9 +492,8 @@
 /* 		case CS_ISO_8859_9: */
 /* 		case CS_UNICODE: */
 		default:
-			IRDA_DEBUG(0, __FUNCTION__
-				   "(), charset %s, not supported\n",
-				   ias_charset_types[charset]);
+			IRDA_DEBUG(0, "%s(), charset %s, not supported\n",
+				   __FUNCTION__, ias_charset_types[charset]);
 
 			/* Aborting, close connection! */
 			iriap_disconnect_request(self);
@@ -503,7 +502,7 @@
 			/* break; */
 		}
 		value_len = fp[n++];
-		IRDA_DEBUG(4, __FUNCTION__ "(), strlen=%d\n", value_len);
+		IRDA_DEBUG(4, "%s(), strlen=%d\n", __FUNCTION__, value_len);
 		
 		/* Make sure the string is null-terminated */
 		fp[n+value_len] = 0x00;
@@ -533,7 +532,7 @@
 	if (self->confirm)
 		self->confirm(IAS_SUCCESS, obj_id, value, self->priv);
 	else {
-		IRDA_DEBUG(0, __FUNCTION__ "(), missing handler!\n");
+		IRDA_DEBUG(0, "%s(), missing handler!\n", __FUNCTION__);
 		irias_delete_value(value);
 	}
 	dev_kfree_skb(skb);
@@ -553,7 +552,7 @@
 	__u32 tmp_be32, tmp_be16;
 	__u8 *fp;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IAS_MAGIC, return;);
@@ -614,12 +613,12 @@
 		memcpy(fp+n, value->t.oct_seq, value->len); n+=value->len;
 		break;
 	case IAS_MISSING:
-		IRDA_DEBUG( 3, __FUNCTION__ ": sending IAS_MISSING\n");
+		IRDA_DEBUG( 3, "%s: sending IAS_MISSING\n", __FUNCTION__);
 		skb_put(skb, 1);
 		fp[n++] = value->type;
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), type not implemented!\n");
+		IRDA_DEBUG(0, "%s(), type not implemented!\n", __FUNCTION__);
 		break;
 	}
 	iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, skb);
@@ -643,7 +642,7 @@
 	__u8 *fp;
 	int n;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IAS_MAGIC, return;);
@@ -700,7 +699,7 @@
 	struct sk_buff *skb;
 	__u8 *frame;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IAS_MAGIC, return;);
@@ -731,7 +730,7 @@
 				    self->saddr, self->daddr, 
 				    NULL, NULL);
 	if (ret < 0) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), connect failed!\n");
+		IRDA_DEBUG(0, "%s(), connect failed!\n", __FUNCTION__);
 		self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
 	}
 }
@@ -776,7 +775,7 @@
 {
 	struct iriap_cb *self, *new;
 
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
 	self = (struct iriap_cb *) instance;
 
@@ -786,7 +785,7 @@
 	/* Start new server */
 	new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL); 
 	if (!new) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), open failed\n");
+		IRDA_DEBUG(0, "%s(), open failed\n", __FUNCTION__);
 		dev_kfree_skb(userdata);
 		return;
 	}
@@ -794,7 +793,7 @@
 	/* Now attach up the new "socket" */
 	new->lsap = irlmp_dup(self->lsap, new);
 	if (!new->lsap) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), dup failed!\n");
+		IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__);
 		return;
 	}
 		
@@ -820,7 +819,7 @@
 	__u8  *frame;
 	__u8  opcode;
 	
-	IRDA_DEBUG(3, __FUNCTION__ "()\n"); 
+	IRDA_DEBUG(3, "%s()\n", __FUNCTION__); 
 	
 	self = (struct iriap_cb *) instance;
 
@@ -833,22 +832,22 @@
 	
 	if (self->mode == IAS_SERVER) {
 		/* Call server */
-		IRDA_DEBUG(4, __FUNCTION__ "(), Calling server!\n");
+		IRDA_DEBUG(4, "%s(), Calling server!\n", __FUNCTION__);
 		iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb);
 
 		return 0;
 	}
 	opcode = frame[0];
 	if (~opcode & IAP_LST) {
-		WARNING(__FUNCTION__ "(), IrIAS multiframe commands or "
-			"results is not implemented yet!\n");
+		WARNING("%s(), IrIAS multiframe commands or "
+			"results is not implemented yet!\n", __FUNCTION__);
 		dev_kfree_skb(skb);
 		return 0;
 	}
 	
 	/* Check for ack frames since they don't contain any data */
 	if (opcode & IAP_ACK) {
-		IRDA_DEBUG(0, __FUNCTION__ "() Got ack frame!\n");
+		IRDA_DEBUG(0, "%s() Got ack frame!\n", __FUNCTION__);
 		dev_kfree_skb(skb);
 	 	return 0;
 	}
@@ -868,7 +867,7 @@
 			iriap_getvaluebyclass_confirm(self, skb);
 			break;
 		case IAS_CLASS_UNKNOWN:
-			IRDA_DEBUG(1, __FUNCTION__ "(), No such class!\n");
+			IRDA_DEBUG(1, "%s(), No such class!\n", __FUNCTION__);
 			/* Finished, close connection! */
 			iriap_disconnect_request(self);
 
@@ -882,7 +881,7 @@
 			dev_kfree_skb(skb);
 			break;
 		case IAS_ATTRIB_UNKNOWN:
-			IRDA_DEBUG(1, __FUNCTION__ "(), No such attribute!\n");
+			IRDA_DEBUG(1, "%s(), No such attribute!\n", __FUNCTION__);
 		       	/* Finished, close connection! */
 			iriap_disconnect_request(self);
 
@@ -898,8 +897,7 @@
 		}		
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown op-code: %02x\n", 
-			   opcode);
+		IRDA_DEBUG(0, "%s(), Unknown op-code: %02x\n", __FUNCTION__, opcode);
 		dev_kfree_skb(skb);
 		break;
 	}
@@ -917,7 +915,7 @@
 	__u8 *fp;
 	__u8 opcode;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IAS_MAGIC, return;);
@@ -927,16 +925,16 @@
 
 	opcode = fp[0];
 	if (~opcode & 0x80) {
-		WARNING(__FUNCTION__ "(), IrIAS multiframe commands or results"
-			"is not implemented yet!\n");
+		WARNING("%s(), IrIAS multiframe commands or results"
+			"is not implemented yet!\n", __FUNCTION__);
 		return;
 	}
 	opcode &= 0x7f; /* Mask away LST bit */
 	
 	switch (opcode) {
 	case GET_INFO_BASE:
-		WARNING(__FUNCTION__ 
-			"(), GetInfoBaseDetails not implemented yet!\n");
+		WARNING("%s(), GetInfoBaseDetails not implemented yet!\n",
+			__FUNCTION__);
 		break;
 	case GET_VALUE_BY_CLASS:
 		iriap_getvaluebyclass_indication(self, skb);
@@ -1020,8 +1018,7 @@
 				len += sprintf(buf+len, "missing\n");
 				break;
 			default:
-				IRDA_DEBUG(0, __FUNCTION__ 
-				      "(), Unknown value type!\n");
+				IRDA_DEBUG(0, "%s(), Unknown value type!\n", __FUNCTION__);
 				return -1;
 			}
 			len += sprintf(buf+len, "\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/iriap_event.c linux-2.4.20/net/irda/iriap_event.c
--- linux-2.4.19/net/irda/iriap_event.c	2000-03-02 19:41:11.000000000 +0000
+++ linux-2.4.20/net/irda/iriap_event.c	2002-10-29 11:18:35.000000000 +0000
@@ -181,7 +181,7 @@
 	case IAP_LM_DISCONNECT_INDICATION:
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__"(), Unknown event %d\n", event);
+		IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event);
 		break;
 	}
 }
@@ -213,7 +213,7 @@
 		iriap_next_client_state(self, S_DISCONNECT);
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event);
 		break;
 	}
 }
@@ -262,7 +262,7 @@
 		iriap_next_call_state(self, S_OUTSTANDING);
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event);
 		if (skb)
 			dev_kfree_skb(skb);
 		break;
@@ -278,7 +278,7 @@
 static void state_s_calling(struct iriap_cb *self, IRIAP_EVENT event, 
 			    struct sk_buff *skb) 
 {
-	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
+	IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
 }
 
 /*
@@ -300,7 +300,7 @@
 		iriap_next_call_state(self, S_WAIT_FOR_CALL);
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %d\n", event);
+		IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event);
 		break;
 	}		
 }
@@ -313,7 +313,7 @@
 static void state_s_replying(struct iriap_cb *self, IRIAP_EVENT event, 
 			     struct sk_buff *skb) 
 {
-	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
+	IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
 }
 
 /*
@@ -325,7 +325,7 @@
 static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event, 
 				  struct sk_buff *skb) 
 {
-	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
+	IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
 }
 
 
@@ -338,7 +338,7 @@
 static void state_s_wait_active(struct iriap_cb *self, IRIAP_EVENT event, 
 				struct sk_buff *skb) 
 {
-	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
+	IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
 }
 
 /**************************************************************************
@@ -362,7 +362,7 @@
 	case IAP_LM_CONNECT_INDICATION:
 		tx_skb = dev_alloc_skb(64);
 		if (tx_skb == NULL) {
-			WARNING(__FUNCTION__ "(), unable to malloc!\n");
+			WARNING("%s(), unable to malloc!\n", __FUNCTION__);
 			return;
 		}
 
@@ -385,7 +385,7 @@
 		
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), unknown event %d\n", event);
+		IRDA_DEBUG(0, "%s(), unknown event %d\n", __FUNCTION__, event);
 		break;
 	}		
 }
@@ -399,7 +399,7 @@
 static void state_r_call(struct iriap_cb *self, IRIAP_EVENT event, 
 			 struct sk_buff *skb) 
 {
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	switch (event) {
 	case IAP_LM_DISCONNECT_INDICATION:
@@ -408,7 +408,7 @@
 		iriap_next_r_connect_state(self, R_WAITING);		
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), unknown event!\n");
+		IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__);
 		break;
 	}
 }
@@ -426,13 +426,13 @@
 static void state_r_waiting(struct iriap_cb *self, IRIAP_EVENT event, 
 			    struct sk_buff *skb) 
 {
-	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
+	IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
 }
 
 static void state_r_wait_active(struct iriap_cb *self, IRIAP_EVENT event, 
 				struct sk_buff *skb) 
 {
-	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
+	IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
 }
 
 /*
@@ -444,7 +444,7 @@
 static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event, 
 			      struct sk_buff *skb) 
 {
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	switch (event) {
 	case IAP_RECV_F_LST:
@@ -453,7 +453,7 @@
 		iriap_call_indication(self, skb);
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), unknown event!\n");
+		IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__);
 		break;
 	}
 
@@ -468,12 +468,12 @@
 static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event, 
 			    struct sk_buff *skb) 
 {
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(skb != NULL, return;);
 	
 	if (!self || self->magic != IAS_MAGIC) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), bad pointer self\n");
+		IRDA_DEBUG(0, "%s(), bad pointer self\n", __FUNCTION__);
 		return;
 	}	
 
@@ -488,7 +488,7 @@
 		irlmp_data_request(self->lsap, skb);
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), unknown event!\n");
+		IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__);
 		break;
 	}
 }
@@ -496,7 +496,7 @@
 static void state_r_returning(struct iriap_cb *self, IRIAP_EVENT event, 
 			      struct sk_buff *skb) 
 {
-	IRDA_DEBUG(0, __FUNCTION__ "(), event=%d\n", event);
+	IRDA_DEBUG(0, "%s(), event=%d\n", __FUNCTION__, event);
 
 	switch (event) {
 	case IAP_RECV_F_LST:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/irlan/irlan_client.c linux-2.4.20/net/irda/irlan/irlan_client.c
--- linux-2.4.19/net/irda/irlan/irlan_client.c	2001-02-08 21:08:38.000000000 +0000
+++ linux-2.4.20/net/irda/irlan/irlan_client.c	2002-10-29 11:18:48.000000000 +0000
@@ -145,7 +145,9 @@
  *    Remote device with IrLAN server support discovered
  *
  */
-void irlan_client_discovery_indication(discovery_t *discovery, void *priv) 
+void irlan_client_discovery_indication(discovery_t *discovery,
+				       DISCOVERY_MODE mode,
+				       void *priv) 
 {
 	struct irlan_cb *self;
 	__u32 saddr, daddr;
@@ -155,6 +157,15 @@
 	ASSERT(irlan != NULL, return;);
 	ASSERT(discovery != NULL, return;);
 
+	/*
+	 * I didn't check it, but I bet that IrLAN suffer from the same
+	 * deficiency as IrComm and doesn't handle two instances
+	 * simultaneously connecting to each other.
+	 * Same workaround, drop passive discoveries.
+	 * Jean II */
+	if(mode == DISCOVERY_PASSIVE)
+		return;
+
 	saddr = discovery->saddr;
 	daddr = discovery->daddr;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/irlap.c linux-2.4.20/net/irda/irlap.c
--- linux-2.4.19/net/irda/irlap.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/irda/irlap.c	2002-10-29 11:18:38.000000000 +0000
@@ -82,7 +82,7 @@
 	/* Allocate master array */
 	irlap = hashbin_new(HB_LOCAL);
 	if (irlap == NULL) {
-	        ERROR(__FUNCTION__ "(), can't allocate irlap hashbin!\n");
+	        ERROR("%s(), can't allocate irlap hashbin!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 
@@ -107,7 +107,7 @@
 {
 	struct irlap_cb *self;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 	
 	/* Initialize the irlap structure. */
 	self = kmalloc(sizeof(struct irlap_cb), GFP_KERNEL);
@@ -202,7 +202,7 @@
 {
 	struct irlap_cb *lap;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 	
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -215,7 +215,7 @@
 	/* Be sure that we manage to remove ourself from the hash */
 	lap = hashbin_remove(irlap, self->saddr, NULL);
 	if (!lap) {
-		IRDA_DEBUG(1, __FUNCTION__ "(), Didn't find myself!\n");
+		IRDA_DEBUG(1, "%s(), Didn't find myself!\n", __FUNCTION__);
 		return;
 	}
 	__irlap_close(lap);
@@ -229,7 +229,7 @@
  */
 void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb) 
 {
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -249,7 +249,7 @@
  */
 void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb) 
 {
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 	
 	irlap_do_event(self, CONNECT_RESPONSE, skb, NULL);
 	kfree_skb(skb);
@@ -265,7 +265,7 @@
 void irlap_connect_request(struct irlap_cb *self, __u32 daddr, 
 			   struct qos_info *qos_user, int sniff) 
 {
-	IRDA_DEBUG(3, __FUNCTION__ "(), daddr=0x%08x\n", daddr);
+	IRDA_DEBUG(3, "%s(), daddr=0x%08x\n", __FUNCTION__, daddr);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -292,7 +292,7 @@
  */
 void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -331,7 +331,7 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
 
-	IRDA_DEBUG(3, __FUNCTION__ "()\n");
+	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
 	ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), 
 	       return;);
@@ -375,7 +375,7 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
 
-	IRDA_DEBUG(3, __FUNCTION__ "()\n");
+	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
 	ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), 
 	       return;);
@@ -399,7 +399,7 @@
 #ifdef CONFIG_IRDA_ULTRA
 void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb)
 {
-	IRDA_DEBUG(1, __FUNCTION__ "()\n"); 
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__); 
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -420,7 +420,7 @@
  */
 void irlap_disconnect_request(struct irlap_cb *self) 
 {
-	IRDA_DEBUG(3, __FUNCTION__ "()\n");
+	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -442,7 +442,7 @@
 		irlap_do_event(self, DISCONNECT_REQUEST, NULL, NULL);
 		break;
 	default:
-		IRDA_DEBUG(2, __FUNCTION__ "(), disconnect pending!\n");
+		IRDA_DEBUG(2, "%s(), disconnect pending!\n", __FUNCTION__);
 		self->disconnect_pending = TRUE;
 		break;
 	}
@@ -456,7 +456,7 @@
  */
 void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason) 
 {
-	IRDA_DEBUG(1, __FUNCTION__ "(), reason=%s\n", lap_reasons[reason]); 
+	IRDA_DEBUG(1, "%s(), reason=%s\n", __FUNCTION__, lap_reasons[reason]); 
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -466,7 +466,7 @@
 	
 	switch (reason) {
 	case LAP_RESET_INDICATION:
-		IRDA_DEBUG(1, __FUNCTION__ "(), Sending reset request!\n");
+		IRDA_DEBUG(1, "%s(), Sending reset request!\n", __FUNCTION__);
 		irlap_do_event(self, RESET_REQUEST, NULL, NULL);
 		break;
 	case LAP_NO_RESPONSE:	   /* FALLTROUGH */	
@@ -477,7 +477,7 @@
 						 reason, NULL);
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), Unknown reason %d\n", reason);
+		ERROR("%s(), Unknown reason %d\n", __FUNCTION__, reason);
 	}
 }
 
@@ -495,7 +495,7 @@
 	ASSERT(self->magic == LAP_MAGIC, return;);
 	ASSERT(discovery != NULL, return;);
 	
-	IRDA_DEBUG(4, __FUNCTION__ "(), nslots = %d\n", discovery->nslots);
+	IRDA_DEBUG(4, "%s(), nslots = %d\n", __FUNCTION__, discovery->nslots);
 
 	ASSERT((discovery->nslots == 1) || (discovery->nslots == 6) ||
 	       (discovery->nslots == 8) || (discovery->nslots == 16), 
@@ -503,8 +503,8 @@
 	
   	/* Discovery is only possible in NDM mode */
 	if (self->state != LAP_NDM) {
-		IRDA_DEBUG(4, __FUNCTION__ 
-			   "(), discovery only possible in NDM mode\n");
+		IRDA_DEBUG(4, "%s(), discovery only possible in NDM mode\n",
+			__FUNCTION__);
 		irlap_discovery_confirm(self, NULL);
 		/* Note : in theory, if we are not in NDM, we could postpone
 		 * the discovery like we do for connection request.
@@ -575,7 +575,7 @@
  */
 void irlap_discovery_indication(struct irlap_cb *self, discovery_t *discovery) 
 {
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -627,7 +627,7 @@
  */
 void irlap_reset_indication(struct irlap_cb *self)
 {
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -646,7 +646,7 @@
  */
 void irlap_reset_confirm(void)
 {
- 	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+ 	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 }
 
 /*
@@ -746,7 +746,7 @@
 {
 	/*  nr as expected?  */
 	if (nr == self->vs) {
-		IRDA_DEBUG(4, __FUNCTION__ "(), expected!\n");
+		IRDA_DEBUG(4, "%s(), expected!\n", __FUNCTION__);
 		return NR_EXPECTED;
 	}
 
@@ -774,7 +774,7 @@
  */
 void irlap_initiate_connection_state(struct irlap_cb *self) 
 {
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 	
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -857,7 +857,7 @@
 {
 	struct sk_buff *skb;
 
-	IRDA_DEBUG(0, __FUNCTION__ "(), setting speed to %d\n", speed);
+	IRDA_DEBUG(0, "%s(), setting speed to %d\n", __FUNCTION__, speed);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -899,7 +899,7 @@
 	 *  user may not have set all of them.
 	 */
 	if (qos_user) {
-		IRDA_DEBUG(1, __FUNCTION__ "(), Found user specified QoS!\n");
+		IRDA_DEBUG(1, "%s(), Found user specified QoS!\n", __FUNCTION__);
 
 		if (qos_user->baud_rate.bits)
 			self->qos_rx.baud_rate.bits &= qos_user->baud_rate.bits;
@@ -930,7 +930,7 @@
  */
 void irlap_apply_default_connection_parameters(struct irlap_cb *self)
 {
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
@@ -993,7 +993,7 @@
  */
 void irlap_apply_connection_parameters(struct irlap_cb *self, int now) 
 {
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 	
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/irlap_event.c linux-2.4.20/net/irda/irlap_event.c
--- linux-2.4.19/net/irda/irlap_event.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/irda/irlap_event.c	2002-10-29 11:18:48.000000000 +0000
@@ -174,6 +174,12 @@
 	irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL);
 }
 
+/*
+ * Calculate and set time before we will have to send back the pf bit
+ * to the peer. Use in primary.
+ * Make sure that state is XMIT_P/XMIT_S when calling this function
+ * (and that nobody messed up with the state). - Jean II
+ */
 void irlap_start_poll_timer(struct irlap_cb *self, int timeout)
 {
 	ASSERT(self != NULL, return;);
@@ -1163,15 +1169,26 @@
 				self->ack_required = TRUE;
 			
 				irlap_wait_min_turn_around(self, &self->qos_tx);
-				/* 
-				 * Important to switch state before calling
-				 * upper layers
-				 */
-				irlap_next_state(self, LAP_XMIT_P);
 
+				/* Call higher layer *before* changing state
+				 * to give them a chance to send data in the
+				 * next LAP frame.
+				 * Jean II */
 				irlap_data_indication(self, skb, FALSE);
 
-				/* This is the last frame */
+				/* XMIT states are the most dangerous state
+				 * to be in, because user requests are
+				 * processed directly and may change state.
+				 * On the other hand, in NDM_P, those
+				 * requests are queued and we will process
+				 * them when we return to irlap_do_event().
+				 * Jean II
+				 */
+				irlap_next_state(self, LAP_XMIT_P);
+
+				/* This is the last frame.
+				 * Make sure it's always called in XMIT state.
+				 * - Jean II */
 				irlap_start_poll_timer(self, self->poll_timeout);
 			}
 			break;
@@ -1309,6 +1326,7 @@
 		} else {
 			del_timer(&self->final_timer);
 			irlap_data_indication(self, skb, TRUE);
+			irlap_next_state(self, LAP_XMIT_P);
 			printk(__FUNCTION__ "(): RECV_UI_FRAME: next state %s\n", irlap_state[self->state]);
 			irlap_start_poll_timer(self, self->poll_timeout);
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/irlmp.c linux-2.4.20/net/irda/irlmp.c
--- linux-2.4.19/net/irda/irlmp.c	2001-12-21 17:42:06.000000000 +0000
+++ linux-2.4.20/net/irda/irlmp.c	2002-10-29 11:18:50.000000000 +0000
@@ -76,7 +76,7 @@
  */
 int __init irlmp_init(void)
 {
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 	/* Initialize the irlmp structure. */
 	irlmp = kmalloc( sizeof(struct irlmp_cb), GFP_KERNEL);
 	if (irlmp == NULL)
@@ -155,7 +155,7 @@
 	/* Allocate new instance of a LSAP connection */
 	self = kmalloc(sizeof(struct lsap_cb), GFP_ATOMIC);
 	if (self == NULL) {
-		ERROR(__FUNCTION__ "(), can't allocate memory");
+		ERROR("%s(), can't allocate memory", __FUNCTION__);
 		return NULL;
 	}
 	memset(self, 0, sizeof(struct lsap_cb));
@@ -194,7 +194,7 @@
  */
 static void __irlmp_close_lsap(struct lsap_cb *self)
 {
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
@@ -245,8 +245,7 @@
 				      NULL);
 	}
 	if (!lsap) {
-		IRDA_DEBUG(0, __FUNCTION__ 
-		     "(), Looks like somebody has removed me already!\n");
+		IRDA_DEBUG(0, "%s(), Looks like somebody has removed me already!\n", __FUNCTION__);
 		return;
 	}
 	__irlmp_close_lsap(self);
@@ -272,7 +271,7 @@
 	 */
 	lap = kmalloc(sizeof(struct lap_cb), GFP_KERNEL);
 	if (lap == NULL) {
-		ERROR(__FUNCTION__ "(), unable to kmalloc\n");
+		ERROR("%s(), unable to kmalloc\n", __FUNCTION__);
 		return;
 	}
 	memset(lap, 0, sizeof(struct lap_cb));
@@ -310,7 +309,7 @@
 {
 	struct lap_cb *link;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	link = hashbin_remove(irlmp->links, saddr, NULL);
 	if (link) {
@@ -344,9 +343,8 @@
 	ASSERT(self != NULL, return -EBADR;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;);
 	
-	IRDA_DEBUG(2, __FUNCTION__ 
-	      "(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n", 
-	      self->slsap_sel, dlsap_sel, saddr, daddr);
+	IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n", 
+		__FUNCTION__, self->slsap_sel, dlsap_sel, saddr, daddr);
 	
 	if (test_bit(0, &self->connected))
 		return -EISCONN;
@@ -383,7 +381,7 @@
 		if (daddr != DEV_ADDR_ANY)
 			discovery = hashbin_find(irlmp->cachelog, daddr, NULL);
 		else {
-			IRDA_DEBUG(2, __FUNCTION__ "(), no daddr\n");
+			IRDA_DEBUG(2, "%s(), no daddr\n", __FUNCTION__);
 			discovery = (discovery_t *) 
 				hashbin_get_first(irlmp->cachelog);
 		}
@@ -395,7 +393,7 @@
 	}
 	lap = hashbin_find(irlmp->links, saddr, NULL);	
 	if (lap == NULL) {
-		IRDA_DEBUG(1, __FUNCTION__ "(), Unable to find a usable link!\n");
+		IRDA_DEBUG(1, "%s(), Unable to find a usable link!\n", __FUNCTION__);
 		return -EHOSTUNREACH;
 	}
 
@@ -412,13 +410,13 @@
 			 * disconnected yet (waiting for timeout in LAP).
 			 * Maybe we could give LAP a bit of help in this case.
 			 */
-			IRDA_DEBUG(0, __FUNCTION__ "(), sorry, but I'm waiting for LAP to timeout!\n");
+			IRDA_DEBUG(0, "%s(), sorry, but I'm waiting for LAP to timeout!\n", __FUNCTION__);
 			return -EAGAIN;
 		}
 
 		/* LAP is already connected to a different node, and LAP
 		 * can only talk to one node at a time */
-		IRDA_DEBUG(0, __FUNCTION__ "(), sorry, but link is busy!\n");
+		IRDA_DEBUG(0, "%s(), sorry, but link is busy!\n", __FUNCTION__);
 		return -EBUSY;
 	}
 
@@ -467,8 +465,8 @@
 	ASSERT(skb != NULL, return;);
 	ASSERT(self->lap != NULL, return;);
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
-		   self->slsap_sel, self->dlsap_sel);
+	IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n", 
+		__FUNCTION__, self->slsap_sel, self->dlsap_sel);
 
 	/* Note : self->lap is set in irlmp_link_data_indication(),
 	 * (case CONNECT_CMD:) because we have no way to set it here.
@@ -506,8 +504,8 @@
 
 	set_bit(0, &self->connected);	/* TRUE */
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
-		   self->slsap_sel, self->dlsap_sel);
+	IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n", 
+		__FUNCTION__, self->slsap_sel, self->dlsap_sel);
 
 	/* Make room for MUX control header (3 bytes) */
 	ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return -1;);
@@ -529,7 +527,7 @@
 	int lap_header_size;
 	int max_seg_size;
 
-	IRDA_DEBUG(3, __FUNCTION__ "()\n");
+	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 	
 	ASSERT(skb != NULL, return;);
 	ASSERT(self != NULL, return;);
@@ -542,8 +540,8 @@
 	lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap);	
 	max_header_size = LMP_HEADER + lap_header_size;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), max_header_size=%d\n", 
-		   max_header_size);
+	IRDA_DEBUG(2, "%s(), max_header_size=%d\n",
+		__FUNCTION__, max_header_size);
 
 	/* Hide LMP_CONTROL_HEADER header from layer above */
 	skb_pull(skb, LMP_CONTROL_HEADER);
@@ -567,16 +565,16 @@
 {
 	struct lsap_cb *new;
 
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
 	/* Only allowed to duplicate unconnected LSAP's */
 	if (!hashbin_find(irlmp->unconnected_lsaps, (int) orig, NULL)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), unable to find LSAP\n");
+		IRDA_DEBUG(0, "%s(), unable to find LSAP\n", __FUNCTION__);
 		return NULL;
 	}
 	new = kmalloc(sizeof(struct lsap_cb), GFP_ATOMIC);
 	if (!new)  {
-		IRDA_DEBUG(0, __FUNCTION__ "(), unable to kmalloc\n");
+		IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __FUNCTION__);
 		return NULL;
 	}
 	/* Dup */
@@ -617,7 +615,7 @@
 	 * and us that might mess up the hashbins below. This fixes it.
 	 * Jean II */
 	if (! test_and_clear_bit(0, &self->connected)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), already disconnected!\n");
+		IRDA_DEBUG(0, "%s(), already disconnected!\n", __FUNCTION__);
 		dev_kfree_skb(userdata);
 		return -1;
 	}
@@ -664,19 +662,19 @@
 {
 	struct lsap_cb *lsap;
 
-	IRDA_DEBUG(1, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]);
+	IRDA_DEBUG(1, "%s(), reason=%s\n", __FUNCTION__, lmp_reasons[reason]);
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
 
-	IRDA_DEBUG(3, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
-		   self->slsap_sel, self->dlsap_sel);
+	IRDA_DEBUG(3, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n", 
+		__FUNCTION__, self->slsap_sel, self->dlsap_sel);
 
 	/* Already disconnected ?
 	 * There is a race condition between irlmp_disconnect_request()
 	 * and us that might mess up the hashbins below. This fixes it.
 	 * Jean II */
 	if (! test_and_clear_bit(0, &self->connected)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), already disconnected!\n");
+		IRDA_DEBUG(0, "%s(), already disconnected!\n", __FUNCTION__);
 		if (userdata)
 			dev_kfree_skb(userdata);
 		return;
@@ -709,7 +707,7 @@
 		self->notify.disconnect_indication(self->notify.instance, 
 						   self, reason, userdata);
 	else {
-		IRDA_DEBUG(0, __FUNCTION__ "(), no handler\n");
+		IRDA_DEBUG(0, "%s(), no handler\n", __FUNCTION__);
 		if (userdata)
 			dev_kfree_skb(userdata);
 	}
@@ -732,7 +730,9 @@
 	 * On links which are connected, we can't do discovery
 	 * anymore and can't refresh the log, so we freeze the
 	 * discovery log to keep info about the device we are
-	 * connected to. - Jean II
+	 * connected to.
+	 * This info is mandatory if we want irlmp_connect_request()
+	 * to work properly. - Jean II
 	 */
 	lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
 	while (lap != NULL) {
@@ -760,8 +760,7 @@
 
 	/* Make sure the value is sane */
 	if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){
-		WARNING(__FUNCTION__ 
-		       "(), invalid value for number of slots!\n");
+		WARNING("%s(), invalid value for number of slots!\n", __FUNCTION__);
 		nslots = sysctl_discovery_slots = 8;
 	}
 
@@ -804,7 +803,7 @@
 void irlmp_discovery_request(int nslots)
 {
 	/* Return current cached discovery log */
-	irlmp_discovery_confirm(irlmp->cachelog);
+	irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_LOG);
 
 	/* 
 	 * Start a single discovery operation if discovery is not already
@@ -907,11 +906,12 @@
  * partial/selective discovery based on the hints that it passed to IrLMP.
  */
 static inline void
-irlmp_notify_client(irlmp_client_t *client, hashbin_t *log)
+irlmp_notify_client(irlmp_client_t *client,
+		    hashbin_t *log, DISCOVERY_MODE mode)
 {
 	discovery_t *discovery;
 
-	IRDA_DEBUG(3, __FUNCTION__ "()\n");
+	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 	
 	/* Check if client wants or not partial/selective log (optimisation) */
 	if (!client->disco_callback)
@@ -930,7 +930,7 @@
 		 * bits ;-)
 		 */
 		if (client->hint_mask & discovery->hints.word & 0x7f7f)
-			client->disco_callback(discovery, client->priv);
+			client->disco_callback(discovery, mode, client->priv);
 
 		discovery = (discovery_t *) hashbin_get_next(log);
 	}
@@ -943,11 +943,11 @@
  *    device it is, and give indication to the client(s)
  * 
  */
-void irlmp_discovery_confirm(hashbin_t *log) 
+void irlmp_discovery_confirm(hashbin_t *log, DISCOVERY_MODE mode) 
 {
 	irlmp_client_t *client;
 	
-	IRDA_DEBUG(3, __FUNCTION__ "()\n");
+	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 	
 	ASSERT(log != NULL, return;);
 	
@@ -957,7 +957,7 @@
 	client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
 	while (client != NULL) {
 		/* Check if we should notify client */
-		irlmp_notify_client(client, log);
+		irlmp_notify_client(client, log, mode);
 			
 		client = (irlmp_client_t *) hashbin_get_next(irlmp->clients);
 	}
@@ -978,7 +978,7 @@
 {
 	irlmp_client_t *client;
 	
-	IRDA_DEBUG(3, __FUNCTION__ "()\n");
+	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
 	ASSERT(expiry != NULL, return;);
 	
@@ -987,7 +987,8 @@
 		/* Check if we should notify client */
 		if ((client->expir_callback) &&
 		    (client->hint_mask & expiry->hints.word & 0x7f7f))
-			client->expir_callback(expiry, client->priv);
+			client->expir_callback(expiry, EXPIRY_TIMEOUT,
+					       client->priv);
 
 		/* Next client */
 		client = (irlmp_client_t *) hashbin_get_next(irlmp->clients);
@@ -1002,7 +1003,7 @@
  */
 discovery_t *irlmp_get_discovery_response()
 {
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(irlmp != NULL, return NULL;);
 
@@ -1065,7 +1066,7 @@
  */
 int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *skb) 
 {
- 	IRDA_DEBUG(4, __FUNCTION__ "()\n"); 
+ 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__); 
 
 	ASSERT(skb != NULL, return -1;);
 	
@@ -1084,7 +1085,7 @@
  */
 void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb) 
 {
- 	IRDA_DEBUG(4, __FUNCTION__ "()\n"); 
+ 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__); 
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
@@ -1112,7 +1113,7 @@
 	struct sk_buff *clone_skb;
 	struct lap_cb *lap;
 
- 	IRDA_DEBUG(4, __FUNCTION__ "()\n"); 
+ 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__); 
 
 	ASSERT(skb != NULL, return -1;);
 	
@@ -1155,7 +1156,7 @@
 #ifdef CONFIG_IRDA_ULTRA
 void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb) 
 {
- 	IRDA_DEBUG(4, __FUNCTION__ "()\n"); 
+ 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__); 
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
@@ -1174,7 +1175,7 @@
 
 void irlmp_status_request(void) 
 {
-	IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
+	IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
 }
 
 /*
@@ -1204,7 +1205,7 @@
 			curr->notify.status_indication(curr->notify.instance, 
 						       link, lock);
 		else
-			IRDA_DEBUG(2, __FUNCTION__ "(), no handler\n");
+			IRDA_DEBUG(2, "%s(), no handler\n", __FUNCTION__);
 	}
 }
 
@@ -1225,7 +1226,7 @@
 	 */
 	service = kmalloc(16, GFP_ATOMIC);
 	if (!service) {
-		IRDA_DEBUG(1, __FUNCTION__ "(), Unable to kmalloc!\n");
+		IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __FUNCTION__);
 		return NULL;
 	}
 
@@ -1331,7 +1332,7 @@
 		hint.word = 0xffff;
 		break;
 	default:
-		IRDA_DEBUG( 1, __FUNCTION__ "(), Unknown service!\n");
+		IRDA_DEBUG( 1, "%s(), Unknown service!\n", __FUNCTION__);
 		break;
 	}
 	return hint.word;
@@ -1348,7 +1349,7 @@
 	irlmp_service_t *service;
 	__u32 handle;
 
-	IRDA_DEBUG(4, __FUNCTION__ "(), hints = %04x\n", hints);
+	IRDA_DEBUG(4, "%s(), hints = %04x\n", __FUNCTION__, hints);
 
 	/* Get a unique handle for this service */
 	get_random_bytes(&handle, sizeof(handle));
@@ -1360,7 +1361,7 @@
 	/* Make a new registration */
  	service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC);
 	if (!service) {
-		IRDA_DEBUG(1, __FUNCTION__ "(), Unable to kmalloc!\n");
+		IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __FUNCTION__);
 		return 0;
 	}
 	service->hints = hints;
@@ -1380,14 +1381,14 @@
 {
 	irlmp_service_t *service;
 		
- 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+ 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	if (!handle)
 		return -1;
  
 	service = hashbin_find(irlmp->services, handle, NULL);
 	if (!service) {
-		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown service!\n");
+		IRDA_DEBUG(1, "%s(), Unknown service!\n", __FUNCTION__);
 		return -1;
 	}
 
@@ -1423,7 +1424,7 @@
 	irlmp_client_t *client;
 	__u32 handle;
 
-	IRDA_DEBUG(1, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 	ASSERT(irlmp != NULL, return 0;);
 	
 	/* Get a unique handle for this client */
@@ -1434,7 +1435,7 @@
 	/* Make a new registration */
  	client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC);
 	if (!client) {
-		IRDA_DEBUG( 1, __FUNCTION__ "(), Unable to kmalloc!\n");
+		IRDA_DEBUG( 1, "%s(), Unable to kmalloc!\n", __FUNCTION__);
 		return 0;
 	}
 
@@ -1468,7 +1469,7 @@
 
 	client = hashbin_find(irlmp->clients, handle, NULL);
 	if (!client) {
-		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown client!\n");
+		IRDA_DEBUG(1, "%s(), Unknown client!\n", __FUNCTION__);
 		return -1;
 	}
 
@@ -1490,18 +1491,18 @@
 {
  	struct irlmp_client *client;
  
- 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+ 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	if (!handle)
 		return -1;
  
 	client = hashbin_find(irlmp->clients, handle, NULL);
 	if (!client) {
-		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown client!\n");
+		IRDA_DEBUG(1, "%s(), Unknown client!\n", __FUNCTION__);
 		return -1;
 	}
 
-	IRDA_DEBUG( 4, __FUNCTION__ "(), removing client!\n");
+	IRDA_DEBUG( 4, "%s(), removing client!\n", __FUNCTION__);
 	client = hashbin_remove( irlmp->clients, handle, NULL);
 	if (client)
 		kfree(client);
@@ -1523,7 +1524,7 @@
 	ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;);
 	ASSERT(slsap_sel != LSAP_ANY, return TRUE;);
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 #ifdef CONFIG_IRDA_ULTRA
 	/* Accept all bindings to the connectionless LSAP */
@@ -1589,7 +1590,7 @@
 				return 0;
 		}
 	}
-	IRDA_DEBUG(4, __FUNCTION__ "(), next free lsap_sel=%02x\n", lsap_sel);
+	IRDA_DEBUG(4, "%s(), next free lsap_sel=%02x\n", __FUNCTION__, lsap_sel);
 	
 	return lsap_sel;
 }
@@ -1607,26 +1608,26 @@
 
 	switch (lap_reason) {		
 	case LAP_DISC_INDICATION: /* Received a disconnect request from peer */
-		IRDA_DEBUG( 1, __FUNCTION__ "(), LAP_DISC_INDICATION\n");
+		IRDA_DEBUG( 1, "%s(), LAP_DISC_INDICATION\n", __FUNCTION__);
 		reason = LM_USER_REQUEST;
 		break;
 	case LAP_NO_RESPONSE:    /* To many retransmits without response */
-		IRDA_DEBUG( 1, __FUNCTION__ "(), LAP_NO_RESPONSE\n");
+		IRDA_DEBUG( 1, "%s(), LAP_NO_RESPONSE\n", __FUNCTION__);
 		reason = LM_LAP_DISCONNECT;
 		break;
 	case LAP_RESET_INDICATION:
-		IRDA_DEBUG( 1, __FUNCTION__ "(), LAP_RESET_INDICATION\n");
+		IRDA_DEBUG( 1, "%s(), LAP_RESET_INDICATION\n", __FUNCTION__);
 		reason = LM_LAP_RESET;
 		break;
 	case LAP_FOUND_NONE:
 	case LAP_MEDIA_BUSY:
 	case LAP_PRIMARY_CONFLICT:
-		IRDA_DEBUG(1, __FUNCTION__ "(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n");
+		IRDA_DEBUG(1, "%s(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n", __FUNCTION__);
 		reason = LM_CONNECT_FAILURE;
 		break;
 	default:
-		IRDA_DEBUG(1, __FUNCTION__ 
-		      "(), Unknow IrLAP disconnect reason %d!\n", lap_reason);
+		IRDA_DEBUG(1, "%s(), Unknow IrLAP disconnect reason %d!\n", 
+			__FUNCTION__, lap_reason);
 		reason = LM_LAP_DISCONNECT;
 		break;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/irlmp_event.c linux-2.4.20/net/irda/irlmp_event.c
--- linux-2.4.19/net/irda/irlmp_event.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.20/net/irda/irlmp_event.c	2002-10-29 11:18:34.000000000 +0000
@@ -121,7 +121,7 @@
 					IRLMP_STATE state) 
 {
 	/*
-	IRDA_DEBUG(4, __FUNCTION__ "(), LMP LAP = %s\n", irlmp_state[state]);
+	IRDA_DEBUG(4, "%s(), LMP LAP = %s\n", __FUNCTION__, irlmp_state[state]);
 	*/
 	self->lap_state = state;
 }
@@ -131,7 +131,7 @@
 {
 	/*
 	ASSERT(self != NULL, return;);
-	IRDA_DEBUG(4, __FUNCTION__ "(), LMP LSAP = %s\n", irlsap_state[state]);
+	IRDA_DEBUG(4, "%s(), LMP LSAP = %s\n", __FUNCTION__, irlsap_state[state]);
 	*/
 	self->lsap_state = state;
 }
@@ -143,8 +143,8 @@
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 
-	IRDA_DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
-		   irlmp_event[event], irlsap_state[ self->lsap_state]);
+	IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n",
+		__FUNCTION__, irlmp_event[event], irlsap_state[ self->lsap_state]);
 
 	return (*lsap_state[self->lsap_state]) (self, event, skb);
 }
@@ -161,16 +161,16 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
 	
-	IRDA_DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
-		   irlmp_event[event], 
-		   irlmp_state[self->lap_state]);
+	IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n",
+		__FUNCTION__, irlmp_event[event], 
+		irlmp_state[self->lap_state]);
 
 	(*lap_state[self->lap_state]) (self, event, skb);
 }
 
 void irlmp_discovery_timer_expired(void *data)
 {
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 	
 	/* We always cleanup the log (active & passive discovery) */ 
 	irlmp_do_expiry();
@@ -187,7 +187,7 @@
 {
 	struct lsap_cb *self = (struct lsap_cb *) data;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
@@ -199,7 +199,7 @@
 {
 	struct lap_cb *self = (struct lap_cb *) data;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
@@ -222,7 +222,7 @@
 static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event, 
 				struct sk_buff *skb)
 {	
-	IRDA_DEBUG(4, __FUNCTION__ "()\n"); 
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__); 
 	ASSERT(self->irlap != NULL, return;);
 	
 	switch (event) {
@@ -242,7 +242,7 @@
 		irlap_connect_response(self->irlap, skb);
 		break;
 	case LM_LAP_CONNECT_REQUEST:
-		IRDA_DEBUG(4, __FUNCTION__ "() LS_CONNECT_REQUEST\n");
+		IRDA_DEBUG(4, "%s() LS_CONNECT_REQUEST\n", __FUNCTION__);
 
 		irlmp_next_lap_state(self, LAP_U_CONNECT);
 
@@ -250,14 +250,12 @@
 		irlap_connect_request(self->irlap, self->daddr, NULL, 0);
 		break;
 	case LM_LAP_DISCONNECT_INDICATION:
-		IRDA_DEBUG(4, __FUNCTION__ 
-			   "(), Error LM_LAP_DISCONNECT_INDICATION\n");
+		IRDA_DEBUG(4, "%s(), Error LM_LAP_DISCONNECT_INDICATION\n", __FUNCTION__);
 		
 		irlmp_next_lap_state(self, LAP_STANDBY);
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
-			   irlmp_event[event]);
+		IRDA_DEBUG(0, "%s(), Unknown event %s\n", __FUNCTION__, irlmp_event[event]);
 		if (skb)
  			dev_kfree_skb(skb);
 		break;
@@ -277,7 +275,7 @@
 	struct lsap_cb *lsap;
 	struct lsap_cb *lsap_current;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), event=%s\n", irlmp_event[event]);
+	IRDA_DEBUG(2, "%s(), event=%s\n",  __FUNCTION__, irlmp_event[event]);
 
 	switch (event) {
 	case LM_LAP_CONNECT_INDICATION:
@@ -299,7 +297,7 @@
 		 * the lsaps may already have gone. This avoid getting stuck
 		 * forever in LAP_ACTIVE state - Jean II */
 		if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
-			IRDA_DEBUG(0, __FUNCTION__ "() NO LSAPs !\n");
+			IRDA_DEBUG(0, "%s() NO LSAPs !\n",  __FUNCTION__);
 			irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
 		}
 		break;
@@ -319,12 +317,12 @@
 		 * the lsaps may already have gone. This avoid getting stuck
 		 * forever in LAP_ACTIVE state - Jean II */
 		if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
-			IRDA_DEBUG(0, __FUNCTION__ "() NO LSAPs !\n");
+			IRDA_DEBUG(0, "%s() NO LSAPs !\n",  __FUNCTION__);
 			irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
 		}
 		break;
 	case LM_LAP_DISCONNECT_INDICATION:
-		IRDA_DEBUG(4, __FUNCTION__ "(), LM_LAP_DISCONNECT_INDICATION\n");
+		IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_INDICATION\n",  __FUNCTION__);
 		irlmp_next_lap_state(self, LAP_STANDBY);
 
 		/* Send disconnect event to all LSAPs using this link */
@@ -342,7 +340,7 @@
 		}
 		break;
 	case LM_LAP_DISCONNECT_REQUEST:
-		IRDA_DEBUG(4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n");
+		IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_REQUEST\n",  __FUNCTION__);
 
 		/* One of the LSAP did timeout or was closed, if it was
 		 * the last one, try to get out of here - Jean II */
@@ -351,8 +349,8 @@
 		}
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
-			   irlmp_event[event]);
+		IRDA_DEBUG(0, "%s(), Unknown event %s\n",
+			 __FUNCTION__, irlmp_event[event]);
 		if (skb)
  			dev_kfree_skb(skb);
 		break;
@@ -371,11 +369,11 @@
 	struct lsap_cb *lsap;
 	struct lsap_cb *lsap_current;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n"); 
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__); 
 
  	switch (event) {
 	case LM_LAP_CONNECT_REQUEST:
-		IRDA_DEBUG(4, __FUNCTION__ "(), LS_CONNECT_REQUEST\n");
+		IRDA_DEBUG(4, "%s(), LS_CONNECT_REQUEST\n",  __FUNCTION__);
 
 		/*
 		 *  LAP connection allready active, just bounce back! Since we 
@@ -459,10 +457,19 @@
 					    LM_LAP_DISCONNECT_INDICATION,
 					    NULL);
 		}
+
+		/* Force an expiry of the discovery log.
+		 * Now that the LAP is free, the system may attempt to
+		 * connect to another device. Unfortunately, our entries
+		 * are stale. There is a small window (<3s) before the
+		 * normal discovery will run and where irlmp_connect_request()
+		 * can get the wrong info, so make sure things get
+		 * cleaned *NOW* ;-) - Jean II */
+		irlmp_do_expiry();
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
-			   irlmp_event[event]);
+		IRDA_DEBUG(0, "%s(), Unknown event %s\n",
+			 __FUNCTION__, irlmp_event[event]);
 		if (skb)
  			dev_kfree_skb(skb);
 		break;
@@ -486,7 +493,7 @@
 {
 	int ret = 0;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
@@ -498,11 +505,10 @@
 		break;
 #endif /* CONFIG_IRDA_ULTRA */
 	case LM_CONNECT_REQUEST:
-		IRDA_DEBUG(4, __FUNCTION__ "(), LM_CONNECT_REQUEST\n");
+		IRDA_DEBUG(4, "%s(), LM_CONNECT_REQUEST\n",  __FUNCTION__);
 
 		if (self->conn_skb) {
-			WARNING(__FUNCTION__ 
-				"(), busy with another request!\n");
+			WARNING("%s(), busy with another request!\n",  __FUNCTION__);
 			return -EBUSY;
 		}
 		self->conn_skb = skb;
@@ -516,8 +522,7 @@
 		break;
 	case LM_CONNECT_INDICATION:
 		if (self->conn_skb) {
-			WARNING(__FUNCTION__ 
-				"(), busy with another request!\n");
+			WARNING("%s(), busy with another request!\n",  __FUNCTION__);
 			return -EBUSY;
 		}
 		self->conn_skb = skb;
@@ -540,8 +545,8 @@
 		irlmp_start_watchdog_timer(self, 1*HZ);
 		break;
 	default:
-		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n", 
-			   irlmp_event[event]);
+		IRDA_DEBUG(2, "%s(), Unknown event %s\n", 
+			 __FUNCTION__, irlmp_event[event]);
 		if (skb)
   			dev_kfree_skb(skb);
 		break;
@@ -561,7 +566,7 @@
 	struct lsap_cb *lsap;
 	int ret = 0;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 	
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
@@ -592,15 +597,15 @@
 	case LM_WATCHDOG_TIMEOUT:
 		/* May happen, who knows...
 		 * Jean II */
-		IRDA_DEBUG(0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n");
+		IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n",  __FUNCTION__);
 
 		/* Disconnect, get out... - Jean II */
 		self->dlsap_sel = LSAP_ANY;
 		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
-			   irlmp_event[event]);
+		IRDA_DEBUG(0, "%s(), Unknown event %s\n",
+			 __FUNCTION__, irlmp_event[event]);
 		if (skb)
  			dev_kfree_skb(skb);
 		break;
@@ -619,7 +624,7 @@
 {
 	int ret = 0;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
@@ -629,17 +634,17 @@
 		/* Keep state */
 		break;
 	case LM_CONNECT_RESPONSE:
-		IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, "
-			   "no indication issued yet\n");
+		IRDA_DEBUG(0, "%s(), LM_CONNECT_RESPONSE, "
+			   "no indication issued yet\n",  __FUNCTION__);
 		/* Keep state */
 		break;
 	case LM_DISCONNECT_REQUEST:
-		IRDA_DEBUG(0, __FUNCTION__ "(), LM_DISCONNECT_REQUEST, "
-			   "not yet bound to IrLAP connection\n");
+		IRDA_DEBUG(0, "%s(), LM_DISCONNECT_REQUEST, "
+			   "not yet bound to IrLAP connection\n",  __FUNCTION__);
 		/* Keep state */
 		break;
 	case LM_LAP_CONNECT_CONFIRM:
-		IRDA_DEBUG(4, __FUNCTION__ "(), LS_CONNECT_CONFIRM\n");
+		IRDA_DEBUG(4, "%s(), LS_CONNECT_CONFIRM\n",  __FUNCTION__);
 		irlmp_next_lsap_state(self, LSAP_CONNECT);
 
 		skb = self->conn_skb;
@@ -651,7 +656,7 @@
 		/* Will happen in some rare cases because of a race condition.
 		 * Just make sure we don't stay there forever...
 		 * Jean II */
-		IRDA_DEBUG(0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n");
+		IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n",  __FUNCTION__);
 
 		/* Go back to disconnected mode, keep the socket waiting */
 		self->dlsap_sel = LSAP_ANY;
@@ -661,8 +666,8 @@
 		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "Unknown event %s\n", 
-			   irlmp_event[event]);
+		IRDA_DEBUG(0, "%s() Unknown event %s\n", 
+			 __FUNCTION__, irlmp_event[event]);
 		if (skb)
  			dev_kfree_skb(skb);
 		break;	
@@ -682,7 +687,7 @@
 	LM_REASON reason;
 	int ret = 0;
 
- 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+ 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
@@ -705,13 +710,13 @@
 		irlmp_udata_indication(self, skb); 
 		break;
 	case LM_CONNECT_REQUEST:
-		IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_REQUEST, "
-			   "error, LSAP already connected\n");
+		IRDA_DEBUG(0, "%s(), LM_CONNECT_REQUEST, "
+			   "error, LSAP already connected\n",  __FUNCTION__);
 		/* Keep state */
 		break;
 	case LM_CONNECT_RESPONSE:
-		IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, " 
-			   "error, LSAP allready connected\n");
+		IRDA_DEBUG(0, "%s(), LM_CONNECT_RESPONSE, " 
+			   "error, LSAP allready connected\n",  __FUNCTION__);
 		/* Keep state */
 		break;
 	case LM_DISCONNECT_REQUEST:
@@ -721,7 +726,7 @@
 		
 		/* Try to close the LAP connection if its still there */
 		if (self->lap) {
-			IRDA_DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n");
+			IRDA_DEBUG(4, "%s(), trying to close IrLAP\n",  __FUNCTION__);
 			irlmp_do_lap_event(self->lap, 
 					   LM_LAP_DISCONNECT_REQUEST, 
 					   NULL);
@@ -745,14 +750,14 @@
 		reason = skb->data[3];
 
 		 /* Try to close the LAP connection */
-		IRDA_DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n");
+		IRDA_DEBUG(4, "%ss(), trying to close IrLAP\n",  __FUNCTION__);
 		irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
 
 		irlmp_disconnect_indication(self, reason, skb);
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", 
-			   irlmp_event[event]);
+		IRDA_DEBUG(0, "%s(), Unknown event %s\n", 
+			 __FUNCTION__, irlmp_event[event]);
 		if (skb)
  			dev_kfree_skb(skb);
 		break;	
@@ -776,7 +781,7 @@
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	switch (event) {
 	case LM_CONNECT_CONFIRM:
@@ -797,7 +802,7 @@
 		reason = skb->data[3];
 
 		 /* Try to close the LAP connection */
-		IRDA_DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n");
+		IRDA_DEBUG(4, "%s(), trying to close IrLAP\n",  __FUNCTION__);
 		irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
 
 		irlmp_disconnect_indication(self, reason, skb);
@@ -815,7 +820,7 @@
 		irlmp_disconnect_indication(self, reason, skb);
 		break;
 	case LM_WATCHDOG_TIMEOUT:
-		IRDA_DEBUG(0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n");
+		IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n",  __FUNCTION__);
 		
 		ASSERT(self->lap != NULL, return -1;);
 		irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
@@ -824,8 +829,8 @@
 		irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL);
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", 
-			   irlmp_event[event]);
+		IRDA_DEBUG(0, "%s(), Unknown event %s\n", 
+			 __FUNCTION__, irlmp_event[event]);
 		if (skb)
  			dev_kfree_skb(skb);
 		break;	
@@ -847,7 +852,7 @@
 	LM_REASON reason;
 	int ret = 0;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n"); 
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__); 
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(irlmp != NULL, return -1;);
@@ -865,7 +870,7 @@
 		irlmp_next_lsap_state(self, LSAP_SETUP);
 		break;
 	case LM_WATCHDOG_TIMEOUT:
-		IRDA_DEBUG(0, __FUNCTION__ "() : WATCHDOG_TIMEOUT !\n");
+		IRDA_DEBUG(0, "%s() : WATCHDOG_TIMEOUT !\n",  __FUNCTION__);
 
 		ASSERT(self->lap != NULL, return -1;);
 		irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
@@ -883,8 +888,8 @@
 		irlmp_disconnect_indication(self, reason, NULL);
 		break;
 	default:
-		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", 
-			   irlmp_event[event]);
+		IRDA_DEBUG(0, "%s(), Unknown event %s\n", 
+			 __FUNCTION__, irlmp_event[event]);
 		if (skb)
  			dev_kfree_skb(skb);
 		break;	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/irlmp_frame.c linux-2.4.20/net/irda/irlmp_frame.c
--- linux-2.4.19/net/irda/irlmp_frame.c	2001-11-09 22:22:17.000000000 +0000
+++ linux-2.4.20/net/irda/irlmp_frame.c	2002-10-29 11:18:49.000000000 +0000
@@ -378,7 +378,7 @@
 	
 	/* Just handle it the same way as a discovery confirm,
 	 * bypass the LM_LAP state machine (see below) */
-	irlmp_discovery_confirm(irlmp->cachelog);
+	irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_PASSIVE);
 }
 
 /*
@@ -404,7 +404,7 @@
 	 *	2) It doesn't affect the LM_LAP state
 	 *	3) Faster, slimer, simpler, ...
 	 * Jean II */
-	irlmp_discovery_confirm(irlmp->cachelog);
+	irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_ACTIVE);
 }
 
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/irnet/irnet.h linux-2.4.20/net/irda/irnet/irnet.h
--- linux-2.4.19/net/irda/irnet/irnet.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/irda/irnet/irnet.h	2002-10-29 11:18:49.000000000 +0000
@@ -211,6 +211,12 @@
  *	o When receiving a disconnect indication, don't reenable the
  *	  PPP Tx queue, this will trigger a reconnect. Instead, close
  *	  the channel, which will kill pppd...
+ *
+ * v11 - 20.3.02 - Jean II
+ *	o Oops ! v10 fix disabled IrNET retries and passive behaviour.
+ *	  Better fix in irnet_disconnect_indication() :
+ *	  - if connected, kill pppd via hangup.
+ *	  - if not connected, reenable ppp Tx, which trigger IrNET retry.
  */
 
 /***************************** INCLUDES *****************************/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/irnet/irnet_irda.c linux-2.4.20/net/irda/irnet/irnet_irda.c
--- linux-2.4.19/net/irda/irnet/irnet_irda.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/irda/irnet/irnet_irda.c	2002-10-29 11:18:32.000000000 +0000
@@ -1070,7 +1070,7 @@
  *	o attempted to connect, timeout
  *	o connected, link is broken, LAP has timeout
  *	o connected, other side close the link
- *	o connection request on the server no handled
+ *	o connection request on the server not handled
  */
 static void
 irnet_disconnect_indication(void *	instance,
@@ -1121,20 +1121,31 @@
       DEBUG(IRDA_CB_INFO, "Closing our TTP connection.\n");
       irttp_close_tsap(self->tsap);
       self->tsap = NULL;
-
-      /* Cleanup & close the PPP channel, which will kill pppd and the rest */
-      if(self->ppp_open)
-	ppp_unregister_channel(&self->chan);
-      self->ppp_open = 0;
     }
-  /* Cleanup the socket in case we want to reconnect */
+  /* Cleanup the socket in case we want to reconnect in ppp_output_wakeup() */
   self->stsap_sel = 0;
   self->daddr = DEV_ADDR_ANY;
   self->tx_flow = FLOW_START;
 
-  /* Note : what should we say to ppp ?
-   * It seem the ppp_generic and pppd are happy that way and will eventually
-   * timeout gracefully, so don't bother them... */
+  /* Deal with the ppp instance if it's still alive */
+  if(self->ppp_open)
+    {
+      if(test_open)
+	{
+	  /* If we were connected, cleanup & close the PPP channel,
+	   * which will kill pppd (hangup) and the rest */
+	  ppp_unregister_channel(&self->chan);
+	  self->ppp_open = 0;
+	}
+      else
+	{
+	  /* If we were trying to connect, flush (drain) ppp_generic
+	   * Tx queue (most often we have blocked it), which will
+	   * trigger an other attempt to connect. If we are passive,
+	   * this will empty the Tx queue after last try. */
+	  ppp_output_wakeup(&self->chan);
+	}
+    }
 
   DEXIT(IRDA_TCB_TRACE, "\n");
 }
@@ -1588,8 +1599,9 @@
  * is to messy, so we leave that to user space...
  */
 static void
-irnet_discovery_indication(discovery_t *discovery,
-			   void *	priv)
+irnet_discovery_indication(discovery_t *	discovery,
+			   DISCOVERY_MODE	mode,
+			   void *		priv)
 {
   irnet_socket *	self = &irnet_server.s;
 	
@@ -1627,6 +1639,7 @@
  */
 static void
 irnet_expiry_indication(discovery_t *	expiry,
+			DISCOVERY_MODE	mode,
 			void *		priv)
 {
   irnet_socket *	self = &irnet_server.s;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/irnet/irnet_irda.h linux-2.4.20/net/irda/irnet/irnet_irda.h
--- linux-2.4.19/net/irda/irnet/irnet_irda.h	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.20/net/irda/irnet/irnet_irda.h	2002-10-29 11:18:33.000000000 +0000
@@ -151,9 +151,11 @@
 #ifdef DISCOVERY_EVENTS
 static void
 	irnet_discovery_indication(discovery_t *,
+				   DISCOVERY_MODE,
 				   void *);
 static void
 	irnet_expiry_indication(discovery_t *,
+				DISCOVERY_MODE,
 				void *);
 #endif
 /* -------------------------- PROC ENTRY -------------------------- */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/irsyms.c linux-2.4.20/net/irda/irsyms.c
--- linux-2.4.19/net/irda/irsyms.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.20/net/irda/irsyms.c	2002-10-29 11:18:50.000000000 +0000
@@ -171,7 +171,7 @@
 
 int __init irda_init(void)
 {
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 
  	irlmp_init();
 	irlap_init();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/irsysctl.c linux-2.4.20/net/irda/irsysctl.c
--- linux-2.4.19/net/irda/irsysctl.c	2001-12-21 17:42:06.000000000 +0000
+++ linux-2.4.20/net/irda/irsysctl.c	2002-10-29 11:18:38.000000000 +0000
@@ -35,17 +35,19 @@
 #define NET_IRDA 412 /* Random number */
 enum { DISCOVERY=1, DEVNAME, DEBUG, FAST_POLL, DISCOVERY_SLOTS,
        DISCOVERY_TIMEOUT, SLOT_TIMEOUT, MAX_BAUD_RATE, MIN_TX_TURN_TIME,
-       MAX_NOREPLY_TIME, WARN_NOREPLY_TIME, LAP_KEEPALIVE_TIME };
+       MAX_TX_DATA_SIZE, MAX_NOREPLY_TIME, WARN_NOREPLY_TIME,
+       LAP_KEEPALIVE_TIME };
 
 extern int  sysctl_discovery;
 extern int  sysctl_discovery_slots;
 extern int  sysctl_discovery_timeout;
-extern int  sysctl_slot_timeout;	/* Candidate */
+extern int  sysctl_slot_timeout;
 extern int  sysctl_fast_poll_increase;
 int         sysctl_compression = 0;
 extern char sysctl_devname[];
 extern int  sysctl_max_baud_rate;
 extern int  sysctl_min_tx_turn_time;
+extern int  sysctl_max_tx_data_size;
 extern int  sysctl_max_noreply_time;
 extern int  sysctl_warn_noreply_time;
 extern int  sysctl_lap_keepalive_time;
@@ -65,6 +67,8 @@
 static int min_max_baud_rate = 2400;
 static int max_min_tx_turn_time = 10000;	/* See qos.c - IrLAP spec */
 static int min_min_tx_turn_time = 0;
+static int max_max_tx_data_size = 2048;		/* See qos.c - IrLAP spec */
+static int min_max_tx_data_size = 64;
 static int max_max_noreply_time = 40;		/* See qos.c - IrLAP spec */
 static int min_max_noreply_time = 3;
 static int max_warn_noreply_time = 3;		/* 3s == standard */
@@ -118,6 +122,9 @@
 	{ MIN_TX_TURN_TIME, "min_tx_turn_time", &sysctl_min_tx_turn_time,
 	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
 	  NULL, &min_min_tx_turn_time, &max_min_tx_turn_time },
+	{ MAX_TX_DATA_SIZE, "max_tx_data_size", &sysctl_max_tx_data_size,
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_max_tx_data_size, &max_max_tx_data_size },
 	{ MAX_NOREPLY_TIME, "max_noreply_time", &sysctl_max_noreply_time,
 	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
 	  NULL, &min_max_noreply_time, &max_max_noreply_time },
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/irda/qos.c linux-2.4.20/net/irda/qos.c
--- linux-2.4.19/net/irda/qos.c	2001-12-21 17:42:06.000000000 +0000
+++ linux-2.4.20/net/irda/qos.c	2002-10-29 11:18:36.000000000 +0000
@@ -57,10 +57,26 @@
  * Nonzero values (usec) are used as lower limit to the per-connection
  * mtt value which was announced by the other end during negotiation.
  * Might be helpful if the peer device provides too short mtt.
- * Default is 10 which means using the unmodified value given by the peer
- * except if it's 0 (0 is likely a bug in the other stack).
+ * Default is 10us which means using the unmodified value given by the
+ * peer except if it's 0 (0 is likely a bug in the other stack).
  */
 unsigned sysctl_min_tx_turn_time = 10;
+/*
+ * Maximum data size to be used in transmission in payload of LAP frame.
+ * There is a bit of confusion in the IrDA spec :
+ * The LAP spec defines the payload of a LAP frame (I field) to be
+ * 2048 bytes max (IrLAP 1.1, chapt 6.6.5, p40).
+ * On the other hand, the PHY mention frames of 2048 bytes max (IrPHY
+ * 1.2, chapt 5.3.2.1, p41). But, this number includes the LAP header
+ * (2 bytes), and CRC (32 bits at 4 Mb/s). So, for the I field (LAP
+ * payload), that's only 2042 bytes. Oups !
+ * I've had trouble trouble transmitting 2048 bytes frames with USB
+ * dongles and nsc-ircc at 4 Mb/s, so adjust to 2042... I don't know
+ * if this bug applies only for 2048 bytes frames or all negociated
+ * frame sizes, but all hardware seem to support "2048 bytes" frames.
+ * You can use the sysctl to play with this value anyway.
+ * Jean II */
+unsigned sysctl_max_tx_data_size = 2042;
 
 static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get);
 static int irlap_param_link_disconnect(void *instance, irda_param_t *parm, 
@@ -355,10 +371,10 @@
 	while ((qos->data_size.value > line_capacity) && (index > 0)) {
 		qos->data_size.value = data_sizes[index--];
 		IRDA_DEBUG(2, __FUNCTION__ 
-			   "(), redusing data size to %d\n",
+			   "(), reducing data size to %d\n",
 			   qos->data_size.value);
 	}
-#else /* Use method descibed in section 6.6.11 of IrLAP */
+#else /* Use method described in section 6.6.11 of IrLAP */
 	while (irlap_requested_line_capacity(qos) > line_capacity) {
 		ASSERT(index != 0, return;);
 
@@ -366,18 +382,24 @@
 		if (qos->window_size.value > 1) {
 			qos->window_size.value--;
 			IRDA_DEBUG(2, __FUNCTION__ 
-				   "(), redusing window size to %d\n",
+				   "(), reducing window size to %d\n",
 				   qos->window_size.value);
 		} else if (index > 1) {
 			qos->data_size.value = data_sizes[index--];
 			IRDA_DEBUG(2, __FUNCTION__ 
-				   "(), redusing data size to %d\n",
+				   "(), reducing data size to %d\n",
 				   qos->data_size.value);
 		} else {
 			WARNING(__FUNCTION__ "(), nothing more we can do!\n");
 		}
 	}
 #endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
+	/*
+	 * Fix tx data size according to user limits - Jean II
+	 */
+	if (qos->data_size.value > sysctl_max_tx_data_size)
+		/* Allow non discrete adjustement to avoid loosing capacity */
+		qos->data_size.value = sysctl_max_tx_data_size;
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/khttpd/README linux-2.4.20/net/khttpd/README
--- linux-2.4.19/net/khttpd/README	2000-11-16 22:07:53.000000000 +0000
+++ linux-2.4.20/net/khttpd/README	2002-10-29 11:18:49.000000000 +0000
@@ -14,14 +14,15 @@
    other webservers in that it runs from within the Linux-kernel as a module 
    (device-driver).
 
-   kHTTPd handles only static (file based) web-pages, and passes all requests
-   for non-static information to a regular userspace-webserver such as Apache or 
-   Zeus. The userspace-daemon doesn't have to be altered in any way.
+   kHTTPd handles only static (file based) web-pages, and passes all requests 
+   for non-static information to a regular userspace-webserver such as Apache 
+   or Zeus. The userspace-daemon doesn't have to be altered in any way.
 
    Static web-pages are not a very complex thing to serve, but these are very
    important nevertheless, since virtually all images are static, and a large
    portion of the html-pages are static also. A "regular" webserver has little
-   added value for static pages, it is simply a "copy file to network"-operation.
+   added value for static pages, it is simply a "copy file to network"
+   operation.
    This can be done very efficiently from within the Linux-kernel, for example 
    the nfs (network file system) daemon performs a similar task and also runs 
    in the kernel.
@@ -44,6 +45,7 @@
  
    echo 1 > /proc/sys/net/khttpd/stop
    echo 1 > /proc/sys/net/khttpd/unload 
+   sleep 2
    rmmod khttpd
    
 
@@ -71,7 +73,7 @@
 
    Before you can start using kHTTPd, you have to configure it. This
    is done through the /proc filesystem, and can thus be done from inside
-   a script. Most parameters can only be set when kHTTPd is not active.
+   a script. Most parameters can only be set when kHTTPd is stopped.
 
    The following things need configuration:
 
@@ -117,26 +119,31 @@
 
    Port 8080
 
+   Starting kHTTPd
+   ===============
+   Once you have set up the configuration, start kHTTPD by running
+   echo 1 > /proc/sys/net/khttpd/start
+   It may take a jiffie or two to start.
 
-   
    Stopping kHTTPd
    ===============
-   In order to change the configuration, you should stop kHTTPd by typing
+   To stop kHTTPd, do
    echo 1 > /proc/sys/net/khttpd/stop
-   on a command-prompt.
+   It should stop in a jiffy or two.
 
-   If you want to unload the module, you should type
+   Unloading kHTTPd
+   ===============
+   To unload the module, do
+   echo 1 > /proc/sys/net/khttpd/stop
    echo 1 > /proc/sys/net/khttpd/unload
-   after stopping kHTTPd first.
+   #killall -HUP khttpd
+   sleep 2
+   rmmod khttpd
 
-   If this doesn't work fast enough for you (the commands above can wait for 
+   If this doesn't work fast enough for you (unloading can wait for 
    a remote connection to close down), you can send the daemons a "HUP"
    signal after you told them to stop. This will cause the daemon-threads to
    stop immediately. 
-
-   Note that the daemons will restart immediately if they are not told to
-   stop.
-
    
 
 4. Permissions
@@ -212,7 +219,21 @@
 	maxconnect	1000		Maximum number of concurrent
 					connections
 
-6. More information
+6. Known Issues
+   kHTTPd is *not* currently compatible with tmpfs.  Trying to serve
+   files stored on a tmpfs partition is known to cause kernel oopses
+   as of 2.4.18.  This is due to the same problem that prevents sendfile()
+   from being usable with tmpfs.  A tmpfs patch is floating around that seems
+   to fix this, but has not been released as of 27 May 2002.
+   kHTTPD does work fine with ramfs, though.
+
+   There is debate about whether to remove kHTTPd from the main
+   kernel sources.  This will probably happen in the 2.5 kernel series,
+   after which khttpd will still be available as a patch.
+
+   The kHTTPd source code could use a good spring cleaning.
+
+7. More information
 -------------------
    More information about the architecture of kHTTPd, the mailinglist and
    configuration-examples can be found at the kHTTPd homepage:
@@ -221,4 +242,6 @@
 
    Bugreports, patches, etc can be send to the mailinglist
    (khttpd-users@zgp.org) or to khttpd@fenrus.demon.nl
+   Mailing list archives are at 
+      http://lists.alt.org/mailman/listinfo/khttpd-users
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/khttpd/main.c linux-2.4.20/net/khttpd/main.c
--- linux-2.4.19/net/khttpd/main.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/khttpd/main.c	2002-10-29 11:18:32.000000000 +0000
@@ -95,11 +95,17 @@
 {
 	int CPUNR;
 	sigset_t tmpsig;
+	int old_stop_count;
 	
 	DECLARE_WAITQUEUE(main_wait,current);
 	
 	MOD_INC_USE_COUNT;
 
+	/* Remember value of stop count.  If it changes, user must have 
+	 * asked us to stop.  Sensing this is much less racy than 
+	 * directly sensing sysctl_khttpd_stop. - dank
+	 */
+	old_stop_count = atomic_read(&khttpd_stopCount);
 	
 	CPUNR=0;
 	if (cpu_pointer!=NULL)
@@ -125,11 +131,9 @@
 	atomic_inc(&DaemonCount);
 	atomic_set(&Running[CPUNR],1);
 	
-	while (sysctl_khttpd_stop==0)
+	while (old_stop_count == atomic_read(&khttpd_stopCount)) 
 	{
 		int changes = 0;
-				
-
 		
 		changes +=AcceptConnections(CPUNR,MainSocket);
 		if (ConnectionsPending(CPUNR))
@@ -194,11 +198,9 @@
 	
 	DECLARE_WAIT_QUEUE_HEAD(WQ);
 	
-	
 	sprintf(current->comm,"khttpd manager");
 	daemonize();
 	
-
 	/* Block all signals except SIGKILL and SIGSTOP */
 	spin_lock_irq(&current->sigmask_lock);
 	tmpsig = current->blocked;
@@ -206,42 +208,35 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-
 	/* main loop */
 	while (sysctl_khttpd_unload==0)
 	{
 		int I;
-		
+		int old_stop_count;
 		
 		/* First : wait for activation */
-		
-		sysctl_khttpd_start = 0;
-		
 		while ( (sysctl_khttpd_start==0) && (!signal_pending(current)) && (sysctl_khttpd_unload==0) )
 		{
 			current->state = TASK_INTERRUPTIBLE;
 			interruptible_sleep_on_timeout(&WQ,HZ); 
 		}
-		
 		if ( (signal_pending(current)) || (sysctl_khttpd_unload!=0) )
 		 	break;
+		sysctl_khttpd_stop = 0;
 		 	
 		/* Then start listening and spawn the daemons */
-		 	
 		if (StartListening(sysctl_khttpd_serverport)==0)
 		{
+			sysctl_khttpd_start = 0;
 			continue;
 		}
-		
+
 		ActualThreads = sysctl_khttpd_threads;
 		if (ActualThreads<1) 
 			ActualThreads = 1;
-			
 		if (ActualThreads>CONFIG_KHTTPD_NUMCPU) 
 			ActualThreads = CONFIG_KHTTPD_NUMCPU;
-		
 		/* Write back the actual value */
-		
 		sysctl_khttpd_threads = ActualThreads;
 		
 		InitUserspace(ActualThreads);
@@ -249,87 +244,63 @@
 		if (InitDataSending(ActualThreads)!=0)
 		{
 			StopListening();
+			sysctl_khttpd_start = 0;
 			continue;
 		}
 		if (InitWaitHeaders(ActualThreads)!=0)
 		{
-			I=0;
-			while (I<ActualThreads)
-			{
+			for (I=0; I<ActualThreads; I++) {
 				StopDataSending(I);
-				I++;
 			}
 			StopListening();
+			sysctl_khttpd_start = 0;
 			continue;
 		}
 	
 		/* Clean all queues */
 		memset(threadinfo, 0, sizeof(struct khttpd_threadinfo));
 
-
-		 	
-		I=0;
-		while (I<ActualThreads)
-		{
+		for (I=0; I<ActualThreads; I++) {
 			atomic_set(&Running[I],1);
 			(void)kernel_thread(MainDaemon,&(CountBuf[I]), CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-			I++;
 		}
 		
 		/* Then wait for deactivation */
-		sysctl_khttpd_stop = 0;
-
-		while ( (sysctl_khttpd_stop==0) && (!signal_pending(current)) && (sysctl_khttpd_unload==0) )
+		/* Remember value of stop count.  If it changes, user must 
+		 * have asked us to stop.  Sensing this is much less racy 
+		 * than directly sensing sysctl_khttpd_stop. - dank
+		 */
+		old_stop_count = atomic_read(&khttpd_stopCount);
+		while ( ( old_stop_count == atomic_read(&khttpd_stopCount)) 
+			 && (!signal_pending(current)) 
+			 && (sysctl_khttpd_unload==0) )
 		{
-			if (atomic_read(&DaemonCount)<ActualThreads)
-			{
-				I=0;
-				while (I<ActualThreads)
-				{
-					if (atomic_read(&Running[I])==0)
-					{
-						atomic_set(&Running[I],1);
-						(void)kernel_thread(MainDaemon,&(CountBuf[I]), CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-						(void)printk(KERN_CRIT "kHTTPd: Restarting daemon %i \n",I);
-					}
-					I++;
-				}
-			}
+			/* Used to restart dead threads here, but it was buggy*/
 			interruptible_sleep_on_timeout(&WQ,HZ);
-			
-			/* reap the daemons */
-			waitpid_result = waitpid(-1,NULL,__WCLONE|WNOHANG);
-			
 		}
 		
-		
-		/* The user wants us to stop. So stop listening on the socket. */
-		if (sysctl_khttpd_stop!=0)	
-		{
-			/* Wait for the daemons to stop, one second per iteration */
-			while (atomic_read(&DaemonCount)>0)
-		 		interruptible_sleep_on_timeout(&WQ,HZ);
-			StopListening();
-		}
-
-		
-	
+		/* Wait for the daemons to stop, one second per iteration */
+		while (atomic_read(&DaemonCount)>0)
+			interruptible_sleep_on_timeout(&WQ,HZ);
+		StopListening();
+		sysctl_khttpd_start = 0;
+		/* reap the zombie-daemons */
+		do
+			waitpid_result = waitpid(-1,NULL,__WCLONE|WNOHANG);
+		while (waitpid_result>0);
 	}
-	
+	sysctl_khttpd_start = 0;
 	sysctl_khttpd_stop = 1;
+	atomic_inc(&khttpd_stopCount);
 
 	/* Wait for the daemons to stop, one second per iteration */
 	while (atomic_read(&DaemonCount)>0)
  		interruptible_sleep_on_timeout(&WQ,HZ);
-		
-		
-	waitpid_result = 1;
+	StopListening();
 	/* reap the zombie-daemons */
-	while (waitpid_result>0)
+	do
 		waitpid_result = waitpid(-1,NULL,__WCLONE|WNOHANG);
-		
-	StopListening();
-	
+	while (waitpid_result>0);
 	
 	(void)printk(KERN_NOTICE "kHTTPd: Management daemon stopped. \n        You can unload the module now.\n");
 
@@ -344,16 +315,13 @@
 
 	MOD_INC_USE_COUNT;
 	
-	I=0;
-	while (I<CONFIG_KHTTPD_NUMCPU)
-	{
+	for (I=0; I<CONFIG_KHTTPD_NUMCPU; I++) {
 		CountBuf[I]=I;
-		
-		I++;
 	}
 	
 	atomic_set(&ConnectCount,0);
 	atomic_set(&DaemonCount,0);
+	atomic_set(&khttpd_stopCount,0);
 	
 
 	/* Maybe the mime-types will be set-able through sysctl in the future */	   
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/khttpd/security.c linux-2.4.20/net/khttpd/security.c
--- linux-2.4.19/net/khttpd/security.c	2001-02-09 19:29:44.000000000 +0000
+++ linux-2.4.20/net/khttpd/security.c	2002-10-29 11:18:32.000000000 +0000
@@ -83,22 +83,21 @@
 */
 struct file *OpenFileForSecurity(char *Filename)
 {
-	struct file *filp;
+	struct file *filp = NULL;
 	struct DynamicString *List;
 	umode_t permission;
 	
-	
-
 	EnterFunction("OpenFileForSecurity");
 	if (Filename==NULL)
-		return NULL;
+		goto out_error;
 	
-	if (strlen(Filename)>=256 ) return NULL;  /* Sanity check */
+	if (strlen(Filename)>=256 )
+		goto out_error;  /* Sanity check */
 	
 	/* Rule no. 1  -- No "?" characters */
 #ifndef BENCHMARK	
 	if (strchr(Filename,'?')!=NULL)
-		return NULL;
+		goto out_error;
 
 	/* Intermediate step: decode all %hex sequences */
 	
@@ -106,9 +105,8 @@
 
 	/* Rule no. 2  -- Must start with a "/" */
 	
-	
 	if (Filename[0]!='/')
-		return NULL;
+		goto out_error;
 		
 #endif
 	/* Rule no. 3 -- Does the file exist ? */
@@ -116,55 +114,44 @@
 	filp = filp_open(Filename, O_RDONLY, 0);
 	
 	if (IS_ERR(filp))
-		return NULL;
+		goto out_error;
 
 #ifndef BENCHMARK		
 	permission = filp->f_dentry->d_inode->i_mode;
 	
 	/* Rule no. 4 : must have enough permissions */
 	
-	
 	if ((permission & sysctl_khttpd_permreq)==0)
-	{
-		if (filp!=NULL)
-			fput(filp);
-		filp=NULL;
-		return NULL;
-	}
-		
+		goto out_error_put;	
+
 	/* Rule no. 5 : cannot have "forbidden" permission */
 	
-	
 	if ((permission & sysctl_khttpd_permforbid)!=0)
-	{
-		if (filp!=NULL)
-			fput(filp);
-		filp=NULL;
-		return NULL;
-	}
+		goto out_error_put;	
 		
 	/* Rule no. 6 : No string in DynamicList can be a
 			substring of the filename */
-			
 	
 	List = DynamicList;
-	
 	while (List!=NULL)
 	{
 		if (strstr(Filename,List->value)!=NULL)
-		{
-			if (filp!=NULL)
-				fput(filp);
-			filp=NULL;
-			return NULL;
-		}
+			goto out_error_put;	
+
 		List = List->Next;
 	}
 	
 #endif	
 	LeaveFunction("OpenFileForSecurity - success");
-
+out:
 	return filp;
+
+out_error_put:
+	fput(filp);
+out_error:
+	filp=NULL;
+	LeaveFunction("OpenFileForSecurity - fail");
+	goto out;
 }
 
 /* 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/khttpd/sysctl.c linux-2.4.20/net/khttpd/sysctl.c
--- linux-2.4.19/net/khttpd/sysctl.c	2001-02-09 19:34:13.000000000 +0000
+++ linux-2.4.20/net/khttpd/sysctl.c	2002-10-29 11:18:51.000000000 +0000
@@ -64,6 +64,7 @@
 int	sysctl_khttpd_threads	= 2;
 int	sysctl_khttpd_maxconnect = 1000;
 
+atomic_t        khttpd_stopCount;
 
 static struct ctl_table_header *khttpd_table_header;
 
@@ -72,6 +73,8 @@
 		  void *newval, size_t newlen, void **context);
 static int proc_dosecurestring(ctl_table *table, int write, struct file *filp,
 		  void *buffer, size_t *lenp);
+static int khttpd_stop_wrap_proc_dointvec(ctl_table *table, int write, struct file *filp,
+		  void *buffer, size_t *lenp);
 
 
 static ctl_table khttpd_table[] = {
@@ -93,7 +96,7 @@
 		sizeof(int),
 		0644,
 		NULL,
-		proc_dointvec,
+		khttpd_stop_wrap_proc_dointvec,
 		&sysctl_intvec,
 		NULL,
 		NULL,
@@ -307,6 +310,24 @@
 	return 0;
 }
 
+/* A wrapper around proc_dointvec that computes
+ * khttpd_stopCount = # of times sysctl_khttpd_stop has gone true
+ * Sensing sysctl_khttpd_stop in other threads is racy;
+ * sensing khttpd_stopCount in other threads is not.
+ */
+static int khttpd_stop_wrap_proc_dointvec(ctl_table *table, int write, struct file *filp,
+		  void *buffer, size_t *lenp)
+{
+	int rv;
+	int oldstop = sysctl_khttpd_stop;
+	rv = proc_dointvec(table, write, filp, buffer, lenp);
+	if (sysctl_khttpd_stop && !oldstop)
+		atomic_inc(&khttpd_stopCount);
+
+	return rv;
+}
+		
+
 static int sysctl_SecureString (/*@unused@*/ctl_table *table, 
 				/*@unused@*/int *name, 
 				/*@unused@*/int nlen,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/khttpd/sysctl.h linux-2.4.20/net/khttpd/sysctl.h
--- linux-2.4.19/net/khttpd/sysctl.h	1999-08-18 16:45:10.000000000 +0000
+++ linux-2.4.20/net/khttpd/sysctl.h	2002-10-29 11:18:35.000000000 +0000
@@ -14,4 +14,7 @@
 extern int 	sysctl_khttpd_threads;
 extern int	sysctl_khttpd_maxconnect;
 
+/* incremented each time sysctl_khttpd_stop goes nonzero */
+extern atomic_t	khttpd_stopCount;
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/khttpd/waitheaders.c linux-2.4.20/net/khttpd/waitheaders.c
--- linux-2.4.19/net/khttpd/waitheaders.c	2001-09-10 14:57:00.000000000 +0000
+++ linux-2.4.20/net/khttpd/waitheaders.c	2002-10-29 11:18:36.000000000 +0000
@@ -134,7 +134,7 @@
 		CurrentRequest = CurrentRequest->Next;
 	}
 
-	LeaveFunction("WaitHeaders");
+	LeaveFunction("WaitForHeaders");
 	return count;
 }
 
@@ -178,6 +178,12 @@
 	
 	EnterFunction("DecodeHeader");
 	
+	if (Buffer[CPUNR] == NULL) {
+		/* see comments in main.c regarding buffer managemnet - dank */
+		printk(KERN_CRIT "khttpd: lost my buffer");
+		BUG();
+	}
+
 	/* First, read the data */
 
 	msg.msg_name     = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/netlink/af_netlink.c linux-2.4.20/net/netlink/af_netlink.c
--- linux-2.4.19/net/netlink/af_netlink.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.20/net/netlink/af_netlink.c	2002-10-29 11:18:48.000000000 +0000
@@ -39,6 +39,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/proc_fs.h>
 #include <linux/smp_lock.h>
+#include <linux/notifier.h>
 #include <net/sock.h>
 #include <net/scm.h>
 
@@ -64,6 +65,7 @@
 
 static struct sock *nl_table[MAX_LINKS];
 static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait);
+static unsigned nl_nonroot[MAX_LINKS];
 
 #ifdef NL_EMULATE_DEV
 static struct socket *netlink_kernel[MAX_LINKS];
@@ -77,6 +79,8 @@
 static rwlock_t nl_table_lock = RW_LOCK_UNLOCKED;
 static atomic_t nl_table_users = ATOMIC_INIT(0);
 
+static struct notifier_block *netlink_chain;
+
 static void netlink_sock_destruct(struct sock *sk)
 {
 	skb_queue_purge(&sk->receive_queue);
@@ -269,6 +273,12 @@
 
 	skb_queue_purge(&sk->write_queue);
 
+	if (sk->protinfo.af_netlink->pid && !sk->protinfo.af_netlink->groups) {
+		struct netlink_notify n = { protocol:sk->protocol,
+		                            pid:sk->protinfo.af_netlink->pid };
+		notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n);
+	}	
+	
 	sock_put(sk);
 	return 0;
 }
@@ -301,6 +311,11 @@
 	return 0;
 }
 
+static inline int netlink_capable(struct socket *sock, unsigned flag) 
+{ 
+	return (nl_nonroot[sock->sk->protocol] & flag) || capable(CAP_NET_ADMIN);
+} 
+
 static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
 {
 	struct sock *sk = sock->sk;
@@ -311,7 +326,7 @@
 		return -EINVAL;
 
 	/* Only superuser is allowed to listen multicasts */
-	if (nladdr->nl_groups && !capable(CAP_NET_ADMIN))
+	if (nladdr->nl_groups && !netlink_capable(sock, NL_NONROOT_RECV))
 		return -EPERM;
 
 	if (sk->protinfo.af_netlink->pid) {
@@ -350,7 +365,7 @@
 		return -EINVAL;
 
 	/* Only superuser is allowed to send multicasts */
-	if (nladdr->nl_groups && !capable(CAP_NET_ADMIN))
+	if (nladdr->nl_groups && !netlink_capable(sock, NL_NONROOT_SEND))
 		return -EPERM;
 
 	if (!sk->protinfo.af_netlink->pid)
@@ -565,7 +580,7 @@
 			return -EINVAL;
 		dst_pid = addr->nl_pid;
 		dst_groups = addr->nl_groups;
-		if (dst_groups && !capable(CAP_NET_ADMIN))
+		if (dst_groups && !netlink_capable(sock, NL_NONROOT_SEND))
 			return -EPERM;
 	} else {
 		dst_pid = sk->protinfo.af_netlink->dst_pid;
@@ -715,6 +730,12 @@
 	return sk;
 }
 
+void netlink_set_nonroot(int protocol, unsigned flags)
+{ 
+	if ((unsigned)protocol < MAX_LINKS) 
+		nl_nonroot[protocol] = flags;
+} 
+
 static void netlink_destroy_callback(struct netlink_callback *cb)
 {
 	if (cb->skb)
@@ -945,6 +966,16 @@
 }
 #endif
 
+int netlink_register_notifier(struct notifier_block *nb)
+{
+	return notifier_chain_register(&netlink_chain, nb);
+}
+
+int netlink_unregister_notifier(struct notifier_block *nb)
+{
+	return notifier_chain_unregister(&netlink_chain, nb);
+}
+                
 struct proto_ops netlink_ops = {
 	family:		PF_NETLINK,
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/netsyms.c linux-2.4.20/net/netsyms.c
--- linux-2.4.19/net/netsyms.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/netsyms.c	2002-10-29 11:18:39.000000000 +0000
@@ -416,6 +416,9 @@
 EXPORT_SYMBOL(netlink_kernel_create);
 EXPORT_SYMBOL(netlink_dump_start);
 EXPORT_SYMBOL(netlink_ack);
+EXPORT_SYMBOL(netlink_set_nonroot);
+EXPORT_SYMBOL(netlink_register_notifier);
+EXPORT_SYMBOL(netlink_unregister_notifier);
 #if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE)
 EXPORT_SYMBOL(netlink_attach);
 EXPORT_SYMBOL(netlink_detach);
@@ -490,6 +493,7 @@
 EXPORT_SYMBOL(skb_clone);
 EXPORT_SYMBOL(skb_copy);
 EXPORT_SYMBOL(netif_rx);
+EXPORT_SYMBOL(netif_receive_skb);
 EXPORT_SYMBOL(dev_add_pack);
 EXPORT_SYMBOL(dev_remove_pack);
 EXPORT_SYMBOL(dev_get);
@@ -585,7 +589,11 @@
 
 EXPORT_SYMBOL(register_gifconf);
 
-EXPORT_SYMBOL(net_call_rx_atomic);
 EXPORT_SYMBOL(softnet_data);
 
+#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
+#include <net/iw_handler.h>
+EXPORT_SYMBOL(wireless_send_event);
+#endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
+
 #endif  /* CONFIG_NET */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/sched/Config.in linux-2.4.20/net/sched/Config.in
--- linux-2.4.19/net/sched/Config.in	2001-12-21 17:42:06.000000000 +0000
+++ linux-2.4.20/net/sched/Config.in	2002-10-29 11:18:31.000000000 +0000
@@ -2,6 +2,7 @@
 # Traffic control configuration.
 # 
 tristate '  CBQ packet scheduler' CONFIG_NET_SCH_CBQ
+tristate '  HTB packet scheduler' CONFIG_NET_SCH_HTB
 tristate '  CSZ packet scheduler' CONFIG_NET_SCH_CSZ
 #tristate '  H-PFQ packet scheduler' CONFIG_NET_SCH_HPFQ
 #tristate '  H-FSC packet scheduler' CONFIG_NET_SCH_HFCS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/sched/Makefile linux-2.4.20/net/sched/Makefile
--- linux-2.4.19/net/sched/Makefile	2001-03-07 06:44:15.000000000 +0000
+++ linux-2.4.20/net/sched/Makefile	2002-10-29 11:18:47.000000000 +0000
@@ -16,6 +16,7 @@
 obj-$(CONFIG_NET_SCH_CSZ)	+= sch_csz.o
 obj-$(CONFIG_NET_SCH_HPFQ)	+= sch_hpfq.o
 obj-$(CONFIG_NET_SCH_HFSC)	+= sch_hfsc.o
+obj-$(CONFIG_NET_SCH_HTB)	+= sch_htb.o
 obj-$(CONFIG_NET_SCH_SFQ)	+= sch_sfq.o
 obj-$(CONFIG_NET_SCH_RED)	+= sch_red.o
 obj-$(CONFIG_NET_SCH_TBF)	+= sch_tbf.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/sched/sch_api.c linux-2.4.20/net/sched/sch_api.c
--- linux-2.4.19/net/sched/sch_api.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/sched/sch_api.c	2002-10-29 11:18:40.000000000 +0000
@@ -1205,6 +1205,9 @@
 #ifdef CONFIG_NET_SCH_CBQ
 	INIT_QDISC(cbq);
 #endif
+#ifdef CONFIG_NET_SCH_HTB
+	INIT_QDISC(htb);
+#endif
 #ifdef CONFIG_NET_SCH_CSZ
 	INIT_QDISC(csz);
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/sched/sch_generic.c linux-2.4.20/net/sched/sch_generic.c
--- linux-2.4.19/net/sched/sch_generic.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/sched/sch_generic.c	2002-10-29 11:18:32.000000000 +0000
@@ -475,10 +475,8 @@
 
 	dev_watchdog_down(dev);
 
-	while (test_bit(__LINK_STATE_SCHED, &dev->state)) {
-		current->policy |= SCHED_YIELD;
-		schedule();
-	}
+	while (test_bit(__LINK_STATE_SCHED, &dev->state))
+		yield();
 
 	spin_unlock_wait(&dev->xmit_lock);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/sched/sch_htb.c linux-2.4.20/net/sched/sch_htb.c
--- linux-2.4.19/net/sched/sch_htb.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/sched/sch_htb.c	2002-10-29 11:18:31.000000000 +0000
@@ -0,0 +1,1660 @@
+/* vim: ts=8 sw=8
+ * net/sched/sch_htb.c	Hierarchical token bucket, feed tree version
+ *
+ *		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.
+ *
+ * Authors:	Martin Devera, <devik@cdi.cz>
+ *
+ * Credits (in time order) for older HTB versions:
+ *		Ondrej Kraus, <krauso@barr.cz> 
+ *			found missing INIT_QDISC(htb)
+ *		Vladimir Smelhaus, Aamer Akhter, Bert Hubert
+ *			helped a lot to locate nasty class stall bug
+ *		Andi Kleen, Jamal Hadi, Bert Hubert
+ *			code review and helpful comments on shaping
+ *		Tomasz Wrona, <tw@eter.tym.pl>
+ *			created test case so that I was able to fix nasty bug
+ *		and many others. thanks.
+ *
+ * $Id: sch_htb.c,v 1.14 2002/09/28 12:55:22 devik Exp devik $
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/notifier.h>
+#include <net/ip.h>
+#include <net/route.h>
+#include <linux/skbuff.h>
+#include <linux/list.h>
+#include <linux/compiler.h>
+#include <net/sock.h>
+#include <net/pkt_sched.h>
+#include <linux/rbtree.h>
+
+/* HTB algorithm.
+    Author: devik@cdi.cz
+    ========================================================================
+    HTB is like TBF with multiple classes. It is also similar to CBQ because
+    it allows to assign priority to each class in hierarchy. 
+    In fact it is another implementation of Floyd's formal sharing.
+
+    Levels:
+    Each class is assigned level. Leaf has ALWAYS level 0 and root 
+    classes have level TC_HTB_MAXDEPTH-1. Interior nodes has level
+    one less than their parent.
+*/
+
+#define HTB_HSIZE 16	/* classid hash size */
+#define HTB_EWMAC 2	/* rate average over HTB_EWMAC*HTB_HSIZE sec */
+#define HTB_DEBUG 1	/* compile debugging support (activated by tc tool) */
+#define HTB_RATECM 1    /* whether to use rate computer */
+#define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */
+#define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock)
+#define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock)
+#define HTB_VER 0x30007	/* major must be matched with number suplied by TC as version */
+
+#if HTB_VER >> 16 != TC_HTB_PROTOVER
+#error "Mismatched sch_htb.c and pkt_sch.h"
+#endif
+
+/* temporary debug defines to be removed after beta stage */
+#define DEVIK_MEND(N)
+#define DEVIK_MSTART(N)
+
+/* debugging support; S is subsystem, these are defined:
+  0 - netlink messages
+  1 - enqueue
+  2 - drop & requeue
+  3 - dequeue main
+  4 - dequeue one prio DRR part
+  5 - dequeue class accounting
+  6 - class overlimit status computation
+  7 - hint tree
+  8 - event queue
+ 10 - rate estimator
+ 11 - classifier 
+ 12 - fast dequeue cache
+
+ L is level; 0 = none, 1 = basic info, 2 = detailed, 3 = full
+ q->debug uint32 contains 16 2-bit fields one for subsystem starting
+ from LSB
+ */
+#ifdef HTB_DEBUG
+#define HTB_DBG(S,L,FMT,ARG...) if (((q->debug>>(2*S))&3) >= L) \
+	printk(KERN_DEBUG FMT,##ARG)
+#define HTB_CHCL(cl) BUG_TRAP((cl)->magic == HTB_CMAGIC)
+#define HTB_PASSQ q,
+#define HTB_ARGQ struct htb_sched *q,
+#define static
+#define __inline__
+#define inline
+#define HTB_CMAGIC 0xFEFAFEF1
+#define htb_safe_rb_erase(N,R) do { BUG_TRAP((N)->rb_color != -1); \
+		if ((N)->rb_color == -1) break; \
+		rb_erase(N,R); \
+		(N)->rb_color = -1; } while (0)
+#else
+#define HTB_DBG(S,L,FMT,ARG...)
+#define HTB_PASSQ
+#define HTB_ARGQ
+#define HTB_CHCL(cl)
+#define htb_safe_rb_erase(N,R) rb_erase(N,R)
+#endif
+
+
+/* used internaly to keep status of single class */
+enum htb_cmode {
+    HTB_CANT_SEND,		/* class can't send and can't borrow */
+    HTB_MAY_BORROW,		/* class can't send but may borrow */
+    HTB_CAN_SEND		/* class can send */
+};
+
+/* interior & leaf nodes; props specific to leaves are marked L: */
+struct htb_class
+{
+#ifdef HTB_DEBUG
+	unsigned magic;
+#endif
+    /* general class parameters */
+    u32 classid;
+    struct tc_stats	stats;	/* generic stats */
+    struct tc_htb_xstats xstats;/* our special stats */
+    int refcnt;			/* usage count of this class */
+
+#ifdef HTB_RATECM
+    /* rate measurement counters */
+    unsigned long rate_bytes,sum_bytes;
+    unsigned long rate_packets,sum_packets;
+#endif
+
+    /* topology */
+    int level;			/* our level (see above) */
+    struct htb_class *parent;	/* parent class */
+    struct list_head hlist;	/* classid hash list item */
+    struct list_head sibling;	/* sibling list item */
+    struct list_head children;	/* children list */
+
+    union {
+	    struct htb_class_leaf {
+		    struct Qdisc *q;
+		    int prio;
+		    int aprio;	
+		    int quantum;
+		    int deficit[TC_HTB_MAXDEPTH];
+		    struct list_head drop_list;
+	    } leaf;
+	    struct htb_class_inner {
+		    rb_root_t feed[TC_HTB_NUMPRIO];	/* feed trees */
+		    rb_node_t *ptr[TC_HTB_NUMPRIO];	/* current class ptr */
+	    } inner;
+    } un;
+    rb_node_t node[TC_HTB_NUMPRIO];	/* node for self or feed tree */
+    rb_node_t pq_node;			/* node for event queue */
+    unsigned long pq_key;	/* the same type as jiffies global */
+    
+    int prio_activity;		/* for which prios are we active */
+    enum htb_cmode cmode;	/* current mode of the class */
+
+    /* class attached filters */
+    struct tcf_proto *filter_list;
+    int filter_cnt;
+
+    int warned;		/* only one warning about non work conserving .. */
+
+    /* token bucket parameters */
+    struct qdisc_rate_table *rate;	/* rate table of the class itself */
+    struct qdisc_rate_table *ceil;	/* ceiling rate (limits borrows too) */
+    long buffer,cbuffer;		/* token bucket depth/rate */
+    long mbuffer;			/* max wait time */
+    long tokens,ctokens;		/* current number of tokens */
+    psched_time_t t_c;			/* checkpoint time */
+};
+
+/* TODO: maybe compute rate when size is too large .. or drop ? */
+static __inline__ long L2T(struct htb_class *cl,struct qdisc_rate_table *rate,
+	int size)
+{ 
+    int slot = size >> rate->rate.cell_log;
+    if (slot > 255) {
+	cl->xstats.giants++;
+	slot = 255;
+    }
+    return rate->data[slot];
+}
+
+struct htb_sched
+{
+    struct list_head root;			/* root classes list */
+    struct list_head hash[HTB_HSIZE];		/* hashed by classid */
+    struct list_head drops[TC_HTB_NUMPRIO];	/* active leaves (for drops) */
+    
+    /* self list - roots of self generating tree */
+    rb_root_t row[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO];
+    int row_mask[TC_HTB_MAXDEPTH];
+    rb_node_t *ptr[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO];
+
+    /* self wait list - roots of wait PQs per row */
+    rb_root_t wait_pq[TC_HTB_MAXDEPTH];
+
+    /* time of nearest event per level (row) */
+    unsigned long near_ev_cache[TC_HTB_MAXDEPTH];
+
+    /* whether we hit non-work conserving class during this dequeue; we use */
+    int nwc_hit;	/* this to disable mindelay complaint in dequeue */
+
+    int defcls;		/* class where unclassified flows go to */
+    u32 debug;		/* subsystem debug levels */
+
+    /* filters for qdisc itself */
+    struct tcf_proto *filter_list;
+    int filter_cnt;
+
+    int rate2quantum;		/* quant = rate / rate2quantum */
+    psched_time_t now;		/* cached dequeue time */
+    struct timer_list timer;	/* send delay timer */
+#ifdef HTB_RATECM
+    struct timer_list rttim;	/* rate computer timer */
+    int recmp_bucket;		/* which hash bucket to recompute next */
+#endif
+    
+    /* non shaped skbs; let them go directly thru */
+    struct sk_buff_head direct_queue;
+    int direct_qlen;  /* max qlen of above */
+
+    long direct_pkts;
+};
+
+/* compute hash of size HTB_HSIZE for given handle */
+static __inline__ int htb_hash(u32 h) 
+{
+#if HTB_HSIZE != 16
+ #error "Declare new hash for your HTB_HSIZE"
+#endif
+    h ^= h>>8;	/* stolen from cbq_hash */
+    h ^= h>>4;
+    return h & 0xf;
+}
+
+/* find class in global hash table using given handle */
+static __inline__ struct htb_class *htb_find(u32 handle, struct Qdisc *sch)
+{
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+	struct list_head *p;
+	if (TC_H_MAJ(handle) != sch->handle) 
+		return NULL;
+	
+	list_for_each (p,q->hash+htb_hash(handle)) {
+		struct htb_class *cl = list_entry(p,struct htb_class,hlist);
+		if (cl->classid == handle)
+			return cl;
+	}
+	return NULL;
+}
+
+/**
+ * htb_classify - classify a packet into class
+ *
+ * It returns NULL if the packet should be dropped or -1 if the packet
+ * should be passed directly thru. In all other cases leaf class is returned.
+ * We allow direct class selection by classid in priority. The we examine
+ * filters in qdisc and in inner nodes (if higher filter points to the inner
+ * node). If we end up with classid MAJOR:0 we enqueue the skb into special
+ * internal fifo (direct). These packets then go directly thru. If we still 
+ * have no valid leaf we try to use MAJOR:default leaf. It still unsuccessfull
+ * then finish and return direct queue.
+ */
+#define HTB_DIRECT (struct htb_class*)-1
+static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch)
+{
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+	struct htb_class *cl;
+	struct tcf_result res;
+	struct tcf_proto *tcf;
+	int result;
+
+	/* allow to select class by setting skb->priority to valid classid;
+	   note that nfmark can be used too by attaching filter fw with no
+	   rules in it */
+	if (skb->priority == sch->handle)
+		return HTB_DIRECT;  /* X:0 (direct flow) selected */
+	if ((cl = htb_find(skb->priority,sch)) != NULL) 
+		return cl;
+
+	tcf = q->filter_list;
+	while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) {
+#ifdef CONFIG_NET_CLS_POLICE
+		if (result == TC_POLICE_SHOT)
+			return NULL;
+#endif
+		if ((cl = (void*)res.class) == NULL) {
+			if (res.classid == sch->handle)
+				return HTB_DIRECT;  /* X:0 (direct flow) */
+			if ((cl = htb_find(res.classid,sch)) == NULL)
+				break; /* filter selected invalid classid */
+		}
+		if (!cl->level)
+			return cl; /* we hit leaf; return it */
+
+		/* we have got inner class; apply inner filter chain */
+		tcf = cl->filter_list;
+	}
+	/* classification failed; try to use default class */
+	cl = htb_find(TC_H_MAKE(TC_H_MAJ(sch->handle),q->defcls),sch);
+	if (!cl || cl->level)
+		return HTB_DIRECT; /* bad default .. this is safe bet */
+	return cl;
+}
+
+#ifdef HTB_DEBUG
+static void htb_next_rb_node(rb_node_t **n);
+#define HTB_DUMTREE(root,memb) if(root) { \
+	rb_node_t *n = (root)->rb_node; \
+	while (n->rb_left) n = n->rb_left; \
+	while (n) { \
+		struct htb_class *cl = rb_entry(n, struct htb_class, memb); \
+		printk(" %x",cl->classid); htb_next_rb_node (&n); \
+	} }
+
+static void htb_debug_dump (struct htb_sched *q)
+{
+	int i,p;
+	printk(KERN_DEBUG "htb*g j=%lu\n",jiffies);
+	/* rows */
+	for (i=TC_HTB_MAXDEPTH-1;i>=0;i--) {
+		printk(KERN_DEBUG "htb*r%d m=%x",i,q->row_mask[i]);
+		for (p=0;p<TC_HTB_NUMPRIO;p++) {
+			if (!q->row[i][p].rb_node) continue;
+			printk(" p%d:",p);
+			HTB_DUMTREE(q->row[i]+p,node[p]);
+		}
+		printk("\n");
+	}
+	/* classes */
+	for (i = 0; i < HTB_HSIZE; i++) {
+		struct list_head *l;
+		list_for_each (l,q->hash+i) {
+			struct htb_class *cl = list_entry(l,struct htb_class,hlist);
+			long diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32)cl->mbuffer, 0);
+			printk(KERN_DEBUG "htb*c%x m=%d t=%ld c=%ld pq=%lu df=%ld ql=%d "
+					"pa=%x f:",
+				cl->classid,cl->cmode,cl->tokens,cl->ctokens,
+				cl->pq_node.rb_color==-1?0:cl->pq_key,diff,
+				cl->level?0:cl->un.leaf.q->q.qlen,cl->prio_activity);
+			if (cl->level)
+			for (p=0;p<TC_HTB_NUMPRIO;p++) {
+				if (!cl->un.inner.feed[p].rb_node) continue;
+				printk(" p%d a=%x:",p,cl->un.inner.ptr[p]?rb_entry(cl->un.inner.ptr[p], struct htb_class,node[p])->classid:0);
+				HTB_DUMTREE(cl->un.inner.feed+p,node[p]);
+			}
+			printk("\n");
+		}
+	}
+}
+#endif
+/**
+ * htb_add_to_id_tree - adds class to the round robin list
+ *
+ * Routine adds class to the list (actually tree) sorted by classid.
+ * Make sure that class is not already on such list for given prio.
+ */
+static void htb_add_to_id_tree (HTB_ARGQ rb_root_t *root,
+		struct htb_class *cl,int prio)
+{
+	rb_node_t **p = &root->rb_node, *parent = NULL;
+	HTB_DBG(7,3,"htb_add_id_tree cl=%X prio=%d\n",cl->classid,prio);
+#ifdef HTB_DEBUG
+	if (cl->node[prio].rb_color != -1) { BUG_TRAP(0); return; }
+	HTB_CHCL(cl);
+	if (*p) {
+		struct htb_class *x = rb_entry(*p,struct htb_class,node[prio]);
+		HTB_CHCL(x);
+	}
+#endif
+	while (*p) {
+		struct htb_class *c; parent = *p;
+		c = rb_entry(parent, struct htb_class, node[prio]);
+		HTB_CHCL(c);
+		if (cl->classid > c->classid)
+			p = &parent->rb_right;
+		else 
+			p = &parent->rb_left;
+	}
+	rb_link_node(&cl->node[prio], parent, p);
+	rb_insert_color(&cl->node[prio], root);
+}
+
+/**
+ * htb_add_to_wait_tree - adds class to the event queue with delay
+ *
+ * The class is added to priority event queue to indicate that class will
+ * change its mode in cl->pq_key microseconds. Make sure that class is not
+ * already in the queue.
+ */
+static void htb_add_to_wait_tree (struct htb_sched *q,
+		struct htb_class *cl,long delay,int debug_hint)
+{
+	rb_node_t **p = &q->wait_pq[cl->level].rb_node, *parent = NULL;
+	HTB_DBG(7,3,"htb_add_wt cl=%X key=%lu\n",cl->classid,cl->pq_key);
+#ifdef HTB_DEBUG
+	if (cl->pq_node.rb_color != -1) { BUG_TRAP(0); return; }
+	HTB_CHCL(cl);
+	if ((delay <= 0 || delay > cl->mbuffer) && net_ratelimit())
+		printk(KERN_ERR "HTB: suspicious delay in wait_tree d=%ld cl=%X h=%d\n",delay,cl->classid,debug_hint);
+#endif
+	DEVIK_MSTART(9);
+	cl->pq_key = jiffies + PSCHED_US2JIFFIE(delay);
+	if (cl->pq_key == jiffies)
+		cl->pq_key++;
+
+	/* update the nearest event cache */
+	if (q->near_ev_cache[cl->level] - cl->pq_key < 0x80000000)
+		q->near_ev_cache[cl->level] = cl->pq_key;
+	
+	while (*p) {
+		struct htb_class *c; parent = *p;
+		c = rb_entry(parent, struct htb_class, pq_node);
+		if (cl->pq_key - c->pq_key < 0x80000000)
+			p = &parent->rb_right;
+		else 
+			p = &parent->rb_left;
+	}
+	rb_link_node(&cl->pq_node, parent, p);
+	rb_insert_color(&cl->pq_node, &q->wait_pq[cl->level]);
+	DEVIK_MEND(9);
+}
+
+/**
+ * htb_next_rb_node - finds next node in binary tree
+ *
+ * When we are past last key we return NULL.
+ * Average complexity is 2 steps per call.
+ */
+static void htb_next_rb_node(rb_node_t **n)
+{
+	rb_node_t *p;
+	if ((*n)->rb_right) {
+		*n = (*n)->rb_right;
+		while ((*n)->rb_left) 
+			*n = (*n)->rb_left;
+		return;
+	}
+	while ((p = (*n)->rb_parent) != NULL) {
+		if (p->rb_left == *n) break;
+		*n = p;
+	}
+	*n = p;
+}
+
+/**
+ * htb_add_class_to_row - add class to its row
+ *
+ * The class is added to row at priorities marked in mask.
+ * It does nothing if mask == 0.
+ */
+static inline void htb_add_class_to_row(struct htb_sched *q, 
+		struct htb_class *cl,int mask)
+{
+	HTB_DBG(7,2,"htb_addrow cl=%X mask=%X rmask=%X\n",
+			cl->classid,mask,q->row_mask[cl->level]);
+	HTB_CHCL(cl);
+	q->row_mask[cl->level] |= mask;
+	while (mask) {
+		int prio = ffz(~mask);
+		mask &= ~(1 << prio);
+		htb_add_to_id_tree(HTB_PASSQ q->row[cl->level]+prio,cl,prio);
+	}
+}
+
+/**
+ * htb_remove_class_from_row - removes class from its row
+ *
+ * The class is removed from row at priorities marked in mask.
+ * It does nothing if mask == 0.
+ */
+static __inline__ void htb_remove_class_from_row(struct htb_sched *q,
+		struct htb_class *cl,int mask)
+{
+	int m = 0;
+	HTB_CHCL(cl);
+	while (mask) {
+		int prio = ffz(~mask);
+		mask &= ~(1 << prio);
+		if (q->ptr[cl->level][prio] == cl->node+prio)
+			htb_next_rb_node(q->ptr[cl->level]+prio);
+		htb_safe_rb_erase(cl->node + prio,q->row[cl->level]+prio);
+		if (!q->row[cl->level][prio].rb_node) 
+			m |= 1 << prio;
+	}
+	HTB_DBG(7,2,"htb_delrow cl=%X mask=%X rmask=%X maskdel=%X\n",
+			cl->classid,mask,q->row_mask[cl->level],m);
+	q->row_mask[cl->level] &= ~m;
+}
+
+/**
+ * htb_activate_prios - creates active classe's feed chain
+ *
+ * The class is connected to ancestors and/or appropriate rows
+ * for priorities it is participating on. cl->cmode must be new 
+ * (activated) mode. It does nothing if cl->prio_activity == 0.
+ */
+static void htb_activate_prios(struct htb_sched *q,struct htb_class *cl)
+{
+	struct htb_class *p = cl->parent;
+	long m,mask = cl->prio_activity;
+	HTB_DBG(7,2,"htb_act_prios cl=%X mask=%lX cmode=%d\n",cl->classid,mask,cl->cmode);
+	HTB_CHCL(cl);
+
+	while (cl->cmode == HTB_MAY_BORROW && p && mask) {
+		HTB_CHCL(p);
+		m = mask; while (m) {
+			int prio = ffz(~m);
+			m &= ~(1 << prio);
+			
+			if (p->un.inner.feed[prio].rb_node)
+				/* parent already has its feed in use so that
+				   reset bit in mask as parent is already ok */
+				mask &= ~(1 << prio);
+			
+			htb_add_to_id_tree(HTB_PASSQ p->un.inner.feed+prio,cl,prio);
+		}
+		HTB_DBG(7,3,"htb_act_pr_aft p=%X pact=%X mask=%lX pmode=%d\n",
+				p->classid,p->prio_activity,mask,p->cmode);
+		p->prio_activity |= mask;
+		cl = p; p = cl->parent;
+		HTB_CHCL(cl);
+	}
+	if (cl->cmode == HTB_CAN_SEND && mask)
+		htb_add_class_to_row(q,cl,mask);
+}
+
+/**
+ * htb_deactivate_prios - remove class from feed chain
+ *
+ * cl->cmode must represent old mode (before deactivation). It does 
+ * nothing if cl->prio_activity == 0. Class is removed from all feed
+ * chains and rows.
+ */
+static void htb_deactivate_prios(struct htb_sched *q, struct htb_class *cl)
+{
+	struct htb_class *p = cl->parent;
+	long m,mask = cl->prio_activity;
+	HTB_DBG(7,2,"htb_deact_prios cl=%X mask=%lX cmode=%d\n",cl->classid,mask,cl->cmode);
+	HTB_CHCL(cl);
+
+	while (cl->cmode == HTB_MAY_BORROW && p && mask) {
+		m = mask; mask = 0; 
+		while (m) {
+			int prio = ffz(~m);
+			m &= ~(1 << prio);
+			
+			if (p->un.inner.ptr[prio] == cl->node+prio)
+				htb_next_rb_node(p->un.inner.ptr + prio);
+			
+			htb_safe_rb_erase(cl->node + prio,p->un.inner.feed + prio);
+			
+			if (!p->un.inner.feed[prio].rb_node) 
+				mask |= 1 << prio;
+		}
+		HTB_DBG(7,3,"htb_deact_pr_aft p=%X pact=%X mask=%lX pmode=%d\n",
+				p->classid,p->prio_activity,mask,p->cmode);
+		p->prio_activity &= ~mask;
+		cl = p; p = cl->parent;
+		HTB_CHCL(cl);
+	}
+	if (cl->cmode == HTB_CAN_SEND && mask) 
+		htb_remove_class_from_row(q,cl,mask);
+}
+
+/**
+ * htb_class_mode - computes and returns current class mode
+ *
+ * It computes cl's mode at time cl->t_c+diff and returns it. If mode
+ * is not HTB_CAN_SEND then cl->pq_key is updated to time difference
+ * from now to time when cl will change its state. 
+ * Also it is worth to note that class mode doesn't change simply
+ * at cl->{c,}tokens == 0 but there can rather be hysteresis of 
+ * 0 .. -cl->{c,}buffer range. It is meant to limit number of
+ * mode transitions per time unit. The speed gain is about 1/6.
+ */
+static __inline__ enum htb_cmode 
+htb_class_mode(struct htb_class *cl,long *diff)
+{
+    long toks;
+
+    if ((toks = (cl->ctokens + *diff)) < (
+#ifdef HTB_HYSTERESIS
+	    cl->cmode != HTB_CANT_SEND ? -cl->cbuffer :
+#endif
+       	    0)) {
+	    *diff = -toks;
+	    return HTB_CANT_SEND;
+    }
+    if ((toks = (cl->tokens + *diff)) >= (
+#ifdef HTB_HYSTERESIS
+	    cl->cmode == HTB_CAN_SEND ? -cl->buffer :
+#endif
+	    0))
+	    return HTB_CAN_SEND;
+
+    *diff = -toks;
+    return HTB_MAY_BORROW;
+}
+
+/**
+ * htb_change_class_mode - changes classe's mode
+ *
+ * This should be the only way how to change classe's mode under normal
+ * cirsumstances. Routine will update feed lists linkage, change mode
+ * and add class to the wait event queue if appropriate. New mode should
+ * be different from old one and cl->pq_key has to be valid if changing
+ * to mode other than HTB_CAN_SEND (see htb_add_to_wait_tree).
+ */
+static void 
+htb_change_class_mode(struct htb_sched *q, struct htb_class *cl, long *diff)
+{ 
+	enum htb_cmode new_mode = htb_class_mode(cl,diff);
+	
+	HTB_CHCL(cl);
+	HTB_DBG(7,1,"htb_chging_clmode %d->%d cl=%X\n",cl->cmode,new_mode,cl->classid);
+
+	if (new_mode == cl->cmode)
+		return;	
+	
+	if (cl->prio_activity) { /* not neccessary: speed optimization */
+		if (cl->cmode != HTB_CANT_SEND) 
+			htb_deactivate_prios(q,cl);
+		cl->cmode = new_mode;
+		if (new_mode != HTB_CANT_SEND) 
+			htb_activate_prios(q,cl);
+	} else 
+		cl->cmode = new_mode;
+}
+
+/**
+ * htb_activate - inserts leaf cl into appropriate active feeds 
+ *
+ * Routine learns (new) priority of leaf and activates feed chain
+ * for the prio. It can be called on already active leaf safely.
+ * It also adds leaf into droplist.
+ */
+static __inline__ void htb_activate(struct htb_sched *q,struct htb_class *cl)
+{
+	BUG_TRAP(!cl->level && cl->un.leaf.q && cl->un.leaf.q->q.qlen);
+	HTB_CHCL(cl);
+	if (!cl->prio_activity) {
+		cl->prio_activity = 1 << (cl->un.leaf.aprio = cl->un.leaf.prio);
+		htb_activate_prios(q,cl);
+		list_add_tail(&cl->un.leaf.drop_list,q->drops+cl->un.leaf.aprio);
+	}
+}
+
+/**
+ * htb_deactivate - remove leaf cl from active feeds 
+ *
+ * Make sure that leaf is active. In the other words it can't be called
+ * with non-active leaf. It also removes class from the drop list.
+ */
+static __inline__ void 
+htb_deactivate(struct htb_sched *q,struct htb_class *cl)
+{
+	BUG_TRAP(cl->prio_activity);
+	HTB_CHCL(cl);
+	htb_deactivate_prios(q,cl);
+	cl->prio_activity = 0;
+	list_del_init(&cl->un.leaf.drop_list);
+}
+
+static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+    struct htb_sched *q = (struct htb_sched *)sch->data;
+    struct htb_class *cl = htb_classify(skb,sch);
+
+    DEVIK_MSTART(0);
+    if (cl == HTB_DIRECT || !cl) {
+	/* enqueue to helper queue */
+	if (q->direct_queue.qlen < q->direct_qlen && cl) {
+	    __skb_queue_tail(&q->direct_queue, skb);
+	    q->direct_pkts++;
+	} else {
+	    kfree_skb (skb);
+	    sch->stats.drops++;
+	    DEVIK_MEND(0);
+	    return NET_XMIT_DROP;
+	}
+    } else if (cl->un.leaf.q->enqueue(skb, cl->un.leaf.q) != NET_XMIT_SUCCESS) {
+	sch->stats.drops++;
+	cl->stats.drops++;
+	DEVIK_MEND(0);
+	return NET_XMIT_DROP;
+    } else {
+	cl->stats.packets++; cl->stats.bytes += skb->len;
+	DEVIK_MSTART(1);
+	htb_activate (q,cl);
+	DEVIK_MEND(1);
+    }
+
+    sch->q.qlen++;
+    sch->stats.packets++; sch->stats.bytes += skb->len;
+    HTB_DBG(1,1,"htb_enq_ok cl=%X skb=%p\n",cl?cl->classid:0,skb);
+    DEVIK_MEND(0);
+    return NET_XMIT_SUCCESS;
+}
+
+/* TODO: requeuing packet charges it to policers again !! */
+static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch)
+{
+    struct htb_sched *q = (struct htb_sched *)sch->data;
+    struct htb_class *cl = htb_classify(skb,sch);
+
+    if (cl == HTB_DIRECT || !cl) {
+	/* enqueue to helper queue */
+	if (q->direct_queue.qlen < q->direct_qlen && cl) {
+	    __skb_queue_tail(&q->direct_queue, skb);
+	    q->direct_pkts++;
+	} else {
+	    kfree_skb (skb);
+	    sch->stats.drops++;
+	    return NET_XMIT_DROP;
+	}
+    } else if (cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q) != NET_XMIT_SUCCESS) {
+	sch->stats.drops++;
+	cl->stats.drops++;
+	return NET_XMIT_DROP;
+    } else 
+	    htb_activate (q,cl);
+
+    sch->q.qlen++;
+    HTB_DBG(1,1,"htb_req_ok cl=%X skb=%p\n",cl?cl->classid:0,skb);
+    return NET_XMIT_SUCCESS;
+}
+
+static void htb_timer(unsigned long arg)
+{
+    struct Qdisc *sch = (struct Qdisc*)arg;
+    sch->flags &= ~TCQ_F_THROTTLED;
+    wmb();
+    netif_schedule(sch->dev);
+}
+
+#ifdef HTB_RATECM
+#define RT_GEN(D,R) R+=D-(R/HTB_EWMAC);D=0
+static void htb_rate_timer(unsigned long arg)
+{
+	struct Qdisc *sch = (struct Qdisc*)arg;
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+	struct list_head *p;
+
+	/* lock queue so that we can muck with it */
+	HTB_QLOCK(sch);
+	HTB_DBG(10,1,"htb_rttmr j=%ld\n",jiffies);
+
+	q->rttim.expires = jiffies + HZ;
+	add_timer(&q->rttim);
+
+	/* scan and recompute one bucket at time */
+	if (++q->recmp_bucket >= HTB_HSIZE) 
+		q->recmp_bucket = 0;
+	list_for_each (p,q->hash+q->recmp_bucket) {
+		struct htb_class *cl = list_entry(p,struct htb_class,hlist);
+		HTB_DBG(10,2,"htb_rttmr_cl cl=%X sbyte=%lu spkt=%lu\n",
+				cl->classid,cl->sum_bytes,cl->sum_packets);
+		RT_GEN (cl->sum_bytes,cl->rate_bytes);
+		RT_GEN (cl->sum_packets,cl->rate_packets);
+	}
+	HTB_QUNLOCK(sch);
+}
+#endif
+
+/**
+ * htb_charge_class - charges ammount "bytes" to leaf and ancestors
+ *
+ * Routine assumes that packet "bytes" long was dequeued from leaf cl
+ * borrowing from "level". It accounts bytes to ceil leaky bucket for
+ * leaf and all ancestors and to rate bucket for ancestors at levels
+ * "level" and higher. It also handles possible change of mode resulting
+ * from the update. Note that mode can also increase here (MAY_BORROW to
+ * CAN_SEND) because we can use more precise clock that event queue here.
+ * In such case we remove class from event queue first.
+ */
+static void htb_charge_class(struct htb_sched *q,struct htb_class *cl,
+		int level,int bytes)
+{	
+	long toks,diff;
+	enum htb_cmode old_mode;
+	HTB_DBG(5,1,"htb_chrg_cl cl=%X lev=%d len=%d\n",cl->classid,level,bytes);
+
+#define HTB_ACCNT(T,B,R) toks = diff + cl->T; \
+	if (toks > cl->B) toks = cl->B; \
+	toks -= L2T(cl, cl->R, bytes); \
+	if (toks <= -cl->mbuffer) toks = 1-cl->mbuffer; \
+	cl->T = toks
+
+	while (cl) {
+		HTB_CHCL(cl);
+		diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32)cl->mbuffer, 0);
+#ifdef HTB_DEBUG
+		if (diff > cl->mbuffer || diff < 0 || PSCHED_TLESS(q->now, cl->t_c)) {
+			if (net_ratelimit())
+				printk(KERN_ERR "HTB: bad diff in charge, cl=%X diff=%lX now=%Lu then=%Lu j=%lu\n",
+				       cl->classid, diff,
+				       (unsigned long long) q->now,
+				       (unsigned long long) cl->t_c,
+				       jiffies);
+			diff = 1000;
+		}
+#endif
+		if (cl->level >= level) {
+			if (cl->level == level) cl->xstats.lends++;
+			HTB_ACCNT (tokens,buffer,rate);
+		} else {
+			cl->xstats.borrows++;
+			cl->tokens += diff; /* we moved t_c; update tokens */
+		}
+		HTB_ACCNT (ctokens,cbuffer,ceil);
+		cl->t_c = q->now;
+		HTB_DBG(5,2,"htb_chrg_clp cl=%X diff=%ld tok=%ld ctok=%ld\n",cl->classid,diff,cl->tokens,cl->ctokens);
+
+		old_mode = cl->cmode; diff = 0;
+		htb_change_class_mode(q,cl,&diff);
+		if (old_mode != cl->cmode) {
+			if (old_mode != HTB_CAN_SEND)
+				htb_safe_rb_erase(&cl->pq_node,q->wait_pq+cl->level);
+			if (cl->cmode != HTB_CAN_SEND)
+				htb_add_to_wait_tree (q,cl,diff,1);
+		}
+		
+#ifdef HTB_RATECM
+		/* update rate counters */
+		cl->sum_bytes += bytes; cl->sum_packets++;
+#endif
+
+		/* update byte stats except for leaves which are already updated */
+		if (cl->level) {
+			cl->stats.bytes += bytes;
+			cl->stats.packets++;
+		}
+		cl = cl->parent;
+	}
+}
+
+/**
+ * htb_do_events - make mode changes to classes at the level
+ *
+ * Scans event queue for pending events and applies them. Returns jiffies to
+ * next pending event (0 for no event in pq).
+ */
+static long htb_do_events(struct htb_sched *q,int level)
+{
+	int i;
+	HTB_DBG(8,1,"htb_do_events l=%d root=%p rmask=%X\n",
+			level,q->wait_pq[level].rb_node,q->row_mask[level]);
+	for (i = 0; i < 500; i++) {
+		struct htb_class *cl;
+		long diff;
+		rb_node_t *p = q->wait_pq[level].rb_node;
+		if (!p) return 0;
+		while (p->rb_left) p = p->rb_left;
+
+		cl = rb_entry(p, struct htb_class, pq_node);
+		if (cl->pq_key - (jiffies+1) < 0x80000000) {
+			HTB_DBG(8,3,"htb_do_ev_ret delay=%ld\n",cl->pq_key - jiffies);
+			return cl->pq_key - jiffies;
+		}
+		htb_safe_rb_erase(p,q->wait_pq+level);
+		diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32)cl->mbuffer, 0);
+#ifdef HTB_DEBUG
+		if (diff > cl->mbuffer || diff < 0 || PSCHED_TLESS(q->now, cl->t_c)) {
+			if (net_ratelimit())
+				printk(KERN_ERR "HTB: bad diff in events, cl=%X diff=%lX now=%Lu then=%Lu j=%lu\n",
+				       cl->classid, diff,
+				       (unsigned long long) q->now,
+				       (unsigned long long) cl->t_c,
+				       jiffies);
+			diff = 1000;
+		}
+#endif
+		htb_change_class_mode(q,cl,&diff);
+		if (cl->cmode != HTB_CAN_SEND)
+			htb_add_to_wait_tree (q,cl,diff,2);
+	}
+	if (net_ratelimit())
+		printk(KERN_WARNING "htb: too many events !\n");
+	return HZ/10;
+}
+
+/**
+ * htb_lookup_leaf - returns next leaf class in DRR order
+ *
+ * Find leaf where current feed pointers points to.
+ */
+static struct htb_class *
+htb_lookup_leaf(rb_root_t *tree,int prio,rb_node_t **pptr)
+{
+	int i;
+	struct {
+		rb_node_t *root;
+		rb_node_t **pptr;
+	} stk[TC_HTB_MAXDEPTH],*sp = stk;
+	
+	sp->root = tree->rb_node;
+	sp->pptr = pptr;
+
+	for (i = 0; i < 65535; i++) {
+		if (!*sp->pptr) { /* we are at right end; rewind & go up */
+			*sp->pptr = sp->root;
+			while ((*sp->pptr)->rb_left) 
+				*sp->pptr = (*sp->pptr)->rb_left;
+			if (sp > stk) {
+				sp--;
+				BUG_TRAP(*sp->pptr); if(!*sp->pptr) return NULL;
+				htb_next_rb_node (sp->pptr);
+			}
+		} else {
+			struct htb_class *cl;
+			cl = rb_entry(*sp->pptr,struct htb_class,node[prio]);
+			HTB_CHCL(cl);
+			if (!cl->level) 
+				return cl;
+			(++sp)->root = cl->un.inner.feed[prio].rb_node;
+			sp->pptr = cl->un.inner.ptr+prio;
+		}
+	}
+	BUG_TRAP(0);
+	return NULL;
+}
+
+/* dequeues packet at given priority and level; call only if
+   you are sure that there is active class at prio/level */
+static struct sk_buff *
+htb_dequeue_tree(struct htb_sched *q,int prio,int level)
+{
+	struct sk_buff *skb = NULL;
+	//struct htb_sched *q = (struct htb_sched *)sch->data;
+	struct htb_class *cl,*start;
+	/* look initial class up in the row */
+	DEVIK_MSTART(6);
+	start = cl = htb_lookup_leaf (q->row[level]+prio,prio,q->ptr[level]+prio);
+	
+	do {
+		BUG_TRAP(cl && cl->un.leaf.q->q.qlen); if (!cl) return NULL;
+		HTB_DBG(4,1,"htb_deq_tr prio=%d lev=%d cl=%X defic=%d\n",
+				prio,level,cl->classid,cl->un.leaf.deficit[level]);
+	
+		if (likely((skb = cl->un.leaf.q->dequeue(cl->un.leaf.q)) != NULL)) 
+			break;
+		if (!cl->warned) {
+			printk(KERN_WARNING "htb: class %X isn't work conserving ?!\n",cl->classid);
+			cl->warned = 1;
+		}
+		q->nwc_hit++;
+		htb_next_rb_node((level?cl->parent->un.inner.ptr:q->ptr[0])+prio);
+		cl = htb_lookup_leaf (q->row[level]+prio,prio,q->ptr[level]+prio);
+	} while (cl != start);
+
+	DEVIK_MEND(6);
+	DEVIK_MSTART(7);
+	if (likely(skb != NULL)) {
+		if ((cl->un.leaf.deficit[level] -= skb->len) < 0) {
+			HTB_DBG(4,2,"htb_next_cl oldptr=%p quant_add=%d\n",
+				level?cl->parent->un.inner.ptr[prio]:q->ptr[0][prio],cl->un.leaf.quantum);
+			cl->un.leaf.deficit[level] += cl->un.leaf.quantum;
+			htb_next_rb_node((level?cl->parent->un.inner.ptr:q->ptr[0])+prio);
+		}
+		/* this used to be after charge_class but this constelation
+		   gives us slightly better performance */
+		if (!cl->un.leaf.q->q.qlen)
+			htb_deactivate (q,cl);
+	DEVIK_MSTART(8);
+		htb_charge_class (q,cl,level,skb->len);
+	DEVIK_MEND(8);
+	}
+	DEVIK_MEND(7);
+	return skb;
+}
+
+static void htb_delay_by(struct Qdisc *sch,long delay)
+{
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+	if (netif_queue_stopped(sch->dev)) return;
+	if (delay <= 0) delay = 1;
+	if (unlikely(delay > 5*HZ)) {
+		if (net_ratelimit())
+			printk(KERN_INFO "HTB delay %ld > 5sec\n", delay);
+		delay = 5*HZ;
+	}
+	del_timer(&q->timer);
+	q->timer.expires = jiffies + delay;
+	add_timer(&q->timer);
+	sch->flags |= TCQ_F_THROTTLED;
+	sch->stats.overlimits++;
+	HTB_DBG(3,1,"htb_deq t_delay=%ld\n",delay);
+}
+
+static struct sk_buff *htb_dequeue(struct Qdisc *sch)
+{
+	struct sk_buff *skb = NULL;
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+	int level;
+	long min_delay;
+
+	HTB_DBG(3,1,"htb_deq dircnt=%d qlen=%d\n",skb_queue_len(&q->direct_queue),
+			sch->q.qlen);
+
+	/* try to dequeue direct packets as high prio (!) to minimize cpu work */
+	if ((skb = __skb_dequeue(&q->direct_queue)) != NULL) {
+		sch->flags &= ~TCQ_F_THROTTLED;
+		sch->q.qlen--;
+		return skb;
+	}
+
+	DEVIK_MSTART(2);
+	if (!sch->q.qlen) goto fin;
+	PSCHED_GET_TIME(q->now);
+
+	min_delay = HZ*5;
+	q->nwc_hit = 0;
+	for (level = 0; level < TC_HTB_MAXDEPTH; level++) {
+		/* common case optimization - skip event handler quickly */
+		int m;
+		long delay;
+	DEVIK_MSTART(3);
+		if (jiffies - q->near_ev_cache[level] < 0x80000000 || 0) {
+			delay = htb_do_events(q,level);
+			q->near_ev_cache[level] += delay ? delay : HZ;
+		} else
+			delay = q->near_ev_cache[level] - jiffies;	
+		
+		if (delay && min_delay > delay) 
+			min_delay = delay;
+	DEVIK_MEND(3);
+	DEVIK_MSTART(5);
+		m = ~q->row_mask[level];
+		while (m != (int)(-1)) {
+			int prio = ffz (m);
+			m |= 1 << prio;
+			skb = htb_dequeue_tree(q,prio,level);
+			if (likely(skb != NULL)) {
+				sch->q.qlen--;
+				sch->flags &= ~TCQ_F_THROTTLED;
+	DEVIK_MEND(5);
+				goto fin;
+			}
+		}
+	DEVIK_MEND(5);
+	}
+	DEVIK_MSTART(4);
+#ifdef HTB_DEBUG
+	if (!q->nwc_hit && min_delay >= 5*HZ && net_ratelimit()) { 
+		printk(KERN_ERR "HTB: mindelay=%ld, report it please !\n",min_delay);
+		htb_debug_dump(q);
+	}
+#endif
+	htb_delay_by (sch,min_delay);
+	DEVIK_MEND(4);
+fin:
+	HTB_DBG(3,1,"htb_deq_end %s j=%lu skb=%p\n",sch->dev->name,jiffies,skb);
+	DEVIK_MEND(2);
+	return skb;
+}
+
+/* try to drop from each class (by prio) until one succeed */
+static int htb_drop(struct Qdisc* sch)
+{
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+	int prio;
+
+	for (prio = TC_HTB_NUMPRIO - 1; prio >= 0; prio--) {
+		struct list_head *p;
+		list_for_each (p,q->drops+prio) {
+			struct htb_class *cl = list_entry(p,struct htb_class,
+					un.leaf.drop_list);
+			if (cl->un.leaf.q->ops->drop && 
+				cl->un.leaf.q->ops->drop(cl->un.leaf.q)) {
+				sch->q.qlen--;
+				if (!cl->un.leaf.q->q.qlen)
+					htb_deactivate (q,cl);
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+/* reset all classes */
+/* always caled under BH & queue lock */
+static void htb_reset(struct Qdisc* sch)
+{
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+	int i;
+	HTB_DBG(0,1,"htb_reset sch=%p, handle=%X\n",sch,sch->handle);
+
+	for (i = 0; i < HTB_HSIZE; i++) {
+		struct list_head *p;
+		list_for_each (p,q->hash+i) {
+			struct htb_class *cl = list_entry(p,struct htb_class,hlist);
+			if (cl->level)
+				memset(&cl->un.inner,0,sizeof(cl->un.inner));
+			else {
+				if (cl->un.leaf.q) 
+					qdisc_reset(cl->un.leaf.q);
+				INIT_LIST_HEAD(&cl->un.leaf.drop_list);
+			}
+			cl->prio_activity = 0;
+			cl->cmode = HTB_CAN_SEND;
+#ifdef HTB_DEBUG
+			cl->pq_node.rb_color = -1;
+			memset(cl->node,255,sizeof(cl->node));
+#endif
+
+		}
+	}
+	sch->flags &= ~TCQ_F_THROTTLED;
+	del_timer(&q->timer);
+	__skb_queue_purge(&q->direct_queue);
+	sch->q.qlen = 0;
+	memset(q->row,0,sizeof(q->row));
+	memset(q->row_mask,0,sizeof(q->row_mask));
+	memset(q->wait_pq,0,sizeof(q->wait_pq));
+	memset(q->ptr,0,sizeof(q->ptr));
+	for (i = 0; i < TC_HTB_NUMPRIO; i++)
+		INIT_LIST_HEAD(q->drops+i);
+}
+
+static int htb_init(struct Qdisc *sch, struct rtattr *opt)
+{
+	struct htb_sched *q = (struct htb_sched*)sch->data;
+	struct rtattr *tb[TCA_HTB_INIT];
+	struct tc_htb_glob *gopt;
+	int i;
+#ifdef HTB_DEBUG
+	printk(KERN_INFO "HTB init, kernel part version %d.%d\n",
+			  HTB_VER >> 16,HTB_VER & 0xffff);
+#endif
+	if (!opt || rtattr_parse(tb, TCA_HTB_INIT, RTA_DATA(opt), RTA_PAYLOAD(opt)) ||
+			tb[TCA_HTB_INIT-1] == NULL ||
+			RTA_PAYLOAD(tb[TCA_HTB_INIT-1]) < sizeof(*gopt)) {
+		printk(KERN_ERR "HTB: hey probably you have bad tc tool ?\n");
+		return -EINVAL;
+	}
+	gopt = RTA_DATA(tb[TCA_HTB_INIT-1]);
+	if (gopt->version != HTB_VER >> 16) {
+		printk(KERN_ERR "HTB: need tc/htb version %d (minor is %d), you have %d\n",
+				HTB_VER >> 16,HTB_VER & 0xffff,gopt->version);
+		return -EINVAL;
+	}
+	memset(q,0,sizeof(*q));
+	q->debug = gopt->debug;
+	HTB_DBG(0,1,"htb_init sch=%p handle=%X r2q=%d\n",sch,sch->handle,gopt->rate2quantum);
+
+	INIT_LIST_HEAD(&q->root);
+	for (i = 0; i < HTB_HSIZE; i++)
+		INIT_LIST_HEAD(q->hash+i);
+	for (i = 0; i < TC_HTB_NUMPRIO; i++)
+		INIT_LIST_HEAD(q->drops+i);
+
+	init_timer(&q->timer);
+	skb_queue_head_init(&q->direct_queue);
+
+	q->direct_qlen = sch->dev->tx_queue_len;
+	if (q->direct_qlen < 2) /* some devices have zero tx_queue_len */
+		q->direct_qlen = 2;
+	q->timer.function = htb_timer;
+	q->timer.data = (unsigned long)sch;
+
+#ifdef HTB_RATECM
+	init_timer(&q->rttim);
+	q->rttim.function = htb_rate_timer;
+	q->rttim.data = (unsigned long)sch;
+	q->rttim.expires = jiffies + HZ;
+	add_timer(&q->rttim);
+#endif
+	if ((q->rate2quantum = gopt->rate2quantum) < 1)
+		q->rate2quantum = 1;
+	q->defcls = gopt->defcls;
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int htb_dump(struct Qdisc *sch, struct sk_buff *skb)
+{
+	struct htb_sched *q = (struct htb_sched*)sch->data;
+	unsigned char	 *b = skb->tail;
+	struct rtattr *rta;
+	struct tc_htb_glob gopt;
+	HTB_DBG(0,1,"htb_dump sch=%p, handle=%X\n",sch,sch->handle);
+	/* stats */
+	HTB_QLOCK(sch);
+	gopt.direct_pkts = q->direct_pkts;
+
+#ifdef HTB_DEBUG
+	htb_debug_dump(q);
+#endif
+	gopt.version = HTB_VER;
+	gopt.rate2quantum = q->rate2quantum;
+	gopt.defcls = q->defcls;
+	gopt.debug = q->debug;
+	rta = (struct rtattr*)b;
+	RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
+	RTA_PUT(skb, TCA_HTB_INIT, sizeof(gopt), &gopt);
+	rta->rta_len = skb->tail - b;
+	sch->stats.qlen = sch->q.qlen;
+	RTA_PUT(skb, TCA_STATS, sizeof(sch->stats), &sch->stats);
+	HTB_QUNLOCK(sch);
+	return skb->len;
+rtattr_failure:
+	HTB_QUNLOCK(sch);
+	skb_trim(skb, skb->tail - skb->data);
+	return -1;
+}
+
+static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
+	struct sk_buff *skb, struct tcmsg *tcm)
+{
+#ifdef HTB_DEBUG
+	struct htb_sched *q = (struct htb_sched*)sch->data;
+#endif
+	struct htb_class *cl = (struct htb_class*)arg;
+	unsigned char	 *b = skb->tail;
+	struct rtattr *rta;
+	struct tc_htb_opt opt;
+
+	HTB_DBG(0,1,"htb_dump_class handle=%X clid=%X\n",sch->handle,cl->classid);
+
+	HTB_QLOCK(sch);
+	tcm->tcm_parent = cl->parent ? cl->parent->classid : TC_H_ROOT;
+	tcm->tcm_handle = cl->classid;
+	if (!cl->level && cl->un.leaf.q) {
+		tcm->tcm_info = cl->un.leaf.q->handle;
+		cl->stats.qlen = cl->un.leaf.q->q.qlen;
+	}
+
+	rta = (struct rtattr*)b;
+	RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
+
+	memset (&opt,0,sizeof(opt));
+
+	opt.rate = cl->rate->rate; opt.buffer = cl->buffer;
+	opt.ceil = cl->ceil->rate; opt.cbuffer = cl->cbuffer;
+	opt.quantum = cl->un.leaf.quantum; opt.prio = cl->un.leaf.prio;
+	opt.level = cl->level; 
+	RTA_PUT(skb, TCA_HTB_PARMS, sizeof(opt), &opt);
+	rta->rta_len = skb->tail - b;
+
+#ifdef HTB_RATECM
+	cl->stats.bps = cl->rate_bytes/(HTB_EWMAC*HTB_HSIZE);
+	cl->stats.pps = cl->rate_packets/(HTB_EWMAC*HTB_HSIZE);
+#endif
+
+	cl->xstats.tokens = cl->tokens;
+	cl->xstats.ctokens = cl->ctokens;
+	RTA_PUT(skb, TCA_STATS, sizeof(cl->stats), &cl->stats);
+	RTA_PUT(skb, TCA_XSTATS, sizeof(cl->xstats), &cl->xstats);
+	HTB_QUNLOCK(sch);
+	return skb->len;
+rtattr_failure:
+	HTB_QUNLOCK(sch);
+	skb_trim(skb, b - skb->data);
+	return -1;
+}
+
+static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
+	struct Qdisc **old)
+{
+	struct htb_class *cl = (struct htb_class*)arg;
+
+	if (cl && !cl->level) {
+		if (new == NULL && (new = qdisc_create_dflt(sch->dev, 
+					&pfifo_qdisc_ops)) == NULL)
+					return -ENOBUFS;
+		sch_tree_lock(sch);
+		if ((*old = xchg(&cl->un.leaf.q, new)) != NULL) {
+			/* TODO: is it correct ? Why CBQ doesn't do it ? */
+			sch->q.qlen -= (*old)->q.qlen;	
+			qdisc_reset(*old);
+		}
+		sch_tree_unlock(sch);
+		return 0;
+	}
+	return -ENOENT;
+}
+
+static struct Qdisc * htb_leaf(struct Qdisc *sch, unsigned long arg)
+{
+	struct htb_class *cl = (struct htb_class*)arg;
+	return (cl && !cl->level) ? cl->un.leaf.q : NULL;
+}
+
+static unsigned long htb_get(struct Qdisc *sch, u32 classid)
+{
+#ifdef HTB_DEBUG
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+#endif
+	struct htb_class *cl = htb_find(classid,sch);
+	HTB_DBG(0,1,"htb_get clid=%X q=%p cl=%p ref=%d\n",classid,q,cl,cl?cl->refcnt:0);
+	if (cl) 
+		cl->refcnt++;
+	return (unsigned long)cl;
+}
+
+static void htb_destroy_filters(struct tcf_proto **fl)
+{
+	struct tcf_proto *tp;
+
+	while ((tp = *fl) != NULL) {
+		*fl = tp->next;
+		tp->ops->destroy(tp);
+	}
+}
+
+static void htb_destroy_class(struct Qdisc* sch,struct htb_class *cl)
+{
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+	HTB_DBG(0,1,"htb_destrycls clid=%X ref=%d\n", cl?cl->classid:0,cl?cl->refcnt:0);
+	if (!cl->level) {
+		BUG_TRAP(cl->un.leaf.q);
+		sch->q.qlen -= cl->un.leaf.q->q.qlen;
+		qdisc_destroy(cl->un.leaf.q);
+	}
+	qdisc_put_rtab(cl->rate);
+	qdisc_put_rtab(cl->ceil);
+	
+#ifdef CONFIG_NET_ESTIMATOR
+	qdisc_kill_estimator(&cl->stats);
+#endif
+	htb_destroy_filters (&cl->filter_list);
+	
+	while (!list_empty(&cl->children)) 
+		htb_destroy_class (sch,list_entry(cl->children.next,
+					struct htb_class,sibling));
+
+	/* note: this delete may happen twice (see htb_delete) */
+	list_del(&cl->hlist);
+	list_del(&cl->sibling);
+	
+	if (cl->prio_activity)
+		htb_deactivate (q,cl);
+	
+	if (cl->cmode != HTB_CAN_SEND)
+		htb_safe_rb_erase(&cl->pq_node,q->wait_pq+cl->level);
+	
+	kfree(cl);
+}
+
+/* always caled under BH & queue lock */
+static void htb_destroy(struct Qdisc* sch)
+{
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+	HTB_DBG(0,1,"htb_destroy q=%p\n",q);
+
+	del_timer_sync (&q->timer);
+#ifdef HTB_RATECM
+	del_timer_sync (&q->rttim);
+#endif
+	while (!list_empty(&q->root)) 
+		htb_destroy_class (sch,list_entry(q->root.next,
+					struct htb_class,sibling));
+
+	htb_destroy_filters(&q->filter_list);
+	__skb_queue_purge(&q->direct_queue);
+	MOD_DEC_USE_COUNT;
+}
+
+static int htb_delete(struct Qdisc *sch, unsigned long arg)
+{
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+	struct htb_class *cl = (struct htb_class*)arg;
+	HTB_DBG(0,1,"htb_delete q=%p cl=%X ref=%d\n",q,cl?cl->classid:0,cl?cl->refcnt:0);
+
+	// TODO: why don't allow to delete subtree ? references ? does
+	// tc subsys quarantee us that in htb_destroy it holds no class
+	// refs so that we can remove children safely there ?
+	if (!list_empty(&cl->children) || cl->filter_cnt)
+		return -EBUSY;
+	
+	sch_tree_lock(sch);
+	
+	/* delete from hash and active; remainder in destroy_class */
+	list_del_init(&cl->hlist);
+	if (cl->prio_activity)
+		htb_deactivate (q,cl);
+
+	if (--cl->refcnt == 0)
+		htb_destroy_class(sch,cl);
+
+	sch_tree_unlock(sch);
+	return 0;
+}
+
+static void htb_put(struct Qdisc *sch, unsigned long arg)
+{
+#ifdef HTB_DEBUG
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+#endif
+	struct htb_class *cl = (struct htb_class*)arg;
+	HTB_DBG(0,1,"htb_put q=%p cl=%X ref=%d\n",q,cl?cl->classid:0,cl?cl->refcnt:0);
+
+	if (--cl->refcnt == 0)
+		htb_destroy_class(sch,cl);
+}
+
+static int htb_change_class(struct Qdisc *sch, u32 classid, 
+		u32 parentid, struct rtattr **tca, unsigned long *arg)
+{
+	int err = -EINVAL;
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+	struct htb_class *cl = (struct htb_class*)*arg,*parent;
+	struct rtattr *opt = tca[TCA_OPTIONS-1];
+	struct qdisc_rate_table *rtab = NULL, *ctab = NULL;
+	struct rtattr *tb[TCA_HTB_RTAB];
+	struct tc_htb_opt *hopt;
+
+	/* extract all subattrs from opt attr */
+	if (!opt || rtattr_parse(tb, TCA_HTB_RTAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) ||
+			tb[TCA_HTB_PARMS-1] == NULL ||
+			RTA_PAYLOAD(tb[TCA_HTB_PARMS-1]) < sizeof(*hopt))
+		goto failure;
+	
+	parent = parentid == TC_H_ROOT ? NULL : htb_find (parentid,sch);
+
+	hopt = RTA_DATA(tb[TCA_HTB_PARMS-1]);
+	HTB_DBG(0,1,"htb_chg cl=%p, clid=%X, opt/prio=%d, rate=%u, buff=%d, quant=%d\n", cl,cl?cl->classid:0,(int)hopt->prio,hopt->rate.rate,hopt->buffer,hopt->quantum);
+	rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB-1]);
+	ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB-1]);
+	if (!rtab || !ctab) goto failure;
+
+	if (!cl) { /* new class */
+		/* check for valid classid */
+		if (!classid || TC_H_MAJ(classid^sch->handle) || htb_find(classid,sch))
+			goto failure;
+
+		/* check maximal depth */
+		if (parent && parent->parent && parent->parent->level < 2) {
+			printk(KERN_ERR "htb: tree is too deep\n");
+			goto failure;
+		}
+		err = -ENOBUFS;
+		if ((cl = kmalloc(sizeof(*cl), GFP_KERNEL)) == NULL)
+			goto failure;
+		
+		memset(cl, 0, sizeof(*cl));
+		cl->refcnt = 1;
+		INIT_LIST_HEAD(&cl->sibling);
+		INIT_LIST_HEAD(&cl->hlist);
+		INIT_LIST_HEAD(&cl->children);
+		INIT_LIST_HEAD(&cl->un.leaf.drop_list);
+#ifdef HTB_DEBUG
+		cl->magic = HTB_CMAGIC;
+#endif
+
+		sch_tree_lock(sch);
+		if (parent && !parent->level) {
+			/* turn parent into inner node */
+			sch->q.qlen -= parent->un.leaf.q->q.qlen;
+			qdisc_destroy (parent->un.leaf.q);
+			if (parent->prio_activity) 
+				htb_deactivate (q,parent);
+
+			/* remove from evt list because of level change */
+			if (parent->cmode != HTB_CAN_SEND) {
+				htb_safe_rb_erase(&parent->pq_node,q->wait_pq /*+0*/);
+				parent->cmode = HTB_CAN_SEND;
+			}
+			parent->level = (parent->parent ? parent->parent->level
+					: TC_HTB_MAXDEPTH) - 1;
+			memset (&parent->un.inner,0,sizeof(parent->un.inner));
+		}
+		/* leaf (we) needs elementary qdisc */
+		if (!(cl->un.leaf.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops)))
+			cl->un.leaf.q = &noop_qdisc;
+
+		cl->classid = classid; cl->parent = parent;
+
+		/* set class to be in HTB_CAN_SEND state */
+		cl->tokens = hopt->buffer;
+		cl->ctokens = hopt->cbuffer;
+		cl->mbuffer = 60000000; /* 1min */
+		PSCHED_GET_TIME(cl->t_c);
+		cl->cmode = HTB_CAN_SEND;
+
+		/* attach to the hash list and parent's family */
+		list_add_tail(&cl->hlist, q->hash+htb_hash(classid));
+		list_add_tail(&cl->sibling, parent ? &parent->children : &q->root);
+#ifdef HTB_DEBUG
+		{ 
+			int i;
+			for (i = 0; i < TC_HTB_NUMPRIO; i++) cl->node[i].rb_color = -1;
+			cl->pq_node.rb_color = -1;
+		}
+#endif
+	} else sch_tree_lock(sch);
+
+	/* it used to be a nasty bug here, we have to check that node
+           is really leaf before changing cl->un.leaf ! */
+	if (!cl->level) {
+		cl->un.leaf.quantum = rtab->rate.rate / q->rate2quantum;
+		if (!hopt->quantum && cl->un.leaf.quantum < 1000) {
+			printk(KERN_WARNING "HTB: quantum of class %X is small. Consider r2q change.", cl->classid);
+			cl->un.leaf.quantum = 1000;
+		}
+		if (!hopt->quantum && cl->un.leaf.quantum > 200000) {
+			printk(KERN_WARNING "HTB: quantum of class %X is big. Consider r2q change.", cl->classid);
+			cl->un.leaf.quantum = 200000;
+		}
+		if (hopt->quantum)
+			cl->un.leaf.quantum = hopt->quantum;
+		if ((cl->un.leaf.prio = hopt->prio) >= TC_HTB_NUMPRIO)
+			cl->un.leaf.prio = TC_HTB_NUMPRIO - 1;
+	}
+
+	cl->buffer = hopt->buffer;
+	cl->cbuffer = hopt->cbuffer;
+	if (cl->rate) qdisc_put_rtab(cl->rate); cl->rate = rtab;
+	if (cl->ceil) qdisc_put_rtab(cl->ceil); cl->ceil = ctab;
+	sch_tree_unlock(sch);
+
+	*arg = (unsigned long)cl;
+	return 0;
+
+failure:
+	if (rtab) qdisc_put_rtab(rtab);
+	if (ctab) qdisc_put_rtab(ctab);
+	return err;
+}
+
+static struct tcf_proto **htb_find_tcf(struct Qdisc *sch, unsigned long arg)
+{
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+	struct htb_class *cl = (struct htb_class *)arg;
+	struct tcf_proto **fl = cl ? &cl->filter_list : &q->filter_list;
+	HTB_DBG(0,2,"htb_tcf q=%p clid=%X fref=%d fl=%p\n",q,cl?cl->classid:0,cl?cl->filter_cnt:q->filter_cnt,*fl);
+	return fl;
+}
+
+static unsigned long htb_bind_filter(struct Qdisc *sch, unsigned long parent,
+	u32 classid)
+{
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+	struct htb_class *cl = htb_find (classid,sch);
+	HTB_DBG(0,2,"htb_bind q=%p clid=%X cl=%p fref=%d\n",q,classid,cl,cl?cl->filter_cnt:q->filter_cnt);
+	/*if (cl && !cl->level) return 0;
+	  The line above used to be there to prevent attaching filters to 
+	  leaves. But at least tc_index filter uses this just to get class 
+	  for other reasons so that we have to allow for it.
+	  ----
+	  19.6.2002 As Werner explained it is ok - bind filter is just
+	  another way to "lock" the class - unlike "get" this lock can
+	  be broken by class during destroy IIUC.
+	 */
+	if (cl) 
+		cl->filter_cnt++; 
+	else 
+		q->filter_cnt++;
+	return (unsigned long)cl;
+}
+
+static void htb_unbind_filter(struct Qdisc *sch, unsigned long arg)
+{
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+	struct htb_class *cl = (struct htb_class *)arg;
+	HTB_DBG(0,2,"htb_unbind q=%p cl=%p fref=%d\n",q,cl,cl?cl->filter_cnt:q->filter_cnt);
+	if (cl) 
+		cl->filter_cnt--; 
+	else 
+		q->filter_cnt--;
+}
+
+static void htb_walk(struct Qdisc *sch, struct qdisc_walker *arg)
+{
+	struct htb_sched *q = (struct htb_sched *)sch->data;
+	int i;
+
+	if (arg->stop)
+		return;
+
+	for (i = 0; i < HTB_HSIZE; i++) {
+		struct list_head *p;
+		list_for_each (p,q->hash+i) {
+			struct htb_class *cl = list_entry(p,struct htb_class,hlist);
+			if (arg->count < arg->skip) {
+				arg->count++;
+				continue;
+			}
+			if (arg->fn(sch, (unsigned long)cl, arg) < 0) {
+				arg->stop = 1;
+				return;
+			}
+			arg->count++;
+		}
+	}
+}
+
+static struct Qdisc_class_ops htb_class_ops =
+{
+    htb_graft,
+    htb_leaf,
+    htb_get,
+    htb_put,
+    htb_change_class,
+    htb_delete,
+    htb_walk,
+
+    htb_find_tcf,
+    htb_bind_filter,
+    htb_unbind_filter,
+
+    htb_dump_class,
+};
+
+struct Qdisc_ops htb_qdisc_ops =
+{
+    NULL,
+    &htb_class_ops,
+    "htb",
+    sizeof(struct htb_sched),
+
+    htb_enqueue,
+    htb_dequeue,
+    htb_requeue,
+    htb_drop,
+
+    htb_init,
+    htb_reset,
+    htb_destroy,
+    NULL /* htb_change */,
+
+    htb_dump,
+};
+
+#ifdef MODULE
+int init_module(void)
+{
+    return register_qdisc(&htb_qdisc_ops);
+}
+
+void cleanup_module(void) 
+{
+    unregister_qdisc(&htb_qdisc_ops);
+}
+MODULE_LICENSE("GPL");
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/sched/sch_ingress.c linux-2.4.20/net/sched/sch_ingress.c
--- linux-2.4.19/net/sched/sch_ingress.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/sched/sch_ingress.c	2002-10-29 11:18:34.000000000 +0000
@@ -106,7 +106,7 @@
 #endif
 	DPRINTK("ingress_change(sch %p,[qdisc %p],classid %x,parent %x),"
 		"arg 0x%lx\n", sch, p, classid, parent, *arg);
-	DPRINTK("No effect. sch_ingress doesnt maintain classes at the moment");
+	DPRINTK("No effect. sch_ingress doesn't maintain classes at the moment");
 	return 0;
 }
 
@@ -118,7 +118,7 @@
 	struct ingress_qdisc_data *p = PRIV(sch);
 #endif
 	DPRINTK("ingress_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker);
-	DPRINTK("No effect. sch_ingress doesnt maintain classes at the moment");
+	DPRINTK("No effect. sch_ingress doesn't maintain classes at the moment");
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/socket.c linux-2.4.20/net/socket.c
--- linux-2.4.19/net/socket.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/socket.c	2002-10-29 11:18:37.000000000 +0000
@@ -147,8 +147,7 @@
 	while (atomic_read(&net_family_lockct) != 0) {
 		spin_unlock(&net_family_lock);
 
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 
 		spin_lock(&net_family_lock);
 	}
@@ -743,11 +742,13 @@
 			return -ENOMEM;
 	}
 
-
 	sock = socki_lookup(filp->f_dentry->d_inode);
 	
-	if ((sk=sock->sk) == NULL)
+	if ((sk=sock->sk) == NULL) {
+		if (fna)
+			kfree(fna);
 		return -EINVAL;
+	}
 
 	lock_sock(sk);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/sunrpc/Makefile linux-2.4.20/net/sunrpc/Makefile
--- linux-2.4.19/net/sunrpc/Makefile	2000-12-29 22:07:24.000000000 +0000
+++ linux-2.4.20/net/sunrpc/Makefile	2002-10-29 11:18:32.000000000 +0000
@@ -14,7 +14,7 @@
 obj-y    := clnt.o xprt.o sched.o \
 	    auth.o auth_null.o auth_unix.o \
 	    svc.o svcsock.o svcauth.o \
-	    pmap_clnt.o xdr.o sunrpc_syms.o
+	    pmap_clnt.o timer.o xdr.o sunrpc_syms.o
 
 obj-$(CONFIG_PROC_FS) += stats.o
 obj-$(CONFIG_SYSCTL) += sysctl.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/sunrpc/clnt.c linux-2.4.20/net/sunrpc/clnt.c
--- linux-2.4.19/net/sunrpc/clnt.c	2001-09-21 18:24:50.000000000 +0000
+++ linux-2.4.20/net/sunrpc/clnt.c	2002-10-29 11:18:38.000000000 +0000
@@ -78,10 +78,6 @@
 	dprintk("RPC: creating %s client for %s (xprt %p)\n",
 		program->name, servname, xprt);
 
-#ifdef RPC_DEBUG
-	rpc_register_sysctl();
-#endif
-
 	if (!xprt)
 		goto out;
 	if (vers >= program->nrvers || !(version = program->version[vers]))
@@ -103,11 +99,13 @@
 	clnt->cl_vers     = version->number;
 	clnt->cl_prot     = xprt->prot;
 	clnt->cl_stats    = program->stats;
-	clnt->cl_bindwait = RPC_INIT_WAITQ("bindwait");
+	INIT_RPC_WAITQ(&clnt->cl_bindwait, "bindwait");
 
 	if (!clnt->cl_port)
 		clnt->cl_autobind = 1;
 
+	rpc_init_rtt(&clnt->cl_rtt, xprt->timeout.to_initval);
+
 	if (!rpcauth_create(flavor, clnt))
 		goto out_no_auth;
 
@@ -337,6 +335,20 @@
 		rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
 }
 
+void
+rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize)
+{
+	struct rpc_xprt *xprt = clnt->cl_xprt;
+
+	xprt->sndsize = 0;
+	if (sndsize)
+		xprt->sndsize = sndsize + RPC_SLACK_SPACE;
+	xprt->rcvsize = 0;
+	if (rcvsize)
+		xprt->rcvsize = rcvsize + RPC_SLACK_SPACE;
+	xprt_sock_setbufsize(xprt);
+}
+
 /*
  * Restart an (async) RPC call. Usually called from within the
  * exit handler.
@@ -465,6 +477,8 @@
 {
 	struct rpc_clnt	*clnt = task->tk_client;
 	struct rpc_rqst	*req = task->tk_rqstp;
+	struct xdr_buf *sndbuf = &req->rq_snd_buf;
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 	unsigned int	bufsiz;
 	kxdrproc_t	encode;
 	int		status;
@@ -477,14 +491,16 @@
 
 	/* Default buffer setup */
 	bufsiz = rpcproc_bufsiz(clnt, task->tk_msg.rpc_proc)+RPC_SLACK_SPACE;
-	req->rq_svec[0].iov_base = (void *)task->tk_buffer;
-	req->rq_svec[0].iov_len  = bufsiz;
-	req->rq_slen		 = 0;
-	req->rq_snr		 = 1;
-	req->rq_rvec[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz);
-	req->rq_rvec[0].iov_len  = bufsiz;
-	req->rq_rlen		 = bufsiz;
-	req->rq_rnr		 = 1;
+	sndbuf->head[0].iov_base = (void *)task->tk_buffer;
+	sndbuf->head[0].iov_len  = bufsiz;
+	sndbuf->tail[0].iov_len  = 0;
+	sndbuf->page_len	 = 0;
+	sndbuf->len		 = 0;
+	rcvbuf->head[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz);
+	rcvbuf->head[0].iov_len  = bufsiz;
+	rcvbuf->tail[0].iov_len  = 0;
+	rcvbuf->page_len	 = 0;
+	rcvbuf->len		 = bufsiz;
 
 	/* Zero buffer so we have automatic zero-padding of opaque & string */
 	memset(task->tk_buffer, 0, bufsiz);
@@ -575,7 +591,7 @@
 	if (task->tk_status < 0)
 		return;
 	xprt_transmit(task);
-	if (!rpcproc_decode(clnt, task->tk_msg.rpc_proc)) {
+	if (!rpcproc_decode(clnt, task->tk_msg.rpc_proc) && task->tk_status >= 0) {
 		task->tk_action = NULL;
 		rpc_wake_up_task(task);
 	}
@@ -589,19 +605,22 @@
 {
 	struct rpc_clnt	*clnt = task->tk_client;
 	struct rpc_xprt *xprt = clnt->cl_xprt;
-	struct rpc_rqst	*req;
-	int		status = task->tk_status;
+	struct rpc_rqst	*req = task->tk_rqstp;
+	int		status;
+
+	if (req->rq_received != 0)
+		task->tk_status = req->rq_received;
 
 	dprintk("RPC: %4d call_status (status %d)\n", 
 				task->tk_pid, task->tk_status);
 
+	status = task->tk_status;
 	if (status >= 0) {
 		task->tk_action = call_decode;
 		return;
 	}
 
 	task->tk_status = 0;
-	req = task->tk_rqstp;
 	switch(status) {
 	case -ETIMEDOUT:
 		task->tk_action = call_timeout;
@@ -666,7 +685,7 @@
 		rpc_exit(task, -EIO);
 		return;
 	}
-	if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN)) {
+	if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN) && rpc_ntimeo(&clnt->cl_rtt) > 7) {
 		task->tk_flags |= RPC_CALL_MAJORSEEN;
 		if (req)
 			printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/sunrpc/sched.c linux-2.4.20/net/sunrpc/sched.c
--- linux-2.4.19/net/sunrpc/sched.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/sunrpc/sched.c	2002-10-29 11:18:48.000000000 +0000
@@ -41,23 +41,23 @@
  * handler, or while executing another RPC task, it is put on
  * schedq, and rpciod is woken up.
  */
-static struct rpc_wait_queue	schedq = RPC_INIT_WAITQ("schedq");
+static RPC_WAITQ(schedq, "schedq");
 
 /*
  * RPC tasks that create another task (e.g. for contacting the portmapper)
  * will wait on this queue for their child's completion
  */
-static struct rpc_wait_queue	childq = RPC_INIT_WAITQ("childq");
+static RPC_WAITQ(childq, "childq");
 
 /*
  * RPC tasks sit here while waiting for conditions to improve.
  */
-static struct rpc_wait_queue	delay_queue = RPC_INIT_WAITQ("delayq");
+static RPC_WAITQ(delay_queue, "delayq");
 
 /*
  * All RPC tasks are linked into this list
  */
-static struct rpc_task *	all_tasks;
+static LIST_HEAD(all_tasks);
 
 /*
  * rpciod-related stuff
@@ -73,7 +73,7 @@
  * Spinlock for wait queues. Access to the latter also has to be
  * interrupt-safe in order to allow timers to wake up sleeping tasks.
  */
-spinlock_t rpc_queue_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t rpc_queue_lock = SPIN_LOCK_UNLOCKED;
 /*
  * Spinlock for other critical sections of code.
  */
@@ -157,7 +157,7 @@
 void rpc_add_timer(struct rpc_task *task, rpc_action timer)
 {
 	spin_lock_bh(&rpc_queue_lock);
-	if (!(RPC_IS_RUNNING(task) || task->tk_wakeup))
+	if (!RPC_IS_RUNNING(task))
 		__rpc_add_timer(task, timer);
 	spin_unlock_bh(&rpc_queue_lock);
 }
@@ -194,9 +194,9 @@
 		return -EWOULDBLOCK;
 	}
 	if (RPC_IS_SWAPPER(task))
-		rpc_insert_list(&queue->task, task);
+		list_add(&task->tk_list, &queue->tasks);
 	else
-		rpc_append_list(&queue->task, task);
+		list_add_tail(&task->tk_list, &queue->tasks);
 	task->tk_rpcwait = queue;
 
 	dprintk("RPC: %4d added to queue %p \"%s\"\n",
@@ -228,7 +228,7 @@
 	if (!queue)
 		return;
 
-	rpc_remove_list(&queue->task, task);
+	list_del(&task->tk_list);
 	task->tk_rpcwait = NULL;
 
 	dprintk("RPC: %4d removed from queue %p \"%s\"\n",
@@ -358,27 +358,10 @@
 	spin_unlock_bh(&rpc_queue_lock);
 }
 
-void
-rpc_sleep_locked(struct rpc_wait_queue *q, struct rpc_task *task,
-		 rpc_action action, rpc_action timer)
-{
-	/*
-	 * Protect the queue operations.
-	 */
-	spin_lock_bh(&rpc_queue_lock);
-	__rpc_sleep_on(q, task, action, timer);
-	__rpc_lock_task(task);
-	spin_unlock_bh(&rpc_queue_lock);
-}
-
 /**
  * __rpc_wake_up_task - wake up a single rpc_task
  * @task: task to be woken up
  *
- * If the task is locked, it is merely removed from the queue, and
- * 'task->tk_wakeup' is set. rpc_unlock_task() will then ensure
- * that it is woken up as soon as the lock count goes to zero.
- *
  * Caller must hold rpc_queue_lock
  */
 static void
@@ -407,14 +390,6 @@
 	if (task->tk_rpcwait != &schedq)
 		__rpc_remove_wait_queue(task);
 
-	/* If the task has been locked, then set tk_wakeup so that
-	 * rpc_unlock_task() wakes us up... */
-	if (task->tk_lock) {
-		task->tk_wakeup = 1;
-		return;
-	} else
-		task->tk_wakeup = 0;
-
 	rpc_make_runnable(task);
 
 	dprintk("RPC:      __rpc_wake_up_task done\n");
@@ -450,11 +425,11 @@
 struct rpc_task *
 rpc_wake_up_next(struct rpc_wait_queue *queue)
 {
-	struct rpc_task	*task;
+	struct rpc_task	*task = NULL;
 
 	dprintk("RPC:      wake_up_next(%p \"%s\")\n", queue, rpc_qname(queue));
 	spin_lock_bh(&rpc_queue_lock);
-	if ((task = queue->task) != 0)
+	task_for_first(task, &queue->tasks)
 		__rpc_wake_up_task(task);
 	spin_unlock_bh(&rpc_queue_lock);
 
@@ -470,9 +445,12 @@
 void
 rpc_wake_up(struct rpc_wait_queue *queue)
 {
+	struct rpc_task *task;
+
 	spin_lock_bh(&rpc_queue_lock);
-	while (queue->task)
-		__rpc_wake_up_task(queue->task);
+	while (!list_empty(&queue->tasks))
+		task_for_first(task, &queue->tasks)
+			__rpc_wake_up_task(task);
 	spin_unlock_bh(&rpc_queue_lock);
 }
 
@@ -486,41 +464,19 @@
 void
 rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
 {
-	struct rpc_task	*task;
+	struct rpc_task *task;
 
 	spin_lock_bh(&rpc_queue_lock);
-	while ((task = queue->task) != NULL) {
-		task->tk_status = status;
-		__rpc_wake_up_task(task);
+	while (!list_empty(&queue->tasks)) {
+		task_for_first(task, &queue->tasks) {
+			task->tk_status = status;
+			__rpc_wake_up_task(task);
+		}
 	}
 	spin_unlock_bh(&rpc_queue_lock);
 }
 
 /*
- * Lock down a sleeping task to prevent it from waking up
- * and disappearing from beneath us.
- *
- * This function should always be called with the
- * rpc_queue_lock held.
- */
-int
-__rpc_lock_task(struct rpc_task *task)
-{
-	if (!RPC_IS_RUNNING(task))
-		return ++task->tk_lock;
-	return 0;
-}
-
-void
-rpc_unlock_task(struct rpc_task *task)
-{
-	spin_lock_bh(&rpc_queue_lock);
-	if (task->tk_lock && !--task->tk_lock && task->tk_wakeup)
-		__rpc_wake_up_task(task);
-	spin_unlock_bh(&rpc_queue_lock);
-}
-
-/*
  * Run a task at a later time
  */
 static void	__rpc_atrun(struct rpc_task *);
@@ -700,23 +656,16 @@
 	dprintk("RPC:      rpc_schedule enter\n");
 	while (1) {
 		spin_lock_bh(&rpc_queue_lock);
-		if (!(task = schedq.task)) {
+
+		task_for_first(task, &schedq.tasks) {
+			__rpc_remove_wait_queue(task);
 			spin_unlock_bh(&rpc_queue_lock);
-			break;
-		}
-		if (task->tk_lock) {
+
+			__rpc_execute(task);
+		} else {
 			spin_unlock_bh(&rpc_queue_lock);
-			printk(KERN_ERR "RPC: Locked task was scheduled !!!!\n");
-#ifdef RPC_DEBUG			
-			rpc_debug = ~0;
-			rpc_show_tasks();
-#endif			
 			break;
 		}
-		__rpc_remove_wait_queue(task);
-		spin_unlock_bh(&rpc_queue_lock);
-
-		__rpc_execute(task);
 
 		if (++count >= 200 || current->need_resched) {
 			count = 0;
@@ -770,8 +719,7 @@
 		}
 		if (flags & RPC_TASK_ASYNC)
 			return NULL;
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 	} while (!signalled());
 
 	return NULL;
@@ -812,11 +760,7 @@
 
 	/* Add to global list of all tasks */
 	spin_lock(&rpc_sched_lock);
-	task->tk_next_task = all_tasks;
-	task->tk_prev_task = NULL;
-	if (all_tasks)
-		all_tasks->tk_prev_task = task;
-	all_tasks = task;
+	list_add(&task->tk_task, &all_tasks);
 	spin_unlock(&rpc_sched_lock);
 
 	if (clnt)
@@ -875,8 +819,6 @@
 void
 rpc_release_task(struct rpc_task *task)
 {
-	struct rpc_task	*next, *prev;
-
 	dprintk("RPC: %4d release task\n", task->tk_pid);
 
 #ifdef RPC_DEBUG
@@ -890,15 +832,7 @@
 
 	/* Remove from global task list */
 	spin_lock(&rpc_sched_lock);
-	prev = task->tk_prev_task;
-	next = task->tk_next_task;
-	if (next)
-		next->tk_prev_task = prev;
-	if (prev)
-		prev->tk_next_task = next;
-	else
-		all_tasks = next;
-	task->tk_next_task = task->tk_prev_task = NULL;
+	list_del(&task->tk_task);
 	spin_unlock(&rpc_sched_lock);
 
 	/* Protect the execution below. */
@@ -952,14 +886,13 @@
 rpc_find_parent(struct rpc_task *child)
 {
 	struct rpc_task	*task, *parent;
+	struct list_head *le;
 
 	parent = (struct rpc_task *) child->tk_calldata;
-	if ((task = childq.task) != NULL) {
-		do {
-			if (task == parent)
-				return parent;
-		} while ((task = task->tk_next) != childq.task);
-	}
+	task_for_each(task, le, &childq.tasks)
+		if (task == parent)
+			return parent;
+
 	return NULL;
 }
 
@@ -1013,7 +946,8 @@
 void
 rpc_killall_tasks(struct rpc_clnt *clnt)
 {
-	struct rpc_task	**q, *rovr;
+	struct rpc_task	*rovr;
+	struct list_head *le;
 
 	dprintk("RPC:      killing all tasks for client %p\n", clnt);
 
@@ -1021,13 +955,12 @@
 	 * Spin lock all_tasks to prevent changes...
 	 */
 	spin_lock(&rpc_sched_lock);
-	for (q = &all_tasks; (rovr = *q); q = &rovr->tk_next_task) {
+	alltask_for_each(rovr, le, &all_tasks)
 		if (!clnt || rovr->tk_client == clnt) {
 			rovr->tk_flags |= RPC_TASK_KILLED;
 			rpc_exit(rovr, -EIO);
 			rpc_wake_up_task(rovr);
 		}
-	}
 	spin_unlock(&rpc_sched_lock);
 }
 
@@ -1036,7 +969,7 @@
 static inline int
 rpciod_task_pending(void)
 {
-	return schedq.task != NULL;
+	return !list_empty(&schedq.tasks);
 }
 
 
@@ -1088,7 +1021,7 @@
 	}
 
 	dprintk("RPC: rpciod shutdown commences\n");
-	if (all_tasks) {
+	if (!list_empty(&all_tasks)) {
 		printk(KERN_ERR "rpciod: active tasks at shutdown?!\n");
 		rpciod_killall();
 	}
@@ -1106,14 +1039,13 @@
 {
 	unsigned long flags;
 
-	while (all_tasks) {
+	while (!list_empty(&all_tasks)) {
 		current->sigpending = 0;
 		rpc_killall_tasks(NULL);
 		__rpc_schedule();
-		if (all_tasks) {
+		if (!list_empty(&all_tasks)) {
 			dprintk("rpciod_killall: waiting for tasks to exit\n");
-			current->policy |= SCHED_YIELD;
-			schedule();
+			yield();
 		}
 	}
 
@@ -1183,8 +1115,7 @@
 	 * wait briefly before checking the process id.
 	 */
 	current->sigpending = 0;
-	current->policy |= SCHED_YIELD;
-	schedule();
+	yield();
 	/*
 	 * Display a message if we're going to wait longer.
 	 */
@@ -1207,25 +1138,23 @@
 #ifdef RPC_DEBUG
 void rpc_show_tasks(void)
 {
-	struct rpc_task *t = all_tasks, *next;
+	struct list_head *le;
+	struct rpc_task *t;
 
 	spin_lock(&rpc_sched_lock);
-	t = all_tasks;
-	if (!t) {
+	if (list_empty(&all_tasks)) {
 		spin_unlock(&rpc_sched_lock);
 		return;
 	}
 	printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout "
 		"-rpcwait -action- --exit--\n");
-	for (; t; t = next) {
-		next = t->tk_next_task;
+	alltask_for_each(t, le, &all_tasks)
 		printk("%05d %04d %04x %06d %8p %6d %8p %08ld %8s %8p %8p\n",
 			t->tk_pid, t->tk_msg.rpc_proc, t->tk_flags, t->tk_status,
 			t->tk_client, t->tk_client->cl_prog,
 			t->tk_rqstp, t->tk_timeout,
 			t->tk_rpcwait ? rpc_qname(t->tk_rpcwait) : " <NULL> ",
 			t->tk_action, t->tk_exit);
-	}
 	spin_unlock(&rpc_sched_lock);
 }
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/sunrpc/stats.c linux-2.4.20/net/sunrpc/stats.c
--- linux-2.4.19/net/sunrpc/stats.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/sunrpc/stats.c	2002-10-29 11:18:51.000000000 +0000
@@ -15,6 +15,7 @@
 #define __NO_VERSION__
 #include <linux/module.h>
 
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
@@ -182,10 +183,9 @@
 	}
 }
 
-#ifdef MODULE
 
-int
-init_module(void)
+static int __init
+init_sunrpc(void)
 {
 #ifdef RPC_DEBUG
 	rpc_register_sysctl();
@@ -194,13 +194,14 @@
 	return 0;
 }
 
-void
-cleanup_module(void)
+static void __exit
+cleanup_sunrpc(void)
 {
 #ifdef RPC_DEBUG
 	rpc_unregister_sysctl();
 #endif
 	rpc_proc_exit();
 }
-#endif
 MODULE_LICENSE("GPL");
+module_init(init_sunrpc);
+module_exit(cleanup_sunrpc);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/sunrpc/sunrpc_syms.c linux-2.4.20/net/sunrpc/sunrpc_syms.c
--- linux-2.4.19/net/sunrpc/sunrpc_syms.c	2001-09-21 04:02:01.000000000 +0000
+++ linux-2.4.20/net/sunrpc/sunrpc_syms.c	2002-10-29 11:18:49.000000000 +0000
@@ -50,6 +50,7 @@
 EXPORT_SYMBOL(rpc_clnt_sigunmask);
 EXPORT_SYMBOL(rpc_delay);
 EXPORT_SYMBOL(rpc_restart_call);
+EXPORT_SYMBOL(rpc_setbufsize);
 
 /* Client transport */
 EXPORT_SYMBOL(xprt_create_proto);
@@ -77,6 +78,7 @@
 EXPORT_SYMBOL(svc_recv);
 EXPORT_SYMBOL(svc_wake_up);
 EXPORT_SYMBOL(svc_makesock);
+EXPORT_SYMBOL(svc_reserve);
 
 /* RPC statistics */
 #ifdef CONFIG_PROC_FS
@@ -95,8 +97,9 @@
 EXPORT_SYMBOL(xdr_decode_string_inplace);
 EXPORT_SYMBOL(xdr_decode_netobj);
 EXPORT_SYMBOL(xdr_encode_netobj);
-EXPORT_SYMBOL(xdr_shift_iovec);
-EXPORT_SYMBOL(xdr_zero_iovec);
+EXPORT_SYMBOL(xdr_encode_pages);
+EXPORT_SYMBOL(xdr_inline_pages);
+EXPORT_SYMBOL(xdr_shift_buf);
 
 /* Debugging symbols */
 #ifdef RPC_DEBUG
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/sunrpc/svc.c linux-2.4.20/net/sunrpc/svc.c
--- linux-2.4.19/net/sunrpc/svc.c	2001-09-07 17:48:39.000000000 +0000
+++ linux-2.4.20/net/sunrpc/svc.c	2002-10-29 11:18:50.000000000 +0000
@@ -31,10 +31,6 @@
 {
 	struct svc_serv	*serv;
 
-#ifdef RPC_DEBUG
-	rpc_register_sysctl();
-#endif
-
 	if (!(serv = (struct svc_serv *) kmalloc(sizeof(*serv), GFP_KERNEL)))
 		return NULL;
 
@@ -44,6 +40,10 @@
 	serv->sv_stats     = prog->pg_stats;
 	serv->sv_bufsz	   = bufsize? bufsize : 4096;
 	serv->sv_xdrsize   = xdrsize;
+	INIT_LIST_HEAD(&serv->sv_threads);
+	INIT_LIST_HEAD(&serv->sv_sockets);
+	INIT_LIST_HEAD(&serv->sv_tempsocks);
+	INIT_LIST_HEAD(&serv->sv_permsocks);
 	spin_lock_init(&serv->sv_lock);
 
 	serv->sv_name      = prog->pg_name;
@@ -67,13 +67,25 @@
 				serv->sv_nrthreads);
 
 	if (serv->sv_nrthreads) {
-		if (--(serv->sv_nrthreads) != 0)
+		if (--(serv->sv_nrthreads) != 0) {
+			svc_sock_update_bufs(serv);
 			return;
+		}
 	} else
 		printk("svc_destroy: no threads for serv=%p!\n", serv);
 
-	while ((svsk = serv->sv_allsocks) != NULL)
+	while (!list_empty(&serv->sv_tempsocks)) {
+		svsk = list_entry(serv->sv_tempsocks.next,
+				  struct svc_sock,
+				  sk_list);
+		svc_delete_socket(svsk);
+	}
+	while (!list_empty(&serv->sv_permsocks)) {
+		svsk = list_entry(serv->sv_permsocks.next,
+				  struct svc_sock,
+				  sk_list);
 		svc_delete_socket(svsk);
+	}
 
 	/* Unregister service with the portmapper */
 	svc_register(serv, 0, 0);
@@ -138,6 +150,7 @@
 	error = kernel_thread((int (*)(void *)) func, rqstp, 0);
 	if (error < 0)
 		goto out_thread;
+	svc_sock_update_bufs(serv);
 	error = 0;
 out:
 	return error;
@@ -296,6 +309,12 @@
 	memset(rqstp->rq_argp, 0, procp->pc_argsize);
 	memset(rqstp->rq_resp, 0, procp->pc_ressize);
 
+	/* un-reserve some of the out-queue now that we have a 
+	 * better idea of reply size
+	 */
+	if (procp->pc_xdrressize)
+		svc_reserve(rqstp, procp->pc_xdrressize<<2);
+
 	/* Call the function that processes the request. */
 	if (!versp->vs_dispatch) {
 		/* Decode arguments */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/sunrpc/svcsock.c linux-2.4.20/net/sunrpc/svcsock.c
--- linux-2.4.19/net/sunrpc/svcsock.c	2001-07-04 18:50:38.000000000 +0000
+++ linux-2.4.20/net/sunrpc/svcsock.c	2002-10-29 11:18:33.000000000 +0000
@@ -44,10 +44,19 @@
 
 /* SMP locking strategy:
  *
- * 	svc_sock->sk_lock and svc_serv->sv_lock protect their
- *	respective structures.
+ * 	svc_serv->sv_lock protects most stuff for that service.
+ *
+ *	Some flags can be set to certain values at any time
+ *	providing that certain rules are followed:
+ *
+ *	SK_BUSY  can be set to 0 at any time.  
+ *		svc_sock_enqueue must be called afterwards
+ *	SK_CONN, SK_DATA, can be set or cleared at any time.
+ *		after a set, svc_sock_enqueue must be called.	
+ *		after a clear, the socket must be read/accepted
+ *		 if this succeeds, it must be set again.
+ *	SK_CLOSE can set at any time. It is never cleared.
  *
- *	Antideadlock ordering is sk_lock --> sv_lock.
  */
 
 #define RPCDBG_FACILITY	RPCDBG_SVCSOCK
@@ -62,11 +71,14 @@
 
 /*
  * Queue up an idle server thread.  Must have serv->sv_lock held.
+ * Note: this is really a stack rather than a queue, so that we only
+ * use as many different threads as we need, and the rest don't polute
+ * the cache.
  */
 static inline void
 svc_serv_enqueue(struct svc_serv *serv, struct svc_rqst *rqstp)
 {
-	rpc_append_list(&serv->sv_threads, rqstp);
+	list_add(&rqstp->rq_list, &serv->sv_threads);
 }
 
 /*
@@ -75,7 +87,7 @@
 static inline void
 svc_serv_dequeue(struct svc_serv *serv, struct svc_rqst *rqstp)
 {
-	rpc_remove_list(&serv->sv_threads, rqstp);
+	list_del(&rqstp->rq_list);
 }
 
 /*
@@ -98,7 +110,6 @@
  * Queue up a socket with data pending. If there are idle nfsd
  * processes, wake 'em up.
  *
- * This must be called with svsk->sk_lock held.
  */
 static void
 svc_sock_enqueue(struct svc_sock *svsk)
@@ -106,26 +117,44 @@
 	struct svc_serv	*serv = svsk->sk_server;
 	struct svc_rqst	*rqstp;
 
-	/* NOTE: Local BH is already disabled by our caller. */
-	spin_lock(&serv->sv_lock);
+	if (!(svsk->sk_flags &
+	      ( (1<<SK_CONN)|(1<<SK_DATA)|(1<<SK_CLOSE)) ))
+		return;
+
+	spin_lock_bh(&serv->sv_lock);
 
-	if (serv->sv_threads && serv->sv_sockets)
+	if (!list_empty(&serv->sv_threads) && 
+	    !list_empty(&serv->sv_sockets))
 		printk(KERN_ERR
 			"svc_sock_enqueue: threads and sockets both waiting??\n");
 
-	if (svsk->sk_busy) {
+	if (test_bit(SK_BUSY, &svsk->sk_flags)) {
 		/* Don't enqueue socket while daemon is receiving */
 		dprintk("svc: socket %p busy, not enqueued\n", svsk->sk_sk);
 		goto out_unlock;
 	}
 
+	if (((svsk->sk_reserved + serv->sv_bufsz)*2
+	     > sock_wspace(svsk->sk_sk))
+	    && !test_bit(SK_CLOSE, &svsk->sk_flags)
+	    && !test_bit(SK_CONN, &svsk->sk_flags)) {
+		/* Don't enqueue while not enough space for reply */
+		dprintk("svc: socket %p  no space, %d*2 > %ld, not enqueued\n",
+			svsk->sk_sk, svsk->sk_reserved+serv->sv_bufsz,
+			sock_wspace(svsk->sk_sk));
+		goto out_unlock;
+	}
+
 	/* Mark socket as busy. It will remain in this state until the
 	 * server has processed all pending data and put the socket back
 	 * on the idle list.
 	 */
-	svsk->sk_busy = 1;
+	set_bit(SK_BUSY, &svsk->sk_flags);
 
-	if ((rqstp = serv->sv_threads) != NULL) {
+	if (!list_empty(&serv->sv_threads)) {
+		rqstp = list_entry(serv->sv_threads.next,
+				   struct svc_rqst,
+				   rq_list);
 		dprintk("svc: socket %p served by daemon %p\n",
 			svsk->sk_sk, rqstp);
 		svc_serv_dequeue(serv, rqstp);
@@ -135,15 +164,17 @@
 				rqstp, rqstp->rq_sock);
 		rqstp->rq_sock = svsk;
 		svsk->sk_inuse++;
+		rqstp->rq_reserved = serv->sv_bufsz;
+		svsk->sk_reserved += rqstp->rq_reserved;
 		wake_up(&rqstp->rq_wait);
 	} else {
 		dprintk("svc: socket %p put into queue\n", svsk->sk_sk);
-		rpc_append_list(&serv->sv_sockets, svsk);
-		svsk->sk_qued = 1;
+		list_add_tail(&svsk->sk_ready, &serv->sv_sockets);
+		set_bit(SK_QUED, &svsk->sk_flags);
 	}
 
 out_unlock:
-	spin_unlock(&serv->sv_lock);
+	spin_unlock_bh(&serv->sv_lock);
 }
 
 /*
@@ -154,71 +185,69 @@
 {
 	struct svc_sock	*svsk;
 
-	if ((svsk = serv->sv_sockets) != NULL)
-		rpc_remove_list(&serv->sv_sockets, svsk);
+	if (list_empty(&serv->sv_sockets))
+		return NULL;
 
-	if (svsk) {
-		dprintk("svc: socket %p dequeued, inuse=%d\n",
-			svsk->sk_sk, svsk->sk_inuse);
-		svsk->sk_qued = 0;
-	}
+	svsk = list_entry(serv->sv_sockets.next,
+			  struct svc_sock, sk_ready);
+	list_del(&svsk->sk_ready);
+
+	dprintk("svc: socket %p dequeued, inuse=%d\n",
+		svsk->sk_sk, svsk->sk_inuse);
+	clear_bit(SK_QUED, &svsk->sk_flags);
 
 	return svsk;
 }
 
 /*
- * Having read count bytes from a socket, check whether it
+ * Having read something from a socket, check whether it
  * needs to be re-enqueued.
+ * Note: SK_DATA only gets cleared when a read-attempt finds
+ * no (or insufficient) data.
  */
 static inline void
-svc_sock_received(struct svc_sock *svsk, int count)
+svc_sock_received(struct svc_sock *svsk)
 {
-	spin_lock_bh(&svsk->sk_lock);
-	if ((svsk->sk_data -= count) < 0) {
-		printk(KERN_NOTICE "svc: sk_data negative!\n");
-		svsk->sk_data = 0;
-	}
-	svsk->sk_rqstp = NULL; /* XXX */
-	svsk->sk_busy = 0;
-	if (svsk->sk_conn || svsk->sk_data || svsk->sk_close) {
-		dprintk("svc: socket %p re-enqueued after receive\n",
-						svsk->sk_sk);
-		svc_sock_enqueue(svsk);
-	}
-	spin_unlock_bh(&svsk->sk_lock);
+	clear_bit(SK_BUSY, &svsk->sk_flags);
+	svc_sock_enqueue(svsk);
 }
 
-/*
- * Dequeue a new connection.
+
+/**
+ * svc_reserve - change the space reserved for the reply to a request.
+ * @rqstp:  The request in question
+ * @space: new max space to reserve
+ *
+ * Each request reserves some space on the output queue of the socket
+ * to make sure the reply fits.  This function reduces that reserved
+ * space to be the amount of space used already, plus @space.
+ *
  */
-static inline void
-svc_sock_accepted(struct svc_sock *svsk)
+void svc_reserve(struct svc_rqst *rqstp, int space)
 {
-	spin_lock_bh(&svsk->sk_lock);
-        svsk->sk_busy = 0;
-        svsk->sk_conn--;
-        if (svsk->sk_conn || svsk->sk_data || svsk->sk_close) {
-                dprintk("svc: socket %p re-enqueued after accept\n",
-						svsk->sk_sk);
-                svc_sock_enqueue(svsk);
-        }
-	spin_unlock_bh(&svsk->sk_lock);
+	space += rqstp->rq_resbuf.len<<2;
+
+	if (space < rqstp->rq_reserved) {
+		struct svc_sock *svsk = rqstp->rq_sock;
+		spin_lock_bh(&svsk->sk_server->sv_lock);
+		svsk->sk_reserved -= (rqstp->rq_reserved - space);
+		rqstp->rq_reserved = space;
+		spin_unlock_bh(&svsk->sk_server->sv_lock);
+
+		svc_sock_enqueue(svsk);
+	}
 }
 
 /*
  * Release a socket after use.
  */
 static inline void
-svc_sock_release(struct svc_rqst *rqstp)
+svc_sock_put(struct svc_sock *svsk)
 {
-	struct svc_sock	*svsk = rqstp->rq_sock;
-	struct svc_serv	*serv = svsk->sk_server;
-
-	svc_release_skb(rqstp);
-	rqstp->rq_sock = NULL;
+	struct svc_serv *serv = svsk->sk_server;
 
 	spin_lock_bh(&serv->sv_lock);
-	if (!--(svsk->sk_inuse) && svsk->sk_dead) {
+	if (!--(svsk->sk_inuse) && test_bit(SK_DEAD, &svsk->sk_flags)) {
 		spin_unlock_bh(&serv->sv_lock);
 		dprintk("svc: releasing dead socket\n");
 		sock_release(svsk->sk_sock);
@@ -228,6 +257,31 @@
 		spin_unlock_bh(&serv->sv_lock);
 }
 
+static void
+svc_sock_release(struct svc_rqst *rqstp)
+{
+	struct svc_sock	*svsk = rqstp->rq_sock;
+
+	svc_release_skb(rqstp);
+
+	/* Reset response buffer and release
+	 * the reservation.
+	 * But first, check that enough space was reserved
+	 * for the reply, otherwise we have a bug!
+	 */
+	if ((rqstp->rq_resbuf.len<<2) >  rqstp->rq_reserved)
+		printk(KERN_ERR "RPC request reserved %d but used %d\n",
+		       rqstp->rq_reserved,
+		       rqstp->rq_resbuf.len<<2);
+
+	rqstp->rq_resbuf.buf = rqstp->rq_resbuf.base;
+	rqstp->rq_resbuf.len = 0;
+	svc_reserve(rqstp, 0);
+	rqstp->rq_sock = NULL;
+
+	svc_sock_put(svsk);
+}
+
 /*
  * External function to wake up a server waiting for data
  */
@@ -237,7 +291,10 @@
 	struct svc_rqst	*rqstp;
 
 	spin_lock_bh(&serv->sv_lock);
-	if ((rqstp = serv->sv_threads) != NULL) {
+	if (!list_empty(&serv->sv_threads)) {
+		rqstp = list_entry(serv->sv_threads.next,
+				   struct svc_rqst,
+				   rq_list);
 		dprintk("svc: daemon %p woken up.\n", rqstp);
 		/*
 		svc_serv_dequeue(serv, rqstp);
@@ -270,7 +327,13 @@
 	msg.msg_control = NULL;
 	msg.msg_controllen = 0;
 
-	msg.msg_flags	= MSG_DONTWAIT;
+	/* This was MSG_DONTWAIT, but I now want it to wait.
+	 * The only thing that it would wait for is memory and
+	 * if we are fairly low on memory, then we aren't likely
+	 * to make much progress anyway.
+	 * sk->sndtimeo is set to 30seconds just in case.
+	 */
+	msg.msg_flags	= 0;
 
 	oldfs = get_fs(); set_fs(KERNEL_DS);
 	len = sock_sendmsg(sock, &msg, buflen);
@@ -340,6 +403,32 @@
 }
 
 /*
+ * Set socket snd and rcv buffer lengths
+ */
+static inline void
+svc_sock_setbufsize(struct socket *sock, unsigned int snd, unsigned int rcv)
+{
+#if 0
+	mm_segment_t	oldfs;
+	oldfs = get_fs(); set_fs(KERNEL_DS);
+	sock_setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
+			(char*)&snd, sizeof(snd));
+	sock_setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
+			(char*)&rcv, sizeof(rcv));
+#else
+	/* sock_setsockopt limits use to sysctl_?mem_max,
+	 * which isn't acceptable.  Until that is made conditional
+	 * on not having CAP_SYS_RESOURCE or similar, we go direct...
+	 * DaveM said I could!
+	 */
+	lock_sock(sock->sk);
+	sock->sk->sndbuf = snd * 2;
+	sock->sk->rcvbuf = rcv * 2;
+	sock->sk->userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK;
+	release_sock(sock->sk);
+#endif
+}
+/*
  * INET callback when data has been received on the socket.
  */
 static void
@@ -350,17 +439,36 @@
 	if (!svsk)
 		goto out;
 	dprintk("svc: socket %p(inet %p), count=%d, busy=%d\n",
-		svsk, sk, count, svsk->sk_busy);
-	spin_lock_bh(&svsk->sk_lock);
-	svsk->sk_data = 1;
+		svsk, sk, count, test_bit(SK_BUSY, &svsk->sk_flags));
+	set_bit(SK_DATA, &svsk->sk_flags);
 	svc_sock_enqueue(svsk);
-	spin_unlock_bh(&svsk->sk_lock);
  out:
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible(sk->sleep);
 }
 
 /*
+ * INET callback when space is newly available on the socket.
+ */
+static void
+svc_write_space(struct sock *sk)
+{
+	struct svc_sock	*svsk = (struct svc_sock *)(sk->user_data);
+
+	if (svsk) {
+		dprintk("svc: socket %p(inet %p), write_space busy=%d\n",
+			svsk, sk, test_bit(SK_BUSY, &svsk->sk_flags));
+		svc_sock_enqueue(svsk);
+	}
+
+	if (sk->sleep && waitqueue_active(sk->sleep)) {
+		printk(KERN_WARNING "RPC svc_write_space: some sleeping on %p\n",
+		       svsk);
+		wake_up_interruptible(sk->sleep);
+	}
+}
+
+/*
  * Receive a datagram from a UDP socket.
  */
 static int
@@ -372,20 +480,31 @@
 	u32		*data;
 	int		err, len;
 
-	svsk->sk_data = 0;
+	if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags))
+		/* udp sockets need large rcvbuf as all pending
+		 * requests are still in that buffer.  sndbuf must
+		 * also be large enough that there is enough space
+		 * for one reply per thread.
+		 */
+		svc_sock_setbufsize(svsk->sk_sock,
+				    (serv->sv_nrthreads+3)* serv->sv_bufsz,
+				    (serv->sv_nrthreads+3)* serv->sv_bufsz);
+
+	clear_bit(SK_DATA, &svsk->sk_flags);
 	while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) {
-		svc_sock_received(svsk, 0);
+		svc_sock_received(svsk);
 		if (err == -EAGAIN)
 			return err;
 		/* possibly an icmp error */
 		dprintk("svc: recvfrom returned error %d\n", -err);
 	}
+	set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */
 
 	/* Sorry. */
 	if (skb_is_nonlinear(skb)) {
 		if (skb_linearize(skb, GFP_KERNEL) != 0) {
 			kfree_skb(skb);
-			svc_sock_received(svsk, 0);
+			svc_sock_received(svsk);
 			return 0;
 		}
 	}
@@ -393,13 +512,11 @@
 	if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
 		if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) {
 			skb_free_datagram(svsk->sk_sk, skb);
-			svc_sock_received(svsk, 0);
+			svc_sock_received(svsk);
 			return 0;
 		}
 	}
 
-	/* There may be more data */
-	svsk->sk_data = 1;
 
 	len  = skb->len - sizeof(struct udphdr);
 	data = (u32 *) (skb->data + sizeof(struct udphdr));
@@ -421,7 +538,7 @@
 
 	/* One down, maybe more to go... */
 	svsk->sk_sk->stamp = skb->stamp;
-	svc_sock_received(svsk, 0);
+	svc_sock_received(svsk);
 
 	return len;
 }
@@ -444,9 +561,6 @@
 	if (error == -ECONNREFUSED)
 		/* ICMP error on earlier request. */
 		error = svc_sendto(rqstp, bufp->iov, bufp->nriov);
-	else if (error == -EAGAIN)
-		/* Ignore and wait for re-xmit */
-		error = 0;
 
 	return error;
 }
@@ -455,9 +569,20 @@
 svc_udp_init(struct svc_sock *svsk)
 {
 	svsk->sk_sk->data_ready = svc_udp_data_ready;
+	svsk->sk_sk->write_space = svc_write_space;
 	svsk->sk_recvfrom = svc_udp_recvfrom;
 	svsk->sk_sendto = svc_udp_sendto;
 
+	/* initialise setting must have enough space to
+	 * receive and respond to one request.  
+	 * svc_udp_recvfrom will re-adjust if necessary
+	 */
+	svc_sock_setbufsize(svsk->sk_sock,
+			    3 * svsk->sk_server->sv_bufsz,
+			    3 * svsk->sk_server->sv_bufsz);
+
+	set_bit(SK_CHNGBUF, &svsk->sk_flags);
+
 	return 0;
 }
 
@@ -481,10 +606,8 @@
 		printk("svc: socket %p: no user data\n", sk);
 		goto out;
 	}
-	spin_lock_bh(&svsk->sk_lock);
-	svsk->sk_conn++;
+	set_bit(SK_CONN, &svsk->sk_flags);
 	svc_sock_enqueue(svsk);
-	spin_unlock_bh(&svsk->sk_lock);
  out:
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible_all(sk->sleep);
@@ -505,10 +628,8 @@
 		printk("svc: socket %p: no user data\n", sk);
 		goto out;
 	}
-	spin_lock_bh(&svsk->sk_lock);
-	svsk->sk_close = 1;
+	set_bit(SK_CLOSE, &svsk->sk_flags);
 	svc_sock_enqueue(svsk);
-	spin_unlock_bh(&svsk->sk_lock);
  out:
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible_all(sk->sleep);
@@ -523,10 +644,8 @@
 			sk, sk->user_data);
 	if (!(svsk = (struct svc_sock *)(sk->user_data)))
 		goto out;
-	spin_lock_bh(&svsk->sk_lock);
-	svsk->sk_data++;
+	set_bit(SK_DATA, &svsk->sk_flags);
 	svc_sock_enqueue(svsk);
-	spin_unlock_bh(&svsk->sk_lock);
  out:
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible(sk->sleep);
@@ -559,12 +678,15 @@
 	newsock->type = sock->type;
 	newsock->ops = ops = sock->ops;
 
+	clear_bit(SK_CONN, &svsk->sk_flags);
 	if ((err = ops->accept(sock, newsock, O_NONBLOCK)) < 0) {
-		if (net_ratelimit())
+		if (err != -EAGAIN && net_ratelimit())
 			printk(KERN_WARNING "%s: accept failed (err %d)!\n",
 				   serv->sv_name, -err);
 		goto failed;		/* aborted connection or whatever */
 	}
+	set_bit(SK_CONN, &svsk->sk_flags);
+	svc_sock_enqueue(svsk);
 
 	slen = sizeof(sin);
 	err = ops->getname(newsock, (struct sockaddr *) &sin, &slen, 1);
@@ -580,11 +702,10 @@
 	 * tell us anything. For now just warn about unpriv connections.
 	 */
 	if (ntohs(sin.sin_port) >= 1024) {
-		if (net_ratelimit())
-			printk(KERN_WARNING
-				   "%s: connect from unprivileged port: %u.%u.%u.%u:%d\n",
-				   serv->sv_name, 
-				   NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
+		dprintk(KERN_WARNING
+			"%s: connect from unprivileged port: %u.%u.%u.%u:%d\n",
+			serv->sv_name, 
+			NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
 	}
 
 	dprintk("%s: connect from %u.%u.%u.%u:%04x\n", serv->sv_name,
@@ -593,14 +714,45 @@
 	if (!(newsvsk = svc_setup_socket(serv, newsock, &err, 0)))
 		goto failed;
 
+	/* make sure that a write doesn't block forever when
+	 * low on memory
+	 */
+	newsock->sk->sndtimeo = HZ*30;
+
 	/* Precharge. Data may have arrived on the socket before we
 	 * installed the data_ready callback. 
 	 */
-	spin_lock_bh(&newsvsk->sk_lock);
-	newsvsk->sk_data = 1;
-	newsvsk->sk_temp = 1;
+	set_bit(SK_DATA, &newsvsk->sk_flags);
 	svc_sock_enqueue(newsvsk);
-	spin_unlock_bh(&newsvsk->sk_lock);
+
+	/* make sure that we don't have too many active connections.
+	 * If we have, something must be dropped.
+	 * We randomly choose between newest and oldest (in terms
+	 * of recent activity) and drop it.
+	 */
+	if (serv->sv_tmpcnt > (serv->sv_nrthreads+3)*10) {
+		struct svc_sock *svsk = NULL;
+		spin_lock_bh(&serv->sv_lock);
+		if (!list_empty(&serv->sv_tempsocks)) {
+			if (net_random()&1)
+				svsk = list_entry(serv->sv_tempsocks.prev,
+						  struct svc_sock,
+						  sk_list);
+			else
+				svsk = list_entry(serv->sv_tempsocks.next,
+						  struct svc_sock,
+						  sk_list);
+			set_bit(SK_CLOSE, &svsk->sk_flags);
+			svsk->sk_inuse ++;
+		}
+		spin_unlock_bh(&serv->sv_lock);
+
+		if (svsk) {
+			svc_sock_enqueue(svsk);
+			svc_sock_put(svsk);
+		}
+
+	}
 
 	if (serv->sv_stats)
 		serv->sv_stats->nettcpconn++;
@@ -621,23 +773,38 @@
 	struct svc_sock	*svsk = rqstp->rq_sock;
 	struct svc_serv	*serv = svsk->sk_server;
 	struct svc_buf	*bufp = &rqstp->rq_argbuf;
-	int		len, ready, used;
+	int		len;
 
 	dprintk("svc: tcp_recv %p data %d conn %d close %d\n",
-			svsk, svsk->sk_data, svsk->sk_conn, svsk->sk_close);
+		svsk, test_bit(SK_DATA, &svsk->sk_flags),
+		test_bit(SK_CONN, &svsk->sk_flags),
+		test_bit(SK_CLOSE, &svsk->sk_flags));
 
-	if (svsk->sk_close) {
+	if (test_bit(SK_CLOSE, &svsk->sk_flags)) {
 		svc_delete_socket(svsk);
 		return 0;
 	}
 
-	if (svsk->sk_conn) {
+	if (test_bit(SK_CONN, &svsk->sk_flags)) {
 		svc_tcp_accept(svsk);
-		svc_sock_accepted(svsk);
+		svc_sock_received(svsk);
 		return 0;
 	}
 
-	ready = svsk->sk_data;
+	if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags))
+		/* sndbuf needs to have room for one request
+		 * per thread, otherwise we can stall even when the
+		 * network isn't a bottleneck.
+		 * rcvbuf just needs to be able to hold a few requests.
+		 * Normally they will be removed from the queue 
+		 * as soon as a complete request arrives.
+		 */
+		svc_sock_setbufsize(svsk->sk_sock,
+				    (serv->sv_nrthreads+3) *
+				    serv->sv_bufsz,
+				    3 * serv->sv_bufsz);
+
+	clear_bit(SK_DATA, &svsk->sk_flags);
 
 	/* Receive data. If we haven't got the record length yet, get
 	 * the next four bytes. Otherwise try to gobble up as much as
@@ -652,6 +819,8 @@
 		if ((len = svc_recvfrom(rqstp, &iov, 1, want)) < 0)
 			goto error;
 		svsk->sk_tcplen += len;
+		if (len < want)
+			return 0;
 
 		svsk->sk_reclen = ntohl(svsk->sk_reclen);
 		if (!(svsk->sk_reclen & 0x80000000)) {
@@ -660,13 +829,17 @@
 			 *  bit set in the fragment length header.
 			 *  But apparently no known nfs clients send fragmented
 			 *  records. */
-			/* FIXME: shutdown socket */
-			printk(KERN_NOTICE "RPC: bad TCP reclen %08lx",
+			printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx (non-terminal)\n",
 			       (unsigned long) svsk->sk_reclen);
-			return -EIO;
+			goto err_delete;
 		}
 		svsk->sk_reclen &= 0x7fffffff;
 		dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen);
+		if (svsk->sk_reclen > (bufp->buflen<<2)) {
+			printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx (large)\n",
+			       (unsigned long) svsk->sk_reclen);
+			goto err_delete;
+		}
 	}
 
 	/* Check whether enough data is available */
@@ -675,21 +848,12 @@
 		goto error;
 
 	if (len < svsk->sk_reclen) {
-		/* FIXME: if sk_reclen > window-size, then we will
-		 * never be able to receive the record, so should
-		 * shutdown the connection
-		 */
 		dprintk("svc: incomplete TCP record (%d of %d)\n",
 			len, svsk->sk_reclen);
-		svc_sock_received(svsk, ready);
+		svc_sock_received(svsk);
 		return -EAGAIN;	/* record not complete */
 	}
-	/* if we think there is only one more record to read, but
-	 * it is bigger than we expect, then two records must have arrived
-	 * together, so pretend we aren't using the record.. */
-	if (len > svsk->sk_reclen && ready == 1)
-		used = 0;
-	else	used = 1;
+	set_bit(SK_DATA, &svsk->sk_flags);
 
 	/* Frob argbuf */
 	bufp->iov[0].iov_base += 4;
@@ -716,20 +880,24 @@
 	svsk->sk_reclen = 0;
 	svsk->sk_tcplen = 0;
 
-	svc_sock_received(svsk, used);
+	svc_sock_received(svsk);
 	if (serv->sv_stats)
 		serv->sv_stats->nettcpcnt++;
 
 	return len;
 
-error:
+ err_delete:
+	svc_delete_socket(svsk);
+	return -EAGAIN;
+
+ error:
 	if (len == -EAGAIN) {
 		dprintk("RPC: TCP recvfrom got EAGAIN\n");
-		svc_sock_received(svsk, ready); /* Clear data ready */
+		svc_sock_received(svsk);
 	} else {
 		printk(KERN_NOTICE "%s: recvfrom returned errno %d\n",
 					svsk->sk_server->sv_name, -len);
-		svc_sock_received(svsk, 0);
+		svc_sock_received(svsk);
 	}
 
 	return len;
@@ -737,8 +905,6 @@
 
 /*
  * Send out data on TCP socket.
- * FIXME: Make the sendto call non-blocking in order not to hang
- * a daemon on a dead client. Requires write queue maintenance.
  */
 static int
 svc_tcp_sendto(struct svc_rqst *rqstp)
@@ -756,13 +922,11 @@
 
 	sent = svc_sendto(rqstp, bufp->iov, bufp->nriov);
 	if (sent != bufp->len<<2) {
-		printk(KERN_NOTICE "rpc-srv/tcp: %s: sent only %d bytes of %d - should shutdown socket\n",
+		printk(KERN_NOTICE "rpc-srv/tcp: %s: sent only %d bytes of %d - shutting down socket\n",
 		       rqstp->rq_sock->sk_server->sv_name,
 		       sent, bufp->len << 2);
-		/* FIXME: should shutdown the socket, or allocate more memort
-		 * or wait and try again or something.  Otherwise
-		 * client will get confused
-		 */
+		svc_delete_socket(rqstp->rq_sock);
+		sent = -EAGAIN;
 	}
 	return sent;
 }
@@ -782,21 +946,58 @@
 		dprintk("setting up TCP socket for reading\n");
 		sk->state_change = svc_tcp_state_change;
 		sk->data_ready = svc_tcp_data_ready;
+		sk->write_space = svc_write_space;
 
 		svsk->sk_reclen = 0;
 		svsk->sk_tcplen = 0;
+
+		/* initialise setting must have enough space to
+		 * receive and respond to one request.  
+		 * svc_tcp_recvfrom will re-adjust if necessary
+		 */
+		svc_sock_setbufsize(svsk->sk_sock,
+				    3 * svsk->sk_server->sv_bufsz,
+				    3 * svsk->sk_server->sv_bufsz);
+
+		set_bit(SK_CHNGBUF, &svsk->sk_flags);
 	}
 
 	return 0;
 }
 
+void
+svc_sock_update_bufs(struct svc_serv *serv)
+{
+	/*
+	 * The number of server threads has changed. 
+	 * flag all socket to the snd/rcv buffer sizes
+	 * updated.
+	 * We don't just do it, as the locking is rather
+	 * awkward at this point
+	 */
+	struct list_head *le;
+
+	spin_lock_bh(&serv->sv_lock);
+	list_for_each(le, &serv->sv_permsocks) {
+		struct svc_sock *svsk = 
+			list_entry(le, struct svc_sock, sk_list);
+		set_bit(SK_CHNGBUF, &svsk->sk_flags);
+	}
+	list_for_each(le, &serv->sv_tempsocks) {
+		struct svc_sock *svsk =
+			list_entry(le, struct svc_sock, sk_list);
+		set_bit(SK_CHNGBUF, &svsk->sk_flags);
+	}
+	spin_unlock_bh(&serv->sv_lock);
+}
+
 /*
  * Receive the next request on any socket.
  */
 int
 svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
 {
-	struct svc_sock		*svsk;
+	struct svc_sock		*svsk =NULL;
 	int			len;
 	DECLARE_WAITQUEUE(wait, current);
 
@@ -820,9 +1021,28 @@
 		return -EINTR;
 
 	spin_lock_bh(&serv->sv_lock);
-	if ((svsk = svc_sock_dequeue(serv)) != NULL) {
+	if (!list_empty(&serv->sv_tempsocks)) {
+		svsk = list_entry(serv->sv_tempsocks.next,
+				  struct svc_sock, sk_list);
+		/* apparently the "standard" is that clients close
+		 * idle connections after 5 minutes, servers after
+		 * 6 minutes
+		 *   http://www.connectathon.org/talks96/nfstcp.pdf 
+		 */
+		if (CURRENT_TIME - svsk->sk_lastrecv < 6*60
+		    || test_bit(SK_BUSY, &svsk->sk_flags))
+			svsk = NULL;
+	}
+	if (svsk) {
+		set_bit(SK_BUSY, &svsk->sk_flags);
+		set_bit(SK_CLOSE, &svsk->sk_flags);
+		rqstp->rq_sock = svsk;
+		svsk->sk_inuse++;
+	} else if ((svsk = svc_sock_dequeue(serv)) != NULL) {
 		rqstp->rq_sock = svsk;
 		svsk->sk_inuse++;
+		rqstp->rq_reserved = serv->sv_bufsz;	
+		svsk->sk_reserved += rqstp->rq_reserved;
 	} else {
 		/* No data pending. Go to sleep */
 		svc_serv_enqueue(serv, rqstp);
@@ -859,6 +1079,14 @@
 		svc_sock_release(rqstp);
 		return -EAGAIN;
 	}
+	svsk->sk_lastrecv = CURRENT_TIME;
+	if (test_bit(SK_TEMP, &svsk->sk_flags)) {
+		/* push active sockets to end of list */
+		spin_lock_bh(&serv->sv_lock);
+		list_del(&svsk->sk_list);
+		list_add_tail(&svsk->sk_list, &serv->sv_tempsocks);
+		spin_unlock_bh(&serv->sv_lock);
+	}
 
 	rqstp->rq_secure  = ntohs(rqstp->rq_addr.sin_port) < 1024;
 	rqstp->rq_userset = 0;
@@ -935,8 +1163,9 @@
 	svsk->sk_sk = inet;
 	svsk->sk_ostate = inet->state_change;
 	svsk->sk_odata = inet->data_ready;
+	svsk->sk_owspace = inet->write_space;
 	svsk->sk_server = serv;
-	spin_lock_init(&svsk->sk_lock);
+	svsk->sk_lastrecv = CURRENT_TIME;
 
 	/* Initialize the socket */
 	if (sock->type == SOCK_DGRAM)
@@ -956,9 +1185,16 @@
 		return NULL;
 	}
 
+
 	spin_lock_bh(&serv->sv_lock);
-	svsk->sk_list = serv->sv_allsocks;
-	serv->sv_allsocks = svsk;
+	if (!pmap_register) {
+		set_bit(SK_TEMP, &svsk->sk_flags);
+		list_add(&svsk->sk_list, &serv->sv_tempsocks);
+		serv->sv_tmpcnt++;
+	} else {
+		clear_bit(SK_TEMP, &svsk->sk_flags);
+		list_add(&svsk->sk_list, &serv->sv_permsocks);
+	}
 	spin_unlock_bh(&serv->sv_lock);
 
 	dprintk("svc: svc_setup_socket created %p (inet %p)\n",
@@ -993,6 +1229,7 @@
 		return error;
 
 	if (sin != NULL) {
+		sock->sk->reuse = 1; /* allow address reuse */
 		error = sock->ops->bind(sock, (struct sockaddr *) sin,
 						sizeof(*sin));
 		if (error < 0)
@@ -1000,7 +1237,7 @@
 	}
 
 	if (protocol == IPPROTO_TCP) {
-		if ((error = sock->ops->listen(sock, 5)) < 0)
+		if ((error = sock->ops->listen(sock, 64)) < 0)
 			goto bummer;
 	}
 
@@ -1019,7 +1256,6 @@
 void
 svc_delete_socket(struct svc_sock *svsk)
 {
-	struct svc_sock	**rsk;
 	struct svc_serv	*serv;
 	struct sock	*sk;
 
@@ -1030,23 +1266,18 @@
 
 	sk->state_change = svsk->sk_ostate;
 	sk->data_ready = svsk->sk_odata;
+	sk->write_space = svsk->sk_owspace;
 
 	spin_lock_bh(&serv->sv_lock);
 
-	for (rsk = &serv->sv_allsocks; *rsk; rsk = &(*rsk)->sk_list) {
-		if (*rsk == svsk)
-			break;
-	}
-	if (!*rsk) {
-		spin_unlock_bh(&serv->sv_lock);
-		return;
-	}
-	*rsk = svsk->sk_list;
-	if (svsk->sk_qued)
-		rpc_remove_list(&serv->sv_sockets, svsk);
+	list_del(&svsk->sk_list);
+	if (test_bit(SK_TEMP, &svsk->sk_flags))
+		serv->sv_tmpcnt--;
+	if (test_bit(SK_QUED, &svsk->sk_flags))
+		list_del(&svsk->sk_ready);
 
 
-	svsk->sk_dead = 1;
+	set_bit(SK_DEAD, &svsk->sk_flags);
 
 	if (!svsk->sk_inuse) {
 		spin_unlock_bh(&serv->sv_lock);
@@ -1054,7 +1285,7 @@
 		kfree(svsk);
 	} else {
 		spin_unlock_bh(&serv->sv_lock);
-		printk(KERN_NOTICE "svc: server socket destroy delayed\n");
+		dprintk(KERN_NOTICE "svc: server socket destroy delayed\n");
 		/* svsk->sk_server = NULL; */
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/sunrpc/timer.c linux-2.4.20/net/sunrpc/timer.c
--- linux-2.4.19/net/sunrpc/timer.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/net/sunrpc/timer.c	2002-10-29 11:18:37.000000000 +0000
@@ -0,0 +1,74 @@
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/unistd.h>
+
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprt.h>
+#include <linux/sunrpc/timer.h>
+
+#define RPC_RTO_MAX (60*HZ)
+#define RPC_RTO_INIT (HZ/5)
+#define RPC_RTO_MIN (2)
+
+void
+rpc_init_rtt(struct rpc_rtt *rt, long timeo)
+{
+	long t = (timeo - RPC_RTO_INIT) << 3;
+	int i;
+	rt->timeo = timeo;
+	if (t < 0)
+		t = 0;
+	for (i = 0; i < 5; i++) {
+		rt->srtt[i] = t;
+		rt->sdrtt[i] = RPC_RTO_INIT;
+	}
+	atomic_set(&rt->ntimeouts, 0);
+}
+
+void
+rpc_update_rtt(struct rpc_rtt *rt, int timer, long m)
+{
+	long *srtt, *sdrtt;
+
+	if (timer-- == 0)
+		return;
+
+	if (m == 0)
+		m = 1;
+	srtt = &rt->srtt[timer];
+	m -= *srtt >> 3;
+	*srtt += m;
+	if (m < 0)
+		m = -m;
+	sdrtt = &rt->sdrtt[timer];
+	m -= *sdrtt >> 2;
+	*sdrtt += m;
+	/* Set lower bound on the variance */
+	if (*sdrtt < RPC_RTO_MIN)
+		*sdrtt = RPC_RTO_MIN;
+}
+
+/*
+ * Estimate rto for an nfs rpc sent via. an unreliable datagram.
+ * Use the mean and mean deviation of rtt for the appropriate type of rpc
+ * for the frequent rpcs and a default for the others.
+ * The justification for doing "other" this way is that these rpcs
+ * happen so infrequently that timer est. would probably be stale.
+ * Also, since many of these rpcs are
+ * non-idempotent, a conservative timeout is desired.
+ * getattr, lookup,
+ * read, write, commit     - A+4D
+ * other                   - timeo
+ */
+
+long
+rpc_calc_rto(struct rpc_rtt *rt, int timer)
+{
+	long res;
+	if (timer-- == 0)
+		return rt->timeo;
+	res = (rt->srtt[timer] >> 3) + rt->sdrtt[timer];
+	if (res > RPC_RTO_MAX)
+		res = RPC_RTO_MAX;
+	return res;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/sunrpc/xdr.c linux-2.4.20/net/sunrpc/xdr.c
--- linux-2.4.19/net/sunrpc/xdr.c	2001-10-01 16:19:56.000000000 +0000
+++ linux-2.4.20/net/sunrpc/xdr.c	2002-10-29 11:18:49.000000000 +0000
@@ -10,6 +10,8 @@
 #include <linux/socket.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/pagemap.h>
+#include <linux/errno.h>
 #include <linux/in.h>
 #include <linux/sunrpc/xdr.h>
 #include <linux/sunrpc/msg_prot.h>
@@ -100,6 +102,46 @@
 }
 
 
+void
+xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
+		 unsigned int len)
+{
+	xdr->pages = pages;
+	xdr->page_base = base;
+	xdr->page_len = len;
+
+	if (len & 3) {
+		struct iovec *iov = xdr->tail;
+		unsigned int pad = 4 - (len & 3);
+
+		iov->iov_base = (void *) "\0\0\0";
+		iov->iov_len  = pad;
+		len += pad;
+	}
+	xdr->len += len;
+}
+
+void
+xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
+		 struct page **pages, unsigned int base, unsigned int len)
+{
+	struct iovec *head = xdr->head;
+	struct iovec *tail = xdr->tail;
+	char *buf = (char *)head->iov_base;
+	unsigned int buflen = head->iov_len;
+
+	head->iov_len  = offset;
+
+	xdr->pages = pages;
+	xdr->page_base = base;
+	xdr->page_len = len;
+
+	tail->iov_base = buf + offset;
+	tail->iov_len = buflen - offset;
+
+	xdr->len += len;
+}
+
 /*
  * Realign the iovec if the server missed out some reply elements
  * (such as post-op attributes,...)
@@ -132,19 +174,152 @@
 }
 
 /*
- * Zero the last n bytes in an iovec array of 'nr' elements
+ * Map a struct xdr_buf into an iovec array.
  */
-void xdr_zero_iovec(struct iovec *iov, int nr, size_t n)
+int xdr_kmap(struct iovec *iov_base, struct xdr_buf *xdr, unsigned int base)
 {
-	struct iovec *pvec;
+	struct iovec	*iov = iov_base;
+	struct page	**ppage = xdr->pages;
+	unsigned int	len, pglen = xdr->page_len;
+
+	len = xdr->head[0].iov_len;
+	if (base < len) {
+		iov->iov_len = len - base;
+		iov->iov_base = (char *)xdr->head[0].iov_base + base;
+		iov++;
+		base = 0;
+	} else
+		base -= len;
+
+	if (pglen == 0)
+		goto map_tail;
+	if (base >= pglen) {
+		base -= pglen;
+		goto map_tail;
+	}
+	if (base || xdr->page_base) {
+		pglen -= base;
+		base  += xdr->page_base;
+		ppage += base >> PAGE_CACHE_SHIFT;
+		base &= ~PAGE_CACHE_MASK;
+	}
+	do {
+		len = PAGE_CACHE_SIZE;
+		iov->iov_base = kmap(*ppage);
+		if (base) {
+			iov->iov_base += base;
+			len -= base;
+			base = 0;
+		}
+		if (pglen < len)
+			len = pglen;
+		iov->iov_len = len;
+		iov++;
+		ppage++;
+	} while ((pglen -= len) != 0);
+map_tail:
+	if (xdr->tail[0].iov_len) {
+		iov->iov_len = xdr->tail[0].iov_len - base;
+		iov->iov_base = (char *)xdr->tail[0].iov_base + base;
+		iov++;
+	}
+	return (iov - iov_base);
+}
 
-	for (pvec = iov + nr - 1; n && nr > 0; nr--, pvec--) {
-		if (n < pvec->iov_len) {
-			memset((char *)pvec->iov_base + pvec->iov_len - n, 0, n);
-			n = 0;
+void xdr_kunmap(struct xdr_buf *xdr, unsigned int base)
+{
+	struct page	**ppage = xdr->pages;
+	unsigned int	pglen = xdr->page_len;
+
+	if (!pglen)
+		return;
+	if (base > xdr->head[0].iov_len)
+		base -= xdr->head[0].iov_len;
+	else
+		base = 0;
+
+	if (base >= pglen)
+		return;
+	if (base || xdr->page_base) {
+		pglen -= base;
+		base  += xdr->page_base;
+		ppage += base >> PAGE_CACHE_SHIFT;
+	}
+	for (;;) {
+		flush_dcache_page(*ppage);
+		kunmap(*ppage);
+		if (pglen <= PAGE_CACHE_SIZE)
+			break;
+		pglen -= PAGE_CACHE_SIZE;
+		ppage++;
+	}
+}
+
+void
+xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base,
+			  skb_reader_t *desc,
+			  skb_read_actor_t copy_actor)
+{
+	struct page	**ppage = xdr->pages;
+	unsigned int	len, pglen = xdr->page_len;
+	int		ret;
+
+	len = xdr->head[0].iov_len;
+	if (base < len) {
+		len -= base;
+		ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len);
+		if (ret != len || !desc->count)
+			return;
+		base = 0;
+	} else
+		base -= len;
+
+	if (pglen == 0)
+		goto copy_tail;
+	if (base >= pglen) {
+		base -= pglen;
+		goto copy_tail;
+	}
+	if (base || xdr->page_base) {
+		pglen -= base;
+		base  += xdr->page_base;
+		ppage += base >> PAGE_CACHE_SHIFT;
+		base &= ~PAGE_CACHE_MASK;
+	}
+	do {
+		char *kaddr;
+
+		len = PAGE_CACHE_SIZE;
+		kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA);
+		if (base) {
+			len -= base;
+			if (pglen < len)
+				len = pglen;
+			ret = copy_actor(desc, kaddr + base, len);
+			base = 0;
 		} else {
-			memset(pvec->iov_base, 0, pvec->iov_len);
-			n -= pvec->iov_len;
+			if (pglen < len)
+				len = pglen;
+			ret = copy_actor(desc, kaddr, len);
 		}
-	}
+		kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA);
+		if (ret != len || !desc->count)
+			return;
+		ppage++;
+	} while ((pglen -= len) != 0);
+copy_tail:
+	len = xdr->tail[0].iov_len;
+	if (len)
+		copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len);
+}
+
+void
+xdr_shift_buf(struct xdr_buf *xdr, size_t len)
+{
+	struct iovec iov[MAX_IOVEC];
+	unsigned int nr;
+
+	nr = xdr_kmap(iov, xdr, 0);
+	xdr_shift_iovec(iov, nr, len);
+	xdr_kunmap(xdr, 0);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/sunrpc/xprt.c linux-2.4.20/net/sunrpc/xprt.c
--- linux-2.4.19/net/sunrpc/xprt.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/sunrpc/xprt.c	2002-10-29 11:18:33.000000000 +0000
@@ -67,8 +67,6 @@
 
 #include <asm/uaccess.h>
 
-extern spinlock_t rpc_queue_lock;
-
 /*
  * Local variables
  */
@@ -78,6 +76,8 @@
 # define RPCDBG_FACILITY	RPCDBG_XPRT
 #endif
 
+#define XPRT_MAX_BACKOFF	(8)
+
 /*
  * Local functions
  */
@@ -88,6 +88,7 @@
 static void	xprt_reconn_status(struct rpc_task *task);
 static struct socket *xprt_create_socket(int, struct rpc_timeout *);
 static int	xprt_bind_socket(struct rpc_xprt *, struct socket *);
+static int      __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
 
 #ifdef RPC_DEBUG_DATA
 /*
@@ -130,75 +131,74 @@
 }
 
 /*
- *	Adjust the iovec to move on 'n' bytes
- */
- 
-extern inline void
-xprt_move_iov(struct msghdr *msg, struct iovec *niv, unsigned amount)
-{
-	struct iovec *iv=msg->msg_iov;
-	int i;
-	
-	/*
-	 *	Eat any sent iovecs
-	 */
-	while (iv->iov_len <= amount) {
-		amount -= iv->iov_len;
-		iv++;
-		msg->msg_iovlen--;
-	}
-
-	/*
-	 *	And chew down the partial one
-	 */
-	niv[0].iov_len = iv->iov_len-amount;
-	niv[0].iov_base =((unsigned char *)iv->iov_base)+amount;
-	iv++;
-
-	/*
-	 *	And copy any others
-	 */
-	for(i = 1; i < msg->msg_iovlen; i++)
-		niv[i]=*iv++;
-
-	msg->msg_iov=niv;
-}
-
-/*
  * Serialize write access to sockets, in order to prevent different
  * requests from interfering with each other.
  * Also prevents TCP socket reconnections from colliding with writes.
  */
 static int
-xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
+__xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
 {
-	int retval;
-	spin_lock_bh(&xprt->sock_lock);
-	if (!xprt->snd_task)
-		xprt->snd_task = task;
-	else if (xprt->snd_task != task) {
-		dprintk("RPC: %4d TCP write queue full (task %d)\n",
-			task->tk_pid, xprt->snd_task->tk_pid);
+	if (!xprt->snd_task) {
+		if (xprt->nocong || __xprt_get_cong(xprt, task))
+			xprt->snd_task = task;
+	}
+	if (xprt->snd_task != task) {
+		dprintk("RPC: %4d TCP write queue full\n", task->tk_pid);
 		task->tk_timeout = 0;
 		task->tk_status = -EAGAIN;
-		rpc_sleep_on(&xprt->sending, task, NULL, NULL);
+		if (task->tk_rqstp && task->tk_rqstp->rq_nresend)
+			rpc_sleep_on(&xprt->resend, task, NULL, NULL);
+		else
+			rpc_sleep_on(&xprt->sending, task, NULL, NULL);
 	}
-	retval = xprt->snd_task == task;
+	return xprt->snd_task == task;
+}
+
+static inline int
+xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
+{
+	int retval;
+	spin_lock_bh(&xprt->sock_lock);
+	retval = __xprt_lock_write(xprt, task);
 	spin_unlock_bh(&xprt->sock_lock);
 	return retval;
 }
 
+static void
+__xprt_lock_write_next(struct rpc_xprt *xprt)
+{
+	struct rpc_task *task;
+
+	if (xprt->snd_task)
+		return;
+	task = rpc_wake_up_next(&xprt->resend);
+	if (!task) {
+		if (!xprt->nocong && RPCXPRT_CONGESTED(xprt))
+			return;
+		task = rpc_wake_up_next(&xprt->sending);
+		if (!task)
+			return;
+	}
+	if (xprt->nocong || __xprt_get_cong(xprt, task))
+		xprt->snd_task = task;
+}
+
 /*
  * Releases the socket for use by other requests.
  */
 static void
+__xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task)
+{
+	if (xprt->snd_task == task)
+		xprt->snd_task = NULL;
+	__xprt_lock_write_next(xprt);
+}
+
+static inline void
 xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task)
 {
 	spin_lock_bh(&xprt->sock_lock);
-	if (xprt->snd_task == task) {
-		xprt->snd_task = NULL;
-		rpc_wake_up_next(&xprt->sending);
-	}
+	__xprt_release_write(xprt, task);
 	spin_unlock_bh(&xprt->sock_lock);
 }
 
@@ -210,13 +210,11 @@
 {
 	struct socket	*sock = xprt->sock;
 	struct msghdr	msg;
+	struct xdr_buf	*xdr = &req->rq_snd_buf;
+	struct iovec	niv[MAX_IOVEC];
+	unsigned int	niov, slen, skip;
 	mm_segment_t	oldfs;
 	int		result;
-	int		slen = req->rq_slen - req->rq_bytes_sent;
-	struct iovec	niv[MAX_IOVEC];
-
-	if (slen <= 0)
-		return 0;
 
 	if (!sock)
 		return -ENOTCONN;
@@ -225,22 +223,26 @@
 				req->rq_svec->iov_base,
 				req->rq_svec->iov_len);
 
+	/* Dont repeat bytes */
+	skip = req->rq_bytes_sent;
+	slen = xdr->len - skip;
+	niov = xdr_kmap(niv, xdr, skip);
+
 	msg.msg_flags   = MSG_DONTWAIT|MSG_NOSIGNAL;
-	msg.msg_iov	= req->rq_svec;
-	msg.msg_iovlen	= req->rq_snr;
+	msg.msg_iov	= niv;
+	msg.msg_iovlen	= niov;
 	msg.msg_name	= (struct sockaddr *) &xprt->addr;
 	msg.msg_namelen = sizeof(xprt->addr);
 	msg.msg_control = NULL;
 	msg.msg_controllen = 0;
 
-	/* Dont repeat bytes */
-	if (req->rq_bytes_sent)
-		xprt_move_iov(&msg, niv, req->rq_bytes_sent);
-
 	oldfs = get_fs(); set_fs(get_ds());
+	clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags);
 	result = sock_sendmsg(sock, &msg, slen);
 	set_fs(oldfs);
 
+	xdr_kunmap(xdr, skip);
+
 	dprintk("RPC:      xprt_sendmsg(%d) = %d\n", slen, result);
 
 	if (result >= 0)
@@ -251,10 +253,7 @@
 		/* When the server has died, an ICMP port unreachable message
 		 * prompts ECONNREFUSED.
 		 */
-		break;
 	case -EAGAIN:
-		if (test_bit(SOCK_NOSPACE, &sock->flags))
-			result = -ENOMEM;
 		break;
 	case -ENOTCONN:
 	case -EPIPE:
@@ -269,6 +268,40 @@
 }
 
 /*
+ * Van Jacobson congestion avoidance. Check if the congestion window
+ * overflowed. Put the task to sleep if this is the case.
+ */
+static int
+__xprt_get_cong(struct rpc_xprt *xprt, struct rpc_task *task)
+{
+	struct rpc_rqst *req = task->tk_rqstp;
+
+	if (req->rq_cong)
+		return 1;
+	dprintk("RPC: %4d xprt_cwnd_limited cong = %ld cwnd = %ld\n",
+			task->tk_pid, xprt->cong, xprt->cwnd);
+	if (RPCXPRT_CONGESTED(xprt))
+		return 0;
+	req->rq_cong = 1;
+	xprt->cong += RPC_CWNDSCALE;
+	return 1;
+}
+
+/*
+ * Adjust the congestion window, and wake up the next task
+ * that has been sleeping due to congestion
+ */
+static void
+__xprt_put_cong(struct rpc_xprt *xprt, struct rpc_rqst *req)
+{
+	if (!req->rq_cong)
+		return;
+	req->rq_cong = 0;
+	xprt->cong -= RPC_CWNDSCALE;
+	__xprt_lock_write_next(xprt);
+}
+
+/*
  * Adjust RPC congestion window
  * We use a time-smoothed congestion estimator to avoid heavy oscillation.
  */
@@ -277,40 +310,22 @@
 {
 	unsigned long	cwnd;
 
-	if (xprt->nocong)
-		return;
-	/*
-	 * Note: we're in a BH context
-	 */
-	spin_lock(&xprt->xprt_lock);
 	cwnd = xprt->cwnd;
-	if (result >= 0) {
-		if (xprt->cong < cwnd || time_before(jiffies, xprt->congtime))
-			goto out;
+	if (result >= 0 && cwnd <= xprt->cong) {
 		/* The (cwnd >> 1) term makes sure
 		 * the result gets rounded properly. */
 		cwnd += (RPC_CWNDSCALE * RPC_CWNDSCALE + (cwnd >> 1)) / cwnd;
 		if (cwnd > RPC_MAXCWND)
 			cwnd = RPC_MAXCWND;
-		else
-			pprintk("RPC: %lu %ld cwnd\n", jiffies, cwnd);
-		xprt->congtime = jiffies + ((cwnd * HZ) << 2) / RPC_CWNDSCALE;
-		dprintk("RPC:      cong %08lx, cwnd was %08lx, now %08lx, "
-			"time %ld ms\n", xprt->cong, xprt->cwnd, cwnd,
-			(xprt->congtime-jiffies)*1000/HZ);
+		__xprt_lock_write_next(xprt);
 	} else if (result == -ETIMEDOUT) {
-		if ((cwnd >>= 1) < RPC_CWNDSCALE)
+		cwnd >>= 1;
+		if (cwnd < RPC_CWNDSCALE)
 			cwnd = RPC_CWNDSCALE;
-		xprt->congtime = jiffies + ((cwnd * HZ) << 3) / RPC_CWNDSCALE;
-		dprintk("RPC:      cong %ld, cwnd was %ld, now %ld, "
-			"time %ld ms\n", xprt->cong, xprt->cwnd, cwnd,
-			(xprt->congtime-jiffies)*1000/HZ);
-		pprintk("RPC: %lu %ld cwnd\n", jiffies, cwnd);
 	}
-
+	dprintk("RPC:      cong %ld, cwnd was %ld, now %ld\n",
+			xprt->cong, xprt->cwnd, cwnd);
 	xprt->cwnd = cwnd;
- out:
-	spin_unlock(&xprt->xprt_lock);
 }
 
 /*
@@ -370,7 +385,7 @@
 
 	sock_release(sock);
 	/*
-	 *	TCP doesnt require the rpciod now - other things may
+	 *	TCP doesn't require the rpciod now - other things may
 	 *	but rpciod handles that not us.
 	 */
 	if(xprt->stream)
@@ -460,9 +475,9 @@
 		if (inet->state != TCP_ESTABLISHED) {
 			task->tk_timeout = xprt->timeout.to_maxval;
 			/* if the socket is already closing, delay 5 secs */
-			if ((1<<inet->state) & ~(TCP_SYN_SENT|TCP_SYN_RECV))
+			if ((1<<inet->state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV))
 				task->tk_timeout = 5*HZ;
-			rpc_sleep_on(&xprt->sending, task, xprt_reconn_status, NULL);
+			rpc_sleep_on(&xprt->pending, task, xprt_reconn_status, NULL);
 			release_sock(inet);
 			return;
 		}
@@ -498,30 +513,16 @@
 static inline struct rpc_rqst *
 xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid)
 {
-	struct rpc_task	*head, *task;
-	struct rpc_rqst	*req;
-	int		safe = 0;
+	struct list_head *pos;
+	struct rpc_rqst	*req = NULL;
 
-	spin_lock_bh(&rpc_queue_lock);
-	if ((head = xprt->pending.task) != NULL) {
-		task = head;
-		do {
-			if ((req = task->tk_rqstp) && req->rq_xid == xid)
-				goto out;
-			task = task->tk_next;
-			if (++safe > 100) {
-				printk("xprt_lookup_rqst: loop in Q!\n");
-				goto out_bad;
-			}
-		} while (task != head);
+	list_for_each(pos, &xprt->recv) {
+		struct rpc_rqst *entry = list_entry(pos, struct rpc_rqst, rq_list);
+		if (entry->rq_xid == xid) {
+			req = entry;
+			break;
+		}
 	}
-	dprintk("RPC:      unknown XID %08x in reply.\n", xid);
- out_bad:
-	req = NULL;
- out:
-	if (req && !__rpc_lock_task(req->rq_task))
-		req = NULL;
-	spin_unlock_bh(&rpc_queue_lock);
 	return req;
 }
 
@@ -529,13 +530,23 @@
  * Complete reply received.
  * The TCP code relies on us to remove the request from xprt->pending.
  */
-static inline void
+static void
 xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied)
 {
 	struct rpc_task	*task = req->rq_task;
+	struct rpc_clnt *clnt = task->tk_client;
 
 	/* Adjust congestion window */
-	xprt_adjust_cwnd(xprt, copied);
+	if (!xprt->nocong) {
+		xprt_adjust_cwnd(xprt, copied);
+		__xprt_put_cong(xprt, req);
+	       	if (!req->rq_nresend) {
+			int timer = rpcproc_timer(clnt, task->tk_msg.rpc_proc);
+			if (timer)
+				rpc_update_rtt(&clnt->cl_rtt, timer, (long)jiffies - req->rq_xtime);
+		}
+		rpc_clear_timeo(&clnt->cl_rtt);
+	}
 
 #ifdef RPC_PROFILE
 	/* Profile only reads for now */
@@ -557,66 +568,68 @@
 #endif
 
 	dprintk("RPC: %4d has input (%d bytes)\n", task->tk_pid, copied);
-	task->tk_status = copied;
-	req->rq_received = 1;
+	req->rq_received = copied;
+	list_del_init(&req->rq_list);
 
 	/* ... and wake up the process. */
 	rpc_wake_up_task(task);
 	return;
 }
 
+static size_t
+skb_read_bits(skb_reader_t *desc, void *to, size_t len)
+{
+	if (len > desc->count)
+		len = desc->count;
+	skb_copy_bits(desc->skb, desc->offset, to, len);
+	desc->count -= len;
+	desc->offset += len;
+	return len;
+}
+
+static size_t
+skb_read_and_csum_bits(skb_reader_t *desc, void *to, size_t len)
+{
+	unsigned int csum2, pos;
+
+	if (len > desc->count)
+		len = desc->count;
+	pos = desc->offset;
+	csum2 = skb_copy_and_csum_bits(desc->skb, pos, to, len, 0);
+	desc->csum = csum_block_add(desc->csum, csum2, pos);
+	desc->count -= len;
+	desc->offset += len;
+	return len;
+}
+
 /*
  * We have set things up such that we perform the checksum of the UDP
  * packet in parallel with the copies into the RPC client iovec.  -DaveM
  */
-static int csum_partial_copy_to_page_cache(struct iovec *iov,
-					   struct sk_buff *skb,
-					   int copied)
-{
-	int offset = sizeof(struct udphdr);
-	__u8 *cur_ptr = iov->iov_base;
-	__kernel_size_t cur_len = iov->iov_len;
-	unsigned int csum = skb->csum;
-	int need_csum = (skb->ip_summed != CHECKSUM_UNNECESSARY);
-	int slack = skb->len - copied - sizeof(struct udphdr);
-
-	if (need_csum)
-		csum = csum_partial(skb->data, sizeof(struct udphdr), csum);
-	while (copied > 0) {
-		if (cur_len) {
-			int to_move = cur_len;
-			if (to_move > copied)
-				to_move = copied;
-			if (need_csum) {
-				unsigned int csum2;
-
-				csum2 = skb_copy_and_csum_bits(skb, offset,
-							       cur_ptr,
-							       to_move, 0);
-				csum = csum_block_add(csum, csum2, offset);
-			} else
-				skb_copy_bits(skb, offset, cur_ptr, to_move);
-			offset += to_move;
-			copied -= to_move;
-			cur_ptr += to_move;
-			cur_len -= to_move;
-		}
-		if (cur_len <= 0) {
-			iov++;
-			cur_len = iov->iov_len;
-			cur_ptr = iov->iov_base;
-		}
-	}
-	if (need_csum) {
-		if (slack > 0) {
-			unsigned int csum2;
+static int
+csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb)
+{
+	skb_reader_t desc;
 
-			csum2 = skb_checksum(skb, offset, slack, 0);
-			csum = csum_block_add(csum, csum2, offset);
-		}
-		if ((unsigned short)csum_fold(csum))
-			return -1;
+	desc.skb = skb;
+	desc.offset = sizeof(struct udphdr);
+	desc.count = skb->len - desc.offset;
+
+	if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+		goto no_checksum;
+
+	desc.csum = csum_partial(skb->data, desc.offset, skb->csum);
+	xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits);
+	if (desc.offset != skb->len) {
+		unsigned int csum2;
+		csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0);
+		desc.csum = csum_block_add(desc.csum, csum2, desc.offset);
 	}
+	if ((unsigned short)csum_fold(desc.csum))
+		return -1;
+	return 0;
+no_checksum:
+	xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits);
 	return 0;
 }
 
@@ -654,9 +667,10 @@
 	}
 
 	/* Look up and lock the request corresponding to the given XID */
+	spin_lock(&xprt->sock_lock);
 	rovr = xprt_lookup_rqst(xprt, *(u32 *) (skb->h.raw + sizeof(struct udphdr)));
 	if (!rovr)
-		goto dropit;
+		goto out_unlock;
 	task = rovr->rq_task;
 
 	dprintk("RPC: %4d received reply\n", task->tk_pid);
@@ -667,7 +681,7 @@
 		copied = repsize;
 
 	/* Suck it into the iovec, verify checksum if not done by hw. */
-	if (csum_partial_copy_to_page_cache(rovr->rq_rvec, skb, copied))
+	if (csum_partial_copy_to_xdr(&rovr->rq_rcv_buf, skb))
 		goto out_unlock;
 
 	/* Something worked... */
@@ -676,8 +690,7 @@
 	xprt_complete_rqst(xprt, rovr, copied);
 
  out_unlock:
-	rpc_unlock_task(task);
-
+	spin_unlock(&xprt->sock_lock);
  dropit:
 	skb_free_datagram(sk, skb);
  out:
@@ -685,12 +698,6 @@
 		wake_up_interruptible(sk->sleep);
 }
 
-typedef struct {
-	struct sk_buff *skb;
-	unsigned offset;
-	size_t count;
-} skb_reader_t;
-
 /*
  * Copy from an skb into memory and shrink the skb.
  */
@@ -781,50 +788,43 @@
 tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc)
 {
 	struct rpc_rqst *req;
-	struct iovec *iov;
-	char *p;
-	unsigned long skip;
-	size_t len, used;
-	int n;
+	struct xdr_buf *rcvbuf;
+	size_t len;
 
 	/* Find and lock the request corresponding to this xid */
+	spin_lock(&xprt->sock_lock);
 	req = xprt_lookup_rqst(xprt, xprt->tcp_xid);
 	if (!req) {
 		xprt->tcp_flags &= ~XPRT_COPY_DATA;
 		dprintk("RPC:      XID %08x request not found!\n",
 				xprt->tcp_xid);
+		spin_unlock(&xprt->sock_lock);
 		return;
 	}
-	skip = xprt->tcp_copied;
-	iov = req->rq_rvec;
-	for (n = req->rq_rnr; n != 0; n--, iov++) {
-		if (skip >= iov->iov_len) {
-			skip -= iov->iov_len;
-			continue;
-		}
-		p = iov->iov_base;
-		len = iov->iov_len;
-		if (skip) {
-			p += skip;
-			len -= skip;
-			skip = 0;
-		}
-		if (xprt->tcp_offset + len > xprt->tcp_reclen)
-			len = xprt->tcp_reclen - xprt->tcp_offset;
-		used = tcp_copy_data(desc, p, len);
-		xprt->tcp_copied += used;
-		xprt->tcp_offset += used;
-		if (used != len)
-			break;
-		if (xprt->tcp_copied == req->rq_rlen) {
+
+	rcvbuf = &req->rq_rcv_buf;
+	len = desc->count;
+	if (len > xprt->tcp_reclen - xprt->tcp_offset) {
+		skb_reader_t my_desc;
+
+		len = xprt->tcp_reclen - xprt->tcp_offset;
+		memcpy(&my_desc, desc, sizeof(my_desc));
+		my_desc.count = len;
+		xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied,
+					  &my_desc, tcp_copy_data);
+		desc->count -= len;
+		desc->offset += len;
+	} else
+		xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied,
+					  desc, tcp_copy_data);
+	xprt->tcp_copied += len;
+	xprt->tcp_offset += len;
+
+	if (xprt->tcp_copied == req->rq_rlen)
+		xprt->tcp_flags &= ~XPRT_COPY_DATA;
+	else if (xprt->tcp_offset == xprt->tcp_reclen) {
+		if (xprt->tcp_flags & XPRT_LAST_FRAG)
 			xprt->tcp_flags &= ~XPRT_COPY_DATA;
-			break;
-		}
-		if (xprt->tcp_offset == xprt->tcp_reclen) {
-			if (xprt->tcp_flags & XPRT_LAST_FRAG)
-				xprt->tcp_flags &= ~XPRT_COPY_DATA;
-			break;
-		}
 	}
 
 	if (!(xprt->tcp_flags & XPRT_COPY_DATA)) {
@@ -832,7 +832,7 @@
 				req->rq_task->tk_pid);
 		xprt_complete_rqst(xprt, req, xprt->tcp_copied);
 	}
-	rpc_unlock_task(req->rq_task); 
+	spin_unlock(&xprt->sock_lock);
 	tcp_check_recm(xprt);
 }
 
@@ -932,7 +932,7 @@
 		xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID;
 
 		spin_lock(&xprt->sock_lock);
-		if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
+		if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending)
 			rpc_wake_up_task(xprt->snd_task);
 		spin_unlock(&xprt->sock_lock);
 		break;
@@ -967,19 +967,30 @@
 	if (!sock_writeable(sk))
 		return;
 
-	if (!xprt_test_and_set_wspace(xprt)) {
-		spin_lock(&xprt->sock_lock);
-		if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
-			rpc_wake_up_task(xprt->snd_task);
-		spin_unlock(&xprt->sock_lock);
-	}
+	if (!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))
+		return;
 
-	if (test_bit(SOCK_NOSPACE, &sock->flags)) {
-		if (sk->sleep && waitqueue_active(sk->sleep)) {
-			clear_bit(SOCK_NOSPACE, &sock->flags);
-			wake_up_interruptible(sk->sleep);
-		}
-	}
+	spin_lock_bh(&xprt->sock_lock);
+	if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending)
+		rpc_wake_up_task(xprt->snd_task);
+	spin_unlock_bh(&xprt->sock_lock);
+	if (sk->sleep && waitqueue_active(sk->sleep))
+		wake_up_interruptible(sk->sleep);
+}
+
+/*
+ * Exponential backoff for UDP retries
+ */
+static inline int
+xprt_expbackoff(struct rpc_task *task, struct rpc_rqst *req)
+{
+	int backoff;
+
+	req->rq_ntimeo++;
+	backoff = min(rpc_ntimeo(&task->tk_client->cl_rtt), XPRT_MAX_BACKOFF);
+	if (req->rq_ntimeo < (1 << backoff))
+		return 1;
+	return 0;
 }
 
 /*
@@ -989,16 +1000,31 @@
 xprt_timer(struct rpc_task *task)
 {
 	struct rpc_rqst	*req = task->tk_rqstp;
+	struct rpc_xprt *xprt = req->rq_xprt;
 
-	if (req)
-		xprt_adjust_cwnd(task->tk_xprt, -ETIMEDOUT);
+	spin_lock(&xprt->sock_lock);
+	if (req->rq_received)
+		goto out;
+
+	if (!xprt->nocong) {
+		if (xprt_expbackoff(task, req)) {
+			rpc_add_timer(task, xprt_timer);
+			goto out_unlock;
+		}
+		rpc_inc_timeo(&task->tk_client->cl_rtt);
+		xprt_adjust_cwnd(req->rq_xprt, -ETIMEDOUT);
+	}
+	req->rq_nresend++;
 
 	dprintk("RPC: %4d xprt_timer (%s request)\n",
 		task->tk_pid, req ? "pending" : "backlogged");
 
 	task->tk_status  = -ETIMEDOUT;
+out:
 	task->tk_timeout = 0;
 	rpc_wake_up_task(task);
+out_unlock:
+	spin_unlock(&xprt->sock_lock);
 }
 
 /*
@@ -1034,37 +1060,35 @@
 		*marker = htonl(0x80000000|(req->rq_slen-sizeof(*marker)));
 	}
 
-	if (!xprt_lock_write(xprt, task))
+	spin_lock_bh(&xprt->sock_lock);
+	if (!__xprt_lock_write(xprt, task)) {
+		spin_unlock_bh(&xprt->sock_lock);
 		return;
+	}
+	if (list_empty(&req->rq_list)) {
+		list_add_tail(&req->rq_list, &xprt->recv);
+		req->rq_received = 0;
+	}
+	spin_unlock_bh(&xprt->sock_lock);
 
-#ifdef RPC_PROFILE
-	req->rq_xtime = jiffies;
-#endif
 	do_xprt_transmit(task);
 }
 
 static void
 do_xprt_transmit(struct rpc_task *task)
 {
+	struct rpc_clnt *clnt = task->tk_client;
 	struct rpc_rqst	*req = task->tk_rqstp;
 	struct rpc_xprt	*xprt = req->rq_xprt;
 	int status, retry = 0;
 
 
-	/* For fast networks/servers we have to put the request on
-	 * the pending list now:
-	 * Note that we don't want the task timing out during the
-	 * call to xprt_sendmsg(), so we initially disable the timeout,
-	 * and then reset it later...
-	 */
-	xprt_receive(task);
-
 	/* Continue transmitting the packet/record. We must be careful
 	 * to cope with writespace callbacks arriving _after_ we have
 	 * called xprt_sendmsg().
 	 */
 	while (1) {
-		xprt_clear_wspace(xprt);
+		req->rq_xtime = jiffies;
 		status = xprt_sendmsg(xprt, req);
 
 		if (status < 0)
@@ -1078,7 +1102,7 @@
 		} else {
 			if (status >= req->rq_slen)
 				goto out_receive;
-			status = -ENOMEM;
+			status = -EAGAIN;
 			break;
 		}
 
@@ -1090,31 +1114,28 @@
 		if (retry++ > 50)
 			break;
 	}
-	rpc_unlock_task(task);
 
 	/* Note: at this point, task->tk_sleeping has not yet been set,
 	 *	 hence there is no danger of the waking up task being put on
 	 *	 schedq, and being picked up by a parallel run of rpciod().
 	 */
-	rpc_wake_up_task(task);
-	if (!RPC_IS_RUNNING(task))
-		goto out_release;
 	if (req->rq_received)
 		goto out_release;
 
 	task->tk_status = status;
 
 	switch (status) {
-	case -ENOMEM:
-		/* Protect against (udp|tcp)_write_space */
-		spin_lock_bh(&xprt->sock_lock);
-		if (!xprt_wspace(xprt)) {
-			task->tk_timeout = req->rq_timeout.to_current;
-			rpc_sleep_on(&xprt->sending, task, NULL, NULL);
-		}
-		spin_unlock_bh(&xprt->sock_lock);
-		return;
 	case -EAGAIN:
+		if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) {
+			/* Protect against races with xprt_write_space */
+			spin_lock_bh(&xprt->sock_lock);
+			if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) {
+				task->tk_timeout = req->rq_timeout.to_current;
+				rpc_sleep_on(&xprt->pending, task, NULL, NULL);
+			}
+			spin_unlock_bh(&xprt->sock_lock);
+			return;
+		}
 		/* Keep holding the socket if it is blocked */
 		rpc_delay(task, HZ>>4);
 		return;
@@ -1126,35 +1147,26 @@
 		if (xprt->stream)
 			xprt_disconnect(xprt);
 		req->rq_bytes_sent = 0;
-		goto out_release;
 	}
-
+ out_release:
+	xprt_release_write(xprt, task);
+	return;
  out_receive:
 	dprintk("RPC: %4d xmit complete\n", task->tk_pid);
 	/* Set the task's receive timeout value */
-	task->tk_timeout = req->rq_timeout.to_current;
-	rpc_add_timer(task, xprt_timer);
-	rpc_unlock_task(task);
- out_release:
-	xprt_release_write(xprt, task);
-}
-
-/*
- * Queue the task for a reply to our call.
- * When the callback is invoked, the congestion window should have
- * been updated already.
- */
-void
-xprt_receive(struct rpc_task *task)
-{
-	struct rpc_rqst	*req = task->tk_rqstp;
-	struct rpc_xprt	*xprt = req->rq_xprt;
-
-	dprintk("RPC: %4d xprt_receive\n", task->tk_pid);
-
-	req->rq_received = 0;
-	task->tk_timeout = 0;
-	rpc_sleep_locked(&xprt->pending, task, NULL, NULL);
+	if (!xprt->nocong) {
+		task->tk_timeout = rpc_calc_rto(&clnt->cl_rtt,
+				rpcproc_timer(clnt, task->tk_msg.rpc_proc));
+		req->rq_ntimeo = 0;
+		if (task->tk_timeout > req->rq_timeout.to_maxval)
+			task->tk_timeout = req->rq_timeout.to_maxval;
+	} else
+		task->tk_timeout = req->rq_timeout.to_current;
+	spin_lock_bh(&xprt->sock_lock);
+	if (!req->rq_received)
+		rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer);
+	__xprt_release_write(xprt, task);
+	spin_unlock_bh(&xprt->sock_lock);
 }
 
 /*
@@ -1169,9 +1181,7 @@
 	if (task->tk_rqstp)
 		return 0;
 
-	dprintk("RPC: %4d xprt_reserve cong = %ld cwnd = %ld\n",
-				task->tk_pid, xprt->cong, xprt->cwnd);
-	spin_lock_bh(&xprt->xprt_lock);
+	spin_lock(&xprt->xprt_lock);
 	xprt_reserve_status(task);
 	if (task->tk_rqstp) {
 		task->tk_timeout = 0;
@@ -1182,7 +1192,7 @@
 		task->tk_status = -EAGAIN;
 		rpc_sleep_on(&xprt->backlog, task, NULL, NULL);
 	}
-	spin_unlock_bh(&xprt->xprt_lock);
+	spin_unlock(&xprt->xprt_lock);
 	dprintk("RPC: %4d xprt_reserve returns %d\n",
 				task->tk_pid, task->tk_status);
 	return task->tk_status;
@@ -1204,18 +1214,13 @@
 	} else if (task->tk_rqstp) {
 		/* We've already been given a request slot: NOP */
 	} else {
-		if (RPCXPRT_CONGESTED(xprt) || !(req = xprt->free))
+		if (!(req = xprt->free))
 			goto out_nofree;
-		/* OK: There's room for us. Grab a free slot and bump
-		 * congestion value */
+		/* OK: There's room for us. Grab a free slot */
 		xprt->free     = req->rq_next;
 		req->rq_next   = NULL;
-		xprt->cong    += RPC_CWNDSCALE;
 		task->tk_rqstp = req;
 		xprt_request_init(task, xprt);
-
-		if (xprt->free)
-			xprt_clear_backlog(xprt);
 	}
 
 	return;
@@ -1244,6 +1249,7 @@
 	req->rq_xid     = xid++;
 	if (!xid)
 		xid++;
+	INIT_LIST_HEAD(&req->rq_list);
 }
 
 /*
@@ -1255,27 +1261,25 @@
 	struct rpc_xprt	*xprt = task->tk_xprt;
 	struct rpc_rqst	*req;
 
-	if (xprt->snd_task == task) {
-		if (xprt->stream)
-			xprt_disconnect(xprt);
-		xprt_release_write(xprt, task);
-	}
 	if (!(req = task->tk_rqstp))
 		return;
+	spin_lock_bh(&xprt->sock_lock);
+	__xprt_release_write(xprt, task);
+	__xprt_put_cong(xprt, req);
+	if (!list_empty(&req->rq_list))
+		list_del(&req->rq_list);
+	spin_unlock_bh(&xprt->sock_lock);
 	task->tk_rqstp = NULL;
 	memset(req, 0, sizeof(*req));	/* mark unused */
 
 	dprintk("RPC: %4d release request %p\n", task->tk_pid, req);
 
-	spin_lock_bh(&xprt->xprt_lock);
+	spin_lock(&xprt->xprt_lock);
 	req->rq_next = xprt->free;
 	xprt->free   = req;
 
-	/* Decrease congestion value. */
-	xprt->cong -= RPC_CWNDSCALE;
-
 	xprt_clear_backlog(xprt);
-	spin_unlock_bh(&xprt->xprt_lock);
+	spin_unlock(&xprt->xprt_lock);
 }
 
 /*
@@ -1331,11 +1335,12 @@
 		xprt->nocong = 1;
 	} else
 		xprt->cwnd = RPC_INITCWND;
-	xprt->congtime = jiffies;
 	spin_lock_init(&xprt->sock_lock);
 	spin_lock_init(&xprt->xprt_lock);
 	init_waitqueue_head(&xprt->cong_wait);
 
+	INIT_LIST_HEAD(&xprt->recv);
+
 	/* Set timeout parameters */
 	if (to) {
 		xprt->timeout = *to;
@@ -1344,9 +1349,10 @@
 	} else
 		xprt_default_timeout(&xprt->timeout, xprt->prot);
 
-	xprt->pending = RPC_INIT_WAITQ("xprt_pending");
-	xprt->sending = RPC_INIT_WAITQ("xprt_sending");
-	xprt->backlog = RPC_INIT_WAITQ("xprt_backlog");
+	INIT_RPC_WAITQ(&xprt->pending, "xprt_pending");
+	INIT_RPC_WAITQ(&xprt->sending, "xprt_sending");
+	INIT_RPC_WAITQ(&xprt->resend, "xprt_resend");
+	INIT_RPC_WAITQ(&xprt->backlog, "xprt_backlog");
 
 	/* initialize free list */
 	for (i = 0, req = xprt->slot; i < RPC_MAXREQS-1; i++, req++)
@@ -1420,6 +1426,27 @@
 }
 
 /*
+ * Set socket buffer length
+ */
+void
+xprt_sock_setbufsize(struct rpc_xprt *xprt)
+{
+	struct sock *sk = xprt->inet;
+
+	if (xprt->stream)
+		return;
+	if (xprt->rcvsize) {
+		sk->userlocks |= SOCK_RCVBUF_LOCK;
+		sk->rcvbuf = xprt->rcvsize * RPC_MAXCONG * 2;
+	}
+	if (xprt->sndsize) {
+		sk->userlocks |= SOCK_SNDBUF_LOCK;
+		sk->sndbuf = xprt->sndsize * RPC_MAXCONG * 2;
+		sk->write_space(sk);
+	}
+}
+
+/*
  * Create a client socket given the protocol and peer address.
  */
 static struct socket *
@@ -1477,6 +1504,7 @@
 {
 	xprt->shutdown = 1;
 	rpc_wake_up(&xprt->sending);
+	rpc_wake_up(&xprt->resend);
 	rpc_wake_up(&xprt->pending);
 	rpc_wake_up(&xprt->backlog);
 	if (waitqueue_active(&xprt->cong_wait))
@@ -1488,8 +1516,6 @@
  */
 int
 xprt_clear_backlog(struct rpc_xprt *xprt) {
-	if (RPCXPRT_CONGESTED(xprt))
-		return 0;
 	rpc_wake_up_next(&xprt->backlog);
 	if (waitqueue_active(&xprt->cong_wait))
 		wake_up(&xprt->cong_wait);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/net/unix/af_unix.c linux-2.4.20/net/unix/af_unix.c
--- linux-2.4.19/net/unix/af_unix.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.20/net/unix/af_unix.c	2002-10-29 11:18:48.000000000 +0000
@@ -183,7 +183,7 @@
 		/*
 		 *	This may look like an off by one error but it is
 		 *	a bit more subtle. 108 is the longest valid AF_UNIX
-		 *	path for a binding. sun_path[108] doesnt as such
+		 *	path for a binding. sun_path[108] doesn't as such
 		 *	exist. However in kernel space we are guaranteed that
 		 *	it is a valid memory location in our kernel
 		 *	address buffer.
@@ -565,10 +565,8 @@
 				      addr->hash)) {
 		write_unlock(&unix_table_lock);
 		/* Sanity yield. It is unusual case, but yet... */
-		if (!(ordernum&0xFF)) {
-			current->policy |= SCHED_YIELD;
-			schedule();
-		}
+		if (!(ordernum&0xFF))
+			yield();
 		goto retry;
 	}
 	addr->hash ^= sk->type;
@@ -608,6 +606,9 @@
 		if (!u)
 			goto put_fail;
 
+		if (u->type == type)
+			UPDATE_ATIME(nd.dentry->d_inode);
+
 		path_release(&nd);
 
 		err=-EPROTOTYPE;
@@ -618,7 +619,12 @@
 	} else {
 		err = -ECONNREFUSED;
 		u=unix_find_socket_byname(sunname, len, type, hash);
-		if (!u)
+		if (u) {
+			struct dentry *dentry;
+			dentry = u->protinfo.af_unix.dentry;
+			if (dentry)
+				UPDATE_ATIME(dentry->d_inode);
+		} else
 			goto fail;
 	}
 	return u;
@@ -1385,7 +1391,7 @@
 
 static void unix_copy_addr(struct msghdr *msg, struct sock *sk)
 {
-	msg->msg_namelen = sizeof(short);
+	msg->msg_namelen = 0;
 	if (sk->protinfo.af_unix.addr) {
 		msg->msg_namelen=sk->protinfo.af_unix.addr->len;
 		memcpy(msg->msg_name,
@@ -1885,8 +1891,4 @@
 module_init(af_unix_init);
 module_exit(af_unix_exit);
 
-/*
- * Local variables:
- *  compile-command: "gcc -g -D__KERNEL__ -Wall -O6 -I/usr/src/linux/include -c af_unix.c"
- * End:
- */
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.19/scripts/ver_linux linux-2.4.20/scripts/ver_linux
--- linux-2.4.19/scripts/ver_linux	2001-09-02 14:27:18.000000000 +0000
+++ linux-2.4.20/scripts/ver_linux	2002-10-29 11:18:48.000000000 +0000
@@ -4,7 +4,7 @@
 # /bin /sbin /usr/bin /usr/sbin /usr/local/bin, but it may
 # differ on your system.
 #
-PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH
+PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:$PATH
 echo 'If some fields are empty or look unusual you may have an old version.'
 echo 'Compare to the current minimal requirements in Documentation/Changes.'
 echo ' '
@@ -12,7 +12,11 @@
 uname -a
 echo ' '
 
-echo "Gnu C                 " `gcc --version`
+gcc --version 2>&1| head -n 1 | grep -v gcc | awk \
+'NR==1{print "Gnu C                 ", $1}'
+
+gcc --version 2>&1| grep gcc | awk \
+'NR==1{print "Gnu C                 ", $3}'
 
 make --version 2>&1 | awk -F, '{print $1}' | awk \
       '/GNU Make/{print "Gnu make              ",$NF}'
@@ -29,7 +33,10 @@
 tune2fs 2>&1 | grep "^tune2fs" | sed 's/,//' |  awk \
 'NR==1 {print "e2fsprogs             ", $2}'
 
-reiserfsck 2>&1 | grep reiserfsprogs | awk \
+fsck.jfs -V 2>&1 | grep version | sed 's/,//' |  awk \
+'NR==1 {print "jfsutils              ", $3}'
+
+reiserfsck -V 2>&1 | grep reiserfsprogs | awk \
 'NR==1{print "reiserfsprogs         ", $NF}'
 
 cardmgr -V 2>&1| grep version | awk \
